[Spice-devel] [PATCH 08/30] Use pixman_image_t instead of cairo_surface_t as the generic pixman container

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


This allows us to use the simpler dependency of pixman outside of the
cairo backend, and it later lets us move the cairo backend to using
pixman only.
---
 client/canvas.h       |   30 +++---
 common/cairo_canvas.c |  151 +++++++++++++----------
 common/canvas_base.c  |  324 ++++++++++++++++++++++++------------------------
 common/canvas_base.h  |    8 +-
 common/canvas_utils.c |  151 +++++++++++------------
 common/canvas_utils.h |   30 +++---
 common/gdi_canvas.c   |  156 ++++++++++++------------
 common/gdi_canvas.h   |    2 +-
 common/gl_canvas.c    |  173 +++++++++++++-------------
 common/rop3.c         |   56 +++++-----
 common/rop3.h         |    8 +-
 server/red_worker.c   |   12 +-
 12 files changed, 556 insertions(+), 545 deletions(-)

diff --git a/client/canvas.h b/client/canvas.h
index ac9a1f0..0878d2d 100644
--- a/client/canvas.h
+++ b/client/canvas.h
@@ -40,14 +40,14 @@ struct QRegion;
 
 class PixmapCacheTreat {
 public:
-    static inline cairo_surface_t *get(cairo_surface_t *surf)
+    static inline pixman_image_t *get(pixman_image_t *surf)
     {
-        return cairo_surface_reference(surf);
+        return pixman_image_ref(surf);
     }
 
-    static inline void release(cairo_surface_t *surf)
+    static inline void release(pixman_image_t *surf)
     {
-        cairo_surface_destroy(surf);
+        pixman_image_ref(surf);
     }
 
     static const char* name() { return "pixmap";}
@@ -55,19 +55,19 @@ public:
 
 class SpiceImageCacheBase;
 
-typedef SharedCache<cairo_surface_t, PixmapCacheTreat, 1024, SpiceImageCacheBase> PixmapCache;
+typedef SharedCache<pixman_image_t, PixmapCacheTreat, 1024, SpiceImageCacheBase> PixmapCache;
 
 class SpiceImageCacheBase {
 public:
     SpiceImageCache base;
 
-    static void op_put(SpiceImageCache *c, uint64_t id, cairo_surface_t *surface)
+    static void op_put(SpiceImageCache *c, uint64_t id, pixman_image_t *surface)
     {
 	PixmapCache* cache = reinterpret_cast<PixmapCache*>(c);
 	cache->add(id, surface);
     }
 
-    static cairo_surface_t* op_get(SpiceImageCache *c, uint64_t id)
+    static pixman_image_t* op_get(SpiceImageCache *c, uint64_t id)
     {
 	PixmapCache* cache = reinterpret_cast<PixmapCache*>(c);
 	return cache->get(id);
@@ -185,20 +185,20 @@ public:
 class GlzDecodedSurface: public GlzDecodedImage {
 public:
     GlzDecodedSurface(uint64_t id, uint64_t win_head_id, uint8_t *data, int size,
-                      int bytes_per_pixel, cairo_surface_t *surface)
+                      int bytes_per_pixel, pixman_image_t *surface)
         : GlzDecodedImage(id, win_head_id, data, size, bytes_per_pixel)
         , _surface (surface)
     {
-        cairo_surface_reference(_surface);
+        pixman_image_ref(_surface);
     }
 
     virtual ~GlzDecodedSurface()
     {
-        cairo_surface_destroy(_surface);
+        pixman_image_unref(_surface);
     }
 
 private:
-    cairo_surface_t *_surface;
+    pixman_image_t *_surface;
 };
 
 class GlzDecodeSurfaceHandler: public GlzDecodeHandler {
@@ -208,10 +208,10 @@ public:
                                          int width, int height, int gross_pixels,
                                          int n_bytes_per_pixel, bool top_down)
     {
-        cairo_surface_t *surface = alloc_lz_image_surface((LzDecodeUsrData *)opaque_usr_info,
-                                                          type, width, height, gross_pixels,
-                                                          top_down);
-        uint8_t *data = cairo_image_surface_get_data(surface);
+        pixman_image_t *surface = alloc_lz_image_surface((LzDecodeUsrData *)opaque_usr_info,
+                                                         type, width, height, gross_pixels,
+                                                         top_down);
+        uint8_t *data = (uint8_t *)pixman_image_get_data(surface);
         if (!top_down) {
             data = data - (gross_pixels / height) * n_bytes_per_pixel * (height - 1);
         }
diff --git a/common/cairo_canvas.c b/common/cairo_canvas.c
index 51069dd..8f5e24b 100644
--- a/common/cairo_canvas.c
+++ b/common/cairo_canvas.c
@@ -297,7 +297,7 @@ static inline void canvas_invers_1bpp_be(uint8_t* dest, int dest_stride, uint8_t
     }
 }
 
-static cairo_surface_t *canvas_bitmap_to_invers_surface(CairoCanvas *canvas, SpiceBitmap* bitmap,
+static pixman_image_t *canvas_bitmap_to_invers_surface(CairoCanvas *canvas, SpiceBitmap* bitmap,
                                                         SpicePalette *palette)
 {
     uint8_t* src = (uint8_t *)SPICE_GET_ADDRESS(bitmap->data);
@@ -305,21 +305,20 @@ static cairo_surface_t *canvas_bitmap_to_invers_surface(CairoCanvas *canvas, Spi
     uint8_t* end;
     uint8_t* dest;
     int dest_stride;
-    cairo_surface_t* cairo_surface;
+    pixman_image_t* surface;
 
     src_stride = bitmap->stride;
     end = src + (bitmap->y * src_stride);
     access_test(&canvas->base, src, bitmap->y * src_stride);
 
-    cairo_surface = cairo_image_surface_create((bitmap->format == SPICE_BITMAP_FMT_RGBA) ?
-                                               CAIRO_FORMAT_ARGB32 : CAIRO_FORMAT_RGB24,
-                                               bitmap->x, bitmap->y);
-    if (cairo_surface_status(cairo_surface) != CAIRO_STATUS_SUCCESS) {
-        CANVAS_ERROR("create surface failed, %s",
-                     cairo_status_to_string(cairo_surface_status(cairo_surface)));
+    surface = pixman_image_create_bits((bitmap->format == SPICE_BITMAP_FMT_RGBA) ?
+                                       PIXMAN_a8r8g8b8 : PIXMAN_x8r8g8b8,
+                                       bitmap->x, bitmap->y, NULL, 0);
+    if (surface == NULL) {
+        CANVAS_ERROR("create surface failed");
     }
-    dest = cairo_image_surface_get_data(cairo_surface);
-    dest_stride = cairo_image_surface_get_stride(cairo_surface);
+    dest = (uint8_t *)pixman_image_get_data(surface);
+    dest_stride = pixman_image_get_stride(surface);
 
     if (!(bitmap->flags & SPICE_BITMAP_FLAGS_TOP_DOWN)) {
         ASSERT(bitmap->y > 0);
@@ -347,7 +346,7 @@ static cairo_surface_t *canvas_bitmap_to_invers_surface(CairoCanvas *canvas, Spi
         canvas_invers_1bpp_be(dest, dest_stride, src, src_stride, bitmap->x, end, palette);
         break;
     }
-    return cairo_surface;
+    return surface;
 }
 
 #if defined(CAIRO_CANVAS_CACHE) || defined(CAIRO_CANVAS_IMAGE_CACHE)
@@ -386,11 +385,11 @@ static void free_palette(SpiceBitmap *bitmap, SpicePalette *palette)
 
 #endif
 
-static cairo_surface_t *canvas_get_invers_image(CairoCanvas *canvas, SPICE_ADDRESS addr)
+static pixman_image_t *canvas_get_invers_image(CairoCanvas *canvas, SPICE_ADDRESS addr)
 {
     SpiceImageDescriptor *descriptor = (SpiceImageDescriptor *)SPICE_GET_ADDRESS(addr);
-    cairo_surface_t *surface;
-    cairo_surface_t *invers = NULL;
+    pixman_image_t *surface;
+    pixman_image_t *invers = NULL;
 
     access_test(&canvas->base, descriptor, sizeof(SpiceImageDescriptor));
 
@@ -469,13 +468,13 @@ static cairo_surface_t *canvas_get_invers_image(CairoCanvas *canvas, SPICE_ADDRE
     }
 
     invers = canvas_handle_inverse_user_data(surface);
-    cairo_surface_destroy(surface);
+    pixman_image_unref(surface);
     return invers;
 }
 
 #else
 
-static cairo_surface_t *canvas_get_invers(CairoCanvas *canvas, SpiceBitmap *bitmap)
+static pixman_image_t *canvas_get_invers(CairoCanvas *canvas, SpiceBitmap *bitmap)
 {
     SpicePalette *palette;
 
@@ -486,7 +485,7 @@ static cairo_surface_t *canvas_get_invers(CairoCanvas *canvas, SpiceBitmap *bitm
     if (canvas->color_shift == 5) {
         int size = sizeof(SpicePalette) + (palette->num_ents << 2);
         SpicePalette *local_palette = malloc(size);
-        cairo_surface_t* surface;
+        pixman_image_t* surface;
 
         memcpy(local_palette, palette, size);
         canvas_localize_palette(canvas, palette);
@@ -498,7 +497,7 @@ static cairo_surface_t *canvas_get_invers(CairoCanvas *canvas, SpiceBitmap *bitm
     }
 }
 
-static cairo_surface_t *canvas_get_invers_image(CairoCanvas *canvas, SPICE_ADDRESS addr)
+static pixman_image_t *canvas_get_invers_image(CairoCanvas *canvas, SPICE_ADDRESS addr)
 {
     SpiceImageDescriptor *descriptor = (SpiceImageDescriptor *)SPICE_GET_ADDRESS(addr);
 
@@ -522,28 +521,28 @@ static cairo_surface_t *canvas_get_invers_image(CairoCanvas *canvas, SPICE_ADDRE
 
 #endif
 
-static cairo_surface_t* canvas_surface_from_self(CairoCanvas *canvas, SpicePoint *pos,
-                                                 int32_t width, int32_t heigth)
+static pixman_image_t* canvas_surface_from_self(CairoCanvas *canvas, SpicePoint *pos,
+                                                int32_t width, int32_t heigth)
 {
-    cairo_surface_t *surface;
-    cairo_surface_t *src_surface;
+    pixman_image_t *surface;
+    pixman_image_t *src_surface;
     uint8_t *dest;
     int dest_stride;
     uint8_t *src;
     int src_stride;
     int i;
 
-    surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24, width, heigth);
-    if (cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS) {
-        CANVAS_ERROR("create surface failed, %s",
-                     cairo_status_to_string(cairo_surface_status(surface)));
+    surface = pixman_image_create_bits(PIXMAN_x8r8g8b8, width, heigth, NULL, 0);
+    if (surface == NULL) {
+        CANVAS_ERROR("create surface failed");
     }
-    dest = cairo_image_surface_get_data(surface);
-    dest_stride = cairo_image_surface_get_stride(surface);
 
-    src_surface = cairo_get_target(canvas->cairo);
-    src = cairo_image_surface_get_data(src_surface);
-    src_stride = cairo_image_surface_get_stride(src_surface);
+    dest = (uint8_t *)pixman_image_get_data(surface);
+    dest_stride = pixman_image_get_stride(surface);
+
+    src_surface = canvas->image;
+    src = (uint8_t *)pixman_image_get_data(src_surface);
+    src_stride = pixman_image_get_stride(src_surface);
     src += pos->y * src_stride + (pos->x << 2);
     for (i = 0; i < heigth; i++, dest += dest_stride, src += src_stride) {
         memcpy(dest, src, width << 2);
@@ -566,7 +565,8 @@ static cairo_pattern_t *canvas_get_brush(CairoCanvas *canvas, SpiceBrush *brush,
         return cairo_pattern_create_rgb(r, g, b);
     }
     case SPICE_BRUSH_TYPE_PATTERN: {
-        cairo_surface_t* surface;
+        pixman_image_t* surface;
+        cairo_surface_t* cairo_surface;
         cairo_pattern_t *pattern;
         cairo_matrix_t matrix;
 
@@ -575,13 +575,15 @@ static cairo_pattern_t *canvas_get_brush(CairoCanvas *canvas, SpiceBrush *brush,
         } else {
             surface = canvas_get_image(&canvas->base, brush->u.pattern.pat);
         }
-        pattern = cairo_pattern_create_for_surface(surface);
+        cairo_surface = surface_from_pixman_image (surface);
+        pixman_image_unref (surface);
+        pattern = cairo_pattern_create_for_surface(cairo_surface);
         if (cairo_pattern_status(pattern) != CAIRO_STATUS_SUCCESS) {
-            cairo_surface_destroy(surface);
+            cairo_surface_destroy(cairo_surface);
             CANVAS_ERROR("create pattern failed, %s",
                          cairo_status_to_string(cairo_pattern_status(pattern)));
         }
-        cairo_surface_destroy(surface);
+        cairo_surface_destroy(cairo_surface);
         cairo_matrix_init_translate(&matrix, -brush->u.pattern.pos.x, -brush->u.pattern.pos.y);
         cairo_pattern_set_matrix(pattern, &matrix);
         cairo_pattern_set_extend(pattern, CAIRO_EXTEND_REPEAT);
@@ -666,20 +668,23 @@ static inline void canvas_draw(CairoCanvas *canvas, SpiceBrush *brush, uint16_t
 
 static cairo_pattern_t *canvas_get_mask_pattern(CairoCanvas *canvas, SpiceQMask *mask, int x, int y)
 {
-    cairo_surface_t *surface;
+    pixman_image_t *surface;
+    cairo_surface_t *cairo_surface;
     cairo_pattern_t *pattern;
     cairo_matrix_t matrix;
 
     if (!(surface = canvas_get_mask(&canvas->base, mask))) {
         return NULL;
     }
-    pattern = cairo_pattern_create_for_surface(surface);
+    cairo_surface = surface_from_pixman_image (surface);
+    pixman_image_unref (surface);
+    pattern = cairo_pattern_create_for_surface(cairo_surface);
     if (cairo_pattern_status(pattern) != CAIRO_STATUS_SUCCESS) {
-        cairo_surface_destroy(surface);
+        cairo_surface_destroy(cairo_surface);
         CANVAS_ERROR("create pattern failed, %s",
                      cairo_status_to_string(cairo_pattern_status(pattern)));
     }
-    cairo_surface_destroy(surface);
+    cairo_surface_destroy(cairo_surface);
 
     cairo_matrix_init_translate(&matrix, mask->pos.x - x, mask->pos.y - y);
     cairo_pattern_set_matrix(pattern, &matrix);
@@ -724,7 +729,8 @@ static cairo_pattern_t *canvas_src_image_to_pat(CairoCanvas *canvas, SPICE_ADDRE
                                                 int scale_mode)
 {
     cairo_pattern_t *pattern;
-    cairo_surface_t *surface;
+    pixman_image_t *surface;
+    cairo_surface_t *cairo_surface;
     cairo_matrix_t matrix;
 
     ASSERT(src_bitmap);
@@ -735,8 +741,10 @@ static cairo_pattern_t *canvas_src_image_to_pat(CairoCanvas *canvas, SPICE_ADDRE
         surface = canvas_get_image(&canvas->base, src_bitmap);
     }
 
-    pattern = cairo_pattern_create_for_surface(surface);
-    cairo_surface_destroy(surface);
+    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)));
@@ -1124,8 +1132,9 @@ void canvas_draw_rop3(CairoCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, Spi
 {
     cairo_t *cairo = canvas->cairo;
     cairo_pattern_t *mask;
+    pixman_image_t *dd;
     cairo_surface_t *d;
-    cairo_surface_t *s;
+    pixman_image_t *s;
     SpicePoint pos;
     int width;
     int heigth;
@@ -1142,13 +1151,13 @@ void canvas_draw_rop3(CairoCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, Spi
     cairo_user_to_device(cairo, &x_pos, &y_pos);
     pos.x = (int32_t)x_pos;
     pos.y = (int32_t)y_pos;
-    d = canvas_surface_from_self(canvas, &pos, width, heigth);
+    dd = canvas_surface_from_self(canvas, &pos, width, heigth);
     s = canvas_get_image(&canvas->base, rop3->src_bitmap);
 
     if (!rect_is_same_size(bbox, &rop3->src_area)) {
-        cairo_surface_t *scaled_s = canvas_scale_surface(s, &rop3->src_area, width, heigth,
+        pixman_image_t *scaled_s = canvas_scale_surface(s, &rop3->src_area, width, heigth,
                                                          rop3->scale_mode);
-        cairo_surface_destroy(s);
+        pixman_image_unref(s);
         s = scaled_s;
         src_pos.x = 0;
         src_pos.y = 0;
@@ -1156,26 +1165,28 @@ void canvas_draw_rop3(CairoCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, Spi
         src_pos.x = rop3->src_area.left;
         src_pos.y = rop3->src_area.top;
     }
-    if (cairo_image_surface_get_width(s) - src_pos.x < width ||
-        cairo_image_surface_get_height(s) - src_pos.y < heigth) {
+    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) {
-        cairo_surface_t *p = canvas_get_image(&canvas->base, rop3->brush.u.pattern.pat);
+        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) % cairo_image_surface_get_width(p);
-        pat_pos.y = (bbox->top - rop3->brush.u.pattern.pos.y) % cairo_image_surface_get_height(p);
-        do_rop3_with_pattern(rop3->rop3, d, s, &src_pos, p, &pat_pos);
-        cairo_surface_destroy(p);
+        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, dd, 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);
+        do_rop3_with_color(rop3->rop3, dd, s, &src_pos, color);
     }
-    cairo_surface_destroy(s);
+    pixman_image_unref(s);
+    d = surface_from_pixman_image (dd);
     cairo_set_source_surface(cairo, d, bbox->left, bbox->top);
     cairo_surface_destroy(d);
+    pixman_image_unref (dd);
     if ((mask = canvas_get_mask_pattern(canvas, &rop3->mask, bbox->left, bbox->top))) {
         cairo_rectangle(cairo,
                         bbox->left,
@@ -1360,7 +1371,8 @@ static inline void __canvas_copy_region_bits(uint8_t *data, int stride, SpiceRec
 void canvas_copy_bits(CairoCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, SpicePoint *src_pos)
 {
     cairo_t *cairo = canvas->cairo;
-    cairo_surface_t *surface;
+    cairo_surface_t *cairo_surface;
+    pixman_image_t *surface;
     int32_t width;
     int32_t heigth;
 
@@ -1368,22 +1380,20 @@ void canvas_copy_bits(CairoCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, Spi
 #ifdef FAST_COPY_BITS
     switch (clip->type) {
     case SPICE_CLIP_TYPE_NONE: {
-        surface = cairo_get_target(cairo);
-        __canvas_copy_rect_bits(cairo_image_surface_get_data(surface),
-                                cairo_image_surface_get_stride(surface),
+        __canvas_copy_rect_bits((uint8_t *)pixman_image_get_data(canvas->image),
+                                pixman_image_get_stride(canvas->image),
                                 bbox, src_pos);
         break;
     }
     case SPICE_CLIP_TYPE_RECTS: {
-        surface = cairo_get_target(cairo);
         uint32_t *n = (uint32_t *)SPICE_GET_ADDRESS(clip->data);
         access_test(&canvas->base, n, sizeof(uint32_t));
 
         SpiceRect *now = (SpiceRect *)(n + 1);
         SpiceRect *end = now + *n;
         access_test(&canvas->base, now, (unsigned long)end - (unsigned long)now);
-        uint8_t *data = cairo_image_surface_get_data(surface);
-        int stride = cairo_image_surface_get_stride(surface);
+        uint8_t *data = (uint8_t *)pixman_image_get_data(canvas->image);
+        int stride = pixman_image_get_stride(canvas->image);
 
         //using QRegion in order to sort and remove intersections
         QRegion region;
@@ -1402,11 +1412,13 @@ void canvas_copy_bits(CairoCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, Spi
         width = bbox->right - bbox->left;
         heigth = bbox->bottom - bbox->top;
         surface = canvas_surface_from_self(canvas, src_pos, width, heigth);
-        cairo_set_source_surface(cairo, surface, bbox->left, bbox->top);
-        cairo_surface_destroy(surface);
+        cairo_surface = surface_from_pixman_image (surface);
+        cairo_set_source_surface(cairo, cairo_surface, bbox->left, bbox->top);
         cairo_rectangle(cairo, bbox->left, bbox->top, width, heigth);
         cairo_set_operator(cairo, CAIRO_OPERATOR_RASTER_COPY);
         cairo_fill(cairo);
+        cairo_surface_destroy(cairo_surface);
+        pixman_image_unref (surface);
 #ifdef FAST_COPY_BITS
     }
 
@@ -1417,16 +1429,18 @@ void canvas_copy_bits(CairoCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, Spi
 static void canvas_draw_raster_str(CairoCanvas *canvas, SpiceString *str, int bpp,
                                    SpiceBrush *brush, uint16_t rop_decriptor)
 {
-    cairo_surface_t *str_mask;
+    pixman_image_t *str_mask;
+    cairo_surface_t *cairo_str_mask;
     DrawMaskData draw_data;
     cairo_matrix_t matrix;
     SpicePoint pos;
 
     str_mask = canvas_get_str_mask(&canvas->base, str, bpp, &pos);
+    cairo_str_mask = surface_from_pixman_image (str_mask);
     draw_data.cairo = canvas->cairo;
-    draw_data.mask = cairo_pattern_create_for_surface(str_mask);
+    draw_data.mask = cairo_pattern_create_for_surface(cairo_str_mask);
     if (cairo_pattern_status(draw_data.mask) != CAIRO_STATUS_SUCCESS) {
-        cairo_surface_destroy(str_mask);
+        cairo_surface_destroy(cairo_str_mask);
         CANVAS_ERROR("create pattern failed, %s",
                      cairo_status_to_string(cairo_pattern_status(draw_data.mask)));
     }
@@ -1434,7 +1448,8 @@ static void canvas_draw_raster_str(CairoCanvas *canvas, SpiceString *str, int bp
     cairo_pattern_set_matrix(draw_data.mask, &matrix);
     canvas_draw(canvas, brush, rop_decriptor, __draw_mask, &draw_data);
     cairo_pattern_destroy(draw_data.mask);
-    cairo_surface_destroy(str_mask);
+    pixman_image_unref(str_mask);
+    cairo_surface_destroy(cairo_str_mask);
 }
 
 static void canvas_draw_vector_str(CairoCanvas *canvas, SpiceString *str, SpiceBrush *brush,
diff --git a/common/canvas_base.c b/common/canvas_base.c
index 0ddbaf4..2ea66a4 100644
--- a/common/canvas_base.c
+++ b/common/canvas_base.c
@@ -21,6 +21,7 @@
 #include <stdlib.h>
 #include <setjmp.h>
 #include <stdio.h>
+#include <math.h>
 
 #include <spice/draw.h>
 #include "quic.h"
@@ -76,6 +77,8 @@
 #define MAX(x, y) (((x) >= (y)) ? (x) : (y))
 #endif
 
+#define ROUND(_x) floor((_x) + 0.5)
+
 #ifdef WIN32
 typedef struct  __declspec (align(1)) LZImage {
 #else
@@ -88,12 +91,7 @@ typedef struct __attribute__ ((__packed__)) LZImage {
     };
 } LZImage;
 
-static const cairo_user_data_key_t invers_data_type = {0};
-
-#ifdef CAIRO_CANVAS_CACH_IS_SHARED
-/* should be defined and initialized once in application.cpp */
-extern mutex_t cairo_surface_user_data_mutex;
-#endif
+static const cairo_user_data_key_t pixman_data_type = {0};
 
 static inline double fix_to_double(SPICE_FIXED28_4 fixed)
 {
@@ -234,9 +232,13 @@ pixman_image_from_surface (cairo_surface_t *surface)
   pixman_image_t *image;
   cairo_format_t format;
 
-
   format = cairo_image_surface_get_format (surface);
 
+  image = (pixman_image_t *)cairo_surface_get_user_data(surface, &pixman_data_type);
+
+  if (image)
+      return pixman_image_ref (image);
+
   image = pixman_image_create_bits (pixman_format_from_cairo_format (format),
                                     cairo_image_surface_get_width (surface),
                                     cairo_image_surface_get_height (surface),
@@ -246,6 +248,44 @@ pixman_image_from_surface (cairo_surface_t *surface)
   return image;
 }
 
+static cairo_format_t
+cairo_format_from_depth (int depth)
+{
+    switch (depth) {
+    case 1:
+        return CAIRO_FORMAT_A1;
+    case 8:
+        return CAIRO_FORMAT_A8;
+    case 24:
+        return CAIRO_FORMAT_RGB24;
+    case 32:
+    default:
+        return CAIRO_FORMAT_ARGB32;
+    }
+}
+
+static cairo_surface_t *
+surface_from_pixman_image (pixman_image_t *image)
+{
+  cairo_surface_t *surface;
+  int depth;
+
+  depth = pixman_image_get_depth (image);
+
+  surface = cairo_image_surface_create_for_data ((uint8_t *)pixman_image_get_data (image),
+                                                 cairo_format_from_depth (depth),
+                                                 pixman_image_get_width (image),
+                                                 pixman_image_get_height (image),
+                                                 pixman_image_get_stride (image));
+
+
+  if (cairo_surface_set_user_data (surface, &pixman_data_type,
+                                   image, (cairo_destroy_func_t) pixman_image_unref) == CAIRO_STATUS_SUCCESS)
+      pixman_image_ref (image);
+
+  return surface;
+}
+
 #endif
 
 static inline void canvas_localize_palette(CanvasBase *canvas, SpicePalette *palette)
@@ -261,11 +301,11 @@ static inline void canvas_localize_palette(CanvasBase *canvas, SpicePalette *pal
 
 //#define DEBUG_DUMP_COMPRESS
 #ifdef DEBUG_DUMP_COMPRESS
-static void dump_surface(cairo_surface_t *surface, int cache);
+static void dump_surface(pixman_image_t *surface, int cache);
 #endif
-static cairo_surface_t *canvas_get_quic(CanvasBase *canvas, SpiceQUICImage *image, int invers)
+static pixman_image_t *canvas_get_quic(CanvasBase *canvas, SpiceQUICImage *image, int invers)
 {
-    cairo_surface_t *surface = NULL;
+    pixman_image_t *surface = NULL;
     QuicData *quic_data = &canvas->quic_data;
     QuicImageType type;
     uint8_t *dest;
@@ -279,7 +319,7 @@ static cairo_surface_t *canvas_get_quic(CanvasBase *canvas, SpiceQUICImage *imag
 #endif
 
     if (setjmp(quic_data->jmp_env)) {
-        cairo_surface_destroy(surface);
+        pixman_image_unref(surface);
         CANVAS_ERROR("quic error, %s", quic_data->message_buf);
     }
 
@@ -320,18 +360,18 @@ static cairo_surface_t *canvas_get_quic(CanvasBase *canvas, SpiceQUICImage *imag
 #ifdef WIN32
                              canvas->dc,
 #endif
-                             alpha ? CAIRO_FORMAT_ARGB32 : CAIRO_FORMAT_RGB24,
+                             alpha ? PIXMAN_a8r8g8b8 : PIXMAN_x8r8g8b8,
                              width, height, FALSE);
 
-    if (cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS) {
-        CANVAS_ERROR("create surface failed, %s",
-                     cairo_status_to_string(cairo_surface_status(surface)));
+    if (surface == NULL) {
+        CANVAS_ERROR("create surface failed");
     }
 
-    dest = cairo_image_surface_get_data(surface);
-    stride = cairo_image_surface_get_stride(surface);
+    dest = (uint8_t *)pixman_image_get_data(surface);
+    stride = pixman_image_get_stride(surface);
     if (quic_decode(quic_data->quic, alpha ? QUIC_IMAGE_TYPE_RGBA : QUIC_IMAGE_TYPE_RGB32,
                     dest, stride) == QUIC_ERROR) {
+        pixman_image_unref (surface);
         CANVAS_ERROR("quic decode failed");
     }
 
@@ -463,33 +503,32 @@ static inline void canvas_copy_1bpp_be(uint8_t* dest, int dest_stride, uint8_t*
     }
 }
 
-static cairo_surface_t *canvas_bitmap_to_surface(CanvasBase *canvas, SpiceBitmap* bitmap,
-                                                 SpicePalette *palette)
+static pixman_image_t *canvas_bitmap_to_surface(CanvasBase *canvas, SpiceBitmap* bitmap,
+                                                SpicePalette *palette)
 {
     uint8_t* src = (uint8_t *)SPICE_GET_ADDRESS(bitmap->data);
     int src_stride;
     uint8_t* end;
     uint8_t* dest;
     int dest_stride;
-    cairo_surface_t* cairo_surface;
+    pixman_image_t* image;
 
     src_stride = bitmap->stride;
     end = src + (bitmap->y * src_stride);
     access_test(canvas, src, bitmap->y * src_stride);
 
-    cairo_surface = surface_create(
+    image = surface_create(
 #ifdef WIN32
                                    canvas->dc,
 #endif
-                                   (bitmap->format == SPICE_BITMAP_FMT_RGBA) ? CAIRO_FORMAT_ARGB32 :
-                                                                         CAIRO_FORMAT_RGB24,
+                                   (bitmap->format == SPICE_BITMAP_FMT_RGBA) ? PIXMAN_a8r8g8b8 :
+                                                                         PIXMAN_x8r8g8b8,
                                    bitmap->x, bitmap->y, FALSE);
-    if (cairo_surface_status(cairo_surface) != CAIRO_STATUS_SUCCESS) {
-        CANVAS_ERROR("create surface failed, %s",
-                     cairo_status_to_string(cairo_surface_status(cairo_surface)));
+    if (image == NULL) {
+        CANVAS_ERROR("create surface failed");
     }
-    dest = cairo_image_surface_get_data(cairo_surface);
-    dest_stride = cairo_image_surface_get_stride(cairo_surface);
+    dest = (uint8_t *)pixman_image_get_data(image);
+    dest_stride = pixman_image_get_stride(image);
     if (!(bitmap->flags & SPICE_BITMAP_FLAGS_TOP_DOWN)) {
         ASSERT(bitmap->y > 0);
         dest += dest_stride * ((int)bitmap->y - 1);
@@ -517,7 +556,7 @@ static cairo_surface_t *canvas_bitmap_to_surface(CanvasBase *canvas, SpiceBitmap
         canvas_copy_1bpp_be(dest, dest_stride, src, src_stride, bitmap->x, end, palette);
         break;
     }
-    return cairo_surface;
+    return image;
 }
 
 #ifdef CAIRO_CANVAS_CACHE
@@ -544,7 +583,7 @@ static inline SpicePalette *canvas_get_palett(CanvasBase *canvas, SPICE_ADDRESS
     return palette;
 }
 
-static cairo_surface_t *canvas_get_lz(CanvasBase *canvas, LZImage *image, int invers)
+static pixman_image_t *canvas_get_lz(CanvasBase *canvas, LZImage *image, int invers)
 {
     LzData *lz_data = &canvas->lz_data;
     uint8_t *comp_buf = NULL;
@@ -612,7 +651,7 @@ static cairo_surface_t *canvas_get_lz(CanvasBase *canvas, LZImage *image, int in
     alloc_lz_image_surface(&lz_data->decode_data, alpha ? LZ_IMAGE_TYPE_RGBA : LZ_IMAGE_TYPE_RGB32,
                            width, height, n_comp_pixels, top_down);
 
-    src = cairo_image_surface_get_data(lz_data->decode_data.out_surface);
+    src = (uint8_t *)pixman_image_get_data(lz_data->decode_data.out_surface);
 
     stride = (n_comp_pixels / height) * 4;
     if (!top_down) {
@@ -644,7 +683,7 @@ static cairo_surface_t *canvas_get_lz(CanvasBase *canvas, LZImage *image, int in
 
 // don't handle plts since bitmaps with plt can be decoded globaly to RGB32 (because
 // same byte sequence can be transformed to different RGB pixels by different plts)
-static cairo_surface_t *canvas_get_glz(CanvasBase *canvas, LZImage *image)
+static pixman_image_t *canvas_get_glz(CanvasBase *canvas, LZImage *image)
 {
     ASSERT(image->descriptor.type == SPICE_IMAGE_TYPE_GLZ_RGB);
 #ifdef WIN32
@@ -696,9 +735,9 @@ static void dump_bitmap(SpiceBitmap *bitmap, SpicePalette *palette)
 
 #endif
 
-static cairo_surface_t *canvas_get_bits(CanvasBase *canvas, SpiceBitmap *bitmap)
+static pixman_image_t *canvas_get_bits(CanvasBase *canvas, SpiceBitmap *bitmap)
 {
-    cairo_surface_t* surface;
+    pixman_image_t* surface;
     SpicePalette *palette;
 
     palette = canvas_get_palett(canvas, bitmap->palette, bitmap->flags);
@@ -720,7 +759,7 @@ static cairo_surface_t *canvas_get_bits(CanvasBase *canvas, SpiceBitmap *bitmap)
 #else
 
 
-static cairo_surface_t *canvas_get_bits(CanvasBase *canvas, SpiceBitmap *bitmap)
+static pixman_image_t *canvas_get_bits(CanvasBase *canvas, SpiceBitmap *bitmap)
 {
     SpicePalette *palette;
 
@@ -731,7 +770,7 @@ static cairo_surface_t *canvas_get_bits(CanvasBase *canvas, SpiceBitmap *bitmap)
     if (canvas->color_shift == 5) {
         int size = sizeof(SpicePalette) + (palette->num_ents << 2);
         SpicePalette *local_palette = malloc(size);
-        cairo_surface_t* surface;
+        pixman_image_t* surface;
 
         memcpy(local_palette, palette, size);
         canvas_localize_palette(canvas, local_palette);
@@ -754,21 +793,21 @@ static cairo_surface_t *canvas_get_bits(CanvasBase *canvas, SpiceBitmap *bitmap)
 
 #if defined(DEBUG_DUMP_SURFACE) || defined(DEBUG_DUMP_COMPRESS)
 
-static void dump_surface(cairo_surface_t *surface, int cache)
+static void dump_surface(pixman_image_t *surface, int cache)
 {
     static uint32_t file_id = 0;
     int i, j;
     char file_str[200];
-    cairo_format_t format = cairo_image_surface_get_format(surface);
+    int depth = pixman_image_get_depth(surface);
 
-    if (format != CAIRO_FORMAT_RGB24 && format != CAIRO_FORMAT_ARGB32) {
+    if (depth != 24 && depth != 32) {
         return;
     }
 
-    uint8_t *data = cairo_image_surface_get_data(surface);
-    int width = cairo_image_surface_get_width(surface);
-    int height = cairo_image_surface_get_height(surface);
-    int stride = cairo_image_surface_get_stride(surface);
+    uint8_t *data = (uint8_t *)pixman_image_get_data(surface);
+    int width = pixman_image_get_width(surface);
+    int height = pixman_image_get_height(surface);
+    int stride = pixman_image_surface_get_stride(surface);
 
     uint32_t id = ++file_id;
 #ifdef WIN32
@@ -800,17 +839,12 @@ static void dump_surface(cairo_surface_t *surface, int cache)
 
 #if defined(CAIRO_CANVAS_CACHE) || defined(CAIRO_CANVAS_IMAGE_CACHE)
 
-static void __release_surface(void *inv_surf)
-{
-    cairo_surface_destroy((cairo_surface_t *)inv_surf);
-}
-
 //#define DEBUG_LZ
 
-static cairo_surface_t *canvas_get_image(CanvasBase *canvas, SPICE_ADDRESS addr)
+static pixman_image_t *canvas_get_image(CanvasBase *canvas, SPICE_ADDRESS addr)
 {
     SpiceImageDescriptor *descriptor = (SpiceImageDescriptor *)SPICE_GET_ADDRESS(addr);
-    cairo_surface_t *surface;
+    pixman_image_t *surface;
     access_test(canvas, descriptor, sizeof(SpiceImageDescriptor));
 #ifdef DEBUG_LZ
     LOG_DEBUG("canvas_get_image image type: " << (int)descriptor->type);
@@ -872,7 +906,7 @@ static cairo_surface_t *canvas_get_image(CanvasBase *canvas, SPICE_ADDRESS addr)
 
 #else
 
-static cairo_surface_t *canvas_get_image(CairoCanvas *canvas, SPICE_ADDRESS addr)
+static pixman_image_t *canvas_get_image(CairoCanvas *canvas, SPICE_ADDRESS addr)
 {
     SpiceImageDescriptor *descriptor = (SpiceImageDescriptor *)SPICE_GET_ADDRESS(addr);
 
@@ -909,9 +943,9 @@ static inline uint8_t revers_bits(uint8_t byte)
     return ret;
 }
 
-static cairo_surface_t *canvas_get_bitmap_mask(CanvasBase *canvas, SpiceBitmap* bitmap, int invers)
+static pixman_image_t *canvas_get_bitmap_mask(CanvasBase *canvas, SpiceBitmap* bitmap, int invers)
 {
-    cairo_surface_t *surface;
+    pixman_image_t *surface;
     uint8_t *src_line;
     uint8_t *end_line;
     uint8_t *dest_line;
@@ -923,10 +957,9 @@ static cairo_surface_t *canvas_get_bitmap_mask(CanvasBase *canvas, SpiceBitmap*
 #ifdef WIN32
             canvas->dc,
 #endif
-            CAIRO_FORMAT_A1, bitmap->x, bitmap->y, TRUE);
-    if (cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS) {
-        CANVAS_ERROR("create surface failed, %s",
-                     cairo_status_to_string(cairo_surface_status(surface)));
+            PIXMAN_a1, bitmap->x, bitmap->y, TRUE);
+    if (surface == NULL) {
+        CANVAS_ERROR("create surface failed");
     }
 
     src_line = (uint8_t *)SPICE_GET_ADDRESS(bitmap->data);
@@ -935,8 +968,8 @@ static cairo_surface_t *canvas_get_bitmap_mask(CanvasBase *canvas, SpiceBitmap*
     access_test(canvas, src_line, end_line - src_line);
     line_size = ALIGN(bitmap->x, 8) >> 3;
 
-    dest_stride = cairo_image_surface_get_stride(surface);
-    dest_line = cairo_image_surface_get_data(surface);
+    dest_stride = pixman_image_get_stride(surface);
+    dest_line = (uint8_t *)pixman_image_get_data(surface);
 #if defined(GL_CANVAS)
     if ((bitmap->flags & SPICE_BITMAP_FLAGS_TOP_DOWN)) {
 #else
@@ -979,7 +1012,8 @@ static cairo_surface_t *canvas_get_bitmap_mask(CanvasBase *canvas, SpiceBitmap*
             }
             break;
         default:
-            cairo_surface_destroy(surface);
+            pixman_image_unref(surface);
+            surface = NULL;
             CANVAS_ERROR("invalid bitmap format");
         }
     } else {
@@ -1009,26 +1043,27 @@ static cairo_surface_t *canvas_get_bitmap_mask(CanvasBase *canvas, SpiceBitmap*
             }
             break;
         default:
-            cairo_surface_destroy(surface);
+            pixman_image_unref(surface);
+            surface = NULL;
             CANVAS_ERROR("invalid bitmap format");
         }
     }
     return surface;
 }
 
-static inline cairo_surface_t *canvas_A1_invers(cairo_surface_t *src_surf)
+static inline pixman_image_t *canvas_A1_invers(pixman_image_t *src_surf)
 {
-    int width = cairo_image_surface_get_width(src_surf);
-    int height = cairo_image_surface_get_height(src_surf);
+    int width = pixman_image_get_width(src_surf);
+    int height = pixman_image_get_height(src_surf);
 
-    cairo_surface_t * invers = cairo_image_surface_create(CAIRO_FORMAT_A1, width, height);
-    if (cairo_surface_status(invers) == CAIRO_STATUS_SUCCESS) {
-        uint8_t *src_line = cairo_image_surface_get_data(src_surf);
-        int src_stride = cairo_image_surface_get_stride(src_surf);
+    pixman_image_t * invers = pixman_image_create_bits(PIXMAN_a1, width, height, NULL, 0);
+    if (invers != NULL) {
+        uint8_t *src_line = (uint8_t *)pixman_image_get_data(src_surf);
+        int src_stride = pixman_image_get_stride(src_surf);
         uint8_t *end_line = src_line + (height * src_stride);
         int line_size = ALIGN(width, 8) >> 3;
-        uint8_t *dest_line = cairo_image_surface_get_data(invers);
-        int dest_stride = cairo_image_surface_get_stride(invers);
+        uint8_t *dest_line = (uint8_t *)pixman_image_get_data(invers);
+        int dest_stride = pixman_image_get_stride(invers);
 
         for (; src_line != end_line; src_line += src_stride, dest_line += dest_stride) {
             uint8_t *dest = dest_line;
@@ -1042,29 +1077,28 @@ static inline cairo_surface_t *canvas_A1_invers(cairo_surface_t *src_surf)
     return invers;
 }
 
-static cairo_surface_t *canvas_surf_to_invers(cairo_surface_t *surf)
+static pixman_image_t *canvas_surf_to_invers(pixman_image_t *surf)
 {
-    int width = cairo_image_surface_get_width(surf);
-    int height = cairo_image_surface_get_height(surf);
+    int width = pixman_image_get_width(surf);
+    int height = pixman_image_get_height(surf);
     uint8_t *dest_line;
     uint8_t *dest_line_end;
     uint8_t *src_line;
     int dest_stride;
     int src_stride;
 
-    ASSERT(cairo_image_surface_get_format(surf) == CAIRO_FORMAT_RGB24);
-    cairo_surface_t *invers = cairo_image_surface_create(CAIRO_FORMAT_RGB24, width, height);
+    ASSERT(pixman_image_get_depth(surf) == 24);
+    pixman_image_t *invers = pixman_image_create_bits (PIXMAN_x8r8g8b8, width, height, NULL, 0);
 
-    if (cairo_surface_status(invers) != CAIRO_STATUS_SUCCESS) {
-        CANVAS_ERROR("create surface failed, %s",
-                     cairo_status_to_string(cairo_surface_status(invers)));
+    if (invers == NULL) {
+        CANVAS_ERROR("create surface failed");
     }
 
-    dest_line = cairo_image_surface_get_data(invers);
-    dest_stride = cairo_image_surface_get_stride(invers);
+    dest_line = (uint8_t *)pixman_image_get_data(invers);
+    dest_stride = pixman_image_get_stride(invers);
     dest_line_end = dest_line + dest_stride * height;
-    src_line = cairo_image_surface_get_data(surf);
-    src_stride = cairo_image_surface_get_stride(surf);
+    src_line = (uint8_t *)pixman_image_get_data(surf);
+    src_stride = pixman_image_get_stride(surf);
 
     for (; dest_line != dest_line_end; dest_line += dest_stride, src_line += src_stride) {
         uint32_t *src = (uint32_t *)src_line;
@@ -1083,53 +1117,27 @@ static cairo_surface_t *canvas_surf_to_invers(cairo_surface_t *surf)
 * the returned reference, you must call cairo_surface_destroy.
 * Thread safe with respect to the user data.
 */
-static inline cairo_surface_t* canvas_handle_inverse_user_data(cairo_surface_t* surface)
+static inline pixman_image_t* canvas_handle_inverse_user_data(pixman_image_t* surface)
 {
-    cairo_surface_t *inv_surf = NULL;
-#ifdef CAIRO_CANVAS_CACH_IS_SHARED
-    MUTEX_LOCK(cairo_surface_user_data_mutex);
-#endif
-    inv_surf = (cairo_surface_t *)cairo_surface_get_user_data(surface, &invers_data_type);
-#ifdef CAIRO_CANVAS_CACH_IS_SHARED
-    MUTEX_UNLOCK(cairo_surface_user_data_mutex);
-#endif
-    if (!inv_surf) {
-        if (cairo_image_surface_get_format(surface) == CAIRO_FORMAT_A1) {
-            inv_surf = canvas_A1_invers(surface);
-        } else {
-            inv_surf = canvas_surf_to_invers(surface);
-        }
+    pixman_image_t *inv_surf = NULL;
 
-        if (cairo_surface_status(inv_surf) != CAIRO_STATUS_SUCCESS) {
-            cairo_surface_destroy(inv_surf);
-            CANVAS_ERROR("create surface failed, %s",
-                         cairo_status_to_string(cairo_surface_status(surface)));
-        }
-#ifdef CAIRO_CANVAS_CACH_IS_SHARED
-        MUTEX_LOCK(cairo_surface_user_data_mutex);
-
-        // checking if other thread has already assigned the user data
-        if (!cairo_surface_get_user_data(surface, &invers_data_type)) {
-#endif
-            if (cairo_surface_set_user_data(surface, &invers_data_type, inv_surf,
-                                            __release_surface) == CAIRO_STATUS_SUCCESS) {
-                cairo_surface_reference(inv_surf);
-            }
-#ifdef CAIRO_CANVAS_CACH_IS_SHARED
-        }
-        MUTEX_UNLOCK(cairo_surface_user_data_mutex);
-#endif
+    if (pixman_image_get_depth (surface) == 1) {
+        inv_surf = canvas_A1_invers(surface);
     } else {
-        cairo_surface_reference(inv_surf);
+        inv_surf = canvas_surf_to_invers(surface);
+    }
+
+    if (inv_surf == NULL) {
+        CANVAS_ERROR("create surface failed");
     }
 
     return inv_surf;
 }
 
-static cairo_surface_t *canvas_get_mask(CanvasBase *canvas, SpiceQMask *mask)
+static pixman_image_t *canvas_get_mask(CanvasBase *canvas, SpiceQMask *mask)
 {
     SpiceImageDescriptor *descriptor;
-    cairo_surface_t *surface;
+    pixman_image_t *surface;
     int need_invers;
     int is_invers;
     int cache_me;
@@ -1172,11 +1180,11 @@ static cairo_surface_t *canvas_get_mask(CanvasBase *canvas, SpiceQMask *mask)
     }
 
     if (need_invers && !is_invers) { // surface is in cache
-        cairo_surface_t *inv_surf;
+        pixman_image_t *inv_surf;
 
         inv_surf = canvas_handle_inverse_user_data(surface);
 
-        cairo_surface_destroy(surface);
+        pixman_image_unref(surface);
         surface = inv_surf;
     }
 #endif
@@ -1332,12 +1340,12 @@ static void canvas_put_glyph_bits(SpiceRasterGlyph *glyph, int bpp, uint8_t *des
     }
 }
 
-static cairo_surface_t *canvas_get_str_mask(CanvasBase *canvas, SpiceString *str, int bpp, SpicePoint *pos)
+static pixman_image_t *canvas_get_str_mask(CanvasBase *canvas, SpiceString *str, int bpp, SpicePoint *pos)
 {
     SpiceRasterGlyph *glyph = (SpiceRasterGlyph *)str->data;
     SpiceRasterGlyph *next_glyph;
     SpiceRect bounds;
-    cairo_surface_t *str_mask;
+    pixman_image_t *str_mask;
     uint8_t *dest;
     int dest_stride;
     int i;
@@ -1360,15 +1368,14 @@ static cairo_surface_t *canvas_get_str_mask(CanvasBase *canvas, SpiceString *str
         rect_union(&bounds, &glyph_box);
     }
 
-    str_mask = cairo_image_surface_create((bpp == 1) ? CAIRO_FORMAT_A1 : CAIRO_FORMAT_A8,
-                                          bounds.right - bounds.left,
-                                          bounds.bottom - bounds.top);
-    if (cairo_surface_status(str_mask) != CAIRO_STATUS_SUCCESS) {
-        CANVAS_ERROR("create surface failed, %s",
-                     cairo_status_to_string(cairo_surface_status(str_mask)));
+    str_mask = pixman_image_create_bits((bpp == 1) ? PIXMAN_a1 : PIXMAN_a8,
+                                        bounds.right - bounds.left,
+                                        bounds.bottom - bounds.top, NULL, 0);
+    if (str_mask == NULL) {
+        CANVAS_ERROR("create surface failed");
     }
-    dest = cairo_image_surface_get_data(str_mask);
-    dest_stride = cairo_image_surface_get_stride(str_mask);
+    dest = (uint8_t *)pixman_image_get_data(str_mask);
+    dest_stride = pixman_image_get_stride(str_mask);
     glyph = (SpiceRasterGlyph *)str->data;
     for (i = 0; i < str->length; i++) {
 #if defined(GL_CANVAS)
@@ -1390,47 +1397,40 @@ static inline SpiceVectorGlyph *canvas_next_vector_glyph(const SpiceVectorGlyph
     return (SpiceVectorGlyph *)((uint8_t *)(glyph + 1) + glyph->data_size);
 }
 
-static cairo_surface_t *canvas_scale_surface(cairo_surface_t *src, const SpiceRect *src_area, int width,
-                                             int hight, int scale_mode)
+static pixman_image_t *canvas_scale_surface(pixman_image_t *src, const SpiceRect *src_area, int width,
+                                            int height, int scale_mode)
 {
-    cairo_t *cairo;
-    cairo_surface_t *surface;
-    cairo_pattern_t *pattern;
-    cairo_matrix_t matrix;
+    pixman_image_t *surface;
+    pixman_transform_t transform;
     double sx, sy;
 
-    surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24, width, hight);
-    if (cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS) {
-        CANVAS_ERROR("create surface failed, %s",
-                     cairo_status_to_string(cairo_surface_status(surface)));
-    }
-
-    cairo = cairo_create(surface);
-    if (cairo_status(cairo) != CAIRO_STATUS_SUCCESS) {
-        CANVAS_ERROR("create surface failed, %s", cairo_status_to_string(cairo_status(cairo)));
-    }
-
-    pattern = cairo_pattern_create_for_surface(src);
-    if (cairo_pattern_status(pattern) != CAIRO_STATUS_SUCCESS) {
-        CANVAS_ERROR("create pattern failed, %s",
-                     cairo_status_to_string(cairo_pattern_status(pattern)));
+    surface = pixman_image_create_bits(PIXMAN_x8r8g8b8, width, height, NULL, 0);
+    if (surface == NULL) {
+        CANVAS_ERROR("create surface failed");
     }
 
     sx = (double)(src_area->right - src_area->left) / width;
-    sy = (double)(src_area->bottom - src_area->top) / hight;
+    sy = (double)(src_area->bottom - src_area->top) / height;
 
-    cairo_matrix_init_translate(&matrix, src_area->left, src_area->top);
-    cairo_matrix_scale(&matrix, sx, sy);
+    pixman_transform_init_scale(&transform, pixman_double_to_fixed(sx), pixman_double_to_fixed(sy));
 
-    cairo_pattern_set_matrix(pattern, &matrix);
+    pixman_image_set_transform (src, &transform);
+    pixman_image_set_repeat(src, PIXMAN_REPEAT_NONE);
+    pixman_image_set_source_clipping(src, TRUE);
     ASSERT(scale_mode == SPICE_IMAGE_SCALE_MODE_INTERPOLATE || scale_mode == SPICE_IMAGE_SCALE_MODE_NEAREST);
-    cairo_pattern_set_filter(pattern, (scale_mode == SPICE_IMAGE_SCALE_MODE_NEAREST) ?
-                                                          CAIRO_FILTER_NEAREST : CAIRO_FILTER_GOOD);
+    pixman_image_set_filter (src,
+                             (scale_mode == SPICE_IMAGE_SCALE_MODE_NEAREST) ?PIXMAN_FILTER_NEAREST : PIXMAN_FILTER_GOOD,
+                             NULL, 0);
+
+    pixman_image_composite32 (PIXMAN_OP_SRC,
+                              src, NULL, surface,
+                              ROUND(src_area->left / sx), ROUND (src_area->top / sy),
+                              0, 0, /* mask */
+                              0, 0, /* dst */
+                              width, height);
+
+    pixman_image_set_transform (src, NULL);
 
-    cairo_set_source(cairo, pattern);
-    cairo_pattern_destroy(pattern);
-    cairo_paint(cairo);
-    cairo_destroy(cairo);
     return surface;
 }
 
diff --git a/common/canvas_base.h b/common/canvas_base.h
index cc75087..78ece62 100644
--- a/common/canvas_base.h
+++ b/common/canvas_base.h
@@ -20,7 +20,7 @@
 #define _H_CANVAS_BASE
 
 
-#include "cairo.h"
+#include "pixman_utils.h"
 #include "lz.h"
 #include <spice/draw.h>
 
@@ -30,9 +30,9 @@ typedef struct _SpicePaletteCache SpicePaletteCache;
 typedef struct {
     void (*put)(SpiceImageCache *cache,
                 uint64_t id,
-                cairo_surface_t *surface);
-    cairo_surface_t *(*get)(SpiceImageCache *cache,
-                            uint64_t id);
+                pixman_image_t *surface);
+    pixman_image_t *(*get)(SpiceImageCache *cache,
+                           uint64_t id);
 } SpiceImageCacheOps;
 
 struct _SpiceImageCache {
diff --git a/common/canvas_utils.c b/common/canvas_utils.c
index f6470ca..d581abd 100644
--- a/common/canvas_utils.c
+++ b/common/canvas_utils.c
@@ -1,3 +1,4 @@
+/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
 /*
    Copyright (C) 2009 Red Hat, Inc.
 
@@ -45,31 +46,49 @@ extern int gdi_handlers;
 #define ALIGN(a, b) (((a) + ((b) - 1)) & ~((b) - 1))
 #endif
 
-const cairo_user_data_key_t bitmap_data_type = {0};
-const cairo_user_data_key_t bitmap_withstride_data_type = {0};
-
-#ifdef WIN32
-static void release_bitmap(void *bitmap_cache)
+static void release_data (pixman_image_t *image, void *release_data)
 {
-    DeleteObject((HBITMAP)((BitmapCache *)bitmap_cache)->bitmap);
-    CloseHandle(((BitmapCache *)bitmap_cache)->mutex);
-    free(bitmap_cache);
-    gdi_handlers--;
-}
+    PixmanData *data = (PixmanData *)release_data;
 
+#ifdef WIN32
+    if (data->bitmap) {
+        DeleteObject((HBITMAP)data->bitmap);
+        CloseHandle(data->mutex);
+        gdi_handlers--;
+    }
 #endif
+    if (data->data)
+        free(data->data);
 
-static void release_withstride_bitmap(void *data)
-{
     free(data);
 }
 
-static inline cairo_surface_t *__surface_create_stride(cairo_format_t format, int width, int height,
-                                                       int stride)
+static PixmanData *
+pixman_image_add_data (pixman_image_t *image)
+{
+    PixmanData *data;
+
+    data = (PixmanData *)pixman_image_get_destroy_data (image);
+    if (data == NULL) {
+        data = (PixmanData *)calloc(1, sizeof(PixmanData));
+        if (data == NULL) {
+            CANVAS_ERROR("out of memory");
+        }
+        pixman_image_set_destroy_function (image,
+                                           release_data,
+                                           data);
+    }
+
+    return data;
+}
+
+static inline pixman_image_t *__surface_create_stride(pixman_format_code_t format, int width, int height,
+                                                      int stride)
 {
     uint8_t *data;
     uint8_t *stride_data;
-    cairo_surface_t *surface;
+    pixman_image_t *surface;
+    PixmanData *pixman_data;
 
     data = (uint8_t *)malloc(abs(stride) * height);
     if (stride < 0) {
@@ -78,30 +97,24 @@ static inline cairo_surface_t *__surface_create_stride(cairo_format_t format, in
         stride_data = data;
     }
 
-    surface = cairo_image_surface_create_for_data(stride_data, format, width, height, stride);
+    surface = pixman_image_create_bits(format, width, height, (uint32_t *)stride_data, stride);
 
-    if (cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS) {
+    if (surface == NULL) {
         free(data);
-        CANVAS_ERROR("create surface failed, %s",
-                     cairo_status_to_string(cairo_surface_status(surface)));
+        CANVAS_ERROR("create surface failed, out of memory");
     }
 
-    if (cairo_surface_set_user_data(surface, &bitmap_withstride_data_type, data,
-                                    release_withstride_bitmap) != CAIRO_STATUS_SUCCESS) {
-        free(data);
-        cairo_surface_destroy(surface);
-        CANVAS_ERROR("set_user_data surface failed, %s",
-                     cairo_status_to_string(cairo_surface_status(surface)));
-    }
+    pixman_data = pixman_image_add_data (surface);
+    pixman_data->data = data;
 
     return surface;
 }
 
 #ifdef WIN32
-cairo_surface_t *surface_create(HDC dc, cairo_format_t format,
+pixman_image_t *surface_create(HDC dc, pixman_format_code_t format,
                                 int width, int height, int top_down)
 #else
-cairo_surface_t * surface_create(cairo_format_t format, int width, int height, int top_down)
+pixman_image_t * surface_create(pixman_format_code_t format, int width, int height, int top_down)
 #endif
 {
 #ifdef WIN32
@@ -120,8 +133,10 @@ cairo_surface_t * surface_create(cairo_format_t format, int width, int height, i
             RGBQUAD palette[255];
         } bitmap_info;
         int nstride;
-        cairo_surface_t *surface;
-        BitmapCache *bitmap_cache;
+        pixman_image_t *surface;
+        PixmanData *pixman_data;
+        HBITMAP bitmap;
+        HANDLE mutex;
 
         memset(&bitmap_info, 0, sizeof(bitmap_info));
         bitmap_info.inf.bmiHeader.biSize = sizeof(bitmap_info.inf.bmiHeader);
@@ -131,16 +146,16 @@ cairo_surface_t * surface_create(cairo_format_t format, int width, int height, i
 
         bitmap_info.inf.bmiHeader.biPlanes = 1;
         switch (format) {
-        case CAIRO_FORMAT_ARGB32:
-        case CAIRO_FORMAT_RGB24:
+        case PIXMAN_a8r8g8b8:
+        case PIXMAN_x8r8g8b8:
             bitmap_info.inf.bmiHeader.biBitCount = 32;
             nstride = width * 4;
             break;
-        case CAIRO_FORMAT_A8:
+        case PIXMAN_a8:
             bitmap_info.inf.bmiHeader.biBitCount = 8;
             nstride = ALIGN(width, 4);
             break;
-        case CAIRO_FORMAT_A1:
+        case PIXMAN_a1:
             bitmap_info.inf.bmiHeader.biBitCount = 1;
             nstride = ALIGN(width, 32) / 8;
             break;
@@ -150,25 +165,15 @@ cairo_surface_t * surface_create(cairo_format_t format, int width, int height, i
 
         bitmap_info.inf.bmiHeader.biCompression = BI_RGB;
 
-        bitmap_cache = (BitmapCache *)malloc(sizeof(*bitmap_cache));
-        if (!bitmap_cache) {
-            CANVAS_ERROR("malloc failed");
-            return NULL;
-        }
-
-        bitmap_cache->mutex = CreateMutex(NULL, 0, NULL);
-        if (!bitmap_cache->mutex) {
-            free(bitmap_cache);
+        mutex = CreateMutex(NULL, 0, NULL);
+        if (!mutex) {
             CANVAS_ERROR("Unable to CreateMutex");
-            return NULL;
         }
 
-        bitmap_cache->bitmap = CreateDIBSection(dc, &bitmap_info.inf, 0, (VOID **)&data, NULL, 0);
-        if (!bitmap_cache->bitmap) {
+        bitmap = CreateDIBSection(dc, &bitmap_info.inf, 0, (VOID **)&data, NULL, 0);
+        if (!bitmap) {
             CloseHandle(bitmap_cache->mutex);
-            free(bitmap_cache);
             CANVAS_ERROR("Unable to CreateDIBSection");
-            return NULL;
         }
 
         if (top_down) {
@@ -178,41 +183,33 @@ cairo_surface_t * surface_create(cairo_format_t format, int width, int height, i
             nstride = -nstride;
         }
 
-        surface = cairo_image_surface_create_for_data(src, format, width, height, nstride);
-        if (cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS) {
-            CloseHandle(bitmap_cache->mutex);
-            DeleteObject((HBITMAP)bitmap_cache->bitmap);
-            free(bitmap_cache);
-            CANVAS_ERROR("create surface failed, %s",
-                         cairo_status_to_string(cairo_surface_status(surface)));
-        }
-        if (cairo_surface_set_user_data(surface, &bitmap_data_type, bitmap_cache,
-                                        release_bitmap) != CAIRO_STATUS_SUCCESS) {
-            CloseHandle(bitmap_cache->mutex);
-            cairo_surface_destroy(surface);
-            DeleteObject((HBITMAP)bitmap_cache->bitmap);
-            free(bitmap_cache);
-            CANVAS_ERROR("set_user_data surface failed, %s",
-                         cairo_status_to_string(cairo_surface_status(surface)));
+        surface = pixman_image_create_bits(format, width, height, (uint32_t *)src, stride);
+        if (surface == NULL) {
+            CloseHandle(mutex);
+            DeleteObject(bitmap);
+            CANVAS_ERROR("create surface failed, out of memory");
         }
+        pixman_data = pixman_image_add_data (surface);
+        pixman_data.bitmap = bitmap;
+        pixman_data.mutex = mutex;
         gdi_handlers++;
         return surface;
     } else {
 #endif
     if (top_down) {
-        return cairo_image_surface_create(format, width, height);
+        return pixman_image_create_bits(format, width, height, NULL, 0);
     } else {
         // NOTE: we assume here that the lz decoders always decode to RGB32.
         int stride = 0;
         switch (format) {
-        case CAIRO_FORMAT_ARGB32:
-        case CAIRO_FORMAT_RGB24:
+        case PIXMAN_a8r8g8b8:
+        case PIXMAN_x8r8g8b8:
             stride = width * 4;
             break;
-        case CAIRO_FORMAT_A8:
+        case PIXMAN_a8:
             stride = ALIGN(width, 4);
             break;
-        case CAIRO_FORMAT_A1:
+        case PIXMAN_a1:
             stride = ALIGN(width, 32) / 8;
             break;
         default:
@@ -228,11 +225,11 @@ cairo_surface_t * surface_create(cairo_format_t format, int width, int height, i
 }
 
 #ifdef WIN32
-cairo_surface_t *surface_create_stride(HDC dc, cairo_format_t format, int width, int height,
-                                       int stride)
+pixman_image_t *surface_create_stride(HDC dc, pixman_format_code_t format, int width, int height,
+				      int stride)
 #else
-cairo_surface_t *surface_create_stride(cairo_format_t format, int width, int height,
-                                        int stride)
+pixman_image_t *surface_create_stride(pixman_format_code_t format, int width, int height,
+				      int stride)
 #endif
 {
 #ifdef WIN32
@@ -246,12 +243,12 @@ cairo_surface_t *surface_create_stride(cairo_format_t format, int width, int hei
     return __surface_create_stride(format, width, height, stride);
 }
 
-cairo_surface_t *alloc_lz_image_surface(LzDecodeUsrData *canvas_data, LzImageType type, int width,
-                                        int height, int gross_pixels, int top_down)
+pixman_image_t *alloc_lz_image_surface(LzDecodeUsrData *canvas_data, LzImageType type, int width,
+				       int height, int gross_pixels, int top_down)
 {
     int stride;
     int alpha;
-    cairo_surface_t *surface = NULL;
+    pixman_image_t *surface = NULL;
 
     stride = (gross_pixels / height) * 4;
 
@@ -270,7 +267,7 @@ cairo_surface_t *alloc_lz_image_surface(LzDecodeUsrData *canvas_data, LzImageTyp
 #ifdef WIN32
             canvas_data->dc,
 #endif
-            alpha ? CAIRO_FORMAT_ARGB32 : CAIRO_FORMAT_RGB24, width, height, stride);
+            alpha ? PIXMAN_a8r8g8b8 : PIXMAN_x8r8g8b8, width, height, stride);
     canvas_data->out_surface = surface;
     return surface;
 }
diff --git a/common/canvas_utils.h b/common/canvas_utils.h
index 10f2d64..4fdbe6a 100644
--- a/common/canvas_utils.h
+++ b/common/canvas_utils.h
@@ -1,3 +1,4 @@
+/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
 /*
    Copyright (C) 2009 Red Hat, Inc.
 
@@ -20,31 +21,30 @@
 
 #include <spice/types.h>
 
-#include "cairo.h"
+#include "pixman_utils.h"
 #include "lz.h"
 
+typedef struct PixmanData {
 #ifdef WIN32
-typedef struct BitmapCache {
     HBITMAP bitmap;
     HANDLE mutex;
-} BitmapCache;
 #endif
-
-extern const cairo_user_data_key_t bitmap_data_type;
+    uint8_t *data;
+} PixmanData;
 
 #ifdef WIN32
-cairo_surface_t *surface_create(HDC dc, cairo_format_t format,
-                                int width, int height, int top_down);
+pixman_image_t *surface_create(HDC dc, pixman_format_code_t format,
+                               int width, int height, int top_down);
 #else
-cairo_surface_t *surface_create(cairo_format_t format, int width, int height, int top_down);
+pixman_image_t *surface_create(pixman_format_code_t format, int width, int height, int top_down);
 #endif
 
 #ifdef WIN32
-cairo_surface_t *surface_create_stride(HDC dc, cairo_format_t format, int width, int height,
-                                       int stride);
+pixman_image_t *surface_create_stride(HDC dc, pixman_format_code_t format, int width, int height,
+                                      int stride);
 #else
-cairo_surface_t *surface_create_stride(cairo_format_t format, int width, int height,
-                                       int stride);
+pixman_image_t *surface_create_stride(pixman_format_code_t format, int width, int height,
+                                      int stride);
 #endif
 
 
@@ -52,10 +52,10 @@ typedef struct LzDecodeUsrData {
 #ifdef WIN32
     HDC dc;
 #endif
-    cairo_surface_t       *out_surface;
+    pixman_image_t       *out_surface;
 } LzDecodeUsrData;
 
 
-cairo_surface_t *alloc_lz_image_surface(LzDecodeUsrData *canvas_data, LzImageType type, int width,
-                                        int height, int gross_pixels, int top_down);
+pixman_image_t *alloc_lz_image_surface(LzDecodeUsrData *canvas_data, LzImageType type, int width,
+                                       int height, int gross_pixels, int top_down);
 #endif
diff --git a/common/gdi_canvas.c b/common/gdi_canvas.c
index be351b5..7dda270 100644
--- a/common/gdi_canvas.c
+++ b/common/gdi_canvas.c
@@ -304,15 +304,15 @@ uint32_t raster_ops[] = {
     0x00FF0062 // 1 WHITENESS
 };
 
-static inline void surface_to_image(cairo_surface_t *surface, GdiImage *image)
+static inline void surface_to_image(pixman_image_t *surface, GdiImage *image)
 {
-    cairo_format_t format = cairo_image_surface_get_format(surface);
+    int depth = pixman_image_surface_get_depth(surface);
 
-    ASSERT(format == CAIRO_FORMAT_ARGB32 || format == CAIRO_FORMAT_RGB24);
-    image->width = cairo_image_surface_get_width(surface);
-    image->height = cairo_image_surface_get_height(surface);
-    image->stride = cairo_image_surface_get_stride(surface);
-    image->pixels = cairo_image_surface_get_data(surface);
+    ASSERT(depth == 32 || depth == 24);
+    image->width = pixman_image_get_width(surface);
+    image->height = pixman_image_get_height(surface);
+    image->stride = pixman_image_get_stride(surface);
+    image->pixels = pixman_image_get_data(surface);
 }
 
 static void set_path(GdiCanvas *canvas, void *addr)
@@ -644,7 +644,7 @@ static HBRUSH get_brush(GdiCanvas *canvas, SpiceBrush *brush)
     case SPICE_BRUSH_TYPE_PATTERN: {
         GdiImage image;
         HBRUSH hbrush;
-        cairo_surface_t *surface;
+        pixman_image_t *surface;
         HDC dc;
         HBITMAP bitmap;
         HBITMAP prev_bitmap;
@@ -663,7 +663,7 @@ static HBRUSH get_brush(GdiCanvas *canvas, SpiceBrush *brush)
         }
 
         release_bitmap(dc, bitmap, prev_bitmap, 0);
-        cairo_surface_destroy(surface);
+        pixman_image_unref(surface);
         return hbrush;
     }
     case SPICE_BRUSH_TYPE_NONE:
@@ -778,27 +778,27 @@ uint8_t calc_rop3_src_brush(uint16_t rop3_bits)
 
 static struct BitmapData get_mask_bitmap(struct GdiCanvas *canvas, struct SpiceQMask *mask)
 {
-    cairo_surface_t *surface;
+    pixman_image_t *surface;
     struct BitmapData bitmap;
-    BitmapCache *bitmap_cache;
+    PixmanData *pixman_data;
 
     bitmap.hbitmap = NULL;
     if (!(surface = canvas_get_mask(&canvas->base, mask))) {
         return bitmap;
     }
 
-    bitmap_cache = (BitmapCache *)cairo_surface_get_user_data(surface, &bitmap_data_type);
-    if (bitmap_cache && (WaitForSingleObject(bitmap_cache->mutex, INFINITE) != WAIT_FAILED)) {
+    pixman_data = pixman_image_get_destroy_data (surface);
+    if (pixman_data && (WaitForSingleObject(pixman_data->mutex, INFINITE) != WAIT_FAILED)) {
         bitmap.dc = create_compatible_dc();
-        bitmap.prev_hbitmap = (HBITMAP)SelectObject(bitmap.dc, bitmap_cache->bitmap);
-        bitmap.hbitmap = bitmap_cache->bitmap;
-        ReleaseMutex(bitmap_cache->mutex);
+        bitmap.prev_hbitmap = (HBITMAP)SelectObject(bitmap.dc, pixman_data->bitmap);
+        bitmap.hbitmap = pixman_data->bitmap;
+        ReleaseMutex(pixman_data->mutex);
         bitmap.cache = 1;
     } else if (!create_bitmap(&bitmap.hbitmap, &bitmap.prev_hbitmap, &bitmap.dc,
-                              cairo_image_surface_get_data(surface),
-                              cairo_image_surface_get_width(surface),
-                              cairo_image_surface_get_height(surface),
-                              cairo_image_surface_get_stride(surface), 1, 0)) {
+                              pixman_image_get_data(surface),
+                              pixman_image_get_width(surface),
+                              pixman_image_get_height(surface),
+                              pixman_image_get_stride(surface), 1, 0)) {
         bitmap.hbitmap = NULL;
     } else {
         bitmap.cache = 0;
@@ -864,7 +864,7 @@ static void draw_str_mask_bitmap(struct GdiCanvas *canvas,
                                  SpiceString *str, int n, SpiceRect *dest,
                                  SpiceRect *src, SpiceBrush *brush)
 {
-    cairo_surface_t *surface;
+    pixman_image_t *surface;
     struct BitmapData bitmap;
     SpicePoint pos;
     int dest_stride;
@@ -881,9 +881,9 @@ static void draw_str_mask_bitmap(struct GdiCanvas *canvas,
     bitmap.cache = 0;
     bitmap_data = create_bitmap(&bitmap.hbitmap, &bitmap.prev_hbitmap,
                                 &bitmap.dc, NULL,
-                                cairo_image_surface_get_width(surface),
-                                cairo_image_surface_get_height(surface),
-                                cairo_image_surface_get_stride(surface), 32, 0);
+                                pixman_image_get_width(surface),
+                                pixman_image_get_height(surface),
+                                pixman_image_get_stride(surface), 32, 0);
 
     if (!bitmap_data) {
         return;
@@ -895,14 +895,14 @@ static void draw_str_mask_bitmap(struct GdiCanvas *canvas,
 
     dest->left = pos.x;
     dest->top = pos.y;
-    dest->right = pos.x + cairo_image_surface_get_width(surface);
-    dest->bottom = pos.y + cairo_image_surface_get_height(surface);
+    dest->right = pos.x + pixman_image_get_width(surface);
+    dest->bottom = pos.y + pixman_image_get_height(surface);
     src->left = 0;
     src->top = 0;
-    src->right = cairo_image_surface_get_width(surface);
-    src->bottom = cairo_image_surface_get_height(surface);
+    src->right = pixman_image_get_width(surface);
+    src->bottom = pixman_image_get_height(surface);
 
-    dest_stride = cairo_image_surface_get_width(surface);
+    dest_stride = pixman_image_get_width(surface);
     switch (n) {
     case 1:
         dest_stride = dest_stride / 8;
@@ -925,10 +925,10 @@ static void draw_str_mask_bitmap(struct GdiCanvas *canvas,
 
     unset_brush(bitmap.dc, prev_hbrush);
 
-    copy_bitmap_alpha(cairo_image_surface_get_data(surface),
-                      cairo_image_surface_get_height(surface),
-                      cairo_image_surface_get_width(surface),
-                      cairo_image_surface_get_stride(surface),
+    copy_bitmap_alpha(pixman_image_get_data(surface),
+                      pixman_image_get_height(surface),
+                      pixman_image_get_width(surface),
+                      pixman_image_get_stride(surface),
                       bitmap_data, dest_stride, n);
 
     BLENDFUNCTION bf = {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA};
@@ -999,30 +999,30 @@ void gdi_canvas_draw_fill(GdiCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, S
 
 void gdi_canvas_draw_copy(GdiCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, SpiceCopy *copy)
 {
-    cairo_surface_t *surface;
+    pixman_image_t *surface;
     GdiImage image;
     struct BitmapData bitmapmask;
-    BitmapCache *bitmap_cache;
+    PixmanData *pixman_data;
 
     bitmapmask = get_mask_bitmap(canvas, &copy->mask);
     surface = canvas_get_image(&canvas->base, copy->src_bitmap);
-    bitmap_cache = (BitmapCache *)cairo_surface_get_user_data(surface, &bitmap_data_type);
+    pixman_data = (PixmanData *)pixman_image_get_destroy_data(surface);
 
     Lock lock(*canvas->lock);
     set_scale_mode(canvas, copy->scale_mode);
     set_clip(canvas, clip);
 
-    if (bitmap_cache && (WaitForSingleObject(bitmap_cache->mutex, INFINITE) != WAIT_FAILED)) {
+    if (pixman_data && (WaitForSingleObject(pixman_data->mutex, INFINITE) != WAIT_FAILED)) {
         HDC dc;
         HBITMAP prev_bitmap;
 
         dc = create_compatible_dc();
-        prev_bitmap = (HBITMAP)SelectObject(dc, bitmap_cache->bitmap);
+        prev_bitmap = (HBITMAP)SelectObject(dc, pixman_data->bitmap);
         gdi_draw_bitmap_redrop(canvas->dc, &copy->src_area, bbox, dc,
                                &bitmapmask, copy->rop_decriptor, 0);
         SelectObject(dc, prev_bitmap);
         DeleteObject(dc);
-        ReleaseMutex(bitmap_cache->mutex);
+        ReleaseMutex(pixman_data->mutex);
     } else {
         surface_to_image(surface, &image);
         gdi_draw_image(canvas->dc, &copy->src_area, bbox, image.pixels,
@@ -1032,7 +1032,7 @@ void gdi_canvas_draw_copy(GdiCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, S
 
     free_mask(&bitmapmask);
 
-    cairo_surface_destroy(surface);
+    pixman_image_unref(surface);
 }
 
 void gdi_canvas_put_image(GdiCanvas *canvas, HDC dc, const SpiceRect *dest, const uint8_t *src_data,
@@ -1126,26 +1126,26 @@ static void gdi_draw_image_transparent(GdiCanvas *canvas, HDC dest_dc, const Spi
 void gdi_canvas_draw_transparent(GdiCanvas *canvas, SpiceRect *bbox, SpiceClip *clip,
                                  SpiceTransparent* transparent)
 {
-    cairo_surface_t *surface;
+    pixman_image_t *surface;
     GdiImage image;
-    BitmapCache *bitmap_cache;
+    PixmanData *pixman_data;
 
     surface = canvas_get_image(&canvas->base, transparent->src_bitmap);
-    bitmap_cache = (BitmapCache *)cairo_surface_get_user_data(surface, &bitmap_data_type);
+    pixman_data = (PixmanData *)pixman_image_get_destroy_data(surface);
     Lock lock(*canvas->lock);
     set_clip(canvas, clip);
-    if (bitmap_cache && (WaitForSingleObject(bitmap_cache->mutex, INFINITE) != WAIT_FAILED)) {
+    if (pixman_data && (WaitForSingleObject(pixman_data->mutex, INFINITE) != WAIT_FAILED)) {
         HDC dc;
         HBITMAP prev_bitmap;
 
         dc = create_compatible_dc();
-        prev_bitmap = (HBITMAP)SelectObject(dc, bitmap_cache->bitmap);
+        prev_bitmap = (HBITMAP)SelectObject(dc, pixman_data->bitmap);
         gdi_draw_bitmap_transparent(canvas, canvas->dc, &transparent->src_area, bbox, dc,
                                     transparent->true_color);
 
         SelectObject(dc, prev_bitmap);
         DeleteObject(dc);
-        ReleaseMutex(bitmap_cache->mutex);
+        ReleaseMutex(pixman_data->mutex);
     } else {
         surface_to_image(surface, &image);
         gdi_draw_image_transparent(canvas, canvas->dc, &transparent->src_area, bbox, image.pixels,
@@ -1153,7 +1153,7 @@ void gdi_canvas_draw_transparent(GdiCanvas *canvas, SpiceRect *bbox, SpiceClip *
                                    transparent->true_color, 0);
     }
 
-    cairo_surface_destroy(surface);
+    pixman_image_unref(surface);
 }
 
 static void gdi_draw_bitmap_alpha(HDC dest_dc, const SpiceRect *src, const SpiceRect *dest,
@@ -1197,28 +1197,28 @@ static void gdi_draw_image_alpha(HDC dest_dc, const SpiceRect *src, const SpiceR
 
 void gdi_canvas_draw_alpha_blend(GdiCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, SpiceAlphaBlnd* alpha_blend)
 {
-    cairo_surface_t *surface;
+    pixman_image_t *surface;
     GdiImage image;
-    BitmapCache *bitmap_cache;
+    PixmanData *pixman_data;
     int use_bitmap_alpha;
 
     surface = canvas_get_image(&canvas->base, alpha_blend->src_bitmap);
-    use_bitmap_alpha = cairo_image_surface_get_format(surface) == CAIRO_FORMAT_ARGB32;
-    bitmap_cache = (BitmapCache *)cairo_surface_get_user_data(surface, &bitmap_data_type);
+    use_bitmap_alpha = pixman_image_get_depth(surface) == 32;
+    pixman_data = (PixmanData *)pixman_image_get_destroy_data(surface);
 
     Lock lock(*canvas->lock);
     set_clip(canvas, clip);
-    if (bitmap_cache && (WaitForSingleObject(bitmap_cache->mutex, INFINITE) != WAIT_FAILED)) {
+    if (pixman_data && (WaitForSingleObject(pixman_data->mutex, INFINITE) != WAIT_FAILED)) {
         HDC dc;
         HBITMAP prev_bitmap;
 
         dc = create_compatible_dc();
-        prev_bitmap = (HBITMAP)SelectObject(dc, bitmap_cache->bitmap);
+        prev_bitmap = (HBITMAP)SelectObject(dc, pixman_data->bitmap);
         gdi_draw_bitmap_alpha(canvas->dc, &alpha_blend->src_area, bbox, dc, alpha_blend->alpha,
                               use_bitmap_alpha);
         SelectObject(dc, prev_bitmap);
         DeleteObject(dc);
-        ReleaseMutex(bitmap_cache->mutex);
+        ReleaseMutex(pixman_data->mutex);
     } else {
         surface_to_image(surface, &image);
         gdi_draw_image_alpha(canvas->dc, &alpha_blend->src_area, bbox, image.pixels,
@@ -1226,21 +1226,21 @@ void gdi_canvas_draw_alpha_blend(GdiCanvas *canvas, SpiceRect *bbox, SpiceClip *
                              alpha_blend->alpha, 0, use_bitmap_alpha);
     }
 
-    cairo_surface_destroy(surface);
+    pixman_image_unref(surface);
 }
 
 void gdi_canvas_draw_opaque(GdiCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, SpiceOpaque *opaque)
 {
-    cairo_surface_t *surface;
+    pixman_image_t *surface;
     GdiImage image;
     struct BitmapData bitmapmask;
-    BitmapCache *bitmap_cache;
+    PixmanData *pixman_data;
     HBRUSH prev_hbrush;
     HBRUSH hbrush;
     uint8_t rop3;
 
     surface = canvas_get_image(&canvas->base, opaque->src_bitmap);
-    bitmap_cache = (BitmapCache *)cairo_surface_get_user_data(surface, &bitmap_data_type);
+    pixman_data = (PixmanData *)pixman_image_get_destroy_data(surface);
     bitmapmask = get_mask_bitmap(canvas, &opaque->mask);
     rop3 = calc_rop3_src_brush(opaque->rop_decriptor);
     hbrush = get_brush(canvas, &opaque->brush);
@@ -1251,16 +1251,16 @@ void gdi_canvas_draw_opaque(GdiCanvas *canvas, SpiceRect *bbox, SpiceClip *clip,
     set_clip(canvas, clip);
     prev_hbrush = set_brush(canvas->dc, hbrush, &opaque->brush);
 
-    if (bitmap_cache && (WaitForSingleObject(bitmap_cache->mutex, INFINITE) != WAIT_FAILED)) {
+    if (pixman_data && (WaitForSingleObject(pixman_data->mutex, INFINITE) != WAIT_FAILED)) {
         HDC dc;
         HBITMAP prev_bitmap;
 
         dc = create_compatible_dc();
-        prev_bitmap = (HBITMAP)SelectObject(dc, bitmap_cache->bitmap);
+        prev_bitmap = (HBITMAP)SelectObject(dc, pixman_data->bitmap);
         gdi_draw_bitmap(canvas->dc, &opaque->src_area, bbox, dc, &bitmapmask, rop3);
         SelectObject(dc, prev_bitmap);
         DeleteObject(dc);
-        ReleaseMutex(bitmap_cache->mutex);
+        ReleaseMutex(pixman_data->mutex);
     } else {
         surface_to_image(surface, &image);
         gdi_draw_image_rop3(canvas->dc, &opaque->src_area, bbox, image.pixels,
@@ -1271,35 +1271,35 @@ void gdi_canvas_draw_opaque(GdiCanvas *canvas, SpiceRect *bbox, SpiceClip *clip,
 
     free_mask(&bitmapmask);
 
-    cairo_surface_destroy(surface);
+    pixman_image_unref(surface);
 }
 
 void gdi_canvas_draw_blend(GdiCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, SpiceBlend *blend)
 {
-    cairo_surface_t *surface;
+    pixman_image_t *surface;
     GdiImage image;
     struct BitmapData bitmapmask;
-    BitmapCache *bitmap_cache;
+    PixmanData *pixman_data;
 
     bitmapmask = get_mask_bitmap(canvas, &blend->mask);
     surface = canvas_get_image(&canvas->base, blend->src_bitmap);
-    bitmap_cache = (BitmapCache *)cairo_surface_get_user_data(surface, &bitmap_data_type);
+    pixman_data = (PixmanData *)pixman_image_get_destroy_data(surface);
 
     Lock lock(*canvas->lock);
     set_scale_mode(canvas, blend->scale_mode);
     set_clip(canvas, clip);
 
-    if (bitmap_cache && (WaitForSingleObject(bitmap_cache->mutex, INFINITE) != WAIT_FAILED)) {
+    if (pixman_data && (WaitForSingleObject(pixman_data->mutex, INFINITE) != WAIT_FAILED)) {
         HDC dc;
         HBITMAP prev_bitmap;
 
         dc = create_compatible_dc();
-        prev_bitmap = (HBITMAP)SelectObject(dc, bitmap_cache->bitmap);
+        prev_bitmap = (HBITMAP)SelectObject(dc, pixman_data->bitmap);
         gdi_draw_bitmap_redrop(canvas->dc, &blend->src_area, bbox, dc,
                                &bitmapmask, blend->rop_decriptor, 0);
         SelectObject(dc, prev_bitmap);
         DeleteObject(dc);
-        ReleaseMutex(bitmap_cache->mutex);
+        ReleaseMutex(pixman_data->mutex);
     } else {
         surface_to_image(surface, &image);
         gdi_draw_image(canvas->dc, &blend->src_area, bbox, image.pixels, image.stride, image.width,
@@ -1308,7 +1308,7 @@ void gdi_canvas_draw_blend(GdiCanvas *canvas, SpiceRect *bbox, SpiceClip *clip,
 
     free_mask(&bitmapmask);
 
-    cairo_surface_destroy(surface);
+    pixman_image_unref(surface);
 }
 
 void gdi_canvas_draw_blackness(GdiCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, SpiceBlackness *blackness)
@@ -1352,16 +1352,16 @@ void gdi_canvas_draw_whiteness(GdiCanvas *canvas, SpiceRect *bbox, SpiceClip *cl
 
 void gdi_canvas_draw_rop3(GdiCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, SpiceRop3 *rop3)
 {
-    cairo_surface_t *surface;
+    pixman_image_t *surface;
     GdiImage image;
     struct BitmapData bitmapmask;
     HBRUSH prev_hbrush;
     HBRUSH hbrush;
-    BitmapCache *bitmap_cache;
+    PixmanData *pixman_data;
 
     hbrush = get_brush(canvas, &rop3->brush);
     surface = canvas_get_image(&canvas->base, rop3->src_bitmap);
-    bitmap_cache = (BitmapCache *)cairo_surface_get_user_data(surface, &bitmap_data_type);
+    pixman_data = (PixmanData *)pixman_image_get_destroy_data(surface);
     bitmapmask = get_mask_bitmap(canvas, &rop3->mask);
 
     Lock lock(*canvas->lock);
@@ -1369,17 +1369,17 @@ void gdi_canvas_draw_rop3(GdiCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, S
     set_clip(canvas, clip);
     prev_hbrush = set_brush(canvas->dc, hbrush, &rop3->brush);
 
-    if (bitmap_cache && (WaitForSingleObject(bitmap_cache->mutex, INFINITE) != WAIT_FAILED)) {
+    if (pixman_data && (WaitForSingleObject(pixman_data->mutex, INFINITE) != WAIT_FAILED)) {
         HDC dc;
         HBITMAP prev_bitmap;
 
         dc = create_compatible_dc();
-        prev_bitmap = (HBITMAP)SelectObject(dc, bitmap_cache->bitmap);
+        prev_bitmap = (HBITMAP)SelectObject(dc, pixman_data->bitmap);
         gdi_draw_bitmap(canvas->dc, &rop3->src_area, bbox, dc,
                         &bitmapmask, rop3->rop3);
         SelectObject(dc, prev_bitmap);
         DeleteObject(dc);
-        ReleaseMutex(bitmap_cache->mutex);
+        ReleaseMutex(pixman_data->mutex);
     } else {
         surface_to_image(surface, &image);
         gdi_draw_image_rop3(canvas->dc, &rop3->src_area, bbox, image.pixels,
@@ -1389,7 +1389,7 @@ void gdi_canvas_draw_rop3(GdiCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, S
     unset_brush(canvas->dc, prev_hbrush);
     free_mask(&bitmapmask);
 
-    cairo_surface_destroy(surface);
+    pixman_image_unref(surface);
 }
 
 void gdi_canvas_copy_bits(GdiCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, SpicePoint *src_pos)
@@ -1516,7 +1516,7 @@ void gdi_canvas_draw_stroke(GdiCanvas *canvas, SpiceRect *bbox, SpiceClip *clip,
     int ps_join = 0;
     int line_cap = 0;
     uint32_t *user_style = NULL;
-    cairo_surface_t *surface = NULL;
+    pixman_image_t *surface = NULL;
 
     if (stroke->brush.type == SPICE_BRUSH_TYPE_PATTERN) {
         surface = canvas_get_image(&canvas->base, stroke->brush.u.pattern.pat);
@@ -1629,7 +1629,7 @@ void gdi_canvas_draw_stroke(GdiCanvas *canvas, SpiceRect *bbox, SpiceClip *clip,
         logbrush.lbStyle = BS_DIBPATTERN | DIB_RGB_COLORS;
         logbrush.lbColor = 0;
 #endif
-        cairo_surface_destroy(surface);
+        pixman_image_unref(surface);
     }
 
 #if 0
diff --git a/common/gdi_canvas.h b/common/gdi_canvas.h
index 36aae59..12e6f2c 100644
--- a/common/gdi_canvas.h
+++ b/common/gdi_canvas.h
@@ -21,7 +21,7 @@
 #include <stdint.h>
 
 #include <spice/draw.h>
-#include "cairo.h"
+#include "pixman_utils.h"
 #include "canvas_base.h"
 #include "region.h"
 
diff --git a/common/gl_canvas.c b/common/gl_canvas.c
index d7f2889..559566b 100644
--- a/common/gl_canvas.c
+++ b/common/gl_canvas.c
@@ -70,8 +70,8 @@ static inline uint8_t *copy_opposite_image(GLCanvas *canvas, void *data, int str
     return (uint8_t *)canvas->private_data;
 }
 
-static cairo_surface_t *canvas_surf_to_trans_surf(GLCImage *image,
-                                                  uint32_t trans_color)
+static pixman_image_t *canvas_surf_to_trans_surf(GLCImage *image,
+						 uint32_t trans_color)
 {
     int width = image->width;
     int height = image->height;
@@ -80,21 +80,20 @@ static cairo_surface_t *canvas_surf_to_trans_surf(GLCImage *image,
     int src_stride;
     uint8_t *dest_line;
     int dest_stride;
-    cairo_surface_t *ret;
+    pixman_image_t *ret;
     int i;
 
-    ret = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
-    if (cairo_surface_status(ret) != CAIRO_STATUS_SUCCESS) {
-        CANVAS_ERROR("create surface failed, %s",
-                     cairo_status_to_string(cairo_surface_status(ret)));
+    ret = pixman_image_create_bits(PIXMAN_a8r8g8b8, width, height, NULL, 0);
+    if (ret == NULL) {
+        CANVAS_ERROR("create surface failed");
     }
 
     src_line = image->pixels;
     src_stride = image->stride;
     end_src_line = src_line + src_stride * height;
 
-    dest_line = cairo_image_surface_get_data(ret);
-    dest_stride = cairo_image_surface_get_stride(ret);
+    dest_line = (uint8_t *)pixman_image_get_data(ret);
+    dest_stride = pixman_image_get_stride(ret);
 
     for (; src_line < end_src_line; src_line += src_stride, dest_line += dest_stride) {
         for (i = 0; i < width; i++) {
@@ -208,32 +207,32 @@ static void set_clip(GLCanvas *canvas, SpiceRect *bbox, SpiceClip *clip)
 
 static void set_mask(GLCanvas *canvas, SpiceQMask *mask, int x, int y)
 {
-    cairo_surface_t *surface;
+    pixman_image_t *image;
 
-    if (!(surface = canvas_get_mask(&canvas->base, mask))) {
+    if (!(image = canvas_get_mask(&canvas->base, mask))) {
         glc_clear_mask(canvas->glc, GLC_MASK_A);
         return;
     }
 
 
     glc_set_mask(canvas->glc, x - mask->pos.x, y - mask->pos.y,
-                 cairo_image_surface_get_width(surface),
-                 cairo_image_surface_get_height(surface),
-                 cairo_image_surface_get_stride(surface),
-                 cairo_image_surface_get_data(surface), GLC_MASK_A);
+                 pixman_image_get_width(image),
+                 pixman_image_get_height(image),
+                 pixman_image_get_stride(image),
+                 (uint8_t *)pixman_image_get_data(image), GLC_MASK_A);
 }
 
-static inline void surface_to_image(GLCanvas *canvas, cairo_surface_t *surface, GLCImage *image,
+static inline void surface_to_image(GLCanvas *canvas, pixman_image_t *surface, GLCImage *image,
                                     int ignore_stride)
 {
-    cairo_format_t format = cairo_image_surface_get_format(surface);
+    int depth = pixman_image_get_depth(surface);
 
-    ASSERT(format == CAIRO_FORMAT_ARGB32 || format == CAIRO_FORMAT_RGB24);
-    image->format = (format == CAIRO_FORMAT_RGB24) ? GLC_IMAGE_RGB32 : GLC_IMAGE_ARGB32;
-    image->width = cairo_image_surface_get_width(surface);
-    image->height = cairo_image_surface_get_height(surface);
-    image->stride = cairo_image_surface_get_stride(surface);
-    image->pixels = cairo_image_surface_get_data(surface);
+    ASSERT(depth == 32 || depth == 24);
+    image->format = (depth == 24) ? GLC_IMAGE_RGB32 : GLC_IMAGE_ARGB32;
+    image->width = pixman_image_get_width(surface);
+    image->height = pixman_image_get_height(surface);
+    image->stride = pixman_image_get_stride(surface);
+    image->pixels = (uint8_t *)pixman_image_get_data(surface);
     image->pallet = NULL;
     if (ignore_stride) {
         return;
@@ -264,7 +263,7 @@ static void set_brush(GLCanvas *canvas, SpiceBrush *brush)
     case SPICE_BRUSH_TYPE_PATTERN: {
         GLCImage image;
         GLCPattern pattern;
-        cairo_surface_t *surface;
+        pixman_image_t *surface;
 
         surface = canvas_get_image(&canvas->base, brush->u.pattern.pat);
         surface_to_image(canvas, surface, &image, 0);
@@ -274,6 +273,7 @@ static void set_brush(GLCanvas *canvas, SpiceBrush *brush)
 
         glc_set_pattern(canvas->glc, pattern);
         glc_pattern_destroy(pattern);
+        pixman_image_unref (surface);
     }
     case SPICE_BRUSH_TYPE_NONE:
         return;
@@ -357,7 +357,7 @@ void gl_canvas_draw_fill(GLCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, Spi
 
 void gl_canvas_draw_copy(GLCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, SpiceCopy *copy)
 {
-    cairo_surface_t *surface;
+    pixman_image_t *surface;
     GLCRecti src;
     GLCRecti dest;
     GLCImage image;
@@ -373,13 +373,13 @@ void gl_canvas_draw_copy(GLCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, Spi
     SET_GLC_RECT(&src, &copy->src_area);
     glc_draw_image(canvas->glc, &dest, &src, &image, 0, 1);
 
-    cairo_surface_destroy(surface);
+    pixman_image_unref(surface);
     glc_flush(canvas->glc);
 }
 
 void gl_canvas_draw_opaque(GLCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, SpiceOpaque *opaque)
 {
-    cairo_surface_t *surface;
+    pixman_image_t *surface;
     GLCRecti src;
     GLCRecti dest;
     GLCRect fill_rect;
@@ -395,7 +395,7 @@ void gl_canvas_draw_opaque(GLCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, S
     SET_GLC_RECT(&dest, bbox);
     SET_GLC_RECT(&src, &opaque->src_area);
     glc_draw_image(canvas->glc, &dest, &src, &image, 0, 1);
-    cairo_surface_destroy(surface);
+    pixman_image_unref(surface);
 
     set_brush(canvas, &opaque->brush);
     set_op(canvas, opaque->rop_decriptor & ~SPICE_ROPD_INVERS_SRC);
@@ -407,7 +407,7 @@ void gl_canvas_draw_opaque(GLCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, S
 
 void gl_canvas_draw_alpha_blend(GLCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, SpiceAlphaBlnd *alpha_blend)
 {
-    cairo_surface_t *surface;
+    pixman_image_t *surface;
     GLCRecti src;
     GLCRecti dest;
     GLCImage image;
@@ -422,13 +422,13 @@ void gl_canvas_draw_alpha_blend(GLCanvas *canvas, SpiceRect *bbox, SpiceClip *cl
     SET_GLC_RECT(&src, &alpha_blend->src_area);
     glc_draw_image(canvas->glc, &dest, &src, &image, 0, (double)alpha_blend->alpha / 0xff);
 
-    cairo_surface_destroy(surface);
+    pixman_image_unref(surface);
     glc_flush(canvas->glc);
 }
 
 void gl_canvas_draw_blend(GLCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, SpiceBlend *blend)
 {
-    cairo_surface_t *surface;
+    pixman_image_t *surface;
     GLCRecti src;
     GLCRecti dest;
     GLCImage image;
@@ -443,14 +443,14 @@ void gl_canvas_draw_blend(GLCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, Sp
     surface_to_image(canvas, surface, &image, 0);
     glc_draw_image(canvas->glc, &dest, &src, &image, 0, 1);
 
-    cairo_surface_destroy(surface);
+    pixman_image_unref(surface);
     glc_flush(canvas->glc);
 }
 
 void gl_canvas_draw_transparent(GLCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, SpiceTransparent *transparent)
 {
-    cairo_surface_t *surface;
-    cairo_surface_t *trans_surf;
+    pixman_image_t *surface;
+    pixman_image_t *trans_surf;
     GLCImage image;
     GLCRecti src;
     GLCRecti dest;
@@ -463,14 +463,14 @@ void gl_canvas_draw_transparent(GLCanvas *canvas, SpiceRect *bbox, SpiceClip *cl
     surface_to_image(canvas, surface, &image, 0);
 
     trans_surf = canvas_surf_to_trans_surf(&image, transparent->true_color);
-    cairo_surface_destroy(surface);
+    pixman_image_unref(surface);
 
     surface_to_image(canvas, trans_surf, &image, 1);
     SET_GLC_RECT(&dest, bbox);
     SET_GLC_RECT(&src, &transparent->src_area);
     glc_draw_image(canvas->glc, &dest, &src, &image, 0, 1);
 
-    cairo_surface_destroy(trans_surf);
+    pixman_image_unref(trans_surf);
     glc_flush(canvas->glc);
 }
 
@@ -502,8 +502,8 @@ void gl_canvas_draw_invers(GLCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, S
 
 void gl_canvas_draw_rop3(GLCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, SpiceRop3 *rop3)
 {
-    cairo_surface_t *d;
-    cairo_surface_t *s;
+    pixman_image_t *d;
+    pixman_image_t *s;
     GLCImage image;
     SpicePoint src_pos;
     uint8_t *data_opp;
@@ -520,34 +520,33 @@ void gl_canvas_draw_rop3(GLCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, Spi
 
     image.pallet = NULL;
 
-    d = cairo_image_surface_create(CAIRO_FORMAT_RGB24, image.width, image.height);
-    if (cairo_surface_status(d) != CAIRO_STATUS_SUCCESS) {
-        CANVAS_ERROR("create surface failed, %s",
-                     cairo_status_to_string(cairo_surface_status(d)));
+    d = pixman_image_create_bits(PIXMAN_x8r8g8b8, image.width, image.height, NULL, 0);
+    if (d == NULL) {
+        CANVAS_ERROR("create surface failed");
     }
-    image.pixels = cairo_image_surface_get_data(d);
-    image.stride = cairo_image_surface_get_stride(d);
+    image.pixels = (uint8_t *)pixman_image_get_data(d);
+    image.stride = pixman_image_get_stride(d);
 
     glc_read_pixels(canvas->glc, bbox->left, bbox->top, &image);
     data_opp = copy_opposite_image(canvas, image.pixels,
-                                   cairo_image_surface_get_stride(d),
-                                   cairo_image_surface_get_height(d));
+                                   image.stride,
+                                   pixman_image_get_height(d));
     memcpy(image.pixels, data_opp,
-           cairo_image_surface_get_stride(d) * cairo_image_surface_get_height(d));
+           image.stride * pixman_image_get_height(d));
 
     s = canvas_get_image(&canvas->base, rop3->src_bitmap);
-    src_stride = cairo_image_surface_get_stride(s);
+    src_stride = pixman_image_get_stride(s);
     if (src_stride > 0) {
-        data_opp = copy_opposite_image(canvas, cairo_image_surface_get_data(s),
-                                       src_stride, cairo_image_surface_get_height(s));
-        memcpy(cairo_image_surface_get_data(s), data_opp,
-               src_stride * cairo_image_surface_get_height(s));
+      data_opp = copy_opposite_image(canvas, (uint8_t *)pixman_image_get_data(s),
+                                       src_stride, pixman_image_get_height(s));
+        memcpy((uint8_t *)pixman_image_get_data(s), data_opp,
+               src_stride * pixman_image_get_height(s));
     }
 
     if (!rect_is_same_size(bbox, &rop3->src_area)) {
-        cairo_surface_t *scaled_s = canvas_scale_surface(s, &rop3->src_area, image.width,
-                                                         image.height, rop3->scale_mode);
-        cairo_surface_destroy(s);
+        pixman_image_t *scaled_s = canvas_scale_surface(s, &rop3->src_area, image.width,
+                                                        image.height, rop3->scale_mode);
+        pixman_image_unref(s);
         s = scaled_s;
         src_pos.x = 0;
         src_pos.y = 0;
@@ -556,49 +555,49 @@ void gl_canvas_draw_rop3(GLCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, Spi
         src_pos.y = rop3->src_area.top;
     }
 
-    if (cairo_image_surface_get_width(s) - src_pos.x < image.width ||
-                                  cairo_image_surface_get_height(s) - src_pos.y < image.height) {
+    if (pixman_image_get_width(s) - src_pos.x < image.width ||
+        pixman_image_get_height(s) - src_pos.y < image.height) {
         CANVAS_ERROR("bad src bitmap size");
     }
 
     if (rop3->brush.type == SPICE_BRUSH_TYPE_PATTERN) {
-        cairo_surface_t *p = canvas_get_image(&canvas->base, rop3->brush.u.pattern.pat);
+        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) % cairo_image_surface_get_width(p);
+        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) % cairo_image_surface_get_height(p);
+        pat_pos.y = (bbox->top - rop3->brush.u.pattern.pos.y) % pixman_image_get_height(p);
 
         //for now (bottom-top)
         if (pat_pos.y < 0) {
-            pat_pos.y = cairo_image_surface_get_height(p) + pat_pos.y;
+            pat_pos.y = pixman_image_get_height(p) + pat_pos.y;
         }
-        pat_pos.y = (image.height + pat_pos.y) % cairo_image_surface_get_height(p);
-        pat_pos.y = cairo_image_surface_get_height(p) - pat_pos.y;
+        pat_pos.y = (image.height + pat_pos.y) % pixman_image_get_height(p);
+        pat_pos.y = pixman_image_get_height(p) - pat_pos.y;
 
         do_rop3_with_pattern(rop3->rop3, d, s, &src_pos, p, &pat_pos);
-        cairo_surface_destroy(p);
+        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);
     }
 
-    cairo_surface_destroy(s);
+    pixman_image_unref(s);
 
     GLCRecti dest;
     GLCRecti src;
     dest.x = bbox->left;
     dest.y = bbox->top;
 
-    image.pixels = copy_opposite_image(canvas, image.pixels, cairo_image_surface_get_stride(d),
-                                       cairo_image_surface_get_height(d));
+    image.pixels = copy_opposite_image(canvas, image.pixels, pixman_image_get_stride(d),
+                                       pixman_image_get_height(d));
 
     src.x = src.y = 0;
     dest.width = src.width = image.width;
     dest.height = src.height = image.height;
     glc_draw_image(canvas->glc, &dest, &src, &image, 0, 1);
-    cairo_surface_destroy(d);
+    pixman_image_unref(d);
 }
 
 void gl_canvas_draw_stroke(GLCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, SpiceStroke *stroke)
@@ -640,34 +639,34 @@ void gl_canvas_draw_text(GLCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, Spi
     set_op(canvas, text->fore_mode);
     if (str->flags & SPICE_STRING_FLAGS_RASTER_A1) {
         SpicePoint pos;
-        cairo_surface_t *mask = canvas_get_str_mask(&canvas->base, str, 1, &pos);
+        pixman_image_t *mask = canvas_get_str_mask(&canvas->base, str, 1, &pos);
         _glc_fill_mask(canvas->glc, pos.x, pos.y,
-                       cairo_image_surface_get_width(mask),
-                       cairo_image_surface_get_height(mask),
-                       cairo_image_surface_get_stride(mask),
-                       cairo_image_surface_get_data(mask));
-        cairo_surface_destroy(mask);
+                       pixman_image_get_width(mask),
+                       pixman_image_get_height(mask),
+                       pixman_image_get_stride(mask),
+                       (uint8_t *)pixman_image_get_data(mask));
+        pixman_image_unref(mask);
     } else if (str->flags & SPICE_STRING_FLAGS_RASTER_A4) {
         SpicePoint pos;
-        cairo_surface_t *mask = canvas_get_str_mask(&canvas->base, str, 4, &pos);
+        pixman_image_t *mask = canvas_get_str_mask(&canvas->base, str, 4, &pos);
         glc_fill_alpha(canvas->glc, pos.x, pos.y,
-                       cairo_image_surface_get_width(mask),
-                       cairo_image_surface_get_height(mask),
-                       cairo_image_surface_get_stride(mask),
-                       cairo_image_surface_get_data(mask));
+                       pixman_image_get_width(mask),
+                       pixman_image_get_height(mask),
+                       pixman_image_get_stride(mask),
+                       (uint8_t *)pixman_image_get_data(mask));
 
-        cairo_surface_destroy(mask);
+        pixman_image_unref(mask);
     } else if (str->flags & SPICE_STRING_FLAGS_RASTER_A8) {
         WARN("untested path A8 glyphs, doing nothing");
         if (0) {
             SpicePoint pos;
-            cairo_surface_t *mask = canvas_get_str_mask(&canvas->base, str, 8, &pos);
+            pixman_image_t *mask = canvas_get_str_mask(&canvas->base, str, 8, &pos);
             glc_fill_alpha(canvas->glc, pos.x, pos.y,
-                           cairo_image_surface_get_width(mask),
-                           cairo_image_surface_get_height(mask),
-                           cairo_image_surface_get_stride(mask),
-                           cairo_image_surface_get_data(mask));
-            cairo_surface_destroy(mask);
+                           pixman_image_get_width(mask),
+                           pixman_image_get_height(mask),
+                           pixman_image_get_stride(mask),
+                           (uint8_t *)pixman_image_get_data(mask));
+            pixman_image_unref(mask);
         }
     } else {
         WARN("untested path vector glyphs, doing nothing");
diff --git a/common/rop3.c b/common/rop3.c
index 6d2efa2..1afb3d7 100644
--- a/common/rop3.c
+++ b/common/rop3.c
@@ -23,11 +23,11 @@
 #define WARN(x) printf("warning: %s\n", x)
 #endif
 
-typedef void (*rop3_with_pattern_handler_t)(cairo_surface_t *d, cairo_surface_t *s,
-                                            SpicePoint *src_pos, cairo_surface_t *p,
+typedef void (*rop3_with_pattern_handler_t)(pixman_image_t *d, pixman_image_t *s,
+                                            SpicePoint *src_pos, pixman_image_t *p,
                                             SpicePoint *pat_pos);
 
-typedef void (*rop3_with_color_handler_t)(cairo_surface_t *d, cairo_surface_t *s,
+typedef void (*rop3_with_color_handler_t)(pixman_image_t *d, pixman_image_t *s,
                                           SpicePoint *src_pos, uint32_t rgb);
 
 typedef void (*rop3_test_handler_t)();
@@ -39,14 +39,14 @@ static rop3_with_color_handler_t rop3_with_color_handlers[ROP3_NUM_OPS];
 static rop3_test_handler_t rop3_test_handlers[ROP3_NUM_OPS];
 
 
-static void default_rop3_with_pattern_handler(cairo_surface_t *d, cairo_surface_t *s,
-                                              SpicePoint *src_pos, cairo_surface_t *p,
+static void default_rop3_with_pattern_handler(pixman_image_t *d, pixman_image_t *s,
+                                              SpicePoint *src_pos, pixman_image_t *p,
                                               SpicePoint *pat_pos)
 {
     WARN("not implemented 0x%x");
 }
 
-static void default_rop3_withe_color_handler(cairo_surface_t *d, cairo_surface_t *s, SpicePoint *src_pos,
+static void default_rop3_withe_color_handler(pixman_image_t *d, pixman_image_t *s, SpicePoint *src_pos,
                                              uint32_t rgb)
 {
     WARN("not implemented 0x%x");
@@ -57,24 +57,24 @@ static void default_rop3_test_handler()
 }
 
 #define ROP3_HANDLERS(name, formula, index)                                                     \
-static void rop3_handle_p_##name(cairo_surface_t *d, cairo_surface_t *s, SpicePoint *src_pos,        \
-                                      cairo_surface_t *p, SpicePoint *pat_pos)                       \
+static void rop3_handle_p_##name(pixman_image_t *d, pixman_image_t *s, SpicePoint *src_pos,     \
+                                      pixman_image_t *p, SpicePoint *pat_pos)                   \
 {                                                                                               \
-    int width = cairo_image_surface_get_width(d);                                               \
-    int height = cairo_image_surface_get_height(d);                                             \
-    uint8_t *dest_line = cairo_image_surface_get_data(d);                                       \
-    int dest_stride = cairo_image_surface_get_stride(d);                                        \
+    int width = pixman_image_get_width(d);                                                      \
+    int height = pixman_image_get_height(d);                                                    \
+    uint8_t *dest_line = (uint8_t *)pixman_image_get_data(d);		                        \
+    int dest_stride = pixman_image_get_stride(d);                                               \
     uint8_t *end_line = dest_line + height * dest_stride;                                       \
                                                                                                 \
-    int pat_width = cairo_image_surface_get_width(p);                                           \
-    int pat_height = cairo_image_surface_get_height(p);                                         \
-    uint8_t *pat_base = cairo_image_surface_get_data(p);                                        \
-    int pat_stride = cairo_image_surface_get_stride(p);                                         \
+    int pat_width = pixman_image_get_width(p);                                                  \
+    int pat_height = pixman_image_get_height(p);                                                \
+    uint8_t *pat_base = (uint8_t *)pixman_image_get_data(p);                                    \
+    int pat_stride = pixman_image_get_stride(p);                                                \
     int pat_v_offset = pat_pos->y;                                                              \
                                                                                                 \
-    int src_stride = cairo_image_surface_get_stride(s);                                         \
+    int src_stride = pixman_image_get_stride(s);                                                \
     uint8_t *src_line;                                                                          \
-    src_line = cairo_image_surface_get_data(s) + src_pos->y * src_stride + (src_pos->x << 2);   \
+    src_line = (uint8_t *)pixman_image_get_data(s) + src_pos->y * src_stride + (src_pos->x << 2); \
                                                                                                 \
     for (; dest_line < end_line; dest_line += dest_stride, src_line += src_stride) {            \
         uint32_t *dest = (uint32_t *)dest_line;                                                 \
@@ -94,19 +94,19 @@ static void rop3_handle_p_##name(cairo_surface_t *d, cairo_surface_t *s, SpicePo
     }                                                                                           \
 }                                                                                               \
                                                                                                 \
-static void rop3_handle_c_##name(cairo_surface_t *d, cairo_surface_t *s, SpicePoint *src_pos,        \
+static void rop3_handle_c_##name(pixman_image_t *d, pixman_image_t *s, SpicePoint *src_pos,     \
                                    uint32_t rgb)                                                \
 {                                                                                               \
-    int width = cairo_image_surface_get_width(d);                                               \
-    int height = cairo_image_surface_get_height(d);                                             \
-    uint8_t *dest_line = cairo_image_surface_get_data(d);                                       \
-    int dest_stride = cairo_image_surface_get_stride(d);                                        \
+    int width = pixman_image_get_width(d);                                                      \
+    int height = pixman_image_get_height(d);                                                    \
+    uint8_t *dest_line = (uint8_t *)pixman_image_get_data(d);                                   \
+    int dest_stride = pixman_image_get_stride(d);                                               \
     uint8_t *end_line = dest_line + height * dest_stride;                                       \
     uint32_t *pat = &rgb;                                                                       \
                                                                                                 \
-    int src_stride = cairo_image_surface_get_stride(s);                                         \
+    int src_stride = pixman_image_get_stride(s);                                                \
     uint8_t *src_line;                                                                          \
-    src_line = cairo_image_surface_get_data(s) + src_pos->y * src_stride + (src_pos->x << 2);   \
+    src_line = (uint8_t *)pixman_image_get_data(s) + src_pos->y * src_stride + (src_pos->x << 2); \
                                                                                                 \
     for (; dest_line < end_line; dest_line += dest_stride, src_line += src_stride) {            \
         uint32_t *dest = (uint32_t *)dest_line;                                                 \
@@ -599,13 +599,13 @@ void rop3_init()
     }
 }
 
-void do_rop3_with_pattern(uint8_t rop3, cairo_surface_t *d, cairo_surface_t *s, SpicePoint *src_pos,
-                          cairo_surface_t *p, SpicePoint *pat_pos)
+void do_rop3_with_pattern(uint8_t rop3, pixman_image_t *d, pixman_image_t *s, SpicePoint *src_pos,
+                          pixman_image_t *p, SpicePoint *pat_pos)
 {
     rop3_with_pattern_handlers[rop3](d, s, src_pos, p, pat_pos);
 }
 
-void do_rop3_with_color(uint8_t rop3, cairo_surface_t *d, cairo_surface_t *s, SpicePoint *src_pos,
+void do_rop3_with_color(uint8_t rop3, pixman_image_t *d, pixman_image_t *s, SpicePoint *src_pos,
                         uint32_t rgb)
 {
     rop3_with_color_handlers[rop3](d, s, src_pos, rgb);
diff --git a/common/rop3.h b/common/rop3.h
index 3a24ece..839d3b6 100644
--- a/common/rop3.h
+++ b/common/rop3.h
@@ -21,11 +21,11 @@
 #include <stdint.h>
 
 #include <spice/draw.h>
-#include "cairo.h"
+#include "pixman_utils.h"
 
-void do_rop3_with_pattern(uint8_t rop3, cairo_surface_t *d, cairo_surface_t *s, SpicePoint *src_pos,
-                          cairo_surface_t *p, SpicePoint *pat_pos);
-void do_rop3_with_color(uint8_t rop3, cairo_surface_t *d, cairo_surface_t *s, SpicePoint *src_pos,
+void do_rop3_with_pattern(uint8_t rop3, pixman_image_t *d, pixman_image_t *s, SpicePoint *src_pos,
+                          pixman_image_t *p, SpicePoint *pat_pos);
+void do_rop3_with_color(uint8_t rop3, pixman_image_t *d, pixman_image_t *s, SpicePoint *src_pos,
                         uint32_t rgb);
 
 void rop3_init();
diff --git a/server/red_worker.c b/server/red_worker.c
index 85964ce..b2cb1f6 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -722,7 +722,7 @@ typedef struct ImageCacheItem {
     uint32_t age;
 #endif
     struct ImageCacheItem *next;
-    cairo_surface_t *surf;
+    pixman_image_t *image;
 } ImageCacheItem;
 
 #define IMAGE_CACHE_HASH_SIZE 1024
@@ -3890,7 +3890,7 @@ static void image_cache_remove(ImageCache *cache, ImageCacheItem *item)
         now = &(*now)->next;
     }
     ring_remove(&item->lru_link);
-    cairo_surface_destroy(item->surf);
+    pixman_image_unref(item->image);
     free(item);
 #ifndef IMAGE_CACHE_AGE
     cache->num_items--;
@@ -3899,7 +3899,7 @@ static void image_cache_remove(ImageCache *cache, ImageCacheItem *item)
 
 #define IMAGE_CACHE_MAX_ITEMS 2
 
-static void image_cache_put(SpiceImageCache *spice_cache, uint64_t id, cairo_surface_t *surface)
+static void image_cache_put(SpiceImageCache *spice_cache, uint64_t id, pixman_image_t *image)
 {
     ImageCache *cache = (ImageCache *)spice_cache;
     ImageCacheItem *item;
@@ -3921,7 +3921,7 @@ static void image_cache_put(SpiceImageCache *spice_cache, uint64_t id, cairo_sur
 #else
     cache->num_items++;
 #endif
-    item->surf = cairo_surface_reference(surface);
+    item->image = pixman_image_ref(image);
     ring_item_init(&item->lru_link);
 
     item->next = cache->hash_table[item->id % IMAGE_CACHE_HASH_SIZE];
@@ -3930,7 +3930,7 @@ static void image_cache_put(SpiceImageCache *spice_cache, uint64_t id, cairo_sur
     ring_add(&cache->lru, &item->lru_link);
 }
 
-static cairo_surface_t *image_cache_get(SpiceImageCache *spice_cache, uint64_t id)
+static pixman_image_t *image_cache_get(SpiceImageCache *spice_cache, uint64_t id)
 {
     ImageCache *cache = (ImageCache *)spice_cache;
 
@@ -3938,7 +3938,7 @@ static cairo_surface_t *image_cache_get(SpiceImageCache *spice_cache, uint64_t i
     if (!item) {
         red_error("not found");
     }
-    return cairo_surface_reference(item->surf);
+    return pixman_image_ref(item->image);
 }
 
 static void image_cache_init(ImageCache *cache)
-- 
1.6.6



More information about the Spice-devel mailing list