[cairo-commit] cairo/src cairo-gstate-private.h, 1.7, 1.8 cairo-gstate.c, 1.129, 1.130 cairo-pattern.c, 1.38, 1.39 cairo-surface.c, 1.68, 1.69 cairo-xcb-surface.c, 1.29, 1.30 cairo-xlib-surface.c, 1.72, 1.73 cairo.c, 1.97, 1.98 cairo.h, 1.121, 1.122 cairoint.h, 1.143, 1.144

Keith Packard commit at pdx.freedesktop.org
Thu May 26 11:35:48 PDT 2005


Committed by: keithp

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

Modified Files:
	cairo-gstate-private.h cairo-gstate.c cairo-pattern.c 
	cairo-surface.c cairo-xcb-surface.c cairo-xlib-surface.c 
	cairo.c cairo.h cairoint.h 
Log Message:
2005-05-26  Keith Packard  <keithp at keithp.com>

	reviewed by: krh, otaylor, cworth

	Replace nesting-only surface clipping with gstate contained
	serial-number tracked clipping sets that are loaded into the surface
	on demand just before each rendering operation.  This permits
	multiple cairo_t contexts to reference a surface without
	regard to ordering of operations among the contexts.

	Also in this patch is a change to the xlib surface that
	creates two separate Pictures, one for source and one for
	destination operands which separates the source clipping
	from destination clipping.  Cairo now specifies that sources
	are never clipped by any clipping applied to them as destinations.

	* src/cairoint.h:
	* src/cairo-gstate-private.h:
	Move cairo_clip_t (renamed from cairo_clip_rec_t) from cairoint.h
	to cairo-gstate-private.h.  Eliminate stack of clip state
	from surfaces.  Add new surface clipping API.
	
	* src/cairo-gstate.c: (_cairo_gstate_init),
	(_cairo_gstate_init_copy), (_cairo_gstate_fini),
	(_cairo_gstate_has_surface_clip), (_cairo_gstate_set_clip),
	(_cairo_gstate_get_clip_extents),
	(_cairo_gstate_set_target_surface), (_cairo_gstate_paint),
	(_cairo_gstate_combine_clip_surface),
	(_cairo_gstate_intersect_clip), (_get_mask_extents),
	(_cairo_gstate_mask), (_cairo_gstate_stroke),
	(_clip_and_compute_extents_arbitrary), (_composite_trap_region),
	(_cairo_gstate_fill), (_cairo_gstate_reset_clip),
	(_cairo_gstate_clip), (_cairo_gstate_show_glyphs):
	Manage clip objects entirely within the gstate, loading
	the whole thing into the surface just before drawing.
	
	* src/cairo-pattern.c:
	(_cairo_pattern_acquire_surface_for_gradient),
	(_cairo_pattern_acquire_surface_for_solid),
	(_cairo_pattern_acquire_surface_for_surface),
	(_cairo_pattern_acquire_surface), (_cairo_pattern_release_surface):
	Source surfaces need not have clipping modified as the
	surface interface now specifies that source surfaces are always
	unclipped.
	
	* src/cairo-surface.c: (_cairo_surface_init),
	(cairo_surface_finish), (_cairo_surface_clone_similar),
	(_cairo_surface_get_current_clip_serial),
	(_cairo_surface_allocate_clip_serial), (_cairo_surface_reset_clip),
	(_cairo_surface_can_clip_region), (_cairo_surface_set_clip_region),
	(_cairo_surface_can_clip_path), (_cairo_surface_clip_path),
	(_cairo_surface_get_extents):
	Eliminate nested clipping contexts, leaving clip management
	entirely to the gstate.  Create new clip API for the gstate
	which uses per-surface serial numbers to match gstate clipping
	against current surface clipping values.
	
	Surfaces no longer track clipping regions at all, so the
	old _cairo_surface_get_clip_extents has been replaced with
	_cairo_surface_get_extents.  For PDF/PS surfaces, this
	function is expected to return a rectangle covering the
	entire fixed point coordinate space to leave rendering
	unclipped by the surface.
	
	* src/cairo-xcb-surface.c:
	Region clipping capability is now signalled by a non-NULL
	function pointer in set_clip_region.
	
	* src/cairo-xlib-surface.c: (_cairo_xlib_surface_finish),
	(_cairo_xlib_surface_ensure_src_picture),
	(_cairo_xlib_surface_ensure_dst_picture),
	(_cairo_xlib_surface_set_matrix), (_cairo_xlib_surface_set_filter),
	(_cairo_xlib_surface_set_repeat),
	(_cairo_xlib_surface_set_attributes),
	(_cairo_xlib_surface_composite),
	(_cairo_xlib_surface_fill_rectangles),
	(_cairo_xlib_surface_composite_trapezoids),
	(_cairo_xlib_surface_set_clip_region),
	(_cairo_xlib_surface_create_internal),
	(_cairo_xlib_surface_show_glyphs32),
	(_cairo_xlib_surface_show_glyphs16),
	(_cairo_xlib_surface_show_glyphs8),
	(_cairo_xlib_surface_show_glyphs):
	Each surface now contains two Pictures, one for source
	and one for destination operands so that source operands
	are never clipped by destination clipping.

	* src/cairo.h:
	* src/cairo.c: (cairo_status_string):
	CAIRO_STATUS_BAD_NESTING removed
	
	* test/Makefile.am:
	* test/self-copy.c: (main):
	self-copy now passes (Xlib only, until libpixman changes land)


Index: cairo-gstate-private.h
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo-gstate-private.h,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -d -r1.7 -r1.8
--- cairo-gstate-private.h	2 May 2005 20:39:33 -0000	1.7
+++ cairo-gstate-private.h	26 May 2005 18:35:46 -0000	1.8
@@ -36,6 +36,33 @@
 #ifndef CAIRO_GSTATE_PRIVATE_H
 #define CAIRO_GSTATE_PRIVATE_H
 
+typedef struct _cairo_clip {
+    /*
+     * Mask-based clipping for cases where the backend 
+     * clipping isn't sufficiently able.
+     *
+     * The rectangle here represents the
+     * portion of the destination surface that this
+     * clip surface maps to, it does not
+     * represent the extents of the clip region or
+     * clip paths
+     */
+    cairo_surface_t *surface;
+    cairo_rectangle_t surface_rect;
+    /*
+     * Surface clip serial number to store
+     * in the surface when this clip is set
+     */
+    unsigned int serial;
+    /*
+     * A clip region that can be placed in the surface
+     */
+    pixman_region16_t *region;
+    /*
+     * XXX add clip paths here
+     */
+} cairo_clip_t;
+
 struct _cairo_gstate {
     cairo_operator_t operator;
     
@@ -61,11 +88,10 @@
     cairo_scaled_font_t *scaled_font;	/* Specific to the current CTM */
 
     cairo_surface_t *surface;
-    int surface_level;		/* Used to detect bad nested use */
 
     cairo_pattern_t *source;
 
-    cairo_clip_rec_t clip;
+    cairo_clip_t clip;
 
     cairo_matrix_t font_matrix;
 

Index: cairo-gstate.c
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo-gstate.c,v
retrieving revision 1.129
retrieving revision 1.130
diff -u -d -r1.129 -r1.130
--- cairo-gstate.c	12 May 2005 18:02:35 -0000	1.129
+++ cairo-gstate.c	26 May 2005 18:35:46 -0000	1.130
@@ -61,6 +61,9 @@
 static void
 _cairo_gstate_unset_font (cairo_gstate_t *gstate);
 
+static void
+_cairo_rectangle_intersect (cairo_rectangle_t *dest, cairo_rectangle_t *src);
+
 cairo_gstate_t *
 _cairo_gstate_create (cairo_surface_t *target)
 {
@@ -110,10 +113,10 @@
 			     CAIRO_GSTATE_DEFAULT_FONT_SIZE);
     
     gstate->surface = NULL;
-    gstate->surface_level = 0;
 
     gstate->clip.region = NULL;
     gstate->clip.surface = NULL;
+    gstate->clip.serial = 0;
 
     gstate->source = _cairo_pattern_create_solid (CAIRO_COLOR_BLACK);
     if (!gstate->source)
@@ -151,8 +154,7 @@
 	memcpy (gstate->dash, other->dash, other->num_dashes * sizeof (double));
     }
 
