--- rxvt-unicode/src/rxvtimg.C 2012/06/17 21:58:18 1.98 +++ rxvt-unicode/src/rxvtimg.C 2019/09/17 18:31:32 1.112 @@ -8,7 +8,7 @@ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or + * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, @@ -166,15 +166,15 @@ else if (!this->dstimg->pm) // somewhat unsatisfying this->dstimg->alloc (); - dpy = srcimg->s->dpy; + dpy = srcimg->d->dpy; src = srcimg->picture (); dst = this->dstimg->picture (); } ecb_noinline - void mask (bool rgb = true, int x = 1, int y = 1) + void mask (bool rgb = true, int w = 1, int h = 1) { - Pixmap pixmap = XCreatePixmap (dpy, srcimg->pm, x, y, rgb ? 32 : 8); + Pixmap pixmap = XCreatePixmap (dpy, srcimg->pm, w, h, rgb ? 32 : 8); XRenderPictFormat *format = XRenderFindStandardFormat (dpy, rgb ? PictStandardARGB32 : PictStandardA8); XRenderPictureAttributes pa; @@ -190,11 +190,12 @@ // CreateSolidFill creates a very very very weird picture void mask (const rgba &c) { + // the casts are needed in C++11 (see 8.5.1) XRenderColor rc = { - c.r * c.a / 65535, - c.g * c.a / 65535, - c.b * c.a / 65535, - c.a + (unsigned short)(c.r * c.a / 65535), + (unsigned short)(c.g * c.a / 65535), + (unsigned short)(c.b * c.a / 65535), + c.a }; msk = XRenderCreateSolidFill (dpy, &rc); ecb_assume (msk); @@ -203,10 +204,10 @@ void fill (const rgba &c) { XRenderColor rc = { - c.r * c.a / 65535, - c.g * c.a / 65535, - c.b * c.a / 65535, - c.a + (unsigned short)(c.r * c.a / 65535), + (unsigned short)(c.g * c.a / 65535), + (unsigned short)(c.b * c.a / 65535), + c.a }; XRenderFillRectangle (dpy, PictOpSrc, msk, &rc, 0, 0, 1, 1); @@ -248,13 +249,19 @@ } rxvt_img::rxvt_img (rxvt_screen *screen, XRenderPictFormat *format, int x, int y, int width, int height, int repeat) -: s(screen), x(x), y(y), w(width), h(height), format(format), repeat(repeat), +: d(screen->display), x(x), y(y), w(width), h(height), format(format), repeat(repeat), + pm(0), ref(0) +{ +} + +rxvt_img::rxvt_img (rxvt_display *display, XRenderPictFormat *format, int x, int y, int width, int height, int repeat) +: d(display), x(x), y(y), w(width), h(height), format(format), repeat(repeat), pm(0), ref(0) { } rxvt_img::rxvt_img (const rxvt_img &img) -: 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) +: d(img.d), x(img.x), y(img.y), w(img.w), h(img.h), format(img.format), repeat(img.repeat), pm(img.pm), ref(img.ref) { ++ref->cnt; } @@ -351,35 +358,28 @@ unsigned char *src = row; uint32_t *dst = (uint32_t *)line; - if (!pb_has_alpha) - for (int x = 0; x < width; x++) - { - uint8_t r = *src++; - uint8_t g = *src++; - uint8_t b = *src++; - - uint32_t v = (255 << 24) | (r << 16) | (g << 8) | b; - - if (ecb_big_endian () ? !byte_order_mismatch : byte_order_mismatch) - v = ecb_bswap32 (v); - - *dst++ = v; - } - else - for (int x = 0; x < width; x++) - { - uint32_t v = *(uint32_t *)src; src += 4; - - if (ecb_big_endian ()) - v = ecb_bswap32 (v); + for (int x = 0; x < width; x++) + { + uint8_t r = *src++; + uint8_t g = *src++; + uint8_t b = *src++; + uint8_t a = *src; + + // this is done so it can be jump-free, but newer gcc's clone inner the loop + a = pb_has_alpha ? a : 255; + src += pb_has_alpha; - v = ecb_rotl32 (v, 8); // abgr to bgra + r = (r * a + 127) / 255; + g = (g * a + 127) / 255; + b = (b * a + 127) / 255; - if (!byte_order_mismatch) - v = ecb_bswap32 (v); + uint32_t v = (a << 24) | (r << 16) | (g << 8) | b; - *dst++ = v; - } + if (ecb_big_endian () ? !byte_order_mismatch : byte_order_mismatch) + v = ecb_bswap32 (v); + + *dst++ = v; + } row += rowstride; line += xi.bytes_per_line; @@ -404,7 +404,15 @@ GdkPixbuf *pb = gdk_pixbuf_new_from_file (filename, &err); if (!pb) - rxvt_fatal ("rxvt_img::new_from_file: %s\n", err->message); + try + { + rxvt_fatal ("rxvt_img::new_from_file: %s\n", err->message); + } + catch (...) + { + g_error_free (err); + throw; + } rxvt_img *img = new_from_pixbuf (s, pb); @@ -422,7 +430,7 @@ return; if (pm && ref->ours) - XFreePixmap (s->dpy, pm); + XFreePixmap (d->dpy, pm); delete ref; } @@ -435,14 +443,14 @@ void rxvt_img::alloc () { - pm = XCreatePixmap (s->dpy, s->display->root, w, h, format->depth); + pm = XCreatePixmap (d->dpy, d->root, w, h, format->depth); ref = new pixref (w, h); } rxvt_img * rxvt_img::new_empty () { - rxvt_img *img = new rxvt_img (s, format, x, y, w, h, repeat); + rxvt_img *img = new rxvt_img (d, format, x, y, w, h, repeat); img->alloc (); return img; @@ -451,7 +459,7 @@ Picture rxvt_img::picture () { - Display *dpy = s->dpy; + Display *dpy = d->dpy; XRenderPictureAttributes pa; pa.repeat = repeat; @@ -466,10 +474,10 @@ if (ref->cnt == 1 && ref->ours) return; - Pixmap pm2 = XCreatePixmap (s->dpy, s->display->root, ref->w, ref->h, format->depth); - GC gc = XCreateGC (s->dpy, pm, 0, 0); - XCopyArea (s->dpy, pm, pm2, gc, 0, 0, ref->w, ref->h, 0, 0); - XFreeGC (s->dpy, gc); + Pixmap pm2 = XCreatePixmap (d->dpy, d->root, ref->w, ref->h, format->depth); + GC gc = XCreateGC (d->dpy, pm, 0, 0); + XCopyArea (d->dpy, pm, pm2, gc, 0, 0, ref->w, ref->h, 0, 0); + XFreeGC (d->dpy, gc); destroy (); @@ -478,23 +486,29 @@ } void -rxvt_img::fill (const rgba &c) +rxvt_img::fill (const rgba &c, int x, int y, int w, int h) { XRenderColor rc = { c.r, c.g, c.b, c.a }; - Display *dpy = s->dpy; + Display *dpy = d->dpy; Picture src = picture (); - XRenderFillRectangle (dpy, PictOpSrc, src, &rc, 0, 0, w, h); + XRenderFillRectangle (dpy, PictOpSrc, src, &rc, x, y, w, h); XRenderFreePicture (dpy, src); } void +rxvt_img::fill (const rgba &c) +{ + fill (c, 0, 0, w, h); +} + +void rxvt_img::add_alpha () { if (format->direct.alphaMask) return; - composer cc (this, new rxvt_img (s, find_alpha_format_for (s->dpy, format), x, y, w, h, repeat)); + composer cc (this, new rxvt_img (d, find_alpha_format_for (d->dpy, format), x, y, w, h, repeat)); XRenderComposite (cc.dpy, PictOpSrc, cc.src, None, cc.dst, 0, 0, 0, 0, 0, 0, w, h); @@ -530,13 +544,13 @@ rxvt_img * rxvt_img::blur (int rh, int rv) { - if (!(s->display->flags & DISPLAY_HAS_RENDER_CONV)) + if (!(d->flags & DISPLAY_HAS_RENDER_CONV)) return clone (); - Display *dpy = s->dpy; + Display *dpy = d->dpy; int size = max (rh, rv) * 2 + 1; nv *kernel = (nv *)malloc (size * sizeof (nv)); - XFixed *params = (XFixed *)malloc ((size + 2) * sizeof (XFixed)); + XFixed *params = rxvt_temp_buf (size + 2); rxvt_img *img = new_empty (); XRenderPictureAttributes pa; @@ -581,7 +595,6 @@ } free (kernel); - free (params); XRenderFreePicture (dpy, src); XRenderFreePicture (dpy, dst); @@ -590,6 +603,64 @@ return img; } +rxvt_img * +rxvt_img::muladd (nv mul, nv add) +{ + // STEP 1: double the image width, fill all odd columns with white (==1) + + composer cc (this, new rxvt_img (d, format, 0, 0, w * 2, h, repeat)); + + // why the hell does XRenderSetPictureTransform want a writable matrix :( + // that keeps us from just static const'ing this matrix. + XTransform h_double = { + 0x08000, 0, 0, + 0, 0x10000, 0, + 0, 0, 0x10000 + }; + + XRenderSetPictureFilter (cc.dpy, cc.src, "nearest", 0, 0); + XRenderSetPictureTransform (cc.dpy, cc.src, &h_double); + XRenderComposite (cc.dpy, PictOpSrc, cc.src, None, cc.dst, 0, 0, 0, 0, 0, 0, w * 2, h); + + cc.mask (false, 2, 1); + + static const XRenderColor c0 = { 0, 0, 0, 0 }; + XRenderFillRectangle (cc.dpy, PictOpSrc, cc.msk, &c0, 0, 0, 1, 1); + static const XRenderColor c1 = { 65535, 65535, 65535, 65535 }; + XRenderFillRectangle (cc.dpy, PictOpSrc, cc.msk, &c1, 1, 0, 1, 1); + + Picture white = XRenderCreateSolidFill (cc.dpy, &c1); + + XRenderComposite (cc.dpy, PictOpOver, white, cc.msk, cc.dst, 0, 0, 0, 0, 0, 0, w * 2, h); + + XRenderFreePicture (cc.dpy, white); + + // STEP 2: convolve the image with a 3x1 filter + // a 2x1 filter would obviously suffice, but given the total lack of specification + // for xrender, I expect different xrender implementations to randomly diverge. + // we also halve the image, and hope for the best (again, for lack of specs). + composer cc2 (cc.dstimg); + + XFixed kernel [] = { + XDoubleToFixed (3), XDoubleToFixed (1), + XDoubleToFixed (0), XDoubleToFixed (mul), XDoubleToFixed (add) + }; + + XTransform h_halve = { + 0x20000, 0, 0, + 0, 0x10000, 0, + 0, 0, 0x10000 + }; + + XRenderSetPictureFilter (cc.dpy, cc2.src, "nearest", 0, 0); + XRenderSetPictureTransform (cc.dpy, cc2.src, &h_halve); + XRenderSetPictureFilter (cc.dpy, cc2.src, FilterConvolution, kernel, ecb_array_length (kernel)); + + XRenderComposite (cc.dpy, PictOpSrc, cc2.src, None, cc2.dst, 0, 0, 0, 0, 0, 0, w * 2, h); + + return cc2; +} + ecb_noinline static void extract (int32_t cl0, int32_t cl1, int32_t &c, unsigned short &xc) { @@ -614,7 +685,7 @@ { unshare (); - Display *dpy = s->dpy; + Display *dpy = d->dpy; Picture dst = XRenderCreatePicture (dpy, pm, format, 0, 0); // loop should not be needed for brightness, as only -1..1 makes sense @@ -703,17 +774,15 @@ if (x == 0 && y == 0 && w == ref->w && h == ref->h) return clone (); - Display *dpy = s->dpy; - // add an alpha channel if... bool alpha = !format->direct.alphaMask // pixmap has none yet && (x || y) // we need one because of non-zero offset && repeat == RepeatNone; // and we have no good pixels to fill with - composer cc (this, new rxvt_img (s, alpha ? find_alpha_format_for (s->dpy, format) : format, + composer cc (this, new rxvt_img (d, alpha ? find_alpha_format_for (d->dpy, format) : format, 0, 0, w, h, repeat)); - if (alpha) + if (repeat == RepeatNone) { XRenderColor rc = { 0, 0, 0, 0 }; XRenderFillRectangle (cc.dpy, PictOpSrc, cc.dst, &rc, 0, 0, w, h);//TODO: split into four fillrectangles @@ -782,7 +851,7 @@ mat3x3 inv = (mat3x3::translate (-x, -y) * m * mat3x3::translate (x, y)).inverse (); - composer cc (this, new rxvt_img (s, format, nx, ny, new_width, new_height, repeat)); + composer cc (this, new rxvt_img (d, format, nx, ny, new_width, new_height, repeat)); XTransform xfrm; @@ -817,12 +886,6 @@ rxvt_img * rxvt_img::rotate (int cx, int cy, nv phi) { -#if 0 - { c, -s, cx - c * cx + s * cy }, - { s, c, cy - s * cx - c * cy }, - { 0, 0, 1 } -#endif - move (-cx, -cy); rxvt_img *img = transform (mat3x3::rotate (phi)); move ( cx, cy); @@ -837,7 +900,7 @@ if (new_format == format) return clone (); - composer cc (this, new rxvt_img (s, new_format, x, y, w, h, repeat)); + composer cc (this, new rxvt_img (d, new_format, x, y, w, h, repeat)); int op = PictOpSrc; @@ -868,11 +931,43 @@ } rxvt_img * -rxvt_img::filter (const char *name, int nparams, nv *params) +rxvt_img::shade (nv factor, rgba c) { - rxvt_img *img = new_empty (); + clamp_it (factor, -1., 1.); + factor++; - composer cc (img); + if (factor > 1) + { + c.r = c.r * (2 - factor); + c.g = c.g * (2 - factor); + c.b = c.b * (2 - factor); + } + else + { + c.r = c.r * factor; + c.g = c.g * factor; + c.b = c.b * factor; + } + + rxvt_img *img = this->tint (c); + + if (factor > 1) + { + c.a = 0xffff; + c.r = + c.g = + c.b = 0xffff * (factor - 1); + + img->brightness (c.r, c.g, c.b, c.a); + } + + return img; +} + +rxvt_img * +rxvt_img::filter (const char *name, int nparams, nv *params) +{ + composer cc (this); XFixed *xparams = rxvt_temp_buf (nparams);