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