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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines