[cairo-commit] 9 commits - src/cairo-analysis-surface.c src/cairo-backend-private.h src/cairo.c src/cairo-clip.c src/cairo-composite-rectangles.c src/cairo-debug.c src/cairo-default-context.c src/cairo-default-context-private.h src/cairo-directfb-surface.c src/cairo-ft-font.c src/cairo-gl-surface.c src/cairo-gstate.c src/cairo-gstate-private.h src/cairo-image-surface.c src/cairoint.h src/cairo-mesh-pattern-rasterizer.c src/cairo-os2-surface.c src/cairo-paginated-surface.c src/cairo-path.c src/cairo-path-private.h src/cairo-path-stroke.c src/cairo-pattern.c src/cairo-pattern-private.h src/cairo-pdf-shading-private.h src/cairo-pdf-surface.c src/cairo-private.h src/cairo-ps-surface.c src/cairo-qt-surface.cpp src/cairo-quartz-image-surface.c src/cairo-recording-surface.c src/cairo-recording-surface-private.h src/cairo-scaled-font.c src/cairo-scaled-font-subsets.c src/cairo-script-surface.c src/cairo-surface-fallback.c src/cairo-surface-offset.c src/cairo-surface-snapshot.c src/cairo-su rface-subsurface.c src/cairo-surface-wrapper.c src/cairo-svg-surface.c src/cairo-tee-surface.c src/cairo-type3-glyph-surface.c src/cairo-types-private.h src/cairo-vg-surface.c src/cairo-win32-printing-surface.c src/cairo-win32-surface.c 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/cairo-xml-surface.c src/drm src/Makefile.sources src/test-fallback16-surface.c src/test-fallback-surface.c src/test-null-surface.c src/test-paginated-surface.c src/test-wrapping-surface.c test/clip-complex-shape.c test/clip-complex-shape-eo-aa.ref.png test/clip-complex-shape-eo-mono.ref.png test/Makefile.am test/Makefile.refs test/Makefile.sources test/paint-clip-fill-aa.ref.png test/paint-clip-fill.c test/paint-clip-fill-mono.ref.png test/random-clips.c

Chris Wilson ickle at kemper.freedesktop.org
Sat Jul 16 12:47:48 PDT 2011


 src/Makefile.sources                    |    3 
 src/cairo-analysis-surface.c            |    4 
 src/cairo-backend-private.h             |  170 +++
 src/cairo-clip.c                        |    8 
 src/cairo-composite-rectangles.c        |    1 
 src/cairo-debug.c                       |    3 
 src/cairo-default-context-private.h     |   58 +
 src/cairo-default-context.c             | 1407 ++++++++++++++++++++++++++++++++
 src/cairo-directfb-surface.c            |    3 
 src/cairo-ft-font.c                     |    1 
 src/cairo-gl-surface.c                  |    3 
 src/cairo-gstate-private.h              |   39 
 src/cairo-gstate.c                      |  143 +--
 src/cairo-image-surface.c               |   13 
 src/cairo-mesh-pattern-rasterizer.c     |    2 
 src/cairo-os2-surface.c                 |    3 
 src/cairo-paginated-surface.c           |    9 
 src/cairo-path-private.h                |    4 
 src/cairo-path-stroke.c                 |    4 
 src/cairo-path.c                        |   98 --
 src/cairo-pattern-private.h             |  362 ++++++++
 src/cairo-pattern.c                     |   17 
 src/cairo-pdf-shading-private.h         |    1 
 src/cairo-pdf-surface.c                 |    3 
 src/cairo-private.h                     |   25 
 src/cairo-ps-surface.c                  |    3 
 src/cairo-qt-surface.cpp                |    3 
 src/cairo-quartz-image-surface.c        |    2 
 src/cairo-recording-surface-private.h   |    1 
 src/cairo-recording-surface.c           |    3 
 src/cairo-scaled-font-subsets.c         |    1 
 src/cairo-scaled-font.c                 |    4 
 src/cairo-script-surface.c              |    2 
 src/cairo-surface-fallback.c            |    1 
 src/cairo-surface-offset.c              |    1 
 src/cairo-surface-snapshot.c            |    1 
 src/cairo-surface-subsurface.c          |    9 
 src/cairo-surface-wrapper.c             |    1 
 src/cairo-svg-surface.c                 |    3 
 src/cairo-tee-surface.c                 |    3 
 src/cairo-type3-glyph-surface.c         |    3 
 src/cairo-types-private.h               |  128 --
 src/cairo-vg-surface.c                  |    3 
 src/cairo-win32-printing-surface.c      |    3 
 src/cairo-win32-surface.c               |    3 
 src/cairo-xcb-private.h                 |    4 
 src/cairo-xcb-surface-core.c            |    1 
 src/cairo-xcb-surface-render.c          |    5 
 src/cairo-xcb-surface.c                 |   68 -
 src/cairo-xlib-surface.c                |    6 
 src/cairo-xlib-xcb-surface.c            |    6 
 src/cairo-xml-surface.c                 |    3 
 src/cairo.c                             | 1040 +++++++++--------------
 src/cairoint.h                          |  180 ----
 src/drm/cairo-drm-gallium-surface.c     |    3 
 src/drm/cairo-drm-i915-surface.c        |    2 
 src/drm/cairo-drm-i965-surface.c        |    2 
 src/drm/cairo-drm-intel-surface.c       |    2 
 src/drm/cairo-drm-radeon-surface.c      |    2 
 src/test-fallback-surface.c             |    3 
 src/test-fallback16-surface.c           |    3 
 src/test-null-surface.c                 |    2 
 src/test-paginated-surface.c            |    2 
 src/test-wrapping-surface.c             |    3 
 test/Makefile.am                        |    2 
 test/Makefile.refs                      |    5 
 test/Makefile.sources                   |    3 
 test/clip-complex-shape-eo-aa.ref.png   |binary
 test/clip-complex-shape-eo-mono.ref.png |binary
 test/clip-complex-shape.c               |  114 ++
 test/paint-clip-fill-aa.ref.png         |binary
 test/paint-clip-fill-mono.ref.png       |binary
 test/paint-clip-fill.c                  |  106 ++
 test/random-clips.c                     |  217 ++++
 74 files changed, 3179 insertions(+), 1167 deletions(-)

New commits:
commit 27692ca75967b482ff1bd0ffbca8b4e3551776f7
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Sat Jul 16 20:45:43 2011 +0100

    test: Add random-clips to stress test clipping
    
    Not sure what the right results are, so refs will come later. The output
    looks superficially right, but the *code* is known to be buggy...
    
    (And hopefully this has captured a few of those bugs.)
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/test/Makefile.sources b/test/Makefile.sources
index 56a8d32..46ce337 100644
--- a/test/Makefile.sources
+++ b/test/Makefile.sources
@@ -212,6 +212,7 @@ test_sources = \
 	push-group-path-offset.c			\
 	radial-gradient.c				\
 	radial-gradient-extend.c			\
+	random-clips.c			\
 	random-intersections-eo.c			\
 	random-intersections-nonzero.c			\
 	random-intersections-curves-eo.c		\
diff --git a/test/random-clips.c b/test/random-clips.c
new file mode 100644
index 0000000..9fed28e
--- /dev/null
+++ b/test/random-clips.c
@@ -0,0 +1,217 @@
+/*
+ * Copyright © 2006 M Joonas Pihlaja
+ * Copyright © 2011 Chris Wilson
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Authors:
+ *   M Joonas Pihlaja <jpihlaja at cc.helsinki.fi>
+ *   Chris Wilson <chris at chris-wilson.co.uk>
+ */
+#include "cairo-test.h"
+
+#define SIZE 512
+#define STEP (512+2)
+#define NUM_SEGMENTS 128
+
+static uint32_t state;
+
+static double
+uniform_random (double minval, double maxval)
+{
+    static uint32_t const poly = 0x9a795537U;
+    uint32_t n = 32;
+    while (n-->0)
+	state = 2*state < state ? (2*state ^ poly) : 2*state;
+    return minval + state * (maxval - minval) / 4294967296.0;
+}
+
+static void nz_path (cairo_t *cr)
+{
+    int i;
+
+    state = 0xc0ffee;
+
+    cairo_move_to (cr, 0, 0);
+    for (i = 0; i < NUM_SEGMENTS; i++) {
+	double x = uniform_random (0, SIZE);
+	double y = uniform_random (0, SIZE);
+	cairo_line_to (cr, x, y);
+    }
+    cairo_close_path (cr);
+}
+
+static void region_path (cairo_t *cr)
+{
+    int i;
+
+    state = 0xc0ffee;
+
+    for (i = 0; i < NUM_SEGMENTS; i++) {
+	int x = uniform_random (0, SIZE);
+	int y = uniform_random (0, SIZE);
+	int w = uniform_random (0, 40);
+	int h = uniform_random (0, 40);
+	cairo_rectangle (cr, x, y, w, h);
+    }
+}
+
+static void rectangle_path (cairo_t *cr)
+{
+    int i;
+
+    state = 0xc0ffee;
+
+    for (i = 0; i < NUM_SEGMENTS; i++) {
+	double x = uniform_random (0, SIZE);
+	double y = uniform_random (0, SIZE);
+	double w = uniform_random (0, 40);
+	double h = uniform_random (0, 40);
+	cairo_rectangle (cr, x, y, w, h);
+    }
+}
+
+static void arc_path (cairo_t *cr)
+{
+    int i;
+
+    state = 0xc0ffee;
+
+    for (i = 0; i < NUM_SEGMENTS; i++) {
+	double x = uniform_random (0, SIZE);
+	double y = uniform_random (0, SIZE);
+	double r = uniform_random (0, 20);
+	cairo_new_sub_path (cr);
+	cairo_arc (cr, x, y, r, 0, 2*M_PI);
+    }
+}
+
+
+static void nz_fill_stroke (cairo_t *cr)
+{
+    nz_path (cr);
+
+    cairo_set_source_rgb (cr, 1, 0, 0);
+    cairo_fill_preserve (cr);
+    cairo_set_source_rgb (cr, 0, 1, 0);
+    cairo_set_line_width (cr, 1.0);
+    cairo_stroke (cr);
+}
+
+static void clip_to_quadrant (cairo_t *cr)
+{
+    cairo_rectangle (cr, 0, 0, SIZE, SIZE);
+    cairo_clip (cr);
+}
+
+static cairo_test_status_t
+draw (cairo_t *cr, int width, int height)
+{
+    cairo_set_source_rgb (cr, 0, 0, 0);
+    cairo_paint (cr);
+
+    cairo_set_fill_rule (cr, CAIRO_FILL_RULE_WINDING);
+
+    state = 0xc0ffee;
+    cairo_translate (cr, 1, 1);
+
+    /* no clipping */
+    cairo_save (cr); {
+	clip_to_quadrant (cr);
+
+	nz_fill_stroke (cr);
+    } cairo_restore (cr);
+
+    cairo_translate (cr, STEP, 0);
+
+    /* random clipping */
+    cairo_save (cr); {
+	clip_to_quadrant (cr);
+
+	nz_path (cr);
+	cairo_clip (cr);
+
+	nz_fill_stroke (cr);
+    } cairo_restore (cr);
+
+    cairo_translate (cr, STEP, 0);
+
+    /* regional clipping */
+    cairo_save (cr); {
+	clip_to_quadrant (cr);
+
+	region_path (cr);
+	cairo_clip (cr);
+
+	nz_fill_stroke (cr);
+    } cairo_restore (cr);
+
+    cairo_translate (cr, -2*STEP, STEP);
+
+    /* rectangular clipping */
+    cairo_save (cr); {
+	clip_to_quadrant (cr);
+
+	rectangle_path (cr);
+	cairo_clip (cr);
+
+	nz_fill_stroke (cr);
+    } cairo_restore (cr);
+
+    cairo_translate (cr, STEP, 0);
+
+    /* circular clipping */
+    cairo_save (cr); {
+	clip_to_quadrant (cr);
+
+	arc_path (cr);
+	cairo_clip (cr);
+
+	nz_fill_stroke (cr);
+    } cairo_restore (cr);
+
+    cairo_translate (cr, STEP, 0);
+
+    /* all-of-the-above clipping */
+    cairo_save (cr); {
+	clip_to_quadrant (cr);
+
+	nz_path (cr);
+	cairo_clip (cr);
+	region_path (cr);
+	cairo_clip (cr);
+	rectangle_path (cr);
+	cairo_clip (cr);
+	arc_path (cr);
+	cairo_clip (cr);
+
+	nz_fill_stroke (cr);
+    } cairo_restore (cr);
+
+    return CAIRO_TEST_SUCCESS;
+}
+
+CAIRO_TEST (random_clip,
+	    "Tests the clip generation and intersection computation",
+	    "trap, clip", /* keywords */
+	    NULL, /* requirements */
+	    3*STEP+2, 2*STEP+2,
+	    NULL, draw)
commit b8f43617a98aeb6c10d554ed11b48a83fc9b5129
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Sat Jul 16 20:45:03 2011 +0100

    test: Always compile cairo-test-suite
    
    I'm tired of having to explicitly type make cairo-test-suite.
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/test/Makefile.am b/test/Makefile.am
index 14c16b0..f44ce06 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -73,6 +73,8 @@ endif
 endif
 test_sources += $(test)
 
+noinst_PROGRAMS = cairo-test-suite # always build
+
 TESTS += cairo-test-suite$(EXEEXT)
 
 cairo-test-constructors.c: Makefile $(test_sources) make-cairo-test-constructors.sh
commit 54ae2e1619ba2f1039c8e652b2f24d7a72ab8395
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Thu Jul 14 23:40:38 2011 +0100

    xcb: Remove more bits of drm integration
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/cairo-xcb-private.h b/src/cairo-xcb-private.h
index 420a879..6aca5b9 100644
--- a/src/cairo-xcb-private.h
+++ b/src/cairo-xcb-private.h
@@ -85,9 +85,6 @@ struct _cairo_xcb_surface {
     cairo_xcb_connection_t *connection;
     cairo_xcb_screen_t *screen;
 
-    cairo_surface_t *drm;
-    cairo_bool_t marked_dirty;
-
     xcb_drawable_t drawable;
     cairo_bool_t owns_pixmap;
     int use_pixmap;
diff --git a/src/cairo-xcb-surface-render.c b/src/cairo-xcb-surface-render.c
index 065e896..fc349a3 100644
--- a/src/cairo-xcb-surface-render.c
+++ b/src/cairo-xcb-surface-render.c
@@ -981,10 +981,6 @@ _copy_to_picture (cairo_xcb_surface_t *source)
 	    return (cairo_xcb_picture_t *) _cairo_surface_create_in_error (status);
     }
 
