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 CGContextSaveGState(cgRef); 537 CGContextConcatCTM(cgRef, CGAffineTransformMake(a, b, c, d, tx, ty)); 538 jint alphaInfo = isdo->contextInfo.alphaInfo & kCGBitmapAlphaInfoMask; 539 540 if ((sx == 0) && (sy == 0) && (sw == w) && (sh == h)) // no subimages allowed here 541 { 542 CGContextDrawImage(cgRef, CGRectMake(0, 0, dw, dh), isdo->imgRef); 543 } 544 else // handle subimages 545 { 546 CGImageRef subImg = CGImageCreateWithImageInRect(isdo->imgRef, CGRectMake(sx, sy, sw, sh)); 547 CGContextDrawImage(cgRef, CGRectMake(0.0f, 0.0f, dw, dh), subImg); 548 CGImageRelease(subImg); 549 } 550 551 CGContextRestoreGState(cgRef); 552 UnlockImage(env, isdo); 553 } 554 555 QUARTZ_RENDERER_INLINE void doImage(JNIEnv *env, QuartzSDOps *qsdo, jobject imageSurfaceData, 556 jboolean fliph, jboolean flipv, jint w, jint h, jint sx, jint sy, jint sw, jint sh, jint dx, jint dy, jint dw, jint dh) 557 { 558 if ((w > 0) && (h > 0) && (sw > 0) && (sh > 0) && (dw > 0) && (dh > 0)) 559 { 560 doImageCG(env, qsdo->cgRef, imageSurfaceData, 561 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); 562 } 563 } 564 565 566 567 QUARTZ_RENDERER_INLINE void completePath(JNIEnv *env, QuartzSDOps *qsdo, CGContextRef cgRef, jint renderType) 568 { 569 switch (renderType) 570 { 571 case SD_Stroke: 572 if (CGContextIsPathEmpty(cgRef) == 0) 573 { 574 CGContextStrokePath(cgRef); 575 } 576 break; 577 case SD_Fill: 578 if (CGContextIsPathEmpty(cgRef) == 0) 579 { 580 CGContextFillPath(cgRef); 581 } 582 break; 583 case SD_Image: 584 break; 585 case SD_Nothing: 586 break; 587 default: 588 fprintf(stderr, "completePath unknown renderType=%d\n", (int)renderType); 589 break; 590 } 591 } 592 593 /* 594 * Class: sun_java2d_CRenderer 595 * Method: init 596 * Signature: ()V 597 */ 598 JNIEXPORT void JNICALL Java_sun_java2d_CRenderer_init 599 (JNIEnv *env, jobject jthis) 600 { 601 PRINT("Java_sun_java2d_CRenderer_init") 602 CGFloat angle = PI / 4.0f; 603 CGFloat a = 1.0f - cos(angle); 604 CGFloat b = tan(angle); 605 CGFloat c = sqrt(1.0f + b * b) - 1.0f + a; 606 CGFloat cv = 4.0f / 3.0f * a * b / c; 607 CGFloat acv = (1.0f - cv) / 2.0f; 608 609 gRoundRectCtrlpts[2][3] = -acv; 610 gRoundRectCtrlpts[2][5] = acv; 611 gRoundRectCtrlpts[4][1] = -acv; 612 gRoundRectCtrlpts[4][7] = -acv; 613 gRoundRectCtrlpts[6][3] = acv; 614 gRoundRectCtrlpts[6][5] = -acv; 615 gRoundRectCtrlpts[8][1] = acv; 616 gRoundRectCtrlpts[8][7] = acv; 617 } 618 619 /* 620 * Class: sun_java2d_CRenderer 621 * Method: doLine 622 * Signature: (Lsun/java2d/SurfaceData;Ljava/nio/IntBuffer;Ljava/nio/FloatBuffer;[Ljava/lang/Object;FFFF)V 623 */ 624 JNIEXPORT void JNICALL Java_sun_java2d_CRenderer_doLine 625 (JNIEnv *env, jobject jthis, jobject jsurfacedata, jfloat x1, jfloat y1, jfloat x2, jfloat y2) 626 { 627 PRINT("Java_sun_java2d_CRenderer_doLine") 628 QuartzSDOps *qsdo = (QuartzSDOps*)SurfaceData_GetOps(env, jsurfacedata); 629 JNF_COCOA_ENTER(env); 630 SDRenderType renderType = SD_Stroke; 631 qsdo->BeginSurface(env, qsdo, renderType); 632 if (qsdo->cgRef != NULL) 633 { 634 doLine(qsdo, x1, y1, x2, y2); 635 } 636 qsdo->FinishSurface(env, qsdo); 637 JNF_COCOA_RENDERER_EXIT(env); 638 } 639 640 /* 641 * Class: sun_java2d_CRenderer 642 * Method: doRect 643 * Signature: (Lsun/java2d/SurfaceData;Ljava/nio/IntBuffer;Ljava/nio/FloatBuffer;[Ljava/lang/Object;FFFF)V 644 */ 645 JNIEXPORT void JNICALL Java_sun_java2d_CRenderer_doRect 646 (JNIEnv *env, jobject jthis, jobject jsurfacedata, jfloat x, jfloat y, jfloat w, jfloat h, jboolean isfill) 647 { 648 PRINT("Java_sun_java2d_CRenderer_doRect") 649 QuartzSDOps *qsdo = (QuartzSDOps*)SurfaceData_GetOps(env, jsurfacedata); 650 JNF_COCOA_ENTER(env); 651 SDRenderType renderType = (isfill? SD_Fill : SD_Stroke); 652 qsdo->BeginSurface(env, qsdo, renderType); 653 if (qsdo->cgRef != NULL) 654 { 655 doRect(qsdo, x, y, w, h, isfill); 656 } 657 qsdo->FinishSurface(env, qsdo); 658 JNF_COCOA_RENDERER_EXIT(env); 659 } 660 661 /* 662 * Class: sun_java2d_CRenderer 663 * Method: doRoundRect 664 * Signature: (Lsun/java2d/SurfaceData;Ljava/nio/IntBuffer;Ljava/nio/FloatBuffer;[Ljava/lang/Object;IIIIII)V 665 */ 666 JNIEXPORT void JNICALL Java_sun_java2d_CRenderer_doRoundRect 667 (JNIEnv *env, jobject jthis, jobject jsurfacedata, jfloat x, jfloat y, jfloat w, jfloat h, jfloat arcWidth, jfloat arcHeight, jboolean isfill) 668 { 669 PRINT("Java_sun_java2d_CRenderer_doRoundRect") 670 QuartzSDOps *qsdo = (QuartzSDOps*)SurfaceData_GetOps(env, jsurfacedata); 671 JNF_COCOA_ENTER(env); 672 SDRenderType renderType = (isfill? SD_Fill : SD_Stroke); 673 qsdo->BeginSurface(env, qsdo, renderType); 674 if (qsdo->cgRef != NULL) 675 { 676 doRoundRect(qsdo, x, y, w, h, arcWidth, arcHeight, isfill); 677 } 678 qsdo->FinishSurface(env, qsdo); 679 JNF_COCOA_RENDERER_EXIT(env); 680 } 681 682 /* 683 * Class: sun_java2d_CRenderer 684 * Method: doOval 685 * Signature: (Lsun/java2d/SurfaceData;Ljava/nio/IntBuffer;Ljava/nio/FloatBuffer;[Ljava/lang/Object;IIII)V 686 */ 687 JNIEXPORT void JNICALL Java_sun_java2d_CRenderer_doOval 688 (JNIEnv *env, jobject jthis, jobject jsurfacedata, jfloat x, jfloat y, jfloat w, jfloat h, jboolean isfill) 689 { 690 PRINT("Java_sun_java2d_CRenderer_doOval") 691 QuartzSDOps *qsdo = (QuartzSDOps*)SurfaceData_GetOps(env, jsurfacedata); 692 JNF_COCOA_ENTER(env); 693 SDRenderType renderType = (isfill? SD_Fill : SD_Stroke); 694 qsdo->BeginSurface(env, qsdo, renderType); 695 if (qsdo->cgRef != NULL) 696 { 697 doOval(qsdo, x, y, w, h, isfill); 698 } 699 qsdo->FinishSurface(env, qsdo); 700 JNF_COCOA_RENDERER_EXIT(env); 701 } 702 703 /* 704 * Class: sun_java2d_CRenderer 705 * Method: doArc 706 * Signature: (Lsun/java2d/SurfaceData;Ljava/nio/IntBuffer;Ljava/nio/FloatBuffer;[Ljava/lang/Object;IIIIII)V 707 */ 708 JNIEXPORT void JNICALL Java_sun_java2d_CRenderer_doArc 709 (JNIEnv *env, jobject jthis, jobject jsurfacedata, jfloat x, jfloat y, jfloat w, jfloat h, jfloat angleStart, jfloat angleExtent, jint arcType, jboolean isfill) 710 { 711 PRINT("Java_sun_java2d_CRenderer_doArc") 712 QuartzSDOps *qsdo = (QuartzSDOps*)SurfaceData_GetOps(env, jsurfacedata); 713 JNF_COCOA_ENTER(env); 714 SDRenderType renderType = (isfill? SD_Fill : SD_Stroke); 715 qsdo->BeginSurface(env, qsdo, renderType); 716 if (qsdo->cgRef != NULL) 717 { 718 doArc(qsdo, x, y, w, h, angleStart, angleExtent, arcType, isfill); 719 } 720 qsdo->FinishSurface(env, qsdo); 721 JNF_COCOA_RENDERER_EXIT(env); 722 } 723 724 /* 725 * Class: sun_java2d_CRenderer 726 * Method: doPoly 727 * Signature: 728 */ 729 JNIEXPORT void JNICALL Java_sun_java2d_CRenderer_doPoly 730 (JNIEnv *env, jobject jthis, jobject jsurfacedata, jintArray xpointsarray, jintArray ypointsarray, jint npoints, jboolean ispolygon, jboolean isfill) 731 { 732 PRINT("Java_sun_java2d_CRenderer_doPoly") 733 QuartzSDOps *qsdo = (QuartzSDOps*)SurfaceData_GetOps(env, jsurfacedata); 734 JNF_COCOA_ENTER(env); 735 BOOL eoFill = YES; // polys are WIND_EVEN_ODD by definition 736 SDRenderType renderType = (isfill? (eoFill ? SD_EOFill : SD_Fill) : SD_Stroke); 737 qsdo->BeginSurface(env, qsdo, renderType); 738 if (qsdo->cgRef != NULL) 739 { 740 doPoly(env, qsdo, xpointsarray, ypointsarray, npoints, ispolygon, isfill); 741 } 742 qsdo->FinishSurface(env, qsdo); 743 JNF_COCOA_RENDERER_EXIT(env); 744 } 745 746 /* 747 * Class: sun_java2d_CRenderer 748 * Method: doShape 749 * Signature: (Lsun/java2d/SurfaceData;Ljava/nio/IntBuffer;Ljava/nio/FloatBuffer;[Ljava/lang/Object;ILjava/nio/FloatBuffer;Ljava/nio/IntBuffer;IZ)V 750 */ 751 JNIEXPORT void JNICALL Java_sun_java2d_CRenderer_doShape 752 (JNIEnv *env, jobject jthis, jobject jsurfacedata, jint length, jobject jFloatCoordinates, jobject jIntTypes, jint windingRule, jboolean isfill, jboolean shouldApplyOffset) 753 { 754 PRINT("Java_sun_java2d_CRenderer_doShape") 755 QuartzSDOps *qsdo = (QuartzSDOps*)SurfaceData_GetOps(env, jsurfacedata); 756 JNF_COCOA_ENTER(env); 757 BOOL eoFill = (windingRule == java_awt_geom_PathIterator_WIND_EVEN_ODD); 758 SDRenderType renderType = (isfill? (eoFill ? SD_EOFill : SD_Fill) : SD_Stroke); 759 qsdo->BeginSurface(env, qsdo, renderType); 760 if (qsdo->cgRef != NULL) 761 { 762 jfloat *coordinates = (jfloat*)((*env)->GetDirectBufferAddress(env, jFloatCoordinates)); 763 jint *types = (jint*)((*env)->GetDirectBufferAddress(env, jIntTypes)); 764 doShape(qsdo, types, coordinates, length, isfill, shouldApplyOffset); 765 } 766 qsdo->FinishSurface(env, qsdo); 767 JNF_COCOA_RENDERER_EXIT(env); 768 } 769 770 #define invalidContext(c) \ 771 ((c) == NULL /* || (c)->identifer != CGContextIdentifier */) 772 773 /* 774 * Class: sun_java2d_CRenderer 775 * Method: doImage 776 * Signature: (Lsun/java2d/SurfaceData;Ljava/nio/IntBuffer;Ljava/nio/FloatBuffer;[Ljava/lang/Object;Lsun/java2d/SurfaceData;ZZIIIIIIII)V 777 */ 778 JNIEXPORT void JNICALL Java_sun_java2d_CRenderer_doImage 779 (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) 780 { 781 PRINT("Java_sun_java2d_CRenderer_doImage") 782 QuartzSDOps *qsdo = (QuartzSDOps*)SurfaceData_GetOps(env, jsurfacedata); 783 JNF_COCOA_ENTER(env); 784 qsdo->BeginSurface(env, qsdo, SD_Image); 785 if (qsdo->cgRef != NULL) 786 { 787 doImage(env, qsdo, imageSurfaceData, fliph, flipv, w, h, sx, sy, sw, sh, dx, dy, dw, dh); 788 } 789 qsdo->FinishSurface(env, qsdo); 790 JNF_COCOA_RENDERER_EXIT(env); 791 }