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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines