summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexander Larsson <alexl@redhat.com>2010-02-11 17:25:12 +0100
committerAlexander Larsson <alexl@redhat.com>2010-02-23 22:52:05 +0100
commit974c662ae4f3375ea4162556ac644f1431af2f9f (patch)
treec2324b0ae0ec15ce3e288a52fdfb91ea33b961c9
parent824496405ab1f7550e9f98a445342777e700aae5 (diff)
downloadspice-974c662ae4f3375ea4162556ac644f1431af2f9f.tar.gz
spice-974c662ae4f3375ea4162556ac644f1431af2f9f.tar.xz
spice-974c662ae4f3375ea4162556ac644f1431af2f9f.zip
Convert cairo canvas alpha_blend to using pixman
-rw-r--r--common/cairo_canvas.c150
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)