ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/rxvt-unicode/src/rxvtimg.C
(Generate patch)

Comparing rxvt-unicode/src/rxvtimg.C (file contents):
Revision 1.10 by sf-exg, Mon Jun 4 06:59:50 2012 UTC vs.
Revision 1.90 by root, Thu Jun 14 19:44:45 2012 UTC

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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines