1
/*----------------------------------------------------------------------*
3
*----------------------------------------------------------------------*
5
* All portions of code are copyright by their respective author/s.
6
* Copyright (c) 2012 Marc Lehmann <schmorp@schmorp.de>
7
* Copyright (c) 2012 Emanuele Giaquinta <e.giaquinta@glauco.it>
9
* This program is free software; you can redistribute it and/or modify
10
* it under the terms of the GNU General Public License as published by
11
* the Free Software Foundation; either version 2 of the License, or
12
* (at your option) any later version.
14
* This program is distributed in the hope that it will be useful,
15
* but WITHOUT ANY WARRANTY; without even the implied warranty of
16
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
* GNU General Public License for more details.
19
* You should have received a copy of the GNU General Public License
20
* along with this program; if not, write to the Free Software
21
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22
*---------------------------------------------------------------------*/
26
#include "../config.h"
31
typedef rxvt_img::nv nv;
43
mat3x3 (const nv *matrix)
45
memcpy (v, matrix, sizeof (v));
48
mat3x3 (nv v11, nv v12, nv v13, nv v21, nv v22, nv v23, nv v31, nv v32, nv v33)
50
v[0][0] = v11; v[0][1] = v12; v[0][2] = v13;
51
v[1][0] = v21; v[1][1] = v22; v[1][2] = v23;
52
v[2][0] = v31; v[2][1] = v32; v[2][2] = v33;
57
nv *operator [](int i) { return &v[i][0]; }
58
const nv *operator [](int i) const { return &v[i][0]; }
60
operator const nv * () const { return &v[0][0]; }
61
operator nv * () { return &v[0][0]; }
63
// quite inefficient, hopefully gcc pulls the w calc out of any loops
64
nv apply1 (int i, nv x, nv y)
68
nv v = m[i][0] * x + m[i][1] * y + m[i][2];
69
nv w = m[2][0] * x + m[2][1] * y + m[2][2];
74
static mat3x3 translate (nv x, nv y);
75
static mat3x3 scale (nv s, nv t);
76
static mat3x3 rotate (nv phi);
85
nv s0 = m[2][2] * m[1][1] - m[2][1] * m[1][2];
86
nv s1 = m[2][1] * m[0][2] - m[2][2] * m[0][1];
87
nv s2 = m[1][2] * m[0][1] - m[1][1] * m[0][2];
89
nv invdet = 1. / (m[0][0] * s0 + m[1][0] * s1 + m[2][0] * s2);
91
inv[0][0] = invdet * s0;
92
inv[0][1] = invdet * s1;
93
inv[0][2] = invdet * s2;
95
inv[1][0] = invdet * (m[2][0] * m[1][2] - m[2][2] * m[1][0]);
96
inv[1][1] = invdet * (m[2][2] * m[0][0] - m[2][0] * m[0][2]);
97
inv[1][2] = invdet * (m[1][0] * m[0][2] - m[1][2] * m[0][0]);
99
inv[2][0] = invdet * (m[2][1] * m[1][0] - m[2][0] * m[1][1]);
100
inv[2][1] = invdet * (m[2][0] * m[0][1] - m[2][1] * m[0][0]);
101
inv[2][2] = invdet * (m[1][1] * m[0][0] - m[1][0] * m[0][1]);
107
operator *(const mat3x3 &a, const mat3x3 &b)
111
for (int i = 0; i < 3; ++i)
112
for (int j = 0; j < 3; ++j)
113
r[i][j] = a[i][0] * b[0][j]
121
mat3x3::translate (nv x, nv y)
131
mat3x3::scale (nv s, nv t)
142
mat3x3::rotate (nv phi)
156
rxvt_img *srcimg, *dstimg;
157
Picture src, dst, msk;
161
composer (rxvt_img *srcimg, rxvt_img *dstimg = 0)
162
: srcimg (srcimg), dstimg (dstimg), msk (0)
165
this->dstimg = srcimg->new_empty ();
166
else if (!this->dstimg->pm) // somewhat unsatisfying
167
this->dstimg->alloc ();
169
dpy = srcimg->s->dpy;
170
src = srcimg->picture ();
171
dst = this->dstimg->picture ();
175
void mask (bool rgb = true, int w = 1, int h = 1)
177
Pixmap pixmap = XCreatePixmap (dpy, srcimg->pm, w, h, rgb ? 32 : 8);
179
XRenderPictFormat *format = XRenderFindStandardFormat (dpy, rgb ? PictStandardARGB32 : PictStandardA8);
180
XRenderPictureAttributes pa;
181
pa.repeat = RepeatNormal;
182
pa.component_alpha = rgb;
183
msk = XRenderCreatePicture (dpy, pixmap, format, CPRepeat | CPComponentAlpha, &pa);
185
XFreePixmap (dpy, pixmap);
190
// CreateSolidFill creates a very very very weird picture
191
void mask (const rgba &c)
199
msk = XRenderCreateSolidFill (dpy, &rc);
203
void fill (const rgba &c)
212
XRenderFillRectangle (dpy, PictOpSrc, msk, &rc, 0, 0, 1, 1);
215
operator rxvt_img *()
223
XRenderFreePicture (dpy, src);
224
XRenderFreePicture (dpy, dst);
225
if (msk) XRenderFreePicture (dpy, msk);
230
static XRenderPictFormat *
231
find_alpha_format_for (Display *dpy, XRenderPictFormat *format)
233
if (format->direct.alphaMask)
234
return format; // already has alpha
236
// try to find a suitable alpha format, one bit alpha is enough for our purposes
237
if (format->type == PictTypeDirect)
238
for (int n = 0; XRenderPictFormat *f = XRenderFindFormat (dpy, 0, 0, n); ++n)
239
if (f->direct.alphaMask
240
&& f->type == PictTypeDirect
241
&& ecb_popcount32 (f->direct.redMask ) >= ecb_popcount32 (format->direct.redMask )
242
&& ecb_popcount32 (f->direct.greenMask) >= ecb_popcount32 (format->direct.greenMask)
243
&& ecb_popcount32 (f->direct.blueMask ) >= ecb_popcount32 (format->direct.blueMask ))
246
// should be a very good fallback
247
return XRenderFindStandardFormat (dpy, PictStandardARGB32);
250
rxvt_img::rxvt_img (rxvt_screen *screen, XRenderPictFormat *format, int x, int y, int width, int height, int repeat)
251
: s(screen), x(x), y(y), w(width), h(height), format(format), repeat(repeat),
256
rxvt_img::rxvt_img (const rxvt_img &img)
257
: 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)
263
rxvt_img::new_from_root (rxvt_screen *s)
265
Display *dpy = s->dpy;
266
unsigned int root_pm_w, root_pm_h;
267
Pixmap root_pixmap = s->display->get_pixmap_property (s->display->xa [XA_XROOTPMAP_ID]);
268
if (root_pixmap == None)
269
root_pixmap = s->display->get_pixmap_property (s->display->xa [XA_ESETROOT_PMAP_ID]);
271
if (root_pixmap == None)
278
if (!XGetGeometry (dpy, root_pixmap, &wdummy, &idummy, &idummy, &root_pm_w, &root_pm_h, &udummy, &udummy))
281
rxvt_img *img = new rxvt_img (
283
XRenderFindVisualFormat (dpy, DefaultVisual (dpy, s->display->screen)),
290
img->pm = root_pixmap;
291
img->ref = new pixref (root_pm_w, root_pm_h);
292
img->ref->ours = false;
300
rxvt_img::new_from_pixbuf (rxvt_screen *s, GdkPixbuf *pb)
302
Display *dpy = s->dpy;
304
int width = gdk_pixbuf_get_width (pb);
305
int height = gdk_pixbuf_get_height (pb);
307
if (width > 32767 || height > 32767) // well, we *could* upload in chunks
308
rxvt_fatal ("rxvt_img::new_from_pixbuf: image too big (maximum size 32768x32768).\n");
310
// since we require rgb24/argb32 formats from xrender we assume
311
// that both 24 and 32 bpp MUST be supported by any screen that supports xrender
313
int byte_order = ecb_big_endian () ? MSBFirst : LSBFirst;
321
xi.byte_order = ImageByteOrder (dpy);
322
xi.bitmap_unit = 0; //XY only, unused
323
xi.bitmap_bit_order = 0; //XY only, unused
324
xi.bitmap_pad = BitmapPad (dpy);
326
xi.bytes_per_line = 0;
327
xi.bits_per_pixel = 32; //Z only
328
xi.red_mask = 0x00000000; //Z only, unused
329
xi.green_mask = 0x00000000; //Z only, unused
330
xi.blue_mask = 0x00000000; //Z only, unused
331
xi.obdata = 0; // probably unused
333
bool byte_order_mismatch = byte_order != xi.byte_order;
335
if (!XInitImage (&xi))
336
rxvt_fatal ("unable to initialise ximage, please report.\n");
338
if (height > INT_MAX / xi.bytes_per_line)
339
rxvt_fatal ("rxvt_img::new_from_pixbuf: image too big for Xlib.\n");
341
xi.data = (char *)rxvt_malloc (height * xi.bytes_per_line);
343
int rowstride = gdk_pixbuf_get_rowstride (pb);
344
bool pb_has_alpha = gdk_pixbuf_get_has_alpha (pb);
345
unsigned char *row = gdk_pixbuf_get_pixels (pb);
347
char *line = xi.data;
349
for (int y = 0; y < height; y++)
351
unsigned char *src = row;
352
uint32_t *dst = (uint32_t *)line;
354
for (int x = 0; x < width; x++)
361
// this is done so it can be jump-free, but newer gcc's clone inner the loop
362
a = pb_has_alpha ? a : 255;
365
r = (r * a + 127) / 255;
366
g = (g * a + 127) / 255;
367
b = (b * a + 127) / 255;
369
uint32_t v = (a << 24) | (r << 16) | (g << 8) | b;
371
if (ecb_big_endian () ? !byte_order_mismatch : byte_order_mismatch)
378
line += xi.bytes_per_line;
381
rxvt_img *img = new rxvt_img (s, XRenderFindStandardFormat (dpy, PictStandardARGB32), 0, 0, width, height);
384
GC gc = XCreateGC (dpy, img->pm, 0, 0);
385
XPutImage (dpy, img->pm, gc, &xi, 0, 0, 0, 0, width, height);
394
rxvt_img::new_from_file (rxvt_screen *s, const char *filename)
397
GdkPixbuf *pb = gdk_pixbuf_new_from_file (filename, &err);
400
rxvt_fatal ("rxvt_img::new_from_file: %s\n", err->message);
402
rxvt_img *img = new_from_pixbuf (s, pb);
418
XFreePixmap (s->dpy, pm);
423
rxvt_img::~rxvt_img ()
431
pm = XCreatePixmap (s->dpy, s->display->root, w, h, format->depth);
432
ref = new pixref (w, h);
436
rxvt_img::new_empty ()
438
rxvt_img *img = new rxvt_img (s, format, x, y, w, h, repeat);
447
Display *dpy = s->dpy;
449
XRenderPictureAttributes pa;
451
Picture pic = XRenderCreatePicture (dpy, pm, format, CPRepeat, &pa);
459
if (ref->cnt == 1 && ref->ours)
462
Pixmap pm2 = XCreatePixmap (s->dpy, s->display->root, ref->w, ref->h, format->depth);
463
GC gc = XCreateGC (s->dpy, pm, 0, 0);
464
XCopyArea (s->dpy, pm, pm2, gc, 0, 0, ref->w, ref->h, 0, 0);
465
XFreeGC (s->dpy, gc);
470
ref = new pixref (ref->w, ref->h);
474
rxvt_img::fill (const rgba &c, int x, int y, int w, int h)
476
XRenderColor rc = { c.r, c.g, c.b, c.a };
478
Display *dpy = s->dpy;
479
Picture src = picture ();
480
XRenderFillRectangle (dpy, PictOpSrc, src, &rc, x, y, w, h);
481
XRenderFreePicture (dpy, src);
485
rxvt_img::fill (const rgba &c)
487
fill (c, 0, 0, w, h);
491
rxvt_img::add_alpha ()
493
if (format->direct.alphaMask)
496
composer cc (this, new rxvt_img (s, find_alpha_format_for (s->dpy, format), x, y, w, h, repeat));
498
XRenderComposite (cc.dpy, PictOpSrc, cc.src, None, cc.dst, 0, 0, 0, 0, 0, 0, w, h);
502
::swap (img->ref, ref);
503
::swap (img->pm , pm );
509
get_gaussian_kernel (int radius, int width, nv *kernel, XFixed *params)
511
nv sigma = radius / 2.0;
512
nv scale = sqrt (2.0 * M_PI) * sigma;
515
for (int i = 0; i < width; i++)
517
nv x = i - width / 2;
518
kernel[i] = exp (-(x * x) / (2.0 * sigma * sigma)) / scale;
522
params[0] = XDoubleToFixed (width);
523
params[1] = XDoubleToFixed (1);
525
for (int i = 0; i < width; i++)
526
params[i+2] = XDoubleToFixed (kernel[i] / sum);
530
rxvt_img::blur (int rh, int rv)
532
if (!(s->display->flags & DISPLAY_HAS_RENDER_CONV))
535
Display *dpy = s->dpy;
536
int size = max (rh, rv) * 2 + 1;
537
nv *kernel = (nv *)malloc (size * sizeof (nv));
538
XFixed *params = rxvt_temp_buf<XFixed> (size + 2);
539
rxvt_img *img = new_empty ();
541
XRenderPictureAttributes pa;
542
pa.repeat = RepeatPad;
543
Picture src = XRenderCreatePicture (dpy, pm, format, CPRepeat, &pa);
544
Picture dst = XRenderCreatePicture (dpy, img->pm, format, 0, 0);
546
Pixmap tmp_pm = XCreatePixmap (dpy, pm, w, h, format->depth);
547
Picture tmp = XRenderCreatePicture (dpy, tmp_pm , format, CPRepeat, &pa);
548
XFreePixmap (dpy, tmp_pm);
550
if (kernel && params)
553
get_gaussian_kernel (rh, size, kernel, params);
555
XRenderSetPictureFilter (dpy, src, FilterConvolution, params, size+2);
556
XRenderComposite (dpy,
567
get_gaussian_kernel (rv, size, kernel, params);
568
::swap (params[0], params[1]);
570
XRenderSetPictureFilter (dpy, tmp, FilterConvolution, params, size+2);
571
XRenderComposite (dpy,
584
XRenderFreePicture (dpy, src);
585
XRenderFreePicture (dpy, dst);
586
XRenderFreePicture (dpy, tmp);
592
rxvt_img::muladd (nv mul, nv add)
594
// STEP 1: double the image width, fill all odd columns with white (==1)
596
composer cc (this, new rxvt_img (s, format, 0, 0, w * 2, h, repeat));
598
// why the hell does XRenderSetPictureTransform want a writable matrix :(
599
// that keeps us from just static const'ing this matrix.
600
XTransform h_double = {
606
XRenderSetPictureFilter (cc.dpy, cc.src, "nearest", 0, 0);
607
XRenderSetPictureTransform (cc.dpy, cc.src, &h_double);
608
XRenderComposite (cc.dpy, PictOpSrc, cc.src, None, cc.dst, 0, 0, 0, 0, 0, 0, w * 2, h);
610
cc.mask (false, 2, 1);
612
static const XRenderColor c0 = { 0, 0, 0, 0 };
613
XRenderFillRectangle (cc.dpy, PictOpSrc, cc.msk, &c0, 0, 0, 1, 1);
614
static const XRenderColor c1 = { 65535, 65535, 65535, 65535 };
615
XRenderFillRectangle (cc.dpy, PictOpSrc, cc.msk, &c1, 1, 0, 1, 1);
617
Picture white = XRenderCreateSolidFill (cc.dpy, &c1);
619
XRenderComposite (cc.dpy, PictOpOver, white, cc.msk, cc.dst, 0, 0, 0, 0, 0, 0, w * 2, h);
621
XRenderFreePicture (cc.dpy, white);
623
// STEP 2: convolve the image with a 3x1 filter
624
// a 2x1 filter would obviously suffice, but given the total lack of specification
625
// for xrender, I expect different xrender implementations to randomly diverge.
626
// we also halve the image, and hope for the best (again, for lack of specs).
627
composer cc2 (cc.dstimg);
630
XDoubleToFixed (3), XDoubleToFixed (1),
631
XDoubleToFixed (0), XDoubleToFixed (mul), XDoubleToFixed (add)
634
XTransform h_halve = {
640
XRenderSetPictureFilter (cc.dpy, cc2.src, "nearest", 0, 0);
641
XRenderSetPictureTransform (cc.dpy, cc2.src, &h_halve);
642
XRenderSetPictureFilter (cc.dpy, cc2.src, FilterConvolution, kernel, ecb_array_length (kernel));
644
XRenderComposite (cc.dpy, PictOpSrc, cc2.src, None, cc2.dst, 0, 0, 0, 0, 0, 0, w * 2, h);
649
ecb_noinline static void
650
extract (int32_t cl0, int32_t cl1, int32_t &c, unsigned short &xc)
652
int32_t x = clamp (c, cl0, cl1);
657
ecb_noinline static bool
658
extract (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)
660
extract (cl0, cl1, r, xr);
661
extract (cl0, cl1, g, xg);
662
extract (cl0, cl1, b, xb);
663
extract (cl0, cl1, a, xa);
665
return xr | xg | xb | xa;
669
rxvt_img::brightness (int32_t r, int32_t g, int32_t b, int32_t a)
673
Display *dpy = s->dpy;
674
Picture dst = XRenderCreatePicture (dpy, pm, format, 0, 0);
676
// loop should not be needed for brightness, as only -1..1 makes sense
677
//while (r | g | b | a)
679
unsigned short xr, xg, xb, xa;
682
if (extract (0, 65535, r, g, b, a, mask_c.red, mask_c.green, mask_c.blue, mask_c.alpha))
683
XRenderFillRectangle (dpy, PictOpAdd, dst, &mask_c, 0, 0, w, h);
685
if (extract (-65535, 0, r, g, b, a, mask_c.red, mask_c.green, mask_c.blue, mask_c.alpha))
687
XRenderColor mask_w = { 65535, 65535, 65535, 65535 };
688
XRenderFillRectangle (dpy, PictOpDifference, dst, &mask_w, 0, 0, w, h);
689
mask_c.red = -mask_c.red; //TODO: verify that doing clamp, assign, and negation does the right thing
690
mask_c.green = -mask_c.green;
691
mask_c.blue = -mask_c.blue;
692
mask_c.alpha = -mask_c.alpha;
693
XRenderFillRectangle (dpy, PictOpAdd, dst, &mask_c, 0, 0, w, h);
694
XRenderFillRectangle (dpy, PictOpDifference, dst, &mask_w, 0, 0, w, h);
698
XRenderFreePicture (dpy, dst);
702
rxvt_img::contrast (int32_t r, int32_t g, int32_t b, int32_t a)
704
if (r < 0 || g < 0 || b < 0 || a < 0)
705
rxvt_fatal ("rxvt_img::contrast does not support negative values.\n");
707
// premultiply (yeah, these are not exact, sue me or fix it)
708
r = (r * (a >> 8)) >> 8;
709
g = (g * (a >> 8)) >> 8;
710
b = (b * (a >> 8)) >> 8;
714
img->fill (rgba (0, 0, 0, 0));
718
//TODO: this operator does not yet implement some useful contrast
719
while (r | g | b | a)
721
unsigned short xr, xg, xb, xa;
724
if (extract (0, 65535, r, g, b, a, mask_c.red, mask_c.green, mask_c.blue, mask_c.alpha))
726
XRenderFillRectangle (cc.dpy, PictOpSrc, cc.msk, &mask_c, 0, 0, 1, 1);
727
XRenderComposite (cc.dpy, PictOpAdd, cc.src, cc.msk, cc.dst, 0, 0, 0, 0, 0, 0, w, h);
731
::swap (img->ref, ref);
732
::swap (img->pm , pm );
738
rxvt_img::draw (rxvt_img *img, int op, nv mask)
742
composer cc (img, this);
745
cc.mask (rgba (0, 0, 0, float_to_component (mask)));
747
XRenderComposite (cc.dpy, op, cc.src, cc.msk, cc.dst, x - img->x, y - img->y, 0, 0, 0, 0, w, h);
753
return new rxvt_img (*this);
759
if (x == 0 && y == 0 && w == ref->w && h == ref->h)
762
// add an alpha channel if...
763
bool alpha = !format->direct.alphaMask // pixmap has none yet
764
&& (x || y) // we need one because of non-zero offset
765
&& repeat == RepeatNone; // and we have no good pixels to fill with
767
composer cc (this, new rxvt_img (s, alpha ? find_alpha_format_for (s->dpy, format) : format,
768
0, 0, w, h, repeat));
770
if (repeat == RepeatNone)
772
XRenderColor rc = { 0, 0, 0, 0 };
773
XRenderFillRectangle (cc.dpy, PictOpSrc, cc.dst, &rc, 0, 0, w, h);//TODO: split into four fillrectangles
774
XRenderComposite (cc.dpy, PictOpSrc, cc.src, None, cc.dst, 0, 0, 0, 0, x, y, ref->w, ref->h);
777
XRenderComposite (cc.dpy, PictOpSrc, cc.src, None, cc.dst, -x, -y, 0, 0, 0, 0, w, h);
783
rxvt_img::sub_rect (int x, int y, int width, int height)
785
rxvt_img *img = clone ();
790
if (w != width || h != height)
795
rxvt_img *img2 = img->reify ();
804
rxvt_img::transform (const nv matrix[3][3])
806
return transform (mat3x3 (&matrix[0][0]));
810
rxvt_img::transform (const nv *matrix)
814
// calculate new pixel bounding box coordinates
817
for (int i = 0; i < 2; ++i)
821
v = m.apply1 (i, 0+x, 0+y); rmin [i] = rmax [i] = v;
822
v = m.apply1 (i, w+x, 0+y); min_it (rmin [i], v); max_it (rmax [i], v);
823
v = m.apply1 (i, 0+x, h+y); min_it (rmin [i], v); max_it (rmax [i], v);
824
v = m.apply1 (i, w+x, h+y); min_it (rmin [i], v); max_it (rmax [i], v);
827
float sx = rmin [0] - x;
828
float sy = rmin [1] - y;
830
// TODO: adjust matrix for subpixel accuracy
831
int nx = floor (rmin [0]);
832
int ny = floor (rmin [1]);
834
int new_width = ceil (rmax [0] - rmin [0]);
835
int new_height = ceil (rmax [1] - rmin [1]);
837
mat3x3 inv = (mat3x3::translate (-x, -y) * m * mat3x3::translate (x, y)).inverse ();
839
composer cc (this, new rxvt_img (s, format, nx, ny, new_width, new_height, repeat));
843
for (int i = 0; i < 3; ++i)
844
for (int j = 0; j < 3; ++j)
845
xfrm.matrix [i][j] = XDoubleToFixed (inv [i][j]);
847
XRenderSetPictureFilter (cc.dpy, cc.src, "good", 0, 0);
848
XRenderSetPictureTransform (cc.dpy, cc.src, &xfrm);
849
XRenderComposite (cc.dpy, PictOpSrc, cc.src, None, cc.dst, sx, sy, 0, 0, 0, 0, new_width, new_height);
855
rxvt_img::scale (int new_width, int new_height)
857
if (w == new_width && h == new_height)
860
int old_repeat_mode = repeat;
861
repeat = RepeatPad; // not right, but xrender can't properly scale it seems
863
rxvt_img *img = transform (mat3x3::scale (new_width / (nv)w, new_height / (nv)h));
865
repeat = old_repeat_mode;
866
img->repeat = repeat;
872
rxvt_img::rotate (int cx, int cy, nv phi)
875
rxvt_img *img = transform (mat3x3::rotate (phi));
883
rxvt_img::convert_format (XRenderPictFormat *new_format, const rgba &bg)
885
if (new_format == format)
888
composer cc (this, new rxvt_img (s, new_format, x, y, w, h, repeat));
892
if (format->direct.alphaMask && !new_format->direct.alphaMask)
894
// does it have to be that complicated
895
XRenderColor rc = { bg.r, bg.g, bg.b, bg.a };
896
XRenderFillRectangle (cc.dpy, PictOpSrc, cc.dst, &rc, 0, 0, w, h);
901
XRenderComposite (cc.dpy, op, cc.src, None, cc.dst, 0, 0, 0, 0, 0, 0, w, h);
907
rxvt_img::tint (const rgba &c)
913
XRenderComposite (cc.dpy, PictOpSrc, cc.src, cc.msk, cc.dst, 0, 0, 0, 0, 0, 0, w, h);
919
rxvt_img::shade (nv factor, rgba c)
921
clamp_it (factor, -1., 1.);
926
c.r = c.r * (2 - factor);
927
c.g = c.g * (2 - factor);
928
c.b = c.b * (2 - factor);
937
rxvt_img *img = this->tint (c);
944
c.b = 0xffff * (factor - 1);
946
img->brightness (c.r, c.g, c.b, c.a);
953
rxvt_img::filter (const char *name, int nparams, nv *params)
957
XFixed *xparams = rxvt_temp_buf<XFixed> (nparams);
959
for (int i = 0; i < nparams; ++i)
960
xparams [i] = XDoubleToFixed (params [i]);
962
XRenderSetPictureFilter (cc.dpy, cc.src, name, xparams, nparams);
964
XRenderComposite (cc.dpy, PictOpSrc, cc.src, 0, cc.dst, 0, 0, 0, 0, 0, 0, w, h);