[cairo-commit] 2 commits - build/Makefile.am.changelog configure.ac perf/Makefile.am src/cairo-arc-private.h src/cairo-backend-private.h src/cairo-clip-private.h src/cairo-composite-rectangles-private.h src/cairo-debug.c src/cairo-error-private.h src/cairo-freed-pool-private.h src/cairo-ft-font.c src/cairo-gl-composite.c src/cairo-gl-glyphs.c src/cairo-gl-surface.c src/cairo-image-surface.c src/cairoint.h src/cairo-paginated-surface.c src/cairo-pattern.c src/cairo-pdf-surface.c src/cairo-png.c src/cairo-ps-surface.c src/cairo-recording-surface.c src/cairo-scaled-font.c src/cairo-script-surface.c src/cairo-skia.h src/cairo-surface.c src/cairo-surface-fallback.c src/cairo-surface-snapshot.c src/cairo-surface-subsurface.c src/cairo-svg-surface.c src/cairo-type3-glyph-surface.c src/cairo-types-private.h src/cairo-xcb-private.h src/cairo-xcb-surface.c src/cairo-xcb-surface-core.c src/cairo-xcb-surface-render.c src/cairo-xlib-surface.c src/cairo-xlib-xcb-surface.c src/Makefile.sources sr c/skia test/Makefile.am

Chris Wilson ickle at kemper.freedesktop.org
Sat Aug 13 01:59:14 PDT 2011


 build/Makefile.am.changelog              |    2 
 configure.ac                             |   15 
 perf/Makefile.am                         |    5 
 src/Makefile.sources                     |    6 
 src/cairo-arc-private.h                  |    4 
 src/cairo-backend-private.h              |    1 
 src/cairo-clip-private.h                 |    1 
 src/cairo-composite-rectangles-private.h |    2 
 src/cairo-debug.c                        |    1 
 src/cairo-error-private.h                |    8 
 src/cairo-freed-pool-private.h           |    4 
 src/cairo-ft-font.c                      |    1 
 src/cairo-gl-composite.c                 |    4 
 src/cairo-gl-glyphs.c                    |    1 
 src/cairo-gl-surface.c                   |    4 
 src/cairo-image-surface.c                |   47 
 src/cairo-paginated-surface.c            |    1 
 src/cairo-pattern.c                      |    1 
 src/cairo-pdf-surface.c                  |    1 
 src/cairo-png.c                          |    1 
 src/cairo-ps-surface.c                   |    1 
 src/cairo-recording-surface.c            |    1 
 src/cairo-scaled-font.c                  |    1 
 src/cairo-script-surface.c               |    1 
 src/cairo-skia.h                         |   18 
 src/cairo-surface-fallback.c             |    1 
 src/cairo-surface-snapshot.c             |    1 
 src/cairo-surface-subsurface.c           |    1 
 src/cairo-surface.c                      |    1 
 src/cairo-svg-surface.c                  |    1 
 src/cairo-type3-glyph-surface.c          |    1 
 src/cairo-types-private.h                |   11 
 src/cairo-xcb-private.h                  |    2 
 src/cairo-xcb-surface-core.c             |    1 
 src/cairo-xcb-surface-render.c           |    1 
 src/cairo-xcb-surface.c                  |   98 -
 src/cairo-xlib-surface.c                 |    1 
 src/cairo-xlib-xcb-surface.c             |    1 
 src/cairoint.h                           |   29 
 src/skia/cairo-skia-context.cpp          | 1740 +++++++++++++++++++++++++++++++
 src/skia/cairo-skia-private.h            |  110 +
 src/skia/cairo-skia-surface.cpp          |  525 +++++++++
 test/Makefile.am                         |    4 
 43 files changed, 2529 insertions(+), 132 deletions(-)

New commits:
commit 1ccd269a3f33684bfbedcd94ad9bca56b1404143
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Sat Apr 24 00:50:33 2010 +0100

    skia: Update to use cairo_backend_t interface
    
    Still hopelessly broken. Requires compiling cairo to use static linking
    and then still requires manual linkage to workaround libtool. Lots of
    functionality is still absent - we need to either find analogues to some
    Cairo operations or implement fallbacks - but it is sufficient to
    investigate how Skia functions in direct comparison with Cairo for
    tessellation/rasterisation.
    
    Caveat emptor.
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/build/Makefile.am.changelog b/build/Makefile.am.changelog
index 07e6036..861e531 100644
--- a/build/Makefile.am.changelog
+++ b/build/Makefile.am.changelog
@@ -54,7 +54,7 @@ DISTCLEANFILES += ChangeLog.cache-*
 
 ChangeLog.cache-*..: .git
 
-ChangeLog%: $(srcdir)/ChangeLog%
+#ChangeLog%: $(srcdir)/ChangeLog%
 
 $(srcdir)/ChangeLog.cache-% $(srcdir)/ChangeLog.pre-%:
 	@echo Creating $@
diff --git a/configure.ac b/configure.ac
index 8e6bc4d..0782baf 100644
--- a/configure.ac
+++ b/configure.ac
@@ -9,7 +9,8 @@ AC_GNU_SOURCE
 AC_USE_SYSTEM_EXTENSIONS
 AC_CONFIG_SRCDIR(src/cairo.h)
 AC_CONFIG_HEADERS(config.h)
-AM_INIT_AUTOMAKE([1.9.6 gnu -Wall no-define])
+#AM_INIT_AUTOMAKE([1.9.6 gnu -Wall no-define])
+AM_INIT_AUTOMAKE([1.9.6])
 m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
 AC_LIBTOOL_WIN32_DLL dnl Must be called before AC_PROG_LIBTOOL
 AC_PROG_LIBTOOL dnl ([1.4]) Don't remove!
@@ -199,9 +200,17 @@ CAIRO_ENABLE_SURFACE_BACKEND(skia, Skia, no, [
 	      [AS_HELP_STRING([--with-skia=/path/to/skia],
 			      [directory to find compiled skia sources])],
 	      [skia_DIR="$withval"],
-	      [skia_DIR="`pwd`/../mesa"])
+	      [skia_DIR="`pwd`/../skia"])
+  AC_ARG_WITH([skia-bulid],
+	      [AS_HELP_STRING([--with-skia-build=(Release|Debug)]
+			      [build of skia to link with, default is Relese])],
+	      [skia_BUILD="$withval"],
+	      [skia_BUILD="Release"])
   skia_NONPKGCONFIG_CFLAGS="-I$skia_DIR/include/config -I$skia_DIR/include/core -I$skia_DIR/include/effects"
-  skia_NONPKGCONFIG_LIBS="$skia_DIR/out/libskia.a"
+  if test "x$(skia_BUILD)" = x"Relese"; then
+  	skia_NONPKGCONFIG_CFLAGS="-DSK_RELEASE -DSK_CAN_USE_FLOAT $skia_NONPKGCONFIG_CFLAGS"
+  fi
+  skia_NONPKGCONFIG_LIBS="--start-group $skia_DIR/out/$skia_BUILD/obj.target/gyp/libeffects.a $skia_DIR/out/$skia_BUILD/obj.target/gyp/libimages.a $skia_DIR/out/$skia_BUILD/obj.target/gyp/libutils.a $skia_DIR/out/$skia_BUILD/obj.target/gyp/libopts.a $skia_DIR/out/$skia_BUILD/obj.target/gyp/libcore.a -end-group"
   AC_SUBST(skia_DIR)
 ])
 
diff --git a/perf/Makefile.am b/perf/Makefile.am
index d41891f..f3eb734 100644
--- a/perf/Makefile.am
+++ b/perf/Makefile.am
@@ -43,12 +43,13 @@ libcairoperf_la_SOURCES = \
 	$(libcairoperf_headers)
 libcairoperf_la_LIBADD = $(CAIROPERF_LIBS)
 
-cairo_perf_trace_SOURCES = \
+cairo_perf_trace_SOURCES = a.cpp \
 	$(cairo_perf_trace_sources)	\
 	$(cairo_perf_trace_external_sources)
 cairo_perf_trace_LDADD =		\
 	$(top_builddir)/util/cairo-script/libcairo-script-interpreter.la \
-	$(LDADD)
+	$(LDADD) $(CAIRO_LIBS)
+skia = -Wl,--start-group @skia_DIR@/out/Debug/obj.target/gyp/libeffects.a @skia_DIR@/out/Debug/obj.target/gyp/libimages.a @skia_DIR@/out/Debug/obj.target/gyp/libutils.a @skia_DIR@/out/Debug/obj.target/gyp/libopts.a @skia_DIR@/out/Debug/obj.target/gyp/libcore.a -Wl,--end-group
 cairo_perf_trace_DEPENDENCIES = \
 	$(top_builddir)/util/cairo-script/libcairo-script-interpreter.la \
 	$(LDADD)
diff --git a/src/Makefile.sources b/src/Makefile.sources
index 2af733e..5b116c6 100644
--- a/src/Makefile.sources
+++ b/src/Makefile.sources
@@ -306,7 +306,10 @@ cairo_win32_sources = cairo-win32-surface.c cairo-win32-printing-surface.c
 cairo_win32_font_sources = cairo-win32-font.c
 
 cairo_skia_headers = cairo-skia.h
-cairo_skia_cxx_sources = cairo-skia-surface.cpp
+cairo_skia_cxx_sources = \
+	skia/cairo-skia-context.cpp \
+	skia/cairo-skia-surface.cpp \
+	$(NULL)
 
 cairo_os2_headers = cairo-os2.h
 cairo_os2_private = cairo-os2-private.h
diff --git a/src/cairo-arc-private.h b/src/cairo-arc-private.h
index 018a14b..a22c01a 100644
--- a/src/cairo-arc-private.h
+++ b/src/cairo-arc-private.h
@@ -38,6 +38,8 @@
 
 #include "cairoint.h"
 
