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.15 by root, Mon Jun 4 16:03:32 2012 UTC vs.
Revision 1.93 by root, Fri Jun 15 18:07:24 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); 593
195 mask_c.green = float_to_component (g); 594 if (extract (0, 65535, r, g, b, a, mask_c.red, mask_c.green, mask_c.blue, mask_c.alpha))
196 mask_c.blue = float_to_component (b); 595 {
197 mask_c.alpha = float_to_component (a); 596 XRenderFillRectangle (dpy, PictOpSrc, mul, &mask_c, 0, 0, 1, 1);
597 XRenderComposite (dpy, PictOpAdd, src, mul, dst, 0, 0, 0, 0, 0, 0, w, h);
598 }
599 }
600
601 XRenderFreePicture (dpy, mul);
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.)
622 {
623 mask_p = create_xrender_mask (dpy, img->pm, False, False);
624 XRenderColor mask_c = { 0, 0, 0, float_to_component (mask) };
198 XRenderFillRectangle (dpy, PictOpSrc, src, &mask_c, 0, 0, 1, 1); 625 XRenderFillRectangle (dpy, PictOpSrc, mask, &mask_c, 0, 0, 1, 1);
626 }
199 627
628 XRenderComposite (dpy, op, src, mask_p, dst, x - img->x, y - img->y, 0, 0, 0, 0, w, h);
629
630 XRenderFreePicture (dpy, src);
631 XRenderFreePicture (dpy, dst);
632
633 if (mask_p)
634 XRenderFreePicture (dpy, mask_p);
635}
636
637rxvt_img *
638rxvt_img::clone ()
639{
640 return new rxvt_img (*this);
641}
642
643rxvt_img *
644rxvt_img::reify ()
645{
646 if (x == 0 && y == 0 && w == ref->w && h == ref->h)
647 return clone ();
648
649 Display *dpy = s->display->dpy;
650
651 // add an alpha channel if...
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 ();
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
200 XRenderComposite (dpy, PictOpMultiply, src, None, dst, 0, 0, 0, 0, 0, 0, w, h); 666 XRenderComposite (dpy, PictOpSrc, src, None, dst, 0, 0, 0, 0, x, y, ref->w, ref->h);
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 bool argb = format->id == PictStandardARGB32;
207
208 Display *dpy = s->display->dpy;
209
210 if (s->visual->c_class != TrueColor)
211 return false;
212
213 uint32_t red_mask, green_mask, blue_mask, alpha_mask;
214
215 if (argb)
216 {
217 red_mask = 0xff << 16;
218 green_mask = 0xff << 8;
219 blue_mask = 0xff;
220 alpha_mask = 0xff << 24;
221 } 667 }
222 else 668 else
223 { 669 XRenderComposite (dpy, PictOpSrc, src, None, dst, -x, -y, 0, 0, 0, 0, w, h);
224 red_mask = s->visual->red_mask; 670
225 green_mask = s->visual->green_mask; 671 XRenderFreePicture (dpy, src);
226 blue_mask = s->visual->blue_mask; 672 XRenderFreePicture (dpy, dst);
227 alpha_mask = (uint32_t)format->direct.alphaMask << format->direct.alpha; 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)
228 } 686 {
687 img->w = width;
688 img->h = height;
229 689
230 int width_r = ecb_popcount32 (red_mask); 690 rxvt_img *img2 = img->reify ();
231 int width_g = ecb_popcount32 (green_mask); 691 delete img;
232 int width_b = ecb_popcount32 (blue_mask); 692 img = img2;
233 int width_a = ecb_popcount32 (alpha_mask);
234
235 if (width_r > 8 || width_g > 8 || width_b > 8 || width_a > 8)
236 return false;
237
238 int sh_r = ecb_ctz32 (red_mask);
239 int sh_g = ecb_ctz32 (green_mask);
240 int sh_b = ecb_ctz32 (blue_mask);
241 int sh_a = ecb_ctz32 (alpha_mask);
242
243 if (width > 32767 || height > 32767)
244 return false;
245
246 XImage *ximage = XCreateImage (dpy, s->visual, argb ? 32 : format->depth, ZPixmap, 0, 0,
247 width, height, 32, 0);
248 if (!ximage)
249 return false;
250
251 if (height > INT_MAX / ximage->bytes_per_line
252 || !(ximage->data = (char *)malloc (height * ximage->bytes_per_line)))
253 { 693 }
254 XDestroyImage (ximage); 694
255 return false; 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)
256 } 707 {
708 nv v;
257 709
258 GC gc = XCreateGC (dpy, pm, 0, 0); 710 v = m.apply1 (i, 0+x, 0+y); rmin [i] = rmax [i] = v; r [i] = v;
259 711 v = m.apply1 (i, w+x, 0+y); min_it (rmin [i], v); max_it (rmax [i], v);
260 ximage->byte_order = ecb_big_endian () ? MSBFirst : LSBFirst; 712 v = m.apply1 (i, 0+x, h+y); min_it (rmin [i], v); max_it (rmax [i], v);
261 713 v = m.apply1 (i, w+x, h+y); min_it (rmin [i], v); max_it (rmax [i], v);
262 int rowstride = gdk_pixbuf_get_rowstride (pixbuf);
263 int channels = gdk_pixbuf_get_n_channels (pixbuf);
264 unsigned char *row = gdk_pixbuf_get_pixels (pixbuf) + src_y * rowstride + src_x * channels;
265 char *line = ximage->data;
266
267 rgba c (0, 0, 0);
268
269 if (channels == 4 && alpha_mask == 0)
270 { 714 }
271 //pix_colors[Color_bg].get (c);
272 //TODO
273 c.r = 0xffff; c.g = 0xc0c0; c.b = 0xcbcb;//D
274 c.r >>= 8;
275 c.g >>= 8;
276 c.b >>= 8;
277 }
278 715
279 for (int y = 0; y < height; y++) 716 float sx = rmin [0] - x;
280 { 717 float sy = rmin [1] - y;
281 for (int x = 0; x < width; x++)
282 {
283 unsigned char *pixel = row + x * channels;
284 uint32_t value;
285 unsigned char r, g, b, a;
286 718
287 if (channels == 4) 719 // TODO: adjust matrix for subpixel accuracy
288 { 720 int nx = floor (rmin [0]);
289 a = pixel[3]; 721 int ny = floor (rmin [1]);
290 r = (pixel[0] * a + c.r * (0xff - a)) / 0xff;
291 g = (pixel[1] * a + c.g * (0xff - a)) / 0xff;
292 b = (pixel[2] * a + c.b * (0xff - a)) / 0xff;
293 }
294 else
295 {
296 a = 0xff;
297 r = pixel[0];
298 g = pixel[1];
299 b = pixel[2];
300 }
301 722
302 value = ((r >> (8 - width_r)) << sh_r) 723 int new_width = ceil (rmax [0] - rmin [0]);
303 | ((g >> (8 - width_g)) << sh_g) 724 int new_height = ceil (rmax [1] - rmin [1]);
304 | ((b >> (8 - width_b)) << sh_b)
305 | ((a >> (8 - width_a)) << sh_a);
306 725
307 if (ximage->bits_per_pixel == 32) 726 m = mat3x3::translate (-x, -y) * m * mat3x3::translate (x, y);
308 ((uint32_t *)line)[x] = value;
309 else
310 XPutPixel (ximage, x, y, value);
311 }
312 727
313 row += rowstride; 728 mat3x3 inv = m.invert ();
314 line += ximage->bytes_per_line;
315 }
316 729
317 XPutImage (dpy, pm, gc, ximage, 0, 0, dst_x, dst_y, width, height);
318 XDestroyImage (ximage);
319 XFreeGC (dpy, gc);
320
321 return true;
322}
323
324rxvt_img *
325rxvt_img::clone ()
326{
327 GC gc = XCreateGC (s->display->dpy, pm, 0, 0);
328 Pixmap pm2 = XCreatePixmap (s->display->dpy, pm, w, h, format->depth);
329 XCopyArea (s->display->dpy, pm, pm2, gc, 0, 0, w, h, 0, 0);
330 XFreeGC (s->display->dpy, gc);
331 return new rxvt_img (s, format, w, h, pm2);
332}
333
334rxvt_img *
335rxvt_img::transform (int new_width, int new_height, int repeat, double matrix[9])
336{
337 rxvt_img *img = new rxvt_img (s, format, new_width, new_height); 730 rxvt_img *img = new rxvt_img (s, format, nx, ny, new_width, new_height, repeat);
731 img->alloc ();
338 732
339 Display *dpy = s->display->dpy; 733 Display *dpy = s->display->dpy;
340 XRenderPictureAttributes pa; 734 Picture src = picture ();
341 pa.repeat = repeat;
342 Picture src = XRenderCreatePicture (dpy, pm, format, CPRepeat, &pa);
343 Picture dst = XRenderCreatePicture (dpy, img->pm, img->format, 0, 0); 735 Picture dst = XRenderCreatePicture (dpy, img->pm, img->format, 0, 0);
344 736
345 XTransform xfrm; 737 XTransform xfrm;
346 738
347 for (int i = 0; i < 3; ++i) 739 for (int i = 0; i < 3; ++i)
348 for (int j = 0; j < 3; ++j) 740 for (int j = 0; j < 3; ++j)
349 xfrm.matrix [i][j] = XDoubleToFixed (matrix [i * 3 + j]); 741 xfrm.matrix [i][j] = XDoubleToFixed (inv [i][j]);
350 742
743 XRenderSetPictureFilter (dpy, src, "good", 0, 0);
351 XRenderSetPictureTransform (dpy, src, &xfrm); 744 XRenderSetPictureTransform (dpy, src, &xfrm);
352 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);
746#if 1
747 {
748 XRenderColor rc = { 65535,0,0,65535 };
749 XRenderFillRectangle (dpy, PictOpSrc, dst, &rc, 0, 0, new_width, new_height);
750 }{
751 XRenderColor rc = { 0,0,0,65535 };
752 XRenderFillRectangle (dpy, PictOpSrc, dst, &rc, 1, 1, new_width - 2, new_height - 2);
753 }
754 XRenderComposite (dpy, PictOpOver, src, None, dst, sx, sy, 0, 0, 0, 0, new_width, new_height);
755#endif
353 756
354 XRenderFreePicture (dpy, src); 757 XRenderFreePicture (dpy, src);
355 XRenderFreePicture (dpy, dst); 758 XRenderFreePicture (dpy, dst);
356 759
357 return img; 760 return img;
358} 761}
359 762
360rxvt_img * 763rxvt_img *
361rxvt_img::scale (int new_width, int new_height) 764rxvt_img::scale (int new_width, int new_height)
362{ 765{
363 double matrix[9] = { 766 if (w == new_width && h == new_height)
767 return clone ();
768
769 nv matrix[3][3] = {
364 new_width / (double)w, 0, 0, 770 { new_width / (nv)w, 0, 0 },
365 0, new_height / (double)h, 0, 771 { 0, new_height / (nv)h, 0 },
366 0, 0, 1 772 { 0, 0, 1 }
367 }; 773 };
368 774
369 return transform (new_width, new_height, RepeatNormal, matrix); 775 int old_repeat_mode = repeat;
370} 776 repeat = RepeatPad; // not right, but xrender can't properly scale it seems
371 777
778 rxvt_img *img = transform (matrix);
779
780 repeat = old_repeat_mode;
781 img->repeat = repeat;
782
783 return img;
784}
785
372rxvt_img * 786rxvt_img *
787rxvt_img::rotate (int cx, int cy, nv phi)
788{
789 nv s = sin (phi);
790 nv c = cos (phi);
791
792 nv matrix[3][3] = {
793#if 0
794 { c, -s, cx - c * cx + s * cy },
795 { s, c, cy - s * cx - c * cy },
796 { 0, 0, 1 }
797#else
798 { c, -s, 0 },
799 { s, c, 0 },
800 { 0, 0, 1 }
801#endif
802 };
803
804 move (-cx, -cy);
805 rxvt_img *img = transform (matrix);
806 move ( cx, cy);
807 img->move (cx, cy);
808
809 return img;
810}
811
812rxvt_img *
373rxvt_img::convert_to (XRenderPictFormat *new_format) 813rxvt_img::convert_format (XRenderPictFormat *new_format, const rgba &bg)
374{ 814{
815 if (new_format == format)
816 return clone ();
817
375 rxvt_img *img = new rxvt_img (s, new_format, w, h); 818 rxvt_img *img = new rxvt_img (s, new_format, x, y, w, h, repeat);
819 img->alloc ();
376 820
377 Display *dpy = s->display->dpy; 821 Display *dpy = s->display->dpy;
378 Picture src = XRenderCreatePicture (dpy, pm, format, 0, 0); 822 Picture src = picture ();
379 Picture dst = XRenderCreatePicture (dpy, img->pm, new_format, 0, 0); 823 Picture dst = XRenderCreatePicture (dpy, img->pm, new_format, 0, 0);
824 int op = PictOpSrc;
380 825
826 if (format->direct.alphaMask && !new_format->direct.alphaMask)
827 {
828 // does it have to be that complicated
829 XRenderColor rc = { bg.r, bg.g, bg.b, bg.a };
830 XRenderFillRectangle (dpy, PictOpSrc, dst, &rc, 0, 0, w, h);
831
832 op = PictOpOver;
833 }
834
381 XRenderComposite (dpy, PictOpSrc, src, None, dst, 0, 0, 0, 0, 0, 0, w, h); 835 XRenderComposite (dpy, op, src, None, dst, 0, 0, 0, 0, 0, 0, w, h);
382 836
383 XRenderFreePicture (dpy, src); 837 XRenderFreePicture (dpy, src);
384 XRenderFreePicture (dpy, dst); 838 XRenderFreePicture (dpy, dst);
385 839
386 return img; 840 return img;
387} 841}
388 842
843rxvt_img *
844rxvt_img::blend (rxvt_img *img, nv factor)
845{
846 rxvt_img *img2 = clone ();
847 Display *dpy = s->display->dpy;
848 Picture src = img->picture ();
849 Picture dst = XRenderCreatePicture (dpy, img2->pm, img2->format, 0, 0);
850 Picture mask = create_xrender_mask (dpy, img->pm, False, False);
851
852 XRenderColor mask_c;
853
854 mask_c.alpha = float_to_component (factor);
855 mask_c.red =
856 mask_c.green =
857 mask_c.blue = 0;
858 XRenderFillRectangle (dpy, PictOpSrc, mask, &mask_c, 0, 0, 1, 1);
859
860 XRenderComposite (dpy, PictOpOver, src, mask, dst, 0, 0, 0, 0, 0, 0, w, h);
861
862 XRenderFreePicture (dpy, src);
863 XRenderFreePicture (dpy, dst);
864 XRenderFreePicture (dpy, mask);
865
866 return img2;
867}
868
389#endif 869#endif
390 870

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines