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 335 JNIEXPORT void JNICALL 336 Java_sun_java2d_xr_XRBackendNative_initIDs(JNIEnv *env, jclass cls) { 337 char *maskData; 338 XImage* defaultImg; 339 jfieldID maskImgID; 340 jlong fmt8; 341 jlong fmt32; 342 343 jfieldID a8ID = (*env)->GetStaticFieldID(env, cls, "FMTPTR_A8", "J"); 344 if (a8ID == NULL) { 345 return; 346 } 347 jfieldID argb32ID = (*env)->GetStaticFieldID(env, cls, "FMTPTR_ARGB32", "J"); 348 if (argb32ID == NULL) { 349 return; 350 } 351 352 if (awt_display == (Display *)NULL) { 353 return; 354 } 355 356 fmt8 = ptr_to_jlong(XRenderFindStandardFormat(awt_display, PictStandardA8)); 357 fmt32 = ptr_to_jlong(XRenderFindStandardFormat(awt_display, PictStandardARGB32)); 358 359 (*env)->SetStaticLongField(env, cls, a8ID, fmt8); 360 (*env)->SetStaticLongField(env, cls, argb32ID, fmt32); 361 362 maskData = (char *) malloc(32*32); 363 if (maskData == NULL) { 364 return; 365 } 366 367 defaultImg = XCreateImage(awt_display, NULL, 8, ZPixmap, 0, maskData, 32, 32, 8, 0); 368 defaultImg->data = maskData; //required? 369 maskImgID = (*env)->GetStaticFieldID(env, cls, "MASK_XIMG", "J"); 370 if (maskImgID == NULL) { 371 return; 372 } 373 374 (*env)->SetStaticLongField(env, cls, maskImgID, ptr_to_jlong(defaultImg)); 375 } 376 377 JNIEXPORT void JNICALL 378 Java_sun_java2d_xr_XRBackendNative_freeGC 379 (JNIEnv *env, jobject this, jlong gc) { 380 XFreeGC(awt_display, (GC) jlong_to_ptr(gc)); 381 } 382 383 JNIEXPORT jlong JNICALL 384 Java_sun_java2d_xr_XRBackendNative_createGC 385 (JNIEnv *env, jobject this, jint drawable) { 386 GC xgc = XCreateGC(awt_display, (Drawable) drawable, 0L, NULL); 387 return ptr_to_jlong(xgc); 388 } 389 390 JNIEXPORT jint JNICALL 391 Java_sun_java2d_xr_XRBackendNative_createPixmap(JNIEnv *env, jobject this, 392 jint drawable, jint depth, 393 jint width, jint height) { 394 return (jint) XCreatePixmap(awt_display, (Drawable) drawable, 395 width, height, depth); 396 } 397 398 JNIEXPORT jint JNICALL 399 Java_sun_java2d_xr_XRBackendNative_createPictureNative 400 (JNIEnv *env, jclass cls, jint drawable, jlong formatPtr) { 401 XRenderPictureAttributes pict_attr; 402 return XRenderCreatePicture(awt_display, (Drawable) drawable, 403 (XRenderPictFormat *) jlong_to_ptr(formatPtr), 404 0, &pict_attr); 405 } 406 407 JNIEXPORT void JNICALL 408 Java_sun_java2d_xr_XRBackendNative_freePicture 409 (JNIEnv *env, jobject this, jint picture) { 410 XRenderFreePicture(awt_display, (Picture) picture); 411 } 412 413 JNIEXPORT void JNICALL 414 Java_sun_java2d_xr_XRBackendNative_freePixmap 415 (JNIEnv *env, jobject this, jint pixmap) { 416 XFreePixmap(awt_display, (Pixmap) pixmap); 417 } 418 419 JNIEXPORT void JNICALL 420 Java_sun_java2d_xr_XRBackendNative_setPictureRepeat 421 (JNIEnv *env, jobject this, jint picture, jint repeat) { 422 XRenderPictureAttributes pict_attr; 423 pict_attr.repeat = repeat; 424 XRenderChangePicture (awt_display, (Picture) picture, CPRepeat, &pict_attr); 425 } 426 427 428 JNIEXPORT void JNICALL 429 Java_sun_java2d_xr_XRBackendNative_setGCExposures 430 (JNIEnv *env, jobject this, jlong gc, jboolean exposure) { 431 XSetGraphicsExposures(awt_display, 432 (GC) jlong_to_ptr(gc), exposure ? True : False); //TODO: ???? 433 } 434 435 JNIEXPORT void JNICALL 436 Java_sun_java2d_xr_XRBackendNative_setGCForeground 437 (JNIEnv *env, jobject this, jlong gc, jint pixel) { 438 XSetForeground(awt_display, (GC) jlong_to_ptr(gc), (unsigned long) pixel); 439 } 440 441 442 JNIEXPORT void JNICALL 443 Java_sun_java2d_xr_XRBackendNative_copyArea 444 (JNIEnv *env, jobject this, jint src, jint dst, jlong gc, 445 jint srcx, jint srcy, jint width, jint height, jint dstx, jint dsty) { 446 XCopyArea(awt_display, (Drawable) src, (Drawable) dst, 447 (GC) jlong_to_ptr(gc), srcx, srcy, width, height, dstx, dsty); 448 } 449 450 JNIEXPORT void JNICALL 451 Java_sun_java2d_xr_XRBackendNative_renderComposite 452 (JNIEnv *env, jobject this, jbyte op, jint src, jint mask, jint dst, 453 jint srcX, jint srcY, jint maskX, jint maskY, 454 jint dstX, jint dstY, jint width, jint height) { 455 XRenderComposite (awt_display, op, 456 (Picture)src, (Picture)mask, (Picture)dst, 457 srcX, srcY, maskX, maskY, dstX, dstY, width, height); 458 } 459 460 JNIEXPORT void JNICALL 461 Java_sun_java2d_xr_XRBackendNative_renderRectangle 462 (JNIEnv *env, jobject this, jint dst, jbyte op, 463 jshort red, jshort green, jshort blue, jshort alpha, 464 jint x, jint y, jint width, jint height) { 465 XRenderColor color; 466 color.alpha = alpha; 467 color.red = red; 468 color.green = green; 469 color.blue = blue; 470 XRenderFillRectangle(awt_display, op, (Picture) dst, &color, 471 x, y, width, height); 472 } 473 474 JNIEXPORT void JNICALL 475 Java_sun_java2d_xr_XRBackendNative_XRenderRectanglesNative 476 (JNIEnv *env, jclass xsd, jint dst, jbyte op, 477 jshort red, jshort green, jshort blue, jshort alpha, 478 jintArray rectArray, jint rectCnt) { 479 int i; 480 jint* rects; 481 XRectangle *xRects; 482 XRectangle sRects[256]; 483 484 XRenderColor color; 485 color.alpha = alpha; 486 color.red = red; 487 color.green = green; 488 color.blue = blue; 489 490 if (rectCnt <= 256) { 491 xRects = &sRects[0]; 492 } else { 493 if (MAXUINT / sizeof(XRectangle) < (unsigned)rectCnt) { 494 /* rectCnt too big, integer overflow */ 495 return; 496 } 497 xRects = (XRectangle *) malloc(sizeof(XRectangle) * rectCnt); 498 if (xRects == NULL) { 499 return; 500 } 501 } 502 503 if ((rects = (jint *) 504 (*env)->GetPrimitiveArrayCritical(env, rectArray, NULL)) == NULL) { 505 if (xRects != &sRects[0]) { 506 free(xRects); 507 } 508 return; 509 } 510 511 for (i=0; i < rectCnt; i++) { 512 xRects[i].x = rects[i*4 + 0]; 513 xRects[i].y = rects[i*4 + 1]; 514 xRects[i].width = rects[i*4 + 2]; 515 xRects[i].height = rects[i*4 + 3]; 516 } 517 518 XRenderFillRectangles(awt_display, op, 519 (Picture) dst, &color, xRects, rectCnt); 520 521 (*env)->ReleasePrimitiveArrayCritical(env, rectArray, rects, JNI_ABORT); 522 if (xRects != &sRects[0]) { 523 free(xRects); 524 } 525 } 526 527 JNIEXPORT void JNICALL 528 Java_sun_java2d_xr_XRBackendNative_XRSetTransformNative 529 (JNIEnv *env, jclass xsd, jint pic, 530 jint m00, jint m01, jint m02, jint m10, jint m11, jint m12) { 531 532 XTransform tr; 533 BUILD_TRANSFORM_MATRIX(tr, m00, m01, m02, m10, m11, m12); 534 XRenderSetPictureTransform (awt_display, (Picture) pic, &tr); 535 } 536 537 JNIEXPORT jint JNICALL 538 Java_sun_java2d_xr_XRBackendNative_XRCreateLinearGradientPaintNative 539 (JNIEnv *env, jclass xsd, jfloatArray fractionsArray, 540 jshortArray pixelsArray, jint x1, jint y1, jint x2, jint y2, 541 jint numStops, jint repeat) { 542 jint i; 543 jshort* pixels; 544 jfloat* fractions; 545 XRenderPictureAttributes pict_attr; 546 Picture gradient = 0; 547 XRenderColor *colors; 548 XFixed *stops; 549 XLinearGradient grad; 550 551 if (MAX_PAYLOAD / (sizeof(XRenderColor) + sizeof(XFixed)) 552 < (unsigned)numStops) { 553 /* numStops too big, payload overflow */ 554 return -1; 555 } 556 557 if ((pixels = (jshort *) 558 (*env)->GetPrimitiveArrayCritical(env, pixelsArray, NULL)) == NULL) { 559 return -1; 560 } 561 if ((fractions = (jfloat *) 562 (*env)->GetPrimitiveArrayCritical(env, fractionsArray, NULL)) == NULL) { 563 (*env)->ReleasePrimitiveArrayCritical(env, 564 pixelsArray, pixels, JNI_ABORT); 565 return -1; 566 } 567 568 grad.p1.x = x1; 569 grad.p1.y = y1; 570 grad.p2.x = x2; 571 grad.p2.y = y2; 572 573 /*TODO optimized & malloc check*/ 574 colors = (XRenderColor *) malloc(numStops * sizeof(XRenderColor)); 575 stops = (XFixed *) malloc(numStops * sizeof(XFixed)); 576 577 if (colors == NULL || stops == NULL) { 578 if (colors != NULL) { 579 free(colors); 580 } 581 if (stops != NULL) { 582 free(stops); 583 } 584 (*env)->ReleasePrimitiveArrayCritical(env, pixelsArray, pixels, JNI_ABORT); 585 (*env)->ReleasePrimitiveArrayCritical(env, fractionsArray, fractions, JNI_ABORT); 586 return -1; 587 } 588 589 for (i=0; i < numStops; i++) { 590 stops[i] = XDoubleToFixed(fractions[i]); 591 colors[i].alpha = pixels[i*4 + 0]; 592 colors[i].red = pixels[i*4 + 1]; 593 colors[i].green = pixels[i*4 + 2]; 594 colors[i].blue = pixels[i*4 + 3]; 595 } 596 #ifdef __solaris__ 597 if (XRenderCreateLinearGradientFunc!=NULL) { 598 gradient = (*XRenderCreateLinearGradientFunc)(awt_display, &grad, stops, colors, numStops); 599 } 600 #else 601 gradient = XRenderCreateLinearGradient(awt_display, &grad, stops, colors, numStops); 602 #endif 603 free(colors); 604 free(stops); 605 606 (*env)->ReleasePrimitiveArrayCritical(env, pixelsArray, pixels, JNI_ABORT); 607 (*env)->ReleasePrimitiveArrayCritical(env, fractionsArray, fractions, JNI_ABORT); 608 609 if (gradient != 0) { 610 pict_attr.repeat = repeat; 611 XRenderChangePicture (awt_display, gradient, CPRepeat, &pict_attr); 612 } 613 614 return (jint) gradient; 615 } 616 617 618 JNIEXPORT jint JNICALL 619 Java_sun_java2d_xr_XRBackendNative_XRCreateRadialGradientPaintNative 620 (JNIEnv *env, jclass xsd, jfloatArray fractionsArray, 621 jshortArray pixelsArray, jint numStops, 622 jint centerX, jint centerY, 623 jint innerRadius, jint outerRadius, jint repeat) { 624 jint i; 625 jshort* pixels; 626 jfloat* fractions; 627 XRenderPictureAttributes pict_attr; 628 Picture gradient = 0; 629 XRenderColor *colors; 630 XFixed *stops; 631 XRadialGradient grad; 632 633 if (MAX_PAYLOAD / (sizeof(XRenderColor) + sizeof(XFixed)) 634 < (unsigned)numStops) { 635 /* numStops too big, payload overflow */ 636 return -1; 637 } 638 639 if ((pixels = 640 (jshort *)(*env)->GetPrimitiveArrayCritical(env, pixelsArray, NULL)) == NULL) { 641 return -1; 642 } 643 if ((fractions = (jfloat *) 644 (*env)->GetPrimitiveArrayCritical(env, fractionsArray, NULL)) == NULL) { 645 (*env)->ReleasePrimitiveArrayCritical(env, 646 pixelsArray, pixels, JNI_ABORT); 647 return -1; //TODO release pixels first 648 } 649 650 grad.inner.x = centerX; 651 grad.inner.y = centerY; 652 grad.inner.radius = innerRadius; 653 grad.outer.x = centerX; 654 grad.outer.y = centerY; 655 grad.outer.radius = outerRadius; 656 657 /*TODO optimized & malloc check*/ 658 colors = (XRenderColor *) malloc(numStops * sizeof(XRenderColor)); 659 stops = (XFixed *) malloc(numStops * sizeof(XFixed)); 660 661 if (colors == NULL || stops == NULL) { 662 if (colors != NULL) { 663 free(colors); 664 } 665 if (stops != NULL) { 666 free(stops); 667 } 668 (*env)->ReleasePrimitiveArrayCritical(env, pixelsArray, pixels, JNI_ABORT); 669 (*env)->ReleasePrimitiveArrayCritical(env, fractionsArray, fractions, JNI_ABORT); 670 return -1; 671 } 672 673 for (i=0; i < numStops; i++) { 674 stops[i] = XDoubleToFixed(fractions[i]); 675 colors[i].alpha = pixels[i*4 + 0]; 676 colors[i].red = pixels[i*4 + 1]; 677 colors[i].green = pixels[i*4 + 2]; 678 colors[i].blue = pixels[i*4 + 3]; 679 } 680 #ifdef __solaris__ 681 if (XRenderCreateRadialGradientFunc != NULL) { 682 gradient = (jint) (*XRenderCreateRadialGradientFunc)(awt_display, &grad, stops, colors, numStops); 683 } 684 #else 685 gradient = (jint) XRenderCreateRadialGradient(awt_display, &grad, stops, colors, numStops); 686 #endif 687 free(colors); 688 free(stops); 689 690 (*env)->ReleasePrimitiveArrayCritical(env, pixelsArray, pixels, JNI_ABORT); 691 (*env)->ReleasePrimitiveArrayCritical(env, fractionsArray, fractions, JNI_ABORT); 692 693 694 if (gradient != 0) { 695 pict_attr.repeat = repeat; 696 XRenderChangePicture (awt_display, gradient, CPRepeat, &pict_attr); 697 } 698 699 return (jint) gradient; 700 } 701 702 JNIEXPORT void JNICALL 703 Java_sun_java2d_xr_XRBackendNative_setFilter 704 (JNIEnv *env, jobject this, jint picture, jint filter) { 705 706 char * filterName = "fast"; 707 708 switch(filter) { 709 case 0: 710 filterName = "fast"; 711 break; 712 713 case 1: 714 filterName = "good"; 715 break; 716 717 case 2: 718 filterName = "best"; 719 break; 720 } 721 722 XRenderSetPictureFilter(awt_display, (Picture) picture, filterName, NULL, 0); 723 } 724 725 JNIEXPORT void JNICALL 726 Java_sun_java2d_xr_XRBackendNative_XRSetClipNative 727 (JNIEnv *env, jclass xsd, jlong dst, 728 jint x1, jint y1, jint x2, jint y2, 729 jobject complexclip, jboolean isGC) 730 { 731 int numrects; 732 XRectangle rects[256]; 733 XRectangle *pRect = rects; 734 735 numrects = RegionToYXBandedRectangles(env, 736 x1, y1, x2, y2, complexclip, 737 &pRect, 256); 738 739 if (isGC == JNI_TRUE) { 740 if (dst != (jlong) 0) { 741 XSetClipRectangles(awt_display, (GC) jlong_to_ptr(dst), 0, 0, pRect, numrects, YXBanded); 742 } 743 } else { 744 XRenderSetPictureClipRectangles (awt_display, (Picture) dst, 0, 0, pRect, numrects); 745 } 746 747 if (pRect != rects) { 748 free(pRect); 749 } 750 } 751 752 JNIEXPORT void JNICALL 753 Java_sun_java2d_xr_XRBackendNative_putMaskNative 754 (JNIEnv *env, jclass cls, jint drawable, jlong gc, jbyteArray imageData, 755 jint sx, jint sy, jint dx, jint dy, jint width, jint height, 756 jint maskOff, jint maskScan, jfloat ea, jlong imgPtr) { 757 758 int line, pix; 759 char *mask; 760 char *defaultData; 761 XImage *defaultImg, *img; 762 jboolean imageFits; 763 764 if ((mask = (char *) 765 (*env)->GetPrimitiveArrayCritical(env, imageData, NULL)) == NULL) { 766 return; 767 } 768 769 defaultImg = (XImage *) jlong_to_ptr(imgPtr); 770 771 if (ea != 1.0f) { 772 for (line=0; line < height; line++) { 773 for (pix=0; pix < width; pix++) { 774 int index = maskScan*line + pix + maskOff; 775 mask[index] = (((unsigned char) mask[index])*ea); 776 } 777 } 778 } 779 780 /* 781 * 1. If existing XImage and supplied buffer match, only adjust the data pointer 782 * 2. If existing XImage is large enough to hold the data but does not match in 783 * scan the data is copied to fit the XImage. 784 * 3. If data is larger than the existing XImage a new temporary XImage is 785 * allocated. 786 * The default XImage is optimized for the AA tiles, which are currently 32x32. 787 */ 788 defaultData = defaultImg->data; 789 img = defaultImg; 790 imageFits = defaultImg->width >= width && defaultImg->height >= height; 791 792 if (imageFits && 793 maskOff == defaultImg->xoffset && maskScan == defaultImg->bytes_per_line) { 794 defaultImg->data = mask; 795 } else { 796 if (imageFits) { 797 for (line=0; line < height; line++) { 798 for (pix=0; pix < width; pix++) { 799 img->data[line*img->bytes_per_line + pix] = 800 (unsigned char) (mask[maskScan*line + pix + maskOff]); 801 } 802 } 803 } else { 804 img = XCreateImage(awt_display, NULL, 8, ZPixmap, 805 maskOff, mask, maskScan, height, 8, 0); 806 } 807 } 808 809 XPutImage(awt_display, (Pixmap) drawable, (GC) jlong_to_ptr(gc), 810 img, 0, 0, 0, 0, width, height); 811 (*env)->ReleasePrimitiveArrayCritical(env, imageData, mask, JNI_ABORT); 812 813 if (img != defaultImg) { 814 img->data = NULL; 815 XDestroyImage(img); 816 } 817 defaultImg->data = defaultData; 818 } 819 820 JNIEXPORT void JNICALL 821 Java_sun_java2d_xr_XRBackendNative_XRAddGlyphsNative 822 (JNIEnv *env, jclass cls, jint glyphSet, 823 jlongArray glyphInfoPtrsArray, jint glyphCnt, 824 jbyteArray pixelDataArray, int pixelDataLength) { 825 jlong *glyphInfoPtrs; 826 unsigned char *pixelData; 827 int i; 828 829 if (MAX_PAYLOAD / (sizeof(XGlyphInfo) + sizeof(Glyph)) 830 < (unsigned)glyphCnt) { 831 /* glyphCnt too big, payload overflow */ 832 return; 833 } 834 835 XGlyphInfo *xginfo = (XGlyphInfo *) malloc(sizeof(XGlyphInfo) * glyphCnt); 836 Glyph *gid = (Glyph *) malloc(sizeof(Glyph) * glyphCnt); 837 838 if (xginfo == NULL || gid == NULL) { 839 if (xginfo != NULL) { 840 free(xginfo); 841 } 842 if (gid != NULL) { 843 free(gid); 844 } 845 return; 846 } 847 848 if ((glyphInfoPtrs = (jlong *)(*env)-> 849 GetPrimitiveArrayCritical(env, glyphInfoPtrsArray, NULL)) == NULL) 850 { 851 free(xginfo); 852 free(gid); 853 return; 854 } 855 856 if ((pixelData = (unsigned char *) 857 (*env)->GetPrimitiveArrayCritical(env, pixelDataArray, NULL)) == NULL) 858 { 859 (*env)->ReleasePrimitiveArrayCritical(env, 860 glyphInfoPtrsArray, glyphInfoPtrs, JNI_ABORT); 861 free(xginfo); 862 free(gid); 863 return; 864 } 865 866 for (i=0; i < glyphCnt; i++) { 867 GlyphInfo *jginfo = (GlyphInfo *) jlong_to_ptr(glyphInfoPtrs[i]); 868 869 // 'jginfo->cellInfo' is of type 'void*' 870 // (see definition of 'GlyphInfo' in fontscalerdefs.h) 871 // 'Glyph' is typedefed to 'unsigned long' 872 // (see http://www.x.org/releases/X11R7.7/doc/libXrender/libXrender.txt) 873 // Maybe we should assert that (sizeof(void*) == sizeof(Glyph)) ? 874 gid[i] = (Glyph) (jginfo->cellInfo); 875 xginfo[i].x = (-jginfo->topLeftX); 876 xginfo[i].y = (-jginfo->topLeftY); 877 xginfo[i].width = jginfo->width; 878 xginfo[i].height = jginfo->height; 879 xginfo[i].xOff = round(jginfo->advanceX); 880 xginfo[i].yOff = round(jginfo->advanceY); 881 } 882 883 XRenderAddGlyphs(awt_display, glyphSet, &gid[0], &xginfo[0], glyphCnt, 884 (const char*)pixelData, pixelDataLength); 885 886 (*env)->ReleasePrimitiveArrayCritical(env, glyphInfoPtrsArray, glyphInfoPtrs, JNI_ABORT); 887 (*env)->ReleasePrimitiveArrayCritical(env, pixelDataArray, pixelData, JNI_ABORT); 888 889 free(xginfo); 890 free(gid); 891 } 892 893 JNIEXPORT void JNICALL 894 Java_sun_java2d_xr_XRBackendNative_XRFreeGlyphsNative 895 (JNIEnv *env, jclass cls, jint glyphSet, jintArray gidArray, jint glyphCnt) { 896 897 if (MAX_PAYLOAD / sizeof(Glyph) < (unsigned)glyphCnt) { 898 /* glyphCnt too big, payload overflow */ 899 return; 900 } 901 902 /* The glyph ids are 32 bit but may be stored in a 64 bit long on 903 * a 64 bit architecture. So optimise the 32 bit case to avoid 904 * extra stack or heap allocations by directly referencing the 905 * underlying Java array and only allocate on 64 bit. 906 */ 907 if (sizeof(jint) == sizeof(Glyph)) { 908 jint *gids = 909 (*env)->GetPrimitiveArrayCritical(env, gidArray, NULL); 910 if (gids == NULL) { 911 return; 912 } else { 913 XRenderFreeGlyphs(awt_display, 914 (GlyphSet)glyphSet, (Glyph *)gids, glyphCnt); 915 (*env)->ReleasePrimitiveArrayCritical(env, gidArray, 916 gids, JNI_ABORT); 917 } 918 return; 919 } else { 920 Glyph stack_ids[64]; 921 Glyph *gids = NULL; 922 jint* jgids = NULL; 923 int i; 924 925 if (glyphCnt <= 64) { 926 gids = stack_ids; 927 } else { 928 gids = (Glyph *)malloc(sizeof(Glyph) * glyphCnt); 929 if (gids == NULL) { 930 return; 931 } 932 } 933 jgids = (*env)->GetPrimitiveArrayCritical(env, gidArray, NULL); 934 if (jgids == NULL) { 935 if (gids != stack_ids) { 936 free(gids); 937 } 938 return; 939 } 940 for (i=0; i < glyphCnt; i++) { 941 gids[i] = jgids[i]; 942 } 943 XRenderFreeGlyphs(awt_display, 944 (GlyphSet) glyphSet, gids, glyphCnt); 945 (*env)->ReleasePrimitiveArrayCritical(env, gidArray, 946 jgids, JNI_ABORT); 947 if (gids != stack_ids) { 948 free(gids); 949 } 950 } 951 } 952 953 JNIEXPORT jint JNICALL 954 Java_sun_java2d_xr_XRBackendNative_XRenderCreateGlyphSetNative 955 (JNIEnv *env, jclass cls, jlong format) { 956 return XRenderCreateGlyphSet(awt_display, (XRenderPictFormat *) jlong_to_ptr(format)); 957 } 958 959 JNIEXPORT void JNICALL 960 Java_sun_java2d_xr_XRBackendNative_XRenderCompositeTextNative 961 (JNIEnv *env, jclass cls, jint op, jint src, jint dst, 962 jint sx, jint sy, jlong maskFmt, jintArray eltArray, 963 jintArray glyphIDArray, jint eltCnt, jint glyphCnt) { 964 jint i; 965 jint *ids; 966 jint *elts; 967 XGlyphElt32 *xelts; 968 unsigned int *xids; 969 XGlyphElt32 selts[24]; 970 unsigned int sids[256]; 971 int charCnt = 0; 972 973 if ((MAX_PAYLOAD / sizeof(XGlyphElt32) < (unsigned)eltCnt) 974 || (MAX_PAYLOAD / sizeof(unsigned int) < (unsigned)glyphCnt) 975 || ((MAX_PAYLOAD - sizeof(XGlyphElt32)*(unsigned)eltCnt) / 976 sizeof(unsigned int) < (unsigned)glyphCnt)) 977 { 978 /* (eltCnt, glyphCnt) too big, payload overflow */ 979 return; 980 } 981 982 if (eltCnt <= 24) { 983 xelts = &selts[0]; 984 }else { 985 xelts = (XGlyphElt32 *) malloc(sizeof(XGlyphElt32) * eltCnt); 986 if (xelts == NULL) { 987 return; 988 } 989 } 990 991 if (glyphCnt <= 256) { 992 xids = &sids[0]; 993 } else { 994 xids = (unsigned int*)malloc(sizeof(unsigned int) * glyphCnt); 995 if (xids == NULL) { 996 if (xelts != &selts[0]) { 997 free(xelts); 998 } 999 return; 1000 } 1001 } 1002 1003 if ((ids = (jint *) 1004 (*env)->GetPrimitiveArrayCritical(env, glyphIDArray, NULL)) == NULL) { 1005 if (xelts != &selts[0]) { 1006 free(xelts); 1007 } 1008 if (xids != &sids[0]) { 1009 free(xids); 1010 } 1011 return; 1012 } 1013 if ((elts = (jint *) 1014 (*env)->GetPrimitiveArrayCritical(env, eltArray, NULL)) == NULL) { 1015 (*env)->ReleasePrimitiveArrayCritical(env, 1016 glyphIDArray, ids, JNI_ABORT); 1017 if (xelts != &selts[0]) { 1018 free(xelts); 1019 } 1020 if (xids != &sids[0]) { 1021 free(xids); 1022 } 1023 return; 1024 } 1025 1026 for (i=0; i < glyphCnt; i++) { 1027 xids[i] = ids[i]; 1028 } 1029 1030 for (i=0; i < eltCnt; i++) { 1031 xelts[i].nchars = elts[i*4 + 0]; 1032 xelts[i].xOff = elts[i*4 + 1]; 1033 xelts[i].yOff = elts[i*4 + 2]; 1034 xelts[i].glyphset = (GlyphSet) elts[i*4 + 3]; 1035 xelts[i].chars = &xids[charCnt]; 1036 1037 charCnt += xelts[i].nchars; 1038 } 1039 1040 XRenderCompositeText32(awt_display, op, (Picture) src, (Picture) dst, 1041 (XRenderPictFormat *) jlong_to_ptr(maskFmt), 1042 sx, sy, 0, 0, xelts, eltCnt); 1043 1044 (*env)->ReleasePrimitiveArrayCritical(env, glyphIDArray, ids, JNI_ABORT); 1045 (*env)->ReleasePrimitiveArrayCritical(env, eltArray, elts, JNI_ABORT); 1046 1047 if (xelts != &selts[0]) { 1048 free(xelts); 1049 } 1050 1051 if (xids != &sids[0]) { 1052 free(xids); 1053 } 1054 } 1055 1056 JNIEXPORT void JNICALL 1057 Java_sun_java2d_xr_XRBackendNative_setGCMode 1058 (JNIEnv *env, jobject this, jlong gc, jboolean copy) { 1059 GC xgc = (GC) jlong_to_ptr(gc); 1060 1061 if (copy == JNI_TRUE) { 1062 XSetFunction(awt_display, xgc, GXcopy); 1063 } else { 1064 XSetFunction(awt_display, xgc, GXxor); 1065 } 1066 } 1067 1068 JNIEXPORT void JNICALL 1069 Java_sun_java2d_xr_XRBackendNative_GCRectanglesNative 1070 (JNIEnv *env, jclass xsd, jint dst, jlong gc, 1071 jintArray rectArray, jint rectCnt) { 1072 int i; 1073 jint* rects; 1074 XRectangle *xRects; 1075 XRectangle sRects[256]; 1076 1077 if (rectCnt <= 256) { 1078 xRects = &sRects[0]; 1079 } else { 1080 if (MAXUINT / sizeof(XRectangle) < (unsigned)rectCnt) { 1081 /* rectCnt too big, integer overflow */ 1082 return; 1083 } 1084 1085 xRects = (XRectangle *) malloc(sizeof(XRectangle) * rectCnt); 1086 if (xRects == NULL) { 1087 return; 1088 } 1089 } 1090 1091 if ((rects = (jint*) 1092 (*env)->GetPrimitiveArrayCritical(env, rectArray, NULL)) == NULL) { 1093 if (xRects != &sRects[0]) { 1094 free(xRects); 1095 } 1096 return; 1097 } 1098 1099 for (i=0; i < rectCnt; i++) { 1100 xRects[i].x = rects[i*4 + 0]; 1101 xRects[i].y = rects[i*4 + 1]; 1102 xRects[i].width = rects[i*4 + 2]; 1103 xRects[i].height = rects[i*4 + 3]; 1104 } 1105 1106 XFillRectangles(awt_display, (Drawable) dst, (GC) jlong_to_ptr(gc), xRects, rectCnt); 1107 1108 (*env)->ReleasePrimitiveArrayCritical(env, rectArray, rects, JNI_ABORT); 1109 if (xRects != &sRects[0]) { 1110 free(xRects); 1111 } 1112 }