-    if (other->clip.region)
-    {	
+    if (other->clip.region) {
 	gstate->clip.region = pixman_region_create ();
 	pixman_region_copy (gstate->clip.region, other->clip.region);
     }
@@ -172,16 +174,8 @@
     if (status)
 	goto CLEANUP_FONT;
 
-    status = _cairo_surface_begin (gstate->surface);
-    if (status)
-	goto CLEANUP_PEN;
-    gstate->surface_level = gstate->surface->level;
-
     return status;
 
-  CLEANUP_PEN:
-    _cairo_pen_fini (&gstate->pen_regular);
-
   CLEANUP_FONT:
     cairo_scaled_font_destroy (gstate->scaled_font);
     gstate->scaled_font = NULL;
@@ -202,7 +196,6 @@
 	cairo_scaled_font_destroy (gstate->scaled_font);
 
     if (gstate->surface) {
-	_cairo_surface_end (gstate->surface);
 	cairo_surface_destroy (gstate->surface);
 	gstate->surface = NULL;
     }
@@ -214,6 +207,7 @@
     if (gstate->clip.region)
 	pixman_region_destroy (gstate->clip.region);
     gstate->clip.region = NULL;
+    gstate->clip.serial = 0;
 
     cairo_pattern_destroy (gstate->source);
 
@@ -333,26 +327,84 @@
 }
 */
 
+static cairo_bool_t
+_cairo_gstate_has_surface_clip (cairo_gstate_t *gstate)
+{
+    /* check for path clipping here */
+    
+    if (gstate->clip.region)
+	return 1;
+    return 0;
+}
+
 static cairo_status_t
-_cairo_gstate_set_target_surface (cairo_gstate_t *gstate, cairo_surface_t *surface)
+_cairo_gstate_set_clip (cairo_gstate_t *gstate)
 {
-    cairo_status_t status;
+    cairo_surface_t *surface = gstate->surface;
     
-    if (gstate->surface == surface)
+    if (!surface)
+	return CAIRO_STATUS_NULL_POINTER;
+    if (gstate->clip.serial == _cairo_surface_get_current_clip_serial (surface))
 	return CAIRO_STATUS_SUCCESS;
     
-    if (surface) {
-	status = _cairo_surface_begin_reset_clip (surface);
-	if (!CAIRO_OK (status))
-	    return status;
+    /* check for path clipping here */
+    
+    if (gstate->clip.region)
+	return _cairo_surface_set_clip_region (surface, 
+					       gstate->clip.region,
+					       gstate->clip.serial);
+    
+    return _cairo_surface_reset_clip (surface);
+}
+
+static cairo_status_t
+_cairo_gstate_get_clip_extents (cairo_gstate_t	    *gstate,
+				cairo_rectangle_t   *rectangle)
+{
+    cairo_status_t  status;
+    
+    status = _cairo_surface_get_extents (gstate->surface, rectangle);
+    if (!CAIRO_OK(status))
+	return status;
+    /* check path extents here */
+    
+    if (gstate->clip.region) {
+	pixman_box16_t	    *clip_box;
+	cairo_rectangle_t   clip_rect;
+
+	/* get region extents as a box */
+	clip_box = pixman_region_extents (gstate->clip.region);
+	/* convert to a rectangle */
+	clip_rect.x = clip_box->x1;
+	clip_rect.width = clip_box->x2 - clip_box->x1;
+	clip_rect.y = clip_box->y1;
+	clip_rect.width = clip_box->y2 + clip_box->y1;
+	/* intersect with surface extents */
+	_cairo_rectangle_intersect (rectangle, &clip_rect);
     }
 
+    if (gstate->clip.surface)
+	_cairo_rectangle_intersect (rectangle, &gstate->clip.surface_rect);
+    
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_gstate_set_target_surface (cairo_gstate_t *gstate, cairo_surface_t *surface)
+{
+    if (gstate->surface == surface)
+	return CAIRO_STATUS_SUCCESS;
+    
+    /* allocate a new serial to represent our current state. Each 
+       surface has its own set of serials */
+    gstate->clip.serial = 0;
+    if (surface && _cairo_gstate_has_surface_clip (gstate))
+	gstate->clip.serial = _cairo_surface_allocate_clip_serial (surface);
+
     _cairo_gstate_unset_font (gstate);
 
-    if (gstate->surface) {
-	_cairo_surface_end (gstate->surface);
+    if (gstate->surface)
 	cairo_surface_destroy (gstate->surface);
-    }
 
     gstate->surface = surface;
 
@@ -360,12 +412,10 @@
      * (just like after cairo_create). This can be useful for forcing
      * the old surface to be destroyed. */
     if (surface == NULL) {
-	gstate->surface_level = 0;
 	return CAIRO_STATUS_SUCCESS;
     }
 
     cairo_surface_reference (gstate->surface);
-    gstate->surface_level = surface->level;
 
     _cairo_gstate_identity_matrix (gstate);
 
@@ -733,10 +783,11 @@
     cairo_box_t box;
     cairo_traps_t traps;
 
-    if (gstate->surface->level != gstate->surface_level)
-	return CAIRO_STATUS_BAD_NESTING;
-    
-    status = _cairo_surface_get_clip_extents (gstate->surface, &rectangle);
+    status = _cairo_gstate_set_clip (gstate);
+    if (!CAIRO_OK (status))
+	return status;
+
+    status = _cairo_gstate_get_clip_extents (gstate, &rectangle);
     if (!CAIRO_OK (status))
 	return status;
 
@@ -778,8 +829,8 @@
 				       &pattern.base,
 				       NULL,
 				       intermediate,
-				       extents->x - gstate->clip.rect.x,
-				       extents->y - gstate->clip.rect.y, 
+				       extents->x - gstate->clip.surface_rect.x,
+				       extents->y - gstate->clip.surface_rect.y, 
 				       0, 0,
 				       0, 0,
 				       extents->width, extents->height);
@@ -832,7 +883,7 @@
 	pixman_region16_t *clip_rect;
 	cairo_status_t status;
     
-	status = _region_new_from_rect (&gstate->clip.rect, &clip_rect);
+	status = _region_new_from_rect (&gstate->clip.surface_rect, &clip_rect);
 	if (!CAIRO_OK (status))
 	    return status;
 	
@@ -855,27 +906,12 @@
 		   cairo_pattern_t   *mask,
 		   cairo_rectangle_t *extents)
 {
-    cairo_rectangle_t clip_rect;
-    pixman_region16_t *clip_region;
-    cairo_status_t status;
-    
-    status = _cairo_surface_get_clip_extents (gstate->surface, &clip_rect);
-    if (!CAIRO_OK (status))
-	return status;
-
-    status = _region_new_from_rect (&clip_rect, &clip_region);
-    if (!CAIRO_OK (status))
-	return status;
-
-    status = _cairo_gstate_intersect_clip (gstate, clip_region);
-    if (!CAIRO_OK (status))
-	return status;
-
-    _region_rect_extents (clip_region, extents);
-
-    pixman_region_destroy (clip_region);
-
-    return CAIRO_STATUS_SUCCESS;
+    /*
+     * XXX should take mask extents into account, but
+     * that involves checking the transform...  For now,
+     * be lazy and just use the destination extents
+     */
+    return _cairo_gstate_get_clip_extents (gstate, extents);
 }
 
 cairo_status_t
@@ -889,9 +925,10 @@
     cairo_status_t status;
     int mask_x, mask_y;
 
-    if (gstate->surface->level != gstate->surface_level)
-	return CAIRO_STATUS_BAD_NESTING;
-    
+    status = _cairo_gstate_set_clip (gstate);
+    if (!CAIRO_OK (status))
+	return status;
+
     _get_mask_extents (gstate, mask, &extents);
     
     if (gstate->clip.surface) {
@@ -960,12 +997,13 @@
     cairo_status_t status;
     cairo_traps_t traps;
 
-    if (gstate->surface->level != gstate->surface_level)
-	return CAIRO_STATUS_BAD_NESTING;
-    
     if (gstate->line_width <= 0.0)
 	return CAIRO_STATUS_SUCCESS;
 
+    status = _cairo_gstate_set_clip (gstate);
+    if (!CAIRO_OK (status))
+	return status;
+
     _cairo_pen_init (&gstate->pen_regular, gstate->line_width / 2.0, gstate);
 
     _cairo_traps_init (&traps);
@@ -1122,7 +1160,7 @@
     }
 
     if (gstate->clip.surface)
-	_cairo_rectangle_intersect (extents, &gstate->clip.rect);
+	_cairo_rectangle_intersect (extents, &gstate->clip.surface_rect);
 
     return CAIRO_STATUS_SUCCESS;
 }
