[cairo-commit] cairo/src cairo-gstate.c, 1.109, 1.110 cairo-traps.c, 1.23, 1.24 cairoint.h, 1.125, 1.126

Owen Taylor commit at pdx.freedesktop.org
Wed Apr 13 11:23:45 PDT 2005


Committed by: otaylor

Update of /cvs/cairo/cairo/src
In directory gabe:/tmp/cvs-serv1992/src

Modified Files:
	cairo-gstate.c cairo-traps.c cairoint.h 
Log Message:
2005-04-13  Owen Taylor  <otaylor at redhat.com>

        * src/cairoint.h src/cairo-traps.c: Add _cairo_traps_extract_region
        for converting trapezoids into a pixman region.

        * src/cairo-gstate.c (cairo_clip): Represent all rectangular
        pixel-aligned regions as regions, not just single rectangles.

        * src/cairo-gstate.c (_cairo_gstate_clip_and_composite_trapezoid):
        Split into manageable pieces, optimize rectangular pixel-
        aligned regions by using _cairo_surface_fill_rectangles()
        or _cairo_surface_set_clip_region() as appropriate.

        * tests/trap-clip.c tests/trap-clip-ref.png tests/Makefile.am:
        Add a test for trapezoids clipping.

        * doc/public/cairo-docs.xml: Add an index.


Index: cairo-gstate.c
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo-gstate.c,v
retrieving revision 1.109
retrieving revision 1.110
diff -u -d -r1.109 -r1.110
--- cairo-gstate.c	12 Apr 2005 14:12:08 -0000	1.109
+++ cairo-gstate.c	13 Apr 2005 18:23:43 -0000	1.110
@@ -1438,6 +1438,165 @@
     return rect->width == 0 || rect->height == 0;
 }
 
