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