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.13 by root, Mon Jun 4 15:30:41 2012 UTC vs.
Revision 1.96 by root, Sat Jun 16 15:55:19 2012 UTC

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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines