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 #if (defined(__solaris__) || defined(AIX)) 72 /* Solaris 10 and AIX 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 #if (defined(__solaris__) || defined(AIX)) 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*' 746 // (see definition of 'GlyphInfo' in fontscalerdefs.h) 747 // 'Glyph' is typedefed to 'unsigned long' 748 // (see http://www.x.org/releases/X11R7.7/doc/libXrender/libXrender.txt) 749 // Maybe we should assert that (sizeof(void*) == sizeof(Glyph)) ? 750 gid[i] = (Glyph) (jginfo->cellInfo); 751 xginfo[i].x = (-jginfo->topLeftX); 752 xginfo[i].y = (-jginfo->topLeftY); 753 xginfo[i].width = jginfo->width; 754 xginfo[i].height = jginfo->height; 755 xginfo[i].xOff = round(jginfo->advanceX); 756 xginfo[i].yOff = round(jginfo->advanceY); 757 } 758 759 XRenderAddGlyphs(awt_display, glyphSet, &gid[0], &xginfo[0], glyphCnt, 760 (const char*)pixelData, pixelDataLength); 761 762 (*env)->ReleasePrimitiveArrayCritical(env, glyphInfoPtrsArray, glyphInfoPtrs, JNI_ABORT); 763 (*env)->ReleasePrimitiveArrayCritical(env, pixelDataArray, pixelData, JNI_ABORT); 764 765 free(xginfo); 766 free(gid); 767 } 768 769 JNIEXPORT void JNICALL 770 Java_sun_java2d_xr_XRBackendNative_XRFreeGlyphsNative 771 (JNIEnv *env, jclass cls, jint glyphSet, jintArray gidArray, jint glyphCnt) { 772 773 /* The glyph ids are 32 bit but may be stored in a 64 bit long on 774 * a 64 bit architecture. So optimise the 32 bit case to avoid 775 * extra stack or heap allocations by directly referencing the 776 * underlying Java array and only allocate on 64 bit. 777 */ 778 if (sizeof(jint) == sizeof(Glyph)) { 779 jint *gids = 780 (*env)->GetPrimitiveArrayCritical(env, gidArray, NULL); 781 if (gids == NULL) { 782 return; 783 } else { 784 XRenderFreeGlyphs(awt_display, 785 (GlyphSet)glyphSet, (Glyph *)gids, glyphCnt); 786 (*env)->ReleasePrimitiveArrayCritical(env, gidArray, 787 gids, JNI_ABORT); 788 } 789 return; 790 } else { 791 Glyph stack_ids[64]; 792 Glyph *gids = NULL; 793 jint* jgids = NULL; 794 int i; 795 796 if (glyphCnt <= 64) { 797 gids = stack_ids; 798 } else { 799 gids = (Glyph *)malloc(sizeof(Glyph) * glyphCnt); 800 if (gids == NULL) { 801 return; 802 } 803 } 804 jgids = (*env)->GetPrimitiveArrayCritical(env, gidArray, NULL); 805 if (jgids == NULL) { 806 if (gids != stack_ids) { 807 free(gids); 808 } 809 return; 810 } 811 for (i=0; i < glyphCnt; i++) { 812 gids[i] = jgids[i]; 813 } 814 XRenderFreeGlyphs(awt_display, 815 (GlyphSet) glyphSet, gids, glyphCnt); 816 (*env)->ReleasePrimitiveArrayCritical(env, gidArray, 817 jgids, JNI_ABORT); 818 if (gids != stack_ids) { 819 free(gids); 820 } 821 } 822 } 823 824 JNIEXPORT jint JNICALL 825 Java_sun_java2d_xr_XRBackendNative_XRenderCreateGlyphSetNative 826 (JNIEnv *env, jclass cls, jlong format) { 827 return XRenderCreateGlyphSet(awt_display, (XRenderPictFormat *) jlong_to_ptr(format)); 828 } 829 830 JNIEXPORT void JNICALL 831 Java_sun_java2d_xr_XRBackendNative_XRenderCompositeTextNative 832 (JNIEnv *env, jclass cls, jint op, jint src, jint dst, jlong maskFmt, 833 jintArray eltArray, jintArray glyphIDArray, jint eltCnt, jint glyphCnt) { 834 jint i; 835 jint *ids; 836 jint *elts; 837 XGlyphElt32 *xelts; 838 unsigned int *xids; 839 XGlyphElt32 selts[24]; 840 unsigned int sids[256]; 841 int charCnt = 0; 842 843 if (eltCnt <= 24) { 844 xelts = &selts[0]; 845 }else { 846 xelts = (XGlyphElt32 *) malloc(sizeof(XGlyphElt32) * eltCnt); 847 if (xelts == NULL) { 848 return; 849 } 850 } 851 852 if (glyphCnt <= 256) { 853 xids = &sids[0]; 854 } else { 855 xids = (unsigned int*)malloc(sizeof(unsigned int) * glyphCnt); 856 if (xids == NULL) { 857 if (xelts != &selts[0]) { 858 free(xelts); 859 } 860 return; 861 } 862 } 863 864 if ((ids = (jint *) 865 (*env)->GetPrimitiveArrayCritical(env, glyphIDArray, NULL)) == NULL) { 866 if (xelts != &selts[0]) { 867 free(xelts); 868 } 869 if (xids != &sids[0]) { 870 free(xids); 871 } 872 return; 873 } 874 if ((elts = (jint *) 875 (*env)->GetPrimitiveArrayCritical(env, eltArray, NULL)) == NULL) { 876 (*env)->ReleasePrimitiveArrayCritical(env, 877 glyphIDArray, ids, JNI_ABORT); 878 if (xelts != &selts[0]) { 879 free(xelts); 880 } 881 if (xids != &sids[0]) { 882 free(xids); 883 } 884 return; 885 } 886 887 for (i=0; i < glyphCnt; i++) { 888 xids[i] = ids[i]; 889 } 890 891 for (i=0; i < eltCnt; i++) { 892 xelts[i].nchars = elts[i*4 + 0]; 893 xelts[i].xOff = elts[i*4 + 1]; 894 xelts[i].yOff = elts[i*4 + 2]; 895 xelts[i].glyphset = (GlyphSet) elts[i*4 + 3]; 896 xelts[i].chars = &xids[charCnt]; 897 898 charCnt += xelts[i].nchars; 899 } 900 901 XRenderCompositeText32(awt_display, op, (Picture) src, (Picture) dst, 902 (XRenderPictFormat *) jlong_to_ptr(maskFmt), 903 0, 0, 0, 0, xelts, eltCnt); 904 905 (*env)->ReleasePrimitiveArrayCritical(env, glyphIDArray, ids, JNI_ABORT); 906 (*env)->ReleasePrimitiveArrayCritical(env, eltArray, elts, JNI_ABORT); 907 908 if (xelts != &selts[0]) { 909 free(xelts); 910 } 911 912 if (xids != &sids[0]) { 913 free(xids); 914 } 915 } 916 917 JNIEXPORT void JNICALL 918 Java_sun_java2d_xr_XRBackendNative_setGCMode 919 (JNIEnv *env, jobject this, jlong gc, jboolean copy) { 920 GC xgc = (GC) jlong_to_ptr(gc); 921 922 if (copy == JNI_TRUE) { 923 XSetFunction(awt_display, xgc, GXcopy); 924 } else { 925 XSetFunction(awt_display, xgc, GXxor); 926 } 927 } 928 929 JNIEXPORT void JNICALL 930 Java_sun_java2d_xr_XRBackendNative_GCRectanglesNative 931 (JNIEnv *env, jclass xsd, jint dst, jlong gc, 932 jintArray rectArray, jint rectCnt) { 933 int i; 934 jint* rects; 935 XRectangle *xRects; 936 XRectangle sRects[256]; 937 938 if (rectCnt <= 256) { 939 xRects = &sRects[0]; 940 } else { 941 xRects = (XRectangle *) malloc(sizeof(XRectangle) * rectCnt); 942 if (xRects == NULL) { 943 return; 944 } 945 } 946 947 if ((rects = (jint*) 948 (*env)->GetPrimitiveArrayCritical(env, rectArray, NULL)) == NULL) { 949 if (xRects != &sRects[0]) { 950 free(xRects); 951 } 952 return; 953 } 954 955 for (i=0; i < rectCnt; i++) { 956 xRects[i].x = rects[i*4 + 0]; 957 xRects[i].y = rects[i*4 + 1]; 958 xRects[i].width = rects[i*4 + 2]; 959 xRects[i].height = rects[i*4 + 3]; 960 } 961 962 XFillRectangles(awt_display, (Drawable) dst, (GC) jlong_to_ptr(gc), xRects, rectCnt); 963 964 (*env)->ReleasePrimitiveArrayCritical(env, rectArray, rects, JNI_ABORT); 965 if (xRects != &sRects[0]) { 966 free(xRects); 967 } 968 } 969 970 JNIEXPORT void JNICALL 971 Java_sun_java2d_xr_XRBackendNative_renderCompositeTrapezoidsNative 972 (JNIEnv *env, jclass cls, jbyte op, jint src, jlong maskFmt, 973 jint dst, jint srcX, jint srcY, jintArray trapArray) { 974 jint *traps; 975 976 if ((traps = (jint *) (*env)->GetPrimitiveArrayCritical(env, trapArray, NULL)) == NULL) { 977 return; 978 } 979 980 XRenderCompositeTrapezoids(awt_display, op, (Picture) src, (Picture) dst, 981 (XRenderPictFormat *) jlong_to_ptr(maskFmt), 982 srcX, srcY, (XTrapezoid *) (traps+5), traps[0]); 983 984 (*env)->ReleasePrimitiveArrayCritical(env, trapArray, traps, JNI_ABORT); 985 }