ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/rxvt-unicode/src/rxvtimg.C
Revision: 1.51
Committed: Thu Jun 7 20:04:54 2012 UTC (11 years, 11 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.50: +13 -9 lines
Log Message:
*** empty log message ***

File Contents

# User Rev Content
1 sf-exg 1.6 #include <math.h>
2 root 1.1 #include "../config.h"
3     #include "rxvt.h"
4    
5     #if HAVE_IMG
6    
7 root 1.41 rxvt_img::rxvt_img (rxvt_screen *screen, XRenderPictFormat *format, int x, int y, int width, int height, int repeat)
8     : s(screen), x(x), y(y), w(width), h(height), format(format), repeat(repeat),
9 root 1.34 pm(0), ref(0)
10 root 1.1 {
11     }
12    
13 root 1.32 rxvt_img::rxvt_img (const rxvt_img &img)
14 root 1.34 : 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)
15 root 1.32 {
16 root 1.34 ++ref->cnt;
17 root 1.32 }
18    
19     #if 0
20 root 1.3 rxvt_img::rxvt_img (rxvt_screen *screen, XRenderPictFormat *format, int width, int height, Pixmap pixmap)
21 root 1.30 : s(screen), x(0), y(0), w(width), h(height), format(format), repeat(RepeatNormal), shared(false), pm(pixmap)
22 root 1.1 {
23     }
24 root 1.32 #endif
25 root 1.1
26 root 1.4 rxvt_img *
27 sf-exg 1.21 rxvt_img::new_from_root (rxvt_screen *s)
28     {
29     Display *dpy = s->display->dpy;
30     unsigned int root_pm_w, root_pm_h;
31     Pixmap root_pixmap = s->display->get_pixmap_property (s->display->xa[XA_XROOTPMAP_ID]);
32     if (root_pixmap == None)
33     root_pixmap = s->display->get_pixmap_property (s->display->xa[XA_ESETROOT_PMAP_ID]);
34    
35     if (root_pixmap == None)
36     return 0;
37    
38     Window wdummy;
39     int idummy;
40     unsigned int udummy;
41    
42     if (!XGetGeometry (dpy, root_pixmap, &wdummy, &idummy, &idummy, &root_pm_w, &root_pm_h, &udummy, &udummy))
43     return 0;
44    
45     rxvt_img *img = new rxvt_img (
46     s,
47     XRenderFindVisualFormat (dpy, DefaultVisual (dpy, s->display->screen)),
48 root 1.33 0,
49     0,
50 sf-exg 1.21 root_pm_w,
51 root 1.32 root_pm_h
52 sf-exg 1.21 );
53    
54 root 1.32 img->pm = root_pixmap;
55 root 1.34 img->ref = new pixref (root_pm_w, root_pm_h);
56     img->ref->ours = false;
57 sf-exg 1.21
58     return img;
59     }
60    
61     rxvt_img *
62 root 1.47 rxvt_img::new_from_pixbuf (rxvt_screen *s, GdkPixbuf *pb)
63     {
64 root 1.48 Display *dpy = s->display->dpy;
65    
66 root 1.47 int width = gdk_pixbuf_get_width (pb);
67     int height = gdk_pixbuf_get_height (pb);
68    
69     if (width > 32767 || height > 32767) // well, we *could* upload in chunks
70     rxvt_fatal ("rxvt_img::new_from_pixbuf: image too big (maximum size 32768x32768).\n");
71    
72     // since we require rgb24/argb32 formats from xrender we assume
73     // that both 24 and 32 bpp MUST be supported by any screen that supports xrender
74     int depth = gdk_pixbuf_get_has_alpha (pb) ? 32 : 24;
75    
76     XImage xi;
77    
78     xi.width = width;
79     xi.height = height;
80     xi.xoffset = 0;
81     xi.format = ZPixmap;
82 root 1.50 xi.byte_order = LSBFirst; // maybe go for host byte order, because servers are usually local?
83 root 1.51 xi.bitmap_unit = 32; //XY only, unused
84     xi.bitmap_bit_order = LSBFirst; //XY only, unused
85 root 1.48 xi.bitmap_pad = BitmapPad (dpy);
86 root 1.47 xi.depth = depth;
87     xi.bytes_per_line = 0;
88 root 1.51 xi.bits_per_pixel = 32; //Z only
89     xi.red_mask = 0x000000ff; //Z only
90     xi.green_mask = 0x0000ff00; //Z only
91     xi.blue_mask = 0x00ff0000; //Z only
92     xi.obdata = 0; // probbaly unused
93 root 1.47
94     if (!XInitImage (&xi))
95     rxvt_fatal ("unable to initialise ximage, please report.\n");
96    
97     if (height > INT_MAX / xi.bytes_per_line)
98     rxvt_fatal ("rxvt_img::new_from_pixbuf: image too big for Xlib.\n");
99    
100     xi.data = (char *)rxvt_malloc (height * xi.bytes_per_line);
101    
102     int rowstride = gdk_pixbuf_get_rowstride (pb);
103    
104     assert (3 + (depth == 32) == gdk_pixbuf_get_n_channels (pb));
105     unsigned char *row = gdk_pixbuf_get_pixels (pb);
106     char *line = xi.data;
107    
108     for (int y = 0; y < height; y++)
109     {
110 root 1.50 unsigned char *src = row;
111     uint32_t *dst = (uint32_t *)line;
112 root 1.47
113     if (depth == 24)
114     for (int x = 0; x < width; x++)
115     {
116 root 1.50 uint8_t r = *src++;
117     uint8_t g = *src++;
118     uint8_t b = *src++;
119    
120     uint32_t v = r | (g << 8) | (b << 16);
121    
122     if (ecb_big_endian ())
123     v = ecb_bswap32 (v);
124    
125 root 1.51 *dst++ = v;
126 root 1.47 }
127     else
128     for (int x = 0; x < width; x++)
129     {
130 root 1.50 uint32_t v = *(uint32_t *)src; src += 4;
131 root 1.51
132     if (ecb_big_endian ())
133     v = ecb_bswap32 (v);
134    
135     *dst++ = v;
136 root 1.47 }
137    
138     row += rowstride;
139 root 1.50 line += xi.bytes_per_line;
140 root 1.47 }
141    
142     rxvt_img *img = new rxvt_img (s, XRenderFindStandardFormat (dpy, depth == 24 ? PictStandardRGB24 : PictStandardARGB32), 0, 0, width, height);
143     img->alloc ();
144    
145     GC gc = XCreateGC (dpy, img->pm, 0, 0);
146     XPutImage (dpy, img->pm, gc, &xi, 0, 0, 0, 0, width, height);
147     XFreeGC (dpy, gc);
148    
149     free (xi.data);
150    
151     return img;
152     }
153    
154     rxvt_img *
155 root 1.4 rxvt_img::new_from_file (rxvt_screen *s, const char *filename)
156     {
157 root 1.11 GError *err = 0;
158 root 1.4 GdkPixbuf *pb = gdk_pixbuf_new_from_file (filename, &err);
159    
160     if (!pb)
161 root 1.11 rxvt_fatal ("rxvt_img::new_from_file: %s\n", err->message);
162 root 1.4
163 root 1.47 rxvt_img *img = new_from_pixbuf (s, pb);
164 root 1.4
165 sf-exg 1.26 g_object_unref (pb);
166    
167 root 1.4 return img;
168     }
169    
170 root 1.32 void
171     rxvt_img::destroy ()
172     {
173 root 1.34 if (--ref->cnt)
174 root 1.32 return;
175    
176 root 1.34 if (pm && ref->ours)
177 root 1.32 XFreePixmap (s->display->dpy, pm);
178    
179 root 1.34 delete ref;
180 root 1.32 }
181    
182 root 1.1 rxvt_img::~rxvt_img ()
183     {
184 root 1.32 destroy ();
185     }
186    
187     void
188     rxvt_img::alloc ()
189     {
190     pm = XCreatePixmap (s->display->dpy, s->display->root, w, h, format->depth);
191 root 1.34 ref = new pixref (w, h);
192     }
193    
194     Picture
195     rxvt_img::src_picture ()
196     {
197     Display *dpy = s->display->dpy;
198    
199     XRenderPictureAttributes pa;
200     pa.repeat = repeat;
201     Picture pic = XRenderCreatePicture (dpy, pm, format, CPRepeat, &pa);
202    
203     return pic;
204 root 1.1 }
205    
206     void
207 root 1.11 rxvt_img::unshare ()
208     {
209 root 1.34 if (ref->cnt == 1 && ref->ours)
210 root 1.11 return;
211    
212 root 1.34 //TODO: maybe should reify instead
213     Pixmap pm2 = XCreatePixmap (s->display->dpy, s->display->root, ref->w, ref->h, format->depth);
214 root 1.32 GC gc = XCreateGC (s->display->dpy, pm, 0, 0);
215 root 1.34 XCopyArea (s->display->dpy, pm, pm2, gc, 0, 0, ref->w, ref->h, 0, 0);
216 root 1.32 XFreeGC (s->display->dpy, gc);
217 root 1.11
218 root 1.32 destroy ();
219 root 1.11
220 root 1.32 pm = pm2;
221 root 1.34 ref = new pixref (ref->w, ref->h);
222 root 1.11 }
223    
224     void
225 root 1.1 rxvt_img::fill (const rxvt_color &c)
226     {
227     XGCValues gcv;
228     gcv.foreground = c;
229     GC gc = XCreateGC (s->display->dpy, pm, GCForeground, &gcv);
230     XFillRectangle (s->display->dpy, pm, gc, 0, 0, w, h);
231 root 1.3 XFreeGC (s->display->dpy, gc);
232 root 1.1 }
233    
234 sf-exg 1.6 static void
235     get_gaussian_kernel (int radius, int width, double *kernel, XFixed *params)
236     {
237     double sigma = radius / 2.0;
238     double scale = sqrt (2.0 * M_PI) * sigma;
239     double sum = 0.0;
240    
241     for (int i = 0; i < width; i++)
242     {
243     double x = i - width / 2;
244     kernel[i] = exp (-(x * x) / (2.0 * sigma * sigma)) / scale;
245     sum += kernel[i];
246     }
247    
248     params[0] = XDoubleToFixed (width);
249     params[1] = XDoubleToFixed (1);
250    
251     for (int i = 0; i < width; i++)
252     params[i+2] = XDoubleToFixed (kernel[i] / sum);
253     }
254    
255 sf-exg 1.22 rxvt_img *
256 root 1.3 rxvt_img::blur (int rh, int rv)
257     {
258 sf-exg 1.6 if (!(s->display->flags & DISPLAY_HAS_RENDER_CONV))
259 sf-exg 1.22 return clone ();
260 sf-exg 1.6
261     Display *dpy = s->display->dpy;
262     int size = max (rh, rv) * 2 + 1;
263     double *kernel = (double *)malloc (size * sizeof (double));
264     XFixed *params = (XFixed *)malloc ((size + 2) * sizeof (XFixed));
265 root 1.41 rxvt_img *img = new rxvt_img (s, format, x, y, w, h, repeat);
266 root 1.32 img->alloc ();
267 sf-exg 1.6
268 root 1.34 Picture src = src_picture ();
269    
270 sf-exg 1.6 XRenderPictureAttributes pa;
271     pa.repeat = RepeatPad;
272 sf-exg 1.22 Picture dst = XRenderCreatePicture (dpy, img->pm, format, CPRepeat, &pa);
273    
274     Pixmap tmp_pm = XCreatePixmap (dpy, pm, w, h, format->depth);
275     Picture tmp = XRenderCreatePicture (dpy, tmp_pm , format, CPRepeat, &pa);
276     XFreePixmap (dpy, tmp_pm);
277 sf-exg 1.6
278     if (kernel && params)
279     {
280     size = rh * 2 + 1;
281     get_gaussian_kernel (rh, size, kernel, params);
282    
283     XRenderSetPictureFilter (dpy, src, FilterConvolution, params, size+2);
284     XRenderComposite (dpy,
285     PictOpSrc,
286     src,
287     None,
288 sf-exg 1.22 tmp,
289 sf-exg 1.6 0, 0,
290     0, 0,
291     0, 0,
292     w, h);
293    
294     size = rv * 2 + 1;
295     get_gaussian_kernel (rv, size, kernel, params);
296     ::swap (params[0], params[1]);
297    
298     XRenderSetPictureFilter (dpy, src, FilterConvolution, params, size+2);
299     XRenderComposite (dpy,
300     PictOpSrc,
301 sf-exg 1.22 tmp,
302 sf-exg 1.6 None,
303     dst,
304     0, 0,
305     0, 0,
306     0, 0,
307     w, h);
308     }
309    
310     free (kernel);
311     free (params);
312     XRenderFreePicture (dpy, src);
313     XRenderFreePicture (dpy, dst);
314 sf-exg 1.22 XRenderFreePicture (dpy, tmp);
315    
316     return img;
317 sf-exg 1.6 }
318    
319     static Picture
320     create_xrender_mask (Display *dpy, Drawable drawable, Bool argb)
321     {
322     Pixmap pixmap = XCreatePixmap (dpy, drawable, 1, 1, argb ? 32 : 8);
323    
324     XRenderPictFormat *format = XRenderFindStandardFormat (dpy, argb ? PictStandardARGB32 : PictStandardA8);
325     XRenderPictureAttributes pa;
326     pa.repeat = True;
327     Picture mask = XRenderCreatePicture (dpy, pixmap, format, CPRepeat, &pa);
328    
329     XFreePixmap (dpy, pixmap);
330    
331     return mask;
332 root 1.3 }
333    
334     void
335 sf-exg 1.31 rxvt_img::brightness (unsigned short r, unsigned short g, unsigned short b, unsigned short a)
336 root 1.3 {
337 sf-exg 1.6 Display *dpy = s->display->dpy;
338     Picture src = create_xrender_mask (dpy, pm, True);
339     Picture dst = XRenderCreatePicture (dpy, pm, format, 0, 0);
340    
341     XRenderColor mask_c;
342 sf-exg 1.31 mask_c.red = r;
343     mask_c.green = g;
344     mask_c.blue = b;
345     mask_c.alpha = a;
346 sf-exg 1.6 XRenderFillRectangle (dpy, PictOpSrc, src, &mask_c, 0, 0, 1, 1);
347    
348     XRenderComposite (dpy, PictOpAdd, src, None, dst, 0, 0, 0, 0, 0, 0, w, h);
349 sf-exg 1.23
350     XRenderFreePicture (dpy, src);
351     XRenderFreePicture (dpy, dst);
352 root 1.3 }
353    
354     void
355 sf-exg 1.31 rxvt_img::contrast (unsigned short r, unsigned short g, unsigned short b, unsigned short a)
356 root 1.1 {
357 sf-exg 1.6 if (!(s->display->flags & DISPLAY_HAS_RENDER_MUL))
358     return;
359    
360     Display *dpy = s->display->dpy;
361     Picture src = create_xrender_mask (dpy, pm, True);
362     Picture dst = XRenderCreatePicture (dpy, pm, format, 0, 0);
363    
364     XRenderColor mask_c;
365 sf-exg 1.31 mask_c.red = r;
366     mask_c.green = g;
367     mask_c.blue = b;
368     mask_c.alpha = a;
369 sf-exg 1.6 XRenderFillRectangle (dpy, PictOpSrc, src, &mask_c, 0, 0, 1, 1);
370    
371     XRenderComposite (dpy, PictOpMultiply, src, None, dst, 0, 0, 0, 0, 0, 0, w, h);
372 sf-exg 1.23
373     XRenderFreePicture (dpy, src);
374     XRenderFreePicture (dpy, dst);
375 root 1.1 }
376    
377 root 1.3 rxvt_img *
378 root 1.11 rxvt_img::clone ()
379 root 1.3 {
380 root 1.32 return new rxvt_img (*this);
381 root 1.3 }
382    
383 root 1.46 static XRenderPictFormat *
384     find_alpha_format_for (Display *dpy, XRenderPictFormat *format)
385     {
386     if (format->direct.alphaMask)
387     return format; // already has alpha
388    
389     // try to find a suitable alpha format, one bit alpha is enough for our purposes
390     if (format->type == PictTypeDirect)
391     for (int n = 0; XRenderPictFormat *f = XRenderFindFormat (dpy, 0, 0, n); ++n)
392     if (f->direct.alphaMask
393     && f->type == PictTypeDirect
394     && ecb_popcount32 (f->direct.redMask ) >= ecb_popcount32 (format->direct.redMask )
395     && ecb_popcount32 (f->direct.greenMask) >= ecb_popcount32 (format->direct.greenMask)
396     && ecb_popcount32 (f->direct.blueMask ) >= ecb_popcount32 (format->direct.blueMask ))
397     return f;
398    
399     // should be a very good fallback
400     return XRenderFindStandardFormat (dpy, PictStandardARGB32);
401     }
402    
403 root 1.3 rxvt_img *
404 root 1.33 rxvt_img::reify ()
405 root 1.19 {
406 root 1.35 if (x == 0 && y == 0 && w == ref->w && h == ref->h)
407     return clone ();
408    
409 root 1.40 Display *dpy = s->display->dpy;
410    
411     bool alpha = !format->direct.alphaMask
412     && (x || y)
413     && repeat == RepeatNone;
414    
415 root 1.46 rxvt_img *img = new rxvt_img (s, alpha ? find_alpha_format_for (dpy, format) : format, 0, 0, w, h, repeat);
416 root 1.32 img->alloc ();
417 root 1.19
418 root 1.34 Picture src = src_picture ();
419     Picture dst = XRenderCreatePicture (dpy, img->pm, img->format, 0, 0);
420 root 1.33
421 root 1.42 if (alpha)
422     {
423     XRenderColor rc = { 0, 0, 0, 0 };
424 root 1.44 XRenderFillRectangle (dpy, PictOpSrc, dst, &rc, 0, 0, w, h);//TODO: split into four fillrectangles
425 root 1.42 XRenderComposite (dpy, PictOpSrc, src, None, dst, 0, 0, 0, 0, -x, -y, ref->w, ref->h);
426     }
427     else
428     XRenderComposite (dpy, PictOpSrc, src, None, dst, x, y, 0, 0, 0, 0, w, h);
429    
430 root 1.33 XRenderFreePicture (dpy, src);
431     XRenderFreePicture (dpy, dst);
432 root 1.19
433 root 1.33 return img;
434     }
435 root 1.19
436 root 1.33 rxvt_img *
437     rxvt_img::sub_rect (int x, int y, int width, int height)
438     {
439     rxvt_img *img = clone ();
440    
441     img->x += x;
442     img->y += y;
443 root 1.19
444 root 1.37 if (w != width || h != height)
445     {
446     img->w = width;
447     img->h = height;
448    
449 root 1.39 rxvt_img *img2 = img->reify ();
450     delete img;
451     img = img2;
452 root 1.37 }
453 root 1.36
454 root 1.19 return img;
455     }
456    
457     rxvt_img *
458 root 1.30 rxvt_img::transform (int new_width, int new_height, double matrix[9])
459 root 1.3 {
460 root 1.41 rxvt_img *img = new rxvt_img (s, format, 0, 0, new_width, new_height, repeat);
461 root 1.32 img->alloc ();
462 root 1.12
463     Display *dpy = s->display->dpy;
464 root 1.34 Picture src = src_picture ();
465     Picture dst = XRenderCreatePicture (dpy, img->pm, img->format, 0, 0);
466 root 1.12
467     XTransform xfrm;
468    
469     for (int i = 0; i < 3; ++i)
470     for (int j = 0; j < 3; ++j)
471     xfrm.matrix [i][j] = XDoubleToFixed (matrix [i * 3 + j]);
472    
473 root 1.44 #if 0
474     xfrm.matrix [0][2] -= XDoubleToFixed (x);//TODO
475     xfrm.matrix [1][2] -= XDoubleToFixed (y);
476     #endif
477 root 1.33
478 root 1.17 XRenderSetPictureFilter (dpy, src, "good", 0, 0);
479 root 1.12 XRenderSetPictureTransform (dpy, src, &xfrm);
480     XRenderComposite (dpy, PictOpSrc, src, None, dst, 0, 0, 0, 0, 0, 0, new_width, new_height);
481    
482     XRenderFreePicture (dpy, src);
483     XRenderFreePicture (dpy, dst);
484    
485     return img;
486 root 1.3 }
487    
488     rxvt_img *
489     rxvt_img::scale (int new_width, int new_height)
490     {
491 sf-exg 1.43 if (w == new_width && h == new_height)
492     return clone ();
493    
494 root 1.11 double matrix[9] = {
495 root 1.16 w / (double)new_width, 0, 0,
496     0, h / (double)new_height, 0,
497 root 1.11 0, 0, 1
498     };
499    
500 root 1.42 int old_repeat_mode = repeat;
501     repeat = RepeatPad; // not right, but xrender can't proeprly scale it seems
502    
503     rxvt_img *img = transform (new_width, new_height, matrix);
504    
505     repeat = old_repeat_mode;
506     img->repeat = repeat;
507    
508     return img;
509 root 1.3 }
510    
511 sf-exg 1.7 rxvt_img *
512 root 1.30 rxvt_img::rotate (int new_width, int new_height, int x, int y, double phi)
513 root 1.17 {
514     double s = sin (phi);
515     double c = cos (phi);
516    
517     double matrix[9] = {
518     c, -s, -c * x + s * y + x,
519     s, c, -s * x - c * y + y,
520     0, 0, 1
521     };
522    
523 root 1.30 return transform (new_width, new_height, matrix);
524 root 1.17 }
525    
526     rxvt_img *
527 root 1.45 rxvt_img::convert_format (XRenderPictFormat *new_format, const rxvt_color &bg)
528 sf-exg 1.7 {
529 root 1.32 if (new_format == format)
530     return clone ();
531    
532 root 1.45 rxvt_img *img = new rxvt_img (s, new_format, x, y, w, h, repeat);
533 root 1.32 img->alloc ();
534 root 1.9
535 sf-exg 1.7 Display *dpy = s->display->dpy;
536 root 1.34 Picture src = src_picture ();
537 root 1.8 Picture dst = XRenderCreatePicture (dpy, img->pm, new_format, 0, 0);
538 root 1.27 int op = PictOpSrc;
539 sf-exg 1.7
540 root 1.29 if (format->direct.alphaMask && !new_format->direct.alphaMask)
541 root 1.27 {
542     // does it have to be that complicated
543     rgba c;
544     bg.get (c);
545    
546     XRenderColor rc = { c.r, c.g, c.b, 0xffff };
547 root 1.28 XRenderFillRectangle (dpy, PictOpSrc, dst, &rc, 0, 0, w, h);
548 root 1.27
549     op = PictOpOver;
550     }
551    
552     XRenderComposite (dpy, op, src, None, dst, 0, 0, 0, 0, 0, 0, w, h);
553 sf-exg 1.7
554     XRenderFreePicture (dpy, src);
555     XRenderFreePicture (dpy, dst);
556    
557     return img;
558     }
559 root 1.3
560 sf-exg 1.24 rxvt_img *
561     rxvt_img::blend (rxvt_img *img, double factor)
562     {
563     rxvt_img *img2 = clone ();
564     Display *dpy = s->display->dpy;
565 sf-exg 1.38 Picture src = img->src_picture ();
566 sf-exg 1.24 Picture dst = XRenderCreatePicture (dpy, img2->pm, img2->format, 0, 0);
567     Picture mask = create_xrender_mask (dpy, img->pm, False);
568    
569     XRenderColor mask_c;
570    
571     mask_c.alpha = float_to_component (factor);
572     mask_c.red =
573     mask_c.green =
574     mask_c.blue = 0;
575     XRenderFillRectangle (dpy, PictOpSrc, mask, &mask_c, 0, 0, 1, 1);
576    
577     XRenderComposite (dpy, PictOpOver, src, mask, dst, 0, 0, 0, 0, 0, 0, w, h);
578    
579     XRenderFreePicture (dpy, src);
580     XRenderFreePicture (dpy, dst);
581     XRenderFreePicture (dpy, mask);
582    
583     return img2;
584     }
585    
586 root 1.1 #endif
587