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.14 by root, Mon Jun 4 15:53:12 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{
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_pixbuf (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} 282}
60 283
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}
70
71static void 284static void
72get_gaussian_kernel (int radius, int width, double *kernel, XFixed *params) 285get_gaussian_kernel (int radius, int width, rxvt_img::nv *kernel, XFixed *params)
73{ 286{
74 double sigma = radius / 2.0; 287 rxvt_img::nv sigma = radius / 2.0;
75 double scale = sqrt (2.0 * M_PI) * sigma; 288 rxvt_img::nv scale = sqrt (2.0 * M_PI) * sigma;
76 double sum = 0.0; 289 rxvt_img::nv sum = 0.0;
77 290
78 for (int i = 0; i < width; i++) 291 for (int i = 0; i < width; i++)
79 { 292 {
80 double x = i - width / 2; 293 rxvt_img::nv x = i - width / 2;
81 kernel[i] = exp (-(x * x) / (2.0 * sigma * sigma)) / scale; 294 kernel[i] = exp (-(x * x) / (2.0 * sigma * sigma)) / scale;
82 sum += kernel[i]; 295 sum += kernel[i];
83 } 296 }
84 297
85 params[0] = XDoubleToFixed (width); 298 params[0] = XDoubleToFixed (width);
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 nv *kernel = (nv *)malloc (size * sizeof (nv));
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 }
202
203bool
204rxvt_img::render_pixbuf (GdkPixbuf *pixbuf, int src_x, int src_y, int width, int height, int dst_x, int dst_y)
205{
206 bool argb = format->id == PictStandardARGB32;
207
208 Display *dpy = s->display->dpy;
209
210 if (s->visual->c_class != TrueColor)
211 return false;
212
213 uint32_t red_mask, green_mask, blue_mask, alpha_mask;
214
215 if (argb)
216 { 469 }
217 red_mask = 0xff << 16; 470
218 green_mask = 0xff << 8; 471 XRenderFreePicture (dpy, mul);
219 blue_mask = 0xff; 472 XRenderFreePicture (dpy, dst);
220 alpha_mask = 0xff << 24; 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);
221 } 511 }
222 else 512 else
223 { 513 XRenderComposite (dpy, PictOpSrc, src, None, dst, x, y, 0, 0, 0, 0, w, h);
224 red_mask = s->visual->red_mask; 514
225 green_mask = s->visual->green_mask; 515 XRenderFreePicture (dpy, src);
226 blue_mask = s->visual->blue_mask; 516 XRenderFreePicture (dpy, dst);
227 alpha_mask = (uint32_t)format->direct.alphaMask << format->direct.alpha; 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)
228 } 530 {
531 img->w = width;
532 img->h = height;
229 533
230 int width_r = ecb_popcount32 (red_mask); 534 rxvt_img *img2 = img->reify ();
231 int width_g = ecb_popcount32 (green_mask); 535 delete img;
232 int width_b = ecb_popcount32 (blue_mask); 536 img = img2;
233 int width_a = ecb_popcount32 (alpha_mask);
234
235 if (width_r > 8 || width_g > 8 || width_b > 8 || width_a > 8)
236 return false;
237
238 int sh_r = ecb_ctz32 (red_mask);
239 int sh_g = ecb_ctz32 (green_mask);
240 int sh_b = ecb_ctz32 (blue_mask);
241 int sh_a = ecb_ctz32 (alpha_mask);
242
243 if (width > 32767 || height > 32767)
244 return false;
245
246 XImage *ximage = XCreateImage (dpy, s->visual, argb ? 32 : format->depth, ZPixmap, 0, 0,
247 width, height, 32, 0);
248 if (!ximage)
249 return false;
250
251 if (height > INT_MAX / ximage->bytes_per_line
252 || !(ximage->data = (char *)malloc (height * ximage->bytes_per_line)))
253 { 537 }
254 XDestroyImage (ximage); 538
255 return false; 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)
256 } 584 {
257 585 nv v;
258 GC gc = XCreateGC (dpy, pm, 0, 0); 586 v = mat_apply (matrix, i, 0, 0); rmin [i] = rmax [i] = v; d [i] = v;
259 587 v = mat_apply (matrix, i, w, 0); min_it (rmin [i], v); max_it (rmax [i], v);
260 ximage->byte_order = ecb_big_endian () ? MSBFirst : LSBFirst; 588 v = mat_apply (matrix, i, 0, h); min_it (rmin [i], v); max_it (rmax [i], v);
261 589 v = mat_apply (matrix, i, w, h); min_it (rmin [i], v); max_it (rmax [i], v);
262 int rowstride = gdk_pixbuf_get_rowstride (pixbuf);
263 int channels = gdk_pixbuf_get_n_channels (pixbuf);
264 unsigned char *row = gdk_pixbuf_get_pixels (pixbuf) + src_y * rowstride + src_x * channels;
265 char *line = ximage->data;
266
267 rgba c (0, 0, 0);
268
269 if (channels == 4 && alpha_mask == 0)
270 { 590 }
271 //pix_colors[Color_bg].get (c);
272 //TODO
273 c.r >>= 8;
274 c.g >>= 8;
275 c.b >>= 8;
276 }
277 591
278 for (int y = 0; y < height; y++) 592 int dx = floor (rmin [0]);
279 { 593 int dy = floor (rmin [1]);
280 for (int x = 0; x < width; x++)
281 {
282 unsigned char *pixel = row + x * channels;
283 uint32_t value;
284 unsigned char r, g, b, a;
285 594
286 if (channels == 4) 595 int new_width = ceil (rmax [0] - dx);
287 { 596 int new_height = ceil (rmax [1] - dy);
288 a = pixel[3];
289 r = (pixel[0] * a + c.r * (0xff - a)) / 0xff;
290 g = (pixel[1] * a + c.g * (0xff - a)) / 0xff;
291 b = (pixel[2] * a + c.b * (0xff - a)) / 0xff;
292 }
293 else
294 {
295 a = 0xff;
296 r = pixel[0];
297 g = pixel[1];
298 b = pixel[2];
299 }
300 597
301 value = ((r >> (8 - width_r)) << sh_r) 598 nv inv[3][3];
302 | ((g >> (8 - width_g)) << sh_g) 599 mat_invert (matrix, inv);
303 | ((b >> (8 - width_b)) << sh_b)
304 | ((a >> (8 - width_a)) << sh_a);
305 600
306 if (ximage->bits_per_pixel == 32)
307 ((uint32_t *)line)[x] = value;
308 else
309 XPutPixel (ximage, x, y, value);
310 }
311
312 row += rowstride;
313 line += ximage->bytes_per_line;
314 }
315
316 XPutImage (dpy, pm, gc, ximage, 0, 0, dst_x, dst_y, width, height);
317 XDestroyImage (ximage);
318 XFreeGC (dpy, gc);
319
320 return true;
321}
322
323rxvt_img *
324rxvt_img::clone ()
325{
326 GC gc = XCreateGC (s->display->dpy, pm, 0, 0);
327 Pixmap pm2 = XCreatePixmap (s->display->dpy, pm, w, h, format->depth);
328 XCopyArea (s->display->dpy, pm, pm2, gc, 0, 0, w, h, 0, 0);
329 XFreeGC (s->display->dpy, gc);
330 return new rxvt_img (s, format, w, h, pm2);
331}
332
333rxvt_img *
334rxvt_img::transform (int new_width, int new_height, int repeat, double matrix[9])
335{
336 rxvt_img *img = new rxvt_img (s, format, new_width, new_height); 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 ();
337 603
338 Display *dpy = s->display->dpy; 604 Display *dpy = s->display->dpy;
339 XRenderPictureAttributes pa; 605 Picture src = src_picture ();
340 pa.repeat = repeat;
341 Picture src = XRenderCreatePicture (dpy, pm, format, CPRepeat, &pa);
342 Picture dst = XRenderCreatePicture (dpy, img->pm, img->format, 0, 0); 606 Picture dst = XRenderCreatePicture (dpy, img->pm, img->format, 0, 0);
343 607
344 XTransform xfrm; 608 XTransform xfrm;
345 609
346 for (int i = 0; i < 3; ++i) 610 for (int i = 0; i < 3; ++i)
347 for (int j = 0; j < 3; ++j) 611 for (int j = 0; j < 3; ++j)
348 xfrm.matrix [i][j] = XDoubleToFixed (matrix [i * 3 + j]); 612 xfrm.matrix [i][j] = XDoubleToFixed (inv [i][j]);
349 613
614 XRenderSetPictureFilter (dpy, src, "good", 0, 0);
350 XRenderSetPictureTransform (dpy, src, &xfrm); 615 XRenderSetPictureTransform (dpy, src, &xfrm);
351 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);
352 617
353 XRenderFreePicture (dpy, src); 618 XRenderFreePicture (dpy, src);
354 XRenderFreePicture (dpy, dst); 619 XRenderFreePicture (dpy, dst);
355 620
356 return img; 621 return img;
357} 622}
358 623
359rxvt_img * 624rxvt_img *
360rxvt_img::scale (int new_width, int new_height) 625rxvt_img::scale (int new_width, int new_height)
361{ 626{
362 double matrix[9] = { 627 if (w == new_width && h == new_height)
628 return clone ();
629
630 nv matrix[3][3] = {
363 new_width / (double)w, 0, 0, 631 { new_width / (nv)w, 0, 0 },
364 0, new_height / (double)h, 0, 632 { 0, new_height / (nv)h, 0 },
365 0, 0, 1 633 { 0, 0, 1 }
366 }; 634 };
367 635
368 return transform (new_width, new_height, RepeatNormal, matrix); 636 int old_repeat_mode = repeat;
369} 637 repeat = RepeatPad; // not right, but xrender can't properly scale it seems
370 638
639 rxvt_img *img = transform (matrix);
640
641 repeat = old_repeat_mode;
642 img->repeat = repeat;
643
644 return img;
645}
646
371rxvt_img * 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 *
372rxvt_img::convert_to (XRenderPictFormat *new_format) 671rxvt_img::convert_format (XRenderPictFormat *new_format, const rgba &bg)
373{ 672{
673 if (new_format == format)
674 return clone ();
675
374 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 ();
375 678
376 Display *dpy = s->display->dpy; 679 Display *dpy = s->display->dpy;
377 Picture src = XRenderCreatePicture (dpy, pm, format, 0, 0); 680 Picture src = src_picture ();
378 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;
379 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
380 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);
381 694
382 XRenderFreePicture (dpy, src); 695 XRenderFreePicture (dpy, src);
383 XRenderFreePicture (dpy, dst); 696 XRenderFreePicture (dpy, dst);
384 697
385 return img; 698 return img;
386} 699}
387 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
388#endif 727#endif
389 728

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines