[cairo] Cairo and layered application

Mathias Hasselmann mathias.hasselmann at gmx.de
Fri Mar 9 13:41:32 PST 2007


Updated version of the patch which should properly release memory
allocated in pixman_region_init.
-------------- next part --------------
>From 93115b53e151eaad0e476a23864fc3301cf0cf86 Mon Sep 17 00:00:00 2001
From: (null) <(null)>
Date: Fri, 9 Mar 2007 22:37:36 +0100
Subject: [PATCH] Avoid malloc in _cairo_pixman_region_create_simple.

---
 pixman/src/pixman.h          |   12 ++-
 pixman/src/pixregion.c       |   18 +--
 pixman/src/pixregionint.h    |    7 +-
 src/cairo-clip-private.h     |    3 +-
 src/cairo-clip.c             |  125 ++++++++++-----------
 src/cairo-region.c           |   34 +++---
 src/cairo-surface-fallback.c |  255 ++++++++++++++++++++++--------------------
 src/cairo-surface.c          |   56 ++++++----
 src/cairo-traps.c            |   18 ++--
 src/cairoint.h               |   11 +-
 10 files changed, 279 insertions(+), 260 deletions(-)

diff --git a/pixman/src/pixman.h b/pixman/src/pixman.h
index 7f0ef32..8428543 100644
--- a/pixman/src/pixman.h
+++ b/pixman/src/pixman.h
@@ -113,12 +113,17 @@ extern "C" {
 
 /* pixregion.h */
 
-typedef struct pixman_region16 pixman_region16_t;
+typedef struct pixman_region16_data pixman_region16_data_t;
 
 typedef struct pixman_box16 {
     short x1, y1, x2, y2;
 } pixman_box16_t;
 
+typedef struct pixman_region16 {
+    pixman_box16_t          extents;
+    pixman_region16_data_t  *data;
+} pixman_region16_t;
+
 typedef enum {
     PIXMAN_REGION_STATUS_FAILURE,
     PIXMAN_REGION_STATUS_SUCCESS
@@ -133,6 +138,11 @@ pixman_private pixman_region16_t *
 pixman_region_create_simple (pixman_box16_t *extents);
 
 pixman_private void
+pixman_region_init(pixman_region16_t *region, pixman_box16_t *extents);
+pixman_private void
+pixman_region_uninit (pixman_region16_t *region);
+
+pixman_private void
 pixman_region_destroy (pixman_region16_t *region);
 
 /* manipulation */
diff --git a/pixman/src/pixregion.c b/pixman/src/pixregion.c
index 0404dff..f710294 100644
--- a/pixman/src/pixregion.c
+++ b/pixman/src/pixregion.c
@@ -82,12 +82,6 @@ static pixman_region16_t   pixman_brokenregion = { { 0, 0, 0, 0 }, &pixman_broke
 static pixman_region_status_t
 pixman_break (pixman_region16_t *pReg);
 
-static void
-pixman_init (pixman_region16_t *region, pixman_box16_t *rect);
-
-static void
-pixman_uninit (pixman_region16_t *region);
-
 /*
  * The functions in this file implement the Region abstraction used extensively
  * throughout the X11 sample server. A Region is simply a set of disjoint
@@ -318,7 +312,7 @@ pixman_region_create_simple (pixman_box16_t *extents)
     if (region == NULL)
 	return &pixman_brokenregion;
 
-    pixman_init (region, extents);
+    pixman_region_init (region, extents);
 
     return region;
 }
@@ -328,8 +322,8 @@ pixman_region_create_simple (pixman_box16_t *extents)
  *     Outer region rect is statically allocated.
  *****************************************************************/
 
-static void
-pixman_init(pixman_region16_t *region, pixman_box16_t *extents)
+void
+pixman_region_init(pixman_region16_t *region, pixman_box16_t *extents)
 {
     if (extents)
     {
@@ -343,8 +337,8 @@ pixman_init(pixman_region16_t *region, pixman_box16_t *extents)
     }
 }
 
-static void
-pixman_uninit (pixman_region16_t *region)
+void
+pixman_region_uninit (pixman_region16_t *region)
 {
     good (region);
     freeData (region);
@@ -353,7 +347,7 @@ pixman_uninit (pixman_region16_t *region)
 void
 pixman_region_destroy (pixman_region16_t *region)
 {
-    pixman_uninit (region);
+    pixman_region_uninit (region);
 
     if (region != &pixman_brokenregion)
 	free (region);
diff --git a/pixman/src/pixregionint.h b/pixman/src/pixregionint.h
index b5b53fd..385a7f2 100644
--- a/pixman/src/pixregionint.h
+++ b/pixman/src/pixregionint.h
@@ -48,16 +48,11 @@ SOFTWARE.
 
 #include "pixman.h"
 
-typedef struct pixman_region16_data {
+struct pixman_region16_data {
     long		size;
     long		numRects;
     /* XXX: And why, exactly, do we have this bogus struct definition? */
 /*  pixman_box16_t	rects[size];   in memory but not explicitly declared */
-} pixman_region16_data_t;
-
-struct pixman_region16 {
-    pixman_box16_t	extents;
-    pixman_region16_data_t	*data;
 };
 
 typedef struct pixman_region16_point {
diff --git a/src/cairo-clip-private.h b/src/cairo-clip-private.h
index 3c4ff0d..381c003 100644
--- a/src/cairo-clip-private.h
+++ b/src/cairo-clip-private.h
@@ -72,7 +72,8 @@ struct _cairo_clip {
     /*
      * A clip region that can be placed in the surface
      */
-    pixman_region16_t *region;
+    pixman_region16_t region;
+    cairo_bool_t has_region;
     /*
      * If the surface supports path clipping, we store the list of
      * clipping paths that has been set here as a linked list.
diff --git a/src/cairo-clip.c b/src/cairo-clip.c
index 605589b..46179d9 100644
--- a/src/cairo-clip.c
+++ b/src/cairo-clip.c
@@ -58,7 +58,7 @@ _cairo_clip_init (cairo_clip_t *clip, cairo_surface_t *target)
 
     clip->serial = 0;
 
-    clip->region = NULL;
+    clip->has_region = FALSE;
 
     clip->path = NULL;
 }
@@ -71,9 +71,10 @@ _cairo_clip_fini (cairo_clip_t *clip)
 
     clip->serial = 0;
 
-    if (clip->region)
-	pixman_region_destroy (clip->region);
-    clip->region = NULL;
+    if (clip->has_region) {
+	pixman_region_uninit (&clip->region);
+    	clip->has_region = FALSE;
+    }
 
     _cairo_clip_path_destroy (clip->path);
     clip->path = NULL;
@@ -89,11 +90,11 @@ _cairo_clip_init_copy (cairo_clip_t *clip, cairo_clip_t *other)
 
     clip->serial = other->serial;
 
-    if (other->region == NULL) {
-	clip->region = other->region;
+    if (other->has_region) {
+        pixman_region_copy (&clip->region, &other->region);
+        clip->has_region = TRUE;
     } else {
-	clip->region = pixman_region_create ();
-	pixman_region_copy (clip->region, other->region);
+        clip->has_region = FALSE;
     }
 
     clip->path = _cairo_clip_path_reference (other->path);
@@ -108,9 +109,10 @@ _cairo_clip_reset (cairo_clip_t *clip)
 
     clip->serial = 0;
 
-    if (clip->region)
-	pixman_region_destroy (clip->region);
-    clip->region = NULL;
+    if (clip->has_region) {
+	pixman_region_uninit (&clip->region);
+        clip->has_region = FALSE;
+    }
 
     _cairo_clip_path_destroy (clip->path);
     clip->path = NULL;
@@ -167,27 +169,25 @@ _cairo_clip_intersect_to_rectangle (cairo_clip_t            *clip,
             return status;
     }
 
-    if (clip->region) {
-	pixman_region16_t *intersection;
+    if (clip->has_region) {
 	cairo_status_t status = CAIRO_STATUS_SUCCESS;
-	pixman_region_status_t pixman_status;
+	pixman_region16_t intersection;
 
-	intersection = _cairo_region_create_from_rectangle (rectangle);
-	if (intersection == NULL)
+	if (_cairo_region_init_from_rectangle (&intersection, rectangle))
 	    return CAIRO_STATUS_NO_MEMORY;
 
-	pixman_status = pixman_region_intersect (intersection,
-					  clip->region,
-					  intersection);
-	if (pixman_status == PIXMAN_REGION_STATUS_SUCCESS)
-	    _cairo_region_extents_rectangle (intersection, rectangle);
-	else
+	if (PIXMAN_REGION_STATUS_SUCCESS !=
+            pixman_region_intersect (&intersection, &clip->region,
+                                     &intersection)) {
 	    status = CAIRO_STATUS_NO_MEMORY;
+	} else {
+            _cairo_region_extents_rectangle (&intersection, rectangle);
+        }
 
-	pixman_region_destroy (intersection);
+        pixman_region_uninit (&intersection);
 
-	if (status)
-	    return status;
+        if (status)
+            return status;
     }
 
     if (clip->surface)
@@ -207,28 +207,24 @@ _cairo_clip_intersect_to_region (cairo_clip_t      *clip,
 	/* Intersect clip path into region. */
     }
 
-    if (clip->region)
-	pixman_region_intersect (region, clip->region, region);
+    if (clip->has_region)
+	pixman_region_intersect (region, &clip->region, region);
 
     if (clip->surface) {
-	pixman_region16_t *clip_rect;
-	pixman_region_status_t pixman_status;
 	cairo_status_t status = CAIRO_STATUS_SUCCESS;
+	pixman_region16_t clip_rect;
 
-	clip_rect = _cairo_region_create_from_rectangle (&clip->surface_rect);
-	if (clip_rect == NULL)
+	if (_cairo_region_init_from_rectangle (&clip_rect, &clip->surface_rect))
 	    return CAIRO_STATUS_NO_MEMORY;
 
-	pixman_status = pixman_region_intersect (region,
-						 clip_rect,
-						 region);
-	if (pixman_status != PIXMAN_REGION_STATUS_SUCCESS)
+        if (PIXMAN_REGION_STATUS_SUCCESS != 
+            pixman_region_intersect (region, &clip_rect, region))
 	    status = CAIRO_STATUS_NO_MEMORY;
 
-	pixman_region_destroy (clip_rect);
+        pixman_region_uninit (&clip_rect);
 
-	if (status)
-	    return status;
+        if (status)
+            return status;
     }
 
     return CAIRO_STATUS_SUCCESS;
@@ -326,42 +322,43 @@ _cairo_clip_path_destroy (cairo_clip_path_t *clip_path)
     free (clip_path);
 }
 
-static cairo_status_t
+static cairo_int_status_t
 _cairo_clip_intersect_region (cairo_clip_t    *clip,
 			      cairo_traps_t   *traps,
 			      cairo_surface_t *target)
 {
-    pixman_region16_t *region;
-    cairo_status_t status;
+    pixman_region16_t region;
+    cairo_int_status_t status;
 
     if (clip->mode != CAIRO_CLIP_MODE_REGION)
 	return CAIRO_INT_STATUS_UNSUPPORTED;
 
     status = _cairo_traps_extract_region (traps, &region);
+
     if (status)
 	return status;
 
-    if (region == NULL)
-	return CAIRO_INT_STATUS_UNSUPPORTED;
-
     status = CAIRO_STATUS_SUCCESS;
-    if (clip->region == NULL) {
-	clip->region = region;
+
+    if (!clip->has_region) {
+        pixman_region_copy (&clip->region, &region);
+        clip->has_region = TRUE;
     } else {
-	pixman_region16_t *intersection = pixman_region_create();
+	pixman_region16_t intersection;
+        pixman_region_init (&intersection, NULL);
+
+	if (PIXMAN_REGION_STATUS_SUCCESS == 
+            pixman_region_intersect (&intersection, &clip->region, &region)) {
+            pixman_region_copy (&clip->region, &intersection);
+        } else {
+            status = CAIRO_STATUS_NO_MEMORY;
+        }
 
-	if (pixman_region_intersect (intersection,
-				     clip->region, region)
-	    == PIXMAN_REGION_STATUS_SUCCESS) {
-	    pixman_region_destroy (clip->region);
-	    clip->region = intersection;
-	} else {
-	    status = CAIRO_STATUS_NO_MEMORY;
-	}
-	pixman_region_destroy (region);
+        pixman_region_uninit (&intersection);
     }
 
     clip->serial = _cairo_surface_allocate_clip_serial (target);
+    pixman_region_uninit (&region);
 
     return status;
 }
@@ -506,8 +503,8 @@ _cairo_clip_translate (cairo_clip_t  *clip,
                        cairo_fixed_t  tx,
                        cairo_fixed_t  ty)
 {
-    if (clip->region) {
-        pixman_region_translate (clip->region,
+    if (clip->has_region) {
+        pixman_region_translate (&clip->region,
                                  _cairo_fixed_integer_part (tx),
                                  _cairo_fixed_integer_part (ty));
     }
@@ -557,9 +554,9 @@ _cairo_clip_init_deep_copy (cairo_clip_t    *clip,
         /* We should reapply the original clip path in this case, and let
          * whatever the right handling is happen */
     } else {
-        if (other->region) {
-            clip->region = pixman_region_create ();
-            pixman_region_copy (clip->region, other->region);
+        if (other->has_region) {
+            pixman_region_copy (&clip->region, &other->region);
+            clip->has_region = TRUE;
         }
 
         if (other->surface) {
@@ -610,16 +607,16 @@ _cairo_clip_copy_rectangle_list (cairo_clip_t *clip, cairo_gstate_t *gstate)
     if (clip->path || clip->surface)
         return (cairo_rectangle_list_t*) &_cairo_rectangles_not_representable;
 
-    n_boxes = clip->region ? pixman_region_num_rects (clip->region) : 1;
+    n_boxes = clip->has_region ? pixman_region_num_rects (&clip->region) : 1;
     rectangles = malloc (sizeof (cairo_rectangle_t)*n_boxes);
     if (rectangles == NULL)
         return (cairo_rectangle_list_t*) &_cairo_rectangles_nil;
 
-    if (clip->region) {
+    if (clip->has_region) {
         pixman_box16_t *boxes;
         int i;
         
-        boxes = pixman_region_rects (clip->region);
+        boxes = pixman_region_rects (&clip->region);
         for (i = 0; i < n_boxes; ++i) {
             if (!_cairo_clip_rect_to_user(gstate, boxes[i].x1, boxes[i].y1,
                                           boxes[i].x2 - boxes[i].x1,
diff --git a/src/cairo-region.c b/src/cairo-region.c
index 057f9fe..883e1fc 100644
--- a/src/cairo-region.c
+++ b/src/cairo-region.c
@@ -36,30 +36,28 @@
 #include <cairoint.h>
 
 /**
- * _cairo_region_create_from_rectangle:
+ * _cairo_region_init_from_rectangle:
+ * @region: a #pixman_region16_t
  * @rect: a #cairo_rectangle_int16_t
  *
- * Creates a region with extents initialized from the given
- * rectangle.
+ * Initializes a region with extents from the given rectangle.
  *
- * Return value: a newly created #pixman_region16_t or %NULL if
- *    memory couldn't a allocated.
+ * Return value: #CAIRO_STATUS_SUCCESS on success, or
+ * #CAIRO_STATUS_NO_MEMORY when pixman fails to initialize
+ * the region.
  **/
-pixman_region16_t *
-_cairo_region_create_from_rectangle (cairo_rectangle_int16_t *rect)
+cairo_status_t
+_cairo_region_init_from_rectangle (pixman_region16_t       *region,
+                                   cairo_rectangle_int16_t *rect)
 {
-    /* We can't use pixman_region_create_simple(), because it doesn't
-     * have an error return
-     */
-    pixman_region16_t *region = pixman_region_create ();
-    if (pixman_region_union_rect (region, region,
-				  rect->x, rect->y,
-				  rect->width, rect->height) != PIXMAN_REGION_STATUS_SUCCESS) {
-	pixman_region_destroy (region);
-	return NULL;
-    }
+    pixman_region_init (region, NULL);
+
+    if (PIXMAN_REGION_STATUS_SUCCESS == pixman_region_union_rect (
+        region, region, rect->x, rect->y, rect->width, rect->height))
+        return CAIRO_STATUS_SUCCESS;
 
-    return region;
+    pixman_region_uninit (region);
+    return CAIRO_STATUS_NO_MEMORY;
 }
 
 /**
diff --git a/src/cairo-surface-fallback.c b/src/cairo-surface-fallback.c
index 1a7d666..24c9115 100644
--- a/src/cairo-surface-fallback.c
+++ b/src/cairo-surface-fallback.c
@@ -511,145 +511,158 @@ _clip_and_composite_trapezoids (cairo_pattern_t *src,
 				cairo_antialias_t antialias)
 {
     cairo_status_t status;
-    pixman_region16_t *trap_region = NULL;
-    pixman_region16_t *clear_region = NULL;
+    pixman_region16_t trap_region;
+    pixman_region16_t clear_region;
+    cairo_bool_t has_trap_region = FALSE;
+    cairo_bool_t has_clear_region = FALSE;
     cairo_rectangle_int16_t extents;
     cairo_composite_traps_info_t traps_info;
 
     if (traps->num_traps == 0)
-	return CAIRO_STATUS_SUCCESS;
+        return CAIRO_STATUS_SUCCESS;
 
     status = _cairo_surface_get_extents (dst, &extents);
-    if (status)
-	return status;
 
-    status = _cairo_traps_extract_region (traps, &trap_region);
     if (status)
-	return status;
+        return status;
 
-    if (_cairo_operator_bounded_by_mask (op))
-    {
-	cairo_rectangle_int16_t trap_extents;
-	if (trap_region) {
-	    status = _cairo_clip_intersect_to_region (clip, trap_region);
-	    if (status)
-		goto out;
-
-	    _cairo_region_extents_rectangle (trap_region, &trap_extents);
-	} else {
-	    cairo_box_t trap_box;
-	    _cairo_traps_extents (traps, &trap_box);
-	    _cairo_box_round_to_rectangle (&trap_box, &trap_extents);
-	}
+    status = _cairo_traps_extract_region (traps, &trap_region);
 
-	_cairo_rectangle_intersect (&extents, &trap_extents);
-	status = _cairo_clip_intersect_to_rectangle (clip, &extents);
-	if (status)
-	    goto out;
-    }
-    else
-    {
-	cairo_surface_t *clip_surface = clip ? clip->surface : NULL;
-
-	if (trap_region && !clip_surface) {
-	    /* If we optimize drawing with an unbounded operator to
-	     * _cairo_surface_fill_rectangles() or to drawing with a
-	     * clip region, then we have an additional region to clear.
-	     */
-	    clear_region = _cairo_region_create_from_rectangle (&extents);
-	    if (clear_region == NULL)
-		return CAIRO_STATUS_NO_MEMORY;
-
-	    status = _cairo_clip_intersect_to_region (clip, clear_region);
-	    if (status)
-		return status;
-
-	    _cairo_region_extents_rectangle (clear_region,  &extents);
-
-	    if (pixman_region_subtract (clear_region, clear_region, trap_region) != PIXMAN_REGION_STATUS_SUCCESS)
-		return CAIRO_STATUS_NO_MEMORY;
-
-	    if (!pixman_region_not_empty (clear_region)) {
-		pixman_region_destroy (clear_region);
-		clear_region = NULL;
-	    }
-	} else {
-	    status = _cairo_clip_intersect_to_rectangle (clip, &extents);
-	    if (status)
-		return status;
-	}
+    if (CAIRO_INT_STATUS_UNSUPPORTED == status) {
+        has_trap_region = FALSE;
+    } else if (status) {
+        return status;
+    } else {
+        has_trap_region = TRUE;
     }
 
-    if (status)
-	goto out;
-
-    if (trap_region)
-    {
-	cairo_surface_t *clip_surface = clip ? clip->surface : NULL;
-
-	if ((src->type == CAIRO_PATTERN_TYPE_SOLID || op == CAIRO_OPERATOR_CLEAR) &&
-	    !clip_surface)
-	{
-	    const cairo_color_t *color;
-
-	    if (op == CAIRO_OPERATOR_CLEAR)
-		color = CAIRO_COLOR_TRANSPARENT;
-	    else
-		color = &((cairo_solid_pattern_t *)src)->color;
-
-	    /* Solid rectangles special case */
-	    status = _cairo_surface_fill_region (dst, op, color, trap_region);
-	    if (!status && clear_region)
-		status = _cairo_surface_fill_region (dst, CAIRO_OPERATOR_CLEAR,
-						     CAIRO_COLOR_TRANSPARENT,
-						     clear_region);
-
-	    goto out;
-	}
-
-	if ((_cairo_operator_bounded_by_mask (op) && op != CAIRO_OPERATOR_SOURCE) ||
-	    !clip_surface)
-	{
-	    /* For a simple rectangle, we can just use composite(), for more
-	     * rectangles, we have to set a clip region. The cost of rasterizing
-	     * trapezoids is pretty high for most backends currently, so it's
-	     * worthwhile even if a region is needed.
-	     *
-	     * If we have a clip surface, we set it as the mask; this only works
-	     * for bounded operators other than SOURCE; for unbounded operators,
-	     * clip and mask cannot be interchanged. For SOURCE, the operator
-	     * as implemented by the backends is different in it's handling
-	     * of the mask then what we want.
-	     *
-	     * CAIRO_INT_STATUS_UNSUPPORTED will be returned if the region has
-	     * more than rectangle and the destination doesn't support clip
-	     * regions. In that case, we fall through.
-	     */
-	    status = _composite_trap_region (clip, src, op, dst,
-					     trap_region, &extents);
-	    if (status != CAIRO_INT_STATUS_UNSUPPORTED)
-	    {
-		if (!status && clear_region)
-		    status = _cairo_surface_fill_region (dst, CAIRO_OPERATOR_CLEAR,
-							 CAIRO_COLOR_TRANSPARENT,
-							 clear_region);
-		goto out;
-	    }
-	}
+    if (_cairo_operator_bounded_by_mask (op)) {
+        cairo_rectangle_int16_t trap_extents;
+
+        if (has_trap_region) {
+            status = _cairo_clip_intersect_to_region (clip, &trap_region);
+
+            if (status)
+                goto out;
+
+            _cairo_region_extents_rectangle (&trap_region, &trap_extents);
+        } else {
+            cairo_box_t trap_box;
+            _cairo_traps_extents (traps, &trap_box);
+            _cairo_box_round_to_rectangle (&trap_box, &trap_extents);
+        }
+
+        _cairo_rectangle_intersect (&extents, &trap_extents);
+        status = _cairo_clip_intersect_to_rectangle (clip, &extents);
+
+        if (status)
+            goto out;
+    } else {
+        cairo_surface_t *clip_surface = clip ? clip->surface : NULL;
+
+        if (has_trap_region && !clip_surface) {
+            /* If we optimize drawing with an unbounded operator to
+             * _cairo_surface_fill_rectangles() or to drawing with a
+             * clip region, then we have an additional region to clear.
+             */
+            if (_cairo_region_init_from_rectangle (&clear_region, &extents)) {
+                status = CAIRO_STATUS_NO_MEMORY;
+                goto out;
+            }
+
+            has_clear_region = TRUE;
+            status = _cairo_clip_intersect_to_region (clip, &clear_region);
+
+            if (status)
+                goto out;
+
+            _cairo_region_extents_rectangle (&clear_region,  &extents);
+
+            if (PIXMAN_REGION_STATUS_SUCCESS != 
+                pixman_region_subtract (&clear_region, &clear_region, &trap_region)) {
+                status = CAIRO_STATUS_NO_MEMORY;
+                goto out;
+            }
+
+            if (!pixman_region_not_empty (&clear_region)) {
+                pixman_region_uninit (&clear_region);
+                has_clear_region = FALSE;
+            }
+        } else {
+            status = _cairo_clip_intersect_to_rectangle (clip, &extents);
+        }
+
+        if (status)
+            goto out;
+
+        if (has_trap_region) {
+            cairo_surface_t *clip_surface = clip ? clip->surface : NULL;
+
+            if ((src->type == CAIRO_PATTERN_TYPE_SOLID ||
+                 op == CAIRO_OPERATOR_CLEAR) && !clip_surface) {
+                const cairo_color_t *color;
+
+                if (op == CAIRO_OPERATOR_CLEAR) {
+                    color = CAIRO_COLOR_TRANSPARENT;
+                } else {
+                    color = &((cairo_solid_pattern_t *)src)->color;
+                }
+
+                /* Solid rectangles special case */
+                status = _cairo_surface_fill_region (dst, op, color,
+                        has_trap_region ? &trap_region : NULL);
+
+                if (!status && has_clear_region)
+                    status = _cairo_surface_fill_region (dst, CAIRO_OPERATOR_CLEAR,
+                                                         CAIRO_COLOR_TRANSPARENT,
+                                                         &clear_region);
+
+                goto out;
+            }
+
+            if ((_cairo_operator_bounded_by_mask (op) && 
+                 op != CAIRO_OPERATOR_SOURCE) || !clip_surface) {
+                /* For a simple rectangle, we can just use composite(), for more
+                 * rectangles, we have to set a clip region. The cost of rasterizing
+                 * trapezoids is pretty high for most backends currently, so it's
+                 * worthwhile even if a region is needed.
+                 *
+                 * If we have a clip surface, we set it as the mask; this only works
+                 * for bounded operators other than SOURCE; for unbounded operators,
+                 * clip and mask cannot be interchanged. For SOURCE, the operator
+                 * as implemented by the backends is different in it's handling
+                 * of the mask then what we want.
+                 *
+                 * CAIRO_INT_STATUS_UNSUPPORTED will be returned if the region has
+                 * more than rectangle and the destination doesn't support clip
+                 * regions. In that case, we fall through.
+                 */
+                status = _composite_trap_region (clip, src, op, dst,
+                        has_trap_region ? &trap_region : NULL, 
+                        &extents);
+
+                if (status != CAIRO_INT_STATUS_UNSUPPORTED) {
+                    if (!status && has_clear_region)
+                        status = _cairo_surface_fill_region (dst, CAIRO_OPERATOR_CLEAR,
+                                                             CAIRO_COLOR_TRANSPARENT,
+                                                             &clear_region);
+                    goto out;
+                }
+            }
+        }
     }
 
     traps_info.traps = traps;
     traps_info.antialias = antialias;
 
-    status = _clip_and_composite (clip, op, src,
-				  _composite_traps_draw_func, &traps_info,
-				  dst, &extents);
+    status = _clip_and_composite (clip, op, src, _composite_traps_draw_func,
+                                  &traps_info, dst, &extents);
 
- out:
-    if (trap_region)
-	pixman_region_destroy (trap_region);
-    if (clear_region)
-	pixman_region_destroy (clear_region);
+out:
+    if (has_trap_region)
+        pixman_region_uninit (&trap_region);
+    if (has_clear_region)
+        pixman_region_uninit (&clear_region);
 
     return status;
 }
diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index 3162a01..67df039 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -1694,9 +1694,9 @@ _cairo_surface_set_clip (cairo_surface_t *surface, cairo_clip_t *clip)
 						 clip->path,
 						 clip->serial);
 
-	if (clip->region)
+	if (clip->has_region)
 	    return _cairo_surface_set_clip_region (surface,
-						   clip->region,
+						   &clip->region,
 						   clip->serial);
     }
 
@@ -1859,9 +1859,11 @@ _cairo_surface_composite_fixup_unbounded_internal (cairo_surface_t         *dst,
 {
     cairo_rectangle_int16_t dst_rectangle;
     cairo_rectangle_int16_t drawn_rectangle;
-    pixman_region16_t *drawn_region;
-    pixman_region16_t *clear_region;
-    cairo_status_t status = CAIRO_STATUS_SUCCESS;
+    cairo_bool_t has_drawn_region = FALSE;
+    cairo_bool_t has_clear_region = FALSE;
+    pixman_region16_t drawn_region;
+    pixman_region16_t clear_region;
+    cairo_status_t status;
 
     /* The area that was drawn is the area in the destination rectangle but not within
      * the source or the mask.
@@ -1874,34 +1876,42 @@ _cairo_surface_composite_fixup_unbounded_internal (cairo_surface_t         *dst,
     drawn_rectangle = dst_rectangle;
 
     if (src_rectangle)
-	_cairo_rectangle_intersect (&drawn_rectangle, src_rectangle);
+        _cairo_rectangle_intersect (&drawn_rectangle, src_rectangle);
 
     if (mask_rectangle)
-	_cairo_rectangle_intersect (&drawn_rectangle, mask_rectangle);
+        _cairo_rectangle_intersect (&drawn_rectangle, mask_rectangle);
 
     /* Now compute the area that is in dst_rectangle but not in drawn_rectangle
      */
-    drawn_region = _cairo_region_create_from_rectangle (&drawn_rectangle);
-    clear_region = _cairo_region_create_from_rectangle (&dst_rectangle);
-    if (!drawn_region || !clear_region) {
-	status = CAIRO_STATUS_NO_MEMORY;
-	goto CLEANUP_REGIONS;
+    if (_cairo_region_init_from_rectangle (&drawn_region, &drawn_rectangle)) {
+        status = CAIRO_STATUS_NO_MEMORY;
+        goto CLEANUP_REGIONS;
     }
 
-    if (pixman_region_subtract (clear_region, clear_region, drawn_region) != PIXMAN_REGION_STATUS_SUCCESS) {
-	status = CAIRO_STATUS_NO_MEMORY;
-	goto CLEANUP_REGIONS;
+    has_drawn_region = TRUE;
+
+    if (_cairo_region_init_from_rectangle (&clear_region, &dst_rectangle)) {
+        status = CAIRO_STATUS_NO_MEMORY;
+        goto CLEANUP_REGIONS;
+    }
+
+    has_clear_region = TRUE;
+
+    if (PIXMAN_REGION_STATUS_SUCCESS != 
+        pixman_region_subtract (&clear_region, &clear_region, &drawn_region)) {
+        status = CAIRO_STATUS_NO_MEMORY;
+        goto CLEANUP_REGIONS;
     }
 
     status = _cairo_surface_fill_region (dst, CAIRO_OPERATOR_SOURCE,
-					 CAIRO_COLOR_TRANSPARENT,
-					 clear_region);
-
- CLEANUP_REGIONS:
-    if (drawn_region)
-	pixman_region_destroy (drawn_region);
-    if (clear_region)
-	pixman_region_destroy (clear_region);
+                                         CAIRO_COLOR_TRANSPARENT,
+                                         &clear_region);
+
+CLEANUP_REGIONS:
+    if (has_drawn_region)
+        pixman_region_uninit (&drawn_region);
+    if (has_clear_region)
+        pixman_region_uninit (&clear_region);
 
     return status;
 }
diff --git a/src/cairo-traps.c b/src/cairo-traps.c
index 9b3931f..6acebf8 100644
--- a/src/cairo-traps.c
+++ b/src/cairo-traps.c
@@ -935,11 +935,12 @@ _cairo_traps_extents (cairo_traps_t *traps, cairo_box_t *extents)
  * Determines if a set of trapezoids are exactly representable as a
  * pixman region, and if so creates such a region.
  *
- * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY
+ * Return value: %CAIRO_STATUS_SUCCESS, %CAIRO_INT_STATUS_UNSUPPORTED 
+ * or %CAIRO_STATUS_NO_MEMORY
  **/
-cairo_status_t
-_cairo_traps_extract_region (cairo_traps_t      *traps,
-			     pixman_region16_t **region)
+cairo_int_status_t
+_cairo_traps_extract_region (cairo_traps_t     *traps,
+			     pixman_region16_t *region)
 {
     int i;
 
@@ -950,11 +951,10 @@ _cairo_traps_extract_region (cairo_traps_t      *traps,
 	      && _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))) {
-	    *region = NULL;
-	    return CAIRO_STATUS_SUCCESS;
+	    return CAIRO_INT_STATUS_UNSUPPORTED;
 	}
 
-    *region = pixman_region_create ();
+    pixman_region_init (region, NULL);
 
     for (i = 0; i < traps->num_traps; i++) {
 	int x = _cairo_fixed_integer_part(traps->traps[i].left.p1.x);
@@ -969,9 +969,9 @@ _cairo_traps_extract_region (cairo_traps_t      *traps,
 	if (width == 0 || height == 0)
 	  continue;
 
-	if (pixman_region_union_rect (*region, *region,
+	if (pixman_region_union_rect (region, region,
 				      x, y, width, height) != PIXMAN_REGION_STATUS_SUCCESS) {
-	    pixman_region_destroy (*region);
+	    pixman_region_uninit (region);
 	    return CAIRO_STATUS_NO_MEMORY;
 	}
     }
diff --git a/src/cairoint.h b/src/cairoint.h
index 3e54857..3494a92 100755
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -2374,9 +2374,9 @@ _cairo_traps_contain (cairo_traps_t *traps, double x, double y);
 cairo_private void
 _cairo_traps_extents (cairo_traps_t *traps, cairo_box_t *extents);
 
-cairo_private cairo_status_t
-_cairo_traps_extract_region (cairo_traps_t      *tr,
-			     pixman_region16_t **region);
+cairo_private cairo_int_status_t
+_cairo_traps_extract_region (cairo_traps_t     *tr,
+			     pixman_region16_t *region);
 
 cairo_private void
 _cairo_trapezoid_array_translate_and_scale (cairo_trapezoid_t *offset_traps,
@@ -2480,8 +2480,9 @@ _cairo_gstate_get_antialias (cairo_gstate_t *gstate);
 
 /* cairo-region.c */
 
-cairo_private pixman_region16_t *
-_cairo_region_create_from_rectangle (cairo_rectangle_int16_t *rect);
+cairo_private cairo_status_t
+_cairo_region_init_from_rectangle (pixman_region16_t       *region,
+				   cairo_rectangle_int16_t *rect);
 
 cairo_private void
 _cairo_region_extents_rectangle (pixman_region16_t       *region,
-- 
1.4.4.2



More information about the cairo mailing list