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