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