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 
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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                 int index = 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[line*img->bytes_per_line + pix] =
 785                         (unsigned char) (mask[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
 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
 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
 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
 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
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
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
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 }