1 /*
2 * System dependent image routines (unix, x11)
3 */
4 
5 #include "unix/guts.h"
6 #include "Image.h"
7 #include "Icon.h"
8 #include "DeviceBitmap.h"
9 
10 #define REVERT(a)	( XX-> size. y - (a) - 1 )
11 #define SHIFT(a,b)	{ (a) += XX-> gtransform. x + XX-> btransform. x; \
12 									(b) += XX-> gtransform. y + XX-> btransform. y; }
13 /* Multiple evaluation macro! */
14 #define REVERSE_BYTES_32(x) ((((x)&0xff)<<24) | (((x)&0xff00)<<8) | (((x)&0xff0000)>>8) | (((x)&0xff000000)>>24))
15 #define REVERSE_BYTES_16(x) ((((x)&0xff)<<8 ) | (((x)&0xff00)>>8))
16 
17 #define ByteBits                8
18 #define ByteMask                0xff
19 #define ByteValues              256
20 #define LOWER_BYTE(x)           ((x)&ByteMask)
21 #define ColorComponentMask      ByteMask
22 #define LSNibble                0x0f
23 #define LSNibbleShift           0
24 #define MSNibble                0xf0
25 #define MSNibbleShift           4
26 #define NPalEntries4            16
27 #define NPalEntries8            256
28 
29 typedef U8 Pixel8;
30 typedef unsigned long XPixel;
31 
32 typedef uint16_t Pixel16;
33 
34 typedef struct
35 {
36 	Pixel16 a;
37 	Pixel16 b;
38 } Duplet16;
39 
40 typedef struct
41 {
42 	ColorComponent a0, a1, a2;
43 } Pixel24;
44 
45 typedef struct
46 {
47 	ColorComponent a0, a1, a2;
48 	ColorComponent b0, b1, b2;
49 } Duplet24;
50 
51 typedef uint32_t Pixel32;
52 
53 typedef struct
54 {
55 	Pixel32 a;
56 	Pixel32 b;
57 } Duplet32;
58 
59 
60 #define get_ximage_data(xim)            ((xim)->data_alias)
61 #define get_ximage_bytes_per_line(xim)  ((xim)->bytes_per_line_alias)
62 
63 #ifdef USE_MITSHM
64 static int
shm_ignore_errors(Display * d,XErrorEvent * ev)65 shm_ignore_errors(Display *d, XErrorEvent *ev)
66 {
67 	guts.xshmattach_failed = true;
68 	return 0;
69 }
70 #endif
71 
72 PrimaXImage*
prima_prepare_ximage(int width,int height,int format)73 prima_prepare_ximage( int width, int height, int format)
74 {
75 	PrimaXImage *i;
76 	int extra_bytes, depth, pformat, idepth;
77 	Visual *visual;
78 
79 	if (width == 0 || height == 0) return false;
80 
81 	switch(format) {
82 	case CACHE_BITMAP:
83 		depth   = 1;
84 		idepth  = 1;
85 		visual  = guts.visual.visual;
86 		pformat = XYBitmap;
87 		break;
88 	case CACHE_LAYERED:
89 		if ( guts. argb_depth ) {
90 			depth   = guts. argb_visual.depth;
91 			idepth  = guts. argb_depth;
92 			visual  = guts. argb_visual. visual;
93 			pformat = ZPixmap;
94 			break;
95 		}
96 	case CACHE_PIXMAP:
97 		idepth  = guts.idepth;
98 		depth   = guts.depth;
99 		visual  = guts.visual.visual;
100 		pformat = ZPixmap;
101 		break;
102 	default:
103 		croak("bad call to prima_prepare_ximage");
104 	}
105 
106 	switch ( idepth) {
107 	case 16:     extra_bytes = 1;        break;
108 	case 24:     extra_bytes = 5;        break;
109 	case 32:     extra_bytes = 7;        break;
110 	default:     extra_bytes = 0;
111 	}
112 
113 	i = malloc( sizeof( PrimaXImage));
114 	if (!i) {
115 		warn("Not enough memory");
116 		return NULL;
117 	}
118 	bzero( i, sizeof( PrimaXImage));
119 
120 #ifdef USE_MITSHM
121 	if ( guts. shared_image_extension && format != CACHE_BITMAP) {
122 		i-> image = XShmCreateImage(
123 			DISP, visual, depth, pformat,
124 			NULL, &i->xmem, width, height
125 		);
126 		XCHECKPOINT;
127 		if ( !i-> image) goto normal_way;
128 		i-> bytes_per_line_alias = i-> image-> bytes_per_line;
129 		i-> xmem. shmid = shmget(
130 			IPC_PRIVATE,
131 			i-> image-> bytes_per_line * height + extra_bytes,
132 			IPC_CREAT | 0666
133 		);
134 		if ( i-> xmem. shmid < 0) {
135 			XDestroyImage( i-> image);
136 			goto normal_way;
137 		}
138 		i-> xmem. shmaddr = i-> image-> data = shmat( i-> xmem. shmid, 0, 0);
139 		if ( i-> xmem. shmaddr == (void*)-1 || i-> xmem. shmaddr == NULL) {
140 			i-> image-> data = NULL;
141 			XDestroyImage( i-> image);
142 			shmctl( i-> xmem. shmid, IPC_RMID, NULL);
143 			goto normal_way;
144 		}
145 		i-> xmem. readOnly = false;
146 		guts.xshmattach_failed = false;
147 		XSetErrorHandler(shm_ignore_errors);
148 		if ( XShmAttach(DISP, &i->xmem) == 0) {
149 			XCHECKPOINT;
150 bad_xshm_attach:
151 			XSetErrorHandler(guts.main_error_handler);
152 			i-> image-> data = NULL;
153 			XDestroyImage( i-> image);
154 			shmdt( i-> xmem. shmaddr);
155 			shmctl( i-> xmem. shmid, IPC_RMID, NULL);
156 			goto normal_way;
157 		}
158 		XCHECKPOINT;
159 		XSync(DISP,false);
160 		XCHECKPOINT;
161 		if (guts.xshmattach_failed)       goto bad_xshm_attach;
162 		shmctl( i-> xmem. shmid, IPC_RMID, NULL);
163 		i-> data_alias = i-> image-> data;
164 		i-> shm = true;
165 		return i;
166 	}
167 normal_way:
168 #endif
169 	i-> bytes_per_line_alias = (( width * idepth + 31) / 32) * 4;
170 	i-> data_alias = malloc( height * i-> bytes_per_line_alias + extra_bytes);
171 	if (!i-> data_alias) {
172 		warn("Not enough memory");
173 		free(i);
174 		return NULL;
175 	}
176 	i-> image = XCreateImage(
177 		DISP, visual, depth, pformat,
178 		0, i-> data_alias,
179 		width, height, 32, i-> bytes_per_line_alias
180 	);
181 	XCHECKPOINT;
182 	if ( !i-> image) {
183 		warn("XCreateImage(%d,%d,visual=%x,depth=%d/%d) error", width, height, (int)visual->visualid,depth,idepth);
184 		free( i-> data_alias);
185 		free( i);
186 		return NULL;
187 	}
188 	return i;
189 }
190 
191 void
prima_XDestroyImage(XImage * i)192 prima_XDestroyImage( XImage * i)
193 {
194 	if ( i) {
195 		if ( i-> data) {
196 			free( i-> data);
197 			i-> data = NULL;
198 		}
199 		((*((i)->f.destroy_image))((i)));
200 	}
201 }
202 
203 Bool
prima_free_ximage(PrimaXImage * i)204 prima_free_ximage( PrimaXImage *i)
205 {
206 	if (!i) return true;
207 #ifdef USE_MITSHM
208 	if ( i-> shm) {
209 		XShmDetach( DISP, &i-> xmem);
210 		i-> image-> data = NULL;
211 		XDestroyImage( i-> image);
212 		shmdt( i-> xmem. shmaddr);
213 		free(i);
214 		return true;
215 	}
216 #endif
217 	XDestroyImage( i-> image);
218 	free(i);
219 	return true;
220 }
221 
222 static Bool
destroy_ximage(PrimaXImage * i)223 destroy_ximage( PrimaXImage *i)
224 {
225 	if ( !i) return true;
226 	if ( i-> ref_cnt > 0) {
227 		i-> can_free = true;
228 		return true;
229 	}
230 	return prima_free_ximage( i);
231 }
232 
233 static Bool
destroy_one_ximage(PrimaXImage * i,int nothing1,void * nothing2,void * nothing3)234 destroy_one_ximage( PrimaXImage *i, int nothing1, void *nothing2, void *nothing3)
235 {
236 	prima_free_ximage( i);
237 	return false;
238 }
239 
240 void
prima_gc_ximages(void)241 prima_gc_ximages( void )
242 {
243 	if ( !guts.ximages) return;
244 	hash_first_that( guts.ximages, (void*)destroy_one_ximage, NULL, NULL, NULL);
245 }
246 
247 void
prima_ximage_event(XEvent * eve)248 prima_ximage_event( XEvent *eve) /* to be called from apc_event's handle_event */
249 {
250 #ifdef USE_MITSHM
251 	XShmCompletionEvent *ev = (XShmCompletionEvent*)eve;
252 	PrimaXImage *i;
253 
254 	if ( eve && eve-> type == guts. shared_image_completion_event) {
255 		i = hash_fetch( guts.ximages, (void*)&ev->shmseg, sizeof(ev->shmseg));
256 		if ( i) {
257 			i-> ref_cnt--;
258 			if ( i-> ref_cnt <= 0) {
259 				hash_delete( guts.ximages, (void*)&ev->shmseg, sizeof(ev->shmseg), false);
260 				if ( i-> can_free)
261 					prima_free_ximage( i);
262 			}
263 		}
264 	}
265 #endif
266 }
267 
268 #ifdef USE_MITSHM
269 static int
check_ximage_event(Display * disp,XEvent * ev,XPointer data)270 check_ximage_event( Display * disp, XEvent * ev, XPointer data)
271 {
272 	return ev-> type == guts. shared_image_completion_event;
273 }
274 #endif
275 
276 Bool
prima_put_ximage(XDrawable win,GC gc,PrimaXImage * i,int src_x,int src_y,int dst_x,int dst_y,int width,int height)277 prima_put_ximage(
278 	XDrawable win, GC gc, PrimaXImage *i,
279 	int src_x, int src_y, int dst_x, int dst_y,
280 	int width, int height
281 ) {
282 	if ( src_x < 0) {
283 		width += src_x;
284 		dst_x -= src_x;
285 		src_x = 0;
286 		if ( width <= 0) return false;
287 	}
288 #ifdef USE_MITSHM
289 	if ( i-> shm) {
290 		XEvent ev;
291 		if ( src_y + height > i-> image-> height)
292 			height = i-> image-> height - src_y;
293 		if ( i-> ref_cnt < 0)
294 			i-> ref_cnt = 0;
295 		i-> ref_cnt++;
296 		if ( i-> ref_cnt == 1)
297 			hash_store( guts.ximages, &i->xmem.shmseg, sizeof(i->xmem.shmseg), i);
298 		XShmPutImage( DISP, win, gc, i-> image, src_x, src_y, dst_x, dst_y, width, height, true);
299 		XFlush(DISP);
300 		while (XCheckIfEvent( DISP, &ev, check_ximage_event, NULL))
301 			prima_ximage_event(&ev);
302 		return true;
303 	}
304 #endif
305 	XPutImage( DISP, win, gc, i-> image, src_x, src_y, dst_x, dst_y, width, height);
306 	XCHECKPOINT;
307 	return true;
308 }
309 
310 
311 /* image & bitmaps */
312 Bool
apc_image_create(Handle self)313 apc_image_create( Handle self)
314 {
315 	DEFXX;
316 	XX-> type.image        = true;
317 	XX-> type.icon         = !!kind_of(self, CIcon);
318 	XX-> type.drawable     = true;
319 	XX-> image_cache. type = CACHE_INVALID;
320 	XX->size. x            = PImage(self)-> w;
321 	XX->size. y            = PImage(self)-> h;
322 	return true;
323 }
324 
325 static void
clear_caches(Handle self)326 clear_caches( Handle self)
327 {
328 	DEFXX;
329 
330 	prima_palette_free( self, false);
331 	destroy_ximage( XX-> image_cache. icon);
332 	destroy_ximage( XX-> image_cache. image);
333 	XX-> image_cache. icon      = NULL;
334 	XX-> image_cache. image     = NULL;
335 }
336 
337 Bool
apc_image_destroy(Handle self)338 apc_image_destroy( Handle self)
339 {
340 	clear_caches( self);
341 	return true;
342 }
343 
344 ApiHandle
apc_image_get_handle(Handle self)345 apc_image_get_handle( Handle self)
346 {
347 	return (ApiHandle) X(self)-> gdrawable;
348 }
349 
350 Bool
apc_image_begin_paint_info(Handle self)351 apc_image_begin_paint_info( Handle self)
352 {
353 	DEFXX;
354 	PIcon img = PIcon( self);
355 	int icon = XX-> type. icon;
356 	Bool bitmap = (img-> type == imBW) || ( guts. idepth == 1);
357 	Bool layered = icon && img-> maskType == imbpp8 && guts. argb_visual. visual;
358 	int depth = layered ? guts. argb_depth : ( bitmap ? 1 : guts. depth );
359 
360 	if ( !DISP) return false;
361 	XX-> gdrawable = XCreatePixmap( DISP, guts. root, 1, 1, depth);
362 	XCHECKPOINT;
363 	prima_prepare_drawable_for_painting( self, false);
364 	XX-> size. x = 1;
365 	XX-> size. y = 1;
366 	return true;
367 }
368 
369 Bool
apc_image_end_paint_info(Handle self)370 apc_image_end_paint_info( Handle self)
371 {
372 	DEFXX;
373 	prima_cleanup_drawable_after_painting( self);
374 	if ( XX-> gdrawable) {
375 		XFreePixmap( DISP, XX-> gdrawable);
376 		XCHECKPOINT;
377 		XX-> gdrawable = 0;
378 	}
379 	XX-> size. x = PImage( self)-> w;
380 	XX-> size. y = PImage( self)-> h;
381 	return true;
382 }
383 
384 Bool
apc_image_update_change(Handle self)385 apc_image_update_change( Handle self)
386 {
387 	DEFXX;
388 	PImage img = PImage( self);
389 
390 	clear_caches( self);
391 
392 	XX-> size. x = img-> w;
393 	XX-> size. y = img-> h;
394 	if ( guts. depth > 1)
395 		XX-> type.pixmap = (img-> type == imBW) ? 0 : 1;
396 	else
397 		XX-> type.pixmap = 0;
398 	XX-> type.bitmap = !!XX-> type.pixmap;
399 	if ( XX-> cached_region) {
400 		XDestroyRegion( XX-> cached_region);
401 		XX-> cached_region = NULL;
402 	}
403 	return true;
404 }
405 
406 Bool
apc_dbm_create(Handle self,int type)407 apc_dbm_create( Handle self, int type)
408 {
409 	int depth;
410 	DEFXX;
411 
412 	if ( !DISP) return false;
413 	if ( guts. idepth == 1) type = dbtBitmap;
414 
415 	XX-> colormap = guts. defaultColormap;
416 	XX-> visual   = &guts. visual;
417 
418 	switch (type) {
419 	case dbtBitmap:
420 		XX-> type.bitmap = 1;
421 		depth = 1;
422 		break;
423 	case dbtLayered:
424 		if ( guts. argb_depth ) {
425 			XX-> flags.layered = 1;
426 			depth = guts. argb_depth;
427 			XX-> colormap = guts. argbColormap;
428 			XX-> visual   = &guts. argb_visual;
429 			break;
430 		}
431 	case dbtPixmap:
432 		XX-> type.pixmap = 1;
433 		depth = guts.depth;
434 		break;
435 	default:
436 		return false;
437 	}
438 	XX-> type.dbm = true;
439 	XX-> type.drawable = true;
440 	XX->size. x          = ((PDeviceBitmap)(self))-> w;
441 	XX->size. y          = ((PDeviceBitmap)(self))-> h;
442 	if ( XX-> size.x == 0) XX-> size.x = 1;
443 	if ( XX-> size.y == 0) XX-> size.y = 1;
444 	XX->gdrawable        = XCreatePixmap( DISP, guts. root, XX->size. x, XX->size. y, depth);
445 	if (XX-> gdrawable == None) return false;
446 	XCHECKPOINT;
447 	prima_prepare_drawable_for_painting( self, false);
448 
449 	CREATE_ARGB_PICTURE(XX->gdrawable,
450 		XX->type.bitmap ? 1 : (XF_LAYERED(XX) ? 32 : 0),
451 		XX->argb_picture);
452 
453 	return true;
454 }
455 
456 Bool
apc_dbm_destroy(Handle self)457 apc_dbm_destroy( Handle self)
458 {
459 	DEFXX;
460 	if ( XX->gdrawable) {
461 		prima_cleanup_drawable_after_painting( self);
462 		XFreePixmap( DISP, XX->gdrawable);
463 		XX-> gdrawable = None;
464 	}
465 	return true;
466 }
467 
468 ApiHandle
apc_dbm_get_handle(Handle self)469 apc_dbm_get_handle( Handle self)
470 {
471 	return (ApiHandle) X(self)-> gdrawable;
472 }
473 
474 Byte*
prima_mirror_bits(void)475 prima_mirror_bits( void)
476 {
477 	static Bool initialized = false;
478 	static Byte bits[256];
479 	unsigned int i, j;
480 	int k;
481 
482 	if (!initialized) {
483 		for ( i = 0; i < 256; i++) {
484 			bits[i] = 0;
485 			j = i;
486 			for ( k = 0; k < 8; k++) {
487 				bits[i] <<= 1;
488 				if ( j & 0x1)
489 					bits[i] |= 1;
490 				j >>= 1;
491 			}
492 		}
493 		initialized = true;
494 	}
495 
496 	return bits;
497 }
498 
499 void
prima_copy_xybitmap(unsigned char * data,const unsigned char * idata,int w,int h,int ls,int ils)500 prima_copy_xybitmap( unsigned char *data, const unsigned char *idata, int w, int h, int ls, int ils)
501 {
502 	int y;
503 	register int x;
504 	Byte *mirrored_bits;
505 
506 	/* XXX: MSB/LSB */
507 	if ( guts.bit_order == MSBFirst) {
508 		for ( y = h-1; y >= 0; y--) {
509 			memcpy( ls*(h-y-1)+data, idata+y*ils, ls);
510 		}
511 	} else {
512 		mirrored_bits = prima_mirror_bits();
513 		for ( y = h-1; y >= 0; y--) {
514 			register const unsigned char *s = idata+y*ils;
515 			register unsigned char *t = ls*(h-y-1)+data;
516 			x = ls;
517 			while (x--)
518 				*t++ = mirrored_bits[*s++];
519 		}
520 	}
521 }
522 
523 void
prima_mirror_bytes(unsigned char * data,int dataSize)524 prima_mirror_bytes( unsigned char *data, int dataSize)
525 {
526 	Byte *mirrored_bits = prima_mirror_bits();
527 	while ( dataSize--) {
528 		*data = mirrored_bits[*data];
529 		data++;
530 	}
531 }
532 
533 static Bool
create_cache1_1(Image * img,ImageCache * cache,Bool for_icon)534 create_cache1_1( Image *img, ImageCache *cache, Bool for_icon)
535 {
536 	unsigned char *data;
537 	int ls;
538 	int h = img-> h, w = img-> w;
539 	int ils;
540 	unsigned char *idata;
541 	PrimaXImage *ximage;
542 
543 	if ( for_icon) {
544 		ils = PIcon(img)->maskLine;
545 		idata = PIcon(img)->mask;
546 	} else {
547 		ils = img-> lineSize;
548 		idata = img-> data;
549 	}
550 
551 	ximage = prima_prepare_ximage( w, h, CACHE_BITMAP);
552 	if (!ximage) return false;
553 	ls = get_ximage_bytes_per_line(ximage);
554 	data = get_ximage_data(ximage);
555 	prima_copy_xybitmap( data, idata, w, h, ls, ils);
556 
557 	if ( for_icon) {
558 		cache-> icon  = ximage;
559 	} else {
560 		cache-> image = ximage;
561 	}
562 	return true;
563 }
564 
565 static Bool
create_icon_cache8_1(PIcon img,ImageCache * cache)566 create_icon_cache8_1(PIcon img, ImageCache * cache)
567 {
568 	Byte * monomask;
569 	PrimaXImage *ximage;
570 	int ls;
571 	unsigned char *data;
572 
573 	if (!(monomask = img->self->convert_mask((Handle)img, imbpp1)))
574 		return false;
575 
576 	ximage = prima_prepare_ximage( img->w, img->h, CACHE_BITMAP);
577 	if (!ximage) {
578 		free(monomask);
579 		return false;
580 	}
581 	ls = get_ximage_bytes_per_line(ximage);
582 	data = get_ximage_data(ximage);
583 	prima_copy_xybitmap( data, monomask, img->w, img->h, ls, LINE_SIZE(img->w,imbpp1));
584 
585 	free( monomask );
586 	cache->icon = ximage;
587 
588 	return true;
589 }
590 
591 static void
create_rgb_to_8_lut(int ncolors,const PRGBColor pal,Pixel8 * lut)592 create_rgb_to_8_lut( int ncolors, const PRGBColor pal, Pixel8 *lut)
593 {
594 	int i;
595 	for ( i = 0; i < ncolors; i++)
596 		lut[i] =
597 			(((pal[i].r << guts. screen_bits. red_range  ) >> 8) << guts. screen_bits.   red_shift) |
598 			(((pal[i].g << guts. screen_bits. green_range) >> 8) << guts. screen_bits. green_shift) |
599 			(((pal[i].b << guts. screen_bits. blue_range ) >> 8) << guts. screen_bits.  blue_shift);
600 }
601 
602 static void
create_rgb_to_16_lut(int ncolors,const PRGBColor pal,Pixel16 * lut)603 create_rgb_to_16_lut( int ncolors, const PRGBColor pal, Pixel16 *lut)
604 {
605 	int i;
606 	for ( i = 0; i < ncolors; i++)
607 		lut[i] =
608 			(((pal[i].r << guts. screen_bits. red_range  ) >> 8) << guts. screen_bits.   red_shift) |
609 			(((pal[i].g << guts. screen_bits. green_range) >> 8) << guts. screen_bits. green_shift) |
610 			(((pal[i].b << guts. screen_bits. blue_range ) >> 8) << guts. screen_bits.  blue_shift);
611 	if ( guts.machine_byte_order != guts.byte_order)
612 		for ( i = 0; i < ncolors; i++)
613 			lut[i] = REVERSE_BYTES_16(lut[i]);
614 }
615 
616 static int *
rank_rgb_shifts(void)617 rank_rgb_shifts( void)
618 {
619 	static int shift[3];
620 	static Bool shift_unknown = true;
621 
622 	if ( shift_unknown) {
623 		int xchg;
624 		shift[0] = guts. screen_bits. red_shift;
625 		shift[1] = guts. screen_bits. green_shift;
626 		if ( shift[1] < shift[0]) {
627 			xchg = shift[0];
628 			shift[0] = shift[1];
629 			shift[1] = xchg;
630 		}
631 		shift[2] = guts. screen_bits. blue_shift;
632 		if ( shift[2] < shift[0]) {
633 			xchg = shift[2];
634 			shift[2] = shift[1];
635 			shift[1] = shift[0];
636 			shift[0] = xchg;
637 		} else if ( shift[2] < shift[1]) {
638 			xchg = shift[1];
639 			shift[1] = shift[2];
640 			shift[2] = xchg;
641 		}
642 
643 		shift_unknown = false;
644 	}
645 
646 	return shift;
647 }
648 
649 static void
create_rgb_to_xpixel_lut(int ncolors,const PRGBColor pal,XPixel * lut)650 create_rgb_to_xpixel_lut( int ncolors, const PRGBColor pal, XPixel *lut)
651 {
652 	int i;
653 	for ( i = 0; i < ncolors; i++)
654 		lut[i] =
655 			(((pal[i].r << guts. screen_bits. red_range  ) >> 8) << guts. screen_bits.   red_shift) |
656 			(((pal[i].g << guts. screen_bits. green_range) >> 8) << guts. screen_bits. green_shift) |
657 			(((pal[i].b << guts. screen_bits. blue_range ) >> 8) << guts. screen_bits.  blue_shift);
658 	if ( guts.machine_byte_order != guts.byte_order)
659 		for ( i = 0; i < ncolors; i++)
660 			lut[i] = REVERSE_BYTES_32(lut[i]);
661 }
662 
663 static Bool
create_cache4_8(Image * img,ImageCache * cache)664 create_cache4_8( Image *img, ImageCache *cache)
665 {
666 	static Bool init = false;
667 	static unsigned char lut1[ NPalEntries8];
668 	static unsigned char lut2[ NPalEntries8];
669 	unsigned char *data;
670 	int x, y;
671 	int ls;
672 	int h = img-> h, w = img-> w, ww = (w >> 1) + (w & 1);
673 	unsigned i;
674 
675 	if ( !init) {
676 		init = true;
677 		for ( i = 0; i < NPalEntries8; i++) {
678 			lut1[i] = ((i & MSNibble) >> MSNibbleShift);
679 			lut2[i] = ((i & LSNibble) >> LSNibbleShift);
680 		}
681 	}
682 
683 	cache->image = prima_prepare_ximage( w, h, CACHE_PIXMAP);
684 	if ( !cache->image) return false;
685 	ls = get_ximage_bytes_per_line( cache->image);
686 	data = get_ximage_data( cache->image);
687 	for ( y = h-1; y >= 0; y--) {
688 		register unsigned char *line = img-> data + y*img-> lineSize;
689 		register unsigned char *d = (unsigned char*)(ls*(h-y-1)+data);
690 		for ( x = 0; x < ww; x++) {
691 			*d++ = lut1[line[x]];
692 			*d++ = lut2[line[x]];
693 		}
694 	}
695 	return true;
696 }
697 
698 
699 static Bool
create_cache4_16(Image * img,ImageCache * cache)700 create_cache4_16( Image *img, ImageCache *cache)
701 {
702 	Duplet16 lut[ NPalEntries8];
703 	Pixel16 lut1[ NPalEntries4];
704 	unsigned char *data;
705 	int x, y;
706 	int ls;
707 	int h = img-> h, w = img-> w;
708 	unsigned i;
709 
710 	create_rgb_to_16_lut( NPalEntries4, img-> palette, lut1);
711 	for ( i = 0; i < NPalEntries8; i++) {
712 		lut[i]. a = lut1[(i & MSNibble) >> MSNibbleShift];
713 		lut[i]. b = lut1[(i & LSNibble) >> LSNibbleShift];
714 	}
715 	cache->image = prima_prepare_ximage( w, h, CACHE_PIXMAP);
716 	if ( !cache->image) return false;
717 	ls = get_ximage_bytes_per_line( cache->image);
718 	data = get_ximage_data( cache->image);
719 	for ( y = h-1; y >= 0; y--) {
720 		register unsigned char *line = img-> data + y*img-> lineSize;
721 		register Duplet16 *d = (Duplet16*)(ls*(h-y-1)+data);
722 		for ( x = 0; x < (w+1)/2; x++) {
723 			*d++ = lut[line[x]];
724 		}
725 	}
726 	return true;
727 }
728 
729 static Bool
create_cache4_24(Image * img,ImageCache * cache)730 create_cache4_24( Image *img, ImageCache *cache)
731 {
732 	Duplet24 lut[ NPalEntries8];
733 	XPixel lut1[ NPalEntries4];
734 	unsigned char *data;
735 	int x, y;
736 	int ls;
737 	int h = img-> h, w = img-> w;
738 	unsigned i;
739 	int *shift = rank_rgb_shifts();
740 
741 	create_rgb_to_xpixel_lut( NPalEntries4, img-> palette, lut1);
742 	for ( i = 0; i < NPalEntries8; i++) {
743 		lut[i]. a0 = (ColorComponent)((lut1[(i & MSNibble) >> MSNibbleShift] >> shift[0]) & ColorComponentMask);
744 		lut[i]. a1 = (ColorComponent)((lut1[(i & MSNibble) >> MSNibbleShift] >> shift[1]) & ColorComponentMask);
745 		lut[i]. a2 = (ColorComponent)((lut1[(i & MSNibble) >> MSNibbleShift] >> shift[2]) & ColorComponentMask);
746 		lut[i]. b0 = (ColorComponent)((lut1[(i & LSNibble) >> LSNibbleShift] >> shift[0]) & ColorComponentMask);
747 		lut[i]. b1 = (ColorComponent)((lut1[(i & LSNibble) >> LSNibbleShift] >> shift[1]) & ColorComponentMask);
748 		lut[i]. b2 = (ColorComponent)((lut1[(i & LSNibble) >> LSNibbleShift] >> shift[2]) & ColorComponentMask);
749 	}
750 
751 	cache->image = prima_prepare_ximage( w, h, CACHE_PIXMAP);
752 	if ( !cache->image) return false;
753 	ls = get_ximage_bytes_per_line( cache->image);
754 	data = get_ximage_data( cache->image);
755 
756 	for ( y = h-1; y >= 0; y--) {
757 		register unsigned char *line = img-> data + y*img-> lineSize;
758 		register Duplet24 *d = (Duplet24 *)(ls*(h-y-1)+data);
759 		for ( x = 0; x < (w+1)/2; x++) {
760 			*d++ = lut[line[x]];
761 		}
762 	}
763 	return true;
764 }
765 
766 static Bool
create_cache4_32(Image * img,ImageCache * cache)767 create_cache4_32( Image *img, ImageCache *cache)
768 {
769 	Duplet32 lut[ NPalEntries8];
770 	XPixel lut1[ NPalEntries4];
771 	unsigned char *data;
772 	int x, y;
773 	int ls;
774 	int h = img-> h, w = img-> w;
775 	unsigned i;
776 
777 	create_rgb_to_xpixel_lut( NPalEntries4, img-> palette, lut1);
778 	for ( i = 0; i < NPalEntries8; i++) {
779 		lut[i]. a = lut1[(i & MSNibble) >> MSNibbleShift];
780 		lut[i]. b = lut1[(i & LSNibble) >> LSNibbleShift];
781 	}
782 
783 	cache->image = prima_prepare_ximage( w, h, CACHE_PIXMAP);
784 	if ( !cache->image) return false;
785 	ls = get_ximage_bytes_per_line( cache->image);
786 	data = get_ximage_data( cache->image);
787 
788 	for ( y = h-1; y >= 0; y--) {
789 		register unsigned char *line = img-> data + y*img-> lineSize;
790 		register Duplet32 *d = (Duplet32 *)(ls*(h-y-1)+data);
791 		for ( x = 0; x < (w+1)/2; x++) {
792 			*d++ = lut[line[x]];
793 		}
794 	}
795 	return true;
796 }
797 
798 static Bool
create_cache_equal(Image * img,ImageCache * cache)799 create_cache_equal( Image *img, ImageCache *cache)
800 {
801 	unsigned char *data;
802 	int y, ls, lls, h = img-> h;
803 	cache->image = prima_prepare_ximage( img-> w, h, CACHE_PIXMAP);
804 	if ( !cache->image) return false;
805 	ls = get_ximage_bytes_per_line( cache->image);
806 	data = get_ximage_data( cache->image);
807 	lls = (ls > img-> lineSize) ? img-> lineSize : ls;
808 
809 	for ( y = h-1; y >= 0; y--)
810 		memcpy( data + ls * (h - y - 1), img-> data + y*img-> lineSize,  lls);
811 	return true;
812 }
813 
814 static Bool
create_cache8_8_tc(Image * img,ImageCache * cache)815 create_cache8_8_tc( Image *img, ImageCache *cache)
816 {
817 	Pixel8 lut[ NPalEntries8];
818 	Pixel8 *data;
819 	int x, y;
820 	int ls;
821 	int h = img-> h, w = img-> w;
822 
823 	create_rgb_to_8_lut( img-> palSize, img-> palette, lut);
824 
825 	cache->image = prima_prepare_ximage( w, h, CACHE_PIXMAP);
826 	if ( !cache->image) return false;
827 	ls = get_ximage_bytes_per_line( cache->image);
828 	data = get_ximage_data( cache->image);
829 
830 	for ( y = h-1; y >= 0; y--) {
831 		register unsigned char *line = img-> data + y*img-> lineSize;
832 		register Pixel8 *d = (Pixel8*)(ls*(h-y-1)+(unsigned char *)data);
833 		for ( x = 0; x < w; x++) {
834 			*d++ = lut[line[x]];
835 		}
836 	}
837 	return true;
838 }
839 
840 static Bool
create_cache8_16(Image * img,ImageCache * cache)841 create_cache8_16( Image *img, ImageCache *cache)
842 {
843 	Pixel16 lut[ NPalEntries8];
844 	Pixel16 *data;
845 	int x, y;
846 	int ls;
847 	int h = img-> h, w = img-> w;
848 
849 	create_rgb_to_16_lut( img-> palSize, img-> palette, lut);
850 
851 	cache->image = prima_prepare_ximage( w, h, CACHE_PIXMAP);
852 	if ( !cache->image) return false;
853 	ls = get_ximage_bytes_per_line( cache->image);
854 	data = get_ximage_data( cache->image);
855 
856 	for ( y = h-1; y >= 0; y--) {
857 		register unsigned char *line = img-> data + y*img-> lineSize;
858 		register Pixel16 *d = (Pixel16*)(ls*(h-y-1)+(unsigned char *)data);
859 		for ( x = 0; x < w; x++) {
860 			*d++ = lut[line[x]];
861 		}
862 	}
863 	return true;
864 }
865 
866 static Bool
create_cache8_24(Image * img,ImageCache * cache)867 create_cache8_24( Image *img, ImageCache *cache)
868 {
869 	Pixel24 lut[ NPalEntries8];
870 	XPixel lut1[ NPalEntries8];
871 	Pixel24 *data;
872 	int i;
873 	int x, y;
874 	int ls;
875 	int h = img-> h, w = img-> w;
876 	int *shift = rank_rgb_shifts();
877 
878 	create_rgb_to_xpixel_lut( img-> palSize, img-> palette, lut1);
879 	for ( i = 0; i < NPalEntries8; i++) {
880 		lut[i]. a0 = (ColorComponent)((lut1[i] >> shift[0]) & ColorComponentMask);
881 		lut[i]. a1 = (ColorComponent)((lut1[i] >> shift[1]) & ColorComponentMask);
882 		lut[i]. a2 = (ColorComponent)((lut1[i] >> shift[2]) & ColorComponentMask);
883 	}
884 
885 	cache->image = prima_prepare_ximage( w, h, CACHE_PIXMAP);
886 	if ( !cache->image) return false;
887 	ls = get_ximage_bytes_per_line( cache->image);
888 	data = get_ximage_data( cache->image);
889 
890 	for ( y = h-1; y >= 0; y--) {
891 		register unsigned char *line = img-> data + y*img-> lineSize;
892 		register Pixel24 *d = (Pixel24*)(ls*(h-y-1)+(unsigned char *)data);
893 		for ( x = 0; x < w; x++) {
894 			*d++ = lut[line[x]];
895 		}
896 	}
897 	return true;
898 }
899 
900 static Bool
create_cache8_32(Image * img,ImageCache * cache)901 create_cache8_32( Image *img, ImageCache *cache)
902 {
903 	XPixel lut[ NPalEntries8];
904 	Pixel32 *data;
905 	int x, y;
906 	int ls;
907 	int h = img-> h, w = img-> w;
908 
909 	create_rgb_to_xpixel_lut( img-> palSize, img-> palette, lut);
910 
911 	cache->image = prima_prepare_ximage( w, h, CACHE_PIXMAP);
912 	if ( !cache->image) return false;
913 	ls = get_ximage_bytes_per_line( cache->image);
914 	data = get_ximage_data( cache->image);
915 
916 	for ( y = h-1; y >= 0; y--) {
917 		register unsigned char *line = img-> data + y*img-> lineSize;
918 		register Pixel32 *d = (Pixel32*)(ls*(h-y-1)+(unsigned char *)data);
919 		for ( x = 0; x < w; x++) {
920 			*d++ = lut[line[x]];
921 		}
922 	}
923 	return true;
924 }
925 
926 static Bool
create_cache24_16(Image * img,ImageCache * cache)927 create_cache24_16( Image *img, ImageCache *cache)
928 {
929 	static Pixel16 lur[NPalEntries8], lub[NPalEntries8], lug[NPalEntries8];
930 	static Bool initialize = true;
931 	U16 *data;
932 	int x, y;
933 	int i;
934 	RGBColor pal[NPalEntries8];
935 	int ls;
936 	int h = img-> h, w = img-> w;
937 
938 	if ( initialize) {
939 		for ( i = 0; i < NPalEntries8; i++) {
940 			pal[i]. r = i; pal[i]. g = 0; pal[i]. b = 0;
941 		}
942 		create_rgb_to_16_lut( NPalEntries8, pal, lur);
943 		for ( i = 0; i < NPalEntries8; i++) {
944 			pal[i]. r = 0; pal[i]. g = i; pal[i]. b = 0;
945 		}
946 		create_rgb_to_16_lut( NPalEntries8, pal, lug);
947 		for ( i = 0; i < NPalEntries8; i++) {
948 			pal[i]. r = 0; pal[i]. g = 0; pal[i]. b = i;
949 		}
950 		create_rgb_to_16_lut( NPalEntries8, pal, lub);
951 		initialize = false;
952 	}
953 
954 	cache->image = prima_prepare_ximage( w, h, CACHE_PIXMAP);
955 	if ( !cache->image) return false;
956 	ls = get_ximage_bytes_per_line( cache->image);
957 	data = get_ximage_data( cache->image);
958 
959 	for ( y = h-1; y >= 0; y--) {
960 		register Pixel24 *line = (Pixel24*)(img-> data + y*img-> lineSize);
961 		register Pixel16 *d = (Pixel16*)(ls*(h-y-1)+(unsigned char *)data);
962 		for ( x = 0; x < w; x++) {
963 			*d++ = lub[line->a0] | lug[line->a1] | lur[line->a2];
964 			line++;
965 		}
966 	}
967 	return true;
968 }
969 
970 static Bool
create_cache24_32(Image * img,ImageCache * cache)971 create_cache24_32( Image *img, ImageCache *cache)
972 {
973 	static XPixel lur[NPalEntries8], lub[NPalEntries8], lug[NPalEntries8];
974 	static Bool initialize = true;
975 	RGBColor pal[NPalEntries8];
976 	Pixel32 *data;
977 	int x, y;
978 	int i, ls;
979 	int h = img-> h, w = img-> w;
980 
981 	if ( initialize) {
982 		for ( i = 0; i < NPalEntries8; i++) {
983 			pal[i]. r = i;
984 			pal[i]. g = 0;
985 			pal[i]. b = 0;
986 		}
987 		create_rgb_to_xpixel_lut( NPalEntries8, pal, lur);
988 		for ( i = 0; i < NPalEntries8; i++) {
989 			pal[i]. r = 0;
990 			pal[i]. g = i;
991 			pal[i]. b = 0;
992 		}
993 		create_rgb_to_xpixel_lut( NPalEntries8, pal, lug);
994 		for ( i = 0; i < NPalEntries8; i++) {
995 			pal[i]. r = 0;
996 			pal[i]. g = 0;
997 			pal[i]. b = i;
998 		}
999 		create_rgb_to_xpixel_lut( NPalEntries8, pal, lub);
1000 		initialize = false;
1001 	}
1002 
1003 	cache->image = prima_prepare_ximage( w, h, CACHE_PIXMAP);
1004 	if ( !cache->image) return false;
1005 	ls = get_ximage_bytes_per_line( cache->image);
1006 	data = get_ximage_data( cache->image);
1007 
1008 	for ( y = h-1; y >= 0; y--) {
1009 		register Pixel24 *line = (Pixel24*)(img-> data + y*img-> lineSize);
1010 		register Pixel32 *d = (Pixel32*)(ls*(h-y-1)+(unsigned char *)data);
1011 		for ( x = 0; x < w; x++) {
1012 			*d++ = lub[line->a0] | lug[line->a1] | lur[line->a2];
1013 			line++;
1014 		}
1015 	}
1016 	return true;
1017 }
1018 
1019 static Bool
create_cache1(Image * img,ImageCache * cache,int bpp)1020 create_cache1( Image* img, ImageCache *cache, int bpp)
1021 {
1022 	return create_cache1_1( img, cache, false);
1023 }
1024 
1025 static Bool
create_cache4(Image * img,ImageCache * cache,int bpp)1026 create_cache4( Image* img, ImageCache *cache, int bpp)
1027 {
1028 	switch (bpp) {
1029 	case  8:     return create_cache4_8( img, cache);
1030 	case 16:     return create_cache4_16( img, cache);
1031 	case 24:     return create_cache4_24( img, cache);
1032 	case 32:     return create_cache4_32( img, cache);
1033 	default:     warn( "UAI_011: unsupported image conversion: %d => %d", 4, bpp);
1034 	}
1035 	return false;
1036 }
1037 
1038 static Bool
create_cache8(Image * img,ImageCache * cache,int bpp)1039 create_cache8( Image* img, ImageCache *cache, int bpp)
1040 {
1041 	switch (bpp) {
1042 	case 8:
1043 		return ( guts. visualClass == TrueColor || guts. visualClass == DirectColor) ?
1044 			create_cache8_8_tc( img, cache) :
1045 			create_cache_equal( img, cache);
1046 	case 16: return create_cache8_16( img, cache);
1047 	case 24: return create_cache8_24( img, cache);
1048 	case 32: return create_cache8_32( img, cache);
1049 	default: warn( "UAI_012: unsupported image conversion: %d => %d", 8, bpp);
1050 	}
1051 	return false;
1052 }
1053 
1054 static Bool
create_cache24(Image * img,ImageCache * cache,int bpp)1055 create_cache24( Image* img, ImageCache *cache, int bpp)
1056 {
1057 	switch (bpp) {
1058 	case 16: return create_cache24_16( img, cache); break;
1059 	case 32: return create_cache24_32( img, cache); break;
1060 	default: warn( "UAI_013: unsupported image conversion: %d => %d", 24, bpp);
1061 	}
1062 	return false;
1063 }
1064 
1065 static void
cache_remap_8(Image * img,ImageCache * cache)1066 cache_remap_8( Image*img, ImageCache* cache)
1067 {
1068 	int sz = img-> h * cache-> image-> bytes_per_line_alias;
1069 	Byte * p = cache-> image-> data_alias;
1070 	while ( sz--) {
1071 		*p = guts. mappingPlace[ *p];
1072 		p++;
1073 	}
1074 }
1075 
1076 static void
cache_remap_4(Image * img,ImageCache * cache)1077 cache_remap_4( Image*img, ImageCache* cache)
1078 {
1079 	int sz = img-> h * cache-> image-> bytes_per_line_alias;
1080 	Byte * p = cache-> image-> data_alias;
1081 	while ( sz--) {
1082 		*p =
1083 			guts. mappingPlace[(*p) & 0xf] |
1084 		(guts. mappingPlace[((*p) & 0xf0) >> 4] << 4);
1085 		p++;
1086 	}
1087 }
1088 
1089 static void
cache_remap_1(Image * img,ImageCache * cache)1090 cache_remap_1( Image*img, ImageCache* cache)
1091 {
1092 	int sz = img-> h * cache-> image-> bytes_per_line_alias;
1093 	Byte * p = cache-> image-> data_alias;
1094 	if ( guts. mappingPlace[0] == guts. mappingPlace[1])
1095 		memset( p, (guts. mappingPlace[0] == 0) ? 0 : 0xff, sz);
1096 	else if ( guts. mappingPlace[0] != 0)
1097 		while ( sz--) {
1098 			*p = ~(*p);
1099 			p++;
1100 		}
1101 }
1102 
1103 static void
create_rgb_to_argb_xpixel_lut(int ncolors,const PRGBColor pal,XPixel * lut)1104 create_rgb_to_argb_xpixel_lut( int ncolors, const PRGBColor pal, XPixel *lut)
1105 {
1106 	int i;
1107 	for ( i = 0; i < ncolors; i++)
1108 		lut[i] =
1109 			(((pal[i].r << guts. argb_bits. red_range  ) >> 8) << guts. argb_bits.   red_shift) |
1110 			(((pal[i].g << guts. argb_bits. green_range) >> 8) << guts. argb_bits. green_shift) |
1111 			(((pal[i].b << guts. argb_bits. blue_range ) >> 8) << guts. argb_bits.  blue_shift);
1112 	if ( guts.machine_byte_order != guts.byte_order)
1113 		for ( i = 0; i < ncolors; i++)
1114 			lut[i] = REVERSE_BYTES_32(lut[i]);
1115 }
1116 
1117 static void
create_rgb_to_alpha_xpixel_lut(int ncolors,const Byte * alpha,XPixel * lut)1118 create_rgb_to_alpha_xpixel_lut( int ncolors, const Byte * alpha, XPixel *lut)
1119 {
1120 	int i;
1121 	for ( i = 0; i < ncolors; i++)
1122 		lut[i] = ((alpha[i] << guts. argb_bits. alpha_range) >> 8) << guts. argb_bits. alpha_shift;
1123 	if ( guts.machine_byte_order != guts.byte_order)
1124 		for ( i = 0; i < ncolors; i++)
1125 			lut[i] = REVERSE_BYTES_32(lut[i]);
1126 }
1127 
1128 static Bool
create_argb_cache(PIcon img,ImageCache * cache,int type)1129 create_argb_cache(PIcon img, ImageCache * cache, int type)
1130 {
1131 	static XPixel lur[NPalEntries8], lub[NPalEntries8], lug[NPalEntries8], lua[NPalEntries8];
1132 	static Bool initialize = true;
1133 	RGBColor pal[NPalEntries8];
1134 	Byte alpha[NPalEntries8];
1135 	Pixel32 *data;
1136 	int x, y;
1137 	int i, ls;
1138 	int h = img-> h, w = img-> w;
1139 
1140 	if ( initialize) {
1141 		for ( i = 0; i < NPalEntries8; i++) {
1142 			pal[i]. r = i;
1143 			pal[i]. g = 0;
1144 			pal[i]. b = 0;
1145 		}
1146 		create_rgb_to_argb_xpixel_lut( NPalEntries8, pal, lur);
1147 		for ( i = 0; i < NPalEntries8; i++) {
1148 			pal[i]. r = 0;
1149 			pal[i]. g = i;
1150 			pal[i]. b = 0;
1151 		}
1152 		create_rgb_to_argb_xpixel_lut( NPalEntries8, pal, lug);
1153 		for ( i = 0; i < NPalEntries8; i++) {
1154 			pal[i]. r = 0;
1155 			pal[i]. g = 0;
1156 			pal[i]. b = i;
1157 		}
1158 		create_rgb_to_argb_xpixel_lut( NPalEntries8, pal, lub);
1159 		for ( i = 0; i < NPalEntries8; i++)
1160 			alpha[i] = i;
1161 		create_rgb_to_alpha_xpixel_lut( NPalEntries8, alpha, lua);
1162 		initialize = false;
1163 	}
1164 
1165 	cache->image = prima_prepare_ximage( w, h, CACHE_LAYERED);
1166 	if ( !cache->image) return false;
1167 	ls = get_ximage_bytes_per_line( cache->image);
1168 	data = get_ximage_data( cache->image);
1169 
1170 	switch (type) {
1171 	case CACHE_LAYERED_ALPHA:
1172 		for ( y = h-1; y >= 0; y--) {
1173 			register Pixel24 *line = (Pixel24*)(img-> data + y*img-> lineSize);
1174 			register Pixel8  *mask = (Pixel8 *)(img-> mask + y*img-> maskLine);
1175 			register Pixel32 *d = (Pixel32*)(ls*(h-y-1)+(unsigned char *)data);
1176 			for ( x = 0; x < w; x++) {
1177 				*(d++) = lub[line->a0] | lug[line->a1] | lur[line->a2] | lua[*(mask++)];
1178 				line++;
1179 			}
1180 		}
1181 		break;
1182 	case CACHE_LAYERED: {
1183 		XPixel alpha = lua[0]; /* RGB without A assumes A=0, transparent */
1184 		for ( y = h-1; y >= 0; y--) {
1185 			register Pixel24 *line = (Pixel24*)(img-> data + y*img-> lineSize);
1186 			register Pixel32 *d = (Pixel32*)(ls*(h-y-1)+(unsigned char *)data);
1187 			for ( x = 0; x < w; x++) {
1188 				*d++ = lub[line->a0] | lug[line->a1] | lur[line->a2] | alpha;
1189 				line++;
1190 			}
1191 		}}
1192 		break;
1193 	case CACHE_A8:
1194 		for ( y = h-1; y >= 0; y--) {
1195 			register Pixel8  *line = (Pixel8*)(img-> data + y*img-> lineSize);
1196 			register Pixel32 *d = (Pixel32*)(ls*(h-y-1)+(unsigned char *)data);
1197 			for ( x = 0; x < w; x++)
1198 				*(d++) = lua[*(line++)];
1199 		}
1200 		break;
1201 	default:
1202 		croak("bad call to create_argb_cache");
1203 	}
1204 	return true;
1205 }
1206 
1207 static ImageCache*
create_image_cache(PImage img,int type)1208 create_image_cache( PImage img, int type)
1209 {
1210 	PDrawableSysData IMG = X((Handle)img);
1211 	int target_bpp;
1212 	ImageCache *cache    = &X((Handle)img)-> image_cache;
1213 	Bool ret;
1214 	Handle dup = NULL_HANDLE;
1215 	PImage pass = img;
1216 
1217 	/* common validity checks */
1218 	if ( img-> w == 0 || img-> h == 0) return NULL;
1219 	if ( img-> palette == NULL) {
1220 		warn( "UAI_014: image has no palette");
1221 		return NULL;
1222 	}
1223 
1224 	/* test if types are applicable */
1225 	switch ( type) {
1226 	case CACHE_A8:
1227 	case CACHE_LAYERED:
1228 	case CACHE_LAYERED_ALPHA:
1229 		if ( !guts. argb_visual. visual ) {
1230 			warn("panic: no argb visual");
1231 			return NULL;
1232 		}
1233 		break;
1234 	case CACHE_PIXMAP:
1235 		if ( guts. idepth == 1) type = CACHE_BITMAP;
1236 		break;
1237 	case CACHE_LOW_RES:
1238 		if ( !guts. dynamicColors) type = CACHE_PIXMAP;
1239 		if ( guts. idepth == 1) type = CACHE_BITMAP;
1240 		break;
1241 	}
1242 
1243 	/* find Prima image depth */
1244 	switch (type) {
1245 	case CACHE_BITMAP:
1246 		target_bpp = 1;
1247 		break;
1248 	case CACHE_A8:
1249 	case CACHE_LAYERED:
1250 	case CACHE_LAYERED_ALPHA:
1251 		target_bpp = guts. argb_depth;
1252 		break;
1253 	default:
1254 		target_bpp = guts. idepth;
1255 	}
1256 
1257 	/* create icon cache, if any */
1258 	if ( XT_IS_ICON(IMG) && type != CACHE_LAYERED_ALPHA) {
1259 		if ( cache-> icon == NULL) {
1260 			Bool ok;
1261 			ok = ( PIcon(img)-> maskType == imbpp8 ) ?
1262 				create_icon_cache8_1(( PIcon) img, cache) :
1263 				create_cache1_1( img, cache, true);
1264 			if ( !ok ) return NULL;
1265 		}
1266 	} else
1267 		cache-> icon = NULL;
1268 
1269 	if ( cache-> image != NULL) {
1270 		if ( cache-> type == type) return cache;
1271 		destroy_ximage( cache-> image);
1272 		cache-> image = NULL;
1273 	}
1274 
1275 	/* convert from funky image types */
1276 	if (( img-> type & ( imRealNumber | imComplexNumber | imTrigComplexNumber)) ||
1277 		( img-> type == imLong || img-> type == imShort)) {
1278 		if ( !dup) {
1279 			if (!(dup = img-> self-> dup(( Handle) img)))
1280 				return NULL;
1281 		}
1282 		pass = ( PImage) dup;
1283 		pass-> self->resample(( Handle) pass,
1284 			pass-> self->stats(( Handle) pass, false, isRangeLo, 0),
1285 			pass-> self->stats(( Handle) pass, false, isRangeHi, 0),
1286 			0, 255
1287 		);
1288 		pass-> self-> set_type(( Handle) pass, imByte);
1289 	}
1290 
1291 	/* treat ARGB separately, and leave */
1292 	if ( type == CACHE_LAYERED || type == CACHE_LAYERED_ALPHA ) {
1293 		Bool ok;
1294 		PIcon i = (PIcon) pass;
1295 		if ( i->type != imRGB ) {
1296 			if ( !dup)
1297 				if (!(dup = img-> self-> dup(( Handle) i)))
1298 					return NULL;
1299 			i = (PIcon) dup;
1300 			i-> self-> set_type(dup, imRGB);
1301 		}
1302 		if ( XT_IS_ICON(IMG) && type == CACHE_LAYERED_ALPHA && i->maskType != imbpp8 ) {
1303 			if ( !dup)
1304 				if (!(dup = i-> self-> dup((Handle) i)))
1305 					return NULL;
1306 			i = (PIcon) dup;
1307 			i-> self-> set_maskType(dup, imbpp8);
1308 		}
1309 		ok = create_argb_cache(i, cache,
1310 			(XT_IS_ICON(IMG) && type == CACHE_LAYERED_ALPHA) ? CACHE_LAYERED_ALPHA : CACHE_LAYERED
1311 		);
1312 		if ( dup) Object_destroy(dup);
1313 		if ( !ok ) return NULL;
1314 
1315 		cache-> type = type;
1316 		return cache;
1317 	}
1318 
1319 	if ( type == CACHE_A8 ) {
1320 		Bool ok;
1321 		PImage i = (PImage) pass;
1322 		if ( i->type != imByte ) {
1323 			if ( !dup)
1324 				if (!(dup = img-> self-> dup(( Handle) i)))
1325 					return NULL;
1326 			i = (PImage) dup;
1327 			i-> self-> set_type(dup, imByte);
1328 		}
1329 		ok = create_argb_cache((PIcon) i, cache, CACHE_A8);
1330 		if ( dup) Object_destroy(dup);
1331 		if ( !ok ) return NULL;
1332 
1333 		cache-> type = type;
1334 		return cache;
1335 	}
1336 
1337 	/*
1338 		apply as much of system palette colors as possible to new image,
1339 		if we're working on 1-8 bit displays. CACHE_LOW_RES on displays with
1340 		dynamic colors goes only after conservative strategy, using only
1341 		immutable colors to be copied to clipboard, icon, etc.
1342 	*/
1343 	if ( target_bpp <= 8 && img-> type != imBW) {
1344 		int bpp, colors = 0;
1345 		RGBColor palbuf[256], *palptr = NULL;
1346 		if ( !dup) {
1347 			if (!(dup = img-> self-> dup(( Handle) img)))
1348 				return NULL;
1349 		}
1350 		pass = ( PImage) dup;
1351 		if ( target_bpp <= 1) bpp = imbpp1; else
1352 		if ( target_bpp <= 4) bpp = imbpp4; else bpp = imbpp8;
1353 
1354 		if ( guts. palSize > 0 && target_bpp > 1) {
1355 			int i, maxRank = RANK_FREE;
1356 			if ( type == CACHE_LOW_RES) maxRank = RANK_LOCKED;
1357 			for ( i = 0; i < guts. palSize; i++) {
1358 				if ( guts. palette[i]. rank <= maxRank) continue;
1359 				palbuf[colors]. r = guts. palette[i]. r;
1360 				palbuf[colors]. g = guts. palette[i]. g;
1361 				palbuf[colors]. b = guts. palette[i]. b;
1362 				colors++;
1363 				if ( colors > 255) break;
1364 			}
1365 			palptr = palbuf;
1366 		}
1367 		pass-> self-> reset( dup, bpp, palptr, colors);
1368 	}
1369 
1370 	/* convert image bits */
1371 	switch ( pass-> type & imBPP) {
1372 	case 1:   ret = create_cache1( pass, cache, target_bpp); break;
1373 	case 4:   ret = create_cache4( pass, cache, target_bpp); break;
1374 	case 8:   ret = create_cache8( pass, cache, target_bpp); break;
1375 	case 24:  ret = create_cache24(pass, cache, target_bpp); break;
1376 	default:
1377 		warn( "UAI_015: unsupported image type");
1378 		return NULL;
1379 	}
1380 	if ( !ret) {
1381 		if ( dup) Object_destroy(dup);
1382 		return NULL;
1383 	}
1384 
1385 	/* on paletted displays, acquire actual color indexes, and
1386 		remap pixels to match them */
1387 	if (( guts. palSize > 0) && (( pass-> type & imBPP) != 24)) {
1388 		int i, maxRank = RANK_FREE;
1389 		Byte * p = X((Handle)img)-> palette;
1390 
1391 		if ( type == CACHE_LOW_RES) /* don't use dynamic colors */
1392 			maxRank = RANK_LOCKED;
1393 
1394 		for ( i = 0; i < pass-> palSize; i++) {
1395 			int j = guts. mappingPlace[i] = prima_color_find( NULL_HANDLE,
1396 				RGB_COMPOSITE(
1397 				pass-> palette[i].r,
1398 				pass-> palette[i].g,
1399 				pass-> palette[i].b
1400 				), -1, NULL, maxRank);
1401 
1402 			if ( p && ( prima_lpal_get( p, j) == RANK_FREE))
1403 				prima_color_add_ref(( Handle) img, j, RANK_LOCKED);
1404 		}
1405 		for ( i = pass-> palSize; i < 256; i++) guts. mappingPlace[i] = 0;
1406 
1407 		switch(target_bpp){
1408 		case 8: if ((pass-> type & imBPP) != 1) cache_remap_8( img, cache); break;
1409 		case 4: if ((pass-> type & imBPP) != 1) cache_remap_4( img, cache); break;
1410 		case 1: cache_remap_1( img, cache); break;
1411 		default: warn("UAI_019: palette is not supported");
1412 		}
1413 	} else if ( target_bpp == 1 ) {
1414 		RGBColor * p = pass->palette;
1415 		guts. mappingPlace[0] = (p[0].r + p[0].g + p[0].b > 382) ? 0xff : 0;
1416 		guts. mappingPlace[1] = (p[1].r + p[1].g + p[1].b > 382) ? 0xff : 0;
1417 		cache_remap_1( img, cache);
1418 	}
1419 
1420 	if ( dup) Object_destroy(dup);
1421 	cache-> type = type;
1422 	return cache;
1423 }
1424 
1425 ImageCache*
prima_image_cache(PImage img,int type)1426 prima_image_cache( PImage img, int type)
1427 {
1428 	ImageCache *cache = &X((Handle)img)-> image_cache;
1429 	if ( cache-> image != NULL && cache-> type == type) return cache;
1430 	return create_image_cache(img, type);
1431 }
1432 
1433 Bool
prima_create_icon_pixmaps(Handle self,Pixmap * xor,Pixmap * and)1434 prima_create_icon_pixmaps( Handle self, Pixmap *xor, Pixmap *and)
1435 {
1436 	Pixmap p1, p2;
1437 	PIcon icon = PIcon(self);
1438 	ImageCache *cache;
1439 	GC gc;
1440 	XGCValues gcv;
1441 
1442 	cache = prima_image_cache((PImage)icon, CACHE_BITMAP);
1443 	if ( !cache) return false;
1444 	p1 = XCreatePixmap( DISP, guts. root, icon-> w, icon-> h, 1);
1445 	p2 = XCreatePixmap( DISP, guts. root, icon-> w, icon-> h, 1);
1446 	XCHECKPOINT;
1447 	if ( p1 == None || p2 == None) {
1448 		if (p1 != None) XFreePixmap( DISP, p1);
1449 		if (p2 != None) XFreePixmap( DISP, p2);
1450 		return false;
1451 	}
1452 	gcv. graphics_exposures = false;
1453 	gc = XCreateGC( DISP, p1, GCGraphicsExposures, &gcv);
1454 	XSetForeground( DISP, gc, 0);
1455 	XSetBackground( DISP, gc, 1);
1456 	prima_put_ximage( p2, gc, cache->icon, 0, 0, 0, 0, icon-> w, icon-> h);
1457 	XSetForeground( DISP, gc, 1);
1458 	XSetBackground( DISP, gc, 0);
1459 	prima_put_ximage( p1, gc, cache->image, 0, 0, 0, 0, icon-> w, icon-> h);
1460 	XFreeGC( DISP, gc);
1461 	*xor = p1;
1462 	*and = p2;
1463 	return true;
1464 }
1465 
1466 typedef struct {
1467 	int src_x;
1468 	int src_y;
1469 	int w;
1470 	int h;
1471 	int dst_x;
1472 	int dst_y;
1473 	int rop;
1474 	int old_rop;
1475 } PutImageRequest;
1476 
1477 static void
rop_apply_colors(Handle self,PutImageRequest * req)1478 rop_apply_colors(Handle self, PutImageRequest * req)
1479 {
1480 	DEFXX;
1481 	/*
1482 	Special case with current foreground and background colors for 1-bit bitmaps/pixmaps, see also
1483 	L<pod/Prima/Drawable.pod | Monochrome bitmaps>.
1484 
1485 	Raster ops can be identified by a fingerprint.  For example, Or's is 14
1486 	and Noop's is 10:
1487 
1488         0 | 0 =    0                      0 | 0 =    0
1489         0 | 1 =   1                       0 | 1 =   1
1490         1 | 0 =  1                        1 | 0 =  0
1491         1 | 1 = 1                         1 | 1 = 1
1492         ---     ----                      ---     ----
1493                 1110 = 14                         1010 = 10
1494 
1495 	when this special case uses not actual 0s and 1s, but bit values of
1496 	foreground and background color instead, the resulting operation can
1497 	still be expressed in rops, but these needs to be adjusted. Let's
1498 	consider a case where both colors are 0, and rop = OrPut:
1499 
1500         0 | 0 =    0
1501         0 | 1 =   1
1502         0 | 0 =  0
1503         0 | 1 = 1
1504         ---     ----
1505                 1010 = 10
1506 
1507 	this means that in these conditions, Or (as well as Xor and AndInverted) becomes Noop.
1508 
1509 	*/
1510 	unsigned long fore = XX-> fore.primary & 1;
1511 	unsigned long back = XX-> back.primary & 1;
1512 	if ( fore == 0 && back == 0 ) {
1513 		switch( req->rop) {
1514 			case GXand:
1515 			case GXandReverse:
1516 			case GXclear:
1517 			case GXcopy:          req->rop = GXclear;         break;
1518 			case GXequiv:
1519 			case GXinvert:
1520 			case GXnor:
1521 			case GXorReverse:     req->rop = GXinvert;        break;
1522 			case GXandInverted:
1523 			case GXnoop:
1524 			case GXor:
1525 			case GXxor:           req->rop = GXnoop;          break;
1526 			case GXnand:
1527 			case GXcopyInverted:
1528 			case GXorInverted:
1529 			case GXset:           req->rop = GXset;           break;
1530 		}
1531 	} else if ( fore == 1 && back == 0 ) {
1532 		switch( req->rop) {
1533 			case GXand:           req->rop = GXandInverted;   break;
1534 			case GXandInverted:   req->rop = GXand;           break;
1535 			case GXandReverse:    req->rop = GXnor;           break;
1536 			case GXclear:         req->rop = GXclear;         break;
1537 			case GXcopy:          req->rop = GXcopyInverted;  break;
1538 			case GXcopyInverted:  req->rop = GXcopy;          break;
1539 			case GXequiv:         req->rop = GXxor;           break;
1540 			case GXinvert:        req->rop = GXinvert;        break;
1541 			case GXnand:          req->rop = GXorReverse;     break;
1542 			case GXnoop:          req->rop = GXnoop;          break;
1543 			case GXnor:           req->rop = GXandReverse;    break;
1544 			case GXor:            req->rop = GXorInverted;    break;
1545 			case GXorInverted:    req->rop = GXor;            break;
1546 			case GXorReverse:     req->rop = GXnand;          break;
1547 			case GXset:           req->rop = GXset;           break;
1548 			case GXxor:           req->rop = GXequiv;         break;
1549 		}
1550 	} else if ( fore == 1 && back == 1 ) {
1551 		switch( req->rop) {
1552 			case GXand:
1553 			case GXorInverted:
1554 			case GXequiv:
1555 			case GXnoop:          req->rop = GXnoop;          break;
1556 			case GXandInverted:
1557 			case GXclear:
1558 			case GXcopyInverted:
1559 			case GXnor:           req->rop = GXclear;         break;
1560 			case GXinvert:
1561 			case GXnand:
1562 			case GXandReverse:
1563 			case GXxor:           req->rop = GXinvert;        break;
1564 			case GXor:
1565 			case GXorReverse:
1566 			case GXset:
1567 			case GXcopy:          req->rop = GXset;           break;
1568 		}
1569 	}
1570 }
1571 
1572 #define SET_ROP(x) if ( req->old_rop != x) XSetFunction( DISP, XX-> gc, req->old_rop = x)
1573 typedef Bool PutImageFunc( Handle self, Handle image, PutImageRequest * req);
1574 
1575 static Bool
img_put_copy_area(Handle self,Handle image,PutImageRequest * req)1576 img_put_copy_area( Handle self, Handle image, PutImageRequest * req)
1577 {
1578 	DEFXX;
1579 	PDrawableSysData YY = X(image);
1580 
1581 	XCHECKPOINT;
1582 	SET_ROP(req->rop);
1583 
1584 	XCopyArea(
1585 		DISP, YY-> gdrawable, XX-> gdrawable, XX-> gc,
1586 		req->src_x, req->src_y,
1587 		req->w, req->h,
1588 		req->dst_x, req->dst_y
1589 	);
1590 
1591 	XCHECKPOINT;
1592 	XFLUSH;
1593 
1594 	return true;
1595 }
1596 
1597 static Bool
img_put_ximage(Handle self,PrimaXImage * image,PutImageRequest * req)1598 img_put_ximage( Handle self, PrimaXImage * image, PutImageRequest * req)
1599 {
1600 	DEFXX;
1601 	SET_ROP(req->rop);
1602 	return prima_put_ximage(
1603 		XX-> gdrawable, XX-> gc, image,
1604 		req->src_x, req->src_y,
1605 		req->dst_x, req->dst_y,
1606 		req->w, req->h
1607 	);
1608 }
1609 
1610 static Handle
img_get_image(Pixmap pixmap,PutImageRequest * req)1611 img_get_image( Pixmap pixmap, PutImageRequest * req)
1612 {
1613 	XImage *i;
1614 	Handle obj;
1615 	Bool ok;
1616 
1617 	XCHECKPOINT;
1618 	if ( !( i = XGetImage( DISP, pixmap,
1619 		req->src_x, req->src_y, req->w, req->h, AllPlanes, ZPixmap)))
1620 		return NULL_HANDLE;
1621 
1622 	obj = ( Handle) create_object("Prima::Image", "");
1623 	CImage( obj)-> create_empty( obj, req->w, req->h, guts. qdepth);
1624 	ok = prima_query_image( obj, i);
1625 	XDestroyImage( i);
1626 	if ( !ok ) {
1627 		Object_destroy( obj );
1628 		return NULL_HANDLE;
1629 	}
1630 	return obj;
1631 }
1632 
1633 static Bool
img_put_icon_mask(Handle self,PrimaXImage * icon,PutImageRequest * req)1634 img_put_icon_mask( Handle self, PrimaXImage * icon, PutImageRequest * req)
1635 {
1636 	Bool ret;
1637 	DEFXX;
1638 	XSetForeground( DISP, XX-> gc, 0xFFFFFFFF);
1639 	XSetBackground( DISP, XX-> gc, 0x00000000);
1640 	XX-> flags. brush_fore = 0;
1641 	XX-> flags. brush_back = 0;
1642 
1643 	req->rop = GXand;
1644 	XCHECKPOINT;
1645 	ret = img_put_ximage( self, icon, req);
1646 	req->rop = GXxor;
1647 	return ret;
1648 }
1649 
1650 static Bool
img_put_bitmap_on_bitmap(Handle self,Handle image,PutImageRequest * req)1651 img_put_bitmap_on_bitmap( Handle self, Handle image, PutImageRequest * req)
1652 {
1653 	PDrawableSysData YY = X(image);
1654 
1655 	if ( XT_IS_DBM(YY) && XT_IS_BITMAP(YY))
1656 		rop_apply_colors(self, req);
1657 
1658 	return img_put_copy_area( self, image, req);
1659 }
1660 
1661 static Bool
img_put_image_on_bitmap(Handle self,Handle image,PutImageRequest * req)1662 img_put_image_on_bitmap( Handle self, Handle image, PutImageRequest * req)
1663 {
1664 	DEFXX;
1665 	ImageCache *cache;
1666 	PImage img = (PImage) image;
1667 	PDrawableSysData YY = X(image);
1668 
1669 	if (!(cache = prima_image_cache(img, CACHE_BITMAP)))
1670 		return false;
1671 
1672 	if ( XT_IS_ICON(YY) && !img_put_icon_mask( self, cache->icon, req))
1673 		return false;
1674 
1675 	XSetForeground( DISP, XX-> gc, 1);
1676 	XSetBackground( DISP, XX-> gc, 0);
1677 	XX-> flags. brush_fore = XX-> flags. brush_back = 0;
1678 
1679 	return img_put_ximage( self, cache->image, req);
1680 }
1681 
1682 static Bool
img_put_pixmap_on_bitmap(Handle self,Handle image,PutImageRequest * req)1683 img_put_pixmap_on_bitmap( Handle self, Handle image, PutImageRequest * req)
1684 {
1685 	Bool ret;
1686 	Handle obj;
1687 
1688 	if (!( obj = img_get_image( X(image)-> gdrawable, req )))
1689 		return false;
1690 
1691 	CImage( obj)-> set_type( obj, imBW);
1692 	req->src_x = req->src_y = 0;
1693 	ret = img_put_image_on_bitmap( self, obj, req);
1694 	Object_destroy( obj);
1695 
1696 	return ret;
1697 }
1698 
1699 static Bool
img_put_argb_on_bitmap(Handle self,Handle image,PutImageRequest * req)1700 img_put_argb_on_bitmap( Handle self, Handle image, PutImageRequest * req)
1701 {
1702 	DEFXX;
1703 	ImageCache *cache;
1704 	int rop = req->rop;
1705 
1706 	PImage img = (PImage) image;
1707 
1708 	if (!(cache = prima_image_cache(img, CACHE_BITMAP)))
1709 		return false;
1710 
1711 	if ( !img_put_icon_mask( self, cache->icon, req))
1712 		return false;
1713 
1714 	req-> rop = ( rop == ropSrcCopy ) ? GXcopy : GXor;
1715 	XSetForeground( DISP, XX-> gc, 1);
1716 	XSetBackground( DISP, XX-> gc, 0);
1717 	XX-> flags. brush_fore = XX-> flags. brush_back = 0;
1718 
1719 	return img_put_ximage( self, cache->image, req);
1720 }
1721 
1722 Bool
1723 prima_query_argb_rect( Handle self, Pixmap px, int x, int y, int w, int h);
1724 
1725 static Bool
img_put_layered_on_bitmap(Handle self,Handle image,PutImageRequest * req)1726 img_put_layered_on_bitmap( Handle self, Handle image, PutImageRequest * req)
1727 {
1728 	Handle obj;
1729 	Bool ok;
1730 
1731 	obj = ( Handle) create_object("Prima::Icon", "");
1732 	ok = prima_query_argb_rect( obj, X(image)-> gdrawable, req-> src_x, req-> src_y, req-> w, req-> h);
1733 	if ( !ok ) {
1734 		Object_destroy( obj );
1735 		return false;
1736 	}
1737 
1738 	req->src_x = req->src_y = 0;
1739 	ok = img_put_argb_on_bitmap( self, obj, req );
1740 	Object_destroy( obj);
1741 	return ok;
1742 }
1743 
1744 static Bool
img_put_bitmap_on_pixmap(Handle self,Handle image,PutImageRequest * req)1745 img_put_bitmap_on_pixmap( Handle self, Handle image, PutImageRequest * req)
1746 {
1747 	DEFXX;
1748 	PDrawableSysData YY = X(image);
1749 
1750 	/* XCopyPlane uses 0s for background and 1s for foreground */
1751 	if ( XT_IS_BITMAP(YY)) {
1752 		if ( XT_IS_DBM(YY)) {
1753 			XSetBackground( DISP, XX-> gc, XX-> fore. primary);
1754 			XSetForeground( DISP, XX-> gc, XX-> back. primary);
1755 		} else {
1756 			/* imBW in paint - no palettes, no colors, just plain black & white */
1757 			if ( XF_LAYERED(XX)) {
1758 				XSetForeground( DISP, XX-> gc, 0xFFFFFF);
1759 				XSetBackground( DISP, XX-> gc, 0x000000);
1760 			} else {
1761 				XSetForeground( DISP, XX-> gc, guts. monochromeMap[1]);
1762 				XSetBackground( DISP, XX-> gc, guts. monochromeMap[0]);
1763 			}
1764 		}
1765 		XX->flags.brush_fore = XX->flags.brush_back = 0;
1766 	}
1767 
1768 	SET_ROP(req->rop);
1769 	XCHECKPOINT;
1770 
1771 	XCopyPlane(
1772 		DISP, YY-> gdrawable, XX-> gdrawable, XX-> gc,
1773 		req->src_x, req->src_y,
1774 		req->w, req->h,
1775 		req->dst_x, req->dst_y, 1
1776 	);
1777 
1778 	XCHECKPOINT;
1779 	XFLUSH;
1780 
1781 	return true;
1782 }
1783 
1784 static Bool
img_put_image_on_pixmap(Handle self,Handle image,PutImageRequest * req)1785 img_put_image_on_pixmap( Handle self, Handle image, PutImageRequest * req)
1786 {
1787 	DEFXX;
1788 	ImageCache *cache;
1789 	PImage img = (PImage) image;
1790 	PDrawableSysData YY = X(image);
1791 
1792 	if (!(cache = prima_image_cache(img,
1793 		XT_IS_DBM(YY) ? CACHE_LOW_RES : CACHE_PIXMAP)))
1794 		return false;
1795 
1796 	if ( XT_IS_ICON(YY) && !img_put_icon_mask( self, cache->icon, req))
1797 		return false;
1798 
1799 	if (( img->type & imBPP ) == 1) {
1800 		RGBColor * p = img->palette;
1801 		if ( !XX->flags. brush_fore) {
1802 			XSetBackground( DISP, XX-> gc, prima_allocate_color( self, ARGB(p[0].r, p[0].g, p[0].b), NULL));
1803 			XX->flags.brush_fore = 0;
1804 		}
1805 		if ( !XX->flags. brush_back) {
1806 			XSetForeground( DISP, XX-> gc, prima_allocate_color( self, ARGB(p[1].r, p[1].g, p[1].b), NULL));
1807 			XX->flags.brush_back = 0;
1808 		}
1809 	}
1810 
1811 	return img_put_ximage( self, cache->image, req);
1812 }
1813 
1814 static Bool
img_put_layered_on_pixmap(Handle self,Handle image,PutImageRequest * req)1815 img_put_layered_on_pixmap( Handle self, Handle image, PutImageRequest * req)
1816 {
1817 #ifdef HAVE_X11_EXTENSIONS_XRENDER_H
1818 	DEFXX;
1819 	PDrawableSysData YY = X(image);
1820 
1821 	XRenderComposite(
1822 		DISP, (req-> rop == ropSrcCopy) ? PictOpSrc : PictOpOver, YY-> argb_picture, 0, XX-> argb_picture,
1823 		req->src_x, req->src_y, 0, 0,
1824 		req->dst_x, req->dst_y, req->w, req->h
1825 	);
1826 	XSync(DISP, false);
1827 	return true;
1828 #else
1829 	return false;
1830 #endif
1831 }
1832 
1833 static Bool
img_put_image_on_widget(Handle self,Handle image,PutImageRequest * req)1834 img_put_image_on_widget( Handle self, Handle image, PutImageRequest * req)
1835 {
1836 	DEFXX;
1837 	ImageCache *cache;
1838 	PImage img = (PImage) image;
1839 	PDrawableSysData YY = X(image);
1840 
1841 	if (!(cache = prima_image_cache(img, CACHE_PIXMAP)))
1842 		return false;
1843 
1844 	if ( XT_IS_ICON(YY) && !img_put_icon_mask( self, cache->icon, req))
1845 		return false;
1846 
1847 	if (( img->type & imBPP ) == 1) {
1848 		unsigned int fore, back;
1849 
1850 		if ( guts. palSize > 0) {
1851 			fore = prima_color_find( self,
1852 				RGB_COMPOSITE( img-> palette[1].r, img-> palette[1].g, img-> palette[1].b),
1853 				-1, NULL, RANK_NORMAL);
1854 			back = prima_color_find( self,
1855 				RGB_COMPOSITE( img-> palette[0].r, img-> palette[0].g, img-> palette[0].b),
1856 				-1, NULL, RANK_NORMAL);
1857 		} else {
1858 			fore =
1859 				(((img-> palette[1].r << guts. screen_bits. red_range  ) >> 8) << guts. screen_bits.   red_shift) |
1860 				(((img-> palette[1].g << guts. screen_bits. green_range) >> 8) << guts. screen_bits. green_shift) |
1861 				(((img-> palette[1].b << guts. screen_bits. blue_range ) >> 8) << guts. screen_bits.  blue_shift);
1862 			back =
1863 				(((img-> palette[0].r << guts. screen_bits. red_range  ) >> 8) << guts. screen_bits.   red_shift) |
1864 				(((img-> palette[0].g << guts. screen_bits. green_range) >> 8) << guts. screen_bits. green_shift) |
1865 				(((img-> palette[0].b << guts. screen_bits. blue_range ) >> 8) << guts. screen_bits.  blue_shift);
1866 		}
1867 		XSetBackground( DISP, XX-> gc, back);
1868 		XSetForeground( DISP, XX-> gc, fore);
1869 		XX->flags.brush_back = XX->flags.brush_fore = 0;
1870 	}
1871 
1872 	if ( guts. dynamicColors) {
1873 		int i;
1874 		for ( i = 0; i < guts. palSize; i++)
1875 			if (( wlpal_get( image, i) == RANK_FREE) &&
1876 				( wlpal_get( self,  i) != RANK_FREE))
1877 				prima_color_add_ref( self, i, RANK_LOCKED);
1878 	}
1879 
1880 	return img_put_ximage( self, cache->image, req);
1881 }
1882 
1883 static Bool
img_put_image_on_layered(Handle self,Handle image,PutImageRequest * req)1884 img_put_image_on_layered( Handle self, Handle image, PutImageRequest * req)
1885 {
1886 	ImageCache *cache;
1887 	PDrawableSysData YY = X(image);
1888 	if (!(cache = prima_image_cache((PImage) image, CACHE_LAYERED)))
1889 		return false;
1890 	if ( XT_IS_ICON(YY) && !img_put_icon_mask( self, cache->icon, req))
1891 		return false;
1892 	return img_put_ximage( self, cache->image, req);
1893 }
1894 
1895 static Bool
img_put_pixmap_on_layered(Handle self,Handle image,PutImageRequest * req)1896 img_put_pixmap_on_layered( Handle self, Handle image, PutImageRequest * req)
1897 {
1898 #ifdef HAVE_X11_EXTENSIONS_XRENDER_H
1899 	DEFXX;
1900 	PDrawableSysData YY = X(image);
1901 	int render_rop = PictOpMinimum - 1;
1902 
1903 	switch ( req-> rop ) {
1904 		case GXcopy:  render_rop = PictOpSrc;   break;
1905 		case GXclear: render_rop = PictOpClear; break;
1906 		case GXnoop:  render_rop = PictOpDst;   break;
1907 	}
1908 
1909 	if ( render_rop >= PictOpMinimum ) {
1910 		/* cheap on-server blit */
1911 		XRenderComposite(
1912 			DISP, render_rop, YY->argb_picture, 0, XX-> argb_picture,
1913 			req->src_x, req->src_y, 0, 0,
1914 			req->dst_x, req->dst_y, req->w, req->h
1915 		);
1916 		XSync(DISP, false);
1917 		return true;
1918 	} else {
1919 		/* expensive bit-transfer and blit with rop */
1920 		Handle obj;
1921 		Bool ret;
1922 		if (!( obj = img_get_image( X(image)-> gdrawable, req )))
1923 			return false;
1924 		req-> src_x = req-> src_y = 0;
1925 		ret = img_put_image_on_layered( self, obj, req );
1926 		Object_destroy( obj);
1927 		return ret;
1928 	}
1929 #else
1930 	return false;
1931 #endif
1932 }
1933 
1934 static Bool
img_put_argb_on_pixmap_or_widget(Handle self,Handle image,PutImageRequest * req,PutImageFunc fallback)1935 img_put_argb_on_pixmap_or_widget( Handle self, Handle image, PutImageRequest * req, PutImageFunc fallback)
1936 {
1937 #ifdef HAVE_X11_EXTENSIONS_XRENDER_H
1938 	DEFXX;
1939 	ImageCache *cache;
1940 	Pixmap pixmap;
1941 	GC gc;
1942 	XGCValues gcv;
1943 	Bool ret = false;
1944 	Picture picture;
1945 
1946 	if ( !guts. argb_visual. visual)
1947 		return fallback( self, image, req);
1948 
1949 	if (!(cache = prima_image_cache((PImage) image, CACHE_LAYERED_ALPHA)))
1950 		return false;
1951 
1952 	pixmap = XCreatePixmap( DISP, guts.root, req->w, req->h, guts. argb_visual. depth);
1953 	gcv. graphics_exposures = false;
1954 	gc = XCreateGC( DISP, pixmap, GCGraphicsExposures, &gcv);
1955 
1956 	SET_ROP(GXcopy);
1957 	if ( !( prima_put_ximage(
1958 		pixmap, gc, cache->image,
1959 		req->src_x, req->src_y, 0, 0,
1960 		req->w, req->h
1961 	))) goto FAIL;
1962 
1963 	picture = XRenderCreatePicture( DISP, pixmap, guts. xrender_argb32_format, 0, NULL);
1964 	XRenderComposite(
1965 		DISP, (req-> rop == ropSrcCopy) ? PictOpSrc : PictOpOver, picture, 0, XX->argb_picture,
1966 		0, 0, 0, 0,
1967 		req->dst_x, req->dst_y, req->w, req->h
1968 	);
1969 	XRenderFreePicture( DISP, picture);
1970 	XSync(DISP, false);
1971 	ret = true;
1972 
1973 FAIL:
1974 	XFreeGC( DISP, gc);
1975 	XFreePixmap( DISP, pixmap );
1976 	return ret;
1977 #else
1978 	return fallback( self, image, req);
1979 #endif
1980 }
1981 
1982 static Bool
img_put_argb_on_pixmap(Handle self,Handle image,PutImageRequest * req)1983 img_put_argb_on_pixmap( Handle self, Handle image, PutImageRequest * req)
1984 {
1985 	return img_put_argb_on_pixmap_or_widget( self, image, req, img_put_image_on_pixmap);
1986 }
1987 
1988 static Bool
img_put_argb_on_widget(Handle self,Handle image,PutImageRequest * req)1989 img_put_argb_on_widget( Handle self, Handle image, PutImageRequest * req)
1990 {
1991 	return img_put_argb_on_pixmap_or_widget( self, image, req, img_put_image_on_widget);
1992 }
1993 
1994 static Bool
img_put_composite(Handle self,Handle image,PutImageRequest * req)1995 img_put_composite( Handle self, Handle image, PutImageRequest * req)
1996 {
1997 #ifdef HAVE_X11_EXTENSIONS_XRENDER_H
1998 	DEFXX;
1999 	PDrawableSysData YY = X(image);
2000 	XRenderComposite(
2001 		DISP, (req-> rop == ropSrcCopy) ? PictOpSrc : PictOpOver,
2002 		YY->argb_picture, 0, XX->argb_picture,
2003 		0, 0, 0, 0,
2004 		req->dst_x, req->dst_y, req->w, req->h
2005 	);
2006 	XSync(DISP, false);
2007 	return true;
2008 #else
2009 	return false;
2010 #endif
2011 }
2012 
2013 static Bool
img_put_a8_on_layered(Handle self,Handle image,PutImageRequest * req)2014 img_put_a8_on_layered( Handle self, Handle image, PutImageRequest * req)
2015 {
2016 	DEFXX;
2017 	Bool ok;
2018 	ImageCache *cache;
2019 	if (!(cache = prima_image_cache((PImage) image, CACHE_A8)))
2020 		return false;
2021 	XSetPlaneMask( DISP, XX-> gc, guts. argb_bits. alpha_mask);
2022 	req->rop = GXcopy;
2023 	ok = img_put_ximage( self, cache->image, req);
2024 	XSetPlaneMask( DISP, XX-> gc, AllPlanes);
2025 	return ok;
2026 }
2027 
2028 static Bool
img_put_argb_on_layered(Handle self,Handle image,PutImageRequest * req)2029 img_put_argb_on_layered( Handle self, Handle image, PutImageRequest * req)
2030 {
2031 #ifdef HAVE_X11_EXTENSIONS_XRENDER_H
2032 	DEFXX;
2033 	ImageCache *cache;
2034 	Pixmap pixmap;
2035 	GC gc;
2036 	XGCValues gcv;
2037 	Bool ret = false;
2038 	Picture picture;
2039 
2040 	if (!(cache = prima_image_cache((PImage) image, CACHE_LAYERED_ALPHA)))
2041 		return false;
2042 
2043 	pixmap = XCreatePixmap( DISP, guts.root, req->w, req->h, guts. argb_visual. depth);
2044 	gcv. graphics_exposures = false;
2045 	gc = XCreateGC( DISP, pixmap, GCGraphicsExposures, &gcv);
2046 
2047 	SET_ROP(GXcopy);
2048 	if ( !( prima_put_ximage(
2049 		pixmap, gc, cache->image,
2050 		req->src_x, req->src_y, 0, 0,
2051 		req->w, req->h
2052 	))) goto FAIL;
2053 
2054 	picture = XRenderCreatePicture( DISP, pixmap, guts. xrender_argb32_format, 0, NULL);
2055 	if ( XX-> clip_mask_extent. x != 0 && XX-> clip_mask_extent. y != 0)
2056 		XRenderSetPictureClipRegion(DISP, picture, XX->current_region);
2057 	XRenderComposite(
2058 		DISP, (req-> rop == ropSrcCopy) ? PictOpSrc : PictOpOver, picture, 0, XX-> argb_picture,
2059 		0, 0, 0, 0,
2060 		req->dst_x, req->dst_y, req->w, req->h
2061 	);
2062 	XRenderFreePicture( DISP, picture);
2063 	XSync(DISP, false);
2064 	ret = true;
2065 
2066 FAIL:
2067 	XFreeGC( DISP, gc);
2068 	XFreePixmap( DISP, pixmap );
2069 	return ret;
2070 #else
2071 	return false;
2072 #endif
2073 }
2074 
2075 #define SRC_BITMAP       0
2076 #define SRC_PIXMAP       1
2077 #define SRC_IMAGE        2
2078 #define SRC_A8           3
2079 #define SRC_ARGB         4
2080 #define SRC_LAYERED      5
2081 #define SRC_MAX          5
2082 #define SRC_NUM          SRC_MAX+1
2083 
2084 PutImageFunc (*img_put_on_bitmap[SRC_NUM]) = {
2085 	img_put_bitmap_on_bitmap,
2086 	img_put_pixmap_on_bitmap,
2087 	img_put_image_on_bitmap,
2088 	img_put_image_on_bitmap,
2089 	img_put_argb_on_bitmap,
2090 	img_put_layered_on_bitmap
2091 };
2092 
2093 PutImageFunc (*img_put_on_pixmap[SRC_NUM]) = {
2094 	img_put_bitmap_on_pixmap,
2095 	img_put_copy_area,
2096 	img_put_image_on_pixmap,
2097 	img_put_image_on_pixmap,
2098 	img_put_argb_on_pixmap,
2099 	img_put_layered_on_pixmap
2100 };
2101 
2102 PutImageFunc (*img_put_on_widget[SRC_NUM]) = {
2103 	img_put_bitmap_on_pixmap,
2104 	img_put_copy_area,
2105 	img_put_image_on_widget,
2106 	img_put_image_on_widget,
2107 	img_put_argb_on_widget,
2108 	img_put_layered_on_pixmap
2109 };
2110 
2111 PutImageFunc (*img_put_on_layered[SRC_NUM]) = {
2112 	img_put_bitmap_on_pixmap,
2113 	img_put_pixmap_on_layered,
2114 	img_put_image_on_layered,
2115 	img_put_a8_on_layered,
2116 	img_put_argb_on_layered,
2117 	img_put_composite
2118 };
2119 
2120 static int
get_image_src_format(Handle self,Handle image,int * rop)2121 get_image_src_format( Handle self, Handle image, int * rop )
2122 {
2123 	DEFXX;
2124 	PDrawableSysData YY = X(image);
2125 	int src = -1;
2126 
2127 	if ( XT_IS_DBM(YY)) {
2128 		if (XT_IS_BITMAP(YY) || ( XT_IS_PIXMAP(YY) && guts.depth==1))
2129 			src = SRC_BITMAP;
2130 		else if ( XF_LAYERED(YY))
2131 			src = SRC_LAYERED;
2132 		else if ( XT_IS_PIXMAP(YY))
2133 			src = SRC_PIXMAP;
2134 	} else if ( XT_IS_IMAGE(YY)) {
2135 		if ( XF_IN_PAINT(YY)) {
2136 			if ( XT_IS_BITMAP(YY) || ( XT_IS_PIXMAP(YY) && guts.depth==1))
2137 				src = SRC_BITMAP;
2138 			else if ( XF_LAYERED(YY))
2139 				src = SRC_LAYERED;
2140 			else if ( XT_IS_PIXMAP(YY))
2141 				src = SRC_PIXMAP;
2142 		} else if ( XT_IS_ICON(YY) && PIcon(image)->maskType == imbpp8) {
2143 			src = SRC_ARGB;
2144 		} else {
2145 			src = SRC_IMAGE;
2146 			if (XF_LAYERED(XX) && !XT_IS_ICON(YY) && (PImage(image)->type & imGrayScale) && *rop == ropAlphaCopy ) {
2147 				src = SRC_A8;
2148 				*rop = ropCopyPut;
2149 			}
2150 		}
2151 	}
2152 
2153 	return src;
2154 }
2155 
2156 Bool
apc_gp_put_image(Handle self,Handle image,int x,int y,int xFrom,int yFrom,int xLen,int yLen,int rop)2157 apc_gp_put_image( Handle self, Handle image, int x, int y, int xFrom, int yFrom, int xLen, int yLen, int rop)
2158 {
2159 	DEFXX;
2160 	PImage img = PImage( image);
2161 	PutImageRequest req;
2162 	PutImageFunc ** dst = NULL;
2163 	Bool ok;
2164 	XGCValues gcv;
2165 	int src;
2166 
2167 	if ( PObject( self)-> options. optInDrawInfo) return false;
2168 	if ( !XF_IN_PAINT(XX)) return false;
2169 
2170 	if ( xFrom >= img-> w || yFrom >= img-> h) return false;
2171 	if ( xFrom + xLen > img-> w) xLen = img-> w - xFrom;
2172 	if ( yFrom + yLen > img-> h) yLen = img-> h - yFrom;
2173 	if ( xLen <= 0 || yLen <= 0) return false;
2174 
2175 	SHIFT( x, y);
2176 	bzero( &req, sizeof(req));
2177 	req. src_x = xFrom;
2178 	req. src_y = img->h - yFrom - yLen;
2179 	req. dst_x = x;
2180 	req. dst_y = XX->size. y - y - yLen;
2181 	req. w     = xLen;
2182 	req. h     = yLen;
2183 
2184 	if (XT_IS_BITMAP(XX) || (( XT_IS_PIXMAP(XX) || XT_IS_APPLICATION(XX)) && guts.depth==1))
2185 		dst = img_put_on_bitmap;
2186 	else if ( XF_LAYERED(XX))
2187 		dst =  img_put_on_layered;
2188 	else if ( XT_IS_PIXMAP(XX) || XT_IS_APPLICATION(XX))
2189 		dst =  img_put_on_pixmap;
2190 	else if ( XT_IS_WIDGET(XX))
2191 		dst =  img_put_on_widget;
2192 	if (!dst) {
2193 		warn("cannot guess surface type");
2194 		return false;
2195 	}
2196 	src = get_image_src_format(self, image, &rop);
2197 	if ( rop > ropNoOper ) return false;
2198 	if ( src < 0 ) {
2199 		warn("cannot guess image type");
2200 		return false;
2201 	}
2202 	/* printf("dst: %x(%d), b %x, p %x, l %x, w %x\n", dst, src, img_put_on_bitmap, img_put_on_pixmap, img_put_on_widget, img_put_on_layered); */
2203 
2204 	if ( !XGetGCValues(DISP, XX->gc, GCFunction, &gcv))
2205 		warn("cannot query XGCValues");
2206 
2207 	req. old_rop = gcv.function;
2208 	req. rop     = (src == SRC_LAYERED || src == SRC_ARGB) ? rop : prima_rop_map( rop);
2209 
2210 	ok = (*dst[src])(self, image, &req);
2211 
2212 	if ( gcv.function != req. old_rop)
2213 		XSetFunction( DISP, XX->gc, gcv. function);
2214 
2215 	return ok;
2216 }
2217 
2218 Bool
apc_image_begin_paint(Handle self)2219 apc_image_begin_paint( Handle self)
2220 {
2221 	DEFXX;
2222 	PIcon img = PIcon( self);
2223 	int icon = XX-> type. icon;
2224 	Bool bitmap = (img-> type  == imBW) || ( guts. idepth == 1);
2225 	Bool layered = icon && img-> maskType == imbpp8 && guts. argb_visual. visual;
2226 	int depth = layered ? guts. argb_depth : ( bitmap ? 1 : guts. depth );
2227 
2228 	if ( !DISP) return false;
2229 	if (img-> w == 0 || img-> h == 0) return false;
2230 
2231 	XX-> gdrawable = XCreatePixmap( DISP, guts. root, img-> w, img-> h, depth);
2232 
2233 	XX-> type.pixmap = !bitmap;
2234 	XX-> type.bitmap = !!bitmap;
2235 	XX-> flags.layered = layered;
2236 	XX-> visual      = &guts. visual;
2237 	XX-> colormap    = guts. defaultColormap;
2238 	if ( XF_LAYERED(XX)) {
2239 		XX-> visual    = &guts. argb_visual;
2240 		XX-> colormap  = guts. argbColormap;
2241 	}
2242 	CREATE_ARGB_PICTURE(XX->gdrawable,
2243 		bitmap ? 1 : (XF_LAYERED(XX) ? 32 : 0),
2244 		XX->argb_picture);
2245 	XCHECKPOINT;
2246 	XX-> type. icon = 0;
2247 	prima_prepare_drawable_for_painting( self, false);
2248 	XX-> type. icon = icon;
2249 	PObject( self)-> options. optInDraw = 0;
2250 	XX->flags. paint = 0;
2251 	{
2252 		PutImageRequest req;
2253 		PutImageFunc ** dst = layered ? img_put_on_layered : ( bitmap ? img_put_on_bitmap : img_put_on_pixmap );
2254 		bzero(&req, sizeof(req));
2255 		req. w   = img-> w;
2256 		req. h   = img-> h;
2257 		req. rop = layered ? ropSrcCopy : GXcopy;
2258 		req. old_rop = XX-> gcv. function;
2259 		(*dst[layered ? SRC_ARGB : SRC_IMAGE])(self, self, &req);
2260 		/*                                     ^^^^^ ^^^^    :-)))  */
2261 		if ( req. old_rop != XX-> gcv. function)
2262 			XSetFunction( DISP, XX-> gc, XX-> gcv. function);
2263 	}
2264 	PObject( self)-> options. optInDraw = 1;
2265 	XX->flags. paint = 1;
2266 	return true;
2267 }
2268 
2269 static void
convert_8_to_24(XImage * i,PImage img,RGBABitDescription * bits)2270 convert_8_to_24( XImage *i, PImage img, RGBABitDescription * bits)
2271 {
2272 	int y, x, h, w;
2273 	Pixel8 *d;
2274 	register Pixel24 *line;
2275 
2276 	/*
2277 		Compensate less than 8-bit true-color memory layout depth converted into
2278 		real 8 bit, a bit slower but more error-prone in general sense. Although
2279 		Prima::gp-problems advises not to check against 0xffffff as white, since
2280 		white is 0xf8f8f8 on 15-bit displays for example, it is not practical to
2281 		use this check fro example when a RGB image is to be converted into a
2282 		low-palette image with RGB(0xff,0xff,0xff) expected and desirable palette
2283 		slot value.
2284 	*/
2285 
2286 	int rmax = 0xff & ( 0xff << ( 8 - bits-> red_range));
2287 	int gmax = 0xff & ( 0xff << ( 8 - bits-> green_range));
2288 	int bmax = 0xff & ( 0xff << ( 8 - bits-> blue_range));
2289 	if ( rmax == 0 ) rmax = 0xff;
2290 	if ( gmax == 0 ) gmax = 0xff;
2291 	if ( bmax == 0 ) bmax = 0xff;
2292 
2293 	h = img-> h; w = img-> w;
2294 	for ( y = 0; y < h; y++) {
2295 		d = (Pixel8 *)(i-> data + (h-y-1)*i-> bytes_per_line);
2296 		line = (Pixel24*)(img-> data + y*img-> lineSize);
2297 		for ( x = 0; x < w; x++) {
2298 			line-> a0 = (((*d & bits-> blue_mask)  >> bits-> blue_shift) << 8)  >> bits->  blue_range;
2299 			line-> a1 = (((*d & bits-> green_mask) >> bits-> green_shift) << 8) >> bits->  green_range;
2300 			line-> a2 = (((*d & bits-> red_mask)   >> bits-> red_shift) << 8)   >> bits->  red_range;
2301 			if ( line-> a0 == bmax) line-> a0 = 0xff;
2302 			if ( line-> a1 == gmax) line-> a1 = 0xff;
2303 			if ( line-> a2 == rmax) line-> a2 = 0xff;
2304 			line++; d++;
2305 		}
2306 	}
2307 }
2308 static void
convert_16_to_24(XImage * i,PImage img,RGBABitDescription * bits)2309 convert_16_to_24( XImage *i, PImage img, RGBABitDescription * bits)
2310 {
2311 	int y, x, h, w;
2312 	Pixel16 *d;
2313 	register Pixel24 *line;
2314 
2315 	/*
2316 		Compensate less than 8-bit true-color memory layout depth converted into
2317 		real 8 bit, a bit slower but more error-prone in general sense. Although
2318 		Prima::gp-problems advises not to check against 0xffffff as white, since
2319 		white is 0xf8f8f8 on 15-bit displays for example, it is not practical to
2320 		use this check fro example when a RGB image is to be converted into a
2321 		low-palette image with RGB(0xff,0xff,0xff) expected and desirable palette
2322 		slot value.
2323 	*/
2324 
2325 	int rmax = 0xff & ( 0xff << ( 8 - bits-> red_range));
2326 	int gmax = 0xff & ( 0xff << ( 8 - bits-> green_range));
2327 	int bmax = 0xff & ( 0xff << ( 8 - bits-> blue_range));
2328 	if ( rmax == 0 ) rmax = 0xff;
2329 	if ( gmax == 0 ) gmax = 0xff;
2330 	if ( bmax == 0 ) bmax = 0xff;
2331 
2332 	h = img-> h; w = img-> w;
2333 	for ( y = 0; y < h; y++) {
2334 		d = (Pixel16 *)(i-> data + (h-y-1)*i-> bytes_per_line);
2335 		line = (Pixel24*)(img-> data + y*img-> lineSize);
2336 		if ( guts.machine_byte_order != guts.byte_order) {
2337 			for ( x = 0; x < w; x++) {
2338 				register Pixel16 dd = REVERSE_BYTES_16(*d);
2339 				line-> a0 = (((dd & bits-> blue_mask)  >> bits-> blue_shift) << 8)  >> bits->  blue_range;
2340 				line-> a1 = (((dd & bits-> green_mask) >> bits-> green_shift) << 8) >> bits->  green_range;
2341 				line-> a2 = (((dd & bits-> red_mask)   >> bits-> red_shift) << 8)   >> bits->  red_range;
2342 				if ( line-> a0 == bmax) line-> a0 = 0xff;
2343 				if ( line-> a1 == gmax) line-> a1 = 0xff;
2344 				if ( line-> a2 == rmax) line-> a2 = 0xff;
2345 				line++; d++;
2346 			}
2347 		} else {
2348 			for ( x = 0; x < w; x++) {
2349 				line-> a0 = (((*d & bits-> blue_mask)  >> bits-> blue_shift) << 8)  >> bits->  blue_range;
2350 				line-> a1 = (((*d & bits-> green_mask) >> bits-> green_shift) << 8) >> bits->  green_range;
2351 				line-> a2 = (((*d & bits-> red_mask)   >> bits-> red_shift) << 8)   >> bits->  red_range;
2352 				if ( line-> a0 == bmax) line-> a0 = 0xff;
2353 				if ( line-> a1 == gmax) line-> a1 = 0xff;
2354 				if ( line-> a2 == rmax) line-> a2 = 0xff;
2355 				line++; d++;
2356 			}
2357 		}
2358 	}
2359 }
2360 
2361 static void
convert_32_to_24(XImage * i,PImage img,RGBABitDescription * bits)2362 convert_32_to_24( XImage *i, PImage img, RGBABitDescription * bits)
2363 {
2364 	int y, x, h, w;
2365 	Pixel32 *d, dd;
2366 	Pixel24 *line;
2367 
2368 	h = img-> h; w = img-> w;
2369 	if ( guts.machine_byte_order != guts.byte_order) {
2370 		for ( y = 0; y < h; y++) {
2371 			d = (Pixel32 *)(i-> data + (h-y-1)*i-> bytes_per_line);
2372 			line = (Pixel24*)(img-> data + y*img-> lineSize);
2373 			for ( x = 0; x < w; x++) {
2374 				dd = REVERSE_BYTES_32(*d);
2375 				line-> a0 = (((dd & bits-> blue_mask)  >> bits-> blue_shift) << 8)  >> bits-> blue_range;
2376 				line-> a1 = (((dd & bits-> green_mask) >> bits-> green_shift) << 8) >> bits-> green_range;
2377 				line-> a2 = (((dd & bits-> red_mask)   >> bits-> red_shift) << 8)   >> bits-> red_range;
2378 				d++; line++;
2379 			}
2380 		}
2381 	} else {
2382 		for ( y = 0; y < h; y++) {
2383 			d = (Pixel32 *)(i-> data + (h-y-1)*i-> bytes_per_line);
2384 			line = (Pixel24*)(img-> data + y*img-> lineSize);
2385 			for ( x = 0; x < w; x++) {
2386 				line-> a0 = (((*d & bits-> blue_mask)  >> bits-> blue_shift) << 8)  >> bits-> blue_range;
2387 				line-> a1 = (((*d & bits-> green_mask) >> bits-> green_shift) << 8) >> bits-> green_range;
2388 				line-> a2 = (((*d & bits-> red_mask)   >> bits-> red_shift) << 8)   >> bits-> red_range;
2389 				d++; line++;
2390 			}
2391 		}
2392 	}
2393 }
2394 
2395 static void
convert_equal_paletted(XImage * i,PImage img)2396 convert_equal_paletted( XImage *i, PImage img)
2397 {
2398 	int y, h;
2399 	Pixel8 *d, *line;
2400 	XColor xc[256];
2401 
2402 	h = img-> h;
2403 	d = ( Pixel8*)(i-> data + (h-1) * i-> bytes_per_line);
2404 	line = (Pixel8*)img-> data;
2405 	bzero( line, img-> dataSize);
2406 	for ( y = 0; y < h; y++) {
2407 		memcpy( line, d, img-> w);
2408 		d -= i-> bytes_per_line;
2409 		line += img-> lineSize;
2410 	}
2411 	for ( y = 0; y < 256; y++) guts. mappingPlace[y] = -1;
2412 	for ( y = 0; y < img-> dataSize; y++)
2413 		guts. mappingPlace[ img-> data[y]] = 0;
2414 	for ( y = 0; y < guts. palSize; y++) xc[y]. pixel = y;
2415 	XQueryColors( DISP, guts. defaultColormap, xc, guts. palSize);
2416 
2417 /* XXX if ( guts. bit_order != MSBFirst) prima_mirror_bytes( img-> data, img-> dataSize); */
2418 
2419 	img-> palSize = 0;
2420 	for ( y = 0; y < 256; y++)
2421 		if ( guts. mappingPlace[y] == 0) {
2422 			img-> palette[img-> palSize]. r = xc[y].red/256;
2423 			img-> palette[img-> palSize]. g = xc[y].green/256;
2424 			img-> palette[img-> palSize]. b = xc[y].blue/256;
2425 			guts. mappingPlace[y] = img-> palSize++;
2426 		}
2427 
2428 	for ( y = 0; y < img-> dataSize; y++)
2429 		img-> data[y] = guts. mappingPlace[ img-> data[y]];
2430 }
2431 
2432 Bool
prima_query_image(Handle self,XImage * i)2433 prima_query_image( Handle self, XImage * i)
2434 {
2435 	PImage img = PImage( self);
2436 	int target_depth = ( img-> type == imBW) ? 1 : guts. qdepth;
2437 
2438 	if (( img-> type & imBPP) != target_depth)
2439 		CImage( self)-> create_empty( self, img-> w, img-> h, target_depth);
2440 
2441 	X(self)-> size. x = img-> w;
2442 	X(self)-> size. y = img-> h;
2443 
2444 	if ( target_depth == 1) {
2445 		prima_copy_xybitmap( img-> data, (Byte*)i-> data, img-> w, img-> h, img-> lineSize, i-> bytes_per_line);
2446 	} else {
2447 	switch ( guts. idepth) {
2448 	case 8:
2449 		switch ( target_depth) {
2450 		case 4:
2451 			CImage( self)-> create_empty( self, img-> w, img-> h, 8);
2452 		case 8:
2453 			convert_equal_paletted( i, img);
2454 			break;
2455 		default: goto slurp_image_unsupported_depth;
2456 		}
2457 		break;
2458 	case 16:
2459 		switch ( target_depth) {
2460 		case 24:
2461 			convert_16_to_24( i, img, &guts. screen_bits);
2462 			break;
2463 		default: goto slurp_image_unsupported_depth;
2464 		}
2465 		break;
2466 	case 32:
2467 		switch ( target_depth) {
2468 		case 24:
2469 			convert_32_to_24( i, img, &guts. screen_bits);
2470 			break;
2471 		default: goto slurp_image_unsupported_depth;
2472 		}
2473 		break;
2474 slurp_image_unsupported_depth:
2475 	default:
2476 		warn("UAI_023: unsupported backing image conversion from %d to %d\n", guts.idepth, target_depth);
2477 		return false;
2478 	}
2479 	}
2480 	return true;
2481 }
2482 
2483 Bool
prima_std_query_image(Handle self,Pixmap px)2484 prima_std_query_image( Handle self, Pixmap px)
2485 {
2486 	XImage * i;
2487 	Bool mono = PImage(self)-> type == imBW || guts. depth == 1;
2488 	Bool ret;
2489 	if (!( i = XGetImage( DISP, px, 0, 0,
2490 		PImage(self)-> w, PImage( self)-> h,
2491 		mono ? 1 : AllPlanes, mono ? XYPixmap : ZPixmap)))
2492 		return false;
2493 	XCHECKPOINT;
2494 	ret = prima_query_image( self, i);
2495 	XDestroyImage( i);
2496 	return ret;
2497 }
2498 
2499 static void
convert_32_to_mask(XImage * i,PIcon img)2500 convert_32_to_mask( XImage *i, PIcon img)
2501 {
2502 	int y, x, h, w;
2503 	Pixel32 *d, dd;
2504 	Pixel8 *line;
2505 	int max = 0xff & ( 0xff << ( 8 - guts. argb_bits. alpha_range));
2506 	if ( max == 0 ) max = 0xff;
2507 
2508 	h = img-> h; w = img-> w;
2509 	if ( guts.machine_byte_order != guts.byte_order) {
2510 		for ( y = 0; y < h; y++) {
2511 			d = (Pixel32 *)(i-> data + (h-y-1)*i-> bytes_per_line);
2512 			line = (Pixel8*)(img-> mask + y*img-> maskLine);
2513 			for ( x = 0; x < w; x++) {
2514 				dd = REVERSE_BYTES_32(*d);
2515 				*line = (((dd & guts. argb_bits. alpha_mask) >> guts. argb_bits. alpha_shift) << 8) >> guts. argb_bits. alpha_range;
2516 				if ( *line == max) *line = 0xff;
2517 				d++; line++;
2518 			}
2519 		}
2520 	} else {
2521 		for ( y = 0; y < h; y++) {
2522 			d = (Pixel32*)(i-> data + (h-y-1)*i-> bytes_per_line);
2523 			line = (Pixel8*)(img-> mask + y*img-> maskLine);
2524 			for ( x = 0; x < w; x++) {
2525 				*line = (((*d & guts. argb_bits. alpha_mask) >> guts. argb_bits. alpha_shift) << 8) >> guts. argb_bits. alpha_range;
2526 				if ( *line == max) *line = 0xff;
2527 				d++; line++;
2528 			}
2529 		}
2530 	}
2531 }
2532 
2533 static void
convert_16_to_mask(XImage * i,PIcon img)2534 convert_16_to_mask( XImage *i, PIcon img)
2535 {
2536 	int y, x, h, w;
2537 	Pixel16 *d, dd;
2538 	Pixel8 *line;
2539 	int max = 0xff & ( 0xff << ( 8 - guts. argb_bits. alpha_range));
2540 	if ( max == 0 ) max = 0xff;
2541 
2542 	h = img-> h; w = img-> w;
2543 	if ( guts.machine_byte_order != guts.byte_order) {
2544 		for ( y = 0; y < h; y++) {
2545 			d = (Pixel16 *)(i-> data + (h-y-1)*i-> bytes_per_line);
2546 			line = (Pixel8*)(img-> mask + y*img-> maskLine);
2547 			for ( x = 0; x < w; x++) {
2548 				dd = REVERSE_BYTES_16(*d);
2549 				*line = (((dd & guts. argb_bits. alpha_mask) >> guts. argb_bits. alpha_shift) << 8) >> guts. argb_bits. alpha_range;
2550 				if ( *line == max) *line = 0xff;
2551 				d++; line++;
2552 			}
2553 		}
2554 	} else {
2555 		for ( y = 0; y < h; y++) {
2556 			d = (Pixel16*)(i-> data + (h-y-1)*i-> bytes_per_line);
2557 			line = (Pixel8*)(img-> mask + y*img-> maskLine);
2558 			for ( x = 0; x < w; x++) {
2559 				*line = (((*d & guts. argb_bits. alpha_mask) >> guts. argb_bits. alpha_shift) << 8) >> guts. argb_bits. alpha_range;
2560 				if ( *line == max) *line = 0xff;
2561 				d++; line++;
2562 			}
2563 		}
2564 	}
2565 }
2566 
2567 static void
convert_8_to_mask(XImage * i,PIcon img)2568 convert_8_to_mask( XImage *i, PIcon img)
2569 {
2570 	int y, x, h, w;
2571 	Pixel8 *d;
2572 	Pixel8 *line;
2573 	int max = 0xff & ( 0xff << ( 8 - guts. argb_bits. alpha_range));
2574 	if ( max == 0 ) max = 0xff;
2575 
2576 	h = img-> h; w = img-> w;
2577 	for ( y = 0; y < h; y++) {
2578 		d = (Pixel8*)(i-> data + (h-y-1)*i-> bytes_per_line);
2579 		line = (Pixel8*)(img-> mask + y*img-> maskLine);
2580 		for ( x = 0; x < w; x++) {
2581 			*line = (((*d & guts. argb_bits. alpha_mask) >> guts. argb_bits. alpha_shift) << 8) >> guts. argb_bits. alpha_range;
2582 			if ( *line == max) *line = 0xff;
2583 			d++; line++;
2584 		}
2585 	}
2586 }
2587 
2588 Bool
prima_query_argb_rect(Handle self,Pixmap px,int x,int y,int w,int h)2589 prima_query_argb_rect( Handle self, Pixmap px, int x, int y, int w, int h)
2590 {
2591 	XImage * i;
2592 	PIcon img = (PIcon) self;
2593 
2594 	if (!( i = XGetImage( DISP, px, x, y, w, h,
2595 		AllPlanes, ZPixmap)))
2596 		return false;
2597 	XCHECKPOINT;
2598 
2599 	if (( img-> type & imBPP) != 24 || img->maskType != imbpp8)
2600 		CIcon( self)-> create_empty_icon( self, w, h, imRGB, imbpp8);
2601 
2602 	switch ( guts. argb_depth) {
2603 	case 8:
2604 		convert_8_to_24( i, (PImage)img, &guts. argb_bits);
2605 		convert_8_to_mask( i, img);
2606 		break;
2607 	case 16:
2608 		convert_16_to_24( i, (PImage)img, &guts. argb_bits);
2609 		convert_16_to_mask( i, img);
2610 		break;
2611 	case 32:
2612 		convert_32_to_24( i, (PImage)img, &guts. argb_bits);
2613 		convert_32_to_mask( i, img);
2614 		break;
2615 	default:
2616 		warn("UAI_023: unsupported backing image conversion from %d to %d\n", guts. argb_depth, guts. qdepth);
2617 		return false;
2618 	}
2619 
2620 	XDestroyImage( i);
2621 	return true;
2622 }
2623 
2624 Bool
prima_query_argb_image(Handle self,Pixmap px)2625 prima_query_argb_image( Handle self, Pixmap px)
2626 {
2627 	return prima_query_argb_rect( self, px, 0, 0, PImage(self)-> w, PImage( self)-> h);
2628 }
2629 
2630 Pixmap
prima_std_pixmap(Handle self,int type)2631 prima_std_pixmap( Handle self, int type)
2632 {
2633 	Pixmap px;
2634 	XGCValues gcv;
2635 	GC gc;
2636 	PImage img = ( PImage) self;
2637 	unsigned long fore, back;
2638 
2639 	ImageCache * xi = prima_image_cache(( PImage) self, type);
2640 	if ( !xi) return NULL_HANDLE;
2641 
2642 	px = XCreatePixmap( DISP, guts. root, img-> w, img-> h,
2643 		( type == CACHE_BITMAP) ? 1 : guts. depth);
2644 	if ( !px) return NULL_HANDLE;
2645 
2646 	gcv. graphics_exposures = false;
2647 	gc = XCreateGC( DISP, guts. root, GCGraphicsExposures, &gcv);
2648 	if ( guts. palSize > 0) {
2649 		fore = prima_color_find( self,
2650 			RGB_COMPOSITE( img-> palette[1].r, img-> palette[1].g, img-> palette[1].b),
2651 			-1, NULL, RANK_NORMAL);
2652 		back = prima_color_find( self,
2653 			RGB_COMPOSITE( img-> palette[0].r, img-> palette[0].g, img-> palette[0].b),
2654 			-1, NULL, RANK_NORMAL);
2655 	} else {
2656 		fore =
2657 			(((img-> palette[1].r << guts. screen_bits. red_range  ) >> 8) << guts. screen_bits.   red_shift) |
2658 			(((img-> palette[1].g << guts. screen_bits. green_range) >> 8) << guts. screen_bits. green_shift) |
2659 			(((img-> palette[1].b << guts. screen_bits. blue_range ) >> 8) << guts. screen_bits.  blue_shift);
2660 		back =
2661 			(((img-> palette[0].r << guts. screen_bits. red_range  ) >> 8) << guts. screen_bits.   red_shift) |
2662 			(((img-> palette[0].g << guts. screen_bits. green_range) >> 8) << guts. screen_bits. green_shift) |
2663 			(((img-> palette[0].b << guts. screen_bits. blue_range ) >> 8) << guts. screen_bits.  blue_shift);
2664 	}
2665 
2666 	XSetForeground( DISP, gc, fore);
2667 	XSetBackground( DISP, gc, back);
2668 	prima_put_ximage( px, gc, xi->image, 0, 0, 0, 0, img-> w, img-> h);
2669 	XFreeGC( DISP, gc);
2670 	return px;
2671 }
2672 
2673 Bool
apc_image_end_paint(Handle self)2674 apc_image_end_paint( Handle self)
2675 {
2676 	DEFXX;
2677 	if ( XF_LAYERED(XX))
2678 		prima_query_argb_image( self, XX-> gdrawable);
2679 	else
2680 		prima_std_query_image( self, XX-> gdrawable);
2681 	prima_cleanup_drawable_after_painting( self);
2682 	if ( XX-> gdrawable) {
2683 		XFreePixmap( DISP, XX-> gdrawable);
2684 		XCHECKPOINT;
2685 		XX-> gdrawable = 0;
2686 	}
2687 	clear_caches( self);
2688 	return true;
2689 }
2690 
2691 Bool
apc_gp_stretch_image(Handle self,Handle image,int dst_x,int dst_y,int src_x,int src_y,int dst_w,int dst_h,int src_w,int src_h,int rop)2692 apc_gp_stretch_image( Handle self, Handle image,
2693 	int dst_x, int dst_y, int src_x, int src_y,
2694 	int dst_w, int dst_h, int src_w, int src_h, int rop)
2695 {
2696 	DEFXX;
2697 	PDrawableSysData YY = X(image);
2698 	PImage img = (PImage) image;
2699 	int src;
2700 	Handle obj;
2701 	Bool ok;
2702 
2703 	if ( PObject( self)-> options. optInDrawInfo) return false;
2704 	if ( !XF_IN_PAINT(XX)) return false;
2705 
2706 	if ( src_h < 0) {
2707 		src_h = -src_h;
2708 		dst_h = -dst_h;
2709 	}
2710 	if ( src_w < 0) {
2711 		src_w = -src_w;
2712 		dst_w = -dst_w;
2713 	}
2714 	if ( abs(src_x) >= img-> w) return false;
2715 	if ( abs(src_y) >= img-> h) return false;
2716 	if ( src_w == 0 || src_h == 0) return false;
2717 	if ( src_x < 0) {
2718 		dst_x -= src_x * dst_w / src_w;
2719 		dst_w += src_x * dst_w / src_w;
2720 		src_w += src_x;
2721 		src_x = 0;
2722 	}
2723 	if ( src_y < 0) {
2724 		dst_y -= src_y * dst_h / src_h;
2725 		dst_h += src_y * dst_h / src_h;
2726 		src_h += src_y;
2727 		src_y = 0;
2728 	}
2729 	if ( src_x + src_w > img-> w) {
2730 		dst_w = (img-> w - src_x) * dst_w / src_w;
2731 		src_w = img-> w - src_x;
2732 	}
2733 	if ( src_y + src_h > img-> h) {
2734 		dst_h = (img-> h - src_y) * dst_h / src_h;
2735 		src_h = img-> h - src_y;
2736 	}
2737 	if ( src_w <= 0 || src_h <= 0) return false;
2738 
2739 	src = get_image_src_format(self, image, &rop);
2740 	if ( rop > ropNoOper ) return false;
2741 	if ( src < 0 ) return false;
2742 
2743 	/* query xserver bits */
2744 	if ( src == SRC_BITMAP || src == SRC_PIXMAP ) {
2745 		XImage *i;
2746 
2747 		if ( !( i = XGetImage( DISP, YY-> gdrawable,
2748 				src_x, img-> h - src_y - src_h, src_w, src_h,
2749 				AllPlanes, (src == SRC_BITMAP) ? XYPixmap : ZPixmap)))
2750 			return false;
2751 
2752 		if ( XT_IS_ICON(YY)) {
2753 			int height = src_w;
2754 			PIcon isrc = (PIcon) image, idst;
2755 			obj = ( Handle) create_object("Prima::Icon", "");
2756 			idst = (PIcon) obj;
2757 			CIcon( obj)-> create_empty_icon( obj, src_w, src_h,
2758 				(src == SRC_BITMAP) ? imBW : guts. qdepth,
2759 				isrc-> maskType
2760 			);
2761 			if ( isrc->maskType == imbpp8) {
2762 				while ( height-- > 0)
2763 					memcpy(
2764 						idst-> mask + height * idst-> maskLine,
2765 						isrc-> mask + ( src_y + height) * isrc-> maskLine + src_x, src_w);
2766 			} else {
2767 				while ( height-- > 0)
2768 					bc_mono_copy(
2769 						isrc->mask + ( src_y + height) * isrc->maskLine,
2770 						idst-> mask + height * idst-> maskLine, src_x, src_w);
2771 			}
2772 		} else {
2773 			obj = ( Handle) create_object("Prima::Image", "");
2774 			CIcon( obj)-> create_empty( obj, src_w, src_h,
2775 				(src == SRC_BITMAP) ? imBW : guts. qdepth
2776 			);
2777 		}
2778 		if (!prima_query_image( obj, i)) {
2779 			XDestroyImage( i);
2780 			Object_destroy( obj);
2781 			return false;
2782 		}
2783 		XDestroyImage( i);
2784 		if ( src == SRC_BITMAP && !XT_IS_IMAGE(YY)) {
2785 			PImage o = (PImage) obj;
2786 			o->type = imbpp1;
2787 			o->palette[0].r = XX->fore. color & 0xff;
2788 			o->palette[0].g = (XX->fore. color >> 8) & 0xff;
2789 			o->palette[0].b = (XX->fore. color >> 16) & 0xff;
2790 			o->palette[1].r = XX->back. color & 0xff;
2791 			o->palette[1].g = (XX->back. color >> 8) & 0xff;
2792 			o->palette[1].b = (XX->back. color >> 16) & 0xff;
2793 		}
2794 		ok = apc_gp_stretch_image( self, obj, dst_x, dst_y, 0, 0, dst_w, dst_h, src_w, src_h, rop);
2795 	} else if ( src == SRC_LAYERED ) {
2796 		obj = ( Handle) create_object("Prima::Icon", "");
2797 		ok = prima_query_argb_rect( obj, X(image)-> gdrawable, src_x, PDrawable(image)-> h - src_h - src_y, src_w, src_h);
2798 		if ( !ok ) {
2799 			Object_destroy( obj );
2800 			return false;
2801 		}
2802 		ok = apc_gp_stretch_image( self, obj, dst_x, dst_y, 0, 0, dst_w, dst_h, src_w, src_h, rop);
2803 	} else if ( img->w != dst_w || img->h != dst_h || src_x != 0 || src_y != 0) {
2804 		/* extract local bits */
2805 		obj = CImage(image)->extract( image, src_x, src_y, src_w, src_h );
2806 		if ( !obj ) return false;
2807 		CImage(obj)-> set_scaling( obj, istBox );
2808 		CImage(obj)-> stretch( obj, dst_w, dst_h );
2809 		ok  = apc_gp_put_image( self, obj, dst_x, dst_y, 0, 0, dst_w, dst_h, rop);
2810 	} else {
2811 		return apc_gp_put_image( self, image, dst_x, dst_y, 0, 0, dst_w, dst_h, rop);
2812 	}
2813 
2814 	Object_destroy( obj );
2815 	return ok;
2816 }
2817 
2818 Bool
apc_application_get_bitmap(Handle self,Handle image,int x,int y,int xLen,int yLen)2819 apc_application_get_bitmap( Handle self, Handle image, int x, int y, int xLen, int yLen)
2820 {
2821 	DEFXX;
2822 	Bool inPaint = opt_InPaint, ret = false;
2823 	XImage * i;
2824 	XErrorEvent xr;
2825 
2826 	if ( !image || PObject(image)-> stage == csDead) return false;
2827 
2828 	XFLUSH;
2829 
2830 	/* rect validation - questionable but without it the request may be fatal ( by BadMatch) */
2831 	if ( x < 0) x = 0;
2832 	if ( y < 0) y = 0;
2833 	if ( x + xLen > XX-> size. x) xLen = XX-> size. x - x;
2834 	if ( y + yLen > XX-> size. y) yLen = XX-> size. y - y;
2835 	if ( xLen <= 0 || yLen <= 0) return false;
2836 
2837 #ifdef WITH_COCOA
2838 	if ( guts. use_quartz && prima_cocoa_is_x11_local()) {
2839 		uint32_t *pixels;
2840 		if ( PImage(image)->type != imRGB)
2841 			CImage( image)-> create_empty( image, xLen, yLen, imRGB);
2842 		if (( pixels = prima_cocoa_application_get_bitmap(
2843 			x, XX->size.y - y - yLen, xLen, yLen, XX->size.y
2844 		))) {
2845 			int y;
2846 			Byte *src = (Byte*) (pixels + xLen * (yLen - 1));
2847 			Byte *dst = PImage(image)->data;
2848 			for ( y = 0; y < yLen; y++, src -= xLen * 4, dst += PImage(image)->lineSize)
2849 				bc_bgri_rgb(src, dst, xLen);
2850 			free(pixels);
2851 			return true;
2852 		}
2853 	}
2854 #endif
2855 
2856 	if ( !inPaint) apc_application_begin_paint( self);
2857 
2858 	CImage( image)-> create_empty( image, xLen, yLen, guts. qdepth);
2859 	prima_save_xerror_event( &xr);
2860 	if ( guts. idepth == 1)
2861 		i = XGetImage( DISP, XX-> gdrawable, x, XX-> size.y - y - yLen, xLen, yLen, 1, XYPixmap);
2862 	else
2863 		i = XGetImage( DISP, XX-> gdrawable, x, XX-> size.y - y - yLen, xLen, yLen, AllPlanes, ZPixmap);
2864 	XCHECKPOINT;
2865 
2866 	if ( i) {
2867 		if ( !( ret = prima_query_image( image, i)))
2868 			warn("UAI_017: unsupported depths combination");
2869 		XDestroyImage( i);
2870 	}
2871 
2872 	if ( !inPaint) apc_application_end_paint( self);
2873 #ifdef WITH_GTK
2874 	if ( !ret && guts. use_gtk )
2875 		ret = prima_gtk_application_get_bitmap( self, image, x, y, xLen, yLen);
2876 #endif
2877 	if (ret) bzero( &xr, sizeof(xr));
2878 	prima_restore_xerror_event( &xr);
2879 
2880 	return ret;
2881 }
2882 
2883