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