[Spice-devel] [PATCH 6/8] Move most of the shared draw_xyz() methods from CairoCanvas to CanvasBase

alexl at redhat.com alexl at redhat.com
Mon Mar 8 09:33:57 PST 2010


From: Alexander Larsson <alexl at redhat.com>

This adds a set of virtual methods for low-level operations. A subclass
can choose to implement those and let the default CanvasBase implementations
handle the highlevel stuff.
---
 common/cairo_canvas.c | 1063 +++++++------------------------------------------
 common/canvas_base.c  |  824 ++++++++++++++++++++++++++++++++++++++-
 common/canvas_base.h  |   84 ++++
 3 files changed, 1039 insertions(+), 932 deletions(-)

diff --git a/common/cairo_canvas.c b/common/cairo_canvas.c
index 2c5b0d7..c5ef3b2 100644
--- a/common/cairo_canvas.c
+++ b/common/cairo_canvas.c
@@ -36,304 +36,6 @@ struct CairoCanvas {
     pixman_image_t *image;
 };
 
-typedef enum {
-    ROP_INPUT_SRC,
-    ROP_INPUT_BRUSH,
-    ROP_INPUT_DEST
-} ROPInput;
-
-SpiceROP ropd_descriptor_to_rop(int desc,
-                                ROPInput src_input,
-                                ROPInput dest_input)
-{
-    int old;
-    int invert_masks[] = {
-        SPICE_ROPD_INVERS_SRC,
-        SPICE_ROPD_INVERS_BRUSH,
-        SPICE_ROPD_INVERS_DEST
-    };
-
-    old = desc;
-
-    desc &= ~(SPICE_ROPD_INVERS_SRC | SPICE_ROPD_INVERS_DEST);
-    if (old & invert_masks[src_input]) {
-        desc |= SPICE_ROPD_INVERS_SRC;
-    }
-
-    if (old & invert_masks[dest_input]) {
-        desc |= SPICE_ROPD_INVERS_DEST;
-    }
-
-    if (desc & SPICE_ROPD_OP_PUT) {
-        if (desc & SPICE_ROPD_INVERS_SRC) {
-            if (desc & SPICE_ROPD_INVERS_RES) {
-                return SPICE_ROP_COPY;
-            }
-            return SPICE_ROP_COPY_INVERTED;
-        } else {
-            if (desc & SPICE_ROPD_INVERS_RES) {
-                return SPICE_ROP_COPY_INVERTED;
-            }
-            return SPICE_ROP_COPY;
-        }
-    } else if (desc & SPICE_ROPD_OP_OR) {
-
-        if (desc & SPICE_ROPD_INVERS_RES) {
-            if (desc & SPICE_ROPD_INVERS_SRC) {
-                if (desc & SPICE_ROPD_INVERS_DEST) {
-                    /* !(!src or !dest) == src and dest*/
-                    return SPICE_ROP_AND;
-                } else {
-                    /* ! (!src or dest) = src and !dest*/
-                    return SPICE_ROP_AND_REVERSE;
-                }
-            } else {
-                if (desc & SPICE_ROPD_INVERS_DEST) {
-                    /* !(src or !dest) == !src and dest */
-                    return SPICE_ROP_AND_INVERTED;
-                } else {
-                    /* !(src or dest) */
-                    return SPICE_ROP_NOR;
-                }
-            }
-        } else {
-            if (desc & SPICE_ROPD_INVERS_SRC) {
-                if (desc & SPICE_ROPD_INVERS_DEST) {
-                    /* !src or !dest == !(src and dest)*/
-                    return SPICE_ROP_NAND;
-                } else {
-                    /* !src or dest */
-                    return SPICE_ROP_OR_INVERTED;
-                }
-            } else {
-                if (desc & SPICE_ROPD_INVERS_DEST) {
-                    /* src or !dest */
-                    return SPICE_ROP_OR_REVERSE;
-                } else {
-                    /* src or dest */
-                    return SPICE_ROP_OR;
-                }
-            }
-        }
-
-    } else if (desc & SPICE_ROPD_OP_AND) {
-
-        if (desc & SPICE_ROPD_INVERS_RES) {
-            if (desc & SPICE_ROPD_INVERS_SRC) {
-                if (desc & SPICE_ROPD_INVERS_DEST) {
-                    /* !(!src and !dest) == src or dest*/
-                    return SPICE_ROP_OR;
-                } else {
-                    /* ! (!src and dest) = src or !dest*/
-                    return SPICE_ROP_OR_REVERSE;
-                }
-            } else {
-                if (desc & SPICE_ROPD_INVERS_DEST) {
-                    /* !(src and !dest) == !src or dest */
-                    return SPICE_ROP_OR_INVERTED;
-                } else {
-                    /* !(src and dest) */
-                    return SPICE_ROP_NAND;
-                }
-            }
-        } else {
-            if (desc & SPICE_ROPD_INVERS_SRC) {
-                if (desc & SPICE_ROPD_INVERS_DEST) {
-                    /* !src and !dest == !(src or dest)*/
-                    return SPICE_ROP_NOR;
-                } else {
-                    /* !src and dest */
-                    return SPICE_ROP_AND_INVERTED;
-                }
-            } else {
-                if (desc & SPICE_ROPD_INVERS_DEST) {
-                    /* src and !dest */
-                    return SPICE_ROP_AND_REVERSE;
-                } else {
-                    /* src and dest */
-                    return SPICE_ROP_AND;
-                }
-            }
-        }
-
-    } else if (desc & SPICE_ROPD_OP_XOR) {
-
-        if (desc & SPICE_ROPD_INVERS_RES) {
-            if (desc & SPICE_ROPD_INVERS_SRC) {
-                if (desc & SPICE_ROPD_INVERS_DEST) {
-                    /* !(!src xor !dest) == !src xor dest */
-                    return SPICE_ROP_EQUIV;
-                } else {
-                    /* ! (!src xor dest) = src xor dest*/
-                    return SPICE_ROP_XOR;
-                }
-            } else {
-                if (desc & SPICE_ROPD_INVERS_DEST) {
-                    /* !(src xor !dest) == src xor dest */
-                    return SPICE_ROP_XOR;
-                } else {
-                    /* !(src xor dest) */
-                    return SPICE_ROP_EQUIV;
-                }
-            }
-        } else {
-            if (desc & SPICE_ROPD_INVERS_SRC) {
-                if (desc & SPICE_ROPD_INVERS_DEST) {
-                    /* !src xor !dest == src xor dest */
-                    return SPICE_ROP_XOR;
-                } else {
-                    /* !src xor dest */
-                    return SPICE_ROP_EQUIV;
-                }
-            } else {
-                if (desc & SPICE_ROPD_INVERS_DEST) {
-                    /* src xor !dest */
-                    return SPICE_ROP_EQUIV;
-                } else {
-                    /* src xor dest */
-                    return SPICE_ROP_XOR;
-                }
-            }
-        }
-
-    } else if (desc & SPICE_ROPD_OP_BLACKNESS) {
-        return SPICE_ROP_CLEAR;
-    } else if (desc & SPICE_ROPD_OP_WHITENESS) {
-        return SPICE_ROP_SET;
-    } else if (desc & SPICE_ROPD_OP_INVERS) {
-        return SPICE_ROP_INVERT;
-    }
-    return SPICE_ROP_COPY;
-}
-
-static void canvas_clip_pixman(CairoCanvas *canvas,
-                               pixman_region32_t *dest_region,
-                               SpiceClip *clip)
-{
-    pixman_region32_intersect(dest_region, dest_region, &canvas->base.canvas_region);
-
-    switch (clip->type) {
-    case SPICE_CLIP_TYPE_NONE:
-        break;
-    case SPICE_CLIP_TYPE_RECTS: {
-        uint32_t *n = (uint32_t *)SPICE_GET_ADDRESS(clip->data);
-        access_test(&canvas->base, n, sizeof(uint32_t));
-
-        SpiceRect *now = (SpiceRect *)(n + 1);
-        access_test(&canvas->base, now, (unsigned long)(now + *n) - (unsigned long)now);
-
-        pixman_region32_t clip;
-
-        if (spice_pixman_region32_init_rects(&clip, now, *n)) {
-            pixman_region32_intersect(dest_region, dest_region, &clip);
-            pixman_region32_fini(&clip);
-        }
-
-        break;
-    }
-    case SPICE_CLIP_TYPE_PATH:
-        CANVAS_ERROR("clip paths not supported anymore");
-        break;
-    default:
-        CANVAS_ERROR("invalid clip type");
-    }
-}
-
-static void canvas_mask_pixman(CairoCanvas *canvas,
-                               pixman_region32_t *dest_region,
-                               SpiceQMask *mask, int x, int y)
-{
-    pixman_image_t *image, *subimage;
-    int needs_invert;
-    pixman_region32_t mask_region;
-    uint32_t *mask_data;
-    int mask_x, mask_y;
-    int mask_width, mask_height, mask_stride;
-    pixman_box32_t extents;
-
-    needs_invert = FALSE;
-    image = canvas_get_mask(&canvas->base,
-                            mask,
-                            &needs_invert);
-
-    if (image == NULL) {
-        return; /* no mask */
-    }
-
-    mask_data = pixman_image_get_data(image);
-    mask_width = pixman_image_get_width(image);
-    mask_height = pixman_image_get_height(image);
-    mask_stride = pixman_image_get_stride(image);
-
-    mask_x = mask->pos.x;
-    mask_y = mask->pos.y;
-
-    /* We need to subset the area of the mask that we turn into a region,
-       because a cached mask may be much larger than what is used for
-       the clip operation. */
-    extents = *pixman_region32_extents(dest_region);
-
-    /* convert from destination pixels to mask pixels */
-    extents.x1 -= x - mask_x;
-    extents.y1 -= y - mask_y;
-    extents.x2 -= x - mask_x;
-    extents.y2 -= y - mask_y;
-
-    /* clip to mask size */
-    if (extents.x1 < 0) {
-        extents.x1 = 0;
-    }
-    if (extents.x2 >= mask_width) {
-        extents.x2 = mask_width;
-    }
-    if (extents.x2 < extents.x1) {
-        extents.x2 = extents.x1;
-    }
-    if (extents.y1 < 0) {
-        extents.y1 = 0;
-    }
-    if (extents.y2 >= mask_height) {
-        extents.y2 = mask_height;
-    }
-    if (extents.y2 < extents.y1) {
-        extents.y2 = extents.y1;
-    }
-
-    /* round down X to even 32 pixels (i.e. uint32_t) */
-    extents.x1 = extents.x1 & ~(0x1f);
-
-    mask_data = (uint32_t *)((uint8_t *)mask_data + mask_stride * extents.y1 + extents.x1 / 32);
-    mask_x -= extents.x1;
-    mask_y -= extents.y1;
-    mask_width = extents.x2 - extents.x1;
-    mask_height = extents.y2 - extents.y1;
-
-    subimage = pixman_image_create_bits(PIXMAN_a1, mask_width, mask_height,
-                                        mask_data, mask_stride);
-    pixman_region32_init_from_image(&mask_region,
-                                    subimage);
-    pixman_image_unref(subimage);
-
-    if (needs_invert) {
-        pixman_box32_t rect;
-
-        rect.x1 = rect.y1 = 0;
-        rect.x2 = mask_width;
-        rect.y2 = mask_height;
-
-        pixman_region32_inverse(&mask_region, &mask_region, &rect);
-    }
-
-    pixman_region32_translate(&mask_region,
-                              -mask_x + x, -mask_y + y);
-
-    pixman_region32_intersect(dest_region, dest_region, &mask_region);
-    pixman_region32_fini(&mask_region);
-
-    pixman_image_unref(image);
-}
-
-
 static pixman_image_t* canvas_surface_from_self(CairoCanvas *canvas,
                                                 int x, int y,
                                                 int32_t width, int32_t heigth)
@@ -401,10 +103,11 @@ static pixman_image_t *canvas_get_pixman_brush(CairoCanvas *canvas,
 }
 
 
-static void copy_region(CairoCanvas *canvas,
+static void copy_region(SpiceCanvas *spice_canvas,
                         pixman_region32_t *dest_region,
                         int dx, int dy)
 {
+    CairoCanvas *canvas = (CairoCanvas *)spice_canvas;
     pixman_box32_t *dest_rects;
     int n_rects;
     int i, j, end_line;
@@ -470,17 +173,33 @@ static void copy_region(CairoCanvas *canvas,
     }
 }
 
-static void fill_solid_rects(CairoCanvas *canvas,
-                             pixman_region32_t *region,
+static void fill_solid_spans(SpiceCanvas *spice_canvas,
+                             SpicePoint *points,
+                             int *widths,
+                             int n_spans,
                              uint32_t color)
 {
-    pixman_box32_t *rects;
-    int n_rects;
+    CairoCanvas *canvas = (CairoCanvas *)spice_canvas;
     int i;
 
-    rects = pixman_region32_rectangles(region, &n_rects);
+   for (i = 0; i < n_spans; i++) {
+        spice_pixman_fill_rect(canvas->image,
+                               points[i].x, points[i].y,
+                               widths[i],
+                               1,
+                               color);
+    }
+}
 
-    for (i = 0; i < n_rects; i++) {
+static void fill_solid_rects(SpiceCanvas *spice_canvas,
+                             pixman_box32_t *rects,
+                             int n_rects,
+                             uint32_t color)
+{
+    CairoCanvas *canvas = (CairoCanvas *)spice_canvas;
+    int i;
+
+   for (i = 0; i < n_rects; i++) {
         spice_pixman_fill_rect(canvas->image,
                                rects[i].x1, rects[i].y1,
                                rects[i].x2 - rects[i].x1,
@@ -489,18 +208,16 @@ static void fill_solid_rects(CairoCanvas *canvas,
     }
 }
 
-static void fill_solid_rects_rop(CairoCanvas *canvas,
-                                 pixman_region32_t *region,
+static void fill_solid_rects_rop(SpiceCanvas *spice_canvas,
+                                 pixman_box32_t *rects,
+                                 int n_rects,
                                  uint32_t color,
                                  SpiceROP rop)
 {
-    pixman_box32_t *rects;
-    int n_rects;
+    CairoCanvas *canvas = (CairoCanvas *)spice_canvas;
     int i;
 
-    rects = pixman_region32_rectangles(region, &n_rects);
-
-    for (i = 0; i < n_rects; i++) {
+   for (i = 0; i < n_rects; i++) {
         spice_pixman_fill_rect_rop(canvas->image,
                                    rects[i].x1, rects[i].y1,
                                    rects[i].x2 - rects[i].x1,
@@ -509,51 +226,35 @@ static void fill_solid_rects_rop(CairoCanvas *canvas,
     }
 }
 
-static void fill_tiled_rects(CairoCanvas *canvas,
-                             pixman_region32_t *region,
-                             SpicePattern *pattern)
+static void fill_tiled_rects(SpiceCanvas *spice_canvas,
+                             pixman_box32_t *rects,
+                             int n_rects,
+                             pixman_image_t *tile,
+                             int offset_x, int offset_y)
 {
-    pixman_image_t *tile;
-    int offset_x, offset_y;
-    pixman_box32_t *rects;
-    int n_rects;
+    CairoCanvas *canvas = (CairoCanvas *)spice_canvas;
     int i;
 
-    rects = pixman_region32_rectangles(region, &n_rects);
-
-    tile = canvas_get_image(&canvas->base, pattern->pat);
-    offset_x = pattern->pos.x;
-    offset_y = pattern->pos.y;
-
-    for (i = 0; i < n_rects; i++) {
+   for (i = 0; i < n_rects; i++) {
         spice_pixman_tile_rect(canvas->image,
                                rects[i].x1, rects[i].y1,
                                rects[i].x2 - rects[i].x1,
                                rects[i].y2 - rects[i].y1,
                                tile, offset_x, offset_y);
     }
-
-    pixman_image_unref(tile);
 }
 
-static void fill_tiled_rects_rop(CairoCanvas *canvas,
-                                 pixman_region32_t *region,
-                                 SpicePattern *pattern,
+static void fill_tiled_rects_rop(SpiceCanvas *spice_canvas,
+                                 pixman_box32_t *rects,
+                                 int n_rects,
+                                 pixman_image_t *tile,
+                                 int offset_x, int offset_y,
                                  SpiceROP rop)
 {
-    pixman_image_t *tile;
-    int offset_x, offset_y;
-    pixman_box32_t *rects;
-    int n_rects;
+    CairoCanvas *canvas = (CairoCanvas *)spice_canvas;
     int i;
 
-    rects = pixman_region32_rectangles(region, &n_rects);
-
-    tile = canvas_get_image(&canvas->base, pattern->pat);
-    offset_x = pattern->pos.x;
-    offset_y = pattern->pos.y;
-
-    for (i = 0; i < n_rects; i++) {
+   for (i = 0; i < n_rects; i++) {
         spice_pixman_tile_rect_rop(canvas->image,
                                    rects[i].x1, rects[i].y1,
                                    rects[i].x2 - rects[i].x1,
@@ -561,16 +262,14 @@ static void fill_tiled_rects_rop(CairoCanvas *canvas,
                                    tile, offset_x, offset_y,
                                    rop);
     }
-
-    pixman_image_unref(tile);
 }
 
-
-static void blit_with_region(CairoCanvas *canvas,
-                             pixman_region32_t *region,
-                             pixman_image_t *src_image,
-                             int offset_x, int offset_y)
+static void blit_image(SpiceCanvas *spice_canvas,
+                       pixman_region32_t *region,
+                       pixman_image_t *src_image,
+                       int offset_x, int offset_y)
 {
+    CairoCanvas *canvas = (CairoCanvas *)spice_canvas;
     pixman_box32_t *rects;
     int n_rects, i;
 
@@ -595,32 +294,18 @@ static void blit_with_region(CairoCanvas *canvas,
     }
 }
 
-static void blit_image(CairoCanvas *canvas,
-                       pixman_region32_t *region,
-                       SPICE_ADDRESS src_bitmap,
-                       int offset_x, int offset_y)
-{
-    pixman_image_t *src_image;
-
-    src_image = canvas_get_image(&canvas->base, src_bitmap);
-    blit_with_region(canvas, region, src_image,
-                      offset_x, offset_y);
-    pixman_image_unref(src_image);
-}
-
-static void blit_image_rop(CairoCanvas *canvas,
+static void blit_image_rop(SpiceCanvas *spice_canvas,
                            pixman_region32_t *region,
-                           SPICE_ADDRESS src_bitmap,
+                           pixman_image_t *src_image,
                            int offset_x, int offset_y,
                            SpiceROP rop)
 {
-    pixman_image_t *src_image;
+    CairoCanvas *canvas = (CairoCanvas *)spice_canvas;
     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;
 
@@ -638,27 +323,24 @@ static void blit_image_rop(CairoCanvas *canvas,
                               dest_x, dest_y,
                               width, height, rop);
     }
-    pixman_image_unref(src_image);
 }
 
-static void scale_image(CairoCanvas *canvas,
+static void scale_image(SpiceCanvas *spice_canvas,
                         pixman_region32_t *region,
-                        SPICE_ADDRESS src_bitmap,
+                        pixman_image_t *src,
                         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)
 {
+    CairoCanvas *canvas = (CairoCanvas *)spice_canvas;
     pixman_transform_t transform;
-    pixman_image_t *src;
     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,
@@ -685,20 +367,19 @@ static void scale_image(CairoCanvas *canvas,
     pixman_image_set_transform(src, &transform);
 
     pixman_image_set_clip_region32(canvas->image, NULL);
-    pixman_image_unref(src);
 }
 
-static void scale_image_rop(CairoCanvas *canvas,
+static void scale_image_rop(SpiceCanvas *spice_canvas,
                             pixman_region32_t *region,
-                            SPICE_ADDRESS src_bitmap,
+                            pixman_image_t *src,
                             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, SpiceROP rop)
 {
+    CairoCanvas *canvas = (CairoCanvas *)spice_canvas;
     pixman_transform_t transform;
-    pixman_image_t *src;
     pixman_image_t *scaled;
     pixman_box32_t *rects;
     int n_rects, i;
@@ -707,8 +388,6 @@ static void scale_image_rop(CairoCanvas *canvas,
     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,
@@ -758,20 +437,18 @@ static void scale_image_rop(CairoCanvas *canvas,
     }
 
     pixman_image_unref(scaled);
-    pixman_image_unref(src);
 }
 
-static void blend_image(CairoCanvas *canvas,
+static void blend_image(SpiceCanvas *spice_canvas,
                         pixman_region32_t *region,
-                        SPICE_ADDRESS src_bitmap,
+                        pixman_image_t *src,
                         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);
+    CairoCanvas *canvas = (CairoCanvas *)spice_canvas;
+    pixman_image_t *mask;
 
     pixman_image_set_clip_region32(canvas->image, region);
 
@@ -795,14 +472,13 @@ static void blend_image(CairoCanvas *canvas,
     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,
+static void blend_scale_image(SpiceCanvas *spice_canvas,
                               pixman_region32_t *region,
-                              SPICE_ADDRESS src_bitmap,
+                              pixman_image_t *src,
                               int src_x, int src_y,
                               int src_width, int src_height,
                               int dest_x, int dest_y,
@@ -810,15 +486,14 @@ static void blend_scale_image(CairoCanvas *canvas,
                               int scale_mode,
                               int overall_alpha)
 {
+    CairoCanvas *canvas = (CairoCanvas *)spice_canvas;
     pixman_transform_t transform;
-    pixman_image_t *src, *mask;
+    pixman_image_t *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,
@@ -854,24 +529,22 @@ static void blend_scale_image(CairoCanvas *canvas,
     if (mask) {
         pixman_image_unref(mask);
     }
-    pixman_image_unref(src);
 
     pixman_image_set_clip_region32(canvas->image, NULL);
 }
 
-static void colorkey_image(CairoCanvas *canvas,
+static void colorkey_image(SpiceCanvas *spice_canvas,
                            pixman_region32_t *region,
-                           SPICE_ADDRESS src_bitmap,
+                           pixman_image_t *src_image,
                            int offset_x, int offset_y,
                            uint32_t transparent_color)
 {
-    pixman_image_t *src_image;
+    CairoCanvas *canvas = (CairoCanvas *)spice_canvas;
     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;
 
@@ -890,20 +563,19 @@ static void colorkey_image(CairoCanvas *canvas,
                                    width, height,
                                    transparent_color);
     }
-    pixman_image_unref(src_image);
 }
 
-static void colorkey_scale_image(CairoCanvas *canvas,
+static void colorkey_scale_image(SpiceCanvas *spice_canvas,
                                  pixman_region32_t *region,
-                                 SPICE_ADDRESS src_bitmap,
+                                 pixman_image_t *src,
                                  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)
 {
+    CairoCanvas *canvas = (CairoCanvas *)spice_canvas;
     pixman_transform_t transform;
-    pixman_image_t *src;
     pixman_image_t *scaled;
     pixman_box32_t *rects;
     int n_rects, i;
@@ -912,8 +584,6 @@ static void colorkey_scale_image(CairoCanvas *canvas,
     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,
@@ -960,60 +630,16 @@ static void colorkey_scale_image(CairoCanvas *canvas,
     }
 
     pixman_image_unref(scaled);
-    pixman_image_unref(src);
 }
-
-static void draw_brush(CairoCanvas *canvas,
-                       pixman_region32_t *region,
-                       SpiceBrush *brush,
-                       SpiceROP rop)
-{
-    uint32_t color;
-    SpicePattern *pattern;
-
-    switch (brush->type) {
-    case SPICE_BRUSH_TYPE_SOLID:
-        color = brush->u.color;
-        if (rop == SPICE_ROP_COPY) {
-            fill_solid_rects(canvas, region, color);
-        } else {
-            fill_solid_rects_rop(canvas, region, color, rop);
-        }
-        break;
-    case SPICE_BRUSH_TYPE_PATTERN:
-        pattern = &brush->u.pattern;
-
-        if (rop == SPICE_ROP_COPY) {
-            fill_tiled_rects(canvas, region, pattern);
-        } else {
-            fill_tiled_rects_rop(canvas, region, pattern, rop);
-        }
-        break;
-    case SPICE_BRUSH_TYPE_NONE:
-        /* Still need to do *something* here, because rop could be e.g invert dest */
-        fill_solid_rects_rop(canvas, region, 0, rop);
-        break;
-    default:
-        CANVAS_ERROR("invalid brush type");
-    }
-}
-
-/* If we're exiting early we may still have to load an image in case
-   it has to be cached or something */
-static void touch_brush(CairoCanvas *canvas, SpiceBrush *brush)
-{
-    SpicePattern *pattern;
-    if (brush->type == SPICE_BRUSH_TYPE_PATTERN) {
-        pattern = &brush->u.pattern;
-        canvas_touch_image(&canvas->base, pattern->pat);
-    }
-}
-
-static void canvas_draw_fill(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceFill *fill)
+static void canvas_draw_rop3(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceRop3 *rop3)
 {
     CairoCanvas *canvas = (CairoCanvas *)spice_canvas;
     pixman_region32_t dest_region;
-    SpiceROP rop;
+    pixman_image_t *d;
+    pixman_image_t *s;
+    SpicePoint src_pos;
+    int width;
+    int heigth;
 
     pixman_region32_init_rect(&dest_region,
                               bbox->left, bbox->top,
@@ -1021,91 +647,51 @@ static void canvas_draw_fill(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceCl
                               bbox->bottom - bbox->top);
 
 
-    canvas_clip_pixman(canvas, &dest_region, clip);
-    canvas_mask_pixman(canvas, &dest_region, &fill->mask,
+    canvas_clip_pixman(&canvas->base, &dest_region, clip);
+    canvas_mask_pixman(&canvas->base, &dest_region, &rop3->mask,
                        bbox->left, bbox->top);
 
-    rop = ropd_descriptor_to_rop(fill->rop_decriptor,
-                                 ROP_INPUT_BRUSH,
-                                 ROP_INPUT_DEST);
-
-    if (rop == SPICE_ROP_NOOP || pixman_region32_n_rects(&dest_region) == 0) {
-        touch_brush(canvas, &fill->brush);
-        pixman_region32_fini(&dest_region);
-        return;
-    }
-
-    draw_brush(canvas, &dest_region, &fill->brush, rop);
-
-    pixman_region32_fini(&dest_region);
-}
-
-static void canvas_draw_copy(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceCopy *copy)
-{
-    CairoCanvas *canvas = (CairoCanvas *)spice_canvas;
-    pixman_region32_t dest_region;
-    SpiceROP rop;
-
-    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);
-    canvas_mask_pixman(canvas, &dest_region, &copy->mask,
-                       bbox->left, bbox->top);
+    width = bbox->right - bbox->left;
+    heigth = bbox->bottom - bbox->top;
 
-    rop = ropd_descriptor_to_rop(copy->rop_decriptor,
-                                 ROP_INPUT_SRC,
-                                 ROP_INPUT_DEST);
+    d = canvas_surface_from_self(canvas, bbox->left, bbox->top, width, heigth);
+    s = canvas_get_image(&canvas->base, rop3->src_bitmap);
 
-    if (rop == SPICE_ROP_NOOP || pixman_region32_n_rects(&dest_region) == 0) {
-        canvas_touch_image(&canvas->base, copy->src_bitmap);
-        pixman_region32_fini(&dest_region);
-        return;
+    if (!rect_is_same_size(bbox, &rop3->src_area)) {
+        pixman_image_t *scaled_s = canvas_scale_surface(s, &rop3->src_area, width, heigth,
+                                                        rop3->scale_mode);
+        pixman_image_unref(s);
+        s = scaled_s;
+        src_pos.x = 0;
+        src_pos.y = 0;
+    } else {
+        src_pos.x = rop3->src_area.left;
+        src_pos.y = rop3->src_area.top;
     }
+    if (pixman_image_get_width(s) - src_pos.x < width ||
+        pixman_image_get_height(s) - src_pos.y < heigth) {
+        CANVAS_ERROR("bad src bitmap size");
+    }
+    if (rop3->brush.type == SPICE_BRUSH_TYPE_PATTERN) {
+        pixman_image_t *p = canvas_get_image(&canvas->base, rop3->brush.u.pattern.pat);
+        SpicePoint pat_pos;
 
-    if (rect_is_same_size(bbox, &copy->src_area)) {
-        if (rop == SPICE_ROP_COPY) {
-            blit_image(canvas, &dest_region,
-                       copy->src_bitmap,
-                       bbox->left - copy->src_area.left,
-                       bbox->top - copy->src_area.top);
-        } else {
-            blit_image_rop(canvas, &dest_region,
-                           copy->src_bitmap,
-                           bbox->left - copy->src_area.left,
-                           bbox->top - copy->src_area.top,
-                           rop);
-        }
+        pat_pos.x = (bbox->left - rop3->brush.u.pattern.pos.x) % pixman_image_get_width(p);
+        pat_pos.y = (bbox->top - rop3->brush.u.pattern.pos.y) % pixman_image_get_height(p);
+        do_rop3_with_pattern(rop3->rop3, d, s, &src_pos, p, &pat_pos);
+        pixman_image_unref(p);
     } else {
-        if (rop == SPICE_ROP_COPY) {
-            scale_image(canvas, &dest_region,
-                        copy->src_bitmap,
-                        copy->src_area.left,
-                        copy->src_area.top,
-                        copy->src_area.right - copy->src_area.left,
-                        copy->src_area.bottom - copy->src_area.top,
-                        bbox->left,
-                        bbox->top,
-                        bbox->right - bbox->left,
-                        bbox->bottom - bbox->top,
-                        copy->scale_mode);
-        } else {
-            scale_image_rop(canvas, &dest_region,
-                            copy->src_bitmap,
-                            copy->src_area.left,
-                            copy->src_area.top,
-                            copy->src_area.right - copy->src_area.left,
-                            copy->src_area.bottom - copy->src_area.top,
-                            bbox->left,
-                            bbox->top,
-                            bbox->right - bbox->left,
-                            bbox->bottom - bbox->top,
-                            copy->scale_mode,
-                            rop);
-        }
+        uint32_t color = (canvas->base.color_shift) == 8 ? rop3->brush.u.color :
+                                                         canvas_16bpp_to_32bpp(rop3->brush.u.color);
+        do_rop3_with_color(rop3->rop3, d, s, &src_pos, color);
     }
+    pixman_image_unref(s);
+
+    blit_image(spice_canvas, &dest_region, d,
+               bbox->left,
+               bbox->top);
+
+    pixman_image_unref(d);
 
     pixman_region32_fini(&dest_region);
 }
@@ -1168,390 +754,6 @@ static void canvas_put_image(SpiceCanvas *spice_canvas,
     pixman_image_unref(src);
 }
 
-static void canvas_draw_transparent(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceTransparent* transparent)
-{
-    CairoCanvas *canvas = (CairoCanvas *)spice_canvas;
-    pixman_region32_t dest_region;
-
-    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 (pixman_region32_n_rects (&dest_region) == 0) {
-        canvas_touch_image(&canvas->base, transparent->src_bitmap);
-        pixman_region32_fini(&dest_region);
-        return;
-    }
-
-    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);
-    }
-
-    pixman_region32_fini(&dest_region);
-}
-
-static void canvas_draw_alpha_blend(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceAlphaBlnd* alpha_blend)
-{
-    CairoCanvas *canvas = (CairoCanvas *)spice_canvas;
-    pixman_region32_t dest_region;
-
-    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,
-                    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);
-}
-
-static void canvas_draw_opaque(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceOpaque *opaque)
-{
-    CairoCanvas *canvas = (CairoCanvas *)spice_canvas;
-    pixman_region32_t dest_region;
-    SpiceROP rop;
-
-    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);
-    canvas_mask_pixman(canvas, &dest_region, &opaque->mask,
-                       bbox->left, bbox->top);
-
-    rop = ropd_descriptor_to_rop(opaque->rop_decriptor,
-                                 ROP_INPUT_BRUSH,
-                                 ROP_INPUT_SRC);
-
-    if (rop == SPICE_ROP_NOOP || pixman_region32_n_rects(&dest_region) == 0) {
-        canvas_touch_image(&canvas->base, opaque->src_bitmap);
-        touch_brush(canvas, &opaque->brush);
-        pixman_region32_fini(&dest_region);
-        return;
-    }
-
-    if (rect_is_same_size(bbox, &opaque->src_area)) {
-        blit_image(canvas, &dest_region,
-                   opaque->src_bitmap,
-                   bbox->left - opaque->src_area.left,
-                   bbox->top - opaque->src_area.top);
-    } else {
-        scale_image(canvas, &dest_region,
-                    opaque->src_bitmap,
-                    opaque->src_area.left,
-                    opaque->src_area.top,
-                    opaque->src_area.right - opaque->src_area.left,
-                    opaque->src_area.bottom - opaque->src_area.top,
-                    bbox->left,
-                    bbox->top,
-                    bbox->right - bbox->left,
-                    bbox->bottom - bbox->top,
-                    opaque->scale_mode);
-    }
-
-    draw_brush(canvas, &dest_region, &opaque->brush, rop);
-
-    pixman_region32_fini(&dest_region);
-}
-
-static void canvas_draw_blend(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceBlend *blend)
-{
-    CairoCanvas *canvas = (CairoCanvas *)spice_canvas;
-    pixman_region32_t dest_region;
-    SpiceROP rop;
-
-    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);
-    canvas_mask_pixman(canvas, &dest_region, &blend->mask,
-                       bbox->left, bbox->top);
-
-    rop = ropd_descriptor_to_rop(blend->rop_decriptor,
-                                 ROP_INPUT_SRC,
-                                 ROP_INPUT_DEST);
-
-    if (rop == SPICE_ROP_NOOP || pixman_region32_n_rects(&dest_region) == 0) {
-        canvas_touch_image(&canvas->base, blend->src_bitmap);
-        pixman_region32_fini(&dest_region);
-        return;
-    }
-
-    if (rect_is_same_size(bbox, &blend->src_area)) {
-        if (rop == SPICE_ROP_COPY)
-            blit_image(canvas, &dest_region,
-                       blend->src_bitmap,
-                       bbox->left - blend->src_area.left,
-                       bbox->top - blend->src_area.top);
-        else
-            blit_image_rop(canvas, &dest_region,
-                           blend->src_bitmap,
-                           bbox->left - blend->src_area.left,
-                           bbox->top - blend->src_area.top,
-                           rop);
-    } else {
-        double sx, sy;
-
-        sx = (double)(blend->src_area.right - blend->src_area.left) / (bbox->right - bbox->left);
-        sy = (double)(blend->src_area.bottom - blend->src_area.top) / (bbox->bottom - bbox->top);
-
-        if (rop == SPICE_ROP_COPY) {
-            scale_image(canvas, &dest_region,
-                         blend->src_bitmap,
-                         blend->src_area.left,
-                         blend->src_area.top,
-                         blend->src_area.right - blend->src_area.left,
-                         blend->src_area.bottom - blend->src_area.top,
-                         bbox->left,
-                         bbox->top,
-                         bbox->right - bbox->left,
-                         bbox->bottom - bbox->top,
-                         blend->scale_mode);
-        } else {
-            scale_image_rop(canvas, &dest_region,
-                            blend->src_bitmap,
-                            blend->src_area.left,
-                            blend->src_area.top,
-                            blend->src_area.right - blend->src_area.left,
-                            blend->src_area.bottom - blend->src_area.top,
-                            bbox->left,
-                            bbox->top,
-                            bbox->right - bbox->left,
-                            bbox->bottom - bbox->top,
-                            blend->scale_mode, rop);
-        }
-    }
-
-    pixman_region32_fini(&dest_region);
-}
-
-static void canvas_draw_blackness(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceBlackness *blackness)
-{
-    CairoCanvas *canvas = (CairoCanvas *)spice_canvas;
-    pixman_region32_t dest_region;
-
-    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);
-    canvas_mask_pixman(canvas, &dest_region, &blackness->mask,
-                       bbox->left, bbox->top);
-
-    if (pixman_region32_n_rects(&dest_region) == 0) {
-        pixman_region32_fini (&dest_region);
-        return;
-    }
-
-    fill_solid_rects(canvas, &dest_region, 0x000000);
-
-    pixman_region32_fini(&dest_region);
-}
-
-static void canvas_draw_whiteness(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceWhiteness *whiteness)
-{
-    CairoCanvas *canvas = (CairoCanvas *)spice_canvas;
-    pixman_region32_t dest_region;
-
-    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);
-    canvas_mask_pixman(canvas, &dest_region, &whiteness->mask,
-                       bbox->left, bbox->top);
-
-    if (pixman_region32_n_rects(&dest_region) == 0) {
-        pixman_region32_fini(&dest_region);
-        return;
-    }
-
-    fill_solid_rects(canvas, &dest_region, 0xffffffff);
-
-    pixman_region32_fini(&dest_region);
-}
-
-static void canvas_draw_invers(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceInvers *invers)
-{
-    CairoCanvas *canvas = (CairoCanvas *)spice_canvas;
-    pixman_region32_t dest_region;
-
-    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);
-    canvas_mask_pixman(canvas, &dest_region, &invers->mask,
-                       bbox->left, bbox->top);
-
-    if (pixman_region32_n_rects(&dest_region) == 0) {
-        pixman_region32_fini(&dest_region);
-        return;
-    }
-
-    fill_solid_rects_rop(canvas, &dest_region, 0x00000000,
-                         SPICE_ROP_INVERT);
-
-    pixman_region32_fini(&dest_region);
-}
-
-static void canvas_draw_rop3(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceRop3 *rop3)
-{
-    CairoCanvas *canvas = (CairoCanvas *)spice_canvas;
-    pixman_region32_t dest_region;
-    pixman_image_t *d;
-    pixman_image_t *s;
-    SpicePoint src_pos;
-    int width;
-    int heigth;
-
-    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);
-    canvas_mask_pixman(canvas, &dest_region, &rop3->mask,
-                       bbox->left, bbox->top);
-
-    width = bbox->right - bbox->left;
-    heigth = bbox->bottom - bbox->top;
-
-    d = canvas_surface_from_self(canvas, bbox->left, bbox->top, width, heigth);
-    s = canvas_get_image(&canvas->base, rop3->src_bitmap);
-
-    if (!rect_is_same_size(bbox, &rop3->src_area)) {
-        pixman_image_t *scaled_s = canvas_scale_surface(s, &rop3->src_area, width, heigth,
-                                                        rop3->scale_mode);
-        pixman_image_unref(s);
-        s = scaled_s;
-        src_pos.x = 0;
-        src_pos.y = 0;
-    } else {
-        src_pos.x = rop3->src_area.left;
-        src_pos.y = rop3->src_area.top;
-    }
-    if (pixman_image_get_width(s) - src_pos.x < width ||
-        pixman_image_get_height(s) - src_pos.y < heigth) {
-        CANVAS_ERROR("bad src bitmap size");
-    }
-    if (rop3->brush.type == SPICE_BRUSH_TYPE_PATTERN) {
-        pixman_image_t *p = canvas_get_image(&canvas->base, rop3->brush.u.pattern.pat);
-        SpicePoint pat_pos;
-
-        pat_pos.x = (bbox->left - rop3->brush.u.pattern.pos.x) % pixman_image_get_width(p);
-        pat_pos.y = (bbox->top - rop3->brush.u.pattern.pos.y) % pixman_image_get_height(p);
-        do_rop3_with_pattern(rop3->rop3, d, s, &src_pos, p, &pat_pos);
-        pixman_image_unref(p);
-    } else {
-        uint32_t color = (canvas->base.color_shift) == 8 ? rop3->brush.u.color :
-                                                         canvas_16bpp_to_32bpp(rop3->brush.u.color);
-        do_rop3_with_color(rop3->rop3, d, s, &src_pos, color);
-    }
-    pixman_image_unref(s);
-
-    blit_with_region(canvas, &dest_region, d,
-                     bbox->left,
-                     bbox->top);
-
-    pixman_image_unref(d);
-
-    pixman_region32_fini(&dest_region);
-}
-
-static void canvas_copy_bits(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpicePoint *src_pos)
-{
-    CairoCanvas *canvas = (CairoCanvas *)spice_canvas;
-    pixman_region32_t dest_region;
-    int dx, dy;
-
-    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);
-
-    dx = bbox->left - src_pos->x;
-    dy = bbox->top - src_pos->y;
-
-    if (dx != 0 || dy != 0) {
-        pixman_region32_t src_region;
-
-        /* Clip so we don't read outside canvas */
-        pixman_region32_init_rect(&src_region,
-                                  dx, dy,
-                                  pixman_image_get_width (canvas->image),
-                                  pixman_image_get_height (canvas->image));
-        pixman_region32_intersect(&dest_region, &dest_region, &src_region);
-        pixman_region32_fini(&src_region);
-
-        copy_region(canvas, &dest_region, dx, dy);
-    }
-
-    pixman_region32_fini(&dest_region);
-}
 
 static void canvas_draw_text(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceText *text)
 {
@@ -1567,11 +769,11 @@ static void canvas_draw_text(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceCl
                               bbox->right - bbox->left,
                               bbox->bottom - bbox->top);
 
-    canvas_clip_pixman(canvas, &dest_region, clip);
+    canvas_clip_pixman(&canvas->base, &dest_region, clip);
 
     if (pixman_region32_n_rects(&dest_region) == 0) {
-        touch_brush(canvas, &text->fore_brush);
-        touch_brush(canvas, &text->back_brush);
+        touch_brush(&canvas->base, &text->fore_brush);
+        touch_brush(&canvas->base, &text->back_brush);
         pixman_region32_fini(&dest_region);
         return;
     }
@@ -1592,7 +794,7 @@ static void canvas_draw_text(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceCl
         pixman_region32_intersect(&back_region, &back_region, &dest_region);
 
         if (pixman_region32_not_empty(&back_region)) {
-            draw_brush(canvas, &back_region, &text->back_brush, SPICE_ROP_COPY);
+            draw_brush(spice_canvas, &back_region, &text->back_brush, SPICE_ROP_COPY);
         }
 
         pixman_region32_fini(&back_region);
@@ -1942,10 +1144,10 @@ static void canvas_draw_stroke(SpiceCanvas *spice_canvas, SpiceRect *bbox, Spice
                               bbox->right - bbox->left,
                               bbox->bottom - bbox->top);
 
-    canvas_clip_pixman(canvas, &gc.dest_region, clip);
+    canvas_clip_pixman(&canvas->base, &gc.dest_region, clip);
 
     if (pixman_region32_n_rects(&gc.dest_region) == 0) {
-        touch_brush(canvas, &stroke->brush);
+        touch_brush(&canvas->base, &stroke->brush);
         pixman_region32_fini(&gc.dest_region);
         return;
     }
@@ -2194,25 +1396,28 @@ void cairo_canvas_init() //unsafe global function
     need_init = 0;
 
     canvas_base_init_ops(&cairo_canvas_ops);
-    cairo_canvas_ops.draw_fill = canvas_draw_fill;
-    cairo_canvas_ops.draw_copy = canvas_draw_copy;
-    cairo_canvas_ops.draw_opaque = canvas_draw_opaque;
-    cairo_canvas_ops.copy_bits = canvas_copy_bits;
     cairo_canvas_ops.draw_text = canvas_draw_text;
     cairo_canvas_ops.draw_stroke = canvas_draw_stroke;
     cairo_canvas_ops.draw_rop3 = canvas_draw_rop3;
-    cairo_canvas_ops.draw_blend = canvas_draw_blend;
-    cairo_canvas_ops.draw_blackness = canvas_draw_blackness;
-    cairo_canvas_ops.draw_whiteness = canvas_draw_whiteness;
-    cairo_canvas_ops.draw_invers = canvas_draw_invers;
-    cairo_canvas_ops.draw_transparent = canvas_draw_transparent;
-    cairo_canvas_ops.draw_alpha_blend = canvas_draw_alpha_blend;
     cairo_canvas_ops.put_image = canvas_put_image;
     cairo_canvas_ops.clear = canvas_clear;
     cairo_canvas_ops.read_bits = canvas_read_bits;
     cairo_canvas_ops.set_access_params = canvas_set_access_params;
     cairo_canvas_ops.destroy = canvas_destroy;
 
+    cairo_canvas_ops.fill_solid_spans = fill_solid_spans;
+    cairo_canvas_ops.fill_solid_rects = fill_solid_rects;
+    cairo_canvas_ops.fill_solid_rects_rop = fill_solid_rects_rop;
+    cairo_canvas_ops.fill_tiled_rects = fill_tiled_rects;
+    cairo_canvas_ops.fill_tiled_rects_rop = fill_tiled_rects_rop;
+    cairo_canvas_ops.blit_image = blit_image;
+    cairo_canvas_ops.blit_image_rop = blit_image_rop;
+    cairo_canvas_ops.scale_image = scale_image;
+    cairo_canvas_ops.scale_image_rop = scale_image_rop;
+    cairo_canvas_ops.blend_image = blend_image;
+    cairo_canvas_ops.blend_scale_image = blend_scale_image;
+    cairo_canvas_ops.colorkey_image = colorkey_image;
+    cairo_canvas_ops.colorkey_scale_image = colorkey_scale_image;
+    cairo_canvas_ops.copy_region = copy_region;
     rop3_init();
 }
-
diff --git a/common/canvas_base.c b/common/canvas_base.c
index 4bf2be7..231b5ed 100644
--- a/common/canvas_base.c
+++ b/common/canvas_base.c
@@ -231,6 +231,176 @@ typedef struct ATTR_PACKED DataChunk {
 
 #endif
 
+typedef enum {
+    ROP_INPUT_SRC,
+    ROP_INPUT_BRUSH,
+    ROP_INPUT_DEST
+} ROPInput;
+
+static SpiceROP ropd_descriptor_to_rop(int desc,
+                                       ROPInput src_input,
+                                       ROPInput dest_input)
+{
+    int old;
+    int invert_masks[] = {
+        SPICE_ROPD_INVERS_SRC,
+        SPICE_ROPD_INVERS_BRUSH,
+        SPICE_ROPD_INVERS_DEST
+    };
+
+    old = desc;
+
+    desc &= ~(SPICE_ROPD_INVERS_SRC | SPICE_ROPD_INVERS_DEST);
+    if (old & invert_masks[src_input]) {
+        desc |= SPICE_ROPD_INVERS_SRC;
+    }
+
+    if (old & invert_masks[dest_input]) {
+        desc |= SPICE_ROPD_INVERS_DEST;
+    }
+
+    if (desc & SPICE_ROPD_OP_PUT) {
+        if (desc & SPICE_ROPD_INVERS_SRC) {
+            if (desc & SPICE_ROPD_INVERS_RES) {
+                return SPICE_ROP_COPY;
+            }
+            return SPICE_ROP_COPY_INVERTED;
+        } else {
+            if (desc & SPICE_ROPD_INVERS_RES) {
+                return SPICE_ROP_COPY_INVERTED;
+            }
+            return SPICE_ROP_COPY;
+        }
+    } else if (desc & SPICE_ROPD_OP_OR) {
+
+        if (desc & SPICE_ROPD_INVERS_RES) {
+            if (desc & SPICE_ROPD_INVERS_SRC) {
+                if (desc & SPICE_ROPD_INVERS_DEST) {
+                    /* !(!src or !dest) == src and dest*/
+                    return SPICE_ROP_AND;
+                } else {
+                    /* ! (!src or dest) = src and !dest*/
+                    return SPICE_ROP_AND_REVERSE;
+                }
+            } else {
+                if (desc & SPICE_ROPD_INVERS_DEST) {
+                    /* !(src or !dest) == !src and dest */
+                    return SPICE_ROP_AND_INVERTED;
+                } else {
+                    /* !(src or dest) */
+                    return SPICE_ROP_NOR;
+                }
+            }
+        } else {
+            if (desc & SPICE_ROPD_INVERS_SRC) {
+                if (desc & SPICE_ROPD_INVERS_DEST) {
+                    /* !src or !dest == !(src and dest)*/
+                    return SPICE_ROP_NAND;
+                } else {
+                    /* !src or dest */
+                    return SPICE_ROP_OR_INVERTED;
+                }
+            } else {
+                if (desc & SPICE_ROPD_INVERS_DEST) {
+                    /* src or !dest */
+                    return SPICE_ROP_OR_REVERSE;
+                } else {
+                    /* src or dest */
+                    return SPICE_ROP_OR;
+                }
+            }
+        }
+
+    } else if (desc & SPICE_ROPD_OP_AND) {
+
+        if (desc & SPICE_ROPD_INVERS_RES) {
+            if (desc & SPICE_ROPD_INVERS_SRC) {
+                if (desc & SPICE_ROPD_INVERS_DEST) {
+                    /* !(!src and !dest) == src or dest*/
+                    return SPICE_ROP_OR;
+                } else {
+                    /* ! (!src and dest) = src or !dest*/
+                    return SPICE_ROP_OR_REVERSE;
+                }
+            } else {
+                if (desc & SPICE_ROPD_INVERS_DEST) {
+                    /* !(src and !dest) == !src or dest */
+                    return SPICE_ROP_OR_INVERTED;
+                } else {
+                    /* !(src and dest) */
+                    return SPICE_ROP_NAND;
+                }
+            }
+        } else {
+            if (desc & SPICE_ROPD_INVERS_SRC) {
+                if (desc & SPICE_ROPD_INVERS_DEST) {
+                    /* !src and !dest == !(src or dest)*/
+                    return SPICE_ROP_NOR;
+                } else {
+                    /* !src and dest */
+                    return SPICE_ROP_AND_INVERTED;
+                }
+            } else {
+                if (desc & SPICE_ROPD_INVERS_DEST) {
+                    /* src and !dest */
+                    return SPICE_ROP_AND_REVERSE;
+                } else {
+                    /* src and dest */
+                    return SPICE_ROP_AND;
+                }
+            }
+        }
+
+    } else if (desc & SPICE_ROPD_OP_XOR) {
+
+        if (desc & SPICE_ROPD_INVERS_RES) {
+            if (desc & SPICE_ROPD_INVERS_SRC) {
+                if (desc & SPICE_ROPD_INVERS_DEST) {
+                    /* !(!src xor !dest) == !src xor dest */
+                    return SPICE_ROP_EQUIV;
+                } else {
+                    /* ! (!src xor dest) = src xor dest*/
+                    return SPICE_ROP_XOR;
+                }
+            } else {
+                if (desc & SPICE_ROPD_INVERS_DEST) {
+                    /* !(src xor !dest) == src xor dest */
+                    return SPICE_ROP_XOR;
+                } else {
+                    /* !(src xor dest) */
+                    return SPICE_ROP_EQUIV;
+                }
+            }
+        } else {
+            if (desc & SPICE_ROPD_INVERS_SRC) {
+                if (desc & SPICE_ROPD_INVERS_DEST) {
+                    /* !src xor !dest == src xor dest */
+                    return SPICE_ROP_XOR;
+                } else {
+                    /* !src xor dest */
+                    return SPICE_ROP_EQUIV;
+                }
+            } else {
+                if (desc & SPICE_ROPD_INVERS_DEST) {
+                    /* src xor !dest */
+                    return SPICE_ROP_EQUIV;
+                } else {
+                    /* src xor dest */
+                    return SPICE_ROP_XOR;
+                }
+            }
+        }
+
+    } else if (desc & SPICE_ROPD_OP_BLACKNESS) {
+        return SPICE_ROP_CLEAR;
+    } else if (desc & SPICE_ROPD_OP_WHITENESS) {
+        return SPICE_ROP_SET;
+    } else if (desc & SPICE_ROPD_OP_INVERS) {
+        return SPICE_ROP_INVERT;
+    }
+    return SPICE_ROP_COPY;
+}
+
 static inline void canvas_localize_palette(CanvasBase *canvas, SpicePalette *palette)
 {
     if (canvas->color_shift == 5) {
@@ -874,7 +1044,7 @@ static pixman_image_t *canvas_get_image_internal(CanvasBase *canvas, SPICE_ADDRE
 
 #else
 
-static pixman_image_t *canvas_get_image_internal(CairoCanvas *canvas, SPICE_ADDRESS addr, int real_get)
+static pixman_image_t *canvas_get_image_internal(CanvasBase *canvas, SPICE_ADDRESS addr, int real_get)
 {
     SpiceImageDescriptor *descriptor = (SpiceImageDescriptor *)SPICE_GET_ADDRESS(addr);
 
@@ -908,12 +1078,10 @@ static pixman_image_t *canvas_get_image(CanvasBase *canvas, SPICE_ADDRESS addr)
     return canvas_get_image_internal(canvas, addr, TRUE);
 }
 
-#ifdef CANVAS_USE_PIXMAN
 static void canvas_touch_image(CanvasBase *canvas, SPICE_ADDRESS addr)
 {
     canvas_get_image_internal(canvas, addr, FALSE);
 }
-#endif
 
 static inline uint8_t revers_bits(uint8_t byte)
 {
@@ -1582,6 +1750,646 @@ void *spice_canvas_get_usr_data(SpiceCanvas *spice_canvas)
 }
 #endif
 
+
+static void canvas_clip_pixman(CanvasBase *canvas,
+                               pixman_region32_t *dest_region,
+                               SpiceClip *clip)
+{
+    pixman_region32_intersect(dest_region, dest_region, &canvas->canvas_region);
+
+    switch (clip->type) {
+    case SPICE_CLIP_TYPE_NONE:
+        break;
+    case SPICE_CLIP_TYPE_RECTS: {
+        uint32_t *n = (uint32_t *)SPICE_GET_ADDRESS(clip->data);
+        access_test(canvas, n, sizeof(uint32_t));
+
+        SpiceRect *now = (SpiceRect *)(n + 1);
+        access_test(canvas, now, (unsigned long)(now + *n) - (unsigned long)now);
+
+        pixman_region32_t clip;
+
+        if (spice_pixman_region32_init_rects(&clip, now, *n)) {
+            pixman_region32_intersect(dest_region, dest_region, &clip);
+            pixman_region32_fini(&clip);
+        }
+
+        break;
+    }
+    case SPICE_CLIP_TYPE_PATH:
+        CANVAS_ERROR("clip paths not supported anymore");
+        break;
+    default:
+        CANVAS_ERROR("invalid clip type");
+    }
+}
+
+static void canvas_mask_pixman(CanvasBase *canvas,
+                               pixman_region32_t *dest_region,
+                               SpiceQMask *mask, int x, int y)
+{
+    pixman_image_t *image, *subimage;
+    int needs_invert;
+    pixman_region32_t mask_region;
+    uint32_t *mask_data;
+    int mask_x, mask_y;
+    int mask_width, mask_height, mask_stride;
+    pixman_box32_t extents;
+
+    needs_invert = FALSE;
+    image = canvas_get_mask(canvas,
+                            mask,
+                            &needs_invert);
+
+    if (image == NULL) {
+        return; /* no mask */
+    }
+
+    mask_data = pixman_image_get_data(image);
+    mask_width = pixman_image_get_width(image);
+    mask_height = pixman_image_get_height(image);
+    mask_stride = pixman_image_get_stride(image);
+
+    mask_x = mask->pos.x;
+    mask_y = mask->pos.y;
+
+    /* We need to subset the area of the mask that we turn into a region,
+       because a cached mask may be much larger than what is used for
+       the clip operation. */
+    extents = *pixman_region32_extents(dest_region);
+
+    /* convert from destination pixels to mask pixels */
+    extents.x1 -= x - mask_x;
+    extents.y1 -= y - mask_y;
+    extents.x2 -= x - mask_x;
+    extents.y2 -= y - mask_y;
+
+    /* clip to mask size */
+    if (extents.x1 < 0) {
+        extents.x1 = 0;
+    }
+    if (extents.x2 >= mask_width) {
+        extents.x2 = mask_width;
+    }
+    if (extents.x2 < extents.x1) {
+        extents.x2 = extents.x1;
+    }
+    if (extents.y1 < 0) {
+        extents.y1 = 0;
+    }
+    if (extents.y2 >= mask_height) {
+        extents.y2 = mask_height;
+    }
+    if (extents.y2 < extents.y1) {
+        extents.y2 = extents.y1;
+    }
+
+    /* round down X to even 32 pixels (i.e. uint32_t) */
+    extents.x1 = extents.x1 & ~(0x1f);
+
+    mask_data = (uint32_t *)((uint8_t *)mask_data + mask_stride * extents.y1 + extents.x1 / 32);
+    mask_x -= extents.x1;
+    mask_y -= extents.y1;
+    mask_width = extents.x2 - extents.x1;
+    mask_height = extents.y2 - extents.y1;
+
+    subimage = pixman_image_create_bits(PIXMAN_a1, mask_width, mask_height,
+                                        mask_data, mask_stride);
+    pixman_region32_init_from_image(&mask_region,
+                                    subimage);
+    pixman_image_unref(subimage);
+
+    if (needs_invert) {
+        pixman_box32_t rect;
+
+        rect.x1 = rect.y1 = 0;
+        rect.x2 = mask_width;
+        rect.y2 = mask_height;
+
+        pixman_region32_inverse(&mask_region, &mask_region, &rect);
+    }
+
+    pixman_region32_translate(&mask_region,
+                              -mask_x + x, -mask_y + y);
+
+    pixman_region32_intersect(dest_region, dest_region, &mask_region);
+    pixman_region32_fini(&mask_region);
+
+    pixman_image_unref(image);
+}
+
+static void draw_brush(SpiceCanvas *canvas,
+                       pixman_region32_t *region,
+                       SpiceBrush *brush,
+                       SpiceROP rop)
+{
+    CanvasBase *canvas_base = (CanvasBase *)canvas;
+    uint32_t color;
+    SpicePattern *pattern;
+    pixman_image_t *tile;
+    int offset_x, offset_y;
+    pixman_box32_t *rects;
+    int n_rects;
+
+    rects = pixman_region32_rectangles(region, &n_rects);
+
+   switch (brush->type) {
+    case SPICE_BRUSH_TYPE_SOLID:
+        color = brush->u.color;
+        if (rop == SPICE_ROP_COPY) {
+            canvas->ops->fill_solid_rects(canvas, rects, n_rects, color);
+        } else {
+            canvas->ops->fill_solid_rects_rop(canvas, rects, n_rects, color, rop);
+        }
+        break;
+    case SPICE_BRUSH_TYPE_PATTERN:
+        pattern = &brush->u.pattern;
+        tile = canvas_get_image(canvas_base, pattern->pat);
+        offset_x = pattern->pos.x;
+        offset_y = pattern->pos.y;
+
+        if (rop == SPICE_ROP_COPY) {
+            canvas->ops->fill_tiled_rects(canvas, rects, n_rects, tile, offset_x, offset_y);
+        } else {
+            canvas->ops->fill_tiled_rects_rop(canvas, rects, n_rects,
+                                              tile, offset_x, offset_y, rop);
+        }
+        pixman_image_unref(tile);
+        break;
+    case SPICE_BRUSH_TYPE_NONE:
+        /* Still need to do *something* here, because rop could be e.g invert dest */
+        canvas->ops->fill_solid_rects_rop(canvas, rects, n_rects, 0, rop);
+        break;
+    default:
+        CANVAS_ERROR("invalid brush type");
+    }
+}
+
+/* If we're exiting early we may still have to load an image in case
+   it has to be cached or something */
+static void touch_brush(CanvasBase *canvas, SpiceBrush *brush)
+{
+    SpicePattern *pattern;
+
+    if (brush->type == SPICE_BRUSH_TYPE_PATTERN) {
+        pattern = &brush->u.pattern;
+        canvas_touch_image(canvas, pattern->pat);
+    }
+}
+
+static void canvas_draw_fill(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceFill *fill)
+{
+    CanvasBase *canvas = (CanvasBase *)spice_canvas;
+    pixman_region32_t dest_region;
+    SpiceROP rop;
+
+    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);
+    canvas_mask_pixman(canvas, &dest_region, &fill->mask,
+                       bbox->left, bbox->top);
+
+    rop = ropd_descriptor_to_rop(fill->rop_decriptor,
+                                 ROP_INPUT_BRUSH,
+                                 ROP_INPUT_DEST);
+
+    if (rop == SPICE_ROP_NOOP || pixman_region32_n_rects(&dest_region) == 0) {
+        touch_brush(canvas, &fill->brush);
+        pixman_region32_fini(&dest_region);
+        return;
+    }
+
+    draw_brush(spice_canvas, &dest_region, &fill->brush, rop);
+
+    pixman_region32_fini(&dest_region);
+}
+
+static void canvas_draw_copy(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceCopy *copy)
+{
+    CanvasBase *canvas = (CanvasBase *)spice_canvas;
+    pixman_region32_t dest_region;
+    pixman_image_t *src_image;
+    SpiceROP rop;
+
+    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);
+    canvas_mask_pixman(canvas, &dest_region, &copy->mask,
+                       bbox->left, bbox->top);
+
+    rop = ropd_descriptor_to_rop(copy->rop_decriptor,
+                                 ROP_INPUT_SRC,
+                                 ROP_INPUT_DEST);
+
+    if (rop == SPICE_ROP_NOOP || pixman_region32_n_rects(&dest_region) == 0) {
+        canvas_touch_image(canvas, copy->src_bitmap);
+        pixman_region32_fini(&dest_region);
+        return;
+    }
+
+    src_image = canvas_get_image(canvas, copy->src_bitmap);
+
+    if (rect_is_same_size(bbox, &copy->src_area)) {
+        if (rop == SPICE_ROP_COPY) {
+            spice_canvas->ops->blit_image(spice_canvas, &dest_region,
+                                          src_image,
+                                          bbox->left - copy->src_area.left,
+                                          bbox->top - copy->src_area.top);
+        } else {
+            spice_canvas->ops->blit_image_rop(spice_canvas, &dest_region,
+                                              src_image,
+                                              bbox->left - copy->src_area.left,
+                                              bbox->top - copy->src_area.top,
+                                              rop);
+        }
+    } else {
+        if (rop == SPICE_ROP_COPY) {
+            spice_canvas->ops->scale_image(spice_canvas, &dest_region,
+                                           src_image,
+                                           copy->src_area.left,
+                                           copy->src_area.top,
+                                           copy->src_area.right - copy->src_area.left,
+                                           copy->src_area.bottom - copy->src_area.top,
+                                           bbox->left,
+                                           bbox->top,
+                                           bbox->right - bbox->left,
+                                           bbox->bottom - bbox->top,
+                                           copy->scale_mode);
+        } else {
+            spice_canvas->ops->scale_image_rop(spice_canvas, &dest_region,
+                                               src_image,
+                                               copy->src_area.left,
+                                               copy->src_area.top,
+                                               copy->src_area.right - copy->src_area.left,
+                                               copy->src_area.bottom - copy->src_area.top,
+                                               bbox->left,
+                                               bbox->top,
+                                               bbox->right - bbox->left,
+                                               bbox->bottom - bbox->top,
+                                               copy->scale_mode,
+                                               rop);
+        }
+    }
+
+    pixman_image_unref(src_image);
+    pixman_region32_fini(&dest_region);
+}
+
+static void canvas_draw_transparent(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceTransparent* transparent)
+{
+    CanvasBase *canvas = (CanvasBase *)spice_canvas;
+    pixman_image_t *src_image;
+    pixman_region32_t dest_region;
+
+    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 (pixman_region32_n_rects (&dest_region) == 0) {
+        canvas_touch_image(canvas, transparent->src_bitmap);
+        pixman_region32_fini(&dest_region);
+        return;
+    }
+
+    src_image = canvas_get_image(canvas, transparent->src_bitmap);
+
+    if (rect_is_same_size(bbox, &transparent->src_area)) {
+        spice_canvas->ops->colorkey_image(spice_canvas, &dest_region,
+                                          src_image,
+                                          bbox->left - transparent->src_area.left,
+                                          bbox->top - transparent->src_area.top,
+                                          transparent->true_color);
+    } else {
+        spice_canvas->ops->colorkey_scale_image(spice_canvas, &dest_region,
+                                                src_image,
+                                                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);
+    }
+
+    pixman_image_unref(src_image);
+    pixman_region32_fini(&dest_region);
+}
+
+static void canvas_draw_alpha_blend(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceAlphaBlnd* alpha_blend)
+{
+    CanvasBase *canvas = (CanvasBase *)spice_canvas;
+    pixman_region32_t dest_region;
+    pixman_image_t *src_image;
+
+    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, alpha_blend->src_bitmap);
+        pixman_region32_fini(&dest_region);
+        return;
+    }
+
+    src_image = canvas_get_image(canvas, alpha_blend->src_bitmap);
+
+    if (rect_is_same_size(bbox, &alpha_blend->src_area)) {
+        spice_canvas->ops->blend_image(spice_canvas, &dest_region,
+                                       src_image,
+                                       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 {
+        spice_canvas->ops->blend_scale_image(spice_canvas, &dest_region,
+                                             src_image,
+                                             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_image_unref(src_image);
+    pixman_region32_fini(&dest_region);
+}
+
+static void canvas_draw_opaque(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceOpaque *opaque)
+{
+    CanvasBase *canvas = (CanvasBase *)spice_canvas;
+    pixman_image_t *src_image;
+    pixman_region32_t dest_region;
+    SpiceROP rop;
+
+    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);
+    canvas_mask_pixman(canvas, &dest_region, &opaque->mask,
+                       bbox->left, bbox->top);
+
+    rop = ropd_descriptor_to_rop(opaque->rop_decriptor,
+                                 ROP_INPUT_BRUSH,
+                                 ROP_INPUT_SRC);
+
+    if (rop == SPICE_ROP_NOOP || pixman_region32_n_rects(&dest_region) == 0) {
+        canvas_touch_image(canvas, opaque->src_bitmap);
+        touch_brush(canvas, &opaque->brush);
+        pixman_region32_fini(&dest_region);
+        return;
+    }
+
+    src_image = canvas_get_image(canvas, opaque->src_bitmap);
+
+    if (rect_is_same_size(bbox, &opaque->src_area)) {
+        spice_canvas->ops->blit_image(spice_canvas, &dest_region,
+                                      src_image,
+                                      bbox->left - opaque->src_area.left,
+                                      bbox->top - opaque->src_area.top);
+    } else {
+        spice_canvas->ops->scale_image(spice_canvas, &dest_region,
+                                       src_image,
+                                       opaque->src_area.left,
+                                       opaque->src_area.top,
+                                       opaque->src_area.right - opaque->src_area.left,
+                                       opaque->src_area.bottom - opaque->src_area.top,
+                                       bbox->left,
+                                       bbox->top,
+                                       bbox->right - bbox->left,
+                                       bbox->bottom - bbox->top,
+                                       opaque->scale_mode);
+    }
+
+    draw_brush(spice_canvas, &dest_region, &opaque->brush, rop);
+
+    pixman_image_unref(src_image);
+    pixman_region32_fini(&dest_region);
+}
+
+static void canvas_draw_blend(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceBlend *blend)
+{
+    CanvasBase *canvas = (CanvasBase *)spice_canvas;
+    pixman_image_t *src_image;
+    pixman_region32_t dest_region;
+    SpiceROP rop;
+
+    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);
+    canvas_mask_pixman(canvas, &dest_region, &blend->mask,
+                       bbox->left, bbox->top);
+
+    rop = ropd_descriptor_to_rop(blend->rop_decriptor,
+                                 ROP_INPUT_SRC,
+                                 ROP_INPUT_DEST);
+
+    if (rop == SPICE_ROP_NOOP || pixman_region32_n_rects(&dest_region) == 0) {
+        canvas_touch_image(canvas, blend->src_bitmap);
+        pixman_region32_fini(&dest_region);
+        return;
+    }
+
+    src_image = canvas_get_image(canvas, blend->src_bitmap);
+
+    if (rect_is_same_size(bbox, &blend->src_area)) {
+        if (rop == SPICE_ROP_COPY)
+            spice_canvas->ops->blit_image(spice_canvas, &dest_region,
+                                          src_image,
+                                          bbox->left - blend->src_area.left,
+                                          bbox->top - blend->src_area.top);
+        else
+            spice_canvas->ops->blit_image_rop(spice_canvas, &dest_region,
+                                              src_image,
+                                              bbox->left - blend->src_area.left,
+                                              bbox->top - blend->src_area.top,
+                                              rop);
+    } else {
+        double sx, sy;
+
+        sx = (double)(blend->src_area.right - blend->src_area.left) / (bbox->right - bbox->left);
+        sy = (double)(blend->src_area.bottom - blend->src_area.top) / (bbox->bottom - bbox->top);
+
+        if (rop == SPICE_ROP_COPY) {
+            spice_canvas->ops->scale_image(spice_canvas, &dest_region,
+                                           src_image,
+                                           blend->src_area.left,
+                                           blend->src_area.top,
+                                           blend->src_area.right - blend->src_area.left,
+                                           blend->src_area.bottom - blend->src_area.top,
+                                           bbox->left,
+                                           bbox->top,
+                                           bbox->right - bbox->left,
+                                           bbox->bottom - bbox->top,
+                                           blend->scale_mode);
+        } else {
+            spice_canvas->ops->scale_image_rop(spice_canvas, &dest_region,
+                                               src_image,
+                                               blend->src_area.left,
+                                               blend->src_area.top,
+                                               blend->src_area.right - blend->src_area.left,
+                                               blend->src_area.bottom - blend->src_area.top,
+                                               bbox->left,
+                                               bbox->top,
+                                               bbox->right - bbox->left,
+                                               bbox->bottom - bbox->top,
+                                               blend->scale_mode, rop);
+        }
+    }
+
+    pixman_image_unref(src_image);
+    pixman_region32_fini(&dest_region);
+}
+
+static void canvas_draw_blackness(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceBlackness *blackness)
+{
+    CanvasBase *canvas = (CanvasBase *)spice_canvas;
+    pixman_region32_t dest_region;
+    pixman_box32_t *rects;
+    int n_rects;
+
+   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);
+    canvas_mask_pixman(canvas, &dest_region, &blackness->mask,
+                       bbox->left, bbox->top);
+
+    if (pixman_region32_n_rects(&dest_region) == 0) {
+        pixman_region32_fini (&dest_region);
+        return;
+    }
+
+    rects = pixman_region32_rectangles(&dest_region, &n_rects);
+
+    spice_canvas->ops->fill_solid_rects(spice_canvas, rects, n_rects, 0x000000);
+
+    pixman_region32_fini(&dest_region);
+}
+
+static void canvas_draw_whiteness(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceWhiteness *whiteness)
+{
+    CanvasBase *canvas = (CanvasBase *)spice_canvas;
+    pixman_region32_t dest_region;
+    pixman_box32_t *rects;
+    int n_rects;
+
+    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);
+    canvas_mask_pixman(canvas, &dest_region, &whiteness->mask,
+                       bbox->left, bbox->top);
+
+    if (pixman_region32_n_rects(&dest_region) == 0) {
+        pixman_region32_fini(&dest_region);
+        return;
+    }
+
+    rects = pixman_region32_rectangles(&dest_region, &n_rects);
+    spice_canvas->ops->fill_solid_rects(spice_canvas, rects, n_rects, 0xffffffff);
+
+    pixman_region32_fini(&dest_region);
+}
+
+static void canvas_draw_invers(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceInvers *invers)
+{
+    CanvasBase *canvas = (CanvasBase *)spice_canvas;
+    pixman_region32_t dest_region;
+    pixman_box32_t *rects;
+    int n_rects;
+
+    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);
+    canvas_mask_pixman(canvas, &dest_region, &invers->mask,
+                       bbox->left, bbox->top);
+
+    if (pixman_region32_n_rects(&dest_region) == 0) {
+        pixman_region32_fini(&dest_region);
+        return;
+    }
+
+    rects = pixman_region32_rectangles(&dest_region, &n_rects);
+    spice_canvas->ops->fill_solid_rects_rop(spice_canvas, rects, n_rects, 0x00000000,
+                                            SPICE_ROP_INVERT);
+
+    pixman_region32_fini(&dest_region);
+}
+
+static void canvas_copy_bits(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpicePoint *src_pos)
+{
+    CanvasBase *canvas = (CanvasBase *)spice_canvas;
+    pixman_region32_t dest_region;
+    int dx, dy;
+
+    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);
+
+    dx = bbox->left - src_pos->x;
+    dy = bbox->top - src_pos->y;
+
+    if (dx != 0 || dy != 0) {
+        pixman_region32_t src_region;
+
+        /* Clip so we don't read outside canvas */
+        pixman_region32_init_rect(&src_region,
+                                  dx, dy,
+                                  canvas->width,
+                                  canvas->height);
+        pixman_region32_intersect(&dest_region, &dest_region, &src_region);
+        pixman_region32_fini(&src_region);
+
+        spice_canvas->ops->copy_region(spice_canvas, &dest_region, dx, dy);
+    }
+
+    pixman_region32_fini(&dest_region);
+}
+
+
+
 static void canvas_base_group_start(SpiceCanvas *spice_canvas, QRegion *region)
 {
     CanvasBase *canvas = (CanvasBase *)spice_canvas;
@@ -1622,6 +2430,16 @@ inline static void canvas_base_init_ops(SpiceCanvasOps *ops)
         ops_cast[i] = (void *) unimplemented_op;
     }
 
+    ops->draw_fill = canvas_draw_fill;
+    ops->draw_copy = canvas_draw_copy;
+    ops->draw_opaque = canvas_draw_opaque;
+    ops->copy_bits = canvas_copy_bits;
+    ops->draw_blend = canvas_draw_blend;
+    ops->draw_blackness = canvas_draw_blackness;
+    ops->draw_whiteness = canvas_draw_whiteness;
+    ops->draw_invers = canvas_draw_invers;
+    ops->draw_transparent = canvas_draw_transparent;
+    ops->draw_alpha_blend = canvas_draw_alpha_blend;
     ops->group_start = canvas_base_group_start;
     ops->group_end = canvas_base_group_end;
 }
diff --git a/common/canvas_base.h b/common/canvas_base.h
index 48e921e..bed1e1b 100644
--- a/common/canvas_base.h
+++ b/common/canvas_base.h
@@ -106,6 +106,90 @@ typedef struct {
     void (*group_end)(SpiceCanvas *canvas);
     void (*set_access_params)(SpiceCanvas *canvas, unsigned long base, unsigned long max);
     void (*destroy)(SpiceCanvas *canvas);
+
+    /* Implementation vfuncs */
+    void (*fill_solid_spans)(SpiceCanvas *canvas,
+                             SpicePoint *points,
+                             int *widths,
+                             int n_spans,
+                             uint32_t color);
+    void (*fill_solid_rects)(SpiceCanvas *canvas,
+                             pixman_box32_t *rects,
+                             int n_rects,
+                             uint32_t color);
+    void (*fill_solid_rects_rop)(SpiceCanvas *canvas,
+                                 pixman_box32_t *rects,
+                                 int n_rects,
+                                 uint32_t color,
+                                 SpiceROP rop);
+    void (*fill_tiled_rects)(SpiceCanvas *canvas,
+                             pixman_box32_t *rects,
+                             int n_rects,
+                             pixman_image_t *tile,
+                             int offset_x, int offset_y);
+    void (*fill_tiled_rects_rop)(SpiceCanvas *canvas,
+                                 pixman_box32_t *rects,
+                                 int n_rects,
+                                 pixman_image_t *tile,
+                                 int offset_x, int offset_y,
+                                 SpiceROP rop);
+    void (*blit_image)(SpiceCanvas *canvas,
+                       pixman_region32_t *region,
+                       pixman_image_t *src_image,
+                       int offset_x, int offset_y);
+    void (*blit_image_rop)(SpiceCanvas *canvas,
+                           pixman_region32_t *region,
+                           pixman_image_t *src_image,
+                           int offset_x, int offset_y,
+                           SpiceROP rop);
+    void (*scale_image)(SpiceCanvas *canvas,
+                        pixman_region32_t *region,
+                        pixman_image_t *src_image,
+                        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);
+    void (*scale_image_rop)(SpiceCanvas *canvas,
+                            pixman_region32_t *region,
+                            pixman_image_t *src_image,
+                            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, SpiceROP rop);
+    void (*blend_image)(SpiceCanvas *canvas,
+                        pixman_region32_t *region,
+                        pixman_image_t *src_image,
+                        int src_x, int src_y,
+                        int dest_x, int dest_y,
+                        int width, int height,
+                        int overall_alpha);
+    void (*blend_scale_image)(SpiceCanvas *canvas,
+                              pixman_region32_t *region,
+                              pixman_image_t *src_image,
+                              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);
+    void (*colorkey_image)(SpiceCanvas *canvas,
+                           pixman_region32_t *region,
+                           pixman_image_t *src_image,
+                           int offset_x, int offset_y,
+                           uint32_t transparent_color);
+    void (*colorkey_scale_image)(SpiceCanvas *canvas,
+                                 pixman_region32_t *region,
+                                 pixman_image_t *src_image,
+                                 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);
+    void (*copy_region)(SpiceCanvas *canvas,
+                        pixman_region32_t *dest_region,
+                        int dx, int dy);
 } SpiceCanvasOps;
 
 void spice_canvas_set_usr_data(SpiceCanvas *canvas, void *data, spice_destroy_fn_t destroy_fn);
-- 
1.6.6



More information about the Spice-devel mailing list