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