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.21 by sf-exg, Tue Jun 5 14:59:44 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;
18} 37}
19 38
20rxvt_img * 39rxvt_img *
21rxvt_img::new_from_root (rxvt_screen *s) 40rxvt_img::new_from_root (rxvt_screen *s)
22{ 41{
37 return 0; 56 return 0;
38 57
39 rxvt_img *img = new rxvt_img ( 58 rxvt_img *img = new rxvt_img (
40 s, 59 s,
41 XRenderFindVisualFormat (dpy, DefaultVisual (dpy, s->display->screen)), 60 XRenderFindVisualFormat (dpy, DefaultVisual (dpy, s->display->screen)),
61 0,
62 0,
42 root_pm_w, 63 root_pm_w,
43 root_pm_h, 64 root_pm_h
44 root_pixmap
45 ); 65 );
46 66
47 img->shared = true; 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);
48 173
49 return img; 174 return img;
50} 175}
51 176
52rxvt_img * 177rxvt_img *
56 GdkPixbuf *pb = gdk_pixbuf_new_from_file (filename, &err); 181 GdkPixbuf *pb = gdk_pixbuf_new_from_file (filename, &err);
57 182
58 if (!pb) 183 if (!pb)
59 rxvt_fatal ("rxvt_img::new_from_file: %s\n", err->message); 184 rxvt_fatal ("rxvt_img::new_from_file: %s\n", err->message);
60 185
61 rxvt_img *img = new rxvt_img ( 186 rxvt_img *img = new_from_pixbuf (s, pb);
62 s,
63 XRenderFindStandardFormat (s->display->dpy, gdk_pixbuf_get_has_alpha (pb) ? PictStandardARGB32 : PictStandardRGB24),
64 gdk_pixbuf_get_width (pb),
65 gdk_pixbuf_get_height (pb)
66 );
67 187
68 img->render_pixbuf (pb, 0, 0, img->w, img->h, 0, 0); 188 g_object_unref (pb);
69 189
190 return img;
191}
192
193# endif
194
195void
196rxvt_img::destroy ()
197{
198 if (--ref->cnt)
70 return img; 199 return;
200
201 if (pm && ref->ours)
202 XFreePixmap (s->display->dpy, pm);
203
204 delete ref;
71} 205}
72 206
73rxvt_img::~rxvt_img () 207rxvt_img::~rxvt_img ()
74{ 208{
75 if (!shared) 209 destroy ();
76 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;
77} 229}
78 230
79void 231void
80rxvt_img::unshare () 232rxvt_img::unshare ()
81{ 233{
82 if (!shared) 234 if (ref->cnt == 1 && ref->ours)
83 return; 235 return;
84 236
85 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);
86 241
87 ::swap (pm , img->pm); 242 destroy ();
88 ::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 );
89 280
90 delete img; 281 delete img;
91}
92
93void
94rxvt_img::fill (const rxvt_color &c)
95{
96 XGCValues gcv;
97 gcv.foreground = c;
98 GC gc = XCreateGC (s->display->dpy, pm, GCForeground, &gcv);
99 XFillRectangle (s->display->dpy, pm, gc, 0, 0, w, h);
100 XFreeGC (s->display->dpy, gc);
101} 282}
102 283
103static void 284static void
104get_gaussian_kernel (int radius, int width, double *kernel, XFixed *params) 285get_gaussian_kernel (int radius, int width, double *kernel, XFixed *params)
105{ 286{
119 300
120 for (int i = 0; i < width; i++) 301 for (int i = 0; i < width; i++)
121 params[i+2] = XDoubleToFixed (kernel[i] / sum); 302 params[i+2] = XDoubleToFixed (kernel[i] / sum);
122} 303}
123 304
124void 305rxvt_img *
125rxvt_img::blur (int rh, int rv) 306rxvt_img::blur (int rh, int rv)
126{ 307{
127 if (!(s->display->flags & DISPLAY_HAS_RENDER_CONV)) 308 if (!(s->display->flags & DISPLAY_HAS_RENDER_CONV))
128 return; 309 return clone ();
129 310
130 Display *dpy = s->display->dpy; 311 Display *dpy = s->display->dpy;
131 int size = max (rh, rv) * 2 + 1; 312 int size = max (rh, rv) * 2 + 1;
132 double *kernel = (double *)malloc (size * sizeof (double)); 313 double *kernel = (double *)malloc (size * sizeof (double));
133 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 ();
134 317
135 XRenderPictureAttributes pa; 318 XRenderPictureAttributes pa;
136
137 pa.repeat = RepeatPad; 319 pa.repeat = RepeatPad;
138 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
139 Pixmap tmp = XCreatePixmap (dpy, pm, w, h, format->depth); 323 Pixmap tmp_pm = XCreatePixmap (dpy, pm, w, h, format->depth);
140 Picture dst = XRenderCreatePicture (dpy, tmp, format, CPRepeat, &pa); 324 Picture tmp = XRenderCreatePicture (dpy, tmp_pm , format, CPRepeat, &pa);
141 XFreePixmap (dpy, tmp); 325 XFreePixmap (dpy, tmp_pm);
142 326
143 if (kernel && params) 327 if (kernel && params)
144 { 328 {
145 size = rh * 2 + 1; 329 size = rh * 2 + 1;
146 get_gaussian_kernel (rh, size, kernel, params); 330 get_gaussian_kernel (rh, size, kernel, params);
147 331
148 XRenderSetPictureFilter (dpy, src, FilterConvolution, params, size+2); 332 XRenderSetPictureFilter (dpy, src, FilterConvolution, params, size+2);
149 XRenderComposite (dpy, 333 XRenderComposite (dpy,
150 PictOpSrc, 334 PictOpSrc,
151 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,
152 None, 351 None,
153 dst, 352 dst,
154 0, 0, 353 0, 0,
155 0, 0, 354 0, 0,
156 0, 0, 355 0, 0,
157 w, h); 356 w, h);
158
159 ::swap (src, dst);
160
161 size = rv * 2 + 1;
162 get_gaussian_kernel (rv, size, kernel, params);
163 ::swap (params[0], params[1]);
164
165 XRenderSetPictureFilter (dpy, src, FilterConvolution, params, size+2);
166 XRenderComposite (dpy,
167 PictOpSrc,
168 src,
169 None,
170 dst,
171 0, 0,
172 0, 0,
173 0, 0,
174 w, h);
175 } 357 }
176 358
177 free (kernel); 359 free (kernel);
178 free (params); 360 free (params);
361
179 XRenderFreePicture (dpy, src); 362 XRenderFreePicture (dpy, src);
180 XRenderFreePicture (dpy, dst); 363 XRenderFreePicture (dpy, dst);
364 XRenderFreePicture (dpy, tmp);
365
366 return img;
181} 367}
182 368
183static Picture 369static Picture
184create_xrender_mask (Display *dpy, Drawable drawable, Bool argb) 370create_xrender_mask (Display *dpy, Drawable drawable, Bool argb, Bool component_alpha)
185{ 371{
186 Pixmap pixmap = XCreatePixmap (dpy, drawable, 1, 1, argb ? 32 : 8); 372 Pixmap pixmap = XCreatePixmap (dpy, drawable, 1, 1, argb ? 32 : 8);
187 373
188 XRenderPictFormat *format = XRenderFindStandardFormat (dpy, argb ? PictStandardARGB32 : PictStandardA8); 374 XRenderPictFormat *format = XRenderFindStandardFormat (dpy, argb ? PictStandardARGB32 : PictStandardA8);
189 XRenderPictureAttributes pa; 375 XRenderPictureAttributes pa;
190 pa.repeat = True; 376 pa.repeat = RepeatNormal;
377 pa.component_alpha = component_alpha;
191 Picture mask = XRenderCreatePicture (dpy, pixmap, format, CPRepeat, &pa); 378 Picture mask = XRenderCreatePicture (dpy, pixmap, format, CPRepeat | CPComponentAlpha, &pa);
192 379
193 XFreePixmap (dpy, pixmap); 380 XFreePixmap (dpy, pixmap);
194 381
195 return mask; 382 return mask;
196} 383}
197 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
198void 404void
199rxvt_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)
200{ 406{
407 unshare ();
408
201 Display *dpy = s->display->dpy; 409 Display *dpy = s->display->dpy;
202 Picture src = create_xrender_mask (dpy, pm, True);
203 Picture dst = XRenderCreatePicture (dpy, pm, format, 0, 0); 410 Picture dst = XRenderCreatePicture (dpy, pm, format, 0, 0);
204 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;
205 XRenderColor mask_c; 416 XRenderColor mask_c;
206 mask_c.red = float_to_component (r); 417
207 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))
208 mask_c.blue = float_to_component (b);
209 mask_c.alpha = float_to_component (a);
210 XRenderFillRectangle (dpy, PictOpSrc, src, &mask_c, 0, 0, 1, 1); 419 XRenderFillRectangle (dpy, PictOpAdd, dst, &mask_c, 0, 0, w, h);
211 420
212 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);
213} 435}
214 436
215void 437void
216rxvt_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)
217{ 439{
218 if (!(s->display->flags & DISPLAY_HAS_RENDER_MUL)) 440 if (r < 0 || g < 0 || b < 0 || a < 0)
219 return; 441 rxvt_fatal ("rxvt_img::contrast does not support negative values.\n");
220 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
221 Display *dpy = s->display->dpy; 452 Display *dpy = s->display->dpy;
222 Picture src = create_xrender_mask (dpy, pm, True); 453
454 Picture src = src_picture ();
223 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);
224 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;
225 XRenderColor mask_c; 462 XRenderColor mask_c;
226 mask_c.red = float_to_component (r);
227 mask_c.green = float_to_component (g);
228 mask_c.blue = float_to_component (b);
229 mask_c.alpha = float_to_component (a);
230 XRenderFillRectangle (dpy, PictOpSrc, src, &mask_c, 0, 0, 1, 1);
231 463
232 XRenderComposite (dpy, PictOpMultiply, src, None, dst, 0, 0, 0, 0, 0, 0, w, h); 464 if (extract (0, 65535, r, g, b, a, mask_c.red, mask_c.green, mask_c.blue, mask_c.alpha))
233}
234
235bool
236rxvt_img::render_pixbuf (GdkPixbuf *pixbuf, int src_x, int src_y, int width, int height, int dst_x, int dst_y)
237{
238 Display *dpy = s->display->dpy;
239
240 if (s->visual->c_class != TrueColor)
241 return false;
242
243 uint32_t red_mask, green_mask, blue_mask, alpha_mask;
244
245 red_mask = (uint32_t)format->direct.redMask << format->direct.red;
246 green_mask = (uint32_t)format->direct.greenMask << format->direct.green;
247 blue_mask = (uint32_t)format->direct.blueMask << format->direct.blue;
248 alpha_mask = (uint32_t)format->direct.alphaMask << format->direct.alpha;
249
250 int width_r = ecb_popcount32 (red_mask);
251 int width_g = ecb_popcount32 (green_mask);
252 int width_b = ecb_popcount32 (blue_mask);
253 int width_a = ecb_popcount32 (alpha_mask);
254
255 if (width_r > 8 || width_g > 8 || width_b > 8 || width_a > 8)
256 return false;
257
258 int sh_r = ecb_ctz32 (red_mask);
259 int sh_g = ecb_ctz32 (green_mask);
260 int sh_b = ecb_ctz32 (blue_mask);
261 int sh_a = ecb_ctz32 (alpha_mask);
262
263 if (width > 32767 || height > 32767)
264 return false;
265
266 XImage *ximage = XCreateImage (dpy, s->visual, format->depth, ZPixmap, 0, 0,
267 width, height, 32, 0);
268 if (!ximage)
269 return false;
270
271 if (height > INT_MAX / ximage->bytes_per_line
272 || !(ximage->data = (char *)malloc (height * ximage->bytes_per_line)))
273 {
274 XDestroyImage (ximage);
275 return false;
276 }
277
278 GC gc = XCreateGC (dpy, pm, 0, 0);
279
280 ximage->byte_order = ecb_big_endian () ? MSBFirst : LSBFirst;
281
282 int rowstride = gdk_pixbuf_get_rowstride (pixbuf);
283 int channels = gdk_pixbuf_get_n_channels (pixbuf);
284 unsigned char *row = gdk_pixbuf_get_pixels (pixbuf) + src_y * rowstride + src_x * channels;
285 char *line = ximage->data;
286
287 rgba c (0, 0, 0);
288
289 if (channels == 4 && alpha_mask == 0)
290 {
291 //pix_colors[Color_bg].get (c);
292 //TODO
293 c.r = 0xffff; c.g = 0xc0c0; c.b = 0xcbcb;//D
294 c.r >>= 8;
295 c.g >>= 8;
296 c.b >>= 8;
297 }
298
299 for (int y = 0; y < height; y++)
300 {
301 for (int x = 0; x < width; x++)
302 { 465 {
303 unsigned char *pixel = row + x * channels; 466 XRenderFillRectangle (dpy, PictOpSrc, mul, &mask_c, 0, 0, 1, 1);
304 uint32_t value; 467 XRenderComposite (dpy, PictOpAdd, src, mul, dst, 0, 0, 0, 0, 0, 0, w, h);
305 unsigned char r, g, b, a;
306
307 if (channels == 4)
308 {
309 a = pixel[3];
310 r = (pixel[0] * a + c.r * (0xff - a)) / 0xff;
311 g = (pixel[1] * a + c.g * (0xff - a)) / 0xff;
312 b = (pixel[2] * a + c.b * (0xff - a)) / 0xff;
313 }
314 else
315 {
316 a = 0xff;
317 r = pixel[0];
318 g = pixel[1];
319 b = pixel[2];
320 }
321
322 value = ((r >> (8 - width_r)) << sh_r)
323 | ((g >> (8 - width_g)) << sh_g)
324 | ((b >> (8 - width_b)) << sh_b)
325 | ((a >> (8 - width_a)) << sh_a);
326
327 if (ximage->bits_per_pixel == 32)
328 ((uint32_t *)line)[x] = value;
329 else
330 XPutPixel (ximage, x, y, value);
331 } 468 }
332
333 row += rowstride;
334 line += ximage->bytes_per_line;
335 } 469 }
336 470
337 XPutImage (dpy, pm, gc, ximage, 0, 0, dst_x, dst_y, width, height); 471 XRenderFreePicture (dpy, mul);
338 XDestroyImage (ximage); 472 XRenderFreePicture (dpy, dst);
339 XFreeGC (dpy, gc); 473 XRenderFreePicture (dpy, src);
340 474
341 return true; 475 ::swap (img->ref, ref);
476 ::swap (img->pm , pm );
477
478 delete img;
342} 479}
343 480
344rxvt_img * 481rxvt_img *
345rxvt_img::clone () 482rxvt_img::clone ()
346{ 483{
347 rxvt_img *img = new rxvt_img (s, format, w, h); 484 return new rxvt_img (*this);
348
349 GC gc = XCreateGC (s->display->dpy, pm, 0, 0);
350 XCopyArea (s->display->dpy, pm, img->pm, gc, 0, 0, w, h, 0, 0);
351 XFreeGC (s->display->dpy, gc);
352
353 return img;
354} 485}
355 486
356rxvt_img * 487rxvt_img *
357rxvt_img::sub_rect (int x, int y, int width, int height, int repeat) 488rxvt_img::reify ()
358{ 489{
359 rxvt_img *img = new rxvt_img (s, format, width, height); 490 if (x == 0 && y == 0 && w == ref->w && h == ref->h)
491 return clone ();
360 492
361 Display *dpy = s->display->dpy; 493 Display *dpy = s->display->dpy;
362 XRenderPictureAttributes pa; 494
363 pa.repeat = repeat; 495 // add an alpha channel if...
364 Picture src = XRenderCreatePicture (dpy, pm, format, CPRepeat, &pa); 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 ();
365 Picture dst = XRenderCreatePicture (dpy, img->pm, img->format, 0, 0); 504 Picture dst = XRenderCreatePicture (dpy, img->pm, img->format, 0, 0);
366 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
367 XRenderComposite (dpy, PictOpSrc, src, None, dst, x, y, 0, 0, 0, 0, width, height); 513 XRenderComposite (dpy, PictOpSrc, src, None, dst, x, y, 0, 0, 0, 0, w, h);
368 514
369 XRenderFreePicture (dpy, src); 515 XRenderFreePicture (dpy, src);
370 XRenderFreePicture (dpy, dst); 516 XRenderFreePicture (dpy, dst);
371 517
372 return img; 518 return img;
373} 519}
374 520
375rxvt_img * 521rxvt_img *
376rxvt_img::transform (int new_width, int new_height, double matrix[9], int repeat) 522rxvt_img::sub_rect (int x, int y, int width, int height)
377{ 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
378 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 ();
379 603
380 Display *dpy = s->display->dpy; 604 Display *dpy = s->display->dpy;
381 XRenderPictureAttributes pa; 605 Picture src = src_picture ();
382 pa.repeat = repeat;
383 Picture src = XRenderCreatePicture (dpy, pm, format, CPRepeat, &pa);
384 Picture dst = XRenderCreatePicture (dpy, img->pm, img->format, 0, 0); 606 Picture dst = XRenderCreatePicture (dpy, img->pm, img->format, 0, 0);
385 607
386 XTransform xfrm; 608 XTransform xfrm;
387 609
388 for (int i = 0; i < 3; ++i) 610 for (int i = 0; i < 3; ++i)
389 for (int j = 0; j < 3; ++j) 611 for (int j = 0; j < 3; ++j)
390 xfrm.matrix [i][j] = XDoubleToFixed (matrix [i * 3 + j]); 612 xfrm.matrix [i][j] = XDoubleToFixed (inv [i][j]);
391 613
392 XRenderSetPictureFilter (dpy, src, "good", 0, 0); 614 XRenderSetPictureFilter (dpy, src, "good", 0, 0);
393 XRenderSetPictureTransform (dpy, src, &xfrm); 615 XRenderSetPictureTransform (dpy, src, &xfrm);
394 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);
395 617
396 XRenderFreePicture (dpy, src); 618 XRenderFreePicture (dpy, src);
397 XRenderFreePicture (dpy, dst); 619 XRenderFreePicture (dpy, dst);
398 620
399 return img; 621 return img;
400} 622}
401 623
402rxvt_img * 624rxvt_img *
403rxvt_img::scale (int new_width, int new_height) 625rxvt_img::scale (int new_width, int new_height)
404{ 626{
627 if (w == new_width && h == new_height)
628 return clone ();
629
405 double matrix[9] = { 630 double matrix[3][3] = {
406 w / (double)new_width, 0, 0, 631 { new_width / (double)w, 0, 0 },
407 0, h / (double)new_height, 0, 632 { 0, new_height / (double)h, 0 },
408 0, 0, 1 633 { 0, 0, 1 }
409 }; 634 };
410 635
411 return transform (new_width, new_height, matrix); 636 int old_repeat_mode = repeat;
412} 637 repeat = RepeatPad; // not right, but xrender can't properly scale it seems
413 638
639 rxvt_img *img = transform (matrix);
640
641 repeat = old_repeat_mode;
642 img->repeat = repeat;
643
644 return img;
645}
646
414rxvt_img * 647rxvt_img *
415rxvt_img::rotate (int new_width, int new_height, int x, int y, double phi, int repeat) 648rxvt_img::rotate (int cx, int cy, double phi)
416{ 649{
417 double s = sin (phi); 650 double s = sin (phi);
418 double c = cos (phi); 651 double c = cos (phi);
419 652
420 double matrix[9] = { 653 double matrix[3][3] = {
421 c, -s, -c * x + s * y + x, 654 { c, -s, cx - c * cx + s * cy },
422 s, c, -s * x - c * y + y, 655 { s, c, cy - s * cx - c * cy },
423 0, 0, 1 656 { 0, 0, 1 }
657 //{ c, -s, 0 },
658 //{ s, c, 0 },
659 //{ 0, 0, 1 }
424 }; 660 };
425 661
426 return transform (new_width, new_height, matrix, repeat); 662 //move (-cx, -cy);
427} 663 rxvt_img *img = transform (matrix);
664 //move ( cx, cy);
665 //img->move (cx, cy);
428 666
667 return img;
668}
669
429rxvt_img * 670rxvt_img *
430rxvt_img::convert_to (XRenderPictFormat *new_format) 671rxvt_img::convert_format (XRenderPictFormat *new_format, const rgba &bg)
431{ 672{
673 if (new_format == format)
674 return clone ();
675
432 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 ();
433 678
434 Display *dpy = s->display->dpy; 679 Display *dpy = s->display->dpy;
435 Picture src = XRenderCreatePicture (dpy, pm, format, 0, 0); 680 Picture src = src_picture ();
436 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;
437 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
438 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);
439 694
440 XRenderFreePicture (dpy, src); 695 XRenderFreePicture (dpy, src);
441 XRenderFreePicture (dpy, dst); 696 XRenderFreePicture (dpy, dst);
442 697
443 return img; 698 return img;
444} 699}
445 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
446#endif 727#endif
447 728

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines