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 /* 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 #ifdef __solaris__
  70 /* Solaris 10 will not have these symbols at runtime */
  71 #include <dlfcn.h>
  72 #include <link.h>
  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 
 108 static jboolean IsXRenderAvailable() {
 109 
 110     void *xrenderlib;
 111 
 112     int major_opcode, first_event, first_error;
 113 
 114     if (!XQueryExtension(awt_display, "RENDER",
 115                          &major_opcode, &first_event, &first_error)) {
 116         return JNI_FALSE;
 117     }
 118 
 119 #ifdef __solaris__
 120     xrenderlib = dlopen("libXrender.so",RTLD_GLOBAL|RTLD_LAZY);
 121     if (xrenderlib != NULL) {
 122 
 123         XRenderCreateLinearGradientFunc =
 124             (XRenderCreateLinearGradientFuncType)
 125             dlsym(xrenderlib, "XRenderCreateLinearGradient");
 126 
 127         XRenderCreateRadialGradientFunc =
 128             (XRenderCreateRadialGradientFuncType)
 129             dlsym(xrenderlib, "XRenderCreateRadialGradient");
 130 
 131         if (XRenderCreateLinearGradientFunc == NULL ||
 132             XRenderCreateRadialGradientFunc == NULL)
 133         {
 134             dlclose(xrenderlib);
 135             return JNI_FALSE;
 136         }
 137     }
 138 #endif
 139     return JNI_TRUE;
 140 }
 141 /*
 142  * Class:     sun_awt_X11GraphicsEnvironment
 143  * Method:    initGLX
 144  * Signature: ()Z
 145  */
 146 JNIEXPORT jboolean JNICALL
 147 Java_sun_awt_X11GraphicsEnvironment_initXRender
 148  (JNIEnv *env, jclass x11ge)
 149 {
 150 #ifndef HEADLESS
 151     static jboolean xrenderAvailable = JNI_FALSE;
 152     static jboolean firstTime = JNI_TRUE;
 153 
 154     if (firstTime) {
 155         AWT_LOCK();
 156         xrenderAvailable = IsXRenderAvailable();
 157         AWT_UNLOCK();
 158         firstTime = JNI_FALSE;
 159     }
 160     return xrenderAvailable;
 161 #else
 162     return JNI_FALSE;
 163 #endif /* !HEADLESS */
 164 }
 165 
 166 
 167 JNIEXPORT void JNICALL
 168 Java_sun_java2d_xr_XRBackendNative_initIDs(JNIEnv *env, jclass cls) {
 169     char *maskData;
 170     XImage* defaultImg;
 171     jfieldID maskImgID;
 172     jlong fmt8 =
 173         ptr_to_jlong(XRenderFindStandardFormat(awt_display, PictStandardA8));
 174     jlong fmt32 =
 175        ptr_to_jlong(XRenderFindStandardFormat(awt_display, PictStandardARGB32));
 176     jfieldID a8ID = (*env)->GetStaticFieldID(env, cls, "FMTPTR_A8", "J");
 177     jfieldID argb32ID = (*env)->GetStaticFieldID(env, cls, "FMTPTR_ARGB32", "J");
 178 
 179     (*env)->SetStaticLongField(env, cls, a8ID, fmt8);
 180     (*env)->SetStaticLongField(env, cls, argb32ID, fmt32);
 181 
 182     maskData = (char *) malloc(32*32);
 183     if (maskData == NULL) {
 184        return;
 185     }
 186 
 187     defaultImg = XCreateImage(awt_display, NULL, 8, ZPixmap, 0, maskData, 32, 32, 8, 0);
 188     defaultImg->data = maskData; //required?
 189     maskImgID = (*env)->GetStaticFieldID(env, cls, "MASK_XIMG", "J");
 190     (*env)->SetStaticLongField(env, cls, maskImgID, ptr_to_jlong(defaultImg));
 191 }
 192 
 193 JNIEXPORT void JNICALL
 194 Java_sun_java2d_xr_XRBackendNative_freeGC
 195  (JNIEnv *env, jobject this, jlong gc) {
 196     XFreeGC(awt_display, (GC) jlong_to_ptr(gc));
 197 }
 198 
 199 JNIEXPORT jlong JNICALL
 200 Java_sun_java2d_xr_XRBackendNative_createGC
 201  (JNIEnv *env, jobject this, jint drawable) {
 202   GC xgc = XCreateGC(awt_display, (Drawable) drawable, 0L, NULL);
 203   return ptr_to_jlong(xgc);
 204 }
 205 
 206 JNIEXPORT jint JNICALL
 207 Java_sun_java2d_xr_XRBackendNative_createPixmap(JNIEnv *env, jobject this,
 208                                                 jint drawable, jint depth,
 209                                                 jint width, jint height) {
 210     return (jint) XCreatePixmap(awt_display, (Drawable) drawable,
 211                                 width, height, depth);
 212 }
 213 
 214 JNIEXPORT jint JNICALL
 215 Java_sun_java2d_xr_XRBackendNative_createPictureNative
 216  (JNIEnv *env, jclass cls, jint drawable, jlong formatPtr) {
 217   XRenderPictureAttributes pict_attr;
 218   return XRenderCreatePicture(awt_display, (Drawable) drawable,
 219                               (XRenderPictFormat *) jlong_to_ptr(formatPtr),
 220                                0, &pict_attr);
 221 }
 222 
 223 JNIEXPORT void JNICALL
 224 Java_sun_java2d_xr_XRBackendNative_freePicture
 225  (JNIEnv *env, jobject this, jint picture) {
 226       XRenderFreePicture(awt_display, (Picture) picture);
 227 }
 228 
 229 JNIEXPORT void JNICALL
 230 Java_sun_java2d_xr_XRBackendNative_freePixmap
 231  (JNIEnv *env, jobject this, jint pixmap) {
 232    XFreePixmap(awt_display, (Pixmap) pixmap);
 233 }
 234 
 235 JNIEXPORT void JNICALL
 236 Java_sun_java2d_xr_XRBackendNative_setPictureRepeat
 237  (JNIEnv *env, jobject this, jint picture, jint repeat) {
 238     XRenderPictureAttributes pict_attr;
 239     pict_attr.repeat = repeat;
 240     XRenderChangePicture (awt_display, (Picture) picture, CPRepeat, &pict_attr);
 241 }
 242 
 243 
 244 JNIEXPORT void JNICALL
 245 Java_sun_java2d_xr_XRBackendNative_setGCExposures
 246  (JNIEnv *env, jobject this, jlong gc, jboolean exposure) {
 247     XSetGraphicsExposures(awt_display,
 248                          (GC) jlong_to_ptr(gc), exposure ? True : False); //TODO: ????
 249 }
 250 
 251 JNIEXPORT void JNICALL
 252 Java_sun_java2d_xr_XRBackendNative_setGCForeground
 253  (JNIEnv *env, jobject this, jlong gc, jint pixel) {
 254     XSetForeground(awt_display, (GC) jlong_to_ptr(gc), (unsigned long) pixel);
 255 }
 256 
 257 
 258 JNIEXPORT void JNICALL
 259 Java_sun_java2d_xr_XRBackendNative_copyArea
 260  (JNIEnv *env, jobject this, jint src, jint dst, jlong gc,
 261   jint srcx, jint srcy, jint width, jint height, jint dstx, jint dsty) {
 262     XCopyArea(awt_display, (Drawable) src, (Drawable) dst,
 263              (GC) jlong_to_ptr(gc), srcx, srcy, width, height, dstx, dsty);
 264 }
 265 
 266 JNIEXPORT void JNICALL
 267 Java_sun_java2d_xr_XRBackendNative_renderComposite
 268  (JNIEnv *env, jobject this, jbyte op, jint src, jint mask, jint dst,
 269   jint srcX, jint srcY, jint maskX, jint maskY,
 270   jint dstX, jint dstY, jint width, jint height) {
 271     XRenderComposite (awt_display, op,
 272                       (Picture)src, (Picture)mask, (Picture)dst,
 273                        srcX, srcY, maskX, maskY, dstX, dstY, width, height);
 274 }
 275 
 276 JNIEXPORT void JNICALL
 277 Java_sun_java2d_xr_XRBackendNative_renderRectangle
 278  (JNIEnv *env, jobject this, jint dst, jbyte op,
 279   jshort red, jshort green, jshort blue, jshort alpha,
 280   jint x, jint y, jint width, jint height) {
 281     XRenderColor color;
 282     color.alpha = alpha;
 283     color.red = red;
 284     color.green = green;
 285     color.blue = blue;
 286     XRenderFillRectangle(awt_display, op, (Picture) dst, &color,
 287                          x, y, width, height);
 288 }
 289 
 290 JNIEXPORT void JNICALL
 291 Java_sun_java2d_xr_XRBackendNative_XRenderRectanglesNative
 292  (JNIEnv *env, jclass xsd, jint dst, jbyte op,
 293   jshort red, jshort green, jshort blue, jshort alpha,
 294   jintArray rectArray, jint rectCnt) {
 295     int i;
 296     jint* rects;
 297     XRectangle *xRects;
 298     XRectangle sRects[256];
 299 
 300     XRenderColor color;
 301     color.alpha = alpha;
 302     color.red = red;
 303     color.green = green;
 304     color.blue = blue;
 305 
 306     if (rectCnt <= 256) {
 307         xRects = &sRects[0];
 308     } else {
 309         xRects = (XRectangle *) malloc(sizeof(XRectangle) * rectCnt);
 310         if (xRects == NULL) {
 311             return;
 312         }
 313     }
 314 
 315     if ((rects = (jint *)
 316          (*env)->GetPrimitiveArrayCritical(env, rectArray, NULL)) == NULL) {
 317         if (xRects != &sRects[0]) {
 318             free(xRects);
 319         }
 320         return;
 321     }
 322 
 323     for (i=0; i < rectCnt; i++) {
 324         xRects[i].x = rects[i*4 + 0];
 325         xRects[i].y = rects[i*4 + 1];
 326         xRects[i].width = rects[i*4 + 2];
 327         xRects[i].height = rects[i*4 + 3];
 328     }
 329 
 330     XRenderFillRectangles(awt_display, op,
 331                           (Picture) dst, &color, xRects, rectCnt);
 332 
 333     (*env)->ReleasePrimitiveArrayCritical(env, rectArray, rects, JNI_ABORT);
 334     if (xRects != &sRects[0]) {
 335         free(xRects);
 336     }
 337 }
 338 
 339 JNIEXPORT void JNICALL
 340 Java_sun_java2d_xr_XRBackendNative_XRSetTransformNative
 341  (JNIEnv *env, jclass xsd, jint pic,
 342   jint m00, jint m01, jint m02, jint m10, jint m11, jint m12) {
 343 
 344   XTransform tr;
 345   BUILD_TRANSFORM_MATRIX(tr, m00, m01, m02, m10, m11, m12);
 346   XRenderSetPictureTransform (awt_display, (Picture) pic, &tr);
 347 }
 348 
 349 JNIEXPORT jint JNICALL
 350 Java_sun_java2d_xr_XRBackendNative_XRCreateLinearGradientPaintNative
 351     (JNIEnv *env, jclass xsd, jfloatArray fractionsArray,
 352      jshortArray pixelsArray, jint x1, jint y1, jint x2, jint y2,
 353      jint numStops, jint repeat,
 354      jint m00, jint m01, jint m02, jint m10, jint m11, jint m12) {
 355    jint i;
 356    jshort* pixels;
 357    jfloat* fractions;
 358    XTransform tr;
 359    XRenderPictureAttributes pict_attr;
 360    Picture gradient = 0;
 361    XRenderColor *colors;
 362    XFixed *stops;
 363    XLinearGradient grad;
 364 
 365    if ((pixels = (jshort *)
 366         (*env)->GetPrimitiveArrayCritical(env, pixelsArray, NULL)) == NULL) {
 367        return -1;
 368    }
 369    if ((fractions = (jfloat *)
 370        (*env)->GetPrimitiveArrayCritical(env, fractionsArray, NULL)) == NULL) {
 371        (*env)->ReleasePrimitiveArrayCritical(env,
 372                                               pixelsArray, pixels, JNI_ABORT);
 373        return -1;
 374    }
 375 
 376     grad.p1.x = x1;
 377     grad.p1.y = y1;
 378     grad.p2.x = x2;
 379     grad.p2.y = y2;
 380 
 381     /*TODO optimized & malloc check*/
 382     colors = (XRenderColor *) malloc(numStops * sizeof(XRenderColor));
 383     stops =  (XFixed *) malloc(numStops * sizeof(XFixed));
 384 
 385     for (i=0; i < numStops; i++) {
 386       stops[i] = XDoubleToFixed(fractions[i]);
 387       colors[i].alpha = pixels[i*4 + 0];
 388       colors[i].red = pixels[i*4 + 1];
 389       colors[i].green = pixels[i*4 + 2];
 390       colors[i].blue = pixels[i*4 + 3];
 391     }
 392 #ifdef __solaris__
 393     if (XRenderCreateLinearGradientFunc!=NULL) {
 394       gradient = (*XRenderCreateLinearGradientFunc)(awt_display, &grad, stops, colors, numStops);
 395     }
 396 #else
 397     gradient = XRenderCreateLinearGradient(awt_display, &grad, stops, colors, numStops);
 398 #endif
 399     free(colors);
 400     free(stops);
 401 
 402    (*env)->ReleasePrimitiveArrayCritical(env, pixelsArray, pixels, JNI_ABORT);
 403    (*env)->ReleasePrimitiveArrayCritical(env, fractionsArray, fractions, JNI_ABORT);
 404 
 405     if (gradient != 0) {
 406         BUILD_TRANSFORM_MATRIX(tr, m00, m01, m02, m10, m11, m12);
 407         XRenderSetPictureTransform (awt_display, gradient, &tr);
 408         pict_attr.repeat = repeat;
 409         XRenderChangePicture (awt_display, gradient, CPRepeat, &pict_attr);
 410     }
 411 
 412    return (jint) gradient;
 413 }
 414 
 415 
 416 JNIEXPORT jint JNICALL
 417 Java_sun_java2d_xr_XRBackendNative_XRCreateRadialGradientPaintNative
 418     (JNIEnv *env, jclass xsd, jfloatArray fractionsArray,
 419      jshortArray pixelsArray, jint numStops,
 420      jint innerRadius, jint outerRadius, jint repeat,
 421      jint m00, jint m01, jint m02, jint m10, jint m11, jint m12) {
 422    jint i;
 423    jshort* pixels;
 424    jfloat* fractions;
 425    XTransform tr;
 426    XRenderPictureAttributes pict_attr;
 427    Picture gradient = 0;
 428    XRenderColor *colors;
 429    XFixed *stops;
 430    XRadialGradient grad;
 431 
 432 
 433    if ((pixels =
 434        (jshort *)(*env)->GetPrimitiveArrayCritical(env, pixelsArray, NULL)) == NULL) {
 435        return -1;
 436    }
 437    if ((fractions = (jfloat *)
 438         (*env)->GetPrimitiveArrayCritical(env, fractionsArray, NULL)) == NULL) {
 439        (*env)->ReleasePrimitiveArrayCritical(env,
 440                                              pixelsArray, pixels, JNI_ABORT);
 441        return -1; //TODO release pixels first
 442    }
 443 
 444     grad.inner.x = 0;
 445     grad.inner.y = 0;
 446     grad.inner.radius = innerRadius;
 447     grad.outer.x = 0;
 448     grad.outer.y = 0;
 449     grad.outer.radius = outerRadius;
 450 
 451     /*TODO optimized & malloc check*/
 452     colors = (XRenderColor *) malloc(numStops * sizeof(XRenderColor));
 453     stops =  (XFixed *) malloc(numStops * sizeof(XFixed));
 454 
 455     for (i=0; i < numStops; i++) {
 456       stops[i] = XDoubleToFixed(fractions[i]);
 457       colors[i].alpha = pixels[i*4 + 0];
 458       colors[i].red = pixels[i*4 + 1];
 459       colors[i].green = pixels[i*4 + 2];
 460       colors[i].blue = pixels[i*4 + 3];
 461     }
 462 #ifdef __solaris__
 463     if (XRenderCreateRadialGradientFunc != NULL) {
 464         gradient = (jint) (*XRenderCreateRadialGradientFunc)(awt_display, &grad, stops, colors, numStops);
 465     }
 466 #else
 467     gradient = (jint) XRenderCreateRadialGradient(awt_display, &grad, stops, colors, numStops);
 468 #endif
 469     free(colors);
 470     free(stops);
 471 
 472    (*env)->ReleasePrimitiveArrayCritical(env, pixelsArray, pixels, JNI_ABORT);
 473    (*env)->ReleasePrimitiveArrayCritical(env, fractionsArray, fractions, JNI_ABORT);
 474 
 475 
 476     if (gradient != 0) {
 477         BUILD_TRANSFORM_MATRIX(tr, m00, m01, m02, m10, m11, m12);
 478         XRenderSetPictureTransform (awt_display, gradient, &tr);
 479         pict_attr.repeat = repeat;
 480         XRenderChangePicture (awt_display, gradient, CPRepeat, &pict_attr);
 481     }
 482 
 483    return (jint) gradient;
 484 }
 485 
 486 JNIEXPORT void JNICALL
 487 Java_sun_java2d_xr_XRBackendNative_setFilter
 488  (JNIEnv *env, jobject this, jint picture, jint filter) {
 489 
 490   char * filterName = "fast";
 491 
 492   switch(filter) {
 493     case 0:
 494       filterName = "fast";
 495       break;
 496 
 497     case 1:
 498       filterName = "good";
 499       break;
 500 
 501     case 2:
 502       filterName = "best";
 503       break;
 504   }
 505 
 506     XRenderSetPictureFilter(awt_display, (Picture) picture, filterName, NULL, 0);
 507 }
 508 
 509 JNIEXPORT void JNICALL
 510 Java_sun_java2d_xr_XRBackendNative_XRSetClipNative
 511     (JNIEnv *env, jclass xsd, jlong dst,
 512      jint x1, jint y1, jint x2, jint y2,
 513      jobject complexclip, jboolean isGC)
 514 {
 515     int numrects;
 516     XRectangle rects[256];
 517     XRectangle *pRect = rects;
 518 
 519     numrects = RegionToYXBandedRectangles(env,
 520             x1, y1, x2, y2, complexclip,
 521             &pRect, 256);
 522 
 523     if (isGC == JNI_TRUE) {
 524       if (dst != (jlong) 0) {
 525           XSetClipRectangles(awt_display, (GC) jlong_to_ptr(dst), 0, 0, pRect, numrects, YXBanded);
 526       }
 527     } else {
 528        XRenderSetPictureClipRectangles (awt_display, (Picture) dst, 0, 0, pRect, numrects);
 529     }
 530 
 531     if (pRect != rects) {
 532         free(pRect);
 533     }
 534 }
 535 
 536 JNIEXPORT void JNICALL
 537 Java_sun_java2d_xr_XRBackendNative_putMaskNative
 538  (JNIEnv *env, jclass cls, jint drawable, jlong gc, jbyteArray imageData,
 539   jint sx, jint sy, jint dx, jint dy, jint width, jint height,
 540   jint maskOff, jint maskScan, jfloat ea, jlong imgPtr) {
 541 
 542     int line, pix;
 543     char *mask;
 544     char *defaultData;
 545     XImage *defaultImg, *img;
 546     jboolean imageFits;
 547 
 548     if ((mask = (char *)
 549          (*env)->GetPrimitiveArrayCritical(env, imageData, NULL)) == NULL) {
 550         return;
 551      }
 552 
 553     defaultImg = (XImage *) jlong_to_ptr(imgPtr);
 554 
 555     if (ea != 1.0f) {
 556         for (line=0; line < height; line++) {
 557             for (pix=0; pix < width; pix++) {
 558                 int index = maskScan*line + pix + maskOff;
 559                 mask[index] = (((unsigned char) mask[index])*ea);
 560             }
 561         }
 562     }
 563 
 564     /*
 565     * 1. If existing XImage and supplied buffer match, only adjust the data pointer
 566     * 2. If existing XImage is large enough to hold the data but does not match in
 567     *    scan the data is copied to fit the XImage.
 568     * 3. If data is larger than the existing XImage a new temporary XImage is
 569     *    allocated.
 570     * The default XImage is optimized for the AA tiles, which are currently 32x32.
 571     */
 572     defaultData = defaultImg->data;
 573     img = defaultImg;
 574     imageFits = defaultImg->width >= width && defaultImg->height >= height;
 575 
 576     if (imageFits &&
 577         maskOff == defaultImg->xoffset && maskScan == defaultImg->bytes_per_line) {
 578         defaultImg->data = mask;
 579     } else {
 580         if (imageFits) {
 581             for (line=0; line < height; line++) {
 582                 for (pix=0; pix < width; pix++) {
 583                     img->data[line*img->bytes_per_line + pix] =
 584                         (unsigned char) (mask[maskScan*line + pix + maskOff]);
 585                 }
 586             }
 587         } else {
 588             img = XCreateImage(awt_display, NULL, 8, ZPixmap,
 589                                maskOff, mask, maskScan, height, 8, 0);
 590         }
 591     }
 592 
 593     XPutImage(awt_display, (Pixmap) drawable, (GC) jlong_to_ptr(gc),
 594               img, 0, 0, 0, 0, width, height);
 595     (*env)->ReleasePrimitiveArrayCritical(env, imageData, mask, JNI_ABORT);
 596 
 597     if (img != defaultImg) {
 598         img->data = NULL;
 599         XDestroyImage(img);
 600     }
 601     defaultImg->data = defaultData;
 602 }
 603 
 604 JNIEXPORT void JNICALL
 605 Java_sun_java2d_xr_XRBackendNative_XRAddGlyphsNative
 606  (JNIEnv *env, jclass cls, jint glyphSet,
 607   jlongArray glyphInfoPtrsArray, jint glyphCnt,
 608   jbyteArray pixelDataArray, int pixelDataLength) {
 609     jlong *glyphInfoPtrs;
 610     unsigned char *pixelData;
 611     int i;
 612 
 613     XGlyphInfo *xginfo = (XGlyphInfo *) malloc(sizeof(XGlyphInfo) * glyphCnt);
 614     Glyph *gid = (Glyph *) malloc(sizeof(Glyph) * glyphCnt);
 615 
 616     if (xginfo == NULL || gid == NULL) {
 617         if (xginfo != NULL) {
 618             free(xginfo);
 619         }
 620         if (gid != NULL) {
 621             free(gid);
 622         }
 623         return;
 624     }
 625 
 626     if ((glyphInfoPtrs = (jlong *)(*env)->
 627         GetPrimitiveArrayCritical(env, glyphInfoPtrsArray, NULL)) == NULL)
 628     {
 629         free(xginfo);
 630         free(gid);
 631         return;
 632     }
 633 
 634     if ((pixelData = (unsigned char *)
 635         (*env)->GetPrimitiveArrayCritical(env, pixelDataArray, NULL)) == NULL)
 636     {
 637         (*env)->ReleasePrimitiveArrayCritical(env,
 638                                 glyphInfoPtrsArray, glyphInfoPtrs, JNI_ABORT);
 639         free(xginfo);
 640         free(gid);
 641         return;
 642     }
 643 
 644     for (i=0; i < glyphCnt; i++) {
 645       GlyphInfo *jginfo = (GlyphInfo *) jlong_to_ptr(glyphInfoPtrs[i]);
 646 
 647       gid[i] = (Glyph) (0xffffffff & ((unsigned int) jginfo->cellInfo));
 648       xginfo[i].x = (-jginfo->topLeftX);
 649       xginfo[i].y = (-jginfo->topLeftY);
 650       xginfo[i].width = jginfo->width;
 651       xginfo[i].height = jginfo->height;
 652       xginfo[i].xOff = round(jginfo->advanceX);
 653       xginfo[i].yOff = round(jginfo->advanceY);
 654     }
 655 
 656     XRenderAddGlyphs(awt_display, glyphSet, &gid[0], &xginfo[0], glyphCnt,
 657                      (const char*)pixelData, pixelDataLength);
 658 
 659     (*env)->ReleasePrimitiveArrayCritical(env, glyphInfoPtrsArray, glyphInfoPtrs, JNI_ABORT);
 660     (*env)->ReleasePrimitiveArrayCritical(env, pixelDataArray, pixelData, JNI_ABORT);
 661 
 662     free(xginfo);
 663     free(gid);
 664 }
 665 
 666 JNIEXPORT void JNICALL
 667 Java_sun_java2d_xr_XRBackendNative_XRFreeGlyphsNative
 668  (JNIEnv *env, jclass cls, jint glyphSet, jintArray gidArray, jint glyphCnt) {
 669     jint *gids;
 670     int i;
 671 
 672     if ((gids = (jint *) (*env)->GetPrimitiveArrayCritical(env, gidArray, NULL)) == NULL) {
 673         return;
 674     }
 675 
 676     XRenderFreeGlyphs (awt_display, (GlyphSet) glyphSet, (Glyph *) gids, glyphCnt);
 677 
 678     (*env)->ReleasePrimitiveArrayCritical(env, gidArray, gids, JNI_ABORT);
 679 }
 680 
 681 JNIEXPORT jint JNICALL
 682 Java_sun_java2d_xr_XRBackendNative_XRenderCreateGlyphSetNative
 683  (JNIEnv *env, jclass cls, jlong format) {
 684   return XRenderCreateGlyphSet(awt_display, (XRenderPictFormat *) jlong_to_ptr(format));
 685 }
 686 
 687 JNIEXPORT void JNICALL
 688 Java_sun_java2d_xr_XRBackendNative_XRenderCompositeTextNative
 689  (JNIEnv *env, jclass cls, jint op, jint src, jint dst, jlong maskFmt,
 690   jintArray eltArray, jintArray  glyphIDArray, jint eltCnt, jint glyphCnt) {
 691     jint i;
 692     jint *ids;
 693     jint *elts;
 694     XGlyphElt32 *xelts;
 695     Glyph *xids;
 696     XGlyphElt32 selts[24];
 697     Glyph sids[256];
 698     int charCnt = 0;
 699 
 700     if (eltCnt <= 24) {
 701       xelts = &selts[0];
 702     }else {
 703       xelts = (XGlyphElt32 *) malloc(sizeof(XGlyphElt32) * eltCnt);
 704       if (xelts == NULL) {
 705           return;
 706       }
 707     }
 708 
 709     if (glyphCnt <= 256) {
 710       xids = &sids[0];
 711     } else {
 712       xids = (Glyph *) malloc(sizeof(Glyph) * glyphCnt);
 713       if (xids == NULL) {
 714           if (xelts != &selts[0]) {
 715             free(xelts);
 716           }
 717           return;
 718       }
 719     }
 720 
 721     if ((ids = (jint *)
 722          (*env)->GetPrimitiveArrayCritical(env, glyphIDArray, NULL)) == NULL) {
 723         if (xelts != &selts[0]) {
 724             free(xelts);
 725         }
 726         if (xids != &sids[0]) {
 727             free(xids);
 728         }
 729         return;
 730     }
 731     if ((elts = (jint *)
 732           (*env)->GetPrimitiveArrayCritical(env, eltArray, NULL)) == NULL) {
 733         (*env)->ReleasePrimitiveArrayCritical(env,
 734                                               glyphIDArray, ids, JNI_ABORT);
 735         if (xelts != &selts[0]) {
 736             free(xelts);
 737         }
 738         if (xids != &sids[0]) {
 739             free(xids);
 740         }
 741         return;
 742     }
 743 
 744     for (i=0; i < glyphCnt; i++) {
 745       xids[i] = (Glyph) ids[i];
 746     }
 747 
 748     for (i=0; i < eltCnt; i++) {
 749       xelts[i].nchars = elts[i*4 + 0];
 750       xelts[i].xOff = elts[i*4 + 1];
 751       xelts[i].yOff = elts[i*4 + 2];
 752       xelts[i].glyphset = (GlyphSet) elts[i*4 + 3];
 753       xelts[i].chars = (unsigned int *) &xids[charCnt];
 754 
 755       charCnt += xelts[i].nchars;
 756     }
 757 
 758     XRenderCompositeText32(awt_display, op, (Picture) src, (Picture) dst,
 759                            (XRenderPictFormat *) jlong_to_ptr(maskFmt),
 760                             0, 0, 0, 0, xelts, eltCnt);
 761 
 762     (*env)->ReleasePrimitiveArrayCritical(env, glyphIDArray, ids, JNI_ABORT);
 763     (*env)->ReleasePrimitiveArrayCritical(env, eltArray, elts, JNI_ABORT);
 764 
 765     if (xelts != &selts[0]) {
 766         free(xelts);
 767     }
 768 
 769     if (xids != &sids[0]) {
 770         free(xids);
 771     }
 772 }
 773 
 774 JNIEXPORT void JNICALL
 775 Java_sun_java2d_xr_XRBackendNative_setGCMode
 776  (JNIEnv *env, jobject this, jlong gc, jboolean copy) {
 777   GC xgc = (GC) jlong_to_ptr(gc);
 778 
 779   if (copy == JNI_TRUE) {
 780     XSetFunction(awt_display, xgc, GXcopy);
 781   } else {
 782     XSetFunction(awt_display, xgc, GXxor);
 783   }
 784 }
 785 
 786 JNIEXPORT void JNICALL
 787 Java_sun_java2d_xr_XRBackendNative_GCRectanglesNative
 788  (JNIEnv *env, jclass xsd, jint dst, jlong gc,
 789   jintArray rectArray, jint rectCnt) {
 790     int i;
 791     jint* rects;
 792     XRectangle *xRects;
 793     XRectangle sRects[256];
 794 
 795     if (rectCnt <= 256) {
 796       xRects = &sRects[0];
 797     } else {
 798       xRects = (XRectangle *) malloc(sizeof(XRectangle) * rectCnt);
 799       if (xRects == NULL) {
 800         return;
 801       }
 802     }
 803 
 804     if ((rects = (jint*)
 805          (*env)->GetPrimitiveArrayCritical(env, rectArray, NULL)) == NULL) {
 806         if (xRects != &sRects[0]) {
 807             free(xRects);
 808         }
 809         return;
 810     }
 811 
 812     for (i=0; i < rectCnt; i++) {
 813       xRects[i].x = rects[i*4 + 0];
 814       xRects[i].y = rects[i*4 + 1];
 815       xRects[i].width = rects[i*4 + 2];
 816       xRects[i].height = rects[i*4 + 3];
 817     }
 818 
 819     XFillRectangles(awt_display, (Drawable) dst, (GC) jlong_to_ptr(gc), xRects, rectCnt);
 820 
 821     (*env)->ReleasePrimitiveArrayCritical(env, rectArray, rects, JNI_ABORT);
 822     if (xRects != &sRects[0]) {
 823       free(xRects);
 824     }
 825 }
 826 
 827 JNIEXPORT void JNICALL
 828 Java_sun_java2d_xr_XRBackendNative_renderCompositeTrapezoidsNative
 829  (JNIEnv *env, jclass cls, jbyte op, jint src, jlong maskFmt,
 830  jint dst, jint srcX, jint srcY, jintArray  trapArray) {
 831     jint *traps;
 832 
 833     if ((traps = (jint *) (*env)->GetPrimitiveArrayCritical(env, trapArray, NULL)) == NULL) {
 834       return;
 835     }
 836 
 837     XRenderCompositeTrapezoids(awt_display, op, (Picture) src, (Picture) dst,
 838                                (XRenderPictFormat *) jlong_to_ptr(maskFmt),
 839                                srcX, srcY, (XTrapezoid *) (traps+5), traps[0]);
 840 
 841     (*env)->ReleasePrimitiveArrayCritical(env, trapArray, traps, JNI_ABORT);
 842 }