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