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.16 by root, Mon Jun 4 16:12:55 2012 UTC vs.
Revision 1.92 by root, Fri Jun 15 18:05:15 2012 UTC

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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines