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