1 /*
2  * Copyright (C) 2004-2021 Kim Woelders
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a copy
5  * of this software and associated documentation files (the "Software"), to
6  * deal in the Software without restriction, including without limitation the
7  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
8  * sell copies of the Software, and to permit persons to whom the Software is
9  * furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies of the Software, its documentation and marketing & publicity
13  * materials, and acknowledgment shall be given in the documentation, materials
14  * and software packages that this Software was used.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19  * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
20  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22  */
23 #include "config.h"
24 
25 #include <Imlib2.h>
26 #include <X11/Xlib.h>
27 #if USE_XRENDER
28 #include <X11/extensions/Xrender.h>
29 #endif
30 
31 #include "E.h"
32 #include "eimage.h"
33 #include "file.h"
34 #include "xwin.h"
35 
36 #define IMG_CACHE_DEFAULT_SIZE          (2 * 1024 * 1024)
37 #define XIM_CACHE_DEFAULT_COUNT         0
38 
39 void
EImageInit(void)40 EImageInit(void)
41 {
42    EImageSetCacheSize(Conf.testing.image_cache_size);
43    EImageSetXImageCacheSize(Conf.testing.ximage_cache_count, -1);
44    imlib_set_font_cache_size(512 * 1024);
45 
46    imlib_set_color_usage(128);
47 
48    imlib_context_set_display(disp);
49    imlib_context_set_visual(WinGetVisual(VROOT));
50    imlib_context_set_colormap(WinGetCmap(VROOT));
51 
52 #ifdef HAVE_IMLIB_CONTEXT_SET_MASK_ALPHA_THRESHOLD
53    imlib_context_set_mask_alpha_threshold(Conf.testing.mask_alpha_threshold);
54 #endif
55 
56    imlib_context_set_anti_alias(0);
57    imlib_context_set_dither(1);
58 }
59 
60 void
EImageExit(int quit __UNUSED__)61 EImageExit(int quit __UNUSED__)
62 {
63 #if HAVE_IMLIB_CONTEXT_DISCONNECT_DISPLAY
64    imlib_context_disconnect_display();
65 #endif
66 }
67 
68 void
EImageSetCacheSize(int size)69 EImageSetCacheSize(int size)
70 {
71    Conf.testing.image_cache_size = size;
72    if (size < 0)
73       size = IMG_CACHE_DEFAULT_SIZE;
74    imlib_set_cache_size(size);
75 }
76 
77 void
EImageSetXImageCacheSize(int count,int size __UNUSED__)78 EImageSetXImageCacheSize(int count, int size __UNUSED__)
79 {
80    Conf.testing.ximage_cache_count = count;
81 #if HAVE_IMLIB_XIMAGE_CACHE_CONTROL
82    if (count < 0)
83       count = XIM_CACHE_DEFAULT_COUNT;
84    imlib_set_ximage_cache_count_max(count);
85 #endif
86 }
87 
88 void
EImageGetCacheInfo(ECacheInfo * ci)89 EImageGetCacheInfo(ECacheInfo * ci)
90 {
91    memset(ci, 0, sizeof(ECacheInfo));
92    ci->img.max_mem = imlib_get_cache_size();
93 #if HAVE_IMLIB_XIMAGE_CACHE_CONTROL
94    ci->img.used_mem = imlib_get_cache_used();
95    ci->xim.max_mem = imlib_get_ximage_cache_size_max();
96    ci->xim.used_mem = imlib_get_ximage_cache_size_used();
97    ci->xim.max_cnt = imlib_get_ximage_cache_count_max();
98    ci->xim.used_cnt = imlib_get_ximage_cache_count_used();
99 #endif
100 }
101 
102 static void
_EImageFlagsSet(int flags)103 _EImageFlagsSet(int flags)
104 {
105    if (flags & EIMAGE_ANTI_ALIAS)
106       imlib_context_set_anti_alias(1);
107    if (flags & EIMAGE_BLEND)
108       imlib_context_set_blend(1);
109 #ifdef HAVE_IMLIB_CONTEXT_SET_MASK_ALPHA_THRESHOLD
110    if (flags & EIMAGE_HIGH_MASK_THR)
111       imlib_context_set_mask_alpha_threshold(128);
112 #endif
113 }
114 
115 static void
_EImageFlagsReset(void)116 _EImageFlagsReset(void)
117 {
118    imlib_context_set_anti_alias(0);
119    imlib_context_set_blend(0);
120 #ifdef HAVE_IMLIB_CONTEXT_SET_MASK_ALPHA_THRESHOLD
121    imlib_context_set_mask_alpha_threshold(Conf.testing.mask_alpha_threshold);
122 #endif
123 }
124 
125 EImage             *
EImageLoad(const char * file)126 EImageLoad(const char *file)
127 {
128    return imlib_load_image(file);
129 }
130 
131 EImage             *
EImageLoadOrientate(const char * file,int orientation)132 EImageLoadOrientate(const char *file, int orientation)
133 {
134    EImage             *im, *im2;
135    char                name[2048], path[4096], *s, *s2;
136 
137    snprintf(name, sizeof(name), "%s", file);
138    for (s = name, s2 = NULL; *s; s++)
139      {
140 	if (*s == '/')
141 	   *s = '.';
142 	else if (*s == '.')
143 	   s2 = s;
144      }
145    if (s2)
146       *s2 = '\0';
147    snprintf(path, sizeof(path), "%s/cached/cfg/%s-%d.png",
148 	    EDirUserCache(), name, orientation);
149 
150    if (!exists(path))
151      {
152 	im = imlib_load_image(file);
153 	if (!im)
154 	   return NULL;
155 
156 	imlib_context_set_image(im);
157 	im2 = imlib_clone_image();
158 	imlib_free_image();
159 
160 	imlib_context_set_image(im2);
161 	imlib_image_orientate(orientation);
162 	imlib_image_set_format("png");
163 	imlib_save_image(path);
164 	imlib_free_image();
165      }
166 
167    im = imlib_load_image(path);
168 
169    return im;
170 }
171 
172 void
EImageSave(EImage * im,const char * file)173 EImageSave(EImage * im, const char *file)
174 {
175    imlib_context_set_image(im);
176    imlib_image_set_format("png");
177    imlib_save_image(file);
178 }
179 
180 EImage             *
EImageCreate(int w,int h)181 EImageCreate(int w, int h)
182 {
183    EImage             *im;
184 
185    im = imlib_create_image(w, h);
186 
187    return im;
188 }
189 
190 EImage             *
EImageCreateFromData(int w,int h,unsigned int * data)191 EImageCreateFromData(int w, int h, unsigned int *data)
192 {
193    EImage             *im;
194 
195    im = imlib_create_image_using_copied_data(w, h, data);
196 
197    return im;
198 }
199 
200 EImage             *
EImageCreateScaled(EImage * im,int sx,int sy,int sw,int sh,int dw,int dh)201 EImageCreateScaled(EImage * im, int sx, int sy, int sw, int sh, int dw, int dh)
202 {
203    imlib_context_set_image(im);
204    if (sw <= 0)
205       sw = imlib_image_get_width();
206    if (sh <= 0)
207       sh = imlib_image_get_height();
208    if (dw <= 0)
209       dw = sw;
210    if (dh <= 0)
211       dh = sh;
212    return imlib_create_cropped_scaled_image(sx, sy, sw, sh, dw, dh);
213 }
214 
215 void
EImageFree(EImage * im)216 EImageFree(EImage * im)
217 {
218    imlib_context_set_image(im);
219    imlib_free_image();
220 }
221 
222 void
EImageDecache(EImage * im)223 EImageDecache(EImage * im)
224 {
225    imlib_context_set_image(im);
226    imlib_free_image_and_decache();
227 }
228 
229 static int
_EImageCheckAlpha(void)230 _EImageCheckAlpha(void)
231 {
232    static const short  oink = 3;	/* For endianness checking */
233    unsigned char      *pb, *pe;
234 
235    if (!imlib_image_has_alpha())
236       return 0;
237 
238    pb = (unsigned char *)imlib_image_get_data_for_reading_only();
239    if (!pb)
240       return 0;
241 
242    pe = pb + 4 * imlib_image_get_width() * imlib_image_get_height();
243    pb += *((char *)(&oink));
244    for (; pb < pe; pb += 4)
245       if (*pb != 0xff)
246 	 return 1;
247 
248    return 0;
249 }
250 
251 void
EImageCheckAlpha(EImage * im)252 EImageCheckAlpha(EImage * im)
253 {
254    imlib_context_set_image(im);
255 
256    if (imlib_image_has_alpha() && !_EImageCheckAlpha())
257      {
258 #if 0
259 	Eprintf("Alpha set but no shape %s\n", is->real_file);
260 #endif
261 	imlib_image_set_has_alpha(0);
262      }
263 }
264 
265 void
EImageSetHasAlpha(EImage * im,int has_alpha)266 EImageSetHasAlpha(EImage * im, int has_alpha)
267 {
268    imlib_context_set_image(im);
269    imlib_image_set_has_alpha(has_alpha);
270 }
271 
272 void
EImageSetBorder(EImage * im,EImageBorder * border)273 EImageSetBorder(EImage * im, EImageBorder * border)
274 {
275    Imlib_Border        ib;
276 
277    ib.left = border->left;
278    ib.right = border->right;
279    ib.top = border->top;
280    ib.bottom = border->bottom;
281    imlib_context_set_image(im);
282    imlib_image_set_border(&ib);
283 
284    if (EDebug(1))
285      {
286 	int                 l;
287 
288 	l = imlib_image_get_width();
289 	if ((l < ib.left + ib.right) || (ib.left < 0) || (ib.left < 0))
290 	   Eprintf("%s: %s: Image W = %d < border L+R = %d+%d\n", __func__,
291 		   imlib_image_get_filename(), l, ib.left, ib.right);
292 	l = imlib_image_get_height();
293 	if ((l < ib.top + ib.bottom) || (ib.top < 0) || (ib.bottom < 0))
294 	   Eprintf("%s: %s: Image H = %d < border T+B = %d+%d\n", __func__,
295 		   imlib_image_get_filename(), l, ib.top, ib.bottom);
296      }
297 }
298 
299 int
EImageHasAlpha(EImage * im)300 EImageHasAlpha(EImage * im)
301 {
302    imlib_context_set_image(im);
303    return imlib_image_has_alpha();
304 }
305 
306 void
EImageGetSize(EImage * im,int * pw,int * ph)307 EImageGetSize(EImage * im, int *pw, int *ph)
308 {
309    imlib_context_set_image(im);
310    *pw = imlib_image_get_width();
311    *ph = imlib_image_get_height();
312 }
313 
314 void               *
EImageGetData(EImage * im)315 EImageGetData(EImage * im)
316 {
317    imlib_context_set_image(im);
318    return imlib_image_get_data_for_reading_only();
319 }
320 
321 void
EImageFill(EImage * im,int x,int y,int w,int h,unsigned int color)322 EImageFill(EImage * im, int x, int y, int w, int h, unsigned int color)
323 {
324    int                 a, r, g, b;
325 
326    imlib_context_set_image(im);
327    COLOR32_TO_ARGB(color, a, r, g, b);
328    imlib_context_set_color(r, g, b, a);
329    imlib_context_set_blend(0);
330    imlib_image_fill_rectangle(x, y, w, h);
331 }
332 
333 void
EImageOrientate(EImage * im,int orientation)334 EImageOrientate(EImage * im, int orientation)
335 {
336    imlib_context_set_image(im);
337    imlib_image_orientate(orientation);
338 }
339 
340 void
EImageBlend(EImage * im,EImage * src,int flags,int sx,int sy,int sw,int sh,int dx,int dy,int dw,int dh,int merge_alpha)341 EImageBlend(EImage * im, EImage * src, int flags,
342 	    int sx, int sy, int sw, int sh,
343 	    int dx, int dy, int dw, int dh, int merge_alpha)
344 {
345    imlib_context_set_image(im);
346    if (flags)
347       _EImageFlagsSet(flags);
348    imlib_blend_image_onto_image(src, merge_alpha, sx, sy, sw, sh,
349 				dx, dy, dw, dh);
350    if (flags)
351       _EImageFlagsReset();
352 }
353 
354 void
EImageTile(EImage * im,EImage * tile,int flags,int tw,int th,int dx,int dy,int dw,int dh,int ox,int oy)355 EImageTile(EImage * im, EImage * tile, int flags, int tw, int th,
356 	   int dx, int dy, int dw, int dh, int ox, int oy)
357 {
358    Imlib_Image         tim;
359    int                 x, y, tx, ty, ww, hh;
360    int                 sw, sh;
361 
362    if (tw <= 0 || th <= 0)
363       return;
364 
365    if (flags)
366       _EImageFlagsSet(flags);
367 
368    imlib_context_set_image(tile);
369    sw = imlib_image_get_width();
370    sh = imlib_image_get_height();
371    if (sw == tw && sh == th)
372      {
373 	tim = tile;
374      }
375    else
376      {
377 	tim = imlib_create_image(tw, th);
378 	imlib_context_set_image(tim);
379 	imlib_context_set_blend(0);
380 	imlib_context_set_anti_alias(1);
381 	imlib_blend_image_onto_image(tile, 0, 0, 0, sw, sh, 0, 0, tw, th);
382 	imlib_context_set_anti_alias(0);
383      }
384    imlib_context_set_image(im);
385 
386    if (ox)
387      {
388 	ox = tw - ox;
389 	ox %= tw;
390 	if (ox < 0)
391 	   ox += tw;
392      }
393    if (oy)
394      {
395 	oy = th - oy;
396 	oy %= th;
397 	if (oy < 0)
398 	   oy += th;
399      }
400    dw += dx;
401    dh += dy;
402    y = dy;
403    ty = oy;
404    hh = th - oy;
405    for (;;)
406      {
407 	if (y + hh >= dh)
408 	   hh = dh - y;
409 	if (hh <= 0)
410 	   break;
411 	x = dx;
412 	tx = ox;
413 	ww = tw - ox;
414 	for (;;)
415 	  {
416 	     if (x + ww >= dw)
417 		ww = dw - x;
418 	     if (ww <= 0)
419 		break;
420 	     imlib_blend_image_onto_image(tim, 0, tx, ty, ww, hh, x, y, ww, hh);
421 	     tx = 0;
422 	     x += ww;
423 	     ww = tw;
424 	  }
425 	ty = 0;
426 	y += hh;
427 	hh = th;
428      }
429    if (tim != tile)
430      {
431 	imlib_context_set_image(tim);
432 	imlib_free_image();
433 	imlib_context_set_image(im);	/* FIXME - Remove */
434      }
435 
436    if (flags)
437       _EImageFlagsReset();
438 }
439 
440 EImage             *
EImageGrabDrawable(EX_Drawable draw,EX_Pixmap mask,int x,int y,int w,int h,int grab)441 EImageGrabDrawable(EX_Drawable draw, EX_Pixmap mask, int x, int y, int w,
442 		   int h, int grab)
443 {
444    EImage             *im;
445    EX_Colormap         cm;
446 
447    cm = imlib_context_get_colormap();
448    imlib_context_set_colormap(NoXID);	/* Fix for grabbing bitmaps */
449    imlib_context_set_drawable(draw);
450    im = imlib_create_image_from_drawable(mask, x, y, w, h, grab);
451    imlib_context_set_colormap(cm);
452 
453    return im;
454 }
455 
456 EImage             *
EImageGrabDrawableScaled(Win win,EX_Drawable draw,EX_Pixmap mask,int x,int y,int w,int h,int iw,int ih,int grab,int get_mask_from_shape)457 EImageGrabDrawableScaled(Win win, EX_Drawable draw, EX_Pixmap mask,
458 			 int x, int y, int w, int h,
459 			 int iw, int ih, int grab, int get_mask_from_shape)
460 {
461    EImage             *im;
462    Visual             *vis;
463 
464    imlib_context_set_drawable(draw);
465    vis = (win) ? WinGetVisual(win) : NULL;
466    if (vis)
467       imlib_context_set_visual(vis);
468 
469    im = imlib_create_scaled_image_from_drawable(mask, x, y, w, h, iw, ih, grab,
470 						get_mask_from_shape);
471 
472    if (vis)
473       imlib_context_set_visual(WinGetVisual(VROOT));
474 
475    return im;
476 }
477 
478 void
EImageRenderOnDrawable(EImage * im,Win win,EX_Drawable draw,int flags,int x,int y,int w,int h)479 EImageRenderOnDrawable(EImage * im, Win win, EX_Drawable draw, int flags,
480 		       int x, int y, int w, int h)
481 {
482    Visual             *vis;
483 
484    imlib_context_set_image(im);
485    imlib_context_set_drawable((draw != NoXID) ? draw : WinGetXwin(win));
486    vis = (win) ? WinGetVisual(win) : NULL;
487    if (vis)
488       imlib_context_set_visual(vis);
489 
490    if (flags)
491       _EImageFlagsSet(flags);
492    imlib_render_image_on_drawable_at_size(x, y, w, h);
493    if (flags)
494       _EImageFlagsReset();
495 
496    if (vis)
497       imlib_context_set_visual(WinGetVisual(VROOT));
498 }
499 
500 #if USE_XRENDER
501 
502 void
EImageRenderOnDrawableARGB(EImage * im,EX_Drawable draw,int w,int h)503 EImageRenderOnDrawableARGB(EImage * im, EX_Drawable draw, int w, int h)
504 {
505    Visual             *vis;
506 
507    imlib_context_set_image(im);
508    imlib_context_set_drawable(draw);
509    vis = EVisualFindARGB();
510    if (vis)
511       imlib_context_set_visual(vis);
512 
513    imlib_render_image_on_drawable_at_size(0, 0, w, h);
514 
515    if (vis)
516       imlib_context_set_visual(WinGetVisual(VROOT));
517 }
518 
519 #endif
520 
521 void
EImageRenderPixmaps(EImage * im,Win win,int flags,EX_Pixmap * ppmap,EX_Pixmap * pmask,int w,int h)522 EImageRenderPixmaps(EImage * im, Win win, int flags,
523 		    EX_Pixmap * ppmap, EX_Pixmap * pmask, int w, int h)
524 {
525    Visual             *vis;
526    Pixmap              pmap, mask, *pm;
527 
528    imlib_context_set_image(im);
529    imlib_context_set_drawable((win) ? WinGetXwin(win) : WinGetXwin(VROOT));
530    vis = (win) ? WinGetVisual(win) : NULL;
531    if (vis)
532       imlib_context_set_visual(vis);
533 
534    pmap = mask = NoXID;
535    pm = pmask ? &mask : NULL;
536 
537    if (flags)
538       _EImageFlagsSet(flags);
539    if (w <= 0 || h <= 0)
540       imlib_render_pixmaps_for_whole_image(&pmap, pm);
541    else
542       imlib_render_pixmaps_for_whole_image_at_size(&pmap, pm, w, h);
543    if (flags)
544       _EImageFlagsReset();
545 
546    if (vis)
547       imlib_context_set_visual(WinGetVisual(VROOT));
548 
549    *ppmap = pmap;
550    if (pmask)
551       *pmask = mask;
552 }
553 
554 void
EImagePixmapsFree(EX_Pixmap pmap,EX_Pixmap mask __UNUSED__)555 EImagePixmapsFree(EX_Pixmap pmap, EX_Pixmap mask __UNUSED__)
556 {
557    imlib_free_pixmap_and_mask(pmap);
558 }
559 
560 void
EImageApplyToWin(EImage * im,Win win,int flags,int w,int h)561 EImageApplyToWin(EImage * im, Win win, int flags, int w, int h)
562 {
563    EX_Pixmap           pmap, mask;
564 
565    EImageRenderPixmaps(im, win, flags, &pmap, &mask, w, h);
566    ESetWindowBackgroundPixmap(win, pmap, 0);
567    if ((mask != NoXID) || (mask == NoXID && WinIsShaped(win)))
568       EShapeSetMask(win, 0, 0, mask);
569    EImagePixmapsFree(pmap, mask);
570    EClearWindow(win);
571 }
572 
573 void
ScaleRect(Win wsrc,EX_Drawable src,Win wdst,EX_Pixmap dst,int sx,int sy,int sw,int sh,int dx,int dy,int dw,int dh,int flags)574 ScaleRect(Win wsrc, EX_Drawable src, Win wdst, EX_Pixmap dst,
575 	  int sx, int sy, int sw, int sh,
576 	  int dx, int dy, int dw, int dh, int flags)
577 {
578 #if USE_XRENDER
579    if (Conf.testing.use_render_for_scaling)
580      {
581 	XTransform          tr;
582 	EX_Picture          psrc, pdst;
583 	double              scale_x, scale_y;
584 
585 	scale_x = (double)sw / (double)dw;
586 	scale_y = (double)sh / (double)dh;
587 	memset(&tr, 0, sizeof(tr));
588 	tr.matrix[0][0] = XDoubleToFixed(scale_x);
589 	tr.matrix[1][1] = XDoubleToFixed(scale_y);
590 	tr.matrix[2][2] = XDoubleToFixed(1.);
591 
592 	psrc = EPictureCreateII(wsrc, src);
593 	pdst = EPictureCreateII(wdst, dst);
594 
595 	XRenderSetPictureFilter(disp, psrc, (flags & EIMAGE_ANTI_ALIAS) ?
596 				FilterBest : FilterNearest, NULL, 0);
597 	XRenderSetPictureTransform(disp, psrc, &tr);
598 	XRenderComposite(disp, PictOpSrc, psrc, NoXID, pdst,
599 			 (int)(sx / scale_x + .5), (int)(sy / scale_y + .5),
600 			 0, 0, dx, dy, dw, dh);
601 	XRenderFreePicture(disp, psrc);
602 	XRenderFreePicture(disp, pdst);
603      }
604    else
605 #endif
606      {
607 	int                 scale;
608 	Imlib_Image         im;
609 
610 	if (flags & (EIMAGE_ISCALE))
611 	  {
612 	     scale = (flags & EIMAGE_ISCALE) >> 8;
613 	     im = EImageGrabDrawableScaled(wsrc, src, NoXID, sx, sy, sw, sh,
614 					   scale * dw, scale * dh, 0, 0);
615 	     flags |= EIMAGE_ANTI_ALIAS;
616 	  }
617 	else
618 	  {
619 	     im = EImageGrabDrawableScaled(wsrc, src, NoXID, sx, sy, sw, sh,
620 					   sw, sh, 0, 0);
621 	  }
622 
623 	EImageRenderOnDrawable(im, wdst, dst, flags, dx, dy, dw, dh);
624 	imlib_free_image();
625      }
626 }
627 
628 void
ScaleTile(Win wsrc,EX_Drawable src,Win wdst,EX_Pixmap dst,int dx,int dy,int dw,int dh,int scale)629 ScaleTile(Win wsrc, EX_Drawable src, Win wdst, EX_Pixmap dst,
630 	  int dx, int dy, int dw, int dh, int scale)
631 {
632    Imlib_Image         im, tim;
633    int                 sw, sh, stw, sth, tw, th;
634 
635    sw = WinGetW(wsrc);
636    sh = WinGetH(wsrc);
637    EXGetSize(src, &stw, &sth);
638    if (stw >= sw && sth >= sh)
639      {
640 	ScaleRect(wsrc, src, wdst, dst, 0, 0, sw, sh, dx, dy, dw, dh, scale);
641 	return;
642      }
643 
644    /* Source Drawawble is smaller than source window - do scaled tiling */
645 
646    scale = (scale) ? 2 : 1;
647 
648    tw = (int)((float)(stw * scale * dw) / sw + .5f);
649    th = (int)((float)(sth * scale * dh) / sh + .5f);
650 #if 0
651    Eprintf("%s: Tile %#x %dx%d -> %dx%d T %dx%d -> %dx%d\n", __func__,
652 	   src, stw, sth, tw, th, scale * dw, scale * dh, dw, dh);
653 #endif
654    tim =
655       EImageGrabDrawableScaled(wsrc, src, NoXID, 0, 0, stw, sth, tw, th, 0, 0);
656    im = EImageCreate(scale * dw, scale * dh);
657    EImageTile(im, tim, 0, tw, th, 0, 0, scale * dw, scale * dh, 0, 0);
658    EImageFree(tim);
659 
660    EImageRenderOnDrawable(im, wdst, dst, EIMAGE_ANTI_ALIAS, dx, dy, dw, dh);
661    imlib_free_image();
662 }
663 
664 #if 0				/* Unused */
665 void
666 EDrawableDumpImage(EX_Drawable draw, const char *txt)
667 {
668    static int          seqn = 0;
669    char                buf[1024];
670    Imlib_Image         im;
671    int                 w, h;
672 
673    EXGetSize(draw, &w, &h);
674    if (w <= 0 || h <= 0)
675       return;
676    im = EImageGrabDrawableScaled(ELookupXwin(draw), draw, NoXID,
677 				 0, 0, w, h, w, h, 0, 0);
678    imlib_context_set_image(im);
679    imlib_image_set_format("png");
680    sprintf(buf, "%s-%#x-%d.png", txt, draw, seqn++);
681    Eprintf("%s: %s\n", __func__, buf);
682    imlib_save_image(buf);
683    imlib_free_image_and_decache();
684 }
685 #endif
686 
687 void
PmapMaskInit(PmapMask * pmm,Win win,int w,int h)688 PmapMaskInit(PmapMask * pmm, Win win, int w, int h)
689 {
690    if (pmm->pmap)
691      {
692 	if (pmm->w == w && pmm->h == h && pmm->depth == WinGetDepth(win))
693 	   return;
694 	PmapMaskFree(pmm);
695      }
696 
697    pmm->type = 0;
698    pmm->depth = WinGetDepth(win);
699    pmm->pmap = ECreatePixmap(win, w, h, 0);
700    pmm->mask = NoXID;
701    pmm->w = w;
702    pmm->h = h;
703 }
704 
705 void
PmapMaskFree(PmapMask * pmm)706 PmapMaskFree(PmapMask * pmm)
707 {
708    /* type !=0: Created by imlib_render_pixmaps_for_whole_image... */
709    if (pmm->pmap)
710      {
711 	if (pmm->type == 0)
712 	   EFreePixmap(pmm->pmap);
713 	else
714 	   imlib_free_pixmap_and_mask(pmm->pmap);
715 	pmm->pmap = 0;
716      }
717 
718    if (pmm->mask)
719      {
720 	if (pmm->type == 0)
721 	   EFreePixmap(pmm->mask);
722 	pmm->mask = 0;
723      }
724 }
725 
726 #if USE_XRENDER
727 
728 EX_Cursor
EImageDefineCursor(EImage * im,int xh,int yh)729 EImageDefineCursor(EImage * im, int xh, int yh)
730 {
731    EX_Cursor           curs;
732    int                 w, h;
733    EX_Pixmap           pmap;
734    EX_Picture          pict;
735 
736    EImageGetSize(im, &w, &h);
737 
738    pict = EPictureCreateBuffer(RROOT, w, h, 1, &pmap);
739 
740    EImageRenderOnDrawableARGB(im, pmap, w, h);
741    EFreePixmap(pmap);
742 
743    curs = XRenderCreateCursor(disp, pict, xh, yh);
744    XRenderFreePicture(disp, pict);
745 
746    return curs;
747 }
748 
749 #endif /* USE_XRENDER */
750