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.18 by sf-exg, Tue Jun 5 12:30:37 2012 UTC vs.
Revision 1.94 by root, Fri Jun 15 18:10:40 2012 UTC

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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines