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.10 by sf-exg, Mon Jun 4 06:59:50 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{
18} 156}
19 157
20rxvt_img * 158rxvt_img::rxvt_img (const rxvt_img &img)
21rxvt_img::new_from_file (rxvt_screen *s, const char *filename) 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)
22{ 160{
23 GError *err; 161 ++ref->cnt;
24 GdkPixbuf *pb = gdk_pixbuf_new_from_file (filename, &err); 162}
25 163
26 if (!pb) 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))
27 return 0; 181 return 0;
28 182
29 rxvt_img *img = new rxvt_img ( 183 rxvt_img *img = new rxvt_img (
30 s, 184 s,
31 XRenderFindStandardFormat (s->display->dpy, gdk_pixbuf_get_has_alpha (pb) ? PictStandardARGB32 : PictStandardRGB24), 185 XRenderFindVisualFormat (dpy, DefaultVisual (dpy, s->display->screen)),
32 gdk_pixbuf_get_width (pb), 186 0,
33 gdk_pixbuf_get_height (pb) 187 0,
188 root_pm_w,
189 root_pm_h
34 ); 190 );
35 191
36 img->render (pb, 0, 0, img->w, img->h, 0, 0); 192 img->pm = root_pixmap;
193 img->ref = new pixref (root_pm_w, root_pm_h);
194 img->ref->ours = false;
37 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;
300}
301
302rxvt_img *
303rxvt_img::new_from_file (rxvt_screen *s, const char *filename)
304{
305 GError *err = 0;
306 GdkPixbuf *pb = gdk_pixbuf_new_from_file (filename, &err);
307
308 if (!pb)
309 rxvt_fatal ("rxvt_img::new_from_file: %s\n", err->message);
310
311 rxvt_img *img = new_from_pixbuf (s, pb);
312
313 g_object_unref (pb);
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);
45} 335}
46 336
47void 337void
48rxvt_img::fill (const rxvt_color &c) 338rxvt_img::alloc ()
49{ 339{
50 XGCValues gcv; 340 pm = XCreatePixmap (s->display->dpy, s->display->root, w, h, format->depth);
51 gcv.foreground = c; 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;
354}
355
356void
357rxvt_img::unshare ()
358{
359 if (ref->cnt == 1 && ref->ours)
360 return;
361
362 Pixmap pm2 = XCreatePixmap (s->display->dpy, s->display->root, ref->w, ref->h, format->depth);
52 GC gc = XCreateGC (s->display->dpy, pm, GCForeground, &gcv); 363 GC gc = XCreateGC (s->display->dpy, pm, 0, 0);
53 XFillRectangle (s->display->dpy, pm, gc, 0, 0, w, h); 364 XCopyArea (s->display->dpy, pm, pm2, gc, 0, 0, ref->w, ref->h, 0, 0);
54 XFreeGC (s->display->dpy, gc); 365 XFreeGC (s->display->dpy, gc);
366
367 destroy ();
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 );
405
406 delete img;
55} 407}
56 408
57static void 409static void
58get_gaussian_kernel (int radius, int width, double *kernel, XFixed *params) 410get_gaussian_kernel (int radius, int width, nv *kernel, XFixed *params)
59{ 411{
60 double sigma = radius / 2.0; 412 nv sigma = radius / 2.0;
61 double scale = sqrt (2.0 * M_PI) * sigma; 413 nv scale = sqrt (2.0 * M_PI) * sigma;
62 double sum = 0.0; 414 nv sum = 0.0;
63 415
64 for (int i = 0; i < width; i++) 416 for (int i = 0; i < width; i++)
65 { 417 {
66 double x = i - width / 2; 418 nv x = i - width / 2;
67 kernel[i] = exp (-(x * x) / (2.0 * sigma * sigma)) / scale; 419 kernel[i] = exp (-(x * x) / (2.0 * sigma * sigma)) / scale;
68 sum += kernel[i]; 420 sum += kernel[i];
69 } 421 }
70 422
71 params[0] = XDoubleToFixed (width); 423 params[0] = XDoubleToFixed (width);
73 425
74 for (int i = 0; i < width; i++) 426 for (int i = 0; i < width; i++)
75 params[i+2] = XDoubleToFixed (kernel[i] / sum); 427 params[i+2] = XDoubleToFixed (kernel[i] / sum);
76} 428}
77 429
78void 430rxvt_img *
79rxvt_img::blur (int rh, int rv) 431rxvt_img::blur (int rh, int rv)
80{ 432{
81 if (!(s->display->flags & DISPLAY_HAS_RENDER_CONV)) 433 if (!(s->display->flags & DISPLAY_HAS_RENDER_CONV))
82 return; 434 return clone ();
83 435
84 Display *dpy = s->display->dpy; 436 Display *dpy = s->display->dpy;
85 int size = max (rh, rv) * 2 + 1; 437 int size = max (rh, rv) * 2 + 1;
86 double *kernel = (double *)malloc (size * sizeof (double)); 438 nv *kernel = (nv *)malloc (size * sizeof (nv));
87 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 ();
88 442
89 XRenderPictureAttributes pa; 443 XRenderPictureAttributes pa;
90
91 pa.repeat = RepeatPad; 444 pa.repeat = RepeatPad;
92 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
93 Pixmap tmp = XCreatePixmap (dpy, pm, w, h, format->depth); 448 Pixmap tmp_pm = XCreatePixmap (dpy, pm, w, h, format->depth);
94 Picture dst = XRenderCreatePicture (dpy, tmp, format, CPRepeat, &pa); 449 Picture tmp = XRenderCreatePicture (dpy, tmp_pm , format, CPRepeat, &pa);
95 XFreePixmap (dpy, tmp); 450 XFreePixmap (dpy, tmp_pm);
96 451
97 if (kernel && params) 452 if (kernel && params)
98 { 453 {
99 size = rh * 2 + 1; 454 size = rh * 2 + 1;
100 get_gaussian_kernel (rh, size, kernel, params); 455 get_gaussian_kernel (rh, size, kernel, params);
101 456
102 XRenderSetPictureFilter (dpy, src, FilterConvolution, params, size+2); 457 XRenderSetPictureFilter (dpy, src, FilterConvolution, params, size+2);
103 XRenderComposite (dpy, 458 XRenderComposite (dpy,
104 PictOpSrc, 459 PictOpSrc,
105 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,
106 None, 476 None,
107 dst, 477 dst,
108 0, 0, 478 0, 0,
109 0, 0, 479 0, 0,
110 0, 0, 480 0, 0,
111 w, h); 481 w, h);
112
113 ::swap (src, dst);
114
115 size = rv * 2 + 1;
116 get_gaussian_kernel (rv, size, kernel, params);
117 ::swap (params[0], params[1]);
118
119 XRenderSetPictureFilter (dpy, src, FilterConvolution, params, size+2);
120 XRenderComposite (dpy,
121 PictOpSrc,
122 src,
123 None,
124 dst,
125 0, 0,
126 0, 0,
127 0, 0,
128 w, h);
129 } 482 }
130 483
131 free (kernel); 484 free (kernel);
132 free (params); 485 free (params);
486
133 XRenderFreePicture (dpy, src); 487 XRenderFreePicture (dpy, src);
134 XRenderFreePicture (dpy, dst); 488 XRenderFreePicture (dpy, dst);
489 XRenderFreePicture (dpy, tmp);
490
491 return img;
135} 492}
136 493
137static Picture 494static Picture
138create_xrender_mask (Display *dpy, Drawable drawable, Bool argb) 495create_xrender_mask (Display *dpy, Drawable drawable, Bool argb, Bool component_alpha)
139{ 496{
140 Pixmap pixmap = XCreatePixmap (dpy, drawable, 1, 1, argb ? 32 : 8); 497 Pixmap pixmap = XCreatePixmap (dpy, drawable, 1, 1, argb ? 32 : 8);
141 498
142 XRenderPictFormat *format = XRenderFindStandardFormat (dpy, argb ? PictStandardARGB32 : PictStandardA8); 499 XRenderPictFormat *format = XRenderFindStandardFormat (dpy, argb ? PictStandardARGB32 : PictStandardA8);
143 XRenderPictureAttributes pa; 500 XRenderPictureAttributes pa;
144 pa.repeat = True; 501 pa.repeat = RepeatNormal;
502 pa.component_alpha = component_alpha;
145 Picture mask = XRenderCreatePicture (dpy, pixmap, format, CPRepeat, &pa); 503 Picture mask = XRenderCreatePicture (dpy, pixmap, format, CPRepeat | CPComponentAlpha, &pa);
146 504
147 XFreePixmap (dpy, pixmap); 505 XFreePixmap (dpy, pixmap);
148 506
149 return mask; 507 return mask;
150} 508}
151 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
152void 529void
153rxvt_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)
154{ 531{
532 unshare ();
533
155 Display *dpy = s->display->dpy; 534 Display *dpy = s->display->dpy;
156 Picture src = create_xrender_mask (dpy, pm, True);
157 Picture dst = XRenderCreatePicture (dpy, pm, format, 0, 0); 535 Picture dst = XRenderCreatePicture (dpy, pm, format, 0, 0);
158 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;
159 XRenderColor mask_c; 541 XRenderColor mask_c;
160 mask_c.red = float_to_component (r); 542
161 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))
162 mask_c.blue = float_to_component (b);
163 mask_c.alpha = float_to_component (a);
164 XRenderFillRectangle (dpy, PictOpSrc, src, &mask_c, 0, 0, 1, 1); 544 XRenderFillRectangle (dpy, PictOpAdd, dst, &mask_c, 0, 0, w, h);
165 545
166 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);
167} 560}
168 561
169void 562void
170rxvt_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)
171{ 564{
172 if (!(s->display->flags & DISPLAY_HAS_RENDER_MUL)) 565 if (r < 0 || g < 0 || b < 0 || a < 0)
173 return; 566 rxvt_fatal ("rxvt_img::contrast does not support negative values.\n");
174 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
175 Display *dpy = s->display->dpy; 577 Display *dpy = s->display->dpy;
176 Picture src = create_xrender_mask (dpy, pm, True); 578
579 Picture src = picture ();
177 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);
178 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;
179 XRenderColor mask_c; 587 XRenderColor mask_c;
180 mask_c.red = float_to_component (r); 588
181 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))
182 mask_c.blue = float_to_component (b); 590 {
183 mask_c.alpha = float_to_component (a);
184 XRenderFillRectangle (dpy, PictOpSrc, src, &mask_c, 0, 0, 1, 1); 591 XRenderFillRectangle (dpy, PictOpSrc, mul, &mask_c, 0, 0, 1, 1);
185
186 XRenderComposite (dpy, PictOpMultiply, src, None, dst, 0, 0, 0, 0, 0, 0, w, h); 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;
187} 604}
188 605
189void 606void
190rxvt_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)
191{ 608{
192 //TODO 609 unshare ();
193}
194 610
195rxvt_img *
196rxvt_img::copy ()
197{
198 GC gc = XCreateGC (s->display->dpy, pm, 0, 0);
199 Pixmap pm2 = XCreatePixmap (s->display->dpy, pm, w, h, format->depth);
200 XCopyArea (s->display->dpy, pm, pm2, gc, 0, 0, w, h, 0, 0);
201 XFreeGC (s->display->dpy, gc);
202 return new rxvt_img (s, format, w, h, pm2);
203}
204
205rxvt_img *
206rxvt_img::transform (int new_width, int new_height, double matrix[16])
207{
208 //TODO
209}
210
211rxvt_img *
212rxvt_img::scale (int new_width, int new_height)
213{
214 // use transform
215 //TODO
216}
217
218rxvt_img *
219rxvt_img::convert_to (XRenderPictFormat *new_format)
220{
221 rxvt_img *img = new rxvt_img (s, new_format, w, h);
222
223 Display *dpy = s->display->dpy; 611 Display *dpy = s->display->dpy;
224 Picture src = XRenderCreatePicture (dpy, pm, format, 0, 0); 612 Picture src = img->picture ();
225 Picture dst = XRenderCreatePicture (dpy, img->pm, new_format, 0, 0); 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 }
226 622
227 XRenderComposite (dpy, PictOpSrc, src, None, dst, 0, 0, 0, 0, 0, 0, w, h); 623 XRenderComposite (dpy, op, src, mask_p, dst, x - img->x, y - img->y, 0, 0, 0, 0, w, h);
228 624
229 XRenderFreePicture (dpy, src); 625 XRenderFreePicture (dpy, src);
230 XRenderFreePicture (dpy, dst); 626 XRenderFreePicture (dpy, dst);
231 627
232 return img; 628 if (mask_p)
629 XRenderFreePicture (dpy, mask_p);
233} 630}
234 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
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);
731
732 XTransform xfrm;
733
734 for (int i = 0; i < 3; ++i)
735 for (int j = 0; j < 3; ++j)
736 xfrm.matrix [i][j] = XDoubleToFixed (inv [i][j]);
737
738 XRenderSetPictureFilter (dpy, src, "good", 0, 0);
739 XRenderSetPictureTransform (dpy, src, &xfrm);
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);
235#endif 750#endif
236 751
752 XRenderFreePicture (dpy, src);
753 XRenderFreePicture (dpy, dst);
754
755 return img;
756}
757
758rxvt_img *
759rxvt_img::scale (int new_width, int new_height)
760{
761 if (w == new_width && h == new_height)
762 return clone ();
763
764 nv matrix[3][3] = {
765 { new_width / (nv)w, 0, 0 },
766 { 0, new_height / (nv)h, 0 },
767 { 0, 0, 1 }
768 };
769
770 int old_repeat_mode = repeat;
771 repeat = RepeatPad; // not right, but xrender can't properly scale it seems
772
773 rxvt_img *img = transform (matrix);
774
775 repeat = old_repeat_mode;
776 img->repeat = repeat;
777
778 return img;
779}
780
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 *
808rxvt_img::convert_format (XRenderPictFormat *new_format, const rgba &bg)
809{
810 if (new_format == format)
811 return clone ();
812
813 rxvt_img *img = new rxvt_img (s, new_format, x, y, w, h, repeat);
814 img->alloc ();
815
816 Display *dpy = s->display->dpy;
817 Picture src = picture ();
818 Picture dst = XRenderCreatePicture (dpy, img->pm, new_format, 0, 0);
819 int op = PictOpSrc;
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
830 XRenderComposite (dpy, op, src, None, dst, 0, 0, 0, 0, 0, 0, w, h);
831
832 XRenderFreePicture (dpy, src);
833 XRenderFreePicture (dpy, dst);
834
835 return img;
836}
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
864#endif
865

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines