[cairo-commit] boilerplate/cairo-boilerplate.c boilerplate/cairo-boilerplate-test-surfaces.c boilerplate/cairo-boilerplate-xlib.c configure.ac perf/cairo-perf-compare-backends.c perf/cairo-perf-diff-files.c perf/cairo-perf.h perf/cairo-perf-micro.c perf/cairo-perf-report.c perf/cairo-perf-trace.c perf/cairo-stats.c perf/Makefile.sources perf/micro src/cairo-analysis-surface.c src/cairo-array.c src/cairo-array-private.h src/cairo-atomic-private.h src/cairo-bentley-ottmann.c src/cairo-bentley-ottmann-rectangular.c src/cairo-bentley-ottmann-rectilinear.c src/cairo-botor-scan-converter.c src/cairo-boxes.c src/cairo-boxes-intersect.c src/cairo-boxes-private.h src/cairo-box-private.h src/cairo.c src/cairo-cff-subset.c src/cairo-clip-boxes.c src/cairo-clip.c src/cairo-clip-private.h src/cairo-clip-region.c src/cairo-clip-surface.c src/cairo-clip-tor-scan-converter.c src/cairo-composite-rectangles.c src/cairo-composite-rectangles-private.h src/cairo-compositor.c src/cairo-compositor-privat e.h src/cairo-default-context.c src/cairo-fallback-compositor.c src/cairo-freed-pool-private.h src/cairo-ft-font.c src/cairo-gl-composite.c src/cairo-gl-device.c src/cairo-gl-glyphs.c src/cairo-gl-operand.c src/cairo-gl-private.h src/cairo-gl-shaders.c src/cairo-gl-spans-compositor.c src/cairo-gl-surface.c src/cairo-gl-traps-compositor.c src/cairo-gstate.c src/cairo.h src/cairo-image-compositor.c src/cairo-image-mask-compositor.c src/cairo-image-source.c src/cairo-image-spans-compositor.c src/cairo-image-surface.c src/cairo-image-surface-private.h src/cairoint.h src/cairo-mask-compositor.c src/cairo-matrix.c src/cairo-mesh-pattern-rasterizer.c src/cairo-mime-surface.c src/cairo-mono-scan-converter.c src/cairo-no-compositor.c src/cairo-output-stream.c src/cairo-paginated-surface.c src/cairo-path-bounds.c src/cairo-path-fill.c src/cairo-path-fixed.c src/cairo-path-fixed-private.h src/cairo-path-stroke-boxes.c src/cairo-path-stroke.c src/cairo-path-stroke-polygon.c src/cairo-pa th-stroke-tristrip.c src/cairo-pattern.c src/cairo-pattern-private.h src/cairo-pdf-operators.c src/cairo-pdf-shading.c src/cairo-pdf-surface.c src/cairo-polygon.c src/cairo-polygon-intersect.c src/cairo-ps-surface.c src/cairo-quartz-image-surface.c src/cairo-quartz-surface.c src/cairo-recording-surface.c src/cairo-recording-surface-private.h src/cairo-rectangular-scan-converter.c src/cairo-reference-count-private.h src/cairo-scaled-font.c src/cairo-scaled-font-private.h src/cairo-script-private.h src/cairo-script-surface.c src/cairo-slope.c src/cairo-spans.c src/cairo-spans-compositor.c src/cairo-spans-compositor-private.h src/cairo-spans-private.h src/cairo-spline.c src/cairo-stroke-style.c src/cairo-surface-backend-private.h src/cairo-surface.c src/cairo-surface-fallback.c src/cairo-surface-fallback-private.h src/cairo-surface-observer.c src/cairo-surface-observer-private.h src/cairo-surface-private.h src/cairo-surface-snapshot.c src/cairo-surface-snapshot-private.h src/ca iro-surface-subsurface.c src/cairo-surface-subsurface-private.h src/cairo-surface-wrapper.c src/cairo-surface-wrapper-private.h src/cairo-svg-surface.c src/cairo-time.c src/cairo-time-private.h src/cairo-tor22-scan-converter.c src/cairo-tor-scan-converter.c src/cairo-traps.c src/cairo-traps-compositor.c src/cairo-traps-private.h src/cairo-tristrip.c src/cairo-tristrip-private.h src/cairo-truetype-subset.c src/cairo-type1-fallback.c src/cairo-type1-subset.c src/cairo-type3-glyph-surface.c src/cairo-types-private.h src/cairo-wideint.c src/cairo-wideint-private.h src/cairo-win32-printing-surface.c src/cairo-win32-surface.c src/cairo-xcb-connection.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-core-compositor.c src/cairo-xlib-display.c src/cairo-xlib-fallback-compositor.c src/cairo-xlib-private.h src/cairo-xlib-render-compositor.c src/cairo-xlib-screen.c src/cairo-xlib-source.c src/cairo-xlib-surface. c src/cairo-xlib-surface-private.h src/Makefile.sources src/skia src/test-base-compositor-surface.c src/test-compositor-surface.c src/test-compositor-surface.h src/test-compositor-surface-private.h src/test-fallback16-surface.c src/test-fallback16-surface.h src/test-fallback-surface.c src/test-fallback-surface.h src/test-null-compositor-surface.c src/test-null-compositor-surface.h src/test-null-surface.c src/test-null-surface.h src/test-paginated-surface.c src/test-wrapping-surface.c src/test-wrapping-surface.h test/a1-clip-fill-rule.argb32.ref.png test/a1-clip-fill-rule.rgb24.ref.png test/a1-rectilinear-grid.ref.png test/cairo-test-trace.c test/clear-source.c test/clip-fill-rule.c test/Makefile.refs test/Makefile.sources test/map-to-image.c test/overlapping-boxes.argb32.ref.png test/overlapping-boxes.c test/overlapping-boxes.rgb24.ref.png test/rectilinear-grid.c test/shape-sierpinski.c test/shape-sierpinski.ref.png test/test-fallback16-surface-source.c test/test-fallback16- surface-source.ps.ref.png test/test-fallback16-surface-source.svg12.argb32.xfail.png test/test-fallback16-surface-source.svg12.rgb24.xfail.png test/zero-mask.c util/cairo-script util/cairo-trace util/show-polygon.c

Chris Wilson ickle at kemper.freedesktop.org
Mon Sep 12 00:35:30 PDT 2011


 boilerplate/cairo-boilerplate-test-surfaces.c |  351 +-
 boilerplate/cairo-boilerplate-xlib.c          |    3 
 boilerplate/cairo-boilerplate.c               |   14 
 configure.ac                                  |    4 
 dev/null                                      |binary
 perf/Makefile.sources                         |    3 
 perf/cairo-perf-compare-backends.c            |    6 
 perf/cairo-perf-diff-files.c                  |   47 
 perf/cairo-perf-micro.c                       |  108 
 perf/cairo-perf-report.c                      |    7 
 perf/cairo-perf-trace.c                       |  136 
 perf/cairo-perf.h                             |   16 
 perf/cairo-stats.c                            |   66 
 perf/micro/Makefile.sources                   |    5 
 perf/micro/a1-curve.c                         |  112 
 perf/micro/a1-line.c                          |  223 +
 perf/micro/box-outline.c                      |  119 
 perf/micro/composite-checker.c                |    9 
 perf/micro/curve.c                            |    9 
 perf/micro/disjoint.c                         |    6 
 perf/micro/dragon.c                           |    9 
 perf/micro/fill-clip.c                        |  126 
 perf/micro/fill.c                             |    9 
 perf/micro/glyphs.c                           |    9 
 perf/micro/hash-table.c                       |    9 
 perf/micro/hatching.c                         |    9 
 perf/micro/intersections.c                    |    9 
 perf/micro/line.c                             |    9 
 perf/micro/long-dashed-lines.c                |    9 
 perf/micro/long-lines.c                       |    9 
 perf/micro/many-curves.c                      |    9 
 perf/micro/many-fills.c                       |    9 
 perf/micro/many-strokes.c                     |   13 
 perf/micro/mask.c                             |    6 
 perf/micro/mosaic.c                           |    9 
 perf/micro/paint-with-alpha.c                 |    9 
 perf/micro/paint.c                            |    9 
 perf/micro/pattern_create_radial.c            |    9 
 perf/micro/pixel.c                            |  177 +
 perf/micro/pythagoras-tree.c                  |    9 
 perf/micro/rectangles.c                       |    9 
 perf/micro/rounded-rectangles.c               |    9 
 perf/micro/sierpinski.c                       |   94 
 perf/micro/spiral.c                           |    9 
 perf/micro/stroke.c                           |    9 
 perf/micro/subimage_copy.c                    |    9 
 perf/micro/tessellate.c                       |    9 
 perf/micro/text.c                             |    9 
 perf/micro/twin.c                             |    9 
 perf/micro/unaligned-clip.c                   |    9 
 perf/micro/wave.c                             |    9 
 perf/micro/wide-fills.c                       |    9 
 perf/micro/wide-strokes.c                     |    9 
 perf/micro/world-map.c                        |    9 
 perf/micro/zrusin.c                           |    8 
 src/Makefile.sources                          |   42 
 src/cairo-analysis-surface.c                  |   77 
 src/cairo-array-private.h                     |   90 
 src/cairo-array.c                             |   11 
 src/cairo-atomic-private.h                    |    5 
 src/cairo-bentley-ottmann-rectangular.c       |   55 
 src/cairo-bentley-ottmann-rectilinear.c       |   69 
 src/cairo-bentley-ottmann.c                   |  154 -
 src/cairo-botor-scan-converter.c              |    5 
 src/cairo-box-private.h                       |   48 
 src/cairo-boxes-intersect.c                   |   47 
 src/cairo-boxes-private.h                     |   16 
 src/cairo-boxes.c                             |   77 
 src/cairo-cff-subset.c                        |    8 
 src/cairo-clip-boxes.c                        |   42 
 src/cairo-clip-private.h                      |   23 
 src/cairo-clip-region.c                       |    8 
 src/cairo-clip-surface.c                      |   39 
 src/cairo-clip-tor-scan-converter.c           | 1845 ++++++++++++
 src/cairo-clip.c                              |   20 
 src/cairo-composite-rectangles-private.h      |   38 
 src/cairo-composite-rectangles.c              |  179 -
 src/cairo-compositor-private.h                |  355 ++
 src/cairo-compositor.c                        |  213 +
 src/cairo-default-context.c                   |    3 
 src/cairo-fallback-compositor.c               |  174 +
 src/cairo-freed-pool-private.h                |    6 
 src/cairo-ft-font.c                           |    1 
 src/cairo-gl-composite.c                      | 1148 -------
 src/cairo-gl-device.c                         |   20 
 src/cairo-gl-glyphs.c                         |  382 --
 src/cairo-gl-operand.c                        |  538 +++
 src/cairo-gl-private.h                        |  106 
 src/cairo-gl-shaders.c                        |   69 
 src/cairo-gl-spans-compositor.c               |  502 +++
 src/cairo-gl-surface.c                        | 1021 +-----
 src/cairo-gl-traps-compositor.c               |  550 +++
 src/cairo-gstate.c                            |  341 +-
 src/cairo-image-compositor.c                  | 1545 ++++++++++
 src/cairo-image-mask-compositor.c             |  408 ++
 src/cairo-image-source.c                      |  975 ++++++
 src/cairo-image-spans-compositor.c            |  131 
 src/cairo-image-surface-private.h             |   88 
 src/cairo-image-surface.c                     | 3981 --------------------------
 src/cairo-mask-compositor.c                   | 1412 +++++++++
 src/cairo-matrix.c                            |    6 
 src/cairo-mesh-pattern-rasterizer.c           |    1 
 src/cairo-mime-surface.c                      |   18 
 src/cairo-mono-scan-converter.c               |  607 +++
 src/cairo-no-compositor.c                     |  107 
 src/cairo-output-stream.c                     |    2 
 src/cairo-paginated-surface.c                 |   29 
 src/cairo-path-bounds.c                       |   28 
 src/cairo-path-fill.c                         |   69 
 src/cairo-path-fixed-private.h                |    4 
 src/cairo-path-fixed.c                        |   57 
 src/cairo-path-stroke-boxes.c                 |   90 
 src/cairo-path-stroke-polygon.c               |   71 
 src/cairo-path-stroke-tristrip.c              | 1088 +++++++
 src/cairo-path-stroke.c                       |   10 
 src/cairo-pattern-private.h                   |   58 
 src/cairo-pattern.c                           | 1137 +------
 src/cairo-pdf-operators.c                     |    2 
 src/cairo-pdf-shading.c                       |    2 
 src/cairo-pdf-surface.c                       |   83 
 src/cairo-polygon-intersect.c                 |   69 
 src/cairo-polygon.c                           |   52 
 src/cairo-ps-surface.c                        |  211 -
 src/cairo-quartz-image-surface.c              |  160 -
 src/cairo-quartz-surface.c                    |  802 +----
 src/cairo-recording-surface-private.h         |    6 
 src/cairo-recording-surface.c                 |  131 
 src/cairo-rectangular-scan-converter.c        |   75 
 src/cairo-reference-count-private.h           |    1 
 src/cairo-scaled-font-private.h               |   68 
 src/cairo-scaled-font.c                       |  111 
 src/cairo-script-private.h                    |    3 
 src/cairo-script-surface.c                    |  179 -
 src/cairo-slope.c                             |    4 
 src/cairo-spans-compositor-private.h          |   96 
 src/cairo-spans-compositor.c                  | 1007 ++++++
 src/cairo-spans-private.h                     |   55 
 src/cairo-spans.c                             |  108 
 src/cairo-spline.c                            |   53 
 src/cairo-stroke-style.c                      |   10 
 src/cairo-surface-backend-private.h           |  196 +
 src/cairo-surface-fallback-private.h          |  112 
 src/cairo-surface-fallback.c                  | 1563 ----------
 src/cairo-surface-observer-private.h          |   24 
 src/cairo-surface-observer.c                  |  227 +
 src/cairo-surface-private.h                   |    1 
 src/cairo-surface-snapshot-private.h          |    3 
 src/cairo-surface-snapshot.c                  |   17 
 src/cairo-surface-subsurface-private.h        |   22 
 src/cairo-surface-subsurface.c                |   21 
 src/cairo-surface-wrapper-private.h           |    1 
 src/cairo-surface-wrapper.c                   |    6 
 src/cairo-surface.c                           | 1212 -------
 src/cairo-svg-surface.c                       |   26 
 src/cairo-time-private.h                      |   19 
 src/cairo-time.c                              |   37 
 src/cairo-tor-scan-converter.c                |  265 -
 src/cairo-tor22-scan-converter.c              | 1707 +++++++++++
 src/cairo-traps-compositor.c                  | 2032 +++++++++++++
 src/cairo-traps-private.h                     |  126 
 src/cairo-traps.c                             |   61 
 src/cairo-tristrip-private.h                  |   94 
 src/cairo-tristrip.c                          |  185 +
 src/cairo-truetype-subset.c                   |    2 
 src/cairo-type1-fallback.c                    |    2 
 src/cairo-type1-subset.c                      |    2 
 src/cairo-type3-glyph-surface.c               |   35 
 src/cairo-types-private.h                     |   34 
 src/cairo-wideint-private.h                   |    6 
 src/cairo-wideint.c                           |   16 
 src/cairo-win32-printing-surface.c            |   19 
 src/cairo-win32-surface.c                     |    2 
 src/cairo-xcb-connection.c                    |    2 
 src/cairo-xcb-private.h                       |    4 
 src/cairo-xcb-surface-core.c                  |    1 
 src/cairo-xcb-surface-render.c                |  507 +--
 src/cairo-xcb-surface.c                       |   33 
 src/cairo-xlib-core-compositor.c              |  524 +++
 src/cairo-xlib-display.c                      |  243 -
 src/cairo-xlib-fallback-compositor.c          |   54 
 src/cairo-xlib-private.h                      |  254 +
 src/cairo-xlib-render-compositor.c            | 1685 +++++++++++
 src/cairo-xlib-screen.c                       |   20 
 src/cairo-xlib-source.c                       |  938 ++++++
 src/cairo-xlib-surface-private.h              |   71 
 src/cairo-xlib-surface.c                      | 3224 +--------------------
 src/cairo.c                                   |    1 
 src/cairo.h                                   |   45 
 src/cairoint.h                                |  631 ----
 src/skia/cairo-skia-context.cpp               |    1 
 src/skia/cairo-skia-surface.cpp               |  220 -
 src/test-base-compositor-surface.c            |  942 ++++++
 src/test-compositor-surface-private.h         |   53 
 src/test-compositor-surface.c                 |  259 +
 src/test-compositor-surface.h                 |   71 
 src/test-fallback-surface.c                   |  244 -
 src/test-fallback-surface.h                   |   50 
 src/test-fallback16-surface.c                 |  241 -
 src/test-fallback16-surface.h                 |   52 
 src/test-null-compositor-surface.c            |  480 +++
 src/test-null-compositor-surface.h            |   60 
 src/test-null-surface.c                       |  195 -
 src/test-null-surface.h                       |   46 
 src/test-paginated-surface.c                  |   24 
 src/test-wrapping-surface.c                   |  281 -
 src/test-wrapping-surface.h                   |   51 
 test/Makefile.refs                            |    9 
 test/Makefile.sources                         |    5 
 test/a1-clip-fill-rule.argb32.ref.png         |binary
 test/a1-clip-fill-rule.rgb24.ref.png          |binary
 test/a1-rectilinear-grid.ref.png              |binary
 test/cairo-test-trace.c                       |  195 -
 test/clear-source.c                           |    2 
 test/clip-fill-rule.c                         |   13 
 test/map-to-image.c                           |    4 
 test/overlapping-boxes.argb32.ref.png         |binary
 test/overlapping-boxes.c                      |   96 
 test/overlapping-boxes.rgb24.ref.png          |binary
 test/rectilinear-grid.c                       |   14 
 test/shape-sierpinski.c                       |   85 
 test/shape-sierpinski.ref.png                 |binary
 test/test-fallback16-surface-source.c         |   43 
 test/zero-mask.c                              |    6 
 util/cairo-script/cairo-script-interpreter.c  |    1 
 util/cairo-script/cairo-script-operators.c    |   12 
 util/cairo-trace/trace.c                      |  114 
 util/show-polygon.c                           |   31 
 227 files changed, 27634 insertions(+), 18044 deletions(-)

New commits:
commit af9fbd176b145f042408ef5391eef2a51d7531f8
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Sat Jul 30 17:28:21 2011 +0100

    Introduce a new compositor architecture
    
    Having spent the last dev cycle looking at how we could specialize the
    compositors for various backends, we once again look for the
    commonalities in order to reduce the duplication. In part this is
    motivated by the idea that spans is a good interface for both the
    existent GL backend and pixman, and so they deserve a dedicated
    compositor. xcb/xlib target an identical rendering system and so they
    should be using the same compositor, and it should be possible to run
    that same compositor locally against pixman to generate reference tests.
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
    
    P.S. This brings massive upheaval (read breakage) I've tried delaying in
    order to fix as many things as possible but now this one patch does far,
    far, far too much. Apologies in advance for breaking your favourite
    backend, but trust me in that the end result will be much better. :)

diff --git a/boilerplate/cairo-boilerplate-test-surfaces.c b/boilerplate/cairo-boilerplate-test-surfaces.c
index 909475b..f7a89a7 100644
--- a/boilerplate/cairo-boilerplate-test-surfaces.c
+++ b/boilerplate/cairo-boilerplate-test-surfaces.c
@@ -30,66 +30,133 @@
 
 #include <cairo-types-private.h>
 
-#include <test-fallback-surface.h>
-#include <test-fallback16-surface.h>
+#include <test-compositor-surface.h>
+#include <test-null-compositor-surface.h>
 #if CAIRO_HAS_TEST_PAGINATED_SURFACE
 #include <test-paginated-surface.h>
 #endif
-#if CAIRO_HAS_TEST_NULL_SURFACE
-#include <test-null-surface.h>
-#endif
-#if CAIRO_HAS_TEST_WRAPPING_SURFACE
-#include <test-wrapping-surface.h>
-#endif
 
 static cairo_surface_t *
-_cairo_boilerplate_test_fallback_create_surface (const char		   *name,
-						 cairo_content_t	    content,
-						 double 		    width,
-						 double 		    height,
-						 double 		    max_width,
-						 double 		    max_height,
-						 cairo_boilerplate_mode_t   mode,
-						 int			    id,
-						 void			  **closure)
+_cairo_boilerplate_test_base_compositor_create_surface (const char		   *name,
+							cairo_content_t	    content,
+							double		    width,
+							double		    height,
+							double		    max_width,
+							double		    max_height,
+							cairo_boilerplate_mode_t mode,
+							int			    id,
+							void		  **closure)
 {
     *closure = NULL;
-    return _cairo_test_fallback_surface_create (content,
-						ceil (width), ceil (height));
+    return _cairo_test_base_compositor_surface_create (content, ceil (width), ceil (height));
 }
 
+
 static cairo_surface_t *
-_cairo_boilerplate_test_fallback16_create_surface (const char		     *name,
-						   cairo_content_t	      content,
-						   double		      width,
-						   double		      height,
-						   double		      max_width,
-						   double		      max_height,
-						   cairo_boilerplate_mode_t   mode,
-						   int			      id,
-						   void 		    **closure)
+_cairo_boilerplate_test_fallback_compositor_create_surface (const char		   *name,
+							    cairo_content_t	    content,
+							    double		    width,
+							    double		    height,
+							    double		    max_width,
+							    double		    max_height,
+							    cairo_boilerplate_mode_t mode,
+							    int			    id,
+							    void		  **closure)
 {
     *closure = NULL;
-    return _cairo_test_fallback16_surface_create (content,
-						  ceil (width), ceil (height));
+    return _cairo_test_fallback_compositor_surface_create (content, ceil (width), ceil (height));
 }
 
-#if CAIRO_HAS_TEST_NULL_SURFACE
 static cairo_surface_t *
-_cairo_boilerplate_test_null_create_surface (const char 	       *name,
-					     cairo_content_t		content,
-					     double			width,
-					     double			height,
-					     double			max_width,
-					     double			max_height,
-					     cairo_boilerplate_mode_t	mode,
-					     int			id,
-					     void		      **closure)
+_cairo_boilerplate_test_mask_compositor_create_surface (const char		   *name,
+							 cairo_content_t	    content,
+							 double			    width,
+							 double			    height,
+							 double			    max_width,
+							 double			    max_height,
+							 cairo_boilerplate_mode_t   mode,
+							 int			    id,
+							 void			  **closure)
 {
     *closure = NULL;
-    return _cairo_test_null_surface_create (content);
+    return _cairo_test_mask_compositor_surface_create (content, ceil (width), ceil (height));
+}
+
+
+static cairo_surface_t *
+_cairo_boilerplate_test_traps_compositor_create_surface (const char		   *name,
+							 cairo_content_t	    content,
+							 double			    width,
+							 double			    height,
+							 double			    max_width,
+							 double			    max_height,
+							 cairo_boilerplate_mode_t   mode,
+							 int			    id,
+							 void			  **closure)
+{
+    *closure = NULL;
+    return _cairo_test_traps_compositor_surface_create (content, ceil (width), ceil (height));
+}
+
+static cairo_surface_t *
+_cairo_boilerplate_test_spans_compositor_create_surface (const char		   *name,
+							 cairo_content_t	    content,
+							 double			    width,
+							 double			    height,
+							 double			    max_width,
+							 double			    max_height,
+							 cairo_boilerplate_mode_t   mode,
+							 int			    id,
+							 void			  **closure)
+{
+    *closure = NULL;
+    return _cairo_test_spans_compositor_surface_create (content, ceil (width), ceil (height));
+}
+
+static cairo_surface_t *
+_cairo_boilerplate_test_no_fallback_compositor_create_surface (const char		   *name,
+							       cairo_content_t	    content,
+							       double			    width,
+							       double			    height,
+							       double			    max_width,
+							       double			    max_height,
+							       cairo_boilerplate_mode_t   mode,
+							       int			    id,
+							       void			  **closure)
+{
+    *closure = NULL;
+    return _cairo_test_no_fallback_compositor_surface_create (content, ceil (width), ceil (height));
+}
+
+static cairo_surface_t *
+_cairo_boilerplate_test_no_traps_compositor_create_surface (const char		   *name,
+							 cairo_content_t	    content,
+							 double			    width,
+							 double			    height,
+							 double			    max_width,
+							 double			    max_height,
+							 cairo_boilerplate_mode_t   mode,
+							 int			    id,
+							 void			  **closure)
+{
+    *closure = NULL;
+    return _cairo_test_no_traps_compositor_surface_create (content, ceil (width), ceil (height));
+}
+
+static cairo_surface_t *
+_cairo_boilerplate_test_no_spans_compositor_create_surface (const char		   *name,
+							 cairo_content_t	    content,
+							 double			    width,
+							 double			    height,
+							 double			    max_width,
+							 double			    max_height,
+							 cairo_boilerplate_mode_t   mode,
+							 int			    id,
+							 void			  **closure)
+{
+    *closure = NULL;
+    return _cairo_test_no_spans_compositor_surface_create (content, ceil (width), ceil (height));
 }
-#endif
 
 #if CAIRO_HAS_TEST_PAGINATED_SURFACE
 static const cairo_user_data_key_t test_paginated_closure_key;
@@ -201,40 +268,38 @@ _cairo_boilerplate_test_paginated_cleanup (void *closure)
 }
 #endif
 
-#if CAIRO_HAS_TEST_WRAPPING_SURFACE
-static cairo_surface_t *
-_cairo_boilerplate_test_wrapping_create_surface (const char		   *name,
-						 cairo_content_t	    content,
-						 double 		    width,
-						 double 		    height,
-						 double 		    max_width,
-						 double 		    max_height,
-						 cairo_boilerplate_mode_t   mode,
-						 int			    id,
-						 void			  **closure)
-{
-    cairo_surface_t *target;
-    cairo_surface_t *surface;
-    cairo_format_t format;
-
-    *closure = NULL;
-
-    format = cairo_boilerplate_format_from_content (content);
-    target = cairo_image_surface_create (format, ceil (width), ceil (height));
-    surface = _cairo_test_wrapping_surface_create (target);
-    cairo_surface_destroy (target);
-
-    return surface;
-}
-#endif
-
 static const cairo_boilerplate_target_t targets[] = {
     {
+	"test-base", "image", NULL, NULL,
+	CAIRO_SURFACE_TYPE_IMAGE,
+	CAIRO_CONTENT_COLOR_ALPHA, 0,
+	"_cairo_test_base_compositor_surface_create",
+	_cairo_boilerplate_test_base_compositor_create_surface,
+	cairo_surface_create_similar,
+	NULL, NULL,
+	_cairo_boilerplate_get_image_surface,
+	cairo_surface_write_to_png,
+	NULL, NULL, NULL, TRUE, FALSE, FALSE
+    },
+    {
+	"test-base", "image", NULL, NULL,
+	CAIRO_SURFACE_TYPE_IMAGE,
+	CAIRO_CONTENT_COLOR, 0,
+	"_cairo_test_base_compositor_surface_create",
+	_cairo_boilerplate_test_base_compositor_create_surface,
+	cairo_surface_create_similar,
+	NULL, NULL,
+	_cairo_boilerplate_get_image_surface,
+	cairo_surface_write_to_png,
+	NULL, NULL, NULL, FALSE, FALSE, FALSE
+    },
+
+    {
 	"test-fallback", "image", NULL, NULL,
-	CAIRO_INTERNAL_SURFACE_TYPE_TEST_FALLBACK,
+	CAIRO_SURFACE_TYPE_IMAGE,
 	CAIRO_CONTENT_COLOR_ALPHA, 0,
-	"_cairo_test_fallback_surface_create",
-	_cairo_boilerplate_test_fallback_create_surface,
+	"_cairo_test_fallback_compositor_surface_create",
+	_cairo_boilerplate_test_fallback_compositor_create_surface,
 	cairo_surface_create_similar,
 	NULL, NULL,
 	_cairo_boilerplate_get_image_surface,
@@ -243,40 +308,128 @@ static const cairo_boilerplate_target_t targets[] = {
     },
     {
 	"test-fallback", "image", NULL, NULL,
-	CAIRO_INTERNAL_SURFACE_TYPE_TEST_FALLBACK,
+	CAIRO_SURFACE_TYPE_IMAGE,
 	CAIRO_CONTENT_COLOR, 0,
-	"_cairo_test_fallback_surface_create",
-	_cairo_boilerplate_test_fallback_create_surface,
+	"_cairo_test_fallback_compositor_surface_create",
+	_cairo_boilerplate_test_fallback_compositor_create_surface,
 	cairo_surface_create_similar,
 	NULL, NULL,
 	_cairo_boilerplate_get_image_surface,
 	cairo_surface_write_to_png,
 	NULL, NULL, NULL, FALSE, FALSE, FALSE
     },
+
     {
-	"test-fallback16", "image", NULL, NULL,
-	CAIRO_INTERNAL_SURFACE_TYPE_TEST_FALLBACK,
+	"test-mask", "mask", NULL, NULL,
+	CAIRO_SURFACE_TYPE_IMAGE,
 	CAIRO_CONTENT_COLOR_ALPHA, 0,
-	"_cairo_test_fallback16_surface_create",
-	_cairo_boilerplate_test_fallback16_create_surface,
+	"_cairo_test_traps_compositor_surface_create",
+	_cairo_boilerplate_test_mask_compositor_create_surface,
 	cairo_surface_create_similar,
 	NULL, NULL,
-	NULL, /* _cairo_boilerplate_get_image_surface, */
+	_cairo_boilerplate_get_image_surface,
+	cairo_surface_write_to_png,
+	NULL, NULL, NULL, TRUE, FALSE, FALSE
+    },
+    {
+	"test-mask", "mask", NULL, NULL,
+	CAIRO_SURFACE_TYPE_IMAGE,
+	CAIRO_CONTENT_COLOR, 0,
+	"_cairo_test_mask_compositor_surface_create",
+	_cairo_boilerplate_test_mask_compositor_create_surface,
+	cairo_surface_create_similar,
+	NULL, NULL,
+	_cairo_boilerplate_get_image_surface,
 	cairo_surface_write_to_png,
 	NULL, NULL, NULL, FALSE, FALSE, FALSE
     },
+
     {
-	"test-fallback16", "image", NULL, NULL,
-	CAIRO_INTERNAL_SURFACE_TYPE_TEST_FALLBACK,
+	"test-traps", "traps", NULL, NULL,
+	CAIRO_SURFACE_TYPE_IMAGE,
+	CAIRO_CONTENT_COLOR_ALPHA, 0,
+	"_cairo_test_traps_compositor_surface_create",
+	_cairo_boilerplate_test_traps_compositor_create_surface,
+	cairo_surface_create_similar,
+	NULL, NULL,
+	_cairo_boilerplate_get_image_surface,
+	cairo_surface_write_to_png,
+	NULL, NULL, NULL, TRUE, FALSE, FALSE
+    },
+    {
+	"test-traps", "traps", NULL, NULL,
+	CAIRO_SURFACE_TYPE_IMAGE,
 	CAIRO_CONTENT_COLOR, 0,
-	"_cairo_test_fallback16_surface_create",
-	_cairo_boilerplate_test_fallback16_create_surface,
+	"_cairo_test_traps_compositor_surface_create",
+	_cairo_boilerplate_test_traps_compositor_create_surface,
+	cairo_surface_create_similar,
+	NULL, NULL,
+	_cairo_boilerplate_get_image_surface,
+	cairo_surface_write_to_png,
+	NULL, NULL, NULL, FALSE, FALSE, FALSE
+    },
+
+    {
+	"test-spans", "spans", NULL, NULL,
+	CAIRO_SURFACE_TYPE_IMAGE,
+	CAIRO_CONTENT_COLOR_ALPHA, 0,
+	"_cairo_test_spans_compositor_surface_create",
+	_cairo_boilerplate_test_spans_compositor_create_surface,
+	cairo_surface_create_similar,
+	NULL, NULL,
+	_cairo_boilerplate_get_image_surface,
+	cairo_surface_write_to_png,
+	NULL, NULL, NULL, TRUE, FALSE, FALSE
+    },
+    {
+	"test-spans", "spans", NULL, NULL,
+	CAIRO_SURFACE_TYPE_IMAGE,
+	CAIRO_CONTENT_COLOR, 0,
+	"_cairo_test_spans_compositor_surface_create",
+	_cairo_boilerplate_test_spans_compositor_create_surface,
+	cairo_surface_create_similar,
+	NULL, NULL,
+	_cairo_boilerplate_get_image_surface,
+	cairo_surface_write_to_png,
+	NULL, NULL, NULL, FALSE, FALSE, FALSE
+    },
+
+    {
+	"no-fallback", "image", NULL, NULL,
+	CAIRO_SURFACE_TYPE_IMAGE,
+	CAIRO_CONTENT_COLOR_ALPHA, 0,
+	"_cairo_test_no_fallback_compositor_surface_create",
+	_cairo_boilerplate_test_no_fallback_compositor_create_surface,
 	cairo_surface_create_similar,
 	NULL, NULL,
-	NULL, /* _cairo_boilerplate_get_image_surface, */
+	_cairo_boilerplate_get_image_surface,
 	cairo_surface_write_to_png,
 	NULL, NULL, NULL, FALSE, FALSE, FALSE
     },
+    {
+	"no-traps", "traps", NULL, NULL,
+	CAIRO_SURFACE_TYPE_IMAGE,
+	CAIRO_CONTENT_COLOR_ALPHA, 0,
+	"_cairo_test_no_traps_compositor_surface_create",
+	_cairo_boilerplate_test_no_traps_compositor_create_surface,
+	cairo_surface_create_similar,
+	NULL, NULL,
+	_cairo_boilerplate_get_image_surface,
+	cairo_surface_write_to_png,
+	NULL, NULL, NULL, TRUE, FALSE, FALSE
+    },
+    {
+	"no-spans", "spans", NULL, NULL,
+	CAIRO_SURFACE_TYPE_IMAGE,
+	CAIRO_CONTENT_COLOR_ALPHA, 0,
+	"_cairo_test_no_spans_compositor_surface_create",
+	_cairo_boilerplate_test_no_spans_compositor_create_surface,
+	cairo_surface_create_similar,
+	NULL, NULL,
+	_cairo_boilerplate_get_image_surface,
+	cairo_surface_write_to_png,
+	NULL, NULL, NULL, TRUE, FALSE, FALSE
+    },
 #if CAIRO_HAS_TEST_PAGINATED_SURFACE
     {
 	"test-paginated", "image", NULL, NULL,
@@ -305,33 +458,5 @@ static const cairo_boilerplate_target_t targets[] = {
 	NULL, NULL, FALSE, TRUE, FALSE
     },
 #endif
-#if CAIRO_HAS_TEST_WRAPPING_SURFACE
-    {
-	"test-wrapping", "image", NULL, NULL,
-	CAIRO_INTERNAL_SURFACE_TYPE_TEST_WRAPPING,
-	CAIRO_CONTENT_COLOR_ALPHA, 0,
-	"_cairo_test_wrapping_surface_create",
-	_cairo_boilerplate_test_wrapping_create_surface,
-	cairo_surface_create_similar,
-	NULL, NULL,
-	_cairo_boilerplate_get_image_surface,
-	cairo_surface_write_to_png,
-	NULL, NULL, NULL, FALSE, FALSE, FALSE
-    },
-#endif
-#if CAIRO_HAS_TEST_NULL_SURFACE
-    {
-	"null", "image", NULL, NULL,
-	CAIRO_INTERNAL_SURFACE_TYPE_NULL,
-	CAIRO_CONTENT_COLOR_ALPHA, 0,
-	"_cairo_test_null_surface_create",
-	_cairo_boilerplate_test_null_create_surface,
-	cairo_surface_create_similar,
-	NULL, NULL,
-	NULL, NULL, NULL,
-	NULL, NULL,
-	TRUE, TRUE, FALSE
-    },
-#endif
 };
 CAIRO_BOILERPLATE (test, targets)
diff --git a/boilerplate/cairo-boilerplate-xlib.c b/boilerplate/cairo-boilerplate-xlib.c
index 6818caf..cad2884 100644
--- a/boilerplate/cairo-boilerplate-xlib.c
+++ b/boilerplate/cairo-boilerplate-xlib.c
@@ -31,7 +31,6 @@
 #if CAIRO_HAS_XLIB_XRENDER_SURFACE
 #include <cairo-xlib-xrender.h>
 #endif
-#include <cairo-xlib-surface-private.h>
 
 #include <X11/Xutil.h> /* for XDestroyImage */
 
@@ -412,6 +411,7 @@ _cairo_boilerplate_xlib_window_create_surface (const char		 *name,
 cairo_status_t
 cairo_boilerplate_xlib_surface_disable_render (cairo_surface_t *abstract_surface)
 {
+#if 0
     /* The following stunt doesn't work with xlib-xcb because it doesn't use
      * cairo_xlib_surface_t for its surfaces. Sadly, there is no sane
      * alternative, so we can't disable render with xlib-xcb.
@@ -440,6 +440,7 @@ cairo_boilerplate_xlib_surface_disable_render (cairo_surface_t *abstract_surface
     surface->buggy_repeat = TRUE;
 #endif
 #endif
+#endif
 
     return CAIRO_STATUS_SUCCESS;
 }
diff --git a/boilerplate/cairo-boilerplate.c b/boilerplate/cairo-boilerplate.c
index 229c4c7..8e252f5 100644
--- a/boilerplate/cairo-boilerplate.c
+++ b/boilerplate/cairo-boilerplate.c
@@ -683,16 +683,12 @@ cairo_boilerplate_get_image_target (cairo_content_t content)
     if (cairo_boilerplate_targets == NULL)
 	_cairo_boilerplate_register_all ();
 
-    for (list = cairo_boilerplate_targets; list != NULL; list = list->next) {
-	const cairo_boilerplate_target_t *target = list->target;
-	if (target->expected_type == CAIRO_SURFACE_TYPE_IMAGE &&
-	    target->content == content)
-	{
-	    return target;
-	}
+    switch (content) {
+    default:
+    case CAIRO_CONTENT_ALPHA: return NULL;
+    case CAIRO_CONTENT_COLOR: return &builtin_targets[1];
+    case CAIRO_CONTENT_COLOR_ALPHA: return &builtin_targets[0];
     }
-
-    return NULL;
 }
 
 const cairo_boilerplate_target_t *
diff --git a/configure.ac b/configure.ac
index 4b85c8a..5879a44 100644
--- a/configure.ac
+++ b/configure.ac
@@ -202,11 +202,11 @@ CAIRO_ENABLE_SURFACE_BACKEND(skia, Skia, no, [
 	      [skia_DIR="`pwd`/../skia"])
   AC_ARG_WITH([skia-bulid],
 	      [AS_HELP_STRING([--with-skia-build=(Release|Debug)]
-			      [build of skia to link with, default is Relese])],
+			      [build of skia to link with, default is Release])],
 	      [skia_BUILD="$withval"],
 	      [skia_BUILD="Release"])
   skia_NONPKGCONFIG_CFLAGS="-I$skia_DIR/include/config -I$skia_DIR/include/core -I$skia_DIR/include/effects"
-  if test "x$(skia_BUILD)" = x"Relese"; then
+  if test "x$skia_BUILD" = x"Release"; then
   	skia_NONPKGCONFIG_CFLAGS="-DSK_RELEASE -DSK_CAN_USE_FLOAT $skia_NONPKGCONFIG_CFLAGS"
   fi
   skia_NONPKGCONFIG_LIBS="--start-group $skia_DIR/out/$skia_BUILD/obj.target/gyp/libeffects.a $skia_DIR/out/$skia_BUILD/obj.target/gyp/libimages.a $skia_DIR/out/$skia_BUILD/obj.target/gyp/libutils.a $skia_DIR/out/$skia_BUILD/obj.target/gyp/libopts.a $skia_DIR/out/$skia_BUILD/obj.target/gyp/libcore.a -end-group"
diff --git a/perf/Makefile.sources b/perf/Makefile.sources
index b99234b..1fcf148 100644
--- a/perf/Makefile.sources
+++ b/perf/Makefile.sources
@@ -1,5 +1,6 @@
 libcairoperf_sources = \
-	cairo-perf.c	\
+	cairo-perf.c		\
+	cairo-perf-report.c	\
 	cairo-stats.c		\
 	$(NULL)
 
diff --git a/perf/cairo-perf-compare-backends.c b/perf/cairo-perf-compare-backends.c
index 1630637..2cbb24c 100644
--- a/perf/cairo-perf-compare-backends.c
+++ b/perf/cairo-perf-compare-backends.c
@@ -73,7 +73,7 @@ print_change_bar (double change,
 		  double max_change,
 		  int	 use_utf)
 {
-    int units_per_cell = (int) ceil (max_change / CHANGE_BAR_WIDTH);
+    int units_per_cell = ceil (max_change / CHANGE_BAR_WIDTH);
     static char const *ascii_boxes[8] = {
 	"****","***" ,"***", "**",
 	"**",  "*",   "*",   ""
@@ -369,7 +369,7 @@ main (int	  argc,
     if (args.num_filenames) {
 	reports = xcalloc (args.num_filenames, sizeof (cairo_perf_report_t));
 	for (i = 0; i < args.num_filenames; i++) {
-	    cairo_perf_report_load (&reports[i], args.filenames[i],
+	    cairo_perf_report_load (&reports[i], args.filenames[i], i,
 				    test_report_cmp_name);
 	    printf ("loaded: %s, %d tests\n",
 		    args.filenames[i], reports[i].tests_count);
@@ -377,7 +377,7 @@ main (int	  argc,
     } else {
 	args.num_filenames = 1;
 	reports = xcalloc (args.num_filenames, sizeof (cairo_perf_report_t));
-	cairo_perf_report_load (&reports[0], NULL, test_report_cmp_name);
+	cairo_perf_report_load (&reports[0], NULL, 0, test_report_cmp_name);
     }
 
     cairo_perf_reports_compare (reports, args.num_filenames, &args.options);
diff --git a/perf/cairo-perf-diff-files.c b/perf/cairo-perf-diff-files.c
index 34311b0..0850927 100644
--- a/perf/cairo-perf-diff-files.c
+++ b/perf/cairo-perf-diff-files.c
@@ -161,16 +161,14 @@ test_diff_print_binary (test_diff_t		    *diff,
     else
 	printf ("%5s %26s", diff->tests[0]->backend, diff->tests[0]->name);
 
-    if (diff->tests[0]->size) {
-	printf ("  %6.2f (%.2f %4.2f%%) -> %6.2f (%.2f %4.2f%%): %5.2fx ",
-		diff->tests[0]->stats.min_ticks / diff->tests[0]->stats.ticks_per_ms,
-		diff->tests[0]->stats.median_ticks / diff->tests[0]->stats.ticks_per_ms,
-		diff->tests[0]->stats.std_dev * 100,
-		diff->tests[1]->stats.min_ticks / diff->tests[1]->stats.ticks_per_ms,
-		diff->tests[1]->stats.median_ticks / diff->tests[1]->stats.ticks_per_ms,
-		diff->tests[1]->stats.std_dev * 100,
-		fabs (diff->change));
-    }
+    printf ("  %6.2f (%.2f %4.2f%%) -> %6.2f (%.2f %4.2f%%): %5.2fx ",
+	    diff->tests[0]->stats.min_ticks / diff->tests[0]->stats.ticks_per_ms,
+	    diff->tests[0]->stats.median_ticks / diff->tests[0]->stats.ticks_per_ms,
+	    diff->tests[0]->stats.std_dev * 100,
+	    diff->tests[1]->stats.min_ticks / diff->tests[1]->stats.ticks_per_ms,
+	    diff->tests[1]->stats.median_ticks / diff->tests[1]->stats.ticks_per_ms,
+	    diff->tests[1]->stats.std_dev * 100,
+	    fabs (diff->change));
 
     if (diff->change > 1.0)
 	printf ("speedup\n");
@@ -191,24 +189,32 @@ test_diff_print_multi (test_diff_t		   *diff,
     double test_time;
     double change;
 
-    printf ("%s (backend: %s-%s, size: %d)\n",
-	    diff->tests[0]->name,
-	    diff->tests[0]->backend,
-	    diff->tests[0]->content,
-	    diff->tests[0]->size);
+    if (diff->tests[0]->size) {
+	printf ("%s (backend: %s-%s, size: %d)\n",
+		diff->tests[0]->name,
+		diff->tests[0]->backend,
+		diff->tests[0]->content,
+		diff->tests[0]->size);
+    } else {
+	printf ("%s (backend: %s)\n",
+		diff->tests[0]->name,
+		diff->tests[0]->backend);
+    }
 
     for (i = 0; i < diff->num_tests; i++) {
 	test_time = diff->tests[i]->stats.min_ticks;
 	if (! options->use_ticks)
 	    test_time /= diff->tests[i]->stats.ticks_per_ms;
 	change = diff->max / test_time;
-	printf ("%8s %6.2f: %5.2fx ",
-		diff->tests[i]->configuration,
+	printf ("[%d] %6.2f: %5.2fx ",
+		diff->tests[i]->fileno,
 		diff->tests[i]->stats.min_ticks / diff->tests[i]->stats.ticks_per_ms,
 		change);
 
 	if (options->print_change_bars)
 	    print_change_bar (change, max_change, options->use_utf);
+	else
+	    printf("\n");
     }
 
     printf("\n");
@@ -476,8 +482,11 @@ main (int	  argc,
 
     reports = xmalloc (args.num_filenames * sizeof (cairo_perf_report_t));
 
-    for (i = 0; i < args.num_filenames; i++ )
-	cairo_perf_report_load (&reports[i], args.filenames[i], NULL);
+    for (i = 0; i < args.num_filenames; i++ ) {
+	cairo_perf_report_load (&reports[i], args.filenames[i], i, NULL);
+	printf ("[%d] %s\n", i, args.filenames[i]);
+    }
+    printf ("\n");
 
     cairo_perf_reports_compare (reports, args.num_filenames, &args.options);
 
diff --git a/perf/cairo-perf-micro.c b/perf/cairo-perf-micro.c
index 096986b..f3c6f8d 100644
--- a/perf/cairo-perf-micro.c
+++ b/perf/cairo-perf-micro.c
@@ -50,12 +50,13 @@
 
 #define CAIRO_PERF_ITERATIONS_DEFAULT		100
 #define CAIRO_PERF_LOW_STD_DEV			0.03
-#define CAIRO_PERF_STABLE_STD_DEV_COUNT 	5
-#define CAIRO_PERF_ITERATION_MS_DEFAULT 	2000
+#define CAIRO_PERF_STABLE_STD_DEV_COUNT		5
+#define CAIRO_PERF_ITERATION_MS_DEFAULT		2000
 #define CAIRO_PERF_ITERATION_MS_FAST		5
 
 typedef struct _cairo_perf_case {
-    CAIRO_PERF_DECL (*run);
+    CAIRO_PERF_RUN_DECL (*run);
+    cairo_bool_t (*enabled) (cairo_perf_t *perf);
     unsigned int min_size;
     unsigned int max_size;
 } cairo_perf_case_t;
@@ -251,7 +252,7 @@ cairo_perf_run (cairo_perf_t	   *perf,
 					       cairo_boilerplate_content (perf->target->content));
 	    else
 		cairo_save (perf->cr);
-	    times[i] = perf_func (perf->cr, perf->size, perf->size, loops) / loops;
+	    times[i] = perf_func (perf->cr, perf->size, perf->size, loops) ;
 	    if (similar)
 		cairo_pattern_destroy (cairo_pop_group (perf->cr));
 	    else
@@ -263,7 +264,7 @@ cairo_perf_run (cairo_perf_t	   *perf,
 			    _content_to_string (perf->target->content, similar),
 			    name, perf->size,
 			    _cairo_time_to_double (_cairo_time_from_s (1.)) / 1000.);
-		printf (" %lld", (long long) times[i]);
+		printf (" %lld", (long long) (times[i] / (double) loops));
 	    } else if (! perf->exact_iterations) {
 		if (i > 0) {
 		    _cairo_stats_compute (&stats, times, i+1);
@@ -287,18 +288,18 @@ cairo_perf_run (cairo_perf_t	   *perf,
 	    if (count_func != NULL) {
 		double count = count_func (perf->cr, perf->size, perf->size);
 		fprintf (perf->summary,
-			 "%10lld %#8.3f %#8.3f %#5.2f%% %3d: %.2f\n",
-			 (long long) stats.min_ticks,
-			 _cairo_time_to_s (stats.min_ticks) * 1000.0,
-			 _cairo_time_to_s (stats.median_ticks) * 1000.0,
+			 "%10lld/%d %#8.3f %#8.3f %#5.2f%% %3d: %.2f\n",
+			 (long long) stats.min_ticks, loops,
+			 _cairo_time_to_s (stats.min_ticks) * 1000.0 / loops,
+			 _cairo_time_to_s (stats.median_ticks) * 1000.0 / loops,
 			 stats.std_dev * 100.0, stats.iterations,
 			 count / _cairo_time_to_s (stats.min_ticks));
 	    } else {
 		fprintf (perf->summary,
-			 "%10lld %#8.3f %#8.3f %#5.2f%% %3d\n",
-			 (long long) stats.min_ticks,
-			 _cairo_time_to_s (stats.min_ticks) * 1000.0,
-			 _cairo_time_to_s (stats.median_ticks) * 1000.0,
+			 "%10lld/%d %#8.3f %#8.3f %#5.2f%% %3d\n",
+			 (long long) stats.min_ticks, loops,
+			 _cairo_time_to_s (stats.min_ticks) * 1000.0 / loops,
+			 _cairo_time_to_s (stats.median_ticks) * 1000.0 / loops,
 			 stats.std_dev * 100.0, stats.iterations);
 	    }
 	    fflush (perf->summary);
@@ -491,6 +492,9 @@ main (int   argc,
 	for (j = 0; perf_cases[j].run; j++) {
 	    const cairo_perf_case_t *perf_case = &perf_cases[j];
 
+	    if (! perf_case->enabled (&perf))
+		continue;
+
 	    for (perf.size = perf_case->min_size;
 		 perf.size <= perf_case->max_size;
 		 perf.size *= 2)
@@ -536,42 +540,48 @@ main (int   argc,
     return 0;
 }
 
+#define FUNC(f) f, f##_enabled
 const cairo_perf_case_t perf_cases[] = {
-    { paint,  64, 512},
-    { paint_with_alpha,  64, 512},
-    { fill,   64, 512},
-    { stroke, 64, 512},
-    { text,   64, 512},
-    { glyphs, 64, 512},
-    { mask,   64, 512},
-    { line,  32, 512},
-    { curve,  32, 512},
-    { disjoint,   64, 512},
-    { hatching,   64, 512},
-    { tessellate, 100, 100},
-    { subimage_copy, 16, 512},
-    { hash_table, 16, 16},
-    { pattern_create_radial, 16, 16},
-    { zrusin, 415, 415},
-    { world_map, 800, 800},
-    { box_outline, 100, 100},
-    { mosaic, 800, 800 },
-    { long_lines, 100, 100},
-    { unaligned_clip, 100, 100},
-    { rectangles, 512, 512},
-    { rounded_rectangles, 512, 512},
-    { long_dashed_lines, 512, 512},
-    { composite_checker, 16, 512},
-    { twin, 800, 800},
-    { dragon, 1024, 1024 },
-    { pythagoras_tree, 768, 768 },
-    { intersections, 512, 512 },
-    { many_strokes, 32, 512 },
-    { wide_strokes, 32, 512 },
-    { many_fills, 32, 512 },
-    { wide_fills, 32, 512 },
-    { many_curves, 32, 512 },
-    { spiral, 512, 512 },
-    { wave, 500, 500 },
+    { FUNC(pixel),  1, 1 },
+    { FUNC(paint),  64, 512},
+    { FUNC(paint_with_alpha),  64, 512},
+    { FUNC(fill),   64, 512},
+    { FUNC(stroke), 64, 512},
+    { FUNC(text),   64, 512},
+    { FUNC(glyphs), 64, 512},
+    { FUNC(mask),   64, 512},
+    { FUNC(line),  32, 512},
+    { FUNC(a1_line),  32, 512},
+    { FUNC(curve),  32, 512},
+    { FUNC(a1_curve),  32, 512},
+    { FUNC(disjoint),   64, 512},
+    { FUNC(hatching),   64, 512},
+    { FUNC(tessellate), 100, 100},
+    { FUNC(subimage_copy), 16, 512},
+    { FUNC(hash_table), 16, 16},
+    { FUNC(pattern_create_radial), 16, 16},
+    { FUNC(zrusin), 415, 415},
+    { FUNC(world_map), 800, 800},
+    { FUNC(box_outline), 100, 100},
+    { FUNC(mosaic), 800, 800 },
+    { FUNC(long_lines), 100, 100},
+    { FUNC(unaligned_clip), 100, 100},
+    { FUNC(rectangles), 512, 512},
+    { FUNC(rounded_rectangles), 512, 512},
+    { FUNC(long_dashed_lines), 512, 512},
+    { FUNC(composite_checker), 16, 512},
+    { FUNC(twin), 800, 800},
+    { FUNC(dragon), 1024, 1024 },
+    { FUNC(sierpinski), 32, 1024 },
+    { FUNC(pythagoras_tree), 768, 768 },
+    { FUNC(intersections), 512, 512 },
+    { FUNC(many_strokes), 32, 512 },
+    { FUNC(wide_strokes), 32, 512 },
+    { FUNC(many_fills), 32, 512 },
+    { FUNC(wide_fills), 32, 512 },
+    { FUNC(many_curves), 32, 512 },
+    { FUNC(spiral), 512, 512 },
+    { FUNC(wave), 500, 500 },
+    { FUNC(fill_clip), 16, 512 },
     { NULL }
 };
diff --git a/perf/cairo-perf-report.c b/perf/cairo-perf-report.c
index fcce0e0..8df78c6 100644
--- a/perf/cairo-perf-report.c
+++ b/perf/cairo-perf-report.c
@@ -110,6 +110,7 @@ do {									\
 
 static test_report_status_t
 test_report_parse (test_report_t *report,
+		   int fileno,
 		   char 	 *line,
 		   char 	 *configuration)
 {
@@ -137,6 +138,7 @@ test_report_parse (test_report_t *report,
 
     skip_space ();
 
+    report->fileno = fileno;
     report->configuration = configuration;
     parse_string (report->backend);
     end = strrchr (report->backend, '.');
@@ -369,7 +371,7 @@ cairo_perf_report_sort_and_compute_stats (cairo_perf_report_t *report,
 
 void
 cairo_perf_report_load (cairo_perf_report_t *report,
-			const char *filename,
+			const char *filename, int id,
 			int (*cmp) (const void *, const void *))
 {
     FILE *file;
@@ -401,6 +403,7 @@ cairo_perf_report_load (cairo_perf_report_t *report,
     report->tests_size = 16;
     report->tests = xmalloc (report->tests_size * sizeof (test_report_t));
     report->tests_count = 0;
+    report->fileno = id;
 
     if (filename == NULL) {
 	file = stdin;
@@ -425,7 +428,7 @@ cairo_perf_report_load (cairo_perf_report_t *report,
 	    break;
 
 	status = test_report_parse (&report->tests[report->tests_count],
-				    line, report->configuration);
+				    id, line, report->configuration);
 	if (status == TEST_REPORT_STATUS_ERROR)
 	    fprintf (stderr, "Ignoring unrecognized line %d of %s:\n%s",
 		     line_number, filename, line);
diff --git a/perf/cairo-perf-trace.c b/perf/cairo-perf-trace.c
index 2cef2b1..8e637a7 100644
--- a/perf/cairo-perf-trace.c
+++ b/perf/cairo-perf-trace.c
@@ -79,7 +79,7 @@ basename_no_ext (char *path)
 
     name = basename (path);
 
-    dot = strchr (name, '.');
+    dot = strrchr (name, '.');
     if (dot)
 	*dot = '\0';
 
@@ -108,6 +108,7 @@ struct trace {
     void            *closure;
     cairo_surface_t *surface;
     cairo_bool_t observe;
+    int tile_size;
 };
 
 cairo_bool_t
@@ -132,7 +133,7 @@ cairo_perf_can_run (cairo_perf_t *perf,
 	return TRUE;
 
     copy = xstrdup (name);
-    dot = strchr (copy, '.');
+    dot = strrchr (copy, '.');
     if (dot != NULL)
 	*dot = '\0';
 
@@ -435,6 +436,7 @@ parse_options (cairo_perf_t *perf,
     perf->raw = FALSE;
     perf->observe = FALSE;
     perf->list_only = FALSE;
+    perf->tile_size = 0;
     perf->names = NULL;
     perf->num_names = 0;
     perf->summary = stdout;
@@ -443,7 +445,7 @@ parse_options (cairo_perf_t *perf,
     perf->num_exclude_names = 0;
 
     while (1) {
-	c = _cairo_getopt (argc, argv, "i:x:lsrvc");
+	c = _cairo_getopt (argc, argv, "t:i:x:lsrvc");
 	if (c == -1)
 	    break;
 
@@ -457,6 +459,14 @@ parse_options (cairo_perf_t *perf,
 		exit (1);
 	    }
 	    break;
+	case 't':
+	    perf->tile_size = strtoul (optarg, &end, 10);
+	    if (*end != '\0') {
+		fprintf (stderr, "Invalid argument for -t (not an integer): %s\n",
+			 optarg);
+		exit (1);
+	    }
+	    break;
 	case 'l':
 	    perf->list_only = TRUE;
 	    break;
@@ -489,6 +499,11 @@ parse_options (cairo_perf_t *perf,
 	}
     }
 
+    if (perf->observe && perf->tile_size) {
+	fprintf (stderr, "Can't mix observer and tiling. Sorry.\n");
+	exit (1);
+    }
+
     if (verbose && perf->summary == NULL)
 	perf->summary = stderr;
 #if HAVE_UNISTD_H
@@ -536,6 +551,79 @@ have_trace_filenames (cairo_perf_t *perf)
 }
 
 static void
+_tiling_surface_finish (cairo_surface_t *observer,
+			cairo_surface_t *target,
+			void *closure)
+{
+    struct trace *args = closure;
+    cairo_surface_t *surface;
+    cairo_content_t content;
+    cairo_rectangle_t r;
+    int width, height;
+    int x, y, w, h;
+
+    cairo_recording_surface_get_extents (target, &r);
+    w = r.width;
+    h = r.height;
+
+    content = cairo_surface_get_content (target);
+
+    for (y = 0; y < h; y += args->tile_size) {
+	height = args->tile_size;
+	if (y + height > h)
+	    height = h - y;
+
+	for (x = 0; x < w; x += args->tile_size) {
+	    cairo_t *cr;
+
+	    width = args->tile_size;
+	    if (x + width > w)
+		width = w - x;
+
+	    /* XXX to correctly observe the playback we would need
+	     * to replay the target onto the observer directly.
+	     */
+	    surface = args->target->create_similar (args->surface,
+						    content, width, height);
+
+	    cr = cairo_create (surface);
+	    cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
+	    cairo_set_source_surface (cr, target, -x, -y);
+	    cairo_paint (cr);
+	    cairo_destroy (cr);
+
+	    cairo_surface_destroy (surface);
+	}
+    }
+}
+
+static cairo_surface_t *
+_tiling_surface_create (void		 *closure,
+			cairo_content_t  content,
+			double		  width,
+			double		  height,
+			long		  uid)
+{
+    cairo_rectangle_t r;
+    cairo_surface_t *surface, *observer;
+
+    r.x = r.y = 0;
+    r.width = width;
+    r.height = height;
+
+    surface = cairo_recording_surface_create (content, &r);
+    observer = cairo_surface_create_observer (surface,
+					      CAIRO_SURFACE_OBSERVER_NORMAL);
+    cairo_surface_destroy (surface);
+
+    cairo_surface_observer_add_finish_callback (observer,
+						_tiling_surface_finish,
+						closure);
+
+    return observer;
+}
+
+static void
 cairo_perf_trace (cairo_perf_t			   *perf,
 		  const cairo_boilerplate_target_t *target,
 		  const char			   *trace)
@@ -549,7 +637,7 @@ cairo_perf_trace (cairo_perf_t			   *perf,
     char *trace_cpy, *name;
     const cairo_script_interpreter_hooks_t hooks = {
 	&args,
-	_similar_surface_create,
+	perf->tile_size ? _tiling_surface_create : _similar_surface_create,
 	NULL, /* surface_destroy */
 	_context_create,
 	NULL, /* context_destroy */
@@ -557,6 +645,7 @@ cairo_perf_trace (cairo_perf_t			   *perf,
 	NULL /* copy_page */
     };
 
+    args.tile_size = perf->tile_size;
     args.observe = perf->observe;
 
     trace_cpy = xstrdup (trace);
@@ -648,26 +737,30 @@ cairo_perf_trace (cairo_perf_t			   *perf,
 	}
 
 	cairo_script_interpreter_run (csi, trace);
+	line_no = cairo_script_interpreter_get_line_number (csi);
+
+	/* Finish before querying timings in case we are using an intermediate
+	 * target and so need to destroy all surfaces before rendering
+	 * commences.
+	 */
+	cairo_script_interpreter_finish (csi);
 
 	if (perf->observe) {
 	    cairo_device_t *observer = cairo_surface_get_device (args.surface);
-	    times[i] = _cairo_time_from_s (1.e9 * cairo_device_observer_elapsed (observer));
-	    paint[i] = _cairo_time_from_s (1.e9 * cairo_device_observer_paint_elapsed (observer));
-	    mask[i] = _cairo_time_from_s (1.e9 * cairo_device_observer_mask_elapsed (observer));
-	    stroke[i] = _cairo_time_from_s (1.e9 * cairo_device_observer_stroke_elapsed (observer));
-	    fill[i] = _cairo_time_from_s (1.e9 * cairo_device_observer_fill_elapsed (observer));
-	    glyphs[i] = _cairo_time_from_s (1.e9 * cairo_device_observer_glyphs_elapsed (observer));
+	    times[i] = _cairo_time_from_s (1.e-9 * cairo_device_observer_elapsed (observer));
+	    paint[i] = _cairo_time_from_s (1.e-9 * cairo_device_observer_paint_elapsed (observer));
+	    mask[i] = _cairo_time_from_s (1.e-9 * cairo_device_observer_mask_elapsed (observer));
+	    stroke[i] = _cairo_time_from_s (1.e-9 * cairo_device_observer_stroke_elapsed (observer));
+	    fill[i] = _cairo_time_from_s (1.e-9 * cairo_device_observer_fill_elapsed (observer));
+	    glyphs[i] = _cairo_time_from_s (1.e-9 * cairo_device_observer_glyphs_elapsed (observer));
 	} else {
 	    clear_surface (args.surface); /* queue a write to the sync'ed surface */
 	    cairo_perf_timer_stop ();
 	    times[i] = cairo_perf_timer_elapsed ();
 	}
 
-	cairo_script_interpreter_finish (csi);
 	scache_clear ();
 
-	line_no = cairo_script_interpreter_get_line_number (csi);
-
 	cairo_surface_destroy (args.surface);
 
 	if (target->cleanup)
@@ -766,28 +859,28 @@ cairo_perf_trace (cairo_perf_t			   *perf,
 	    fprintf (perf->summary,
 		     " %#9.3f", _cairo_time_to_s (stats.median_ticks));
 
-	    _cairo_stats_compute (&stats, paint, i+1);
+	    _cairo_stats_compute (&stats, paint, i);
 	    fprintf (perf->summary,
 		     " %#9.3f", _cairo_time_to_s (stats.median_ticks));
 
-	    _cairo_stats_compute (&stats, mask, i+1);
+	    _cairo_stats_compute (&stats, mask, i);
 	    fprintf (perf->summary,
 		     " %#9.3f", _cairo_time_to_s (stats.median_ticks));
 
-	    _cairo_stats_compute (&stats, fill, i+1);
+	    _cairo_stats_compute (&stats, fill, i);
 	    fprintf (perf->summary,
 		     " %#9.3f", _cairo_time_to_s (stats.median_ticks));
 
-	    _cairo_stats_compute (&stats, stroke, i+1);
+	    _cairo_stats_compute (&stats, stroke, i);
 	    fprintf (perf->summary,
 		     " %#9.3f", _cairo_time_to_s (stats.median_ticks));
 
-	    _cairo_stats_compute (&stats, glyphs, i+1);
+	    _cairo_stats_compute (&stats, glyphs, i);
 	    fprintf (perf->summary,
 		     " %#9.3f", _cairo_time_to_s (stats.median_ticks));
 
 	    fprintf (perf->summary,
-		     " %5d\n", i+1);
+		     " %5d\n", i);
 	} else {
 	    fprintf (perf->summary,
 		     "%#8.3f %#8.3f %#6.2f%% %4d/%d\n",
@@ -807,11 +900,6 @@ out:
 
     perf->test_number++;
     free (trace_cpy);
-
-    cairo_debug_reset_static_data ();
-#if HAVE_FCFINI
-    FcFini ();
-#endif
 }
 
 static void
diff --git a/perf/cairo-perf.h b/perf/cairo-perf.h
index 11c03f7..d6a71cc 100644
--- a/perf/cairo-perf.h
+++ b/perf/cairo-perf.h
@@ -83,6 +83,8 @@ typedef struct _cairo_perf {
     double ms_per_iteration;
     cairo_bool_t fast_and_sloppy;
 
+    unsigned int tile_size;
+
     /* Stuff used internally */
     cairo_time_t *times;
     const cairo_boilerplate_target_t **targets;
@@ -121,6 +123,7 @@ cairo_perf_cover_sources_and_operators (cairo_perf_t	   *perf,
 
 typedef struct _test_report {
     int id;
+    int fileno;
     const char *configuration;
     char *backend;
     char *content;
@@ -149,6 +152,7 @@ typedef struct _test_diff {
 typedef struct _cairo_perf_report {
     char *configuration;
     const char *name;
+    int fileno;
     test_report_t *tests;
     int tests_size;
     int tests_count;
@@ -162,7 +166,7 @@ typedef enum {
 
 void
 cairo_perf_report_load (cairo_perf_report_t *report,
-			const char *filename,
+			const char *filename, int id,
 			int (*cmp) (const void *, const void *));
 
 void
@@ -177,7 +181,10 @@ int
 test_report_cmp_name (const void *a,
 		      const void *b);
 
-#define CAIRO_PERF_DECL(func) void (func) (cairo_perf_t *perf, cairo_t *cr, int width, int height)
+#define CAIRO_PERF_ENABLED_DECL(func) cairo_bool_t (func ## _enabled) (cairo_perf_t *perf)
+#define CAIRO_PERF_RUN_DECL(func) void (func) (cairo_perf_t *perf, cairo_t *cr, int width, int height)
+
+#define CAIRO_PERF_DECL(func) CAIRO_PERF_RUN_DECL(func); CAIRO_PERF_ENABLED_DECL(func)
 
 CAIRO_PERF_DECL (fill);
 CAIRO_PERF_DECL (paint);
@@ -214,6 +221,11 @@ CAIRO_PERF_DECL (many_fills);
 CAIRO_PERF_DECL (wide_fills);
 CAIRO_PERF_DECL (many_curves);
 CAIRO_PERF_DECL (curve);
+CAIRO_PERF_DECL (a1_curve);
 CAIRO_PERF_DECL (line);
+CAIRO_PERF_DECL (a1_line);
+CAIRO_PERF_DECL (pixel);
+CAIRO_PERF_DECL (sierpinski);
+CAIRO_PERF_DECL (fill_clip);
 
 #endif
diff --git a/perf/cairo-stats.c b/perf/cairo-stats.c
index e088e19..c422d6c 100644
--- a/perf/cairo-stats.c
+++ b/perf/cairo-stats.c
@@ -25,16 +25,25 @@
 
 #include "cairo-stats.h"
 
+#include <assert.h>
+
 void
 _cairo_stats_compute (cairo_stats_t *stats,
 		      cairo_time_t  *values,
 		      int	     num_values)
 {
-    int i;
-    cairo_time_t sumtime;
-    double sum, mean, delta, q1, q3, iqr;
-    double outlier_min, outlier_max;
-    int min_valid, num_valid;
+    cairo_time_t sum, mean, delta, q1, q3, iqr;
+    cairo_time_t outlier_min, outlier_max;
+    int i, min_valid, num_valid;
+
+    assert (num_values > 0);
+
+    if (num_values == 1) {
+	stats->min_ticks = stats->median_ticks = values[0];
+	stats->std_dev = 0;
+	stats->iterations = 1;
+	return;
+    }
 
     /* First, identify any outliers, using the definition of "mild
      * outliers" from:
@@ -48,44 +57,35 @@ _cairo_stats_compute (cairo_stats_t *stats,
      */
     qsort (values, num_values, sizeof (cairo_time_t), _cairo_time_cmp);
 
-    q1 = _cairo_time_to_s (values[(1*num_values)/4]);
-    q3 = _cairo_time_to_s (values[(3*num_values)/4]);
+    q1 = values[1*num_values/4];
+    q3 = values[3*num_values/4];
 
+    /* XXX assumes we have native uint64_t */
     iqr = q3 - q1;
+    outlier_min = q1 - 3 * iqr / 2;
+    outlier_max = q3 + 3 * iqr / 2;
 
-    outlier_min = _cairo_time_from_s (q1 - 1.5 * iqr);
-    outlier_max = _cairo_time_from_s (q3 + 1.5 * iqr);
-
-    min_valid = 0;
-    while (min_valid < num_values &&
-	   _cairo_time_to_s (values[min_valid]) < outlier_min)
-    {
-	min_valid++;
-    }
+    for (i = 0; i < num_values && values[i] < outlier_min; i++)
+	;
+    min_valid = i;
 
-    i = min_valid;
-    num_valid = 0;
-    while (i + num_valid < num_values &&
-	   _cairo_time_to_s (values[i+num_valid]) <= outlier_max)
-    {
-	num_valid++;
-    }
+    for (i = 0; i < num_values && values[i] <= outlier_max; i++)
+	;
+    num_valid = i - min_valid;
+    assert(num_valid);
 
     stats->iterations = num_valid;
     stats->min_ticks = values[min_valid];
-
-    sumtime = _cairo_time_from_s (0);
-    for (i = min_valid; i < min_valid + num_valid; i++) {
-	sumtime = _cairo_time_add (sumtime, values[i]);
-	stats->min_ticks = _cairo_time_min (stats->min_ticks, values[i]);
-    }
-
-    mean = _cairo_time_to_s (sumtime) / num_valid;
     stats->median_ticks = values[min_valid + num_valid / 2];
 
-    sum = 0.0;
+    sum = 0;
+    for (i = min_valid; i < min_valid + num_valid; i++)
+	sum = _cairo_time_add (sum, values[i]);
+    mean = sum / num_valid;
+
+    sum = 0;
     for (i = min_valid; i < min_valid + num_valid; i++) {
-	delta = _cairo_time_to_s (values[i]) - mean;
+	delta = values[i] - mean;
 	sum += delta * delta;
     }
 
diff --git a/perf/micro/Makefile.sources b/perf/micro/Makefile.sources
index 0c2bca0..e72d44a 100644
--- a/perf/micro/Makefile.sources
+++ b/perf/micro/Makefile.sources
@@ -7,6 +7,7 @@ libcairo_perf_micro_sources = \
 	hatching.c		\
 	hash-table.c		\
 	line.c			\
+	a1-line.c		\
 	long-lines.c		\
 	mosaic.c		\
 	paint.c			\
@@ -35,7 +36,11 @@ libcairo_perf_micro_sources = \
 	wide-fills.c		\
 	many-curves.c		\
 	curve.c			\
+	a1-curve.c		\
 	spiral.c		\
+	pixel.c			\
+	sierpinski.c		\
+	fill-clip.c		\
 	$(NULL)
 
 libcairo_perf_micro_headers = \
diff --git a/perf/micro/a1-curve.c b/perf/micro/a1-curve.c
new file mode 100644
index 0000000..594c46d
--- /dev/null
+++ b/perf/micro/a1-curve.c
@@ -0,0 +1,112 @@
+/*
+ * Copyright © 2011 Intel 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: Chris Wilson <chris at chris-wilson.co.uk>
+ */
+
+#include "cairo-perf.h"
+
+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 cairo_time_t
+do_curve_stroke (cairo_t *cr, int width, int height, int loops)
+{
+    state = 0xc0ffee;
+    cairo_set_line_width (cr, 2.);
+    cairo_perf_timer_start ();
+
+    while (loops--) {
+	double x1 = uniform_random (0, width);
+	double x2 = uniform_random (0, width);
+	double x3 = uniform_random (0, width);
+	double y1 = uniform_random (0, height);
+	double y2 = uniform_random (0, height);
+	double y3 = uniform_random (0, height);
+	cairo_move_to (cr, uniform_random (0, width), uniform_random (0, height));
+	cairo_curve_to (cr, x1, y1, x2, y2, x3, y3);
+	cairo_stroke(cr);
+    }
+
+    cairo_perf_timer_stop ();
+
+    return cairo_perf_timer_elapsed ();
+}
+
+static cairo_time_t
+do_curve_fill (cairo_t *cr, int width, int height, int loops)
+{
+    state = 0xc0ffee;
+    cairo_perf_timer_start ();
+
+    while (loops--) {
+	double x0 = uniform_random (0, width);
+	double x1 = uniform_random (0, width);
+	double x2 = uniform_random (0, width);
+	double x3 = uniform_random (0, width);
+	double xm = uniform_random (0, width);
+	double xn = uniform_random (0, width);
+	double y0 = uniform_random (0, height);
+	double y1 = uniform_random (0, height);
+	double y2 = uniform_random (0, height);
+	double y3 = uniform_random (0, height);
+	double ym = uniform_random (0, height);
+	double yn = uniform_random (0, height);
+
+	cairo_move_to (cr, xm, ym);
+	cairo_curve_to (cr, x1, y1, x2, y2, xn, yn);
+	cairo_curve_to (cr, x3, y3, x0, y0, xm, ym);
+	cairo_close_path (cr);
+
+	cairo_fill(cr);
+    }
+
+    cairo_perf_timer_stop ();
+
+    return cairo_perf_timer_elapsed ();
+}
+
+cairo_bool_t
+a1_curve_enabled (cairo_perf_t *perf)
+{
+    return cairo_perf_can_run (perf, "a1-curve", NULL);
+}
+
+void
+a1_curve (cairo_perf_t *perf, cairo_t *cr, int width, int height)
+{
+    cairo_set_source_rgb (cr, 1., 1., 1.);
+    cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE);
+
+    cairo_perf_run (perf, "a1-curve-stroked", do_curve_stroke, NULL);
+    cairo_perf_run (perf, "a1-curve-filled", do_curve_fill, NULL);
+}
diff --git a/perf/micro/a1-line.c b/perf/micro/a1-line.c
new file mode 100644
index 0000000..ae86602
--- /dev/null
+++ b/perf/micro/a1-line.c
@@ -0,0 +1,223 @@
+/*
+ * Copyright © 2011 Intel 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: Chris Wilson <chris at chris-wilson.co.uk>
+ */
+
+#include "cairo-perf.h"
+
+static cairo_time_t
+horizontal (cairo_t *cr, int width, int height, int loops)
+{
+    double h = height/2 + .5;
+
+    cairo_move_to (cr, 0, h);
+    cairo_line_to (cr, width, h);
+
+    cairo_perf_timer_start ();
+
+    while (loops--)
+	cairo_stroke_preserve (cr);
+
+    cairo_perf_timer_stop ();
+
+    cairo_new_path (cr);
+
+    return cairo_perf_timer_elapsed ();
+}
+
+static cairo_time_t
+horizontal_hair (cairo_t *cr, int width, int height, int loops)
+{
+    cairo_set_line_width (cr, 1.);
+    return horizontal (cr, width, height, loops);
+}
+
+static cairo_time_t
+horizontal_wide (cairo_t *cr, int width, int height, int loops)
+{
+    cairo_set_line_width (cr, 5.);
+    return horizontal (cr, width, height, loops);
+}
+
+static cairo_time_t
+nearly_horizontal (cairo_t *cr, int width, int height, int loops)
+{
+    double h = height/2;
+
+    cairo_move_to (cr, 0, h);
+    cairo_line_to (cr, width, h+1);
+
+    cairo_perf_timer_start ();
+
+    while (loops--)
+	cairo_stroke_preserve (cr);
+
+    cairo_perf_timer_stop ();
+
+    cairo_new_path (cr);
+
+    return cairo_perf_timer_elapsed ();
+}
+
+static cairo_time_t
+nearly_horizontal_hair (cairo_t *cr, int width, int height, int loops)
+{
+    cairo_set_line_width (cr, 1.);
+    return nearly_horizontal (cr, width, height, loops);
+}
+
+static cairo_time_t
+nearly_horizontal_wide (cairo_t *cr, int width, int height, int loops)
+{
+    cairo_set_line_width (cr, 5.);
+    return nearly_horizontal (cr, width, height, loops);
+}
+
+
+static cairo_time_t
+vertical (cairo_t *cr, int width, int height, int loops)
+{
+    double w = width/2 + .5;
+
+    cairo_move_to (cr, w, 0);
+    cairo_line_to (cr, w, height);
+
+    cairo_perf_timer_start ();
+
+    while (loops--)
+	cairo_stroke_preserve (cr);
+
+    cairo_perf_timer_stop ();
+
+    cairo_new_path (cr);
+
+    return cairo_perf_timer_elapsed ();
+}
+
+static cairo_time_t
+vertical_hair (cairo_t *cr, int width, int height, int loops)
+{
+    cairo_set_line_width (cr, 1.);
+    return vertical (cr, width, height, loops);
+}
+
+static cairo_time_t
+vertical_wide (cairo_t *cr, int width, int height, int loops)
+{
+    cairo_set_line_width (cr, 5.);
+    return vertical (cr, width, height, loops);
+}
+
+static cairo_time_t
+nearly_vertical (cairo_t *cr, int width, int height, int loops)
+{
+    double w = width/2;
+
+    cairo_move_to (cr, w, 0);
+    cairo_line_to (cr, w+1, height);
+
+    cairo_perf_timer_start ();
+
+    while (loops--)
+	cairo_stroke_preserve (cr);
+
+    cairo_perf_timer_stop ();
+
+    cairo_new_path (cr);
+
+    return cairo_perf_timer_elapsed ();
+}
+
+static cairo_time_t
+nearly_vertical_hair (cairo_t *cr, int width, int height, int loops)
+{
+    cairo_set_line_width (cr, 1.);
+    return nearly_vertical (cr, width, height, loops);
+}
+
+static cairo_time_t
+nearly_vertical_wide (cairo_t *cr, int width, int height, int loops)
+{
+    cairo_set_line_width (cr, 5.);
+    return nearly_vertical (cr, width, height, loops);
+}
+
+
+static cairo_time_t
+diagonal (cairo_t *cr, int width, int height, int loops)
+{
+    cairo_move_to (cr, 0, 0);
+    cairo_line_to (cr, width, height);
+
+    cairo_perf_timer_start ();
+
+    while (loops--)
+	cairo_stroke_preserve (cr);
+
+    cairo_perf_timer_stop ();
+
+    cairo_new_path (cr);
+
+    return cairo_perf_timer_elapsed ();
+}
+
+static cairo_time_t
+diagonal_hair (cairo_t *cr, int width, int height, int loops)
+{
+    cairo_set_line_width (cr, 1.);
+    return diagonal (cr, width, height, loops);
+}
+
+static cairo_time_t
+diagonal_wide (cairo_t *cr, int width, int height, int loops)
+{
+    cairo_set_line_width (cr, 5.);
+    return diagonal (cr, width, height, loops);
+}
+
+cairo_bool_t
+a1_line_enabled (cairo_perf_t *perf)
+{
+    return cairo_perf_can_run (perf, "a1-line", NULL);
+}
+
+void
+a1_line (cairo_perf_t *perf, cairo_t *cr, int width, int height)
+{
+    cairo_set_source_rgb (cr, 1., 1., 1.);
+    cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE);
+
+    cairo_perf_run (perf, "a1-line-hh", horizontal_hair, NULL);
+    cairo_perf_run (perf, "a1-line-hw", horizontal_wide, NULL);
+    cairo_perf_run (perf, "a1-line-nhh", nearly_horizontal_hair, NULL);
+    cairo_perf_run (perf, "a1-line-nhw", nearly_horizontal_wide, NULL);
+
+    cairo_perf_run (perf, "a1-line-vh", vertical_hair, NULL);
+    cairo_perf_run (perf, "a1-line-vw", vertical_wide, NULL);
+    cairo_perf_run (perf, "a1-line-nvh", nearly_vertical_hair, NULL);
+    cairo_perf_run (perf, "a1-line-nvw", nearly_vertical_wide, NULL);
+
+    cairo_perf_run (perf, "a1-line-dh", diagonal_hair, NULL);
+    cairo_perf_run (perf, "a1-line-dw", diagonal_wide, NULL);
+}
diff --git a/perf/micro/box-outline.c b/perf/micro/box-outline.c
index a0c47f7..1e654eb 100644
--- a/perf/micro/box-outline.c
+++ b/perf/micro/box-outline.c
@@ -65,6 +65,55 @@ box_outline_stroke (cairo_t *cr, int width, int height, int loops)
 }
 
 static cairo_time_t
+box_outline_alpha_stroke (cairo_t *cr, int width, int height, int loops)
+{
+    cairo_set_source_rgb (cr, 0, 0, 1); /* blue */
+    cairo_paint (cr);
+
+    cairo_rectangle (cr,
+		     1.5, 1.5,
+		     width - 3, height - 3);
+    cairo_set_line_width (cr, 1.0);
+    cairo_set_source_rgba (cr, 1, 0, 0, .5); /* red */
+
+    cairo_perf_timer_start ();
+
+    while (loops--)
+	cairo_stroke_preserve (cr);
+
+    cairo_perf_timer_stop ();
+
+    cairo_new_path (cr);
+
+    return cairo_perf_timer_elapsed ();
+}
+
+static cairo_time_t
+box_outline_aa_stroke (cairo_t *cr, int width, int height, int loops)
+{
+    cairo_set_source_rgb (cr, 0, 0, 1); /* blue */
+    cairo_paint (cr);
+
+    cairo_translate (cr, .5, .5);
+    cairo_rectangle (cr,
+		     1.5, 1.5,
+		     width - 3, height - 3);
+    cairo_set_line_width (cr, 1.0);
+    cairo_set_source_rgb (cr, 1, 0, 0); /* red */
+
+    cairo_perf_timer_start ();
+
+    while (loops--)
+	cairo_stroke_preserve (cr);
+
+    cairo_perf_timer_stop ();
+
+    cairo_new_path (cr);
+
+    return cairo_perf_timer_elapsed ();
+}
+
+static cairo_time_t
 box_outline_fill (cairo_t *cr, int width, int height, int loops)
 {
     cairo_set_source_rgb (cr, 0, 0, 1); /* blue */
@@ -91,12 +140,76 @@ box_outline_fill (cairo_t *cr, int width, int height, int loops)
     return cairo_perf_timer_elapsed ();
 }
 
+static cairo_time_t
+box_outline_alpha_fill (cairo_t *cr, int width, int height, int loops)
+{
+    cairo_set_source_rgb (cr, 0, 0, 1); /* blue */
+    cairo_paint (cr);
+
+    cairo_rectangle (cr,
+		     1.0, 1.0,
+		     width - 2, height - 2);
+    cairo_rectangle (cr,
+		     2.0, 2.0,
+		     width - 4, height - 4);
+    cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD);
+    cairo_set_source_rgba (cr, 0, 1, 0, .5); /* green */
+
+    cairo_perf_timer_start ();
+
+    while (loops--)
+	cairo_fill_preserve (cr);
+
+    cairo_perf_timer_stop ();
+
+    cairo_new_path (cr);
+
+    return cairo_perf_timer_elapsed ();
+}
+
+static cairo_time_t
+box_outline_aa_fill (cairo_t *cr, int width, int height, int loops)
+{
+    cairo_set_source_rgb (cr, 0, 0, 1); /* blue */
+    cairo_paint (cr);
+
+    cairo_translate (cr, .5, .5);
+    cairo_rectangle (cr,
+		     1.0, 1.0,
+		     width - 2, height - 2);
+    cairo_rectangle (cr,
+		     2.0, 2.0,
+		     width - 4, height - 4);
+    cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD);
+    cairo_set_source_rgb (cr, 0, 1, 0); /* green */
+
+    cairo_perf_timer_start ();
+
+    while (loops--)
+	cairo_fill_preserve (cr);
+
+    cairo_perf_timer_stop ();
+
+    cairo_new_path (cr);
+
+    return cairo_perf_timer_elapsed ();
+}
+
+cairo_bool_t
+box_outline_enabled (cairo_perf_t *perf)
+{
+    return cairo_perf_can_run (perf, "box-outline", NULL);
+}
+
 void
 box_outline (cairo_perf_t *perf, cairo_t *cr, int width, int height)
 {
-    if (! cairo_perf_can_run (perf, "box-outline", NULL))
-	return;
-
     cairo_perf_run (perf, "box-outline-stroke", box_outline_stroke, NULL);
     cairo_perf_run (perf, "box-outline-fill", box_outline_fill, NULL);
+
+    cairo_perf_run (perf, "box-outline-alpha-stroke", box_outline_alpha_stroke, NULL);
+    cairo_perf_run (perf, "box-outline-alpha-fill", box_outline_alpha_fill, NULL);
+
+    cairo_perf_run (perf, "box-outline-aa-stroke", box_outline_aa_stroke, NULL);
+    cairo_perf_run (perf, "box-outline-aa-fill", box_outline_aa_fill, NULL);
 }
diff --git a/perf/micro/composite-checker.c b/perf/micro/composite-checker.c
index 0d7af0c..d6d17ab 100644
--- a/perf/micro/composite-checker.c
+++ b/perf/micro/composite-checker.c
@@ -75,6 +75,12 @@ do_composite_checker (cairo_t *cr,
     return cairo_perf_timer_elapsed ();
 }
 
+cairo_bool_t
+composite_checker_enabled (cairo_perf_t *perf)
+{
+    return cairo_perf_can_run (perf, "composite-checker", NULL);
+}
+
 void
 composite_checker (cairo_perf_t *perf,
                    cairo_t      *cr,
@@ -83,9 +89,6 @@ composite_checker (cairo_perf_t *perf,
 {
     cairo_surface_t *image;
 
-    if (! cairo_perf_can_run (perf, "composite-checker", NULL))
-	return;
-
     /* Create the checker pattern. We don't actually need to draw
      * anything on it since that wouldn't affect performance.
      */
diff --git a/perf/micro/curve.c b/perf/micro/curve.c
index 7def326..3b5a163 100644
--- a/perf/micro/curve.c
+++ b/perf/micro/curve.c
@@ -95,12 +95,15 @@ do_curve_fill (cairo_t *cr, int width, int height, int loops)
     return cairo_perf_timer_elapsed ();
 }
 
+cairo_bool_t
+curve_enabled (cairo_perf_t *perf)
+{
+    return cairo_perf_can_run (perf, "curve", NULL);
+}
+
 void
 curve (cairo_perf_t *perf, cairo_t *cr, int width, int height)
 {
-    if (! cairo_perf_can_run (perf, "curve", NULL))
-	return;
-
     cairo_set_source_rgb (cr, 1., 1., 1.);
 
     cairo_perf_run (perf, "curve-stroked", do_curve_stroke, NULL);
diff --git a/perf/micro/disjoint.c b/perf/micro/disjoint.c
index d7f5026..623eb6f 100644
--- a/perf/micro/disjoint.c
+++ b/perf/micro/disjoint.c
@@ -85,6 +85,12 @@ draw (cairo_t *cr, int width, int height, int loops)
     return cairo_perf_timer_elapsed ();
 }
 
+cairo_bool_t
+disjoint_enabled (cairo_perf_t *perf)
+{
+    return cairo_perf_can_run (perf, "disjoint", NULL);
+}
+
 void
 disjoint (cairo_perf_t *perf, cairo_t *cr, int width, int height)
 {
diff --git a/perf/micro/dragon.c b/perf/micro/dragon.c
index 5bc8d26..e215eac 100644
--- a/perf/micro/dragon.c
+++ b/perf/micro/dragon.c
@@ -265,12 +265,15 @@ do_dragon_solid_circle_clip (cairo_t *cr, int width, int height, int loops)
     return do_dragon_solid (cr, width, height, loops);
 }
 
+cairo_bool_t
+dragon_enabled (cairo_perf_t *perf)
+{
+    return cairo_perf_can_run (perf, "dragon", NULL);
+}
+
 void
 dragon (cairo_perf_t *perf, cairo_t *cr, int width, int height)
 {
-    if (! cairo_perf_can_run (perf, "dragon", NULL))
-	return;
-
     cairo_perf_run (perf, "dragon-solid", do_dragon_solid, NULL);
     cairo_perf_run (perf, "dragon-unaligned-solid", do_dragon_solid_unaligned, NULL);
     cairo_perf_run (perf, "dragon-solid-aligned-clip", do_dragon_solid_aligned_clip, NULL);
diff --git a/perf/micro/fill-clip.c b/perf/micro/fill-clip.c
new file mode 100644
index 0000000..2d014ac
--- /dev/null
+++ b/perf/micro/fill-clip.c
@@ -0,0 +1,126 @@
+/*
+ * Copyright © 2011 Intel 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: Chris Wilson <chris at chris-wilson.co.uk>
+ */
+
+/* Compares the overhead for WebKit's drawRect() */
+
+#include "cairo-perf.h"
+
+#include <pixman.h>
+
+static cairo_time_t
+clip_paint (cairo_t *cr, int width, int height, int loops)
+{
+    int x = width/4, w = width/2;
+    int y = height/4, h = height/2;
+
+    cairo_perf_timer_start ();
+
+    while (loops--) {
+	cairo_reset_clip (cr);
+	cairo_rectangle (cr, x, y, w, h);
+	cairo_clip (cr);
+	cairo_paint (cr);
+    }
+
+    cairo_perf_timer_stop ();
+
+    return cairo_perf_timer_elapsed ();
+}
+
+static cairo_time_t
+rect_fill (cairo_t *cr, int width, int height, int loops)
+{
+    int x = width/4, w = width/2;
+    int y = height/4, h = height/2;
+
+    cairo_perf_timer_start ();
+
+    while (loops--) {
+	cairo_rectangle (cr, x, y, w, h);
+	cairo_fill (cr);
+    }
+
+    cairo_perf_timer_stop ();
+
+    return cairo_perf_timer_elapsed ();
+}
+
+static cairo_time_t
+direct (cairo_t *cr, int width, int height, int loops)
+{
+    int x = width/4, w = width/2;
+    int y = height/4, h = height/2;
+    cairo_surface_t *surface, *image;
+    uint8_t *data;
+    int stride, bpp;
+
+
+    surface = cairo_get_target (cr);
+    image = cairo_surface_map_to_image (surface, NULL);
+    data = cairo_image_surface_get_data (image);
+    stride = cairo_image_surface_get_stride (image);
+
+    switch (cairo_image_surface_get_format (image)) {
+    default:
+    case CAIRO_FORMAT_INVALID:
+    case CAIRO_FORMAT_A1: bpp = 0; break;
+    case CAIRO_FORMAT_A8: bpp = 8; break;
+    case CAIRO_FORMAT_RGB16_565: bpp = 16; break;
+    case CAIRO_FORMAT_RGB24:
+    case CAIRO_FORMAT_RGB30:
+    case CAIRO_FORMAT_ARGB32: bpp = 32; break;
+    }
+
+    cairo_perf_timer_start ();
+
+    while (loops--) {
+	pixman_fill ((uint32_t *)data, stride / sizeof(uint32_t), bpp,
+		     x, y, w, h,
+		     -1);
+    }
+
+    cairo_perf_timer_stop ();
+
+    cairo_surface_unmap_image (surface, image);
+
+    return cairo_perf_timer_elapsed ();
+}
+
+cairo_bool_t
+fill_clip_enabled (cairo_perf_t *perf)
+{
+    return cairo_perf_can_run (perf, "fillclip", NULL);
+}
+
+void
+fill_clip (cairo_perf_t *perf, cairo_t *cr, int width, int height)
+{
+    cairo_set_source_rgb (cr, 1., 1., 1.);
+
+    cairo_perf_run (perf, "fillclip-clip", clip_paint, NULL);
+    cairo_perf_run (perf, "fillclip-fill", rect_fill, NULL);
+    cairo_perf_run (perf, "fillclip-direct", direct, NULL);
+}
diff --git a/perf/micro/fill.c b/perf/micro/fill.c
index 0795227..d356c26 100644
--- a/perf/micro/fill.c
+++ b/perf/micro/fill.c
@@ -107,12 +107,15 @@ do_fill_eo_noaa (cairo_t *cr, int width, int height, int loops)
     return cairo_perf_timer_elapsed ();
 }
 
+cairo_bool_t
+fill_enabled (cairo_perf_t *perf)
+{
+    return cairo_perf_can_run (perf, "fill", NULL);
+}
+
 void
 fill (cairo_perf_t *perf, cairo_t *cr, int width, int height)
 {
-    if (! cairo_perf_can_run (perf, "fill", NULL))
-	return;
-
     cairo_perf_cover_sources_and_operators (perf, "fill", do_fill, NULL);
     cairo_perf_cover_sources_and_operators (perf, "fill-annuli", do_fill_annuli, NULL);
     cairo_perf_cover_sources_and_operators (perf, "fill-eo-noaa", do_fill_eo_noaa, NULL);
diff --git a/perf/micro/glyphs.c b/perf/micro/glyphs.c
index 74c67ee..5f088b2 100644
--- a/perf/micro/glyphs.c
+++ b/perf/micro/glyphs.c
@@ -170,12 +170,15 @@ DECL(48ca, 48, CAIRO_ANTIALIAS_SUBPIXEL)
 DECL(8mono, 8, CAIRO_ANTIALIAS_NONE)
 DECL(48mono, 48, CAIRO_ANTIALIAS_NONE)
 
+cairo_bool_t
+glyphs_enabled (cairo_perf_t *perf)
+{
+    return cairo_perf_can_run (perf, "glyphs", NULL);
+}
+
 void
 glyphs (cairo_perf_t *perf, cairo_t *cr, int width, int height)
 {
-    if (! cairo_perf_can_run (perf, "glyphs", NULL))
-	return;
-
     cairo_perf_cover_sources_and_operators (perf, "glyphs8mono", do_glyphs8mono, count_glyphs8mono);
     cairo_perf_cover_sources_and_operators (perf, "glyphs8", do_glyphs8, count_glyphs8);
     cairo_perf_cover_sources_and_operators (perf, "glyphs8ca", do_glyphs8ca, count_glyphs8ca);
diff --git a/perf/micro/hash-table.c b/perf/micro/hash-table.c
index a026638..d162917 100644
--- a/perf/micro/hash-table.c
+++ b/perf/micro/hash-table.c
@@ -101,12 +101,15 @@ do_hash_table (cairo_t *cr, int width, int height, int loops)
     return cairo_perf_timer_elapsed ();
 }
 
+cairo_bool_t
+hash_table_enabled (cairo_perf_t *perf)
+{
+    return cairo_perf_can_run (perf, "hash-table", NULL);
+}
+
 void
 hash_table (cairo_perf_t *perf, cairo_t *cr, int width, int height)
 {
-    if (! cairo_perf_can_run (perf, "hash-table", NULL))
-	return;
-
     cairo_perf_cover_sources_and_operators (perf, "hash-table",
 					    do_hash_table, NULL);
 }
diff --git a/perf/micro/hatching.c b/perf/micro/hatching.c
index e31d301..b51acec 100644
--- a/perf/micro/hatching.c
+++ b/perf/micro/hatching.c
@@ -170,12 +170,15 @@ F(clip_alpha_aligned_mono, clip_alpha, aligned, mono)
 F(clip_alpha_misaligned_mono, clip_alpha, misaligned, mono)
 F(clip_alpha_rotated_mono, clip_alpha, rotated, mono)
 
+cairo_bool_t
+hatching_enabled (cairo_perf_t *perf)
+{
+    return cairo_perf_can_run (perf, "hatching", NULL);
+}
+
 void
 hatching (cairo_perf_t *perf, cairo_t *cr, int width, int height)
 {
-    if (! cairo_perf_can_run (perf, "hatching", NULL))
-	return;
-
     cairo_perf_run (perf, "hatching-aligned-aa", draw_aligned_aa, NULL);
     cairo_perf_run (perf, "hatching-misaligned-aa", draw_misaligned_aa, NULL);
     cairo_perf_run (perf, "hatching-rotated-aa", draw_rotated_aa, NULL);
diff --git a/perf/micro/intersections.c b/perf/micro/intersections.c
index 9a81eee..57931fa 100644
--- a/perf/micro/intersections.c
+++ b/perf/micro/intersections.c
@@ -143,12 +143,15 @@ random_curve_nz (cairo_t *cr, int width, int height, int loops)
     return draw_random_curve (cr, CAIRO_FILL_RULE_WINDING, width, height, loops);
 }
 
+cairo_bool_t
+intersections_enabled (cairo_perf_t *perf)
+{
+    return cairo_perf_can_run (perf, "intersections", NULL);
+}
+
 void
 intersections (cairo_perf_t *perf, cairo_t *cr, int width, int height)
 {
-    if (! cairo_perf_can_run (perf, "intersections", NULL))
-	return;
-
     cairo_perf_run (perf, "intersections-nz-fill", random_nz, NULL);
     cairo_perf_run (perf, "intersections-eo-fill", random_eo, NULL);
 
diff --git a/perf/micro/line.c b/perf/micro/line.c
index 7ba9f90..3ed5f8d 100644
--- a/perf/micro/line.c
+++ b/perf/micro/line.c
@@ -196,12 +196,15 @@ diagonal_wide (cairo_t *cr, int width, int height, int loops)
     return diagonal (cr, width, height, loops);
 }
 
+cairo_bool_t
+line_enabled (cairo_perf_t *perf)
+{
+    return cairo_perf_can_run (perf, "line", NULL);
+}
+
 void
 line (cairo_perf_t *perf, cairo_t *cr, int width, int height)
 {
-    if (! cairo_perf_can_run (perf, "line", NULL))
-	return;
-
     cairo_set_source_rgb (cr, 1., 1., 1.);
 
     cairo_perf_run (perf, "line-hh", horizontal_hair, NULL);
diff --git a/perf/micro/long-dashed-lines.c b/perf/micro/long-dashed-lines.c
index fa99b20..ba66a4a 100644
--- a/perf/micro/long-dashed-lines.c
+++ b/perf/micro/long-dashed-lines.c
@@ -61,11 +61,14 @@ do_long_dashed_lines (cairo_t *cr, int width, int height, int loops)
     return cairo_perf_timer_elapsed ();
 }
 
+cairo_bool_t
+long_dashed_lines_enabled (cairo_perf_t *perf)
+{
+    return cairo_perf_can_run (perf, "long-dashed-lines", NULL);
+}
+
 void
 long_dashed_lines (cairo_perf_t *perf, cairo_t *cr, int width, int height)
 {
-    if (! cairo_perf_can_run (perf, "long-dashed-lines", NULL))
-	return;
-
     cairo_perf_run (perf, "long-dashed-lines", do_long_dashed_lines, NULL);
 }
diff --git a/perf/micro/long-lines.c b/perf/micro/long-lines.c
index b3a9458..a0d134c 100644
--- a/perf/micro/long-lines.c
+++ b/perf/micro/long-lines.c
@@ -132,12 +132,15 @@ long_lines_cropped_once (cairo_t *cr, int width, int height, int loops)
     return do_long_lines (cr, width, height, loops, LONG_LINES_CROPPED | LONG_LINES_ONCE);
 }
 
+cairo_bool_t
+long_lines_enabled (cairo_perf_t *perf)
+{
+    return cairo_perf_can_run (perf, "long-lines", NULL);
+}
+
 void
 long_lines (cairo_perf_t *perf, cairo_t *cr, int width, int height)
 {
-    if (! cairo_perf_can_run (perf, "long-lines", NULL))
-	return;
-
     cairo_perf_run (perf, "long-lines-uncropped", long_lines_uncropped, NULL);
     cairo_perf_run (perf, "long-lines-uncropped-once", long_lines_uncropped_once, NULL);
     cairo_perf_run (perf, "long-lines-cropped", long_lines_cropped, NULL);
diff --git a/perf/micro/many-curves.c b/perf/micro/many-curves.c
index dc7cdf9..f985d34 100644
--- a/perf/micro/many-curves.c
+++ b/perf/micro/many-curves.c
@@ -118,12 +118,15 @@ do_many_curves_filled (cairo_t *cr, int width, int height, int loops)
     return cairo_perf_timer_elapsed ();
 }
 
+cairo_bool_t
+many_curves_enabled (cairo_perf_t *perf)
+{
+    return cairo_perf_can_run (perf, "many-curves", NULL);
+}
+
 void
 many_curves (cairo_perf_t *perf, cairo_t *cr, int width, int height)
 {
-    if (! cairo_perf_can_run (perf, "many-curves", NULL))
-	return;
-
     cairo_set_source_rgb (cr, 1., 1., 1.);
 
     cairo_perf_run (perf, "many-curves-hair-stroked", do_many_curves_hair_stroked, NULL);
diff --git a/perf/micro/many-fills.c b/perf/micro/many-fills.c
index eb56e8b..9d3fd64 100644
--- a/perf/micro/many-fills.c
+++ b/perf/micro/many-fills.c
@@ -170,12 +170,15 @@ do_many_fills (cairo_t *cr, int width, int height, int loops)
     return cairo_perf_timer_elapsed ();
 }
 
+cairo_bool_t
+many_fills_enabled (cairo_perf_t *perf)
+{
+    return cairo_perf_can_run (perf, "many-fills", NULL);
+}
+
 void
 many_fills (cairo_perf_t *perf, cairo_t *cr, int width, int height)
 {
-    if (! cairo_perf_can_run (perf, "many-fills", NULL))
-	return;
-
     cairo_perf_run (perf, "many-fills-halign", do_many_fills_ha, NULL);
     cairo_perf_run (perf, "many-fills-valign", do_many_fills_va, NULL);
     cairo_perf_run (perf, "many-fills-horizontal", do_many_fills_h, NULL);
diff --git a/perf/micro/many-strokes.c b/perf/micro/many-strokes.c
index f033945..9aeb393 100644
--- a/perf/micro/many-strokes.c
+++ b/perf/micro/many-strokes.c
@@ -45,7 +45,7 @@ do_many_strokes_ha (cairo_t *cr, int width, int height, int loops)
 
     state = 0xc0ffee;
     for (count = 0; count < 1000; count++) {
-	double h = floor (uniform_random (0, height));
+	double h = floor (uniform_random (0, height)) + .5;
 	cairo_move_to (cr, floor (uniform_random (0, width)), h);
 	cairo_line_to (cr, ceil (uniform_random (0, width)), h);
     }
@@ -97,7 +97,7 @@ do_many_strokes_va (cairo_t *cr, int width, int height, int loops)
 
     state = 0xc0ffee;
     for (count = 0; count < 1000; count++) {
-	double v = floor (uniform_random (0, width));
+	double v = floor (uniform_random (0, width)) + .5;
 	cairo_move_to (cr, v, floor (uniform_random (0, height)));
 	cairo_line_to (cr, v, ceil (uniform_random (0, height)));
     }
@@ -169,12 +169,15 @@ do_many_strokes (cairo_t *cr, int width, int height, int loops)
     return cairo_perf_timer_elapsed ();
 }
 
+cairo_bool_t
+many_strokes_enabled (cairo_perf_t *perf)
+{
+    return cairo_perf_can_run (perf, "many-strokes", NULL);
+}
+
 void
 many_strokes (cairo_perf_t *perf, cairo_t *cr, int width, int height)
 {
-    if (! cairo_perf_can_run (perf, "many-strokes", NULL))
-	return;
-
     cairo_perf_run (perf, "many-strokes-halign", do_many_strokes_ha, NULL);
     cairo_perf_run (perf, "many-strokes-valign", do_many_strokes_va, NULL);
     cairo_perf_run (perf, "many-strokes-horizontal", do_many_strokes_h, NULL);
diff --git a/perf/micro/mask.c b/perf/micro/mask.c
index 79092e8..11a3ba7 100644
--- a/perf/micro/mask.c
+++ b/perf/micro/mask.c
@@ -272,6 +272,12 @@ do_mask_radial (cairo_t *cr, int width, int height, int loops)
     return cairo_perf_timer_elapsed ();
 }
 
+cairo_bool_t
+mask_enabled (cairo_perf_t *perf)
+{
+    return cairo_perf_can_run (perf, "mask", NULL);
+}
+
 void
 mask (cairo_perf_t *perf, cairo_t *cr, int width, int height)
 {
diff --git a/perf/micro/mosaic.c b/perf/micro/mosaic.c
index d76b840..ed30ae5 100644
--- a/perf/micro/mosaic.c
+++ b/perf/micro/mosaic.c
@@ -160,12 +160,15 @@ mosaic_tessellate_curves (cairo_t *cr, int width, int height, int loops)
     return mosaic_perform (cr, MOSAIC_TESSELLATE | MOSAIC_CURVE_TO, width, height, loops);
 }
 
+cairo_bool_t
+mosaic_enabled (cairo_perf_t *perf)
+{
+    return cairo_perf_can_run (perf, "mosaic", NULL);
+}
+
 void
 mosaic (cairo_perf_t *perf, cairo_t *cr, int width, int height)
 {
-    if (! cairo_perf_can_run (perf, "mosaic", NULL))
-	return;
-
     cairo_perf_run (perf, "mosaic-fill-curves", mosaic_fill_curves, NULL);
     cairo_perf_run (perf, "mosaic-fill-lines", mosaic_fill_lines, NULL);
     cairo_perf_run (perf, "mosaic-tessellate-curves", mosaic_tessellate_curves, NULL);
diff --git a/perf/micro/paint-with-alpha.c b/perf/micro/paint-with-alpha.c
index 3c1f69e..047e35c 100644
--- a/perf/micro/paint-with-alpha.c
+++ b/perf/micro/paint-with-alpha.c
@@ -44,12 +44,15 @@ count_paint_with_alpha (cairo_t *cr, int width, int height)
     return width * height / 1e6; /* Mpix/s */
 }
 
+cairo_bool_t
+paint_with_alpha_enabled (cairo_perf_t *perf)
+{
+    return cairo_perf_can_run (perf, "paint-with-alpha", NULL);
+}
+
 void
 paint_with_alpha (cairo_perf_t *perf, cairo_t *cr, int width, int height)
 {
-    if (! cairo_perf_can_run (perf, "paint-with-alpha", NULL))
-	return;
-
     cairo_perf_cover_sources_and_operators (perf, "paint-with-alpha",
 					    do_paint_with_alpha,
 					    count_paint_with_alpha);
diff --git a/perf/micro/paint.c b/perf/micro/paint.c
index dc7e0a0..2a59a45 100644
--- a/perf/micro/paint.c
+++ b/perf/micro/paint.c
@@ -44,11 +44,14 @@ count_paint (cairo_t *cr, int width, int height)
     return width * height / 1e6; /* Mpix/s */
 }
 
+cairo_bool_t
+paint_enabled (cairo_perf_t *perf)
+{
+    return cairo_perf_can_run (perf, "paint", NULL);
+}
+
 void
 paint (cairo_perf_t *perf, cairo_t *cr, int width, int height)
 {
-    if (! cairo_perf_can_run (perf, "paint", NULL))
-	return;
-
     cairo_perf_cover_sources_and_operators (perf, "paint", do_paint, count_paint);
 }
diff --git a/perf/micro/pattern_create_radial.c b/perf/micro/pattern_create_radial.c
index 13260bb..f236ef5 100644
--- a/perf/micro/pattern_create_radial.c
+++ b/perf/micro/pattern_create_radial.c
@@ -79,14 +79,17 @@ do_pattern_create_radial (cairo_t *cr, int width, int height, int loops)
     return cairo_perf_timer_elapsed ();
 }
 
+cairo_bool_t
+pattern_create_radial_enabled (cairo_perf_t *perf)
+{
+    return cairo_perf_can_run (perf, "pattern-create-radial", NULL);
+}
+
 void
 pattern_create_radial (cairo_perf_t *perf, cairo_t *cr, int width, int height)
 {
     int i;
 
-    if (! cairo_perf_can_run (perf, "pattern-create-radial", NULL))
-	return;
-
     srand (time (0));
     for (i = 0; i < RADIALS_COUNT; i++)
     {
diff --git a/perf/micro/pixel.c b/perf/micro/pixel.c
new file mode 100644
index 0000000..12b8f47
--- /dev/null
+++ b/perf/micro/pixel.c
@@ -0,0 +1,177 @@
+/*
+ * Copyright © 2011 Intel 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: Chris Wilson <chris at chris-wilson.co.uk>
+ */
+
+/* Measure the overhead in setting a single pixel */
+
+#include "cairo-perf.h"
+
+static cairo_time_t
+pixel_paint (cairo_t *cr, int width, int height, int loops)
+{
+    cairo_perf_timer_start ();
+
+    while (loops--)
+	cairo_paint (cr);
+
+    cairo_perf_timer_stop ();
+
+    return cairo_perf_timer_elapsed ();
+}
+
+static cairo_time_t
+pixel_mask (cairo_t *cr, int width, int height, int loops)
+{
+    cairo_surface_t *mask;
+    cairo_t *cr2;
+
+    mask = cairo_surface_create_similar (cairo_get_target (cr),
+					 CAIRO_CONTENT_ALPHA,
+					 1, 1);
+    cr2 = cairo_create (mask);
+    cairo_set_source_rgb (cr2, 1,1,1);
+    cairo_paint (cr2);
+    cairo_destroy (cr2);
+
+    cairo_perf_timer_start ();
+
+    while (loops--)
+	cairo_mask_surface (cr, mask, 0, 0);
+
+    cairo_perf_timer_stop ();
+
+    cairo_surface_destroy (mask);
+
+    return cairo_perf_timer_elapsed ();
+}
+
+static cairo_time_t
+pixel_rectangle (cairo_t *cr, int width, int height, int loops)
+{
+    cairo_new_path (cr);
+    cairo_rectangle (cr, 0, 0, 1, 1);
+
+    cairo_perf_timer_start ();
+
+    while (loops--)
+	cairo_fill_preserve (cr);
+
+    cairo_perf_timer_stop ();
+
+    cairo_new_path (cr);
+    return cairo_perf_timer_elapsed ();
+}
+
+static cairo_time_t
+pixel_subrectangle (cairo_t *cr, int width, int height, int loops)
+{
+    cairo_new_path (cr);
+    cairo_rectangle (cr, 0.1, 0.1, .8, .8);
+
+    cairo_perf_timer_start ();
+
+    while (loops--)
+	cairo_fill_preserve (cr);
+
+    cairo_perf_timer_stop ();
+
+    cairo_new_path (cr);
+    return cairo_perf_timer_elapsed ();
+}
+
+static cairo_time_t
+pixel_triangle (cairo_t *cr, int width, int height, int loops)
+{
+    cairo_new_path (cr);
+    cairo_move_to (cr, 0, 0);
+    cairo_line_to (cr, 1, 1);
+    cairo_line_to (cr, 0, 1);
+
+    cairo_perf_timer_start ();
+
+    while (loops--)
+	cairo_fill_preserve (cr);
+
+    cairo_perf_timer_stop ();
+
+    cairo_new_path (cr);
+    return cairo_perf_timer_elapsed ();
+}
+
+static cairo_time_t
+pixel_circle (cairo_t *cr, int width, int height, int loops)
+{
+    cairo_new_path (cr);
+    cairo_arc (cr, 0.5, 0.5, 0.5, 0, 2 * M_PI);
+
+    cairo_perf_timer_start ();
+
+    while (loops--)
+	cairo_fill_preserve (cr);
+
+    cairo_perf_timer_stop ();
+
+    cairo_new_path (cr);
+    return cairo_perf_timer_elapsed ();
+}
+
+static cairo_time_t
+pixel_stroke (cairo_t *cr, int width, int height, int loops)
+{
+    cairo_set_line_width (cr, 1.);
+    cairo_new_path (cr);
+    cairo_move_to (cr, 0, 0.5);
+    cairo_line_to (cr, 1, 0.5);
+
+    cairo_perf_timer_start ();
+
+    while (loops--)
+	cairo_stroke_preserve (cr);
+
+    cairo_perf_timer_stop ();
+
+    cairo_new_path (cr);
+    return cairo_perf_timer_elapsed ();
+}
+
+cairo_bool_t
+pixel_enabled (cairo_perf_t *perf)
+{
+    return cairo_perf_can_run (perf, "pixel", NULL);
+}
+
+void
+pixel (cairo_perf_t *perf, cairo_t *cr, int width, int height)
+{
+    cairo_set_source_rgb (cr, 1., 1., 1.);
+
+    cairo_perf_run (perf, "pixel-paint", pixel_paint, NULL);
+    cairo_perf_run (perf, "pixel-mask", pixel_mask, NULL);
+    cairo_perf_run (perf, "pixel-rectangle", pixel_rectangle, NULL);
+    cairo_perf_run (perf, "pixel-subrectangle", pixel_subrectangle, NULL);
+    cairo_perf_run (perf, "pixel-triangle", pixel_triangle, NULL);
+    cairo_perf_run (perf, "pixel-circle", pixel_circle, NULL);
+    cairo_perf_run (perf, "pixel-stroke", pixel_stroke, NULL);
+}
diff --git a/perf/micro/pythagoras-tree.c b/perf/micro/pythagoras-tree.c
index 6e823a8..9d3ca11 100644
--- a/perf/micro/pythagoras-tree.c
+++ b/perf/micro/pythagoras-tree.c
@@ -82,11 +82,14 @@ do_pythagoras_tree (cairo_t *cr, int width, int height, int loops)
     return cairo_perf_timer_elapsed ();
 }
 
+cairo_bool_t
+pythagoras_tree_enabled (cairo_perf_t *perf)
+{
+    return cairo_perf_can_run (perf, "pythagoras-tree", NULL);
+}
+
 void
 pythagoras_tree (cairo_perf_t *perf, cairo_t *cr, int width, int height)
 {
-    if (! cairo_perf_can_run (perf, "pythagoras-tree", NULL))
-	return;
-
     cairo_perf_run (perf, "pythagoras-tree", do_pythagoras_tree, NULL);
 }
diff --git a/perf/micro/rectangles.c b/perf/micro/rectangles.c
index 891572b..9228a4e 100644
--- a/perf/micro/rectangles.c
+++ b/perf/micro/rectangles.c
@@ -95,14 +95,17 @@ do_rectangle (cairo_t *cr, int width, int height, int loops)
     return cairo_perf_timer_elapsed ();
 }
 
+cairo_bool_t
+rectangles_enabled (cairo_perf_t *perf)
+{
+    return cairo_perf_can_run (perf, "rectangles", NULL);
+}
+
 void
 rectangles (cairo_perf_t *perf, cairo_t *cr, int width, int height)
 {
     int i;
 
-    if (! cairo_perf_can_run (perf, "rectangles", NULL))
-	return;
-
     srand (8478232);
     for (i = 0; i < RECTANGLE_COUNT; i++)
     {
diff --git a/perf/micro/rounded-rectangles.c b/perf/micro/rounded-rectangles.c
index 5985249..1e432dd 100644
--- a/perf/micro/rounded-rectangles.c
+++ b/perf/micro/rounded-rectangles.c
@@ -119,14 +119,17 @@ do_rectangles_once (cairo_t *cr, int width, int height, int loops)
     return cairo_perf_timer_elapsed ();
 }
 
+cairo_bool_t
+rounded_rectangles_enabled (cairo_perf_t *perf)
+{
+    return cairo_perf_can_run (perf, "rounded-rectangles", NULL);
+}
+
 void
 rounded_rectangles (cairo_perf_t *perf, cairo_t *cr, int width, int height)
 {
     int i;
 
-    if (! cairo_perf_can_run (perf, "rounded-rectangles", NULL))
-	return;
-
     srand (8478232);
     for (i = 0; i < RECTANGLE_COUNT; i++) {
         rects[i].x = rand () % width;
diff --git a/perf/micro/sierpinski.c b/perf/micro/sierpinski.c
new file mode 100644
index 0000000..c6f5fad
--- /dev/null
+++ b/perf/micro/sierpinski.c
@@ -0,0 +1,94 @@
+/*
+ * Copyright © 2011 Intel 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: Chris Wilson <chris at chris-wilson.co.uk>
+ */
+
+#include "cairo-perf.h"
+
+static const double m_1_sqrt_3 = 0.577359269;
+
+static void
+T (cairo_t *cr, int size)
+{
+    cairo_move_to (cr, 0, 0);
+    cairo_line_to (cr, size, 0);
+    cairo_line_to (cr, size/2, size*m_1_sqrt_3);
+
+    size /= 2;
+    if (size >= 4) {
+	T (cr, size);
+	cairo_save (cr); {
+	    cairo_translate (cr, size, 0);
+	    T (cr, size);
+	} cairo_restore (cr);
+	cairo_save (cr); {
+	    cairo_translate (cr, size/2, size*m_1_sqrt_3);
+	    T (cr, size);
+	} cairo_restore (cr);
+    }
+}
+
+static cairo_time_t
+draw (cairo_t *cr, int width, int height, int loops)
+{
+    int t_height = height/2;
+    int t_width = t_height / m_1_sqrt_3;
+
+    cairo_set_source_rgb (cr, 1, 1, 1);
+    cairo_paint (cr);
+
+    cairo_set_source_rgb (cr, 0, 0, 0);
+    cairo_set_line_width (cr, 1.);
+
+    cairo_perf_timer_start ();
+
+    while (loops--) {
+	cairo_save (cr);
+	T (cr, t_width);
+
+	cairo_translate (cr, 0, height);
+	cairo_scale (cr, 1, -1);
+
+	T (cr, t_width);
+
+	cairo_stroke (cr);
+	cairo_restore (cr);
+    }
+
+    cairo_perf_timer_stop ();
+
+    return cairo_perf_timer_elapsed ();
+}
+
+cairo_bool_t
+sierpinski_enabled (cairo_perf_t *perf)
+{
+    return cairo_perf_can_run (perf, "sierpinski", NULL);
+}
+
+void
+sierpinski (cairo_perf_t *perf, cairo_t *cr, int width, int height)
+{
+    cairo_perf_run (perf, "sierpinski", draw, NULL);
+}
diff --git a/perf/micro/spiral.c b/perf/micro/spiral.c
index 85d0580..87dbcb5 100644
--- a/perf/micro/spiral.c
+++ b/perf/micro/spiral.c
@@ -326,12 +326,15 @@ draw_spiral_stroke_na (cairo_t *cr, int width, int height, int loops)
 			       width, height, loops);
 }
 
+cairo_bool_t
+spiral_enabled (cairo_perf_t *perf)
+{
+    return cairo_perf_can_run (perf, "spiral", NULL);
+}
+
 void
 spiral (cairo_perf_t *perf, cairo_t *cr, int width, int height)
 {
-    if (! cairo_perf_can_run (perf, "spiral", NULL))
-	return;
-
     cairo_perf_run (perf, "spiral-box-nonalign-evenodd-fill", draw_spiral_eo_na_box, NULL);
     cairo_perf_run (perf, "spiral-box-nonalign-nonzero-fill", draw_spiral_nz_na_box, NULL);
     cairo_perf_run (perf, "spiral-box-pixalign-evenodd-fill", draw_spiral_eo_pa_box, NULL);
diff --git a/perf/micro/stroke.c b/perf/micro/stroke.c
index 8d7dc52..4b29547 100644
--- a/perf/micro/stroke.c
+++ b/perf/micro/stroke.c
@@ -86,12 +86,15 @@ do_strokes (cairo_t *cr, int width, int height, int loops)
     return cairo_perf_timer_elapsed ();
 }
 
+cairo_bool_t
+stroke_enabled (cairo_perf_t *perf)
+{
+    return cairo_perf_can_run (perf, "stroke", NULL);
+}
+
 void
 stroke (cairo_perf_t *perf, cairo_t *cr, int width, int height)
 {
-    if (! cairo_perf_can_run (perf, "stroke", NULL))
-	return;
-
     cairo_perf_cover_sources_and_operators (perf, "stroke", do_stroke, NULL);
     cairo_perf_cover_sources_and_operators (perf, "strokes", do_strokes, NULL);
 }
diff --git a/perf/micro/subimage_copy.c b/perf/micro/subimage_copy.c
index eb04154..e749c06 100644
--- a/perf/micro/subimage_copy.c
+++ b/perf/micro/subimage_copy.c
@@ -52,15 +52,18 @@ do_subimage_copy (cairo_t *cr, int width, int height, int loops)
     return cairo_perf_timer_elapsed ();
 }
 
+cairo_bool_t
+subimage_copy_enabled (cairo_perf_t *perf)
+{
+    return cairo_perf_can_run (perf, "subimage-copy", NULL);
+}
+
 void
 subimage_copy (cairo_perf_t *perf, cairo_t *cr, int width, int height)
 {
     cairo_surface_t *image;
     cairo_t *cr2;
 
-    if (! cairo_perf_can_run (perf, "subimage-copy", NULL))
-	return;
-
     cairo_set_source_rgb (cr, 0, 0, 1); /* blue */
     cairo_paint (cr);
 
diff --git a/perf/micro/tessellate.c b/perf/micro/tessellate.c
index 38c8b86..b6277fe 100644
--- a/perf/micro/tessellate.c
+++ b/perf/micro/tessellate.c
@@ -141,12 +141,15 @@ tessellate_256 (cairo_t *cr, int width, int height, int loops)
     return do_tessellate (cr, 256, loops);
 }
 
+cairo_bool_t
+tessellate_enabled (cairo_perf_t *perf)
+{
+    return cairo_perf_can_run (perf, "tessellate", NULL);
+}
+
 void
 tessellate (cairo_perf_t *perf, cairo_t *cr, int width, int height)
 {
-    if (! cairo_perf_can_run (perf, "tessellate", NULL))
-	return;
-
     cairo_perf_run (perf, "tessellate-16", tessellate_16, NULL);
     cairo_perf_run (perf, "tessellate-64", tessellate_64, NULL);
     cairo_perf_run (perf, "tessellate-256", tessellate_256, NULL);
diff --git a/perf/micro/text.c b/perf/micro/text.c
index bd2ca7b..cdb3199 100644
--- a/perf/micro/text.c
+++ b/perf/micro/text.c
@@ -56,11 +56,14 @@ do_text (cairo_t *cr, int width, int height, int loops)
     return cairo_perf_timer_elapsed ();
 }
 
+cairo_bool_t
+text_enabled (cairo_perf_t *perf)
+{
+    return cairo_perf_can_run (perf, "text", NULL);
+}
+
 void
 text (cairo_perf_t *perf, cairo_t *cr, int width, int height)
 {
-    if (! cairo_perf_can_run (perf, "text", NULL))
-	return;
-
     cairo_perf_cover_sources_and_operators (perf, "text", do_text, NULL);
 }
diff --git a/perf/micro/twin.c b/perf/micro/twin.c
index cc6f020..99433bd 100644
--- a/perf/micro/twin.c
+++ b/perf/micro/twin.c
@@ -43,14 +43,17 @@ do_twin (cairo_t *cr,
     return cairo_perf_timer_elapsed ();
 }
 
+cairo_bool_t
+twin_enabled (cairo_perf_t *perf)
+{
+    return cairo_perf_can_run (perf, "twin", NULL);
+}
+
 void
 twin (cairo_perf_t *perf,
       cairo_t      *cr,
       int           width,
       int           height)
 {
-    if (! cairo_perf_can_run (perf, "twin", NULL))
-	return;
-
     cairo_perf_run (perf, "twin", do_twin, NULL);
 }
diff --git a/perf/micro/unaligned-clip.c b/perf/micro/unaligned-clip.c
index d71549c..41e327f 100644
--- a/perf/micro/unaligned-clip.c
+++ b/perf/micro/unaligned-clip.c
@@ -60,11 +60,14 @@ do_unaligned_clip (cairo_t *cr, int width, int height, int loops)
     return cairo_perf_timer_elapsed ();
 }
 
+cairo_bool_t
+unaligned_clip_enabled (cairo_perf_t *perf)
+{
+    return cairo_perf_can_run (perf, "unaligned-clip", NULL);
+}
+
 void
 unaligned_clip (cairo_perf_t *perf, cairo_t *cr, int width, int height)
 {
-    if (! cairo_perf_can_run (perf, "unaligned-clip", NULL))
-	return;
-
     cairo_perf_run (perf, "unaligned-clip", do_unaligned_clip, NULL);
 }
diff --git a/perf/micro/wave.c b/perf/micro/wave.c
index 88029f8..f6e6f74 100644
--- a/perf/micro/wave.c
+++ b/perf/micro/wave.c
@@ -102,11 +102,14 @@ do_wave (cairo_t *cr, int width, int height, int loops)
     return cairo_perf_timer_elapsed ();
 }
 
+cairo_bool_t
+wave_enabled (cairo_perf_t *perf)
+{
+    return cairo_perf_can_run (perf, "wave", NULL);
+}
+
 void
 wave (cairo_perf_t *perf, cairo_t *cr, int width, int height)
 {
-    if (! cairo_perf_can_run (perf, "wave", NULL))
-	return;
-
     cairo_perf_run (perf, "wave", do_wave, NULL);
 }
diff --git a/perf/micro/wide-fills.c b/perf/micro/wide-fills.c
index a9beeeb..0747e6e 100644
--- a/perf/micro/wide-fills.c
+++ b/perf/micro/wide-fills.c
@@ -170,12 +170,15 @@ do_wide_fills (cairo_t *cr, int width, int height, int loops)
     return cairo_perf_timer_elapsed ();
 }
 
+cairo_bool_t
+wide_fills_enabled (cairo_perf_t *perf)
+{
+    return cairo_perf_can_run (perf, "wide-fills", NULL);
+}
+
 void
 wide_fills (cairo_perf_t *perf, cairo_t *cr, int width, int height)
 {
-    if (! cairo_perf_can_run (perf, "wide-fills", NULL))
-	return;
-
     cairo_perf_run (perf, "wide-fills-halign", do_wide_fills_ha, NULL);
     cairo_perf_run (perf, "wide-fills-valign", do_wide_fills_va, NULL);
     cairo_perf_run (perf, "wide-fills-horizontal", do_wide_fills_h, NULL);
diff --git a/perf/micro/wide-strokes.c b/perf/micro/wide-strokes.c
index e6c27da..1413091 100644
--- a/perf/micro/wide-strokes.c
+++ b/perf/micro/wide-strokes.c
@@ -169,12 +169,15 @@ do_wide_strokes (cairo_t *cr, int width, int height, int loops)
     return cairo_perf_timer_elapsed ();
 }
 
+cairo_bool_t
+wide_strokes_enabled (cairo_perf_t *perf)
+{
+    return cairo_perf_can_run (perf, "wide-strokes", NULL);
+}
+
 void
 wide_strokes (cairo_perf_t *perf, cairo_t *cr, int width, int height)
 {
-    if (! cairo_perf_can_run (perf, "wide-strokes", NULL))
-	return;
-
     cairo_set_source_rgb (cr, 1., 1., 1.);
 
     cairo_perf_run (perf, "wide-strokes-halign", do_wide_strokes_ha, NULL);
diff --git a/perf/micro/world-map.c b/perf/micro/world-map.c
index cb0aeee..ff22eeb 100644
--- a/perf/micro/world-map.c
+++ b/perf/micro/world-map.c
@@ -134,12 +134,15 @@ do_world_map_both (cairo_t *cr, int width, int height, int loops)
     return do_world_map (cr, width, height, loops, FILL | STROKE);
 }
 
+cairo_bool_t
+world_map_enabled (cairo_perf_t *perf)
+{
+    return cairo_perf_can_run (perf, "world-map", NULL);
+}
+
 void
 world_map (cairo_perf_t *perf, cairo_t *cr, int width, int height)
 {
-    if (! cairo_perf_can_run (perf, "world-map", NULL))
-	return;
-
     cairo_perf_run (perf, "world-map-stroke", do_world_map_stroke, NULL);
     cairo_perf_run (perf, "world-map-fill", do_world_map_fill, NULL);
     cairo_perf_run (perf, "world-map", do_world_map_both, NULL);
diff --git a/perf/micro/zrusin.c b/perf/micro/zrusin.c
index c4dccbf..7d8b004 100644
--- a/perf/micro/zrusin.c
+++ b/perf/micro/zrusin.c
@@ -84,11 +84,15 @@ zrusin_another_fill (cairo_t *cr, int width, int height, int loops)
     return cairo_perf_timer_elapsed ();
 }
 
+cairo_bool_t
+zrusin_enabled (cairo_perf_t *perf)
+{
+    return cairo_perf_can_run (perf, "zrusin", NULL);
+}
+
 void
 zrusin (cairo_perf_t *perf, cairo_t *cr, int width, int height)
 {
-    if (! cairo_perf_can_run (perf, "zrusin", NULL))
-	return;
 
     cairo_perf_run (perf, "zrusin-another-tessellate", zrusin_another_tessellate, NULL);
     cairo_perf_run (perf, "zrusin-another-fill", zrusin_another_fill, NULL);
diff --git a/src/Makefile.sources b/src/Makefile.sources
index 0b820f8..d23d504 100644
--- a/src/Makefile.sources
+++ b/src/Makefile.sources
@@ -54,6 +54,7 @@ cairo_private = \
 	cairoint.h \
 	cairo-analysis-surface-private.h \
 	cairo-arc-private.h \
+	cairo-array-private.h \
 	cairo-atomic-private.h \
 	cairo-backend-private.h \
 	cairo-box-private.h \
@@ -62,6 +63,7 @@ cairo_private = \
 	cairo-clip-private.h \
 	cairo-combsort-private.h \
 	cairo-compiler-private.h \
+	cairo-compositor-private.h \
 	cairo-contour-private.h \
 	cairo-composite-rectangles-private.h \
 	cairo-default-context-private.h \
@@ -97,10 +99,11 @@ cairo_private = \
 	cairo-scaled-font-private.h \
 	cairo-slope-private.h \
 	cairo-spans-private.h \
+	cairo-spans-compositor-private.h \
 	cairo-stroke-dash-private.h \
-	cairo-surface-fallback-private.h \
 	cairo-surface-private.h \
 	cairo-surface-clipper-private.h \
+	cairo-surface-fallback-private.h \
 	cairo-surface-observer-private.h \
 	cairo-surface-offset-private.h \
 	cairo-surface-subsurface-private.h \
@@ -108,6 +111,8 @@ cairo_private = \
 	cairo-surface-wrapper-private.h \
 	cairo-time-private.h \
 	cairo-types-private.h \
+	cairo-traps-private.h \
+	cairo-tristrip-private.h \
 	cairo-user-font-private.h \
 	cairo-wideint-private.h \
 	cairo-wideint-type-private.h \
@@ -134,11 +139,13 @@ cairo_sources = \
 	cairo-clip-surface.c \
 	cairo-color.c \
 	cairo-composite-rectangles.c \
+	cairo-compositor.c \
 	cairo-contour.c \
 	cairo-debug.c \
 	cairo-default-context.c \
 	cairo-device.c \
 	cairo-error.c \
+	cairo-fallback-compositor.c \
 	cairo-fixed.c \
 	cairo-font-face.c \
 	cairo-font-face-twin.c \
@@ -149,14 +156,19 @@ cairo_sources = \
 	cairo-gstate.c \
 	cairo-hash.c \
 	cairo-hull.c \
+	cairo-image-compositor.c \
 	cairo-image-info.c \
+	cairo-image-source.c \
 	cairo-image-surface.c \
 	cairo-lzw.c \
 	cairo-matrix.c \
+	cairo-mask-compositor.c \
 	cairo-mesh-pattern-rasterizer.c \
 	cairo-mime-surface.c \
 	cairo-misc.c \
+	cairo-mono-scan-converter.c \
 	cairo-mutex.c \
+	cairo-no-compositor.c \
 	cairo-observer.c \
 	cairo-output-stream.c \
 	cairo-paginated-surface.c \
@@ -168,6 +180,7 @@ cairo_sources = \
 	cairo-path-stroke.c \
 	cairo-path-stroke-boxes.c \
 	cairo-path-stroke-polygon.c \
+	cairo-path-stroke-tristrip.c \
 	cairo-pattern.c \
 	cairo-pen.c \
 	cairo-polygon.c \
@@ -181,12 +194,13 @@ cairo_sources = \
 	cairo-scaled-font.c \
 	cairo-slope.c \
 	cairo-spans.c \
+	cairo-spans-compositor.c \
 	cairo-spline.c \
 	cairo-stroke-dash.c \
 	cairo-stroke-style.c \
 	cairo-surface.c \
-	cairo-surface-fallback.c \
 	cairo-surface-clipper.c \
+	cairo-surface-fallback.c \
 	cairo-surface-observer.c \
 	cairo-surface-offset.c \
 	cairo-surface-snapshot.c \
@@ -195,8 +209,12 @@ cairo_sources = \
 	cairo-system.c \
 	cairo-time.c \
 	cairo-tor-scan-converter.c \
+	cairo-tor22-scan-converter.c \
+	cairo-clip-tor-scan-converter.c \
 	cairo-toy-font-face.c \
 	cairo-traps.c \
+	cairo-tristrip.c \
+	cairo-traps-compositor.c \
 	cairo-unicode.c \
 	cairo-user-font.c \
 	cairo-version.c \
@@ -253,18 +271,15 @@ cairo_ft_sources = cairo-ft-font.c
 
 # These are private, even though they look like public headers
 cairo_test_surfaces_private = \
-	test-fallback-surface.h \
-	test-fallback16-surface.h \
-	test-null-surface.h \
+	test-compositor-surface.h \
+	test-null-compositor-surface.h \
 	test-paginated-surface.h \
-	test-wrapping-surface.h \
 	$(NULL)
 cairo_test_surfaces_sources = \
-	test-fallback-surface.c \
-	test-fallback16-surface.c \
-	test-null-surface.c \
+	test-compositor-surface.c \
+	test-null-compositor-surface.c \
+	test-base-compositor-surface.c \
 	test-paginated-surface.c \
-	test-wrapping-surface.c \
 	$(NULL)
 
 cairo_xlib_headers = cairo-xlib.h
@@ -275,7 +290,11 @@ cairo_xlib_private = \
 	$(NULL)
 cairo_xlib_sources = \
 	cairo-xlib-display.c \
+	cairo-xlib-core-compositor.c \
+	cairo-xlib-fallback-compositor.c \
+	cairo-xlib-render-compositor.c \
 	cairo-xlib-screen.c \
+	cairo-xlib-source.c \
 	cairo-xlib-surface.c \
 	cairo-xlib-visual.c \
 	cairo-xlib-xcb-surface.c \
@@ -343,7 +362,10 @@ cairo_gl_sources = cairo-gl-composite.c \
 		   cairo-gl-glyphs.c \
 		   cairo-gl-gradient.c \
 		   cairo-gl-info.c \
+		   cairo-gl-operand.c \
 		   cairo-gl-shaders.c \
+		   cairo-gl-spans-compositor.c \
+		   cairo-gl-traps-compositor.c \
 		   cairo-gl-surface.c
 
 cairo_glesv2_headers = $(cairo_gl_headers)
diff --git a/src/cairo-analysis-surface.c b/src/cairo-analysis-surface.c
index beb9a07..e1c28b6 100644
--- a/src/cairo-analysis-surface.c
+++ b/src/cairo-analysis-surface.c
@@ -144,7 +144,7 @@ _analyze_recording_surface_pattern (cairo_analysis_surface_t *surface,
     cairo_analysis_surface_t *tmp;
     cairo_surface_t *source, *proxy;
     cairo_matrix_t p2d;
-    cairo_status_t status;
+    cairo_status_t status, analysis_status;
 
     assert (pattern->type == CAIRO_PATTERN_TYPE_SURFACE);
     surface_pattern = (const cairo_surface_pattern_t *) pattern;
@@ -175,11 +175,16 @@ _analyze_recording_surface_pattern (cairo_analysis_surface_t *surface,
     if (_cairo_surface_is_subsurface (source))
 	source = _cairo_surface_subsurface_get_target (source);
 
-    status = _cairo_recording_surface_replay_and_create_regions (source, &tmp->base);
+    status = _cairo_recording_surface_replay_and_create_regions (source,
+								 &tmp->base);
+    analysis_status = tmp->has_unsupported ? CAIRO_INT_STATUS_IMAGE_FALLBACK : CAIRO_INT_STATUS_SUCCESS;
     detach_proxy (proxy);
     cairo_surface_destroy (&tmp->base);
 
-    return status;
+    if (unlikely (status))
+	return status;
+
+    return analysis_status;
 }
 
 static cairo_int_status_t
@@ -548,8 +553,7 @@ _cairo_analysis_surface_show_glyphs (void		  *abstract_surface,
 				     cairo_glyph_t	  *glyphs,
 				     int		   num_glyphs,
 				     cairo_scaled_font_t  *scaled_font,
-				     const cairo_clip_t         *clip,
-				     int                  *remaining_glyphs)
+				     const cairo_clip_t         *clip)
 {
     cairo_analysis_surface_t *surface = abstract_surface;
     cairo_int_status_t	     status, backend_status;
@@ -562,8 +566,7 @@ _cairo_analysis_surface_show_glyphs (void		  *abstract_surface,
 						   source,
 						   glyphs, num_glyphs,
 						   scaled_font,
-						   clip,
-						   remaining_glyphs);
+						   clip);
 	if (_cairo_int_status_is_error (backend_status))
 	    return backend_status;
     }
@@ -652,21 +655,14 @@ _cairo_analysis_surface_show_text_glyphs (void			    *abstract_surface,
     if (backend_status == CAIRO_INT_STATUS_UNSUPPORTED &&
 	surface->target->backend->show_glyphs != NULL)
     {
-	int remaining_glyphs = num_glyphs;
 	backend_status =
 	    surface->target->backend->show_glyphs (surface->target, op,
 						   source,
 						   glyphs, num_glyphs,
 						   scaled_font,
-						   clip,
-						   &remaining_glyphs);
+						   clip);
 	if (_cairo_int_status_is_error (backend_status))
 	    return backend_status;
-
-	glyphs += num_glyphs - remaining_glyphs;
-	num_glyphs = remaining_glyphs;
-	if (remaining_glyphs == 0)
-	    backend_status = CAIRO_STATUS_SUCCESS;
     }
 
     if (backend_status == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN)
@@ -701,35 +697,26 @@ static const cairo_surface_backend_t cairo_analysis_surface_backend = {
     NULL, /* create_similar_image */
     NULL, /* map_to_image */
     NULL, /* unmap */
+
     NULL, /* acquire_source_image */
     NULL, /* release_source_image */
-    NULL, /* acquire_dest_image */
-    NULL, /* release_dest_image */
-    NULL, /* clone_similar */
-    NULL, /* composite */
-    NULL, /* fill_rectangles */
-    NULL, /* composite_trapezoids */
-    NULL, /* create_span_renderer */
-    NULL, /* check_span_renderer */
+    NULL, /* snapshot */
+
     NULL, /* copy_page */
     NULL, /* show_page */
+
     _cairo_analysis_surface_get_extents,
-    NULL, /* old_show_glyphs */
     NULL, /* get_font_options */
+
     NULL, /* flush */
     NULL, /* mark_dirty_rectangle */
-    NULL, /* scaled_font_fini */
-    NULL, /* scaled_glyph_fini */
+
     _cairo_analysis_surface_paint,
     _cairo_analysis_surface_mask,
     _cairo_analysis_surface_stroke,
     _cairo_analysis_surface_fill,
-    _cairo_analysis_surface_show_glyphs,
-    NULL, /* snapshot */
-    NULL, /* is_similar */
     NULL, /* fill_stroke */
-    NULL, /* create_solid_pattern_surface */
-    NULL, /* can_repaint_solid_pattern_surface */
+    _cairo_analysis_surface_show_glyphs,
     _cairo_analysis_surface_has_show_text_glyphs,
     _cairo_analysis_surface_show_text_glyphs
 };
@@ -891,48 +878,38 @@ typedef cairo_int_status_t
 				 cairo_glyph_t		*glyphs,
 				 int			 num_glyphs,
 				 cairo_scaled_font_t	*scaled_font,
-				 const cairo_clip_t		*clip,
-				 int			*remaining_glyphs);
+				 const cairo_clip_t		*clip);
 
 static const cairo_surface_backend_t cairo_null_surface_backend = {
     CAIRO_INTERNAL_SURFACE_TYPE_NULL,
     NULL, /* finish */
 
-    _cairo_default_context_create, /* XXX */
+    NULL, /* only accessed through the surface functions */
 
     NULL, /* create_similar */
     NULL, /* create similar image */
     NULL, /* map to image */
     NULL, /* unmap image*/
+
     NULL, /* acquire_source_image */
     NULL, /* release_source_image */
-    NULL, /* acquire_dest_image */
-    NULL, /* release_dest_image */
-    NULL, /* clone_similar */
-    NULL, /* composite */
-    NULL, /* fill_rectangles */
-    NULL, /* composite_trapezoids */
-    NULL, /* create_span_renderer */
-    NULL, /* check_span_renderer */
+    NULL, /* snapshot */
+
     NULL, /* copy_page */
     NULL, /* show_page */
+
     NULL, /* get_extents */
-    NULL, /* old_show_glyphs */
     NULL, /* get_font_options */
+
     NULL, /* flush */
     NULL, /* mark_dirty_rectangle */
-    NULL, /* scaled_font_fini */
-    NULL, /* scaled_glyph_fini */
+
     (_paint_func) _return_success,	    /* paint */
     (_mask_func) _return_success,	    /* mask */
     (_stroke_func) _return_success,	    /* stroke */
     (_fill_func) _return_success,	    /* fill */
-    (_show_glyphs_func) _return_success,    /* show_glyphs */
-    NULL, /* snapshot */
-    NULL, /* is_similar */
     NULL, /* fill_stroke */
-    NULL, /* create_solid_pattern_surface */
-    NULL, /* can_repaint_solid_pattern_surface */
+    (_show_glyphs_func) _return_success,    /* show_glyphs */
     NULL, /* has_show_text_glyphs */
     NULL  /* show_text_glyphs */
 };
diff --git a/src/cairo-array-private.h b/src/cairo-array-private.h
new file mode 100644
index 0000000..35b29e5
--- /dev/null
+++ b/src/cairo-array-private.h
@@ -0,0 +1,90 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2002 University of Southern California
+ * 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., 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>
+ */
+
+#ifndef CAIRO_ARRAY_PRIVATE_H
+#define CAIRO_ARRAY_PRIVATE_H
+
+#include "cairo-compiler-private.h"
+#include "cairo-types-private.h"
+
+CAIRO_BEGIN_DECLS
+
+/* cairo-array.c structures and functions */
+
+cairo_private void
+_cairo_array_init (cairo_array_t *array, unsigned int element_size);
+
+cairo_private void
+_cairo_array_fini (cairo_array_t *array);
+
+cairo_private cairo_status_t
+_cairo_array_grow_by (cairo_array_t *array, unsigned int additional);
+
+cairo_private void
+_cairo_array_truncate (cairo_array_t *array, unsigned int num_elements);
+
+cairo_private cairo_status_t
+_cairo_array_append (cairo_array_t *array, const void *element);
+
+cairo_private cairo_status_t
+_cairo_array_append_multiple (cairo_array_t	*array,
+			      const void	*elements,
+			      unsigned int	 num_elements);
+
+cairo_private cairo_status_t
+_cairo_array_allocate (cairo_array_t	 *array,
+		       unsigned int	  num_elements,
+		       void		**elements);
+
+cairo_private void *
+_cairo_array_index (cairo_array_t *array, unsigned int index);
+
+cairo_private const void *
+_cairo_array_index_const (const cairo_array_t *array, unsigned int index);
+
+cairo_private void
+_cairo_array_copy_element (const cairo_array_t *array, unsigned int index, void *dst);
+
+cairo_private unsigned int
+_cairo_array_num_elements (const cairo_array_t *array);
+
+cairo_private unsigned int
+_cairo_array_size (const cairo_array_t *array);
+
+CAIRO_END_DECLS
+
+#endif /* CAIRO_ARRAY_PRIVATE_H */
diff --git a/src/cairo-array.c b/src/cairo-array.c
index 52b283f..4f3c082 100644
--- a/src/cairo-array.c
+++ b/src/cairo-array.c
@@ -37,6 +37,7 @@
  */
 
 #include "cairoint.h"
+#include "cairo-array-private.h"
 #include "cairo-error-private.h"
 
 /**
@@ -385,11 +386,11 @@ _cairo_user_data_array_fini (cairo_user_data_array_t *array)
 	cairo_user_data_slot_t *slots;
 
 	slots = _cairo_array_index (array, 0);
-	do {
-	    if (slots->user_data != NULL && slots->destroy != NULL)
-		slots->destroy (slots->user_data);
-	    slots++;
-	} while (--num_slots);
+	while (num_slots--) {
+	    cairo_user_data_slot_t *s = &slots[num_slots];
+	    if (s->user_data != NULL && s->destroy != NULL)
+		s->destroy (s->user_data);
+	}
     }
 
     _cairo_array_fini (array);
diff --git a/src/cairo-atomic-private.h b/src/cairo-atomic-private.h
index 9f5888c..327fed1 100644
--- a/src/cairo-atomic-private.h
+++ b/src/cairo-atomic-private.h
@@ -79,6 +79,7 @@ _cairo_atomic_ptr_get (void **x)
 #endif
 
 # define _cairo_atomic_int_inc(x) ((void) __sync_fetch_and_add(x, 1))
+# define _cairo_atomic_int_dec(x) ((void) __sync_fetch_and_add(x, -1))
 # define _cairo_atomic_int_dec_and_test(x) (__sync_fetch_and_add(x, -1) == 1)
 # define _cairo_atomic_int_cmpxchg(x, oldv, newv) __sync_bool_compare_and_swap (x, oldv, newv)
 # define _cairo_atomic_int_cmpxchg_return_old(x, oldv, newv) __sync_val_compare_and_swap (x, oldv, newv)
@@ -111,6 +112,7 @@ typedef  AO_t cairo_atomic_int_t;
 # define _cairo_atomic_int_get(x) (AO_load_full (x))
 
 # define _cairo_atomic_int_inc(x) ((void) AO_fetch_and_add1_full(x))
+# define _cairo_atomic_int_dec(x) ((void) AO_fetch_and_sub1_full(x))
 # define _cairo_atomic_int_dec_and_test(x) (AO_fetch_and_sub1_full(x) == 1)
 # define _cairo_atomic_int_cmpxchg(x, oldv, newv) AO_compare_and_swap_full(x, oldv, newv)
 
@@ -140,6 +142,7 @@ typedef int32_t cairo_atomic_int_t;
 # define _cairo_atomic_int_get(x) (OSMemoryBarrier(), *(x))
 
 # define _cairo_atomic_int_inc(x) ((void) OSAtomicIncrement32Barrier (x))
+# define _cairo_atomic_int_dec(x) ((void) OSAtomicDecrement32Barrier (x))
 # define _cairo_atomic_int_dec_and_test(x) (OSAtomicDecrement32Barrier (x) == 0)
 # define _cairo_atomic_int_cmpxchg(x, oldv, newv) OSAtomicCompareAndSwap32Barrier(oldv, newv, x)
 
@@ -178,6 +181,8 @@ typedef cairo_atomic_intptr_t cairo_atomic_int_t;
 cairo_private void
 _cairo_atomic_int_inc (cairo_atomic_int_t *x);
 
+#define _cairo_atomic_int_dec(x) _cairo_atomic_int_dec_and_test(x)
+
 cairo_private cairo_bool_t
 _cairo_atomic_int_dec_and_test (cairo_atomic_int_t *x);
 
diff --git a/src/cairo-bentley-ottmann-rectangular.c b/src/cairo-bentley-ottmann-rectangular.c
index 5191178..aec7ae4 100644
--- a/src/cairo-bentley-ottmann-rectangular.c
+++ b/src/cairo-bentley-ottmann-rectangular.c
@@ -42,6 +42,7 @@
 #include "cairo-error-private.h"
 #include "cairo-combsort-private.h"
 #include "cairo-list-private.h"
+#include "cairo-traps-private.h"
 
 #include <setjmp.h>
 
@@ -740,7 +741,7 @@ _cairo_bentley_ottmann_tessellate_boxes (const cairo_boxes_t *in,
     rectangle_t *stack_rectangles_ptrs[ARRAY_LENGTH (stack_rectangles) + 3];
     rectangle_t *rectangles, **rectangles_ptrs;
     rectangle_t *stack_rectangles_chain[CAIRO_STACK_ARRAY_LENGTH (rectangle_t *) ];
-    rectangle_t **rectangles_chain;
+    rectangle_t **rectangles_chain = NULL;
     const struct _cairo_boxes_chunk *chunk;
     cairo_status_t status;
     int i, j, y_min, y_max;
@@ -789,13 +790,15 @@ _cairo_bentley_ottmann_tessellate_boxes (const cairo_boxes_t *in,
     y_max = _cairo_fixed_integer_floor (y_max) + 1;
     y_max -= y_min;
 
-    rectangles_chain = stack_rectangles_chain;
-    if (y_max > ARRAY_LENGTH (stack_rectangles_chain)) {
-	rectangles_chain = _cairo_malloc_ab (y_max, sizeof (rectangle_t *));
-	if (unlikely (rectangles_chain == NULL))
-	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+    if (y_max < in->num_boxes) {
+	rectangles_chain = stack_rectangles_chain;
+	if (y_max > ARRAY_LENGTH (stack_rectangles_chain)) {
+	    rectangles_chain = _cairo_malloc_ab (y_max, sizeof (rectangle_t *));
+	    if (unlikely (rectangles_chain == NULL))
+		return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+	}
+	memset (rectangles_chain, 0, y_max * sizeof (rectangle_t*));
     }
-    memset (rectangles_chain, 0, y_max * sizeof (rectangle_t*));
 
     rectangles = stack_rectangles;
     rectangles_ptrs = stack_rectangles_ptrs;
@@ -839,28 +842,38 @@ _cairo_bentley_ottmann_tessellate_boxes (const cairo_boxes_t *in,
 	    rectangles[j].top = box[i].p1.y;
 	    rectangles[j].bottom = box[i].p2.y;
 
-	    h = _cairo_fixed_integer_floor (box[i].p1.y) - y_min;
-	    rectangles[j].left.next = (edge_t *)rectangles_chain[h];
-	    rectangles_chain[h] = &rectangles[j];
+	    if (rectangles_chain) {
+		h = _cairo_fixed_integer_floor (box[i].p1.y) - y_min;
+		rectangles[j].left.next = (edge_t *)rectangles_chain[h];
+		rectangles_chain[h] = &rectangles[j];
+	    } else {
+		rectangles_ptrs[j+2] = &rectangles[j];
+	    }
 	    j++;
 	}
     }
 
-    j = 2;
-    for (y_min = 0; y_min < y_max; y_min++) {
-	rectangle_t *r;
-	int start = j;
-	for (r = rectangles_chain[y_min]; r; r = (rectangle_t *)r->left.next)
-	    rectangles_ptrs[j++] = r;
-	if (j > start + 1)
+    if (rectangles_chain) {
+	j = 2;
+	for (y_min = 0; y_min < y_max; y_min++) {
+	    rectangle_t *r;
+	    int start = j;
+	    for (r = rectangles_chain[y_min]; r; r = (rectangle_t *)r->left.next)
+		rectangles_ptrs[j++] = r;
+	    if (j > start + 1)
 		_rectangle_sort (rectangles_ptrs + start, j - start);
-    }
+	}
+
+	if (rectangles_chain != stack_rectangles_chain)
+	    free (rectangles_chain);
 
-    if (rectangles_chain != stack_rectangles_chain)
-	free (rectangles_chain);
+	j -= 2;
+    } else {
+	_rectangle_sort (rectangles_ptrs + 2, j);
+    }
 
     _cairo_boxes_clear (out);
-    status = _cairo_bentley_ottmann_tessellate_rectangular (rectangles_ptrs+2, j-2,
+    status = _cairo_bentley_ottmann_tessellate_rectangular (rectangles_ptrs+2, j,
 							    fill_rule,
 							    FALSE, out);
     if (rectangles != stack_rectangles)
diff --git a/src/cairo-bentley-ottmann-rectilinear.c b/src/cairo-bentley-ottmann-rectilinear.c
index a3eb490..1edeeb5 100644
--- a/src/cairo-bentley-ottmann-rectilinear.c
+++ b/src/cairo-bentley-ottmann-rectilinear.c
@@ -41,6 +41,7 @@
 #include "cairo-boxes-private.h"
 #include "cairo-combsort-private.h"
 #include "cairo-error-private.h"
+#include "cairo-traps-private.h"
 
 typedef struct _cairo_bo_edge cairo_bo_edge_t;
 typedef struct _cairo_bo_trap cairo_bo_trap_t;
@@ -437,74 +438,6 @@ _cairo_bentley_ottmann_tessellate_rectilinear (cairo_bo_event_t   **start_events
 }
 
 cairo_status_t
-_cairo_bentley_ottmann_tessellate_rectilinear_polygon (cairo_traps_t	 *traps,
-						       const cairo_polygon_t *polygon,
-						       cairo_fill_rule_t	  fill_rule)
-{
-    cairo_status_t status;
-    cairo_bo_event_t stack_events[CAIRO_STACK_ARRAY_LENGTH (cairo_bo_event_t)];
-    cairo_bo_event_t *events;
-    cairo_bo_event_t *stack_event_ptrs[ARRAY_LENGTH (stack_events) + 1];
-    cairo_bo_event_t **event_ptrs;
-    cairo_bo_edge_t stack_edges[ARRAY_LENGTH (stack_events)];
-    cairo_bo_edge_t *edges;
-    int num_events;
-    int i, j;
-
-    if (unlikely (polygon->num_edges == 0))
-	return CAIRO_STATUS_SUCCESS;
-
-    num_events = 2 * polygon->num_edges;
-
-    events = stack_events;
-    event_ptrs = stack_event_ptrs;
-    edges = stack_edges;
-    if (num_events > ARRAY_LENGTH (stack_events)) {
-	events = _cairo_malloc_ab_plus_c (num_events,
-					  sizeof (cairo_bo_event_t) +
-					  sizeof (cairo_bo_edge_t) +
-					  sizeof (cairo_bo_event_t *),
-					  sizeof (cairo_bo_event_t *));
-	if (unlikely (events == NULL))
-	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
-	event_ptrs = (cairo_bo_event_t **) (events + num_events);
-	edges = (cairo_bo_edge_t *) (event_ptrs + num_events + 1);
-    }
-
-    for (i = j = 0; i < polygon->num_edges; i++) {
-	edges[i].edge = polygon->edges[i];
-	edges[i].deferred_trap.right = NULL;
-	edges[i].prev = NULL;
-	edges[i].next = NULL;
-
-	event_ptrs[j] = &events[j];
-	events[j].type = CAIRO_BO_EVENT_TYPE_START;
-	events[j].point.y = polygon->edges[i].top;
-	events[j].point.x = polygon->edges[i].line.p1.x;
-	events[j].edge = &edges[i];
-	j++;
-
-	event_ptrs[j] = &events[j];
-	events[j].type = CAIRO_BO_EVENT_TYPE_STOP;
-	events[j].point.y = polygon->edges[i].bottom;
-	events[j].point.x = polygon->edges[i].line.p1.x;
-	events[j].edge = &edges[i];
-	j++;
-    }
-
-    status = _cairo_bentley_ottmann_tessellate_rectilinear (event_ptrs, j,
-							    fill_rule,
-							    TRUE, traps);
-    if (events != stack_events)
-	free (events);
-
-    traps->is_rectilinear = TRUE;
-
-    return status;
-}
-
-cairo_status_t
 _cairo_bentley_ottmann_tessellate_rectilinear_polygon_to_boxes (const cairo_polygon_t *polygon,
 								cairo_fill_rule_t	  fill_rule,
 								cairo_boxes_t *boxes)
diff --git a/src/cairo-bentley-ottmann.c b/src/cairo-bentley-ottmann.c
index 70d4482..634da6f 100644
--- a/src/cairo-bentley-ottmann.c
+++ b/src/cairo-bentley-ottmann.c
@@ -41,6 +41,7 @@
 #include "cairo-error-private.h"
 #include "cairo-freelist-private.h"
 #include "cairo-combsort-private.h"
+#include "cairo-traps-private.h"
 
 #define DEBUG_PRINT_STATE 0
 #define DEBUG_EVENTS 0
@@ -1301,7 +1302,14 @@ event_log (const char *fmt, ...)
 static inline cairo_bool_t
 edges_colinear (const cairo_bo_edge_t *a, const cairo_bo_edge_t *b)
 {
-    if (_line_equal (&a->edge.line, &b->edge.line))
+    unsigned p;
+
+    p = 0;
+    p |= (a->edge.line.p1.x == b->edge.line.p1.x) << 0;
+    p |= (a->edge.line.p1.y == b->edge.line.p1.y) << 1;
+    p |= (a->edge.line.p2.x == b->edge.line.p2.x) << 3;
+    p |= (a->edge.line.p2.y == b->edge.line.p2.y) << 4;
+    if (p == ((1 << 0) | (1 << 1) | (1 << 3) | (1 << 4)))
 	return TRUE;
 
     if (_slope_compare (a, b))
@@ -1310,8 +1318,9 @@ edges_colinear (const cairo_bo_edge_t *a, const cairo_bo_edge_t *b)
     /* The choice of y is not truly arbitrary since we must guarantee that it
      * is greater than the start of either line.
      */
-    if (a->edge.line.p1.y == b->edge.line.p1.y) {
-	return a->edge.line.p1.x == b->edge.line.p1.x;
+    if (p != 0) {
+	/* colinear if either end-point are coincident */
+	return ((p >> 1) & p) != 0;
     } else if (a->edge.line.p1.y < b->edge.line.p1.y) {
 	return edge_compare_for_y_against_x (b,
 					     a->edge.line.p1.y,
@@ -1377,8 +1386,9 @@ _cairo_bo_edge_start_or_continue_trap (cairo_bo_edge_t	*left,
     if (left->deferred_trap.right == right)
 	return CAIRO_STATUS_SUCCESS;
 
+    assert (right);
     if (left->deferred_trap.right != NULL) {
-	if (right != NULL && edges_colinear (left->deferred_trap.right, right))
+	if (edges_colinear (left->deferred_trap.right, right))
 	{
 	    /* continuation on right, so just swap edges */
 	    left->deferred_trap.right = right;
@@ -1390,7 +1400,7 @@ _cairo_bo_edge_start_or_continue_trap (cairo_bo_edge_t	*left,
 	    return status;
     }
 
-    if (right != NULL && ! edges_colinear (left, right)) {
+    if (! edges_colinear (left, right)) {
 	left->deferred_trap.top = top;
 	left->deferred_trap.right = right;
 
@@ -1406,112 +1416,50 @@ _cairo_bo_edge_start_or_continue_trap (cairo_bo_edge_t	*left,
 }
 
 static inline cairo_status_t
-_active_edges_to_traps (cairo_bo_edge_t		*left,
-			int32_t			 top,
-			cairo_fill_rule_t	 fill_rule,
-			cairo_traps_t	        *traps)
+_active_edges_to_traps (cairo_bo_edge_t	*pos,
+			int32_t		 top,
+			unsigned	 mask,
+			cairo_traps_t        *traps)
 {
-    cairo_bo_edge_t *right;
+    cairo_bo_edge_t *left;
     cairo_status_t status;
+    int in_out;
+
 
 #if DEBUG_PRINT_STATE
     printf ("Processing active edges for %x\n", top);
 #endif
 
-    if (fill_rule == CAIRO_FILL_RULE_WINDING) {
-	while (left != NULL) {
-	    int in_out;
-
-	    /* Greedily search for the closing edge, so that we generate the
-	     * maximal span width with the minimal number of trapezoids.
-	     */
-	    in_out = left->edge.dir;
-
-	    /* Check if there is a co-linear edge with an existing trap */
-	    right = left->next;
-	    if (left->deferred_trap.right == NULL) {
-		while (right != NULL && right->deferred_trap.right == NULL)
-		    right = right->next;
-
-		if (right != NULL && edges_colinear (left, right)) {
-		    /* continuation on left */
-		    left->deferred_trap = right->deferred_trap;
-		    right->deferred_trap.right = NULL;
-		}
-	    }
-
-	    /* End all subsumed traps */
-	    right = left->next;
-	    while (right != NULL) {
-		if (right->deferred_trap.right != NULL) {
-		    status = _cairo_bo_edge_end_trap (right, top, traps);
-		    if (unlikely (status))
-			return status;
-		}
-
-		in_out += right->edge.dir;
-		if (in_out == 0) {
-		    cairo_bo_edge_t *next;
-		    cairo_bool_t skip = FALSE;
-
-		    /* skip co-linear edges */
-		    next = right->next;
-		    if (next != NULL)
-			skip = edges_colinear (right, next);
-
-		    if (! skip)
-			break;
-		}
-
-		right = right->next;
+    in_out = 0;
+    left = pos;
+    while (pos != NULL) {
+	if (pos != left && pos->deferred_trap.right) {
+	    if (edges_colinear (left, pos)) {
+		/* continuation on left */
+		assert (left->deferred_trap.right == NULL);
+		left->deferred_trap = pos->deferred_trap;
+		pos->deferred_trap.right = NULL;
+	    } else {
+		status = _cairo_bo_edge_end_trap (pos, top, traps);
+		if (unlikely (status))
+		    return status;
 	    }
-
-	    status = _cairo_bo_edge_start_or_continue_trap (left, right,
-							    top, traps);
-	    if (unlikely (status))
-		return status;
-
-	    left = right;
-	    if (left != NULL)
-		left = left->next;
 	}
-    } else {
-	while (left != NULL) {
-	    int in_out = 0;
-
-	    right = left->next;
-	    while (right != NULL) {
-		if (right->deferred_trap.right != NULL) {
-		    status = _cairo_bo_edge_end_trap (right, top, traps);
-		    if (unlikely (status))
-			return status;
-		}
-
-		if ((in_out++ & 1) == 0) {
-		    cairo_bo_edge_t *next;
-		    cairo_bool_t skip = FALSE;
 
-		    /* skip co-linear edges */
-		    next = right->next;
-		    if (next != NULL)
-			skip = edges_colinear (right, next);
-
-		    if (! skip)
-			break;
-		}
+	in_out += pos->edge.dir;
+	if ((in_out & mask) == 0) {
+	    /* skip co-linear edges */
+	    if (pos->next == NULL || ! edges_colinear (pos, pos->next)) {
+		status = _cairo_bo_edge_start_or_continue_trap (left, pos,
+								top, traps);
+		if (unlikely (status))
+		    return status;
 
-		right = right->next;
+		left = pos->next;
 	    }
-
-	    status = _cairo_bo_edge_start_or_continue_trap (left, right,
-							    top, traps);
-	    if (unlikely (status))
-		return status;
-
-	    left = right;
-	    if (left != NULL)
-		left = left->next;
 	}
+
+	pos = pos->next;
     }
 
     return CAIRO_STATUS_SUCCESS;
@@ -1524,7 +1472,7 @@ _active_edges_to_traps (cairo_bo_edge_t		*left,
 static cairo_status_t
 _cairo_bentley_ottmann_tessellate_bo_edges (cairo_bo_event_t   **start_events,
 					    int			 num_events,
-					    cairo_fill_rule_t	 fill_rule,
+					    unsigned		 fill_rule,
 					    cairo_traps_t	*traps,
 					    int			*num_intersections)
 {
@@ -1536,6 +1484,12 @@ _cairo_bentley_ottmann_tessellate_bo_edges (cairo_bo_event_t   **start_events,
     cairo_bo_edge_t *left, *right;
     cairo_bo_edge_t *e1, *e2;
 
+    /* convert the fill_rule into a winding mask */
+    if (fill_rule == CAIRO_FILL_RULE_WINDING)
+	fill_rule = (unsigned) -1;
+    else
+	fill_rule = 1;
+
 #if DEBUG_EVENTS
     {
 	int i;
@@ -1781,7 +1735,7 @@ _cairo_bentley_ottmann_tessellate_polygon (cairo_traps_t	 *traps,
 	for (y = i = 0; y < ymax && i < num_events; y++) {
 	    cairo_bo_start_event_t *e;
 	    int j = i;
-	    for (e = event_y[y]; e; e = (cairo_bo_start_event_t *)e->edge.next) 
+	    for (e = event_y[y]; e; e = (cairo_bo_start_event_t *)e->edge.next)
 		event_ptrs[i++] = (cairo_bo_event_t *) e;
 	    if (i > j + 1)
 		_cairo_bo_event_queue_sort (event_ptrs+j, i-j);
diff --git a/src/cairo-botor-scan-converter.c b/src/cairo-botor-scan-converter.c
index 0778a5d..cbb752f 100644
--- a/src/cairo-botor-scan-converter.c
+++ b/src/cairo-botor-scan-converter.c
@@ -1397,6 +1397,7 @@ render_rows (cairo_botor_scan_converter_t *self,
 
 	if (x > prev_x) {
 	    spans[num_spans].x = prev_x;
+	    spans[num_spans].inverse = 0;
 	    spans[num_spans].coverage = AREA_TO_ALPHA (cover);
 	    ++num_spans;
 	}
@@ -1413,12 +1414,14 @@ render_rows (cairo_botor_scan_converter_t *self,
 
     if (prev_x <= self->xmax) {
 	spans[num_spans].x = prev_x;
+	spans[num_spans].inverse = 0;
 	spans[num_spans].coverage = AREA_TO_ALPHA (cover);
 	++num_spans;
     }
 
     if (cover && prev_x < self->xmax) {
 	spans[num_spans].x = self->xmax;
+	spans[num_spans].inverse = 1;
 	spans[num_spans].coverage = 0;
 	++num_spans;
     }
@@ -2179,8 +2182,6 @@ _cairo_botor_scan_converter_init (cairo_botor_scan_converter_t *self,
 				  cairo_fill_rule_t fill_rule)
 {
     self->base.destroy     = _cairo_botor_scan_converter_destroy;
-    self->base.add_edge    = _cairo_botor_scan_converter_add_edge;
-    self->base.add_polygon = _cairo_botor_scan_converter_add_polygon;
     self->base.generate    = _cairo_botor_scan_converter_generate;
 
     self->extents   = *extents;
diff --git a/src/cairo-box-private.h b/src/cairo-box-private.h
index 3bced99..d6b9941 100644
--- a/src/cairo-box-private.h
+++ b/src/cairo-box-private.h
@@ -37,6 +37,7 @@
 
 #include "cairo-types-private.h"
 #include "cairo-compiler-private.h"
+#include "cairo-fixed-private.h"
 
 static inline void
 _cairo_box_set (cairo_box_t *box,
@@ -47,6 +48,15 @@ _cairo_box_set (cairo_box_t *box,
     box->p2 = *p2;
 }
 
+static inline void
+_cairo_box_from_integers (cairo_box_t *box, int x, int y, int w, int h)
+{
+    box->p1.x = _cairo_fixed_from_int (x);
+    box->p1.y = _cairo_fixed_from_int (y);
+    box->p2.x = _cairo_fixed_from_int (x + w);
+    box->p2.y = _cairo_fixed_from_int (y + h);
+}
+
 /* assumes box->p1 is top-left, p2 bottom-right */
 static inline void
 _cairo_box_add_point (cairo_box_t *box,
@@ -63,13 +73,49 @@ _cairo_box_add_point (cairo_box_t *box,
 	box->p2.y = point->y;
 }
 
+static inline void
+_cairo_box_add_box (cairo_box_t *box,
+		    const cairo_box_t *add)
+{
+    if (add->p1.x < box->p1.x)
+	box->p1.x = add->p1.x;
+    if (add->p2.x > box->p2.x)
+	box->p2.x = add->p2.x;
+
+    if (add->p1.y < box->p1.y)
+	box->p1.y = add->p1.y;
+    if (add->p2.y > box->p2.y)
+	box->p2.y = add->p2.y;
+}
+
 /* assumes box->p1 is top-left, p2 bottom-right */
 static inline cairo_bool_t
-_cairo_box_contains_point (cairo_box_t *box,
+_cairo_box_contains_point (const cairo_box_t *box,
 			   const cairo_point_t *point)
 {
     return box->p1.x <= point->x  && point->x <= box->p2.x &&
 	box->p1.y <= point->y  && point->y <= box->p2.y;
 }
 
+static inline cairo_bool_t
+_cairo_box_is_pixel_aligned (const cairo_box_t *box)
+{
+#if CAIRO_FIXED_FRAC_BITS <= 8 && 0
+    return ((box->p1.x & CAIRO_FIXED_FRAC_MASK) << 24 |
+	    (box->p1.y & CAIRO_FIXED_FRAC_MASK) << 16 |
+	    (box->p2.x & CAIRO_FIXED_FRAC_MASK) << 8 |
+	    (box->p2.y & CAIRO_FIXED_FRAC_MASK) << 0) == 0;
+#else /* GCC on i7 prefers this variant (bizarrely according to the profiler) */
+    cairo_fixed_t f;
+
+    f = 0;
+    f |= box->p1.x & CAIRO_FIXED_FRAC_MASK;
+    f |= box->p1.y & CAIRO_FIXED_FRAC_MASK;
+    f |= box->p2.x & CAIRO_FIXED_FRAC_MASK;
+    f |= box->p2.y & CAIRO_FIXED_FRAC_MASK;
+
+    return f == 0;
+#endif
+}
+
 #endif /* CAIRO_BOX_H */
diff --git a/src/cairo-boxes-intersect.c b/src/cairo-boxes-intersect.c
index 230c6f0..dd4c241 100644
--- a/src/cairo-boxes-intersect.c
+++ b/src/cairo-boxes-intersect.c
@@ -535,19 +535,44 @@ _cairo_boxes_intersect_with_box (const cairo_boxes_t *boxes,
 				 const cairo_box_t *box,
 				 cairo_boxes_t *out)
 {
-    const struct _cairo_boxes_chunk *chunk;
     cairo_status_t status;
-    int i;
+    int i, j;
+
+    if (out == boxes) { /* inplace update */
+	struct _cairo_boxes_chunk *chunk;
+
+	out->num_boxes = 0;
+	for (chunk = &out->chunks; chunk != NULL; chunk = chunk->next) {
+	    for (i = j = 0; i < chunk->count; i++) {
+		cairo_box_t *b = &chunk->base[i];
+
+		b->p1.x = MAX (b->p1.x, box->p1.x);
+		b->p1.y = MAX (b->p1.y, box->p1.y);
+		b->p2.x = MIN (b->p2.x, box->p2.x);
+		b->p2.y = MIN (b->p2.y, box->p2.y);
+		if (b->p1.x < b->p2.x && b->p1.y < b->p2.y) {
+		    if (i != j)
+			chunk->base[j] = *b;
+		    j++;
+		}
+	    }
+	    /* XXX unlink empty chains? */
+	    chunk->count = j;
+	    out->num_boxes += j;
+	}
+    } else {
+	const struct _cairo_boxes_chunk *chunk;
 
-    _cairo_boxes_clear (out);
-    _cairo_boxes_limit (out, box, 1);
-    for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
-	for (i = 0; i < chunk->count; i++) {
-	    status = _cairo_boxes_add (out,
-				       CAIRO_ANTIALIAS_DEFAULT,
-				       &chunk->base[i]);
-	    if (unlikely (status))
-		return status;
+	_cairo_boxes_clear (out);
+	_cairo_boxes_limit (out, box, 1);
+	for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
+	    for (i = 0; i < chunk->count; i++) {
+		status = _cairo_boxes_add (out,
+					   CAIRO_ANTIALIAS_DEFAULT,
+					   &chunk->base[i]);
+		if (unlikely (status))
+		    return status;
+	    }
 	}
     }
 
diff --git a/src/cairo-boxes-private.h b/src/cairo-boxes-private.h
index 890d1b2..57d1228 100644
--- a/src/cairo-boxes-private.h
+++ b/src/cairo-boxes-private.h
@@ -42,11 +42,14 @@
 
 struct _cairo_boxes_t {
     cairo_status_t status;
+
     cairo_box_t limit;
     const cairo_box_t *limits;
     int num_limits;
+
     int num_boxes;
-    unsigned int is_pixel_aligned : 1;
+
+    unsigned int is_pixel_aligned;
 
     struct _cairo_boxes_chunk {
 	struct _cairo_boxes_chunk *next;
@@ -70,6 +73,10 @@ _cairo_boxes_init_for_array (cairo_boxes_t *boxes,
 			     int num_boxes);
 
 cairo_private void
+_cairo_boxes_init_from_rectangle (cairo_boxes_t *boxes,
+				  int x, int y, int w, int h);
+
+cairo_private void
 _cairo_boxes_limit (cairo_boxes_t	*boxes,
 		    const cairo_box_t	*limits,
 		    int			 num_limits);
@@ -81,7 +88,7 @@ _cairo_boxes_add (cairo_boxes_t *boxes,
 
 cairo_private void
 _cairo_boxes_extents (const cairo_boxes_t *boxes,
-		      cairo_rectangle_int_t *extents);
+		      cairo_box_t *box);
 
 cairo_private cairo_box_t *
 _cairo_boxes_to_array (const cairo_boxes_t *boxes,
@@ -104,6 +111,11 @@ _cairo_boxes_intersect (const cairo_boxes_t *a,
 cairo_private void
 _cairo_boxes_clear (cairo_boxes_t *boxes);
 
+cairo_private_no_warn cairo_bool_t
+_cairo_boxes_for_each_box (cairo_boxes_t *boxes,
+			   cairo_bool_t (*func) (cairo_box_t *box, void *data),
+			   void *data);
+
 cairo_private void
 _cairo_boxes_fini (cairo_boxes_t *boxes);
 
diff --git a/src/cairo-boxes.c b/src/cairo-boxes.c
index 130a44c..182601a 100644
--- a/src/cairo-boxes.c
+++ b/src/cairo-boxes.c
@@ -33,6 +33,7 @@
 
 #include "cairoint.h"
 
+#include "cairo-box-private.h"
 #include "cairo-boxes-private.h"
 #include "cairo-error-private.h"
 
@@ -53,6 +54,16 @@ _cairo_boxes_init (cairo_boxes_t *boxes)
 }
 
 void
+_cairo_boxes_init_from_rectangle (cairo_boxes_t *boxes,
+				  int x, int y, int w, int h)
+{
+    _cairo_boxes_init (boxes);
+
+    _cairo_box_from_integers (&boxes->chunks.base[0], x, y, w, h);
+    boxes->num_boxes = 1;
+}
+
+void
 _cairo_boxes_init_with_clip (cairo_boxes_t *boxes,
 			     cairo_clip_t *clip)
 {
@@ -154,13 +165,8 @@ _cairo_boxes_add_internal (cairo_boxes_t *boxes,
     chunk->base[chunk->count++] = *box;
     boxes->num_boxes++;
 
-    if (boxes->is_pixel_aligned) {
-	boxes->is_pixel_aligned =
-	    _cairo_fixed_is_integer (box->p1.x) &&
-	    _cairo_fixed_is_integer (box->p1.y) &&
-	    _cairo_fixed_is_integer (box->p2.x) &&
-	    _cairo_fixed_is_integer (box->p2.y);
-    }
+    if (boxes->is_pixel_aligned)
+	boxes->is_pixel_aligned = _cairo_box_is_pixel_aligned (box);
 }
 
 cairo_status_t
@@ -261,38 +267,34 @@ _cairo_boxes_add (cairo_boxes_t *boxes,
 
 void
 _cairo_boxes_extents (const cairo_boxes_t *boxes,
-		      cairo_rectangle_int_t *extents)
+		      cairo_box_t *box)
 {
     const struct _cairo_boxes_chunk *chunk;
-    cairo_box_t box;
+    cairo_box_t b;
     int i;
 
     if (boxes->num_boxes == 0) {
-	extents->x = extents->y = extents->width = extents->height = 0;
+	box->p1.x = box->p1.y = box->p2.x = box->p2.y = 0;
 	return;
     }
 
-    box.p1.y = box.p1.x = INT_MAX;
-    box.p2.y = box.p2.x = INT_MIN;
-
+    b = boxes->chunks.base[0];
     for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
-	const cairo_box_t *b = chunk->base;
 	for (i = 0; i < chunk->count; i++) {
-	    if (b[i].p1.x < box.p1.x)
-		box.p1.x = b[i].p1.x;
+	    if (chunk->base[i].p1.x < b.p1.x)
+		b.p1.x = chunk->base[i].p1.x;
 
-	    if (b[i].p1.y < box.p1.y)
-		box.p1.y = b[i].p1.y;
+	    if (chunk->base[i].p1.y < b.p1.y)
+		b.p1.y = chunk->base[i].p1.y;
 
-	    if (b[i].p2.x > box.p2.x)
-		box.p2.x = b[i].p2.x;
+	    if (chunk->base[i].p2.x > b.p2.x)
+		b.p2.x = chunk->base[i].p2.x;
 
-	    if (b[i].p2.y > box.p2.y)
-		box.p2.y = b[i].p2.y;
+	    if (chunk->base[i].p2.y > b.p2.y)
+		b.p2.y = chunk->base[i].p2.y;
 	}
     }
-
-    _cairo_box_round_to_rectangle (&box, extents);
+    *box = b;
 }
 
 void
@@ -354,17 +356,38 @@ _cairo_boxes_fini (cairo_boxes_t *boxes)
     }
 }
 
+cairo_bool_t
+_cairo_boxes_for_each_box (cairo_boxes_t *boxes,
+			   cairo_bool_t (*func) (cairo_box_t *box, void *data),
+			   void *data)
+{
+    struct _cairo_boxes_chunk *chunk;
+    int i;
+
+    for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
+	for (i = 0; i < chunk->count; i++)
+	    if (! func (&chunk->base[i], data))
+		return FALSE;
+    }
+
+    return TRUE;
+}
+
+
 void
 _cairo_debug_print_boxes (FILE *stream, const cairo_boxes_t *boxes)
 {
-    cairo_rectangle_int_t extents;
     const struct _cairo_boxes_chunk *chunk;
+    cairo_box_t extents;
     int i;
 
     _cairo_boxes_extents (boxes, &extents);
-    fprintf (stream, "boxes x %d: (%d, %d) x (%d, %d)\n",
+    fprintf (stream, "boxes x %d: (%f, %f) x (%f, %f)\n",
 	     boxes->num_boxes,
-	     extents.x, extents.y, extents.width, extents.height);
+	     _cairo_fixed_to_double (extents.p1.x),
+	     _cairo_fixed_to_double (extents.p1.y),
+	     _cairo_fixed_to_double (extents.p2.x),
+	     _cairo_fixed_to_double (extents.p2.y));
 
     for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
 	for (i = 0; i < chunk->count; i++) {
diff --git a/src/cairo-cff-subset.c b/src/cairo-cff-subset.c
index 6c71795..3ee3ef3 100644
--- a/src/cairo-cff-subset.c
+++ b/src/cairo-cff-subset.c
@@ -42,6 +42,8 @@
 
 #define _BSD_SOURCE /* for snprintf(), strdup() */
 #include "cairoint.h"
+
+#include "cairo-array-private.h"
 #include "cairo-error-private.h"
 
 #if CAIRO_HAS_FONT_SUBSET
@@ -2897,7 +2899,7 @@ cairo_bool_t
 _cairo_cff_scaled_font_is_cid_cff (cairo_scaled_font_t *scaled_font)
 {
     const cairo_scaled_font_backend_t *backend;
-    cairo_status_t status;
+    cairo_int_status_t status;
     unsigned char *data;
     unsigned long data_length;
     unsigned char *current_ptr;
@@ -2916,7 +2918,7 @@ _cairo_cff_scaled_font_is_cid_cff (cairo_scaled_font_t *scaled_font)
     /* Try to load an OpenType/CFF font */
     if (backend->load_truetype_table &&
 	(status = backend->load_truetype_table (scaled_font, TT_TAG_CFF,
-						0, NULL, &data_length)) == CAIRO_STATUS_SUCCESS)
+						0, NULL, &data_length)) == CAIRO_INT_STATUS_SUCCESS)
     {
 	data = malloc (data_length);
 	if (unlikely (data == NULL)) {
@@ -2933,7 +2935,7 @@ _cairo_cff_scaled_font_is_cid_cff (cairo_scaled_font_t *scaled_font)
     if (status == CAIRO_INT_STATUS_UNSUPPORTED &&
 	backend->load_type1_data &&
 	(status = backend->load_type1_data (scaled_font,
-					    0, NULL, &data_length)) == CAIRO_STATUS_SUCCESS)
+					    0, NULL, &data_length)) == CAIRO_INT_STATUS_SUCCESS)
     {
 	data = malloc (data_length);
 	if (unlikely (data == NULL)) {
diff --git a/src/cairo-clip-boxes.c b/src/cairo-clip-boxes.c
index e18c2f8..3b8265b 100644
--- a/src/cairo-clip-boxes.c
+++ b/src/cairo-clip-boxes.c
@@ -40,6 +40,8 @@
  */
 
 #include "cairoint.h"
+
+#include "cairo-box-private.h"
 #include "cairo-clip-private.h"
 #include "cairo-error-private.h"
 #include "cairo-freed-pool-private.h"
@@ -62,7 +64,6 @@ pot (int v)
     return v;
 }
 
-
 static cairo_bool_t
 _cairo_clip_contains_rectangle_box (const cairo_clip_t *clip,
 				    const cairo_rectangle_int_t *rect,
@@ -90,7 +91,6 @@ _cairo_clip_contains_rectangle_box (const cairo_clip_t *clip,
     }
 
     /* Check for a clip-box that wholly contains the rectangle */
-    assert (clip->num_boxes);
     for (i = 0; i < clip->num_boxes; i++) {
 	if (box->p1.x >= clip->boxes[i].p1.x &&
 	    box->p1.y >= clip->boxes[i].p1.y &&
@@ -176,6 +176,8 @@ _cairo_clip_intersect_rectangle_box (cairo_clip_t *clip,
 	    if (! _cairo_rectangle_intersect (&clip->extents, r))
 		clip = _cairo_clip_set_all_clipped (clip);
 	}
+	if (clip->path == NULL)
+	    clip->is_region = _cairo_box_is_pixel_aligned (box);
 	return clip;
     }
 
@@ -269,6 +271,7 @@ _cairo_clip_intersect_boxes (cairo_clip_t *clip,
 			     const cairo_boxes_t *boxes)
 {
     cairo_boxes_t clip_boxes;
+    cairo_box_t limits;
     cairo_rectangle_int_t extents;
 
     if (_cairo_clip_is_all_clipped (clip))
@@ -301,10 +304,11 @@ _cairo_clip_intersect_boxes (cairo_clip_t *clip,
     } else {
 	clip->boxes = _cairo_boxes_to_array (boxes, &clip->num_boxes, TRUE);
     }
-    _cairo_boxes_extents (boxes, &extents);
+    _cairo_boxes_extents (boxes, &limits);
     if (boxes == &clip_boxes)
 	_cairo_boxes_fini (&clip_boxes);
 
+    _cairo_box_round_to_rectangle (&limits, &extents);
     if (clip->path == NULL)
 	clip->extents = extents;
     else if (! _cairo_rectangle_intersect (&clip->extents, &extents))
@@ -557,37 +561,10 @@ _cairo_clip_reduce_for_composite (const cairo_clip_t *clip,
     return _cairo_clip_reduce_to_rectangle (clip, r);
 }
 
-cairo_status_t
-_cairo_clip_to_boxes (cairo_clip_t *clip,
-		      cairo_boxes_t *boxes)
-{
-    _cairo_boxes_init_for_array (boxes, clip->boxes, clip->num_boxes);
-
-    if (clip->path == NULL) {
-	cairo_box_t *src = clip->boxes;
-	int i;
-
-	clip->boxes = _cairo_malloc_ab (clip->num_boxes, sizeof (cairo_box_t));
-	if (clip->boxes == NULL) {
-	    clip->boxes = src;
-	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-	}
-
-	for (i = 0; i < clip->num_boxes; i++) {
-	    clip->boxes[i].p1.x = _cairo_fixed_floor (src[i].p1.x);
-	    clip->boxes[i].p1.y = _cairo_fixed_floor (src[i].p1.y);
-	    clip->boxes[i].p2.x = _cairo_fixed_ceil (src[i].p2.x);
-	    clip->boxes[i].p2.y = _cairo_fixed_ceil (src[i].p2.y);
-	}
-    }
-
-    return CAIRO_STATUS_SUCCESS;
-
-}
-
 cairo_clip_t *
 _cairo_clip_from_boxes (const cairo_boxes_t *boxes)
 {
+    cairo_box_t extents;
     cairo_clip_t *clip = _cairo_clip_create ();
     if (clip == NULL)
 	return _cairo_clip_set_all_clipped (clip);
@@ -603,7 +580,8 @@ _cairo_clip_from_boxes (const cairo_boxes_t *boxes)
 	    return _cairo_clip_set_all_clipped (clip);
     }
 
-    _cairo_boxes_extents (boxes, &clip->extents);
+    _cairo_boxes_extents (boxes, &extents);
+    _cairo_box_round_to_rectangle (&extents, &clip->extents);
 
     return clip;
 }
diff --git a/src/cairo-clip-private.h b/src/cairo-clip-private.h
index 3ebcb0e..7cbef24 100644
--- a/src/cairo-clip-private.h
+++ b/src/cairo-clip-private.h
@@ -40,6 +40,7 @@
 #include "cairo-types-private.h"
 
 #include "cairo-boxes-private.h"
+#include "cairo-error-private.h"
 #include "cairo-compiler-private.h"
 #include "cairo-error-private.h"
 #include "cairo-path-fixed-private.h"
@@ -160,14 +161,30 @@ _cairo_clip_get_extents (const cairo_clip_t *clip);
 cairo_private cairo_surface_t *
 _cairo_clip_get_surface (const cairo_clip_t *clip, cairo_surface_t *dst, int *tx, int *ty);
 
+cairo_private cairo_surface_t *
+_cairo_clip_get_image (const cairo_clip_t *clip,
+		       cairo_surface_t *target,
+		       const cairo_rectangle_int_t *extents);
+
 cairo_private cairo_status_t
 _cairo_clip_combine_with_surface (const cairo_clip_t *clip,
 				  cairo_surface_t *dst,
 				  int dst_x, int dst_y);
 
-cairo_private cairo_status_t
-_cairo_clip_to_boxes (cairo_clip_t *clip,
-		      cairo_boxes_t *boxes);
+static inline void
+_cairo_clip_steal_boxes (cairo_clip_t *clip, cairo_boxes_t *boxes)
+{
+    _cairo_boxes_init_for_array (boxes, clip->boxes, clip->num_boxes);
+    clip->boxes = NULL;
+    clip->num_boxes = 0;
+}
+
+static inline void
+_cairo_clip_unsteal_boxes (cairo_clip_t *clip, cairo_boxes_t *boxes)
+{
+    clip->boxes = boxes->chunks.base;
+    clip->num_boxes = boxes->num_boxes;
+}
 
 cairo_private cairo_clip_t *
 _cairo_clip_from_boxes (const cairo_boxes_t *boxes);
diff --git a/src/cairo-clip-region.c b/src/cairo-clip-region.c
index 28a0d4b..e3f4891 100644
--- a/src/cairo-clip-region.c
+++ b/src/cairo-clip-region.c
@@ -105,10 +105,16 @@ _cairo_clip_is_region (const cairo_clip_t *clip)
     if (clip == NULL)
 	return TRUE;
 
+    if (clip->is_region)
+	return TRUE;
+
     /* XXX Geometric reduction? */
 
     if (clip->path)
-	    return FALSE;
+	return FALSE;
+
+    if (clip->num_boxes == 0)
+	return TRUE;
 
     if (clip->region == NULL)
 	_cairo_clip_extract_region ((cairo_clip_t *) clip);
diff --git a/src/cairo-clip-surface.c b/src/cairo-clip-surface.c
index 79e6a62..e1e9312 100644
--- a/src/cairo-clip-surface.c
+++ b/src/cairo-clip-surface.c
@@ -103,8 +103,7 @@ _cairo_clip_get_surface (const cairo_clip_t *clip,
 						   CAIRO_CONTENT_ALPHA,
 						   clip->extents.width,
 						   clip->extents.height,
-						   CAIRO_COLOR_TRANSPARENT,
-						   TRUE);
+						   CAIRO_COLOR_WHITE);
     if (unlikely (surface->status))
 	return surface;
 
@@ -114,12 +113,7 @@ _cairo_clip_get_surface (const cairo_clip_t *clip,
     copy_path = copy->path;
     copy->path = NULL;
 
-    assert (copy->num_boxes);
-    status = _cairo_surface_paint (surface,
-				   CAIRO_OPERATOR_ADD,
-				   &_cairo_pattern_white.base,
-				   copy);
-
+    status = CAIRO_STATUS_SUCCESS;
     clip_path = copy_path;
     while (status == CAIRO_STATUS_SUCCESS && clip_path) {
 	status = _cairo_surface_fill (surface,
@@ -140,3 +134,32 @@ _cairo_clip_get_surface (const cairo_clip_t *clip,
     *ty = clip->extents.y;
     return surface;
 }
+
+cairo_surface_t *
+_cairo_clip_get_image (const cairo_clip_t *clip,
+		       cairo_surface_t *target,
+		       const cairo_rectangle_int_t *extents)
+{
+    cairo_surface_t *surface;
+    cairo_status_t status;
+
+    surface = cairo_surface_create_similar_image (target,
+						  CAIRO_FORMAT_A8,
+						  extents->width,
+						  extents->height);
+    if (unlikely (surface->status))
+	return surface;
+
+    status = _cairo_surface_paint (surface, CAIRO_OPERATOR_SOURCE,
+				   &_cairo_pattern_white.base, NULL);
+    if (likely (status == CAIRO_STATUS_SUCCESS))
+	status = _cairo_clip_combine_with_surface (clip, surface,
+						   extents->x, extents->y);
+
+    if (unlikely (status)) {
+	cairo_surface_destroy (surface);
+	surface = _cairo_surface_create_in_error (status);
+    }
+
+    return surface;
+}
diff --git a/src/cairo-clip-tor-scan-converter.c b/src/cairo-clip-tor-scan-converter.c
new file mode 100644
index 0000000..e32a5a9
--- /dev/null
+++ b/src/cairo-clip-tor-scan-converter.c
@@ -0,0 +1,1845 @@
+/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
+/* glitter-paths - polygon scan converter
+ *
+ * Copyright (c) 2008  M Joonas Pihlaja
+ * Copyright (c) 2007  David Turner
+ *
+ * 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.
+ */
+/* This is the Glitter paths scan converter incorporated into cairo.
+ * The source is from commit 734c53237a867a773640bd5b64816249fa1730f8
+ * of
+ *
+ *   http://gitweb.freedesktop.org/?p=users/joonas/glitter-paths
+ */
+/* Glitter-paths is a stand alone polygon rasteriser derived from
+ * David Turner's reimplementation of Tor Anderssons's 15x17
+ * supersampling rasteriser from the Apparition graphics library.  The
+ * main new feature here is cheaply choosing per-scan line between
+ * doing fully analytical coverage computation for an entire row at a
+ * time vs. using a supersampling approach.
+ *
+ * David Turner's code can be found at
+ *
+ *   http://david.freetype.org/rasterizer-shootout/raster-comparison-20070813.tar.bz2
+ *
+ * In particular this file incorporates large parts of ftgrays_tor10.h
+ * from raster-comparison-20070813.tar.bz2
+ */
+/* Overview
+ *
+ * A scan converter's basic purpose to take polygon edges and convert
+ * them into an RLE compressed A8 mask.  This one works in two phases:
+ * gathering edges and generating spans.
+ *
+ * 1) As the user feeds the scan converter edges they are vertically
+ * clipped and bucketted into a _polygon_ data structure.  The edges
+ * are also snapped from the user's coordinates to the subpixel grid
+ * coordinates used during scan conversion.
+ *
+ *     user
+ *      |
+ *      | edges
+ *      V
+ *    polygon buckets
+ *
+ * 2) Generating spans works by performing a vertical sweep of pixel
+ * rows from top to bottom and maintaining an _active_list_ of edges
+ * that intersect the row.  From the active list the fill rule
+ * determines which edges are the left and right edges of the start of
+ * each span, and their contribution is then accumulated into a pixel
+ * coverage list (_cell_list_) as coverage deltas.  Once the coverage
+ * deltas of all edges are known we can form spans of constant pixel
+ * coverage by summing the deltas during a traversal of the cell list.
+ * At the end of a pixel row the cell list is sent to a coverage
+ * blitter for rendering to some target surface.
+ *
+ * The pixel coverages are computed by either supersampling the row
+ * and box filtering a mono rasterisation, or by computing the exact
+ * coverages of edges in the active list.  The supersampling method is
+ * used whenever some edge starts or stops within the row or there are
+ * edge intersections in the row.
+ *
+ *   polygon bucket for       \
+ *   current pixel row        |
+ *      |                     |
+ *      | activate new edges  |  Repeat GRID_Y times if we
+ *      V                     \  are supersampling this row,
+ *   active list              /  or just once if we're computing
+ *      |                     |  analytical coverage.
+ *      | coverage deltas     |
+ *      V                     |
+ *   pixel coverage list     /
+ *      |
+ *      V
+ *   coverage blitter
+ */
+#include "cairoint.h"
+#include "cairo-spans-private.h"
+#include "cairo-error-private.h"
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <setjmp.h>
+
+/* The input coordinate scale and the rasterisation grid scales. */
+#define GLITTER_INPUT_BITS CAIRO_FIXED_FRAC_BITS
+#define GRID_X_BITS CAIRO_FIXED_FRAC_BITS
+#define GRID_Y 15
+
+/* Set glitter up to use a cairo span renderer to do the coverage
+ * blitting. */
+struct pool;
+struct cell_list;
+
+/*-------------------------------------------------------------------------
+ * glitter-paths.h
+ */
+
+/* "Input scaled" numbers are fixed precision reals with multiplier
+ * 2**GLITTER_INPUT_BITS.  Input coordinates are given to glitter as
+ * pixel scaled numbers.  These get converted to the internal grid
+ * scaled numbers as soon as possible. Internal overflow is possible
+ * if GRID_X/Y inside glitter-paths.c is larger than
+ * 1<<GLITTER_INPUT_BITS. */
+#ifndef GLITTER_INPUT_BITS
+#  define GLITTER_INPUT_BITS 8
+#endif
+#define GLITTER_INPUT_SCALE (1<<GLITTER_INPUT_BITS)
+typedef int glitter_input_scaled_t;
+
+/* Opaque type for scan converting. */
+typedef struct glitter_scan_converter glitter_scan_converter_t;
+
+/*-------------------------------------------------------------------------
+ * glitter-paths.c: Implementation internal types
+ */
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+/* All polygon coordinates are snapped onto a subsample grid. "Grid
+ * scaled" numbers are fixed precision reals with multiplier GRID_X or
+ * GRID_Y. */
+typedef int grid_scaled_t;
+typedef int grid_scaled_x_t;
+typedef int grid_scaled_y_t;
+
+/* Default x/y scale factors.
+ *  You can either define GRID_X/Y_BITS to get a power-of-two scale
+ *  or define GRID_X/Y separately. */
+#if !defined(GRID_X) && !defined(GRID_X_BITS)
+#  define GRID_X_BITS 8
+#endif
+#if !defined(GRID_Y) && !defined(GRID_Y_BITS)
+#  define GRID_Y 15
+#endif
+
+/* Use GRID_X/Y_BITS to define GRID_X/Y if they're available. */
+#ifdef GRID_X_BITS
+#  define GRID_X (1 << GRID_X_BITS)
+#endif
+#ifdef GRID_Y_BITS
+#  define GRID_Y (1 << GRID_Y_BITS)
+#endif
+
+/* The GRID_X_TO_INT_FRAC macro splits a grid scaled coordinate into
+ * integer and fractional parts. The integer part is floored. */
+#if defined(GRID_X_TO_INT_FRAC)
+  /* do nothing */
+#elif defined(GRID_X_BITS)
+#  define GRID_X_TO_INT_FRAC(x, i, f) \
+	_GRID_TO_INT_FRAC_shift(x, i, f, GRID_X_BITS)
+#else
+#  define GRID_X_TO_INT_FRAC(x, i, f) \
+	_GRID_TO_INT_FRAC_general(x, i, f, GRID_X)
+#endif
+
+#define _GRID_TO_INT_FRAC_general(t, i, f, m) do {	\
+    (i) = (t) / (m);					\
+    (f) = (t) % (m);					\
+    if ((f) < 0) {					\
+	--(i);						\
+	(f) += (m);					\
+    }							\
+} while (0)
+
+#define _GRID_TO_INT_FRAC_shift(t, i, f, b) do {	\
+    (f) = (t) & ((1 << (b)) - 1);			\
+    (i) = (t) >> (b);					\
+} while (0)
+
+/* A grid area is a real in [0,1] scaled by 2*GRID_X*GRID_Y.  We want
+ * to be able to represent exactly areas of subpixel trapezoids whose
+ * vertices are given in grid scaled coordinates.  The scale factor
+ * comes from needing to accurately represent the area 0.5*dx*dy of a
+ * triangle with base dx and height dy in grid scaled numbers. */
+typedef int grid_area_t;
+#define GRID_XY (2*GRID_X*GRID_Y) /* Unit area on the grid. */
+
+/* GRID_AREA_TO_ALPHA(area): map [0,GRID_XY] to [0,255]. */
+#if GRID_XY == 510
+#  define GRID_AREA_TO_ALPHA(c)	  (((c)+1) >> 1)
+#elif GRID_XY == 255
+#  define  GRID_AREA_TO_ALPHA(c)  (c)
+#elif GRID_XY == 64
+#  define  GRID_AREA_TO_ALPHA(c)  (((c) << 2) | -(((c) & 0x40) >> 6))
+#elif GRID_XY == 128
+#  define  GRID_AREA_TO_ALPHA(c)  ((((c) << 1) | -((c) >> 7)) & 255)
+#elif GRID_XY == 256
+#  define  GRID_AREA_TO_ALPHA(c)  (((c) | -((c) >> 8)) & 255)
+#elif GRID_XY == 15
+#  define  GRID_AREA_TO_ALPHA(c)  (((c) << 4) + (c))
+#elif GRID_XY == 2*256*15
+#  define  GRID_AREA_TO_ALPHA(c)  (((c) + ((c)<<4) + 256) >> 9)
+#else
+#  define  GRID_AREA_TO_ALPHA(c)  (((c)*255 + GRID_XY/2) / GRID_XY)
+#endif
+
+#define UNROLL3(x) x x x
+
+struct quorem {
+    int32_t quo;
+    int32_t rem;
+};
+
+/* Header for a chunk of memory in a memory pool. */
+struct _pool_chunk {
+    /* # bytes used in this chunk. */
+    size_t size;
+
+    /* # bytes total in this chunk */
+    size_t capacity;
+
+    /* Pointer to the previous chunk or %NULL if this is the sentinel
+     * chunk in the pool header. */
+    struct _pool_chunk *prev_chunk;
+
+    /* Actual data starts here.	 Well aligned for pointers. */
+};
+
+/* A memory pool.  This is supposed to be embedded on the stack or
+ * within some other structure.	 It may optionally be followed by an
+ * embedded array from which requests are fulfilled until
+ * malloc needs to be called to allocate a first real chunk. */
+struct pool {
+    /* Chunk we're allocating from. */
+    struct _pool_chunk *current;
+
+    jmp_buf *jmp;
+
+    /* Free list of previously allocated chunks.  All have >= default
+     * capacity. */
+    struct _pool_chunk *first_free;
+
+    /* The default capacity of a chunk. */
+    size_t default_capacity;
+
+    /* Header for the sentinel chunk.  Directly following the pool
+     * struct should be some space for embedded elements from which
+     * the sentinel chunk allocates from. */
+    struct _pool_chunk sentinel[1];
+};
+
+/* A polygon edge. */
+struct edge {
+    /* Next in y-bucket or active list. */
+    struct edge *next;
+
+    /* Current x coordinate while the edge is on the active
+     * list. Initialised to the x coordinate of the top of the
+     * edge. The quotient is in grid_scaled_x_t units and the
+     * remainder is mod dy in grid_scaled_y_t units.*/
+    struct quorem x;
+
+    /* Advance of the current x when moving down a subsample line. */
+    struct quorem dxdy;
+
+    /* Advance of the current x when moving down a full pixel
+     * row. Only initialised when the height of the edge is large
+     * enough that there's a chance the edge could be stepped by a
+     * full row's worth of subsample rows at a time. */
+    struct quorem dxdy_full;
+
+    /* The clipped y of the top of the edge. */
+    grid_scaled_y_t ytop;
+
+    /* y2-y1 after orienting the edge downwards.  */
+    grid_scaled_y_t dy;
+
+    /* Number of subsample rows remaining to scan convert of this
+     * edge. */
+    grid_scaled_y_t height_left;
+
+    /* Original sign of the edge: +1 for downwards, -1 for upwards
+     * edges.  */
+    int dir;
+    int vertical;
+    int clip;
+};
+
+/* Number of subsample rows per y-bucket. Must be GRID_Y. */
+#define EDGE_Y_BUCKET_HEIGHT GRID_Y
+
+#define EDGE_Y_BUCKET_INDEX(y, ymin) (((y) - (ymin))/EDGE_Y_BUCKET_HEIGHT)
+
+/* A collection of sorted and vertically clipped edges of the polygon.
+ * Edges are moved from the polygon to an active list while scan
+ * converting. */
+struct polygon {
+    /* The vertical clip extents. */
+    grid_scaled_y_t ymin, ymax;
+
+    /* Array of edges all starting in the same bucket.	An edge is put
+     * into bucket EDGE_BUCKET_INDEX(edge->ytop, polygon->ymin) when
+     * it is added to the polygon. */
+    struct edge **y_buckets;
+    struct edge *y_buckets_embedded[64];
+
+    struct {
+	struct pool base[1];
+	struct edge embedded[32];
+    } edge_pool;
+};
+
+/* A cell records the effect on pixel coverage of polygon edges
+ * passing through a pixel.  It contains two accumulators of pixel
+ * coverage.
+ *
+ * Consider the effects of a polygon edge on the coverage of a pixel
+ * it intersects and that of the following one.  The coverage of the
+ * following pixel is the height of the edge multiplied by the width
+ * of the pixel, and the coverage of the pixel itself is the area of
+ * the trapezoid formed by the edge and the right side of the pixel.
+ *
+ * +-----------------------+-----------------------+
+ * |                       |                       |
+ * |                       |                       |
+ * |_______________________|_______________________|
+ * |   \...................|.......................|\
+ * |    \..................|.......................| |
+ * |     \.................|.......................| |
+ * |      \....covered.....|.......................| |
+ * |       \....area.......|.......................| } covered height
+ * |        \..............|.......................| |
+ * |uncovered\.............|.......................| |
+ * |  area    \............|.......................| |
+ * |___________\...........|.......................|/
+ * |                       |                       |
+ * |                       |                       |
+ * |                       |                       |
+ * +-----------------------+-----------------------+
+ *
+ * Since the coverage of the following pixel will always be a multiple
+ * of the width of the pixel, we can store the height of the covered
+ * area instead.  The coverage of the pixel itself is the total
+ * coverage minus the area of the uncovered area to the left of the
+ * edge.  As it's faster to compute the uncovered area we only store
+ * that and subtract it from the total coverage later when forming
+ * spans to blit.
+ *
+ * The heights and areas are signed, with left edges of the polygon
+ * having positive sign and right edges having negative sign.  When
+ * two edges intersect they swap their left/rightness so their
+ * contribution above and below the intersection point must be
+ * computed separately. */
+struct cell {
+    struct cell		*next;
+    int			 x;
+    grid_area_t		 uncovered_area;
+    grid_scaled_y_t	 covered_height;
+    grid_scaled_y_t	 clipped_height;
+};
+
+/* A cell list represents the scan line sparsely as cells ordered by
+ * ascending x.  It is geared towards scanning the cells in order
+ * using an internal cursor. */
+struct cell_list {
+    /* Sentinel nodes */
+    struct cell head, tail;
+
+    /* Cursor state for iterating through the cell list. */
+    struct cell *cursor;
+
+    /* Cells in the cell list are owned by the cell list and are
+     * allocated from this pool.  */
+    struct {
+	struct pool base[1];
+	struct cell embedded[32];
+    } cell_pool;
+};
+
+struct cell_pair {
+    struct cell *cell1;
+    struct cell *cell2;
+};
+
+/* The active list contains edges in the current scan line ordered by
+ * the x-coordinate of the intercept of the edge and the scan line. */
+struct active_list {
+    /* Leftmost edge on the current scan line. */
+    struct edge *head;
+
+    /* A lower bound on the height of the active edges is used to
+     * estimate how soon some active edge ends.	 We can't advance the
+     * scan conversion by a full pixel row if an edge ends somewhere
+     * within it. */
+    grid_scaled_y_t min_height;
+};
+
+struct glitter_scan_converter {
+    struct polygon	polygon[1];
+    struct active_list	active[1];
+    struct cell_list	coverages[1];
+
+    /* Clip box. */
+    grid_scaled_y_t ymin, ymax;
+};
+
+/* Compute the floored division a/b. Assumes / and % perform symmetric
+ * division. */
+inline static struct quorem
+floored_divrem(int a, int b)
+{
+    struct quorem qr;
+    qr.quo = a/b;
+    qr.rem = a%b;
+    if ((a^b)<0 && qr.rem) {
+	qr.quo -= 1;
+	qr.rem += b;
+    }
+    return qr;
+}
+
+/* Compute the floored division (x*a)/b. Assumes / and % perform symmetric
+ * division. */
+static struct quorem
+floored_muldivrem(int x, int a, int b)
+{
+    struct quorem qr;
+    long long xa = (long long)x*a;
+    qr.quo = xa/b;
+    qr.rem = xa%b;
+    if ((xa>=0) != (b>=0) && qr.rem) {
+	qr.quo -= 1;
+	qr.rem += b;
+    }
+    return qr;
+}
+
+static struct _pool_chunk *
+_pool_chunk_init(
+    struct _pool_chunk *p,
+    struct _pool_chunk *prev_chunk,
+    size_t capacity)
+{
+    p->prev_chunk = prev_chunk;
+    p->size = 0;
+    p->capacity = capacity;
+    return p;
+}
+
+static struct _pool_chunk *
+_pool_chunk_create(struct pool *pool, size_t size)
+{
+    struct _pool_chunk *p;
+
+    p = malloc(size + sizeof(struct _pool_chunk));
+    if (unlikely (NULL == p))
+	longjmp (*pool->jmp, _cairo_error (CAIRO_STATUS_NO_MEMORY));
+
+    return _pool_chunk_init(p, pool->current, size);
+}
+
+static void
+pool_init(struct pool *pool,
+	  jmp_buf *jmp,
+	  size_t default_capacity,
+	  size_t embedded_capacity)
+{
+    pool->jmp = jmp;
+    pool->current = pool->sentinel;
+    pool->first_free = NULL;
+    pool->default_capacity = default_capacity;
+    _pool_chunk_init(pool->sentinel, NULL, embedded_capacity);
+}
+
+static void
+pool_fini(struct pool *pool)
+{
+    struct _pool_chunk *p = pool->current;
+    do {
+	while (NULL != p) {
+	    struct _pool_chunk *prev = p->prev_chunk;
+	    if (p != pool->sentinel)
+		free(p);
+	    p = prev;
+	}
+	p = pool->first_free;
+	pool->first_free = NULL;
+    } while (NULL != p);
+}
+
+/* Satisfy an allocation by first allocating a new large enough chunk
+ * and adding it to the head of the pool's chunk list. This function
+ * is called as a fallback if pool_alloc() couldn't do a quick
+ * allocation from the current chunk in the pool. */
+static void *
+_pool_alloc_from_new_chunk(
+    struct pool *pool,
+    size_t size)
+{
+    struct _pool_chunk *chunk;
+    void *obj;
+    size_t capacity;
+
+    /* If the allocation is smaller than the default chunk size then
+     * try getting a chunk off the free list.  Force alloc of a new
+     * chunk for large requests. */
+    capacity = size;
+    chunk = NULL;
+    if (size < pool->default_capacity) {
+	capacity = pool->default_capacity;
+	chunk = pool->first_free;
+	if (chunk) {
+	    pool->first_free = chunk->prev_chunk;
+	    _pool_chunk_init(chunk, pool->current, chunk->capacity);
+	}
+    }
+
+    if (NULL == chunk)
+	chunk = _pool_chunk_create (pool, capacity);
+    pool->current = chunk;
+
+    obj = ((unsigned char*)chunk + sizeof(*chunk) + chunk->size);
+    chunk->size += size;
+    return obj;
+}
+
+/* Allocate size bytes from the pool.  The first allocated address
+ * returned from a pool is aligned to sizeof(void*).  Subsequent
+ * addresses will maintain alignment as long as multiples of void* are
+ * allocated.  Returns the address of a new memory area or %NULL on
+ * allocation failures.	 The pool retains ownership of the returned
+ * memory. */
+inline static void *
+pool_alloc (struct pool *pool, size_t size)
+{
+    struct _pool_chunk *chunk = pool->current;
+
+    if (size <= chunk->capacity - chunk->size) {
+	void *obj = ((unsigned char*)chunk + sizeof(*chunk) + chunk->size);
+	chunk->size += size;
+	return obj;
+    } else {
+	return _pool_alloc_from_new_chunk(pool, size);
+    }
+}
+
+/* Relinquish all pool_alloced memory back to the pool. */
+static void
+pool_reset (struct pool *pool)
+{
+    /* Transfer all used chunks to the chunk free list. */
+    struct _pool_chunk *chunk = pool->current;
+    if (chunk != pool->sentinel) {
+	while (chunk->prev_chunk != pool->sentinel) {
+	    chunk = chunk->prev_chunk;
+	}
+	chunk->prev_chunk = pool->first_free;
+	pool->first_free = pool->current;
+    }
+    /* Reset the sentinel as the current chunk. */
+    pool->current = pool->sentinel;
+    pool->sentinel->size = 0;
+}
+
+/* Rewinds the cell list's cursor to the beginning.  After rewinding
+ * we're good to cell_list_find() the cell any x coordinate. */
+inline static void
+cell_list_rewind (struct cell_list *cells)
+{
+    cells->cursor = &cells->head;
+}
+
+/* Rewind the cell list if its cursor has been advanced past x. */
+inline static void
+cell_list_maybe_rewind (struct cell_list *cells, int x)
+{
+    struct cell *tail = cells->cursor;
+    if (tail->x > x)
+	cell_list_rewind (cells);
+}
+
+static void
+cell_list_init(struct cell_list *cells, jmp_buf *jmp)
+{
+    pool_init(cells->cell_pool.base, jmp,
+	      256*sizeof(struct cell),
+	      sizeof(cells->cell_pool.embedded));
+    cells->tail.next = NULL;
+    cells->tail.x = INT_MAX;
+    cells->head.x = INT_MIN;
+    cells->head.next = &cells->tail;
+    cell_list_rewind (cells);
+}
+
+static void
+cell_list_fini(struct cell_list *cells)
+{
+    pool_fini (cells->cell_pool.base);
+}
+
+/* Empty the cell list.  This is called at the start of every pixel
+ * row. */
+inline static void
+cell_list_reset (struct cell_list *cells)
+{
+    cell_list_rewind (cells);
+    cells->head.next = &cells->tail;
+    pool_reset (cells->cell_pool.base);
+}
+
+static struct cell *
+cell_list_alloc (struct cell_list *cells,
+		 struct cell *tail,
+		 int x)
+{
+    struct cell *cell;
+
+    cell = pool_alloc (cells->cell_pool.base, sizeof (struct cell));
+    cell->next = tail->next;
+    tail->next = cell;
+    cell->x = x;
+    cell->uncovered_area = 0;
+    cell->covered_height = 0;
+    cell->clipped_height = 0;
+    return cell;
+}
+
+/* Find a cell at the given x-coordinate.  Returns %NULL if a new cell
+ * needed to be allocated but couldn't be.  Cells must be found with
+ * non-decreasing x-coordinate until the cell list is rewound using
+ * cell_list_rewind(). Ownership of the returned cell is retained by
+ * the cell list. */
+inline static struct cell *
+cell_list_find (struct cell_list *cells, int x)
+{
+    struct cell *tail = cells->cursor;
+
+    while (1) {
+	UNROLL3({
+	    if (tail->next->x > x)
+		break;
+	    tail = tail->next;
+	});
+    }
+
+    if (tail->x != x)
+	tail = cell_list_alloc (cells, tail, x);
+    return cells->cursor = tail;
+
+}
+
+/* Find two cells at x1 and x2.	 This is exactly equivalent
+ * to
+ *
+ *   pair.cell1 = cell_list_find(cells, x1);
+ *   pair.cell2 = cell_list_find(cells, x2);
+ *
+ * except with less function call overhead. */
+inline static struct cell_pair
+cell_list_find_pair(struct cell_list *cells, int x1, int x2)
+{
+    struct cell_pair pair;
+
+    pair.cell1 = cells->cursor;
+    while (1) {
+	UNROLL3({
+	    if (pair.cell1->next->x > x1)
+		break;
+	    pair.cell1 = pair.cell1->next;
+	});
+    }
+    if (pair.cell1->x != x1) {
+	struct cell *cell = pool_alloc (cells->cell_pool.base,
+					sizeof (struct cell));
+	cell->x = x1;
+	cell->uncovered_area = 0;
+	cell->covered_height = 0;
+	cell->clipped_height = 0;
+	cell->next = pair.cell1->next;
+	pair.cell1->next = cell;
+	pair.cell1 = cell;
+    }
+
+    pair.cell2 = pair.cell1;
+    while (1) {
+	UNROLL3({
+	    if (pair.cell2->next->x > x2)
+		break;
+	    pair.cell2 = pair.cell2->next;
+	});
+    }
+    if (pair.cell2->x != x2) {
+	struct cell *cell = pool_alloc (cells->cell_pool.base,
+					sizeof (struct cell));
+	cell->uncovered_area = 0;
+	cell->covered_height = 0;
+	cell->clipped_height = 0;
+	cell->x = x2;
+	cell->next = pair.cell2->next;
+	pair.cell2->next = cell;
+	pair.cell2 = cell;
+    }
+
+    cells->cursor = pair.cell2;
+    return pair;
+}
+
+/* Add a subpixel span covering [x1, x2) to the coverage cells. */
+inline static void
+cell_list_add_subspan(struct cell_list *cells,
+		      grid_scaled_x_t x1,
+		      grid_scaled_x_t x2)
+{
+    int ix1, fx1;
+    int ix2, fx2;
+
+    GRID_X_TO_INT_FRAC(x1, ix1, fx1);
+    GRID_X_TO_INT_FRAC(x2, ix2, fx2);
+
+    if (ix1 != ix2) {
+	struct cell_pair p;
+	p = cell_list_find_pair(cells, ix1, ix2);
+	p.cell1->uncovered_area += 2*fx1;
+	++p.cell1->covered_height;
+	p.cell2->uncovered_area -= 2*fx2;
+	--p.cell2->covered_height;
+    } else {
+	struct cell *cell = cell_list_find(cells, ix1);
+	cell->uncovered_area += 2*(fx1-fx2);
+    }
+}
+
+/* Adds the analytical coverage of an edge crossing the current pixel
+ * row to the coverage cells and advances the edge's x position to the
+ * following row.
+ *
+ * This function is only called when we know that during this pixel row:
+ *
+ * 1) The relative order of all edges on the active list doesn't
+ * change.  In particular, no edges intersect within this row to pixel
+ * precision.
+ *
+ * 2) No new edges start in this row.
+ *
+ * 3) No existing edges end mid-row.
+ *
+ * This function depends on being called with all edges from the
+ * active list in the order they appear on the list (i.e. with
+ * non-decreasing x-coordinate.)  */
+static void
+cell_list_render_edge(
+    struct cell_list *cells,
+    struct edge *edge,
+    int sign)
+{
+    grid_scaled_y_t y1, y2, dy;
+    grid_scaled_x_t dx;
+    int ix1, ix2;
+    grid_scaled_x_t fx1, fx2;
+
+    struct quorem x1 = edge->x;
+    struct quorem x2 = x1;
+
+    if (! edge->vertical) {
+	x2.quo += edge->dxdy_full.quo;
+	x2.rem += edge->dxdy_full.rem;
+	if (x2.rem >= 0) {
+	    ++x2.quo;
+	    x2.rem -= edge->dy;
+	}
+
+	edge->x = x2;
+    }
+
+    GRID_X_TO_INT_FRAC(x1.quo, ix1, fx1);
+    GRID_X_TO_INT_FRAC(x2.quo, ix2, fx2);
+
+    /* Edge is entirely within a column? */
+    if (ix1 == ix2) {
+	/* We always know that ix1 is >= the cell list cursor in this
+	 * case due to the no-intersections precondition.  */
+	struct cell *cell = cell_list_find(cells, ix1);
+	cell->covered_height += sign*GRID_Y;
+	cell->uncovered_area += sign*(fx1 + fx2)*GRID_Y;
+	return;
+    }
+
+    /* Orient the edge left-to-right. */
+    dx = x2.quo - x1.quo;
+    if (dx >= 0) {
+	y1 = 0;
+	y2 = GRID_Y;
+    } else {
+	int tmp;
+	tmp = ix1; ix1 = ix2; ix2 = tmp;
+	tmp = fx1; fx1 = fx2; fx2 = tmp;
+	dx = -dx;
+	sign = -sign;
+	y1 = GRID_Y;
+	y2 = 0;
+    }
+    dy = y2 - y1;
+
+    /* Add coverage for all pixels [ix1,ix2] on this row crossed
+     * by the edge. */
+    {
+	struct cell_pair pair;
+	struct quorem y = floored_divrem((GRID_X - fx1)*dy, dx);
+
+	/* When rendering a previous edge on the active list we may
+	 * advance the cell list cursor past the leftmost pixel of the
+	 * current edge even though the two edges don't intersect.
+	 * e.g. consider two edges going down and rightwards:
+	 *
+	 *  --\_+---\_+-----+-----+----
+	 *      \_    \_    |     |
+	 *      | \_  | \_  |     |
+	 *      |   \_|   \_|     |
+	 *      |     \_    \_    |
+	 *  ----+-----+-\---+-\---+----
+	 *
+	 * The left edge touches cells past the starting cell of the
+	 * right edge.  Fortunately such cases are rare.
+	 *
+	 * The rewinding is never necessary if the current edge stays
+	 * within a single column because we've checked before calling
+	 * this function that the active list order won't change. */
+	cell_list_maybe_rewind(cells, ix1);
+
+	pair = cell_list_find_pair(cells, ix1, ix1+1);
+	pair.cell1->uncovered_area += sign*y.quo*(GRID_X + fx1);
+	pair.cell1->covered_height += sign*y.quo;
+	y.quo += y1;
+
+	if (ix1+1 < ix2) {
+	    struct quorem dydx_full = floored_divrem(GRID_X*dy, dx);
+	    struct cell *cell = pair.cell2;
+
+	    ++ix1;
+	    do {
+		grid_scaled_y_t y_skip = dydx_full.quo;
+		y.rem += dydx_full.rem;
+		if (y.rem >= dx) {
+		    ++y_skip;
+		    y.rem -= dx;
+		}
+
+		y.quo += y_skip;
+
+		y_skip *= sign;
+		cell->uncovered_area += y_skip*GRID_X;
+		cell->covered_height += y_skip;
+
+		++ix1;
+		cell = cell_list_find(cells, ix1);
+	    } while (ix1 != ix2);
+
+	    pair.cell2 = cell;
+	}
+	pair.cell2->uncovered_area += sign*(y2 - y.quo)*fx2;
+	pair.cell2->covered_height += sign*(y2 - y.quo);
+    }
+}
+
+static void
+polygon_init (struct polygon *polygon, jmp_buf *jmp)
+{
+    polygon->ymin = polygon->ymax = 0;
+    polygon->y_buckets = polygon->y_buckets_embedded;
+    pool_init (polygon->edge_pool.base, jmp,
+	       8192 - sizeof (struct _pool_chunk),
+	       sizeof (polygon->edge_pool.embedded));
+}
+
+static void
+polygon_fini (struct polygon *polygon)
+{
+    if (polygon->y_buckets != polygon->y_buckets_embedded)
+	free (polygon->y_buckets);
+
+    pool_fini (polygon->edge_pool.base);
+}
+
+/* Empties the polygon of all edges. The polygon is then prepared to
+ * receive new edges and clip them to the vertical range
+ * [ymin,ymax). */
+static cairo_status_t
+polygon_reset (struct polygon *polygon,
+	       grid_scaled_y_t ymin,
+	       grid_scaled_y_t ymax)
+{
+    unsigned h = ymax - ymin;
+    unsigned num_buckets = EDGE_Y_BUCKET_INDEX(ymax + EDGE_Y_BUCKET_HEIGHT-1,
+					       ymin);
+
+    pool_reset(polygon->edge_pool.base);
+
+    if (unlikely (h > 0x7FFFFFFFU - EDGE_Y_BUCKET_HEIGHT))
+	goto bail_no_mem; /* even if you could, you wouldn't want to. */
+
+    if (polygon->y_buckets != polygon->y_buckets_embedded)
+	free (polygon->y_buckets);
+
+    polygon->y_buckets =  polygon->y_buckets_embedded;
+    if (num_buckets > ARRAY_LENGTH (polygon->y_buckets_embedded)) {
+	polygon->y_buckets = _cairo_malloc_ab (num_buckets,
+					       sizeof (struct edge *));
+	if (unlikely (NULL == polygon->y_buckets))
+	    goto bail_no_mem;
+    }
+    memset (polygon->y_buckets, 0, num_buckets * sizeof (struct edge *));
+
+    polygon->ymin = ymin;
+    polygon->ymax = ymax;
+    return CAIRO_STATUS_SUCCESS;
+
+ bail_no_mem:
+    polygon->ymin = 0;
+    polygon->ymax = 0;
+    return CAIRO_STATUS_NO_MEMORY;
+}
+
+static void
+_polygon_insert_edge_into_its_y_bucket(
+    struct polygon *polygon,
+    struct edge *e)
+{
+    unsigned ix = EDGE_Y_BUCKET_INDEX(e->ytop, polygon->ymin);
+    struct edge **ptail = &polygon->y_buckets[ix];
+    e->next = *ptail;
+    *ptail = e;
+}
+
+inline static void
+polygon_add_edge (struct polygon *polygon,
+		  const cairo_edge_t *edge,
+		  int clip)
+{
+    struct edge *e;
+    grid_scaled_x_t dx;
+    grid_scaled_y_t dy;
+    grid_scaled_y_t ytop, ybot;
+    grid_scaled_y_t ymin = polygon->ymin;
+    grid_scaled_y_t ymax = polygon->ymax;
+
+    assert (edge->bottom > edge->top);
+
+    if (unlikely (edge->top >= ymax || edge->bottom <= ymin))
+	return;
+
+    e = pool_alloc (polygon->edge_pool.base, sizeof (struct edge));
+
+    dx = edge->line.p2.x - edge->line.p1.x;
+    dy = edge->line.p2.y - edge->line.p1.y;
+    e->dy = dy;
+    e->dir = edge->dir;
+    e->clip = clip;
+
+    ytop = edge->top >= ymin ? edge->top : ymin;
+    ybot = edge->bottom <= ymax ? edge->bottom : ymax;
+    e->ytop = ytop;
+    e->height_left = ybot - ytop;
+
+    if (dx == 0) {
+	e->vertical = TRUE;
+	e->x.quo = edge->line.p1.x;
+	e->x.rem = 0;
+	e->dxdy.quo = 0;
+	e->dxdy.rem = 0;
+	e->dxdy_full.quo = 0;
+	e->dxdy_full.rem = 0;
+    } else {
+	e->vertical = FALSE;
+	e->dxdy = floored_divrem (dx, dy);
+	if (ytop == edge->line.p1.y) {
+	    e->x.quo = edge->line.p1.x;
+	    e->x.rem = 0;
+	} else {
+	    e->x = floored_muldivrem (ytop - edge->line.p1.y, dx, dy);
+	    e->x.quo += edge->line.p1.x;
+	}
+
+	if (e->height_left >= GRID_Y) {
+	    e->dxdy_full = floored_muldivrem (GRID_Y, dx, dy);
+	} else {
+	    e->dxdy_full.quo = 0;
+	    e->dxdy_full.rem = 0;
+	}
+    }
+
+    _polygon_insert_edge_into_its_y_bucket (polygon, e);
+
+    e->x.rem -= dy;		/* Bias the remainder for faster
+				 * edge advancement. */
+}
+
+static void
+active_list_reset (struct active_list *active)
+{
+    active->head = NULL;
+    active->min_height = 0;
+}
+
+static void
+active_list_init(struct active_list *active)
+{
+    active_list_reset(active);
+}
+
+/*
+ * Merge two sorted edge lists.
+ * Input:
+ *  - head_a: The head of the first list.
+ *  - head_b: The head of the second list; head_b cannot be NULL.
+ * Output:
+ * Returns the head of the merged list.
+ *
+ * Implementation notes:
+ * To make it fast (in particular, to reduce to an insertion sort whenever
+ * one of the two input lists only has a single element) we iterate through
+ * a list until its head becomes greater than the head of the other list,
+ * then we switch their roles. As soon as one of the two lists is empty, we
+ * just attach the other one to the current list and exit.
+ * Writes to memory are only needed to "switch" lists (as it also requires
+ * attaching to the output list the list which we will be iterating next) and
+ * to attach the last non-empty list.
+ */
+static struct edge *
+merge_sorted_edges (struct edge *head_a, struct edge *head_b)
+{
+    struct edge *head, **next;
+    int32_t x;
+
+    if (head_a == NULL)
+	return head_b;
+
+    next = &head;
+    if (head_a->x.quo <= head_b->x.quo) {
+	head = head_a;
+    } else {
+	head = head_b;
+	goto start_with_b;
+    }
+
+    do {
+	x = head_b->x.quo;
+	while (head_a != NULL && head_a->x.quo <= x) {
+	    next = &head_a->next;
+	    head_a = head_a->next;
+	}
+
+	*next = head_b;
+	if (head_a == NULL)
+	    return head;
+
+start_with_b:
+	x = head_a->x.quo;
+	while (head_b != NULL && head_b->x.quo <= x) {
+	    next = &head_b->next;
+	    head_b = head_b->next;
+	}
+
+	*next = head_a;
+	if (head_b == NULL)
+	    return head;
+    } while (1);
+}
+
+/*
+ * Sort (part of) a list.
+ * Input:
+ *  - list: The list to be sorted; list cannot be NULL.
+ *  - limit: Recursion limit.
+ * Output:
+ *  - head_out: The head of the sorted list containing the first 2^(level+1) elements of the
+ *              input list; if the input list has fewer elements, head_out be a sorted list
+ *              containing all the elements of the input list.
+ * Returns the head of the list of unprocessed elements (NULL if the sorted list contains
+ * all the elements of the input list).
+ *
+ * Implementation notes:
+ * Special case single element list, unroll/inline the sorting of the first two elements.
+ * Some tail recursion is used since we iterate on the bottom-up solution of the problem
+ * (we start with a small sorted list and keep merging other lists of the same size to it).
+ */
+static struct edge *
+sort_edges (struct edge  *list,
+	    unsigned int  level,
+	    struct edge **head_out)
+{
+    struct edge *head_other, *remaining;
+    unsigned int i;
+
+    head_other = list->next;
+
+    /* Single element list -> return */
+    if (head_other == NULL) {
+	*head_out = list;
+	return NULL;
+    }
+
+    /* Unroll the first iteration of the following loop (halves the number of calls to merge_sorted_edges):
+     *  - Initialize remaining to be the list containing the elements after the second in the input list.
+     *  - Initialize *head_out to be the sorted list containing the first two element.
+     */
+    remaining = head_other->next;
+    if (list->x.quo <= head_other->x.quo) {
+	*head_out = list;
+	/* list->next = head_other; */ /* The input list is already like this. */
+	head_other->next = NULL;
+    } else {
+	*head_out = head_other;
+	head_other->next = list;
+	list->next = NULL;
+    }
+
+    for (i = 0; i < level && remaining; i++) {
+	/* Extract a sorted list of the same size as *head_out
+	 * (2^(i+1) elements) from the list of remaining elements. */
+	remaining = sort_edges (remaining, i, &head_other);
+	*head_out = merge_sorted_edges (*head_out, head_other);
+    }
+
+    /* *head_out now contains (at most) 2^(level+1) elements. */
+
+    return remaining;
+}
+
+/* Test if the edges on the active list can be safely advanced by a
+ * full row without intersections or any edges ending. */
+inline static int
+active_list_can_step_full_row (struct active_list *active)
+{
+    const struct edge *e;
+    int prev_x = INT_MIN;
+
+    /* Recomputes the minimum height of all edges on the active
+     * list if we have been dropping edges. */
+    if (active->min_height <= 0) {
+	int min_height = INT_MAX;
+
+	e = active->head;
+	while (NULL != e) {
+	    if (e->height_left < min_height)
+		min_height = e->height_left;
+	    e = e->next;
+	}
+
+	active->min_height = min_height;
+    }
+
+    if (active->min_height < GRID_Y)
+	return 0;
+
+    /* Check for intersections as no edges end during the next row. */
+    e = active->head;
+    while (NULL != e) {
+	struct quorem x = e->x;
+
+	if (! e->vertical) {
+	    x.quo += e->dxdy_full.quo;
+	    x.rem += e->dxdy_full.rem;
+	    if (x.rem >= 0)
+		++x.quo;
+	}
+
+	if (x.quo <= prev_x)
+	    return 0;
+
+	prev_x = x.quo;
+	e = e->next;
+    }
+
+    return 1;
+}
+
+/* Merges edges on the given subpixel row from the polygon to the
+ * active_list. */
+inline static void
+active_list_merge_edges_from_polygon(struct active_list *active,
+				     struct edge **ptail,
+				     grid_scaled_y_t y,
+				     struct polygon *polygon)
+{
+    /* Split off the edges on the current subrow and merge them into
+     * the active list. */
+    int min_height = active->min_height;
+    struct edge *subrow_edges = NULL;
+    struct edge *tail = *ptail;
+
+    do {
+	struct edge *next = tail->next;
+
+	if (y == tail->ytop) {
+	    tail->next = subrow_edges;
+	    subrow_edges = tail;
+
+	    if (tail->height_left < min_height)
+		min_height = tail->height_left;
+
+	    *ptail = next;
+	} else
+	    ptail = &tail->next;
+
+	tail = next;
+    } while (tail);
+
+    if (subrow_edges) {
+	sort_edges (subrow_edges, UINT_MAX, &subrow_edges);
+	active->head = merge_sorted_edges (active->head, subrow_edges);
+	active->min_height = min_height;
+    }
+}
+
+/* Advance the edges on the active list by one subsample row by
+ * updating their x positions.  Drop edges from the list that end. */
+inline static void
+active_list_substep_edges(struct active_list *active)
+{
+    struct edge **cursor = &active->head;
+    grid_scaled_x_t prev_x = INT_MIN;
+    struct edge *unsorted = NULL;
+    struct edge *edge = *cursor;
+
+    do {
+	UNROLL3({
+	    struct edge *next;
+
+	    if (NULL == edge)
+		break;
+
+	    next = edge->next;
+	    if (--edge->height_left) {
+		edge->x.quo += edge->dxdy.quo;
+		edge->x.rem += edge->dxdy.rem;
+		if (edge->x.rem >= 0) {
+		    ++edge->x.quo;
+		    edge->x.rem -= edge->dy;
+		}
+
+		if (edge->x.quo < prev_x) {
+		    *cursor = next;
+		    edge->next = unsorted;
+		    unsorted = edge;
+		} else {
+		    prev_x = edge->x.quo;
+		    cursor = &edge->next;
+		}
+	    } else {
+		 *cursor = next;
+	    }
+	    edge = next;
+	})
+    } while (1);
+
+    if (unsorted) {
+	sort_edges (unsorted, UINT_MAX, &unsorted);
+	active->head = merge_sorted_edges (active->head, unsorted);
+    }
+}
+
+inline static void
+apply_nonzero_fill_rule_for_subrow (struct active_list *active,
+				    struct cell_list *coverages)
+{
+    struct edge *edge = active->head;
+    int winding = 0;
+    int xstart;
+    int xend;
+
+    cell_list_rewind (coverages);
+
+    while (NULL != edge) {
+	xstart = edge->x.quo;
+	winding = edge->dir;
+	while (1) {
+	    edge = edge->next;
+	    if (NULL == edge) {
+		ASSERT_NOT_REACHED;
+		return;
+	    }
+
+	    winding += edge->dir;
+	    if (0 == winding) {
+		if (edge->next == NULL || edge->next->x.quo != edge->x.quo)
+		    break;
+	    }
+	}
+
+	xend = edge->x.quo;
+	cell_list_add_subspan (coverages, xstart, xend);
+
+	edge = edge->next;
+    }
+}
+
+static void
+apply_evenodd_fill_rule_for_subrow (struct active_list *active,
+				    struct cell_list *coverages)
+{
+    struct edge *edge = active->head;
+    int xstart;
+    int xend;
+
+    cell_list_rewind (coverages);
+
+    while (NULL != edge) {
+	xstart = edge->x.quo;
+
+	while (1) {
+	    edge = edge->next;
+	    if (NULL == edge) {
+		ASSERT_NOT_REACHED;
+		return;
+	    }
+
+	    if (edge->next == NULL || edge->next->x.quo != edge->x.quo)
+		break;
+
+	    edge = edge->next;
+	}
+
+	xend = edge->x.quo;
+	cell_list_add_subspan (coverages, xstart, xend);
+
+	edge = edge->next;
+    }
+}
+
+static void
+apply_nonzero_fill_rule_and_step_edges (struct active_list *active,
+					struct cell_list *coverages)
+{
+    struct edge **cursor = &active->head;
+    struct edge *left_edge;
+
+    left_edge = *cursor;
+    while (NULL != left_edge) {
+	struct edge *right_edge;
+	int winding = left_edge->dir;
+
+	left_edge->height_left -= GRID_Y;
+	if (left_edge->height_left)
+	    cursor = &left_edge->next;
+	else
+	    *cursor = left_edge->next;
+
+	while (1) {
+	    right_edge = *cursor;
+	    if (NULL == right_edge) {
+		cell_list_render_edge (coverages, left_edge, +1);
+		return;
+	    }
+
+	    right_edge->height_left -= GRID_Y;
+	    if (right_edge->height_left)
+		cursor = &right_edge->next;
+	    else
+		*cursor = right_edge->next;
+
+	    winding += right_edge->dir;
+	    if (0 == winding) {
+		if (right_edge->next == NULL ||
+		    right_edge->next->x.quo != right_edge->x.quo)
+		{
+		    break;
+		}
+	    }
+
+	    if (! right_edge->vertical) {
+		right_edge->x.quo += right_edge->dxdy_full.quo;
+		right_edge->x.rem += right_edge->dxdy_full.rem;
+		if (right_edge->x.rem >= 0) {
+		    ++right_edge->x.quo;
+		    right_edge->x.rem -= right_edge->dy;
+		}
+	    }
+	}
+
+	cell_list_render_edge (coverages, left_edge, +1);
+	cell_list_render_edge (coverages, right_edge, -1);
+
+	left_edge = *cursor;
+    }
+}
+
+static void
+apply_evenodd_fill_rule_and_step_edges (struct active_list *active,
+					struct cell_list *coverages)
+{
+    struct edge **cursor = &active->head;
+    struct edge *left_edge;
+
+    left_edge = *cursor;
+    while (NULL != left_edge) {
+	struct edge *right_edge;
+
+	left_edge->height_left -= GRID_Y;
+	if (left_edge->height_left)
+	    cursor = &left_edge->next;
+	else
+	    *cursor = left_edge->next;
+
+	while (1) {
+	    right_edge = *cursor;
+	    if (NULL == right_edge) {
+		cell_list_render_edge (coverages, left_edge, +1);
+		return;
+	    }
+
+	    right_edge->height_left -= GRID_Y;
+	    if (right_edge->height_left)
+		cursor = &right_edge->next;
+	    else
+		*cursor = right_edge->next;
+
+	    if (right_edge->next == NULL ||
+		right_edge->next->x.quo != right_edge->x.quo)
+	    {
+		break;
+	    }
+
+	    if (! right_edge->vertical) {
+		right_edge->x.quo += right_edge->dxdy_full.quo;
+		right_edge->x.rem += right_edge->dxdy_full.rem;
+		if (right_edge->x.rem >= 0) {
+		    ++right_edge->x.quo;
+		    right_edge->x.rem -= right_edge->dy;
+		}
+	    }
+	}
+
+	cell_list_render_edge (coverages, left_edge, +1);
+	cell_list_render_edge (coverages, right_edge, -1);
+
+	left_edge = *cursor;
+    }
+}
+
+static void
+_glitter_scan_converter_init(glitter_scan_converter_t *converter, jmp_buf *jmp)
+{
+    polygon_init(converter->polygon, jmp);
+    active_list_init(converter->active);
+    cell_list_init(converter->coverages, jmp);
+    converter->ymin=0;
+    converter->ymax=0;
+}
+
+static void
+_glitter_scan_converter_fini(glitter_scan_converter_t *converter)
+{
+    polygon_fini(converter->polygon);
+    cell_list_fini(converter->coverages);
+    converter->ymin=0;
+    converter->ymax=0;
+}
+
+static grid_scaled_t
+int_to_grid_scaled(int i, int scale)
+{
+    /* Clamp to max/min representable scaled number. */
+    if (i >= 0) {
+	if (i >= INT_MAX/scale)
+	    i = INT_MAX/scale;
+    }
+    else {
+	if (i <= INT_MIN/scale)
+	    i = INT_MIN/scale;
+    }
+    return i*scale;
+}
+
+#define int_to_grid_scaled_x(x) int_to_grid_scaled((x), GRID_X)
+#define int_to_grid_scaled_y(x) int_to_grid_scaled((x), GRID_Y)
+
+static cairo_status_t
+glitter_scan_converter_reset(glitter_scan_converter_t *converter,
+			     int ymin, int ymax)
+{
+    cairo_status_t status;
+
+    converter->ymin = 0;
+    converter->ymax = 0;
+
+    ymin = int_to_grid_scaled_y(ymin);
+    ymax = int_to_grid_scaled_y(ymax);
+
+    active_list_reset(converter->active);
+    cell_list_reset(converter->coverages);
+    status = polygon_reset(converter->polygon, ymin, ymax);
+    if (status)
+	return status;
+
+    converter->ymin = ymin;
+    converter->ymax = ymax;
+    return CAIRO_STATUS_SUCCESS;
+}
+
+/* INPUT_TO_GRID_X/Y (in_coord, out_grid_scaled, grid_scale)
+ *   These macros convert an input coordinate in the client's
+ *   device space to the rasterisation grid.
+ */
+/* Gah.. this bit of ugly defines INPUT_TO_GRID_X/Y so as to use
+ * shifts if possible, and something saneish if not.
+ */
+#if !defined(INPUT_TO_GRID_Y) && defined(GRID_Y_BITS) && GRID_Y_BITS <= GLITTER_INPUT_BITS
+#  define INPUT_TO_GRID_Y(in, out) (out) = (in) >> (GLITTER_INPUT_BITS - GRID_Y_BITS)
+#else
+#  define INPUT_TO_GRID_Y(in, out) INPUT_TO_GRID_general(in, out, GRID_Y)
+#endif
+
+#if !defined(INPUT_TO_GRID_X) && defined(GRID_X_BITS) && GRID_X_BITS <= GLITTER_INPUT_BITS
+#  define INPUT_TO_GRID_X(in, out) (out) = (in) >> (GLITTER_INPUT_BITS - GRID_X_BITS)
+#else
+#  define INPUT_TO_GRID_X(in, out) INPUT_TO_GRID_general(in, out, GRID_X)
+#endif
+
+#define INPUT_TO_GRID_general(in, out, grid_scale) do {		\
+	long long tmp__ = (long long)(grid_scale) * (in);	\
+	tmp__ >>= GLITTER_INPUT_BITS;				\
+	(out) = tmp__;						\
+} while (0)
+
+static void
+glitter_scan_converter_add_edge (glitter_scan_converter_t *converter,
+				 const cairo_edge_t *edge,
+				 int clip)
+{
+    cairo_edge_t e;
+
+    INPUT_TO_GRID_Y (edge->top, e.top);
+    INPUT_TO_GRID_Y (edge->bottom, e.bottom);
+    if (e.top >= e.bottom)
+	return;
+
+    /* XXX: possible overflows if GRID_X/Y > 2**GLITTER_INPUT_BITS */
+    INPUT_TO_GRID_Y (edge->line.p1.y, e.line.p1.y);
+    INPUT_TO_GRID_Y (edge->line.p2.y, e.line.p2.y);
+    if (e.line.p1.y == e.line.p2.y)
+	return;
+
+    INPUT_TO_GRID_X (edge->line.p1.x, e.line.p1.x);
+    INPUT_TO_GRID_X (edge->line.p2.x, e.line.p2.x);
+
+    e.dir = edge->dir;
+
+    polygon_add_edge (converter->polygon, &e, clip);
+}
+
+static cairo_bool_t
+active_list_is_vertical (struct active_list *active)
+{
+    struct edge *e;
+
+    for (e = active->head; e != NULL; e = e->next) {
+	if (! e->vertical)
+	    return FALSE;
+    }
+
+    return TRUE;
+}
+
+static void
+step_edges (struct active_list *active, int count)
+{
+    struct edge **cursor = &active->head;
+    struct edge *edge;
+
+    for (edge = *cursor; edge != NULL; edge = *cursor) {
+	edge->height_left -= GRID_Y * count;
+	if (edge->height_left)
+	    cursor = &edge->next;
+	else
+	    *cursor = edge->next;
+    }
+}
+
+static cairo_status_t
+blit_coverages (struct cell_list *cells,
+		cairo_span_renderer_t *renderer,
+		struct pool *span_pool,
+		int y, int height)
+{
+    struct cell *cell = cells->head.next;
+    int prev_x = -1;
+    int cover = 0, last_cover = 0;
+    int clip = 0;
+    cairo_half_open_span_t *spans;
+    unsigned num_spans;
+
+    assert (cell != &cells->tail);
+
+    /* Count number of cells remaining. */
+    {
+	struct cell *next = cell;
+	num_spans = 2;
+	while (next->next) {
+	    next = next->next;
+	    ++num_spans;
+	}
+	num_spans = 2*num_spans;
+    }
+
+    /* Allocate enough spans for the row. */
+    pool_reset (span_pool);
+    spans = pool_alloc (span_pool, sizeof(spans[0])*num_spans);
+    num_spans = 0;
+
+    /* Form the spans from the coverages and areas. */
+    for (; cell->next; cell = cell->next) {
+	int x = cell->x;
+	int area;
+
+	if (x > prev_x && cover != last_cover) {
+	    spans[num_spans].x = prev_x;
+	    spans[num_spans].coverage = GRID_AREA_TO_ALPHA (cover);
+	    spans[num_spans].inverse = 0;
+	    last_cover = cover;
+	    ++num_spans;
+	}
+
+	cover += cell->covered_height*GRID_X*2;
+	clip += cell->covered_height*GRID_X*2;
+	area = cover - cell->uncovered_area;
+
+	if (area != last_cover) {
+	    spans[num_spans].x = x;
+	    spans[num_spans].coverage = GRID_AREA_TO_ALPHA (area);
+	    spans[num_spans].inverse = 0;
+	    last_cover = area;
+	    ++num_spans;
+	}
+
+	prev_x = x+1;
+    }
+
+    /* Dump them into the renderer. */
+    return renderer->render_rows (renderer, y, height, spans, num_spans);
+}
+
+static void
+glitter_scan_converter_render(glitter_scan_converter_t *converter,
+			      int nonzero_fill,
+			      cairo_span_renderer_t *span_renderer,
+			      struct pool *span_pool)
+{
+    int i, j;
+    int ymax_i = converter->ymax / GRID_Y;
+    int ymin_i = converter->ymin / GRID_Y;
+    int h = ymax_i - ymin_i;
+    struct polygon *polygon = converter->polygon;
+    struct cell_list *coverages = converter->coverages;
+    struct active_list *active = converter->active;
+
+    /* Render each pixel row. */
+    for (i = 0; i < h; i = j) {
+	int do_full_step = 0;
+
+	j = i + 1;
+
+	/* Determine if we can ignore this row or use the full pixel
+	 * stepper. */
+	if (GRID_Y == EDGE_Y_BUCKET_HEIGHT && ! polygon->y_buckets[i]) {
+	    if (! active->head) {
+		for (; j < h && ! polygon->y_buckets[j]; j++)
+		    ;
+		continue;
+	    }
+
+	    do_full_step = active_list_can_step_full_row (active);
+	}
+
+	if (do_full_step) {
+	    /* Step by a full pixel row's worth. */
+	    if (nonzero_fill)
+		apply_nonzero_fill_rule_and_step_edges (active, coverages);
+	    else
+		apply_evenodd_fill_rule_and_step_edges (active, coverages);
+
+	    if (active_list_is_vertical (active)) {
+		while (j < h &&
+		       polygon->y_buckets[j] == NULL &&
+		       active->min_height >= 2*GRID_Y)
+		{
+		    active->min_height -= GRID_Y;
+		    j++;
+		}
+		if (j != i + 1)
+		    step_edges (active, j - (i + 1));
+	    }
+	} else {
+	    grid_scaled_y_t suby;
+
+	    /* Subsample this row. */
+	    for (suby = 0; suby < GRID_Y; suby++) {
+		grid_scaled_y_t y = (i+ymin_i)*GRID_Y + suby;
+
+		if (polygon->y_buckets[i]) {
+		    active_list_merge_edges_from_polygon (active,
+							  &polygon->y_buckets[i], y,
+							  polygon);
+		}
+
+		if (nonzero_fill)
+		    apply_nonzero_fill_rule_for_subrow (active, coverages);
+		else
+		    apply_evenodd_fill_rule_for_subrow (active, coverages);
+
+		active_list_substep_edges(active);
+	    }
+	}
+
+	blit_coverages (coverages, span_renderer, span_pool, i+ymin_i, j -i);
+	cell_list_reset (coverages);
+
+	if (! active->head)
+	    active->min_height = INT_MAX;
+	else
+	    active->min_height -= GRID_Y;
+    }
+}
+
+struct _cairo_clip_tor_scan_converter {
+    cairo_scan_converter_t base;
+
+    glitter_scan_converter_t converter[1];
+    cairo_fill_rule_t fill_rule;
+    cairo_antialias_t antialias;
+
+    cairo_fill_rule_t clip_fill_rule;
+    cairo_antialias_t clip_antialias;
+
+    jmp_buf jmp;
+
+    struct {
+	struct pool base[1];
+	cairo_half_open_span_t embedded[32];
+    } span_pool;
+};
+
+typedef struct _cairo_clip_tor_scan_converter cairo_clip_tor_scan_converter_t;
+
+static void
+_cairo_clip_tor_scan_converter_destroy (void *converter)
+{
+    cairo_clip_tor_scan_converter_t *self = converter;
+    if (self == NULL) {
+	return;
+    }
+    _glitter_scan_converter_fini (self->converter);
+    pool_fini (self->span_pool.base);
+    free(self);
+}
+
+static cairo_status_t
+_cairo_clip_tor_scan_converter_generate (void			*converter,
+				    cairo_span_renderer_t	*renderer)
+{
+    cairo_clip_tor_scan_converter_t *self = converter;
+    cairo_status_t status;
+
+    if ((status = setjmp (self->jmp)))
+	return _cairo_scan_converter_set_error (self, _cairo_error (status));
+
+    glitter_scan_converter_render (self->converter,
+				   self->fill_rule == CAIRO_FILL_RULE_WINDING,
+				   renderer,
+				   self->span_pool.base);
+    return CAIRO_STATUS_SUCCESS;
+}
+
+cairo_scan_converter_t *
+_cairo_clip_tor_scan_converter_create (cairo_clip_t *clip,
+				       cairo_polygon_t *polygon,
+				       cairo_fill_rule_t fill_rule,
+				       cairo_antialias_t antialias)
+{
+    cairo_clip_tor_scan_converter_t *self;
+    cairo_polygon_t clipper;
+    cairo_status_t status;
+    int i;
+
+    self = calloc (1, sizeof(struct _cairo_clip_tor_scan_converter));
+    if (unlikely (self == NULL)) {
+	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+	goto bail_nomem;
+    }
+
+    self->base.destroy = _cairo_clip_tor_scan_converter_destroy;
+    self->base.generate = _cairo_clip_tor_scan_converter_generate;
+
+    pool_init (self->span_pool.base, &self->jmp,
+	       250 * sizeof(self->span_pool.embedded[0]),
+	       sizeof(self->span_pool.embedded));
+
+    _glitter_scan_converter_init (self->converter, &self->jmp);
+    status = glitter_scan_converter_reset (self->converter,
+					   clip->extents.y,
+					   clip->extents.y + clip->extents.height);
+    if (unlikely (status))
+	goto bail;
+
+    self->fill_rule = fill_rule;
+    self->antialias = antialias;
+
+    for (i = 0; i < polygon->num_edges; i++)
+	 glitter_scan_converter_add_edge (self->converter,
+					  &polygon->edges[i],
+					  FALSE);
+
+    status = _cairo_clip_get_polygon (clip,
+				      &clipper,
+				      &self->clip_fill_rule,
+				      &self->clip_antialias);
+    if (unlikely (status))
+	goto bail;
+
+    for (i = 0; i < clipper.num_edges; i++)
+	 glitter_scan_converter_add_edge (self->converter,
+					  &clipper.edges[i],
+					  TRUE);
+    _cairo_polygon_fini (&clipper);
+
+    return &self->base;
+
+ bail:
+    self->base.destroy(&self->base);
+ bail_nomem:
+    return _cairo_scan_converter_create_in_error (status);
+}
+
diff --git a/src/cairo-clip.c b/src/cairo-clip.c
index 6355a97..44f4e7b 100644
--- a/src/cairo-clip.c
+++ b/src/cairo-clip.c
@@ -246,16 +246,9 @@ _cairo_clip_intersect_path (cairo_clip_t       *clip,
     if (extents.width == 0 || extents.height == 0)
 	return _cairo_clip_set_all_clipped (clip);
 
-    if (clip && ! _cairo_rectangle_intersect (&clip->extents, &extents))
-	return _cairo_clip_set_all_clipped (clip);
-
-    if (clip == NULL) {
-	clip = _cairo_clip_create ();
-	if (unlikely (clip == NULL))
-	    return _cairo_clip_set_all_clipped (clip);
-
-	clip->extents = extents;
-    }
+    clip = _cairo_clip_intersect_rectangle (clip, &extents);
+    if (_cairo_clip_is_all_clipped (clip))
+	return clip;
 
     clip_path = _cairo_clip_path_create (clip);
     if (unlikely (clip_path == NULL))
@@ -263,7 +256,7 @@ _cairo_clip_intersect_path (cairo_clip_t       *clip,
 
     status = _cairo_path_fixed_init_copy (&clip_path->path, path);
     if (unlikely (status))
-	    return _cairo_clip_set_all_clipped (clip);
+	return _cairo_clip_set_all_clipped (clip);
 
     clip_path->fill_rule = fill_rule;
     clip_path->tolerance = tolerance;
@@ -532,9 +525,10 @@ _cairo_debug_print_clip (FILE *stream, const cairo_clip_t *clip)
     }
 
     fprintf (stream, "clip:\n");
-    fprintf (stream, "  extents: (%d, %d) x (%d, %d)",
+    fprintf (stream, "  extents: (%d, %d) x (%d, %d), is-region? %d",
 	     clip->extents.x, clip->extents.y,
-	     clip->extents.width, clip->extents.height);
+	     clip->extents.width, clip->extents.height,
+	     clip->is_region);
 
     fprintf (stream, "  num_boxes = %d\n", clip->num_boxes);
     for (i = 0; i < clip->num_boxes; i++) {
diff --git a/src/cairo-composite-rectangles-private.h b/src/cairo-composite-rectangles-private.h
index f0553ab..8a06bf9 100644
--- a/src/cairo-composite-rectangles-private.h
+++ b/src/cairo-composite-rectangles-private.h
@@ -39,6 +39,7 @@
 
 #include "cairo-types-private.h"
 #include "cairo-error-private.h"
+#include "cairo-pattern-private.h"
 
 CAIRO_BEGIN_DECLS
 
@@ -52,6 +53,9 @@ CAIRO_BEGIN_DECLS
  *
  */
 struct _cairo_composite_rectangles {
+    cairo_surface_t *surface;
+    cairo_operator_t op;
+
     cairo_rectangle_int_t source;
     cairo_rectangle_int_t mask;
     cairo_rectangle_int_t destination;
@@ -60,19 +64,27 @@ struct _cairo_composite_rectangles {
     cairo_rectangle_int_t unbounded; /* destination IN clip */
     uint32_t is_bounded;
 
+    cairo_rectangle_int_t source_sample_area;
+    cairo_rectangle_int_t mask_sample_area;
+
+    cairo_pattern_union_t source_pattern;
+    cairo_pattern_union_t mask_pattern;
+    const cairo_pattern_t *original_source_pattern;
+    const cairo_pattern_t *original_mask_pattern;
+
     cairo_clip_t *clip; /* clip will be reduced to the minimal container */
 };
 
 cairo_private cairo_int_status_t
 _cairo_composite_rectangles_init_for_paint (cairo_composite_rectangles_t *extents,
-					    const cairo_rectangle_int_t *unbounded,
+					    cairo_surface_t *surface,
 					    cairo_operator_t	 op,
 					    const cairo_pattern_t	*source,
 					    const cairo_clip_t		*clip);
 
 cairo_private cairo_int_status_t
 _cairo_composite_rectangles_init_for_mask (cairo_composite_rectangles_t *extents,
-					   const cairo_rectangle_int_t *unbounded,
+					   cairo_surface_t *surface,
 					   cairo_operator_t	 op,
 					   const cairo_pattern_t	*source,
 					   const cairo_pattern_t	*mask,
@@ -80,7 +92,7 @@ _cairo_composite_rectangles_init_for_mask (cairo_composite_rectangles_t *extents
 
 cairo_private cairo_int_status_t
 _cairo_composite_rectangles_init_for_stroke (cairo_composite_rectangles_t *extents,
-					     const cairo_rectangle_int_t *unbounded,
+					     cairo_surface_t *surface,
 					     cairo_operator_t	 op,
 					     const cairo_pattern_t	*source,
 					     const cairo_path_fixed_t	*path,
@@ -90,15 +102,31 @@ _cairo_composite_rectangles_init_for_stroke (cairo_composite_rectangles_t *exten
 
 cairo_private cairo_int_status_t
 _cairo_composite_rectangles_init_for_fill (cairo_composite_rectangles_t *extents,
-					   const cairo_rectangle_int_t *unbounded,
+					   cairo_surface_t *surface,
 					   cairo_operator_t	 op,
 					   const cairo_pattern_t	*source,
 					   const cairo_path_fixed_t	*path,
 					   const cairo_clip_t		*clip);
 
 cairo_private cairo_int_status_t
+_cairo_composite_rectangles_init_for_boxes (cairo_composite_rectangles_t *extents,
+					      cairo_surface_t		*surface,
+					      cairo_operator_t		 op,
+					      const cairo_pattern_t	*source,
+					      const cairo_boxes_t	*boxes,
+					      const cairo_clip_t		*clip);
+
+cairo_private cairo_int_status_t
+_cairo_composite_rectangles_init_for_polygon (cairo_composite_rectangles_t *extents,
+					      cairo_surface_t		*surface,
+					      cairo_operator_t		 op,
+					      const cairo_pattern_t	*source,
+					      const cairo_polygon_t	*polygon,
+					      const cairo_clip_t		*clip);
+
+cairo_private cairo_int_status_t
 _cairo_composite_rectangles_init_for_glyphs (cairo_composite_rectangles_t *extents,
-					     const cairo_rectangle_int_t *unbounded,
+					     cairo_surface_t *surface,
 					     cairo_operator_t		 op,
 					     const cairo_pattern_t	*source,
 					     cairo_scaled_font_t	*scaled_font,
diff --git a/src/cairo-composite-rectangles.c b/src/cairo-composite-rectangles.c
index a25e6d3..a50a347 100644
--- a/src/cairo-composite-rectangles.c
+++ b/src/cairo-composite-rectangles.c
@@ -46,57 +46,93 @@ void _cairo_composite_rectangles_fini (cairo_composite_rectangles_t *extents)
     _cairo_clip_destroy (extents->clip);
 }
 
+static void
+_cairo_composite_reduce_pattern (const cairo_pattern_t *src,
+				 cairo_pattern_union_t *dst)
+{
+    int tx, ty;
+
+    _cairo_pattern_init_static_copy (&dst->base, src);
+    if (dst->base.type == CAIRO_PATTERN_TYPE_SOLID)
+	return;
+
+    dst->base.filter = _cairo_pattern_analyze_filter (&dst->base, NULL),
+
+    tx = ty = 0;
+    if (_cairo_matrix_is_pixman_translation (&dst->base.matrix,
+					     dst->base.filter,
+					     &tx, &ty))
+    {
+	dst->base.matrix.x0 = tx;
+	dst->base.matrix.y0 = ty;
+    }
+}
+
 static inline cairo_bool_t
 _cairo_composite_rectangles_init (cairo_composite_rectangles_t *extents,
-				  const cairo_rectangle_int_t *unbounded,
+				  cairo_surface_t *surface,
 				  cairo_operator_t op,
 				  const cairo_pattern_t *source,
 				  const cairo_clip_t *clip)
 {
-    extents->clip = NULL;
-    extents->destination = *unbounded;
-
     if (_cairo_clip_is_all_clipped (clip))
 	return FALSE;
 
+    extents->surface = surface;
+    extents->op = op;
+
+    _cairo_surface_get_extents (surface, &extents->destination);
+    extents->clip = NULL;
+
     extents->unbounded = extents->destination;
-    if (clip != NULL) {
-	if (! _cairo_rectangle_intersect (&extents->unbounded,
-					  _cairo_clip_get_extents (clip)))
-	    return FALSE;
-    }
+    if (clip && ! _cairo_rectangle_intersect (&extents->unbounded,
+					      _cairo_clip_get_extents (clip)))
+	return FALSE;
 
     extents->bounded = extents->unbounded;
     extents->is_bounded = _cairo_operator_bounded_by_either (op);
 
-    _cairo_pattern_get_extents (source, &extents->source);
+    extents->original_source_pattern = source;
+    _cairo_composite_reduce_pattern (source, &extents->source_pattern);
+
+    _cairo_pattern_get_extents (&extents->source_pattern.base,
+				&extents->source);
     if (extents->is_bounded & CAIRO_OPERATOR_BOUND_BY_SOURCE) {
 	if (! _cairo_rectangle_intersect (&extents->bounded, &extents->source))
 	    return FALSE;
     }
 
+    extents->original_mask_pattern = NULL;
+    extents->mask_pattern.base.type = CAIRO_PATTERN_TYPE_SOLID;
+    extents->mask_pattern.solid.color.alpha = 1.; /* XXX full initialisation? */
+
     return TRUE;
 }
 
 cairo_int_status_t
 _cairo_composite_rectangles_init_for_paint (cairo_composite_rectangles_t *extents,
-					    const cairo_rectangle_int_t *unbounded,
+					    cairo_surface_t *surface,
 					    cairo_operator_t		 op,
 					    const cairo_pattern_t	*source,
 					    const cairo_clip_t		*clip)
 {
-    if (! _cairo_composite_rectangles_init (extents, unbounded,
-					    op, source, clip))
+    if (! _cairo_composite_rectangles_init (extents,
+					    surface, op, source, clip))
     {
 	return CAIRO_INT_STATUS_NOTHING_TO_DO;
     }
 
-    extents->mask = *unbounded;
+    extents->mask = extents->destination;
 
     extents->clip = _cairo_clip_reduce_for_composite (clip, extents);
     if (_cairo_clip_is_all_clipped (extents->clip))
 	return CAIRO_INT_STATUS_NOTHING_TO_DO;
 
+    if (extents->source_pattern.base.type != CAIRO_PATTERN_TYPE_SOLID)
+	_cairo_pattern_sampled_area (&extents->source_pattern.base,
+				     &extents->bounded,
+				     &extents->source_sample_area);
+
     return CAIRO_STATUS_SUCCESS;
 }
 
@@ -117,6 +153,21 @@ _cairo_composite_rectangles_intersect (cairo_composite_rectangles_t *extents,
     if (_cairo_clip_is_all_clipped (extents->clip))
 	return CAIRO_INT_STATUS_NOTHING_TO_DO;
 
+    if (extents->source_pattern.base.type != CAIRO_PATTERN_TYPE_SOLID)
+	_cairo_pattern_sampled_area (&extents->source_pattern.base,
+				     &extents->bounded,
+				     &extents->source_sample_area);
+    if (extents->mask_pattern.base.type != CAIRO_PATTERN_TYPE_SOLID) {
+	_cairo_pattern_sampled_area (&extents->mask_pattern.base,
+				     &extents->bounded,
+				     &extents->mask_sample_area);
+	if (extents->mask_sample_area.width == 0 ||
+	    extents->mask_sample_area.height == 0) {
+	    _cairo_composite_rectangles_fini (extents);
+	    return CAIRO_INT_STATUS_NOTHING_TO_DO;
+	}
+    }
+
     return CAIRO_STATUS_SUCCESS;
 }
 
@@ -125,7 +176,6 @@ _cairo_composite_rectangles_intersect_mask_extents (cairo_composite_rectangles_t
 						    const cairo_box_t *box)
 {
     cairo_rectangle_int_t mask;
-    cairo_int_status_t status;
     cairo_clip_t *clip;
 
     _cairo_box_round_to_rectangle (box, &mask);
@@ -139,39 +189,70 @@ _cairo_composite_rectangles_intersect_mask_extents (cairo_composite_rectangles_t
 
     _cairo_rectangle_intersect (&extents->mask, &mask);
 
+    mask = extents->bounded;
+    if (! _cairo_rectangle_intersect (&extents->bounded, &extents->mask) &&
+	extents->is_bounded & CAIRO_OPERATOR_BOUND_BY_MASK)
+	return CAIRO_INT_STATUS_NOTHING_TO_DO;
+
+    if (mask.width  == extents->bounded.width &&
+	mask.height == extents->bounded.height)
+	return CAIRO_INT_STATUS_SUCCESS;
+
+    if (extents->is_bounded == (CAIRO_OPERATOR_BOUND_BY_MASK | CAIRO_OPERATOR_BOUND_BY_SOURCE))
+	extents->unbounded = extents->bounded;
+
     extents->mask = mask;
     clip = extents->clip;
 
-    status = _cairo_composite_rectangles_intersect (extents, clip);
+    extents->clip = _cairo_clip_reduce_for_composite (clip, extents);
 
     if (clip != extents->clip)
 	_cairo_clip_destroy (clip);
 
-    return status;
+    if (_cairo_clip_is_all_clipped (extents->clip))
+	return CAIRO_INT_STATUS_NOTHING_TO_DO;
+
+    if (extents->source_pattern.base.type != CAIRO_PATTERN_TYPE_SOLID)
+	_cairo_pattern_sampled_area (&extents->source_pattern.base,
+				     &extents->bounded,
+				     &extents->source_sample_area);
+    if (extents->mask_pattern.base.type != CAIRO_PATTERN_TYPE_SOLID) {
+	_cairo_pattern_sampled_area (&extents->mask_pattern.base,
+				     &extents->bounded,
+				     &extents->mask_sample_area);
+	if (extents->mask_sample_area.width == 0 ||
+	    extents->mask_sample_area.height == 0)
+	    return CAIRO_INT_STATUS_NOTHING_TO_DO;
+    }
+
+    return CAIRO_INT_STATUS_SUCCESS;
 }
 
 cairo_int_status_t
 _cairo_composite_rectangles_init_for_mask (cairo_composite_rectangles_t *extents,
-					   const cairo_rectangle_int_t *unbounded,
+					   cairo_surface_t*surface,
 					   cairo_operator_t		 op,
 					   const cairo_pattern_t	*source,
 					   const cairo_pattern_t	*mask,
 					   const cairo_clip_t		*clip)
 {
-    if (! _cairo_composite_rectangles_init (extents, unbounded,
-					    op, source, clip))
+    if (! _cairo_composite_rectangles_init (extents,
+					    surface, op, source, clip))
     {
 	return CAIRO_INT_STATUS_NOTHING_TO_DO;
     }
 
-    _cairo_pattern_get_extents (mask, &extents->mask);
+
+    extents->original_mask_pattern = mask;
+    _cairo_composite_reduce_pattern (mask, &extents->mask_pattern);
+    _cairo_pattern_get_extents (&extents->mask_pattern.base, &extents->mask);
 
     return _cairo_composite_rectangles_intersect (extents, clip);
 }
 
 cairo_int_status_t
 _cairo_composite_rectangles_init_for_stroke (cairo_composite_rectangles_t *extents,
-					     const cairo_rectangle_int_t *unbounded,
+					     cairo_surface_t *surface,
 					     cairo_operator_t		 op,
 					     const cairo_pattern_t	*source,
 					     const cairo_path_fixed_t		*path,
@@ -179,8 +260,8 @@ _cairo_composite_rectangles_init_for_stroke (cairo_composite_rectangles_t *exten
 					     const cairo_matrix_t	*ctm,
 					     const cairo_clip_t		*clip)
 {
-    if (! _cairo_composite_rectangles_init (extents, unbounded,
-					    op, source, clip))
+    if (! _cairo_composite_rectangles_init (extents,
+					    surface, op, source, clip))
     {
 	return CAIRO_INT_STATUS_NOTHING_TO_DO;
     }
@@ -192,14 +273,14 @@ _cairo_composite_rectangles_init_for_stroke (cairo_composite_rectangles_t *exten
 
 cairo_int_status_t
 _cairo_composite_rectangles_init_for_fill (cairo_composite_rectangles_t *extents,
-					   const cairo_rectangle_int_t *unbounded,
+					   cairo_surface_t *surface,
 					   cairo_operator_t		 op,
 					   const cairo_pattern_t	*source,
 					   const cairo_path_fixed_t		*path,
 					   const cairo_clip_t		*clip)
 {
-    if (! _cairo_composite_rectangles_init (extents, unbounded,
-					    op, source, clip))
+    if (! _cairo_composite_rectangles_init (extents,
+					    surface, op, source, clip))
     {
 	return CAIRO_INT_STATUS_NOTHING_TO_DO;
     }
@@ -210,8 +291,47 @@ _cairo_composite_rectangles_init_for_fill (cairo_composite_rectangles_t *extents
 }
 
 cairo_int_status_t
+_cairo_composite_rectangles_init_for_polygon (cairo_composite_rectangles_t *extents,
+					      cairo_surface_t		*surface,
+					      cairo_operator_t		 op,
+					      const cairo_pattern_t	*source,
+					      const cairo_polygon_t	*polygon,
+					      const cairo_clip_t		*clip)
+{
+    if (! _cairo_composite_rectangles_init (extents,
+					    surface, op, source, clip))
+    {
+	return CAIRO_INT_STATUS_NOTHING_TO_DO;
+    }
+
+    _cairo_box_round_to_rectangle (&polygon->extents, &extents->mask);
+    return _cairo_composite_rectangles_intersect (extents, clip);
+}
+
+cairo_int_status_t
+_cairo_composite_rectangles_init_for_boxes (cairo_composite_rectangles_t *extents,
+					      cairo_surface_t		*surface,
+					      cairo_operator_t		 op,
+					      const cairo_pattern_t	*source,
+					      const cairo_boxes_t	*boxes,
+					      const cairo_clip_t		*clip)
+{
+    cairo_box_t box;
+
+    if (! _cairo_composite_rectangles_init (extents,
+					    surface, op, source, clip))
+    {
+	return CAIRO_INT_STATUS_NOTHING_TO_DO;
+    }
+
+    _cairo_boxes_extents (boxes, &box);
+    _cairo_box_round_to_rectangle (&box, &extents->mask);
+    return _cairo_composite_rectangles_intersect (extents, clip);
+}
+
+cairo_int_status_t
 _cairo_composite_rectangles_init_for_glyphs (cairo_composite_rectangles_t *extents,
-					     const cairo_rectangle_int_t *unbounded,
+					     cairo_surface_t *surface,
 					     cairo_operator_t		 op,
 					     const cairo_pattern_t	*source,
 					     cairo_scaled_font_t	*scaled_font,
@@ -222,8 +342,7 @@ _cairo_composite_rectangles_init_for_glyphs (cairo_composite_rectangles_t *exten
 {
     cairo_status_t status;
 
-    if (! _cairo_composite_rectangles_init (extents, unbounded,
-					    op, source, clip))
+    if (! _cairo_composite_rectangles_init (extents, surface, op, source, clip))
 	return CAIRO_INT_STATUS_NOTHING_TO_DO;
 
     /* Computing the exact bbox and the overlap is expensive.
diff --git a/src/cairo-compositor-private.h b/src/cairo-compositor-private.h
new file mode 100644
index 0000000..72507b2
--- /dev/null
+++ b/src/cairo-compositor-private.h
@@ -0,0 +1,355 @@
+/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
+/* cairo - a vector graphics library with display and print output
+ *
+ * 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):
+ *	Chris Wilson <chris at chris-wilson.co.uk>
+ */
+
+#ifndef CAIRO_COMPOSITOR_PRIVATE_H
+#define CAIRO_COMPOSITOR_PRIVATE_H
+
+#include "cairo-composite-rectangles-private.h"
+
+CAIRO_BEGIN_DECLS
+
+typedef struct {
+    cairo_scaled_font_t *font;
+    cairo_glyph_t *glyphs;
+    int num_glyphs;
+    cairo_bool_t use_mask;
+    cairo_rectangle_int_t extents;
+} cairo_composite_glyphs_info_t;
+
+struct cairo_compositor {
+    const cairo_compositor_t *delegate;
+
+    cairo_warn cairo_int_status_t
+    (*paint)			(const cairo_compositor_t	*compositor,
+				 cairo_composite_rectangles_t	*extents);
+
+    cairo_warn cairo_int_status_t
+    (*mask)			(const cairo_compositor_t	*compositor,
+				 cairo_composite_rectangles_t	*extents);
+
+    cairo_warn cairo_int_status_t
+    (*stroke)			(const cairo_compositor_t	*compositor,
+				 cairo_composite_rectangles_t	*extents,
+				 const cairo_path_fixed_t	*path,
+				 const cairo_stroke_style_t	*style,
+				 const cairo_matrix_t		*ctm,
+				 const cairo_matrix_t		*ctm_inverse,
+				 double				 tolerance,
+				 cairo_antialias_t		 antialias);
+
+    cairo_warn cairo_int_status_t
+    (*fill)			(const cairo_compositor_t	*compositor,
+				 cairo_composite_rectangles_t	*extents,
+				 const cairo_path_fixed_t	*path,
+				 cairo_fill_rule_t		 fill_rule,
+				 double				 tolerance,
+				 cairo_antialias_t		 antialias);
+
+    cairo_warn cairo_int_status_t
+    (*glyphs)			(const cairo_compositor_t	 *compositor,
+				 cairo_composite_rectangles_t	*extents,
+				 cairo_scaled_font_t		*scaled_font,
+				 cairo_glyph_t			*glyphs,
+				 int				 num_glyphs,
+				 cairo_bool_t			 overlap);
+};
+
+struct cairo_mask_compositor {
+    cairo_compositor_t base;
+
+    cairo_int_status_t (*acquire) (void *surface);
+    cairo_int_status_t (*release) (void *surface);
+
+    cairo_int_status_t (*set_clip_region) (void		 *surface,
+					   cairo_region_t	*clip_region);
+
+    cairo_surface_t * (*pattern_to_surface) (cairo_surface_t *dst,
+					     const cairo_pattern_t *pattern,
+					     cairo_bool_t is_mask,
+					     const cairo_rectangle_int_t *extents,
+					     const cairo_rectangle_int_t *sample,
+					     int *src_x, int *src_y);
+
+    cairo_int_status_t (*draw_image_boxes) (void *surface,
+					    cairo_image_surface_t *image,
+					    cairo_boxes_t *boxes,
+					    int dx, int dy);
+
+    cairo_int_status_t (*copy_boxes) (void *surface,
+				      cairo_surface_t *src,
+				      cairo_boxes_t *boxes,
+				      const cairo_rectangle_int_t *extents,
+				      int dx, int dy);
+
+    cairo_int_status_t
+	(*fill_rectangles)	(void			 *surface,
+				 cairo_operator_t	  op,
+				 const cairo_color_t     *color,
+				 cairo_rectangle_int_t   *rectangles,
+				 int			  num_rects);
+
+    cairo_int_status_t
+	(*fill_boxes)		(void			*surface,
+				 cairo_operator_t	 op,
+				 const cairo_color_t	*color,
+				 cairo_boxes_t		*boxes);
+
+    cairo_int_status_t
+	(*composite)		(void			*dst,
+				 cairo_operator_t	 op,
+				 cairo_surface_t	*src,
+				 cairo_surface_t	*mask,
+				 int			 src_x,
+				 int			 src_y,
+				 int			 mask_x,
+				 int			 mask_y,
+				 int			 dst_x,
+				 int			 dst_y,
+				 unsigned int		 width,
+				 unsigned int		 height);
+
+    cairo_int_status_t
+	(*composite_boxes)	(void			*surface,
+				 cairo_operator_t	 op,
+				 cairo_surface_t	*source,
+				 cairo_surface_t	*mask,
+				 int			 src_x,
+				 int			 src_y,
+				 int			 mask_x,
+				 int			 mask_y,
+				 int			 dst_x,
+				 int			 dst_y,
+				 cairo_boxes_t		*boxes,
+				 const cairo_rectangle_int_t  *extents);
+
+    cairo_int_status_t
+	(*check_composite_glyphs) (const cairo_composite_rectangles_t *extents,
+				   cairo_scaled_font_t *scaled_font,
+				   cairo_glyph_t *glyphs,
+				   int *num_glyphs);
+    cairo_int_status_t
+	(*composite_glyphs)	(void				*surface,
+				 cairo_operator_t		 op,
+				 cairo_surface_t		*src,
+				 int				 src_x,
+				 int				 src_y,
+				 int				 dst_x,
+				 int				 dst_y,
+				 cairo_composite_glyphs_info_t  *info);
+};
+
+struct cairo_traps_compositor {
+    cairo_compositor_t base;
+
+    cairo_int_status_t
+	(*acquire) (void *surface);
+
+    cairo_int_status_t
+	(*release) (void *surface);
+
+    cairo_int_status_t
+	(*set_clip_region) (void		 *surface,
+			    cairo_region_t	*clip_region);
+
+    cairo_surface_t *
+	(*pattern_to_surface) (cairo_surface_t *dst,
+			       const cairo_pattern_t *pattern,
+			       cairo_bool_t is_mask,
+			       const cairo_rectangle_int_t *extents,
+			       const cairo_rectangle_int_t *sample,
+			       int *src_x, int *src_y);
+
+    cairo_int_status_t (*draw_image_boxes) (void *surface,
+					    cairo_image_surface_t *image,
+					    cairo_boxes_t *boxes,
+					    int dx, int dy);
+
+    cairo_int_status_t (*copy_boxes) (void *surface,
+				      cairo_surface_t *src,
+				      cairo_boxes_t *boxes,
+				      const cairo_rectangle_int_t *extents,
+				      int dx, int dy);
+
+    cairo_int_status_t
+	(*fill_boxes)		(void			*surface,
+				 cairo_operator_t	 op,
+				 const cairo_color_t	*color,
+				 cairo_boxes_t		*boxes);
+
+    cairo_int_status_t
+	(*composite)		(void			*dst,
+				 cairo_operator_t	 op,
+				 cairo_surface_t	*src,
+				 cairo_surface_t	*mask,
+				 int			 src_x,
+				 int			 src_y,
+				 int			 mask_x,
+				 int			 mask_y,
+				 int			 dst_x,
+				 int			 dst_y,
+				 unsigned int		 width,
+				 unsigned int		 height);
+    cairo_int_status_t
+	    (*lerp)		(void			*_dst,
+				 cairo_surface_t	*abstract_src,
+				 cairo_surface_t	*abstract_mask,
+				 int			src_x,
+				 int			src_y,
+				 int			mask_x,
+				 int			mask_y,
+				 int			dst_x,
+				 int			dst_y,
+				 unsigned int		width,
+				 unsigned int		height);
+
+    cairo_int_status_t
+	(*composite_boxes)	(void			*surface,
+				 cairo_operator_t	 op,
+				 cairo_surface_t	*source,
+				 cairo_surface_t	*mask,
+				 int			 src_x,
+				 int			 src_y,
+				 int			 mask_x,
+				 int			 mask_y,
+				 int			 dst_x,
+				 int			 dst_y,
+				 cairo_boxes_t		*boxes,
+				 const cairo_rectangle_int_t  *extents);
+
+    cairo_int_status_t
+	(*composite_traps)	(void			*dst,
+				 cairo_operator_t	 op,
+				 cairo_surface_t	*source,
+				 int			 src_x,
+				 int			 src_y,
+				 int			 dst_x,
+				 int			 dst_y,
+				 const cairo_rectangle_int_t *extents,
+				 cairo_antialias_t	 antialias,
+				 cairo_traps_t		*traps);
+
+    cairo_int_status_t
+	(*composite_tristrip)	(void			*dst,
+				 cairo_operator_t	 op,
+				 cairo_surface_t	*source,
+				 int			 src_x,
+				 int			 src_y,
+				 int			 dst_x,
+				 int			 dst_y,
+				 const cairo_rectangle_int_t *extents,
+				 cairo_antialias_t	 antialias,
+				 cairo_tristrip_t	*tristrip);
+
+    cairo_int_status_t
+	(*check_composite_glyphs) (const cairo_composite_rectangles_t *extents,
+				   cairo_scaled_font_t *scaled_font,
+				   cairo_glyph_t *glyphs,
+				   int *num_glyphs);
+    cairo_int_status_t
+	(*composite_glyphs)	(void				*surface,
+				 cairo_operator_t		 op,
+				 cairo_surface_t		*src,
+				 int				 src_x,
+				 int				 src_y,
+				 int				 dst_x,
+				 int				 dst_y,
+				 cairo_composite_glyphs_info_t  *info);
+};
+
+cairo_private extern const cairo_compositor_t __cairo_no_compositor;
+cairo_private extern const cairo_compositor_t _cairo_fallback_compositor;
+
+cairo_private void
+_cairo_mask_compositor_init (cairo_mask_compositor_t *compositor,
+			     const cairo_compositor_t *delegate);
+
+cairo_private void
+_cairo_traps_compositor_init (cairo_traps_compositor_t *compositor,
+			      const cairo_compositor_t *delegate);
+
+cairo_private cairo_int_status_t
+_cairo_compositor_paint (const cairo_compositor_t	*compositor,
+			 cairo_surface_t		*surface,
+			 cairo_operator_t		 op,
+			 const cairo_pattern_t		*source,
+			 const cairo_clip_t		*clip);
+
+cairo_private cairo_int_status_t
+_cairo_compositor_mask (const cairo_compositor_t	*compositor,
+			cairo_surface_t			*surface,
+			cairo_operator_t		 op,
+			const cairo_pattern_t		*source,
+			const cairo_pattern_t		*mask,
+			const cairo_clip_t		*clip);
+
+cairo_private cairo_int_status_t
+_cairo_compositor_stroke (const cairo_compositor_t	*compositor,
+			  cairo_surface_t		*surface,
+			  cairo_operator_t		 op,
+			  const cairo_pattern_t		*source,
+			  const cairo_path_fixed_t	*path,
+			  const cairo_stroke_style_t	*style,
+			  const cairo_matrix_t		*ctm,
+			  const cairo_matrix_t		*ctm_inverse,
+			  double			 tolerance,
+			  cairo_antialias_t		 antialias,
+			  const cairo_clip_t		*clip);
+
+cairo_private cairo_int_status_t
+_cairo_compositor_fill (const cairo_compositor_t	*compositor,
+			cairo_surface_t			*surface,
+			cairo_operator_t		 op,
+			const cairo_pattern_t		*source,
+			const cairo_path_fixed_t	*path,
+			cairo_fill_rule_t		 fill_rule,
+			double				 tolerance,
+			cairo_antialias_t		 antialias,
+			const cairo_clip_t		*clip);
+
+cairo_private cairo_int_status_t
+_cairo_compositor_glyphs (const cairo_compositor_t		*compositor,
+			  cairo_surface_t			*surface,
+			  cairo_operator_t			 op,
+			  const cairo_pattern_t			*source,
+			  cairo_glyph_t				*glyphs,
+			  int					 num_glyphs,
+			  cairo_scaled_font_t			*scaled_font,
+			  const cairo_clip_t			*clip);
+
+CAIRO_END_DECLS
+
+#endif /* CAIRO_COMPOSITOR_PRIVATE_H */
diff --git a/src/cairo-compositor.c b/src/cairo-compositor.c
new file mode 100644
index 0000000..cf943e7
--- /dev/null
+++ b/src/cairo-compositor.c
@@ -0,0 +1,213 @@
+/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
+/* cairo - a vector graphics library with display and print output
+ *
+ * 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):
+ *	Chris Wilson <chris at chris-wilson.co.uk>
+ */
+
+#include "cairoint.h"
+
+#include "cairo-compositor-private.h"
+#include "cairo-error-private.h"
+
+cairo_int_status_t
+_cairo_compositor_paint (const cairo_compositor_t	*compositor,
+			 cairo_surface_t		*surface,
+			 cairo_operator_t		 op,
+			 const cairo_pattern_t		*source,
+			 const cairo_clip_t		*clip)
+{
+    cairo_composite_rectangles_t extents;
+    cairo_int_status_t status;
+
+    status = _cairo_composite_rectangles_init_for_paint (&extents, surface,
+							 op, source,
+							 clip);
+    if (unlikely (status))
+	return status;
+
+    do {
+	while (compositor->paint == NULL)
+	    compositor = compositor->delegate;
+
+	status = compositor->paint (compositor, &extents);
+
+	compositor = compositor->delegate;
+    } while (status == CAIRO_INT_STATUS_UNSUPPORTED);
+
+    _cairo_composite_rectangles_fini (&extents);
+
+    return status;
+}
+
+cairo_int_status_t
+_cairo_compositor_mask (const cairo_compositor_t	*compositor,
+			cairo_surface_t			*surface,
+			cairo_operator_t		 op,
+			const cairo_pattern_t		*source,
+			const cairo_pattern_t		*mask,
+			const cairo_clip_t		*clip)
+{
+    cairo_composite_rectangles_t extents;
+    cairo_int_status_t status;
+
+    status = _cairo_composite_rectangles_init_for_mask (&extents, surface,
+							op, source, mask,
+							clip);
+    if (unlikely (status))
+	return status;
+
+    do {
+	while (compositor->mask == NULL)
+	    compositor = compositor->delegate;
+
+	status = compositor->mask (compositor, &extents);
+
+	compositor = compositor->delegate;
+    } while (status == CAIRO_INT_STATUS_UNSUPPORTED);
+
+    _cairo_composite_rectangles_fini (&extents);
+
+    return status;
+}
+
+cairo_int_status_t
+_cairo_compositor_stroke (const cairo_compositor_t	*compositor,
+			  cairo_surface_t		*surface,
+			  cairo_operator_t		 op,
+			  const cairo_pattern_t		*source,
+			  const cairo_path_fixed_t	*path,
+			  const cairo_stroke_style_t	*style,
+			  const cairo_matrix_t		*ctm,
+			  const cairo_matrix_t		*ctm_inverse,
+			  double			 tolerance,
+			  cairo_antialias_t		 antialias,
+			  const cairo_clip_t		*clip)
+{
+    cairo_composite_rectangles_t extents;
+    cairo_int_status_t status;
+
+    status = _cairo_composite_rectangles_init_for_stroke (&extents, surface,
+							  op, source,
+							  path, style, ctm,
+							  clip);
+    if (unlikely (status))
+	return status;
+
+    do {
+	while (compositor->stroke == NULL)
+	    compositor = compositor->delegate;
+
+	status = compositor->stroke (compositor, &extents,
+				     path, style, ctm, ctm_inverse,
+				     tolerance, antialias);
+
+	compositor = compositor->delegate;
+    } while (status == CAIRO_INT_STATUS_UNSUPPORTED);
+
+    _cairo_composite_rectangles_fini (&extents);
+
+    return status;
+}
+
+cairo_int_status_t
+_cairo_compositor_fill (const cairo_compositor_t	*compositor,
+			cairo_surface_t			*surface,
+			cairo_operator_t		 op,
+			const cairo_pattern_t		*source,
+			const cairo_path_fixed_t	*path,
+			cairo_fill_rule_t		 fill_rule,
+			double				 tolerance,
+			cairo_antialias_t		 antialias,
+			const cairo_clip_t		*clip)
+{
+    cairo_composite_rectangles_t extents;
+    cairo_int_status_t status;
+
+    status = _cairo_composite_rectangles_init_for_fill (&extents, surface,
+							op, source, path,
+							clip);
+    if (unlikely (status))
+	return status;
+
+    do {
+	while (compositor->fill == NULL)
+	    compositor = compositor->delegate;
+
+	status = compositor->fill (compositor, &extents,
+				   path, fill_rule, tolerance, antialias);
+
+	compositor = compositor->delegate;
+    } while (status == CAIRO_INT_STATUS_UNSUPPORTED);
+
+    _cairo_composite_rectangles_fini (&extents);
+
+    return status;
+}
+
+cairo_int_status_t
+_cairo_compositor_glyphs (const cairo_compositor_t		*compositor,
+			  cairo_surface_t			*surface,
+			  cairo_operator_t			 op,
+			  const cairo_pattern_t			*source,
+			  cairo_glyph_t				*glyphs,
+			  int					 num_glyphs,
+			  cairo_scaled_font_t			*scaled_font,
+			  const cairo_clip_t			*clip)
+{
+    cairo_composite_rectangles_t extents;
+    cairo_bool_t overlap;
+    cairo_int_status_t status;
+
+    status = _cairo_composite_rectangles_init_for_glyphs (&extents, surface,
+							  op, source,
+							  scaled_font,
+							  glyphs, num_glyphs,
+							  clip, &overlap);
+    if (unlikely (status))
+	return status;
+
+    do {
+	while (compositor->glyphs == NULL)
+	    compositor = compositor->delegate;
+
+	status = compositor->glyphs (compositor, &extents,
+				     scaled_font, glyphs, num_glyphs, overlap);
+
+	compositor = compositor->delegate;
+    } while (status == CAIRO_INT_STATUS_UNSUPPORTED);
+
+    _cairo_composite_rectangles_fini (&extents);
+
+    return status;
+}
diff --git a/src/cairo-default-context.c b/src/cairo-default-context.c
index 017eb7b..98cc668 100644
--- a/src/cairo-default-context.c
+++ b/src/cairo-default-context.c
@@ -158,8 +158,7 @@ _cairo_default_context_push_group (void *abstract_cr, cairo_content_t content)
 							     content,
 							     extents.width,
 							     extents.height,
-							     CAIRO_COLOR_TRANSPARENT,
-							     TRUE);
+							     CAIRO_COLOR_TRANSPARENT);
 	status = group_surface->status;
 	if (unlikely (status))
 	    goto bail;
diff --git a/src/cairo-fallback-compositor.c b/src/cairo-fallback-compositor.c
new file mode 100644
index 0000000..105859d
--- /dev/null
+++ b/src/cairo-fallback-compositor.c
@@ -0,0 +1,174 @@
+/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
+/* 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>
+ *      Joonas Pihlaja <jpihlaja at cc.helsinki.fi>
+ *	Chris Wilson <chris at chris-wilson.co.uk>
+ */
+
+#include "cairoint.h"
+
+#include "cairo-compositor-private.h"
+#include "cairo-surface-offset-private.h"
+
+/* high-level compositor interface */
+
+static cairo_int_status_t
+_cairo_fallback_compositor_paint (const cairo_compositor_t	*_compositor,
+				  cairo_composite_rectangles_t	*extents)
+{
+    cairo_surface_t *image;
+    cairo_int_status_t status;
+
+    image = cairo_surface_map_to_image (extents->surface, &extents->unbounded);
+    status = _cairo_surface_offset_paint (image,
+					  -extents->unbounded.x,
+					  -extents->unbounded.y,
+					  extents->op,
+					  &extents->source_pattern.base,
+					  extents->clip);
+    cairo_surface_unmap_image (extents->surface, image);
+
+    return status;
+}
+
+static cairo_int_status_t
+_cairo_fallback_compositor_mask (const cairo_compositor_t	*_compositor,
+				 cairo_composite_rectangles_t	*extents)
+{
+    cairo_surface_t *image;
+    cairo_int_status_t status;
+
+    image = cairo_surface_map_to_image (extents->surface, &extents->unbounded);
+    status = _cairo_surface_offset_mask (image,
+					 extents->unbounded.x,
+					 extents->unbounded.y,
+					 extents->op,
+					 &extents->source_pattern.base,
+					 &extents->mask_pattern.base,
+					 extents->clip);
+    cairo_surface_unmap_image (extents->surface, image);
+
+    return status;
+}
+
+static cairo_int_status_t
+_cairo_fallback_compositor_stroke (const cairo_compositor_t	*_compositor,
+				   cairo_composite_rectangles_t *extents,
+				   const cairo_path_fixed_t	*path,
+				   const cairo_stroke_style_t	*style,
+				   const cairo_matrix_t		*ctm,
+				   const cairo_matrix_t		*ctm_inverse,
+				   double			 tolerance,
+				   cairo_antialias_t		 antialias)
+{
+    cairo_surface_t *image;
+    cairo_int_status_t status;
+
+    image = cairo_surface_map_to_image (extents->surface, &extents->unbounded);
+    status = _cairo_surface_offset_stroke (image,
+					   extents->unbounded.x,
+					   extents->unbounded.y,
+					   extents->op,
+					   &extents->source_pattern.base,
+					   path, style,
+					   ctm, ctm_inverse,
+					   tolerance,
+					   antialias,
+					   extents->clip);
+    cairo_surface_unmap_image (extents->surface, image);
+
+    return status;
+}
+
+static cairo_int_status_t
+_cairo_fallback_compositor_fill (const cairo_compositor_t	*_compositor,
+				 cairo_composite_rectangles_t *extents,
+				 const cairo_path_fixed_t	*path,
+				 cairo_fill_rule_t		 fill_rule,
+				 double				 tolerance,
+				 cairo_antialias_t		 antialias)
+{
+    cairo_surface_t *image;
+    cairo_int_status_t status;
+
+    image = cairo_surface_map_to_image (extents->surface, &extents->unbounded);
+    status = _cairo_surface_offset_fill (image,
+					 extents->unbounded.x,
+					 extents->unbounded.y,
+					 extents->op,
+					 &extents->source_pattern.base,
+					 path,
+					 fill_rule, tolerance, antialias,
+					 extents->clip);
+    cairo_surface_unmap_image (extents->surface, image);
+
+    return status;
+}
+
+static cairo_int_status_t
+_cairo_fallback_compositor_glyphs (const cairo_compositor_t	*_compositor,
+				   cairo_composite_rectangles_t *extents,
+				   cairo_scaled_font_t		*scaled_font,
+				   cairo_glyph_t		*glyphs,
+				   int				 num_glyphs,
+				   cairo_bool_t			 overlap)
+{
+    cairo_surface_t *image;
+    cairo_int_status_t status;
+
+    image = cairo_surface_map_to_image (extents->surface, &extents->unbounded);
+    status = _cairo_surface_offset_glyphs (image,
+					   extents->unbounded.x,
+					   extents->unbounded.y,
+					   extents->op,
+					   &extents->source_pattern.base,
+					   scaled_font, glyphs, num_glyphs,
+					   extents->clip);
+    cairo_surface_unmap_image (extents->surface, image);
+
+    return status;
+}
+
+const cairo_compositor_t _cairo_fallback_compositor = {
+     &__cairo_no_compositor,
+
+     _cairo_fallback_compositor_paint,
+     _cairo_fallback_compositor_mask,
+     _cairo_fallback_compositor_stroke,
+     _cairo_fallback_compositor_fill,
+     _cairo_fallback_compositor_glyphs,
+};
diff --git a/src/cairo-freed-pool-private.h b/src/cairo-freed-pool-private.h
index 259c57d..0ec6de3 100644
--- a/src/cairo-freed-pool-private.h
+++ b/src/cairo-freed-pool-private.h
@@ -42,7 +42,9 @@
 
 CAIRO_BEGIN_DECLS
 
-#if HAS_ATOMIC_OPS
+#define DISABLE_FREED_POOLS 0
+
+#if HAS_ATOMIC_OPS && ! DISABLE_FREED_POOLS
 /* Keep a stash of recently freed clip_paths, since we need to
  * reallocate them frequently.
  */
@@ -128,7 +130,7 @@ typedef int freed_pool_t;
 
 #define _freed_pool_get(pool) NULL
 #define _freed_pool_put(pool, ptr) free(ptr)
-#define _freed_pool_reset(ptr) assert((ptr) != NULL)
+#define _freed_pool_reset(ptr)
 
 #endif
 
diff --git a/src/cairo-ft-font.c b/src/cairo-ft-font.c
index 9024463..e0df535 100644
--- a/src/cairo-ft-font.c
+++ b/src/cairo-ft-font.c
@@ -2586,7 +2586,6 @@ static const cairo_scaled_font_backend_t _cairo_ft_scaled_font_backend = {
     _cairo_ft_scaled_glyph_init,
     NULL,			/* text_to_glyphs */
     _cairo_ft_ucs4_to_index,
-    NULL,			/* show_glyphs */
     _cairo_ft_load_truetype_table,
     _cairo_ft_index_to_ucs4,
     _cairo_ft_is_synthetic,
diff --git a/src/cairo-gl-composite.c b/src/cairo-gl-composite.c
index 01fe725..c59501e 100644
--- a/src/cairo-gl-composite.c
+++ b/src/cairo-gl-composite.c
@@ -49,326 +49,6 @@
 #include "cairo-error-private.h"
 #include "cairo-image-surface-private.h"
 
-static cairo_int_status_t
-_cairo_gl_create_gradient_texture (cairo_gl_surface_t *dst,
-				   const cairo_gradient_pattern_t *pattern,
-                                   cairo_gl_gradient_t **gradient)
-{
-    cairo_gl_context_t *ctx;
-    cairo_status_t status;
-
-    status = _cairo_gl_context_acquire (dst->base.device, &ctx);
-    if (unlikely (status))
-	return status;
-
-    status = _cairo_gl_gradient_create (ctx, pattern->n_stops, pattern->stops, gradient);
-
-    return _cairo_gl_context_release (ctx, status);
-}
-
-/*
- * Like cairo_pattern_acquire_surface(), but returns a matrix that transforms
- * from dest to src coords.
- */
-static cairo_status_t
-_cairo_gl_pattern_texture_setup (cairo_gl_operand_t *operand,
-				 const cairo_pattern_t *src,
-				 cairo_gl_surface_t *dst,
-				 int src_x, int src_y,
-				 int dst_x, int dst_y,
-				 int width, int height)
-{
-    cairo_status_t status;
-    cairo_matrix_t m;
-    cairo_gl_surface_t *surface;
-    cairo_surface_attributes_t *attributes;
-    attributes = &operand->texture.attributes;
-
-    status = _cairo_pattern_acquire_surface (src, &dst->base,
-					     src_x, src_y,
-					     width, height,
-					     CAIRO_PATTERN_ACQUIRE_NONE,
-					     (cairo_surface_t **)
-					     &surface,
-					     attributes);
-    if (unlikely (status))
-	return status;
-
-    if (_cairo_gl_device_requires_power_of_two_textures (dst->base.device) &&
-	(attributes->extend == CAIRO_EXTEND_REPEAT ||
-	 attributes->extend == CAIRO_EXTEND_REFLECT))
-    {
-	_cairo_pattern_release_surface (src,
-					&surface->base,
-					attributes);
-	return UNSUPPORTED ("EXT_texture_rectangle with repeat/reflect");
-    }
-
-    assert (surface->base.backend == &_cairo_gl_surface_backend);
-    assert (_cairo_gl_surface_is_texture (surface));
-
-    operand->type = CAIRO_GL_OPERAND_TEXTURE;
-    operand->texture.surface = surface;
-    operand->texture.tex = surface->tex;
-    /* Translate the matrix from
-     * (unnormalized src -> unnormalized src) to
-     * (unnormalized dst -> unnormalized src)
-     */
-    cairo_matrix_init_translate (&m,
-				 src_x - dst_x + attributes->x_offset,
-				 src_y - dst_y + attributes->y_offset);
-    cairo_matrix_multiply (&attributes->matrix,
-			   &m,
-			   &attributes->matrix);
-
-
-    /* Translate the matrix from
-     * (unnormalized dst -> unnormalized src) to
-     * (unnormalized dst -> normalized src)
-     */
-    if (_cairo_gl_device_requires_power_of_two_textures (dst->base.device)) {
-	cairo_matrix_init_scale (&m,
-				 1.0,
-				 1.0);
-    } else {
-	cairo_matrix_init_scale (&m,
-				 1.0 / surface->width,
-				 1.0 / surface->height);
-    }
-    cairo_matrix_multiply (&attributes->matrix,
-			   &attributes->matrix,
-			   &m);
-
-    return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_gl_solid_operand_init (cairo_gl_operand_t *operand,
-	                      const cairo_color_t *color)
-{
-    operand->type = CAIRO_GL_OPERAND_CONSTANT;
-    operand->constant.color[0] = color->red   * color->alpha;
-    operand->constant.color[1] = color->green * color->alpha;
-    operand->constant.color[2] = color->blue  * color->alpha;
-    operand->constant.color[3] = color->alpha;
-    return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_gl_gradient_operand_init (cairo_gl_operand_t *operand,
-                                 const cairo_pattern_t *pattern,
-				 cairo_gl_surface_t *dst,
-				 int src_x, int src_y,
-				 int dst_x, int dst_y)
-{
-    const cairo_gradient_pattern_t *gradient = (const cairo_gradient_pattern_t *)pattern;
-    cairo_status_t status;
-
-    assert (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR ||
-	    gradient->base.type == CAIRO_PATTERN_TYPE_RADIAL);
-
-    if (! _cairo_gl_device_has_glsl (dst->base.device))
-	return CAIRO_INT_STATUS_UNSUPPORTED;
-
-    status = _cairo_gl_create_gradient_texture (dst,
-						gradient,
-						&operand->gradient.gradient);
-    if (unlikely (status))
-	return status;
-
-    if (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR) {
-	cairo_linear_pattern_t *linear = (cairo_linear_pattern_t *) gradient;
-	double x0, y0, dx, dy, sf, offset;
-
-	dx = linear->pd2.x - linear->pd1.x;
-	dy = linear->pd2.y - linear->pd1.y;
-	sf = 1.0 / (dx * dx + dy * dy);
-	dx *= sf;
-	dy *= sf;
-
-	x0 = linear->pd1.x;
-	y0 = linear->pd1.y;
-	offset = dx * x0 + dy * y0;
-
-	operand->type = CAIRO_GL_OPERAND_LINEAR_GRADIENT;
-
-	cairo_matrix_init (&operand->gradient.m, dx, 0, dy, 1, -offset, 0);
-	if (! _cairo_matrix_is_identity (&pattern->matrix)) {
-	    cairo_matrix_multiply (&operand->gradient.m,
-				   &pattern->matrix,
-				   &operand->gradient.m);
-	}
-    } else {
-	cairo_matrix_t m;
-	cairo_circle_double_t circles[2];
-	double x0, y0, r0, dx, dy, dr;
-
-	/*
-	 * Some fragment shader implementations use half-floats to
-	 * represent numbers, so the maximum number they can represent
-	 * is about 2^14. Some intermediate computations used in the
-	 * radial gradient shaders can produce results of up to 2*k^4.
-	 * Setting k=8 makes the maximum result about 8192 (assuming
-	 * that the extreme circles are not much smaller than the
-	 * destination image).
-	 */
-	_cairo_gradient_pattern_fit_to_range (gradient, 8.,
-					      &operand->gradient.m, circles);
-
-	x0 = circles[0].center.x;
-	y0 = circles[0].center.y;
-	r0 = circles[0].radius;
-	dx = circles[1].center.x - x0;
-	dy = circles[1].center.y - y0;
-	dr = circles[1].radius   - r0;
-
-	operand->gradient.a = dx * dx + dy * dy - dr * dr;
-	operand->gradient.radius_0 = r0;
-	operand->gradient.circle_d.center.x = dx;
-	operand->gradient.circle_d.center.y = dy;
-	operand->gradient.circle_d.radius   = dr;
-
-	if (operand->gradient.a == 0)
-	    operand->type = CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0;
-	else if (pattern->extend == CAIRO_EXTEND_NONE)
-	    operand->type = CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE;
-	else
-	    operand->type = CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT;
-
-	cairo_matrix_init_translate (&m, -x0, -y0);
-	cairo_matrix_multiply (&operand->gradient.m,
-			       &operand->gradient.m,
-			       &m);
-    }
-
-    cairo_matrix_translate (&operand->gradient.m, src_x - dst_x, src_y - dst_y);
-
-    operand->gradient.extend = pattern->extend;
-
-    return CAIRO_STATUS_SUCCESS;
-}
-
-static void
-_cairo_gl_operand_destroy (cairo_gl_operand_t *operand)
-{
-    switch (operand->type) {
-    case CAIRO_GL_OPERAND_CONSTANT:
-	break;
-    case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
-    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
-    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
-    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
-	_cairo_gl_gradient_destroy (operand->gradient.gradient);
-	break;
-    case CAIRO_GL_OPERAND_TEXTURE:
-        _cairo_pattern_release_surface (NULL, /* XXX */
-                                        &operand->texture.surface->base,
-                                        &operand->texture.attributes);
-	break;
-    default:
-    case CAIRO_GL_OPERAND_COUNT:
-        ASSERT_NOT_REACHED;
-    case CAIRO_GL_OPERAND_NONE:
-    case CAIRO_GL_OPERAND_SPANS:
-        break;
-    }
-
-    operand->type = CAIRO_GL_OPERAND_NONE;
-}
-
-static cairo_int_status_t
-_cairo_gl_operand_init (cairo_gl_operand_t *operand,
-		        const cairo_pattern_t *pattern,
-		        cairo_gl_surface_t *dst,
-		        int src_x, int src_y,
-		        int dst_x, int dst_y,
-		        int width, int height)
-{
-    cairo_int_status_t status;
-
-    switch (pattern->type) {
-    case CAIRO_PATTERN_TYPE_SOLID:
-	return _cairo_gl_solid_operand_init (operand,
-		                             &((cairo_solid_pattern_t *) pattern)->color);
-    case CAIRO_PATTERN_TYPE_LINEAR:
-    case CAIRO_PATTERN_TYPE_RADIAL:
-	status = _cairo_gl_gradient_operand_init (operand,
-						  pattern, dst,
-						  src_x, src_y,
-						  dst_x, dst_y);
-	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
-	    return status;
-
-	/* fall through */
-
-    default:
-    case CAIRO_PATTERN_TYPE_MESH:
-    case CAIRO_PATTERN_TYPE_SURFACE:
-	return _cairo_gl_pattern_texture_setup (operand,
-						pattern, dst,
-						src_x, src_y,
-						dst_x, dst_y,
-						width, height);
-    }
-}
-
-cairo_filter_t
-_cairo_gl_operand_get_filter (cairo_gl_operand_t *operand)
-{
-    cairo_filter_t filter;
-
-    switch ((int) operand->type) {
-    case CAIRO_GL_OPERAND_TEXTURE:
-	filter = operand->texture.attributes.filter;
-	break;
-    case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
-    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
-    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
-    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
-	filter = CAIRO_FILTER_BILINEAR;
-	break;
-    default:
-	filter = CAIRO_FILTER_DEFAULT;
-	break;
-    }
-
-    return filter;
-}
-
-GLint
-_cairo_gl_operand_get_gl_filter (cairo_gl_operand_t *operand)
-{
-    cairo_filter_t filter = _cairo_gl_operand_get_filter (operand);
-
-    return filter != CAIRO_FILTER_FAST && filter != CAIRO_FILTER_NEAREST ?
-	   GL_LINEAR :
-	   GL_NEAREST;
-}
-
-cairo_extend_t
-_cairo_gl_operand_get_extend (cairo_gl_operand_t *operand)
-{
-    cairo_extend_t extend;
-
-    switch ((int) operand->type) {
-    case CAIRO_GL_OPERAND_TEXTURE:
-	extend = operand->texture.attributes.extend;
-	break;
-    case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
-    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
-    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
-    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
-	extend = operand->gradient.extend;
-	break;
-    default:
-	extend = CAIRO_EXTEND_NONE;
-	break;
-    }
-
-    return extend;
-}
-
-
 cairo_int_status_t
 _cairo_gl_composite_set_source (cairo_gl_composite_t *setup,
 			        const cairo_pattern_t *pattern,
@@ -384,6 +64,22 @@ _cairo_gl_composite_set_source (cairo_gl_composite_t *setup,
                                    width, height);
 }
 
+void
+_cairo_gl_composite_set_source_operand (cairo_gl_composite_t *setup,
+					const cairo_gl_operand_t *source)
+{
+    _cairo_gl_operand_destroy (&setup->src);
+    setup->src = *source;
+}
+
+void
+_cairo_gl_composite_set_solid_source (cairo_gl_composite_t *setup,
+				      const cairo_color_t *color)
+{
+    _cairo_gl_operand_destroy (&setup->src);
+    _cairo_gl_solid_operand_init (&setup->src, color);
+}
+
 cairo_int_status_t
 _cairo_gl_composite_set_mask (cairo_gl_composite_t *setup,
 			      const cairo_pattern_t *pattern,
@@ -403,91 +99,25 @@ _cairo_gl_composite_set_mask (cairo_gl_composite_t *setup,
 }
 
 void
-_cairo_gl_composite_set_mask_spans (cairo_gl_composite_t *setup)
+_cairo_gl_composite_set_mask_operand (cairo_gl_composite_t *setup,
+				      const cairo_gl_operand_t *mask)
 {
     _cairo_gl_operand_destroy (&setup->mask);
-    setup->mask.type = CAIRO_GL_OPERAND_SPANS;
+    if (mask)
+	setup->mask = *mask;
 }
 
 void
-_cairo_gl_composite_set_clip_region (cairo_gl_composite_t *setup,
-                                     cairo_region_t *clip_region)
+_cairo_gl_composite_set_spans (cairo_gl_composite_t *setup)
 {
-    setup->clip_region = clip_region;
+    setup->spans = TRUE;
 }
 
-static void
-_cairo_gl_operand_bind_to_shader (cairo_gl_context_t *ctx,
-                                  cairo_gl_operand_t *operand,
-                                  cairo_gl_tex_t      tex_unit)
+void
+_cairo_gl_composite_set_clip_region (cairo_gl_composite_t *setup,
+                                     cairo_region_t *clip_region)
 {
-    char uniform_name[50];
-    char *custom_part;
-    static const char *names[] = { "source", "mask" };
-
-    strcpy (uniform_name, names[tex_unit]);
-    custom_part = uniform_name + strlen (names[tex_unit]);
-
-    switch (operand->type) {
-    default:
-    case CAIRO_GL_OPERAND_COUNT:
-        ASSERT_NOT_REACHED;
-    case CAIRO_GL_OPERAND_NONE:
-    case CAIRO_GL_OPERAND_SPANS:
-        break;
-    case CAIRO_GL_OPERAND_CONSTANT:
-        strcpy (custom_part, "_constant");
-	_cairo_gl_shader_bind_vec4 (ctx,
-                                    uniform_name,
-                                    operand->constant.color[0],
-                                    operand->constant.color[1],
-                                    operand->constant.color[2],
-                                    operand->constant.color[3]);
-        break;
-    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
-    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
-	strcpy (custom_part, "_a");
-	_cairo_gl_shader_bind_float  (ctx,
-				      uniform_name,
-				      operand->gradient.a);
-	/* fall through */
-    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
-	strcpy (custom_part, "_circle_d");
-	_cairo_gl_shader_bind_vec3   (ctx,
-				      uniform_name,
-				      operand->gradient.circle_d.center.x,
-				      operand->gradient.circle_d.center.y,
-				      operand->gradient.circle_d.radius);
-	strcpy (custom_part, "_radius_0");
-	_cairo_gl_shader_bind_float  (ctx,
-				      uniform_name,
-				      operand->gradient.radius_0);
-        /* fall through */
-    case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
-    case CAIRO_GL_OPERAND_TEXTURE:
-	/*
-	 * For GLES2 we use shaders to implement GL_CLAMP_TO_BORDER (used
-	 * with CAIRO_EXTEND_NONE). When bilinear filtering is enabled,
-	 * these shaders need the texture dimensions for their calculations.
-	 */
-	if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES &&
-	    _cairo_gl_operand_get_extend (operand) == CAIRO_EXTEND_NONE &&
-	    _cairo_gl_operand_get_gl_filter (operand) == GL_LINEAR)
-	{
-	    float width, height;
-	    if (operand->type == CAIRO_GL_OPERAND_TEXTURE) {
-		width = operand->texture.surface->width;
-		height = operand->texture.surface->height;
-	    }
-	    else {
-		width = operand->gradient.gradient->cache_entry.size,
-		height = 1;
-	    }
-	    strcpy (custom_part, "_texdims");
-	    _cairo_gl_shader_bind_vec2 (ctx, uniform_name, width, height);
-	}
-        break;
-    }
+    setup->clip_region = clip_region;
 }
 
 static void
@@ -501,6 +131,29 @@ _cairo_gl_composite_bind_to_shader (cairo_gl_context_t   *ctx,
 }
 
 static void
+_cairo_gl_texture_set_filter (cairo_gl_context_t *ctx,
+                              GLuint              target,
+                              cairo_filter_t      filter)
+{
+    switch (filter) {
+    case CAIRO_FILTER_FAST:
+    case CAIRO_FILTER_NEAREST:
+	glTexParameteri (target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+	glTexParameteri (target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+	break;
+    case CAIRO_FILTER_GOOD:
+    case CAIRO_FILTER_BEST:
+    case CAIRO_FILTER_BILINEAR:
+	glTexParameteri (target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+	glTexParameteri (target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+	break;
+    default:
+    case CAIRO_FILTER_GAUSSIAN:
+	ASSERT_NOT_REACHED;
+    }
+}
+
+static void
 _cairo_gl_texture_set_extend (cairo_gl_context_t *ctx,
                               GLuint              target,
                               cairo_extend_t      extend)
@@ -534,66 +187,6 @@ _cairo_gl_texture_set_extend (cairo_gl_context_t *ctx,
     }
 }
 
-static void
-_cairo_gl_texture_set_filter (cairo_gl_context_t *ctx,
-                              GLuint              target,
-                              cairo_filter_t      filter)
-{
-    switch (filter) {
-    case CAIRO_FILTER_FAST:
-    case CAIRO_FILTER_NEAREST:
-	glTexParameteri (target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
-	glTexParameteri (target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
-	break;
-    case CAIRO_FILTER_GOOD:
-    case CAIRO_FILTER_BEST:
-    case CAIRO_FILTER_BILINEAR:
-	glTexParameteri (target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-	glTexParameteri (target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-	break;
-    default:
-    case CAIRO_FILTER_GAUSSIAN:
-	ASSERT_NOT_REACHED;
-    }
-}
-
-static cairo_bool_t
-_cairo_gl_operand_needs_setup (cairo_gl_operand_t *dest,
-                               cairo_gl_operand_t *source,
-                               unsigned int        vertex_offset)
-{
-    if (dest->type != source->type)
-        return TRUE;
-    if (dest->vertex_offset != vertex_offset)
-        return TRUE;
-
-    switch (source->type) {
-    case CAIRO_GL_OPERAND_NONE:
-    case CAIRO_GL_OPERAND_SPANS:
-        return FALSE;
-    case CAIRO_GL_OPERAND_CONSTANT:
-        return dest->constant.color[0] != source->constant.color[0] ||
-               dest->constant.color[1] != source->constant.color[1] ||
-               dest->constant.color[2] != source->constant.color[2] ||
-               dest->constant.color[3] != source->constant.color[3];
-    case CAIRO_GL_OPERAND_TEXTURE:
-        return dest->texture.surface != source->texture.surface ||
-               dest->texture.attributes.extend != source->texture.attributes.extend ||
-               dest->texture.attributes.filter != source->texture.attributes.filter ||
-               dest->texture.attributes.has_component_alpha != source->texture.attributes.has_component_alpha;
-    case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
-    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
-    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
-    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
-        /* XXX: improve this */
-        return TRUE;
-    default:
-    case CAIRO_GL_OPERAND_COUNT:
-        ASSERT_NOT_REACHED;
-        break;
-    }
-    return TRUE;
-}
 
 static void
 _cairo_gl_context_setup_operand (cairo_gl_context_t *ctx,
@@ -629,11 +222,6 @@ _cairo_gl_context_setup_operand (cairo_gl_context_t *ctx,
         ASSERT_NOT_REACHED;
     case CAIRO_GL_OPERAND_NONE:
         break;
-    case CAIRO_GL_OPERAND_SPANS:
-	dispatch->VertexAttribPointer (CAIRO_GL_COLOR_ATTRIB_INDEX, 4,
-				       GL_UNSIGNED_BYTE, GL_TRUE, vertex_size,
-				       (void *) (uintptr_t) vertex_offset);
-	dispatch->EnableVertexAttribArray (CAIRO_GL_COLOR_ATTRIB_INDEX);
         /* fall through */
     case CAIRO_GL_OPERAND_CONSTANT:
         break;
@@ -668,6 +256,19 @@ _cairo_gl_context_setup_operand (cairo_gl_context_t *ctx,
     }
 }
 
+static void
+_cairo_gl_context_setup_spans (cairo_gl_context_t *ctx,
+			       unsigned int        vertex_size,
+			       unsigned int        vertex_offset)
+{
+    cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
+
+    dispatch->VertexAttribPointer (CAIRO_GL_COLOR_ATTRIB_INDEX, 4,
+				   GL_UNSIGNED_BYTE, GL_TRUE, vertex_size,
+				   (void *) (uintptr_t) vertex_offset);
+    dispatch->EnableVertexAttribArray (CAIRO_GL_COLOR_ATTRIB_INDEX);
+}
+
 void
 _cairo_gl_context_destroy_operand (cairo_gl_context_t *ctx,
                                    cairo_gl_tex_t tex_unit)
@@ -681,8 +282,6 @@ _cairo_gl_context_destroy_operand (cairo_gl_context_t *ctx,
         ASSERT_NOT_REACHED;
     case CAIRO_GL_OPERAND_NONE:
         break;
-    case CAIRO_GL_OPERAND_SPANS:
-        dispatch->DisableVertexAttribArray (CAIRO_GL_COLOR_ATTRIB_INDEX);
         /* fall through */
     case CAIRO_GL_OPERAND_CONSTANT:
         break;
@@ -764,27 +363,6 @@ _cairo_gl_set_operator (cairo_gl_context_t *ctx,
     }
 }
 
-static unsigned int
-_cairo_gl_operand_get_vertex_size (cairo_gl_operand_type_t type)
-{
-    switch (type) {
-    default:
-    case CAIRO_GL_OPERAND_COUNT:
-        ASSERT_NOT_REACHED;
-    case CAIRO_GL_OPERAND_NONE:
-    case CAIRO_GL_OPERAND_CONSTANT:
-        return 0;
-    case CAIRO_GL_OPERAND_SPANS:
-        return 4 * sizeof (GLbyte);
-    case CAIRO_GL_OPERAND_TEXTURE:
-    case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
-    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
-    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
-    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
-        return 2 * sizeof (GLfloat);
-    }
-}
-
 static cairo_status_t
 _cairo_gl_composite_begin_component_alpha  (cairo_gl_context_t *ctx,
                                             cairo_gl_composite_t *setup)
@@ -872,6 +450,7 @@ _cairo_gl_composite_begin_component_alpha  (cairo_gl_context_t *ctx,
 	status = _cairo_gl_get_shader_by_type (ctx,
                                                &setup->src,
                                                &setup->mask,
+					       setup->spans,
                                                CAIRO_GL_SHADER_IN_CA_SOURCE_ALPHA,
                                                &pre_shader);
         if (unlikely (status))
@@ -919,10 +498,12 @@ _cairo_gl_composite_begin (cairo_gl_composite_t *setup,
     }
 
     status = _cairo_gl_get_shader_by_type (ctx,
-                                           &setup->src,
-                                           &setup->mask,
-                                           component_alpha ? CAIRO_GL_SHADER_IN_CA_SOURCE
-                                                           : CAIRO_GL_SHADER_IN_NORMAL,
+					   &setup->src,
+					   &setup->mask,
+					   setup->spans,
+                                           component_alpha ?
+					   CAIRO_GL_SHADER_IN_CA_SOURCE :
+					   CAIRO_GL_SHADER_IN_NORMAL,
                                            &shader);
     if (unlikely (status)) {
         ctx->pre_shader = NULL;
@@ -954,10 +535,12 @@ _cairo_gl_composite_begin (cairo_gl_composite_t *setup,
 
     _cairo_gl_context_setup_operand (ctx, CAIRO_GL_TEX_SOURCE, &setup->src, vertex_size, dst_size);
     _cairo_gl_context_setup_operand (ctx, CAIRO_GL_TEX_MASK, &setup->mask, vertex_size, dst_size + src_size);
+    if (setup->spans)
+	_cairo_gl_context_setup_spans (ctx, vertex_size, dst_size + src_size);
+    else
+	ctx->dispatch.DisableVertexAttribArray (CAIRO_GL_COLOR_ATTRIB_INDEX);
 
-    _cairo_gl_set_operator (ctx,
-                            setup->op,
-                            component_alpha);
+    _cairo_gl_set_operator (ctx, setup->op, component_alpha);
 
     ctx->vertex_size = vertex_size;
 
@@ -1065,62 +648,6 @@ _cairo_gl_composite_prepare_buffer (cairo_gl_context_t *ctx,
 }
 
 static inline void
-_cairo_gl_operand_emit (cairo_gl_operand_t *operand,
-                        GLfloat ** vb,
-                        GLfloat x,
-                        GLfloat y,
-                        uint8_t alpha)
-{
-    switch (operand->type) {
-    default:
-    case CAIRO_GL_OPERAND_COUNT:
-        ASSERT_NOT_REACHED;
-    case CAIRO_GL_OPERAND_NONE:
-    case CAIRO_GL_OPERAND_CONSTANT:
-        break;
-    case CAIRO_GL_OPERAND_SPANS:
-        {
-            union fi {
-                float f;
-                GLbyte bytes[4];
-            } fi;
-
-            fi.bytes[0] = 0;
-            fi.bytes[1] = 0;
-            fi.bytes[2] = 0;
-            fi.bytes[3] = alpha;
-            *(*vb)++ = fi.f;
-        }
-        break;
-    case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
-    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
-    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
-    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
-        {
-	    double s = x;
-	    double t = y;
-
-	    cairo_matrix_transform_point (&operand->gradient.m, &s, &t);
-
-	    *(*vb)++ = s;
-	    *(*vb)++ = t;
-        }
-	break;
-    case CAIRO_GL_OPERAND_TEXTURE:
-        {
-            cairo_surface_attributes_t *src_attributes = &operand->texture.attributes;
-            double s = x;
-            double t = y;
-
-            cairo_matrix_transform_point (&src_attributes->matrix, &s, &t);
-            *(*vb)++ = s;
-            *(*vb)++ = t;
-        }
-        break;
-    }
-}
-
-static inline void
 _cairo_gl_composite_emit_vertex (cairo_gl_context_t *ctx,
                                  GLfloat x,
                                  GLfloat y,
@@ -1134,6 +661,19 @@ _cairo_gl_composite_emit_vertex (cairo_gl_context_t *ctx,
     _cairo_gl_operand_emit (&ctx->operands[CAIRO_GL_TEX_SOURCE], &vb, x, y, alpha);
     _cairo_gl_operand_emit (&ctx->operands[CAIRO_GL_TEX_MASK  ], &vb, x, y, alpha);
 
+    if (ctx->spans) {
+	union fi {
+	    float f;
+	    GLbyte bytes[4];
+	} fi;
+
+	fi.bytes[0] = 0;
+	fi.bytes[1] = 0;
+	fi.bytes[2] = 0;
+	fi.bytes[3] = alpha;
+	*vb++ = fi.f;
+    }
+
     ctx->vb_offset += ctx->vertex_size;
 }
 
@@ -1229,517 +769,3 @@ _cairo_gl_composite_init (cairo_gl_composite_t *setup,
 
     return CAIRO_STATUS_SUCCESS;
 }
-
-static cairo_bool_t
-cairo_boxes_for_each_box (cairo_boxes_t *boxes,
-			  cairo_bool_t (*func) (cairo_box_t *box,
-						void *data),
-			  void *data)
-{
-    struct _cairo_boxes_chunk *chunk;
-    int i;
-
-    for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
-	for (i = 0; i < chunk->count; i++)
-	    if (! func (&chunk->base[i], data))
-		return FALSE;
-    }
-
-    return TRUE;
-}
-
-struct image_contains_box {
-    int width, height;
-    int tx, ty;
-};
-
-static cairo_bool_t image_contains_box (cairo_box_t *box, void *closure)
-{
-    struct image_contains_box *data = closure;
-
-    return
-	_cairo_fixed_integer_part (box->p1.x) + data->tx >= 0 &&
-	_cairo_fixed_integer_part (box->p1.y) + data->ty >= 0 &&
-	_cairo_fixed_integer_part (box->p2.x) + data->tx <= data->width &&
-	_cairo_fixed_integer_part (box->p2.y) + data->ty <= data->height;
-}
-
-struct image_upload_box {
-    cairo_gl_surface_t *surface;
-    cairo_image_surface_t *image;
-    int tx, ty;
-};
-
-static cairo_bool_t image_upload_box (cairo_box_t *box, void *closure)
-{
-    const struct image_upload_box *iub = closure;
-    int x = _cairo_fixed_integer_part (box->p1.x);
-    int y = _cairo_fixed_integer_part (box->p1.y);
-    int w = _cairo_fixed_integer_part (box->p2.x - box->p1.x);
-    int h = _cairo_fixed_integer_part (box->p2.y - box->p1.y);
-
-    return _cairo_gl_surface_draw_image (iub->surface,
-				  iub->image,
-				  x + iub->tx, y + iub->ty,
-				  w, h,
-				  x, y) == CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_upload_image_inplace (cairo_gl_surface_t *surface,
-		       const cairo_pattern_t *source,
-		       cairo_boxes_t *boxes)
-{
-    const cairo_surface_pattern_t *pattern;
-    struct image_contains_box icb;
-    struct image_upload_box iub;
-    cairo_image_surface_t *image;
-    int tx, ty;
-
-    if (! boxes->is_pixel_aligned)
-	return CAIRO_INT_STATUS_UNSUPPORTED;
-
-    if (source->type != CAIRO_PATTERN_TYPE_SURFACE)
-	return CAIRO_INT_STATUS_UNSUPPORTED;
-
-    pattern = (const cairo_surface_pattern_t *) source;
-    if (pattern->surface->type != CAIRO_SURFACE_TYPE_IMAGE)
-	return CAIRO_INT_STATUS_UNSUPPORTED;
-
-    image = (cairo_image_surface_t *) pattern->surface;
-    if (image->format == CAIRO_FORMAT_INVALID)
-	return CAIRO_INT_STATUS_UNSUPPORTED;
-
-    if (! _cairo_matrix_is_integer_translation (&source->matrix, &tx, &ty))
-	return CAIRO_INT_STATUS_UNSUPPORTED;
-
-    /* Check that the data is entirely within the image */
-    icb.width  = image->width;
-    icb.height = image->height;
-    icb.tx = tx;
-    icb.ty = ty;
-    if (! cairo_boxes_for_each_box (boxes, image_contains_box, &icb))
-	return CAIRO_INT_STATUS_UNSUPPORTED;
-
-    iub.surface = surface;
-    iub.image = image;
-    iub.tx = tx;
-    iub.ty = ty;
-    cairo_boxes_for_each_box (boxes, image_upload_box, &iub);
-
-    return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_bool_t composite_box (cairo_box_t *box, void *closure)
-{
-    _cairo_gl_composite_emit_rect (closure,
-				   _cairo_fixed_integer_part (box->p1.x),
-				   _cairo_fixed_integer_part (box->p1.y),
-				   _cairo_fixed_integer_part (box->p2.x),
-				   _cairo_fixed_integer_part (box->p2.y),
-				   0);
-    return TRUE;
-}
-
-static cairo_status_t
-_composite_boxes (cairo_gl_surface_t *dst,
-		  cairo_operator_t op,
-		  const cairo_pattern_t *src,
-		  cairo_boxes_t *boxes,
-		  const cairo_composite_rectangles_t *extents)
-{
-    cairo_bool_t need_clip_mask = FALSE;
-    cairo_gl_composite_t setup;
-    cairo_gl_context_t *ctx;
-    cairo_surface_pattern_t mask;
-    cairo_status_t status;
-
-    /* If the boxes are not pixel-aligned, we will need to compute a real mask */
-    if (! boxes->is_pixel_aligned)
-	return CAIRO_INT_STATUS_UNSUPPORTED;
-
-    if (extents->clip->path &&
-	(! extents->is_bounded || op == CAIRO_OPERATOR_SOURCE))
-    {
-	return CAIRO_INT_STATUS_UNSUPPORTED;
-    }
-
-    if (! extents->is_bounded)
-	return CAIRO_INT_STATUS_UNSUPPORTED;
-
-    status = _cairo_gl_composite_init (&setup, op, dst, FALSE,
-				       &extents->bounded);
-    if (unlikely (status))
-        goto CLEANUP;
-
-    status = _cairo_gl_composite_set_source (&setup, src,
-					     extents->bounded.x,
-					     extents->bounded.y,
-					     extents->bounded.x,
-					     extents->bounded.y,
-					     extents->bounded.width,
-					     extents->bounded.height);
-    if (unlikely (status))
-        goto CLEANUP;
-
-    need_clip_mask = extents->clip->path != NULL;
-    if (need_clip_mask) {
-	cairo_surface_t *clip_surface;
-	int clip_x, clip_y;
-
-	clip_surface = _cairo_clip_get_surface (extents->clip,
-						&dst->base,
-						&clip_x, &clip_y);
-	if (unlikely (clip_surface->status)) {
-	    status = clip_surface->status;
-	    need_clip_mask = FALSE;
-	    goto CLEANUP;
-	}
-
-	_cairo_pattern_init_for_surface (&mask, clip_surface);
-	mask.base.filter = CAIRO_FILTER_NEAREST;
-	cairo_matrix_init_translate (&mask.base.matrix,
-				     -clip_x,
-				     -clip_y);
-	cairo_surface_destroy (clip_surface);
-
-	if (op == CAIRO_OPERATOR_CLEAR) {
-	    src = NULL;
-	    op = CAIRO_OPERATOR_DEST_OUT;
-	}
-
-	status = _cairo_gl_composite_set_mask (&setup, &mask.base,
-					       extents->bounded.x,
-					       extents->bounded.y,
-					       extents->bounded.x,
-					       extents->bounded.y,
-					       extents->bounded.width,
-					       extents->bounded.height);
-	if (unlikely (status))
-	    goto CLEANUP;
-    }
-
-    status = _cairo_gl_composite_begin (&setup, &ctx);
-    if (unlikely (status))
-	goto CLEANUP;
-
-    cairo_boxes_for_each_box (boxes, composite_box, ctx);
-
-    status = _cairo_gl_context_release (ctx, status);
-
-  CLEANUP:
-    if (need_clip_mask)
-	_cairo_pattern_fini (&mask.base);
-
-    _cairo_gl_composite_fini (&setup);
-    return status;
-}
-
-static cairo_bool_t converter_add_box (cairo_box_t *box, void *closure)
-{
-    return _cairo_rectangular_scan_converter_add_box (closure, box, 1) == CAIRO_STATUS_SUCCESS;
-}
-
-typedef struct _cairo_gl_surface_span_renderer {
-    cairo_span_renderer_t base;
-
-    cairo_gl_composite_t setup;
-
-    int xmin, xmax;
-    int ymin, ymax;
-
-    cairo_gl_context_t *ctx;
-} cairo_gl_surface_span_renderer_t;
-
-static cairo_status_t
-_cairo_gl_render_bounded_spans (void *abstract_renderer,
-				int y, int height,
-				const cairo_half_open_span_t *spans,
-				unsigned num_spans)
-{
-    cairo_gl_surface_span_renderer_t *renderer = abstract_renderer;
-
-    if (num_spans == 0)
-	return CAIRO_STATUS_SUCCESS;
-
-    do {
-	if (spans[0].coverage) {
-            _cairo_gl_composite_emit_rect (renderer->ctx,
-                                           spans[0].x, y,
-                                           spans[1].x, y + height,
-                                           spans[0].coverage);
-	}
-
-	spans++;
-    } while (--num_spans > 1);
-
-    return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_gl_render_unbounded_spans (void *abstract_renderer,
-				  int y, int height,
-				  const cairo_half_open_span_t *spans,
-				  unsigned num_spans)
-{
-    cairo_gl_surface_span_renderer_t *renderer = abstract_renderer;
-
-    if (y > renderer->ymin) {
-        _cairo_gl_composite_emit_rect (renderer->ctx,
-                                       renderer->xmin, renderer->ymin,
-                                       renderer->xmax, y,
-                                       0);
-    }
-
-    if (num_spans == 0) {
-        _cairo_gl_composite_emit_rect (renderer->ctx,
-                                       renderer->xmin, y,
-                                       renderer->xmax, y + height,
-                                       0);
-    } else {
-        if (spans[0].x != renderer->xmin) {
-            _cairo_gl_composite_emit_rect (renderer->ctx,
-                                           renderer->xmin, y,
-                                           spans[0].x,     y + height,
-                                           0);
-        }
-
-        do {
-            _cairo_gl_composite_emit_rect (renderer->ctx,
-                                           spans[0].x, y,
-                                           spans[1].x, y + height,
-                                           spans[0].coverage);
-            spans++;
-        } while (--num_spans > 1);
-
-        if (spans[0].x != renderer->xmax) {
-            _cairo_gl_composite_emit_rect (renderer->ctx,
-                                           spans[0].x,     y,
-                                           renderer->xmax, y + height,
-                                           0);
-        }
-    }
-
-    renderer->ymin = y + height;
-    return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_gl_finish_unbounded_spans (void *abstract_renderer)
-{
-    cairo_gl_surface_span_renderer_t *renderer = abstract_renderer;
-
-    if (renderer->ymax > renderer->ymin) {
-        _cairo_gl_composite_emit_rect (renderer->ctx,
-                                       renderer->xmin, renderer->ymin,
-                                       renderer->xmax, renderer->ymax,
-                                       0);
-    }
-
-    return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_gl_finish_bounded_spans (void *abstract_renderer)
-{
-    return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_int_status_t
-_composite_unaligned_boxes (cairo_gl_surface_t *dst,
-			    cairo_operator_t op,
-			    const cairo_pattern_t *pattern,
-			    cairo_boxes_t *boxes,
-			    const cairo_composite_rectangles_t *composite)
-{
-    cairo_rectangular_scan_converter_t converter;
-    cairo_gl_surface_span_renderer_t renderer;
-    const cairo_rectangle_int_t *extents;
-    cairo_status_t status;
-
-    if (composite->clip->path)
-	return CAIRO_INT_STATUS_UNSUPPORTED;
-
-    /* XXX for ADD or if we know the boxes are disjoint we can do a simpler
-     * pass, but for now... */
-
-    _cairo_rectangular_scan_converter_init (&converter, &composite->bounded);
-    cairo_boxes_for_each_box (boxes, converter_add_box, &converter);
-
-    if (composite->is_bounded) {
-	renderer.base.render_rows = _cairo_gl_render_bounded_spans;
-        renderer.base.finish =      _cairo_gl_finish_bounded_spans;
-	extents = &composite->bounded;
-    } else {
-	renderer.base.render_rows = _cairo_gl_render_unbounded_spans;
-        renderer.base.finish =      _cairo_gl_finish_unbounded_spans;
-	extents = &composite->unbounded;
-    }
-    renderer.xmin = extents->x;
-    renderer.xmax = extents->x + extents->width;
-    renderer.ymin = extents->y;
-    renderer.ymax = extents->y + extents->height;
-
-    status = _cairo_gl_composite_init (&renderer.setup,
-                                       op, dst,
-                                       FALSE, extents);
-    if (unlikely (status))
-        goto FAIL;
-
-    status = _cairo_gl_composite_set_source (&renderer.setup, pattern,
-                                             extents->x, extents->y,
-                                             extents->x, extents->y,
-                                             extents->width, extents->height);
-    if (unlikely (status))
-        goto FAIL;
-
-    _cairo_gl_composite_set_mask_spans (&renderer.setup);
-    if (! composite->is_bounded)
-	_cairo_gl_composite_set_clip_region (&renderer.setup,
-					     _cairo_clip_get_region (composite->clip));
-
-    status = _cairo_gl_composite_begin (&renderer.setup, &renderer.ctx);
-    if (unlikely (status))
-        goto FAIL;
-
-    status = converter.base.generate (&converter.base, &renderer.base);
-
-    converter.base.destroy (&converter.base);
-    renderer.base.finish (&renderer.base);
-
-    status = _cairo_gl_context_release (renderer.ctx, status);
-FAIL:
-    _cairo_gl_composite_fini (&renderer.setup);
-    return status;
-}
-
-/* XXX _cairo_gl_clip_and_composite_polygon() */
-cairo_int_status_t
-_cairo_gl_surface_polygon (cairo_gl_surface_t *dst,
-                           cairo_operator_t op,
-                           const cairo_pattern_t *src,
-                           cairo_polygon_t *polygon,
-                           cairo_fill_rule_t fill_rule,
-                           cairo_antialias_t antialias,
-                           const cairo_composite_rectangles_t *extents)
-{
-    cairo_region_t *clip_region = _cairo_clip_get_region (extents->clip);
-
-    if (! _cairo_clip_is_region (extents->clip))
-	return UNSUPPORTED ("a clip surface would be required");
-
-    if (! _cairo_surface_check_span_renderer (op, src, &dst->base, antialias))
-        return UNSUPPORTED ("no span renderer");
-
-    if (op == CAIRO_OPERATOR_SOURCE)
-        return UNSUPPORTED ("SOURCE compositing doesn't work in GL");
-    if (op == CAIRO_OPERATOR_CLEAR) {
-        op = CAIRO_OPERATOR_DEST_OUT;
-        src = &_cairo_pattern_white.base;
-    }
-
-    return _cairo_surface_composite_polygon (&dst->base,
-					     op,
-					     src,
-					     fill_rule,
-					     antialias,
-					     extents,
-					     polygon,
-					     clip_region);
-}
-
-cairo_int_status_t
-_cairo_gl_clip_and_composite_boxes (cairo_gl_surface_t *dst,
-				    cairo_operator_t op,
-				    const cairo_pattern_t *src,
-				    cairo_boxes_t *boxes,
-				    cairo_composite_rectangles_t *extents)
-{
-    cairo_int_status_t status;
-
-    if (boxes->num_boxes == 0 && extents->is_bounded)
-	return CAIRO_STATUS_SUCCESS;
-
-    if (! _cairo_gl_operator_is_supported (op))
-	return CAIRO_INT_STATUS_UNSUPPORTED;
-
-    if (boxes->is_pixel_aligned && _cairo_clip_is_region (extents->clip) &&
-	(op == CAIRO_OPERATOR_SOURCE ||
-	 (dst->base.is_clear && (op == CAIRO_OPERATOR_OVER || op == CAIRO_OPERATOR_ADD))))
-    {
-	if (boxes->num_boxes == 1 &&
-	    extents->bounded.width  == dst->width &&
-	    extents->bounded.height == dst->height)
-	{
-	    op = CAIRO_OPERATOR_SOURCE;
-#if 0
-	    dst->deferred_clear = FALSE;
-#endif
-	}
-
-	status = _upload_image_inplace (dst, src, boxes);
-	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
-	    return status;
-    }
-
-    /* Can we reduce drawing through a clip-mask to simply drawing the clip? */
-    if (extents->clip->path != NULL && extents->is_bounded) {
-	cairo_polygon_t polygon;
-	cairo_fill_rule_t fill_rule;
-	cairo_antialias_t antialias;
-	cairo_clip_t *clip;
-
-	clip = _cairo_clip_copy (extents->clip);
-	clip = _cairo_clip_intersect_boxes (clip, boxes);
-	status = _cairo_clip_get_polygon (clip, &polygon,
-					  &fill_rule, &antialias);
-	_cairo_clip_path_destroy (clip->path);
-	clip->path = NULL;
-	if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
-	    cairo_clip_t *saved_clip = extents->clip;
-	    extents->clip = clip;
-	    status = _cairo_gl_surface_polygon (dst, op, src,
-						&polygon,
-						fill_rule,
-						antialias,
-						extents);
-	    if (extents->clip != clip)
-		clip = NULL;
-	    extents->clip = saved_clip;
-	    _cairo_polygon_fini (&polygon);
-	}
-	if (clip)
-	    _cairo_clip_destroy (clip);
-
-	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
-	    return status;
-    }
-
-#if 0
-    if (dst->deferred_clear) {
-	status = _cairo_gl_surface_clear (dst);
-	if (unlikely (status))
-	    return status;
-    }
-#endif
-
-    if (boxes->is_pixel_aligned &&
-	_cairo_clip_is_region (extents->clip) &&
-	op == CAIRO_OPERATOR_SOURCE) {
-	status = _upload_image_inplace (dst, src, boxes);
-	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
-	    return status;
-    }
-
-    /* Use a fast path if the boxes are pixel aligned */
-    status = _composite_boxes (dst, op, src, boxes, extents);
-    if (status != CAIRO_INT_STATUS_UNSUPPORTED)
-	return status;
-
-    status = _composite_unaligned_boxes (dst, op, src, boxes, extents);
-    if (status != CAIRO_INT_STATUS_UNSUPPORTED)
-	return status;
-
-    /* Otherwise XXX */
-    return CAIRO_INT_STATUS_UNSUPPORTED;
-}
diff --git a/src/cairo-gl-device.c b/src/cairo-gl-device.c
index 170cf96..f20850e 100644
--- a/src/cairo-gl-device.c
+++ b/src/cairo-gl-device.c
@@ -113,18 +113,20 @@ static void
 _gl_destroy (void *device)
 {
     cairo_gl_context_t *ctx = device;
-    cairo_scaled_font_t *scaled_font, *next_scaled_font;
     int n;
 
     ctx->acquire (ctx);
 
-    cairo_list_foreach_entry_safe (scaled_font,
-				   next_scaled_font,
-				   cairo_scaled_font_t,
-				   &ctx->fonts,
-				   link)
-    {
-	_cairo_scaled_font_revoke_ownership (scaled_font);
+    while (! cairo_list_is_empty (&ctx->fonts)) {
+	cairo_gl_font_t *font;
+
+	font = cairo_list_first_entry (&ctx->fonts,
+				       cairo_gl_font_t,
+				       link);
+
+	cairo_list_del (&font->base.link);
+	cairo_list_del (&font->link);
+	free (font);
     }
 
     for (n = 0; n < ARRAY_LENGTH (ctx->glyph_cache); n++)
@@ -161,6 +163,8 @@ _cairo_gl_context_init (cairo_gl_context_t *ctx)
 
     _cairo_device_init (&ctx->base, &_cairo_gl_device_backend);
 
+    ctx->compositor = _cairo_gl_span_compositor_get ();
+
     memset (ctx->glyph_cache, 0, sizeof (ctx->glyph_cache));
     cairo_list_init (&ctx->fonts);
 
diff --git a/src/cairo-gl-glyphs.c b/src/cairo-gl-glyphs.c
index 0772d2a..ee5c543 100644
--- a/src/cairo-gl-glyphs.c
+++ b/src/cairo-gl-glyphs.c
@@ -40,6 +40,7 @@
 
 #include "cairo-gl-private.h"
 
+#include "cairo-compositor-private.h"
 #include "cairo-composite-rectangles-private.h"
 #include "cairo-error-private.h"
 #include "cairo-image-surface-private.h"
@@ -50,11 +51,26 @@
 #define GLYPH_CACHE_MIN_SIZE 4
 #define GLYPH_CACHE_MAX_SIZE 128
 
-typedef struct _cairo_gl_glyph_private {
+typedef struct _cairo_gl_glyph {
     cairo_rtree_node_t node;
+    cairo_scaled_glyph_private_t base;
     cairo_gl_glyph_cache_t *cache;
     struct { float x, y; } p1, p2;
-} cairo_gl_glyph_private_t;
+} cairo_gl_glyph_t;
+
+static void
+_cairo_gl_glyph_fini (cairo_scaled_glyph_private_t *_priv,
+		      cairo_scaled_glyph_t *scaled_glyph,
+		      cairo_scaled_font_t  *scaled_font)
+{
+    cairo_gl_glyph_t *priv = cairo_container_of (_priv, cairo_gl_glyph_t, base);
+
+    priv->node.owner = NULL;
+    if (! priv->node.pinned) {
+	/* XXX thread-safety? Probably ok due to the frozen scaled-font. */
+	_cairo_rtree_node_remove (&priv->cache->rtree, &priv->node);
+    }
+}
 
 static cairo_int_status_t
 _cairo_gl_glyph_cache_add_glyph (cairo_gl_context_t *ctx,
@@ -63,7 +79,7 @@ _cairo_gl_glyph_cache_add_glyph (cairo_gl_context_t *ctx,
 {
     cairo_image_surface_t *glyph_surface = scaled_glyph->surface;
     cairo_gl_surface_t *cache_surface;
-    cairo_gl_glyph_private_t *glyph_private;
+    cairo_gl_glyph_t *glyph_private;
     cairo_rtree_node_t *node = NULL;
     cairo_int_status_t status;
     int width, height;
@@ -101,11 +117,15 @@ _cairo_gl_glyph_cache_add_glyph (cairo_gl_context_t *ctx,
     if (unlikely (status))
 	return status;
 
-    scaled_glyph->surface_private = node;
-    node->owner = &scaled_glyph->surface_private;
-
-    glyph_private = (cairo_gl_glyph_private_t *) node;
+    glyph_private = (cairo_gl_glyph_t *) node;
     glyph_private->cache = cache;
+    _cairo_scaled_glyph_attach_private (scaled_glyph,
+					&glyph_private->base,
+					cache,
+					_cairo_gl_glyph_fini);
+
+    scaled_glyph->dev_private = glyph_private;
+    scaled_glyph->dev_private_key = cache;
 
     /* compute tex coords */
     glyph_private->p1.x = node->x;
@@ -122,11 +142,11 @@ _cairo_gl_glyph_cache_add_glyph (cairo_gl_context_t *ctx,
     return CAIRO_STATUS_SUCCESS;
 }
 
-static cairo_gl_glyph_private_t *
+static cairo_gl_glyph_t *
 _cairo_gl_glyph_cache_lock (cairo_gl_glyph_cache_t *cache,
 			    cairo_scaled_glyph_t *scaled_glyph)
 {
-    return _cairo_rtree_pin (&cache->rtree, scaled_glyph->surface_private);
+    return _cairo_rtree_pin (&cache->rtree, scaled_glyph->dev_private);
 }
 
 static cairo_status_t
@@ -183,63 +203,29 @@ _cairo_gl_glyph_cache_unlock (cairo_gl_glyph_cache_t *cache)
     _cairo_rtree_unpin (&cache->rtree);
 }
 
-static cairo_bool_t
-_cairo_gl_surface_owns_font (cairo_gl_surface_t *surface,
-			     cairo_scaled_font_t *scaled_font)
-{
-    cairo_device_t *font_private;
-
-    font_private = scaled_font->surface_private;
-    if ((scaled_font->surface_backend != NULL &&
-	 scaled_font->surface_backend != &_cairo_gl_surface_backend) ||
-	(font_private != NULL && font_private != surface->base.device))
-    {
-	return FALSE;
-    }
-
-    return TRUE;
-}
-
-void
-_cairo_gl_surface_scaled_font_fini (cairo_scaled_font_t  *scaled_font)
+static void
+_cairo_gl_font_fini (cairo_scaled_font_private_t *_priv,
+		     cairo_scaled_font_t  *scaled_font)
 {
-    cairo_list_del (&scaled_font->link);
-}
+    cairo_gl_font_t *priv = (cairo_gl_font_t *)_priv;
 
-void
-_cairo_gl_surface_scaled_glyph_fini (cairo_scaled_glyph_t *scaled_glyph,
-				     cairo_scaled_font_t  *scaled_font)
-{
-    cairo_gl_glyph_private_t *glyph_private;
-
-    glyph_private = scaled_glyph->surface_private;
-    if (glyph_private != NULL) {
-	glyph_private->node.owner = NULL;
-	if (! glyph_private->node.pinned) {
-	    /* XXX thread-safety? Probably ok due to the frozen scaled-font. */
-	    _cairo_rtree_node_remove (&glyph_private->cache->rtree,
-		                      &glyph_private->node);
-	}
-    }
+    cairo_list_del (&priv->link);
+    free (priv);
 }
 
 static cairo_status_t
-_render_glyphs (cairo_gl_surface_t	*dst,
-	        int dst_x, int dst_y,
-	        cairo_operator_t	 op,
-		const cairo_pattern_t	*source,
-		cairo_glyph_t		*glyphs,
-		int			 num_glyphs,
-		cairo_scaled_font_t	*scaled_font,
-		const cairo_composite_rectangles_t *extents,
-		cairo_bool_t		*has_component_alpha,
-		int			*remaining_glyphs)
+render_glyphs (cairo_gl_surface_t	*dst,
+	       int dst_x, int dst_y,
+	       cairo_operator_t	 op,
+	       const cairo_pattern_t	*source,
+	       cairo_composite_glyphs_info_t *info,
+	       cairo_bool_t		*has_component_alpha)
 {
     cairo_format_t last_format = CAIRO_FORMAT_INVALID;
     cairo_gl_glyph_cache_t *cache = NULL;
     cairo_gl_context_t *ctx;
     cairo_gl_composite_t setup;
-    cairo_status_t status;
+    cairo_int_status_t status;
     int i = 0;
 
     *has_component_alpha = FALSE;
@@ -248,45 +234,30 @@ _render_glyphs (cairo_gl_surface_t	*dst,
     if (unlikely (status))
 	return status;
 
-    _cairo_scaled_font_freeze_cache (scaled_font);
-
-    status = _cairo_gl_composite_init (&setup, op, dst,
-                                       TRUE, &extents->bounded);
-
+    status = _cairo_gl_composite_init (&setup, op, dst, TRUE, &info->extents);
     if (unlikely (status))
 	goto FINISH;
 
-    if (! _cairo_gl_surface_owns_font (dst, scaled_font)) {
-	status = CAIRO_INT_STATUS_UNSUPPORTED;
-	goto FINISH;
-    }
-
     status = _cairo_gl_composite_set_source (&setup, source,
-                                             extents->bounded.x,
-					     extents->bounded.y,
+                                             info->extents.x,
+					     info->extents.y,
                                              dst_x, dst_y,
-                                             extents->bounded.width,
-                                             extents->bounded.height);
+                                             info->extents.width,
+                                             info->extents.height);
     if (unlikely (status))
 	goto FINISH;
 
-    if (scaled_font->surface_private == NULL) {
-	scaled_font->surface_private = ctx;
-	scaled_font->surface_backend = &_cairo_gl_surface_backend;
-	cairo_list_add (&scaled_font->link, &ctx->fonts);
-    }
 
-    _cairo_gl_composite_set_clip_region (&setup,
-					 _cairo_clip_get_region (extents->clip));
+    //_cairo_gl_composite_set_clip_region (&setup, _cairo_clip_get_region (extents->clip));
 
-    for (i = 0; i < num_glyphs; i++) {
+    for (i = 0; i < info->num_glyphs; i++) {
 	cairo_scaled_glyph_t *scaled_glyph;
-	cairo_gl_glyph_private_t *glyph;
+	cairo_gl_glyph_t *glyph;
 	double x_offset, y_offset;
 	double x1, x2, y1, y2;
 
-	status = _cairo_scaled_glyph_lookup (scaled_font,
-					     glyphs[i].index,
+	status = _cairo_scaled_glyph_lookup (info->font,
+					     info->glyphs[i].index,
 					     CAIRO_SCALED_GLYPH_INFO_SURFACE,
 					     &scaled_glyph);
 	if (unlikely (status))
@@ -297,13 +268,6 @@ _render_glyphs (cairo_gl_surface_t	*dst,
 	{
 	    continue;
 	}
-	if (scaled_glyph->surface->width  > GLYPH_CACHE_MAX_SIZE ||
-	    scaled_glyph->surface->height > GLYPH_CACHE_MAX_SIZE)
-	{
-	    status = CAIRO_INT_STATUS_UNSUPPORTED;
-	    goto FINISH;
-	}
-
 	if (scaled_glyph->surface->format != last_format) {
 	    status = cairo_gl_context_get_glyph_cache (ctx,
 						       scaled_glyph->surface->format,
@@ -331,25 +295,35 @@ _render_glyphs (cairo_gl_surface_t	*dst,
 		goto FINISH;
 	}
 
-	if (scaled_glyph->surface_private == NULL) {
-	    status = _cairo_gl_glyph_cache_add_glyph (ctx, cache, scaled_glyph);
+	if (scaled_glyph->dev_private_key != cache) {
+	    cairo_scaled_glyph_private_t *priv;
 
-	    if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
-		/* Cache is full, so flush existing prims and try again. */
-                _cairo_gl_composite_flush (ctx);
-		_cairo_gl_glyph_cache_unlock (cache);
+	    priv = _cairo_scaled_glyph_find_private (scaled_glyph, cache);
+	    if (priv) {
+		scaled_glyph->dev_private_key = cache;
+		scaled_glyph->dev_private = cairo_container_of (priv,
+								cairo_gl_glyph_t,
+								base);;
+	    } else {
 		status = _cairo_gl_glyph_cache_add_glyph (ctx, cache, scaled_glyph);
-	    }
 
-	    if (unlikely (_cairo_status_is_error (status)))
-		goto FINISH;
+		if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
+		    /* Cache is full, so flush existing prims and try again. */
+		    _cairo_gl_composite_flush (ctx);
+		    _cairo_gl_glyph_cache_unlock (cache);
+		    status = _cairo_gl_glyph_cache_add_glyph (ctx, cache, scaled_glyph);
+		}
+
+		if (unlikely (_cairo_int_status_is_error (status)))
+		    goto FINISH;
+	    }
 	}
 
 	x_offset = scaled_glyph->surface->base.device_transform.x0;
 	y_offset = scaled_glyph->surface->base.device_transform.y0;
 
-	x1 = _cairo_lround (glyphs[i].x - x_offset);
-	y1 = _cairo_lround (glyphs[i].y - y_offset);
+	x1 = _cairo_lround (info->glyphs[i].x - x_offset);
+	y1 = _cairo_lround (info->glyphs[i].y - y_offset);
 	x2 = x1 + scaled_glyph->surface->width;
 	y2 = y1 + scaled_glyph->surface->height;
 
@@ -362,75 +336,59 @@ _render_glyphs (cairo_gl_surface_t	*dst,
 
     status = CAIRO_STATUS_SUCCESS;
   FINISH:
-    _cairo_scaled_font_thaw_cache (scaled_font);
-
     status = _cairo_gl_context_release (ctx, status);
 
     _cairo_gl_composite_fini (&setup);
-
-    *remaining_glyphs = num_glyphs - i;
     return status;
 }
 
 static cairo_int_status_t
-_cairo_gl_surface_show_glyphs_via_mask (cairo_gl_surface_t	*dst,
-			                cairo_operator_t	 op,
-					const cairo_pattern_t	*source,
-					cairo_glyph_t		*glyphs,
-					int			 num_glyphs,
-					cairo_scaled_font_t	*scaled_font,
-					cairo_composite_rectangles_t *extents,
-					int			*remaining_glyphs)
+render_glyphs_via_mask (cairo_gl_surface_t	*dst,
+			   cairo_operator_t	 op,
+			   const cairo_surface_t	*source,
+			   cairo_composite_glyphs_info_t *info)
 {
     cairo_surface_t *mask;
     cairo_status_t status;
     cairo_bool_t has_component_alpha;
-    cairo_clip_t *saved_clip;
     int i;
 
     /* XXX: For non-CA, this should be CAIRO_CONTENT_ALPHA to save memory */
     mask = cairo_gl_surface_create (dst->base.device,
                                     CAIRO_CONTENT_COLOR_ALPHA,
-                                    extents->bounded.width,
-                                    extents->bounded.height);
+                                    info->extents.width,
+                                    info->extents.height);
     if (unlikely (mask->status))
         return mask->status;
 
-    for (i = 0; i < num_glyphs; i++) {
-	glyphs[i].x -= extents->bounded.x;
-	glyphs[i].y -= extents->bounded.y;
+    for (i = 0; i < info->num_glyphs; i++) {
+	info->glyphs[i].x -= info->extents.x;
+	info->glyphs[i].y -= info->extents.y;
     }
 
-
-    saved_clip = extents->clip;
-    extents->clip = NULL;
-    status = _render_glyphs ((cairo_gl_surface_t *) mask, 0, 0,
-	                     CAIRO_OPERATOR_ADD,
-			     &_cairo_pattern_white.base,
-	                     glyphs, num_glyphs, scaled_font,
-			     extents,
-			     &has_component_alpha,
-			     remaining_glyphs);
-    extents->clip = saved_clip;
-
+    status = render_glyphs ((cairo_gl_surface_t *) mask, 0, 0,
+			    CAIRO_OPERATOR_ADD,
+			    &_cairo_pattern_white.base,
+			    info, &has_component_alpha);
     if (likely (status == CAIRO_STATUS_SUCCESS)) {
+	/* XXX composite */
+#if 0
 	cairo_surface_pattern_t mask_pattern;
-
         mask->is_clear = FALSE;
 	_cairo_pattern_init_for_surface (&mask_pattern, mask);
 	mask_pattern.base.has_component_alpha = has_component_alpha;
 	cairo_matrix_init_translate (&mask_pattern.base.matrix,
-		                     -extents->bounded.x, -extents->bounded.y);
+		                     -info->extents.x, -info->extents.y);
 	status = _cairo_surface_mask (&dst->base, op,
 		                      source, &mask_pattern.base,
-				      extents->clip);
+				      NULL);
 	_cairo_pattern_fini (&mask_pattern.base);
+#endif
     } else {
-	for (i = 0; i < num_glyphs; i++) {
-	    glyphs[i].x += extents->bounded.x;
-	    glyphs[i].y += extents->bounded.y;
+	for (i = 0; i < info->num_glyphs; i++) {
+	    info->glyphs[i].x += info->extents.x;
+	    info->glyphs[i].y += info->extents.y;
 	}
-	*remaining_glyphs = num_glyphs;
     }
 
     cairo_surface_destroy (mask);
@@ -438,143 +396,62 @@ _cairo_gl_surface_show_glyphs_via_mask (cairo_gl_surface_t	*dst,
     return status;
 }
 
+cairo_int_status_t
+_cairo_gl_check_composite_glyphs (const cairo_composite_rectangles_t *extents,
+				  cairo_scaled_font_t *scaled_font,
+				  cairo_glyph_t *glyphs,
+				  int *num_glyphs)
+{
+    if (! _cairo_gl_operator_is_supported (extents->op))
+	return UNSUPPORTED ("unsupported operator");
+
+    /* XXX use individual masks for large glyphs? */
+    if (ceil (scaled_font->max_scale) >= GLYPH_CACHE_MAX_SIZE)
+	return UNSUPPORTED ("glyphs too large");
 
-cairo_private cairo_bool_t
-_cairo_gl_surface_get_extents (void		     *abstract_surface,
-			       cairo_rectangle_int_t *rectangle);
+    return CAIRO_STATUS_SUCCESS;
+}
 
 cairo_int_status_t
-_cairo_gl_surface_show_glyphs (void			*abstract_dst,
-			       cairo_operator_t		 op,
-			       const cairo_pattern_t	*source,
-			       cairo_glyph_t		*glyphs,
-			       int			 num_glyphs,
-			       cairo_scaled_font_t	*scaled_font,
-			       const cairo_clip_t	*clip,
-			       int			*remaining_glyphs)
+_cairo_gl_composite_glyphs (void			*_dst,
+			    cairo_operator_t		 op,
+			    cairo_surface_t		*_src,
+			    int				 src_x,
+			    int				 src_y,
+			    int				 dst_x,
+			    int				 dst_y,
+			    cairo_composite_glyphs_info_t *info)
 {
-    cairo_gl_surface_t *dst = abstract_dst;
-    cairo_composite_rectangles_t extents;
-    cairo_rectangle_int_t unbounded;
-    cairo_bool_t overlap, use_mask = FALSE;
+    cairo_gl_surface_t *dst = _dst;
     cairo_bool_t has_component_alpha;
-    cairo_status_t status;
     int i;
 
-    if (! _cairo_gl_operator_is_supported (op))
-	return UNSUPPORTED ("unsupported operator");
-
-    if (! _cairo_operator_bounded_by_mask (op))
-	use_mask |= TRUE;
-
     /* If any of the glyphs are component alpha, we have to go through a mask,
      * since only _cairo_gl_surface_composite() currently supports component
      * alpha.
      */
-    if (!use_mask && op != CAIRO_OPERATOR_OVER) {
-	for (i = 0; i < num_glyphs; i++) {
+    if (!dst->base.is_clear && ! info->use_mask && op != CAIRO_OPERATOR_OVER) {
+	for (i = 0; i < info->num_glyphs; i++) {
 	    cairo_scaled_glyph_t *scaled_glyph;
 
-	    status = _cairo_scaled_glyph_lookup (scaled_font,
-						 glyphs[i].index,
-						 CAIRO_SCALED_GLYPH_INFO_SURFACE,
-						 &scaled_glyph);
-	    if (!_cairo_status_is_error (status) &&
+	    if (_cairo_scaled_glyph_lookup (info->font, info->glyphs[i].index,
+					    CAIRO_SCALED_GLYPH_INFO_SURFACE,
+					    &scaled_glyph) == CAIRO_INT_STATUS_SUCCESS &&
 		scaled_glyph->surface->format == CAIRO_FORMAT_ARGB32)
 	    {
-		use_mask = TRUE;
+		info->use_mask = TRUE;
 		break;
 	    }
 	}
     }
 
-    /* For CLEAR, cairo's rendering equation (quoting Owen's description in:
-     * http://lists.cairographics.org/archives/cairo/2005-August/004992.html)
-     * is:
-     *     mask IN clip ? src OP dest : dest
-     * or more simply:
-     *     mask IN CLIP ? 0 : dest
-     *
-     * where the ternary operator A ? B : C is (A * B) + ((1 - A) * C).
-     *
-     * The model we use in _cairo_gl_set_operator() is Render's:
-     *     src IN mask IN clip OP dest
-     * which would boil down to:
-     *     0 (bounded by the extents of the drawing).
-     *
-     * However, we can do a Render operation using an opaque source
-     * and DEST_OUT to produce:
-     *    1 IN mask IN clip DEST_OUT dest
-     * which is
-     *    mask IN clip ? 0 : dest
-     */
-    if (op == CAIRO_OPERATOR_CLEAR) {
-	source = &_cairo_pattern_white.base;
-	op = CAIRO_OPERATOR_DEST_OUT;
-    }
-
-    /* For SOURCE, cairo's rendering equation is:
-     *     (mask IN clip) ? src OP dest : dest
-     * or more simply:
-     *     (mask IN clip) ? src : dest.
-     *
-     * If we just used the Render equation, we would get:
-     *     (src IN mask IN clip) OP dest
-     * or:
-     *     (src IN mask IN clip) bounded by extents of the drawing.
-     *
-     * The trick is that for GL blending, we only get our 4 source values
-     * into the blender, and since we need all 4 components of source, we
-     * can't also get the mask IN clip into the blender.  But if we did
-     * two passes we could make it work:
-     *     dest = (mask IN clip) DEST_OUT dest
-     *     dest = src IN mask IN clip ADD dest
-     *
-     * But for now, composite via an intermediate mask.
-     */
-    if (op == CAIRO_OPERATOR_SOURCE)
-	use_mask |= TRUE;
-
-    /* XXX we don't need ownership of the font as we use a global
-     * glyph cache -- but we do need scaled_glyph eviction notification. :-(
-     */
-    if (! _cairo_gl_surface_owns_font (dst, scaled_font))
-	return UNSUPPORTED ("do not control font");
-
-    _cairo_gl_surface_get_extents (dst, &unbounded);
-    status = _cairo_composite_rectangles_init_for_glyphs (&extents,
-							  &unbounded,
-							  op, source,
-							  scaled_font,
-							  glyphs, num_glyphs,
-							  clip, &overlap);
-    if (unlikely (status))
-	return status;
-
-    /* If the glyphs overlap, we need to build an intermediate mask rather
-     * then perform the compositing directly.
-     */
-    use_mask |= overlap;
-    use_mask |= ! _cairo_clip_is_region (extents.clip);
-
-    if (use_mask) {
-	status = _cairo_gl_surface_show_glyphs_via_mask (dst, op,
-							 source,
-							 glyphs, num_glyphs,
-							 scaled_font,
-							 &extents,
-							 remaining_glyphs);
+    if (info->use_mask) {
+	return render_glyphs_via_mask (dst, op, _src, info);
     } else {
-	status = _render_glyphs (dst, extents.bounded.x, extents.bounded.y,
-				 op, source,
-				 glyphs, num_glyphs, scaled_font,
-				 &extents,
-				 &has_component_alpha,
-				 remaining_glyphs);
+	return render_glyphs (dst, dst_x, dst_y,
+			      op, _src, info,
+			      &has_component_alpha);
     }
-
-    _cairo_composite_rectangles_fini (&extents);
-    return status;
 }
 
 void
@@ -584,7 +461,7 @@ _cairo_gl_glyph_cache_init (cairo_gl_glyph_cache_t *cache)
 		       GLYPH_CACHE_WIDTH,
 		       GLYPH_CACHE_HEIGHT,
 		       GLYPH_CACHE_MIN_SIZE,
-		       sizeof (cairo_gl_glyph_private_t));
+		       sizeof (cairo_gl_glyph_t));
 }
 
 void
@@ -598,4 +475,3 @@ _cairo_gl_glyph_cache_fini (cairo_gl_context_t *ctx,
         cache->pattern.surface = NULL;
     }
 }
-
diff --git a/src/cairo-gl-operand.c b/src/cairo-gl-operand.c
new file mode 100644
index 0000000..8b345bb
--- /dev/null
+++ b/src/cairo-gl-operand.c
@@ -0,0 +1,538 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2009 Eric Anholt
+ * Copyright © 2009 Chris Wilson
+ * Copyright © 2005,2010 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 Red Hat, Inc.
+ *
+ * Contributor(s):
+ *	Benjamin Otte <otte at gnome.org>
+ *	Carl Worth <cworth at cworth.org>
+ *	Chris Wilson <chris at chris-wilson.co.uk>
+ *	Eric Anholt <eric at anholt.net>
+ */
+
+#include "cairoint.h"
+
+#include "cairo-gl-private.h"
+
+#include "cairo-composite-rectangles-private.h"
+#include "cairo-compositor-private.h"
+#include "cairo-default-context-private.h"
+#include "cairo-error-private.h"
+#include "cairo-image-surface-private.h"
+#include "cairo-surface-backend-private.h"
+
+static cairo_int_status_t
+_cairo_gl_create_gradient_texture (cairo_gl_surface_t *dst,
+				   const cairo_gradient_pattern_t *pattern,
+                                   cairo_gl_gradient_t **gradient)
+{
+    cairo_gl_context_t *ctx;
+    cairo_status_t status;
+
+    status = _cairo_gl_context_acquire (dst->base.device, &ctx);
+    if (unlikely (status))
+	return status;
+
+    status = _cairo_gl_gradient_create (ctx, pattern->n_stops, pattern->stops, gradient);
+
+    return _cairo_gl_context_release (ctx, status);
+}
+
+/*
+ * Like cairo_pattern_acquire_surface(), but returns a matrix that transforms
+ * from dest to src coords.
+ */
+static cairo_status_t
+_cairo_gl_pattern_texture_setup (cairo_gl_operand_t *operand,
+				 const cairo_pattern_t *src,
+				 cairo_gl_surface_t *dst,
+				 int src_x, int src_y,
+				 int dst_x, int dst_y,
+				 int width, int height)
+{
+    cairo_status_t status;
+    cairo_matrix_t m;
+    cairo_gl_surface_t *surface;
+    cairo_surface_attributes_t *attributes;
+
+    attributes = &operand->texture.attributes;
+
+#if 0
+    status = _cairo_pattern_acquire_surface (src, &dst->base,
+					     src_x, src_y,
+					     width, height,
+					     CAIRO_PATTERN_ACQUIRE_NONE,
+					     (cairo_surface_t **)
+					     &surface,
+					     attributes);
+    if (unlikely (status))
+	return status;
+#endif
+
+    if (_cairo_gl_device_requires_power_of_two_textures (dst->base.device) &&
+	(attributes->extend == CAIRO_EXTEND_REPEAT ||
+	 attributes->extend == CAIRO_EXTEND_REFLECT))
+    {
+	return UNSUPPORTED ("EXT_texture_rectangle with repeat/reflect");
+    }
+
+    assert (_cairo_gl_surface_is_texture (surface));
+
+    operand->type = CAIRO_GL_OPERAND_TEXTURE;
+    operand->texture.surface = surface;
+    operand->texture.tex = surface->tex;
+    /* Translate the matrix from
+     * (unnormalized src -> unnormalized src) to
+     * (unnormalized dst -> unnormalized src)
+     */
+    cairo_matrix_init_translate (&m,
+				 src_x - dst_x + attributes->x_offset,
+				 src_y - dst_y + attributes->y_offset);
+    cairo_matrix_multiply (&attributes->matrix,
+			   &m,
+			   &attributes->matrix);
+
+
+    /* Translate the matrix from
+     * (unnormalized dst -> unnormalized src) to
+     * (unnormalized dst -> normalized src)
+     */
+    if (_cairo_gl_device_requires_power_of_two_textures (dst->base.device)) {
+	cairo_matrix_init_scale (&m,
+				 1.0,
+				 1.0);
+    } else {
+	cairo_matrix_init_scale (&m,
+				 1.0 / surface->width,
+				 1.0 / surface->height);
+    }
+    cairo_matrix_multiply (&attributes->matrix,
+			   &attributes->matrix,
+			   &m);
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+void
+_cairo_gl_solid_operand_init (cairo_gl_operand_t *operand,
+	                      const cairo_color_t *color)
+{
+    operand->type = CAIRO_GL_OPERAND_CONSTANT;
+    operand->constant.color[0] = color->red   * color->alpha;
+    operand->constant.color[1] = color->green * color->alpha;
+    operand->constant.color[2] = color->blue  * color->alpha;
+    operand->constant.color[3] = color->alpha;
+}
+
+static cairo_status_t
+_cairo_gl_gradient_operand_init (cairo_gl_operand_t *operand,
+                                 const cairo_pattern_t *pattern,
+				 cairo_gl_surface_t *dst,
+				 int src_x, int src_y,
+				 int dst_x, int dst_y)
+{
+    const cairo_gradient_pattern_t *gradient = (const cairo_gradient_pattern_t *)pattern;
+    cairo_status_t status;
+
+    assert (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR ||
+	    gradient->base.type == CAIRO_PATTERN_TYPE_RADIAL);
+
+    if (! _cairo_gl_device_has_glsl (dst->base.device))
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+
+    status = _cairo_gl_create_gradient_texture (dst,
+						gradient,
+						&operand->gradient.gradient);
+    if (unlikely (status))
+	return status;
+
+    if (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR) {
+	cairo_linear_pattern_t *linear = (cairo_linear_pattern_t *) gradient;
+	double x0, y0, dx, dy, sf, offset;
+
+	dx = linear->pd2.x - linear->pd1.x;
+	dy = linear->pd2.y - linear->pd1.y;
+	sf = 1.0 / (dx * dx + dy * dy);
+	dx *= sf;
+	dy *= sf;
+
+	x0 = linear->pd1.x;
+	y0 = linear->pd1.y;
+	offset = dx * x0 + dy * y0;
+
+	operand->type = CAIRO_GL_OPERAND_LINEAR_GRADIENT;
+
+	cairo_matrix_init (&operand->gradient.m, dx, 0, dy, 1, -offset, 0);
+	if (! _cairo_matrix_is_identity (&pattern->matrix)) {
+	    cairo_matrix_multiply (&operand->gradient.m,
+				   &pattern->matrix,
+				   &operand->gradient.m);
+	}
+    } else {
+	cairo_matrix_t m;
+	cairo_circle_double_t circles[2];
+	double x0, y0, r0, dx, dy, dr;
+
+	/*
+	 * Some fragment shader implementations use half-floats to
+	 * represent numbers, so the maximum number they can represent
+	 * is about 2^14. Some intermediate computations used in the
+	 * radial gradient shaders can produce results of up to 2*k^4.
+	 * Setting k=8 makes the maximum result about 8192 (assuming
+	 * that the extreme circles are not much smaller than the
+	 * destination image).
+	 */
+	_cairo_gradient_pattern_fit_to_range (gradient, 8.,
+					      &operand->gradient.m, circles);
+
+	x0 = circles[0].center.x;
+	y0 = circles[0].center.y;
+	r0 = circles[0].radius;
+	dx = circles[1].center.x - x0;
+	dy = circles[1].center.y - y0;
+	dr = circles[1].radius   - r0;
+
+	operand->gradient.a = dx * dx + dy * dy - dr * dr;
+	operand->gradient.radius_0 = r0;
+	operand->gradient.circle_d.center.x = dx;
+	operand->gradient.circle_d.center.y = dy;
+	operand->gradient.circle_d.radius   = dr;
+
+	if (operand->gradient.a == 0)
+	    operand->type = CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0;
+	else if (pattern->extend == CAIRO_EXTEND_NONE)
+	    operand->type = CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE;
+	else
+	    operand->type = CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT;
+
+	cairo_matrix_init_translate (&m, -x0, -y0);
+	cairo_matrix_multiply (&operand->gradient.m,
+			       &operand->gradient.m,
+			       &m);
+    }
+
+    cairo_matrix_translate (&operand->gradient.m, src_x - dst_x, src_y - dst_y);
+
+    operand->gradient.extend = pattern->extend;
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+void
+_cairo_gl_operand_destroy (cairo_gl_operand_t *operand)
+{
+    switch (operand->type) {
+    case CAIRO_GL_OPERAND_CONSTANT:
+	break;
+    case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
+    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
+    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
+    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
+	_cairo_gl_gradient_destroy (operand->gradient.gradient);
+	break;
+    case CAIRO_GL_OPERAND_TEXTURE:
+	break;
+    default:
+    case CAIRO_GL_OPERAND_COUNT:
+        ASSERT_NOT_REACHED;
+    case CAIRO_GL_OPERAND_NONE:
+        break;
+    }
+
+    operand->type = CAIRO_GL_OPERAND_NONE;
+}
+
+cairo_int_status_t
+_cairo_gl_operand_init (cairo_gl_operand_t *operand,
+		        const cairo_pattern_t *pattern,
+		        cairo_gl_surface_t *dst,
+		        int src_x, int src_y,
+		        int dst_x, int dst_y,
+		        int width, int height)
+{
+    cairo_int_status_t status;
+
+    switch (pattern->type) {
+    case CAIRO_PATTERN_TYPE_SOLID:
+	_cairo_gl_solid_operand_init (operand,
+				      &((cairo_solid_pattern_t *) pattern)->color);
+	return CAIRO_STATUS_SUCCESS;
+    case CAIRO_PATTERN_TYPE_LINEAR:
+    case CAIRO_PATTERN_TYPE_RADIAL:
+	status = _cairo_gl_gradient_operand_init (operand,
+						  pattern, dst,
+						  src_x, src_y,
+						  dst_x, dst_y);
+	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+	    return status;
+
+	/* fall through */
+
+    default:
+    case CAIRO_PATTERN_TYPE_MESH:
+    case CAIRO_PATTERN_TYPE_SURFACE:
+	return _cairo_gl_pattern_texture_setup (operand,
+						pattern, dst,
+						src_x, src_y,
+						dst_x, dst_y,
+						width, height);
+    }
+}
+
+cairo_filter_t
+_cairo_gl_operand_get_filter (cairo_gl_operand_t *operand)
+{
+    cairo_filter_t filter;
+
+    switch ((int) operand->type) {
+    case CAIRO_GL_OPERAND_TEXTURE:
+	filter = operand->texture.attributes.filter;
+	break;
+    case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
+    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
+    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
+    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
+	filter = CAIRO_FILTER_BILINEAR;
+	break;
+    default:
+	filter = CAIRO_FILTER_DEFAULT;
+	break;
+    }
+
+    return filter;
+}
+
+GLint
+_cairo_gl_operand_get_gl_filter (cairo_gl_operand_t *operand)
+{
+    cairo_filter_t filter = _cairo_gl_operand_get_filter (operand);
+
+    return filter != CAIRO_FILTER_FAST && filter != CAIRO_FILTER_NEAREST ?
+	   GL_LINEAR :
+	   GL_NEAREST;
+}
+
+cairo_extend_t
+_cairo_gl_operand_get_extend (cairo_gl_operand_t *operand)
+{
+    cairo_extend_t extend;
+
+    switch ((int) operand->type) {
+    case CAIRO_GL_OPERAND_TEXTURE:
+	extend = operand->texture.attributes.extend;
+	break;
+    case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
+    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
+    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
+    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
+	extend = operand->gradient.extend;
+	break;
+    default:
+	extend = CAIRO_EXTEND_NONE;
+	break;
+    }
+
+    return extend;
+}
+
+
+void
+_cairo_gl_operand_bind_to_shader (cairo_gl_context_t *ctx,
+                                  cairo_gl_operand_t *operand,
+                                  cairo_gl_tex_t      tex_unit)
+{
+    char uniform_name[50];
+    char *custom_part;
+    static const char *names[] = { "source", "mask" };
+
+    strcpy (uniform_name, names[tex_unit]);
+    custom_part = uniform_name + strlen (names[tex_unit]);
+
+    switch (operand->type) {
+    default:
+    case CAIRO_GL_OPERAND_COUNT:
+        ASSERT_NOT_REACHED;
+    case CAIRO_GL_OPERAND_NONE:
+        break;
+    case CAIRO_GL_OPERAND_CONSTANT:
+        strcpy (custom_part, "_constant");
+	_cairo_gl_shader_bind_vec4 (ctx,
+                                    uniform_name,
+                                    operand->constant.color[0],
+                                    operand->constant.color[1],
+                                    operand->constant.color[2],
+                                    operand->constant.color[3]);
+        break;
+    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
+    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
+	strcpy (custom_part, "_a");
+	_cairo_gl_shader_bind_float  (ctx,
+				      uniform_name,
+				      operand->gradient.a);
+	/* fall through */
+    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
+	strcpy (custom_part, "_circle_d");
+	_cairo_gl_shader_bind_vec3   (ctx,
+				      uniform_name,
+				      operand->gradient.circle_d.center.x,
+				      operand->gradient.circle_d.center.y,
+				      operand->gradient.circle_d.radius);
+	strcpy (custom_part, "_radius_0");
+	_cairo_gl_shader_bind_float  (ctx,
+				      uniform_name,
+				      operand->gradient.radius_0);
+        /* fall through */
+    case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
+    case CAIRO_GL_OPERAND_TEXTURE:
+	/*
+	 * For GLES2 we use shaders to implement GL_CLAMP_TO_BORDER (used
+	 * with CAIRO_EXTEND_NONE). When bilinear filtering is enabled,
+	 * these shaders need the texture dimensions for their calculations.
+	 */
+	if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES &&
+	    _cairo_gl_operand_get_extend (operand) == CAIRO_EXTEND_NONE &&
+	    _cairo_gl_operand_get_gl_filter (operand) == GL_LINEAR)
+	{
+	    float width, height;
+	    if (operand->type == CAIRO_GL_OPERAND_TEXTURE) {
+		width = operand->texture.surface->width;
+		height = operand->texture.surface->height;
+	    }
+	    else {
+		width = operand->gradient.gradient->cache_entry.size,
+		height = 1;
+	    }
+	    strcpy (custom_part, "_texdims");
+	    _cairo_gl_shader_bind_vec2 (ctx, uniform_name, width, height);
+	}
+        break;
+    }
+}
+
+
+cairo_bool_t
+_cairo_gl_operand_needs_setup (cairo_gl_operand_t *dest,
+                               cairo_gl_operand_t *source,
+                               unsigned int        vertex_offset)
+{
+    if (dest->type != source->type)
+        return TRUE;
+    if (dest->vertex_offset != vertex_offset)
+        return TRUE;
+
+    switch (source->type) {
+    case CAIRO_GL_OPERAND_NONE:
+        return FALSE;
+    case CAIRO_GL_OPERAND_CONSTANT:
+        return dest->constant.color[0] != source->constant.color[0] ||
+               dest->constant.color[1] != source->constant.color[1] ||
+               dest->constant.color[2] != source->constant.color[2] ||
+               dest->constant.color[3] != source->constant.color[3];
+    case CAIRO_GL_OPERAND_TEXTURE:
+        return dest->texture.surface != source->texture.surface ||
+               dest->texture.attributes.extend != source->texture.attributes.extend ||
+               dest->texture.attributes.filter != source->texture.attributes.filter ||
+               dest->texture.attributes.has_component_alpha != source->texture.attributes.has_component_alpha;
+    case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
+    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
+    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
+    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
+        /* XXX: improve this */
+        return TRUE;
+    default:
+    case CAIRO_GL_OPERAND_COUNT:
+        ASSERT_NOT_REACHED;
+        break;
+    }
+    return TRUE;
+}
+
+unsigned int
+_cairo_gl_operand_get_vertex_size (cairo_gl_operand_type_t type)
+{
+    switch (type) {
+    default:
+    case CAIRO_GL_OPERAND_COUNT:
+        ASSERT_NOT_REACHED;
+    case CAIRO_GL_OPERAND_NONE:
+    case CAIRO_GL_OPERAND_CONSTANT:
+        return 0;
+    case CAIRO_GL_OPERAND_TEXTURE:
+    case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
+    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
+    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
+    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
+        return 2 * sizeof (GLfloat);
+    }
+}
+
+void
+_cairo_gl_operand_emit (cairo_gl_operand_t *operand,
+                        GLfloat ** vb,
+                        GLfloat x,
+                        GLfloat y,
+                        uint8_t alpha)
+{
+    switch (operand->type) {
+    default:
+    case CAIRO_GL_OPERAND_COUNT:
+        ASSERT_NOT_REACHED;
+    case CAIRO_GL_OPERAND_NONE:
+    case CAIRO_GL_OPERAND_CONSTANT:
+        break;
+    case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
+    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
+    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
+    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
+        {
+	    double s = x;
+	    double t = y;
+
+	    cairo_matrix_transform_point (&operand->gradient.m, &s, &t);
+
+	    *(*vb)++ = s;
+	    *(*vb)++ = t;
+        }
+	break;
+    case CAIRO_GL_OPERAND_TEXTURE:
+        {
+            cairo_surface_attributes_t *src_attributes = &operand->texture.attributes;
+            double s = x;
+            double t = y;
+
+            cairo_matrix_transform_point (&src_attributes->matrix, &s, &t);
+            *(*vb)++ = s;
+            *(*vb)++ = t;
+        }
+        break;
+    }
+}
diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h
index ee79b23..e1005ba 100644
--- a/src/cairo-gl-private.h
+++ b/src/cairo-gl-private.h
@@ -48,16 +48,17 @@
 
 #include "cairoint.h"
 
+#include "cairo-gl.h"
 #include "cairo-gl-gradient-private.h"
 
 #include "cairo-device-private.h"
 #include "cairo-error-private.h"
 #include "cairo-rtree-private.h"
+#include "cairo-scaled-font-private.h"
+#include "cairo-spans-compositor-private.h"
 
 #include <assert.h>
 
-#include "cairo-gl.h"
-
 #if CAIRO_HAS_GL_SURFACE
 #include <GL/gl.h>
 #include <GL/glext.h>
@@ -138,7 +139,6 @@ typedef enum cairo_gl_operand_type {
     CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0,
     CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE,
     CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT,
-    CAIRO_GL_OPERAND_SPANS,
 
     CAIRO_GL_OPERAND_COUNT
 } cairo_gl_operand_type_t;
@@ -161,11 +161,10 @@ typedef enum cairo_gl_shader_in {
 typedef enum cairo_gl_var_type {
   CAIRO_GL_VAR_NONE,
   CAIRO_GL_VAR_TEXCOORDS,
-  CAIRO_GL_VAR_COVERAGE
 } cairo_gl_var_type_t;
 
-#define cairo_gl_var_type_hash(src,mask,dest) ((mask) << 2 | (src << 1) | (dest))
-#define CAIRO_GL_VAR_TYPE_MAX ((CAIRO_GL_VAR_COVERAGE << 2) | (CAIRO_GL_VAR_TEXCOORDS << 1) | CAIRO_GL_VAR_TEXCOORDS)
+#define cairo_gl_var_type_hash(src,mask,spans,dest) ((spans) << 3) | ((mask) << 2 | (src << 1) | (dest))
+#define CAIRO_GL_VAR_TYPE_MAX ((CAIRO_GL_VAR_TEXCOORDS << 3) | (CAIRO_GL_VAR_TEXCOORDS << 2) | (CAIRO_GL_VAR_TEXCOORDS << 1) | CAIRO_GL_VAR_TEXCOORDS)
 
 /* This union structure describes a potential source or mask operand to the
  * compositing equation.
@@ -259,6 +258,8 @@ typedef struct _cairo_gl_dispatch {
 struct _cairo_gl_context {
     cairo_device_t base;
 
+    const cairo_compositor_t *compositor;
+
     GLuint texture_load_pbo;
     GLuint vbo;
     GLint max_framebuffer_size;
@@ -283,6 +284,7 @@ struct _cairo_gl_context {
     cairo_gl_shader_t *current_shader;
 
     cairo_gl_operand_t operands[2];
+    cairo_bool_t spans;
 
     char *vb;
     char *vb_mem;
@@ -311,8 +313,15 @@ typedef struct _cairo_gl_composite {
 
     cairo_gl_operand_t src;
     cairo_gl_operand_t mask;
+    cairo_bool_t spans;
 } cairo_gl_composite_t;
 
+typedef struct _cairo_gl_font {
+    cairo_scaled_font_private_t		base;
+    cairo_device_t			*device;
+    cairo_list_t			link;
+} cairo_gl_font_t;
+
 cairo_private extern const cairo_surface_backend_t _cairo_gl_surface_backend;
 
 static cairo_always_inline GLenum
@@ -432,6 +441,13 @@ _cairo_gl_composite_set_source (cairo_gl_composite_t *setup,
                                 int src_x, int src_y,
                                 int dst_x, int dst_y,
                                 int width, int height);
+cairo_private void
+_cairo_gl_composite_set_solid_source (cairo_gl_composite_t *setup,
+				      const cairo_color_t *color);
+
+cairo_private void
+_cairo_gl_composite_set_source_operand (cairo_gl_composite_t *setup,
+					const cairo_gl_operand_t *source);
 
 cairo_private cairo_int_status_t
 _cairo_gl_composite_set_mask (cairo_gl_composite_t *setup,
@@ -441,7 +457,11 @@ _cairo_gl_composite_set_mask (cairo_gl_composite_t *setup,
                               int width, int height);
 
 cairo_private void
-_cairo_gl_composite_set_mask_spans (cairo_gl_composite_t *setup);
+_cairo_gl_composite_set_mask_operand (cairo_gl_composite_t *setup,
+				      const cairo_gl_operand_t *mask);
+
+cairo_private void
+_cairo_gl_composite_set_spans (cairo_gl_composite_t *setup);
 
 cairo_private cairo_status_t
 _cairo_gl_composite_begin (cairo_gl_composite_t *setup,
@@ -481,13 +501,6 @@ _cairo_gl_get_image_format_and_type (cairo_gl_flavor_t flavor,
 				     cairo_bool_t *needs_swap);
 
 cairo_private void
-_cairo_gl_surface_scaled_font_fini ( cairo_scaled_font_t  *scaled_font);
-
-cairo_private void
-_cairo_gl_surface_scaled_glyph_fini (cairo_scaled_glyph_t *scaled_glyph,
-				     cairo_scaled_font_t  *scaled_font);
-
-cairo_private void
 _cairo_gl_glyph_cache_init (cairo_gl_glyph_cache_t *cache);
 
 cairo_private void
@@ -529,6 +542,7 @@ cairo_private cairo_status_t
 _cairo_gl_get_shader_by_type (cairo_gl_context_t *ctx,
                               cairo_gl_operand_t *source,
                               cairo_gl_operand_t *mask,
+			      cairo_bool_t use_coverage,
                               cairo_gl_shader_in_t in,
                               cairo_gl_shader_t **shader);
 
@@ -585,6 +599,17 @@ cairo_private cairo_status_t
 _cairo_gl_dispatch_init(cairo_gl_dispatch_t *dispatch,
 			cairo_gl_get_proc_addr_func_t get_proc_addr);
 
+cairo_private cairo_int_status_t
+_cairo_gl_operand_init (cairo_gl_operand_t *operand,
+		        const cairo_pattern_t *pattern,
+		        cairo_gl_surface_t *dst,
+		        int src_x, int src_y,
+		        int dst_x, int dst_y,
+		        int width, int height);
+cairo_private void
+_cairo_gl_solid_operand_init (cairo_gl_operand_t *operand,
+	                      const cairo_color_t *color);
+
 cairo_private cairo_filter_t
 _cairo_gl_operand_get_filter (cairo_gl_operand_t *operand);
 
@@ -594,25 +619,50 @@ _cairo_gl_operand_get_gl_filter (cairo_gl_operand_t *operand);
 cairo_private cairo_extend_t
 _cairo_gl_operand_get_extend (cairo_gl_operand_t *operand);
 
+cairo_private unsigned int
+_cairo_gl_operand_get_vertex_size (cairo_gl_operand_type_t type);
+
 cairo_private cairo_bool_t
-_cairo_gl_surface_get_extents (void		     *abstract_surface,
-			       cairo_rectangle_int_t *rectangle);
+_cairo_gl_operand_needs_setup (cairo_gl_operand_t *dest,
+                               cairo_gl_operand_t *source,
+                               unsigned int        vertex_offset);
+
+cairo_private void
+_cairo_gl_operand_bind_to_shader (cairo_gl_context_t *ctx,
+                                  cairo_gl_operand_t *operand,
+                                  cairo_gl_tex_t      tex_unit);
+
+cairo_private void
+_cairo_gl_operand_emit (cairo_gl_operand_t *operand,
+                        GLfloat ** vb,
+                        GLfloat x,
+                        GLfloat y,
+                        uint8_t alpha);
+
+cairo_private void
+_cairo_gl_operand_destroy (cairo_gl_operand_t *operand);
+
+cairo_private const cairo_compositor_t *
+_cairo_gl_span_compositor_get (void);
+
+cairo_private const cairo_compositor_t *
+_cairo_gl_traps_compositor_get (void);
 
 cairo_private cairo_int_status_t
-_cairo_gl_surface_polygon (cairo_gl_surface_t *dst,
-                           cairo_operator_t op,
-                           const cairo_pattern_t *src,
-                           cairo_polygon_t *polygon,
-                           cairo_fill_rule_t fill_rule,
-                           cairo_antialias_t antialias,
-                           const cairo_composite_rectangles_t *extents);
+_cairo_gl_check_composite_glyphs (const cairo_composite_rectangles_t *extents,
+				  cairo_scaled_font_t *scaled_font,
+				  cairo_glyph_t *glyphs,
+				  int *num_glyphs);
 
 cairo_private cairo_int_status_t
-_cairo_gl_clip_and_composite_boxes (cairo_gl_surface_t *dst,
-				    cairo_operator_t op,
-				    const cairo_pattern_t *src,
-				    cairo_boxes_t *boxes,
-				    cairo_composite_rectangles_t *extents);
+_cairo_gl_composite_glyphs (void			*_dst,
+			    cairo_operator_t		 op,
+			    cairo_surface_t		*_src,
+			    int				 src_x,
+			    int				 src_y,
+			    int				 dst_x,
+			    int				 dst_y,
+			    cairo_composite_glyphs_info_t *info);
 
 slim_hidden_proto (cairo_gl_surface_create);
 slim_hidden_proto (cairo_gl_surface_create_for_texture);
diff --git a/src/cairo-gl-shaders.c b/src/cairo-gl-shaders.c
index 7d60c0f..69609df 100644
--- a/src/cairo-gl-shaders.c
+++ b/src/cairo-gl-shaders.c
@@ -108,6 +108,7 @@ _cairo_gl_shader_compile (cairo_gl_context_t *ctx,
 			  cairo_gl_shader_t *shader,
 			  cairo_gl_var_type_t src,
 			  cairo_gl_var_type_t mask,
+			  cairo_bool_t use_coverage,
 			  const char *fragment_text);
 
 /* OpenGL Core 2.0 API. */
@@ -426,6 +427,7 @@ _cairo_gl_context_init_shaders (cairo_gl_context_t *ctx)
 				       &ctx->fill_rectangles_shader,
 				       CAIRO_GL_VAR_NONE,
 				       CAIRO_GL_VAR_NONE,
+				       FALSE,
 				       fill_fs_source);
     if (unlikely (status))
 	return status;
@@ -475,8 +477,6 @@ cairo_gl_operand_get_var_type (cairo_gl_operand_type_t type)
     case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
     case CAIRO_GL_OPERAND_TEXTURE:
         return CAIRO_GL_VAR_TEXCOORDS;
-    case CAIRO_GL_OPERAND_SPANS:
-        return CAIRO_GL_VAR_COVERAGE;
     }
 }
 
@@ -491,13 +491,8 @@ cairo_gl_shader_emit_variable (cairo_output_stream_t *stream,
     case CAIRO_GL_VAR_NONE:
         break;
     case CAIRO_GL_VAR_TEXCOORDS:
-        _cairo_output_stream_printf (stream, 
-                                     "varying vec2 %s_texcoords;\n", 
-                                     operand_names[name]);
-        break;
-    case CAIRO_GL_VAR_COVERAGE:
-        _cairo_output_stream_printf (stream, 
-                                     "varying float %s_coverage;\n", 
+        _cairo_output_stream_printf (stream,
+                                     "varying vec2 %s_texcoords;\n",
                                      operand_names[name]);
         break;
     }
@@ -514,21 +509,29 @@ cairo_gl_shader_emit_vertex (cairo_output_stream_t *stream,
     case CAIRO_GL_VAR_NONE:
         break;
     case CAIRO_GL_VAR_TEXCOORDS:
-        _cairo_output_stream_printf (stream, 
+        _cairo_output_stream_printf (stream,
                                      "    %s_texcoords = MultiTexCoord%d.xy;\n",
                                      operand_names[name], name);
         break;
-    case CAIRO_GL_VAR_COVERAGE:
-        _cairo_output_stream_printf (stream, 
-                                     "    %s_coverage = Color.a;\n",
-                                     operand_names[name]);
-        break;
     }
 }
 
+static void
+cairo_gl_shader_dcl_coverage (cairo_output_stream_t *stream)
+{
+    _cairo_output_stream_printf (stream, "varying float coverage;\n");
+}
+
+static void
+cairo_gl_shader_def_coverage (cairo_output_stream_t *stream)
+{
+    _cairo_output_stream_printf (stream, "    coverage = Color.a;\n");
+}
+
 static cairo_status_t
 cairo_gl_shader_get_vertex_source (cairo_gl_var_type_t src,
                                    cairo_gl_var_type_t mask,
+				   cairo_bool_t use_coverage,
                                    cairo_gl_var_type_t dest,
 				   char **out)
 {
@@ -539,6 +542,8 @@ cairo_gl_shader_get_vertex_source (cairo_gl_var_type_t src,
 
     cairo_gl_shader_emit_variable (stream, src, CAIRO_GL_TEX_SOURCE);
     cairo_gl_shader_emit_variable (stream, mask, CAIRO_GL_TEX_MASK);
+    if (use_coverage)
+	cairo_gl_shader_dcl_coverage (stream);
 
     _cairo_output_stream_printf (stream,
 				 "attribute vec4 Vertex;\n"
@@ -552,6 +557,8 @@ cairo_gl_shader_get_vertex_source (cairo_gl_var_type_t src,
 
     cairo_gl_shader_emit_vertex (stream, src, CAIRO_GL_TEX_SOURCE);
     cairo_gl_shader_emit_vertex (stream, mask, CAIRO_GL_TEX_MASK);
+    if (use_coverage)
+	cairo_gl_shader_def_coverage (stream);
 
     _cairo_output_stream_write (stream,
 				"}\n\0", 3);
@@ -774,15 +781,6 @@ cairo_gl_shader_emit_color (cairo_output_stream_t *stream,
 	    namestr, namestr, namestr, namestr, namestr,
 	    namestr, namestr, namestr, rectstr, namestr);
 	break;
-    case CAIRO_GL_OPERAND_SPANS:
-        _cairo_output_stream_printf (stream, 
-            "varying float %s_coverage;\n"
-            "vec4 get_%s()\n"
-            "{\n"
-            "    return vec4(0, 0, 0, %s_coverage);\n"
-            "}\n",
-            namestr, namestr, namestr);
-        break;
     }
 }
 
@@ -842,6 +840,7 @@ cairo_gl_shader_get_fragment_source (cairo_gl_context_t *ctx,
                                      cairo_gl_shader_in_t in,
                                      cairo_gl_operand_t *src,
                                      cairo_gl_operand_t *mask,
+				     cairo_bool_t use_coverage,
                                      cairo_gl_operand_type_t dest_type,
 				     char **out)
 {
@@ -849,6 +848,7 @@ cairo_gl_shader_get_fragment_source (cairo_gl_context_t *ctx,
     unsigned char *source;
     unsigned long length;
     cairo_status_t status;
+    const char *coverage_str;
 
     _cairo_output_stream_printf (stream,
 	"#ifdef GL_ES\n"
@@ -865,6 +865,10 @@ cairo_gl_shader_get_fragment_source (cairo_gl_context_t *ctx,
     cairo_gl_shader_emit_color (stream, ctx, src, CAIRO_GL_TEX_SOURCE);
     cairo_gl_shader_emit_color (stream, ctx, mask, CAIRO_GL_TEX_MASK);
 
+    coverage_str = "";
+    if (use_coverage)
+	coverage_str = " * coverage.a";
+
     _cairo_output_stream_printf (stream,
         "void main()\n"
         "{\n");
@@ -874,15 +878,18 @@ cairo_gl_shader_get_fragment_source (cairo_gl_context_t *ctx,
         ASSERT_NOT_REACHED;
     case CAIRO_GL_SHADER_IN_NORMAL:
         _cairo_output_stream_printf (stream,
-            "    gl_FragColor = get_source() * get_mask().a;\n");
+            "    gl_FragColor = get_source() * get_mask().a%s;\n",
+	    coverage_str);
         break;
     case CAIRO_GL_SHADER_IN_CA_SOURCE:
         _cairo_output_stream_printf (stream,
-            "    gl_FragColor = get_source() * get_mask();\n");
+            "    gl_FragColor = get_source() * get_mask()%s;\n",
+	    coverage_str);
         break;
     case CAIRO_GL_SHADER_IN_CA_SOURCE_ALPHA:
         _cairo_output_stream_printf (stream,
-            "    gl_FragColor = get_source().a * get_mask();\n");
+            "    gl_FragColor = get_source().a * get_mask()%s;\n",
+	    coverage_str);
         break;
     }
 
@@ -902,6 +909,7 @@ _cairo_gl_shader_compile (cairo_gl_context_t *ctx,
 			  cairo_gl_shader_t *shader,
 			  cairo_gl_var_type_t src,
 			  cairo_gl_var_type_t mask,
+			  cairo_bool_t use_coverage,
 			  const char *fragment_text)
 {
     unsigned int vertex_shader;
@@ -909,12 +917,14 @@ _cairo_gl_shader_compile (cairo_gl_context_t *ctx,
 
     assert (shader->program == 0);
 
-    vertex_shader = cairo_gl_var_type_hash (src, mask, CAIRO_GL_VAR_NONE);
+    vertex_shader = cairo_gl_var_type_hash (src, mask, use_coverage,
+					    CAIRO_GL_VAR_NONE);
     if (ctx->vertex_shaders[vertex_shader] == 0) {
 	char *source;
 
 	status = cairo_gl_shader_get_vertex_source (src,
 						    mask,
+						    use_coverage,
 						    CAIRO_GL_VAR_NONE,
 						    &source);
         if (unlikely (status))
@@ -1042,6 +1052,7 @@ cairo_status_t
 _cairo_gl_get_shader_by_type (cairo_gl_context_t *ctx,
                               cairo_gl_operand_t *source,
                               cairo_gl_operand_t *mask,
+			      cairo_bool_t use_coverage,
                               cairo_gl_shader_in_t in,
                               cairo_gl_shader_t **shader)
 {
@@ -1071,6 +1082,7 @@ _cairo_gl_get_shader_by_type (cairo_gl_context_t *ctx,
 						  in,
 						  source,
 						  mask,
+						  use_coverage,
 						  CAIRO_GL_OPERAND_NONE,
 						  &fs_source);
     if (unlikely (status))
@@ -1090,6 +1102,7 @@ _cairo_gl_get_shader_by_type (cairo_gl_context_t *ctx,
 				       &entry->shader,
 				       cairo_gl_operand_get_var_type (source->type),
 				       cairo_gl_operand_get_var_type (mask->type),
+				       use_coverage,
 				       fs_source);
     free (fs_source);
 
diff --git a/src/cairo-gl-spans-compositor.c b/src/cairo-gl-spans-compositor.c
new file mode 100644
index 0000000..57cccc9
--- /dev/null
+++ b/src/cairo-gl-spans-compositor.c
@@ -0,0 +1,502 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2009 Eric Anholt
+ * Copyright © 2009 Chris Wilson
+ * Copyright © 2005,2010 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 Red Hat, Inc.
+ *
+ * Contributor(s):
+ *	Benjamin Otte <otte at gnome.org>
+ *	Carl Worth <cworth at cworth.org>
+ *	Chris Wilson <chris at chris-wilson.co.uk>
+ *	Eric Anholt <eric at anholt.net>
+ */
+
+#include "cairoint.h"
+
+#include "cairo-gl-private.h"
+
+#include "cairo-composite-rectangles-private.h"
+#include "cairo-compositor-private.h"
+#include "cairo-default-context-private.h"
+#include "cairo-error-private.h"
+#include "cairo-image-surface-private.h"
+#include "cairo-spans-compositor-private.h"
+#include "cairo-surface-backend-private.h"
+
+typedef struct _cairo_gl_span_renderer {
+    cairo_span_renderer_t base;
+
+    cairo_gl_composite_t setup;
+    double opacity;
+
+    int xmin, xmax;
+    int ymin, ymax;
+
+    cairo_gl_context_t *ctx;
+} cairo_gl_span_renderer_t;
+
+static cairo_status_t
+_cairo_gl_bounded_opaque_spans (void *abstract_renderer,
+				int y, int height,
+				const cairo_half_open_span_t *spans,
+				unsigned num_spans)
+{
+    cairo_gl_span_renderer_t *r = abstract_renderer;
+
+    if (num_spans == 0)
+	return CAIRO_STATUS_SUCCESS;
+
+    do {
+	if (spans[0].coverage) {
+            _cairo_gl_composite_emit_rect (r->ctx,
+                                           spans[0].x, y,
+                                           spans[1].x, y + height,
+                                           spans[0].coverage);
+	}
+
+	spans++;
+    } while (--num_spans > 1);
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_gl_bounded_spans (void *abstract_renderer,
+			 int y, int height,
+			 const cairo_half_open_span_t *spans,
+			 unsigned num_spans)
+{
+    cairo_gl_span_renderer_t *r = abstract_renderer;
+
+    if (num_spans == 0)
+	return CAIRO_STATUS_SUCCESS;
+
+    do {
+	if (spans[0].coverage) {
+            _cairo_gl_composite_emit_rect (r->ctx,
+                                           spans[0].x, y,
+                                           spans[1].x, y + height,
+                                           r->opacity * spans[0].coverage);
+	}
+
+	spans++;
+    } while (--num_spans > 1);
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_gl_unbounded_spans (void *abstract_renderer,
+			   int y, int height,
+			   const cairo_half_open_span_t *spans,
+			   unsigned num_spans)
+{
+    cairo_gl_span_renderer_t *r = abstract_renderer;
+
+    if (y > r->ymin) {
+        _cairo_gl_composite_emit_rect (r->ctx,
+                                       r->xmin, r->ymin,
+                                       r->xmax, y,
+                                       0);
+    }
+
+    if (num_spans == 0) {
+        _cairo_gl_composite_emit_rect (r->ctx,
+                                       r->xmin, y,
+                                       r->xmax, y + height,
+                                       0);
+    } else {
+        if (spans[0].x != r->xmin) {
+            _cairo_gl_composite_emit_rect (r->ctx,
+                                           r->xmin, y,
+                                           spans[0].x,     y + height,
+                                           0);
+        }
+
+        do {
+            _cairo_gl_composite_emit_rect (r->ctx,
+                                           spans[0].x, y,
+                                           spans[1].x, y + height,
+                                           r->opacity * spans[0].coverage);
+            spans++;
+        } while (--num_spans > 1);
+
+        if (spans[0].x != r->xmax) {
+            _cairo_gl_composite_emit_rect (r->ctx,
+                                           spans[0].x,     y,
+                                           r->xmax, y + height,
+                                           0);
+        }
+    }
+
+    r->ymin = y + height;
+    return CAIRO_STATUS_SUCCESS;
+}
+
+/* XXX */
+static cairo_status_t
+_cairo_gl_clipped_spans (void *abstract_renderer,
+			   int y, int height,
+			   const cairo_half_open_span_t *spans,
+			   unsigned num_spans)
+{
+    cairo_gl_span_renderer_t *r = abstract_renderer;
+
+    if (y > r->ymin) {
+        _cairo_gl_composite_emit_rect (r->ctx,
+                                       r->xmin, r->ymin,
+                                       r->xmax, y,
+                                       0);
+    }
+
+    if (num_spans == 0) {
+        _cairo_gl_composite_emit_rect (r->ctx,
+                                       r->xmin, y,
+                                       r->xmax, y + height,
+                                       0);
+    } else {
+        if (spans[0].x != r->xmin) {
+            _cairo_gl_composite_emit_rect (r->ctx,
+                                           r->xmin, y,
+                                           spans[0].x,     y + height,
+                                           0);
+        }
+
+        do {
+            _cairo_gl_composite_emit_rect (r->ctx,
+                                           spans[0].x, y,
+                                           spans[1].x, y + height,
+                                           r->opacity * spans[0].coverage);
+            spans++;
+        } while (--num_spans > 1);
+
+        if (spans[0].x != r->xmax) {
+            _cairo_gl_composite_emit_rect (r->ctx,
+                                           spans[0].x,     y,
+                                           r->xmax, y + height,
+                                           0);
+        }
+    }
+
+    r->ymin = y + height;
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_gl_finish_unbounded_spans (void *abstract_renderer)
+{
+    cairo_gl_span_renderer_t *r = abstract_renderer;
+
+    if (r->ymax > r->ymin) {
+        _cairo_gl_composite_emit_rect (r->ctx,
+                                       r->xmin, r->ymin,
+                                       r->xmax, r->ymax,
+                                       0);
+    }
+
+    return _cairo_gl_context_release (r->ctx, CAIRO_STATUS_SUCCESS);
+}
+
+static cairo_status_t
+_cairo_gl_finish_bounded_spans (void *abstract_renderer)
+{
+    cairo_gl_span_renderer_t *r = abstract_renderer;
+
+    return _cairo_gl_context_release (r->ctx, CAIRO_STATUS_SUCCESS);
+}
+
+static void
+emit_aligned_boxes (cairo_gl_context_t *ctx,
+		    const cairo_boxes_t *boxes)
+{
+    const struct _cairo_boxes_chunk *chunk;
+    int i;
+
+    for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
+	for (i = 0; i < chunk->count; i++) {
+	    int x1 = _cairo_fixed_integer_part (chunk->base[i].p1.x);
+	    int y1 = _cairo_fixed_integer_part (chunk->base[i].p1.y);
+	    int x2 = _cairo_fixed_integer_part (chunk->base[i].p2.x);
+	    int y2 = _cairo_fixed_integer_part (chunk->base[i].p2.y);
+	    _cairo_gl_composite_emit_rect (ctx, x1, y1, x2, y2, 0);
+	}
+    }
+}
+
+static cairo_int_status_t
+fill_boxes (void		*_dst,
+	    cairo_operator_t	 op,
+	    const cairo_color_t	*color,
+	    cairo_boxes_t	*boxes)
+{
+    cairo_gl_composite_t setup;
+    cairo_gl_context_t *ctx;
+    cairo_int_status_t status;
+
+    status = _cairo_gl_composite_init (&setup, op, _dst, FALSE, NULL);
+    if (unlikely (status))
+        goto FAIL;
+
+   _cairo_gl_composite_set_solid_source (&setup, color);
+
+    status = _cairo_gl_composite_begin (&setup, &ctx);
+    if (unlikely (status))
+        goto FAIL;
+
+    emit_aligned_boxes (ctx, boxes);
+    status = _cairo_gl_context_release (ctx, CAIRO_STATUS_SUCCESS);
+
+FAIL:
+    _cairo_gl_composite_fini (&setup);
+    return status;
+}
+
+typedef struct cairo_gl_source {
+    cairo_surface_t base;
+
+    cairo_gl_operand_t operand;
+} cairo_gl_source_t;
+
+static cairo_status_t
+_cairo_gl_source_finish (void *abstract_surface)
+{
+    cairo_gl_source_t *source = abstract_surface;
+
+    _cairo_gl_operand_destroy (&source->operand);
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static const cairo_surface_backend_t cairo_gl_source_backend = {
+    CAIRO_SURFACE_TYPE_GL,
+    _cairo_gl_source_finish,
+    NULL, /* read-only wrapper */
+};
+
+static cairo_surface_t *
+pattern_to_surface (cairo_surface_t *dst,
+		    const cairo_pattern_t *pattern,
+		    cairo_bool_t is_mask,
+		    const cairo_rectangle_int_t *extents,
+		    const cairo_rectangle_int_t *sample,
+		    int *src_x, int *src_y)
+{
+    cairo_gl_source_t *source;
+    cairo_int_status_t status;
+
+    source = malloc (sizeof (*source));
+    if (unlikely (source == NULL))
+	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
+
+    _cairo_surface_init (&source->base,
+			 &cairo_gl_source_backend,
+			 NULL, /* device */
+			 CAIRO_CONTENT_COLOR_ALPHA);
+
+    *src_x = *src_y = 0;
+    status = _cairo_gl_operand_init (&source->operand, pattern, (cairo_gl_surface_t *)dst,
+				     extents->x, extents->y,
+				     extents->x, extents->y,
+				     extents->width, extents->height);
+    if (unlikely (status)) {
+	cairo_surface_destroy (&source->base);
+	return _cairo_surface_create_in_error (status);
+    }
+
+    return &source->base;
+}
+
+static inline cairo_gl_operand_t *
+source_to_operand (cairo_surface_t *surface)
+{
+    cairo_gl_source_t *source = (cairo_gl_source_t *)surface;
+    return &source->operand;
+}
+
+static cairo_int_status_t
+composite_boxes (void			*_dst,
+		 cairo_operator_t	op,
+		 cairo_surface_t	*abstract_src,
+		 cairo_surface_t	*abstract_mask,
+		 int			src_x,
+		 int			src_y,
+		 int			mask_x,
+		 int			mask_y,
+		 int			dst_x,
+		 int			dst_y,
+		 cairo_boxes_t		*boxes,
+		 const cairo_rectangle_int_t  *extents)
+{
+    cairo_gl_composite_t setup;
+    cairo_gl_context_t *ctx;
+    cairo_int_status_t status;
+
+    status = _cairo_gl_composite_init (&setup, op, _dst, FALSE, extents);
+    if (unlikely (status))
+        goto FAIL;
+
+    _cairo_gl_composite_set_source_operand (&setup,
+					    source_to_operand (abstract_src));
+
+    _cairo_gl_composite_set_mask_operand (&setup,
+					  source_to_operand (abstract_mask));
+
+    status = _cairo_gl_composite_begin (&setup, &ctx);
+    if (unlikely (status))
+        goto FAIL;
+
+    emit_aligned_boxes (ctx, boxes);
+    status = _cairo_gl_context_release (ctx, CAIRO_STATUS_SUCCESS);
+
+FAIL:
+    _cairo_gl_composite_fini (&setup);
+    return status;
+}
+
+static cairo_int_status_t
+_cairo_gl_span_renderer_init (cairo_abstract_span_renderer_t	*_r,
+			      const cairo_composite_rectangles_t *composite,
+			      cairo_bool_t			 needs_clip)
+{
+    cairo_gl_span_renderer_t *r = (cairo_gl_span_renderer_t *)_r;
+    const cairo_pattern_t *source = &composite->source_pattern.base;
+    cairo_operator_t op = composite->op;
+    cairo_int_status_t status;
+
+    /* XXX earlier! */
+    if (op == CAIRO_OPERATOR_CLEAR) {
+	source = &_cairo_pattern_white.base;
+	op = CAIRO_OPERATOR_DEST_OUT;
+    } else if (composite->surface->is_clear &&
+	       (op == CAIRO_OPERATOR_SOURCE ||
+		op == CAIRO_OPERATOR_OVER ||
+		op == CAIRO_OPERATOR_ADD)) {
+	op = CAIRO_OPERATOR_SOURCE;
+    } else if (op == CAIRO_OPERATOR_SOURCE) {
+	/* no lerp equivalent without some major PITA */
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+    } else if (! _cairo_gl_operator_is_supported (op))
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+
+    status = _cairo_gl_composite_init (&r->setup,
+                                       op, (cairo_gl_surface_t *)composite->surface,
+                                       FALSE, &composite->unbounded);
+    if (unlikely (status))
+        goto FAIL;
+
+    status = _cairo_gl_composite_set_source (&r->setup, source,
+					     composite->unbounded.x,
+					     composite->unbounded.y,
+					     composite->unbounded.x,
+					     composite->unbounded.y,
+					     composite->unbounded.width,
+					     composite->unbounded.height);
+    if (unlikely (status))
+        goto FAIL;
+
+    r->opacity = 1.0;
+    if (composite->mask_pattern.base.type == CAIRO_PATTERN_TYPE_SOLID) {
+	r->opacity = composite->mask_pattern.solid.color.alpha;
+    } else {
+	status = _cairo_gl_composite_set_mask (&r->setup,
+					       &composite->mask_pattern.base,
+					       composite->unbounded.x,
+					       composite->unbounded.y,
+					       composite->unbounded.x,
+					       composite->unbounded.y,
+					       composite->unbounded.width,
+					       composite->unbounded.height);
+	if (unlikely (status))
+	    goto FAIL;
+    }
+
+    _cairo_gl_composite_set_spans (&r->setup);
+
+    status = _cairo_gl_composite_begin (&r->setup, &r->ctx);
+    if (unlikely (status))
+        goto FAIL;
+
+    if (composite->is_bounded) {
+	if (r->opacity == 1.)
+	    r->base.render_rows = _cairo_gl_bounded_opaque_spans;
+	else
+	    r->base.render_rows = _cairo_gl_bounded_spans;
+        r->base.finish = _cairo_gl_finish_bounded_spans;
+    } else {
+	if (needs_clip)
+	    r->base.render_rows = _cairo_gl_clipped_spans;
+	else
+	    r->base.render_rows = _cairo_gl_unbounded_spans;
+        r->base.finish = _cairo_gl_finish_unbounded_spans;
+	r->xmin = composite->unbounded.x;
+	r->xmax = composite->unbounded.x + composite->unbounded.width;
+	r->ymin = composite->unbounded.y;
+	r->ymax = composite->unbounded.y + composite->unbounded.height;
+    }
+
+    return CAIRO_STATUS_SUCCESS;
+
+FAIL:
+    return status;
+}
+
+static void
+_cairo_gl_span_renderer_fini (cairo_abstract_span_renderer_t *_r,
+			      cairo_int_status_t status)
+{
+    cairo_gl_span_renderer_t *r = (cairo_gl_span_renderer_t *) _r;
+
+    if (status == CAIRO_INT_STATUS_SUCCESS)
+	r->base.finish (r);
+
+    _cairo_gl_composite_fini (&r->setup);
+}
+
+const cairo_compositor_t *
+_cairo_gl_span_compositor_get (void)
+{
+    static cairo_spans_compositor_t compositor;
+
+    if (compositor.base.delegate == NULL) {
+	/* The fallback to traps here is essentially just for glyphs... */
+	_cairo_spans_compositor_init (&compositor,
+				      _cairo_gl_traps_compositor_get());
+
+	compositor.fill_boxes = fill_boxes;
+	//compositor.check_composite_boxes = check_composite_boxes;
+	compositor.pattern_to_surface = pattern_to_surface;
+	compositor.composite_boxes = composite_boxes;
+	//compositor.check_span_renderer = check_span_renderer;
+	compositor.renderer_init = _cairo_gl_span_renderer_init;
+	compositor.renderer_fini = _cairo_gl_span_renderer_fini;
+    }
+
+    return &compositor.base;
+}
diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index ec70820..dec4b82 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -43,31 +43,11 @@
 #include "cairo-gl-private.h"
 
 #include "cairo-composite-rectangles-private.h"
+#include "cairo-compositor-private.h"
 #include "cairo-default-context-private.h"
 #include "cairo-error-private.h"
 #include "cairo-image-surface-private.h"
-
-static cairo_int_status_t
-_cairo_gl_surface_fill_rectangles (void			   *abstract_dst,
-				   cairo_operator_t	    op,
-				   const cairo_color_t     *color,
-				   cairo_rectangle_int_t   *rects,
-				   int			    num_rects);
-
-static cairo_int_status_t
-_cairo_gl_surface_composite (cairo_operator_t		  op,
-			     const cairo_pattern_t	 *src,
-			     const cairo_pattern_t	 *mask,
-			     void			 *abstract_dst,
-			     int			  src_x,
-			     int			  src_y,
-			     int			  mask_x,
-			     int			  mask_y,
-			     int			  dst_x,
-			     int			  dst_y,
-			     unsigned int		  width,
-			     unsigned int		  height,
-			     cairo_region_t		 *clip_region);
+#include "cairo-surface-backend-private.h"
 
 static cairo_status_t
 _cairo_gl_surface_flush (void *abstract_surface);
@@ -306,6 +286,9 @@ _cairo_gl_get_image_format_and_type_gl (pixman_format_code_t pixman_format,
     case PIXMAN_yv12:
     case PIXMAN_x2r10g10b10:
     case PIXMAN_a2r10g10b10:
+    case PIXMAN_r8g8b8x8:
+    case PIXMAN_r8g8b8a8:
+    case PIXMAN_x14r6g6b6:
     default:
 	return FALSE;
     }
@@ -509,10 +492,8 @@ cairo_gl_surface_create (cairo_device_t		*abstract_device,
     if (! CAIRO_CONTENT_VALID (content))
 	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_CONTENT));
 
-    if (abstract_device == NULL) {
-	return cairo_image_surface_create (_cairo_format_from_content (content),
-					   width, height);
-    }
+    if (abstract_device == NULL)
+	return _cairo_image_surface_create_with_content (content, width, height);
 
     if (abstract_device->status)
 	return _cairo_surface_create_in_error (abstract_device->status);
@@ -545,7 +526,6 @@ cairo_gl_surface_create (cairo_device_t		*abstract_device,
 }
 slim_hidden_def (cairo_gl_surface_create);
 
-
 /**
  * cairo_gl_surface_create_for_texture:
  * @content: type of content in the surface
@@ -592,7 +572,7 @@ cairo_gl_surface_create_for_texture (cairo_device_t	*abstract_device,
 	return _cairo_surface_create_in_error (abstract_device->status);
 
     if (abstract_device->backend->type != CAIRO_DEVICE_TYPE_GL)
-	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH));
+	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_DEVICE_TYPE_MISMATCH));
 
     status = _cairo_gl_context_acquire (abstract_device, &ctx);
     if (unlikely (status))
@@ -614,20 +594,19 @@ cairo_gl_surface_set_size (cairo_surface_t *abstract_surface,
 			   int              height)
 {
     cairo_gl_surface_t *surface = (cairo_gl_surface_t *) abstract_surface;
-    cairo_status_t status;
 
     if (unlikely (abstract_surface->status))
 	return;
     if (unlikely (abstract_surface->finished)) {
-	status = _cairo_surface_set_error (abstract_surface,
-		                           _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
+	_cairo_surface_set_error (abstract_surface,
+				  _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
         return;
     }
 
     if (! _cairo_surface_is_gl (abstract_surface) ||
         _cairo_gl_surface_is_texture (surface)) {
-	status = _cairo_surface_set_error (abstract_surface,
-		                           _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH));
+	_cairo_surface_set_error (abstract_surface,
+				  _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH));
 	return;
     }
 
@@ -664,19 +643,18 @@ void
 cairo_gl_surface_swapbuffers (cairo_surface_t *abstract_surface)
 {
     cairo_gl_surface_t *surface = (cairo_gl_surface_t *) abstract_surface;
-    cairo_status_t status;
 
     if (unlikely (abstract_surface->status))
 	return;
     if (unlikely (abstract_surface->finished)) {
-	status = _cairo_surface_set_error (abstract_surface,
-		                           _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
+	_cairo_surface_set_error (abstract_surface,
+				  _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
         return;
     }
 
     if (! _cairo_surface_is_gl (abstract_surface)) {
-	status = _cairo_surface_set_error (abstract_surface,
-		                           CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
+	_cairo_surface_set_error (abstract_surface,
+				  CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
 	return;
     }
 
@@ -694,10 +672,20 @@ cairo_gl_surface_swapbuffers (cairo_surface_t *abstract_surface)
 
         status = _cairo_gl_context_release (ctx, status);
         if (status)
-            status = _cairo_surface_set_error (abstract_surface, status);         
+            status = _cairo_surface_set_error (abstract_surface, status);
     }
 }
 
+static cairo_bool_t
+_cairo_gl_surface_size_valid (cairo_gl_surface_t *surface,
+			      int width, int height)
+{
+    cairo_gl_context_t *ctx = (cairo_gl_context_t *)surface->base.device;
+    return width > 0 && height > 0 &&
+	width <= ctx->max_framebuffer_size &&
+	height <= ctx->max_framebuffer_size;
+}
+
 static cairo_surface_t *
 _cairo_gl_surface_create_similar (void		 *abstract_surface,
 				  cairo_content_t  content,
@@ -708,24 +696,15 @@ _cairo_gl_surface_create_similar (void		 *abstract_surface,
     cairo_gl_context_t *ctx;
     cairo_status_t status;
 
-    if (width < 1 || height < 1)
-        return cairo_image_surface_create (_cairo_format_from_content (content),
-                                           width, height);
+    if (! _cairo_gl_surface_size_valid (abstract_surface, width, height))
+        return _cairo_image_surface_create_with_content (content, width, height);
 
     status = _cairo_gl_context_acquire (surface->device, &ctx);
     if (unlikely (status))
 	return _cairo_surface_create_in_error (status);
 
-    if (width > ctx->max_framebuffer_size ||
-	height > ctx->max_framebuffer_size)
-    {
-	surface = NULL;
-        goto RELEASE;
-    }
-
     surface = _cairo_gl_surface_create_scratch (ctx, content, width, height);
 
-RELEASE:
     status = _cairo_gl_context_release (ctx, status);
     if (unlikely (status)) {
         cairo_surface_destroy (surface);
@@ -735,6 +714,43 @@ RELEASE:
     return surface;
 }
 
+static cairo_int_status_t
+_cairo_gl_surface_fill_alpha_channel (void *abstract_dst,
+				      int x, int y,
+				      int width, int height)
+{
+    cairo_gl_surface_t *dst = abstract_dst;
+    cairo_gl_composite_t setup;
+    cairo_gl_context_t *ctx;
+    cairo_status_t status;
+
+    _cairo_gl_composite_flush (ctx);
+    glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE);
+
+    status = _cairo_gl_composite_init (&setup, CAIRO_OPERATOR_SOURCE, dst,
+                                       FALSE, NULL);
+    if (unlikely (status))
+        goto CLEANUP;
+
+    _cairo_gl_composite_set_solid_source (&setup, CAIRO_COLOR_BLACK);
+
+    status = _cairo_gl_composite_begin (&setup, &ctx);
+    if (unlikely (status))
+        goto CLEANUP;
+
+    _cairo_gl_composite_emit_rect (ctx, x, y, x + width, y + height, 0);
+
+    status = _cairo_gl_context_release (ctx, status);
+
+  CLEANUP:
+    _cairo_gl_composite_fini (&setup);
+
+    _cairo_gl_composite_flush (ctx);
+    glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+
+    return status;
+}
+
 cairo_status_t
 _cairo_gl_surface_draw_image (cairo_gl_surface_t *dst,
 			      cairo_image_surface_t *src,
@@ -797,8 +813,8 @@ _cairo_gl_surface_draw_image (cairo_gl_surface_t *dst,
 	 * image data ourselves in some cases. In particular, we must extract
 	 * the pixels if:
 	 * a. we don't want full-length lines or
-	 * b. the row stride cannot be handled by GL itself using a 4 byte alignment
-	 *    constraint
+	 * b. the row stride cannot be handled by GL itself using a 4 byte
+	 *     alignment constraint
 	 */
 	if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES &&
 	    (src->width * cpp < src->stride - 3 ||
@@ -826,7 +842,6 @@ _cairo_gl_surface_draw_image (cairo_gl_surface_t *dst,
 			 data_start_gles2 != NULL ? data_start_gles2 :
 						    data_start);
 
-
 	free (data_start_gles2);
 
 	/* If we just treated some rgb-only data as rgba, then we have to
@@ -834,21 +849,9 @@ _cairo_gl_surface_draw_image (cairo_gl_surface_t *dst,
 	 * texture data.
 	 */
 	if (!has_alpha) {
-	    cairo_rectangle_int_t rect;
-
-	    rect.x = dst_x;
-	    rect.y = dst_y;
-	    rect.width = width;
-	    rect.height = height;
-
-            _cairo_gl_composite_flush (ctx);
-	    glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE);
-	    _cairo_gl_surface_fill_rectangles (dst,
-					       CAIRO_OPERATOR_SOURCE,
-					       CAIRO_COLOR_BLACK,
-					       &rect, 1);
-            _cairo_gl_composite_flush (ctx);
-	    glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+	    _cairo_gl_surface_fill_alpha_channel (dst,
+						  dst_x, dst_y,
+						  width, height);
 	}
     } else {
         cairo_surface_t *tmp;
@@ -869,15 +872,10 @@ _cairo_gl_surface_draw_image (cairo_gl_surface_t *dst,
             cairo_surface_pattern_t tmp_pattern;
 
             _cairo_pattern_init_for_surface (&tmp_pattern, tmp);
-            _cairo_gl_surface_composite (CAIRO_OPERATOR_SOURCE,
-                                         &tmp_pattern.base,
-                                         NULL,
-                                         dst,
-                                         0, 0,
-                                         0, 0,
-                                         dst_x, dst_y,
-                                         width, height,
-                                         NULL);
+	    status = _cairo_surface_paint (&dst->base,
+					   CAIRO_OPERATOR_SOURCE,
+					   &tmp_pattern.base,
+					   NULL);
             _cairo_pattern_fini (&tmp_pattern.base);
         }
 
@@ -896,17 +894,53 @@ FAIL:
     return status;
 }
 
+static int _cairo_gl_surface_flavor (cairo_gl_surface_t *surface)
+{
+    cairo_gl_context_t *ctx = (cairo_gl_context_t *)surface->base.device;
+    return ctx->gl_flavor;
+}
+
 static cairo_status_t
-_cairo_gl_surface_get_image (cairo_gl_surface_t      *surface,
-			     cairo_rectangle_int_t   *interest,
-			     cairo_image_surface_t  **image_out,
-			     cairo_rectangle_int_t   *rect_out)
+_cairo_gl_surface_finish (void *abstract_surface)
 {
+    cairo_gl_surface_t *surface = abstract_surface;
+    cairo_status_t status;
+    cairo_gl_context_t *ctx;
+
+    status = _cairo_gl_context_acquire (surface->base.device, &ctx);
+    if (unlikely (status))
+        return status;
+
+    if (ctx->operands[CAIRO_GL_TEX_SOURCE].type == CAIRO_GL_OPERAND_TEXTURE &&
+        ctx->operands[CAIRO_GL_TEX_SOURCE].texture.surface == surface)
+        _cairo_gl_context_destroy_operand (ctx, CAIRO_GL_TEX_SOURCE);
+    if (ctx->operands[CAIRO_GL_TEX_MASK].type == CAIRO_GL_OPERAND_TEXTURE &&
+        ctx->operands[CAIRO_GL_TEX_MASK].texture.surface == surface)
+        _cairo_gl_context_destroy_operand (ctx, CAIRO_GL_TEX_MASK);
+    if (ctx->current_target == surface)
+	ctx->current_target = NULL;
+
+    if (surface->depth)
+        ctx->dispatch.DeleteFramebuffers (1, &surface->depth);
+    if (surface->fb)
+        ctx->dispatch.DeleteFramebuffers (1, &surface->fb);
+    if (surface->owns_tex)
+	glDeleteTextures (1, &surface->tex);
+
+    return _cairo_gl_context_release (ctx, status);
+}
+
+static cairo_surface_t *
+_cairo_gl_surface_map_to_image (void      *abstract_surface,
+				const cairo_rectangle_int_t   *extents)
+{
+    cairo_gl_surface_t *surface = abstract_surface;
     cairo_image_surface_t *image;
     cairo_gl_context_t *ctx;
     GLenum format, type;
     pixman_format_code_t pixman_format;
     unsigned int cpp;
+    cairo_bool_t invert;
     cairo_status_t status;
 
     /* Want to use a switch statement here but the compiler gets whiny. */
@@ -927,22 +961,18 @@ _cairo_gl_surface_get_image (cairo_gl_surface_t      *surface,
 	cpp = 1;
     } else {
 	ASSERT_NOT_REACHED;
-	return CAIRO_INT_STATUS_UNSUPPORTED;
+	return NULL;
     }
 
-    status = _cairo_gl_context_acquire (surface->base.device, &ctx);
-    if (unlikely (status))
-        return status;
-
     /*
      * GLES2 supports only RGBA, UNSIGNED_BYTE so use that.
      * We are also using this format for ALPHA as GLES2 does not
      * support GL_PACK_ROW_LENGTH anyway, and this makes sure that the
      * pixman image that is created has row_stride = row_width * bpp.
      */
-    if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES) {
+    if (_cairo_gl_surface_flavor (surface) == CAIRO_GL_FLAVOR_ES) {
 	format = GL_RGBA;
-	if (!_cairo_is_little_endian ()) {
+	if (! _cairo_is_little_endian ()) {
 	    if (surface->base.content == CAIRO_CONTENT_COLOR)
 		pixman_format = PIXMAN_r8g8b8x8;
 	    else
@@ -960,11 +990,20 @@ _cairo_gl_surface_get_image (cairo_gl_surface_t      *surface,
     image = (cairo_image_surface_t*)
 	_cairo_image_surface_create_with_pixman_format (NULL,
 							pixman_format,
-							interest->width,
-							interest->height,
+							extents->width,
+							extents->height,
 							-1);
     if (unlikely (image->base.status))
-	return _cairo_gl_context_release (ctx, image->base.status);
+	return &image->base;
+
+    if (surface->base.serial == 0)
+	return &image->base;
+
+    status = _cairo_gl_context_acquire (surface->base.device, &ctx);
+    if (unlikely (status)) {
+	cairo_surface_destroy (&image->base);
+	return _cairo_surface_create_in_error (status);
+    }
 
     /* This is inefficient, as we'd rather just read the thing without making
      * it the destination.  But then, this is the fallback path, so let's not
@@ -973,60 +1012,28 @@ _cairo_gl_surface_get_image (cairo_gl_surface_t      *surface,
     _cairo_gl_composite_flush (ctx);
     _cairo_gl_context_set_destination (ctx, surface);
 
+    invert = ! _cairo_gl_surface_is_texture (surface) &&
+	    ctx->has_mesa_pack_invert;
+
     glPixelStorei (GL_PACK_ALIGNMENT, 4);
     if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP)
 	glPixelStorei (GL_PACK_ROW_LENGTH, image->stride / cpp);
-    if (! _cairo_gl_surface_is_texture (surface) &&
-	ctx->has_mesa_pack_invert)
+    if (invert)
 	glPixelStorei (GL_PACK_INVERT_MESA, 1);
-    glReadPixels (interest->x, interest->y,
-		  interest->width, interest->height,
+    glReadPixels (extents->x, extents->y,
+		  extents->width, extents->height,
 		  format, type, image->data);
-    if (! _cairo_gl_surface_is_texture (surface) &&
-	ctx->has_mesa_pack_invert)
+    if (invert)
 	glPixelStorei (GL_PACK_INVERT_MESA, 0);
 
     status = _cairo_gl_context_release (ctx, status);
     if (unlikely (status)) {
 	cairo_surface_destroy (&image->base);
-	return status;
+	image = (cairo_image_surface_t *)
+	    _cairo_surface_create_in_error (status);
     }
 
-    *image_out = image;
-    if (rect_out != NULL)
-	*rect_out = *interest;
-
-    return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_gl_surface_finish (void *abstract_surface)
-{
-    cairo_gl_surface_t *surface = abstract_surface;
-    cairo_status_t status;
-    cairo_gl_context_t *ctx;
-
-    status = _cairo_gl_context_acquire (surface->base.device, &ctx);
-    if (unlikely (status))
-        return status;
-
-    if (ctx->operands[CAIRO_GL_TEX_SOURCE].type == CAIRO_GL_OPERAND_TEXTURE &&
-        ctx->operands[CAIRO_GL_TEX_SOURCE].texture.surface == surface)
-        _cairo_gl_context_destroy_operand (ctx, CAIRO_GL_TEX_SOURCE);
-    if (ctx->operands[CAIRO_GL_TEX_MASK].type == CAIRO_GL_OPERAND_TEXTURE &&
-        ctx->operands[CAIRO_GL_TEX_MASK].texture.surface == surface)
-        _cairo_gl_context_destroy_operand (ctx, CAIRO_GL_TEX_MASK);
-    if (ctx->current_target == surface)
-	ctx->current_target = NULL;
-
-    if (surface->depth)
-        ctx->dispatch.DeleteFramebuffers (1, &surface->depth);
-    if (surface->fb)
-        ctx->dispatch.DeleteFramebuffers (1, &surface->fb);
-    if (surface->owns_tex)
-	glDeleteTextures (1, &surface->tex);
-
-    return _cairo_gl_context_release (ctx, status);
+    return &image->base;
 }
 
 static cairo_status_t
@@ -1042,7 +1049,10 @@ _cairo_gl_surface_acquire_source_image (void		       *abstract_surface,
     extents.x = extents.y = 0;
     extents.width = surface->width;
     extents.height = surface->height;
-    return _cairo_gl_surface_get_image (surface, &extents, image_out, NULL);
+
+    *image_out = (cairo_image_surface_t *)
+	_cairo_gl_surface_map_to_image (surface, &extents);
+    return (*image_out)->base.status;
 }
 
 static void
@@ -1053,536 +1063,18 @@ _cairo_gl_surface_release_source_image (void		      *abstract_surface,
     cairo_surface_destroy (&image->base);
 }
 
-static cairo_status_t
-_cairo_gl_surface_acquire_dest_image (void		      *abstract_surface,
-				      cairo_rectangle_int_t   *interest_rect,
-				      cairo_image_surface_t  **image_out,
-				      cairo_rectangle_int_t   *image_rect_out,
-				      void		     **image_extra)
-{
-    cairo_gl_surface_t *surface = abstract_surface;
-
-    *image_extra = NULL;
-    return _cairo_gl_surface_get_image (surface, interest_rect, image_out,
-					image_rect_out);
-}
-
-static void
-_cairo_gl_surface_release_dest_image (void		      *abstract_surface,
-				      cairo_rectangle_int_t   *interest_rect,
-				      cairo_image_surface_t   *image,
-				      cairo_rectangle_int_t   *image_rect,
-				      void		      *image_extra)
-{
-    cairo_status_t status;
-
-    status = _cairo_gl_surface_draw_image (abstract_surface, image,
-					   0, 0,
-					   image->width, image->height,
-					   image_rect->x, image_rect->y);
-    /* as we created the image, its format should be directly applicable */
-    assert (status == CAIRO_STATUS_SUCCESS);
-
-    cairo_surface_destroy (&image->base);
-}
-
-static cairo_status_t
-_cairo_gl_surface_clone_similar (void		     *abstract_surface,
-				 cairo_surface_t     *src,
-				 int                  src_x,
-				 int                  src_y,
-				 int                  width,
-				 int                  height,
-				 int                 *clone_offset_x,
-				 int                 *clone_offset_y,
-				 cairo_surface_t    **clone_out)
-{
-    cairo_gl_surface_t *surface = abstract_surface;
-
-    /* XXX: Use GLCopyTexImage2D to clone non-texture-surfaces */
-    if (src->device == surface->base.device &&
-        _cairo_gl_surface_is_texture ((cairo_gl_surface_t *) src)) {
-	*clone_offset_x = 0;
-	*clone_offset_y = 0;
-	*clone_out = cairo_surface_reference (src);
-
-	return CAIRO_STATUS_SUCCESS;
-    } else if (_cairo_surface_is_image (src)) {
-	cairo_image_surface_t *image_src = (cairo_image_surface_t *)src;
-	cairo_gl_surface_t *clone;
-	cairo_status_t status;
-
-	clone = (cairo_gl_surface_t *)
-	    _cairo_gl_surface_create_similar (&surface->base,
-		                              src->content,
-					      width, height);
-	if (clone == NULL)
-	    return UNSUPPORTED ("create_similar failed");
-	if (clone->base.status)
-	    return clone->base.status;
-
-	status = _cairo_gl_surface_draw_image (clone, image_src,
-					       src_x, src_y,
-					       width, height,
-					       0, 0);
-	if (status) {
-	    cairo_surface_destroy (&clone->base);
-	    return status;
-	}
-
-	*clone_out = &clone->base;
-	*clone_offset_x = src_x;
-	*clone_offset_y = src_y;
-
-	return CAIRO_STATUS_SUCCESS;
-    }
-
-    return UNSUPPORTED ("unknown src surface type in clone_similar");
-}
-
-/** Creates a cairo-gl pattern surface for the given trapezoids */
-static cairo_status_t
-_cairo_gl_get_traps_pattern (cairo_gl_surface_t *dst,
-			     int dst_x, int dst_y,
-			     int width, int height,
-			     cairo_trapezoid_t *traps,
-			     int num_traps,
-			     cairo_antialias_t antialias,
-			     cairo_surface_pattern_t *pattern)
-{
-    pixman_format_code_t pixman_format;
-    pixman_image_t *image;
-    cairo_surface_t *surface;
-    int i;
-
-    pixman_format = antialias != CAIRO_ANTIALIAS_NONE ? PIXMAN_a8 : PIXMAN_a1,
-    image = pixman_image_create_bits (pixman_format, width, height, NULL, 0);
-    if (unlikely (image == NULL))
-	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
-    for (i = 0; i < num_traps; i++) {
-	pixman_trapezoid_t trap;
-
-	trap.top = _cairo_fixed_to_16_16 (traps[i].top);
-	trap.bottom = _cairo_fixed_to_16_16 (traps[i].bottom);
-
-	trap.left.p1.x = _cairo_fixed_to_16_16 (traps[i].left.p1.x);
-	trap.left.p1.y = _cairo_fixed_to_16_16 (traps[i].left.p1.y);
-	trap.left.p2.x = _cairo_fixed_to_16_16 (traps[i].left.p2.x);
-	trap.left.p2.y = _cairo_fixed_to_16_16 (traps[i].left.p2.y);
-
-	trap.right.p1.x = _cairo_fixed_to_16_16 (traps[i].right.p1.x);
-	trap.right.p1.y = _cairo_fixed_to_16_16 (traps[i].right.p1.y);
-	trap.right.p2.x = _cairo_fixed_to_16_16 (traps[i].right.p2.x);
-	trap.right.p2.y = _cairo_fixed_to_16_16 (traps[i].right.p2.y);
-
-	pixman_rasterize_trapezoid (image, &trap, -dst_x, -dst_y);
-    }
-
-    surface = _cairo_image_surface_create_for_pixman_image (image,
-							    pixman_format);
-    if (unlikely (surface->status)) {
-	pixman_image_unref (image);
-	return surface->status;
-    }
-
-    _cairo_pattern_init_for_surface (pattern, surface);
-    cairo_surface_destroy (surface);
-
-    return CAIRO_STATUS_SUCCESS;
-}
-
 static cairo_int_status_t
-_cairo_gl_surface_composite (cairo_operator_t		  op,
-			     const cairo_pattern_t	 *src,
-			     const cairo_pattern_t	 *mask,
-			     void			 *abstract_dst,
-			     int			  src_x,
-			     int			  src_y,
-			     int			  mask_x,
-			     int			  mask_y,
-			     int			  dst_x,
-			     int			  dst_y,
-			     unsigned int		  width,
-			     unsigned int		  height,
-			     cairo_region_t		 *clip_region)
+_cairo_gl_surface_unmap_image (void		      *abstract_surface,
+			       cairo_image_surface_t *image)
 {
-    cairo_gl_surface_t *dst = abstract_dst;
-    cairo_gl_context_t *ctx;
-    cairo_int_status_t status;
-    cairo_gl_composite_t setup;
-    cairo_rectangle_int_t rect = { dst_x, dst_y, width, height };
-    int dx, dy;
-
-    if (op == CAIRO_OPERATOR_SOURCE &&
-        mask == NULL &&
-        src->type == CAIRO_PATTERN_TYPE_SURFACE &&
-        _cairo_surface_is_image (((cairo_surface_pattern_t *) src)->surface) &&
-        _cairo_matrix_is_integer_translation (&src->matrix, &dx, &dy)) {
-        cairo_image_surface_t *image = (cairo_image_surface_t *)
-            ((cairo_surface_pattern_t *) src)->surface;
-        dx += src_x;
-        dy += src_y;
-        if (dx >= 0 &&
-            dy >= 0 &&
-            dx + width <= (unsigned int) image->width &&
-            dy + height <= (unsigned int) image->height) {
-            status = _cairo_gl_surface_draw_image (dst, image,
-                                                   dx, dy,
-                                                   width, height,
-                                                   dst_x, dst_y);
-            if (status != CAIRO_INT_STATUS_UNSUPPORTED)
-                return status;
-        }
-    }
-
-    status = _cairo_gl_composite_init (&setup, op, dst,
-                                       mask && mask->has_component_alpha,
-                                       &rect);
-    if (unlikely (status))
-        goto CLEANUP;
-
-    status = _cairo_gl_composite_set_source (&setup, src,
-                                             src_x, src_y,
-                                             dst_x, dst_y,
-                                             width, height);
-    if (unlikely (status))
-        goto CLEANUP;
-
-    status = _cairo_gl_composite_set_mask (&setup, mask,
-                                           mask_x, mask_y,
-                                           dst_x, dst_y,
-                                           width, height);
-    if (unlikely (status))
-        goto CLEANUP;
-
-    status = _cairo_gl_composite_begin (&setup, &ctx);
-    if (unlikely (status))
-	goto CLEANUP;
-
-    if (clip_region != NULL) {
-        int i, num_rectangles;
-
-        num_rectangles = cairo_region_num_rectangles (clip_region);
-
-	for (i = 0; i < num_rectangles; i++) {
-	    cairo_rectangle_int_t rect;
-
-	    cairo_region_get_rectangle (clip_region, i, &rect);
-            _cairo_gl_composite_emit_rect (ctx,
-                                           rect.x,              rect.y,
-                                           rect.x + rect.width, rect.y + rect.height,
-                                           0);
-	}
-    } else {
-        _cairo_gl_composite_emit_rect (ctx,
-                                       dst_x,         dst_y,
-                                       dst_x + width, dst_y + height,
-                                       0);
-    }
-
-    status = _cairo_gl_context_release (ctx, status);
-
-  CLEANUP:
-    _cairo_gl_composite_fini (&setup);
-
-    return status;
-}
-
-static cairo_int_status_t
-_cairo_gl_surface_composite_trapezoids (cairo_operator_t op,
-					const cairo_pattern_t *pattern,
-					void *abstract_dst,
-					cairo_antialias_t antialias,
-					int src_x, int src_y,
-					int dst_x, int dst_y,
-					unsigned int width,
-					unsigned int height,
-					cairo_trapezoid_t *traps,
-					int num_traps,
-					cairo_region_t *clip_region)
-{
-    cairo_gl_surface_t *dst = abstract_dst;
-    cairo_surface_pattern_t traps_pattern;
-    cairo_int_status_t status;
-
-    if (! _cairo_gl_operator_is_supported (op))
-	return UNSUPPORTED ("unsupported operator");
-
-    status = _cairo_gl_get_traps_pattern (dst,
-					  dst_x, dst_y, width, height,
-					  traps, num_traps, antialias,
-					  &traps_pattern);
-    if (unlikely (status))
-	return status;
-
-    status = _cairo_gl_surface_composite (op,
-					  pattern, &traps_pattern.base, dst,
-					  src_x, src_y,
-					  0, 0,
-					  dst_x, dst_y,
-					  width, height,
-					  clip_region);
-
-    _cairo_pattern_fini (&traps_pattern.base);
-
-    assert (status != CAIRO_INT_STATUS_UNSUPPORTED);
-    return status;
-}
-
-static cairo_int_status_t
-_cairo_gl_surface_fill_rectangles (void			   *abstract_dst,
-				   cairo_operator_t	    op,
-				   const cairo_color_t     *color,
-				   cairo_rectangle_int_t   *rects,
-				   int			    num_rects)
-{
-    cairo_gl_surface_t *dst = abstract_dst;
-    cairo_solid_pattern_t solid;
-    cairo_gl_context_t *ctx;
-    cairo_status_t status;
-    cairo_gl_composite_t setup;
-    int i;
-
-    status = _cairo_gl_composite_init (&setup, op, dst,
-                                       FALSE,
-                                       /* XXX */ NULL);
-    if (unlikely (status))
-        goto CLEANUP;
-
-    _cairo_pattern_init_solid (&solid, color);
-    status = _cairo_gl_composite_set_source (&setup, &solid.base,
-                                             0, 0,
-                                             0, 0,
-                                             0, 0);
-    if (unlikely (status))
-        goto CLEANUP;
-
-    status = _cairo_gl_composite_set_mask (&setup, NULL,
-                                           0, 0,
-                                           0, 0,
-                                           0, 0);
-    if (unlikely (status))
-        goto CLEANUP;
-
-    status = _cairo_gl_composite_begin (&setup, &ctx);
-    if (unlikely (status))
-        goto CLEANUP;
-
-    for (i = 0; i < num_rects; i++) {
-        _cairo_gl_composite_emit_rect (ctx,
-                                       rects[i].x,
-                                       rects[i].y,
-                                       rects[i].x + rects[i].width,
-                                       rects[i].y + rects[i].height,
-                                       0);
-    }
-
-    status = _cairo_gl_context_release (ctx, status);
-
-  CLEANUP:
-    _cairo_gl_composite_fini (&setup);
-
-    return status;
-}
-
-typedef struct _cairo_gl_surface_span_renderer {
-    cairo_span_renderer_t base;
-
-    cairo_gl_composite_t setup;
-
-    int xmin, xmax;
-    int ymin, ymax;
-
-    cairo_gl_context_t *ctx;
-} cairo_gl_surface_span_renderer_t;
-
-static cairo_status_t
-_cairo_gl_render_bounded_spans (void *abstract_renderer,
-				int y, int height,
-				const cairo_half_open_span_t *spans,
-				unsigned num_spans)
-{
-    cairo_gl_surface_span_renderer_t *renderer = abstract_renderer;
-
-    if (num_spans == 0)
-	return CAIRO_STATUS_SUCCESS;
-
-    do {
-	if (spans[0].coverage) {
-            _cairo_gl_composite_emit_rect (renderer->ctx,
-                                           spans[0].x, y,
-                                           spans[1].x, y + height,
-                                           spans[0].coverage);
-	}
-
-	spans++;
-    } while (--num_spans > 1);
-
-    return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_gl_render_unbounded_spans (void *abstract_renderer,
-				  int y, int height,
-				  const cairo_half_open_span_t *spans,
-				  unsigned num_spans)
-{
-    cairo_gl_surface_span_renderer_t *renderer = abstract_renderer;
-
-    if (y > renderer->ymin) {
-        _cairo_gl_composite_emit_rect (renderer->ctx,
-                                       renderer->xmin, renderer->ymin,
-                                       renderer->xmax, y,
-                                       0);
-    }
-
-    if (num_spans == 0) {
-        _cairo_gl_composite_emit_rect (renderer->ctx,
-                                       renderer->xmin, y,
-                                       renderer->xmax, y + height,
-                                       0);
-    } else {
-        if (spans[0].x != renderer->xmin) {
-            _cairo_gl_composite_emit_rect (renderer->ctx,
-                                           renderer->xmin, y,
-                                           spans[0].x,     y + height,
-                                           0);
-        }
-
-        do {
-            _cairo_gl_composite_emit_rect (renderer->ctx,
-                                           spans[0].x, y,
-                                           spans[1].x, y + height,
-                                           spans[0].coverage);
-            spans++;
-        } while (--num_spans > 1);
-
-        if (spans[0].x != renderer->xmax) {
-            _cairo_gl_composite_emit_rect (renderer->ctx,
-                                           spans[0].x,     y,
-                                           renderer->xmax, y + height,
-                                           0);
-        }
-    }
-
-    renderer->ymin = y + height;
-    return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_gl_finish_unbounded_spans (void *abstract_renderer)
-{
-    cairo_gl_surface_span_renderer_t *renderer = abstract_renderer;
-
-    if (renderer->ymax > renderer->ymin) {
-        _cairo_gl_composite_emit_rect (renderer->ctx,
-                                       renderer->xmin, renderer->ymin,
-                                       renderer->xmax, renderer->ymax,
-                                       0);
-    }
-
-    return _cairo_gl_context_release (renderer->ctx, CAIRO_STATUS_SUCCESS);
-}
-
-static cairo_status_t
-_cairo_gl_finish_bounded_spans (void *abstract_renderer)
-{
-    cairo_gl_surface_span_renderer_t *renderer = abstract_renderer;
-
-    return _cairo_gl_context_release (renderer->ctx, CAIRO_STATUS_SUCCESS);
-}
-
-static void
-_cairo_gl_surface_span_renderer_destroy (void *abstract_renderer)
-{
-    cairo_gl_surface_span_renderer_t *renderer = abstract_renderer;
-
-    if (!renderer)
-	return;
-
-    _cairo_gl_composite_fini (&renderer->setup);
-
-    free (renderer);
+    return _cairo_gl_surface_draw_image (abstract_surface, image,
+					 0, 0,
+					 image->width, image->height,
+					 image->base.device_transform_inverse.x0,
+					 image->base.device_transform_inverse.y0);
 }
 
 static cairo_bool_t
-_cairo_gl_surface_check_span_renderer (cairo_operator_t	       op,
-				       const cairo_pattern_t  *pattern,
-				       void		      *abstract_dst,
-				       cairo_antialias_t       antialias)
-{
-    if (! _cairo_gl_operator_is_supported (op))
-	return FALSE;
-
-    return TRUE;
-
-    (void) pattern;
-    (void) abstract_dst;
-    (void) antialias;
-}
-
-static cairo_span_renderer_t *
-_cairo_gl_surface_create_span_renderer (cairo_operator_t	 op,
-					const cairo_pattern_t	*src,
-					void			*abstract_dst,
-					cairo_antialias_t	 antialias,
-					const cairo_composite_rectangles_t *rects,
-					cairo_region_t		*clip_region)
-{
-    cairo_gl_surface_t *dst = abstract_dst;
-    cairo_gl_surface_span_renderer_t *renderer;
-    cairo_status_t status;
-    const cairo_rectangle_int_t *extents;
-
-    renderer = calloc (1, sizeof (*renderer));
-    if (unlikely (renderer == NULL))
-	return _cairo_span_renderer_create_in_error (CAIRO_STATUS_NO_MEMORY);
-
-    renderer->base.destroy = _cairo_gl_surface_span_renderer_destroy;
-    if (rects->is_bounded) {
-	renderer->base.render_rows = _cairo_gl_render_bounded_spans;
-        renderer->base.finish =      _cairo_gl_finish_bounded_spans;
-	extents = &rects->bounded;
-    } else {
-	renderer->base.render_rows = _cairo_gl_render_unbounded_spans;
-        renderer->base.finish =      _cairo_gl_finish_unbounded_spans;
-	extents = &rects->unbounded;
-    }
-    renderer->xmin = extents->x;
-    renderer->xmax = extents->x + extents->width;
-    renderer->ymin = extents->y;
-    renderer->ymax = extents->y + extents->height;
-
-    status = _cairo_gl_composite_init (&renderer->setup,
-                                       op, dst,
-                                       FALSE, extents);
-    if (unlikely (status))
-        goto FAIL;
-
-    status = _cairo_gl_composite_set_source (&renderer->setup, src,
-                                             extents->x, extents->y,
-                                             extents->x, extents->y,
-                                             extents->width, extents->height);
-    if (unlikely (status))
-        goto FAIL;
-
-    _cairo_gl_composite_set_mask_spans (&renderer->setup);
-    _cairo_gl_composite_set_clip_region (&renderer->setup, clip_region);
-
-    status = _cairo_gl_composite_begin (&renderer->setup, &renderer->ctx);
-    if (unlikely (status))
-        goto FAIL;
-
-    return &renderer->base;
-
-FAIL:
-    _cairo_gl_composite_fini (&renderer->setup);
-    free (renderer);
-    return _cairo_span_renderer_create_in_error (status);
-}
-
-cairo_bool_t
 _cairo_gl_surface_get_extents (void		     *abstract_surface,
 			       cairo_rectangle_int_t *rectangle)
 {
@@ -1596,16 +1088,6 @@ _cairo_gl_surface_get_extents (void		     *abstract_surface,
     return TRUE;
 }
 
-static void
-_cairo_gl_surface_get_font_options (void                  *abstract_surface,
-				    cairo_font_options_t  *options)
-{
-    _cairo_font_options_init_default (options);
-
-    cairo_font_options_set_hint_metrics (options, CAIRO_HINT_METRICS_ON);
-    _cairo_font_options_set_round_glyph_positions (options, CAIRO_ROUND_GLYPH_POS_ON);
-}
-
 static cairo_status_t
 _cairo_gl_surface_flush (void *abstract_surface)
 {
@@ -1627,18 +1109,20 @@ _cairo_gl_surface_flush (void *abstract_surface)
     return _cairo_gl_context_release (ctx, status);
 }
 
+static const cairo_compositor_t *
+get_compositor (cairo_gl_surface_t *surface)
+{
+    cairo_gl_context_t *ctx = (cairo_gl_context_t *)surface->base.device;
+    return ctx->compositor;
+}
+
 static cairo_int_status_t
-_cairo_gl_surface_paint (void *abstract_surface,
+_cairo_gl_surface_paint (void			*surface,
 			 cairo_operator_t	 op,
-			 const cairo_pattern_t *source,
-			 const cairo_clip_t    *clip)
+			 const cairo_pattern_t	*source,
+			 const cairo_clip_t	*clip)
 {
-    cairo_gl_surface_t *surface = abstract_surface;
-    cairo_composite_rectangles_t extents;
-    cairo_rectangle_int_t unbounded;
-    cairo_boxes_t boxes;
-    cairo_status_t status;
-
+#if 0
     /* simplify the common case of clearing the surface */
     if (clip == NULL) {
         if (op == CAIRO_OPERATOR_CLEAR)
@@ -1650,93 +1134,43 @@ _cairo_gl_surface_paint (void *abstract_surface,
                                             &((cairo_solid_pattern_t *) source)->color);
         }
     }
+#endif
 
-    _cairo_gl_surface_get_extents (surface, &unbounded);
-    status = _cairo_composite_rectangles_init_for_paint (&extents, &unbounded,
-							 op, source,
-							 clip);
-    if (unlikely (status))
-	return status;
-
-    status = _cairo_clip_to_boxes(extents.clip, &boxes);
-    if (likely (status == CAIRO_STATUS_SUCCESS)) {
-	status = _cairo_gl_clip_and_composite_boxes (surface, op, source,
-						     &boxes, &extents);
-    }
-
-    _cairo_composite_rectangles_fini (&extents);
+    return _cairo_compositor_paint (get_compositor (surface), surface,
+				    op, source, clip);
+}
 
-    return status;
+static cairo_int_status_t
+_cairo_gl_surface_mask (void			 *surface,
+			cairo_operator_t	  op,
+			const cairo_pattern_t	*source,
+			const cairo_pattern_t	*mask,
+			const cairo_clip_t	*clip)
+{
+    return _cairo_compositor_mask (get_compositor (surface), surface,
+				   op, source, mask, clip);
 }
 
 static cairo_int_status_t
-_cairo_gl_surface_stroke (void			        *abstract_surface,
+_cairo_gl_surface_stroke (void			        *surface,
                           cairo_operator_t		 op,
                           const cairo_pattern_t	        *source,
-                          const cairo_path_fixed_t		*path,
+                          const cairo_path_fixed_t	*path,
                           const cairo_stroke_style_t	*style,
                           const cairo_matrix_t	        *ctm,
                           const cairo_matrix_t	        *ctm_inverse,
                           double			 tolerance,
                           cairo_antialias_t		 antialias,
-                          const cairo_clip_t		        *clip)
+                          const cairo_clip_t		*clip)
 {
-    cairo_gl_surface_t *surface = abstract_surface;
-    cairo_composite_rectangles_t extents;
-    cairo_rectangle_int_t unbounded;
-    cairo_int_status_t status;
-
-    _cairo_gl_surface_get_extents (surface, &unbounded);
-    status = _cairo_composite_rectangles_init_for_stroke (&extents,
-							  &unbounded,
-							  op, source,
-							  path, style, ctm,
-							  clip);
-    if (unlikely (status))
-	return status;
-
-    status = CAIRO_INT_STATUS_UNSUPPORTED;
-    if (_cairo_path_fixed_stroke_is_rectilinear (path)) {
-	cairo_boxes_t boxes;
-
-	_cairo_boxes_init_with_clip (&boxes, extents.clip);
-	status = _cairo_path_fixed_stroke_rectilinear_to_boxes (path,
-								style,
-								ctm,
-								antialias,
-								&boxes);
-	if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
-	    status = _cairo_gl_clip_and_composite_boxes (surface, op, source,
-							 &boxes, &extents);
-	}
-	_cairo_boxes_fini (&boxes);
-    }
-
-
-    if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
-	cairo_polygon_t polygon;
-
-	_cairo_polygon_init_with_clip (&polygon, extents.clip);
-	status = _cairo_path_fixed_stroke_to_polygon (path,
-						      style,
-						      ctm, ctm_inverse,
-						      tolerance,
-						      &polygon);
-	if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
-	    status = _cairo_gl_surface_polygon (surface, op, source, &polygon,
-						CAIRO_FILL_RULE_WINDING, antialias,
-						&extents);
-	}
-	_cairo_polygon_fini (&polygon);
-    }
-
-    _cairo_composite_rectangles_fini (&extents);
-
-    return status;
+    return _cairo_compositor_stroke (get_compositor (surface), surface,
+				     op, source, path, style,
+				     ctm, ctm_inverse, tolerance, antialias,
+				     clip);
 }
 
 static cairo_int_status_t
-_cairo_gl_surface_fill (void			*abstract_surface,
+_cairo_gl_surface_fill (void			*surface,
                         cairo_operator_t	 op,
                         const cairo_pattern_t	*source,
                         const cairo_path_fixed_t*path,
@@ -1745,51 +1179,24 @@ _cairo_gl_surface_fill (void			*abstract_surface,
                         cairo_antialias_t	 antialias,
                         const cairo_clip_t	*clip)
 {
-    cairo_gl_surface_t *surface = abstract_surface;
-    cairo_composite_rectangles_t extents;
-    cairo_rectangle_int_t unbounded;
-    cairo_int_status_t status;
-
-    _cairo_gl_surface_get_extents (surface, &unbounded);
-    status = _cairo_composite_rectangles_init_for_fill (&extents,
-							&unbounded,
-							op, source, path,
-							clip);
-    if (unlikely (status))
-	return status;
-
-    status = CAIRO_INT_STATUS_UNSUPPORTED;
-    if (_cairo_path_fixed_fill_is_rectilinear (path)) {
-	cairo_boxes_t boxes;
-
-	_cairo_boxes_init_with_clip (&boxes, extents.clip);
-	status = _cairo_path_fixed_fill_rectilinear_to_boxes (path,
-							      fill_rule,
-							      antialias,
-							      &boxes);
-	if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
-	    status = _cairo_gl_clip_and_composite_boxes (surface, op, source,
-							 &boxes, &extents);
-	}
-	_cairo_boxes_fini (&boxes);
-    }
-
-    if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
-	cairo_polygon_t polygon;
-
-	_cairo_polygon_init_with_clip (&polygon, extents.clip);
-	status = _cairo_path_fixed_fill_to_polygon (path, tolerance, &polygon);
-	if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
-	    status = _cairo_gl_surface_polygon (surface, op, source, &polygon,
-						fill_rule, antialias,
-						&extents);
-	}
-	_cairo_polygon_fini (&polygon);
-    }
-
-    _cairo_composite_rectangles_fini (&extents);
+    return _cairo_compositor_fill (get_compositor (surface), surface,
+				   op, source, path,
+				   fill_rule, tolerance, antialias,
+				   clip);
+}
 
-    return status;
+static cairo_int_status_t
+_cairo_gl_surface_glyphs (void			*surface,
+			  cairo_operator_t	 op,
+			  const cairo_pattern_t	*source,
+			  cairo_glyph_t		*glyphs,
+			  int			 num_glyphs,
+			  cairo_scaled_font_t	*font,
+			  const cairo_clip_t	*clip)
+{
+    return _cairo_compositor_glyphs (get_compositor (surface), surface,
+				     op, source, glyphs, num_glyphs, font,
+				     clip);
 }
 
 const cairo_surface_backend_t _cairo_gl_surface_backend = {
@@ -1799,34 +1206,26 @@ const cairo_surface_backend_t _cairo_gl_surface_backend = {
 
     _cairo_gl_surface_create_similar,
     NULL, /* similar image */
-    NULL, /* map to image */
-    NULL, /* unmap image */
+    _cairo_gl_surface_map_to_image,
+    _cairo_gl_surface_unmap_image,
 
     _cairo_gl_surface_acquire_source_image,
     _cairo_gl_surface_release_source_image,
-    _cairo_gl_surface_acquire_dest_image,
-    _cairo_gl_surface_release_dest_image,
-
-    _cairo_gl_surface_clone_similar,
-    _cairo_gl_surface_composite,
-    _cairo_gl_surface_fill_rectangles,
-    _cairo_gl_surface_composite_trapezoids,
-    _cairo_gl_surface_create_span_renderer,
-    _cairo_gl_surface_check_span_renderer,
+    NULL, /* snapshot */
 
     NULL, /* copy_page */
     NULL, /* show_page */
+
     _cairo_gl_surface_get_extents,
-    NULL, /* old_show_glyphs */
-    _cairo_gl_surface_get_font_options,
+    _cairo_image_surface_get_font_options,
+
     _cairo_gl_surface_flush,
     NULL, /* mark_dirty_rectangle */
-    _cairo_gl_surface_scaled_font_fini,
-    _cairo_gl_surface_scaled_glyph_fini,
+
     _cairo_gl_surface_paint,
-    NULL, /* mask */
+    _cairo_gl_surface_mask,
     _cairo_gl_surface_stroke,
     _cairo_gl_surface_fill,
-    _cairo_gl_surface_show_glyphs, /* show_glyphs */
-    NULL  /* snapshot */
+    NULL, /* fill/stroke */
+    _cairo_gl_surface_glyphs,
 };
diff --git a/src/cairo-gl-traps-compositor.c b/src/cairo-gl-traps-compositor.c
new file mode 100644
index 0000000..afc74d0
--- /dev/null
+++ b/src/cairo-gl-traps-compositor.c
@@ -0,0 +1,550 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2009 Eric Anholt
+ * Copyright © 2009 Chris Wilson
+ * Copyright © 2005,2010 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 Red Hat, Inc.
+ *
+ * Contributor(s):
+ *	Benjamin Otte <otte at gnome.org>
+ *	Carl Worth <cworth at cworth.org>
+ *	Chris Wilson <chris at chris-wilson.co.uk>
+ *	Eric Anholt <eric at anholt.net>
+ */
+
+#include "cairoint.h"
+
+#include "cairo-gl-private.h"
+
+#include "cairo-composite-rectangles-private.h"
+#include "cairo-compositor-private.h"
+#include "cairo-default-context-private.h"
+#include "cairo-error-private.h"
+#include "cairo-image-surface-private.h"
+#include "cairo-spans-compositor-private.h"
+#include "cairo-surface-backend-private.h"
+
+static cairo_int_status_t
+acquire (void *abstract_dst)
+{
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+release (void *abstract_dst)
+{
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+set_clip_region (void *_surface,
+		 cairo_region_t *region)
+{
+    cairo_gl_surface_t *surface = _surface;
+
+    //surface->clip_region = region;
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+draw_image_boxes (void *_dst,
+		  cairo_image_surface_t *image,
+		  cairo_boxes_t *boxes,
+		  int dx, int dy)
+{
+    cairo_gl_surface_t *dst = _dst;
+    struct _cairo_boxes_chunk *chunk;
+    int i;
+
+    for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
+	for (i = 0; i < chunk->count; i++) {
+	    cairo_box_t *b = &chunk->base[i];
+	    int x = _cairo_fixed_integer_part (b->p1.x);
+	    int y = _cairo_fixed_integer_part (b->p1.y);
+	    int w = _cairo_fixed_integer_part (b->p2.x) - x;
+	    int h = _cairo_fixed_integer_part (b->p2.y) - y;
+	    cairo_status_t status;
+
+	    status = _cairo_gl_surface_draw_image (dst, image,
+						   x + dx, y + dy,
+						   w, h,
+						   x, y);
+	    if (unlikely (status))
+		return status;
+	}
+    }
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static void
+emit_aligned_boxes (cairo_gl_context_t *ctx,
+		    const cairo_boxes_t *boxes)
+{
+    const struct _cairo_boxes_chunk *chunk;
+    int i;
+
+    for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
+	for (i = 0; i < chunk->count; i++) {
+	    int x1 = _cairo_fixed_integer_part (chunk->base[i].p1.x);
+	    int y1 = _cairo_fixed_integer_part (chunk->base[i].p1.y);
+	    int x2 = _cairo_fixed_integer_part (chunk->base[i].p2.x);
+	    int y2 = _cairo_fixed_integer_part (chunk->base[i].p2.y);
+	    _cairo_gl_composite_emit_rect (ctx, x1, y1, x2, y2, 0);
+	}
+    }
+}
+
+static cairo_int_status_t
+fill_boxes (void		*_dst,
+	    cairo_operator_t	 op,
+	    const cairo_color_t	*color,
+	    cairo_boxes_t	*boxes)
+{
+    cairo_gl_composite_t setup;
+    cairo_gl_context_t *ctx;
+    cairo_int_status_t status;
+
+    status = _cairo_gl_composite_init (&setup, op, _dst, FALSE, NULL);
+    if (unlikely (status))
+        goto FAIL;
+
+   _cairo_gl_composite_set_solid_source (&setup, color);
+
+    status = _cairo_gl_composite_begin (&setup, &ctx);
+    if (unlikely (status))
+        goto FAIL;
+
+    emit_aligned_boxes (ctx, boxes);
+    status = _cairo_gl_context_release (ctx, CAIRO_STATUS_SUCCESS);
+
+FAIL:
+    _cairo_gl_composite_fini (&setup);
+    return status;
+}
+
+typedef struct cairo_gl_source {
+    cairo_surface_t base;
+
+    cairo_gl_operand_t operand;
+} cairo_gl_source_t;
+
+static cairo_status_t
+_cairo_gl_source_finish (void *abstract_surface)
+{
+    cairo_gl_source_t *source = abstract_surface;
+
+    _cairo_gl_operand_destroy (&source->operand);
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static const cairo_surface_backend_t cairo_gl_source_backend = {
+    CAIRO_SURFACE_TYPE_GL,
+    _cairo_gl_source_finish,
+    NULL, /* read-only wrapper */
+};
+
+static cairo_surface_t *
+pattern_to_surface (cairo_surface_t *dst,
+		    const cairo_pattern_t *pattern,
+		    cairo_bool_t is_mask,
+		    const cairo_rectangle_int_t *extents,
+		    const cairo_rectangle_int_t *sample,
+		    int *src_x, int *src_y)
+{
+    cairo_gl_source_t *source;
+    cairo_int_status_t status;
+
+    source = malloc (sizeof (*source));
+    if (unlikely (source == NULL))
+	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
+
+    _cairo_surface_init (&source->base,
+			 &cairo_gl_source_backend,
+			 NULL, /* device */
+			 CAIRO_CONTENT_COLOR_ALPHA);
+
+    *src_x = *src_y = 0;
+    status = _cairo_gl_operand_init (&source->operand, pattern, (cairo_gl_surface_t *)dst,
+				     extents->x, extents->y,
+				     extents->x, extents->y,
+				     extents->width, extents->height);
+    if (unlikely (status)) {
+	cairo_surface_destroy (&source->base);
+	return _cairo_surface_create_in_error (status);
+    }
+
+    return &source->base;
+}
+
+static inline cairo_gl_operand_t *
+source_to_operand (cairo_surface_t *surface)
+{
+    cairo_gl_source_t *source = (cairo_gl_source_t *)surface;
+    return &source->operand;
+}
+
+static cairo_int_status_t
+composite_boxes (void			*_dst,
+		 cairo_operator_t	op,
+		 cairo_surface_t	*abstract_src,
+		 cairo_surface_t	*abstract_mask,
+		 int			src_x,
+		 int			src_y,
+		 int			mask_x,
+		 int			mask_y,
+		 int			dst_x,
+		 int			dst_y,
+		 cairo_boxes_t		*boxes,
+		 const cairo_rectangle_int_t  *extents)
+{
+    cairo_gl_composite_t setup;
+    cairo_gl_context_t *ctx;
+    cairo_int_status_t status;
+
+    status = _cairo_gl_composite_init (&setup, op, _dst, FALSE, extents);
+    if (unlikely (status))
+        goto FAIL;
+
+    _cairo_gl_composite_set_source_operand (&setup,
+					    source_to_operand (abstract_src));
+
+    _cairo_gl_composite_set_mask_operand (&setup,
+					  source_to_operand (abstract_mask));
+
+    status = _cairo_gl_composite_begin (&setup, &ctx);
+    if (unlikely (status))
+        goto FAIL;
+
+    emit_aligned_boxes (ctx, boxes);
+    status = _cairo_gl_context_release (ctx, CAIRO_STATUS_SUCCESS);
+
+FAIL:
+    _cairo_gl_composite_fini (&setup);
+    return status;
+}
+
+static cairo_int_status_t
+composite (void			*_dst,
+	   cairo_operator_t	op,
+	   cairo_surface_t	*abstract_src,
+	   cairo_surface_t	*abstract_mask,
+	   int			src_x,
+	   int			src_y,
+	   int			mask_x,
+	   int			mask_y,
+	   int			dst_x,
+	   int			dst_y,
+	   unsigned int		width,
+	   unsigned int		height)
+{
+    cairo_gl_composite_t setup;
+    cairo_gl_context_t *ctx;
+    cairo_int_status_t status;
+
+    status = _cairo_gl_composite_init (&setup, op, _dst, FALSE, NULL);
+    if (unlikely (status))
+        goto FAIL;
+
+    _cairo_gl_composite_set_source_operand (&setup,
+					    source_to_operand (abstract_src));
+
+    _cairo_gl_composite_set_mask_operand (&setup,
+					  source_to_operand (abstract_mask));
+
+    status = _cairo_gl_composite_begin (&setup, &ctx);
+    if (unlikely (status))
+        goto FAIL;
+
+    /* XXX clip */
+    _cairo_gl_composite_emit_rect (ctx, dst_x, dst_y, dst_x+width, dst_y+height, 0);
+    status = _cairo_gl_context_release (ctx, CAIRO_STATUS_SUCCESS);
+
+FAIL:
+    _cairo_gl_composite_fini (&setup);
+    return status;
+}
+
+static cairo_int_status_t
+lerp (void			*dst,
+      cairo_surface_t		*src,
+      cairo_surface_t		*mask,
+      int			src_x,
+      int			src_y,
+      int			mask_x,
+      int			mask_y,
+      int			dst_x,
+      int			dst_y,
+      unsigned int		width,
+      unsigned int		height)
+{
+    cairo_int_status_t status;
+
+    /* we could avoid some repetition... */
+    status = composite (dst, CAIRO_OPERATOR_DEST_OUT, src, mask,
+			src_x, src_y,
+			mask_x, mask_y,
+			dst_x, dst_y,
+			width, height);
+    if (unlikely (status))
+	return status;
+
+    status = composite (dst, CAIRO_OPERATOR_ADD, src, mask,
+			src_x, src_y,
+			mask_x, mask_y,
+			dst_x, dst_y,
+			width, height);
+    if (unlikely (status))
+	return status;
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_gl_surface_t *
+traps_to_surface (void *_dst,
+		  const cairo_rectangle_int_t *extents,
+		  cairo_antialias_t	antialias,
+		  cairo_traps_t		*traps)
+{
+    pixman_format_code_t pixman_format;
+    pixman_image_t *pixman_image;
+    cairo_surface_t *image, *mask;
+    cairo_status_t status;
+
+    pixman_format = antialias != CAIRO_ANTIALIAS_NONE ? PIXMAN_a8 : PIXMAN_a1,
+    pixman_image = pixman_image_create_bits (pixman_format,
+					     extents->width,
+					     extents->height,
+					     NULL, 0);
+    if (unlikely (pixman_image == NULL))
+	return (cairo_gl_surface_t *)_cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
+
+    _pixman_image_add_traps (pixman_image, extents->x, extents->y, traps);
+    image = _cairo_image_surface_create_for_pixman_image (pixman_image,
+							  pixman_format);
+    if (unlikely (image->status)) {
+	pixman_image_unref (pixman_image);
+	return (cairo_gl_surface_t *)image;
+    }
+
+    mask = _cairo_surface_create_similar_scratch (_dst, CAIRO_CONTENT_ALPHA,
+						  extents->width,
+						  extents->height);
+    if (unlikely (mask->status)) {
+	cairo_surface_destroy (image);
+	return (cairo_gl_surface_t *)mask;
+    }
+
+    status = _cairo_gl_surface_draw_image ((cairo_gl_surface_t *)mask,
+					   (cairo_image_surface_t *)image,
+					   0, 0,
+					   extents->width, extents->height,
+					   0, 0);
+    cairo_surface_destroy (image);
+    if (unlikely (status)) {
+	cairo_surface_destroy (mask);
+	return (cairo_gl_surface_t*)_cairo_surface_create_in_error (status);
+    }
+
+    return (cairo_gl_surface_t*)mask;
+}
+
+static cairo_int_status_t
+composite_traps (void			*_dst,
+		 cairo_operator_t	op,
+		 cairo_surface_t	*abstract_src,
+		 int			src_x,
+		 int			src_y,
+		 int			dst_x,
+		 int			dst_y,
+		 const cairo_rectangle_int_t *extents,
+		 cairo_antialias_t	antialias,
+		 cairo_traps_t		*traps)
+{
+    cairo_gl_composite_t setup;
+    cairo_gl_context_t *ctx;
+    cairo_gl_surface_t *mask;
+    cairo_int_status_t status;
+
+    mask = traps_to_surface (_dst, extents, antialias, traps);
+    if (unlikely (mask->base.status))
+	return mask->base.status;
+
+    status = _cairo_gl_composite_init (&setup, op, _dst, FALSE, NULL);
+    if (unlikely (status))
+        goto FAIL;
+
+    _cairo_gl_composite_set_source_operand (&setup,
+					    source_to_operand (abstract_src));
+
+    //_cairo_gl_composite_set_mask_surface (&setup, mask, 0, 0);
+
+    status = _cairo_gl_composite_begin (&setup, &ctx);
+    if (unlikely (status))
+        goto FAIL;
+
+    /* XXX clip */
+    _cairo_gl_composite_emit_rect (ctx,
+				   dst_x, dst_y,
+				   dst_x+extents->width,
+				   dst_y+extents->height, 0);
+    status = _cairo_gl_context_release (ctx, CAIRO_STATUS_SUCCESS);
+
+FAIL:
+    _cairo_gl_composite_fini (&setup);
+    cairo_surface_destroy (&mask->base);
+    return status;
+}
+
+static cairo_gl_surface_t *
+tristrip_to_surface (void *_dst,
+		  const cairo_rectangle_int_t *extents,
+		  cairo_antialias_t	antialias,
+		  cairo_tristrip_t	*strip)
+{
+    pixman_format_code_t pixman_format;
+    pixman_image_t *pixman_image;
+    cairo_surface_t *image, *mask;
+    cairo_status_t status;
+
+    pixman_format = antialias != CAIRO_ANTIALIAS_NONE ? PIXMAN_a8 : PIXMAN_a1,
+    pixman_image = pixman_image_create_bits (pixman_format,
+					     extents->width,
+					     extents->height,
+					     NULL, 0);
+    if (unlikely (pixman_image == NULL))
+	return (cairo_gl_surface_t *)_cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
+
+    _pixman_image_add_tristrip (pixman_image, extents->x, extents->y, strip);
+    image = _cairo_image_surface_create_for_pixman_image (pixman_image,
+							  pixman_format);
+    if (unlikely (image->status)) {
+	pixman_image_unref (pixman_image);
+	return (cairo_gl_surface_t *)image;
+    }
+
+    mask = _cairo_surface_create_similar_scratch (_dst, CAIRO_CONTENT_ALPHA,
+						  extents->width,
+						  extents->height);
+    if (unlikely (mask->status)) {
+	cairo_surface_destroy (image);
+	return (cairo_gl_surface_t *)mask;
+    }
+
+    status = _cairo_gl_surface_draw_image ((cairo_gl_surface_t *)mask,
+					   (cairo_image_surface_t *)image,
+					   0, 0,
+					   extents->width, extents->height,
+					   0, 0);
+    cairo_surface_destroy (image);
+    if (unlikely (status)) {
+	cairo_surface_destroy (mask);
+	return (cairo_gl_surface_t*)_cairo_surface_create_in_error (status);
+    }
+
+    return (cairo_gl_surface_t*)mask;
+}
+
+static cairo_int_status_t
+composite_tristrip (void		*_dst,
+		    cairo_operator_t	op,
+		    cairo_surface_t	*abstract_src,
+		    int			src_x,
+		    int			src_y,
+		    int			dst_x,
+		    int			dst_y,
+		    const cairo_rectangle_int_t *extents,
+		    cairo_antialias_t	antialias,
+		    cairo_tristrip_t	*strip)
+{
+    cairo_gl_composite_t setup;
+    cairo_gl_context_t *ctx;
+    cairo_gl_surface_t *mask;
+    cairo_int_status_t status;
+
+    mask = tristrip_to_surface (_dst, extents, antialias, strip);
+    if (unlikely (mask->base.status))
+	return mask->base.status;
+
+    status = _cairo_gl_composite_init (&setup, op, _dst, FALSE, NULL);
+    if (unlikely (status))
+        goto FAIL;
+
+    _cairo_gl_composite_set_source_operand (&setup,
+					    source_to_operand (abstract_src));
+
+    //_cairo_gl_composite_set_mask_surface (&setup, mask, 0, 0);
+
+    status = _cairo_gl_composite_begin (&setup, &ctx);
+    if (unlikely (status))
+        goto FAIL;
+
+    /* XXX clip */
+    _cairo_gl_composite_emit_rect (ctx,
+				   dst_x, dst_y,
+				   dst_x+extents->width,
+				   dst_y+extents->height, 0);
+    status = _cairo_gl_context_release (ctx, CAIRO_STATUS_SUCCESS);
+
+FAIL:
+    _cairo_gl_composite_fini (&setup);
+    cairo_surface_destroy (&mask->base);
+    return status;
+}
+
+const cairo_compositor_t *
+_cairo_gl_traps_compositor_get (void)
+{
+    static cairo_traps_compositor_t compositor;
+
+    if (compositor.base.delegate == NULL) {
+	_cairo_traps_compositor_init (&compositor, &_cairo_fallback_compositor);
+	compositor.acquire = acquire;
+	compositor.release = release;
+	compositor.set_clip_region = set_clip_region;
+	compositor.pattern_to_surface = pattern_to_surface;
+	compositor.draw_image_boxes = draw_image_boxes;
+	//compositor.copy_boxes = copy_boxes;
+	compositor.fill_boxes = fill_boxes;
+	//compositor.check_composite = check_composite;
+	compositor.composite = composite;
+	compositor.lerp = lerp;
+	//compositor.check_composite_boxes = check_composite_boxes;
+	compositor.composite_boxes = composite_boxes;
+	//compositor.check_composite_traps = check_composite_traps;
+	compositor.composite_traps = composite_traps;
+	//compositor.check_composite_tristrip = check_composite_traps;
+	compositor.composite_tristrip = composite_tristrip;
+	compositor.check_composite_glyphs = _cairo_gl_check_composite_glyphs;
+	compositor.composite_glyphs = _cairo_gl_composite_glyphs;
+    }
+
+    return &compositor.base;
+}
diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c
index 1b0658d..c37fd8b 100644
--- a/src/cairo-gstate.c
+++ b/src/cairo-gstate.c
@@ -41,6 +41,7 @@
 #include "cairo-error-private.h"
 #include "cairo-gstate-private.h"
 #include "cairo-pattern-private.h"
+#include "cairo-traps-private.h"
 
 #if _XOPEN_SOURCE >= 600 || defined (_ISOC99_SOURCE)
 #define ISFINITE(x) isfinite (x)
@@ -60,7 +61,7 @@ _cairo_gstate_ensure_scaled_font (cairo_gstate_t *gstate);
 static void
 _cairo_gstate_unset_scaled_font (cairo_gstate_t *gstate);
 
-static cairo_status_t
+static void
 _cairo_gstate_transform_glyphs_to_backend (cairo_gstate_t      *gstate,
                                            const cairo_glyph_t *glyphs,
                                            int                  num_glyphs,
@@ -800,11 +801,21 @@ _cairo_gstate_backend_to_user_rectangle (cairo_gstate_t *gstate,
 {
     cairo_matrix_t matrix_inverse;
 
-    cairo_matrix_multiply (&matrix_inverse,
-                           &gstate->target->device_transform_inverse,
-			   &gstate->ctm_inverse);
-    _cairo_matrix_transform_bounding_box (&matrix_inverse,
-					  x1, y1, x2, y2, is_tight);
+    if (! _cairo_matrix_is_identity (&gstate->target->device_transform_inverse) ||
+    ! _cairo_matrix_is_identity (&gstate->ctm_inverse))
+    {
+	cairo_matrix_multiply (&matrix_inverse,
+			       &gstate->target->device_transform_inverse,
+			       &gstate->ctm_inverse);
+	_cairo_matrix_transform_bounding_box (&matrix_inverse,
+					      x1, y1, x2, y2, is_tight);
+    }
+
+    else
+    {
+	if (is_tight)
+	    *is_tight = TRUE;
+    }
 }
 
 /* XXX: NYI
@@ -1346,45 +1357,29 @@ _cairo_gstate_show_page (cairo_gstate_t *gstate)
 }
 
 static void
-_cairo_gstate_traps_extents_to_user_rectangle (cairo_gstate_t	  *gstate,
-                                               cairo_traps_t      *traps,
-                                               double *x1, double *y1,
-                                               double *x2, double *y2)
+_cairo_gstate_extents_to_user_rectangle (cairo_gstate_t	  *gstate,
+					 const cairo_box_t *extents,
+					 double *x1, double *y1,
+					 double *x2, double *y2)
 {
-    cairo_box_t extents;
-
-    if (traps->num_traps == 0) {
-        /* no traps, so we actually won't draw anything */
-	if (x1)
-	    *x1 = 0.0;
-	if (y1)
-	    *y1 = 0.0;
-	if (x2)
-	    *x2 = 0.0;
-	if (y2)
-	    *y2 = 0.0;
-    } else {
-	double px1, py1, px2, py2;
-
-	_cairo_traps_extents (traps, &extents);
+    double px1, py1, px2, py2;
 
-	px1 = _cairo_fixed_to_double (extents.p1.x);
-	py1 = _cairo_fixed_to_double (extents.p1.y);
-	px2 = _cairo_fixed_to_double (extents.p2.x);
-	py2 = _cairo_fixed_to_double (extents.p2.y);
+    px1 = _cairo_fixed_to_double (extents->p1.x);
+    py1 = _cairo_fixed_to_double (extents->p1.y);
+    px2 = _cairo_fixed_to_double (extents->p2.x);
+    py2 = _cairo_fixed_to_double (extents->p2.y);
 
-        _cairo_gstate_backend_to_user_rectangle (gstate,
-						 &px1, &py1, &px2, &py2,
-						 NULL);
-	if (x1)
-	    *x1 = px1;
-	if (y1)
-	    *y1 = py1;
-	if (x2)
-	    *x2 = px2;
-	if (y2)
-	    *y2 = py2;
-    }
+    _cairo_gstate_backend_to_user_rectangle (gstate,
+					     &px1, &py1, &px2, &py2,
+					     NULL);
+    if (x1)
+	*x1 = px1;
+    if (y1)
+	*y1 = py1;
+    if (x2)
+	*x2 = px2;
+    if (y2)
+	*y2 = py2;
 }
 
 cairo_status_t
@@ -1393,35 +1388,57 @@ _cairo_gstate_stroke_extents (cairo_gstate_t	 *gstate,
                               double *x1, double *y1,
 			      double *x2, double *y2)
 {
-    cairo_status_t status;
-    cairo_traps_t traps;
+    cairo_int_status_t status;
+    cairo_box_t extents;
+    cairo_bool_t empty;
 
-    if (gstate->stroke_style.line_width <= 0.0) {
-	if (x1)
-	    *x1 = 0.0;
-	if (y1)
-	    *y1 = 0.0;
-	if (x2)
-	    *x2 = 0.0;
-	if (y2)
-	    *y2 = 0.0;
-	return CAIRO_STATUS_SUCCESS;
-    }
+    if (x1)
+	*x1 = 0.0;
+    if (y1)
+	*y1 = 0.0;
+    if (x2)
+	*x2 = 0.0;
+    if (y2)
+	*y2 = 0.0;
 
-    _cairo_traps_init (&traps);
+    if (gstate->stroke_style.line_width <= 0.0)
+	return CAIRO_STATUS_SUCCESS;
 
-    status = _cairo_path_fixed_stroke_to_traps (path,
-						&gstate->stroke_style,
-						&gstate->ctm,
-						&gstate->ctm_inverse,
-						gstate->tolerance,
-						&traps);
-    if (likely (status == CAIRO_STATUS_SUCCESS)) {
-	_cairo_gstate_traps_extents_to_user_rectangle (gstate, &traps,
-						       x1, y1, x2, y2);
+    status = CAIRO_INT_STATUS_UNSUPPORTED;
+    if (_cairo_path_fixed_stroke_is_rectilinear (path)) {
+	cairo_boxes_t boxes;
+
+	_cairo_boxes_init (&boxes);
+	status = _cairo_path_fixed_stroke_rectilinear_to_boxes (path,
+								&gstate->stroke_style,
+								&gstate->ctm,
+								gstate->antialias,
+								&boxes);
+	empty = boxes.num_boxes == 0;
+	if (! empty)
+	    _cairo_boxes_extents (&boxes, &extents);
+	_cairo_boxes_fini (&boxes);
     }
 
-    _cairo_traps_fini (&traps);
+    if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
+	cairo_traps_t traps;
+
+	_cairo_traps_init (&traps);
+	status = _cairo_path_fixed_stroke_to_traps (path,
+						    &gstate->stroke_style,
+						    &gstate->ctm,
+						    &gstate->ctm_inverse,
+						    gstate->tolerance,
+						    &traps);
+	empty = traps.num_traps == 0;
+	if (! empty)
+	    _cairo_traps_extents (&traps, &extents);
+	_cairo_traps_fini (&traps);
+    }
+    if (! empty) {
+	_cairo_gstate_extents_to_user_rectangle (gstate, &extents,
+						 x1, y1, x2, y2);
+    }
 
     return status;
 }
@@ -1433,32 +1450,54 @@ _cairo_gstate_fill_extents (cairo_gstate_t     *gstate,
 			    double *x2, double *y2)
 {
     cairo_status_t status;
-    cairo_traps_t traps;
+    cairo_box_t extents;
+    cairo_bool_t empty;
 
-    if (_cairo_path_fixed_fill_is_empty (path)) {
-	if (x1)
-	    *x1 = 0.0;
-	if (y1)
-	    *y1 = 0.0;
-	if (x2)
-	    *x2 = 0.0;
-	if (y2)
-	    *y2 = 0.0;
+    if (x1)
+	*x1 = 0.0;
+    if (y1)
+	*y1 = 0.0;
+    if (x2)
+	*x2 = 0.0;
+    if (y2)
+	*y2 = 0.0;
+
+    if (_cairo_path_fixed_fill_is_empty (path))
 	return CAIRO_STATUS_SUCCESS;
-    }
 
-    _cairo_traps_init (&traps);
+    if (_cairo_path_fixed_fill_is_rectilinear (path)) {
+	cairo_boxes_t boxes;
+
+	_cairo_boxes_init (&boxes);
+	status = _cairo_path_fixed_fill_rectilinear_to_boxes (path,
+							      gstate->fill_rule,
+							      gstate->antialias,
+							      &boxes);
+	empty = boxes.num_boxes == 0;
+	if (! empty)
+	    _cairo_boxes_extents (&boxes, &extents);
+
+	_cairo_boxes_fini (&boxes);
+    } else {
+	cairo_traps_t traps;
 
-    status = _cairo_path_fixed_fill_to_traps (path,
-					      gstate->fill_rule,
-					      gstate->tolerance,
-					      &traps);
-    if (likely (status == CAIRO_STATUS_SUCCESS)) {
-	_cairo_gstate_traps_extents_to_user_rectangle (gstate, &traps,
-						       x1, y1, x2, y2);
+	_cairo_traps_init (&traps);
+
+	status = _cairo_path_fixed_fill_to_traps (path,
+						  gstate->fill_rule,
+						  gstate->tolerance,
+						  &traps);
+	empty = traps.num_traps == 0;
+	if (! empty)
+	    _cairo_traps_extents (&traps, &extents);
+
+	_cairo_traps_fini (&traps);
     }
 
-    _cairo_traps_fini (&traps);
+    if (! empty) {
+	_cairo_gstate_extents_to_user_rectangle (gstate, &extents,
+						 x1, y1, x2, y2);
+    }
 
     return status;
 }
@@ -1834,12 +1873,12 @@ _cairo_gstate_show_text_glyphs (cairo_gstate_t		   *gstate,
 				int			    num_glyphs,
 				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 = NULL;
+    cairo_pattern_union_t source_pattern;
+    cairo_glyph_t *transformed_glyphs;
+    const cairo_pattern_t *pattern;
+    cairo_text_cluster_t *transformed_clusters;
     cairo_operator_t op;
     cairo_status_t status;
 
@@ -1858,16 +1897,15 @@ _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)) {
-	    status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
-	    goto CLEANUP_GLYPHS;
-	}
+	if (unlikely (transformed_glyphs == NULL))
+	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
     }
 
     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)) {
@@ -1876,24 +1914,24 @@ _cairo_gstate_show_text_glyphs (cairo_gstate_t		   *gstate,
 	    }
 	}
 
-	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);
+	_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);
+	_cairo_gstate_transform_glyphs_to_backend (gstate,
+						   glyphs, num_glyphs,
+						   NULL, 0, 0,
+						   transformed_glyphs,
+						   &num_glyphs,
+						   NULL);
     }
 
-    if (status || num_glyphs == 0)
+    if (num_glyphs == 0)
 	goto CLEANUP_GLYPHS;
 
     op = _reduce_op (gstate);
@@ -1971,35 +2009,32 @@ _cairo_gstate_glyph_path (cairo_gstate_t      *gstate,
 			  int		       num_glyphs,
 			  cairo_path_fixed_t  *path)
 {
-    cairo_status_t status;
-    cairo_glyph_t *transformed_glyphs;
     cairo_glyph_t stack_transformed_glyphs[CAIRO_STACK_ARRAY_LENGTH (cairo_glyph_t)];
+    cairo_glyph_t *transformed_glyphs;
+    cairo_status_t status;
 
     status = _cairo_gstate_ensure_scaled_font (gstate);
     if (unlikely (status))
 	return status;
 
     if (num_glyphs < ARRAY_LENGTH (stack_transformed_glyphs)) {
-      transformed_glyphs = stack_transformed_glyphs;
+	transformed_glyphs = stack_transformed_glyphs;
     } else {
 	transformed_glyphs = cairo_glyph_allocate (num_glyphs);
 	if (unlikely (transformed_glyphs == NULL))
 	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
     }
 
-    status = _cairo_gstate_transform_glyphs_to_backend (gstate,
-							glyphs, num_glyphs,
-							NULL, 0, 0,
-							transformed_glyphs,
-							&num_glyphs, NULL);
-    if (unlikely (status))
-	goto CLEANUP_GLYPHS;
+    _cairo_gstate_transform_glyphs_to_backend (gstate,
+					       glyphs, num_glyphs,
+					       NULL, 0, 0,
+					       transformed_glyphs,
+					       &num_glyphs, NULL);
 
     status = _cairo_scaled_font_glyph_path (gstate->scaled_font,
 					    transformed_glyphs, num_glyphs,
 					    path);
 
-  CLEANUP_GLYPHS:
     if (transformed_glyphs != stack_transformed_glyphs)
       cairo_glyph_free (transformed_glyphs);
 
@@ -2039,7 +2074,7 @@ _cairo_gstate_get_antialias (cairo_gstate_t *gstate)
  * This also uses information from the scaled font and the surface to
  * cull/drop glyphs that will not be visible.
  **/
-static cairo_status_t
+static void
 _cairo_gstate_transform_glyphs_to_backend (cairo_gstate_t	*gstate,
                                            const cairo_glyph_t	*glyphs,
                                            int			 num_glyphs,
@@ -2050,44 +2085,40 @@ _cairo_gstate_transform_glyphs_to_backend (cairo_gstate_t	*gstate,
 					   int			*num_transformed_glyphs,
 					   cairo_text_cluster_t *transformed_clusters)
 {
-    int i, j, k;
+    cairo_rectangle_int_t surface_extents;
     cairo_matrix_t *ctm = &gstate->ctm;
     cairo_matrix_t *font_matrix = &gstate->font_matrix;
     cairo_matrix_t *device_transform = &gstate->target->device_transform;
     cairo_bool_t drop = FALSE;
     double x1 = 0, x2 = 0, y1 = 0, y2 = 0;
+    int i, j, k;
 
-    if (num_transformed_glyphs != NULL) {
-	cairo_rectangle_int_t surface_extents;
-
-	drop = TRUE;
-	if (! _cairo_gstate_int_clip_extents (gstate, &surface_extents)) {
-	    drop = FALSE; /* unbounded surface */
-	} else {
-	    double scale10 = 10 * _cairo_scaled_font_get_max_scale (gstate->scaled_font);
-	    if (surface_extents.width == 0 || surface_extents.height == 0) {
-	      /* No visible area.  Don't draw anything */
-	      *num_transformed_glyphs = 0;
-	      return CAIRO_STATUS_SUCCESS;
-	    }
-	    /* XXX We currently drop any glyphs that has its position outside
-	     * of the surface boundaries by a safety margin depending on the
-	     * font scale.  This however can fail in extreme cases where the
-	     * font has really long swashes for example...  We can correctly
-	     * handle that by looking the glyph up and using its device bbox
-	     * to device if it's going to be visible, but I'm not inclined to
-	     * do that now.
-	     */
-	    x1 = surface_extents.x - scale10;
-	    y1 = surface_extents.y - scale10;
-	    x2 = surface_extents.x + (int) surface_extents.width  + scale10;
-	    y2 = surface_extents.y + (int) surface_extents.height + scale10;
+    drop = TRUE;
+    if (! _cairo_gstate_int_clip_extents (gstate, &surface_extents)) {
+	drop = FALSE; /* unbounded surface */
+    } else {
+	double scale10 = 10 * _cairo_scaled_font_get_max_scale (gstate->scaled_font);
+	if (surface_extents.width == 0 || surface_extents.height == 0) {
+	  /* No visible area.  Don't draw anything */
+	  *num_transformed_glyphs = 0;
+	  return;
 	}
+	/* XXX We currently drop any glyphs that has its position outside
+	 * of the surface boundaries by a safety margin depending on the
+	 * font scale.  This however can fail in extreme cases where the
+	 * font has really long swashes for example...  We can correctly
+	 * handle that by looking the glyph up and using its device bbox
+	 * to device if it's going to be visible, but I'm not inclined to
+	 * do that now.
+	 */
+	x1 = surface_extents.x - scale10;
+	y1 = surface_extents.y - scale10;
+	x2 = surface_extents.x + (int) surface_extents.width  + scale10;
+	y2 = surface_extents.y + (int) surface_extents.height + scale10;
+    }
 
-	if (!drop)
-	    *num_transformed_glyphs = num_glyphs;
-    } else
-	num_transformed_glyphs = &j;
+    if (!drop)
+	*num_transformed_glyphs = num_glyphs;
 
 #define KEEP_GLYPH(glyph) (x1 <= glyph.x && glyph.x <= x2 && y1 <= glyph.y && glyph.y <= y2)
 
@@ -2156,6 +2187,8 @@ _cairo_gstate_transform_glyphs_to_backend (cairo_gstate_t	*gstate,
 		if (!drop || KEEP_GLYPH (transformed_glyphs[j]))
 		    j++;
 	    }
+	    memcpy (transformed_clusters, clusters,
+		    num_clusters * sizeof (cairo_text_cluster_t));
 	} else {
 	    const cairo_glyph_t *cur_glyph;
 
@@ -2209,6 +2242,8 @@ _cairo_gstate_transform_glyphs_to_backend (cairo_gstate_t	*gstate,
 		if (! drop || KEEP_GLYPH (transformed_glyphs[j]))
 		    j++;
 	    }
+	    memcpy (transformed_clusters, clusters,
+		    num_clusters * sizeof (cairo_text_cluster_t));
 	} else {
 	    const cairo_glyph_t *cur_glyph;
 
@@ -2252,6 +2287,4 @@ _cairo_gstate_transform_glyphs_to_backend (cairo_gstate_t	*gstate,
 	    transformed_glyphs[j] = tmp;
 	}
     }
-
-    return CAIRO_STATUS_SUCCESS;
 }
diff --git a/src/cairo-image-compositor.c b/src/cairo-image-compositor.c
new file mode 100644
index 0000000..35472de
--- /dev/null
+++ b/src/cairo-image-compositor.c
@@ -0,0 +1,1545 @@
+/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2003 University of Southern California
+ * Copyright © 2009,2010,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>
+ */
+
+/* The primarily reason for keeping a traps-compositor around is
+ * for validating cairo-xlib (which currently also uses traps).
+ */
+
+#include "cairoint.h"
+
+#include "cairo-image-surface-private.h"
+
+#include "cairo-compositor-private.h"
+#include "cairo-spans-compositor-private.h"
+
+#include "cairo-region-private.h"
+#include "cairo-traps-private.h"
+#include "cairo-tristrip-private.h"
+
+static pixman_image_t *
+to_pixman_image (cairo_surface_t *s)
+{
+    return ((cairo_image_surface_t *)s)->pixman_image;
+}
+
+static cairo_int_status_t
+acquire (void *abstract_dst)
+{
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+release (void *abstract_dst)
+{
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+set_clip_region (void *_surface,
+		 cairo_region_t *region)
+{
+    cairo_image_surface_t *surface = _surface;
+    pixman_region32_t *rgn = region ? &region->rgn : NULL;
+
+    if (! pixman_image_set_clip_region32 (surface->pixman_image, rgn))
+	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+draw_image_boxes (void *_dst,
+		  cairo_image_surface_t *image,
+		  cairo_boxes_t *boxes,
+		  int dx, int dy)
+{
+    cairo_image_surface_t *dst = _dst;
+    struct _cairo_boxes_chunk *chunk;
+    int i;
+
+    for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
+	for (i = 0; i < chunk->count; i++) {
+	    cairo_box_t *b = &chunk->base[i];
+	    int x = _cairo_fixed_integer_part (b->p1.x);
+	    int y = _cairo_fixed_integer_part (b->p1.y);
+	    int w = _cairo_fixed_integer_part (b->p2.x) - x;
+	    int h = _cairo_fixed_integer_part (b->p2.y) - y;
+	    if (dst->pixman_format != image->pixman_format ||
+		! pixman_blt ((uint32_t *)image->data, (uint32_t *)dst->data,
+			      image->stride / sizeof (uint32_t),
+			      dst->stride / sizeof (uint32_t),
+			      PIXMAN_FORMAT_BPP (image->pixman_format),
+			      PIXMAN_FORMAT_BPP (dst->pixman_format),
+			      x + dx, y + dy,
+			      x, y,
+			      w, h))
+	    {
+		pixman_image_composite32 (PIXMAN_OP_SRC,
+					  image->pixman_image, NULL, dst->pixman_image,
+					  x + dx, y + dy,
+					  0, 0,
+					  x, y,
+					  w, h);
+	    }
+	}
+    }
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static inline uint32_t
+color_to_uint32 (const cairo_color_t *color)
+{
+    return
+        (color->alpha_short >> 8 << 24) |
+        (color->red_short >> 8 << 16)   |
+        (color->green_short & 0xff00)   |
+        (color->blue_short >> 8);
+}
+
+static inline cairo_bool_t
+color_to_pixel (const cairo_color_t	*color,
+                pixman_format_code_t	 format,
+                uint32_t		*pixel)
+{
+    uint32_t c;
+
+    if (!(format == PIXMAN_a8r8g8b8     ||
+          format == PIXMAN_x8r8g8b8     ||
+          format == PIXMAN_a8b8g8r8     ||
+          format == PIXMAN_x8b8g8r8     ||
+          format == PIXMAN_b8g8r8a8     ||
+          format == PIXMAN_b8g8r8x8     ||
+          format == PIXMAN_r5g6b5       ||
+          format == PIXMAN_b5g6r5       ||
+          format == PIXMAN_a8))
+    {
+	return FALSE;
+    }
+
+    c = color_to_uint32 (color);
+
+    if (PIXMAN_FORMAT_TYPE (format) == PIXMAN_TYPE_ABGR) {
+	c = ((c & 0xff000000) >>  0) |
+	    ((c & 0x00ff0000) >> 16) |
+	    ((c & 0x0000ff00) >>  0) |
+	    ((c & 0x000000ff) << 16);
+    }
+
+    if (PIXMAN_FORMAT_TYPE (format) == PIXMAN_TYPE_BGRA) {
+	c = ((c & 0xff000000) >> 24) |
+	    ((c & 0x00ff0000) >>  8) |
+	    ((c & 0x0000ff00) <<  8) |
+	    ((c & 0x000000ff) << 24);
+    }
+
+    if (format == PIXMAN_a8) {
+	c = c >> 24;
+    } else if (format == PIXMAN_r5g6b5 || format == PIXMAN_b5g6r5) {
+	c = ((((c) >> 3) & 0x001f) |
+	     (((c) >> 5) & 0x07e0) |
+	     (((c) >> 8) & 0xf800));
+    }
+
+    *pixel = c;
+    return TRUE;
+}
+
+static pixman_op_t
+_pixman_operator (cairo_operator_t op)
+{
+    switch ((int) op) {
+    case CAIRO_OPERATOR_CLEAR:
+	return PIXMAN_OP_CLEAR;
+
+    case CAIRO_OPERATOR_SOURCE:
+	return PIXMAN_OP_SRC;
+    case CAIRO_OPERATOR_OVER:
+	return PIXMAN_OP_OVER;
+    case CAIRO_OPERATOR_IN:
+	return PIXMAN_OP_IN;
+    case CAIRO_OPERATOR_OUT:
+	return PIXMAN_OP_OUT;
+    case CAIRO_OPERATOR_ATOP:
+	return PIXMAN_OP_ATOP;
+
+    case CAIRO_OPERATOR_DEST:
+	return PIXMAN_OP_DST;
+    case CAIRO_OPERATOR_DEST_OVER:
+	return PIXMAN_OP_OVER_REVERSE;
+    case CAIRO_OPERATOR_DEST_IN:
+	return PIXMAN_OP_IN_REVERSE;
+    case CAIRO_OPERATOR_DEST_OUT:
+	return PIXMAN_OP_OUT_REVERSE;
+    case CAIRO_OPERATOR_DEST_ATOP:
+	return PIXMAN_OP_ATOP_REVERSE;
+
+    case CAIRO_OPERATOR_XOR:
+	return PIXMAN_OP_XOR;
+    case CAIRO_OPERATOR_ADD:
+	return PIXMAN_OP_ADD;
+    case CAIRO_OPERATOR_SATURATE:
+	return PIXMAN_OP_SATURATE;
+
+    case CAIRO_OPERATOR_MULTIPLY:
+	return PIXMAN_OP_MULTIPLY;
+    case CAIRO_OPERATOR_SCREEN:
+	return PIXMAN_OP_SCREEN;
+    case CAIRO_OPERATOR_OVERLAY:
+	return PIXMAN_OP_OVERLAY;
+    case CAIRO_OPERATOR_DARKEN:
+	return PIXMAN_OP_DARKEN;
+    case CAIRO_OPERATOR_LIGHTEN:
+	return PIXMAN_OP_LIGHTEN;
+    case CAIRO_OPERATOR_COLOR_DODGE:
+	return PIXMAN_OP_COLOR_DODGE;
+    case CAIRO_OPERATOR_COLOR_BURN:
+	return PIXMAN_OP_COLOR_BURN;
+    case CAIRO_OPERATOR_HARD_LIGHT:
+	return PIXMAN_OP_HARD_LIGHT;
+    case CAIRO_OPERATOR_SOFT_LIGHT:
+	return PIXMAN_OP_SOFT_LIGHT;
+    case CAIRO_OPERATOR_DIFFERENCE:
+	return PIXMAN_OP_DIFFERENCE;
+    case CAIRO_OPERATOR_EXCLUSION:
+	return PIXMAN_OP_EXCLUSION;
+    case CAIRO_OPERATOR_HSL_HUE:
+	return PIXMAN_OP_HSL_HUE;
+    case CAIRO_OPERATOR_HSL_SATURATION:
+	return PIXMAN_OP_HSL_SATURATION;
+    case CAIRO_OPERATOR_HSL_COLOR:
+	return PIXMAN_OP_HSL_COLOR;
+    case CAIRO_OPERATOR_HSL_LUMINOSITY:
+	return PIXMAN_OP_HSL_LUMINOSITY;
+
+    default:
+	ASSERT_NOT_REACHED;
+	return PIXMAN_OP_OVER;
+    }
+}
+
+static cairo_bool_t
+fill_reduces_to_source (cairo_operator_t op,
+			const cairo_color_t *color,
+			cairo_image_surface_t *dst)
+{
+    if (op == CAIRO_OPERATOR_SOURCE || op == CAIRO_OPERATOR_CLEAR)
+	return TRUE;
+    if (op == CAIRO_OPERATOR_OVER && CAIRO_COLOR_IS_OPAQUE (color))
+	return TRUE;
+    if (dst->base.is_clear)
+	return op == CAIRO_OPERATOR_OVER || op == CAIRO_OPERATOR_ADD;
+
+    return FALSE;
+}
+
+static cairo_int_status_t
+fill_rectangles (void			*_dst,
+		 cairo_operator_t	 op,
+		 const cairo_color_t	*color,
+		 cairo_rectangle_int_t	*rects,
+		 int			 num_rects)
+{
+    cairo_image_surface_t *dst = _dst;
+    uint32_t pixel;
+    int i;
+
+    if (fill_reduces_to_source (op, color, dst) &&
+	color_to_pixel (color, dst->pixman_format, &pixel))
+    {
+	for (i = 0; i < num_rects; i++) {
+	    pixman_fill ((uint32_t *) dst->data, dst->stride / sizeof (uint32_t),
+			 PIXMAN_FORMAT_BPP (dst->pixman_format),
+			 rects[i].x, rects[i].y,
+			 rects[i].width, rects[i].height,
+			 pixel);
+	}
+    }
+    else
+    {
+	pixman_image_t *src = _pixman_image_for_color (color);
+
+	op = _pixman_operator (op);
+	for (i = 0; i < num_rects; i++) {
+	    pixman_image_composite32 (op,
+				      src, NULL, dst->pixman_image,
+				      0, 0,
+				      0, 0,
+				      rects[i].x, rects[i].y,
+				      rects[i].width, rects[i].height);
+	}
+
+	pixman_image_unref (src);
+    }
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+fill_boxes (void		*_dst,
+	    cairo_operator_t	 op,
+	    const cairo_color_t	*color,
+	    cairo_boxes_t	*boxes)
+{
+    cairo_image_surface_t *dst = _dst;
+    struct _cairo_boxes_chunk *chunk;
+    uint32_t pixel;
+    int i;
+
+    if (fill_reduces_to_source (op, color, dst) &&
+	color_to_pixel (color, dst->pixman_format, &pixel))
+    {
+	for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
+	    for (i = 0; i < chunk->count; i++) {
+		int x = _cairo_fixed_integer_part (chunk->base[i].p1.x);
+		int y = _cairo_fixed_integer_part (chunk->base[i].p1.y);
+		int w = _cairo_fixed_integer_part (chunk->base[i].p2.x) - x;
+		int h = _cairo_fixed_integer_part (chunk->base[i].p2.y) - y;
+		pixman_fill ((uint32_t *) dst->data,
+			     dst->stride / sizeof (uint32_t),
+			     PIXMAN_FORMAT_BPP (dst->pixman_format),
+			     x, y, w, h, pixel);
+	    }
+	}
+    }
+    else
+    {
+	pixman_image_t *src = _pixman_image_for_color (color);
+
+	op = _pixman_operator (op);
+	for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
+	    for (i = 0; i < chunk->count; i++) {
+		int x1 = _cairo_fixed_integer_part (chunk->base[i].p1.x);
+		int y1 = _cairo_fixed_integer_part (chunk->base[i].p1.y);
+		int x2 = _cairo_fixed_integer_part (chunk->base[i].p2.x);
+		int y2 = _cairo_fixed_integer_part (chunk->base[i].p2.y);
+		pixman_image_composite32 (op,
+					  src, NULL, dst->pixman_image,
+					  0, 0,
+					  0, 0,
+					  x1, y1,
+					  x2-x1, y2-y1);
+	    }
+	}
+
+	pixman_image_unref (src);
+    }
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+composite (void			*_dst,
+	   cairo_operator_t	op,
+	   cairo_surface_t	*abstract_src,
+	   cairo_surface_t	*abstract_mask,
+	   int			src_x,
+	   int			src_y,
+	   int			mask_x,
+	   int			mask_y,
+	   int			dst_x,
+	   int			dst_y,
+	   unsigned int		width,
+	   unsigned int		height)
+{
+    cairo_image_source_t *src = (cairo_image_source_t *)abstract_src;
+    cairo_image_source_t *mask = (cairo_image_source_t *)abstract_mask;
+    if (mask) {
+	pixman_image_composite32 (_pixman_operator (op),
+				  src->pixman_image, mask->pixman_image, to_pixman_image (_dst),
+				  src_x, src_y,
+				  mask_x, mask_y,
+				  dst_x, dst_y,
+				  width, height);
+    } else {
+	pixman_image_composite32 (_pixman_operator (op),
+				  src->pixman_image, NULL, to_pixman_image (_dst),
+				  src_x, src_y,
+				  0, 0,
+				  dst_x, dst_y,
+				  width, height);
+    }
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+lerp (void			*_dst,
+      cairo_surface_t		*abstract_src,
+      cairo_surface_t		*abstract_mask,
+      int			src_x,
+      int			src_y,
+      int			mask_x,
+      int			mask_y,
+      int			dst_x,
+      int			dst_y,
+      unsigned int		width,
+      unsigned int		height)
+{
+    cairo_image_surface_t *dst = _dst;
+    cairo_image_source_t *src = (cairo_image_source_t *)abstract_src;
+    cairo_image_source_t *mask = (cairo_image_source_t *)abstract_mask;
+
+#if PIXMAN_HAS_OP_LERP
+    pixman_image_composite32 (PIXMAN_OP_LERP,
+			      src->pixman_image, mask->pixman_image, dst->pixman_image,
+			      src_x,  src_y,
+			      mask_x, mask_y,
+			      dst_x,  dst_y,
+			      width,  height);
+#else
+    /* Punch the clip out of the destination */
+    pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE,
+			      mask->pixman_image, NULL, dst->pixman_image,
+			      mask_x, mask_y,
+			      0,      0,
+			      dst_x,  dst_y,
+			      width,  height);
+
+    /* Now add the two results together */
+    pixman_image_composite32 (PIXMAN_OP_ADD,
+			      src->pixman_image, mask->pixman_image, dst->pixman_image,
+			      src_x,  src_y,
+			      mask_x, mask_y,
+			      dst_x,  dst_y,
+			      width,  height);
+#endif
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+composite_boxes (void			*_dst,
+		 cairo_operator_t	op,
+		 cairo_surface_t	*abstract_src,
+		 cairo_surface_t	*abstract_mask,
+		 int			src_x,
+		 int			src_y,
+		 int			mask_x,
+		 int			mask_y,
+		 int			dst_x,
+		 int			dst_y,
+		 cairo_boxes_t		*boxes,
+		 const cairo_rectangle_int_t  *extents)
+{
+    pixman_image_t *dst = to_pixman_image (_dst);
+    pixman_image_t *src = ((cairo_image_source_t *)abstract_src)->pixman_image;
+    pixman_image_t *mask = abstract_mask ? ((cairo_image_source_t *)abstract_mask)->pixman_image : NULL;
+    struct _cairo_boxes_chunk *chunk;
+    int i;
+
+    /* XXX consider using a region? saves multiple prepare-composite */
+
+    op = _pixman_operator (op);
+    for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
+	for (i = 0; i < chunk->count; i++) {
+	    int x1 = _cairo_fixed_integer_part (chunk->base[i].p1.x);
+	    int y1 = _cairo_fixed_integer_part (chunk->base[i].p1.y);
+	    int x2 = _cairo_fixed_integer_part (chunk->base[i].p2.x);
+	    int y2 = _cairo_fixed_integer_part (chunk->base[i].p2.y);
+
+	    pixman_image_composite32 (op, src, mask, dst,
+				      x1 + src_x, y1 + src_y,
+				      x1 + mask_x, y1 + mask_y,
+				      x1 + dst_x, y1 + dst_y,
+				      x2 - x1, y2 - y1);
+	}
+    }
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+#define CAIRO_FIXED_16_16_MIN _cairo_fixed_from_int (-32768)
+#define CAIRO_FIXED_16_16_MAX _cairo_fixed_from_int (32767)
+
+static cairo_bool_t
+line_exceeds_16_16 (const cairo_line_t *line)
+{
+    return
+	line->p1.x <= CAIRO_FIXED_16_16_MIN ||
+	line->p1.x >= CAIRO_FIXED_16_16_MAX ||
+
+	line->p2.x <= CAIRO_FIXED_16_16_MIN ||
+	line->p2.x >= CAIRO_FIXED_16_16_MAX ||
+
+	line->p1.y <= CAIRO_FIXED_16_16_MIN ||
+	line->p1.y >= CAIRO_FIXED_16_16_MAX ||
+
+	line->p2.y <= CAIRO_FIXED_16_16_MIN ||
+	line->p2.y >= CAIRO_FIXED_16_16_MAX;
+}
+
+static void
+project_line_x_onto_16_16 (const cairo_line_t *line,
+			   cairo_fixed_t top,
+			   cairo_fixed_t bottom,
+			   pixman_line_fixed_t *out)
+{
+    /* XXX use fixed-point arithmetic? */
+    cairo_point_double_t p1, p2;
+    double m;
+
+    p1.x = _cairo_fixed_to_double (line->p1.x);
+    p1.y = _cairo_fixed_to_double (line->p1.y);
+
+    p2.x = _cairo_fixed_to_double (line->p2.x);
+    p2.y = _cairo_fixed_to_double (line->p2.y);
+
+    m = (p2.x - p1.x) / (p2.y - p1.y);
+    out->p1.x = _cairo_fixed_16_16_from_double (p1.x + m * _cairo_fixed_to_double (top - line->p1.y));
+    out->p2.x = _cairo_fixed_16_16_from_double (p1.x + m * _cairo_fixed_to_double (bottom - line->p1.y));
+}
+
+void
+_pixman_image_add_traps (pixman_image_t *image,
+			 int dst_x, int dst_y,
+			 cairo_traps_t *traps)
+{
+    cairo_trapezoid_t *t = traps->traps;
+    int num_traps = traps->num_traps;
+    while (num_traps--) {
+	pixman_trapezoid_t trap;
+
+	/* top/bottom will be clamped to surface bounds */
+	trap.top = _cairo_fixed_to_16_16 (t->top);
+	trap.bottom = _cairo_fixed_to_16_16 (t->bottom);
+
+	/* However, all the other coordinates will have been left untouched so
+	 * as not to introduce numerical error. Recompute them if they
+	 * exceed the 16.16 limits.
+	 */
+	if (unlikely (line_exceeds_16_16 (&t->left))) {
+	    project_line_x_onto_16_16 (&t->left, t->top, t->bottom, &trap.left);
+	    trap.left.p1.y = trap.top;
+	    trap.left.p2.y = trap.bottom;
+	} else {
+	    trap.left.p1.x = _cairo_fixed_to_16_16 (t->left.p1.x);
+	    trap.left.p1.y = _cairo_fixed_to_16_16 (t->left.p1.y);
+	    trap.left.p2.x = _cairo_fixed_to_16_16 (t->left.p2.x);
+	    trap.left.p2.y = _cairo_fixed_to_16_16 (t->left.p2.y);
+	}
+
+	if (unlikely (line_exceeds_16_16 (&t->right))) {
+	    project_line_x_onto_16_16 (&t->right, t->top, t->bottom, &trap.right);
+	    trap.right.p1.y = trap.top;
+	    trap.right.p2.y = trap.bottom;
+	} else {
+	    trap.right.p1.x = _cairo_fixed_to_16_16 (t->right.p1.x);
+	    trap.right.p1.y = _cairo_fixed_to_16_16 (t->right.p1.y);
+	    trap.right.p2.x = _cairo_fixed_to_16_16 (t->right.p2.x);
+	    trap.right.p2.y = _cairo_fixed_to_16_16 (t->right.p2.y);
+	}
+
+	pixman_rasterize_trapezoid (image, &trap, -dst_x, -dst_y);
+	t++;
+    }
+}
+
+static cairo_int_status_t
+composite_traps (void			*_dst,
+		 cairo_operator_t	op,
+		 cairo_surface_t	*abstract_src,
+		 int			src_x,
+		 int			src_y,
+		 int			dst_x,
+		 int			dst_y,
+		 const cairo_rectangle_int_t *extents,
+		 cairo_antialias_t	antialias,
+		 cairo_traps_t		*traps)
+{
+    cairo_image_surface_t *dst = (cairo_image_surface_t *) _dst;
+    cairo_image_source_t *src = (cairo_image_source_t *) abstract_src;
+    pixman_image_t *mask;
+    pixman_format_code_t format;
+
+    /* Special case adding trapezoids onto a mask surface; we want to avoid
+     * creating an intermediate temporary mask unnecessarily.
+     *
+     * We make the assumption here that the portion of the trapezoids
+     * contained within the surface is bounded by [dst_x,dst_y,width,height];
+     * the Cairo core code passes bounds based on the trapezoid extents.
+     */
+    format = antialias == CAIRO_ANTIALIAS_NONE ? PIXMAN_a1 : PIXMAN_a8;
+    if (dst->pixman_format == format &&
+	(abstract_src == NULL ||
+	 (op == CAIRO_OPERATOR_ADD && src->is_opaque_solid)))
+    {
+	_pixman_image_add_traps (dst->pixman_image, dst_x, dst_y, traps);
+	return CAIRO_STATUS_SUCCESS;
+    }
+
+    mask = pixman_image_create_bits (format,
+				     extents->width, extents->height,
+				     NULL, 0);
+    if (unlikely (mask == NULL))
+	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+    _pixman_image_add_traps (mask, extents->x, extents->y, traps);
+    pixman_image_composite32 (_pixman_operator (op),
+                              src->pixman_image, mask, dst->pixman_image,
+                              extents->x + src_x, extents->y + src_y,
+                              0, 0,
+                              extents->x - dst_x, extents->y - dst_y,
+                              extents->width, extents->height);
+
+    pixman_image_unref (mask);
+
+    return  CAIRO_STATUS_SUCCESS;
+}
+
+static void
+set_point (pixman_point_fixed_t *p, cairo_point_t *c)
+{
+    p->x = _cairo_fixed_to_16_16 (c->x);
+    p->y = _cairo_fixed_to_16_16 (c->y);
+}
+
+void
+_pixman_image_add_tristrip (pixman_image_t *image,
+			    int dst_x, int dst_y,
+			    cairo_tristrip_t *strip)
+{
+    pixman_triangle_t tri;
+    pixman_point_fixed_t *p[3] = {&tri.p1, &tri.p2, &tri.p3 };
+    int n;
+
+    set_point (p[0], &strip->points[0]);
+    set_point (p[1], &strip->points[1]);
+    set_point (p[2], &strip->points[2]);
+    pixman_add_triangles (image, -dst_x, -dst_y, 1, &tri);
+    for (n = 3; n < strip->num_points; n++) {
+	set_point (p[n%3], &strip->points[n]);
+	pixman_add_triangles (image, -dst_x, -dst_y, 1, &tri);
+    }
+}
+
+static cairo_int_status_t
+composite_tristrip (void			*_dst,
+		    cairo_operator_t	op,
+		    cairo_surface_t	*abstract_src,
+		    int			src_x,
+		    int			src_y,
+		    int			dst_x,
+		    int			dst_y,
+		    const cairo_rectangle_int_t *extents,
+		    cairo_antialias_t	antialias,
+		    cairo_tristrip_t	*strip)
+{
+    cairo_image_surface_t *dst = (cairo_image_surface_t *) _dst;
+    cairo_image_source_t *src = (cairo_image_source_t *) abstract_src;
+    pixman_image_t *mask;
+    pixman_format_code_t format;
+
+    if (strip->num_points < 3)
+	return CAIRO_STATUS_SUCCESS;
+
+    format = antialias == CAIRO_ANTIALIAS_NONE ? PIXMAN_a1 : PIXMAN_a8;
+    if (dst->pixman_format == format &&
+	(abstract_src == NULL ||
+	 (op == CAIRO_OPERATOR_ADD && src->is_opaque_solid)))
+    {
+	_pixman_image_add_tristrip (dst->pixman_image, dst_x, dst_y, strip);
+	return CAIRO_STATUS_SUCCESS;
+    }
+
+    mask = pixman_image_create_bits (format,
+				     extents->width, extents->height,
+				     NULL, 0);
+    if (unlikely (mask == NULL))
+	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+    _pixman_image_add_tristrip (mask, extents->x, extents->y, strip);
+    pixman_image_composite32 (_pixman_operator (op),
+                              src->pixman_image, mask, dst->pixman_image,
+                              extents->x + src_x, extents->y + src_y,
+                              0, 0,
+                              extents->x - dst_x, extents->y - dst_y,
+                              extents->width, extents->height);
+
+    pixman_image_unref (mask);
+
+    return  CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+check_composite_glyphs (const cairo_composite_rectangles_t *extents,
+			cairo_scaled_font_t *scaled_font,
+			cairo_glyph_t *glyphs,
+			int *num_glyphs)
+{
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+composite_one_glyph (void				*_dst,
+		     cairo_operator_t			 op,
+		     cairo_surface_t			*_src,
+		     int				 src_x,
+		     int				 src_y,
+		     int				 dst_x,
+		     int				 dst_y,
+		     cairo_composite_glyphs_info_t	 *info)
+{
+    cairo_image_surface_t *glyph_surface;
+    cairo_scaled_glyph_t *scaled_glyph;
+    cairo_status_t status;
+    int x, y;
+
+    status = _cairo_scaled_glyph_lookup (info->font,
+					 info->glyphs[0].index,
+					 CAIRO_SCALED_GLYPH_INFO_SURFACE,
+					 &scaled_glyph);
+
+    if (unlikely (status))
+	return status;
+
+    glyph_surface = scaled_glyph->surface;
+    if (glyph_surface->width == 0 || glyph_surface->height == 0)
+	return CAIRO_INT_STATUS_NOTHING_TO_DO;
+
+    /* round glyph locations to the nearest pixel */
+    /* XXX: FRAGILE: We're ignoring device_transform scaling here. A bug? */
+    x = _cairo_lround (info->glyphs[0].x -
+		       glyph_surface->base.device_transform.x0);
+    y = _cairo_lround (info->glyphs[0].y -
+		       glyph_surface->base.device_transform.y0);
+
+    pixman_image_composite32 (_pixman_operator (op),
+			      ((cairo_image_source_t *)_src)->pixman_image,
+			      glyph_surface->pixman_image,
+			      to_pixman_image (_dst),
+			      x + src_x,  y + src_y,
+			      0, 0,
+			      x - dst_x, y - dst_y,
+			      glyph_surface->width,
+			      glyph_surface->height);
+
+    return CAIRO_INT_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+composite_glyphs_via_mask (void				*_dst,
+			   cairo_operator_t		 op,
+			   cairo_surface_t		*_src,
+			   int				 src_x,
+			   int				 src_y,
+			   int				 dst_x,
+			   int				 dst_y,
+			   cairo_composite_glyphs_info_t *info)
+{
+    cairo_scaled_glyph_t *glyph_cache[64];
+    cairo_bool_t component_alpha = FALSE;
+    uint8_t buf[2048];
+    pixman_image_t *mask;
+    cairo_status_t status;
+    int i;
+
+    /* XXX convert the glyphs to common formats a8/a8r8g8b8 to hit
+     * optimised paths through pixman. Should we increase the bit
+     * depth of the target surface, we should reconsider the appropriate
+     * mask formats.
+     */
+    i = (info->extents.width + 3) & ~3;
+    if (i * info->extents.height > (int) sizeof (buf)) {
+	mask = pixman_image_create_bits (PIXMAN_a8,
+					info->extents.width,
+					info->extents.height,
+					NULL, 0);
+    } else {
+	memset (buf, 0, i * info->extents.height);
+	mask = pixman_image_create_bits (PIXMAN_a8,
+					info->extents.width,
+					info->extents.height,
+					(uint32_t *)buf, i);
+    }
+    if (unlikely (mask == NULL))
+	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+    memset (glyph_cache, 0, sizeof (glyph_cache));
+    status = CAIRO_STATUS_SUCCESS;
+
+    for (i = 0; i < info->num_glyphs; i++) {
+	cairo_image_surface_t *glyph_surface;
+	cairo_scaled_glyph_t *scaled_glyph;
+	unsigned long glyph_index = info->glyphs[i].index;
+	int cache_index = glyph_index % ARRAY_LENGTH (glyph_cache);
+	int x, y;
+
+	scaled_glyph = glyph_cache[cache_index];
+	if (scaled_glyph == NULL ||
+	    _cairo_scaled_glyph_index (scaled_glyph) != glyph_index)
+	{
+	    status = _cairo_scaled_glyph_lookup (info->font, glyph_index,
+						 CAIRO_SCALED_GLYPH_INFO_SURFACE,
+						 &scaled_glyph);
+
+	    if (unlikely (status)) {
+		pixman_image_unref (mask);
+		return status;
+	    }
+
+	    glyph_cache[cache_index] = scaled_glyph;
+	}
+
+	glyph_surface = scaled_glyph->surface;
+	if (glyph_surface->width && glyph_surface->height) {
+	    if (glyph_surface->base.content & CAIRO_CONTENT_COLOR &&
+		! component_alpha) {
+		pixman_image_t *ca_mask;
+
+		ca_mask = pixman_image_create_bits (PIXMAN_a8r8g8b8,
+						    info->extents.width,
+						    info->extents.height,
+						    NULL, 0);
+		if (unlikely (ca_mask == NULL)) {
+		    pixman_image_unref (mask);
+		    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+		}
+
+		pixman_image_composite32 (PIXMAN_OP_SRC,
+					  mask, 0, ca_mask,
+					  0, 0,
+					  0, 0,
+					  0, 0,
+					  info->extents.width,
+					  info->extents.height);
+		pixman_image_unref (mask);
+		mask = ca_mask;
+		component_alpha = TRUE;
+	    }
+
+	    /* round glyph locations to the nearest pixel */
+	    /* XXX: FRAGILE: We're ignoring device_transform scaling here. A bug? */
+	    x = _cairo_lround (info->glyphs[i].x -
+			       glyph_surface->base.device_transform.x0);
+	    y = _cairo_lround (info->glyphs[i].y -
+			       glyph_surface->base.device_transform.y0);
+
+	    pixman_image_composite32 (PIXMAN_OP_ADD,
+				      glyph_surface->pixman_image, NULL, mask,
+                                      0, 0,
+				      0, 0,
+                                      x - info->extents.x, y - info->extents.y,
+				      glyph_surface->width,
+				      glyph_surface->height);
+	}
+    }
+
+    if (component_alpha)
+	pixman_image_set_component_alpha (mask, TRUE);
+
+    pixman_image_composite32 (_pixman_operator (op),
+			      ((cairo_image_source_t *)_src)->pixman_image,
+			      mask,
+			      to_pixman_image (_dst),
+			      info->extents.x + src_x, info->extents.y + src_y,
+			      0, 0,
+			      info->extents.x - dst_x, info->extents.y - dst_y,
+			      info->extents.width, info->extents.height);
+    pixman_image_unref (mask);
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+composite_glyphs (void				*_dst,
+		  cairo_operator_t		 op,
+		  cairo_surface_t		*_src,
+		  int				 src_x,
+		  int				 src_y,
+		  int				 dst_x,
+		  int				 dst_y,
+		  cairo_composite_glyphs_info_t *info)
+{
+    cairo_scaled_glyph_t *glyph_cache[64];
+    pixman_image_t *dst, *src;
+    cairo_status_t status;
+    int i;
+
+    if (info->num_glyphs == 1)
+	return composite_one_glyph(_dst, op, _src, src_x, src_y, dst_x, dst_y, info);
+
+    if (info->use_mask)
+	return composite_glyphs_via_mask(_dst, op, _src, src_x, src_y, dst_x, dst_y, info);
+
+    op = _pixman_operator (op);
+    dst = to_pixman_image (_dst);
+    src = ((cairo_image_source_t *)_src)->pixman_image;
+
+    memset (glyph_cache, 0, sizeof (glyph_cache));
+    status = CAIRO_STATUS_SUCCESS;
+
+    for (i = 0; i < info->num_glyphs; i++) {
+	int x, y;
+	cairo_image_surface_t *glyph_surface;
+	cairo_scaled_glyph_t *scaled_glyph;
+	unsigned long glyph_index = info->glyphs[i].index;
+	int cache_index = glyph_index % ARRAY_LENGTH (glyph_cache);
+
+	scaled_glyph = glyph_cache[cache_index];
+	if (scaled_glyph == NULL ||
+	    _cairo_scaled_glyph_index (scaled_glyph) != glyph_index)
+	{
+	    status = _cairo_scaled_glyph_lookup (info->font, glyph_index,
+						 CAIRO_SCALED_GLYPH_INFO_SURFACE,
+						 &scaled_glyph);
+
+	    if (unlikely (status))
+		break;
+
+	    glyph_cache[cache_index] = scaled_glyph;
+	}
+
+	glyph_surface = scaled_glyph->surface;
+	if (glyph_surface->width && glyph_surface->height) {
+	    /* round glyph locations to the nearest pixel */
+	    /* XXX: FRAGILE: We're ignoring device_transform scaling here. A bug? */
+	    x = _cairo_lround (info->glyphs[i].x -
+			       glyph_surface->base.device_transform.x0);
+	    y = _cairo_lround (info->glyphs[i].y -
+			       glyph_surface->base.device_transform.y0);
+
+	    pixman_image_composite32 (op, src, glyph_surface->pixman_image, dst,
+                                      x + src_x,  y + src_y,
+                                      0, 0,
+                                      x - dst_x, y - dst_y,
+				      glyph_surface->width,
+				      glyph_surface->height);
+	}
+    }
+
+    return status;
+}
+
+const cairo_compositor_t *
+_cairo_image_traps_compositor_get (void)
+{
+    static cairo_traps_compositor_t compositor;
+
+    if (compositor.base.delegate == NULL) {
+	_cairo_traps_compositor_init (&compositor,
+				      &__cairo_no_compositor);
+	compositor.acquire = acquire;
+	compositor.release = release;
+	compositor.set_clip_region = set_clip_region;
+	compositor.pattern_to_surface = _cairo_image_source_create_for_pattern;
+	compositor.draw_image_boxes = draw_image_boxes;
+	//compositor.copy_boxes = copy_boxes;
+	compositor.fill_boxes = fill_boxes;
+	//compositor.check_composite = check_composite;
+	compositor.composite = composite;
+	compositor.lerp = lerp;
+	//compositor.check_composite_boxes = check_composite_boxes;
+	compositor.composite_boxes = composite_boxes;
+	//compositor.check_composite_traps = check_composite_traps;
+	compositor.composite_traps = composite_traps;
+	//compositor.check_composite_tristrip = check_composite_traps;
+	compositor.composite_tristrip = composite_tristrip;
+	compositor.check_composite_glyphs = check_composite_glyphs;
+	compositor.composite_glyphs = composite_glyphs;
+    }
+
+    return &compositor.base;
+}
+
+const cairo_compositor_t *
+_cairo_image_mask_compositor_get (void)
+{
+    static cairo_mask_compositor_t compositor;
+
+    if (compositor.base.delegate == NULL) {
+	_cairo_mask_compositor_init (&compositor,
+				     _cairo_image_traps_compositor_get ());
+	compositor.acquire = acquire;
+	compositor.release = release;
+	compositor.set_clip_region = set_clip_region;
+	compositor.pattern_to_surface = _cairo_image_source_create_for_pattern;
+	compositor.draw_image_boxes = draw_image_boxes;
+	compositor.fill_rectangles = fill_rectangles;
+	compositor.fill_boxes = fill_boxes;
+	//compositor.check_composite = check_composite;
+	compositor.composite = composite;
+	//compositor.lerp = lerp;
+	//compositor.check_composite_boxes = check_composite_boxes;
+	compositor.composite_boxes = composite_boxes;
+	compositor.check_composite_glyphs = check_composite_glyphs;
+	compositor.composite_glyphs = composite_glyphs;
+    }
+
+    return &compositor.base;
+}
+
+#if PIXMAN_HAS_COMPOSITOR
+typedef struct _cairo_image_span_renderer {
+    cairo_span_renderer_t base;
+
+    pixman_image_compositor_t *compositor;
+    pixman_image_t *src, *mask;
+    float opacity;
+    cairo_rectangle_int_t extents;
+} cairo_image_span_renderer_t;
+COMPILE_TIME_ASSERT (sizeof (cairo_image_span_renderer_t) <= sizeof (cairo_abstract_span_renderer_t));
+
+static cairo_status_t
+_cairo_image_bounded_opaque_spans (void *abstract_renderer,
+				   int y, int height,
+				   const cairo_half_open_span_t *spans,
+				   unsigned num_spans)
+{
+    cairo_image_span_renderer_t *r = abstract_renderer;
+
+    if (num_spans == 0)
+	return CAIRO_STATUS_SUCCESS;
+
+    do {
+	if (spans[0].coverage)
+	    pixman_image_compositor_blt (r->compositor,
+					 spans[0].x, y,
+					 spans[1].x - spans[0].x, height,
+					 spans[0].coverage);
+	spans++;
+    } while (--num_spans > 1);
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_image_bounded_spans (void *abstract_renderer,
+			    int y, int height,
+			    const cairo_half_open_span_t *spans,
+			    unsigned num_spans)
+{
+    cairo_image_span_renderer_t *r = abstract_renderer;
+
+    if (num_spans == 0)
+	return CAIRO_STATUS_SUCCESS;
+
+    do {
+	if (spans[0].coverage) {
+	    pixman_image_compositor_blt (r->compositor,
+					 spans[0].x, y,
+					 spans[1].x - spans[0].x, height,
+					  r->opacity * spans[0].coverage);
+	}
+	spans++;
+    } while (--num_spans > 1);
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_image_unbounded_spans (void *abstract_renderer,
+			      int y, int height,
+			      const cairo_half_open_span_t *spans,
+			      unsigned num_spans)
+{
+    cairo_image_span_renderer_t *r = abstract_renderer;
+
+    assert (y + height <= r->extents.height);
+    if (y > r->extents.y) {
+	pixman_image_compositor_blt (r->compositor,
+				     r->extents.x, r->extents.y,
+				     r->extents.width, y - r->extents.y,
+				     0);
+    }
+
+    if (num_spans == 0) {
+	pixman_image_compositor_blt (r->compositor,
+				     r->extents.x, y,
+				     r->extents.width,  height,
+				     0);
+    } else {
+	if (spans[0].x != r->extents.x) {
+	    pixman_image_compositor_blt (r->compositor,
+					 r->extents.x, y,
+					 spans[0].x - r->extents.x,
+					 height,
+					 0);
+	}
+
+	do {
+	    assert (spans[0].x < r->extents.x + r->extents.width);
+	    pixman_image_compositor_blt (r->compositor,
+					 spans[0].x, y,
+					 spans[1].x - spans[0].x, height,
+					 r->opacity * spans[0].coverage);
+	    spans++;
+	} while (--num_spans > 1);
+
+	if (spans[0].x != r->extents.x + r->extents.width) {
+	    assert (spans[0].x < r->extents.x + r->extents.width);
+	    pixman_image_compositor_blt (r->compositor,
+					 spans[0].x,     y,
+					 r->extents.x + r->extents.width - spans[0].x, height,
+					 0);
+	}
+    }
+
+    r->extents.y = y + height;
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_image_clipped_spans (void *abstract_renderer,
+			    int y, int height,
+			    const cairo_half_open_span_t *spans,
+			    unsigned num_spans)
+{
+    cairo_image_span_renderer_t *r = abstract_renderer;
+
+    assert (num_spans);
+
+    do {
+	if (! spans[0].inverse)
+	    pixman_image_compositor_blt (r->compositor,
+					 spans[0].x, y,
+					 spans[1].x - spans[0].x, height,
+					 r->opacity * spans[0].coverage);
+	spans++;
+    } while (--num_spans > 1);
+
+    r->extents.y = y + height;
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_image_finish_unbounded_spans (void *abstract_renderer)
+{
+    cairo_image_span_renderer_t *r = abstract_renderer;
+
+    if (r->extents.y < r->extents.height) {
+	pixman_image_compositor_blt (r->compositor,
+				     r->extents.x, r->extents.y,
+				     r->extents.width,
+				     r->extents.height - r->extents.y,
+				     0);
+    }
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+span_renderer_init (cairo_abstract_span_renderer_t	*_r,
+		    const cairo_composite_rectangles_t *composite,
+		    cairo_bool_t			 needs_clip)
+{
+    cairo_image_span_renderer_t *r = (cairo_image_span_renderer_t *)_r;
+    cairo_image_surface_t *dst = (cairo_image_surface_t *)composite->surface;
+    const cairo_pattern_t *source = &composite->source_pattern.base;
+    cairo_operator_t op = composite->op;
+    int src_x, src_y;
+    int mask_x, mask_y;
+
+    if (op == CAIRO_OPERATOR_CLEAR) {
+	source = &_cairo_pattern_white.base;
+	op = PIXMAN_OP_OUT_REVERSE;
+    } else if (dst->base.is_clear &&
+	       (op == CAIRO_OPERATOR_SOURCE ||
+		op == CAIRO_OPERATOR_OVER ||
+		op == CAIRO_OPERATOR_ADD)) {
+	op = PIXMAN_OP_SRC;
+    } else if (op == CAIRO_OPERATOR_SOURCE) {
+	op = PIXMAN_OP_LERP;
+    } else {
+	op = _pixman_operator (op);
+    }
+
+    r->compositor = NULL;
+    r->mask = NULL;
+    r->src = _pixman_image_for_pattern (dst, source, FALSE,
+					&composite->unbounded,
+					&composite->source_sample_area,
+					&src_x, &src_y);
+    if (unlikely (r->src == NULL))
+	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+    r->opacity = 1.0;
+    if (composite->mask_pattern.base.type == CAIRO_PATTERN_TYPE_SOLID) {
+	r->opacity = composite->mask_pattern.solid.color.alpha;
+    } else {
+	r->mask = _pixman_image_for_pattern (dst,
+					     &composite->mask_pattern.base,
+					     TRUE,
+					     &composite->unbounded,
+					     &composite->mask_sample_area,
+					     &mask_x, &mask_y);
+	if (unlikely (r->mask == NULL))
+	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+	/* XXX Component-alpha? */
+	if ((dst->base.content & CAIRO_CONTENT_COLOR) == 0 &&
+	    _cairo_pattern_is_opaque (source, &composite->source_sample_area))
+	{
+	    pixman_image_unref (r->src);
+	    r->src = r->mask;
+	    src_x = mask_x;
+	    src_y = mask_y;
+	    r->mask = NULL;
+	}
+    }
+
+    if (composite->is_bounded) {
+	if (r->opacity == 1.)
+	    r->base.render_rows = _cairo_image_bounded_opaque_spans;
+	else
+	    r->base.render_rows = _cairo_image_bounded_spans;
+	r->base.finish = NULL;
+    } else {
+	if (needs_clip)
+	    r->base.render_rows = _cairo_image_clipped_spans;
+	else
+	    r->base.render_rows = _cairo_image_unbounded_spans;
+        r->base.finish = _cairo_image_finish_unbounded_spans;
+	r->extents = composite->unbounded;
+	r->extents.height += r->extents.y;
+    }
+
+    r->compositor =
+	pixman_image_create_compositor (op, r->src, r->mask, dst->pixman_image,
+					composite->unbounded.x + src_x,
+					composite->unbounded.y + src_y,
+					composite->unbounded.x + mask_x,
+					composite->unbounded.y + mask_y,
+					composite->unbounded.x,
+					composite->unbounded.y,
+					composite->unbounded.width,
+					composite->unbounded.height);
+    if (unlikely (r->compositor == NULL))
+	return CAIRO_INT_STATUS_NOTHING_TO_DO;
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static void
+span_renderer_fini (cairo_abstract_span_renderer_t *_r,
+		    cairo_int_status_t status)
+{
+    cairo_image_span_renderer_t *r = (cairo_image_span_renderer_t *) _r;
+
+    if (status == CAIRO_INT_STATUS_SUCCESS && r->base.finish)
+	r->base.finish (r);
+
+    if (r->compositor)
+	pixman_image_compositor_destroy (r->compositor);
+
+    if (r->src)
+	pixman_image_unref (r->src);
+    if (r->mask)
+	pixman_image_unref (r->mask);
+}
+#else
+typedef struct _cairo_image_span_renderer {
+    cairo_span_renderer_t base;
+
+    cairo_rectangle_int_t extents;
+
+    float opacity;
+    int stride;
+    uint8_t *data;
+
+    const cairo_composite_rectangles_t *composite;
+    pixman_image_t *src, *mask;
+    int src_x, src_y;
+
+    uint8_t op;
+
+    uint8_t buf[sizeof(cairo_abstract_span_renderer_t)-128];
+} cairo_image_span_renderer_t;
+COMPILE_TIME_ASSERT (sizeof (cairo_image_span_renderer_t) <= sizeof (cairo_abstract_span_renderer_t));
+
+static cairo_status_t
+_cairo_image_spans (void *abstract_renderer,
+		    int y, int height,
+		    const cairo_half_open_span_t *spans,
+		    unsigned num_spans)
+{
+    cairo_image_span_renderer_t *r = abstract_renderer;
+    uint8_t *mask, *row;
+    int len;
+
+    if (num_spans == 0)
+	return CAIRO_STATUS_SUCCESS;
+
+    mask = r->data + (y - r->extents.y) * r->stride;
+    mask += spans[0].x - r->extents.x;
+    row = mask;
+
+    do {
+	len = spans[1].x - spans[0].x;
+	if (spans[0].coverage) {
+	    *row++ = r->opacity * spans[0].coverage;
+	    if (--len)
+		memset (row, row[-1], len);
+	}
+	row += len;
+	spans++;
+    } while (--num_spans > 1);
+
+    len = row - mask;
+    row = mask;
+    while (--height) {
+	mask += r->stride;
+	memcpy (mask, row, len);
+    }
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_image_spans_and_zero (void *abstract_renderer,
+			     int y, int height,
+			     const cairo_half_open_span_t *spans,
+			     unsigned num_spans)
+{
+    cairo_image_span_renderer_t *r = abstract_renderer;
+    uint8_t *mask;
+    int len;
+
+    mask = r->data;
+    if (y > r->extents.y) {
+	len = (y - r->extents.y) * r->stride;
+	memset (mask, 0, len);
+	mask += len;
+    }
+
+    r->extents.y = y + height;
+    r->data = mask + height * r->stride;
+    if (num_spans == 0) {
+	memset (mask, 0, height * r->stride);
+    } else {
+	uint8_t *row = mask;
+
+	if (spans[0].x != r->extents.x) {
+	    len = spans[0].x - r->extents.x;
+	    memset (row, 0, len);
+	    row += len;
+	}
+
+	do {
+	    len = spans[1].x - spans[0].x;
+	    *row++ = r->opacity * spans[0].coverage;
+	    if (len > 1) {
+		memset (row, row[-1], --len);
+		row += len;
+	    }
+	    spans++;
+	} while (--num_spans > 1);
+
+	if (spans[0].x != r->extents.x + r->extents.width) {
+	    len = r->extents.x + r->extents.width - spans[0].x;
+	    memset (row, 0, len);
+	}
+
+	row = mask;
+	while (--height) {
+	    mask += r->stride;
+	    memcpy (mask, row, r->extents.width);
+	}
+    }
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_image_finish_spans_and_zero (void *abstract_renderer)
+{
+    cairo_image_span_renderer_t *r = abstract_renderer;
+
+    if (r->extents.y < r->extents.height)
+	memset (r->data, 0, (r->extents.height - r->extents.y) * r->stride);
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+span_renderer_init (cairo_abstract_span_renderer_t	*_r,
+		    const cairo_composite_rectangles_t *composite,
+		    cairo_bool_t			 needs_clip)
+{
+    cairo_image_span_renderer_t *r = (cairo_image_span_renderer_t *)_r;
+    cairo_image_surface_t *dst = (cairo_image_surface_t *)composite->surface;
+    const cairo_pattern_t *source = &composite->source_pattern.base;
+    cairo_operator_t op = composite->op;
+
+    r->composite = composite;
+    r->mask = NULL;
+    r->src = NULL;
+
+    if (needs_clip)
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+
+    if (op == CAIRO_OPERATOR_CLEAR) {
+	source = &_cairo_pattern_white.base;
+	op = PIXMAN_OP_OUT_REVERSE;
+    } else if (dst->base.is_clear &&
+	       (op == CAIRO_OPERATOR_SOURCE ||
+		op == CAIRO_OPERATOR_OVER ||
+		op == CAIRO_OPERATOR_ADD)) {
+	op = PIXMAN_OP_SRC;
+    } else if (op == CAIRO_OPERATOR_SOURCE) {
+#if PIXMAN_HAS_OP_LERP
+	op = PIXMAN_OP_LERP;
+#else
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+#endif
+    } else {
+	op = _pixman_operator (op);
+    }
+    r->op = op;
+
+    r->src = _pixman_image_for_pattern (dst, source, FALSE,
+					&composite->unbounded,
+					&composite->source_sample_area,
+					&r->src_x, &r->src_y);
+    if (unlikely (r->src == NULL))
+	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+    r->opacity = 1.0;
+    if (composite->mask_pattern.base.type == CAIRO_PATTERN_TYPE_SOLID) {
+	r->opacity = composite->mask_pattern.solid.color.alpha;
+    } else {
+	pixman_image_t *mask;
+	int mask_x, mask_y;
+
+	mask = _pixman_image_for_pattern (dst,
+					  &composite->mask_pattern.base,
+					  TRUE,
+					  &composite->unbounded,
+					  &composite->mask_sample_area,
+					  &mask_x, &mask_y);
+	if (unlikely (mask == NULL))
+	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+	/* XXX Component-alpha? */
+	if ((dst->base.content & CAIRO_CONTENT_COLOR) == 0 &&
+	    _cairo_pattern_is_opaque (source, &composite->source_sample_area))
+	{
+	    pixman_image_unref (r->src);
+	    r->src = mask;
+	    r->src_x = mask_x;
+	    r->src_y = mask_y;
+	    mask = NULL;
+	}
+
+	if (mask) {
+	    pixman_image_unref (mask);
+	    return CAIRO_INT_STATUS_UNSUPPORTED;
+	}
+    }
+
+    r->extents = composite->unbounded;
+    r->stride = (r->extents.width + 3) & ~3;
+    if (r->extents.height * r->stride > (int)sizeof (r->buf)) {
+	r->mask = pixman_image_create_bits (PIXMAN_a8,
+					    r->extents.width,
+					    r->extents.height,
+					    NULL, 0);
+
+	r->base.render_rows = _cairo_image_spans;
+	r->base.finish = NULL;
+    } else {
+	r->mask = pixman_image_create_bits (PIXMAN_a8,
+					    r->extents.width,
+					    r->extents.height,
+					    (uint32_t *)r->buf, r->stride);
+
+	r->base.render_rows = _cairo_image_spans_and_zero;
+	r->base.finish = _cairo_image_finish_spans_and_zero;
+    }
+    if (unlikely (r->mask == NULL))
+	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+    r->data = (uint8_t *) pixman_image_get_data (r->mask);
+    r->stride = pixman_image_get_stride (r->mask);
+
+    r->extents.height += r->extents.y;
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static void
+span_renderer_fini (cairo_abstract_span_renderer_t *_r,
+		    cairo_int_status_t status)
+{
+    cairo_image_span_renderer_t *r = (cairo_image_span_renderer_t *) _r;
+
+    if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
+	const cairo_composite_rectangles_t *composite = r->composite;
+
+	if (r->base.finish)
+	    r->base.finish (r);
+
+	pixman_image_composite32 (r->op, r->src, r->mask,
+				  to_pixman_image (composite->surface),
+				  composite->unbounded.x + r->src_x,
+				  composite->unbounded.y + r->src_y,
+				  0, 0,
+				  composite->unbounded.x,
+				  composite->unbounded.y,
+				  composite->unbounded.width,
+				  composite->unbounded.height);
+    }
+
+    if (r->src)
+	pixman_image_unref (r->src);
+    if (r->mask)
+	pixman_image_unref (r->mask);
+}
+#endif
+
+const cairo_compositor_t *
+_cairo_image_spans_compositor_get (void)
+{
+    static cairo_spans_compositor_t compositor;
+
+    if (compositor.base.delegate == NULL) {
+	_cairo_spans_compositor_init (&compositor,
+				      _cairo_image_traps_compositor_get());
+
+	//compositor.acquire = acquire;
+	//compositor.release = release;
+	compositor.fill_boxes = fill_boxes;
+	compositor.pattern_to_surface = _cairo_image_source_create_for_pattern;
+	//compositor.check_composite_boxes = check_composite_boxes;
+	compositor.composite_boxes = composite_boxes;
+	//compositor.check_span_renderer = check_span_renderer;
+	compositor.renderer_init = span_renderer_init;
+	compositor.renderer_fini = span_renderer_fini;
+    }
+
+    return &compositor.base;
+}
diff --git a/src/cairo-image-mask-compositor.c b/src/cairo-image-mask-compositor.c
new file mode 100644
index 0000000..33fd6dd
--- /dev/null
+++ b/src/cairo-image-mask-compositor.c
@@ -0,0 +1,408 @@
+/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2003 University of Southern California
+ * Copyright © 2009,2010,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>
+ */
+
+/* This compositor is slightly pointless. Just exists for testing
+ * and as skeleton code.
+ */
+
+#include "cairoint.h"
+
+#include "cairo-image-surface-private.h"
+
+#include "cairo-compositor-private.h"
+#include "cairo-region-private.h"
+
+static cairo_int_status_t
+acquire (void *abstract_dst)
+{
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+release (void *abstract_dst)
+{
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+set_clip_region (void *_surface,
+		 cairo_region_t *region)
+{
+    cairo_image_surface_t *surface = _surface;
+    pixman_region32_t *rgn = region ? &region->rgn : NULL;
+
+    if (! pixman_image_set_clip_region32 (surface->pixman_image, rgn))
+	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_bool_t
+has_snapshot (void *_dst,
+	      const cairo_pattern_t *pattern)
+{
+    return FALSE;
+}
+
+static cairo_int_status_t
+draw_image (void *_dst,
+	    cairo_image_surface_t *image,
+	    int src_x, int src_y,
+	    int width, int height,
+	    int dst_x, int dst_y)
+{
+    cairo_image_surface_t *dst = (cairo_image_surface_t *)_dst;
+
+    pixman_image_composite32 (PIXMAN_OP_SRC,
+			      image->pixman_image, NULL, dst->pixman_image,
+			      src_x, src_y,
+			      0, 0,
+			      dst_x, dst_y,
+			      width, height);
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static inline uint32_t
+color_to_uint32 (const cairo_color_t *color)
+{
+    return
+        (color->alpha_short >> 8 << 24) |
+        (color->red_short >> 8 << 16)   |
+        (color->green_short & 0xff00)   |
+        (color->blue_short >> 8);
+}
+
+static inline cairo_bool_t
+color_to_pixel (const cairo_color_t	*color,
+		double opacity,
+                pixman_format_code_t	 format,
+                uint32_t		*pixel)
+{
+    cairo_color_t opacity_color;
+    uint32_t c;
+
+    if (!(format == PIXMAN_a8r8g8b8     ||
+          format == PIXMAN_x8r8g8b8     ||
+          format == PIXMAN_a8b8g8r8     ||
+          format == PIXMAN_x8b8g8r8     ||
+          format == PIXMAN_b8g8r8a8     ||
+          format == PIXMAN_b8g8r8x8     ||
+          format == PIXMAN_r5g6b5       ||
+          format == PIXMAN_b5g6r5       ||
+          format == PIXMAN_a8))
+    {
+	return FALSE;
+    }
+
+    if (opacity != 1.0) {
+	_cairo_color_init_rgba (&opacity_color,
+				color->red,
+				color->green,
+				color->blue,
+				color->alpha * opacity);
+	color = &opacity_color;
+    }
+    c = color_to_uint32 (color);
+
+    if (PIXMAN_FORMAT_TYPE (format) == PIXMAN_TYPE_ABGR) {
+	c = ((c & 0xff000000) >>  0) |
+	    ((c & 0x00ff0000) >> 16) |
+	    ((c & 0x0000ff00) >>  0) |
+	    ((c & 0x000000ff) << 16);
+    }
+
+    if (PIXMAN_FORMAT_TYPE (format) == PIXMAN_TYPE_BGRA) {
+	c = ((c & 0xff000000) >> 24) |
+	    ((c & 0x00ff0000) >>  8) |
+	    ((c & 0x0000ff00) <<  8) |
+	    ((c & 0x000000ff) << 24);
+    }
+
+    if (format == PIXMAN_a8) {
+	c = c >> 24;
+    } else if (format == PIXMAN_r5g6b5 || format == PIXMAN_b5g6r5) {
+	c = ((((c) >> 3) & 0x001f) |
+	     (((c) >> 5) & 0x07e0) |
+	     (((c) >> 8) & 0xf800));
+    }
+
+    *pixel = c;
+    return TRUE;
+}
+
+static cairo_int_status_t
+fill_rectangles (void			*_dst,
+		 cairo_operator_t	 op,
+		 const cairo_color_t	*color,
+		 cairo_rectangle_int_t	*rects,
+		 int			 num_rects)
+{
+    cairo_image_surface_t *dst = _dst;
+    uint32_t pixel;
+    int i;
+
+    if (! color_to_pixel (color, 1.0, dst->pixman_format, &pixel))
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+
+    for (i = 0; i < num_rects; i++) {
+	pixman_fill ((uint32_t *) dst->data, dst->stride / sizeof (uint32_t),
+		     PIXMAN_FORMAT_BPP (dst->pixman_format),
+		     rects[i].x, rects[i].y,
+		     rects[i].width, rects[i].height,
+		     pixel);
+    }
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+fill_boxes (void		*_dst,
+	    cairo_operator_t	 op,
+	    const cairo_color_t	*color,
+	    cairo_boxes_t	*boxes)
+{
+    cairo_image_surface_t *dst = _dst;
+    struct _cairo_boxes_chunk *chunk;
+    uint32_t pixel;
+    int i;
+
+    assert (boxes->is_pixel_aligned);
+
+    if (! color_to_pixel (color, 1.0, dst->pixman_format, &pixel))
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+
+    for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
+	for (i = 0; i < chunk->count; i++) {
+	    int x1 = _cairo_fixed_integer_part (chunk->base[i].p1.x);
+	    int y1 = _cairo_fixed_integer_part (chunk->base[i].p1.y);
+	    int x2 = _cairo_fixed_integer_part (chunk->base[i].p2.x);
+	    int y2 = _cairo_fixed_integer_part (chunk->base[i].p2.y);
+	    pixman_fill ((uint32_t *) dst->data, dst->stride / sizeof (uint32_t),
+			 PIXMAN_FORMAT_BPP (dst->pixman_format),
+			 x1, y1, x2 - x1, y2 - y1,
+			 pixel);
+	}
+    }
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static pixman_op_t
+_pixman_operator (cairo_operator_t op)
+{
+    switch ((int) op) {
+    case CAIRO_OPERATOR_CLEAR:
+	return PIXMAN_OP_CLEAR;
+
+    case CAIRO_OPERATOR_SOURCE:
+	return PIXMAN_OP_SRC;
+    case CAIRO_OPERATOR_OVER:
+	return PIXMAN_OP_OVER;
+    case CAIRO_OPERATOR_IN:
+	return PIXMAN_OP_IN;
+    case CAIRO_OPERATOR_OUT:
+	return PIXMAN_OP_OUT;
+    case CAIRO_OPERATOR_ATOP:
+	return PIXMAN_OP_ATOP;
+
+    case CAIRO_OPERATOR_DEST:
+	return PIXMAN_OP_DST;
+    case CAIRO_OPERATOR_DEST_OVER:
+	return PIXMAN_OP_OVER_REVERSE;
+    case CAIRO_OPERATOR_DEST_IN:
+	return PIXMAN_OP_IN_REVERSE;
+    case CAIRO_OPERATOR_DEST_OUT:
+	return PIXMAN_OP_OUT_REVERSE;
+    case CAIRO_OPERATOR_DEST_ATOP:
+	return PIXMAN_OP_ATOP_REVERSE;
+
+    case CAIRO_OPERATOR_XOR:
+	return PIXMAN_OP_XOR;
+    case CAIRO_OPERATOR_ADD:
+	return PIXMAN_OP_ADD;
+    case CAIRO_OPERATOR_SATURATE:
+	return PIXMAN_OP_SATURATE;
+
+    case CAIRO_OPERATOR_MULTIPLY:
+	return PIXMAN_OP_MULTIPLY;
+    case CAIRO_OPERATOR_SCREEN:
+	return PIXMAN_OP_SCREEN;
+    case CAIRO_OPERATOR_OVERLAY:
+	return PIXMAN_OP_OVERLAY;
+    case CAIRO_OPERATOR_DARKEN:
+	return PIXMAN_OP_DARKEN;
+    case CAIRO_OPERATOR_LIGHTEN:
+	return PIXMAN_OP_LIGHTEN;
+    case CAIRO_OPERATOR_COLOR_DODGE:
+	return PIXMAN_OP_COLOR_DODGE;
+    case CAIRO_OPERATOR_COLOR_BURN:
+	return PIXMAN_OP_COLOR_BURN;
+    case CAIRO_OPERATOR_HARD_LIGHT:
+	return PIXMAN_OP_HARD_LIGHT;
+    case CAIRO_OPERATOR_SOFT_LIGHT:
+	return PIXMAN_OP_SOFT_LIGHT;
+    case CAIRO_OPERATOR_DIFFERENCE:
+	return PIXMAN_OP_DIFFERENCE;
+    case CAIRO_OPERATOR_EXCLUSION:
+	return PIXMAN_OP_EXCLUSION;
+    case CAIRO_OPERATOR_HSL_HUE:
+	return PIXMAN_OP_HSL_HUE;
+    case CAIRO_OPERATOR_HSL_SATURATION:
+	return PIXMAN_OP_HSL_SATURATION;
+    case CAIRO_OPERATOR_HSL_COLOR:
+	return PIXMAN_OP_HSL_COLOR;
+    case CAIRO_OPERATOR_HSL_LUMINOSITY:
+	return PIXMAN_OP_HSL_LUMINOSITY;
+
+    default:
+	ASSERT_NOT_REACHED;
+	return PIXMAN_OP_OVER;
+    }
+}
+
+static cairo_int_status_t
+composite (void			*_dst,
+	   cairo_operator_t	op,
+	   cairo_surface_t	*abstract_src,
+	   cairo_surface_t	*abstract_mask,
+	   int			src_x,
+	   int			src_y,
+	   int			mask_x,
+	   int			mask_y,
+	   int			dst_x,
+	   int			dst_y,
+	   unsigned int		width,
+	   unsigned int		height)
+{
+    cairo_image_surface_t *dst = _dst;
+    cairo_pixman_source_t *src = (cairo_pixman_source_t *)abstract_src;
+    cairo_pixman_source_t *mask = (cairo_pixman_source_t *)abstract_mask;
+    if (mask) {
+	pixman_image_composite32 (_pixman_operator (op),
+				  src->pixman_image, mask->pixman_image, dst->pixman_image,
+				  src_x, src_y,
+				  mask_x, mask_y,
+				  dst_x, dst_y,
+				  width, height);
+    } else {
+	pixman_image_composite32 (_pixman_operator (op),
+				  src->pixman_image, NULL, dst->pixman_image,
+				  src_x, src_y,
+				  0, 0,
+				  dst_x, dst_y,
+				  width, height);
+    }
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+composite_boxes (void			*_dst,
+		 cairo_operator_t	op,
+		 cairo_surface_t	*abstract_src,
+		 cairo_surface_t	*abstract_mask,
+		 int			src_x,
+		 int			src_y,
+		 int			mask_x,
+		 int			mask_y,
+		 int			dst_x,
+		 int			dst_y,
+		 cairo_boxes_t		*boxes)
+{
+    cairo_image_surface_t *dst = _dst;
+    cairo_pixman_source_t *src = (cairo_pixman_source_t *)abstract_src;
+    cairo_pixman_source_t *mask = (cairo_pixman_source_t *)abstract_mask;
+    struct _cairo_boxes_chunk *chunk;
+    int i;
+
+    assert (boxes->is_pixel_aligned);
+
+    op = _pixman_operator (op);
+    for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
+	for (i = 0; i < chunk->count; i++) {
+	    int x1 = _cairo_fixed_integer_part (chunk->base[i].p1.x);
+	    int y1 = _cairo_fixed_integer_part (chunk->base[i].p1.y);
+	    int x2 = _cairo_fixed_integer_part (chunk->base[i].p2.x);
+	    int y2 = _cairo_fixed_integer_part (chunk->base[i].p2.y);
+
+	    if (mask) {
+		pixman_image_composite32 (op,
+					  src->pixman_image, mask->pixman_image, dst->pixman_image,
+					  x1 + src_x, y1 + src_y,
+					  x1 + mask_x, y1 + mask_y,
+					  x1 + dst_x, y1 + dst_y,
+					  x2 - x1, y2 - y1);
+	    } else {
+		pixman_image_composite32 (op,
+					  src->pixman_image, NULL, dst->pixman_image,
+					  x1 + src_x, y1 + src_y,
+					  0, 0,
+					  x1 + dst_x, y1 + dst_y,
+					  x2 - x1, y2 - y1);
+	    }
+	}
+    }
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+const cairo_compositor_t *
+_cairo_image_mask_compositor_get (void)
+{
+    static cairo_mask_compositor_t compositor;
+
+    if (compositor.base.delegate == NULL) {
+	_cairo_mask_compositor_init (&compositor,
+				     _cairo_image_traps_compositor_get ());
+	compositor.acquire = acquire;
+	compositor.release = release;
+	compositor.set_clip_region = set_clip_region;
+	compositor.pattern_to_surface = _cairo_pixman_source_create_for_pattern;
+	compositor.has_snapshot = has_snapshot;
+	compositor.draw_image = draw_image;
+	compositor.fill_rectangles = fill_rectangles;
+	compositor.fill_boxes = fill_boxes;
+	//compositor.check_composite = check_composite;
+	compositor.composite = composite;
+	//compositor.check_composite_boxes = check_composite_boxes;
+	compositor.composite_boxes = composite_boxes;
+    }
+
+    return &compositor.base;
+}
diff --git a/src/cairo-image-source.c b/src/cairo-image-source.c
new file mode 100644
index 0000000..7c1eb82
--- /dev/null
+++ b/src/cairo-image-source.c
@@ -0,0 +1,975 @@
+/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2003 University of Southern California
+ * Copyright © 2009,2010,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>
+ */
+
+/* The purpose of this file/surface is to simply translate a pattern
+ * to a pixman_image_t and thence to feed it back to the general
+ * compositor interface.
+ */
+
+#include "cairoint.h"
+
+#include "cairo-image-surface-private.h"
+
+#include "cairo-compositor-private.h"
+#include "cairo-error-private.h"
+#include "cairo-pattern-private.h"
+#include "cairo-paginated-private.h"
+#include "cairo-recording-surface-private.h"
+#include "cairo-surface-observer-private.h"
+#include "cairo-surface-snapshot-private.h"
+#include "cairo-surface-subsurface-private.h"
+
+#define PIXMAN_MAX_INT ((pixman_fixed_1 >> 1) - pixman_fixed_e) /* need to ensure deltas also fit */
+
+#if CAIRO_NO_MUTEX
+#define PIXMAN_HAS_ATOMIC_OPS 1
+#endif
+
+#if PIXMAN_HAS_ATOMIC_OPS
+static pixman_image_t *__pixman_transparent_image;
+static pixman_image_t *__pixman_black_image;
+static pixman_image_t *__pixman_white_image;
+
+static pixman_image_t *
+_pixman_transparent_image (void)
+{
+    pixman_image_t *image;
+
+    image = __pixman_transparent_image;
+    if (unlikely (image == NULL)) {
+	pixman_color_t color;
+
+	color.red   = 0x00;
+	color.green = 0x00;
+	color.blue  = 0x00;
+	color.alpha = 0x00;
+
+	image = pixman_image_create_solid_fill (&color);
+	if (unlikely (image == NULL))
+	    return NULL;
+
+	if (_cairo_atomic_ptr_cmpxchg (&__pixman_transparent_image,
+				       NULL, image))
+	{
+	    pixman_image_ref (image);
+	}
+    } else {
+	pixman_image_ref (image);
+    }
+
+    return image;
+}
+
+static pixman_image_t *
+_pixman_black_image (void)
+{
+    pixman_image_t *image;
+
+    image = __pixman_black_image;
+    if (unlikely (image == NULL)) {
+	pixman_color_t color;
+
+	color.red   = 0x00;
+	color.green = 0x00;
+	color.blue  = 0x00;
+	color.alpha = 0xffff;
+
+	image = pixman_image_create_solid_fill (&color);
+	if (unlikely (image == NULL))
+	    return NULL;
+
+	if (_cairo_atomic_ptr_cmpxchg (&__pixman_black_image,
+				       NULL, image))
+	{
+	    pixman_image_ref (image);
+	}
+    } else {
+	pixman_image_ref (image);
+    }
+
+    return image;
+}
+
+static pixman_image_t *
+_pixman_white_image (void)
+{
+    pixman_image_t *image;
+
+    image = __pixman_white_image;
+    if (unlikely (image == NULL)) {
+	pixman_color_t color;
+
+	color.red   = 0xffff;
+	color.green = 0xffff;
+	color.blue  = 0xffff;
+	color.alpha = 0xffff;
+
+	image = pixman_image_create_solid_fill (&color);
+	if (unlikely (image == NULL))
+	    return NULL;
+
+	if (_cairo_atomic_ptr_cmpxchg (&__pixman_white_image,
+				       NULL, image))
+	{
+	    pixman_image_ref (image);
+	}
+    } else {
+	pixman_image_ref (image);
+    }
+
+    return image;
+}
+
+static uint32_t
+hars_petruska_f54_1_random (void)
+{
+#define rol(x,k) ((x << k) | (x >> (32-k)))
+    static uint32_t x;
+    return x = (x ^ rol (x, 5) ^ rol (x, 24)) + 0x37798849;
+#undef rol
+}
+
+static struct {
+    cairo_color_t color;
+    pixman_image_t *image;
+} cache[16];
+static int n_cached;
+
+#else  /* !PIXMAN_HAS_ATOMIC_OPS */
+static pixman_image_t *
+_pixman_transparent_image (void)
+{
+    return _pixman_image_for_color (CAIRO_COLOR_TRANSPARENT);
+}
+
+static pixman_image_t *
+_pixman_black_image (void)
+{
+    return _pixman_image_for_color (CAIRO_COLOR_BLACK);
+}
+
+static pixman_image_t *
+_pixman_white_image (void)
+{
+    return _pixman_image_for_color (CAIRO_COLOR_WHITE);
+}
+#endif /* !PIXMAN_HAS_ATOMIC_OPS */
+
+
+pixman_image_t *
+_pixman_image_for_color (const cairo_color_t *cairo_color)
+{
+    pixman_color_t color;
+    pixman_image_t *image;
+
+#if PIXMAN_HAS_ATOMIC_OPS
+    int i;
+
+    if (CAIRO_COLOR_IS_CLEAR (cairo_color))
+	return _pixman_transparent_image ();
+
+    if (CAIRO_COLOR_IS_OPAQUE (cairo_color)) {
+	if (cairo_color->red_short <= 0x00ff &&
+	    cairo_color->green_short <= 0x00ff &&
+	    cairo_color->blue_short <= 0x00ff)
+	{
+	    return _pixman_black_image ();
+	}
+
+	if (cairo_color->red_short >= 0xff00 &&
+	    cairo_color->green_short >= 0xff00 &&
+	    cairo_color->blue_short >= 0xff00)
+	{
+	    return _pixman_white_image ();
+	}
+    }
+
+    CAIRO_MUTEX_LOCK (_cairo_image_solid_cache_mutex);
+    for (i = 0; i < n_cached; i++) {
+	if (_cairo_color_equal (&cache[i].color, cairo_color)) {
+	    image = pixman_image_ref (cache[i].image);
+	    goto UNLOCK;
+	}
+    }
+#endif
+
+    color.red   = cairo_color->red_short;
+    color.green = cairo_color->green_short;
+    color.blue  = cairo_color->blue_short;
+    color.alpha = cairo_color->alpha_short;
+
+    image = pixman_image_create_solid_fill (&color);
+#if PIXMAN_HAS_ATOMIC_OPS
+    if (image == NULL)
+	goto UNLOCK;
+
+    if (n_cached < ARRAY_LENGTH (cache)) {
+	i = n_cached++;
+    } else {
+	i = hars_petruska_f54_1_random () % ARRAY_LENGTH (cache);
+	pixman_image_unref (cache[i].image);
+    }
+    cache[i].image = pixman_image_ref (image);
+    cache[i].color = *cairo_color;
+
+UNLOCK:
+    CAIRO_MUTEX_UNLOCK (_cairo_image_solid_cache_mutex);
+#endif
+    return image;
+}
+
+
+void
+_cairo_image_reset_static_data (void)
+{
+#if PIXMAN_HAS_ATOMIC_OPS
+    while (n_cached)
+	pixman_image_unref (cache[--n_cached].image);
+
+    if (__pixman_transparent_image) {
+	pixman_image_unref (__pixman_transparent_image);
+	__pixman_transparent_image = NULL;
+    }
+
+    if (__pixman_black_image) {
+	pixman_image_unref (__pixman_black_image);
+	__pixman_black_image = NULL;
+    }
+
+    if (__pixman_white_image) {
+	pixman_image_unref (__pixman_white_image);
+	__pixman_white_image = NULL;
+    }
+#endif
+}
+
+static pixman_image_t *
+_pixman_image_for_gradient (const cairo_gradient_pattern_t *pattern,
+			    const cairo_rectangle_int_t *extents,
+			    int *ix, int *iy)
+{
+    pixman_image_t	  *pixman_image;
+    pixman_gradient_stop_t pixman_stops_static[2];
+    pixman_gradient_stop_t *pixman_stops = pixman_stops_static;
+    pixman_transform_t      pixman_transform;
+    cairo_matrix_t matrix;
+    cairo_circle_double_t extremes[2];
+    pixman_point_fixed_t p1, p2;
+    unsigned int i;
+    cairo_int_status_t status;
+
+    if (pattern->n_stops > ARRAY_LENGTH(pixman_stops_static)) {
+	pixman_stops = _cairo_malloc_ab (pattern->n_stops,
+					 sizeof(pixman_gradient_stop_t));
+	if (unlikely (pixman_stops == NULL))
+	    return NULL;
+    }
+
+    for (i = 0; i < pattern->n_stops; i++) {
+	pixman_stops[i].x = _cairo_fixed_16_16_from_double (pattern->stops[i].offset);
+	pixman_stops[i].color.red   = pattern->stops[i].color.red_short;
+	pixman_stops[i].color.green = pattern->stops[i].color.green_short;
+	pixman_stops[i].color.blue  = pattern->stops[i].color.blue_short;
+	pixman_stops[i].color.alpha = pattern->stops[i].color.alpha_short;
+    }
+
+    _cairo_gradient_pattern_fit_to_range (pattern, PIXMAN_MAX_INT >> 1, &matrix, extremes);
+
+    p1.x = _cairo_fixed_16_16_from_double (extremes[0].center.x);
+    p1.y = _cairo_fixed_16_16_from_double (extremes[0].center.y);
+    p2.x = _cairo_fixed_16_16_from_double (extremes[1].center.x);
+    p2.y = _cairo_fixed_16_16_from_double (extremes[1].center.y);
+
+    if (pattern->base.type == CAIRO_PATTERN_TYPE_LINEAR) {
+	pixman_image = pixman_image_create_linear_gradient (&p1, &p2,
+							    pixman_stops,
+							    pattern->n_stops);
+    } else {
+	pixman_fixed_t r1, r2;
+
+	r1   = _cairo_fixed_16_16_from_double (extremes[0].radius);
+	r2   = _cairo_fixed_16_16_from_double (extremes[1].radius);
+
+	pixman_image = pixman_image_create_radial_gradient (&p1, &p2, r1, r2,
+							    pixman_stops,
+							    pattern->n_stops);
+    }
+
+    if (pixman_stops != pixman_stops_static)
+	free (pixman_stops);
+
+    if (unlikely (pixman_image == NULL))
+	return NULL;
+
+    *ix = *iy = 0;
+    status = _cairo_matrix_to_pixman_matrix_offset (&matrix, pattern->base.filter,
+						    extents->x + extents->width/2.,
+						    extents->y + extents->height/2.,
+						    &pixman_transform, ix, iy);
+    if (status != CAIRO_INT_STATUS_NOTHING_TO_DO) {
+	if (unlikely (status != CAIRO_INT_STATUS_SUCCESS) ||
+	    ! pixman_image_set_transform (pixman_image, &pixman_transform))
+	{
+	    pixman_image_unref (pixman_image);
+	    return NULL;
+	}
+    }
+
+    {
+	pixman_repeat_t pixman_repeat;
+
+	switch (pattern->base.extend) {
+	default:
+	case CAIRO_EXTEND_NONE:
+	    pixman_repeat = PIXMAN_REPEAT_NONE;
+	    break;
+	case CAIRO_EXTEND_REPEAT:
+	    pixman_repeat = PIXMAN_REPEAT_NORMAL;
+	    break;
+	case CAIRO_EXTEND_REFLECT:
+	    pixman_repeat = PIXMAN_REPEAT_REFLECT;
+	    break;
+	case CAIRO_EXTEND_PAD:
+	    pixman_repeat = PIXMAN_REPEAT_PAD;
+	    break;
+	}
+
+	pixman_image_set_repeat (pixman_image, pixman_repeat);
+    }
+
+    return pixman_image;
+}
+
+static pixman_image_t *
+_pixman_image_for_mesh (const cairo_mesh_pattern_t *pattern,
+			const cairo_rectangle_int_t *extents,
+			int *tx, int *ty)
+{
+    pixman_image_t *image;
+    int width, height;
+
+    *tx = -extents->x;
+    *ty = -extents->y;
+    width = extents->width;
+    height = extents->height;
+
+    image = pixman_image_create_bits (PIXMAN_a8r8g8b8, width, height, NULL, 0);
+    if (unlikely (image == NULL))
+	return NULL;
+
+    _cairo_mesh_pattern_rasterize (pattern,
+				   pixman_image_get_data (image),
+				   width, height,
+				   pixman_image_get_stride (image),
+				   *tx, *ty);
+    return image;
+}
+
+struct acquire_source_cleanup {
+    cairo_surface_t *surface;
+    cairo_image_surface_t *image;
+    void *image_extra;
+};
+
+static void
+_acquire_source_cleanup (pixman_image_t *pixman_image,
+			 void *closure)
+{
+    struct acquire_source_cleanup *data = closure;
+
+    _cairo_surface_release_source_image (data->surface,
+					 data->image,
+					 data->image_extra);
+    free (data);
+}
+
+static uint16_t
+expand_channel (uint16_t v, uint32_t bits)
+{
+    int offset = 16 - bits;
+    while (offset > 0) {
+	v |= v >> bits;
+	offset -= bits;
+	bits += bits;
+    }
+    return v;
+}
+
+static pixman_image_t *
+_pixel_to_solid (cairo_image_surface_t *image, int x, int y)
+{
+    uint32_t pixel;
+    pixman_color_t color;
+
+    switch (image->format) {
+    default:
+    case CAIRO_FORMAT_INVALID:
+	ASSERT_NOT_REACHED;
+	return NULL;
+
+    case CAIRO_FORMAT_A1:
+	pixel = *(uint8_t *) (image->data + y * image->stride + x/8);
+	return pixel & (1 << (x&7)) ? _pixman_black_image () : _pixman_transparent_image ();
+
+    case CAIRO_FORMAT_A8:
+	color.alpha = *(uint8_t *) (image->data + y * image->stride + x);
+	color.alpha |= color.alpha << 8;
+	if (color.alpha == 0)
+	    return _pixman_transparent_image ();
+	if (color.alpha == 0xffff)
+	    return _pixman_black_image ();
+
+	color.red = color.green = color.blue = 0;
+	return pixman_image_create_solid_fill (&color);
+
+    case CAIRO_FORMAT_RGB16_565:
+	pixel = *(uint16_t *) (image->data + y * image->stride + 2 * x);
+	if (pixel == 0)
+	    return _pixman_black_image ();
+	if (pixel == 0xffff)
+	    return _pixman_white_image ();
+
+	color.alpha = 0xffff;
+	color.red = expand_channel ((pixel >> 11 & 0x1f) << 11, 5);
+	color.green = expand_channel ((pixel >> 5 & 0x3f) << 10, 6);
+	color.blue = expand_channel ((pixel & 0x1f) << 11, 5);
+	return pixman_image_create_solid_fill (&color);
+
+    case CAIRO_FORMAT_RGB30:
+	pixel = *(uint32_t *) (image->data + y * image->stride + 4 * x);
+	pixel &= 0x3fffffff; /* ignore alpha bits */
+	if (pixel == 0)
+	    return _pixman_black_image ();
+	if (pixel == 0x3fffffff)
+	    return _pixman_white_image ();
+
+	/* convert 10bpc to 16bpc */
+	color.alpha = 0xffff;
+	color.red = expand_channel((pixel >> 20) & 0x3fff, 10);
+	color.green = expand_channel((pixel >> 10) & 0x3fff, 10);
+	color.blue = expand_channel(pixel & 0x3fff, 10);
+	return pixman_image_create_solid_fill (&color);
+
+    case CAIRO_FORMAT_ARGB32:
+    case CAIRO_FORMAT_RGB24:
+	pixel = *(uint32_t *) (image->data + y * image->stride + 4 * x);
+	color.alpha = image->format == CAIRO_FORMAT_ARGB32 ? (pixel >> 24) | (pixel >> 16 & 0xff00) : 0xffff;
+	if (color.alpha == 0)
+	    return _pixman_transparent_image ();
+	if (pixel == 0xffffffff)
+	    return _pixman_white_image ();
+	if (color.alpha == 0xffff && (pixel & 0xffffff) == 0)
+	    return _pixman_black_image ();
+
+	color.red = (pixel >> 16 & 0xff) | (pixel >> 8 & 0xff00);
+	color.green = (pixel >> 8 & 0xff) | (pixel & 0xff00);
+	color.blue = (pixel & 0xff) | (pixel << 8 & 0xff00);
+	return pixman_image_create_solid_fill (&color);
+    }
+}
+
+static cairo_bool_t
+_pixman_image_set_properties (pixman_image_t *pixman_image,
+			      const cairo_pattern_t *pattern,
+			      const cairo_rectangle_int_t *extents,
+			      int *ix,int *iy)
+{
+    pixman_transform_t pixman_transform;
+    cairo_int_status_t status;
+
+    status = _cairo_matrix_to_pixman_matrix_offset (&pattern->matrix,
+						    pattern->filter,
+						    extents->x + extents->width/2.,
+						    extents->y + extents->height/2.,
+						    &pixman_transform, ix, iy);
+    if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
+    {
+	/* If the transform is an identity, we don't need to set it
+	 * and we can use any filtering, so choose the fastest one. */
+	pixman_image_set_filter (pixman_image, PIXMAN_FILTER_NEAREST, NULL, 0);
+    }
+    else if (unlikely (status != CAIRO_INT_STATUS_SUCCESS ||
+		       ! pixman_image_set_transform (pixman_image,
+						     &pixman_transform)))
+    {
+	return FALSE;
+    }
+    else
+    {
+	pixman_filter_t pixman_filter;
+
+	switch (pattern->filter) {
+	case CAIRO_FILTER_FAST:
+	    pixman_filter = PIXMAN_FILTER_FAST;
+	    break;
+	case CAIRO_FILTER_GOOD:
+	    pixman_filter = PIXMAN_FILTER_GOOD;
+	    break;
+	case CAIRO_FILTER_BEST:
+	    pixman_filter = PIXMAN_FILTER_BEST;
+	    break;
+	case CAIRO_FILTER_NEAREST:
+	    pixman_filter = PIXMAN_FILTER_NEAREST;
+	    break;
+	case CAIRO_FILTER_BILINEAR:
+	    pixman_filter = PIXMAN_FILTER_BILINEAR;
+	    break;
+	case CAIRO_FILTER_GAUSSIAN:
+	    /* XXX: The GAUSSIAN value has no implementation in cairo
+	     * whatsoever, so it was really a mistake to have it in the
+	     * API. We could fix this by officially deprecating it, or
+	     * else inventing semantics and providing an actual
+	     * implementation for it. */
+	default:
+	    pixman_filter = PIXMAN_FILTER_BEST;
+	}
+
+	pixman_image_set_filter (pixman_image, pixman_filter, NULL, 0);
+    }
+
+    {
+	pixman_repeat_t pixman_repeat;
+
+	switch (pattern->extend) {
+	default:
+	case CAIRO_EXTEND_NONE:
+	    pixman_repeat = PIXMAN_REPEAT_NONE;
+	    break;
+	case CAIRO_EXTEND_REPEAT:
+	    pixman_repeat = PIXMAN_REPEAT_NORMAL;
+	    break;
+	case CAIRO_EXTEND_REFLECT:
+	    pixman_repeat = PIXMAN_REPEAT_REFLECT;
+	    break;
+	case CAIRO_EXTEND_PAD:
+	    pixman_repeat = PIXMAN_REPEAT_PAD;
+	    break;
+	}
+
+	pixman_image_set_repeat (pixman_image, pixman_repeat);
+    }
+
+    if (pattern->has_component_alpha)
+	pixman_image_set_component_alpha (pixman_image, TRUE);
+
+    return TRUE;
+}
+
+static pixman_image_t *
+_pixman_image_for_recording (cairo_image_surface_t *dst,
+			     const cairo_surface_pattern_t *pattern,
+			     cairo_bool_t is_mask,
+			     const cairo_rectangle_int_t *extents,
+			     const cairo_rectangle_int_t *sample,
+			     int *ix, int *iy)
+{
+    cairo_surface_t *source, *clone;
+    cairo_rectangle_int_t limit;
+    pixman_image_t *pixman_image;
+    cairo_status_t status;
+    cairo_extend_t extend;
+    cairo_matrix_t *m, matrix;
+    int tx = 0, ty = 0;
+
+    *ix = *iy = 0;
+
+    source = pattern->surface;
+    if (_cairo_surface_is_subsurface (source))
+	source = _cairo_surface_subsurface_get_target_with_offset (source, &tx, &ty);
+    if (_cairo_surface_is_snapshot (source))
+	source = _cairo_surface_snapshot_get_target (source);
+    if (_cairo_surface_is_observer (source))
+	source = _cairo_surface_observer_get_target (source);
+    if (_cairo_surface_is_paginated (source))
+	source = _cairo_paginated_surface_get_target (source);
+
+    extend = pattern->base.extend;
+    if (_cairo_surface_get_extents (source, &limit)) {
+	if (sample->x >= limit.x &&
+	    sample->y >= limit.y &&
+	    sample->x + sample->width <= limit.x + limit.width &&
+	    sample->y + sample->height <= limit.y + limit.height)
+	{
+	    extend = CAIRO_EXTEND_NONE;
+	}
+	else if (extend == CAIRO_EXTEND_NONE &&
+		 (sample->x + sample->width <= limit.x ||
+		  sample->x >= limit.x + limit.width ||
+		  sample->y + sample->height <= limit.y ||
+		  sample->y >= limit.y + limit.height))
+	{
+	    return _pixman_transparent_image ();
+	}
+    } else
+	extend = CAIRO_EXTEND_NONE;
+
+    if (extents == CAIRO_EXTEND_NONE)
+	limit = *extents;
+
+    clone = cairo_image_surface_create (dst->format, limit.width, limit.height);
+    cairo_surface_set_device_offset (clone, limit.x, limit.y);
+
+    m = NULL;
+    if (extend == CAIRO_EXTEND_NONE) {
+	m = &matrix;
+	cairo_matrix_multiply (m,
+			       &dst->base.device_transform,
+			       &pattern->base.matrix);
+	if (tx | ty)
+	    cairo_matrix_translate (m, tx, ty);
+    } else {
+	/* XXX extract scale factor for repeating patterns */
+    }
+
+    status = _cairo_recording_surface_replay_with_clip (source, m, clone, NULL);
+    if (unlikely (status)) {
+	cairo_surface_destroy (clone);
+	return NULL;
+    }
+
+    pixman_image = pixman_image_ref (((cairo_image_surface_t *)clone)->pixman_image);
+    cairo_surface_destroy (clone);
+
+    if (extend != CAIRO_EXTEND_NONE) {
+	if (! _pixman_image_set_properties (pixman_image,
+					    &pattern->base, extents,
+					    ix, iy)) {
+	    pixman_image_unref (pixman_image);
+	    pixman_image= NULL;
+	}
+    }
+
+
+    return pixman_image;
+}
+
+static pixman_image_t *
+_pixman_image_for_surface (cairo_image_surface_t *dst,
+			   const cairo_surface_pattern_t *pattern,
+			   cairo_bool_t is_mask,
+			   const cairo_rectangle_int_t *extents,
+			   const cairo_rectangle_int_t *sample,
+			   int *ix, int *iy)
+{
+    cairo_extend_t extend = pattern->base.extend;
+    pixman_image_t *pixman_image;
+
+    *ix = *iy = 0;
+    pixman_image = NULL;
+    if (pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING)
+	return _pixman_image_for_recording(dst, pattern,
+					   is_mask, extents, sample,
+					   ix, iy);
+
+    if (pattern->surface->type == CAIRO_SURFACE_TYPE_IMAGE &&
+	(! is_mask || ! pattern->base.has_component_alpha ||
+	 (pattern->surface->content & CAIRO_CONTENT_COLOR) == 0))
+    {
+	cairo_image_surface_t *source = (cairo_image_surface_t *) pattern->surface;
+	cairo_surface_type_t type;
+
+	if (_cairo_surface_is_snapshot (&source->base))
+	    source = (cairo_image_surface_t *) _cairo_surface_snapshot_get_target (&source->base);
+
+	type = source->base.backend->type;
+	if (type == CAIRO_SURFACE_TYPE_IMAGE) {
+	    if (extend != CAIRO_EXTEND_NONE &&
+		sample->x >= 0 &&
+		sample->y >= 0 &&
+		sample->x + sample->width  <= source->width &&
+		sample->y + sample->height <= source->height)
+	    {
+		extend = CAIRO_EXTEND_NONE;
+	    }
+
+	    if (sample->width == 1 && sample->height == 1) {
+		if (sample->x < 0 ||
+		    sample->y < 0 ||
+		    sample->x >= source->width ||
+		    sample->y >= source->height)
+		{
+		    if (extend == CAIRO_EXTEND_NONE)
+			return _pixman_transparent_image ();
+		}
+		else
+		{
+		    pixman_image = _pixel_to_solid (source,
+						    sample->x, sample->y);
+                    if (pixman_image)
+                        return pixman_image;
+		}
+	    }
+
+#if PIXMAN_HAS_ATOMIC_OPS
+	    /* avoid allocating a 'pattern' image if we can reuse the original */
+	    *ix = *iy = 0;
+	    if (extend == CAIRO_EXTEND_NONE &&
+		_cairo_matrix_is_pixman_translation (&pattern->base.matrix,
+						     pattern->base.filter,
+						     ix, iy))
+	    {
+		return pixman_image_ref (source->pixman_image);
+	    }
+#endif
+
+	    pixman_image = pixman_image_create_bits (source->pixman_format,
+						     source->width,
+						     source->height,
+						     (uint32_t *) source->data,
+						     source->stride);
+	    if (unlikely (pixman_image == NULL))
+		return NULL;
+	} else if (type == CAIRO_SURFACE_TYPE_SUBSURFACE) {
+	    cairo_surface_subsurface_t *sub;
+	    cairo_bool_t is_contained = FALSE;
+
+	    sub = (cairo_surface_subsurface_t *) source;
+	    source = (cairo_image_surface_t *) sub->target;
+
+	    if (sample->x >= 0 &&
+		sample->y >= 0 &&
+		sample->x + sample->width  <= sub->extents.width &&
+		sample->y + sample->height <= sub->extents.height)
+	    {
+		is_contained = TRUE;
+	    }
+
+	    if (sample->width == 1 && sample->height == 1) {
+		if (is_contained) {
+		    pixman_image = _pixel_to_solid (source,
+                                                    sub->extents.x + sample->x,
+                                                    sub->extents.y + sample->y);
+                    if (pixman_image)
+                        return pixman_image;
+		} else {
+		    if (extend == CAIRO_EXTEND_NONE)
+			return _pixman_transparent_image ();
+		}
+	    }
+
+#if PIXMAN_HAS_ATOMIC_OPS
+	    *ix = sub->extents.x;
+	    *iy = sub->extents.y;
+	    if (is_contained &&
+		_cairo_matrix_is_pixman_translation (&pattern->base.matrix,
+						     pattern->base.filter,
+						     ix, iy))
+	    {
+		return pixman_image_ref (source->pixman_image);
+	    }
+#endif
+
+	    /* Avoid sub-byte offsets, force a copy in that case. */
+	    if (PIXMAN_FORMAT_BPP (source->pixman_format) >= 8) {
+		void *data = source->data
+		    + sub->extents.x * PIXMAN_FORMAT_BPP(source->pixman_format)/8
+		    + sub->extents.y * source->stride;
+		pixman_image = pixman_image_create_bits (source->pixman_format,
+							 sub->extents.width,
+							 sub->extents.height,
+							 data,
+							 source->stride);
+		if (unlikely (pixman_image == NULL))
+		    return NULL;
+	    }
+	}
+    }
+
+#if PIXMAN_HAS_ATOMIC_OPS
+    *ix = *iy = 0;
+#endif
+    if (pixman_image == NULL) {
+	struct acquire_source_cleanup *cleanup;
+	cairo_image_surface_t *image;
+	void *extra;
+	cairo_status_t status;
+
+	status = _cairo_surface_acquire_source_image (pattern->surface, &image, &extra);
+	if (unlikely (status))
+	    return NULL;
+
+	if (sample->x >= 0 && sample->y >= 0 &&
+	    sample->x + sample->width  <= image->width &&
+	    sample->y + sample->height <= image->height)
+	{
+	    extend = CAIRO_EXTEND_NONE;
+	}
+
+	if (sample->width == 1 && sample->height == 1) {
+	    if (sample->x < 0 ||
+		sample->y < 0 ||
+		sample->x >= image->width ||
+		sample->y >= image->height)
+	    {
+		if (extend == CAIRO_EXTEND_NONE) {
+		    pixman_image = _pixman_transparent_image ();
+		    _cairo_surface_release_source_image (pattern->surface, image, extra);
+		    return pixman_image;
+		}
+	    }
+	    else
+	    {
+		pixman_image = _pixel_to_solid (image, sample->x, sample->y);
+                if (pixman_image) {
+                    _cairo_surface_release_source_image (pattern->surface, image, extra);
+                    return pixman_image;
+                }
+	    }
+	}
+
+	pixman_image = pixman_image_create_bits (image->pixman_format,
+						 image->width,
+						 image->height,
+						 (uint32_t *) image->data,
+						 image->stride);
+	if (unlikely (pixman_image == NULL)) {
+	    _cairo_surface_release_source_image (pattern->surface, image, extra);
+	    return NULL;
+	}
+
+	cleanup = malloc (sizeof (*cleanup));
+	if (unlikely (cleanup == NULL)) {
+	    _cairo_surface_release_source_image (pattern->surface, image, extra);
+	    pixman_image_unref (pixman_image);
+	    return NULL;
+	}
+
+	cleanup->surface = pattern->surface;
+	cleanup->image = image;
+	cleanup->image_extra = extra;
+	pixman_image_set_destroy_function (pixman_image,
+					   _acquire_source_cleanup, cleanup);
+    }
+
+    if (! _pixman_image_set_properties (pixman_image,
+					&pattern->base, extents,
+					ix, iy)) {
+	pixman_image_unref (pixman_image);
+	pixman_image= NULL;
+    }
+
+    return pixman_image;
+}
+
+pixman_image_t *
+_pixman_image_for_pattern (cairo_image_surface_t *dst,
+			   const cairo_pattern_t *pattern,
+			   cairo_bool_t is_mask,
+			   const cairo_rectangle_int_t *extents,
+			   const cairo_rectangle_int_t *sample,
+			   int *tx, int *ty)
+{
+    *tx = *ty = 0;
+
+    if (pattern == NULL)
+	return _pixman_white_image ();
+
+    switch (pattern->type) {
+    default:
+	ASSERT_NOT_REACHED;
+    case CAIRO_PATTERN_TYPE_SOLID:
+	return _pixman_image_for_color (&((const cairo_solid_pattern_t *) pattern)->color);
+
+    case CAIRO_PATTERN_TYPE_RADIAL:
+    case CAIRO_PATTERN_TYPE_LINEAR:
+	return _pixman_image_for_gradient ((const cairo_gradient_pattern_t *) pattern,
+					   extents, tx, ty);
+
+    case CAIRO_PATTERN_TYPE_MESH:
+	return _pixman_image_for_mesh ((const cairo_mesh_pattern_t *) pattern,
+					   extents, tx, ty);
+
+    case CAIRO_PATTERN_TYPE_SURFACE:
+	return _pixman_image_for_surface (dst,
+					  (const cairo_surface_pattern_t *) pattern,
+					  is_mask, extents, sample,
+					  tx, ty);
+
+    }
+}
+
+static cairo_status_t
+_cairo_image_source_finish (void *abstract_surface)
+{
+    cairo_image_source_t *source = abstract_surface;
+
+    pixman_image_unref (source->pixman_image);
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static const cairo_surface_backend_t cairo_image_source_backend = {
+    CAIRO_SURFACE_TYPE_IMAGE,
+    _cairo_image_source_finish,
+    NULL, /* read-only wrapper */
+};
+
+cairo_surface_t *
+_cairo_image_source_create_for_pattern (cairo_surface_t *dst,
+					 const cairo_pattern_t *pattern,
+					 cairo_bool_t is_mask,
+					 const cairo_rectangle_int_t *extents,
+					 const cairo_rectangle_int_t *sample,
+					 int *src_x, int *src_y)
+{
+    cairo_image_source_t *source;
+
+    source = malloc (sizeof (cairo_image_source_t));
+    if (unlikely (source == NULL))
+	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
+
+    source->pixman_image =
+	_pixman_image_for_pattern ((cairo_image_surface_t *)dst,
+				   pattern, is_mask,
+				   extents, sample,
+				   src_x, src_y);
+    if (unlikely (source->pixman_image == NULL)) {
+	free (source);
+	return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);
+    }
+
+    _cairo_surface_init (&source->base,
+			 &cairo_image_source_backend,
+			 NULL, /* device */
+			 CAIRO_CONTENT_COLOR_ALPHA);
+
+    source->is_opaque_solid =
+	pattern == NULL || _cairo_pattern_is_opaque_solid (pattern);
+
+    return &source->base;
+}
diff --git a/src/cairo-image-spans-compositor.c b/src/cairo-image-spans-compositor.c
new file mode 100644
index 0000000..5718b55
--- /dev/null
+++ b/src/cairo-image-spans-compositor.c
@@ -0,0 +1,131 @@
+/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2003 University of Southern California
+ * Copyright © 2009,2010,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-compositor-private.h"
+#include "cairo-image-surface-private.h"
+#include "cairo-spans-compositor-private.h"
+
+typedef struct _cairo_image_span_renderer {
+    cairo_span_renderer_t base;
+
+    pixman_image_compositor_t *compositor;
+    pixman_image_t *src;
+    float opacity;
+    cairo_rectangle_int_t extents;
+} cairo_image_span_renderer_t;
+
+static cairo_status_t
+_cairo_image_span_renderer_init (cairo_abstract_span_renderer_t *_r,
+				 cairo_surface_t *dst,
+				 cairo_operator_t op,
+				 cairo_surface_t *src,
+				 int src_x, int src_y;
+				 float opacity,
+				 const cairo_composite_rectangles_t *composite,
+				 cairo_bool_t needs_clip)
+{
+    cairo_image_span_renderer_t *r = (cairo_image_span_renderer_t *)_r;
+    cairo_pixman_source_t *src = (cairo_pixman_source_t *)_src;
+    int src_x, src_y;
+
+    if (op == CAIRO_OPERATOR_CLEAR) {
+	op = CAIRO_OPERATOR_DEST_OUT;
+	pattern = NULL;
+    }
+
+    r->src = ((cairo_pixman_source_t *) src)->pixman_image;
+    r->opacity = opacity;
+
+    if (composite->is_bounded) {
+	if (opacity == 1.)
+	    r->base.render_rows = _cairo_image_bounded_opaque_spans;
+	else
+	    r->base.render_rows = _cairo_image_bounded_spans;
+	r->base.finish = NULL;
+    } else {
+	if (needs_clip)
+	    r->base.render_rows = _cairo_image_clipped_spans;
+	else
+	    r->base.render_rows = _cairo_image_unbounded_spans;
+        r->base.finish =      _cairo_image_finish_unbounded_spans;
+	r->extents = composite->unbounded;
+	r->extents.height += r->extents.y;
+
+    }
+    r->compositor =
+	pixman_image_create_compositor (_pixman_operator (op),
+					r->src, NULL, dst->pixman_image,
+					composite->bounded.x + src_x,
+					composite->bounded.y + src_y,
+					0, 0,
+					composite->bounded.x,
+					composite->bounded.y,
+					composite->bounded.width,
+					composite->bounded.height);
+    if (unlikely (r->compositor == NULL))
+	return CAIRO_INT_STATUS_NOTHING_TO_DO;
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static void
+_cairo_image_span_renderer_fini (cairo_abstract_span_renderer_t *_r)
+{
+    cairo_image_span_renderer_t *r = (cairo_image_span_renderer_t *) r;
+    pixman_image_compositor_destroy (r->compositor);
+}
+
+const cairo_compositor_t *
+_cairo_image_spans_compositor_get (void)
+{
+    static cairo_spans_compositor_t compositor;
+
+    if (compositor.base.delegate == NULL) {
+	/* Can't fallback to the mask compositor as that will simply
+	 * call the spans-compositor again to render the mask!
+	 */
+	_cairo_spans_compositor_init (&compositor,
+				      _cairo_image_traps_compositor_get());
+
+    }
+
+    return &compositor.base;
+}
diff --git a/src/cairo-image-surface-private.h b/src/cairo-image-surface-private.h
index 56a1dc4..227a447 100644
--- a/src/cairo-image-surface-private.h
+++ b/src/cairo-image-surface-private.h
@@ -44,9 +44,13 @@
 
 CAIRO_BEGIN_DECLS
 
+/* The canonical image backend */
 struct _cairo_image_surface {
     cairo_surface_t base;
 
+    pixman_image_t *pixman_image;
+    const cairo_compositor_t *compositor;
+
     pixman_format_code_t pixman_format;
     cairo_format_t format;
     unsigned char *data;
@@ -56,20 +60,55 @@ struct _cairo_image_surface {
     int stride;
     int depth;
 
-    pixman_image_t *pixman_image;
-
     unsigned owns_data : 1;
     unsigned transparency : 2;
     unsigned color : 2;
 };
 
-extern const cairo_private cairo_surface_backend_t _cairo_image_surface_backend;
+/* A wrapper for holding pixman images returned by create_for_pattern */
+typedef struct _cairo_image_source {
+    cairo_surface_t base;
+
+    pixman_image_t *pixman_image;
+    unsigned is_opaque_solid : 1;
+} cairo_image_source_t;
+
+cairo_private extern const cairo_surface_backend_t _cairo_image_surface_backend;
+
+cairo_private const cairo_compositor_t *
+_cairo_image_mask_compositor_get (void);
+
+cairo_private const cairo_compositor_t *
+_cairo_image_traps_compositor_get (void);
+
+cairo_private const cairo_compositor_t *
+_cairo_image_spans_compositor_get (void);
 
 cairo_private void
 _cairo_image_surface_init (cairo_image_surface_t *surface,
 			   pixman_image_t	*pixman_image,
 			   pixman_format_code_t	 pixman_format);
 
+cairo_private cairo_surface_t *
+_cairo_image_surface_map_to_image (void *abstract_other,
+				   const cairo_rectangle_int_t *extents);
+
+cairo_private cairo_int_status_t
+_cairo_image_surface_unmap_image (void *abstract_surface,
+				  cairo_image_surface_t *image);
+cairo_private cairo_status_t
+_cairo_image_surface_acquire_source_image (void                    *abstract_surface,
+					   cairo_image_surface_t  **image_out,
+					   void                   **image_extra);
+
+cairo_private void
+_cairo_image_surface_release_source_image (void                   *abstract_surface,
+					   cairo_image_surface_t  *image,
+					   void                   *image_extra);
+
+cairo_private cairo_surface_t *
+_cairo_image_surface_snapshot (void *abstract_surface);
+
 cairo_private_no_warn cairo_bool_t
 _cairo_image_surface_get_extents (void			  *abstract_surface,
 				  cairo_rectangle_int_t   *rectangle);
@@ -78,9 +117,52 @@ cairo_private void
 _cairo_image_surface_get_font_options (void                  *abstract_surface,
 				       cairo_font_options_t  *options);
 
+cairo_private cairo_surface_t *
+_cairo_image_source_create_for_pattern (cairo_surface_t *dst,
+					const cairo_pattern_t *pattern,
+					cairo_bool_t is_mask,
+					const cairo_rectangle_int_t *extents,
+					const cairo_rectangle_int_t *sample,
+					int *src_x, int *src_y);
+
 cairo_private cairo_status_t
 _cairo_image_surface_finish (void *abstract_surface);
 
+cairo_private pixman_image_t *
+_pixman_image_for_color (const cairo_color_t *cairo_color);
+
+cairo_private pixman_image_t *
+_pixman_image_for_pattern (cairo_image_surface_t *dst,
+			   const cairo_pattern_t *pattern,
+			   cairo_bool_t is_mask,
+			   const cairo_rectangle_int_t *extents,
+			   const cairo_rectangle_int_t *sample,
+			   int *tx, int *ty);
+
+cairo_private void
+_pixman_image_add_traps (pixman_image_t *image,
+			 int dst_x, int dst_y,
+			 cairo_traps_t *traps);
+
+cairo_private void
+_pixman_image_add_tristrip (pixman_image_t *image,
+			    int dst_x, int dst_y,
+			    cairo_tristrip_t *strip);
+
+/**
+ * _cairo_surface_is_image:
+ * @surface: a #cairo_surface_t
+ *
+ * Checks if a surface is an #cairo_image_surface_t
+ *
+ * Return value: %TRUE if the surface is an image surface
+ **/
+static inline cairo_bool_t
+_cairo_surface_is_image (const cairo_surface_t *surface)
+{
+    return surface->backend == &_cairo_image_surface_backend;
+}
+
 CAIRO_END_DECLS
 
 #endif /* CAIRO_IMAGE_SURFACE_PRIVATE_H */
diff --git a/src/cairo-image-surface.c b/src/cairo-image-surface.c
index bda05eb..6adbdd6 100644
--- a/src/cairo-image-surface.c
+++ b/src/cairo-image-surface.c
@@ -2,7 +2,7 @@
 /* cairo - a vector graphics library with display and print output
  *
  * Copyright © 2003 University of Southern California
- * Copyright © 2009,2010 Intel Corporation
+ * Copyright © 2009,2010,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
@@ -42,6 +42,7 @@
 #include "cairo-boxes-private.h"
 #include "cairo-clip-private.h"
 #include "cairo-composite-rectangles-private.h"
+#include "cairo-compositor-private.h"
 #include "cairo-default-context-private.h"
 #include "cairo-error-private.h"
 #include "cairo-image-surface-private.h"
@@ -57,7 +58,6 @@
  * mainly determined by coordinates of things sent to pixman at the
  * moment being in 16.16 format. */
 #define MAX_IMAGE_SIZE 32767
-#define PIXMAN_MAX_INT ((pixman_fixed_1 >> 1) - pixman_fixed_e) /* need to ensure deltas also fit */
 
 /**
  * SECTION:cairo-image
@@ -80,9 +80,6 @@
  * @Since: 1.8
  */
 
-static pixman_image_t *
-_pixman_image_for_solid (const cairo_solid_pattern_t *pattern);
-
 static cairo_bool_t
 _cairo_image_surface_is_size_valid (int width, int height)
 {
@@ -165,6 +162,8 @@ _cairo_image_surface_init (cairo_image_surface_t *surface,
     surface->depth = pixman_image_get_depth (pixman_image);
 
     surface->base.is_clear = surface->width == 0 || surface->height == 0;
+
+    surface->compositor = _cairo_image_spans_compositor_get ();
 }
 
 cairo_surface_t *
@@ -391,7 +390,7 @@ cairo_image_surface_create (cairo_format_t	format,
 }
 slim_hidden_def (cairo_image_surface_create);
 
-cairo_surface_t *
+    cairo_surface_t *
 _cairo_image_surface_create_with_content (cairo_content_t	content,
 					  int			width,
 					  int			height)
@@ -427,7 +426,7 @@ _cairo_image_surface_create_with_content (cairo_content_t	content,
  *
  * Since: 1.6
  **/
-int
+    int
 cairo_format_stride_for_width (cairo_format_t	format,
 			       int		width)
 {
@@ -489,7 +488,7 @@ slim_hidden_def (cairo_format_stride_for_width);
  * See cairo_surface_set_user_data() for a means of attaching a
  * destroy-notification fallback to the surface if necessary.
  **/
-cairo_surface_t *
+    cairo_surface_t *
 cairo_image_surface_create_for_data (unsigned char     *data,
 				     cairo_format_t	format,
 				     int		width,
@@ -545,7 +544,7 @@ slim_hidden_def (cairo_image_surface_create_for_data);
  *
  * Since: 1.2
  **/
-unsigned char *
+    unsigned char *
 cairo_image_surface_get_data (cairo_surface_t *surface)
 {
     cairo_image_surface_t *image_surface = (cairo_image_surface_t *) surface;
@@ -569,7 +568,7 @@ slim_hidden_def (cairo_image_surface_get_data);
  *
  * Since: 1.2
  **/
-cairo_format_t
+    cairo_format_t
 cairo_image_surface_get_format (cairo_surface_t *surface)
 {
     cairo_image_surface_t *image_surface = (cairo_image_surface_t *) surface;
@@ -591,7 +590,7 @@ slim_hidden_def (cairo_image_surface_get_format);
  *
  * Return value: the width of the surface in pixels.
  **/
-int
+    int
 cairo_image_surface_get_width (cairo_surface_t *surface)
 {
     cairo_image_surface_t *image_surface = (cairo_image_surface_t *) surface;
@@ -613,7 +612,7 @@ slim_hidden_def (cairo_image_surface_get_width);
  *
  * Return value: the height of the surface in pixels.
  **/
-int
+    int
 cairo_image_surface_get_height (cairo_surface_t *surface)
 {
     cairo_image_surface_t *image_surface = (cairo_image_surface_t *) surface;
@@ -640,7 +639,7 @@ slim_hidden_def (cairo_image_surface_get_height);
  *
  * Since: 1.2
  **/
-int
+    int
 cairo_image_surface_get_stride (cairo_surface_t *surface)
 {
 
@@ -655,7 +654,7 @@ cairo_image_surface_get_stride (cairo_surface_t *surface)
 }
 slim_hidden_def (cairo_image_surface_get_stride);
 
-cairo_format_t
+    cairo_format_t
 _cairo_format_from_content (cairo_content_t content)
 {
     switch (content) {
@@ -671,7 +670,7 @@ _cairo_format_from_content (cairo_content_t content)
     return CAIRO_FORMAT_INVALID;
 }
 
-cairo_content_t
+    cairo_content_t
 _cairo_content_from_format (cairo_format_t format)
 {
     switch (format) {
@@ -694,7 +693,7 @@ _cairo_content_from_format (cairo_format_t format)
     return CAIRO_CONTENT_COLOR_ALPHA;
 }
 
-int
+    int
 _cairo_format_bits_per_pixel (cairo_format_t format)
 {
     switch (format) {
@@ -715,7 +714,7 @@ _cairo_format_bits_per_pixel (cairo_format_t format)
     }
 }
 
-static cairo_surface_t *
+    static cairo_surface_t *
 _cairo_image_surface_create_similar (void	       *abstract_other,
 				     cairo_content_t	content,
 				     int		width,
@@ -737,7 +736,7 @@ _cairo_image_surface_create_similar (void	       *abstract_other,
 						     width, height);
 }
 
-static cairo_surface_t *
+cairo_surface_t *
 _cairo_image_surface_snapshot (void *abstract_surface)
 {
     cairo_image_surface_t *image = abstract_surface;
@@ -766,8 +765,7 @@ _cairo_image_surface_snapshot (void *abstract_surface)
     return &clone->base;
 }
 
-
-static cairo_surface_t *
+cairo_surface_t *
 _cairo_image_surface_map_to_image (void *abstract_other,
 				   const cairo_rectangle_int_t *extents)
 {
@@ -790,7 +788,7 @@ _cairo_image_surface_map_to_image (void *abstract_other,
     return surface;
 }
 
-static cairo_int_status_t
+cairo_int_status_t
 _cairo_image_surface_unmap_image (void *abstract_surface,
 				  cairo_image_surface_t *image)
 {
@@ -821,7 +819,7 @@ _cairo_image_surface_assume_ownership_of_data (cairo_image_surface_t *surface)
     surface->owns_data = TRUE;
 }
 
-static cairo_status_t
+cairo_status_t
 _cairo_image_surface_acquire_source_image (void                    *abstract_surface,
 					   cairo_image_surface_t  **image_out,
 					   void                   **image_extra)
@@ -832,2601 +830,13 @@ _cairo_image_surface_acquire_source_image (void                    *abstract_sur
     return CAIRO_STATUS_SUCCESS;
 }
 
-static void
+void
 _cairo_image_surface_release_source_image (void                   *abstract_surface,
 					   cairo_image_surface_t  *image,
 					   void                   *image_extra)
 {
 }
 
-/* XXX: I think we should fix pixman to match the names/order of the
- * cairo operators, but that will likely be better done at the same
- * time the X server is ported to pixman, (which will change a lot of
- * things in pixman I think).
- */
-static pixman_op_t
-_pixman_operator (cairo_operator_t op)
-{
-    switch (op) {
-    case CAIRO_OPERATOR_CLEAR:
-	return PIXMAN_OP_CLEAR;
-
-    case CAIRO_OPERATOR_SOURCE:
-	return PIXMAN_OP_SRC;
-    case CAIRO_OPERATOR_OVER:
-	return PIXMAN_OP_OVER;
-    case CAIRO_OPERATOR_IN:
-	return PIXMAN_OP_IN;
-    case CAIRO_OPERATOR_OUT:
-	return PIXMAN_OP_OUT;
-    case CAIRO_OPERATOR_ATOP:
-	return PIXMAN_OP_ATOP;
-
-    case CAIRO_OPERATOR_DEST:
-	return PIXMAN_OP_DST;
-    case CAIRO_OPERATOR_DEST_OVER:
-	return PIXMAN_OP_OVER_REVERSE;
-    case CAIRO_OPERATOR_DEST_IN:
-	return PIXMAN_OP_IN_REVERSE;
-    case CAIRO_OPERATOR_DEST_OUT:
-	return PIXMAN_OP_OUT_REVERSE;
-    case CAIRO_OPERATOR_DEST_ATOP:
-	return PIXMAN_OP_ATOP_REVERSE;
-
-    case CAIRO_OPERATOR_XOR:
-	return PIXMAN_OP_XOR;
-    case CAIRO_OPERATOR_ADD:
-	return PIXMAN_OP_ADD;
-    case CAIRO_OPERATOR_SATURATE:
-	return PIXMAN_OP_SATURATE;
-
-    case CAIRO_OPERATOR_MULTIPLY:
-	return PIXMAN_OP_MULTIPLY;
-    case CAIRO_OPERATOR_SCREEN:
-	return PIXMAN_OP_SCREEN;
-    case CAIRO_OPERATOR_OVERLAY:
-	return PIXMAN_OP_OVERLAY;
-    case CAIRO_OPERATOR_DARKEN:
-	return PIXMAN_OP_DARKEN;
-    case CAIRO_OPERATOR_LIGHTEN:
-	return PIXMAN_OP_LIGHTEN;
-    case CAIRO_OPERATOR_COLOR_DODGE:
-	return PIXMAN_OP_COLOR_DODGE;
-    case CAIRO_OPERATOR_COLOR_BURN:
-	return PIXMAN_OP_COLOR_BURN;
-    case CAIRO_OPERATOR_HARD_LIGHT:
-	return PIXMAN_OP_HARD_LIGHT;
-    case CAIRO_OPERATOR_SOFT_LIGHT:
-	return PIXMAN_OP_SOFT_LIGHT;
-    case CAIRO_OPERATOR_DIFFERENCE:
-	return PIXMAN_OP_DIFFERENCE;
-    case CAIRO_OPERATOR_EXCLUSION:
-	return PIXMAN_OP_EXCLUSION;
-    case CAIRO_OPERATOR_HSL_HUE:
-	return PIXMAN_OP_HSL_HUE;
-    case CAIRO_OPERATOR_HSL_SATURATION:
-	return PIXMAN_OP_HSL_SATURATION;
-    case CAIRO_OPERATOR_HSL_COLOR:
-	return PIXMAN_OP_HSL_COLOR;
-    case CAIRO_OPERATOR_HSL_LUMINOSITY:
-	return PIXMAN_OP_HSL_LUMINOSITY;
-
-    default:
-	ASSERT_NOT_REACHED;
-	return PIXMAN_OP_OVER;
-    }
-}
-
-static cairo_status_t
-_cairo_image_surface_set_clip_region (cairo_image_surface_t *surface,
-				      cairo_region_t *region)
-{
-    if (! pixman_image_set_clip_region32 (surface->pixman_image, &region->rgn))
-	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
-    return CAIRO_STATUS_SUCCESS;
-}
-
-static void
-_cairo_image_surface_unset_clip_region (cairo_image_surface_t *surface)
-{
-    pixman_image_set_clip_region32 (surface->pixman_image, NULL);
-}
-
-#if PIXMAN_HAS_ATOMIC_OPS
-static pixman_image_t *__pixman_transparent_image;
-static pixman_image_t *__pixman_black_image;
-static pixman_image_t *__pixman_white_image;
-
-static pixman_image_t *
-_pixman_transparent_image (void)
-{
-    pixman_image_t *image;
-
-    image = __pixman_transparent_image;
-    if (unlikely (image == NULL)) {
-	pixman_color_t color;
-
-	color.red   = 0x00;
-	color.green = 0x00;
-	color.blue  = 0x00;
-	color.alpha = 0x00;
-
-	image = pixman_image_create_solid_fill (&color);
-	if (unlikely (image == NULL))
-	    return NULL;
-
-	if (_cairo_atomic_ptr_cmpxchg (&__pixman_transparent_image,
-				       NULL, image))
-	{
-	    pixman_image_ref (image);
-	}
-    } else {
-	pixman_image_ref (image);
-    }
-
-    return image;
-}
-
-static pixman_image_t *
-_pixman_black_image (void)
-{
-    pixman_image_t *image;
-
-    image = __pixman_black_image;
-    if (unlikely (image == NULL)) {
-	pixman_color_t color;
-
-	color.red   = 0x00;
-	color.green = 0x00;
-	color.blue  = 0x00;
-	color.alpha = 0xffff;
-
-	image = pixman_image_create_solid_fill (&color);
-	if (unlikely (image == NULL))
-	    return NULL;
-
-	if (_cairo_atomic_ptr_cmpxchg (&__pixman_black_image,
-				       NULL, image))
-	{
-	    pixman_image_ref (image);
-	}
-    } else {
-	pixman_image_ref (image);
-    }
-
-    return image;
-}
-
-static pixman_image_t *
-_pixman_white_image (void)
-{
-    pixman_image_t *image;
-
-    image = __pixman_white_image;
-    if (unlikely (image == NULL)) {
-	pixman_color_t color;
-
-	color.red   = 0xffff;
-	color.green = 0xffff;
-	color.blue  = 0xffff;
-	color.alpha = 0xffff;
-
-	image = pixman_image_create_solid_fill (&color);
-	if (unlikely (image == NULL))
-	    return NULL;
-
-	if (_cairo_atomic_ptr_cmpxchg (&__pixman_white_image,
-				       NULL, image))
-	{
-	    pixman_image_ref (image);
-	}
-    } else {
-	pixman_image_ref (image);
-    }
-
-    return image;
-}
-
-static uint32_t
-hars_petruska_f54_1_random (void)
-{
-#define rol(x,k) ((x << k) | (x >> (32-k)))
-    static uint32_t x;
-    return x = (x ^ rol (x, 5) ^ rol (x, 24)) + 0x37798849;
-#undef rol
-}
-
-static struct {
-    cairo_color_t color;
-    pixman_image_t *image;
-} cache[16];
-static int n_cached;
-
-#else  /* !PIXMAN_HAS_ATOMIC_OPS */
-static pixman_image_t *
-_pixman_transparent_image (void)
-{
-    return _pixman_image_for_solid (&_cairo_pattern_clear);
-}
-
-static pixman_image_t *
-_pixman_black_image (void)
-{
-    return _pixman_image_for_solid (&_cairo_pattern_black);
-}
-
-static pixman_image_t *
-_pixman_white_image (void)
-{
-    return _pixman_image_for_solid (&_cairo_pattern_white);
-}
-#endif /* !PIXMAN_HAS_ATOMIC_OPS */
-
-void
-_cairo_image_reset_static_data (void)
-{
-#if PIXMAN_HAS_ATOMIC_OPS
-    while (n_cached)
-	pixman_image_unref (cache[--n_cached].image);
-
-    if (__pixman_transparent_image) {
-	pixman_image_unref (__pixman_transparent_image);
-	__pixman_transparent_image = NULL;
-    }
-
-    if (__pixman_black_image) {
-	pixman_image_unref (__pixman_black_image);
-	__pixman_black_image = NULL;
-    }
-
-    if (__pixman_white_image) {
-	pixman_image_unref (__pixman_white_image);
-	__pixman_white_image = NULL;
-    }
-#endif
-}
-
-static pixman_image_t *
-_pixman_image_for_solid (const cairo_solid_pattern_t *pattern)
-{
-    pixman_color_t color;
-    pixman_image_t *image;
-
-#if PIXMAN_HAS_ATOMIC_OPS
-    int i;
-
-    if (pattern->color.alpha_short <= 0x00ff)
-	return _pixman_transparent_image ();
-
-    if (pattern->color.alpha_short >= 0xff00) {
-	if (pattern->color.red_short <= 0x00ff &&
-	    pattern->color.green_short <= 0x00ff &&
-	    pattern->color.blue_short <= 0x00ff)
-	{
-	    return _pixman_black_image ();
-	}
-
-	if (pattern->color.red_short >= 0xff00 &&
-	    pattern->color.green_short >= 0xff00 &&
-	    pattern->color.blue_short >= 0xff00)
-	{
-	    return _pixman_white_image ();
-	}
-    }
-
-    CAIRO_MUTEX_LOCK (_cairo_image_solid_cache_mutex);
-    for (i = 0; i < n_cached; i++) {
-	if (_cairo_color_equal (&cache[i].color, &pattern->color)) {
-	    image = pixman_image_ref (cache[i].image);
-	    goto UNLOCK;
-	}
-    }
-#endif
-
-    color.red   = pattern->color.red_short;
-    color.green = pattern->color.green_short;
-    color.blue  = pattern->color.blue_short;
-    color.alpha = pattern->color.alpha_short;
-
-    image = pixman_image_create_solid_fill (&color);
-#if PIXMAN_HAS_ATOMIC_OPS
-    if (image == NULL)
-	goto UNLOCK;
-
-    if (n_cached < ARRAY_LENGTH (cache)) {
-	i = n_cached++;
-    } else {
-	i = hars_petruska_f54_1_random () % ARRAY_LENGTH (cache);
-	pixman_image_unref (cache[i].image);
-    }
-    cache[i].image = pixman_image_ref (image);
-    cache[i].color = pattern->color;
-
-UNLOCK:
-    CAIRO_MUTEX_UNLOCK (_cairo_image_solid_cache_mutex);
-#endif
-    return image;
-}
-
-static pixman_image_t *
-_pixman_image_for_gradient (const cairo_gradient_pattern_t *pattern,
-			    const cairo_rectangle_int_t *extents,
-			    int *ix, int *iy)
-{
-    pixman_image_t	  *pixman_image;
-    pixman_gradient_stop_t pixman_stops_static[2];
-    pixman_gradient_stop_t *pixman_stops = pixman_stops_static;
-    pixman_transform_t      pixman_transform;
-    cairo_matrix_t matrix;
-    cairo_circle_double_t extremes[2];
-    pixman_point_fixed_t p1, p2;
-    unsigned int i;
-    cairo_int_status_t status;
-
-    if (pattern->n_stops > ARRAY_LENGTH(pixman_stops_static)) {
-	pixman_stops = _cairo_malloc_ab (pattern->n_stops,
-					 sizeof(pixman_gradient_stop_t));
-	if (unlikely (pixman_stops == NULL))
-	    return NULL;
-    }
-
-    for (i = 0; i < pattern->n_stops; i++) {
-	pixman_stops[i].x = _cairo_fixed_16_16_from_double (pattern->stops[i].offset);
-	pixman_stops[i].color.red   = pattern->stops[i].color.red_short;
-	pixman_stops[i].color.green = pattern->stops[i].color.green_short;
-	pixman_stops[i].color.blue  = pattern->stops[i].color.blue_short;
-	pixman_stops[i].color.alpha = pattern->stops[i].color.alpha_short;
-    }
-
-    _cairo_gradient_pattern_fit_to_range (pattern, PIXMAN_MAX_INT >> 1, &matrix, extremes);
-
-    p1.x = _cairo_fixed_16_16_from_double (extremes[0].center.x);
-    p1.y = _cairo_fixed_16_16_from_double (extremes[0].center.y);
-    p2.x = _cairo_fixed_16_16_from_double (extremes[1].center.x);
-    p2.y = _cairo_fixed_16_16_from_double (extremes[1].center.y);
-
-    if (pattern->base.type == CAIRO_PATTERN_TYPE_LINEAR) {
-	pixman_image = pixman_image_create_linear_gradient (&p1, &p2,
-							    pixman_stops,
-							    pattern->n_stops);
-    } else {
-	pixman_fixed_t r1, r2;
-
-	r1   = _cairo_fixed_16_16_from_double (extremes[0].radius);
-	r2   = _cairo_fixed_16_16_from_double (extremes[1].radius);
-
-	pixman_image = pixman_image_create_radial_gradient (&p1, &p2, r1, r2,
-							    pixman_stops,
-							    pattern->n_stops);
-    }
-
-    if (pixman_stops != pixman_stops_static)
-	free (pixman_stops);
-
-    if (unlikely (pixman_image == NULL))
-	return NULL;
-
-    *ix = *iy = 0;
-    status = _cairo_matrix_to_pixman_matrix_offset (&matrix, pattern->base.filter,
-						    extents->x + extents->width/2.,
-						    extents->y + extents->height/2.,
-						    &pixman_transform, ix, iy);
-    if (status != CAIRO_INT_STATUS_NOTHING_TO_DO) {
-	if (unlikely (status != CAIRO_INT_STATUS_SUCCESS) ||
-	    ! pixman_image_set_transform (pixman_image, &pixman_transform))
-	{
-	    pixman_image_unref (pixman_image);
-	    return NULL;
-	}
-    }
-
-    {
-	pixman_repeat_t pixman_repeat;
-
-	switch (pattern->base.extend) {
-	default:
-	case CAIRO_EXTEND_NONE:
-	    pixman_repeat = PIXMAN_REPEAT_NONE;
-	    break;
-	case CAIRO_EXTEND_REPEAT:
-	    pixman_repeat = PIXMAN_REPEAT_NORMAL;
-	    break;
-	case CAIRO_EXTEND_REFLECT:
-	    pixman_repeat = PIXMAN_REPEAT_REFLECT;
-	    break;
-	case CAIRO_EXTEND_PAD:
-	    pixman_repeat = PIXMAN_REPEAT_PAD;
-	    break;
-	}
-
-	pixman_image_set_repeat (pixman_image, pixman_repeat);
-    }
-
-    return pixman_image;
-}
-
-struct acquire_source_cleanup {
-    cairo_surface_t *surface;
-    cairo_image_surface_t *image;
-    void *image_extra;
-};
-
-static void
-_acquire_source_cleanup (pixman_image_t *pixman_image,
-			 void *closure)
-{
-    struct acquire_source_cleanup *data = closure;
-
-    _cairo_surface_release_source_image (data->surface,
-					 data->image,
-					 data->image_extra);
-    free (data);
-}
-
-static cairo_filter_t
-sampled_area (const cairo_surface_pattern_t *pattern,
-	      const cairo_rectangle_int_t *extents,
-	      cairo_rectangle_int_t *sample)
-{
-    cairo_filter_t filter;
-    double x1, x2, y1, y2;
-    double pad;
-
-    x1 = extents->x;
-    y1 = extents->y;
-    x2 = extents->x + (int) extents->width;
-    y2 = extents->y + (int) extents->height;
-
-    _cairo_matrix_transform_bounding_box (&pattern->base.matrix,
-                                          &x1, &y1, &x2, &y2,
-                                          NULL);
-
-    filter = _cairo_pattern_analyze_filter (&pattern->base, &pad);
-    sample->x = floor (x1 - pad);
-    sample->y = floor (y1 - pad);
-    sample->width  = ceil (x2 + pad) - sample->x;
-    sample->height = ceil (y2 + pad) - sample->y;
-
-    return filter;
-}
-
-static uint16_t
-expand_channel (uint16_t v, uint32_t bits)
-{
-    int offset = 16 - bits;
-    while (offset > 0) {
-	v |= v >> bits;
-	offset -= bits;
-	bits += bits;
-    }
-    return v;
-}
-
-static pixman_image_t *
-_pixel_to_solid (cairo_image_surface_t *image, int x, int y)
-{
-    uint32_t pixel;
-    pixman_color_t color;
-
-    switch (image->format) {
-    default:
-	ASSERT_NOT_REACHED;
-	return NULL;
-
-    case CAIRO_FORMAT_INVALID:
-	return NULL;
-
-    case CAIRO_FORMAT_A1:
-	pixel = *(uint8_t *) (image->data + y * image->stride + x/8);
-	return pixel & (1 << (x&7)) ? _pixman_black_image () : _pixman_transparent_image ();
-
-    case CAIRO_FORMAT_A8:
-	color.alpha = *(uint8_t *) (image->data + y * image->stride + x);
-	color.alpha |= color.alpha << 8;
-	if (color.alpha == 0)
-	    return _pixman_transparent_image ();
-	if (color.alpha == 0xffff)
-	    return _pixman_black_image ();
-
-	color.red = color.green = color.blue = 0;
-	return pixman_image_create_solid_fill (&color);
-
-    case CAIRO_FORMAT_RGB16_565:
-	pixel = *(uint16_t *) (image->data + y * image->stride + 2 * x);
-	if (pixel == 0)
-	    return _pixman_black_image ();
-	if (pixel == 0xffff)
-	    return _pixman_white_image ();
-
-	color.alpha = 0xffff;
-	color.red = expand_channel ((pixel >> 11 & 0x1f) << 11, 5);
-	color.green = expand_channel ((pixel >> 5 & 0x3f) << 10, 6);
-	color.blue = expand_channel ((pixel & 0x1f) << 11, 5);
-	return pixman_image_create_solid_fill (&color);
-
-    case CAIRO_FORMAT_RGB30:
-	pixel = *(uint32_t *) (image->data + y * image->stride + 4 * x);
-	pixel &= 0x3fffffff; /* ignore alpha bits */
-	if (pixel == 0)
-	    return _pixman_black_image ();
-	if (pixel == 0x3fffffff)
-	    return _pixman_white_image ();
-
-	/* convert 10bpc to 16bpc */
-	color.alpha = 0xffff;
-	color.red = expand_channel((pixel >> 20) & 0x3fff, 10);
-	color.green = expand_channel((pixel >> 10) & 0x3fff, 10);
-	color.blue = expand_channel(pixel & 0x3fff, 10);
-	return pixman_image_create_solid_fill (&color);
-
-    case CAIRO_FORMAT_ARGB32:
-    case CAIRO_FORMAT_RGB24:
-	pixel = *(uint32_t *) (image->data + y * image->stride + 4 * x);
-	color.alpha = image->format == CAIRO_FORMAT_ARGB32 ? (pixel >> 24) | (pixel >> 16 & 0xff00) : 0xffff;
-	if (color.alpha == 0)
-	    return _pixman_transparent_image ();
-	if (pixel == 0xffffffff)
-	    return _pixman_white_image ();
-	if (color.alpha == 0xffff && (pixel & 0xffffff) == 0)
-	    return _pixman_black_image ();
-
-	color.red = (pixel >> 16 & 0xff) | (pixel >> 8 & 0xff00);
-	color.green = (pixel >> 8 & 0xff) | (pixel & 0xff00);
-	color.blue = (pixel & 0xff) | (pixel << 8 & 0xff00);
-	return pixman_image_create_solid_fill (&color);
-    }
-}
-
-static pixman_image_t *
-_pixman_image_for_surface (const cairo_surface_pattern_t *pattern,
-			   cairo_bool_t is_mask,
-			   const cairo_rectangle_int_t *extents,
-			   cairo_matrix_t *dst_device_transform,
-			   int *ix, int *iy)
-{
-    pixman_transform_t pixman_transform;
-    pixman_image_t *pixman_image;
-    cairo_matrix_t m;
-    cairo_rectangle_int_t sample;
-    cairo_extend_t extend;
-    cairo_filter_t filter;
-    cairo_int_status_t status;
-    cairo_bool_t undo_src_transform = FALSE;
-
-    extend = pattern->base.extend;
-    filter = sampled_area (pattern, extents, &sample);
-
-    *ix = *iy = 0;
-    pixman_image = NULL;
-    if (pattern->surface->type == CAIRO_SURFACE_TYPE_IMAGE &&
-	(! is_mask || ! pattern->base.has_component_alpha ||
-	 (pattern->surface->content & CAIRO_CONTENT_COLOR) == 0))
-    {
-	cairo_image_surface_t *source = (cairo_image_surface_t *) pattern->surface;
-	cairo_surface_type_t type;
-
-	if (_cairo_surface_is_snapshot (&source->base))
-	    source = (cairo_image_surface_t *) _cairo_surface_snapshot_get_target (&source->base);
-
-	type = source->base.backend->type;
-	if (type == CAIRO_SURFACE_TYPE_IMAGE) {
-	    if (extend != CAIRO_EXTEND_NONE &&
-		sample.x >= 0 &&
-		sample.y >= 0 &&
-		sample.x + sample.width  <= source->width &&
-		sample.y + sample.height <= source->height)
-	    {
-		extend = CAIRO_EXTEND_NONE;
-	    }
-
-	    if (sample.width == 1 && sample.height == 1) {
-		if (sample.x < 0 ||
-		    sample.y < 0 ||
-		    sample.x >= source->width ||
-		    sample.y >= source->height)
-		{
-		    if (extend == CAIRO_EXTEND_NONE)
-			return _pixman_transparent_image ();
-		}
-		else
-		{
-		    pixman_image = _pixel_to_solid (source, sample.x, sample.y);
-                    if (pixman_image)
-                        return pixman_image;
-		}
-	    }
-
-#if PIXMAN_HAS_ATOMIC_OPS
-	    /* avoid allocating a 'pattern' image if we can reuse the original */
-	    *ix = *iy = 0;
-	    if (extend == CAIRO_EXTEND_NONE &&
-		_cairo_matrix_is_pixman_translation (&pattern->base.matrix,
-						     filter, ix, iy))
-	    {
-		return pixman_image_ref (source->pixman_image);
-	    }
-#endif
-
-	    pixman_image = pixman_image_create_bits (source->pixman_format,
-						     source->width,
-						     source->height,
-						     (uint32_t *) source->data,
-						     source->stride);
-	    if (unlikely (pixman_image == NULL))
-		return NULL;
-	} else if (type == CAIRO_SURFACE_TYPE_SUBSURFACE) {
-	    cairo_surface_subsurface_t *sub;
-	    cairo_bool_t is_contained = FALSE;
-
-	    sub = (cairo_surface_subsurface_t *) source;
-	    source = (cairo_image_surface_t *) sub->target;
-
-	    if (sample.x >= 0 &&
-		sample.y >= 0 &&
-		sample.x + sample.width  <= sub->extents.width &&
-		sample.y + sample.height <= sub->extents.height)
-	    {
-		is_contained = TRUE;
-	    }
-
-	    if (sample.width == 1 && sample.height == 1) {
-		if (is_contained) {
-		    pixman_image = _pixel_to_solid (source,
-                                                    sub->extents.x + sample.x,
-                                                    sub->extents.y + sample.y);
-                    if (pixman_image)
-                        return pixman_image;
-		} else {
-		    if (extend == CAIRO_EXTEND_NONE)
-			return _pixman_transparent_image ();
-		}
-	    }
-
-#if PIXMAN_HAS_ATOMIC_OPS
-	    *ix = sub->extents.x;
-	    *iy = sub->extents.y;
-	    if (is_contained &&
-		_cairo_matrix_is_pixman_translation (&pattern->base.matrix,
-						     filter, ix, iy))
-	    {
-		return pixman_image_ref (source->pixman_image);
-	    }
-#endif
-
-	    /* Avoid sub-byte offsets, force a copy in that case. */
-	    if (PIXMAN_FORMAT_BPP (source->pixman_format) >= 8) {
-		void *data = source->data
-		    + sub->extents.x * PIXMAN_FORMAT_BPP(source->pixman_format)/8
-		    + sub->extents.y * source->stride;
-		pixman_image = pixman_image_create_bits (source->pixman_format,
-							 sub->extents.width,
-							 sub->extents.height,
-							 data,
-							 source->stride);
-		if (unlikely (pixman_image == NULL))
-		    return NULL;
-	    }
-	}
-    }
-
-#if PIXMAN_HAS_ATOMIC_OPS
-    *ix = *iy = 0;
-#endif
-
-    if (pixman_image == NULL) {
-	struct acquire_source_cleanup *cleanup;
-	cairo_image_surface_t *image;
-	void *extra;
-	cairo_status_t status;
-
-	status = _cairo_surface_acquire_source_image_transformed (pattern->surface, dst_device_transform, &image, &extra);
-	if (unlikely (status))
-	    return NULL;
-
-	if (sample.width == 1 && sample.height == 1) {
-	    if (sample.x < 0 ||
-		sample.y < 0 ||
-		sample.x >= image->width ||
-		sample.y >= image->height)
-	    {
-		if (extend == CAIRO_EXTEND_NONE) {
-		    pixman_image = _pixman_transparent_image ();
-		    _cairo_surface_release_source_image (pattern->surface, image, extra);
-		    return pixman_image;
-		}
-	    }
-	    else
-	    {
-		pixman_image = _pixel_to_solid (image, sample.x, sample.y);
-                if (pixman_image)
-                {
-                    _cairo_surface_release_source_image (pattern->surface, image, extra);
-                    return pixman_image;
-                }
-	    }
-	}
-
-	pixman_image = pixman_image_create_bits (image->pixman_format,
-						 image->width,
-						 image->height,
-						 (uint32_t *) image->data,
-						 image->stride);
-	if (unlikely (pixman_image == NULL)) {
-	    _cairo_surface_release_source_image (pattern->surface, image, extra);
-	    return NULL;
-	}
-
-	cleanup = malloc (sizeof (*cleanup));
-	if (unlikely (cleanup == NULL)) {
-	    _cairo_surface_release_source_image (pattern->surface, image, extra);
-	    pixman_image_unref (pixman_image);
-	    return NULL;
-	}
-
-	cleanup->surface = pattern->surface;
-	cleanup->image = image;
-	cleanup->image_extra = extra;
-	pixman_image_set_destroy_function (pixman_image,
-					   _acquire_source_cleanup, cleanup);
-	undo_src_transform = TRUE;
-    }
-
-    m = pattern->base.matrix;
-    if (undo_src_transform) {
-	cairo_matrix_t sm;
-
-	cairo_matrix_init_scale (&sm,
-				 dst_device_transform->xx,
-				 dst_device_transform->yy);
-	cairo_matrix_multiply (&m, &m, &sm);
-    }
-
-    status = _cairo_matrix_to_pixman_matrix_offset (&m, filter,
-						    extents->x + extents->width/2.,
-						    extents->y + extents->height/2.,
-						    &pixman_transform, ix, iy);
-    if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
-    {
-	/* If the transform is an identity, we don't need to set it
-	 * and we can use any filtering, so choose the fastest one. */
-	pixman_image_set_filter (pixman_image, PIXMAN_FILTER_NEAREST, NULL, 0);
-    }
-    else if (unlikely (status != CAIRO_INT_STATUS_SUCCESS ||
-		       ! pixman_image_set_transform (pixman_image,
-						     &pixman_transform)))
-    {
-	pixman_image_unref (pixman_image);
-	return NULL;
-    }
-    else
-    {
-	pixman_filter_t pixman_filter;
-
-	switch (filter) {
-	case CAIRO_FILTER_FAST:
-	    pixman_filter = PIXMAN_FILTER_FAST;
-	    break;
-	case CAIRO_FILTER_GOOD:
-	    pixman_filter = PIXMAN_FILTER_GOOD;
-	    break;
-	case CAIRO_FILTER_BEST:
-	    pixman_filter = PIXMAN_FILTER_BEST;
-	    break;
-	case CAIRO_FILTER_NEAREST:
-	    pixman_filter = PIXMAN_FILTER_NEAREST;
-	    break;
-	case CAIRO_FILTER_BILINEAR:
-	    pixman_filter = PIXMAN_FILTER_BILINEAR;
-	    break;
-	case CAIRO_FILTER_GAUSSIAN:
-	    /* XXX: The GAUSSIAN value has no implementation in cairo
-	     * whatsoever, so it was really a mistake to have it in the
-	     * API. We could fix this by officially deprecating it, or
-	     * else inventing semantics and providing an actual
-	     * implementation for it. */
-	default:
-	    pixman_filter = PIXMAN_FILTER_BEST;
-	}
-
-	pixman_image_set_filter (pixman_image, pixman_filter, NULL, 0);
-    }
-
-    {
-	pixman_repeat_t pixman_repeat;
-
-	switch (extend) {
-	default:
-	case CAIRO_EXTEND_NONE:
-	    pixman_repeat = PIXMAN_REPEAT_NONE;
-	    break;
-	case CAIRO_EXTEND_REPEAT:
-	    pixman_repeat = PIXMAN_REPEAT_NORMAL;
-	    break;
-	case CAIRO_EXTEND_REFLECT:
-	    pixman_repeat = PIXMAN_REPEAT_REFLECT;
-	    break;
-	case CAIRO_EXTEND_PAD:
-	    pixman_repeat = PIXMAN_REPEAT_PAD;
-	    break;
-	}
-
-	pixman_image_set_repeat (pixman_image, pixman_repeat);
-    }
-
-    if (pattern->base.has_component_alpha)
-	pixman_image_set_component_alpha (pixman_image, TRUE);
-
-    return pixman_image;
-}
-
-static pixman_image_t *
-_pixman_image_for_pattern (const cairo_pattern_t *pattern,
-			   cairo_bool_t is_mask,
-			   const cairo_rectangle_int_t *extents,
-			   cairo_matrix_t *dst_device_transform,
-			   int *tx, int *ty)
-{
-    *tx = *ty = 0;
-
-    if (pattern == NULL)
-	return _pixman_white_image ();
-
-    switch (pattern->type) {
-    default:
-	ASSERT_NOT_REACHED;
-    case CAIRO_PATTERN_TYPE_SOLID:
-	return _pixman_image_for_solid ((const cairo_solid_pattern_t *) pattern);
-
-    case CAIRO_PATTERN_TYPE_RADIAL:
-    case CAIRO_PATTERN_TYPE_LINEAR:
-	return _pixman_image_for_gradient ((const cairo_gradient_pattern_t *) pattern,
-					   extents, tx, ty);
-
-    case CAIRO_PATTERN_TYPE_SURFACE:
-	return _pixman_image_for_surface ((const cairo_surface_pattern_t *) pattern,
-					  is_mask, extents, dst_device_transform, tx, ty);
-
-    case CAIRO_PATTERN_TYPE_MESH: {
-	cairo_surface_t *image;
-	pixman_image_t *r;
-	void * data;
-	int width, height, stride;
-
-	*tx = -extents->x;
-	*ty = -extents->y;
-	width = extents->width;
-	height = extents->height;
-
-	image = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
-	if (unlikely (image->status))
-	    return NULL;
-
-	stride = cairo_image_surface_get_stride (image);
-	data = cairo_image_surface_get_data (image);
-
-	_cairo_mesh_pattern_rasterize ((cairo_mesh_pattern_t *) pattern,
-				       data, width, height, stride, *tx, *ty);
-	r = pixman_image_ref (((cairo_image_surface_t *)image)->pixman_image);
-	cairo_surface_destroy (image);
-	return r;
-    }
-    }
-}
-
-static cairo_status_t
-_cairo_image_surface_fixup_unbounded (cairo_image_surface_t *dst,
-				      const cairo_composite_rectangles_t *rects,
-				      cairo_clip_t *clip)
-{
-    cairo_surface_t *clip_surface = NULL;
-    pixman_image_t *mask = NULL;
-    pixman_box32_t boxes[4];
-    int i, mask_x = 0, mask_y = 0, n_boxes = 0;
-    cairo_status_t status = CAIRO_STATUS_SUCCESS;
-
-    if (clip != NULL) {
-	int clip_x, clip_y;
-
-	clip_surface = _cairo_clip_get_surface (clip, &dst->base, &clip_x, &clip_y);
-	if (unlikely (clip_surface->status))
-	    return clip_surface->status;
-
-	mask = ((cairo_image_surface_t *) clip_surface)->pixman_image;
-	mask_x = -clip_x;
-	mask_y = -clip_y;
-    } else {
-	if (rects->bounded.width  == rects->unbounded.width &&
-	    rects->bounded.height == rects->unbounded.height)
-	{
-	    return CAIRO_STATUS_SUCCESS;
-	}
-    }
-
-    /* wholly unbounded? */
-    if (rects->bounded.width == 0 || rects->bounded.height == 0) {
-	int x = rects->unbounded.x;
-	int y = rects->unbounded.y;
-	int width = rects->unbounded.width;
-	int height = rects->unbounded.height;
-
-	if (mask != NULL) {
-	    pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE,
-                                      mask, NULL, dst->pixman_image,
-                                      x + mask_x, y + mask_y,
-                                      0, 0,
-                                      x, y,
-                                      width, height);
-	} else {
-            pixman_color_t color = { 0, };
-            pixman_box32_t box = { x, y, x + width, y + height };
-
-            if (! pixman_image_fill_boxes (PIXMAN_OP_CLEAR,
-					   dst->pixman_image,
-					   &color,
-					   1, &box))
-		status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
-	}
-
-	cairo_surface_destroy (clip_surface);
-	return status;
-    }
-
-    /* top */
-    if (rects->bounded.y != rects->unbounded.y) {
-        boxes[n_boxes].x1 = rects->unbounded.x;
-        boxes[n_boxes].y1 = rects->unbounded.y;
-        boxes[n_boxes].x2 = rects->unbounded.x + rects->unbounded.width;
-        boxes[n_boxes].y2 = rects->bounded.y;
-        n_boxes++;
-    }
-
-    /* left */
-    if (rects->bounded.x != rects->unbounded.x) {
-        boxes[n_boxes].x1 = rects->unbounded.x;
-        boxes[n_boxes].y1 = rects->bounded.y;
-        boxes[n_boxes].x2 = rects->bounded.x;
-        boxes[n_boxes].y2 = rects->bounded.y + rects->bounded.height;
-        n_boxes++;
-    }
-
-    /* right */
-    if (rects->bounded.x + rects->bounded.width != rects->unbounded.x + rects->unbounded.width) {
-        boxes[n_boxes].x1 = rects->bounded.x + rects->bounded.width;
-        boxes[n_boxes].y1 = rects->bounded.y;
-        boxes[n_boxes].x2 = rects->unbounded.x + rects->unbounded.width;
-        boxes[n_boxes].y2 = rects->bounded.y + rects->bounded.height;
-        n_boxes++;
-    }
-
-    /* bottom */
-    if (rects->bounded.y + rects->bounded.height != rects->unbounded.y + rects->unbounded.height) {
-        boxes[n_boxes].x1 = rects->unbounded.x;
-        boxes[n_boxes].y1 = rects->bounded.y + rects->bounded.height;
-        boxes[n_boxes].x2 = rects->unbounded.x + rects->unbounded.width;
-        boxes[n_boxes].y2 = rects->unbounded.y + rects->unbounded.height;
-        n_boxes++;
-    }
-
-    if (mask != NULL) {
-        for (i = 0; i < n_boxes; i++) {
-            pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE,
-                                      mask, NULL, dst->pixman_image,
-                                      boxes[i].x1 + mask_x, boxes[i].y1 + mask_y,
-                                      0, 0,
-                                      boxes[i].x1, boxes[i].y1,
-                                      boxes[i].x2 - boxes[i].x1, boxes[i].y2 - boxes[i].y1);
-        }
-    } else {
-        pixman_color_t color = { 0, };
-
-        if (! pixman_image_fill_boxes (PIXMAN_OP_CLEAR,
-				       dst->pixman_image,
-				       &color,
-				       n_boxes,
-				       boxes))
-	{
-	    status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
-	}
-    }
-
-    cairo_surface_destroy (clip_surface);
-    return status;
-}
-
-static cairo_status_t
-_cairo_image_surface_fixup_unbounded_boxes (cairo_image_surface_t *dst,
-					    const cairo_composite_rectangles_t *extents,
-					    cairo_region_t *clip_region,
-					    cairo_boxes_t *boxes)
-{
-    cairo_boxes_t clear;
-    cairo_box_t box;
-    cairo_status_t status;
-    struct _cairo_boxes_chunk *chunk;
-    int i;
-
-    if (boxes->num_boxes <= 1 && clip_region == NULL)
-	return _cairo_image_surface_fixup_unbounded (dst, extents, NULL);
-
-    _cairo_boxes_init (&clear);
-
-    box.p1.x = _cairo_fixed_from_int (extents->unbounded.x + extents->unbounded.width);
-    box.p1.y = _cairo_fixed_from_int (extents->unbounded.y);
-    box.p2.x = _cairo_fixed_from_int (extents->unbounded.x);
-    box.p2.y = _cairo_fixed_from_int (extents->unbounded.y + extents->unbounded.height);
-
-    if (clip_region == NULL) {
-	cairo_boxes_t tmp;
-
-	_cairo_boxes_init (&tmp);
-
-	status = _cairo_boxes_add (&tmp, CAIRO_ANTIALIAS_DEFAULT, &box);
-	assert (status == CAIRO_STATUS_SUCCESS);
-
-	tmp.chunks.next = &boxes->chunks;
-	tmp.num_boxes += boxes->num_boxes;
-
-	status = _cairo_bentley_ottmann_tessellate_boxes (&tmp,
-							  CAIRO_FILL_RULE_WINDING,
-							  &clear);
-
-	tmp.chunks.next = NULL;
-    } else {
-	pixman_box32_t *pbox;
-
-	pbox = pixman_region32_rectangles (&clip_region->rgn, &i);
-	_cairo_boxes_limit (&clear, (cairo_box_t *) pbox, i);
-
-	status = _cairo_boxes_add (&clear, CAIRO_ANTIALIAS_DEFAULT, &box);
-	assert (status == CAIRO_STATUS_SUCCESS);
-
-	for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
-	    for (i = 0; i < chunk->count; i++) {
-		status = _cairo_boxes_add (&clear,
-					   CAIRO_ANTIALIAS_DEFAULT,
-					   &chunk->base[i]);
-		if (unlikely (status)) {
-		    _cairo_boxes_fini (&clear);
-		    return status;
-		}
-	    }
-	}
-
-	status = _cairo_bentley_ottmann_tessellate_boxes (&clear,
-							  CAIRO_FILL_RULE_WINDING,
-							  &clear);
-    }
-
-    if (likely (status == CAIRO_STATUS_SUCCESS)) {
-	for (chunk = &clear.chunks; chunk != NULL; chunk = chunk->next) {
-	    for (i = 0; i < chunk->count; i++) {
-		int x1 = _cairo_fixed_integer_part (chunk->base[i].p1.x);
-		int y1 = _cairo_fixed_integer_part (chunk->base[i].p1.y);
-		int x2 = _cairo_fixed_integer_part (chunk->base[i].p2.x);
-		int y2 = _cairo_fixed_integer_part (chunk->base[i].p2.y);
-
-		pixman_fill ((uint32_t *) dst->data, dst->stride / sizeof (uint32_t),
-			     PIXMAN_FORMAT_BPP (dst->pixman_format),
-			     x1, y1, x2 - x1, y2 - y1,
-			     0);
-	    }
-	}
-    }
-
-    _cairo_boxes_fini (&clear);
-
-    return status;
-}
-
-static cairo_bool_t
-can_reduce_alpha_op (cairo_operator_t op)
-{
-    int iop = op;
-    switch (iop) {
-    case CAIRO_OPERATOR_OVER:
-    case CAIRO_OPERATOR_SOURCE:
-    case CAIRO_OPERATOR_ADD:
-	return TRUE;
-    default:
-	return FALSE;
-    }
-}
-
-static cairo_bool_t
-reduce_alpha_op (cairo_image_surface_t *dst,
-		 cairo_operator_t op,
-		 const cairo_pattern_t *pattern)
-{
-    return dst->base.is_clear &&
-	   dst->base.content == CAIRO_CONTENT_ALPHA &&
-	   _cairo_pattern_is_opaque_solid (pattern) &&
-	   can_reduce_alpha_op (op);
-}
-
-/* low level compositor */
-typedef cairo_status_t
-(*image_draw_func_t) (void				*closure,
-		      pixman_image_t			*dst,
-		      pixman_format_code_t		 dst_format,
-		      cairo_operator_t			 op,
-		      const cairo_pattern_t		*src,
-		      int				 dst_x,
-		      int				 dst_y,
-		      cairo_matrix_t			*dst_device_transform,
-		      const cairo_composite_rectangles_t	*extents);
-
-static pixman_image_t *
-_create_composite_mask_pattern (cairo_composite_rectangles_t *extents,
-				image_draw_func_t              draw_func,
-				void                          *draw_closure,
-				cairo_image_surface_t         *dst)
-{
-    cairo_region_t *clip_region = _cairo_clip_get_region (extents->clip);
-    cairo_bool_t need_clip_surface = ! _cairo_clip_is_region (extents->clip);
-    pixman_image_t *mask;
-    cairo_status_t status;
-
-    if (clip_region != NULL && cairo_region_num_rectangles (clip_region) == 1)
-	clip_region = NULL;
-
-    mask = pixman_image_create_bits (PIXMAN_a8, extents->bounded.width, extents->bounded.height,
-				     NULL, 0);
-    if (unlikely (mask == NULL))
-	return NULL;
-
-    /* Is it worth setting the clip region here? */
-    if (clip_region != NULL) {
-	pixman_bool_t ret;
-
-	pixman_region32_translate (&clip_region->rgn, -extents->bounded.x, -extents->bounded.y);
-	ret = pixman_image_set_clip_region32 (mask, &clip_region->rgn);
-	pixman_region32_translate (&clip_region->rgn, extents->bounded.x, extents->bounded.y);
-
-	if (! ret) {
-	    pixman_image_unref (mask);
-	    return NULL;
-	}
-    }
-
-    status = draw_func (draw_closure,
-			mask, PIXMAN_a8,
-			CAIRO_OPERATOR_ADD, NULL,
-			extents->bounded.x, extents->bounded.y,
-			&dst->base.device_transform,
-			extents);
-    if (unlikely (status)) {
-	pixman_image_unref (mask);
-	return NULL;
-    }
-
-    if (need_clip_surface) {
-	cairo_surface_t *tmp;
-
-	tmp = _cairo_image_surface_create_for_pixman_image (mask, PIXMAN_a8);
-	if (unlikely (tmp->status)) {
-	    pixman_image_unref (mask);
-	    return NULL;
-	}
-
-	pixman_image_ref (mask);
-
-	status = _cairo_clip_combine_with_surface (extents->clip, tmp,
-						   extents->bounded.x,
-						   extents->bounded.y);
-	cairo_surface_destroy (tmp);
-	if (unlikely (status)) {
-	    pixman_image_unref (mask);
-	    return NULL;
-	}
-    }
-
-    if (clip_region != NULL)
-	pixman_image_set_clip_region (mask, NULL);
-
-    return mask;
-}
-
-/* Handles compositing with a clip surface when the operator allows
- * us to combine the clip with the mask
- */
-static cairo_status_t
-_clip_and_composite_with_mask (cairo_composite_rectangles_t *extents,
-			       cairo_operator_t               op,
-			       const cairo_pattern_t         *pattern,
-			       image_draw_func_t              draw_func,
-			       void                          *draw_closure,
-			       cairo_image_surface_t         *dst)
-{
-    pixman_image_t *mask;
-
-    mask = _create_composite_mask_pattern (extents, draw_func, draw_closure, dst);
-    if (unlikely (mask == NULL))
-	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
-    if (pattern == NULL) {
-	if (dst->pixman_format == PIXMAN_a8) {
-	    pixman_image_composite32 (_pixman_operator (op),
-                                      mask, NULL, dst->pixman_image,
-                                      0, 0, 0, 0,
-                                      extents->bounded.x,      extents->bounded.y,
-                                      extents->bounded.width,  extents->bounded.height);
-	} else {
-	    pixman_image_t *src;
-
-	    src = _pixman_white_image ();
-	    if (unlikely (src == NULL)) {
-		pixman_image_unref (mask);
-		return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-	    }
-
-	    pixman_image_composite32 (_pixman_operator (op),
-                                      src, mask, dst->pixman_image,
-                                      0, 0, 0, 0,
-                                      extents->bounded.x,      extents->bounded.y,
-                                      extents->bounded.width,  extents->bounded.height);
-	    pixman_image_unref (src);
-	}
-    } else {
-	pixman_image_t *src;
-	int src_x, src_y;
-
-	src = _pixman_image_for_pattern (pattern, FALSE, &extents->bounded,
-					 &dst->base.device_transform,
-					 &src_x, &src_y);
-	if (unlikely (src == NULL)) {
-	    pixman_image_unref (mask);
-	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-	}
-
-	pixman_image_composite32 (_pixman_operator (op),
-                                  src, mask, dst->pixman_image,
-                                  extents->bounded.x + src_x,  extents->bounded.y + src_y,
-                                  0, 0,
-                                  extents->bounded.x,          extents->bounded.y,
-                                  extents->bounded.width,      extents->bounded.height);
-	pixman_image_unref (src);
-    }
-
-    pixman_image_unref (mask);
-
-    return CAIRO_STATUS_SUCCESS;
-}
-
-/* Handles compositing with a clip surface when we have to do the operation
- * in two pieces and combine them together.
- */
-static cairo_status_t
-_clip_and_composite_combine (cairo_composite_rectangles_t	*extents,
-			     cairo_operator_t               op,
-			     const cairo_pattern_t         *src,
-			     image_draw_func_t              draw_func,
-			     void                          *draw_closure,
-			     cairo_image_surface_t               *dst)
-{
-    pixman_image_t *tmp;
-    cairo_surface_t *clip_surface;
-    int clip_x, clip_y;
-    cairo_status_t status;
-
-    tmp  = pixman_image_create_bits (dst->pixman_format,
-				     extents->bounded.width,
-				     extents->bounded.height,
-				     NULL, 0);
-    if (unlikely (tmp == NULL))
-	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
-    if (src == NULL) {
-	status = (*draw_func) (draw_closure,
-			       tmp, dst->pixman_format,
-			       CAIRO_OPERATOR_ADD, NULL,
-			       extents->bounded.x, extents->bounded.y,
-			       &dst->base.device_transform,
-			       extents);
-    } else {
-	/* Initialize the temporary surface from the destination surface */
-	if (! dst->base.is_clear) {
-	    pixman_image_composite32 (PIXMAN_OP_SRC,
-                                      dst->pixman_image, NULL, tmp,
-                                      extents->bounded.x,
-				      extents->bounded.y,
-                                      0, 0,
-                                      0, 0,
-                                      extents->bounded.width,
-				      extents->bounded.height);
-	}
-
-	status = (*draw_func) (draw_closure,
-			       tmp, dst->pixman_format,
-			       op, src,
-			       extents->bounded.x, extents->bounded.y,
-			       &dst->base.device_transform,
-			       extents);
-    }
-    if (unlikely (status))
-	goto CLEANUP_SURFACE;
-
-    clip_surface = _cairo_clip_get_surface (extents->clip, &dst->base,
-					    &clip_x, &clip_y);
-    if (unlikely (clip_surface->status))
-	goto CLEANUP_SURFACE;
-
-    if (! dst->base.is_clear) {
-#if PIXMAN_HAS_OP_LERP
-	pixman_image_composite32 (PIXMAN_OP_LERP,
-                                  tmp,
-                                  ((cairo_image_surface_t *) clip_surface)->pixman_image,
-                                  dst->pixman_image,
-                                  0, 0,
-                                  extents->bounded.x - clip_x,
-                                  extents->bounded.y - clip_y,
-                                  extents->bounded.x, extents->bounded.y,
-                                  extents->bounded.width, extents->bounded.height);
-#else
-	/* Punch the clip out of the destination */
-	pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE,
-                                  ((cairo_image_surface_t *) clip_surface)->pixman_image,
-                                  NULL, dst->pixman_image,
-                                  extents->bounded.x - clip_x,
-                                  extents->bounded.y - clip_y,
-                                  0, 0,
-                                  extents->bounded.x, extents->bounded.y,
-                                  extents->bounded.width, extents->bounded.height);
-
-	/* Now add the two results together */
-	pixman_image_composite32 (PIXMAN_OP_ADD,
-                                  tmp,
-                                  ((cairo_image_surface_t *) clip_surface)->pixman_image,
-                                  dst->pixman_image,
-                                  0, 0,
-                                  extents->bounded.x - clip_x,
-                                  extents->bounded.y - clip_y,
-                                  extents->bounded.x, extents->bounded.y,
-                                  extents->bounded.width, extents->bounded.height);
-#endif
-    } else {
-	pixman_image_composite32 (PIXMAN_OP_SRC,
-                                  tmp,
-                                  ((cairo_image_surface_t *) clip_surface)->pixman_image,
-                                  dst->pixman_image,
-                                  0, 0,
-                                  extents->bounded.x - clip_x,
-                                  extents->bounded.y - clip_y,
-                                  extents->bounded.x, extents->bounded.y,
-                                  extents->bounded.width, extents->bounded.height);
-    }
-
-    cairo_surface_destroy (clip_surface);
- CLEANUP_SURFACE:
-    pixman_image_unref (tmp);
-
-    return status;
-}
-
-/* Handles compositing for %CAIRO_OPERATOR_SOURCE, which is special; it's
- * defined as (src IN mask IN clip) ADD (dst OUT (mask IN clip))
- */
-static cairo_status_t
-_clip_and_composite_source (cairo_composite_rectangles_t  *extents,
-			    const cairo_pattern_t         *pattern,
-			    image_draw_func_t              draw_func,
-			    void                          *draw_closure,
-			    cairo_image_surface_t         *dst)
-{
-    pixman_image_t *mask, *src;
-    int src_x, src_y;
-
-    if (pattern == NULL) {
-	cairo_status_t status;
-
-	status = draw_func (draw_closure,
-			    dst->pixman_image, dst->pixman_format,
-			    CAIRO_OPERATOR_SOURCE, NULL,
-			    extents->bounded.x, extents->bounded.y,
-			    &dst->base.device_transform,
-			    extents);
-	if (unlikely (status))
-	    return status;
-
-	if (! _cairo_clip_is_region (extents->clip))
-	    status = _cairo_clip_combine_with_surface (extents->clip,
-						       &dst->base, 0, 0);
-
-	return status;
-    }
-
-    /* Create a surface that is mask IN clip */
-    mask = _create_composite_mask_pattern (extents, draw_func, draw_closure, dst);
-    if (unlikely (mask == NULL))
-	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
-    src = _pixman_image_for_pattern (pattern, FALSE, &extents->bounded,
-				     &dst->base.device_transform,
-				     &src_x, &src_y);
-    if (unlikely (src == NULL)) {
-	pixman_image_unref (mask);
-	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-    }
-
-    if (! dst->base.is_clear) {
-#if PIXMAN_HAS_OP_LERP
-	pixman_image_composite32 (PIXMAN_OP_LERP,
-                                  src, mask, dst->pixman_image,
-                                  extents->bounded.x + src_x, extents->bounded.y + src_y,
-                                  0, 0,
-                                  extents->bounded.x,     extents->bounded.y,
-                                  extents->bounded.width, extents->bounded.height);
-#else
-	/* Compute dest' = dest OUT (mask IN clip) */
-	pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE,
-                                  mask, NULL, dst->pixman_image,
-                                  0, 0, 0, 0,
-                                  extents->bounded.x,     extents->bounded.y,
-                                  extents->bounded.width, extents->bounded.height);
-
-	/* Now compute (src IN (mask IN clip)) ADD dest' */
-	pixman_image_composite32 (PIXMAN_OP_ADD,
-                                  src, mask, dst->pixman_image,
-                                  extents->bounded.x + src_x, extents->bounded.y + src_y,
-                                  0, 0,
-                                  extents->bounded.x,     extents->bounded.y,
-                                  extents->bounded.width, extents->bounded.height);
-#endif
-    } else {
-	pixman_image_composite32 (PIXMAN_OP_SRC,
-                                  src, mask, dst->pixman_image,
-                                  extents->bounded.x + src_x, extents->bounded.y + src_y,
-                                  0, 0,
-                                  extents->bounded.x,     extents->bounded.y,
-                                  extents->bounded.width, extents->bounded.height);
-    }
-
-    pixman_image_unref (src);
-    pixman_image_unref (mask);
-
-    return CAIRO_STATUS_SUCCESS;
-}
-
-enum {
-    NEED_CLIP_REGION = 0x1,
-    NEED_CLIP_SURFACE = 0x2,
-    FORCE_CLIP_REGION = 0x4,
-};
-
-static cairo_bool_t
-need_bounded_clip (cairo_composite_rectangles_t *extents)
-{
-    unsigned int flags = NEED_CLIP_REGION;
-    if (! _cairo_clip_is_region (extents->clip))
-	flags |= NEED_CLIP_SURFACE;
-    return flags;
-}
-
-static cairo_bool_t
-need_unbounded_clip (cairo_composite_rectangles_t *extents)
-{
-    unsigned int flags = 0;
-    if (! extents->is_bounded) {
-	flags |= NEED_CLIP_REGION;
-	if (! _cairo_clip_is_region (extents->clip))
-	    flags |= NEED_CLIP_SURFACE;
-    }
-    if (extents->clip->path != NULL)
-	flags |= NEED_CLIP_SURFACE;
-    return flags;
-}
-
-
-static cairo_status_t
-_clip_and_composite (cairo_image_surface_t	*dst,
-		     cairo_operator_t		 op,
-		     const cairo_pattern_t	*src,
-		     image_draw_func_t		 draw_func,
-		     void			*draw_closure,
-		     cairo_composite_rectangles_t*extents,
-		     unsigned int need_clip)
-{
-    cairo_region_t *clip_region = NULL;
-    cairo_status_t status;
-
-    if (need_clip & NEED_CLIP_REGION) {
-	clip_region = _cairo_clip_get_region (extents->clip);
-	if ((need_clip & FORCE_CLIP_REGION) == 0 &&
-	    cairo_region_contains_rectangle (clip_region,
-					     &extents->unbounded) == CAIRO_REGION_OVERLAP_IN)
-	    clip_region = NULL;
-	if (clip_region != NULL) {
-	    status = _cairo_image_surface_set_clip_region (dst, clip_region);
-	    if (unlikely (status))
-		return status;
-	}
-    }
-
-    if (reduce_alpha_op (dst, op, src)) {
-	op = CAIRO_OPERATOR_ADD;
-	src = NULL;
-    }
-
-    if (op == CAIRO_OPERATOR_SOURCE) {
-	status = _clip_and_composite_source (extents, src,
-					     draw_func, draw_closure, dst);
-    } else {
-	if (op == CAIRO_OPERATOR_CLEAR) {
-	    src = NULL;
-	    op = CAIRO_OPERATOR_DEST_OUT;
-	}
-
-	if (need_clip & NEED_CLIP_SURFACE) {
-	    if (extents->is_bounded) {
-		status = _clip_and_composite_with_mask (extents, op, src,
-							draw_func, draw_closure,
-							dst);
-	    } else {
-		status = _clip_and_composite_combine (extents, op, src,
-						      draw_func, draw_closure,
-						      dst);
-	    }
-	} else {
-	    status = draw_func (draw_closure,
-				dst->pixman_image, dst->pixman_format,
-				op, src,
-				0, 0,
-				&dst->base.device_transform,
-				extents);
-	}
-    }
-
-    if (status == CAIRO_STATUS_SUCCESS && ! extents->is_bounded) {
-	status = _cairo_image_surface_fixup_unbounded (dst, extents,
-						       need_clip & NEED_CLIP_SURFACE ? extents->clip : NULL);
-    }
-
-    if (clip_region != NULL)
-	_cairo_image_surface_unset_clip_region (dst);
-
-    return status;
-}
-
-#define CAIRO_FIXED_16_16_MIN _cairo_fixed_from_int (-32768)
-#define CAIRO_FIXED_16_16_MAX _cairo_fixed_from_int (32767)
-
-static cairo_bool_t
-_line_exceeds_16_16 (const cairo_line_t *line)
-{
-    return
-	line->p1.x <= CAIRO_FIXED_16_16_MIN ||
-	line->p1.x >= CAIRO_FIXED_16_16_MAX ||
-
-	line->p2.x <= CAIRO_FIXED_16_16_MIN ||
-	line->p2.x >= CAIRO_FIXED_16_16_MAX ||
-
-	line->p1.y <= CAIRO_FIXED_16_16_MIN ||
-	line->p1.y >= CAIRO_FIXED_16_16_MAX ||
-
-	line->p2.y <= CAIRO_FIXED_16_16_MIN ||
-	line->p2.y >= CAIRO_FIXED_16_16_MAX;
-}
-
-static void
-_project_line_x_onto_16_16 (const cairo_line_t *line,
-			    cairo_fixed_t top,
-			    cairo_fixed_t bottom,
-			    pixman_line_fixed_t *out)
-{
-    cairo_point_double_t p1, p2;
-    double m;
-
-    p1.x = _cairo_fixed_to_double (line->p1.x);
-    p1.y = _cairo_fixed_to_double (line->p1.y);
-
-    p2.x = _cairo_fixed_to_double (line->p2.x);
-    p2.y = _cairo_fixed_to_double (line->p2.y);
-
-    m = (p2.x - p1.x) / (p2.y - p1.y);
-    out->p1.x = _cairo_fixed_16_16_from_double (p1.x + m * _cairo_fixed_to_double (top - line->p1.y));
-    out->p2.x = _cairo_fixed_16_16_from_double (p1.x + m * _cairo_fixed_to_double (bottom - line->p1.y));
-}
-
-
-typedef struct {
-    cairo_trapezoid_t *traps;
-    int num_traps;
-    cairo_antialias_t antialias;
-} composite_traps_info_t;
-
-static void
-_pixman_image_add_traps (pixman_image_t *image,
-			 int dst_x, int dst_y,
-			 composite_traps_info_t *info)
-{
-    cairo_trapezoid_t *t = info->traps;
-    int num_traps = info->num_traps;
-    while (num_traps--) {
-	pixman_trapezoid_t trap;
-
-	/* top/bottom will be clamped to surface bounds */
-	trap.top = _cairo_fixed_to_16_16 (t->top);
-	trap.bottom = _cairo_fixed_to_16_16 (t->bottom);
-
-	/* However, all the other coordinates will have been left untouched so
-	 * as not to introduce numerical error. Recompute them if they
-	 * exceed the 16.16 limits.
-	 */
-	if (unlikely (_line_exceeds_16_16 (&t->left))) {
-	    _project_line_x_onto_16_16 (&t->left, t->top, t->bottom, &trap.left);
-	    trap.left.p1.y = trap.top;
-	    trap.left.p2.y = trap.bottom;
-	} else {
-	    trap.left.p1.x = _cairo_fixed_to_16_16 (t->left.p1.x);
-	    trap.left.p1.y = _cairo_fixed_to_16_16 (t->left.p1.y);
-	    trap.left.p2.x = _cairo_fixed_to_16_16 (t->left.p2.x);
-	    trap.left.p2.y = _cairo_fixed_to_16_16 (t->left.p2.y);
-	}
-
-	if (unlikely (_line_exceeds_16_16 (&t->right))) {
-	    _project_line_x_onto_16_16 (&t->right, t->top, t->bottom, &trap.right);
-	    trap.right.p1.y = trap.top;
-	    trap.right.p2.y = trap.bottom;
-	} else {
-	    trap.right.p1.x = _cairo_fixed_to_16_16 (t->right.p1.x);
-	    trap.right.p1.y = _cairo_fixed_to_16_16 (t->right.p1.y);
-	    trap.right.p2.x = _cairo_fixed_to_16_16 (t->right.p2.x);
-	    trap.right.p2.y = _cairo_fixed_to_16_16 (t->right.p2.y);
-	}
-
-	pixman_rasterize_trapezoid (image, &trap, -dst_x, -dst_y);
-
-	t++;
-    }
-}
-
-static cairo_status_t
-_composite_traps (void                          *closure,
-		  pixman_image_t		*dst,
-		  pixman_format_code_t		 dst_format,
-		  cairo_operator_t               op,
-		  const cairo_pattern_t         *pattern,
-		  int                            dst_x,
-		  int                            dst_y,
-		  cairo_matrix_t		*dst_device_transform,
-		  const cairo_composite_rectangles_t   *extents)
-{
-    composite_traps_info_t *info = closure;
-    pixman_image_t *src, *mask;
-    pixman_format_code_t format;
-    int src_x = 0, src_y = 0;
-    cairo_status_t status;
-
-    /* Special case adding trapezoids onto a mask surface; we want to avoid
-     * creating an intermediate temporary mask unnecessarily.
-     *
-     * We make the assumption here that the portion of the trapezoids
-     * contained within the surface is bounded by [dst_x,dst_y,width,height];
-     * the Cairo core code passes bounds based on the trapezoid extents.
-     */
-    format = info->antialias == CAIRO_ANTIALIAS_NONE ? PIXMAN_a1 : PIXMAN_a8;
-    if (dst_format == format &&
-	(pattern == NULL ||
-	 (op == CAIRO_OPERATOR_ADD && _cairo_pattern_is_opaque_solid (pattern))))
-    {
-	_pixman_image_add_traps (dst, dst_x, dst_y, info);
-	return CAIRO_STATUS_SUCCESS;
-    }
-
-    src = _pixman_image_for_pattern (pattern, FALSE, &extents->bounded,
-				     dst_device_transform,
-				     &src_x, &src_y);
-    if (unlikely (src == NULL))
-	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
-    mask = pixman_image_create_bits (format,
-				     extents->bounded.width,
-				     extents->bounded.height,
-				     NULL, 0);
-    if (unlikely (mask == NULL)) {
-	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
-	goto CLEANUP_SOURCE;
-    }
-
-    _pixman_image_add_traps (mask, extents->bounded.x, extents->bounded.y, info);
-    pixman_image_composite32 (_pixman_operator (op),
-                              src, mask, dst,
-                              extents->bounded.x + src_x, extents->bounded.y + src_y,
-                              0, 0,
-                              extents->bounded.x - dst_x, extents->bounded.y - dst_y,
-                              extents->bounded.width, extents->bounded.height);
-
-    pixman_image_unref (mask);
-
-    status = CAIRO_STATUS_SUCCESS;
- CLEANUP_SOURCE:
-    pixman_image_unref (src);
-
-    return status;
-}
-
-static inline uint32_t
-color_to_uint32 (const cairo_color_t *color)
-{
-    return
-        (color->alpha_short >> 8 << 24) |
-        (color->red_short >> 8 << 16)   |
-        (color->green_short & 0xff00)   |
-        (color->blue_short >> 8);
-}
-
-static inline cairo_bool_t
-color_to_pixel (const cairo_color_t	*color,
-                pixman_format_code_t	 format,
-                uint32_t		*pixel)
-{
-    uint32_t c;
-
-    if (!(format == PIXMAN_a8r8g8b8     ||
-          format == PIXMAN_x8r8g8b8     ||
-          format == PIXMAN_a8b8g8r8     ||
-          format == PIXMAN_x8b8g8r8     ||
-          format == PIXMAN_b8g8r8a8     ||
-          format == PIXMAN_b8g8r8x8     ||
-          format == PIXMAN_r5g6b5       ||
-          format == PIXMAN_b5g6r5       ||
-          format == PIXMAN_a8))
-    {
-	return FALSE;
-    }
-
-    c = color_to_uint32 (color);
-
-    if (PIXMAN_FORMAT_TYPE (format) == PIXMAN_TYPE_ABGR) {
-	c = ((c & 0xff000000) >>  0) |
-	    ((c & 0x00ff0000) >> 16) |
-	    ((c & 0x0000ff00) >>  0) |
-	    ((c & 0x000000ff) << 16);
-    }
-
-    if (PIXMAN_FORMAT_TYPE (format) == PIXMAN_TYPE_BGRA) {
-	c = ((c & 0xff000000) >> 24) |
-	    ((c & 0x00ff0000) >>  8) |
-	    ((c & 0x0000ff00) <<  8) |
-	    ((c & 0x000000ff) << 24);
-    }
-
-    if (format == PIXMAN_a8) {
-	c = c >> 24;
-    } else if (format == PIXMAN_r5g6b5 || format == PIXMAN_b5g6r5) {
-	c = ((((c) >> 3) & 0x001f) |
-	     (((c) >> 5) & 0x07e0) |
-	     (((c) >> 8) & 0xf800));
-    }
-
-    *pixel = c;
-    return TRUE;
-}
-
-static inline cairo_bool_t
-pattern_to_pixel (const cairo_solid_pattern_t *solid,
-		  cairo_operator_t op,
-		  pixman_format_code_t format,
-		  uint32_t *pixel)
-{
-    if (op == CAIRO_OPERATOR_CLEAR) {
-	*pixel = 0;
-	return TRUE;
-    }
-
-    if (solid->base.type != CAIRO_PATTERN_TYPE_SOLID)
-	return FALSE;
-
-    if (op == CAIRO_OPERATOR_OVER) {
-	if (solid->color.alpha_short >= 0xff00)
-	    op = CAIRO_OPERATOR_SOURCE;
-    }
-
-    if (op != CAIRO_OPERATOR_SOURCE)
-	return FALSE;
-
-    return color_to_pixel (&solid->color, format, pixel);
-}
-
-typedef struct _fill_span {
-    cairo_span_renderer_t base;
-
-    uint8_t *mask_data;
-    pixman_image_t *src, *dst, *mask;
-} fill_span_renderer_t;
-
-static cairo_status_t
-_fill_span (void *abstract_renderer,
-	    int y, int height,
-	    const cairo_half_open_span_t *spans,
-	    unsigned num_spans)
-{
-    fill_span_renderer_t *renderer = abstract_renderer;
-    uint8_t *row;
-    unsigned i;
-
-    if (num_spans == 0)
-	return CAIRO_STATUS_SUCCESS;
-
-    row = renderer->mask_data - spans[0].x;
-    for (i = 0; i < num_spans - 1; i++) {
-	/* We implement setting the most common single pixel wide
-	 * span case to avoid the overhead of a memset call.
-	 * Open coding setting longer spans didn't show a
-	 * noticeable improvement over memset.
-	 */
-	if (spans[i+1].x == spans[i].x + 1) {
-	    row[spans[i].x] = spans[i].coverage;
-	} else {
-	    memset (row + spans[i].x,
-		    spans[i].coverage,
-		    spans[i+1].x - spans[i].x);
-	}
-    }
-
-    do {
-	pixman_image_composite32 (PIXMAN_OP_OVER,
-                                  renderer->src, renderer->mask, renderer->dst,
-                                  0, 0, 0, 0,
-                                  spans[0].x, y++,
-                                  spans[i].x - spans[0].x, 1);
-    } while (--height);
-
-    return CAIRO_STATUS_SUCCESS;
-}
-
-/* avoid using region code to re-validate boxes */
-static cairo_status_t
-_fill_unaligned_boxes (cairo_image_surface_t *dst,
-		       const cairo_pattern_t *pattern,
-		       uint32_t pixel,
-		       const cairo_boxes_t *boxes,
-		       const cairo_composite_rectangles_t *extents)
-{
-    uint8_t buf[CAIRO_STACK_BUFFER_SIZE];
-    fill_span_renderer_t renderer;
-    cairo_rectangular_scan_converter_t converter;
-    const struct _cairo_boxes_chunk *chunk;
-    cairo_status_t status;
-    int i;
-
-    /* XXX
-     * using composite for fill:
-     *   spiral-box-nonalign-evenodd-fill.512    2201957    2.202
-     *   spiral-box-nonalign-nonzero-fill.512     336726    0.337
-     *   spiral-box-pixalign-evenodd-fill.512     352256    0.352
-     *   spiral-box-pixalign-nonzero-fill.512     147056    0.147
-     * using fill:
-     *   spiral-box-nonalign-evenodd-fill.512    3174565    3.175
-     *   spiral-box-nonalign-nonzero-fill.512     182710    0.183
-     *   spiral-box-pixalign-evenodd-fill.512     353863    0.354
-     *   spiral-box-pixalign-nonzero-fill.512     147402    0.147
-     *
-     * cairo-perf-trace seems to favour using fill.
-     */
-
-    renderer.base.render_rows = _fill_span;
-    renderer.dst = dst->pixman_image;
-
-    if ((unsigned) extents->bounded.width <= sizeof (buf)) {
-	renderer.mask = pixman_image_create_bits (PIXMAN_a8,
-						  extents->bounded.width, 1,
-						  (uint32_t *) buf,
-						  sizeof (buf));
-    } else {
-	renderer.mask = pixman_image_create_bits (PIXMAN_a8,
-						  extents->bounded.width, 1,
-						  NULL,  0);
-    }
-    if (unlikely (renderer.mask == NULL))
-	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
-    renderer.mask_data = (uint8_t *) pixman_image_get_data (renderer.mask);
-
-    renderer.src = _pixman_image_for_solid ((const cairo_solid_pattern_t *) pattern);
-    if (unlikely (renderer.src == NULL)) {
-	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
-	goto CLEANUP_MASK;
-    }
-
-    _cairo_rectangular_scan_converter_init (&converter, &extents->bounded);
-
-    /* first blit any aligned part of the boxes */
-    for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
-	const cairo_box_t *box = chunk->base;
-
-	for (i = 0; i < chunk->count; i++) {
-	    int x1 = _cairo_fixed_integer_ceil (box[i].p1.x);
-	    int y1 = _cairo_fixed_integer_ceil (box[i].p1.y);
-	    int x2 = _cairo_fixed_integer_floor (box[i].p2.x);
-	    int y2 = _cairo_fixed_integer_floor (box[i].p2.y);
-
-	    if (x2 > x1 && y2 > y1) {
-		cairo_box_t b;
-
-		pixman_fill ((uint32_t *) dst->data,
-			     dst->stride / sizeof (uint32_t),
-			     PIXMAN_FORMAT_BPP (dst->pixman_format),
-			     x1, y1, x2 - x1, y2 - y1,
-			     pixel);
-
-		/*
-		 * Corners have to be included only once if the rects
-		 * are passed to the rectangular scan converter
-		 * because it can only handle disjoint rectangles.
-		*/
-
-		/* top (including top-left and top-right corners) */
-		if (! _cairo_fixed_is_integer (box[i].p1.y)) {
-		    b.p1.x = box[i].p1.x;
-		    b.p1.y = box[i].p1.y;
-		    b.p2.x = box[i].p2.x;
-		    b.p2.y = _cairo_fixed_from_int (y1);
-
-		    status = _cairo_rectangular_scan_converter_add_box (&converter, &b, 1);
-		    if (unlikely (status))
-			goto CLEANUP_CONVERTER;
-		}
-
-		/* left (no corners) */
-		if (! _cairo_fixed_is_integer (box[i].p1.x)) {
-		    b.p1.x = box[i].p1.x;
-		    b.p1.y = _cairo_fixed_from_int (y1);
-		    b.p2.x = _cairo_fixed_from_int (x1);
-		    b.p2.y = _cairo_fixed_from_int (y2);
-
-		    status = _cairo_rectangular_scan_converter_add_box (&converter, &b, 1);
-		    if (unlikely (status))
-			goto CLEANUP_CONVERTER;
-		}
-
-		/* right (no corners) */
-		if (! _cairo_fixed_is_integer (box[i].p2.x)) {
-		    b.p1.x = _cairo_fixed_from_int (x2);
-		    b.p1.y = _cairo_fixed_from_int (y1);
-		    b.p2.x = box[i].p2.x;
-		    b.p2.y = _cairo_fixed_from_int (y2);
-
-		    status = _cairo_rectangular_scan_converter_add_box (&converter, &b, 1);
-		    if (unlikely (status))
-			goto CLEANUP_CONVERTER;
-		}
-
-		/* bottom (including bottom-left and bottom-right corners) */
-		if (! _cairo_fixed_is_integer (box[i].p2.y)) {
-		    b.p1.x = box[i].p1.x;
-		    b.p1.y = _cairo_fixed_from_int (y2);
-		    b.p2.x = box[i].p2.x;
-		    b.p2.y = box[i].p2.y;
-
-		    status = _cairo_rectangular_scan_converter_add_box (&converter, &b, 1);
-		    if (unlikely (status))
-			goto CLEANUP_CONVERTER;
-		}
-	    } else {
-		status = _cairo_rectangular_scan_converter_add_box (&converter, &box[i], 1);
-		if (unlikely (status))
-		    goto CLEANUP_CONVERTER;
-	    }
-	}
-    }
-
-    status = converter.base.generate (&converter.base, &renderer.base);
-
-  CLEANUP_CONVERTER:
-    converter.base.destroy (&converter.base);
-    pixman_image_unref (renderer.src);
-  CLEANUP_MASK:
-    pixman_image_unref (renderer.mask);
-
-    return status;
-}
-
-typedef struct _cairo_image_surface_span_renderer {
-    cairo_span_renderer_t base;
-
-    uint8_t *mask_data;
-    uint32_t mask_stride;
-} cairo_image_surface_span_renderer_t;
-
-static cairo_status_t
-_cairo_image_surface_span (void *abstract_renderer,
-			   int y, int height,
-			   const cairo_half_open_span_t *spans,
-			   unsigned num_spans)
-{
-    cairo_image_surface_span_renderer_t *renderer = abstract_renderer;
-    uint8_t *row;
-    unsigned i;
-
-    if (num_spans == 0)
-	return CAIRO_STATUS_SUCCESS;
-
-    /* XXX will it be quicker to repeat the sparse memset,
-     * or perform a simpler memcpy?
-     * The fairly dense spiral benchmarks suggests that the sparse
-     * memset is a win there as well.
-     */
-    row = renderer->mask_data + y * renderer->mask_stride;
-    do {
-	for (i = 0; i < num_spans - 1; i++) {
-	    if (! spans[i].coverage)
-		continue;
-
-	    /* We implement setting rendering the most common single
-	     * pixel wide span case to avoid the overhead of a memset
-	     * call.  Open coding setting longer spans didn't show a
-	     * noticeable improvement over memset. */
-	    if (spans[i+1].x == spans[i].x + 1) {
-		row[spans[i].x] = spans[i].coverage;
-	    } else {
-		memset (row + spans[i].x,
-			spans[i].coverage,
-			spans[i+1].x - spans[i].x);
-	    }
-	}
-	row += renderer->mask_stride;
-    } while (--height);
-
-    return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_composite_unaligned_boxes (cairo_image_surface_t *dst,
-			    cairo_operator_t op,
-			    const cairo_pattern_t *pattern,
-			    const cairo_boxes_t *boxes,
-			    const cairo_composite_rectangles_t *extents)
-{
-    uint8_t buf[CAIRO_STACK_BUFFER_SIZE];
-    cairo_image_surface_span_renderer_t renderer;
-    cairo_rectangular_scan_converter_t converter;
-    pixman_image_t *mask, *src;
-    cairo_status_t status;
-    const struct _cairo_boxes_chunk *chunk;
-    int i, src_x, src_y;
-
-    /* The below code breaks for operator source. This can best be seen with
-     * multiple boxes where black is drawn to dst outside of the boxes. */
-    if (op == CAIRO_OPERATOR_SOURCE)
-	return CAIRO_INT_STATUS_UNSUPPORTED;
-
-    i = CAIRO_STRIDE_FOR_WIDTH_BPP (extents->bounded.width, 8) * extents->bounded.height;
-    if ((unsigned) i <= sizeof (buf)) {
-	mask = pixman_image_create_bits (PIXMAN_a8,
-					 extents->bounded.width,
-					 extents->bounded.height,
-					 (uint32_t *) buf,
-					 CAIRO_STRIDE_FOR_WIDTH_BPP (extents->bounded.width, 8));
-	memset (buf, 0, i);
-    } else {
-	mask = pixman_image_create_bits (PIXMAN_a8,
-					 extents->bounded.width,
-					 extents->bounded.height,
-					 NULL,  0);
-    }
-    if (unlikely (mask == NULL))
-	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
-    renderer.base.render_rows = _cairo_image_surface_span;
-    renderer.mask_stride = pixman_image_get_stride (mask);
-    renderer.mask_data = (uint8_t *) pixman_image_get_data (mask);
-    renderer.mask_data -= extents->bounded.y * renderer.mask_stride + extents->bounded.x;
-
-    _cairo_rectangular_scan_converter_init (&converter, &extents->bounded);
-
-    for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
-	const cairo_box_t *box = chunk->base;
-
-	for (i = 0; i < chunk->count; i++) {
-	    status = _cairo_rectangular_scan_converter_add_box (&converter, &box[i], 1);
-	    if (unlikely (status))
-		goto CLEANUP;
-	}
-    }
-
-    status = converter.base.generate (&converter.base, &renderer.base);
-    if (unlikely (status))
-	goto CLEANUP;
-
-    src = _pixman_image_for_pattern (pattern, FALSE, &extents->bounded,
-				     &dst->base.device_transform,
-				     &src_x, &src_y);
-    if (unlikely (src == NULL)) {
-	status =  _cairo_error (CAIRO_STATUS_NO_MEMORY);
-	goto CLEANUP;
-    }
-
-    pixman_image_composite32 (_pixman_operator (op),
-                              src, mask, dst->pixman_image,
-                              extents->bounded.x + src_x, extents->bounded.y + src_y,
-                              0, 0,
-                              extents->bounded.x, extents->bounded.y,
-                              extents->bounded.width, extents->bounded.height);
-    pixman_image_unref (src);
-
-  CLEANUP:
-    converter.base.destroy (&converter.base);
-    pixman_image_unref (mask);
-
-    return status;
-}
-
-static cairo_bool_t
-is_recording_pattern (const cairo_pattern_t *pattern)
-{
-    cairo_surface_t *surface;
-
-    if (pattern->type != CAIRO_PATTERN_TYPE_SURFACE)
-	return FALSE;
-
-    surface = ((const cairo_surface_pattern_t *) pattern)->surface;
-    if (_cairo_surface_is_paginated (surface))
-	surface = _cairo_paginated_surface_get_recording (surface);
-    if (_cairo_surface_is_snapshot (surface))
-	surface = _cairo_surface_snapshot_get_target (surface);
-    return _cairo_surface_is_recording (surface);
-}
-
-static cairo_surface_t *
-recording_pattern_get_surface (const cairo_pattern_t *pattern)
-{
-    cairo_surface_t *surface;
-
-    surface = ((const cairo_surface_pattern_t *) pattern)->surface;
-    if (_cairo_surface_is_paginated (surface))
-	surface = _cairo_paginated_surface_get_recording (surface);
-    if (_cairo_surface_is_snapshot (surface))
-	surface = _cairo_surface_snapshot_get_target (surface);
-    return surface;
-}
-
-static cairo_bool_t
-op_reduces_to_source (cairo_operator_t op,
-		      cairo_image_surface_t *dst)
-{
-    if (op == CAIRO_OPERATOR_SOURCE)
-	return TRUE;
-
-    if (dst->base.is_clear)
-	return op == CAIRO_OPERATOR_OVER || op == CAIRO_OPERATOR_ADD;
-
-    return FALSE;
-}
-
-static cairo_bool_t
-recording_pattern_contains_sample (const cairo_pattern_t *pattern,
-				   const cairo_rectangle_int_t *extents)
-{
-    cairo_rectangle_int_t area;
-    cairo_recording_surface_t *surface;
-
-    if (! is_recording_pattern (pattern))
-	return FALSE;
-
-    if (pattern->extend == CAIRO_EXTEND_NONE)
-	return TRUE;
-
-    surface = (cairo_recording_surface_t *) recording_pattern_get_surface (pattern);
-    if (surface->unbounded)
-	return TRUE;
-
-    sampled_area ((cairo_surface_pattern_t *) pattern, extents, &area);
-    if (area.x >= surface->extents.x &&
-	area.y >= surface->extents.y &&
-	area.x + area.width <= surface->extents.x + surface->extents.width &&
-	area.y + area.height <= surface->extents.y + surface->extents.height)
-    {
-	return TRUE;
-    }
-
-    return FALSE;
-}
-
-static cairo_status_t
-_composite_boxes (cairo_image_surface_t *dst,
-		  cairo_operator_t op,
-		  const cairo_pattern_t *pattern,
-		  cairo_boxes_t *boxes,
-		  const cairo_composite_rectangles_t *extents)
-{
-    cairo_region_t *clip_region = _cairo_clip_get_region (extents->clip);
-    cairo_bool_t need_clip_mask = extents->clip->path != NULL;
-    cairo_status_t status;
-    struct _cairo_boxes_chunk *chunk;
-    uint32_t pixel;
-    int i;
-
-    if (need_clip_mask &&
-	(op == CAIRO_OPERATOR_SOURCE || ! extents->is_bounded))
-    {
-	return CAIRO_INT_STATUS_UNSUPPORTED;
-    }
-
-    if (clip_region != NULL && cairo_region_num_rectangles (clip_region) == 1)
-	clip_region = NULL;
-
-    if (! boxes->is_pixel_aligned) {
-	if (need_clip_mask)
-	    return CAIRO_INT_STATUS_UNSUPPORTED;
-
-	if (pattern_to_pixel ((cairo_solid_pattern_t *) pattern, op,
-			      dst->pixman_format, &pixel))
-	{
-	    return _fill_unaligned_boxes (dst, pattern, pixel, boxes, extents);
-	}
-	else
-	{
-	    return _composite_unaligned_boxes (dst, op, pattern, boxes, extents);
-	}
-    }
-
-    /* Are we just copying a recording surface? */
-    if (! need_clip_mask &&
-	op_reduces_to_source (op, dst) &&
-	recording_pattern_contains_sample (pattern, &extents->bounded))
-    {
-	cairo_clip_t *recording_clip;
-
-	/* XXX could also do tiling repeat modes... */
-
-	/* first clear the area about to be overwritten */
-	if (! dst->base.is_clear) {
-	    for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
-		cairo_box_t *box = chunk->base;
-
-		for (i = 0; i < chunk->count; i++) {
-		    int x1 = _cairo_fixed_integer_part (box[i].p1.x);
-		    int y1 = _cairo_fixed_integer_part (box[i].p1.y);
-		    int x2 = _cairo_fixed_integer_part (box[i].p2.x);
-		    int y2 = _cairo_fixed_integer_part (box[i].p2.y);
-
-		    if (x2 == x1 || y2 == y1)
-			continue;
-
-		    pixman_fill ((uint32_t *) dst->data,
-				 dst->stride / sizeof (uint32_t),
-				 PIXMAN_FORMAT_BPP (dst->pixman_format),
-				 x1, y1, x2 - x1, y2 - y1,
-				 0);
-		}
-	    }
-	}
-
-	recording_clip = _cairo_clip_from_boxes (boxes);
-	status = _cairo_recording_surface_replay_with_clip (recording_pattern_get_surface (pattern),
-							    &pattern->matrix,
-							    &dst->base,
-							    recording_clip);
-	_cairo_clip_destroy (recording_clip);
-
-	return status;
-    }
-
-    status = CAIRO_STATUS_SUCCESS;
-    if (! need_clip_mask &&
-	pattern_to_pixel ((cairo_solid_pattern_t *) pattern, op, dst->pixman_format,
-			  &pixel))
-    {
-	for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
-	    cairo_box_t *box = chunk->base;
-
-	    for (i = 0; i < chunk->count; i++) {
-		int x1 = _cairo_fixed_integer_part (box[i].p1.x);
-		int y1 = _cairo_fixed_integer_part (box[i].p1.y);
-		int x2 = _cairo_fixed_integer_part (box[i].p2.x);
-		int y2 = _cairo_fixed_integer_part (box[i].p2.y);
-
-		if (x2 == x1 || y2 == y1)
-		    continue;
-
-		pixman_fill ((uint32_t *) dst->data, dst->stride / sizeof (uint32_t),
-			     PIXMAN_FORMAT_BPP (dst->pixman_format),
-			     x1, y1, x2 - x1, y2 - y1,
-			     pixel);
-	    }
-	}
-    }
-    else
-    {
-	cairo_surface_t *clip_surface = NULL;
-	pixman_image_t *src = NULL, *mask = NULL;
-	int src_x, src_y, mask_x = 0, mask_y = 0;
-	pixman_op_t pixman_op = _pixman_operator (op);
-
-	if (need_clip_mask) {
-	    int clip_x, clip_y;
-
-	    clip_surface = _cairo_clip_get_surface (extents->clip,
-						    &dst->base,
-						    &clip_x, &clip_y);
-	    if (unlikely (clip_surface->status))
-		return clip_surface->status;
-
-	    mask_x = -clip_x;
-	    mask_y = -clip_y;
-
-	    if (op == CAIRO_OPERATOR_CLEAR) {
-		pattern = NULL;
-		pixman_op = PIXMAN_OP_OUT_REVERSE;
-	    }
-
-	    mask = ((cairo_image_surface_t *) clip_surface)->pixman_image;
-	}
-
-	if (pattern != NULL) {
-	    src = _pixman_image_for_pattern (pattern, FALSE, &extents->bounded,
-					     &dst->base.device_transform,
-					     &src_x, &src_y);
-	    if (unlikely (src == NULL)) {
-		cairo_surface_destroy (clip_surface);
-		return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-	    }
-	} else {
-	    src = mask;
-	    src_x = mask_x;
-	    src_y = mask_y;
-	    mask = NULL;
-	}
-
-	for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
-	    const cairo_box_t *box = chunk->base;
-
-	    for (i = 0; i < chunk->count; i++) {
-		int x1 = _cairo_fixed_integer_part (box[i].p1.x);
-		int y1 = _cairo_fixed_integer_part (box[i].p1.y);
-		int x2 = _cairo_fixed_integer_part (box[i].p2.x);
-		int y2 = _cairo_fixed_integer_part (box[i].p2.y);
-
-		if (x2 == x1 || y2 == y1)
-		    continue;
-
-		pixman_image_composite32 (pixman_op,
-                                          src, mask, dst->pixman_image,
-                                          x1 + src_x,  y1 + src_y,
-                                          x1 + mask_x, y1 + mask_y,
-                                          x1, y1,
-                                          x2 - x1, y2 - y1);
-	    }
-	}
-
-	cairo_surface_destroy (clip_surface);
-	if (pattern != NULL)
-	    pixman_image_unref (src);
-
-	if (! extents->is_bounded) {
-	    status =
-		_cairo_image_surface_fixup_unbounded_boxes (dst, extents,
-							    clip_region, boxes);
-	}
-    }
-
-    return status;
-}
-
-static cairo_status_t
-_clip_and_composite_polygon (cairo_image_surface_t *dst,
-			     cairo_operator_t op,
-			     const cairo_pattern_t *src,
-			     cairo_polygon_t *polygon,
-			     cairo_fill_rule_t fill_rule,
-			     cairo_antialias_t antialias,
-			     cairo_composite_rectangles_t *extents);
-
-static cairo_status_t
-_clip_and_composite_boxes (cairo_image_surface_t *dst,
-			   cairo_operator_t op,
-			   const cairo_pattern_t *src,
-			   cairo_boxes_t *boxes,
-			   cairo_composite_rectangles_t *extents)
-{
-    cairo_traps_t traps;
-    cairo_int_status_t status;
-    composite_traps_info_t info;
-
-    if (boxes->num_boxes == 0 && extents->is_bounded)
-	return CAIRO_STATUS_SUCCESS;
-
-    /* Can we reduce drawing through a clip-mask to simply drawing the clip? */
-    if (extents->clip->path != NULL && extents->is_bounded) {
-	cairo_polygon_t polygon;
-	cairo_fill_rule_t fill_rule;
-	cairo_antialias_t antialias;
-	cairo_clip_t *clip;
-
-	clip = _cairo_clip_copy (extents->clip);
-	clip = _cairo_clip_intersect_boxes (clip, boxes);
-	status = _cairo_clip_get_polygon (clip, &polygon,
-					  &fill_rule, &antialias);
-	_cairo_clip_path_destroy (clip->path);
-	clip->path = NULL;
-	if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
-	    cairo_clip_t *saved_clip = extents->clip;
-	    extents->clip = clip;
-	    status = _clip_and_composite_polygon (dst, op, src,
-						  &polygon,
-						  fill_rule,
-						  antialias,
-						  extents);
-	    if (extents->clip != clip)
-		clip = NULL;
-	    extents->clip = saved_clip;
-	    _cairo_polygon_fini (&polygon);
-	}
-	if (clip)
-	    _cairo_clip_destroy (clip);
-
-	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
-	    return status;
-    }
-
-    /* Use a fast path if the boxes are pixel aligned */
-    status = _composite_boxes (dst, op, src, boxes, extents);
-    if (status != CAIRO_INT_STATUS_UNSUPPORTED)
-	return status;
-
-    /* Otherwise render via a mask and composite in the usual fashion.  */
-    status = _cairo_traps_init_boxes (&traps, boxes);
-    if (unlikely (status))
-	return status;
-
-    info.num_traps = traps.num_traps;
-    info.traps = traps.traps;
-    info.antialias = CAIRO_ANTIALIAS_DEFAULT;
-    status = _clip_and_composite (dst, op, src,
-				  _composite_traps, &info,
-				  extents, need_unbounded_clip (extents));
-
-    _cairo_traps_fini (&traps);
-    return status;
-}
-
-static cairo_bool_t
-_mono_edge_is_vertical (const cairo_line_t *line)
-{
-    return _cairo_fixed_integer_round_down (line->p1.x) == _cairo_fixed_integer_round_down (line->p2.x);
-}
-
-static cairo_bool_t
-_traps_are_pixel_aligned (cairo_traps_t *traps,
-			  cairo_antialias_t antialias)
-{
-    int i;
-
-    if (antialias == CAIRO_ANTIALIAS_NONE) {
-	for (i = 0; i < traps->num_traps; i++) {
-	    if (! _mono_edge_is_vertical (&traps->traps[i].left)   ||
-		! _mono_edge_is_vertical (&traps->traps[i].right))
-	    {
-		traps->maybe_region = FALSE;
-		return FALSE;
-	    }
-	}
-    } else {
-	for (i = 0; i < traps->num_traps; i++) {
-	    if (traps->traps[i].left.p1.x != traps->traps[i].left.p2.x   ||
-		traps->traps[i].right.p1.x != traps->traps[i].right.p2.x ||
-		! _cairo_fixed_is_integer (traps->traps[i].top)          ||
-		! _cairo_fixed_is_integer (traps->traps[i].bottom)       ||
-		! _cairo_fixed_is_integer (traps->traps[i].left.p1.x)    ||
-		! _cairo_fixed_is_integer (traps->traps[i].right.p1.x))
-	    {
-		traps->maybe_region = FALSE;
-		return FALSE;
-	    }
-	}
-    }
-
-    return TRUE;
-}
-
-static void
-_boxes_for_traps (cairo_boxes_t *boxes,
-		  cairo_traps_t *traps,
-		  cairo_antialias_t antialias)
-{
-    int i;
-
-    _cairo_boxes_init (boxes);
-
-    boxes->num_boxes    = traps->num_traps;
-    boxes->chunks.base  = (cairo_box_t *) traps->traps;
-    boxes->chunks.count = traps->num_traps;
-    boxes->chunks.size  = traps->num_traps;
-
-    if (antialias != CAIRO_ANTIALIAS_NONE) {
-	for (i = 0; i < traps->num_traps; i++) {
-	    /* Note the traps and boxes alias so we need to take the local copies first. */
-	    cairo_fixed_t x1 = traps->traps[i].left.p1.x;
-	    cairo_fixed_t x2 = traps->traps[i].right.p1.x;
-	    cairo_fixed_t y1 = traps->traps[i].top;
-	    cairo_fixed_t y2 = traps->traps[i].bottom;
-
-	    boxes->chunks.base[i].p1.x = x1;
-	    boxes->chunks.base[i].p1.y = y1;
-	    boxes->chunks.base[i].p2.x = x2;
-	    boxes->chunks.base[i].p2.y = y2;
-
-	    if (boxes->is_pixel_aligned) {
-		boxes->is_pixel_aligned =
-		    _cairo_fixed_is_integer (x1) && _cairo_fixed_is_integer (y1) &&
-		    _cairo_fixed_is_integer (x2) && _cairo_fixed_is_integer (y2);
-	    }
-	}
-    } else {
-	boxes->is_pixel_aligned = TRUE;
-
-	for (i = 0; i < traps->num_traps; i++) {
-	    /* Note the traps and boxes alias so we need to take the local copies first. */
-	    cairo_fixed_t x1 = traps->traps[i].left.p1.x;
-	    cairo_fixed_t x2 = traps->traps[i].right.p1.x;
-	    cairo_fixed_t y1 = traps->traps[i].top;
-	    cairo_fixed_t y2 = traps->traps[i].bottom;
-
-	    /* round down here to match Pixman's behavior when using traps. */
-	    boxes->chunks.base[i].p1.x = _cairo_fixed_round_down (x1);
-	    boxes->chunks.base[i].p1.y = _cairo_fixed_round_down (y1);
-	    boxes->chunks.base[i].p2.x = _cairo_fixed_round_down (x2);
-	    boxes->chunks.base[i].p2.y = _cairo_fixed_round_down (y2);
-	}
-    }
-}
-
-static cairo_status_t
-_clip_and_composite_trapezoids (cairo_image_surface_t *dst,
-				cairo_operator_t op,
-				const cairo_pattern_t *src,
-				cairo_traps_t *traps,
-				cairo_antialias_t antialias,
-				cairo_composite_rectangles_t *extents)
-{
-    composite_traps_info_t info;
-    cairo_bool_t need_clip_surface = FALSE;
-    cairo_status_t status;
-
-    if (traps->num_traps == 0 && extents->is_bounded)
-	return CAIRO_STATUS_SUCCESS;
-
-    need_clip_surface = ! _cairo_clip_is_region (extents->clip);
-
-    if (traps->has_intersections) {
-	if (traps->is_rectangular)
-	    status = _cairo_bentley_ottmann_tessellate_rectangular_traps (traps, CAIRO_FILL_RULE_WINDING);
-	else if (traps->is_rectilinear)
-	    status = _cairo_bentley_ottmann_tessellate_rectilinear_traps (traps, CAIRO_FILL_RULE_WINDING);
-	else
-	    status = _cairo_bentley_ottmann_tessellate_traps (traps, CAIRO_FILL_RULE_WINDING);
-	if (unlikely (status))
-	    return status;
-    }
-
-    /* Use a fast path if the trapezoids consist of a simple region,
-     * but we can only do this if we do not have a clip surface, or can
-     * substitute the mask with the clip.
-     */
-    if (traps->maybe_region && _traps_are_pixel_aligned (traps, antialias) &&
-	(! need_clip_surface ||
-	 (extents->is_bounded && op != CAIRO_OPERATOR_SOURCE)))
-    {
-	cairo_boxes_t boxes;
-
-	_boxes_for_traps (&boxes, traps, antialias);
-	return _clip_and_composite_boxes (dst, op, src,
-					  &boxes, extents);
-    }
-
-    /* No fast path, exclude self-intersections and clip trapezoids. */
-    /* Otherwise render the trapezoids to a mask and composite in the usual
-     * fashion.
-     */
-    info.traps = traps->traps;
-    info.num_traps = traps->num_traps;
-    info.antialias = antialias;
-    return _clip_and_composite (dst, op, src,
-				_composite_traps, &info,
-				extents, need_unbounded_clip (extents));
-}
-
 /* high level image interface */
 cairo_bool_t
 _cairo_image_surface_get_extents (void			  *abstract_surface,
@@ -3449,235 +859,10 @@ _cairo_image_surface_paint (void			*abstract_surface,
 			    const cairo_clip_t		*clip)
 {
     cairo_image_surface_t *surface = abstract_surface;
-    cairo_rectangle_int_t unbounded;
-    cairo_composite_rectangles_t extents;
-    cairo_status_t status;
-    cairo_boxes_t boxes;
-
-    _cairo_image_surface_get_extents (surface, &unbounded);
-    status = _cairo_composite_rectangles_init_for_paint (&extents, &unbounded,
-							 op, source,
-							 clip);
-    if (unlikely (status))
-	return status;
-
-    /* If the clip cannot be reduced to a set of boxes, we will need to
-     * use a clipmask. Paint is special as it is the only operation that
-     * does not implicitly use a mask, so we may be able to reduce this
-     * operation to a fill...
-     */
-
-    status = _cairo_clip_to_boxes (extents.clip, &boxes);
-    if (likely (status == CAIRO_STATUS_SUCCESS)) {
-	status = _clip_and_composite_boxes (surface, op, source,
-					    &boxes, &extents);
-	_cairo_boxes_fini (&boxes);
-    }
-
-    _cairo_composite_rectangles_fini (&extents);
-
-    return status;
-}
-
-static cairo_status_t
-_composite_mask (void				*closure,
-		 pixman_image_t			*dst,
-		 pixman_format_code_t		 dst_format,
-		 cairo_operator_t		 op,
-		 const cairo_pattern_t		*src_pattern,
-		 int				 dst_x,
-		 int				 dst_y,
-		 cairo_matrix_t			*dst_device_transform,
-		 const cairo_composite_rectangles_t	*extents)
-{
-    const cairo_pattern_t *mask_pattern = closure;
-    pixman_image_t *src, *mask = NULL;
-    int src_x = 0, src_y = 0;
-    int mask_x = 0, mask_y = 0;
-
-    if (src_pattern != NULL) {
-	src = _pixman_image_for_pattern (src_pattern, FALSE, &extents->bounded,
-					 dst_device_transform,
-					 &src_x, &src_y);
-	if (unlikely (src == NULL))
-	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
-	mask = _pixman_image_for_pattern (mask_pattern, TRUE, &extents->bounded,
-					  dst_device_transform,
-					  &mask_x, &mask_y);
-	if (unlikely (mask == NULL)) {
-	    pixman_image_unref (src);
-	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-	}
-
-	if (mask_pattern->has_component_alpha)
-	    pixman_image_set_component_alpha (mask, TRUE);
-    } else {
-	src = _pixman_image_for_pattern (mask_pattern, FALSE, &extents->bounded,
-					 dst_device_transform,
-					 &src_x, &src_y);
-	if (unlikely (src == NULL))
-	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-    }
-
-    pixman_image_composite32 (_pixman_operator (op), src, mask, dst,
-                              extents->bounded.x + src_x,  extents->bounded.y + src_y,
-                              extents->bounded.x + mask_x, extents->bounded.y + mask_y,
-                              extents->bounded.x - dst_x,  extents->bounded.y - dst_y,
-                              extents->bounded.width,      extents->bounded.height);
-
-    if (mask != NULL)
-	pixman_image_unref (mask);
-    pixman_image_unref (src);
-
-    return CAIRO_STATUS_SUCCESS;
-}
-
-static void do_unaligned_row(void (*blt)(void *closure,
-					 int16_t x, int16_t y,
-					 int16_t w, int16_t h,
-					 uint16_t coverage),
-			     void *closure,
-			     const cairo_box_t *b,
-			     int tx, int y, int h,
-			     uint16_t coverage)
-{
-    int x1 = _cairo_fixed_integer_part (b->p1.x) - tx;
-    int x2 = _cairo_fixed_integer_part (b->p2.x) - tx;
-    if (x2 > x1) {
-	if (! _cairo_fixed_is_integer (b->p1.x)) {
-	    blt(closure, x1, y, 1, h,
-		coverage * (256 - _cairo_fixed_fractional_part (b->p1.x)));
-	    x1++;
-	}
-
-	if (x2 > x1)
-	    blt(closure, x1, y, x2-x1, h, (coverage << 8) - (coverage >> 8));
-
-	if (! _cairo_fixed_is_integer (b->p2.x))
-	    blt(closure, x2, y, 1, h,
-		coverage * _cairo_fixed_fractional_part (b->p2.x));
-    } else
-	blt(closure, x1, y, 1, h,
-	    coverage * (b->p2.x - b->p1.x));
-}
-
-static void do_unaligned_box(void (*blt)(void *closure,
-					 int16_t x, int16_t y,
-					 int16_t w, int16_t h,
-					 uint16_t coverage),
-			     void *closure,
-			     const cairo_box_t *b, int tx, int ty)
-{
-    int y1 = _cairo_fixed_integer_part (b->p1.y) - ty;
-    int y2 = _cairo_fixed_integer_part (b->p2.y) - ty;
-    if (y2 > y1) {
-	if (! _cairo_fixed_is_integer (b->p1.y)) {
-	    do_unaligned_row(blt, closure, b, tx, y1, 1,
-			     256 - _cairo_fixed_fractional_part (b->p1.y));
-	    y1++;
-	}
-
-	if (y2 > y1)
-	    do_unaligned_row(blt, closure, b, tx, y1, y2-y1, 256);
-
-	if (! _cairo_fixed_is_integer (b->p2.y))
-	    do_unaligned_row(blt, closure, b, tx, y2, 1,
-			     _cairo_fixed_fractional_part (b->p2.y));
-    } else
-	do_unaligned_row(blt, closure, b, tx, y1, 1,
-			 b->p2.y - b->p1.y);
-}
-
-struct composite_opacity_info {
-    uint8_t op;
-    pixman_image_t *dst;
-    pixman_image_t *src;
-    int src_x, src_y;
-    double opacity;
-};
-
-static void composite_opacity(void *closure,
-			      int16_t x, int16_t y,
-			      int16_t w, int16_t h,
-			      uint16_t coverage)
-{
-    struct composite_opacity_info *info = closure;
-    pixman_color_t color;
-    pixman_image_t *mask;
-
-    color.red   = 0;
-    color.green = 0;
-    color.blue  = 0;
-    color.alpha = coverage * info->opacity;
-
-    mask = pixman_image_create_solid_fill (&color);
-    if (mask == NULL)
-	return;
-
-    if (info->src) {
-	pixman_image_composite32 (info->op,
-				  info->src,
-				  mask,
-				  info->dst,
-				  x + info->src_x,  y + info->src_y,
-				  0,                 0,
-				  x,                 y,
-				  w,                 h);
-    } else {
-	pixman_image_composite32 (info->op,
-				  mask,
-				  NULL,
-				  info->dst,
-				  0, 0,
-				  0, 0,
-				  x, y,
-				  w, h);
-    }
-
-    pixman_image_unref (mask);
+    return _cairo_compositor_paint (surface->compositor,
+				    &surface->base, op, source, clip);
 }
 
-static cairo_status_t
-_composite_opacity_boxes (void				*closure,
-			  pixman_image_t		*dst,
-			  pixman_format_code_t		 dst_format,
-			  cairo_operator_t		 op,
-			  const cairo_pattern_t		*src_pattern,
-			  int				 dst_x,
-			  int				 dst_y,
-			  cairo_matrix_t		*dst_device_transform,
-			  const cairo_composite_rectangles_t	*extents)
-{
-    const cairo_solid_pattern_t *mask_pattern = closure;
-    struct composite_opacity_info info;
-    int i;
-
-    info.op = _pixman_operator (op);
-    info.dst = dst;
-
-    if (src_pattern != NULL) {
-	info.src = _pixman_image_for_pattern (src_pattern, TRUE, &extents->bounded,
-					      dst_device_transform,
-					      &info.src_x, &info.src_y);
-	if (unlikely (info.src == NULL))
-	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-    } else
-	info.src = NULL;
-
-    info.opacity = mask_pattern->color.alpha;
-
-    /* XXX for lots of boxes create a clip region for the fully opaque areas */
-    for (i = 0; i < extents->clip->num_boxes; i++)
-	do_unaligned_box(composite_opacity, &info,
-			 &extents->clip->boxes[i], dst_x, dst_y);
-    if (info.src)
-	pixman_image_unref (info.src);
-
-    return CAIRO_STATUS_SUCCESS;
-}
-
-
 static cairo_int_status_t
 _cairo_image_surface_mask (void				*abstract_surface,
 			   cairo_operator_t		 op,
@@ -3686,225 +871,8 @@ _cairo_image_surface_mask (void				*abstract_surface,
 			   const cairo_clip_t		*clip)
 {
     cairo_image_surface_t *surface = abstract_surface;
-    cairo_composite_rectangles_t extents;
-    cairo_rectangle_int_t unbounded;
-    cairo_status_t status;
-
-    _cairo_image_surface_get_extents (surface, &unbounded);
-    status = _cairo_composite_rectangles_init_for_mask (&extents, &unbounded,
-							op, source, mask, clip);
-    if (unlikely (status))
-	return status;
-
-    if (mask->type == CAIRO_PATTERN_TYPE_SOLID &&
-	extents.clip->path == NULL &&
-	! _cairo_clip_is_region (extents.clip))
-    {
-	status = _clip_and_composite (surface, op, source,
-				      _composite_opacity_boxes, (void *) mask,
-				      &extents, need_bounded_clip (&extents));
-    } else {
-	status = _clip_and_composite (surface, op, source,
-				      _composite_mask, (void *) mask,
-				      &extents, need_bounded_clip (&extents));
-    }
-
-    _cairo_composite_rectangles_fini (&extents);
-
-    return status;
-}
-
-typedef struct {
-    cairo_polygon_t		*polygon;
-    cairo_fill_rule_t		 fill_rule;
-    cairo_antialias_t		 antialias;
-} composite_spans_info_t;
-
-//#define USE_BOTOR_SCAN_CONVERTER
-static cairo_status_t
-_composite_spans (void                          *closure,
-		  pixman_image_t		*dst,
-		  pixman_format_code_t		 dst_format,
-		  cairo_operator_t               op,
-		  const cairo_pattern_t         *pattern,
-		  int                            dst_x,
-		  int                            dst_y,
-		  cairo_matrix_t		*dst_device_transform,
-		  const cairo_composite_rectangles_t   *extents)
-{
-    uint8_t mask_buf[CAIRO_STACK_BUFFER_SIZE];
-    composite_spans_info_t *info = closure;
-    cairo_image_surface_span_renderer_t renderer;
-#if USE_BOTOR_SCAN_CONVERTER
-    cairo_box_t box;
-    cairo_botor_scan_converter_t converter;
-#else
-    cairo_scan_converter_t *converter;
-#endif
-    pixman_image_t *mask;
-    const cairo_rectangle_int_t *r = &extents->bounded;
-    cairo_status_t status;
-
-#if USE_BOTOR_SCAN_CONVERTER
-    box.p1.x = _cairo_fixed_from_int (r->x);
-    box.p1.y = _cairo_fixed_from_int (r->y);
-    box.p2.x = _cairo_fixed_from_int (r->x + r->width);
-    box.p2.y = _cairo_fixed_from_int (r->y + r->height);
-    _cairo_botor_scan_converter_init (&converter, &box, info->fill_rule);
-    status = converter.base.add_polygon (&converter.base, info->polygon);
-#else
-    converter = _cairo_tor_scan_converter_create (r->x, r->y,
-						  r->x + r->width,
-						  r->y + r->height,
-						  info->fill_rule);
-    status = converter->add_polygon (converter, info->polygon);
-#endif
-    if (unlikely (status))
-	goto CLEANUP_CONVERTER;
-
-    /* TODO: support rendering to A1 surfaces (or: go add span
-     * compositing to pixman.) */
-
-    if (pattern == NULL &&
-	dst_format == PIXMAN_a8 &&
-	op == CAIRO_OPERATOR_SOURCE)
-    {
-	mask = dst;
-	dst = NULL;
-    }
-    else
-    {
-	int stride = CAIRO_STRIDE_FOR_WIDTH_BPP (r->width, 8);
-	uint8_t *data = mask_buf;
-
-	if (r->height * stride <= (int) sizeof (mask_buf))
-	    memset (data, 0, r->height * stride);
-	else
-	    data = NULL, stride = 0;
-
-	mask = pixman_image_create_bits (PIXMAN_a8,
-					 r->width,
-					 r->height,
-					 (uint32_t *) data,
-					 stride);
-	if (unlikely (mask == NULL)) {
-	    status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
-	    goto CLEANUP_CONVERTER;
-	}
-    }
-
-    renderer.base.render_rows = _cairo_image_surface_span;
-    renderer.mask_stride = pixman_image_get_stride (mask);
-    renderer.mask_data = (uint8_t *) pixman_image_get_data (mask);
-    if (dst != NULL)
-	renderer.mask_data -= r->y * renderer.mask_stride + r->x;
-    else
-	renderer.mask_data -= dst_y * renderer.mask_stride + dst_x;
-
-#if USE_BOTOR_SCAN_CONVERTER
-    status = converter.base.generate (&converter.base, &renderer.base);
-#else
-    status = converter->generate (converter, &renderer.base);
-#endif
-    if (unlikely (status))
-	goto CLEANUP_RENDERER;
-
-    if (dst != NULL) {
-	pixman_image_t *src;
-	int src_x, src_y;
-
-	src = _pixman_image_for_pattern (pattern, FALSE, r,
-					 dst_device_transform,
-					 &src_x, &src_y);
-	if (unlikely (src == NULL)) {
-	    status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
-	    goto CLEANUP_RENDERER;
-	}
-
-	pixman_image_composite32 (_pixman_operator (op), src, mask, dst,
-                                  r->x + src_x, r->y + src_y,
-                                  0, 0, /* mask.x, mask.y */
-                                  r->x - dst_x, r->y - dst_y,
-                                  r->width, r->height);
-	pixman_image_unref (src);
-    }
-
- CLEANUP_RENDERER:
-    if (dst != NULL)
-	pixman_image_unref (mask);
- CLEANUP_CONVERTER:
-#if USE_BOTOR_SCAN_CONVERTER
-    converter.base.destroy (&converter.base);
-#else
-    converter->destroy (converter);
-#endif
-    return status;
-}
-
-static cairo_status_t
-_clip_and_composite_polygon (cairo_image_surface_t *dst,
-			     cairo_operator_t op,
-			     const cairo_pattern_t *src,
-			     cairo_polygon_t *polygon,
-			     cairo_fill_rule_t fill_rule,
-			     cairo_antialias_t antialias,
-			     cairo_composite_rectangles_t *extents)
-{
-    cairo_status_t status;
-
-    if (_cairo_polygon_is_empty (polygon)) {
-	cairo_boxes_t boxes;
-
-	if (extents->is_bounded)
-	    return CAIRO_STATUS_SUCCESS;
-
-	status = _cairo_clip_to_boxes (extents->clip, &boxes);
-	if (likely (status == CAIRO_STATUS_SUCCESS)) {
-	    extents->is_bounded = _cairo_operator_bounded_by_either (op);
-	    extents->mask = extents->bounded = extents->unbounded;
-	    status = _clip_and_composite_boxes (dst,
-						CAIRO_OPERATOR_CLEAR,
-						&_cairo_pattern_clear.base,
-						&boxes, extents);
-	    _cairo_boxes_fini (&boxes);
-	}
-
-	return status;
-    }
-
-    _cairo_box_round_to_rectangle (&polygon->extents, &extents->mask);
-    if (! _cairo_rectangle_intersect (&extents->bounded, &extents->mask))
-	return CAIRO_STATUS_SUCCESS;
-
-    if (antialias != CAIRO_ANTIALIAS_NONE) {
-	composite_spans_info_t info;
-
-	info.polygon = polygon;
-	info.fill_rule = fill_rule;
-	info.antialias = antialias;
-
-	status = _clip_and_composite (dst, op, src,
-				      _composite_spans, &info,
-				      extents, need_unbounded_clip (extents));
-    } else {
-	cairo_traps_t traps;
-
-	_cairo_traps_init (&traps);
-
-	/* Fall back to trapezoid fills. */
-	status = _cairo_bentley_ottmann_tessellate_polygon (&traps,
-							    polygon,
-							    fill_rule);
-	if (likely (status == CAIRO_STATUS_SUCCESS)) {
-	    status = _clip_and_composite_trapezoids (dst, op, src,
-						     &traps, antialias,
-						     extents);
-	}
-
-	_cairo_traps_fini (&traps);
-    }
-
-    return status;
+    return _cairo_compositor_mask (surface->compositor,
+				   &surface->base, op, source, mask, clip);
 }
 
 static cairo_int_status_t
@@ -3920,56 +888,10 @@ _cairo_image_surface_stroke (void			*abstract_surface,
 			     const cairo_clip_t		*clip)
 {
     cairo_image_surface_t *surface = abstract_surface;
-    cairo_composite_rectangles_t extents;
-    cairo_rectangle_int_t unbounded;
-    cairo_int_status_t status;
-
-    _cairo_image_surface_get_extents (surface, &unbounded);
-    status = _cairo_composite_rectangles_init_for_stroke (&extents, &unbounded,
-							  op, source,
-							  path, style, ctm,
-							  clip);
-    if (unlikely (status))
-	return status;
-
-    status = CAIRO_INT_STATUS_UNSUPPORTED;
-    if (_cairo_path_fixed_stroke_is_rectilinear (path)) {
-	cairo_boxes_t boxes;
-
-	_cairo_boxes_init_with_clip (&boxes, extents.clip);
-	status = _cairo_path_fixed_stroke_rectilinear_to_boxes (path,
-								style,
-								ctm,
-								antialias,
-								&boxes);
-	if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
-	    status = _clip_and_composite_boxes (surface, op, source,
-						&boxes, &extents);
-	}
-	_cairo_boxes_fini (&boxes);
-    }
-
-    if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
-	cairo_polygon_t polygon;
-
-	_cairo_polygon_init_with_clip (&polygon, extents.clip);
-	status = _cairo_path_fixed_stroke_to_polygon (path,
-						      style,
-						      ctm, ctm_inverse,
-						      tolerance,
-						      &polygon);
-	if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
-	    status = _clip_and_composite_polygon (surface, op, source, &polygon,
-						  CAIRO_FILL_RULE_WINDING,
-						  antialias,
-						  &extents);
-	}
-	_cairo_polygon_fini (&polygon);
-    }
-
-    _cairo_composite_rectangles_fini (&extents);
-
-    return status;
+    return _cairo_compositor_stroke (surface->compositor, &surface->base,
+				     op, source, path,
+				     style, ctm, ctm_inverse,
+				     tolerance, antialias, clip);
 }
 
 static cairo_int_status_t
@@ -3983,291 +905,10 @@ _cairo_image_surface_fill (void				*abstract_surface,
 			   const cairo_clip_t		*clip)
 {
     cairo_image_surface_t *surface = abstract_surface;
-    cairo_composite_rectangles_t extents;
-    cairo_rectangle_int_t unbounded;
-    cairo_status_t status;
-
-    _cairo_image_surface_get_extents (surface, &unbounded);
-    status = _cairo_composite_rectangles_init_for_fill (&extents, &unbounded,
-							op, source, path,
-							clip);
-    if (unlikely (status))
-	return status;
-
-    if (_cairo_path_fixed_fill_is_rectilinear (path)) {
-	cairo_boxes_t boxes;
-
-	_cairo_boxes_init_with_clip (&boxes, extents.clip);
-	status = _cairo_path_fixed_fill_rectilinear_to_boxes (path,
-							      fill_rule,
-							      antialias,
-							      &boxes);
-	if (likely (status == CAIRO_STATUS_SUCCESS)) {
-	    status = _clip_and_composite_boxes (surface, op, source,
-						&boxes, &extents);
-	}
-	_cairo_boxes_fini (&boxes);
-    } else {
-	cairo_polygon_t polygon;
-
-	assert (! _cairo_path_fixed_fill_is_empty (path));
-
-	_cairo_polygon_init_with_clip (&polygon, extents.clip);
-	status = _cairo_path_fixed_fill_to_polygon (path, tolerance, &polygon);
-	if (likely (status == CAIRO_STATUS_SUCCESS)) {
-	    status = _clip_and_composite_polygon (surface, op, source, &polygon,
-						  fill_rule, antialias,
-						  &extents);
-	}
-	_cairo_polygon_fini (&polygon);
-    }
-
-    _cairo_composite_rectangles_fini (&extents);
-
-    return status;
-}
-
-typedef struct {
-    cairo_scaled_font_t *font;
-    cairo_glyph_t *glyphs;
-    int num_glyphs;
-} composite_glyphs_info_t;
-
-static cairo_status_t
-_composite_glyphs_via_mask (void			*closure,
-			    pixman_image_t		*dst,
-			    pixman_format_code_t	 dst_format,
-			    cairo_operator_t		 op,
-			    const cairo_pattern_t	*pattern,
-			    int				 dst_x,
-			    int				 dst_y,
-			    cairo_matrix_t		*dst_device_transform,
-			    const cairo_composite_rectangles_t	*extents)
-{
-    composite_glyphs_info_t *info = closure;
-    cairo_scaled_font_t *font = info->font;
-    cairo_glyph_t *glyphs = info->glyphs;
-    int num_glyphs = info->num_glyphs;
-    pixman_image_t *mask = NULL;
-    pixman_image_t *src;
-    pixman_image_t *white;
-    pixman_format_code_t mask_format = 0; /* silence gcc */
-    cairo_status_t status = CAIRO_STATUS_SUCCESS; /* silence gcc */
-    int src_x, src_y;
-    int i;
-
-    src = _pixman_image_for_pattern (pattern, FALSE, &extents->bounded,
-				     dst_device_transform,
-				     &src_x, &src_y);
-    if (unlikely (src == NULL))
-	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
-    white = _pixman_white_image ();
-    if (unlikely (white == NULL)) {
-	pixman_image_unref (src);
-	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-    }
-
-    _cairo_scaled_font_freeze_cache (font);
-
-    for (i = 0; i < num_glyphs; i++) {
-	int x, y;
-	cairo_image_surface_t *glyph_surface;
-	cairo_scaled_glyph_t *scaled_glyph;
-
-	status = _cairo_scaled_glyph_lookup (font, glyphs[i].index,
-					     CAIRO_SCALED_GLYPH_INFO_SURFACE,
-					     &scaled_glyph);
-
-	if (unlikely (status))
-	    goto CLEANUP;
-
-	glyph_surface = scaled_glyph->surface;
-
-	if (glyph_surface->width == 0 || glyph_surface->height == 0)
-	    continue;
-
-	/* To start, create the mask using the format from the first
-	 * glyph. Later we'll deal with different formats. */
-	if (mask == NULL) {
-	    mask_format = glyph_surface->pixman_format;
-	    mask = pixman_image_create_bits (mask_format,
-					     extents->bounded.width,
-					     extents->bounded.height,
-					     NULL, 0);
-	    if (unlikely (mask == NULL)) {
-		status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
-		goto CLEANUP;
-	    }
-
-	    if (PIXMAN_FORMAT_RGB (mask_format))
-		pixman_image_set_component_alpha (mask, TRUE);
-	}
-
-	/* If we have glyphs of different formats, we "upgrade" the mask
-	 * to the wider of the formats. */
-	if (glyph_surface->pixman_format != mask_format &&
-	    PIXMAN_FORMAT_BPP (mask_format) <
-	    PIXMAN_FORMAT_BPP (glyph_surface->pixman_format))
-	{
-	    pixman_image_t *new_mask;
-
-	    mask_format = glyph_surface->pixman_format;
-	    new_mask = pixman_image_create_bits (mask_format,
-						 extents->bounded.width,
-						 extents->bounded.height,
-						 NULL, 0);
-	    if (unlikely (new_mask == NULL)) {
-		status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
-		goto CLEANUP;
-	    }
-
-	    pixman_image_composite32 (PIXMAN_OP_SRC,
-                                      white, mask, new_mask,
-                                      0, 0, 0, 0, 0, 0,
-                                      extents->bounded.width,
-				      extents->bounded.height);
-
-	    pixman_image_unref (mask);
-	    mask = new_mask;
-	    if (PIXMAN_FORMAT_RGB (mask_format))
-		pixman_image_set_component_alpha (mask, TRUE);
-	}
-
-	/* round glyph locations to the nearest pixel */
-	/* XXX: FRAGILE: We're ignoring device_transform scaling here. A bug? */
-	x = _cairo_lround (glyphs[i].x -
-			   glyph_surface->base.device_transform.x0);
-	y = _cairo_lround (glyphs[i].y -
-			   glyph_surface->base.device_transform.y0);
-	if (glyph_surface->pixman_format == mask_format) {
-	    pixman_image_composite32 (PIXMAN_OP_ADD,
-                                      glyph_surface->pixman_image, NULL, mask,
-                                      0, 0, 0, 0,
-                                      x - extents->bounded.x, y - extents->bounded.y,
-                                      glyph_surface->width,
-                                      glyph_surface->height);
-	} else {
-	    pixman_image_composite32 (PIXMAN_OP_ADD,
-                                      white, glyph_surface->pixman_image, mask,
-                                      0, 0, 0, 0,
-                                      x - extents->bounded.x, y - extents->bounded.y,
-                                      glyph_surface->width,
-                                      glyph_surface->height);
-	}
-    }
-
-    pixman_image_composite32 (_pixman_operator (op),
-                              src, mask, dst,
-                              extents->bounded.x + src_x, extents->bounded.y + src_y,
-                              0, 0,
-                              extents->bounded.x - dst_x, extents->bounded.y - dst_y,
-                              extents->bounded.width,     extents->bounded.height);
-
-CLEANUP:
-    _cairo_scaled_font_thaw_cache (font);
-    if (mask != NULL)
-	pixman_image_unref (mask);
-    pixman_image_unref (src);
-    pixman_image_unref (white);
-
-    return status;
-}
-
-static cairo_status_t
-_composite_glyphs (void				*closure,
-		   pixman_image_t		*dst,
-		   pixman_format_code_t		 dst_format,
-		   cairo_operator_t		 op,
-		   const cairo_pattern_t	*pattern,
-		   int				 dst_x,
-		   int				 dst_y,
-		   cairo_matrix_t		*dst_device_transform,
-		   const cairo_composite_rectangles_t	*extents)
-{
-    composite_glyphs_info_t *info = closure;
-    cairo_scaled_glyph_t *glyph_cache[64];
-    pixman_op_t pixman_op = _pixman_operator (op);
-    pixman_image_t *src = NULL;
-    int src_x = 0, src_y = 0;
-    cairo_status_t status;
-    int i;
-
-    if (pattern != NULL) {
-	src = _pixman_image_for_pattern (pattern, FALSE, &extents->bounded,
-					 dst_device_transform,
-					 &src_x, &src_y);
-	src_x -= dst_x;
-	src_y -= dst_y;
-    } else {
-	src = _pixman_white_image ();
-    }
-    if (unlikely (src == NULL))
-	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
-    memset (glyph_cache, 0, sizeof (glyph_cache));
-    status = CAIRO_STATUS_SUCCESS;
-
-    _cairo_scaled_font_freeze_cache (info->font);
-    for (i = 0; i < info->num_glyphs; i++) {
-	int x, y;
-	cairo_image_surface_t *glyph_surface;
-	cairo_scaled_glyph_t *scaled_glyph;
-	unsigned long glyph_index = info->glyphs[i].index;
-	int cache_index = glyph_index % ARRAY_LENGTH (glyph_cache);
-
-	scaled_glyph = glyph_cache[cache_index];
-	if (scaled_glyph == NULL ||
-	    _cairo_scaled_glyph_index (scaled_glyph) != glyph_index)
-	{
-	    status = _cairo_scaled_glyph_lookup (info->font, glyph_index,
-						 CAIRO_SCALED_GLYPH_INFO_SURFACE,
-						 &scaled_glyph);
-
-	    if (unlikely (status))
-		break;
-
-	    glyph_cache[cache_index] = scaled_glyph;
-	}
-
-	glyph_surface = scaled_glyph->surface;
-	if (glyph_surface->width && glyph_surface->height) {
-	    int x1, y1, x2, y2;
-
-	    /* round glyph locations to the nearest pixel */
-	    /* XXX: FRAGILE: We're ignoring device_transform scaling here. A bug? */
-	    x = _cairo_lround (info->glyphs[i].x -
-			       glyph_surface->base.device_transform.x0);
-	    y = _cairo_lround (info->glyphs[i].y -
-			       glyph_surface->base.device_transform.y0);
-
-	    x1 = x;
-	    if (x1 < extents->bounded.x)
-		x1 = extents->bounded.x;
-	    x2 = x + glyph_surface->width;
-	    if (x2 > extents->bounded.x + extents->bounded.width)
-		x2 = extents->bounded.x + extents->bounded.width;
-
-	    y1 = y;
-	    if (y1 < extents->bounded.y)
-		y1 = extents->bounded.y;
-	    y2 = y + glyph_surface->height;
-	    if (y2 > extents->bounded.y + extents->bounded.height)
-		y2 = extents->bounded.y + extents->bounded.height;
-
-	    pixman_image_composite32 (pixman_op,
-                                      src, glyph_surface->pixman_image, dst,
-                                      x1 + src_x,  y1 + src_y,
-                                      x1 - x, y1 - y,
-                                      x1 - dst_x, y1 - dst_y,
-                                      x2 - x1, y2 - y1);
-	}
-    }
-    _cairo_scaled_font_thaw_cache (info->font);
-
-    pixman_image_unref (src);
-
-    return status;
+    return _cairo_compositor_fill (surface->compositor, &surface->base,
+				   op, source, path,
+				   fill_rule, tolerance, antialias,
+				   clip);
 }
 
 static cairo_int_status_t
@@ -4277,49 +918,13 @@ _cairo_image_surface_glyphs (void			*abstract_surface,
 			     cairo_glyph_t		*glyphs,
 			     int			 num_glyphs,
 			     cairo_scaled_font_t	*scaled_font,
-			     const cairo_clip_t		*clip,
-			     int *num_remaining)
+			     const cairo_clip_t		*clip)
 {
     cairo_image_surface_t *surface = abstract_surface;
-    cairo_composite_rectangles_t extents;
-    cairo_rectangle_int_t unbounded;
-    composite_glyphs_info_t glyph_info;
-    cairo_status_t status;
-    cairo_bool_t overlap;
-    unsigned int flags;
-
-    _cairo_image_surface_get_extents (surface, &unbounded);
-    status = _cairo_composite_rectangles_init_for_glyphs (&extents, &unbounded,
-							  op, source,
-							  scaled_font,
-							  glyphs, num_glyphs,
-							  clip,
-							  &overlap);
-    if (unlikely (status))
-	return status;
-
-    glyph_info.font = scaled_font;
-    glyph_info.glyphs = glyphs;
-    glyph_info.num_glyphs = num_glyphs;
-
-    flags = 0;
-    if (extents.mask.width > extents.unbounded.width ||
-	extents.mask.height > extents.unbounded.height)
-    {
-	flags |= FORCE_CLIP_REGION;
-    }
-    status = _clip_and_composite (surface, op, source,
-				  overlap || extents.is_bounded == 0 ?
-				  _composite_glyphs_via_mask :
-				  _composite_glyphs,
-				  &glyph_info,
-				  &extents,
-				  need_bounded_clip (&extents) | flags);
-
-    _cairo_composite_rectangles_fini (&extents);
-
-    *num_remaining = 0;
-    return status;
+    return _cairo_compositor_glyphs (surface->compositor, &surface->base,
+				     op, source,
+				     glyphs, num_glyphs, scaled_font,
+				     clip);
 }
 
 void
@@ -4332,494 +937,6 @@ _cairo_image_surface_get_font_options (void                  *abstract_surface,
     _cairo_font_options_set_round_glyph_positions (options, CAIRO_ROUND_GLYPH_POS_ON);
 }
 
-/* legacy interface kept for compatibility until surface-fallback is removed */
-static cairo_status_t
-_cairo_image_surface_acquire_dest_image (void                    *abstract_surface,
-					 cairo_rectangle_int_t   *interest_rect,
-					 cairo_image_surface_t  **image_out,
-					 cairo_rectangle_int_t   *image_rect_out,
-					 void                   **image_extra)
-{
-    cairo_image_surface_t *surface = abstract_surface;
-
-    image_rect_out->x = 0;
-    image_rect_out->y = 0;
-    image_rect_out->width = surface->width;
-    image_rect_out->height = surface->height;
-
-    *image_out = surface;
-    *image_extra = NULL;
-
-    return CAIRO_STATUS_SUCCESS;
-}
-
-static void
-_cairo_image_surface_release_dest_image (void                    *abstract_surface,
-                                        cairo_rectangle_int_t   *interest_rect,
-                                        cairo_image_surface_t   *image,
-                                        cairo_rectangle_int_t   *image_rect,
-                                        void                    *image_extra)
-{
-}
-
-static cairo_status_t
-_cairo_image_surface_clone_similar (void               *abstract_surface,
-				    cairo_surface_t     *src,
-				    int                  src_x,
-				    int                  src_y,
-				    int                  width,
-				    int                  height,
-				    int                 *clone_offset_x,
-				    int                 *clone_offset_y,
-				    cairo_surface_t    **clone_out)
-{
-    cairo_image_surface_t *surface = abstract_surface;
-
-    if (src->backend == surface->base.backend) {
-	*clone_offset_x = *clone_offset_y = 0;
-	*clone_out = cairo_surface_reference (src);
-
-	return CAIRO_STATUS_SUCCESS;
-    }
-
-    return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-static cairo_int_status_t
-_cairo_image_surface_composite (cairo_operator_t	 op,
-				const cairo_pattern_t	*src_pattern,
-				const cairo_pattern_t	*mask_pattern,
-				void			*abstract_dst,
-				int			 src_x,
-				int			 src_y,
-				int			 mask_x,
-				int			 mask_y,
-				int			 dst_x,
-				int			 dst_y,
-				unsigned int		 width,
-				unsigned int		 height,
-				cairo_region_t		*clip_region)
-{
-    cairo_image_surface_t *dst = abstract_dst;
-    cairo_composite_rectangles_t extents;
-    pixman_image_t *src;
-    int src_offset_x, src_offset_y;
-    cairo_status_t status;
-
-    if (clip_region != NULL) {
-	status = _cairo_image_surface_set_clip_region (dst, clip_region);
-	if (unlikely (status))
-	    return status;
-    }
-
-    extents.source.x = src_x;
-    extents.source.y = src_y;
-    extents.source.width  = width;
-    extents.source.height = height;
-
-    extents.mask.x = mask_x;
-    extents.mask.y = mask_y;
-    extents.mask.width  = width;
-    extents.mask.height = height;
-
-    extents.bounded.x = dst_x;
-    extents.bounded.y = dst_y;
-    extents.bounded.width  = width;
-    extents.bounded.height = height;
-
-    extents.unbounded.x = 0;
-    extents.unbounded.y = 0;
-    extents.unbounded.width  = dst->width;
-    extents.unbounded.height = dst->height;
-
-    if (clip_region != NULL) {
-	cairo_rectangle_int_t rect;
-
-	cairo_region_get_extents (clip_region, &rect);
-	if (! _cairo_rectangle_intersect (&extents.unbounded, &rect))
-	    return CAIRO_STATUS_SUCCESS;
-    }
-
-    extents.is_bounded = _cairo_operator_bounded_by_either (op);
-
-    src = _pixman_image_for_pattern (src_pattern, FALSE, &extents.source,
-				     &dst->base.device_transform,
-				     &src_offset_x, &src_offset_y);
-    if (unlikely (src == NULL))
-	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
-    status = CAIRO_STATUS_SUCCESS;
-    if (mask_pattern != NULL) {
-	pixman_image_t *mask;
-	int mask_offset_x, mask_offset_y;
-
-	mask = _pixman_image_for_pattern (mask_pattern, TRUE, &extents.mask,
-					  &dst->base.device_transform,
-					  &mask_offset_x, &mask_offset_y);
-	if (unlikely (mask == NULL)) {
-	    pixman_image_unref (src);
-	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-	}
-
-	pixman_image_composite32 (_pixman_operator (op),
-                                  src, mask, dst->pixman_image,
-                                  src_x + src_offset_x,
-                                  src_y + src_offset_y,
-                                  mask_x + mask_offset_x,
-                                  mask_y + mask_offset_y,
-				  dst_x, dst_y, width, height);
-
-	pixman_image_unref (mask);
-    } else {
-	pixman_image_composite32 (_pixman_operator (op),
-                                  src, NULL, dst->pixman_image,
-                                  src_x + src_offset_x,
-                                  src_y + src_offset_y,
-                                  0, 0,
-                                  dst_x, dst_y, width, height);
-    }
-
-    pixman_image_unref (src);
-
-    if (! extents.is_bounded)
-	status = _cairo_image_surface_fixup_unbounded (dst, &extents, NULL);
-
-    if (clip_region != NULL)
-	_cairo_image_surface_unset_clip_region (dst);
-
-    return status;
-}
-
-static cairo_int_status_t
-_cairo_image_surface_fill_rectangles (void		      *abstract_surface,
-				      cairo_operator_t	       op,
-				      const cairo_color_t     *color,
-				      cairo_rectangle_int_t   *rects,
-				      int		       num_rects)
-{
-    cairo_image_surface_t *surface = abstract_surface;
-
-    pixman_color_t pixman_color;
-    pixman_box32_t stack_boxes[CAIRO_STACK_ARRAY_LENGTH (pixman_box32_t)];
-    pixman_box32_t *pixman_boxes = stack_boxes;
-    int i;
-
-    cairo_int_status_t status;
-
-    if (CAIRO_INJECT_FAULT ())
-	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
-    pixman_color.red   = color->red_short;
-    pixman_color.green = color->green_short;
-    pixman_color.blue  = color->blue_short;
-    pixman_color.alpha = color->alpha_short;
-
-    if (num_rects > ARRAY_LENGTH (stack_boxes)) {
-	pixman_boxes = _cairo_malloc_ab (num_rects, sizeof (pixman_box32_t));
-	if (unlikely (pixman_boxes == NULL))
-	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-    }
-
-    for (i = 0; i < num_rects; i++) {
-	pixman_boxes[i].x1 = rects[i].x;
-	pixman_boxes[i].y1 = rects[i].y;
-	pixman_boxes[i].x2 = rects[i].x + rects[i].width;
-	pixman_boxes[i].y2 = rects[i].y + rects[i].height;
-    }
-
-    status = CAIRO_STATUS_SUCCESS;
-    if (! pixman_image_fill_boxes (_pixman_operator (op),
-                                   surface->pixman_image,
-                                   &pixman_color,
-                                   num_rects,
-                                   pixman_boxes))
-    {
-	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
-    }
-
-    if (pixman_boxes != stack_boxes)
-	free (pixman_boxes);
-
-    return status;
-}
-
-static cairo_int_status_t
-_cairo_image_surface_composite_trapezoids (cairo_operator_t	op,
-					   const cairo_pattern_t *pattern,
-					   void			*abstract_dst,
-					   cairo_antialias_t	antialias,
-					   int			src_x,
-					   int			src_y,
-					   int			dst_x,
-					   int			dst_y,
-					   unsigned int		width,
-					   unsigned int		height,
-					   cairo_trapezoid_t	*traps,
-					   int			num_traps,
-					   cairo_region_t	*clip_region)
-{
-    cairo_image_surface_t	*dst = abstract_dst;
-    cairo_composite_rectangles_t extents;
-    cairo_pattern_union_t        source_pattern;
-    composite_traps_info_t	 info;
-    cairo_status_t		 status;
-
-    if (height == 0 || width == 0)
-	return CAIRO_STATUS_SUCCESS;
-
-    if (CAIRO_INJECT_FAULT ())
-	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
-    extents.source.x = src_x;
-    extents.source.y = src_y;
-    extents.source.width  = width;
-    extents.source.height = height;
-
-    extents.mask.x = dst_x;
-    extents.mask.y = dst_y;
-    extents.mask.width  = width;
-    extents.mask.height = height;
-
-    extents.bounded.x = dst_x;
-    extents.bounded.y = dst_y;
-    extents.bounded.width  = width;
-    extents.bounded.height = height;
-
-    extents.unbounded.x = 0;
-    extents.unbounded.y = 0;
-    extents.unbounded.width  = dst->width;
-    extents.unbounded.height = dst->height;
-
-    if (clip_region != NULL) {
-	cairo_rectangle_int_t rect;
-
-	cairo_region_get_extents (clip_region, &rect);
-	if (! _cairo_rectangle_intersect (&extents.unbounded, &rect))
-	    return CAIRO_STATUS_SUCCESS;
-    }
-
-    extents.is_bounded = _cairo_operator_bounded_by_either (op);
-
-    if (clip_region != NULL) {
-	status = _cairo_image_surface_set_clip_region (dst, clip_region);
-	if (unlikely (status))
-	    return status;
-    }
-
-    _cairo_pattern_init_static_copy (&source_pattern.base, pattern);
-    cairo_matrix_translate (&source_pattern.base.matrix,
-                            src_x - extents.bounded.x,
-                            src_y - extents.bounded.y);
-
-    info.traps = traps;
-    info.num_traps = num_traps;
-    info.antialias = antialias;
-    status = _composite_traps (&info,
-			       dst->pixman_image,
-			       dst->pixman_format,
-			       op,
-			       &source_pattern.base,
-			       0, 0,
-			       &dst->base.device_transform,
-			       &extents);
-
-    if (status == CAIRO_STATUS_SUCCESS && ! extents.is_bounded)
-	status = _cairo_image_surface_fixup_unbounded (dst, &extents, NULL);
-
-    if (clip_region != NULL)
-	_cairo_image_surface_unset_clip_region (dst);
-
-    return status;
-}
-
-typedef struct _legacy_image_surface_span_renderer {
-    cairo_span_renderer_t base;
-
-    cairo_operator_t op;
-    const cairo_pattern_t *pattern;
-    cairo_antialias_t antialias;
-    cairo_region_t *clip_region;
-
-    pixman_image_t *mask;
-    uint8_t *mask_data;
-    uint32_t mask_stride;
-
-    cairo_image_surface_t *dst;
-    cairo_composite_rectangles_t composite_rectangles;
-} legacy_image_surface_span_renderer_t;
-
-void
-_cairo_image_surface_span_render_row (
-    int                                  y,
-    const cairo_half_open_span_t        *spans,
-    unsigned                             num_spans,
-    uint8_t				*data,
-    uint32_t				 stride)
-{
-    uint8_t *row;
-    unsigned i;
-
-    if (num_spans == 0)
-	return;
-
-    row = data + y * stride;
-    for (i = 0; i < num_spans - 1; i++) {
-	if (! spans[i].coverage)
-	    continue;
-
-	/* We implement setting the most common single pixel wide
-	 * span case to avoid the overhead of a memset call.
-	 * Open coding setting longer spans didn't show a
-	 * noticeable improvement over memset.
-	 */
-	if (spans[i+1].x == spans[i].x + 1) {
-	    row[spans[i].x] = spans[i].coverage;
-	} else {
-	    memset (row + spans[i].x,
-		    spans[i].coverage,
-		    spans[i+1].x - spans[i].x);
-	}
-    }
-}
-
-static cairo_status_t
-_cairo_image_surface_span_renderer_render_rows (
-    void				*abstract_renderer,
-    int					 y,
-    int					 height,
-    const cairo_half_open_span_t	*spans,
-    unsigned				 num_spans)
-{
-    legacy_image_surface_span_renderer_t *renderer = abstract_renderer;
-    while (height--)
-	_cairo_image_surface_span_render_row (y++, spans, num_spans, renderer->mask_data, renderer->mask_stride);
-    return CAIRO_STATUS_SUCCESS;
-}
-
-static void
-_cairo_image_surface_span_renderer_destroy (void *abstract_renderer)
-{
-    legacy_image_surface_span_renderer_t *renderer = abstract_renderer;
-    if (renderer == NULL)
-	return;
-
-    pixman_image_unref (renderer->mask);
-
-    free (renderer);
-}
-
-static cairo_status_t
-_cairo_image_surface_span_renderer_finish (void *abstract_renderer)
-{
-    legacy_image_surface_span_renderer_t *renderer = abstract_renderer;
-    cairo_composite_rectangles_t *rects = &renderer->composite_rectangles;
-    cairo_image_surface_t *dst = renderer->dst;
-    pixman_image_t *src;
-    int src_x, src_y;
-    cairo_status_t status;
-
-    if (renderer->clip_region != NULL) {
-	status = _cairo_image_surface_set_clip_region (dst, renderer->clip_region);
-	if (unlikely (status))
-	    return status;
-    }
-
-    src = _pixman_image_for_pattern (renderer->pattern, FALSE, &rects->bounded,
-				     &renderer->dst->base.device_transform,
-				     &src_x, &src_y);
-    if (src == NULL)
-	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
-    status = CAIRO_STATUS_SUCCESS;
-    pixman_image_composite32 (_pixman_operator (renderer->op),
-                              src,
-                              renderer->mask,
-                              dst->pixman_image,
-                              rects->bounded.x + src_x,
-                              rects->bounded.y + src_y,
-                              0, 0,
-                              rects->bounded.x, rects->bounded.y,
-                              rects->bounded.width, rects->bounded.height);
-
-    if (! rects->is_bounded)
-	status = _cairo_image_surface_fixup_unbounded (dst, rects, NULL);
-
-    if (renderer->clip_region != NULL)
-	 _cairo_image_surface_unset_clip_region (dst);
-
-    return status;
-}
-
-static cairo_bool_t
-_cairo_image_surface_check_span_renderer (cairo_operator_t	  op,
-					  const cairo_pattern_t  *pattern,
-					  void			 *abstract_dst,
-					  cairo_antialias_t	  antialias)
-{
-    return TRUE;
-    (void) op;
-    (void) pattern;
-    (void) abstract_dst;
-    (void) antialias;
-}
-
-static cairo_span_renderer_t *
-_cairo_image_surface_create_span_renderer (cairo_operator_t	 op,
-					   const cairo_pattern_t  *pattern,
-					   void			*abstract_dst,
-					   cairo_antialias_t	 antialias,
-					   const cairo_composite_rectangles_t *rects,
-					   cairo_region_t *clip_region)
-{
-    cairo_image_surface_t *dst = abstract_dst;
-    legacy_image_surface_span_renderer_t *renderer;
-
-    renderer = calloc(1, sizeof(*renderer));
-    if (unlikely (renderer == NULL))
-	return _cairo_span_renderer_create_in_error (CAIRO_STATUS_NO_MEMORY);
-
-    renderer->base.destroy = _cairo_image_surface_span_renderer_destroy;
-    renderer->base.finish = _cairo_image_surface_span_renderer_finish;
-    renderer->base.render_rows = _cairo_image_surface_span_renderer_render_rows;
-    renderer->op = op;
-    renderer->pattern = pattern;
-    renderer->antialias = antialias;
-    renderer->dst = dst;
-    renderer->clip_region = clip_region;
-
-    renderer->composite_rectangles = *rects;
-
-    /* TODO: support rendering to A1 surfaces (or: go add span
-     * compositing to pixman.) */
-    renderer->mask = pixman_image_create_bits (PIXMAN_a8,
-					       rects->bounded.width,
-					       rects->bounded.height,
-					       NULL, 0);
-    if (renderer->mask == NULL) {
-	free (renderer);
-	return _cairo_span_renderer_create_in_error (CAIRO_STATUS_NO_MEMORY);
-    }
-
-    renderer->mask_stride = pixman_image_get_stride (renderer->mask);
-    renderer->mask_data = (uint8_t *) pixman_image_get_data (renderer->mask) - rects->bounded.x - rects->bounded.y * renderer->mask_stride;
-
-    return &renderer->base;
-}
-
-/**
- * _cairo_surface_is_image:
- * @surface: a #cairo_surface_t
- *
- * Checks if a surface is an #cairo_image_surface_t
- *
- * Return value: %TRUE if the surface is an image surface
- **/
-cairo_bool_t
-_cairo_surface_is_image (const cairo_surface_t *surface)
-{
-    return surface->backend == &_cairo_image_surface_backend;
-}
-
 const cairo_surface_backend_t _cairo_image_surface_backend = {
     CAIRO_SURFACE_TYPE_IMAGE,
     _cairo_image_surface_finish,
@@ -4833,32 +950,23 @@ const cairo_surface_backend_t _cairo_image_surface_backend = {
 
     _cairo_image_surface_acquire_source_image,
     _cairo_image_surface_release_source_image,
-    _cairo_image_surface_acquire_dest_image,
-    _cairo_image_surface_release_dest_image,
-    _cairo_image_surface_clone_similar,
-    _cairo_image_surface_composite,
-    _cairo_image_surface_fill_rectangles,
-    _cairo_image_surface_composite_trapezoids,
-    _cairo_image_surface_create_span_renderer,
-    _cairo_image_surface_check_span_renderer,
+    _cairo_image_surface_snapshot,
 
     NULL, /* copy_page */
     NULL, /* show_page */
+
     _cairo_image_surface_get_extents,
-    NULL, /* old_show_glyphs */
     _cairo_image_surface_get_font_options,
+
     NULL, /* flush */
     NULL, /* mark dirty */
-    NULL, /* font_fini */
-    NULL, /* glyph_fini */
 
     _cairo_image_surface_paint,
     _cairo_image_surface_mask,
     _cairo_image_surface_stroke,
     _cairo_image_surface_fill,
+    NULL, /* fill-stroke */
     _cairo_image_surface_glyphs,
-    _cairo_image_surface_snapshot,
-    NULL, /* is_similar */
 };
 
 /* A convenience function for when one needs to coerce an image
@@ -4908,7 +1016,7 @@ _cairo_image_surface_coerce_to_format (cairo_image_surface_t *surface,
 }
 
 cairo_image_transparency_t
-_cairo_image_analyze_transparency (cairo_image_surface_t      *image)
+_cairo_image_analyze_transparency (cairo_image_surface_t *image)
 {
     int x, y;
 
@@ -4918,6 +1026,9 @@ _cairo_image_analyze_transparency (cairo_image_surface_t      *image)
     if ((image->base.content & CAIRO_CONTENT_ALPHA) == 0)
 	return image->transparency = CAIRO_IMAGE_IS_OPAQUE;
 
+    if (image->base.is_clear)
+	return image->transparency = CAIRO_IMAGE_HAS_BILEVEL_ALPHA;
+
     if ((image->base.content & CAIRO_CONTENT_COLOR) == 0) {
 	if (image->format == CAIRO_FORMAT_A1) {
 	    return image->transparency = CAIRO_IMAGE_HAS_BILEVEL_ALPHA;
diff --git a/src/cairo-mask-compositor.c b/src/cairo-mask-compositor.c
new file mode 100644
index 0000000..b34ffa2
--- /dev/null
+++ b/src/cairo-mask-compositor.c
@@ -0,0 +1,1412 @@
+/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
+/* 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>
+ *      Joonas Pihlaja <jpihlaja at cc.helsinki.fi>
+ *	Chris Wilson <chris at chris-wilson.co.uk>
+ */
+
+/* This compositor renders the shape to a mask using an image surface
+ * then calls composite.
+ */
+
+#include "cairoint.h"
+
+#include "cairo-compositor-private.h"
+#include "cairo-image-surface-private.h"
+#include "cairo-pattern-private.h"
+#include "cairo-region-private.h"
+#include "cairo-surface-observer-private.h"
+#include "cairo-surface-offset-private.h"
+#include "cairo-surface-snapshot-private.h"
+#include "cairo-surface-subsurface-private.h"
+
+typedef cairo_int_status_t
+(*draw_func_t) (const cairo_mask_compositor_t *compositor,
+		cairo_surface_t			*dst,
+		void				*closure,
+		cairo_operator_t		 op,
+		const cairo_pattern_t		*src,
+		const cairo_rectangle_int_t	*src_sample,
+		int				 dst_x,
+		int				 dst_y,
+		const cairo_rectangle_int_t	*extents,
+		cairo_clip_t			*clip);
+
+static void do_unaligned_row(void (*blt)(void *closure,
+					 int16_t x, int16_t y,
+					 int16_t w, int16_t h,
+					 uint16_t coverage),
+			     void *closure,
+			     const cairo_box_t *b,
+			     int tx, int y, int h,
+			     uint16_t coverage)
+{
+    int x1 = _cairo_fixed_integer_part (b->p1.x) - tx;
+    int x2 = _cairo_fixed_integer_part (b->p2.x) - tx;
+    if (x2 > x1) {
+	if (! _cairo_fixed_is_integer (b->p1.x)) {
+	    blt(closure, x1, y, 1, h,
+		coverage * (256 - _cairo_fixed_fractional_part (b->p1.x)));
+	    x1++;
+	}
+
+	if (x2 > x1)
+	    blt(closure, x1, y, x2-x1, h, (coverage << 8) - (coverage >> 8));
+
+	if (! _cairo_fixed_is_integer (b->p2.x))
+	    blt(closure, x2, y, 1, h,
+		coverage * _cairo_fixed_fractional_part (b->p2.x));
+    } else
+	blt(closure, x1, y, 1, h,
+	    coverage * (b->p2.x - b->p1.x));
+}
+
+static void do_unaligned_box(void (*blt)(void *closure,
+					 int16_t x, int16_t y,
+					 int16_t w, int16_t h,
+					 uint16_t coverage),
+			     void *closure,
+			     const cairo_box_t *b, int tx, int ty)
+{
+    int y1 = _cairo_fixed_integer_part (b->p1.y) - ty;
+    int y2 = _cairo_fixed_integer_part (b->p2.y) - ty;
+    if (y2 > y1) {
+	if (! _cairo_fixed_is_integer (b->p1.y)) {
+	    do_unaligned_row(blt, closure, b, tx, y1, 1,
+			     256 - _cairo_fixed_fractional_part (b->p1.y));
+	    y1++;
+	}
+
+	if (y2 > y1)
+	    do_unaligned_row(blt, closure, b, tx, y1, y2-y1, 256);
+
+	if (! _cairo_fixed_is_integer (b->p2.y))
+	    do_unaligned_row(blt, closure, b, tx, y2, 1,
+			     _cairo_fixed_fractional_part (b->p2.y));
+    } else
+	do_unaligned_row(blt, closure, b, tx, y1, 1,
+			 b->p2.y - b->p1.y);
+}
+
+struct blt_in {
+    const cairo_mask_compositor_t *compositor;
+    cairo_surface_t *dst;
+};
+
+static void blt_in(void *closure,
+		   int16_t x, int16_t y,
+		   int16_t w, int16_t h,
+		   uint16_t coverage)
+{
+    struct blt_in *info = closure;
+    cairo_color_t color;
+    cairo_rectangle_int_t rect;
+
+    if (coverage == 0xffff)
+	return;
+
+    rect.x = x;
+    rect.y = y;
+    rect.width  = w;
+    rect.height = h;
+
+    _cairo_color_init_rgba (&color, 0, 0, 0, coverage / (double) 0xffff);
+    info->compositor->fill_rectangles (info->dst, CAIRO_OPERATOR_IN,
+				       &color, &rect, 1);
+}
+
+static cairo_surface_t *
+create_composite_mask (const cairo_mask_compositor_t *compositor,
+		       cairo_surface_t		*dst,
+		       void			*draw_closure,
+		       draw_func_t		 draw_func,
+		       draw_func_t		 mask_func,
+		       const cairo_composite_rectangles_t *extents)
+{
+    cairo_surface_t *surface;
+    cairo_int_status_t status;
+    struct blt_in info;
+    int i;
+
+    surface = _cairo_surface_create_similar_solid (dst,
+						   CAIRO_CONTENT_ALPHA,
+						   extents->bounded.width,
+						   extents->bounded.height,
+						   CAIRO_COLOR_TRANSPARENT);
+    if (unlikely (surface->status))
+	return surface;
+
+    if (mask_func) {
+	status = mask_func (compositor, surface, draw_closure,
+			    CAIRO_OPERATOR_SOURCE, NULL, NULL,
+			    extents->bounded.x, extents->bounded.y,
+			    &extents->bounded, extents->clip);
+	if (likely (status != CAIRO_INT_STATUS_UNSUPPORTED))
+	    return surface;
+    }
+
+    /* Is it worth setting the clip region here? */
+    status = draw_func (compositor, surface, draw_closure,
+			CAIRO_OPERATOR_ADD, NULL, NULL,
+			extents->bounded.x, extents->bounded.y,
+			&extents->bounded, NULL);
+    if (unlikely (status)) {
+	cairo_surface_destroy (surface);
+	return _cairo_surface_create_in_error (status);
+    }
+
+    info.compositor = compositor;
+    info.dst = surface;
+    for (i = 0; i < extents->clip->num_boxes; i++) {
+	cairo_box_t *b = &extents->clip->boxes[i];
+
+	if (! _cairo_fixed_is_integer (b->p1.x) ||
+	    ! _cairo_fixed_is_integer (b->p1.y) ||
+	    ! _cairo_fixed_is_integer (b->p2.x) ||
+	    ! _cairo_fixed_is_integer (b->p2.y))
+	{
+	    do_unaligned_box(blt_in, &info, b,
+			     extents->bounded.x,
+			     extents->bounded.y);
+	}
+    }
+
+    if (extents->clip->path != NULL) {
+	status = _cairo_clip_combine_with_surface (extents->clip, surface,
+						   extents->bounded.x,
+						   extents->bounded.y);
+	if (unlikely (status)) {
+	    cairo_surface_destroy (surface);
+	    return _cairo_surface_create_in_error (status);
+	}
+    }
+
+    return surface;
+}
+
+/* Handles compositing with a clip surface when the operator allows
+ * us to combine the clip with the mask
+ */
+static cairo_status_t
+clip_and_composite_with_mask (const cairo_mask_compositor_t *compositor,
+			      void			*draw_closure,
+			      draw_func_t		 draw_func,
+			      draw_func_t		 mask_func,
+			      cairo_operator_t		 op,
+			      cairo_pattern_t		*pattern,
+			      const cairo_composite_rectangles_t*extents)
+{
+    cairo_surface_t *dst = extents->surface;
+    cairo_surface_t *mask, *src;
+    int src_x, src_y;
+
+    mask = create_composite_mask (compositor, dst, draw_closure,
+				  draw_func, mask_func,
+				  extents);
+    if (unlikely (mask->status))
+	return mask->status;
+
+    if (pattern != NULL || dst->content != CAIRO_CONTENT_ALPHA) {
+	src = compositor->pattern_to_surface (dst,
+					      &extents->source_pattern.base,
+					      FALSE,
+					      &extents->bounded,
+					      &extents->source_sample_area,
+					      &src_x, &src_y);
+	if (unlikely (src->status)) {
+	    cairo_surface_destroy (mask);
+	    return src->status;
+	}
+
+	compositor->composite (dst, op, src, mask,
+			       extents->bounded.x + src_x,
+			       extents->bounded.y + src_y,
+			       0, 0,
+			       extents->bounded.x,      extents->bounded.y,
+			       extents->bounded.width,  extents->bounded.height);
+
+	cairo_surface_destroy (src);
+    } else {
+	compositor->composite (dst, op, mask, NULL,
+			       0, 0,
+			       0, 0,
+			       extents->bounded.x,      extents->bounded.y,
+			       extents->bounded.width,  extents->bounded.height);
+    }
+    cairo_surface_destroy (mask);
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+/* Handles compositing with a clip surface when we have to do the operation
+ * in two pieces and combine them together.
+ */
+static cairo_status_t
+clip_and_composite_combine (const cairo_mask_compositor_t *compositor,
+			    void			*draw_closure,
+			    draw_func_t		 draw_func,
+			    cairo_operator_t		 op,
+			    const cairo_pattern_t	*pattern,
+			    const cairo_composite_rectangles_t*extents)
+{
+    cairo_surface_t *dst = extents->surface;
+    cairo_surface_t *tmp, *clip;
+    cairo_status_t status;
+
+    tmp = _cairo_surface_create_similar_scratch (dst, dst->content,
+						 extents->bounded.width,
+						 extents->bounded.height);
+    if (unlikely (tmp->status))
+	return tmp->status;
+
+    compositor->composite (tmp, CAIRO_OPERATOR_SOURCE, dst, NULL,
+			   extents->bounded.x,      extents->bounded.y,
+			   0, 0,
+			   0, 0,
+			   extents->bounded.width,  extents->bounded.height);
+
+    status = draw_func (compositor, tmp, draw_closure, op,
+			pattern, &extents->source_sample_area,
+			extents->bounded.x, extents->bounded.y,
+			&extents->bounded, NULL);
+    if (unlikely (status))
+	goto cleanup;
+
+    clip = _cairo_clip_get_image (extents->clip, dst, &extents->bounded);
+    if (unlikely ((status = clip->status)))
+	goto cleanup;
+
+    if (dst->is_clear) {
+	compositor->composite (dst, CAIRO_OPERATOR_SOURCE, tmp, clip,
+			       0, 0,
+			       0, 0,
+			       extents->bounded.x,      extents->bounded.y,
+			       extents->bounded.width,  extents->bounded.height);
+    } else {
+	/* Punch the clip out of the destination */
+	compositor->composite (dst, CAIRO_OPERATOR_DEST_OUT, clip, NULL,
+			       0, 0,
+			       0, 0,
+			       extents->bounded.x,     extents->bounded.y,
+			       extents->bounded.width, extents->bounded.height);
+
+	/* Now add the two results together */
+	compositor->composite (dst, CAIRO_OPERATOR_ADD, tmp, clip,
+			       0, 0,
+			       0, 0,
+			       extents->bounded.x,     extents->bounded.y,
+			       extents->bounded.width, extents->bounded.height);
+    }
+    cairo_surface_destroy (clip);
+
+cleanup:
+    cairo_surface_destroy (tmp);
+    return status;
+}
+
+/* Handles compositing for %CAIRO_OPERATOR_SOURCE, which is special; it's
+ * defined as (src IN mask IN clip) ADD (dst OUT (mask IN clip))
+ */
+static cairo_status_t
+clip_and_composite_source (const cairo_mask_compositor_t	*compositor,
+			   void				*draw_closure,
+			   draw_func_t			 draw_func,
+			   draw_func_t			 mask_func,
+			   cairo_pattern_t		*pattern,
+			   const cairo_composite_rectangles_t	*extents)
+{
+    cairo_surface_t *dst = extents->surface;
+    cairo_surface_t *mask, *src;
+    int src_x, src_y;
+
+    /* Create a surface that is mask IN clip */
+    mask = create_composite_mask (compositor, dst, draw_closure,
+				  draw_func, mask_func,
+				  extents);
+    if (unlikely (mask->status))
+	return mask->status;
+
+    src = compositor->pattern_to_surface (dst,
+					  pattern,
+					  FALSE,
+					  &extents->bounded,
+					  &extents->source_sample_area,
+					  &src_x, &src_y);
+    if (unlikely (src->status)) {
+	cairo_surface_destroy (mask);
+	return src->status;
+    }
+
+    if (dst->is_clear) {
+	compositor->composite (dst, CAIRO_OPERATOR_SOURCE, src, mask,
+			       extents->bounded.x + src_x, extents->bounded.y + src_y,
+			       0, 0,
+			       extents->bounded.x,      extents->bounded.y,
+			       extents->bounded.width,  extents->bounded.height);
+    } else {
+	/* Compute dest' = dest OUT (mask IN clip) */
+	compositor->composite (dst, CAIRO_OPERATOR_DEST_OUT, mask, NULL,
+			       0, 0, 0, 0,
+			       extents->bounded.x,     extents->bounded.y,
+			       extents->bounded.width, extents->bounded.height);
+
+	/* Now compute (src IN (mask IN clip)) ADD dest' */
+	compositor->composite (dst, CAIRO_OPERATOR_ADD, src, mask,
+			       extents->bounded.x + src_x, extents->bounded.y + src_y,
+			       0, 0,
+			       extents->bounded.x,     extents->bounded.y,
+			       extents->bounded.width, extents->bounded.height);
+    }
+
+    cairo_surface_destroy (src);
+    cairo_surface_destroy (mask);
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_bool_t
+can_reduce_alpha_op (cairo_operator_t op)
+{
+    int iop = op;
+    switch (iop) {
+    case CAIRO_OPERATOR_OVER:
+    case CAIRO_OPERATOR_SOURCE:
+    case CAIRO_OPERATOR_ADD:
+	return TRUE;
+    default:
+	return FALSE;
+    }
+}
+
+static cairo_bool_t
+reduce_alpha_op (cairo_surface_t *dst,
+		 cairo_operator_t op,
+		 const cairo_pattern_t *pattern)
+{
+    return dst->is_clear &&
+	   dst->content == CAIRO_CONTENT_ALPHA &&
+	   _cairo_pattern_is_opaque_solid (pattern) &&
+	   can_reduce_alpha_op (op);
+}
+
+static cairo_status_t
+fixup_unbounded (const cairo_mask_compositor_t *compositor,
+		 cairo_surface_t *dst,
+		 const cairo_composite_rectangles_t *extents)
+{
+    cairo_rectangle_int_t rects[4];
+    int n;
+
+    if (extents->bounded.width  == extents->unbounded.width &&
+	extents->bounded.height == extents->unbounded.height)
+    {
+	return CAIRO_STATUS_SUCCESS;
+    }
+
+    n = 0;
+    if (extents->bounded.width == 0 || extents->bounded.height == 0) {
+	rects[n].x = extents->unbounded.x;
+	rects[n].width = extents->unbounded.width;
+	rects[n].y = extents->unbounded.y;
+	rects[n].height = extents->unbounded.height;
+	n++;
+    } else {
+	/* top */
+	if (extents->bounded.y != extents->unbounded.y) {
+	    rects[n].x = extents->unbounded.x;
+	    rects[n].width = extents->unbounded.width;
+	    rects[n].y = extents->unbounded.y;
+	    rects[n].height = extents->bounded.y - extents->unbounded.y;
+	    n++;
+	}
+	/* left */
+	if (extents->bounded.x != extents->unbounded.x) {
+	    rects[n].x = extents->unbounded.x;
+	    rects[n].width = extents->bounded.x - extents->unbounded.x;
+	    rects[n].y = extents->bounded.y;
+	    rects[n].height = extents->bounded.height;
+	    n++;
+	}
+	/* right */
+	if (extents->bounded.x + extents->bounded.width != extents->unbounded.x + extents->unbounded.width) {
+	    rects[n].x = extents->bounded.x + extents->bounded.width;
+	    rects[n].width = extents->unbounded.x + extents->unbounded.width - rects[n].x;
+	    rects[n].y = extents->bounded.y;
+	    rects[n].height = extents->bounded.height;
+	    n++;
+	}
+	/* bottom */
+	if (extents->bounded.y + extents->bounded.height != extents->unbounded.y + extents->unbounded.height) {
+	    rects[n].x = extents->unbounded.x;
+	    rects[n].width = extents->unbounded.width;
+	    rects[n].y = extents->bounded.y + extents->bounded.height;
+	    rects[n].height = extents->unbounded.y + extents->unbounded.height - rects[n].y;
+	    n++;
+	}
+    }
+
+    return compositor->fill_rectangles (dst, CAIRO_OPERATOR_CLEAR,
+					CAIRO_COLOR_TRANSPARENT,
+					rects, n);
+}
+
+static cairo_status_t
+fixup_unbounded_with_mask (const cairo_mask_compositor_t *compositor,
+			   cairo_surface_t *dst,
+			   const cairo_composite_rectangles_t *extents)
+{
+    cairo_clip_t *clip = extents->clip;
+    cairo_surface_t *mask;
+    int mask_x, mask_y;
+
+    mask = _cairo_clip_get_image (clip, dst, &extents->unbounded);
+    if (unlikely (mask->status))
+	return mask->status;
+
+    mask_x = -extents->unbounded.x;
+    mask_y = -extents->unbounded.y;
+
+    /* top */
+    if (extents->bounded.y != extents->unbounded.y) {
+	int x = extents->unbounded.x;
+	int y = extents->unbounded.y;
+	int width = extents->unbounded.width;
+	int height = extents->bounded.y - y;
+
+	compositor->composite (dst, CAIRO_OPERATOR_DEST_OUT, mask, NULL,
+			       x + mask_x, y + mask_y,
+			       0, 0,
+			       x, y,
+			       width, height);
+    }
+
+    /* left */
+    if (extents->bounded.x != extents->unbounded.x) {
+	int x = extents->unbounded.x;
+	int y = extents->bounded.y;
+	int width = extents->bounded.x - x;
+	int height = extents->bounded.height;
+
+	compositor->composite (dst, CAIRO_OPERATOR_DEST_OUT, mask, NULL,
+			       x + mask_x, y + mask_y,
+			       0, 0,
+			       x, y,
+			       width, height);
+    }
+
+    /* right */
+    if (extents->bounded.x + extents->bounded.width != extents->unbounded.x + extents->unbounded.width) {
+	int x = extents->bounded.x + extents->bounded.width;
+	int y = extents->bounded.y;
+	int width = extents->unbounded.x + extents->unbounded.width - x;
+	int height = extents->bounded.height;
+
+	compositor->composite (dst, CAIRO_OPERATOR_DEST_OUT, mask, NULL,
+			       x + mask_x, y + mask_y,
+			       0, 0,
+			       x, y,
+			       width, height);
+    }
+
+    /* bottom */
+    if (extents->bounded.y + extents->bounded.height != extents->unbounded.y + extents->unbounded.height) {
+	int x = extents->unbounded.x;
+	int y = extents->bounded.y + extents->bounded.height;
+	int width = extents->unbounded.width;
+	int height = extents->unbounded.y + extents->unbounded.height - y;
+
+	compositor->composite (dst, CAIRO_OPERATOR_DEST_OUT, mask, NULL,
+			       x + mask_x, y + mask_y,
+			       0, 0,
+			       x, y,
+			       width, height);
+    }
+
+    cairo_surface_destroy (mask);
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+fixup_unbounded_boxes (const cairo_mask_compositor_t *compositor,
+		       const cairo_composite_rectangles_t *extents,
+		       cairo_boxes_t *boxes)
+{
+    cairo_surface_t *dst = extents->surface;
+    cairo_boxes_t clear;
+    cairo_region_t *clip_region;
+    cairo_box_t box;
+    cairo_status_t status;
+    struct _cairo_boxes_chunk *chunk;
+    int i;
+
+    assert (boxes->is_pixel_aligned);
+
+    clip_region = NULL;
+    if (_cairo_clip_is_region (extents->clip) &&
+	(clip_region = _cairo_clip_get_region (extents->clip)) &&
+	cairo_region_contains_rectangle (clip_region,
+					 &extents->bounded) == CAIRO_REGION_OVERLAP_IN)
+	clip_region = NULL;
+
+
+    if (boxes->num_boxes <= 1 && clip_region == NULL)
+	return fixup_unbounded (compositor, dst, extents);
+
+    _cairo_boxes_init (&clear);
+
+    box.p1.x = _cairo_fixed_from_int (extents->unbounded.x + extents->unbounded.width);
+    box.p1.y = _cairo_fixed_from_int (extents->unbounded.y);
+    box.p2.x = _cairo_fixed_from_int (extents->unbounded.x);
+    box.p2.y = _cairo_fixed_from_int (extents->unbounded.y + extents->unbounded.height);
+
+    if (clip_region == NULL) {
+	cairo_boxes_t tmp;
+
+	_cairo_boxes_init (&tmp);
+
+	status = _cairo_boxes_add (&tmp, CAIRO_ANTIALIAS_DEFAULT, &box);
+	assert (status == CAIRO_STATUS_SUCCESS);
+
+	tmp.chunks.next = &boxes->chunks;
+	tmp.num_boxes += boxes->num_boxes;
+
+	status = _cairo_bentley_ottmann_tessellate_boxes (&tmp,
+							  CAIRO_FILL_RULE_WINDING,
+							  &clear);
+
+	tmp.chunks.next = NULL;
+    } else {
+	pixman_box32_t *pbox;
+
+	pbox = pixman_region32_rectangles (&clip_region->rgn, &i);
+	_cairo_boxes_limit (&clear, (cairo_box_t *) pbox, i);
+
+	status = _cairo_boxes_add (&clear, CAIRO_ANTIALIAS_DEFAULT, &box);
+	assert (status == CAIRO_STATUS_SUCCESS);
+
+	for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
+	    for (i = 0; i < chunk->count; i++) {
+		status = _cairo_boxes_add (&clear,
+					   CAIRO_ANTIALIAS_DEFAULT,
+					   &chunk->base[i]);
+		if (unlikely (status)) {
+		    _cairo_boxes_fini (&clear);
+		    return status;
+		}
+	    }
+	}
+
+	status = _cairo_bentley_ottmann_tessellate_boxes (&clear,
+							  CAIRO_FILL_RULE_WINDING,
+							  &clear);
+    }
+
+    if (likely (status == CAIRO_STATUS_SUCCESS)) {
+	status = compositor->fill_boxes (dst,
+					 CAIRO_OPERATOR_CLEAR,
+					 CAIRO_COLOR_TRANSPARENT,
+					 &clear);
+    }
+
+    _cairo_boxes_fini (&clear);
+
+    return status;
+}
+
+enum {
+    NEED_CLIP_REGION = 0x1,
+    NEED_CLIP_SURFACE = 0x2,
+    FORCE_CLIP_REGION = 0x4,
+};
+
+static cairo_bool_t
+need_bounded_clip (cairo_composite_rectangles_t *extents)
+{
+    unsigned int flags = NEED_CLIP_REGION;
+    if (! _cairo_clip_is_region (extents->clip))
+	flags |= NEED_CLIP_SURFACE;
+    return flags;
+}
+
+static cairo_bool_t
+need_unbounded_clip (cairo_composite_rectangles_t *extents)
+{
+    unsigned int flags = 0;
+    if (! extents->is_bounded) {
+	flags |= NEED_CLIP_REGION;
+	if (! _cairo_clip_is_region (extents->clip))
+	    flags |= NEED_CLIP_SURFACE;
+    }
+    if (extents->clip->path != NULL)
+	flags |= NEED_CLIP_SURFACE;
+    return flags;
+}
+
+static cairo_status_t
+clip_and_composite (const cairo_mask_compositor_t *compositor,
+		    draw_func_t			 draw_func,
+		    draw_func_t			 mask_func,
+		    void			*draw_closure,
+		    cairo_composite_rectangles_t*extents,
+		    unsigned int need_clip)
+{
+    cairo_surface_t *dst = extents->surface;
+    cairo_operator_t op = extents->op;
+    cairo_pattern_t *src = &extents->source_pattern.base;
+    cairo_region_t *clip_region = NULL;
+    cairo_status_t status;
+
+    compositor->acquire (dst);
+
+    if (need_clip & NEED_CLIP_REGION) {
+	clip_region = _cairo_clip_get_region (extents->clip);
+	if ((need_clip & FORCE_CLIP_REGION) == 0 &&
+	    _cairo_composite_rectangles_can_reduce_clip (extents,
+							 extents->clip))
+	    clip_region = NULL;
+	if (clip_region != NULL) {
+	    status = compositor->set_clip_region (dst, clip_region);
+	    if (unlikely (status)) {
+		compositor->release (dst);
+		return status;
+	    }
+	}
+    }
+
+    if (reduce_alpha_op (dst, op, &extents->source_pattern.base)) {
+	op = CAIRO_OPERATOR_ADD;
+	src = NULL;
+    }
+
+    if (op == CAIRO_OPERATOR_SOURCE) {
+	status = clip_and_composite_source (compositor,
+					    draw_closure, draw_func, mask_func,
+					    src, extents);
+    } else {
+	if (op == CAIRO_OPERATOR_CLEAR) {
+	    op = CAIRO_OPERATOR_DEST_OUT;
+	    src = NULL;
+	}
+
+	if (need_clip & NEED_CLIP_SURFACE) {
+	    if (extents->is_bounded) {
+		status = clip_and_composite_with_mask (compositor,
+						       draw_closure,
+						       draw_func,
+						       mask_func,
+						       op, src, extents);
+	    } else {
+		status = clip_and_composite_combine (compositor,
+						     draw_closure,
+						     draw_func,
+						     op, src, extents);
+	    }
+	} else {
+	    status = draw_func (compositor,
+				dst, draw_closure,
+				op, src, &extents->source_sample_area,
+				0, 0,
+				&extents->bounded,
+				extents->clip);
+	}
+    }
+
+    if (status == CAIRO_STATUS_SUCCESS && ! extents->is_bounded) {
+	if (need_clip & NEED_CLIP_SURFACE)
+	    status = fixup_unbounded_with_mask (compositor, dst, extents);
+	else
+	    status = fixup_unbounded (compositor, dst, extents);
+    }
+
+    if (clip_region)
+	compositor->set_clip_region (dst, NULL);
+
+    compositor->release (dst);
+
+    return status;
+}
+
+static cairo_int_status_t
+trim_extents_to_boxes (cairo_composite_rectangles_t *extents,
+		       cairo_boxes_t *boxes)
+{
+    cairo_box_t box;
+
+    _cairo_boxes_extents (boxes, &box);
+    return _cairo_composite_rectangles_intersect_mask_extents (extents, &box);
+}
+
+static cairo_status_t
+upload_boxes (const cairo_mask_compositor_t *compositor,
+	      cairo_composite_rectangles_t *extents,
+	      cairo_boxes_t *boxes)
+{
+    cairo_surface_t *dst = extents->surface;
+    const cairo_pattern_t *source = &extents->source_pattern.base;
+    const cairo_surface_pattern_t *pattern;
+    cairo_surface_t *src;
+    cairo_rectangle_int_t limit;
+    cairo_int_status_t status;
+    int tx, ty;
+
+    pattern = (const cairo_surface_pattern_t *) source;
+    src = pattern->surface;
+    if (!(src->type == CAIRO_SURFACE_TYPE_IMAGE || src->type == dst->type))
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+
+    if (! _cairo_matrix_is_integer_translation (&source->matrix, &tx, &ty))
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+
+    if (_cairo_surface_is_snapshot (src))
+	src = _cairo_surface_snapshot_get_target (src);
+    if (_cairo_surface_is_observer (src))
+	src = _cairo_surface_observer_get_target (src);
+    if (_cairo_surface_is_subsurface (src)) {
+	_cairo_surface_subsurface_offset (src, &tx, &ty);
+	src = _cairo_surface_subsurface_get_target (src);
+    }
+
+    /* Check that the data is entirely within the image */
+    if (extents->bounded.x + tx < 0 || extents->bounded.y + ty < 0)
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+
+    _cairo_surface_get_extents (pattern->surface, &limit);
+    if (extents->bounded.x + extents->bounded.width  + tx > limit.width ||
+	extents->bounded.y + extents->bounded.height + ty > limit.height)
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+
+    if (pattern->surface->type == CAIRO_SURFACE_TYPE_IMAGE)
+	status = compositor->draw_image_boxes (dst,
+					       (cairo_image_surface_t *)src,
+					       boxes, tx, ty);
+    else
+	status = compositor->copy_boxes (dst, src, boxes, &extents->bounded,
+					 tx, ty);
+
+    return status;
+}
+
+static cairo_status_t
+composite_boxes (const cairo_mask_compositor_t *compositor,
+		 const cairo_composite_rectangles_t *extents,
+		 cairo_boxes_t *boxes)
+{
+    cairo_surface_t *dst = extents->surface;
+    cairo_operator_t op = extents->op;
+    const cairo_pattern_t *source = &extents->source_pattern.base;
+    cairo_bool_t need_clip_mask = extents->clip->path != NULL;
+    cairo_status_t status;
+
+    if (need_clip_mask &&
+	(! extents->is_bounded || op == CAIRO_OPERATOR_SOURCE))
+    {
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+    }
+
+    status = compositor->acquire (dst);
+    if (unlikely (status))
+	return status;
+
+    if (! need_clip_mask && source->type == CAIRO_PATTERN_TYPE_SOLID) {
+	const cairo_color_t *color;
+
+	color = &((cairo_solid_pattern_t *) source)->color;
+	status = compositor->fill_boxes (dst, op, color, boxes);
+    } else {
+	cairo_surface_t *src, *mask = NULL;
+	int src_x, src_y;
+	int mask_x = 0, mask_y = 0;
+
+	if (need_clip_mask) {
+	    mask = _cairo_clip_get_image (extents->clip, dst,
+					  &extents->bounded);
+	    if (unlikely (mask->status))
+		return mask->status;
+
+	    if (op == CAIRO_OPERATOR_CLEAR) {
+		source = NULL;
+		op = CAIRO_OPERATOR_DEST_OUT;
+	    }
+
+	    mask_x = -extents->bounded.x;
+	    mask_y = -extents->bounded.y;
+	}
+
+	if (source || mask == NULL) {
+	    src = compositor->pattern_to_surface (dst, source, FALSE,
+						  &extents->bounded,
+						  &extents->source_sample_area,
+						  &src_x, &src_y);
+	} else {
+	    src = mask;
+	    src_x = mask_x;
+	    src_y = mask_y;
+	    mask = NULL;
+	}
+
+	status = compositor->composite_boxes (dst, op, src, mask,
+					      src_x, src_y,
+					      mask_x, mask_y,
+					      0, 0,
+					      boxes, &extents->bounded);
+
+	cairo_surface_destroy (src);
+	cairo_surface_destroy (mask);
+    }
+
+    if (status == CAIRO_STATUS_SUCCESS && ! extents->is_bounded)
+	status = fixup_unbounded_boxes (compositor, extents, boxes);
+
+    compositor->release (dst);
+
+    return status;
+}
+
+static cairo_status_t
+clip_and_composite_boxes (const cairo_mask_compositor_t *compositor,
+			  cairo_composite_rectangles_t *extents,
+			  cairo_boxes_t *boxes)
+{
+    cairo_surface_t *dst = extents->surface;
+    cairo_int_status_t status;
+
+    if (boxes->num_boxes == 0) {
+	if (extents->is_bounded)
+	    return CAIRO_STATUS_SUCCESS;
+
+	return fixup_unbounded_boxes (compositor, extents, boxes);
+    }
+
+    if (! boxes->is_pixel_aligned)
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+
+    status = trim_extents_to_boxes (extents, boxes);
+    if (unlikely (status))
+	return status;
+
+    if (extents->source_pattern.base.type == CAIRO_PATTERN_TYPE_SURFACE &&
+	extents->clip->path == NULL &&
+	(extents->op == CAIRO_OPERATOR_SOURCE ||
+	 (dst->is_clear && (extents->op == CAIRO_OPERATOR_OVER ||
+			    extents->op == CAIRO_OPERATOR_ADD))))
+    {
+	status = upload_boxes (compositor, extents, boxes);
+	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+	    return status;
+    }
+
+    return composite_boxes (compositor, extents, boxes);
+}
+
+/* high-level compositor interface */
+
+static cairo_int_status_t
+_cairo_mask_compositor_paint (const cairo_compositor_t *_compositor,
+			      cairo_composite_rectangles_t *extents)
+{
+    cairo_mask_compositor_t *compositor = (cairo_mask_compositor_t*)_compositor;
+    cairo_boxes_t boxes;
+    cairo_int_status_t status;
+
+    _cairo_clip_steal_boxes (extents->clip, &boxes);
+    status = clip_and_composite_boxes (compositor, extents, &boxes);
+    _cairo_clip_unsteal_boxes (extents->clip, &boxes);
+
+    return status;
+}
+
+struct composite_opacity_info {
+    const cairo_mask_compositor_t *compositor;
+    uint8_t op;
+    cairo_surface_t *dst;
+    cairo_surface_t *src;
+    int src_x, src_y;
+    double opacity;
+};
+
+static void composite_opacity(void *closure,
+			      int16_t x, int16_t y,
+			      int16_t w, int16_t h,
+			      uint16_t coverage)
+{
+    struct composite_opacity_info *info = closure;
+    const cairo_mask_compositor_t *compositor = info->compositor;
+    cairo_surface_t *mask;
+    int mask_x, mask_y;
+    cairo_color_t color;
+    cairo_solid_pattern_t solid;
+
+    _cairo_color_init_rgba (&color, 0, 0, 0, info->opacity * coverage);
+    _cairo_pattern_init_solid (&solid, &color);
+    mask = compositor->pattern_to_surface (info->dst, &solid.base, TRUE,
+					   &_cairo_unbounded_rectangle,
+					   &_cairo_unbounded_rectangle,
+					   &mask_x, &mask_y);
+    if (likely (mask->status == CAIRO_STATUS_SUCCESS)) {
+	if (info->src) {
+	    compositor->composite (info->dst, info->op, info->src, mask,
+				   x + info->src_x,  y + info->src_y,
+				   mask_x,           mask_y,
+				   x,                y,
+				   w,                h);
+	} else {
+	    compositor->composite (info->dst, info->op, mask, NULL,
+				   mask_x,            mask_y,
+				   0,                 0,
+				   x,                 y,
+				   w,                 h);
+	}
+    }
+
+    cairo_surface_destroy (mask);
+}
+
+static cairo_int_status_t
+composite_opacity_boxes (const cairo_mask_compositor_t *compositor,
+			 cairo_surface_t		*dst,
+			 void				*closure,
+			 cairo_operator_t		 op,
+			 const cairo_pattern_t		*src_pattern,
+			 const cairo_rectangle_int_t	*src_sample,
+			 int				 dst_x,
+			 int				 dst_y,
+			 const cairo_rectangle_int_t	*extents,
+			 cairo_clip_t			*clip)
+{
+    const cairo_solid_pattern_t *mask_pattern = closure;
+    struct composite_opacity_info info;
+    int i;
+
+    assert (clip);
+
+    info.compositor = compositor;
+    info.op = op;
+    info.dst = dst;
+
+    if (src_pattern != NULL) {
+	info.src = compositor->pattern_to_surface (dst, src_pattern, FALSE,
+						   extents, src_sample,
+						   &info.src_x, &info.src_y);
+	if (unlikely (info.src->status))
+	    return info.src->status;
+    } else
+	info.src = NULL;
+
+    info.opacity = mask_pattern->color.alpha / (double) 0xffff;
+
+    /* XXX for lots of boxes create a clip region for the fully opaque areas */
+    for (i = 0; i < clip->num_boxes; i++)
+	do_unaligned_box(composite_opacity, &info,
+			 &clip->boxes[i], dst_x, dst_y);
+    cairo_surface_destroy (info.src);
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+struct composite_box_info {
+    const cairo_mask_compositor_t *compositor;
+    cairo_surface_t *dst;
+    cairo_surface_t *src;
+    int src_x, src_y;
+    uint8_t op;
+};
+
+static void composite_box(void *closure,
+			  int16_t x, int16_t y,
+			  int16_t w, int16_t h,
+			  uint16_t coverage)
+{
+    struct composite_box_info *info = closure;
+    const cairo_mask_compositor_t *compositor = info->compositor;
+
+    if (! CAIRO_ALPHA_SHORT_IS_OPAQUE (coverage)) {
+	cairo_surface_t *mask;
+	cairo_color_t color;
+	cairo_solid_pattern_t solid;
+	int mask_x, mask_y;
+
+	_cairo_color_init_rgba (&color, 0, 0, 0, coverage / (double)0xffff);
+	_cairo_pattern_init_solid (&solid, &color);
+
+	mask = compositor->pattern_to_surface (info->dst, &solid.base, FALSE,
+					       &_cairo_unbounded_rectangle,
+					       &_cairo_unbounded_rectangle,
+					       &mask_x, &mask_y);
+
+	if (likely (mask->status == CAIRO_STATUS_SUCCESS)) {
+	    compositor->composite (info->dst, info->op, info->src, mask,
+				   x + info->src_x,  y + info->src_y,
+				   mask_x,           mask_y,
+				   x,                y,
+				   w,                h);
+	}
+
+	cairo_surface_destroy (mask);
+    } else {
+	compositor->composite (info->dst, info->op, info->src, NULL,
+			       x + info->src_x,  y + info->src_y,
+			       0,                0,
+			       x,                y,
+			       w,                h);
+    }
+}
+
+static cairo_int_status_t
+composite_mask_clip_boxes (const cairo_mask_compositor_t *compositor,
+			   cairo_surface_t		*dst,
+			   void				*closure,
+			   cairo_operator_t		 op,
+			   const cairo_pattern_t	*src_pattern,
+			   const cairo_rectangle_int_t	*src_sample,
+			   int				 dst_x,
+			   int				 dst_y,
+			   const cairo_rectangle_int_t	*extents,
+			   cairo_clip_t			*clip)
+{
+    cairo_composite_rectangles_t *composite = closure;
+    struct composite_box_info info;
+    int i;
+
+    assert (src_pattern == NULL);
+    assert (op == CAIRO_OPERATOR_SOURCE);
+
+    info.compositor = compositor;
+    info.op = CAIRO_OPERATOR_SOURCE;
+    info.dst = dst;
+    info.src = compositor->pattern_to_surface (dst,
+					       &composite->mask_pattern.base,
+					       FALSE, extents,
+					       &composite->mask_sample_area,
+					       &info.src_x, &info.src_y);
+    if (unlikely (info.src->status))
+	return info.src->status;
+
+    info.src_x += dst_x;
+    info.src_y += dst_y;
+
+    for (i = 0; i < clip->num_boxes; i++)
+	do_unaligned_box(composite_box, &info, &clip->boxes[i], dst_x, dst_y);
+
+    cairo_surface_destroy (info.src);
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+composite_mask (const cairo_mask_compositor_t *compositor,
+		cairo_surface_t			*dst,
+		void				*closure,
+		cairo_operator_t		 op,
+		const cairo_pattern_t		*src_pattern,
+		const cairo_rectangle_int_t	*src_sample,
+		int				 dst_x,
+		int				 dst_y,
+		const cairo_rectangle_int_t	*extents,
+		cairo_clip_t			*clip)
+{
+    cairo_composite_rectangles_t *composite = closure;
+    cairo_surface_t *src, *mask;
+    int src_x, src_y;
+    int mask_x, mask_y;
+
+    if (src_pattern != NULL) {
+	src = compositor->pattern_to_surface (dst, src_pattern, FALSE,
+					      extents, src_sample,
+					      &src_x, &src_y);
+	if (unlikely (src->status))
+	    return src->status;
+
+	mask = compositor->pattern_to_surface (dst, &composite->mask_pattern.base, TRUE,
+					       extents, &composite->mask_sample_area,
+					       &mask_x, &mask_y);
+	if (unlikely (mask->status)) {
+	    cairo_surface_destroy (src);
+	    return mask->status;
+	}
+
+	compositor->composite (dst, op, src, mask,
+			       extents->x + src_x,  extents->y + src_y,
+			       extents->x + mask_x, extents->y + mask_y,
+			       extents->x - dst_x,  extents->y - dst_y,
+			       extents->width,      extents->height);
+
+	cairo_surface_destroy (mask);
+	cairo_surface_destroy (src);
+    } else {
+	src = compositor->pattern_to_surface (dst, &composite->mask_pattern.base, FALSE,
+					      extents, &composite->mask_sample_area,
+					      &src_x, &src_y);
+	if (unlikely (src->status))
+	    return src->status;
+
+	compositor->composite (dst, op, src, NULL,
+			       extents->x + src_x,  extents->y + src_y,
+			       0, 0,
+			       extents->x - dst_x,  extents->y - dst_y,
+			       extents->width,      extents->height);
+
+	cairo_surface_destroy (src);
+    }
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+_cairo_mask_compositor_mask (const cairo_compositor_t *_compositor,
+			     cairo_composite_rectangles_t *extents)
+{
+    const cairo_mask_compositor_t *compositor = (cairo_mask_compositor_t*)_compositor;
+    cairo_int_status_t status = CAIRO_INT_STATUS_UNSUPPORTED;
+
+    if (extents->mask_pattern.base.type == CAIRO_PATTERN_TYPE_SOLID &&
+	extents->clip->path == NULL &&
+	! _cairo_clip_is_region (extents->clip)) {
+	status = clip_and_composite (compositor,
+				     composite_opacity_boxes,
+				     composite_opacity_boxes,
+				     &extents->mask_pattern.solid,
+				     extents, need_unbounded_clip (extents));
+    } else {
+	status = clip_and_composite (compositor,
+				     composite_mask,
+				     extents->clip->path == NULL ? composite_mask_clip_boxes : NULL,
+				     extents,
+				     extents, need_bounded_clip (extents));
+    }
+
+    return status;
+}
+
+static cairo_int_status_t
+_cairo_mask_compositor_stroke (const cairo_compositor_t *_compositor,
+			       cairo_composite_rectangles_t *extents,
+			       const cairo_path_fixed_t	*path,
+			       const cairo_stroke_style_t	*style,
+			       const cairo_matrix_t	*ctm,
+			       const cairo_matrix_t	*ctm_inverse,
+			       double		 tolerance,
+			       cairo_antialias_t	 antialias)
+{
+    const cairo_mask_compositor_t *compositor = (cairo_mask_compositor_t*)_compositor;
+    cairo_surface_t *mask;
+    cairo_surface_pattern_t pattern;
+    cairo_int_status_t status;
+
+    status = CAIRO_INT_STATUS_UNSUPPORTED;
+    if (_cairo_path_fixed_stroke_is_rectilinear (path)) {
+	cairo_boxes_t boxes;
+
+	_cairo_boxes_init_with_clip (&boxes, extents->clip);
+	status = _cairo_path_fixed_stroke_rectilinear_to_boxes (path,
+								style,
+								ctm,
+								antialias,
+								&boxes);
+	if (likely (status == CAIRO_INT_STATUS_SUCCESS))
+	    status = clip_and_composite_boxes (compositor, extents, &boxes);
+	_cairo_boxes_fini (&boxes);
+    }
+
+
+    if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
+	mask = cairo_surface_create_similar_image (extents->surface,
+						   CAIRO_FORMAT_A8,
+						   extents->bounded.width,
+						   extents->bounded.height);
+	if (unlikely (mask->status))
+	    return mask->status;
+
+	status = _cairo_surface_offset_stroke (mask,
+					       extents->bounded.x,
+					       extents->bounded.y,
+					       CAIRO_OPERATOR_ADD,
+					       &_cairo_pattern_white.base,
+					       path, style, ctm, ctm_inverse,
+					       tolerance, antialias,
+					       extents->clip);
+	if (unlikely (status)) {
+	    cairo_surface_destroy (mask);
+	    return status;
+	}
+
+	_cairo_pattern_init_for_surface (&pattern, mask);
+	cairo_surface_destroy (mask);
+
+	cairo_matrix_init_translate (&pattern.base.matrix,
+				     -extents->bounded.x,
+				     -extents->bounded.y);
+	pattern.base.filter = CAIRO_FILTER_NEAREST;
+	pattern.base.extend = CAIRO_EXTEND_NONE;
+	status = _cairo_surface_mask (extents->surface,
+				      extents->op,
+				      &extents->source_pattern.base,
+				      &pattern.base,
+				      extents->clip);
+	_cairo_pattern_fini (&pattern.base);
+    }
+
+    return status;
+}
+
+static cairo_int_status_t
+_cairo_mask_compositor_fill (const cairo_compositor_t *_compositor,
+			     cairo_composite_rectangles_t *extents,
+			     const cairo_path_fixed_t	*path,
+			     cairo_fill_rule_t	 fill_rule,
+			     double			 tolerance,
+			     cairo_antialias_t	 antialias)
+{
+    const cairo_mask_compositor_t *compositor = (cairo_mask_compositor_t*)_compositor;
+    cairo_surface_t *mask;
+    cairo_surface_pattern_t pattern;
+    cairo_int_status_t status;
+
+    status = CAIRO_INT_STATUS_UNSUPPORTED;
+    if (_cairo_path_fixed_fill_is_rectilinear (path)) {
+	cairo_boxes_t boxes;
+
+	_cairo_boxes_init_with_clip (&boxes, extents->clip);
+	status = _cairo_path_fixed_fill_rectilinear_to_boxes (path,
+							      fill_rule,
+							      antialias,
+							      &boxes);
+	if (likely (status == CAIRO_INT_STATUS_SUCCESS))
+	    status = clip_and_composite_boxes (compositor, extents, &boxes);
+	_cairo_boxes_fini (&boxes);
+    }
+
+    if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
+	mask = cairo_surface_create_similar_image (extents->surface,
+						   CAIRO_FORMAT_A8,
+						   extents->bounded.width,
+						   extents->bounded.height);
+	if (unlikely (mask->status))
+	    return mask->status;
+
+	status = _cairo_surface_offset_fill (mask,
+					     extents->bounded.x,
+					     extents->bounded.y,
+					     CAIRO_OPERATOR_ADD,
+					     &_cairo_pattern_white.base,
+					     path, fill_rule, tolerance, antialias,
+					     extents->clip);
+	if (unlikely (status)) {
+	    cairo_surface_destroy (mask);
+	    return status;
+	}
+
+	_cairo_pattern_init_for_surface (&pattern, mask);
+	cairo_surface_destroy (mask);
+
+	cairo_matrix_init_translate (&pattern.base.matrix,
+				     -extents->bounded.x,
+				     -extents->bounded.y);
+	pattern.base.filter = CAIRO_FILTER_NEAREST;
+	pattern.base.extend = CAIRO_EXTEND_NONE;
+	status = _cairo_surface_mask (extents->surface,
+				      extents->op,
+				      &extents->source_pattern.base,
+				      &pattern.base,
+				      extents->clip);
+	_cairo_pattern_fini (&pattern.base);
+    }
+
+    return status;
+}
+
+static cairo_int_status_t
+_cairo_mask_compositor_glyphs (const cairo_compositor_t *_compositor,
+			       cairo_composite_rectangles_t *extents,
+			       cairo_scaled_font_t	*scaled_font,
+			       cairo_glyph_t		*glyphs,
+			       int			 num_glyphs,
+			       cairo_bool_t		 overlap)
+{
+    cairo_surface_t *mask;
+    cairo_surface_pattern_t pattern;
+    cairo_int_status_t status;
+
+    mask = cairo_surface_create_similar_image (extents->surface,
+					       CAIRO_FORMAT_A8,
+					       extents->bounded.width,
+					       extents->bounded.height);
+    if (unlikely (mask->status))
+	return mask->status;
+
+    status = _cairo_surface_offset_glyphs (mask,
+					   extents->bounded.x,
+					   extents->bounded.y,
+					   CAIRO_OPERATOR_ADD,
+					   &_cairo_pattern_white.base,
+					   scaled_font, glyphs, num_glyphs,
+					   extents->clip);
+    if (unlikely (status)) {
+	cairo_surface_destroy (mask);
+	return status;
+    }
+
+    _cairo_pattern_init_for_surface (&pattern, mask);
+    cairo_surface_destroy (mask);
+
+    cairo_matrix_init_translate (&pattern.base.matrix,
+				 -extents->bounded.x,
+				 -extents->bounded.y);
+    pattern.base.filter = CAIRO_FILTER_NEAREST;
+    pattern.base.extend = CAIRO_EXTEND_NONE;
+    status = _cairo_surface_mask (extents->surface,
+				  extents->op,
+				  &extents->source_pattern.base,
+				  &pattern.base,
+				  extents->clip);
+    _cairo_pattern_fini (&pattern.base);
+
+    return status;
+}
+
+void
+_cairo_mask_compositor_init (cairo_mask_compositor_t *compositor,
+			     const cairo_compositor_t *delegate)
+{
+    compositor->base.delegate = delegate;
+
+    compositor->base.paint = _cairo_mask_compositor_paint;
+    compositor->base.mask  = _cairo_mask_compositor_mask;
+    compositor->base.fill  = _cairo_mask_compositor_fill;
+    compositor->base.stroke = _cairo_mask_compositor_stroke;
+    compositor->base.glyphs = _cairo_mask_compositor_glyphs;
+}
diff --git a/src/cairo-matrix.c b/src/cairo-matrix.c
index 195438c..2521135 100644
--- a/src/cairo-matrix.c
+++ b/src/cairo-matrix.c
@@ -889,6 +889,9 @@ _cairo_matrix_transformed_circle_major_axis (const cairo_matrix_t *matrix,
 {
     double  a, b, c, d, f, g, h, i, j;
 
+    if (_cairo_matrix_has_unity_scale (matrix))
+	return radius;
+
     _cairo_matrix_get_affine (matrix,
                               &a, &b,
                               &c, &d,
@@ -1043,6 +1046,9 @@ _cairo_matrix_is_pixman_translation (const cairo_matrix_t     *matrix,
     if (!_cairo_matrix_is_translation (matrix))
 	return FALSE;
 
+    if (matrix->x0 == 0. && matrix->y0 == 0.)
+	return TRUE;
+
     tx = matrix->x0 + *x_offset;
     ty = matrix->y0 + *y_offset;
 
diff --git a/src/cairo-mesh-pattern-rasterizer.c b/src/cairo-mesh-pattern-rasterizer.c
index 9c9d0ec..82b16e7 100644
--- a/src/cairo-mesh-pattern-rasterizer.c
+++ b/src/cairo-mesh-pattern-rasterizer.c
@@ -36,6 +36,7 @@
 
 #include "cairoint.h"
 
+#include "cairo-array-private.h"
 #include "cairo-pattern-private.h"
 
 /*
diff --git a/src/cairo-mime-surface.c b/src/cairo-mime-surface.c
index f23c451..e19852f 100644
--- a/src/cairo-mime-surface.c
+++ b/src/cairo-mime-surface.c
@@ -97,6 +97,7 @@
 #include "cairoint.h"
 #include "cairo-error-private.h"
 #include "cairo-image-surface-private.h"
+#include "cairo-surface-backend-private.h"
 
 typedef struct _cairo_mime_surface {
     cairo_surface_t base;
@@ -221,32 +222,25 @@ static const cairo_surface_backend_t cairo_mime_surface_backend = {
 
     _cairo_mime_surface_acquire_source_image,
     _cairo_mime_surface_release_source_image,
-    NULL, /* acquire_dest_image */
-    NULL, /* release_dest_image */
-    NULL, /* clone_similar */
-    NULL, /* composite */
-    NULL, /* fill_rectangles */
-    NULL, /* composite_trapezoids */
-    NULL, /* create_span_renderer */
-    NULL, /* check_span_renderer */
+    _cairo_mime_surface_snapshot,
+
     NULL, /* copy_page */
     NULL, /* show_page */
+
     _cairo_mime_surface_get_extents,
-    NULL, /* old_show_glyphs */
     NULL, /* get_font_options */
+
     NULL, /* flush */
     NULL, /* mark_dirty_rectangle */
+
     NULL, /* scaled_font_fini */
     NULL, /* scaled_glyph_fini */
 
-
     NULL, /* paint */
     NULL, /* mask */
     NULL, /* stroke */
     NULL, /* fill */
     NULL, /* glyphs */
-
-    _cairo_mime_surface_snapshot,
 };
 
 cairo_surface_t *
diff --git a/src/cairo-mono-scan-converter.c b/src/cairo-mono-scan-converter.c
new file mode 100644
index 0000000..98b7631
--- /dev/null
+++ b/src/cairo-mono-scan-converter.c
@@ -0,0 +1,607 @@
+/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
+/*
+ * Copyright (c) 2011  Intel 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.
+ */
+#include "cairoint.h"
+#include "cairo-spans-private.h"
+#include "cairo-error-private.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+struct quorem {
+    int32_t quo;
+    int32_t rem;
+};
+
+struct edge {
+    struct edge *next, *prev;
+
+    int32_t height_left;
+    int32_t dir;
+    int32_t vertical;
+
+    int32_t dy;
+    struct quorem x;
+    struct quorem dxdy;
+};
+
+/* A collection of sorted and vertically clipped edges of the polygon.
+ * Edges are moved from the polygon to an active list while scan
+ * converting. */
+struct polygon {
+    /* The vertical clip extents. */
+    int32_t ymin, ymax;
+
+    int num_edges;
+    struct edge *edges;
+
+    /* Array of edges all starting in the same bucket.	An edge is put
+     * into bucket EDGE_BUCKET_INDEX(edge->ytop, polygon->ymin) when
+     * it is added to the polygon. */
+    struct edge **y_buckets;
+
+    struct edge *y_buckets_embedded[64];
+    struct edge edges_embedded[32];
+};
+
+struct mono_scan_converter {
+    struct polygon polygon[1];
+
+    /* Leftmost edge on the current scan line. */
+    struct edge head, tail;
+    int is_vertical;
+
+    cairo_half_open_span_t *spans;
+    cairo_half_open_span_t spans_embedded[64];
+    int num_spans;
+
+    /* Clip box. */
+    int32_t xmin, xmax;
+    int32_t ymin, ymax;
+};
+
+#define I(x) _cairo_fixed_integer_round_down(x)
+
+/* Compute the floored division a/b. Assumes / and % perform symmetric
+ * division. */
+inline static struct quorem
+floored_divrem(int a, int b)
+{
+    struct quorem qr;
+    qr.quo = a/b;
+    qr.rem = a%b;
+    if ((a^b)<0 && qr.rem) {
+	qr.quo -= 1;
+	qr.rem += b;
+    }
+    return qr;
+}
+
+/* Compute the floored division (x*a)/b. Assumes / and % perform symmetric
+ * division. */
+static struct quorem
+floored_muldivrem(int x, int a, int b)
+{
+    struct quorem qr;
+    long long xa = (long long)x*a;
+    qr.quo = xa/b;
+    qr.rem = xa%b;
+    if ((xa>=0) != (b>=0) && qr.rem) {
+	qr.quo -= 1;
+	qr.rem += b;
+    }
+    return qr;
+}
+
+static cairo_status_t
+polygon_init (struct polygon *polygon, int ymin, int ymax)
+{
+    unsigned h = ymax - ymin;
+
+    polygon->y_buckets = polygon->y_buckets_embedded;
+    if (h > ARRAY_LENGTH (polygon->y_buckets_embedded)) {
+	polygon->y_buckets = _cairo_malloc_ab (h, sizeof (struct edge *));
+	if (unlikely (NULL == polygon->y_buckets))
+	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+    }
+    memset (polygon->y_buckets, 0, h * sizeof (struct edge *)); 
+
+    polygon->ymin = ymin;
+    polygon->ymax = ymax;
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static void
+polygon_fini (struct polygon *polygon)
+{
+    if (polygon->y_buckets != polygon->y_buckets_embedded)
+	free (polygon->y_buckets);
+
+    if (polygon->edges != polygon->edges_embedded)
+	free (polygon->edges);
+}
+
+static void
+_polygon_insert_edge_into_its_y_bucket(struct polygon *polygon,
+				       struct edge *e,
+				       int y)
+{
+    struct edge **ptail = &polygon->y_buckets[y - polygon->ymin];
+    if (*ptail)
+	(*ptail)->prev = e;
+    e->next = *ptail;
+    e->prev = NULL;
+    *ptail = e;
+}
+
+inline static void
+polygon_add_edge (struct polygon *polygon,
+		  const cairo_edge_t *edge)
+{
+    struct edge *e;
+    cairo_fixed_t dx;
+    cairo_fixed_t dy;
+    int y, ytop, ybot;
+    int ymin = polygon->ymin;
+    int ymax = polygon->ymax;
+
+    y = I(edge->top);
+    ytop = MAX(y, ymin);
+
+    y = I(edge->bottom);
+    ybot = MIN(y, ymax);
+
+    if (ybot <= ytop)
+	return;
+
+    e = polygon->edges + polygon->num_edges++;
+    e->height_left = ybot - ytop;
+    e->dir = edge->dir;
+
+    dx = edge->line.p2.x - edge->line.p1.x;
+    dy = edge->line.p2.y - edge->line.p1.y;
+
+    if (dx == 0) {
+	e->vertical = TRUE;
+	e->x.quo = edge->line.p1.x;
+	e->x.rem = 0;
+	e->dxdy.quo = 0;
+	e->dxdy.rem = 0;
+	e->dy = 0;
+    } else {
+	e->vertical = FALSE;
+	e->dxdy = floored_muldivrem (dx, CAIRO_FIXED_ONE, dy);
+	e->dy = dy;
+
+	e->x = floored_muldivrem (ytop * CAIRO_FIXED_ONE + CAIRO_FIXED_FRAC_MASK/2 - edge->line.p1.y,
+				  dx, dy);
+	e->x.quo += edge->line.p1.x;
+	e->x.rem -= dy;
+    }
+
+    _polygon_insert_edge_into_its_y_bucket (polygon, e, ytop);
+}
+
+static struct edge *
+merge_sorted_edges (struct edge *head_a, struct edge *head_b)
+{
+    struct edge *head, **next, *prev;
+    int32_t x;
+
+    prev = head_a->prev;
+    next = &head;
+    if (head_a->x.quo <= head_b->x.quo) {
+	head = head_a;
+    } else {
+	head = head_b;
+	head_b->prev = prev;
+	goto start_with_b;
+    }
+
+    do {
+	x = head_b->x.quo;
+	while (head_a != NULL && head_a->x.quo <= x) {
+	    prev = head_a;
+	    next = &head_a->next;
+	    head_a = head_a->next;
+	}
+
+	head_b->prev = prev;
+	*next = head_b;
+	if (head_a == NULL)
+	    return head;
+
+start_with_b:
+	x = head_a->x.quo;
+	while (head_b != NULL && head_b->x.quo <= x) {
+	    prev = head_b;
+	    next = &head_b->next;
+	    head_b = head_b->next;
+	}
+
+	head_a->prev = prev;
+	*next = head_a;
+	if (head_b == NULL)
+	    return head;
+    } while (1);
+}
+
+static struct edge *
+sort_edges (struct edge *list,
+	    unsigned int level,
+	    struct edge **head_out)
+{
+    struct edge *head_other, *remaining;
+    unsigned int i;
+
+    head_other = list->next;
+
+    if (head_other == NULL) {
+	*head_out = list;
+	return NULL;
+    }
+
+    remaining = head_other->next;
+    if (list->x.quo <= head_other->x.quo) {
+	*head_out = list;
+	head_other->next = NULL;
+    } else {
+	*head_out = head_other;
+	head_other->prev = list->prev;
+	head_other->next = list;
+	list->prev = head_other;
+	list->next = NULL;
+    }
+
+    for (i = 0; i < level && remaining; i++) {
+	remaining = sort_edges (remaining, i, &head_other);
+	*head_out = merge_sorted_edges (*head_out, head_other);
+    }
+
+    return remaining;
+}
+
+static struct edge *
+merge_unsorted_edges (struct edge *head, struct edge *unsorted)
+{
+    sort_edges (unsorted, UINT_MAX, &unsorted);
+    return merge_sorted_edges (head, unsorted);
+}
+
+inline static void
+active_list_merge_edges (struct mono_scan_converter *c, struct edge *edges)
+{
+    struct edge *e;
+
+    for (e = edges; c->is_vertical && e; e = e->next)
+	c->is_vertical = e->vertical;
+
+    c->head.next = merge_unsorted_edges (c->head.next, edges);
+}
+
+inline static void
+add_span (struct mono_scan_converter *c, int x1, int x2)
+{
+    int n;
+
+    if (x1 < c->xmin)
+	x1 = c->xmin;
+    if (x2 > c->xmax)
+	x2 = c->xmax;
+    if (x2 <= x1)
+	return;
+
+    n = c->num_spans++;
+    c->spans[n].x = x1;
+    c->spans[n].coverage = 255;
+
+    n = c->num_spans++;
+    c->spans[n].x = x2;
+    c->spans[n].coverage = 0;
+}
+
+inline static void
+row (struct mono_scan_converter *c, unsigned int mask)
+{
+    struct edge *edge = c->head.next;
+    int xstart = INT_MIN, prev_x = INT_MIN;
+    int winding = 0;
+
+    c->num_spans = 0;
+    while (&c->tail != edge) {
+	struct edge *next = edge->next;
+	int xend = I(edge->x.quo);
+
+	if (--edge->height_left) {
+	    edge->x.quo += edge->dxdy.quo;
+	    edge->x.rem += edge->dxdy.rem;
+	    if (edge->x.rem >= 0) {
+		++edge->x.quo;
+		edge->x.rem -= edge->dy;
+	    }
+
+	    if (edge->x.quo < prev_x) {
+		struct edge *pos = edge->prev;
+		pos->next = next;
+		next->prev = pos;
+		do {
+		    pos = pos->prev;
+		} while (edge->x.quo < pos->x.quo);
+		pos->next->prev = edge;
+		edge->next = pos->next;
+		edge->prev = pos;
+		pos->next = edge;
+	    } else
+		prev_x = edge->x.quo;
+	} else {
+	    edge->prev->next = next;
+	    next->prev = edge->prev;
+	}
+
+	winding += edge->dir;
+	if ((winding & mask) == 0) {
+	    if (I(next->x.quo) != xend) {
+		add_span (c, xstart, xend);
+		xstart = INT_MIN;
+	    }
+	} else if (xstart == INT_MIN)
+	    xstart = xend;
+
+	edge = next;
+    }
+}
+
+inline static void dec (struct edge *e, int h)
+{
+    e->height_left -= h;
+    if (e->height_left == 0) {
+	e->prev->next = e->next;
+	e->next->prev = e->prev;
+    }
+}
+
+static cairo_status_t
+_mono_scan_converter_init(struct mono_scan_converter *c,
+			  int xmin, int ymin,
+			  int xmax, int ymax)
+{
+    cairo_status_t status;
+
+    status = polygon_init (c->polygon, ymin, ymax);
+    if  (unlikely (status))
+	return status;
+
+    if (xmax - xmin > ARRAY_LENGTH(c->spans_embedded)) {
+	c->spans = _cairo_malloc_ab (xmax - xmin,
+				     sizeof (cairo_half_open_span_t));
+	if (unlikely (c->spans == NULL)) {
+	    polygon_fini (c->polygon);
+	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+	}
+    } else
+	c->spans = c->spans_embedded;
+
+    c->xmin = xmin;
+    c->xmax = xmax;
+    c->ymin = ymin;
+    c->ymax = ymax;
+
+    c->head.vertical = 1;
+    c->head.height_left = INT_MAX;
+    c->head.x.quo = INT_MIN;
+    c->head.prev = NULL;
+    c->head.next = &c->tail;
+    c->tail.prev = &c->head;
+    c->tail.next = NULL;
+    c->tail.x.quo = INT_MAX;
+    c->tail.height_left = INT_MAX;
+    c->tail.vertical = 1;
+
+    c->is_vertical = 1;
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static void
+_mono_scan_converter_fini(struct mono_scan_converter *self)
+{
+    if (self->spans != self->spans_embedded)
+	free (self->spans);
+
+    polygon_fini(self->polygon);
+}
+
+static cairo_status_t
+mono_scan_converter_allocate_edges(struct mono_scan_converter *c,
+				   int num_edges)
+
+{
+    c->polygon->num_edges = 0;
+    c->polygon->edges = c->polygon->edges_embedded;
+    if (num_edges > ARRAY_LENGTH (c->polygon->edges_embedded)) {
+	c->polygon->edges = _cairo_malloc_ab (num_edges, sizeof (struct edge));
+	if (unlikely (c->polygon->edges == NULL))
+	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+    }
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static void
+mono_scan_converter_add_edge (struct mono_scan_converter *c,
+			      const cairo_edge_t *edge)
+{
+    polygon_add_edge (c->polygon, edge);
+}
+
+static void
+step_edges (struct mono_scan_converter *c, int count)
+{
+    struct edge *edge;
+
+    for (edge = c->head.next; edge != &c->tail; edge = edge->next) {
+	edge->height_left -= count;
+	if (! edge->height_left) {
+	    edge->prev->next = edge->next;
+	    edge->next->prev = edge->prev;
+	}
+    }
+}
+
+static cairo_status_t
+mono_scan_converter_render(struct mono_scan_converter *c,
+			   unsigned int winding_mask,
+			   cairo_span_renderer_t *renderer)
+{
+    struct polygon *polygon = c->polygon;
+    int i, j, h = c->ymax - c->ymin;
+    cairo_status_t status;
+
+    for (i = 0; i < h; i = j) {
+	j = i + 1;
+
+	if (polygon->y_buckets[i])
+	    active_list_merge_edges (c, polygon->y_buckets[i]);
+
+	if (c->is_vertical) {
+	    int min_height;
+	    struct edge *e;
+
+	    e = c->head.next;
+	    min_height = e->height_left;
+	    while (e != &c->tail) {
+		if (e->height_left < min_height)
+		    min_height = e->height_left;
+		e = e->next;
+	    }
+
+	    while (min_height >= 2 && polygon->y_buckets[j] == NULL)
+		j++;
+	    if (j != i + 1)
+		step_edges (c, j - (i + 1));
+	}
+
+	row (c, winding_mask);
+	if (c->num_spans) {
+	    status = renderer->render_rows (renderer, c->ymin+i, j-i,
+					    c->spans, c->num_spans);
+	    if (unlikely (status))
+		return status;
+	}
+
+	/* XXX recompute after dropping edges? */
+	if (c->head.next == &c->tail)
+	    c->is_vertical = 1;
+    }
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+struct _cairo_mono_scan_converter {
+    cairo_scan_converter_t base;
+
+    struct mono_scan_converter converter[1];
+    cairo_fill_rule_t fill_rule;
+};
+
+typedef struct _cairo_mono_scan_converter cairo_mono_scan_converter_t;
+
+static void
+_cairo_mono_scan_converter_destroy (void *converter)
+{
+    cairo_mono_scan_converter_t *self = converter;
+    _mono_scan_converter_fini (self->converter);
+    free(self);
+}
+
+cairo_status_t
+_cairo_mono_scan_converter_add_polygon (void		*converter,
+				       const cairo_polygon_t *polygon)
+{
+    cairo_mono_scan_converter_t *self = converter;
+    cairo_status_t status;
+    int i;
+
+#if 0
+    FILE *file = fopen ("polygon.txt", "w");
+    _cairo_debug_print_polygon (file, polygon);
+    fclose (file);
+#endif
+
+    status = mono_scan_converter_allocate_edges (self->converter,
+						 polygon->num_edges);
+    if (unlikely (status))
+	return status;
+
+    for (i = 0; i < polygon->num_edges; i++)
+	 mono_scan_converter_add_edge (self->converter, &polygon->edges[i]);
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_mono_scan_converter_generate (void			*converter,
+				    cairo_span_renderer_t	*renderer)
+{
+    cairo_mono_scan_converter_t *self = converter;
+
+    return mono_scan_converter_render (self->converter,
+				       self->fill_rule == CAIRO_FILL_RULE_WINDING ? ~0 : 1,
+				       renderer);
+}
+
+cairo_scan_converter_t *
+_cairo_mono_scan_converter_create (int			xmin,
+				  int			ymin,
+				  int			xmax,
+				  int			ymax,
+				  cairo_fill_rule_t	fill_rule)
+{
+    cairo_mono_scan_converter_t *self;
+    cairo_status_t status;
+
+    self = malloc (sizeof(struct _cairo_mono_scan_converter));
+    if (unlikely (self == NULL)) {
+	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+	goto bail_nomem;
+    }
+
+    self->base.destroy = _cairo_mono_scan_converter_destroy;
+    self->base.generate = _cairo_mono_scan_converter_generate;
+
+    status = _mono_scan_converter_init (self->converter,
+					xmin, ymin, xmax, ymax);
+    if (unlikely (status))
+	goto bail;
+
+    self->fill_rule = fill_rule;
+
+    return &self->base;
+
+ bail:
+    self->base.destroy(&self->base);
+ bail_nomem:
+    return _cairo_scan_converter_create_in_error (status);
+}
diff --git a/src/cairo-no-compositor.c b/src/cairo-no-compositor.c
new file mode 100644
index 0000000..1602a12
--- /dev/null
+++ b/src/cairo-no-compositor.c
@@ -0,0 +1,107 @@
+/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
+/* 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>
+ *      Joonas Pihlaja <jpihlaja at cc.helsinki.fi>
+ *	Chris Wilson <chris at chris-wilson.co.uk>
+ */
+
+#include "cairoint.h"
+
+#include "cairo-compositor-private.h"
+
+static cairo_int_status_t
+_cairo_no_compositor_paint (const cairo_compositor_t *_compositor,
+			    cairo_composite_rectangles_t *extents)
+{
+    ASSERT_NOT_REACHED;
+    return CAIRO_INT_STATUS_NOTHING_TO_DO;
+}
+
+static cairo_int_status_t
+_cairo_no_compositor_mask (const cairo_compositor_t *compositor,
+			   cairo_composite_rectangles_t *extents)
+{
+    ASSERT_NOT_REACHED;
+    return CAIRO_INT_STATUS_NOTHING_TO_DO;
+}
+
+static cairo_int_status_t
+_cairo_no_compositor_stroke (const cairo_compositor_t *_compositor,
+			     cairo_composite_rectangles_t *extents,
+			     const cairo_path_fixed_t	*path,
+			     const cairo_stroke_style_t	*style,
+			     const cairo_matrix_t	*ctm,
+			     const cairo_matrix_t	*ctm_inverse,
+			     double		 tolerance,
+			     cairo_antialias_t	 antialias)
+{
+    ASSERT_NOT_REACHED;
+    return CAIRO_INT_STATUS_NOTHING_TO_DO;
+}
+
+static cairo_int_status_t
+_cairo_no_compositor_fill (const cairo_compositor_t *_compositor,
+			   cairo_composite_rectangles_t *extents,
+			   const cairo_path_fixed_t	*path,
+			   cairo_fill_rule_t	 fill_rule,
+			   double			 tolerance,
+			   cairo_antialias_t	 antialias)
+{
+    ASSERT_NOT_REACHED;
+    return CAIRO_INT_STATUS_NOTHING_TO_DO;
+}
+
+static cairo_int_status_t
+_cairo_no_compositor_glyphs (const cairo_compositor_t *compositor,
+			     cairo_composite_rectangles_t *extents,
+			     cairo_scaled_font_t	*scaled_font,
+			     cairo_glyph_t		*glyphs,
+			     int			 num_glyphs,
+			     cairo_bool_t overlap)
+{
+    ASSERT_NOT_REACHED;
+    return CAIRO_INT_STATUS_NOTHING_TO_DO;
+}
+
+const cairo_compositor_t __cairo_no_compositor = {
+    NULL,
+    _cairo_no_compositor_paint,
+    _cairo_no_compositor_mask,
+    _cairo_no_compositor_stroke,
+    _cairo_no_compositor_fill,
+    _cairo_no_compositor_glyphs,
+};
diff --git a/src/cairo-output-stream.c b/src/cairo-output-stream.c
index 0adda36..cc7e300 100644
--- a/src/cairo-output-stream.c
+++ b/src/cairo-output-stream.c
@@ -37,6 +37,8 @@
 #include "cairoint.h"
 
 #include "cairo-output-stream-private.h"
+
+#include "cairo-array-private.h"
 #include "cairo-error-private.h"
 #include "cairo-compiler-private.h"
 
diff --git a/src/cairo-paginated-surface.c b/src/cairo-paginated-surface.c
index d9c6c2f..0418e67 100644
--- a/src/cairo-paginated-surface.c
+++ b/src/cairo-paginated-surface.c
@@ -347,11 +347,10 @@ _paint_page (cairo_paginated_surface_t *surface)
 	                                  CAIRO_PAGINATED_MODE_ANALYZE);
     status = _cairo_recording_surface_replay_and_create_regions (surface->recording_surface,
 								 analysis);
-    if (status || analysis->status) {
-	if (status == CAIRO_INT_STATUS_SUCCESS)
-	    status = analysis->status;
+    if (status)
 	goto FAIL;
-    }
+
+    assert (analysis->status == CAIRO_STATUS_SUCCESS);
 
      if (surface->backend->set_bounding_box) {
 	 cairo_box_t bbox;
@@ -674,33 +673,23 @@ static const cairo_surface_backend_t cairo_paginated_surface_backend = {
 
     _cairo_paginated_surface_acquire_source_image,
     _cairo_paginated_surface_release_source_image,
-    NULL, /* acquire_dest_image */
-    NULL, /* release_dest_image */
-    NULL, /* clone_similar */
-    NULL, /* composite */
-    NULL, /* fill_rectangles */
-    NULL, /* composite_trapezoids */
-    NULL, /* create_span_renderer */
-    NULL, /* check_span_renderer */
+    _cairo_paginated_surface_snapshot,
+
     _cairo_paginated_surface_copy_page,
     _cairo_paginated_surface_show_page,
+
     _cairo_paginated_surface_get_extents,
-    NULL, /* old_show_glyphs */
     _cairo_paginated_surface_get_font_options,
+
     NULL, /* flush */
     NULL, /* mark_dirty_rectangle */
-    NULL, /* scaled_font_fini */
-    NULL, /* scaled_glyph_fini */
+
     _cairo_paginated_surface_paint,
     _cairo_paginated_surface_mask,
     _cairo_paginated_surface_stroke,
     _cairo_paginated_surface_fill,
-    NULL, /* show_glyphs */
-    _cairo_paginated_surface_snapshot,
-    NULL, /* is_similar */
     NULL, /* fill_stroke */
-    NULL, /* create_solid_pattern_surface */
-    NULL, /* can_repaint_solid_pattern_surface */
+    NULL, /* show_glyphs */
     _cairo_paginated_surface_has_show_text_glyphs,
     _cairo_paginated_surface_show_text_glyphs
 };
diff --git a/src/cairo-path-bounds.c b/src/cairo-path-bounds.c
index 1fc9a06..087a7d0 100644
--- a/src/cairo-path-bounds.c
+++ b/src/cairo-path-bounds.c
@@ -40,7 +40,6 @@
 #include "cairo-error-private.h"
 #include "cairo-path-fixed-private.h"
 
-
 typedef struct _cairo_path_bounder {
     cairo_point_t current_point;
     cairo_bool_t has_extents;
@@ -161,8 +160,9 @@ _cairo_path_fixed_approximate_stroke_extents (const cairo_path_fixed_t *path,
 	cairo_box_t box_extents;
 	double dx, dy;
 
+	_cairo_stroke_style_max_distance_from_path (style, path, ctm, &dx, &dy);
+
 	box_extents = path->extents;
-	_cairo_stroke_style_max_distance_from_path (style, ctm, &dx, &dy);
 	box_extents.p1.x -= _cairo_fixed_from_double (dx);
 	box_extents.p1.y -= _cairo_fixed_from_double (dy);
 	box_extents.p2.x += _cairo_fixed_from_double (dx);
@@ -183,23 +183,17 @@ _cairo_path_fixed_stroke_extents (const cairo_path_fixed_t	*path,
 				  double			 tolerance,
 				  cairo_rectangle_int_t		*extents)
 {
-    cairo_traps_t traps;
-    cairo_box_t bbox;
+    cairo_polygon_t polygon;
     cairo_status_t status;
 
-    _cairo_traps_init (&traps);
-
-    status = _cairo_path_fixed_stroke_to_traps (path,
-						stroke_style,
-						ctm,
-						ctm_inverse,
-						tolerance,
-						&traps);
-
-    _cairo_traps_extents (&traps, &bbox);
-    _cairo_traps_fini (&traps);
-
-    _cairo_box_round_to_rectangle (&bbox, extents);
+    _cairo_polygon_init (&polygon, NULL, 0);
+    status = _cairo_path_fixed_stroke_to_polygon (path,
+						  stroke_style,
+						  ctm, ctm_inverse,
+						  tolerance,
+						  &polygon);
+    _cairo_box_round_to_rectangle (&polygon.extents, extents);
+    _cairo_polygon_fini (&polygon);
 
     return status;
 }
diff --git a/src/cairo-path-fill.c b/src/cairo-path-fill.c
index ce4c86a..8339307 100644
--- a/src/cairo-path-fill.c
+++ b/src/cairo-path-fill.c
@@ -40,9 +40,14 @@
 #include "cairo-error-private.h"
 #include "cairo-path-fixed-private.h"
 #include "cairo-region-private.h"
+#include "cairo-traps-private.h"
 
 typedef struct cairo_filler {
     cairo_polygon_t *polygon;
+    double tolerance;
+
+    cairo_box_t limit;
+    cairo_bool_t has_limits;
 
     cairo_point_t current_point;
     cairo_point_t last_move_to;
@@ -86,13 +91,38 @@ _cairo_filler_move_to (void *closure,
     if (unlikely (status))
 	return status;
 
-    /* make sure that the closure represents a degenerate path */
+        /* make sure that the closure represents a degenerate path */
     filler->current_point = *point;
     filler->last_move_to = *point;
 
     return CAIRO_STATUS_SUCCESS;
 }
 
+static cairo_status_t
+_cairo_filler_curve_to (void		*closure,
+			const cairo_point_t	*p1,
+			const cairo_point_t	*p2,
+			const cairo_point_t	*p3)
+{
+    cairo_filler_t *filler = closure;
+    cairo_spline_t spline;
+
+    if (filler->has_limits) {
+	if (! _cairo_spline_intersects (&filler->current_point, p1, p2, p3,
+					&filler->limit))
+	    return _cairo_filler_line_to (filler, p3);
+    }
+
+    if (! _cairo_spline_init (&spline,
+			      (cairo_spline_add_point_func_t)_cairo_filler_line_to, filler,
+			      &filler->current_point, p1, p2, p3))
+    {
+	return _cairo_filler_line_to (closure, p3);
+    }
+
+    return _cairo_spline_decompose (&spline, filler->tolerance);
+}
+
 cairo_status_t
 _cairo_path_fixed_fill_to_polygon (const cairo_path_fixed_t *path,
 				   double tolerance,
@@ -102,18 +132,25 @@ _cairo_path_fixed_fill_to_polygon (const cairo_path_fixed_t *path,
     cairo_status_t status;
 
     filler.polygon = polygon;
+    filler.tolerance = tolerance;
+
+    filler.has_limits = FALSE;
+    if (polygon->num_limits) {
+	filler.has_limits = TRUE;
+	filler.limit = polygon->limit;
+    }
 
     /* make sure that the closure represents a degenerate path */
     filler.current_point.x = 0;
     filler.current_point.y = 0;
     filler.last_move_to = filler.current_point;
 
-    status = _cairo_path_fixed_interpret_flat (path,
-					       _cairo_filler_move_to,
-					       _cairo_filler_line_to,
-					       _cairo_filler_close,
-					       &filler,
-					       tolerance);
+    status = _cairo_path_fixed_interpret (path,
+					  _cairo_filler_move_to,
+					  _cairo_filler_line_to,
+					  _cairo_filler_curve_to,
+					  _cairo_filler_close,
+					  &filler);
     if (unlikely (status))
 	return status;
 
@@ -179,7 +216,7 @@ _cairo_path_fixed_fill_rectilinear_to_polygon (const cairo_path_fixed_t *path,
     cairo_status_t status;
 
     if (antialias != CAIRO_ANTIALIAS_NONE)
-	    return _cairo_path_fixed_fill_to_polygon (path, 0., polygon);
+	return _cairo_path_fixed_fill_to_polygon (path, 0., polygon);
 
     filler.polygon = polygon;
 
@@ -213,22 +250,12 @@ _cairo_path_fixed_fill_to_traps (const cairo_path_fixed_t *path,
 	return CAIRO_STATUS_SUCCESS;
 
     _cairo_polygon_init (&polygon, traps->limits, traps->num_limits);
-
-    status = _cairo_path_fixed_fill_to_polygon (path,
-						tolerance,
-						&polygon);
+    status = _cairo_path_fixed_fill_to_polygon (path, tolerance, &polygon);
     if (unlikely (status || polygon.num_edges == 0))
 	goto CLEANUP;
 
-    if (_cairo_path_fixed_fill_is_rectilinear (path)) {
-	status = _cairo_bentley_ottmann_tessellate_rectilinear_polygon (traps,
-									&polygon,
-									fill_rule);
-    } else {
-	status = _cairo_bentley_ottmann_tessellate_polygon (traps,
-							    &polygon,
-							    fill_rule);
-    }
+    status = _cairo_bentley_ottmann_tessellate_polygon (traps,
+							&polygon, fill_rule);
 
   CLEANUP:
     _cairo_polygon_fini (&polygon);
diff --git a/src/cairo-path-fixed-private.h b/src/cairo-path-fixed-private.h
index e24b1c7..9b7b403 100644
--- a/src/cairo-path-fixed-private.h
+++ b/src/cairo-path-fixed-private.h
@@ -182,4 +182,8 @@ _cairo_path_fixed_fill_maybe_region (const cairo_path_fixed_t *path)
 	   path->current_point.y == path->last_move_point.y;
 }
 
+cairo_private cairo_bool_t
+_cairo_path_fixed_is_stroke_box (const cairo_path_fixed_t *path,
+				 cairo_box_t *box);
+
 #endif /* CAIRO_PATH_FIXED_PRIVATE_H */
diff --git a/src/cairo-path-fixed.c b/src/cairo-path-fixed.c
index d67954f..c257d73 100644
--- a/src/cairo-path-fixed.c
+++ b/src/cairo-path-fixed.c
@@ -584,6 +584,18 @@ _cairo_path_fixed_curve_to (cairo_path_fixed_t	*path,
     cairo_status_t status;
     cairo_point_t point[3];
 
+    /* If this curves does not move, replace it with a line-to.
+     * This frequently happens with rounded-rectangles and r==0.
+    */
+    if (path->current_point.x == x2 && path->current_point.y == y2) {
+	if (x1 == x2 && x0 == x2 && y1 == y2 && y0 == y2)
+	    return _cairo_path_fixed_line_to (path, x2, y2);
+
+	/* We may want to check for the absence of a cusp, in which case
+	 * we can also replace the curve-to with a line-to.
+	 */
+    }
+
     /* make sure subpaths are started properly */
     if (! path->has_current_point) {
 	status = _cairo_path_fixed_move_to (path, x0, y0);
@@ -1270,6 +1282,51 @@ _cairo_path_fixed_is_box (const cairo_path_fixed_t *path,
     return FALSE;
 }
 
+cairo_bool_t
+_cairo_path_fixed_is_stroke_box (const cairo_path_fixed_t *path,
+				 cairo_box_t *box)
+{
+    const cairo_path_buf_t *buf = cairo_path_head (path);
+
+    if (! path->fill_is_rectilinear)
+	return FALSE;
+
+    /* Do we have the right number of ops? */
+    if (buf->num_ops != 5)
+	return FALSE;
+
+    /* Check whether the ops are those that would be used for a rectangle */
+    if (buf->op[0] != CAIRO_PATH_OP_MOVE_TO ||
+	buf->op[1] != CAIRO_PATH_OP_LINE_TO ||
+	buf->op[2] != CAIRO_PATH_OP_LINE_TO ||
+	buf->op[3] != CAIRO_PATH_OP_LINE_TO ||
+	buf->op[4] != CAIRO_PATH_OP_CLOSE_PATH)
+    {
+	return FALSE;
+    }
+
+    /* Ok, we may have a box, if the points line up */
+    if (buf->points[0].y == buf->points[1].y &&
+	buf->points[1].x == buf->points[2].x &&
+	buf->points[2].y == buf->points[3].y &&
+	buf->points[3].x == buf->points[0].x)
+    {
+	_canonical_box (box, &buf->points[0], &buf->points[2]);
+	return TRUE;
+    }
+
+    if (buf->points[0].x == buf->points[1].x &&
+	buf->points[1].y == buf->points[2].y &&
+	buf->points[2].x == buf->points[3].x &&
+	buf->points[3].y == buf->points[0].y)
+    {
+	_canonical_box (box, &buf->points[0], &buf->points[2]);
+	return TRUE;
+    }
+
+    return FALSE;
+}
+
 /*
  * Check whether the given path contains a single rectangle
  * that is logically equivalent to:
diff --git a/src/cairo-path-stroke-boxes.c b/src/cairo-path-stroke-boxes.c
index de3a628..794250b 100644
--- a/src/cairo-path-stroke-boxes.c
+++ b/src/cairo-path-stroke-boxes.c
@@ -234,29 +234,31 @@ _cairo_rectilinear_stroker_emit_segments (cairo_rectilinear_stroker_t *stroker)
 	}
 
 	/* Perform the adjustments of the endpoints. */
-	if (a->y == b->y) {
-	    if (a->x < b->x) {
-		if (lengthen_initial)
-		    a->x -= half_line_width;
-		if (lengthen_final)
-		    b->x += half_line_width;
-	    } else {
-		if (lengthen_initial)
-		    a->x += half_line_width;
-		if (lengthen_final)
-		    b->x -= half_line_width;
-	    }
-	} else {
-	    if (a->y < b->y) {
-		if (lengthen_initial)
-		    a->y -= half_line_width;
-		if (lengthen_final)
-		    b->y += half_line_width;
+	if (lengthen_initial | lengthen_final) {
+	    if (a->y == b->y) {
+		if (a->x < b->x) {
+		    if (lengthen_initial)
+			a->x -= half_line_width;
+		    if (lengthen_final)
+			b->x += half_line_width;
+		} else {
+		    if (lengthen_initial)
+			a->x += half_line_width;
+		    if (lengthen_final)
+			b->x -= half_line_width;
+		}
 	    } else {
-		if (lengthen_initial)
-		    a->y += half_line_width;
-		if (lengthen_final)
-		    b->y -= half_line_width;
+		if (a->y < b->y) {
+		    if (lengthen_initial)
+			a->y -= half_line_width;
+		    if (lengthen_final)
+			b->y += half_line_width;
+		} else {
+		    if (lengthen_initial)
+			a->y += half_line_width;
+		    if (lengthen_final)
+			b->y -= half_line_width;
+		}
 	    }
 	}
 
@@ -291,7 +293,6 @@ _cairo_rectilinear_stroker_emit_segments (cairo_rectilinear_stroker_t *stroker)
     }
 
     stroker->num_segments = 0;
-
     return CAIRO_STATUS_SUCCESS;
 }
 
@@ -606,6 +607,7 @@ _cairo_path_fixed_stroke_rectilinear_to_boxes (const cairo_path_fixed_t	*path,
 {
     cairo_rectilinear_stroker_t rectilinear_stroker;
     cairo_int_status_t status;
+    cairo_box_t box;
 
     assert (_cairo_path_fixed_stroke_is_rectilinear (path));
 
@@ -616,6 +618,46 @@ _cairo_path_fixed_stroke_rectilinear_to_boxes (const cairo_path_fixed_t	*path,
 	return CAIRO_INT_STATUS_UNSUPPORTED;
     }
 
+    if (! rectilinear_stroker.dash.dashed &&
+	_cairo_path_fixed_is_stroke_box (path, &box))
+    {
+	cairo_box_t b;
+
+	/* top */
+	b.p1.x = box.p1.x - rectilinear_stroker.half_line_width;
+	b.p2.x = box.p2.x + rectilinear_stroker.half_line_width;
+	b.p1.y = box.p1.y - rectilinear_stroker.half_line_width;
+	b.p2.y = box.p1.y + rectilinear_stroker.half_line_width;
+	status = _cairo_boxes_add (boxes, antialias, &b);
+	assert (status == CAIRO_INT_STATUS_SUCCESS);
+
+	/* left  (excluding top/bottom) */
+	b.p1.x = box.p1.x - rectilinear_stroker.half_line_width;
+	b.p2.x = box.p1.x + rectilinear_stroker.half_line_width;
+	b.p1.y = box.p1.y + rectilinear_stroker.half_line_width;
+	b.p2.y = box.p2.y - rectilinear_stroker.half_line_width;
+	status = _cairo_boxes_add (boxes, antialias, &b);
+	assert (status == CAIRO_INT_STATUS_SUCCESS);
+
+	/* right  (excluding top/bottom) */
+	b.p1.x = box.p2.x - rectilinear_stroker.half_line_width;
+	b.p2.x = box.p2.x + rectilinear_stroker.half_line_width;
+	b.p1.y = box.p1.y + rectilinear_stroker.half_line_width;
+	b.p2.y = box.p2.y - rectilinear_stroker.half_line_width;
+	status = _cairo_boxes_add (boxes, antialias, &b);
+	assert (status == CAIRO_INT_STATUS_SUCCESS);
+
+	/* bottom */
+	b.p1.x = box.p1.x - rectilinear_stroker.half_line_width;
+	b.p2.x = box.p2.x + rectilinear_stroker.half_line_width;
+	b.p1.y = box.p2.y - rectilinear_stroker.half_line_width;
+	b.p2.y = box.p2.y + rectilinear_stroker.half_line_width;
+	status = _cairo_boxes_add (boxes, antialias, &b);
+	assert (status == CAIRO_INT_STATUS_SUCCESS);
+
+	goto done;
+    }
+
     if (boxes->num_limits) {
 	_cairo_rectilinear_stroker_limit (&rectilinear_stroker,
 					  boxes->limits,
@@ -647,8 +689,8 @@ _cairo_path_fixed_stroke_rectilinear_to_boxes (const cairo_path_fixed_t	*path,
     if (unlikely (status))
 	goto BAIL;
 
+done:
     _cairo_rectilinear_stroker_fini (&rectilinear_stroker);
-
     return CAIRO_STATUS_SUCCESS;
 
 BAIL:
diff --git a/src/cairo-path-stroke-polygon.c b/src/cairo-path-stroke-polygon.c
index 3b8a67d..9128a00 100644
--- a/src/cairo-path-stroke-polygon.c
+++ b/src/cairo-path-stroke-polygon.c
@@ -104,6 +104,7 @@ within_tolerance (const cairo_point_t *p1,
 	      const cairo_point_t *p2,
 	      cairo_uint64_t tolerance)
 {
+    return FALSE;
     return _cairo_int64_lt (point_distance_sq (p1, p2), tolerance);
 }
 
@@ -115,6 +116,7 @@ contour_add_point (struct stroker *stroker,
     if (! within_tolerance (point, _cairo_contour_last_point (&c->contour),
 			stroker->contour_tolerance))
 	_cairo_contour_add_point (&c->contour, point);
+    //*_cairo_contour_last_point (&c->contour) = *point;
 }
 
 static void
@@ -789,7 +791,7 @@ outer_join (struct stroker *stroker,
 	     * Make sure the miter point line lies between the two
 	     * faces by comparing the slopes
 	     */
-	    if (1 || slope_compare_sgn (fdx1, fdy1, mdx, mdy) !=
+	    if (slope_compare_sgn (fdx1, fdy1, mdx, mdy) !=
 		slope_compare_sgn (fdx2, fdy2, mdx, mdy))
 	    {
 		cairo_point_t p;
@@ -1091,6 +1093,7 @@ line_to (void *closure,
     cairo_stroke_face_t start;
     cairo_point_t *p1 = &stroker->current_face.point;
     cairo_slope_t dev_slope;
+    int move_last = 0;
 
     stroker->has_initial_sub_path = TRUE;
 
@@ -1105,15 +1108,21 @@ line_to (void *closure,
     compute_face (p1, &dev_slope, stroker, &start);
 
     if (stroker->has_current_face) {
-	int clockwise = join_is_clockwise (&stroker->current_face, &start);
-	/* Join with final face from previous segment */
-	if (! within_tolerance (&stroker->current_face.ccw, &start.ccw,
-				stroker->contour_tolerance) ||
-	    ! within_tolerance (&stroker->current_face.cw, &start.cw,
-				stroker->contour_tolerance))
-	{
-	    outer_join (stroker, &stroker->current_face, &start, clockwise);
-	    inner_join (stroker, &stroker->current_face, &start, clockwise);
+	int clockwise = _cairo_slope_compare (&stroker->current_face.dev_vector,
+					      &start.dev_vector);
+	if (clockwise == 0) {
+	    move_last = 1;
+	} else {
+	    clockwise = clockwise < 0;
+	    /* Join with final face from previous segment */
+	    if (! within_tolerance (&stroker->current_face.ccw, &start.ccw,
+				    stroker->contour_tolerance) ||
+		! within_tolerance (&stroker->current_face.cw, &start.cw,
+				    stroker->contour_tolerance))
+	    {
+		outer_join (stroker, &stroker->current_face, &start, clockwise);
+		inner_join (stroker, &stroker->current_face, &start, clockwise);
+	    }
 	}
     } else {
 	if (! stroker->has_first_face) {
@@ -1134,8 +1143,13 @@ line_to (void *closure,
     stroker->current_face.cw.x += dev_slope.dx;
     stroker->current_face.cw.y += dev_slope.dy;
 
-    contour_add_point (stroker, &stroker->cw, &stroker->current_face.cw);
-    contour_add_point (stroker, &stroker->ccw, &stroker->current_face.ccw);
+    if (move_last) {
+	*_cairo_contour_last_point (&stroker->cw.contour) = stroker->current_face.cw;
+	*_cairo_contour_last_point (&stroker->ccw.contour) = stroker->current_face.ccw;
+    } else {
+	contour_add_point (stroker, &stroker->cw, &stroker->current_face.cw);
+	contour_add_point (stroker, &stroker->ccw, &stroker->current_face.ccw);
+    }
 
     return CAIRO_STATUS_SUCCESS;
 }
@@ -1187,6 +1201,37 @@ spline_to (void *closure,
     } else {
 	compute_face (point, tangent, stroker, &face);
 
+	if (face.dev_slope.x * stroker->current_face.dev_slope.x +
+	    face.dev_slope.y * stroker->current_face.dev_slope.y < 0)
+	{
+	    const cairo_point_t *inpt, *outpt;
+	    struct stroke_contour *outer;
+	    int clockwise = join_is_clockwise (&stroker->current_face, &face);
+
+	    stroker->current_face.cw.x += face.point.x - stroker->current_face.point.x;
+	    stroker->current_face.cw.y += face.point.y - stroker->current_face.point.y;
+	    contour_add_point (stroker, &stroker->cw, &stroker->current_face.cw);
+
+	    stroker->current_face.ccw.x += face.point.x - stroker->current_face.point.x;
+	    stroker->current_face.ccw.y += face.point.y - stroker->current_face.point.y;
+	    contour_add_point (stroker, &stroker->ccw, &stroker->current_face.ccw);
+
+	    if (clockwise) {
+		inpt = &stroker->current_face.cw;
+		outpt = &face.cw;
+		outer = &stroker->cw;
+	    } else {
+		inpt = &stroker->current_face.ccw;
+		outpt = &face.ccw;
+		outer = &stroker->ccw;
+	    }
+	    add_fan (stroker,
+		     &stroker->current_face.dev_vector,
+		     &face.dev_vector,
+		     &stroker->current_face.point, inpt, outpt,
+		     clockwise, outer);
+	}
+
 	contour_add_point (stroker, &stroker->cw, &face.cw);
 	contour_add_point (stroker, &stroker->ccw, &face.ccw);
     }
@@ -1328,6 +1373,8 @@ _cairo_path_fixed_stroke_to_polygon (const cairo_path_fixed_t	*path,
     stroker.has_initial_sub_path = FALSE;
 
 #if DEBUG
+    remove ("contours.txt");
+    remove ("polygons.txt");
     _cairo_contour_init (&stroker.path, 0);
 #endif
     _cairo_contour_init (&stroker.cw.contour, 1);
diff --git a/src/cairo-path-stroke-tristrip.c b/src/cairo-path-stroke-tristrip.c
new file mode 100644
index 0000000..337d814
--- /dev/null
+++ b/src/cairo-path-stroke-tristrip.c
@@ -0,0 +1,1088 @@
+/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2002 University of Southern California
+ * 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>
+ */
+
+#define _BSD_SOURCE /* for hypot() */
+#include "cairoint.h"
+
+#include "cairo-box-private.h"
+#include "cairo-boxes-private.h"
+#include "cairo-error-private.h"
+#include "cairo-path-fixed-private.h"
+#include "cairo-slope-private.h"
+#include "cairo-tristrip-private.h"
+
+struct stroker {
+    cairo_stroke_style_t style;
+
+    cairo_tristrip_t *strip;
+
+    const cairo_matrix_t *ctm;
+    const cairo_matrix_t *ctm_inverse;
+    double tolerance;
+    cairo_bool_t ctm_det_positive;
+
+    cairo_pen_t pen;
+
+    cairo_bool_t has_sub_path;
+
+    cairo_point_t first_point;
+
+    cairo_bool_t has_current_face;
+    cairo_stroke_face_t current_face;
+
+    cairo_bool_t has_first_face;
+    cairo_stroke_face_t first_face;
+
+    cairo_box_t limit;
+    cairo_bool_t has_limits;
+};
+
+static inline double
+normalize_slope (double *dx, double *dy);
+
+static void
+compute_face (const cairo_point_t *point,
+	      const cairo_slope_t *dev_slope,
+	      struct stroker *stroker,
+	      cairo_stroke_face_t *face);
+
+static void
+translate_point (cairo_point_t *point, const cairo_point_t *offset)
+{
+    point->x += offset->x;
+    point->y += offset->y;
+}
+
+static int
+slope_compare_sgn (double dx1, double dy1, double dx2, double dy2)
+{
+    double  c = (dx1 * dy2 - dx2 * dy1);
+
+    if (c > 0) return 1;
+    if (c < 0) return -1;
+    return 0;
+}
+
+static inline int
+range_step (int i, int step, int max)
+{
+    i += step;
+    if (i < 0)
+	i = max - 1;
+    if (i >= max)
+	i = 0;
+    return i;
+}
+
+/*
+ * Construct a fan around the midpoint using the vertices from pen between
+ * inpt and outpt.
+ */
+static void
+add_fan (struct stroker *stroker,
+	 const cairo_slope_t *in_vector,
+	 const cairo_slope_t *out_vector,
+	 const cairo_point_t *midpt,
+	 const cairo_point_t *inpt,
+	 const cairo_point_t *outpt,
+	 cairo_bool_t clockwise)
+{
+    int start, stop, step, i, npoints;
+
+    if (clockwise) {
+	step  = 1;
+
+	start = _cairo_pen_find_active_cw_vertex_index (&stroker->pen,
+							in_vector);
+	if (_cairo_slope_compare (&stroker->pen.vertices[start].slope_cw,
+				  in_vector) < 0)
+	    start = range_step (start, 1, stroker->pen.num_vertices);
+
+	stop  = _cairo_pen_find_active_cw_vertex_index (&stroker->pen,
+							out_vector);
+	if (_cairo_slope_compare (&stroker->pen.vertices[stop].slope_ccw,
+				  out_vector) > 0)
+	{
+	    stop = range_step (stop, -1, stroker->pen.num_vertices);
+	    if (_cairo_slope_compare (&stroker->pen.vertices[stop].slope_cw,
+				      in_vector) < 0)
+		return;
+	}
+
+	npoints = stop - start;
+    } else {
+	step  = -1;
+
+	start = _cairo_pen_find_active_ccw_vertex_index (&stroker->pen,
+							 in_vector);
+	if (_cairo_slope_compare (&stroker->pen.vertices[start].slope_ccw,
+				  in_vector) < 0)
+	    start = range_step (start, -1, stroker->pen.num_vertices);
+
+	stop  = _cairo_pen_find_active_ccw_vertex_index (&stroker->pen,
+							 out_vector);
+	if (_cairo_slope_compare (&stroker->pen.vertices[stop].slope_cw,
+				  out_vector) > 0)
+	{
+	    stop = range_step (stop, 1, stroker->pen.num_vertices);
+	    if (_cairo_slope_compare (&stroker->pen.vertices[stop].slope_ccw,
+				      in_vector) < 0)
+		return;
+	}
+
+	npoints = start - stop;
+    }
+    stop = range_step (stop, step, stroker->pen.num_vertices);
+    if (npoints < 0)
+	npoints += stroker->pen.num_vertices;
+    if (npoints <= 1)
+	return;
+
+    for (i = start;
+	 i != stop;
+	i = range_step (i, step, stroker->pen.num_vertices))
+    {
+	cairo_point_t p = *midpt;
+	translate_point (&p, &stroker->pen.vertices[i].point);
+	//contour_add_point (stroker, c, &p);
+    }
+}
+
+static int
+join_is_clockwise (const cairo_stroke_face_t *in,
+		   const cairo_stroke_face_t *out)
+{
+    return _cairo_slope_compare (&in->dev_vector, &out->dev_vector) < 0;
+}
+
+static void
+inner_join (struct stroker *stroker,
+	    const cairo_stroke_face_t *in,
+	    const cairo_stroke_face_t *out,
+	    int clockwise)
+{
+    const cairo_point_t *outpt;
+
+    if (clockwise) {
+	outpt = &out->ccw;
+    } else {
+	outpt = &out->cw;
+    }
+    //contour_add_point (stroker, inner, &in->point);
+    //contour_add_point (stroker, inner, outpt);
+}
+
+static void
+inner_close (struct stroker *stroker,
+	     const cairo_stroke_face_t *in,
+	     cairo_stroke_face_t *out)
+{
+    const cairo_point_t *inpt;
+
+    if (join_is_clockwise (in, out)) {
+	inpt = &out->ccw;
+    } else {
+	inpt = &out->cw;
+    }
+
+    //contour_add_point (stroker, inner, &in->point);
+    //contour_add_point (stroker, inner, inpt);
+    //*_cairo_contour_first_point (&inner->contour) =
+	//*_cairo_contour_last_point (&inner->contour);
+}
+
+static void
+outer_close (struct stroker *stroker,
+	     const cairo_stroke_face_t *in,
+	     const cairo_stroke_face_t *out)
+{
+    const cairo_point_t	*inpt, *outpt;
+    int	clockwise;
+
+    if (in->cw.x == out->cw.x && in->cw.y == out->cw.y &&
+	in->ccw.x == out->ccw.x && out->ccw.y == out->ccw.y)
+    {
+	return;
+    }
+    clockwise = join_is_clockwise (in, out);
+    if (clockwise) {
+	inpt = &in->cw;
+	outpt = &out->cw;
+    } else {
+	inpt = &in->ccw;
+	outpt = &out->ccw;
+    }
+
+    switch (stroker->style.line_join) {
+    case CAIRO_LINE_JOIN_ROUND:
+	/* construct a fan around the common midpoint */
+	add_fan (stroker,
+		 &in->dev_vector,
+		 &out->dev_vector,
+		 &in->point, inpt, outpt,
+		 clockwise);
+	break;
+
+    case CAIRO_LINE_JOIN_MITER:
+    default: {
+	/* dot product of incoming slope vector with outgoing slope vector */
+	double	in_dot_out = -in->usr_vector.x * out->usr_vector.x +
+			     -in->usr_vector.y * out->usr_vector.y;
+	double	ml = stroker->style.miter_limit;
+
+	/* Check the miter limit -- lines meeting at an acute angle
+	 * can generate long miters, the limit converts them to bevel
+	 *
+	 * Consider the miter join formed when two line segments
+	 * meet at an angle psi:
+	 *
+	 *	   /.\
+	 *	  /. .\
+	 *	 /./ \.\
+	 *	/./psi\.\
+	 *
+	 * We can zoom in on the right half of that to see:
+	 *
+	 *	    |\
+	 *	    | \ psi/2
+	 *	    |  \
+	 *	    |   \
+	 *	    |    \
+	 *	    |     \
+	 *	  miter    \
+	 *	 length     \
+	 *	    |        \
+	 *	    |        .\
+	 *	    |    .     \
+	 *	    |.   line   \
+	 *	     \    width  \
+	 *	      \           \
+	 *
+	 *
+	 * The right triangle in that figure, (the line-width side is
+	 * shown faintly with three '.' characters), gives us the
+	 * following expression relating miter length, angle and line
+	 * width:
+	 *
+	 *	1 /sin (psi/2) = miter_length / line_width
+	 *
+	 * The right-hand side of this relationship is the same ratio
+	 * in which the miter limit (ml) is expressed. We want to know
+	 * when the miter length is within the miter limit. That is
+	 * when the following condition holds:
+	 *
+	 *	1/sin(psi/2) <= ml
+	 *	1 <= ml sin(psi/2)
+	 *	1 <= ml² sin²(psi/2)
+	 *	2 <= ml² 2 sin²(psi/2)
+	 *				2·sin²(psi/2) = 1-cos(psi)
+	 *	2 <= ml² (1-cos(psi))
+	 *
+	 *				in · out = |in| |out| cos (psi)
+	 *
+	 * in and out are both unit vectors, so:
+	 *
+	 *				in · out = cos (psi)
+	 *
+	 *	2 <= ml² (1 - in · out)
+	 *
+	 */
+	if (2 <= ml * ml * (1 - in_dot_out)) {
+	    double		x1, y1, x2, y2;
+	    double		mx, my;
+	    double		dx1, dx2, dy1, dy2;
+	    double		ix, iy;
+	    double		fdx1, fdy1, fdx2, fdy2;
+	    double		mdx, mdy;
+
+	    /*
+	     * we've got the points already transformed to device
+	     * space, but need to do some computation with them and
+	     * also need to transform the slope from user space to
+	     * device space
+	     */
+	    /* outer point of incoming line face */
+	    x1 = _cairo_fixed_to_double (inpt->x);
+	    y1 = _cairo_fixed_to_double (inpt->y);
+	    dx1 = in->usr_vector.x;
+	    dy1 = in->usr_vector.y;
+	    cairo_matrix_transform_distance (stroker->ctm, &dx1, &dy1);
+
+	    /* outer point of outgoing line face */
+	    x2 = _cairo_fixed_to_double (outpt->x);
+	    y2 = _cairo_fixed_to_double (outpt->y);
+	    dx2 = out->usr_vector.x;
+	    dy2 = out->usr_vector.y;
+	    cairo_matrix_transform_distance (stroker->ctm, &dx2, &dy2);
+
+	    /*
+	     * Compute the location of the outer corner of the miter.
+	     * That's pretty easy -- just the intersection of the two
+	     * outer edges.  We've got slopes and points on each
+	     * of those edges.  Compute my directly, then compute
+	     * mx by using the edge with the larger dy; that avoids
+	     * dividing by values close to zero.
+	     */
+	    my = (((x2 - x1) * dy1 * dy2 - y2 * dx2 * dy1 + y1 * dx1 * dy2) /
+		  (dx1 * dy2 - dx2 * dy1));
+	    if (fabs (dy1) >= fabs (dy2))
+		mx = (my - y1) * dx1 / dy1 + x1;
+	    else
+		mx = (my - y2) * dx2 / dy2 + x2;
+
+	    /*
+	     * When the two outer edges are nearly parallel, slight
+	     * perturbations in the position of the outer points of the lines
+	     * caused by representing them in fixed point form can cause the
+	     * intersection point of the miter to move a large amount. If
+	     * that moves the miter intersection from between the two faces,
+	     * then draw a bevel instead.
+	     */
+
+	    ix = _cairo_fixed_to_double (in->point.x);
+	    iy = _cairo_fixed_to_double (in->point.y);
+
+	    /* slope of one face */
+	    fdx1 = x1 - ix; fdy1 = y1 - iy;
+
+	    /* slope of the other face */
+	    fdx2 = x2 - ix; fdy2 = y2 - iy;
+
+	    /* slope from the intersection to the miter point */
+	    mdx = mx - ix; mdy = my - iy;
+
+	    /*
+	     * Make sure the miter point line lies between the two
+	     * faces by comparing the slopes
+	     */
+	    if (slope_compare_sgn (fdx1, fdy1, mdx, mdy) !=
+		slope_compare_sgn (fdx2, fdy2, mdx, mdy))
+	    {
+		cairo_point_t p;
+
+		p.x = _cairo_fixed_from_double (mx);
+		p.y = _cairo_fixed_from_double (my);
+
+		//*_cairo_contour_last_point (&outer->contour) = p;
+		//*_cairo_contour_first_point (&outer->contour) = p;
+		return;
+	    }
+	}
+	break;
+    }
+
+    case CAIRO_LINE_JOIN_BEVEL:
+	break;
+    }
+    //contour_add_point (stroker, outer, outpt);
+}
+
+static void
+outer_join (struct stroker *stroker,
+	    const cairo_stroke_face_t *in,
+	    const cairo_stroke_face_t *out,
+	    int clockwise)
+{
+    const cairo_point_t	*inpt, *outpt;
+
+    if (in->cw.x == out->cw.x && in->cw.y == out->cw.y &&
+	in->ccw.x == out->ccw.x && out->ccw.y == out->ccw.y)
+    {
+	return;
+    }
+    if (clockwise) {
+	inpt = &in->cw;
+	outpt = &out->cw;
+    } else {
+	inpt = &in->ccw;
+	outpt = &out->ccw;
+    }
+
+    switch (stroker->style.line_join) {
+    case CAIRO_LINE_JOIN_ROUND:
+	/* construct a fan around the common midpoint */
+	add_fan (stroker,
+		 &in->dev_vector,
+		 &out->dev_vector,
+		 &in->point, inpt, outpt,
+		 clockwise);
+	break;
+
+    case CAIRO_LINE_JOIN_MITER:
+    default: {
+	/* dot product of incoming slope vector with outgoing slope vector */
+	double	in_dot_out = -in->usr_vector.x * out->usr_vector.x +
+			     -in->usr_vector.y * out->usr_vector.y;
+	double	ml = stroker->style.miter_limit;
+
+	/* Check the miter limit -- lines meeting at an acute angle
+	 * can generate long miters, the limit converts them to bevel
+	 *
+	 * Consider the miter join formed when two line segments
+	 * meet at an angle psi:
+	 *
+	 *	   /.\
+	 *	  /. .\
+	 *	 /./ \.\
+	 *	/./psi\.\
+	 *
+	 * We can zoom in on the right half of that to see:
+	 *
+	 *	    |\
+	 *	    | \ psi/2
+	 *	    |  \
+	 *	    |   \
+	 *	    |    \
+	 *	    |     \
+	 *	  miter    \
+	 *	 length     \
+	 *	    |        \
+	 *	    |        .\
+	 *	    |    .     \
+	 *	    |.   line   \
+	 *	     \    width  \
+	 *	      \           \
+	 *
+	 *
+	 * The right triangle in that figure, (the line-width side is
+	 * shown faintly with three '.' characters), gives us the
+	 * following expression relating miter length, angle and line
+	 * width:
+	 *
+	 *	1 /sin (psi/2) = miter_length / line_width
+	 *
+	 * The right-hand side of this relationship is the same ratio
+	 * in which the miter limit (ml) is expressed. We want to know
+	 * when the miter length is within the miter limit. That is
+	 * when the following condition holds:
+	 *
+	 *	1/sin(psi/2) <= ml
+	 *	1 <= ml sin(psi/2)
+	 *	1 <= ml² sin²(psi/2)
+	 *	2 <= ml² 2 sin²(psi/2)
+	 *				2·sin²(psi/2) = 1-cos(psi)
+	 *	2 <= ml² (1-cos(psi))
+	 *
+	 *				in · out = |in| |out| cos (psi)
+	 *
+	 * in and out are both unit vectors, so:
+	 *
+	 *				in · out = cos (psi)
+	 *
+	 *	2 <= ml² (1 - in · out)
+	 *
+	 */
+	if (2 <= ml * ml * (1 - in_dot_out)) {
+	    double		x1, y1, x2, y2;
+	    double		mx, my;
+	    double		dx1, dx2, dy1, dy2;
+	    double		ix, iy;
+	    double		fdx1, fdy1, fdx2, fdy2;
+	    double		mdx, mdy;
+
+	    /*
+	     * we've got the points already transformed to device
+	     * space, but need to do some computation with them and
+	     * also need to transform the slope from user space to
+	     * device space
+	     */
+	    /* outer point of incoming line face */
+	    x1 = _cairo_fixed_to_double (inpt->x);
+	    y1 = _cairo_fixed_to_double (inpt->y);
+	    dx1 = in->usr_vector.x;
+	    dy1 = in->usr_vector.y;
+	    cairo_matrix_transform_distance (stroker->ctm, &dx1, &dy1);
+
+	    /* outer point of outgoing line face */
+	    x2 = _cairo_fixed_to_double (outpt->x);
+	    y2 = _cairo_fixed_to_double (outpt->y);
+	    dx2 = out->usr_vector.x;
+	    dy2 = out->usr_vector.y;
+	    cairo_matrix_transform_distance (stroker->ctm, &dx2, &dy2);
+
+	    /*
+	     * Compute the location of the outer corner of the miter.
+	     * That's pretty easy -- just the intersection of the two
+	     * outer edges.  We've got slopes and points on each
+	     * of those edges.  Compute my directly, then compute
+	     * mx by using the edge with the larger dy; that avoids
+	     * dividing by values close to zero.
+	     */
+	    my = (((x2 - x1) * dy1 * dy2 - y2 * dx2 * dy1 + y1 * dx1 * dy2) /
+		  (dx1 * dy2 - dx2 * dy1));
+	    if (fabs (dy1) >= fabs (dy2))
+		mx = (my - y1) * dx1 / dy1 + x1;
+	    else
+		mx = (my - y2) * dx2 / dy2 + x2;
+
+	    /*
+	     * When the two outer edges are nearly parallel, slight
+	     * perturbations in the position of the outer points of the lines
+	     * caused by representing them in fixed point form can cause the
+	     * intersection point of the miter to move a large amount. If
+	     * that moves the miter intersection from between the two faces,
+	     * then draw a bevel instead.
+	     */
+
+	    ix = _cairo_fixed_to_double (in->point.x);
+	    iy = _cairo_fixed_to_double (in->point.y);
+
+	    /* slope of one face */
+	    fdx1 = x1 - ix; fdy1 = y1 - iy;
+
+	    /* slope of the other face */
+	    fdx2 = x2 - ix; fdy2 = y2 - iy;
+
+	    /* slope from the intersection to the miter point */
+	    mdx = mx - ix; mdy = my - iy;
+
+	    /*
+	     * Make sure the miter point line lies between the two
+	     * faces by comparing the slopes
+	     */
+	    if (slope_compare_sgn (fdx1, fdy1, mdx, mdy) !=
+		slope_compare_sgn (fdx2, fdy2, mdx, mdy))
+	    {
+		cairo_point_t p;
+
+		p.x = _cairo_fixed_from_double (mx);
+		p.y = _cairo_fixed_from_double (my);
+
+		//*_cairo_contour_last_point (&outer->contour) = p;
+		return;
+	    }
+	}
+	break;
+    }
+
+    case CAIRO_LINE_JOIN_BEVEL:
+	break;
+    }
+    //contour_add_point (stroker,outer, outpt);
+}
+
+static void
+add_cap (struct stroker *stroker,
+	 const cairo_stroke_face_t *f)
+{
+    switch (stroker->style.line_cap) {
+    case CAIRO_LINE_CAP_ROUND: {
+	cairo_slope_t slope;
+
+	slope.dx = -f->dev_vector.dx;
+	slope.dy = -f->dev_vector.dy;
+
+	add_fan (stroker, &f->dev_vector, &slope,
+		 &f->point, &f->ccw, &f->cw,
+		 FALSE);
+	break;
+    }
+
+    case CAIRO_LINE_CAP_SQUARE: {
+	double dx, dy;
+	cairo_slope_t	fvector;
+	cairo_point_t	quad[4];
+
+	dx = f->usr_vector.x;
+	dy = f->usr_vector.y;
+	dx *= stroker->style.line_width / 2.0;
+	dy *= stroker->style.line_width / 2.0;
+	cairo_matrix_transform_distance (stroker->ctm, &dx, &dy);
+	fvector.dx = _cairo_fixed_from_double (dx);
+	fvector.dy = _cairo_fixed_from_double (dy);
+
+	quad[0] = f->ccw;
+	quad[1].x = f->ccw.x + fvector.dx;
+	quad[1].y = f->ccw.y + fvector.dy;
+	quad[2].x = f->cw.x + fvector.dx;
+	quad[2].y = f->cw.y + fvector.dy;
+	quad[3] = f->cw;
+
+	//contour_add_point (stroker, c, &quad[1]);
+	//contour_add_point (stroker, c, &quad[2]);
+    }
+
+    case CAIRO_LINE_CAP_BUTT:
+    default:
+	break;
+    }
+    //contour_add_point (stroker, c, &f->cw);
+}
+
+static void
+add_leading_cap (struct stroker *stroker,
+		 const cairo_stroke_face_t *face)
+{
+    cairo_stroke_face_t reversed;
+    cairo_point_t t;
+
+    reversed = *face;
+
+    /* The initial cap needs an outward facing vector. Reverse everything */
+    reversed.usr_vector.x = -reversed.usr_vector.x;
+    reversed.usr_vector.y = -reversed.usr_vector.y;
+    reversed.dev_vector.dx = -reversed.dev_vector.dx;
+    reversed.dev_vector.dy = -reversed.dev_vector.dy;
+
+    t = reversed.cw;
+    reversed.cw = reversed.ccw;
+    reversed.ccw = t;
+
+    add_cap (stroker, &reversed);
+}
+
+static void
+add_trailing_cap (struct stroker *stroker,
+		  const cairo_stroke_face_t *face)
+{
+    add_cap (stroker, face);
+}
+
+static inline double
+normalize_slope (double *dx, double *dy)
+{
+    double dx0 = *dx, dy0 = *dy;
+    double mag;
+
+    assert (dx0 != 0.0 || dy0 != 0.0);
+
+    if (dx0 == 0.0) {
+	*dx = 0.0;
+	if (dy0 > 0.0) {
+	    mag = dy0;
+	    *dy = 1.0;
+	} else {
+	    mag = -dy0;
+	    *dy = -1.0;
+	}
+    } else if (dy0 == 0.0) {
+	*dy = 0.0;
+	if (dx0 > 0.0) {
+	    mag = dx0;
+	    *dx = 1.0;
+	} else {
+	    mag = -dx0;
+	    *dx = -1.0;
+	}
+    } else {
+	mag = hypot (dx0, dy0);
+	*dx = dx0 / mag;
+	*dy = dy0 / mag;
+    }
+
+    return mag;
+}
+
+static void
+compute_face (const cairo_point_t *point,
+	      const cairo_slope_t *dev_slope,
+	      struct stroker *stroker,
+	      cairo_stroke_face_t *face)
+{
+    double face_dx, face_dy;
+    cairo_point_t offset_ccw, offset_cw;
+    double slope_dx, slope_dy;
+
+    slope_dx = _cairo_fixed_to_double (dev_slope->dx);
+    slope_dy = _cairo_fixed_to_double (dev_slope->dy);
+    face->length = normalize_slope (&slope_dx, &slope_dy);
+    face->dev_slope.x = slope_dx;
+    face->dev_slope.y = slope_dy;
+
+    /*
+     * rotate to get a line_width/2 vector along the face, note that
+     * the vector must be rotated the right direction in device space,
+     * but by 90° in user space. So, the rotation depends on
+     * whether the ctm reflects or not, and that can be determined
+     * by looking at the determinant of the matrix.
+     */
+    if (! _cairo_matrix_is_identity (stroker->ctm_inverse)) {
+	/* Normalize the matrix! */
+	cairo_matrix_transform_distance (stroker->ctm_inverse,
+					 &slope_dx, &slope_dy);
+	normalize_slope (&slope_dx, &slope_dy);
+
+	if (stroker->ctm_det_positive) {
+	    face_dx = - slope_dy * (stroker->style.line_width / 2.0);
+	    face_dy = slope_dx * (stroker->style.line_width / 2.0);
+	} else {
+	    face_dx = slope_dy * (stroker->style.line_width / 2.0);
+	    face_dy = - slope_dx * (stroker->style.line_width / 2.0);
+	}
+
+	/* back to device space */
+	cairo_matrix_transform_distance (stroker->ctm, &face_dx, &face_dy);
+    } else {
+	face_dx = - slope_dy * (stroker->style.line_width / 2.0);
+	face_dy = slope_dx * (stroker->style.line_width / 2.0);
+    }
+
+    offset_ccw.x = _cairo_fixed_from_double (face_dx);
+    offset_ccw.y = _cairo_fixed_from_double (face_dy);
+    offset_cw.x = -offset_ccw.x;
+    offset_cw.y = -offset_ccw.y;
+
+    face->ccw = *point;
+    translate_point (&face->ccw, &offset_ccw);
+
+    face->point = *point;
+
+    face->cw = *point;
+    translate_point (&face->cw, &offset_cw);
+
+    face->usr_vector.x = slope_dx;
+    face->usr_vector.y = slope_dy;
+
+    face->dev_vector = *dev_slope;
+}
+
+static void
+add_caps (struct stroker *stroker)
+{
+    /* check for a degenerative sub_path */
+    if (stroker->has_sub_path &&
+	! stroker->has_first_face &&
+	! stroker->has_current_face &&
+	stroker->style.line_cap == CAIRO_LINE_CAP_ROUND)
+    {
+	/* pick an arbitrary slope to use */
+	cairo_slope_t slope = { CAIRO_FIXED_ONE, 0 };
+	cairo_stroke_face_t face;
+
+	/* arbitrarily choose first_point */
+	compute_face (&stroker->first_point, &slope, stroker, &face);
+
+	add_leading_cap (stroker, &face);
+	add_trailing_cap (stroker, &face);
+
+	/* ensure the circle is complete */
+	//_cairo_contour_add_point (&stroker->ccw.contour,
+				  //_cairo_contour_first_point (&stroker->ccw.contour));
+    } else {
+	if (stroker->has_current_face)
+	    add_trailing_cap (stroker, &stroker->current_face);
+
+	//_cairo_polygon_add_contour (stroker->polygon, &stroker->ccw.contour);
+	//_cairo_contour_reset (&stroker->ccw.contour);
+
+	if (stroker->has_first_face) {
+	    //_cairo_contour_add_point (&stroker->ccw.contour,
+				      //&stroker->first_face.cw);
+	    add_leading_cap (stroker, &stroker->first_face);
+	    //_cairo_polygon_add_contour (stroker->polygon,
+					//&stroker->ccw.contour);
+	    //_cairo_contour_reset (&stroker->ccw.contour);
+	}
+    }
+}
+
+static cairo_status_t
+move_to (void *closure,
+	 const cairo_point_t *point)
+{
+    struct stroker *stroker = closure;
+
+    /* Cap the start and end of the previous sub path as needed */
+    add_caps (stroker);
+
+    stroker->has_first_face = FALSE;
+    stroker->has_current_face = FALSE;
+    stroker->has_sub_path = FALSE;
+
+    stroker->first_point = *point;
+
+    stroker->current_face.point = *point;
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+line_to (void *closure,
+	 const cairo_point_t *point)
+{
+    struct stroker *stroker = closure;
+    cairo_stroke_face_t start;
+    cairo_point_t *p1 = &stroker->current_face.point;
+    cairo_slope_t dev_slope;
+
+    stroker->has_sub_path = TRUE;
+
+    if (p1->x == point->x && p1->y == point->y)
+	return CAIRO_STATUS_SUCCESS;
+
+    _cairo_slope_init (&dev_slope, p1, point);
+    compute_face (p1, &dev_slope, stroker, &start);
+
+    if (stroker->has_current_face) {
+	int clockwise = join_is_clockwise (&stroker->current_face, &start);
+	/* Join with final face from previous segment */
+	outer_join (stroker, &stroker->current_face, &start, clockwise);
+	inner_join (stroker, &stroker->current_face, &start, clockwise);
+    } else {
+	if (! stroker->has_first_face) {
+	    /* Save sub path's first face in case needed for closing join */
+	    stroker->first_face = start;
+	    _cairo_tristrip_move_to (stroker->strip, &start.cw);
+	    stroker->has_first_face = TRUE;
+	}
+	stroker->has_current_face = TRUE;
+
+	_cairo_tristrip_add_point (stroker->strip, &start.cw);
+	_cairo_tristrip_add_point (stroker->strip, &start.ccw);
+    }
+
+    stroker->current_face = start;
+    stroker->current_face.point = *point;
+    stroker->current_face.ccw.x += dev_slope.dx;
+    stroker->current_face.ccw.y += dev_slope.dy;
+    stroker->current_face.cw.x += dev_slope.dx;
+    stroker->current_face.cw.y += dev_slope.dy;
+
+    _cairo_tristrip_add_point (stroker->strip, &stroker->current_face.cw);
+    _cairo_tristrip_add_point (stroker->strip, &stroker->current_face.ccw);
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+spline_to (void *closure,
+	   const cairo_point_t *point,
+	   const cairo_slope_t *tangent)
+{
+    struct stroker *stroker = closure;
+    cairo_stroke_face_t face;
+
+    if (tangent->dx == 0 && tangent->dy == 0) {
+	const cairo_point_t *inpt, *outpt;
+	cairo_point_t t;
+	int clockwise;
+
+	face = stroker->current_face;
+
+	face.usr_vector.x = -face.usr_vector.x;
+	face.usr_vector.y = -face.usr_vector.y;
+	face.dev_vector.dx = -face.dev_vector.dx;
+	face.dev_vector.dy = -face.dev_vector.dy;
+
+	t = face.cw;
+	face.cw = face.ccw;
+	face.ccw = t;
+
+	clockwise = join_is_clockwise (&stroker->current_face, &face);
+	if (clockwise) {
+	    inpt = &stroker->current_face.cw;
+	    outpt = &face.cw;
+	} else {
+	    inpt = &stroker->current_face.ccw;
+	    outpt = &face.ccw;
+	}
+
+	add_fan (stroker,
+		 &stroker->current_face.dev_vector,
+		 &face.dev_vector,
+		 &stroker->current_face.point, inpt, outpt,
+		 clockwise);
+    } else {
+	compute_face (point, tangent, stroker, &face);
+
+	if (face.dev_slope.x * stroker->current_face.dev_slope.x +
+	    face.dev_slope.y * stroker->current_face.dev_slope.y < 0)
+	{
+	    const cairo_point_t *inpt, *outpt;
+	    int clockwise = join_is_clockwise (&stroker->current_face, &face);
+
+	    stroker->current_face.cw.x += face.point.x - stroker->current_face.point.x;
+	    stroker->current_face.cw.y += face.point.y - stroker->current_face.point.y;
+	    //contour_add_point (stroker, &stroker->cw, &stroker->current_face.cw);
+
+	    stroker->current_face.ccw.x += face.point.x - stroker->current_face.point.x;
+	    stroker->current_face.ccw.y += face.point.y - stroker->current_face.point.y;
+	    //contour_add_point (stroker, &stroker->ccw, &stroker->current_face.ccw);
+
+	    if (clockwise) {
+		inpt = &stroker->current_face.cw;
+		outpt = &face.cw;
+	    } else {
+		inpt = &stroker->current_face.ccw;
+		outpt = &face.ccw;
+	    }
+	    add_fan (stroker,
+		     &stroker->current_face.dev_vector,
+		     &face.dev_vector,
+		     &stroker->current_face.point, inpt, outpt,
+		     clockwise);
+	}
+
+	_cairo_tristrip_add_point (stroker->strip, &face.cw);
+	_cairo_tristrip_add_point (stroker->strip, &face.ccw);
+    }
+
+    stroker->current_face = face;
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+curve_to (void *closure,
+	  const cairo_point_t *b,
+	  const cairo_point_t *c,
+	  const cairo_point_t *d)
+{
+    struct stroker *stroker = closure;
+    cairo_spline_t spline;
+    cairo_stroke_face_t face;
+
+    if (stroker->has_limits) {
+	if (! _cairo_spline_intersects (&stroker->current_face.point, b, c, d,
+					&stroker->limit))
+	    return line_to (closure, d);
+    }
+
+    if (! _cairo_spline_init (&spline, spline_to, stroker,
+			      &stroker->current_face.point, b, c, d))
+	return line_to (closure, d);
+
+    compute_face (&stroker->current_face.point, &spline.initial_slope,
+		  stroker, &face);
+
+    if (stroker->has_current_face) {
+	int clockwise = join_is_clockwise (&stroker->current_face, &face);
+	/* Join with final face from previous segment */
+	outer_join (stroker, &stroker->current_face, &face, clockwise);
+	inner_join (stroker, &stroker->current_face, &face, clockwise);
+    } else {
+	if (! stroker->has_first_face) {
+	    /* Save sub path's first face in case needed for closing join */
+	    stroker->first_face = face;
+	    _cairo_tristrip_move_to (stroker->strip, &face.cw);
+	    stroker->has_first_face = TRUE;
+	}
+	stroker->has_current_face = TRUE;
+
+	_cairo_tristrip_add_point (stroker->strip, &face.cw);
+	_cairo_tristrip_add_point (stroker->strip, &face.ccw);
+    }
+    stroker->current_face = face;
+
+    return _cairo_spline_decompose (&spline, stroker->tolerance);
+}
+
+static cairo_status_t
+close_path (void *closure)
+{
+    struct stroker *stroker = closure;
+    cairo_status_t status;
+
+    status = line_to (stroker, &stroker->first_point);
+    if (unlikely (status))
+	return status;
+
+    if (stroker->has_first_face && stroker->has_current_face) {
+	/* Join first and final faces of sub path */
+	outer_close (stroker, &stroker->current_face, &stroker->first_face);
+	inner_close (stroker, &stroker->current_face, &stroker->first_face);
+    } else {
+	/* Cap the start and end of the sub path as needed */
+	add_caps (stroker);
+    }
+
+    stroker->has_sub_path = FALSE;
+    stroker->has_first_face = FALSE;
+    stroker->has_current_face = FALSE;
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+cairo_int_status_t
+_cairo_path_fixed_stroke_to_tristrip (const cairo_path_fixed_t	*path,
+				      const cairo_stroke_style_t*style,
+				      const cairo_matrix_t	*ctm,
+				      const cairo_matrix_t	*ctm_inverse,
+				      double			 tolerance,
+				      cairo_tristrip_t		 *strip)
+{
+    struct stroker stroker;
+    cairo_int_status_t status;
+    int i;
+
+    if (style->num_dashes)
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+
+    stroker.style = *style;
+    stroker.ctm = ctm;
+    stroker.ctm_inverse = ctm_inverse;
+    stroker.tolerance = tolerance;
+
+    stroker.ctm_det_positive =
+	_cairo_matrix_compute_determinant (ctm) >= 0.0;
+
+    status = _cairo_pen_init (&stroker.pen,
+		              style->line_width / 2.0,
+			      tolerance, ctm);
+    if (unlikely (status))
+	return status;
+
+    if (stroker.pen.num_vertices <= 1)
+	return CAIRO_INT_STATUS_NOTHING_TO_DO;
+
+    stroker.has_current_face = FALSE;
+    stroker.has_first_face = FALSE;
+    stroker.has_sub_path = FALSE;
+
+    stroker.has_limits = strip->num_limits > 0;
+    stroker.limit = strip->limits[0];
+    for (i = 1; i < strip->num_limits; i++)
+	_cairo_box_add_box (&stroker.limit, &strip->limits[i]);
+
+    stroker.strip = strip;
+
+    status = _cairo_path_fixed_interpret (path,
+					  move_to,
+					  line_to,
+					  curve_to,
+					  close_path,
+					  &stroker);
+    /* Cap the start and end of the final sub path as needed */
+    if (likely (status == CAIRO_INT_STATUS_SUCCESS))
+	add_caps (&stroker);
+
+    _cairo_pen_fini (&stroker.pen);
+
+    return status;
+}
diff --git a/src/cairo-path-stroke.c b/src/cairo-path-stroke.c
index c438291..f25cfe4 100644
--- a/src/cairo-path-stroke.c
+++ b/src/cairo-path-stroke.c
@@ -45,6 +45,7 @@
 #include "cairo-path-fixed-private.h"
 #include "cairo-slope-private.h"
 #include "cairo-stroke-dash-private.h"
+#include "cairo-traps-private.h"
 
 typedef struct cairo_stroker {
     cairo_stroke_style_t style;
@@ -125,6 +126,7 @@ _cairo_stroker_init (cairo_stroker_t		*stroker,
 
 static void
 _cairo_stroker_limit (cairo_stroker_t *stroker,
+		      const cairo_path_fixed_t *path,
 		      const cairo_box_t *boxes,
 		      int num_boxes)
 {
@@ -139,8 +141,8 @@ _cairo_stroker_limit (cairo_stroker_t *stroker,
      * of the bounds but which might generate rendering that's within bounds.
      */
 
-    _cairo_stroke_style_max_distance_from_path (&stroker->style, stroker->ctm,
-						&dx, &dy);
+    _cairo_stroke_style_max_distance_from_path (&stroker->style, path,
+						stroker->ctm, &dx, &dy);
 
     fdx = _cairo_fixed_from_double (dx);
     fdy = _cairo_fixed_from_double (dy);
@@ -1293,7 +1295,8 @@ _cairo_path_fixed_stroke_dashed_to_polygon (const cairo_path_fixed_t	*path,
     stroker.closure = polygon;
 
     if (polygon->num_limits)
-	_cairo_stroker_limit (&stroker, polygon->limits, polygon->num_limits);
+	_cairo_stroker_limit (&stroker, path,
+			      polygon->limits, polygon->num_limits);
 
     status = _cairo_path_fixed_interpret (path,
 					  _cairo_stroker_move_to,
@@ -1328,7 +1331,6 @@ _cairo_path_fixed_stroke_to_traps (const cairo_path_fixed_t	*path,
     cairo_polygon_t polygon;
 
     _cairo_polygon_init (&polygon, traps->limits, traps->num_limits);
-
     status = _cairo_path_fixed_stroke_to_polygon (path,
 						  stroke_style,
 						  ctm,
diff --git a/src/cairo-pattern-private.h b/src/cairo-pattern-private.h
index 46a8ad6..8be319e 100644
--- a/src/cairo-pattern-private.h
+++ b/src/cairo-pattern-private.h
@@ -40,6 +40,8 @@
 #include "cairo-types-private.h"
 #include "cairo-list-private.h"
 
+#include <stdio.h> /* FILE* */
+
 CAIRO_BEGIN_DECLS
 
 typedef struct _cairo_pattern_observer cairo_pattern_observer_t;
@@ -59,19 +61,19 @@ struct _cairo_pattern_observer {
 };
 
 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_list_t		observers;
+
+    cairo_pattern_type_t	type;
 
-    cairo_matrix_t		matrix;
     cairo_filter_t		filter;
     cairo_extend_t		extend;
-    double			opacity;
-
     cairo_bool_t		has_component_alpha;
 
-    cairo_list_t		observers;
+    cairo_matrix_t		matrix;
+    double			opacity;
 };
 
 struct _cairo_solid_pattern {
@@ -265,46 +267,19 @@ _cairo_mesh_pattern_coord_box (const cairo_mesh_pattern_t *mesh,
 			       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_no_warn cairo_filter_t
+_cairo_pattern_sampled_area (const cairo_pattern_t *pattern,
+			     const cairo_rectangle_int_t *extents,
+			     cairo_rectangle_int_t *sample);
 
 cairo_private void
 _cairo_pattern_get_extents (const cairo_pattern_t	    *pattern,
 			    cairo_rectangle_int_t           *extents);
 
+cairo_private cairo_int_status_t
+_cairo_pattern_get_ink_extents (const cairo_pattern_t	    *pattern,
+				cairo_rectangle_int_t       *extents);
+
 cairo_private unsigned long
 _cairo_pattern_hash (const cairo_pattern_t *pattern);
 
@@ -353,7 +328,8 @@ _cairo_mesh_pattern_rasterize (const cairo_mesh_pattern_t *mesh,
 			       double                      x_offset,
 			       double                      y_offset);
 
-
+cairo_private void
+_cairo_debug_print_pattern (FILE *file, const cairo_pattern_t *pattern);
 
 CAIRO_END_DECLS
 
diff --git a/src/cairo-pattern.c b/src/cairo-pattern.c
index 19aa978..f91de26 100644
--- a/src/cairo-pattern.c
+++ b/src/cairo-pattern.c
@@ -29,11 +29,14 @@
  */
 
 #include "cairoint.h"
+
+#include "cairo-array-private.h"
 #include "cairo-error-private.h"
 #include "cairo-freed-pool-private.h"
+#include "cairo-image-surface-private.h"
 #include "cairo-path-private.h"
 #include "cairo-pattern-private.h"
-#include "cairo-image-surface-private.h"
+#include "cairo-recording-surface-private.h"
 
 #include <float.h>
 
@@ -61,55 +64,85 @@
 static freed_pool_t freed_pattern_pool[5];
 
 static const cairo_solid_pattern_t _cairo_pattern_nil = {
-    { CAIRO_PATTERN_TYPE_SOLID,		/* type */
+    {
       CAIRO_REFERENCE_COUNT_INVALID,	/* ref_count */
       CAIRO_STATUS_NO_MEMORY,		/* status */
       { 0, 0, 0, NULL },		/* user_data */
-      { 1., 0., 0., 1., 0., 0., },	/* matrix */
+      { NULL, NULL },			/* observers */
+
+      CAIRO_PATTERN_TYPE_SOLID,		/* type */
       CAIRO_FILTER_DEFAULT,		/* filter */
-      CAIRO_EXTEND_GRADIENT_DEFAULT },	/* extend */
+      CAIRO_EXTEND_GRADIENT_DEFAULT,	/* extend */
+      FALSE,				/* has component alpha */
+      { 1., 0., 0., 1., 0., 0., },	/* matrix */
+      1.0                               /* opacity */
+    }
 };
 
 static const cairo_solid_pattern_t _cairo_pattern_nil_null_pointer = {
-    { CAIRO_PATTERN_TYPE_SOLID,		/* type */
+    {
       CAIRO_REFERENCE_COUNT_INVALID,	/* ref_count */
       CAIRO_STATUS_NULL_POINTER,	/* status */
       { 0, 0, 0, NULL },		/* user_data */
-      { 1., 0., 0., 1., 0., 0., },	/* matrix */
+      { NULL, NULL },			/* observers */
+
+      CAIRO_PATTERN_TYPE_SOLID,		/* type */
       CAIRO_FILTER_DEFAULT,		/* filter */
-      CAIRO_EXTEND_GRADIENT_DEFAULT },	/* extend */
+      CAIRO_EXTEND_GRADIENT_DEFAULT,	/* extend */
+      FALSE,				/* has component alpha */
+      { 1., 0., 0., 1., 0., 0., },	/* matrix */
+      1.0                               /* opacity */
+    }
 };
 
 const cairo_solid_pattern_t _cairo_pattern_black = {
-    { CAIRO_PATTERN_TYPE_SOLID,		/* type */
+    {
       CAIRO_REFERENCE_COUNT_INVALID,	/* ref_count */
       CAIRO_STATUS_SUCCESS,		/* status */
       { 0, 0, 0, NULL },		/* user_data */
+      { NULL, NULL },			/* observers */
+
+      CAIRO_PATTERN_TYPE_SOLID,		/* type */
+      CAIRO_FILTER_NEAREST,		/* filter */
+      CAIRO_EXTEND_REPEAT,		/* extend */
+      FALSE,				/* has component alpha */
       { 1., 0., 0., 1., 0., 0., },	/* matrix */
-      CAIRO_FILTER_DEFAULT,		/* filter */
-      CAIRO_EXTEND_GRADIENT_DEFAULT},	/* extend */
+      1.0                               /* opacity */
+    },
     { 0., 0., 0., 1., 0, 0, 0, 0xffff },/* color (double rgba, short rgba) */
 };
 
 const cairo_solid_pattern_t _cairo_pattern_clear = {
-    { CAIRO_PATTERN_TYPE_SOLID,		/* type */
+    {
       CAIRO_REFERENCE_COUNT_INVALID,	/* ref_count */
       CAIRO_STATUS_SUCCESS,		/* status */
       { 0, 0, 0, NULL },		/* user_data */
+      { NULL, NULL },			/* observers */
+
+      CAIRO_PATTERN_TYPE_SOLID,		/* type */
+      CAIRO_FILTER_NEAREST,		/* filter */
+      CAIRO_EXTEND_REPEAT,		/* extend */
+      FALSE,				/* has component alpha */
       { 1., 0., 0., 1., 0., 0., },	/* matrix */
-      CAIRO_FILTER_DEFAULT,		/* filter */
-      CAIRO_EXTEND_GRADIENT_DEFAULT},	/* extend */
+      1.0                               /* opacity */
+    },
     { 0., 0., 0., 0., 0, 0, 0, 0 },/* color (double rgba, short rgba) */
 };
 
 const cairo_solid_pattern_t _cairo_pattern_white = {
-    { CAIRO_PATTERN_TYPE_SOLID,		/* type */
+    {
       CAIRO_REFERENCE_COUNT_INVALID,	/* ref_count */
       CAIRO_STATUS_SUCCESS,		/* status */
       { 0, 0, 0, NULL },		/* user_data */
+      { NULL, NULL },			/* observers */
+
+      CAIRO_PATTERN_TYPE_SOLID,		/* type */
+      CAIRO_FILTER_NEAREST,		/* filter */
+      CAIRO_EXTEND_REPEAT,		/* extend */
+      FALSE,				/* has component alpha */
       { 1., 0., 0., 1., 0., 0., },	/* matrix */
-      CAIRO_FILTER_DEFAULT,		/* filter */
-      CAIRO_EXTEND_GRADIENT_DEFAULT},	/* extend */
+      1.0                               /* opacity */
+    },
     { 1., 1., 1., 1., 0xffff, 0xffff, 0xffff, 0xffff },/* color (double rgba, short rgba) */
 };
 
@@ -249,7 +282,6 @@ _cairo_mesh_pattern_init_copy (cairo_mesh_pattern_t       *pattern,
     *pattern = *other;
 
     _cairo_array_init (&pattern->patches,  sizeof (cairo_mesh_patch_t));
-
     return _cairo_array_append_multiple (&pattern->patches,
 					 _cairo_array_index_const (&other->patches, 0),
 					 _cairo_array_num_elements (&other->patches));
@@ -477,7 +509,6 @@ _cairo_pattern_create_copy (cairo_pattern_t	  **pattern_out,
     return CAIRO_STATUS_SUCCESS;
 }
 
-
 void
 _cairo_pattern_init_solid (cairo_solid_pattern_t *pattern,
 			   const cairo_color_t	 *color)
@@ -2049,477 +2080,6 @@ _cairo_pattern_transform (cairo_pattern_t	*pattern,
     cairo_matrix_multiply (&pattern->matrix, ctm_inverse, &pattern->matrix);
 }
 
-static void
-_cairo_linear_pattern_classify (cairo_linear_pattern_t *pattern,
-				double		       offset_x,
-				double		       offset_y,
-				int		       width,
-				int		       height,
-				cairo_bool_t           *is_horizontal,
-				cairo_bool_t           *is_vertical)
-{
-    cairo_point_double_t point0, point1;
-    double a, b, c, d, tx, ty;
-    double scale, start, dx, dy;
-    cairo_fixed_t factors[3];
-    int i;
-
-    /* To classify a pattern as horizontal or vertical, we first
-     * compute the (fixed point) factors at the corners of the
-     * pattern. We actually only need 3/4 corners, so we skip the
-     * fourth.
-     */
-    point0 = pattern->pd1;
-    point1 = pattern->pd2;
-
-    _cairo_matrix_get_affine (&pattern->base.base.matrix,
-			      &a, &b, &c, &d, &tx, &ty);
-
-    dx = point1.x - point0.x;
-    dy = point1.y - point0.y;
-    scale = dx * dx + dy * dy;
-    scale = (scale) ? 1.0 / scale : 1.0;
-
-    start = dx * point0.x + dy * point0.y;
-
-    for (i = 0; i < 3; i++) {
-	double qx_device = (i % 2) * (width - 1) + offset_x;
-	double qy_device = (i / 2) * (height - 1) + offset_y;
-
-	/* transform fragment into pattern space */
-	double qx = a * qx_device + c * qy_device + tx;
-	double qy = b * qx_device + d * qy_device + ty;
-
-	factors[i] = _cairo_fixed_from_double (((dx * qx + dy * qy) - start) * scale);
-    }
-
-    /* We consider a pattern to be vertical if the fixed point factor
-     * at the two upper corners is the same. We could accept a small
-     * change, but determining what change is acceptable would require
-     * sorting the stops in the pattern and looking at the differences.
-     *
-     * Horizontal works the same way with the two left corners.
-     */
-
-    *is_vertical = factors[1] == factors[0];
-    *is_horizontal = factors[2] == factors[0];
-}
-
-static cairo_int_status_t
-_cairo_pattern_acquire_surface_for_gradient (const cairo_gradient_pattern_t *pattern,
-					     cairo_surface_t	        *dst,
-					     int			x,
-					     int			y,
-					     unsigned int		width,
-					     unsigned int	        height,
-					     cairo_surface_t	        **out,
-					     cairo_surface_attributes_t *attr)
-{
-    cairo_image_surface_t *image;
-    pixman_image_t	  *pixman_image;
-    pixman_transform_t	  pixman_transform;
-    cairo_circle_double_t extremes[2];
-    pixman_point_fixed_t  p1, p2;
-    cairo_int_status_t	  status;
-    cairo_bool_t	  repeat = FALSE;
-    int                   ix, iy;
-    pixman_gradient_stop_t pixman_stops_static[2];
-    pixman_gradient_stop_t *pixman_stops = pixman_stops_static;
-    unsigned int i;
-    int clone_offset_x, clone_offset_y;
-    cairo_matrix_t matrix = pattern->base.matrix;
-
-    if (CAIRO_INJECT_FAULT ())
-	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
-    if (pattern->n_stops > ARRAY_LENGTH(pixman_stops_static)) {
-	pixman_stops = _cairo_malloc_ab (pattern->n_stops,
-					 sizeof(pixman_gradient_stop_t));
-	if (unlikely (pixman_stops == NULL))
-	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-    }
-
-    for (i = 0; i < pattern->n_stops; i++) {
-	pixman_stops[i].x = _cairo_fixed_16_16_from_double (pattern->stops[i].offset);
-	pixman_stops[i].color.red = pattern->stops[i].color.red_short;
-	pixman_stops[i].color.green = pattern->stops[i].color.green_short;
-	pixman_stops[i].color.blue = pattern->stops[i].color.blue_short;
-	pixman_stops[i].color.alpha = pattern->stops[i].color.alpha_short;
-    }
-
-    _cairo_gradient_pattern_fit_to_range (pattern, PIXMAN_MAX_INT >> 1, &matrix, extremes);
-
-    p1.x = _cairo_fixed_16_16_from_double (extremes[0].center.x);
-    p1.y = _cairo_fixed_16_16_from_double (extremes[0].center.y);
-    p2.x = _cairo_fixed_16_16_from_double (extremes[1].center.x);
-    p2.y = _cairo_fixed_16_16_from_double (extremes[1].center.y);
-
-    if (pattern->base.type == CAIRO_PATTERN_TYPE_LINEAR) {
-	pixman_image = pixman_image_create_linear_gradient (&p1, &p2,
-							    pixman_stops,
-							    pattern->n_stops);
-    } else {
-	pixman_fixed_t r1, r2;
-
-	r1   = _cairo_fixed_16_16_from_double (extremes[0].radius);
-	r2   = _cairo_fixed_16_16_from_double (extremes[1].radius);
-
-	pixman_image = pixman_image_create_radial_gradient (&p1, &p2, r1, r2,
-							    pixman_stops,
-							    pattern->n_stops);
-    }
-
-    if (pixman_stops != pixman_stops_static)
-	free (pixman_stops);
-
-    if (unlikely (pixman_image == NULL))
-	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
-    if (_cairo_surface_is_image (dst))
-    {
-	image = (cairo_image_surface_t *)
-	    _cairo_image_surface_create_for_pixman_image (pixman_image,
-							  PIXMAN_a8r8g8b8);
-	if (image->base.status)
-	{
-	    pixman_image_unref (pixman_image);
-	    return image->base.status;
-	}
-
-	attr->x_offset = attr->y_offset = 0;
-	attr->matrix = matrix;
-	attr->extend = pattern->base.extend;
-	attr->filter = CAIRO_FILTER_NEAREST;
-	attr->has_component_alpha = pattern->base.has_component_alpha;
-
-	*out = &image->base;
-
-	return CAIRO_STATUS_SUCCESS;
-    }
-
-    if (pattern->base.type == CAIRO_PATTERN_TYPE_LINEAR) {
-	cairo_bool_t is_horizontal;
-	cairo_bool_t is_vertical;
-
-	_cairo_linear_pattern_classify ((cairo_linear_pattern_t *)pattern,
-					x, y, width, height,
-					&is_horizontal, &is_vertical);
-	if (is_horizontal) {
-	    height = 1;
-	    repeat = TRUE;
-	}
-	/* width-1 repeating patterns are quite slow with scan-line based
-	 * compositing code, so we use a wider strip and spend some extra
-	 * expense in computing the gradient. It's possible that for narrow
-	 * gradients we'd be better off using a 2 or 4 pixel strip; the
-	 * wider the gradient, the more it's worth spending extra time
-	 * computing a sample.
-	 */
-	if (is_vertical && width > 8) {
-	    width = 8;
-	    repeat = TRUE;
-	}
-    }
-
-    if (! pixman_image_set_filter (pixman_image, PIXMAN_FILTER_BILINEAR,
-				   NULL, 0))
-    {
-	pixman_image_unref (pixman_image);
-	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-    }
-
-    image = (cairo_image_surface_t *)
-	cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
-    if (image->base.status) {
-	pixman_image_unref (pixman_image);
-	return image->base.status;
-    }
-
-    ix = x;
-    iy = y;
-    status = _cairo_matrix_to_pixman_matrix_offset (&matrix,
-						    pattern->base.filter,
-						    width/2., height/2.,
-						    &pixman_transform,
-						    &ix, &iy);
-    if (status != CAIRO_INT_STATUS_NOTHING_TO_DO) {
-	if (unlikely (status != CAIRO_INT_STATUS_SUCCESS) ||
-	    ! pixman_image_set_transform (pixman_image, &pixman_transform))
-	{
-	    cairo_surface_destroy (&image->base);
-	    pixman_image_unref (pixman_image);
-	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-	}
-    }
-
-    switch (pattern->base.extend) {
-    case CAIRO_EXTEND_NONE:
-	pixman_image_set_repeat (pixman_image, PIXMAN_REPEAT_NONE);
-	break;
-    case CAIRO_EXTEND_REPEAT:
-	pixman_image_set_repeat (pixman_image, PIXMAN_REPEAT_NORMAL);
-	break;
-    case CAIRO_EXTEND_REFLECT:
-	pixman_image_set_repeat (pixman_image, PIXMAN_REPEAT_REFLECT);
-	break;
-    case CAIRO_EXTEND_PAD:
-	pixman_image_set_repeat (pixman_image, PIXMAN_REPEAT_PAD);
-	break;
-    }
-
-    pixman_image_composite32 (PIXMAN_OP_SRC,
-                              pixman_image,
-                              NULL,
-                              image->pixman_image,
-			      ix, iy,
-                              0, 0,
-                              0, 0,
-                              width, height);
-
-    pixman_image_unref (pixman_image);
-
-    _cairo_debug_check_image_surface_is_defined (&image->base);
-
-    status = _cairo_surface_clone_similar (dst, &image->base,
-					   0, 0, width, height,
-					   &clone_offset_x,
-					   &clone_offset_y,
-					   out);
-
-    cairo_surface_destroy (&image->base);
-
-    attr->x_offset = -x;
-    attr->y_offset = -y;
-    cairo_matrix_init_identity (&attr->matrix);
-    attr->extend = repeat ? CAIRO_EXTEND_REPEAT : CAIRO_EXTEND_NONE;
-    attr->filter = CAIRO_FILTER_NEAREST;
-    attr->has_component_alpha = pattern->base.has_component_alpha;
-
-    return status;
-}
-
-static cairo_int_status_t
-_cairo_pattern_acquire_surface_for_mesh (const cairo_mesh_pattern_t *pattern,
-					 cairo_surface_t            *dst,
-					 int   	                     x,
-					 int                         y,
-					 unsigned int                width,
-					 unsigned int                height,
-					 cairo_surface_t           **out,
-					 cairo_surface_attributes_t *attr)
-{
-    cairo_surface_t *image;
-    void *data;
-    cairo_status_t status;
-    int clone_offset_x, clone_offset_y;
-    int stride;
-
-    image = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
-    if (unlikely (image->status))
-	return image->status;
-
-    stride = cairo_image_surface_get_stride (image);
-    data = cairo_image_surface_get_data (image);
-
-    _cairo_mesh_pattern_rasterize (pattern, data, width, height, stride, -x, -y);
-
-    attr->x_offset = -x;
-    attr->y_offset = -y;
-    attr->filter = CAIRO_FILTER_NEAREST;
-    attr->extend = pattern->base.extend;
-    cairo_matrix_init_identity (&attr->matrix);
-    attr->has_component_alpha = pattern->base.has_component_alpha;
-
-    if (_cairo_surface_is_image (dst)) {
-	*out = image;
-
-	return CAIRO_STATUS_SUCCESS;
-    }
-
-    status = _cairo_surface_clone_similar (dst, image,
-					   0, 0, width, height,
-					   &clone_offset_x,
-					   &clone_offset_y, out);
-
-    cairo_surface_destroy (image);
-
-    return status;
-}
-
-/* We maintain a small cache here, because we don't want to constantly
- * recreate surfaces for simple solid colors. */
-#define MAX_SURFACE_CACHE_SIZE 16
-static struct {
-    struct _cairo_pattern_solid_surface_cache{
-	cairo_color_t    color;
-	cairo_surface_t *surface;
-    } cache[MAX_SURFACE_CACHE_SIZE];
-    int size;
-} solid_surface_cache;
-
-static cairo_bool_t
-_cairo_pattern_solid_surface_matches (
-	const struct _cairo_pattern_solid_surface_cache	    *cache,
-	const cairo_solid_pattern_t			    *pattern,
-	cairo_surface_t					    *dst)
-{
-    if (cairo_surface_get_content (cache->surface) != _cairo_color_get_content (&pattern->color))
-	return FALSE;
-
-    if (CAIRO_REFERENCE_COUNT_GET_VALUE (&cache->surface->ref_count) != 1)
-	return FALSE;
-
-    if (! _cairo_surface_is_similar (cache->surface, dst))
-	return FALSE;
-
-    return TRUE;
-}
-
-static cairo_bool_t
-_cairo_pattern_solid_surface_matches_color (
-	const struct _cairo_pattern_solid_surface_cache	    *cache,
-	const cairo_solid_pattern_t			    *pattern,
-	cairo_surface_t					    *dst)
-{
-    if (! _cairo_color_equal (&cache->color, &pattern->color))
-	return FALSE;
-
-    return _cairo_pattern_solid_surface_matches (cache, pattern, dst);
-}
-
-static cairo_int_status_t
-_cairo_pattern_acquire_surface_for_solid (const cairo_solid_pattern_t	     *pattern,
-					  cairo_surface_t	     *dst,
-					  int			     x,
-					  int			     y,
-					  unsigned int		     width,
-					  unsigned int		     height,
-					  cairo_surface_t	     **out,
-					  cairo_surface_attributes_t *attribs)
-{
-    static int i;
-
-    cairo_surface_t *surface, *to_destroy = NULL;
-    cairo_status_t   status;
-
-    CAIRO_MUTEX_LOCK (_cairo_pattern_solid_surface_cache_lock);
-
-    /* Check cache first */
-    if (i < solid_surface_cache.size &&
-	_cairo_pattern_solid_surface_matches_color (&solid_surface_cache.cache[i],
-						    pattern,
-						    dst))
-    {
-	goto DONE;
-    }
-
-    for (i = 0 ; i < solid_surface_cache.size; i++) {
-	if (_cairo_pattern_solid_surface_matches_color (&solid_surface_cache.cache[i],
-							pattern,
-							dst))
-	{
-	    goto DONE;
-	}
-    }
-
-    /* Choose a surface to repaint/evict */
-    surface = NULL;
-    if (solid_surface_cache.size == MAX_SURFACE_CACHE_SIZE) {
-	i = rand () % MAX_SURFACE_CACHE_SIZE;
-	surface = solid_surface_cache.cache[i].surface;
-
-	if (_cairo_pattern_solid_surface_matches (&solid_surface_cache.cache[i],
-						  pattern,
-						  dst))
-	{
-	    /* Reuse the surface instead of evicting */
-	    status = _cairo_surface_repaint_solid_pattern_surface (dst, surface, pattern);
-	    if (unlikely (status))
-		goto EVICT;
-
-	    cairo_surface_reference (surface);
-	}
-	else
-	{
-	  EVICT:
-	    surface = NULL;
-	}
-    }
-
-    if (surface == NULL) {
-	/* Not cached, need to create new */
-	surface = _cairo_surface_create_solid_pattern_surface (dst, pattern);
-	if (surface == NULL) {
-	    status = CAIRO_INT_STATUS_UNSUPPORTED;
-	    goto UNLOCK;
-	}
-	if (unlikely (surface->status)) {
-	    status = surface->status;
-	    goto UNLOCK;
-	}
-
-	if (unlikely (! _cairo_surface_is_similar (surface, dst)))
-	{
-	    /* In the rare event of a substitute surface being returned,
-	     * don't cache the fallback.
-	     */
-	    *out = surface;
-	    goto NOCACHE;
-	}
-    }
-
-    if (i == solid_surface_cache.size)
-	solid_surface_cache.size++;
-
-    to_destroy = solid_surface_cache.cache[i].surface;
-    solid_surface_cache.cache[i].surface = surface;
-    solid_surface_cache.cache[i].color   = pattern->color;
-
-DONE:
-    *out = cairo_surface_reference (solid_surface_cache.cache[i].surface);
-
-NOCACHE:
-    attribs->x_offset = attribs->y_offset = 0;
-    cairo_matrix_init_identity (&attribs->matrix);
-    attribs->extend = CAIRO_EXTEND_REPEAT;
-    attribs->filter = CAIRO_FILTER_NEAREST;
-    attribs->has_component_alpha = pattern->base.has_component_alpha;
-
-    status = CAIRO_STATUS_SUCCESS;
-
-UNLOCK:
-    CAIRO_MUTEX_UNLOCK (_cairo_pattern_solid_surface_cache_lock);
-
-    if (to_destroy)
-      cairo_surface_destroy (to_destroy);
-
-    return status;
-}
-
-static void
-_cairo_pattern_reset_solid_surface_cache (void)
-{
-    CAIRO_MUTEX_LOCK (_cairo_pattern_solid_surface_cache_lock);
-
-    /* remove surfaces starting from the end so that solid_surface_cache.cache
-     * is always in a consistent state when we release the mutex. */
-    while (solid_surface_cache.size) {
-	cairo_surface_t *surface;
-
-	solid_surface_cache.size--;
-	surface = solid_surface_cache.cache[solid_surface_cache.size].surface;
-	solid_surface_cache.cache[solid_surface_cache.size].surface = NULL;
-
-	/* release the lock to avoid the possibility of a recursive
-	 * deadlock when the surface destroy closure gets called */
-	CAIRO_MUTEX_UNLOCK (_cairo_pattern_solid_surface_cache_lock);
-	cairo_surface_destroy (surface);
-	CAIRO_MUTEX_LOCK (_cairo_pattern_solid_surface_cache_lock);
-    }
-
-    CAIRO_MUTEX_UNLOCK (_cairo_pattern_solid_surface_cache_lock);
-}
-
 static cairo_bool_t
 _linear_pattern_is_degenerate (const cairo_linear_pattern_t *linear)
 {
@@ -3546,7 +3106,7 @@ _cairo_pattern_is_opaque_solid (const cairo_pattern_t *pattern)
 
 static cairo_bool_t
 _surface_is_opaque (const cairo_surface_pattern_t *pattern,
-		    const cairo_rectangle_int_t *r)
+		    const cairo_rectangle_int_t *sample)
 {
     if (pattern->surface->content & CAIRO_CONTENT_ALPHA)
 	return FALSE;
@@ -3554,16 +3114,16 @@ _surface_is_opaque (const cairo_surface_pattern_t *pattern,
     if (pattern->base.extend != CAIRO_EXTEND_NONE)
 	return TRUE;
 
-    if (r != NULL) {
+    if (sample != NULL) {
 	cairo_rectangle_int_t extents;
 
 	if (! _cairo_surface_get_extents (pattern->surface, &extents))
 	    return TRUE;
 
-	if (r->x >= extents.x &&
-	    r->y >= extents.y &&
-	    r->x + r->width <= extents.x + extents.width &&
-	    r->y + r->height <= extents.y + extents.height)
+	if (sample->x >= extents.x &&
+	    sample->y >= extents.y &&
+	    sample->x + sample->width  <= extents.x + extents.width &&
+	    sample->y + sample->height <= extents.y + extents.height)
 	{
 	    return TRUE;
 	}
@@ -3587,7 +3147,7 @@ _surface_is_clear (const cairo_surface_pattern_t *pattern)
 
 static cairo_bool_t
 _gradient_is_opaque (const cairo_gradient_pattern_t *gradient,
-		     const cairo_rectangle_int_t *extents)
+		     const cairo_rectangle_int_t *sample)
 {
     unsigned int i;
 
@@ -3608,14 +3168,14 @@ _gradient_is_opaque (const cairo_gradient_pattern_t *gradient,
 	    if (_linear_pattern_is_degenerate (linear))
 		return FALSE;
 
-	    if (extents == NULL)
+	    if (sample == NULL)
 		return FALSE;
 
 	    _cairo_linear_pattern_box_to_parameter (linear,
-						    extents->x,
-						    extents->y,
-						    extents->x + extents->width,
-						    extents->y + extents->height,
+						    sample->x,
+						    sample->y,
+						    sample->x + sample->width,
+						    sample->y + sample->height,
 						    t);
 
 	    if (t[0] < 0.0 || t[1] > 1.0)
@@ -3642,7 +3202,7 @@ _gradient_is_opaque (const cairo_gradient_pattern_t *gradient,
  **/
 cairo_bool_t
 _cairo_pattern_is_opaque (const cairo_pattern_t *abstract_pattern,
-			  const cairo_rectangle_int_t *extents)
+			  const cairo_rectangle_int_t *sample)
 {
     const cairo_pattern_union_t *pattern;
 
@@ -3654,10 +3214,10 @@ _cairo_pattern_is_opaque (const cairo_pattern_t *abstract_pattern,
     case CAIRO_PATTERN_TYPE_SOLID:
 	return _cairo_pattern_is_opaque_solid (abstract_pattern);
     case CAIRO_PATTERN_TYPE_SURFACE:
-	return _surface_is_opaque (&pattern->surface, extents);
+	return _surface_is_opaque (&pattern->surface, sample);
     case CAIRO_PATTERN_TYPE_LINEAR:
     case CAIRO_PATTERN_TYPE_RADIAL:
-	return _gradient_is_opaque (&pattern->gradient.base, extents);
+	return _gradient_is_opaque (&pattern->gradient.base, sample);
     case CAIRO_PATTERN_TYPE_MESH:
 	return FALSE;
     }
@@ -3749,437 +3309,53 @@ _cairo_pattern_analyze_filter (const cairo_pattern_t	*pattern,
     return optimized_filter;
 }
 
-
-static double
-_pixman_nearest_sample (double d)
-{
-    return ceil (d - .5);
-}
-
-static cairo_int_status_t
-_cairo_pattern_acquire_surface_for_surface (const cairo_surface_pattern_t   *pattern,
-					    cairo_surface_t	       *dst,
-					    int			       x,
-					    int			       y,
-					    unsigned int	       width,
-					    unsigned int	       height,
-					    unsigned int	       flags,
-					    cairo_surface_t	       **out,
-					    cairo_surface_attributes_t *attr)
+cairo_filter_t
+_cairo_pattern_sampled_area (const cairo_pattern_t *pattern,
+			     const cairo_rectangle_int_t *extents,
+			     cairo_rectangle_int_t *sample)
 {
-    cairo_surface_t *surface;
-    cairo_rectangle_int_t extents;
-    cairo_rectangle_int_t sampled_area;
-    double x1, y1, x2, y2;
-    int tx, ty;
+    cairo_filter_t filter;
+    double x1, x2, y1, y2;
     double pad;
-    cairo_bool_t is_identity;
-    cairo_bool_t is_bounded;
-    cairo_int_status_t status;
-
-    surface = cairo_surface_reference (pattern->surface);
-
-    is_identity = FALSE;
-    attr->matrix = pattern->base.matrix;
-    attr->extend = pattern->base.extend;
-    attr->filter = _cairo_pattern_analyze_filter (&pattern->base, &pad);
-    attr->has_component_alpha = pattern->base.has_component_alpha;
-
-    attr->x_offset = attr->y_offset = tx = ty = 0;
-    if (_cairo_matrix_is_integer_translation (&attr->matrix, &tx, &ty)) {
-	cairo_matrix_init_identity (&attr->matrix);
-	attr->x_offset = tx;
-	attr->y_offset = ty;
-	is_identity = TRUE;
-    } else if (attr->filter == CAIRO_FILTER_NEAREST) {
-	/*
-	 * For NEAREST, we can remove the fractional translation component
-	 * from the transformation - this ensures that the pattern will always
-	 * hit fast-paths in the backends for simple transformations that
-	 * become (almost) identity, without loss of quality.
-	 */
-	attr->matrix.x0 = 0;
-	attr->matrix.y0 = 0;
-	if (_cairo_matrix_is_pixel_exact (&attr->matrix)) {
-	    /* The rounding here is rather peculiar as it needs to match the
-	     * rounding performed on the sample coordinate used by pixman.
-	     */
-	    attr->matrix.x0 = _pixman_nearest_sample (pattern->base.matrix.x0);
-	    attr->matrix.y0 = _pixman_nearest_sample (pattern->base.matrix.y0);
-	} else {
-	    attr->matrix.x0 = pattern->base.matrix.x0;
-	    attr->matrix.y0 = pattern->base.matrix.y0;
-	}
 
-	if (_cairo_matrix_is_integer_translation (&attr->matrix, &tx, &ty)) {
-	    cairo_matrix_init_identity (&attr->matrix);
-	    attr->x_offset = tx;
-	    attr->y_offset = ty;
-	    is_identity = TRUE;
-	}
+    filter = _cairo_pattern_analyze_filter (pattern, &pad);
+    if (pad == 0.0 && _cairo_matrix_is_identity (&pattern->matrix)) {
+	*sample = *extents;
+	return filter;
     }
 
-    /* XXX: Hack:
-     *
-     * The way we currently support CAIRO_EXTEND_REFLECT is to create
-     * an image twice bigger on each side, and create a pattern of four
-     * images such that the new image, when repeated, has the same effect
-     * of reflecting the original pattern.
-     */
-    if (flags & CAIRO_PATTERN_ACQUIRE_NO_REFLECT &&
-	attr->extend == CAIRO_EXTEND_REFLECT)
-    {
-	cairo_t *cr;
-	cairo_surface_t *src;
-	int w, h;
-
-	is_bounded = _cairo_surface_get_extents (surface, &extents);
-	assert (is_bounded);
-
-	status = _cairo_surface_clone_similar (dst, surface,
-					       extents.x, extents.y,
-					       extents.width, extents.height,
-					       &extents.x, &extents.y, &src);
-	if (unlikely (status))
-	    goto BAIL;
-
-	w = 2 * extents.width;
-	h = 2 * extents.height;
-
-	if (is_identity) {
-	    attr->x_offset = -x;
-	    x += tx;
-	    while (x <= -w)
-		x += w;
-	    while (x >= w)
-		x -= w;
-	    extents.x += x;
-	    tx = x = 0;
-
-	    attr->y_offset = -y;
-	    y += ty;
-	    while (y <= -h)
-		y += h;
-	    while (y >= h)
-		y -= h;
-	    extents.y += y;
-	    ty = y = 0;
-	}
-
-	cairo_surface_destroy (surface);
-	surface = _cairo_surface_create_similar_solid (dst,
-						       dst->content, w, h,
-						       CAIRO_COLOR_TRANSPARENT,
-						       FALSE);
-	if (surface == NULL)
-	    return CAIRO_INT_STATUS_UNSUPPORTED;
-	if (unlikely (surface->status)) {
-	    cairo_surface_destroy (src);
-	    return surface->status;
-	}
-
-	surface->device_transform = pattern->surface->device_transform;
-	surface->device_transform_inverse = pattern->surface->device_transform_inverse;
-
-	cr = cairo_create (surface);
-
-	cairo_set_source_surface (cr, src, -extents.x, -extents.y);
-	cairo_paint (cr);
-
-	cairo_scale (cr, -1, +1);
-	cairo_set_source_surface (cr, src, extents.x-w, -extents.y);
-	cairo_paint (cr);
-	cairo_set_source_surface (cr, src, extents.x, -extents.y);
-	cairo_paint (cr);
-
-	cairo_scale (cr, +1, -1);
-	cairo_set_source_surface (cr, src, extents.x-w, extents.y-h);
-	cairo_paint (cr);
-	cairo_set_source_surface (cr, src, extents.x, extents.y-h);
-	cairo_paint (cr);
-	cairo_set_source_surface (cr, src, extents.x-w, extents.y);
-	cairo_paint (cr);
-	cairo_set_source_surface (cr, src, extents.x, extents.y);
-	cairo_paint (cr);
-
-	cairo_scale (cr, -1, +1);
-	cairo_set_source_surface (cr, src, -extents.x, extents.y-h);
-	cairo_paint (cr);
-	cairo_set_source_surface (cr, src, -extents.x, extents.y);
-	cairo_paint (cr);
-
-	status = cairo_status (cr);
-	cairo_destroy (cr);
-
-	cairo_surface_destroy (src);
-
-	if (unlikely (status))
-	    goto BAIL;
-
-	attr->extend = CAIRO_EXTEND_REPEAT;
-    }
-
-    /* We first transform the rectangle to the coordinate space of the
-     * source surface so that we only need to clone that portion of the
-     * surface that will be read.
-     */
-    x1 = x;
-    y1 = y;
-    x2 = x + (int) width;
-    y2 = y + (int) height;
-    if (! is_identity) {
-	_cairo_matrix_transform_bounding_box (&attr->matrix,
-					      &x1, &y1, &x2, &y2,
-					      NULL);
-    }
-
-    sampled_area.x = floor (x1 - pad);
-    sampled_area.y = floor (y1 - pad);
-    sampled_area.width  = ceil (x2 + pad) - sampled_area.x;
-    sampled_area.height = ceil (y2 + pad) - sampled_area.y;
-
-    sampled_area.x += tx;
-    sampled_area.y += ty;
-
-    if ( _cairo_surface_get_extents (surface, &extents)) {
-	if (attr->extend == CAIRO_EXTEND_NONE) {
-	    /* Never acquire a larger area than the source itself */
-	    _cairo_rectangle_intersect (&extents, &sampled_area);
-	} else {
-	    int trim = 0;
-
-	    if (sampled_area.x >= extents.x &&
-		sampled_area.x + (int) sampled_area.width <= extents.x + (int) extents.width)
-	    {
-		/* source is horizontally contained within extents, trim */
-		extents.x = sampled_area.x;
-		extents.width = sampled_area.width;
-		trim |= 0x1;
-	    }
-
-	    if (sampled_area.y >= extents.y &&
-		sampled_area.y + (int) sampled_area.height <= extents.y + (int) extents.height)
-	    {
-		/* source is vertically contained within extents, trim */
-		extents.y = sampled_area.y;
-		extents.height = sampled_area.height;
-		trim |= 0x2;
-	    }
-
-	    if (trim == 0x3) {
-		/* source is wholly contained within extents, drop the REPEAT */
-		attr->extend = CAIRO_EXTEND_NONE;
-	    }
-	}
-    }
-
-    status = _cairo_surface_clone_similar (dst, surface,
-					   extents.x, extents.y,
-					   extents.width, extents.height,
-					   &x, &y, out);
-    if (unlikely (status))
-	goto BAIL;
-
-    if (x != 0 || y != 0) {
-	if (is_identity) {
-	    attr->x_offset -= x;
-	    attr->y_offset -= y;
-	} else {
-	    cairo_matrix_t m;
-
-	    x -= attr->x_offset;
-	    y -= attr->y_offset;
-	    attr->x_offset = 0;
-	    attr->y_offset = 0;
-
-	    cairo_matrix_init_translate (&m, -x, -y);
-	    cairo_matrix_multiply (&attr->matrix, &attr->matrix, &m);
-	}
-    }
-
-    /* reduce likelihood of range overflow with large downscaling */
-    if (! is_identity) {
-	cairo_matrix_t m;
-	cairo_status_t invert_status;
-
-	m = attr->matrix;
-	invert_status = cairo_matrix_invert (&m);
-	assert (invert_status == CAIRO_STATUS_SUCCESS);
-
-	if (m.x0 != 0. || m.y0 != 0.) {
-	    /* pixman also limits the [xy]_offset to 16 bits so evenly
-	     * spread the bits between the two.
-	     */
-	    x = floor (m.x0 / 2);
-	    y = floor (m.y0 / 2);
-	    attr->x_offset -= x;
-	    attr->y_offset -= y;
-	    cairo_matrix_init_translate (&m, x, y);
-	    cairo_matrix_multiply (&attr->matrix, &m, &attr->matrix);
-	}
-    }
-
-  BAIL:
-    cairo_surface_destroy (surface);
-    return status;
-}
-
-/**
- * _cairo_pattern_acquire_surface:
- * @pattern: a #cairo_pattern_t
- * @dst: destination surface
- * @x: X coordinate in source corresponding to left side of destination area
- * @y: Y coordinate in source corresponding to top side of destination area
- * @width: width of destination area
- * @height: height of destination area
- * @surface_out: location to store a pointer to a surface
- * @attributes: surface attributes that destination backend should apply to
- * the returned surface
- *
- * A convenience function to obtain a surface to use as the source for
- * drawing on @dst.
- *
- * Note that this function is only suitable for use when the destination
- * surface is pixel based and 1 device unit maps to one pixel.
- *
- * Return value: %CAIRO_STATUS_SUCCESS if a surface was stored in @surface_out.
- **/
-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)
-{
-    if (unlikely (pattern->status)) {
-	*surface_out = NULL;
-	return pattern->status;
-    }
+    x1 = extents->x;
+    y1 = extents->y;
+    x2 = extents->x + (int) extents->width;
+    y2 = extents->y + (int) extents->height;
 
-    switch (pattern->type) {
-    case CAIRO_PATTERN_TYPE_SOLID:
-	return _cairo_pattern_acquire_surface_for_solid ((cairo_solid_pattern_t *) pattern,
-							 dst, x, y, width, height,
-							 surface_out,
-							 attributes);
-
-    case CAIRO_PATTERN_TYPE_LINEAR:
-    case CAIRO_PATTERN_TYPE_RADIAL:
-	return _cairo_pattern_acquire_surface_for_gradient ((cairo_gradient_pattern_t *) pattern,
-							    dst, x, y, width, height,
-							    surface_out,
-							    attributes);
-
-    case CAIRO_PATTERN_TYPE_SURFACE:
-	return _cairo_pattern_acquire_surface_for_surface ((cairo_surface_pattern_t *) pattern,
-							   dst, x, y, width, height,
-							   flags,
-							   surface_out,
-							   attributes);
-
-    case CAIRO_PATTERN_TYPE_MESH:
-	return _cairo_pattern_acquire_surface_for_mesh ((cairo_mesh_pattern_t *) pattern,
-							dst, x, y, width, height,
-							surface_out,
-							attributes);
-
-    default:
-	ASSERT_NOT_REACHED;
-	return _cairo_error (CAIRO_STATUS_PATTERN_TYPE_MISMATCH);
-    }
-}
-
-/**
- * _cairo_pattern_release_surface:
- * @pattern: a #cairo_pattern_t
- * @surface: a surface obtained by _cairo_pattern_acquire_surface
- * @attributes: attributes obtained by _cairo_pattern_acquire_surface
- *
- * Releases resources obtained by _cairo_pattern_acquire_surface.
- **/
-void
-_cairo_pattern_release_surface (const cairo_pattern_t *pattern,
-				cairo_surface_t		   *surface,
-				cairo_surface_attributes_t *attributes)
-{
-    cairo_surface_destroy (surface);
-}
-
-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_int_status_t	  status;
-    cairo_pattern_union_t src_tmp;
-
-    if (unlikely (src->status))
-	return src->status;
-    if (unlikely (mask != NULL && mask->status))
-	return mask->status;
-
-    /* If src and mask are both solid, then the mask alpha can be
-     * combined into src and mask can be ignored. */
-
-    if (src->type == CAIRO_PATTERN_TYPE_SOLID &&
-	mask &&
-	! mask->has_component_alpha &&
-	mask->type == CAIRO_PATTERN_TYPE_SOLID)
-    {
-	cairo_color_t combined;
-	cairo_solid_pattern_t *src_solid = (cairo_solid_pattern_t *) src;
-	cairo_solid_pattern_t *mask_solid = (cairo_solid_pattern_t *) mask;
-
-	combined = src_solid->color;
-	_cairo_color_multiply_alpha (&combined, mask_solid->color.alpha);
-
-	_cairo_pattern_init_solid (&src_tmp.solid, &combined);
-
-	src = &src_tmp.base;
-	mask = NULL;
-    }
+    _cairo_matrix_transform_bounding_box (&pattern->matrix,
+					  &x1, &y1, &x2, &y2,
+					  NULL);
+    if (x1 > CAIRO_RECT_INT_MIN)
+	sample->x = floor (x1 - pad);
+    else
+	sample->x = CAIRO_RECT_INT_MIN;
 
-    status = _cairo_pattern_acquire_surface (src, dst,
-					     src_x, src_y,
-					     width, height,
-					     flags,
-					     src_out, src_attributes);
-    if (unlikely (status))
-	goto BAIL;
+    if (y1 > CAIRO_RECT_INT_MIN)
+	sample->y = floor (y1 - pad);
+    else
+	sample->y = CAIRO_RECT_INT_MIN;
 
-    if (mask == NULL) {
-	*mask_out = NULL;
-	goto BAIL;
-    }
+    if (x2 < CAIRO_RECT_INT_MAX)
+	sample->width = ceil (x2 + pad);
+    else
+	sample->width = CAIRO_RECT_INT_MAX;
 
-    status = _cairo_pattern_acquire_surface (mask, dst,
-					     mask_x, mask_y,
-					     width, height,
-					     flags,
-					     mask_out, mask_attributes);
-    if (unlikely (status))
-	_cairo_pattern_release_surface (src, *src_out, src_attributes);
+    if (y2 < CAIRO_RECT_INT_MAX)
+	sample->height = ceil (y2 + pad);
+    else
+	sample->height = CAIRO_RECT_INT_MAX;
 
-  BAIL:
-    if (src == &src_tmp.base)
-	_cairo_pattern_fini (&src_tmp.base);
+    sample->width  -= sample->x;
+    sample->height -= sample->y;
 
-    return status;
+    return filter;
 }
 
 /**
@@ -4381,7 +3557,7 @@ _cairo_pattern_get_extents (const cairo_pattern_t         *pattern,
  *
  * Return the "target-space" inked extents of @pattern in @extents.
  **/
-void
+cairo_int_status_t
 _cairo_pattern_get_ink_extents (const cairo_pattern_t         *pattern,
 				cairo_rectangle_int_t         *extents)
 {
@@ -4392,33 +3568,28 @@ _cairo_pattern_get_ink_extents (const cairo_pattern_t         *pattern,
 	    (const cairo_surface_pattern_t *) pattern;
 	cairo_surface_t *surface = surface_pattern->surface;
 
-	if (surface->type == CAIRO_SURFACE_TYPE_RECORDING) {
+	if (_cairo_surface_is_recording (surface)) {
 	    cairo_matrix_t imatrix;
-	    double x1, y1, x2, y2, width, height;
+	    cairo_box_t box;
 	    cairo_status_t status;
 
-	    cairo_recording_surface_ink_extents (surface, &x1, &y1, &width, &height);
 	    imatrix = pattern->matrix;
 	    status = cairo_matrix_invert (&imatrix);
 	    /* cairo_pattern_set_matrix ensures the matrix is invertible */
 	    assert (status == CAIRO_STATUS_SUCCESS);
 
-	    x2 = x1 + width;
-	    y2 = y1 + height;
-	    _cairo_matrix_transform_bounding_box (&imatrix,
-						  &x1, &y1, &x2, &y2,
-						  NULL);
-	    x1 = floor (x1);
-	    y1 = floor (y1);
-	    x2 = ceil (x2);
-	    y2 = ceil (y2);
-	    extents->x = x1; extents->width  = x2 - x1;
-	    extents->y = y1; extents->height = y2 - y1;
-	    return;
+	    status = _cairo_recording_surface_get_ink_bbox ((cairo_recording_surface_t *)surface,
+						   &box, &imatrix);
+	    if (unlikely (status))
+		return status;
+
+	    _cairo_box_round_to_rectangle (&box, extents);
+	    return CAIRO_STATUS_SUCCESS;
 	}
     }
 
-    return _cairo_pattern_get_extents (pattern, extents);
+    _cairo_pattern_get_extents (pattern, extents);
+    return CAIRO_STATUS_SUCCESS;
 }
 
 static unsigned long
@@ -5200,6 +4371,88 @@ _cairo_pattern_reset_static_data (void)
 
     for (i = 0; i < ARRAY_LENGTH (freed_pattern_pool); i++)
 	_freed_pool_reset (&freed_pattern_pool[i]);
+}
+
+static void
+_cairo_debug_print_surface_pattern (FILE *file,
+				    const cairo_surface_pattern_t *pattern)
+{
+    printf ("  surface type: %d\n", pattern->surface->type);
+}
+
+static void
+_cairo_debug_print_linear_pattern (FILE *file,
+				    const cairo_linear_pattern_t *pattern)
+{
+}
+
+static void
+_cairo_debug_print_radial_pattern (FILE *file,
+				   const cairo_radial_pattern_t *pattern)
+{
+}
+
+static void
+_cairo_debug_print_mesh_pattern (FILE *file,
+				 const cairo_mesh_pattern_t *pattern)
+{
+}
+
+void
+_cairo_debug_print_pattern (FILE *file, const cairo_pattern_t *pattern)
+{
+    const char *s;
+    switch (pattern->type) {
+    case CAIRO_PATTERN_TYPE_SOLID: s = "solid"; break;
+    case CAIRO_PATTERN_TYPE_SURFACE: s = "surface"; break;
+    case CAIRO_PATTERN_TYPE_LINEAR: s = "linear"; break;
+    case CAIRO_PATTERN_TYPE_RADIAL: s = "radial"; break;
+    case CAIRO_PATTERN_TYPE_MESH: s = "mesh"; break;
+    default: s = "invalid"; ASSERT_NOT_REACHED; break;
+    }
 
-    _cairo_pattern_reset_solid_surface_cache ();
+    fprintf (file, "pattern: %s\n", s);
+    if (pattern->type == CAIRO_PATTERN_TYPE_SOLID)
+	return;
+
+    switch (pattern->extend) {
+    case CAIRO_EXTEND_NONE: s = "none"; break;
+    case CAIRO_EXTEND_REPEAT: s = "repeat"; break;
+    case CAIRO_EXTEND_REFLECT: s = "reflect"; break;
+    case CAIRO_EXTEND_PAD: s = "pad"; break;
+    default: s = "invalid"; ASSERT_NOT_REACHED; break;
+    }
+    fprintf (file, "  extend: %s\n", s);
+
+    switch (pattern->filter) {
+    case CAIRO_FILTER_FAST: s = "fast"; break;
+    case CAIRO_FILTER_GOOD: s = "good"; break;
+    case CAIRO_FILTER_BEST: s = "best"; break;
+    case CAIRO_FILTER_NEAREST: s = "nearest"; break;
+    case CAIRO_FILTER_BILINEAR: s = "bilinear"; break;
+    case CAIRO_FILTER_GAUSSIAN: s = "guassian"; break;
+    default: s = "invalid"; ASSERT_NOT_REACHED; break;
+    }
+    fprintf (file, "  filter: %s\n", s);
+    fprintf (file, "  matrix: [%g %g %g %g %g %g]\n",
+	     pattern->matrix.xx, pattern->matrix.yx,
+	     pattern->matrix.xy, pattern->matrix.yy,
+	     pattern->matrix.x0, pattern->matrix.y0);
+    switch (pattern->type) {
+    default:
+    case CAIRO_PATTERN_TYPE_SOLID:
+	break;
+    case CAIRO_PATTERN_TYPE_SURFACE:
+	_cairo_debug_print_surface_pattern (file, (cairo_surface_pattern_t *)pattern);
+	break;
+    case CAIRO_PATTERN_TYPE_LINEAR:
+	_cairo_debug_print_linear_pattern (file, (cairo_linear_pattern_t *)pattern);
+	break;
+    case CAIRO_PATTERN_TYPE_RADIAL:
+	_cairo_debug_print_radial_pattern (file, (cairo_radial_pattern_t *)pattern);
+	break;
+    case CAIRO_PATTERN_TYPE_MESH:
+	_cairo_debug_print_mesh_pattern (file, (cairo_mesh_pattern_t *)pattern);
+	break;
+    }
 }
diff --git a/src/cairo-pdf-operators.c b/src/cairo-pdf-operators.c
index 58c6472..fceaf1c 100644
--- a/src/cairo-pdf-operators.c
+++ b/src/cairo-pdf-operators.c
@@ -769,7 +769,7 @@ _cairo_pdf_operators_emit_stroke (cairo_pdf_operators_t		*pdf_operators,
 				  const cairo_matrix_t		*ctm_inverse,
 				  const char			*pdf_operator)
 {
-    cairo_status_t status;
+    cairo_int_status_t status;
     cairo_matrix_t m, path_transform;
     cairo_bool_t has_ctm = TRUE;
     double scale = 1.0;
diff --git a/src/cairo-pdf-shading.c b/src/cairo-pdf-shading.c
index 6b7bcea..646e2cd 100644
--- a/src/cairo-pdf-shading.c
+++ b/src/cairo-pdf-shading.c
@@ -39,6 +39,8 @@
 #if CAIRO_HAS_PDF_OPERATORS
 
 #include "cairo-pdf-shading-private.h"
+
+#include "cairo-array-private.h"
 #include "cairo-error-private.h"
 #include <float.h>
 
diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c
index b115fd1..3f2d047 100644
--- a/src/cairo-pdf-surface.c
+++ b/src/cairo-pdf-surface.c
@@ -41,10 +41,13 @@
 
 #define _BSD_SOURCE /* for snprintf() */
 #include "cairoint.h"
+
 #include "cairo-pdf.h"
 #include "cairo-pdf-surface-private.h"
 #include "cairo-pdf-operators-private.h"
 #include "cairo-pdf-shading-private.h"
+
+#include "cairo-array-private.h"
 #include "cairo-analysis-surface-private.h"
 #include "cairo-composite-rectangles-private.h"
 #include "cairo-default-context-private.h"
@@ -1122,17 +1125,19 @@ _get_source_surface_size (cairo_surface_t         *source,
 	     *height = extents->height;
 	} else {
 	    cairo_rectangle_int_t surf_extents;
-	    double x, y, w, h;
+	    cairo_box_t box;
 	    cairo_bool_t bounded;
 
 	    if (_cairo_surface_is_snapshot (source))
 		source = _cairo_surface_snapshot_get_target (source);
 
-	    cairo_recording_surface_ink_extents (source, &x, &y,&w, &h);
-	    extents->x = floor (x);
-	    extents->y = floor (y);
-	    extents->width = ceil (x + w) - extents->x;
-	    extents->height = ceil (y + h) - extents->y;
+	    status = _cairo_recording_surface_get_ink_bbox ((cairo_recording_surface_t *)source,
+							    &box, NULL);
+	    if (unlikely (status))
+		return status;
+
+	    _cairo_box_round_to_rectangle (&box, extents);
+
 	    bounded = _cairo_surface_get_extents (source, &surf_extents);
 	    *width = surf_extents.width;
 	    *height = surf_extents.height;
@@ -2358,16 +2363,9 @@ _cairo_pdf_surface_emit_padded_image_surface (cairo_pdf_surface_t     *surface,
         _cairo_pattern_init_for_surface (&pad_pattern, &image->base);
         cairo_matrix_init_translate (&pad_pattern.base.matrix, -x, -y);
         pad_pattern.base.extend = CAIRO_EXTEND_PAD;
-        status = _cairo_surface_composite (CAIRO_OPERATOR_SOURCE,
-                                           &pad_pattern.base,
-                                           NULL,
-                                           pad_image,
-                                           0, 0,
-                                           0, 0,
-                                           0, 0,
-                                           rect.width,
-                                           rect.height,
-					   NULL);
+        status = _cairo_surface_paint (pad_image,
+				       CAIRO_OPERATOR_SOURCE, &pad_pattern.base,
+				       NULL);
         _cairo_pattern_fini (&pad_pattern.base);
         if (unlikely (status))
             goto BAIL;
@@ -5917,11 +5915,10 @@ _cairo_pdf_surface_paint (void			*abstract_surface,
     cairo_pdf_smask_group_t *group;
     cairo_pdf_resource_t pattern_res, gstate_res;
     cairo_composite_rectangles_t extents;
-    cairo_rectangle_int_t unbounded;
     cairo_int_status_t status;
 
-    _cairo_pdf_surface_get_extents (surface, &unbounded);
-    status = _cairo_composite_rectangles_init_for_paint (&extents, &unbounded,
+    status = _cairo_composite_rectangles_init_for_paint (&extents,
+							 &surface->base,
 							 op, source, clip);
     if (unlikely (status))
 	return status;
@@ -6037,11 +6034,10 @@ _cairo_pdf_surface_mask (void			*abstract_surface,
     cairo_pdf_surface_t *surface = abstract_surface;
     cairo_pdf_smask_group_t *group;
     cairo_composite_rectangles_t extents;
-    cairo_rectangle_int_t unbounded;
     cairo_int_status_t status;
 
-    _cairo_pdf_surface_get_extents (surface, &unbounded);
-    status = _cairo_composite_rectangles_init_for_mask (&extents, &unbounded,
+    status = _cairo_composite_rectangles_init_for_mask (&extents,
+							&surface->base,
 							op, source, mask, clip);
     if (unlikely (status))
 	return status;
@@ -6166,11 +6162,10 @@ _cairo_pdf_surface_stroke (void			*abstract_surface,
     cairo_pdf_smask_group_t *group;
     cairo_pdf_resource_t pattern_res, gstate_res;
     cairo_composite_rectangles_t extents;
-    cairo_rectangle_int_t unbounded;
     cairo_int_status_t status;
 
-    _cairo_pdf_surface_get_extents (surface, &unbounded);
-    status = _cairo_composite_rectangles_init_for_stroke (&extents, &unbounded,
+    status = _cairo_composite_rectangles_init_for_stroke (&extents,
+							  &surface->base,
 							  op, source,
 							  path, style, ctm,
 							  clip);
@@ -6305,10 +6300,9 @@ _cairo_pdf_surface_fill (void			*abstract_surface,
     cairo_pdf_smask_group_t *group;
     cairo_pdf_resource_t pattern_res, gstate_res;
     cairo_composite_rectangles_t extents;
-    cairo_rectangle_int_t unbounded;
 
-    _cairo_pdf_surface_get_extents (surface, &unbounded);
-    status = _cairo_composite_rectangles_init_for_fill (&extents, &unbounded,
+    status = _cairo_composite_rectangles_init_for_fill (&extents,
+							&surface->base,
 							op, source, path,
 							clip);
     if (unlikely (status))
@@ -6471,7 +6465,6 @@ _cairo_pdf_surface_fill_stroke (void			*abstract_surface,
     cairo_int_status_t status;
     cairo_pdf_resource_t fill_pattern_res, stroke_pattern_res, gstate_res;
     cairo_composite_rectangles_t extents;
-    cairo_rectangle_int_t unbounded;
 
     /* During analysis we return unsupported and let the _fill and
      * _stroke functions that are on the fallback path do the analysis
@@ -6498,8 +6491,8 @@ _cairo_pdf_surface_fill_stroke (void			*abstract_surface,
     /* Compute the operation extents using the stroke which will naturally
      * be larger than the fill extents.
      */
-    _cairo_pdf_surface_get_extents (surface, &unbounded);
-    status = _cairo_composite_rectangles_init_for_stroke (&extents, &unbounded,
+    status = _cairo_composite_rectangles_init_for_stroke (&extents,
+							  &surface->base,
 							  stroke_op, stroke_source,
 							  path, stroke_style, stroke_ctm,
 							  clip);
@@ -6630,12 +6623,11 @@ _cairo_pdf_surface_show_text_glyphs (void			*abstract_surface,
     cairo_pdf_smask_group_t *group;
     cairo_pdf_resource_t pattern_res, gstate_res;
     cairo_composite_rectangles_t extents;
-    cairo_rectangle_int_t unbounded;
     cairo_bool_t overlap;
     cairo_int_status_t status;
 
-    _cairo_pdf_surface_get_extents (surface, &unbounded);
-    status = _cairo_composite_rectangles_init_for_glyphs (&extents, &unbounded,
+    status = _cairo_composite_rectangles_init_for_glyphs (&extents,
+							  &surface->base,
 							  op, source,
 							  scaled_font,
 							  glyphs, num_glyphs,
@@ -6798,37 +6790,24 @@ static const cairo_surface_backend_t cairo_pdf_surface_backend = {
 
     NULL, /* acquire_source_image */
     NULL, /* release_source_image */
-    NULL, /* acquire_dest_image */
-    NULL, /* release_dest_image */
-    NULL, /* clone_similar */
-    NULL, /* composite */
-    NULL, /* fill_rectangles */
-    NULL, /* composite_trapezoids */
-    NULL, /* create_span_renderer */
-    NULL, /* check_span_renderer */
+    NULL, /* snapshot */
+
     NULL,  /* _cairo_pdf_surface_copy_page */
     _cairo_pdf_surface_show_page,
+
     _cairo_pdf_surface_get_extents,
-    NULL, /* old_show_glyphs */
     _cairo_pdf_surface_get_font_options,
+
     NULL, /* flush */
     NULL, /* mark_dirty_rectangle */
-    NULL, /* scaled_font_fini */
-    NULL, /* scaled_glyph_fini */
 
     /* Here are the drawing functions */
-
     _cairo_pdf_surface_paint,
     _cairo_pdf_surface_mask,
     _cairo_pdf_surface_stroke,
     _cairo_pdf_surface_fill,
-    NULL, /* show_glyphs */
-    NULL, /* snapshot */
-
-    NULL, /* is_compatible */
     _cairo_pdf_surface_fill_stroke,
-    NULL, /* create_solid_pattern_surface */
-    NULL, /* can_repaint_solid_pattern_surface */
+    NULL, /* show_glyphs */
     _cairo_pdf_surface_has_show_text_glyphs,
     _cairo_pdf_surface_show_text_glyphs,
 };
diff --git a/src/cairo-polygon-intersect.c b/src/cairo-polygon-intersect.c
index e2ed6e9..d9d0cf2 100644
--- a/src/cairo-polygon-intersect.c
+++ b/src/cairo-polygon-intersect.c
@@ -1454,13 +1454,78 @@ _cairo_polygon_intersect (cairo_polygon_t *a, int winding_a,
     }
     assert (j == num_events);
 
-    //fprintf(stderr, "a "); _cairo_debug_print_polygon(stderr,a);
-    //fprintf(stderr, "b "); _cairo_debug_print_polygon(stderr,b);
+#if 0
+    {
+	FILE *file = fopen ("clip_a.txt", "w");
+	_cairo_debug_print_polygon (file, a);
+	fclose (file);
+    }
+    {
+	FILE *file = fopen ("clip_b.txt", "w");
+	_cairo_debug_print_polygon (file, b);
+	fclose (file);
+    }
+#endif
 
     a->num_edges = 0;
     status = intersection_sweep (event_ptrs, num_events, a);
     if (events != stack_events)
 	free (events);
 
+#if 0
+    {
+	FILE *file = fopen ("clip_result.txt", "w");
+	_cairo_debug_print_polygon (file, a);
+	fclose (file);
+    }
+#endif
+
+    return status;
+}
+
+cairo_status_t
+_cairo_polygon_intersect_with_boxes (cairo_polygon_t *polygon,
+				     cairo_fill_rule_t *winding,
+				     cairo_box_t *boxes,
+				     int num_boxes)
+{
+    cairo_polygon_t b;
+    cairo_status_t status;
+    int n;
+
+    if (num_boxes == 0) {
+	polygon->num_edges = 0;
+	return CAIRO_STATUS_SUCCESS;
+    }
+
+    for (n = 0; n < num_boxes; n++) {
+	if (polygon->extents.p1.x >= boxes[n].p1.x &&
+	    polygon->extents.p2.x <= boxes[n].p2.x &&
+	    polygon->extents.p1.y >= boxes[n].p1.y &&
+	    polygon->extents.p2.y <= boxes[n].p2.y)
+	{
+	    return CAIRO_STATUS_SUCCESS;
+	}
+    }
+
+    _cairo_polygon_init (&b, NULL, 0);
+    for (n = 0; n < num_boxes; n++) {
+	cairo_point_t p1, p2;
+
+	p1.y = boxes[n].p1.y;
+	p2.y = boxes[n].p2.y;
+
+	p2.x = p1.x = boxes[n].p1.x;
+	_cairo_polygon_add_external_edge (&b, &p1, &p2);
+
+	p2.x = p1.x = boxes[n].p2.x;
+	_cairo_polygon_add_external_edge (&b, &p2, &p1);
+    }
+
+    status = _cairo_polygon_intersect (polygon, *winding,
+				       &b, CAIRO_FILL_RULE_WINDING);
+    _cairo_polygon_fini (&b);
+
+    *winding = CAIRO_FILL_RULE_WINDING;
     return status;
 }
diff --git a/src/cairo-polygon.c b/src/cairo-polygon.c
index 6436712..a44cba3 100644
--- a/src/cairo-polygon.c
+++ b/src/cairo-polygon.c
@@ -127,19 +127,19 @@ _cairo_polygon_init_boxes (cairo_polygon_t *polygon,
     polygon->num_limits = 0;
 
     for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
-	    for (i = 0; i < chunk->count; i++) {
-		    cairo_point_t p1, p2;
-
-		    p1 = chunk->base[i].p1;
-		    p2.x = p1.x;
-		    p2.y = chunk->base[i].p2.y;
-		    _cairo_polygon_add_edge (polygon, &p1, &p2, 1);
-
-		    p1 = chunk->base[i].p2;
-		    p2.x = p1.x;
-		    p2.y = chunk->base[i].p1.y;
-		    _cairo_polygon_add_edge (polygon, &p1, &p2, 1);
-	    }
+	for (i = 0; i < chunk->count; i++) {
+	    cairo_point_t p1, p2;
+
+	    p1 = chunk->base[i].p1;
+	    p2.x = p1.x;
+	    p2.y = chunk->base[i].p2.y;
+	    _cairo_polygon_add_edge (polygon, &p1, &p2, 1);
+
+	    p1 = chunk->base[i].p2;
+	    p2.x = p1.x;
+	    p2.y = chunk->base[i].p1.y;
+	    _cairo_polygon_add_edge (polygon, &p1, &p2, 1);
+	}
     }
 
     return polygon->status;
@@ -491,3 +491,29 @@ _cairo_polygon_add_contour (cairo_polygon_t *polygon,
 
     return polygon->status;
 }
+
+void
+_cairo_polygon_translate (cairo_polygon_t *polygon, int dx, int dy)
+{
+    int n;
+
+    dx = _cairo_fixed_from_int (dx);
+    dy = _cairo_fixed_from_int (dy);
+
+    polygon->extents.p1.x += dx;
+    polygon->extents.p2.x += dx;
+    polygon->extents.p1.y += dy;
+    polygon->extents.p2.y += dy;
+
+    for (n = 0; n < polygon->num_edges; n++) {
+	cairo_edge_t *e = &polygon->edges[n];
+
+	e->top += dy;
+	e->bottom += dy;
+
+	e->line.p1.x += dx;
+	e->line.p2.x += dx;
+	e->line.p1.y += dy;
+	e->line.p2.y += dy;
+    }
+}
diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c
index a804887..dcd2161 100644
--- a/src/cairo-ps-surface.c
+++ b/src/cairo-ps-surface.c
@@ -55,10 +55,14 @@
 
 #define _BSD_SOURCE /* for ctime_r(), snprintf(), strdup() */
 #include "cairoint.h"
+
 #include "cairo-ps.h"
 #include "cairo-ps-surface-private.h"
+
 #include "cairo-pdf-operators-private.h"
 #include "cairo-pdf-shading-private.h"
+
+#include "cairo-array-private.h"
 #include "cairo-composite-rectangles-private.h"
 #include "cairo-default-context-private.h"
 #include "cairo-error-private.h"
@@ -79,7 +83,7 @@
 #include <zlib.h>
 #include <errno.h>
 
-#define DEBUG_PS 0
+#define DEBUG_PS 1
 
 #if DEBUG_PS
 #define DEBUG_FALLBACK(s) \
@@ -1153,41 +1157,40 @@ _extract_ps_surface (cairo_surface_t	 *surface,
 		     cairo_ps_surface_t **ps_surface)
 {
     cairo_surface_t *target;
-    cairo_status_t status_ignored;
 
     if (surface->status)
 	return FALSE;
     if (surface->finished) {
         if (set_error_on_failure)
-            status_ignored = _cairo_surface_set_error (surface,
-                                                       _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
+	    _cairo_surface_set_error (surface,
+				      _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
 	return FALSE;
     }
 
     if (! _cairo_surface_is_paginated (surface)) {
         if (set_error_on_failure)
-            status_ignored = _cairo_surface_set_error (surface,
-                                                       _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH));
+	    _cairo_surface_set_error (surface,
+				      _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH));
 	return FALSE;
     }
 
     target = _cairo_paginated_surface_get_target (surface);
     if (target->status) {
         if (set_error_on_failure)
-            status_ignored = _cairo_surface_set_error (surface, target->status);
+	    _cairo_surface_set_error (surface, target->status);
 	return FALSE;
     }
     if (target->finished) {
         if (set_error_on_failure)
-            status_ignored = _cairo_surface_set_error (surface,
-                                                       _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
+	    _cairo_surface_set_error (surface,
+				      _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
 	return FALSE;
     }
 
     if (! _cairo_surface_is_ps (target)) {
         if (set_error_on_failure)
-            status_ignored = _cairo_surface_set_error (surface,
-                                                       _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH));
+	    _cairo_surface_set_error (surface,
+				      _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH));
 	return FALSE;
     }
 
@@ -1783,7 +1786,7 @@ mask_supported (cairo_ps_surface_t *surface, const cairo_pattern_t *mask)
 	cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) mask;
 	if (surface_pattern->surface->type == CAIRO_SURFACE_TYPE_IMAGE) {
 	    /* check if mask if opaque or bilevel alpha */
-	    if (_cairo_ps_surface_analyze_surface_pattern_transparency (surface, surface_pattern) == CAIRO_STATUS_SUCCESS) {
+	    if (_cairo_ps_surface_analyze_surface_pattern_transparency (surface, surface_pattern) == CAIRO_INT_STATUS_SUCCESS) {
 		surface->ps_level_used = CAIRO_PS_LEVEL_3;
 		return TRUE;
 	    }
@@ -3780,17 +3783,18 @@ _cairo_ps_surface_paint (void			*abstract_surface,
     cairo_ps_surface_t *surface = abstract_surface;
     cairo_output_stream_t *stream = surface->stream;
     cairo_composite_rectangles_t extents;
-    cairo_rectangle_int_t unbounded;
     cairo_status_t status;
 
-    _cairo_ps_surface_get_extents (surface, &unbounded);
-    status = _cairo_composite_rectangles_init_for_paint (&extents, &unbounded,
+    status = _cairo_composite_rectangles_init_for_paint (&extents,
+							 &surface->base,
 							 op, source, clip);
     if (unlikely (status))
 	return status;
 
-    if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
-	return _cairo_ps_surface_analyze_operation (surface, op, source, NULL, &extents.bounded);
+    if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
+	status = _cairo_ps_surface_analyze_operation (surface, op, source, NULL, &extents.bounded);
+	goto cleanup_composite;
+    }
 
     assert (_cairo_ps_surface_operation_supported (surface, op, source, NULL, &extents.bounded));
 
@@ -3801,7 +3805,7 @@ _cairo_ps_surface_paint (void			*abstract_surface,
 
     status = _cairo_ps_surface_set_clip (surface, &extents);
     if (unlikely (status))
-	return status;
+	goto cleanup_composite;
 
     if (source->type == CAIRO_PATTERN_TYPE_SURFACE &&
 	(source->extend == CAIRO_EXTEND_NONE ||
@@ -3809,26 +3813,28 @@ _cairo_ps_surface_paint (void			*abstract_surface,
     {
 	status = _cairo_pdf_operators_flush (&surface->pdf_operators);
 	if (unlikely (status))
-	    return status;
+	    goto cleanup_composite;
 
 	_cairo_output_stream_printf (stream, "q\n");
 	status = _cairo_ps_surface_paint_surface (surface,
 						 (cairo_surface_pattern_t *) source,
 						  &extents.bounded, op, FALSE);
 	if (unlikely (status))
-	    return status;
+	    goto cleanup_composite;
 
 	_cairo_output_stream_printf (stream, "Q\n");
     } else {
 	status = _cairo_ps_surface_emit_pattern (surface, source, &extents.bounded, op);
 	if (unlikely (status))
-	    return status;
+	    goto cleanup_composite;
 
 	_cairo_output_stream_printf (stream, "0 0 %f %f rectfill\n",
 				     surface->width, surface->height);
     }
 
-    return CAIRO_STATUS_SUCCESS;
+cleanup_composite:
+    _cairo_composite_rectangles_fini (&extents);
+    return status;
 }
 
 static cairo_int_status_t
@@ -3841,17 +3847,18 @@ _cairo_ps_surface_mask (void			*abstract_surface,
     cairo_ps_surface_t *surface = abstract_surface;
     cairo_output_stream_t *stream = surface->stream;
     cairo_composite_rectangles_t extents;
-    cairo_rectangle_int_t unbounded;
     cairo_status_t status;
 
-    _cairo_ps_surface_get_extents (surface, &unbounded);
-    status = _cairo_composite_rectangles_init_for_mask (&extents, &unbounded,
+    status = _cairo_composite_rectangles_init_for_mask (&extents,
+						       	&surface->base,
 							op, source, mask, clip);
     if (unlikely (status))
 	return status;
 
-    if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
-	return _cairo_ps_surface_analyze_operation (surface, op, source, mask, &extents.bounded);
+    if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
+	status = _cairo_ps_surface_analyze_operation (surface, op, source, mask, &extents.bounded);
+	goto cleanup_composite;
+    }
 
     assert (_cairo_ps_surface_operation_supported (surface, op, source, mask, &extents.bounded));
 
@@ -3862,22 +3869,24 @@ _cairo_ps_surface_mask (void			*abstract_surface,
 
     status = _cairo_ps_surface_set_clip (surface, &extents);
     if (unlikely (status))
-	return status;
+	goto cleanup_composite;
 
     status = _cairo_ps_surface_emit_pattern (surface, source, &extents.bounded, op);
     if (unlikely (status))
-	return status;
+	goto cleanup_composite;
 
     _cairo_output_stream_printf (stream, "q\n");
     status = _cairo_ps_surface_paint_surface (surface,
 					      (cairo_surface_pattern_t *) mask,
 					      &extents.bounded, op, TRUE);
     if (unlikely (status))
-	return status;
+	goto cleanup_composite;
 
     _cairo_output_stream_printf (stream, "Q\n");
 
-    return CAIRO_STATUS_SUCCESS;
+cleanup_composite:
+    _cairo_composite_rectangles_fini (&extents);
+    return status;
 }
 
 static cairo_int_status_t
@@ -3894,11 +3903,10 @@ _cairo_ps_surface_stroke (void			*abstract_surface,
 {
     cairo_ps_surface_t *surface = abstract_surface;
     cairo_composite_rectangles_t extents;
-    cairo_rectangle_int_t unbounded;
     cairo_int_status_t status;
 
-    _cairo_ps_surface_get_extents (surface, &unbounded);
-    status = _cairo_composite_rectangles_init_for_stroke (&extents, &unbounded,
+    status = _cairo_composite_rectangles_init_for_stroke (&extents,
+							  &surface->base,
 							  op, source,
 							  path, style, ctm,
 							  clip);
@@ -3906,21 +3914,27 @@ _cairo_ps_surface_stroke (void			*abstract_surface,
 	return status;
 
     /* use the more accurate extents */
-    if (extents.is_bounded) {
+    {
+	cairo_rectangle_int_t r;
+	cairo_box_t b;
+
 	status = _cairo_path_fixed_stroke_extents (path, style,
 						   ctm, ctm_inverse,
 						   tolerance,
-						   &extents.mask);
+						   &r);
 	if (unlikely (status))
-	    return status;
+	    goto cleanup_composite;
 
-	if (! _cairo_rectangle_intersect (&extents.bounded, &extents.mask))
-	    return CAIRO_STATUS_SUCCESS;
+	_cairo_box_from_rectangle (&b, &r);
+	status = _cairo_composite_rectangles_intersect_mask_extents (&extents, &b);
+	if (unlikely (status))
+	    goto cleanup_composite;
     }
 
-
-    if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
-	return _cairo_ps_surface_analyze_operation (surface, op, source, NULL, &extents.bounded);
+    if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
+	status = _cairo_ps_surface_analyze_operation (surface, op, source, NULL, &extents.bounded);
+	goto cleanup_composite;
+    }
 
     assert (_cairo_ps_surface_operation_supported (surface, op, source, NULL, &extents.bounded));
 
@@ -3931,17 +3945,21 @@ _cairo_ps_surface_stroke (void			*abstract_surface,
 
     status = _cairo_ps_surface_set_clip (surface, &extents);
     if (unlikely (status))
-	return status;
+	goto cleanup_composite;
 
     status = _cairo_ps_surface_emit_pattern (surface, source, &extents.bounded, op);
     if (unlikely (status))
-	return status;
+	goto cleanup_composite;
+
+    status = _cairo_pdf_operators_stroke (&surface->pdf_operators,
+					  path,
+					  style,
+					  ctm,
+					  ctm_inverse);
 
-    return _cairo_pdf_operators_stroke (&surface->pdf_operators,
-					path,
-					style,
-					ctm,
-					ctm_inverse);
+cleanup_composite:
+    _cairo_composite_rectangles_fini (&extents);
+    return status;
 }
 
 static cairo_int_status_t
@@ -3956,29 +3974,35 @@ _cairo_ps_surface_fill (void		*abstract_surface,
 {
     cairo_ps_surface_t *surface = abstract_surface;
     cairo_composite_rectangles_t extents;
-    cairo_rectangle_int_t unbounded;
     cairo_int_status_t status;
 
-    _cairo_ps_surface_get_extents (surface, &unbounded);
-    status = _cairo_composite_rectangles_init_for_fill (&extents, &unbounded,
+    status = _cairo_composite_rectangles_init_for_fill (&extents,
+							&surface->base,
 							op, source, path,
 							clip);
     if (unlikely (status))
 	return status;
 
     /* use the more accurate extents */
-    if (extents.is_bounded) {
+    {
+	cairo_rectangle_int_t r;
+	cairo_box_t b;
+
 	_cairo_path_fixed_fill_extents (path,
 					fill_rule,
 					tolerance,
-					&extents.mask);
+					&r);
 
-	if (! _cairo_rectangle_intersect (&extents.bounded, &extents.mask))
-	    return CAIRO_STATUS_SUCCESS;
+	_cairo_box_from_rectangle (&b, &r);
+	status = _cairo_composite_rectangles_intersect_mask_extents (&extents, &b);
+	if (unlikely (status))
+	    goto cleanup_composite;
     }
 
-    if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
-	return _cairo_ps_surface_analyze_operation (surface, op, source, NULL, &extents.bounded);
+    if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
+	status = _cairo_ps_surface_analyze_operation (surface, op, source, NULL, &extents.bounded);
+	goto cleanup_composite;
+    }
 
     assert (_cairo_ps_surface_operation_supported (surface, op, source, NULL, &extents.bounded));
 
@@ -3989,11 +4013,11 @@ _cairo_ps_surface_fill (void		*abstract_surface,
 
     status = _cairo_pdf_operators_flush (&surface->pdf_operators);
     if (unlikely (status))
-	return status;
+	goto cleanup_composite;
 
     status = _cairo_ps_surface_set_clip (surface, &extents);
     if (unlikely (status))
-	return status;
+	goto cleanup_composite;
 
     if (source->type == CAIRO_PATTERN_TYPE_SURFACE &&
 	(source->extend == CAIRO_EXTEND_NONE ||
@@ -4005,26 +4029,28 @@ _cairo_ps_surface_fill (void		*abstract_surface,
 					     path,
 					     fill_rule);
 	if (unlikely (status))
-	    return status;
+	    goto cleanup_composite;
 
 	status = _cairo_ps_surface_paint_surface (surface,
 						 (cairo_surface_pattern_t *) source,
 						  &extents.bounded, op, FALSE);
 	if (unlikely (status))
-	    return status;
+	    goto cleanup_composite;
 
 	_cairo_output_stream_printf (surface->stream, "Q\n");
 	_cairo_pdf_operators_reset (&surface->pdf_operators);
     } else {
 	status = _cairo_ps_surface_emit_pattern (surface, source, &extents.bounded, op);
 	if (unlikely (status))
-	    return status;
+	    goto cleanup_composite;
 
 	status = _cairo_pdf_operators_fill (&surface->pdf_operators,
 					    path,
 					    fill_rule);
     }
 
+cleanup_composite:
+    _cairo_composite_rectangles_fini (&extents);
     return status;
 }
 
@@ -4050,26 +4076,23 @@ _cairo_ps_surface_show_text_glyphs (void		       *abstract_surface,
 {
     cairo_ps_surface_t *surface = abstract_surface;
     cairo_composite_rectangles_t extents;
-    cairo_rectangle_int_t unbounded;
     cairo_bool_t overlap;
     cairo_status_t status;
 
-    _cairo_ps_surface_get_extents (surface, &unbounded);
-    status = _cairo_composite_rectangles_init_for_glyphs (&extents, &unbounded,
+    status = _cairo_composite_rectangles_init_for_glyphs (&extents,
+							  &surface->base,
 							  op, source,
 							  scaled_font,
 							  glyphs, num_glyphs,
 							  clip,
 							  &overlap);
-    if (unlikely (status)) {
-	if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
-	    return CAIRO_INT_STATUS_SUCCESS;
-
+    if (unlikely (status))
 	return status;
-    }
 
-    if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
-	return _cairo_ps_surface_analyze_operation (surface, op, source, NULL, &extents.bounded);
+    if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
+	status = _cairo_ps_surface_analyze_operation (surface, op, source, NULL, &extents.bounded);
+	goto cleanup_composite;
+    }
 
     assert (_cairo_ps_surface_operation_supported (surface, op, source, NULL, &extents.bounded));
 
@@ -4080,18 +4103,22 @@ _cairo_ps_surface_show_text_glyphs (void		       *abstract_surface,
 
     status = _cairo_ps_surface_set_clip (surface, &extents);
     if (unlikely (status))
-	return status;
+	goto cleanup_composite;
 
     status = _cairo_ps_surface_emit_pattern (surface, source, &extents.bounded, op);
     if (unlikely (status))
-	return status;
+	goto cleanup_composite;
+
+    status = _cairo_pdf_operators_show_text_glyphs (&surface->pdf_operators,
+						    utf8, utf8_len,
+						    glyphs, num_glyphs,
+						    clusters, num_clusters,
+						    cluster_flags,
+						    scaled_font);
 
-    return _cairo_pdf_operators_show_text_glyphs (&surface->pdf_operators,
-						  utf8, utf8_len,
-						  glyphs, num_glyphs,
-						  clusters, num_clusters,
-						  cluster_flags,
-						  scaled_font);
+cleanup_composite:
+    _cairo_composite_rectangles_fini (&extents);
+    return status;
 }
 
 static void
@@ -4222,23 +4249,16 @@ static const cairo_surface_backend_t cairo_ps_surface_backend = {
 
     NULL, /* acquire_source_image */
     NULL, /* release_source_image */
-    NULL, /* acquire_dest_image */
-    NULL, /* release_dest_image */
-    NULL, /* clone_similar */
-    NULL, /* composite */
-    NULL, /* fill_rectangles */
-    NULL, /* composite_trapezoids */
-    NULL, /* create_span_renderer */
-    NULL, /* check_span_renderer */
+    NULL, /* snapshot */
+
     NULL, /* cairo_ps_surface_copy_page */
     _cairo_ps_surface_show_page,
+
     _cairo_ps_surface_get_extents,
-    NULL, /* old_show_glyphs */
     _cairo_ps_surface_get_font_options,
+
     NULL, /* flush */
     NULL, /* mark_dirty_rectangle */
-    NULL, /* scaled_font_fini */
-    NULL, /* scaled_glyph_fini */
 
     /* Here are the drawing functions */
 
@@ -4246,13 +4266,8 @@ static const cairo_surface_backend_t cairo_ps_surface_backend = {
     _cairo_ps_surface_mask,
     _cairo_ps_surface_stroke,
     _cairo_ps_surface_fill,
+    NULL, /* fill-stroke */
     NULL, /* show_glyphs */
-    NULL, /* snapshot */
-
-    NULL, /* is_compatible */
-    NULL, /* fill_stroke */
-    NULL, /* create_solid_pattern_surface */
-    NULL, /* can_repaint_solid_pattern_surface */
     _cairo_ps_surface_has_show_text_glyphs,
     _cairo_ps_surface_show_text_glyphs,
 };
diff --git a/src/cairo-quartz-image-surface.c b/src/cairo-quartz-image-surface.c
index bbe5fa7..b04c421 100644
--- a/src/cairo-quartz-image-surface.c
+++ b/src/cairo-quartz-image-surface.c
@@ -60,13 +60,22 @@ _cairo_quartz_image_surface_create_similar (void *asurface,
 					    int width,
 					    int height)
 {
-    cairo_surface_t *result;
     cairo_surface_t *isurf =
 	_cairo_image_surface_create_with_content (content, width, height);
-    if (cairo_surface_status(isurf))
-	return isurf;
+    cairo_surface_t *result = cairo_quartz_image_surface_create (isurf);
+    cairo_surface_destroy (isurf);
 
-    result = cairo_quartz_image_surface_create (isurf);
+    return result;
+}
+
+static cairo_surface_t *
+_cairo_quartz_image_surface_create_similar_image (void *asurface,
+						  cairo_format_t format,
+						  int width,
+						  int height)
+{
+    cairo_surface_t *isurf = cairo_image_surface_create (format, width, height);
+    cairo_surface_t *result = cairo_quartz_image_surface_create (isurf);
     cairo_surface_destroy (isurf);
 
     return result;
@@ -96,23 +105,19 @@ _cairo_quartz_image_surface_acquire_source_image (void *asurface,
     return CAIRO_STATUS_SUCCESS;
 }
 
-static cairo_status_t
-_cairo_quartz_image_surface_acquire_dest_image (void *asurface,
-						cairo_rectangle_int_t *interest_rect,
-						cairo_image_surface_t **image_out,
-						cairo_rectangle_int_t *image_rect,
-						void **image_extra)
+static cairo_surface_t *
+_cairo_quartz_image_surface_map_to_image (void *asurface,
+					  const cairo_rectangle_int_t *extents)
 {
     cairo_quartz_image_surface_t *surface = (cairo_quartz_image_surface_t *) asurface;
+    return _cairo_surface_create_for_rectangle_int (surface->imageSurface, extents);
+}
 
-    *image_out = surface->imageSurface;
-    image_rect->x = 0;
-    image_rect->y = 0;
-    image_rect->width = surface->width;
-    image_rect->height = surface->height;
-    *image_extra = NULL;
-
-    return CAIRO_STATUS_SUCCESS;
+static cairo_int_status_t
+_cairo_quartz_image_surface_unmap_image (void *asurface,
+					 cairo_image_surface_t *image)
+{
+    cairo_surface_destroy (&image->base);
 }
 
 static cairo_bool_t
@@ -123,7 +128,7 @@ _cairo_quartz_image_surface_get_extents (void *asurface,
 
     extents->x = 0;
     extents->y = 0;
-    extents->width = surface->width;
+    extents->width  = surface->width;
     extents->height = surface->height;
     return TRUE;
 }
@@ -139,6 +144,8 @@ _cairo_quartz_image_surface_flush (void *asurface)
     CGImageRef oldImage = surface->image;
     CGImageRef newImage = NULL;
 
+    /* XXX only flush if the image has been modified. */
+
     /* To be released by the ReleaseCallback */
     cairo_surface_reference ((cairo_surface_t*) surface->imageSurface);
 
@@ -158,6 +165,82 @@ _cairo_quartz_image_surface_flush (void *asurface)
     return CAIRO_STATUS_SUCCESS;
 }
 
+static cairo_int_status_t
+_cairo_quartz_image_surface_paint (void			*abstract_surface,
+				   cairo_operator_t		 op,
+				   const cairo_pattern_t	*source,
+				   const cairo_clip_t		*clip)
+{
+    cairo_quartz_image_surface_t *surface = abstract_surface;
+    return _cairo_surface_paint (&surface->imageSurface->base,
+				 op, source, clip);
+}
+
+static cairo_int_status_t
+_cairo_quartz_image_surface_mask (void				*abstract_surface,
+				  cairo_operator_t		 op,
+				  const cairo_pattern_t		*source,
+				  const cairo_pattern_t		*mask,
+				  const cairo_clip_t		*clip)
+{
+    cairo_quartz_image_surface_t *surface = abstract_surface;
+    return _cairo_surface_mask (&surface->imageSurface->base,
+				op, source, mask, clip);
+}
+
+static cairo_int_status_t
+_cairo_quartz_image_surface_stroke (void			*abstract_surface,
+				    cairo_operator_t		 op,
+				    const cairo_pattern_t	*source,
+				    const cairo_path_fixed_t	*path,
+				    const cairo_stroke_style_t	*style,
+				    const cairo_matrix_t	*ctm,
+				    const cairo_matrix_t	*ctm_inverse,
+				    double			 tolerance,
+				    cairo_antialias_t		 antialias,
+				    const cairo_clip_t		*clip)
+{
+    cairo_quartz_image_surface_t *surface = abstract_surface;
+    return _cairo_surface_stroke (&surface->imageSurface->base,
+				  op, source, path,
+				  style, ctm, ctm_inverse,
+				  tolerance, antialias, clip);
+}
+
+static cairo_int_status_t
+_cairo_quartz_image_surface_fill (void				*abstract_surface,
+			   cairo_operator_t		 op,
+			   const cairo_pattern_t	*source,
+			   const cairo_path_fixed_t	*path,
+			   cairo_fill_rule_t		 fill_rule,
+			   double			 tolerance,
+			   cairo_antialias_t		 antialias,
+			   const cairo_clip_t		*clip)
+{
+    cairo_quartz_image_surface_t *surface = abstract_surface;
+    return _cairo_surface_fill (&surface->imageSurface->base,
+				op, source, path,
+				fill_rule, tolerance, antialias,
+				clip);
+}
+
+static cairo_int_status_t
+_cairo_quartz_image_surface_glyphs (void			*abstract_surface,
+				    cairo_operator_t		 op,
+				    const cairo_pattern_t	*source,
+				    cairo_glyph_t		*glyphs,
+				    int				 num_glyphs,
+				    cairo_scaled_font_t		*scaled_font,
+				    const cairo_clip_t		*clip)
+{
+    cairo_quartz_image_surface_t *surface = abstract_surface;
+    return _cairo_surface_show_glyphs (&surface->imageSurface->base,
+				       op, source,
+				       glyphs, num_glyphs, scaled_font,
+				       clip, num_remaining);
+}
+
+
 static const cairo_surface_backend_t cairo_quartz_image_surface_backend = {
     CAIRO_SURFACE_TYPE_QUARTZ_IMAGE,
     _cairo_quartz_image_surface_finish,
@@ -165,39 +248,29 @@ static const cairo_surface_backend_t cairo_quartz_image_surface_backend = {
     _cairo_default_context_create,
 
     _cairo_quartz_image_surface_create_similar,
-    NULL, /* create_similar_image */
-    NULL, /* map_to_image */
-    NULL, /* unmap_image */
+    _cairo_quartz_image_surface_create_similar_image,
+    _cairo_quartz_image_surface_map_to_image,
+    _cairo_quartz_image_surface_unmap_image,
 
     _cairo_quartz_image_surface_acquire_source_image,
     NULL, /* release_source_image */
-    _cairo_quartz_image_surface_acquire_dest_image,
-    NULL, /* release_dest_image */
-    NULL, /* clone_similar */
-    NULL, /* composite */
-    NULL, /* fill_rectangles */
-    NULL, /* composite_trapezoids */
-    NULL, /* create_span_renderer */
-    NULL, /* check_span_renderer */
+    NULL, /* snapshot */
+
     NULL, /* copy_page */
     NULL, /* show_page */
+
     _cairo_quartz_image_surface_get_extents,
-    NULL, /* old_show_glyphs */
     NULL, /* get_font_options */
+
     _cairo_quartz_image_surface_flush,
     NULL, /* mark_dirty_rectangle */
-    NULL, /* scaled_font_fini */
-    NULL, /* scaled_glyph_fini */
-
-    NULL, /* paint */
-    NULL, /* mask */
-    NULL, /* stroke */
-    NULL, /* fill */
-    NULL, /* surface_show_glyphs */
-    NULL, /* snapshot */
-    NULL, /* is_similar */
-    NULL  /* fill_stroke */
 
+    _cairo_quartz_image_surface_paint,
+    _cairo_quartz_image_surface_mask,
+    _cairo_quartz_image_surface_stroke,
+    _cairo_quartz_image_surface_fill,
+    NULL  /* fill-stroke */
+    _cairo_quartz_image_surface_glyphs,
 };
 
 /**
@@ -227,6 +300,9 @@ cairo_quartz_image_surface_create (cairo_surface_t *surface)
     cairo_format_t format;
     unsigned char *data;
 
+    if (surface->status)
+	return surface;
+
     if (cairo_surface_get_type(surface) != CAIRO_SURFACE_TYPE_IMAGE)
 	return SURFACE_ERROR_TYPE_MISMATCH;
 
diff --git a/src/cairo-quartz-surface.c b/src/cairo-quartz-surface.c
index 0f015c8..60ce8d1 100644
--- a/src/cairo-quartz-surface.c
+++ b/src/cairo-quartz-surface.c
@@ -39,10 +39,13 @@
 
 #include "cairo-quartz-private.h"
 
+#include "cairo-composite-rectangles-private.h"
+#include "cairo-compositor-private.h"
 #include "cairo-default-context-private.h"
 #include "cairo-error-private.h"
 #include "cairo-image-surface-private.h"
 #include "cairo-pattern-private.h"
+#include "cairo-surface-backend-private.h"
 #include "cairo-surface-clipper-private.h"
 
 #include <dlfcn.h>
@@ -500,8 +503,7 @@ _cairo_cgcontext_set_cairo_operator (CGContextRef context, cairo_operator_t op)
 {
     CGBlendMode blendmode;
 
-    if (op == CAIRO_OPERATOR_DEST)
-	return CAIRO_INT_STATUS_NOTHING_TO_DO;
+    assert (op != CAIRO_OPERATOR_DEST);
 
     /* Quartz doesn't support SATURATE at all. COLOR_DODGE and
      * COLOR_BURN in Quartz follow the ISO32000 definition, but cairo
@@ -538,8 +540,7 @@ _cairo_quartz_surface_set_cairo_operator (cairo_quartz_surface_t *surface, cairo
      * fallbacks, but we have to workaround operators which behave
      * differently in Quartz. */
     if (surface->base.content == CAIRO_CONTENT_ALPHA) {
-	if (op == CAIRO_OPERATOR_ATOP)
-	    return CAIRO_INT_STATUS_NOTHING_TO_DO;
+	assert (op != CAIRO_OPERATOR_ATOP); /* filtered by surface layer */
 
 	if (op == CAIRO_OPERATOR_SOURCE ||
 	    op == CAIRO_OPERATOR_IN ||
@@ -794,7 +795,7 @@ _cairo_surface_to_cgimage (cairo_surface_t *source,
 	cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) source;
 	if (IS_EMPTY (surface)) {
 	    *image_out = NULL;
-	    return CAIRO_STATUS_SUCCESS;
+	    return CAIRO_INT_STATUS_NOTHING_TO_DO;
 	}
 
 	if (_cairo_quartz_is_cgcontext_bitmap_context (surface->cgContext)) {
@@ -924,8 +925,6 @@ _cairo_quartz_cairo_repeating_surface_pattern_to_quartz (cairo_quartz_surface_t
     status = _cairo_surface_to_cgimage (pat_surf, &image);
     if (unlikely (status))
 	return status;
-    if (unlikely (image == NULL))
-	return CAIRO_INT_STATUS_NOTHING_TO_DO;
 
     info = malloc (sizeof (SurfacePatternDrawInfo));
     if (unlikely (!info))
@@ -1082,11 +1081,12 @@ _cairo_quartz_setup_gradient_source (cairo_quartz_drawing_state_t *state,
 
 static cairo_int_status_t
 _cairo_quartz_setup_state (cairo_quartz_drawing_state_t *state,
-			   cairo_quartz_surface_t       *surface,
-			   cairo_operator_t              op,
-			   const cairo_pattern_t        *source,
-			   const cairo_clip_t           *clip)
+			   cairo_composite_rectangles_int_t *extents)
 {
+    cairo_quartz_surface_t       *surface = extents->surface;
+    cairo_operator_t              op = extents->op;
+    const cairo_pattern_t        *source = &extents->surface_pattern.base;
+    const cairo_clip_t           *clip = extents->clip;
     cairo_bool_t needs_temp;
     cairo_status_t status;
 
@@ -1205,8 +1205,6 @@ _cairo_quartz_setup_state (cairo_quartz_drawing_state_t *state,
 	status = _cairo_surface_to_cgimage (pat_surf, &img);
 	if (unlikely (status))
 	    return status;
-	if (unlikely (img == NULL))
-	    return CAIRO_INT_STATUS_NOTHING_TO_DO;
 
 	state->image = img;
 
@@ -1318,8 +1316,10 @@ _cairo_quartz_setup_state (cairo_quartz_drawing_state_t *state,
 
 static void
 _cairo_quartz_teardown_state (cairo_quartz_drawing_state_t *state,
-			      cairo_quartz_surface_t       *surface)
+			      cairo_composite_rectangles_int_t *extents)
 {
+    cairo_quartz_surface_t *surfce = (cairo_quartz_surface_t *)extents;
+
     if (state->layer) {
 	CGContextDrawLayerInRect (surface->cgContext,
 				  state->clipRect,
@@ -1383,7 +1383,6 @@ _cairo_quartz_draw_source (cairo_quartz_drawing_state_t *state,
     }
 }
 
-
 /*
  * get source/dest image implementation
  */
@@ -1552,39 +1551,28 @@ _cairo_quartz_surface_release_source_image (void *abstract_surface,
 }
 
 
-static cairo_status_t
-_cairo_quartz_surface_acquire_dest_image (void *abstract_surface,
-					  cairo_rectangle_int_t *interest_rect,
-					  cairo_image_surface_t **image_out,
-					  cairo_rectangle_int_t *image_rect,
-					  void **image_extra)
+static cairo_surface_t *
+_cairo_quartz_surface_map_to_image (void *abstract_surface,
+				    const cairo_rectangle_int_t *extents)
 {
     cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface;
-    cairo_int_status_t status;
-
-    ND ((stderr, "%p _cairo_quartz_surface_acquire_dest_image\n", surface));
+    cairo_image_surface_t *image;
+    cairo_surface_t *surface;
 
-    status = _cairo_quartz_get_image (surface, image_out);
+    status = _cairo_quartz_get_image (surface, &image);
     if (unlikely (status))
-	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+	return _cairo_surace_create_in_error (status);
 
-    *image_rect = surface->extents;
-    *image_extra = NULL;
+    surface = _cairo_surface_create_for_rectangle_int (&image->base, extents);
+    cairo_surface_destroy (&image->base);
 
-    return CAIRO_STATUS_SUCCESS;
+    return surface;
 }
 
-static void
-_cairo_quartz_surface_release_dest_image (void *abstract_surface,
-					  cairo_rectangle_int_t *interest_rect,
-					  cairo_image_surface_t *image,
-					  cairo_rectangle_int_t *image_rect,
-					  void *image_extra)
+static cairo_int_status_t
+_cairo_quartz_surface_unmap_image (void *abstract_surface,
+				   cairo_image_surface_t *image)
 {
-    //cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface;
-
-    //ND ((stderr, "%p _cairo_quartz_surface_release_dest_image\n", surface));
-
     cairo_surface_destroy (&image->base);
 }
 
@@ -1624,173 +1612,218 @@ _cairo_quartz_surface_create_similar (void *abstract_surface,
     return similar;
 }
 
-static cairo_status_t
-_cairo_quartz_surface_clone_similar (void *abstract_surface,
-				     cairo_surface_t *src,
-				     int              src_x,
-				     int              src_y,
-				     int              width,
-				     int              height,
-				     int             *clone_offset_x,
-				     int             *clone_offset_y,
-				     cairo_surface_t **clone_out)
+static cairo_bool_t
+_cairo_quartz_surface_get_extents (void *abstract_surface,
+				   cairo_rectangle_int_t *extents)
 {
-    cairo_quartz_surface_t *new_surface = NULL;
-    cairo_format_t new_format;
-    CGImageRef quartz_image = NULL;
-    cairo_status_t status;
+    cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface;
 
-    *clone_out = NULL;
+    *extents = surface->extents;
+    return TRUE;
+}
 
-    // verify width and height of surface
-    if (!_cairo_quartz_verify_surface_size (width, height))
-	return CAIRO_INT_STATUS_UNSUPPORTED;
+static cairo_int_status_t
+_cairo_quartz_cg_paint (const cairo_compositor_t *compositor,
+			cairo_composite_rectangles_int_t *extents)
+{
+    cairo_quartz_drawing_state_t state;
+    cairo_int_status_t rv;
 
-    if (width == 0 || height == 0) {
-	*clone_out = &_cairo_quartz_surface_create_internal (NULL, CAIRO_CONTENT_COLOR_ALPHA,
-							     width, height)->base;
-	*clone_offset_x = 0;
-	*clone_offset_y = 0;
-	return CAIRO_STATUS_SUCCESS;
-    }
+    ND ((stderr, "%p _cairo_quartz_surface_paint op %d source->type %d\n", surface, op, source->type));
 
-    if (_cairo_surface_is_quartz (src)) {
-	cairo_quartz_surface_t *qsurf = (cairo_quartz_surface_t *) src;
+    rv = _cairo_quartz_setup_state (&state, extents);
+    if (unlikely (rv))
+	goto BAIL;
 
-	if (IS_EMPTY (qsurf)) {
-	    *clone_out = &_cairo_quartz_surface_create_internal (NULL,
-								 CAIRO_CONTENT_COLOR_ALPHA,
-								 qsurf->extents.width,
-								 qsurf->extents.height)->base;
-	    *clone_offset_x = 0;
-	    *clone_offset_y = 0;
-	    return CAIRO_STATUS_SUCCESS;
-	}
-    }
+    _cairo_quartz_draw_source (&state, extents->op);
+
+BAIL:
+    _cairo_quartz_teardown_state (&state, extents);
+
+    ND ((stderr, "-- paint\n"));
+    return rv;
+}
 
-    status = _cairo_surface_to_cgimage (src, &quartz_image);
+static cairo_int_status_t
+_cairo_quartz_cg_mask_with_surface (cairo_composite_extents_t *extents,
+				    cairo_surface_t        *mask_surf,
+				    const cairo_matrix_t   *mask_mat,
+				    CGInterpolationQuality filter)
+{
+    cairo_quartz_surface_t *surface = extents->surface;
+    cairo_operator_t op = extents->op;
+    const cairo_pattern_t *source = &extents->surface_pattern.base;
+    cairo_clip_t *clip = extents->clip;
+    CGRect rect;
+    CGImageRef img;
+    cairo_status_t status;
+    CGAffineTransform mask_matrix;
+    cairo_quartz_drawing_state_t state;
+
+    status = _cairo_surface_to_cgimage (mask_surf, &img);
     if (unlikely (status))
-	return CAIRO_INT_STATUS_UNSUPPORTED;
+	return status;
 
-    new_format = CAIRO_FORMAT_ARGB32;  /* assumed */
-    if (_cairo_surface_is_image (src))
-	new_format = ((cairo_image_surface_t *) src)->format;
+    status = _cairo_quartz_setup_state (&state, extents);
+    if (unlikely (status))
+	goto BAIL;
 
-    new_surface = (cairo_quartz_surface_t *)
-	cairo_quartz_surface_create (new_format, width, height);
+    rect = CGRectMake (0.0, 0.0, CGImageGetWidth (img), CGImageGetHeight (img));
+    _cairo_quartz_cairo_matrix_to_quartz (mask_mat, &mask_matrix);
 
-    if (quartz_image == NULL)
-	goto FINISH;
+    /* ClipToMask is essentially drawing an image, so we need to flip the CTM
+     * to get the image to appear oriented the right way */
+    CGContextConcatCTM (state.cgMaskContext, CGAffineTransformInvert (mask_matrix));
+    CGContextTranslateCTM (state.cgMaskContext, 0.0, rect.size.height);
+    CGContextScaleCTM (state.cgMaskContext, 1.0, -1.0);
 
-    if (!new_surface || new_surface->base.status) {
-	CGImageRelease (quartz_image);
-	return CAIRO_INT_STATUS_UNSUPPORTED;
-    }
+    state.filter = filter;
 
-    CGContextSaveGState (new_surface->cgContext);
+    CGContextSetInterpolationQuality (state.cgMaskContext, filter);
+    CGContextSetShouldAntialias (state.cgMaskContext, filter != kCGInterpolationNone);
 
-    _cairo_quartz_surface_set_cairo_operator (new_surface, CAIRO_OPERATOR_SOURCE);
+    CGContextClipToMask (state.cgMaskContext, rect, img);
 
-    CGContextTranslateCTM (new_surface->cgContext, -src_x, -src_y);
-    CGContextDrawImage (new_surface->cgContext,
-			CGRectMake (0, 0, CGImageGetWidth (quartz_image), CGImageGetHeight (quartz_image)),
-			quartz_image);
+    CGContextScaleCTM (state.cgMaskContext, 1.0, -1.0);
+    CGContextTranslateCTM (state.cgMaskContext, 0.0, -rect.size.height);
+    CGContextConcatCTM (state.cgMaskContext, mask_matrix);
 
-    CGContextRestoreGState (new_surface->cgContext);
+    _cairo_quartz_draw_source (&state, extents->op);
 
-    CGImageRelease (quartz_image);
+BAIL:
+    _cairo_quartz_teardown_state (&state, extents);
 
-FINISH:
-    *clone_offset_x = src_x;
-    *clone_offset_y = src_y;
-    *clone_out = &new_surface->base;
+    CGImageRelease (img);
 
-    return CAIRO_STATUS_SUCCESS;
+    return status;
 }
 
-static cairo_bool_t
-_cairo_quartz_surface_get_extents (void *abstract_surface,
-				   cairo_rectangle_int_t *extents)
+static cairo_int_status_t
+_cairo_quartz_cg_mask_with_solid (cairo_quartz_surface_t *surface,
+				  cairo_composite_rectangles_t *extents)
 {
-    cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface;
+    cairo_quartz_drawing_state_t state;
+    double alpha = extents->mask_pattern.solid.color.alpha;
+    cairo_status_t status;
 
-    *extents = surface->extents;
-    return TRUE;
+    status = _cairo_quartz_setup_state (&state, extents);
+    if (unlikely (status))
+	return status;
+
+    CGContextSetAlpha (surface->cgContext, alpha);
+    _cairo_quartz_draw_source (&state, extents->op);
+
+    _cairo_quartz_teardown_state (&state, extents);
+
+    return CAIRO_STATUS_SUCCESS;
 }
 
 static cairo_int_status_t
-_cairo_quartz_surface_paint_cg (cairo_quartz_surface_t *surface,
-				cairo_operator_t op,
-				const cairo_pattern_t *source,
-				const cairo_clip_t *clip)
+_cairo_quartz_cg_mask (const cairo_compositor_t *compositor,
+		       cairo_composite_rectangles_int_t *extents)
 {
-    cairo_quartz_drawing_state_t state;
-    cairo_int_status_t rv = CAIRO_STATUS_SUCCESS;
+    cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *)extents->surface;
+    cairo_operator_t op = extents->op;
+    const cairo_pattern_t *source = &extents->source_pattern.base;
+    const cairo_pattern_t *mask = &extents->mask_pattern.base;
+    cairo_surface_t *mask_surf;
+    cairo_matrix_t matrix;
+    cairo_status_t status;
+    cairo_bool_t need_temp;
+    CGInterpolationQuality filter;
 
-    ND ((stderr, "%p _cairo_quartz_surface_paint op %d source->type %d\n", surface, op, source->type));
+    ND ((stderr, "%p _cairo_quartz_surface_mask op %d source->type %d mask->type %d\n", surface, op, source->type, mask->type));
 
-    if (IS_EMPTY (surface))
-	return CAIRO_INT_STATUS_NOTHING_TO_DO;
+    if (mask->type == CAIRO_PATTERN_TYPE_SOLID)
+	return _cairo_quartz_cg_mask_with_solid (surface, extents);
 
-    rv = _cairo_quartz_setup_state (&state, surface, op, source, clip);
-    if (unlikely (rv))
-	goto BAIL;
+    need_temp = (mask->type   != CAIRO_PATTERN_TYPE_SURFACE ||
+		 mask->extend != CAIRO_EXTEND_NONE);
 
-    _cairo_quartz_draw_source (&state, op);
+    filter = _cairo_quartz_filter_to_quartz (source->filter);
 
-BAIL:
-    _cairo_quartz_teardown_state (&state, surface);
+    if (! need_temp) {
+	mask_surf = extents->mask_pattern.surface.surface;
 
-    ND ((stderr, "-- paint\n"));
-    return rv;
-}
+	/* When an opaque surface used as a mask in Quartz, its
+	 * luminosity is used as the alpha value, so we con only use
+	 * surfaces with alpha without creating a temporary mask. */
+	need_temp = ! (mask_surf->content & CAIRO_CONTENT_ALPHA);
+    }
 
-static cairo_int_status_t
-_cairo_quartz_surface_paint (void *abstract_surface,
-			     cairo_operator_t op,
-			     const cairo_pattern_t *source,
-			     const cairo_clip_t *clip)
-{
-    cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface;
-    cairo_int_status_t rv;
-    cairo_image_surface_t *image;
+    if (! need_temp) {
+	CGInterpolationQuality mask_filter;
+	cairo_bool_t simple_transform;
 
-    rv = _cairo_quartz_surface_paint_cg (surface,
-					 op,
-					 source,
-					 clip);
+	matrix = mask->matrix;
 
-    if (likely (rv != CAIRO_INT_STATUS_UNSUPPORTED))
-	return rv;
+	mask_filter = _cairo_quartz_filter_to_quartz (mask->filter);
+	if (mask_filter == kCGInterpolationNone) {
+	    simple_transform = _cairo_matrix_is_translation (&matrix);
+	    if (simple_transform) {
+		matrix.x0 = ceil (matrix.x0 - 0.5);
+		matrix.y0 = ceil (matrix.y0 - 0.5);
+	    }
+	} else {
+	    simple_transform = _cairo_matrix_is_integer_translation (&matrix,
+								     NULL,
+								     NULL);
+	}
 
-    rv = _cairo_quartz_get_image (surface, &image);
-    if (likely (rv == CAIRO_STATUS_SUCCESS)) {
-	rv = _cairo_surface_paint (&image->base, op, source, clip);
-	cairo_surface_destroy (&image->base);
+	/* Quartz only allows one interpolation to be set for mask and
+	 * source, so we can skip the temp surface only if the source
+	 * filtering makes the mask look correct. */
+	if (source->type == CAIRO_PATTERN_TYPE_SURFACE)
+	    need_temp = ! (simple_transform || filter == mask_filter);
+	else
+	    filter = mask_filter;
     }
 
-    return rv;
+    if (need_temp) {
+	/* Render the mask to a surface */
+	mask_surf = _cairo_quartz_surface_create_similar (surface,
+							  CAIRO_CONTENT_ALPHA,
+							  surface->extents.width,
+							  surface->extents.height);
+	status = mask_surf->status;
+	if (unlikely (status))
+	    goto BAIL;
+
+	/* mask_surf is clear, so use OVER instead of SOURCE to avoid a
+	 * temporary layer or fallback to cairo-image. */
+	status = _cairo_surface_paint (mask_surf, CAIRO_OPERATOR_OVER, mask, NULL);
+	if (unlikely (status))
+	    goto BAIL;
+
+	cairo_matrix_init_identity (&matrix);
+    }
+
+    status = _cairo_quartz_cg_mask_with_surface (extents,
+						 mask_surf, &matrix, filter);
+
+BAIL:
+
+    if (need_temp)
+	cairo_surface_destroy (mask_surf);
+
+    return status;
 }
 
 static cairo_int_status_t
-_cairo_quartz_surface_fill_cg (cairo_quartz_surface_t *surface,
-			       cairo_operator_t op,
-			       const cairo_pattern_t *source,
-			       const cairo_path_fixed_t *path,
-			       cairo_fill_rule_t fill_rule,
-			       double tolerance,
-			       cairo_antialias_t antialias,
-			       const cairo_clip_t *clip)
+_cairo_quartz_cg_fill (const cairo_compositor_t *compositor,
+		       cairo_composite_rectangles_int_t *extents,
+		       const cairo_path_fixed_t *path,
+		       cairo_fill_rule_t fill_rule,
+		       double tolerance,
+		       cairo_antialias_t antialias)
 {
+    cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *)extents->surface;
     cairo_quartz_drawing_state_t state;
     cairo_int_status_t rv = CAIRO_STATUS_SUCCESS;
 
     ND ((stderr, "%p _cairo_quartz_surface_fill op %d source->type %d\n", surface, op, source->type));
 
-    if (IS_EMPTY (surface))
-	return CAIRO_INT_STATUS_NOTHING_TO_DO;
-
-    rv = _cairo_quartz_setup_state (&state, surface, op, source, clip);
+    rv = _cairo_quartz_setup_state (&state, extents);
     if (unlikely (rv))
 	goto BAIL;
 
@@ -1810,75 +1843,34 @@ _cairo_quartz_surface_fill_cg (cairo_quartz_surface_t *surface,
 	else
 	    CGContextEOClip (state.cgMaskContext);
 
-	_cairo_quartz_draw_source (&state, op);
+	_cairo_quartz_draw_source (&state, extents->op);
     }
 
 BAIL:
-    _cairo_quartz_teardown_state (&state, surface);
+    _cairo_quartz_teardown_state (&state, extents);
 
     ND ((stderr, "-- fill\n"));
     return rv;
 }
 
 static cairo_int_status_t
-_cairo_quartz_surface_fill (void *abstract_surface,
-			    cairo_operator_t op,
-			    const cairo_pattern_t *source,
-			    const cairo_path_fixed_t *path,
-			    cairo_fill_rule_t fill_rule,
-			    double tolerance,
-			    cairo_antialias_t antialias,
-			    const cairo_clip_t *clip)
-{
-    cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface;
-    cairo_int_status_t rv;
-    cairo_image_surface_t *image;
-
-    rv = _cairo_quartz_surface_fill_cg (surface,
-					op,
-					source,
-					path,
-					fill_rule,
-					tolerance,
-					antialias,
-					clip);
-
-    if (likely (rv != CAIRO_INT_STATUS_UNSUPPORTED))
-	return rv;
-
-    rv = _cairo_quartz_get_image (surface, &image);
-    if (likely (rv == CAIRO_STATUS_SUCCESS)) {
-	rv = _cairo_surface_fill (&image->base, op, source,
-				  path, fill_rule, tolerance, antialias,
-				  clip);
-	cairo_surface_destroy (&image->base);
-    }
-
-    return rv;
-}
-
-static cairo_int_status_t
-_cairo_quartz_surface_stroke_cg (cairo_quartz_surface_t *surface,
-				 cairo_operator_t op,
-				 const cairo_pattern_t *source,
-				 const cairo_path_fixed_t *path,
-				 const cairo_stroke_style_t *style,
-				 const cairo_matrix_t *ctm,
-				 const cairo_matrix_t *ctm_inverse,
-				 double tolerance,
-				 cairo_antialias_t antialias,
-				 const cairo_clip_t *clip)
+_cairo_quartz_cg_stroke (const cairo_compositor_t *compositor,
+			 cairo_composite_rectangles_int_t *extents,
+			 const cairo_path_fixed_t *path,
+			 const cairo_stroke_style_t *style,
+			 const cairo_matrix_t *ctm,
+			 const cairo_matrix_t *ctm_inverse,
+			 double tolerance,
+			 cairo_antialias_t antialias)
 {
+    cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *)extents->surface;
     cairo_quartz_drawing_state_t state;
     cairo_int_status_t rv = CAIRO_STATUS_SUCCESS;
     CGAffineTransform strokeTransform, invStrokeTransform;
 
     ND ((stderr, "%p _cairo_quartz_surface_stroke op %d source->type %d\n", surface, op, source->type));
 
-    if (IS_EMPTY (surface))
-	return CAIRO_INT_STATUS_NOTHING_TO_DO;
-
-    rv = _cairo_quartz_setup_state (&state, surface, op, source, clip);
+    rv = _cairo_quartz_setup_state (&state, extents);
     if (unlikely (rv))
 	goto BAIL;
 
@@ -1930,63 +1922,26 @@ _cairo_quartz_surface_stroke_cg (cairo_quartz_surface_t *surface,
 	_cairo_quartz_cairo_matrix_to_quartz (ctm_inverse, &invStrokeTransform);
 	CGContextConcatCTM (state.cgMaskContext, invStrokeTransform);
 
-	_cairo_quartz_draw_source (&state, op);
+	_cairo_quartz_draw_source (&state, extents->op);
     }
 
 BAIL:
-    _cairo_quartz_teardown_state (&state, surface);
+    _cairo_quartz_teardown_state (&state, extents);
 
     ND ((stderr, "-- stroke\n"));
     return rv;
 }
 
-static cairo_int_status_t
-_cairo_quartz_surface_stroke (void *abstract_surface,
-			      cairo_operator_t op,
-			      const cairo_pattern_t *source,
-			      const cairo_path_fixed_t *path,
-			      const cairo_stroke_style_t *style,
-			      const cairo_matrix_t *ctm,
-			      const cairo_matrix_t *ctm_inverse,
-			      double tolerance,
-			      cairo_antialias_t antialias,
-			      const cairo_clip_t *clip)
-{
-    cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface;
-    cairo_int_status_t rv;
-    cairo_image_surface_t *image;
-
-    rv = _cairo_quartz_surface_stroke_cg (surface, op, source,
-					  path, style, ctm, ctm_inverse,
-					  tolerance, antialias,
-					  clip);
-
-    if (likely (rv != CAIRO_INT_STATUS_UNSUPPORTED))
-	return rv;
-
-    rv = _cairo_quartz_get_image (surface, &image);
-    if (likely (rv == CAIRO_STATUS_SUCCESS)) {
-	rv = _cairo_surface_stroke (&image->base, op, source,
-				    path, style, ctm, ctm_inverse,
-				    tolerance, antialias,
-				    clip);
-	cairo_surface_destroy (&image->base);
-    }
-
-    return rv;
-}
-
 #if CAIRO_HAS_QUARTZ_FONT
 static cairo_int_status_t
-_cairo_quartz_surface_show_glyphs_cg (cairo_quartz_surface_t *surface,
-				      cairo_operator_t op,
-				      const cairo_pattern_t *source,
-				      cairo_glyph_t *glyphs,
-				      int num_glyphs,
-				      cairo_scaled_font_t *scaled_font,
-				      const cairo_clip_t *clip,
-				      int *remaining_glyphs)
+_cairo_quartz_cg_glyphs (const cairo_compositor_t *compositor,
+			 cairo_composite_rectangles_int_t *extents,
+			 cairo_glyph_t *glyphs,
+			 int num_glyphs,
+			 cairo_scaled_font_t *scaled_font,
+			 cairo_bool_t overlap)
 {
+    cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *)_surface;
     CGAffineTransform textTransform, invTextTransform;
     CGGlyph glyphs_static[CAIRO_STACK_ARRAY_LENGTH (CGSize)];
     CGSize cg_advances_static[CAIRO_STACK_ARRAY_LENGTH (CGSize)];
@@ -1995,23 +1950,17 @@ _cairo_quartz_surface_show_glyphs_cg (cairo_quartz_surface_t *surface,
     COMPILE_TIME_ASSERT (sizeof (CGGlyph) <= sizeof (CGSize));
 
     cairo_quartz_drawing_state_t state;
-    cairo_int_status_t rv = CAIRO_STATUS_SUCCESS;
+    cairo_int_status_t rv = CAIRO_INT_STATUS_UNSUPPORTED;
     cairo_quartz_float_t xprev, yprev;
     int i;
     CGFontRef cgfref = NULL;
 
     cairo_bool_t didForceFontSmoothing = FALSE;
 
-    if (IS_EMPTY (surface))
-	return CAIRO_INT_STATUS_NOTHING_TO_DO;
-
-    if (num_glyphs <= 0)
-	return CAIRO_INT_STATUS_NOTHING_TO_DO;
-
     if (cairo_scaled_font_get_type (scaled_font) != CAIRO_FONT_TYPE_QUARTZ)
 	return CAIRO_INT_STATUS_UNSUPPORTED;
 
-    rv = _cairo_quartz_setup_state (&state, surface, op, source, clip);
+    rv = _cairo_quartz_setup_state (&state, extents);
     if (unlikely (rv))
 	goto BAIL;
 
@@ -2106,13 +2055,13 @@ _cairo_quartz_surface_show_glyphs_cg (cairo_quartz_surface_t *surface,
     CGContextTranslateCTM (state.cgMaskContext, -glyphs[0].x, -glyphs[0].y);
 
     if (state.action != DO_DIRECT)
-	_cairo_quartz_draw_source (&state, op);
+	_cairo_quartz_draw_source (&state, extents->op);
 
 BAIL:
     if (didForceFontSmoothing)
 	CGContextSetAllowsFontSmoothingPtr (state.cgMaskContext, FALSE);
 
-    _cairo_quartz_teardown_state (&state, surface);
+    _cairo_quartz_teardown_state (&state, extents);
 
     if (cg_glyphs != glyphs_static)
 	free (cg_glyphs);
@@ -2121,254 +2070,90 @@ BAIL:
 }
 #endif /* CAIRO_HAS_QUARTZ_FONT */
 
-static cairo_int_status_t
-_cairo_quartz_surface_show_glyphs (void *abstract_surface,
-				   cairo_operator_t op,
-				   const cairo_pattern_t *source,
-				   cairo_glyph_t *glyphs,
-				   int num_glyphs,
-				   cairo_scaled_font_t *scaled_font,
-				   const cairo_clip_t *clip,
-				   int *remaining_glyphs)
-{
-    cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface;
-    cairo_int_status_t rv = CAIRO_INT_STATUS_UNSUPPORTED;
-    cairo_image_surface_t *image;
+static const cairo_compositor_t _cairo_quartz_cg_compositor = {
+    &_cairo_fallback_compositor,
 
+    _cairo_quartz_cg_paint,
+    _cairo_quartz_cg_mask,
+    _cairo_quartz_cg_stroke,
+    _cairo_quartz_cg_fill,
 #if CAIRO_HAS_QUARTZ_FONT
-    rv = _cairo_quartz_surface_show_glyphs_cg (surface, op, source,
-					       glyphs, num_glyphs,
-					       scaled_font, clip, remaining_glyphs);
-
-    if (likely (rv != CAIRO_INT_STATUS_UNSUPPORTED))
-	return rv;
-
+    _cairo_quartz_cg_glyphs,
+#else
+    NULL,
 #endif
+};
 
-    rv = _cairo_quartz_get_image (surface, &image);
-    if (likely (rv == CAIRO_STATUS_SUCCESS)) {
-	rv = _cairo_surface_show_text_glyphs (&image->base, op, source,
-					      NULL, 0,
-					      glyphs, num_glyphs,
-					      NULL, 0, 0,
-					      scaled_font, clip);
-	cairo_surface_destroy (&image->base);
-    }
-
-    return rv;
+static cairo_int_status_t
+_cairo_quartz_surface_paint (void *surface,
+			     cairo_operator_t op,
+			     const cairo_pattern_t *source,
+			     const cairo_clip_t *clip)
+{
+    return _cairo_compositor_paint (&_cairo_quartz_cg_compositor,
+				    surface, op, source, clip);
 }
 
 static cairo_int_status_t
-_cairo_quartz_surface_mask_with_surface (cairo_quartz_surface_t *surface,
-					 cairo_operator_t        op,
-					 const cairo_pattern_t  *source,
-					 cairo_surface_t        *mask_surf,
-					 const cairo_matrix_t   *mask_mat,
-					 CGInterpolationQuality filter,
-					 const cairo_clip_t     *clip)
+_cairo_quartz_surface_mask (void *surface,
+			    cairo_operator_t op,
+			    const cairo_pattern_t *source,
+			    const cairo_pattern_t *mask,
+			    const cairo_clip_t *clip)
 {
-    CGRect rect;
-    CGImageRef img;
-    cairo_status_t status = CAIRO_STATUS_SUCCESS;
-    CGAffineTransform mask_matrix;
-    cairo_quartz_drawing_state_t state;
-
-    if (IS_EMPTY (surface))
-	return CAIRO_INT_STATUS_NOTHING_TO_DO;
-
-    status = _cairo_surface_to_cgimage (mask_surf, &img);
-    if (unlikely (status))
-	return status;
-
-    status = _cairo_quartz_setup_state (&state, surface, op, source, clip);
-    if (unlikely (status))
-	goto BAIL;
-
-    if (unlikely (img == NULL))
-	goto BAIL;
-
-    rect = CGRectMake (0.0, 0.0, CGImageGetWidth (img), CGImageGetHeight (img));
-    _cairo_quartz_cairo_matrix_to_quartz (mask_mat, &mask_matrix);
-
-    /* ClipToMask is essentially drawing an image, so we need to flip the CTM
-     * to get the image to appear oriented the right way */
-    CGContextConcatCTM (state.cgMaskContext, CGAffineTransformInvert (mask_matrix));
-    CGContextTranslateCTM (state.cgMaskContext, 0.0, rect.size.height);
-    CGContextScaleCTM (state.cgMaskContext, 1.0, -1.0);
-
-    state.filter = filter;
-
-    CGContextSetInterpolationQuality (state.cgMaskContext, filter);
-    CGContextSetShouldAntialias (state.cgMaskContext, filter != kCGInterpolationNone);
-
-    CGContextClipToMask (state.cgMaskContext, rect, img);
-
-    CGContextScaleCTM (state.cgMaskContext, 1.0, -1.0);
-    CGContextTranslateCTM (state.cgMaskContext, 0.0, -rect.size.height);
-    CGContextConcatCTM (state.cgMaskContext, mask_matrix);
-
-    _cairo_quartz_draw_source (&state, op);
-
-BAIL:
-    _cairo_quartz_teardown_state (&state, surface);
-
-    CGImageRelease (img);
-
-    return status;
+    return _cairo_compositor_mask (&_cairo_quartz_cg_compositor,
+				   surface, op, source, mask,
+				   clip);
 }
 
 static cairo_int_status_t
-_cairo_quartz_surface_mask_with_solid (cairo_quartz_surface_t *surface,
-				       cairo_operator_t        op,
-				       const cairo_pattern_t  *source,
-				       double                  alpha,
-				       const cairo_clip_t *clip)
+_cairo_quartz_surface_fill (void *surface,
+			    cairo_operator_t op,
+			    const cairo_pattern_t *source,
+			    const cairo_path_fixed_t *path,
+			    cairo_fill_rule_t fill_rule,
+			    double tolerance,
+			    cairo_antialias_t antialias,
+			    const cairo_clip_t *clip)
 {
-    cairo_quartz_drawing_state_t state;
-    cairo_status_t status;
-
-    status = _cairo_quartz_setup_state (&state, surface, op, source, clip);
-    if (unlikely (status))
-	goto BAIL;
-
-    CGContextSetAlpha (surface->cgContext, alpha);
-    _cairo_quartz_draw_source (&state, op);
-
-BAIL:
-    _cairo_quartz_teardown_state (&state, surface);
-
-    return status;
+    return _cairo_compositor_fill (&_cairo_quartz_cg_compositor,
+				   surface, op, source, path,
+				   fill_rule, tolerance, antialias,
+				   clip);
 }
 
 static cairo_int_status_t
-_cairo_quartz_surface_mask_cg (cairo_quartz_surface_t *surface,
-			       cairo_operator_t op,
-			       const cairo_pattern_t *source,
-			       const cairo_pattern_t *mask,
-			       const cairo_clip_t *clip)
+_cairo_quartz_surface_stroke (void *surface,
+			      cairo_operator_t op,
+			      const cairo_pattern_t *source,
+			      const cairo_path_fixed_t *path,
+			      const cairo_stroke_style_t *style,
+			      const cairo_matrix_t *ctm,
+			      const cairo_matrix_t *ctm_inverse,
+			      double tolerance,
+			      cairo_antialias_t antialias,
+			      const cairo_clip_t *clip)
 {
-    cairo_surface_t *mask_surf;
-    cairo_matrix_t matrix;
-    cairo_status_t status;
-    cairo_bool_t need_temp;
-    CGInterpolationQuality filter;
-
-    ND ((stderr, "%p _cairo_quartz_surface_mask op %d source->type %d mask->type %d\n", surface, op, source->type, mask->type));
-
-    if (IS_EMPTY (surface))
-	return CAIRO_INT_STATUS_NOTHING_TO_DO;
-
-    if (mask->type == CAIRO_PATTERN_TYPE_SOLID) {
-	const cairo_solid_pattern_t *mask_solid;
-
-	mask_solid = (const cairo_solid_pattern_t *) mask;
-	return _cairo_quartz_surface_mask_with_solid (surface, op, source,
-						      mask_solid->color.alpha,
-						      clip);
-    }
-
-    need_temp = (mask->type   != CAIRO_PATTERN_TYPE_SURFACE ||
-		 mask->extend != CAIRO_EXTEND_NONE);
-
-    filter = _cairo_quartz_filter_to_quartz (source->filter);
-
-    if (! need_temp) {
-	mask_surf = ((const cairo_surface_pattern_t *) mask)->surface;
-
-	/* When an opaque surface used as a mask in Quartz, its
-	 * luminosity is used as the alpha value, so we con only use
-	 * surfaces with alpha without creating a temporary mask. */
-	need_temp = ! (mask_surf->content & CAIRO_CONTENT_ALPHA);
-    }
-
-    if (! need_temp) {
-	CGInterpolationQuality mask_filter;
-	cairo_bool_t simple_transform;
-
-	matrix = mask->matrix;
-
-	mask_filter = _cairo_quartz_filter_to_quartz (mask->filter);
-	if (mask_filter == kCGInterpolationNone) {
-	    simple_transform = _cairo_matrix_is_translation (&matrix);
-	    if (simple_transform) {
-		matrix.x0 = ceil (matrix.x0 - 0.5);
-		matrix.y0 = ceil (matrix.y0 - 0.5);
-	    }
-	} else {
-	    simple_transform = _cairo_matrix_is_integer_translation (&matrix,
-								     NULL,
-								     NULL);
-	}
-
-	/* Quartz only allows one interpolation to be set for mask and
-	 * source, so we can skip the temp surface only if the source
-	 * filtering makes the mask look correct. */
-	if (source->type == CAIRO_PATTERN_TYPE_SURFACE)
-	    need_temp = ! (simple_transform || filter == mask_filter);
-	else
-	    filter = mask_filter;
-    }
-
-    if (need_temp) {
-	/* Render the mask to a surface */
-	mask_surf = _cairo_quartz_surface_create_similar (surface,
-							  CAIRO_CONTENT_ALPHA,
-							  surface->extents.width,
-							  surface->extents.height);
-	status = mask_surf->status;
-	if (unlikely (status))
-	    goto BAIL;
-
-	/* mask_surf is clear, so use OVER instead of SOURCE to avoid a
-	 * temporary layer or fallback to cairo-image. */
-	status = _cairo_surface_paint (mask_surf, CAIRO_OPERATOR_OVER, mask, NULL);
-	if (unlikely (status))
-	    goto BAIL;
-
-	cairo_matrix_init_identity (&matrix);
-    }
-
-    status = _cairo_quartz_surface_mask_with_surface (surface, op, source,
-						      mask_surf,
-						      &matrix,
-						      filter,
-						      clip);
-
-BAIL:
-
-    if (need_temp)
-	cairo_surface_destroy (mask_surf);
-
-    return status;
+    return _cairo_compositor_stroke (&_cairo_quartz_cg_compositor,
+				     surface, op, source, path,
+				     style, ctm,ctm_inverse,
+				     tolerance, antialias, clip);
 }
 
 static cairo_int_status_t
-_cairo_quartz_surface_mask (void *abstract_surface,
-			    cairo_operator_t op,
-			    const cairo_pattern_t *source,
-			    const cairo_pattern_t *mask,
-			    const cairo_clip_t *clip)
+_cairo_quartz_surface_glyphs (void *surface,
+			      cairo_operator_t op,
+			      const cairo_pattern_t *source,
+			      cairo_glyph_t *glyphs,
+			      int num_glyphs,
+			      cairo_scaled_font_t *scaled_font,
+			      const cairo_clip_t *clip,
+			      int *remaining_glyphs)
 {
-    cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface;
-    cairo_int_status_t rv;
-    cairo_image_surface_t *image;
-
-    rv = _cairo_quartz_surface_mask_cg (surface,
-					op,
-					source,
-					mask,
-					clip);
-
-    if (likely (rv != CAIRO_INT_STATUS_UNSUPPORTED))
-	return rv;
-
-    rv = _cairo_quartz_get_image (surface, &image);
-    if (likely (rv == CAIRO_STATUS_SUCCESS)) {
-	rv = _cairo_surface_mask (&image->base, op, source, mask, clip);
-	cairo_surface_destroy (&image->base);
-    }
-
-    return rv;
+    return _cairo_compositor_glyphs (&_cairo_quartz_cg_compositor,
+				     surface, op, source,
+				     glyphs, num_glyphs, scaled_font,
+				     clip, remaining_glyphs);
 }
 
 static cairo_status_t
@@ -2422,38 +2207,28 @@ static const struct _cairo_surface_backend cairo_quartz_surface_backend = {
 
     _cairo_quartz_surface_create_similar,
     NULL, /* similar image */
-    NULL, /* map to image */
-    NULL, /* unmap image */
+    _cairo_quartz_surface_map_to_image,
+    _cairo_quartz_surface_unmap_image,
 
     _cairo_quartz_surface_acquire_source_image,
     _cairo_quartz_surface_release_source_image,
-    _cairo_quartz_surface_acquire_dest_image,
-    _cairo_quartz_surface_release_dest_image,
-    _cairo_quartz_surface_clone_similar,
-    NULL, /* composite */
-    NULL, /* fill_rectangles */
-    NULL, /* composite_trapezoids */
-    NULL, /* create_span_renderer */
-    NULL, /* check_span_renderer */
+    _cairo_quartz_surface_snapshot,
+
     NULL, /* copy_page */
     NULL, /* show_page */
+
     _cairo_quartz_surface_get_extents,
-    NULL, /* old_show_glyphs */
     NULL, /* get_font_options */
+
     NULL, /* flush */
     NULL, /* mark_dirty_rectangle */
-    NULL, /* scaled_font_fini */
-    NULL, /* scaled_glyph_fini */
 
     _cairo_quartz_surface_paint,
     _cairo_quartz_surface_mask,
     _cairo_quartz_surface_stroke,
     _cairo_quartz_surface_fill,
-    _cairo_quartz_surface_show_glyphs,
-
-    _cairo_quartz_surface_snapshot,
-    NULL, /* is_similar */
-    NULL  /* fill_stroke */
+    NULL  /* fill-stroke */
+    _cairo_quartz_surface_glyphs,
 };
 
 cairo_quartz_surface_t *
@@ -2578,7 +2353,6 @@ cairo_quartz_surface_create (cairo_format_t format,
     int stride;
     int bitsPerComponent;
 
-    // verify width and height of surface
     if (!_cairo_quartz_verify_surface_size (width, height))
 	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE));
 
diff --git a/src/cairo-recording-surface-private.h b/src/cairo-recording-surface-private.h
index ea38c19..6e93eab 100644
--- a/src/cairo-recording-surface-private.h
+++ b/src/cairo-recording-surface-private.h
@@ -40,6 +40,7 @@
 #include "cairoint.h"
 #include "cairo-path-fixed-private.h"
 #include "cairo-pattern-private.h"
+#include "cairo-surface-backend-private.h"
 
 typedef enum {
     /* The 5 basic drawing operations. */
@@ -178,6 +179,11 @@ _cairo_recording_surface_get_bbox (cairo_recording_surface_t *recording,
 				   cairo_box_t *bbox,
 				   const cairo_matrix_t *transform);
 
+cairo_private cairo_status_t
+_cairo_recording_surface_get_ink_bbox (cairo_recording_surface_t *surface,
+				       cairo_box_t *bbox,
+				       const cairo_matrix_t *transform);
+
 static inline cairo_bool_t
 _cairo_recording_surface_get_bounds (cairo_surface_t *surface,
 				     cairo_rectangle_t *extents)
diff --git a/src/cairo-recording-surface.c b/src/cairo-recording-surface.c
index 6d4cb37..7a18b53 100644
--- a/src/cairo-recording-surface.c
+++ b/src/cairo-recording-surface.c
@@ -77,6 +77,8 @@
  */
 
 #include "cairoint.h"
+
+#include "cairo-array-private.h"
 #include "cairo-analysis-surface-private.h"
 #include "cairo-clip-private.h"
 #include "cairo-combsort-private.h"
@@ -86,6 +88,7 @@
 #include "cairo-image-surface-private.h"
 #include "cairo-recording-surface-private.h"
 #include "cairo-surface-wrapper-private.h"
+#include "cairo-traps-private.h"
 
 typedef enum {
     CAIRO_RECORDING_REPLAY,
@@ -493,42 +496,6 @@ _cairo_recording_surface_finish (void *abstract_surface)
     return CAIRO_STATUS_SUCCESS;
 }
 
-static cairo_status_t
-_cairo_recording_surface_acquire_source_image_transformed (void			   *abstract_surface,
-							   cairo_matrix_t	   *device_transform,
-							   cairo_image_surface_t  **image_out,
-							   void			  **image_extra)
-{
-    cairo_status_t status;
-    cairo_recording_surface_t *surface = abstract_surface;
-    cairo_surface_t *image;
-    double width;
-    double height;
-
-    width = surface->extents.width * device_transform->xx;
-    height = surface->extents.height * device_transform->yy;
-    image = _cairo_image_surface_create_with_content (surface->base.content,
-						      width, height);
-    if (unlikely (image->status))
-	return image->status;
-
-    cairo_surface_set_device_offset (image,
-				     -surface->extents.x,
-				     -surface->extents.y);
-
-    _cairo_surface_set_device_scale (image,
-				     device_transform->xx, device_transform->yy);
-    status = _cairo_recording_surface_replay (&surface->base, image);
-    if (unlikely (status)) {
-	cairo_surface_destroy (image);
-	return status;
-    }
-
-    *image_out = (cairo_image_surface_t *) image;
-    *image_extra = NULL;
-    return CAIRO_STATUS_SUCCESS;
-}
-
 struct proxy {
     cairo_surface_t base;
     cairo_surface_t *image;
@@ -680,15 +647,6 @@ _command_init (cairo_recording_surface_t *surface,
     return status;
 }
 
-static const cairo_rectangle_int_t *
-_cairo_recording_surface_extents (cairo_recording_surface_t *surface)
-{
-    if (surface->unbounded)
-	return &_cairo_unbounded_rectangle;
-
-    return &surface->extents;
-}
-
 static void
 _cairo_recording_surface_break_self_copy_loop (cairo_recording_surface_t *surface)
 {
@@ -713,7 +671,6 @@ _cairo_recording_surface_paint (void			  *abstract_surface,
     cairo_recording_surface_t *surface = abstract_surface;
     cairo_command_paint_t *command;
     cairo_composite_rectangles_t composite;
-    const cairo_rectangle_int_t *extents;
 
     if (op == CAIRO_OPERATOR_CLEAR && clip == NULL) {
 	if (surface->optimize_clears) {
@@ -723,8 +680,8 @@ _cairo_recording_surface_paint (void			  *abstract_surface,
 	}
     }
 
-    extents = _cairo_recording_surface_extents (surface);
-    status = _cairo_composite_rectangles_init_for_paint (&composite, extents,
+    status = _cairo_composite_rectangles_init_for_paint (&composite,
+							 &surface->base,
 							 op, source,
 							 clip);
     if (unlikely (status))
@@ -776,10 +733,9 @@ _cairo_recording_surface_mask (void			*abstract_surface,
     cairo_recording_surface_t *surface = abstract_surface;
     cairo_command_mask_t *command;
     cairo_composite_rectangles_t composite;
-    const cairo_rectangle_int_t *extents;
 
-    extents = _cairo_recording_surface_extents (surface);
-    status = _cairo_composite_rectangles_init_for_mask (&composite, extents,
+    status = _cairo_composite_rectangles_init_for_mask (&composite,
+							&surface->base,
 							op, source, mask,
 							clip);
     if (unlikely (status))
@@ -842,10 +798,9 @@ _cairo_recording_surface_stroke (void			*abstract_surface,
     cairo_recording_surface_t *surface = abstract_surface;
     cairo_command_stroke_t *command;
     cairo_composite_rectangles_t composite;
-    const cairo_rectangle_int_t *extents;
 
-    extents = _cairo_recording_surface_extents (surface);
-    status = _cairo_composite_rectangles_init_for_stroke (&composite, extents,
+    status = _cairo_composite_rectangles_init_for_stroke (&composite,
+							  &surface->base,
 							  op, source,
 							  path, style, ctm,
 							  clip);
@@ -918,10 +873,9 @@ _cairo_recording_surface_fill (void			*abstract_surface,
     cairo_recording_surface_t *surface = abstract_surface;
     cairo_command_fill_t *command;
     cairo_composite_rectangles_t composite;
-    const cairo_rectangle_int_t *extents;
 
-    extents = _cairo_recording_surface_extents (surface);
-    status = _cairo_composite_rectangles_init_for_fill (&composite, extents,
+    status = _cairo_composite_rectangles_init_for_fill (&composite,
+							&surface->base,
 							op, source, path,
 							clip);
     if (unlikely (status))
@@ -996,10 +950,9 @@ _cairo_recording_surface_show_text_glyphs (void				*abstract_surface,
     cairo_recording_surface_t *surface = abstract_surface;
     cairo_command_show_text_glyphs_t *command;
     cairo_composite_rectangles_t composite;
-    const cairo_rectangle_int_t *extents;
 
-    extents = _cairo_recording_surface_extents (surface);
-    status = _cairo_composite_rectangles_init_for_glyphs (&composite, extents,
+    status = _cairo_composite_rectangles_init_for_glyphs (&composite,
+							  &surface->base,
 							  op, source,
 							  scaled_font,
 							  glyphs, num_glyphs,
@@ -1121,6 +1074,9 @@ _cairo_recording_surface_snapshot (void *abstract_other)
     surface->bbtree.left = surface->bbtree.right = NULL;
     surface->bbtree.chain = INVALID_CHAIN;
 
+    surface->indices = NULL;
+    surface->num_indices = 0;
+
     _cairo_array_init (&surface->commands, sizeof (cairo_command_t *));
     status = _cairo_recording_surface_replay (&other->base, &surface->base);
     if (unlikely (status)) {
@@ -1128,9 +1084,6 @@ _cairo_recording_surface_snapshot (void *abstract_other)
 	return _cairo_surface_create_in_error (status);
     }
 
-    surface->indices = NULL;
-    surface->num_indices = 0;
-
     return &surface->base;
 }
 
@@ -1160,23 +1113,16 @@ static const cairo_surface_backend_t cairo_recording_surface_backend = {
 
     _cairo_recording_surface_acquire_source_image,
     _cairo_recording_surface_release_source_image,
-    NULL, /* acquire_dest_image */
-    NULL, /* release_dest_image */
-    NULL, /* clone_similar */
-    NULL, /* composite */
-    NULL, /* fill_rectangles */
-    NULL, /* composite_trapezoids */
-    NULL, /* create_span_renderer */
-    NULL, /* check_span_renderer */
+    _cairo_recording_surface_snapshot,
+
     NULL, /* copy_page */
     NULL, /* show_page */
+
     _cairo_recording_surface_get_extents,
-    NULL, /* old_show_glyphs */
     NULL, /* get_font_options */
+
     NULL, /* flush */
     NULL, /* mark_dirty_rectangle */
-    NULL, /* scaled_font_fini */
-    NULL, /* scaled_glyph_fini */
 
     /* Here are the 5 basic drawing operations, (which are in some
      * sense the only things that cairo_recording_surface should need to
@@ -1187,18 +1133,10 @@ static const cairo_surface_backend_t cairo_recording_surface_backend = {
     _cairo_recording_surface_mask,
     _cairo_recording_surface_stroke,
     _cairo_recording_surface_fill,
+    NULL, /* fill-stroke */
     NULL,
-
-    _cairo_recording_surface_snapshot,
-
-    NULL, /* is_similar */
-    NULL, /* fill_stroke */
-    NULL, /* create_solid_pattern_surface */
-    NULL, /* can_repaint_solid_pattern_surface */
-
     _cairo_recording_surface_has_show_text_glyphs,
     _cairo_recording_surface_show_text_glyphs,
-    _cairo_recording_surface_acquire_source_image_transformed
 };
 
 cairo_int_status_t
@@ -1723,3 +1661,30 @@ _cairo_recording_surface_get_bbox (cairo_recording_surface_t *surface,
 
     return _recording_surface_get_ink_bbox (surface, bbox, transform);
 }
+
+cairo_status_t
+_cairo_recording_surface_get_ink_bbox (cairo_recording_surface_t *surface,
+				       cairo_box_t *bbox,
+				       const cairo_matrix_t *transform)
+{
+    return _recording_surface_get_ink_bbox (surface, bbox, transform);
+}
+
+cairo_bool_t
+cairo_recording_surface_get_extents (cairo_surface_t *surface,
+				     cairo_rectangle_t *extents)
+{
+    cairo_recording_surface_t *record;
+
+    if (surface->status || ! _cairo_surface_is_recording (surface)) {
+	_cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
+	return FALSE;
+    }
+
+    record = (cairo_recording_surface_t *)surface;
+    if (record->unbounded)
+	return FALSE;
+
+    *extents = record->extents_pixels;
+    return TRUE;
+}
diff --git a/src/cairo-rectangular-scan-converter.c b/src/cairo-rectangular-scan-converter.c
index 56e552b..b4214c8 100644
--- a/src/cairo-rectangular-scan-converter.c
+++ b/src/cairo-rectangular-scan-converter.c
@@ -379,18 +379,20 @@ _active_edges_to_spans (sweep_line_t	*sweep)
     for (cell = sweep->coverage.head.next; cell != &sweep->coverage.tail; cell = cell->next) {
 	if (cell->x != prev_x && coverage != prev_coverage) {
 	    int n = sweep->num_spans++;
+	    int c = coverage >> (CAIRO_FIXED_FRAC_BITS * 2 - 8);
 	    sweep->spans[n].x = prev_x;
-	    sweep->spans[n].coverage = coverage >> (CAIRO_FIXED_FRAC_BITS * 2 - 8);
-	    sweep->spans[n].coverage -= sweep->spans[n].coverage >> 8;
+	    sweep->spans[n].inverse = 0;
+	    sweep->spans[n].coverage = c - (c >> 8);
 	    prev_coverage = coverage;
 	}
 
 	coverage += cell->covered;
 	if (coverage != prev_coverage) {
 	    int n = sweep->num_spans++;
+	    int c = coverage >> (CAIRO_FIXED_FRAC_BITS * 2 - 8);
 	    sweep->spans[n].x = cell->x;
-	    sweep->spans[n].coverage = coverage >> (CAIRO_FIXED_FRAC_BITS * 2 - 8);
-	    sweep->spans[n].coverage -= sweep->spans[n].coverage >> 8;
+	    sweep->spans[n].inverse = 0;
+	    sweep->spans[n].coverage = c - (c >> 8);
 	    prev_coverage = coverage;
 	}
 	coverage += cell->uncovered;
@@ -401,13 +403,16 @@ _active_edges_to_spans (sweep_line_t	*sweep)
     if (sweep->num_spans) {
 	if (prev_x <= sweep->xmax) {
 	    int n = sweep->num_spans++;
+	    int c = coverage >> (CAIRO_FIXED_FRAC_BITS * 2 - 8);
 	    sweep->spans[n].x = prev_x;
-	    sweep->spans[n].coverage = coverage;
+	    sweep->spans[n].inverse = 0;
+	    sweep->spans[n].coverage = c - (c >> 8);
 	}
 
 	if (coverage && prev_x < sweep->xmax) {
 	    int n = sweep->num_spans++;
 	    sweep->spans[n].x = sweep->xmax;
+	    sweep->spans[n].inverse = 1;
 	    sweep->spans[n].coverage = 0;
 	}
     }
@@ -489,13 +494,13 @@ generate (cairo_rectangular_scan_converter_t *self,
     cairo_status_t status;
 
     sweep_line_init (&sweep_line);
-    sweep_line.xmin = self->xmin;
-    sweep_line.xmax = self->xmax;
+    sweep_line.xmin = _cairo_fixed_integer_part (self->extents.p1.x);
+    sweep_line.xmax = _cairo_fixed_integer_part (self->extents.p2.x);
     sweep_line.start = rectangles;
     if ((status = setjmp (sweep_line.jmpbuf)))
-	goto BAIL;
+	goto out;
 
-    sweep_line.current_y = self->ymin;
+    sweep_line.current_y = _cairo_fixed_integer_part (self->extents.p1.y);
     start = *sweep_line.start++;
     do {
 	if (start->top_y != sweep_line.current_y) {
@@ -554,9 +559,7 @@ generate (cairo_rectangular_scan_converter_t *self,
 	    goto out;
     }
 
-    sweep_line.current_y++;
-
-    do {
+    while (++sweep_line.current_y < _cairo_fixed_integer_part (self->extents.p2.y)) {
 	if (stop->bottom_y != sweep_line.current_y) {
 	    render_rows (&sweep_line, renderer,
 			 stop->bottom_y - sweep_line.current_y);
@@ -572,16 +575,9 @@ generate (cairo_rectangular_scan_converter_t *self,
 		goto out;
 	} while (stop->bottom_y == sweep_line.current_y);
 
-	sweep_line.current_y++;
-    } while (TRUE);
+    }
 
   out:
-    status =  renderer->render_rows (renderer,
-				     sweep_line.current_y,
-				     self->ymax - sweep_line.current_y,
-				     NULL, 0);
-
-  BAIL:
     sweep_line_fini (&sweep_line);
 
     return status;
@@ -611,18 +607,18 @@ static void generate_row(cairo_span_renderer_t *renderer,
 	}
 
 	if (! _cairo_fixed_is_integer (r->right)) {
-	    spans[num_spans].x = x2;
+	    spans[num_spans].x = x2++;
 	    spans[num_spans].coverage =
 		coverage * _cairo_fixed_fractional_part (r->right) >> 8;
 	    num_spans++;
 	}
     } else {
-	spans[num_spans].x = x1;
+	spans[num_spans].x = x2++;
 	spans[num_spans].coverage = coverage * (r->right - r->left) >> 8;
 	num_spans++;
     }
 
-    spans[num_spans].x = x2 + 1;
+    spans[num_spans].x = x2;
     spans[num_spans].coverage = 0;
     num_spans++;
 
@@ -668,7 +664,8 @@ _cairo_rectangular_scan_converter_generate (void			*converter,
 
     if (unlikely (self->num_rectangles == 0)) {
 	return renderer->render_rows (renderer,
-				      self->ymin, self->ymax - self->ymin,
+				      _cairo_fixed_integer_part (self->extents.p1.y),
+				      _cairo_fixed_integer_part (self->extents.p2.y - self->extents.p1.y),
 				      NULL, 0);
     }
 
@@ -743,17 +740,22 @@ _cairo_rectangular_scan_converter_add_box (cairo_rectangular_scan_converter_t *s
     if (unlikely (rectangle == NULL))
 	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
-    rectangle->left  = box->p1.x;
-    rectangle->right = box->p2.x;
     rectangle->dir = dir;
+    rectangle->left  = MAX (box->p1.x, self->extents.p1.x);
+    rectangle->right = MIN (box->p2.x, self->extents.p2.x);
+    if (unlikely (rectangle->right <= rectangle->left)) {
+	self->tail->count--;
+	return CAIRO_STATUS_SUCCESS;
+    }
 
-    rectangle->top = box->p1.y;
-    rectangle->top_y  = _cairo_fixed_integer_floor (box->p1.y);
-    rectangle->bottom = box->p2.y;
-    rectangle->bottom_y = _cairo_fixed_integer_floor (box->p2.y);
-    assert (rectangle->bottom_y >= rectangle->top_y);
-
-    self->num_rectangles++;
+    rectangle->top = MAX (box->p1.y, self->extents.p1.y);
+    rectangle->top_y  = _cairo_fixed_integer_floor (rectangle->top);
+    rectangle->bottom = MIN (box->p2.y, self->extents.p2.y);
+    rectangle->bottom_y = _cairo_fixed_integer_floor (rectangle->bottom);
+    if (likely (rectangle->bottom > rectangle->top))
+	self->num_rectangles++;
+    else
+	self->tail->count--;
 
     return CAIRO_STATUS_SUCCESS;
 }
@@ -775,14 +777,9 @@ _cairo_rectangular_scan_converter_init (cairo_rectangular_scan_converter_t *self
 					const cairo_rectangle_int_t *extents)
 {
     self->base.destroy = _cairo_rectangular_scan_converter_destroy;
-    self->base.add_edge = NULL;
-    self->base.add_polygon = NULL;
     self->base.generate = _cairo_rectangular_scan_converter_generate;
 
-    self->xmin = extents->x;
-    self->xmax = extents->x + extents->width;
-    self->ymin = extents->y;
-    self->ymax = extents->y + extents->height;
+    _cairo_box_from_rectangle (&self->extents, extents);
 
     self->chunks.base = self->buf;
     self->chunks.next = NULL;
diff --git a/src/cairo-reference-count-private.h b/src/cairo-reference-count-private.h
index 0cb5695..75fdf35 100644
--- a/src/cairo-reference-count-private.h
+++ b/src/cairo-reference-count-private.h
@@ -45,6 +45,7 @@ typedef struct {
 } cairo_reference_count_t;
 
 #define _cairo_reference_count_inc(RC) _cairo_atomic_int_inc (&(RC)->ref_count)
+#define _cairo_reference_count_dec(RC) _cairo_atomic_int_dec (&(RC)->ref_count)
 #define _cairo_reference_count_dec_and_test(RC) _cairo_atomic_int_dec_and_test (&(RC)->ref_count)
 
 #define CAIRO_REFERENCE_COUNT_INIT(RC, VALUE) ((RC)->ref_count = (VALUE))
diff --git a/src/cairo-scaled-font-private.h b/src/cairo-scaled-font-private.h
index 029377b..da7b346 100644
--- a/src/cairo-scaled-font-private.h
+++ b/src/cairo-scaled-font-private.h
@@ -45,6 +45,8 @@
 #include "cairo-mutex-type-private.h"
 #include "cairo-reference-count-private.h"
 
+CAIRO_BEGIN_DECLS
+
 typedef struct _cairo_scaled_glyph_page cairo_scaled_glyph_page_t;
 
 struct _cairo_scaled_font {
@@ -112,20 +114,70 @@ struct _cairo_scaled_font {
     cairo_bool_t cache_frozen;
     cairo_bool_t global_cache_frozen;
 
-    /*
-     * One surface backend may store data in each glyph.
-     * Whichever surface manages to store its pointer here
-     * first gets to store data in each glyph
-     */
-    const cairo_surface_backend_t *surface_backend;
-    void *surface_private;
+    cairo_list_t dev_privates;
 
     /* font backend managing this scaled font */
     const cairo_scaled_font_backend_t *backend;
     cairo_list_t link;
 };
 
+struct _cairo_scaled_font_private {
+    cairo_list_t link;
+    const void *key;
+    void (*destroy) (cairo_scaled_font_private_t *,
+		     cairo_scaled_font_t *);
+};
+
+struct _cairo_scaled_glyph {
+    cairo_hash_entry_t hash_entry;
+
+    cairo_text_extents_t    metrics;		/* user-space metrics */
+    cairo_text_extents_t    fs_metrics;		/* font-space metrics */
+    cairo_box_t		    bbox;		/* device-space bounds */
+    int16_t                 x_advance;		/* device-space rounded X advance */
+    int16_t                 y_advance;		/* device-space rounded Y advance */
+
+    unsigned int	    has_info;
+    cairo_image_surface_t   *surface;		/* device-space image */
+    cairo_path_fixed_t	    *path;		/* device-space outline */
+    cairo_surface_t         *recording_surface;	/* device-space recording-surface */
+
+    const void		   *dev_private_key;
+    void		   *dev_private;
+    cairo_list_t            dev_privates;
+};
+
+struct _cairo_scaled_glyph_private {
+    cairo_list_t link;
+    const void *key;
+    void (*destroy) (cairo_scaled_glyph_private_t *,
+		     cairo_scaled_glyph_t *,
+		     cairo_scaled_font_t *);
+};
+
+cairo_private cairo_scaled_font_private_t *
+_cairo_scaled_font_find_private (cairo_scaled_font_t *scaled_font,
+				 const void *key);
+
+cairo_private void
+_cairo_scaled_font_attach_private (cairo_scaled_font_t *scaled_font,
+				   cairo_scaled_font_private_t *priv,
+				   const void *key,
+				   void (*destroy) (cairo_scaled_font_private_t *,
+						    cairo_scaled_font_t *));
+
+cairo_private cairo_scaled_glyph_private_t *
+_cairo_scaled_glyph_find_private (cairo_scaled_glyph_t *scaled_glyph,
+				 const void *key);
+
 cairo_private void
-_cairo_scaled_font_revoke_ownership (cairo_scaled_font_t *scaled_font);
+_cairo_scaled_glyph_attach_private (cairo_scaled_glyph_t *scaled_glyph,
+				   cairo_scaled_glyph_private_t *priv,
+				   const void *key,
+				   void (*destroy) (cairo_scaled_glyph_private_t *,
+						    cairo_scaled_glyph_t *,
+						    cairo_scaled_font_t *));
+
+CAIRO_END_DECLS
 
 #endif /* CAIRO_SCALED_FONT_PRIVATE_H */
diff --git a/src/cairo-scaled-font.c b/src/cairo-scaled-font.c
index 5b77546..be612a9 100644
--- a/src/cairo-scaled-font.c
+++ b/src/cairo-scaled-font.c
@@ -43,6 +43,7 @@
 #include "cairo-image-surface-private.h"
 #include "cairo-pattern-private.h"
 #include "cairo-scaled-font-private.h"
+#include "cairo-surface-backend-private.h"
 
 #if _XOPEN_SOURCE >= 600 || defined (_ISOC99_SOURCE)
 #define ISFINITE(x) isfinite (x)
@@ -199,10 +200,13 @@ static void
 _cairo_scaled_glyph_fini (cairo_scaled_font_t *scaled_font,
 			  cairo_scaled_glyph_t *scaled_glyph)
 {
-    const cairo_surface_backend_t *surface_backend = scaled_font->surface_backend;
-
-    if (surface_backend != NULL && surface_backend->scaled_glyph_fini != NULL)
-	surface_backend->scaled_glyph_fini (scaled_glyph, scaled_font);
+    while (! cairo_list_is_empty (&scaled_glyph->dev_privates)) {
+	cairo_scaled_glyph_private_t *private =
+	    cairo_list_first_entry (&scaled_glyph->dev_privates,
+				    cairo_scaled_glyph_private_t,
+				    link);
+	private->destroy (private, scaled_glyph, scaled_font);
+    }
 
     if (scaled_glyph->surface != NULL)
 	cairo_surface_destroy (&scaled_glyph->surface->base);
@@ -243,8 +247,7 @@ static const cairo_scaled_font_t _cairo_scaled_font_nil = {
     { NULL, NULL },		/* pages */
     FALSE,			/* cache_frozen */
     FALSE,			/* global_cache_frozen */
-    NULL,			/* surface_backend */
-    NULL,			/* surface_private */
+    { NULL, NULL },		/* privates */
     NULL			/* backend */
 };
 
@@ -445,6 +448,8 @@ _cairo_scaled_glyph_page_destroy (void *closure)
     cairo_scaled_font_t *scaled_font;
     unsigned int n;
 
+    assert (! cairo_list_is_empty (&page->link));
+
     scaled_font = (cairo_scaled_font_t *) page->cache_entry.hash;
     for (n = 0; n < page->num_glyphs; n++) {
 	_cairo_hash_table_remove (scaled_font->glyphs,
@@ -734,8 +739,7 @@ _cairo_scaled_font_init (cairo_scaled_font_t               *scaled_font,
 
     CAIRO_MUTEX_INIT (scaled_font->mutex);
 
-    scaled_font->surface_backend = NULL;
-    scaled_font->surface_private = NULL;
+    cairo_list_init (&scaled_font->dev_privates);
 
     scaled_font->backend = backend;
     cairo_list_init (&scaled_font->link);
@@ -826,9 +830,13 @@ _cairo_scaled_font_fini_internal (cairo_scaled_font_t *scaled_font)
 
     CAIRO_MUTEX_FINI (scaled_font->mutex);
 
-    if (scaled_font->surface_backend != NULL &&
-	scaled_font->surface_backend->scaled_font_fini != NULL)
-	scaled_font->surface_backend->scaled_font_fini (scaled_font);
+    while (! cairo_list_is_empty (&scaled_font->dev_privates)) {
+	cairo_scaled_font_private_t *private =
+	    cairo_list_first_entry (&scaled_font->dev_privates,
+				    cairo_scaled_font_private_t,
+				    link);
+	private->destroy (private, scaled_font);
+    }
 
     if (scaled_font->backend != NULL && scaled_font->backend->fini != NULL)
 	scaled_font->backend->fini (scaled_font);
@@ -836,30 +844,77 @@ _cairo_scaled_font_fini_internal (cairo_scaled_font_t *scaled_font)
     _cairo_user_data_array_fini (&scaled_font->user_data);
 }
 
-/* XXX: allow multiple backends to share the font */
 void
-_cairo_scaled_font_revoke_ownership (cairo_scaled_font_t *scaled_font)
+_cairo_scaled_font_fini (cairo_scaled_font_t *scaled_font)
 {
-    if (scaled_font->surface_backend == NULL)
-	return;
+    /* Release the lock to avoid the possibility of a recursive
+     * deadlock when the scaled font destroy closure gets called. */
+    CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_map_mutex);
+    _cairo_scaled_font_fini_internal (scaled_font);
+    CAIRO_MUTEX_LOCK (_cairo_scaled_font_map_mutex);
+}
 
-    _cairo_scaled_font_reset_cache (scaled_font);
+void
+_cairo_scaled_font_attach_private (cairo_scaled_font_t *scaled_font,
+				   cairo_scaled_font_private_t *private,
+				   const void *key,
+				   void (*destroy) (cairo_scaled_font_private_t *,
+						    cairo_scaled_font_t *))
+{
+    private->key = key;
+    private->destroy = destroy;
+    cairo_list_add (&private->link, &scaled_font->dev_privates);
+}
+
+cairo_scaled_font_private_t *
+_cairo_scaled_font_find_private (cairo_scaled_font_t *scaled_font,
+				 const void *key)
+{
+    cairo_scaled_font_private_t *priv;
 
-    if (scaled_font->surface_backend->scaled_font_fini != NULL)
-	scaled_font->surface_backend->scaled_font_fini (scaled_font);
+    cairo_list_foreach_entry (priv, cairo_scaled_font_private_t,
+			      &scaled_font->dev_privates, link)
+    {
+	if (priv->key == key) {
+	    if (priv->link.prev != &scaled_font->dev_privates)
+		cairo_list_move (&priv->link, &scaled_font->dev_privates);
+	    return priv;
+	}
+    }
 
-    scaled_font->surface_backend = NULL;
-    scaled_font->surface_private = NULL;
+    return NULL;
 }
 
 void
-_cairo_scaled_font_fini (cairo_scaled_font_t *scaled_font)
+_cairo_scaled_glyph_attach_private (cairo_scaled_glyph_t *scaled_glyph,
+				   cairo_scaled_glyph_private_t *private,
+				   const void *key,
+				   void (*destroy) (cairo_scaled_glyph_private_t *,
+						    cairo_scaled_glyph_t *,
+						    cairo_scaled_font_t *))
 {
-    /* Release the lock to avoid the possibility of a recursive
-     * deadlock when the scaled font destroy closure gets called. */
-    CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_map_mutex);
-    _cairo_scaled_font_fini_internal (scaled_font);
-    CAIRO_MUTEX_LOCK (_cairo_scaled_font_map_mutex);
+    private->key = key;
+    private->destroy = destroy;
+    cairo_list_add (&private->link, &scaled_glyph->dev_privates);
+}
+
+cairo_scaled_glyph_private_t *
+_cairo_scaled_glyph_find_private (cairo_scaled_glyph_t *scaled_glyph,
+				 const void *key)
+{
+    cairo_scaled_glyph_private_t *priv;
+
+    cairo_list_foreach_entry (priv, cairo_scaled_glyph_private_t,
+			      &scaled_glyph->dev_privates, link)
+    {
+	if (priv->key == key) {
+	    if (priv->link.prev != &scaled_glyph->dev_privates)
+		cairo_list_move (&priv->link, &scaled_glyph->dev_privates);
+	    return priv;
+	}
+    }
+
+    return NULL;
 }
 
 /**
@@ -2209,6 +2264,8 @@ _cairo_scaled_font_glyph_approximate_extents (cairo_scaled_font_t	 *scaled_font,
     extents->height = ceil (y1 + pad) - extents->y;
 }
 
+#if 0
+/* XXX win32 */
 cairo_status_t
 _cairo_scaled_font_show_glyphs (cairo_scaled_font_t	*scaled_font,
 				cairo_operator_t	 op,
@@ -2399,6 +2456,7 @@ CLEANUP_MASK:
 	cairo_surface_destroy (mask);
     return _cairo_scaled_font_set_error (scaled_font, status);
 }
+#endif
 
 /* Add a single-device-unit rectangle to a path. */
 static cairo_status_t
@@ -2844,6 +2902,7 @@ _cairo_scaled_glyph_lookup (cairo_scaled_font_t *scaled_font,
 
 	memset (scaled_glyph, 0, sizeof (cairo_scaled_glyph_t));
 	_cairo_scaled_glyph_set_index (scaled_glyph, index);
+	cairo_list_init (&scaled_glyph->dev_privates);
 
 	/* ask backend to initialize metrics and shape fields */
 	status =
diff --git a/src/cairo-script-private.h b/src/cairo-script-private.h
index 698a54e..5b506f5 100644
--- a/src/cairo-script-private.h
+++ b/src/cairo-script-private.h
@@ -37,10 +37,11 @@
 #define CAIRO_SCRIPT_PRIVATE_H
 
 #include "cairo.h"
+#include "cairo-script.h"
 
 #include "cairo-compiler-private.h"
 #include "cairo-output-stream-private.h"
-#include "cairo-script.h"
+#include "cairo-types-private.h"
 
 CAIRO_BEGIN_DECLS
 
diff --git a/src/cairo-script-surface.c b/src/cairo-script-surface.c
index 56e9d80..7199cd1 100644
--- a/src/cairo-script-surface.c
+++ b/src/cairo-script-surface.c
@@ -81,7 +81,7 @@
 typedef struct _cairo_script_context cairo_script_context_t;
 typedef struct _cairo_script_surface cairo_script_surface_t;
 typedef struct _cairo_script_implicit_context cairo_script_implicit_context_t;
-typedef struct _cairo_script_surface_font_private cairo_script_surface_font_private_t;
+typedef struct _cairo_script_font cairo_script_font_t;
 
 typedef struct _operand {
     enum {
@@ -121,8 +121,9 @@ struct _cairo_script_context {
     cairo_list_t defines;
 };
 
-struct _cairo_script_surface_font_private {
-    cairo_script_context_t *ctx;
+struct _cairo_script_font {
+    cairo_scaled_font_private_t base;
+
     cairo_bool_t has_sfnt;
     unsigned long id;
     unsigned long subset_glyph_index;
@@ -173,7 +174,8 @@ _cairo_script_surface_create_internal (cairo_script_context_t *ctx,
 				       cairo_surface_t *passthrough);
 
 static void
-_cairo_script_surface_scaled_font_fini (cairo_scaled_font_t *scaled_font);
+_cairo_script_scaled_font_fini (cairo_scaled_font_private_t *abstract_private,
+				cairo_scaled_font_t *scaled_font);
 
 static void
 _cairo_script_implicit_context_init (cairo_script_implicit_context_t *cr);
@@ -2022,14 +2024,11 @@ _device_destroy (void *abstract_device)
     cairo_status_t status;
 
     while (! cairo_list_is_empty (&ctx->fonts)) {
-	cairo_script_surface_font_private_t *font;
+	cairo_script_font_t *font;
 
-	font = cairo_list_first_entry (&ctx->fonts,
-				       cairo_script_surface_font_private_t,
-				       link);
+	font = cairo_list_first_entry (&ctx->fonts, cairo_script_font_t, link);
+	cairo_list_del (&font->base.link);
 	cairo_list_del (&font->link);
-	if (font->parent->surface_private == font)
-	    font->parent->surface_private = NULL;
 	free (font);
     }
 
@@ -2733,31 +2732,39 @@ _emit_font_options (cairo_script_surface_t *surface,
 }
 
 static void
-_cairo_script_surface_scaled_font_fini (cairo_scaled_font_t *scaled_font)
+_cairo_script_scaled_font_fini (cairo_scaled_font_private_t *abstract_private,
+				cairo_scaled_font_t *scaled_font)
 {
-    cairo_script_surface_font_private_t *font_private;
+    cairo_script_font_t *priv = (cairo_script_font_t *)abstract_private;
+    cairo_script_context_t *ctx = (cairo_script_context_t *)abstract_private->key;
+    cairo_status_t status;
 
-    font_private = scaled_font->surface_private;
-    if (font_private != NULL) {
-	cairo_status_t status;
-	cairo_device_t *device;
+    status = cairo_device_acquire (&ctx->base);
+    if (likely (status == CAIRO_STATUS_SUCCESS)) {
+	_cairo_output_stream_printf (ctx->stream,
+				     "/f%lu undef /sf%lu undef\n",
+				     priv->id,
+				     priv->id);
 
-	status = cairo_device_acquire (device = &font_private->ctx->base);
-	if (likely (status == CAIRO_STATUS_SUCCESS)) {
-	    _cairo_output_stream_printf (font_private->ctx->stream,
-					 "/f%lu undef /sf%lu undef\n",
-					 font_private->id,
-					 font_private->id);
+	_bitmap_release_id (&ctx->font_id, priv->id);
+	cairo_device_release (&ctx->base);
+    }
 
-	    _bitmap_release_id (&font_private->ctx->font_id, font_private->id);
-	    cairo_list_del (&font_private->link);
-	    free (font_private);
+    cairo_list_del (&priv->link);
+    cairo_list_del (&priv->base.link);
+    free (priv);
+}
 
-	    cairo_device_release (device);
-	}
+static cairo_script_font_t *
+_cairo_script_font_get (cairo_script_context_t *ctx, cairo_scaled_font_t *font)
+{
+    return (cairo_script_font_t *) _cairo_scaled_font_find_private (font, ctx);
+}
 
-	scaled_font->surface_private = NULL;
-    }
+static long unsigned
+_cairo_script_font_id (cairo_script_context_t *ctx, cairo_scaled_font_t *font)
+{
+    return _cairo_script_font_get (ctx, font)->id;
 }
 
 static cairo_status_t
@@ -2766,7 +2773,6 @@ _emit_type42_font (cairo_script_surface_t *surface,
 {
     cairo_script_context_t *ctx = to_context (surface);
     const cairo_scaled_font_backend_t *backend;
-    cairo_script_surface_font_private_t *font_private;
     cairo_output_stream_t *base85_stream;
     cairo_output_stream_t *zlib_stream;
     cairo_status_t status, status2;
@@ -2824,27 +2830,29 @@ _emit_type42_font (cairo_script_surface_t *surface,
     if (status == CAIRO_STATUS_SUCCESS)
 	status = status2;
 
-    font_private = scaled_font->surface_private;
     _cairo_output_stream_printf (ctx->stream,
 				 "~> >> font dup /f%lu exch def set-font-face",
-				 font_private->id);
+				 _cairo_script_font_id (ctx, scaled_font));
 
     return status;
 }
 
 static cairo_status_t
 _emit_scaled_font_init (cairo_script_surface_t *surface,
-			cairo_scaled_font_t *scaled_font)
+			cairo_scaled_font_t *scaled_font,
+			cairo_script_font_t **font_out)
 {
     cairo_script_context_t *ctx = to_context (surface);
-    cairo_script_surface_font_private_t *font_private;
+    cairo_script_font_t *font_private;
     cairo_int_status_t status;
 
-    font_private = malloc (sizeof (cairo_script_surface_font_private_t));
+    font_private = malloc (sizeof (cairo_script_font_t));
     if (unlikely (font_private == NULL))
 	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
-    font_private->ctx = ctx;
+    _cairo_scaled_font_attach_private (scaled_font, &font_private->base, ctx,
+				       _cairo_script_scaled_font_fini);
+
     font_private->parent = scaled_font;
     font_private->subset_glyph_index = 0;
     font_private->has_sfnt = TRUE;
@@ -2858,16 +2866,17 @@ _emit_scaled_font_init (cairo_script_surface_t *surface,
 	return status;
     }
 
-    scaled_font->surface_private = font_private;
-    scaled_font->surface_backend = &_cairo_script_surface_backend;
-
     status = _emit_context (surface);
-    if (unlikely (status))
+    if (unlikely (status)) {
+	free (font_private);
 	return status;
+    }
 
     status = _emit_type42_font (surface, scaled_font);
-    if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+    if (status != CAIRO_INT_STATUS_UNSUPPORTED) {
+	*font_out = font_private;
 	return status;
+    }
 
     font_private->has_sfnt = FALSE;
     _cairo_output_stream_printf (ctx->stream,
@@ -2883,6 +2892,7 @@ _emit_scaled_font_init (cairo_script_surface_t *surface,
 				 scaled_font->fs_extents.max_y_advance,
 				 font_private->id);
 
+    *font_out = font_private;
     return CAIRO_STATUS_SUCCESS;
 }
 
@@ -2895,7 +2905,7 @@ _emit_scaled_font (cairo_script_surface_t *surface,
     cairo_font_options_t options;
     cairo_bool_t matrix_updated = FALSE;
     cairo_status_t status;
-    cairo_script_surface_font_private_t *font_private;
+    cairo_script_font_t *font_private;
 
     cairo_scaled_font_get_ctm (scaled_font, &matrix);
     status = _emit_scaling_matrix (surface, &matrix, &matrix_updated);
@@ -2907,13 +2917,7 @@ _emit_scaled_font (cairo_script_surface_t *surface,
 
     surface->cr.current_scaled_font = scaled_font;
 
-    if (! (scaled_font->surface_backend == NULL ||
-	   scaled_font->surface_backend == &_cairo_script_surface_backend))
-    {
-	_cairo_scaled_font_revoke_ownership (scaled_font);
-    }
-
-    font_private = scaled_font->surface_private;
+    font_private = _cairo_script_font_get (ctx, scaled_font);
     if (font_private == NULL) {
 	cairo_scaled_font_get_font_matrix (scaled_font, &matrix);
 	status = _emit_font_matrix (surface, &matrix);
@@ -2925,13 +2929,10 @@ _emit_scaled_font (cairo_script_surface_t *surface,
 	if (unlikely (status))
 	    return status;
 
-	status = _emit_scaled_font_init (surface, scaled_font);
+	status = _emit_scaled_font_init (surface, scaled_font, &font_private);
 	if (unlikely (status))
 	    return status;
 
-	font_private = scaled_font->surface_private;
-	assert (font_private != NULL);
-
 	assert (target_is_active (surface));
 	_cairo_output_stream_printf (ctx->stream,
 				     " /scaled-font get /sf%lu exch def\n",
@@ -2948,17 +2949,17 @@ _emit_scaled_font (cairo_script_surface_t *surface,
 static cairo_status_t
 _emit_scaled_glyph_vector (cairo_script_surface_t *surface,
 			   cairo_scaled_font_t *scaled_font,
+			   cairo_script_font_t *font_private,
 			   cairo_scaled_glyph_t *scaled_glyph)
 {
     cairo_script_context_t *ctx = to_context (surface);
-    cairo_script_surface_font_private_t *font_private;
     cairo_script_implicit_context_t old_cr;
     cairo_status_t status;
     unsigned long index;
 
-    font_private = scaled_font->surface_private;
     index = ++font_private->subset_glyph_index;
-    scaled_glyph->surface_private = (void *) index;
+    scaled_glyph->dev_private_key = ctx;
+    scaled_glyph->dev_private = (void *) index;
 
     _cairo_output_stream_printf (ctx->stream,
 				 "%lu <<\n"
@@ -2997,16 +2998,16 @@ _emit_scaled_glyph_vector (cairo_script_surface_t *surface,
 static cairo_status_t
 _emit_scaled_glyph_bitmap (cairo_script_surface_t *surface,
 			   cairo_scaled_font_t *scaled_font,
+			   cairo_script_font_t *font_private,
 			   cairo_scaled_glyph_t *scaled_glyph)
 {
     cairo_script_context_t *ctx = to_context (surface);
-    cairo_script_surface_font_private_t *font_private;
     cairo_status_t status;
     unsigned long index;
 
-    font_private = scaled_font->surface_private;
     index = ++font_private->subset_glyph_index;
-    scaled_glyph->surface_private = (void *) index;
+    scaled_glyph->dev_private_key = ctx;
+    scaled_glyph->dev_private = (void *) index;
 
     _cairo_output_stream_printf (ctx->stream,
 				 "%lu <<\n"
@@ -3049,15 +3050,10 @@ static cairo_status_t
 _emit_scaled_glyph_prologue (cairo_script_surface_t *surface,
 			     cairo_scaled_font_t *scaled_font)
 {
-    cairo_script_surface_font_private_t *font_private;
-
-    assert (scaled_font->surface_backend == &_cairo_script_surface_backend);
-
-    font_private = scaled_font->surface_private;
+    cairo_script_context_t *ctx = to_context (surface);
 
-    _cairo_output_stream_printf (to_context (surface)->stream,
-				 "f%lu /glyphs get\n",
-				 font_private->id);
+    _cairo_output_stream_printf (ctx->stream, "f%lu /glyphs get\n",
+				 _cairo_script_font_id (ctx, scaled_font));
 
     return CAIRO_STATUS_SUCCESS;
 }
@@ -3068,7 +3064,8 @@ _emit_scaled_glyphs (cairo_script_surface_t *surface,
 		     cairo_glyph_t *glyphs,
 		     unsigned int num_glyphs)
 {
-    cairo_script_surface_font_private_t *font_private;
+    cairo_script_context_t *ctx = to_context (surface);
+    cairo_script_font_t *font_private;
     cairo_status_t status;
     unsigned int n;
     cairo_bool_t have_glyph_prologue = FALSE;
@@ -3076,7 +3073,7 @@ _emit_scaled_glyphs (cairo_script_surface_t *surface,
     if (num_glyphs == 0)
 	return CAIRO_STATUS_SUCCESS;
 
-    font_private = scaled_font->surface_private;
+    font_private = _cairo_script_font_get (ctx, scaled_font);
     if (font_private->has_sfnt)
 	return CAIRO_STATUS_SUCCESS;
 
@@ -3091,7 +3088,7 @@ _emit_scaled_glyphs (cairo_script_surface_t *surface,
 	if (unlikely (status))
 	    break;
 
-	if (scaled_glyph->surface_private != NULL)
+	if (scaled_glyph->dev_private_key == ctx)
 	    continue;
 
 	status = _cairo_scaled_glyph_lookup (scaled_font,
@@ -3111,7 +3108,7 @@ _emit_scaled_glyphs (cairo_script_surface_t *surface,
 	    }
 
 	    status = _emit_scaled_glyph_vector (surface,
-						scaled_font,
+						scaled_font, font_private,
 						scaled_glyph);
 	    if (unlikely (status))
 		break;
@@ -3137,6 +3134,7 @@ _emit_scaled_glyphs (cairo_script_surface_t *surface,
 
 	    status = _emit_scaled_glyph_bitmap (surface,
 						scaled_font,
+						font_private,
 						scaled_glyph);
 	    if (unlikely (status))
 		break;
@@ -3234,7 +3232,7 @@ _cairo_script_surface_show_text_glyphs (void			    *abstract_surface,
 {
     cairo_script_surface_t *surface = abstract_surface;
     cairo_script_context_t *ctx = to_context (surface);
-    cairo_script_surface_font_private_t *font_private;
+    cairo_script_font_t *font_private;
     cairo_scaled_glyph_t *scaled_glyph;
     cairo_matrix_t matrix;
     cairo_status_t status;
@@ -3289,7 +3287,7 @@ _cairo_script_surface_show_text_glyphs (void			    *abstract_surface,
     iy -= scaled_font->font_matrix.y0;
 
     _cairo_scaled_font_freeze_cache (scaled_font);
-    font_private = scaled_font->surface_private;
+    font_private = _cairo_script_font_get (ctx, scaled_font);
 
     _cairo_output_stream_printf (ctx->stream,
 				 "[%f %f ",
@@ -3309,7 +3307,7 @@ _cairo_script_surface_show_text_glyphs (void			    *abstract_surface,
 		goto BAIL;
 	    }
 
-	    if ((long unsigned) scaled_glyph->surface_private > 256)
+	    if ((long unsigned) scaled_glyph->dev_private > 256)
 		break;
 	}
     }
@@ -3378,7 +3376,7 @@ _cairo_script_surface_show_text_glyphs (void			    *abstract_surface,
 	    if (font_private->has_sfnt)
 		c = glyphs[n].index;
 	    else
-		c = (uint8_t) (long unsigned) scaled_glyph->surface_private;
+		c = (uint8_t) (long unsigned) scaled_glyph->dev_private;
 
 	    _cairo_output_stream_write (base85_stream, &c, 1);
 	} else {
@@ -3387,7 +3385,7 @@ _cairo_script_surface_show_text_glyphs (void			    *abstract_surface,
 					     glyphs[n].index);
 	    else
 		_cairo_output_stream_printf (ctx->stream, " %lu",
-					     (long unsigned) scaled_glyph->surface_private);
+					     (long unsigned) scaled_glyph->dev_private);
 	}
 
         dx = scaled_glyph->metrics.x_advance;
@@ -3512,40 +3510,23 @@ _cairo_script_surface_backend = {
 
     _cairo_script_surface_acquire_source_image,
     _cairo_script_surface_release_source_image,
-    NULL, /* acquire_dest_image */
-    NULL, /* release_dest_image */
-    NULL, /* clone_similar */
-    NULL, /* composite */
-    NULL, /* fill_rectangles */
-    NULL, /* composite_trapezoids */
-    NULL, /* create_span_renderer */
-    NULL, /* check_span_renderer */
+    _cairo_script_surface_snapshot,
+
     _cairo_script_surface_copy_page,
     _cairo_script_surface_show_page,
+
     _cairo_script_surface_get_extents,
-    NULL, /* old_show_glyphs */
     NULL, /* get_font_options */
+
     NULL, /* flush */
     NULL, /* mark_dirty_rectangle */
-    _cairo_script_surface_scaled_font_fini,
-    NULL, /* scaled_glyph_fini */
 
-    /* The 5 high level operations */
     _cairo_script_surface_paint,
     _cairo_script_surface_mask,
     _cairo_script_surface_stroke,
     _cairo_script_surface_fill,
-    NULL,
-
-    _cairo_script_surface_snapshot,
-
-    NULL, /* is_similar */
-    /* XXX need fill-stroke for passthrough */
-    NULL, /* fill_stroke */
-    NULL, /* create_solid_pattern_surface */
-    NULL, /* can_repaint_solid_pattern_surface */
-
-    /* The alternate high-level text operation */
+    NULL, /* fill/stroke */
+    NULL, /* glyphs */
     _cairo_script_surface_has_show_text_glyphs,
     _cairo_script_surface_show_text_glyphs
 };
diff --git a/src/cairo-slope.c b/src/cairo-slope.c
index 827037f..cc5f30c 100644
--- a/src/cairo-slope.c
+++ b/src/cairo-slope.c
@@ -89,9 +89,9 @@ _cairo_slope_compare (const cairo_slope_t *a, const cairo_slope_t *b)
      */
     if ((a->dx ^ b->dx) < 0 || (a->dy ^ b->dy) < 0) {
 	if (a->dx > 0 || (a->dx == 0 && a->dy > 0))
-	    return +1;
-	else
 	    return -1;
+	else
+	    return +1;
     }
 
     /* Finally, for identical slopes, we obviously return 0. */
diff --git a/src/cairo-spans-compositor-private.h b/src/cairo-spans-compositor-private.h
new file mode 100644
index 0000000..4175639
--- /dev/null
+++ b/src/cairo-spans-compositor-private.h
@@ -0,0 +1,96 @@
+/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
+/* cairo - a vector graphics library with display and print output
+ *
+ * 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):
+ *	Chris Wilson <chris at chris-wilson.co.uk>
+ */
+
+#ifndef CAIRO_SPANS_COMPOSITOR_PRIVATE_H
+#define CAIRO_SPANS_COMPOSITOR_PRIVATE_H
+
+#include "cairo-compositor-private.h"
+#include "cairo-types-private.h"
+#include "cairo-spans-private.h"
+
+CAIRO_BEGIN_DECLS
+
+typedef struct _cairo_abstract_span_renderer {
+    cairo_span_renderer_t base;
+    char data[2048];
+} cairo_abstract_span_renderer_t;
+
+struct cairo_spans_compositor {
+    cairo_compositor_t base;
+
+    /* pixel-aligned fast paths */
+    cairo_int_status_t (*fill_boxes)	(void			*surface,
+					 cairo_operator_t	 op,
+					 const cairo_color_t	*color,
+					 cairo_boxes_t		*boxes);
+
+    cairo_surface_t * (*pattern_to_surface) (cairo_surface_t *dst,
+					     const cairo_pattern_t *pattern,
+					     cairo_bool_t is_mask,
+					     const cairo_rectangle_int_t *extents,
+					     const cairo_rectangle_int_t *sample,
+					     int *src_x, int *src_y);
+
+    cairo_int_status_t (*composite_boxes) (void			*surface,
+					   cairo_operator_t	 op,
+					   cairo_surface_t	*source,
+					   cairo_surface_t	*mask,
+					   int			 src_x,
+					   int			 src_y,
+					   int			 mask_x,
+					   int			 mask_y,
+					   int			 dst_x,
+					   int			 dst_y,
+					   cairo_boxes_t		*boxes,
+					   const cairo_rectangle_int_t  *extents);
+
+    /* general shape masks using a span renderer */
+    cairo_int_status_t (*renderer_init) (cairo_abstract_span_renderer_t *renderer,
+					 const cairo_composite_rectangles_t *extents,
+					 cairo_bool_t	 needs_clip);
+
+    void (*renderer_fini) (cairo_abstract_span_renderer_t *renderer,
+			   cairo_int_status_t status);
+};
+
+cairo_private void
+_cairo_spans_compositor_init (cairo_spans_compositor_t *compositor,
+			      const cairo_compositor_t  *delegate);
+
+CAIRO_END_DECLS
+
+#endif /* CAIRO_SPANS_COMPOSITOR_PRIVATE_H */
diff --git a/src/cairo-spans-compositor.c b/src/cairo-spans-compositor.c
new file mode 100644
index 0000000..4320a3e
--- /dev/null
+++ b/src/cairo-spans-compositor.c
@@ -0,0 +1,1007 @@
+/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
+/* 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>
+ *      Joonas Pihlaja <jpihlaja at cc.helsinki.fi>
+ *	Chris Wilson <chris at chris-wilson.co.uk>
+ */
+
+#include "cairoint.h"
+
+#include "cairo-compositor-private.h"
+#include "cairo-clip-private.h"
+#include "cairo-image-surface-private.h"
+#include "cairo-paginated-private.h"
+#include "cairo-pattern-private.h"
+#include "cairo-region-private.h"
+#include "cairo-recording-surface-private.h"
+#include "cairo-spans-compositor-private.h"
+#include "cairo-surface-subsurface-private.h"
+#include "cairo-surface-snapshot-private.h"
+#include "cairo-surface-observer-private.h"
+
+typedef struct {
+    cairo_polygon_t	*polygon;
+    cairo_fill_rule_t	 fill_rule;
+    cairo_antialias_t	 antialias;
+} composite_spans_info_t;
+
+static cairo_int_status_t
+composite_polygon (const cairo_spans_compositor_t	*compositor,
+		   cairo_composite_rectangles_t		 *extents,
+		   cairo_polygon_t			*polygon,
+		   cairo_fill_rule_t			 fill_rule,
+		   cairo_antialias_t			 antialias);
+
+static cairo_int_status_t
+composite_boxes (const cairo_spans_compositor_t *compositor,
+		 cairo_composite_rectangles_t *extents,
+		 cairo_boxes_t		*boxes);
+
+static cairo_int_status_t
+clip_and_composite_polygon (const cairo_spans_compositor_t	*compositor,
+			    cairo_composite_rectangles_t	 *extents,
+			    cairo_polygon_t			*polygon,
+			    cairo_fill_rule_t			 fill_rule,
+			    cairo_antialias_t			 antialias);
+static cairo_surface_t *
+get_clip_surface (const cairo_spans_compositor_t *compositor,
+		  cairo_surface_t *dst,
+		  const cairo_clip_t *clip,
+		  const cairo_rectangle_int_t *extents)
+{
+    cairo_composite_rectangles_t composite;
+    cairo_surface_t *surface;
+    cairo_box_t box;
+    cairo_polygon_t polygon;
+    const cairo_clip_path_t *clip_path;
+    cairo_antialias_t antialias;
+    cairo_fill_rule_t fill_rule;
+    cairo_int_status_t status;
+
+    assert (clip->path);
+
+    surface = _cairo_surface_create_similar_solid (dst,
+						   CAIRO_CONTENT_ALPHA,
+						   extents->width,
+						   extents->height,
+						   CAIRO_COLOR_TRANSPARENT);
+
+    _cairo_box_from_rectangle (&box, extents);
+    _cairo_polygon_init (&polygon, &box, 1);
+
+    clip_path = clip->path;
+    status = _cairo_path_fixed_fill_to_polygon (&clip_path->path,
+						clip_path->tolerance,
+						&polygon);
+    if (unlikely (status))
+	goto cleanup_polygon;
+
+    polygon.limits = NULL;
+    polygon.num_limits = 0;
+
+    antialias = clip_path->antialias;
+    fill_rule = clip_path->fill_rule;
+    clip_path = clip_path->prev;
+    while (clip_path) {
+	if (clip_path->antialias == antialias) {
+	    cairo_polygon_t next;
+
+	    _cairo_polygon_init (&next, NULL, 0);
+	    status = _cairo_path_fixed_fill_to_polygon (&clip_path->path,
+							clip_path->tolerance,
+							&next);
+	    if (likely (status == CAIRO_INT_STATUS_SUCCESS))
+		status = _cairo_polygon_intersect (&polygon, fill_rule,
+						   &next, clip_path->fill_rule);
+	    _cairo_polygon_fini (&next);
+	    if (unlikely (status))
+		goto cleanup_polygon;
+
+	    fill_rule = CAIRO_FILL_RULE_WINDING;
+	}
+
+	clip_path = clip_path->prev;
+    }
+
+    _cairo_polygon_translate (&polygon, -extents->x, -extents->y);
+    status = _cairo_composite_rectangles_init_for_polygon (&composite, surface,
+							   CAIRO_OPERATOR_ADD,
+							   &_cairo_pattern_white.base,
+							   &polygon,
+							   NULL);
+    if (unlikely (status))
+	goto cleanup_polygon;
+
+    status = composite_polygon (compositor, &composite,
+				&polygon, fill_rule, antialias);
+    _cairo_composite_rectangles_fini (&composite);
+    _cairo_polygon_fini (&polygon);
+    if (unlikely (status))
+	goto error;
+
+    _cairo_polygon_init (&polygon, &box, 1);
+
+    clip_path = clip->path;
+    antialias = clip_path->antialias == CAIRO_ANTIALIAS_DEFAULT ? CAIRO_ANTIALIAS_NONE : CAIRO_ANTIALIAS_DEFAULT;
+    clip_path = clip_path->prev;
+    while (clip_path) {
+	if (clip_path->antialias == antialias) {
+	    if (polygon.num_edges == 0) {
+		status = _cairo_path_fixed_fill_to_polygon (&clip_path->path,
+							    clip_path->tolerance,
+							    &polygon);
+
+		fill_rule = clip_path->fill_rule;
+		polygon.limits = NULL;
+		polygon.num_limits = 0;
+	    } else {
+		cairo_polygon_t next;
+
+		_cairo_polygon_init (&next, NULL, 0);
+		status = _cairo_path_fixed_fill_to_polygon (&clip_path->path,
+							    clip_path->tolerance,
+							    &next);
+		if (likely (status == CAIRO_INT_STATUS_SUCCESS))
+		    status = _cairo_polygon_intersect (&polygon, fill_rule,
+						       &next, clip_path->fill_rule);
+		_cairo_polygon_fini (&next);
+		fill_rule = CAIRO_FILL_RULE_WINDING;
+	    }
+	    if (unlikely (status))
+		goto error;
+	}
+
+	clip_path = clip_path->prev;
+    }
+
+    if (polygon.num_edges) {
+	_cairo_polygon_translate (&polygon, -extents->x, -extents->y);
+	status = _cairo_composite_rectangles_init_for_polygon (&composite, surface,
+							       CAIRO_OPERATOR_IN,
+							       &_cairo_pattern_white.base,
+							       &polygon,
+							       NULL);
+	if (unlikely (status))
+	    goto cleanup_polygon;
+
+	status = composite_polygon (compositor, &composite,
+				    &polygon, fill_rule, antialias);
+	_cairo_composite_rectangles_fini (&composite);
+	_cairo_polygon_fini (&polygon);
+	if (unlikely (status))
+	    goto error;
+    }
+
+    return surface;
+
+cleanup_polygon:
+    _cairo_polygon_fini (&polygon);
+error:
+    cairo_surface_destroy (surface);
+    return _cairo_surface_create_in_error (status);
+}
+
+static cairo_int_status_t
+fixup_unbounded_mask (const cairo_spans_compositor_t *compositor,
+		      const cairo_composite_rectangles_t *extents,
+		      cairo_boxes_t *boxes)
+{
+    cairo_composite_rectangles_t composite;
+    cairo_surface_t *clip;
+    cairo_int_status_t status;
+
+    clip = get_clip_surface (compositor, extents->surface, extents->clip,
+			     &extents->unbounded);
+    if (unlikely (clip->status))
+	return clip->status;
+
+    status = _cairo_composite_rectangles_init_for_boxes (&composite,
+							 extents->surface,
+							 CAIRO_OPERATOR_DEST_OUT,
+							 &_cairo_pattern_white.base,
+							 boxes,
+							 NULL);
+    if (unlikely (status))
+	goto cleanup_clip;
+
+    _cairo_pattern_init_for_surface (&composite.mask_pattern.surface, clip);
+    composite.mask_pattern.base.filter = CAIRO_FILTER_NEAREST;
+    composite.mask_pattern.base.extend = CAIRO_EXTEND_NONE;
+
+    status = composite_boxes (compositor, &composite, boxes);
+
+    _cairo_pattern_fini (&composite.mask_pattern.base);
+    _cairo_composite_rectangles_fini (&composite);
+
+cleanup_clip:
+    cairo_surface_destroy (clip);
+    return status;
+}
+
+static cairo_int_status_t
+fixup_unbounded_polygon (const cairo_spans_compositor_t *compositor,
+			 const cairo_composite_rectangles_t *extents,
+			 cairo_boxes_t *boxes)
+{
+    cairo_polygon_t polygon, intersect;
+    cairo_composite_rectangles_t composite;
+    cairo_fill_rule_t fill_rule;
+    cairo_antialias_t antialias;
+    cairo_int_status_t status;
+
+    /* Can we treat the clip as a regular clear-polygon and use it to fill? */
+    status = _cairo_clip_get_polygon (extents->clip, &polygon,
+				      &fill_rule, &antialias);
+    if (status == CAIRO_INT_STATUS_UNSUPPORTED)
+	return status;
+
+    status= _cairo_polygon_init_boxes (&intersect, boxes);
+    if (unlikely (status))
+	goto cleanup_polygon;
+
+    status = _cairo_polygon_intersect (&polygon, fill_rule,
+				       &intersect, CAIRO_FILL_RULE_WINDING);
+    _cairo_polygon_fini (&intersect);
+
+    if (unlikely (status))
+	goto cleanup_polygon;
+
+    status = _cairo_composite_rectangles_init_for_polygon (&composite,
+							   extents->surface,
+							   CAIRO_OPERATOR_DEST_OUT,
+							   &_cairo_pattern_white.base,
+							   &polygon,
+							   NULL);
+    if (unlikely (status))
+	goto cleanup_polygon;
+
+    status = composite_polygon (compositor, &composite,
+				&polygon, fill_rule, antialias);
+
+    _cairo_composite_rectangles_fini (&composite);
+cleanup_polygon:
+    _cairo_polygon_fini (&polygon);
+
+    return status;
+}
+
+static cairo_int_status_t
+fixup_unbounded_boxes (const cairo_spans_compositor_t *compositor,
+		       const cairo_composite_rectangles_t *extents,
+		       cairo_boxes_t *boxes)
+{
+    cairo_boxes_t tmp, clear;
+    cairo_box_t box;
+    cairo_int_status_t status;
+
+    assert (boxes->is_pixel_aligned);
+
+    if (extents->bounded.width  == extents->unbounded.width &&
+	extents->bounded.height == extents->unbounded.height)
+    {
+	return CAIRO_STATUS_SUCCESS;
+    }
+
+    /* subtract the drawn boxes from the unbounded area */
+    _cairo_boxes_init (&clear);
+
+    box.p1.x = _cairo_fixed_from_int (extents->unbounded.x + extents->unbounded.width);
+    box.p1.y = _cairo_fixed_from_int (extents->unbounded.y);
+    box.p2.x = _cairo_fixed_from_int (extents->unbounded.x);
+    box.p2.y = _cairo_fixed_from_int (extents->unbounded.y + extents->unbounded.height);
+
+    if (boxes->num_boxes) {
+	_cairo_boxes_init (&tmp);
+
+	status = _cairo_boxes_add (&tmp, CAIRO_ANTIALIAS_DEFAULT, &box);
+	assert (status == CAIRO_INT_STATUS_SUCCESS);
+
+	tmp.chunks.next = &boxes->chunks;
+	tmp.num_boxes += boxes->num_boxes;
+
+	status = _cairo_bentley_ottmann_tessellate_boxes (&tmp,
+							  CAIRO_FILL_RULE_WINDING,
+							  &clear);
+	tmp.chunks.next = NULL;
+	if (unlikely (status))
+	    goto error;
+    } else {
+	box.p1.x = _cairo_fixed_from_int (extents->unbounded.x);
+	box.p2.x = _cairo_fixed_from_int (extents->unbounded.x + extents->unbounded.width);
+
+	status = _cairo_boxes_add (&clear, CAIRO_ANTIALIAS_DEFAULT, &box);
+	assert (status == CAIRO_INT_STATUS_SUCCESS);
+    }
+
+    /* Now intersect with the clip boxes */
+    if (extents->clip->num_boxes) {
+	_cairo_boxes_init_for_array (&tmp,
+				     extents->clip->boxes,
+				     extents->clip->num_boxes);
+	status = _cairo_boxes_intersect (&clear, &tmp, &clear);
+	if (unlikely (status))
+	    goto error;
+    }
+
+    /* If we have a clip polygon, we need to intersect with that as well */
+    if (extents->clip->path) {
+	status = fixup_unbounded_polygon (compositor, extents, &clear);
+	if (status == CAIRO_INT_STATUS_UNSUPPORTED)
+	    status = fixup_unbounded_mask (compositor, extents, &clear);
+    } else {
+	status = compositor->fill_boxes (extents->surface,
+					 CAIRO_OPERATOR_CLEAR,
+					 CAIRO_COLOR_TRANSPARENT,
+					 &clear);
+    }
+
+error:
+    _cairo_boxes_fini (&clear);
+    return status;
+}
+
+static cairo_surface_t *
+unwrap_surface (const cairo_pattern_t *pattern)
+{
+    cairo_surface_t *surface;
+
+    surface = ((const cairo_surface_pattern_t *) pattern)->surface;
+    if (_cairo_surface_is_paginated (surface))
+	surface = _cairo_paginated_surface_get_recording (surface);
+    if (_cairo_surface_is_snapshot (surface))
+	surface = _cairo_surface_snapshot_get_target (surface);
+    if (_cairo_surface_is_observer (surface))
+	surface = _cairo_surface_observer_get_target (surface);
+    return surface;
+}
+
+static cairo_bool_t
+is_recording_pattern (const cairo_pattern_t *pattern)
+{
+    cairo_surface_t *surface;
+
+    if (pattern->type != CAIRO_PATTERN_TYPE_SURFACE)
+	return FALSE;
+
+    surface = ((const cairo_surface_pattern_t *) pattern)->surface;
+    return _cairo_surface_is_recording (surface);
+}
+
+static cairo_bool_t
+recording_pattern_contains_sample (const cairo_pattern_t *pattern,
+				   const cairo_rectangle_int_t *sample)
+{
+    cairo_recording_surface_t *surface;
+
+    if (! is_recording_pattern (pattern))
+	return FALSE;
+
+    if (pattern->extend == CAIRO_EXTEND_NONE)
+	return TRUE;
+
+    surface = (cairo_recording_surface_t *) unwrap_surface (pattern);
+    if (surface->unbounded)
+	return TRUE;
+
+    if (sample->x >= surface->extents.x &&
+	sample->y >= surface->extents.y &&
+	sample->x + sample->width <= surface->extents.x + surface->extents.width &&
+	sample->y + sample->height <= surface->extents.y + surface->extents.height)
+    {
+	return TRUE;
+    }
+
+    return FALSE;
+}
+
+static cairo_bool_t
+op_reduces_to_source (const cairo_composite_rectangles_t *extents)
+{
+    if (extents->op == CAIRO_OPERATOR_SOURCE)
+	return TRUE;
+
+    if (extents->surface->is_clear)
+	return extents->op == CAIRO_OPERATOR_OVER || extents->op == CAIRO_OPERATOR_ADD;
+
+    return FALSE;
+}
+
+static cairo_int_status_t
+composite_aligned_boxes (const cairo_spans_compositor_t		*compositor,
+			 const cairo_composite_rectangles_t	*extents,
+			 cairo_boxes_t				*boxes)
+{
+    cairo_surface_t *dst = extents->surface;
+    cairo_operator_t op = extents->op;
+    const cairo_pattern_t *source = &extents->source_pattern.base;
+    cairo_int_status_t status;
+    cairo_bool_t need_clip_mask = extents->clip->path != NULL;
+    cairo_bool_t op_is_source;
+    cairo_bool_t no_mask;
+    cairo_bool_t inplace;
+
+    if (need_clip_mask && ! extents->is_bounded)
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+
+    op_is_source = op_reduces_to_source (extents);
+    no_mask = extents->mask_pattern.base.type == CAIRO_PATTERN_TYPE_SOLID &&
+	CAIRO_ALPHA_IS_OPAQUE (extents->mask_pattern.solid.color.alpha);
+    inplace = ! need_clip_mask && op_is_source && no_mask;
+
+    if (op == CAIRO_OPERATOR_SOURCE && (need_clip_mask || ! no_mask)) {
+	/* SOURCE with a mask is actually a LERP in cairo semantics */
+	/* XXX push this choice down to the backend */
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+    }
+
+    /* Are we just copying a recording surface? */
+    if (inplace &&
+	recording_pattern_contains_sample (&extents->source_pattern.base,
+					   &extents->source_sample_area))
+    {
+	cairo_clip_t *recording_clip;
+	const cairo_pattern_t *source = &extents->source_pattern.base;
+
+	/* XXX could also do tiling repeat modes... */
+
+	/* first clear the area about to be overwritten */
+	if (! dst->is_clear)
+	    status = compositor->fill_boxes (dst,
+					     CAIRO_OPERATOR_CLEAR,
+					     CAIRO_COLOR_TRANSPARENT,
+					     boxes);
+
+	recording_clip = _cairo_clip_from_boxes (boxes);
+	status = _cairo_recording_surface_replay_with_clip (unwrap_surface (source),
+							    &source->matrix,
+							    dst, recording_clip);
+	_cairo_clip_destroy (recording_clip);
+
+	return status;
+    }
+
+    if (! need_clip_mask && no_mask && source->type == CAIRO_PATTERN_TYPE_SOLID) {
+	const cairo_color_t *color;
+
+	color = &((cairo_solid_pattern_t *) source)->color;
+	if (op_is_source)
+	    op = CAIRO_OPERATOR_SOURCE;
+	status = compositor->fill_boxes (dst, op, color, boxes);
+#if 0
+    } else if (inplace && source->type == CAIRO_PATTERN_TYPE_SURFACE) {
+	status = upload_inplace (compositor, extents, boxes);
+#endif
+    } else {
+	cairo_surface_t *src;
+	cairo_surface_t *mask = NULL;
+	int src_x, src_y;
+	int mask_x = 0, mask_y = 0;
+
+	/* All typical cases will have been resolved before now... */
+	if (need_clip_mask) {
+	    mask = get_clip_surface (compositor, dst, extents->clip,
+				     &extents->bounded);
+	    if (unlikely (mask->status))
+		return mask->status;
+
+	    mask_x = -extents->bounded.x;
+	    mask_y = -extents->bounded.y;
+	}
+
+	/* XXX but this is still ugly */
+	if (! no_mask) {
+	    src = compositor->pattern_to_surface (dst,
+						  &extents->mask_pattern.base,
+						  TRUE,
+						  &extents->bounded,
+						  &extents->mask_sample_area,
+						  &src_x, &src_y);
+	    if (unlikely (src->status)) {
+		cairo_surface_destroy (mask);
+		return src->status;
+	    }
+
+	    if (mask != NULL) {
+		status = compositor->composite_boxes (mask, CAIRO_OPERATOR_IN,
+						      src, NULL,
+						      src_x, src_y,
+						      0, 0,
+						      mask_x, mask_y,
+						      boxes, &extents->bounded);
+
+		cairo_surface_destroy (src);
+	    } else {
+		mask = src;
+		mask_x = src_x;
+		mask_y = src_y;
+	    }
+	}
+
+	if (mask && op == CAIRO_OPERATOR_CLEAR) {
+	    source = &_cairo_pattern_white.base;
+	    op = CAIRO_OPERATOR_DEST_OUT;
+	}
+
+	src = compositor->pattern_to_surface (dst, source, FALSE,
+					      &extents->bounded,
+					      &extents->source_sample_area,
+					      &src_x, &src_y);
+	if (likely (src->status == CAIRO_STATUS_SUCCESS)) {
+	    status = compositor->composite_boxes (dst, op, src, mask,
+						  src_x, src_y,
+						  mask_x, mask_y,
+						  0, 0,
+						  boxes, &extents->bounded);
+	    cairo_surface_destroy (src);
+	} else
+	    status = src->status;
+
+	cairo_surface_destroy (mask);
+    }
+
+    if (status == CAIRO_INT_STATUS_SUCCESS && ! extents->is_bounded)
+	status = fixup_unbounded_boxes (compositor, extents, boxes);
+
+    return status;
+}
+
+static cairo_bool_t
+composite_needs_clip (const cairo_composite_rectangles_t *composit,
+		      const cairo_box_t *extents)
+{
+    cairo_bool_t needs_clip;
+
+    needs_clip = ! composit->is_bounded;
+    if (needs_clip)
+	needs_clip = ! _cairo_clip_contains_box (composit->clip, extents);
+
+    return needs_clip;
+}
+
+static cairo_int_status_t
+composite_boxes (const cairo_spans_compositor_t *compositor,
+		 cairo_composite_rectangles_t *extents,
+		 cairo_boxes_t		*boxes)
+{
+    cairo_abstract_span_renderer_t renderer;
+    cairo_rectangular_scan_converter_t converter;
+    const struct _cairo_boxes_chunk *chunk;
+    cairo_int_status_t status;
+    cairo_box_t box;
+
+    _cairo_box_from_rectangle (&box, &extents->bounded);
+    if (composite_needs_clip (extents, &box))
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+
+    _cairo_rectangular_scan_converter_init (&converter, &extents->bounded);
+    for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
+	const cairo_box_t *box = chunk->base;
+	int i;
+
+	for (i = 0; i < chunk->count; i++) {
+	    status = _cairo_rectangular_scan_converter_add_box (&converter, &box[i], 1);
+	    if (unlikely (status))
+		goto cleanup_converter;
+	}
+    }
+
+    status = compositor->renderer_init (&renderer, extents, FALSE);
+    if (likely (status == CAIRO_INT_STATUS_SUCCESS))
+	status = converter.base.generate (&converter.base, &renderer.base);
+    compositor->renderer_fini (&renderer, status);
+
+cleanup_converter:
+    converter.base.destroy (&converter.base);
+    return status;
+}
+
+static cairo_int_status_t
+composite_polygon (const cairo_spans_compositor_t	*compositor,
+		   cairo_composite_rectangles_t		 *extents,
+		   cairo_polygon_t			*polygon,
+		   cairo_fill_rule_t			 fill_rule,
+		   cairo_antialias_t			 antialias)
+{
+    cairo_abstract_span_renderer_t renderer;
+    cairo_scan_converter_t *converter;
+    cairo_bool_t needs_clip;
+    cairo_int_status_t status;
+
+    needs_clip = composite_needs_clip (extents, &polygon->extents);
+    if (needs_clip) {
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+	converter = _cairo_clip_tor_scan_converter_create (extents->clip,
+							   polygon,
+							   fill_rule, antialias);
+    } else {
+	const cairo_rectangle_int_t *r = &extents->bounded;
+
+	if (antialias == CAIRO_ANTIALIAS_FAST) {
+	    converter = _cairo_tor22_scan_converter_create (r->x, r->y,
+							    r->x + r->width,
+							    r->y + r->height,
+							    fill_rule, antialias);
+	    status = _cairo_tor22_scan_converter_add_polygon (converter, polygon);
+	} else if (antialias == CAIRO_ANTIALIAS_NONE) {
+	    converter = _cairo_mono_scan_converter_create (r->x, r->y,
+							   r->x + r->width,
+							   r->y + r->height,
+							   fill_rule);
+	    status = _cairo_mono_scan_converter_add_polygon (converter, polygon);
+	} else {
+	    converter = _cairo_tor_scan_converter_create (r->x, r->y,
+							  r->x + r->width,
+							  r->y + r->height,
+							  fill_rule, antialias);
+	    status = _cairo_tor_scan_converter_add_polygon (converter, polygon);
+	}
+    }
+    if (unlikely (status))
+	goto cleanup_converter;
+
+    status = compositor->renderer_init (&renderer, extents, needs_clip);
+    if (likely (status == CAIRO_INT_STATUS_SUCCESS))
+	status = converter->generate (converter, &renderer.base);
+    compositor->renderer_fini (&renderer, status);
+
+cleanup_converter:
+    converter->destroy (converter);
+    return status;
+}
+
+static cairo_int_status_t
+trim_extents_to_boxes (cairo_composite_rectangles_t *extents,
+		       cairo_boxes_t *boxes)
+{
+    cairo_box_t box;
+
+    _cairo_boxes_extents (boxes, &box);
+    return _cairo_composite_rectangles_intersect_mask_extents (extents, &box);
+}
+
+static cairo_int_status_t
+trim_extents_to_polygon (cairo_composite_rectangles_t *extents,
+			 cairo_polygon_t *polygon)
+{
+    return _cairo_composite_rectangles_intersect_mask_extents (extents,
+							       &polygon->extents);
+}
+
+static cairo_int_status_t
+clip_and_composite_boxes (const cairo_spans_compositor_t	*compositor,
+			  cairo_composite_rectangles_t		*extents,
+			  cairo_boxes_t				*boxes)
+{
+    cairo_int_status_t status;
+    cairo_polygon_t polygon;
+
+    status = trim_extents_to_boxes (extents, boxes);
+    if (unlikely (status))
+	return status;
+
+    if (boxes->num_boxes == 0) {
+	if (extents->is_bounded)
+	    return CAIRO_STATUS_SUCCESS;
+
+	return fixup_unbounded_boxes (compositor, extents, boxes);
+    }
+
+    /* Can we reduce drawing through a clip-mask to simply drawing the clip? */
+    if (extents->clip->path != NULL && extents->is_bounded) {
+	cairo_polygon_t polygon;
+	cairo_fill_rule_t fill_rule;
+	cairo_antialias_t antialias;
+	cairo_clip_t *clip;
+
+	clip = _cairo_clip_copy (extents->clip);
+	clip = _cairo_clip_intersect_boxes (clip, boxes);
+	status = _cairo_clip_get_polygon (clip, &polygon,
+					  &fill_rule, &antialias);
+	_cairo_clip_path_destroy (clip->path);
+	clip->path = NULL;
+	if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
+	    cairo_clip_t *saved_clip = extents->clip;
+	    extents->clip = clip;
+
+	    status = clip_and_composite_polygon (compositor, extents, &polygon,
+						 fill_rule, antialias);
+
+	    clip = extents->clip;
+	    extents->clip = saved_clip;
+
+	    _cairo_polygon_fini (&polygon);
+	}
+	_cairo_clip_destroy (clip);
+
+	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+	    return status;
+    }
+
+    if (boxes->is_pixel_aligned) {
+	status = composite_aligned_boxes (compositor, extents, boxes);
+	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+	    return status;
+    }
+
+    status = composite_boxes (compositor, extents, boxes);
+    if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+	return status;
+
+    status = _cairo_polygon_init_boxes (&polygon, boxes);
+    if (unlikely (status))
+	return status;
+
+    status = composite_polygon (compositor, extents, &polygon,
+				CAIRO_FILL_RULE_WINDING,
+				CAIRO_ANTIALIAS_DEFAULT);
+    _cairo_polygon_fini (&polygon);
+
+    return status;
+}
+
+static cairo_int_status_t
+clip_and_composite_polygon (const cairo_spans_compositor_t	*compositor,
+			    cairo_composite_rectangles_t	 *extents,
+			    cairo_polygon_t			*polygon,
+			    cairo_fill_rule_t			 fill_rule,
+			    cairo_antialias_t			 antialias)
+{
+    cairo_int_status_t status;
+
+    if (_cairo_polygon_is_empty (polygon)) {
+	cairo_boxes_t boxes;
+
+	if (extents->is_bounded)
+	    return CAIRO_STATUS_SUCCESS;
+
+	_cairo_boxes_init (&boxes);
+	return fixup_unbounded_boxes (compositor, extents, &boxes);
+    }
+
+#if 0 /* XXX not accurate currently... */
+    if (antialias == CAIRO_ANTIALIAS_NONE)
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+#endif
+
+    if (extents->is_bounded && extents->clip->path) {
+	cairo_polygon_t clipper;
+	cairo_antialias_t clip_antialias;
+	cairo_fill_rule_t clip_fill_rule;
+
+	status = _cairo_clip_get_polygon (extents->clip,
+					  &clipper,
+					  &clip_fill_rule,
+					  &clip_antialias);
+	if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
+	    cairo_clip_t *old_clip;
+
+	    if (clip_antialias == antialias) {
+		status = _cairo_polygon_intersect (polygon, fill_rule,
+						   &clipper, clip_fill_rule);
+		_cairo_polygon_fini (&clipper);
+		if (unlikely (status))
+		    return status;
+
+		old_clip = extents->clip;
+		extents->clip = _cairo_clip_copy_region (extents->clip);
+		_cairo_clip_destroy (old_clip);
+	    } else {
+		_cairo_polygon_fini (&clipper);
+	    }
+	}
+    }
+
+    status = trim_extents_to_polygon (extents, polygon);
+    if (unlikely (status))
+	return status;
+
+    return composite_polygon (compositor, extents,
+			      polygon, fill_rule, antialias);
+}
+
+/* high-level compositor interface */
+
+static cairo_int_status_t
+_cairo_spans_compositor_paint (const cairo_compositor_t		*_compositor,
+			       cairo_composite_rectangles_t	*extents)
+{
+    const cairo_spans_compositor_t *compositor = (cairo_spans_compositor_t*)_compositor;
+    cairo_boxes_t boxes;
+    cairo_int_status_t status;
+
+    _cairo_clip_steal_boxes (extents->clip, &boxes);
+    status = clip_and_composite_boxes (compositor, extents, &boxes);
+    _cairo_clip_unsteal_boxes (extents->clip, &boxes);
+
+    return status;
+}
+
+static cairo_int_status_t
+_cairo_spans_compositor_mask (const cairo_compositor_t		*_compositor,
+			      cairo_composite_rectangles_t	*extents)
+{
+    const cairo_spans_compositor_t *compositor = (cairo_spans_compositor_t*)_compositor;
+    cairo_int_status_t status;
+    cairo_boxes_t boxes;
+
+    _cairo_clip_steal_boxes (extents->clip, &boxes);
+    status = clip_and_composite_boxes (compositor, extents, &boxes);
+    _cairo_clip_unsteal_boxes (extents->clip, &boxes);
+
+    return status;
+}
+
+static cairo_int_status_t
+_cairo_spans_compositor_stroke (const cairo_compositor_t	*_compositor,
+				cairo_composite_rectangles_t	 *extents,
+				const cairo_path_fixed_t	*path,
+				const cairo_stroke_style_t	*style,
+				const cairo_matrix_t		*ctm,
+				const cairo_matrix_t		*ctm_inverse,
+				double				 tolerance,
+				cairo_antialias_t		 antialias)
+{
+    const cairo_spans_compositor_t *compositor = (cairo_spans_compositor_t*)_compositor;
+    cairo_int_status_t status;
+
+    status = CAIRO_INT_STATUS_UNSUPPORTED;
+    if (_cairo_path_fixed_stroke_is_rectilinear (path)) {
+	cairo_boxes_t boxes;
+
+	_cairo_boxes_init (&boxes);
+	if (! _cairo_clip_contains_rectangle (extents->clip, &extents->mask))
+	    _cairo_boxes_limit (&boxes,
+				extents->clip->boxes,
+				extents->clip->num_boxes);
+
+	status = _cairo_path_fixed_stroke_rectilinear_to_boxes (path,
+								style,
+								ctm,
+								antialias,
+								&boxes);
+	if (likely (status == CAIRO_INT_STATUS_SUCCESS))
+	    status = clip_and_composite_boxes (compositor, extents, &boxes);
+	_cairo_boxes_fini (&boxes);
+    }
+
+    if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
+	cairo_polygon_t polygon;
+
+	if (extents->mask.width  > extents->unbounded.width ||
+	    extents->mask.height > extents->unbounded.height)
+	{
+	    _cairo_polygon_init_with_clip (&polygon, extents->clip);
+	}
+	else
+	{
+	    _cairo_polygon_init_with_clip (&polygon, NULL);
+	}
+	status = _cairo_path_fixed_stroke_to_polygon (path,
+						      style,
+						      ctm, ctm_inverse,
+						      tolerance,
+						      &polygon);
+	if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
+	    status = clip_and_composite_polygon (compositor, extents, &polygon,
+						 CAIRO_FILL_RULE_WINDING,
+						 antialias);
+	}
+	_cairo_polygon_fini (&polygon);
+    }
+
+    return status;
+}
+
+static cairo_int_status_t
+_cairo_spans_compositor_fill (const cairo_compositor_t		*_compositor,
+			      cairo_composite_rectangles_t	 *extents,
+			      const cairo_path_fixed_t		*path,
+			      cairo_fill_rule_t			 fill_rule,
+			      double				 tolerance,
+			      cairo_antialias_t			 antialias)
+{
+    const cairo_spans_compositor_t *compositor = (cairo_spans_compositor_t*)_compositor;
+    cairo_int_status_t status;
+
+    status = CAIRO_INT_STATUS_UNSUPPORTED;
+    if (_cairo_path_fixed_fill_is_rectilinear (path)) {
+	cairo_boxes_t boxes;
+
+	_cairo_boxes_init (&boxes);
+	if (! _cairo_clip_contains_rectangle (extents->clip, &extents->mask))
+	    _cairo_boxes_limit (&boxes,
+				extents->clip->boxes,
+				extents->clip->num_boxes);
+	status = _cairo_path_fixed_fill_rectilinear_to_boxes (path,
+							      fill_rule,
+							      antialias,
+							      &boxes);
+	if (likely (status == CAIRO_INT_STATUS_SUCCESS))
+	    status = clip_and_composite_boxes (compositor, extents, &boxes);
+	_cairo_boxes_fini (&boxes);
+    }
+    if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
+	cairo_polygon_t polygon;
+
+	if (extents->mask.width  > extents->unbounded.width ||
+	    extents->mask.height > extents->unbounded.height)
+	{
+	    cairo_box_t limits;
+	    _cairo_box_from_rectangle (&limits, &extents->unbounded);
+	    _cairo_polygon_init (&polygon, &limits, 1);
+	}
+	else
+	{
+	    _cairo_polygon_init (&polygon, NULL, 0);
+	}
+
+	status = _cairo_path_fixed_fill_to_polygon (path, tolerance, &polygon);
+	if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
+	    status = _cairo_polygon_intersect_with_boxes (&polygon, &fill_rule,
+							  extents->clip->boxes,
+							  extents->clip->num_boxes);
+	}
+	if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
+	    if (extents->is_bounded) {
+		if (extents->clip->boxes != &extents->clip->embedded_box)
+		    free (extents->clip->boxes);
+
+		extents->clip->num_boxes = 1;
+		extents->clip->boxes = &extents->clip->embedded_box;
+		extents->clip->boxes[0] = polygon.extents;
+	    }
+	    status = clip_and_composite_polygon (compositor, extents, &polygon,
+						 fill_rule, antialias);
+	}
+	_cairo_polygon_fini (&polygon);
+    }
+
+    return status;
+}
+
+void
+_cairo_spans_compositor_init (cairo_spans_compositor_t *compositor,
+			      const cairo_compositor_t  *delegate)
+{
+    compositor->base.delegate = delegate;
+
+    compositor->base.paint  = _cairo_spans_compositor_paint;
+    compositor->base.mask   = _cairo_spans_compositor_mask;
+    compositor->base.fill   = _cairo_spans_compositor_fill;
+    compositor->base.stroke = _cairo_spans_compositor_stroke;
+    compositor->base.glyphs = NULL;
+}
diff --git a/src/cairo-spans-private.h b/src/cairo-spans-private.h
index 00a4df8..c42b5af 100644
--- a/src/cairo-spans-private.h
+++ b/src/cairo-spans-private.h
@@ -36,11 +36,9 @@
 /* A structure representing an open-ended horizontal span of constant
  * pixel coverage. */
 typedef struct _cairo_half_open_span {
-    /* The inclusive x-coordinate of the start of the span. */
-    int x;
-
-    /* The pixel coverage for the pixels to the right. */
-    int coverage;
+    int32_t x; /* The inclusive x-coordinate of the start of the span. */
+    uint8_t coverage; /* The pixel coverage for the pixels to the right. */
+    uint8_t inverse; /* between regular mask and clip */
 } cairo_half_open_span_t;
 
 /* Span renderer interface. Instances of renderers are provided by
@@ -73,17 +71,6 @@ struct _cairo_scan_converter {
     /* Destroy this scan converter. */
     cairo_destroy_func_t	destroy;
 
-    /* Add a single edge to the converter. */
-    cairo_status_t (*add_edge) (void		    *abstract_converter,
-				const cairo_point_t *p1,
-				const cairo_point_t *p2,
-				int top, int bottom,
-				int dir);
-
-    /* Add a polygon (set of edges) to the converter. */
-    cairo_status_t (*add_polygon) (void		    *abstract_converter,
-				   const cairo_polygon_t  *polygon);
-
     /* Generates coverage spans for rows for the added edges and calls
      * the renderer function for each row. After generating spans the
      * only valid thing to do with the converter is to destroy it. */
@@ -101,13 +88,43 @@ _cairo_tor_scan_converter_create (int			xmin,
 				  int			ymin,
 				  int			xmax,
 				  int			ymax,
-				  cairo_fill_rule_t	fill_rule);
+				  cairo_fill_rule_t	fill_rule,
+				  cairo_antialias_t	antialias);
+cairo_private cairo_status_t
+_cairo_tor_scan_converter_add_polygon (void		*converter,
+				       const cairo_polygon_t *polygon);
+
+cairo_private cairo_scan_converter_t *
+_cairo_tor22_scan_converter_create (int			xmin,
+				    int			ymin,
+				    int			xmax,
+				    int			ymax,
+				    cairo_fill_rule_t	fill_rule,
+				    cairo_antialias_t	antialias);
+cairo_private cairo_status_t
+_cairo_tor22_scan_converter_add_polygon (void		*converter,
+					 const cairo_polygon_t *polygon);
+
+cairo_private cairo_scan_converter_t *
+_cairo_mono_scan_converter_create (int			xmin,
+				   int			ymin,
+				   int			xmax,
+				   int			ymax,
+				   cairo_fill_rule_t	fill_rule);
+cairo_private cairo_status_t
+_cairo_mono_scan_converter_add_polygon (void		*converter,
+					const cairo_polygon_t *polygon);
+
+cairo_private cairo_scan_converter_t *
+_cairo_clip_tor_scan_converter_create (cairo_clip_t *clip,
+				       cairo_polygon_t *polygon,
+				       cairo_fill_rule_t fill_rule,
+				       cairo_antialias_t antialias);
 
 typedef struct _cairo_rectangular_scan_converter {
     cairo_scan_converter_t base;
 
-    int xmin, xmax;
-    int ymin, ymax;
+    cairo_box_t extents;
 
     struct _cairo_rectangular_scan_converter_chunk {
 	struct _cairo_rectangular_scan_converter_chunk *next;
diff --git a/src/cairo-spans.c b/src/cairo-spans.c
index f658650..b8d4180 100644
--- a/src/cairo-spans.c
+++ b/src/cairo-spans.c
@@ -32,87 +32,6 @@
 #include "cairo-fixed-private.h"
 #include "cairo-types-private.h"
 
-static cairo_scan_converter_t *
-_create_scan_converter (cairo_fill_rule_t			 fill_rule,
-			cairo_antialias_t			 antialias,
-			const cairo_composite_rectangles_t	*rects)
-{
-    if (antialias == CAIRO_ANTIALIAS_NONE) {
-	ASSERT_NOT_REACHED;
-	return NULL;
-    }
-
-    return _cairo_tor_scan_converter_create (rects->bounded.x,
-					     rects->bounded.y,
-					     rects->bounded.x + rects->bounded.width,
-					     rects->bounded.y + rects->bounded.height,
-					     fill_rule);
-}
-
-/* XXX Add me to the compositor interface. Ok, first create the compositor
- * interface, and then add this with associated fallback!
- */
-cairo_status_t
-_cairo_surface_composite_polygon (cairo_surface_t	*surface,
-				  cairo_operator_t	 op,
-				  const cairo_pattern_t	*pattern,
-				  cairo_fill_rule_t	fill_rule,
-				  cairo_antialias_t	antialias,
-				  const cairo_composite_rectangles_t *rects,
-				  cairo_polygon_t	*polygon,
-				  cairo_region_t	*clip_region)
-{
-    cairo_span_renderer_t *renderer;
-    cairo_scan_converter_t *converter;
-    cairo_status_t status;
-    cairo_clip_path_t *clip_path = rects->clip->path;
-
-    if (rects->is_bounded) {
-	if (polygon->num_edges == 0)
-	    return CAIRO_STATUS_SUCCESS;
-
-	if (clip_path) { /* XXX */
-	    cairo_polygon_t clipper;
-	    cairo_fill_rule_t clipper_fill_rule;
-	    cairo_antialias_t clipper_antialias;
-
-	    if (_cairo_clip_get_polygon (rects->clip, &clipper,
-					 &clipper_fill_rule,
-					 &clipper_antialias) == CAIRO_INT_STATUS_SUCCESS) {
-		if (clipper_antialias != CAIRO_ANTIALIAS_NONE &&
-		    _cairo_polygon_intersect (polygon, fill_rule,
-					      &clipper, clipper_fill_rule) == CAIRO_STATUS_SUCCESS)
-		{
-		    rects->clip->path = NULL;
-		}
-
-		_cairo_polygon_fini (&clipper);
-	    }
-	}
-    }
-
-    converter = _create_scan_converter (fill_rule, antialias, rects);
-    status = converter->add_polygon (converter, polygon);
-    if (unlikely (status))
-	goto CLEANUP_CONVERTER;
-
-    renderer = _cairo_surface_create_span_renderer (op, pattern, surface,
-						    antialias, rects,
-						    clip_region);
-    status = converter->generate (converter, renderer);
-    if (unlikely (status))
-	goto CLEANUP_RENDERER;
-
-    status = renderer->finish (renderer);
-
- CLEANUP_RENDERER:
-    renderer->destroy (renderer);
- CLEANUP_CONVERTER:
-    converter->destroy (converter);
-    rects->clip->path = clip_path;
-    return status;
-}
-
 static void
 _cairo_nil_destroy (void *abstract)
 {
@@ -120,31 +39,6 @@ _cairo_nil_destroy (void *abstract)
 }
 
 static cairo_status_t
-_cairo_nil_scan_converter_add_polygon (void *abstract_converter,
-				       const cairo_polygon_t *polygon)
-{
-    (void) abstract_converter;
-    (void) polygon;
-    return _cairo_scan_converter_status (abstract_converter);
-}
-
-static cairo_status_t
-_cairo_nil_scan_converter_add_edge (void *abstract_converter,
-				    const cairo_point_t *p1,
-				    const cairo_point_t *p2,
-				    int top, int bottom,
-				    int dir)
-{
-    (void) abstract_converter;
-    (void) p1;
-    (void) p2;
-    (void) top;
-    (void) bottom;
-    (void) dir;
-    return _cairo_scan_converter_status (abstract_converter);
-}
-
-