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