[cairo-commit] 2 commits - src/cairo-analysis-surface.c src/cairo-analysis-surface-private.h src/cairoint.h src/cairo-meta-surface.c src/cairo-meta-surface-private.h src/cairo-paginated-surface.c src/cairo-ps-surface.c src/cairo-region.c src/cairo-region-private.h

Carl Worth cworth at kemper.freedesktop.org
Tue Aug 21 15:16:28 PDT 2007


 src/cairo-analysis-surface-private.h |    3 
 src/cairo-analysis-surface.c         |  358 ++++++++++++++++++++++++++++++-----
 src/cairo-meta-surface-private.h     |   34 ++-
 src/cairo-meta-surface.c             |   78 ++++++-
 src/cairo-paginated-surface.c        |  131 ++++++++++--
 src/cairo-ps-surface.c               |   97 +++++----
 src/cairo-region-private.h           |    4 
 src/cairo-region.c                   |   13 +
 src/cairoint.h                       |    4 
 9 files changed, 589 insertions(+), 133 deletions(-)

New commits:
diff-tree e66b2b68ab456d779524d9b4ab34acf5d38362b5 (from bf92255edd20595a6eb220c6ee9d6aa40b244eef)
Author: Carl Worth <cworth at cworth.org>
Date:   Tue Aug 21 14:52:54 2007 -0700

    Use 8-bit math to flatten color when emitting a solid pattern to PostScript
    
    This isn't necessarily more correct than the old code using the doubles,
    but it does result in bit-for-bit color equivalence when comparing the
    results against the image backend. So that's both good consistency, and
    more ease is using the test suite to verify things.

diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c
index df78212..676014c 100644
--- a/src/cairo-ps-surface.c
+++ b/src/cairo-ps-surface.c
@@ -1681,25 +1681,29 @@ static void
 _cairo_ps_surface_emit_solid_pattern (cairo_ps_surface_t    *surface,
 				      cairo_solid_pattern_t *pattern)
 {
-    cairo_color_t color = pattern->color;
+    cairo_color_t *color = &pattern->color;
+    double red, green, blue;
 
-    if (!CAIRO_COLOR_IS_OPAQUE(&color)) {
-	/* Blend into white */
-	color.red = color.red*color.alpha + 1 - color.alpha;
-	color.green = color.green*color.alpha + 1 - color.alpha;
-	color.blue = color.blue*color.alpha + 1 - color.alpha;
+    red = color->red;
+    green = color->green;
+    blue = color->blue;
+
+    if (!CAIRO_COLOR_IS_OPAQUE(color)) {
+	uint8_t one_minus_alpha = 255 - (color->alpha_short >> 8);
+
+	red   = ((color->red_short   >> 8) + one_minus_alpha) / 255.0;
+	green = ((color->green_short >> 8) + one_minus_alpha) / 255.0;
+	blue  = ((color->blue_short  >> 8) + one_minus_alpha) / 255.0;
     }
 
-    if (color_is_gray (&color))
+    if (color_is_gray (color))
 	_cairo_output_stream_printf (surface->stream,
 				     "%f G\n",
-				     color.red);
+				     red);
     else
 	_cairo_output_stream_printf (surface->stream,
 				     "%f %f %f R\n",
-				     color.red,
-				     color.green,
-				     color.blue);
+				     red, green, blue);
 }
 
 static cairo_status_t
diff-tree bf92255edd20595a6eb220c6ee9d6aa40b244eef (from bf4bdbb6076dbe3b74534bc4308dbc9213bf628d)
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Tue Aug 21 22:27:57 2007 +0930

    PS: Add finer-grained image fallback support
    
    The analysis surface now keeps track of two regions: supported
    operations, and unsupported operations. If the target surface returns
    CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY, the analysis surface will check
    if any previous operation intersects with this operation. If there is
    nothing previously drawn under the operation, the status is changed to
    supported.
    
    The meta surface has two new functions:
            _cairo_meta_surface_replay_region()
            _cairo_meta_surface_replay_and_create_regions()
    
    During the analysis stage, the paginated surface replays the meta
    surface using _cairo_meta_surface_replay_and_create_regions(). The
    return status from each analyzed operation is saved in the meta
    surface. The _cairo_meta_surface_replay_region() function allows only
    operations from either the supported or unsupported region to be
    replayed. This allows the paginated surface to replay only the
    supported operations before emitting a fallback image for each
    rectangle in the unsupported region.

diff --git a/src/cairo-analysis-surface-private.h b/src/cairo-analysis-surface-private.h
index 056972a..c17b0ef 100644
--- a/src/cairo-analysis-surface-private.h
+++ b/src/cairo-analysis-surface-private.h
@@ -49,6 +49,9 @@ cairo_private cairo_region_t *
 _cairo_analysis_surface_get_unsupported (cairo_surface_t *unsupported);
 
 cairo_private cairo_bool_t
+_cairo_analysis_surface_has_supported (cairo_surface_t *unsupported);
+
+cairo_private cairo_bool_t
 _cairo_analysis_surface_has_unsupported (cairo_surface_t *unsupported);
 
 #endif /* CAIRO_ANALYSIS_SURFACE_H */
diff --git a/src/cairo-analysis-surface.c b/src/cairo-analysis-surface.c
index 3dbc73c..b2295ea 100644
--- a/src/cairo-analysis-surface.c
+++ b/src/cairo-analysis-surface.c
@@ -1,5 +1,6 @@
 /*
  * Copyright © 2006 Keith Packard
+ * Copyright © 2007 Adrian Johnson
  *
  * This library is free software; you can redistribute it and/or
  * modify it either under the terms of the GNU Lesser General Public
@@ -30,12 +31,14 @@
  *
  * Contributor(s):
  *      Keith Packard <keithp at keithp.com>
+ *      Adrian Johnson <ajohnson at redneon.com>
  */
 
 #include "cairoint.h"
 
 #include "cairo-analysis-surface-private.h"
 #include "cairo-paginated-private.h"
