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.8 by root, Sun Jun 3 20:38:24 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{
18} 213}
19 214
20rxvt_img * 215rxvt_img::rxvt_img (const rxvt_img &img)
21rxvt_img::new_from_file (rxvt_screen *s, const char *filename) 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)
22{ 217{
23 GError *err; 218 ++ref->cnt;
24 GdkPixbuf *pb = gdk_pixbuf_new_from_file (filename, &err); 219}
25 220
26 if (!pb) 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))
27 return 0; 238 return 0;
28 239
29 rxvt_img *img = new rxvt_img ( 240 rxvt_img *img = new rxvt_img (
30 s, 241 s,
31 XRenderFindStandardFormat (s->display->dpy, gdk_pixbuf_get_has_alpha (pb) ? PictStandardARGB32 : PictStandardRGB24), 242 XRenderFindVisualFormat (dpy, DefaultVisual (dpy, s->display->screen)),
32 gdk_pixbuf_get_width (pb), 243 0,
33 gdk_pixbuf_get_height (pb) 244 0,
245 root_pm_w,
246 root_pm_h
34 ); 247 );
35 248
36 img->render (pb, 0, 0, img->w, img->h, 0, 0); 249 img->pm = root_pixmap;
250 img->ref = new pixref (root_pm_w, root_pm_h);
251 img->ref->ours = false;
37 252
38 return img; 253 return img;
39} 254}
40 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;
357}
358
359rxvt_img *
360rxvt_img::new_from_file (rxvt_screen *s, const char *filename)
361{
362 GError *err = 0;
363 GdkPixbuf *pb = gdk_pixbuf_new_from_file (filename, &err);
364
365 if (!pb)
366 rxvt_fatal ("rxvt_img::new_from_file: %s\n", err->message);
367
368 rxvt_img *img = new_from_pixbuf (s, pb);
369
370 g_object_unref (pb);
371
372 return img;
373}
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);
45} 392}
46 393
47void 394void
48rxvt_img::fill (const rxvt_color &c) 395rxvt_img::alloc ()
49{ 396{
50 XGCValues gcv; 397 pm = XCreatePixmap (s->display->dpy, s->display->root, w, h, format->depth);
51 gcv.foreground = c; 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;
411}
412
413void
414rxvt_img::unshare ()
415{
416 if (ref->cnt == 1 && ref->ours)
417 return;
418
419 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); 420 GC gc = XCreateGC (s->display->dpy, pm, 0, 0);
53 XFillRectangle (s->display->dpy, pm, gc, 0, 0, w, h); 421 XCopyArea (s->display->dpy, pm, pm2, gc, 0, 0, ref->w, ref->h, 0, 0);
54 XFreeGC (s->display->dpy, gc); 422 XFreeGC (s->display->dpy, gc);
423
424 destroy ();
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 );
462
463 delete img;
55} 464}
56 465
57static void 466static void
58get_gaussian_kernel (int radius, int width, double *kernel, XFixed *params) 467get_gaussian_kernel (int radius, int width, nv *kernel, XFixed *params)
59{ 468{
60 double sigma = radius / 2.0; 469 nv sigma = radius / 2.0;
61 double scale = sqrt (2.0 * M_PI) * sigma; 470 nv scale = sqrt (2.0 * M_PI) * sigma;
62 double sum = 0.0; 471 nv sum = 0.0;
63 472
64 for (int i = 0; i < width; i++) 473 for (int i = 0; i < width; i++)
65 { 474 {
66 double x = i - width / 2; 475 nv x = i - width / 2;
67 kernel[i] = exp (-(x * x) / (2.0 * sigma * sigma)) / scale; 476 kernel[i] = exp (-(x * x) / (2.0 * sigma * sigma)) / scale;
68 sum += kernel[i]; 477 sum += kernel[i];
69 } 478 }
70 479
71 params[0] = XDoubleToFixed (width); 480 params[0] = XDoubleToFixed (width);
73 482
74 for (int i = 0; i < width; i++) 483 for (int i = 0; i < width; i++)
75 params[i+2] = XDoubleToFixed (kernel[i] / sum); 484 params[i+2] = XDoubleToFixed (kernel[i] / sum);
76} 485}
77 486
78void 487rxvt_img *
79rxvt_img::blur (int rh, int rv) 488rxvt_img::blur (int rh, int rv)
80{ 489{
81 if (!(s->display->flags & DISPLAY_HAS_RENDER_CONV)) 490 if (!(s->display->flags & DISPLAY_HAS_RENDER_CONV))
82 return; 491 return clone ();
83 492
84 Display *dpy = s->display->dpy; 493 Display *dpy = s->display->dpy;
85 int size = max (rh, rv) * 2 + 1; 494 int size = max (rh, rv) * 2 + 1;
86 double *kernel = (double *)malloc (size * sizeof (double)); 495 nv *kernel = (nv *)malloc (size * sizeof (nv));
87 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 ();
88 499
89 XRenderPictureAttributes pa; 500 XRenderPictureAttributes pa;
90
91 pa.repeat = RepeatPad; 501 pa.repeat = RepeatPad;
92 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
93 Pixmap tmp = XCreatePixmap (dpy, pm, w, h, format->depth); 505 Pixmap tmp_pm = XCreatePixmap (dpy, pm, w, h, format->depth);
94 Picture dst = XRenderCreatePicture (dpy, tmp, format, CPRepeat, &pa); 506 Picture tmp = XRenderCreatePicture (dpy, tmp_pm , format, CPRepeat, &pa);
95 XFreePixmap (dpy, tmp); 507 XFreePixmap (dpy, tmp_pm);
96 508
97 if (kernel && params) 509 if (kernel && params)
98 { 510 {
99 size = rh * 2 + 1; 511 size = rh * 2 + 1;
100 get_gaussian_kernel (rh, size, kernel, params); 512 get_gaussian_kernel (rh, size, kernel, params);
101 513
102 XRenderSetPictureFilter (dpy, src, FilterConvolution, params, size+2); 514 XRenderSetPictureFilter (dpy, src, FilterConvolution, params, size+2);
103 XRenderComposite (dpy, 515 XRenderComposite (dpy,
104 PictOpSrc, 516 PictOpSrc,
105 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,
106 None, 533 None,
107 dst, 534 dst,
108 0, 0, 535 0, 0,
109 0, 0, 536 0, 0,
110 0, 0, 537 0, 0,
111 w, h); 538 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 } 539 }
130 540
131 free (kernel); 541 free (kernel);
132 free (params); 542 free (params);
543
133 XRenderFreePicture (dpy, src); 544 XRenderFreePicture (dpy, src);
134 XRenderFreePicture (dpy, dst); 545 XRenderFreePicture (dpy, dst);
546 XRenderFreePicture (dpy, tmp);
547
548 return img;
135} 549}
136 550
137static Picture 551static Picture
138create_xrender_mask (Display *dpy, Drawable drawable, Bool argb) 552create_xrender_mask (Display *dpy, Drawable drawable, Bool argb, Bool component_alpha)
139{ 553{
140 Pixmap pixmap = XCreatePixmap (dpy, drawable, 1, 1, argb ? 32 : 8); 554 Pixmap pixmap = XCreatePixmap (dpy, drawable, 1, 1, argb ? 32 : 8);
141 555
142 XRenderPictFormat *format = XRenderFindStandardFormat (dpy, argb ? PictStandardARGB32 : PictStandardA8); 556 XRenderPictFormat *format = XRenderFindStandardFormat (dpy, argb ? PictStandardARGB32 : PictStandardA8);
143 XRenderPictureAttributes pa; 557 XRenderPictureAttributes pa;
144 pa.repeat = True; 558 pa.repeat = RepeatNormal;
559 pa.component_alpha = component_alpha;
145 Picture mask = XRenderCreatePicture (dpy, pixmap, format, CPRepeat, &pa); 560 Picture mask = XRenderCreatePicture (dpy, pixmap, format, CPRepeat | CPComponentAlpha, &pa);
146 561
147 XFreePixmap (dpy, pixmap); 562 XFreePixmap (dpy, pixmap);
148 563
149 return mask; 564 return mask;
150} 565}
151 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
152void 586void
153rxvt_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)
154{ 588{
589 unshare ();
590
155 Display *dpy = s->display->dpy; 591 Display *dpy = s->display->dpy;
156 Picture src = create_xrender_mask (dpy, pm, True);
157 Picture dst = XRenderCreatePicture (dpy, pm, format, 0, 0); 592 Picture dst = XRenderCreatePicture (dpy, pm, format, 0, 0);
158 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;
159 XRenderColor mask_c; 598 XRenderColor mask_c;
160 mask_c.red = float_to_component (r); 599
161 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))
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); 601 XRenderFillRectangle (dpy, PictOpAdd, dst, &mask_c, 0, 0, w, h);
165 602
166 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);
167} 617}
168 618
169void 619void
170rxvt_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)
171{ 621{
172 if (!(s->display->flags & DISPLAY_HAS_RENDER_MUL)) 622 if (r < 0 || g < 0 || b < 0 || a < 0)
173 return; 623 rxvt_fatal ("rxvt_img::contrast does not support negative values.\n");
174 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
175 Display *dpy = s->display->dpy; 634 Display *dpy = s->display->dpy;
176 Picture src = create_xrender_mask (dpy, pm, True); 635
636 Picture src = picture ();
177 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);
178 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;
179 XRenderColor mask_c; 644 XRenderColor mask_c;
180 mask_c.red = float_to_component (r); 645
181 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))
182 mask_c.blue = float_to_component (b); 647 {
183 mask_c.alpha = float_to_component (a);
184 XRenderFillRectangle (dpy, PictOpSrc, src, &mask_c, 0, 0, 1, 1); 648 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); 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;
187} 661}
188 662
189void 663void
190rxvt_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)
191{ 665{
192 //TODO 666 unshare ();
193}
194 667
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; 668 Display *dpy = s->display->dpy;
222 rxvt_img *img = new rxvt_img (s,new_format,w, h); 669 Picture src = img->picture ();
223 Picture src = XRenderCreatePicture (dpy, pm, format, 0, 0); 670 Picture dst = picture ();
224 Picture dst = XRenderCreatePicture (dpy, img->pm, new_format, 0, 0); 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 }
225 679
226 XRenderComposite (dpy, PictOpSrc, src, None, dst, 0, 0, 0, 0, 0, 0, w, h); 680 XRenderComposite (dpy, op, src, mask_p, dst, x - img->x, y - img->y, 0, 0, 0, 0, w, h);
227 681
228 XRenderFreePicture (dpy, src); 682 XRenderFreePicture (dpy, src);
229 XRenderFreePicture (dpy, dst); 683 XRenderFreePicture (dpy, dst);
230 684
685 if (mask_p)
686 XRenderFreePicture (dpy, mask_p);
687}
688
689rxvt_img *
690rxvt_img::clone ()
691{
692 return new rxvt_img (*this);
693}
694
695rxvt_img *
696rxvt_img::reify ()
697{
698 if (x == 0 && y == 0 && w == ref->w && h == ref->h)
699 return clone ();
700
701 Display *dpy = s->display->dpy;
702
703 // add an alpha channel if...
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 ();
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
231 return img; 726 return img;
232} 727}
233 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);
794
795 XTransform xfrm;
796
797 for (int i = 0; i < 3; ++i)
798 for (int j = 0; j < 3; ++j)
799 xfrm.matrix [i][j] = XDoubleToFixed (inv [i][j]);
800
801 XRenderSetPictureFilter (dpy, src, "good", 0, 0);
802 XRenderSetPictureTransform (dpy, src, &xfrm);
803 XRenderComposite (dpy, PictOpSrc, src, None, dst, sx, sy, 0, 0, 0, 0, new_width, new_height);
804
805 XRenderFreePicture (dpy, src);
806 XRenderFreePicture (dpy, dst);
807
808 return img;
809}
810
811rxvt_img *
812rxvt_img::scale (int new_width, int new_height)
813{
814 if (w == new_width && h == new_height)
815 return clone ();
816
817 int old_repeat_mode = repeat;
818 repeat = RepeatPad; // not right, but xrender can't properly scale it seems
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
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 }
234#endif 835#endif
235 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 *
846rxvt_img::convert_format (XRenderPictFormat *new_format, const rgba &bg)
847{
848 if (new_format == format)
849 return clone ();
850
851 rxvt_img *img = new rxvt_img (s, new_format, x, y, w, h, repeat);
852 img->alloc ();
853
854 Display *dpy = s->display->dpy;
855 Picture src = picture ();
856 Picture dst = XRenderCreatePicture (dpy, img->pm, new_format, 0, 0);
857 int op = PictOpSrc;
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
868 XRenderComposite (dpy, op, src, None, dst, 0, 0, 0, 0, 0, 0, w, h);
869
870 XRenderFreePicture (dpy, src);
871 XRenderFreePicture (dpy, dst);
872
873 return img;
874}
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
902#endif
903

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines