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