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