-    /* XXX two level device locking, ensure we release the xcb device mutex? */
-    if (source->drm != NULL)
-	cairo_surface_flush (source->drm);
-
     picture = _cairo_xcb_picture_create (source->screen,
 					 source->xrender_format,
 					 source->pixman_format,
diff --git a/src/cairo-xcb-surface.c b/src/cairo-xcb-surface.c
index a890fe8..92b596e 100644
--- a/src/cairo-xcb-surface.c
+++ b/src/cairo-xcb-surface.c
@@ -491,9 +491,6 @@ _get_image (cairo_xcb_surface_t		 *surface,
 
     _cairo_xcb_connection_release (connection);
 
-    /* synchronisation point */
-    surface->marked_dirty = FALSE;
-
     *image_out = image;
     return CAIRO_STATUS_SUCCESS;
 
@@ -511,11 +508,6 @@ _cairo_xcb_surface_acquire_source_image (void *abstract_surface,
     cairo_image_surface_t *image;
     cairo_status_t status;
 
-    if (surface->drm != NULL && ! surface->marked_dirty) {
-	return _cairo_surface_acquire_source_image (surface->drm,
-						    image_out, image_extra);
-    }
-
     if (surface->fallback != NULL) {
 	image = (cairo_image_surface_t *) cairo_surface_reference (surface->fallback);
 	goto DONE;
@@ -546,12 +538,7 @@ _cairo_xcb_surface_release_source_image (void *abstract_surface,
 					 cairo_image_surface_t *image,
 					 void *image_extra)
 {
-    cairo_xcb_surface_t *surface = abstract_surface;
-
-    if (surface->drm != NULL && !surface->marked_dirty)
-	_cairo_surface_release_source_image (surface->drm, image, image_extra);
-    else
-	cairo_surface_destroy (&image->base);
+    cairo_surface_destroy (&image->base);
 }
 
 static cairo_bool_t
@@ -656,9 +643,6 @@ _cairo_xcb_surface_flush (void *abstract_surface)
     cairo_xcb_surface_t *surface = abstract_surface;
     cairo_status_t status;
 
-    if (surface->drm != NULL && ! surface->marked_dirty)
-	return surface->drm->backend->flush (surface->drm);
-
     if (likely (surface->fallback == NULL)) {
 	status = CAIRO_STATUS_SUCCESS;
 	if (! surface->base.finished && surface->deferred_clear)
@@ -689,16 +673,6 @@ _cairo_xcb_surface_flush (void *abstract_surface)
     return status;
 }
 
-static cairo_status_t
-_cairo_xcb_surface_mark_dirty (void *abstract_surface,
-			       int x, int y,
-			       int width, int height)
-{
-    cairo_xcb_surface_t *surface = abstract_surface;
-    surface->marked_dirty = TRUE;
-    return CAIRO_STATUS_SUCCESS;
-}
-
 static cairo_surface_t *
 _cairo_xcb_surface_map_to_image (cairo_xcb_surface_t *surface)
 {
@@ -721,9 +695,6 @@ _cairo_xcb_surface_paint (void			*abstract_surface,
     cairo_xcb_surface_t *surface = abstract_surface;
     cairo_status_t status;
 
-    if (surface->drm != NULL && ! surface->marked_dirty)
-	return _cairo_surface_paint (surface->drm, op, source, clip);
-
     if (surface->fallback == NULL) {
 	status = _cairo_xcb_surface_cairo_paint (surface, op, source, clip);
 	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
@@ -749,9 +720,6 @@ _cairo_xcb_surface_mask (void			*abstract_surface,
     cairo_xcb_surface_t *surface = abstract_surface;
     cairo_status_t status;
 
-    if (surface->drm != NULL && ! surface->marked_dirty)
-	return _cairo_surface_mask (surface->drm, op, source, mask, clip);
-
     if (surface->fallback == NULL) {
 	status =  _cairo_xcb_surface_cairo_mask (surface,
 						 op, source, mask, clip);
@@ -786,15 +754,6 @@ _cairo_xcb_surface_stroke (void				*abstract_surface,
     cairo_xcb_surface_t *surface = abstract_surface;
     cairo_status_t status;
 
-    if (surface->drm != NULL && ! surface->marked_dirty) {
-	return _cairo_surface_stroke (surface->drm,
-				      op, source,
-				      path, style,
-				      ctm, ctm_inverse,
-				      tolerance, antialias,
-				      clip);
-    }
-
     if (surface->fallback == NULL) {
 	status = _cairo_xcb_surface_cairo_stroke (surface, op, source,
 						  path, style,
@@ -838,14 +797,6 @@ _cairo_xcb_surface_fill (void			*abstract_surface,
     cairo_xcb_surface_t *surface = abstract_surface;
     cairo_status_t status;
 
-    if (surface->drm != NULL && ! surface->marked_dirty) {
-	return _cairo_surface_fill (surface->drm,
-				    op, source,
-				    path, fill_rule,
-				    tolerance, antialias,
-				    clip);
-    }
-
     if (surface->fallback == NULL) {
 	status = _cairo_xcb_surface_cairo_fill (surface, op, source,
 						path, fill_rule,
@@ -886,16 +837,6 @@ _cairo_xcb_surface_glyphs (void				*abstract_surface,
 
     *num_remaining = 0;
 
-    if (surface->drm != NULL && ! surface->marked_dirty) {
-	return _cairo_surface_show_text_glyphs (surface->drm,
-						op, source,
-						NULL, 0,
-						glyphs, num_glyphs,
-						NULL, 0, 0,
-						scaled_font,
-						clip);
-    }
-
     if (surface->fallback == NULL) {
 	status = _cairo_xcb_surface_cairo_glyphs (surface,
 						  op, source,
@@ -946,7 +887,7 @@ const cairo_surface_backend_t _cairo_xcb_surface_backend = {
     _cairo_xcb_surface_get_font_options,
 
     _cairo_xcb_surface_flush,
-    _cairo_xcb_surface_mark_dirty,
+    NULL,
     _cairo_xcb_surface_scaled_font_fini,
     _cairo_xcb_surface_scaled_glyph_fini,
 
@@ -1001,8 +942,6 @@ _cairo_xcb_surface_create_internal (cairo_xcb_screen_t		*screen,
 
     surface->flags = screen->connection->flags;
 
-    surface->marked_dirty = FALSE;
-
     return &surface->base;
 }
 
commit 2458120dee350cd1b49f999f64b17a895a4b6607
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Thu Jul 14 18:35:32 2011 +0100

    pattern: Add observer hooks
    
    In order for custom context to automatically track when a pattern is
    modify after being set on the context (and before it is used in an
    operator), we need for there to be a callback when the pattern is
    modified.
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/Makefile.sources b/src/Makefile.sources
index 03b2030..5371e81 100644
--- a/src/Makefile.sources
+++ b/src/Makefile.sources
@@ -85,6 +85,7 @@ cairo_private = \
 	cairo-paginated-surface-private.h \
 	cairo-path-fixed-private.h \
 	cairo-path-private.h \
+	cairo-pattern-private.h \
 	cairo-private.h \
 	cairo-recording-surface-private.h \
 	cairo-reference-count-private.h \
diff --git a/src/cairo-clip.c b/src/cairo-clip.c
index 929c107..9054b4e 100644
--- a/src/cairo-clip.c
+++ b/src/cairo-clip.c
@@ -45,6 +45,7 @@
 #include "cairo-freed-pool-private.h"
 #include "cairo-gstate-private.h"
 #include "cairo-path-fixed-private.h"
+#include "cairo-pattern-private.h"
 #include "cairo-composite-rectangles-private.h"
 #include "cairo-region-private.h"
 
diff --git a/src/cairo-composite-rectangles.c b/src/cairo-composite-rectangles.c
index 0aebee3..4240de3 100644
--- a/src/cairo-composite-rectangles.c
+++ b/src/cairo-composite-rectangles.c
@@ -37,6 +37,7 @@
 
 #include "cairo-error-private.h"
 #include "cairo-composite-rectangles-private.h"
+#include "cairo-pattern-private.h"
 
 /* A collection of routines to facilitate writing compositors. */
 
diff --git a/src/cairo-debug.c b/src/cairo-debug.c
index f8ef717..9b16de8 100644
--- a/src/cairo-debug.c
+++ b/src/cairo-debug.c
@@ -35,6 +35,7 @@
 
 #include "cairoint.h"
 
+
 /**
  * cairo_debug_reset_static_data:
  *
diff --git a/src/cairo-default-context.c b/src/cairo-default-context.c
index dbd014a..cec8016 100644
--- a/src/cairo-default-context.c
+++ b/src/cairo-default-context.c
@@ -47,6 +47,7 @@
 #include "cairo-error-private.h"
 #include "cairo-freed-pool-private.h"
 #include "cairo-path-private.h"
+#include "cairo-pattern-private.h"
 
 #define CAIRO_TOLERANCE_MINIMUM	_cairo_fixed_to_double(1)
 
diff --git a/src/cairo-ft-font.c b/src/cairo-ft-font.c
index e6d7de3..d007fd2 100644
--- a/src/cairo-ft-font.c
+++ b/src/cairo-ft-font.c
@@ -43,6 +43,7 @@
 
 #include "cairo-error-private.h"
 #include "cairo-ft-private.h"
+#include "cairo-pattern-private.h"
 
 #include <float.h>
 
diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c
index 7aea6c1..a7eced6 100644
--- a/src/cairo-gstate.c
+++ b/src/cairo-gstate.c
@@ -40,6 +40,7 @@
 #include "cairo-clip-private.h"
 #include "cairo-error-private.h"
 #include "cairo-gstate-private.h"
+#include "cairo-pattern-private.h"
 
 #if _XOPEN_SOURCE >= 600 || defined (_ISOC99_SOURCE)
 #define ISFINITE(x) isfinite (x)
diff --git a/src/cairo-image-surface.c b/src/cairo-image-surface.c
index 71d8d88..be42724 100644
--- a/src/cairo-image-surface.c
+++ b/src/cairo-image-surface.c
@@ -45,6 +45,7 @@
 #include "cairo-default-context-private.h"
 #include "cairo-error-private.h"
 #include "cairo-region-private.h"
+#include "cairo-pattern-private.h"
 #include "cairo-scaled-font-private.h"
 #include "cairo-surface-snapshot-private.h"
 #include "cairo-surface-subsurface-private.h"
diff --git a/src/cairo-mesh-pattern-rasterizer.c b/src/cairo-mesh-pattern-rasterizer.c
index ed964bb..9c9d0ec 100644
--- a/src/cairo-mesh-pattern-rasterizer.c
+++ b/src/cairo-mesh-pattern-rasterizer.c
@@ -36,6 +36,8 @@
 
 #include "cairoint.h"
 
+#include "cairo-pattern-private.h"
+
 /*
  * Rasterizer for mesh patterns.
  *
diff --git a/src/cairo-pattern-private.h b/src/cairo-pattern-private.h
new file mode 100644
index 0000000..af9cb43
--- /dev/null
+++ b/src/cairo-pattern-private.h
@@ -0,0 +1,362 @@
+/* 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_PATTERN_PRIVATE_H
+#define CAIRO_PATTERN_PRIVATE_H
+
+#include "cairo-types-private.h"
+#include "cairo-list-private.h"
+
+CAIRO_BEGIN_DECLS
+
+typedef struct _cairo_pattern_observer cairo_pattern_observer_t;
+
+enum {
+    CAIRO_PATTERN_NOTIFY_MATRIX = 0x1,
+    CAIRO_PATTERN_NOTIFY_FILTER = 0x2,
+    CAIRO_PATTERN_NOTIFY_EXTEND = 0x4,
+    CAIRO_PATTERN_NOTIFY_OPACITY = 0x9,
+};
+
+struct _cairo_pattern_observer {
+    void (*notify) (cairo_pattern_observer_t *,
+		    cairo_pattern_t *pattern,
+		    unsigned int flags);
+    cairo_list_t link;
+};
+
+struct _cairo_pattern {
+    cairo_pattern_type_t	type;
+    cairo_reference_count_t	ref_count;
+    cairo_status_t		status;
+    cairo_user_data_array_t	user_data;
+
+    cairo_matrix_t		matrix;
+    cairo_filter_t		filter;
+    cairo_extend_t		extend;
+    double			opacity;
+
+    cairo_bool_t		has_component_alpha;
+
+    cairo_list_t		observers;
+};
+
+struct _cairo_solid_pattern {
+    cairo_pattern_t base;
+    cairo_color_t color;
+};
+
+typedef struct _cairo_surface_pattern {
+    cairo_pattern_t base;
+
+    cairo_surface_t *surface;
+} cairo_surface_pattern_t;
+
+typedef struct _cairo_gradient_stop {
+    double offset;
+    cairo_color_stop_t color;
+} cairo_gradient_stop_t;
+
+typedef struct _cairo_gradient_pattern {
+    cairo_pattern_t base;
+
+    unsigned int	    n_stops;
+    unsigned int	    stops_size;
+    cairo_gradient_stop_t  *stops;
+    cairo_gradient_stop_t   stops_embedded[2];
+} cairo_gradient_pattern_t;
+
+typedef struct _cairo_linear_pattern {
+    cairo_gradient_pattern_t base;
+
+    cairo_point_double_t pd1;
+    cairo_point_double_t pd2;
+} cairo_linear_pattern_t;
+
+typedef struct _cairo_radial_pattern {
+    cairo_gradient_pattern_t base;
+
+    cairo_circle_double_t cd1;
+    cairo_circle_double_t cd2;
+} cairo_radial_pattern_t;
+
+typedef union {
+    cairo_gradient_pattern_t base;
+
+    cairo_linear_pattern_t linear;
+    cairo_radial_pattern_t radial;
+} cairo_gradient_pattern_union_t;
+
+/*
+ * A mesh patch is a tensor-product patch (bicubic Bezier surface
+ * patch). It has 16 control points. Each set of 4 points along the
+ * sides of the 4x4 grid of control points is a Bezier curve that
+ * defines one side of the patch. A color is assigned to each
+ * corner. The inner 4 points provide additional control over the
+ * shape and the color mapping.
+ *
+ * Cairo uses the same convention as the PDF Reference for numbering
+ * the points and side of the patch.
+ *
+ *
+ *                      Side 1
+ *
+ *          p[0][3] p[1][3] p[2][3] p[3][3]
+ * Side 0   p[0][2] p[1][2] p[2][2] p[3][2]  Side 2
+ *          p[0][1] p[1][1] p[2][1] p[3][1]
+ *          p[0][0] p[1][0] p[2][0] p[3][0]
+ *
+ *                      Side 3
+ *
+ *
+ *   Point            Color
+ *  -------------------------
+ *  points[0][0]    colors[0]
+ *  points[0][3]    colors[1]
+ *  points[3][3]    colors[2]
+ *  points[3][0]    colors[3]
+ */
+
+typedef struct _cairo_mesh_patch {
+    cairo_point_double_t points[4][4];
+    cairo_color_t colors[4];
+} cairo_mesh_patch_t;
+
+typedef struct _cairo_mesh_pattern {
+    cairo_pattern_t base;
+
+    cairo_array_t patches;
+    cairo_mesh_patch_t *current_patch;
+    int current_side;
+    cairo_bool_t has_control_point[4];
+    cairo_bool_t has_color[4];
+} cairo_mesh_pattern_t;
+
+typedef union {
+    cairo_pattern_type_t	    type;
+    cairo_pattern_t		    base;
+
+    cairo_solid_pattern_t	    solid;
+    cairo_surface_pattern_t	    surface;
+    cairo_gradient_pattern_union_t  gradient;
+    cairo_mesh_pattern_t	    mesh;
+} cairo_pattern_union_t;
+
+
+/* cairo-pattern.c */
+
+cairo_private cairo_pattern_t *
+_cairo_pattern_create_in_error (cairo_status_t status);
+
+cairo_private cairo_status_t
+_cairo_pattern_create_copy (cairo_pattern_t	  **pattern,
+			    const cairo_pattern_t  *other);
+
+cairo_private cairo_status_t
+_cairo_pattern_init_copy (cairo_pattern_t	*pattern,
+			  const cairo_pattern_t *other);
+
+cairo_private void
+_cairo_pattern_init_static_copy (cairo_pattern_t	*pattern,
+				 const cairo_pattern_t *other);
+
+cairo_private cairo_status_t
+_cairo_pattern_init_snapshot (cairo_pattern_t       *pattern,
+			      const cairo_pattern_t *other);
+
+cairo_private void
+_cairo_pattern_init_solid (cairo_solid_pattern_t	*pattern,
+			   const cairo_color_t		*color);
+
+cairo_private void
+_cairo_pattern_init_for_surface (cairo_surface_pattern_t *pattern,
+				 cairo_surface_t *surface);
+
+cairo_private void
+_cairo_pattern_fini (cairo_pattern_t *pattern);
+
+cairo_private void
+_cairo_pattern_fini_snapshot (cairo_pattern_t *pattern);
+
+cairo_private cairo_pattern_t *
+_cairo_pattern_create_solid (const cairo_color_t	*color);
+
+cairo_private void
+_cairo_pattern_transform (cairo_pattern_t      *pattern,
+			  const cairo_matrix_t *ctm_inverse);
+
+cairo_private cairo_bool_t
+_cairo_pattern_is_opaque_solid (const cairo_pattern_t *pattern);
+
+cairo_private cairo_bool_t
+_cairo_pattern_is_opaque (const cairo_pattern_t *pattern,
+			  const cairo_rectangle_int_t *extents);
+
+cairo_private cairo_bool_t
+_cairo_pattern_is_clear (const cairo_pattern_t *pattern);
+
+cairo_private cairo_bool_t
+_cairo_gradient_pattern_is_solid (const cairo_gradient_pattern_t *gradient,
+				  const cairo_rectangle_int_t *extents,
+				  cairo_color_t *color);
+
+cairo_private void
+_cairo_gradient_pattern_fit_to_range (const cairo_gradient_pattern_t *gradient,
+				      double			      max_value,
+				      cairo_matrix_t                 *out_matrix,
+				      cairo_circle_double_t	      out_circle[2]);
+
+cairo_private cairo_bool_t
+_cairo_radial_pattern_focus_is_inside (const cairo_radial_pattern_t *radial);
+
+cairo_private void
+_cairo_gradient_pattern_box_to_parameter (const cairo_gradient_pattern_t *gradient,
+					  double x0, double y0,
+					  double x1, double y1,
+					  double tolerance,
+					  double out_range[2]);
+
+cairo_private void
+_cairo_gradient_pattern_interpolate (const cairo_gradient_pattern_t *gradient,
+				     double			     t,
+				     cairo_circle_double_t	    *out_circle);
+
+cairo_private void
+_cairo_pattern_alpha_range (const cairo_pattern_t *pattern,
+			    double                *out_min,
+			    double                *out_max);
+
+cairo_private cairo_bool_t
+_cairo_mesh_pattern_coord_box (const cairo_mesh_pattern_t *mesh,
+			       double                     *out_xmin,
+			       double                     *out_ymin,
+			       double                     *out_xmax,
+			       double                     *out_ymax);
+
+enum {
+    CAIRO_PATTERN_ACQUIRE_NONE = 0x0,
+    CAIRO_PATTERN_ACQUIRE_NO_REFLECT = 0x1,
+};
+cairo_private cairo_int_status_t
+_cairo_pattern_acquire_surface (const cairo_pattern_t	   *pattern,
+				cairo_surface_t		   *dst,
+				int			   x,
+				int			   y,
+				unsigned int		   width,
+				unsigned int		   height,
+				unsigned int		   flags,
+				cairo_surface_t		   **surface_out,
+				cairo_surface_attributes_t *attributes);
+
+cairo_private void
+_cairo_pattern_release_surface (const cairo_pattern_t	   *pattern,
+				cairo_surface_t		   *surface,
+				cairo_surface_attributes_t *attributes);
+
+cairo_private cairo_int_status_t
+_cairo_pattern_acquire_surfaces (const cairo_pattern_t	    *src,
+				 const cairo_pattern_t	    *mask,
+				 cairo_surface_t	    *dst,
+				 int			    src_x,
+				 int			    src_y,
+				 int			    mask_x,
+				 int			    mask_y,
+				 unsigned int		    width,
+				 unsigned int		    height,
+				 unsigned int		    flags,
+				 cairo_surface_t	    **src_out,
+				 cairo_surface_t	    **mask_out,
+				 cairo_surface_attributes_t *src_attributes,
+				 cairo_surface_attributes_t *mask_attributes);
+
+cairo_private void
+_cairo_pattern_get_extents (const cairo_pattern_t	    *pattern,
+			    cairo_rectangle_int_t           *extents);
+
+cairo_private unsigned long
+_cairo_pattern_hash (const cairo_pattern_t *pattern);
+
+cairo_private unsigned long
+_cairo_linear_pattern_hash (unsigned long hash,
+			    const cairo_linear_pattern_t *linear);
+
+cairo_private unsigned long
+_cairo_radial_pattern_hash (unsigned long hash,
+			    const cairo_radial_pattern_t *radial);
+
+cairo_private cairo_bool_t
+_cairo_linear_pattern_equal (const cairo_linear_pattern_t *a,
+			     const cairo_linear_pattern_t *b);
+
+cairo_private unsigned long
+_cairo_pattern_size (const cairo_pattern_t *pattern);
+
+cairo_private cairo_bool_t
+_cairo_radial_pattern_equal (const cairo_radial_pattern_t *a,
+			     const cairo_radial_pattern_t *b);
+
+cairo_private cairo_bool_t
+_cairo_pattern_equal (const cairo_pattern_t *a,
+		      const cairo_pattern_t *b);
+
+static inline void
+_cairo_pattern_add_observer (cairo_pattern_t *pattern,
+			     cairo_pattern_observer_t *observer,
+			     void (*func) (cairo_pattern_observer_t *,
+					   cairo_pattern_t *,
+					   unsigned int))
+{
+    observer->notify = func;
+    cairo_list_add (&observer->link, &pattern->observers);
+}
+
+/* cairo-mesh-pattern-rasterizer.c */
+
+cairo_private void
+_cairo_mesh_pattern_rasterize (const cairo_mesh_pattern_t *mesh,
+			       void                       *data,
+			       int                         width,
+			       int                         height,
+			       int                         stride,
+			       double                      x_offset,
+			       double                      y_offset);
+
+
+
+CAIRO_END_DECLS
+
+#endif /* CAIRO_PATTERN_PRIVATE */
+
+
diff --git a/src/cairo-pattern.c b/src/cairo-pattern.c
index 7fab4f3..b14a5f8 100644
--- a/src/cairo-pattern.c
+++ b/src/cairo-pattern.c
@@ -32,6 +32,7 @@
 #include "cairo-error-private.h"
 #include "cairo-freed-pool-private.h"
 #include "cairo-path-private.h"
+#include "cairo-pattern-private.h"
 
 #include <float.h>
 
@@ -111,6 +112,16 @@ const cairo_solid_pattern_t _cairo_pattern_white = {
     { 1., 1., 1., 1., 0xffff, 0xffff, 0xffff, 0xffff },/* color (double rgba, short rgba) */
 };
 
+static void
+_cairo_pattern_notify_observers (cairo_pattern_t *pattern,
+				 unsigned int flags)
+{
+    cairo_pattern_observer_t *pos;
+
+    cairo_list_foreach_entry (pos, cairo_pattern_observer_t, &pattern->observers, link)
+	pos->notify (pos, pattern, flags);
+}
+
 /**
  * _cairo_pattern_set_error:
  * @pattern: a pattern
@@ -180,10 +191,13 @@ _cairo_pattern_init (cairo_pattern_t *pattern, cairo_pattern_type_t type)
 	pattern->extend = CAIRO_EXTEND_GRADIENT_DEFAULT;
 
     pattern->filter    = CAIRO_FILTER_DEFAULT;
+    pattern->opacity   = 1.0;
 
     pattern->has_component_alpha = FALSE;
 
     cairo_matrix_init_identity (&pattern->matrix);
+
+    cairo_list_init (&pattern->observers);
 }
 
 static cairo_status_t
@@ -1916,6 +1930,7 @@ cairo_pattern_set_matrix (cairo_pattern_t      *pattern,
 	return;
 
     pattern->matrix = *matrix;
+    _cairo_pattern_notify_observers (pattern, CAIRO_PATTERN_NOTIFY_MATRIX);
 
     inverse = *matrix;
     status = cairo_matrix_invert (&inverse);
@@ -1964,6 +1979,7 @@ cairo_pattern_set_filter (cairo_pattern_t *pattern, cairo_filter_t filter)
 	return;
 
     pattern->filter = filter;
+    _cairo_pattern_notify_observers (pattern, CAIRO_PATTERN_NOTIFY_FILTER);
 }
 
 /**
@@ -2001,6 +2017,7 @@ cairo_pattern_set_extend (cairo_pattern_t *pattern, cairo_extend_t extend)
 	return;
 
     pattern->extend = extend;
+    _cairo_pattern_notify_observers (pattern, CAIRO_PATTERN_NOTIFY_EXTEND);
 }
 
 /**
diff --git a/src/cairo-pdf-shading-private.h b/src/cairo-pdf-shading-private.h
index dcf244e..f059d7f 100644
--- a/src/cairo-pdf-shading-private.h
+++ b/src/cairo-pdf-shading-private.h
@@ -39,6 +39,7 @@
 
 #include "cairo-compiler-private.h"
 #include "cairo-types-private.h"
+#include "cairo-pattern-private.h"
 
 
 typedef struct _cairo_pdf_shading {
diff --git a/src/cairo-recording-surface-private.h b/src/cairo-recording-surface-private.h
index d08b709..3d8cba3 100644
--- a/src/cairo-recording-surface-private.h
+++ b/src/cairo-recording-surface-private.h
@@ -39,6 +39,7 @@
 
 #include "cairoint.h"
 #include "cairo-path-fixed-private.h"
+#include "cairo-pattern-private.h"
 #include "cairo-clip-private.h"
 
 typedef enum {
diff --git a/src/cairo-scaled-font.c b/src/cairo-scaled-font.c
index 3f37e1c..c6c599b 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-pattern-private.h"
 #include "cairo-scaled-font-private.h"
 
 #if _XOPEN_SOURCE >= 600 || defined (_ISOC99_SOURCE)
diff --git a/src/cairo-surface-fallback.c b/src/cairo-surface-fallback.c
index ca7a051..5a30d4f 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-pattern-private.h"
 #include "cairo-region-private.h"
 #include "cairo-spans-private.h"
 #include "cairo-surface-fallback-private.h"
diff --git a/src/cairo-surface-offset.c b/src/cairo-surface-offset.c
index fdbe1a1..c36196e 100644
--- a/src/cairo-surface-offset.c
+++ b/src/cairo-surface-offset.c
@@ -38,6 +38,7 @@
 #include "cairoint.h"
 
 #include "cairo-error-private.h"
+#include "cairo-pattern-private.h"
 #include "cairo-surface-offset-private.h"
 
 /* A collection of routines to facilitate drawing to an alternate surface. */
diff --git a/src/cairo-surface-wrapper.c b/src/cairo-surface-wrapper.c
index 9667305..a76003b 100644
--- a/src/cairo-surface-wrapper.c
+++ b/src/cairo-surface-wrapper.c
@@ -38,6 +38,7 @@
 #include "cairoint.h"
 
 #include "cairo-error-private.h"
+#include "cairo-pattern-private.h"
 #include "cairo-surface-wrapper-private.h"
 
 /* A collection of routines to facilitate surface wrapping */
diff --git a/src/cairo-types-private.h b/src/cairo-types-private.h
index 5460a42..8881055 100644
--- a/src/cairo-types-private.h
+++ b/src/cairo-types-private.h
@@ -393,120 +393,6 @@ struct _cairo_mime_data {
     void *closure;
 };
 
-struct _cairo_pattern {
-    cairo_pattern_type_t	type;
-    cairo_reference_count_t	ref_count;
-    cairo_status_t		status;
-    cairo_user_data_array_t	user_data;
-
-    cairo_matrix_t		matrix;
-    cairo_filter_t		filter;
-    cairo_extend_t		extend;
-
-    cairo_bool_t		has_component_alpha;
-};
-
-struct _cairo_solid_pattern {
-    cairo_pattern_t base;
-    cairo_color_t color;
-};
-
-typedef struct _cairo_surface_pattern {
-    cairo_pattern_t base;
-
-    cairo_surface_t *surface;
-} cairo_surface_pattern_t;
-
-typedef struct _cairo_gradient_stop {
-    double offset;
-    cairo_color_stop_t color;
-} cairo_gradient_stop_t;
-
-typedef struct _cairo_gradient_pattern {
-    cairo_pattern_t base;
-
-    unsigned int	    n_stops;
-    unsigned int	    stops_size;
-    cairo_gradient_stop_t  *stops;
-    cairo_gradient_stop_t   stops_embedded[2];
-} cairo_gradient_pattern_t;
-
-typedef struct _cairo_linear_pattern {
-    cairo_gradient_pattern_t base;
-
-    cairo_point_double_t pd1;
-    cairo_point_double_t pd2;
-} cairo_linear_pattern_t;
-
-typedef struct _cairo_radial_pattern {
-    cairo_gradient_pattern_t base;
-
-    cairo_circle_double_t cd1;
-    cairo_circle_double_t cd2;
-} cairo_radial_pattern_t;
-
-typedef union {
-    cairo_gradient_pattern_t base;
-
-    cairo_linear_pattern_t linear;
-    cairo_radial_pattern_t radial;
-} cairo_gradient_pattern_union_t;
-
-/*
- * A mesh patch is a tensor-product patch (bicubic Bezier surface
- * patch). It has 16 control points. Each set of 4 points along the
- * sides of the 4x4 grid of control points is a Bezier curve that
- * defines one side of the patch. A color is assigned to each
- * corner. The inner 4 points provide additional control over the
- * shape and the color mapping.
- *
- * Cairo uses the same convention as the PDF Reference for numbering
- * the points and side of the patch.
- *
- *
- *                      Side 1
- *
- *          p[0][3] p[1][3] p[2][3] p[3][3]
- * Side 0   p[0][2] p[1][2] p[2][2] p[3][2]  Side 2
- *          p[0][1] p[1][1] p[2][1] p[3][1]
- *          p[0][0] p[1][0] p[2][0] p[3][0]
- *
- *                      Side 3
- *
- *
- *   Point            Color
- *  -------------------------
- *  points[0][0]    colors[0]
- *  points[0][3]    colors[1]
- *  points[3][3]    colors[2]
- *  points[3][0]    colors[3]
- */
-
-typedef struct _cairo_mesh_patch {
-    cairo_point_double_t points[4][4];
-    cairo_color_t colors[4];
-} cairo_mesh_patch_t;
-
-typedef struct _cairo_mesh_pattern {
-    cairo_pattern_t base;
-
-    cairo_array_t patches;
-    cairo_mesh_patch_t *current_patch;
-    int current_side;
-    cairo_bool_t has_control_point[4];
-    cairo_bool_t has_color[4];
-} cairo_mesh_pattern_t;
-
-typedef union {
-    cairo_pattern_type_t	    type;
-    cairo_pattern_t		    base;
-
-    cairo_solid_pattern_t	    solid;
-    cairo_surface_pattern_t	    surface;
-    cairo_gradient_pattern_union_t  gradient;
-    cairo_mesh_pattern_t	    mesh;
-} cairo_pattern_union_t;
-
 /*
  * A #cairo_unscaled_font_t is just an opaque handle we use in the
  * glyph cache.
diff --git a/src/cairo-xcb-private.h b/src/cairo-xcb-private.h
index ec6aeb5..420a879 100644
--- a/src/cairo-xcb-private.h
+++ b/src/cairo-xcb-private.h
@@ -46,6 +46,7 @@
 #include "cairo-freelist-private.h"
 #include "cairo-list-private.h"
 #include "cairo-mutex-private.h"
+#include "cairo-pattern-private.h"
 #include "cairo-reference-count-private.h"
 #include "cairo-spans-private.h"
 #include "cairo-surface-private.h"
diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c
index 4aecac5..25cfc68 100644
--- a/src/cairo-xlib-surface.c
+++ b/src/cairo-xlib-surface.c
@@ -54,10 +54,11 @@
 #include "cairo-clip-private.h"
 #include "cairo-default-context-private.h"
 #include "cairo-error-private.h"
+#include "cairo-pattern-private.h"
+#include "cairo-region-private.h"
 #include "cairo-scaled-font-private.h"
 #include "cairo-surface-snapshot-private.h"
 #include "cairo-surface-subsurface-private.h"
-#include "cairo-region-private.h"
 
 #include <X11/Xutil.h> /* for XDestroyImage */
 
diff --git a/src/cairo.c b/src/cairo.c
index 42e3b5f..e58206b 100644
--- a/src/cairo.c
+++ b/src/cairo.c
@@ -44,6 +44,7 @@
 #include "cairo-backend-private.h"
 #include "cairo-error-private.h"
 #include "cairo-path-private.h"
+#include "cairo-pattern-private.h"
 #include "cairo-surface-private.h"
 
 #include <assert.h>
diff --git a/src/cairoint.h b/src/cairoint.h
index 13d1555..5a21616 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -2174,162 +2174,6 @@ _cairo_trapezoid_array_translate_and_scale (cairo_trapezoid_t *offset_traps,
 					    double tx, double ty,
 					    double sx, double sy);
 
-/* cairo-pattern.c */
-
-cairo_private cairo_pattern_t *
-_cairo_pattern_create_in_error (cairo_status_t status);
-
-cairo_private cairo_status_t
-_cairo_pattern_create_copy (cairo_pattern_t	  **pattern,
-			    const cairo_pattern_t  *other);
-
-cairo_private cairo_status_t
-_cairo_pattern_init_copy (cairo_pattern_t	*pattern,
-			  const cairo_pattern_t *other);
-
-cairo_private void
-_cairo_pattern_init_static_copy (cairo_pattern_t	*pattern,
-				 const cairo_pattern_t *other);
-
-cairo_private cairo_status_t
-_cairo_pattern_init_snapshot (cairo_pattern_t       *pattern,
-			      const cairo_pattern_t *other);
-
-cairo_private void
-_cairo_pattern_init_solid (cairo_solid_pattern_t	*pattern,
-			   const cairo_color_t		*color);
-
-cairo_private void
-_cairo_pattern_init_for_surface (cairo_surface_pattern_t *pattern,
-				 cairo_surface_t *surface);
-
-cairo_private void
-_cairo_pattern_fini (cairo_pattern_t *pattern);
-
-cairo_private cairo_pattern_t *
-_cairo_pattern_create_solid (const cairo_color_t	*color);
-
-cairo_private void
-_cairo_pattern_transform (cairo_pattern_t      *pattern,
-			  const cairo_matrix_t *ctm_inverse);
-
-cairo_private cairo_bool_t
-_cairo_mesh_pattern_coord_box (const cairo_mesh_pattern_t *mesh,
-			       double                     *out_xmin,
-			       double                     *out_ymin,
-			       double                     *out_xmax,
-			       double                     *out_ymax);
-
-cairo_private void
-_cairo_pattern_alpha_range (const cairo_pattern_t *gradient,
-			    double *out_min, double *out_max);
-
-cairo_private cairo_bool_t
-_cairo_gradient_pattern_is_solid (const cairo_gradient_pattern_t *gradient,
-				  const cairo_rectangle_int_t *extents,
-				  cairo_color_t *color);
-
-cairo_private void
-_cairo_gradient_pattern_box_to_parameter (const cairo_gradient_pattern_t *gradient,
-					  double x0, double y0,
-					  double x1, double y1,
-					  double tolerance,
-					  double out_range[2]);
-
-cairo_private void
-_cairo_gradient_pattern_interpolate (const cairo_gradient_pattern_t *gradient,
-                                     double			     t,
-                                     cairo_circle_double_t	    *out_circle);
-
-cairo_private void
-_cairo_gradient_pattern_fit_to_range (const cairo_gradient_pattern_t *gradient,
-				      double			      max_value,
-				      cairo_matrix_t                 *out_matrix,
-				      cairo_circle_double_t	      out_circle[2]);
-
-cairo_private cairo_bool_t
-_cairo_radial_pattern_focus_is_inside (const cairo_radial_pattern_t *radial);
-
-cairo_private cairo_bool_t
-_cairo_pattern_is_opaque_solid (const cairo_pattern_t *pattern);
-
-cairo_private cairo_bool_t
-_cairo_pattern_is_opaque (const cairo_pattern_t *pattern,
-			  const cairo_rectangle_int_t *extents);
-
-cairo_private cairo_bool_t
-_cairo_pattern_is_clear (const cairo_pattern_t *pattern);
-
-cairo_private_no_warn cairo_filter_t
-_cairo_pattern_analyze_filter (const cairo_pattern_t	*pattern,
-			       double			*pad_out);
-
-enum {
-    CAIRO_PATTERN_ACQUIRE_NONE = 0x0,
-    CAIRO_PATTERN_ACQUIRE_NO_REFLECT = 0x1
-};
-cairo_private cairo_int_status_t
-_cairo_pattern_acquire_surface (const cairo_pattern_t	   *pattern,
-				cairo_surface_t		   *dst,
-				int			   x,
-				int			   y,
-				unsigned int		   width,
-				unsigned int		   height,
-				unsigned int		   flags,
-				cairo_surface_t		   **surface_out,
-				cairo_surface_attributes_t *attributes);
-
-cairo_private void
-_cairo_pattern_release_surface (const cairo_pattern_t	   *pattern,
-				cairo_surface_t		   *surface,
-				cairo_surface_attributes_t *attributes);
-
-cairo_private cairo_int_status_t
-_cairo_pattern_acquire_surfaces (const cairo_pattern_t	    *src,
-				 const cairo_pattern_t	    *mask,
-				 cairo_surface_t	    *dst,
-				 int			    src_x,
-				 int			    src_y,
-				 int			    mask_x,
-				 int			    mask_y,
-				 unsigned int		    width,
-				 unsigned int		    height,
-				 unsigned int		    flags,
-				 cairo_surface_t	    **src_out,
-				 cairo_surface_t	    **mask_out,
-				 cairo_surface_attributes_t *src_attributes,
-				 cairo_surface_attributes_t *mask_attributes);
-
-cairo_private void
-_cairo_pattern_get_extents (const cairo_pattern_t	    *pattern,
-			    cairo_rectangle_int_t           *extents);
-
-cairo_private unsigned long
-_cairo_pattern_hash (const cairo_pattern_t *pattern);
-
-cairo_private unsigned long
-_cairo_linear_pattern_hash (unsigned long hash,
-			    const cairo_linear_pattern_t *linear);
-
-cairo_private unsigned long
-_cairo_radial_pattern_hash (unsigned long hash,
-			    const cairo_radial_pattern_t *radial);
-
-cairo_private cairo_bool_t
-_cairo_linear_pattern_equal (const cairo_linear_pattern_t *a,
-			     const cairo_linear_pattern_t *b);
-
-cairo_private cairo_bool_t
-_cairo_radial_pattern_equal (const cairo_radial_pattern_t *a,
-			     const cairo_radial_pattern_t *b);
-
-cairo_private cairo_bool_t
-_cairo_pattern_equal (const cairo_pattern_t *a,
-		      const cairo_pattern_t *b);
-
-cairo_private void
-_cairo_pattern_reset_static_data (void);
-
 #if CAIRO_HAS_DRM_SURFACE
 
 cairo_private void
@@ -2340,6 +2184,9 @@ _cairo_drm_device_reset_static_data (void);
 cairo_private void
 _cairo_clip_reset_static_data (void);
 
+cairo_private void
+_cairo_pattern_reset_static_data (void);
+
 /* cairo-unicode.c */
 
 cairo_private int
@@ -2367,18 +2214,6 @@ _cairo_utf8_to_utf16 (const char *str,
 		      int	 *items_written);
 #endif
 
-/* cairo-mesh-pattern-rasterizer.c */
-
-cairo_private void
-_cairo_mesh_pattern_rasterize (const cairo_mesh_pattern_t *mesh,
-			       void                       *data,
-			       int                         width,
-			       int                         height,
-			       int                         stride,
-			       double                      x_offset,
-			       double                      y_offset);
-
-
 /* cairo-observer.c */
 
 cairo_private void
commit 83bfd85a1378e61b8bdc3f554f5e07900311f61f
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Fri Apr 23 19:45:26 2010 +0100

    Implement cairo_backend_t
    
    Allow a backend to completely reimplement the Cairo API as it wants. The
    goal is to pass operations to the native backends such as Quartz,
    Direct2D, Qt, Skia, OpenVG with no overhead. And to permit complete
    logging contexts, and whatever else the imagination holds. Perhaps to
    experiment with double-paths?
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/Makefile.sources b/src/Makefile.sources
index 966e03d..03b2030 100644
--- a/src/Makefile.sources
+++ b/src/Makefile.sources
@@ -62,6 +62,7 @@ cairo_private = \
 	cairo-combsort-private.h \
 	cairo-compiler-private.h \
 	cairo-composite-rectangles-private.h \
+	cairo-default-context-private.h \
 	cairo-device-private.h \
 	cairo-error-private.h \
 	cairo-fixed-private.h \
@@ -122,6 +123,7 @@ cairo_sources = \
 	cairo-color.c \
 	cairo-composite-rectangles.c \
 	cairo-debug.c \
+	cairo-default-context.c \
 	cairo-device.c \
 	cairo-error.c \
 	cairo-fixed.c \
diff --git a/src/cairo-analysis-surface.c b/src/cairo-analysis-surface.c
index 5468eac..affa556 100644
--- a/src/cairo-analysis-surface.c
+++ b/src/cairo-analysis-surface.c
@@ -37,6 +37,7 @@
 #include "cairoint.h"
 
 #include "cairo-analysis-surface-private.h"
+#include "cairo-default-context-private.h"
 #include "cairo-error-private.h"
 #include "cairo-paginated-private.h"
 #include "cairo-recording-surface-private.h"
@@ -646,6 +647,8 @@ _cairo_analysis_surface_show_text_glyphs (void			    *abstract_surface,
 
 static const cairo_surface_backend_t cairo_analysis_surface_backend = {
     CAIRO_INTERNAL_SURFACE_TYPE_ANALYSIS,
+    NULL,
+
     NULL, /* create_similar */
     _cairo_analysis_surface_finish,
     NULL, /* acquire_source_image */
@@ -843,6 +846,7 @@ typedef cairo_int_status_t
 
 static const cairo_surface_backend_t cairo_null_surface_backend = {
     CAIRO_INTERNAL_SURFACE_TYPE_NULL,
+    _cairo_default_context_create, /* XXX */
 
     NULL, /* create_similar */
     NULL, /* finish */
diff --git a/src/cairo-backend-private.h b/src/cairo-backend-private.h
new file mode 100644
index 0000000..720b28c
--- /dev/null
+++ b/src/cairo-backend-private.h
@@ -0,0 +1,170 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * 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 Intel Corporation
+ *
+ * Contributor(s):
+ *	Chris Wilson <chris at chris-wilson.co.uk>
+ */
+
+#ifndef CAIRO_BACKEND_PRIVATE_H
+#define CAIRO_BACKEND_PRIVATE_H
+
+#include "cairo-types-private.h"
+
+typedef enum _cairo_backend_type {
+    CAIRO_TYPE_DEFAULT,
+} cairo_backend_type_t;
+
+struct _cairo_backend {
+    cairo_backend_type_t type;
+    void (*destroy) (void *cr);
+
+    cairo_surface_t *(*get_original_target) (void *cr);
+    cairo_surface_t *(*get_current_target) (void *cr);
+
+    cairo_status_t (*save) (void *cr);
+    cairo_status_t (*restore) (void *cr);
+
+    cairo_status_t (*push_group) (void *cr, cairo_content_t content);
+    cairo_pattern_t *(*pop_group) (void *cr);
+
+    cairo_status_t (*set_source_rgba) (void *cr, double red, double green, double blue, double alpha);
+    cairo_status_t (*set_source_surface) (void *cr, cairo_surface_t *surface, double x, double y);
+    cairo_status_t (*set_source) (void *cr, cairo_pattern_t *source);
+    cairo_pattern_t *(*get_source) (void *cr);
+
+    cairo_status_t (*set_antialias) (void *cr, cairo_antialias_t antialias);
+    cairo_status_t (*set_dash) (void *cr, const double *dashes, int num_dashes, double offset);
+    cairo_status_t (*set_fill_rule) (void *cr, cairo_fill_rule_t fill_rule);
+    cairo_status_t (*set_line_cap) (void *cr, cairo_line_cap_t line_cap);
+    cairo_status_t (*set_line_join) (void *cr, cairo_line_join_t line_join);
+    cairo_status_t (*set_line_width) (void *cr, double line_width);
+    cairo_status_t (*set_miter_limit) (void *cr, double limit);
+    cairo_status_t (*set_opacity) (void *cr, double opacity);
+    cairo_status_t (*set_operator) (void *cr, cairo_operator_t op);
+    cairo_status_t (*set_tolerance) (void *cr, double tolerance);
+
+    cairo_antialias_t (*get_antialias) (void *cr);
+    void (*get_dash) (void *cr, double *dashes, int *num_dashes, double *offset);
+    cairo_fill_rule_t (*get_fill_rule) (void *cr);
+    cairo_line_cap_t (*get_line_cap) (void *cr);
+    cairo_line_join_t (*get_line_join) (void *cr);
+    double (*get_line_width) (void *cr);
+    double (*get_miter_limit) (void *cr);
+    double (*get_opacity) (void *cr);
+    cairo_operator_t (*get_operator) (void *cr);
+    double (*get_tolerance) (void *cr);
+
+    cairo_status_t (*translate) (void *cr, double tx, double ty);
+    cairo_status_t (*scale) (void *cr, double sx, double sy);
+    cairo_status_t (*rotate) (void *cr, double theta);
+    cairo_status_t (*transform) (void *cr, const cairo_matrix_t *matrix);
+    cairo_status_t (*set_matrix) (void *cr, const cairo_matrix_t *matrix);
+    cairo_status_t (*set_identity_matrix) (void *cr);
+    void (*get_matrix) (void *cr, cairo_matrix_t *matrix);
+
+    void (*user_to_device) (void *cr, double *x, double *y);
+    void (*user_to_device_distance) (void *cr, double *x, double *y);
+    void (*device_to_user) (void *cr, double *x, double *y);
+    void (*device_to_user_distance) (void *cr, double *x, double *y);
+
+    cairo_status_t (*new_path) (void *cr);
+    cairo_status_t (*new_sub_path) (void *cr);
+    cairo_status_t (*move_to) (void *cr, double x, double y);
+    cairo_status_t (*rel_move_to) (void *cr, double dx, double dy);
+    cairo_status_t (*line_to) (void *cr, double x, double y);
+    cairo_status_t (*rel_line_to) (void *cr, double dx, double dy);
+    cairo_status_t (*curve_to) (void *cr, double x1, double y1, double x2, double y2, double x3, double y3);
+    cairo_status_t (*rel_curve_to) (void *cr, double dx1, double dy1, double dx2, double dy2, double dx3, double dy3);
+    cairo_status_t (*arc_to) (void *cr, double x1, double y1, double x2, double y2, double radius);
+    cairo_status_t (*rel_arc_to) (void *cr, double dx1, double dy1, double dx2, double dy2, double radius);
+    cairo_status_t (*close_path) (void *cr);
+
+    cairo_status_t (*arc) (void *cr, double xc, double yc, double radius, double angle1, double angle2, cairo_bool_t forward);
+    cairo_status_t (*rectangle) (void *cr, double x, double y, double width, double height);
+
+    void (*path_extents) (void *cr, double *x1, double *y1, double *x2, double *y2);
+    cairo_bool_t (*has_current_point) (void *cr);
+    cairo_bool_t (*get_current_point) (void *cr, double *x, double *y);
+
+    cairo_path_t *(*copy_path) (void *cr);
+    cairo_path_t *(*copy_path_flat) (void *cr);
+    cairo_status_t (*append_path) (void *cr, const cairo_path_t *path);
+
+    cairo_status_t (*stroke_to_path) (void *cr);
+
+    cairo_status_t (*clip) (void *cr);
+    cairo_status_t (*clip_preserve) (void *cr);
+    cairo_status_t (*in_clip) (void *cr, double x, double y, cairo_bool_t *inside);
+    cairo_status_t (*clip_extents) (void *cr, double *x1, double *y1, double *x2, double *y2);
+    cairo_status_t (*reset_clip) (void *cr);
+    cairo_rectangle_list_t *(*clip_copy_rectangle_list) (void *cr);
+
+    cairo_status_t (*paint) (void *cr);
+    cairo_status_t (*paint_with_alpha) (void *cr, double opacity);
+    cairo_status_t (*mask) (void *cr, cairo_pattern_t *pattern);
+
+    cairo_status_t (*stroke) (void *cr);
+    cairo_status_t (*stroke_preserve) (void *cr);
+    cairo_status_t (*in_stroke) (void *cr, double x, double y, cairo_bool_t *inside);
+    cairo_status_t (*stroke_extents) (void *cr, double *x1, double *y1, double *x2, double *y2);
+
+    cairo_status_t (*fill) (void *cr);
+    cairo_status_t (*fill_preserve) (void *cr);
+    cairo_status_t (*in_fill) (void *cr, double x, double y, cairo_bool_t *inside);
+    cairo_status_t (*fill_extents) (void *cr, double *x1, double *y1, double *x2, double *y2);
+
+    cairo_status_t (*set_font_face) (void *cr, cairo_font_face_t *font_face);
+    cairo_font_face_t *(*get_font_face) (void *cr);
+    cairo_status_t (*set_font_size) (void *cr, double size);
+    cairo_status_t (*set_font_matrix) (void *cr, const cairo_matrix_t *matrix);
+    void (*get_font_matrix) (void *cr, cairo_matrix_t *matrix);
+    cairo_status_t (*set_font_options) (void *cr, const cairo_font_options_t *options);
+    void (*get_font_options) (void *cr, cairo_font_options_t *options);
+    cairo_status_t (*set_scaled_font) (void *cr, cairo_scaled_font_t *scaled_font);
+    cairo_scaled_font_t *(*get_scaled_font) (void *cr);
+    cairo_status_t (*font_extents) (void *cr, cairo_font_extents_t *extents);
+
+    cairo_status_t (*glyphs) (void *cr,
+			      const cairo_glyph_t *glyphs, int num_glyphs,
+			      cairo_glyph_text_info_t *info);
+    cairo_status_t (*glyph_path) (void *cr,
+				  const cairo_glyph_t *glyphs, int num_glyphs);
+
+    cairo_status_t (*glyph_extents) (void *cr,
+				     const cairo_glyph_t *glyphs,
+				     int num_glyphs,
+				     cairo_text_extents_t *extents);
+
+    cairo_status_t (*copy_page) (void *cr);
+    cairo_status_t (*show_page) (void *cr);
+};
+
+#endif /* CAIRO_BACKEND_PRIVATE_H */
diff --git a/src/cairo-clip.c b/src/cairo-clip.c
index d78a17c..929c107 100644
--- a/src/cairo-clip.c
+++ b/src/cairo-clip.c
@@ -513,10 +513,13 @@ static cairo_status_t
 _cairo_clip_apply_clip_path (cairo_clip_t *clip,
 			     const cairo_clip_path_t *path)
 {
-    cairo_status_t status;
+    if (path->prev != NULL) {
+	cairo_status_t status;
 
-    if (path->prev != NULL)
 	status = _cairo_clip_apply_clip_path (clip, path->prev);
+	if (unlikely (status))
+	    return status;
+    }
 
     return _cairo_clip_intersect_path (clip,
 				       &path->path,
diff --git a/src/cairo-debug.c b/src/cairo-debug.c
index 1aa5779..f8ef717 100644
--- a/src/cairo-debug.c
+++ b/src/cairo-debug.c
@@ -87,7 +87,7 @@ cairo_debug_reset_static_data (void)
     _cairo_drm_device_reset_static_data ();
 #endif
 
-    _cairo_reset_static_data ();
+    _cairo_default_context_reset_static_data ();
 
     CAIRO_MUTEX_FINALIZE ();
 }
diff --git a/src/cairo-default-context-private.h b/src/cairo-default-context-private.h
new file mode 100644
index 0000000..e2d780d
--- /dev/null
+++ b/src/cairo-default-context-private.h
@@ -0,0 +1,58 @@
+/* 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_DEFAULT_CONTEXT_PRIVATE_H
+#define CAIRO_DEFAULT_CONTEXT_PRIVATE_H
+
+#include "cairo-private.h"
+#include "cairo-gstate-private.h"
+#include "cairo-path-fixed-private.h"
+
+typedef struct _cairo_default_context cairo_default_context_t;
+
+struct _cairo_default_context {
+    cairo_t base;
+
+    cairo_gstate_t *gstate;
+    cairo_gstate_t  gstate_tail[2];
+    cairo_gstate_t *gstate_freelist;
+
+    cairo_path_fixed_t path[1];
+};
+
+cairo_private cairo_t *
+_cairo_default_context_create (void *target);
+
+#endif /* CAIRO_DEFAULT_CONTEXT_PRIVATE_H */
diff --git a/src/cairo-default-context.c b/src/cairo-default-context.c
new file mode 100644
index 0000000..dbd014a
--- /dev/null
+++ b/src/cairo-default-context.c
@@ -0,0 +1,1406 @@
+/* -*- 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 © 2011 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., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, 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-arc-private.h"
+#include "cairo-backend-private.h"
+#include "cairo-default-context-private.h"
+#include "cairo-error-private.h"
+#include "cairo-freed-pool-private.h"
+#include "cairo-path-private.h"
+
+#define CAIRO_TOLERANCE_MINIMUM	_cairo_fixed_to_double(1)
+
+#if !defined(INFINITY)
+#define INFINITY HUGE_VAL
+#endif
+
+static freed_pool_t context_pool;
+
+void
+_cairo_default_context_reset_static_data (void)
+{
+    _freed_pool_reset (&context_pool);
+}
+
+static void
+_cairo_default_context_destroy (void *abstract_cr)
+{
+    cairo_default_context_t *cr = abstract_cr;
+
+    while (cr->gstate != &cr->gstate_tail[0]) {
+	if (_cairo_gstate_restore (&cr->gstate, &cr->gstate_freelist))
+	    break;
+    }
+
+    _cairo_gstate_fini (cr->gstate);
+    cr->gstate_freelist = cr->gstate_freelist->next; /* skip over tail[1] */
+    while (cr->gstate_freelist != NULL) {
+	cairo_gstate_t *gstate = cr->gstate_freelist;
+	cr->gstate_freelist = gstate->next;
+	free (gstate);
+    }
+
+    _cairo_path_fixed_fini (cr->path);
+
+    _cairo_fini (&cr->base);
+
+    /* mark the context as invalid to protect against misuse */
+    cr->base.status = CAIRO_STATUS_NULL_POINTER;
+    _freed_pool_put (&context_pool, cr);
+}
+
+static cairo_surface_t *
+_cairo_default_context_get_original_target (void *abstract_cr)
+{
+    cairo_default_context_t *cr = abstract_cr;
+
+    return _cairo_gstate_get_original_target (cr->gstate);
+}
+
+static cairo_surface_t *
+_cairo_default_context_get_current_target (void *abstract_cr)
+{
+    cairo_default_context_t *cr = abstract_cr;
+
+    return _cairo_gstate_get_target (cr->gstate);
+}
+
+static cairo_status_t
+_cairo_default_context_save (void *abstract_cr)
+{
+    cairo_default_context_t *cr = abstract_cr;
+
+    return _cairo_gstate_save (&cr->gstate, &cr->gstate_freelist);
+}
+
+static cairo_status_t
+_cairo_default_context_restore (void *abstract_cr)
+{
+    cairo_default_context_t *cr = abstract_cr;
+
+    return _cairo_gstate_restore (&cr->gstate, &cr->gstate_freelist);
+}
+
+static cairo_status_t
+_cairo_default_context_push_group (void *abstract_cr, cairo_content_t content)
+{
+    cairo_default_context_t *cr = abstract_cr;
+    cairo_surface_t *group_surface;
+    cairo_clip_t *clip;
+    cairo_status_t status;
+
+    clip = _cairo_gstate_get_clip (cr->gstate);
+    if (clip->all_clipped) {
+	group_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 0, 0);
+	status = group_surface->status;
+	if (unlikely (status))
+	    goto bail;
+    } else {
+	cairo_surface_t *parent_surface;
+	const cairo_rectangle_int_t *clip_extents;
+	cairo_rectangle_int_t extents;
+        cairo_matrix_t matrix;
+	cairo_bool_t is_empty;
+
+	parent_surface = _cairo_gstate_get_target (cr->gstate);
+
+	/* Get the extents that we'll use in creating our new group surface */
+	is_empty = _cairo_surface_get_extents (parent_surface, &extents);
+	clip_extents = _cairo_clip_get_extents (_cairo_gstate_get_clip (cr->gstate));
+	if (clip_extents != NULL)
+	    is_empty = _cairo_rectangle_intersect (&extents, clip_extents);
+
+	group_surface = _cairo_surface_create_similar_solid (parent_surface,
+							     content,
+							     extents.width,
+							     extents.height,
+							     CAIRO_COLOR_TRANSPARENT,
+							     TRUE);
+	status = group_surface->status;
+	if (unlikely (status))
+	    goto bail;
+
+	/* 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_matrix_init_translate (&matrix, -extents.x, -extents.y);
+	_cairo_path_fixed_transform (cr->path, &matrix);
+    }
+
+    /* create a new gstate for the redirect */
+    status = _cairo_gstate_save (&cr->gstate, &cr->gstate_freelist);
+    if (unlikely (status))
+	goto bail;
+
+    status = _cairo_gstate_redirect_target (cr->gstate, group_surface);
+
+bail:
+    cairo_surface_destroy (group_surface);
+    return status;
+}
+
+static cairo_pattern_t *
+_cairo_default_context_pop_group (void *abstract_cr)
+{
+    cairo_default_context_t *cr = abstract_cr;
+    cairo_surface_t *group_surface;
+    cairo_pattern_t *group_pattern;
+    cairo_matrix_t group_matrix, device_transform_matrix;
+    cairo_status_t status;
+
+    /* Verify that we are at the right nesting level */
+    if (unlikely (! _cairo_gstate_is_group (cr->gstate)))
+	return _cairo_pattern_create_in_error (CAIRO_STATUS_INVALID_POP_GROUP);
+
+    /* Get a reference to the active surface before restoring */
+    group_surface = _cairo_gstate_get_target (cr->gstate);
+    group_surface = cairo_surface_reference (group_surface);
+
+    status = _cairo_gstate_restore (&cr->gstate, &cr->gstate_freelist);
+    assert (status == CAIRO_STATUS_SUCCESS);
+
+    group_pattern = cairo_pattern_create_for_surface (group_surface);
+    status = group_pattern->status;
+    if (unlikely (status))
+        goto done;
+
+    _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_matrix_multiply (&device_transform_matrix,
+                           &_cairo_gstate_get_target (cr->gstate)->device_transform,
+			   &group_surface->device_transform_inverse);
+    _cairo_path_fixed_transform (cr->path, &device_transform_matrix);
+
+done:
+    cairo_surface_destroy (group_surface);
+
+    return group_pattern;
+}
+
+static cairo_status_t
+_cairo_default_context_set_source (void *abstract_cr,
+				   cairo_pattern_t *source)
+{
+    cairo_default_context_t *cr = abstract_cr;
+
+    return _cairo_gstate_set_source (cr->gstate, source);
+}
+
+static cairo_bool_t
+_current_source_matches_solid (const cairo_pattern_t *pattern,
+			       double red,
+			       double green,
+			       double blue,
+			       double alpha)
+{
+    cairo_color_t color;
+
+    if (pattern->type != CAIRO_PATTERN_TYPE_SOLID)
+	return FALSE;
+
+    red   = _cairo_restrict_value (red,   0.0, 1.0);
+    green = _cairo_restrict_value (green, 0.0, 1.0);
+    blue  = _cairo_restrict_value (blue,  0.0, 1.0);
+    alpha = _cairo_restrict_value (alpha, 0.0, 1.0);
+
+    _cairo_color_init_rgba (&color, red, green, blue, alpha);
+    return _cairo_color_equal (&color,
+			       &((cairo_solid_pattern_t *) pattern)->color);
+}
+
+static cairo_status_t
+_cairo_default_context_set_source_rgba (void *abstract_cr, double red, double green, double blue, double alpha)
+{
+    cairo_default_context_t *cr = abstract_cr;
+    cairo_pattern_t *pattern;
+    cairo_status_t status;
+
+    if (_current_source_matches_solid (cr->gstate->source, red, green, blue, 1.))
+	return CAIRO_STATUS_SUCCESS;
+
+    /* push the current pattern to the freed lists */
+    _cairo_default_context_set_source (cr, (cairo_pattern_t *) &_cairo_pattern_black);
+
+    pattern = cairo_pattern_create_rgba (red, green, blue, alpha);
+    if (unlikely (pattern->status))
+	return pattern->status;
+
+    status = _cairo_default_context_set_source (cr, pattern);
+    cairo_pattern_destroy (pattern);
+
+    return status;
+}
+
+static cairo_status_t
+_cairo_default_context_set_source_surface (void *abstract_cr,
+					   cairo_surface_t *surface,
+					   double	   x,
+					   double	   y)
+{
+    cairo_default_context_t *cr = abstract_cr;
+    cairo_pattern_t *pattern;
+    cairo_matrix_t matrix;
+    cairo_status_t status;
+
+    /* push the current pattern to the freed lists */
+    _cairo_default_context_set_source (cr, (cairo_pattern_t *) &_cairo_pattern_black);
+
+    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_default_context_set_source (cr, pattern);
+    cairo_pattern_destroy (pattern);
+
+    return status;
+}
+
+static cairo_pattern_t *
+_cairo_default_context_get_source (void *abstract_cr)
+{
+    cairo_default_context_t *cr = abstract_cr;
+
+    return _cairo_gstate_get_source (cr->gstate);
+}
+
+static cairo_status_t
+_cairo_default_context_set_tolerance (void *abstract_cr,
+				      double tolerance)
+{
+    cairo_default_context_t *cr = abstract_cr;
+
+    if (tolerance < CAIRO_TOLERANCE_MINIMUM)
+	tolerance = CAIRO_TOLERANCE_MINIMUM;
+
+    return _cairo_gstate_set_tolerance (cr->gstate, tolerance);
+}
+
+static cairo_status_t
+_cairo_default_context_set_operator (void *abstract_cr, cairo_operator_t op)
+{
+    cairo_default_context_t *cr = abstract_cr;
+
+    return _cairo_gstate_set_operator (cr->gstate, op);
+}
+
+static cairo_status_t
+_cairo_default_context_set_opacity (void *abstract_cr, double opacity)
+{
+    cairo_default_context_t *cr = abstract_cr;
+
+    return _cairo_gstate_set_opacity (cr->gstate, opacity);
+}
+
+static cairo_status_t
+_cairo_default_context_set_antialias (void *abstract_cr,
+				      cairo_antialias_t antialias)
+{
+    cairo_default_context_t *cr = abstract_cr;
+
+    return _cairo_gstate_set_antialias (cr->gstate, antialias);
+}
+
+static cairo_status_t
+_cairo_default_context_set_fill_rule (void *abstract_cr,
+				      cairo_fill_rule_t fill_rule)
+{
+    cairo_default_context_t *cr = abstract_cr;
+
+    return _cairo_gstate_set_fill_rule (cr->gstate, fill_rule);
+}
+
+static cairo_status_t
+_cairo_default_context_set_line_width (void *abstract_cr,
+				       double line_width)
+{
+    cairo_default_context_t *cr = abstract_cr;
+
+    return _cairo_gstate_set_line_width (cr->gstate, line_width);
+}
+
+static cairo_status_t
+_cairo_default_context_set_line_cap (void *abstract_cr,
+				     cairo_line_cap_t line_cap)
+{
+    cairo_default_context_t *cr = abstract_cr;
+
+    return _cairo_gstate_set_line_cap (cr->gstate, line_cap);
+}
+
+static cairo_status_t
+_cairo_default_context_set_line_join (void *abstract_cr,
+				      cairo_line_join_t line_join)
+{
+    cairo_default_context_t *cr = abstract_cr;
+
+    return _cairo_gstate_set_line_join (cr->gstate, line_join);
+}
+
+static cairo_status_t
+_cairo_default_context_set_dash (void *abstract_cr,
+				 const double *dashes,
+				 int	      num_dashes,
+				 double	      offset)
+{
+    cairo_default_context_t *cr = abstract_cr;
+
+    return _cairo_gstate_set_dash (cr->gstate,
+				   dashes, num_dashes, offset);
+}
+
+static cairo_status_t
+_cairo_default_context_set_miter_limit (void *abstract_cr,
+					double limit)
+{
+    cairo_default_context_t *cr = abstract_cr;
+
+    return _cairo_gstate_set_miter_limit (cr->gstate, limit);
+}
+
+static cairo_antialias_t
+_cairo_default_context_get_antialias (void *abstract_cr)
+{
+    cairo_default_context_t *cr = abstract_cr;
+
+    return _cairo_gstate_get_antialias (cr->gstate);
+}
+
+static void
+_cairo_default_context_get_dash (void *abstract_cr,
+				 double *dashes,
+				 int *num_dashes,
+				 double *offset)
+{
+    cairo_default_context_t *cr = abstract_cr;
+
+    _cairo_gstate_get_dash (cr->gstate, dashes, num_dashes, offset);
+}
+
+static cairo_fill_rule_t
+_cairo_default_context_get_fill_rule (void *abstract_cr)
+{
+    cairo_default_context_t *cr = abstract_cr;
+
+    return _cairo_gstate_get_fill_rule (cr->gstate);
+}
+
+static double
+_cairo_default_context_get_line_width (void *abstract_cr)
+{
+    cairo_default_context_t *cr = abstract_cr;
+
+    return _cairo_gstate_get_line_width (cr->gstate);
+}
+
+static cairo_line_cap_t
+_cairo_default_context_get_line_cap (void *abstract_cr)
+{
+    cairo_default_context_t *cr = abstract_cr;
+
+    return _cairo_gstate_get_line_cap (cr->gstate);
+}
+
+static cairo_line_join_t
+_cairo_default_context_get_line_join (void *abstract_cr)
+{
+    cairo_default_context_t *cr = abstract_cr;
+
+    return _cairo_gstate_get_line_join (cr->gstate);
+}
+
+static double
+_cairo_default_context_get_miter_limit (void *abstract_cr)
+{
+    cairo_default_context_t *cr = abstract_cr;
+
+    return _cairo_gstate_get_miter_limit (cr->gstate);
+}
+
+static cairo_operator_t
+_cairo_default_context_get_operator (void *abstract_cr)
+{
+    cairo_default_context_t *cr = abstract_cr;
+
+    return _cairo_gstate_get_operator (cr->gstate);
+}
+
+static double
+_cairo_default_context_get_opacity (void *abstract_cr)
+{
+    cairo_default_context_t *cr = abstract_cr;
+
+    return _cairo_gstate_get_opacity (cr->gstate);
+}
+
+static double
+_cairo_default_context_get_tolerance (void *abstract_cr)
+{
+    cairo_default_context_t *cr = abstract_cr;
+
+    return _cairo_gstate_get_tolerance (cr->gstate);
+}
+
+
+/* Current tranformation matrix */
+
+static cairo_status_t
+_cairo_default_context_translate (void *abstract_cr,
+				  double tx,
+				  double ty)
+{
+    cairo_default_context_t *cr = abstract_cr;
+
+    return _cairo_gstate_translate (cr->gstate, tx, ty);
+}
+
+static cairo_status_t
+_cairo_default_context_scale (void *abstract_cr,
+			      double sx,
+			      double sy)
+{
+    cairo_default_context_t *cr = abstract_cr;
+
+    return _cairo_gstate_scale (cr->gstate, sx, sy);
+}
+
+static cairo_status_t
+_cairo_default_context_rotate (void *abstract_cr,
+			       double theta)
+{
+    cairo_default_context_t *cr = abstract_cr;
+
+    return _cairo_gstate_rotate (cr->gstate, theta);
+}
+
+static cairo_status_t
+_cairo_default_context_transform (void *abstract_cr,
+				  const cairo_matrix_t *matrix)
+{
+    cairo_default_context_t *cr = abstract_cr;
+
+    return _cairo_gstate_transform (cr->gstate, matrix);
+}
+
+static cairo_status_t
+_cairo_default_context_set_matrix (void *abstract_cr,
+				   const cairo_matrix_t *matrix)
+{
+    cairo_default_context_t *cr = abstract_cr;
+
+    return _cairo_gstate_set_matrix (cr->gstate, matrix);
+}
+
+static cairo_status_t
+_cairo_default_context_set_identity_matrix (void *abstract_cr)
+{
+    cairo_default_context_t *cr = abstract_cr;
+
+    _cairo_gstate_identity_matrix (cr->gstate);
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static void
+_cairo_default_context_get_matrix (void *abstract_cr,
+				   cairo_matrix_t *matrix)
+{
+    cairo_default_context_t *cr = abstract_cr;
+
+    _cairo_gstate_get_matrix (cr->gstate, matrix);
+}
+
+static void
+_cairo_default_context_user_to_device (void *abstract_cr,
+				       double *x,
+				       double *y)
+{
+    cairo_default_context_t *cr = abstract_cr;
+
+    _cairo_gstate_user_to_device (cr->gstate, x, y);
+}
+
+static void
+_cairo_default_context_user_to_device_distance (void *abstract_cr, double *dx, double *dy)
+{
+    cairo_default_context_t *cr = abstract_cr;
+
+    _cairo_gstate_user_to_device_distance (cr->gstate, dx, dy);
+}
+
+static void
+_cairo_default_context_device_to_user (void *abstract_cr,
+				       double *x,
+				       double *y)
+{
+    cairo_default_context_t *cr = abstract_cr;
+
+    _cairo_gstate_device_to_user (cr->gstate, x, y);
+}
+
+static void
+_cairo_default_context_device_to_user_distance (void *abstract_cr,
+						double *dx,
+						double *dy)
+{
+    cairo_default_context_t *cr = abstract_cr;
+
+    _cairo_gstate_device_to_user_distance (cr->gstate, dx, dy);
+}
+
+/* Path constructor */
+
+static cairo_status_t
+_cairo_default_context_new_path (void *abstract_cr)
+{
+    cairo_default_context_t *cr = abstract_cr;
+
+    _cairo_path_fixed_fini (cr->path);
+    _cairo_path_fixed_init (cr->path);
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_default_context_new_sub_path (void *abstract_cr)
+{
+    cairo_default_context_t *cr = abstract_cr;
+
+    _cairo_path_fixed_new_sub_path (cr->path);
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_default_context_move_to (void *abstract_cr, double x, double y)
+{
+    cairo_default_context_t *cr = abstract_cr;
+    cairo_fixed_t x_fixed, y_fixed;
+
+    _cairo_gstate_user_to_backend (cr->gstate, &x, &y);
+    x_fixed = _cairo_fixed_from_double (x);
+    y_fixed = _cairo_fixed_from_double (y);
+
+    return _cairo_path_fixed_move_to (cr->path, x_fixed, y_fixed);
+}
+
+static cairo_status_t
+_cairo_default_context_line_to (void *abstract_cr, double x, double y)
+{
+    cairo_default_context_t *cr = abstract_cr;
+    cairo_fixed_t x_fixed, y_fixed;
+
+    _cairo_gstate_user_to_backend (cr->gstate, &x, &y);
+    x_fixed = _cairo_fixed_from_double (x);
+    y_fixed = _cairo_fixed_from_double (y);
+
+    return _cairo_path_fixed_line_to (cr->path, x_fixed, y_fixed);
+}
+
+static cairo_status_t
+_cairo_default_context_curve_to (void *abstract_cr,
+				 double x1, double y1,
+				 double x2, double y2,
+				 double x3, double y3)
+{
+    cairo_default_context_t *cr = abstract_cr;
+    cairo_fixed_t x1_fixed, y1_fixed;
+    cairo_fixed_t x2_fixed, y2_fixed;
+    cairo_fixed_t x3_fixed, y3_fixed;
+
+    _cairo_gstate_user_to_backend (cr->gstate, &x1, &y1);
+    _cairo_gstate_user_to_backend (cr->gstate, &x2, &y2);
+    _cairo_gstate_user_to_backend (cr->gstate, &x3, &y3);
+
+    x1_fixed = _cairo_fixed_from_double (x1);
+    y1_fixed = _cairo_fixed_from_double (y1);
+
+    x2_fixed = _cairo_fixed_from_double (x2);
+    y2_fixed = _cairo_fixed_from_double (y2);
+
+    x3_fixed = _cairo_fixed_from_double (x3);
+    y3_fixed = _cairo_fixed_from_double (y3);
+
+    return _cairo_path_fixed_curve_to (cr->path,
+				       x1_fixed, y1_fixed,
+				       x2_fixed, y2_fixed,
+				       x3_fixed, y3_fixed);
+}
+
+static cairo_status_t
+_cairo_default_context_arc (void *abstract_cr,
+			    double xc, double yc, double radius,
+			    double angle1, double angle2,
+			    cairo_bool_t forward)
+{
+    cairo_default_context_t *cr = abstract_cr;
+    cairo_status_t status;
+
+    /* Do nothing, successfully, if radius is <= 0 */
+    if (radius <= 0.0) {
+	cairo_fixed_t x_fixed, y_fixed;
+
+	_cairo_gstate_user_to_backend (cr->gstate, &xc, &yc);
+	x_fixed = _cairo_fixed_from_double (xc);
+	y_fixed = _cairo_fixed_from_double (yc);
+	status = _cairo_path_fixed_line_to (cr->path, x_fixed, y_fixed);
+	if (unlikely (status))
+	    return status;
+
+	status = _cairo_path_fixed_line_to (cr->path, x_fixed, y_fixed);
+	if (unlikely (status))
+	    return status;
+
+	return CAIRO_STATUS_SUCCESS;
+    }
+
+    status = _cairo_default_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; /* any error will have already been set on cr */
+}
+
+static cairo_status_t
+_cairo_default_context_rel_move_to (void *abstract_cr, double dx, double dy)
+{
+    cairo_default_context_t *cr = abstract_cr;
+    cairo_fixed_t dx_fixed, dy_fixed;
+
+    _cairo_gstate_user_to_device_distance (cr->gstate, &dx, &dy);
+
+    dx_fixed = _cairo_fixed_from_double (dx);
+    dy_fixed = _cairo_fixed_from_double (dy);
+
+    return _cairo_path_fixed_rel_move_to (cr->path, dx_fixed, dy_fixed);
+}
+
+static cairo_status_t
+_cairo_default_context_rel_line_to (void *abstract_cr, double dx, double dy)
+{
+    cairo_default_context_t *cr = abstract_cr;
+    cairo_fixed_t dx_fixed, dy_fixed;
+
+    _cairo_gstate_user_to_device_distance (cr->gstate, &dx, &dy);
+
+    dx_fixed = _cairo_fixed_from_double (dx);
+    dy_fixed = _cairo_fixed_from_double (dy);
+
+    return _cairo_path_fixed_rel_line_to (cr->path, dx_fixed, dy_fixed);
+}
+
+
+static cairo_status_t
+_cairo_default_context_rel_curve_to (void *abstract_cr,
+				     double dx1, double dy1,
+				     double dx2, double dy2,
+				     double dx3, double dy3)
+{
+    cairo_default_context_t *cr = abstract_cr;
+    cairo_fixed_t dx1_fixed, dy1_fixed;
+    cairo_fixed_t dx2_fixed, dy2_fixed;
+    cairo_fixed_t dx3_fixed, dy3_fixed;
+
+    _cairo_gstate_user_to_device_distance (cr->gstate, &dx1, &dy1);
+    _cairo_gstate_user_to_device_distance (cr->gstate, &dx2, &dy2);
+    _cairo_gstate_user_to_device_distance (cr->gstate, &dx3, &dy3);
+
+    dx1_fixed = _cairo_fixed_from_double (dx1);
+    dy1_fixed = _cairo_fixed_from_double (dy1);
+
+    dx2_fixed = _cairo_fixed_from_double (dx2);
+    dy2_fixed = _cairo_fixed_from_double (dy2);
+
+    dx3_fixed = _cairo_fixed_from_double (dx3);
+    dy3_fixed = _cairo_fixed_from_double (dy3);
+
+    return _cairo_path_fixed_rel_curve_to (cr->path,
+					   dx1_fixed, dy1_fixed,
+					   dx2_fixed, dy2_fixed,
+					   dx3_fixed, dy3_fixed);
+}
+
+static cairo_status_t
+_cairo_default_context_close_path (void *abstract_cr)
+{
+    cairo_default_context_t *cr = abstract_cr;
+
+    return _cairo_path_fixed_close_path (cr->path);
+}
+
+static cairo_status_t
+_cairo_default_context_rectangle (void *abstract_cr,
+				  double x, double y,
+				  double width, double height)
+{
+    cairo_default_context_t *cr = abstract_cr;
+    cairo_status_t status;
+
+    status = _cairo_default_context_move_to (cr, x, y);
+    if (unlikely (status))
+	return status;
+
+    status = _cairo_default_context_rel_line_to (cr, width, 0);
+    if (unlikely (status))
+	return status;
+
+    status = _cairo_default_context_rel_line_to (cr, 0, height);
+    if (unlikely (status))
+	return status;
+
+    status = _cairo_default_context_rel_line_to (cr, -width, 0);
+    if (unlikely (status))
+	return status;
+
+    return _cairo_default_context_close_path (cr);
+}
+
+static void
+_cairo_default_context_path_extents (void *abstract_cr,
+				     double *x1,
+				     double *y1,
+				     double *x2,
+				     double *y2)
+{
+    cairo_default_context_t *cr = abstract_cr;
+
+    _cairo_gstate_path_extents (cr->gstate,
+				cr->path,
+				x1, y1, x2, y2);
+}
+
+static cairo_bool_t
+_cairo_default_context_has_current_point (void *abstract_cr)
+{
+    cairo_default_context_t *cr = abstract_cr;
+
+    return cr->path->has_current_point;
+}
+
+static cairo_bool_t
+_cairo_default_context_get_current_point (void *abstract_cr,
+					  double *x,
+					  double *y)
+{
+    cairo_default_context_t *cr = abstract_cr;
+    cairo_fixed_t x_fixed, y_fixed;
+
+    if (_cairo_path_fixed_get_current_point (cr->path, &x_fixed, &y_fixed))
+    {
+	*x = _cairo_fixed_to_double (x_fixed);
+	*y = _cairo_fixed_to_double (y_fixed);
+	_cairo_gstate_backend_to_user (cr->gstate, x, y);
+
+	return TRUE;
+    }
+    else
+    {
+	return FALSE;
+    }
+}
+
+static cairo_path_t *
+_cairo_default_context_copy_path (void *abstract_cr)
+{
+    cairo_default_context_t *cr = abstract_cr;
+
+    return _cairo_path_create (cr->path, &cr->base);
+}
+
+static cairo_path_t *
+_cairo_default_context_copy_path_flat (void *abstract_cr)
+{
+    cairo_default_context_t *cr = abstract_cr;
+
+    return _cairo_path_create_flat (cr->path, &cr->base);
+}
+
+static cairo_status_t
+_cairo_default_context_append_path (void *abstract_cr,
+				    const cairo_path_t *path)
+{
+    cairo_default_context_t *cr = abstract_cr;
+
+    return _cairo_path_append_to_context (path, &cr->base);
+}
+
+static cairo_status_t
+_cairo_default_context_paint (void *abstract_cr)
+{
+    cairo_default_context_t *cr = abstract_cr;
+
+    return _cairo_gstate_paint (cr->gstate);
+}
+
+static cairo_status_t
+_cairo_default_context_paint_with_alpha (void *abstract_cr,
+					 double alpha)
+{
+    cairo_default_context_t *cr = abstract_cr;
+    cairo_solid_pattern_t pattern;
+    cairo_status_t status;
+    cairo_color_t color;
+
+    if (CAIRO_ALPHA_IS_OPAQUE (alpha))
+	return _cairo_gstate_paint (cr->gstate);
+
+    if (CAIRO_ALPHA_IS_ZERO (alpha) &&
+        _cairo_operator_bounded_by_mask (cr->gstate->op)) {
+	return CAIRO_STATUS_SUCCESS;
+    }
+
+    _cairo_color_init_rgba (&color, 0., 0., 0., alpha);
+    _cairo_pattern_init_solid (&pattern, &color);
+
+    status = _cairo_gstate_mask (cr->gstate, &pattern.base);
+    _cairo_pattern_fini (&pattern.base);
+
+    return status;
+}
+
+static cairo_status_t
+_cairo_default_context_mask (void *abstract_cr,
+			     cairo_pattern_t *mask)
+{
+    cairo_default_context_t *cr = abstract_cr;
+
+    return _cairo_gstate_mask (cr->gstate, mask);
+}
+
+static cairo_status_t
+_cairo_default_context_stroke_preserve (void *abstract_cr)
+{
+    cairo_default_context_t *cr = abstract_cr;
+
+    return _cairo_gstate_stroke (cr->gstate, cr->path);
+}
+
+static cairo_status_t
+_cairo_default_context_stroke (void *abstract_cr)
+{
+    cairo_default_context_t *cr = abstract_cr;
+    cairo_status_t status;
+
+    status = _cairo_gstate_stroke (cr->gstate, cr->path);
+    if (unlikely (status))
+	return status;
+
+    return _cairo_default_context_new_path (cr);
+}
+
+static cairo_status_t
+_cairo_default_context_in_stroke (void *abstract_cr,
+				  double x, double y,
+				  cairo_bool_t *inside)
+{
+    cairo_default_context_t *cr = abstract_cr;
+
+    return _cairo_gstate_in_stroke (cr->gstate,
+				    cr->path,
+				    x, y,
+				    inside);
+}
+
+static cairo_status_t
+_cairo_default_context_stroke_extents (void *abstract_cr,
+				       double *x1, double *y1, double *x2, double *y2)
+{
+    cairo_default_context_t *cr = abstract_cr;
+
+    return _cairo_gstate_stroke_extents (cr->gstate,
+					 cr->path,
+					 x1, y1, x2, y2);
+}
+
+static cairo_status_t
+_cairo_default_context_fill_preserve (void *abstract_cr)
+{
+    cairo_default_context_t *cr = abstract_cr;
+
+    return _cairo_gstate_fill (cr->gstate, cr->path);
+}
+
+static cairo_status_t
+_cairo_default_context_fill (void *abstract_cr)
+{
+    cairo_default_context_t *cr = abstract_cr;
+    cairo_status_t status;
+
+    status = _cairo_gstate_fill (cr->gstate, cr->path);
+    if (unlikely (status))
+	return status;
+
+    return _cairo_default_context_new_path (cr);
+}
+
+static cairo_status_t
+_cairo_default_context_in_fill (void *abstract_cr,
+				double x, double y,
+				cairo_bool_t *inside)
+{
+    cairo_default_context_t *cr = abstract_cr;
+
+    *inside = _cairo_gstate_in_fill (cr->gstate,
+				     cr->path,
+				     x, y);
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_default_context_fill_extents (void *abstract_cr,
+				     double *x1, double *y1, double *x2, double *y2)
+{
+    cairo_default_context_t *cr = abstract_cr;
+
+    return _cairo_gstate_fill_extents (cr->gstate,
+				       cr->path,
+				       x1, y1, x2, y2);
+}
+
+static cairo_status_t
+_cairo_default_context_clip_preserve (void *abstract_cr)
+{
+    cairo_default_context_t *cr = abstract_cr;
+
+    return _cairo_gstate_clip (cr->gstate, cr->path);
+}
+
+static cairo_status_t
+_cairo_default_context_clip (void *abstract_cr)
+{
+    cairo_default_context_t *cr = abstract_cr;
+    cairo_status_t status;
+
+    status = _cairo_gstate_clip (cr->gstate, cr->path);
+    if (unlikely (status))
+	return status;
+
+    return _cairo_default_context_new_path (cr);
+}
+
+static cairo_status_t
+_cairo_default_context_in_clip (void *abstract_cr,
+				double x, double y,
+				cairo_bool_t *inside)
+{
+    cairo_default_context_t *cr = abstract_cr;
+
+    *inside = _cairo_gstate_in_clip (cr->gstate, x, y);
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_default_context_reset_clip (void *abstract_cr)
+{
+    cairo_default_context_t *cr = abstract_cr;
+
+    return _cairo_gstate_reset_clip (cr->gstate);
+}
+
+static cairo_status_t
+_cairo_default_context_clip_extents (void *abstract_cr,
+				     double *x1, double *y1, double *x2, double *y2)
+{
+    cairo_default_context_t *cr = abstract_cr;
+
+    if (! _cairo_gstate_clip_extents (cr->gstate, x1, y1, x2, y2)) {
+	*x1 = -INFINITY;
+	*y1 = -INFINITY;
+	*x2 = +INFINITY;
+	*y2 = +INFINITY;
+    }
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_rectangle_list_t *
+_cairo_default_context_copy_clip_rectangle_list (void *abstract_cr)
+{
+    cairo_default_context_t *cr = abstract_cr;
+
+    return _cairo_gstate_copy_clip_rectangle_list (cr->gstate);
+}
+
+static cairo_status_t
+_cairo_default_context_copy_page (void *abstract_cr)
+{
+    cairo_default_context_t *cr = abstract_cr;
+
+    return _cairo_gstate_copy_page (cr->gstate);
+}
+
+static cairo_status_t
+_cairo_default_context_show_page (void *abstract_cr)
+{
+    cairo_default_context_t *cr = abstract_cr;
+
+    return _cairo_gstate_show_page (cr->gstate);
+}
+
+static cairo_status_t
+_cairo_default_context_set_font_face (void *abstract_cr,
+				      cairo_font_face_t *font_face)
+{
+    cairo_default_context_t *cr = abstract_cr;
+
+    return _cairo_gstate_set_font_face (cr->gstate, font_face);
+}
+
+static cairo_font_face_t *
+_cairo_default_context_get_font_face (void *abstract_cr)
+{
+    cairo_default_context_t *cr = abstract_cr;
+    cairo_font_face_t *font_face;
+    cairo_status_t status;
+
+    status = _cairo_gstate_get_font_face (cr->gstate, &font_face);
+    if (unlikely (status)) {
+	_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
+	return (cairo_font_face_t *) &_cairo_font_face_nil;
+    }
+
+    return font_face;
+}
+
+static cairo_status_t
+_cairo_default_context_font_extents (void *abstract_cr,
+				     cairo_font_extents_t *extents)
+{
+    cairo_default_context_t *cr = abstract_cr;
+
+    return _cairo_gstate_get_font_extents (cr->gstate, extents);
+}
+
+static cairo_status_t
+_cairo_default_context_set_font_size (void *abstract_cr,
+				      double size)
+{
+    cairo_default_context_t *cr = abstract_cr;
+
+    return _cairo_gstate_set_font_size (cr->gstate, size);
+}
+
+static cairo_status_t
+_cairo_default_context_set_font_matrix (void *abstract_cr,
+					const cairo_matrix_t *matrix)
+{
+    cairo_default_context_t *cr = abstract_cr;
+
+    return _cairo_gstate_set_font_matrix (cr->gstate, matrix);
+}
+
+static void
+_cairo_default_context_get_font_matrix (void *abstract_cr,
+					cairo_matrix_t *matrix)
+{
+    cairo_default_context_t *cr = abstract_cr;
+
+    _cairo_gstate_get_font_matrix (cr->gstate, matrix);
+}
+
+static cairo_status_t
+_cairo_default_context_set_font_options (void *abstract_cr,
+					 const cairo_font_options_t *options)
+{
+    cairo_default_context_t *cr = abstract_cr;
+
+    _cairo_gstate_set_font_options (cr->gstate, options);
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static void
+_cairo_default_context_get_font_options (void *abstract_cr,
+					 cairo_font_options_t *options)
+{
+    cairo_default_context_t *cr = abstract_cr;
+
+    _cairo_gstate_get_font_options (cr->gstate, options);
+}
+
+static cairo_status_t
+_cairo_default_context_set_scaled_font (void *abstract_cr,
+					cairo_scaled_font_t *scaled_font)
+{
+    cairo_default_context_t *cr = abstract_cr;
+    cairo_bool_t was_previous;
+    cairo_status_t status;
+
+    if (scaled_font == cr->gstate->scaled_font)
+	return CAIRO_STATUS_SUCCESS;
+
+    was_previous = scaled_font == cr->gstate->previous_scaled_font;
+
+    status = _cairo_gstate_set_font_face (cr->gstate, scaled_font->font_face);
+    if (unlikely (status))
+	return status;
+
+    status = _cairo_gstate_set_font_matrix (cr->gstate, &scaled_font->font_matrix);
+    if (unlikely (status))
+	return status;
+
+    _cairo_gstate_set_font_options (cr->gstate, &scaled_font->options);
+
+    if (was_previous)
+	cr->gstate->scaled_font = cairo_scaled_font_reference (scaled_font);
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_scaled_font_t *
+_cairo_default_context_get_scaled_font (void *abstract_cr)
+{
+    cairo_default_context_t *cr = abstract_cr;
+    cairo_scaled_font_t *scaled_font;
+    cairo_status_t status;
+
+    status = _cairo_gstate_get_scaled_font (cr->gstate, &scaled_font);
+    if (unlikely (status))
+	return _cairo_scaled_font_create_in_error (status);
+
+    return scaled_font;
+}
+
+static cairo_status_t
+_cairo_default_context_glyphs (void *abstract_cr,
+			       const cairo_glyph_t *glyphs,
+			       int num_glyphs,
+			       cairo_glyph_text_info_t *info)
+{
+    cairo_default_context_t *cr = abstract_cr;
+
+    return _cairo_gstate_show_text_glyphs (cr->gstate, glyphs, num_glyphs, info);
+}
+
+static cairo_status_t
+_cairo_default_context_glyph_path (void *abstract_cr,
+				   const cairo_glyph_t *glyphs,
+				   int num_glyphs)
+{
+    cairo_default_context_t *cr = abstract_cr;
+
+    return _cairo_gstate_glyph_path (cr->gstate,
+				     glyphs, num_glyphs,
+				     cr->path);
+}
+
+static cairo_status_t
+_cairo_default_context_glyph_extents (void                *abstract_cr,
+				      const cairo_glyph_t    *glyphs,
+				      int                    num_glyphs,
+				      cairo_text_extents_t   *extents)
+{
+    cairo_default_context_t *cr = abstract_cr;
+
+    return _cairo_gstate_glyph_extents (cr->gstate, glyphs, num_glyphs, extents);
+}
+
+static const cairo_backend_t _cairo_default_context_backend = {
+    CAIRO_TYPE_DEFAULT,
+    _cairo_default_context_destroy,
+
+    _cairo_default_context_get_original_target,
+    _cairo_default_context_get_current_target,
+
+    _cairo_default_context_save,
+    _cairo_default_context_restore,
+
+    _cairo_default_context_push_group,
+    _cairo_default_context_pop_group,
+
+    _cairo_default_context_set_source_rgba,
+    _cairo_default_context_set_source_surface,
+    _cairo_default_context_set_source,
+    _cairo_default_context_get_source,
+
+    _cairo_default_context_set_antialias,
+    _cairo_default_context_set_dash,
+    _cairo_default_context_set_fill_rule,
+    _cairo_default_context_set_line_cap,
+    _cairo_default_context_set_line_join,
+    _cairo_default_context_set_line_width,
+    _cairo_default_context_set_miter_limit,
+    _cairo_default_context_set_opacity,
+    _cairo_default_context_set_operator,
+    _cairo_default_context_set_tolerance,
+    _cairo_default_context_get_antialias,
+    _cairo_default_context_get_dash,
+    _cairo_default_context_get_fill_rule,
+    _cairo_default_context_get_line_cap,
+    _cairo_default_context_get_line_join,
+    _cairo_default_context_get_line_width,
+    _cairo_default_context_get_miter_limit,
+    _cairo_default_context_get_opacity,
+    _cairo_default_context_get_operator,
+    _cairo_default_context_get_tolerance,
+
+    _cairo_default_context_translate,
+    _cairo_default_context_scale,
+    _cairo_default_context_rotate,
+    _cairo_default_context_transform,
+    _cairo_default_context_set_matrix,
+    _cairo_default_context_set_identity_matrix,
+    _cairo_default_context_get_matrix,
+    _cairo_default_context_user_to_device,
+    _cairo_default_context_user_to_device_distance,
+    _cairo_default_context_device_to_user,
+    _cairo_default_context_device_to_user_distance,
+
+    _cairo_default_context_new_path,
+    _cairo_default_context_new_sub_path,
+    _cairo_default_context_move_to,
+    _cairo_default_context_rel_move_to,
+    _cairo_default_context_line_to,
+    _cairo_default_context_rel_line_to,
+    _cairo_default_context_curve_to,
+    _cairo_default_context_rel_curve_to,
+    NULL, /* arc-to */
+    NULL, /* rel-arc-to */
+    _cairo_default_context_close_path,
+    _cairo_default_context_arc,
+    _cairo_default_context_rectangle,
+    _cairo_default_context_path_extents,
+    _cairo_default_context_has_current_point,
+    _cairo_default_context_get_current_point,
+    _cairo_default_context_copy_path,
+    _cairo_default_context_copy_path_flat,
+    _cairo_default_context_append_path,
+
+    NULL, /* stroke-to-path */
+
+    _cairo_default_context_clip,
+    _cairo_default_context_clip_preserve,
+    _cairo_default_context_in_clip,
+    _cairo_default_context_clip_extents,
+    _cairo_default_context_reset_clip,
+    _cairo_default_context_copy_clip_rectangle_list,
+
+    _cairo_default_context_paint,
+    _cairo_default_context_paint_with_alpha,
+    _cairo_default_context_mask,
+
+    _cairo_default_context_stroke,
+    _cairo_default_context_stroke_preserve,
+    _cairo_default_context_in_stroke,
+    _cairo_default_context_stroke_extents,
+
+    _cairo_default_context_fill,
+    _cairo_default_context_fill_preserve,
+    _cairo_default_context_in_fill,
+    _cairo_default_context_fill_extents,
+
+    _cairo_default_context_set_font_face,
+    _cairo_default_context_get_font_face,
+    _cairo_default_context_set_font_size,
+    _cairo_default_context_set_font_matrix,
+    _cairo_default_context_get_font_matrix,
+    _cairo_default_context_set_font_options,
+    _cairo_default_context_get_font_options,
+    _cairo_default_context_set_scaled_font,
+    _cairo_default_context_get_scaled_font,
+    _cairo_default_context_font_extents,
+
+    _cairo_default_context_glyphs,
+    _cairo_default_context_glyph_path,
+    _cairo_default_context_glyph_extents,
+
+    _cairo_default_context_copy_page,
+    _cairo_default_context_show_page,
+};
+
+cairo_t *
+_cairo_default_context_create (void *target)
+{
+    cairo_default_context_t *cr;
+    cairo_status_t status;
+
+    cr = _freed_pool_get (&context_pool);
+    if (unlikely (cr == NULL)) {
+	cr = malloc (sizeof (cairo_default_context_t));
+	if (unlikely (cr == NULL))
+	    return _cairo_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
+    }
+
+    _cairo_init (&cr->base, &_cairo_default_context_backend);
+    _cairo_path_fixed_init (cr->path);
+
+    cr->gstate = &cr->gstate_tail[0];
+    cr->gstate_freelist = &cr->gstate_tail[1];
+    cr->gstate_tail[1].next = NULL;
+
+    status = _cairo_gstate_init (cr->gstate, target);
+    if (unlikely (status)) {
+	_freed_pool_put (&context_pool, cr);
+	return _cairo_create_in_error (status);
+    }
+
+    return &cr->base;
+}
diff --git a/src/cairo-directfb-surface.c b/src/cairo-directfb-surface.c
index fc7509c..3de0168 100644
--- a/src/cairo-directfb-surface.c
+++ b/src/cairo-directfb-surface.c
@@ -39,6 +39,7 @@
 #include "cairo-directfb.h"
 
 #include "cairo-clip-private.h"
+#include "cairo-default-context-private.h"
 #include "cairo-error-private.h"
 
 #include <pixman.h>
@@ -1827,6 +1828,8 @@ _cairo_directfb_surface_is_similar (void *surface_a, void *surface_b)
 static cairo_surface_backend_t
 _cairo_directfb_surface_backend = {
          CAIRO_SURFACE_TYPE_DIRECTFB, /*type*/
+	 _cairo_default_context_create,
+
         _cairo_directfb_surface_create_similar,/*create_similar*/
         _cairo_directfb_surface_finish, /*finish*/
         _cairo_directfb_surface_acquire_source_image,/*acquire_source_image*/
diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index 813e354..eb317f0 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -41,6 +41,7 @@
 #include "cairoint.h"
 
 #include "cairo-composite-rectangles-private.h"
+#include "cairo-default-context-private.h"
 #include "cairo-error-private.h"
 #include "cairo-gl-private.h"
 
@@ -1839,6 +1840,8 @@ _cairo_gl_surface_fill (void			*abstract_surface,
 
 const cairo_surface_backend_t _cairo_gl_surface_backend = {
     CAIRO_SURFACE_TYPE_GL,
+    _cairo_default_context_create,
+
     _cairo_gl_surface_create_similar,
     _cairo_gl_surface_finish,
 
diff --git a/src/cairo-gstate-private.h b/src/cairo-gstate-private.h
index f1e03b3..9e823fa 100644
--- a/src/cairo-gstate-private.h
+++ b/src/cairo-gstate-private.h
@@ -41,6 +41,7 @@
 struct _cairo_gstate {
     cairo_operator_t op;
 
+    double opacity;
     double tolerance;
     cairo_antialias_t antialias;
 
@@ -115,6 +116,12 @@ cairo_private cairo_operator_t
 _cairo_gstate_get_operator (cairo_gstate_t *gstate);
 
 cairo_private cairo_status_t
+_cairo_gstate_set_opacity (cairo_gstate_t *gstate, double opacity);
+
+cairo_private double
+_cairo_gstate_get_opacity (cairo_gstate_t *gstate);
+
+cairo_private cairo_status_t
 _cairo_gstate_set_tolerance (cairo_gstate_t *gstate, double tolerance);
 
 cairo_private double
@@ -289,10 +296,16 @@ cairo_private cairo_rectangle_list_t*
 _cairo_gstate_copy_clip_rectangle_list (cairo_gstate_t *gstate);
 
 cairo_private cairo_status_t
-_cairo_gstate_select_font_face (cairo_gstate_t *gstate,
-				const char *family,
-				cairo_font_slant_t slant,
-				cairo_font_weight_t weight);
+_cairo_gstate_show_surface (cairo_gstate_t	*gstate,
+			    cairo_surface_t	*surface,
+			    double		 x,
+			    double		 y,
+			    double		width,
+			    double		height);
+
+cairo_private cairo_status_t
+_cairo_gstate_set_font_size (cairo_gstate_t *gstate,
+			     double          size);
 
 cairo_private void
 _cairo_gstate_get_font_matrix (cairo_gstate_t *gstate,
@@ -327,18 +340,6 @@ _cairo_gstate_set_font_face (cairo_gstate_t    *gstate,
 			     cairo_font_face_t *font_face);
 
 cairo_private cairo_status_t
-_cairo_gstate_text_to_glyphs (cairo_gstate_t	         *gstate,
-			      double		          x,
-			      double		          y,
-			      const char	         *utf8,
-			      int		          utf8_len,
-			      cairo_glyph_t	        **glyphs,
-			      int		         *num_glyphs,
-			      cairo_text_cluster_t      **clusters,
-			      int		         *num_clusters,
-			      cairo_text_cluster_flags_t *cluster_flags);
-
-cairo_private cairo_status_t
 _cairo_gstate_glyph_extents (cairo_gstate_t *gstate,
 			     const cairo_glyph_t *glyphs,
 			     int num_glyphs,
@@ -346,13 +347,9 @@ _cairo_gstate_glyph_extents (cairo_gstate_t *gstate,
 
 cairo_private cairo_status_t
 _cairo_gstate_show_text_glyphs (cairo_gstate_t		   *gstate,
-				const char		   *utf8,
-				int			    utf8_len,
 				const cairo_glyph_t	   *glyphs,
 				int			    num_glyphs,
-				const cairo_text_cluster_t *clusters,
-				int			    num_clusters,
-			        cairo_text_cluster_flags_t  cluster_flags);
+				cairo_glyph_text_info_t    *info);
 
 cairo_private cairo_status_t
 _cairo_gstate_glyph_path (cairo_gstate_t      *gstate,
diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c
index d9672c2..7aea6c1 100644
--- a/src/cairo-gstate.c
+++ b/src/cairo-gstate.c
@@ -91,6 +91,7 @@ _cairo_gstate_init (cairo_gstate_t  *gstate,
     gstate->next = NULL;
 
     gstate->op = CAIRO_GSTATE_OPERATOR_DEFAULT;
+    gstate->opacity = 1.;
 
     gstate->tolerance = CAIRO_GSTATE_TOLERANCE_DEFAULT;
     gstate->antialias = CAIRO_ANTIALIAS_DEFAULT;
@@ -147,6 +148,7 @@ _cairo_gstate_init_copy (cairo_gstate_t *gstate, cairo_gstate_t *other)
     VG (VALGRIND_MAKE_MEM_UNDEFINED (gstate, sizeof (cairo_gstate_t)));
 
     gstate->op = other->op;
+    gstate->opacity = other->opacity;
 
     gstate->tolerance = other->tolerance;
     gstate->antialias = other->antialias;
@@ -429,6 +431,20 @@ _cairo_gstate_get_operator (cairo_gstate_t *gstate)
 }
 
 cairo_status_t
+_cairo_gstate_set_opacity (cairo_gstate_t *gstate, double op)
+{
+    gstate->opacity = op;
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+double
+_cairo_gstate_get_opacity (cairo_gstate_t *gstate)
+{
+    return gstate->opacity;
+}
+
+cairo_status_t
 _cairo_gstate_set_tolerance (cairo_gstate_t *gstate, double tolerance)
 {
     gstate->tolerance = tolerance;
@@ -1066,6 +1082,8 @@ _cairo_gstate_mask (cairo_gstate_t  *gstate,
     if (_clipped (gstate))
 	return CAIRO_STATUS_SUCCESS;
 
+    assert (gstate->opacity == 1.0);
+
     if (_cairo_pattern_is_opaque (mask, NULL))
 	return _cairo_gstate_paint (gstate);
 
@@ -1143,6 +1161,8 @@ _cairo_gstate_stroke (cairo_gstate_t *gstate, cairo_path_fixed_t *path)
     if (_clipped (gstate))
 	return CAIRO_STATUS_SUCCESS;
 
+    assert (gstate->opacity == 1.0);
+
     memcpy (&style, &gstate->stroke_style, sizeof (gstate->stroke_style));
     if (_cairo_stroke_style_dash_can_approximate (&gstate->stroke_style, &gstate->ctm, gstate->tolerance)) {
         style.dash = dash;
@@ -1243,6 +1263,8 @@ _cairo_gstate_fill (cairo_gstate_t *gstate, cairo_path_fixed_t *path)
     if (_clipped (gstate))
 	return CAIRO_STATUS_SUCCESS;
 
+    assert (gstate->opacity == 1.0);
+
     if (_cairo_path_fixed_fill_is_empty (path)) {
 	if (_cairo_operator_bounded_by_mask (gstate->op))
 	    return CAIRO_STATUS_SUCCESS;
@@ -1580,22 +1602,14 @@ _cairo_gstate_unset_scaled_font (cairo_gstate_t *gstate)
 }
 
 cairo_status_t
-_cairo_gstate_select_font_face (cairo_gstate_t       *gstate,
-				const char           *family,
-				cairo_font_slant_t    slant,
-				cairo_font_weight_t   weight)
+_cairo_gstate_set_font_size (cairo_gstate_t *gstate,
+			     double          size)
 {
-    cairo_font_face_t *font_face;
-    cairo_status_t status;
-
-    font_face = cairo_toy_font_face_create (family, slant, weight);
-    if (font_face->status)
-	return font_face->status;
+    _cairo_gstate_unset_scaled_font (gstate);
 
-    status = _cairo_gstate_set_font_face (gstate, font_face);
-    cairo_font_face_destroy (font_face);
+    cairo_matrix_init_scale (&gstate->font_matrix, size, size);
 
-    return status;
+    return CAIRO_STATUS_SUCCESS;
 }
 
 cairo_status_t
@@ -1810,31 +1824,6 @@ _cairo_gstate_get_font_extents (cairo_gstate_t *gstate,
 }
 
 cairo_status_t
-_cairo_gstate_text_to_glyphs (cairo_gstate_t	         *gstate,
-			      double		          x,
-			      double		          y,
-			      const char	         *utf8,
-			      int		          utf8_len,
-			      cairo_glyph_t	        **glyphs,
-			      int		         *num_glyphs,
-			      cairo_text_cluster_t      **clusters,
-			      int		         *num_clusters,
-			      cairo_text_cluster_flags_t *cluster_flags)
-{
-    cairo_status_t status;
-
-    status = _cairo_gstate_ensure_scaled_font (gstate);
-    if (unlikely (status))
-	return status;
-
-    return cairo_scaled_font_text_to_glyphs (gstate->scaled_font, x, y,
-					     utf8, utf8_len,
-					     glyphs, num_glyphs,
-					     clusters, num_clusters,
-					     cluster_flags);
-}
-
-cairo_status_t
 _cairo_gstate_set_font_face (cairo_gstate_t    *gstate,
 			     cairo_font_face_t *font_face)
 {
@@ -1873,20 +1862,16 @@ _cairo_gstate_glyph_extents (cairo_gstate_t *gstate,
 
 cairo_status_t
 _cairo_gstate_show_text_glyphs (cairo_gstate_t		   *gstate,
-				const char		   *utf8,
-				int			    utf8_len,
 				const cairo_glyph_t	   *glyphs,
 				int			    num_glyphs,
-				const cairo_text_cluster_t *clusters,
-				int			    num_clusters,
-				cairo_text_cluster_flags_t  cluster_flags)
+				cairo_glyph_text_info_t    *info)
 {
     cairo_pattern_union_t source_pattern;
     const cairo_pattern_t *pattern;
     cairo_glyph_t stack_transformed_glyphs[CAIRO_STACK_ARRAY_LENGTH (cairo_glyph_t)];
     cairo_glyph_t *transformed_glyphs;
     cairo_text_cluster_t stack_transformed_clusters[CAIRO_STACK_ARRAY_LENGTH (cairo_text_cluster_t)];
-    cairo_text_cluster_t *transformed_clusters;
+    cairo_text_cluster_t *transformed_clusters = NULL;
     cairo_operator_t op;
     cairo_status_t status;
     cairo_clip_t clip;
@@ -1906,8 +1891,6 @@ _cairo_gstate_show_text_glyphs (cairo_gstate_t		   *gstate,
 	return status;
 
     transformed_glyphs = stack_transformed_glyphs;
-    transformed_clusters = stack_transformed_clusters;
-
     if (num_glyphs > ARRAY_LENGTH (stack_transformed_glyphs)) {
 	transformed_glyphs = cairo_glyph_allocate (num_glyphs);
 	if (unlikely (transformed_glyphs == NULL)) {
@@ -1916,26 +1899,32 @@ _cairo_gstate_show_text_glyphs (cairo_gstate_t		   *gstate,
 	}
     }
 
-    /* Just in case */
-    if (!clusters)
-	num_clusters = 0;
-
-    if (num_clusters > ARRAY_LENGTH (stack_transformed_clusters)) {
-	transformed_clusters = cairo_text_cluster_allocate (num_clusters);
-	if (unlikely (transformed_clusters == NULL)) {
-	    status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
-	    goto CLEANUP_GLYPHS;
+    if (info != NULL) {
+	transformed_clusters = stack_transformed_clusters;
+	if (info->num_clusters > ARRAY_LENGTH (stack_transformed_clusters)) {
+	    transformed_clusters = cairo_text_cluster_allocate (info->num_clusters);
+	    if (unlikely (transformed_clusters == NULL)) {
+		status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+		goto CLEANUP_GLYPHS;
+	    }
 	}
-    }
 
-    status = _cairo_gstate_transform_glyphs_to_backend (gstate,
-							glyphs, num_glyphs,
-							clusters,
-							num_clusters,
-							cluster_flags,
-							transformed_glyphs,
-							&num_glyphs,
-							transformed_clusters);
+	status = _cairo_gstate_transform_glyphs_to_backend (gstate,
+							    glyphs, num_glyphs,
+							    info->clusters,
+							    info->num_clusters,
+							    info->cluster_flags,
+							    transformed_glyphs,
+							    &num_glyphs,
+							    transformed_clusters);
+    } else {
+	status = _cairo_gstate_transform_glyphs_to_backend (gstate,
+							    glyphs, num_glyphs,
+							    NULL, 0, 0,
+							    transformed_glyphs,
+							    &num_glyphs,
+							    NULL);
+    }
 
     if (status || num_glyphs == 0)
 	goto CLEANUP_GLYPHS;
@@ -1961,13 +1950,22 @@ _cairo_gstate_show_text_glyphs (cairo_gstate_t		   *gstate,
     if (cairo_surface_has_show_text_glyphs (gstate->target) ||
 	_cairo_scaled_font_get_max_scale (gstate->scaled_font) <= 10240)
     {
-	status = _cairo_surface_show_text_glyphs (gstate->target, op, pattern,
-						  utf8, utf8_len,
-						  transformed_glyphs, num_glyphs,
-						  transformed_clusters, num_clusters,
-						  cluster_flags,
-						  gstate->scaled_font,
-						  _gstate_get_clip (gstate, &clip));
+	if (info != NULL) {
+	    status = _cairo_surface_show_text_glyphs (gstate->target, op, pattern,
+						      info->utf8, info->utf8_len,
+						      transformed_glyphs, num_glyphs,
+						      transformed_clusters, info->num_clusters,
+						      info->cluster_flags,
+						      gstate->scaled_font,
+						      _gstate_get_clip (gstate, &clip));
+	} else {
+	    status = _cairo_surface_show_text_glyphs (gstate->target, op, pattern,
+						      NULL, 0,
+						      transformed_glyphs, num_glyphs,
+						      NULL, 0, 0,
+						      gstate->scaled_font,
+						      _gstate_get_clip (gstate, &clip));
+	}
     }
     else
     {
@@ -2028,7 +2026,7 @@ _cairo_gstate_glyph_path (cairo_gstate_t      *gstate,
 							glyphs, num_glyphs,
 							NULL, 0, 0,
 							transformed_glyphs,
-							NULL, NULL);
+							&num_glyphs, NULL);
     if (unlikely (status))
 	goto CLEANUP_GLYPHS;
 
diff --git a/src/cairo-image-surface.c b/src/cairo-image-surface.c
index 2c538d5..71d8d88 100644
--- a/src/cairo-image-surface.c
+++ b/src/cairo-image-surface.c
@@ -42,6 +42,7 @@
 #include "cairo-boxes-private.h"
 #include "cairo-clip-private.h"
 #include "cairo-composite-rectangles-private.h"
+#include "cairo-default-context-private.h"
 #include "cairo-error-private.h"
 #include "cairo-region-private.h"
 #include "cairo-scaled-font-private.h"
@@ -4601,6 +4602,8 @@ _cairo_surface_is_image (const cairo_surface_t *surface)
 
 const cairo_surface_backend_t _cairo_image_surface_backend = {
     CAIRO_SURFACE_TYPE_IMAGE,
+    _cairo_default_context_create,
+
     _cairo_image_surface_create_similar,
     _cairo_image_surface_finish,
     _cairo_image_surface_acquire_source_image,
diff --git a/src/cairo-os2-surface.c b/src/cairo-os2-surface.c
index b975828..c8a5458 100644
--- a/src/cairo-os2-surface.c
+++ b/src/cairo-os2-surface.c
@@ -39,6 +39,7 @@
 #include "cairoint.h"
 
 #include "cairo-os2-private.h"
+#include "cairo-default-context-private.h"
 #include "cairo-error-private.h"
 
 #if CAIRO_HAS_FC_FONT
@@ -1438,6 +1439,8 @@ _cairo_os2_surface_mark_dirty_rectangle (void *surface,
 
 static const cairo_surface_backend_t cairo_os2_surface_backend = {
     CAIRO_SURFACE_TYPE_OS2,
+    _cairo_default_context_create,
+
     NULL, /* create_similar */
     _cairo_os2_surface_finish,
     _cairo_os2_surface_acquire_source_image,
diff --git a/src/cairo-paginated-surface.c b/src/cairo-paginated-surface.c
index 9e65f7b..74c8468 100644
--- a/src/cairo-paginated-surface.c
+++ b/src/cairo-paginated-surface.c
@@ -641,8 +641,17 @@ _cairo_paginated_surface_snapshot (void *abstract_other)
     return _cairo_surface_snapshot (other->recording_surface);
 }
 
+static cairo_t *
+_cairo_paginated_context_create (void *target)
+{
+    cairo_paginated_surface_t *surface = target;
+    return cairo_create (surface->recording_surface);
+}
+
 static const cairo_surface_backend_t cairo_paginated_surface_backend = {
     CAIRO_INTERNAL_SURFACE_TYPE_PAGINATED,
+    _cairo_paginated_context_create,
+
     _cairo_paginated_surface_create_similar,
     _cairo_paginated_surface_finish,
     _cairo_paginated_surface_acquire_source_image,
diff --git a/src/cairo-path-private.h b/src/cairo-path-private.h
index 61b4060..7b54317 100644
--- a/src/cairo-path-private.h
+++ b/src/cairo-path-private.h
@@ -41,11 +41,11 @@
 
 cairo_private cairo_path_t *
 _cairo_path_create (cairo_path_fixed_t *path,
-		    cairo_gstate_t     *gstate);
+		    cairo_t		*cr);
 
 cairo_private cairo_path_t *
 _cairo_path_create_flat (cairo_path_fixed_t *path,
-			 cairo_gstate_t     *gstate);
+			 cairo_t	    *cr);
 
 cairo_private cairo_path_t *
 _cairo_path_create_in_error (cairo_status_t status);
diff --git a/src/cairo-path-stroke.c b/src/cairo-path-stroke.c
index 522f1ab..6b0df9c 100644
--- a/src/cairo-path-stroke.c
+++ b/src/cairo-path-stroke.c
@@ -1382,7 +1382,7 @@ BAIL:
     return status;
 }
 
-cairo_status_t
+cairo_int_status_t
 _cairo_path_fixed_stroke_to_traps (const cairo_path_fixed_t	*path,
 				   const cairo_stroke_style_t	*stroke_style,
 				   const cairo_matrix_t	*ctm,
@@ -1390,7 +1390,7 @@ _cairo_path_fixed_stroke_to_traps (const cairo_path_fixed_t	*path,
 				   double		 tolerance,
 				   cairo_traps_t	*traps)
 {
-    cairo_status_t status;
+    cairo_int_status_t status;
     cairo_polygon_t polygon;
 
     /* Before we do anything else, we attempt the rectilinear
diff --git a/src/cairo-path.c b/src/cairo-path.c
index bc5b731..16447a4 100644
--- a/src/cairo-path.c
+++ b/src/cairo-path.c
@@ -138,7 +138,7 @@ _cairo_path_count (cairo_path_t		*path,
 /* Closure for path interpretation. */
 typedef struct cairo_path_populate {
     cairo_path_data_t *data;
-    cairo_gstate_t    *gstate;
+    cairo_t *cr;
 } cpp_t;
 
 static cairo_status_t
@@ -152,7 +152,7 @@ _cpp_move_to (void *closure,
     x = _cairo_fixed_to_double (point->x);
     y = _cairo_fixed_to_double (point->y);
 
-    _cairo_gstate_backend_to_user (cpp->gstate, &x, &y);
+    cairo_device_to_user (cpp->cr, &x, &y);
 
     data->header.type = CAIRO_PATH_MOVE_TO;
     data->header.length = 2;
@@ -177,7 +177,7 @@ _cpp_line_to (void *closure,
     x = _cairo_fixed_to_double (point->x);
     y = _cairo_fixed_to_double (point->y);
 
-    _cairo_gstate_backend_to_user (cpp->gstate, &x, &y);
+    cairo_device_to_user (cpp->cr, &x, &y);
 
     data->header.type = CAIRO_PATH_LINE_TO;
     data->header.length = 2;
@@ -205,15 +205,15 @@ _cpp_curve_to (void			*closure,
 
     x1 = _cairo_fixed_to_double (p1->x);
     y1 = _cairo_fixed_to_double (p1->y);
-    _cairo_gstate_backend_to_user (cpp->gstate, &x1, &y1);
+    cairo_device_to_user (cpp->cr, &x1, &y1);
 
     x2 = _cairo_fixed_to_double (p2->x);
     y2 = _cairo_fixed_to_double (p2->y);
-    _cairo_gstate_backend_to_user (cpp->gstate, &x2, &y2);
+    cairo_device_to_user (cpp->cr, &x2, &y2);
 
     x3 = _cairo_fixed_to_double (p3->x);
     y3 = _cairo_fixed_to_double (p3->y);
-    _cairo_gstate_backend_to_user (cpp->gstate, &x3, &y3);
+    cairo_device_to_user (cpp->cr, &x3, &y3);
 
     data->header.type = CAIRO_PATH_CURVE_TO;
     data->header.length = 4;
@@ -250,23 +250,22 @@ _cpp_close_path (void *closure)
 static cairo_status_t
 _cairo_path_populate (cairo_path_t		*path,
 		      cairo_path_fixed_t	*path_fixed,
-		      cairo_gstate_t		*gstate,
+		      cairo_t			*cr,
 		      cairo_bool_t		 flatten)
 {
     cairo_status_t status;
     cpp_t cpp;
 
     cpp.data = path->data;
-    cpp.gstate = gstate;
+    cpp.cr = cr;
 
     if (flatten) {
-	double tolerance = _cairo_gstate_get_tolerance (gstate);
 	status = _cairo_path_fixed_interpret_flat (path_fixed,
 						   _cpp_move_to,
 						   _cpp_line_to,
 						   _cpp_close_path,
 						   &cpp,
-						   tolerance);
+						   cairo_get_tolerance (cr));
     } else {
 	status = _cairo_path_fixed_interpret (path_fixed,
 					  _cpp_move_to,
@@ -309,7 +308,7 @@ _cairo_path_create_in_error (cairo_status_t status)
 
 static cairo_path_t *
 _cairo_path_create_internal (cairo_path_fixed_t *path_fixed,
-			     cairo_gstate_t     *gstate,
+			     cairo_t		*cr,
 			     cairo_bool_t	 flatten)
 {
     cairo_path_t *path;
@@ -321,7 +320,7 @@ _cairo_path_create_internal (cairo_path_fixed_t *path_fixed,
     }
 
     path->num_data = _cairo_path_count (path, path_fixed,
-					_cairo_gstate_get_tolerance (gstate),
+					cairo_get_tolerance (cr),
 					flatten);
     if (path->num_data < 0) {
 	free (path);
@@ -337,8 +336,7 @@ _cairo_path_create_internal (cairo_path_fixed_t *path_fixed,
 	    return (cairo_path_t*) &_cairo_path_nil;
 	}
 
-	path->status = _cairo_path_populate (path, path_fixed,
-					     gstate, flatten);
+	path->status = _cairo_path_populate (path, path_fixed, cr, flatten);
     } else {
 	path->data = NULL;
 	path->status = CAIRO_STATUS_SUCCESS;
@@ -377,10 +375,10 @@ slim_hidden_def (cairo_path_destroy);
 /**
  * _cairo_path_create:
  * @path: a fixed-point, device-space path to be converted and copied
- * @gstate: the current graphics state
+ * @cr: the current graphics context
  *
  * Creates a user-space #cairo_path_t copy of the given device-space
- * @path. The @gstate parameter provides the inverse CTM for the
+ * @path. The @cr parameter provides the inverse CTM for the
  * conversion.
  *
  * Return value: the new copy of the path. If there is insufficient
@@ -389,19 +387,19 @@ slim_hidden_def (cairo_path_destroy);
  * data==%NULL.
  **/
 cairo_path_t *
-_cairo_path_create (cairo_path_fixed_t *path,
-		    cairo_gstate_t     *gstate)
+_cairo_path_create (cairo_path_fixed_t	*path,
+		    cairo_t		*cr)
 {
-    return _cairo_path_create_internal (path, gstate, FALSE);
+    return _cairo_path_create_internal (path, cr, FALSE);
 }
 
 /**
  * _cairo_path_create_flat:
  * @path: a fixed-point, device-space path to be flattened, converted and copied
- * @gstate: the current graphics state
+ * @cr: the current graphics context
  *
  * Creates a flattened, user-space #cairo_path_t copy of the given
- * device-space @path. The @gstate parameter provide the inverse CTM
+ * device-space @path. The @cr parameter provide the inverse CTM
  * for the conversion, as well as the tolerance value to control the
  * accuracy of the flattening.
  *
@@ -412,9 +410,9 @@ _cairo_path_create (cairo_path_fixed_t *path,
  **/
 cairo_path_t *
 _cairo_path_create_flat (cairo_path_fixed_t *path,
-			 cairo_gstate_t     *gstate)
+			 cairo_t	    *cr)
 {
-    return _cairo_path_create_internal (path, gstate, TRUE);
+    return _cairo_path_create_internal (path, cr, TRUE);
 }
 
 /**
@@ -432,17 +430,6 @@ _cairo_path_append_to_context (const cairo_path_t	*path,
 			       cairo_t			*cr)
 {
     const cairo_path_data_t *p, *end;
-    cairo_fixed_t x1_fixed, y1_fixed;
-    cairo_fixed_t x2_fixed, y2_fixed;
-    cairo_fixed_t x3_fixed, y3_fixed;
-    cairo_matrix_t user_to_backend;
-    cairo_status_t status;
-    double x, y;
-
-    user_to_backend = cr->gstate->ctm;
-    cairo_matrix_multiply (&user_to_backend,
-			   &user_to_backend,
-	                   &cr->gstate->target->device_transform);
 
     end = &path->data[path->num_data];
     for (p = &path->data[0]; p < end; p += p->header.length) {
@@ -451,64 +438,39 @@ _cairo_path_append_to_context (const cairo_path_t	*path,
 	    if (unlikely (p->header.length < 2))
 		return _cairo_error (CAIRO_STATUS_INVALID_PATH_DATA);
 
-	    x = p[1].point.x, y = p[1].point.y;
-	    cairo_matrix_transform_point (&user_to_backend, &x, &y);
-	    x1_fixed = _cairo_fixed_from_double (x);
-	    y1_fixed = _cairo_fixed_from_double (y);
-
-	    status = _cairo_path_fixed_move_to (cr->path, x1_fixed, y1_fixed);
+	    cairo_move_to (cr, p[1].point.x, p[1].point.y);
 	    break;
 
 	case CAIRO_PATH_LINE_TO:
 	    if (unlikely (p->header.length < 2))
 		return _cairo_error (CAIRO_STATUS_INVALID_PATH_DATA);
 
-	    x = p[1].point.x, y = p[1].point.y;
-	    cairo_matrix_transform_point (&user_to_backend, &x, &y);
-	    x1_fixed = _cairo_fixed_from_double (x);
-	    y1_fixed = _cairo_fixed_from_double (y);
-
-	    status = _cairo_path_fixed_line_to (cr->path, x1_fixed, y1_fixed);
+	    cairo_line_to (cr, p[1].point.x, p[1].point.y);
 	    break;
 
 	case CAIRO_PATH_CURVE_TO:
 	    if (unlikely (p->header.length < 4))
 		return _cairo_error (CAIRO_STATUS_INVALID_PATH_DATA);
 
-	    x = p[1].point.x, y = p[1].point.y;
-	    cairo_matrix_transform_point (&user_to_backend, &x, &y);
-	    x1_fixed = _cairo_fixed_from_double (x);
-	    y1_fixed = _cairo_fixed_from_double (y);
-
-	    x = p[2].point.x, y = p[2].point.y;
-	    cairo_matrix_transform_point (&user_to_backend, &x, &y);
-	    x2_fixed = _cairo_fixed_from_double (x);
-	    y2_fixed = _cairo_fixed_from_double (y);
-
-	    x = p[3].point.x, y = p[3].point.y;
-	    cairo_matrix_transform_point (&user_to_backend, &x, &y);
-	    x3_fixed = _cairo_fixed_from_double (x);
-	    y3_fixed = _cairo_fixed_from_double (y);
-
-	    status = _cairo_path_fixed_curve_to (cr->path,
-		                                 x1_fixed, y1_fixed,
-						 x2_fixed, y2_fixed,
-						 x3_fixed, y3_fixed);
+	    cairo_curve_to (cr,
+			    p[1].point.x, p[1].point.y,
+			    p[2].point.x, p[2].point.y,
+			    p[3].point.x, p[3].point.y);
 	    break;
 
 	case CAIRO_PATH_CLOSE_PATH:
 	    if (unlikely (p->header.length < 1))
 		return _cairo_error (CAIRO_STATUS_INVALID_PATH_DATA);
 
-	    status = _cairo_path_fixed_close_path (cr->path);
+	    cairo_close_path (cr);
 	    break;
 
 	default:
 	    return _cairo_error (CAIRO_STATUS_INVALID_PATH_DATA);
 	}
 
-	if (unlikely (status))
-	    return status;
+	if (unlikely (cr->status))
+	    return cr->status;
     }
 
     return CAIRO_STATUS_SUCCESS;
diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c
index b4b2981..9447c36 100644
--- a/src/cairo-pdf-surface.c
+++ b/src/cairo-pdf-surface.c
@@ -47,6 +47,7 @@
 #include "cairo-pdf-shading-private.h"
 #include "cairo-analysis-surface-private.h"
 #include "cairo-composite-rectangles-private.h"
+#include "cairo-default-context-private.h"
 #include "cairo-error-private.h"
 #include "cairo-image-info-private.h"
 #include "cairo-recording-surface-private.h"
@@ -6566,6 +6567,8 @@ _cairo_pdf_surface_set_paginated_mode (void			*abstract_surface,
 
 static const cairo_surface_backend_t cairo_pdf_surface_backend = {
     CAIRO_SURFACE_TYPE_PDF,
+    _cairo_default_context_create,
+
     NULL, /* create similar: handled by wrapper */
     _cairo_pdf_surface_finish,
     NULL, /* acquire_source_image */
diff --git a/src/cairo-private.h b/src/cairo-private.h
index 901a69a..9f4f55b 100644
--- a/src/cairo-private.h
+++ b/src/cairo-private.h
@@ -36,22 +36,29 @@
 #ifndef CAIRO_PRIVATE_H
 #define CAIRO_PRIVATE_H
 
+#include "cairo-types-private.h"
 #include "cairo-reference-count-private.h"
-#include "cairo-gstate-private.h"
-#include "cairo-path-fixed-private.h"
+
+CAIRO_BEGIN_DECLS
 
 struct _cairo {
     cairo_reference_count_t ref_count;
-
     cairo_status_t status;
-
     cairo_user_data_array_t user_data;
 
-    cairo_gstate_t *gstate;
-    cairo_gstate_t  gstate_tail[2];
-    cairo_gstate_t *gstate_freelist;
-
-    cairo_path_fixed_t path[1];
+    const cairo_backend_t *backend;
 };
 
+cairo_private cairo_t *
+_cairo_create_in_error (cairo_status_t status);
+
+cairo_private void
+_cairo_init (cairo_t *cr,
+	     const cairo_backend_t *backend);
+
+cairo_private void
+_cairo_fini (cairo_t *cr);
+
+CAIRO_END_DECLS
+
 #endif /* CAIRO_PRIVATE_H */
diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c
index 5c83453..cf6908f 100644
--- a/src/cairo-ps-surface.c
+++ b/src/cairo-ps-surface.c
@@ -60,6 +60,7 @@
 #include "cairo-pdf-operators-private.h"
 #include "cairo-pdf-shading-private.h"
 #include "cairo-composite-rectangles-private.h"
+#include "cairo-default-context-private.h"
 #include "cairo-error-private.h"
 #include "cairo-scaled-font-subsets-private.h"
 #include "cairo-paginated-private.h"
@@ -3931,6 +3932,8 @@ _cairo_ps_surface_supports_fine_grained_fallbacks (void	    *abstract_surface)
 
 static const cairo_surface_backend_t cairo_ps_surface_backend = {
     CAIRO_SURFACE_TYPE_PS,
+    _cairo_default_context_create,
+
     NULL, /* create similar: handled by wrapper */
     _cairo_ps_surface_finish,
     NULL, /* acquire_source_image */
diff --git a/src/cairo-qt-surface.cpp b/src/cairo-qt-surface.cpp
index 25ee9e9..772d610 100644
--- a/src/cairo-qt-surface.cpp
+++ b/src/cairo-qt-surface.cpp
@@ -40,6 +40,7 @@
 #include "cairoint.h"
 
 #include "cairo-clip-private.h"
+#include "cairo-default-context-private.h"
 #include "cairo-error-private.h"
 #include "cairo-region-private.h"
 #include "cairo-surface-clipper-private.h"
@@ -1551,6 +1552,8 @@ _cairo_qt_surface_mark_dirty (void *abstract_surface,
 
 static const cairo_surface_backend_t cairo_qt_surface_backend = {
     CAIRO_SURFACE_TYPE_QT,
+    _cairo_default_context_create,
+
     _cairo_qt_surface_create_similar,
     _cairo_qt_surface_finish,
     _cairo_qt_surface_acquire_source_image,
diff --git a/src/cairo-quartz-image-surface.c b/src/cairo-quartz-image-surface.c
index 81ed5fe..cd675a1 100644
--- a/src/cairo-quartz-image-surface.c
+++ b/src/cairo-quartz-image-surface.c
@@ -159,6 +159,8 @@ _cairo_quartz_image_surface_flush (void *asurface)
 
 static const cairo_surface_backend_t cairo_quartz_image_surface_backend = {
     CAIRO_SURFACE_TYPE_QUARTZ_IMAGE,
+    _cairo_default_context_create,
+
     _cairo_quartz_image_surface_create_similar,
     _cairo_quartz_image_surface_finish,
     _cairo_quartz_image_surface_acquire_source_image,
diff --git a/src/cairo-recording-surface.c b/src/cairo-recording-surface.c
index ce8a95a..84ae347 100644
--- a/src/cairo-recording-surface.c
+++ b/src/cairo-recording-surface.c
@@ -79,6 +79,7 @@
 #include "cairoint.h"
 #include "cairo-analysis-surface-private.h"
 #include "cairo-clip-private.h"
+#include "cairo-default-context-private.h"
 #include "cairo-error-private.h"
 #include "cairo-recording-surface-private.h"
 #include "cairo-surface-wrapper-private.h"
@@ -707,6 +708,8 @@ _cairo_surface_is_recording (const cairo_surface_t *surface)
 
 static const cairo_surface_backend_t cairo_recording_surface_backend = {
     CAIRO_SURFACE_TYPE_RECORDING,
+    _cairo_default_context_create,
+
     _cairo_recording_surface_create_similar,
     _cairo_recording_surface_finish,
     _cairo_recording_surface_acquire_source_image,
diff --git a/src/cairo-scaled-font-subsets.c b/src/cairo-scaled-font-subsets.c
index f5e6dec..ec228ca 100644
--- a/src/cairo-scaled-font-subsets.c
+++ b/src/cairo-scaled-font-subsets.c
@@ -630,6 +630,7 @@ _cairo_sub_font_map_glyph (cairo_sub_font_t	*sub_font,
 	 * create a separate subset just for the .notdef glyph.
 	 */
 	is_latin = FALSE;
+	latin_character = -1;
 	if (sub_font->use_latin_subset &&
 	    (! _cairo_font_face_is_user (sub_font->scaled_font->font_face)))
 	{
diff --git a/src/cairo-script-surface.c b/src/cairo-script-surface.c
index 89311a0..6b59464 100644
--- a/src/cairo-script-surface.c
+++ b/src/cairo-script-surface.c
@@ -3405,6 +3405,8 @@ _cairo_script_surface_get_extents (void *abstract_surface,
 static const cairo_surface_backend_t
 _cairo_script_surface_backend = {
     CAIRO_SURFACE_TYPE_SCRIPT,
+    _cairo_default_context_create,
+
     _cairo_script_surface_create_similar,
     _cairo_script_surface_finish,
     _cairo_script_surface_acquire_source_image,
diff --git a/src/cairo-surface-snapshot.c b/src/cairo-surface-snapshot.c
index 20cc6b9..757ec1e 100644
--- a/src/cairo-surface-snapshot.c
+++ b/src/cairo-surface-snapshot.c
@@ -89,6 +89,7 @@ _cairo_surface_snapshot_get_extents (void                  *abstract_surface,
 
 static const cairo_surface_backend_t _cairo_surface_snapshot_backend = {
     CAIRO_INTERNAL_SURFACE_TYPE_SNAPSHOT,
+    NULL,
 
     NULL, /* create similar */
     _cairo_surface_snapshot_finish,
diff --git a/src/cairo-surface-subsurface.c b/src/cairo-surface-subsurface.c
index 3cf8330..ff1df83 100644
--- a/src/cairo-surface-subsurface.c
+++ b/src/cairo-surface-subsurface.c
@@ -442,8 +442,17 @@ _cairo_surface_subsurface_snapshot (void *abstract_surface)
     return &snapshot->base;
 }
 
+static cairo_t *
+_cairo_surface_subsurface_create_context(void *target)
+{
+    cairo_surface_subsurface_t *surface = target;
+    return cairo_create (surface->target);
+}
+
 static const cairo_surface_backend_t _cairo_surface_subsurface_backend = {
     CAIRO_SURFACE_TYPE_SUBSURFACE,
+    _cairo_surface_subsurface_create_context,
+
     _cairo_surface_subsurface_create_similar,
     _cairo_surface_subsurface_finish,
 
diff --git a/src/cairo-svg-surface.c b/src/cairo-svg-surface.c
index bb5bccf..7adcfb7 100644
--- a/src/cairo-svg-surface.c
+++ b/src/cairo-svg-surface.c
@@ -43,6 +43,7 @@
 #include "cairoint.h"
 #include "cairo-svg.h"
 #include "cairo-analysis-surface-private.h"
+#include "cairo-default-context-private.h"
 #include "cairo-error-private.h"
 #include "cairo-image-info-private.h"
 #include "cairo-recording-surface-private.h"
@@ -2574,6 +2575,8 @@ _cairo_svg_surface_get_font_options (void                  *abstract_surface,
 
 static const cairo_surface_backend_t cairo_svg_surface_backend = {
 	CAIRO_SURFACE_TYPE_SVG,
+	_cairo_default_context_create,
+
 	NULL, /* create_similar: handled by wrapper */
 	_cairo_svg_surface_finish,
 	NULL, /* acquire_source_image */
diff --git a/src/cairo-tee-surface.c b/src/cairo-tee-surface.c
index 83811bd..df0ae99 100644
--- a/src/cairo-tee-surface.c
+++ b/src/cairo-tee-surface.c
@@ -42,6 +42,7 @@
 
 #include "cairo-tee.h"
 
+#include "cairo-default-context-private.h"
 #include "cairo-error-private.h"
 #include "cairo-tee-surface-private.h"
 #include "cairo-surface-wrapper-private.h"
@@ -395,6 +396,8 @@ _cairo_tee_surface_show_text_glyphs (void		    *abstract_surface,
 
 static const cairo_surface_backend_t cairo_tee_surface_backend = {
     CAIRO_SURFACE_TYPE_TEE,
+    _cairo_default_context_create, /* XXX */
+
     _cairo_tee_surface_create_similar,
     _cairo_tee_surface_finish,
     _cairo_tee_surface_acquire_source_image,
diff --git a/src/cairo-type3-glyph-surface.c b/src/cairo-type3-glyph-surface.c
index 74257d4..e9e8311 100644
--- a/src/cairo-type3-glyph-surface.c
+++ b/src/cairo-type3-glyph-surface.c
@@ -42,6 +42,7 @@
 #include "cairo-output-stream-private.h"
 #include "cairo-recording-surface-private.h"
 #include "cairo-analysis-surface-private.h"
+#include "cairo-default-context-private.h"
 #include "cairo-error-private.h"
 #include "cairo-surface-clipper-private.h"
 
@@ -321,6 +322,8 @@ _cairo_type3_glyph_surface_show_glyphs (void		     *abstract_surface,
 
 static const cairo_surface_backend_t cairo_type3_glyph_surface_backend = {
     CAIRO_INTERNAL_SURFACE_TYPE_TYPE3_GLYPH,
+    _cairo_default_context_create,
+
     NULL, /* _cairo_type3_glyph_surface_create_similar */
     _cairo_type3_glyph_surface_finish,
     NULL, /* acquire_source_image */
diff --git a/src/cairo-types-private.h b/src/cairo-types-private.h
index 967781c..5460a42 100644
--- a/src/cairo-types-private.h
+++ b/src/cairo-types-private.h
@@ -64,6 +64,8 @@ typedef struct _cairo_color_stop cairo_color_stop_t;
 typedef struct _cairo_device_backend cairo_device_backend_t;
 typedef struct _cairo_font_face_backend     cairo_font_face_backend_t;
 typedef struct _cairo_gstate cairo_gstate_t;
+typedef struct _cairo_gstate_backend cairo_gstate_backend_t;
+typedef struct _cairo_glyph_text_info cairo_glyph_text_info_t;
 typedef struct _cairo_hash_entry cairo_hash_entry_t;
 typedef struct _cairo_hash_table cairo_hash_table_t;
 typedef struct _cairo_image_surface cairo_image_surface_t;
@@ -174,6 +176,16 @@ struct _cairo_font_options {
     cairo_round_glyph_positions_t round_glyph_positions;
 };
 
+struct _cairo_glyph_text_info {
+    const char *utf8;
+    int utf8_len;
+
+    const cairo_text_cluster_t *clusters;
+    int num_clusters;
+    cairo_text_cluster_flags_t cluster_flags;
+};
+
+
 /* XXX: Right now, the _cairo_color structure puts unpremultiplied
    color in the doubles and premultiplied color in the shorts. Yes,
    this is crazy insane, (but at least we don't export this
@@ -209,7 +221,7 @@ struct _cairo_color_stop {
 typedef enum _cairo_paginated_mode {
     CAIRO_PAGINATED_MODE_ANALYZE,	/* analyze page regions */
     CAIRO_PAGINATED_MODE_RENDER,	/* render page contents */
-    CAIRO_PAGINATED_MODE_FALLBACK 	/* paint fallback images */
+    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
diff --git a/src/cairo-vg-surface.c b/src/cairo-vg-surface.c
index 0034d73..06d46c1 100644
--- a/src/cairo-vg-surface.c
+++ b/src/cairo-vg-surface.c
@@ -39,6 +39,7 @@
 #include "cairo-vg.h"
 
 #include "cairo-cache-private.h"
+#include "cairo-default-context-private.h"
 #include "cairo-error-private.h"
 #include "cairo-path-fixed-private.h"
 #include "cairo-recording-surface-private.h"
@@ -1547,6 +1548,8 @@ _vg_surface_finish (void *abstract_surface)
 
 static const cairo_surface_backend_t cairo_vg_surface_backend = {
     CAIRO_SURFACE_TYPE_VG,
+    _cairo_default_context_create, /* XXX */
+
     _vg_surface_create_similar,
     _vg_surface_finish,
 
diff --git a/src/cairo-win32-printing-surface.c b/src/cairo-win32-printing-surface.c
index 8023335..58d404a 100644
--- a/src/cairo-win32-printing-surface.c
+++ b/src/cairo-win32-printing-surface.c
@@ -46,6 +46,7 @@
 
 #include "cairoint.h"
 
+#include "cairo-default-context-private.h"
 #include "cairo-error-private.h"
 #include "cairo-paginated-private.h"
 
@@ -1861,6 +1862,8 @@ _cairo_surface_is_win32_printing (cairo_surface_t *surface)
 
 static const cairo_surface_backend_t cairo_win32_printing_surface_backend = {
     CAIRO_SURFACE_TYPE_WIN32_PRINTING,
+    _cairo_default_context_create,
+
     _cairo_win32_printing_surface_create_similar,
     _cairo_win32_surface_finish,
     NULL, /* acquire_source_image */
diff --git a/src/cairo-win32-surface.c b/src/cairo-win32-surface.c
index 1be2192..24b1ba6 100644
--- a/src/cairo-win32-surface.c
+++ b/src/cairo-win32-surface.c
@@ -49,6 +49,7 @@
 
 #include "cairo-clip-private.h"
 #include "cairo-composite-rectangles-private.h"
+#include "cairo-default-context-private.h"
 #include "cairo-error-private.h"
 #include "cairo-paginated-private.h"
 #include "cairo-win32-private.h"
@@ -2089,6 +2090,8 @@ _cairo_win32_surface_create_span_renderer (cairo_operator_t	 op,
 
 static const cairo_surface_backend_t cairo_win32_surface_backend = {
     CAIRO_SURFACE_TYPE_WIN32,
+    _cairo_default_context_create,
+
     _cairo_win32_surface_create_similar,
     _cairo_win32_surface_finish,
     _cairo_win32_surface_acquire_source_image,
diff --git a/src/cairo-xcb-surface-core.c b/src/cairo-xcb-surface-core.c
index 6801e3f..1a2bcad 100644
--- a/src/cairo-xcb-surface-core.c
+++ b/src/cairo-xcb-surface-core.c
@@ -75,6 +75,7 @@ _cairo_xcb_pixmap_finish (void *abstract_surface)
 static const cairo_surface_backend_t _cairo_xcb_pixmap_backend = {
     CAIRO_SURFACE_TYPE_XCB,
     NULL,
+    NULL,
     _cairo_xcb_pixmap_finish,
 };
 
diff --git a/src/cairo-xcb-surface-render.c b/src/cairo-xcb-surface-render.c
index 5a0bb22..065e896 100644
--- a/src/cairo-xcb-surface-render.c
+++ b/src/cairo-xcb-surface-render.c
@@ -95,6 +95,7 @@ _cairo_xcb_picture_finish (void *abstract_surface)
 static const cairo_surface_backend_t _cairo_xcb_picture_backend = {
     CAIRO_SURFACE_TYPE_XCB,
     NULL,
+    NULL,
     _cairo_xcb_picture_finish,
 };
 
diff --git a/src/cairo-xcb-surface.c b/src/cairo-xcb-surface.c
index bba7a9c..a890fe8 100644
--- a/src/cairo-xcb-surface.c
+++ b/src/cairo-xcb-surface.c
@@ -43,6 +43,8 @@
 #include "cairo-xcb.h"
 #include "cairo-xcb-private.h"
 
+#include "cairo-default-context-private.h"
+
 #define AllPlanes ((unsigned) -1)
 #define CAIRO_ASSUME_PIXMAP 20
 #define XLIB_COORD_MAX 32767
@@ -923,6 +925,7 @@ _cairo_xcb_surface_glyphs (void				*abstract_surface,
 
 const cairo_surface_backend_t _cairo_xcb_surface_backend = {
     CAIRO_SURFACE_TYPE_XCB,
+    _cairo_default_context_create,
 
     _cairo_xcb_surface_create_similar,
     _cairo_xcb_surface_finish,
diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c
index 8585208..4aecac5 100644
--- a/src/cairo-xlib-surface.c
+++ b/src/cairo-xlib-surface.c
@@ -52,6 +52,7 @@
 #include "cairo-xlib-private.h"
 #include "cairo-xlib-surface-private.h"
 #include "cairo-clip-private.h"
+#include "cairo-default-context-private.h"
 #include "cairo-error-private.h"
 #include "cairo-scaled-font-private.h"
 #include "cairo-surface-snapshot-private.h"
@@ -3133,6 +3134,8 @@ _cairo_xlib_surface_is_similar (void		*surface_a,
 
 static const cairo_surface_backend_t cairo_xlib_surface_backend = {
     CAIRO_SURFACE_TYPE_XLIB,
+    _cairo_default_context_create,
+
     _cairo_xlib_surface_create_similar,
     _cairo_xlib_surface_finish,
     _cairo_xlib_surface_acquire_source_image,
diff --git a/src/cairo-xlib-xcb-surface.c b/src/cairo-xlib-xcb-surface.c
index 0ffbc4c..6381e05 100644
--- a/src/cairo-xlib-xcb-surface.c
+++ b/src/cairo-xlib-xcb-surface.c
@@ -46,6 +46,8 @@
 #include "cairo-xcb-private.h"
 #include "cairo-xlib-xrender-private.h"
 
+#include "cairo-default-context-private.h"
+
 #include <X11/Xlib-xcb.h>
 #include <X11/Xlibint.h>	/* For XESetCloseDisplay */
 
@@ -60,7 +62,7 @@ struct cairo_xlib_xcb_display_t {
 };
 typedef struct cairo_xlib_xcb_display_t cairo_xlib_xcb_display_t;
 
-/* List of all cairo_xlib_xcb_display_t alive,
+/* List of all #cairo_xlib_xcb_display_t alive,
  * protected by _cairo_xlib_display_mutex */
 static cairo_list_t displays;
 
@@ -232,6 +234,8 @@ _cairo_xlib_xcb_surface_mark_dirty (void *abstract_surface,
 
 static const cairo_surface_backend_t _cairo_xlib_xcb_surface_backend = {
     CAIRO_SURFACE_TYPE_XLIB,
+    _cairo_default_context_create, /* XXX */
+
     _cairo_xlib_xcb_surface_create_similar,
     _cairo_xlib_xcb_surface_finish,
     _cairo_xlib_xcb_surface_acquire_source_image,
diff --git a/src/cairo-xml-surface.c b/src/cairo-xml-surface.c
index 83d4f91..cf99ee6 100644
--- a/src/cairo-xml-surface.c
+++ b/src/cairo-xml-surface.c
@@ -46,6 +46,7 @@
 
 #include "cairo-clip-private.h"
 #include "cairo-device-private.h"
+#include "cairo-default-context-private.h"
 #include "cairo-error-private.h"
 #include "cairo-output-stream-private.h"
 #include "cairo-recording-surface-private.h"
@@ -989,6 +990,8 @@ _cairo_xml_surface_glyphs (void			    *abstract_surface,
 static const cairo_surface_backend_t
 _cairo_xml_surface_backend = {
     CAIRO_SURFACE_TYPE_XML,
+    _cairo_default_context_create,
+
     _cairo_xml_surface_create_similar,
     NULL,
     NULL, NULL, /* source image */
diff --git a/src/cairo.c b/src/cairo.c
index 0aae04b..42e3b5f 100644
--- a/src/cairo.c
+++ b/src/cairo.c
@@ -3,6 +3,7 @@
  *
  * Copyright © 2002 University of Southern California
  * Copyright © 2005 Red Hat, Inc.
+ * Copyright © 2011 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
@@ -34,15 +35,18 @@
  *
  * 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-arc-private.h"
+#include "cairo-backend-private.h"
 #include "cairo-error-private.h"
-#include "cairo-freed-pool-private.h"
 #include "cairo-path-private.h"
+#include "cairo-surface-private.h"
+
+#include <assert.h>
 
 /**
  * SECTION:cairo
@@ -101,34 +105,12 @@
  * space</firstterm>.
  */
 
-#define CAIRO_TOLERANCE_MINIMUM	_cairo_fixed_to_double(1)
-
-#if !defined(INFINITY)
-#define INFINITY HUGE_VAL
-#endif
-
 #define DEFINE_NIL_CONTEXT(status)					\
     {									\
 	CAIRO_REFERENCE_COUNT_INVALID,	/* ref_count */			\
 	status,				/* status */			\
 	{ 0, 0, 0, NULL },		/* user_data */			\
-	NULL,				/* gstate */			\
-	{{ 0 }, { 0 }},			/* gstate_tail */		\
-	NULL,				/* gstate_freelist */		\
-	{{				/* path */			\
-		{ 0, 0 },		/* last_move_point */		\
-		{ 0, 0 },		/* current point */		\
-		FALSE,			/* has_current_point */		\
-		TRUE,			/* needs_move_to */		\
-		FALSE,			/* has_extents */		\
-		FALSE,			/* has_curve_to */		\
-		TRUE,			/* stroke_is_rectilinear */	\
-		TRUE,			/* fill_is_rectilinear */	\
-		TRUE,			/* fill_maybe_region */		\
-		TRUE,			/* fill_is_empty */		\
-		{{0, 0}, {0, 0}},	/* extents */			\
-		{{{NULL,NULL}}}		/* link */			\
-	}}								\
+	NULL								\
     }
 
 static const cairo_t _cairo_nil[] = {
@@ -170,11 +152,8 @@ static const cairo_t _cairo_nil[] = {
     DEFINE_NIL_CONTEXT (CAIRO_STATUS_INVALID_MESH_CONSTRUCTION),
     DEFINE_NIL_CONTEXT (CAIRO_STATUS_DEVICE_FINISHED)
 };
-
 COMPILE_TIME_ASSERT (ARRAY_LENGTH (_cairo_nil) == CAIRO_STATUS_LAST_STATUS - 1);
 
-#include <assert.h>
-
 /**
  * _cairo_set_error:
  * @cr: a cairo context
@@ -199,9 +178,7 @@ _cairo_set_error (cairo_t *cr, cairo_status_t status)
     _cairo_status_set_error (&cr->status, _cairo_error (status));
 }
 
-static freed_pool_t context_pool;
-
-static cairo_t *
+cairo_t *
 _cairo_create_in_error (cairo_status_t status)
 {
     cairo_t *cr;
@@ -214,12 +191,6 @@ _cairo_create_in_error (cairo_status_t status)
     return cr;
 }
 
-void
-_cairo_reset_static_data (void)
-{
-    _freed_pool_reset (&context_pool);
-}
-
 /**
  * cairo_create:
  * @target: target surface for the context
@@ -247,41 +218,26 @@ _cairo_reset_static_data (void)
 cairo_t *
 cairo_create (cairo_surface_t *target)
 {
-    cairo_t *cr;
-    cairo_status_t status;
-
     if (unlikely (target == NULL))
 	return _cairo_create_in_error (_cairo_error (CAIRO_STATUS_NULL_POINTER));
     if (unlikely (target->status))
 	return _cairo_create_in_error (target->status);
 
-    cr = _freed_pool_get (&context_pool);
-    if (unlikely (cr == NULL)) {
-	cr = malloc (sizeof (cairo_t));
-	if (unlikely (cr == NULL))
-	    return _cairo_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
-    }
+    return target->backend->create_context (target);
 
-    CAIRO_REFERENCE_COUNT_INIT (&cr->ref_count, 1);
+}
+slim_hidden_def (cairo_create);
 
+void
+_cairo_init (cairo_t *cr,
+	     const cairo_backend_t *backend)
+{
+    CAIRO_REFERENCE_COUNT_INIT (&cr->ref_count, 1);
     cr->status = CAIRO_STATUS_SUCCESS;
-
     _cairo_user_data_array_init (&cr->user_data);
-    _cairo_path_fixed_init (cr->path);
-
-    cr->gstate = &cr->gstate_tail[0];
-    cr->gstate_freelist = &cr->gstate_tail[1];
-    cr->gstate_tail[1].next = NULL;
-
-    status = _cairo_gstate_init (cr->gstate, target);
-    if (unlikely (status)) {
-	_freed_pool_put (&context_pool, cr);
-	cr = _cairo_create_in_error (status);
-    }
 
-    return cr;
+    cr->backend = backend;
 }
-slim_hidden_def (cairo_create);
 
 /**
  * cairo_reference:
@@ -309,6 +265,12 @@ cairo_reference (cairo_t *cr)
     return cr;
 }
 
+void
+_cairo_fini (cairo_t *cr)
+{
+    _cairo_user_data_array_fini (&cr->user_data);
+}
+
 /**
  * cairo_destroy:
  * @cr: a #cairo_t
@@ -328,27 +290,7 @@ cairo_destroy (cairo_t *cr)
     if (! _cairo_reference_count_dec_and_test (&cr->ref_count))
 	return;
 
-    while (cr->gstate != &cr->gstate_tail[0]) {
-	if (_cairo_gstate_restore (&cr->gstate, &cr->gstate_freelist))
-	    break;
-    }
-
-    _cairo_gstate_fini (cr->gstate);
-    cr->gstate_freelist = cr->gstate_freelist->next; /* skip over tail[1] */
-    while (cr->gstate_freelist != NULL) {
-	cairo_gstate_t *gstate = cr->gstate_freelist;
-	cr->gstate_freelist = gstate->next;
-	free (gstate);
-    }
-
-    _cairo_path_fixed_fini (cr->path);
-
-    _cairo_user_data_array_fini (&cr->user_data);
-
-    /* mark the context as invalid to protect against misuse */
-    cr->status = CAIRO_STATUS_NULL_POINTER;
-
-    _freed_pool_put (&context_pool, cr);
+    cr->backend->destroy (cr);
 }
 slim_hidden_def (cairo_destroy);
 
@@ -370,8 +312,7 @@ void *
 cairo_get_user_data (cairo_t			 *cr,
 		     const cairo_user_data_key_t *key)
 {
-    return _cairo_user_data_array_get_data (&cr->user_data,
-					    key);
+    return _cairo_user_data_array_get_data (&cr->user_data, key);
 }
 
 /**
@@ -449,7 +390,7 @@ cairo_save (cairo_t *cr)
     if (unlikely (cr->status))
 	return;
 
-    status = _cairo_gstate_save (&cr->gstate, &cr->gstate_freelist);
+    status = cr->backend->save (cr);
     if (unlikely (status))
 	_cairo_set_error (cr, status);
 }
@@ -471,12 +412,7 @@ cairo_restore (cairo_t *cr)
     if (unlikely (cr->status))
 	return;
 
-    if (unlikely (_cairo_gstate_is_group (cr->gstate))) {
-	_cairo_set_error (cr, _cairo_error (CAIRO_STATUS_INVALID_RESTORE));
-	return;
-    }
-
-    status = _cairo_gstate_restore (&cr->gstate, &cr->gstate_freelist);
+    status = cr->backend->restore (cr);
     if (unlikely (status))
 	_cairo_set_error (cr, status);
 }
@@ -554,68 +490,12 @@ cairo_push_group (cairo_t *cr)
 void
 cairo_push_group_with_content (cairo_t *cr, cairo_content_t content)
 {
-    cairo_surface_t *group_surface;
-    cairo_clip_t *clip;
     cairo_status_t status;
 
     if (unlikely (cr->status))
 	return;
 
-    clip = _cairo_gstate_get_clip (cr->gstate);
-    if (clip->all_clipped) {
-	group_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 0, 0);
-	status = group_surface->status;
-	if (unlikely (status))
-	    goto bail;
-    } else {
-	cairo_surface_t *parent_surface;
-	const cairo_rectangle_int_t *clip_extents;
-	cairo_rectangle_int_t extents;
-        cairo_matrix_t matrix;
-	cairo_bool_t is_empty;
-
-	parent_surface = _cairo_gstate_get_target (cr->gstate);
-
-	/* Get the extents that we'll use in creating our new group surface */
-	is_empty = _cairo_surface_get_extents (parent_surface, &extents);
-	clip_extents = _cairo_clip_get_extents (_cairo_gstate_get_clip (cr->gstate));
-	if (clip_extents != NULL)
-	    _cairo_rectangle_intersect (&extents, clip_extents);
-
-	group_surface = _cairo_surface_create_similar_solid (parent_surface,
-							     content,
-							     extents.width,
-							     extents.height,
-							     CAIRO_COLOR_TRANSPARENT,
-							     TRUE);
-	status = group_surface->status;
-	if (unlikely (status))
-	    goto bail;
-
-	/* 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_matrix_init_translate (&matrix, -extents.x, -extents.y);
-	_cairo_path_fixed_transform (cr->path, &matrix);
-    }
-
-    /* create a new gstate for the redirect */
-    cairo_save (cr);
-    if (unlikely (cr->status))
-	goto bail;
-
-    status = _cairo_gstate_redirect_target (cr->gstate, group_surface);
-
-bail:
-    cairo_surface_destroy (group_surface);
+    status = cr->backend->push_group (cr, content);
     if (unlikely (status))
 	_cairo_set_error (cr, status);
 }
@@ -645,55 +525,14 @@ slim_hidden_def(cairo_push_group_with_content);
 cairo_pattern_t *
 cairo_pop_group (cairo_t *cr)
 {
-    cairo_surface_t *group_surface;
     cairo_pattern_t *group_pattern;
-    cairo_matrix_t group_matrix, device_transform_matrix;
-    cairo_status_t status;
 
     if (unlikely (cr->status))
 	return _cairo_pattern_create_in_error (cr->status);
 
-    /* Verify that we are at the right nesting level */
-    if (unlikely (! _cairo_gstate_is_group (cr->gstate))) {
-	_cairo_set_error (cr, CAIRO_STATUS_INVALID_POP_GROUP);
-	return _cairo_pattern_create_in_error (CAIRO_STATUS_INVALID_POP_GROUP);
-    }
-
-    /* Get a reference to the active surface before restoring */
-    group_surface = _cairo_gstate_get_target (cr->gstate);
-    group_surface = cairo_surface_reference (group_surface);
-
-    status = _cairo_gstate_restore (&cr->gstate, &cr->gstate_freelist);
-    assert (status == CAIRO_STATUS_SUCCESS);
-
-    group_pattern = cairo_pattern_create_for_surface (group_surface);
-    status = group_pattern->status;
-    if (unlikely (status)) {
-	_cairo_set_error (cr, status);
-        goto done;
-    }
-
-    _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_matrix_multiply (&device_transform_matrix, 
-                           &_cairo_gstate_get_target (cr->gstate)->device_transform,
-			   &group_surface->device_transform_inverse);
-    _cairo_path_fixed_transform (cr->path, &device_transform_matrix);
-
-done:
-    cairo_surface_destroy (group_surface);
+    group_pattern = cr->backend->pop_group (cr);
+    if (unlikely (group_pattern->status))
+	_cairo_set_error (cr, group_pattern->status);
 
     return group_pattern;
 }
@@ -755,36 +594,39 @@ cairo_set_operator (cairo_t *cr, cairo_operator_t op)
     if (unlikely (cr->status))
 	return;
 
-    status = _cairo_gstate_set_operator (cr->gstate, op);
+    status = cr->backend->set_operator (cr, op);
     if (unlikely (status))
 	_cairo_set_error (cr, status);
 }
 slim_hidden_def (cairo_set_operator);
 
 
-static cairo_bool_t
-_current_source_matches_solid (cairo_t *cr,
-			       double red,
-			       double green,
-			       double blue,
-			       double alpha)
+#if 0
+/**
+ * cairo_set_opacity:
+ * @cr: a #cairo_t
+ * @opacity: the level of opacity to use when compositing
+ *
+ * Sets the compositing opacity to be used for all drawing
+ * operations. The effect is to fade out the operations
+ * using the alpha value.
+ *
+ * The default opacity is 1.
+ **/
+void
+cairo_set_opacity (cairo_t *cr, double opacity)
 {
-    const cairo_pattern_t *current;
-    cairo_color_t color;
-
-    current = cr->gstate->source;
-    if (current->type != CAIRO_PATTERN_TYPE_SOLID)
-	return FALSE;
+    cairo_status_t status;
 
-    red   = _cairo_restrict_value (red,   0.0, 1.0);
-    green = _cairo_restrict_value (green, 0.0, 1.0);
-    blue  = _cairo_restrict_value (blue,  0.0, 1.0);
-    alpha = _cairo_restrict_value (alpha, 0.0, 1.0);
+    if (unlikely (cr->status))
+	return;
 
-    _cairo_color_init_rgba (&color, red, green, blue, alpha);
-    return _cairo_color_equal (&color,
-			       &((cairo_solid_pattern_t *) current)->color);
+    status = cr->backend->set_opacity (cr, opacity);
+    if (unlikely (status))
+	_cairo_set_error (cr, status);
 }
+#endif
+
 /**
  * cairo_set_source_rgb
  * @cr: a cairo context
@@ -806,20 +648,14 @@ _current_source_matches_solid (cairo_t *cr,
 void
 cairo_set_source_rgb (cairo_t *cr, double red, double green, double blue)
 {
-    cairo_pattern_t *pattern;
+    cairo_status_t status;
 
     if (unlikely (cr->status))
 	return;
 
-    if (_current_source_matches_solid (cr, red, green, blue, 1.))
-	return;
-
-    /* push the current pattern to the freed lists */
-    cairo_set_source (cr, (cairo_pattern_t *) &_cairo_pattern_black);
-
-    pattern = cairo_pattern_create_rgb (red, green, blue);
-    cairo_set_source (cr, pattern);
-    cairo_pattern_destroy (pattern);
+    status = cr->backend->set_source_rgba (cr, red, green, blue, 1.);
+    if (unlikely (status))
+	_cairo_set_error (cr, status);
 }
 slim_hidden_def (cairo_set_source_rgb);
 
@@ -847,20 +683,14 @@ cairo_set_source_rgba (cairo_t *cr,
 		       double red, double green, double blue,
 		       double alpha)
 {
-    cairo_pattern_t *pattern;
+    cairo_status_t status;
 
     if (unlikely (cr->status))
 	return;
 
-    if (_current_source_matches_solid (cr, red, green, blue, alpha))
-	return;
-
-    /* push the current pattern to the freed lists */
-    cairo_set_source (cr, (cairo_pattern_t *) &_cairo_pattern_black);
-
-    pattern = cairo_pattern_create_rgba (red, green, blue, alpha);
-    cairo_set_source (cr, pattern);
-    cairo_pattern_destroy (pattern);
+    status = cr->backend->set_source_rgba (cr, red, green, blue, alpha);
+    if (unlikely (status))
+	_cairo_set_error (cr, status);
 }
 
 /**
@@ -892,22 +722,19 @@ cairo_set_source_surface (cairo_t	  *cr,
 			  double	   x,
 			  double	   y)
 {
-    cairo_pattern_t *pattern;
-    cairo_matrix_t matrix;
+    cairo_status_t status;
 
     if (unlikely (cr->status))
 	return;
 
-    /* push the current pattern to the freed lists */
-    cairo_set_source (cr, (cairo_pattern_t *) &_cairo_pattern_black);
-
-    pattern = cairo_pattern_create_for_surface (surface);
-
-    cairo_matrix_init_translate (&matrix, -x, -y);
-    cairo_pattern_set_matrix (pattern, &matrix);
+    if (unlikely (surface == NULL)) {
+	_cairo_set_error (cr, CAIRO_STATUS_NULL_POINTER);
+	return;
+    }
 
-    cairo_set_source (cr, pattern);
-    cairo_pattern_destroy (pattern);
+    status = cr->backend->set_source_surface (cr, surface, x, y);
+    if (unlikely (status))
+	_cairo_set_error (cr, status);
 }
 slim_hidden_def (cairo_set_source_surface);
 
@@ -938,17 +765,17 @@ cairo_set_source (cairo_t *cr, cairo_pattern_t *source)
     if (unlikely (cr->status))
 	return;
 
-    if (source == NULL) {
+    if (unlikely (source == NULL)) {
 	_cairo_set_error (cr, CAIRO_STATUS_NULL_POINTER);
 	return;
     }
 
-    if (source->status) {
+    if (unlikely (source->status)) {
 	_cairo_set_error (cr, source->status);
 	return;
     }
 
-    status = _cairo_gstate_set_source (cr->gstate, source);
+    status = cr->backend->set_source (cr, source);
     if (unlikely (status))
 	_cairo_set_error (cr, status);
 }
@@ -970,7 +797,7 @@ cairo_get_source (cairo_t *cr)
     if (unlikely (cr->status))
 	return _cairo_pattern_create_in_error (cr->status);
 
-    return _cairo_gstate_get_source (cr->gstate);
+    return cr->backend->get_source (cr);
 }
 
 /**
@@ -997,10 +824,7 @@ cairo_set_tolerance (cairo_t *cr, double tolerance)
     if (unlikely (cr->status))
 	return;
 
-    if (tolerance < CAIRO_TOLERANCE_MINIMUM)
-	tolerance = CAIRO_TOLERANCE_MINIMUM;
-
-    status = _cairo_gstate_set_tolerance (cr->gstate, tolerance);
+    status = cr->backend->set_tolerance (cr, tolerance);
     if (unlikely (status))
 	_cairo_set_error (cr, status);
 }
@@ -1027,7 +851,7 @@ cairo_set_antialias (cairo_t *cr, cairo_antialias_t antialias)
     if (unlikely (cr->status))
 	return;
 
-    status = _cairo_gstate_set_antialias (cr->gstate, antialias);
+    status = cr->backend->set_antialias (cr, antialias);
     if (unlikely (status))
 	_cairo_set_error (cr, status);
 }
@@ -1053,7 +877,7 @@ cairo_set_fill_rule (cairo_t *cr, cairo_fill_rule_t fill_rule)
     if (unlikely (cr->status))
 	return;
 
-    status = _cairo_gstate_set_fill_rule (cr->gstate, fill_rule);
+    status = cr->backend->set_fill_rule (cr, fill_rule);
     if (unlikely (status))
 	_cairo_set_error (cr, status);
 }
@@ -1095,7 +919,7 @@ cairo_set_line_width (cairo_t *cr, double width)
     if (width < 0.)
 	width = 0.;
 
-    status = _cairo_gstate_set_line_width (cr->gstate, width);
+    status = cr->backend->set_line_width (cr, width);
     if (unlikely (status))
 	_cairo_set_error (cr, status);
 }
@@ -1125,7 +949,7 @@ cairo_set_line_cap (cairo_t *cr, cairo_line_cap_t line_cap)
     if (unlikely (cr->status))
 	return;
 
-    status = _cairo_gstate_set_line_cap (cr->gstate, line_cap);
+    status = cr->backend->set_line_cap (cr, line_cap);
     if (unlikely (status))
 	_cairo_set_error (cr, status);
 }
@@ -1155,7 +979,7 @@ cairo_set_line_join (cairo_t *cr, cairo_line_join_t line_join)
     if (unlikely (cr->status))
 	return;
 
-    status = _cairo_gstate_set_line_join (cr->gstate, line_join);
+    status = cr->backend->set_line_join (cr, line_join);
     if (unlikely (status))
 	_cairo_set_error (cr, status);
 }
@@ -1204,8 +1028,7 @@ cairo_set_dash (cairo_t	     *cr,
     if (unlikely (cr->status))
 	return;
 
-    status = _cairo_gstate_set_dash (cr->gstate,
-				     dashes, num_dashes, offset);
+    status = cr->backend->set_dash (cr, dashes, num_dashes, offset);
     if (unlikely (status))
 	_cairo_set_error (cr, status);
 }
@@ -1231,7 +1054,7 @@ cairo_get_dash_count (cairo_t *cr)
     if (unlikely (cr->status))
 	return 0;
 
-    _cairo_gstate_get_dash (cr->gstate, NULL, &num_dashes, NULL);
+    cr->backend->get_dash (cr, NULL, &num_dashes, NULL);
 
     return num_dashes;
 }
@@ -1256,7 +1079,7 @@ cairo_get_dash (cairo_t *cr,
     if (unlikely (cr->status))
 	return;
 
-    _cairo_gstate_get_dash (cr->gstate, dashes, NULL, offset);
+    cr->backend->get_dash (cr, dashes, NULL, offset);
 }
 
 /**
@@ -1295,7 +1118,7 @@ cairo_set_miter_limit (cairo_t *cr, double limit)
     if (unlikely (cr->status))
 	return;
 
-    status = _cairo_gstate_set_miter_limit (cr->gstate, limit);
+    status = cr->backend->set_miter_limit (cr, limit);
     if (unlikely (status))
 	_cairo_set_error (cr, status);
 }
@@ -1320,7 +1143,7 @@ cairo_translate (cairo_t *cr, double tx, double ty)
     if (unlikely (cr->status))
 	return;
 
-    status = _cairo_gstate_translate (cr->gstate, tx, ty);
+    status = cr->backend->translate (cr, tx, ty);
     if (unlikely (status))
 	_cairo_set_error (cr, status);
 }
@@ -1345,7 +1168,7 @@ cairo_scale (cairo_t *cr, double sx, double sy)
     if (unlikely (cr->status))
 	return;
 
-    status = _cairo_gstate_scale (cr->gstate, sx, sy);
+    status = cr->backend->scale (cr, sx, sy);
     if (unlikely (status))
 	_cairo_set_error (cr, status);
 }
@@ -1371,7 +1194,7 @@ cairo_rotate (cairo_t *cr, double angle)
     if (unlikely (cr->status))
 	return;
 
-    status = _cairo_gstate_rotate (cr->gstate, angle);
+    status = cr->backend->rotate (cr, angle);
     if (unlikely (status))
 	_cairo_set_error (cr, status);
 }
@@ -1394,7 +1217,7 @@ cairo_transform (cairo_t	      *cr,
     if (unlikely (cr->status))
 	return;
 
-    status = _cairo_gstate_transform (cr->gstate, matrix);
+    status = cr->backend->transform (cr, matrix);
     if (unlikely (status))
 	_cairo_set_error (cr, status);
 }
@@ -1417,7 +1240,7 @@ cairo_set_matrix (cairo_t	       *cr,
     if (unlikely (cr->status))
 	return;
 
-    status = _cairo_gstate_set_matrix (cr->gstate, matrix);
+    status = cr->backend->set_matrix (cr, matrix);
     if (unlikely (status))
 	_cairo_set_error (cr, status);
 }
@@ -1435,10 +1258,14 @@ slim_hidden_def (cairo_set_matrix);
 void
 cairo_identity_matrix (cairo_t *cr)
 {
+    cairo_status_t status;
+
     if (unlikely (cr->status))
 	return;
 
-    _cairo_gstate_identity_matrix (cr->gstate);
+    status = cr->backend->set_identity_matrix (cr);
+    if (unlikely (status))
+	_cairo_set_error (cr, status);
 }
 
 /**
@@ -1457,7 +1284,7 @@ cairo_user_to_device (cairo_t *cr, double *x, double *y)
     if (unlikely (cr->status))
 	return;
 
-    _cairo_gstate_user_to_device (cr->gstate, x, y);
+    cr->backend->user_to_device (cr, x, y);
 }
 slim_hidden_def (cairo_user_to_device);
 
@@ -1478,7 +1305,7 @@ cairo_user_to_device_distance (cairo_t *cr, double *dx, double *dy)
     if (unlikely (cr->status))
 	return;
 
-    _cairo_gstate_user_to_device_distance (cr->gstate, dx, dy);
+    cr->backend->user_to_device_distance (cr, dx, dy);
 }
 slim_hidden_def (cairo_user_to_device_distance);
 
@@ -1498,8 +1325,9 @@ cairo_device_to_user (cairo_t *cr, double *x, double *y)
     if (unlikely (cr->status))
 	return;
 
-    _cairo_gstate_device_to_user (cr->gstate, x, y);
+    cr->backend->device_to_user (cr, x, y);
 }
+slim_hidden_def (cairo_device_to_user);
 
 /**
  * cairo_device_to_user_distance:
@@ -1518,7 +1346,7 @@ cairo_device_to_user_distance (cairo_t *cr, double *dx, double *dy)
     if (unlikely (cr->status))
 	return;
 
-    _cairo_gstate_device_to_user_distance (cr->gstate, dx, dy);
+    cr->backend->device_to_user_distance (cr, dx, dy);
 }
 
 /**
@@ -1531,41 +1359,16 @@ cairo_device_to_user_distance (cairo_t *cr, double *dx, double *dy)
 void
 cairo_new_path (cairo_t *cr)
 {
-    if (unlikely (cr->status))
-	return;
-
-    _cairo_path_fixed_fini (cr->path);
-    _cairo_path_fixed_init (cr->path);
-}
-slim_hidden_def(cairo_new_path);
-
-/**
- * cairo_move_to:
- * @cr: a cairo context
- * @x: the X coordinate of the new position
- * @y: the Y coordinate of the new position
- *
- * Begin a new sub-path. After this call the current point will be (@x,
- * @y).
- **/
-void
-cairo_move_to (cairo_t *cr, double x, double y)
-{
     cairo_status_t status;
-    cairo_fixed_t x_fixed, y_fixed;
 
     if (unlikely (cr->status))
 	return;
 
-    _cairo_gstate_user_to_backend (cr->gstate, &x, &y);
-    x_fixed = _cairo_fixed_from_double (x);
-    y_fixed = _cairo_fixed_from_double (y);
-
-    status = _cairo_path_fixed_move_to (cr->path, x_fixed, y_fixed);
+    status = cr->backend->new_path (cr);
     if (unlikely (status))
 	_cairo_set_error (cr, status);
 }
-slim_hidden_def(cairo_move_to);
+slim_hidden_def(cairo_new_path);
 
 /**
  * cairo_new_sub_path:
@@ -1588,13 +1391,41 @@ slim_hidden_def(cairo_move_to);
 void
 cairo_new_sub_path (cairo_t *cr)
 {
+    cairo_status_t status;
+
     if (unlikely (cr->status))
 	return;
 
-    _cairo_path_fixed_new_sub_path (cr->path);
+    status = cr->backend->new_sub_path (cr);
+    if (unlikely (status))
+	_cairo_set_error (cr, status);
 }
 
 /**
+ * cairo_move_to:
+ * @cr: a cairo context
+ * @x: the X coordinate of the new position
+ * @y: the Y coordinate of the new position
+ *
+ * Begin a new sub-path. After this call the current point will be (@x,
+ * @y).
+ **/
+void
+cairo_move_to (cairo_t *cr, double x, double y)
+{
+    cairo_status_t status;
+
+    if (unlikely (cr->status))
+	return;
+
+    status = cr->backend->move_to (cr, x, y);
+    if (unlikely (status))
+	_cairo_set_error (cr, status);
+}
+slim_hidden_def(cairo_move_to);
+
+
+/**
  * cairo_line_to:
  * @cr: a cairo context
  * @x: the X coordinate of the end of the new line
@@ -1611,16 +1442,11 @@ void
 cairo_line_to (cairo_t *cr, double x, double y)
 {
     cairo_status_t status;
-    cairo_fixed_t x_fixed, y_fixed;
 
     if (unlikely (cr->status))
 	return;
 
-    _cairo_gstate_user_to_backend (cr->gstate, &x, &y);
-    x_fixed = _cairo_fixed_from_double (x);
-    y_fixed = _cairo_fixed_from_double (y);
-
-    status = _cairo_path_fixed_line_to (cr->path, x_fixed, y_fixed);
+    status = cr->backend->line_to (cr, x, y);
     if (unlikely (status))
 	_cairo_set_error (cr, status);
 }
@@ -1652,30 +1478,14 @@ cairo_curve_to (cairo_t *cr,
 		double x3, double y3)
 {
     cairo_status_t status;
-    cairo_fixed_t x1_fixed, y1_fixed;
-    cairo_fixed_t x2_fixed, y2_fixed;
-    cairo_fixed_t x3_fixed, y3_fixed;
 
     if (unlikely (cr->status))
 	return;
 
-    _cairo_gstate_user_to_backend (cr->gstate, &x1, &y1);
-    _cairo_gstate_user_to_backend (cr->gstate, &x2, &y2);
-    _cairo_gstate_user_to_backend (cr->gstate, &x3, &y3);
-
-    x1_fixed = _cairo_fixed_from_double (x1);
-    y1_fixed = _cairo_fixed_from_double (y1);
-
-    x2_fixed = _cairo_fixed_from_double (x2);
-    y2_fixed = _cairo_fixed_from_double (y2);
-
-    x3_fixed = _cairo_fixed_from_double (x3);
-    y3_fixed = _cairo_fixed_from_double (y3);
-
-    status = _cairo_path_fixed_curve_to (cr->path,
-					 x1_fixed, y1_fixed,
-					 x2_fixed, y2_fixed,
-					 x3_fixed, y3_fixed);
+    status = cr->backend->curve_to (cr,
+				    x1, y1,
+				    x2, y2,
+				    x3, y3);
     if (unlikely (status))
 	_cairo_set_error (cr, status);
 }
@@ -1735,15 +1545,10 @@ cairo_arc (cairo_t *cr,
 	   double radius,
 	   double angle1, double angle2)
 {
-    if (unlikely (cr->status))
-	return;
+    cairo_status_t status;
 
-    /* Do nothing, successfully, if radius is <= 0 */
-    if (radius <= 0.0) {
-	cairo_line_to (cr, xc, yc); /* might become a move_to */
-	cairo_line_to (cr, xc, yc);
+    if (unlikely (cr->status))
 	return;
-    }
 
     if (angle2 < angle1) {
 	/* increase angle2 by multiples of full circle until it
@@ -1754,12 +1559,9 @@ cairo_arc (cairo_t *cr,
 	angle2 += angle1;
     }
 
-    cairo_line_to (cr,
-		   xc + radius * cos (angle1),
-		   yc + radius * sin (angle1));
-
-    _cairo_arc_path (cr, xc, yc, radius,
-		     angle1, angle2);
+    status = cr->backend->arc (cr, xc, yc, radius, angle1, angle2, TRUE);
+    if (unlikely (status))
+	_cairo_set_error (cr, status);
 }
 
 /**
@@ -1786,15 +1588,10 @@ cairo_arc_negative (cairo_t *cr,
 		    double radius,
 		    double angle1, double angle2)
 {
-    if (unlikely (cr->status))
-	return;
+    cairo_status_t status;
 
-    /* Do nothing, successfully, if radius is <= 0 */
-    if (radius <= 0.0) {
-	cairo_line_to (cr, xc, yc); /* might become a move_to */
-	cairo_line_to (cr, xc, yc);
+    if (unlikely (cr->status))
 	return;
-    }
 
     if (angle2 > angle1) {
 	/* decrease angle2 by multiples of full circle until it
@@ -1805,12 +1602,9 @@ cairo_arc_negative (cairo_t *cr,
 	angle2 += angle1;
     }
 
-    cairo_line_to (cr,
-		   xc + radius * cos (angle1),
-		   yc + radius * sin (angle1));
-
-     _cairo_arc_path_negative (cr, xc, yc, radius,
-			       angle1, angle2);
+    status = cr->backend->arc (cr, xc, yc, radius, angle1, angle2, FALSE);
+    if (unlikely (status))
+	_cairo_set_error (cr, status);
 }
 
 /* XXX: NYI
@@ -1825,10 +1619,23 @@ cairo_arc_to (cairo_t *cr,
     if (unlikely (cr->status))
 	return;
 
-    status = _cairo_gstate_arc_to (cr->gstate,
-				   x1, y1,
-				   x2, y2,
-				   radius);
+    status = cr->backend->arc_to (cr, x1, y1, x2, y2, radius);
+    if (unlikely (status))
+	_cairo_set_error (cr, status);
+}
+
+void
+cairo_rel_arc_to (cairo_t *cr,
+	      double dx1, double dy1,
+	      double dx2, double dy2,
+	      double radius)
+{
+    cairo_status_t status;
+
+    if (unlikely (cr->status))
+	return;
+
+    status = cr->backend->rel_arc_to (cr, dx1, dy1, dx2, dy2, radius);
     if (unlikely (status))
 	_cairo_set_error (cr, status);
 }
@@ -1853,18 +1660,12 @@ cairo_arc_to (cairo_t *cr,
 void
 cairo_rel_move_to (cairo_t *cr, double dx, double dy)
 {
-    cairo_fixed_t dx_fixed, dy_fixed;
     cairo_status_t status;
 
     if (unlikely (cr->status))
 	return;
 
-    _cairo_gstate_user_to_device_distance (cr->gstate, &dx, &dy);
-
-    dx_fixed = _cairo_fixed_from_double (dx);
-    dy_fixed = _cairo_fixed_from_double (dy);
-
-    status = _cairo_path_fixed_rel_move_to (cr->path, dx_fixed, dy_fixed);
+    status = cr->backend->rel_move_to (cr, dx, dy);
     if (unlikely (status))
 	_cairo_set_error (cr, status);
 }
@@ -1890,18 +1691,12 @@ cairo_rel_move_to (cairo_t *cr, double dx, double dy)
 void
 cairo_rel_line_to (cairo_t *cr, double dx, double dy)
 {
-    cairo_fixed_t dx_fixed, dy_fixed;
     cairo_status_t status;
 
     if (unlikely (cr->status))
 	return;
 
-    _cairo_gstate_user_to_device_distance (cr->gstate, &dx, &dy);
-
-    dx_fixed = _cairo_fixed_from_double (dx);
-    dy_fixed = _cairo_fixed_from_double (dy);
-
-    status = _cairo_path_fixed_rel_line_to (cr->path, dx_fixed, dy_fixed);
+    status = cr->backend->rel_line_to (cr, dx, dy);
     if (unlikely (status))
 	_cairo_set_error (cr, status);
 }
@@ -1938,31 +1733,15 @@ cairo_rel_curve_to (cairo_t *cr,
 		    double dx2, double dy2,
 		    double dx3, double dy3)
 {
-    cairo_fixed_t dx1_fixed, dy1_fixed;
-    cairo_fixed_t dx2_fixed, dy2_fixed;
-    cairo_fixed_t dx3_fixed, dy3_fixed;
     cairo_status_t status;
 
     if (unlikely (cr->status))
 	return;
 
-    _cairo_gstate_user_to_device_distance (cr->gstate, &dx1, &dy1);
-    _cairo_gstate_user_to_device_distance (cr->gstate, &dx2, &dy2);
-    _cairo_gstate_user_to_device_distance (cr->gstate, &dx3, &dy3);
-
-    dx1_fixed = _cairo_fixed_from_double (dx1);
-    dy1_fixed = _cairo_fixed_from_double (dy1);
-
-    dx2_fixed = _cairo_fixed_from_double (dx2);
-    dy2_fixed = _cairo_fixed_from_double (dy2);
-
-    dx3_fixed = _cairo_fixed_from_double (dx3);
-    dy3_fixed = _cairo_fixed_from_double (dy3);
-
-    status = _cairo_path_fixed_rel_curve_to (cr->path,
-					     dx1_fixed, dy1_fixed,
-					     dx2_fixed, dy2_fixed,
-					     dx3_fixed, dy3_fixed);
+    status = cr->backend->rel_curve_to (cr,
+					dx1, dy1,
+					dx2, dy2,
+					dx3, dy3);
     if (unlikely (status))
 	_cairo_set_error (cr, status);
 }
@@ -1992,14 +1771,14 @@ cairo_rectangle (cairo_t *cr,
 		 double x, double y,
 		 double width, double height)
 {
+    cairo_status_t status;
+
     if (unlikely (cr->status))
 	return;
 
-    cairo_move_to (cr, x, y);
-    cairo_rel_line_to (cr, width, 0);
-    cairo_rel_line_to (cr, 0, height);
-    cairo_rel_line_to (cr, -width, 0);
-    cairo_close_path (cr);
+    status = cr->backend->rectangle (cr, x, y, width, height);
+    if (unlikely (status))
+	_cairo_set_error (cr, status);
 }
 
 #if 0
@@ -2054,7 +1833,7 @@ cairo_close_path (cairo_t *cr)
     if (unlikely (cr->status))
 	return;
 
-    status = _cairo_path_fixed_close_path (cr->path);
+    status = cr->backend->close_path (cr);
     if (unlikely (status))
 	_cairo_set_error (cr, status);
 }
@@ -2108,9 +1887,7 @@ cairo_path_extents (cairo_t *cr,
 	return;
     }
 
-    _cairo_gstate_path_extents (cr->gstate,
-				cr->path,
-				x1, y1, x2, y2);
+    cr->backend->path_extents (cr, x1, y1, x2, y2);
 }
 
 /**
@@ -2128,7 +1905,7 @@ cairo_paint (cairo_t *cr)
     if (unlikely (cr->status))
 	return;
 
-    status = _cairo_gstate_paint (cr->gstate);
+    status = cr->backend->paint (cr);
     if (unlikely (status))
 	_cairo_set_error (cr, status);
 }
@@ -2149,30 +1926,13 @@ cairo_paint_with_alpha (cairo_t *cr,
 			double   alpha)
 {
     cairo_status_t status;
-    cairo_color_t color;
-    cairo_solid_pattern_t pattern;
 
     if (unlikely (cr->status))
 	return;
 
-    if (CAIRO_ALPHA_IS_OPAQUE (alpha)) {
-	cairo_paint (cr);
-	return;
-    }
-
-    if (CAIRO_ALPHA_IS_ZERO (alpha) &&
-        _cairo_operator_bounded_by_mask (cr->gstate->op)) {
-	return;
-    }
-
-    _cairo_color_init_rgba (&color, 0., 0., 0., alpha);
-    _cairo_pattern_init_solid (&pattern, &color);
-
-    status = _cairo_gstate_mask (cr->gstate, &pattern.base);
+    status = cr->backend->paint_with_alpha (cr, alpha);
     if (unlikely (status))
 	_cairo_set_error (cr, status);
-
-    _cairo_pattern_fini (&pattern.base);
 }
 
 /**
@@ -2194,17 +1954,17 @@ cairo_mask (cairo_t         *cr,
     if (unlikely (cr->status))
 	return;
 
-    if (pattern == NULL) {
+    if (unlikely (pattern == NULL)) {
 	_cairo_set_error (cr, CAIRO_STATUS_NULL_POINTER);
 	return;
     }
 
-    if (pattern->status) {
+    if (unlikely (pattern->status)) {
 	_cairo_set_error (cr, pattern->status);
 	return;
     }
 
-    status = _cairo_gstate_mask (cr->gstate, pattern);
+    status = cr->backend->mask (cr, pattern);
     if (unlikely (status))
 	_cairo_set_error (cr, status);
 }
@@ -2279,9 +2039,14 @@ cairo_mask_surface (cairo_t         *cr,
 void
 cairo_stroke (cairo_t *cr)
 {
-    cairo_stroke_preserve (cr);
+    cairo_status_t status;
 
-    cairo_new_path (cr);
+    if (unlikely (cr->status))
+	return;
+
+    status = cr->backend->stroke (cr);
+    if (unlikely (status))
+	_cairo_set_error (cr, status);
 }
 slim_hidden_def(cairo_stroke);
 
@@ -2306,7 +2071,7 @@ cairo_stroke_preserve (cairo_t *cr)
     if (unlikely (cr->status))
 	return;
 
-    status = _cairo_gstate_stroke (cr->gstate, cr->path);
+    status = cr->backend->stroke_preserve (cr);
     if (unlikely (status))
 	_cairo_set_error (cr, status);
 }
@@ -2325,9 +2090,14 @@ slim_hidden_def(cairo_stroke_preserve);
 void
 cairo_fill (cairo_t *cr)
 {
-    cairo_fill_preserve (cr);
+    cairo_status_t status;
+
+    if (unlikely (cr->status))
+	return;
 
-    cairo_new_path (cr);
+    status = cr->backend->fill (cr);
+    if (unlikely (status))
+	_cairo_set_error (cr, status);
 }
 
 /**
@@ -2349,7 +2119,7 @@ cairo_fill_preserve (cairo_t *cr)
     if (unlikely (cr->status))
 	return;
 
-    status = _cairo_gstate_fill (cr->gstate, cr->path);
+    status = cr->backend->fill_preserve (cr);
     if (unlikely (status))
 	_cairo_set_error (cr, status);
 }
@@ -2375,7 +2145,7 @@ cairo_copy_page (cairo_t *cr)
     if (unlikely (cr->status))
 	return;
 
-    status = _cairo_gstate_copy_page (cr->gstate);
+    status = cr->backend->copy_page (cr);
     if (unlikely (status))
 	_cairo_set_error (cr, status);
 }
@@ -2398,7 +2168,7 @@ cairo_show_page (cairo_t *cr)
     if (unlikely (cr->status))
 	return;
 
-    status = _cairo_gstate_show_page (cr->gstate);
+    status = cr->backend->show_page (cr);
     if (unlikely (status))
 	_cairo_set_error (cr, status);
 }
@@ -2430,9 +2200,7 @@ cairo_in_stroke (cairo_t *cr, double x, double y)
     if (unlikely (cr->status))
 	return FALSE;
 
-    status = _cairo_gstate_in_stroke (cr->gstate,
-				      cr->path,
-				      x, y, &inside);
+    status = cr->backend->in_stroke (cr, x, y, &inside);
     if (unlikely (status))
 	_cairo_set_error (cr, status);
 
@@ -2458,10 +2226,17 @@ cairo_in_stroke (cairo_t *cr, double x, double y)
 cairo_bool_t
 cairo_in_fill (cairo_t *cr, double x, double y)
 {
+    cairo_status_t status;
+    cairo_bool_t inside = FALSE;
+
     if (unlikely (cr->status))
 	return FALSE;
 
-    return _cairo_gstate_in_fill (cr->gstate, cr->path, x, y);
+    status = cr->backend->in_fill (cr, x, y, &inside);
+    if (unlikely (status))
+	_cairo_set_error (cr, status);
+
+    return inside;
 }
 
 /**
@@ -2511,9 +2286,7 @@ cairo_stroke_extents (cairo_t *cr,
 	return;
     }
 
-    status = _cairo_gstate_stroke_extents (cr->gstate,
-					   cr->path,
-					   x1, y1, x2, y2);
+    status = cr->backend->stroke_extents (cr, x1, y1, x2, y2);
     if (unlikely (status))
 	_cairo_set_error (cr, status);
 }
@@ -2562,9 +2335,7 @@ cairo_fill_extents (cairo_t *cr,
 	return;
     }
 
-    status = _cairo_gstate_fill_extents (cr->gstate,
-					 cr->path,
-					 x1, y1, x2, y2);
+    status = cr->backend->fill_extents (cr, x1, y1, x2, y2);
     if (unlikely (status))
 	_cairo_set_error (cr, status);
 }
@@ -2594,9 +2365,14 @@ cairo_fill_extents (cairo_t *cr,
 void
 cairo_clip (cairo_t *cr)
 {
-    cairo_clip_preserve (cr);
+    cairo_status_t status;
 
-    cairo_new_path (cr);
+    if (unlikely (cr->status))
+	return;
+
+    status = cr->backend->clip (cr);
+    if (unlikely (status))
+	_cairo_set_error (cr, status);
 }
 
 /**
@@ -2629,7 +2405,7 @@ cairo_clip_preserve (cairo_t *cr)
     if (unlikely (cr->status))
 	return;
 
-    status = _cairo_gstate_clip (cr->gstate, cr->path);
+    status = cr->backend->clip_preserve (cr);
     if (unlikely (status))
 	_cairo_set_error (cr, status);
 }
@@ -2659,7 +2435,7 @@ cairo_reset_clip (cairo_t *cr)
     if (unlikely (cr->status))
 	return;
 
-    status = _cairo_gstate_reset_clip (cr->gstate);
+    status = cr->backend->reset_clip (cr);
     if (unlikely (status))
 	_cairo_set_error (cr, status);
 }
@@ -2682,25 +2458,23 @@ cairo_clip_extents (cairo_t *cr,
 		    double *x1, double *y1,
 		    double *x2, double *y2)
 {
-    if (unlikely (cr->status)) {
-	if (x1)
-	    *x1 = 0.0;
-	if (y1)
-	    *y1 = 0.0;
-	if (x2)
-	    *x2 = 0.0;
-	if (y2)
-	    *y2 = 0.0;
+    cairo_status_t status;
+
+    if (x1)
+	*x1 = 0.0;
+    if (y1)
+	*y1 = 0.0;
+    if (x2)
+	*x2 = 0.0;
+    if (y2)
+	*y2 = 0.0;
 
+    if (unlikely (cr->status))
 	return;
-    }
 
-    if (! _cairo_gstate_clip_extents (cr->gstate, x1, y1, x2, y2)) {
-	*x1 = -INFINITY;
-	*y1 = -INFINITY;
-	*x2 = +INFINITY;
-	*y2 = +INFINITY;
-    }
+    status = cr->backend->clip_extents (cr, x1, y1, x2, y2);
+    if (unlikely (status))
+	_cairo_set_error (cr, status);
 }
 
 /**
@@ -2723,10 +2497,17 @@ cairo_clip_extents (cairo_t *cr,
 cairo_bool_t
 cairo_in_clip (cairo_t *cr, double x, double y)
 {
+    cairo_status_t status;
+    cairo_bool_t inside = FALSE;
+
     if (unlikely (cr->status))
 	return FALSE;
 
-    return _cairo_gstate_in_clip (cr->gstate, x, y);
+    status = cr->backend->in_clip (cr, x, y, &inside);
+    if (unlikely (status))
+	_cairo_set_error (cr, status);
+
+    return inside;
 }
 
 /**
@@ -2752,7 +2533,7 @@ cairo_copy_clip_rectangle_list (cairo_t *cr)
     if (unlikely (cr->status))
         return _cairo_rectangle_list_create_in_error (cr->status);
 
-    return _cairo_gstate_copy_clip_rectangle_list (cr->gstate);
+    return cr->backend->clip_copy_rectangle_list (cr);
 }
 
 /**
@@ -2812,12 +2593,21 @@ cairo_select_font_face (cairo_t              *cr,
 			cairo_font_slant_t    slant,
 			cairo_font_weight_t   weight)
 {
+    cairo_font_face_t *font_face;
     cairo_status_t status;
 
     if (unlikely (cr->status))
 	return;
 
-    status = _cairo_gstate_select_font_face (cr->gstate, family, slant, weight);
+    font_face = cairo_toy_font_face_create (family, slant, weight);
+    if (unlikely (font_face->status)) {
+	_cairo_set_error (cr, font_face->status);
+	return;
+    }
+
+    status = cr->backend->set_font_face (cr, font_face);
+    cairo_font_face_destroy (font_face);
+
     if (unlikely (status))
 	_cairo_set_error (cr, status);
 }
@@ -2845,7 +2635,7 @@ cairo_font_extents (cairo_t              *cr,
     if (unlikely (cr->status))
 	return;
 
-    status = _cairo_gstate_get_font_extents (cr->gstate, extents);
+    status = cr->backend->font_extents (cr, extents);
     if (unlikely (status))
 	_cairo_set_error (cr, status);
 }
@@ -2868,7 +2658,7 @@ cairo_set_font_face (cairo_t           *cr,
     if (unlikely (cr->status))
 	return;
 
-    status = _cairo_gstate_set_font_face (cr->gstate, font_face);
+    status = cr->backend->set_font_face (cr, font_face);
     if (unlikely (status))
 	_cairo_set_error (cr, status);
 }
@@ -2894,19 +2684,10 @@ cairo_set_font_face (cairo_t           *cr,
 cairo_font_face_t *
 cairo_get_font_face (cairo_t *cr)
 {
-    cairo_status_t status;
-    cairo_font_face_t *font_face;
-
     if (unlikely (cr->status))
 	return (cairo_font_face_t*) &_cairo_font_face_nil;
 
-    status = _cairo_gstate_get_font_face (cr->gstate, &font_face);
-    if (unlikely (status)) {
-	_cairo_set_error (cr, status);
-	return (cairo_font_face_t*) &_cairo_font_face_nil;
-    }
-
-    return font_face;
+    return cr->backend->get_font_face (cr);
 }
 
 /**
@@ -2927,11 +2708,14 @@ cairo_get_font_face (cairo_t *cr)
 void
 cairo_set_font_size (cairo_t *cr, double size)
 {
-    cairo_matrix_t scale;
+    cairo_status_t status;
 
-    cairo_matrix_init_scale (&scale, size, size);
+    if (unlikely (cr->status))
+	return;
 
-    cairo_set_font_matrix (cr, &scale);
+    status = cr->backend->set_font_size (cr, size);
+    if (unlikely (status))
+	_cairo_set_error (cr, status);
 }
 slim_hidden_def (cairo_set_font_size);
 
@@ -2957,7 +2741,7 @@ cairo_set_font_matrix (cairo_t		    *cr,
     if (unlikely (cr->status))
 	return;
 
-    status = _cairo_gstate_set_font_matrix (cr->gstate, matrix);
+    status = cr->backend->set_font_matrix (cr, matrix);
     if (unlikely (status))
 	_cairo_set_error (cr, status);
 }
@@ -2979,7 +2763,7 @@ cairo_get_font_matrix (cairo_t *cr, cairo_matrix_t *matrix)
 	return;
     }
 
-    _cairo_gstate_get_font_matrix (cr->gstate, matrix);
+    cr->backend->get_font_matrix (cr, matrix);
 }
 
 /**
@@ -3008,7 +2792,9 @@ cairo_set_font_options (cairo_t                    *cr,
 	return;
     }
 
-    _cairo_gstate_set_font_options (cr->gstate, options);
+    status = cr->backend->set_font_options (cr, options);
+    if (unlikely (status))
+	_cairo_set_error (cr, status);
 }
 slim_hidden_def (cairo_set_font_options);
 
@@ -3036,7 +2822,7 @@ cairo_get_font_options (cairo_t              *cr,
 	return;
     }
 
-    _cairo_gstate_get_font_options (cr->gstate, options);
+    cr->backend->get_font_options (cr, options);
 }
 
 /**
@@ -3057,42 +2843,24 @@ cairo_set_scaled_font (cairo_t                   *cr,
 		       const cairo_scaled_font_t *scaled_font)
 {
     cairo_status_t status;
-    cairo_bool_t was_previous;
 
     if (unlikely (cr->status))
 	return;
 
-    if (scaled_font == NULL) {
-	status = _cairo_error (CAIRO_STATUS_NULL_POINTER);
-	goto BAIL;
+    if ((scaled_font == NULL)) {
+	_cairo_set_error (cr, _cairo_error (CAIRO_STATUS_NULL_POINTER));
+	return;
     }
 
     status = scaled_font->status;
-    if (unlikely (status))
-        goto BAIL;
-
-    if (scaled_font == cr->gstate->scaled_font)
+    if (unlikely (status)) {
+	_cairo_set_error (cr, status);
 	return;
+    }
 
-    was_previous = scaled_font == cr->gstate->previous_scaled_font;
-
-    status = _cairo_gstate_set_font_face (cr->gstate, scaled_font->font_face);
-    if (unlikely (status))
-        goto BAIL;
-
-    status = _cairo_gstate_set_font_matrix (cr->gstate, &scaled_font->font_matrix);
+    status = cr->backend->set_scaled_font (cr, (cairo_scaled_font_t *) scaled_font);
     if (unlikely (status))
-        goto BAIL;
-
-    _cairo_gstate_set_font_options (cr->gstate, &scaled_font->options);
-
-    if (was_previous)
-	cr->gstate->scaled_font = cairo_scaled_font_reference ((cairo_scaled_font_t *) scaled_font);
-
-    return;
-
-BAIL:
-    _cairo_set_error (cr, status);
+	_cairo_set_error (cr, status);
 }
 
 /**
@@ -3118,20 +2886,12 @@ BAIL:
 cairo_scaled_font_t *
 cairo_get_scaled_font (cairo_t *cr)
 {
-    cairo_status_t status;
-    cairo_scaled_font_t *scaled_font;
-
     if (unlikely (cr->status))
 	return _cairo_scaled_font_create_in_error (cr->status);
 
-    status = _cairo_gstate_get_scaled_font (cr->gstate, &scaled_font);
-    if (unlikely (status)) {
-	_cairo_set_error (cr, status);
-	return _cairo_scaled_font_create_in_error (status);
-    }
-
-    return scaled_font;
+    return cr->backend->get_scaled_font (cr);
 }
+slim_hidden_def (cairo_get_scaled_font);
 
 /**
  * cairo_text_extents:
@@ -3159,8 +2919,9 @@ cairo_text_extents (cairo_t              *cr,
 		    cairo_text_extents_t *extents)
 {
     cairo_status_t status;
+    cairo_scaled_font_t *scaled_font;
     cairo_glyph_t *glyphs = NULL;
-    int num_glyphs;
+    int num_glyphs = 0;
     double x, y;
 
     extents->x_bearing = 0.0;
@@ -3176,19 +2937,24 @@ cairo_text_extents (cairo_t              *cr,
     if (utf8 == NULL)
 	return;
 
-    cairo_get_current_point (cr, &x, &y);
+    scaled_font = cairo_get_scaled_font (cr);
+    if (unlikely (scaled_font->status)) {
+	_cairo_set_error (cr, scaled_font->status);
+	return;
+    }
 
-    status = _cairo_gstate_text_to_glyphs (cr->gstate,
-					   x, y,
-					   utf8, strlen (utf8),
-					   &glyphs, &num_glyphs,
-					   NULL, NULL,
-					   NULL);
-
-    if (status == CAIRO_STATUS_SUCCESS)
-	status = _cairo_gstate_glyph_extents (cr->gstate,
-		                              glyphs, num_glyphs,
-					      extents);
+    cairo_get_current_point (cr, &x, &y);
+    status = cairo_scaled_font_text_to_glyphs (scaled_font,
+					       x, y,
+					       utf8, -1,
+					       &glyphs, &num_glyphs,
+					       NULL, NULL, NULL);
+
+    if (likely (status == CAIRO_STATUS_SUCCESS)) {
+	status = cr->backend->glyph_extents (cr,
+					     glyphs, num_glyphs,
+					     extents);
+    }
     cairo_glyph_free (glyphs);
 
     if (unlikely (status))
@@ -3234,18 +3000,17 @@ cairo_glyph_extents (cairo_t                *cr,
     if (num_glyphs == 0)
 	return;
 
-    if (num_glyphs < 0) {
+    if (unlikely (num_glyphs < 0)) {
 	_cairo_set_error (cr, CAIRO_STATUS_NEGATIVE_COUNT);
 	return;
     }
 
-    if (glyphs == NULL) {
+    if (unlikely (glyphs == NULL)) {
 	_cairo_set_error (cr, CAIRO_STATUS_NULL_POINTER);
 	return;
     }
 
-    status = _cairo_gstate_glyph_extents (cr->gstate, glyphs, num_glyphs,
-					  extents);
+    status = cr->backend->glyph_extents (cr, glyphs, num_glyphs, extents);
     if (unlikely (status))
 	_cairo_set_error (cr, status);
 }
@@ -3290,6 +3055,8 @@ cairo_show_text (cairo_t *cr, const char *utf8)
     cairo_bool_t has_show_text_glyphs;
     cairo_glyph_t stack_glyphs[CAIRO_STACK_ARRAY_LENGTH (cairo_glyph_t)];
     cairo_text_cluster_t stack_clusters[CAIRO_STACK_ARRAY_LENGTH (cairo_text_cluster_t)];
+    cairo_scaled_font_t *scaled_font;
+    cairo_glyph_text_info_t info;
 
     if (unlikely (cr->status))
 	return;
@@ -3297,7 +3064,11 @@ cairo_show_text (cairo_t *cr, const char *utf8)
     if (utf8 == NULL)
 	return;
 
-    cairo_get_current_point (cr, &x, &y);
+    scaled_font = cairo_get_scaled_font (cr);
+    if (unlikely (scaled_font->status)) {
+	_cairo_set_error (cr, scaled_font->status);
+	return;
+    }
 
     utf8_len = strlen (utf8);
 
@@ -3315,36 +3086,37 @@ cairo_show_text (cairo_t *cr, const char *utf8)
 	num_clusters = 0;
     }
 
-    status = _cairo_gstate_text_to_glyphs (cr->gstate,
-					   x, y,
-					   utf8, utf8_len,
-					   &glyphs, &num_glyphs,
-					   has_show_text_glyphs ? &clusters : NULL, &num_clusters,
-					   &cluster_flags);
+    cairo_get_current_point (cr, &x, &y);
+    status = cairo_scaled_font_text_to_glyphs (scaled_font,
+					       x, y,
+					       utf8, utf8_len,
+					       &glyphs, &num_glyphs,
+					       has_show_text_glyphs ? &clusters : NULL, &num_clusters,
+					       &cluster_flags);
     if (unlikely (status))
 	goto BAIL;
 
     if (num_glyphs == 0)
 	return;
 
-    status = _cairo_gstate_show_text_glyphs (cr->gstate,
-					     utf8, utf8_len,
-					     glyphs, num_glyphs,
-					     clusters, num_clusters,
-					     cluster_flags);
+    info.utf8 = utf8;
+    info.utf8_len = utf8_len;
+    info.clusters = clusters;
+    info.num_clusters = num_clusters;
+    info.cluster_flags = cluster_flags;
+
+    status = cr->backend->glyphs (cr, glyphs, num_glyphs, &info);
     if (unlikely (status))
 	goto BAIL;
 
     last_glyph = &glyphs[num_glyphs - 1];
-    status = _cairo_gstate_glyph_extents (cr->gstate,
-					  last_glyph, 1,
-					  &extents);
+    status = cr->backend->glyph_extents (cr, last_glyph, 1, &extents);
     if (unlikely (status))
 	goto BAIL;
 
     x = last_glyph->x + extents.x_advance;
     y = last_glyph->y + extents.y_advance;
-    cairo_move_to (cr, x, y);
+    cr->backend->move_to (cr, x, y);
 
  BAIL:
     if (glyphs != stack_glyphs)
@@ -3387,11 +3159,7 @@ cairo_show_glyphs (cairo_t *cr, const cairo_glyph_t *glyphs, int num_glyphs)
 	return;
     }
 
-    status = _cairo_gstate_show_text_glyphs (cr->gstate,
-					     NULL, 0,
-					     glyphs, num_glyphs,
-					     NULL, 0,
-					     FALSE);
+    status = cr->backend->glyphs (cr, glyphs, num_glyphs, NULL);
     if (unlikely (status))
 	_cairo_set_error (cr, status);
 }
@@ -3469,32 +3237,38 @@ cairo_show_text_glyphs (cairo_t			   *cr,
 	return;
     }
 
-    /* Make sure clusters cover the entire glyphs and utf8 arrays,
-     * and that cluster boundaries are UTF-8 boundaries. */
-    status = _cairo_validate_text_clusters (utf8, utf8_len,
-					    glyphs, num_glyphs,
-					    clusters, num_clusters, cluster_flags);
-    if (status == CAIRO_STATUS_INVALID_CLUSTERS) {
-	/* Either got invalid UTF-8 text, or cluster mapping is bad.
-	 * Differentiate those. */
-
-	cairo_status_t status2;
-
-	status2 = _cairo_utf8_to_ucs4 (utf8, utf8_len, NULL, NULL);
-	if (status2)
-	    status = status2;
-
-	_cairo_set_error (cr, status);
-	return;
-    }
-
     if (num_glyphs == 0 && utf8_len == 0)
 	return;
 
-    status = _cairo_gstate_show_text_glyphs (cr->gstate,
-					     utf8, utf8_len,
-					     glyphs, num_glyphs,
-					     clusters, num_clusters, cluster_flags);
+    if (utf8) {
+	/* Make sure clusters cover the entire glyphs and utf8 arrays,
+	 * and that cluster boundaries are UTF-8 boundaries. */
+	status = _cairo_validate_text_clusters (utf8, utf8_len,
+						glyphs, num_glyphs,
+						clusters, num_clusters, cluster_flags);
+	if (status == CAIRO_STATUS_INVALID_CLUSTERS) {
+	    /* Either got invalid UTF-8 text, or cluster mapping is bad.
+	     * Differentiate those. */
+
+	    cairo_status_t status2;
+
+	    status2 = _cairo_utf8_to_ucs4 (utf8, utf8_len, NULL, NULL);
+	    if (status2)
+		status = status2;
+	} else {
+	    cairo_glyph_text_info_t info;
+
+	    info.utf8 = utf8;
+	    info.utf8_len = utf8_len;
+	    info.clusters = clusters;
+	    info.num_clusters = num_clusters;
+	    info.cluster_flags = cluster_flags;
+
+	    status = cr->backend->glyphs (cr, glyphs, num_glyphs, &info);
+	}
+    } else {
+	status = cr->backend->glyphs (cr, glyphs, num_glyphs, NULL);
+    }
     if (unlikely (status))
 	_cairo_set_error (cr, status);
 }
@@ -3524,12 +3298,13 @@ cairo_show_text_glyphs (cairo_t			   *cr,
  * "real" text path API in cairo.
  **/
 void
-cairo_text_path  (cairo_t *cr, const char *utf8)
+cairo_text_path (cairo_t *cr, const char *utf8)
 {
     cairo_status_t status;
     cairo_text_extents_t extents;
     cairo_glyph_t stack_glyphs[CAIRO_STACK_ARRAY_LENGTH (cairo_glyph_t)];
     cairo_glyph_t *glyphs, *last_glyph;
+    cairo_scaled_font_t *scaled_font;
     int num_glyphs;
     double x, y;
 
@@ -3539,42 +3314,40 @@ cairo_text_path  (cairo_t *cr, const char *utf8)
     if (utf8 == NULL)
 	return;
 
-    cairo_get_current_point (cr, &x, &y);
 
     glyphs = stack_glyphs;
     num_glyphs = ARRAY_LENGTH (stack_glyphs);
 
-    status = _cairo_gstate_text_to_glyphs (cr->gstate,
-					   x, y,
-					   utf8, strlen (utf8),
-					   &glyphs, &num_glyphs,
-					   NULL, NULL,
-					   NULL);
+    scaled_font = cairo_get_scaled_font (cr);
+    if (unlikely (scaled_font->status)) {
+	_cairo_set_error (cr, scaled_font->status);
+	return;
+    }
 
-    if (unlikely (status))
-	goto BAIL;
+    cairo_get_current_point (cr, &x, &y);
+    status = cairo_scaled_font_text_to_glyphs (scaled_font,
+					       x, y,
+					       utf8, -1,
+					       &glyphs, &num_glyphs,
+					       NULL, NULL, NULL);
 
     if (num_glyphs == 0)
 	return;
 
-    status = _cairo_gstate_glyph_path (cr->gstate,
-				       glyphs, num_glyphs,
-				       cr->path);
+    status = cr->backend->glyph_path (cr, glyphs, num_glyphs);
 
     if (unlikely (status))
 	goto BAIL;
 
     last_glyph = &glyphs[num_glyphs - 1];
-    status = _cairo_gstate_glyph_extents (cr->gstate,
-					  last_glyph, 1,
-					  &extents);
+    status = cr->backend->glyph_extents (cr, last_glyph, 1, &extents);
 
     if (unlikely (status))
 	goto BAIL;
 
     x = last_glyph->x + extents.x_advance;
     y = last_glyph->y + extents.y_advance;
-    cairo_move_to (cr, x, y);
+    cr->backend->move_to (cr, x, y);
 
  BAIL:
     if (glyphs != stack_glyphs)
@@ -3605,19 +3378,17 @@ cairo_glyph_path (cairo_t *cr, const cairo_glyph_t *glyphs, int num_glyphs)
     if (num_glyphs == 0)
 	return;
 
-    if (num_glyphs < 0) {
+    if (unlikely (num_glyphs < 0)) {
 	_cairo_set_error (cr, CAIRO_STATUS_NEGATIVE_COUNT);
 	return;
     }
 
-    if (glyphs == NULL) {
+    if (unlikely (glyphs == NULL)) {
 	_cairo_set_error (cr, CAIRO_STATUS_NULL_POINTER);
 	return;
     }
 
-    status = _cairo_gstate_glyph_path (cr->gstate,
-				       glyphs, num_glyphs,
-				       cr->path);
+    status = cr->backend->glyph_path (cr, glyphs, num_glyphs);
     if (unlikely (status))
 	_cairo_set_error (cr, status);
 }
@@ -3636,8 +3407,27 @@ cairo_get_operator (cairo_t *cr)
     if (unlikely (cr->status))
         return CAIRO_GSTATE_OPERATOR_DEFAULT;
 
-    return _cairo_gstate_get_operator (cr->gstate);
+    return cr->backend->get_operator (cr);
+}
+
+#if 0
+/**
+ * cairo_get_opacity:
+ * @cr: a cairo context
+ *
+ * Gets the current compositing opacity for a cairo context.
+ *
+ * Return value: the current compositing opacity.
+ **/
+double
+cairo_get_opacity (cairo_t *cr)
+{
+    if (unlikely (cr->status))
+        return 1.;
+
+    return cr->backend->get_opacity (cr);
 }
+#endif
 
 /**
  * cairo_get_tolerance:
@@ -3653,7 +3443,7 @@ cairo_get_tolerance (cairo_t *cr)
     if (unlikely (cr->status))
         return CAIRO_GSTATE_TOLERANCE_DEFAULT;
 
-    return _cairo_gstate_get_tolerance (cr->gstate);
+    return cr->backend->get_tolerance (cr);
 }
 slim_hidden_def (cairo_get_tolerance);
 
@@ -3672,7 +3462,7 @@ cairo_get_antialias (cairo_t *cr)
     if (unlikely (cr->status))
         return CAIRO_ANTIALIAS_DEFAULT;
 
-    return _cairo_gstate_get_antialias (cr->gstate);
+    return cr->backend->get_antialias (cr);
 }
 
 /**
@@ -3690,9 +3480,9 @@ cairo_bool_t
 cairo_has_current_point (cairo_t *cr)
 {
     if (unlikely (cr->status))
-    return FALSE;
+	return FALSE;
 
-    return cr->path->has_current_point;
+    return cr->backend->has_current_point (cr);
 }
 
 /**
@@ -3728,20 +3518,13 @@ cairo_has_current_point (cairo_t *cr)
 void
 cairo_get_current_point (cairo_t *cr, double *x_ret, double *y_ret)
 {
-    cairo_fixed_t x_fixed, y_fixed;
     double x, y;
 
+    x = y = 0;
     if (cr->status == CAIRO_STATUS_SUCCESS &&
-	_cairo_path_fixed_get_current_point (cr->path, &x_fixed, &y_fixed))
-    {
-	x = _cairo_fixed_to_double (x_fixed);
-	y = _cairo_fixed_to_double (y_fixed);
-	_cairo_gstate_backend_to_user (cr->gstate, &x, &y);
-    }
-    else
+	cr->backend->has_current_point (cr))
     {
-	x = 0.0;
-	y = 0.0;
+	cr->backend->get_current_point (cr, &x, &y);
     }
 
     if (x_ret)
@@ -3765,7 +3548,7 @@ cairo_get_fill_rule (cairo_t *cr)
     if (unlikely (cr->status))
         return CAIRO_GSTATE_FILL_RULE_DEFAULT;
 
-    return _cairo_gstate_get_fill_rule (cr->gstate);
+    return cr->backend->get_fill_rule (cr);
 }
 
 /**
@@ -3785,7 +3568,7 @@ cairo_get_line_width (cairo_t *cr)
     if (unlikely (cr->status))
         return CAIRO_GSTATE_LINE_WIDTH_DEFAULT;
 
-    return _cairo_gstate_get_line_width (cr->gstate);
+    return cr->backend->get_line_width (cr);
 }
 slim_hidden_def (cairo_get_line_width);
 
@@ -3803,7 +3586,7 @@ cairo_get_line_cap (cairo_t *cr)
     if (unlikely (cr->status))
         return CAIRO_GSTATE_LINE_CAP_DEFAULT;
 
-    return _cairo_gstate_get_line_cap (cr->gstate);
+    return cr->backend->get_line_cap (cr);
 }
 
 /**
@@ -3820,7 +3603,7 @@ cairo_get_line_join (cairo_t *cr)
     if (unlikely (cr->status))
         return CAIRO_GSTATE_LINE_JOIN_DEFAULT;
 
-    return _cairo_gstate_get_line_join (cr->gstate);
+    return cr->backend->get_line_join (cr);
 }
 
 /**
@@ -3837,7 +3620,7 @@ cairo_get_miter_limit (cairo_t *cr)
     if (unlikely (cr->status))
         return CAIRO_GSTATE_MITER_LIMIT_DEFAULT;
 
-    return _cairo_gstate_get_miter_limit (cr->gstate);
+    return cr->backend->get_miter_limit (cr);
 }
 
 /**
@@ -3855,7 +3638,7 @@ cairo_get_matrix (cairo_t *cr, cairo_matrix_t *matrix)
 	return;
     }
 
-    _cairo_gstate_get_matrix (cr->gstate, matrix);
+    cr->backend->get_matrix (cr, matrix);
 }
 slim_hidden_def (cairo_get_matrix);
 
@@ -3881,7 +3664,7 @@ cairo_get_target (cairo_t *cr)
     if (unlikely (cr->status))
 	return _cairo_surface_create_in_error (cr->status);
 
-    return _cairo_gstate_get_original_target (cr->gstate);
+    return cr->backend->get_original_target (cr);
 }
 slim_hidden_def (cairo_get_target);
 
@@ -3911,7 +3694,7 @@ cairo_get_group_target (cairo_t *cr)
     if (unlikely (cr->status))
 	return _cairo_surface_create_in_error (cr->status);
 
-    return _cairo_gstate_get_target (cr->gstate);
+    return cr->backend->get_current_target (cr);
 }
 
 /**
@@ -3946,7 +3729,7 @@ cairo_copy_path (cairo_t *cr)
     if (unlikely (cr->status))
 	return _cairo_path_create_in_error (cr->status);
 
-    return _cairo_path_create (cr->path, cr->gstate);
+    return cr->backend->copy_path (cr);
 }
 
 /**
@@ -3988,7 +3771,7 @@ cairo_copy_path_flat (cairo_t *cr)
     if (unlikely (cr->status))
 	return _cairo_path_create_in_error (cr->status);
 
-    return _cairo_path_create_flat (cr->path, cr->gstate);
+    return cr->backend->copy_path_flat (cr);
 }
 
 /**
@@ -4012,12 +3795,12 @@ cairo_append_path (cairo_t		*cr,
     if (unlikely (cr->status))
 	return;
 
-    if (path == NULL) {
+    if (unlikely (path == NULL)) {
 	_cairo_set_error (cr, CAIRO_STATUS_NULL_POINTER);
 	return;
     }
 
-    if (path->status) {
+    if (unlikely (path->status)) {
 	if (path->status > CAIRO_STATUS_SUCCESS &&
 	    path->status <= CAIRO_STATUS_LAST_STATUS)
 	    _cairo_set_error (cr, path->status);
@@ -4029,12 +3812,12 @@ cairo_append_path (cairo_t		*cr,
     if (path->num_data == 0)
 	return;
 
-    if (path->data == NULL) {
+    if (unlikely (path->data == NULL)) {
 	_cairo_set_error (cr, CAIRO_STATUS_NULL_POINTER);
 	return;
     }
 
-    status = _cairo_path_append_to_context (path, cr);
+    status = cr->backend->append_path (cr, path);
     if (unlikely (status))
 	_cairo_set_error (cr, status);
 }
diff --git a/src/cairoint.h b/src/cairoint.h
index 3ab7701..13d1555 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -409,7 +409,7 @@ struct _cairo_font_face {
 };
 
 cairo_private void
-_cairo_reset_static_data (void);
+_cairo_default_context_reset_static_data (void);
 
 cairo_private void
 _cairo_toy_font_face_reset_static_data (void);
@@ -599,6 +599,9 @@ extern const cairo_private struct _cairo_font_face_backend _cairo_quartz_font_fa
 struct _cairo_surface_backend {
     cairo_surface_type_t type;
 
+    cairo_t *
+    (*create_context)		(void			*surface);
+
     cairo_surface_t *
     (*create_similar)		(void			*surface,
 				 cairo_content_t	 content,
@@ -1357,7 +1360,7 @@ _cairo_path_fixed_stroke_rectilinear_to_boxes (const cairo_path_fixed_t	*path,
 					       const cairo_matrix_t	*ctm,
 					       cairo_boxes_t		*boxes);
 
-cairo_private cairo_status_t
+cairo_private cairo_int_status_t
 _cairo_path_fixed_stroke_to_traps (const cairo_path_fixed_t	*path,
 				   const cairo_stroke_style_t	*stroke_style,
 				   const cairo_matrix_t	*ctm,
@@ -2404,6 +2407,7 @@ slim_hidden_proto (cairo_format_stride_for_width);
 slim_hidden_proto (cairo_get_current_point);
 slim_hidden_proto (cairo_get_line_width);
 slim_hidden_proto (cairo_get_matrix);
+slim_hidden_proto (cairo_get_scaled_font);
 slim_hidden_proto (cairo_get_target);
 slim_hidden_proto (cairo_get_tolerance);
 slim_hidden_proto (cairo_glyph_allocate);
@@ -2511,6 +2515,7 @@ slim_hidden_proto (cairo_user_font_face_create);
 slim_hidden_proto (cairo_user_font_face_set_init_func);
 slim_hidden_proto (cairo_user_font_face_set_render_glyph_func);
 slim_hidden_proto (cairo_user_font_face_set_unicode_to_glyph_func);
+slim_hidden_proto (cairo_device_to_user);
 slim_hidden_proto (cairo_user_to_device);
 slim_hidden_proto (cairo_user_to_device_distance);
 slim_hidden_proto (cairo_version_string);
diff --git a/src/drm/cairo-drm-gallium-surface.c b/src/drm/cairo-drm-gallium-surface.c
index 76fbae6..b489753 100644
--- a/src/drm/cairo-drm-gallium-surface.c
+++ b/src/drm/cairo-drm-gallium-surface.c
@@ -34,6 +34,7 @@
 #include "cairoint.h"
 
 #include "cairo-drm-private.h"
+#include "cairo-default-context-private.h"
 #include "cairo-error-private.h"
 
 #include <dlfcn.h>
@@ -462,6 +463,8 @@ gallium_surface_glyphs (void				*abstract_surface,
 
 static const cairo_surface_backend_t gallium_surface_backend = {
     CAIRO_SURFACE_TYPE_DRM,
+    _cairo_default_context_create,
+
     gallium_surface_create_similar,
     gallium_surface_finish,
 
diff --git a/src/drm/cairo-drm-i915-surface.c b/src/drm/cairo-drm-i915-surface.c
index 247d8ad..2a55889 100644
--- a/src/drm/cairo-drm-i915-surface.c
+++ b/src/drm/cairo-drm-i915-surface.c
@@ -103,6 +103,7 @@
 #include "cairo-boxes-private.h"
 #include "cairo-cache-private.h"
 #include "cairo-composite-rectangles-private.h"
+#include "cairo-default-context-private.h"
 #include "cairo-error-private.h"
 #include "cairo-freelist-private.h"
 #include "cairo-list-private.h"
@@ -2338,6 +2339,7 @@ i915_surface_fill (void			*abstract_dst,
 
 static const cairo_surface_backend_t i915_surface_backend = {
     CAIRO_SURFACE_TYPE_DRM,
+    _cairo_default_context_create,
 
     i915_surface_create_similar,
     i915_surface_finish,
diff --git a/src/drm/cairo-drm-i965-surface.c b/src/drm/cairo-drm-i965-surface.c
index 3947836..71061a0 100644
--- a/src/drm/cairo-drm-i965-surface.c
+++ b/src/drm/cairo-drm-i965-surface.c
@@ -56,6 +56,7 @@
 
 #include "cairo-boxes-private.h"
 #include "cairo-composite-rectangles-private.h"
+#include "cairo-default-context-private.h"
 #include "cairo-error-private.h"
 #include "cairo-region-private.h"
 #include "cairo-surface-offset-private.h"
@@ -1490,6 +1491,7 @@ CLEANUP_BOXES:
 
 static const cairo_surface_backend_t i965_surface_backend = {
     CAIRO_SURFACE_TYPE_DRM,
+    _cairo_default_context_create,
 
     i965_surface_create_similar,
     i965_surface_finish,
diff --git a/src/drm/cairo-drm-intel-surface.c b/src/drm/cairo-drm-intel-surface.c
index 96d4615..f28c750 100644
--- a/src/drm/cairo-drm-intel-surface.c
+++ b/src/drm/cairo-drm-intel-surface.c
@@ -32,6 +32,7 @@
 #include "cairo-drm-private.h"
 #include "cairo-drm-intel-private.h"
 
+#include "cairo-default-context-private.h"
 #include "cairo-error-private.h"
 
 /* Basic generic/stub surface for intel chipsets */
@@ -248,6 +249,7 @@ intel_surface_glyphs (void			*abstract_surface,
 
 static const cairo_surface_backend_t intel_surface_backend = {
     CAIRO_SURFACE_TYPE_DRM,
+    _cairo_default_context_create,
 
     intel_surface_create_similar,
     intel_surface_finish,
diff --git a/src/drm/cairo-drm-radeon-surface.c b/src/drm/cairo-drm-radeon-surface.c
index cbcef2a..9335d7b 100644
--- a/src/drm/cairo-drm-radeon-surface.c
+++ b/src/drm/cairo-drm-radeon-surface.c
@@ -32,6 +32,7 @@
 #include "cairo-drm-private.h"
 #include "cairo-drm-radeon-private.h"
 
+#include "cairo-default-context-private.h"
 #include "cairo-error-private.h"
 
 /* Basic stub surface for radeon chipsets */
@@ -252,6 +253,7 @@ radeon_surface_glyphs (void			*abstract_surface,
 
 static const cairo_surface_backend_t radeon_surface_backend = {
     CAIRO_SURFACE_TYPE_DRM,
+    _cairo_default_context_create,
 
     radeon_surface_create_similar,
     radeon_surface_finish,
diff --git a/src/test-fallback-surface.c b/src/test-fallback-surface.c
index 66399d4..5695dc9 100644
--- a/src/test-fallback-surface.c
+++ b/src/test-fallback-surface.c
@@ -54,6 +54,7 @@
 #include "cairoint.h"
 
 #include "test-fallback-surface.h"
+#include "cairo-default-context-private.h"
 #include "cairo-error-private.h"
 
 typedef struct _test_fallback_surface {
@@ -207,6 +208,8 @@ _test_fallback_surface_get_extents (void		  *abstract_surface,
 
 static const cairo_surface_backend_t test_fallback_surface_backend = {
     CAIRO_INTERNAL_SURFACE_TYPE_TEST_FALLBACK,
+    _cairo_default_context_create,
+
     _test_fallback_surface_create_similar,
     _test_fallback_surface_finish,
     _test_fallback_surface_acquire_source_image,
diff --git a/src/test-fallback16-surface.c b/src/test-fallback16-surface.c
index ce2febc..2f4da5b 100644
--- a/src/test-fallback16-surface.c
+++ b/src/test-fallback16-surface.c
@@ -43,6 +43,7 @@
 #include "cairoint.h"
 
 #include "test-fallback16-surface.h"
+#include "cairo-default-context-private.h"
 #include "cairo-error-private.h"
 
 typedef struct _test_fallback16_surface {
@@ -204,6 +205,8 @@ _test_fallback16_surface_get_extents (void		  *abstract_surface,
 
 static const cairo_surface_backend_t test_fallback16_surface_backend = {
     CAIRO_INTERNAL_SURFACE_TYPE_TEST_FALLBACK,
+    _cairo_default_context_create,
+
     _test_fallback16_surface_create_similar,
     _test_fallback16_surface_finish,
     _test_fallback16_surface_acquire_source_image,
diff --git a/src/test-null-surface.c b/src/test-null-surface.c
index 0247d92..620dd2f 100644
--- a/src/test-null-surface.c
+++ b/src/test-null-surface.c
@@ -40,6 +40,7 @@
 
 #include "test-null-surface.h"
 
+#include "cairo-default-context-private.h"
 #include "cairo-error-private.h"
 
 slim_hidden_proto (_cairo_test_null_surface_create);
@@ -133,6 +134,7 @@ _cairo_null_surface_has_show_text_glyphs (void *surface)
 
 static const cairo_surface_backend_t null_surface_backend = {
     CAIRO_INTERNAL_SURFACE_TYPE_NULL,
+    _cairo_default_context_create,
 
     _cairo_null_surface_create_similar,
     NULL, /* finish */
diff --git a/src/test-paginated-surface.c b/src/test-paginated-surface.c
index e06cbed..241f1bd 100644
--- a/src/test-paginated-surface.c
+++ b/src/test-paginated-surface.c
@@ -49,6 +49,7 @@
 
 #include "test-paginated-surface.h"
 
+#include "cairo-default-context-private.h"
 #include "cairo-error-private.h"
 #include "cairo-paginated-private.h"
 
@@ -240,6 +241,7 @@ _test_paginated_surface_set_paginated_mode (void			*abstract_surface,
 
 static const cairo_surface_backend_t test_paginated_surface_backend = {
     CAIRO_INTERNAL_SURFACE_TYPE_TEST_PAGINATED,
+    _cairo_default_context_create,
 
     /* Since we are a paginated user, we get to regard most of the
      * surface backend interface as historical cruft and ignore it. */
diff --git a/src/test-wrapping-surface.c b/src/test-wrapping-surface.c
index 4a60139..4dd6c4c 100644
--- a/src/test-wrapping-surface.c
+++ b/src/test-wrapping-surface.c
@@ -43,6 +43,7 @@
 
 #include "test-wrapping-surface.h"
 
+#include "cairo-default-context-private.h"
 #include "cairo-error-private.h"
 #include "cairo-surface-wrapper-private.h"
 
@@ -234,6 +235,8 @@ _test_wrapping_surface_show_text_glyphs (void			    *abstract_surface,
 
 static const cairo_surface_backend_t test_wrapping_surface_backend = {
     CAIRO_INTERNAL_SURFACE_TYPE_TEST_WRAPPING,
+    _cairo_default_context_create,
+
     _test_wrapping_surface_create_similar,
     _test_wrapping_surface_finish,
     _test_wrapping_surface_acquire_source_image,
commit 2055732ffcd6316c3feb05ac330fbaf8698df5c4
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Thu Jul 14 17:58:31 2011 +0100

    tests: Add paint-clip-fill
    
    A false reduction bug found by Taekyun Kim.
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/test/Makefile.refs b/test/Makefile.refs
index e855a43..5a82b38 100644
--- a/test/Makefile.refs
+++ b/test/Makefile.refs
@@ -857,6 +857,8 @@ REFERENCE_IMAGES = \
 	overlapping-glyphs.rgb24.ref.png \
 	overlapping-glyphs.svg.argb32.ref.png \
 	overlapping-glyphs.svg.rgb24.ref.png \
+	paint-clip-fill-aa.ref.png \
+	paint-clip-fill-mono.ref.png \
 	paint-repeat.ref.png \
 	paint-source-alpha.image16.ref.png \
 	paint-source-alpha.ref.png \
@@ -1338,6 +1340,7 @@ REFERENCE_IMAGES = \
 	user-font.svg.ref.png \
 	user-font.xlib.ref.png \
 	white-in-noop.ref.png \
+	xcb-snapshot-assert.ref.png \
 	xcb-stress-cache.ref.png \
 	xcb-surface-source.argb32.ref.png \
 	xcb-surface-source.image16.ref.png \
diff --git a/test/Makefile.sources b/test/Makefile.sources
index c4e4463..56a8d32 100644
--- a/test/Makefile.sources
+++ b/test/Makefile.sources
@@ -194,6 +194,7 @@ test_sources = \
 	over-between-source.c				\
 	overlapping-glyphs.c				\
 	paint.c						\
+	paint-clip-fill.c				\
 	paint-repeat.c					\
 	paint-source-alpha.c				\
 	paint-with-alpha.c				\
diff --git a/test/paint-clip-fill-aa.ref.png b/test/paint-clip-fill-aa.ref.png
new file mode 100644
index 0000000..a8cf417
Binary files /dev/null and b/test/paint-clip-fill-aa.ref.png differ
diff --git a/test/paint-clip-fill-mono.ref.png b/test/paint-clip-fill-mono.ref.png
new file mode 100644
index 0000000..a8cf417
Binary files /dev/null and b/test/paint-clip-fill-mono.ref.png differ
diff --git a/test/paint-clip-fill.c b/test/paint-clip-fill.c
new file mode 100644
index 0000000..5a9e24f
--- /dev/null
+++ b/test/paint-clip-fill.c
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2011 SCore Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Author: Taekyun Kim <podain77 at gmail.com>
+ */
+
+#include "cairo-test.h"
+
+static void
+rounded_rectangle(cairo_t *cr,
+		  double x, double y,
+		  double width, double height,
+		  double radius)
+{
+    cairo_move_to   (cr, x, y + radius);
+    cairo_line_to   (cr, x, y + height - radius);
+    cairo_curve_to  (cr, x, y + height - radius/2.0,
+			  x + radius/2.0, y + height,
+			  x + radius, y + height);
+    cairo_line_to   (cr, x + width - radius, y + height);
+    cairo_curve_to  (cr, x + width - radius/2.0, y + height,
+		          x + width, y + height - radius/2.0,
+			  x + width, y + height - radius);
+    cairo_line_to   (cr, x + width, y + radius);
+    cairo_curve_to  (cr, x + width, y + radius/2.0,
+		          x + width - radius/2.0, y,
+			  x + width - radius, y);
+    cairo_line_to   (cr, x + radius, y);
+    cairo_curve_to  (cr, x + radius/2.0, y, x, y + radius/2.0, x, y + radius);
+    cairo_close_path(cr);
+}
+
+static cairo_test_status_t
+draw_mono (cairo_t *cr, int width, int height)
+{
+    cairo_set_antialias(cr, CAIRO_ANTIALIAS_NONE);
+    cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
+    cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 1.0);
+    cairo_paint(cr);
+
+    cairo_rectangle(cr, 20, 20, 60, 60);
+    cairo_clip(cr);
+
+    rounded_rectangle(cr, 0, 0, 100, 100, 10);
+    cairo_clip(cr);
+
+    cairo_set_source_rgba(cr, 1.0, 0.0, 0.0, 1.0);
+    cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
+    cairo_paint(cr);
+
+    return CAIRO_TEST_SUCCESS;
+}
+
+static cairo_test_status_t
+draw_aa (cairo_t *cr, int width, int height)
+{
+    cairo_set_antialias(cr, CAIRO_ANTIALIAS_DEFAULT);
+    cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
+    cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 1.0);
+    cairo_paint(cr);
+
+    cairo_rectangle(cr, 20, 20, 60, 60);
+    cairo_clip(cr);
+
+    rounded_rectangle(cr, 0, 0, 100, 100, 10);
+    cairo_clip(cr);
+
+    cairo_set_source_rgba(cr, 1.0, 0.0, 0.0, 1.0);
+    cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
+    cairo_paint(cr);
+
+    return CAIRO_TEST_SUCCESS;
+}
+
+CAIRO_TEST (paint_clip_fill_mono,
+	    "Test reduction of a paint with a clip",
+	    "paint, clip", /* keywords */
+	    NULL, /* requirements */
+	    100, 100,
+	    NULL, draw_mono)
+CAIRO_TEST (paint_clip_fill_aa,
+	    "Test reduction of a paint with a clip",
+	    "paint, clip", /* keywords */
+	    NULL, /* requirements */
+	    100, 100,
+	    NULL, draw_aa)
commit 524809759b7c1c9f01bcdd9f195ec4366ebe8223
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Thu Jul 14 17:51:00 2011 +0100

    tests: Add clip-complex-shape
    
    Contributed by Taekyun Kim to exercise a major bug he found in the
    treatment of complex clips.
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/test/Makefile.refs b/test/Makefile.refs
index 5b2acb1..e855a43 100644
--- a/test/Makefile.refs
+++ b/test/Makefile.refs
@@ -92,6 +92,8 @@ REFERENCE_IMAGES = \
 	clear.svg12.argb32.xfail.png \
 	clear.svg12.rgb24.xfail.png \
 	clip-all.ref.png \
+	clip-complex-shape-eo-aa.ref.png \
+	clip-complex-shape-eo-mono.ref.png \
 	clip-contexts.ref.png \
 	clip-device-offset.argb32.ref.png \
 	clip-device-offset.rgb24.ref.png \
diff --git a/test/Makefile.sources b/test/Makefile.sources
index e4212f0..c4e4463 100644
--- a/test/Makefile.sources
+++ b/test/Makefile.sources
@@ -28,6 +28,7 @@ test_sources = \
 	clear-source.c					\
 	clip-all.c					\
 	clip-contexts.c					\
+	clip-complex-shape.c				\
 	clip-disjoint.c					\
 	clip-device-offset.c				\
 	clip-draw-unbounded.c				\
diff --git a/test/clip-complex-shape-eo-aa.ref.png b/test/clip-complex-shape-eo-aa.ref.png
new file mode 100644
index 0000000..d575aa9
Binary files /dev/null and b/test/clip-complex-shape-eo-aa.ref.png differ
diff --git a/test/clip-complex-shape-eo-mono.ref.png b/test/clip-complex-shape-eo-mono.ref.png
new file mode 100644
index 0000000..d575aa9
Binary files /dev/null and b/test/clip-complex-shape-eo-mono.ref.png differ
diff --git a/test/clip-complex-shape.c b/test/clip-complex-shape.c
new file mode 100644
index 0000000..d7d5301
--- /dev/null
+++ b/test/clip-complex-shape.c
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2011 SCore Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Author: Taekyun Kim <podain77 at gmail.com>
+ */
+
+#include "cairo-test.h"
+
+static void
+rounded_rectangle(cairo_t *cr,
+		  double x, double y,
+		  double width, double height,
+		  double radius)
+{
+    cairo_move_to   (cr, x, y + radius);
+    cairo_line_to   (cr, x, y + height - radius);
+    cairo_curve_to  (cr, x, y + height - radius/2.0,
+			  x + radius/2.0, y + height,
+			  x + radius, y + height);
+    cairo_line_to   (cr, x + width - radius, y + height);
+    cairo_curve_to  (cr, x + width - radius/2.0, y + height,
+		          x + width, y + height - radius/2.0,
+			  x + width, y + height - radius);
+    cairo_line_to   (cr, x + width, y + radius);
+    cairo_curve_to  (cr, x + width, y + radius/2.0,
+		          x + width - radius/2.0, y,
+			  x + width - radius, y);
+    cairo_line_to   (cr, x + radius, y);
+    cairo_curve_to  (cr, x + radius/2.0, y, x, y + radius/2.0, x, y + radius);
+    cairo_close_path(cr);
+}
+
+static void
+background (cairo_t *cr)
+{
+    cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
+    cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 1.0);
+    cairo_paint(cr);
+}
+
+static void
+foreground (cairo_t *cr)
+{
+    cairo_set_source_rgba(cr, 1.0, 0.0, 0.0, 1.0);
+    cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
+    cairo_rectangle(cr, 20, 20, 60, 60);
+    cairo_fill(cr);
+}
+
+static cairo_test_status_t
+clip_eo_mono (cairo_t *cr, int width, int height)
+{
+
+    background (cr);
+
+    cairo_set_antialias(cr, CAIRO_ANTIALIAS_NONE);
+    cairo_set_fill_rule(cr, CAIRO_FILL_RULE_EVEN_ODD);
+    rounded_rectangle(cr, 0, 0, 40, 100, 10);
+    rounded_rectangle(cr, 60, 0, 40, 100, 10);
+    cairo_clip(cr);
+
+    foreground (cr);
+
+    return CAIRO_TEST_SUCCESS;
+}
+
+static cairo_test_status_t
+clip_eo_aa (cairo_t *cr, int width, int height)
+{
+    background (cr);
+
+    cairo_set_antialias(cr, CAIRO_ANTIALIAS_DEFAULT);
+    cairo_set_fill_rule(cr, CAIRO_FILL_RULE_EVEN_ODD);
+    rounded_rectangle(cr, 0, 0, 40, 100, 10);
+    rounded_rectangle(cr, 60, 0, 40, 100, 10);
+    cairo_clip(cr);
+
+    foreground (cr);
+
+    return CAIRO_TEST_SUCCESS;
+}
+
+CAIRO_TEST (clip_complex_shape_eo_mono,
+	    "Test clipping against a complex shape",
+	    "clip", /* keywords */
+	    NULL, /* requirements */
+	    100, 100,
+	    NULL, clip_eo_mono)
+CAIRO_TEST (clip_complex_shape_eo_aa,
+	    "Test clipping against a complex shape",
+	    "clip", /* keywords */
+	    NULL, /* requirements */
+	    100, 100,
+	    NULL, clip_eo_aa)
commit 41b5469b9523c9a8784d230e929518367dbda751
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Tue Jul 5 11:49:50 2011 +0100

    image: Only discard the outer boxes
    
    This is necessary as the callers do not propagate the clip extents after
    finding the singular clip path. *sigh*
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/cairo-image-surface.c b/src/cairo-image-surface.c
index a2345b2..2c538d5 100644
--- a/src/cairo-image-surface.c
+++ b/src/cairo-image-surface.c
@@ -3211,13 +3211,14 @@ _clip_get_single_path (cairo_clip_t *clip)
     cairo_clip_path_t *iter = clip->path;
     cairo_clip_path_t *path = NULL;
 
+    /* Boxes only effect the extents, so discard any outer boxes. */
     do {
-	if ((iter->flags & CAIRO_CLIP_PATH_IS_BOX) == 0) {
-	    if (path != NULL)
-		return FALSE;
+	if (path != NULL)
+	    return FALSE;
 
+	if ((iter->flags & CAIRO_CLIP_PATH_IS_BOX) == 0)
 	    path = iter;
-	}
+
 	iter = iter->prev;
     } while (iter != NULL);
 
commit ebe665867c2ff22c098ede4d4e909d42cca8b39c
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Thu Jul 14 16:45:54 2011 +0100

    scaled-font: Fix assertions for original font-face vs font-face
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/cairo-scaled-font.c b/src/cairo-scaled-font.c
index 1b3cd5e..3f37e1c 100644
--- a/src/cairo-scaled-font.c
+++ b/src/cairo-scaled-font.c
@@ -607,6 +607,7 @@ _cairo_scaled_font_init_key (cairo_scaled_font_t        *scaled_font,
     scaled_font->status = CAIRO_STATUS_SUCCESS;
     scaled_font->placeholder = FALSE;
     scaled_font->font_face = font_face;
+    scaled_font->original_font_face = font_face;
     scaled_font->font_matrix = *font_matrix;
     scaled_font->ctm = *ctm;
     /* ignore translation values in the ctm */
@@ -639,7 +640,7 @@ _cairo_scaled_font_keys_equal (const void *abstract_key_a,
     if (key_a->hash_entry.hash != key_b->hash_entry.hash)
 	return FALSE;
 
-    return key_a->font_face == key_b->font_face &&
+    return key_a->original_font_face == key_b->original_font_face &&
 	    memcmp ((unsigned char *)(&key_a->font_matrix.xx),
 		    (unsigned char *)(&key_b->font_matrix.xx),
 		    sizeof(cairo_matrix_t)) == 0 &&


More information about the cairo-commit mailing list