blob: a8661990b3b9e4bc891bb49702b64a44c8a47f9d [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2000-2006 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any 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 JNU_ThrowOutOfMemoryError(env, "translated coordinate array");
470 } else {
471 if (npoints == 2) {
472 /*
473 * Some X11 implementations fail to draw anything for
474 * simple 2 point polygons where the vertices are the
475 * same point even though this violates the X11
476 * specification. For simplicity we will dispatch all
477 * 2 point polygons through XDrawLine even if they are
478 * non-degenerate as this may invoke less processing
479 * down the line than a Poly primitive anyway.
480 */
481 XDrawLine(awt_display, xsdo->drawable, (GC) xgc,
482 points[0].x, points[0].y,
483 points[1].x, points[1].y);
484 } else {
485 XDrawLines(awt_display, xsdo->drawable, (GC) xgc,
486 points, npoints, CoordModeOrigin);
487 }
488 if (points != pTmp) {
489 free(points);
490 }
491 X11SD_DirectRenderNotify(env, xsdo);
492 }
493#endif /* !HEADLESS */
494}
495
496static void storeLine(DrawHandler* hnd,
497 jint x0, jint y0, jint x1, jint y1)
498{
499#ifndef HEADLESS
500 XDrawHandlerData* dhnd = (XDrawHandlerData*)(hnd->pData);
501
502 XDHD_ADD_POINT(dhnd, x0, y0);
503 XDHD_ADD_POINT(dhnd, x1, y1);
504#endif /* !HEADLESS */
505}
506
507static void storePoint(DrawHandler* hnd, jint x0, jint y0) {
508#ifndef HEADLESS
509 XDrawHandlerData* dhnd = (XDrawHandlerData*)(hnd->pData);
510
511 XDHD_ADD_POINT(dhnd, x0, y0);
512#endif /* !HEADLESS */
513}
514
515static void drawSubPath(ProcessHandler* hnd) {
516#ifndef HEADLESS
517 XDrawHandlerData* dhnd = (XDrawHandlerData*)(hnd->dhnd->pData);
518 XPoint *points = dhnd->pPoints;
519
520 switch (dhnd->npoints) {
521 case 0:
522 /* No-op */
523 break;
524 case 1:
525 /* Draw the single pixel */
526 XFillRectangle(awt_display, dhnd->drawable, dhnd->gc,
527 points[0].x, points[0].y, 1, 1);
528 break;
529 case 2:
530 /*
531 * The XDrawLines method for some X11 implementations
532 * fails to draw anything for simple 2 point polygons
533 * where the vertices are the same point even though
534 * this violates the X11 specification. For simplicity
535 * we will dispatch all 2 point polygons through XDrawLine
536 * even if they are non-degenerate as this may invoke
537 * less processing down the line than a poly primitive anyway.
538 */
539 XDrawLine(awt_display, dhnd->drawable, dhnd->gc,
540 points[0].x, points[0].y,
541 points[1].x, points[1].y);
542 break;
543 default:
544 /* Draw the entire polyline */
545 XDrawLines(awt_display, dhnd->drawable, dhnd->gc, points,
546 dhnd->npoints, CoordModeOrigin);
547 break;
548 }
549
550 XDHD_RESET(dhnd);
551#endif /* !HEADLESS */
552}
553
554static void drawScanline(DrawHandler* hnd, jint x0, jint x1, jint y0)
555{
556#ifndef HEADLESS
557 XDrawHandlerData* dhnd = (XDrawHandlerData*)(hnd->pData);
558
559 XDrawLine(awt_display, dhnd->drawable, dhnd->gc, x0, y0, x1, y0);
560#endif /* !HEADLESS */
561}
562
563/*
564 * Class: sun_java2d_x11_X11Renderer
565 * Method: XDoPath
566 * Signature: (Lsun/java2d/SunGraphics2D;JJIILjava/awt/geom/Path2D/Float;Z)V
567 */
568JNIEXPORT void JNICALL
569Java_sun_java2d_x11_X11Renderer_XDoPath
570 (JNIEnv *env, jobject self, jobject sg2d, jlong pXSData, jlong xgc,
571 jint transX, jint transY, jobject p2df, jboolean isFill)
572{
573#ifndef HEADLESS
574 X11SDOps *xsdo = (X11SDOps *) pXSData;
575 jarray typesArray;
576 jobject pointArray;
577 jarray coordsArray;
578 jint numTypes;
579 jint fillRule;
580 jint maxCoords;
581 jbyte *types;
582 jfloat *coords;
583 XDrawHandlerData dHData;
584 DrawHandler drawHandler = {
585 NULL, NULL, NULL,
586 MIN_SHORT, MIN_SHORT, MAX_SHORT, MAX_SHORT,
587 0, 0, 0, 0,
588 NULL
589 };
590 PHStroke stroke;
591
592 if (xsdo == NULL) {
593 return;
594 }
595
596 if (isFill) {
597 fillRule = (*env)->GetIntField(env, p2df, path2DWindingRuleID);
598 }
599
600 typesArray = (jarray)(*env)->GetObjectField(env, p2df, path2DTypesID);
601 coordsArray = (jarray)(*env)->GetObjectField(env, p2df,
602 path2DFloatCoordsID);
603 if (coordsArray == NULL) {
604 JNU_ThrowNullPointerException(env, "coordinates array");
605 return;
606 }
607 numTypes = (*env)->GetIntField(env, p2df, path2DNumTypesID);
608 if ((*env)->GetArrayLength(env, typesArray) < numTypes) {
609 JNU_ThrowArrayIndexOutOfBoundsException(env, "types array");
610 return;
611 }
612
613 XDHD_INIT(&dHData, (GC)xgc, xsdo->drawable);
614 drawHandler.pData = &dHData;
615
616 stroke = (((*env)->GetIntField(env, sg2d, sg2dStrokeHintID) ==
617 sunHints_INTVAL_STROKE_PURE)
618 ? PH_STROKE_PURE
619 : PH_STROKE_DEFAULT);
620
621 maxCoords = (*env)->GetArrayLength(env, coordsArray);
622 coords = (jfloat*)
623 (*env)->GetPrimitiveArrayCritical(env, coordsArray, NULL);
624 if (coords != NULL) {
625 types = (jbyte*)
626 (*env)->GetPrimitiveArrayCritical(env, typesArray, NULL);
627 if (types != NULL) {
628 jboolean ok;
629
630 if (isFill) {
631 drawHandler.pDrawScanline = &drawScanline;
632 ok = doFillPath(&drawHandler,
633 transX, transY,
634 coords, maxCoords,
635 types, numTypes,
636 stroke, fillRule);
637 } else {
638 drawHandler.pDrawLine = &storeLine;
639 drawHandler.pDrawPixel = &storePoint;
640 ok = doDrawPath(&drawHandler, &drawSubPath,
641 transX, transY,
642 coords, maxCoords,
643 types, numTypes,
644 stroke);
645 }
646 if (!ok) {
647 JNU_ThrowArrayIndexOutOfBoundsException(env, "coords array");
648 }
649 (*env)->ReleasePrimitiveArrayCritical(env, typesArray, types,
650 JNI_ABORT);
651 }
652 (*env)->ReleasePrimitiveArrayCritical(env, coordsArray, coords,
653 JNI_ABORT);
654 }
655
656 XDHD_FREE_POINTS(&dHData);
657 X11SD_DirectRenderNotify(env, xsdo);
658#endif /* !HEADLESS */
659}
660
661/*
662 * Class: sun_java2d_x11_X11Renderer
663 * Method: XFillRect
664 * Signature: (IJIIII)V
665 */
666JNIEXPORT void JNICALL Java_sun_java2d_x11_X11Renderer_XFillRect
667 (JNIEnv *env, jobject xr,
668 jlong pXSData, jlong xgc,
669 jint x, jint y, jint w, jint h)
670{
671#ifndef HEADLESS
672 X11SDOps *xsdo = (X11SDOps *) pXSData;
673
674 if (xsdo == NULL) {
675 return;
676 }
677
678 XFillRectangle(awt_display, xsdo->drawable, (GC) xgc,
679 CLAMP_TO_SHORT(x), CLAMP_TO_SHORT(y),
680 CLAMP_TO_USHORT(w), CLAMP_TO_USHORT(h));
681 X11SD_DirectRenderNotify(env, xsdo);
682#endif /* !HEADLESS */
683}
684
685/*
686 * Class: sun_java2d_x11_X11Renderer
687 * Method: XFillRoundRect
688 * Signature: (IJIIIIII)V
689 */
690JNIEXPORT void JNICALL Java_sun_java2d_x11_X11Renderer_XFillRoundRect
691 (JNIEnv *env, jobject xr,
692 jlong pXSData, jlong xgc,
693 jint x, jint y, jint w, jint h,
694 jint arcW, jint arcH)
695{
696#ifndef HEADLESS
697 long ty1, ty2, tx1, tx2, cx, cy, cxw, cyh,
698 halfW, halfH, leftW, rightW, topH, bottomH;
699 X11SDOps *xsdo = (X11SDOps *) pXSData;
700
701 if (xsdo == NULL || w <= 0 || h <= 0) {
702 return;
703 }
704
705 arcW = ABS(arcW);
706 arcH = ABS(arcH);
707 if (arcW > w) {
708 arcW = w;
709 }
710 if (arcH > h) {
711 arcH = h;
712 }
713
714 if (arcW == 0 || arcH == 0) {
715 Java_sun_java2d_x11_X11Renderer_XFillRect(env, xr, pXSData, xgc,
716 x, y, w, h);
717 return;
718 }
719
720 halfW = (arcW / 2);
721 halfH = (arcH / 2);
722
723 /* clamp to short bounding box of round rectangle */
724 cx = CLAMP_TO_SHORT(x);
725 cy = CLAMP_TO_SHORT(y);
726 cxw = CLAMP_TO_SHORT(x + w);
727 cyh = CLAMP_TO_SHORT(y + h);
728
729 /* clamp to short coordinates of lines */
730 tx1 = CLAMP_TO_SHORT(x + halfW + 1);
731 tx2 = CLAMP_TO_SHORT(x + w - halfW - 1);
732 ty1 = CLAMP_TO_SHORT(y + halfH + 1);
733 ty2 = CLAMP_TO_SHORT(y + h - halfH - 1);
734
735 /*
736 * recalculate heightes and widthes of round parts
737 * to minimize distortions in visible area
738 */
739 leftW = (tx1 - cx) * 2;
740 rightW = (cxw - tx2) * 2;
741 topH = (ty1 - cy) * 2;
742 bottomH = (cyh - ty2) * 2;
743
744 awt_drawArc(env, xsdo->drawable, (GC) xgc,
745 cx, cy, leftW, topH,
746 90, 90, JNI_TRUE);
747 awt_drawArc(env, xsdo->drawable, (GC) xgc,
748 cxw - rightW, cy, rightW, topH,
749 0, 90, JNI_TRUE);
750 awt_drawArc(env, xsdo->drawable, (GC) xgc,
751 cx, cyh - bottomH, leftW, bottomH,
752 180, 90, JNI_TRUE);
753 awt_drawArc(env, xsdo->drawable, (GC) xgc,
754 cxw - rightW, cyh - bottomH, rightW, bottomH,
755 270, 90, JNI_TRUE);
756
757 if (tx1 < tx2) {
758 if (cy < ty1) {
759 XFillRectangle(awt_display, xsdo->drawable, (GC) xgc,
760 tx1, cy, tx2 - tx1, ty1 - cy);
761 }
762 if (ty2 < cyh) {
763 XFillRectangle(awt_display, xsdo->drawable, (GC) xgc,
764 tx1, ty2, tx2 - tx1, cyh - ty2);
765 }
766 }
767 if (ty1 < ty2) {
768 XFillRectangle(awt_display, xsdo->drawable, (GC) xgc,
769 cx, ty1, cxw - cx, ty2 - ty1);
770 }
771 X11SD_DirectRenderNotify(env, xsdo);
772#endif /* !HEADLESS */
773}
774
775/*
776 * Class: sun_java2d_x11_X11Renderer
777 * Method: XFillOval
778 * Signature: (IJIIII)V
779 */
780JNIEXPORT void JNICALL Java_sun_java2d_x11_X11Renderer_XFillOval
781 (JNIEnv *env, jobject xr,
782 jlong pXSData, jlong xgc,
783 jint x, jint y, jint w, jint h)
784{
785#ifndef HEADLESS
786 X11SDOps *xsdo = (X11SDOps *) pXSData;
787
788 if (xsdo == NULL) {
789 return;
790 }
791
792 if (w < 3 || h < 3) {
793 /*
794 * Fix for 4205762 - 1x1 ovals do not draw on Ultra1, Creator3d
795 * (related to 4411814 on Windows platform)
796 * Most X11 servers drivers have poor rendering
797 * for thin ellipses and the rendering is most strikingly
798 * different from our theoretical arcs. Ideally we should
799 * trap all ovals less than some fairly large size and
800 * try to draw aesthetically pleasing ellipses, but that
801 * would require considerably more work to get the corresponding
802 * drawArc variants to match pixel for pixel.
803 * Thin ovals of girth 1 pixel are simple rectangles.
804 * Thin ovals of girth 2 pixels are simple rectangles with
805 * potentially smaller lengths. Determine the correct length
806 * by calculating .5*.5 + scaledlen*scaledlen == 1.0 which
807 * means that scaledlen is the sqrt(0.75). Scaledlen is
808 * relative to the true length (w or h) and needs to be
809 * adjusted by half a pixel in different ways for odd or
810 * even lengths.
811 */
812#define SQRT_3_4 0.86602540378443864676
813 if (w > 2 && h > 1) {
814 int adjw = (int) ((SQRT_3_4 * w - ((w&1)-1)) * 0.5);
815 adjw = adjw * 2 + (w&1);
816 x += (w-adjw)/2;
817 w = adjw;
818 } else if (h > 2 && w > 1) {
819 int adjh = (int) ((SQRT_3_4 * h - ((h&1)-1)) * 0.5);
820 adjh = adjh * 2 + (h&1);
821 y += (h-adjh)/2;
822 h = adjh;
823 }
824#undef SQRT_3_4
825 if (w > 0 && h > 0) {
826 XFillRectangle(awt_display, xsdo->drawable, (GC) xgc, x, y, w, h);
827 }
828 } else {
829 awt_drawArc(env, xsdo->drawable, (GC) xgc,
830 x, y, w, h, 0, 360, JNI_TRUE);
831 }
832 X11SD_DirectRenderNotify(env, xsdo);
833#endif /* !HEADLESS */
834}
835
836/*
837 * Class: sun_java2d_x11_X11Renderer
838 * Method: XFillArc
839 * Signature: (IJIIIIII)V
840 */
841JNIEXPORT void JNICALL Java_sun_java2d_x11_X11Renderer_XFillArc
842 (JNIEnv *env, jobject xr,
843 jlong pXSData, jlong xgc,
844 jint x, jint y, jint w, jint h,
845 jint angleStart, jint angleExtent)
846{
847#ifndef HEADLESS
848 X11SDOps *xsdo = (X11SDOps *) pXSData;
849
850 if (xsdo == NULL) {
851 return;
852 }
853
854 awt_drawArc(env, xsdo->drawable, (GC) xgc,
855 x, y, w, h, angleStart, angleExtent, JNI_TRUE);
856 X11SD_DirectRenderNotify(env, xsdo);
857#endif /* !HEADLESS */
858}
859
860/*
861 * Class: sun_java2d_x11_X11Renderer
862 * Method: XFillPoly
863 * Signature: (IJII[I[II)V
864 */
865JNIEXPORT void JNICALL Java_sun_java2d_x11_X11Renderer_XFillPoly
866 (JNIEnv *env, jobject xr,
867 jlong pXSData, jlong xgc,
868 jint transx, jint transy,
869 jintArray xcoordsArray, jintArray ycoordsArray, jint npoints)
870{
871#ifndef HEADLESS
872 XPoint pTmp[POLYTEMPSIZE], *points;
873 X11SDOps *xsdo = (X11SDOps *) pXSData;
874
875 if (xsdo == NULL) {
876 return;
877 }
878
879 if (JNU_IsNull(env, xcoordsArray) || JNU_IsNull(env, ycoordsArray)) {
880 JNU_ThrowNullPointerException(env, "coordinate array");
881 return;
882 }
883 if ((*env)->GetArrayLength(env, ycoordsArray) < npoints ||
884 (*env)->GetArrayLength(env, xcoordsArray) < npoints)
885 {
886 JNU_ThrowArrayIndexOutOfBoundsException(env, "coordinate array");
887 return;
888 }
889
890 if (npoints < 3) {
891 return;
892 }
893
894 points = transformPoints(env, xcoordsArray, ycoordsArray, transx, transy,
895 pTmp, (int *)&npoints, JNI_FALSE);
896 if (points == 0) {
897 JNU_ThrowOutOfMemoryError(env, "translated coordinate array");
898 } else {
899 if (npoints > 2) {
900 XFillPolygon(awt_display, xsdo->drawable, (GC) xgc,
901 points, npoints, Complex, CoordModeOrigin);
902 X11SD_DirectRenderNotify(env, xsdo);
903 }
904 if (points != pTmp) {
905 free(points);
906 }
907 }
908#endif /* !HEADLESS */
909}
910
911/*
912 * Class: sun_java2d_x11_X11Renderer
913 * Method: XFillSpans
914 * Signature: (IJLsun/java2d/pipe/SpanIterator;JII)V
915 */
916JNIEXPORT void JNICALL Java_sun_java2d_x11_X11Renderer_XFillSpans
917 (JNIEnv *env, jobject xr,
918 jlong pXSData, jlong xgc,
919 jobject si, jlong pIterator,
920 jint transx, jint transy)
921{
922#ifndef HEADLESS
923 SpanIteratorFuncs *pFuncs = (SpanIteratorFuncs *) jlong_to_ptr(pIterator);
924 void *srData;
925 jint x, y, w, h;
926 jint spanbox[4];
927 X11SDOps *xsdo = (X11SDOps *) pXSData;
928
929 if (xsdo == NULL) {
930 return;
931 }
932
933 if (JNU_IsNull(env, si)) {
934 JNU_ThrowNullPointerException(env, "span iterator");
935 return;
936 }
937 if (pFuncs == NULL) {
938 JNU_ThrowNullPointerException(env, "native iterator not supplied");
939 return;
940 }
941
942 srData = (*pFuncs->open)(env, si);
943 while ((*pFuncs->nextSpan)(srData, spanbox)) {
944 x = spanbox[0] + transx;
945 y = spanbox[1] + transy;
946 w = spanbox[2] - spanbox[0];
947 h = spanbox[3] - spanbox[1];
948 XFillRectangle(awt_display, xsdo->drawable, (GC) xgc,
949 CLAMP_TO_SHORT(x), CLAMP_TO_SHORT(y),
950 CLAMP_TO_USHORT(w), CLAMP_TO_USHORT(h));
951 }
952 (*pFuncs->close)(env, srData);
953 X11SD_DirectRenderNotify(env, xsdo);
954#endif /* !HEADLESS */
955}
956
957/*
958 * Class: sun_java2d_x11_X11Renderer
959 * Method: devCopyArea
960 * Signature: (Lsun/java2d/SurfaceData;IIIIII)V
961 */
962JNIEXPORT void JNICALL
963Java_sun_java2d_x11_X11Renderer_devCopyArea
964 (JNIEnv *env, jobject xr,
965 jlong xsd, jlong gc,
966 jint srcx, jint srcy,
967 jint dstx, jint dsty,
968 jint width, jint height)
969{
970#ifndef HEADLESS
971 X11SDOps *xsdo;
972 GC xgc;
973
974 xsdo = (X11SDOps *)jlong_to_ptr(xsd);
975 if (xsdo == NULL) {
976 return;
977 }
978
979 xgc = (GC)gc;
980 if (xgc == NULL) {
981 return;
982 }
983
984 XCopyArea(awt_display, xsdo->drawable, xsdo->drawable, xgc,
985 srcx, srcy, width, height, dstx, dsty);
986
987 X11SD_DirectRenderNotify(env, xsdo);
988#endif /* !HEADLESS */
989}