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.15 by root, Mon Jun 4 16:03:32 2012 UTC vs.
Revision 1.97 by sf-exg, Sun Jun 17 17:06:47 2012 UTC

1/*----------------------------------------------------------------------*
2 * File: rxvtimg.C
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_pixbuf (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); 648 XRenderFillRectangle (dpy, PictOpSrc, mul, &mask_c, 0, 0, 1, 1);
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;
661}
662
663void
664rxvt_img::draw (rxvt_img *img, int op, nv mask)
665{
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) };
198 XRenderFillRectangle (dpy, PictOpSrc, src, &mask_c, 0, 0, 1, 1); 677 XRenderFillRectangle (dpy, PictOpSrc, mask, &mask_c, 0, 0, 1, 1);
678 }
199 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);
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
200 XRenderComposite (dpy, PictOpMultiply, src, None, dst, 0, 0, 0, 0, 0, 0, w, h); 718 XRenderComposite (dpy, PictOpSrc, src, None, dst, 0, 0, 0, 0, x, y, ref->w, ref->h);
201}
202
203bool
204rxvt_img::render_pixbuf (GdkPixbuf *pixbuf, int src_x, int src_y, int width, int height, int dst_x, int dst_y)
205{
206 bool argb = format->id == PictStandardARGB32;
207
208 Display *dpy = s->display->dpy;
209
210 if (s->visual->c_class != TrueColor)
211 return false;
212
213 uint32_t red_mask, green_mask, blue_mask, alpha_mask;
214
215 if (argb)
216 {
217 red_mask = 0xff << 16;
218 green_mask = 0xff << 8;
219 blue_mask = 0xff;
220 alpha_mask = 0xff << 24;
221 } 719 }
222 else 720 else
223 { 721 XRenderComposite (dpy, PictOpSrc, src, None, dst, -x, -y, 0, 0, 0, 0, w, h);
224 red_mask = s->visual->red_mask; 722
225 green_mask = s->visual->green_mask; 723 XRenderFreePicture (dpy, src);
226 blue_mask = s->visual->blue_mask; 724 XRenderFreePicture (dpy, dst);
227 alpha_mask = (uint32_t)format->direct.alphaMask << format->direct.alpha; 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)
228 } 738 {
739 img->w = width;
740 img->h = height;
229 741
230 int width_r = ecb_popcount32 (red_mask); 742 rxvt_img *img2 = img->reify ();
231 int width_g = ecb_popcount32 (green_mask); 743 delete img;
232 int width_b = ecb_popcount32 (blue_mask); 744 img = img2;
233 int width_a = ecb_popcount32 (alpha_mask);
234
235 if (width_r > 8 || width_g > 8 || width_b > 8 || width_a > 8)
236 return false;
237
238 int sh_r = ecb_ctz32 (red_mask);
239 int sh_g = ecb_ctz32 (green_mask);
240 int sh_b = ecb_ctz32 (blue_mask);
241 int sh_a = ecb_ctz32 (alpha_mask);
242
243 if (width > 32767 || height > 32767)
244 return false;
245
246 XImage *ximage = XCreateImage (dpy, s->visual, argb ? 32 : format->depth, ZPixmap, 0, 0,
247 width, height, 32, 0);
248 if (!ximage)
249 return false;
250
251 if (height > INT_MAX / ximage->bytes_per_line
252 || !(ximage->data = (char *)malloc (height * ximage->bytes_per_line)))
253 { 745 }
254 XDestroyImage (ximage); 746
255 return false; 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)
256 } 765 {
766 nv v;
257 767
258 GC gc = XCreateGC (dpy, pm, 0, 0); 768 v = m.apply1 (i, 0+x, 0+y); rmin [i] = rmax [i] = v; r [i] = v;
259 769 v = m.apply1 (i, w+x, 0+y); min_it (rmin [i], v); max_it (rmax [i], v);
260 ximage->byte_order = ecb_big_endian () ? MSBFirst : LSBFirst; 770 v = m.apply1 (i, 0+x, h+y); min_it (rmin [i], v); max_it (rmax [i], v);
261 771 v = m.apply1 (i, w+x, h+y); min_it (rmin [i], v); max_it (rmax [i], v);
262 int rowstride = gdk_pixbuf_get_rowstride (pixbuf);
263 int channels = gdk_pixbuf_get_n_channels (pixbuf);
264 unsigned char *row = gdk_pixbuf_get_pixels (pixbuf) + src_y * rowstride + src_x * channels;
265 char *line = ximage->data;
266
267 rgba c (0, 0, 0);
268
269 if (channels == 4 && alpha_mask == 0)
270 { 772 }
271 //pix_colors[Color_bg].get (c);
272 //TODO
273 c.r = 0xffff; c.g = 0xc0c0; c.b = 0xcbcb;//D
274 c.r >>= 8;
275 c.g >>= 8;
276 c.b >>= 8;
277 }
278 773
279 for (int y = 0; y < height; y++) 774 float sx = rmin [0] - x;
280 { 775 float sy = rmin [1] - y;
281 for (int x = 0; x < width; x++)
282 {
283 unsigned char *pixel = row + x * channels;
284 uint32_t value;
285 unsigned char r, g, b, a;
286 776
287 if (channels == 4) 777 // TODO: adjust matrix for subpixel accuracy
288 { 778 int nx = floor (rmin [0]);
289 a = pixel[3]; 779 int ny = floor (rmin [1]);
290 r = (pixel[0] * a + c.r * (0xff - a)) / 0xff;
291 g = (pixel[1] * a + c.g * (0xff - a)) / 0xff;
292 b = (pixel[2] * a + c.b * (0xff - a)) / 0xff;
293 }
294 else
295 {
296 a = 0xff;
297 r = pixel[0];
298 g = pixel[1];
299 b = pixel[2];
300 }
301 780
302 value = ((r >> (8 - width_r)) << sh_r) 781 int new_width = ceil (rmax [0] - rmin [0]);
303 | ((g >> (8 - width_g)) << sh_g) 782 int new_height = ceil (rmax [1] - rmin [1]);
304 | ((b >> (8 - width_b)) << sh_b)
305 | ((a >> (8 - width_a)) << sh_a);
306 783
307 if (ximage->bits_per_pixel == 32) 784 m = mat3x3::translate (-x, -y) * m * mat3x3::translate (x, y);
308 ((uint32_t *)line)[x] = value;
309 else
310 XPutPixel (ximage, x, y, value);
311 }
312 785
313 row += rowstride; 786 mat3x3 inv = m.invert ();
314 line += ximage->bytes_per_line;
315 }
316 787
317 XPutImage (dpy, pm, gc, ximage, 0, 0, dst_x, dst_y, width, height);
318 XDestroyImage (ximage);
319 XFreeGC (dpy, gc);
320
321 return true;
322}
323
324rxvt_img *
325rxvt_img::clone ()
326{
327 GC gc = XCreateGC (s->display->dpy, pm, 0, 0);
328 Pixmap pm2 = XCreatePixmap (s->display->dpy, pm, w, h, format->depth);
329 XCopyArea (s->display->dpy, pm, pm2, gc, 0, 0, w, h, 0, 0);
330 XFreeGC (s->display->dpy, gc);
331 return new rxvt_img (s, format, w, h, pm2);
332}
333
334rxvt_img *
335rxvt_img::transform (int new_width, int new_height, int repeat, double matrix[9])
336{
337 rxvt_img *img = new rxvt_img (s, format, new_width, new_height); 788 rxvt_img *img = new rxvt_img (s, format, nx, ny, new_width, new_height, repeat);
789 img->alloc ();
338 790
339 Display *dpy = s->display->dpy; 791 Display *dpy = s->display->dpy;
340 XRenderPictureAttributes pa; 792 Picture src = picture ();
341 pa.repeat = repeat;
342 Picture src = XRenderCreatePicture (dpy, pm, format, CPRepeat, &pa);
343 Picture dst = XRenderCreatePicture (dpy, img->pm, img->format, 0, 0); 793 Picture dst = XRenderCreatePicture (dpy, img->pm, img->format, 0, 0);
344 794
345 XTransform xfrm; 795 XTransform xfrm;
346 796
347 for (int i = 0; i < 3; ++i) 797 for (int i = 0; i < 3; ++i)
348 for (int j = 0; j < 3; ++j) 798 for (int j = 0; j < 3; ++j)
349 xfrm.matrix [i][j] = XDoubleToFixed (matrix [i * 3 + j]); 799 xfrm.matrix [i][j] = XDoubleToFixed (inv [i][j]);
350 800
801 XRenderSetPictureFilter (dpy, src, "good", 0, 0);
351 XRenderSetPictureTransform (dpy, src, &xfrm); 802 XRenderSetPictureTransform (dpy, src, &xfrm);
352 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);
353 804
354 XRenderFreePicture (dpy, src); 805 XRenderFreePicture (dpy, src);
355 XRenderFreePicture (dpy, dst); 806 XRenderFreePicture (dpy, dst);
356 807
357 return img; 808 return img;
358} 809}
359 810
360rxvt_img * 811rxvt_img *
361rxvt_img::scale (int new_width, int new_height) 812rxvt_img::scale (int new_width, int new_height)
362{ 813{
363 double matrix[9] = { 814 if (w == new_width && h == new_height)
364 new_width / (double)w, 0, 0, 815 return clone ();
365 0, new_height / (double)h, 0,
366 0, 0, 1
367 };
368 816
369 return transform (new_width, new_height, RepeatNormal, matrix); 817 int old_repeat_mode = repeat;
370} 818 repeat = RepeatPad; // not right, but xrender can't properly scale it seems
371 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
372rxvt_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 *
373rxvt_img::convert_to (XRenderPictFormat *new_format) 846rxvt_img::convert_format (XRenderPictFormat *new_format, const rgba &bg)
374{ 847{
848 if (new_format == format)
849 return clone ();
850
375 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 ();
376 853
377 Display *dpy = s->display->dpy; 854 Display *dpy = s->display->dpy;
378 Picture src = XRenderCreatePicture (dpy, pm, format, 0, 0); 855 Picture src = picture ();
379 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;
380 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
381 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);
382 869
383 XRenderFreePicture (dpy, src); 870 XRenderFreePicture (dpy, src);
384 XRenderFreePicture (dpy, dst); 871 XRenderFreePicture (dpy, dst);
385 872
386 return img; 873 return img;
387} 874}
388 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
389#endif 902#endif
390 903

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines