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