ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/rxvt-unicode/src/rxvtimg.C
(Generate patch)

Comparing rxvt-unicode/src/rxvtimg.C (file contents):
Revision 1.13 by root, Mon Jun 4 15:30:41 2012 UTC vs.
Revision 1.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 (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);
198 XRenderFillRectangle (dpy, PictOpSrc, src, &mask_c, 0, 0, 1, 1); 591 XRenderFillRectangle (dpy, PictOpSrc, mul, &mask_c, 0, 0, 1, 1);
199
200 XRenderComposite (dpy, PictOpMultiply, src, None, dst, 0, 0, 0, 0, 0, 0, w, h); 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;
201} 604}
202 605
203void 606void
204rxvt_img::render (GdkPixbuf *pixbuf, int src_x, int src_y, int width, int height, int dst_x, int dst_y) 607rxvt_img::draw (rxvt_img *img, int op, nv mask)
205{ 608{
206 //TODO 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) };
620 XRenderFillRectangle (dpy, PictOpSrc, mask, &mask_c, 0, 0, 1, 1);
621 }
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);
207} 630}
208 631
209rxvt_img * 632rxvt_img *
210rxvt_img::clone () 633rxvt_img::clone ()
211{ 634{
212 GC gc = XCreateGC (s->display->dpy, pm, 0, 0); 635 return new rxvt_img (*this);
213 Pixmap pm2 = XCreatePixmap (s->display->dpy, pm, w, h, format->depth);
214 XCopyArea (s->display->dpy, pm, pm2, gc, 0, 0, w, h, 0, 0);
215 XFreeGC (s->display->dpy, gc);
216 return new rxvt_img (s, format, w, h, pm2);
217} 636}
218 637
219rxvt_img * 638rxvt_img *
220rxvt_img::transform (int new_width, int new_height, int repeat, double matrix[9]) 639rxvt_img::reify ()
221{ 640{
222 rxvt_img *img = new rxvt_img (s, format, new_width, new_height); 641 if (x == 0 && y == 0 && w == ref->w && h == ref->h)
642 return clone ();
223 643
224 Display *dpy = s->display->dpy; 644 Display *dpy = s->display->dpy;
225 XRenderPictureAttributes pa; 645
226 pa.repeat = repeat; 646 // add an alpha channel if...
227 Picture src = XRenderCreatePicture (dpy, pm, format, CPRepeat, &pa); 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 ();
228 Picture dst = XRenderCreatePicture (dpy, img->pm, img->format, 0, 0); 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
661 XRenderComposite (dpy, PictOpSrc, src, None, dst, 0, 0, 0, 0, x, y, ref->w, ref->h);
662 }
663 else
664 XRenderComposite (dpy, PictOpSrc, src, None, dst, -x, -y, 0, 0, 0, 0, w, h);
665
666 XRenderFreePicture (dpy, src);
667 XRenderFreePicture (dpy, dst);
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)
681 {
682 img->w = width;
683 img->h = height;
684
685 rxvt_img *img2 = img->reify ();
686 delete img;
687 img = img2;
688 }
689
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)
702 {
703 nv v;
704
705 v = m.apply1 (i, 0+x, 0+y); rmin [i] = rmax [i] = v; r [i] = v;
706 v = m.apply1 (i, w+x, 0+y); min_it (rmin [i], v); max_it (rmax [i], v);
707 v = m.apply1 (i, 0+x, h+y); min_it (rmin [i], v); max_it (rmax [i], v);
708 v = m.apply1 (i, w+x, h+y); min_it (rmin [i], v); max_it (rmax [i], v);
709 }
710
711 float sx = rmin [0] - x;
712 float sy = rmin [1] - y;
713
714 // TODO: adjust matrix for subpixel accuracy
715 int nx = floor (rmin [0]);
716 int ny = floor (rmin [1]);
717
718 int new_width = ceil (rmax [0] - rmin [0]);
719 int new_height = ceil (rmax [1] - rmin [1]);
720
721 m = mat3x3::translate (-x, -y) * m * mat3x3::translate (x, y);
722
723 mat3x3 inv = m.invert ();
724
725 rxvt_img *img = new rxvt_img (s, format, nx, ny, new_width, new_height, repeat);
726 img->alloc ();
727
728 Display *dpy = s->display->dpy;
729 Picture src = picture ();
730 Picture dst = XRenderCreatePicture (dpy, img->pm, img->format, 0, 0);
229 731
230 XTransform xfrm; 732 XTransform xfrm;
231 733
232 for (int i = 0; i < 3; ++i) 734 for (int i = 0; i < 3; ++i)
233 for (int j = 0; j < 3; ++j) 735 for (int j = 0; j < 3; ++j)
234 xfrm.matrix [i][j] = XDoubleToFixed (matrix [i * 3 + j]); 736 xfrm.matrix [i][j] = XDoubleToFixed (inv [i][j]);
235 737
738 XRenderSetPictureFilter (dpy, src, "good", 0, 0);
236 XRenderSetPictureTransform (dpy, src, &xfrm); 739 XRenderSetPictureTransform (dpy, src, &xfrm);
237 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
238 751
239 XRenderFreePicture (dpy, src); 752 XRenderFreePicture (dpy, src);
240 XRenderFreePicture (dpy, dst); 753 XRenderFreePicture (dpy, dst);
241 754
242 return img; 755 return img;
243} 756}
244 757
245rxvt_img * 758rxvt_img *
246rxvt_img::scale (int new_width, int new_height) 759rxvt_img::scale (int new_width, int new_height)
247{ 760{
248 double matrix[9] = { 761 if (w == new_width && h == new_height)
762 return clone ();
763
764 nv matrix[3][3] = {
249 new_width / (double)w, 0, 0, 765 { new_width / (nv)w, 0, 0 },
250 0, new_height / (double)h, 0, 766 { 0, new_height / (nv)h, 0 },
251 0, 0, 1 767 { 0, 0, 1 }
252 }; 768 };
253 769
254 return transform (new_width, new_height, RepeatNormal, matrix); 770 int old_repeat_mode = repeat;
255} 771 repeat = RepeatPad; // not right, but xrender can't properly scale it seems
256 772
773 rxvt_img *img = transform (matrix);
774
775 repeat = old_repeat_mode;
776 img->repeat = repeat;
777
778 return img;
779}
780
257rxvt_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 *
258rxvt_img::convert_to (XRenderPictFormat *new_format) 808rxvt_img::convert_format (XRenderPictFormat *new_format, const rgba &bg)
259{ 809{
810 if (new_format == format)
811 return clone ();
812
260 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 ();
261 815
262 Display *dpy = s->display->dpy; 816 Display *dpy = s->display->dpy;
263 Picture src = XRenderCreatePicture (dpy, pm, format, 0, 0); 817 Picture src = picture ();
264 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;
265 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
266 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);
267 831
268 XRenderFreePicture (dpy, src); 832 XRenderFreePicture (dpy, src);
269 XRenderFreePicture (dpy, dst); 833 XRenderFreePicture (dpy, dst);
270 834
271 return img; 835 return img;
272} 836}
273 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
274#endif 864#endif
275 865

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines