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