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.21 by sf-exg, Tue Jun 5 14:59:44 2012 UTC vs.
Revision 1.92 by root, Fri Jun 15 18:05:15 2012 UTC

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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines