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
54typedef 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
108static void
109awt_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 */
145static XPoint *
146transformPoints(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 */
222JNIEXPORT 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 */
246JNIEXPORT 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 */
283JNIEXPORT 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 */
375JNIEXPORT 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 */
412JNIEXPORT 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 */
436JNIEXPORT 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
494static 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
505static 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
513static 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
552static 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 */
566JNIEXPORT void JNICALL
567Java_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 */
663JNIEXPORT 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 */
687JNIEXPORT 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 */
777JNIEXPORT 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 */
838JNIEXPORT 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 */
862JNIEXPORT 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 */
911JNIEXPORT 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 */
957JNIEXPORT void JNICALL
958Java_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