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.9 by root, Sun Jun 3 20:47:00 2012 UTC vs.
Revision 1.84 by root, Thu Jun 14 18:19:11 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{
18} 31}
19 32
20rxvt_img * 33rxvt_img::rxvt_img (const rxvt_img &img)
21rxvt_img::new_from_file (rxvt_screen *s, const char *filename) 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)
22{ 35{
23 GError *err; 36 ++ref->cnt;
24 GdkPixbuf *pb = gdk_pixbuf_new_from_file (filename, &err); 37}
25 38
26 if (!pb) 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))
27 return 0; 56 return 0;
28 57
29 rxvt_img *img = new rxvt_img ( 58 rxvt_img *img = new rxvt_img (
30 s, 59 s,
31 XRenderFindStandardFormat (s->display->dpy, gdk_pixbuf_get_has_alpha (pb) ? PictStandardARGB32 : PictStandardRGB24), 60 XRenderFindVisualFormat (dpy, DefaultVisual (dpy, s->display->screen)),
32 gdk_pixbuf_get_width (pb), 61 0,
33 gdk_pixbuf_get_height (pb) 62 0,
63 root_pm_w,
64 root_pm_h
34 ); 65 );
35 66
36 img->render (pb, 0, 0, img->w, img->h, 0, 0); 67 img->pm = root_pixmap;
68 img->ref = new pixref (root_pm_w, root_pm_h);
69 img->ref->ours = false;
37 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;
175}
176
177rxvt_img *
178rxvt_img::new_from_file (rxvt_screen *s, const char *filename)
179{
180 GError *err = 0;
181 GdkPixbuf *pb = gdk_pixbuf_new_from_file (filename, &err);
182
183 if (!pb)
184 rxvt_fatal ("rxvt_img::new_from_file: %s\n", err->message);
185
186 rxvt_img *img = new_from_pixbuf (s, pb);
187
188 g_object_unref (pb);
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);
45} 210}
46 211
47void 212void
48rxvt_img::fill (const rxvt_color &c) 213rxvt_img::alloc ()
49{ 214{
50 XGCValues gcv; 215 pm = XCreatePixmap (s->display->dpy, s->display->root, w, h, format->depth);
51 gcv.foreground = c; 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;
229}
230
231void
232rxvt_img::unshare ()
233{
234 if (ref->cnt == 1 && ref->ours)
235 return;
236
237 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); 238 GC gc = XCreateGC (s->display->dpy, pm, 0, 0);
53 XFillRectangle (s->display->dpy, pm, gc, 0, 0, w, h); 239 XCopyArea (s->display->dpy, pm, pm2, gc, 0, 0, ref->w, ref->h, 0, 0);
54 XFreeGC (s->display->dpy, gc); 240 XFreeGC (s->display->dpy, gc);
241
242 destroy ();
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 );
280
281 delete img;
55} 282}
56 283
57static void 284static void
58get_gaussian_kernel (int radius, int width, double *kernel, XFixed *params) 285get_gaussian_kernel (int radius, int width, rxvt_img::nv *kernel, XFixed *params)
59{ 286{
60 double sigma = radius / 2.0; 287 rxvt_img::nv sigma = radius / 2.0;
61 double scale = sqrt (2.0 * M_PI) * sigma; 288 rxvt_img::nv scale = sqrt (2.0 * M_PI) * sigma;
62 double sum = 0.0; 289 rxvt_img::nv sum = 0.0;
63 290
64 for (int i = 0; i < width; i++) 291 for (int i = 0; i < width; i++)
65 { 292 {
66 double x = i - width / 2; 293 rxvt_img::nv x = i - width / 2;
67 kernel[i] = exp (-(x * x) / (2.0 * sigma * sigma)) / scale; 294 kernel[i] = exp (-(x * x) / (2.0 * sigma * sigma)) / scale;
68 sum += kernel[i]; 295 sum += kernel[i];
69 } 296 }
70 297
71 params[0] = XDoubleToFixed (width); 298 params[0] = XDoubleToFixed (width);
73 300
74 for (int i = 0; i < width; i++) 301 for (int i = 0; i < width; i++)
75 params[i+2] = XDoubleToFixed (kernel[i] / sum); 302 params[i+2] = XDoubleToFixed (kernel[i] / sum);
76} 303}
77 304
78void 305rxvt_img *
79rxvt_img::blur (int rh, int rv) 306rxvt_img::blur (int rh, int rv)
80{ 307{
81 if (!(s->display->flags & DISPLAY_HAS_RENDER_CONV)) 308 if (!(s->display->flags & DISPLAY_HAS_RENDER_CONV))
82 return; 309 return clone ();
83 310
84 Display *dpy = s->display->dpy; 311 Display *dpy = s->display->dpy;
85 int size = max (rh, rv) * 2 + 1; 312 int size = max (rh, rv) * 2 + 1;
86 double *kernel = (double *)malloc (size * sizeof (double)); 313 nv *kernel = (nv *)malloc (size * sizeof (nv));
87 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 ();
88 317
89 XRenderPictureAttributes pa; 318 XRenderPictureAttributes pa;
90
91 pa.repeat = RepeatPad; 319 pa.repeat = RepeatPad;
92 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
93 Pixmap tmp = XCreatePixmap (dpy, pm, w, h, format->depth); 323 Pixmap tmp_pm = XCreatePixmap (dpy, pm, w, h, format->depth);
94 Picture dst = XRenderCreatePicture (dpy, tmp, format, CPRepeat, &pa); 324 Picture tmp = XRenderCreatePicture (dpy, tmp_pm , format, CPRepeat, &pa);
95 XFreePixmap (dpy, tmp); 325 XFreePixmap (dpy, tmp_pm);
96 326
97 if (kernel && params) 327 if (kernel && params)
98 { 328 {
99 size = rh * 2 + 1; 329 size = rh * 2 + 1;
100 get_gaussian_kernel (rh, size, kernel, params); 330 get_gaussian_kernel (rh, size, kernel, params);
101 331
102 XRenderSetPictureFilter (dpy, src, FilterConvolution, params, size+2); 332 XRenderSetPictureFilter (dpy, src, FilterConvolution, params, size+2);
103 XRenderComposite (dpy, 333 XRenderComposite (dpy,
104 PictOpSrc, 334 PictOpSrc,
105 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,
106 None, 351 None,
107 dst, 352 dst,
108 0, 0, 353 0, 0,
109 0, 0, 354 0, 0,
110 0, 0, 355 0, 0,
111 w, h); 356 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 } 357 }
130 358
131 free (kernel); 359 free (kernel);
132 free (params); 360 free (params);
361
133 XRenderFreePicture (dpy, src); 362 XRenderFreePicture (dpy, src);
134 XRenderFreePicture (dpy, dst); 363 XRenderFreePicture (dpy, dst);
364 XRenderFreePicture (dpy, tmp);
365
366 return img;
135} 367}
136 368
137static Picture 369static Picture
138create_xrender_mask (Display *dpy, Drawable drawable, Bool argb) 370create_xrender_mask (Display *dpy, Drawable drawable, Bool argb, Bool component_alpha)
139{ 371{
140 Pixmap pixmap = XCreatePixmap (dpy, drawable, 1, 1, argb ? 32 : 8); 372 Pixmap pixmap = XCreatePixmap (dpy, drawable, 1, 1, argb ? 32 : 8);
141 373
142 XRenderPictFormat *format = XRenderFindStandardFormat (dpy, argb ? PictStandardARGB32 : PictStandardA8); 374 XRenderPictFormat *format = XRenderFindStandardFormat (dpy, argb ? PictStandardARGB32 : PictStandardA8);
143 XRenderPictureAttributes pa; 375 XRenderPictureAttributes pa;
144 pa.repeat = True; 376 pa.repeat = RepeatNormal;
377 pa.component_alpha = component_alpha;
145 Picture mask = XRenderCreatePicture (dpy, pixmap, format, CPRepeat, &pa); 378 Picture mask = XRenderCreatePicture (dpy, pixmap, format, CPRepeat | CPComponentAlpha, &pa);
146 379
147 XFreePixmap (dpy, pixmap); 380 XFreePixmap (dpy, pixmap);
148 381
149 return mask; 382 return mask;
150} 383}
151 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
152void 404void
153rxvt_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)
154{ 406{
407 unshare ();
408
155 Display *dpy = s->display->dpy; 409 Display *dpy = s->display->dpy;
156 Picture src = create_xrender_mask (dpy, pm, True);
157 Picture dst = XRenderCreatePicture (dpy, pm, format, 0, 0); 410 Picture dst = XRenderCreatePicture (dpy, pm, format, 0, 0);
158 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;
159 XRenderColor mask_c; 416 XRenderColor mask_c;
160 mask_c.red = float_to_component (r); 417
161 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))
162 mask_c.blue = float_to_component (b);
163 mask_c.alpha = float_to_component (a);
164 XRenderFillRectangle (dpy, PictOpSrc, src, &mask_c, 0, 0, 1, 1); 419 XRenderFillRectangle (dpy, PictOpAdd, dst, &mask_c, 0, 0, w, h);
165 420
166 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);
167} 435}
168 436
169void 437void
170rxvt_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)
171{ 439{
172 if (!(s->display->flags & DISPLAY_HAS_RENDER_MUL)) 440 if (r < 0 || g < 0 || b < 0 || a < 0)
173 return; 441 rxvt_fatal ("rxvt_img::contrast does not support negative values.\n");
174 442
175 Display *dpy = s->display->dpy;
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}
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
218rxvt_img *
219rxvt_img::convert_to (XRenderPictFormat *new_format)
220{
221 rxvt_img *img = new rxvt_img (s,new_format,w, h); 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));
222 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
223 Display *dpy = s->display->dpy; 452 Display *dpy = s->display->dpy;
224 Picture src = XRenderCreatePicture (dpy, pm, format, 0, 0); 453
454 Picture src = src_picture ();
225 Picture dst = XRenderCreatePicture (dpy, img->pm, new_format, 0, 0); 455 Picture dst = XRenderCreatePicture (dpy, img->pm, format, 0, 0);
456 Picture mul = create_xrender_mask (dpy, pm, True, True);
226 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;
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
471 XRenderFreePicture (dpy, mul);
472 XRenderFreePicture (dpy, dst);
473 XRenderFreePicture (dpy, src);
474
475 ::swap (img->ref, ref);
476 ::swap (img->pm , pm );
477
478 delete img;
479}
480
481rxvt_img *
482rxvt_img::clone ()
483{
484 return new rxvt_img (*this);
485}
486
487rxvt_img *
488rxvt_img::reify ()
489{
490 if (x == 0 && y == 0 && w == ref->w && h == ref->h)
491 return clone ();
492
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 ();
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
227 XRenderComposite (dpy, PictOpSrc, src, None, dst, 0, 0, 0, 0, 0, 0, w, h); 513 XRenderComposite (dpy, PictOpSrc, src, None, dst, x, y, 0, 0, 0, 0, w, h);
228 514
229 XRenderFreePicture (dpy, src); 515 XRenderFreePicture (dpy, src);
230 XRenderFreePicture (dpy, dst); 516 XRenderFreePicture (dpy, dst);
231 517
232 return img; 518 return img;
233} 519}
234 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 (rxvt_img::nv mat[3][3], rxvt_img::nv (&inv)[3][3])
544{
545 rxvt_img::nv s0 = mat [2][2] * mat [1][1] - mat [2][1] * mat [1][2];
546 rxvt_img::nv s1 = mat [2][1] * mat [0][2] - mat [2][2] * mat [0][1];
547 rxvt_img::nv s2 = mat [1][2] * mat [0][1] - mat [1][1] * mat [0][2];
548
549 rxvt_img::nv 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 rxvt_img::nv
565mat_apply (rxvt_img::nv mat[3][3], int i, rxvt_img::nv x, rxvt_img::nv y)
566{
567 rxvt_img::nv v = mat [i][0] * x + mat [i][1] * y + mat [i][2];
568 rxvt_img::nv 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 (nv 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 nv d [2], rmin[2], rmax[2];
582
583 for (int i = 0; i < 2; ++i)
584 {
585 nv 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 nv 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 ();
606 Picture dst = XRenderCreatePicture (dpy, img->pm, img->format, 0, 0);
607
608 XTransform xfrm;
609
610 for (int i = 0; i < 3; ++i)
611 for (int j = 0; j < 3; ++j)
612 xfrm.matrix [i][j] = XDoubleToFixed (inv [i][j]);
613
614 XRenderSetPictureFilter (dpy, src, "good", 0, 0);
615 XRenderSetPictureTransform (dpy, src, &xfrm);
616 XRenderComposite (dpy, PictOpSrc, src, None, dst, dx, dy, 0, 0, 0, 0, new_width, new_height);
617
618 XRenderFreePicture (dpy, src);
619 XRenderFreePicture (dpy, dst);
620
621 return img;
622}
623
624rxvt_img *
625rxvt_img::scale (int new_width, int new_height)
626{
627 if (w == new_width && h == new_height)
628 return clone ();
629
630 nv matrix[3][3] = {
631 { new_width / (nv)w, 0, 0 },
632 { 0, new_height / (nv)h, 0 },
633 { 0, 0, 1 }
634 };
635
636 int old_repeat_mode = repeat;
637 repeat = RepeatPad; // not right, but xrender can't properly scale it seems
638
639 rxvt_img *img = transform (matrix);
640
641 repeat = old_repeat_mode;
642 img->repeat = repeat;
643
644 return img;
645}
646
647rxvt_img *
648rxvt_img::rotate (int cx, int cy, nv phi)
649{
650 nv s = sin (phi);
651 nv c = cos (phi);
652
653 nv 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 *
671rxvt_img::convert_format (XRenderPictFormat *new_format, const rgba &bg)
672{
673 if (new_format == format)
674 return clone ();
675
676 rxvt_img *img = new rxvt_img (s, new_format, x, y, w, h, repeat);
677 img->alloc ();
678
679 Display *dpy = s->display->dpy;
680 Picture src = src_picture ();
681 Picture dst = XRenderCreatePicture (dpy, img->pm, new_format, 0, 0);
682 int op = PictOpSrc;
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
693 XRenderComposite (dpy, op, src, None, dst, 0, 0, 0, 0, 0, 0, w, h);
694
695 XRenderFreePicture (dpy, src);
696 XRenderFreePicture (dpy, dst);
697
698 return img;
699}
700
701rxvt_img *
702rxvt_img::blend (rxvt_img *img, nv 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
235#endif 727#endif
236 728

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines