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