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