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.11 by root, Mon Jun 4 15:15:49 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 (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);
198 XRenderFillRectangle (dpy, PictOpSrc, src, &mask_c, 0, 0, 1, 1); 596 XRenderFillRectangle (dpy, PictOpSrc, mul, &mask_c, 0, 0, 1, 1);
199
200 XRenderComposite (dpy, PictOpMultiply, src, None, dst, 0, 0, 0, 0, 0, 0, w, h); 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;
201} 609}
202 610
203void 611void
204rxvt_img::render (GdkPixbuf *pixbuf, int src_x, int src_y, int width, int height, int dst_x, int dst_y) 612rxvt_img::draw (rxvt_img *img, int op, nv mask)
205{ 613{
206 //TODO 614 unshare ();
207}
208 615
209rxvt_img *
210rxvt_img::clone ()
211{
212 GC gc = XCreateGC (s->display->dpy, pm, 0, 0);
213 Pixmap pm2 = XCreatePixmap (s->display->dpy, pm, w, h, format->depth);
214 XCopyArea (s->display->dpy, pm, pm2, gc, 0, 0, w, h, 0, 0);
215 XFreeGC (s->display->dpy, gc);
216 return new rxvt_img (s, format, w, h, pm2);
217}
218
219rxvt_img *
220rxvt_img::transform (int new_width, int new_height, int repeat, double matrix[9])
221{
222 //TODO
223}
224
225rxvt_img *
226rxvt_img::scale (int new_width, int new_height)
227{
228 double matrix[9] = {
229 new_width / (double)w, 0, 0,
230 0, new_height / (double)h, 0,
231 0, 0, 1
232 };
233
234 return transform (new_width, new_height, RepeatNormal, matrix);
235}
236
237rxvt_img *
238rxvt_img::convert_to (XRenderPictFormat *new_format)
239{
240 rxvt_img *img = new rxvt_img (s, new_format, w, h);
241
242 Display *dpy = s->display->dpy; 616 Display *dpy = s->display->dpy;
243 Picture src = XRenderCreatePicture (dpy, pm, format, 0, 0); 617 Picture src = img->picture ();
244 Picture dst = XRenderCreatePicture (dpy, img->pm, new_format, 0, 0); 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) };
625 XRenderFillRectangle (dpy, PictOpSrc, mask, &mask_c, 0, 0, 1, 1);
626 }
245 627
246 XRenderComposite (dpy, PictOpSrc, src, None, dst, 0, 0, 0, 0, 0, 0, w, h); 628 XRenderComposite (dpy, op, src, mask_p, dst, x - img->x, y - img->y, 0, 0, 0, 0, w, h);
247 629
248 XRenderFreePicture (dpy, src); 630 XRenderFreePicture (dpy, src);
249 XRenderFreePicture (dpy, dst); 631 XRenderFreePicture (dpy, dst);
250 632
251 return img; 633 if (mask_p)
634 XRenderFreePicture (dpy, mask_p);
252} 635}
253 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
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);
736
737 XTransform xfrm;
738
739 for (int i = 0; i < 3; ++i)
740 for (int j = 0; j < 3; ++j)
741 xfrm.matrix [i][j] = XDoubleToFixed (inv [i][j]);
742
743 XRenderSetPictureFilter (dpy, src, "good", 0, 0);
744 XRenderSetPictureTransform (dpy, src, &xfrm);
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);
254#endif 755#endif
255 756
757 XRenderFreePicture (dpy, src);
758 XRenderFreePicture (dpy, dst);
759
760 return img;
761}
762
763rxvt_img *
764rxvt_img::scale (int new_width, int new_height)
765{
766 if (w == new_width && h == new_height)
767 return clone ();
768
769 nv matrix[3][3] = {
770 { new_width / (nv)w, 0, 0 },
771 { 0, new_height / (nv)h, 0 },
772 { 0, 0, 1 }
773 };
774
775 int old_repeat_mode = repeat;
776 repeat = RepeatPad; // not right, but xrender can't properly scale it seems
777
778 rxvt_img *img = transform (matrix);
779
780 repeat = old_repeat_mode;
781 img->repeat = repeat;
782
783 return img;
784}
785
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 *
813rxvt_img::convert_format (XRenderPictFormat *new_format, const rgba &bg)
814{
815 if (new_format == format)
816 return clone ();
817
818 rxvt_img *img = new rxvt_img (s, new_format, x, y, w, h, repeat);
819 img->alloc ();
820
821 Display *dpy = s->display->dpy;
822 Picture src = picture ();
823 Picture dst = XRenderCreatePicture (dpy, img->pm, new_format, 0, 0);
824 int op = PictOpSrc;
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
835 XRenderComposite (dpy, op, src, None, dst, 0, 0, 0, 0, 0, 0, w, h);
836
837 XRenderFreePicture (dpy, src);
838 XRenderFreePicture (dpy, dst);
839
840 return img;
841}
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
869#endif
870

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines