[Spice-devel] [PATCH 19/30] Convert cairo canvas draw_transparent to use pixman

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


---
 common/cairo_canvas.c |  254 ++++++++++++++++++++++++++-----------------------
 1 files changed, 135 insertions(+), 119 deletions(-)

diff --git a/common/cairo_canvas.c b/common/cairo_canvas.c
index be9d3d8..e149b7d 100644
--- a/common/cairo_canvas.c
+++ b/common/cairo_canvas.c
@@ -1433,6 +1433,111 @@ static void blend_scale_image (CairoCanvas *canvas,
     pixman_image_set_clip_region32 (canvas->image, NULL);
 }
 
+static void colorkey_image (CairoCanvas *canvas,
+                            pixman_region32_t *region,
+                            SPICE_ADDRESS src_bitmap,
+                            int offset_x, int offset_y,
+                            uint32_t transparent_color)
+{
+    pixman_image_t *src_image;
+    pixman_box32_t *rects;
+    int n_rects, i;
+
+    rects = pixman_region32_rectangles (region, &n_rects);
+
+    src_image = canvas_get_image(&canvas->base, src_bitmap);
+    for (i = 0; i < n_rects; i++) {
+        int src_x, src_y, dest_x, dest_y, width, height;
+
+        dest_x = rects[i].x1;
+        dest_y = rects[i].y1;
+        width = rects[i].x2 - rects[i].x1;
+        height = rects[i].y2 - rects[i].y1;
+
+        src_x = rects[i].x1 - offset_x;
+        src_y = rects[i].y1 - offset_y;
+
+        spice_pixman_blit_colorkey (canvas->image,
+                                    src_image,
+                                    src_x, src_y,
+                                    dest_x, dest_y,
+                                    width, height,
+                                    transparent_color);
+    }
+    pixman_image_unref (src_image);
+}
+
+static void colorkey_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,
+                                  uint32_t transparent_color)
+{
+    pixman_transform_t transform;
+    pixman_image_t *src;
+    pixman_image_t *scaled;
+    pixman_box32_t *rects;
+    int n_rects, i;
+    double sx, sy;
+
+    sx = (double)(src_width) / (dest_width);
+    sy = (double)(src_height) / (dest_height);
+
+    src = canvas_get_image(&canvas->base, src_bitmap);
+
+    scaled = pixman_image_create_bits(PIXMAN_x8r8g8b8,
+                                      dest_width,
+                                      dest_height,
+                                      NULL, 0);
+
+    pixman_region32_translate (region, -dest_x, -dest_y);
+    pixman_image_set_clip_region32 (scaled, region);
+
+    pixman_transform_init_scale(&transform,
+                                pixman_double_to_fixed(sx),
+                                pixman_double_to_fixed(sy));
+
+    pixman_image_set_transform (src, &transform);
+    pixman_image_set_repeat(src, PIXMAN_REPEAT_NONE);
+    pixman_image_set_source_clipping(src, TRUE);
+    pixman_image_set_filter (src,
+                             PIXMAN_FILTER_NEAREST,
+                             NULL, 0);
+
+    pixman_image_composite32 (PIXMAN_OP_SRC,
+                              src, NULL, scaled,
+                              ROUND(src_x / sx), ROUND(src_y / sy), /* src */
+                              0, 0, /* mask */
+                              0, 0, /* dst */
+                              dest_width,
+                              dest_height);
+
+    pixman_transform_init_identity (&transform);
+    pixman_image_set_transform (src, &transform);
+
+    /* Translate back */
+    pixman_region32_translate (region, dest_x, dest_y);
+
+    rects = pixman_region32_rectangles (region, &n_rects);
+
+    for (i = 0; i < n_rects; i++) {
+        spice_pixman_blit_colorkey (canvas->image,
+                                    scaled,
+                                    rects[i].x1 - dest_x,
+                                    rects[i].y1 - dest_y,
+                                    rects[i].x1, rects[i].y1,
+                                    rects[i].x2 - rects[i].x1,
+                                    rects[i].y2 - rects[i].y1,
+                                    transparent_color);
+    }
+
+    pixman_image_unref (scaled);
+    pixman_image_unref (src);
+}
+
 static void draw_brush(CairoCanvas *canvas,
                        pixman_region32_t *region,
                        SpiceBrush *brush,
@@ -1506,51 +1611,6 @@ void canvas_draw_fill(CairoCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, Spi
     pixman_region32_fini (&dest_region);
 }
 
-static cairo_pattern_t *canvas_src_image_to_pat(CairoCanvas *canvas, SPICE_ADDRESS src_bitmap,
-                                                const SpiceRect *src, const SpiceRect *dest, int invers,
-                                                int scale_mode)
-{
-    cairo_pattern_t *pattern;
-    pixman_image_t *surface;
-    cairo_surface_t *cairo_surface;
-    cairo_matrix_t matrix;
-
-    ASSERT(src_bitmap);
-    ASSERT(scale_mode == SPICE_IMAGE_SCALE_MODE_INTERPOLATE || scale_mode == SPICE_IMAGE_SCALE_MODE_NEAREST);
-    if (invers) {
-        surface = canvas_get_invers_image(canvas, src_bitmap);
-    } else {
-        surface = canvas_get_image(&canvas->base, src_bitmap);
-    }
-
-    cairo_surface = surface_from_pixman_image (surface);
-    pixman_image_unref (surface);
-    pattern = cairo_pattern_create_for_surface(cairo_surface);
-    cairo_surface_destroy(cairo_surface);
-    if (cairo_pattern_status(pattern) != CAIRO_STATUS_SUCCESS) {
-        CANVAS_ERROR("create pattern failed, %s",
-                     cairo_status_to_string(cairo_pattern_status(pattern)));
-    }
-
-    if (!rect_is_same_size(src, dest)) {
-        double sx, sy;
-
-        sx = (double)(src->right - src->left) / (dest->right - dest->left);
-        sy = (double)(src->bottom - src->top) / (dest->bottom - dest->top);
-
-        cairo_matrix_init_scale(&matrix, sx, sy);
-        cairo_pattern_set_filter(pattern, (scale_mode == SPICE_IMAGE_SCALE_MODE_NEAREST) ?
-                                 CAIRO_FILTER_NEAREST : CAIRO_FILTER_GOOD);
-
-        cairo_matrix_translate(&matrix, src->left / sx - dest->left, src->top / sy - dest->top);
-    } else {
-        cairo_matrix_init_translate(&matrix, src->left - dest->left, src->top - dest->top);
-    }
-
-    cairo_pattern_set_matrix(pattern, &matrix);
-    return pattern;
-}
-
 void canvas_draw_copy(CairoCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, SpiceCopy *copy)
 {
     pixman_region32_t dest_region;
@@ -1718,88 +1778,44 @@ void canvas_put_image(CairoCanvas *canvas, const SpiceRect *dest, const uint8_t
     cairo_restore(cairo);
 }
 
-static cairo_surface_t *canvas_surf_to_color_maks_invers(cairo_surface_t *surface,
-                                                         uint32_t trans_color)
-{
-    int width = cairo_image_surface_get_width(surface);
-    int height = cairo_image_surface_get_height(surface);
-    uint8_t *src_line;
-    uint8_t *end_src_line;
-    int src_stride;
-    uint8_t *dest_line;
-    int dest_stride;
-    cairo_surface_t *mask;
-    int i;
-
-    ASSERT(cairo_image_surface_get_format(surface) == CAIRO_FORMAT_ARGB32 ||
-           cairo_image_surface_get_format(surface) == CAIRO_FORMAT_RGB24);
-
-    mask = cairo_image_surface_create(CAIRO_FORMAT_A1, width, height);
-    if (cairo_surface_status(mask) != CAIRO_STATUS_SUCCESS) {
-        CANVAS_ERROR("create surface failed, %s",
-                     cairo_status_to_string(cairo_surface_status(mask)));
-    }
-
-    src_line = cairo_image_surface_get_data(surface);
-    src_stride = cairo_image_surface_get_stride(surface);
-    end_src_line = src_line + src_stride * height;
-
-    dest_line = cairo_image_surface_get_data(mask);
-    dest_stride = cairo_image_surface_get_stride(mask);
-
-    for (; src_line != end_src_line; src_line += src_stride, dest_line += dest_stride) {
-        memset(dest_line, 0xff, dest_stride);
-        for (i = 0; i < width; i++) {
-            if ((((uint32_t*)src_line)[i] & 0x00ffffff) == trans_color) {
-                dest_line[i >> 3] &= ~(1 << (i & 0x07));
-            }
-        }
-    }
-
-    return mask;
-}
-
 void canvas_draw_transparent(CairoCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, SpiceTransparent* transparent)
 {
-    cairo_t *cairo = canvas->cairo;
-    cairo_pattern_t *pattern;
-    cairo_pattern_t *mask;
-    cairo_surface_t *surface;
-    cairo_surface_t *mask_surf;
-    cairo_matrix_t matrix;
+    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, transparent->src_bitmap, &transparent->src_area, bbox,
-                                      0, SPICE_IMAGE_SCALE_MODE_NEAREST);
-    if (cairo_pattern_get_surface(pattern, &surface) != CAIRO_STATUS_SUCCESS) {
-        CANVAS_ERROR("surfase from pattern pattern failed");
-    }
+    canvas_clip_pixman (canvas, &dest_region, clip);
 
-    mask_surf = canvas_surf_to_color_maks_invers(surface, transparent->true_color);
-    mask = cairo_pattern_create_for_surface(mask_surf);
-    cairo_surface_destroy(mask_surf);
-    if (cairo_pattern_status(mask) != CAIRO_STATUS_SUCCESS) {
-        CANVAS_ERROR("create pattern failed, %s",
-                     cairo_status_to_string(cairo_pattern_status(pattern)));
+    if (pixman_region32_n_rects (&dest_region) == 0) {
+        canvas_touch_image (&canvas->base, transparent->src_bitmap);
+        pixman_region32_fini (&dest_region);
+        return;
     }
-    cairo_pattern_get_matrix(pattern, &matrix);
-    cairo_pattern_set_matrix(mask, &matrix);
 
-    cairo_set_source(cairo, pattern);
-    cairo_pattern_destroy(pattern);
-    cairo_set_operator(cairo, CAIRO_OPERATOR_RASTER_COPY);
-    cairo_mask(cairo, mask);
-    cairo_pattern_destroy(mask);
+    if (rect_is_same_size (bbox, &transparent->src_area)) {
+        colorkey_image (canvas, &dest_region,
+                        transparent->src_bitmap,
+                        bbox->left - transparent->src_area.left,
+                        bbox->top - transparent->src_area.top,
+                        transparent->true_color);
+    } else {
+        colorkey_scale_image (canvas, &dest_region,
+                              transparent->src_bitmap,
+                              transparent->src_area.left,
+                              transparent->src_area.top,
+                              transparent->src_area.right - transparent->src_area.left,
+                              transparent->src_area.bottom - transparent->src_area.top,
+                              bbox->left,
+                              bbox->top,
+                              bbox->right - bbox->left,
+                              bbox->bottom - bbox->top,
+                              transparent->true_color);
+    }
 
-    cairo_restore(cairo);
+    pixman_region32_fini (&dest_region);
 }
 
 void canvas_draw_alpha_blend(CairoCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, SpiceAlphaBlnd* alpha_blend)
-- 
1.6.6



More information about the Spice-devel mailing list