chiark / gitweb /
New option: movres.ignore_transience.
[e16] / src / eimage.c
1 /*
2  * Copyright (C) 2004-2008 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 "E.h"
24 #include "eimage.h"
25 #include "xwin.h"
26 #include <Imlib2.h>
27 #if HAVE_X11_EXTENSIONS_XRENDER_H
28 #include <X11/extensions/Xrender.h>
29 #endif
30
31 void
32 EImageInit(void)
33 {
34    imlib_set_cache_size(2048 * 1024);
35    imlib_set_font_cache_size(512 * 1024);
36
37    imlib_set_color_usage(128);
38
39    imlib_context_set_display(disp);
40    imlib_context_set_visual(WinGetVisual(VROOT));
41    imlib_context_set_colormap(WinGetCmap(VROOT));
42
43 #ifdef HAVE_IMLIB_CONTEXT_SET_MASK_ALPHA_THRESHOLD
44    imlib_context_set_mask_alpha_threshold(Conf.testing.mask_alpha_threshold);
45 #endif
46
47    imlib_context_set_anti_alias(0);
48    imlib_context_set_dither(1);
49 }
50
51 void
52 EImageExit(int quit __UNUSED__)
53 {
54 #if HAVE_IMLIB_CONTEXT_DISCONNECT_DISPLAY
55    imlib_context_disconnect_display();
56 #endif
57 }
58
59 int
60 EImageSetCacheSize(int size)
61 {
62    int                 size_old;
63
64    size_old = imlib_get_cache_size();
65    imlib_set_cache_size(size);
66
67    return size_old;
68 }
69
70 static void
71 _EImageFlagsSet(int flags)
72 {
73    if (flags & EIMAGE_ANTI_ALIAS)
74       imlib_context_set_anti_alias(1);
75    if (flags & EIMAGE_BLEND)
76       imlib_context_set_blend(1);
77 #ifdef HAVE_IMLIB_CONTEXT_SET_MASK_ALPHA_THRESHOLD
78    if (flags & EIMAGE_HIGH_MASK_THR)
79       imlib_context_set_mask_alpha_threshold(128);
80 #endif
81 }
82
83 static void
84 _EImageFlagsReset(void)
85 {
86    imlib_context_set_anti_alias(0);
87    imlib_context_set_blend(0);
88 #ifdef HAVE_IMLIB_CONTEXT_SET_MASK_ALPHA_THRESHOLD
89    imlib_context_set_mask_alpha_threshold(Conf.testing.mask_alpha_threshold);
90 #endif
91 }
92
93 EImage             *
94 EImageLoad(const char *file)
95 {
96    return imlib_load_image(file);
97 }
98
99 void
100 EImageSave(EImage * im, const char *file)
101 {
102    imlib_context_set_image(im);
103    imlib_image_set_format("png");
104    imlib_save_image(file);
105 }
106
107 EImage             *
108 EImageCreate(int w, int h)
109 {
110    EImage             *im;
111
112    im = imlib_create_image(w, h);
113
114    return im;
115 }
116
117 EImage             *
118 EImageCreateFromData(int w, int h, unsigned int *data)
119 {
120    EImage             *im;
121
122    im = imlib_create_image_using_copied_data(w, h, data);
123
124    return im;
125 }
126
127 EImage             *
128 EImageCreateScaled(EImage * im, int sx, int sy, int sw, int sh, int dw, int dh)
129 {
130    imlib_context_set_image(im);
131    if (sw <= 0)
132       sw = imlib_image_get_width();
133    if (sh <= 0)
134       sh = imlib_image_get_height();
135    if (dw <= 0)
136       dw = sw;
137    if (dh <= 0)
138       dh = sh;
139    return imlib_create_cropped_scaled_image(sx, sy, sw, sh, dw, dh);
140 }
141
142 void
143 EImageFree(EImage * im)
144 {
145    imlib_context_set_image(im);
146    imlib_free_image();
147 }
148
149 void
150 EImageDecache(EImage * im)
151 {
152    imlib_context_set_image(im);
153    imlib_free_image_and_decache();
154 }
155
156 static int
157 _EImageCheckAlpha(void)
158 {
159    static const short  oink = 3;        /* For endianness checking */
160    unsigned char      *pb, *pe;
161
162    if (!imlib_image_has_alpha())
163       return 0;
164
165    pb = (unsigned char *)imlib_image_get_data_for_reading_only();
166    if (!pb)
167       return 0;
168
169    pe = pb + 4 * imlib_image_get_width() * imlib_image_get_height();
170    pb += *((char *)(&oink));
171    for (; pb < pe; pb += 4)
172       if (*pb != 0xff)
173          return 1;
174
175    return 0;
176 }
177
178 void
179 EImageCheckAlpha(EImage * im)
180 {
181    imlib_context_set_image(im);
182
183    if (imlib_image_has_alpha() && !_EImageCheckAlpha())
184      {
185 #if 0
186         Eprintf("Alpha set but no shape %s\n", is->real_file);
187 #endif
188         imlib_image_set_has_alpha(0);
189      }
190 }
191
192 void
193 EImageSetHasAlpha(EImage * im, int has_alpha)
194 {
195    imlib_context_set_image(im);
196    imlib_image_set_has_alpha(has_alpha);
197 }
198
199 void
200 EImageSetBorder(EImage * im, EImageBorder * border)
201 {
202    Imlib_Border        ib;
203
204    ib.left = border->left;
205    ib.right = border->right;
206    ib.top = border->top;
207    ib.bottom = border->bottom;
208    imlib_context_set_image(im);
209    imlib_image_set_border(&ib);
210 }
211
212 int
213 EImageHasAlpha(EImage * im)
214 {
215    imlib_context_set_image(im);
216    return imlib_image_has_alpha();
217 }
218
219 void
220 EImageGetSize(EImage * im, int *pw, int *ph)
221 {
222    imlib_context_set_image(im);
223    *pw = imlib_image_get_width();
224    *ph = imlib_image_get_height();
225 }
226
227 void               *
228 EImageGetData(EImage * im)
229 {
230    imlib_context_set_image(im);
231    return imlib_image_get_data_for_reading_only();
232 }
233
234 void
235 EImageFill(EImage * im, int x, int y, int w, int h, int r, int g, int b, int a)
236 {
237    imlib_context_set_image(im);
238    imlib_context_set_color(r, g, b, a);
239    imlib_context_set_blend(0);
240    imlib_image_fill_rectangle(x, y, w, h);
241 }
242
243 void
244 EImageOrientate(EImage * im, int orientation)
245 {
246    imlib_context_set_image(im);
247    imlib_image_orientate(orientation);
248 }
249
250 void
251 EImageBlend(EImage * im, EImage * src, int flags,
252             int sx, int sy, int sw, int sh,
253             int dx, int dy, int dw, int dh, int merge_alpha)
254 {
255    imlib_context_set_image(im);
256    if (flags)
257       _EImageFlagsSet(flags);
258    imlib_blend_image_onto_image(src, merge_alpha, sx, sy, sw, sh,
259                                 dx, dy, dw, dh);
260    if (flags)
261       _EImageFlagsReset();
262 }
263
264 void
265 EImageBlendCM(EImage * im, EImage * src, EImageColorModifier * icm)
266 {
267    int                 w, h, iw, ih;
268
269    imlib_context_set_image(src);
270    iw = imlib_image_get_width();
271    ih = imlib_image_get_height();
272    imlib_context_set_image(im);
273    w = imlib_image_get_width();
274    h = imlib_image_get_height();
275
276    imlib_context_set_blend(1);
277    if (icm)
278       imlib_context_set_color_modifier(icm);
279    imlib_context_set_operation(IMLIB_OP_COPY);
280    imlib_blend_image_onto_image(src, 0, 0, 0, iw, ih, 0, 0, w, h);
281    imlib_context_set_blend(0);
282    if (icm)
283       imlib_context_set_color_modifier(NULL);
284 }
285
286 void
287 EImageTile(EImage * im, EImage * tile, int flags, int tw, int th,
288            int dx, int dy, int dw, int dh, int ox, int oy)
289 {
290    Imlib_Image         tim;
291    int                 x, y, tx, ty, ww, hh;
292    int                 sw, sh;
293
294    if (tw <= 0 || th <= 0)
295       return;
296
297    if (flags)
298       _EImageFlagsSet(flags);
299
300    imlib_context_set_image(tile);
301    sw = imlib_image_get_width();
302    sh = imlib_image_get_height();
303    if (sw == tw && sh == th)
304      {
305         tim = tile;
306      }
307    else
308      {
309         tim = imlib_create_image(tw, th);
310         imlib_context_set_image(tim);
311         imlib_context_set_blend(0);
312         imlib_context_set_anti_alias(1);
313         imlib_blend_image_onto_image(tile, 0, 0, 0, sw, sh, 0, 0, tw, th);
314         imlib_context_set_anti_alias(0);
315      }
316    imlib_context_set_image(im);
317
318    if (ox)
319      {
320         ox = tw - ox;
321         ox %= tw;
322         if (ox < 0)
323            ox += tw;
324      }
325    if (oy)
326      {
327         oy = th - oy;
328         oy %= th;
329         if (oy < 0)
330            oy += th;
331      }
332    dw += dx;
333    dh += dy;
334    y = dy;
335    ty = oy;
336    hh = th - oy;
337    for (;;)
338      {
339         if (y + hh >= dh)
340            hh = dh - y;
341         if (hh <= 0)
342            break;
343         x = dx;
344         tx = ox;
345         ww = tw - ox;
346         for (;;)
347           {
348              if (x + ww >= dw)
349                 ww = dw - x;
350              if (ww <= 0)
351                 break;
352              imlib_blend_image_onto_image(tim, 0, tx, ty, ww, hh, x, y, ww, hh);
353              tx = 0;
354              x += ww;
355              ww = tw;
356           }
357         ty = 0;
358         y += hh;
359         hh = th;
360      }
361    if (tim != tile)
362      {
363         imlib_context_set_image(tim);
364         imlib_free_image();
365         imlib_context_set_image(im);    /* FIXME - Remove */
366      }
367
368    if (flags)
369       _EImageFlagsReset();
370 }
371
372 EImage             *
373 EImageGrabDrawable(Drawable draw, Pixmap mask, int x, int y, int w, int h,
374                    int grab)
375 {
376    EImage             *im;
377    Colormap            cm;
378
379    cm = imlib_context_get_colormap();
380    imlib_context_set_colormap(None);    /* Fix for grabbing bitmaps */
381    imlib_context_set_drawable(draw);
382    im = imlib_create_image_from_drawable(mask, x, y, w, h, grab);
383    imlib_context_set_colormap(cm);
384
385    return im;
386 }
387
388 EImage             *
389 EImageGrabDrawableScaled(Win win, Drawable draw, Pixmap mask,
390                          int x, int y, int w, int h,
391                          int iw, int ih, int grab, int get_mask_from_shape)
392 {
393    EImage             *im;
394    Visual             *vis;
395
396    imlib_context_set_drawable(draw);
397    vis = (win) ? WinGetVisual(win) : NULL;
398    if (vis)
399       imlib_context_set_visual(vis);
400
401    im = imlib_create_scaled_image_from_drawable(mask, x, y, w, h, iw, ih, grab,
402                                                 get_mask_from_shape);
403
404    if (vis)
405       imlib_context_set_visual(WinGetVisual(VROOT));
406
407    return im;
408 }
409
410 void
411 EImageRenderOnDrawable(EImage * im, Win win, Drawable draw, int flags,
412                        int x, int y, int w, int h)
413 {
414    Visual             *vis;
415
416    imlib_context_set_image(im);
417    imlib_context_set_drawable((draw != None) ? draw : WinGetXwin(win));
418    vis = (win) ? WinGetVisual(win) : NULL;
419    if (vis)
420       imlib_context_set_visual(vis);
421
422    if (flags)
423       _EImageFlagsSet(flags);
424    imlib_render_image_on_drawable_at_size(x, y, w, h);
425    if (flags)
426       _EImageFlagsReset();
427
428    if (vis)
429       imlib_context_set_visual(WinGetVisual(VROOT));
430 }
431
432 void
433 EImageRenderPixmaps(EImage * im, Win win, int flags,
434                     Pixmap * pmap, Pixmap * mask, int w, int h)
435 {
436    Visual             *vis;
437    Pixmap              m;
438
439    imlib_context_set_image(im);
440    imlib_context_set_drawable((win) ? WinGetXwin(win) : WinGetXwin(VROOT));
441    vis = (win) ? WinGetVisual(win) : NULL;
442    if (vis)
443       imlib_context_set_visual(vis);
444
445    *pmap = None;
446    if (!mask)                   /* Imlib2 <= 1.3.0 needs a mask pointer */
447       mask = &m;                /* ... to avoid bogus error messages    */
448    if (mask)
449       *mask = None;
450
451    if (flags)
452       _EImageFlagsSet(flags);
453    if (w <= 0 || h <= 0)
454       imlib_render_pixmaps_for_whole_image(pmap, mask);
455    else
456       imlib_render_pixmaps_for_whole_image_at_size(pmap, mask, w, h);
457    if (flags)
458       _EImageFlagsReset();
459
460    if (vis)
461       imlib_context_set_visual(WinGetVisual(VROOT));
462 }
463
464 void
465 EImagePixmapsFree(Pixmap pmap, Pixmap mask __UNUSED__)
466 {
467    imlib_free_pixmap_and_mask(pmap);
468 }
469
470 void
471 EImageApplyToWin(EImage * im, Win win, int flags, int w, int h)
472 {
473    Pixmap              pmap, mask;
474
475    EImageRenderPixmaps(im, win, flags, &pmap, &mask, w, h);
476    ESetWindowBackgroundPixmap(win, pmap);
477    if ((mask != None) || (mask == None && WinIsShaped(win)))
478       EShapeSetMask(win, 0, 0, mask);
479    EImagePixmapsFree(pmap, mask);
480    EClearWindow(win);
481 }
482
483 void
484 ScaleRect(Win wsrc, Drawable src, Win wdst, Pixmap dst,
485           int sx, int sy, int sw, int sh,
486           int dx, int dy, int dw, int dh, int flags)
487 {
488 #if HAVE_X11_EXTENSIONS_XRENDER_H
489    if (Conf.testing.use_render_for_scaling)
490      {
491         XRenderPictFormat  *pictfmt;
492         XRenderPictureAttributes pa;
493         XTransform          tr;
494         Picture             psrc, pdst;
495         double              scale_x, scale_y;
496
497         scale_x = (double)sw / (double)dw;
498         scale_y = (double)sh / (double)dh;
499         memset(&tr, 0, sizeof(tr));
500         tr.matrix[0][0] = XDoubleToFixed(scale_x);
501         tr.matrix[1][1] = XDoubleToFixed(scale_y);
502         tr.matrix[2][2] = XDoubleToFixed(1.);
503
504         pa.subwindow_mode = IncludeInferiors;
505         pictfmt = XRenderFindVisualFormat(disp, wsrc->visual);
506         psrc = XRenderCreatePicture(disp, src, pictfmt, CPSubwindowMode, &pa);
507         pictfmt = XRenderFindVisualFormat(disp, wdst->visual);
508         pdst = XRenderCreatePicture(disp, dst, pictfmt, CPSubwindowMode, &pa);
509
510         XRenderSetPictureFilter(disp, psrc, (flags & EIMAGE_ANTI_ALIAS) ?
511                                 FilterBest : FilterNearest, NULL, 0);
512         XRenderSetPictureTransform(disp, psrc, &tr);
513         XRenderComposite(disp, PictOpSrc, psrc, None, pdst,
514                          (int)(sx / scale_x + .5), (int)(sy / scale_y + .5),
515                          0, 0, dx, dy, dw, dh);
516         XRenderFreePicture(disp, psrc);
517         XRenderFreePicture(disp, pdst);
518      }
519    else
520 #endif
521      {
522         int                 scale;
523         Imlib_Image         im;
524
525         if (flags & (EIMAGE_ISCALE))
526           {
527              scale = (flags & EIMAGE_ISCALE) >> 8;
528              im = EImageGrabDrawableScaled(wsrc, src, None, sx, sy, sw, sh,
529                                            scale * dw, scale * dh, 0, 0);
530              flags |= EIMAGE_ANTI_ALIAS;
531           }
532         else
533           {
534              im = EImageGrabDrawableScaled(wsrc, src, None, sx, sy, sw, sh,
535                                            sw, sh, 0, 0);
536           }
537
538         EImageRenderOnDrawable(im, wdst, dst, flags, dx, dy, dw, dh);
539         imlib_free_image();
540      }
541 }
542
543 void
544 ScaleTile(Win wsrc, Drawable src, Win wdst, Pixmap dst,
545           int dx, int dy, int dw, int dh, int scale)
546 {
547    Imlib_Image         im, tim;
548    int                 sw, sh, stw, sth, tw, th;
549
550    sw = WinGetW(wsrc);
551    sh = WinGetH(wsrc);
552    EXGetGeometry(src, NULL, NULL, NULL, &stw, &sth, NULL, NULL);
553    if (stw >= sw && sth >= sh)
554      {
555         ScaleRect(wsrc, src, wdst, dst, 0, 0, sw, sh, dx, dy, dw, dh, scale);
556         return;
557      }
558
559    /* Source Drawawble is smaller than source window - do scaled tiling */
560
561    scale = (scale) ? 2 : 1;
562
563    tw = (int)((double)(stw * scale * dw) / sw + .5);
564    th = (int)((double)(sth * scale * dh) / sh + .5);
565 #if 0
566    Eprintf("ScaleTile: Tile %#lx %dx%d -> %dx%d T %dx%d -> %dx%d\n", src,
567            stw, sth, tw, th, scale * dw, scale * dh, dw, dh);
568 #endif
569    tim =
570       EImageGrabDrawableScaled(wsrc, src, None, 0, 0, stw, sth, tw, th, 0, 0);
571    im = EImageCreate(scale * dw, scale * dh);
572    EImageTile(im, tim, 0, tw, th, 0, 0, scale * dw, scale * dh, 0, 0);
573    EImageFree(tim);
574
575    EImageRenderOnDrawable(im, wdst, dst, EIMAGE_ANTI_ALIAS, dx, dy, dw, dh);
576    imlib_free_image();
577 }
578
579 #if 0                           /* Unused */
580 void
581 EDrawableDumpImage(Drawable draw, const char *txt)
582 {
583    static int          seqn = 0;
584    char                buf[1024];
585    Imlib_Image         im;
586    int                 w, h;
587
588    w = h = 0;
589    EXGetGeometry(draw, NULL, NULL, NULL, &w, &h, NULL, NULL);
590    if (w <= 0 || h <= 0)
591       return;
592    imlib_context_set_drawable(draw);
593    im = imlib_create_image_from_drawable(None, 0, 0, w, h, !EServerIsGrabbed());
594    imlib_context_set_image(im);
595    imlib_image_set_format("png");
596    sprintf(buf, "%s-%#lx-%d.png", txt, draw, seqn++);
597    Eprintf("EDrawableDumpImage: %s\n", buf);
598    imlib_save_image(buf);
599    imlib_free_image_and_decache();
600 }
601 #endif
602
603 void
604 FreePmapMask(PmapMask * pmm)
605 {
606    /* type !=0: Created by imlib_render_pixmaps_for_whole_image... */
607    if (pmm->pmap)
608      {
609         if (pmm->type == 0)
610            EFreePixmap(pmm->pmap);
611         else
612            imlib_free_pixmap_and_mask(pmm->pmap);
613         pmm->pmap = 0;
614      }
615
616    if (pmm->mask)
617      {
618         if (pmm->type == 0)
619            EFreePixmap(pmm->mask);
620         pmm->mask = 0;
621      }
622 }
623
624 EImageColorModifier *
625 EImageColorModifierCreate(void)
626 {
627    return imlib_create_color_modifier();
628 }
629
630 void
631 EImageColorModifierSetTables(EImageColorModifier * icm,
632                              unsigned char *r, unsigned char *g,
633                              unsigned char *b, unsigned char *a)
634 {
635    if (!icm)
636       return;
637
638    imlib_context_set_color_modifier(icm);
639 #if 0                           /* Useful in this context? */
640    imlib_modify_color_modifier_gamma(0.5);
641    imlib_modify_color_modifier_brightness(0.5);
642    imlib_modify_color_modifier_contrast(0.5);
643 #endif
644    imlib_set_color_modifier_tables(r, g, b, a);
645    imlib_context_set_color_modifier(NULL);
646 }