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