--- rxvt-unicode/src/xpm.C 2007/08/04 07:05:31 1.58 +++ rxvt-unicode/src/xpm.C 2007/08/06 22:42:05 1.60 @@ -125,6 +125,45 @@ return false; } +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 <= 50) + return diff * align / 100; + else if (align > 50 && align <= 100) + return window_size - image_size + 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; +} + +static inline void +make_clip_rectangle (int pos, int size, int target_size, int &clip_pos, int &clip_size) +{ + if (size <= 0) + { /* special case - tiling */ + clip_pos = pos; + clip_size = target_size; + } + else if (pos < 0) + { + clip_pos = 0; + clip_size = MIN (target_size, size + pos); + } + else + { + clip_pos = pos; + clip_size = size; + if (pos < target_size && (int)clip_size > target_size - pos) + clip_pos = target_size - pos; + } +} + bool bgPixmap_t::handle_geometry (const char *geom) { @@ -318,6 +357,172 @@ return (changed > 0); } +#ifdef HAVE_AFTERIMAGE +bool +bgPixmap_t::render_asim (rxvt_term *target, ASImage *background, ARGB32 background_tint) +{ + if (target == NULL) + return false; + + int target_width = (int)target->szHint.width; + int target_height = (int)target->szHint.height; + int new_pmap_width = target_width, new_pmap_height = target_height; + ASImage *result = NULL; + + int x = 0; + int y = 0; + int w = h_scale * target_width / 100; + int h = v_scale * target_height / 100; + + if (original_asim) + { + x = make_align_position (h_align, target_width, w > 0 ? w : (int)original_asim->width); + y = make_align_position (v_align, target_height, h > 0 ? h : (int)original_asim->height); + } + + int dst_x, dst_y; + int clip_width, clip_height; + + make_clip_rectangle (x, w, target_width, dst_x, clip_width); + make_clip_rectangle (y, h, target_height, dst_y, clip_height); + + /* TODO : actuall scaling code :) */ + if (dst_x >= target_width || dst_y >= target_height + || clip_width <= 0 || clip_height <= 0 || original_asim == NULL) + { + result = background; + dst_x = dst_y = 0; + if (background) + { + new_pmap_width = clip_width = background->width; + new_pmap_height = clip_height = background->height; + } + else + new_pmap_width = new_pmap_height = 0; + } + else + { + result = original_asim; + if ((w > 0 && w != original_asim->width) + || (h > 0 && h != original_asim->height)) + { + result = scale_asimage (target->asv, original_asim, + w > 0 ? w : original_asim->width, + h > 0 ? h : original_asim->height, + background ? ASA_ASImage : ASA_XImage, + 100, ASIMAGE_QUALITY_DEFAULT); + } + if (background == NULL) + {/* if tiling - pixmap has to be sized exactly as the image */ + if (h_scale == 0) + new_pmap_width = result->width; + if (v_scale == 0) + new_pmap_height = result->height; + } + else + {/* if blending background and image - pixmap has to be sized same as target window */ + ASImageLayer *layers = create_image_layers (2); + ASImage *merged_im = NULL; + + layers[0].im = background; + layers[0].clip_width = target_width; + layers[0].clip_height = target_height; + layers[0].tint = background_tint; + layers[1].im = result; + if (w <= 0) + {/* tile horizontally */ + layers[1].dst_x = dst_x - (int)result->width; + layers[1].clip_width = result->width; + } + else + {/* clip horizontally */ + layers[1].dst_x = dst_x; + layers[1].clip_width = clip_width; + } + if (h <= 0) + { + layers[1].dst_y = dst_y - (int)result->height; + layers[1].clip_height = result->height; + } + else + { + layers[1].dst_y = dst_y; + layers[1].clip_height = clip_height; + } + if (target->rs[Rs_blendtype]) + { + layers[1].merge_scanlines = blend_scanlines_name2func (target->rs[Rs_blendtype]); + if (layers[1].merge_scanlines == NULL) + layers[1].merge_scanlines = alphablend_scanlines; + } + ASImage *tmp = merge_layers (target->asv, layers, 2, target_width, target_height, + ASA_XImage, 0, ASIMAGE_QUALITY_DEFAULT); + if (tmp) + { + if (result != original_asim) + destroy_asimage (&result); + result = tmp; + dst_x = dst_y = 0; + clip_width = target_width; + clip_height = target_height; + } + free (layers); + } + } + + if (pixmap) + { + if (result == NULL + || pmap_width != new_pmap_width + || pmap_height != new_pmap_height + || pmap_depth != target->depth) + { + XFreePixmap (target->dpy, pixmap); + pixmap = None; + } + } + + if (result) + { + XGCValues gcv; + GC gc; + + /* create Pixmap */ + if (pixmap == None) + { + pixmap = XCreatePixmap (target->dpy, target->vt, new_pmap_width, new_pmap_height, target->depth); + pmap_width = new_pmap_width; + pmap_height = new_pmap_height; + pmap_depth = target->depth; + } + /* fill with background color ( if result's not completely overlapping it)*/ + gcv.foreground = target->pix_colors[Color_bg]; + gc = XCreateGC (target->dpy, target->vt, GCForeground, &gcv); + + if (dst_x > 0 || dst_y > 0 + || dst_x + clip_width < new_pmap_width + || dst_y + clip_height < new_pmap_height) + { + XFillRectangle (target->dpy, pixmap, gc, 0, 0, new_pmap_width, new_pmap_height); + } + /* put result on pixmap */ + asimage2drawable (target->asv, pixmap, result, gc, 0, 0, dst_x, dst_y, clip_width, clip_height, True); + + /* set target's background to pixmap */ + XSetWindowBackgroundPixmap (target->dpy, target->vt, pixmap); + + XFreeGC (target->dpy, gc); + } + else + { + /* set target background to a pixel */ + XSetWindowBackground (target->dpy, target->vt, target->pix_colors[Color_bg]); + } + + return true; +} +#endif + void rxvt_term::resize_pixmap () {