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
54typedef struct _XLinearGradient {
55 XPointFixed p1;
56 XPointFixed p2;
57} XLinearGradient;
58#endif
59
60#ifndef X_RenderCreateRadialGradient
61typedef struct _XCircle {
62 XFixed x;
63 XFixed y;
64 XFixed radius;
65} XCircle;
66
67typedef 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
78typedef Picture (*XRenderCreateLinearGradientFuncType)
79 (Display *dpy,
80 const XLinearGradient *gradient,
81 const XFixed *stops,
82 const XRenderColor *colors,
83 int nstops);
84
85typedef Picture (*XRenderCreateRadialGradientFuncType)
86 (Display *dpy,
87 const XRadialGradient *gradient,
88 const XFixed *stops,
89 const XRenderColor *colors,
90 int nstops);
91
92static
93XRenderCreateLinearGradientFuncType XRenderCreateLinearGradientFunc = NULL;
94static
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
138static 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 */
307JNIEXPORT jboolean JNICALL
308Java_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
335JNIEXPORT void JNICALL
336Java_sun_java2d_xr_XRBackendNative_initIDs(JNIEnv *env, jclass cls) {
337 char *maskData;
338 XImage* defaultImg;
339 jfieldID maskImgID;
340 jlong fmt8;
341 jlong fmt32;
342
343 jfieldID a8ID = (*env)->GetStaticFieldID(env, cls, "FMTPTR_A8", "J");
344 if (a8ID == NULL) {
345 return;
346 }
347 jfieldID argb32ID = (*env)->GetStaticFieldID(env, cls, "FMTPTR_ARGB32", "J");
348 if (argb32ID == NULL) {
349 return;
350 }
351
352 if (awt_display == (Display *)NULL) {
353 return;
354 }
355
356 fmt8 = ptr_to_jlong(XRenderFindStandardFormat(awt_display, PictStandardA8));
357 fmt32 = ptr_to_jlong(XRenderFindStandardFormat(awt_display, PictStandardARGB32));
358
359 (*env)->SetStaticLongField(env, cls, a8ID, fmt8);
360 (*env)->SetStaticLongField(env, cls, argb32ID, fmt32);
361
362 maskData = (char *) malloc(32*32);
363 if (maskData == NULL) {
364 return;
365 }
366
367 defaultImg = XCreateImage(awt_display, NULL, 8, ZPixmap, 0, maskData, 32, 32, 8, 0);
368 defaultImg->data = maskData; //required?
369 maskImgID = (*env)->GetStaticFieldID(env, cls, "MASK_XIMG", "J");
370 if (maskImgID == NULL) {
371 return;
372 }
373
374 (*env)->SetStaticLongField(env, cls, maskImgID, ptr_to_jlong(defaultImg));
375}
376
377JNIEXPORT void JNICALL
378Java_sun_java2d_xr_XRBackendNative_freeGC
379 (JNIEnv *env, jobject this, jlong gc) {
380 XFreeGC(awt_display, (GC) jlong_to_ptr(gc));
381}
382
383JNIEXPORT jlong JNICALL
384Java_sun_java2d_xr_XRBackendNative_createGC
385 (JNIEnv *env, jobject this, jint drawable) {
386 GC xgc = XCreateGC(awt_display, (Drawable) drawable, 0L, NULL);
387 return ptr_to_jlong(xgc);
388}
389
390JNIEXPORT jint JNICALL
391Java_sun_java2d_xr_XRBackendNative_createPixmap(JNIEnv *env, jobject this,
392 jint drawable, jint depth,
393 jint width, jint height) {
394 return (jint) XCreatePixmap(awt_display, (Drawable) drawable,
395 width, height, depth);
396}
397
398JNIEXPORT jint JNICALL
399Java_sun_java2d_xr_XRBackendNative_createPictureNative
400 (JNIEnv *env, jclass cls, jint drawable, jlong formatPtr) {
401 XRenderPictureAttributes pict_attr;
402 return XRenderCreatePicture(awt_display, (Drawable) drawable,
403 (XRenderPictFormat *) jlong_to_ptr(formatPtr),
404 0, &pict_attr);
405}
406
407JNIEXPORT void JNICALL
408Java_sun_java2d_xr_XRBackendNative_freePicture
409 (JNIEnv *env, jobject this, jint picture) {
410 XRenderFreePicture(awt_display, (Picture) picture);
411}
412
413JNIEXPORT void JNICALL
414Java_sun_java2d_xr_XRBackendNative_freePixmap
415 (JNIEnv *env, jobject this, jint pixmap) {
416 XFreePixmap(awt_display, (Pixmap) pixmap);
417}
418
419JNIEXPORT void JNICALL
420Java_sun_java2d_xr_XRBackendNative_setPictureRepeat
421 (JNIEnv *env, jobject this, jint picture, jint repeat) {
422 XRenderPictureAttributes pict_attr;
423 pict_attr.repeat = repeat;
424 XRenderChangePicture (awt_display, (Picture) picture, CPRepeat, &pict_attr);
425}
426
427
428JNIEXPORT void JNICALL
429Java_sun_java2d_xr_XRBackendNative_setGCExposures
430 (JNIEnv *env, jobject this, jlong gc, jboolean exposure) {
431 XSetGraphicsExposures(awt_display,
432 (GC) jlong_to_ptr(gc), exposure ? True : False); //TODO: ????
433}
434
435JNIEXPORT void JNICALL
436Java_sun_java2d_xr_XRBackendNative_setGCForeground
437 (JNIEnv *env, jobject this, jlong gc, jint pixel) {
438 XSetForeground(awt_display, (GC) jlong_to_ptr(gc), (unsigned long) pixel);
439}
440
441
442JNIEXPORT void JNICALL
443Java_sun_java2d_xr_XRBackendNative_copyArea
444 (JNIEnv *env, jobject this, jint src, jint dst, jlong gc,
445 jint srcx, jint srcy, jint width, jint height, jint dstx, jint dsty) {
446 XCopyArea(awt_display, (Drawable) src, (Drawable) dst,
447 (GC) jlong_to_ptr(gc), srcx, srcy, width, height, dstx, dsty);
448}
449
450JNIEXPORT void JNICALL
451Java_sun_java2d_xr_XRBackendNative_renderComposite
452 (JNIEnv *env, jobject this, jbyte op, jint src, jint mask, jint dst,
453 jint srcX, jint srcY, jint maskX, jint maskY,
454 jint dstX, jint dstY, jint width, jint height) {
455 XRenderComposite (awt_display, op,
456 (Picture)src, (Picture)mask, (Picture)dst,
457 srcX, srcY, maskX, maskY, dstX, dstY, width, height);
458}
459
460JNIEXPORT void JNICALL
461Java_sun_java2d_xr_XRBackendNative_renderRectangle
462 (JNIEnv *env, jobject this, jint dst, jbyte op,
463 jshort red, jshort green, jshort blue, jshort alpha,
464 jint x, jint y, jint width, jint height) {
465 XRenderColor color;
466 color.alpha = alpha;
467 color.red = red;
468 color.green = green;
469 color.blue = blue;
470 XRenderFillRectangle(awt_display, op, (Picture) dst, &color,
471 x, y, width, height);
472}
473
474JNIEXPORT void JNICALL
475Java_sun_java2d_xr_XRBackendNative_XRenderRectanglesNative
476 (JNIEnv *env, jclass xsd, jint dst, jbyte op,
477 jshort red, jshort green, jshort blue, jshort alpha,
478 jintArray rectArray, jint rectCnt) {
479 int i;
480 jint* rects;
481 XRectangle *xRects;
482 XRectangle sRects[256];
483
484 XRenderColor color;
485 color.alpha = alpha;
486 color.red = red;
487 color.green = green;
488 color.blue = blue;
489
490 if (rectCnt <= 256) {
491 xRects = &sRects[0];
492 } else {
493 if (MAXUINT / sizeof(XRectangle) < (unsigned)rectCnt) {
494 /* rectCnt too big, integer overflow */
495 return;
496 }
497 xRects = (XRectangle *) malloc(sizeof(XRectangle) * rectCnt);
498 if (xRects == NULL) {
499 return;
500 }
501 }
502
503 if ((rects = (jint *)
504 (*env)->GetPrimitiveArrayCritical(env, rectArray, NULL)) == NULL) {
505 if (xRects != &sRects[0]) {
506 free(xRects);
507 }
508 return;
509 }
510
511 for (i=0; i < rectCnt; i++) {
512 xRects[i].x = rects[i*4 + 0];
513 xRects[i].y = rects[i*4 + 1];
514 xRects[i].width = rects[i*4 + 2];
515 xRects[i].height = rects[i*4 + 3];
516 }
517
518 XRenderFillRectangles(awt_display, op,
519 (Picture) dst, &color, xRects, rectCnt);
520
521 (*env)->ReleasePrimitiveArrayCritical(env, rectArray, rects, JNI_ABORT);
522 if (xRects != &sRects[0]) {
523 free(xRects);
524 }
525}
526
527JNIEXPORT void JNICALL
528Java_sun_java2d_xr_XRBackendNative_XRSetTransformNative
529 (JNIEnv *env, jclass xsd, jint pic,
530 jint m00, jint m01, jint m02, jint m10, jint m11, jint m12) {
531
532 XTransform tr;
533 BUILD_TRANSFORM_MATRIX(tr, m00, m01, m02, m10, m11, m12);
534 XRenderSetPictureTransform (awt_display, (Picture) pic, &tr);
535}
536
537JNIEXPORT jint JNICALL
538Java_sun_java2d_xr_XRBackendNative_XRCreateLinearGradientPaintNative
539 (JNIEnv *env, jclass xsd, jfloatArray fractionsArray,
540 jshortArray pixelsArray, jint x1, jint y1, jint x2, jint y2,
541 jint numStops, jint repeat) {
542 jint i;
543 jshort* pixels;
544 jfloat* fractions;
545 XRenderPictureAttributes pict_attr;
546 Picture gradient = 0;
547 XRenderColor *colors;
548 XFixed *stops;
549 XLinearGradient grad;
550
551 if (MAX_PAYLOAD / (sizeof(XRenderColor) + sizeof(XFixed))
552 < (unsigned)numStops) {
553 /* numStops too big, payload overflow */
554 return -1;
555 }
556
557 if ((pixels = (jshort *)
558 (*env)->GetPrimitiveArrayCritical(env, pixelsArray, NULL)) == NULL) {
559 return -1;
560 }
561 if ((fractions = (jfloat *)
562 (*env)->GetPrimitiveArrayCritical(env, fractionsArray, NULL)) == NULL) {
563 (*env)->ReleasePrimitiveArrayCritical(env,
564 pixelsArray, pixels, JNI_ABORT);
565 return -1;
566 }
567
568 grad.p1.x = x1;
569 grad.p1.y = y1;
570 grad.p2.x = x2;
571 grad.p2.y = y2;
572
573 /*TODO optimized & malloc check*/
574 colors = (XRenderColor *) malloc(numStops * sizeof(XRenderColor));
575 stops = (XFixed *) malloc(numStops * sizeof(XFixed));
576
577 if (colors == NULL || stops == NULL) {
578 if (colors != NULL) {
579 free(colors);
580 }
581 if (stops != NULL) {
582 free(stops);
583 }
584 (*env)->ReleasePrimitiveArrayCritical(env, pixelsArray, pixels, JNI_ABORT);
585 (*env)->ReleasePrimitiveArrayCritical(env, fractionsArray, fractions, JNI_ABORT);
586 return -1;
587 }
588
589 for (i=0; i < numStops; i++) {
590 stops[i] = XDoubleToFixed(fractions[i]);
591 colors[i].alpha = pixels[i*4 + 0];
592 colors[i].red = pixels[i*4 + 1];
593 colors[i].green = pixels[i*4 + 2];
594 colors[i].blue = pixels[i*4 + 3];
595 }
596#ifdef __solaris__
597 if (XRenderCreateLinearGradientFunc!=NULL) {
598 gradient = (*XRenderCreateLinearGradientFunc)(awt_display, &grad, stops, colors, numStops);
599 }
600#else
601 gradient = XRenderCreateLinearGradient(awt_display, &grad, stops, colors, numStops);
602#endif
603 free(colors);
604 free(stops);
605
606 (*env)->ReleasePrimitiveArrayCritical(env, pixelsArray, pixels, JNI_ABORT);
607 (*env)->ReleasePrimitiveArrayCritical(env, fractionsArray, fractions, JNI_ABORT);
608
609 if (gradient != 0) {
610 pict_attr.repeat = repeat;
611 XRenderChangePicture (awt_display, gradient, CPRepeat, &pict_attr);
612 }
613
614 return (jint) gradient;
615}
616
617
618JNIEXPORT jint JNICALL
619Java_sun_java2d_xr_XRBackendNative_XRCreateRadialGradientPaintNative
620 (JNIEnv *env, jclass xsd, jfloatArray fractionsArray,
621 jshortArray pixelsArray, jint numStops,
622 jint centerX, jint centerY,
623 jint innerRadius, jint outerRadius, jint repeat) {
624 jint i;
625 jshort* pixels;
626 jfloat* fractions;
627 XRenderPictureAttributes pict_attr;
628 Picture gradient = 0;
629 XRenderColor *colors;
630 XFixed *stops;
631 XRadialGradient grad;
632
633 if (MAX_PAYLOAD / (sizeof(XRenderColor) + sizeof(XFixed))
634 < (unsigned)numStops) {
635 /* numStops too big, payload overflow */
636 return -1;
637 }
638
639 if ((pixels =
640 (jshort *)(*env)->GetPrimitiveArrayCritical(env, pixelsArray, NULL)) == NULL) {
641 return -1;
642 }
643 if ((fractions = (jfloat *)
644 (*env)->GetPrimitiveArrayCritical(env, fractionsArray, NULL)) == NULL) {
645 (*env)->ReleasePrimitiveArrayCritical(env,
646 pixelsArray, pixels, JNI_ABORT);
647 return -1; //TODO release pixels first
648 }
649
650 grad.inner.x = centerX;
651 grad.inner.y = centerY;
652 grad.inner.radius = innerRadius;
653 grad.outer.x = centerX;
654 grad.outer.y = centerY;
655 grad.outer.radius = outerRadius;
656
657 /*TODO optimized & malloc check*/
658 colors = (XRenderColor *) malloc(numStops * sizeof(XRenderColor));
659 stops = (XFixed *) malloc(numStops * sizeof(XFixed));
660
661 if (colors == NULL || stops == NULL) {
662 if (colors != NULL) {
663 free(colors);
664 }
665 if (stops != NULL) {
666 free(stops);
667 }
668 (*env)->ReleasePrimitiveArrayCritical(env, pixelsArray, pixels, JNI_ABORT);
669 (*env)->ReleasePrimitiveArrayCritical(env, fractionsArray, fractions, JNI_ABORT);
670 return -1;
671 }
672
673 for (i=0; i < numStops; i++) {
674 stops[i] = XDoubleToFixed(fractions[i]);
675 colors[i].alpha = pixels[i*4 + 0];
676 colors[i].red = pixels[i*4 + 1];
677 colors[i].green = pixels[i*4 + 2];
678 colors[i].blue = pixels[i*4 + 3];
679 }
680#ifdef __solaris__
681 if (XRenderCreateRadialGradientFunc != NULL) {
682 gradient = (jint) (*XRenderCreateRadialGradientFunc)(awt_display, &grad, stops, colors, numStops);
683 }
684#else
685 gradient = (jint) XRenderCreateRadialGradient(awt_display, &grad, stops, colors, numStops);
686#endif
687 free(colors);
688 free(stops);
689
690 (*env)->ReleasePrimitiveArrayCritical(env, pixelsArray, pixels, JNI_ABORT);
691 (*env)->ReleasePrimitiveArrayCritical(env, fractionsArray, fractions, JNI_ABORT);
692
693
694 if (gradient != 0) {
695 pict_attr.repeat = repeat;
696 XRenderChangePicture (awt_display, gradient, CPRepeat, &pict_attr);
697 }
698
699 return (jint) gradient;
700}
701
702JNIEXPORT void JNICALL
703Java_sun_java2d_xr_XRBackendNative_setFilter
704 (JNIEnv *env, jobject this, jint picture, jint filter) {
705
706 char * filterName = "fast";
707
708 switch(filter) {
709 case 0:
710 filterName = "fast";
711 break;
712
713 case 1:
714 filterName = "good";
715 break;
716
717 case 2:
718 filterName = "best";
719 break;
720 }
721
722 XRenderSetPictureFilter(awt_display, (Picture) picture, filterName, NULL, 0);
723}
724
725JNIEXPORT void JNICALL
726Java_sun_java2d_xr_XRBackendNative_XRSetClipNative
727 (JNIEnv *env, jclass xsd, jlong dst,
728 jint x1, jint y1, jint x2, jint y2,
729 jobject complexclip, jboolean isGC)
730{
731 int numrects;
732 XRectangle rects[256];
733 XRectangle *pRect = rects;
734
735 numrects = RegionToYXBandedRectangles(env,
736 x1, y1, x2, y2, complexclip,
737 &pRect, 256);
738
739 if (isGC == JNI_TRUE) {
740 if (dst != (jlong) 0) {
741 XSetClipRectangles(awt_display, (GC) jlong_to_ptr(dst), 0, 0, pRect, numrects, YXBanded);
742 }
743 } else {
744 XRenderSetPictureClipRectangles (awt_display, (Picture) dst, 0, 0, pRect, numrects);
745 }
746
747 if (pRect != rects) {
748 free(pRect);
749 }
750}
751
752JNIEXPORT void JNICALL
753Java_sun_java2d_xr_XRBackendNative_putMaskNative
754 (JNIEnv *env, jclass cls, jint drawable, jlong gc, jbyteArray imageData,
755 jint sx, jint sy, jint dx, jint dy, jint width, jint height,
756 jint maskOff, jint maskScan, jfloat ea, jlong imgPtr) {
757
758 int line, pix;
759 char *mask;
760 char *defaultData;
761 XImage *defaultImg, *img;
762 jboolean imageFits;
763
764 if ((mask = (char *)
765 (*env)->GetPrimitiveArrayCritical(env, imageData, NULL)) == NULL) {
766 return;
767 }
768
769 defaultImg = (XImage *) jlong_to_ptr(imgPtr);
770
771 if (ea != 1.0f) {
772 for (line=0; line < height; line++) {
773 for (pix=0; pix < width; pix++) {
774 int index = maskScan*line + pix + maskOff;
775 mask[index] = (((unsigned char) mask[index])*ea);
776 }
777 }
778 }
779
780 /*
781 * 1. If existing XImage and supplied buffer match, only adjust the data pointer
782 * 2. If existing XImage is large enough to hold the data but does not match in
783 * scan the data is copied to fit the XImage.
784 * 3. If data is larger than the existing XImage a new temporary XImage is
785 * allocated.
786 * The default XImage is optimized for the AA tiles, which are currently 32x32.
787 */
788 defaultData = defaultImg->data;
789 img = defaultImg;
790 imageFits = defaultImg->width >= width && defaultImg->height >= height;
791
792 if (imageFits &&
793 maskOff == defaultImg->xoffset && maskScan == defaultImg->bytes_per_line) {
794 defaultImg->data = mask;
795 } else {
796 if (imageFits) {
797 for (line=0; line < height; line++) {
798 for (pix=0; pix < width; pix++) {
799 img->data[line*img->bytes_per_line + pix] =
800 (unsigned char) (mask[maskScan*line + pix + maskOff]);
801 }
802 }
803 } else {
804 img = XCreateImage(awt_display, NULL, 8, ZPixmap,
805 maskOff, mask, maskScan, height, 8, 0);
806 }
807 }
808
809 XPutImage(awt_display, (Pixmap) drawable, (GC) jlong_to_ptr(gc),
810 img, 0, 0, 0, 0, width, height);
811 (*env)->ReleasePrimitiveArrayCritical(env, imageData, mask, JNI_ABORT);
812
813 if (img != defaultImg) {
814 img->data = NULL;
815 XDestroyImage(img);
816 }
817 defaultImg->data = defaultData;
818}
819
820JNIEXPORT void JNICALL
821Java_sun_java2d_xr_XRBackendNative_XRAddGlyphsNative
822 (JNIEnv *env, jclass cls, jint glyphSet,
823 jlongArray glyphInfoPtrsArray, jint glyphCnt,
824 jbyteArray pixelDataArray, int pixelDataLength) {
825 jlong *glyphInfoPtrs;
826 unsigned char *pixelData;
827 int i;
828
829 if (MAX_PAYLOAD / (sizeof(XGlyphInfo) + sizeof(Glyph))
830 < (unsigned)glyphCnt) {
831 /* glyphCnt too big, payload overflow */
832 return;
833 }
834
835 XGlyphInfo *xginfo = (XGlyphInfo *) malloc(sizeof(XGlyphInfo) * glyphCnt);
836 Glyph *gid = (Glyph *) malloc(sizeof(Glyph) * glyphCnt);
837
838 if (xginfo == NULL || gid == NULL) {
839 if (xginfo != NULL) {
840 free(xginfo);
841 }
842 if (gid != NULL) {
843 free(gid);
844 }
845 return;
846 }
847
848 if ((glyphInfoPtrs = (jlong *)(*env)->
849 GetPrimitiveArrayCritical(env, glyphInfoPtrsArray, NULL)) == NULL)
850 {
851 free(xginfo);
852 free(gid);
853 return;
854 }
855
856 if ((pixelData = (unsigned char *)
857 (*env)->GetPrimitiveArrayCritical(env, pixelDataArray, NULL)) == NULL)
858 {
859 (*env)->ReleasePrimitiveArrayCritical(env,
860 glyphInfoPtrsArray, glyphInfoPtrs, JNI_ABORT);
861 free(xginfo);
862 free(gid);
863 return;
864 }
865
866 for (i=0; i < glyphCnt; i++) {
867 GlyphInfo *jginfo = (GlyphInfo *) jlong_to_ptr(glyphInfoPtrs[i]);
868
869 // 'jginfo->cellInfo' is of type 'void*'
870 // (see definition of 'GlyphInfo' in fontscalerdefs.h)
871 // 'Glyph' is typedefed to 'unsigned long'
872 // (see http://www.x.org/releases/X11R7.7/doc/libXrender/libXrender.txt)
873 // Maybe we should assert that (sizeof(void*) == sizeof(Glyph)) ?
874 gid[i] = (Glyph) (jginfo->cellInfo);
875 xginfo[i].x = (-jginfo->topLeftX);
876 xginfo[i].y = (-jginfo->topLeftY);
877 xginfo[i].width = jginfo->width;
878 xginfo[i].height = jginfo->height;
879 xginfo[i].xOff = round(jginfo->advanceX);
880 xginfo[i].yOff = round(jginfo->advanceY);
881 }
882
883 XRenderAddGlyphs(awt_display, glyphSet, &gid[0], &xginfo[0], glyphCnt,
884 (const char*)pixelData, pixelDataLength);
885
886 (*env)->ReleasePrimitiveArrayCritical(env, glyphInfoPtrsArray, glyphInfoPtrs, JNI_ABORT);
887 (*env)->ReleasePrimitiveArrayCritical(env, pixelDataArray, pixelData, JNI_ABORT);
888
889 free(xginfo);
890 free(gid);
891}
892
893JNIEXPORT void JNICALL
894Java_sun_java2d_xr_XRBackendNative_XRFreeGlyphsNative
895 (JNIEnv *env, jclass cls, jint glyphSet, jintArray gidArray, jint glyphCnt) {
896
897 if (MAX_PAYLOAD / sizeof(Glyph) < (unsigned)glyphCnt) {
898 /* glyphCnt too big, payload overflow */
899 return;
900 }
901
902 /* The glyph ids are 32 bit but may be stored in a 64 bit long on
903 * a 64 bit architecture. So optimise the 32 bit case to avoid
904 * extra stack or heap allocations by directly referencing the
905 * underlying Java array and only allocate on 64 bit.
906 */
907 if (sizeof(jint) == sizeof(Glyph)) {
908 jint *gids =
909 (*env)->GetPrimitiveArrayCritical(env, gidArray, NULL);
910 if (gids == NULL) {
911 return;
912 } else {
913 XRenderFreeGlyphs(awt_display,
914 (GlyphSet)glyphSet, (Glyph *)gids, glyphCnt);
915 (*env)->ReleasePrimitiveArrayCritical(env, gidArray,
916 gids, JNI_ABORT);
917 }
918 return;
919 } else {
920 Glyph stack_ids[64];
921 Glyph *gids = NULL;
922 jint* jgids = NULL;
923 int i;
924
925 if (glyphCnt <= 64) {
926 gids = stack_ids;
927 } else {
928 gids = (Glyph *)malloc(sizeof(Glyph) * glyphCnt);
929 if (gids == NULL) {
930 return;
931 }
932 }
933 jgids = (*env)->GetPrimitiveArrayCritical(env, gidArray, NULL);
934 if (jgids == NULL) {
935 if (gids != stack_ids) {
936 free(gids);
937 }
938 return;
939 }
940 for (i=0; i < glyphCnt; i++) {
941 gids[i] = jgids[i];
942 }
943 XRenderFreeGlyphs(awt_display,
944 (GlyphSet) glyphSet, gids, glyphCnt);
945 (*env)->ReleasePrimitiveArrayCritical(env, gidArray,
946 jgids, JNI_ABORT);
947 if (gids != stack_ids) {
948 free(gids);
949 }
950 }
951}
952
953JNIEXPORT jint JNICALL
954Java_sun_java2d_xr_XRBackendNative_XRenderCreateGlyphSetNative
955 (JNIEnv *env, jclass cls, jlong format) {
956 return XRenderCreateGlyphSet(awt_display, (XRenderPictFormat *) jlong_to_ptr(format));
957}
958
959JNIEXPORT void JNICALL
960Java_sun_java2d_xr_XRBackendNative_XRenderCompositeTextNative
961 (JNIEnv *env, jclass cls, jint op, jint src, jint dst,
962 jint sx, jint sy, jlong maskFmt, jintArray eltArray,
963 jintArray glyphIDArray, jint eltCnt, jint glyphCnt) {
964 jint i;
965 jint *ids;
966 jint *elts;
967 XGlyphElt32 *xelts;
968 unsigned int *xids;
969 XGlyphElt32 selts[24];
970 unsigned int sids[256];
971 int charCnt = 0;
972
973 if ((MAX_PAYLOAD / sizeof(XGlyphElt32) < (unsigned)eltCnt)
974 || (MAX_PAYLOAD / sizeof(unsigned int) < (unsigned)glyphCnt)
975 || ((MAX_PAYLOAD - sizeof(XGlyphElt32)*(unsigned)eltCnt) /
976 sizeof(unsigned int) < (unsigned)glyphCnt))
977 {
978 /* (eltCnt, glyphCnt) too big, payload overflow */
979 return;
980 }
981
982 if (eltCnt <= 24) {
983 xelts = &selts[0];
984 }else {
985 xelts = (XGlyphElt32 *) malloc(sizeof(XGlyphElt32) * eltCnt);
986 if (xelts == NULL) {
987 return;
988 }
989 }
990
991 if (glyphCnt <= 256) {
992 xids = &sids[0];
993 } else {
994 xids = (unsigned int*)malloc(sizeof(unsigned int) * glyphCnt);
995 if (xids == NULL) {
996 if (xelts != &selts[0]) {
997 free(xelts);
998 }
999 return;
1000 }
1001 }
1002
1003 if ((ids = (jint *)
1004 (*env)->GetPrimitiveArrayCritical(env, glyphIDArray, NULL)) == NULL) {
1005 if (xelts != &selts[0]) {
1006 free(xelts);
1007 }
1008 if (xids != &sids[0]) {
1009 free(xids);
1010 }
1011 return;
1012 }
1013 if ((elts = (jint *)
1014 (*env)->GetPrimitiveArrayCritical(env, eltArray, NULL)) == NULL) {
1015 (*env)->ReleasePrimitiveArrayCritical(env,
1016 glyphIDArray, ids, JNI_ABORT);
1017 if (xelts != &selts[0]) {
1018 free(xelts);
1019 }
1020 if (xids != &sids[0]) {
1021 free(xids);
1022 }
1023 return;
1024 }
1025
1026 for (i=0; i < glyphCnt; i++) {
1027 xids[i] = ids[i];
1028 }
1029
1030 for (i=0; i < eltCnt; i++) {
1031 xelts[i].nchars = elts[i*4 + 0];
1032 xelts[i].xOff = elts[i*4 + 1];
1033 xelts[i].yOff = elts[i*4 + 2];
1034 xelts[i].glyphset = (GlyphSet) elts[i*4 + 3];
1035 xelts[i].chars = &xids[charCnt];
1036
1037 charCnt += xelts[i].nchars;
1038 }
1039
1040 XRenderCompositeText32(awt_display, op, (Picture) src, (Picture) dst,
1041 (XRenderPictFormat *) jlong_to_ptr(maskFmt),
1042 sx, sy, 0, 0, xelts, eltCnt);
1043
1044 (*env)->ReleasePrimitiveArrayCritical(env, glyphIDArray, ids, JNI_ABORT);
1045 (*env)->ReleasePrimitiveArrayCritical(env, eltArray, elts, JNI_ABORT);
1046
1047 if (xelts != &selts[0]) {
1048 free(xelts);
1049 }
1050
1051 if (xids != &sids[0]) {
1052 free(xids);
1053 }
1054}
1055
1056JNIEXPORT void JNICALL
1057Java_sun_java2d_xr_XRBackendNative_setGCMode
1058 (JNIEnv *env, jobject this, jlong gc, jboolean copy) {
1059 GC xgc = (GC) jlong_to_ptr(gc);
1060
1061 if (copy == JNI_TRUE) {
1062 XSetFunction(awt_display, xgc, GXcopy);
1063 } else {
1064 XSetFunction(awt_display, xgc, GXxor);
1065 }
1066}
1067
1068JNIEXPORT void JNICALL
1069Java_sun_java2d_xr_XRBackendNative_GCRectanglesNative
1070 (JNIEnv *env, jclass xsd, jint dst, jlong gc,
1071 jintArray rectArray, jint rectCnt) {
1072 int i;
1073 jint* rects;
1074 XRectangle *xRects;
1075 XRectangle sRects[256];
1076
1077 if (rectCnt <= 256) {
1078 xRects = &sRects[0];
1079 } else {
1080 if (MAXUINT / sizeof(XRectangle) < (unsigned)rectCnt) {
1081 /* rectCnt too big, integer overflow */
1082 return;
1083 }
1084
1085 xRects = (XRectangle *) malloc(sizeof(XRectangle) * rectCnt);
1086 if (xRects == NULL) {
1087 return;
1088 }
1089 }
1090
1091 if ((rects = (jint*)
1092 (*env)->GetPrimitiveArrayCritical(env, rectArray, NULL)) == NULL) {
1093 if (xRects != &sRects[0]) {
1094 free(xRects);
1095 }
1096 return;
1097 }
1098
1099 for (i=0; i < rectCnt; i++) {
1100 xRects[i].x = rects[i*4 + 0];
1101 xRects[i].y = rects[i*4 + 1];
1102 xRects[i].width = rects[i*4 + 2];
1103 xRects[i].height = rects[i*4 + 3];
1104 }
1105
1106 XFillRectangles(awt_display, (Drawable) dst, (GC) jlong_to_ptr(gc), xRects, rectCnt);
1107
1108 (*env)->ReleasePrimitiveArrayCritical(env, rectArray, rects, JNI_ABORT);
1109 if (xRects != &sRects[0]) {
1110 free(xRects);
1111 }
1112}
1113