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