ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/rxvt-unicode/src/rxvtimg.C
(Generate patch)

Comparing rxvt-unicode/src/rxvtimg.C (file contents):
Revision 1.6 by sf-exg, Sun Jun 3 18:49:55 2012 UTC vs.
Revision 1.82 by root, Thu Jun 14 17:06:57 2012 UTC

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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines