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