[Spice-devel] [PATCH 16/30] Convert cairo canvas alpha_blend to using pixman

Alexander Larsson alexl at redhat.com
Thu Feb 18 12:58:42 PST 2010


---
 common/cairo_canvas.c |  153 +++++++++++++++++++++++++++++++++++++++++++------
 1 files changed, 136 insertions(+), 17 deletions(-)

diff --git a/common/cairo_canvas.c b/common/cairo_canvas.c
index b837a1f..71dfae5 100644
--- a/common/cairo_canvas.c
+++ b/common/cairo_canvas.c
@@ -1334,6 +1334,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_set_source_clipping(src, TRUE);
+
+    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);
+    pixman_image_set_source_clipping(src, TRUE);
+    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,
@@ -1705,26 +1803,47 @@ 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,
-                    bbox->left,
-                    bbox->top,
-                    bbox->right - bbox->left,
-                    bbox->bottom - bbox->top);
-    cairo_clip(cairo);
-    canvas_clip(canvas, clip);
+    pixman_region32_init_rect (&dest_region,
+                               bbox->left, bbox->top,
+                               bbox->right - bbox->left,
+                               bbox->bottom - bbox->top);
 
-    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);
+    canvas_clip_pixman (canvas, &dest_region, clip);
 
-    cairo_restore(cairo);
+    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 (0&&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,
+                     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);
+    }
+
+    pixman_region32_fini (&dest_region);
 }
 
 void canvas_draw_opaque(CairoCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, SpiceOpaque *opaque)
-- 
1.6.6



More information about the Spice-devel mailing list