1 /* 2 * Copyright (c) 2000, 2016, 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 #include "sun_java2d_x11_X11Renderer.h" 27 28 #include "X11SurfaceData.h" 29 #include "SpanIterator.h" 30 #include "Trace.h" 31 #include "ProcessPath.h" 32 #include "GraphicsPrimitiveMgr.h" 33 34 35 #include <jlong.h> 36 37 #ifndef HEADLESS 38 #define POLYTEMPSIZE (int)(256 / sizeof(XPoint)) 39 #define ABS(n) (((n) < 0) ? -(n) : (n)) 40 41 #define MAX_SHORT 32767 42 #define MIN_SHORT (-32768) 43 44 #define CLAMP_TO_SHORT(x) (((x) > MAX_SHORT) \ 45 ? MAX_SHORT \ 46 : ((x) < MIN_SHORT) \ 47 ? MIN_SHORT \ 48 : (x)) 49 50 #define CLAMP_TO_USHORT(x) (((x) > 65535) ? 65535 : ((x) < 0) ? 0 : (x)) 51 52 #define DF_MAX_XPNTS 256 53 54 typedef struct { 55 Drawable drawable; 56 GC gc; 57 XPoint *pPoints; 58 XPoint dfPoints[DF_MAX_XPNTS]; 59 jint npoints; 60 jint maxpoints; 61 } XDrawHandlerData; 62 63 #define XDHD_INIT(PTR, _GC, DRAWABLE) \ 64 do { \ 65 (PTR)->pPoints = (PTR)->dfPoints; \ 66 (PTR)->npoints = 0; \ 67 (PTR)->maxpoints = DF_MAX_XPNTS; \ 68 (PTR)->gc = (_GC); \ 69 (PTR)->drawable = (DRAWABLE); \ 70 } while(0) 71 72 #define XDHD_RESET(PTR) \ 73 do { \ 74 (PTR)->npoints = 0; \ 75 } while(0) 76 77 78 #define XDHD_ADD_POINT(PTR, X, Y) \ 79 do { \ 80 XPoint* _pnts = (PTR)->pPoints; \ 81 jint _npnts = (PTR)->npoints; \ 82 if (_npnts >= (PTR)->maxpoints) { \ 83 jint newMax = (PTR)->maxpoints*2; \ 84 if ((PTR)->pPoints == (PTR)->dfPoints) { \ 85 (PTR)->pPoints = (XPoint*)malloc(newMax*sizeof(XPoint)); \ 86 memcpy((PTR)->pPoints, _pnts, _npnts*sizeof(XPoint)); \ 87 } else { \ 88 (PTR)->pPoints = (XPoint*)realloc( \ 89 _pnts, newMax*sizeof(XPoint)); \ 90 } \ 91 _pnts = (PTR)->pPoints; \ 92 (PTR)->maxpoints = newMax; \ 93 } \ 94 _pnts += _npnts; \ 95 _pnts->x = X; \ 96 _pnts->y = Y; \ 97 (PTR)->npoints = _npnts + 1; \ 98 } while(0) 99 100 #define XDHD_FREE_POINTS(PTR) \ 101 do { \ 102 if ((PTR)->pPoints != (PTR)->dfPoints) { \ 103 free((PTR)->pPoints); \ 104 } \ 105 } while(0) 106 107 108 static void 109 awt_drawArc(JNIEnv * env, jint drawable, GC xgc, 110 int x, int y, int w, int h, 111 int startAngle, int endAngle, 112 int filled) 113 { 114 int s, e; 115 116 if (w < 0 || h < 0) { 117 return; 118 } 119 if (endAngle >= 360 || endAngle <= -360) { 120 s = 0; 121 e = 360 * 64; 122 } else { 123 s = (startAngle % 360) * 64; 124 e = endAngle * 64; 125 } 126 if (filled == 0) { 127 XDrawArc(awt_display, drawable, xgc, x, y, w, h, s, e); 128 } else { 129 XFillArc(awt_display, drawable, xgc, x, y, w, h, s, e); 130 } 131 } 132 133 /* 134 * Copy vertices from xcoordsArray and ycoordsArray to a buffer 135 * of XPoint structures, translating by transx and transy and 136 * collapsing empty segments out of the list as we go. 137 * The number of points to be converted should be guaranteed 138 * to be more than 2 by the caller and is stored at *pNpoints. 139 * The resulting number of uncollapsed unique translated vertices 140 * will be stored back into the location *pNpoints. 141 * The points pointer is guaranteed to be pointing to an area of 142 * memory large enough for POLYTEMPSIZE points and a larger 143 * area of memory is allocated (and returned) if that is not enough. 144 */ 145 static XPoint * 146 transformPoints(JNIEnv * env, 147 jintArray xcoordsArray, jintArray ycoordsArray, 148 jint transx, jint transy, 149 XPoint * points, int *pNpoints, int close) 150 { 151 int npoints = *pNpoints; 152 jint *xcoords, *ycoords; 153 154 xcoords = (jint *) 155 (*env)->GetPrimitiveArrayCritical(env, xcoordsArray, NULL); 156 if (xcoords == NULL) { 157 return 0; 158 } 159 160 ycoords = (jint *) 161 (*env)->GetPrimitiveArrayCritical(env, ycoordsArray, NULL); 162 if (ycoords == NULL) { 163 (*env)->ReleasePrimitiveArrayCritical(env, xcoordsArray, xcoords, 164 JNI_ABORT); 165 return 0; 166 } 167 168 if (close) { 169 close = (xcoords[npoints - 1] != xcoords[0] || 170 ycoords[npoints - 1] != ycoords[0]); 171 if (close) { 172 npoints++; 173 } 174 } 175 if (npoints > POLYTEMPSIZE) { 176 points = (XPoint *) malloc(sizeof(XPoint) * npoints); 177 } 178 if (points != NULL) { 179 int in, out; 180 int oldx = CLAMP_TO_SHORT(xcoords[0] + transx); 181 int oldy = CLAMP_TO_SHORT(ycoords[0] + transy); 182 points[0].x = oldx; 183 points[0].y = oldy; 184 if (close) { 185 npoints--; 186 } 187 for (in = 1, out = 1; in < npoints; in++) { 188 int newx = CLAMP_TO_SHORT(xcoords[in] + transx); 189 int newy = CLAMP_TO_SHORT(ycoords[in] + transy); 190 if (newx != oldx || newy != oldy) { 191 points[out].x = newx; 192 points[out].y = newy; 193 out++; 194 oldx = newx; 195 oldy = newy; 196 } 197 } 198 if (out == 1) { 199 points[1].x = oldx; 200 points[1].y = oldy; 201 out = 2; 202 } else if (close) { 203 points[out++] = points[0]; 204 } 205 *pNpoints = out; 206 } 207 208 (*env)->ReleasePrimitiveArrayCritical(env, xcoordsArray, xcoords, 209 JNI_ABORT); 210 (*env)->ReleasePrimitiveArrayCritical(env, ycoordsArray, ycoords, 211 JNI_ABORT); 212 213 return points; 214 } 215 #endif /* !HEADLESS */ 216 217 /* 218 * Class: sun_java2d_x11_X11Renderer 219 * Method: XDrawLine 220 * Signature: (IJIIII)V 221 */ 222 JNIEXPORT void JNICALL Java_sun_java2d_x11_X11Renderer_XDrawLine 223 (JNIEnv *env, jobject xr, 224 jlong pXSData, jlong xgc, 225 jint x1, jint y1, jint x2, jint y2) 226 { 227 #ifndef HEADLESS 228 X11SDOps *xsdo = (X11SDOps *) jlong_to_ptr(pXSData); 229 230 if (xsdo == NULL) { 231 return; 232 } 233 234 XDrawLine(awt_display, xsdo->drawable, (GC) jlong_to_ptr(xgc), 235 CLAMP_TO_SHORT(x1), CLAMP_TO_SHORT(y1), 236 CLAMP_TO_SHORT(x2), CLAMP_TO_SHORT(y2)); 237 X11SD_DirectRenderNotify(env, xsdo); 238 #endif /* !HEADLESS */ 239 } 240 241 /* 242 * Class: sun_java2d_x11_X11Renderer 243 * Method: XDrawRect 244 * Signature: (IJIIII)V 245 */ 246 JNIEXPORT void JNICALL Java_sun_java2d_x11_X11Renderer_XDrawRect 247 (JNIEnv *env, jobject xr, 248 jlong pXSData, jlong xgc, 249 jint x, jint y, jint w, jint h) 250 { 251 #ifndef HEADLESS 252 X11SDOps *xsdo = (X11SDOps *) jlong_to_ptr(pXSData); 253 254 if (xsdo == NULL || w < 0 || h < 0) { 255 return; 256 } 257 258 if (w < 2 || h < 2) { 259 /* REMIND: This optimization assumes thin lines. */ 260 /* 261 * This optimization not only simplifies the processing 262 * of a particular degenerate case, but it protects against 263 * the anomalies of various X11 implementations that draw 264 * nothing for degenerate Polygons and Rectangles. 265 */ 266 XFillRectangle(awt_display, xsdo->drawable, (GC) jlong_to_ptr(xgc), 267 CLAMP_TO_SHORT(x), CLAMP_TO_SHORT(y), 268 CLAMP_TO_USHORT(w+1), CLAMP_TO_USHORT(h+1)); 269 } else { 270 XDrawRectangle(awt_display, xsdo->drawable, (GC) jlong_to_ptr(xgc), 271 CLAMP_TO_SHORT(x), CLAMP_TO_SHORT(y), 272 CLAMP_TO_USHORT(w), CLAMP_TO_USHORT(h)); 273 } 274 X11SD_DirectRenderNotify(env, xsdo); 275 #endif /* !HEADLESS */ 276 } 277 278 /* 279 * Class: sun_java2d_x11_X11Renderer 280 * Method: XDrawRoundRect 281 * Signature: (IJIIIIII)V 282 */ 283 JNIEXPORT void JNICALL Java_sun_java2d_x11_X11Renderer_XDrawRoundRect 284 (JNIEnv *env, jobject xr, 285 jlong pXSData, jlong xgc, 286 jint x, jint y, jint w, jint h, 287 jint arcW, jint arcH) 288 { 289 #ifndef HEADLESS 290 long ty1, ty2, tx1, tx2, cx, cy, cxw, cyh, 291 halfW, halfH, leftW, rightW, topH, bottomH; 292 X11SDOps *xsdo = (X11SDOps *) jlong_to_ptr(pXSData); 293 294 if (xsdo == NULL || w < 0 || h < 0) { 295 return; 296 } 297 298 arcW = ABS(arcW); 299 arcH = ABS(arcH); 300 if (arcW > w) { 301 arcW = w; 302 } 303 if (arcH > h) { 304 arcH = h; 305 } 306 307 if (arcW == 0 || arcH == 0) { 308 Java_sun_java2d_x11_X11Renderer_XDrawRect(env, xr, pXSData, xgc, 309 x, y, w, h); 310 return; 311 } 312 313 halfW = (arcW / 2); 314 halfH = (arcH / 2); 315 316 /* clamp to short bounding box of round rectangle */ 317 cx = CLAMP_TO_SHORT(x); 318 cy = CLAMP_TO_SHORT(y); 319 cxw = CLAMP_TO_SHORT(x + w); 320 cyh = CLAMP_TO_SHORT(y + h); 321 322 /* clamp to short coordinates of lines */ 323 tx1 = CLAMP_TO_SHORT(x + halfW + 1); 324 tx2 = CLAMP_TO_SHORT(x + w - halfW - 1); 325 ty1 = CLAMP_TO_SHORT(y + halfH + 1); 326 ty2 = CLAMP_TO_SHORT(y + h - halfH - 1); 327 328 /* 329 * recalculate heightes and widthes of round parts 330 * to minimize distortions in visible area 331 */ 332 leftW = (tx1 - cx) * 2; 333 rightW = (cxw - tx2) * 2; 334 topH = (ty1 - cy) * 2; 335 bottomH = (cyh - ty2) * 2; 336 337 awt_drawArc(env, xsdo->drawable, (GC) jlong_to_ptr(xgc), 338 cx, cy, leftW, topH, 339 90, 90, JNI_FALSE); 340 awt_drawArc(env, xsdo->drawable, (GC) jlong_to_ptr(xgc), 341 cxw - rightW, cy, rightW, topH, 342 0, 90, JNI_FALSE); 343 awt_drawArc(env, xsdo->drawable, (GC) jlong_to_ptr(xgc), 344 cx, cyh - bottomH, leftW, bottomH, 345 180, 90, JNI_FALSE); 346 awt_drawArc(env, xsdo->drawable, (GC) jlong_to_ptr(xgc), 347 cxw - rightW, cyh - bottomH, rightW, bottomH, 348 270, 90, JNI_FALSE); 349 350 if (tx1 <= tx2) { 351 XDrawLine(awt_display, xsdo->drawable, (GC) jlong_to_ptr(xgc), 352 tx1, cy, tx2, cy); 353 if (h > 0) { 354 XDrawLine(awt_display, xsdo->drawable, (GC) jlong_to_ptr(xgc), 355 tx1, cyh, tx2, cyh); 356 } 357 } 358 if (ty1 <= ty2) { 359 XDrawLine(awt_display, xsdo->drawable, (GC) jlong_to_ptr(xgc), 360 cx, ty1, cx, ty2); 361 if (w > 0) { 362 XDrawLine(awt_display, xsdo->drawable, (GC) jlong_to_ptr(xgc), 363 cxw, ty1, cxw, ty2); 364 } 365 } 366 X11SD_DirectRenderNotify(env, xsdo); 367 #endif /* !HEADLESS */ 368 } 369 370 /* 371 * Class: sun_java2d_x11_X11Renderer 372 * Method: XDrawOval 373 * Signature: (IJIIII)V 374 */ 375 JNIEXPORT void JNICALL Java_sun_java2d_x11_X11Renderer_XDrawOval 376 (JNIEnv *env, jobject xr, 377 jlong pXSData, jlong xgc, 378 jint x, jint y, jint w, jint h) 379 { 380 #ifndef HEADLESS 381 X11SDOps *xsdo = (X11SDOps *) jlong_to_ptr(pXSData); 382 383 if (xsdo == NULL) { 384 return; 385 } 386 387 if (w < 2 || h < 2) { 388 /* 389 * Fix for 4205762 - 1x1 ovals do not draw on Ultra1, Creator3d 390 * (related to 4411814 on Windows platform) 391 * Really small ovals degenerate to simple rectangles as they 392 * have no curvature or enclosed area. Use XFillRectangle 393 * for speed and to deal better with degenerate sizes. 394 */ 395 if (w >= 0 && h >= 0) { 396 XFillRectangle(awt_display, xsdo->drawable, (GC) jlong_to_ptr(xgc), 397 x, y, w+1, h+1); 398 } 399 } else { 400 awt_drawArc(env, xsdo->drawable, (GC) jlong_to_ptr(xgc), 401 x, y, w, h, 0, 360, JNI_FALSE); 402 } 403 X11SD_DirectRenderNotify(env, xsdo); 404 #endif /* !HEADLESS */ 405 } 406 407 /* 408 * Class: sun_java2d_x11_X11Renderer 409 * Method: XDrawArc 410 * Signature: (IJIIIIII)V 411 */ 412 JNIEXPORT void JNICALL Java_sun_java2d_x11_X11Renderer_XDrawArc 413 (JNIEnv *env, jobject xr, 414 jlong pXSData, jlong xgc, 415 jint x, jint y, jint w, jint h, 416 jint angleStart, jint angleExtent) 417 { 418 #ifndef HEADLESS 419 X11SDOps *xsdo = (X11SDOps *) jlong_to_ptr(pXSData); 420 421 if (xsdo == NULL) { 422 return; 423 } 424 425 awt_drawArc(env, xsdo->drawable, (GC) jlong_to_ptr(xgc), 426 x, y, w, h, angleStart, angleExtent, JNI_FALSE); 427 X11SD_DirectRenderNotify(env, xsdo); 428 #endif /* !HEADLESS */ 429 } 430 431 /* 432 * Class: sun_java2d_x11_X11Renderer 433 * Method: XDrawPoly 434 * Signature: (IJII[I[IIZ)V 435 */ 436 JNIEXPORT void JNICALL Java_sun_java2d_x11_X11Renderer_XDrawPoly 437 (JNIEnv *env, jobject xr, 438 jlong pXSData, jlong xgc, 439 jint transx, jint transy, 440 jintArray xcoordsArray, jintArray ycoordsArray, jint npoints, 441 jboolean isclosed) 442 { 443 #ifndef HEADLESS 444 XPoint pTmp[POLYTEMPSIZE], *points; 445 X11SDOps *xsdo = (X11SDOps *) jlong_to_ptr(pXSData); 446 447 if (xsdo == NULL) { 448 return; 449 } 450 451 if (JNU_IsNull(env, xcoordsArray) || JNU_IsNull(env, ycoordsArray)) { 452 JNU_ThrowNullPointerException(env, "coordinate array"); 453 return; 454 } 455 if ((*env)->GetArrayLength(env, ycoordsArray) < npoints || 456 (*env)->GetArrayLength(env, xcoordsArray) < npoints) 457 { 458 JNU_ThrowArrayIndexOutOfBoundsException(env, "coordinate array"); 459 return; 460 } 461 462 if (npoints < 2) { 463 return; 464 } 465 466 points = transformPoints(env, xcoordsArray, ycoordsArray, transx, transy, 467 pTmp, (int *)&npoints, isclosed); 468 if (points != 0) { 469 if (npoints == 2) { 470 /* 471 * Some X11 implementations fail to draw anything for 472 * simple 2 point polygons where the vertices are the 473 * same point even though this violates the X11 474 * specification. For simplicity we will dispatch all 475 * 2 point polygons through XDrawLine even if they are 476 * non-degenerate as this may invoke less processing 477 * down the line than a Poly primitive anyway. 478 */ 479 XDrawLine(awt_display, xsdo->drawable, (GC) jlong_to_ptr(xgc), 480 points[0].x, points[0].y, 481 points[1].x, points[1].y); 482 } else { 483 XDrawLines(awt_display, xsdo->drawable, (GC) jlong_to_ptr(xgc), 484 points, npoints, CoordModeOrigin); 485 } 486 if (points != pTmp) { 487 free(points); 488 } 489 X11SD_DirectRenderNotify(env, xsdo); 490 } 491 #endif /* !HEADLESS */ 492 } 493 494 static void storeLine(DrawHandler* hnd, 495 jint x0, jint y0, jint x1, jint y1) 496 { 497 #ifndef HEADLESS 498 XDrawHandlerData* dhnd = (XDrawHandlerData*)(hnd->pData); 499 500 XDHD_ADD_POINT(dhnd, x0, y0); 501 XDHD_ADD_POINT(dhnd, x1, y1); 502 #endif /* !HEADLESS */ 503 } 504 505 static void storePoint(DrawHandler* hnd, jint x0, jint y0) { 506 #ifndef HEADLESS 507 XDrawHandlerData* dhnd = (XDrawHandlerData*)(hnd->pData); 508 509 XDHD_ADD_POINT(dhnd, x0, y0); 510 #endif /* !HEADLESS */ 511 } 512 513 static void drawSubPath(ProcessHandler* hnd) { 514 #ifndef HEADLESS 515 XDrawHandlerData* dhnd = (XDrawHandlerData*)(hnd->dhnd->pData); 516 XPoint *points = dhnd->pPoints; 517 518 switch (dhnd->npoints) { 519 case 0: 520 /* No-op */ 521 break; 522 case 1: 523 /* Draw the single pixel */ 524 XFillRectangle(awt_display, dhnd->drawable, dhnd->gc, 525 points[0].x, points[0].y, 1, 1); 526 break; 527 case 2: 528 /* 529 * The XDrawLines method for some X11 implementations 530 * fails to draw anything for simple 2 point polygons 531 * where the vertices are the same point even though 532 * this violates the X11 specification. For simplicity 533 * we will dispatch all 2 point polygons through XDrawLine 534 * even if they are non-degenerate as this may invoke 535 * less processing down the line than a poly primitive anyway. 536 */ 537 XDrawLine(awt_display, dhnd->drawable, dhnd->gc, 538 points[0].x, points[0].y, 539 points[1].x, points[1].y); 540 break; 541 default: 542 /* Draw the entire polyline */ 543 XDrawLines(awt_display, dhnd->drawable, dhnd->gc, points, 544 dhnd->npoints, CoordModeOrigin); 545 break; 546 } 547 548 XDHD_RESET(dhnd); 549 #endif /* !HEADLESS */ 550 } 551 552 static void drawScanline(DrawHandler* hnd, jint x0, jint x1, jint y0) 553 { 554 #ifndef HEADLESS 555 XDrawHandlerData* dhnd = (XDrawHandlerData*)(hnd->pData); 556 557 XDrawLine(awt_display, dhnd->drawable, dhnd->gc, x0, y0, x1, y0); 558 #endif /* !HEADLESS */ 559 } 560 561 /* 562 * Class: sun_java2d_x11_X11Renderer 563 * Method: XDoPath 564 * Signature: (Lsun/java2d/SunGraphics2D;JJIILjava/awt/geom/Path2D/Float;Z)V 565 */ 566 JNIEXPORT void JNICALL 567 Java_sun_java2d_x11_X11Renderer_XDoPath 568 (JNIEnv *env, jobject self, jobject sg2d, jlong pXSData, jlong xgc, 569 jint transX, jint transY, jobject p2df, jboolean isFill) 570 { 571 #ifndef HEADLESS 572 X11SDOps *xsdo = (X11SDOps *) jlong_to_ptr(pXSData); 573 jarray typesArray; 574 jobject pointArray; 575 jarray coordsArray; 576 jint numTypes; 577 jint fillRule; 578 jint maxCoords; 579 jbyte *types; 580 jfloat *coords; 581 XDrawHandlerData dHData; 582 DrawHandler drawHandler = { 583 NULL, NULL, NULL, 584 MIN_SHORT, MIN_SHORT, MAX_SHORT, MAX_SHORT, 585 0, 0, 0, 0, 586 NULL 587 }; 588 PHStroke stroke; 589 jboolean ok = JNI_TRUE; 590 591 if (xsdo == NULL) { 592 return; 593 } 594 595 if (isFill) { 596 fillRule = (*env)->GetIntField(env, p2df, path2DWindingRuleID); 597 } 598 599 typesArray = (jarray)(*env)->GetObjectField(env, p2df, path2DTypesID); 600 coordsArray = (jarray)(*env)->GetObjectField(env, p2df, 601 path2DFloatCoordsID); 602 if (coordsArray == NULL) { 603 JNU_ThrowNullPointerException(env, "coordinates array"); 604 return; 605 } 606 numTypes = (*env)->GetIntField(env, p2df, path2DNumTypesID); 607 if ((*env)->GetArrayLength(env, typesArray) < numTypes) { 608 JNU_ThrowArrayIndexOutOfBoundsException(env, "types array"); 609 return; 610 } 611 612 XDHD_INIT(&dHData, (GC) jlong_to_ptr(xgc), xsdo->drawable); 613 drawHandler.pData = &dHData; 614 615 stroke = (((*env)->GetIntField(env, sg2d, sg2dStrokeHintID) == 616 sunHints_INTVAL_STROKE_PURE) 617 ? PH_STROKE_PURE 618 : PH_STROKE_DEFAULT); 619 620 maxCoords = (*env)->GetArrayLength(env, coordsArray); 621 coords = (jfloat*) 622 (*env)->GetPrimitiveArrayCritical(env, coordsArray, NULL); 623 if (coords != NULL) { 624 types = (jbyte*) 625 (*env)->GetPrimitiveArrayCritical(env, typesArray, NULL); 626 if (types != NULL) { 627 if (isFill) { 628 drawHandler.pDrawScanline = &drawScanline; 629 ok = doFillPath(&drawHandler, 630 transX, transY, 631 coords, maxCoords, 632 types, numTypes, 633 stroke, fillRule); 634 } else { 635 drawHandler.pDrawLine = &storeLine; 636 drawHandler.pDrawPixel = &storePoint; 637 ok = doDrawPath(&drawHandler, &drawSubPath, 638 transX, transY, 639 coords, maxCoords, 640 types, numTypes, 641 stroke); 642 } 643 (*env)->ReleasePrimitiveArrayCritical(env, typesArray, types, 644 JNI_ABORT); 645 } 646 (*env)->ReleasePrimitiveArrayCritical(env, coordsArray, coords, 647 JNI_ABORT); 648 if (!ok) { 649 JNU_ThrowArrayIndexOutOfBoundsException(env, "coords array"); 650 } 651 } 652 653 XDHD_FREE_POINTS(&dHData); 654 X11SD_DirectRenderNotify(env, xsdo); 655 #endif /* !HEADLESS */ 656 } 657 658 /* 659 * Class: sun_java2d_x11_X11Renderer 660 * Method: XFillRect 661 * Signature: (IJIIII)V 662 */ 663 JNIEXPORT void JNICALL Java_sun_java2d_x11_X11Renderer_XFillRect 664 (JNIEnv *env, jobject xr, 665 jlong pXSData, jlong xgc, 666 jint x, jint y, jint w, jint h) 667 { 668 #ifndef HEADLESS 669 X11SDOps *xsdo = (X11SDOps *) jlong_to_ptr(pXSData); 670 671 if (xsdo == NULL) { 672 return; 673 } 674 675 XFillRectangle(awt_display, xsdo->drawable, (GC) jlong_to_ptr(xgc), 676 CLAMP_TO_SHORT(x), CLAMP_TO_SHORT(y), 677 CLAMP_TO_USHORT(w), CLAMP_TO_USHORT(h)); 678 X11SD_DirectRenderNotify(env, xsdo); 679 #endif /* !HEADLESS */ 680 } 681 682 /* 683 * Class: sun_java2d_x11_X11Renderer 684 * Method: XFillRoundRect 685 * Signature: (IJIIIIII)V 686 */ 687 JNIEXPORT void JNICALL Java_sun_java2d_x11_X11Renderer_XFillRoundRect 688 (JNIEnv *env, jobject xr, 689 jlong pXSData, jlong xgc, 690 jint x, jint y, jint w, jint h, 691 jint arcW, jint arcH) 692 { 693 #ifndef HEADLESS 694 long ty1, ty2, tx1, tx2, cx, cy, cxw, cyh, 695 halfW, halfH, leftW, rightW, topH, bottomH; 696 X11SDOps *xsdo = (X11SDOps *) jlong_to_ptr(pXSData); 697 698 if (xsdo == NULL || w <= 0 || h <= 0) { 699 return; 700 } 701 702 arcW = ABS(arcW); 703 arcH = ABS(arcH); 704 if (arcW > w) { 705 arcW = w; 706 } 707 if (arcH > h) { 708 arcH = h; 709 } 710 711 if (arcW == 0 || arcH == 0) { 712 Java_sun_java2d_x11_X11Renderer_XFillRect(env, xr, pXSData, xgc, 713 x, y, w, h); 714 return; 715 } 716 717 halfW = (arcW / 2); 718 halfH = (arcH / 2); 719 720 /* clamp to short bounding box of round rectangle */ 721 cx = CLAMP_TO_SHORT(x); 722 cy = CLAMP_TO_SHORT(y); 723 cxw = CLAMP_TO_SHORT(x + w); 724 cyh = CLAMP_TO_SHORT(y + h); 725 726 /* clamp to short coordinates of lines */ 727 tx1 = CLAMP_TO_SHORT(x + halfW + 1); 728 tx2 = CLAMP_TO_SHORT(x + w - halfW - 1); 729 ty1 = CLAMP_TO_SHORT(y + halfH + 1); 730 ty2 = CLAMP_TO_SHORT(y + h - halfH - 1); 731 732 /* 733 * recalculate heightes and widthes of round parts 734 * to minimize distortions in visible area 735 */ 736 leftW = (tx1 - cx) * 2; 737 rightW = (cxw - tx2) * 2; 738 topH = (ty1 - cy) * 2; 739 bottomH = (cyh - ty2) * 2; 740 741 awt_drawArc(env, xsdo->drawable, (GC) jlong_to_ptr(xgc), 742 cx, cy, leftW, topH, 743 90, 90, JNI_TRUE); 744 awt_drawArc(env, xsdo->drawable, (GC) jlong_to_ptr(xgc), 745 cxw - rightW, cy, rightW, topH, 746 0, 90, JNI_TRUE); 747 awt_drawArc(env, xsdo->drawable, (GC) jlong_to_ptr(xgc), 748 cx, cyh - bottomH, leftW, bottomH, 749 180, 90, JNI_TRUE); 750 awt_drawArc(env, xsdo->drawable, (GC) jlong_to_ptr(xgc), 751 cxw - rightW, cyh - bottomH, rightW, bottomH, 752 270, 90, JNI_TRUE); 753 754 if (tx1 < tx2) { 755 if (cy < ty1) { 756 XFillRectangle(awt_display, xsdo->drawable, (GC) jlong_to_ptr(xgc), 757 tx1, cy, tx2 - tx1, ty1 - cy); 758 } 759 if (ty2 < cyh) { 760 XFillRectangle(awt_display, xsdo->drawable, (GC) jlong_to_ptr(xgc), 761 tx1, ty2, tx2 - tx1, cyh - ty2); 762 } 763 } 764 if (ty1 < ty2) { 765 XFillRectangle(awt_display, xsdo->drawable, (GC) jlong_to_ptr(xgc), 766 cx, ty1, cxw - cx, ty2 - ty1); 767 } 768 X11SD_DirectRenderNotify(env, xsdo); 769 #endif /* !HEADLESS */ 770 } 771 772 /* 773 * Class: sun_java2d_x11_X11Renderer 774 * Method: XFillOval 775 * Signature: (IJIIII)V 776 */ 777 JNIEXPORT void JNICALL Java_sun_java2d_x11_X11Renderer_XFillOval 778 (JNIEnv *env, jobject xr, 779 jlong pXSData, jlong xgc, 780 jint x, jint y, jint w, jint h) 781 { 782 #ifndef HEADLESS 783 X11SDOps *xsdo = (X11SDOps *) jlong_to_ptr(pXSData); 784 785 if (xsdo == NULL) { 786 return; 787 } 788 789 if (w < 3 || h < 3) { 790 /* 791 * Fix for 4205762 - 1x1 ovals do not draw on Ultra1, Creator3d 792 * (related to 4411814 on Windows platform) 793 * Most X11 servers drivers have poor rendering 794 * for thin ellipses and the rendering is most strikingly 795 * different from our theoretical arcs. Ideally we should 796 * trap all ovals less than some fairly large size and 797 * try to draw aesthetically pleasing ellipses, but that 798 * would require considerably more work to get the corresponding 799 * drawArc variants to match pixel for pixel. 800 * Thin ovals of girth 1 pixel are simple rectangles. 801 * Thin ovals of girth 2 pixels are simple rectangles with 802 * potentially smaller lengths. Determine the correct length 803 * by calculating .5*.5 + scaledlen*scaledlen == 1.0 which 804 * means that scaledlen is the sqrt(0.75). Scaledlen is 805 * relative to the true length (w or h) and needs to be 806 * adjusted by half a pixel in different ways for odd or 807 * even lengths. 808 */ 809 #define SQRT_3_4 0.86602540378443864676 810 if (w > 2 && h > 1) { 811 int adjw = (int) ((SQRT_3_4 * w - ((w&1)-1)) * 0.5); 812 adjw = adjw * 2 + (w&1); 813 x += (w-adjw)/2; 814 w = adjw; 815 } else if (h > 2 && w > 1) { 816 int adjh = (int) ((SQRT_3_4 * h - ((h&1)-1)) * 0.5); 817 adjh = adjh * 2 + (h&1); 818 y += (h-adjh)/2; 819 h = adjh; 820 } 821 #undef SQRT_3_4 822 if (w > 0 && h > 0) { 823 XFillRectangle(awt_display, xsdo->drawable, (GC) jlong_to_ptr(xgc), x, y, w, h); 824 } 825 } else { 826 awt_drawArc(env, xsdo->drawable, (GC) jlong_to_ptr(xgc), 827 x, y, w, h, 0, 360, JNI_TRUE); 828 } 829 X11SD_DirectRenderNotify(env, xsdo); 830 #endif /* !HEADLESS */ 831 } 832 833 /* 834 * Class: sun_java2d_x11_X11Renderer 835 * Method: XFillArc 836 * Signature: (IJIIIIII)V 837 */ 838 JNIEXPORT void JNICALL Java_sun_java2d_x11_X11Renderer_XFillArc 839 (JNIEnv *env, jobject xr, 840 jlong pXSData, jlong xgc, 841 jint x, jint y, jint w, jint h, 842 jint angleStart, jint angleExtent) 843 { 844 #ifndef HEADLESS 845 X11SDOps *xsdo = (X11SDOps *) jlong_to_ptr(pXSData); 846 847 if (xsdo == NULL) { 848 return; 849 } 850 851 awt_drawArc(env, xsdo->drawable, (GC) jlong_to_ptr(xgc), 852 x, y, w, h, angleStart, angleExtent, JNI_TRUE); 853 X11SD_DirectRenderNotify(env, xsdo); 854 #endif /* !HEADLESS */ 855 } 856 857 /* 858 * Class: sun_java2d_x11_X11Renderer 859 * Method: XFillPoly 860 * Signature: (IJII[I[II)V 861 */ 862 JNIEXPORT void JNICALL Java_sun_java2d_x11_X11Renderer_XFillPoly 863 (JNIEnv *env, jobject xr, 864 jlong pXSData, jlong xgc, 865 jint transx, jint transy, 866 jintArray xcoordsArray, jintArray ycoordsArray, jint npoints) 867 { 868 #ifndef HEADLESS 869 XPoint pTmp[POLYTEMPSIZE], *points; 870 X11SDOps *xsdo = (X11SDOps *) jlong_to_ptr(pXSData); 871 872 if (xsdo == NULL) { 873 return; 874 } 875 876 if (JNU_IsNull(env, xcoordsArray) || JNU_IsNull(env, ycoordsArray)) { 877 JNU_ThrowNullPointerException(env, "coordinate array"); 878 return; 879 } 880 if ((*env)->GetArrayLength(env, ycoordsArray) < npoints || 881 (*env)->GetArrayLength(env, xcoordsArray) < npoints) 882 { 883 JNU_ThrowArrayIndexOutOfBoundsException(env, "coordinate array"); 884 return; 885 } 886 887 if (npoints < 3) { 888 return; 889 } 890 891 points = transformPoints(env, xcoordsArray, ycoordsArray, transx, transy, 892 pTmp, (int *)&npoints, JNI_FALSE); 893 if (points != 0) { 894 if (npoints > 2) { 895 XFillPolygon(awt_display, xsdo->drawable, (GC) jlong_to_ptr(xgc), 896 points, npoints, Complex, CoordModeOrigin); 897 X11SD_DirectRenderNotify(env, xsdo); 898 } 899 if (points != pTmp) { 900 free(points); 901 } 902 } 903 #endif /* !HEADLESS */ 904 } 905 906 /* 907 * Class: sun_java2d_x11_X11Renderer 908 * Method: XFillSpans 909 * Signature: (IJLsun/java2d/pipe/SpanIterator;JII)V 910 */ 911 JNIEXPORT void JNICALL Java_sun_java2d_x11_X11Renderer_XFillSpans 912 (JNIEnv *env, jobject xr, 913 jlong pXSData, jlong xgc, 914 jobject si, jlong pIterator, 915 jint transx, jint transy) 916 { 917 #ifndef HEADLESS 918 SpanIteratorFuncs *pFuncs = (SpanIteratorFuncs *) jlong_to_ptr(pIterator); 919 void *srData; 920 jint x, y, w, h; 921 jint spanbox[4]; 922 X11SDOps *xsdo = (X11SDOps *) jlong_to_ptr(pXSData); 923 924 if (xsdo == NULL) { 925 return; 926 } 927 928 if (JNU_IsNull(env, si)) { 929 JNU_ThrowNullPointerException(env, "span iterator"); 930 return; 931 } 932 if (pFuncs == NULL) { 933 JNU_ThrowNullPointerException(env, "native iterator not supplied"); 934 return; 935 } 936 937 srData = (*pFuncs->open)(env, si); 938 while ((*pFuncs->nextSpan)(srData, spanbox)) { 939 x = spanbox[0] + transx; 940 y = spanbox[1] + transy; 941 w = spanbox[2] - spanbox[0]; 942 h = spanbox[3] - spanbox[1]; 943 XFillRectangle(awt_display, xsdo->drawable, (GC) jlong_to_ptr(xgc), 944 CLAMP_TO_SHORT(x), CLAMP_TO_SHORT(y), 945 CLAMP_TO_USHORT(w), CLAMP_TO_USHORT(h)); 946 } 947 (*pFuncs->close)(env, srData); 948 X11SD_DirectRenderNotify(env, xsdo); 949 #endif /* !HEADLESS */ 950 } 951 952 /* 953 * Class: sun_java2d_x11_X11Renderer 954 * Method: devCopyArea 955 * Signature: (Lsun/java2d/SurfaceData;IIIIII)V 956 */ 957 JNIEXPORT void JNICALL 958 Java_sun_java2d_x11_X11Renderer_devCopyArea 959 (JNIEnv *env, jobject xr, 960 jlong xsd, jlong gc, 961 jint srcx, jint srcy, 962 jint dstx, jint dsty, 963 jint width, jint height) 964 { 965 #ifndef HEADLESS 966 X11SDOps *xsdo; 967 GC xgc; 968 969 xsdo = (X11SDOps *) jlong_to_ptr(xsd); 970 if (xsdo == NULL) { 971 return; 972 } 973 974 xgc = (GC) jlong_to_ptr(gc); 975 if (xgc == NULL) { 976 return; 977 } 978 979 XCopyArea(awt_display, xsdo->drawable, xsdo->drawable, xgc, 980 srcx, srcy, width, height, dstx, dsty); 981 982 X11SD_DirectRenderNotify(env, xsdo); 983 #endif /* !HEADLESS */ 984 }