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.7 by sf-exg, Sun Jun 3 20:34:25 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{
18} 161}
19 162
20rxvt_img * 163rxvt_img::rxvt_img (const rxvt_img &img)
21rxvt_img::new_from_file (rxvt_screen *s, const char *filename) 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)
22{ 165{
23 GError *err; 166 ++ref->cnt;
24 GdkPixbuf *pb = gdk_pixbuf_new_from_file (filename, &err); 167}
25 168
26 if (!pb) 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))
27 return 0; 186 return 0;
28 187
29 rxvt_img *img = new rxvt_img ( 188 rxvt_img *img = new rxvt_img (
30 s, 189 s,
31 XRenderFindStandardFormat (s->display->dpy, gdk_pixbuf_get_has_alpha (pb) ? PictStandardARGB32 : PictStandardRGB24), 190 XRenderFindVisualFormat (dpy, DefaultVisual (dpy, s->display->screen)),
32 gdk_pixbuf_get_width (pb), 191 0,
33 gdk_pixbuf_get_height (pb) 192 0,
193 root_pm_w,
194 root_pm_h
34 ); 195 );
35 196
36 img->render (pb, 0, 0, img->w, img->h, 0, 0); 197 img->pm = root_pixmap;
198 img->ref = new pixref (root_pm_w, root_pm_h);
199 img->ref->ours = false;
37 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;
305}
306
307rxvt_img *
308rxvt_img::new_from_file (rxvt_screen *s, const char *filename)
309{
310 GError *err = 0;
311 GdkPixbuf *pb = gdk_pixbuf_new_from_file (filename, &err);
312
313 if (!pb)
314 rxvt_fatal ("rxvt_img::new_from_file: %s\n", err->message);
315
316 rxvt_img *img = new_from_pixbuf (s, pb);
317
318 g_object_unref (pb);
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);
45} 340}
46 341
47void 342void
48rxvt_img::fill (const rxvt_color &c) 343rxvt_img::alloc ()
49{ 344{
50 XGCValues gcv; 345 pm = XCreatePixmap (s->display->dpy, s->display->root, w, h, format->depth);
51 gcv.foreground = c; 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;
359}
360
361void
362rxvt_img::unshare ()
363{
364 if (ref->cnt == 1 && ref->ours)
365 return;
366
367 Pixmap pm2 = XCreatePixmap (s->display->dpy, s->display->root, ref->w, ref->h, format->depth);
52 GC gc = XCreateGC (s->display->dpy, pm, GCForeground, &gcv); 368 GC gc = XCreateGC (s->display->dpy, pm, 0, 0);
53 XFillRectangle (s->display->dpy, pm, gc, 0, 0, w, h); 369 XCopyArea (s->display->dpy, pm, pm2, gc, 0, 0, ref->w, ref->h, 0, 0);
54 XFreeGC (s->display->dpy, gc); 370 XFreeGC (s->display->dpy, gc);
371
372 destroy ();
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 );
410
411 delete img;
55} 412}
56 413
57static void 414static void
58get_gaussian_kernel (int radius, int width, double *kernel, XFixed *params) 415get_gaussian_kernel (int radius, int width, nv *kernel, XFixed *params)
59{ 416{
60 double sigma = radius / 2.0; 417 nv sigma = radius / 2.0;
61 double scale = sqrt (2.0 * M_PI) * sigma; 418 nv scale = sqrt (2.0 * M_PI) * sigma;
62 double sum = 0.0; 419 nv sum = 0.0;
63 420
64 for (int i = 0; i < width; i++) 421 for (int i = 0; i < width; i++)
65 { 422 {
66 double x = i - width / 2; 423 nv x = i - width / 2;
67 kernel[i] = exp (-(x * x) / (2.0 * sigma * sigma)) / scale; 424 kernel[i] = exp (-(x * x) / (2.0 * sigma * sigma)) / scale;
68 sum += kernel[i]; 425 sum += kernel[i];
69 } 426 }
70 427
71 params[0] = XDoubleToFixed (width); 428 params[0] = XDoubleToFixed (width);
73 430
74 for (int i = 0; i < width; i++) 431 for (int i = 0; i < width; i++)
75 params[i+2] = XDoubleToFixed (kernel[i] / sum); 432 params[i+2] = XDoubleToFixed (kernel[i] / sum);
76} 433}
77 434
78void 435rxvt_img *
79rxvt_img::blur (int rh, int rv) 436rxvt_img::blur (int rh, int rv)
80{ 437{
81 if (!(s->display->flags & DISPLAY_HAS_RENDER_CONV)) 438 if (!(s->display->flags & DISPLAY_HAS_RENDER_CONV))
82 return; 439 return clone ();
83 440
84 Display *dpy = s->display->dpy; 441 Display *dpy = s->display->dpy;
85 int size = max (rh, rv) * 2 + 1; 442 int size = max (rh, rv) * 2 + 1;
86 double *kernel = (double *)malloc (size * sizeof (double)); 443 nv *kernel = (nv *)malloc (size * sizeof (nv));
87 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 ();
88 447
89 XRenderPictureAttributes pa; 448 XRenderPictureAttributes pa;
90
91 pa.repeat = RepeatPad; 449 pa.repeat = RepeatPad;
92 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
93 Pixmap tmp = XCreatePixmap (dpy, pm, w, h, format->depth); 453 Pixmap tmp_pm = XCreatePixmap (dpy, pm, w, h, format->depth);
94 Picture dst = XRenderCreatePicture (dpy, tmp, format, CPRepeat, &pa); 454 Picture tmp = XRenderCreatePicture (dpy, tmp_pm , format, CPRepeat, &pa);
95 XFreePixmap (dpy, tmp); 455 XFreePixmap (dpy, tmp_pm);
96 456
97 if (kernel && params) 457 if (kernel && params)
98 { 458 {
99 size = rh * 2 + 1; 459 size = rh * 2 + 1;
100 get_gaussian_kernel (rh, size, kernel, params); 460 get_gaussian_kernel (rh, size, kernel, params);
101 461
102 XRenderSetPictureFilter (dpy, src, FilterConvolution, params, size+2); 462 XRenderSetPictureFilter (dpy, src, FilterConvolution, params, size+2);
103 XRenderComposite (dpy, 463 XRenderComposite (dpy,
104 PictOpSrc, 464 PictOpSrc,
105 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,
106 None, 481 None,
107 dst, 482 dst,
108 0, 0, 483 0, 0,
109 0, 0, 484 0, 0,
110 0, 0, 485 0, 0,
111 w, h); 486 w, h);
112
113 ::swap (src, dst);
114
115 size = rv * 2 + 1;
116 get_gaussian_kernel (rv, size, kernel, params);
117 ::swap (params[0], params[1]);
118
119 XRenderSetPictureFilter (dpy, src, FilterConvolution, params, size+2);
120 XRenderComposite (dpy,
121 PictOpSrc,
122 src,
123 None,
124 dst,
125 0, 0,
126 0, 0,
127 0, 0,
128 w, h);
129 } 487 }
130 488
131 free (kernel); 489 free (kernel);
132 free (params); 490 free (params);
491
133 XRenderFreePicture (dpy, src); 492 XRenderFreePicture (dpy, src);
134 XRenderFreePicture (dpy, dst); 493 XRenderFreePicture (dpy, dst);
494 XRenderFreePicture (dpy, tmp);
495
496 return img;
135} 497}
136 498
137static Picture 499static Picture
138create_xrender_mask (Display *dpy, Drawable drawable, Bool argb) 500create_xrender_mask (Display *dpy, Drawable drawable, Bool argb, Bool component_alpha)
139{ 501{
140 Pixmap pixmap = XCreatePixmap (dpy, drawable, 1, 1, argb ? 32 : 8); 502 Pixmap pixmap = XCreatePixmap (dpy, drawable, 1, 1, argb ? 32 : 8);
141 503
142 XRenderPictFormat *format = XRenderFindStandardFormat (dpy, argb ? PictStandardARGB32 : PictStandardA8); 504 XRenderPictFormat *format = XRenderFindStandardFormat (dpy, argb ? PictStandardARGB32 : PictStandardA8);
143 XRenderPictureAttributes pa; 505 XRenderPictureAttributes pa;
144 pa.repeat = True; 506 pa.repeat = RepeatNormal;
507 pa.component_alpha = component_alpha;
145 Picture mask = XRenderCreatePicture (dpy, pixmap, format, CPRepeat, &pa); 508 Picture mask = XRenderCreatePicture (dpy, pixmap, format, CPRepeat | CPComponentAlpha, &pa);
146 509
147 XFreePixmap (dpy, pixmap); 510 XFreePixmap (dpy, pixmap);
148 511
149 return mask; 512 return mask;
150} 513}
151 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
152void 534void
153rxvt_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)
154{ 536{
537 unshare ();
538
155 Display *dpy = s->display->dpy; 539 Display *dpy = s->display->dpy;
156 Picture src = create_xrender_mask (dpy, pm, True);
157 Picture dst = XRenderCreatePicture (dpy, pm, format, 0, 0); 540 Picture dst = XRenderCreatePicture (dpy, pm, format, 0, 0);
158 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;
159 XRenderColor mask_c; 546 XRenderColor mask_c;
160 mask_c.red = float_to_component (r); 547
161 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))
162 mask_c.blue = float_to_component (b);
163 mask_c.alpha = float_to_component (a);
164 XRenderFillRectangle (dpy, PictOpSrc, src, &mask_c, 0, 0, 1, 1); 549 XRenderFillRectangle (dpy, PictOpAdd, dst, &mask_c, 0, 0, w, h);
165 550
166 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);
167} 565}
168 566
169void 567void
170rxvt_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)
171{ 569{
172 if (!(s->display->flags & DISPLAY_HAS_RENDER_MUL)) 570 if (r < 0 || g < 0 || b < 0 || a < 0)
173 return; 571 rxvt_fatal ("rxvt_img::contrast does not support negative values.\n");
174 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
175 Display *dpy = s->display->dpy; 582 Display *dpy = s->display->dpy;
176 Picture src = create_xrender_mask (dpy, pm, True); 583
584 Picture src = picture ();
177 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);
178 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;
179 XRenderColor mask_c; 592 XRenderColor mask_c;
180 mask_c.red = float_to_component (r); 593
181 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))
182 mask_c.blue = float_to_component (b); 595 {
183 mask_c.alpha = float_to_component (a);
184 XRenderFillRectangle (dpy, PictOpSrc, src, &mask_c, 0, 0, 1, 1); 596 XRenderFillRectangle (dpy, PictOpSrc, mul, &mask_c, 0, 0, 1, 1);
185
186 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;
187} 609}
188 610
189void 611void
190rxvt_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)
191{ 613{
192 //TODO 614 unshare ();
193}
194 615
195rxvt_img *
196rxvt_img::copy ()
197{
198 GC gc = XCreateGC (s->display->dpy, pm, 0, 0);
199 Pixmap pm2 = XCreatePixmap (s->display->dpy, pm, w, h, format->depth);
200 XCopyArea (s->display->dpy, pm, pm2, gc, 0, 0, w, h, 0, 0);
201 XFreeGC (s->display->dpy, gc);
202 return new rxvt_img (s, format, w, h, pm2);
203}
204
205rxvt_img *
206rxvt_img::transform (int new_width, int new_height, double matrix[16])
207{
208 //TODO
209}
210
211rxvt_img *
212rxvt_img::scale (int new_width, int new_height)
213{
214 // use transform
215 //TODO
216}
217
218rxvt_img *
219rxvt_img::convert_to (XRenderPictFormat *new_format)
220{
221 Display *dpy = s->display->dpy; 616 Display *dpy = s->display->dpy;
222 Pixmap new_pm = XCreatePixmap (dpy, pm, w, h, new_format->depth); 617 Picture src = img->picture ();
223 Picture src = XRenderCreatePicture (dpy, pm, format, 0, 0); 618 Picture dst = picture ();
224 Picture dst = XRenderCreatePicture (dpy, new_pm, new_format, 0, 0); 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 }
225 627
226 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);
227 629
228 XRenderFreePicture (dpy, src); 630 XRenderFreePicture (dpy, src);
229 XRenderFreePicture (dpy, dst); 631 XRenderFreePicture (dpy, dst);
230 632
231 rxvt_img *img = new rxvt_img ( 633 if (mask_p)
232 s, 634 XRenderFreePicture (dpy, mask_p);
233 new_format, 635}
234 w, 636
235 h, 637rxvt_img *
236 new_pm 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
747 XRenderFreePicture (dpy, src);
748 XRenderFreePicture (dpy, dst);
749
750 return img;
751}
752
753rxvt_img *
754rxvt_img::scale (int new_width, int new_height)
755{
756 if (w == new_width && h == new_height)
757 return clone ();
758
759 nv matrix[3][3] = {
760 { new_width / (nv)w, 0, 0 },
761 { 0, new_height / (nv)h, 0 },
762 { 0, 0, 1 }
237 ); 763 };
238 764
239 return img; 765 int old_repeat_mode = repeat;
240} 766 repeat = RepeatPad; // not right, but xrender can't properly scale it seems
241 767
768 rxvt_img *img = transform (matrix);
769
770 repeat = old_repeat_mode;
771 img->repeat = repeat;
772
773 return img;
774}
775
776rxvt_img *
777rxvt_img::rotate (int cx, int cy, nv phi)
778{
779 nv s = sin (phi);
780 nv c = cos (phi);
781
782 nv matrix[3][3] = {
783#if 0
784 { c, -s, cx - c * cx + s * cy },
785 { s, c, cy - s * cx - c * cy },
786 { 0, 0, 1 }
787#else
788 { c, -s, 0 },
789 { s, c, 0 },
790 { 0, 0, 1 }
242#endif 791#endif
792 };
243 793
794 move (-cx, -cy);
795 rxvt_img *img = transform (matrix);
796 move ( cx, cy);
797 img->move (cx, cy);
798
799 return img;
800}
801
802rxvt_img *
803rxvt_img::convert_format (XRenderPictFormat *new_format, const rgba &bg)
804{
805 if (new_format == format)
806 return clone ();
807
808 rxvt_img *img = new rxvt_img (s, new_format, x, y, w, h, repeat);
809 img->alloc ();
810
811 Display *dpy = s->display->dpy;
812 Picture src = picture ();
813 Picture dst = XRenderCreatePicture (dpy, img->pm, new_format, 0, 0);
814 int op = PictOpSrc;
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
825 XRenderComposite (dpy, op, src, None, dst, 0, 0, 0, 0, 0, 0, w, h);
826
827 XRenderFreePicture (dpy, src);
828 XRenderFreePicture (dpy, dst);
829
830 return img;
831}
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
859#endif
860

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines