diff options
author | Alexander Larsson <alexl@redhat.com> | 2010-02-11 17:25:12 +0100 |
---|---|---|
committer | Alexander Larsson <alexl@redhat.com> | 2010-02-23 22:52:05 +0100 |
commit | 974c662ae4f3375ea4162556ac644f1431af2f9f (patch) | |
tree | c2324b0ae0ec15ce3e288a52fdfb91ea33b961c9 /common | |
parent | 824496405ab1f7550e9f98a445342777e700aae5 (diff) | |
download | spice-974c662ae4f3375ea4162556ac644f1431af2f9f.tar.gz spice-974c662ae4f3375ea4162556ac644f1431af2f9f.tar.xz spice-974c662ae4f3375ea4162556ac644f1431af2f9f.zip |
Convert cairo canvas alpha_blend to using pixman
Diffstat (limited to 'common')
-rw-r--r-- | common/cairo_canvas.c | 150 |
1 files changed, 135 insertions, 15 deletions
diff --git a/common/cairo_canvas.c b/common/cairo_canvas.c index 8e9c2d6d..065bfa23 100644 --- a/common/cairo_canvas.c +++ b/common/cairo_canvas.c @@ -1389,6 +1389,104 @@ static void scale_image_rop(CairoCanvas *canvas, pixman_image_unref(src); } +static void blend_image(CairoCanvas *canvas, + pixman_region32_t *region, + SPICE_ADDRESS src_bitmap, + int src_x, int src_y, + int dest_x, int dest_y, + int width, int height, + int overall_alpha) +{ + pixman_image_t *src, *mask; + + src = canvas_get_image(&canvas->base, src_bitmap); + + pixman_image_set_clip_region32(canvas->image, region); + + mask = NULL; + if (overall_alpha != 0xff) { + pixman_color_t color = { 0 }; + color.alpha = overall_alpha * 0x101; + mask = pixman_image_create_solid_fill(&color); + } + + pixman_image_set_repeat(src, PIXMAN_REPEAT_NONE); + + pixman_image_composite32(PIXMAN_OP_OVER, + src, mask, canvas->image, + src_x, src_y, /* src */ + 0, 0, /* mask */ + dest_x, dest_y, /* dst */ + width, + height); + + if (mask) { + pixman_image_unref(mask); + } + pixman_image_unref(src); + + pixman_image_set_clip_region32(canvas->image, NULL); +} + +static void blend_scale_image(CairoCanvas *canvas, + pixman_region32_t *region, + SPICE_ADDRESS src_bitmap, + int src_x, int src_y, + int src_width, int src_height, + int dest_x, int dest_y, + int dest_width, int dest_height, + int scale_mode, + int overall_alpha) +{ + pixman_transform_t transform; + pixman_image_t *src, *mask; + double sx, sy; + + sx = (double)(src_width) / (dest_width); + sy = (double)(src_height) / (dest_height); + + src = canvas_get_image(&canvas->base, src_bitmap); + + pixman_image_set_clip_region32(canvas->image, region); + + pixman_transform_init_scale(&transform, + pixman_double_to_fixed(sx), + pixman_double_to_fixed(sy)); + + mask = NULL; + if (overall_alpha != 0xff) { + pixman_color_t color = { 0 }; + color.alpha = overall_alpha * 0x101; + mask = pixman_image_create_solid_fill(&color); + } + + pixman_image_set_transform(src, &transform); + pixman_image_set_repeat(src, PIXMAN_REPEAT_NONE); + ASSERT(scale_mode == SPICE_IMAGE_SCALE_MODE_INTERPOLATE || + scale_mode == SPICE_IMAGE_SCALE_MODE_NEAREST); + pixman_image_set_filter(src, + (scale_mode == SPICE_IMAGE_SCALE_MODE_NEAREST) ? + PIXMAN_FILTER_NEAREST : PIXMAN_FILTER_GOOD, + NULL, 0); + + pixman_image_composite32(PIXMAN_OP_OVER, + src, mask, canvas->image, + ROUND(src_x / sx), ROUND(src_y / sy), /* src */ + 0, 0, /* mask */ + dest_x, dest_y, /* dst */ + dest_width, dest_height); + + pixman_transform_init_identity(&transform); + pixman_image_set_transform(src, &transform); + + if (mask) { + pixman_image_unref(mask); + } + pixman_image_unref(src); + + pixman_image_set_clip_region32(canvas->image, NULL); +} + static void draw_brush(CairoCanvas *canvas, pixman_region32_t *region, SpiceBrush *brush, @@ -1765,26 +1863,48 @@ void canvas_draw_transparent(CairoCanvas *canvas, SpiceRect *bbox, SpiceClip *cl void canvas_draw_alpha_blend(CairoCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, SpiceAlphaBlnd* alpha_blend) { - cairo_t *cairo = canvas->cairo; - cairo_pattern_t *pattern; + pixman_region32_t dest_region; - cairo_save(cairo); - cairo_rectangle(cairo, + pixman_region32_init_rect(&dest_region, + bbox->left, bbox->top, + bbox->right - bbox->left, + bbox->bottom - bbox->top); + + canvas_clip_pixman(canvas, &dest_region, clip); + + if (alpha_blend->alpha == 0 || + pixman_region32_n_rects(&dest_region) == 0) { + canvas_touch_image(&canvas->base, alpha_blend->src_bitmap); + pixman_region32_fini(&dest_region); + return; + } + + if (rect_is_same_size(bbox, &alpha_blend->src_area)) { + blend_image(canvas, &dest_region, + alpha_blend->src_bitmap, + alpha_blend->src_area.left, + alpha_blend->src_area.top, bbox->left, bbox->top, bbox->right - bbox->left, - bbox->bottom - bbox->top); - cairo_clip(cairo); - canvas_clip(canvas, clip); - - pattern = canvas_src_image_to_pat(canvas, alpha_blend->src_bitmap, &alpha_blend->src_area, bbox, - 0, SPICE_IMAGE_SCALE_MODE_INTERPOLATE); - cairo_set_source(cairo, pattern); - cairo_pattern_destroy(pattern); - cairo_set_operator(cairo, CAIRO_OPERATOR_ATOP); - cairo_paint_with_alpha(cairo, (double)alpha_blend->alpha / 0xff); + bbox->bottom - bbox->top, + alpha_blend->alpha); + } else { + blend_scale_image(canvas, &dest_region, + alpha_blend->src_bitmap, + alpha_blend->src_area.left, + alpha_blend->src_area.top, + alpha_blend->src_area.right - alpha_blend->src_area.left, + alpha_blend->src_area.bottom - alpha_blend->src_area.top, + bbox->left, + bbox->top, + bbox->right - bbox->left, + bbox->bottom - bbox->top, + SPICE_IMAGE_SCALE_MODE_INTERPOLATE, + alpha_blend->alpha); + } - cairo_restore(cairo); + pixman_region32_fini(&dest_region); } void canvas_draw_opaque(CairoCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, SpiceOpaque *opaque) |