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 53static 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 67CG_EXTERN CGRect CGRectApplyAffineTransform(CGRect rect, CGAffineTransform t); 68 69 70CGRect 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 85QUARTZ_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} 109QUARTZ_RENDERER_INLINE SDRenderType doLine(QuartzSDOps *qsdo, CGFloat x1, CGFloat y1, CGFloat x2, CGFloat y2) 110{ 111PRINT(" 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 121QUARTZ_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} 159QUARTZ_RENDERER_INLINE SDRenderType doRect(QuartzSDOps *qsdo, CGFloat x, CGFloat y, CGFloat w, CGFloat h, BOOL fill) 160{ 161PRINT(" 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 171QUARTZ_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 258QUARTZ_RENDERER_INLINE SDRenderType doRoundRect(QuartzSDOps *qsdo, CGFloat x, CGFloat y, CGFloat w, CGFloat h, CGFloat arcWidth, CGFloat arcHeight, BOOL fill) 259{ 260PRINT(" 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 270QUARTZ_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} 301QUARTZ_RENDERER_INLINE SDRenderType doOval(QuartzSDOps *qsdo, CGFloat x, CGFloat y, CGFloat w, CGFloat h, BOOL fill) 302{ 303PRINT(" 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 313QUARTZ_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} 322QUARTZ_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} 425QUARTZ_RENDERER_INLINE SDRenderType doArc(QuartzSDOps *qsdo, CGFloat x, CGFloat y, CGFloat w, CGFloat h, CGFloat angleStart, CGFloat angleExtent, jint arcType, BOOL fill) 426{ 427PRINT(" 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 436QUARTZ_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} 487QUARTZ_RENDERER_INLINE SDRenderType doPoly(JNIEnv *env, QuartzSDOps *qsdo, jintArray xpointsarray, jintArray ypointsarray, jint npoints, BOOL polygon, BOOL fill) 488{ 489PRINT(" 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 498SDRenderType doShape(QuartzSDOps *qsdo, jint *types, jfloat *coords, jint numtypes, BOOL fill, BOOL shouldApplyOffset) 499{ 500PRINT(" 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 517QUARTZ_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 564QUARTZ_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 576QUARTZ_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: 597fprintf(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 */ 607JNIEXPORT void JNICALL Java_sun_java2d_CRenderer_init 608(JNIEnv *env, jobject jthis) 609{ 610PRINT("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 */ 633JNIEXPORT void JNICALL Java_sun_java2d_CRenderer_doLine 634(JNIEnv *env, jobject jthis, jobject jsurfacedata, jfloat x1, jfloat y1, jfloat x2, jfloat y2) 635{ 636PRINT("Java_sun_java2d_CRenderer_doLine") 637 QuartzSDOps *qsdo = (QuartzSDOps*)SurfaceData_GetOps(env, jsurfacedata); 638JNI_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); 646JNI_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 */ 654JNIEXPORT 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{ 657PRINT("Java_sun_java2d_CRenderer_doRect") 658 QuartzSDOps *qsdo = (QuartzSDOps*)SurfaceData_GetOps(env, jsurfacedata); 659JNI_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); 667JNI_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 */ 675JNIEXPORT 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{ 678PRINT("Java_sun_java2d_CRenderer_doRoundRect") 679 QuartzSDOps *qsdo = (QuartzSDOps*)SurfaceData_GetOps(env, jsurfacedata); 680JNI_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); 688JNI_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 */ 696JNIEXPORT 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{ 699PRINT("Java_sun_java2d_CRenderer_doOval") 700 QuartzSDOps *qsdo = (QuartzSDOps*)SurfaceData_GetOps(env, jsurfacedata); 701JNI_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); 709JNI_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 */ 717JNIEXPORT 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{ 720PRINT("Java_sun_java2d_CRenderer_doArc") 721 QuartzSDOps *qsdo = (QuartzSDOps*)SurfaceData_GetOps(env, jsurfacedata); 722JNI_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); 730JNI_COCOA_RENDERER_EXIT(env); 731} 732 733/* 734 * Class: sun_java2d_CRenderer 735 * Method: doPoly 736 * Signature: 737 */ 738JNIEXPORT 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{ 741PRINT("Java_sun_java2d_CRenderer_doPoly") 742 QuartzSDOps *qsdo = (QuartzSDOps*)SurfaceData_GetOps(env, jsurfacedata); 743JNI_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); 752JNI_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 */ 760JNIEXPORT 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{ 763PRINT("Java_sun_java2d_CRenderer_doShape") 764 QuartzSDOps *qsdo = (QuartzSDOps*)SurfaceData_GetOps(env, jsurfacedata); 765JNI_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); 776JNI_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 */ 787JNIEXPORT 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{ 790PRINT("Java_sun_java2d_CRenderer_doImage") 791 QuartzSDOps *qsdo = (QuartzSDOps*)SurfaceData_GetOps(env, jsurfacedata); 792JNI_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); 799JNI_COCOA_RENDERER_EXIT(env); 800} 801