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 contextQuartzGradientPath(QuartzSDOps* qsdo) 272 { 273 274 PRINT(" contextQuartzGradientPath"); 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 (int i = 0; i < num_locations; i++) { 288 locations[i] = gradientInfo->fractionsdata[i]; 289 //fprintf(stderr, "locations[%d] %f\n", i, locations[i]); 290 } 291 for (i = 0; i < component_size; i++) { 292 components[i] = gradientInfo->colordata[i]; 293 //fprintf(stderr, "components[%d] %f, gradientInfo->colordata[%d] %f\n", 294 // i, components[i], i, gradientInfo->colordata[i]); 295 } 296 CGContextSaveGState(cgRef); 297 gradient = CGGradientCreateWithColorComponents(colorspace, components, locations, num_locations); 298 //fprintf(stderr, "gradientInfo->start.x %f, gradientInfo->start.y %f\n", 299 // gradientInfo->start.x, gradientInfo->start.y); 300 //fprintf(stderr, "gradientInfo->end.x %f, gradientInfo->end.y %f\n", 301 // gradientInfo->end.x, gradientInfo->end.y); 302 if (qsdo->isEvenOddFill) { 303 CGContextEOClip(cgRef); 304 } else { 305 CGContextClip(cgRef); 306 } 307 CGContextDrawLinearGradient(cgRef, gradient, gradientInfo->start, gradientInfo->end, 0); 308 309 CGContextRestoreGState(cgRef); 310 CGColorSpaceRelease(colorspace); 311 CGGradientRelease(gradient); 312 free(locations); 313 free(gradientInfo->colordata); 314 free(gradientInfo->fractionsdata); 315 } 316 317 static inline void contextGradientPath(QuartzSDOps* qsdo) 318 { 319 PRINT(" ContextGradientPath") 320 321 CGContextRef cgRef = qsdo->cgRef; 322 StateShadingInfo* shadingInfo = qsdo->shadingInfo; 323 324 CGRect bounds = CGContextGetClipBoundingBox(cgRef); 325 326 static const CGFloat domain[2] = {0.0f, 1.0f}; 327 static const CGFloat range[8] = {0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f}; 328 CGColorSpaceRef colorspace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB); 329 CGFunctionRef shadingFunc = NULL; 330 CGShadingRef shading = NULL; 331 if (shadingInfo->cyclic == NO) 332 { 333 static const CGFunctionCallbacks callbacks = {0, &gradientLinearPaintEvaluateFunction, &gradientPaintReleaseFunction}; 334 shadingFunc = CGFunctionCreate((void *)shadingInfo, 1, domain, 4, range, &callbacks); 335 shading = CGShadingCreateAxial(colorspace, shadingInfo->start, shadingInfo->end, shadingFunc, 1, 1); 336 } 337 else 338 { 339 //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); 340 // need to extend the line start-end 341 342 CGFloat x1 = shadingInfo->start.x; 343 CGFloat y1 = shadingInfo->start.y; 344 CGFloat x2 = shadingInfo->end.x; 345 CGFloat y2 = shadingInfo->end.y; 346 //fprintf(stderr, "GIVEN x1=%f, y1=%f x2=%f, y2=%f\n", x1, y1, x2, y2); 347 348 if (x1 == x2) 349 { 350 y1 = bounds.origin.y; 351 y2 = y1 + bounds.size.height; 352 } 353 else if (y1 == y2) 354 { 355 x1 = bounds.origin.x; 356 x2 = x1 + bounds.size.width; 357 } 358 else 359 { 360 // find the original line function y = mx + c 361 CGFloat m1 = (y2-y1)/(x2-x1); 362 CGFloat c1 = y1 - m1*x1; 363 //fprintf(stderr, " m1=%f, c1=%f\n", m1, c1); 364 365 // a line perpendicular to the original one will have the slope 366 CGFloat m2 = -(1/m1); 367 //fprintf(stderr, " m2=%f\n", m2); 368 369 // find the only 2 possible lines perpendicular to the original line, passing the two top corners of the bounding box 370 CGFloat x1A = bounds.origin.x; 371 CGFloat y1A = bounds.origin.y; 372 CGFloat c1A = y1A - m2*x1A; 373 //fprintf(stderr, " x1A=%f, y1A=%f, c1A=%f\n", x1A, y1A, c1A); 374 CGFloat x1B = bounds.origin.x+bounds.size.width; 375 CGFloat y1B = bounds.origin.y; 376 CGFloat c1B = y1B - m2*x1B; 377 //fprintf(stderr, " x1B=%f, y1B=%f, c1B=%f\n", x1B, y1B, c1B); 378 379 // find the crossing points of the original line and the two lines we computed above to find the new possible starting points 380 CGFloat x1Anew = (c1A-c1)/(m1-m2); 381 CGFloat y1Anew = m2*x1Anew + c1A; 382 CGFloat x1Bnew = (c1B-c1)/(m1-m2); 383 CGFloat y1Bnew = m2*x1Bnew + c1B; 384 //fprintf(stderr, "NEW x1Anew=%f, y1Anew=%f x1Bnew=%f, y1Bnew=%f\n", x1Anew, y1Anew, x1Bnew, y1Bnew); 385 386 // select the new starting point 387 if (y1Anew <= y1Bnew) 388 { 389 x1 = x1Anew; 390 y1 = y1Anew; 391 } 392 else 393 { 394 x1 = x1Bnew; 395 y1 = y1Bnew; 396 } 397 //fprintf(stderr, "--- NEW x1=%f, y1=%f\n", x1, y1); 398 399 // find the only 2 possible lines perpendicular to the original line, passing the two bottom corners of the bounding box 400 CGFloat x2A = bounds.origin.x; 401 CGFloat y2A = bounds.origin.y+bounds.size.height; 402 CGFloat c2A = y2A - m2*x2A; 403 //fprintf(stderr, " x2A=%f, y2A=%f, c2A=%f\n", x2A, y2A, c2A); 404 CGFloat x2B = bounds.origin.x+bounds.size.width; 405 CGFloat y2B = bounds.origin.y+bounds.size.height; 406 CGFloat c2B = y2B - m2*x2B; 407 //fprintf(stderr, " x2B=%f, y2B=%f, c2B=%f\n", x2B, y2B, c2B); 408 409 // find the crossing points of the original line and the two lines we computed above to find the new possible ending points 410 CGFloat x2Anew = (c2A-c1)/(m1-m2); 411 CGFloat y2Anew = m2*x2Anew + c2A; 412 CGFloat x2Bnew = (c2B-c1)/(m1-m2); 413 CGFloat y2Bnew = m2*x2Bnew + c2B; 414 //fprintf(stderr, "NEW x2Anew=%f, y2Anew=%f x2Bnew=%f, y2Bnew=%f\n", x2Anew, y2Anew, x2Bnew, y2Bnew); 415 416 // select the new ending point 417 if (y2Anew >= y2Bnew) 418 { 419 x2 = x2Anew; 420 y2 = y2Anew; 421 } 422 else 423 { 424 x2 = x2Bnew; 425 y2 = y2Bnew; 426 } 427 //fprintf(stderr, "--- NEW x2=%f, y2=%f\n", x2, y2); 428 } 429 430 qsdo->shadingInfo->period = sqrt(pow(shadingInfo->end.x-shadingInfo->start.x, 2.0) + pow(shadingInfo->end.y-shadingInfo->start.y, 2.0)); 431 if ((qsdo->shadingInfo->period != 0)) 432 { 433 // compute segment lengths that we will need for the gradient function 434 qsdo->shadingInfo->length = sqrt(pow(x2-x1, 2.0) + pow(y2-y1, 2.0)); 435 qsdo->shadingInfo->offset = sqrt(pow(shadingInfo->start.x-x1, 2.0) + pow(shadingInfo->start.y-y1, 2.0)); 436 //fprintf(stderr, "length=%f, period=%f, offset=%f\n", qsdo->shadingInfo->length, qsdo->shadingInfo->period, qsdo->shadingInfo->offset); 437 438 CGPoint newStart = {x1, y1}; 439 CGPoint newEnd = {x2, y2}; 440 441 static const CGFunctionCallbacks callbacks = {0, &gradientCyclicPaintEvaluateFunction, &gradientPaintReleaseFunction}; 442 shadingFunc = CGFunctionCreate((void *)shadingInfo, 1, domain, 4, range, &callbacks); 443 shading = CGShadingCreateAxial(colorspace, newStart, newEnd, shadingFunc, 0, 0); 444 } 445 } 446 CGColorSpaceRelease(colorspace); 447 448 if (shadingFunc != NULL) 449 { 450 CGContextSaveGState(cgRef); 451 452 // rdar://problem/5214320 453 // Gradient fills of Java GeneralPath don't respect the even odd winding rule (quartz pipeline). 454 if (qsdo->isEvenOddFill) { 455 CGContextEOClip(cgRef); 456 } else { 457 CGContextClip(cgRef); 458 } 459 CGContextDrawShading(cgRef, shading); 460 461 CGContextRestoreGState(cgRef); 462 CGShadingRelease(shading); 463 CGFunctionRelease(shadingFunc); 464 qsdo->shadingInfo = NULL; 465 } 466 } 467 468 #pragma mark 469 #pragma mark --- Texture --- 470 471 // this function MUST NOT be inlined! 472 void texturePaintEvaluateFunction(void *info, CGContextRef cgRef) 473 { 474 JNIEnv* env = [ThreadUtilities getJNIEnvUncached]; 475 476 StatePatternInfo* patternInfo = (StatePatternInfo*)info; 477 ImageSDOps* isdo = LockImage(env, patternInfo->sdata); 478 479 makeSureImageIsCreated(isdo); 480 CGContextDrawImage(cgRef, CGRectMake(0.0f, 0.0f, patternInfo->width, patternInfo->height), isdo->imgRef); 481 482 UnlockImage(env, isdo); 483 } 484 485 // this function MUST NOT be inlined! 486 void texturePaintReleaseFunction(void *info) 487 { 488 PRINT(" texturePaintReleaseFunction") 489 JNIEnv* env = [ThreadUtilities getJNIEnvUncached]; 490 491 StatePatternInfo* patternInfo = (StatePatternInfo*)info; 492 (*env)->DeleteGlobalRef(env, patternInfo->sdata); 493 494 free(info); 495 } 496 497 static inline void contextTexturePath(JNIEnv* env, QuartzSDOps* qsdo) 498 { 499 PRINT(" ContextTexturePath") 500 CGContextRef cgRef = qsdo->cgRef; 501 StatePatternInfo* patternInfo = qsdo->patternInfo; 502 503 CGAffineTransform ctm = CGContextGetCTM(cgRef); 504 CGAffineTransform ptm = {patternInfo->sx, 0.0f, 0.0f, -patternInfo->sy, patternInfo->tx, patternInfo->ty}; 505 CGAffineTransform tm = CGAffineTransformConcat(ptm, ctm); 506 CGFloat xStep = (CGFloat)qsdo->patternInfo->width; 507 CGFloat yStep = (CGFloat)qsdo->patternInfo->height; 508 CGPatternTiling tiling = kCGPatternTilingNoDistortion; 509 BOOL isColored = YES; 510 static const CGPatternCallbacks callbacks = {0, &texturePaintEvaluateFunction, &texturePaintReleaseFunction}; 511 CGPatternRef pattern = CGPatternCreate((void*)patternInfo, CGRectMake(0.0f, 0.0f, xStep, yStep), tm, xStep, yStep, tiling, isColored, &callbacks); 512 513 CGColorSpaceRef colorspace = CGColorSpaceCreatePattern(NULL); 514 static const CGFloat alpha = 1.0f; 515 516 CGContextSaveGState(cgRef); 517 518 CGContextSetFillColorSpace(cgRef, colorspace); 519 CGContextSetFillPattern(cgRef, pattern, &alpha); 520 CGContextSetRGBStrokeColor(cgRef, 0.0f, 0.0f, 0.0f, 1.0f); 521 CGContextSetPatternPhase(cgRef, CGSizeMake(0.0f, 0.0f)); 522 // rdar://problem/5214320 523 // Gradient fills of Java GeneralPath don't respect the even odd winding rule (quartz pipeline). 524 if (qsdo->isEvenOddFill) { 525 CGContextEOFillPath(cgRef); 526 } else { 527 CGContextFillPath(cgRef); 528 } 529 530 CGContextRestoreGState(cgRef); 531 532 CGColorSpaceRelease(colorspace); 533 CGPatternRelease(pattern); 534 535 qsdo->patternInfo = NULL; 536 } 537 538 #pragma mark 539 #pragma mark --- Context Setup --- 540 541 static inline void setDefaultColorSpace(CGContextRef cgRef) 542 { 543 static CGColorSpaceRef colorspace = NULL; 544 if (colorspace == NULL) 545 { 546 colorspace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB); 547 } 548 CGContextSetStrokeColorSpace(cgRef, colorspace); 549 CGContextSetFillColorSpace(cgRef, colorspace); 550 } 551 552 void SetUpCGContext(JNIEnv *env, QuartzSDOps *qsdo, SDRenderType renderType) 553 { 554 PRINT(" SetUpCGContext") 555 CGContextRef cgRef = qsdo->cgRef; 556 //fprintf(stderr, "%p ", cgRef); 557 jint *javaGraphicsStates = qsdo->javaGraphicsStates; 558 jfloat *javaFloatGraphicsStates = (jfloat*)(qsdo->javaGraphicsStates); 559 560 jint changeFlags = javaGraphicsStates[sun_java2d_OSXSurfaceData_kChangeFlagIndex]; 561 BOOL everyThingChanged = qsdo->newContext || (changeFlags == sun_java2d_OSXSurfaceData_kEverythingChangedFlag); 562 BOOL clipChanged = everyThingChanged || ((changeFlags&sun_java2d_OSXSurfaceData_kClipChangedBit) != 0); 563 BOOL transformChanged = everyThingChanged || ((changeFlags&sun_java2d_OSXSurfaceData_kCTMChangedBit) != 0); 564 BOOL paintChanged = everyThingChanged || ((changeFlags&sun_java2d_OSXSurfaceData_kColorChangedBit) != 0); 565 BOOL compositeChanged = everyThingChanged || ((changeFlags&sun_java2d_OSXSurfaceData_kCompositeChangedBit) != 0); 566 BOOL strokeChanged = everyThingChanged || ((changeFlags&sun_java2d_OSXSurfaceData_kStrokeChangedBit) != 0); 567 // BOOL fontChanged = everyThingChanged || ((changeFlags&sun_java2d_OSXSurfaceData_kFontChangedBit) != 0); 568 BOOL renderingHintsChanged = everyThingChanged || ((changeFlags&sun_java2d_OSXSurfaceData_kHintsChangedBit) != 0); 569 570 //fprintf(stderr, "SetUpCGContext cgRef=%p new=%d changeFlags=%d, everyThingChanged=%d clipChanged=%d transformChanged=%d\n", 571 // cgRef, qsdo->newContext, changeFlags, everyThingChanged, clipChanged, transformChanged); 572 573 if ((everyThingChanged == YES) || (clipChanged == YES) || (transformChanged == YES)) 574 { 575 everyThingChanged = YES; // in case clipChanged or transformChanged 576 577 CGContextRestoreGState(cgRef); // restore to the original state 578 579 CGContextSaveGState(cgRef); // make our local copy of the state 580 581 setDefaultColorSpace(cgRef); 582 } 583 584 if ((everyThingChanged == YES) || (clipChanged == YES)) 585 { 586 if (javaGraphicsStates[sun_java2d_OSXSurfaceData_kClipStateIndex] == sun_java2d_OSXSurfaceData_kClipRect) 587 { 588 CGFloat x = javaFloatGraphicsStates[sun_java2d_OSXSurfaceData_kClipXIndex]; 589 CGFloat y = javaFloatGraphicsStates[sun_java2d_OSXSurfaceData_kClipYIndex]; 590 CGFloat w = javaFloatGraphicsStates[sun_java2d_OSXSurfaceData_kClipWidthIndex]; 591 CGFloat h = javaFloatGraphicsStates[sun_java2d_OSXSurfaceData_kClipHeightIndex]; 592 CGContextClipToRect(cgRef, CGRectMake(x, y, w, h)); 593 } 594 else 595 { 596 BOOL eoFill = (javaGraphicsStates[sun_java2d_OSXSurfaceData_kClipWindingRuleIndex] == java_awt_geom_PathIterator_WIND_EVEN_ODD); 597 jint numtypes = javaGraphicsStates[sun_java2d_OSXSurfaceData_kClipNumTypesIndex]; 598 599 jobject coordsarray = (jobject)((*env)->GetObjectArrayElement(env, qsdo->javaGraphicsStatesObjects, sun_java2d_OSXSurfaceData_kClipCoordinatesIndex)); 600 jobject typesarray = (jobject)((*env)->GetObjectArrayElement(env, qsdo->javaGraphicsStatesObjects, sun_java2d_OSXSurfaceData_kClipTypesIndex)); 601 602 jfloat* coords = (jfloat*)(*env)->GetDirectBufferAddress(env, coordsarray); 603 jint* types = (jint*)(*env)->GetDirectBufferAddress(env, typesarray); 604 605 DoShapeUsingCG(cgRef, types, coords, numtypes, NO, qsdo->graphicsStateInfo.offsetX, qsdo->graphicsStateInfo.offsetY); 606 607 if (CGContextIsPathEmpty(cgRef) == 0) 608 { 609 if (eoFill) 610 { 611 CGContextEOClip(cgRef); 612 } 613 else 614 { 615 CGContextClip(cgRef); 616 } 617 } 618 else 619 { 620 CGContextClipToRect(cgRef, CGRectZero); 621 } 622 } 623 } 624 // for debugging 625 //CGContextResetClip(cgRef); 626 627 if ((everyThingChanged == YES) || (transformChanged == YES)) 628 { 629 CGFloat a = javaFloatGraphicsStates[sun_java2d_OSXSurfaceData_kCTMaIndex]; 630 CGFloat b = javaFloatGraphicsStates[sun_java2d_OSXSurfaceData_kCTMbIndex]; 631 CGFloat c = javaFloatGraphicsStates[sun_java2d_OSXSurfaceData_kCTMcIndex]; 632 CGFloat d = javaFloatGraphicsStates[sun_java2d_OSXSurfaceData_kCTMdIndex]; 633 CGFloat tx = javaFloatGraphicsStates[sun_java2d_OSXSurfaceData_kCTMtxIndex]; 634 CGFloat ty = javaFloatGraphicsStates[sun_java2d_OSXSurfaceData_kCTMtyIndex]; 635 636 CGContextConcatCTM(cgRef, CGAffineTransformMake(a, b, c, d, tx, ty)); 637 638 if (gAdjustForJavaDrawing == YES) 639 { 640 // find the offsets in the device corrdinate system 641 CGAffineTransform ctm = CGContextGetCTM(cgRef); 642 if ((qsdo->graphicsStateInfo.ctm.a != ctm.a) || 643 (qsdo->graphicsStateInfo.ctm.b != ctm.b) || 644 (qsdo->graphicsStateInfo.ctm.c != ctm.c) || 645 (qsdo->graphicsStateInfo.ctm.d != ctm.d)) 646 { 647 qsdo->graphicsStateInfo.ctm = ctm; 648 // In CG affine xforms y' = bx+dy+ty 649 // We need to flip both y coefficeints to flip the offset point into the java coordinate system. 650 ctm.b = -ctm.b; ctm.d = -ctm.d; ctm.tx = 0.0f; ctm.ty = 0.0f; 651 CGPoint offsets = {kOffset, kOffset}; 652 CGAffineTransform inverse = CGAffineTransformInvert(ctm); 653 offsets = CGPointApplyAffineTransform(offsets, inverse); 654 qsdo->graphicsStateInfo.offsetX = offsets.x; 655 qsdo->graphicsStateInfo.offsetY = offsets.y; 656 } 657 } 658 else 659 { 660 qsdo->graphicsStateInfo.offsetX = 0.0f; 661 qsdo->graphicsStateInfo.offsetY = 0.0f; 662 } 663 } 664 665 // for debugging 666 //CGContextResetCTM(cgRef); 667 668 if ((everyThingChanged == YES) || (compositeChanged == YES)) 669 { 670 jint alphaCompositeRule = javaGraphicsStates[sun_java2d_OSXSurfaceData_kCompositeRuleIndex]; 671 CGFloat alphaCompositeValue = javaFloatGraphicsStates[sun_java2d_OSXSurfaceData_kCompositeValueIndex]; 672 673 NSCompositingOperation op; 674 switch (alphaCompositeRule) 675 { 676 case java_awt_AlphaComposite_CLEAR: 677 op = NSCompositeClear; 678 break; 679 case java_awt_AlphaComposite_SRC: 680 op = NSCompositeCopy; 681 break; 682 case java_awt_AlphaComposite_SRC_OVER: 683 op = NSCompositeSourceOver; 684 break; 685 case java_awt_AlphaComposite_DST_OVER: 686 op = NSCompositeDestinationOver; 687 break; 688 case java_awt_AlphaComposite_SRC_IN: 689 op = NSCompositeSourceIn; 690 break; 691 case java_awt_AlphaComposite_DST_IN: 692 op = NSCompositeDestinationIn; 693 break; 694 case java_awt_AlphaComposite_SRC_OUT: 695 op = NSCompositeSourceOut; 696 break; 697 case java_awt_AlphaComposite_DST_OUT: 698 op = NSCompositeDestinationOut; 699 break; 700 case java_awt_AlphaComposite_DST: 701 // Alpha must be set to 0 because we're using the kCGCompositeSover rule 702 op = NSCompositeSourceOver; 703 alphaCompositeValue = 0.0f; 704 break; 705 case java_awt_AlphaComposite_SRC_ATOP: 706 op = NSCompositeSourceAtop; 707 break; 708 case java_awt_AlphaComposite_DST_ATOP: 709 op = NSCompositeDestinationAtop; 710 break; 711 case java_awt_AlphaComposite_XOR: 712 op = NSCompositeXOR; 713 break; 714 default: 715 op = NSCompositeSourceOver; 716 alphaCompositeValue = 1.0f; 717 break; 718 } 719 720 NSGraphicsContext *context = [NSGraphicsContext graphicsContextWithGraphicsPort:cgRef flipped:NO]; 721 //CGContextSetCompositeOperation(cgRef, op); 722 [context setCompositingOperation:op]; 723 CGContextSetAlpha(cgRef, alphaCompositeValue); 724 } 725 726 if ((everyThingChanged == YES) || (renderingHintsChanged == YES)) 727 { 728 jint antialiasHint = javaGraphicsStates[sun_java2d_OSXSurfaceData_kHintsAntialiasIndex]; 729 // jint textAntialiasHint = javaGraphicsStates[sun_java2d_OSXSurfaceData_kHintsTextAntialiasIndex]; 730 jint renderingHint = javaGraphicsStates[sun_java2d_OSXSurfaceData_kHintsRenderingIndex]; 731 jint interpolationHint = javaGraphicsStates[sun_java2d_OSXSurfaceData_kHintsInterpolationIndex]; 732 // jint textFractionalMetricsHint = javaGraphicsStates[sun_java2d_OSXSurfaceData_kHintsFractionalMetricsIndex]; 733 734 // 10-10-02 VL: since CoreGraphics supports only an interpolation quality attribute we have to map 735 // both interpolationHint and renderingHint to an attribute value that best represents their combination. 736 // (See Radar 3071704.) We'll go for the best quality. CG maps interpolation quality values as follows: 737 // kCGInterpolationNone - nearest_neighbor 738 // kCGInterpolationLow - bilinear 739 // kCGInterpolationHigh - Lanczos (better than bicubic) 740 CGInterpolationQuality interpolationQuality = kCGInterpolationDefault; 741 // First check if the interpolation hint is suggesting to turn off interpolation: 742 if (interpolationHint == sun_awt_SunHints_INTVAL_INTERPOLATION_NEAREST_NEIGHBOR) 743 { 744 interpolationQuality = kCGInterpolationNone; 745 } 746 else if ((interpolationHint >= sun_awt_SunHints_INTVAL_INTERPOLATION_BICUBIC) || (renderingHint >= sun_awt_SunHints_INTVAL_RENDER_QUALITY)) 747 { 748 // Use >= just in case Sun adds some hint values in the future - this check wouldn't fall apart then: 749 interpolationQuality = kCGInterpolationHigh; 750 } 751 else if (interpolationHint == sun_awt_SunHints_INTVAL_INTERPOLATION_BILINEAR) 752 { 753 interpolationQuality = kCGInterpolationLow; 754 } 755 else if (renderingHint == sun_awt_SunHints_INTVAL_RENDER_SPEED) 756 { 757 interpolationQuality = kCGInterpolationNone; 758 } 759 // else interpolationHint == -1 || renderingHint == sun_awt_SunHints_INTVAL_CSURFACE_DEFAULT --> kCGInterpolationDefault 760 CGContextSetInterpolationQuality(cgRef, interpolationQuality); 761 qsdo->graphicsStateInfo.interpolation = interpolationQuality; 762 763 // antialiasing 764 BOOL antialiased = (antialiasHint == sun_awt_SunHints_INTVAL_ANTIALIAS_ON); 765 CGContextSetShouldAntialias(cgRef, antialiased); 766 qsdo->graphicsStateInfo.antialiased = antialiased; 767 } 768 769 if ((everyThingChanged == YES) || (strokeChanged == YES)) 770 { 771 qsdo->graphicsStateInfo.simpleStroke = YES; 772 773 CGFloat linewidth = javaFloatGraphicsStates[sun_java2d_OSXSurfaceData_kStrokeWidthIndex]; 774 jint linejoin = javaGraphicsStates[sun_java2d_OSXSurfaceData_kStrokeJoinIndex]; 775 jint linecap = javaGraphicsStates[sun_java2d_OSXSurfaceData_kStrokeCapIndex]; 776 CGFloat miterlimit = javaFloatGraphicsStates[sun_java2d_OSXSurfaceData_kStrokeLimitIndex]; 777 jobject dasharray = ((*env)->GetObjectArrayElement(env, qsdo->javaGraphicsStatesObjects, sun_java2d_OSXSurfaceData_kStrokeDashArrayIndex)); 778 CGFloat dashphase = javaFloatGraphicsStates[sun_java2d_OSXSurfaceData_kStrokeDashPhaseIndex]; 779 780 if (linewidth == 0.0f) 781 { 782 linewidth = (CGFloat)-109.05473e+14; // Don't ask ! 783 } 784 CGContextSetLineWidth(cgRef, linewidth); 785 786 CGLineCap cap; 787 switch (linecap) 788 { 789 case java_awt_BasicStroke_CAP_BUTT: 790 qsdo->graphicsStateInfo.simpleStroke = NO; 791 cap = kCGLineCapButt; 792 break; 793 case java_awt_BasicStroke_CAP_ROUND: 794 qsdo->graphicsStateInfo.simpleStroke = NO; 795 cap = kCGLineCapRound; 796 break; 797 case java_awt_BasicStroke_CAP_SQUARE: 798 default: 799 cap = kCGLineCapSquare; 800 break; 801 } 802 CGContextSetLineCap(cgRef, cap); 803 804 CGLineJoin join; 805 switch (linejoin) 806 { 807 case java_awt_BasicStroke_JOIN_ROUND: 808 qsdo->graphicsStateInfo.simpleStroke = NO; 809 join = kCGLineJoinRound; 810 break; 811 case java_awt_BasicStroke_JOIN_BEVEL: 812 qsdo->graphicsStateInfo.simpleStroke = NO; 813 join = kCGLineJoinBevel; 814 break; 815 case java_awt_BasicStroke_JOIN_MITER: 816 default: 817 join = kCGLineJoinMiter; 818 break; 819 } 820 CGContextSetLineJoin(cgRef, join); 821 CGContextSetMiterLimit(cgRef, miterlimit); 822 823 if (dasharray != NULL) 824 { 825 qsdo->graphicsStateInfo.simpleStroke = NO; 826 jint length = (*env)->GetArrayLength(env, dasharray); 827 jfloat* jdashes = (jfloat*)(*env)->GetPrimitiveArrayCritical(env, dasharray, NULL); 828 if (jdashes == NULL) { 829 CGContextSetLineDash(cgRef, 0, NULL, 0); 830 return; 831 } 832 CGFloat* dashes = (CGFloat*)malloc(sizeof(CGFloat)*length); 833 if (dashes != NULL) 834 { 835 jint i; 836 for (i=0; i<length; i++) 837 { 838 dashes[i] = (CGFloat)jdashes[i]; 839 } 840 } 841 else 842 { 843 dashphase = 0; 844 length = 0; 845 } 846 CGContextSetLineDash(cgRef, dashphase, dashes, length); 847 if (dashes != NULL) 848 { 849 free(dashes); 850 } 851 (*env)->ReleasePrimitiveArrayCritical(env, dasharray, jdashes, 0); 852 } 853 else 854 { 855 CGContextSetLineDash(cgRef, 0, NULL, 0); 856 } 857 } 858 859 BOOL cocoaPaint = (javaGraphicsStates[sun_java2d_OSXSurfaceData_kColorStateIndex] == sun_java2d_OSXSurfaceData_kColorSystem); 860 BOOL complexPaint = (javaGraphicsStates[sun_java2d_OSXSurfaceData_kColorStateIndex] == sun_java2d_OSXSurfaceData_kColorGradient) || 861 (javaGraphicsStates[sun_java2d_OSXSurfaceData_kColorStateIndex] == sun_java2d_OSXSurfaceData_kColorTexture); 862 if ((everyThingChanged == YES) || (paintChanged == YES) || (cocoaPaint == YES) || (complexPaint == YES)) 863 { 864 // rdar://problem/5214320 865 // Gradient fills of Java GeneralPath don't respect the even odd winding rule (quartz pipeline). 866 // Notice the side effect of the stmt after this if-block. 867 if (renderType == SD_EOFill) { 868 qsdo->isEvenOddFill = YES; 869 } 870 871 renderType = SetUpPaint(env, qsdo, renderType); 872 } 873 874 qsdo->renderType = renderType; 875 } 876 877 SDRenderType SetUpPaint(JNIEnv *env, QuartzSDOps *qsdo, SDRenderType renderType) 878 { 879 CGContextRef cgRef = qsdo->cgRef; 880 881 jint *javaGraphicsStates = qsdo->javaGraphicsStates; 882 jfloat *javaFloatGraphicsStates = (jfloat*)(qsdo->javaGraphicsStates); 883 884 static const CGFloat kColorConversionMultiplier = 1.0f/255.0f; 885 jint colorState = javaGraphicsStates[sun_java2d_OSXSurfaceData_kColorStateIndex]; 886 887 switch (colorState) 888 { 889 case sun_java2d_OSXSurfaceData_kColorSimple: 890 { 891 if (qsdo->graphicsStateInfo.simpleColor == NO) 892 { 893 setDefaultColorSpace(cgRef); 894 } 895 qsdo->graphicsStateInfo.simpleColor = YES; 896 897 // sets the color on the CGContextRef (CGContextSetStrokeColorWithColor/CGContextSetFillColorWithColor) 898 setCachedColor(qsdo, javaGraphicsStates[sun_java2d_OSXSurfaceData_kColorRGBValueIndex]); 899 900 break; 901 } 902 case sun_java2d_OSXSurfaceData_kColorSystem: 903 { 904 qsdo->graphicsStateInfo.simpleStroke = NO; 905 // All our custom Colors are NSPatternColorSpace so we are complex colors! 906 qsdo->graphicsStateInfo.simpleColor = NO; 907 908 NSColor *color = nil; 909 /* TODO:BG 910 { 911 color = getColor(javaGraphicsStates[sun_java2d_OSXSurfaceData_kColorIndexValueIndex]); 912 } 913 */ 914 [color set]; 915 break; 916 } 917 case sun_java2d_OSXSurfaceData_kColorGradient: 918 { 919 qsdo->shadingInfo = (StateShadingInfo*)malloc(sizeof(StateShadingInfo)); 920 if (qsdo->shadingInfo == NULL) 921 { 922 [JNFException raise:env as:kOutOfMemoryError reason:"Failed to malloc memory for gradient paint"]; 923 } 924 925 qsdo->graphicsStateInfo.simpleStroke = NO; 926 qsdo->graphicsStateInfo.simpleColor = NO; 927 928 renderType = SD_Shade; 929 930 qsdo->shadingInfo->start.x = javaFloatGraphicsStates[sun_java2d_OSXSurfaceData_kColorx1Index]; 931 qsdo->shadingInfo->start.y = javaFloatGraphicsStates[sun_java2d_OSXSurfaceData_kColory1Index]; 932 qsdo->shadingInfo->end.x = javaFloatGraphicsStates[sun_java2d_OSXSurfaceData_kColorx2Index]; 933 qsdo->shadingInfo->end.y = javaFloatGraphicsStates[sun_java2d_OSXSurfaceData_kColory2Index]; 934 jint c1 = javaGraphicsStates[sun_java2d_OSXSurfaceData_kColorRGBValue1Index]; 935 qsdo->shadingInfo->colors[0] = ((c1>>16)&0xff)*kColorConversionMultiplier; 936 qsdo->shadingInfo->colors[1] = ((c1>>8)&0xff)*kColorConversionMultiplier; 937 qsdo->shadingInfo->colors[2] = ((c1>>0)&0xff)*kColorConversionMultiplier; 938 qsdo->shadingInfo->colors[3] = ((c1>>24)&0xff)*kColorConversionMultiplier; 939 jint c2 = javaGraphicsStates[sun_java2d_OSXSurfaceData_kColorRGBValue2Index]; 940 qsdo->shadingInfo->colors[4] = ((c2>>16)&0xff)*kColorConversionMultiplier; 941 qsdo->shadingInfo->colors[5] = ((c2>>8)&0xff)*kColorConversionMultiplier; 942 qsdo->shadingInfo->colors[6] = ((c2>>0)&0xff)*kColorConversionMultiplier; 943 qsdo->shadingInfo->colors[7] = ((c2>>24)&0xff)*kColorConversionMultiplier; 944 qsdo->shadingInfo->cyclic = (javaGraphicsStates[sun_java2d_OSXSurfaceData_kColorIsCyclicIndex] == sun_java2d_OSXSurfaceData_kColorCyclic); 945 946 break; 947 } 948 case sun_java2d_OSXSurfaceData_kColorLinearOrRadialGradient: 949 { 950 qsdo->gradientInfo = (StateGradientInfo*)malloc(sizeof(StateGradientInfo)); 951 if (qsdo->gradientInfo == NULL) 952 { 953 [JNFException raise:env as:kOutOfMemoryError reason:"Failed to malloc memory for gradient paint"]; 954 } 955 956 qsdo->graphicsStateInfo.simpleStroke = NO; 957 qsdo->graphicsStateInfo.simpleColor = NO; 958 959 renderType = SD_Gradient; 960 961 qsdo->gradientInfo->start.x = javaFloatGraphicsStates[sun_java2d_OSXSurfaceData_kColorx1Index]; 962 qsdo->gradientInfo->start.y = javaFloatGraphicsStates[sun_java2d_OSXSurfaceData_kColory1Index]; 963 qsdo->gradientInfo->end.x = javaFloatGraphicsStates[sun_java2d_OSXSurfaceData_kColorx2Index]; 964 qsdo->gradientInfo->end.y = javaFloatGraphicsStates[sun_java2d_OSXSurfaceData_kColory2Index]; 965 966 jobject colorArray = ((*env)->GetObjectArrayElement(env, qsdo->javaGraphicsStatesObjects, sun_java2d_OSXSurfaceData_kColorArrayIndex)); 967 if (colorArray != NULL) 968 { 969 jint length = (*env)->GetArrayLength(env, colorArray); 970 //fprintf(stderr, "length %d\n", length); 971 972 jint* jcolorData = (jint*)(*env)->GetPrimitiveArrayCritical(env, colorArray, NULL); 973 CGFloat* colors= (CGFloat*)calloc(0, sizeof(CGFloat)*length); 974 if (jcolorData != NULL) 975 { 976 jint i; 977 for (i=0; i<length; i++) 978 { 979 colors[i] = (CGFloat)jcolorData[i]; 980 } 981 } 982 for (int i = 0; i < length; i++) 983 { 984 jint c1 = colors[i]; 985 //fprintf(stderr, "c1 %x\n", c1); 986 qsdo->gradientInfo->colordata = (CGFloat*)calloc(0, sizeof(CGFloat)*4*length); 987 qsdo->gradientInfo->colordata[i*4] = ((c1>>16)&0xff)*kColorConversionMultiplier; 988 //fprintf(stderr, "qsdo->gradientInfo->colordata[%d] %f\n", i*4, qsdo->gradientInfo->colordata[i*4]); 989 990 qsdo->gradientInfo->colordata[i*4+1] = ((c1>>8)&0xff)*kColorConversionMultiplier; 991 //fprintf(stderr, "qsdo->gradientInfo->colordata[%d] %f\n", i*4+1, qsdo->gradientInfo->colordata[i*4+1]); 992 993 qsdo->gradientInfo->colordata[i*4+2] = ((c1>>0)&0xff)*kColorConversionMultiplier; 994 //fprintf(stderr, "qsdo->gradientInfo->colordata[%d] %f\n", i*4+2, qsdo->gradientInfo->colordata[i*4+2]); 995 996 qsdo->gradientInfo->colordata[i*4+3] = ((c1>>24)&0xff)*kColorConversionMultiplier; 997 //fprintf(stderr, "qsdo->gradientInfo->colordata[%d] %f\n", i*4+3, qsdo->gradientInfo->colordata[i*4+3]); 998 } 999 (*env)->ReleasePrimitiveArrayCritical(env, colorArray, jcolorData, 0); 1000 free(colors); 1001 } 1002 jobject fractionsArray = ((*env)->GetObjectArrayElement(env, qsdo->javaGraphicsStatesObjects, sun_java2d_OSXSurfaceData_kFractionsArrayIndex)); 1003 if (fractionsArray != NULL) 1004 { 1005 jint length = (*env)->GetArrayLength(env, fractionsArray); 1006 //fprintf(stderr, "fractions length %d\n", length); 1007 qsdo->gradientInfo->fractionsLength = length; 1008 1009 jfloat* jfractionsData = (jfloat*)(*env)->GetPrimitiveArrayCritical(env, fractionsArray, NULL); 1010 if (jfractionsData != NULL) 1011 { 1012 qsdo->gradientInfo->fractionsdata = (CGFloat *)malloc(sizeof(CGFloat) *length); 1013 jint i; 1014 for (i=0; i<length; i++) 1015 { 1016 qsdo->gradientInfo->fractionsdata[i] = jfractionsData[i]; 1017 //fprintf(stderr, "jfrationsData[%d] %f, qsdo->gradientInfo->fractionsdata[%d] = %f\n", i, jfractionsData[i], i, qsdo->gradientInfo->fractionsdata[i]); 1018 } 1019 (*env)->ReleasePrimitiveArrayCritical(env, fractionsArray, jfractionsData, 0); 1020 } 1021 } 1022 break; 1023 } 1024 case sun_java2d_OSXSurfaceData_kColorTexture: 1025 { 1026 qsdo->patternInfo = (StatePatternInfo*)malloc(sizeof(StatePatternInfo)); 1027 if (qsdo->patternInfo == NULL) 1028 { 1029 [JNFException raise:env as:kOutOfMemoryError reason:"Failed to malloc memory for texture paint"]; 1030 } 1031 1032 qsdo->graphicsStateInfo.simpleStroke = NO; 1033 qsdo->graphicsStateInfo.simpleColor = NO; 1034 1035 renderType = SD_Pattern; 1036 1037 qsdo->patternInfo->tx = javaFloatGraphicsStates[sun_java2d_OSXSurfaceData_kColortxIndex]; 1038 qsdo->patternInfo->ty = javaFloatGraphicsStates[sun_java2d_OSXSurfaceData_kColortyIndex]; 1039 qsdo->patternInfo->sx = javaFloatGraphicsStates[sun_java2d_OSXSurfaceData_kColorsxIndex]; 1040 if (qsdo->patternInfo->sx == 0.0f) 1041 { 1042 return SD_Fill; // 0 is an invalid value, fill argb rect 1043 } 1044 qsdo->patternInfo->sy = javaFloatGraphicsStates[sun_java2d_OSXSurfaceData_kColorsyIndex]; 1045 if (qsdo->patternInfo->sy == 0.0f) 1046 { 1047 return SD_Fill; // 0 is an invalid value, fill argb rect 1048 } 1049 qsdo->patternInfo->width = javaGraphicsStates[sun_java2d_OSXSurfaceData_kColorWidthIndex]; 1050 qsdo->patternInfo->height = javaGraphicsStates[sun_java2d_OSXSurfaceData_kColorHeightIndex]; 1051 1052 jobject sData = ((*env)->GetObjectArrayElement(env, qsdo->javaGraphicsStatesObjects, sun_java2d_OSXSurfaceData_kTextureImageIndex)); //deleted next time through SetUpPaint and not before ( radr://3913190 ) 1053 if (sData != NULL) 1054 { 1055 qsdo->patternInfo->sdata = (*env)->NewGlobalRef(env, sData); 1056 if (qsdo->patternInfo->sdata == NULL) 1057 { 1058 renderType = SD_Fill; 1059 } 1060 } 1061 else 1062 { 1063 renderType = SD_Fill; 1064 } 1065 1066 break; 1067 } 1068 } 1069 1070 return renderType; 1071 } 1072 1073 #pragma mark 1074 #pragma mark --- Shape Drawing Code --- 1075 1076 SDRenderType DoShapeUsingCG(CGContextRef cgRef, jint *types, jfloat *coords, jint numtypes, BOOL fill, CGFloat offsetX, CGFloat offsetY) 1077 { 1078 //fprintf(stderr, "DoShapeUsingCG fill=%d\n", (jint)fill); 1079 SDRenderType renderType = SD_Nothing; 1080 1081 if (gAdjustForJavaDrawing != YES) 1082 { 1083 offsetX = 0.0f; 1084 offsetY = 0.0f; 1085 } 1086 1087 if (fill == YES) 1088 { 1089 renderType = SD_Fill; 1090 } 1091 else 1092 { 1093 renderType = SD_Stroke; 1094 } 1095 1096 if (numtypes > 0) 1097 { 1098 BOOL needNewSubpath = NO; 1099 1100 CGContextBeginPath(cgRef); // create new path 1101 //fprintf(stderr, " CGContextBeginPath\n"); 1102 1103 jint index = 0; 1104 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; 1105 jint i; 1106 1107 mx = (CGFloat)coords[index++] + offsetX; 1108 my = (CGFloat)coords[index++] + offsetY; 1109 CGContextMoveToPoint(cgRef, mx, my); 1110 1111 for (i=1; i<numtypes; i++) 1112 { 1113 jint pathType = types[i]; 1114 1115 if (needNewSubpath == YES) 1116 { 1117 needNewSubpath = NO; 1118 switch (pathType) 1119 { 1120 case java_awt_geom_PathIterator_SEG_LINETO: 1121 case java_awt_geom_PathIterator_SEG_QUADTO: 1122 case java_awt_geom_PathIterator_SEG_CUBICTO: 1123 //fprintf(stderr, " forced CGContextMoveToPoint (%f, %f)\n", mx, my); 1124 CGContextMoveToPoint(cgRef, mx, my); // force new subpath 1125 break; 1126 } 1127 } 1128 1129 switch (pathType) 1130 { 1131 case java_awt_geom_PathIterator_SEG_MOVETO: 1132 mx = x1 = (CGFloat)coords[index++] + offsetX; 1133 my = y1 = (CGFloat)coords[index++] + offsetY; 1134 CGContextMoveToPoint(cgRef, x1, y1); // start new subpath 1135 //fprintf(stderr, " SEG_MOVETO CGContextMoveToPoint (%f, %f)\n", x1, y1); 1136 break; 1137 case java_awt_geom_PathIterator_SEG_LINETO: 1138 x1 = (CGFloat)coords[index++] + offsetX; 1139 y1 = (CGFloat)coords[index++] + offsetY; 1140 CGContextAddLineToPoint(cgRef, x1, y1); 1141 //fprintf(stderr, " SEG_LINETO CGContextAddLineToPoint (%f, %f)\n", x1, y1); 1142 break; 1143 case java_awt_geom_PathIterator_SEG_QUADTO: 1144 cpx1 = (CGFloat)coords[index++] + offsetX; 1145 cpy1 = (CGFloat)coords[index++] + offsetY; 1146 x1 = (CGFloat)coords[index++] + offsetX; 1147 y1 = (CGFloat)coords[index++]+ offsetY; 1148 CGContextAddQuadCurveToPoint(cgRef, cpx1, cpy1, x1, y1); 1149 //fprintf(stderr, " SEG_QUADTO CGContextAddQuadCurveToPoint (%f, %f), (%f, %f)\n", cpx1, cpy1, x1, y1); 1150 break; 1151 case java_awt_geom_PathIterator_SEG_CUBICTO: 1152 cpx1 = (CGFloat)coords[index++] + offsetX; 1153 cpy1 = (CGFloat)coords[index++] + offsetY; 1154 cpx2 = (CGFloat)coords[index++] + offsetX; 1155 cpy2 = (CGFloat)coords[index++] + offsetY; 1156 x1 = (CGFloat)coords[index++] + offsetX; 1157 y1 = (CGFloat)coords[index++] + offsetY; 1158 CGContextAddCurveToPoint(cgRef, cpx1, cpy1, cpx2, cpy2, x1, y1); 1159 //fprintf(stderr, " SEG_CUBICTO CGContextAddCurveToPoint (%f, %f), (%f, %f), (%f, %f)\n", cpx1, cpy1, cpx2, cpy2, x1, y1); 1160 break; 1161 case java_awt_geom_PathIterator_SEG_CLOSE: 1162 CGContextClosePath(cgRef); // close subpath 1163 needNewSubpath = YES; 1164 //fprintf(stderr, " SEG_CLOSE CGContextClosePath\n"); 1165 break; 1166 } 1167 } 1168 } 1169 1170 return renderType; 1171 } 1172 1173 void CompleteCGContext(JNIEnv *env, QuartzSDOps *qsdo) 1174 { 1175 PRINT(" CompleteCGContext") 1176 switch (qsdo->renderType) 1177 { 1178 case SD_Nothing: 1179 break; 1180 1181 case SD_Stroke: 1182 if (CGContextIsPathEmpty(qsdo->cgRef) == 0) 1183 { 1184 CGContextStrokePath(qsdo->cgRef); 1185 } 1186 break; 1187 1188 case SD_Fill: 1189 if (CGContextIsPathEmpty(qsdo->cgRef) == 0) 1190 { 1191 CGContextFillPath(qsdo->cgRef); 1192 } 1193 break; 1194 1195 case SD_Shade: 1196 fprintf(stderr, "SD_Shade\n"); 1197 if (CGContextIsPathEmpty(qsdo->cgRef) == 0) 1198 { 1199 contextGradientPath(qsdo); 1200 } 1201 break; 1202 1203 case SD_Gradient: 1204 fprintf(stderr, "SD_Gradient\n"); 1205 if (CGContextIsPathEmpty(qsdo->cgRef) == 0) 1206 { 1207 contextQuartzGradientPath(qsdo); 1208 } 1209 break; 1210 1211 case SD_Pattern: 1212 fprintf(stderr, "SD_Pattern\n"); 1213 if (CGContextIsPathEmpty(qsdo->cgRef) == 0) 1214 { 1215 //TODO:BG 1216 //contextTexturePath(env, qsdo); 1217 } 1218 break; 1219 1220 case SD_EOFill: 1221 if (CGContextIsPathEmpty(qsdo->cgRef) == 0) 1222 { 1223 CGContextEOFillPath(qsdo->cgRef); 1224 } 1225 break; 1226 1227 case SD_Image: 1228 break; 1229 1230 case SD_Text: 1231 break; 1232 1233 case SD_CopyArea: 1234 break; 1235 1236 case SD_Queue: 1237 break; 1238 1239 case SD_External: 1240 break; 1241 } 1242 1243 if (qsdo->shadingInfo != NULL) { 1244 gradientPaintReleaseFunction(qsdo->shadingInfo); 1245 qsdo->shadingInfo = NULL; 1246 } 1247 if (qsdo->gradientInfo != NULL) { 1248 gradientPaintReleaseFunction(qsdo->gradientInfo); 1249 qsdo->gradientInfo = NULL; 1250 } 1251 }