+/* Creates a region from a cairo_rectangle_t */
+static cairo_status_t
+_region_new_from_rect (cairo_rectangle_t  *rect,
+		       pixman_region16_t **region)
+{
+    *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 CAIRO_STATUS_NO_MEMORY;
+    }
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+/* Gets the bounding box of a region as a cairo_rectangle_t */
+static void
+_region_rect_extents (pixman_region16_t *region,
+		      cairo_rectangle_t *rect)
+{
+    pixman_box16_t *region_extents = pixman_region_extents (region);
+
+    rect->x = region_extents->x1;
+    rect->y = region_extents->y1;
+    rect->width = region_extents->x2 - region_extents->x1;
+    rect->height = region_extents->y2 - region_extents->y1;
+}
+
+/* Given a region representing a set of trapezoids that will be
+ * drawn, clip the region according to the gstate and compute
+ * the overall extents.
+ */
+static cairo_status_t
+_clip_and_compute_extents_region (cairo_gstate_t    *gstate,
+				  pixman_region16_t *trap_region,
+				  cairo_rectangle_t *extents)
+{
+    if (gstate->clip.region)
+	pixman_region_intersect (trap_region,
+				 gstate->clip.region,
+				 trap_region);
+
+    if (gstate->clip.surface) {
+	pixman_region16_t *clip_rect;
+	cairo_status_t status;
+    
+	status = _region_new_from_rect (&gstate->clip.rect,
+					&clip_rect);
+	if (!CAIRO_OK (status))
+	    return status;
+	
+	if (pixman_region_intersect (trap_region,
+				     clip_rect,
+				     trap_region) != PIXMAN_REGION_STATUS_SUCCESS)
+	    status = CAIRO_STATUS_NO_MEMORY;
+
+	pixman_region_destroy (clip_rect);
+
+	if (!CAIRO_OK (status))
+	    return status;
+    }
+
+    _region_rect_extents (trap_region, extents);
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+/* Given a a set of trapezoids to draw, find a bounding box (non-exact)
+ * of the trapezoids clipped by the gstate
+ */
+static cairo_status_t
+_clip_and_compute_extents_arbitrary (cairo_gstate_t    *gstate,
+				     cairo_traps_t     *traps,
+				     cairo_rectangle_t *extents)
+{
+    cairo_box_t trap_extents;
+	
+    _cairo_traps_extents (traps, &trap_extents);
+    _cairo_box_round_to_rectangle (&trap_extents, extents);
+    
+    if (gstate->clip.region) {
+	pixman_region16_t *intersection;
+	cairo_status_t status;
+	
+	status = _region_new_from_rect (extents, &intersection);
+	if (!CAIRO_OK (status))
+	    return status;
+	
+	if (pixman_region_intersect (intersection,
+				     gstate->clip.region,
+				     intersection) == PIXMAN_REGION_STATUS_SUCCESS) 
+	    _region_rect_extents (intersection, extents);
+	else
+	    status = CAIRO_STATUS_NO_MEMORY;
+
+	pixman_region_destroy (intersection);
+
+	if (!CAIRO_OK (status))
+	    return status;
+    }
+
+    if (gstate->clip.surface)
+	_cairo_rectangle_intersect (extents, &gstate->clip.rect);
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+/* Composites a region representing a set of trapezoids.
+ */
+static cairo_status_t
+_composite_trap_region (cairo_gstate_t    *gstate,
+			cairo_pattern_t   *src,
+			cairo_operator_t   operator,
+			cairo_surface_t   *dst,
+			pixman_region16_t *trap_region,
+			cairo_rectangle_t *extents)
+{
+    cairo_status_t status, tmp_status;
+    cairo_pattern_union_t pattern;
+    cairo_pattern_union_t mask;
+    int num_rects = pixman_region_num_rects (trap_region);
+
+    if (num_rects == 0)
+	return CAIRO_STATUS_SUCCESS;
+    
+    if (num_rects > 1) {
+	status = _cairo_surface_set_clip_region (dst, trap_region);
+	if (!CAIRO_OK (status))
+	    return status;
+    }
+    
+    _cairo_gstate_pattern_init_copy (gstate, &pattern, src);
+    if (gstate->clip.surface)
+	_cairo_pattern_init_for_surface (&mask.surface, gstate->clip.surface);
+	
+    status = _cairo_surface_composite (gstate->operator,
+				       &pattern.base,
+				       gstate->clip.surface ? &mask.base : NULL,
+				       dst,
+				       extents->x, extents->y,
+				       extents->x - (gstate->clip.surface ? gstate->clip.rect.x : 0),
+				       extents->y - (gstate->clip.surface ? gstate->clip.rect.y : 0),
+				       extents->x, extents->y,
+				       extents->width, extents->height);
+
+    if (gstate->clip.surface)
+	_cairo_pattern_fini (&pattern.base);
+    _cairo_pattern_fini (&mask.base);
+
+    if (num_rects > 1) {
+	tmp_status = _cairo_surface_set_clip_region (dst, gstate->clip.region);
+	if (!CAIRO_OK (tmp_status))
+	    status = tmp_status;
+    }
+				      
+    return status;
+}
+
 static void
 translate_traps (cairo_traps_t *traps, int x, int y)
 {
@@ -1467,164 +1626,239 @@
     }
 }
 
-
-/* Warning: This call modifies the coordinates of traps */
+/* Composites a set of trapezoids in the case where we need to create
+ * an intermediate surface to handle gstate->clip.surface
+ * 
+ * Warning: This call modifies the coordinates of traps
+ */
 static cairo_status_t
-_cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate,
-					     cairo_pattern_t *src,
-					     cairo_operator_t operator,
-					     cairo_surface_t *dst,
-					     cairo_traps_t *traps)
+_composite_traps_intermediate_surface (cairo_gstate_t    *gstate,
+				       cairo_pattern_t   *src,
+				       cairo_operator_t   operator,
+				       cairo_surface_t   *dst,
+				       cairo_traps_t     *traps,
+				       cairo_rectangle_t *extents)
 {
-    cairo_status_t status;
+    cairo_surface_t *intermediate;
     cairo_pattern_union_t pattern;
-    cairo_rectangle_t extents;
-    cairo_box_t trap_extents;
+    cairo_surface_pattern_t intermediate_pattern;
+    cairo_color_t empty_color;
+    cairo_status_t status;
 
-    if (traps->num_traps == 0)
-	return CAIRO_STATUS_SUCCESS;
+    translate_traps (traps, -extents->x, -extents->y);
 
-    if (gstate->surface == NULL)
-	return CAIRO_STATUS_NO_TARGET_SURFACE;
+    _cairo_color_init (&empty_color);
+    _cairo_color_set_alpha (&empty_color, 0.);
+    intermediate = _cairo_surface_create_similar_solid (gstate->clip.surface,
+							CAIRO_FORMAT_A8,
+							extents->width,
+							extents->height,
+							&empty_color);    
+    if (intermediate == NULL)
+	return CAIRO_STATUS_NO_MEMORY;
+    
+    _cairo_pattern_init_solid (&pattern.solid, 1.0, 1.0, 1.0);
+    
+    status = _cairo_surface_composite_trapezoids (CAIRO_OPERATOR_ADD,
+						  &pattern.base,
+						  intermediate,
+						  extents->x, extents->y,
+						  0, 0,
+						  extents->width,
+						  extents->height,
+						  traps->traps,
+						  traps->num_traps);
+    _cairo_pattern_fini (&pattern.base);
+    
+    if (!CAIRO_OK (status))
+	goto out;
 
-    _cairo_traps_extents (traps, &trap_extents);
-    _cairo_box_round_to_rectangle (&trap_extents, &extents);
+    _cairo_pattern_init_for_surface (&pattern.surface,
+				     gstate->clip.surface);
     
-    if (gstate->clip.surface) {
-	cairo_surface_t *intermediate;
-	cairo_surface_pattern_t intermediate_pattern;
-	cairo_color_t empty_color;
+    status = _cairo_surface_composite (CAIRO_OPERATOR_IN,
+				       &pattern.base,
+				       NULL,
+				       intermediate,
+				       extents->x - gstate->clip.rect.x,
+				       extents->y - gstate->clip.rect.y, 
+				       0, 0,
+				       0, 0,
+				       extents->width, extents->height);
+    _cairo_pattern_fini (&pattern.base);
+    
+    if (!CAIRO_OK (status))
+	goto out;
+    
+    _cairo_pattern_init_for_surface (&intermediate_pattern, intermediate);
+    _cairo_gstate_pattern_init_copy (gstate, &pattern, src);
+    
+    status = _cairo_surface_composite (operator,
+				       &pattern.base,
+				       &intermediate_pattern.base,
+				       dst,
+				       extents->x, extents->y,
+				       0, 0,
+				       extents->x, extents->y,
+				       extents->width, extents->height);
+    
+    _cairo_pattern_fini (&pattern.base);
+    _cairo_pattern_fini (&intermediate_pattern.base);
+    
+ out:
+    cairo_surface_destroy (intermediate);
+    
+    return status;
+}
 
-	_cairo_rectangle_intersect (&extents, &gstate->clip.rect);
+/* Composites a region representing a set of trapezoids in the
+ * case of a solid source (so we can use
+ * _cairo_surface_fill_rectangles).
+ */
+static cairo_status_t
+_composite_trap_region_solid (cairo_gstate_t        *gstate,
+			      cairo_solid_pattern_t *src,
+			      cairo_operator_t       operator,
+			      cairo_surface_t       *dst,
+			      pixman_region16_t     *region)
+{
+    cairo_color_t color;
+    int num_rects = pixman_region_num_rects (region);
+    pixman_box16_t *boxes = pixman_region_rects (region);
+    cairo_rectangle_t *rects;
+    cairo_status_t status;
+    int i;
 
-	if (_cairo_rectangle_empty (&extents)) {
-	    status = CAIRO_STATUS_SUCCESS;
-	    goto BAIL1;
-	}
-	
-	translate_traps (traps, -extents.x, -extents.y);
+    if (!num_rects)
+	return CAIRO_STATUS_SUCCESS;
+    
+    rects = malloc (sizeof (pixman_rectangle_t) * num_rects);
+    if (!rects)
+	return CAIRO_STATUS_NO_MEMORY;
 
-	_cairo_color_init (&empty_color);
-	_cairo_color_set_alpha (&empty_color, 0.);
-	intermediate = _cairo_surface_create_similar_solid (gstate->clip.surface,
-							    CAIRO_FORMAT_A8,
-							    extents.width,
-							    extents.height,
-							    &empty_color);    
-	if (intermediate == NULL) {
-	    status = CAIRO_STATUS_NO_MEMORY;
-	    goto BAIL1;
-	}
-	
-	_cairo_pattern_init_solid (&pattern.solid, 1.0, 1.0, 1.0);
+    for (i = 0; i < num_rects; i++) {
+	rects[i].x = boxes[i].x1;
+	rects[i].y = boxes[i].y1;
+	rects[i].width = boxes[i].x2 - boxes[i].x1;
+	rects[i].height = boxes[i].y2 - boxes[i].y1;
+    }
 
-	status = _cairo_surface_composite_trapezoids (CAIRO_OPERATOR_ADD,
-						      &pattern.base,
-						      intermediate,
-						      extents.x, extents.y,
-						      0, 0,
-						      extents.width,
-						      extents.height,
-						      traps->traps,
-						      traps->num_traps);
-	_cairo_pattern_fini (&pattern.base);
+    _cairo_color_init (&color);
+    _cairo_color_set_rgb (&color, src->red, src->green, src->blue);
+    _cairo_color_set_alpha (&color, gstate->alpha);
 
-	if (status)
-	    goto BAIL2;
+    status =  _cairo_surface_fill_rectangles (dst, operator,
+					      &color, rects, num_rects);
+    
+    free (rects);
 
+    return status;
+}
 
-	_cairo_pattern_init_for_surface (&pattern.surface,
-					 gstate->clip.surface);
+/* Composites a set of trapezoids in the general case where
+   gstate->clip.surface == NULL
+ */
+static cairo_status_t
+_composite_traps (cairo_gstate_t    *gstate,
+		  cairo_pattern_t   *src,
+		  cairo_operator_t   operator,
+		  cairo_surface_t   *dst,
+		  cairo_traps_t     *traps,
+		  cairo_rectangle_t *extents)
+{
+    cairo_pattern_union_t pattern;
+    cairo_status_t status;
 
-	status = _cairo_surface_composite (CAIRO_OPERATOR_IN,
-					   &pattern.base,
-					   NULL,
-					   intermediate,
-					   extents.x - gstate->clip.rect.x,
-					   extents.y - gstate->clip.rect.y, 
-					   0, 0,
-					   0, 0,
-					   extents.width, extents.height);
-	_cairo_pattern_fini (&pattern.base);
+    _cairo_gstate_pattern_init_copy (gstate, &pattern, src);
     
-	if (status)
-	    goto BAIL2;
+    status = _cairo_surface_composite_trapezoids (gstate->operator,
+						  &pattern.base, dst,
+						  extents->x, extents->y,
+						  extents->x, extents->y,
+						  extents->width,
+						  extents->height,
+						  traps->traps,
+						  traps->num_traps);
 
-	_cairo_pattern_init_for_surface (&intermediate_pattern, intermediate);
-	_cairo_gstate_pattern_init_copy (gstate, &pattern, src);
-	
-	status = _cairo_surface_composite (operator,
-					   &pattern.base,
-					   &intermediate_pattern.base,
-					   dst,
-					   extents.x, extents.y,
-					   0, 0,
-					   extents.x, extents.y,
-					   extents.width, extents.height);
+    _cairo_pattern_fini (&pattern.base);
 
-	_cairo_pattern_fini (&pattern.base);
-	_cairo_pattern_fini (&intermediate_pattern.base);
-	
-    BAIL2:
-	cairo_surface_destroy (intermediate);
-    BAIL1:
+    return status;
+}
 
-	if (status)
-	    return status;
-	
-    } else {
-	if (gstate->clip.region) {
-	    pixman_box16_t box;
-	    pixman_box16_t *intersection_extents;
-	    pixman_region16_t *rect, *intersection;
+/* Warning: This call modifies the coordinates of traps */
+static cairo_status_t
+_cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate,
+					     cairo_pattern_t *src,
+					     cairo_operator_t operator,
+					     cairo_surface_t *dst,
+					     cairo_traps_t *traps)
+{
+    cairo_status_t status;
+    pixman_region16_t *trap_region;
+    cairo_rectangle_t extents;
+    
+    if (traps->num_traps == 0)
+	return CAIRO_STATUS_SUCCESS;
 
-	    box.x1 = _cairo_fixed_integer_floor (trap_extents.p1.x);
-	    box.y1 = _cairo_fixed_integer_floor (trap_extents.p1.y);
-	    box.x2 = _cairo_fixed_integer_ceil (trap_extents.p2.x);
-	    box.y2 = _cairo_fixed_integer_ceil (trap_extents.p2.y);
+    if (gstate->surface == NULL)
+	return CAIRO_STATUS_NO_TARGET_SURFACE;
 
-	    rect = pixman_region_create_simple (&box);
-	    if (rect == NULL)
-		goto bail1;
-	    intersection = pixman_region_create();
-	    if (intersection == NULL)
-		goto bail2;
+    status = _cairo_traps_extract_region (traps, &trap_region);
+    if (!CAIRO_OK (status))
+	return status;
 
-	    if (pixman_region_intersect (intersection, gstate->clip.region,
-					 rect) != PIXMAN_REGION_STATUS_SUCCESS)
-		goto bail3;
-	    intersection_extents = pixman_region_extents (intersection);
+    if (trap_region)
+	status = _clip_and_compute_extents_region (gstate, trap_region, &extents);
+    else
+	status = _clip_and_compute_extents_arbitrary (gstate, traps, &extents);
+	
+    if (!CAIRO_OK (status))
+	goto out;
+    
+    if (_cairo_rectangle_empty (&extents))
+	/* Nothing to do */
+	goto out;
 
-	    extents.x = intersection_extents->x1;
-	    extents.y = intersection_extents->y1;
-	    extents.width = intersection_extents->x2 - intersection_extents->x1;
-	    extents.height = intersection_extents->y2 - intersection_extents->y1;
-	bail3:
-	    pixman_region_destroy (intersection);
-	bail2:
-	    pixman_region_destroy (rect);
-	bail1:
-	    ;
+    if (gstate->clip.surface) {
+	if (trap_region) {
+	    /* If we are compositing a set of rectangles, we can set them as the
+	     * clip region for the destination surface and use the clip surface
+	     * as the mask. A clip region might not be supported, in which case
+	     * we fall through to the next method
+	     */
+	    status = _composite_trap_region (gstate, src, operator, dst,
+					     trap_region, &extents);
+	    if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+		goto out;
 	}
-
-	_cairo_gstate_pattern_init_copy (gstate, &pattern, src);
 	
-	status = _cairo_surface_composite_trapezoids (gstate->operator,
-						      &pattern.base, dst,
-						      extents.x, extents.y,
-						      extents.x, extents.y,
-						      extents.width,
-						      extents.height,
-						      traps->traps,
-						      traps->num_traps);
-
-	_cairo_pattern_fini (&pattern.base);
-    
-	if (status)
-	    return status;
+	/* Handle a clip surface by creating an intermediate surface. */
+	status = _composite_traps_intermediate_surface (gstate, src, operator,
+							dst, traps, &extents);
+    } else {
+        /* No clip surface */
+	if (trap_region && src->type == CAIRO_PATTERN_SOLID) {
+	    /* Solid rectangles are handled specially */
+	    status = _composite_trap_region_solid (gstate, (cairo_solid_pattern_t *)src,
+						   operator, dst, trap_region);
+	} else if (trap_region && pixman_region_num_rects (trap_region) <= 1) {
+	    /* For a simple rectangle, we can just use composite(), for more
+	     * rectangles, we'd have to set a clip region. That might still
+	     * be a win, but it's less obvious. (Depends on the backend)
+	     */
+	    status = _composite_trap_region (gstate, src, operator, dst,
+					     trap_region, &extents);
+	} else {
+	    status = _composite_traps (gstate, src, operator,
+				       dst, traps, &extents);
+	}
     }
+
+ out:
+    if (trap_region)
+	pixman_region_destroy (trap_region);
     
-    return CAIRO_STATUS_SUCCESS;
+    return status;
 }
 
 cairo_status_t
@@ -1781,40 +2015,6 @@
     return CAIRO_STATUS_SUCCESS;
 }
 