@@ -1137,16 +1175,25 @@
 			pixman_region16_t *trap_region,
 			cairo_rectangle_t *extents)
 {
-    cairo_status_t status, tmp_status;
+    cairo_status_t status;
     cairo_pattern_union_t pattern;
     cairo_pattern_union_t mask;
     int num_rects = pixman_region_num_rects (trap_region);
+    unsigned int clip_serial;
 
     if (num_rects == 0)
 	return CAIRO_STATUS_SUCCESS;
     
     if (num_rects > 1) {
-	status = _cairo_surface_set_clip_region (dst, trap_region);
+	
+	status = _cairo_surface_can_clip_region (gstate->surface);
+	if (!CAIRO_OK (status))
+	    return status;
+	
+	clip_serial = _cairo_surface_allocate_clip_serial (gstate->surface);
+	status = _cairo_surface_set_clip_region (gstate->surface, 
+						 trap_region,
+						 clip_serial);
 	if (!CAIRO_OK (status))
 	    return status;
     }
@@ -1162,8 +1209,8 @@
 				       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 - (gstate->clip.surface ? gstate->clip.surface_rect.x : 0),
+				       extents->y - (gstate->clip.surface ? gstate->clip.surface_rect.y : 0),
 				       extents->x, extents->y,
 				       extents->width, extents->height);
 
@@ -1171,12 +1218,6 @@
     if (gstate->clip.surface)
       _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;
 }
 
@@ -1431,8 +1472,9 @@
     cairo_status_t status;
     cairo_traps_t traps;
 
-    if (gstate->surface->level != gstate->surface_level)
-	return CAIRO_STATUS_BAD_NESTING;
+    status = _cairo_gstate_set_clip (gstate);
+    if (!CAIRO_OK (status))
+	return status;
 
     status = _cairo_surface_fill_path (gstate->operator,
 				       gstate->source,
@@ -1574,9 +1616,6 @@
 cairo_status_t
 _cairo_gstate_reset_clip (cairo_gstate_t *gstate)
 {
-    if (gstate->surface->level != gstate->surface_level)
-	return CAIRO_STATUS_BAD_NESTING;
-    
     /* destroy any existing clip-region artifacts */
     if (gstate->clip.surface)
 	cairo_surface_destroy (gstate->clip.surface);
@@ -1585,12 +1624,8 @@
     if (gstate->clip.region)
 	pixman_region_destroy (gstate->clip.region);
     gstate->clip.region = NULL;
-
-    /* reset the surface's clip to the whole surface */
-    if (gstate->surface)
-	_cairo_surface_set_clip_region (gstate->surface, 
-					gstate->clip.region);
-
+    gstate->clip.serial = 0;
+    
     return CAIRO_STATUS_SUCCESS;
 }
 
@@ -1603,9 +1638,6 @@
     cairo_box_t extents;
     pixman_region16_t *region;
 
-    if (gstate->surface->level != gstate->surface_level)
-	return CAIRO_STATUS_BAD_NESTING;
-    
     /* Fill the clip region as traps. */
 
     _cairo_traps_init (&traps);
@@ -1615,63 +1647,62 @@
 	return status;
     }
 
-    /* Check to see if we can represent these traps as a PixRegion. */
-
-    status = _cairo_traps_extract_region (&traps, &region);
-    if (!CAIRO_OK (status)) {
-	_cairo_traps_fini (&traps);
-	return status;
-    }
+    status = _cairo_surface_can_clip_region (gstate->surface);
     
-    if (region) {
-	status = CAIRO_STATUS_SUCCESS;
+    if (status != CAIRO_INT_STATUS_UNSUPPORTED) {
+	if (!CAIRO_OK (status))
+	    return status;
+    
+	/* Check to see if we can represent these traps as a PixRegion. */
+    
+	status = _cairo_traps_extract_region (&traps, &region);
+	if (!CAIRO_OK (status)) {
+	    _cairo_traps_fini (&traps);
+	    return status;
+	}
 	
-	if (gstate->clip.region == NULL) {
-	    gstate->clip.region = region;
-	} else {
-	    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 (region) {
+	    status = CAIRO_STATUS_SUCCESS;
+	    
+	    if (gstate->clip.region == NULL) {
+		gstate->clip.region = region;
+	    } else {
+		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;
+		}
+		pixman_region_destroy (region);
 	    }
-	    pixman_region_destroy (region);
-	}
+	    gstate->clip.serial = _cairo_surface_allocate_clip_serial (gstate->surface);
 	    
-	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);
+	    
 	    return status;
 	}
-
-	/* Fall through as status == CAIRO_INT_STATUS_UNSUPPORTED
-	   means that backend doesn't support clipping regions and
-	   mask surface clipping should be used instead. */
     }
 
     /* Otherwise represent the clip as a mask surface. */
 
     if (gstate->clip.surface == NULL) {
 	_cairo_traps_extents (&traps, &extents);
-	_cairo_box_round_to_rectangle (&extents, &gstate->clip.rect);
+	_cairo_box_round_to_rectangle (&extents, &gstate->clip.surface_rect);
 	gstate->clip.surface =
 	    _cairo_surface_create_similar_solid (gstate->surface,
 						 CAIRO_FORMAT_A8,
-						 gstate->clip.rect.width,
-						 gstate->clip.rect.height,
+						 gstate->clip.surface_rect.width,
+						 gstate->clip.surface_rect.height,
 						 CAIRO_COLOR_WHITE);
 	if (gstate->clip.surface == NULL)
 	    return CAIRO_STATUS_NO_MEMORY;
     }
 
