--- rxvt-unicode/src/background.C 2012/02/04 21:47:06 1.201 +++ rxvt-unicode/src/background.C 2012/05/11 12:21:22 1.209 @@ -5,7 +5,7 @@ * All portions of code are copyright by their respective author/s. * Copyright (c) 2005-2008 Marc Lehmann * Copyright (c) 2007 Sasha Vasko - * Copyright (c) 2010 Emanuele Giaquinta + * Copyright (c) 2010-2012 Emanuele Giaquinta * * 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 @@ -125,16 +125,12 @@ static inline int make_align_position (int align, int window_size, int image_size) { - int diff = window_size - image_size; - int smaller = min (image_size, window_size); - if (align >= 0 && align <= 100) - return diff * align / 100; - else if (align > 100 && align <= 200) - return (align - 100) * smaller / 100 + window_size - smaller; - else if (align >= -100 && align < 0) - return (align + 100) * smaller / 100 - image_size; - return 0; + return lerp (0, window_size - image_size, align); + else if (align > 100) + return lerp (window_size - image_size, window_size, align - 100); + else + return lerp (-image_size, 0, align + 100); } static inline int @@ -336,12 +332,13 @@ y = make_align_position (v_align, target_height, h); } - bg_flags &= ~BG_IS_SIZE_SENSITIVE; if (!(bg_flags & BG_TILE) || h_scale || v_scale || (!(bg_flags & BG_ROOT_ALIGN) && (h_align || v_align)) - || w > target_width || h > target_height) + || image_width > target_width || image_height > target_height) bg_flags |= BG_IS_SIZE_SENSITIVE; + else + bg_flags &= ~BG_IS_SIZE_SENSITIVE; } # ifdef HAVE_PIXBUF @@ -353,8 +350,9 @@ XImage *ximage; char *data, *line; int bytes_per_pixel; - int width_r, width_g, width_b; - int sh_r, sh_g, sh_b; + int width_r, width_g, width_b, width_a; + int sh_r, sh_g, sh_b, sh_a; + uint32_t alpha_mask; int rowstride; int channels; unsigned char *row; @@ -362,6 +360,14 @@ if (visual->c_class != TrueColor) return false; +#if XRENDER + XRenderPictFormat *format = XRenderFindVisualFormat (dpy, visual); + if (format) + alpha_mask = (uint32_t)format->direct.alphaMask << format->direct.alpha; + else +#endif + alpha_mask = 0; + if (depth == 24 || depth == 32) bytes_per_pixel = 4; else if (depth == 15 || depth == 16) @@ -372,13 +378,15 @@ width_r = ecb_popcount32 (visual->red_mask); width_g = ecb_popcount32 (visual->green_mask); width_b = ecb_popcount32 (visual->blue_mask); + width_a = ecb_popcount32 (alpha_mask); - if (width_r > 8 || width_g > 8 || width_b > 8) + if (width_r > 8 || width_g > 8 || width_b > 8 || width_a > 8) return false; sh_r = ecb_ctz32 (visual->red_mask); sh_g = ecb_ctz32 (visual->green_mask); sh_b = ecb_ctz32 (visual->blue_mask); + sh_a = ecb_ctz32 (alpha_mask); if (width > INT_MAX / height / bytes_per_pixel) return false; @@ -402,16 +410,43 @@ row = gdk_pixbuf_get_pixels (pixbuf) + src_y * rowstride + src_x * channels; line = data; + rgba c (0, 0, 0); + + if (channels == 4 && alpha_mask == 0) + { + pix_colors[Color_bg].get (c); + c.r >>= 8; + c.g >>= 8; + c.b >>= 8; + } + for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { unsigned char *pixel = row + x * channels; uint32_t value; + unsigned char r, g, b, a; + + if (channels == 4) + { + a = pixel[3]; + r = (pixel[0] * a + c.r * (0xff - a)) / 0xff; + g = (pixel[1] * a + c.g * (0xff - a)) / 0xff; + b = (pixel[2] * a + c.b * (0xff - a)) / 0xff; + } + else + { + a = 0xff; + r = pixel[0]; + g = pixel[1]; + b = pixel[2]; + } - value = ((pixel[0] >> (8 - width_r)) << sh_r) - | ((pixel[1] >> (8 - width_g)) << sh_g) - | ((pixel[2] >> (8 - width_b)) << sh_b); + value = ((r >> (8 - width_r)) << sh_r) + | ((g >> (8 - width_g)) << sh_g) + | ((b >> (8 - width_b)) << sh_b) + | ((a >> (8 - width_a)) << sh_a); if (bytes_per_pixel == 4) ((uint32_t *)line)[x] = value; @@ -429,12 +464,12 @@ } bool -rxvt_term::render_image (unsigned long tr_flags) +rxvt_term::render_image (bool transparent) { if (!pixbuf) return false; - if (tr_flags + if (transparent && !(bg_flags & BG_HAS_RENDER)) return false; @@ -484,7 +519,7 @@ image_width = gdk_pixbuf_get_width (result); image_height = gdk_pixbuf_get_height (result); - if (tr_flags) + if (transparent) { root_pmap = bg_pixmap; bg_pixmap = None; @@ -552,7 +587,7 @@ } #if XRENDER - if (tr_flags) + if (transparent) { XRenderPictFormat *format = XRenderFindVisualFormat (dpy, visual); @@ -586,7 +621,7 @@ if (result != pixbuf) g_object_unref (result); - if (tr_flags) + if (transparent) XFreePixmap (dpy, root_pmap); return ret; @@ -677,10 +712,10 @@ v_blurRadius = vr; } - if (h_blurRadius == 0 || v_blurRadius == 0) - bg_flags &= ~BG_NEEDS_BLUR; - else + if (h_blurRadius && v_blurRadius) bg_flags |= BG_NEEDS_BLUR; + else + bg_flags &= ~BG_NEEDS_BLUR; return changed; } @@ -688,23 +723,10 @@ void rxvt_term::set_tint_shade_flags () { - rgba c; - bool has_shade = shade != 100; - - bg_flags &= ~BG_TINT_FLAGS; - - if (bg_flags & BG_TINT_SET) - { - tint.get (c); - if (!has_shade - && (c.r <= 0x00ff || c.r >= 0xff00) - && (c.g <= 0x00ff || c.g >= 0xff00) - && (c.b <= 0x00ff || c.b >= 0xff00)) - bg_flags |= BG_TINT_BITAND; - } - - if (has_shade || (bg_flags & BG_TINT_SET)) + if (shade != 100 || (bg_flags & BG_TINT_SET)) bg_flags |= BG_NEEDS_TINT; + else + bg_flags &= ~BG_NEEDS_TINT; } bool @@ -714,6 +736,16 @@ { tint = new_tint; bg_flags |= BG_TINT_SET; + + rgba c; + tint.get (c); + if ((c.r <= 0x00ff || c.r >= 0xff00) + && (c.g <= 0x00ff || c.g >= 0xff00) + && (c.b <= 0x00ff || c.b >= 0xff00)) + bg_flags |= BG_TINT_BITAND; + else + bg_flags &= ~BG_TINT_BITAND; + set_tint_shade_flags (); return true; } @@ -833,7 +865,7 @@ { bool ret = false; - if (bg_flags & BG_TINT_BITAND) + if (shade == 100 && (bg_flags & BG_TINT_BITAND)) { XGCValues gcv; GC gc; @@ -924,10 +956,10 @@ * the tiled portion of the root pixmap that is supposed to be covered by * our window. */ -unsigned long +bool rxvt_term::make_transparency_pixmap () { - unsigned long result = 0; + bool ret = false; /* root dimensions may change from call to call - but Display structure should * be always up-to-date, so let's use it : @@ -1018,21 +1050,22 @@ if (gc) { XFillRectangle (dpy, bg_pixmap, gc, 0, 0, window_width, window_height); - result |= BG_IS_VALID | (bg_flags & BG_EFFECTS_FLAGS); + ret = true; + unsigned long tr_flags = bg_flags & BG_EFFECTS_FLAGS; if (!(bg_flags & BG_CLIENT_RENDER)) { if (bg_flags & BG_NEEDS_BLUR) { if (blur_pixmap (bg_pixmap, visual, window_width, window_height, depth)) - result &= ~BG_NEEDS_BLUR; + tr_flags &= ~BG_NEEDS_BLUR; } if (bg_flags & BG_NEEDS_TINT) { if (tint_pixmap (bg_pixmap, visual, window_width, window_height)) - result &= ~BG_NEEDS_TINT; + tr_flags &= ~BG_NEEDS_TINT; } - if (result & BG_NEEDS_TINT) + if (tr_flags & BG_NEEDS_TINT) { XImage *ximage = XGetImage (dpy, bg_pixmap, 0, 0, bg_pmap_width, bg_pmap_height, AllPlanes, ZPixmap); if (ximage) @@ -1052,7 +1085,7 @@ if (recoded_root_pmap != root_pixmap) XFreePixmap (dpy, recoded_root_pmap); - return result; + return ret; } void @@ -1069,24 +1102,23 @@ bool rxvt_term::bg_render () { - unsigned long tr_flags = 0; + bool transparent = false; bg_invalidate (); # ifdef ENABLE_TRANSPARENCY if (bg_flags & BG_IS_TRANSPARENT) { /* we need to re-generate transparency pixmap in that case ! */ - tr_flags = make_transparency_pixmap (); - if (tr_flags) + transparent = make_transparency_pixmap (); + if (transparent) bg_flags |= BG_IS_VALID; } # endif # ifdef BG_IMAGE_FROM_FILE - if ((bg_flags & BG_IS_FROM_FILE) - || (tr_flags & BG_EFFECTS_FLAGS)) + if (bg_flags & BG_IS_FROM_FILE) { - if (render_image (tr_flags)) + if (render_image (transparent)) bg_flags |= BG_IS_VALID; } # endif @@ -1152,6 +1184,7 @@ void rxvt_term::tint_ximage (Visual *visual, XImage *ximage) { + unsigned int size_r, size_g, size_b; int sh_r, sh_g, sh_b; uint32_t mask_r, mask_g, mask_b; uint32_t *lookup, *lookup_r, *lookup_g, *lookup_b; @@ -1166,63 +1199,21 @@ mask_b = visual->blue_mask; /* boring lookup table pre-initialization */ - switch (ximage->depth) - { - case 15: - if ((mask_r != 0x7c00) || - (mask_g != 0x03e0) || - (mask_b != 0x001f)) - return; - lookup = (uint32_t *) malloc (sizeof (uint32_t)*(32+32+32)); - lookup_r = lookup; - lookup_g = lookup+32; - lookup_b = lookup+32+32; - sh_r = 10; - sh_g = 5; - sh_b = 0; - break; - case 16: - if ((mask_r != 0xf800) || - (mask_g != 0x07e0) || - (mask_b != 0x001f)) - return; - lookup = (uint32_t *) malloc (sizeof (uint32_t)*(32+64+32)); - lookup_r = lookup; - lookup_g = lookup+32; - lookup_b = lookup+32+64; - sh_r = 11; - sh_g = 5; - sh_b = 0; - break; - case 24: - if ((mask_r != 0xff0000) || - (mask_g != 0x00ff00) || - (mask_b != 0x0000ff)) - return; - lookup = (uint32_t *) malloc (sizeof (uint32_t)*(256+256+256)); - lookup_r = lookup; - lookup_g = lookup+256; - lookup_b = lookup+256+256; - sh_r = 16; - sh_g = 8; - sh_b = 0; - break; - case 32: - if ((mask_r != 0xff0000) || - (mask_g != 0x00ff00) || - (mask_b != 0x0000ff)) - return; - lookup = (uint32_t *) malloc (sizeof (uint32_t)*(256+256+256)); - lookup_r = lookup; - lookup_g = lookup+256; - lookup_b = lookup+256+256; - sh_r = 16; - sh_g = 8; - sh_b = 0; - break; - default: - return; /* we do not support this color depth */ - } + sh_r = ecb_ctz32 (mask_r); + sh_g = ecb_ctz32 (mask_g); + sh_b = ecb_ctz32 (mask_b); + + size_r = mask_r >> sh_r; + size_g = mask_g >> sh_g; + size_b = mask_b >> sh_b; + + if (size_r++ > 255 || size_g++ > 255 || size_b++ > 255) + return; + + lookup = (uint32_t *)malloc (sizeof (uint32_t) * (size_r + size_g + size_b)); + lookup_r = lookup; + lookup_g = lookup + size_r; + lookup_b = lookup + size_r + size_g; rgba c (rgba::MAX_CC, rgba::MAX_CC, rgba::MAX_CC); @@ -1254,25 +1245,21 @@ /* apply table to input image (replacing colors by newly calculated ones) */ if (ximage->bits_per_pixel == 32 - && (ximage->depth == 24 || ximage->depth == 32) && ximage->byte_order == host_byte_order) { - uint32_t *p1, *pf, *p, *pl; - p1 = (uint32_t *) ximage->data; - pf = (uint32_t *) (ximage->data + ximage->height * ximage->bytes_per_line); + char *line = ximage->data; - while (p1 < pf) + for (int y = 0; y < ximage->height; y++) { - p = p1; - pl = p1 + ximage->width; - for (; p < pl; p++) + uint32_t *p = (uint32_t *)line; + for (int x = 0; x < ximage->width; x++) { - *p = lookup_r[(*p & 0xff0000) >> 16] | - lookup_g[(*p & 0x00ff00) >> 8] | - lookup_b[(*p & 0x0000ff)] | - (*p & 0xff000000); + *p = lookup_r[(*p & mask_r) >> sh_r] | + lookup_g[(*p & mask_g) >> sh_g] | + lookup_b[(*p & mask_b) >> sh_b]; + p++; } - p1 = (uint32_t *) ((char *) p1 + ximage->bytes_per_line); + line += ximage->bytes_per_line; } } else