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
awt_drawArc(JNIEnv * env,jint drawable,GC xgc,int x,int y,int w,int h,int startAngle,int endAngle,int filled)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 *
transformPoints(JNIEnv * env,jintArray xcoordsArray,jintArray ycoordsArray,jint transx,jint transy,XPoint * points,int * pNpoints,int close)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  */
Java_sun_java2d_x11_X11Renderer_XDrawLine(JNIEnv * env,jobject xr,jlong pXSData,jlong xgc,jint x1,jint y1,jint x2,jint y2)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  */
Java_sun_java2d_x11_X11Renderer_XDrawRect(JNIEnv * env,jobject xr,jlong pXSData,jlong xgc,jint x,jint y,jint w,jint h)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  */
Java_sun_java2d_x11_X11Renderer_XDrawRoundRect(JNIEnv * env,jobject xr,jlong pXSData,jlong xgc,jint x,jint y,jint w,jint h,jint arcW,jint arcH)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  */
Java_sun_java2d_x11_X11Renderer_XDrawOval(JNIEnv * env,jobject xr,jlong pXSData,jlong xgc,jint x,jint y,jint w,jint h)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  */
Java_sun_java2d_x11_X11Renderer_XDrawArc(JNIEnv * env,jobject xr,jlong pXSData,jlong xgc,jint x,jint y,jint w,jint h,jint angleStart,jint angleExtent)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  */
Java_sun_java2d_x11_X11Renderer_XDrawPoly(JNIEnv * env,jobject xr,jlong pXSData,jlong xgc,jint transx,jint transy,jintArray xcoordsArray,jintArray ycoordsArray,jint npoints,jboolean isclosed)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 
storeLine(DrawHandler * hnd,jint x0,jint y0,jint x1,jint y1)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 
storePoint(DrawHandler * hnd,jint x0,jint y0)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 
drawSubPath(ProcessHandler * hnd)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 
drawScanline(DrawHandler * hnd,jint x0,jint x1,jint y0)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
Java_sun_java2d_x11_X11Renderer_XDoPath(JNIEnv * env,jobject self,jobject sg2d,jlong pXSData,jlong xgc,jint transX,jint transY,jobject p2df,jboolean isFill)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  */
Java_sun_java2d_x11_X11Renderer_XFillRect(JNIEnv * env,jobject xr,jlong pXSData,jlong xgc,jint x,jint y,jint w,jint h)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  */
Java_sun_java2d_x11_X11Renderer_XFillRoundRect(JNIEnv * env,jobject xr,jlong pXSData,jlong xgc,jint x,jint y,jint w,jint h,jint arcW,jint arcH)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  */
Java_sun_java2d_x11_X11Renderer_XFillOval(JNIEnv * env,jobject xr,jlong pXSData,jlong xgc,jint x,jint y,jint w,jint h)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  */
Java_sun_java2d_x11_X11Renderer_XFillArc(JNIEnv * env,jobject xr,jlong pXSData,jlong xgc,jint x,jint y,jint w,jint h,jint angleStart,jint angleExtent)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  */
Java_sun_java2d_x11_X11Renderer_XFillPoly(JNIEnv * env,jobject xr,jlong pXSData,jlong xgc,jint transx,jint transy,jintArray xcoordsArray,jintArray ycoordsArray,jint npoints)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  */
Java_sun_java2d_x11_X11Renderer_XFillSpans(JNIEnv * env,jobject xr,jlong pXSData,jlong xgc,jobject si,jlong pIterator,jint transx,jint transy)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
Java_sun_java2d_x11_X11Renderer_devCopyArea(JNIEnv * env,jobject xr,jlong xsd,jlong gc,jint srcx,jint srcy,jint dstx,jint dsty,jint width,jint height)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 }
985