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#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 54static 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 68CG_EXTERN CGRect CGRectApplyAffineTransform(CGRect rect, CGAffineTransform t); 69 70 71CGRect 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 86QUARTZ_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} 110QUARTZ_RENDERER_INLINE SDRenderType doLine(QuartzSDOps *qsdo, CGFloat x1, CGFloat y1, CGFloat x2, CGFloat y2) 111{ 112PRINT(" 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 122QUARTZ_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} 160QUARTZ_RENDERER_INLINE SDRenderType doRect(QuartzSDOps *qsdo, CGFloat x, CGFloat y, CGFloat w, CGFloat h, BOOL fill) 161{ 162PRINT(" 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 172QUARTZ_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 259QUARTZ_RENDERER_INLINE SDRenderType doRoundRect(QuartzSDOps *qsdo, CGFloat x, CGFloat y, CGFloat w, CGFloat h, CGFloat arcWidth, CGFloat arcHeight, BOOL fill) 260{ 261PRINT(" 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 271QUARTZ_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} 302QUARTZ_RENDERER_INLINE SDRenderType doOval(QuartzSDOps *qsdo, CGFloat x, CGFloat y, CGFloat w, CGFloat h, BOOL fill) 303{ 304PRINT(" 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 314QUARTZ_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} 323QUARTZ_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} 426QUARTZ_RENDERER_INLINE SDRenderType doArc(QuartzSDOps *qsdo, CGFloat x, CGFloat y, CGFloat w, CGFloat h, CGFloat angleStart, CGFloat angleExtent, jint arcType, BOOL fill) 427{ 428PRINT(" 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 437QUARTZ_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 (xpointsarray == NULL || ypointsarray == NULL) { 442 return 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 if (xpoints == NULL) { 459 return SD_Nothing; 460 } 461 jint* ypoints = (jint*)(*env)->GetPrimitiveArrayCritical(env, ypointsarray, NULL); 462 if (ypoints == NULL) { 463 (*env)->ReleasePrimitiveArrayCritical(env, xpointsarray, xpoints, 0); 464 return SD_Nothing; 465 } 466 467 CGContextMoveToPoint(cgRef, xpoints[0]+offsetX, ypoints[0]+offsetY); 468 469 for (i=1; i<npoints; i++) 470 { 471 CGContextAddLineToPoint(cgRef, xpoints[i]+offsetX, ypoints[i]+offsetY); 472 } 473 474 if (polygon == YES) 475 { 476 if ((xpoints[0] != xpoints[npoints-1]) || (ypoints[0] != ypoints[npoints-1])) // according to the specs (only applies to polygons, not polylines) 477 { 478 CGContextAddLineToPoint(cgRef, xpoints[0]+offsetX, ypoints[0]+offsetY); 479 } 480 } 481 482 (*env)->ReleasePrimitiveArrayCritical(env, ypointsarray, ypoints, 0); 483 (*env)->ReleasePrimitiveArrayCritical(env, xpointsarray, xpoints, 0); 484 } 485 486 return renderType; 487} 488QUARTZ_RENDERER_INLINE SDRenderType doPoly(JNIEnv *env, QuartzSDOps *qsdo, jintArray xpointsarray, jintArray ypointsarray, jint npoints, BOOL polygon, BOOL fill) 489{ 490PRINT(" doPoly") 491 if (YES) 492 { 493 return doPolyUsingCG(env, qsdo->cgRef, xpointsarray, ypointsarray, npoints, polygon, fill, 494 qsdo->graphicsStateInfo.offsetX, qsdo->graphicsStateInfo.offsetY); 495 } 496 // here we can add other implementations (ex. using QuickDraw, OpenGL, etc.) 497} 498 499SDRenderType doShape(QuartzSDOps *qsdo, jint *types, jfloat *coords, jint numtypes, BOOL fill, BOOL shouldApplyOffset) 500{ 501PRINT(" doShape") 502 if (YES) 503 { 504 CGFloat offsetX = 0.0f; 505 CGFloat offsetY = 0.0f; 506 if (shouldApplyOffset) 507 { 508 offsetX = qsdo->graphicsStateInfo.offsetX; 509 offsetY = qsdo->graphicsStateInfo.offsetY; 510 } 511 return DoShapeUsingCG(qsdo->cgRef, types, coords, numtypes, fill, offsetX, offsetY); // defined in QuartzSurfaceData.m 512 } 513 // here we can add other implementations (ex. using QuickDraw, OpenGL, etc.) 514} 515 516 517 518QUARTZ_RENDERER_INLINE void doImageCG(JNIEnv *env, CGContextRef cgRef, jobject imageSurfaceData, 519 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) 520{ 521//fprintf(stderr, "doImageCG\n"); 522//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); 523 // gznote: need to handle interpolation 524 ImageSDOps* isdo = LockImage(env, imageSurfaceData); 525 526 CGFloat a = 1.0f; 527 CGFloat b = 0.0f; 528 CGFloat c = 0.0f; 529 CGFloat d = -1.0f; 530 CGFloat tx = dx; 531 CGFloat ty = dy+dh; 532 533 if (flipv == YES) 534 { 535 d = 1.0f; 536 ty -= dh; 537 } 538 if (fliph == YES) 539 { 540 a = -1.0f; 541 tx += dw; 542 } 543 544 makeSureImageIsCreated(isdo); 545 546 CGContextSaveGState(cgRef); 547 CGContextConcatCTM(cgRef, CGAffineTransformMake(a, b, c, d, tx, ty)); 548 jint alphaInfo = isdo->contextInfo.alphaInfo & kCGBitmapAlphaInfoMask; 549 550 if ((sx == 0) && (sy == 0) && (sw == w) && (sh == h)) // no subimages allowed here 551 { 552 CGContextDrawImage(cgRef, CGRectMake(0, 0, dw, dh), isdo->imgRef); 553 } 554 else // handle subimages 555 { 556 CGImageRef subImg = CGImageCreateWithImageInRect(isdo->imgRef, CGRectMake(sx, sy, sw, sh)); 557 CGContextDrawImage(cgRef, CGRectMake(0.0f, 0.0f, dw, dh), subImg); 558 CGImageRelease(subImg); 559 } 560 561 CGContextRestoreGState(cgRef); 562 UnlockImage(env, isdo); 563} 564 565QUARTZ_RENDERER_INLINE void doImage(JNIEnv *env, QuartzSDOps *qsdo, jobject imageSurfaceData, 566 jboolean fliph, jboolean flipv, jint w, jint h, jint sx, jint sy, jint sw, jint sh, jint dx, jint dy, jint dw, jint dh) 567{ 568 if ((w > 0) && (h > 0) && (sw > 0) && (sh > 0) && (dw > 0) && (dh > 0)) 569 { 570 doImageCG(env, qsdo->cgRef, imageSurfaceData, 571 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); 572 } 573} 574 575 576 577QUARTZ_RENDERER_INLINE void completePath(JNIEnv *env, QuartzSDOps *qsdo, CGContextRef cgRef, jint renderType) 578{ 579 switch (renderType) 580 { 581 case SD_Stroke: 582 if (CGContextIsPathEmpty(cgRef) == 0) 583 { 584 CGContextStrokePath(cgRef); 585 } 586 break; 587 case SD_Fill: 588 if (CGContextIsPathEmpty(cgRef) == 0) 589 { 590 CGContextFillPath(cgRef); 591 } 592 break; 593 case SD_Image: 594 break; 595 case SD_Nothing: 596 break; 597 default: 598fprintf(stderr, "completePath unknown renderType=%d\n", (int)renderType); 599 break; 600 } 601} 602 603/* 604 * Class: sun_java2d_CRenderer 605 * Method: init 606 * Signature: ()V 607 */ 608JNIEXPORT void JNICALL Java_sun_java2d_CRenderer_init 609(JNIEnv *env, jobject jthis) 610{ 611PRINT("Java_sun_java2d_CRenderer_init") 612 CGFloat angle = PI / 4.0f; 613 CGFloat a = 1.0f - cos(angle); 614 CGFloat b = tan(angle); 615 CGFloat c = sqrt(1.0f + b * b) - 1.0f + a; 616 CGFloat cv = 4.0f / 3.0f * a * b / c; 617 CGFloat acv = (1.0f - cv) / 2.0f; 618 619 gRoundRectCtrlpts[2][3] = -acv; 620 gRoundRectCtrlpts[2][5] = acv; 621 gRoundRectCtrlpts[4][1] = -acv; 622 gRoundRectCtrlpts[4][7] = -acv; 623 gRoundRectCtrlpts[6][3] = acv; 624 gRoundRectCtrlpts[6][5] = -acv; 625 gRoundRectCtrlpts[8][1] = acv; 626 gRoundRectCtrlpts[8][7] = acv; 627} 628 629/* 630 * Class: sun_java2d_CRenderer 631 * Method: doLine 632 * Signature: (Lsun/java2d/SurfaceData;Ljava/nio/IntBuffer;Ljava/nio/FloatBuffer;[Ljava/lang/Object;FFFF)V 633 */ 634JNIEXPORT void JNICALL Java_sun_java2d_CRenderer_doLine 635(JNIEnv *env, jobject jthis, jobject jsurfacedata, jfloat x1, jfloat y1, jfloat x2, jfloat y2) 636{ 637PRINT("Java_sun_java2d_CRenderer_doLine") 638 QuartzSDOps *qsdo = (QuartzSDOps*)SurfaceData_GetOps(env, jsurfacedata); 639JNF_COCOA_ENTER(env); 640 SDRenderType renderType = SD_Stroke; 641 qsdo->BeginSurface(env, qsdo, renderType); 642 if (qsdo->cgRef != NULL) 643 { 644 doLine(qsdo, x1, y1, x2, y2); 645 } 646 qsdo->FinishSurface(env, qsdo); 647JNF_COCOA_RENDERER_EXIT(env); 648} 649 650/* 651 * Class: sun_java2d_CRenderer 652 * Method: doRect 653 * Signature: (Lsun/java2d/SurfaceData;Ljava/nio/IntBuffer;Ljava/nio/FloatBuffer;[Ljava/lang/Object;FFFF)V 654 */ 655JNIEXPORT void JNICALL Java_sun_java2d_CRenderer_doRect 656(JNIEnv *env, jobject jthis, jobject jsurfacedata, jfloat x, jfloat y, jfloat w, jfloat h, jboolean isfill) 657{ 658PRINT("Java_sun_java2d_CRenderer_doRect") 659 QuartzSDOps *qsdo = (QuartzSDOps*)SurfaceData_GetOps(env, jsurfacedata); 660JNF_COCOA_ENTER(env); 661 SDRenderType renderType = (isfill? SD_Fill : SD_Stroke); 662 qsdo->BeginSurface(env, qsdo, renderType); 663 if (qsdo->cgRef != NULL) 664 { 665 doRect(qsdo, x, y, w, h, isfill); 666 } 667 qsdo->FinishSurface(env, qsdo); 668JNF_COCOA_RENDERER_EXIT(env); 669} 670 671/* 672 * Class: sun_java2d_CRenderer 673 * Method: doRoundRect 674 * Signature: (Lsun/java2d/SurfaceData;Ljava/nio/IntBuffer;Ljava/nio/FloatBuffer;[Ljava/lang/Object;IIIIII)V 675 */ 676JNIEXPORT void JNICALL Java_sun_java2d_CRenderer_doRoundRect 677(JNIEnv *env, jobject jthis, jobject jsurfacedata, jfloat x, jfloat y, jfloat w, jfloat h, jfloat arcWidth, jfloat arcHeight, jboolean isfill) 678{ 679PRINT("Java_sun_java2d_CRenderer_doRoundRect") 680 QuartzSDOps *qsdo = (QuartzSDOps*)SurfaceData_GetOps(env, jsurfacedata); 681JNF_COCOA_ENTER(env); 682 SDRenderType renderType = (isfill? SD_Fill : SD_Stroke); 683 qsdo->BeginSurface(env, qsdo, renderType); 684 if (qsdo->cgRef != NULL) 685 { 686 doRoundRect(qsdo, x, y, w, h, arcWidth, arcHeight, isfill); 687 } 688 qsdo->FinishSurface(env, qsdo); 689JNF_COCOA_RENDERER_EXIT(env); 690} 691 692/* 693 * Class: sun_java2d_CRenderer 694 * Method: doOval 695 * Signature: (Lsun/java2d/SurfaceData;Ljava/nio/IntBuffer;Ljava/nio/FloatBuffer;[Ljava/lang/Object;IIII)V 696 */ 697JNIEXPORT void JNICALL Java_sun_java2d_CRenderer_doOval 698(JNIEnv *env, jobject jthis, jobject jsurfacedata, jfloat x, jfloat y, jfloat w, jfloat h, jboolean isfill) 699{ 700PRINT("Java_sun_java2d_CRenderer_doOval") 701 QuartzSDOps *qsdo = (QuartzSDOps*)SurfaceData_GetOps(env, jsurfacedata); 702JNF_COCOA_ENTER(env); 703 SDRenderType renderType = (isfill? SD_Fill : SD_Stroke); 704 qsdo->BeginSurface(env, qsdo, renderType); 705 if (qsdo->cgRef != NULL) 706 { 707 doOval(qsdo, x, y, w, h, isfill); 708 } 709 qsdo->FinishSurface(env, qsdo); 710JNF_COCOA_RENDERER_EXIT(env); 711} 712 713/* 714 * Class: sun_java2d_CRenderer 715 * Method: doArc 716 * Signature: (Lsun/java2d/SurfaceData;Ljava/nio/IntBuffer;Ljava/nio/FloatBuffer;[Ljava/lang/Object;IIIIII)V 717 */ 718JNIEXPORT void JNICALL Java_sun_java2d_CRenderer_doArc 719(JNIEnv *env, jobject jthis, jobject jsurfacedata, jfloat x, jfloat y, jfloat w, jfloat h, jfloat angleStart, jfloat angleExtent, jint arcType, jboolean isfill) 720{ 721PRINT("Java_sun_java2d_CRenderer_doArc") 722 QuartzSDOps *qsdo = (QuartzSDOps*)SurfaceData_GetOps(env, jsurfacedata); 723JNF_COCOA_ENTER(env); 724 SDRenderType renderType = (isfill? SD_Fill : SD_Stroke); 725 qsdo->BeginSurface(env, qsdo, renderType); 726 if (qsdo->cgRef != NULL) 727 { 728 doArc(qsdo, x, y, w, h, angleStart, angleExtent, arcType, isfill); 729 } 730 qsdo->FinishSurface(env, qsdo); 731JNF_COCOA_RENDERER_EXIT(env); 732} 733 734/* 735 * Class: sun_java2d_CRenderer 736 * Method: doPoly 737 * Signature: 738 */ 739JNIEXPORT void JNICALL Java_sun_java2d_CRenderer_doPoly 740(JNIEnv *env, jobject jthis, jobject jsurfacedata, jintArray xpointsarray, jintArray ypointsarray, jint npoints, jboolean ispolygon, jboolean isfill) 741{ 742PRINT("Java_sun_java2d_CRenderer_doPoly") 743 QuartzSDOps *qsdo = (QuartzSDOps*)SurfaceData_GetOps(env, jsurfacedata); 744JNF_COCOA_ENTER(env); 745 BOOL eoFill = YES; // polys are WIND_EVEN_ODD by definition 746 SDRenderType renderType = (isfill? (eoFill ? SD_EOFill : SD_Fill) : SD_Stroke); 747 qsdo->BeginSurface(env, qsdo, renderType); 748 if (qsdo->cgRef != NULL) 749 { 750 doPoly(env, qsdo, xpointsarray, ypointsarray, npoints, ispolygon, isfill); 751 } 752 qsdo->FinishSurface(env, qsdo); 753JNF_COCOA_RENDERER_EXIT(env); 754} 755 756/* 757 * Class: sun_java2d_CRenderer 758 * Method: doShape 759 * Signature: (Lsun/java2d/SurfaceData;Ljava/nio/IntBuffer;Ljava/nio/FloatBuffer;[Ljava/lang/Object;ILjava/nio/FloatBuffer;Ljava/nio/IntBuffer;IZ)V 760 */ 761JNIEXPORT void JNICALL Java_sun_java2d_CRenderer_doShape 762(JNIEnv *env, jobject jthis, jobject jsurfacedata, jint length, jobject jFloatCoordinates, jobject jIntTypes, jint windingRule, jboolean isfill, jboolean shouldApplyOffset) 763{ 764PRINT("Java_sun_java2d_CRenderer_doShape") 765 QuartzSDOps *qsdo = (QuartzSDOps*)SurfaceData_GetOps(env, jsurfacedata); 766JNF_COCOA_ENTER(env); 767 BOOL eoFill = (windingRule == java_awt_geom_PathIterator_WIND_EVEN_ODD); 768 SDRenderType renderType = (isfill? (eoFill ? SD_EOFill : SD_Fill) : SD_Stroke); 769 qsdo->BeginSurface(env, qsdo, renderType); 770 if (qsdo->cgRef != NULL) 771 { 772 jfloat *coordinates = (jfloat*)((*env)->GetDirectBufferAddress(env, jFloatCoordinates)); 773 jint *types = (jint*)((*env)->GetDirectBufferAddress(env, jIntTypes)); 774 doShape(qsdo, types, coordinates, length, isfill, shouldApplyOffset); 775 } 776 qsdo->FinishSurface(env, qsdo); 777JNF_COCOA_RENDERER_EXIT(env); 778} 779 780#define invalidContext(c) \ 781 ((c) == NULL /* || (c)->identifer != CGContextIdentifier */) 782 783/* 784 * Class: sun_java2d_CRenderer 785 * Method: doImage 786 * Signature: (Lsun/java2d/SurfaceData;Ljava/nio/IntBuffer;Ljava/nio/FloatBuffer;[Ljava/lang/Object;Lsun/java2d/SurfaceData;ZZIIIIIIII)V 787 */ 788JNIEXPORT void JNICALL Java_sun_java2d_CRenderer_doImage 789(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) 790{ 791PRINT("Java_sun_java2d_CRenderer_doImage") 792 QuartzSDOps *qsdo = (QuartzSDOps*)SurfaceData_GetOps(env, jsurfacedata); 793JNF_COCOA_ENTER(env); 794 qsdo->BeginSurface(env, qsdo, SD_Image); 795 if (qsdo->cgRef != NULL) 796 { 797 doImage(env, qsdo, imageSurfaceData, fliph, flipv, w, h, sx, sy, sw, sh, dx, dy, dw, dh); 798 } 799 qsdo->FinishSurface(env, qsdo); 800JNF_COCOA_RENDERER_EXIT(env); 801} 802