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.10 by sf-exg, Mon Jun 4 06:59:50 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{
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 rxvt_img *img = new rxvt_img (s, new_format, w, h);
222
223 Display *dpy = s->display->dpy; 616 Display *dpy = s->display->dpy;
224 Picture src = XRenderCreatePicture (dpy, pm, format, 0, 0); 617 Picture src = img->picture ();
225 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 }
226 627
227 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);
228 629
229 XRenderFreePicture (dpy, src); 630 XRenderFreePicture (dpy, src);
230 XRenderFreePicture (dpy, dst); 631 XRenderFreePicture (dpy, dst);
231 632
232 return img; 633 if (mask_p)
634 XRenderFreePicture (dpy, mask_p);
233} 635}
234 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);
235#endif 755#endif
236 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