+#include "cairo-region-private.h"
 
 typedef struct {
     cairo_surface_t base;
@@ -44,10 +47,122 @@ typedef struct {
 
     cairo_surface_t	*target;
 
-    cairo_bool_t fallback;
+    cairo_bool_t has_supported;
+    cairo_bool_t has_unsupported;
+
+    cairo_region_t supported_region;
+    cairo_region_t fallback_region;
+    cairo_rectangle_int_t current_clip;
+
 } cairo_analysis_surface_t;
 
 static cairo_int_status_t
+_cairo_analysis_surface_add_operation  (cairo_analysis_surface_t *surface,
+					cairo_rectangle_int_t    *rect,
+					cairo_int_status_t        backend_status)
+{
+    cairo_int_status_t status;
+
+    if (rect->width == 0 || rect->height == 0)
+	return CAIRO_STATUS_SUCCESS;
+
+    /* If the operation is completely enclosed within the fallback
+     * region there is no benefit in emitting a native operation as
+     * the fallback image will be painted on top.
+     */
+    if (_cairo_region_contains_rectangle (&surface->fallback_region, rect) == PIXMAN_REGION_IN)
+	return CAIRO_INT_STATUS_IMAGE_FALLBACK;
+
+    if (backend_status == CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY) {
+	/* A status of CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY indicates
+	 * that the backend only supports this operation if the
+	 * transparency removed. If the extents of this operation does
+	 * not intersect any other native operation, the operation is
+	 * natively supported and the backend will blend the
+	 * transparency into the white background.
+	 */
+	if (_cairo_region_contains_rectangle (&surface->supported_region, rect) == PIXMAN_REGION_OUT)
+	    backend_status = CAIRO_STATUS_SUCCESS;
+    }
+
+    if (backend_status == CAIRO_STATUS_SUCCESS) {
+	/* Add the operation to the supported region. Operations in
+	 * this region will be emitted as native operations.
+	 */
+	surface->has_supported = TRUE;
+	status = _cairo_region_union_rect (&surface->supported_region,
+					   &surface->supported_region,
+					   rect);
+	return status;
+    }
+
+    /* Add the operation to the unsupported region. This region will
+     * be painted as an image after all native operations have been
+     * emitted.
+     */
+    surface->has_unsupported = TRUE;
+    status = _cairo_region_union_rect (&surface->fallback_region,
+				       &surface->fallback_region,
+				       rect);
+
+    /* The status CAIRO_INT_STATUS_IMAGE_FALLBACK is used to indicate
+     * unsupported operations to the meta surface as using
+     * CAIRO_INT_STATUS_UNSUPPORTED would cause cairo-surface to
+     * invoke the cairo-surface-fallback path then return
+     * CAIRO_STATUS_SUCCESS.
+     */
+    if (status == CAIRO_STATUS_SUCCESS)
+	return CAIRO_INT_STATUS_IMAGE_FALLBACK;
+    else
+	return status;
+}
+
+static cairo_status_t
+_cairo_analysis_surface_finish (void *abstract_surface)
+{
+    cairo_analysis_surface_t	*surface = (cairo_analysis_surface_t *) abstract_surface;
+
+    _cairo_region_fini (&surface->supported_region);
+    _cairo_region_fini (&surface->fallback_region);
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+_cairo_analysis_surface_intersect_clip_path (void		*abstract_surface,
+					     cairo_path_fixed_t *path,
+					     cairo_fill_rule_t   fill_rule,
+					     double		 tolerance,
+					     cairo_antialias_t   antialias)
+{
+    cairo_analysis_surface_t *surface = abstract_surface;
+    double                    x1, y1, x2, y2;
+    cairo_rectangle_int_t   extent;
+    cairo_status_t	      status;
+
+    if (path == NULL) {
+	surface->current_clip.x = 0;
+	surface->current_clip.y = 0;
+	surface->current_clip.width = surface->width;
+	surface->current_clip.height = surface->height;
+	status = CAIRO_STATUS_SUCCESS;
+    } else {
+	status = _cairo_path_fixed_bounds (path, &x1, &y1, &x2, &y2);
+	if (status)
+	    return status;
+
+	extent.x = floor (x1);
+	extent.y = floor (y1);
+	extent.width = ceil (x2) - extent.x;
+	extent.height = ceil (y2) - extent.y;
+
+	_cairo_rectangle_intersect (&surface->current_clip, &extent);
+    }
+
+    return status;
+}
+
+static cairo_int_status_t
 _cairo_analysis_surface_get_extents (void	 		*abstract_surface,
 				     cairo_rectangle_int_t	*rectangle)
 {
@@ -62,17 +177,32 @@ _cairo_analysis_surface_paint (void			*a
 			      cairo_pattern_t		*source)
 {
     cairo_analysis_surface_t *surface = abstract_surface;
-    cairo_status_t	     status;
+    cairo_status_t	     status, backend_status;
+    cairo_rectangle_int_t  extents;
 
     if (!surface->target->backend->paint)
-	status = CAIRO_INT_STATUS_UNSUPPORTED;
+	backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
     else
-	status = (*surface->target->backend->paint) (surface->target, op,
-						     source);
-    if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
-	surface->fallback = TRUE;
-	status = CAIRO_STATUS_SUCCESS;
+	backend_status = (*surface->target->backend->paint) (surface->target, op,
+                                                             source);
+
+    status = _cairo_surface_get_extents (&surface->base, &extents);
+    if (status)
+	return status;
+
+    if (_cairo_operator_bounded_by_source (op)) {
+	cairo_rectangle_int_t source_extents;
+	status = _cairo_pattern_get_extents (source, &source_extents);
+	if (status)
+	    return status;
+
+	_cairo_rectangle_intersect (&extents, &source_extents);
     }
+
+    _cairo_rectangle_intersect (&extents, &surface->current_clip);
+
+    status = _cairo_analysis_surface_add_operation (surface, &extents, backend_status);
+
     return status;
 }
 
@@ -83,17 +213,38 @@ _cairo_analysis_surface_mask (void		*abs
 			      cairo_pattern_t	*mask)
 {
     cairo_analysis_surface_t *surface = abstract_surface;
-    cairo_status_t	     status;
+    cairo_status_t	      status, backend_status;
+    cairo_rectangle_int_t   extents;
 
     if (!surface->target->backend->mask)
-	status = CAIRO_INT_STATUS_UNSUPPORTED;
+	backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
     else
-	status = (*surface->target->backend->mask) (surface->target, op,
-						    source, mask);
-    if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
-	surface->fallback = TRUE;
-	status = CAIRO_STATUS_SUCCESS;
+	backend_status = (*surface->target->backend->mask) (surface->target, op,
+                                                            source, mask);
+
+    status = _cairo_surface_get_extents (&surface->base, &extents);
+    if (status)
+	return status;
+
+    if (_cairo_operator_bounded_by_source (op)) {
+	cairo_rectangle_int_t source_extents;
+	status = _cairo_pattern_get_extents (source, &source_extents);
+	if (status)
+	    return status;
+
+	_cairo_rectangle_intersect (&extents, &source_extents);
+
+	status = _cairo_pattern_get_extents (mask, &source_extents);
+	if (status)
+	    return status;
+
+	_cairo_rectangle_intersect (&extents, &source_extents);
     }
+
+    _cairo_rectangle_intersect (&extents, &surface->current_clip);
+
+    status = _cairo_analysis_surface_add_operation (surface, &extents, backend_status);
+
     return status;
 }
 
@@ -109,19 +260,61 @@ _cairo_analysis_surface_stroke (void			*
 				cairo_antialias_t	 antialias)
 {
     cairo_analysis_surface_t *surface = abstract_surface;
-    cairo_status_t	     status;
+    cairo_status_t	     status, backend_status;
+    cairo_traps_t            traps;
+    cairo_box_t              box;
+    cairo_rectangle_int_t  extents;
 
     if (!surface->target->backend->stroke)
-	status = CAIRO_INT_STATUS_UNSUPPORTED;
+	backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
     else
-	status = (*surface->target->backend->stroke) (surface->target, op,
-						      source, path, style,
-						      ctm, ctm_inverse,
-						      tolerance, antialias);
-    if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
-	surface->fallback = TRUE;
-	status = CAIRO_STATUS_SUCCESS;
+	backend_status = (*surface->target->backend->stroke) (surface->target, op,
+							      source, path, style,
+							      ctm, ctm_inverse,
+							      tolerance, antialias);
+
+    status = _cairo_surface_get_extents (&surface->base, &extents);
+    if (status)
+	return status;
+
+    if (_cairo_operator_bounded_by_source (op)) {
+	cairo_rectangle_int_t source_extents;
+	status = _cairo_pattern_get_extents (source, &source_extents);
+	if (status)
+	    return status;
+
+	_cairo_rectangle_intersect (&extents, &source_extents);
     }
+
+    _cairo_rectangle_intersect (&extents, &surface->current_clip);
+
+    box.p1.x = _cairo_fixed_from_int (extents.x);
+    box.p1.y = _cairo_fixed_from_int (extents.y);
+    box.p2.x = _cairo_fixed_from_int (extents.x + extents.width);
+    box.p2.y = _cairo_fixed_from_int (extents.y + extents.height);
+
+    _cairo_traps_init (&traps);
+
+    _cairo_traps_limit (&traps, &box);
+
+    status = _cairo_path_fixed_stroke_to_traps (path,
+						style,
+						ctm, ctm_inverse,
+						tolerance,
+						&traps);
+    if (status)
+	goto FINISH;
+
+    _cairo_traps_extents (&traps, &box);
+    extents.x = _cairo_fixed_integer_floor (box.p1.x);
+    extents.y = _cairo_fixed_integer_floor (box.p1.y);
+    extents.width = _cairo_fixed_integer_ceil (box.p2.x) - extents.x;
+    extents.height = _cairo_fixed_integer_ceil (box.p2.y) - extents.y;
+    status = _cairo_analysis_surface_add_operation (surface, &extents, backend_status);
+
+FINISH:
+    _cairo_traps_fini (&traps);
+
     return status;
 }
 
@@ -135,18 +328,59 @@ _cairo_analysis_surface_fill (void			*ab
 			      cairo_antialias_t	 	 antialias)
 {
     cairo_analysis_surface_t *surface = abstract_surface;
-    cairo_status_t	     status;
+    cairo_status_t	     status, backend_status;
+    cairo_traps_t            traps;
+    cairo_box_t              box;
+    cairo_rectangle_int_t  extents;
 
     if (!surface->target->backend->fill)
-	status = CAIRO_INT_STATUS_UNSUPPORTED;
+	backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
     else
-	status = (*surface->target->backend->fill) (surface->target, op,
+	backend_status = (*surface->target->backend->fill) (surface->target, op,
 						    source, path, fill_rule,
 						    tolerance, antialias);
-    if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
-	surface->fallback = TRUE;
-	status = CAIRO_STATUS_SUCCESS;
+
+    status = _cairo_surface_get_extents (&surface->base, &extents);
+    if (status)
+	return status;
+
+    if (_cairo_operator_bounded_by_source (op)) {
+	cairo_rectangle_int_t source_extents;
+	status = _cairo_pattern_get_extents (source, &source_extents);
+	if (status)
+	    return status;
+
+	_cairo_rectangle_intersect (&extents, &source_extents);
     }
+
+    _cairo_rectangle_intersect (&extents, &surface->current_clip);
+
+    box.p1.x = _cairo_fixed_from_int (extents.x);
+    box.p1.y = _cairo_fixed_from_int (extents.y);
+    box.p2.x = _cairo_fixed_from_int (extents.x + extents.width);
+    box.p2.y = _cairo_fixed_from_int (extents.y + extents.height);
+
+    _cairo_traps_init (&traps);
+
+    _cairo_traps_limit (&traps, &box);
+
+    status = _cairo_path_fixed_fill_to_traps (path,
+					      fill_rule,
+					      tolerance,
+					      &traps);
+    if (status)
+	goto FINISH;
+
+    _cairo_traps_extents (&traps, &box);
+    extents.x = _cairo_fixed_integer_floor (box.p1.x);
+    extents.y = _cairo_fixed_integer_floor (box.p1.y);
+    extents.width = _cairo_fixed_integer_ceil (box.p2.x) - extents.x;
+    extents.height = _cairo_fixed_integer_ceil (box.p2.y) - extents.y;
+    status = _cairo_analysis_surface_add_operation (surface, &extents, backend_status);
+
+FINISH:
+    _cairo_traps_fini (&traps);
+
     return status;
 }
 
@@ -159,26 +393,34 @@ _cairo_analysis_surface_show_glyphs (voi
 				     cairo_scaled_font_t  *scaled_font)
 {
     cairo_analysis_surface_t *surface = abstract_surface;
-    cairo_status_t	     status;
+    cairo_status_t	     status, backend_status;
+    cairo_rectangle_int_t  extent;
 
     if (!surface->target->backend->show_glyphs)
-	status = CAIRO_INT_STATUS_UNSUPPORTED;
+	backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
     else
-	status = (*surface->target->backend->show_glyphs) (surface->target, op,
+	backend_status = (*surface->target->backend->show_glyphs) (surface->target, op,
 							   source,
 							   glyphs, num_glyphs,
 							   scaled_font);
-    if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
-	surface->fallback = TRUE;
-	status = CAIRO_STATUS_SUCCESS;
-    }
+
+    status = _cairo_scaled_font_glyph_device_extents (scaled_font,
+						      glyphs,
+						      num_glyphs,
+						      &extent);
+    if (status)
+	return status;
+
+    _cairo_rectangle_intersect (&extent, &surface->current_clip);
+    status = _cairo_analysis_surface_add_operation (surface, &extent, backend_status);
+
     return status;
 }
 
 static const cairo_surface_backend_t cairo_analysis_surface_backend = {
     CAIRO_INTERNAL_SURFACE_TYPE_ANALYSIS,
     NULL, /* create_similar */
-    NULL, /* finish_surface */
+    _cairo_analysis_surface_finish,
     NULL, /* acquire_source_image */
     NULL, /* release_source_image */
     NULL, /* acquire_dest_image */
@@ -190,7 +432,7 @@ static const cairo_surface_backend_t cai
     NULL, /* copy_page */
     NULL, /* show_page */
     NULL, /* set_clip_region */
-    NULL, /* clip_path */
+    _cairo_analysis_surface_intersect_clip_path,
     _cairo_analysis_surface_get_extents,
     NULL, /* old_show_glyphs */
     NULL, /* get_font_options */
@@ -206,7 +448,7 @@ static const cairo_surface_backend_t cai
     NULL, /* snapshot */
 };
 
-cairo_private cairo_surface_t *
+cairo_surface_t *
 _cairo_analysis_surface_create (cairo_surface_t		*target,
 				int			 width,
 				int			 height)
@@ -226,7 +468,15 @@ _cairo_analysis_surface_create (cairo_su
     surface->height = height;
 
     surface->target = target;
-    surface->fallback = FALSE;
+    surface->has_supported = FALSE;
+    surface->has_unsupported = FALSE;
+    _cairo_region_init (&surface->supported_region);
+    _cairo_region_init (&surface->fallback_region);
+
+    surface->current_clip.x = 0;
+    surface->current_clip.y = 0;
+    surface->current_clip.width = width;
+    surface->current_clip.height = height;
 
     return &surface->base;
 FAIL:
@@ -234,24 +484,34 @@ FAIL:
     return NULL;
 }
 
-cairo_private cairo_region_t *
+cairo_region_t *
 _cairo_analysis_surface_get_supported (cairo_surface_t *abstract_surface)
 {
-    /* XXX */
-    return NULL;
+    cairo_analysis_surface_t	*surface = (cairo_analysis_surface_t *) abstract_surface;
+
+    return &surface->supported_region;
 }
 
-cairo_private cairo_region_t *
+cairo_region_t *
 _cairo_analysis_surface_get_unsupported (cairo_surface_t *abstract_surface)
 {
-    /* XXX */
-    return NULL;
+    cairo_analysis_surface_t	*surface = (cairo_analysis_surface_t *) abstract_surface;
+
+    return &surface->fallback_region;
+}
+
+cairo_bool_t
+_cairo_analysis_surface_has_supported (cairo_surface_t *abstract_surface)
+{
+    cairo_analysis_surface_t	*surface = (cairo_analysis_surface_t *) abstract_surface;
+
+    return surface->has_supported;
 }
 
-cairo_private cairo_bool_t
+cairo_bool_t
 _cairo_analysis_surface_has_unsupported (cairo_surface_t *abstract_surface)
 {
     cairo_analysis_surface_t	*surface = (cairo_analysis_surface_t *) abstract_surface;
 
-    return surface->fallback;
+    return surface->has_unsupported;
 }
diff --git a/src/cairo-meta-surface-private.h b/src/cairo-meta-surface-private.h
index 3f2d390..b6d5730 100644
--- a/src/cairo-meta-surface-private.h
+++ b/src/cairo-meta-surface-private.h
@@ -31,6 +31,7 @@
  *
  * Contributor(s):
  *	Kristian Høgsberg <krh at redhat.com>
+ *	Adrian Johnson <ajohnson at redneon.com>
  */
 
 #ifndef CAIRO_META_SURFACE_H
@@ -57,21 +58,32 @@ typedef enum {
 
 } cairo_command_type_t;
 
-typedef struct _cairo_command_paint {
+typedef enum {
+    CAIRO_META_REGION_ALL,
+    CAIRO_META_REGION_NATIVE,
+    CAIRO_META_REGION_IMAGE_FALLBACK,
+} cairo_meta_region_type_t;
+
+typedef struct _cairo_command_header {
     cairo_command_type_t	 type;
+    cairo_meta_region_type_t     region;
+} cairo_command_header_t;
+
+typedef struct _cairo_command_paint {
+    cairo_command_header_t       header;
     cairo_operator_t		 op;
     cairo_pattern_union_t	 source;
 } cairo_command_paint_t;
 
 typedef struct _cairo_command_mask {
-    cairo_command_type_t	 type;
+    cairo_command_header_t       header;
     cairo_operator_t		 op;
     cairo_pattern_union_t	 source;
     cairo_pattern_union_t	 mask;
 } cairo_command_mask_t;
 
 typedef struct _cairo_command_stroke {
-    cairo_command_type_t	 type;
+    cairo_command_header_t       header;
     cairo_operator_t		 op;
     cairo_pattern_union_t	 source;
     cairo_path_fixed_t		 path;
@@ -83,7 +95,7 @@ typedef struct _cairo_command_stroke {
 } cairo_command_stroke_t;
 
 typedef struct _cairo_command_fill {
-    cairo_command_type_t	 type;
+    cairo_command_header_t       header;
     cairo_operator_t		 op;
     cairo_pattern_union_t	 source;
     cairo_path_fixed_t		 path;
@@ -93,7 +105,7 @@ typedef struct _cairo_command_fill {
 } cairo_command_fill_t;
 
 typedef struct _cairo_command_show_glyphs {
-    cairo_command_type_t	 type;
+    cairo_command_header_t       header;
     cairo_operator_t		 op;
     cairo_pattern_union_t	 source;
     cairo_glyph_t		*glyphs;
@@ -102,7 +114,7 @@ typedef struct _cairo_command_show_glyph
 } cairo_command_show_glyphs_t;
 
 typedef struct _cairo_command_intersect_clip_path {
-    cairo_command_type_t	type;
+    cairo_command_header_t      header;
     cairo_path_fixed_t	       *path_pointer;
     cairo_path_fixed_t		path;
     cairo_fill_rule_t		fill_rule;
@@ -111,7 +123,7 @@ typedef struct _cairo_command_intersect_
 } cairo_command_intersect_clip_path_t;
 
 typedef union _cairo_command {
-    cairo_command_type_t			type;
+    cairo_command_header_t      header;
 
     /* The 5 basic drawing operations. */
     cairo_command_paint_t			paint;
@@ -151,6 +163,14 @@ cairo_private cairo_status_t
 _cairo_meta_surface_replay (cairo_surface_t *surface,
 			    cairo_surface_t *target);
 
+cairo_private cairo_status_t
+_cairo_meta_surface_replay_and_create_regions (cairo_surface_t *surface,
+					       cairo_surface_t *target);
+cairo_private cairo_status_t
+_cairo_meta_surface_replay_region (cairo_surface_t          *surface,
+				   cairo_surface_t          *target,
+				   cairo_meta_region_type_t  region);
+
 cairo_private cairo_bool_t
 _cairo_surface_is_meta (const cairo_surface_t *surface);
 
diff --git a/src/cairo-meta-surface.c b/src/cairo-meta-surface.c
index 9997baf..35039ad 100644
--- a/src/cairo-meta-surface.c
+++ b/src/cairo-meta-surface.c
@@ -1,6 +1,7 @@
 /* cairo - a vector graphics library with display and print output
  *
  * Copyright © 2005 Red Hat, Inc
+ * Copyright © 2007 Adrian Johnson
  *
  * This library is free software; you can redistribute it and/or
  * modify it either under the terms of the GNU Lesser General Public
@@ -32,6 +33,7 @@
  * Contributor(s):
  *	Kristian Høgsberg <krh at redhat.com>
  *	Carl Worth <cworth at cworth.org>
+ *	Adrian Johnson <ajohnson at redneon.com>
  */
 
 /* A meta surface is a surface that records all drawing operations at
@@ -123,7 +125,7 @@ _cairo_meta_surface_finish (void *abstra
     elements = _cairo_array_index (&meta->commands, 0);
     for (i = 0; i < num_elements; i++) {
 	command = elements[i];
-	switch (command->type) {
+	switch (command->header.type) {
 
 	/* 5 basic drawing operations */
 
@@ -253,7 +255,8 @@ _cairo_meta_surface_paint (void			*abstr
     if (command == NULL)
 	return CAIRO_STATUS_NO_MEMORY;
 
-    command->type = CAIRO_COMMAND_PAINT;
+    command->header.type = CAIRO_COMMAND_PAINT;
+    command->header.region = CAIRO_META_REGION_ALL;
     command->op = op;
 
     status = _init_pattern_with_snapshot (&command->source.base, source);
@@ -287,7 +290,8 @@ _cairo_meta_surface_mask (void			*abstra
     if (command == NULL)
 	return CAIRO_STATUS_NO_MEMORY;
 
-    command->type = CAIRO_COMMAND_MASK;
+    command->header.type = CAIRO_COMMAND_MASK;
+    command->header.region = CAIRO_META_REGION_ALL;
     command->op = op;
 
     status = _init_pattern_with_snapshot (&command->source.base, source);
@@ -332,7 +336,8 @@ _cairo_meta_surface_stroke (void			*abst
     if (command == NULL)
 	return CAIRO_STATUS_NO_MEMORY;
 
-    command->type = CAIRO_COMMAND_STROKE;
+    command->header.type = CAIRO_COMMAND_STROKE;
+    command->header.region = CAIRO_META_REGION_ALL;
     command->op = op;
 
     status = _init_pattern_with_snapshot (&command->source.base, source);
@@ -386,7 +391,8 @@ _cairo_meta_surface_fill (void			*abstra
     if (command == NULL)
 	return CAIRO_STATUS_NO_MEMORY;
 
-    command->type = CAIRO_COMMAND_FILL;
+    command->header.type = CAIRO_COMMAND_FILL;
+    command->header.region = CAIRO_META_REGION_ALL;
     command->op = op;
 
     status = _init_pattern_with_snapshot (&command->source.base, source);
@@ -432,7 +438,8 @@ _cairo_meta_surface_show_glyphs (void			
     if (command == NULL)
 	return CAIRO_STATUS_NO_MEMORY;
 
-    command->type = CAIRO_COMMAND_SHOW_GLYPHS;
+    command->header.type = CAIRO_COMMAND_SHOW_GLYPHS;
+    command->header.region = CAIRO_META_REGION_ALL;
     command->op = op;
 
     status = _init_pattern_with_snapshot (&command->source.base, source);
@@ -521,7 +528,8 @@ _cairo_meta_surface_intersect_clip_path 
     if (command == NULL)
 	return CAIRO_STATUS_NO_MEMORY;
 
-    command->type = CAIRO_COMMAND_INTERSECT_CLIP_PATH;
+    command->header.type = CAIRO_COMMAND_INTERSECT_CLIP_PATH;
+    command->header.region = CAIRO_META_REGION_ALL;
 
     if (path) {
 	status = _cairo_path_fixed_init_copy (&command->path, path);
@@ -622,7 +630,7 @@ static const cairo_surface_backend_t cai
 static cairo_path_fixed_t *
 _cairo_command_get_path (cairo_command_t *command)
 {
-    switch (command->type) {
+    switch (command->header.type) {
     case CAIRO_COMMAND_PAINT:
     case CAIRO_COMMAND_MASK:
     case CAIRO_COMMAND_SHOW_GLYPHS:
@@ -639,9 +647,11 @@ _cairo_command_get_path (cairo_command_t
     return NULL;
 }
 
-cairo_status_t
-_cairo_meta_surface_replay (cairo_surface_t *surface,
-			    cairo_surface_t *target)
+static cairo_status_t
+_cairo_meta_surface_replay_internal (cairo_surface_t	     *surface,
+				     cairo_surface_t	     *target,
+				     cairo_bool_t	      create_regions,
+				     cairo_meta_region_type_t region)
 {
     cairo_meta_surface_t *meta;
     cairo_command_t *command, **elements;
@@ -665,9 +675,14 @@ _cairo_meta_surface_replay (cairo_surfac
     for (i = meta->replay_start_idx; i < num_elements; i++) {
 	command = elements[i];
 
+	if (!create_regions && region != CAIRO_META_REGION_ALL) {
+	    if (command->header.region != region)
+		continue;
+        }
+
 	/* For all commands except intersect_clip_path, we have to
 	 * ensure the current clip gets set on the surface. */
-	if (command->type != CAIRO_COMMAND_INTERSECT_CLIP_PATH) {
+	if (command->header.type != CAIRO_COMMAND_INTERSECT_CLIP_PATH) {
 	    status = _cairo_surface_set_clip (target, &clip);
 	    if (status)
 		break;
@@ -682,7 +697,7 @@ _cairo_meta_surface_replay (cairo_surfac
 	    dev_path = &path_copy;
 	}
 
-	switch (command->type) {
+	switch (command->header.type) {
 	case CAIRO_COMMAND_PAINT:
 	    status = _cairo_surface_paint (target,
 					   command->paint.op,
@@ -770,6 +785,7 @@ _cairo_meta_surface_replay (cairo_surfac
 					   command->intersect_clip_path.tolerance,
 					   command->intersect_clip_path.antialias,
 					   target);
+            assert (status == 0);
 	    break;
 	default:
 	    ASSERT_NOT_REACHED;
@@ -778,6 +794,14 @@ _cairo_meta_surface_replay (cairo_surfac
 	if (dev_path == &path_copy)
 	    _cairo_path_fixed_fini (&path_copy);
 
+	if (create_regions) {
+	    if (status == CAIRO_STATUS_SUCCESS) {
+		command->header.region = CAIRO_META_REGION_NATIVE;
+	    } else if (status == CAIRO_INT_STATUS_IMAGE_FALLBACK) {
+		command->header.region = CAIRO_META_REGION_IMAGE_FALLBACK;
+		status = CAIRO_STATUS_SUCCESS;
+	    }
+	}
 	if (status)
 	    break;
     }
@@ -786,3 +810,31 @@ _cairo_meta_surface_replay (cairo_surfac
 
     return status;
 }
+
+cairo_status_t
+_cairo_meta_surface_replay (cairo_surface_t *surface,
+			    cairo_surface_t *target)
+{
+    return _cairo_meta_surface_replay_internal (surface, target, FALSE, CAIRO_META_REGION_ALL);
+}
+
+/* Replay meta to surface. When the return status of each operation is
+ * one of CAIRO_STATUS_SUCCESS, CAIRO_INT_STATUS_UNSUPPORTED, or
+ * CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY the status of each operation
+ * will be stored in the meta surface. Any other status will abort the
+ * replay and return the status.
+ */
+cairo_status_t
+_cairo_meta_surface_replay_and_create_regions (cairo_surface_t *surface,
+					       cairo_surface_t *target)
+{
+    return _cairo_meta_surface_replay_internal (surface, target, TRUE, CAIRO_META_REGION_ALL);
+}
+
+cairo_status_t
+_cairo_meta_surface_replay_region (cairo_surface_t          *surface,
+				   cairo_surface_t          *target,
+				   cairo_meta_region_type_t  region)
+{
+    return _cairo_meta_surface_replay_internal (surface, target, FALSE, region);
+}
diff --git a/src/cairo-paginated-surface.c b/src/cairo-paginated-surface.c
index d687037..1886bef 100644
--- a/src/cairo-paginated-surface.c
+++ b/src/cairo-paginated-surface.c
@@ -1,6 +1,7 @@
 /* cairo - a vector graphics library with display and print output
  *
  * Copyright © 2005 Red Hat, Inc
+ * Copyright © 2007 Adrian Johnson
  *
  * This library is free software; you can redistribute it and/or
  * modify it either under the terms of the GNU Lesser General Public
@@ -32,6 +33,7 @@
  * Contributor(s):
  *	Carl Worth <cworth at cworth.org>
  *	Keith Packard <keithp at keithp.com>
+ *	Adrian Johnson <ajohnson at redneon.com>
  */
 
 /* The paginated surface layer exists to provide as much code sharing
@@ -210,12 +212,54 @@ _cairo_paginated_surface_release_source_
 }
 
 static cairo_int_status_t
-_paint_page (cairo_paginated_surface_t *surface)
+_paint_fallback_image (cairo_paginated_surface_t *surface,
+		       cairo_box_int_t           *box)
 {
-    cairo_surface_t *analysis;
+    double x_scale = surface->base.x_fallback_resolution / 72.0;
+    double y_scale = surface->base.y_fallback_resolution / 72.0;
+    cairo_matrix_t matrix;
+    int x, y, width, height;
+    cairo_status_t status;
     cairo_surface_t *image;
     cairo_pattern_t *pattern;
+
+    x = box->p1.x;
+    y = box->p1.y;
+    width = box->p2.x - x;
+    height = box->p2.y - y;
+    image = _cairo_paginated_surface_create_image_surface (surface,
+							   width  * x_scale,
+							   height * y_scale);
+    _cairo_surface_set_device_scale (image, x_scale, y_scale);
+    /* set_device_offset just sets the x0/y0 components of the matrix;
+     * so we have to do the scaling manually. */
+    cairo_surface_set_device_offset (image, -x*x_scale, -y*y_scale);
+
+    status = _cairo_meta_surface_replay (surface->meta, image);
+    if (status)
+	goto CLEANUP_IMAGE;
+
+    pattern = cairo_pattern_create_for_surface (image);
+    cairo_matrix_init (&matrix, x_scale, 0, 0, y_scale, -x*x_scale, -y*y_scale);
+    cairo_pattern_set_matrix (pattern, &matrix);
+
+    status = _cairo_surface_paint (surface->target,
+				   CAIRO_OPERATOR_SOURCE,
+				   pattern);
+
+    cairo_pattern_destroy (pattern);
+CLEANUP_IMAGE:
+    cairo_surface_destroy (image);
+
+    return status;
+}
+
+static cairo_int_status_t
+_paint_page (cairo_paginated_surface_t *surface)
+{
+    cairo_surface_t *analysis;
     cairo_status_t status;
+    cairo_bool_t has_supported, has_page_fallback, has_finegrained_fallback;
 
     analysis = _cairo_analysis_surface_create (surface->target,
 					       surface->width, surface->height);
@@ -223,7 +267,7 @@ _paint_page (cairo_paginated_surface_t *
 	return CAIRO_STATUS_NO_MEMORY;
 
     surface->backend->set_paginated_mode (surface->target, CAIRO_PAGINATED_MODE_ANALYZE);
-    status = _cairo_meta_surface_replay (surface->meta, analysis);
+    status = _cairo_meta_surface_replay_and_create_regions (surface->meta, analysis);
     surface->backend->set_paginated_mode (surface->target, CAIRO_PAGINATED_MODE_RENDER);
 
     if (status || analysis->status) {
@@ -233,35 +277,70 @@ _paint_page (cairo_paginated_surface_t *
 	return status;
     }
 
-    if (_cairo_analysis_surface_has_unsupported (analysis))
-    {
-	double x_scale = surface->base.x_fallback_resolution / 72.0;
-	double y_scale = surface->base.y_fallback_resolution / 72.0;
-	cairo_matrix_t matrix;
-
-	image = _cairo_paginated_surface_create_image_surface (surface,
-							       surface->width  * x_scale,
-							       surface->height * y_scale);
-	_cairo_surface_set_device_scale (image, x_scale, y_scale);
+    /* Finer grained fallbacks are currently only supported for PostScript surfaces */
+    if (surface->target->type == CAIRO_SURFACE_TYPE_PS) {
+	has_supported = _cairo_analysis_surface_has_supported (analysis);
+	has_page_fallback = FALSE;
+	has_finegrained_fallback = _cairo_analysis_surface_has_unsupported (analysis);
+    } else {
+	if (_cairo_analysis_surface_has_unsupported (analysis)) {
+	    has_supported = FALSE;
+	    has_page_fallback = TRUE;
+	} else {
+	    has_supported = TRUE;
+	    has_page_fallback = FALSE;
+	}
+	has_finegrained_fallback = FALSE;
+    }
 
-	status = _cairo_meta_surface_replay (surface->meta, image);
+    if (has_supported) {
+	status = _cairo_meta_surface_replay_region (surface->meta,
+						    surface->target,
+						    CAIRO_META_REGION_NATIVE);
 	if (status)
-	    goto CLEANUP_IMAGE;
-
-	pattern = cairo_pattern_create_for_surface (image);
-	cairo_matrix_init_scale (&matrix, x_scale, y_scale);
-	cairo_pattern_set_matrix (pattern, &matrix);
-
-	status = _cairo_surface_paint (surface->target, CAIRO_OPERATOR_SOURCE, pattern);
+	    return status;
+    }
 
-	cairo_pattern_destroy (pattern);
+    if (has_page_fallback)
+    {
+	cairo_box_int_t box;
 
-     CLEANUP_IMAGE:
-	cairo_surface_destroy (image);
+	box.p1.x = 0;
+	box.p1.y = 0;
+	box.p2.x = surface->width;
+	box.p2.y = surface->height;
+	status = _paint_fallback_image (surface, &box);
+	if (status)
+	    return status;
     }
-    else
+
+    if (has_finegrained_fallback)
     {
-	status = _cairo_meta_surface_replay (surface->meta, surface->target);
+        cairo_region_t *region;
+        cairo_box_int_t *boxes;
+        int num_boxes, i;
+
+	/* Reset clip region before drawing the fall back images */
+	status = _cairo_surface_intersect_clip_path (surface->target,
+						     NULL,
+						     CAIRO_FILL_RULE_WINDING,
+						     CAIRO_GSTATE_TOLERANCE_DEFAULT,
+						     CAIRO_ANTIALIAS_DEFAULT);
+	if (status)
+	    return status;
+
+	region = _cairo_analysis_surface_get_unsupported (analysis);
+	status = _cairo_region_get_boxes (region, &num_boxes, &boxes);
+	if (status)
+	    return status;
+	for (i = 0; i < num_boxes; i++) {
+	    status = _paint_fallback_image (surface, &boxes[i]);
+	    if (status) {
+                _cairo_region_boxes_fini (region, boxes);
+		return status;
+            }
+	}
+        _cairo_region_boxes_fini (region, boxes);
     }
 
     cairo_surface_destroy (analysis);
diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c
index 05746a8..df78212 100644
--- a/src/cairo-ps-surface.c
+++ b/src/cairo-ps-surface.c
@@ -1359,34 +1359,53 @@ pattern_supported (const cairo_pattern_t
 }
 
 static cairo_int_status_t
-_cairo_ps_surface_operation_supported (cairo_ps_surface_t *surface,
-		      cairo_operator_t op,
-		      const cairo_pattern_t *pattern)
+_cairo_ps_surface_analyze_operation (cairo_ps_surface_t    *surface,
+				     cairo_operator_t       op,
+				     const cairo_pattern_t *pattern)
 {
-    if (surface->force_fallbacks)
-	return FALSE;
+    if (surface->force_fallbacks && surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
+	return CAIRO_INT_STATUS_UNSUPPORTED;
 
     if (! pattern_supported (pattern))
-	return FALSE;
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+
+    if (op == CAIRO_OPERATOR_SOURCE)
+	return CAIRO_STATUS_SUCCESS;
+
+    if (op != CAIRO_OPERATOR_OVER)
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+
+    /* CAIRO_OPERATOR_OVER is only supported for opaque patterns. If
+     * the pattern contains transparency, we return
+     * CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY to the analysis
+     * surface. If the analysis surface determines that there is
+     * anything drawn under this operation, a fallback image will be
+     * used. Otherwise the operation will be replayed during the
+     * render stage and we blend the transarency into the white
+     * background to convert the pattern to opaque.
+     */
 
     if (_cairo_operator_always_opaque (op))
-	return TRUE;
+	return CAIRO_STATUS_SUCCESS;
 
     if (_cairo_operator_always_translucent (op))
-	return FALSE;
+	return CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY;
 
-    return _cairo_pattern_is_opaque (pattern);
+    if (_cairo_pattern_is_opaque (pattern))
+	return CAIRO_STATUS_SUCCESS;
+    else
+	return CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY;
 }
 
-static cairo_int_status_t
-_cairo_ps_surface_analyze_operation (cairo_ps_surface_t *surface,
-		    cairo_operator_t op,
-		    const cairo_pattern_t *pattern)
+static cairo_bool_t
+_cairo_ps_surface_operation_supported (cairo_ps_surface_t    *surface,
+				       cairo_operator_t       op,
+				       const cairo_pattern_t *pattern)
 {
-    if (_cairo_ps_surface_operation_supported (surface, op, pattern))
-	return CAIRO_STATUS_SUCCESS;
+    if (_cairo_ps_surface_analyze_operation (surface, op, pattern) != CAIRO_INT_STATUS_UNSUPPORTED)
+	return TRUE;
     else
-	return CAIRO_INT_STATUS_UNSUPPORTED;
+	return FALSE;
 }
 
 /* The "standard" implementation limit for PostScript string sizes is
@@ -1514,8 +1533,8 @@ _string_array_stream_create (cairo_outpu
 
 static cairo_status_t
 _cairo_ps_surface_emit_image (cairo_ps_surface_t    *surface,
-	    cairo_image_surface_t *image,
-	    const char		  *name)
+			      cairo_image_surface_t *image,
+			      const char	    *name)
 {
     cairo_status_t status, status2;
     unsigned char *rgb, *compressed;
@@ -1659,24 +1678,33 @@ _cairo_ps_surface_emit_image (cairo_ps_s
 }
 
 static void
-_cairo_ps_surface_emit_solid_pattern (cairo_ps_surface_t *surface,
-		    cairo_solid_pattern_t *pattern)
+_cairo_ps_surface_emit_solid_pattern (cairo_ps_surface_t    *surface,
+				      cairo_solid_pattern_t *pattern)
 {
-    if (color_is_gray (&pattern->color))
+    cairo_color_t color = pattern->color;
+
+    if (!CAIRO_COLOR_IS_OPAQUE(&color)) {
+	/* Blend into white */
+	color.red = color.red*color.alpha + 1 - color.alpha;
+	color.green = color.green*color.alpha + 1 - color.alpha;
+	color.blue = color.blue*color.alpha + 1 - color.alpha;
+    }
+
+    if (color_is_gray (&color))
 	_cairo_output_stream_printf (surface->stream,
 				     "%f G\n",
-				     pattern->color.red);
+				     color.red);
     else
 	_cairo_output_stream_printf (surface->stream,
 				     "%f %f %f R\n",
-				     pattern->color.red,
-				     pattern->color.green,
-				     pattern->color.blue);
+				     color.red,
+				     color.green,
+				     color.blue);
 }
 
 static cairo_status_t
-_cairo_ps_surface_emit_surface_pattern (cairo_ps_surface_t *surface,
-		      cairo_surface_pattern_t *pattern)
+_cairo_ps_surface_emit_surface_pattern (cairo_ps_surface_t      *surface,
+					cairo_surface_pattern_t *pattern)
 {
     cairo_status_t status;
     double bbox_width, bbox_height;
@@ -1919,15 +1947,7 @@ _cairo_ps_surface_paint (void			*abstrac
     if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
 	return _cairo_ps_surface_analyze_operation (surface, op, source);
 
-    /* XXX: It would be nice to be able to assert this condition
-     * here. But, we actually allow one 'cheat' that is used when
-     * painting the final image-based fallbacks. The final fallbacks
-     * do have alpha which we support by blending with white. This is
-     * possible only because there is nothing between the fallback
-     * images and the paper, nor is anything painted above. */
-    /*
-    assert (_cairo_ps_surface_operation_supported (op, source));
-    */
+    assert (_cairo_ps_surface_operation_supported (surface, op, source));
 
     _cairo_output_stream_printf (stream,
 				 "%% _cairo_ps_surface_paint\n");
@@ -2017,7 +2037,6 @@ _cairo_ps_surface_stroke (void			*abstra
 
     assert (_cairo_ps_surface_operation_supported (surface, op, source));
 
-
     _cairo_output_stream_printf (stream,
 				 "%% _cairo_ps_surface_stroke\n");
 
diff --git a/src/cairo-region-private.h b/src/cairo-region-private.h
index a3ee759..7f92f9c 100644
--- a/src/cairo-region-private.h
+++ b/src/cairo-region-private.h
@@ -102,4 +102,8 @@ cairo_private void
 _cairo_region_translate (cairo_region_t *region,
 			 int x, int y);
 
+cairo_private pixman_region_overlap_t
+_cairo_region_contains_rectangle (cairo_region_t *region, cairo_rectangle_int_t *box);
+
+
 #endif /* CAIRO_REGION_PRIVATE_H */
diff --git a/src/cairo-region.c b/src/cairo-region.c
index fe2b405..4fe6832 100644
--- a/src/cairo-region.c
+++ b/src/cairo-region.c
@@ -207,3 +207,16 @@ _cairo_region_translate (cairo_region_t 
 {
     pixman_region_translate (&region->rgn, x, y);
 }
+
+pixman_region_overlap_t
+_cairo_region_contains_rectangle (cairo_region_t *region, cairo_rectangle_int_t *rect)
+{
+    pixman_box16_t pbox;
+
+    pbox.x1 = rect->x;
+    pbox.y1 = rect->y;
+    pbox.x2 = rect->x + rect->width;
+    pbox.y2 = rect->y + rect->height;
+
+    return pixman_region_contains_rectangle (&region->rgn, &pbox);
+}
diff --git a/src/cairoint.h b/src/cairoint.h
index dca8e6a..fd3a647 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -325,7 +325,9 @@ typedef enum cairo_int_status {
     CAIRO_INT_STATUS_DEGENERATE = 1000,
     CAIRO_INT_STATUS_UNSUPPORTED,
     CAIRO_INT_STATUS_NOTHING_TO_DO,
-    CAIRO_INT_STATUS_CACHE_EMPTY
+    CAIRO_INT_STATUS_CACHE_EMPTY,
+    CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY,
+    CAIRO_INT_STATUS_IMAGE_FALLBACK
 } cairo_int_status_t;
 
 typedef enum cairo_internal_surface_type {


More information about the cairo-commit mailing list