1 /*
2 * Copyright (c) 2010, 2020, 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 #ifdef HEADLESS
27 #error This file should not be included in headless library
28 #endif
29
30 #include "X11SurfaceData.h"
31 #include <jni.h>
32 #include <math.h>
33 #include "Region.h"
34 #include "fontscalerdefs.h"
35
36 #include <X11/extensions/Xrender.h>
37
38 #ifdef __linux__
39 #include <sys/utsname.h>
40 #endif
41
42 #ifndef X_RenderCreateLinearGradient
43 typedef struct _XLinearGradient {
44 XPointFixed p1;
45 XPointFixed p2;
46 } XLinearGradient;
47 #endif
48
49 #ifndef X_RenderCreateRadialGradient
50 typedef struct _XCircle {
51 XFixed x;
52 XFixed y;
53 XFixed radius;
54 } XCircle;
55
56 typedef struct _XRadialGradient {
57 XCircle inner;
58 XCircle outer;
59 } XRadialGradient;
60 #endif
61
62 #include <dlfcn.h>
63
64 #define BUILD_TRANSFORM_MATRIX(TRANSFORM, M00, M01, M02, M10, M11, M12) \
65 { \
66 TRANSFORM.matrix[0][0] = M00; \
67 TRANSFORM.matrix[0][1] = M01; \
68 TRANSFORM.matrix[0][2] = M02; \
69 TRANSFORM.matrix[1][0] = M10; \
70 TRANSFORM.matrix[1][1] = M11; \
71 TRANSFORM.matrix[1][2] = M12; \
72 TRANSFORM.matrix[2][0] = 0; \
73 TRANSFORM.matrix[2][1] = 0; \
74 TRANSFORM.matrix[2][2] = 1<<16; \
75 }
76
77 /* The xrender pipleine requires libXrender.so version 0.9.3 or later. */
78 #define REQUIRED_XRENDER_VER1 0
79 #define REQUIRED_XRENDER_VER2 9
80 #define REQUIRED_XRENDER_VER3 3
81
82 #define PKGINFO_LINE_LEN_MAX 256
83 #define PKGINFO_LINE_CNT_MAX 50
84
85 /*
86 * X protocol uses (u_int16)length to specify the length in 4 bytes quantities
87 * of the whole request. Both XRenderFillRectangles() and XFillRectangles()
88 * have provisions to fragment into several requests if the number of rectangles
89 * plus the current x request does not fit into 65535*4 bytes. While
90 * XRenderCreateLinearGradient() and XRenderCreateRadialGradient() have
91 * provisions to gracefully degrade if the resulting request would exceed
92 * 65535*4 bytes.
93 *
94 * Below, we define a cap of 65535*4 bytes for the maximum X request payload
95 * allowed for Non-(XRenderFillRectangles() or XFillRectangles()) API calls,
96 * just to be conservative. This is offset by the size of our maximum x*Req
97 * type in this compilation unit, which is xRenderCreateRadiaGradientReq.
98 *
99 * Note that sizeof(xRenderCreateRadiaGradientReq) = 36
100 */
101 #define MAX_PAYLOAD (262140u - 36u)
102 #define MAXUINT (0xffffffffu)
103
IsXRenderAvailable(jboolean verbose,jboolean ignoreLinuxVersion)104 static jboolean IsXRenderAvailable(jboolean verbose, jboolean ignoreLinuxVersion) {
105
106 void *xrenderlib;
107
108 int major_opcode, first_event, first_error;
109 jboolean available = JNI_TRUE;
110
111 if (!XQueryExtension(awt_display, "RENDER",
112 &major_opcode, &first_event, &first_error)) {
113 return JNI_FALSE;
114 }
115
116 #if defined(_AIX)
117 // On AIX we have to use a special syntax because the shared libraries are packed in
118 // multi-architecture archives. We first try to load the system default libXrender
119 // which is contained in the 'X11.base.lib' fileset starting with AIX 6.1
120 xrenderlib = dlopen("libXrender.a(shr_64.o)", RTLD_GLOBAL | RTLD_LAZY | RTLD_MEMBER);
121 if (xrenderlib == NULL) {
122 // If the latter wasn't successful, we also try to load the version under /opt/freeware
123 // This may be downloaded from the "AIX Toolbox for Linux Applications" even for AIX 5.3
124 xrenderlib = dlopen("libXrender.a(libXrender.so.0)", RTLD_GLOBAL | RTLD_LAZY | RTLD_MEMBER);
125 }
126 if (xrenderlib != NULL) {
127 dlclose(xrenderlib);
128 } else {
129 available = JNI_FALSE;
130 }
131 #else
132 Dl_info info;
133 jboolean versionInfoIsFound = JNI_FALSE;
134
135 memset(&info, 0, sizeof(Dl_info));
136 if (dladdr(&XRenderChangePicture, &info) && info.dli_fname != NULL) {
137 char pkgInfoPath[FILENAME_MAX];
138 char *pkgFileName = "/pkgconfig/xrender.pc";
139 size_t pkgFileNameLen = strlen(pkgFileName);
140 size_t pos, len = strlen(info.dli_fname);
141
142 pos = len;
143 while (pos > 0 && info.dli_fname[pos] != '/') {
144 pos -= 1;
145 }
146
147 if (pos > 0 && pos < (FILENAME_MAX - pkgFileNameLen - 1)) {
148 struct stat stat_info;
149
150 // compose absolute filename to package config
151 strncpy(pkgInfoPath, info.dli_fname, pos);
152
153 strcpy(pkgInfoPath + pos, pkgFileName);
154 pkgInfoPath[pos + pkgFileNameLen] = '\0';
155
156 // check whether the config file exist and is a regular file
157 if ((stat(pkgInfoPath, &stat_info)== 0) &&
158 S_ISREG(stat_info.st_mode))
159 {
160 FILE *fp = fopen(pkgInfoPath, "r");
161 if (fp != NULL) {
162 char line[PKGINFO_LINE_LEN_MAX];
163 int lineCount = PKGINFO_LINE_CNT_MAX;
164 char *versionPrefix = "Version: ";
165 size_t versionPrefixLen = strlen(versionPrefix);
166
167 // look for version
168 while(fgets(line,sizeof(line),fp) != NULL && --lineCount > 0) {
169 size_t lineLen = strlen(line);
170
171 if (lineLen > versionPrefixLen &&
172 strncmp(versionPrefix, line, versionPrefixLen) == 0)
173 {
174 int v1 = 0, v2 = 0, v3 = 0;
175 int numNeeded = 3,numProcessed;
176 char* version = line + versionPrefixLen;
177 numProcessed = sscanf(version, "%d.%d.%d", &v1, &v2, &v3);
178
179 if (numProcessed == numNeeded) {
180 // we successfuly read the library version
181 versionInfoIsFound = JNI_TRUE;
182
183 if (REQUIRED_XRENDER_VER1 == v1 &&
184 ((REQUIRED_XRENDER_VER2 > v2) ||
185 ((REQUIRED_XRENDER_VER2 == v2) && (REQUIRED_XRENDER_VER3 > v3))))
186 {
187 available = JNI_FALSE;
188
189 if (verbose) {
190 printf("INFO: the version %d.%d.%d of libXrender.so is "
191 "not supported.\n\tSee release notes for more details.\n",
192 v1, v2, v3);
193 fflush(stdout);
194 }
195 } else {
196 if (verbose) {
197 printf("INFO: The version of libXrender.so "
198 "is detected as %d.%d%d\n", v1, v2, v3);
199 fflush(stdout);
200 }
201 }
202 }
203 break;
204 }
205 }
206 fclose(fp);
207 }
208 }
209 }
210 }
211 if (verbose && !versionInfoIsFound) {
212 printf("WARNING: The version of libXrender.so cannot be detected.\n,"
213 "The pipe line will be enabled, but note that versions less than 0.9.3\n"
214 "may cause hangs and crashes\n"
215 "\tSee the release notes for more details.\n");
216 fflush(stdout);
217 }
218 #endif
219
220 #ifdef __linux__
221 /*
222 * Check for Linux >= 3.5 (Ubuntu 12.04.02 LTS) to avoid hitting
223 * https://bugs.freedesktop.org/show_bug.cgi?id=48045
224 */
225 struct utsname utsbuf;
226 if(uname(&utsbuf) >= 0) {
227 int major, minor, revision;
228 if(sscanf(utsbuf.release, "%i.%i.%i", &major, &minor, &revision) == 3) {
229 if(major < 3 || (major == 3 && minor < 5)) {
230 if(!ignoreLinuxVersion) {
231 available = JNI_FALSE;
232 }
233 else if(verbose) {
234 printf("WARNING: Linux < 3.5 detected.\n"
235 "The pipeline will be enabled, but graphical "
236 "artifacts can occur with old graphic drivers.\n"
237 "See the release notes for more details.\n");
238 fflush(stdout);
239 }
240 }
241 }
242 }
243 #endif // __linux__
244
245 return available;
246 }
247 /*
248 * Class: sun_awt_X11GraphicsEnvironment
249 * Method: initGLX
250 * Signature: ()Z
251 */
252 JNIEXPORT jboolean JNICALL
Java_sun_awt_X11GraphicsEnvironment_initXRender(JNIEnv * env,jclass x11ge,jboolean verbose,jboolean ignoreLinuxVersion)253 Java_sun_awt_X11GraphicsEnvironment_initXRender
254 (JNIEnv *env, jclass x11ge, jboolean verbose, jboolean ignoreLinuxVersion)
255 {
256 static jboolean xrenderAvailable = JNI_FALSE;
257 static jboolean firstTime = JNI_TRUE;
258
259 if (firstTime) {
260 #ifdef DISABLE_XRENDER_BY_DEFAULT
261 if (verbose == JNI_FALSE) {
262 xrenderAvailable = JNI_FALSE;
263 firstTime = JNI_FALSE;
264 return xrenderAvailable;
265 }
266 #endif
267 AWT_LOCK();
268 xrenderAvailable = IsXRenderAvailable(verbose, ignoreLinuxVersion);
269 AWT_UNLOCK();
270 firstTime = JNI_FALSE;
271 }
272 return xrenderAvailable;
273 }
274
275
276 JNIEXPORT void JNICALL
Java_sun_java2d_xr_XRBackendNative_initIDs(JNIEnv * env,jclass cls)277 Java_sun_java2d_xr_XRBackendNative_initIDs(JNIEnv *env, jclass cls) {
278 char *maskData;
279 XImage* defaultImg;
280 jfieldID maskImgID;
281 jlong fmt8;
282 jlong fmt32;
283
284 jfieldID a8ID = (*env)->GetStaticFieldID(env, cls, "FMTPTR_A8", "J");
285 if (a8ID == NULL) {
286 return;
287 }
288 jfieldID argb32ID = (*env)->GetStaticFieldID(env, cls, "FMTPTR_ARGB32", "J");
289 if (argb32ID == NULL) {
290 return;
291 }
292
293 if (awt_display == (Display *)NULL) {
294 return;
295 }
296
297 fmt8 = ptr_to_jlong(XRenderFindStandardFormat(awt_display, PictStandardA8));
298 fmt32 = ptr_to_jlong(XRenderFindStandardFormat(awt_display, PictStandardARGB32));
299
300 (*env)->SetStaticLongField(env, cls, a8ID, fmt8);
301 (*env)->SetStaticLongField(env, cls, argb32ID, fmt32);
302
303 maskData = (char *) malloc(32*32);
304 if (maskData == NULL) {
305 return;
306 }
307
308 defaultImg = XCreateImage(awt_display, NULL, 8, ZPixmap, 0, maskData, 32, 32, 8, 0);
309 defaultImg->data = maskData; //required?
310 maskImgID = (*env)->GetStaticFieldID(env, cls, "MASK_XIMG", "J");
311 if (maskImgID == NULL) {
312 return;
313 }
314
315 (*env)->SetStaticLongField(env, cls, maskImgID, ptr_to_jlong(defaultImg));
316 }
317
318 JNIEXPORT void JNICALL
Java_sun_java2d_xr_XRBackendNative_freeGC(JNIEnv * env,jobject this,jlong gc)319 Java_sun_java2d_xr_XRBackendNative_freeGC
320 (JNIEnv *env, jobject this, jlong gc) {
321 XFreeGC(awt_display, (GC) jlong_to_ptr(gc));
322 }
323
324 JNIEXPORT jlong JNICALL
Java_sun_java2d_xr_XRBackendNative_createGC(JNIEnv * env,jobject this,jint drawable)325 Java_sun_java2d_xr_XRBackendNative_createGC
326 (JNIEnv *env, jobject this, jint drawable) {
327 GC xgc = XCreateGC(awt_display, (Drawable) drawable, 0L, NULL);
328 return ptr_to_jlong(xgc);
329 }
330
331 JNIEXPORT jint JNICALL
Java_sun_java2d_xr_XRBackendNative_createPixmap(JNIEnv * env,jobject this,jint drawable,jint depth,jint width,jint height)332 Java_sun_java2d_xr_XRBackendNative_createPixmap(JNIEnv *env, jobject this,
333 jint drawable, jint depth,
334 jint width, jint height) {
335 return (jint) XCreatePixmap(awt_display, (Drawable) drawable,
336 width, height, depth);
337 }
338
339 JNIEXPORT jint JNICALL
Java_sun_java2d_xr_XRBackendNative_createPictureNative(JNIEnv * env,jclass cls,jint drawable,jlong formatPtr)340 Java_sun_java2d_xr_XRBackendNative_createPictureNative
341 (JNIEnv *env, jclass cls, jint drawable, jlong formatPtr) {
342 XRenderPictureAttributes pict_attr;
343 return XRenderCreatePicture(awt_display, (Drawable) drawable,
344 (XRenderPictFormat *) jlong_to_ptr(formatPtr),
345 0, &pict_attr);
346 }
347
348 JNIEXPORT void JNICALL
Java_sun_java2d_xr_XRBackendNative_freePicture(JNIEnv * env,jobject this,jint picture)349 Java_sun_java2d_xr_XRBackendNative_freePicture
350 (JNIEnv *env, jobject this, jint picture) {
351 XRenderFreePicture(awt_display, (Picture) picture);
352 }
353
354 JNIEXPORT void JNICALL
Java_sun_java2d_xr_XRBackendNative_freePixmap(JNIEnv * env,jobject this,jint pixmap)355 Java_sun_java2d_xr_XRBackendNative_freePixmap
356 (JNIEnv *env, jobject this, jint pixmap) {
357 XFreePixmap(awt_display, (Pixmap) pixmap);
358 }
359
360 JNIEXPORT void JNICALL
Java_sun_java2d_xr_XRBackendNative_setPictureRepeat(JNIEnv * env,jobject this,jint picture,jint repeat)361 Java_sun_java2d_xr_XRBackendNative_setPictureRepeat
362 (JNIEnv *env, jobject this, jint picture, jint repeat) {
363 XRenderPictureAttributes pict_attr;
364 pict_attr.repeat = repeat;
365 XRenderChangePicture (awt_display, (Picture) picture, CPRepeat, &pict_attr);
366 }
367
368
369 JNIEXPORT void JNICALL
Java_sun_java2d_xr_XRBackendNative_setGCExposures(JNIEnv * env,jobject this,jlong gc,jboolean exposure)370 Java_sun_java2d_xr_XRBackendNative_setGCExposures
371 (JNIEnv *env, jobject this, jlong gc, jboolean exposure) {
372 XSetGraphicsExposures(awt_display,
373 (GC) jlong_to_ptr(gc), exposure ? True : False); //TODO: ????
374 }
375
376 JNIEXPORT void JNICALL
Java_sun_java2d_xr_XRBackendNative_setGCForeground(JNIEnv * env,jobject this,jlong gc,jint pixel)377 Java_sun_java2d_xr_XRBackendNative_setGCForeground
378 (JNIEnv *env, jobject this, jlong gc, jint pixel) {
379 XSetForeground(awt_display, (GC) jlong_to_ptr(gc), (unsigned long) pixel);
380 }
381
382
383 JNIEXPORT void JNICALL
Java_sun_java2d_xr_XRBackendNative_copyArea(JNIEnv * env,jobject this,jint src,jint dst,jlong gc,jint srcx,jint srcy,jint width,jint height,jint dstx,jint dsty)384 Java_sun_java2d_xr_XRBackendNative_copyArea
385 (JNIEnv *env, jobject this, jint src, jint dst, jlong gc,
386 jint srcx, jint srcy, jint width, jint height, jint dstx, jint dsty) {
387 XCopyArea(awt_display, (Drawable) src, (Drawable) dst,
388 (GC) jlong_to_ptr(gc), srcx, srcy, width, height, dstx, dsty);
389 }
390
391 JNIEXPORT void JNICALL
Java_sun_java2d_xr_XRBackendNative_renderComposite(JNIEnv * env,jobject this,jbyte op,jint src,jint mask,jint dst,jint srcX,jint srcY,jint maskX,jint maskY,jint dstX,jint dstY,jint width,jint height)392 Java_sun_java2d_xr_XRBackendNative_renderComposite
393 (JNIEnv *env, jobject this, jbyte op, jint src, jint mask, jint dst,
394 jint srcX, jint srcY, jint maskX, jint maskY,
395 jint dstX, jint dstY, jint width, jint height) {
396 XRenderComposite (awt_display, op,
397 (Picture)src, (Picture)mask, (Picture)dst,
398 srcX, srcY, maskX, maskY, dstX, dstY, width, height);
399 }
400
401 JNIEXPORT void JNICALL
Java_sun_java2d_xr_XRBackendNative_renderRectangle(JNIEnv * env,jobject this,jint dst,jbyte op,jshort red,jshort green,jshort blue,jshort alpha,jint x,jint y,jint width,jint height)402 Java_sun_java2d_xr_XRBackendNative_renderRectangle
403 (JNIEnv *env, jobject this, jint dst, jbyte op,
404 jshort red, jshort green, jshort blue, jshort alpha,
405 jint x, jint y, jint width, jint height) {
406 XRenderColor color;
407 color.alpha = alpha;
408 color.red = red;
409 color.green = green;
410 color.blue = blue;
411 XRenderFillRectangle(awt_display, op, (Picture) dst, &color,
412 x, y, width, height);
413 }
414
415 JNIEXPORT void JNICALL
Java_sun_java2d_xr_XRBackendNative_XRenderRectanglesNative(JNIEnv * env,jclass xsd,jint dst,jbyte op,jshort red,jshort green,jshort blue,jshort alpha,jintArray rectArray,jint rectCnt)416 Java_sun_java2d_xr_XRBackendNative_XRenderRectanglesNative
417 (JNIEnv *env, jclass xsd, jint dst, jbyte op,
418 jshort red, jshort green, jshort blue, jshort alpha,
419 jintArray rectArray, jint rectCnt) {
420 int i;
421 jint* rects;
422 XRectangle *xRects;
423 XRectangle sRects[256];
424
425 XRenderColor color;
426 color.alpha = alpha;
427 color.red = red;
428 color.green = green;
429 color.blue = blue;
430
431 if (rectCnt <= 256) {
432 xRects = &sRects[0];
433 } else {
434 if (MAXUINT / sizeof(XRectangle) < (unsigned)rectCnt) {
435 /* rectCnt too big, integer overflow */
436 return;
437 }
438 xRects = (XRectangle *) malloc(sizeof(XRectangle) * rectCnt);
439 if (xRects == NULL) {
440 return;
441 }
442 }
443
444 if ((rects = (jint *)
445 (*env)->GetPrimitiveArrayCritical(env, rectArray, NULL)) == NULL) {
446 if (xRects != &sRects[0]) {
447 free(xRects);
448 }
449 return;
450 }
451
452 for (i=0; i < rectCnt; i++) {
453 xRects[i].x = rects[i*4 + 0];
454 xRects[i].y = rects[i*4 + 1];
455 xRects[i].width = rects[i*4 + 2];
456 xRects[i].height = rects[i*4 + 3];
457 }
458
459 XRenderFillRectangles(awt_display, op,
460 (Picture) dst, &color, xRects, rectCnt);
461
462 (*env)->ReleasePrimitiveArrayCritical(env, rectArray, rects, JNI_ABORT);
463 if (xRects != &sRects[0]) {
464 free(xRects);
465 }
466 }
467
468 JNIEXPORT void JNICALL
Java_sun_java2d_xr_XRBackendNative_XRSetTransformNative(JNIEnv * env,jclass xsd,jint pic,jint m00,jint m01,jint m02,jint m10,jint m11,jint m12)469 Java_sun_java2d_xr_XRBackendNative_XRSetTransformNative
470 (JNIEnv *env, jclass xsd, jint pic,
471 jint m00, jint m01, jint m02, jint m10, jint m11, jint m12) {
472
473 XTransform tr;
474 BUILD_TRANSFORM_MATRIX(tr, m00, m01, m02, m10, m11, m12);
475 XRenderSetPictureTransform (awt_display, (Picture) pic, &tr);
476 }
477
478 JNIEXPORT jint JNICALL
Java_sun_java2d_xr_XRBackendNative_XRCreateLinearGradientPaintNative(JNIEnv * env,jclass xsd,jfloatArray fractionsArray,jshortArray pixelsArray,jint x1,jint y1,jint x2,jint y2,jint numStops,jint repeat)479 Java_sun_java2d_xr_XRBackendNative_XRCreateLinearGradientPaintNative
480 (JNIEnv *env, jclass xsd, jfloatArray fractionsArray,
481 jshortArray pixelsArray, jint x1, jint y1, jint x2, jint y2,
482 jint numStops, jint repeat) {
483 jint i;
484 jshort* pixels;
485 jfloat* fractions;
486 XRenderPictureAttributes pict_attr;
487 Picture gradient = 0;
488 XRenderColor *colors;
489 XFixed *stops;
490 XLinearGradient grad;
491
492 if (MAX_PAYLOAD / (sizeof(XRenderColor) + sizeof(XFixed))
493 < (unsigned)numStops) {
494 /* numStops too big, payload overflow */
495 return -1;
496 }
497
498 if ((pixels = (jshort *)
499 (*env)->GetPrimitiveArrayCritical(env, pixelsArray, NULL)) == NULL) {
500 return -1;
501 }
502 if ((fractions = (jfloat *)
503 (*env)->GetPrimitiveArrayCritical(env, fractionsArray, NULL)) == NULL) {
504 (*env)->ReleasePrimitiveArrayCritical(env,
505 pixelsArray, pixels, JNI_ABORT);
506 return -1;
507 }
508
509 grad.p1.x = x1;
510 grad.p1.y = y1;
511 grad.p2.x = x2;
512 grad.p2.y = y2;
513
514 /*TODO optimized & malloc check*/
515 colors = (XRenderColor *) malloc(numStops * sizeof(XRenderColor));
516 stops = (XFixed *) malloc(numStops * sizeof(XFixed));
517
518 if (colors == NULL || stops == NULL) {
519 if (colors != NULL) {
520 free(colors);
521 }
522 if (stops != NULL) {
523 free(stops);
524 }
525 (*env)->ReleasePrimitiveArrayCritical(env, pixelsArray, pixels, JNI_ABORT);
526 (*env)->ReleasePrimitiveArrayCritical(env, fractionsArray, fractions, JNI_ABORT);
527 return -1;
528 }
529
530 for (i=0; i < numStops; i++) {
531 stops[i] = XDoubleToFixed(fractions[i]);
532 colors[i].alpha = pixels[i*4 + 0];
533 colors[i].red = pixels[i*4 + 1];
534 colors[i].green = pixels[i*4 + 2];
535 colors[i].blue = pixels[i*4 + 3];
536 }
537 gradient = XRenderCreateLinearGradient(awt_display, &grad, stops, colors, numStops);
538 free(colors);
539 free(stops);
540
541 (*env)->ReleasePrimitiveArrayCritical(env, pixelsArray, pixels, JNI_ABORT);
542 (*env)->ReleasePrimitiveArrayCritical(env, fractionsArray, fractions, JNI_ABORT);
543
544 if (gradient != 0) {
545 pict_attr.repeat = repeat;
546 XRenderChangePicture (awt_display, gradient, CPRepeat, &pict_attr);
547 }
548
549 return (jint) gradient;
550 }
551
552
553 JNIEXPORT jint JNICALL
Java_sun_java2d_xr_XRBackendNative_XRCreateRadialGradientPaintNative(JNIEnv * env,jclass xsd,jfloatArray fractionsArray,jshortArray pixelsArray,jint numStops,jint centerX,jint centerY,jint innerRadius,jint outerRadius,jint repeat)554 Java_sun_java2d_xr_XRBackendNative_XRCreateRadialGradientPaintNative
555 (JNIEnv *env, jclass xsd, jfloatArray fractionsArray,
556 jshortArray pixelsArray, jint numStops,
557 jint centerX, jint centerY,
558 jint innerRadius, jint outerRadius, jint repeat) {
559 jint i;
560 jshort* pixels;
561 jfloat* fractions;
562 XRenderPictureAttributes pict_attr;
563 Picture gradient = 0;
564 XRenderColor *colors;
565 XFixed *stops;
566 XRadialGradient grad;
567
568 if (MAX_PAYLOAD / (sizeof(XRenderColor) + sizeof(XFixed))
569 < (unsigned)numStops) {
570 /* numStops too big, payload overflow */
571 return -1;
572 }
573
574 if ((pixels =
575 (jshort *)(*env)->GetPrimitiveArrayCritical(env, pixelsArray, NULL)) == NULL) {
576 return -1;
577 }
578 if ((fractions = (jfloat *)
579 (*env)->GetPrimitiveArrayCritical(env, fractionsArray, NULL)) == NULL) {
580 (*env)->ReleasePrimitiveArrayCritical(env,
581 pixelsArray, pixels, JNI_ABORT);
582 return -1; //TODO release pixels first
583 }
584
585 grad.inner.x = centerX;
586 grad.inner.y = centerY;
587 grad.inner.radius = innerRadius;
588 grad.outer.x = centerX;
589 grad.outer.y = centerY;
590 grad.outer.radius = outerRadius;
591
592 /*TODO optimized & malloc check*/
593 colors = (XRenderColor *) malloc(numStops * sizeof(XRenderColor));
594 stops = (XFixed *) malloc(numStops * sizeof(XFixed));
595
596 if (colors == NULL || stops == NULL) {
597 if (colors != NULL) {
598 free(colors);
599 }
600 if (stops != NULL) {
601 free(stops);
602 }
603 (*env)->ReleasePrimitiveArrayCritical(env, pixelsArray, pixels, JNI_ABORT);
604 (*env)->ReleasePrimitiveArrayCritical(env, fractionsArray, fractions, JNI_ABORT);
605 return -1;
606 }
607
608 for (i=0; i < numStops; i++) {
609 stops[i] = XDoubleToFixed(fractions[i]);
610 colors[i].alpha = pixels[i*4 + 0];
611 colors[i].red = pixels[i*4 + 1];
612 colors[i].green = pixels[i*4 + 2];
613 colors[i].blue = pixels[i*4 + 3];
614 }
615 gradient = (jint) XRenderCreateRadialGradient(awt_display, &grad, stops, colors, numStops);
616 free(colors);
617 free(stops);
618
619 (*env)->ReleasePrimitiveArrayCritical(env, pixelsArray, pixels, JNI_ABORT);
620 (*env)->ReleasePrimitiveArrayCritical(env, fractionsArray, fractions, JNI_ABORT);
621
622
623 if (gradient != 0) {
624 pict_attr.repeat = repeat;
625 XRenderChangePicture (awt_display, gradient, CPRepeat, &pict_attr);
626 }
627
628 return (jint) gradient;
629 }
630
631 JNIEXPORT void JNICALL
Java_sun_java2d_xr_XRBackendNative_setFilter(JNIEnv * env,jobject this,jint picture,jint filter)632 Java_sun_java2d_xr_XRBackendNative_setFilter
633 (JNIEnv *env, jobject this, jint picture, jint filter) {
634
635 char * filterName = "fast";
636
637 switch(filter) {
638 case 0:
639 filterName = "fast";
640 break;
641
642 case 1:
643 filterName = "good";
644 break;
645
646 case 2:
647 filterName = "best";
648 break;
649 }
650
651 XRenderSetPictureFilter(awt_display, (Picture) picture, filterName, NULL, 0);
652 }
653
654 JNIEXPORT void JNICALL
Java_sun_java2d_xr_XRBackendNative_XRSetClipNative(JNIEnv * env,jclass xsd,jlong dst,jint x1,jint y1,jint x2,jint y2,jobject complexclip,jboolean isGC)655 Java_sun_java2d_xr_XRBackendNative_XRSetClipNative
656 (JNIEnv *env, jclass xsd, jlong dst,
657 jint x1, jint y1, jint x2, jint y2,
658 jobject complexclip, jboolean isGC)
659 {
660 int numrects;
661 XRectangle rects[256];
662 XRectangle *pRect = rects;
663
664 numrects = RegionToYXBandedRectangles(env,
665 x1, y1, x2, y2, complexclip,
666 &pRect, 256);
667
668 if (isGC == JNI_TRUE) {
669 if (dst != (jlong) 0) {
670 XSetClipRectangles(awt_display, (GC) jlong_to_ptr(dst), 0, 0, pRect, numrects, YXBanded);
671 }
672 } else {
673 XRenderSetPictureClipRectangles (awt_display, (Picture) dst, 0, 0, pRect, numrects);
674 }
675
676 if (pRect != rects) {
677 free(pRect);
678 }
679 }
680
681 JNIEXPORT void JNICALL
Java_sun_java2d_xr_XRBackendNative_putMaskNative(JNIEnv * env,jclass cls,jint drawable,jlong gc,jbyteArray imageData,jint sx,jint sy,jint dx,jint dy,jint width,jint height,jint maskOff,jint maskScan,jfloat ea,jlong imgPtr)682 Java_sun_java2d_xr_XRBackendNative_putMaskNative
683 (JNIEnv *env, jclass cls, jint drawable, jlong gc, jbyteArray imageData,
684 jint sx, jint sy, jint dx, jint dy, jint width, jint height,
685 jint maskOff, jint maskScan, jfloat ea, jlong imgPtr) {
686
687 int line, pix;
688 char *mask;
689 char *defaultData;
690 XImage *defaultImg, *img;
691 jboolean imageFits;
692
693 if ((mask = (char *)
694 (*env)->GetPrimitiveArrayCritical(env, imageData, NULL)) == NULL) {
695 return;
696 }
697
698 defaultImg = (XImage *) jlong_to_ptr(imgPtr);
699
700 if (ea != 1.0f) {
701 for (line=0; line < height; line++) {
702 for (pix=0; pix < width; pix++) {
703 size_t index = (size_t) maskScan * line + pix + maskOff;
704 mask[index] = (((unsigned char) mask[index])*ea);
705 }
706 }
707 }
708
709 /*
710 * 1. If existing XImage and supplied buffer match, only adjust the data pointer
711 * 2. If existing XImage is large enough to hold the data but does not match in
712 * scan the data is copied to fit the XImage.
713 * 3. If data is larger than the existing XImage a new temporary XImage is
714 * allocated.
715 * The default XImage is optimized for the AA tiles, which are currently 32x32.
716 */
717 defaultData = defaultImg->data;
718 img = defaultImg;
719 imageFits = defaultImg->width >= width && defaultImg->height >= height;
720
721 if (imageFits &&
722 maskOff == defaultImg->xoffset && maskScan == defaultImg->bytes_per_line) {
723 defaultImg->data = mask;
724 } else {
725 if (imageFits) {
726 for (line=0; line < height; line++) {
727 for (pix=0; pix < width; pix++) {
728 img->data[(size_t) line * img->bytes_per_line + pix] =
729 (unsigned char) (mask[(size_t) maskScan * line + pix + maskOff]);
730 }
731 }
732 } else {
733 img = XCreateImage(awt_display, NULL, 8, ZPixmap,
734 maskOff, mask, maskScan, height, 8, 0);
735 }
736 }
737
738 XPutImage(awt_display, (Pixmap) drawable, (GC) jlong_to_ptr(gc),
739 img, 0, 0, 0, 0, width, height);
740 (*env)->ReleasePrimitiveArrayCritical(env, imageData, mask, JNI_ABORT);
741
742 if (img != defaultImg) {
743 img->data = NULL;
744 XDestroyImage(img);
745 }
746 defaultImg->data = defaultData;
747 }
748
749 JNIEXPORT void JNICALL
Java_sun_java2d_xr_XRBackendNative_XRAddGlyphsNative(JNIEnv * env,jclass cls,jint glyphSet,jlongArray glyphInfoPtrsArray,jint glyphCnt,jbyteArray pixelDataArray,int pixelDataLength)750 Java_sun_java2d_xr_XRBackendNative_XRAddGlyphsNative
751 (JNIEnv *env, jclass cls, jint glyphSet,
752 jlongArray glyphInfoPtrsArray, jint glyphCnt,
753 jbyteArray pixelDataArray, int pixelDataLength) {
754 jlong *glyphInfoPtrs;
755 unsigned char *pixelData;
756 int i;
757
758 if (MAX_PAYLOAD / (sizeof(XGlyphInfo) + sizeof(Glyph))
759 < (unsigned)glyphCnt) {
760 /* glyphCnt too big, payload overflow */
761 return;
762 }
763
764 XGlyphInfo *xginfo = (XGlyphInfo *) malloc(sizeof(XGlyphInfo) * glyphCnt);
765 Glyph *gid = (Glyph *) malloc(sizeof(Glyph) * glyphCnt);
766
767 if (xginfo == NULL || gid == NULL) {
768 if (xginfo != NULL) {
769 free(xginfo);
770 }
771 if (gid != NULL) {
772 free(gid);
773 }
774 return;
775 }
776
777 if ((glyphInfoPtrs = (jlong *)(*env)->
778 GetPrimitiveArrayCritical(env, glyphInfoPtrsArray, NULL)) == NULL)
779 {
780 free(xginfo);
781 free(gid);
782 return;
783 }
784
785 if ((pixelData = (unsigned char *)
786 (*env)->GetPrimitiveArrayCritical(env, pixelDataArray, NULL)) == NULL)
787 {
788 (*env)->ReleasePrimitiveArrayCritical(env,
789 glyphInfoPtrsArray, glyphInfoPtrs, JNI_ABORT);
790 free(xginfo);
791 free(gid);
792 return;
793 }
794
795 for (i=0; i < glyphCnt; i++) {
796 GlyphInfo *jginfo = (GlyphInfo *) jlong_to_ptr(glyphInfoPtrs[i]);
797
798 // 'jginfo->cellInfo' is of type 'void*'
799 // (see definition of 'GlyphInfo' in fontscalerdefs.h)
800 // 'Glyph' is typedefed to 'unsigned long'
801 // (see http://www.x.org/releases/X11R7.7/doc/libXrender/libXrender.txt)
802 // Maybe we should assert that (sizeof(void*) == sizeof(Glyph)) ?
803 gid[i] = (Glyph) (jginfo->cellInfo);
804 xginfo[i].x = (-jginfo->topLeftX);
805 xginfo[i].y = (-jginfo->topLeftY);
806 xginfo[i].width = jginfo->width;
807 xginfo[i].height = jginfo->height;
808 xginfo[i].xOff = round(jginfo->advanceX);
809 xginfo[i].yOff = round(jginfo->advanceY);
810 }
811
812 XRenderAddGlyphs(awt_display, glyphSet, &gid[0], &xginfo[0], glyphCnt,
813 (const char*)pixelData, pixelDataLength);
814
815 (*env)->ReleasePrimitiveArrayCritical(env, glyphInfoPtrsArray, glyphInfoPtrs, JNI_ABORT);
816 (*env)->ReleasePrimitiveArrayCritical(env, pixelDataArray, pixelData, JNI_ABORT);
817
818 free(xginfo);
819 free(gid);
820 }
821
822 JNIEXPORT void JNICALL
Java_sun_java2d_xr_XRBackendNative_XRFreeGlyphsNative(JNIEnv * env,jclass cls,jint glyphSet,jintArray gidArray,jint glyphCnt)823 Java_sun_java2d_xr_XRBackendNative_XRFreeGlyphsNative
824 (JNIEnv *env, jclass cls, jint glyphSet, jintArray gidArray, jint glyphCnt) {
825
826 if (MAX_PAYLOAD / sizeof(Glyph) < (unsigned)glyphCnt) {
827 /* glyphCnt too big, payload overflow */
828 return;
829 }
830
831 /* The glyph ids are 32 bit but may be stored in a 64 bit long on
832 * a 64 bit architecture. So optimise the 32 bit case to avoid
833 * extra stack or heap allocations by directly referencing the
834 * underlying Java array and only allocate on 64 bit.
835 */
836 if (sizeof(jint) == sizeof(Glyph)) {
837 jint *gids =
838 (*env)->GetPrimitiveArrayCritical(env, gidArray, NULL);
839 if (gids == NULL) {
840 return;
841 } else {
842 XRenderFreeGlyphs(awt_display,
843 (GlyphSet)glyphSet, (Glyph *)gids, glyphCnt);
844 (*env)->ReleasePrimitiveArrayCritical(env, gidArray,
845 gids, JNI_ABORT);
846 }
847 return;
848 } else {
849 Glyph stack_ids[64];
850 Glyph *gids = NULL;
851 jint* jgids = NULL;
852 int i;
853
854 if (glyphCnt <= 64) {
855 gids = stack_ids;
856 } else {
857 gids = (Glyph *)malloc(sizeof(Glyph) * glyphCnt);
858 if (gids == NULL) {
859 return;
860 }
861 }
862 jgids = (*env)->GetPrimitiveArrayCritical(env, gidArray, NULL);
863 if (jgids == NULL) {
864 if (gids != stack_ids) {
865 free(gids);
866 }
867 return;
868 }
869 for (i=0; i < glyphCnt; i++) {
870 gids[i] = jgids[i];
871 }
872 XRenderFreeGlyphs(awt_display,
873 (GlyphSet) glyphSet, gids, glyphCnt);
874 (*env)->ReleasePrimitiveArrayCritical(env, gidArray,
875 jgids, JNI_ABORT);
876 if (gids != stack_ids) {
877 free(gids);
878 }
879 }
880 }
881
882 JNIEXPORT jint JNICALL
Java_sun_java2d_xr_XRBackendNative_XRenderCreateGlyphSetNative(JNIEnv * env,jclass cls,jlong format)883 Java_sun_java2d_xr_XRBackendNative_XRenderCreateGlyphSetNative
884 (JNIEnv *env, jclass cls, jlong format) {
885 return XRenderCreateGlyphSet(awt_display, (XRenderPictFormat *) jlong_to_ptr(format));
886 }
887
888 JNIEXPORT void JNICALL
Java_sun_java2d_xr_XRBackendNative_XRenderCompositeTextNative(JNIEnv * env,jclass cls,jint op,jint src,jint dst,jint sx,jint sy,jlong maskFmt,jintArray eltArray,jintArray glyphIDArray,jint eltCnt,jint glyphCnt)889 Java_sun_java2d_xr_XRBackendNative_XRenderCompositeTextNative
890 (JNIEnv *env, jclass cls, jint op, jint src, jint dst,
891 jint sx, jint sy, jlong maskFmt, jintArray eltArray,
892 jintArray glyphIDArray, jint eltCnt, jint glyphCnt) {
893 jint i;
894 jint *ids;
895 jint *elts;
896 XGlyphElt32 *xelts;
897 unsigned int *xids;
898 XGlyphElt32 selts[24];
899 unsigned int sids[256];
900 int charCnt = 0;
901
902 if ((MAX_PAYLOAD / sizeof(XGlyphElt32) < (unsigned)eltCnt)
903 || (MAX_PAYLOAD / sizeof(unsigned int) < (unsigned)glyphCnt)
904 || ((MAX_PAYLOAD - sizeof(XGlyphElt32)*(unsigned)eltCnt) /
905 sizeof(unsigned int) < (unsigned)glyphCnt))
906 {
907 /* (eltCnt, glyphCnt) too big, payload overflow */
908 return;
909 }
910
911 if (eltCnt <= 24) {
912 xelts = &selts[0];
913 }else {
914 xelts = (XGlyphElt32 *) malloc(sizeof(XGlyphElt32) * eltCnt);
915 if (xelts == NULL) {
916 return;
917 }
918 }
919
920 if (glyphCnt <= 256) {
921 xids = &sids[0];
922 } else {
923 xids = (unsigned int*)malloc(sizeof(unsigned int) * glyphCnt);
924 if (xids == NULL) {
925 if (xelts != &selts[0]) {
926 free(xelts);
927 }
928 return;
929 }
930 }
931
932 if ((ids = (jint *)
933 (*env)->GetPrimitiveArrayCritical(env, glyphIDArray, NULL)) == NULL) {
934 if (xelts != &selts[0]) {
935 free(xelts);
936 }
937 if (xids != &sids[0]) {
938 free(xids);
939 }
940 return;
941 }
942 if ((elts = (jint *)
943 (*env)->GetPrimitiveArrayCritical(env, eltArray, NULL)) == NULL) {
944 (*env)->ReleasePrimitiveArrayCritical(env,
945 glyphIDArray, ids, JNI_ABORT);
946 if (xelts != &selts[0]) {
947 free(xelts);
948 }
949 if (xids != &sids[0]) {
950 free(xids);
951 }
952 return;
953 }
954
955 for (i=0; i < glyphCnt; i++) {
956 xids[i] = ids[i];
957 }
958
959 for (i=0; i < eltCnt; i++) {
960 xelts[i].nchars = elts[i*4 + 0];
961 xelts[i].xOff = elts[i*4 + 1];
962 xelts[i].yOff = elts[i*4 + 2];
963 xelts[i].glyphset = (GlyphSet) elts[i*4 + 3];
964 xelts[i].chars = &xids[charCnt];
965
966 charCnt += xelts[i].nchars;
967 }
968
969 XRenderCompositeText32(awt_display, op, (Picture) src, (Picture) dst,
970 (XRenderPictFormat *) jlong_to_ptr(maskFmt),
971 sx, sy, 0, 0, xelts, eltCnt);
972
973 (*env)->ReleasePrimitiveArrayCritical(env, glyphIDArray, ids, JNI_ABORT);
974 (*env)->ReleasePrimitiveArrayCritical(env, eltArray, elts, JNI_ABORT);
975
976 if (xelts != &selts[0]) {
977 free(xelts);
978 }
979
980 if (xids != &sids[0]) {
981 free(xids);
982 }
983 }
984
985 JNIEXPORT void JNICALL
Java_sun_java2d_xr_XRBackendNative_setGCMode(JNIEnv * env,jobject this,jlong gc,jboolean copy)986 Java_sun_java2d_xr_XRBackendNative_setGCMode
987 (JNIEnv *env, jobject this, jlong gc, jboolean copy) {
988 GC xgc = (GC) jlong_to_ptr(gc);
989
990 if (copy == JNI_TRUE) {
991 XSetFunction(awt_display, xgc, GXcopy);
992 } else {
993 XSetFunction(awt_display, xgc, GXxor);
994 }
995 }
996
997 JNIEXPORT void JNICALL
Java_sun_java2d_xr_XRBackendNative_GCRectanglesNative(JNIEnv * env,jclass xsd,jint dst,jlong gc,jintArray rectArray,jint rectCnt)998 Java_sun_java2d_xr_XRBackendNative_GCRectanglesNative
999 (JNIEnv *env, jclass xsd, jint dst, jlong gc,
1000 jintArray rectArray, jint rectCnt) {
1001 int i;
1002 jint* rects;
1003 XRectangle *xRects;
1004 XRectangle sRects[256];
1005
1006 if (rectCnt <= 256) {
1007 xRects = &sRects[0];
1008 } else {
1009 if (MAXUINT / sizeof(XRectangle) < (unsigned)rectCnt) {
1010 /* rectCnt too big, integer overflow */
1011 return;
1012 }
1013
1014 xRects = (XRectangle *) malloc(sizeof(XRectangle) * rectCnt);
1015 if (xRects == NULL) {
1016 return;
1017 }
1018 }
1019
1020 if ((rects = (jint*)
1021 (*env)->GetPrimitiveArrayCritical(env, rectArray, NULL)) == NULL) {
1022 if (xRects != &sRects[0]) {
1023 free(xRects);
1024 }
1025 return;
1026 }
1027
1028 for (i=0; i < rectCnt; i++) {
1029 xRects[i].x = rects[i*4 + 0];
1030 xRects[i].y = rects[i*4 + 1];
1031 xRects[i].width = rects[i*4 + 2];
1032 xRects[i].height = rects[i*4 + 3];
1033 }
1034
1035 XFillRectangles(awt_display, (Drawable) dst, (GC) jlong_to_ptr(gc), xRects, rectCnt);
1036
1037 (*env)->ReleasePrimitiveArrayCritical(env, rectArray, rects, JNI_ABORT);
1038 if (xRects != &sRects[0]) {
1039 free(xRects);
1040 }
1041 }
1042