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