1 /*
   2  * Copyright (c) 2010, 2011, 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 #ifdef __solaris__
  76 /* Solaris 10 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 #ifdef __solaris__
 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     jfieldID argb32ID = (*env)->GetStaticFieldID(env, cls, "FMTPTR_ARGB32", "J");
 330 
 331     if (awt_display == (Display *)NULL) {
 332         return;
 333     }
 334 
 335     fmt8 = ptr_to_jlong(XRenderFindStandardFormat(awt_display, PictStandardA8));
 336     fmt32 = ptr_to_jlong(XRenderFindStandardFormat(awt_display, PictStandardARGB32));
 337 
 338     (*env)->SetStaticLongField(env, cls, a8ID, fmt8);
 339     (*env)->SetStaticLongField(env, cls, argb32ID, fmt32);
 340 
 341     maskData = (char *) malloc(32*32);
 342     if (maskData == NULL) {
 343        return;
 344     }
 345 
 346     defaultImg = XCreateImage(awt_display, NULL, 8, ZPixmap, 0, maskData, 32, 32, 8, 0);
 347     defaultImg->data = maskData; //required?
 348     maskImgID = (*env)->GetStaticFieldID(env, cls, "MASK_XIMG", "J");
 349     (*env)->SetStaticLongField(env, cls, maskImgID, ptr_to_jlong(defaultImg));
 350 }
 351 
 352 JNIEXPORT void JNICALL
 353 Java_sun_java2d_xr_XRBackendNative_freeGC
 354  (JNIEnv *env, jobject this, jlong gc) {
 355     XFreeGC(awt_display, (GC) jlong_to_ptr(gc));
 356 }
 357 
 358 JNIEXPORT jlong JNICALL
 359 Java_sun_java2d_xr_XRBackendNative_createGC
 360  (JNIEnv *env, jobject this, jint drawable) {
 361   GC xgc = XCreateGC(awt_display, (Drawable) drawable, 0L, NULL);
 362   return ptr_to_jlong(xgc);
 363 }
 364 
 365 JNIEXPORT jint JNICALL
 366 Java_sun_java2d_xr_XRBackendNative_createPixmap(JNIEnv *env, jobject this,
 367                                                 jint drawable, jint depth,
 368                                                 jint width, jint height) {
 369     return (jint) XCreatePixmap(awt_display, (Drawable) drawable,
 370                                 width, height, depth);
 371 }
 372 
 373 JNIEXPORT jint JNICALL
 374 Java_sun_java2d_xr_XRBackendNative_createPictureNative
 375  (JNIEnv *env, jclass cls, jint drawable, jlong formatPtr) {
 376   XRenderPictureAttributes pict_attr;
 377   return XRenderCreatePicture(awt_display, (Drawable) drawable,
 378                               (XRenderPictFormat *) jlong_to_ptr(formatPtr),
 379                                0, &pict_attr);
 380 }
 381 
 382 JNIEXPORT void JNICALL
 383 Java_sun_java2d_xr_XRBackendNative_freePicture
 384  (JNIEnv *env, jobject this, jint picture) {
 385       XRenderFreePicture(awt_display, (Picture) picture);
 386 }
 387 
 388 JNIEXPORT void JNICALL
 389 Java_sun_java2d_xr_XRBackendNative_freePixmap
 390  (JNIEnv *env, jobject this, jint pixmap) {
 391    XFreePixmap(awt_display, (Pixmap) pixmap);
 392 }
 393 
 394 JNIEXPORT void JNICALL
 395 Java_sun_java2d_xr_XRBackendNative_setPictureRepeat
 396  (JNIEnv *env, jobject this, jint picture, jint repeat) {
 397     XRenderPictureAttributes pict_attr;
 398     pict_attr.repeat = repeat;
 399     XRenderChangePicture (awt_display, (Picture) picture, CPRepeat, &pict_attr);
 400 }
 401 
 402 
 403 JNIEXPORT void JNICALL
 404 Java_sun_java2d_xr_XRBackendNative_setGCExposures
 405  (JNIEnv *env, jobject this, jlong gc, jboolean exposure) {
 406     XSetGraphicsExposures(awt_display,
 407                          (GC) jlong_to_ptr(gc), exposure ? True : False); //TODO: ????
 408 }
 409 
 410 JNIEXPORT void JNICALL
 411 Java_sun_java2d_xr_XRBackendNative_setGCForeground
 412  (JNIEnv *env, jobject this, jlong gc, jint pixel) {
 413     XSetForeground(awt_display, (GC) jlong_to_ptr(gc), (unsigned long) pixel);
 414 }
 415 
 416 
 417 JNIEXPORT void JNICALL
 418 Java_sun_java2d_xr_XRBackendNative_copyArea
 419  (JNIEnv *env, jobject this, jint src, jint dst, jlong gc,
 420   jint srcx, jint srcy, jint width, jint height, jint dstx, jint dsty) {
 421     XCopyArea(awt_display, (Drawable) src, (Drawable) dst,
 422              (GC) jlong_to_ptr(gc), srcx, srcy, width, height, dstx, dsty);
 423 }
 424 
 425 JNIEXPORT void JNICALL
 426 Java_sun_java2d_xr_XRBackendNative_renderComposite
 427  (JNIEnv *env, jobject this, jbyte op, jint src, jint mask, jint dst,
 428   jint srcX, jint srcY, jint maskX, jint maskY,
 429   jint dstX, jint dstY, jint width, jint height) {
 430     XRenderComposite (awt_display, op,
 431                       (Picture)src, (Picture)mask, (Picture)dst,
 432                        srcX, srcY, maskX, maskY, dstX, dstY, width, height);
 433 }
 434 
 435 JNIEXPORT void JNICALL
 436 Java_sun_java2d_xr_XRBackendNative_renderRectangle
 437  (JNIEnv *env, jobject this, jint dst, jbyte op,
 438   jshort red, jshort green, jshort blue, jshort alpha,
 439   jint x, jint y, jint width, jint height) {
 440     XRenderColor color;
 441     color.alpha = alpha;
 442     color.red = red;
 443     color.green = green;
 444     color.blue = blue;
 445     XRenderFillRectangle(awt_display, op, (Picture) dst, &color,
 446                          x, y, width, height);
 447 }
 448 
 449 JNIEXPORT void JNICALL
 450 Java_sun_java2d_xr_XRBackendNative_XRenderRectanglesNative
 451  (JNIEnv *env, jclass xsd, jint dst, jbyte op,
 452   jshort red, jshort green, jshort blue, jshort alpha,
 453   jintArray rectArray, jint rectCnt) {
 454     int i;
 455     jint* rects;
 456     XRectangle *xRects;
 457     XRectangle sRects[256];
 458 
 459     XRenderColor color;
 460     color.alpha = alpha;
 461     color.red = red;
 462     color.green = green;
 463     color.blue = blue;
 464 
 465     if (rectCnt <= 256) {
 466         xRects = &sRects[0];
 467     } else {
 468         if (MAXUINT / sizeof(XRectangle) < (unsigned)rectCnt) {
 469             /* rectCnt too big, integer overflow */
 470             return;
 471         }
 472         xRects = (XRectangle *) malloc(sizeof(XRectangle) * rectCnt);
 473         if (xRects == NULL) {
 474             return;
 475         }
 476     }
 477 
 478     if ((rects = (jint *)
 479          (*env)->GetPrimitiveArrayCritical(env, rectArray, NULL)) == NULL) {
 480         if (xRects != &sRects[0]) {
 481             free(xRects);
 482         }
 483         return;
 484     }
 485 
 486     for (i=0; i < rectCnt; i++) {
 487         xRects[i].x = rects[i*4 + 0];
 488         xRects[i].y = rects[i*4 + 1];
 489         xRects[i].width = rects[i*4 + 2];
 490         xRects[i].height = rects[i*4 + 3];
 491     }
 492 
 493     XRenderFillRectangles(awt_display, op,
 494                           (Picture) dst, &color, xRects, rectCnt);
 495 
 496     (*env)->ReleasePrimitiveArrayCritical(env, rectArray, rects, JNI_ABORT);
 497     if (xRects != &sRects[0]) {
 498         free(xRects);
 499     }
 500 }
 501 
 502 JNIEXPORT void JNICALL
 503 Java_sun_java2d_xr_XRBackendNative_XRSetTransformNative
 504  (JNIEnv *env, jclass xsd, jint pic,
 505   jint m00, jint m01, jint m02, jint m10, jint m11, jint m12) {
 506 
 507   XTransform tr;
 508   BUILD_TRANSFORM_MATRIX(tr, m00, m01, m02, m10, m11, m12);
 509   XRenderSetPictureTransform (awt_display, (Picture) pic, &tr);
 510 }
 511 
 512 JNIEXPORT jint JNICALL
 513 Java_sun_java2d_xr_XRBackendNative_XRCreateLinearGradientPaintNative
 514     (JNIEnv *env, jclass xsd, jfloatArray fractionsArray,
 515      jshortArray pixelsArray, jint x1, jint y1, jint x2, jint y2,
 516      jint numStops, jint repeat,
 517      jint m00, jint m01, jint m02, jint m10, jint m11, jint m12) {
 518    jint i;
 519    jshort* pixels;
 520    jfloat* fractions;
 521    XTransform tr;
 522    XRenderPictureAttributes pict_attr;
 523    Picture gradient = 0;
 524    XRenderColor *colors;
 525    XFixed *stops;
 526    XLinearGradient grad;
 527 
 528    if (MAX_PAYLOAD / (sizeof(XRenderColor) + sizeof(XFixed))
 529        < (unsigned)numStops) {
 530        /* numStops too big, payload overflow */
 531        return -1;
 532    }
 533 
 534    if ((pixels = (jshort *)
 535         (*env)->GetPrimitiveArrayCritical(env, pixelsArray, NULL)) == NULL) {
 536        return -1;
 537    }
 538    if ((fractions = (jfloat *)
 539        (*env)->GetPrimitiveArrayCritical(env, fractionsArray, NULL)) == NULL) {
 540        (*env)->ReleasePrimitiveArrayCritical(env,
 541                                               pixelsArray, pixels, JNI_ABORT);
 542        return -1;
 543    }
 544 
 545     grad.p1.x = x1;
 546     grad.p1.y = y1;
 547     grad.p2.x = x2;
 548     grad.p2.y = y2;
 549 
 550     /*TODO optimized & malloc check*/
 551     colors = (XRenderColor *) malloc(numStops * sizeof(XRenderColor));
 552     stops =  (XFixed *) malloc(numStops * sizeof(XFixed));
 553 
 554     if (colors == NULL || stops == NULL) {
 555         if (colors != NULL) {
 556             free(colors);
 557         }
 558         if (stops != NULL) {
 559             free(stops);
 560         }
 561         (*env)->ReleasePrimitiveArrayCritical(env, pixelsArray, pixels, JNI_ABORT);
 562         (*env)->ReleasePrimitiveArrayCritical(env, fractionsArray, fractions, JNI_ABORT);
 563         return -1;
 564     }
 565 
 566     for (i=0; i < numStops; i++) {
 567       stops[i] = XDoubleToFixed(fractions[i]);
 568       colors[i].alpha = pixels[i*4 + 0];
 569       colors[i].red = pixels[i*4 + 1];
 570       colors[i].green = pixels[i*4 + 2];
 571       colors[i].blue = pixels[i*4 + 3];
 572     }
 573 #ifdef __solaris__
 574     if (XRenderCreateLinearGradientFunc!=NULL) {
 575       gradient = (*XRenderCreateLinearGradientFunc)(awt_display, &grad, stops, colors, numStops);
 576     }
 577 #else
 578     gradient = XRenderCreateLinearGradient(awt_display, &grad, stops, colors, numStops);
 579 #endif
 580     free(colors);
 581     free(stops);
 582 
 583    (*env)->ReleasePrimitiveArrayCritical(env, pixelsArray, pixels, JNI_ABORT);
 584    (*env)->ReleasePrimitiveArrayCritical(env, fractionsArray, fractions, JNI_ABORT);
 585 
 586     if (gradient != 0) {
 587         BUILD_TRANSFORM_MATRIX(tr, m00, m01, m02, m10, m11, m12);
 588         XRenderSetPictureTransform (awt_display, gradient, &tr);
 589         pict_attr.repeat = repeat;
 590         XRenderChangePicture (awt_display, gradient, CPRepeat, &pict_attr);
 591     }
 592 
 593    return (jint) gradient;
 594 }
 595 
 596 
 597 JNIEXPORT jint JNICALL
 598 Java_sun_java2d_xr_XRBackendNative_XRCreateRadialGradientPaintNative
 599     (JNIEnv *env, jclass xsd, jfloatArray fractionsArray,
 600      jshortArray pixelsArray, jint numStops,
 601      jint innerRadius, jint outerRadius, jint repeat,
 602      jint m00, jint m01, jint m02, jint m10, jint m11, jint m12) {
 603    jint i;
 604    jshort* pixels;
 605    jfloat* fractions;
 606    XTransform tr;
 607    XRenderPictureAttributes pict_attr;
 608    Picture gradient = 0;
 609    XRenderColor *colors;
 610    XFixed *stops;
 611    XRadialGradient grad;
 612 
 613    if (MAX_PAYLOAD / (sizeof(XRenderColor) + sizeof(XFixed))
 614        < (unsigned)numStops) {
 615        /* numStops too big, payload overflow */
 616        return -1;
 617    }
 618 
 619    if ((pixels =
 620        (jshort *)(*env)->GetPrimitiveArrayCritical(env, pixelsArray, NULL)) == NULL) {
 621        return -1;
 622    }
 623    if ((fractions = (jfloat *)
 624         (*env)->GetPrimitiveArrayCritical(env, fractionsArray, NULL)) == NULL) {
 625        (*env)->ReleasePrimitiveArrayCritical(env,
 626                                              pixelsArray, pixels, JNI_ABORT);
 627        return -1; //TODO release pixels first
 628    }
 629 
 630     grad.inner.x = 0;
 631     grad.inner.y = 0;
 632     grad.inner.radius = innerRadius;
 633     grad.outer.x = 0;
 634     grad.outer.y = 0;
 635     grad.outer.radius = outerRadius;
 636 
 637     /*TODO optimized & malloc check*/
 638     colors = (XRenderColor *) malloc(numStops * sizeof(XRenderColor));
 639     stops =  (XFixed *) malloc(numStops * sizeof(XFixed));
 640 
 641     if (colors == NULL || stops == NULL) {
 642         if (colors != NULL) {
 643             free(colors);
 644         }
 645         if (stops != NULL) {
 646             free(stops);
 647         }
 648         (*env)->ReleasePrimitiveArrayCritical(env, pixelsArray, pixels, JNI_ABORT);
 649         (*env)->ReleasePrimitiveArrayCritical(env, fractionsArray, fractions, JNI_ABORT);
 650         return -1;
 651     }
 652 
 653     for (i=0; i < numStops; i++) {
 654       stops[i] = XDoubleToFixed(fractions[i]);
 655       colors[i].alpha = pixels[i*4 + 0];
 656       colors[i].red = pixels[i*4 + 1];
 657       colors[i].green = pixels[i*4 + 2];
 658       colors[i].blue = pixels[i*4 + 3];
 659     }
 660 #ifdef __solaris__
 661     if (XRenderCreateRadialGradientFunc != NULL) {
 662         gradient = (jint) (*XRenderCreateRadialGradientFunc)(awt_display, &grad, stops, colors, numStops);
 663     }
 664 #else
 665     gradient = (jint) XRenderCreateRadialGradient(awt_display, &grad, stops, colors, numStops);
 666 #endif
 667     free(colors);
 668     free(stops);
 669 
 670    (*env)->ReleasePrimitiveArrayCritical(env, pixelsArray, pixels, JNI_ABORT);
 671    (*env)->ReleasePrimitiveArrayCritical(env, fractionsArray, fractions, JNI_ABORT);
 672 
 673 
 674     if (gradient != 0) {
 675         BUILD_TRANSFORM_MATRIX(tr, m00, m01, m02, m10, m11, m12);
 676         XRenderSetPictureTransform (awt_display, gradient, &tr);
 677         pict_attr.repeat = repeat;
 678         XRenderChangePicture (awt_display, gradient, CPRepeat, &pict_attr);
 679     }
 680 
 681    return (jint) gradient;
 682 }
 683 
 684 JNIEXPORT void JNICALL
 685 Java_sun_java2d_xr_XRBackendNative_setFilter
 686  (JNIEnv *env, jobject this, jint picture, jint filter) {
 687 
 688   char * filterName = "fast";
 689 
 690   switch(filter) {
 691     case 0:
 692       filterName = "fast";
 693       break;
 694 
 695     case 1:
 696       filterName = "good";
 697       break;
 698 
 699     case 2:
 700       filterName = "best";
 701       break;
 702   }
 703 
 704     XRenderSetPictureFilter(awt_display, (Picture) picture, filterName, NULL, 0);
 705 }
 706 
 707 JNIEXPORT void JNICALL
 708 Java_sun_java2d_xr_XRBackendNative_XRSetClipNative
 709     (JNIEnv *env, jclass xsd, jlong dst,
 710      jint x1, jint y1, jint x2, jint y2,
 711      jobject complexclip, jboolean isGC)
 712 {
 713     int numrects;
 714     XRectangle rects[256];
 715     XRectangle *pRect = rects;
 716 
 717     numrects = RegionToYXBandedRectangles(env,
 718             x1, y1, x2, y2, complexclip,
 719             &pRect, 256);
 720 
 721     if (isGC == JNI_TRUE) {
 722       if (dst != (jlong) 0) {
 723           XSetClipRectangles(awt_display, (GC) jlong_to_ptr(dst), 0, 0, pRect, numrects, YXBanded);
 724       }
 725     } else {
 726        XRenderSetPictureClipRectangles (awt_display, (Picture) dst, 0, 0, pRect, numrects);
 727     }
 728 
 729     if (pRect != rects) {
 730         free(pRect);
 731     }
 732 }
 733 
 734 JNIEXPORT void JNICALL
 735 Java_sun_java2d_xr_XRBackendNative_putMaskNative
 736  (JNIEnv *env, jclass cls, jint drawable, jlong gc, jbyteArray imageData,
 737   jint sx, jint sy, jint dx, jint dy, jint width, jint height,
 738   jint maskOff, jint maskScan, jfloat ea, jlong imgPtr) {
 739 
 740     int line, pix;
 741     char *mask;
 742     char *defaultData;
 743     XImage *defaultImg, *img;
 744     jboolean imageFits;
 745 
 746     if ((mask = (char *)
 747          (*env)->GetPrimitiveArrayCritical(env, imageData, NULL)) == NULL) {
 748         return;
 749      }
 750 
 751     defaultImg = (XImage *) jlong_to_ptr(imgPtr);
 752 
 753     if (ea != 1.0f) {
 754         for (line=0; line < height; line++) {
 755             for (pix=0; pix < width; pix++) {
 756                 int index = maskScan*line + pix + maskOff;
 757                 mask[index] = (((unsigned char) mask[index])*ea);
 758             }
 759         }
 760     }
 761 
 762     /*
 763     * 1. If existing XImage and supplied buffer match, only adjust the data pointer
 764     * 2. If existing XImage is large enough to hold the data but does not match in
 765     *    scan the data is copied to fit the XImage.
 766     * 3. If data is larger than the existing XImage a new temporary XImage is
 767     *    allocated.
 768     * The default XImage is optimized for the AA tiles, which are currently 32x32.
 769     */
 770     defaultData = defaultImg->data;
 771     img = defaultImg;
 772     imageFits = defaultImg->width >= width && defaultImg->height >= height;
 773 
 774     if (imageFits &&
 775         maskOff == defaultImg->xoffset && maskScan == defaultImg->bytes_per_line) {
 776         defaultImg->data = mask;
 777     } else {
 778         if (imageFits) {
 779             for (line=0; line < height; line++) {
 780                 for (pix=0; pix < width; pix++) {
 781                     img->data[line*img->bytes_per_line + pix] =
 782                         (unsigned char) (mask[maskScan*line + pix + maskOff]);
 783                 }
 784             }
 785         } else {
 786             img = XCreateImage(awt_display, NULL, 8, ZPixmap,
 787                                maskOff, mask, maskScan, height, 8, 0);
 788         }
 789     }
 790 
 791     XPutImage(awt_display, (Pixmap) drawable, (GC) jlong_to_ptr(gc),
 792               img, 0, 0, 0, 0, width, height);
 793     (*env)->ReleasePrimitiveArrayCritical(env, imageData, mask, JNI_ABORT);
 794 
 795     if (img != defaultImg) {
 796         img->data = NULL;
 797         XDestroyImage(img);
 798     }
 799     defaultImg->data = defaultData;
 800 }
 801 
 802 JNIEXPORT void JNICALL
 803 Java_sun_java2d_xr_XRBackendNative_XRAddGlyphsNative
 804  (JNIEnv *env, jclass cls, jint glyphSet,
 805   jlongArray glyphInfoPtrsArray, jint glyphCnt,
 806   jbyteArray pixelDataArray, int pixelDataLength) {
 807     jlong *glyphInfoPtrs;
 808     unsigned char *pixelData;
 809     int i;
 810 
 811     if (MAX_PAYLOAD / (sizeof(XGlyphInfo) + sizeof(Glyph))
 812         < (unsigned)glyphCnt) {
 813         /* glyphCnt too big, payload overflow */
 814         return;
 815     }
 816 
 817     XGlyphInfo *xginfo = (XGlyphInfo *) malloc(sizeof(XGlyphInfo) * glyphCnt);
 818     Glyph *gid = (Glyph *) malloc(sizeof(Glyph) * glyphCnt);
 819 
 820     if (xginfo == NULL || gid == NULL) {
 821         if (xginfo != NULL) {
 822             free(xginfo);
 823         }
 824         if (gid != NULL) {
 825             free(gid);
 826         }
 827         return;
 828     }
 829 
 830     if ((glyphInfoPtrs = (jlong *)(*env)->
 831         GetPrimitiveArrayCritical(env, glyphInfoPtrsArray, NULL)) == NULL)
 832     {
 833         free(xginfo);
 834         free(gid);
 835         return;
 836     }
 837 
 838     if ((pixelData = (unsigned char *)
 839         (*env)->GetPrimitiveArrayCritical(env, pixelDataArray, NULL)) == NULL)
 840     {
 841         (*env)->ReleasePrimitiveArrayCritical(env,
 842                                 glyphInfoPtrsArray, glyphInfoPtrs, JNI_ABORT);
 843         free(xginfo);
 844         free(gid);
 845         return;
 846     }
 847 
 848     for (i=0; i < glyphCnt; i++) {
 849       GlyphInfo *jginfo = (GlyphInfo *) jlong_to_ptr(glyphInfoPtrs[i]);
 850 
 851       // 'jginfo->cellInfo' is of type 'void*'
 852       // (see definition of 'GlyphInfo' in fontscalerdefs.h)
 853       // 'Glyph' is typedefed to 'unsigned long'
 854       // (see http://www.x.org/releases/X11R7.7/doc/libXrender/libXrender.txt)
 855       // Maybe we should assert that (sizeof(void*) == sizeof(Glyph)) ?
 856       gid[i] = (Glyph) (jginfo->cellInfo);
 857       xginfo[i].x = (-jginfo->topLeftX);
 858       xginfo[i].y = (-jginfo->topLeftY);
 859       xginfo[i].width = jginfo->width;
 860       xginfo[i].height = jginfo->height;
 861       xginfo[i].xOff = round(jginfo->advanceX);
 862       xginfo[i].yOff = round(jginfo->advanceY);
 863     }
 864 
 865     XRenderAddGlyphs(awt_display, glyphSet, &gid[0], &xginfo[0], glyphCnt,
 866                      (const char*)pixelData, pixelDataLength);
 867 
 868     (*env)->ReleasePrimitiveArrayCritical(env, glyphInfoPtrsArray, glyphInfoPtrs, JNI_ABORT);
 869     (*env)->ReleasePrimitiveArrayCritical(env, pixelDataArray, pixelData, JNI_ABORT);
 870 
 871     free(xginfo);
 872     free(gid);
 873 }
 874 
 875 JNIEXPORT void JNICALL
 876 Java_sun_java2d_xr_XRBackendNative_XRFreeGlyphsNative
 877  (JNIEnv *env, jclass cls, jint glyphSet, jintArray gidArray, jint glyphCnt) {
 878 
 879     if (MAX_PAYLOAD / sizeof(Glyph) < (unsigned)glyphCnt) {
 880         /* glyphCnt too big, payload overflow */
 881         return;
 882     }
 883 
 884     /* The glyph ids are 32 bit but may be stored in a 64 bit long on
 885      * a 64 bit architecture. So optimise the 32 bit case to avoid
 886      * extra stack or heap allocations by directly referencing the
 887      * underlying Java array and only allocate on 64 bit.
 888      */
 889     if (sizeof(jint) == sizeof(Glyph)) {
 890         jint *gids =
 891             (*env)->GetPrimitiveArrayCritical(env, gidArray, NULL);
 892         if (gids == NULL) {
 893             return;
 894         } else {
 895              XRenderFreeGlyphs(awt_display,
 896                                (GlyphSet)glyphSet, (Glyph *)gids, glyphCnt);
 897              (*env)->ReleasePrimitiveArrayCritical(env, gidArray,
 898                                                    gids, JNI_ABORT);
 899         }
 900         return;
 901     } else {
 902         Glyph stack_ids[64];
 903         Glyph *gids = NULL;
 904         jint* jgids = NULL;
 905         int i;
 906 
 907         if (glyphCnt <= 64) {
 908             gids = stack_ids;
 909         } else {
 910             gids = (Glyph *)malloc(sizeof(Glyph) * glyphCnt);
 911             if (gids == NULL) {
 912                 return;
 913             }
 914         }
 915         jgids = (*env)->GetPrimitiveArrayCritical(env, gidArray, NULL);
 916         if (jgids == NULL) {
 917             if (gids != stack_ids) {
 918                 free(gids);
 919             }
 920             return;
 921         }
 922         for (i=0; i < glyphCnt; i++) {
 923             gids[i] = jgids[i];
 924         }
 925         XRenderFreeGlyphs(awt_display,
 926                           (GlyphSet) glyphSet, gids, glyphCnt);
 927         (*env)->ReleasePrimitiveArrayCritical(env, gidArray,
 928                                               jgids, JNI_ABORT);
 929         if (gids != stack_ids) {
 930             free(gids);
 931         }
 932     }
 933 }
 934 
 935 JNIEXPORT jint JNICALL
 936 Java_sun_java2d_xr_XRBackendNative_XRenderCreateGlyphSetNative
 937  (JNIEnv *env, jclass cls, jlong format) {
 938   return XRenderCreateGlyphSet(awt_display, (XRenderPictFormat *) jlong_to_ptr(format));
 939 }
 940 
 941 JNIEXPORT void JNICALL
 942 Java_sun_java2d_xr_XRBackendNative_XRenderCompositeTextNative
 943  (JNIEnv *env, jclass cls, jint op, jint src, jint dst,
 944   jint sx, jint sy, jlong maskFmt, jintArray eltArray,
 945   jintArray  glyphIDArray, jint eltCnt, jint glyphCnt) {
 946     jint i;
 947     jint *ids;
 948     jint *elts;
 949     XGlyphElt32 *xelts;
 950     unsigned int *xids;
 951     XGlyphElt32 selts[24];
 952     unsigned int sids[256];
 953     int charCnt = 0;
 954 
 955     if ((MAX_PAYLOAD / sizeof(XGlyphElt32) < (unsigned)eltCnt)
 956         || (MAX_PAYLOAD / sizeof(unsigned int) < (unsigned)glyphCnt)
 957         || ((MAX_PAYLOAD - sizeof(XGlyphElt32)*(unsigned)eltCnt) /
 958             sizeof(unsigned int) < (unsigned)glyphCnt))
 959     {
 960         /* (eltCnt, glyphCnt) too big, payload overflow */
 961         return;
 962     }
 963 
 964     if (eltCnt <= 24) {
 965       xelts = &selts[0];
 966     }else {
 967       xelts = (XGlyphElt32 *) malloc(sizeof(XGlyphElt32) * eltCnt);
 968       if (xelts == NULL) {
 969           return;
 970       }
 971     }
 972 
 973     if (glyphCnt <= 256) {
 974       xids = &sids[0];
 975     } else {
 976       xids = (unsigned int*)malloc(sizeof(unsigned int) * glyphCnt);
 977       if (xids == NULL) {
 978           if (xelts != &selts[0]) {
 979             free(xelts);
 980           }
 981           return;
 982       }
 983     }
 984 
 985     if ((ids = (jint *)
 986          (*env)->GetPrimitiveArrayCritical(env, glyphIDArray, NULL)) == NULL) {
 987         if (xelts != &selts[0]) {
 988             free(xelts);
 989         }
 990         if (xids != &sids[0]) {
 991             free(xids);
 992         }
 993         return;
 994     }
 995     if ((elts = (jint *)
 996           (*env)->GetPrimitiveArrayCritical(env, eltArray, NULL)) == NULL) {
 997         (*env)->ReleasePrimitiveArrayCritical(env,
 998                                               glyphIDArray, ids, JNI_ABORT);
 999         if (xelts != &selts[0]) {
1000             free(xelts);
1001         }
1002         if (xids != &sids[0]) {
1003             free(xids);
1004         }
1005         return;
1006     }
1007 
1008     for (i=0; i < glyphCnt; i++) {
1009       xids[i] = ids[i];
1010     }
1011 
1012     for (i=0; i < eltCnt; i++) {
1013       xelts[i].nchars = elts[i*4 + 0];
1014       xelts[i].xOff = elts[i*4 + 1];
1015       xelts[i].yOff = elts[i*4 + 2];
1016       xelts[i].glyphset = (GlyphSet) elts[i*4 + 3];
1017       xelts[i].chars = &xids[charCnt];
1018 
1019       charCnt += xelts[i].nchars;
1020     }
1021 
1022     XRenderCompositeText32(awt_display, op, (Picture) src, (Picture) dst,
1023                            (XRenderPictFormat *) jlong_to_ptr(maskFmt),
1024                             sx, sy, 0, 0, xelts, eltCnt);
1025 
1026     (*env)->ReleasePrimitiveArrayCritical(env, glyphIDArray, ids, JNI_ABORT);
1027     (*env)->ReleasePrimitiveArrayCritical(env, eltArray, elts, JNI_ABORT);
1028 
1029     if (xelts != &selts[0]) {
1030         free(xelts);
1031     }
1032 
1033     if (xids != &sids[0]) {
1034         free(xids);
1035     }
1036 }
1037 
1038 JNIEXPORT void JNICALL
1039 Java_sun_java2d_xr_XRBackendNative_setGCMode
1040  (JNIEnv *env, jobject this, jlong gc, jboolean copy) {
1041   GC xgc = (GC) jlong_to_ptr(gc);
1042 
1043   if (copy == JNI_TRUE) {
1044     XSetFunction(awt_display, xgc, GXcopy);
1045   } else {
1046     XSetFunction(awt_display, xgc, GXxor);
1047   }
1048 }
1049 
1050 JNIEXPORT void JNICALL
1051 Java_sun_java2d_xr_XRBackendNative_GCRectanglesNative
1052  (JNIEnv *env, jclass xsd, jint dst, jlong gc,
1053   jintArray rectArray, jint rectCnt) {
1054     int i;
1055     jint* rects;
1056     XRectangle *xRects;
1057     XRectangle sRects[256];
1058 
1059     if (rectCnt <= 256) {
1060       xRects = &sRects[0];
1061     } else {
1062       if (MAXUINT / sizeof(XRectangle) < (unsigned)rectCnt) {
1063         /* rectCnt too big, integer overflow */
1064         return;
1065       }
1066 
1067       xRects = (XRectangle *) malloc(sizeof(XRectangle) * rectCnt);
1068       if (xRects == NULL) {
1069         return;
1070       }
1071     }
1072 
1073     if ((rects = (jint*)
1074          (*env)->GetPrimitiveArrayCritical(env, rectArray, NULL)) == NULL) {
1075         if (xRects != &sRects[0]) {
1076             free(xRects);
1077         }
1078         return;
1079     }
1080 
1081     for (i=0; i < rectCnt; i++) {
1082       xRects[i].x = rects[i*4 + 0];
1083       xRects[i].y = rects[i*4 + 1];
1084       xRects[i].width = rects[i*4 + 2];
1085       xRects[i].height = rects[i*4 + 3];
1086     }
1087 
1088     XFillRectangles(awt_display, (Drawable) dst, (GC) jlong_to_ptr(gc), xRects, rectCnt);
1089 
1090     (*env)->ReleasePrimitiveArrayCritical(env, rectArray, rects, JNI_ABORT);
1091     if (xRects != &sRects[0]) {
1092       free(xRects);
1093     }
1094 }
1095 
1096 JNIEXPORT void JNICALL
1097 Java_sun_java2d_xr_XRBackendNative_renderCompositeTrapezoidsNative
1098  (JNIEnv *env, jclass cls, jbyte op, jint src, jlong maskFmt,
1099  jint dst, jint srcX, jint srcY, jintArray  trapArray) {
1100     jint *traps;
1101 
1102     if ((traps = (jint *) (*env)->GetPrimitiveArrayCritical(env, trapArray, NULL)) == NULL) {
1103       return;
1104     }
1105 
1106     XRenderCompositeTrapezoids(awt_display, op, (Picture) src, (Picture) dst,
1107                                (XRenderPictFormat *) jlong_to_ptr(maskFmt),
1108                                srcX, srcY, (XTrapezoid *) (traps+5), traps[0]);
1109 
1110     (*env)->ReleasePrimitiveArrayCritical(env, trapArray, traps, JNI_ABORT);
1111 }