1 /* 2 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 #include "X11SurfaceData.h" 27 #include <jni.h> 28 #include <math.h> 29 #include "Region.h" 30 #include "fontscalerdefs.h" 31 32 #include <X11/extensions/Xrender.h> 33 34 #ifdef __linux__ 35 #include <sys/utsname.h> 36 #endif 37 38 /* On Solaris 10 updates 8, 9, the render.h file defines these 39 * protocol values but does not define the structs in Xrender.h. 40 * Thus in order to get these always defined on Solaris 10 41 * we will undefine the symbols if we have determined via the 42 * makefiles that Xrender.h is lacking the structs. This will 43 * trigger providing our own definitions as on earlier updates. 44 * We could assume that *all* Solaris 10 update versions will lack the updated 45 * Xrender.h and do this based solely on O/S being any 5.10 version, but this 46 * could still change and we'd be broken again as we'd be re-defining them. 47 */ 48 #ifdef SOLARIS10_NO_XRENDER_STRUCTS 49 #undef X_RenderCreateLinearGradient 50 #undef X_RenderCreateRadialGradient 51 #endif 52 53 #ifndef X_RenderCreateLinearGradient 54 typedef struct _XLinearGradient { 55 XPointFixed p1; 56 XPointFixed p2; 57 } XLinearGradient; 58 #endif 59 60 #ifndef X_RenderCreateRadialGradient 61 typedef struct _XCircle { 62 XFixed x; 63 XFixed y; 64 XFixed radius; 65 } XCircle; 66 67 typedef struct _XRadialGradient { 68 XCircle inner; 69 XCircle outer; 70 } XRadialGradient; 71 #endif 72 73 #include <dlfcn.h> 74 75 #if defined(__solaris__) || defined(_AIX) 76 /* Solaris 10 and AIX 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 #if defined(__solaris__) || defined(_AIX) 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 i; 528 jshort* pixels; 529 jfloat* fractions; 530 XRenderPictureAttributes pict_attr; 531 Picture gradient = 0; 532 XRenderColor *colors; 533 XFixed *stops; 534 XLinearGradient grad; 535 536 if (MAX_PAYLOAD / (sizeof(XRenderColor) + sizeof(XFixed)) 537 < (unsigned)numStops) { 538 /* numStops too big, payload overflow */ 539 return -1; 540 } 541 542 if ((pixels = (jshort *) 543 (*env)->GetPrimitiveArrayCritical(env, pixelsArray, NULL)) == NULL) { 544 return -1; 545 } 546 if ((fractions = (jfloat *) 547 (*env)->GetPrimitiveArrayCritical(env, fractionsArray, NULL)) == NULL) { 548 (*env)->ReleasePrimitiveArrayCritical(env, 549 pixelsArray, pixels, JNI_ABORT); 550 return -1; 551 } 552 553 grad.p1.x = x1; 554 grad.p1.y = y1; 555 grad.p2.x = x2; 556 grad.p2.y = y2; 557 558 /*TODO optimized & malloc check*/ 559 colors = (XRenderColor *) malloc(numStops * sizeof(XRenderColor)); 560 stops = (XFixed *) malloc(numStops * sizeof(XFixed)); 561 562 if (colors == NULL || stops == NULL) { 563 if (colors != NULL) { 564 free(colors); 565 } 566 if (stops != NULL) { 567 free(stops); 568 } 569 (*env)->ReleasePrimitiveArrayCritical(env, pixelsArray, pixels, JNI_ABORT); 570 (*env)->ReleasePrimitiveArrayCritical(env, fractionsArray, fractions, JNI_ABORT); 571 return -1; 572 } 573 574 for (i=0; i < numStops; i++) { 575 stops[i] = XDoubleToFixed(fractions[i]); 576 colors[i].alpha = pixels[i*4 + 0]; 577 colors[i].red = pixels[i*4 + 1]; 578 colors[i].green = pixels[i*4 + 2]; 579 colors[i].blue = pixels[i*4 + 3]; 580 } 581 #ifdef __solaris__ 582 if (XRenderCreateLinearGradientFunc!=NULL) { 583 gradient = (*XRenderCreateLinearGradientFunc)(awt_display, &grad, stops, colors, numStops); 584 } 585 #else 586 gradient = XRenderCreateLinearGradient(awt_display, &grad, stops, colors, numStops); 587 #endif 588 free(colors); 589 free(stops); 590 591 (*env)->ReleasePrimitiveArrayCritical(env, pixelsArray, pixels, JNI_ABORT); 592 (*env)->ReleasePrimitiveArrayCritical(env, fractionsArray, fractions, JNI_ABORT); 593 594 if (gradient != 0) { 595 pict_attr.repeat = repeat; 596 XRenderChangePicture (awt_display, gradient, CPRepeat, &pict_attr); 597 } 598 599 return (jint) gradient; 600 } 601 602 603 JNIEXPORT jint JNICALL 604 Java_sun_java2d_xr_XRBackendNative_XRCreateRadialGradientPaintNative 605 (JNIEnv *env, jclass xsd, jfloatArray fractionsArray, 606 jshortArray pixelsArray, jint numStops, 607 jint centerX, jint centerY, 608 jint innerRadius, jint outerRadius, jint repeat) { 609 jint i; 610 jshort* pixels; 611 jfloat* fractions; 612 XRenderPictureAttributes pict_attr; 613 Picture gradient = 0; 614 XRenderColor *colors; 615 XFixed *stops; 616 XRadialGradient grad; 617 618 if (MAX_PAYLOAD / (sizeof(XRenderColor) + sizeof(XFixed)) 619 < (unsigned)numStops) { 620 /* numStops too big, payload overflow */ 621 return -1; 622 } 623 624 if ((pixels = 625 (jshort *)(*env)->GetPrimitiveArrayCritical(env, pixelsArray, NULL)) == NULL) { 626 return -1; 627 } 628 if ((fractions = (jfloat *) 629 (*env)->GetPrimitiveArrayCritical(env, fractionsArray, NULL)) == NULL) { 630 (*env)->ReleasePrimitiveArrayCritical(env, 631 pixelsArray, pixels, JNI_ABORT); 632 return -1; //TODO release pixels first 633 } 634 635 grad.inner.x = centerX; 636 grad.inner.y = centerY; 637 grad.inner.radius = innerRadius; 638 grad.outer.x = centerX; 639 grad.outer.y = centerY; 640 grad.outer.radius = outerRadius; 641 642 /*TODO optimized & malloc check*/ 643 colors = (XRenderColor *) malloc(numStops * sizeof(XRenderColor)); 644 stops = (XFixed *) malloc(numStops * sizeof(XFixed)); 645 646 if (colors == NULL || stops == NULL) { 647 if (colors != NULL) { 648 free(colors); 649 } 650 if (stops != NULL) { 651 free(stops); 652 } 653 (*env)->ReleasePrimitiveArrayCritical(env, pixelsArray, pixels, JNI_ABORT); 654 (*env)->ReleasePrimitiveArrayCritical(env, fractionsArray, fractions, JNI_ABORT); 655 return -1; 656 } 657 658 for (i=0; i < numStops; i++) { 659 stops[i] = XDoubleToFixed(fractions[i]); 660 colors[i].alpha = pixels[i*4 + 0]; 661 colors[i].red = pixels[i*4 + 1]; 662 colors[i].green = pixels[i*4 + 2]; 663 colors[i].blue = pixels[i*4 + 3]; 664 } 665 #ifdef __solaris__ 666 if (XRenderCreateRadialGradientFunc != NULL) { 667 gradient = (jint) (*XRenderCreateRadialGradientFunc)(awt_display, &grad, stops, colors, numStops); 668 } 669 #else 670 gradient = (jint) XRenderCreateRadialGradient(awt_display, &grad, stops, colors, numStops); 671 #endif 672 free(colors); 673 free(stops); 674 675 (*env)->ReleasePrimitiveArrayCritical(env, pixelsArray, pixels, JNI_ABORT); 676 (*env)->ReleasePrimitiveArrayCritical(env, fractionsArray, fractions, JNI_ABORT); 677 678 679 if (gradient != 0) { 680 pict_attr.repeat = repeat; 681 XRenderChangePicture (awt_display, gradient, CPRepeat, &pict_attr); 682 } 683 684 return (jint) gradient; 685 } 686 687 JNIEXPORT void JNICALL 688 Java_sun_java2d_xr_XRBackendNative_setFilter 689 (JNIEnv *env, jobject this, jint picture, jint filter) { 690 691 char * filterName = "fast"; 692 693 switch(filter) { 694 case 0: 695 filterName = "fast"; 696 break; 697 698 case 1: 699 filterName = "good"; 700 break; 701 702 case 2: 703 filterName = "best"; 704 break; 705 } 706 707 XRenderSetPictureFilter(awt_display, (Picture) picture, filterName, NULL, 0); 708 } 709 710 JNIEXPORT void JNICALL 711 Java_sun_java2d_xr_XRBackendNative_XRSetClipNative 712 (JNIEnv *env, jclass xsd, jlong dst, 713 jint x1, jint y1, jint x2, jint y2, 714 jobject complexclip, jboolean isGC) 715 { 716 int numrects; 717 XRectangle rects[256]; 718 XRectangle *pRect = rects; 719 720 numrects = RegionToYXBandedRectangles(env, 721 x1, y1, x2, y2, complexclip, 722 &pRect, 256); 723 724 if (isGC == JNI_TRUE) { 725 if (dst != (jlong) 0) { 726 XSetClipRectangles(awt_display, (GC) jlong_to_ptr(dst), 0, 0, pRect, numrects, YXBanded); 727 } 728 } else { 729 XRenderSetPictureClipRectangles (awt_display, (Picture) dst, 0, 0, pRect, numrects); 730 } 731 732 if (pRect != rects) { 733 free(pRect); 734 } 735 } 736 737 JNIEXPORT void JNICALL 738 Java_sun_java2d_xr_XRBackendNative_putMaskNative 739 (JNIEnv *env, jclass cls, jint drawable, jlong gc, jbyteArray imageData, 740 jint sx, jint sy, jint dx, jint dy, jint width, jint height, 741 jint maskOff, jint maskScan, jfloat ea, jlong imgPtr) { 742 743 int line, pix; 744 char *mask; 745 char *defaultData; 746 XImage *defaultImg, *img; 747 jboolean imageFits; 748 749 if ((mask = (char *) 750 (*env)->GetPrimitiveArrayCritical(env, imageData, NULL)) == NULL) { 751 return; 752 } 753 754 defaultImg = (XImage *) jlong_to_ptr(imgPtr); 755 756 if (ea != 1.0f) { 757 for (line=0; line < height; line++) { 758 for (pix=0; pix < width; pix++) { 759 int index = maskScan*line + pix + maskOff; 760 mask[index] = (((unsigned char) mask[index])*ea); 761 } 762 } 763 } 764 765 /* 766 * 1. If existing XImage and supplied buffer match, only adjust the data pointer 767 * 2. If existing XImage is large enough to hold the data but does not match in 768 * scan the data is copied to fit the XImage. 769 * 3. If data is larger than the existing XImage a new temporary XImage is 770 * allocated. 771 * The default XImage is optimized for the AA tiles, which are currently 32x32. 772 */ 773 defaultData = defaultImg->data; 774 img = defaultImg; 775 imageFits = defaultImg->width >= width && defaultImg->height >= height; 776 777 if (imageFits && 778 maskOff == defaultImg->xoffset && maskScan == defaultImg->bytes_per_line) { 779 defaultImg->data = mask; 780 } else { 781 if (imageFits) { 782 for (line=0; line < height; line++) { 783 for (pix=0; pix < width; pix++) { 784 img->data[line*img->bytes_per_line + pix] = 785 (unsigned char) (mask[maskScan*line + pix + maskOff]); 786 } 787 } 788 } else { 789 img = XCreateImage(awt_display, NULL, 8, ZPixmap, 790 maskOff, mask, maskScan, height, 8, 0); 791 } 792 } 793 794 XPutImage(awt_display, (Pixmap) drawable, (GC) jlong_to_ptr(gc), 795 img, 0, 0, 0, 0, width, height); 796 (*env)->ReleasePrimitiveArrayCritical(env, imageData, mask, JNI_ABORT); 797 798 if (img != defaultImg) { 799 img->data = NULL; 800 XDestroyImage(img); 801 } 802 defaultImg->data = defaultData; 803 } 804 805 JNIEXPORT void JNICALL 806 Java_sun_java2d_xr_XRBackendNative_XRAddGlyphsNative 807 (JNIEnv *env, jclass cls, jint glyphSet, 808 jlongArray glyphInfoPtrsArray, jint glyphCnt, 809 jbyteArray pixelDataArray, int pixelDataLength) { 810 jlong *glyphInfoPtrs; 811 unsigned char *pixelData; 812 int i; 813 814 if (MAX_PAYLOAD / (sizeof(XGlyphInfo) + sizeof(Glyph)) 815 < (unsigned)glyphCnt) { 816 /* glyphCnt too big, payload overflow */ 817 return; 818 } 819 820 XGlyphInfo *xginfo = (XGlyphInfo *) malloc(sizeof(XGlyphInfo) * glyphCnt); 821 Glyph *gid = (Glyph *) malloc(sizeof(Glyph) * glyphCnt); 822 823 if (xginfo == NULL || gid == NULL) { 824 if (xginfo != NULL) { 825 free(xginfo); 826 } 827 if (gid != NULL) { 828 free(gid); 829 } 830 return; 831 } 832 833 if ((glyphInfoPtrs = (jlong *)(*env)-> 834 GetPrimitiveArrayCritical(env, glyphInfoPtrsArray, NULL)) == NULL) 835 { 836 free(xginfo); 837 free(gid); 838 return; 839 } 840 841 if ((pixelData = (unsigned char *) 842 (*env)->GetPrimitiveArrayCritical(env, pixelDataArray, NULL)) == NULL) 843 { 844 (*env)->ReleasePrimitiveArrayCritical(env, 845 glyphInfoPtrsArray, glyphInfoPtrs, JNI_ABORT); 846 free(xginfo); 847 free(gid); 848 return; 849 } 850 851 for (i=0; i < glyphCnt; i++) { 852 GlyphInfo *jginfo = (GlyphInfo *) jlong_to_ptr(glyphInfoPtrs[i]); 853 854 // 'jginfo->cellInfo' is of type 'void*' 855 // (see definition of 'GlyphInfo' in fontscalerdefs.h) 856 // 'Glyph' is typedefed to 'unsigned long' 857 // (see http://www.x.org/releases/X11R7.7/doc/libXrender/libXrender.txt) 858 // Maybe we should assert that (sizeof(void*) == sizeof(Glyph)) ? 859 gid[i] = (Glyph) (jginfo->cellInfo); 860 xginfo[i].x = (-jginfo->topLeftX); 861 xginfo[i].y = (-jginfo->topLeftY); 862 xginfo[i].width = jginfo->width; 863 xginfo[i].height = jginfo->height; 864 xginfo[i].xOff = round(jginfo->advanceX); 865 xginfo[i].yOff = round(jginfo->advanceY); 866 } 867 868 XRenderAddGlyphs(awt_display, glyphSet, &gid[0], &xginfo[0], glyphCnt, 869 (const char*)pixelData, pixelDataLength); 870 871 (*env)->ReleasePrimitiveArrayCritical(env, glyphInfoPtrsArray, glyphInfoPtrs, JNI_ABORT); 872 (*env)->ReleasePrimitiveArrayCritical(env, pixelDataArray, pixelData, JNI_ABORT); 873 874 free(xginfo); 875 free(gid); 876 } 877 878 JNIEXPORT void JNICALL 879 Java_sun_java2d_xr_XRBackendNative_XRFreeGlyphsNative 880 (JNIEnv *env, jclass cls, jint glyphSet, jintArray gidArray, jint glyphCnt) { 881 882 if (MAX_PAYLOAD / sizeof(Glyph) < (unsigned)glyphCnt) { 883 /* glyphCnt too big, payload overflow */ 884 return; 885 } 886 887 /* The glyph ids are 32 bit but may be stored in a 64 bit long on 888 * a 64 bit architecture. So optimise the 32 bit case to avoid 889 * extra stack or heap allocations by directly referencing the 890 * underlying Java array and only allocate on 64 bit. 891 */ 892 if (sizeof(jint) == sizeof(Glyph)) { 893 jint *gids = 894 (*env)->GetPrimitiveArrayCritical(env, gidArray, NULL); 895 if (gids == NULL) { 896 return; 897 } else { 898 XRenderFreeGlyphs(awt_display, 899 (GlyphSet)glyphSet, (Glyph *)gids, glyphCnt); 900 (*env)->ReleasePrimitiveArrayCritical(env, gidArray, 901 gids, JNI_ABORT); 902 } 903 return; 904 } else { 905 Glyph stack_ids[64]; 906 Glyph *gids = NULL; 907 jint* jgids = NULL; 908 int i; 909 910 if (glyphCnt <= 64) { 911 gids = stack_ids; 912 } else { 913 gids = (Glyph *)malloc(sizeof(Glyph) * glyphCnt); 914 if (gids == NULL) { 915 return; 916 } 917 } 918 jgids = (*env)->GetPrimitiveArrayCritical(env, gidArray, NULL); 919 if (jgids == NULL) { 920 if (gids != stack_ids) { 921 free(gids); 922 } 923 return; 924 } 925 for (i=0; i < glyphCnt; i++) { 926 gids[i] = jgids[i]; 927 } 928 XRenderFreeGlyphs(awt_display, 929 (GlyphSet) glyphSet, gids, glyphCnt); 930 (*env)->ReleasePrimitiveArrayCritical(env, gidArray, 931 jgids, JNI_ABORT); 932 if (gids != stack_ids) { 933 free(gids); 934 } 935 } 936 } 937 938 JNIEXPORT jint JNICALL 939 Java_sun_java2d_xr_XRBackendNative_XRenderCreateGlyphSetNative 940 (JNIEnv *env, jclass cls, jlong format) { 941 return XRenderCreateGlyphSet(awt_display, (XRenderPictFormat *) jlong_to_ptr(format)); 942 } 943 944 JNIEXPORT void JNICALL 945 Java_sun_java2d_xr_XRBackendNative_XRenderCompositeTextNative 946 (JNIEnv *env, jclass cls, jint op, jint src, jint dst, 947 jint sx, jint sy, jlong maskFmt, jintArray eltArray, 948 jintArray glyphIDArray, jint eltCnt, jint glyphCnt) { 949 jint i; 950 jint *ids; 951 jint *elts; 952 XGlyphElt32 *xelts; 953 unsigned int *xids; 954 XGlyphElt32 selts[24]; 955 unsigned int sids[256]; 956 int charCnt = 0; 957 958 if ((MAX_PAYLOAD / sizeof(XGlyphElt32) < (unsigned)eltCnt) 959 || (MAX_PAYLOAD / sizeof(unsigned int) < (unsigned)glyphCnt) 960 || ((MAX_PAYLOAD - sizeof(XGlyphElt32)*(unsigned)eltCnt) / 961 sizeof(unsigned int) < (unsigned)glyphCnt)) 962 { 963 /* (eltCnt, glyphCnt) too big, payload overflow */ 964 return; 965 } 966 967 if (eltCnt <= 24) { 968 xelts = &selts[0]; 969 }else { 970 xelts = (XGlyphElt32 *) malloc(sizeof(XGlyphElt32) * eltCnt); 971 if (xelts == NULL) { 972 return; 973 } 974 } 975 976 if (glyphCnt <= 256) { 977 xids = &sids[0]; 978 } else { 979 xids = (unsigned int*)malloc(sizeof(unsigned int) * glyphCnt); 980 if (xids == NULL) { 981 if (xelts != &selts[0]) { 982 free(xelts); 983 } 984 return; 985 } 986 } 987 988 if ((ids = (jint *) 989 (*env)->GetPrimitiveArrayCritical(env, glyphIDArray, NULL)) == NULL) { 990 if (xelts != &selts[0]) { 991 free(xelts); 992 } 993 if (xids != &sids[0]) { 994 free(xids); 995 } 996 return; 997 } 998 if ((elts = (jint *) 999 (*env)->GetPrimitiveArrayCritical(env, eltArray, NULL)) == NULL) { 1000 (*env)->ReleasePrimitiveArrayCritical(env, 1001 glyphIDArray, ids, JNI_ABORT); 1002 if (xelts != &selts[0]) { 1003 free(xelts); 1004 } 1005 if (xids != &sids[0]) { 1006 free(xids); 1007 } 1008 return; 1009 } 1010 1011 for (i=0; i < glyphCnt; i++) { 1012 xids[i] = ids[i]; 1013 } 1014 1015 for (i=0; i < eltCnt; i++) { 1016 xelts[i].nchars = elts[i*4 + 0]; 1017 xelts[i].xOff = elts[i*4 + 1]; 1018 xelts[i].yOff = elts[i*4 + 2]; 1019 xelts[i].glyphset = (GlyphSet) elts[i*4 + 3]; 1020 xelts[i].chars = &xids[charCnt]; 1021 1022 charCnt += xelts[i].nchars; 1023 } 1024 1025 XRenderCompositeText32(awt_display, op, (Picture) src, (Picture) dst, 1026 (XRenderPictFormat *) jlong_to_ptr(maskFmt), 1027 sx, sy, 0, 0, xelts, eltCnt); 1028 1029 (*env)->ReleasePrimitiveArrayCritical(env, glyphIDArray, ids, JNI_ABORT); 1030 (*env)->ReleasePrimitiveArrayCritical(env, eltArray, elts, JNI_ABORT); 1031 1032 if (xelts != &selts[0]) { 1033 free(xelts); 1034 } 1035 1036 if (xids != &sids[0]) { 1037 free(xids); 1038 } 1039 } 1040 1041 JNIEXPORT void JNICALL 1042 Java_sun_java2d_xr_XRBackendNative_setGCMode 1043 (JNIEnv *env, jobject this, jlong gc, jboolean copy) { 1044 GC xgc = (GC) jlong_to_ptr(gc); 1045 1046 if (copy == JNI_TRUE) { 1047 XSetFunction(awt_display, xgc, GXcopy); 1048 } else { 1049 XSetFunction(awt_display, xgc, GXxor); 1050 } 1051 } 1052 1053 JNIEXPORT void JNICALL 1054 Java_sun_java2d_xr_XRBackendNative_GCRectanglesNative 1055 (JNIEnv *env, jclass xsd, jint dst, jlong gc, 1056 jintArray rectArray, jint rectCnt) { 1057 int i; 1058 jint* rects; 1059 XRectangle *xRects; 1060 XRectangle sRects[256]; 1061 1062 if (rectCnt <= 256) { 1063 xRects = &sRects[0]; 1064 } else { 1065 if (MAXUINT / sizeof(XRectangle) < (unsigned)rectCnt) { 1066 /* rectCnt too big, integer overflow */ 1067 return; 1068 } 1069 1070 xRects = (XRectangle *) malloc(sizeof(XRectangle) * rectCnt); 1071 if (xRects == NULL) { 1072 return; 1073 } 1074 } 1075 1076 if ((rects = (jint*) 1077 (*env)->GetPrimitiveArrayCritical(env, rectArray, NULL)) == NULL) { 1078 if (xRects != &sRects[0]) { 1079 free(xRects); 1080 } 1081 return; 1082 } 1083 1084 for (i=0; i < rectCnt; i++) { 1085 xRects[i].x = rects[i*4 + 0]; 1086 xRects[i].y = rects[i*4 + 1]; 1087 xRects[i].width = rects[i*4 + 2]; 1088 xRects[i].height = rects[i*4 + 3]; 1089 } 1090 1091 XFillRectangles(awt_display, (Drawable) dst, (GC) jlong_to_ptr(gc), xRects, rectCnt); 1092 1093 (*env)->ReleasePrimitiveArrayCritical(env, rectArray, rects, JNI_ABORT); 1094 if (xRects != &sRects[0]) { 1095 free(xRects); 1096 } 1097 } 1098 1099 JNIEXPORT void JNICALL 1100 Java_sun_java2d_xr_XRBackendNative_renderCompositeTrapezoidsNative 1101 (JNIEnv *env, jclass cls, jbyte op, jint src, jlong maskFmt, 1102 jint dst, jint srcX, jint srcY, jintArray trapArray) { 1103 jint *traps; 1104 1105 if ((traps = (jint *) (*env)->GetPrimitiveArrayCritical(env, trapArray, NULL)) == NULL) { 1106 return; 1107 } 1108 1109 XRenderCompositeTrapezoids(awt_display, op, (Picture) src, (Picture) dst, 1110 (XRenderPictFormat *) jlong_to_ptr(maskFmt), 1111 srcX, srcY, (XTrapezoid *) (traps+5), traps[0]); 1112 1113 (*env)->ReleasePrimitiveArrayCritical(env, trapArray, traps, JNI_ABORT); 1114 }