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