-    translate_traps (&traps, -gstate->clip.rect.x, -gstate->clip.rect.y);
+    translate_traps (&traps, -gstate->clip.surface_rect.x, -gstate->clip.surface_rect.y);
     _cairo_pattern_init_solid (&pattern.solid, CAIRO_COLOR_WHITE);
     
     status = _cairo_surface_composite_trapezoids (CAIRO_OPERATOR_IN,
@@ -1679,8 +1710,8 @@
 						  gstate->clip.surface,
 						  0, 0,
 						  0, 0,
-						  gstate->clip.rect.width,
-						  gstate->clip.rect.height,
+						  gstate->clip.surface_rect.width,
+						  gstate->clip.surface_rect.height,
 						  traps.traps,
 						  traps.num_traps);
 
@@ -1969,9 +2000,10 @@
     cairo_box_t bbox;
     cairo_rectangle_t extents;
 
-    if (gstate->surface->level != gstate->surface_level)
-	return CAIRO_STATUS_BAD_NESTING;
-    
+    status = _cairo_gstate_set_clip (gstate);
+    if (!CAIRO_OK (status))
+	return status;
+
     status = _cairo_gstate_ensure_font (gstate);
     if (status)
 	return status;
@@ -2001,7 +2033,7 @@
 	cairo_surface_t *intermediate;
 	cairo_surface_pattern_t intermediate_pattern;
 	
-	_cairo_rectangle_intersect (&extents, &gstate->clip.rect);
+	_cairo_rectangle_intersect (&extents, &gstate->clip.surface_rect);
 
 	/* Shortcut if empty */
 	if (_cairo_rectangle_empty (&extents)) {
@@ -2048,8 +2080,8 @@
 					   &pattern.base,
 					   NULL,
 					   intermediate,
-					   extents.x - gstate->clip.rect.x,
-					   extents.y - gstate->clip.rect.y, 
+					   extents.x - gstate->clip.surface_rect.x,
+					   extents.y - gstate->clip.surface_rect.y, 
 					   0, 0,
 					   0, 0,
 					   extents.width, extents.height);

Index: cairo-pattern.c
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo-pattern.c,v
retrieving revision 1.38
retrieving revision 1.39
diff -u -d -r1.38 -r1.39
--- cairo-pattern.c	17 May 2005 05:31:36 -0000	1.38
+++ cairo-pattern.c	26 May 2005 18:35:46 -0000	1.39
@@ -960,7 +960,6 @@
     attr->extend = repeat ? CAIRO_EXTEND_REPEAT : CAIRO_EXTEND_NONE;
     attr->filter = CAIRO_FILTER_NEAREST;
     attr->acquired = FALSE;
-    attr->clip_saved = FALSE;
     
     return status;
 }
@@ -988,7 +987,6 @@
     attribs->extend = CAIRO_EXTEND_REPEAT;
     attribs->filter = CAIRO_FILTER_NEAREST;
     attribs->acquired = FALSE;
-    attribs->clip_saved = FALSE;
     
     return CAIRO_STATUS_SUCCESS;
 }
@@ -1032,35 +1030,23 @@
     int tx, ty;
 
     attr->acquired = FALSE;
-    attr->clip_saved = FALSE;
 	    
     if (_cairo_surface_is_image (dst))
     {
 	cairo_image_surface_t *image;
 	
-	status = _cairo_surface_begin_reset_clip (pattern->surface);
-	if (!CAIRO_OK (status))
-	    return status;
-
 	status = _cairo_surface_acquire_source_image (pattern->surface,
 						      &image,
 						      &attr->extra);
 	if (!CAIRO_OK (status))
 	    return status;
 
-	_cairo_surface_end (pattern->surface);
-
 	*out = &image->base;
 	attr->acquired = TRUE;
     }
     else
     {
-	status = _cairo_surface_begin_reset_clip (pattern->surface);
-	if (!CAIRO_OK (status))
-	    return status;
-
 	status = _cairo_surface_clone_similar (dst, pattern->surface, out);
-	_cairo_surface_end (pattern->surface);
     }
     
     attr->extend = pattern->base.extend;
@@ -1162,17 +1148,6 @@
 	status = CAIRO_INT_STATUS_UNSUPPORTED;
     }
 
-    
-    if (CAIRO_OK (status) && (*surface_out)->clip_region) {
-	status = _cairo_surface_begin_reset_clip (*surface_out);
-	if (!CAIRO_OK (status)) {
-	    _cairo_pattern_release_surface (dst, *surface_out, attributes);
-	    return status;
-	}
-	
-	attributes->clip_saved = TRUE;
-    }
-
     return status;
 }
 