-static int
-extract_transformed_rectangle(cairo_matrix_t *mat,
-			      cairo_traps_t *tr,
-			      pixman_box16_t *box)
-{
-    double a, b, c, d, tx, ty;
-
-    cairo_matrix_get_affine (mat, &a, &b, &c, &d, &tx, &ty);    
-    if (!(b == 0. && c == 0.))
-	return 0;
-
-    if (tr->num_traps == 1 
-	&& tr->traps[0].left.p1.x == tr->traps[0].left.p2.x
-	&& tr->traps[0].right.p1.x == tr->traps[0].right.p2.x
-	&& tr->traps[0].left.p1.y == tr->traps[0].right.p1.y
-	&& tr->traps[0].left.p2.y == tr->traps[0].right.p2.y
-	&& _cairo_fixed_is_integer(tr->traps[0].left.p1.x)
-	&& _cairo_fixed_is_integer(tr->traps[0].left.p1.y)
-	&& _cairo_fixed_is_integer(tr->traps[0].left.p2.x)
-	&& _cairo_fixed_is_integer(tr->traps[0].left.p2.y)
-	&& _cairo_fixed_is_integer(tr->traps[0].right.p1.x)
-	&& _cairo_fixed_is_integer(tr->traps[0].right.p1.y)
-	&& _cairo_fixed_is_integer(tr->traps[0].right.p2.x)
-	&& _cairo_fixed_is_integer(tr->traps[0].right.p2.y)) {
-
-	box->x1 = (short) _cairo_fixed_integer_part(tr->traps[0].left.p1.x);
-	box->x2 = (short) _cairo_fixed_integer_part(tr->traps[0].right.p1.x);
-	box->y1 = (short) _cairo_fixed_integer_part(tr->traps[0].left.p1.y);
-	box->y2 = (short) _cairo_fixed_integer_part(tr->traps[0].left.p2.y);
-	return 1;
-    }
-    return 0;
-}
-
 /* Reset surface clip region to the one in the gstate */
 cairo_status_t
 _cairo_gstate_restore_external_state (cairo_gstate_t *gstate)
