--- rxvt-unicode/src/background.C 2012/02/25 22:20:47 1.202 +++ rxvt-unicode/src/background.C 2012/05/17 10:18:32 1.214 @@ -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 @@ -60,11 +60,6 @@ void rxvt_term::bg_destroy () { -#ifdef HAVE_PIXBUF - if (pixbuf) - g_object_unref (pixbuf); -#endif - if (bg_pixmap) XFreePixmap (dpy, bg_pixmap); } @@ -92,9 +87,11 @@ # endif # ifdef BG_IMAGE_FROM_FILE - if (bg_flags & BG_IS_FROM_FILE) + if (bg_image.flags & IM_IS_SET) { - if (bg_flags & BG_IS_SIZE_SENSITIVE) + if ((bg_image.flags & IM_IS_SIZE_SENSITIVE) + || bg_image.width () > szHint.width + || bg_image.height () > szHint.height) return true; } # endif @@ -111,9 +108,9 @@ # endif # ifdef BG_IMAGE_FROM_FILE - if (bg_flags & BG_IS_FROM_FILE) + if (bg_image.flags & IM_IS_SET) { - if (bg_flags & BG_ROOT_ALIGN) + if (bg_image.flags & IM_ROOT_ALIGN) return true; } # endif @@ -125,16 +122,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 @@ -155,7 +148,7 @@ } bool -rxvt_term::bg_set_geometry (const char *geom, bool update) +rxvt_image::set_geometry (const char *geom, bool update) { bool changed = false; int geom_flags = 0; @@ -176,14 +169,14 @@ { if (!strcasecmp (arr[i], "style=tiled")) { - new_flags = BG_TILE; + new_flags = IM_TILE; w = h = noScale; x = y = 0; geom_flags = WidthValue|HeightValue|XValue|YValue; } else if (!strcasecmp (arr[i], "style=aspect-stretched")) { - new_flags = BG_KEEP_ASPECT; + new_flags = IM_KEEP_ASPECT; w = h = windowScale; x = y = centerAlign; geom_flags = WidthValue|HeightValue|XValue|YValue; @@ -203,40 +196,40 @@ } else if (!strcasecmp (arr[i], "style=root-tiled")) { - new_flags = BG_TILE|BG_ROOT_ALIGN; + new_flags = IM_TILE|IM_ROOT_ALIGN; w = h = noScale; geom_flags = WidthValue|HeightValue; } else if (!strcasecmp (arr[i], "op=tile")) - new_flags |= BG_TILE; + new_flags |= IM_TILE; else if (!strcasecmp (arr[i], "op=keep-aspect")) - new_flags |= BG_KEEP_ASPECT; + new_flags |= IM_KEEP_ASPECT; else if (!strcasecmp (arr[i], "op=root-align")) - new_flags |= BG_ROOT_ALIGN; + new_flags |= IM_ROOT_ALIGN; // deprecated else if (!strcasecmp (arr[i], "tile")) { - new_flags |= BG_TILE; + new_flags |= IM_TILE; w = h = noScale; geom_flags |= WidthValue|HeightValue; } else if (!strcasecmp (arr[i], "propscale")) { - new_flags |= BG_KEEP_ASPECT; + new_flags |= IM_KEEP_ASPECT; w = h = windowScale; geom_flags |= WidthValue|HeightValue; } else if (!strcasecmp (arr[i], "hscale")) { - new_flags |= BG_TILE; + new_flags |= IM_TILE; w = windowScale; h = noScale; geom_flags |= WidthValue|HeightValue; } else if (!strcasecmp (arr[i], "vscale")) { - new_flags |= BG_TILE; + new_flags |= IM_TILE; h = windowScale; w = noScale; geom_flags |= WidthValue|HeightValue; @@ -254,7 +247,7 @@ } else if (!strcasecmp (arr[i], "root")) { - new_flags |= BG_TILE|BG_ROOT_ALIGN; + new_flags |= IM_TILE|IM_ROOT_ALIGN; w = h = noScale; geom_flags |= WidthValue|HeightValue; } @@ -266,7 +259,7 @@ rxvt_free_strsplit (arr); } - new_flags |= bg_flags & ~BG_GEOMETRY_FLAGS; + new_flags |= flags & ~IM_GEOMETRY_FLAGS; if (!update) { @@ -288,13 +281,13 @@ clamp_it (x, -100, 200); clamp_it (y, -100, 200); - if (bg_flags != new_flags + if (flags != new_flags || h_scale != w || v_scale != h || h_align != x || v_align != y) { - bg_flags = new_flags; + flags = new_flags; h_scale = w; v_scale = h; h_align = x; @@ -302,19 +295,28 @@ changed = true; } + if (!(flags & IM_TILE) + || h_scale || v_scale + || (!(flags & IM_ROOT_ALIGN) && (h_align || v_align))) + flags |= IM_IS_SIZE_SENSITIVE; + else + flags &= ~IM_IS_SIZE_SENSITIVE; + return changed; } void -rxvt_term::get_image_geometry (int image_width, int image_height, int &w, int &h, int &x, int &y) +rxvt_term::get_image_geometry (rxvt_image &image, int &w, int &h, int &x, int &y) { + int image_width = image.width (); + int image_height = image.height (); int target_width = szHint.width; int target_height = szHint.height; - w = h_scale * target_width / 100; - h = v_scale * target_height / 100; + w = image.h_scale * target_width / 100; + h = image.v_scale * target_height / 100; - if (bg_flags & BG_KEEP_ASPECT) + if (image.flags & IM_KEEP_ASPECT) { float scale = (float)w / image_width; min_it (scale, (float)h / image_height); @@ -325,23 +327,16 @@ if (!w) w = image_width; if (!h) h = image_height; - if (bg_flags & BG_ROOT_ALIGN) + if (image.flags & IM_ROOT_ALIGN) { x = -target_x; y = -target_y; } else { - x = make_align_position (h_align, target_width, w); - y = make_align_position (v_align, target_height, h); + x = make_align_position (image.h_align, target_width, w); + y = make_align_position (image.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) - bg_flags |= BG_IS_SIZE_SENSITIVE; } # ifdef HAVE_PIXBUF @@ -351,10 +346,10 @@ unsigned int width, unsigned int height) { XImage *ximage; - char *data, *line; - int bytes_per_pixel; - int width_r, width_g, width_b; - int sh_r, sh_g, sh_b; + char *line; + 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,36 +357,39 @@ if (visual->c_class != TrueColor) return false; - if (depth == 24 || depth == 32) - bytes_per_pixel = 4; - else if (depth == 15 || depth == 16) - bytes_per_pixel = 2; +#if XRENDER + XRenderPictFormat *format = XRenderFindVisualFormat (dpy, visual); + if (format) + alpha_mask = (uint32_t)format->direct.alphaMask << format->direct.alpha; else - return false; +#endif + alpha_mask = 0; 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) + if (width > 32767 || height > 32767) return false; - data = (char *)malloc (width * height * bytes_per_pixel); - if (!data) + ximage = XCreateImage (dpy, visual, depth, ZPixmap, 0, 0, + width, height, 32, 0); + if (!ximage) return false; - ximage = XCreateImage (dpy, visual, depth, ZPixmap, 0, data, - width, height, bytes_per_pixel * 8, 0); - if (!ximage) + if (height > INT_MAX / ximage->bytes_per_line + || !(ximage->data = (char *)malloc (height * ximage->bytes_per_line))) { - free (data); + XDestroyImage (ximage); return false; } @@ -400,7 +398,17 @@ rowstride = gdk_pixbuf_get_rowstride (pixbuf); channels = gdk_pixbuf_get_n_channels (pixbuf); row = gdk_pixbuf_get_pixels (pixbuf) + src_y * rowstride + src_x * channels; - line = data; + line = ximage->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++) { @@ -408,15 +416,32 @@ { unsigned char *pixel = row + x * channels; uint32_t value; + unsigned char r, g, b, a; - value = ((pixel[0] >> (8 - width_r)) << sh_r) - | ((pixel[1] >> (8 - width_g)) << sh_g) - | ((pixel[2] >> (8 - width_b)) << sh_b); + 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]; + } - if (bytes_per_pixel == 4) + 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 (ximage->bits_per_pixel == 32) ((uint32_t *)line)[x] = value; else - ((uint16_t *)line)[x] = value; + XPutPixel (ximage, x, y, value); } row += rowstride; @@ -429,8 +454,9 @@ } bool -rxvt_term::render_image (bool transparent) +rxvt_term::render_image (rxvt_image &image, bool transparent) { + GdkPixbuf *pixbuf = image.pixbuf; if (!pixbuf) return false; @@ -453,9 +479,9 @@ int w = 0; int h = 0; - get_image_geometry (image_width, image_height, w, h, x, y); + get_image_geometry (image, w, h, x, y); - if (!(bg_flags & BG_ROOT_ALIGN) + if (!(image.flags & IM_ROOT_ALIGN) && (x >= target_width || y >= target_height || x + w <= 0 @@ -491,7 +517,7 @@ } else { - if (bg_flags & BG_TILE) + if (image.flags & IM_TILE) { new_pmap_width = min (image_width, target_width); new_pmap_height = min (image_height, target_height); @@ -514,7 +540,7 @@ if (gc) { - if (bg_flags & BG_TILE) + if (image.flags & IM_TILE) { Pixmap tile = XCreatePixmap (dpy, vt, image_width, image_height, depth); pixbuf_to_pixmap (result, tile, gc, @@ -594,7 +620,7 @@ # endif /* HAVE_PIXBUF */ bool -rxvt_term::bg_set_file (const char *file) +rxvt_image::set_file (const char *file) { if (!file || !*file) return false; @@ -618,7 +644,7 @@ if (pixbuf) g_object_unref (pixbuf); pixbuf = image; - bg_flags |= BG_IS_FROM_FILE; + flags |= IM_IS_SET; ret = true; } # endif @@ -626,9 +652,9 @@ if (ret) { if (p) - bg_set_geometry (p + 1); + set_geometry (p + 1); else - bg_set_default_geometry (); + set_default_geometry (); } return ret; @@ -638,18 +664,6 @@ # ifdef ENABLE_TRANSPARENCY bool -rxvt_term::bg_set_transparent () -{ - if (!(bg_flags & BG_IS_TRANSPARENT)) - { - bg_flags |= BG_IS_TRANSPARENT; - return true; - } - - return false; -} - -bool rxvt_term::bg_set_blur (const char *geom) { bool changed = false; @@ -677,36 +691,9 @@ v_blurRadius = vr; } - if (h_blurRadius == 0 || v_blurRadius == 0) - bg_flags &= ~BG_NEEDS_BLUR; - else - bg_flags |= BG_NEEDS_BLUR; - return changed; } -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)) - bg_flags |= BG_NEEDS_TINT; -} - bool rxvt_term::bg_set_tint (rxvt_color &new_tint) { @@ -714,7 +701,16 @@ { tint = new_tint; bg_flags |= BG_TINT_SET; - set_tint_shade_flags (); + + 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; + return true; } @@ -733,7 +729,6 @@ if (new_shade != shade) { shade = new_shade; - set_tint_shade_flags (); return true; } @@ -764,7 +759,7 @@ #endif bool -rxvt_term::blur_pixmap (Pixmap pixmap, Visual *visual, int width, int height, int depth) +rxvt_term::blur_pixmap (Pixmap pixmap, int width, int height) { bool ret = false; #if XRENDER @@ -829,11 +824,11 @@ } bool -rxvt_term::tint_pixmap (Pixmap pixmap, Visual *visual, int width, int height) +rxvt_term::tint_pixmap (Pixmap pixmap, int width, int height) { bool ret = false; - if (bg_flags & BG_TINT_BITAND) + if (shade == 100 && (bg_flags & BG_TINT_BITAND)) { XGCValues gcv; GC gc; @@ -1019,27 +1014,28 @@ { XFillRectangle (dpy, bg_pixmap, gc, 0, 0, window_width, window_height); ret = true; - unsigned long tr_flags = bg_flags & BG_EFFECTS_FLAGS; + bool need_blur = h_blurRadius && v_blurRadius; + bool need_tint = shade != 100 || (bg_flags & BG_TINT_SET); if (!(bg_flags & BG_CLIENT_RENDER)) { - if (bg_flags & BG_NEEDS_BLUR) + if (need_blur) { - if (blur_pixmap (bg_pixmap, visual, window_width, window_height, depth)) - tr_flags &= ~BG_NEEDS_BLUR; + if (blur_pixmap (bg_pixmap, window_width, window_height)) + need_blur = false; } - if (bg_flags & BG_NEEDS_TINT) + if (need_tint) { - if (tint_pixmap (bg_pixmap, visual, window_width, window_height)) - tr_flags &= ~BG_NEEDS_TINT; + if (tint_pixmap (bg_pixmap, window_width, window_height)) + need_tint = false; } - if (tr_flags & BG_NEEDS_TINT) + if (need_tint) { XImage *ximage = XGetImage (dpy, bg_pixmap, 0, 0, bg_pmap_width, bg_pmap_height, AllPlanes, ZPixmap); if (ximage) { /* our own client-side tinting */ - tint_ximage (DefaultVisual (dpy, display->screen), ximage); + tint_ximage (ximage); XPutImage (dpy, bg_pixmap, gc, ximage, 0, 0, 0, 0, ximage->width, ximage->height); XDestroyImage (ximage); @@ -1084,9 +1080,9 @@ # endif # ifdef BG_IMAGE_FROM_FILE - if (bg_flags & BG_IS_FROM_FILE) + if (bg_image.flags & IM_IS_SET) { - if (render_image (transparent)) + if (render_image (bg_image, transparent)) bg_flags |= BG_IS_VALID; } # endif @@ -1150,8 +1146,9 @@ } void -rxvt_term::tint_ximage (Visual *visual, XImage *ximage) +rxvt_term::tint_ximage (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 +1163,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 +1209,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