1/* 2 * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26#import "QuartzSurfaceData.h" 27 28#import "java_awt_BasicStroke.h" 29#import "java_awt_AlphaComposite.h" 30#import "java_awt_geom_PathIterator.h" 31#import "java_awt_image_BufferedImage.h" 32#import "sun_awt_SunHints.h" 33#import "sun_java2d_CRenderer.h" 34#import "sun_java2d_OSXSurfaceData.h" 35#import "sun_lwawt_macosx_CPrinterSurfaceData.h" 36#import "ImageSurfaceData.h" 37 38#import <AppKit/AppKit.h> 39#import "ThreadUtilities.h" 40 41//#define DEBUG 42#if defined DEBUG 43 #define PRINT(msg) {fprintf(stderr, "%s\n", msg);} 44#else 45 #define PRINT(msg) {} 46#endif 47 48#define kOffset (0.5f) 49 50#define JNI_COCOA_THROW_OOME(env, msg) \ 51 if ([NSThread isMainThread] == NO) { \ 52 JNU_ThrowOutOfMemoryError(env, msg); \ 53 } \ 54 [NSException raise:@"Java Exception" reason:@"Java OutOfMemoryException" userInfo:nil] 55 56BOOL gAdjustForJavaDrawing; 57 58#pragma mark 59#pragma mark --- Color Cache --- 60 61// Creating and deleting CGColorRefs can be expensive, therefore we have a color cache. 62// The color cache was first introduced with <rdar://problem/3923927> 63// With <rdar://problem/4280514>, the hashing function was improved 64// With <rdar://problem/4012223>, the color cache became global (per process) instead of per surface. 65 66// Must be power of 2. 1024 is the least power of 2 number that makes SwingSet2 run without any non-empty cache misses 67#define gColorCacheSize 1024 68struct _ColorCacheInfo 69{ 70 UInt32 keys[gColorCacheSize]; 71 CGColorRef values[gColorCacheSize]; 72}; 73static struct _ColorCacheInfo colorCacheInfo; 74 75static pthread_mutex_t gColorCacheLock = PTHREAD_MUTEX_INITIALIZER; 76 77// given a UInt32 color, it tries to find that find the corresponding CGColorRef in the hash cache. If the CGColorRef 78// doesn't exist or there is a collision, it creates a new one CGColorRef and put's in the cache. Then, 79// it sets with current fill/stroke color for the CGContext passed in (qsdo->cgRef). 80void setCachedColor(QuartzSDOps *qsdo, UInt32 color) 81{ 82 static const CGFloat kColorConversionMultiplier = 1.0f/255.0f; 83 84 pthread_mutex_lock(&gColorCacheLock); 85 86 static CGColorSpaceRef colorspace = NULL; 87 if (colorspace == NULL) 88 { 89 colorspace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB); 90 } 91 92 CGColorRef cgColor = NULL; 93 94 // The colors passed have low randomness. That means we need to scramble the bits of the color 95 // to produce a good hash key. After some analysis, it looks like Thomas's Wang integer hasing algorithm 96 // seems a nice trade off between performance and effectivness. 97 UInt32 index = color; 98 index += ~(index << 15); 99 index ^= (index >> 10); 100 index += (index << 3); 101 index ^= (index >> 6); 102 index += ~(index << 11); 103 index ^= (index >> 16); 104 index = index & (gColorCacheSize - 1); // The bits are scrambled, we just need to make sure it fits inside our table 105 106 UInt32 key = colorCacheInfo.keys[index]; 107 CGColorRef value = colorCacheInfo.values[index]; 108 if ((key == color) && (value != NULL)) 109 { 110 //fprintf(stderr, "+");fflush(stderr);//hit 111 cgColor = value; 112 } 113 else 114 { 115 if (value != NULL) 116 { 117 //fprintf(stderr, "!");fflush(stderr);//miss and replace - double ouch 118 CGColorRelease(value); 119 } 120 //fprintf(stderr, "-");fflush(stderr);// miss 121 122 CGFloat alpha = ((color>>24)&0xff)*kColorConversionMultiplier; 123 CGFloat red = ((color>>16)&0xff)*kColorConversionMultiplier; 124 CGFloat green = ((color>>8)&0xff)*kColorConversionMultiplier; 125 CGFloat blue = ((color>>0)&0xff)*kColorConversionMultiplier; 126 const CGFloat components[] = {red, green, blue, alpha, 1.0f}; 127 value = CGColorCreate(colorspace, components); 128 129 colorCacheInfo.keys[index] = color; 130 colorCacheInfo.values[index] = value; 131 132 cgColor = value; 133 } 134 135 CGContextSetStrokeColorWithColor(qsdo->cgRef, cgColor); 136 CGContextSetFillColorWithColor(qsdo->cgRef, cgColor); 137 138 pthread_mutex_unlock(&gColorCacheLock); 139} 140 141#pragma mark 142#pragma mark --- Gradient --- 143 144// this function MUST NOT be inlined! 145void gradientLinearPaintEvaluateFunction(void *info, const CGFloat *in, CGFloat *out) 146{ 147 StateShadingInfo *shadingInfo = (StateShadingInfo *)info; 148 CGFloat *colors = shadingInfo->colors; 149 CGFloat range = *in; 150 CGFloat c1, c2; 151 jint k; 152 153//fprintf(stderr, "range=%f\n", range); 154 for (k=0; k<4; k++) 155 { 156 c1 = colors[k]; 157//fprintf(stderr, " c1=%f", c1); 158 c2 = colors[k+4]; 159//fprintf(stderr, ", c2=%f", c2); 160 if (c1 == c2) 161 { 162 *out++ = c2; 163//fprintf(stderr, ", %f", *(out-1)); 164 } 165 else if (c1 > c2) 166 { 167 *out++ = c1 - ((c1-c2)*range); 168//fprintf(stderr, ", %f", *(out-1)); 169 } 170 else// if (c1 < c2) 171 { 172 *out++ = c1 + ((c2-c1)*range); 173//fprintf(stderr, ", %f", *(out-1)); 174 } 175//fprintf(stderr, "\n"); 176 } 177} 178 179// this function MUST NOT be inlined! 180void gradientCyclicPaintEvaluateFunction(void *info, const CGFloat *in, CGFloat *out) 181{ 182 StateShadingInfo *shadingInfo = (StateShadingInfo *)info; 183 CGFloat length = shadingInfo->length ; 184 CGFloat period = shadingInfo->period; 185 CGFloat offset = shadingInfo->offset; 186 CGFloat periodLeft = offset; 187 CGFloat periodRight = periodLeft+period; 188 CGFloat *colors = shadingInfo->colors; 189 CGFloat range = *in; 190 CGFloat c1, c2; 191 jint k; 192 jint count = 0; 193 194 range *= length; 195 196 // put the range within the period 197 if (range < periodLeft) 198 { 199 while (range < periodLeft) 200 { 201 range += period; 202 count++; 203 } 204 205 range = range-periodLeft; 206 } 207 else if (range > periodRight) 208 { 209 count = 1; 210 211 while (range > periodRight) 212 { 213 range -= period; 214 count++; 215 } 216 217 range = periodRight-range; 218 } 219 else 220 { 221 range = range - offset; 222 } 223 range = range/period; 224 225 // cycle up or down 226 if (count%2 == 0) 227 { 228 for (k=0; k<4; k++) 229 { 230 c1 = colors[k]; 231 c2 = colors[k+4]; 232 if (c1 == c2) 233 { 234 *out++ = c2; 235 } 236 else if (c1 > c2) 237 { 238 *out++ = c1 - ((c1-c2)*range); 239 } 240 else// if (c1 < c2) 241 { 242 *out++ = c1 + ((c2-c1)*range); 243 } 244 } 245 } 246 else 247 { 248 for (k=0; k<4; k++) 249 { 250 c1 = colors[k+4]; 251 c2 = colors[k]; 252 if (c1 == c2) 253 { 254 *out++ = c2; 255 } 256 else if (c1 > c2) 257 { 258 *out++ = c1 - ((c1-c2)*range); 259 } 260 else// if (c1 < c2) 261 { 262 *out++ = c1 + ((c2-c1)*range); 263 } 264 } 265 } 266 } 267 268// this function MUST NOT be inlined! 269void gradientPaintReleaseFunction(void *info) 270{ 271PRINT(" gradientPaintReleaseFunction") 272 free(info); 273} 274 275static inline void contextQuartzLinearGradientPath(QuartzSDOps* qsdo) 276{ 277 278PRINT(" contextQuartzLinearGradientPath"); 279 280 CGContextRef cgRef = qsdo->cgRef; 281 StateGradientInfo *gradientInfo = qsdo->gradientInfo; 282 283 CGColorSpaceRef colorspace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB); 284 size_t num_locations = gradientInfo->fractionsLength; 285 CGFloat *locations = (CGFloat *) malloc(sizeof(CGFloat) * num_locations); 286 int i = 0; 287 size_t component_size = num_locations * 4; 288 CGFloat components[component_size]; 289 CGGradientRef gradient = NULL; 290 291 for (i = 0; i < num_locations; i++) { 292 locations[i] = gradientInfo->fractionsdata[i]; 293 } 294 for (i = 0; i < component_size; i++) { 295 components[i] = gradientInfo->colordata[i]; 296 } 297 CGContextSaveGState(cgRef); 298 gradient = CGGradientCreateWithColorComponents(colorspace, components, locations, num_locations); 299 if (qsdo->isEvenOddFill) { 300 CGContextEOClip(cgRef); 301 } else { 302 CGContextClip(cgRef); 303 } 304 CGContextDrawLinearGradient(cgRef, gradient, gradientInfo->start, gradientInfo->end, kCGGradientDrawsAfterEndLocation); 305 306 CGContextRestoreGState(cgRef); 307 CGColorSpaceRelease(colorspace); 308 CGGradientRelease(gradient); 309 free(locations); 310 free(gradientInfo->colordata); 311 free(gradientInfo->fractionsdata); 312} 313 314static inline void contextQuartzRadialGradientPath(QuartzSDOps* qsdo) 315{ 316 317PRINT(" contextQuartzRadialGradientPath"); 318 319 CGContextRef cgRef = qsdo->cgRef; 320 StateGradientInfo *gradientInfo = qsdo->gradientInfo; 321 322 CGColorSpaceRef colorspace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB); 323 size_t num_locations = gradientInfo->fractionsLength; 324 CGFloat *locations = (CGFloat *) malloc(sizeof(CGFloat) * num_locations); 325 int i = 0; 326 size_t component_size = num_locations * 4; 327 CGFloat components[component_size]; 328 CGGradientRef gradient = NULL; 329 CGFloat startRadius = gradientInfo->radius; 330 CGFloat endRadius = gradientInfo->radius; 331 332 for (i = 0; i < num_locations; i++) { 333 locations[i] = gradientInfo->fractionsdata[i]; 334 } 335 for (i = 0; i < component_size; i++) { 336 components[i] = gradientInfo->colordata[i]; 337 } 338 CGContextSaveGState(cgRef); 339 gradient = CGGradientCreateWithColorComponents(colorspace, components, locations, num_locations); 340 if (qsdo->isEvenOddFill) { 341 CGContextEOClip(cgRef); 342 } else { 343 CGContextClip(cgRef); 344 } 345 CGContextDrawRadialGradient(cgRef, gradient, gradientInfo->start, 0, gradientInfo->end, endRadius, kCGGradientDrawsAfterEndLocation); 346 347 CGContextRestoreGState(cgRef); 348 CGColorSpaceRelease(colorspace); 349 CGGradientRelease(gradient); 350 free(locations); 351 free(gradientInfo->colordata); 352 free(gradientInfo->fractionsdata); 353} 354 355static inline void contextGradientPath(QuartzSDOps* qsdo) 356{ 357PRINT(" ContextGradientPath") 358 359 CGContextRef cgRef = qsdo->cgRef; 360 StateShadingInfo* shadingInfo = qsdo->shadingInfo; 361 362 CGRect bounds = CGContextGetClipBoundingBox(cgRef); 363 364 static const CGFloat domain[2] = {0.0f, 1.0f}; 365 static const CGFloat range[8] = {0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f}; 366 CGColorSpaceRef colorspace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB); 367 CGFunctionRef shadingFunc = NULL; 368 CGShadingRef shading = NULL; 369 if (shadingInfo->cyclic == NO) 370 { 371 static const CGFunctionCallbacks callbacks = {0, &gradientLinearPaintEvaluateFunction, &gradientPaintReleaseFunction}; 372 shadingFunc = CGFunctionCreate((void *)shadingInfo, 1, domain, 4, range, &callbacks); 373 shading = CGShadingCreateAxial(colorspace, shadingInfo->start, shadingInfo->end, shadingFunc, 1, 1); 374 } 375 else 376 { 377//fprintf(stderr, "BOUNDING BOX x1=%f, y1=%f x2=%f, y2=%f\n", bounds.origin.x, bounds.origin.y, bounds.origin.x+bounds.size.width, bounds.origin.y+bounds.size.height); 378 // need to extend the line start-end 379 380 CGFloat x1 = shadingInfo->start.x; 381 CGFloat y1 = shadingInfo->start.y; 382 CGFloat x2 = shadingInfo->end.x; 383 CGFloat y2 = shadingInfo->end.y; 384//fprintf(stderr, "GIVEN x1=%f, y1=%f x2=%f, y2=%f\n", x1, y1, x2, y2); 385 386 if (x1 == x2) 387 { 388 y1 = bounds.origin.y; 389 y2 = y1 + bounds.size.height; 390 } 391 else if (y1 == y2) 392 { 393 x1 = bounds.origin.x; 394 x2 = x1 + bounds.size.width; 395 } 396 else 397 { 398 // find the original line function y = mx + c 399 CGFloat m1 = (y2-y1)/(x2-x1); 400 CGFloat c1 = y1 - m1*x1; 401//fprintf(stderr, " m1=%f, c1=%f\n", m1, c1); 402 403 // a line perpendicular to the original one will have the slope 404 CGFloat m2 = -(1/m1); 405//fprintf(stderr, " m2=%f\n", m2); 406 407 // find the only 2 possible lines perpendicular to the original line, passing the two top corners of the bounding box 408 CGFloat x1A = bounds.origin.x; 409 CGFloat y1A = bounds.origin.y; 410 CGFloat c1A = y1A - m2*x1A; 411//fprintf(stderr, " x1A=%f, y1A=%f, c1A=%f\n", x1A, y1A, c1A); 412 CGFloat x1B = bounds.origin.x+bounds.size.width; 413 CGFloat y1B = bounds.origin.y; 414 CGFloat c1B = y1B - m2*x1B; 415//fprintf(stderr, " x1B=%f, y1B=%f, c1B=%f\n", x1B, y1B, c1B); 416 417 // find the crossing points of the original line and the two lines we computed above to find the new possible starting points 418 CGFloat x1Anew = (c1A-c1)/(m1-m2); 419 CGFloat y1Anew = m2*x1Anew + c1A; 420 CGFloat x1Bnew = (c1B-c1)/(m1-m2); 421 CGFloat y1Bnew = m2*x1Bnew + c1B; 422//fprintf(stderr, "NEW x1Anew=%f, y1Anew=%f x1Bnew=%f, y1Bnew=%f\n", x1Anew, y1Anew, x1Bnew, y1Bnew); 423 424 // select the new starting point 425 if (y1Anew <= y1Bnew) 426 { 427 x1 = x1Anew; 428 y1 = y1Anew; 429 } 430 else 431 { 432 x1 = x1Bnew; 433 y1 = y1Bnew; 434 } 435//fprintf(stderr, "--- NEW x1=%f, y1=%f\n", x1, y1); 436 437 // find the only 2 possible lines perpendicular to the original line, passing the two bottom corners of the bounding box 438 CGFloat x2A = bounds.origin.x; 439 CGFloat y2A = bounds.origin.y+bounds.size.height; 440 CGFloat c2A = y2A - m2*x2A; 441//fprintf(stderr, " x2A=%f, y2A=%f, c2A=%f\n", x2A, y2A, c2A); 442 CGFloat x2B = bounds.origin.x+bounds.size.width; 443 CGFloat y2B = bounds.origin.y+bounds.size.height; 444 CGFloat c2B = y2B - m2*x2B; 445//fprintf(stderr, " x2B=%f, y2B=%f, c2B=%f\n", x2B, y2B, c2B); 446 447 // find the crossing points of the original line and the two lines we computed above to find the new possible ending points 448 CGFloat x2Anew = (c2A-c1)/(m1-m2); 449 CGFloat y2Anew = m2*x2Anew + c2A; 450 CGFloat x2Bnew = (c2B-c1)/(m1-m2); 451 CGFloat y2Bnew = m2*x2Bnew + c2B; 452//fprintf(stderr, "NEW x2Anew=%f, y2Anew=%f x2Bnew=%f, y2Bnew=%f\n", x2Anew, y2Anew, x2Bnew, y2Bnew); 453 454 // select the new ending point 455 if (y2Anew >= y2Bnew) 456 { 457 x2 = x2Anew; 458 y2 = y2Anew; 459 } 460 else 461 { 462 x2 = x2Bnew; 463 y2 = y2Bnew; 464 } 465//fprintf(stderr, "--- NEW x2=%f, y2=%f\n", x2, y2); 466 } 467 468 qsdo->shadingInfo->period = sqrt(pow(shadingInfo->end.x-shadingInfo->start.x, 2.0) + pow(shadingInfo->end.y-shadingInfo->start.y, 2.0)); 469 if ((qsdo->shadingInfo->period != 0)) 470 { 471 // compute segment lengths that we will need for the gradient function 472 qsdo->shadingInfo->length = sqrt(pow(x2-x1, 2.0) + pow(y2-y1, 2.0)); 473 qsdo->shadingInfo->offset = sqrt(pow(shadingInfo->start.x-x1, 2.0) + pow(shadingInfo->start.y-y1, 2.0)); 474//fprintf(stderr, "length=%f, period=%f, offset=%f\n", qsdo->shadingInfo->length, qsdo->shadingInfo->period, qsdo->shadingInfo->offset); 475 476 CGPoint newStart = {x1, y1}; 477 CGPoint newEnd = {x2, y2}; 478 479 static const CGFunctionCallbacks callbacks = {0, &gradientCyclicPaintEvaluateFunction, &gradientPaintReleaseFunction}; 480 shadingFunc = CGFunctionCreate((void *)shadingInfo, 1, domain, 4, range, &callbacks); 481 shading = CGShadingCreateAxial(colorspace, newStart, newEnd, shadingFunc, 0, 0); 482 } 483 } 484 CGColorSpaceRelease(colorspace); 485 486 if (shadingFunc != NULL) 487 { 488 CGContextSaveGState(cgRef); 489 490 // rdar://problem/5214320 491 // Gradient fills of Java GeneralPath don't respect the even odd winding rule (quartz pipeline). 492 if (qsdo->isEvenOddFill) { 493 CGContextEOClip(cgRef); 494 } else { 495 CGContextClip(cgRef); 496 } 497 CGContextDrawShading(cgRef, shading); 498 499 CGContextRestoreGState(cgRef); 500 CGShadingRelease(shading); 501 CGFunctionRelease(shadingFunc); 502 qsdo->shadingInfo = NULL; 503 } 504} 505 506#pragma mark 507#pragma mark --- Texture --- 508 509// this function MUST NOT be inlined! 510void texturePaintEvaluateFunction(void *info, CGContextRef cgRef) 511{ 512 JNIEnv* env = [ThreadUtilities getJNIEnvUncached]; 513 514 StatePatternInfo* patternInfo = (StatePatternInfo*)info; 515 ImageSDOps* isdo = LockImage(env, patternInfo->sdata); 516 517 makeSureImageIsCreated(isdo); 518 CGContextDrawImage(cgRef, CGRectMake(0.0f, 0.0f, patternInfo->width, patternInfo->height), isdo->imgRef); 519 520 UnlockImage(env, isdo); 521} 522 523// this function MUST NOT be inlined! 524void texturePaintReleaseFunction(void *info) 525{ 526 PRINT(" texturePaintReleaseFunction") 527 JNIEnv* env = [ThreadUtilities getJNIEnvUncached]; 528 529 StatePatternInfo* patternInfo = (StatePatternInfo*)info; 530 (*env)->DeleteGlobalRef(env, patternInfo->sdata); 531 532 free(info); 533} 534 535static inline void contextTexturePath(JNIEnv* env, QuartzSDOps* qsdo) 536{ 537 PRINT(" ContextTexturePath") 538 CGContextRef cgRef = qsdo->cgRef; 539 StatePatternInfo* patternInfo = qsdo->patternInfo; 540 541 CGAffineTransform ctm = CGContextGetCTM(cgRef); 542 CGAffineTransform ptm = {patternInfo->sx, 0.0f, 0.0f, -patternInfo->sy, patternInfo->tx, patternInfo->ty}; 543 CGAffineTransform tm = CGAffineTransformConcat(ptm, ctm); 544 CGFloat xStep = (CGFloat)qsdo->patternInfo->width; 545 CGFloat yStep = (CGFloat)qsdo->patternInfo->height; 546 CGPatternTiling tiling = kCGPatternTilingNoDistortion; 547 BOOL isColored = YES; 548 static const CGPatternCallbacks callbacks = {0, &texturePaintEvaluateFunction, &texturePaintReleaseFunction}; 549 CGPatternRef pattern = CGPatternCreate((void*)patternInfo, CGRectMake(0.0f, 0.0f, xStep, yStep), tm, xStep, yStep, tiling, isColored, &callbacks); 550 551 CGColorSpaceRef colorspace = CGColorSpaceCreatePattern(NULL); 552 static const CGFloat alpha = 1.0f; 553 554 CGContextSaveGState(cgRef); 555 556 CGContextSetFillColorSpace(cgRef, colorspace); 557 CGContextSetFillPattern(cgRef, pattern, &alpha); 558 CGContextSetRGBStrokeColor(cgRef, 0.0f, 0.0f, 0.0f, 1.0f); 559 CGContextSetPatternPhase(cgRef, CGSizeMake(0.0f, 0.0f)); 560 // rdar://problem/5214320 561 // Gradient fills of Java GeneralPath don't respect the even odd winding rule (quartz pipeline). 562 if (qsdo->isEvenOddFill) { 563 CGContextEOFillPath(cgRef); 564 } else { 565 CGContextFillPath(cgRef); 566 } 567 568 CGContextRestoreGState(cgRef); 569 570 CGColorSpaceRelease(colorspace); 571 CGPatternRelease(pattern); 572 573 qsdo->patternInfo = NULL; 574} 575 576#pragma mark 577#pragma mark --- Context Setup --- 578 579static inline void setDefaultColorSpace(CGContextRef cgRef) 580{ 581 static CGColorSpaceRef colorspace = NULL; 582 if (colorspace == NULL) 583 { 584 colorspace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB); 585 } 586 CGContextSetStrokeColorSpace(cgRef, colorspace); 587 CGContextSetFillColorSpace(cgRef, colorspace); 588} 589 590void SetUpCGContext(JNIEnv *env, QuartzSDOps *qsdo, SDRenderType renderType) 591{ 592PRINT(" SetUpCGContext") 593 CGContextRef cgRef = qsdo->cgRef; 594//fprintf(stderr, "%p ", cgRef); 595 jint *javaGraphicsStates = qsdo->javaGraphicsStates; 596 jfloat *javaFloatGraphicsStates = (jfloat*)(qsdo->javaGraphicsStates); 597 598 jint changeFlags = javaGraphicsStates[sun_java2d_OSXSurfaceData_kChangeFlagIndex]; 599 BOOL everyThingChanged = qsdo->newContext || (changeFlags == sun_java2d_OSXSurfaceData_kEverythingChangedFlag); 600 BOOL clipChanged = everyThingChanged || ((changeFlags&sun_java2d_OSXSurfaceData_kClipChangedBit) != 0); 601 BOOL transformChanged = everyThingChanged || ((changeFlags&sun_java2d_OSXSurfaceData_kCTMChangedBit) != 0); 602 BOOL paintChanged = everyThingChanged || ((changeFlags&sun_java2d_OSXSurfaceData_kColorChangedBit) != 0); 603 BOOL compositeChanged = everyThingChanged || ((changeFlags&sun_java2d_OSXSurfaceData_kCompositeChangedBit) != 0); 604 BOOL strokeChanged = everyThingChanged || ((changeFlags&sun_java2d_OSXSurfaceData_kStrokeChangedBit) != 0); 605// BOOL fontChanged = everyThingChanged || ((changeFlags&sun_java2d_OSXSurfaceData_kFontChangedBit) != 0); 606 BOOL renderingHintsChanged = everyThingChanged || ((changeFlags&sun_java2d_OSXSurfaceData_kHintsChangedBit) != 0); 607 608//fprintf(stderr, "SetUpCGContext cgRef=%p new=%d changeFlags=%d, everyThingChanged=%d clipChanged=%d transformChanged=%d\n", 609// cgRef, qsdo->newContext, changeFlags, everyThingChanged, clipChanged, transformChanged); 610 611 if ((everyThingChanged == YES) || (clipChanged == YES) || (transformChanged == YES)) 612 { 613 everyThingChanged = YES; // in case clipChanged or transformChanged 614 615 CGContextRestoreGState(cgRef); // restore to the original state 616 617 CGContextSaveGState(cgRef); // make our local copy of the state 618 619 setDefaultColorSpace(cgRef); 620 } 621 622 if ((everyThingChanged == YES) || (clipChanged == YES)) 623 { 624 if (javaGraphicsStates[sun_java2d_OSXSurfaceData_kClipStateIndex] == sun_java2d_OSXSurfaceData_kClipRect) 625 { 626 CGFloat x = javaFloatGraphicsStates[sun_java2d_OSXSurfaceData_kClipXIndex]; 627 CGFloat y = javaFloatGraphicsStates[sun_java2d_OSXSurfaceData_kClipYIndex]; 628 CGFloat w = javaFloatGraphicsStates[sun_java2d_OSXSurfaceData_kClipWidthIndex]; 629 CGFloat h = javaFloatGraphicsStates[sun_java2d_OSXSurfaceData_kClipHeightIndex]; 630 CGContextClipToRect(cgRef, CGRectMake(x, y, w, h)); 631 } 632 else 633 { 634 BOOL eoFill = (javaGraphicsStates[sun_java2d_OSXSurfaceData_kClipWindingRuleIndex] == java_awt_geom_PathIterator_WIND_EVEN_ODD); 635 jint numtypes = javaGraphicsStates[sun_java2d_OSXSurfaceData_kClipNumTypesIndex]; 636 637 jobject coordsarray = (jobject)((*env)->GetObjectArrayElement(env, qsdo->javaGraphicsStatesObjects, sun_java2d_OSXSurfaceData_kClipCoordinatesIndex)); 638 jobject typesarray = (jobject)((*env)->GetObjectArrayElement(env, qsdo->javaGraphicsStatesObjects, sun_java2d_OSXSurfaceData_kClipTypesIndex)); 639 640 jfloat* coords = (jfloat*)(*env)->GetDirectBufferAddress(env, coordsarray); 641 jint* types = (jint*)(*env)->GetDirectBufferAddress(env, typesarray); 642 643 DoShapeUsingCG(cgRef, types, coords, numtypes, NO, qsdo->graphicsStateInfo.offsetX, qsdo->graphicsStateInfo.offsetY); 644 645 if (CGContextIsPathEmpty(cgRef) == 0) 646 { 647 if (eoFill) 648 { 649 CGContextEOClip(cgRef); 650 } 651 else 652 { 653 CGContextClip(cgRef); 654 } 655 } 656 else 657 { 658 CGContextClipToRect(cgRef, CGRectZero); 659 } 660 } 661 } 662// for debugging 663//CGContextResetClip(cgRef); 664 665 if ((everyThingChanged == YES) || (transformChanged == YES)) 666 { 667 CGFloat a = javaFloatGraphicsStates[sun_java2d_OSXSurfaceData_kCTMaIndex]; 668 CGFloat b = javaFloatGraphicsStates[sun_java2d_OSXSurfaceData_kCTMbIndex]; 669 CGFloat c = javaFloatGraphicsStates[sun_java2d_OSXSurfaceData_kCTMcIndex]; 670 CGFloat d = javaFloatGraphicsStates[sun_java2d_OSXSurfaceData_kCTMdIndex]; 671 CGFloat tx = javaFloatGraphicsStates[sun_java2d_OSXSurfaceData_kCTMtxIndex]; 672 CGFloat ty = javaFloatGraphicsStates[sun_java2d_OSXSurfaceData_kCTMtyIndex]; 673 674 CGContextConcatCTM(cgRef, CGAffineTransformMake(a, b, c, d, tx, ty)); 675 676 if (gAdjustForJavaDrawing == YES) 677 { 678 // find the offsets in the device corrdinate system 679 CGAffineTransform ctm = CGContextGetCTM(cgRef); 680 if ((qsdo->graphicsStateInfo.ctm.a != ctm.a) || 681 (qsdo->graphicsStateInfo.ctm.b != ctm.b) || 682 (qsdo->graphicsStateInfo.ctm.c != ctm.c) || 683 (qsdo->graphicsStateInfo.ctm.d != ctm.d)) 684 { 685 qsdo->graphicsStateInfo.ctm = ctm; 686 // In CG affine xforms y' = bx+dy+ty 687 // We need to flip both y coefficeints to flip the offset point into the java coordinate system. 688 ctm.b = -ctm.b; ctm.d = -ctm.d; ctm.tx = 0.0f; ctm.ty = 0.0f; 689 CGPoint offsets = {kOffset, kOffset}; 690 CGAffineTransform inverse = CGAffineTransformInvert(ctm); 691 offsets = CGPointApplyAffineTransform(offsets, inverse); 692 qsdo->graphicsStateInfo.offsetX = offsets.x; 693 qsdo->graphicsStateInfo.offsetY = offsets.y; 694 } 695 } 696 else 697 { 698 qsdo->graphicsStateInfo.offsetX = 0.0f; 699 qsdo->graphicsStateInfo.offsetY = 0.0f; 700 } 701 } 702 703// for debugging 704//CGContextResetCTM(cgRef); 705 706 if ((everyThingChanged == YES) || (compositeChanged == YES)) 707 { 708 jint alphaCompositeRule = javaGraphicsStates[sun_java2d_OSXSurfaceData_kCompositeRuleIndex]; 709 CGFloat alphaCompositeValue = javaFloatGraphicsStates[sun_java2d_OSXSurfaceData_kCompositeValueIndex]; 710 711 NSCompositingOperation op; 712 switch (alphaCompositeRule) 713 { 714 case java_awt_AlphaComposite_CLEAR: 715 op = NSCompositeClear; 716 break; 717 case java_awt_AlphaComposite_SRC: 718 op = NSCompositeCopy; 719 break; 720 case java_awt_AlphaComposite_SRC_OVER: 721 op = NSCompositeSourceOver; 722 break; 723 case java_awt_AlphaComposite_DST_OVER: 724 op = NSCompositeDestinationOver; 725 break; 726 case java_awt_AlphaComposite_SRC_IN: 727 op = NSCompositeSourceIn; 728 break; 729 case java_awt_AlphaComposite_DST_IN: 730 op = NSCompositeDestinationIn; 731 break; 732 case java_awt_AlphaComposite_SRC_OUT: 733 op = NSCompositeSourceOut; 734 break; 735 case java_awt_AlphaComposite_DST_OUT: 736 op = NSCompositeDestinationOut; 737 break; 738 case java_awt_AlphaComposite_DST: 739 // Alpha must be set to 0 because we're using the kCGCompositeSover rule 740 op = NSCompositeSourceOver; 741 alphaCompositeValue = 0.0f; 742 break; 743 case java_awt_AlphaComposite_SRC_ATOP: 744 op = NSCompositeSourceAtop; 745 break; 746 case java_awt_AlphaComposite_DST_ATOP: 747 op = NSCompositeDestinationAtop; 748 break; 749 case java_awt_AlphaComposite_XOR: 750 op = NSCompositeXOR; 751 break; 752 default: 753 op = NSCompositeSourceOver; 754 alphaCompositeValue = 1.0f; 755 break; 756 } 757 758 NSGraphicsContext *context = [NSGraphicsContext graphicsContextWithGraphicsPort:cgRef flipped:NO]; 759 //CGContextSetCompositeOperation(cgRef, op); 760 [context setCompositingOperation:op]; 761 CGContextSetAlpha(cgRef, alphaCompositeValue); 762 } 763 764 if ((everyThingChanged == YES) || (renderingHintsChanged == YES)) 765 { 766 jint antialiasHint = javaGraphicsStates[sun_java2d_OSXSurfaceData_kHintsAntialiasIndex]; 767// jint textAntialiasHint = javaGraphicsStates[sun_java2d_OSXSurfaceData_kHintsTextAntialiasIndex]; 768 jint renderingHint = javaGraphicsStates[sun_java2d_OSXSurfaceData_kHintsRenderingIndex]; 769 jint interpolationHint = javaGraphicsStates[sun_java2d_OSXSurfaceData_kHintsInterpolationIndex]; 770// jint textFractionalMetricsHint = javaGraphicsStates[sun_java2d_OSXSurfaceData_kHintsFractionalMetricsIndex]; 771 772 // 10-10-02 VL: since CoreGraphics supports only an interpolation quality attribute we have to map 773 // both interpolationHint and renderingHint to an attribute value that best represents their combination. 774 // (See Radar 3071704.) We'll go for the best quality. CG maps interpolation quality values as follows: 775 // kCGInterpolationNone - nearest_neighbor 776 // kCGInterpolationLow - bilinear 777 // kCGInterpolationHigh - Lanczos (better than bicubic) 778 CGInterpolationQuality interpolationQuality = kCGInterpolationDefault; 779 // First check if the interpolation hint is suggesting to turn off interpolation: 780 if (interpolationHint == sun_awt_SunHints_INTVAL_INTERPOLATION_NEAREST_NEIGHBOR) 781 { 782 interpolationQuality = kCGInterpolationNone; 783 } 784 else if ((interpolationHint >= sun_awt_SunHints_INTVAL_INTERPOLATION_BICUBIC) || (renderingHint >= sun_awt_SunHints_INTVAL_RENDER_QUALITY)) 785 { 786 // Use >= just in case Sun adds some hint values in the future - this check wouldn't fall apart then: 787 interpolationQuality = kCGInterpolationHigh; 788 } 789 else if (interpolationHint == sun_awt_SunHints_INTVAL_INTERPOLATION_BILINEAR) 790 { 791 interpolationQuality = kCGInterpolationLow; 792 } 793 else if (renderingHint == sun_awt_SunHints_INTVAL_RENDER_SPEED) 794 { 795 interpolationQuality = kCGInterpolationNone; 796 } 797 // else interpolationHint == -1 || renderingHint == sun_awt_SunHints_INTVAL_CSURFACE_DEFAULT --> kCGInterpolationDefault 798 CGContextSetInterpolationQuality(cgRef, interpolationQuality); 799 qsdo->graphicsStateInfo.interpolation = interpolationQuality; 800 801 // antialiasing 802 BOOL antialiased = (antialiasHint == sun_awt_SunHints_INTVAL_ANTIALIAS_ON); 803 CGContextSetShouldAntialias(cgRef, antialiased); 804 qsdo->graphicsStateInfo.antialiased = antialiased; 805 } 806 807 if ((everyThingChanged == YES) || (strokeChanged == YES)) 808 { 809 qsdo->graphicsStateInfo.simpleStroke = YES; 810 811 CGFloat linewidth = javaFloatGraphicsStates[sun_java2d_OSXSurfaceData_kStrokeWidthIndex]; 812 jint linejoin = javaGraphicsStates[sun_java2d_OSXSurfaceData_kStrokeJoinIndex]; 813 jint linecap = javaGraphicsStates[sun_java2d_OSXSurfaceData_kStrokeCapIndex]; 814 CGFloat miterlimit = javaFloatGraphicsStates[sun_java2d_OSXSurfaceData_kStrokeLimitIndex]; 815 jobject dasharray = ((*env)->GetObjectArrayElement(env, qsdo->javaGraphicsStatesObjects, sun_java2d_OSXSurfaceData_kStrokeDashArrayIndex)); 816 CGFloat dashphase = javaFloatGraphicsStates[sun_java2d_OSXSurfaceData_kStrokeDashPhaseIndex]; 817 818 if (linewidth == 0.0f) 819 { 820 linewidth = (CGFloat)-109.05473e+14; // Don't ask ! 821 } 822 CGContextSetLineWidth(cgRef, linewidth); 823 824 CGLineCap cap; 825 switch (linecap) 826 { 827 case java_awt_BasicStroke_CAP_BUTT: 828 qsdo->graphicsStateInfo.simpleStroke = NO; 829 cap = kCGLineCapButt; 830 break; 831 case java_awt_BasicStroke_CAP_ROUND: 832 qsdo->graphicsStateInfo.simpleStroke = NO; 833 cap = kCGLineCapRound; 834 break; 835 case java_awt_BasicStroke_CAP_SQUARE: 836 default: 837 cap = kCGLineCapSquare; 838 break; 839 } 840 CGContextSetLineCap(cgRef, cap); 841 842 CGLineJoin join; 843 switch (linejoin) 844 { 845 case java_awt_BasicStroke_JOIN_ROUND: 846 qsdo->graphicsStateInfo.simpleStroke = NO; 847 join = kCGLineJoinRound; 848 break; 849 case java_awt_BasicStroke_JOIN_BEVEL: 850 qsdo->graphicsStateInfo.simpleStroke = NO; 851 join = kCGLineJoinBevel; 852 break; 853 case java_awt_BasicStroke_JOIN_MITER: 854 default: 855 join = kCGLineJoinMiter; 856 break; 857 } 858 CGContextSetLineJoin(cgRef, join); 859 CGContextSetMiterLimit(cgRef, miterlimit); 860 861 if (dasharray != NULL) 862 { 863 qsdo->graphicsStateInfo.simpleStroke = NO; 864 jint length = (*env)->GetArrayLength(env, dasharray); 865 jfloat* jdashes = (jfloat*)(*env)->GetPrimitiveArrayCritical(env, dasharray, NULL); 866 if (jdashes == NULL) { 867 CGContextSetLineDash(cgRef, 0, NULL, 0); 868 return; 869 } 870 CGFloat* dashes = (CGFloat*)malloc(sizeof(CGFloat)*length); 871 if (dashes != NULL) 872 { 873 jint i; 874 for (i=0; i<length; i++) 875 { 876 dashes[i] = (CGFloat)jdashes[i]; 877 } 878 } 879 else 880 { 881 dashphase = 0; 882 length = 0; 883 } 884 CGContextSetLineDash(cgRef, dashphase, dashes, length); 885 if (dashes != NULL) 886 { 887 free(dashes); 888 } 889 (*env)->ReleasePrimitiveArrayCritical(env, dasharray, jdashes, 0); 890 } 891 else 892 { 893 CGContextSetLineDash(cgRef, 0, NULL, 0); 894 } 895 } 896 897 BOOL cocoaPaint = (javaGraphicsStates[sun_java2d_OSXSurfaceData_kColorStateIndex] == sun_java2d_OSXSurfaceData_kColorSystem); 898 BOOL complexPaint = (javaGraphicsStates[sun_java2d_OSXSurfaceData_kColorStateIndex] == sun_java2d_OSXSurfaceData_kColorGradient) || 899 (javaGraphicsStates[sun_java2d_OSXSurfaceData_kColorStateIndex] == sun_java2d_OSXSurfaceData_kColorTexture); 900 if ((everyThingChanged == YES) || (paintChanged == YES) || (cocoaPaint == YES) || (complexPaint == YES)) 901 { 902 // rdar://problem/5214320 903 // Gradient fills of Java GeneralPath don't respect the even odd winding rule (quartz pipeline). 904 // Notice the side effect of the stmt after this if-block. 905 if (renderType == SD_EOFill) { 906 qsdo->isEvenOddFill = YES; 907 } 908 909 renderType = SetUpPaint(env, qsdo, renderType); 910 } 911 912 qsdo->renderType = renderType; 913} 914 915void setupGradient(JNIEnv *env, QuartzSDOps* qsdo, jfloat* javaFloatGraphicsStates) 916{ 917 static const CGFloat kColorConversionMultiplier = 1.0f/255.0f; 918 qsdo->gradientInfo = (StateGradientInfo*)malloc(sizeof(StateGradientInfo)); 919 if (qsdo->gradientInfo == NULL) 920 { 921 JNI_COCOA_THROW_OOME(env, "Failed to malloc memory for gradient paint"); 922 } 923 924 qsdo->graphicsStateInfo.simpleStroke = NO; 925 qsdo->graphicsStateInfo.simpleColor = NO; 926 927 qsdo->gradientInfo->start.x = javaFloatGraphicsStates[sun_java2d_OSXSurfaceData_kColorx1Index]; 928 qsdo->gradientInfo->start.y = javaFloatGraphicsStates[sun_java2d_OSXSurfaceData_kColory1Index]; 929 qsdo->gradientInfo->end.x = javaFloatGraphicsStates[sun_java2d_OSXSurfaceData_kColorx2Index]; 930 qsdo->gradientInfo->end.y = javaFloatGraphicsStates[sun_java2d_OSXSurfaceData_kColory2Index]; 931 932 jobject colorArray = ((*env)->GetObjectArrayElement(env, qsdo->javaGraphicsStatesObjects, sun_java2d_OSXSurfaceData_kColorArrayIndex)); 933 if (colorArray != NULL) 934 { 935 jint length = (*env)->GetArrayLength(env, colorArray); 936 937 jint* jcolorData = (jint*)(*env)->GetPrimitiveArrayCritical(env, colorArray, NULL); 938 qsdo->gradientInfo->colordata = (CGFloat*)malloc(sizeof(CGFloat)*4*length); 939 memset(qsdo->gradientInfo->colordata, 0, sizeof(CGFloat)*4*length); 940 if (jcolorData != NULL) 941 { 942 int i; 943 for (i=0; i<length; i++) 944 { 945 qsdo->gradientInfo->colordata[i*4] = ((jcolorData[i]>>16)&0xff)*kColorConversionMultiplier; 946 947 qsdo->gradientInfo->colordata[i*4+1] = ((jcolorData[i]>>8)&0xff)*kColorConversionMultiplier; 948 949 qsdo->gradientInfo->colordata[i*4+2] = ((jcolorData[i]>>0)&0xff)*kColorConversionMultiplier; 950 951 qsdo->gradientInfo->colordata[i*4+3] = ((jcolorData[i]>>24)&0xff)*kColorConversionMultiplier; 952 } 953 } 954 (*env)->ReleasePrimitiveArrayCritical(env, colorArray, jcolorData, 0); 955 } 956 jobject fractionsArray = ((*env)->GetObjectArrayElement(env, qsdo->javaGraphicsStatesObjects, sun_java2d_OSXSurfaceData_kFractionsArrayIndex)); 957 if (fractionsArray != NULL) 958 { 959 jint length = (*env)->GetArrayLength(env, fractionsArray); 960 qsdo->gradientInfo->fractionsLength = length; 961 962 jfloat* jfractionsData = (jfloat*)(*env)->GetPrimitiveArrayCritical(env, fractionsArray, NULL); 963 if (jfractionsData != NULL) 964 { 965 int i; 966 qsdo->gradientInfo->fractionsdata = (CGFloat *)malloc(sizeof(CGFloat) *length); 967 memset(qsdo->gradientInfo->fractionsdata, 0, sizeof(CGFloat)*length); 968 for (i=0; i<length; i++) 969 { 970 qsdo->gradientInfo->fractionsdata[i] = jfractionsData[i]; 971 } 972 (*env)->ReleasePrimitiveArrayCritical(env, fractionsArray, jfractionsData, 0); 973 } 974 } 975} 976 977SDRenderType SetUpPaint(JNIEnv *env, QuartzSDOps *qsdo, SDRenderType renderType) 978{ 979 CGContextRef cgRef = qsdo->cgRef; 980 981 jint *javaGraphicsStates = qsdo->javaGraphicsStates; 982 jfloat *javaFloatGraphicsStates = (jfloat*)(qsdo->javaGraphicsStates); 983 984 static const CGFloat kColorConversionMultiplier = 1.0f/255.0f; 985 jint colorState = javaGraphicsStates[sun_java2d_OSXSurfaceData_kColorStateIndex]; 986 987 switch (colorState) 988 { 989 case sun_java2d_OSXSurfaceData_kColorSimple: 990 { 991 if (qsdo->graphicsStateInfo.simpleColor == NO) 992 { 993 setDefaultColorSpace(cgRef); 994 } 995 qsdo->graphicsStateInfo.simpleColor = YES; 996 997 // sets the color on the CGContextRef (CGContextSetStrokeColorWithColor/CGContextSetFillColorWithColor) 998 setCachedColor(qsdo, javaGraphicsStates[sun_java2d_OSXSurfaceData_kColorRGBValueIndex]); 999 1000 break; 1001 } 1002 case sun_java2d_OSXSurfaceData_kColorSystem: 1003 { 1004 qsdo->graphicsStateInfo.simpleStroke = NO; 1005 // All our custom Colors are NSPatternColorSpace so we are complex colors! 1006 qsdo->graphicsStateInfo.simpleColor = NO; 1007 1008 NSColor *color = nil; 1009 /* TODO:BG 1010 { 1011 color = getColor(javaGraphicsStates[sun_java2d_OSXSurfaceData_kColorIndexValueIndex]); 1012 } 1013 */ 1014 [color set]; 1015 break; 1016 } 1017 case sun_java2d_OSXSurfaceData_kColorGradient: 1018 { 1019 qsdo->shadingInfo = (StateShadingInfo*)malloc(sizeof(StateShadingInfo)); 1020 if (qsdo->shadingInfo == NULL) 1021 { 1022 JNI_COCOA_THROW_OOME(env, "Failed to malloc memory for gradient paint"); 1023 } 1024 1025 qsdo->graphicsStateInfo.simpleStroke = NO; 1026 qsdo->graphicsStateInfo.simpleColor = NO; 1027 1028 renderType = SD_Shade; 1029 1030 qsdo->shadingInfo->start.x = javaFloatGraphicsStates[sun_java2d_OSXSurfaceData_kColorx1Index]; 1031 qsdo->shadingInfo->start.y = javaFloatGraphicsStates[sun_java2d_OSXSurfaceData_kColory1Index]; 1032 qsdo->shadingInfo->end.x = javaFloatGraphicsStates[sun_java2d_OSXSurfaceData_kColorx2Index]; 1033 qsdo->shadingInfo->end.y = javaFloatGraphicsStates[sun_java2d_OSXSurfaceData_kColory2Index]; 1034 jint c1 = javaGraphicsStates[sun_java2d_OSXSurfaceData_kColorRGBValue1Index]; 1035 qsdo->shadingInfo->colors[0] = ((c1>>16)&0xff)*kColorConversionMultiplier; 1036 qsdo->shadingInfo->colors[1] = ((c1>>8)&0xff)*kColorConversionMultiplier; 1037 qsdo->shadingInfo->colors[2] = ((c1>>0)&0xff)*kColorConversionMultiplier; 1038 qsdo->shadingInfo->colors[3] = ((c1>>24)&0xff)*kColorConversionMultiplier; 1039 jint c2 = javaGraphicsStates[sun_java2d_OSXSurfaceData_kColorRGBValue2Index]; 1040 qsdo->shadingInfo->colors[4] = ((c2>>16)&0xff)*kColorConversionMultiplier; 1041 qsdo->shadingInfo->colors[5] = ((c2>>8)&0xff)*kColorConversionMultiplier; 1042 qsdo->shadingInfo->colors[6] = ((c2>>0)&0xff)*kColorConversionMultiplier; 1043 qsdo->shadingInfo->colors[7] = ((c2>>24)&0xff)*kColorConversionMultiplier; 1044 qsdo->shadingInfo->cyclic = (javaGraphicsStates[sun_java2d_OSXSurfaceData_kColorIsCyclicIndex] == sun_java2d_OSXSurfaceData_kColorCyclic); 1045 1046 break; 1047 } 1048 case sun_java2d_OSXSurfaceData_kColorLinearGradient: 1049 { 1050 renderType = SD_LinearGradient; 1051 setupGradient(env, qsdo, javaFloatGraphicsStates); 1052 break; 1053 } 1054 1055 case sun_java2d_OSXSurfaceData_kColorRadialGradient: 1056 { 1057 renderType = SD_RadialGradient; 1058 setupGradient(env, qsdo, javaFloatGraphicsStates); 1059 qsdo->gradientInfo->radius = javaFloatGraphicsStates[sun_java2d_OSXSurfaceData_kRadiusIndex]; 1060 break; 1061 } 1062 1063 case sun_java2d_OSXSurfaceData_kColorTexture: 1064 { 1065 qsdo->patternInfo = (StatePatternInfo*)malloc(sizeof(StatePatternInfo)); 1066 if (qsdo->patternInfo == NULL) 1067 { 1068 JNI_COCOA_THROW_OOME(env, "Failed to malloc memory for texture paint"); 1069 } 1070 1071 qsdo->graphicsStateInfo.simpleStroke = NO; 1072 qsdo->graphicsStateInfo.simpleColor = NO; 1073 1074 renderType = SD_Pattern; 1075 1076 qsdo->patternInfo->tx = javaFloatGraphicsStates[sun_java2d_OSXSurfaceData_kColortxIndex]; 1077 qsdo->patternInfo->ty = javaFloatGraphicsStates[sun_java2d_OSXSurfaceData_kColortyIndex]; 1078 qsdo->patternInfo->sx = javaFloatGraphicsStates[sun_java2d_OSXSurfaceData_kColorsxIndex]; 1079 if (qsdo->patternInfo->sx == 0.0f) 1080 { 1081 return SD_Fill; // 0 is an invalid value, fill argb rect 1082 } 1083 qsdo->patternInfo->sy = javaFloatGraphicsStates[sun_java2d_OSXSurfaceData_kColorsyIndex]; 1084 if (qsdo->patternInfo->sy == 0.0f) 1085 { 1086 return SD_Fill; // 0 is an invalid value, fill argb rect 1087 } 1088 qsdo->patternInfo->width = javaGraphicsStates[sun_java2d_OSXSurfaceData_kColorWidthIndex]; 1089 qsdo->patternInfo->height = javaGraphicsStates[sun_java2d_OSXSurfaceData_kColorHeightIndex]; 1090 1091 jobject sData = ((*env)->GetObjectArrayElement(env, qsdo->javaGraphicsStatesObjects, sun_java2d_OSXSurfaceData_kTextureImageIndex)); //deleted next time through SetUpPaint and not before ( radr://3913190 ) 1092 if (sData != NULL) 1093 { 1094 qsdo->patternInfo->sdata = (*env)->NewGlobalRef(env, sData); 1095 if (qsdo->patternInfo->sdata == NULL) 1096 { 1097 renderType = SD_Fill; 1098 } 1099 } 1100 else 1101 { 1102 renderType = SD_Fill; 1103 } 1104 1105 break; 1106 } 1107 } 1108 1109 return renderType; 1110} 1111 1112#pragma mark 1113#pragma mark --- Shape Drawing Code --- 1114 1115SDRenderType DoShapeUsingCG(CGContextRef cgRef, jint *types, jfloat *coords, jint numtypes, BOOL fill, CGFloat offsetX, CGFloat offsetY) 1116{ 1117//fprintf(stderr, "DoShapeUsingCG fill=%d\n", (jint)fill); 1118 SDRenderType renderType = SD_Nothing; 1119 1120 if (gAdjustForJavaDrawing != YES) 1121 { 1122 offsetX = 0.0f; 1123 offsetY = 0.0f; 1124 } 1125 1126 if (fill == YES) 1127 { 1128 renderType = SD_Fill; 1129 } 1130 else 1131 { 1132 renderType = SD_Stroke; 1133 } 1134 1135 if (numtypes > 0) 1136 { 1137 BOOL needNewSubpath = NO; 1138 1139 CGContextBeginPath(cgRef); // create new path 1140//fprintf(stderr, " CGContextBeginPath\n"); 1141 1142 jint index = 0; 1143 CGFloat mx = 0.0f, my = 0.0f, x1 = 0.0f, y1 = 0.0f, cpx1 = 0.0f, cpy1 = 0.0f, cpx2 = 0.0f, cpy2 = 0.0f; 1144 jint i; 1145 1146 mx = (CGFloat)coords[index++] + offsetX; 1147 my = (CGFloat)coords[index++] + offsetY; 1148 CGContextMoveToPoint(cgRef, mx, my); 1149 1150 for (i=1; i<numtypes; i++) 1151 { 1152 jint pathType = types[i]; 1153 1154 if (needNewSubpath == YES) 1155 { 1156 needNewSubpath = NO; 1157 switch (pathType) 1158 { 1159 case java_awt_geom_PathIterator_SEG_LINETO: 1160 case java_awt_geom_PathIterator_SEG_QUADTO: 1161 case java_awt_geom_PathIterator_SEG_CUBICTO: 1162//fprintf(stderr, " forced CGContextMoveToPoint (%f, %f)\n", mx, my); 1163 CGContextMoveToPoint(cgRef, mx, my); // force new subpath 1164 break; 1165 } 1166 } 1167 1168 switch (pathType) 1169 { 1170 case java_awt_geom_PathIterator_SEG_MOVETO: 1171 mx = x1 = (CGFloat)coords[index++] + offsetX; 1172 my = y1 = (CGFloat)coords[index++] + offsetY; 1173 CGContextMoveToPoint(cgRef, x1, y1); // start new subpath 1174//fprintf(stderr, " SEG_MOVETO CGContextMoveToPoint (%f, %f)\n", x1, y1); 1175 break; 1176 case java_awt_geom_PathIterator_SEG_LINETO: 1177 x1 = (CGFloat)coords[index++] + offsetX; 1178 y1 = (CGFloat)coords[index++] + offsetY; 1179 CGContextAddLineToPoint(cgRef, x1, y1); 1180//fprintf(stderr, " SEG_LINETO CGContextAddLineToPoint (%f, %f)\n", x1, y1); 1181 break; 1182 case java_awt_geom_PathIterator_SEG_QUADTO: 1183 cpx1 = (CGFloat)coords[index++] + offsetX; 1184 cpy1 = (CGFloat)coords[index++] + offsetY; 1185 x1 = (CGFloat)coords[index++] + offsetX; 1186 y1 = (CGFloat)coords[index++]+ offsetY; 1187 CGContextAddQuadCurveToPoint(cgRef, cpx1, cpy1, x1, y1); 1188//fprintf(stderr, " SEG_QUADTO CGContextAddQuadCurveToPoint (%f, %f), (%f, %f)\n", cpx1, cpy1, x1, y1); 1189 break; 1190 case java_awt_geom_PathIterator_SEG_CUBICTO: 1191 cpx1 = (CGFloat)coords[index++] + offsetX; 1192 cpy1 = (CGFloat)coords[index++] + offsetY; 1193 cpx2 = (CGFloat)coords[index++] + offsetX; 1194 cpy2 = (CGFloat)coords[index++] + offsetY; 1195 x1 = (CGFloat)coords[index++] + offsetX; 1196 y1 = (CGFloat)coords[index++] + offsetY; 1197 CGContextAddCurveToPoint(cgRef, cpx1, cpy1, cpx2, cpy2, x1, y1); 1198//fprintf(stderr, " SEG_CUBICTO CGContextAddCurveToPoint (%f, %f), (%f, %f), (%f, %f)\n", cpx1, cpy1, cpx2, cpy2, x1, y1); 1199 break; 1200 case java_awt_geom_PathIterator_SEG_CLOSE: 1201 CGContextClosePath(cgRef); // close subpath 1202 needNewSubpath = YES; 1203//fprintf(stderr, " SEG_CLOSE CGContextClosePath\n"); 1204 break; 1205 } 1206 } 1207 } 1208 1209 return renderType; 1210} 1211 1212void CompleteCGContext(JNIEnv *env, QuartzSDOps *qsdo) 1213{ 1214PRINT(" CompleteCGContext") 1215 switch (qsdo->renderType) 1216 { 1217 case SD_Nothing: 1218 break; 1219 1220 case SD_Stroke: 1221 if (CGContextIsPathEmpty(qsdo->cgRef) == 0) 1222 { 1223 CGContextStrokePath(qsdo->cgRef); 1224 } 1225 break; 1226 1227 case SD_Fill: 1228 if (CGContextIsPathEmpty(qsdo->cgRef) == 0) 1229 { 1230 CGContextFillPath(qsdo->cgRef); 1231 } 1232 break; 1233 1234 case SD_Shade: 1235 if (CGContextIsPathEmpty(qsdo->cgRef) == 0) 1236 { 1237 contextGradientPath(qsdo); 1238 } 1239 break; 1240 1241 case SD_LinearGradient: 1242 if (CGContextIsPathEmpty(qsdo->cgRef) == 0) 1243 { 1244 contextQuartzLinearGradientPath(qsdo); 1245 } 1246 break; 1247 1248 case SD_RadialGradient: 1249 if (CGContextIsPathEmpty(qsdo->cgRef) == 0) 1250 { 1251 contextQuartzRadialGradientPath(qsdo); 1252 } 1253 break; 1254 1255 case SD_Pattern: 1256 if (CGContextIsPathEmpty(qsdo->cgRef) == 0) 1257 { 1258 contextTexturePath(env, qsdo); 1259 } 1260 break; 1261 1262 case SD_EOFill: 1263 if (CGContextIsPathEmpty(qsdo->cgRef) == 0) 1264 { 1265 CGContextEOFillPath(qsdo->cgRef); 1266 } 1267 break; 1268 1269 case SD_Image: 1270 break; 1271 1272 case SD_Text: 1273 break; 1274 1275 case SD_CopyArea: 1276 break; 1277 1278 case SD_Queue: 1279 break; 1280 1281 case SD_External: 1282 break; 1283 } 1284 1285 if (qsdo->shadingInfo != NULL) { 1286 gradientPaintReleaseFunction(qsdo->shadingInfo); 1287 qsdo->shadingInfo = NULL; 1288 } 1289 if (qsdo->gradientInfo != NULL) { 1290 gradientPaintReleaseFunction(qsdo->gradientInfo); 1291 qsdo->gradientInfo = NULL; 1292 } 1293} 1294