+CAIRO_BEGIN_DECLS
+
 cairo_private void
 _cairo_arc_path (cairo_t *cr,
 		 double	  xc,
@@ -54,4 +56,6 @@ _cairo_arc_path_negative (cairo_t *cr,
 			  double   angle1,
 			  double   angle2);
 
+CAIRO_END_DECLS
+
 #endif /* CAIRO_ARC_PRIVATE_H */
diff --git a/src/cairo-backend-private.h b/src/cairo-backend-private.h
index e09b436..1dd5ea0 100644
--- a/src/cairo-backend-private.h
+++ b/src/cairo-backend-private.h
@@ -40,6 +40,7 @@
 
 typedef enum _cairo_backend_type {
     CAIRO_TYPE_DEFAULT,
+    CAIRO_TYPE_SKIA,
 } cairo_backend_type_t;
 
 struct _cairo_backend {
diff --git a/src/cairo-clip-private.h b/src/cairo-clip-private.h
index 5302471..f2cfd63 100644
--- a/src/cairo-clip-private.h
+++ b/src/cairo-clip-private.h
@@ -41,6 +41,7 @@
 
 #include "cairo-boxes-private.h"
 #include "cairo-compiler-private.h"
+#include "cairo-error-private.h"
 #include "cairo-path-fixed-private.h"
 #include "cairo-reference-count-private.h"
 
diff --git a/src/cairo-composite-rectangles-private.h b/src/cairo-composite-rectangles-private.h
index 777279b..c6dac30 100644
--- a/src/cairo-composite-rectangles-private.h
+++ b/src/cairo-composite-rectangles-private.h
@@ -111,4 +111,6 @@ _cairo_composite_rectangles_intersect_mask_extents (cairo_composite_rectangles_t
 cairo_private void
 _cairo_composite_rectangles_fini (cairo_composite_rectangles_t *extents);
 
+CAIRO_END_DECLS
+
 #endif /* CAIRO_COMPOSITE_RECTANGLES_PRIVATE_H */
diff --git a/src/cairo-error-private.h b/src/cairo-error-private.h
index 1c82ae6..a548a35 100644
--- a/src/cairo-error-private.h
+++ b/src/cairo-error-private.h
@@ -46,6 +46,10 @@
 
 CAIRO_BEGIN_DECLS
 
+/* Sure wish C had a real enum type so that this would be distinct
+ * from #cairo_status_t. Oh well, without that, I'll use this bogus 100
+ * offset.  We want to keep it fit in int8_t as the compiler may choose
+ * that for #cairo_status_t */
 enum _cairo_int_status {
     CAIRO_INT_STATUS_SUCCESS = 0,
 
@@ -97,6 +101,8 @@ enum _cairo_int_status {
     CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN,
 };
 
+typedef enum _cairo_int_status cairo_int_status_t;
+
 #define _cairo_status_is_error(status) \
     (status != CAIRO_STATUS_SUCCESS && status < CAIRO_STATUS_LAST_STATUS)
 
@@ -107,7 +113,7 @@ static inline cairo_status_t
 _cairo_public_status (cairo_int_status_t status)
 {
     assert (status <= CAIRO_INT_STATUS_LAST_STATUS);
-    return status;
+    return (cairo_status_t) status;
 }
 
 cairo_private cairo_status_t
diff --git a/src/cairo-freed-pool-private.h b/src/cairo-freed-pool-private.h
index c3267ef..259c57d 100644
--- a/src/cairo-freed-pool-private.h
+++ b/src/cairo-freed-pool-private.h
@@ -40,6 +40,8 @@
 #include "cairoint.h"
 #include "cairo-atomic-private.h"
 
+CAIRO_BEGIN_DECLS
+
 #if HAS_ATOMIC_OPS
 /* Keep a stash of recently freed clip_paths, since we need to
  * reallocate them frequently.
@@ -130,4 +132,6 @@ typedef int freed_pool_t;
 
 #endif
 
+CAIRO_END_DECLS
+
 #endif /* CAIRO_FREED_POOL_PRIVATE_H */
diff --git a/src/cairo-skia.h b/src/cairo-skia.h
index f628235..99b9286 100644
--- a/src/cairo-skia.h
+++ b/src/cairo-skia.h
@@ -55,24 +55,6 @@ cairo_skia_surface_create_for_data (unsigned char *data,
 				    int height,
 				    int stride);
 
-cairo_public unsigned char *
-cairo_skia_surface_get_data (cairo_surface_t *surface);
-
-cairo_public cairo_format_t
-cairo_skia_surface_get_format (cairo_surface_t *surface);
-
-cairo_public int
-cairo_skia_surface_get_width (cairo_surface_t *surface);
-
-cairo_public int
-cairo_skia_surface_get_height (cairo_surface_t *surface);
-
-cairo_public int
-cairo_skia_surface_get_stride (cairo_surface_t *surface);
-
-cairo_public cairo_surface_t *
-cairo_skia_surface_get_image (cairo_surface_t *surface);
-
 CAIRO_END_DECLS
 
 #else
diff --git a/src/cairo-types-private.h b/src/cairo-types-private.h
index b1b0db3..4933cf2 100644
--- a/src/cairo-types-private.h
+++ b/src/cairo-types-private.h
@@ -44,6 +44,8 @@
 #include "cairo-list-private.h"
 #include "cairo-reference-count-private.h"
 
+CAIRO_BEGIN_DECLS
+
 /**
  * SECTION:cairo-types
  * @Title: Types
@@ -225,12 +227,6 @@ typedef enum _cairo_paginated_mode {
     CAIRO_PAGINATED_MODE_FALLBACK	/* paint fallback images */
 } cairo_paginated_mode_t;
 
-/* Sure wish C had a real enum type so that this would be distinct
- * from #cairo_status_t. Oh well, without that, I'll use this bogus 100
- * offset.  We want to keep it fit in int8_t as the compiler may choose
- * that for #cairo_status_t */
-typedef enum _cairo_int_status cairo_int_status_t;
-
 typedef enum _cairo_internal_surface_type {
     CAIRO_INTERNAL_SURFACE_TYPE_SNAPSHOT = 0x1000,
     CAIRO_INTERNAL_SURFACE_TYPE_PAGINATED,
@@ -419,4 +415,7 @@ typedef struct _cairo_scaled_glyph {
 
     void		    *surface_private;	/* for the surface backend */
 } cairo_scaled_glyph_t;
+
+CAIRO_END_DECLS
+
 #endif /* CAIRO_TYPES_PRIVATE_H */
diff --git a/src/cairoint.h b/src/cairoint.h
index 4c9d9c0..86688a2 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -71,6 +71,7 @@
 #include <pixman.h>
 
 #include "cairo-compiler-private.h"
+#include "cairo-error-private.h"
 
 #if CAIRO_HAS_PS_SURFACE || CAIRO_HAS_SCRIPT_SURFACE || CAIRO_HAS_XML_SURFACE
 #define CAIRO_HAS_DEFLATE_STREAM 1
diff --git a/src/skia/cairo-skia-context.cpp b/src/skia/cairo-skia-context.cpp
new file mode 100644
index 0000000..828f6e5
--- /dev/null
+++ b/src/skia/cairo-skia-context.cpp
@@ -0,0 +1,1740 @@
+/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2002 University of Southern California
+ * Copyright © 2005 Red Hat, Inc.
+ * Copyright © 2010 Intel Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is University of Southern
+ * California.
+ *
+ * Contributor(s):
+ *	Carl D. Worth <cworth at cworth.org>
+ *	Chris Wilson <chris at chris-wilson.co.uk>
+ */
+
+#include "cairoint.h"
+
+#include "cairo-private.h"
+#include "cairo-error-private.h"
+#include "cairo-arc-private.h"
+#include "cairo-backend-private.h"
+#include "cairo-default-context-private.h"
+#include "cairo-freed-pool-private.h"
+#include "cairo-gstate-private.h"
+#include "cairo-path-private.h"
+#include "cairo-pattern-private.h"
+#include "cairo-skia-private.h"
+
+#include <SkShader.h>
+#include <SkColorShader.h>
+#include <SkGradientShader.h>
+#include <SkDashPathEffect.h>
+
+#if !defined(INFINITY)
+#define INFINITY HUGE_VAL
+#endif
+
+#if (CAIRO_FIXED_BITS == 32) && (CAIRO_FIXED_FRAC_BITS == 16) && defined(SK_SCALAR_IS_FIXED)
+# define CAIRO_FIXED_TO_SK_SCALAR(x)  (x)
+#elif defined(SK_SCALAR_IS_FIXED)
+/* This can be done better, but this will do for now */
+# define CAIRO_FIXED_TO_SK_SCALAR(x)  SkFloatToScalar(_cairo_fixed_to_double(x))
+#else
+# define CAIRO_FIXED_TO_SK_SCALAR(x)  SkFloatToScalar(_cairo_fixed_to_double(x))
+#endif
+
+#define UNSUPPORTED
+
+
+static freed_pool_t context_pool;
+
+static void
+_cairo_skia_context_destroy (void *abstract_cr)
+{
+    cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
+
+    cr->path->reset ();
+    cr->paint->reset ();
+
+    delete cr->canvas;
+
+    cairo_surface_destroy (&cr->target->image.base);
+    cairo_surface_destroy (&cr->original->image.base);
+
+    if (cr->source != NULL) {
+	if (cr->source_image != NULL) {
+	    _cairo_surface_release_source_image (cr->source, cr->source_image, cr->source_extra);
+	    cr->source_image = NULL;
+	}
+	cairo_surface_destroy (cr->source);
+	cr->source = NULL;
+    }
+
+    _cairo_fini (&cr->base);
+
+    _freed_pool_put (&context_pool, cr);
+}
+
+static cairo_surface_t *
+_cairo_skia_context_get_original_target (void *abstract_cr)
+{
+    cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
+
+    return &cr->original->image.base;
+}
+
+static cairo_surface_t *
+_cairo_skia_context_get_current_target (void *abstract_cr)
+{
+    cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
+
+    return &cr->target->image.base;
+}
+
+static cairo_status_t
+_cairo_skia_context_save (void *abstract_cr)
+{
+    cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
+
+    cr->canvas->save ();
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_skia_context_restore (void *abstract_cr)
+{
+    cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
+
+    cr->canvas->restore ();
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_skia_context_push_group (void *abstract_cr, cairo_content_t content)
+{
+    cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
+    cairo_surface_t *group_surface;
+    cairo_status_t status;
+    int width, height;
+
+    //clip = _cairo_gstate_get_clip (cr->gstate);
+    width = cr->target->image.width;
+    height = cr->target->image.height;
+    group_surface = cr->target->image.base.backend->create_similar (&cr->target->image.base,
+								    content, width, height);
+
+#if 0
+    /* Set device offsets on the new surface so that logically it appears at
+     * the same location on the parent surface -- when we pop_group this,
+     * the source pattern will get fixed up for the appropriate target surface
+     * device offsets, so we want to set our own surface offsets from /that/,
+     * and not from the device origin. */
+    cairo_surface_set_device_offset (group_surface,
+				     parent_surface->device_transform.x0 - extents.x,
+				     parent_surface->device_transform.y0 - extents.y);
+
+    /* If we have a current path, we need to adjust it to compensate for
+     * the device offset just applied. */
+    _cairo_path_fixed_transform (cr->path,
+				 &group_surface->device_transform);
+#endif
+
+    status = _cairo_skia_context_save (cr);
+    if (unlikely (status)) {
+	cairo_surface_destroy (group_surface);
+	return status;
+    }
+
+    cairo_surface_destroy (&cr->target->image.base);
+    cr->target = (cairo_skia_surface_t *) group_surface;
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_pattern_t *
+_cairo_skia_context_pop_group (void *abstract_cr)
+{
+    cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
+    cairo_surface_t *group_surface;
+    cairo_pattern_t *group_pattern;
+    cairo_status_t status;
+
+    group_surface = cairo_surface_reference (&cr->target->image.base);
+
+    status = _cairo_skia_context_restore (cr);
+    if (unlikely (status)) {
+	group_pattern = _cairo_pattern_create_in_error (status);
+	goto done;
+    }
+
+    group_pattern = cairo_pattern_create_for_surface (group_surface);
+    status = group_pattern->status;
+    if (unlikely (status))
+        goto done;
+
+#if 0
+    _cairo_gstate_get_matrix (cr->gstate, &group_matrix);
+    /* Transform by group_matrix centered around device_transform so that when
+     * we call _cairo_gstate_copy_transformed_pattern the result is a pattern
+     * with a matrix equivalent to the device_transform of group_surface. */
+    if (_cairo_surface_has_device_transform (group_surface)) {
+	cairo_pattern_set_matrix (group_pattern, &group_surface->device_transform);
+	_cairo_pattern_transform (group_pattern, &group_matrix);
+	_cairo_pattern_transform (group_pattern, &group_surface->device_transform_inverse);
+    } else {
+	cairo_pattern_set_matrix (group_pattern, &group_matrix);
+    }
+
+    /* If we have a current path, we need to adjust it to compensate for
+     * the device offset just removed. */
+    _cairo_path_fixed_transform (cr->path,
+				 &group_surface->device_transform_inverse);
+#endif
+
+done:
+    cairo_surface_destroy (group_surface);
+
+    return group_pattern;
+}
+
+static inline cairo_surface_t *
+surface_from_pattern (const cairo_pattern_t *pattern)
+{
+    return (reinterpret_cast <const cairo_surface_pattern_t *> (pattern))->surface;
+}
+
+static inline bool
+surface_to_sk_bitmap (cairo_surface_t *surface, SkBitmap& bitmap)
+{
+    cairo_image_surface_t *img = (cairo_image_surface_t *) surface;
+    SkBitmap::Config config;
+    bool opaque;
+
+    if (unlikely (! format_to_sk_config (img->format, config, opaque)))
+	return false;
+
+    bitmap.reset ();
+    bitmap.setConfig (config, img->width, img->height, img->stride);
+    bitmap.setIsOpaque (opaque);
+    bitmap.setPixels (img->data);
+
+    return true;
+}
+
+static inline SkMatrix
+matrix_to_sk (const cairo_matrix_t& mat)
+{
+    SkMatrix skm;
+
+    skm.reset ();
+    skm.set (SkMatrix::kMScaleX, SkFloatToScalar (mat.xx));
+    skm.set (SkMatrix::kMSkewX,  SkFloatToScalar (mat.xy));
+    skm.set (SkMatrix::kMTransX, SkFloatToScalar (mat.x0));
+    skm.set (SkMatrix::kMSkewY,  SkFloatToScalar (mat.yx));
+    skm.set (SkMatrix::kMScaleY, SkFloatToScalar (mat.yy));
+    skm.set (SkMatrix::kMTransY, SkFloatToScalar (mat.y0));
+
+    /*
+    skm[6] = SkFloatToScalar (0.0);
+    skm[7] = SkFloatToScalar (0.0);
+    skm[8] = SkFloatToScalar (1.0); -- this isn't right, it wants a magic value in there that it'll set itself.  It wants Sk_Fract1 (2.30), not Sk_Scalar1
+    */
+
+    return skm;
+}
+
+static inline SkMatrix
+matrix_inverse_to_sk (const cairo_matrix_t& mat)
+{
+    cairo_matrix_t inv = mat;
+    cairo_status_t status = cairo_matrix_invert (&inv);
+    assert (status == CAIRO_STATUS_SUCCESS);
+    return matrix_to_sk (inv);
+}
+
+static SkShader::TileMode
+extend_to_sk (cairo_extend_t extend)
+{
+    static const SkShader::TileMode modeMap[] = {
+	SkShader::kClamp_TileMode,  // NONE behaves like PAD, because noone wants NONE
+	SkShader::kRepeat_TileMode,
+	SkShader::kMirror_TileMode,
+	SkShader::kClamp_TileMode
+    };
+
+    return modeMap[extend];
+}
+
+static inline SkColor
+color_to_sk (const cairo_color_t& c)
+{
+    /* Need unpremultiplied 1-byte values */
+    return SkColorSetARGB ((U8CPU) (c.alpha * 255),
+			   (U8CPU) (c.red * 255),
+			   (U8CPU) (c.green * 255),
+			   (U8CPU) (c.blue * 255));
+}
+
+static inline SkColor
+color_stop_to_sk (const cairo_color_stop_t& c)
+{
+    /* Need unpremultiplied 1-byte values */
+    return SkColorSetARGB ((U8CPU) (c.alpha * 255),
+			   (U8CPU) (c.red * 255),
+			   (U8CPU) (c.green * 255),
+			   (U8CPU) (c.blue * 255));
+}
+
+static SkShader*
+source_to_sk_shader (cairo_skia_context_t *cr,
+		     const cairo_pattern_t *pattern)
+{
+    SkShader *shader = NULL;
+
+    if (pattern->type == CAIRO_PATTERN_TYPE_SOLID) {
+	cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *) pattern;
+	return new SkColorShader (color_to_sk (solid->color));
+    } else if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
+	cairo_surface_t *surface = surface_from_pattern (pattern);
+
+	cr->source = cairo_surface_reference (surface);
+
+	if (surface->type == CAIRO_SURFACE_TYPE_SKIA) {
+	    cairo_skia_surface_t *esurf = (cairo_skia_surface_t *) surface;
+
+	    shader = SkShader::CreateBitmapShader (*esurf->bitmap,
+						   extend_to_sk (pattern->extend),
+						   extend_to_sk (pattern->extend));
+	} else {
+	    SkBitmap bitmap;
+
+	    if (! _cairo_surface_is_image (surface)) {
+		cairo_status_t status;
+
+		status = _cairo_surface_acquire_source_image (surface,
+							      &cr->source_image,
+							      &cr->source_extra);
+		if (status)
+		    return NULL;
+
+		surface = &cr->source_image->base;
+	    }
+
+	    if (unlikely (! surface_to_sk_bitmap (surface, bitmap)))
+		return NULL;
+
+	    shader = SkShader::CreateBitmapShader (bitmap,
+						   extend_to_sk (pattern->extend),
+						   extend_to_sk (pattern->extend));
+	}
+    } else if (pattern->type == CAIRO_PATTERN_TYPE_LINEAR
+	       /* || pattern->type == CAIRO_PATTERN_TYPE_RADIAL */)
+    {
+	cairo_gradient_pattern_t *gradient = (cairo_gradient_pattern_t *) pattern;
+	SkColor colors_stack[10];
+	SkScalar pos_stack[10];
+	SkColor *colors = colors_stack;
+	SkScalar *pos = pos_stack;
+
+	if (gradient->n_stops > 10) {
+	    colors = new SkColor[gradient->n_stops];
+	    pos = new SkScalar[gradient->n_stops];
+	}
+
+	for (unsigned int i = 0; i < gradient->n_stops; i++) {
+	    pos[i] = CAIRO_FIXED_TO_SK_SCALAR (gradient->stops[i].offset);
+	    colors[i] = color_stop_to_sk (gradient->stops[i].color);
+	}
+
+	if (pattern->type == CAIRO_PATTERN_TYPE_LINEAR) {
+	    cairo_linear_pattern_t *linear = (cairo_linear_pattern_t *) gradient;
+	    SkPoint points[2];
+
+	    points[0].set (SkFloatToScalar (linear->pd1.x),
+			   SkFloatToScalar (linear->pd1.y));
+	    points[1].set (SkFloatToScalar (linear->pd2.x),
+			   SkFloatToScalar (linear->pd2.y));
+	    shader = SkGradientShader::CreateLinear (points, colors, pos, gradient->n_stops,
+						     extend_to_sk (pattern->extend));
+	} else {
+	    // XXX todo -- implement real radial shaders in Skia
+	}
+
+	if (gradient->n_stops > 10) {
+	    delete [] colors;
+	    delete [] pos;
+	}
+    }
+
+    if (shader && ! _cairo_matrix_is_identity (&pattern->matrix))
+	shader->setLocalMatrix (matrix_inverse_to_sk (pattern->matrix));
+
+    return shader;
+}
+
+static inline bool
+pattern_filter_to_sk (const cairo_pattern_t *pattern)
+{
+    switch (pattern->filter) {
+    case CAIRO_FILTER_GOOD:
+    case CAIRO_FILTER_BEST:
+    case CAIRO_FILTER_BILINEAR:
+    case CAIRO_FILTER_GAUSSIAN:
+	return true;
+    default:
+    case CAIRO_FILTER_FAST:
+    case CAIRO_FILTER_NEAREST:
+	return false;
+    }
+}
+
+static inline bool
+pattern_to_sk_color (const cairo_pattern_t *pattern, SkColor& color)
+{
+    if (pattern->type != CAIRO_PATTERN_TYPE_SOLID)
+	return false;
+
+    color = color_to_sk (((cairo_solid_pattern_t *) pattern)->color);
+    return true;
+}
+
+static cairo_status_t
+_cairo_skia_context_set_source (void *abstract_cr,
+				cairo_pattern_t *source)
+{
+    cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
+    SkColor color;
+
+    if (cr->source != NULL) {
+	if (cr->source_image != NULL) {
+	    _cairo_surface_release_source_image (cr->source, cr->source_image, cr->source_extra);
+	    cr->source_image = NULL;
+	}
+	cairo_surface_destroy (cr->source);
+	cr->source = NULL;
+    }
+
+    if (pattern_to_sk_color (source, color)) {
+	cr->paint->setColor (color);
+    } else {
+	SkShader *shader = source_to_sk_shader (cr, source);
+	if (shader == NULL) {
+	    UNSUPPORTED;
+	    return CAIRO_STATUS_SUCCESS;
+	}
+
+	cr->paint->setShader (shader);
+	shader->unref ();
+
+	cr->paint->setFilterBitmap (pattern_filter_to_sk (source));
+    }
+
+    /* XXX change notification */
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_skia_context_set_source_rgba (void *abstract_cr, double red, double green, double blue, double alpha)
+{
+    cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
+
+    /* Need unpremultiplied 1-byte values */
+    cr->paint->setARGB ((U8CPU) (alpha * 255),
+			(U8CPU) (red * 255),
+			(U8CPU) (green * 255),
+			(U8CPU) (blue * 255));
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_skia_context_set_source_surface (void *abstract_cr,
+					cairo_surface_t *surface,
+					double	   x,
+					double	   y)
+{
+    cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
+    cairo_pattern_t *pattern;
+    cairo_matrix_t matrix;
+    cairo_status_t status;
+
+    if (surface->type == CAIRO_SURFACE_TYPE_SKIA) {
+	cairo_skia_surface_t *esurf = (cairo_skia_surface_t *) surface;
+	SkShader *shader;
+
+	shader = SkShader::CreateBitmapShader (*esurf->bitmap,
+					       SkShader::kClamp_TileMode, /* XXX */
+					       SkShader::kClamp_TileMode);
+
+	cr->paint->setShader (shader);
+	shader->unref ();
+
+	cr->paint->setFilterBitmap (true);
+
+	return CAIRO_STATUS_SUCCESS;
+    }
+
+    pattern = cairo_pattern_create_for_surface (surface);
+    if (unlikely (pattern->status))
+	return pattern->status;
+
+    cairo_matrix_init_translate (&matrix, -x, -y);
+    cairo_pattern_set_matrix (pattern, &matrix);
+
+    status = _cairo_skia_context_set_source (cr, pattern);
+    cairo_pattern_destroy (pattern);
+
+    return status;
+}
+
+static cairo_pattern_t *
+_cairo_skia_context_get_source (void *abstract_cr)
+{
+    //cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
+
+    UNSUPPORTED;
+    return NULL;
+}
+
+static cairo_status_t
+_cairo_skia_context_set_tolerance (void *abstract_cr,
+				   double tolerance)
+{
+    //cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
+
+    /* XXX ignored */
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static inline SkXfermode::Mode
+operator_to_sk (cairo_operator_t op)
+{
+    static const SkXfermode::Mode modeMap[] = {
+	SkXfermode::kClear_Mode,
+
+	SkXfermode::kSrc_Mode,
+	SkXfermode::kSrcOver_Mode,
+	SkXfermode::kSrcIn_Mode,
+	SkXfermode::kSrcOut_Mode,
+	SkXfermode::kSrcATop_Mode,
+
+	SkXfermode::kDst_Mode,
+	SkXfermode::kDstOver_Mode,
+	SkXfermode::kDstIn_Mode,
+	SkXfermode::kDstOut_Mode,
+	SkXfermode::kDstATop_Mode,
+
+	SkXfermode::kXor_Mode,
+	SkXfermode::kPlus_Mode, // XXX Add?
+	SkXfermode::kPlus_Mode, // XXX SATURATE
+
+	SkXfermode::kPlus_Mode,
+	SkXfermode::kMultiply_Mode,
+	SkXfermode::kScreen_Mode,
+	SkXfermode::kOverlay_Mode,
+	SkXfermode::kDarken_Mode,
+	SkXfermode::kLighten_Mode,
+	SkXfermode::kColorDodge_Mode,
+	SkXfermode::kColorBurn_Mode,
+	SkXfermode::kHardLight_Mode,
+	SkXfermode::kSoftLight_Mode,
+	SkXfermode::kDifference_Mode,
+	SkXfermode::kExclusion_Mode,
+
+	SkXfermode::kSrcOver_Mode, // XXX: CAIRO_OPERATOR_HSL_HUE
+	SkXfermode::kSrcOver_Mode, // XXX: CAIRO_OPERATOR_HSL_SATURATION,
+	SkXfermode::kSrcOver_Mode, // XXX: CAIRO_OPERATOR_HSL_COLOR,
+	SkXfermode::kSrcOver_Mode, // XXX: CAIRO_OPERATOR_HSL_LUMINOSITY
+    };
+
+    return modeMap[op];
+}
+
+static cairo_status_t
+_cairo_skia_context_set_operator (void *abstract_cr, cairo_operator_t op)
+{
+    cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
+
+    cr->paint->setXfermodeMode (operator_to_sk (op));
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_skia_context_set_opacity (void *abstract_cr, double opacity)
+{
+    //cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
+
+    /* XXX */
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_skia_context_set_antialias (void *abstract_cr, cairo_antialias_t antialias)
+{
+    cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
+
+    cr->paint->setAntiAlias (antialias != CAIRO_ANTIALIAS_NONE);
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_skia_context_set_fill_rule (void *abstract_cr,
+				   cairo_fill_rule_t fill_rule)
+{
+    cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
+
+    cr->path->setFillType (fill_rule == CAIRO_FILL_RULE_WINDING ? SkPath::kWinding_FillType : SkPath::kEvenOdd_FillType);
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_skia_context_set_line_width (void *abstract_cr,
+				    double line_width)
+{
+    cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
+
+    cr->paint->setStrokeWidth (SkFloatToScalar (line_width));
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_skia_context_set_line_cap (void *abstract_cr,
+				  cairo_line_cap_t line_cap)
+{
+    cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
+    static const SkPaint::Cap map[] = {
+	SkPaint::kButt_Cap,
+	SkPaint::kRound_Cap,
+	SkPaint::kSquare_Cap
+    };
+    cr->paint->setStrokeCap (map[line_cap]);
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_skia_context_set_line_join (void *abstract_cr,
+				   cairo_line_join_t line_join)
+{
+    cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
+    static const SkPaint::Join map[] = {
+	SkPaint::kMiter_Join,
+	SkPaint::kRound_Join,
+	SkPaint::kBevel_Join
+    };
+    cr->paint->setStrokeJoin (map[line_join]);
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_skia_context_set_dash (void *abstract_cr,
+			      const double *dashes,
+			      int	      num_dashes,
+			      double	      offset)
+{
+    cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
+    SkScalar intervals_static[20];
+    SkScalar *intervals = intervals_static;
+
+    if (num_dashes == 0) {
+	cr->paint->setPathEffect (NULL);
+	return CAIRO_STATUS_SUCCESS;
+    }
+
+    int loop = 0;
+    if ((num_dashes & 1) != 0) {
+	loop = 1;
+	num_dashes <<= 1;
+    }
+
+    if (num_dashes > 20)
+	intervals = new SkScalar[num_dashes];
+
+    int i = 0;
+    do {
+	for (int j = 0; i < num_dashes; j++)
+	    intervals[i++] = SkFloatToScalar (dashes[j]);
+    } while (loop--);
+
+    SkDashPathEffect *dash = new SkDashPathEffect (intervals, num_dashes, SkFloatToScalar (offset));
+
+    cr->paint->setPathEffect (dash);
+    dash->unref ();
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_skia_context_set_miter_limit (void *abstract_cr, double limit)
+{
+    cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
+
+    cr->paint->setStrokeMiter (SkFloatToScalar (limit));
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_antialias_t
+_cairo_skia_context_get_antialias (void *abstract_cr)
+{
+    cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
+
+    return cr->paint->isAntiAlias () ? CAIRO_ANTIALIAS_DEFAULT : CAIRO_ANTIALIAS_NONE;
+}
+
+static void
+_cairo_skia_context_get_dash (void *abstract_cr,
+			      double *dashes,
+			      int *num_dashes,
+			      double *offset)
+{
+    //cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
+
+    *num_dashes = 0;
+    /* XXX */
+}
+
+static cairo_fill_rule_t
+_cairo_skia_context_get_fill_rule (void *abstract_cr)
+{
+    cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
+    SkPath::FillType ft;
+
+    ft = cr->path->getFillType ();
+    if (ft == SkPath::kWinding_FillType)
+	return CAIRO_FILL_RULE_WINDING;
+    if (ft == SkPath::kEvenOdd_FillType)
+	return CAIRO_FILL_RULE_EVEN_ODD;;
+
+    UNSUPPORTED;
+    return CAIRO_FILL_RULE_WINDING;
+}
+
+static double
+_cairo_skia_context_get_line_width (void *abstract_cr)
+{
+    cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
+
+    return /* ScalarToFloat */ cr->paint->getStrokeWidth ();
+}
+
+static cairo_line_cap_t
+_cairo_skia_context_get_line_cap (void *abstract_cr)
+{
+    cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
+    static const cairo_line_cap_t map[] = {
+	CAIRO_LINE_CAP_BUTT,
+	CAIRO_LINE_CAP_ROUND,
+	CAIRO_LINE_CAP_SQUARE
+    };
+    return map[cr->paint->getStrokeCap ()];
+}
+
+static cairo_line_join_t
+_cairo_skia_context_get_line_join (void *abstract_cr)
+{
+    cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
+    static const cairo_line_join_t map[] = {
+	CAIRO_LINE_JOIN_MITER,
+	CAIRO_LINE_JOIN_ROUND,
+	CAIRO_LINE_JOIN_BEVEL
+    };
+    return map[cr->paint->getStrokeJoin ()];
+}
+
+static double
+_cairo_skia_context_get_miter_limit (void *abstract_cr)
+{
+    cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
+
+    return /* SkScalarToFloat */ cr->paint->getStrokeMiter ();
+}
+
+static cairo_operator_t
+_cairo_skia_context_get_operator (void *abstract_cr)
+{
+    //cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
+
+    UNSUPPORTED;
+    //cr->paint->getXfermode ();
+    return CAIRO_OPERATOR_OVER;
+}
+
+static double
+_cairo_skia_context_get_opacity (void *abstract_cr)
+{
+    //cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
+
+    UNSUPPORTED;
+    return 1.;
+}
+
+static double
+_cairo_skia_context_get_tolerance (void *abstract_cr)
+{
+    //cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
+
+    /* XXX */
+    return CAIRO_GSTATE_TOLERANCE_DEFAULT;
+}
+
+
+/* Current tranformation matrix */
+
+static cairo_status_t
+_cairo_skia_context_translate (void *abstract_cr,
+			       double tx,
+			       double ty)
+{
+    cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
+
+    cairo_matrix_translate (&cr->matrix, tx, ty);
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_skia_context_scale (void *abstract_cr,
+			   double sx,
+			      double sy)
+{
+    cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
+
+    cairo_matrix_scale (&cr->matrix, sx, sy);
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_skia_context_rotate (void *abstract_cr,
+			    double theta)
+{
+    cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
+
+    cairo_matrix_rotate (&cr->matrix, theta);
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_skia_context_transform (void *abstract_cr,
+			       const cairo_matrix_t *matrix)
+{
+    cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
+
+    cairo_matrix_multiply (&cr->matrix, &cr->matrix, matrix);
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_skia_context_set_matrix (void *abstract_cr,
+				const cairo_matrix_t *matrix)
+{
+    cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
+
+    cr->matrix = *matrix;
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_skia_context_set_identity_matrix (void *abstract_cr)
+{
+    cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
+
+    cairo_matrix_init_identity (&cr->matrix);
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static void
+_cairo_skia_context_get_matrix (void *abstract_cr,
+				cairo_matrix_t *matrix)
+{
+    cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
+
+    *matrix = cr->matrix;
+}
+
+static void
+_cairo_skia_context_user_to_device (void *abstract_cr,
+				    double *x,
+				    double *y)
+{
+    cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
+
+    cairo_matrix_transform_point (&cr->matrix, x, y);
+}
+
+static void
+_cairo_skia_context_user_to_device_distance (void *abstract_cr,
+					     double *dx,
+					     double *dy)
+{
+    cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
+
+    cairo_matrix_transform_distance (&cr->matrix, dx, dy);
+}
+
+static void
+_cairo_skia_context_device_to_user (void *abstract_cr,
+				    double *x,
+				    double *y)
+{
+    cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
+    cairo_matrix_t inverse;
+    cairo_status_t status;
+
+    inverse = cr->matrix;
+    status = cairo_matrix_invert (&inverse);
+    assert (CAIRO_STATUS_SUCCESS == status);
+
+    cairo_matrix_transform_point (&inverse, x, y);
+}
+
+static void
+_cairo_skia_context_device_to_user_distance (void *abstract_cr,
+					     double *dx,
+					     double *dy)
+{
+    cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
+    cairo_matrix_t inverse;
+    cairo_status_t status;
+
+    inverse = cr->matrix;
+    status = cairo_matrix_invert (&inverse);
+    assert (CAIRO_STATUS_SUCCESS == status);
+
+    cairo_matrix_transform_distance (&inverse, dx, dy);
+}
+
+/* Path constructor */
+
+static cairo_status_t
+_cairo_skia_context_new_path (void *abstract_cr)
+{
+    cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
+
+    cr->path->reset ();
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_skia_context_new_sub_path (void *abstract_cr)
+{
+    cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
+
+    cr->path->rMoveTo (0, 0); /* XXX */
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static void
+user_to_device_point (cairo_skia_context_t *cr, double *x, double *y)
+{
+    cairo_matrix_transform_point (&cr->matrix, x, y);
+    cairo_matrix_transform_point (&cr->target->image.base.device_transform, x, y);
+}
+
+static void
+user_to_device_distance (cairo_skia_context_t *cr, double *dx, double *dy)
+{
+    cairo_matrix_transform_distance (&cr->matrix, dx, dy);
+    cairo_matrix_transform_distance (&cr->target->image.base.device_transform, dx, dy);
+}
+
+static cairo_status_t
+_cairo_skia_context_move_to (void *abstract_cr, double x, double y)
+{
+    cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
+
+    user_to_device_point (cr, &x, &y);
+    cr->path->moveTo (SkFloatToScalar (x), SkFloatToScalar (y));
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_skia_context_line_to (void *abstract_cr, double x, double y)
+{
+    cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
+
+    user_to_device_point (cr, &x, &y);
+    cr->path->lineTo (SkFloatToScalar (x), SkFloatToScalar (y));
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_skia_context_curve_to (void *abstract_cr,
+			      double x1, double y1,
+			      double x2, double y2,
+			      double x3, double y3)
+{
+    cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
+
+    user_to_device_point (cr, &x1, &y1);
+    user_to_device_point (cr, &x2, &y2);
+    user_to_device_point (cr, &x3, &y3);
+    cr->path->cubicTo (SkFloatToScalar (x1), SkFloatToScalar (y1),
+		       SkFloatToScalar (x2), SkFloatToScalar (y2),
+		       SkFloatToScalar (x3), SkFloatToScalar (y3));
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_skia_context_arc_to (void *abstract_cr,
+			    double x1, double y1,
+			    double x2, double y2,
+			    double radius)
+{
+    cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
+
+#if 0
+    user_to_device_point (cr, &x1, &y1);
+    user_to_device_point (cr, &x2, &y2);
+    user_to_device_distance (cr, &radius, &radius);
+#endif
+
+    cr->path->arcTo (SkFloatToScalar (x1), SkFloatToScalar (y1),
+		     SkFloatToScalar (x2), SkFloatToScalar (y2),
+		     SkFloatToScalar (radius));
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_skia_context_rel_move_to (void *abstract_cr, double dx, double dy)
+{
+    cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
+
+    user_to_device_distance (cr, &dx, &dy);
+    cr->path->rMoveTo (SkFloatToScalar (dx), SkFloatToScalar (dy));
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_skia_context_rel_line_to (void *abstract_cr, double dx, double dy)
+{
+    cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
+
+    user_to_device_distance (cr, &dx, &dy);
+    cr->path->rLineTo (SkFloatToScalar (dx), SkFloatToScalar (dy));
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_skia_context_rel_curve_to (void *abstract_cr,
+				  double dx1, double dy1,
+				  double dx2, double dy2,
+				  double dx3, double dy3)
+{
+    cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
+
+    user_to_device_distance (cr, &dx1, &dy1);
+    user_to_device_distance (cr, &dx2, &dy2);
+    user_to_device_distance (cr, &dx3, &dy3);
+    cr->path->rCubicTo (SkFloatToScalar (dx1), SkFloatToScalar (dy1),
+			SkFloatToScalar (dx2), SkFloatToScalar (dy2),
+			SkFloatToScalar (dx3), SkFloatToScalar (dy3));
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_skia_context_rel_arc_to (void *abstract_cr,
+				double dx1, double dy1,
+				double dx2, double dy2,
+				double radius)
+{
+    cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
+
+#if 0
+    user_to_device_point (cr, &x1, &y1);
+    user_to_device_point (cr, &x2, &y2);
+    user_to_device_distance (cr, &radius, &radius);
+#endif
+
+    cr->path->arcTo (SkFloatToScalar (dx1), SkFloatToScalar (dy1),
+		     SkFloatToScalar (dx2), SkFloatToScalar (dy2),
+		     SkFloatToScalar (radius));
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_skia_context_close_path (void *abstract_cr)
+{
+    cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
+
+    cr->path->close ();
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_skia_context_rectangle (void *abstract_cr,
+			       double x, double y,
+			       double width, double height)
+{
+    cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
+    double x1, y1, x2, y2;
+
+    /* XXX assume no rotation! */
+    x1 = x, y1 = y;
+    user_to_device_point (cr, &x1, &y1);
+
+    x2 = x + width, y2 = y + height;
+    user_to_device_point (cr, &x2, &y2);
+
+    cr->path->addRect (SkFloatToScalar (x1), SkFloatToScalar (y1),
+		       SkFloatToScalar (x2), SkFloatToScalar (y2));
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_skia_context_arc (void *abstract_cr,
+			 double xc, double yc, double radius,
+			 double angle1, double angle2,
+			 cairo_bool_t forward)
+{
+    cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
+    cairo_status_t status;
+
+    /* XXX cr->path->arc() */
+
+    /* Do nothing, successfully, if radius is <= 0 */
+    if (radius <= 0.0) {
+	status = _cairo_skia_context_line_to (cr, xc, yc);
+	if (unlikely (status))
+	    return status;
+
+	status = _cairo_skia_context_line_to (cr, xc, yc);
+	if (unlikely (status))
+	    return status;
+
+	return CAIRO_STATUS_SUCCESS;
+    }
+
+    status = _cairo_skia_context_line_to (cr,
+					  xc + radius * cos (angle1),
+					  yc + radius * sin (angle1));
+
+    if (unlikely (status))
+	return status;
+
+    if (forward)
+	_cairo_arc_path (&cr->base, xc, yc, radius, angle1, angle2);
+    else
+	_cairo_arc_path_negative (&cr->base, xc, yc, radius, angle1, angle2);
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static void
+_cairo_skia_context_path_extents (void *abstract_cr,
+				  double *x1,
+				  double *y1,
+				  double *x2,
+				  double *y2)
+{
+    cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
+    SkRect rect;
+
+    rect = cr->path->getBounds ();
+
+    UNSUPPORTED;
+    /* XXX transform SkScalar rect to user */
+}
+
+static cairo_bool_t
+_cairo_skia_context_has_current_point (void *abstract_cr)
+{
+    //cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
+
+    return TRUE;
+}
+
+static cairo_bool_t
+_cairo_skia_context_get_current_point (void *abstract_cr,
+				       double *x,
+				       double *y)
+{
+    cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
+    SkPoint pt;
+
+    cr->path->getLastPt (&pt);
+    //*x = SkScalarToFloat (pt.x);
+    //*y = SkScalarToFloat (pt.y);
+    //_cairo_gstate_backend_to_user (cr->gstate, x, y);
+
+    return TRUE;
+}
+
+static cairo_path_t *
+_cairo_skia_context_copy_path (void *abstract_cr)
+{
+    //cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
+
+    /* XXX iterate */
+    UNSUPPORTED;
+    return NULL;
+}
+
+static cairo_path_t *
+_cairo_skia_context_copy_path_flat (void *abstract_cr)
+{
+    //cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
+
+    /* XXX iterate and decompose */
+    UNSUPPORTED;
+    return NULL;
+}
+
+static cairo_status_t
+_cairo_skia_context_append_path (void *abstract_cr,
+				 const cairo_path_t *path)
+{
+    //cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
+
+   // return _cairo_path_append_to_context (path, cr);
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_skia_stroke_to_path (void *abstract_cr)
+{
+    cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
+
+    cr->paint->setStyle (SkPaint::kStroke_Style);
+    cr->paint->getFillPath (*cr->path, cr->path);
+    return CAIRO_STATUS_SUCCESS;
+}
+
+
+static cairo_status_t
+_cairo_skia_context_paint (void *abstract_cr)
+{
+    cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
+
+#if 0
+    if (cr->source != NULL) {
+	SkBitmap bitmap;
+	SkMatrix bitmapMatrix;
+
+	if (cr->source->type == CAIRO_SURFACE_TYPE_SKIA) {
+	    cairo_skia_surface_t *esurf = (cairo_skia_surface_t *) cr->source->type;
+
+	    bitmap = *esurf->bitmap;
+	} else {
+	    surface_to_sk_bitmap (&cr->source_image->base, bitmap);
+	}
+
+	// XXX pattern->matrix, pattern->filter, pattern->extend
+	cr->canvas->drawBitmapMatrix (bitmap, bitmapMatrix, cr->paint);
+    } else {
+	cr->canvas->drawPaint (*cr->paint);
+    }
+#else
+    cr->canvas->drawPaint (*cr->paint);
+#endif
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_skia_context_paint_with_alpha (void *abstract_cr,
+				      double alpha)
+{
+    cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
+
+    if (CAIRO_ALPHA_IS_OPAQUE (alpha))
+	return _cairo_skia_context_paint (cr);
+
+    /*XXX */
+    return _cairo_skia_context_paint (cr);
+}
+
+static cairo_status_t
+_cairo_skia_context_mask (void *abstract_cr,
+			  cairo_pattern_t *mask)
+{
+    //cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
+
+    /* XXX */
+    //UNSUPPORTED;
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_skia_context_stroke_preserve (void *abstract_cr)
+{
+    cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
+
+    cr->paint->setStyle (SkPaint::kStroke_Style);
+
+    /* XXX pen transformation? */
+    //assert (_cairo_matrix_is_identity (&cr->matrix));
+    cr->canvas->drawPath (*cr->path, *cr->paint);
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_skia_context_stroke (void *abstract_cr)
+{
+    cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
+    cairo_status_t status;
+
+    status = _cairo_skia_context_stroke_preserve (cr);
+    if (unlikely (status))
+	return status;
+
+    return _cairo_skia_context_new_path (cr);
+}
+
+static cairo_status_t
+_cairo_skia_context_in_stroke (void *abstract_cr,
+			       double x, double y,
+			       cairo_bool_t *inside)
+{
+    //cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
+
+    UNSUPPORTED;
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_skia_context_stroke_extents (void *abstract_cr,
+				    double *x1, double *y1, double *x2, double *y2)
+{
+    //cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
+
+    UNSUPPORTED;
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_skia_context_fill_preserve (void *abstract_cr)
+{
+    cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
+
+    cr->paint->setStyle (SkPaint::kFill_Style);
+    cr->canvas->drawPath (*cr->path, *cr->paint);
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_skia_context_fill (void *abstract_cr)
+{
+    cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
+    cairo_status_t status;
+
+    status = _cairo_skia_context_fill_preserve (cr);
+    if (unlikely (status))
+	return status;
+
+    return _cairo_skia_context_new_path (cr);
+}
+
+static cairo_status_t
+_cairo_skia_context_in_fill (void *abstract_cr,
+				double x, double y,
+				cairo_bool_t *inside)
+{
+    //cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
+
+    UNSUPPORTED;
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_skia_context_fill_extents (void *abstract_cr,
+				     double *x1, double *y1, double *x2, double *y2)
+{
+    //cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
+
+    UNSUPPORTED;
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_skia_context_clip_preserve (void *abstract_cr)
+{
+    cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
+
+    cr->canvas->clipPath (*cr->path);
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_skia_context_clip (void *abstract_cr)
+{
+    cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
+    cairo_status_t status;
+
+    status = _cairo_skia_context_clip_preserve (cr);
+    if (unlikely (status))
+	return status;
+
+    return _cairo_skia_context_new_path (cr);
+}
+
+static cairo_status_t
+_cairo_skia_context_in_clip (void *abstract_cr,
+			     double x, double y,
+			     cairo_bool_t *inside)
+{
+    //cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_skia_context_reset_clip (void *abstract_cr)
+{
+    cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
+    SkRegion rgn(SkIRect::MakeWH (cr->target->bitmap->width (),
+				  cr->target->bitmap->height ()));
+
+    cr->canvas->setClipRegion(rgn);
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_skia_context_clip_extents (void *abstract_cr,
+				  double *x1, double *y1,
+				  double *x2, double *y2)
+{
+    //cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
+
+    UNSUPPORTED;
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_rectangle_list_t *
+_cairo_skia_context_copy_clip_rectangle_list (void *abstract_cr)
+{
+    //cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
+
+    UNSUPPORTED;
+    return NULL;
+}
+
+static cairo_status_t
+_cairo_skia_context_copy_page (void *abstract_cr)
+{
+    //cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
+
+    UNSUPPORTED;
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_skia_context_show_page (void *abstract_cr)
+{
+    //cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
+    UNSUPPORTED;
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_skia_context_set_font_face (void *abstract_cr,
+				   cairo_font_face_t *font_face)
+{
+   // cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
+
+    //return _cairo_gstate_set_font_face (cr->gstate, font_face);
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_font_face_t *
+_cairo_skia_context_get_font_face (void *abstract_cr)
+{
+    //cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
+
+    UNSUPPORTED;
+    return NULL;
+}
+
+static cairo_status_t
+_cairo_skia_context_font_extents (void *abstract_cr,
+				  cairo_font_extents_t *extents)
+{
+    //cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
+
+    UNSUPPORTED;
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_skia_context_set_font_size (void *abstract_cr,
+				   double size)
+{
+    //cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
+
+    UNSUPPORTED;
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_skia_context_set_font_matrix (void *abstract_cr,
+				     const cairo_matrix_t *matrix)
+{
+    //cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
+
+    UNSUPPORTED;
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static void
+_cairo_skia_context_get_font_matrix (void *abstract_cr,
+				     cairo_matrix_t *matrix)
+{
+    //cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
+
+    UNSUPPORTED;
+}
+
+static cairo_status_t
+_cairo_skia_context_set_font_options (void *abstract_cr,
+				      const cairo_font_options_t *options)
+{
+    //cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
+
+    UNSUPPORTED;
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static void
+_cairo_skia_context_get_font_options (void *abstract_cr,
+				      cairo_font_options_t *options)
+{
+    //cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
+
+    UNSUPPORTED;
+}
+
+static cairo_status_t
+_cairo_skia_context_set_scaled_font (void *abstract_cr,
+					cairo_scaled_font_t *scaled_font)
+{
+    //cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
+
+    UNSUPPORTED;
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_scaled_font_t *
+_cairo_skia_context_get_scaled_font (void *abstract_cr)
+{
+    //cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
+
+    UNSUPPORTED;
+    return _cairo_scaled_font_create_in_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
+}
+
+static cairo_status_t
+_cairo_skia_context_glyphs (void *abstract_cr,
+			    const cairo_glyph_t *glyphs,
+			    int num_glyphs,
+			    cairo_glyph_text_info_t *info)
+{
+    //cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
+
+    /* XXX */
+    //UNSUPPORTED;
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_skia_context_glyph_path (void *abstract_cr,
+				const cairo_glyph_t *glyphs,
+				int num_glyphs)
+{
+    //cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
+
+    UNSUPPORTED;
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_skia_context_glyph_extents (void                *abstract_cr,
+				   const cairo_glyph_t    *glyphs,
+				   int                    num_glyphs,
+				   cairo_text_extents_t   *extents)
+{
+    //cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
+
+    UNSUPPORTED;
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static const cairo_backend_t _cairo_skia_context_backend = {
+    CAIRO_TYPE_SKIA,
+    _cairo_skia_context_destroy,
+
+    _cairo_skia_context_get_original_target,
+    _cairo_skia_context_get_current_target,
+
+    _cairo_skia_context_save,
+    _cairo_skia_context_restore,
+
+    _cairo_skia_context_push_group,
+    _cairo_skia_context_pop_group,
+
+    _cairo_skia_context_set_source_rgba,
+    _cairo_skia_context_set_source_surface,
+    _cairo_skia_context_set_source,
+    _cairo_skia_context_get_source,
+
+    _cairo_skia_context_set_antialias,
+    _cairo_skia_context_set_dash,
+    _cairo_skia_context_set_fill_rule,
+    _cairo_skia_context_set_line_cap,
+    _cairo_skia_context_set_line_join,
+    _cairo_skia_context_set_line_width,
+    _cairo_skia_context_set_miter_limit,
+    _cairo_skia_context_set_opacity,
+    _cairo_skia_context_set_operator,
+    _cairo_skia_context_set_tolerance,
+    _cairo_skia_context_get_antialias,
+    _cairo_skia_context_get_dash,
+    _cairo_skia_context_get_fill_rule,
+    _cairo_skia_context_get_line_cap,
+    _cairo_skia_context_get_line_join,
+    _cairo_skia_context_get_line_width,
+    _cairo_skia_context_get_miter_limit,
+    _cairo_skia_context_get_opacity,
+    _cairo_skia_context_get_operator,
+    _cairo_skia_context_get_tolerance,
+
+    _cairo_skia_context_translate,
+    _cairo_skia_context_scale,
+    _cairo_skia_context_rotate,
+    _cairo_skia_context_transform,
+    _cairo_skia_context_set_matrix,
+    _cairo_skia_context_set_identity_matrix,
+    _cairo_skia_context_get_matrix,
+    _cairo_skia_context_user_to_device,
+    _cairo_skia_context_user_to_device_distance,
+    _cairo_skia_context_device_to_user,
+    _cairo_skia_context_device_to_user_distance,
+
+    _cairo_skia_context_new_path,
+    _cairo_skia_context_new_sub_path,
+    _cairo_skia_context_move_to,
+    _cairo_skia_context_rel_move_to,
+    _cairo_skia_context_line_to,
+    _cairo_skia_context_rel_line_to,
+    _cairo_skia_context_curve_to,
+    _cairo_skia_context_rel_curve_to,
+    _cairo_skia_context_arc_to,
+    _cairo_skia_context_rel_arc_to,
+    _cairo_skia_context_close_path,
+    _cairo_skia_context_arc,
+    _cairo_skia_context_rectangle,
+    _cairo_skia_context_path_extents,
+    _cairo_skia_context_has_current_point,
+    _cairo_skia_context_get_current_point,
+    _cairo_skia_context_copy_path,
+    _cairo_skia_context_copy_path_flat,
+    _cairo_skia_context_append_path,
+
+    _cairo_skia_stroke_to_path,
+
+    _cairo_skia_context_clip,
+    _cairo_skia_context_clip_preserve,
+    _cairo_skia_context_in_clip,
+    _cairo_skia_context_clip_extents,
+    _cairo_skia_context_reset_clip,
+    _cairo_skia_context_copy_clip_rectangle_list,
+
+    _cairo_skia_context_paint,
+    _cairo_skia_context_paint_with_alpha,
+    _cairo_skia_context_mask,
+
+    _cairo_skia_context_stroke,
+    _cairo_skia_context_stroke_preserve,
+    _cairo_skia_context_in_stroke,
+    _cairo_skia_context_stroke_extents,
+
+    _cairo_skia_context_fill,
+    _cairo_skia_context_fill_preserve,
+    _cairo_skia_context_in_fill,
+    _cairo_skia_context_fill_extents,
+
+    _cairo_skia_context_set_font_face,
+    _cairo_skia_context_get_font_face,
+    _cairo_skia_context_set_font_size,
+    _cairo_skia_context_set_font_matrix,
+    _cairo_skia_context_get_font_matrix,
+    _cairo_skia_context_set_font_options,
+    _cairo_skia_context_get_font_options,
+    _cairo_skia_context_set_scaled_font,
+    _cairo_skia_context_get_scaled_font,
+    _cairo_skia_context_font_extents,
+
+    _cairo_skia_context_glyphs,
+    _cairo_skia_context_glyph_path,
+    _cairo_skia_context_glyph_extents,
+
+    _cairo_skia_context_copy_page,
+    _cairo_skia_context_show_page,
+};
+
+cairo_t *
+_cairo_skia_context_create (void *target)
+{
+    cairo_skia_surface_t *surface = (cairo_skia_surface_t *) target;
+    cairo_skia_context_t *cr;
+
+    cr = (cairo_skia_context_t *) _freed_pool_get (&context_pool);
+    if (unlikely (cr == NULL)) {
+	    cr = new cairo_skia_context_t;
+	    if (unlikely (cr == NULL))
+		return _cairo_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
+
+	    cr->path = new SkPath;
+	    cr->paint = new SkPaint;
+    }
+
+    _cairo_init (&cr->base, &_cairo_skia_context_backend);
+
+    cr->source = NULL;
+    cr->source_image = NULL;
+
+    cr->paint->setStrokeWidth (SkFloatToScalar (2.0));
+
+    cr->target = (cairo_skia_surface_t *) cairo_surface_reference ((cairo_surface_t *) target);
+    cr->original = (cairo_skia_surface_t *) cairo_surface_reference ((cairo_surface_t *) target);
+    cr->canvas = new SkCanvas (*surface->bitmap);
+    cr->canvas->save ();
+
+    cairo_matrix_init_identity (&cr->matrix);
+
+    return &cr->base;
+}
+
+#if 0
+void
+_cairo_skia_context_set_SkPaint (cairo_t *cr, SkPaint paint)
+{
+    *cr->paint = paint;
+}
+
+void
+_cairo_skia_context_set_SkPath (cairo_t *cr, SkPath path)
+{
+    *cr->path = path;
+}
+#endif
diff --git a/src/skia/cairo-skia-private.h b/src/skia/cairo-skia-private.h
new file mode 100644
index 0000000..cbd8c88
--- /dev/null
+++ b/src/skia/cairo-skia-private.h
@@ -0,0 +1,110 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2005 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is Red Hat, Inc.
+ *
+ * Contributor(s):
+ *	Carl D. Worth <cworth at redhat.com>
+ */
+
+#ifndef CAIRO_SKIA_CONTEXT_PRIVATE_H
+#define CAIRO_SKIA_CONTEXT_PRIVATE_H
+
+#include "cairo-private.h"
+#include "cairo-image-surface-private.h"
+
+#include <SkBitmap.h>
+#include <SkCanvas.h>
+#include <SkPaint.h>
+#include <SkPath.h>
+
+typedef struct _cairo_skia_context cairo_skia_context_t;
+typedef struct _cairo_skia_surface cairo_skia_surface_t;
+
+struct _cairo_skia_context {
+    cairo_t base;
+
+    cairo_skia_surface_t *original;
+    cairo_skia_surface_t *target;
+
+    cairo_matrix_t matrix;
+
+    SkCanvas *canvas;
+    SkPaint *paint;
+    SkPath *path;
+
+    cairo_surface_t *source;
+    cairo_image_surface_t *source_image;
+    void *source_extra;
+};
+
+struct _cairo_skia_surface {
+    cairo_image_surface_t image;
+
+    SkBitmap *bitmap;
+};
+
+static inline bool
+format_to_sk_config (cairo_format_t format,
+		     SkBitmap::Config& config,
+		     bool& opaque)
+{
+    opaque = false;
+
+    switch (format) {
+    case CAIRO_FORMAT_ARGB32:
+	config = SkBitmap::kARGB_8888_Config;
+	break;
+    case CAIRO_FORMAT_RGB24:
+	config = SkBitmap::kARGB_8888_Config;
+	opaque = true;
+	break;
+    case CAIRO_FORMAT_RGB16_565:
+	config = SkBitmap::kRGB_565_Config;
+	opaque = true;
+	break;
+    case CAIRO_FORMAT_A8:
+	config = SkBitmap::kA8_Config;
+	break;
+    case CAIRO_FORMAT_A1:
+	config = SkBitmap::kA1_Config;
+	break;
+    case CAIRO_FORMAT_RGB30:
+    case CAIRO_FORMAT_INVALID:
+    default:
+	return false;
+    }
+
+    return true;
+}
+
+cairo_private cairo_t *
+_cairo_skia_context_create (void *target);
+
+#endif /* CAIRO_SKIA_CONTEXT_PRIVATE_H */
diff --git a/src/skia/cairo-skia-surface.cpp b/src/skia/cairo-skia-surface.cpp
new file mode 100644
index 0000000..4c10625
--- /dev/null
+++ b/src/skia/cairo-skia-surface.cpp
@@ -0,0 +1,525 @@
+/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2007 Mozilla Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is Mozilla Corporation.
+ *
+ * Contributor(s):
+ *	Vladimir Vukicevic <vladimir at mozilla.com>
+ */
+
+#include "cairoint.h"
+
+#include "cairo-skia.h"
+#include "cairo-skia-private.h"
+
+#include "cairo-composite-rectangles-private.h"
+#include "cairo-error-private.h"
+
+static cairo_skia_surface_t *
+_cairo_skia_surface_create_internal (SkBitmap::Config config,
+				     bool opaque,
+				     unsigned char *data,
+				     int width,
+				     int height,
+				     int stride);
+
+static cairo_surface_t *
+_cairo_skia_surface_create_similar (void *asurface,
+				    cairo_content_t content,
+				    int width,
+				    int height)
+{
+    cairo_skia_surface_t *surface = (cairo_skia_surface_t *) asurface;
+    SkBitmap::Config config;
+    bool opaque;
+
+    if (content == surface->image.base.content)
+    {
+	config = surface->bitmap->getConfig ();
+	opaque = surface->bitmap->isOpaque ();
+    }
+    else if (! format_to_sk_config (_cairo_format_from_content (content),
+				    config, opaque))
+    {
+	return NULL;
+    }
+
+    return &_cairo_skia_surface_create_internal (config, opaque,
+						 NULL,
+						 width, height,
+						 0)->image.base;
+}
+
+static cairo_status_t
+_cairo_skia_surface_finish (void *asurface)
+{
+    cairo_skia_surface_t *surface = (cairo_skia_surface_t *) asurface;
+
+    cairo_surface_finish (&surface->image.base);
+    delete surface->bitmap;
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_surface_t *
+_cairo_skia_surface_map_to_image (void *asurface,
+				  const cairo_rectangle_int_t *extents)
+{
+    cairo_skia_surface_t *surface = (cairo_skia_surface_t *) asurface;
+
+    surface->bitmap->lockPixels ();
+
+    if (extents->width < surface->image.width ||
+	extents->height < surface->image.height)
+    {
+	return _cairo_surface_create_for_rectangle_int (&surface->image.base,
+							extents);
+    }
+
+    return cairo_surface_reference (&surface->image.base);
+}
+
+static cairo_int_status_t
+_cairo_skia_surface_unmap_image (void *asurface,
+				 cairo_image_surface_t *image)
+{
+    cairo_skia_surface_t *surface = (cairo_skia_surface_t *) asurface;
+
+    surface->bitmap->unlockPixels ();
+    return CAIRO_INT_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_skia_surface_acquire_source_image (void *asurface,
+					  cairo_image_surface_t **image_out,
+					  void **image_extra)
+{
+    cairo_skia_surface_t *surface = (cairo_skia_surface_t *) asurface;
+
+    surface->bitmap->lockPixels ();
+
+    *image_out = &surface->image;
+    *image_extra = NULL;
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static void
+_cairo_skia_surface_release_source_image (void *asurface,
+					  cairo_image_surface_t *image,
+					  void *image_extra)
+{
+    cairo_skia_surface_t *surface = (cairo_skia_surface_t *) asurface;
+
+    surface->bitmap->unlockPixels ();
+}
+
+static cairo_bool_t
+_cairo_skia_surface_get_extents (void *asurface,
+				  cairo_rectangle_int_t *extents)
+{
+    cairo_skia_surface_t *surface = (cairo_skia_surface_t *) asurface;
+    extents->x = extents->y = 0;
+    extents->width  = surface->image.width;
+    extents->height = surface->image.height;
+    return TRUE;
+}
+
+static void
+_cairo_skia_surface_get_font_options (void                  *abstract_surface,
+				       cairo_font_options_t  *options)
+{
+    _cairo_font_options_init_default (options);
+
+    cairo_font_options_set_hint_metrics (options, CAIRO_HINT_METRICS_ON);
+    _cairo_font_options_set_round_glyph_positions (options, CAIRO_ROUND_GLYPH_POS_ON);
+}
+
+static cairo_rectangle_t *
+to_rectangle (cairo_rectangle_t *rf,
+	      cairo_rectangle_int_t *ri)
+{
+    rf->x = ri->x;
+    rf->y = ri->y;
+    rf->width = ri->width;
+    rf->height = ri->height;
+    return rf;
+}
+
+static cairo_int_status_t
+_cairo_foreign_surface_paint (void			*abstract_surface,
+			      cairo_operator_t		 op,
+			      const cairo_pattern_t	*source,
+			      const cairo_clip_t	*clip)
+{
+    cairo_surface_t *surface = (cairo_surface_t *) abstract_surface;
+    cairo_surface_t *image;
+    cairo_rectangle_int_t extents;
+    cairo_rectangle_t rect;
+    cairo_composite_rectangles_t composite;
+    cairo_int_status_t status;
+
+    _cairo_surface_get_extents (surface, &extents);
+    status = _cairo_composite_rectangles_init_for_paint (&composite, &extents,
+							 op, source,
+							 clip);
+    if (unlikely (status))
+	return status;
+
+    image = cairo_surface_map_to_image (surface,
+					to_rectangle(&rect, &composite.unbounded));
+    status = (cairo_int_status_t)
+	_cairo_surface_paint (image, op, source, clip);
+    cairo_surface_unmap_image (surface, image);
+
+    _cairo_composite_rectangles_fini (&composite);
+
+    return status;
+}
+
+static cairo_int_status_t
+_cairo_foreign_surface_mask (void			*abstract_surface,
+			      cairo_operator_t		 op,
+			      const cairo_pattern_t	*source,
+			      const cairo_pattern_t	*mask,
+			      const cairo_clip_t	*clip)
+{
+    cairo_surface_t *surface =(cairo_surface_t *) abstract_surface;
+    cairo_surface_t *image;
+    cairo_rectangle_int_t extents;
+    cairo_rectangle_t rect;
+    cairo_composite_rectangles_t composite;
+    cairo_int_status_t status;
+
+    _cairo_surface_get_extents (surface, &extents);
+    status = _cairo_composite_rectangles_init_for_mask (&composite, &extents,
+							op, source, mask,
+							clip);
+    if (unlikely (status))
+	return status;
+
+    image = cairo_surface_map_to_image (surface,
+					to_rectangle(&rect, &composite.unbounded));
+    status = (cairo_int_status_t)
+	_cairo_surface_mask (image, op, source, mask, clip);
+    cairo_surface_unmap_image (surface, image);
+
+    _cairo_composite_rectangles_fini (&composite);
+
+    return status;
+}
+
+static cairo_int_status_t
+_cairo_foreign_surface_stroke (void			*abstract_surface,
+			       cairo_operator_t		 op,
+			       const cairo_pattern_t	*source,
+			       const cairo_path_fixed_t	*path,
+			       const cairo_stroke_style_t*style,
+			       const cairo_matrix_t	*ctm,
+			       const cairo_matrix_t	*ctm_inverse,
+			       double			 tolerance,
+			       cairo_antialias_t	 antialias,
+			       const cairo_clip_t	*clip)
+{
+    cairo_surface_t *surface =(cairo_surface_t *) abstract_surface;
+    cairo_surface_t *image;
+    cairo_composite_rectangles_t composite;
+    cairo_rectangle_int_t extents;
+    cairo_rectangle_t rect;
+    cairo_int_status_t status;
+
+    _cairo_surface_get_extents (surface, &extents);
+    status = _cairo_composite_rectangles_init_for_stroke (&composite, &extents,
+							  op, source,
+							  path, style, ctm,
+							  clip);
+    if (unlikely (status))
+	return status;
+
+    image = cairo_surface_map_to_image (surface,
+					to_rectangle(&rect, &composite.unbounded));
+    status = (cairo_int_status_t)
+	_cairo_surface_stroke (image, op, source, path, style, ctm, ctm_inverse, tolerance, antialias, clip);
+    cairo_surface_unmap_image (surface, image);
+
+    _cairo_composite_rectangles_fini (&composite);
+
+    return status;
+}
+
+static cairo_int_status_t
+_cairo_foreign_surface_fill (void				*abstract_surface,
+			     cairo_operator_t		 op,
+			     const cairo_pattern_t	*source,
+			     const cairo_path_fixed_t	*path,
+			     cairo_fill_rule_t		 fill_rule,
+			     double			 tolerance,
+			     cairo_antialias_t		 antialias,
+			     const cairo_clip_t		*clip)
+{
+    cairo_surface_t *surface =(cairo_surface_t *) abstract_surface;
+    cairo_surface_t *image;
+    cairo_composite_rectangles_t composite;
+    cairo_rectangle_int_t extents;
+    cairo_rectangle_t rect;
+    cairo_int_status_t status;
+
+    _cairo_surface_get_extents (surface, &extents);
+    status = _cairo_composite_rectangles_init_for_fill (&composite, &extents,
+							op, source, path,
+							clip);
+    if (unlikely (status))
+	return status;
+
+    image = cairo_surface_map_to_image (surface,
+					to_rectangle(&rect, &composite.unbounded));
+    status = (cairo_int_status_t)
+	_cairo_surface_fill (image, op, source, path, fill_rule, tolerance, antialias, clip);
+    cairo_surface_unmap_image (surface, image);
+
+    _cairo_composite_rectangles_fini (&composite);
+
+    return status;
+}
+
+static cairo_int_status_t
+_cairo_foreign_surface_glyphs (void			*abstract_surface,
+			       cairo_operator_t		 op,
+			       const cairo_pattern_t	*source,
+			       cairo_glyph_t		*glyphs,
+			       int			 num_glyphs,
+			       cairo_scaled_font_t	*scaled_font,
+			       const cairo_clip_t	*clip,
+			       int *num_remaining)
+{
+    cairo_surface_t *surface =(cairo_surface_t *) abstract_surface;
+    cairo_surface_t *image;
+    cairo_composite_rectangles_t composite;
+    cairo_rectangle_int_t extents;
+    cairo_rectangle_t rect;
+    cairo_int_status_t status;
+    cairo_bool_t overlap;
+
+    _cairo_surface_get_extents (surface, &extents);
+    status = _cairo_composite_rectangles_init_for_glyphs (&composite, &extents,
+							  op, source,
+							  scaled_font,
+							  glyphs, num_glyphs,
+							  clip,
+							  &overlap);
+    if (unlikely (status))
+	return status;
+
+    image = cairo_surface_map_to_image (surface,
+					to_rectangle(&rect, &composite.unbounded));
+    status = (cairo_int_status_t)
+	_cairo_surface_show_text_glyphs (image,
+					 op, source,
+					 NULL, 0,
+					 glyphs, num_glyphs,
+					 NULL, 0, (cairo_text_cluster_flags_t)0,
+					 scaled_font,
+					 clip);
+    cairo_surface_unmap_image (surface, image);
+    _cairo_composite_rectangles_fini (&composite);
+
+    *num_remaining = 0;
+    return status;
+}
+
+static const struct _cairo_surface_backend
+cairo_skia_surface_backend = {
+    CAIRO_SURFACE_TYPE_SKIA,
+    _cairo_skia_surface_finish,
+
+    _cairo_skia_context_create,
+
+    _cairo_skia_surface_create_similar,
+    NULL, //_cairo_skia_surface_create_similar_image,
+    _cairo_skia_surface_map_to_image,
+    _cairo_skia_surface_unmap_image,
+
+    _cairo_skia_surface_acquire_source_image,
+    _cairo_skia_surface_release_source_image,
+
+    NULL, NULL,
+    NULL, /* clone similar */
+    NULL, /* composite */
+    NULL, /* fill_rectangles */
+    NULL, /* composite_trapezoids */
+    NULL, /* create_span_renderer */
+    NULL, /* check_span_renderer */
+
+    NULL, /* copy_page */
+    NULL, /* show_page */
+
+    _cairo_skia_surface_get_extents,
+    NULL, /* old_show_glyphs */
+    _cairo_skia_surface_get_font_options,
+    NULL, /* flush */
+    NULL, /* mark_dirty_rectangle */
+    NULL, /* scaled_font_fini */
+    NULL, /* scaled_glyph_fini */
+
+    /* XXX native surface functions? */
+    _cairo_foreign_surface_paint,
+    _cairo_foreign_surface_mask,
+    _cairo_foreign_surface_stroke,
+    _cairo_foreign_surface_fill,
+    _cairo_foreign_surface_glyphs
+};
+
+/*
+ * Surface constructors
+ */
+
+static inline pixman_format_code_t
+sk_config_to_pixman_format_code (SkBitmap::Config config,
+				 bool opaque)
+{
+    switch (config) {
+    case SkBitmap::kARGB_8888_Config:
+	return opaque ? PIXMAN_x8r8g8b8 : PIXMAN_a8r8g8b8;
+
+    case SkBitmap::kA8_Config:
+	return PIXMAN_a8;
+
+    case SkBitmap::kA1_Config:
+	return PIXMAN_a1;
+    case SkBitmap::kRGB_565_Config:
+	return PIXMAN_r5g6b5;
+    case SkBitmap::kARGB_4444_Config:
+	return PIXMAN_a4r4g4b4;
+
+    case SkBitmap::kNo_Config:
+    case SkBitmap::kIndex8_Config:
+    case SkBitmap::kRLE_Index8_Config:
+    case SkBitmap::kConfigCount:
+    default:
+	ASSERT_NOT_REACHED;
+	return (pixman_format_code_t) -1;
+    }
+}
+static cairo_skia_surface_t *
+_cairo_skia_surface_create_internal (SkBitmap::Config config,
+				     bool opaque,
+				     unsigned char *data,
+				     int width,
+				     int height,
+				     int stride)
+{
+    cairo_skia_surface_t *surface;
+    pixman_image_t *pixman_image;
+    pixman_format_code_t pixman_format;
+
+    surface = (cairo_skia_surface_t *) malloc (sizeof (cairo_skia_surface_t));
+    if (unlikely (surface == NULL))
+	return (cairo_skia_surface_t *) _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
+
+    pixman_format = sk_config_to_pixman_format_code (config, opaque);
+    pixman_image = pixman_image_create_bits (pixman_format,
+					     width, height,
+					     (uint32_t *) data, stride);
+    if (unlikely (pixman_image == NULL))
+	return (cairo_skia_surface_t *) _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
+
+    _cairo_surface_init (&surface->image.base,
+			 &cairo_skia_surface_backend,
+			 NULL, /* device */
+			 _cairo_content_from_pixman_format (pixman_format));
+
+    _cairo_image_surface_init (&surface->image, pixman_image, pixman_format);
+
+    surface->bitmap = new SkBitmap;
+    surface->bitmap->setConfig (config, width, height, surface->image.stride);
+    surface->bitmap->setIsOpaque (opaque);
+    surface->bitmap->setPixels (surface->image.data);
+
+    surface->image.base.is_clear = data == NULL;
+
+    return surface;
+}
+
+cairo_surface_t *
+cairo_skia_surface_create (cairo_format_t format,
+			   int width,
+			   int height)
+{
+    SkBitmap::Config config;
+    bool opaque;
+
+    if (! CAIRO_FORMAT_VALID (format) ||
+	! format_to_sk_config (format, config, opaque))
+    {
+	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT));
+    }
+
+    return &_cairo_skia_surface_create_internal (config, opaque, NULL, width, height, 0)->image.base;
+}
+
+cairo_surface_t *
+cairo_skia_surface_create_for_data (unsigned char *data,
+				    cairo_format_t format,
+				    int width,
+				    int height,
+				    int stride)
+{
+    SkBitmap::Config config;
+    bool opaque;
+
+    if (! CAIRO_FORMAT_VALID (format) ||
+	! format_to_sk_config (format, config, opaque))
+    {
+	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT));
+    }
+
+    return &_cairo_skia_surface_create_internal (config, opaque, data, width, height, stride)->image.base;
+}
+
+/***
+
+Todo:
+
+*** Skia:
+
+- mask()
+
+*** Sk:
+
+High:
+- antialiased clipping?
+
+Medium:
+- implement clip path reset (to avoid restore/save)
+- implement complex radial patterns (2 centers and 2 radii)
+
+Low:
+- implement EXTEND_NONE
+
+***/
diff --git a/test/Makefile.am b/test/Makefile.am
index e4e3063..d525ae3 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -433,8 +433,8 @@ run:
 check-valgrind:
 	$(MAKE) $(AM_MAKEFLAGS) check TESTS_ENVIRONMENT='$(TESTS_ENVIRONMENT) CAIRO_TEST_MODE="$(MODE),foreground CAIRO_TEST_TIMEOUT=0" $(top_builddir)/libtool --mode=execute valgrind $(VALGRIND_FLAGS)' 2>&1 | tee valgrind-log
 
-%.log: %.c cairo-test-suite
-	-./cairo-test-suite $(<:.c=)
+#%.log: %.c cairo-test-suite
+#-./cairo-test-suite $(<:.c=)
 
 NOLOG_TESTS_LOG = $(NOLOG_TESTS:=.log)
 
commit e849e7c9291d57c3749f499c7e410e7be452b455
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Thu Aug 4 00:19:42 2011 +0100

    image: move surface definition to new header for subclassing
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/Makefile.sources b/src/Makefile.sources
index b5e4805..2af733e 100644
--- a/src/Makefile.sources
+++ b/src/Makefile.sources
@@ -75,6 +75,7 @@ cairo_private = \
 	cairo-gstate-private.h \
 	cairo-hash-private.h \
 	cairo-image-info-private.h \
+	cairo-image-surface-private.h \
 	cairo-list-private.h \
 	cairo-malloc-private.h \
 	cairo-mutex-impl-private.h \
diff --git a/src/cairo-debug.c b/src/cairo-debug.c
index ada0cdb..b4cde7d 100644
--- a/src/cairo-debug.c
+++ b/src/cairo-debug.c
@@ -34,6 +34,7 @@
  */
 
 #include "cairoint.h"
+#include "cairo-image-surface-private.h"
 
 /**
  * cairo_debug_reset_static_data:
diff --git a/src/cairo-ft-font.c b/src/cairo-ft-font.c
index 7f5f6d0..8ef37aa 100644
--- a/src/cairo-ft-font.c
+++ b/src/cairo-ft-font.c
@@ -42,6 +42,7 @@
 #include "cairoint.h"
 
 #include "cairo-error-private.h"
+#include "cairo-image-surface-private.h"
 #include "cairo-ft-private.h"
 #include "cairo-pattern-private.h"
 
diff --git a/src/cairo-gl-composite.c b/src/cairo-gl-composite.c
index 6ea8c85..01fe725 100644
--- a/src/cairo-gl-composite.c
+++ b/src/cairo-gl-composite.c
@@ -42,10 +42,12 @@
 
 #include "cairoint.h"
 
+#include "cairo-gl-private.h"
+
 #include "cairo-composite-rectangles-private.h"
 #include "cairo-clip-private.h"
 #include "cairo-error-private.h"
-#include "cairo-gl-private.h"
+#include "cairo-image-surface-private.h"
 
 static cairo_int_status_t
 _cairo_gl_create_gradient_texture (cairo_gl_surface_t *dst,
diff --git a/src/cairo-gl-glyphs.c b/src/cairo-gl-glyphs.c
index ba09442..0772d2a 100644
--- a/src/cairo-gl-glyphs.c
+++ b/src/cairo-gl-glyphs.c
@@ -42,6 +42,7 @@
 
 #include "cairo-composite-rectangles-private.h"
 #include "cairo-error-private.h"
+#include "cairo-image-surface-private.h"
 #include "cairo-rtree-private.h"
 
 #define GLYPH_CACHE_WIDTH 1024
diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index f6c96ae..ec70820 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -40,10 +40,12 @@
 
 #include "cairoint.h"
 
+#include "cairo-gl-private.h"
+
 #include "cairo-composite-rectangles-private.h"
 #include "cairo-default-context-private.h"
 #include "cairo-error-private.h"
-#include "cairo-gl-private.h"
+#include "cairo-image-surface-private.h"
 
 static cairo_int_status_t
 _cairo_gl_surface_fill_rectangles (void			   *abstract_dst,
diff --git a/src/cairo-image-surface.c b/src/cairo-image-surface.c
index c2afbab..7d8a303 100644
--- a/src/cairo-image-surface.c
+++ b/src/cairo-image-surface.c
@@ -44,6 +44,7 @@
 #include "cairo-composite-rectangles-private.h"
 #include "cairo-default-context-private.h"
 #include "cairo-error-private.h"
+#include "cairo-image-surface-private.h"
 #include "cairo-paginated-private.h"
 #include "cairo-pattern-private.h"
 #include "cairo-recording-surface-private.h"
@@ -144,13 +145,33 @@ _cairo_content_from_pixman_format (pixman_format_code_t pixman_format)
     return content;
 }
 
+void
+_cairo_image_surface_init (cairo_image_surface_t *surface,
+			   pixman_image_t	*pixman_image,
+			   pixman_format_code_t	 pixman_format)
+{
+    surface->pixman_image = pixman_image;
+
+    surface->pixman_format = pixman_format;
+    surface->format = _cairo_format_from_pixman_format (pixman_format);
+    surface->data = (uint8_t *) pixman_image_get_data (pixman_image);
+    surface->owns_data = FALSE;
+    surface->transparency = CAIRO_IMAGE_UNKNOWN;
+    surface->color = CAIRO_IMAGE_UNKNOWN_COLOR;
+
+    surface->width = pixman_image_get_width (pixman_image);
+    surface->height = pixman_image_get_height (pixman_image);
+    surface->stride = pixman_image_get_stride (pixman_image);
+    surface->depth = pixman_image_get_depth (pixman_image);
+
+    surface->base.is_clear = surface->width == 0 || surface->height == 0;
+}
+
 cairo_surface_t *
 _cairo_image_surface_create_for_pixman_image (pixman_image_t		*pixman_image,
 					      pixman_format_code_t	 pixman_format)
 {
     cairo_image_surface_t *surface;
-    int width = pixman_image_get_width (pixman_image);
-    int height = pixman_image_get_height (pixman_image);
 
     surface = malloc (sizeof (cairo_image_surface_t));
     if (unlikely (surface == NULL))
@@ -161,21 +182,7 @@ _cairo_image_surface_create_for_pixman_image (pixman_image_t		*pixman_image,
 			 NULL, /* device */
 			 _cairo_content_from_pixman_format (pixman_format));
 
-    surface->pixman_image = pixman_image;
-
-    surface->pixman_format = pixman_format;
-    surface->format = _cairo_format_from_pixman_format (pixman_format);
-    surface->data = (uint8_t *) pixman_image_get_data (pixman_image);
-    surface->owns_data = FALSE;
-    surface->transparency = CAIRO_IMAGE_UNKNOWN;
-    surface->color = CAIRO_IMAGE_UNKNOWN_COLOR;
-
-    surface->width = width;
-    surface->height = height;
-    surface->stride = pixman_image_get_stride (pixman_image);
-    surface->depth = pixman_image_get_depth (pixman_image);
-
-    surface->base.is_clear = width == 0 || height == 0;
+    _cairo_image_surface_init (surface, pixman_image, pixman_format);
 
     return &surface->base;
 }
@@ -760,7 +767,7 @@ _cairo_image_surface_unmap_image (void *abstract_surface,
     return CAIRO_INT_STATUS_SUCCESS;
 }
 
-static cairo_status_t
+cairo_status_t
 _cairo_image_surface_finish (void *abstract_surface)
 {
     cairo_image_surface_t *surface = abstract_surface;
@@ -3387,7 +3394,7 @@ _clip_and_composite_trapezoids (cairo_image_surface_t *dst,
 }
 
 /* high level image interface */
-static cairo_bool_t
+cairo_bool_t
 _cairo_image_surface_get_extents (void			  *abstract_surface,
 				  cairo_rectangle_int_t   *rectangle)
 {
@@ -4281,7 +4288,7 @@ _cairo_image_surface_glyphs (void			*abstract_surface,
     return status;
 }
 
-static void
+void
 _cairo_image_surface_get_font_options (void                  *abstract_surface,
 				       cairo_font_options_t  *options)
 {
diff --git a/src/cairo-paginated-surface.c b/src/cairo-paginated-surface.c
index 4d93642..61c2815 100644
--- a/src/cairo-paginated-surface.c
+++ b/src/cairo-paginated-surface.c
@@ -49,6 +49,7 @@
 #include "cairo-recording-surface-private.h"
 #include "cairo-analysis-surface-private.h"
 #include "cairo-error-private.h"
+#include "cairo-image-surface-private.h"
 
 static const cairo_surface_backend_t cairo_paginated_surface_backend;
 
diff --git a/src/cairo-pattern.c b/src/cairo-pattern.c
index cb6bba8..3438454 100644
--- a/src/cairo-pattern.c
+++ b/src/cairo-pattern.c
@@ -33,6 +33,7 @@
 #include "cairo-freed-pool-private.h"
 #include "cairo-path-private.h"
 #include "cairo-pattern-private.h"
+#include "cairo-image-surface-private.h"
 
 #include <float.h>
 
diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c
index 01ebcf1..0af638f 100644
--- a/src/cairo-pdf-surface.c
+++ b/src/cairo-pdf-surface.c
@@ -49,6 +49,7 @@
 #include "cairo-composite-rectangles-private.h"
 #include "cairo-default-context-private.h"
 #include "cairo-error-private.h"
+#include "cairo-image-surface-private.h"
 #include "cairo-image-info-private.h"
 #include "cairo-recording-surface-private.h"
 #include "cairo-output-stream-private.h"
diff --git a/src/cairo-png.c b/src/cairo-png.c
index 818b7b0..59bbe68 100644
--- a/src/cairo-png.c
+++ b/src/cairo-png.c
@@ -39,6 +39,7 @@
 #include "cairoint.h"
 
 #include "cairo-error-private.h"
+#include "cairo-image-surface-private.h"
 #include "cairo-output-stream-private.h"
 
 #include <stdio.h>
diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c
index 96f5bcf..267fd59 100644
--- a/src/cairo-ps-surface.c
+++ b/src/cairo-ps-surface.c
@@ -62,6 +62,7 @@
 #include "cairo-composite-rectangles-private.h"
 #include "cairo-default-context-private.h"
 #include "cairo-error-private.h"
+#include "cairo-image-surface-private.h"
 #include "cairo-scaled-font-subsets-private.h"
 #include "cairo-paginated-private.h"
 #include "cairo-recording-surface-private.h"
diff --git a/src/cairo-recording-surface.c b/src/cairo-recording-surface.c
index 987395b..b6df3cc 100644
--- a/src/cairo-recording-surface.c
+++ b/src/cairo-recording-surface.c
@@ -83,6 +83,7 @@
 #include "cairo-composite-rectangles-private.h"
 #include "cairo-default-context-private.h"
 #include "cairo-error-private.h"
+#include "cairo-image-surface-private.h"
 #include "cairo-recording-surface-private.h"
 #include "cairo-surface-wrapper-private.h"
 
diff --git a/src/cairo-scaled-font.c b/src/cairo-scaled-font.c
index cb59bce..5b77546 100644
--- a/src/cairo-scaled-font.c
+++ b/src/cairo-scaled-font.c
@@ -40,6 +40,7 @@
 
 #include "cairoint.h"
 #include "cairo-error-private.h"
+#include "cairo-image-surface-private.h"
 #include "cairo-pattern-private.h"
 #include "cairo-scaled-font-private.h"
 
diff --git a/src/cairo-script-surface.c b/src/cairo-script-surface.c
index b6e0098..1b715f5 100644
--- a/src/cairo-script-surface.c
+++ b/src/cairo-script-surface.c
@@ -51,6 +51,7 @@
 #include "cairo-device-private.h"
 #include "cairo-error-private.h"
 #include "cairo-list-private.h"
+#include "cairo-image-surface-private.h"
 #include "cairo-recording-surface-private.h"
 #include "cairo-output-stream-private.h"
 #include "cairo-scaled-font-private.h"
diff --git a/src/cairo-surface-fallback.c b/src/cairo-surface-fallback.c
index acbf799..b65b2bf 100644
--- a/src/cairo-surface-fallback.c
+++ b/src/cairo-surface-fallback.c
@@ -44,6 +44,7 @@
 #include "cairo-clip-private.h"
 #include "cairo-composite-rectangles-private.h"
 #include "cairo-error-private.h"
+#include "cairo-image-surface-private.h"
 #include "cairo-pattern-private.h"
 #include "cairo-region-private.h"
 #include "cairo-spans-private.h"
diff --git a/src/cairo-surface-snapshot.c b/src/cairo-surface-snapshot.c
index c88d015..56d108b 100644
--- a/src/cairo-surface-snapshot.c
+++ b/src/cairo-surface-snapshot.c
@@ -40,6 +40,7 @@
 #include "cairoint.h"
 
 #include "cairo-error-private.h"
+#include "cairo-image-surface-private.h"
 #include "cairo-surface-snapshot-private.h"
 
 static cairo_status_t
diff --git a/src/cairo-surface-subsurface.c b/src/cairo-surface-subsurface.c
index 29d9ef0..248c20c 100644
--- a/src/cairo-surface-subsurface.c
+++ b/src/cairo-surface-subsurface.c
@@ -36,6 +36,7 @@
 #include "cairoint.h"
 
 #include "cairo-error-private.h"
+#include "cairo-image-surface-private.h"
 #include "cairo-recording-surface-private.h"
 #include "cairo-surface-offset-private.h"
 #include "cairo-surface-subsurface-private.h"
diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index 71f8aea..db127fb 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -42,6 +42,7 @@
 #include "cairo-clip-private.h"
 #include "cairo-device-private.h"
 #include "cairo-error-private.h"
+#include "cairo-image-surface-private.h"
 #include "cairo-recording-surface-private.h"
 #include "cairo-region-private.h"
 #include "cairo-tee-surface-private.h"
diff --git a/src/cairo-svg-surface.c b/src/cairo-svg-surface.c
index 66d0fc2..88acad2 100644
--- a/src/cairo-svg-surface.c
+++ b/src/cairo-svg-surface.c
@@ -46,6 +46,7 @@
 #include "cairo-default-context-private.h"
 #include "cairo-error-private.h"
 #include "cairo-image-info-private.h"
+#include "cairo-image-surface-private.h"
 #include "cairo-recording-surface-private.h"
 #include "cairo-output-stream-private.h"
 #include "cairo-path-fixed-private.h"
diff --git a/src/cairo-type3-glyph-surface.c b/src/cairo-type3-glyph-surface.c
index 93c3a6a..0755415 100644
--- a/src/cairo-type3-glyph-surface.c
+++ b/src/cairo-type3-glyph-surface.c
@@ -44,6 +44,7 @@
 #include "cairo-analysis-surface-private.h"
 #include "cairo-default-context-private.h"
 #include "cairo-error-private.h"
+#include "cairo-image-surface-private.h"
 #include "cairo-surface-clipper-private.h"
 
 static const cairo_surface_backend_t cairo_type3_glyph_surface_backend;
diff --git a/src/cairo-xcb-private.h b/src/cairo-xcb-private.h
index 150aab9..d9557b4 100644
--- a/src/cairo-xcb-private.h
+++ b/src/cairo-xcb-private.h
@@ -83,7 +83,7 @@ struct _cairo_xcb_shm_info {
 
 struct _cairo_xcb_surface {
     cairo_surface_t base;
-    cairo_image_surface_t *fallback;
+    cairo_surface_t *fallback;
 
     cairo_xcb_connection_t *connection;
     cairo_xcb_screen_t *screen;
diff --git a/src/cairo-xcb-surface-core.c b/src/cairo-xcb-surface-core.c
index c3c0953..0770dcd 100644
--- a/src/cairo-xcb-surface-core.c
+++ b/src/cairo-xcb-surface-core.c
@@ -33,6 +33,7 @@
 
 #include "cairo-boxes-private.h"
 #include "cairo-xcb-private.h"
+#include "cairo-image-surface-private.h"
 
 /* XXX dithering */
 
diff --git a/src/cairo-xcb-surface-render.c b/src/cairo-xcb-surface-render.c
index e08ca68..b42795e 100644
--- a/src/cairo-xcb-surface-render.c
+++ b/src/cairo-xcb-surface-render.c
@@ -34,6 +34,7 @@
 #include "cairo-boxes-private.h"
 #include "cairo-clip-private.h"
 #include "cairo-composite-rectangles-private.h"
+#include "cairo-image-surface-private.h"
 #include "cairo-region-private.h"
 #include "cairo-surface-offset-private.h"
 #include "cairo-surface-snapshot-private.h"
diff --git a/src/cairo-xcb-surface.c b/src/cairo-xcb-surface.c
index da35e75..abf8fe3 100644
--- a/src/cairo-xcb-surface.c
+++ b/src/cairo-xcb-surface.c
@@ -44,6 +44,7 @@
 #include "cairo-xcb-private.h"
 
 #include "cairo-default-context-private.h"
+#include "cairo-image-surface-private.h"
 
 #define XLIB_COORD_MAX 32767
 
@@ -222,8 +223,8 @@ _cairo_xcb_surface_finish (void *abstract_surface)
     cairo_status_t status;
 
     if (surface->fallback != NULL) {
-	cairo_surface_finish (&surface->fallback->base);
-	cairo_surface_destroy (&surface->fallback->base);
+	cairo_surface_finish (surface->fallback);
+	cairo_surface_destroy (surface->fallback);
     }
 
     cairo_list_del (&surface->link);
@@ -297,7 +298,7 @@ _cairo_xcb_surface_create_shm_image (cairo_xcb_connection_t *connection,
 }
 #endif
 
-static cairo_image_surface_t *
+static cairo_surface_t *
 _get_shm_image (cairo_xcb_surface_t *surface,
 		int x, int y,
 		int width, int height)
@@ -329,19 +330,19 @@ _get_shm_image (cairo_xcb_surface_t *surface,
     }
 
 done:
-    return (cairo_image_surface_t *) image;
+    return image;
 #else
-    return NULL;;
+    return NULL;
 #endif
 }
 
-static cairo_image_surface_t *
+static cairo_surface_t *
 _get_image (cairo_xcb_surface_t		 *surface,
 	    cairo_bool_t		  use_shm,
 	    int x, int y,
 	    int width, int height)
 {
-    cairo_image_surface_t *image;
+    cairo_surface_t *image;
     cairo_xcb_connection_t *connection;
     xcb_get_image_reply_t *reply;
     cairo_int_status_t status;
@@ -353,7 +354,7 @@ _get_image (cairo_xcb_surface_t		 *surface,
     assert (y + height <= surface->height);
 
     if (surface->deferred_clear) {
-	image = (cairo_image_surface_t *)
+	image =
 	    _cairo_image_surface_create_with_pixman_format (NULL,
 							    surface->pixman_format,
 							    width, height,
@@ -362,14 +363,13 @@ _get_image (cairo_xcb_surface_t		 *surface,
 	    cairo_solid_pattern_t solid;
 
 	    _cairo_pattern_init_solid (&solid, &surface->deferred_clear_color);
-	    status = _cairo_surface_paint (&image->base,
+	    status = _cairo_surface_paint (image,
 					   CAIRO_OPERATOR_SOURCE,
 					   &solid.base,
 					   NULL);
 	    if (unlikely (status)) {
-		cairo_surface_destroy (&image->base);
-		image = (cairo_image_surface_t *)
-		    _cairo_surface_create_in_error (status);
+		cairo_surface_destroy (image);
+		image = _cairo_surface_create_in_error (status);
 	    }
 	}
 	return image;
@@ -379,7 +379,7 @@ _get_image (cairo_xcb_surface_t		 *surface,
 
     status = _cairo_xcb_connection_acquire (connection);
     if (unlikely (status))
-	return (cairo_image_surface_t *) _cairo_surface_create_in_error (status);
+	return _cairo_surface_create_in_error (status);
 
     if (use_shm) {
 	image = _get_shm_image (surface, x, y, width, height);
@@ -450,22 +450,20 @@ _get_image (cairo_xcb_surface_t		 *surface,
     /* XXX format conversion */
     assert (reply->depth == surface->depth);
 
-    image = (cairo_image_surface_t *)
-	_cairo_image_surface_create_with_pixman_format
+    image = _cairo_image_surface_create_with_pixman_format
 	(xcb_get_image_data (reply),
 	 surface->pixman_format,
 	 width, height,
 	 CAIRO_STRIDE_FOR_WIDTH_BPP (width,
 				     PIXMAN_FORMAT_BPP (surface->pixman_format)));
-    status = image->base.status;
+    status = image->status;
     if (unlikely (status)) {
 	free (reply);
 	goto FAIL;
     }
 
-    assert (xcb_get_image_data_length (reply) == image->height * image->stride);
-
-    pixman_image_set_destroy_function (image->pixman_image, _destroy_image, reply);
+    /* XXX */
+    pixman_image_set_destroy_function (((cairo_image_surface_t *)image)->pixman_image, _destroy_image, reply);
 
     _cairo_xcb_connection_release (connection);
 
@@ -473,7 +471,7 @@ _get_image (cairo_xcb_surface_t		 *surface,
 
 FAIL:
     _cairo_xcb_connection_release (connection);
-    return (cairo_image_surface_t *) _cairo_surface_create_in_error (status);
+    return _cairo_surface_create_in_error (status);
 }
 
 static cairo_status_t
@@ -482,29 +480,28 @@ _cairo_xcb_surface_acquire_source_image (void *abstract_surface,
 					 void **image_extra)
 {
     cairo_xcb_surface_t *surface = abstract_surface;
-    cairo_image_surface_t *image;
+    cairo_surface_t *image;
 
     if (surface->fallback != NULL) {
-	image = (cairo_image_surface_t *) cairo_surface_reference (&surface->fallback->base);
+	image = cairo_surface_reference (surface->fallback);
 	goto DONE;
     }
 
-    image = (cairo_image_surface_t *)
-	_cairo_surface_has_snapshot (&surface->base,
-				     &_cairo_image_surface_backend);
+    image = _cairo_surface_has_snapshot (&surface->base,
+					 &_cairo_image_surface_backend);
     if (image != NULL) {
-	image = (cairo_image_surface_t *) cairo_surface_reference (&image->base);
+	image = cairo_surface_reference (image);
 	goto DONE;
     }
 
     image = _get_image (surface, FALSE, 0, 0, surface->width, surface->height);
-    if (unlikely (image->base.status))
-	return image->base.status;
+    if (unlikely (image->status))
+	return image->status;
 
-    _cairo_surface_attach_snapshot (&surface->base, &image->base, NULL);
+    _cairo_surface_attach_snapshot (&surface->base, image, NULL);
 
 DONE:
-    *image_out = image;
+    *image_out = (cairo_image_surface_t *) image;
     *image_extra = NULL;
     return CAIRO_STATUS_SUCCESS;
 }
@@ -629,20 +626,20 @@ _cairo_xcb_surface_flush (void *abstract_surface)
 
     status = surface->base.status;
     if (status == CAIRO_STATUS_SUCCESS && ! surface->base.finished) {
-	status = cairo_surface_status (&surface->fallback->base);
+	status = cairo_surface_status (surface->fallback);
 
 	if (status == CAIRO_STATUS_SUCCESS) {
-	    status = _put_image (surface, surface->fallback);
+	    status = _put_image (surface, (cairo_image_surface_t *)surface->fallback);
 	}
 
 	if (status == CAIRO_STATUS_SUCCESS) {
 	    _cairo_surface_attach_snapshot (&surface->base,
-					    &surface->fallback->base,
+					    surface->fallback,
 					    cairo_surface_finish);
 	}
     }
 
-    cairo_surface_destroy (&surface->fallback->base);
+    cairo_surface_destroy (surface->fallback);
     surface->fallback = NULL;
 
     return status;
@@ -653,16 +650,16 @@ _cairo_xcb_surface_map_to_image (void *abstract_surface,
 				 const cairo_rectangle_int_t *extents)
 {
     cairo_xcb_surface_t *surface = abstract_surface;
-    cairo_image_surface_t *image;
+    cairo_surface_t *image;
 
     if (surface->fallback)
-	return surface->fallback->base.backend->map_to_image (surface->fallback, extents);
+	return surface->fallback->backend->map_to_image (surface->fallback, extents);
 
     image = _get_image (surface, TRUE,
 			extents->x, extents->y,
 			extents->width, extents->height);
-    if (unlikely (image->base.status))
-	return &image->base;
+    if (unlikely (image->status))
+	return image;
 
     /* Do we have a deferred clear and this image surface does NOT cover the
      * whole xcb surface? Have to apply the clear in that case, else
@@ -675,14 +672,14 @@ _cairo_xcb_surface_map_to_image (void *abstract_surface,
 	       extents->height == surface->height)) {
 	cairo_status_t status = _cairo_xcb_surface_clear (surface);
 	if (unlikely (status)) {
-	    cairo_surface_destroy(&image->base);
+	    cairo_surface_destroy(image);
 	    return _cairo_surface_create_in_error (status);
 	}
     }
     surface->deferred_clear = FALSE;
 
-    cairo_surface_set_device_offset (&image->base, -extents->x, -extents->y);
-    return &image->base;
+    cairo_surface_set_device_offset (image, -extents->x, -extents->y);
+    return image;
 }
 
 static cairo_int_status_t
@@ -692,18 +689,19 @@ _cairo_xcb_surface_unmap (void *abstract_surface,
     cairo_xcb_surface_t *surface = abstract_surface;
 
     if (surface->fallback)
-	return surface->fallback->base.backend->unmap_image (surface->fallback, image);
+	return surface->fallback->backend->unmap_image (surface->fallback, image);
     return _put_image (abstract_surface, image);
 }
 
-static cairo_image_surface_t *
+static cairo_surface_t *
 _cairo_xcb_surface_fallback (cairo_xcb_surface_t *surface)
 {
-    cairo_image_surface_t *image;
+    cairo_surface_t *image;
+
     image = _get_image (surface, TRUE, 0, 0, surface->width, surface->height);
 
     /* If there was a deferred clear, _get_image applied it */
-    if (image->base.status == CAIRO_STATUS_SUCCESS)
+    if (image->status == CAIRO_STATUS_SUCCESS)
 	surface->deferred_clear = FALSE;
 
     return image;
@@ -730,7 +728,7 @@ _cairo_xcb_surface_paint (void			*abstract_surface,
 	surface->fallback = _cairo_xcb_surface_fallback (surface);
     }
 
-    return _cairo_surface_paint (&surface->fallback->base, op, source, clip);
+    return _cairo_surface_paint (surface->fallback, op, source, clip);
 }
 
 static cairo_int_status_t
@@ -757,7 +755,7 @@ _cairo_xcb_surface_mask (void			*abstract_surface,
 	surface->fallback = _cairo_xcb_surface_fallback (surface);
     }
 
-    return _cairo_surface_mask (&surface->fallback->base,
+    return _cairo_surface_mask (surface->fallback,
 				op, source, mask,
 				clip);
 }
@@ -799,7 +797,7 @@ _cairo_xcb_surface_stroke (void				*abstract_surface,
 	surface->fallback = _cairo_xcb_surface_fallback (surface);
     }
 
-    return _cairo_surface_stroke (&surface->fallback->base,
+    return _cairo_surface_stroke (surface->fallback,
 				  op, source,
 				  path, style,
 				  ctm, ctm_inverse,
@@ -838,7 +836,7 @@ _cairo_xcb_surface_fill (void			*abstract_surface,
 	surface->fallback = _cairo_xcb_surface_fallback (surface);
     }
 
-    return _cairo_surface_fill (&surface->fallback->base,
+    return _cairo_surface_fill (surface->fallback,
 				op, source,
 				path, fill_rule,
 				tolerance, antialias,
@@ -878,7 +876,7 @@ _cairo_xcb_surface_glyphs (void				*abstract_surface,
 	surface->fallback = _cairo_xcb_surface_fallback (surface);
     }
 
-    return _cairo_surface_show_text_glyphs (&surface->fallback->base,
+    return _cairo_surface_show_text_glyphs (surface->fallback,
 					    op, source,
 					    NULL, 0,
 					    glyphs, num_glyphs,
diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c
index dc3aac8..b2fa0a7 100644
--- a/src/cairo-xlib-surface.c
+++ b/src/cairo-xlib-surface.c
@@ -54,6 +54,7 @@
 #include "cairo-clip-private.h"
 #include "cairo-default-context-private.h"
 #include "cairo-error-private.h"
+#include "cairo-image-surface-private.h"
 #include "cairo-pattern-private.h"
 #include "cairo-region-private.h"
 #include "cairo-scaled-font-private.h"
diff --git a/src/cairo-xlib-xcb-surface.c b/src/cairo-xlib-xcb-surface.c
index 6da44a1..db58815 100644
--- a/src/cairo-xlib-xcb-surface.c
+++ b/src/cairo-xlib-xcb-surface.c
@@ -47,6 +47,7 @@
 #include "cairo-xlib-xrender-private.h"
 
 #include "cairo-default-context-private.h"
+#include "cairo-image-surface-private.h"
 
 #include <X11/Xlib-xcb.h>
 #include <X11/Xlibint.h>	/* For XESetCloseDisplay */
diff --git a/src/cairoint.h b/src/cairoint.h
index e47e14b..4c9d9c0 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -254,6 +254,7 @@ _cairo_isdigit (int c)
 #include "cairo-cache-private.h"
 #include "cairo-reference-count-private.h"
 #include "cairo-spans-private.h"
+#include "cairo-surface-private.h"
 
 cairo_private void
 _cairo_box_from_doubles (cairo_box_t *box,
@@ -795,7 +796,7 @@ struct _cairo_surface_backend {
      * FALSE the surface is considered to be
      * boundless and infinite bounds are used for it.
      */
-    cairo_warn cairo_bool_t
+    cairo_bool_t
     (*get_extents)		(void			 *surface,
 				 cairo_rectangle_int_t   *extents);
 
@@ -946,29 +947,6 @@ struct _cairo_surface_backend {
 					 void                   **image_extra);
 };
 
-#include "cairo-surface-private.h"
-
-struct _cairo_image_surface {
-    cairo_surface_t base;
-
-    pixman_format_code_t pixman_format;
-    cairo_format_t format;
-    unsigned char *data;
-
-    int width;
-    int height;
-    int stride;
-    int depth;
-
-    pixman_image_t *pixman_image;
-
-    unsigned owns_data : 1;
-    unsigned transparency : 2;
-    unsigned color : 2;
-};
-
-extern const cairo_private cairo_surface_backend_t _cairo_image_surface_backend;
-
 #define CAIRO_EXTEND_SURFACE_DEFAULT CAIRO_EXTEND_NONE
 #define CAIRO_EXTEND_GRADIENT_DEFAULT CAIRO_EXTEND_PAD
 #define CAIRO_FILTER_DEFAULT CAIRO_FILTER_GOOD
@@ -1850,7 +1828,7 @@ cairo_private cairo_bool_t
 _cairo_surface_is_similar (cairo_surface_t *surface_a,
 	                   cairo_surface_t *surface_b);
 
-cairo_private cairo_bool_t
+cairo_private_no_warn cairo_bool_t
 _cairo_surface_get_extents (cairo_surface_t         *surface,
 			    cairo_rectangle_int_t   *extents);
 


More information about the cairo-commit mailing list