@@ -1189,9 +1164,6 @@
 				cairo_surface_t		   *surface,
 				cairo_surface_attributes_t *attributes)
 {
-    if (attributes->clip_saved)
-	_cairo_surface_end (surface);
-    
     if (attributes->acquired)
     {
 	_cairo_surface_release_source_image (dst,

Index: cairo-surface.c
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo-surface.c,v
retrieving revision 1.68
retrieving revision 1.69
diff -u -d -r1.68 -r1.69
--- cairo-surface.c	11 May 2005 23:01:56 -0000	1.68
+++ cairo-surface.c	26 May 2005 18:35:46 -0000	1.69
@@ -39,16 +39,6 @@
 
 #include "cairoint.h"
 
-struct _cairo_surface_save {
-    cairo_surface_save_t *next;
-    pixman_region16_t *clip_region;
-};
-
-static cairo_status_t
-_cairo_surface_set_clip_region_internal (cairo_surface_t   *surface,
-					 pixman_region16_t *region,
-					 cairo_bool_t       copy_region,
-					 cairo_bool_t       free_existing);   
 
 void
 _cairo_surface_init (cairo_surface_t			*surface,
@@ -68,110 +58,8 @@
     surface->device_x_offset = 0;
     surface->device_y_offset = 0;
 
-    surface->clip_region = NULL;
-
-    surface->saves = NULL;
-    surface->level = 0;
-}
-
-static cairo_status_t
-_cairo_surface_begin_internal (cairo_surface_t *surface,
-			       cairo_bool_t     reset_clip)
-{
-    cairo_surface_save_t *save;
-
-    if (surface->finished)
-	return CAIRO_STATUS_SURFACE_FINISHED;
-
-    save = malloc (sizeof (cairo_surface_save_t));
-    if (!save)
-	return CAIRO_STATUS_NO_MEMORY;
-
-    if (surface->clip_region) {
-	if (reset_clip)
-	{
-	    cairo_status_t status;
-	    
-	    save->clip_region = surface->clip_region;
-	    status = _cairo_surface_set_clip_region_internal (surface, NULL, FALSE, FALSE);
-	    if (!CAIRO_OK (status)) {
-		free (save);
-		return status;
-	    }
-	}
-	else
-	{
-	    save->clip_region = pixman_region_create ();
-	    pixman_region_copy (save->clip_region, surface->clip_region);
-	}
-    } else {
-	save->clip_region = NULL;
-    }
-
-    save->next = surface->saves;
-    surface->saves = save;
-    surface->level++;
-
-    return CAIRO_STATUS_SUCCESS;
-}
-
-/**
- * _cairo_surface_begin:
- * @surface: a #cairo_surface_t
- * 
- * Must be called before beginning to use the surface. State
- * of the surface like the clip region will be saved then restored
- * on the matching call _cairo_surface_end().
- */
-cairo_private cairo_status_t
-_cairo_surface_begin (cairo_surface_t *surface)
-{
-    return _cairo_surface_begin_internal (surface, FALSE);
-}
-
-/**
- * _cairo_surface_begin_reset_clip:
- * @surface: a #cairo_surface_t
- * 
- * Must be called before beginning to use the surface. State
- * of the surface like the clip region will be saved then restored
- * on the matching call _cairo_surface_end().
- *
- * After the state is saved, the clip region is cleared.  This
- * combination of operations is a little artificial; the caller could
- * simply call _cairo_surface_set_clip_region (surface, NULL); after
- * _cairo_surface_save(). Combining the two saves a copy of the clip
- * region, and also simplifies error handling for the caller.
- **/
-cairo_private cairo_status_t
-_cairo_surface_begin_reset_clip (cairo_surface_t *surface)
-{
-    return _cairo_surface_begin_internal (surface, TRUE);
-}
-
-/**
- * _cairo_surface_end:
- * @surface: a #cairo_surface_t
- * 
- * Restores any state saved by _cairo_surface_begin()
- **/
-cairo_private cairo_status_t
-_cairo_surface_end (cairo_surface_t *surface)
-{
-    cairo_surface_save_t *save;
-    pixman_region16_t *clip_region;
-
-    if (!surface->saves)
-	return CAIRO_STATUS_BAD_NESTING;
-
-    save = surface->saves;
-    surface->saves = save->next;
-    surface->level--;
-
-    clip_region = save->clip_region;
-    free (save);
-
-    return _cairo_surface_set_clip_region_internal (surface, clip_region, FALSE, TRUE);
+    surface->next_clip_serial = 0;
+    surface->current_clip_serial = 0;
 }
 
 cairo_surface_t *
@@ -286,14 +174,6 @@
     if (surface->finished)
 	return CAIRO_STATUS_SURFACE_FINISHED;
 
-    if (surface->saves)
-	return CAIRO_STATUS_BAD_NESTING;
-    
-    if (surface->clip_region) {
-	pixman_region_destroy (surface->clip_region);
-	surface->clip_region = NULL;
-    }
-
     if (surface->backend->finish) {
 	status = surface->backend->finish (surface);
 	if (status)
@@ -521,7 +401,7 @@
     if (surface->backend->clone_similar) {
 	status = surface->backend->clone_similar (surface, src, clone_out);
 	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
-	    return status;
+ 	    return status;
     }
 
     status = _cairo_surface_acquire_source_image (src, &image, &image_extra);
@@ -907,63 +787,153 @@
     return surface->backend->show_page (surface);
 }
 
-static cairo_status_t
-_cairo_surface_set_clip_region_internal (cairo_surface_t   *surface,
-					 pixman_region16_t *region,
-					 cairo_bool_t       copy_region,
-					 cairo_bool_t       free_existing)
+/**
+ * _cairo_surface_allocate_clip_serial:
+ * @surface: the #cairo_surface_t to return the serial number for
+ *
+ * Returns the serial number associated with the current
+ * clip in the surface.  All gstate functions must
+ * verify that the correct clip is set in the surface before
+ * invoking any surface drawing function
+ */
+cairo_private unsigned int
+_cairo_surface_get_current_clip_serial (cairo_surface_t *surface)
+{
+    return surface->current_clip_serial;
+}
+
+/**
+ * _cairo_surface_allocate_clip_serial:
+ * @surface: the #cairo_surface_t to allocate a serial number from
+ *
+ * Each surface has a separate set of clipping serial numbers,
+ * and this function allocates one from the specified surface.
+ * As zero is reserved for the special no-clipping case,
+ * this function will not return that.
+ */
+cairo_private unsigned int
+_cairo_surface_allocate_clip_serial (cairo_surface_t *surface)
 {
+    unsigned int    serial;
+
+    if ((serial = ++(surface->next_clip_serial)) == 0)
+	serial = ++(surface->next_clip_serial);
+    return serial;
+}
+
+/**
+ * _cairo_surface_reset_clip:
+ * @surface: the #cairo_surface_t to reset the clip on
+ *
+ * This function sets the clipping for the surface to
+ * None, which is to say that drawing is entirely
+ * unclipped.  It also sets the clip serial number
+ * to zero.
+ */
+cairo_private cairo_status_t
+_cairo_surface_reset_clip (cairo_surface_t *surface)
+{
+    cairo_status_t  status;
+
     if (surface->finished)
 	return CAIRO_STATUS_SURFACE_FINISHED;
-
-    if (region == surface->clip_region)
-	return CAIRO_STATUS_SUCCESS;
     
+    surface->current_clip_serial = 0;
+#if 0
+    if (surface->backend->clip_path) {
+	status = surface->backend->clip_path (surface, NULL);
+	if (!CAIRO_OK(status))
+	    return status;
+    }
+#endif
+    if (surface->backend->set_clip_region != NULL) {
+	status = surface->backend->set_clip_region (surface, NULL);
+	if (!CAIRO_OK(status))
+	    return status;
+    }
+    return CAIRO_STATUS_SUCCESS;
+}
+
+/**
+ * _cairo_surface_can_clip_region:
+ * @surface: the #cairo_surface_t to check for region clipping support
+ *
+ * This function checks whether the specified surface can
+ * support region-based clipping.
+ */
+cairo_private cairo_status_t
+_cairo_surface_can_clip_region (cairo_surface_t    *surface)
+{
+    if (surface->finished)
+	return CAIRO_STATUS_SURFACE_FINISHED;
     if (surface->backend->set_clip_region == NULL)
 	return CAIRO_INT_STATUS_UNSUPPORTED;
+    return CAIRO_STATUS_SUCCESS;
+}
 
-    if (surface->clip_region) {
-	if (free_existing)
-	    pixman_region_destroy (surface->clip_region);
-	surface->clip_region = NULL;
-    }
-
-    if (region) {
-	if (copy_region) {
-	    surface->clip_region = pixman_region_create ();
-	    pixman_region_copy (surface->clip_region, region);
-	} else
-	    surface->clip_region = region;
-    }
+/**
+ * _cairo_surface_set_clip_region:
+ * @surface: the #cairo_surface_t to reset the clip on
+ * @region: the #pixman_region16_t to use for clipping
+ * @serial: the clip serial number associated with the region
+ *
+ * This function sets the clipping for the surface to
+ * the specified region and sets the surface clipping
+ * serial number to the associated serial number.
+ */
+cairo_private cairo_status_t
+_cairo_surface_set_clip_region (cairo_surface_t	    *surface,
+				pixman_region16_t   *region,
+				unsigned int	    serial)
+{
+    if (surface->finished)
+	return CAIRO_STATUS_SURFACE_FINISHED;
+    
+    assert (surface->backend->set_clip_region != NULL);
     
+    surface->current_clip_serial = serial;
     return surface->backend->set_clip_region (surface, region);
 }
 
-cairo_status_t
-_cairo_surface_set_clip_region (cairo_surface_t   *surface,
-				pixman_region16_t *region)
+#if 0
+/* new interfaces for path-based clipping */
+cairo_private cairo_status_t
+_cairo_surface_can_clip_path (cairo_surface_t	*surface)
 {
-    return _cairo_surface_set_clip_region_internal (surface, region, TRUE, TRUE);
 }
 
+cairo_private cairo_status_t
+_cairo_surface_clip_path (cairo_surface_t	*surface,
+			  cairo_path_fixed_t	*path,
+			  unsigned int		serial)
+{
+    surface->current_clip_serial = clip_serial;
+    return surface->backend->clip_path (surface, path);
+}
+#endif
+
+/**
+ * _cairo_surface_get_extents:
+ * @surface: the #cairo_surface_t to fetch extents for
+ *
+ * This function returns a bounding box for the surface.  The
+ * surface bounds are defined as a region beyond which no
+ * rendering will possibly be recorded, in otherwords, 
+ * it is the maximum extent of potentially usable
+ * coordinates.  For simple pixel-based surfaces,
+ * it can be a close bound on the retained pixel
+ * region.  For virtual surfaces (PDF et al), it
+ * cannot and must extend to the reaches of the
+ * target system coordinate space.
+ */
+
 cairo_status_t
-_cairo_surface_get_clip_extents (cairo_surface_t   *surface,
-				 cairo_rectangle_t *rectangle)
+_cairo_surface_get_extents (cairo_surface_t   *surface,
+			    cairo_rectangle_t *rectangle)
 {
     if (surface->finished)
 	return CAIRO_STATUS_SURFACE_FINISHED;
 
-    if (surface->clip_region) {
-	pixman_box16_t *box = pixman_region_extents (surface->clip_region);
-
-	rectangle->x = box->x1;
-	rectangle->y = box->y1;
-	rectangle->width  = box->x2 - box->x1;
-	rectangle->height = box->y2 - box->y1;
-	
-	return CAIRO_STATUS_SUCCESS;
-    }
-
     return surface->backend->get_extents (surface, rectangle);
 }
 

Index: cairo-xcb-surface.c
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo-xcb-surface.c,v
retrieving revision 1.29
retrieving revision 1.30
diff -u -d -r1.29 -r1.30
--- cairo-xcb-surface.c	17 May 2005 22:23:54 -0000	1.29
+++ cairo-xcb-surface.c	26 May 2005 18:35:46 -0000	1.30
@@ -1016,7 +1016,7 @@
     _cairo_xcb_surface_composite_trapezoids,
     NULL, /* copy_page */
     NULL, /* show_page */
-    _cairo_xcb_surface_set_clip_region,
+    NULL, /* _cairo_xcb_surface_set_clip_region */
     _cairo_xcb_surface_get_extents,
     NULL /* show_glyphs */
 };

Index: cairo-xlib-surface.c
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo-xlib-surface.c,v
retrieving revision 1.72
retrieving revision 1.73
diff -u -d -r1.72 -r1.73
--- cairo-xlib-surface.c	17 May 2005 19:21:56 -0000	1.72
+++ cairo-xlib-surface.c	26 May 2005 18:35:46 -0000	1.73
@@ -46,7 +46,14 @@
 
 typedef struct _cairo_xlib_surface cairo_xlib_surface_t;
 
-static void _cairo_xlib_surface_ensure_gc (cairo_xlib_surface_t *surface);
+static void
+_cairo_xlib_surface_ensure_gc (cairo_xlib_surface_t *surface);
+
+static void 
+_cairo_xlib_surface_ensure_src_picture (cairo_xlib_surface_t *surface);
+
+static void 
+_cairo_xlib_surface_ensure_dst_picture (cairo_xlib_surface_t *surface);
 
 /*
  * Instead of taking two round trips for each blending request,
@@ -74,7 +81,8 @@
     int height;
     int depth;
 
-    Picture picture;
+    Picture dst_picture, src_picture;
+
     XRenderPictFormat *format;
 };
 
@@ -197,8 +205,11 @@
 _cairo_xlib_surface_finish (void *abstract_surface)
 {
     cairo_xlib_surface_t *surface = abstract_surface;
-    if (surface->picture)
-	XRenderFreePicture (surface->dpy, surface->picture);
+    if (surface->dst_picture)
+	XRenderFreePicture (surface->dpy, surface->dst_picture);
+    
+    if (surface->src_picture)
+	XRenderFreePicture (surface->dpy, surface->src_picture);
 
     if (surface->owns_pixmap)
 	XFreePixmap (surface->dpy, surface->drawable);
@@ -433,6 +444,26 @@
 }
 
 static void
+_cairo_xlib_surface_ensure_src_picture (cairo_xlib_surface_t    *surface)
+{
+    if (!surface->src_picture)
+	surface->src_picture = XRenderCreatePicture (surface->dpy, 
+						     surface->drawable, 
+						     surface->format,
+						     0, NULL);
+}
+	
+static void
+_cairo_xlib_surface_ensure_dst_picture (cairo_xlib_surface_t    *surface)
+{
+    if (!surface->dst_picture)
+	surface->dst_picture = XRenderCreatePicture (surface->dpy, 
+						     surface->drawable, 
+						     surface->format,
+						     0, NULL);
+}
+	
+static void
 _cairo_xlib_surface_ensure_gc (cairo_xlib_surface_t *surface)
 {
     XGCValues gcv;
@@ -588,7 +619,7 @@
 {
     XTransform xtransform;
 
-    if (!surface->picture)
+    if (!surface->src_picture)
 	return CAIRO_STATUS_SUCCESS;
     
     xtransform.matrix[0][0] = _cairo_fixed_from_double (matrix->xx);
@@ -617,7 +648,7 @@
 	return CAIRO_INT_STATUS_UNSUPPORTED;
     }
 
-    XRenderSetPictureTransform (surface->dpy, surface->picture, &xtransform);
+    XRenderSetPictureTransform (surface->dpy, surface->src_picture, &xtransform);
 
     return CAIRO_STATUS_SUCCESS;
 }
@@ -628,7 +659,7 @@
 {
     char *render_filter;
 
-    if (!surface->picture)
+    if (!surface->src_picture)
 	return CAIRO_STATUS_SUCCESS;
 
     if (!CAIRO_SURFACE_RENDER_HAS_FILTERS (surface))
@@ -660,7 +691,7 @@
 	break;
     }
 
-    XRenderSetPictureFilter (surface->dpy, surface->picture,
+    XRenderSetPictureFilter (surface->dpy, surface->src_picture,
 			     render_filter, NULL, 0);
 
     return CAIRO_STATUS_SUCCESS;
@@ -672,13 +703,13 @@
     XRenderPictureAttributes pa;
     unsigned long	     mask;
 
-    if (!surface->picture)
+    if (!surface->src_picture)
 	return CAIRO_STATUS_SUCCESS;
     
     mask = CPRepeat;
     pa.repeat = repeat;
 
-    XRenderChangePicture (surface->dpy, surface->picture, mask, &pa);
+    XRenderChangePicture (surface->dpy, surface->src_picture, mask, &pa);
 
     return CAIRO_STATUS_SUCCESS;
 }
@@ -689,6 +720,8 @@
 {
     cairo_int_status_t status;
 
+    _cairo_xlib_surface_ensure_src_picture (surface);
+
     status = _cairo_xlib_surface_set_matrix (surface, &attributes->matrix);
     if (status)
 	return status;
@@ -786,15 +819,17 @@
 	return status;
     
     status = _cairo_xlib_surface_set_attributes (src, &src_attr);
+
     if (CAIRO_OK (status)) {
+	_cairo_xlib_surface_ensure_dst_picture (dst);
 	if (mask) {
 	    status = _cairo_xlib_surface_set_attributes (mask, &mask_attr);
 	    if (CAIRO_OK (status))
 		XRenderComposite (dst->dpy,
 				  _render_operator (operator),
-				  src->picture,
-				  mask->picture,
-				  dst->picture,
+				  src->src_picture,
+				  mask->src_picture,
+				  dst->dst_picture,
 				  src_x + src_attr.x_offset,
 				  src_y + src_attr.y_offset,
 				  mask_x + mask_attr.x_offset,
@@ -804,9 +839,9 @@
 	} else {
 	    XRenderComposite (dst->dpy,
 			      _render_operator (operator),
-			      src->picture,
+			      src->src_picture,
 			      0,
-			      dst->picture,
+			      dst->dst_picture,
 			      src_x + src_attr.x_offset,
 			      src_y + src_attr.y_offset,
 			      0, 0,
@@ -842,9 +877,10 @@
     render_color.alpha = color->alpha_short;
 
     /* XXX: This XRectangle cast is evil... it needs to go away somehow. */
+    _cairo_xlib_surface_ensure_dst_picture (surface);
     XRenderFillRectangles (surface->dpy,
 			   _render_operator (operator),
-			   surface->picture,
+			   surface->dst_picture,
 			   &render_color, (XRectangle *) rects, num_rects);
 
     return CAIRO_STATUS_SUCCESS;
@@ -892,11 +928,12 @@
     render_src_y = src_y + render_reference_y - dst_y;
 
     /* XXX: The XTrapezoid cast is evil and needs to go away somehow. */
+    _cairo_xlib_surface_ensure_dst_picture (dst);
     status = _cairo_xlib_surface_set_attributes (src, &attributes);
     if (CAIRO_OK (status))
 	XRenderCompositeTrapezoids (dst->dpy,
 				    _render_operator (operator),
-				    src->picture, dst->picture,
+				    src->src_picture, dst->dst_picture,
 				    XRenderFindStandardFormat (dst->dpy, PictStandardA8),
 				    render_src_x + attributes.x_offset, 
 				    render_src_y + attributes.y_offset,
@@ -917,10 +954,11 @@
 	if (surface->gc)
 	    XSetClipMask (surface->dpy, surface->gc, None);
 	
-	if (surface->picture) {
+	if (surface->format) {
 	    XRenderPictureAttributes pa;
 	    pa.clip_mask = None;
-	    XRenderChangePicture (surface->dpy, surface->picture,
+	    _cairo_xlib_surface_ensure_dst_picture (surface);
+	    XRenderChangePicture (surface->dpy, surface->dst_picture,
 				  CPClipMask, &pa);
 	}
     } else {
@@ -949,9 +987,11 @@
 	if (surface->gc)
 	    XSetClipRectangles(surface->dpy, surface->gc,
 			       0, 0, rects, n_boxes, YXSorted);
-	if (surface->picture)
-	    XRenderSetPictureClipRectangles (surface->dpy, surface->picture,
+	if (surface->format) {
+	    _cairo_xlib_surface_ensure_dst_picture (surface);
+	    XRenderSetPictureClipRectangles (surface->dpy, surface->dst_picture,
 					     0, 0, rects, n_boxes);
+	}
 
 	if (rects)
 	    free (rects);
@@ -1043,15 +1083,12 @@
     surface->gc = NULL;
     surface->drawable = drawable;
     surface->owns_pixmap = FALSE;
-    surface->visual = visual;
-    surface->format = format;
     surface->use_pixmap = 0;
     surface->width = width;
     surface->height = height;
-    surface->depth = depth;
     
     if (format) {
-	surface->depth = format->depth;
+	depth = format->depth;
     } else if (visual) {
 	int i, j, k;
 
@@ -1061,10 +1098,10 @@
 	for (i = 0; i < ScreenCount (dpy); i++) {
 	    Screen *screen = ScreenOfDisplay (dpy, i);
 	    for (j = 0; j < screen->ndepths; j++) {
-		Depth *depth = &screen->depths[j];
-		for (k = 0; k < depth->nvisuals; k++) {
-		    if (&depth->visuals[k] == visual) {
-			surface->depth = depth->depth;
+		Depth *d = &screen->depths[j];
+		for (k = 0; k < d->nvisuals; k++) {
+		    if (&d->visuals[k] == visual) {
+			depth = d->depth;
 			goto found;
 		    }
 		}
@@ -1080,21 +1117,22 @@
 	surface->render_minor = -1;
     }
 
-    surface->picture = None;
+    surface->dst_picture = None;
+    surface->src_picture = None;
 
     if (CAIRO_SURFACE_RENDER_HAS_CREATE_PICTURE (surface)) {
-
 	if (!format) {
 	    if (visual) {
 		format = XRenderFindVisualFormat (dpy, visual);
 	    } else if (depth == 1)
 		format = XRenderFindStandardFormat (dpy, PictStandardA1);
 	}
+    } else
+	format = NULL;
 
-	if (format)
-	    surface->picture = XRenderCreatePicture (dpy, drawable,
-						     format, 0, NULL);
-    }
+    surface->visual = visual;
+    surface->format = format;
+    surface->depth = depth;
 
     return (cairo_surface_t *) surface;
 }
@@ -1479,8 +1517,8 @@
 
     XRenderCompositeText32 (self->dpy,
 			    _render_operator (operator),
-			    src->picture,
-			    self->picture,
+			    src->src_picture,
+			    self->dst_picture,
 			    g->a8_pict_format,
 			    source_x, source_y,
 			    0, 0,
@@ -1556,8 +1594,8 @@
 
     XRenderCompositeText16 (self->dpy,
 			    _render_operator (operator),
-			    src->picture,
-			    self->picture,
+			    src->src_picture,
+			    self->dst_picture,
 			    g->a8_pict_format,
 			    source_x, source_y,
 			    0, 0,
@@ -1632,8 +1670,8 @@
 
     XRenderCompositeText8 (self->dpy,
 			   _render_operator (operator),
-			   src->picture,
-			   self->picture,
+			   src->src_picture,
+			   self->dst_picture,
 			   g->a8_pict_format,
 			   source_x, source_y,
 			   0, 0,
@@ -1680,7 +1718,7 @@
     glyphset_cache_entry_t *stack_entries [N_STACK_BUF];
     int i;
 
-    if (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE_TEXT (self))
+    if (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE_TEXT (self) || !self->format)
 	return CAIRO_INT_STATUS_UNSUPPORTED;
 
     status = _cairo_pattern_acquire_surface (pattern, &self->base,
@@ -1738,6 +1776,7 @@
 
     /* Call the appropriate sub-function. */
 
+    _cairo_xlib_surface_ensure_dst_picture (self);
     if (elt_size == 8)
 	status = _cairo_xlib_surface_show_glyphs8 (scaled_font, operator, g, &key, src, self,
 						   source_x + attributes.x_offset,

Index: cairo.c
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo.c,v
retrieving revision 1.97
retrieving revision 1.98
diff -u -d -r1.97 -r1.98
--- cairo.c	26 May 2005 10:31:28 -0000	1.97
+++ cairo.c	26 May 2005 18:35:46 -0000	1.98
@@ -2163,8 +2163,6 @@
 	return "the target surface has been finished";
     case CAIRO_STATUS_SURFACE_TYPE_MISMATCH:
 	return "the surface type is not appropriate for the operation";
-    case CAIRO_STATUS_BAD_NESTING:
-	return "drawing operations interleaved for two contexts for the same surface";
     }
 
     return "<unknown error status>";

Index: cairo.h
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo.h,v
retrieving revision 1.121
retrieving revision 1.122
diff -u -d -r1.121 -r1.122
--- cairo.h	17 May 2005 15:34:44 -0000	1.121
+++ cairo.h	26 May 2005 18:35:46 -0000	1.122
@@ -130,6 +130,7 @@
  * @CAIRO_STATUS_NO_MEMORY: 
  * @CAIRO_STATUS_INVALID_RESTORE:
  * @CAIRO_STATUS_INVALID_POP_GROUP:
+ * @CAIRO_STATUS_NO_CURRENT_POINT:
  * @CAIRO_STATUS_INVALID_MATRIX:
  * @CAIRO_STATUS_NO_TARGET_SURFACE:
  * @CAIRO_STATUS_NULL_POINTER:
@@ -139,11 +140,6 @@
  * @CAIRO_STATUS_WRITE_ERROR:
  * @CAIRO_STATUS_SURFACE_FINISHED:
  * @CAIRO_STATUS_SURFACE_TYPE_MISMATCH:
- * @CAIRO_STATUS_BAD_NESTING: the same surface was used as the
- *  target surface for two different cairo contexts at once,
- *  and more drawing was done on the first context before the
- *  surface was unset as the target for the second context.
- *  See the documentation for cairo_create().
  *
  * #cairo_status_t is used to indicate errors that can occur when
  * using Cairo. In some cases it is returned directly by functions.
@@ -165,7 +161,6 @@
     CAIRO_STATUS_WRITE_ERROR,
     CAIRO_STATUS_SURFACE_FINISHED,
     CAIRO_STATUS_SURFACE_TYPE_MISMATCH,
-    CAIRO_STATUS_BAD_NESTING
 } cairo_status_t;
 
 /**

Index: cairoint.h
===================================================================
RCS file: /cvs/cairo/cairo/src/cairoint.h,v
retrieving revision 1.143
retrieving revision 1.144
diff -u -d -r1.143 -r1.144
--- cairoint.h	17 May 2005 12:58:02 -0000	1.143
+++ cairoint.h	26 May 2005 18:35:46 -0000	1.144
@@ -699,8 +699,6 @@
     unsigned long blue_mask;
 } cairo_format_masks_t;
 
-typedef struct _cairo_surface_save cairo_surface_save_t;
-
 struct _cairo_surface {
     const cairo_surface_backend_t *backend;
 
@@ -715,10 +713,21 @@
     double device_x_offset;
     double device_y_offset;
 
-    cairo_surface_save_t *saves; /* Stack of saved states from cairo_surface_begin/end() */
-    int level;			 /* Number saved states */
-  
-    pixman_region16_t *clip_region;
+    /*
+     * Each time a clip region is modified, it gets the next value in this
+     * sequence.  This means that clip regions for this surface are uniquely
+     * identified andupdates to the clip can be readily identified
+     */
+    unsigned int next_clip_serial;
+    /*
+     * The serial number of the current clip.  This is set when
+     * the surface clipping is set.  The gstate can then cheaply
+     * check whether the surface clipping is already correct before
+     * performing a rendering operation.
+     *
+     * The special value '0' is reserved for the unclipped case.
+     */
+    unsigned int current_clip_serial;
 };
 
 struct _cairo_image_surface {
@@ -840,7 +849,6 @@
     int		   x_offset;
     int		   y_offset;
     cairo_bool_t   acquired;
-    cairo_bool_t   clip_saved;
     void	   *extra;
 } cairo_surface_attributes_t;
 
@@ -880,13 +888,6 @@
 #define CAIRO_GSTATE_MITER_LIMIT_DEFAULT	10.0
 #define CAIRO_GSTATE_DEFAULT_FONT_SIZE  10.0
 
-/* Need a name distinct from the cairo_clip function */
-typedef struct _cairo_clip_rec {
-    cairo_rectangle_t rect;
-    pixman_region16_t *region;
-    cairo_surface_t *surface;
-} cairo_clip_rec_t;
-
 typedef struct _cairo_gstate cairo_gstate_t;
 
 typedef struct _cairo_stroke_face {
@@ -1378,7 +1379,7 @@
 				   cairo_gstate_t     *gstate,
 				   cairo_traps_t      *traps);
 
-/* cairo_surface.c */
+/* cairo-surface.c */
 cairo_private cairo_surface_t *
 _cairo_surface_create_similar_scratch (cairo_surface_t	*other,
 				       cairo_format_t	format,
@@ -1398,15 +1399,6 @@
 		     const cairo_surface_backend_t	*backend);
 
 cairo_private cairo_status_t
-_cairo_surface_begin (cairo_surface_t *surface);
-
-cairo_private cairo_status_t
-_cairo_surface_begin_reset_clip (cairo_surface_t *surface);
-
-cairo_private cairo_status_t
-_cairo_surface_end (cairo_surface_t *surface);
-
-cairo_private cairo_status_t
 _cairo_surface_fill_rectangle (cairo_surface_t	   *surface,
 			       cairo_operator_t	    operator,
 			       const cairo_color_t *color,
@@ -1490,13 +1482,37 @@
 			      cairo_surface_t  *src,
 			      cairo_surface_t **clone_out);
 
+cairo_private unsigned int
+_cairo_surface_get_current_clip_serial (cairo_surface_t *surface);
+
+cairo_private unsigned int
+_cairo_surface_allocate_clip_serial (cairo_surface_t *surface);
+
 cairo_private cairo_status_t
-_cairo_surface_set_clip_region (cairo_surface_t   *surface,
-				pixman_region16_t *region);
+_cairo_surface_reset_clip (cairo_surface_t *surface);
 
 cairo_private cairo_status_t
-_cairo_surface_get_clip_extents (cairo_surface_t   *surface,
-				 cairo_rectangle_t *rectangle);
+_cairo_surface_can_clip_region (cairo_surface_t    *surface);
+
+cairo_private cairo_status_t
+_cairo_surface_set_clip_region (cairo_surface_t	    *surface,
+				pixman_region16_t   *region,
+				unsigned int	    serial);
+
+#if 0
+/* new interfaces for path-based clipping */
+cairo_private cairo_status_t
+_cairo_surface_can_clip_path (cairo_surface_t	*surface);
+
+cairo_private cairo_status_t
+_cairo_surface_clip_path (cairo_surface_t	*surface,
+			  cairo_path_fixed_t	*path,
+			  unsigned int		serial);
+#endif
+
+cairo_private cairo_status_t
+_cairo_surface_get_extents (cairo_surface_t   *surface,
+			    cairo_rectangle_t *rectangle);
 
 cairo_private cairo_status_t
 _cairo_surface_show_glyphs (cairo_scaled_font_t	        *scaled_font,




More information about the cairo-commit mailing list