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