@@ -1842,51 +2042,47 @@
     cairo_traps_t traps;
     cairo_color_t white_color;
     cairo_box_t extents;
-    pixman_box16_t box;
+    pixman_region16_t *region;
 
     /* Fill the clip region as traps. */
 
     _cairo_traps_init (&traps);
     status = _cairo_path_fixed_fill_to_traps (&gstate->path, gstate, &traps);
-    if (status) {
+    if (!CAIRO_OK (status)) {
 	_cairo_traps_fini (&traps);
 	return status;
     }
 
     /* Check to see if we can represent these traps as a PixRegion. */
 
-    if (extract_transformed_rectangle (&gstate->ctm, &traps, &box)) {
-
-	pixman_region16_t *rect = NULL;
-	pixman_region16_t *intersection = NULL;
-
+    status = _cairo_traps_extract_region (&traps, &region);
+    if (!CAIRO_OK (status)) {
+	_cairo_traps_fini (&traps);
+	return status;
+    }
+    
+    if (region) {
 	status = CAIRO_STATUS_SUCCESS;
-	rect = pixman_region_create_simple (&box);
 	
-	if (rect == NULL) {
-	    status = CAIRO_STATUS_NO_MEMORY;
-
+	if (gstate->clip.region == NULL) {
+	    gstate->clip.region = region;
 	} else {
-	    
-	    if (gstate->clip.region == NULL) {
-		gstate->clip.region = rect;		
-	    } else {
-		intersection = pixman_region_create();
-		if (pixman_region_intersect (intersection, 
-					     gstate->clip.region, rect)
-		    == PIXMAN_REGION_STATUS_SUCCESS) {
-		    pixman_region_destroy (gstate->clip.region);
-		    gstate->clip.region = intersection;
-		} else {		
-		    status = CAIRO_STATUS_NO_MEMORY;
-		}
-		pixman_region_destroy (rect);
+	    pixman_region16_t *intersection = pixman_region_create();
+
+	    if (pixman_region_intersect (intersection, 
+					 gstate->clip.region, region)
+		== PIXMAN_REGION_STATUS_SUCCESS) {
+		pixman_region_destroy (gstate->clip.region);
+		gstate->clip.region = intersection;
+	    } else {		
+		status = CAIRO_STATUS_NO_MEMORY;
 	    }
-	    
-	    if (!status)
-		status = _cairo_surface_set_clip_region (gstate->surface, 
-							 gstate->clip.region);
+	    pixman_region_destroy (region);
 	}
+	    
+	if (CAIRO_OK (status))
+	    status = _cairo_surface_set_clip_region (gstate->surface, 
+						     gstate->clip.region);
 	
 	if (status != CAIRO_INT_STATUS_UNSUPPORTED) {
 	    _cairo_traps_fini (&traps);

Index: cairo-traps.c
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo-traps.c,v
retrieving revision 1.23
retrieving revision 1.24
diff -u -d -r1.23 -r1.24
--- cairo-traps.c	7 Mar 2005 22:23:07 -0000	1.23
+++ cairo-traps.c	13 Apr 2005 18:23:43 -0000	1.24
@@ -738,3 +738,58 @@
 {
     *extents = traps->extents;
 }
+
+/**
+ * _cairo_traps_extract_region:
+ * @traps: a #cairo_traps_t
+ * @region: on return, %NULL is stored here if the trapezoids aren't
+ *          exactly representable as a pixman region, otherwise a
+ *          a pointer to such a region, newly allocated.
+ *          (free with pixman region destroy)
+ * 
+ * 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
+ **/
+cairo_status_t
+_cairo_traps_extract_region (cairo_traps_t      *traps,
+			     pixman_region16_t **region)
+{
+    int i;
+
+    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
+	      && traps->traps[i].left.p1.y == traps->traps[i].right.p1.y
+	      && traps->traps[i].left.p2.y == traps->traps[i].right.p2.y
+	      && _cairo_fixed_is_integer(traps->traps[i].left.p1.x)
+	      && _cairo_fixed_is_integer(traps->traps[i].left.p1.y)
+	      && _cairo_fixed_is_integer(traps->traps[i].left.p2.x)
+	      && _cairo_fixed_is_integer(traps->traps[i].left.p2.y)
+	      && _cairo_fixed_is_integer(traps->traps[i].right.p1.x)
+	      && _cairo_fixed_is_integer(traps->traps[i].right.p1.y)
+	      && _cairo_fixed_is_integer(traps->traps[i].right.p2.x)
+	      && _cairo_fixed_is_integer(traps->traps[i].right.p2.y))) {
+	    *region = NULL;
+	    return CAIRO_STATUS_SUCCESS;
+	}
+    
+    *region = pixman_region_create ();
+
+    for (i = 0; i < traps->num_traps; i++) {
+	int x = _cairo_fixed_integer_part(traps->traps[i].left.p1.x);
+	int y = _cairo_fixed_integer_part(traps->traps[i].left.p1.y);
+	int width = _cairo_fixed_integer_part(traps->traps[i].right.p1.x) - x;
+	int height = _cairo_fixed_integer_part(traps->traps[i].left.p2.y) - y;
+	
+	if (pixman_region_union_rect (*region, *region,
+				      x, y, width, height) != PIXMAN_REGION_STATUS_SUCCESS) {
+	    pixman_region_destroy (*region);
+	    return CAIRO_STATUS_NO_MEMORY;
+	}
+    }
+
+    return CAIRO_STATUS_SUCCESS;
+}
+

Index: cairoint.h
===================================================================
RCS file: /cvs/cairo/cairo/src/cairoint.h,v
retrieving revision 1.125
retrieving revision 1.126
diff -u -d -r1.125 -r1.126
--- cairoint.h	8 Apr 2005 21:06:32 -0000	1.125
+++ cairoint.h	13 Apr 2005 18:23:43 -0000	1.126
@@ -1625,6 +1625,10 @@
 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_slope.c */
 cairo_private void
 _cairo_slope_init (cairo_slope_t *slope, cairo_point_t *a, cairo_point_t *b);




More information about the cairo-commit mailing list