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 /* 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 #if defined(__solaris__) || defined(AIX) 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 #if defined(__solaris__) || defined(AIX) 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, jlong maskFmt, 915 jintArray eltArray, jintArray glyphIDArray, jint eltCnt, jint glyphCnt) { 916 jint i; 917 jint *ids; 918 jint *elts; 919 XGlyphElt32 *xelts; 920 unsigned int *xids; 921 XGlyphElt32 selts[24]; 922 unsigned int sids[256]; 923 int charCnt = 0; 924 925 if ((MAX_PAYLOAD / sizeof(XGlyphElt32) < (unsigned)eltCnt) 926 || (MAX_PAYLOAD / sizeof(unsigned int) < (unsigned)glyphCnt) 927 || ((MAX_PAYLOAD - sizeof(XGlyphElt32)*(unsigned)eltCnt) / 928 sizeof(unsigned int) < (unsigned)glyphCnt)) 929 { 930 /* (eltCnt, glyphCnt) too big, payload overflow */ 931 return; 932 } 933 934 if (eltCnt <= 24) { 935 xelts = &selts[0]; 936 }else { 937 xelts = (XGlyphElt32 *) malloc(sizeof(XGlyphElt32) * eltCnt); 938 if (xelts == NULL) { 939 return; 940 } 941 } 942 943 if (glyphCnt <= 256) { 944 xids = &sids[0]; 945 } else { 946 xids = (unsigned int*)malloc(sizeof(unsigned int) * glyphCnt); 947 if (xids == NULL) { 948 if (xelts != &selts[0]) { 949 free(xelts); 950 } 951 return; 952 } 953 } 954 955 if ((ids = (jint *) 956 (*env)->GetPrimitiveArrayCritical(env, glyphIDArray, NULL)) == NULL) { 957 if (xelts != &selts[0]) { 958 free(xelts); 959 } 960 if (xids != &sids[0]) { 961 free(xids); 962 } 963 return; 964 } 965 if ((elts = (jint *) 966 (*env)->GetPrimitiveArrayCritical(env, eltArray, NULL)) == NULL) { 967 (*env)->ReleasePrimitiveArrayCritical(env, 968 glyphIDArray, ids, JNI_ABORT); 969 if (xelts != &selts[0]) { 970 free(xelts); 971 } 972 if (xids != &sids[0]) { 973 free(xids); 974 } 975 return; 976 } 977 978 for (i=0; i < glyphCnt; i++) { 979 xids[i] = ids[i]; 980 } 981 982 for (i=0; i < eltCnt; i++) { 983 xelts[i].nchars = elts[i*4 + 0]; 984 xelts[i].xOff = elts[i*4 + 1]; 985 xelts[i].yOff = elts[i*4 + 2]; 986 xelts[i].glyphset = (GlyphSet) elts[i*4 + 3]; 987 xelts[i].chars = &xids[charCnt]; 988 989 charCnt += xelts[i].nchars; 990 } 991 992 XRenderCompositeText32(awt_display, op, (Picture) src, (Picture) dst, 993 (XRenderPictFormat *) jlong_to_ptr(maskFmt), 994 0, 0, 0, 0, xelts, eltCnt); 995 996 (*env)->ReleasePrimitiveArrayCritical(env, glyphIDArray, ids, JNI_ABORT); 997 (*env)->ReleasePrimitiveArrayCritical(env, eltArray, elts, JNI_ABORT); 998 999 if (xelts != &selts[0]) { 1000 free(xelts); 1001 } 1002 1003 if (xids != &sids[0]) { 1004 free(xids); 1005 } 1006 } 1007 1008 JNIEXPORT void JNICALL 1009 Java_sun_java2d_xr_XRBackendNative_setGCMode 1010 (JNIEnv *env, jobject this, jlong gc, jboolean copy) { 1011 GC xgc = (GC) jlong_to_ptr(gc); 1012 1013 if (copy == JNI_TRUE) { 1014 XSetFunction(awt_display, xgc, GXcopy); 1015 } else { 1016 XSetFunction(awt_display, xgc, GXxor); 1017 } 1018 } 1019 1020 JNIEXPORT void JNICALL 1021 Java_sun_java2d_xr_XRBackendNative_GCRectanglesNative 1022 (JNIEnv *env, jclass xsd, jint dst, jlong gc, 1023 jintArray rectArray, jint rectCnt) { 1024 int i; 1025 jint* rects; 1026 XRectangle *xRects; 1027 XRectangle sRects[256]; 1028 1029 if (rectCnt <= 256) { 1030 xRects = &sRects[0]; 1031 } else { 1032 if (MAXUINT / sizeof(XRectangle) < (unsigned)rectCnt) { 1033 /* rectCnt too big, integer overflow */ 1034 return; 1035 } 1036 1037 xRects = (XRectangle *) malloc(sizeof(XRectangle) * rectCnt); 1038 if (xRects == NULL) { 1039 return; 1040 } 1041 } 1042 1043 if ((rects = (jint*) 1044 (*env)->GetPrimitiveArrayCritical(env, rectArray, NULL)) == NULL) { 1045 if (xRects != &sRects[0]) { 1046 free(xRects); 1047 } 1048 return; 1049 } 1050 1051 for (i=0; i < rectCnt; i++) { 1052 xRects[i].x = rects[i*4 + 0]; 1053 xRects[i].y = rects[i*4 + 1]; 1054 xRects[i].width = rects[i*4 + 2]; 1055 xRects[i].height = rects[i*4 + 3]; 1056 } 1057 1058 XFillRectangles(awt_display, (Drawable) dst, (GC) jlong_to_ptr(gc), xRects, rectCnt); 1059 1060 (*env)->ReleasePrimitiveArrayCritical(env, rectArray, rects, JNI_ABORT); 1061 if (xRects != &sRects[0]) { 1062 free(xRects); 1063 } 1064 } 1065 1066 JNIEXPORT void JNICALL 1067 Java_sun_java2d_xr_XRBackendNative_renderCompositeTrapezoidsNative 1068 (JNIEnv *env, jclass cls, jbyte op, jint src, jlong maskFmt, 1069 jint dst, jint srcX, jint srcY, jintArray trapArray) { 1070 jint *traps; 1071 1072 if ((traps = (jint *) (*env)->GetPrimitiveArrayCritical(env, trapArray, NULL)) == NULL) { 1073 return; 1074 } 1075 1076 XRenderCompositeTrapezoids(awt_display, op, (Picture) src, (Picture) dst, 1077 (XRenderPictFormat *) jlong_to_ptr(maskFmt), 1078 srcX, srcY, (XTrapezoid *) (traps+5), traps[0]); 1079 1080 (*env)->ReleasePrimitiveArrayCritical(env, trapArray, traps, JNI_ABORT); 1081 }