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