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.20 by root, Tue Jun 5 14:07:47 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_pixbuf (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);
195 mask_c.green = float_to_component (g);
196 mask_c.blue = float_to_component (b);
197 mask_c.alpha = float_to_component (a);
198 XRenderFillRectangle (dpy, PictOpSrc, src, &mask_c, 0, 0, 1, 1);
199 622
200 XRenderComposite (dpy, PictOpMultiply, src, None, dst, 0, 0, 0, 0, 0, 0, w, h); 623 if (extract (0, 65535, r, g, b, a, mask_c.red, mask_c.green, mask_c.blue, mask_c.alpha))
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 Display *dpy = s->display->dpy;
207
208 if (s->visual->c_class != TrueColor)
209 return false;
210
211 uint32_t red_mask, green_mask, blue_mask, alpha_mask;
212
213 red_mask = (uint32_t)format->direct.redMask << format->direct.red;
214 green_mask = (uint32_t)format->direct.greenMask << format->direct.green;
215 blue_mask = (uint32_t)format->direct.blueMask << format->direct.blue;
216 alpha_mask = (uint32_t)format->direct.alphaMask << format->direct.alpha;
217
218 int width_r = ecb_popcount32 (red_mask);
219 int width_g = ecb_popcount32 (green_mask);
220 int width_b = ecb_popcount32 (blue_mask);
221 int width_a = ecb_popcount32 (alpha_mask);
222
223 if (width_r > 8 || width_g > 8 || width_b > 8 || width_a > 8)
224 return false;
225
226 int sh_r = ecb_ctz32 (red_mask);
227 int sh_g = ecb_ctz32 (green_mask);
228 int sh_b = ecb_ctz32 (blue_mask);
229 int sh_a = ecb_ctz32 (alpha_mask);
230
231 if (width > 32767 || height > 32767)
232 return false;
233
234 XImage *ximage = XCreateImage (dpy, s->visual, format->depth, ZPixmap, 0, 0,
235 width, height, 32, 0);
236 if (!ximage)
237 return false;
238
239 if (height > INT_MAX / ximage->bytes_per_line
240 || !(ximage->data = (char *)malloc (height * ximage->bytes_per_line)))
241 {
242 XDestroyImage (ximage);
243 return false;
244 }
245
246 GC gc = XCreateGC (dpy, pm, 0, 0);
247
248 ximage->byte_order = ecb_big_endian () ? MSBFirst : LSBFirst;
249
250 int rowstride = gdk_pixbuf_get_rowstride (pixbuf);
251 int channels = gdk_pixbuf_get_n_channels (pixbuf);
252 unsigned char *row = gdk_pixbuf_get_pixels (pixbuf) + src_y * rowstride + src_x * channels;
253 char *line = ximage->data;
254
255 rgba c (0, 0, 0);
256
257 if (channels == 4 && alpha_mask == 0)
258 {
259 //pix_colors[Color_bg].get (c);
260 //TODO
261 c.r = 0xffff; c.g = 0xc0c0; c.b = 0xcbcb;//D
262 c.r >>= 8;
263 c.g >>= 8;
264 c.b >>= 8;
265 }
266
267 for (int y = 0; y < height; y++)
268 {
269 for (int x = 0; x < width; x++)
270 { 624 {
271 unsigned char *pixel = row + x * channels; 625 XRenderFillRectangle (dpy, PictOpSrc, mul, &mask_c, 0, 0, 1, 1);
272 uint32_t value; 626 XRenderComposite (dpy, PictOpAdd, src, mul, dst, 0, 0, 0, 0, 0, 0, w, h);
273 unsigned char r, g, b, a;
274
275 if (channels == 4)
276 {
277 a = pixel[3];
278 r = (pixel[0] * a + c.r * (0xff - a)) / 0xff;
279 g = (pixel[1] * a + c.g * (0xff - a)) / 0xff;
280 b = (pixel[2] * a + c.b * (0xff - a)) / 0xff;
281 }
282 else
283 {
284 a = 0xff;
285 r = pixel[0];
286 g = pixel[1];
287 b = pixel[2];
288 }
289
290 value = ((r >> (8 - width_r)) << sh_r)
291 | ((g >> (8 - width_g)) << sh_g)
292 | ((b >> (8 - width_b)) << sh_b)
293 | ((a >> (8 - width_a)) << sh_a);
294
295 if (ximage->bits_per_pixel == 32)
296 ((uint32_t *)line)[x] = value;
297 else
298 XPutPixel (ximage, x, y, value);
299 } 627 }
628 }
300 629
301 row += rowstride; 630 XRenderFreePicture (dpy, mul);
302 line += ximage->bytes_per_line; 631 XRenderFreePicture (dpy, dst);
632 XRenderFreePicture (dpy, src);
633
634 ::swap (img->ref, ref);
635 ::swap (img->pm , pm );
636
637 delete img;
638}
639
640void
641rxvt_img::draw (rxvt_img *img, int op, nv mask)
642{
643 unshare ();
644
645 Display *dpy = s->display->dpy;
646 Picture src = img->picture ();
647 Picture dst = picture ();
648 Picture mask_p = 0;
649
650 if (mask != 1.)
303 } 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 }
304 656
305 XPutImage (dpy, pm, gc, ximage, 0, 0, dst_x, dst_y, width, height); 657 XRenderComposite (dpy, op, src, mask_p, dst, x - img->x, y - img->y, 0, 0, 0, 0, w, h);
306 XDestroyImage (ximage);
307 XFreeGC (dpy, gc);
308
309 return true;
310}
311
312rxvt_img *
313rxvt_img::clone ()
314{
315 rxvt_img *img = new rxvt_img (s, format, w, h);
316
317 GC gc = XCreateGC (s->display->dpy, pm, 0, 0);
318 XCopyArea (s->display->dpy, pm, img->pm, gc, 0, 0, w, h, 0, 0);
319 XFreeGC (s->display->dpy, gc);
320
321 return img;
322}
323
324rxvt_img *
325rxvt_img::sub_rect (int x, int y, int width, int height, int repeat)
326{
327 rxvt_img *img = new rxvt_img (s, format, width, height);
328
329 Display *dpy = s->display->dpy;
330 XRenderPictureAttributes pa;
331 pa.repeat = repeat;
332 Picture src = XRenderCreatePicture (dpy, pm, format, CPRepeat, &pa);
333 Picture dst = XRenderCreatePicture (dpy, img->pm, img->format, 0, 0);
334
335 XRenderComposite (dpy, PictOpSrc, src, None, dst, x, y, 0, 0, 0, 0, width, height);
336 658
337 XRenderFreePicture (dpy, src); 659 XRenderFreePicture (dpy, src);
338 XRenderFreePicture (dpy, dst); 660 XRenderFreePicture (dpy, dst);
339 661
340 return img; 662 if (mask_p)
663 XRenderFreePicture (dpy, mask_p);
341} 664}
342 665
343rxvt_img * 666rxvt_img *
344rxvt_img::transform (int new_width, int new_height, double matrix[9], int repeat) 667rxvt_img::clone ()
345{ 668{
346 rxvt_img *img = new rxvt_img (s, format, new_width, new_height); 669 return new rxvt_img (*this);
670}
347 671
672rxvt_img *
673rxvt_img::reify ()
674{
675 if (x == 0 && y == 0 && w == ref->w && h == ref->h)
676 return clone ();
677
348 Display *dpy = s->display->dpy; 678 Display *dpy = s->display->dpy;
349 XRenderPictureAttributes pa; 679
350 pa.repeat = repeat; 680 // add an alpha channel if...
351 Picture src = XRenderCreatePicture (dpy, pm, format, CPRepeat, &pa); 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 ();
352 Picture dst = XRenderCreatePicture (dpy, img->pm, img->format, 0, 0); 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);
353 771
354 XTransform xfrm; 772 XTransform xfrm;
355 773
356 for (int i = 0; i < 3; ++i) 774 for (int i = 0; i < 3; ++i)
357 for (int j = 0; j < 3; ++j) 775 for (int j = 0; j < 3; ++j)
358 xfrm.matrix [i][j] = XDoubleToFixed (matrix [i * 3 + j]); 776 xfrm.matrix [i][j] = XDoubleToFixed (inv [i][j]);
359 777
360 XRenderSetPictureFilter (dpy, src, "good", 0, 0); 778 XRenderSetPictureFilter (dpy, src, "good", 0, 0);
361 XRenderSetPictureTransform (dpy, src, &xfrm); 779 XRenderSetPictureTransform (dpy, src, &xfrm);
362 XRenderComposite (dpy, PictOpSrc, src, None, dst, 0, 0, 0, 0, 0, 0, new_width, new_height); 780 XRenderComposite (dpy, PictOpSrc, src, None, dst, sx, sy, 0, 0, 0, 0, new_width, new_height);
363 781
364 XRenderFreePicture (dpy, src); 782 XRenderFreePicture (dpy, src);
365 XRenderFreePicture (dpy, dst); 783 XRenderFreePicture (dpy, dst);
366 784
367 return img; 785 return img;
368} 786}
369 787
370rxvt_img * 788rxvt_img *
371rxvt_img::scale (int new_width, int new_height) 789rxvt_img::scale (int new_width, int new_height)
372{ 790{
373 double matrix[9] = { 791 if (w == new_width && h == new_height)
374 w / (double)new_width, 0, 0, 792 return clone ();
375 0, h / (double)new_height, 0,
376 0, 0, 1
377 };
378 793
379 return transform (new_width, new_height, matrix); 794 int old_repeat_mode = repeat;
380} 795 repeat = RepeatPad; // not right, but xrender can't properly scale it seems
381 796
382rxvt_img * 797 rxvt_img *img = transform (mat3x3::scale (new_width / (nv)w, new_height / (nv)h));
383rxvt_img::rotate (int new_width, int new_height, int x, int y, double phi, int repeat)
384{
385 double s = sin (phi);
386 double c = cos (phi);
387 798
388 double matrix[9] = { 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
389 c, -s, -c * x + s * y + x, 809 { c, -s, cx - c * cx + s * cy },
390 s, c, -s * x - c * y + y, 810 { s, c, cy - s * cx - c * cy },
391 0, 0, 1 811 { 0, 0, 1 }
392 }; 812#endif
393 813
394 return transform (new_width, new_height, matrix, repeat); 814 move (-cx, -cy);
395} 815 rxvt_img *img = transform (mat3x3::rotate (phi));
816 move ( cx, cy);
817 img->move (cx, cy);
396 818
819 return img;
820}
821
397rxvt_img * 822rxvt_img *
398rxvt_img::convert_to (XRenderPictFormat *new_format) 823rxvt_img::convert_format (XRenderPictFormat *new_format, const rgba &bg)
399{ 824{
825 if (new_format == format)
826 return clone ();
827
400 rxvt_img *img = new rxvt_img (s, new_format, w, h); 828 rxvt_img *img = new rxvt_img (s, new_format, x, y, w, h, repeat);
829 img->alloc ();
401 830
402 Display *dpy = s->display->dpy; 831 Display *dpy = s->display->dpy;
403 Picture src = XRenderCreatePicture (dpy, pm, format, 0, 0); 832 Picture src = picture ();
404 Picture dst = XRenderCreatePicture (dpy, img->pm, new_format, 0, 0); 833 Picture dst = XRenderCreatePicture (dpy, img->pm, new_format, 0, 0);
834 int op = PictOpSrc;
405 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
406 XRenderComposite (dpy, PictOpSrc, src, None, dst, 0, 0, 0, 0, 0, 0, w, h); 845 XRenderComposite (dpy, op, src, None, dst, 0, 0, 0, 0, 0, 0, w, h);
407 846
408 XRenderFreePicture (dpy, src); 847 XRenderFreePicture (dpy, src);
409 XRenderFreePicture (dpy, dst); 848 XRenderFreePicture (dpy, dst);
410 849
411 return img; 850 return img;
412} 851}
413 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
414#endif 879#endif
415 880

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines