1 /* 2 * Copyright (c) 2011, 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 "java_awt_image_BufferedImage.h" 27 #import "java_awt_geom_PathIterator.h" 28 #import "sun_java2d_OSXSurfaceData.h" 29 30 #import <stdio.h> 31 #import <JavaNativeFoundation/JavaNativeFoundation.h> 32 33 #import "ImageSurfaceData.h" 34 35 36 //#define DEBUG 1 37 #if defined DEBUG 38 #define QUARTZ_RENDERER_INLINE 39 #define PRINT(msg) {fprintf(stderr, "%s\n", msg);fflush(stderr);} 40 #else 41 #define QUARTZ_RENDERER_INLINE static inline 42 #define PRINT(msg) {} 43 #endif 44 45 // Copied the following from Math.java 46 #define PI 3.14159265358979323846f 47 48 #define BATCHED_POINTS_SIZE 1024 49 50 // same value as defined in Sun's own code 51 #define XOR_ALPHA_CUTOFF 128 52 53 54 static CGFloat gRoundRectCtrlpts[10][12] = 55 { 56 {0.0f, 0.0f, 0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, 57 {0.0f, 0.0f, 1.0f, -0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, 58 {0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.5f, 1.0f, 0.0f}, 59 {1.0f, -0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, 60 {1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, -0.5f}, 61 {1.0f, 0.0f, 0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, 62 {1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, -0.5f, 0.0f, 0.0f}, 63 {0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, 64 {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.5f}, 65 {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, 66 }; 67 68 CG_EXTERN CGRect CGRectApplyAffineTransform(CGRect rect, CGAffineTransform t); 69 70 71 CGRect sanitizedRect(CGFloat x1, CGFloat y1, CGFloat x2, CGFloat y2) { 72 CGFloat temp; 73 if (x1 > x2) { 74 temp = x2; 75 x2 = x1; 76 x1 = temp; 77 } 78 if (y1 > y2) { 79 temp = y2; 80 y2 = y1; 81 y1 = temp; 82 } 83 return CGRectMake(x1, y1, x2-x1, y2-y1); 84 } 85 86 QUARTZ_RENDERER_INLINE SDRenderType doLineUsingCG(CGContextRef cgRef, CGFloat x1, CGFloat y1, CGFloat x2, CGFloat y2, BOOL simple, CGFloat offsetX, CGFloat offsetY) 87 { 88 //fprintf(stderr, "doLine start=(%f, %f), end=(%f, %f), linewidth:%f, offsetX:%f, offsetY:%f\n", x1, y1, x2, y2, CGContextGetLineWidth(cgRef), offsetX, offsetY); 89 SDRenderType renderType = SD_Nothing; 90 91 if (simple == YES) 92 { 93 struct CGPoint oneLinePoints[2]; 94 95 oneLinePoints[0] = CGPointMake(x1+offsetX, y1+offsetY); 96 oneLinePoints[1] = CGPointMake(x2+offsetX, y2+offsetY); 97 98 CGContextStrokeLineSegments(cgRef, oneLinePoints, 2); 99 renderType = SD_Nothing; 100 } 101 else 102 { 103 CGContextMoveToPoint(cgRef, x1+offsetX, y1+offsetY); 104 CGContextAddLineToPoint(cgRef, x2+offsetX, y2+offsetY); 105 renderType = SD_Stroke; 106 } 107 108 return renderType; 109 } 110 QUARTZ_RENDERER_INLINE SDRenderType doLine(QuartzSDOps *qsdo, CGFloat x1, CGFloat y1, CGFloat x2, CGFloat y2) 111 { 112 PRINT(" doLine") 113 if (YES) 114 { 115 return doLineUsingCG(qsdo->cgRef, x1, y1, x2, y2, 116 qsdo->graphicsStateInfo.simpleStroke, qsdo->graphicsStateInfo.offsetX, qsdo->graphicsStateInfo.offsetY); 117 } 118 // here we can add other implementations (ex. using QuickDraw, OpenGL, etc.) 119 } 120 121 122 QUARTZ_RENDERER_INLINE SDRenderType doRectUsingCG(CGContextRef cgRef, CGFloat x, CGFloat y, CGFloat w, CGFloat h, BOOL fill, BOOL simple, CGFloat offsetX, CGFloat offsetY) 123 { 124 //fprintf(stderr, "doRect point=(%f, %f), size=(%f, %f), offsets=(%f, %f) fill=%d simple=%d\n", x, y, w, h, offsetX, offsetY, fill, simple); 125 //CGRect clip = CGContextGetClipBoundingBox(cgRef); 126 //fprintf(stderr, " clip: ((%f, %f), (%f, %f))\n", clip.origin.x, clip.origin.y, clip.size.width, clip.size.height); 127 //CGAffineTransform ctm = CGContextGetCTM(cgRef); 128 //fprintf(stderr, " ctm: (%f, %f, %f, %f, %f, %f)\n", ctm.a, ctm.b, ctm.c, ctm.d, ctm.tx, ctm.ty); 129 SDRenderType renderType = SD_Nothing; 130 131 if (fill == YES) 132 { 133 if (simple == YES) 134 { 135 CGContextFillRect(cgRef, CGRectMake(x, y, w, h)); 136 renderType = SD_Nothing; 137 } 138 else 139 { 140 CGContextAddRect(cgRef, CGRectMake(x, y, w, h)); 141 renderType = SD_Fill; 142 } 143 } 144 else 145 { 146 if (simple == YES) 147 { 148 CGContextStrokeRect(cgRef, CGRectMake(x+offsetX, y+offsetY, w, h)); 149 renderType = SD_Nothing; 150 } 151 else 152 { 153 CGContextAddRect(cgRef, CGRectMake(x+offsetX, y+offsetY, w, h)); 154 renderType = SD_Stroke; 155 } 156 } 157 158 return renderType; 159 } 160 QUARTZ_RENDERER_INLINE SDRenderType doRect(QuartzSDOps *qsdo, CGFloat x, CGFloat y, CGFloat w, CGFloat h, BOOL fill) 161 { 162 PRINT(" doRect") 163 if (YES) 164 { 165 return doRectUsingCG(qsdo->cgRef, x, y, w, h, fill, 166 qsdo->graphicsStateInfo.simpleStroke, qsdo->graphicsStateInfo.offsetX, qsdo->graphicsStateInfo.offsetY); 167 } 168 // here we can add other implementations (ex. using QuickDraw, OpenGL, etc.) 169 } 170 171 // from RoundRectIterator.java 172 QUARTZ_RENDERER_INLINE SDRenderType doRoundRectUsingCG(CGContextRef cgRef, CGFloat x, CGFloat y, CGFloat w, CGFloat h, CGFloat arcWidth, CGFloat arcHeight, BOOL fill, CGFloat offsetX, CGFloat offsetY) 173 { 174 SDRenderType renderType = SD_Nothing; 175 176 if (fill == YES) 177 { 178 renderType = SD_Fill; 179 } 180 else 181 { 182 renderType = SD_Stroke; 183 } 184 185 // radr://3593731 RoundRects with corner width/height of 0 don't draw 186 arcWidth = (arcWidth > 0.0f) ? arcWidth : 0.0f; 187 arcHeight = (arcHeight > 0.0f) ? arcHeight : 0.0f; 188 189 CGFloat aw = (w < arcWidth) ? w : arcWidth; 190 CGFloat ah = (h < arcHeight) ? h : arcHeight; 191 192 CGFloat *ctrls, p1, q1, p2, q2, p3, q3; 193 ctrls = gRoundRectCtrlpts[0]; 194 p1 = (x + ctrls[0] * w + ctrls[1] * aw); 195 q1 = (y + ctrls[2] * h + ctrls[3] * ah); 196 CGContextMoveToPoint(cgRef, p1+offsetX, q1+offsetY); 197 198 ctrls = gRoundRectCtrlpts[1]; 199 p1 = (x + ctrls[0] * w + ctrls[1] * aw); 200 q1 = (y + ctrls[2] * h + ctrls[3] * ah); 201 CGContextAddLineToPoint(cgRef, p1+offsetX, q1+offsetY); 202 203 ctrls = gRoundRectCtrlpts[2]; 204 p1 = (x + ctrls[0] * w + ctrls[1] * aw); 205 q1 = (y + ctrls[2] * h + ctrls[3] * ah); 206 p2 = (x + ctrls[4] * w + ctrls[5] * aw); 207 q2 = (y + ctrls[6] * h + ctrls[7] * ah); 208 p3 = (x + ctrls[8] * w + ctrls[9] * aw); 209 q3 = (y + ctrls[10] * h + ctrls[11] * ah); 210 CGContextAddCurveToPoint(cgRef, p1+offsetX, q1+offsetY, p2+offsetX, q2+offsetY, p3+offsetX, q3+offsetY); 211 212 ctrls = gRoundRectCtrlpts[3]; 213 p1 = (x + ctrls[0] * w + ctrls[1] * aw); 214 q1 = (y + ctrls[2] * h + ctrls[3] * ah); 215 CGContextAddLineToPoint(cgRef, p1+offsetX, q1+offsetY); 216 217 ctrls = gRoundRectCtrlpts[4]; 218 p1 = (x + ctrls[0] * w + ctrls[1] * aw); 219 q1 = (y + ctrls[2] * h + ctrls[3] * ah); 220 p2 = (x + ctrls[4] * w + ctrls[5] * aw); 221 q2 = (y + ctrls[6] * h + ctrls[7] * ah); 222 p3 = (x + ctrls[8] * w + ctrls[9] * aw); 223 q3 = (y + ctrls[10] * h + ctrls[11] * ah); 224 CGContextAddCurveToPoint(cgRef, p1+offsetX, q1+offsetY, p2+offsetX, q2+offsetY, p3+offsetX, q3+offsetY); 225 226 ctrls = gRoundRectCtrlpts[5]; 227 p1 = (x + ctrls[0] * w + ctrls[1] * aw); 228 q1 = (y + ctrls[2] * h + ctrls[3] * ah); 229 CGContextAddLineToPoint(cgRef, p1+offsetX, q1+offsetY); 230 231 ctrls = gRoundRectCtrlpts[6]; 232 p1 = (x + ctrls[0] * w + ctrls[1] * aw); 233 q1 = (y + ctrls[2] * h + ctrls[3] * ah); 234 p2 = (x + ctrls[4] * w + ctrls[5] * aw); 235 q2 = (y + ctrls[6] * h + ctrls[7] * ah); 236 p3 = (x + ctrls[8] * w + ctrls[9] * aw); 237 q3 = (y + ctrls[10] * h + ctrls[11] * ah); 238 CGContextAddCurveToPoint(cgRef, p1+offsetX, q1+offsetY, p2+offsetX, q2+offsetY, p3+offsetX, q3+offsetY); 239 240 ctrls = gRoundRectCtrlpts[7]; 241 p1 = (x + ctrls[0] * w + ctrls[1] * aw); 242 q1 = (y + ctrls[2] * h + ctrls[3] * ah); 243 CGContextAddLineToPoint(cgRef, p1+offsetX, q1+offsetY); 244 245 ctrls = gRoundRectCtrlpts[8]; 246 p1 = (x + ctrls[0] * w + ctrls[1] * aw); 247 q1 = (y + ctrls[2] * h + ctrls[3] * ah); 248 p2 = (x + ctrls[4] * w + ctrls[5] * aw); 249 q2 = (y + ctrls[6] * h + ctrls[7] * ah); 250 p3 = (x + ctrls[8] * w + ctrls[9] * aw); 251 q3 = (y + ctrls[10] * h + ctrls[11] * ah); 252 CGContextAddCurveToPoint(cgRef, p1+offsetX, q1+offsetY, p2+offsetX, q2+offsetY, p3+offsetX, q3+offsetY); 253 254 CGContextClosePath(cgRef); 255 256 return renderType; 257 } 258 259 QUARTZ_RENDERER_INLINE SDRenderType doRoundRect(QuartzSDOps *qsdo, CGFloat x, CGFloat y, CGFloat w, CGFloat h, CGFloat arcWidth, CGFloat arcHeight, BOOL fill) 260 { 261 PRINT(" doRoundRect") 262 if (YES) 263 { 264 return doRoundRectUsingCG(qsdo->cgRef, x, y, w, h, arcWidth, arcHeight, fill, 265 qsdo->graphicsStateInfo.offsetX, qsdo->graphicsStateInfo.offsetY); 266 } 267 // here we can add other implementations (ex. using QuickDraw, OpenGL, etc.) 268 } 269 270 // from EllipseIterator.java 271 QUARTZ_RENDERER_INLINE SDRenderType doOvalUsingCG(CGContextRef cgRef, CGFloat x, CGFloat y, CGFloat w, CGFloat h, BOOL fill, BOOL simple, CGFloat offsetX, CGFloat offsetY) 272 { 273 SDRenderType renderType = SD_Nothing; 274 275 if (simple == YES) 276 { 277 if (fill == YES) 278 { 279 CGContextFillEllipseInRect(cgRef, CGRectMake(x+offsetX, y+offsetY, w, h)); 280 } 281 else 282 { 283 CGContextStrokeEllipseInRect(cgRef, CGRectMake(x+offsetX, y+offsetY, w, h)); 284 } 285 } 286 else 287 { 288 if (fill == YES) 289 { 290 renderType = SD_Fill; 291 } 292 else 293 { 294 renderType = SD_Stroke; 295 } 296 297 CGContextAddEllipseInRect(cgRef, CGRectMake(x+offsetX, y+offsetY, w, h)); 298 } 299 300 return renderType; 301 } 302 QUARTZ_RENDERER_INLINE SDRenderType doOval(QuartzSDOps *qsdo, CGFloat x, CGFloat y, CGFloat w, CGFloat h, BOOL fill) 303 { 304 PRINT(" doOval") 305 if (YES) 306 { 307 return doOvalUsingCG(qsdo->cgRef, x, y, w, h, fill, 308 qsdo->graphicsStateInfo.simpleStroke, qsdo->graphicsStateInfo.offsetX, qsdo->graphicsStateInfo.offsetY); 309 } 310 // here we can add other implementations (ex. using QuickDraw, OpenGL, etc.) 311 } 312 313 // from ArcIterator.java 314 QUARTZ_RENDERER_INLINE CGFloat btan(CGFloat increment) 315 { 316 increment /= 2.0f; 317 CGFloat a = 1.0f - cos(increment); 318 CGFloat b = tan(increment); 319 CGFloat c = sqrt(1.0f + b * b) - 1.0f + a; 320 321 return 4.0f / 3.0f * a * b / c; 322 } 323 QUARTZ_RENDERER_INLINE SDRenderType doArcUsingCG(CGContextRef cgRef, CGFloat x, CGFloat y, CGFloat w, CGFloat h, CGFloat angleStart, CGFloat angleExtent, jint arcType, BOOL fill, CGFloat offsetX, CGFloat offsetY) 324 { 325 //fprintf(stderr, "doArc\n"); 326 SDRenderType renderType = SD_Nothing; 327 328 if (fill == YES) 329 { 330 renderType = SD_Fill; 331 } 332 else 333 { 334 renderType = SD_Stroke; 335 } 336 337 CGFloat angStRad, angExtDeg; 338 jint arcSegs; 339 jint lineSegs; 340 jint index = 1; 341 342 w = w / 2.0f; 343 h = h / 2.0f; 344 x = x + w; 345 y = y + h; 346 angStRad = -(angleStart / 180.0f * PI); 347 angExtDeg = -angleExtent; 348 CGFloat ext = (angExtDeg>0) ? angExtDeg : -angExtDeg; 349 if (ext >= 360.0f) 350 { 351 arcSegs = 4; 352 } 353 else 354 { 355 arcSegs = (jint)ceil(ext/90.0f); 356 } 357 switch (arcType) 358 { 359 case 0: 360 lineSegs = 0; 361 break; 362 case 1: 363 lineSegs = 1; 364 break; 365 case 2: 366 lineSegs = 2; 367 break; 368 } 369 if (w < 0 || h < 0) 370 { 371 arcSegs = lineSegs = -1; 372 } 373 374 CGFloat angle = angStRad; 375 CGContextMoveToPoint(cgRef, (x + cos(angle) * w)+offsetX, (y + sin(angle) * h)+offsetY); 376 377 CGFloat increment = angExtDeg; 378 if (increment > 360.0f) 379 { 380 increment = 360.0f; 381 } 382 else if (increment < -360.0f) 383 { 384 increment = -360.0f; 385 } 386 increment /= arcSegs; 387 increment = (increment / 180.0f * PI); 388 CGFloat z = btan(increment); 389 CGFloat angleBase = angle; 390 CGFloat p1, q1, p2, q2, p3, q3; 391 while (index <= arcSegs) 392 { 393 angle = angleBase + increment * (index - 1); 394 CGFloat relx = cos(angle); 395 CGFloat rely = sin(angle); 396 p1 = (x + (relx - z * rely) * w); 397 q1 = (y + (rely + z * relx) * h); 398 angle += increment; 399 relx = cos(angle); 400 rely = sin(angle); 401 p2 = (x + (relx + z * rely) * w); 402 q2 = (y + (rely - z * relx) * h); 403 p3 = (x + relx * w); 404 q3 = (y + rely * h); 405 406 CGContextAddCurveToPoint(cgRef, p1+offsetX, q1+offsetY, p2+offsetX, q2+offsetY, p3+offsetX, q3+offsetY); 407 408 index++; 409 } 410 411 switch (arcType) 412 { 413 case 1: 414 CGContextClosePath(cgRef); 415 break; 416 case 2: 417 CGContextAddLineToPoint(cgRef, x+offsetX, y+offsetY); 418 CGContextClosePath(cgRef); 419 break; 420 default: 421 break; 422 } 423 424 return renderType; 425 } 426 QUARTZ_RENDERER_INLINE SDRenderType doArc(QuartzSDOps *qsdo, CGFloat x, CGFloat y, CGFloat w, CGFloat h, CGFloat angleStart, CGFloat angleExtent, jint arcType, BOOL fill) 427 { 428 PRINT(" doArc") 429 if (YES) 430 { 431 return doArcUsingCG(qsdo->cgRef, x, y, w, h, angleStart, angleExtent, arcType, fill, 432 qsdo->graphicsStateInfo.offsetX, qsdo->graphicsStateInfo.offsetY); 433 } 434 // here we can add other implementations (ex. using QuickDraw, OpenGL, etc.) 435 } 436 437 QUARTZ_RENDERER_INLINE SDRenderType doPolyUsingCG(JNIEnv *env, CGContextRef cgRef, jintArray xpointsarray, jintArray ypointsarray, jint npoints, BOOL polygon, BOOL fill, CGFloat offsetX, CGFloat offsetY) 438 { 439 SDRenderType renderType = SD_Nothing; 440 441 if (npoints > 1) 442 { 443 if (fill == YES) 444 { 445 renderType = SD_Fill; 446 } 447 else 448 { 449 renderType = SD_Stroke; 450 } 451 452 jint i; 453 454 jint* xpoints = (jint*)(*env)->GetPrimitiveArrayCritical(env, xpointsarray, NULL); 455 jint* ypoints = (jint*)(*env)->GetPrimitiveArrayCritical(env, ypointsarray, NULL); 456 457 CGContextMoveToPoint(cgRef, xpoints[0]+offsetX, ypoints[0]+offsetY); 458 459 for (i=1; i<npoints; i++) 460 { 461 CGContextAddLineToPoint(cgRef, xpoints[i]+offsetX, ypoints[i]+offsetY); 462 } 463 464 if (polygon == YES) 465 { 466 if ((xpoints[0] != xpoints[npoints-1]) || (ypoints[0] != ypoints[npoints-1])) // according to the specs (only applies to polygons, not polylines) 467 { 468 CGContextAddLineToPoint(cgRef, xpoints[0]+offsetX, ypoints[0]+offsetY); 469 } 470 } 471 472 (*env)->ReleasePrimitiveArrayCritical(env, ypointsarray, ypoints, 0); 473 (*env)->ReleasePrimitiveArrayCritical(env, xpointsarray, xpoints, 0); 474 } 475 476 return renderType; 477 } 478 QUARTZ_RENDERER_INLINE SDRenderType doPoly(JNIEnv *env, QuartzSDOps *qsdo, jintArray xpointsarray, jintArray ypointsarray, jint npoints, BOOL polygon, BOOL fill) 479 { 480 PRINT(" doPoly") 481 if (YES) 482 { 483 return doPolyUsingCG(env, qsdo->cgRef, xpointsarray, ypointsarray, npoints, polygon, fill, 484 qsdo->graphicsStateInfo.offsetX, qsdo->graphicsStateInfo.offsetY); 485 } 486 // here we can add other implementations (ex. using QuickDraw, OpenGL, etc.) 487 } 488 489 SDRenderType doShape(QuartzSDOps *qsdo, jint *types, jfloat *coords, jint numtypes, BOOL fill, BOOL shouldApplyOffset) 490 { 491 PRINT(" doShape") 492 if (YES) 493 { 494 CGFloat offsetX = 0.0f; 495 CGFloat offsetY = 0.0f; 496 if (shouldApplyOffset) 497 { 498 offsetX = qsdo->graphicsStateInfo.offsetX; 499 offsetY = qsdo->graphicsStateInfo.offsetY; 500 } 501 return DoShapeUsingCG(qsdo->cgRef, types, coords, numtypes, fill, offsetX, offsetY); // defined in QuartzSurfaceData.m 502 } 503 // here we can add other implementations (ex. using QuickDraw, OpenGL, etc.) 504 } 505 506 507 508 QUARTZ_RENDERER_INLINE void doImageCG(JNIEnv *env, CGContextRef cgRef, jobject imageSurfaceData, 509 jint interpolation, BOOL fliph, BOOL flipv, jint w, jint h, jint sx, jint sy, jint sw, jint sh, jint dx, jint dy, jint dw, jint dh) 510 { 511 //fprintf(stderr, "doImageCG\n"); 512 //fprintf(stderr, " flip:(%d, %d), size:(%d, %d), src:(%d, %d, %d, %d), dst:(%d, %d, %d, %d)\n", (jint)fliph, (jint)flipv, w, h, sx, sy, sw, sh, dx, dy, dw, dh); 513 // gznote: need to handle interpolation 514 ImageSDOps* isdo = LockImage(env, imageSurfaceData); 515 516 CGFloat a = 1.0f; 517 CGFloat b = 0.0f; 518 CGFloat c = 0.0f; 519 CGFloat d = -1.0f; 520 CGFloat tx = dx; 521 CGFloat ty = dy+dh; 522 523 if (flipv == YES) 524 { 525 d = 1.0f; 526 ty -= dh; 527 } 528 if (fliph == YES) 529 { 530 a = -1.0f; 531 tx += dw; 532 } 533 534 makeSureImageIsCreated(isdo); 535 536 CGAffineTransform ctm = CGContextGetCTM(cgRef); 537 CGAffineTransform newTm = CGAffineTransformMake(a, b, c, d, tx, ty); 538 CGContextConcatCTM(cgRef, newTm); 539 jint alphaInfo = isdo->contextInfo.alphaInfo & kCGBitmapAlphaInfoMask; 540 541 if ((sx == 0) && (sy == 0) && (sw == w) && (sh == h)) // no subimages allowed here 542 { 543 CGContextDrawImage(cgRef, CGRectMake(0, 0, dw, dh), isdo->imgRef); 544 } 545 else // handle subimages 546 { 547 CGImageRef subImg = CGImageCreateWithImageInRect(isdo->imgRef, CGRectMake(sx, sy, sw, sh)); 548 CGContextDrawImage(cgRef, CGRectMake(0.0f, 0.0f, dw, dh), subImg); 549 CGImageRelease(subImg); 550 } 551 552 CGAffineTransform inverse = CGAffineTransformInvert(newTm); 553 CGContextConcatCTM(cgRef, inverse); 554 UnlockImage(env, isdo); 555 } 556 557 QUARTZ_RENDERER_INLINE void doImage(JNIEnv *env, QuartzSDOps *qsdo, jobject imageSurfaceData, 558 jboolean fliph, jboolean flipv, jint w, jint h, jint sx, jint sy, jint sw, jint sh, jint dx, jint dy, jint dw, jint dh) 559 { 560 if ((w > 0) && (h > 0) && (sw > 0) && (sh > 0) && (dw > 0) && (dh > 0)) 561 { 562 doImageCG(env, qsdo->cgRef, imageSurfaceData, 563 qsdo->graphicsStateInfo.interpolation, (BOOL)fliph, (BOOL)flipv, (jint)w, (jint)h, (jint)sx, (jint)sy, (jint)sw, (jint)sh, (jint)dx, (jint)dy, (jint)dw, (jint)dh); 564 } 565 } 566 567 568 569 QUARTZ_RENDERER_INLINE void completePath(JNIEnv *env, QuartzSDOps *qsdo, CGContextRef cgRef, jint renderType) 570 { 571 switch (renderType) 572 { 573 case SD_Stroke: 574 if (CGContextIsPathEmpty(cgRef) == 0) 575 { 576 CGContextStrokePath(cgRef); 577 } 578 break; 579 case SD_Fill: 580 if (CGContextIsPathEmpty(cgRef) == 0) 581 { 582 CGContextFillPath(cgRef); 583 } 584 break; 585 case SD_Image: 586 break; 587 case SD_Nothing: 588 break; 589 default: 590 fprintf(stderr, "completePath unknown renderType=%d\n", (int)renderType); 591 break; 592 } 593 } 594 595 /* 596 * Class: sun_java2d_CRenderer 597 * Method: init 598 * Signature: ()V 599 */ 600 JNIEXPORT void JNICALL Java_sun_java2d_CRenderer_init 601 (JNIEnv *env, jobject jthis) 602 { 603 PRINT("Java_sun_java2d_CRenderer_init") 604 CGFloat angle = PI / 4.0f; 605 CGFloat a = 1.0f - cos(angle); 606 CGFloat b = tan(angle); 607 CGFloat c = sqrt(1.0f + b * b) - 1.0f + a; 608 CGFloat cv = 4.0f / 3.0f * a * b / c; 609 CGFloat acv = (1.0f - cv) / 2.0f; 610 611 gRoundRectCtrlpts[2][3] = -acv; 612 gRoundRectCtrlpts[2][5] = acv; 613 gRoundRectCtrlpts[4][1] = -acv; 614 gRoundRectCtrlpts[4][7] = -acv; 615 gRoundRectCtrlpts[6][3] = acv; 616 gRoundRectCtrlpts[6][5] = -acv; 617 gRoundRectCtrlpts[8][1] = acv; 618 gRoundRectCtrlpts[8][7] = acv; 619 } 620 621 /* 622 * Class: sun_java2d_CRenderer 623 * Method: doLine 624 * Signature: (Lsun/java2d/SurfaceData;Ljava/nio/IntBuffer;Ljava/nio/FloatBuffer;[Ljava/lang/Object;FFFF)V 625 */ 626 JNIEXPORT void JNICALL Java_sun_java2d_CRenderer_doLine 627 (JNIEnv *env, jobject jthis, jobject jsurfacedata, jfloat x1, jfloat y1, jfloat x2, jfloat y2) 628 { 629 PRINT("Java_sun_java2d_CRenderer_doLine") 630 QuartzSDOps *qsdo = (QuartzSDOps*)SurfaceData_GetOps(env, jsurfacedata); 631 JNF_COCOA_ENTER(env); 632 SDRenderType renderType = SD_Stroke; 633 qsdo->BeginSurface(env, qsdo, renderType); 634 if (qsdo->cgRef != NULL) 635 { 636 doLine(qsdo, x1, y1, x2, y2); 637 } 638 qsdo->FinishSurface(env, qsdo); 639 JNF_COCOA_RENDERER_EXIT(env); 640 } 641 642 /* 643 * Class: sun_java2d_CRenderer 644 * Method: doRect 645 * Signature: (Lsun/java2d/SurfaceData;Ljava/nio/IntBuffer;Ljava/nio/FloatBuffer;[Ljava/lang/Object;FFFF)V 646 */ 647 JNIEXPORT void JNICALL Java_sun_java2d_CRenderer_doRect 648 (JNIEnv *env, jobject jthis, jobject jsurfacedata, jfloat x, jfloat y, jfloat w, jfloat h, jboolean isfill) 649 { 650 PRINT("Java_sun_java2d_CRenderer_doRect") 651 QuartzSDOps *qsdo = (QuartzSDOps*)SurfaceData_GetOps(env, jsurfacedata); 652 JNF_COCOA_ENTER(env); 653 SDRenderType renderType = (isfill? SD_Fill : SD_Stroke); 654 qsdo->BeginSurface(env, qsdo, renderType); 655 if (qsdo->cgRef != NULL) 656 { 657 doRect(qsdo, x, y, w, h, isfill); 658 } 659 qsdo->FinishSurface(env, qsdo); 660 JNF_COCOA_RENDERER_EXIT(env); 661 } 662 663 /* 664 * Class: sun_java2d_CRenderer 665 * Method: doRoundRect 666 * Signature: (Lsun/java2d/SurfaceData;Ljava/nio/IntBuffer;Ljava/nio/FloatBuffer;[Ljava/lang/Object;IIIIII)V 667 */ 668 JNIEXPORT void JNICALL Java_sun_java2d_CRenderer_doRoundRect 669 (JNIEnv *env, jobject jthis, jobject jsurfacedata, jfloat x, jfloat y, jfloat w, jfloat h, jfloat arcWidth, jfloat arcHeight, jboolean isfill) 670 { 671 PRINT("Java_sun_java2d_CRenderer_doRoundRect") 672 QuartzSDOps *qsdo = (QuartzSDOps*)SurfaceData_GetOps(env, jsurfacedata); 673 JNF_COCOA_ENTER(env); 674 SDRenderType renderType = (isfill? SD_Fill : SD_Stroke); 675 qsdo->BeginSurface(env, qsdo, renderType); 676 if (qsdo->cgRef != NULL) 677 { 678 doRoundRect(qsdo, x, y, w, h, arcWidth, arcHeight, isfill); 679 } 680 qsdo->FinishSurface(env, qsdo); 681 JNF_COCOA_RENDERER_EXIT(env); 682 } 683 684 /* 685 * Class: sun_java2d_CRenderer 686 * Method: doOval 687 * Signature: (Lsun/java2d/SurfaceData;Ljava/nio/IntBuffer;Ljava/nio/FloatBuffer;[Ljava/lang/Object;IIII)V 688 */ 689 JNIEXPORT void JNICALL Java_sun_java2d_CRenderer_doOval 690 (JNIEnv *env, jobject jthis, jobject jsurfacedata, jfloat x, jfloat y, jfloat w, jfloat h, jboolean isfill) 691 { 692 PRINT("Java_sun_java2d_CRenderer_doOval") 693 QuartzSDOps *qsdo = (QuartzSDOps*)SurfaceData_GetOps(env, jsurfacedata); 694 JNF_COCOA_ENTER(env); 695 SDRenderType renderType = (isfill? SD_Fill : SD_Stroke); 696 qsdo->BeginSurface(env, qsdo, renderType); 697 if (qsdo->cgRef != NULL) 698 { 699 doOval(qsdo, x, y, w, h, isfill); 700 } 701 qsdo->FinishSurface(env, qsdo); 702 JNF_COCOA_RENDERER_EXIT(env); 703 } 704 705 /* 706 * Class: sun_java2d_CRenderer 707 * Method: doArc 708 * Signature: (Lsun/java2d/SurfaceData;Ljava/nio/IntBuffer;Ljava/nio/FloatBuffer;[Ljava/lang/Object;IIIIII)V 709 */ 710 JNIEXPORT void JNICALL Java_sun_java2d_CRenderer_doArc 711 (JNIEnv *env, jobject jthis, jobject jsurfacedata, jfloat x, jfloat y, jfloat w, jfloat h, jfloat angleStart, jfloat angleExtent, jint arcType, jboolean isfill) 712 { 713 PRINT("Java_sun_java2d_CRenderer_doArc") 714 QuartzSDOps *qsdo = (QuartzSDOps*)SurfaceData_GetOps(env, jsurfacedata); 715 JNF_COCOA_ENTER(env); 716 SDRenderType renderType = (isfill? SD_Fill : SD_Stroke); 717 qsdo->BeginSurface(env, qsdo, renderType); 718 if (qsdo->cgRef != NULL) 719 { 720 doArc(qsdo, x, y, w, h, angleStart, angleExtent, arcType, isfill); 721 } 722 qsdo->FinishSurface(env, qsdo); 723 JNF_COCOA_RENDERER_EXIT(env); 724 } 725 726 /* 727 * Class: sun_java2d_CRenderer 728 * Method: doPoly 729 * Signature: 730 */ 731 JNIEXPORT void JNICALL Java_sun_java2d_CRenderer_doPoly 732 (JNIEnv *env, jobject jthis, jobject jsurfacedata, jintArray xpointsarray, jintArray ypointsarray, jint npoints, jboolean ispolygon, jboolean isfill) 733 { 734 PRINT("Java_sun_java2d_CRenderer_doPoly") 735 QuartzSDOps *qsdo = (QuartzSDOps*)SurfaceData_GetOps(env, jsurfacedata); 736 JNF_COCOA_ENTER(env); 737 BOOL eoFill = YES; // polys are WIND_EVEN_ODD by definition 738 SDRenderType renderType = (isfill? (eoFill ? SD_EOFill : SD_Fill) : SD_Stroke); 739 qsdo->BeginSurface(env, qsdo, renderType); 740 if (qsdo->cgRef != NULL) 741 { 742 doPoly(env, qsdo, xpointsarray, ypointsarray, npoints, ispolygon, isfill); 743 } 744 qsdo->FinishSurface(env, qsdo); 745 JNF_COCOA_RENDERER_EXIT(env); 746 } 747 748 /* 749 * Class: sun_java2d_CRenderer 750 * Method: doShape 751 * Signature: (Lsun/java2d/SurfaceData;Ljava/nio/IntBuffer;Ljava/nio/FloatBuffer;[Ljava/lang/Object;ILjava/nio/FloatBuffer;Ljava/nio/IntBuffer;IZ)V 752 */ 753 JNIEXPORT void JNICALL Java_sun_java2d_CRenderer_doShape 754 (JNIEnv *env, jobject jthis, jobject jsurfacedata, jint length, jobject jFloatCoordinates, jobject jIntTypes, jint windingRule, jboolean isfill, jboolean shouldApplyOffset) 755 { 756 PRINT("Java_sun_java2d_CRenderer_doShape") 757 QuartzSDOps *qsdo = (QuartzSDOps*)SurfaceData_GetOps(env, jsurfacedata); 758 JNF_COCOA_ENTER(env); 759 BOOL eoFill = (windingRule == java_awt_geom_PathIterator_WIND_EVEN_ODD); 760 SDRenderType renderType = (isfill? (eoFill ? SD_EOFill : SD_Fill) : SD_Stroke); 761 qsdo->BeginSurface(env, qsdo, renderType); 762 if (qsdo->cgRef != NULL) 763 { 764 jfloat *coordinates = (jfloat*)((*env)->GetDirectBufferAddress(env, jFloatCoordinates)); 765 jint *types = (jint*)((*env)->GetDirectBufferAddress(env, jIntTypes)); 766 doShape(qsdo, types, coordinates, length, isfill, shouldApplyOffset); 767 } 768 qsdo->FinishSurface(env, qsdo); 769 JNF_COCOA_RENDERER_EXIT(env); 770 } 771 772 #define invalidContext(c) \ 773 ((c) == NULL /* || (c)->identifer != CGContextIdentifier */) 774 775 /* 776 * Class: sun_java2d_CRenderer 777 * Method: doImage 778 * Signature: (Lsun/java2d/SurfaceData;Ljava/nio/IntBuffer;Ljava/nio/FloatBuffer;[Ljava/lang/Object;Lsun/java2d/SurfaceData;ZZIIIIIIII)V 779 */ 780 JNIEXPORT void JNICALL Java_sun_java2d_CRenderer_doImage 781 (JNIEnv *env, jobject jthis, jobject jsurfacedata, jobject imageSurfaceData, jboolean fliph, jboolean flipv, jint w, jint h, jint sx, jint sy, jint sw, jint sh, jint dx, jint dy, jint dw, jint dh) 782 { 783 PRINT("Java_sun_java2d_CRenderer_doImage") 784 QuartzSDOps *qsdo = (QuartzSDOps*)SurfaceData_GetOps(env, jsurfacedata); 785 JNF_COCOA_ENTER(env); 786 qsdo->BeginSurface(env, qsdo, SD_Image); 787 if (qsdo->cgRef != NULL) 788 { 789 doImage(env, qsdo, imageSurfaceData, fliph, flipv, w, h, sx, sy, sw, sh, dx, dy, dw, dh); 790 } 791 qsdo->FinishSurface(env, qsdo); 792 JNF_COCOA_RENDERER_EXIT(env); 793 }