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