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.15 by root, Mon Jun 4 16:03:32 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); 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); 625 XRenderFillRectangle (dpy, PictOpSrc, mul, &mask_c, 0, 0, 1, 1);
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;
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.)
651 {
652 mask_p = create_xrender_mask (dpy, img->pm, False, False);
653 XRenderColor mask_c = { 0, 0, 0, float_to_component (mask) };
198 XRenderFillRectangle (dpy, PictOpSrc, src, &mask_c, 0, 0, 1, 1); 654 XRenderFillRectangle (dpy, PictOpSrc, mask, &mask_c, 0, 0, 1, 1);
655 }
199 656
657 XRenderComposite (dpy, op, src, mask_p, dst, x - img->x, y - img->y, 0, 0, 0, 0, w, h);
658
659 XRenderFreePicture (dpy, src);
660 XRenderFreePicture (dpy, dst);
661
662 if (mask_p)
663 XRenderFreePicture (dpy, mask_p);
664}
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
200 XRenderComposite (dpy, PictOpMultiply, src, None, dst, 0, 0, 0, 0, 0, 0, w, h); 695 XRenderComposite (dpy, PictOpSrc, src, None, dst, 0, 0, 0, 0, x, y, ref->w, ref->h);
201}
202
203bool
204rxvt_img::render_pixbuf (GdkPixbuf *pixbuf, int src_x, int src_y, int width, int height, int dst_x, int dst_y)
205{
206 bool argb = format->id == PictStandardARGB32;
207
208 Display *dpy = s->display->dpy;
209
210 if (s->visual->c_class != TrueColor)
211 return false;
212
213 uint32_t red_mask, green_mask, blue_mask, alpha_mask;
214
215 if (argb)
216 {
217 red_mask = 0xff << 16;
218 green_mask = 0xff << 8;
219 blue_mask = 0xff;
220 alpha_mask = 0xff << 24;
221 } 696 }
222 else 697 else
223 { 698 XRenderComposite (dpy, PictOpSrc, src, None, dst, -x, -y, 0, 0, 0, 0, w, h);
224 red_mask = s->visual->red_mask; 699
225 green_mask = s->visual->green_mask; 700 XRenderFreePicture (dpy, src);
226 blue_mask = s->visual->blue_mask; 701 XRenderFreePicture (dpy, dst);
227 alpha_mask = (uint32_t)format->direct.alphaMask << format->direct.alpha; 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)
228 } 715 {
716 img->w = width;
717 img->h = height;
229 718
230 int width_r = ecb_popcount32 (red_mask); 719 rxvt_img *img2 = img->reify ();
231 int width_g = ecb_popcount32 (green_mask); 720 delete img;
232 int width_b = ecb_popcount32 (blue_mask); 721 img = img2;
233 int width_a = ecb_popcount32 (alpha_mask);
234
235 if (width_r > 8 || width_g > 8 || width_b > 8 || width_a > 8)
236 return false;
237
238 int sh_r = ecb_ctz32 (red_mask);
239 int sh_g = ecb_ctz32 (green_mask);
240 int sh_b = ecb_ctz32 (blue_mask);
241 int sh_a = ecb_ctz32 (alpha_mask);
242
243 if (width > 32767 || height > 32767)
244 return false;
245
246 XImage *ximage = XCreateImage (dpy, s->visual, argb ? 32 : format->depth, ZPixmap, 0, 0,
247 width, height, 32, 0);
248 if (!ximage)
249 return false;
250
251 if (height > INT_MAX / ximage->bytes_per_line
252 || !(ximage->data = (char *)malloc (height * ximage->bytes_per_line)))
253 { 722 }
254 XDestroyImage (ximage); 723
255 return false; 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)
256 } 742 {
743 nv v;
257 744
258 GC gc = XCreateGC (dpy, pm, 0, 0); 745 v = m.apply1 (i, 0+x, 0+y); rmin [i] = rmax [i] = v; r [i] = v;
259 746 v = m.apply1 (i, w+x, 0+y); min_it (rmin [i], v); max_it (rmax [i], v);
260 ximage->byte_order = ecb_big_endian () ? MSBFirst : LSBFirst; 747 v = m.apply1 (i, 0+x, h+y); min_it (rmin [i], v); max_it (rmax [i], v);
261 748 v = m.apply1 (i, w+x, h+y); min_it (rmin [i], v); max_it (rmax [i], v);
262 int rowstride = gdk_pixbuf_get_rowstride (pixbuf);
263 int channels = gdk_pixbuf_get_n_channels (pixbuf);
264 unsigned char *row = gdk_pixbuf_get_pixels (pixbuf) + src_y * rowstride + src_x * channels;
265 char *line = ximage->data;
266
267 rgba c (0, 0, 0);
268
269 if (channels == 4 && alpha_mask == 0)
270 { 749 }
271 //pix_colors[Color_bg].get (c);
272 //TODO
273 c.r = 0xffff; c.g = 0xc0c0; c.b = 0xcbcb;//D
274 c.r >>= 8;
275 c.g >>= 8;
276 c.b >>= 8;
277 }
278 750
279 for (int y = 0; y < height; y++) 751 float sx = rmin [0] - x;
280 { 752 float sy = rmin [1] - y;
281 for (int x = 0; x < width; x++)
282 {
283 unsigned char *pixel = row + x * channels;
284 uint32_t value;
285 unsigned char r, g, b, a;
286 753
287 if (channels == 4) 754 // TODO: adjust matrix for subpixel accuracy
288 { 755 int nx = floor (rmin [0]);
289 a = pixel[3]; 756 int ny = floor (rmin [1]);
290 r = (pixel[0] * a + c.r * (0xff - a)) / 0xff;
291 g = (pixel[1] * a + c.g * (0xff - a)) / 0xff;
292 b = (pixel[2] * a + c.b * (0xff - a)) / 0xff;
293 }
294 else
295 {
296 a = 0xff;
297 r = pixel[0];
298 g = pixel[1];
299 b = pixel[2];
300 }
301 757
302 value = ((r >> (8 - width_r)) << sh_r) 758 int new_width = ceil (rmax [0] - rmin [0]);
303 | ((g >> (8 - width_g)) << sh_g) 759 int new_height = ceil (rmax [1] - rmin [1]);
304 | ((b >> (8 - width_b)) << sh_b)
305 | ((a >> (8 - width_a)) << sh_a);
306 760
307 if (ximage->bits_per_pixel == 32) 761 m = mat3x3::translate (-x, -y) * m * mat3x3::translate (x, y);
308 ((uint32_t *)line)[x] = value;
309 else
310 XPutPixel (ximage, x, y, value);
311 }
312 762
313 row += rowstride; 763 mat3x3 inv = m.invert ();
314 line += ximage->bytes_per_line;
315 }
316 764
317 XPutImage (dpy, pm, gc, ximage, 0, 0, dst_x, dst_y, width, height);
318 XDestroyImage (ximage);
319 XFreeGC (dpy, gc);
320
321 return true;
322}
323
324rxvt_img *
325rxvt_img::clone ()
326{
327 GC gc = XCreateGC (s->display->dpy, pm, 0, 0);
328 Pixmap pm2 = XCreatePixmap (s->display->dpy, pm, w, h, format->depth);
329 XCopyArea (s->display->dpy, pm, pm2, gc, 0, 0, w, h, 0, 0);
330 XFreeGC (s->display->dpy, gc);
331 return new rxvt_img (s, format, w, h, pm2);
332}
333
334rxvt_img *
335rxvt_img::transform (int new_width, int new_height, int repeat, double matrix[9])
336{
337 rxvt_img *img = new rxvt_img (s, format, new_width, new_height); 765 rxvt_img *img = new rxvt_img (s, format, nx, ny, new_width, new_height, repeat);
766 img->alloc ();
338 767
339 Display *dpy = s->display->dpy; 768 Display *dpy = s->display->dpy;
340 XRenderPictureAttributes pa; 769 Picture src = picture ();
341 pa.repeat = repeat;
342 Picture src = XRenderCreatePicture (dpy, pm, format, CPRepeat, &pa);
343 Picture dst = XRenderCreatePicture (dpy, img->pm, img->format, 0, 0); 770 Picture dst = XRenderCreatePicture (dpy, img->pm, img->format, 0, 0);
344 771
345 XTransform xfrm; 772 XTransform xfrm;
346 773
347 for (int i = 0; i < 3; ++i) 774 for (int i = 0; i < 3; ++i)
348 for (int j = 0; j < 3; ++j) 775 for (int j = 0; j < 3; ++j)
349 xfrm.matrix [i][j] = XDoubleToFixed (matrix [i * 3 + j]); 776 xfrm.matrix [i][j] = XDoubleToFixed (inv [i][j]);
350 777
778 XRenderSetPictureFilter (dpy, src, "good", 0, 0);
351 XRenderSetPictureTransform (dpy, src, &xfrm); 779 XRenderSetPictureTransform (dpy, src, &xfrm);
352 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);
353 781
354 XRenderFreePicture (dpy, src); 782 XRenderFreePicture (dpy, src);
355 XRenderFreePicture (dpy, dst); 783 XRenderFreePicture (dpy, dst);
356 784
357 return img; 785 return img;
358} 786}
359 787
360rxvt_img * 788rxvt_img *
361rxvt_img::scale (int new_width, int new_height) 789rxvt_img::scale (int new_width, int new_height)
362{ 790{
363 double matrix[9] = { 791 if (w == new_width && h == new_height)
364 new_width / (double)w, 0, 0, 792 return clone ();
365 0, new_height / (double)h, 0,
366 0, 0, 1
367 };
368 793
369 return transform (new_width, new_height, RepeatNormal, matrix); 794 int old_repeat_mode = repeat;
370} 795 repeat = RepeatPad; // not right, but xrender can't properly scale it seems
371 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
372rxvt_img * 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 }
812#endif
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 *
373rxvt_img::convert_to (XRenderPictFormat *new_format) 823rxvt_img::convert_format (XRenderPictFormat *new_format, const rgba &bg)
374{ 824{
825 if (new_format == format)
826 return clone ();
827
375 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 ();
376 830
377 Display *dpy = s->display->dpy; 831 Display *dpy = s->display->dpy;
378 Picture src = XRenderCreatePicture (dpy, pm, format, 0, 0); 832 Picture src = picture ();
379 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;
380 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
381 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);
382 846
383 XRenderFreePicture (dpy, src); 847 XRenderFreePicture (dpy, src);
384 XRenderFreePicture (dpy, dst); 848 XRenderFreePicture (dpy, dst);
385 849
386 return img; 850 return img;
387} 851}
388 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
389#endif 879#endif
390 880

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines