ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/rxvt-unicode/src/rxvtimg.C
Revision: 1.83
Committed: Thu Jun 14 18:06:15 2012 UTC (11 years, 11 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.82: +45 -20 lines
Log Message:
*** empty log message ***

File Contents

# User Rev Content
1 sf-exg 1.6 #include <math.h>
2 root 1.1 #include "../config.h"
3     #include "rxvt.h"
4    
5     #if HAVE_IMG
6    
7 root 1.83 static XRenderPictFormat *
8     find_alpha_format_for (Display *dpy, XRenderPictFormat *format)
9     {
10     if (format->direct.alphaMask)
11     return format; // already has alpha
12    
13     // try to find a suitable alpha format, one bit alpha is enough for our purposes
14     if (format->type == PictTypeDirect)
15     for (int n = 0; XRenderPictFormat *f = XRenderFindFormat (dpy, 0, 0, n); ++n)
16     if (f->direct.alphaMask
17     && f->type == PictTypeDirect
18     && ecb_popcount32 (f->direct.redMask ) >= ecb_popcount32 (format->direct.redMask )
19     && ecb_popcount32 (f->direct.greenMask) >= ecb_popcount32 (format->direct.greenMask)
20     && ecb_popcount32 (f->direct.blueMask ) >= ecb_popcount32 (format->direct.blueMask ))
21     return f;
22    
23     // should be a very good fallback
24     return XRenderFindStandardFormat (dpy, PictStandardARGB32);
25     }
26    
27 root 1.41 rxvt_img::rxvt_img (rxvt_screen *screen, XRenderPictFormat *format, int x, int y, int width, int height, int repeat)
28     : s(screen), x(x), y(y), w(width), h(height), format(format), repeat(repeat),
29 root 1.34 pm(0), ref(0)
30 root 1.1 {
31     }
32    
33 root 1.32 rxvt_img::rxvt_img (const rxvt_img &img)
34 root 1.34 : s(img.s), x(img.x), y(img.y), w(img.w), h(img.h), format(img.format), repeat(img.repeat), pm(img.pm), ref(img.ref)
35 root 1.32 {
36 root 1.34 ++ref->cnt;
37 root 1.32 }
38    
39 root 1.4 rxvt_img *
40 sf-exg 1.21 rxvt_img::new_from_root (rxvt_screen *s)
41     {
42     Display *dpy = s->display->dpy;
43     unsigned int root_pm_w, root_pm_h;
44     Pixmap root_pixmap = s->display->get_pixmap_property (s->display->xa[XA_XROOTPMAP_ID]);
45     if (root_pixmap == None)
46     root_pixmap = s->display->get_pixmap_property (s->display->xa[XA_ESETROOT_PMAP_ID]);
47    
48     if (root_pixmap == None)
49     return 0;
50    
51     Window wdummy;
52     int idummy;
53     unsigned int udummy;
54    
55     if (!XGetGeometry (dpy, root_pixmap, &wdummy, &idummy, &idummy, &root_pm_w, &root_pm_h, &udummy, &udummy))
56     return 0;
57    
58     rxvt_img *img = new rxvt_img (
59     s,
60     XRenderFindVisualFormat (dpy, DefaultVisual (dpy, s->display->screen)),
61 root 1.33 0,
62     0,
63 sf-exg 1.21 root_pm_w,
64 root 1.32 root_pm_h
65 sf-exg 1.21 );
66    
67 root 1.32 img->pm = root_pixmap;
68 root 1.34 img->ref = new pixref (root_pm_w, root_pm_h);
69     img->ref->ours = false;
70 sf-exg 1.21
71     return img;
72     }
73    
74 sf-exg 1.73 # if HAVE_PIXBUF
75 root 1.77
76 sf-exg 1.21 rxvt_img *
77 root 1.47 rxvt_img::new_from_pixbuf (rxvt_screen *s, GdkPixbuf *pb)
78     {
79 root 1.48 Display *dpy = s->display->dpy;
80    
81 root 1.47 int width = gdk_pixbuf_get_width (pb);
82     int height = gdk_pixbuf_get_height (pb);
83    
84     if (width > 32767 || height > 32767) // well, we *could* upload in chunks
85     rxvt_fatal ("rxvt_img::new_from_pixbuf: image too big (maximum size 32768x32768).\n");
86    
87     // since we require rgb24/argb32 formats from xrender we assume
88     // that both 24 and 32 bpp MUST be supported by any screen that supports xrender
89    
90 root 1.54 int byte_order = ecb_big_endian () ? MSBFirst : LSBFirst;
91    
92 root 1.47 XImage xi;
93    
94     xi.width = width;
95     xi.height = height;
96     xi.xoffset = 0;
97     xi.format = ZPixmap;
98 root 1.54 xi.byte_order = ImageByteOrder (dpy);
99 root 1.55 xi.bitmap_unit = 0; //XY only, unused
100     xi.bitmap_bit_order = 0; //XY only, unused
101 root 1.48 xi.bitmap_pad = BitmapPad (dpy);
102 root 1.76 xi.depth = 32;
103 root 1.47 xi.bytes_per_line = 0;
104 root 1.51 xi.bits_per_pixel = 32; //Z only
105 root 1.52 xi.red_mask = 0x00000000; //Z only, unused
106     xi.green_mask = 0x00000000; //Z only, unused
107     xi.blue_mask = 0x00000000; //Z only, unused
108     xi.obdata = 0; // probably unused
109 root 1.47
110 root 1.54 bool byte_order_mismatch = byte_order != xi.byte_order;
111    
112 root 1.47 if (!XInitImage (&xi))
113     rxvt_fatal ("unable to initialise ximage, please report.\n");
114    
115     if (height > INT_MAX / xi.bytes_per_line)
116     rxvt_fatal ("rxvt_img::new_from_pixbuf: image too big for Xlib.\n");
117    
118     xi.data = (char *)rxvt_malloc (height * xi.bytes_per_line);
119    
120     int rowstride = gdk_pixbuf_get_rowstride (pb);
121 root 1.76 bool pb_has_alpha = gdk_pixbuf_get_has_alpha (pb);
122     unsigned char *row = gdk_pixbuf_get_pixels (pb);
123 root 1.47
124     char *line = xi.data;
125    
126     for (int y = 0; y < height; y++)
127     {
128 root 1.50 unsigned char *src = row;
129     uint32_t *dst = (uint32_t *)line;
130 root 1.47
131 root 1.76 if (!pb_has_alpha)
132 root 1.47 for (int x = 0; x < width; x++)
133     {
134 root 1.50 uint8_t r = *src++;
135     uint8_t g = *src++;
136     uint8_t b = *src++;
137    
138 root 1.76 uint32_t v = (255 << 24) | (r << 16) | (g << 8) | b;
139 root 1.50
140 root 1.56 if (ecb_big_endian () ? !byte_order_mismatch : byte_order_mismatch)
141 root 1.54 v = ecb_bswap32 (v);
142    
143 root 1.51 *dst++ = v;
144 root 1.47 }
145     else
146     for (int x = 0; x < width; x++)
147     {
148 root 1.50 uint32_t v = *(uint32_t *)src; src += 4;
149 root 1.51
150 root 1.57 if (ecb_big_endian ())
151 root 1.51 v = ecb_bswap32 (v);
152    
153 root 1.58 v = ecb_rotl32 (v, 8); // abgr to bgra
154 root 1.52
155 root 1.57 if (!byte_order_mismatch)
156 root 1.54 v = ecb_bswap32 (v);
157    
158 root 1.51 *dst++ = v;
159 root 1.47 }
160    
161     row += rowstride;
162 root 1.50 line += xi.bytes_per_line;
163 root 1.47 }
164    
165 root 1.76 rxvt_img *img = new rxvt_img (s, XRenderFindStandardFormat (dpy, PictStandardARGB32), 0, 0, width, height);
166 root 1.47 img->alloc ();
167    
168     GC gc = XCreateGC (dpy, img->pm, 0, 0);
169     XPutImage (dpy, img->pm, gc, &xi, 0, 0, 0, 0, width, height);
170     XFreeGC (dpy, gc);
171    
172     free (xi.data);
173    
174     return img;
175     }
176    
177     rxvt_img *
178 root 1.4 rxvt_img::new_from_file (rxvt_screen *s, const char *filename)
179     {
180 root 1.11 GError *err = 0;
181 root 1.4 GdkPixbuf *pb = gdk_pixbuf_new_from_file (filename, &err);
182    
183     if (!pb)
184 root 1.11 rxvt_fatal ("rxvt_img::new_from_file: %s\n", err->message);
185 root 1.4
186 root 1.47 rxvt_img *img = new_from_pixbuf (s, pb);
187 root 1.4
188 sf-exg 1.26 g_object_unref (pb);
189    
190 root 1.4 return img;
191     }
192 root 1.77
193 sf-exg 1.73 # endif
194 root 1.4
195 root 1.32 void
196     rxvt_img::destroy ()
197     {
198 root 1.34 if (--ref->cnt)
199 root 1.32 return;
200    
201 root 1.34 if (pm && ref->ours)
202 root 1.32 XFreePixmap (s->display->dpy, pm);
203    
204 root 1.34 delete ref;
205 root 1.32 }
206    
207 root 1.1 rxvt_img::~rxvt_img ()
208     {
209 root 1.32 destroy ();
210     }
211    
212     void
213     rxvt_img::alloc ()
214     {
215     pm = XCreatePixmap (s->display->dpy, s->display->root, w, h, format->depth);
216 root 1.34 ref = new pixref (w, h);
217     }
218    
219     Picture
220     rxvt_img::src_picture ()
221     {
222     Display *dpy = s->display->dpy;
223    
224     XRenderPictureAttributes pa;
225     pa.repeat = repeat;
226     Picture pic = XRenderCreatePicture (dpy, pm, format, CPRepeat, &pa);
227    
228     return pic;
229 root 1.1 }
230    
231     void
232 root 1.11 rxvt_img::unshare ()
233     {
234 root 1.34 if (ref->cnt == 1 && ref->ours)
235 root 1.11 return;
236    
237 root 1.34 Pixmap pm2 = XCreatePixmap (s->display->dpy, s->display->root, ref->w, ref->h, format->depth);
238 root 1.32 GC gc = XCreateGC (s->display->dpy, pm, 0, 0);
239 root 1.34 XCopyArea (s->display->dpy, pm, pm2, gc, 0, 0, ref->w, ref->h, 0, 0);
240 root 1.32 XFreeGC (s->display->dpy, gc);
241 root 1.11
242 root 1.32 destroy ();
243 root 1.11
244 root 1.32 pm = pm2;
245 root 1.34 ref = new pixref (ref->w, ref->h);
246 root 1.11 }
247    
248     void
249 root 1.82 rxvt_img::fill (const rgba &c)
250 root 1.1 {
251 root 1.82 XRenderColor rc = { c.r, c.g, c.b, c.a };
252 root 1.77
253     Display *dpy = s->display->dpy;
254     Picture src = src_picture ();
255     XRenderFillRectangle (dpy, PictOpSrc, src, &rc, 0, 0, w, h);
256     XRenderFreePicture (dpy, src);
257 root 1.1 }
258    
259 root 1.83 void
260     rxvt_img::add_alpha ()
261     {
262     if (format->direct.alphaMask)
263     return;
264    
265     Display *dpy = s->display->dpy;
266    
267     rxvt_img *img = new rxvt_img (s, find_alpha_format_for (dpy, format), x, y, w, h, repeat);
268     img->alloc ();
269    
270     Picture src = src_picture ();
271     Picture dst = XRenderCreatePicture (dpy, img->pm, img->format, 0, 0);
272    
273     XRenderComposite (dpy, PictOpSrc, src, None, dst, 0, 0, 0, 0, 0, 0, w, h);
274    
275     XRenderFreePicture (dpy, src);
276     XRenderFreePicture (dpy, dst);
277    
278     ::swap (img->ref, ref);
279     ::swap (img->pm , pm );
280    
281     delete img;
282     }
283    
284 sf-exg 1.6 static void
285     get_gaussian_kernel (int radius, int width, double *kernel, XFixed *params)
286     {
287     double sigma = radius / 2.0;
288     double scale = sqrt (2.0 * M_PI) * sigma;
289     double sum = 0.0;
290    
291     for (int i = 0; i < width; i++)
292     {
293     double x = i - width / 2;
294     kernel[i] = exp (-(x * x) / (2.0 * sigma * sigma)) / scale;
295     sum += kernel[i];
296     }
297    
298     params[0] = XDoubleToFixed (width);
299     params[1] = XDoubleToFixed (1);
300    
301     for (int i = 0; i < width; i++)
302     params[i+2] = XDoubleToFixed (kernel[i] / sum);
303     }
304    
305 sf-exg 1.22 rxvt_img *
306 root 1.3 rxvt_img::blur (int rh, int rv)
307     {
308 sf-exg 1.6 if (!(s->display->flags & DISPLAY_HAS_RENDER_CONV))
309 sf-exg 1.22 return clone ();
310 sf-exg 1.6
311     Display *dpy = s->display->dpy;
312     int size = max (rh, rv) * 2 + 1;
313     double *kernel = (double *)malloc (size * sizeof (double));
314     XFixed *params = (XFixed *)malloc ((size + 2) * sizeof (XFixed));
315 root 1.41 rxvt_img *img = new rxvt_img (s, format, x, y, w, h, repeat);
316 root 1.32 img->alloc ();
317 sf-exg 1.6
318     XRenderPictureAttributes pa;
319     pa.repeat = RepeatPad;
320 sf-exg 1.61 Picture src = XRenderCreatePicture (dpy, pm, format, CPRepeat, &pa);
321     Picture dst = XRenderCreatePicture (dpy, img->pm, format, 0, 0);
322 sf-exg 1.22
323     Pixmap tmp_pm = XCreatePixmap (dpy, pm, w, h, format->depth);
324     Picture tmp = XRenderCreatePicture (dpy, tmp_pm , format, CPRepeat, &pa);
325     XFreePixmap (dpy, tmp_pm);
326 sf-exg 1.6
327     if (kernel && params)
328     {
329     size = rh * 2 + 1;
330     get_gaussian_kernel (rh, size, kernel, params);
331    
332     XRenderSetPictureFilter (dpy, src, FilterConvolution, params, size+2);
333     XRenderComposite (dpy,
334     PictOpSrc,
335     src,
336     None,
337 sf-exg 1.22 tmp,
338 sf-exg 1.6 0, 0,
339     0, 0,
340     0, 0,
341     w, h);
342    
343     size = rv * 2 + 1;
344     get_gaussian_kernel (rv, size, kernel, params);
345     ::swap (params[0], params[1]);
346    
347 sf-exg 1.60 XRenderSetPictureFilter (dpy, tmp, FilterConvolution, params, size+2);
348 sf-exg 1.6 XRenderComposite (dpy,
349     PictOpSrc,
350 sf-exg 1.22 tmp,
351 sf-exg 1.6 None,
352     dst,
353     0, 0,
354     0, 0,
355     0, 0,
356     w, h);
357     }
358    
359     free (kernel);
360     free (params);
361 root 1.77
362 sf-exg 1.6 XRenderFreePicture (dpy, src);
363     XRenderFreePicture (dpy, dst);
364 sf-exg 1.22 XRenderFreePicture (dpy, tmp);
365    
366     return img;
367 sf-exg 1.6 }
368    
369 root 1.74 static Picture
370 sf-exg 1.75 create_xrender_mask (Display *dpy, Drawable drawable, Bool argb, Bool component_alpha)
371 root 1.74 {
372     Pixmap pixmap = XCreatePixmap (dpy, drawable, 1, 1, argb ? 32 : 8);
373    
374     XRenderPictFormat *format = XRenderFindStandardFormat (dpy, argb ? PictStandardARGB32 : PictStandardA8);
375     XRenderPictureAttributes pa;
376     pa.repeat = RepeatNormal;
377 sf-exg 1.75 pa.component_alpha = component_alpha;
378     Picture mask = XRenderCreatePicture (dpy, pixmap, format, CPRepeat | CPComponentAlpha, &pa);
379 root 1.74
380     XFreePixmap (dpy, pixmap);
381    
382     return mask;
383     }
384    
385 root 1.67 static void
386     extract (int32_t cl0, int32_t cl1, int32_t &c, unsigned short &xc)
387     {
388     int32_t x = clamp (c, cl0, cl1);
389     c -= x;
390     xc = x;
391     }
392    
393     static bool
394     extract (int32_t cl0, int32_t cl1, int32_t &r, int32_t &g, int32_t &b, int32_t &a, unsigned short &xr, unsigned short &xg, unsigned short &xb, unsigned short &xa)
395     {
396     extract (cl0, cl1, r, xr);
397     extract (cl0, cl1, g, xg);
398     extract (cl0, cl1, b, xb);
399     extract (cl0, cl1, a, xa);
400    
401     return xr | xg | xb | xa;
402     }
403    
404 root 1.3 void
405 root 1.67 rxvt_img::brightness (int32_t r, int32_t g, int32_t b, int32_t a)
406 root 1.3 {
407 root 1.67 unshare ();
408    
409 sf-exg 1.6 Display *dpy = s->display->dpy;
410     Picture dst = XRenderCreatePicture (dpy, pm, format, 0, 0);
411    
412 root 1.69 // loop should not be needed for brightness, as only -1..1 makes sense
413 root 1.70 //while (r | g | b | a)
414 root 1.67 {
415     unsigned short xr, xg, xb, xa;
416     XRenderColor mask_c;
417    
418     if (extract (0, 65535, r, g, b, a, mask_c.red, mask_c.green, mask_c.blue, mask_c.alpha))
419     XRenderFillRectangle (dpy, PictOpAdd, dst, &mask_c, 0, 0, w, h);
420    
421     if (extract (-65535, 0, r, g, b, a, mask_c.red, mask_c.green, mask_c.blue, mask_c.alpha))
422     {
423     XRenderColor mask_w = { 65535, 65535, 65535, 65535 };
424     XRenderFillRectangle (dpy, PictOpDifference, dst, &mask_w, 0, 0, w, h);
425 root 1.70 mask_c.red = -mask_c.red; //TODO: verify that doing clamp, assign, and negation does the right thing
426 root 1.68 mask_c.green = -mask_c.green;
427     mask_c.blue = -mask_c.blue;
428     mask_c.alpha = -mask_c.alpha;
429 root 1.67 XRenderFillRectangle (dpy, PictOpAdd, dst, &mask_c, 0, 0, w, h);
430     XRenderFillRectangle (dpy, PictOpDifference, dst, &mask_w, 0, 0, w, h);
431     }
432     }
433 sf-exg 1.6
434 sf-exg 1.23 XRenderFreePicture (dpy, dst);
435 root 1.3 }
436    
437     void
438 root 1.67 rxvt_img::contrast (int32_t r, int32_t g, int32_t b, int32_t a)
439 root 1.1 {
440 root 1.74 if (r < 0 || g < 0 || b < 0 || a < 0)
441     rxvt_fatal ("rxvt_img::contrast does not support negative values.\n");
442    
443     rxvt_img *img = new rxvt_img (s, format, x, y, w, h, repeat);
444     img->alloc ();
445 root 1.82 img->fill (rgba (0, 0, 0, 0));
446 root 1.74
447     // premultiply (yeah, these are not exact, sue me or fix it)
448     r = (r * (a >> 8)) >> 8;
449     g = (g * (a >> 8)) >> 8;
450     b = (b * (a >> 8)) >> 8;
451 root 1.67
452 sf-exg 1.6 Display *dpy = s->display->dpy;
453    
454 root 1.74 Picture src = src_picture ();
455     Picture dst = XRenderCreatePicture (dpy, img->pm, format, 0, 0);
456 sf-exg 1.75 Picture mul = create_xrender_mask (dpy, pm, True, True);
457 root 1.74
458     //TODO: this operator does not yet implement some useful contrast
459     while (r | g | b | a)
460     {
461     unsigned short xr, xg, xb, xa;
462     XRenderColor mask_c;
463    
464     if (extract (0, 65535, r, g, b, a, mask_c.red, mask_c.green, mask_c.blue, mask_c.alpha))
465     {
466     XRenderFillRectangle (dpy, PictOpSrc, mul, &mask_c, 0, 0, 1, 1);
467     XRenderComposite (dpy, PictOpAdd, src, mul, dst, 0, 0, 0, 0, 0, 0, w, h);
468     }
469     }
470 sf-exg 1.6
471 root 1.74 XRenderFreePicture (dpy, mul);
472 sf-exg 1.23 XRenderFreePicture (dpy, dst);
473 root 1.74 XRenderFreePicture (dpy, src);
474    
475     ::swap (img->ref, ref);
476     ::swap (img->pm , pm );
477    
478     delete img;
479 root 1.1 }
480    
481 root 1.3 rxvt_img *
482 root 1.11 rxvt_img::clone ()
483 root 1.3 {
484 root 1.32 return new rxvt_img (*this);
485 root 1.3 }
486    
487     rxvt_img *
488 root 1.33 rxvt_img::reify ()
489 root 1.19 {
490 root 1.35 if (x == 0 && y == 0 && w == ref->w && h == ref->h)
491     return clone ();
492    
493 root 1.40 Display *dpy = s->display->dpy;
494    
495 root 1.62 // add an alpha channel if...
496     bool alpha = !format->direct.alphaMask // pixmap has none yet
497     && (x || y) // we need one because of non-zero offset
498     && repeat == RepeatNone; // and we have no good pixels to fill with
499 root 1.40
500 root 1.46 rxvt_img *img = new rxvt_img (s, alpha ? find_alpha_format_for (dpy, format) : format, 0, 0, w, h, repeat);
501 root 1.32 img->alloc ();
502 root 1.19
503 root 1.34 Picture src = src_picture ();
504     Picture dst = XRenderCreatePicture (dpy, img->pm, img->format, 0, 0);
505 root 1.33
506 root 1.42 if (alpha)
507     {
508     XRenderColor rc = { 0, 0, 0, 0 };
509 root 1.44 XRenderFillRectangle (dpy, PictOpSrc, dst, &rc, 0, 0, w, h);//TODO: split into four fillrectangles
510 root 1.42 XRenderComposite (dpy, PictOpSrc, src, None, dst, 0, 0, 0, 0, -x, -y, ref->w, ref->h);
511     }
512     else
513     XRenderComposite (dpy, PictOpSrc, src, None, dst, x, y, 0, 0, 0, 0, w, h);
514    
515 root 1.33 XRenderFreePicture (dpy, src);
516     XRenderFreePicture (dpy, dst);
517 root 1.19
518 root 1.33 return img;
519     }
520 root 1.19
521 root 1.33 rxvt_img *
522     rxvt_img::sub_rect (int x, int y, int width, int height)
523     {
524     rxvt_img *img = clone ();
525    
526     img->x += x;
527     img->y += y;
528 root 1.19
529 root 1.37 if (w != width || h != height)
530     {
531     img->w = width;
532     img->h = height;
533    
534 root 1.39 rxvt_img *img2 = img->reify ();
535     delete img;
536     img = img2;
537 root 1.37 }
538 root 1.36
539 root 1.19 return img;
540     }
541    
542 root 1.80 static void
543     mat_invert (double mat[3][3], double (&inv)[3][3])
544     {
545     double s0 = mat [2][2] * mat [1][1] - mat [2][1] * mat [1][2];
546     double s1 = mat [2][1] * mat [0][2] - mat [2][2] * mat [0][1];
547     double s2 = mat [1][2] * mat [0][1] - mat [1][1] * mat [0][2];
548    
549     double invdet = 1. / (mat [0][0] * s0 + mat [1][0] * s1 + mat [2][0] * s2);
550    
551     inv [0][0] = invdet * s0;
552     inv [0][1] = invdet * s1;
553     inv [0][2] = invdet * s2;
554    
555     inv [1][0] = invdet * (mat [2][0] * mat [1][2] - mat [2][2] * mat [1][0]);
556     inv [1][1] = invdet * (mat [2][2] * mat [0][0] - mat [2][0] * mat [0][2]);
557     inv [1][2] = invdet * (mat [1][0] * mat [0][2] - mat [1][2] * mat [0][0]);
558    
559     inv [2][0] = invdet * (mat [2][1] * mat [1][0] - mat [2][0] * mat [1][1]);
560     inv [2][1] = invdet * (mat [2][0] * mat [0][1] - mat [2][1] * mat [0][0]);
561     inv [2][2] = invdet * (mat [1][1] * mat [0][0] - mat [1][0] * mat [0][1]);
562     }
563    
564     static double
565     mat_apply (double mat[3][3], int i, double x, double y)
566     {
567     double v = mat [i][0] * x + mat [i][1] * y + mat [i][2];
568     double w = mat [2][0] * x + mat [2][1] * y + mat [2][2];
569    
570     return v * (1. / w);
571     }
572    
573 root 1.19 rxvt_img *
574 root 1.80 rxvt_img::transform (double matrix[3][3])
575 root 1.3 {
576 root 1.80 // find new offset
577     int ox = mat_apply (matrix, 0, x, y);
578     int oy = mat_apply (matrix, 1, x, y);
579    
580     // calculate new pixel bounding box coordinates
581 root 1.81 double d [2], rmin[2], rmax[2];
582 root 1.80
583     for (int i = 0; i < 2; ++i)
584     {
585     double v;
586 root 1.81 v = mat_apply (matrix, i, 0, 0); rmin [i] = rmax [i] = v; d [i] = v;
587 root 1.80 v = mat_apply (matrix, i, w, 0); min_it (rmin [i], v); max_it (rmax [i], v);
588     v = mat_apply (matrix, i, 0, h); min_it (rmin [i], v); max_it (rmax [i], v);
589     v = mat_apply (matrix, i, w, h); min_it (rmin [i], v); max_it (rmax [i], v);
590     }
591    
592     int dx = floor (rmin [0]);
593     int dy = floor (rmin [1]);
594    
595     int new_width = ceil (rmax [0] - dx);
596     int new_height = ceil (rmax [1] - dy);
597    
598     double inv[3][3];
599     mat_invert (matrix, inv);
600    
601 root 1.81 rxvt_img *img = new rxvt_img (s, format, ox - dx - d [0], oy - dy - d [1], new_width, new_height, repeat);
602 root 1.32 img->alloc ();
603 root 1.12
604     Display *dpy = s->display->dpy;
605 root 1.34 Picture src = src_picture ();
606     Picture dst = XRenderCreatePicture (dpy, img->pm, img->format, 0, 0);
607 root 1.12
608     XTransform xfrm;
609    
610     for (int i = 0; i < 3; ++i)
611     for (int j = 0; j < 3; ++j)
612 root 1.80 xfrm.matrix [i][j] = XDoubleToFixed (inv [i][j]);
613 root 1.33
614 root 1.17 XRenderSetPictureFilter (dpy, src, "good", 0, 0);
615 root 1.12 XRenderSetPictureTransform (dpy, src, &xfrm);
616 root 1.80 XRenderComposite (dpy, PictOpSrc, src, None, dst, dx, dy, 0, 0, 0, 0, new_width, new_height);
617 root 1.12
618     XRenderFreePicture (dpy, src);
619     XRenderFreePicture (dpy, dst);
620    
621     return img;
622 root 1.3 }
623    
624     rxvt_img *
625     rxvt_img::scale (int new_width, int new_height)
626     {
627 sf-exg 1.43 if (w == new_width && h == new_height)
628     return clone ();
629    
630 root 1.80 double matrix[3][3] = {
631     { new_width / (double)w, 0, 0 },
632     { 0, new_height / (double)h, 0 },
633     { 0, 0, 1 }
634 root 1.11 };
635    
636 root 1.42 int old_repeat_mode = repeat;
637 sf-exg 1.78 repeat = RepeatPad; // not right, but xrender can't properly scale it seems
638 root 1.42
639 root 1.80 rxvt_img *img = transform (matrix);
640 root 1.42
641     repeat = old_repeat_mode;
642     img->repeat = repeat;
643    
644     return img;
645 root 1.3 }
646    
647 sf-exg 1.7 rxvt_img *
648 root 1.80 rxvt_img::rotate (int cx, int cy, double phi)
649 root 1.17 {
650     double s = sin (phi);
651     double c = cos (phi);
652    
653 root 1.80 double matrix[3][3] = {
654 root 1.81 { c, -s, cx - c * cx + s * cy },
655     { s, c, cy - s * cx - c * cy },
656     { 0, 0, 1 }
657     //{ c, -s, 0 },
658     //{ s, c, 0 },
659     //{ 0, 0, 1 }
660 root 1.17 };
661    
662 root 1.81 //move (-cx, -cy);
663 root 1.80 rxvt_img *img = transform (matrix);
664 root 1.81 //move ( cx, cy);
665     //img->move (cx, cy);
666 root 1.80
667     return img;
668 root 1.17 }
669    
670     rxvt_img *
671 root 1.82 rxvt_img::convert_format (XRenderPictFormat *new_format, const rgba &bg)
672 sf-exg 1.7 {
673 root 1.32 if (new_format == format)
674     return clone ();
675    
676 root 1.45 rxvt_img *img = new rxvt_img (s, new_format, x, y, w, h, repeat);
677 root 1.32 img->alloc ();
678 root 1.9
679 sf-exg 1.7 Display *dpy = s->display->dpy;
680 root 1.34 Picture src = src_picture ();
681 root 1.8 Picture dst = XRenderCreatePicture (dpy, img->pm, new_format, 0, 0);
682 root 1.27 int op = PictOpSrc;
683 sf-exg 1.7
684 root 1.29 if (format->direct.alphaMask && !new_format->direct.alphaMask)
685 root 1.27 {
686     // does it have to be that complicated
687 root 1.82 XRenderColor rc = { bg.r, bg.g, bg.b, bg.a };
688 root 1.28 XRenderFillRectangle (dpy, PictOpSrc, dst, &rc, 0, 0, w, h);
689 root 1.27
690     op = PictOpOver;
691     }
692    
693     XRenderComposite (dpy, op, src, None, dst, 0, 0, 0, 0, 0, 0, w, h);
694 sf-exg 1.7
695     XRenderFreePicture (dpy, src);
696     XRenderFreePicture (dpy, dst);
697    
698     return img;
699     }
700 root 1.3
701 sf-exg 1.24 rxvt_img *
702     rxvt_img::blend (rxvt_img *img, double factor)
703     {
704     rxvt_img *img2 = clone ();
705     Display *dpy = s->display->dpy;
706 sf-exg 1.38 Picture src = img->src_picture ();
707 sf-exg 1.24 Picture dst = XRenderCreatePicture (dpy, img2->pm, img2->format, 0, 0);
708 sf-exg 1.75 Picture mask = create_xrender_mask (dpy, img->pm, False, False);
709 sf-exg 1.24
710     XRenderColor mask_c;
711    
712     mask_c.alpha = float_to_component (factor);
713     mask_c.red =
714     mask_c.green =
715     mask_c.blue = 0;
716     XRenderFillRectangle (dpy, PictOpSrc, mask, &mask_c, 0, 0, 1, 1);
717    
718     XRenderComposite (dpy, PictOpOver, src, mask, dst, 0, 0, 0, 0, 0, 0, w, h);
719    
720     XRenderFreePicture (dpy, src);
721     XRenderFreePicture (dpy, dst);
722     XRenderFreePicture (dpy, mask);
723    
724     return img2;
725     }
726    
727 root 1.1 #endif
728