1 /*
   2  * Copyright (c) 2000, 2013, 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 *) pXSData;
 229 
 230     if (xsdo == NULL) {
 231         return;
 232     }
 233 
 234     XDrawLine(awt_display, xsdo->drawable, (GC) 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 *) 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) 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) 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 *) 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) xgc,
 338                 cx, cy, leftW, topH,
 339                 90, 90, JNI_FALSE);
 340     awt_drawArc(env, xsdo->drawable, (GC) xgc,
 341                 cxw - rightW, cy, rightW, topH,
 342                 0, 90, JNI_FALSE);
 343     awt_drawArc(env, xsdo->drawable, (GC) xgc,
 344                 cx, cyh - bottomH, leftW, bottomH,
 345                 180, 90, JNI_FALSE);
 346     awt_drawArc(env, xsdo->drawable, (GC) 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) xgc,
 352                   tx1, cy, tx2, cy);
 353         if (h > 0) {
 354             XDrawLine(awt_display, xsdo->drawable, (GC) xgc,
 355                       tx1, cyh, tx2, cyh);
 356         }
 357     }
 358     if (ty1 <= ty2) {
 359         XDrawLine(awt_display, xsdo->drawable, (GC) xgc,
 360                   cx, ty1, cx, ty2);
 361         if (w > 0) {
 362             XDrawLine(awt_display, xsdo->drawable, (GC) 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 *) 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) xgc,
 397                            x, y, w+1, h+1);
 398         }
 399     } else {
 400         awt_drawArc(env, xsdo->drawable, (GC) 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 *) pXSData;
 420 
 421     if (xsdo == NULL) {
 422         return;
 423     }
 424 
 425     awt_drawArc(env, xsdo->drawable, (GC) 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 *) 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) xgc,
 480                       points[0].x, points[0].y,
 481                       points[1].x, points[1].y);
 482         } else {
 483             XDrawLines(awt_display, xsdo->drawable, (GC) 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 *) 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)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 *) pXSData;
 670 
 671     if (xsdo == NULL) {
 672         return;
 673     }
 674 
 675     XFillRectangle(awt_display, xsdo->drawable, (GC) 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 *) 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) xgc,
 742                 cx, cy, leftW, topH,
 743                 90, 90, JNI_TRUE);
 744     awt_drawArc(env, xsdo->drawable, (GC) xgc,
 745                 cxw - rightW, cy, rightW, topH,
 746                 0, 90, JNI_TRUE);
 747     awt_drawArc(env, xsdo->drawable, (GC) xgc,
 748                 cx, cyh - bottomH, leftW, bottomH,
 749                 180, 90, JNI_TRUE);
 750     awt_drawArc(env, xsdo->drawable, (GC) 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) xgc,
 757                            tx1, cy, tx2 - tx1, ty1 - cy);
 758         }
 759         if (ty2 < cyh) {
 760             XFillRectangle(awt_display, xsdo->drawable, (GC) xgc,
 761                            tx1, ty2, tx2 - tx1, cyh - ty2);
 762         }
 763     }
 764     if (ty1 < ty2) {
 765         XFillRectangle(awt_display, xsdo->drawable, (GC) 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 *) 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) xgc, x, y, w, h);
 824         }
 825     } else {
 826         awt_drawArc(env, xsdo->drawable, (GC) 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 *) pXSData;
 846 
 847     if (xsdo == NULL) {
 848         return;
 849     }
 850 
 851     awt_drawArc(env, xsdo->drawable, (GC) 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 *) 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) 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 *) 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) 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)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 }
--- EOF ---