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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines