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