ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/rxvt-unicode/src/rxvtimg.C
Revision: 1.97
Committed: Sun Jun 17 17:06:47 2012 UTC (11 years, 11 months ago) by sf-exg
Content type: text/plain
Branch: MAIN
Changes since 1.96: +5 -5 lines
Log Message:
Fix File headers.

File Contents

# User Rev Content
1 root 1.96 /*----------------------------------------------------------------------*
2 sf-exg 1.97 * File: rxvtimg.C
3 root 1.96 *----------------------------------------------------------------------*
4     *
5     * All portions of code are copyright by their respective author/s.
6     * Copyright (c) 2012 Marc Lehmann <schmorp@schmorp.de>
7     * Copyright (c) 2012 Emanuele Giaquinta <e.giaquinta@glauco.it>
8     *
9     * This program is free software; you can redistribute it and/or modify
10     * it under the terms of the GNU General Public License as published by
11     * the Free Software Foundation; either version 2 of the License, or
12     * (at your option) any later version.
13     *
14     * This program is distributed in the hope that it will be useful,
15     * but WITHOUT ANY WARRANTY; without even the implied warranty of
16     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17     * GNU General Public License for more details.
18     *
19     * You should have received a copy of the GNU General Public License
20     * along with this program; if not, write to the Free Software
21     * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22     *---------------------------------------------------------------------*/
23    
24 root 1.92 #include <string.h>
25 sf-exg 1.6 #include <math.h>
26 root 1.1 #include "../config.h"
27     #include "rxvt.h"
28    
29     #if HAVE_IMG
30    
31 root 1.92 typedef rxvt_img::nv nv;
32    
33 root 1.93 namespace
34 root 1.92 {
35    
36 root 1.93 struct mat3x3
37 root 1.92 {
38 root 1.93 nv v[3][3];
39    
40     mat3x3 ()
41     {
42     }
43    
44 root 1.95 mat3x3 (const nv *matrix)
45 root 1.93 {
46     memcpy (v, matrix, sizeof (v));
47     }
48 root 1.92
49 root 1.93 mat3x3 (nv v11, nv v12, nv v13, nv v21, nv v22, nv v23, nv v31, nv v32, nv v33)
50     {
51     v[0][0] = v11; v[0][1] = v12; v[0][2] = v13;
52     v[1][0] = v21; v[1][1] = v22; v[1][2] = v23;
53     v[2][0] = v31; v[2][1] = v32; v[2][2] = v33;
54     }
55 root 1.92
56 root 1.93 mat3x3 invert ();
57 root 1.92
58 root 1.93 nv *operator [](int i) { return &v[i][0]; }
59     const nv *operator [](int i) const { return &v[i][0]; }
60 root 1.92
61 root 1.95 operator const nv * () const { return &v[0][0]; }
62     operator nv * () { return &v[0][0]; }
63    
64 root 1.93 // quite inefficient, hopefully gcc pulls the w calc out of any loops
65     nv apply1 (int i, nv x, nv y)
66     {
67     mat3x3 &m = *this;
68 root 1.92
69 root 1.93 nv v = m[i][0] * x + m[i][1] * y + m[i][2];
70     nv w = m[2][0] * x + m[2][1] * y + m[2][2];
71 root 1.92
72 root 1.93 return v * (1. / w);
73     }
74 root 1.92
75 root 1.93 static mat3x3 translate (nv x, nv y);
76 root 1.95 static mat3x3 scale (nv s, nv t);
77     static mat3x3 rotate (nv phi);
78 root 1.93 };
79 root 1.92
80 root 1.93 mat3x3
81     mat3x3::invert ()
82     {
83     mat3x3 &m = *this;
84     mat3x3 inv;
85 root 1.92
86 root 1.93 nv s0 = m[2][2] * m[1][1] - m[2][1] * m[1][2];
87     nv s1 = m[2][1] * m[0][2] - m[2][2] * m[0][1];
88     nv s2 = m[1][2] * m[0][1] - m[1][1] * m[0][2];
89 root 1.92
90 root 1.93 nv invdet = 1. / (m[0][0] * s0 + m[1][0] * s1 + m[2][0] * s2);
91 root 1.92
92 root 1.93 inv[0][0] = invdet * s0;
93     inv[0][1] = invdet * s1;
94     inv[0][2] = invdet * s2;
95 root 1.92
96 root 1.93 inv[1][0] = invdet * (m[2][0] * m[1][2] - m[2][2] * m[1][0]);
97     inv[1][1] = invdet * (m[2][2] * m[0][0] - m[2][0] * m[0][2]);
98     inv[1][2] = invdet * (m[1][0] * m[0][2] - m[1][2] * m[0][0]);
99 root 1.92
100 root 1.93 inv[2][0] = invdet * (m[2][1] * m[1][0] - m[2][0] * m[1][1]);
101     inv[2][1] = invdet * (m[2][0] * m[0][1] - m[2][1] * m[0][0]);
102     inv[2][2] = invdet * (m[1][1] * m[0][0] - m[1][0] * m[0][1]);
103 root 1.92
104 root 1.93 return inv;
105     }
106 root 1.92
107 root 1.93 static mat3x3
108     operator *(const mat3x3 &a, const mat3x3 &b)
109     {
110     mat3x3 r;
111 root 1.92
112 root 1.93 for (int i = 0; i < 3; ++i)
113     for (int j = 0; j < 3; ++j)
114     r[i][j] = a[i][0] * b[0][j]
115     + a[i][1] * b[1][j]
116     + a[i][2] * b[2][j];
117 root 1.92
118 root 1.93 return r;
119     }
120 root 1.92
121 root 1.93 mat3x3
122     mat3x3::translate (nv x, nv y)
123     {
124     return mat3x3 (
125     1, 0, x,
126     0, 1, y,
127     0, 0, 1
128     );
129     }
130 root 1.92
131 root 1.95 mat3x3
132     mat3x3::scale (nv s, nv t)
133     {
134     return mat3x3 (
135     s, 0, 0,
136     0, t, 0,
137     0, 0, 1
138     );
139     }
140    
141     // clockwise
142     mat3x3
143     mat3x3::rotate (nv phi)
144     {
145     nv s = sin (phi);
146     nv c = cos (phi);
147    
148     return mat3x3 (
149     c, -s, 0,
150     s, c, 0,
151     0, 0, 1
152     );
153     }
154    
155 root 1.92 }
156    
157 root 1.85 #if 0
158     struct pict
159     {
160     Display *dpy;
161     Picture pic;
162    
163     operator Picture () const
164     {
165     return pic;
166     }
167    
168     pict ()
169     : pic (0)
170     {
171     }
172    
173     pict (rxvt_img *img, XRenderPictFormat *format = 0)
174     : dpy (img->s->display->dpy)
175     {
176     XRenderPictureAttributes pa;
177     pa.repeat = img->repeat;
178     pic = XRenderCreatePicture (dpy, img->pm, format ? format : img->format, CPRepeat, &pa);
179     }
180    
181     ~pict ()
182     {
183     if (pic)
184     XRenderFreePicture (dpy, pic);
185     }
186     };
187     #endif
188    
189 root 1.83 static XRenderPictFormat *
190     find_alpha_format_for (Display *dpy, XRenderPictFormat *format)
191     {
192     if (format->direct.alphaMask)
193     return format; // already has alpha
194    
195     // try to find a suitable alpha format, one bit alpha is enough for our purposes
196     if (format->type == PictTypeDirect)
197     for (int n = 0; XRenderPictFormat *f = XRenderFindFormat (dpy, 0, 0, n); ++n)
198     if (f->direct.alphaMask
199     && f->type == PictTypeDirect
200     && ecb_popcount32 (f->direct.redMask ) >= ecb_popcount32 (format->direct.redMask )
201     && ecb_popcount32 (f->direct.greenMask) >= ecb_popcount32 (format->direct.greenMask)
202     && ecb_popcount32 (f->direct.blueMask ) >= ecb_popcount32 (format->direct.blueMask ))
203     return f;
204    
205     // should be a very good fallback
206     return XRenderFindStandardFormat (dpy, PictStandardARGB32);
207     }
208    
209 root 1.41 rxvt_img::rxvt_img (rxvt_screen *screen, XRenderPictFormat *format, int x, int y, int width, int height, int repeat)
210     : s(screen), x(x), y(y), w(width), h(height), format(format), repeat(repeat),
211 root 1.34 pm(0), ref(0)
212 root 1.1 {
213     }
214    
215 root 1.32 rxvt_img::rxvt_img (const rxvt_img &img)
216 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)
217 root 1.32 {
218 root 1.34 ++ref->cnt;
219 root 1.32 }
220    
221 root 1.4 rxvt_img *
222 sf-exg 1.21 rxvt_img::new_from_root (rxvt_screen *s)
223     {
224     Display *dpy = s->display->dpy;
225     unsigned int root_pm_w, root_pm_h;
226     Pixmap root_pixmap = s->display->get_pixmap_property (s->display->xa[XA_XROOTPMAP_ID]);
227     if (root_pixmap == None)
228     root_pixmap = s->display->get_pixmap_property (s->display->xa[XA_ESETROOT_PMAP_ID]);
229    
230     if (root_pixmap == None)
231     return 0;
232    
233     Window wdummy;
234     int idummy;
235     unsigned int udummy;
236    
237     if (!XGetGeometry (dpy, root_pixmap, &wdummy, &idummy, &idummy, &root_pm_w, &root_pm_h, &udummy, &udummy))
238     return 0;
239    
240     rxvt_img *img = new rxvt_img (
241     s,
242     XRenderFindVisualFormat (dpy, DefaultVisual (dpy, s->display->screen)),
243 root 1.33 0,
244     0,
245 sf-exg 1.21 root_pm_w,
246 root 1.32 root_pm_h
247 sf-exg 1.21 );
248    
249 root 1.32 img->pm = root_pixmap;
250 root 1.34 img->ref = new pixref (root_pm_w, root_pm_h);
251     img->ref->ours = false;
252 sf-exg 1.21
253     return img;
254     }
255    
256 sf-exg 1.73 # if HAVE_PIXBUF
257 root 1.77
258 sf-exg 1.21 rxvt_img *
259 root 1.47 rxvt_img::new_from_pixbuf (rxvt_screen *s, GdkPixbuf *pb)
260     {
261 root 1.48 Display *dpy = s->display->dpy;
262    
263 root 1.47 int width = gdk_pixbuf_get_width (pb);
264     int height = gdk_pixbuf_get_height (pb);
265    
266     if (width > 32767 || height > 32767) // well, we *could* upload in chunks
267     rxvt_fatal ("rxvt_img::new_from_pixbuf: image too big (maximum size 32768x32768).\n");
268    
269     // since we require rgb24/argb32 formats from xrender we assume
270     // that both 24 and 32 bpp MUST be supported by any screen that supports xrender
271    
272 root 1.54 int byte_order = ecb_big_endian () ? MSBFirst : LSBFirst;
273    
274 root 1.47 XImage xi;
275    
276     xi.width = width;
277     xi.height = height;
278     xi.xoffset = 0;
279     xi.format = ZPixmap;
280 root 1.54 xi.byte_order = ImageByteOrder (dpy);
281 root 1.55 xi.bitmap_unit = 0; //XY only, unused
282     xi.bitmap_bit_order = 0; //XY only, unused
283 root 1.48 xi.bitmap_pad = BitmapPad (dpy);
284 root 1.76 xi.depth = 32;
285 root 1.47 xi.bytes_per_line = 0;
286 root 1.51 xi.bits_per_pixel = 32; //Z only
287 root 1.52 xi.red_mask = 0x00000000; //Z only, unused
288     xi.green_mask = 0x00000000; //Z only, unused
289     xi.blue_mask = 0x00000000; //Z only, unused
290     xi.obdata = 0; // probably unused
291 root 1.47
292 root 1.54 bool byte_order_mismatch = byte_order != xi.byte_order;
293    
294 root 1.47 if (!XInitImage (&xi))
295     rxvt_fatal ("unable to initialise ximage, please report.\n");
296    
297     if (height > INT_MAX / xi.bytes_per_line)
298     rxvt_fatal ("rxvt_img::new_from_pixbuf: image too big for Xlib.\n");
299    
300     xi.data = (char *)rxvt_malloc (height * xi.bytes_per_line);
301    
302     int rowstride = gdk_pixbuf_get_rowstride (pb);
303 root 1.76 bool pb_has_alpha = gdk_pixbuf_get_has_alpha (pb);
304     unsigned char *row = gdk_pixbuf_get_pixels (pb);
305 root 1.47
306     char *line = xi.data;
307    
308     for (int y = 0; y < height; y++)
309     {
310 root 1.50 unsigned char *src = row;
311     uint32_t *dst = (uint32_t *)line;
312 root 1.47
313 root 1.76 if (!pb_has_alpha)
314 root 1.47 for (int x = 0; x < width; x++)
315     {
316 root 1.50 uint8_t r = *src++;
317     uint8_t g = *src++;
318     uint8_t b = *src++;
319    
320 root 1.76 uint32_t v = (255 << 24) | (r << 16) | (g << 8) | b;
321 sf-exg 1.97
322 root 1.56 if (ecb_big_endian () ? !byte_order_mismatch : byte_order_mismatch)
323 root 1.54 v = ecb_bswap32 (v);
324    
325 root 1.51 *dst++ = v;
326 root 1.47 }
327     else
328     for (int x = 0; x < width; x++)
329     {
330 root 1.50 uint32_t v = *(uint32_t *)src; src += 4;
331 root 1.51
332 root 1.57 if (ecb_big_endian ())
333 root 1.51 v = ecb_bswap32 (v);
334    
335 root 1.58 v = ecb_rotl32 (v, 8); // abgr to bgra
336 root 1.52
337 root 1.57 if (!byte_order_mismatch)
338 root 1.54 v = ecb_bswap32 (v);
339    
340 root 1.51 *dst++ = v;
341 root 1.47 }
342    
343     row += rowstride;
344 root 1.50 line += xi.bytes_per_line;
345 root 1.47 }
346    
347 root 1.76 rxvt_img *img = new rxvt_img (s, XRenderFindStandardFormat (dpy, PictStandardARGB32), 0, 0, width, height);
348 root 1.47 img->alloc ();
349    
350     GC gc = XCreateGC (dpy, img->pm, 0, 0);
351     XPutImage (dpy, img->pm, gc, &xi, 0, 0, 0, 0, width, height);
352     XFreeGC (dpy, gc);
353    
354     free (xi.data);
355    
356     return img;
357     }
358    
359     rxvt_img *
360 root 1.4 rxvt_img::new_from_file (rxvt_screen *s, const char *filename)
361     {
362 root 1.11 GError *err = 0;
363 root 1.4 GdkPixbuf *pb = gdk_pixbuf_new_from_file (filename, &err);
364    
365     if (!pb)
366 root 1.11 rxvt_fatal ("rxvt_img::new_from_file: %s\n", err->message);
367 root 1.4
368 root 1.47 rxvt_img *img = new_from_pixbuf (s, pb);
369 root 1.4
370 sf-exg 1.26 g_object_unref (pb);
371    
372 root 1.4 return img;
373     }
374 root 1.77
375 sf-exg 1.73 # endif
376 root 1.4
377 root 1.32 void
378     rxvt_img::destroy ()
379     {
380 root 1.34 if (--ref->cnt)
381 root 1.32 return;
382    
383 root 1.34 if (pm && ref->ours)
384 root 1.32 XFreePixmap (s->display->dpy, pm);
385    
386 root 1.34 delete ref;
387 root 1.32 }
388    
389 root 1.1 rxvt_img::~rxvt_img ()
390     {
391 root 1.32 destroy ();
392     }
393    
394     void
395     rxvt_img::alloc ()
396     {
397     pm = XCreatePixmap (s->display->dpy, s->display->root, w, h, format->depth);
398 root 1.34 ref = new pixref (w, h);
399     }
400    
401     Picture
402 root 1.85 rxvt_img::picture ()
403 root 1.34 {
404     Display *dpy = s->display->dpy;
405    
406     XRenderPictureAttributes pa;
407     pa.repeat = repeat;
408     Picture pic = XRenderCreatePicture (dpy, pm, format, CPRepeat, &pa);
409    
410     return pic;
411 root 1.1 }
412    
413     void
414 root 1.11 rxvt_img::unshare ()
415     {
416 root 1.34 if (ref->cnt == 1 && ref->ours)
417 root 1.11 return;
418    
419 root 1.34 Pixmap pm2 = XCreatePixmap (s->display->dpy, s->display->root, ref->w, ref->h, format->depth);
420 root 1.32 GC gc = XCreateGC (s->display->dpy, pm, 0, 0);
421 root 1.34 XCopyArea (s->display->dpy, pm, pm2, gc, 0, 0, ref->w, ref->h, 0, 0);
422 root 1.32 XFreeGC (s->display->dpy, gc);
423 root 1.11
424 root 1.32 destroy ();
425 root 1.11
426 root 1.32 pm = pm2;
427 root 1.34 ref = new pixref (ref->w, ref->h);
428 root 1.11 }
429    
430     void
431 root 1.82 rxvt_img::fill (const rgba &c)
432 root 1.1 {
433 root 1.82 XRenderColor rc = { c.r, c.g, c.b, c.a };
434 root 1.77
435     Display *dpy = s->display->dpy;
436 root 1.85 Picture src = picture ();
437 root 1.77 XRenderFillRectangle (dpy, PictOpSrc, src, &rc, 0, 0, w, h);
438     XRenderFreePicture (dpy, src);
439 root 1.1 }
440    
441 root 1.83 void
442     rxvt_img::add_alpha ()
443     {
444     if (format->direct.alphaMask)
445     return;
446    
447     Display *dpy = s->display->dpy;
448    
449     rxvt_img *img = new rxvt_img (s, find_alpha_format_for (dpy, format), x, y, w, h, repeat);
450     img->alloc ();
451    
452 root 1.85 Picture src = picture ();
453 root 1.83 Picture dst = XRenderCreatePicture (dpy, img->pm, img->format, 0, 0);
454 sf-exg 1.97
455 root 1.83 XRenderComposite (dpy, PictOpSrc, src, None, dst, 0, 0, 0, 0, 0, 0, w, h);
456    
457     XRenderFreePicture (dpy, src);
458     XRenderFreePicture (dpy, dst);
459    
460     ::swap (img->ref, ref);
461     ::swap (img->pm , pm );
462    
463     delete img;
464     }
465    
466 sf-exg 1.6 static void
467 root 1.92 get_gaussian_kernel (int radius, int width, nv *kernel, XFixed *params)
468 sf-exg 1.6 {
469 root 1.92 nv sigma = radius / 2.0;
470     nv scale = sqrt (2.0 * M_PI) * sigma;
471     nv sum = 0.0;
472 sf-exg 1.6
473     for (int i = 0; i < width; i++)
474     {
475 root 1.92 nv x = i - width / 2;
476 sf-exg 1.6 kernel[i] = exp (-(x * x) / (2.0 * sigma * sigma)) / scale;
477     sum += kernel[i];
478     }
479    
480     params[0] = XDoubleToFixed (width);
481     params[1] = XDoubleToFixed (1);
482    
483     for (int i = 0; i < width; i++)
484     params[i+2] = XDoubleToFixed (kernel[i] / sum);
485     }
486    
487 sf-exg 1.22 rxvt_img *
488 root 1.3 rxvt_img::blur (int rh, int rv)
489     {
490 sf-exg 1.6 if (!(s->display->flags & DISPLAY_HAS_RENDER_CONV))
491 sf-exg 1.22 return clone ();
492 sf-exg 1.6
493     Display *dpy = s->display->dpy;
494     int size = max (rh, rv) * 2 + 1;
495 root 1.84 nv *kernel = (nv *)malloc (size * sizeof (nv));
496 sf-exg 1.6 XFixed *params = (XFixed *)malloc ((size + 2) * sizeof (XFixed));
497 root 1.41 rxvt_img *img = new rxvt_img (s, format, x, y, w, h, repeat);
498 root 1.32 img->alloc ();
499 sf-exg 1.6
500     XRenderPictureAttributes pa;
501     pa.repeat = RepeatPad;
502 sf-exg 1.61 Picture src = XRenderCreatePicture (dpy, pm, format, CPRepeat, &pa);
503     Picture dst = XRenderCreatePicture (dpy, img->pm, format, 0, 0);
504 sf-exg 1.22
505     Pixmap tmp_pm = XCreatePixmap (dpy, pm, w, h, format->depth);
506     Picture tmp = XRenderCreatePicture (dpy, tmp_pm , format, CPRepeat, &pa);
507     XFreePixmap (dpy, tmp_pm);
508 sf-exg 1.6
509     if (kernel && params)
510     {
511     size = rh * 2 + 1;
512     get_gaussian_kernel (rh, size, kernel, params);
513    
514     XRenderSetPictureFilter (dpy, src, FilterConvolution, params, size+2);
515     XRenderComposite (dpy,
516     PictOpSrc,
517     src,
518     None,
519 sf-exg 1.22 tmp,
520 sf-exg 1.6 0, 0,
521     0, 0,
522     0, 0,
523     w, h);
524    
525     size = rv * 2 + 1;
526     get_gaussian_kernel (rv, size, kernel, params);
527     ::swap (params[0], params[1]);
528    
529 sf-exg 1.60 XRenderSetPictureFilter (dpy, tmp, FilterConvolution, params, size+2);
530 sf-exg 1.6 XRenderComposite (dpy,
531     PictOpSrc,
532 sf-exg 1.22 tmp,
533 sf-exg 1.6 None,
534     dst,
535     0, 0,
536     0, 0,
537     0, 0,
538     w, h);
539     }
540    
541     free (kernel);
542     free (params);
543 root 1.77
544 sf-exg 1.6 XRenderFreePicture (dpy, src);
545     XRenderFreePicture (dpy, dst);
546 sf-exg 1.22 XRenderFreePicture (dpy, tmp);
547    
548     return img;
549 sf-exg 1.6 }
550    
551 root 1.74 static Picture
552 sf-exg 1.75 create_xrender_mask (Display *dpy, Drawable drawable, Bool argb, Bool component_alpha)
553 root 1.74 {
554     Pixmap pixmap = XCreatePixmap (dpy, drawable, 1, 1, argb ? 32 : 8);
555    
556     XRenderPictFormat *format = XRenderFindStandardFormat (dpy, argb ? PictStandardARGB32 : PictStandardA8);
557     XRenderPictureAttributes pa;
558     pa.repeat = RepeatNormal;
559 sf-exg 1.75 pa.component_alpha = component_alpha;
560     Picture mask = XRenderCreatePicture (dpy, pixmap, format, CPRepeat | CPComponentAlpha, &pa);
561 root 1.74
562     XFreePixmap (dpy, pixmap);
563    
564     return mask;
565     }
566    
567 root 1.67 static void
568     extract (int32_t cl0, int32_t cl1, int32_t &c, unsigned short &xc)
569     {
570     int32_t x = clamp (c, cl0, cl1);
571     c -= x;
572     xc = x;
573     }
574    
575     static bool
576     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)
577     {
578     extract (cl0, cl1, r, xr);
579     extract (cl0, cl1, g, xg);
580     extract (cl0, cl1, b, xb);
581     extract (cl0, cl1, a, xa);
582    
583     return xr | xg | xb | xa;
584     }
585    
586 root 1.3 void
587 root 1.67 rxvt_img::brightness (int32_t r, int32_t g, int32_t b, int32_t a)
588 root 1.3 {
589 root 1.67 unshare ();
590    
591 sf-exg 1.6 Display *dpy = s->display->dpy;
592     Picture dst = XRenderCreatePicture (dpy, pm, format, 0, 0);
593    
594 root 1.69 // loop should not be needed for brightness, as only -1..1 makes sense
595 root 1.70 //while (r | g | b | a)
596 root 1.67 {
597     unsigned short xr, xg, xb, xa;
598     XRenderColor mask_c;
599    
600     if (extract (0, 65535, r, g, b, a, mask_c.red, mask_c.green, mask_c.blue, mask_c.alpha))
601     XRenderFillRectangle (dpy, PictOpAdd, dst, &mask_c, 0, 0, w, h);
602    
603     if (extract (-65535, 0, r, g, b, a, mask_c.red, mask_c.green, mask_c.blue, mask_c.alpha))
604     {
605     XRenderColor mask_w = { 65535, 65535, 65535, 65535 };
606     XRenderFillRectangle (dpy, PictOpDifference, dst, &mask_w, 0, 0, w, h);
607 root 1.70 mask_c.red = -mask_c.red; //TODO: verify that doing clamp, assign, and negation does the right thing
608 root 1.68 mask_c.green = -mask_c.green;
609     mask_c.blue = -mask_c.blue;
610     mask_c.alpha = -mask_c.alpha;
611 root 1.67 XRenderFillRectangle (dpy, PictOpAdd, dst, &mask_c, 0, 0, w, h);
612     XRenderFillRectangle (dpy, PictOpDifference, dst, &mask_w, 0, 0, w, h);
613     }
614     }
615 sf-exg 1.6
616 sf-exg 1.23 XRenderFreePicture (dpy, dst);
617 root 1.3 }
618    
619     void
620 root 1.67 rxvt_img::contrast (int32_t r, int32_t g, int32_t b, int32_t a)
621 root 1.1 {
622 root 1.74 if (r < 0 || g < 0 || b < 0 || a < 0)
623     rxvt_fatal ("rxvt_img::contrast does not support negative values.\n");
624    
625     rxvt_img *img = new rxvt_img (s, format, x, y, w, h, repeat);
626     img->alloc ();
627 root 1.82 img->fill (rgba (0, 0, 0, 0));
628 root 1.74
629     // premultiply (yeah, these are not exact, sue me or fix it)
630     r = (r * (a >> 8)) >> 8;
631     g = (g * (a >> 8)) >> 8;
632     b = (b * (a >> 8)) >> 8;
633 root 1.67
634 sf-exg 1.6 Display *dpy = s->display->dpy;
635    
636 root 1.85 Picture src = picture ();
637 root 1.74 Picture dst = XRenderCreatePicture (dpy, img->pm, format, 0, 0);
638 sf-exg 1.75 Picture mul = create_xrender_mask (dpy, pm, True, True);
639 root 1.74
640     //TODO: this operator does not yet implement some useful contrast
641     while (r | g | b | a)
642     {
643     unsigned short xr, xg, xb, xa;
644     XRenderColor mask_c;
645    
646     if (extract (0, 65535, r, g, b, a, mask_c.red, mask_c.green, mask_c.blue, mask_c.alpha))
647     {
648     XRenderFillRectangle (dpy, PictOpSrc, mul, &mask_c, 0, 0, 1, 1);
649     XRenderComposite (dpy, PictOpAdd, src, mul, dst, 0, 0, 0, 0, 0, 0, w, h);
650     }
651     }
652 sf-exg 1.6
653 root 1.74 XRenderFreePicture (dpy, mul);
654 sf-exg 1.23 XRenderFreePicture (dpy, dst);
655 root 1.74 XRenderFreePicture (dpy, src);
656    
657     ::swap (img->ref, ref);
658     ::swap (img->pm , pm );
659    
660     delete img;
661 root 1.1 }
662    
663 root 1.85 void
664     rxvt_img::draw (rxvt_img *img, int op, nv mask)
665     {
666     unshare ();
667    
668     Display *dpy = s->display->dpy;
669     Picture src = img->picture ();
670     Picture dst = picture ();
671     Picture mask_p = 0;
672 sf-exg 1.97
673 root 1.85 if (mask != 1.)
674     {
675     mask_p = create_xrender_mask (dpy, img->pm, False, False);
676     XRenderColor mask_c = { 0, 0, 0, float_to_component (mask) };
677     XRenderFillRectangle (dpy, PictOpSrc, mask, &mask_c, 0, 0, 1, 1);
678     }
679    
680     XRenderComposite (dpy, op, src, mask_p, dst, x - img->x, y - img->y, 0, 0, 0, 0, w, h);
681    
682     XRenderFreePicture (dpy, src);
683     XRenderFreePicture (dpy, dst);
684    
685 root 1.86 if (mask_p)
686 root 1.85 XRenderFreePicture (dpy, mask_p);
687     }
688    
689 root 1.3 rxvt_img *
690 root 1.11 rxvt_img::clone ()
691 root 1.3 {
692 root 1.32 return new rxvt_img (*this);
693 root 1.3 }
694    
695     rxvt_img *
696 root 1.33 rxvt_img::reify ()
697 root 1.19 {
698 root 1.35 if (x == 0 && y == 0 && w == ref->w && h == ref->h)
699     return clone ();
700    
701 root 1.40 Display *dpy = s->display->dpy;
702    
703 root 1.62 // add an alpha channel if...
704     bool alpha = !format->direct.alphaMask // pixmap has none yet
705     && (x || y) // we need one because of non-zero offset
706     && repeat == RepeatNone; // and we have no good pixels to fill with
707 root 1.40
708 root 1.46 rxvt_img *img = new rxvt_img (s, alpha ? find_alpha_format_for (dpy, format) : format, 0, 0, w, h, repeat);
709 root 1.32 img->alloc ();
710 root 1.19
711 root 1.85 Picture src = picture ();
712 root 1.34 Picture dst = XRenderCreatePicture (dpy, img->pm, img->format, 0, 0);
713 sf-exg 1.97
714 root 1.42 if (alpha)
715     {
716     XRenderColor rc = { 0, 0, 0, 0 };
717 root 1.44 XRenderFillRectangle (dpy, PictOpSrc, dst, &rc, 0, 0, w, h);//TODO: split into four fillrectangles
718 root 1.86 XRenderComposite (dpy, PictOpSrc, src, None, dst, 0, 0, 0, 0, x, y, ref->w, ref->h);
719 root 1.42 }
720     else
721 root 1.86 XRenderComposite (dpy, PictOpSrc, src, None, dst, -x, -y, 0, 0, 0, 0, w, h);
722 root 1.42
723 root 1.33 XRenderFreePicture (dpy, src);
724     XRenderFreePicture (dpy, dst);
725 root 1.19
726 root 1.33 return img;
727     }
728 root 1.19
729 root 1.33 rxvt_img *
730     rxvt_img::sub_rect (int x, int y, int width, int height)
731     {
732     rxvt_img *img = clone ();
733    
734 root 1.86 img->x -= x;
735     img->y -= y;
736 root 1.19
737 root 1.37 if (w != width || h != height)
738     {
739     img->w = width;
740     img->h = height;
741    
742 root 1.39 rxvt_img *img2 = img->reify ();
743     delete img;
744     img = img2;
745 root 1.37 }
746 root 1.36
747 root 1.19 return img;
748     }
749    
750     rxvt_img *
751 root 1.95 rxvt_img::transform (const nv matrix[3][3])
752 root 1.3 {
753 root 1.95 return transform (mat3x3 (&matrix[0][0]));
754     }
755    
756     rxvt_img *
757     rxvt_img::transform (const nv *matrix)
758     {
759     mat3x3 m (matrix);
760    
761 root 1.80 // calculate new pixel bounding box coordinates
762 root 1.91 nv r[2], rmin[2], rmax[2];
763 root 1.80
764     for (int i = 0; i < 2; ++i)
765     {
766 root 1.84 nv v;
767 root 1.90
768 root 1.92 v = m.apply1 (i, 0+x, 0+y); rmin [i] = rmax [i] = v; r [i] = v;
769     v = m.apply1 (i, w+x, 0+y); min_it (rmin [i], v); max_it (rmax [i], v);
770     v = m.apply1 (i, 0+x, h+y); min_it (rmin [i], v); max_it (rmax [i], v);
771     v = m.apply1 (i, w+x, h+y); min_it (rmin [i], v); max_it (rmax [i], v);
772 root 1.80 }
773    
774 root 1.91 float sx = rmin [0] - x;
775     float sy = rmin [1] - y;
776    
777 root 1.89 // TODO: adjust matrix for subpixel accuracy
778 root 1.91 int nx = floor (rmin [0]);
779     int ny = floor (rmin [1]);
780    
781     int new_width = ceil (rmax [0] - rmin [0]);
782     int new_height = ceil (rmax [1] - rmin [1]);
783 root 1.80
784 root 1.92 m = mat3x3::translate (-x, -y) * m * mat3x3::translate (x, y);
785 root 1.80
786 root 1.92 mat3x3 inv = m.invert ();
787 root 1.80
788 root 1.91 rxvt_img *img = new rxvt_img (s, format, nx, ny, new_width, new_height, repeat);
789 root 1.32 img->alloc ();
790 root 1.12
791     Display *dpy = s->display->dpy;
792 root 1.85 Picture src = picture ();
793 root 1.34 Picture dst = XRenderCreatePicture (dpy, img->pm, img->format, 0, 0);
794 root 1.12
795     XTransform xfrm;
796    
797     for (int i = 0; i < 3; ++i)
798     for (int j = 0; j < 3; ++j)
799 root 1.80 xfrm.matrix [i][j] = XDoubleToFixed (inv [i][j]);
800 root 1.33
801 root 1.17 XRenderSetPictureFilter (dpy, src, "good", 0, 0);
802 root 1.12 XRenderSetPictureTransform (dpy, src, &xfrm);
803 root 1.91 XRenderComposite (dpy, PictOpSrc, src, None, dst, sx, sy, 0, 0, 0, 0, new_width, new_height);
804 root 1.12
805     XRenderFreePicture (dpy, src);
806     XRenderFreePicture (dpy, dst);
807    
808     return img;
809 root 1.3 }
810    
811     rxvt_img *
812     rxvt_img::scale (int new_width, int new_height)
813     {
814 sf-exg 1.43 if (w == new_width && h == new_height)
815     return clone ();
816    
817 root 1.42 int old_repeat_mode = repeat;
818 sf-exg 1.78 repeat = RepeatPad; // not right, but xrender can't properly scale it seems
819 root 1.42
820 root 1.95 rxvt_img *img = transform (mat3x3::scale (new_width / (nv)w, new_height / (nv)h));
821 root 1.42
822     repeat = old_repeat_mode;
823     img->repeat = repeat;
824    
825     return img;
826 root 1.3 }
827    
828 sf-exg 1.7 rxvt_img *
829 root 1.84 rxvt_img::rotate (int cx, int cy, nv phi)
830 root 1.17 {
831 root 1.91 #if 0
832     { c, -s, cx - c * cx + s * cy },
833 root 1.81 { s, c, cy - s * cx - c * cy },
834 root 1.91 { 0, 0, 1 }
835     #endif
836 root 1.17
837 root 1.91 move (-cx, -cy);
838 root 1.95 rxvt_img *img = transform (mat3x3::rotate (phi));
839 root 1.91 move ( cx, cy);
840     img->move (cx, cy);
841 root 1.80
842     return img;
843 root 1.17 }
844    
845     rxvt_img *
846 root 1.82 rxvt_img::convert_format (XRenderPictFormat *new_format, const rgba &bg)
847 sf-exg 1.7 {
848 root 1.32 if (new_format == format)
849     return clone ();
850    
851 root 1.45 rxvt_img *img = new rxvt_img (s, new_format, x, y, w, h, repeat);
852 root 1.32 img->alloc ();
853 root 1.9
854 sf-exg 1.7 Display *dpy = s->display->dpy;
855 root 1.85 Picture src = picture ();
856 root 1.8 Picture dst = XRenderCreatePicture (dpy, img->pm, new_format, 0, 0);
857 root 1.27 int op = PictOpSrc;
858 sf-exg 1.7
859 root 1.29 if (format->direct.alphaMask && !new_format->direct.alphaMask)
860 root 1.27 {
861     // does it have to be that complicated
862 root 1.82 XRenderColor rc = { bg.r, bg.g, bg.b, bg.a };
863 root 1.28 XRenderFillRectangle (dpy, PictOpSrc, dst, &rc, 0, 0, w, h);
864 root 1.27
865     op = PictOpOver;
866     }
867    
868     XRenderComposite (dpy, op, src, None, dst, 0, 0, 0, 0, 0, 0, w, h);
869 sf-exg 1.7
870     XRenderFreePicture (dpy, src);
871     XRenderFreePicture (dpy, dst);
872    
873     return img;
874     }
875 root 1.3
876 sf-exg 1.24 rxvt_img *
877 root 1.84 rxvt_img::blend (rxvt_img *img, nv factor)
878 sf-exg 1.24 {
879     rxvt_img *img2 = clone ();
880     Display *dpy = s->display->dpy;
881 root 1.85 Picture src = img->picture ();
882 sf-exg 1.24 Picture dst = XRenderCreatePicture (dpy, img2->pm, img2->format, 0, 0);
883 sf-exg 1.75 Picture mask = create_xrender_mask (dpy, img->pm, False, False);
884 sf-exg 1.24
885     XRenderColor mask_c;
886    
887     mask_c.alpha = float_to_component (factor);
888     mask_c.red =
889     mask_c.green =
890     mask_c.blue = 0;
891     XRenderFillRectangle (dpy, PictOpSrc, mask, &mask_c, 0, 0, 1, 1);
892    
893     XRenderComposite (dpy, PictOpOver, src, mask, dst, 0, 0, 0, 0, 0, 0, w, h);
894    
895     XRenderFreePicture (dpy, src);
896     XRenderFreePicture (dpy, dst);
897     XRenderFreePicture (dpy, mask);
898    
899     return img2;
900     }
901    
902 root 1.1 #endif
903