--- rxvt-unicode/src/rxvtimg.C 2012/07/02 02:01:41 1.100 +++ rxvt-unicode/src/rxvtimg.C 2012/07/14 08:26:56 1.103 @@ -172,9 +172,9 @@ } 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; @@ -351,35 +351,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; @@ -596,6 +589,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 (s, 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 = { + 0x8000, 0, 0, + 0, 0x1000, 0, + 0, 0, 0x1000 + }; + + 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 = { + 0x2000, 0, 0, + 0, 0x1000, 0, + 0, 0, 0x1000 + }; + + 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) { @@ -709,8 +760,6 @@ 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 @@ -719,7 +768,7 @@ composer cc (this, new rxvt_img (s, alpha ? find_alpha_format_for (s->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