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.12 by root, Mon Jun 4 15:28:49 2012 UTC vs.
Revision 1.83 by root, Thu Jun 14 18:06:15 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) 7static XRenderPictFormat *
8find_alpha_format_for (Display *dpy, XRenderPictFormat *format)
9{
10 if (format->direct.alphaMask)
11 return format; // already has alpha
8 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
9rxvt_img::rxvt_img (rxvt_screen *screen, XRenderPictFormat *format, int width, int height) 27rxvt_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) 28: s(screen), x(x), y(y), w(width), h(height), format(format), repeat(repeat),
29 pm(0), ref(0)
17{ 30{
31}
32
33rxvt_img::rxvt_img (const rxvt_img &img)
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{
36 ++ref->cnt;
37}
38
39rxvt_img *
40rxvt_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 0,
62 0,
63 root_pm_w,
64 root_pm_h
65 );
66
67 img->pm = root_pixmap;
68 img->ref = new pixref (root_pm_w, root_pm_h);
69 img->ref->ours = false;
70
71 return img;
72}
73
74# if HAVE_PIXBUF
75
76rxvt_img *
77rxvt_img::new_from_pixbuf (rxvt_screen *s, GdkPixbuf *pb)
78{
79 Display *dpy = s->display->dpy;
80
81 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 int byte_order = ecb_big_endian () ? MSBFirst : LSBFirst;
91
92 XImage xi;
93
94 xi.width = width;
95 xi.height = height;
96 xi.xoffset = 0;
97 xi.format = ZPixmap;
98 xi.byte_order = ImageByteOrder (dpy);
99 xi.bitmap_unit = 0; //XY only, unused
100 xi.bitmap_bit_order = 0; //XY only, unused
101 xi.bitmap_pad = BitmapPad (dpy);
102 xi.depth = 32;
103 xi.bytes_per_line = 0;
104 xi.bits_per_pixel = 32; //Z only
105 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
110 bool byte_order_mismatch = byte_order != xi.byte_order;
111
112 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 bool pb_has_alpha = gdk_pixbuf_get_has_alpha (pb);
122 unsigned char *row = gdk_pixbuf_get_pixels (pb);
123
124 char *line = xi.data;
125
126 for (int y = 0; y < height; y++)
127 {
128 unsigned char *src = row;
129 uint32_t *dst = (uint32_t *)line;
130
131 if (!pb_has_alpha)
132 for (int x = 0; x < width; x++)
133 {
134 uint8_t r = *src++;
135 uint8_t g = *src++;
136 uint8_t b = *src++;
137
138 uint32_t v = (255 << 24) | (r << 16) | (g << 8) | b;
139
140 if (ecb_big_endian () ? !byte_order_mismatch : byte_order_mismatch)
141 v = ecb_bswap32 (v);
142
143 *dst++ = v;
144 }
145 else
146 for (int x = 0; x < width; x++)
147 {
148 uint32_t v = *(uint32_t *)src; src += 4;
149
150 if (ecb_big_endian ())
151 v = ecb_bswap32 (v);
152
153 v = ecb_rotl32 (v, 8); // abgr to bgra
154
155 if (!byte_order_mismatch)
156 v = ecb_bswap32 (v);
157
158 *dst++ = v;
159 }
160
161 row += rowstride;
162 line += xi.bytes_per_line;
163 }
164
165 rxvt_img *img = new rxvt_img (s, XRenderFindStandardFormat (dpy, PictStandardARGB32), 0, 0, width, height);
166 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;
18} 175}
19 176
20rxvt_img * 177rxvt_img *
21rxvt_img::new_from_file (rxvt_screen *s, const char *filename) 178rxvt_img::new_from_file (rxvt_screen *s, const char *filename)
22{ 179{
24 GdkPixbuf *pb = gdk_pixbuf_new_from_file (filename, &err); 181 GdkPixbuf *pb = gdk_pixbuf_new_from_file (filename, &err);
25 182
26 if (!pb) 183 if (!pb)
27 rxvt_fatal ("rxvt_img::new_from_file: %s\n", err->message); 184 rxvt_fatal ("rxvt_img::new_from_file: %s\n", err->message);
28 185
29 rxvt_img *img = new rxvt_img ( 186 rxvt_img *img = new_from_pixbuf (s, pb);
30 s,
31 XRenderFindStandardFormat (s->display->dpy, gdk_pixbuf_get_has_alpha (pb) ? PictStandardARGB32 : PictStandardRGB24),
32 gdk_pixbuf_get_width (pb),
33 gdk_pixbuf_get_height (pb)
34 );
35 187
36 img->render (pb, 0, 0, img->w, img->h, 0, 0); 188 g_object_unref (pb);
37 189
190 return img;
191}
192
193# endif
194
195void
196rxvt_img::destroy ()
197{
198 if (--ref->cnt)
38 return img; 199 return;
200
201 if (pm && ref->ours)
202 XFreePixmap (s->display->dpy, pm);
203
204 delete ref;
39} 205}
40 206
41rxvt_img::~rxvt_img () 207rxvt_img::~rxvt_img ()
42{ 208{
43 if (!shared) 209 destroy ();
44 XFreePixmap (s->display->dpy, pm); 210}
211
212void
213rxvt_img::alloc ()
214{
215 pm = XCreatePixmap (s->display->dpy, s->display->root, w, h, format->depth);
216 ref = new pixref (w, h);
217}
218
219Picture
220rxvt_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;
45} 229}
46 230
47void 231void
48rxvt_img::unshare () 232rxvt_img::unshare ()
49{ 233{
50 if (!shared) 234 if (ref->cnt == 1 && ref->ours)
51 return; 235 return;
52 236
53 rxvt_img *img = clone (); 237 Pixmap pm2 = XCreatePixmap (s->display->dpy, s->display->root, ref->w, ref->h, format->depth);
238 GC gc = XCreateGC (s->display->dpy, pm, 0, 0);
239 XCopyArea (s->display->dpy, pm, pm2, gc, 0, 0, ref->w, ref->h, 0, 0);
240 XFreeGC (s->display->dpy, gc);
54 241
55 ::swap (pm , img->pm); 242 destroy ();
56 ::swap (shared, img->shared); 243
244 pm = pm2;
245 ref = new pixref (ref->w, ref->h);
246}
247
248void
249rxvt_img::fill (const rgba &c)
250{
251 XRenderColor rc = { c.r, c.g, c.b, c.a };
252
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}
258
259void
260rxvt_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 );
57 280
58 delete img; 281 delete img;
59}
60
61void
62rxvt_img::fill (const rxvt_color &c)
63{
64 XGCValues gcv;
65 gcv.foreground = c;
66 GC gc = XCreateGC (s->display->dpy, pm, GCForeground, &gcv);
67 XFillRectangle (s->display->dpy, pm, gc, 0, 0, w, h);
68 XFreeGC (s->display->dpy, gc);
69} 282}
70 283
71static void 284static void
72get_gaussian_kernel (int radius, int width, double *kernel, XFixed *params) 285get_gaussian_kernel (int radius, int width, double *kernel, XFixed *params)
73{ 286{
87 300
88 for (int i = 0; i < width; i++) 301 for (int i = 0; i < width; i++)
89 params[i+2] = XDoubleToFixed (kernel[i] / sum); 302 params[i+2] = XDoubleToFixed (kernel[i] / sum);
90} 303}
91 304
92void 305rxvt_img *
93rxvt_img::blur (int rh, int rv) 306rxvt_img::blur (int rh, int rv)
94{ 307{
95 if (!(s->display->flags & DISPLAY_HAS_RENDER_CONV)) 308 if (!(s->display->flags & DISPLAY_HAS_RENDER_CONV))
96 return; 309 return clone ();
97 310
98 Display *dpy = s->display->dpy; 311 Display *dpy = s->display->dpy;
99 int size = max (rh, rv) * 2 + 1; 312 int size = max (rh, rv) * 2 + 1;
100 double *kernel = (double *)malloc (size * sizeof (double)); 313 double *kernel = (double *)malloc (size * sizeof (double));
101 XFixed *params = (XFixed *)malloc ((size + 2) * sizeof (XFixed)); 314 XFixed *params = (XFixed *)malloc ((size + 2) * sizeof (XFixed));
315 rxvt_img *img = new rxvt_img (s, format, x, y, w, h, repeat);
316 img->alloc ();
102 317
103 XRenderPictureAttributes pa; 318 XRenderPictureAttributes pa;
104
105 pa.repeat = RepeatPad; 319 pa.repeat = RepeatPad;
106 Picture src = XRenderCreatePicture (dpy, pm, format, CPRepeat, &pa); 320 Picture src = XRenderCreatePicture (dpy, pm, format, CPRepeat, &pa);
321 Picture dst = XRenderCreatePicture (dpy, img->pm, format, 0, 0);
322
107 Pixmap tmp = XCreatePixmap (dpy, pm, w, h, format->depth); 323 Pixmap tmp_pm = XCreatePixmap (dpy, pm, w, h, format->depth);
108 Picture dst = XRenderCreatePicture (dpy, tmp, format, CPRepeat, &pa); 324 Picture tmp = XRenderCreatePicture (dpy, tmp_pm , format, CPRepeat, &pa);
109 XFreePixmap (dpy, tmp); 325 XFreePixmap (dpy, tmp_pm);
110 326
111 if (kernel && params) 327 if (kernel && params)
112 { 328 {
113 size = rh * 2 + 1; 329 size = rh * 2 + 1;
114 get_gaussian_kernel (rh, size, kernel, params); 330 get_gaussian_kernel (rh, size, kernel, params);
115 331
116 XRenderSetPictureFilter (dpy, src, FilterConvolution, params, size+2); 332 XRenderSetPictureFilter (dpy, src, FilterConvolution, params, size+2);
117 XRenderComposite (dpy, 333 XRenderComposite (dpy,
118 PictOpSrc, 334 PictOpSrc,
119 src, 335 src,
336 None,
337 tmp,
338 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 XRenderSetPictureFilter (dpy, tmp, FilterConvolution, params, size+2);
348 XRenderComposite (dpy,
349 PictOpSrc,
350 tmp,
120 None, 351 None,
121 dst, 352 dst,
122 0, 0, 353 0, 0,
123 0, 0, 354 0, 0,
124 0, 0, 355 0, 0,
125 w, h); 356 w, h);
126
127 ::swap (src, dst);
128
129 size = rv * 2 + 1;
130 get_gaussian_kernel (rv, size, kernel, params);
131 ::swap (params[0], params[1]);
132
133 XRenderSetPictureFilter (dpy, src, FilterConvolution, params, size+2);
134 XRenderComposite (dpy,
135 PictOpSrc,
136 src,
137 None,
138 dst,
139 0, 0,
140 0, 0,
141 0, 0,
142 w, h);
143 } 357 }
144 358
145 free (kernel); 359 free (kernel);
146 free (params); 360 free (params);
361
147 XRenderFreePicture (dpy, src); 362 XRenderFreePicture (dpy, src);
148 XRenderFreePicture (dpy, dst); 363 XRenderFreePicture (dpy, dst);
364 XRenderFreePicture (dpy, tmp);
365
366 return img;
149} 367}
150 368
151static Picture 369static Picture
152create_xrender_mask (Display *dpy, Drawable drawable, Bool argb) 370create_xrender_mask (Display *dpy, Drawable drawable, Bool argb, Bool component_alpha)
153{ 371{
154 Pixmap pixmap = XCreatePixmap (dpy, drawable, 1, 1, argb ? 32 : 8); 372 Pixmap pixmap = XCreatePixmap (dpy, drawable, 1, 1, argb ? 32 : 8);
155 373
156 XRenderPictFormat *format = XRenderFindStandardFormat (dpy, argb ? PictStandardARGB32 : PictStandardA8); 374 XRenderPictFormat *format = XRenderFindStandardFormat (dpy, argb ? PictStandardARGB32 : PictStandardA8);
157 XRenderPictureAttributes pa; 375 XRenderPictureAttributes pa;
158 pa.repeat = True; 376 pa.repeat = RepeatNormal;
377 pa.component_alpha = component_alpha;
159 Picture mask = XRenderCreatePicture (dpy, pixmap, format, CPRepeat, &pa); 378 Picture mask = XRenderCreatePicture (dpy, pixmap, format, CPRepeat | CPComponentAlpha, &pa);
160 379
161 XFreePixmap (dpy, pixmap); 380 XFreePixmap (dpy, pixmap);
162 381
163 return mask; 382 return mask;
164} 383}
165 384
385static void
386extract (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
393static bool
394extract (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
166void 404void
167rxvt_img::brightness (double r, double g, double b, double a) 405rxvt_img::brightness (int32_t r, int32_t g, int32_t b, int32_t a)
168{ 406{
407 unshare ();
408
169 Display *dpy = s->display->dpy; 409 Display *dpy = s->display->dpy;
170 Picture src = create_xrender_mask (dpy, pm, True);
171 Picture dst = XRenderCreatePicture (dpy, pm, format, 0, 0); 410 Picture dst = XRenderCreatePicture (dpy, pm, format, 0, 0);
172 411
412 // loop should not be needed for brightness, as only -1..1 makes sense
413 //while (r | g | b | a)
414 {
415 unsigned short xr, xg, xb, xa;
173 XRenderColor mask_c; 416 XRenderColor mask_c;
174 mask_c.red = float_to_component (r); 417
175 mask_c.green = float_to_component (g); 418 if (extract (0, 65535, r, g, b, a, mask_c.red, mask_c.green, mask_c.blue, mask_c.alpha))
176 mask_c.blue = float_to_component (b);
177 mask_c.alpha = float_to_component (a);
178 XRenderFillRectangle (dpy, PictOpSrc, src, &mask_c, 0, 0, 1, 1); 419 XRenderFillRectangle (dpy, PictOpAdd, dst, &mask_c, 0, 0, w, h);
179 420
180 XRenderComposite (dpy, PictOpAdd, src, None, dst, 0, 0, 0, 0, 0, 0, w, h); 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 mask_c.red = -mask_c.red; //TODO: verify that doing clamp, assign, and negation does the right thing
426 mask_c.green = -mask_c.green;
427 mask_c.blue = -mask_c.blue;
428 mask_c.alpha = -mask_c.alpha;
429 XRenderFillRectangle (dpy, PictOpAdd, dst, &mask_c, 0, 0, w, h);
430 XRenderFillRectangle (dpy, PictOpDifference, dst, &mask_w, 0, 0, w, h);
431 }
432 }
433
434 XRenderFreePicture (dpy, dst);
181} 435}
182 436
183void 437void
184rxvt_img::contrast (double r, double g, double b, double a) 438rxvt_img::contrast (int32_t r, int32_t g, int32_t b, int32_t a)
185{ 439{
186 if (!(s->display->flags & DISPLAY_HAS_RENDER_MUL)) 440 if (r < 0 || g < 0 || b < 0 || a < 0)
187 return; 441 rxvt_fatal ("rxvt_img::contrast does not support negative values.\n");
188 442
443 rxvt_img *img = new rxvt_img (s, format, x, y, w, h, repeat);
444 img->alloc ();
445 img->fill (rgba (0, 0, 0, 0));
446
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
189 Display *dpy = s->display->dpy; 452 Display *dpy = s->display->dpy;
190 Picture src = create_xrender_mask (dpy, pm, True); 453
454 Picture src = src_picture ();
191 Picture dst = XRenderCreatePicture (dpy, pm, format, 0, 0); 455 Picture dst = XRenderCreatePicture (dpy, img->pm, format, 0, 0);
456 Picture mul = create_xrender_mask (dpy, pm, True, True);
192 457
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;
193 XRenderColor mask_c; 462 XRenderColor mask_c;
194 mask_c.red = float_to_component (r); 463
195 mask_c.green = float_to_component (g); 464 if (extract (0, 65535, r, g, b, a, mask_c.red, mask_c.green, mask_c.blue, mask_c.alpha))
196 mask_c.blue = float_to_component (b); 465 {
197 mask_c.alpha = float_to_component (a);
198 XRenderFillRectangle (dpy, PictOpSrc, src, &mask_c, 0, 0, 1, 1); 466 XRenderFillRectangle (dpy, PictOpSrc, mul, &mask_c, 0, 0, 1, 1);
199
200 XRenderComposite (dpy, PictOpMultiply, src, None, dst, 0, 0, 0, 0, 0, 0, w, h); 467 XRenderComposite (dpy, PictOpAdd, src, mul, dst, 0, 0, 0, 0, 0, 0, w, h);
201} 468 }
469 }
202 470
203void 471 XRenderFreePicture (dpy, mul);
204rxvt_img::render (GdkPixbuf *pixbuf, int src_x, int src_y, int width, int height, int dst_x, int dst_y) 472 XRenderFreePicture (dpy, dst);
205{ 473 XRenderFreePicture (dpy, src);
206 //TODO 474
475 ::swap (img->ref, ref);
476 ::swap (img->pm , pm );
477
478 delete img;
207} 479}
208 480
209rxvt_img * 481rxvt_img *
210rxvt_img::clone () 482rxvt_img::clone ()
211{ 483{
212 GC gc = XCreateGC (s->display->dpy, pm, 0, 0); 484 return new rxvt_img (*this);
213 Pixmap pm2 = XCreatePixmap (s->display->dpy, pm, w, h, format->depth);
214 XCopyArea (s->display->dpy, pm, pm2, gc, 0, 0, w, h, 0, 0);
215 XFreeGC (s->display->dpy, gc);
216 return new rxvt_img (s, format, w, h, pm2);
217} 485}
218 486
219rxvt_img * 487rxvt_img *
220rxvt_img::transform (int new_width, int new_height, int repeat, double matrix[9]) 488rxvt_img::reify ()
221{ 489{
222 rxvt_img *img = new rxvt_img (s, format, new_width, new_height); 490 if (x == 0 && y == 0 && w == ref->w && h == ref->h)
491 return clone ();
223 492
224 Display *dpy = s->display->dpy; 493 Display *dpy = s->display->dpy;
494
495 // 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
500 rxvt_img *img = new rxvt_img (s, alpha ? find_alpha_format_for (dpy, format) : format, 0, 0, w, h, repeat);
501 img->alloc ();
502
503 Picture src = src_picture ();
225 Picture src = XRenderCreatePicture (dpy, pm, format, 0, 0); 504 Picture dst = XRenderCreatePicture (dpy, img->pm, img->format, 0, 0);
505
506 if (alpha)
507 {
508 XRenderColor rc = { 0, 0, 0, 0 };
509 XRenderFillRectangle (dpy, PictOpSrc, dst, &rc, 0, 0, w, h);//TODO: split into four fillrectangles
510 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 XRenderFreePicture (dpy, src);
516 XRenderFreePicture (dpy, dst);
517
518 return img;
519}
520
521rxvt_img *
522rxvt_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
529 if (w != width || h != height)
530 {
531 img->w = width;
532 img->h = height;
533
534 rxvt_img *img2 = img->reify ();
535 delete img;
536 img = img2;
537 }
538
539 return img;
540}
541
542static void
543mat_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
564static double
565mat_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
573rxvt_img *
574rxvt_img::transform (double matrix[3][3])
575{
576 // 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 double d [2], rmin[2], rmax[2];
582
583 for (int i = 0; i < 2; ++i)
584 {
585 double v;
586 v = mat_apply (matrix, i, 0, 0); rmin [i] = rmax [i] = v; d [i] = v;
587 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 rxvt_img *img = new rxvt_img (s, format, ox - dx - d [0], oy - dy - d [1], new_width, new_height, repeat);
602 img->alloc ();
603
604 Display *dpy = s->display->dpy;
605 Picture src = src_picture ();
226 Picture dst = XRenderCreatePicture (dpy, img->pm, img->format, 0, 0); 606 Picture dst = XRenderCreatePicture (dpy, img->pm, img->format, 0, 0);
227 607
228 XTransform xfrm; 608 XTransform xfrm;
229 609
230 for (int i = 0; i < 3; ++i) 610 for (int i = 0; i < 3; ++i)
231 for (int j = 0; j < 3; ++j) 611 for (int j = 0; j < 3; ++j)
232 xfrm.matrix [i][j] = XDoubleToFixed (matrix [i * 3 + j]); 612 xfrm.matrix [i][j] = XDoubleToFixed (inv [i][j]);
233 613
614 XRenderSetPictureFilter (dpy, src, "good", 0, 0);
234 XRenderSetPictureTransform (dpy, src, &xfrm); 615 XRenderSetPictureTransform (dpy, src, &xfrm);
235 XRenderComposite (dpy, PictOpSrc, src, None, dst, 0, 0, 0, 0, 0, 0, new_width, new_height); 616 XRenderComposite (dpy, PictOpSrc, src, None, dst, dx, dy, 0, 0, 0, 0, new_width, new_height);
236 617
237 XRenderFreePicture (dpy, src); 618 XRenderFreePicture (dpy, src);
238 XRenderFreePicture (dpy, dst); 619 XRenderFreePicture (dpy, dst);
239 620
240 return img; 621 return img;
241} 622}
242 623
243rxvt_img * 624rxvt_img *
244rxvt_img::scale (int new_width, int new_height) 625rxvt_img::scale (int new_width, int new_height)
245{ 626{
627 if (w == new_width && h == new_height)
628 return clone ();
629
246 double matrix[9] = { 630 double matrix[3][3] = {
247 new_width / (double)w, 0, 0, 631 { new_width / (double)w, 0, 0 },
248 0, new_height / (double)h, 0, 632 { 0, new_height / (double)h, 0 },
249 0, 0, 1 633 { 0, 0, 1 }
250 }; 634 };
251 635
252 return transform (new_width, new_height, RepeatNormal, matrix); 636 int old_repeat_mode = repeat;
253} 637 repeat = RepeatPad; // not right, but xrender can't properly scale it seems
254 638
639 rxvt_img *img = transform (matrix);
640
641 repeat = old_repeat_mode;
642 img->repeat = repeat;
643
644 return img;
645}
646
255rxvt_img * 647rxvt_img *
648rxvt_img::rotate (int cx, int cy, double phi)
649{
650 double s = sin (phi);
651 double c = cos (phi);
652
653 double matrix[3][3] = {
654 { 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 };
661
662 //move (-cx, -cy);
663 rxvt_img *img = transform (matrix);
664 //move ( cx, cy);
665 //img->move (cx, cy);
666
667 return img;
668}
669
670rxvt_img *
256rxvt_img::convert_to (XRenderPictFormat *new_format) 671rxvt_img::convert_format (XRenderPictFormat *new_format, const rgba &bg)
257{ 672{
673 if (new_format == format)
674 return clone ();
675
258 rxvt_img *img = new rxvt_img (s, new_format, w, h); 676 rxvt_img *img = new rxvt_img (s, new_format, x, y, w, h, repeat);
677 img->alloc ();
259 678
260 Display *dpy = s->display->dpy; 679 Display *dpy = s->display->dpy;
261 Picture src = XRenderCreatePicture (dpy, pm, format, 0, 0); 680 Picture src = src_picture ();
262 Picture dst = XRenderCreatePicture (dpy, img->pm, new_format, 0, 0); 681 Picture dst = XRenderCreatePicture (dpy, img->pm, new_format, 0, 0);
682 int op = PictOpSrc;
263 683
684 if (format->direct.alphaMask && !new_format->direct.alphaMask)
685 {
686 // does it have to be that complicated
687 XRenderColor rc = { bg.r, bg.g, bg.b, bg.a };
688 XRenderFillRectangle (dpy, PictOpSrc, dst, &rc, 0, 0, w, h);
689
690 op = PictOpOver;
691 }
692
264 XRenderComposite (dpy, PictOpSrc, src, None, dst, 0, 0, 0, 0, 0, 0, w, h); 693 XRenderComposite (dpy, op, src, None, dst, 0, 0, 0, 0, 0, 0, w, h);
265 694
266 XRenderFreePicture (dpy, src); 695 XRenderFreePicture (dpy, src);
267 XRenderFreePicture (dpy, dst); 696 XRenderFreePicture (dpy, dst);
268 697
269 return img; 698 return img;
270} 699}
271 700
701rxvt_img *
702rxvt_img::blend (rxvt_img *img, double factor)
703{
704 rxvt_img *img2 = clone ();
705 Display *dpy = s->display->dpy;
706 Picture src = img->src_picture ();
707 Picture dst = XRenderCreatePicture (dpy, img2->pm, img2->format, 0, 0);
708 Picture mask = create_xrender_mask (dpy, img->pm, False, False);
709
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
272#endif 727#endif
273 728

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines