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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines