1 | /* |
2 | * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. |
3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 | * |
5 | * This code is free software; you can redistribute it and/or modify it |
6 | * under the terms of the GNU General Public License version 2 only, as |
7 | * published by the Free Software Foundation. Oracle designates this |
8 | * particular file as subject to the "Classpath" exception as provided |
9 | * by Oracle in the LICENSE file that accompanied this code. |
10 | * |
11 | * This code is distributed in the hope that it will be useful, but WITHOUT |
12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
14 | * version 2 for more details (a copy is included in the LICENSE file that |
15 | * accompanied this code). |
16 | * |
17 | * You should have received a copy of the GNU General Public License version |
18 | * 2 along with this work; if not, write to the Free Software Foundation, |
19 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
20 | * |
21 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
22 | * or visit www.oracle.com if you need additional information or have any |
23 | * questions. |
24 | */ |
25 | |
26 | #include "X11SurfaceData.h" |
27 | #include "GraphicsPrimitiveMgr.h" |
28 | #include "Region.h" |
29 | #include "Trace.h" |
30 | |
31 | /* Needed to define intptr_t */ |
32 | #include "gdefs.h" |
33 | |
34 | #include "jni_util.h" |
35 | #include "jvm_md.h" |
36 | #include "awt_Component.h" |
37 | #include "awt_GraphicsEnv.h" |
38 | |
39 | #include <dlfcn.h> |
40 | |
41 | #ifndef HEADLESS |
42 | |
43 | /** |
44 | * This file contains support code for loops using the SurfaceData |
45 | * interface to talk to an X11 drawable from native code. |
46 | */ |
47 | |
48 | typedef struct _X11RIPrivate { |
49 | jint lockType; |
50 | jint lockFlags; |
51 | XImage *img; |
52 | int x, y; |
53 | } X11RIPrivate; |
54 | |
55 | #define XSD_MAX(a,b) ((a) > (b) ? (a) : (b)) |
56 | #define XSD_MIN(a,b) ((a) < (b) ? (a) : (b)) |
57 | |
58 | static LockFunc X11SD_Lock; |
59 | static GetRasInfoFunc X11SD_GetRasInfo; |
60 | static UnlockFunc X11SD_Unlock; |
61 | static DisposeFunc X11SD_Dispose; |
62 | static GetPixmapBgFunc X11SD_GetPixmapWithBg; |
63 | static ReleasePixmapBgFunc X11SD_ReleasePixmapWithBg; |
64 | extern int XShmAttachXErrHandler(Display *display, XErrorEvent *xerr); |
65 | extern AwtGraphicsConfigDataPtr |
66 | getGraphicsConfigFromComponentPeer(JNIEnv *env, jobject this); |
67 | extern struct X11GraphicsConfigIDs x11GraphicsConfigIDs; |
68 | |
69 | static int X11SD_FindClip(SurfaceDataBounds *b, SurfaceDataBounds *bounds, |
70 | X11SDOps *xsdo); |
71 | static int X11SD_ClipToRoot(SurfaceDataBounds *b, SurfaceDataBounds *bounds, |
72 | X11SDOps *xsdo); |
73 | static void X11SD_SwapBytes(X11SDOps *xsdo, XImage *img, int depth, int bpp); |
74 | static XImage * X11SD_GetImage(JNIEnv *env, X11SDOps *xsdo, |
75 | SurfaceDataBounds *bounds, |
76 | jint lockFlags); |
77 | |
78 | extern jfieldID validID; |
79 | |
80 | static int nativeByteOrder; |
81 | static jclass xorCompClass; |
82 | |
83 | jint useMitShmExt = CANT_USE_MITSHM; |
84 | jint useMitShmPixmaps = CANT_USE_MITSHM; |
85 | jint forceSharedPixmaps = JNI_FALSE; |
86 | |
87 | #ifdef MITSHM |
88 | int mitShmPermissionMask = MITSHM_PERM_OWNER; |
89 | #endif |
90 | |
91 | /* Cached shared image, one for all surface datas. */ |
92 | static XImage * cachedXImage; |
93 | |
94 | #endif /* !HEADLESS */ |
95 | |
96 | jboolean XShared_initIDs(JNIEnv *env, jboolean allowShmPixmaps) |
97 | { |
98 | #ifndef HEADLESS |
99 | union { |
100 | char c[4]; |
101 | int i; |
102 | } endian; |
103 | |
104 | endian.i = 0xff000000; |
105 | nativeByteOrder = (endian.c[0]) ? MSBFirst : LSBFirst; |
106 | |
107 | cachedXImage = NULL; |
108 | |
109 | if (sizeof(X11RIPrivate) > SD_RASINFO_PRIVATE_SIZE) { |
110 | JNU_ThrowInternalError(env, "Private RasInfo structure too large!" ); |
111 | return JNI_FALSE; |
112 | } |
113 | |
114 | #ifdef MITSHM |
115 | if (getenv("NO_AWT_MITSHM" ) == NULL && |
116 | getenv("NO_J2D_MITSHM" ) == NULL) { |
117 | char * force; |
118 | char * permission = getenv("J2D_MITSHM_PERMISSION" ); |
119 | if (permission != NULL) { |
120 | if (strcmp(permission, "common" ) == 0) { |
121 | mitShmPermissionMask = MITSHM_PERM_COMMON; |
122 | } |
123 | } |
124 | |
125 | TryInitMITShm(env, &useMitShmExt, &useMitShmPixmaps); |
126 | |
127 | if(allowShmPixmaps) { |
128 | useMitShmPixmaps = (useMitShmPixmaps == CAN_USE_MITSHM); |
129 | force = getenv("J2D_PIXMAPS" ); |
130 | if (force != NULL) { |
131 | if (useMitShmPixmaps && (strcmp(force, "shared" ) == 0)) { |
132 | forceSharedPixmaps = JNI_TRUE; |
133 | } else if (strcmp(force, "server" ) == 0) { |
134 | useMitShmPixmaps = JNI_FALSE; |
135 | } |
136 | } |
137 | }else { |
138 | useMitShmPixmaps = JNI_FALSE; |
139 | } |
140 | } |
141 | #endif /* MITSHM */ |
142 | |
143 | #endif /* !HEADLESS */ |
144 | |
145 | return JNI_TRUE; |
146 | } |
147 | |
148 | |
149 | /* |
150 | * Class: sun_java2d_x11_X11SurfaceData |
151 | * Method: initIDs |
152 | * Signature: (Ljava/lang/Class;Z)V |
153 | */ |
154 | JNIEXPORT void JNICALL |
155 | Java_sun_java2d_x11_X11SurfaceData_initIDs(JNIEnv *env, jclass xsd, |
156 | jclass XORComp) |
157 | { |
158 | #ifndef HEADLESS |
159 | if(XShared_initIDs(env, JNI_TRUE)) |
160 | { |
161 | xorCompClass = (*env)->NewGlobalRef(env, XORComp); |
162 | } |
163 | #endif /* !HEADLESS */ |
164 | } |
165 | |
166 | /* |
167 | * Class: sun_java2d_x11_X11SurfaceData |
168 | * Method: isDrawableValid |
169 | * Signature: ()Z |
170 | */ |
171 | JNIEXPORT jboolean JNICALL |
172 | Java_sun_java2d_x11_XSurfaceData_isDrawableValid(JNIEnv *env, jobject this) |
173 | { |
174 | jboolean ret = JNI_FALSE; |
175 | |
176 | #ifndef HEADLESS |
177 | X11SDOps *xsdo = X11SurfaceData_GetOps(env, this); |
178 | |
179 | AWT_LOCK(); |
180 | if (xsdo->drawable != 0 || X11SD_InitWindow(env, xsdo) == SD_SUCCESS) { |
181 | ret = JNI_TRUE; |
182 | } |
183 | AWT_UNLOCK(); |
184 | #endif /* !HEADLESS */ |
185 | |
186 | return ret; |
187 | } |
188 | |
189 | /* |
190 | * Class: sun_java2d_x11_X11SurfaceData |
191 | * Method: isShmPMAvailable |
192 | * Signature: ()Z |
193 | */ |
194 | JNIEXPORT jboolean JNICALL |
195 | Java_sun_java2d_x11_X11SurfaceData_isShmPMAvailable(JNIEnv *env, jobject this) |
196 | { |
197 | #if defined(HEADLESS) || !defined(MITSHM) |
198 | return JNI_FALSE; |
199 | #else |
200 | return (jboolean)useMitShmPixmaps; |
201 | #endif /* HEADLESS, MITSHM */ |
202 | } |
203 | |
204 | /* |
205 | * Class: sun_java2d_x11_X11SurfaceData |
206 | * Method: initOps |
207 | * Signature: (Ljava/lang/Object;I)V |
208 | */ |
209 | JNIEXPORT void JNICALL |
210 | Java_sun_java2d_x11_XSurfaceData_initOps(JNIEnv *env, jobject xsd, |
211 | jobject peer, |
212 | jobject graphicsConfig, jint depth) |
213 | { |
214 | #ifndef HEADLESS |
215 | X11SDOps *xsdo = (X11SDOps*)SurfaceData_InitOps(env, xsd, sizeof(X11SDOps)); |
216 | jboolean hasException; |
217 | if (xsdo == NULL) { |
218 | JNU_ThrowOutOfMemoryError(env, "Initialization of SurfaceData failed." ); |
219 | return; |
220 | } |
221 | xsdo->sdOps.Lock = X11SD_Lock; |
222 | xsdo->sdOps.GetRasInfo = X11SD_GetRasInfo; |
223 | xsdo->sdOps.Unlock = X11SD_Unlock; |
224 | xsdo->sdOps.Dispose = X11SD_Dispose; |
225 | xsdo->GetPixmapWithBg = X11SD_GetPixmapWithBg; |
226 | xsdo->ReleasePixmapWithBg = X11SD_ReleasePixmapWithBg; |
227 | if (peer != NULL) { |
228 | xsdo->drawable = JNU_CallMethodByName(env, &hasException, peer, "getWindow" , "()J" ).j; |
229 | if (hasException) { |
230 | return; |
231 | } |
232 | } else { |
233 | xsdo->drawable = 0; |
234 | } |
235 | xsdo->depth = depth; |
236 | xsdo->isPixmap = JNI_FALSE; |
237 | xsdo->bitmask = 0; |
238 | xsdo->bgPixel = 0; |
239 | xsdo->isBgInitialized = JNI_FALSE; |
240 | #ifdef MITSHM |
241 | xsdo->shmPMData.shmSegInfo = NULL; |
242 | xsdo->shmPMData.xRequestSent = JNI_FALSE; |
243 | xsdo->shmPMData.pmSize = 0; |
244 | xsdo->shmPMData.usingShmPixmap = JNI_FALSE; |
245 | xsdo->shmPMData.pixmap = 0; |
246 | xsdo->shmPMData.shmPixmap = 0; |
247 | xsdo->shmPMData.numBltsSinceRead = 0; |
248 | xsdo->shmPMData.pixelsReadSinceBlt = 0; |
249 | xsdo->shmPMData.numBltsThreshold = 2; |
250 | #endif /* MITSHM */ |
251 | |
252 | xsdo->configData = (AwtGraphicsConfigDataPtr) |
253 | JNU_GetLongFieldAsPtr(env, |
254 | graphicsConfig, |
255 | x11GraphicsConfigIDs.aData); |
256 | if (xsdo->configData == NULL) { |
257 | JNU_ThrowNullPointerException(env, |
258 | "Native GraphicsConfig data block missing" ); |
259 | return; |
260 | } |
261 | if (depth > 12) { |
262 | xsdo->pixelmask = (xsdo->configData->awt_visInfo.red_mask | |
263 | xsdo->configData->awt_visInfo.green_mask | |
264 | xsdo->configData->awt_visInfo.blue_mask); |
265 | } else if (depth == 12) { |
266 | xsdo->pixelmask = 0xfff; |
267 | } else { |
268 | xsdo->pixelmask = 0xff; |
269 | } |
270 | |
271 | xsdo->xrPic = None; |
272 | #endif /* !HEADLESS */ |
273 | } |
274 | |
275 | /* |
276 | * Class: sun_java2d_x11_X11SurfaceData |
277 | * Method: flushNativeSurface |
278 | * Signature: ()V |
279 | */ |
280 | JNIEXPORT void JNICALL |
281 | Java_sun_java2d_x11_XSurfaceData_flushNativeSurface(JNIEnv *env, jobject xsd) |
282 | { |
283 | #ifndef HEADLESS |
284 | SurfaceDataOps *ops = SurfaceData_GetOps(env, xsd); |
285 | |
286 | if (ops != NULL) { |
287 | X11SD_Dispose(env, ops); |
288 | } |
289 | #endif /* !HEADLESS */ |
290 | } |
291 | |
292 | |
293 | JNIEXPORT X11SDOps * JNICALL |
294 | X11SurfaceData_GetOps(JNIEnv *env, jobject sData) |
295 | { |
296 | #ifdef HEADLESS |
297 | return NULL; |
298 | #else |
299 | SurfaceDataOps *ops = SurfaceData_GetOps(env, sData); |
300 | if (ops != NULL && ops->Lock != X11SD_Lock) { |
301 | SurfaceData_ThrowInvalidPipeException(env, "not an X11 SurfaceData" ); |
302 | ops = NULL; |
303 | } |
304 | return (X11SDOps *) ops; |
305 | #endif /* !HEADLESS */ |
306 | } |
307 | |
308 | /* |
309 | * Method for disposing X11SD-specific data |
310 | */ |
311 | static void |
312 | X11SD_Dispose(JNIEnv *env, SurfaceDataOps *ops) |
313 | { |
314 | #ifndef HEADLESS |
315 | /* ops is assumed non-null as it is checked in SurfaceData_DisposeOps */ |
316 | X11SDOps * xsdo = (X11SDOps*)ops; |
317 | |
318 | AWT_LOCK(); |
319 | |
320 | xsdo->invalid = JNI_TRUE; |
321 | |
322 | if (xsdo->xrPic != None) { |
323 | XRenderFreePicture(awt_display, xsdo->xrPic); |
324 | xsdo->xrPic = None; |
325 | } |
326 | |
327 | if (xsdo->isPixmap == JNI_TRUE && xsdo->drawable != 0) { |
328 | #ifdef MITSHM |
329 | if (xsdo->shmPMData.shmSegInfo != NULL) { |
330 | X11SD_DropSharedSegment(xsdo->shmPMData.shmSegInfo); |
331 | xsdo->shmPMData.shmSegInfo = NULL; |
332 | } |
333 | if (xsdo->shmPMData.pixmap) { |
334 | XFreePixmap(awt_display, xsdo->shmPMData.pixmap); |
335 | xsdo->shmPMData.pixmap = 0; |
336 | } |
337 | if (xsdo->shmPMData.shmPixmap) { |
338 | XFreePixmap(awt_display, xsdo->shmPMData.shmPixmap); |
339 | xsdo->shmPMData.shmPixmap = 0; |
340 | } |
341 | #else |
342 | XFreePixmap(awt_display, xsdo->drawable); |
343 | #endif /* MITSHM */ |
344 | xsdo->drawable = 0; |
345 | } |
346 | if (xsdo->bitmask != 0) { |
347 | XFreePixmap(awt_display, xsdo->bitmask); |
348 | xsdo->bitmask = 0; |
349 | } |
350 | if (xsdo->javaGC != NULL) { |
351 | XFreeGC(awt_display, xsdo->javaGC); |
352 | xsdo->javaGC = NULL; |
353 | } |
354 | if (xsdo->cachedGC != NULL) { |
355 | XFreeGC(awt_display, xsdo->cachedGC); |
356 | xsdo->cachedGC = NULL; |
357 | } |
358 | |
359 | if(xsdo->xrPic != None) { |
360 | XRenderFreePicture(awt_display, xsdo->xrPic); |
361 | } |
362 | |
363 | AWT_UNLOCK(); |
364 | #endif /* !HEADLESS */ |
365 | } |
366 | /* |
367 | * Class: sun_java2d_x11_X11SurfaceData |
368 | * Method: setInvalid |
369 | * Signature: ()V |
370 | */ |
371 | JNIEXPORT void JNICALL |
372 | Java_sun_java2d_x11_XSurfaceData_setInvalid(JNIEnv *env, jobject xsd) |
373 | { |
374 | #ifndef HEADLESS |
375 | X11SDOps *xsdo = (X11SDOps *) SurfaceData_GetOps(env, xsd); |
376 | |
377 | if (xsdo != NULL) { |
378 | xsdo->invalid = JNI_TRUE; |
379 | } |
380 | #endif /* !HEADLESS */ |
381 | } |
382 | |
383 | |
384 | jboolean XShared_initSurface(JNIEnv *env, X11SDOps *xsdo, jint depth, jint width, jint height, jlong drawable) |
385 | { |
386 | #ifndef HEADLESS |
387 | |
388 | if (drawable != (jlong)0) { |
389 | /* Double-buffering */ |
390 | xsdo->drawable = drawable; |
391 | xsdo->isPixmap = JNI_FALSE; |
392 | } else { |
393 | /* |
394 | * width , height must be nonzero otherwise XCreatePixmap |
395 | * generates BadValue in error_handler |
396 | */ |
397 | if (width <= 0 || height <= 0 || width > 32767 || height > 32767) { |
398 | JNU_ThrowOutOfMemoryError(env, |
399 | "Can't create offscreen surface" ); |
400 | return JNI_FALSE; |
401 | } |
402 | xsdo->isPixmap = JNI_TRUE; |
403 | |
404 | xsdo->pmWidth = width; |
405 | xsdo->pmHeight = height; |
406 | |
407 | #ifdef MITSHM |
408 | xsdo->shmPMData.pmSize = width * height * depth; |
409 | xsdo->shmPMData.pixelsReadThreshold = width * height / 8; |
410 | if (forceSharedPixmaps) { |
411 | AWT_LOCK(); |
412 | xsdo->drawable = X11SD_CreateSharedPixmap(xsdo); |
413 | AWT_UNLOCK(); |
414 | JNU_CHECK_EXCEPTION_RETURN(env, JNI_FALSE); |
415 | if (xsdo->drawable) { |
416 | xsdo->shmPMData.usingShmPixmap = JNI_TRUE; |
417 | xsdo->shmPMData.shmPixmap = xsdo->drawable; |
418 | return JNI_TRUE; |
419 | } |
420 | } |
421 | #endif /* MITSHM */ |
422 | |
423 | AWT_LOCK(); |
424 | xsdo->drawable = |
425 | XCreatePixmap(awt_display, |
426 | RootWindow(awt_display, |
427 | xsdo->configData->awt_visInfo.screen), |
428 | width, height, depth); |
429 | AWT_UNLOCK(); |
430 | JNU_CHECK_EXCEPTION_RETURN(env, JNI_FALSE); |
431 | #ifdef MITSHM |
432 | xsdo->shmPMData.usingShmPixmap = JNI_FALSE; |
433 | xsdo->shmPMData.pixmap = xsdo->drawable; |
434 | #endif /* MITSHM */ |
435 | } |
436 | if (xsdo->drawable == 0) { |
437 | JNU_ThrowOutOfMemoryError(env, |
438 | "Can't create offscreen surface" ); |
439 | return JNI_FALSE; |
440 | } |
441 | |
442 | #endif /* !HEADLESS */ |
443 | return JNI_TRUE; |
444 | } |
445 | |
446 | |
447 | /* |
448 | * Class: sun_java2d_x11_X11SurfaceData |
449 | * Method: initSurface |
450 | * Signature: ()V |
451 | */ |
452 | JNIEXPORT void JNICALL |
453 | Java_sun_java2d_x11_X11SurfaceData_initSurface(JNIEnv *env, jclass xsd, |
454 | jint depth, |
455 | jint width, jint height, |
456 | jlong drawable) |
457 | { |
458 | #ifndef HEADLESS |
459 | X11SDOps *xsdo = X11SurfaceData_GetOps(env, xsd); |
460 | if (xsdo == NULL) { |
461 | return; |
462 | } |
463 | |
464 | if (xsdo->configData->awt_cmap == (Colormap)NULL) { |
465 | awtJNI_CreateColorData(env, xsdo->configData, 1); |
466 | JNU_CHECK_EXCEPTION(env); |
467 | } |
468 | /* color_data will be initialized in awtJNI_CreateColorData for |
469 | 8-bit visuals */ |
470 | xsdo->cData = xsdo->configData->color_data; |
471 | |
472 | XShared_initSurface(env, xsdo, depth, width, height, drawable); |
473 | xsdo->xrPic = None; |
474 | #endif /* !HEADLESS */ |
475 | } |
476 | |
477 | #ifndef HEADLESS |
478 | |
479 | #ifdef MITSHM |
480 | |
481 | void X11SD_DropSharedSegment(XShmSegmentInfo *shminfo) |
482 | { |
483 | if (shminfo != NULL) { |
484 | XShmDetach(awt_display, shminfo); |
485 | shmdt(shminfo->shmaddr); |
486 | /* REMIND: we don't need shmctl(shminfo->shmid, IPC_RMID, 0); here. */ |
487 | /* Check X11SD_CreateSharedImage() for the explanation */ |
488 | } |
489 | } |
490 | |
491 | XImage* X11SD_CreateSharedImage(X11SDOps *xsdo, |
492 | jint width, jint height) |
493 | { |
494 | XImage *img = NULL; |
495 | XShmSegmentInfo *shminfo; |
496 | |
497 | shminfo = malloc(sizeof(XShmSegmentInfo)); |
498 | if (shminfo == NULL) { |
499 | return NULL; |
500 | } |
501 | memset(shminfo, 0, sizeof(XShmSegmentInfo)); |
502 | |
503 | img = XShmCreateImage(awt_display, xsdo->configData->awt_visInfo.visual, |
504 | xsdo->depth, ZPixmap, NULL, shminfo, |
505 | width, height); |
506 | if (img == NULL) { |
507 | free((void *)shminfo); |
508 | return NULL; |
509 | } |
510 | shminfo->shmid = |
511 | shmget(IPC_PRIVATE, height * img->bytes_per_line, |
512 | IPC_CREAT|mitShmPermissionMask); |
513 | if (shminfo->shmid < 0) { |
514 | J2dRlsTraceLn1(J2D_TRACE_ERROR, |
515 | "X11SD_SetupSharedSegment shmget has failed: %s" , |
516 | strerror(errno)); |
517 | free((void *)shminfo); |
518 | XDestroyImage(img); |
519 | return NULL; |
520 | } |
521 | |
522 | shminfo->shmaddr = (char *) shmat(shminfo->shmid, 0, 0); |
523 | if (shminfo->shmaddr == ((char *) -1)) { |
524 | shmctl(shminfo->shmid, IPC_RMID, 0); |
525 | J2dRlsTraceLn1(J2D_TRACE_ERROR, |
526 | "X11SD_SetupSharedSegment shmat has failed: %s" , |
527 | strerror(errno)); |
528 | free((void *)shminfo); |
529 | XDestroyImage(img); |
530 | return NULL; |
531 | } |
532 | |
533 | shminfo->readOnly = False; |
534 | |
535 | resetXShmAttachFailed(); |
536 | EXEC_WITH_XERROR_HANDLER(XShmAttachXErrHandler, |
537 | XShmAttach(awt_display, shminfo)); |
538 | |
539 | /* |
540 | * Once the XSync round trip has finished then we |
541 | * can get rid of the id so that this segment does not stick |
542 | * around after we go away, holding system resources. |
543 | */ |
544 | shmctl(shminfo->shmid, IPC_RMID, 0); |
545 | |
546 | if (isXShmAttachFailed() == JNI_TRUE) { |
547 | J2dRlsTraceLn1(J2D_TRACE_ERROR, |
548 | "X11SD_SetupSharedSegment XShmAttach has failed: %s" , |
549 | strerror(errno)); |
550 | shmdt(shminfo->shmaddr); |
551 | free((void *)shminfo); |
552 | XDestroyImage(img); |
553 | return NULL; |
554 | } |
555 | |
556 | img->data = shminfo->shmaddr; |
557 | img->obdata = (char *)shminfo; |
558 | |
559 | return img; |
560 | } |
561 | |
562 | XImage* X11SD_GetSharedImage(X11SDOps *xsdo, jint width, jint height, |
563 | jint maxWidth, jint maxHeight, jboolean readBits) |
564 | { |
565 | XImage * retImage = NULL; |
566 | if (cachedXImage != NULL && |
567 | X11SD_CachedXImageFits(width, height, maxWidth, maxHeight, |
568 | xsdo->depth, readBits)) { |
569 | /* sync so previous data gets flushed */ |
570 | XSync(awt_display, False); |
571 | retImage = cachedXImage; |
572 | cachedXImage = (XImage *)NULL; |
573 | } else if (width * height * xsdo->depth > 0x10000) { |
574 | retImage = X11SD_CreateSharedImage(xsdo, width, height); |
575 | } |
576 | return retImage; |
577 | } |
578 | |
579 | Drawable X11SD_CreateSharedPixmap(X11SDOps *xsdo) |
580 | { |
581 | XShmSegmentInfo *shminfo; |
582 | XImage *img = NULL; |
583 | Drawable pixmap; |
584 | int scan; |
585 | int width = xsdo->pmWidth; |
586 | int height = xsdo->pmHeight; |
587 | |
588 | if (xsdo->shmPMData.pmSize < 0x10000) { |
589 | /* only use shared mem pixmaps for relatively big images */ |
590 | return 0; |
591 | } |
592 | |
593 | /* need to create shared(!) image to get bytes_per_line */ |
594 | img = X11SD_CreateSharedImage(xsdo, width, height); |
595 | if (img == NULL) { |
596 | return 0; |
597 | } |
598 | scan = img->bytes_per_line; |
599 | shminfo = (XShmSegmentInfo*)img->obdata; |
600 | XFree(img); |
601 | |
602 | pixmap = |
603 | XShmCreatePixmap(awt_display, |
604 | RootWindow(awt_display, |
605 | xsdo->configData->awt_visInfo.screen), |
606 | shminfo->shmaddr, shminfo, |
607 | width, height, xsdo->depth); |
608 | if (pixmap == 0) { |
609 | X11SD_DropSharedSegment(shminfo); |
610 | return 0; |
611 | } |
612 | |
613 | xsdo->shmPMData.shmSegInfo = shminfo; |
614 | xsdo->shmPMData.bytesPerLine = scan; |
615 | return pixmap; |
616 | } |
617 | |
618 | void X11SD_PuntPixmap(X11SDOps *xsdo, jint width, jint height) |
619 | { |
620 | |
621 | if (useMitShmPixmaps != CAN_USE_MITSHM || forceSharedPixmaps) { |
622 | return; |
623 | } |
624 | |
625 | /* we wouldn't be here if it's a shared pixmap, so no check |
626 | * for !usingShmPixmap. |
627 | */ |
628 | |
629 | xsdo->shmPMData.numBltsSinceRead = 0; |
630 | |
631 | xsdo->shmPMData.pixelsReadSinceBlt += width * height; |
632 | if (xsdo->shmPMData.pixelsReadSinceBlt > |
633 | xsdo->shmPMData.pixelsReadThreshold) { |
634 | if (!xsdo->shmPMData.shmPixmap) { |
635 | xsdo->shmPMData.shmPixmap = |
636 | X11SD_CreateSharedPixmap(xsdo); |
637 | } |
638 | if (xsdo->shmPMData.shmPixmap) { |
639 | GC xgc = XCreateGC(awt_display, xsdo->shmPMData.shmPixmap, 0L, NULL); |
640 | if (xgc != NULL) { |
641 | xsdo->shmPMData.usingShmPixmap = JNI_TRUE; |
642 | xsdo->drawable = xsdo->shmPMData.shmPixmap; |
643 | XCopyArea(awt_display, |
644 | xsdo->shmPMData.pixmap, xsdo->drawable, xgc, |
645 | 0, 0, xsdo->pmWidth, xsdo->pmHeight, 0, 0); |
646 | XSync(awt_display, False); |
647 | xsdo->shmPMData.xRequestSent = JNI_FALSE; |
648 | XFreeGC(awt_display, xgc); |
649 | } |
650 | } |
651 | } |
652 | } |
653 | |
654 | void X11SD_UnPuntPixmap(X11SDOps *xsdo) |
655 | { |
656 | if (useMitShmPixmaps != CAN_USE_MITSHM || forceSharedPixmaps) { |
657 | return; |
658 | } |
659 | xsdo->shmPMData.pixelsReadSinceBlt = 0; |
660 | if (xsdo->shmPMData.numBltsSinceRead >= |
661 | xsdo->shmPMData.numBltsThreshold) |
662 | { |
663 | if (xsdo->shmPMData.usingShmPixmap) { |
664 | if (!xsdo->shmPMData.pixmap) { |
665 | xsdo->shmPMData.pixmap = |
666 | XCreatePixmap(awt_display, |
667 | RootWindow(awt_display, |
668 | xsdo->configData->awt_visInfo.screen), |
669 | xsdo->pmWidth, xsdo->pmHeight, xsdo->depth); |
670 | } |
671 | if (xsdo->shmPMData.pixmap) { |
672 | GC xgc = XCreateGC(awt_display, xsdo->shmPMData.pixmap, 0L, NULL); |
673 | if (xgc != NULL) { |
674 | xsdo->drawable = xsdo->shmPMData.pixmap; |
675 | XCopyArea(awt_display, |
676 | xsdo->shmPMData.shmPixmap, xsdo->drawable, xgc, |
677 | 0, 0, xsdo->pmWidth, xsdo->pmHeight, 0, 0); |
678 | XSync(awt_display, False); |
679 | XFreeGC(awt_display, xgc); |
680 | xsdo->shmPMData.xRequestSent = JNI_FALSE; |
681 | xsdo->shmPMData.usingShmPixmap = JNI_FALSE; |
682 | xsdo->shmPMData.numBltsThreshold *= 2; |
683 | } |
684 | } |
685 | } |
686 | } else { |
687 | xsdo->shmPMData.numBltsSinceRead++; |
688 | } |
689 | } |
690 | |
691 | /** |
692 | * Determines if the cached image can be used for current operation. |
693 | * If the image is to be used to be read into by XShmGetImage, |
694 | * it must be close enough to avoid excessive reading from the screen; |
695 | * otherwise it should just be at least the size requested. |
696 | */ |
697 | jboolean X11SD_CachedXImageFits(jint width, jint height, jint maxWidth, |
698 | jint maxHeight, jint depth, jboolean readBits) |
699 | { |
700 | /* we assume here that the cached image exists */ |
701 | jint imgWidth = cachedXImage->width; |
702 | jint imgHeight = cachedXImage->height; |
703 | |
704 | if (imgWidth < width || imgHeight < height || depth != cachedXImage->depth) { |
705 | /* doesn't fit if any of the cached image dimensions is smaller |
706 | or the depths are different */ |
707 | return JNI_FALSE; |
708 | } |
709 | |
710 | if (!readBits) { |
711 | /* Not reading from this image, so any image at least of the |
712 | size requested will do */ |
713 | return JNI_TRUE; |
714 | } |
715 | |
716 | if ((imgWidth < width + 64) && (imgHeight < height + 64) |
717 | && imgWidth <= maxWidth && imgHeight <= maxHeight) |
718 | { |
719 | /* Cached image's width/height shouldn't be more than 64 pixels |
720 | * larger than requested, because the region in XShmGetImage |
721 | * can't be specified and we don't want to read too much. |
722 | * Furthermore it has to be smaller than maxWidth/Height |
723 | * so drawables are not read out of bounds. |
724 | */ |
725 | return JNI_TRUE; |
726 | } |
727 | |
728 | return JNI_FALSE; |
729 | } |
730 | #endif /* MITSHM */ |
731 | |
732 | jint X11SD_InitWindow(JNIEnv *env, X11SDOps *xsdo) |
733 | { |
734 | if (xsdo->isPixmap == JNI_TRUE) { |
735 | return SD_FAILURE; |
736 | } |
737 | xsdo->cData = xsdo->configData->color_data; |
738 | |
739 | return SD_SUCCESS; |
740 | } |
741 | |
742 | static jint X11SD_Lock(JNIEnv *env, |
743 | SurfaceDataOps *ops, |
744 | SurfaceDataRasInfo *pRasInfo, |
745 | jint lockflags) |
746 | { |
747 | X11SDOps *xsdo = (X11SDOps *) ops; |
748 | X11RIPrivate *xpriv = (X11RIPrivate *) &(pRasInfo->priv); |
749 | int ret = SD_SUCCESS; |
750 | |
751 | AWT_LOCK(); |
752 | |
753 | if (xsdo->invalid) { |
754 | AWT_UNLOCK(); |
755 | SurfaceData_ThrowInvalidPipeException(env, "bounds changed" ); |
756 | return SD_FAILURE; |
757 | } |
758 | xsdo->cData = xsdo->configData->color_data; |
759 | if (xsdo->drawable == 0 && X11SD_InitWindow(env, xsdo) == SD_FAILURE) { |
760 | AWT_UNLOCK(); |
761 | return SD_FAILURE; |
762 | } |
763 | if ((lockflags & SD_LOCK_LUT) != 0 && |
764 | (xsdo->cData == NULL || |
765 | xsdo->cData->awt_icmLUT == NULL)) |
766 | { |
767 | AWT_UNLOCK(); |
768 | if (!(*env)->ExceptionCheck(env)) |
769 | { |
770 | JNU_ThrowNullPointerException(env, "colormap lookup table" ); |
771 | } |
772 | return SD_FAILURE; |
773 | } |
774 | if ((lockflags & SD_LOCK_INVCOLOR) != 0 && |
775 | (xsdo->cData == NULL || |
776 | xsdo->cData->img_clr_tbl == NULL || |
777 | xsdo->cData->img_oda_red == NULL || |
778 | xsdo->cData->img_oda_green == NULL || |
779 | xsdo->cData->img_oda_blue == NULL)) |
780 | { |
781 | AWT_UNLOCK(); |
782 | if (!(*env)->ExceptionCheck(env)) |
783 | { |
784 | JNU_ThrowNullPointerException(env, "inverse colormap lookup table" ); |
785 | } |
786 | return SD_FAILURE; |
787 | } |
788 | if ((lockflags & SD_LOCK_INVGRAY) != 0 && |
789 | (xsdo->cData == NULL || |
790 | xsdo->cData->pGrayInverseLutData == NULL)) |
791 | { |
792 | AWT_UNLOCK(); |
793 | if (!(*env)->ExceptionCheck(env)) |
794 | { |
795 | JNU_ThrowNullPointerException(env, "inverse gray lookup table" ); |
796 | } |
797 | return SD_FAILURE; |
798 | } |
799 | if (lockflags & SD_LOCK_RD_WR) { |
800 | if (lockflags & SD_LOCK_FASTEST) { |
801 | ret = SD_SLOWLOCK; |
802 | } |
803 | xpriv->lockType = X11SD_LOCK_BY_XIMAGE; |
804 | if (xsdo->isPixmap) { |
805 | #ifdef MITSHM |
806 | if (xsdo->shmPMData.usingShmPixmap) { |
807 | xpriv->lockType = X11SD_LOCK_BY_SHMEM; |
808 | } |
809 | #endif /* MITSHM */ |
810 | if (pRasInfo->bounds.x1 < 0) { |
811 | pRasInfo->bounds.x1 = 0; |
812 | } |
813 | if (pRasInfo->bounds.y1 < 0) { |
814 | pRasInfo->bounds.y1 = 0; |
815 | } |
816 | if (pRasInfo->bounds.x2 > xsdo->pmWidth) { |
817 | pRasInfo->bounds.x2 = xsdo->pmWidth; |
818 | } |
819 | if (pRasInfo->bounds.y2 > xsdo->pmHeight) { |
820 | pRasInfo->bounds.y2 = xsdo->pmHeight; |
821 | } |
822 | } |
823 | } else { |
824 | /* They didn't lock for anything - we won't give them anything */ |
825 | xpriv->lockType = X11SD_LOCK_BY_NULL; |
826 | } |
827 | xpriv->lockFlags = lockflags; |
828 | xpriv->img = NULL; |
829 | |
830 | return ret; |
831 | /* AWT_UNLOCK() called in Unlock */ |
832 | } |
833 | |
834 | static void X11SD_GetRasInfo(JNIEnv *env, |
835 | SurfaceDataOps *ops, |
836 | SurfaceDataRasInfo *pRasInfo) |
837 | { |
838 | X11SDOps *xsdo = (X11SDOps *) ops; |
839 | X11RIPrivate *xpriv = (X11RIPrivate *) &(pRasInfo->priv); |
840 | jint lockFlags = xpriv->lockFlags; |
841 | jint depth = xsdo->depth; |
842 | int mult = xsdo->configData->pixelStride; |
843 | |
844 | |
845 | #ifdef MITSHM |
846 | if (xpriv->lockType == X11SD_LOCK_BY_SHMEM) { |
847 | if (xsdo->shmPMData.xRequestSent == JNI_TRUE) { |
848 | /* need to sync before using shared mem pixmap |
849 | if any x calls were issued for this pixmap */ |
850 | XSync(awt_display, False); |
851 | xsdo->shmPMData.xRequestSent = JNI_FALSE; |
852 | } |
853 | xpriv->x = pRasInfo->bounds.x1; |
854 | xpriv->y = pRasInfo->bounds.y1; |
855 | pRasInfo->rasBase = xsdo->shmPMData.shmSegInfo->shmaddr; |
856 | pRasInfo->pixelStride = mult; |
857 | pRasInfo->pixelBitOffset = 0; |
858 | pRasInfo->scanStride = xsdo->shmPMData.bytesPerLine; |
859 | } else |
860 | #endif /* MITSHM */ |
861 | if (xpriv->lockType == X11SD_LOCK_BY_XIMAGE) { |
862 | int x, y, w, h; |
863 | x = pRasInfo->bounds.x1; |
864 | y = pRasInfo->bounds.y1; |
865 | w = pRasInfo->bounds.x2 - x; |
866 | h = pRasInfo->bounds.y2 - y; |
867 | |
868 | xpriv->img = X11SD_GetImage(env, xsdo, &pRasInfo->bounds, lockFlags); |
869 | if (xpriv->img) { |
870 | int scan = xpriv->img->bytes_per_line; |
871 | xpriv->x = x; |
872 | xpriv->y = y; |
873 | pRasInfo->rasBase = xpriv->img->data - x * mult - y * scan; |
874 | pRasInfo->pixelStride = mult; |
875 | pRasInfo->pixelBitOffset = 0; |
876 | pRasInfo->scanStride = scan; |
877 | } else { |
878 | pRasInfo->rasBase = NULL; |
879 | pRasInfo->pixelStride = 0; |
880 | pRasInfo->pixelBitOffset = 0; |
881 | pRasInfo->scanStride = 0; |
882 | } |
883 | } else { |
884 | /* They didn't lock for anything - we won't give them anything */ |
885 | pRasInfo->rasBase = NULL; |
886 | pRasInfo->pixelStride = 0; |
887 | pRasInfo->pixelBitOffset = 0; |
888 | pRasInfo->scanStride = 0; |
889 | } |
890 | if (lockFlags & SD_LOCK_LUT) { |
891 | pRasInfo->lutBase = (jint *) xsdo->cData->awt_icmLUT; |
892 | pRasInfo->lutSize = xsdo->cData->awt_numICMcolors; |
893 | } else { |
894 | pRasInfo->lutBase = NULL; |
895 | pRasInfo->lutSize = 0; |
896 | } |
897 | if (lockFlags & SD_LOCK_INVCOLOR) { |
898 | pRasInfo->invColorTable = xsdo->cData->img_clr_tbl; |
899 | pRasInfo->redErrTable = xsdo->cData->img_oda_red; |
900 | pRasInfo->grnErrTable = xsdo->cData->img_oda_green; |
901 | pRasInfo->bluErrTable = xsdo->cData->img_oda_blue; |
902 | } else { |
903 | pRasInfo->invColorTable = NULL; |
904 | pRasInfo->redErrTable = NULL; |
905 | pRasInfo->grnErrTable = NULL; |
906 | pRasInfo->bluErrTable = NULL; |
907 | } |
908 | if (lockFlags & SD_LOCK_INVGRAY) { |
909 | pRasInfo->invGrayTable = xsdo->cData->pGrayInverseLutData; |
910 | } else { |
911 | pRasInfo->invGrayTable = NULL; |
912 | } |
913 | } |
914 | |
915 | static void X11SD_Unlock(JNIEnv *env, |
916 | SurfaceDataOps *ops, |
917 | SurfaceDataRasInfo *pRasInfo) |
918 | { |
919 | X11SDOps *xsdo = (X11SDOps *) ops; |
920 | X11RIPrivate *xpriv = (X11RIPrivate *) &(pRasInfo->priv); |
921 | |
922 | if (xpriv->lockType == X11SD_LOCK_BY_XIMAGE && |
923 | xpriv->img != NULL) |
924 | { |
925 | if (xpriv->lockFlags & SD_LOCK_WRITE) { |
926 | int x = xpriv->x; |
927 | int y = xpriv->y; |
928 | int w = pRasInfo->bounds.x2 - x; |
929 | int h = pRasInfo->bounds.y2 - y; |
930 | Drawable drawable = xsdo->drawable; |
931 | GC xgc = xsdo->cachedGC; |
932 | if (xgc == NULL) { |
933 | xsdo->cachedGC = xgc = |
934 | XCreateGC(awt_display, drawable, 0L, NULL); |
935 | } |
936 | |
937 | if (xpriv->img->byte_order != nativeByteOrder) { |
938 | /* switching bytes back in 24 and 32 bpp cases. */ |
939 | /* For 16 bit XLib will switch for us. */ |
940 | if (xsdo->depth > 16) { |
941 | X11SD_SwapBytes(xsdo, xpriv->img, xsdo->depth, |
942 | xsdo->configData->awtImage->wsImageFormat.bits_per_pixel); |
943 | } |
944 | } |
945 | |
946 | #ifdef MITSHM |
947 | if (xpriv->img->obdata != NULL) { |
948 | XShmPutImage(awt_display, drawable, xgc, |
949 | xpriv->img, 0, 0, x, y, w, h, False); |
950 | XFlush(awt_display); |
951 | } else { |
952 | XPutImage(awt_display, drawable, xgc, |
953 | xpriv->img, 0, 0, x, y, w, h); |
954 | } |
955 | if (xsdo->shmPMData.usingShmPixmap) { |
956 | xsdo->shmPMData.xRequestSent = JNI_TRUE; |
957 | } |
958 | #else |
959 | XPutImage(awt_display, drawable, xgc, |
960 | xpriv->img, 0, 0, x, y, w, h); |
961 | #endif /* MITSHM */ |
962 | |
963 | } |
964 | X11SD_DisposeOrCacheXImage(xpriv->img); |
965 | xpriv->img = (XImage *)NULL; |
966 | } |
967 | /* the background pixel is not valid anymore */ |
968 | if (xpriv->lockFlags & SD_LOCK_WRITE) { |
969 | xsdo->isBgInitialized = JNI_FALSE; |
970 | } |
971 | xpriv->lockType = X11SD_LOCK_UNLOCKED; |
972 | AWT_UNLOCK(); |
973 | } |
974 | |
975 | static int |
976 | X11SD_ClipToRoot(SurfaceDataBounds *b, SurfaceDataBounds *bounds, |
977 | X11SDOps *xsdo) |
978 | { |
979 | short x1=0, y1=0, x2=0, y2=0; |
980 | int tmpx, tmpy; |
981 | Window tmpchild; |
982 | |
983 | Window window = (Window)(xsdo->drawable); /* is always a Window */ |
984 | XWindowAttributes winAttr; |
985 | |
986 | Status status = XGetWindowAttributes(awt_display, window, &winAttr); |
987 | if (status == 0) { |
988 | /* Failure, X window no longer valid. */ |
989 | return FALSE; |
990 | } |
991 | if (!XTranslateCoordinates(awt_display, window, |
992 | RootWindowOfScreen(winAttr.screen), |
993 | 0, 0, &tmpx, &tmpy, &tmpchild)) { |
994 | return FALSE; |
995 | } |
996 | |
997 | x1 = -(x1 + tmpx); |
998 | y1 = -(y1 + tmpy); |
999 | |
1000 | x2 = x1 + DisplayWidth(awt_display, xsdo->configData->awt_visInfo.screen); |
1001 | y2 = y1 + DisplayHeight(awt_display, xsdo->configData->awt_visInfo.screen); |
1002 | |
1003 | x1 = XSD_MAX(bounds->x1, x1); |
1004 | y1 = XSD_MAX(bounds->y1, y1); |
1005 | x2 = XSD_MIN(bounds->x2, x2); |
1006 | y2 = XSD_MIN(bounds->y2, y2); |
1007 | if ((x1 >= x2) || (y1 >= y2)) { |
1008 | return FALSE; |
1009 | } |
1010 | b->x1 = x1; |
1011 | b->y1 = y1; |
1012 | b->x2 = x2; |
1013 | b->y2 = y2; |
1014 | |
1015 | return TRUE; |
1016 | } |
1017 | |
1018 | /* |
1019 | * x1, y1, x2, y2 - our rectangle in the coord system of |
1020 | * the widget |
1021 | * px1, xy1, px2, py2 - current parent rect coords in the |
1022 | * same system |
1023 | */ |
1024 | static int |
1025 | X11SD_FindClip(SurfaceDataBounds *b, SurfaceDataBounds *bounds, X11SDOps *xsdo) |
1026 | { |
1027 | return TRUE; |
1028 | } |
1029 | |
1030 | static void |
1031 | X11SD_SwapBytes(X11SDOps *xsdo, XImage * img, int depth, int bpp) { |
1032 | int lengthInBytes = img->height * img->bytes_per_line; |
1033 | int i; |
1034 | |
1035 | switch (depth) { |
1036 | case 12: |
1037 | case 15: |
1038 | case 16: |
1039 | { |
1040 | /* AB -> BA */ |
1041 | unsigned short *d = (unsigned short *)img->data; |
1042 | unsigned short t; |
1043 | for (i = 0; i < lengthInBytes/2; i++) { |
1044 | t = *d; |
1045 | *d++ = (t >> 8) | (t << 8); |
1046 | } |
1047 | img->byte_order = nativeByteOrder; |
1048 | img->bitmap_bit_order = nativeByteOrder; |
1049 | break; |
1050 | } |
1051 | case 24: |
1052 | { |
1053 | /* ABC -> CBA */ |
1054 | if (bpp == 24) { |
1055 | // 4517321: Only swap if we have a "real" ThreeByteBgr |
1056 | // visual (denoted by a red_mask of 0xff). Due to ambiguity |
1057 | // in the X11 spec, it appears that the swap is not required |
1058 | // on Linux configurations that use 24 bits per pixel (denoted |
1059 | // by a red_mask of 0xff0000). |
1060 | if (xsdo->configData->awt_visInfo.red_mask == 0xff) { |
1061 | int scan = img->bytes_per_line; |
1062 | unsigned char *d = (unsigned char *) img->data; |
1063 | unsigned char *d1; |
1064 | unsigned int t; |
1065 | int j; |
1066 | |
1067 | for (i = 0; i < img->height; i++, d += scan) { |
1068 | d1 = d; |
1069 | for (j = 0; j < img->width; j++, d1 += 3) { |
1070 | /* not obvious opt from XLib src */ |
1071 | t = d1[0]; d1[0] = d1[2]; d1[2] = t; |
1072 | } |
1073 | } |
1074 | } |
1075 | break; |
1076 | } |
1077 | } |
1078 | /* FALL THROUGH for 32-bit case */ |
1079 | case 32: |
1080 | { |
1081 | /* ABCD -> DCBA */ |
1082 | unsigned int *d = (unsigned int *) img->data; |
1083 | unsigned int t; |
1084 | for (i = 0; i < lengthInBytes/4; i++) { |
1085 | t = *d; |
1086 | *d++ = ((t >> 24) | |
1087 | ((t >> 8) & 0xff00) | |
1088 | ((t & 0xff00) << 8) | |
1089 | (t << 24)); |
1090 | } |
1091 | break; |
1092 | } |
1093 | } |
1094 | } |
1095 | |
1096 | static XImage * X11SD_GetImage(JNIEnv *env, X11SDOps *xsdo, |
1097 | SurfaceDataBounds *bounds, |
1098 | jint lockFlags) |
1099 | { |
1100 | int x, y, w, h, maxWidth, maxHeight; |
1101 | int scan; |
1102 | XImage * img = NULL; |
1103 | Drawable drawable; |
1104 | int depth = xsdo->depth; |
1105 | int mult = xsdo->configData->pixelStride; |
1106 | int pad = (mult == 3) ? 32 : mult * 8; // pad must be 8, 16, or 32 |
1107 | jboolean readBits = lockFlags & SD_LOCK_NEED_PIXELS; |
1108 | |
1109 | x = bounds->x1; |
1110 | y = bounds->y1; |
1111 | w = bounds->x2 - x; |
1112 | h = bounds->y2 - y; |
1113 | |
1114 | #ifdef MITSHM |
1115 | if (useMitShmExt == CAN_USE_MITSHM) { |
1116 | if (xsdo->isPixmap) { |
1117 | if (readBits) { |
1118 | X11SD_PuntPixmap(xsdo, w, h); |
1119 | } |
1120 | maxWidth = xsdo->pmWidth; |
1121 | maxHeight = xsdo->pmHeight; |
1122 | } else { |
1123 | XWindowAttributes winAttr; |
1124 | if (XGetWindowAttributes(awt_display, |
1125 | (Window) xsdo->drawable, &winAttr) != 0) { |
1126 | maxWidth = winAttr.width; |
1127 | maxHeight = winAttr.height; |
1128 | } else { |
1129 | /* XGWA failed which isn't a good thing. Defaulting to using |
1130 | * x,y means that after the subtraction of these we will use |
1131 | * w=0, h=0 which is a reasonable default on such a failure. |
1132 | */ |
1133 | maxWidth = x; |
1134 | maxHeight = y; |
1135 | } |
1136 | } |
1137 | maxWidth -= x; |
1138 | maxHeight -= y; |
1139 | |
1140 | img = X11SD_GetSharedImage(xsdo, w, h, maxWidth, maxHeight, readBits); |
1141 | } |
1142 | #endif /* MITSHM */ |
1143 | drawable = xsdo->drawable; |
1144 | |
1145 | if (readBits) { |
1146 | #ifdef MITSHM |
1147 | if (img != NULL) { |
1148 | if (!XShmGetImage(awt_display, drawable, img, x, y, -1)) { |
1149 | X11SD_DisposeOrCacheXImage(img); |
1150 | img = NULL; |
1151 | } |
1152 | } |
1153 | if (img == NULL) { |
1154 | img = XGetImage(awt_display, drawable, x, y, w, h, -1, ZPixmap); |
1155 | if (img != NULL) { |
1156 | img->obdata = NULL; |
1157 | } |
1158 | } |
1159 | #else |
1160 | img = XGetImage(awt_display, drawable, x, y, w, h, -1, ZPixmap); |
1161 | #endif /* MITSHM */ |
1162 | if (img == NULL) { |
1163 | SurfaceDataBounds temp; |
1164 | img = XCreateImage(awt_display, |
1165 | xsdo->configData->awt_visInfo.visual, |
1166 | depth, ZPixmap, 0, NULL, w, h, pad, 0); |
1167 | if (img == NULL) { |
1168 | return NULL; |
1169 | } |
1170 | |
1171 | scan = img->bytes_per_line; |
1172 | img->data = malloc(h * scan); |
1173 | if (img->data == NULL) { |
1174 | XFree(img); |
1175 | return NULL; |
1176 | } |
1177 | |
1178 | if (xsdo->isPixmap == JNI_FALSE && |
1179 | X11SD_ClipToRoot(&temp, bounds, xsdo)) { |
1180 | |
1181 | XImage * temp_image; |
1182 | temp_image = XGetImage(awt_display, drawable, |
1183 | temp.x1, temp.y1, |
1184 | temp.x2 - temp.x1, |
1185 | temp.y2 - temp.y1, |
1186 | -1, ZPixmap); |
1187 | if (temp_image == NULL) { |
1188 | XGrabServer(awt_display); |
1189 | if (X11SD_FindClip(&temp, bounds, xsdo)) { |
1190 | temp_image = |
1191 | XGetImage(awt_display, drawable, |
1192 | temp.x1, temp.y1, |
1193 | temp.x2 - temp.x1, |
1194 | temp.y2 - temp.y1, |
1195 | -1, ZPixmap); |
1196 | } |
1197 | XUngrabServer(awt_display); |
1198 | /* Workaround for bug 5039226 */ |
1199 | XSync(awt_display, False); |
1200 | } |
1201 | if (temp_image != NULL) { |
1202 | int temp_scan, bytes_to_copy; |
1203 | char * img_addr, * temp_addr; |
1204 | int i; |
1205 | |
1206 | img_addr = img->data + |
1207 | (temp.y1 - y) * scan + (temp.x1 - x) * mult; |
1208 | temp_scan = temp_image->bytes_per_line; |
1209 | temp_addr = temp_image->data; |
1210 | bytes_to_copy = (temp.x2 - temp.x1) * mult; |
1211 | for (i = temp.y1; i < temp.y2; i++) { |
1212 | memcpy(img_addr, temp_addr, bytes_to_copy); |
1213 | img_addr += scan; |
1214 | temp_addr += temp_scan; |
1215 | } |
1216 | XDestroyImage(temp_image); |
1217 | } |
1218 | } |
1219 | img->obdata = NULL; |
1220 | } |
1221 | if (depth > 8 && img->byte_order != nativeByteOrder) { |
1222 | X11SD_SwapBytes(xsdo, img, depth, |
1223 | xsdo->configData->awtImage->wsImageFormat.bits_per_pixel); |
1224 | } |
1225 | } else { |
1226 | /* |
1227 | * REMIND: This might be better to move to the Lock function |
1228 | * to avoid lengthy I/O pauses inside what may be a critical |
1229 | * section. This will be more critical when SD_LOCK_READ is |
1230 | * implemented. Another solution is to cache the pixels |
1231 | * to avoid reading for every operation. |
1232 | */ |
1233 | if (img == NULL) { |
1234 | img = XCreateImage(awt_display, |
1235 | xsdo->configData->awt_visInfo.visual, |
1236 | depth, ZPixmap, 0, NULL, w, h, pad, 0); |
1237 | if (img == NULL) { |
1238 | return NULL; |
1239 | } |
1240 | |
1241 | img->data = malloc(h * img->bytes_per_line); |
1242 | if (img->data == NULL) { |
1243 | XFree(img); |
1244 | return NULL; |
1245 | } |
1246 | |
1247 | img->obdata = NULL; |
1248 | |
1249 | if (img->byte_order != nativeByteOrder && |
1250 | (depth == 15 || depth == 16 || depth == 12)) { |
1251 | /* bytes will be swapped by XLib. */ |
1252 | img->byte_order = nativeByteOrder; |
1253 | img->bitmap_bit_order = nativeByteOrder; |
1254 | } |
1255 | } |
1256 | } |
1257 | return img; |
1258 | } |
1259 | |
1260 | void X11SD_DisposeOrCacheXImage(XImage * image) { |
1261 | /* REMIND: might want to check if the new image worth caching. */ |
1262 | /* Cache only shared images. Passed image is assumed to be non-null. */ |
1263 | if (image->obdata != NULL) { |
1264 | if (cachedXImage != NULL) { |
1265 | X11SD_DisposeXImage(cachedXImage); |
1266 | } |
1267 | cachedXImage = image; |
1268 | } else { |
1269 | X11SD_DisposeXImage(image); |
1270 | } |
1271 | } |
1272 | |
1273 | void X11SD_DisposeXImage(XImage * image) { |
1274 | if (image != NULL) { |
1275 | #ifdef MITSHM |
1276 | if (image->obdata != NULL) { |
1277 | X11SD_DropSharedSegment((XShmSegmentInfo*)image->obdata); |
1278 | image->obdata = NULL; |
1279 | } |
1280 | #endif /* MITSHM */ |
1281 | XDestroyImage(image); |
1282 | } |
1283 | } |
1284 | |
1285 | void |
1286 | X11SD_DirectRenderNotify(JNIEnv *env, X11SDOps *xsdo) |
1287 | { |
1288 | #ifdef MITSHM |
1289 | if (xsdo->shmPMData.usingShmPixmap) { |
1290 | xsdo->shmPMData.xRequestSent = JNI_TRUE; |
1291 | } |
1292 | #endif /* MITSHM */ |
1293 | awt_output_flush(); |
1294 | } |
1295 | |
1296 | /* |
1297 | * Sets transparent pixels in the pixmap to |
1298 | * the specified solid background color and returns it. |
1299 | * Doesn't update source pixmap unless the color of the |
1300 | * transparent pixels is different from the specified color. |
1301 | * |
1302 | * Note: The AWT lock must be held by the current thread |
1303 | * while calling into this method. |
1304 | */ |
1305 | static Drawable |
1306 | X11SD_GetPixmapWithBg(JNIEnv *env, X11SDOps *xsdo, jint pixel) |
1307 | { |
1308 | /* assert AWT_CHECK_HAVE_LOCK(); */ |
1309 | |
1310 | if (xsdo->invalid) { |
1311 | AWT_UNLOCK(); |
1312 | SurfaceData_ThrowInvalidPipeException(env, "bounds changed" ); |
1313 | return 0; |
1314 | } |
1315 | |
1316 | /* the image doesn't have transparency, just return it */ |
1317 | if (xsdo->bitmask == 0) { |
1318 | /* don't need to unlock here, the caller will unlock through |
1319 | the release call */ |
1320 | return xsdo->drawable; |
1321 | } |
1322 | |
1323 | /* Check if current color of the transparent pixels is different |
1324 | from the specified one */ |
1325 | if (xsdo->isBgInitialized == JNI_FALSE || xsdo->bgPixel != pixel) { |
1326 | GC srcGC; |
1327 | GC bmGC; |
1328 | |
1329 | if (xsdo->drawable == 0) { |
1330 | AWT_UNLOCK(); |
1331 | return 0; |
1332 | } |
1333 | |
1334 | bmGC = XCreateGC(awt_display, xsdo->bitmask, 0, NULL); |
1335 | if (bmGC == NULL) { |
1336 | AWT_UNLOCK(); |
1337 | return 0; |
1338 | } |
1339 | |
1340 | /* invert the bitmask */ |
1341 | XSetFunction(awt_display, bmGC, GXxor); |
1342 | XSetForeground(awt_display, bmGC, 1); |
1343 | XFillRectangle(awt_display, xsdo->bitmask, bmGC, |
1344 | 0, 0, xsdo->pmWidth, xsdo->pmHeight); |
1345 | |
1346 | srcGC = XCreateGC(awt_display, xsdo->drawable, 0L, NULL); |
1347 | if (srcGC == NULL) { |
1348 | XFreeGC(awt_display, bmGC); |
1349 | AWT_UNLOCK(); |
1350 | return 0; |
1351 | } |
1352 | |
1353 | /* set transparent pixels in the source pm to the bg color */ |
1354 | XSetClipMask(awt_display, srcGC, xsdo->bitmask); |
1355 | XSetForeground(awt_display, srcGC, pixel); |
1356 | XFillRectangle(awt_display, xsdo->drawable, srcGC, |
1357 | 0, 0, xsdo->pmWidth, xsdo->pmHeight); |
1358 | |
1359 | /* invert the mask back */ |
1360 | XFillRectangle(awt_display, xsdo->bitmask, bmGC, |
1361 | 0, 0, xsdo->pmWidth, xsdo->pmHeight); |
1362 | |
1363 | XFreeGC(awt_display, bmGC); |
1364 | XFreeGC(awt_display, srcGC); |
1365 | xsdo->bgPixel = pixel; |
1366 | xsdo->isBgInitialized = JNI_TRUE; |
1367 | } |
1368 | |
1369 | return xsdo->drawable; |
1370 | } |
1371 | |
1372 | static void |
1373 | X11SD_ReleasePixmapWithBg(JNIEnv *env, X11SDOps *xsdo) |
1374 | { |
1375 | #ifdef MITSHM |
1376 | if (xsdo->shmPMData.usingShmPixmap) { |
1377 | xsdo->shmPMData.xRequestSent = JNI_TRUE; |
1378 | } |
1379 | #endif /* MITSHM */ |
1380 | } |
1381 | |
1382 | #endif /* !HEADLESS */ |
1383 | |
1384 | /* |
1385 | * Class: sun_java2d_x11_X11SurfaceData |
1386 | * Method: XCreateGC |
1387 | * Signature: (I)J |
1388 | */ |
1389 | JNIEXPORT jlong JNICALL |
1390 | Java_sun_java2d_x11_XSurfaceData_XCreateGC |
1391 | (JNIEnv *env, jclass xsd, jlong pXSData) |
1392 | { |
1393 | jlong ret; |
1394 | |
1395 | #ifndef HEADLESS |
1396 | X11SDOps *xsdo; |
1397 | |
1398 | J2dTraceLn(J2D_TRACE_INFO, "in X11SurfaceData_XCreateGC" ); |
1399 | |
1400 | xsdo = (X11SDOps *) pXSData; |
1401 | if (xsdo == NULL) { |
1402 | return 0L; |
1403 | } |
1404 | |
1405 | xsdo->javaGC = XCreateGC(awt_display, xsdo->drawable, 0, NULL); |
1406 | ret = (jlong) xsdo->javaGC; |
1407 | #else /* !HEADLESS */ |
1408 | ret = 0L; |
1409 | #endif /* !HEADLESS */ |
1410 | |
1411 | return ret; |
1412 | } |
1413 | |
1414 | /* |
1415 | * Class: sun_java2d_x11_X11SurfaceData |
1416 | * Method: XResetClip |
1417 | * Signature: (JIIIILsun/java2d/pipe/Region;)V |
1418 | */ |
1419 | JNIEXPORT void JNICALL |
1420 | Java_sun_java2d_x11_XSurfaceData_XResetClip |
1421 | (JNIEnv *env, jclass xsd, jlong xgc) |
1422 | { |
1423 | #ifndef HEADLESS |
1424 | J2dTraceLn(J2D_TRACE_INFO, "in X11SurfaceData_XResetClip" ); |
1425 | XSetClipMask(awt_display, (GC) xgc, None); |
1426 | #endif /* !HEADLESS */ |
1427 | } |
1428 | |
1429 | /* |
1430 | * Class: sun_java2d_x11_X11SurfaceData |
1431 | * Method: XSetClip |
1432 | * Signature: (JIIIILsun/java2d/pipe/Region;)V |
1433 | */ |
1434 | JNIEXPORT void JNICALL |
1435 | Java_sun_java2d_x11_XSurfaceData_XSetClip |
1436 | (JNIEnv *env, jclass xsd, jlong xgc, |
1437 | jint x1, jint y1, jint x2, jint y2, |
1438 | jobject complexclip) |
1439 | { |
1440 | #ifndef HEADLESS |
1441 | int numrects; |
1442 | XRectangle rects[256]; |
1443 | XRectangle *pRect = rects; |
1444 | |
1445 | J2dTraceLn(J2D_TRACE_INFO, "in X11SurfaceData_XSetClip" ); |
1446 | |
1447 | numrects = RegionToYXBandedRectangles(env, |
1448 | x1, y1, x2, y2, complexclip, |
1449 | &pRect, 256); |
1450 | |
1451 | XSetClipRectangles(awt_display, (GC) xgc, 0, 0, pRect, numrects, YXBanded); |
1452 | |
1453 | if (pRect != rects) { |
1454 | free(pRect); |
1455 | } |
1456 | #endif /* !HEADLESS */ |
1457 | } |
1458 | |
1459 | /* |
1460 | * Class: sun_java2d_x11_X11SurfaceData |
1461 | * Method: XSetCopyMode |
1462 | * Signature: (J)V |
1463 | */ |
1464 | JNIEXPORT void JNICALL |
1465 | Java_sun_java2d_x11_X11SurfaceData_XSetCopyMode |
1466 | (JNIEnv *env, jclass xsd, jlong xgc) |
1467 | { |
1468 | #ifndef HEADLESS |
1469 | J2dTraceLn(J2D_TRACE_INFO, "in X11SurfaceData_XSetCopyMode" ); |
1470 | XSetFunction(awt_display, (GC) xgc, GXcopy); |
1471 | #endif /* !HEADLESS */ |
1472 | } |
1473 | |
1474 | /* |
1475 | * Class: sun_java2d_x11_X11SurfaceData |
1476 | * Method: XSetXorMode |
1477 | * Signature: (J)V |
1478 | */ |
1479 | JNIEXPORT void JNICALL |
1480 | Java_sun_java2d_x11_X11SurfaceData_XSetXorMode |
1481 | (JNIEnv *env, jclass xr, jlong xgc) |
1482 | { |
1483 | #ifndef HEADLESS |
1484 | J2dTraceLn(J2D_TRACE_INFO, "in X11SurfaceData_XSetXorMode" ); |
1485 | XSetFunction(awt_display, (GC) xgc, GXxor); |
1486 | #endif /* !HEADLESS */ |
1487 | } |
1488 | |
1489 | /* |
1490 | * Class: sun_java2d_x11_X11SurfaceData |
1491 | * Method: XSetForeground |
1492 | * Signature: (JI)V |
1493 | */ |
1494 | JNIEXPORT void JNICALL |
1495 | Java_sun_java2d_x11_X11SurfaceData_XSetForeground |
1496 | (JNIEnv *env, jclass xsd, jlong xgc, jint pixel) |
1497 | { |
1498 | #ifndef HEADLESS |
1499 | J2dTraceLn(J2D_TRACE_INFO, "in X11SurfaceData_XSetForeground" ); |
1500 | XSetForeground(awt_display, (GC) xgc, pixel); |
1501 | #endif /* !HEADLESS */ |
1502 | } |
1503 | |
1504 | /* |
1505 | * Class: sun_java2d_x11_X11SurfaceData |
1506 | * Method: XSetGraphicsExposures |
1507 | * Signature: (JZ)V |
1508 | */ |
1509 | JNIEXPORT void JNICALL |
1510 | Java_sun_java2d_x11_XSurfaceData_XSetGraphicsExposures |
1511 | (JNIEnv *env, jclass xsd, jlong xgc, jboolean needExposures) |
1512 | { |
1513 | #ifndef HEADLESS |
1514 | J2dTraceLn(J2D_TRACE_INFO, "in X11SurfaceData_XSetGraphicsExposures" ); |
1515 | XSetGraphicsExposures(awt_display, (GC) xgc, needExposures ? True : False); |
1516 | #endif /* !HEADLESS */ |
1517 | } |
1518 | |