[cairo-commit] cairo/src cairo-glitz-surface.c, 1.45, 1.46 cairo-gstate-private.h, 1.11, 1.12 cairo-gstate.c, 1.141, 1.142 cairo-image-surface.c, 1.45, 1.46 cairo-pdf-surface.c, 1.45, 1.46 cairo-ps-surface.c, 1.36, 1.37 cairo-quartz-surface.c, 1.11, 1.12 cairo-surface.c, 1.73, 1.74 cairo-win32-surface.c, 1.25, 1.26 cairo-xcb-surface.c, 1.35, 1.36 cairo-xlib-surface.c, 1.78, 1.79 cairoint.h, 1.154, 1.155

Kristian Hogsberg commit at pdx.freedesktop.org
Tue Jun 14 19:45:25 PDT 2005


Committed by: krh

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

Modified Files:
	cairo-glitz-surface.c cairo-gstate-private.h cairo-gstate.c 
	cairo-image-surface.c cairo-pdf-surface.c cairo-ps-surface.c 
	cairo-quartz-surface.c cairo-surface.c cairo-win32-surface.c 
	cairo-xcb-surface.c cairo-xlib-surface.c cairoint.h 
Log Message:
2005-06-14  Kristian Høgsberg  <krh at redhat.com>

        * src/cairo-gstate-private.h:
        * src/cairo-gstate.c: (_cairo_gstate_init),
        (_cairo_gstate_init_copy), (_cairo_gstate_fini),
        (_cairo_gstate_set_clip), (_composite_trap_region),
        (_cairo_gstate_fill), (_cairo_gstate_reset_clip),
        (_cairo_gstate_intersect_clip_path), (_cairo_clip_path_reference),
        (_cairo_clip_path_destroy), (_cairo_gstate_intersect_clip_region),
        (_cairo_gstate_intersect_clip_mask), (_cairo_gstate_clip):
        * src/cairo-pdf-surface.c:
        (_cairo_pdf_surface_create_for_document),
        (_cairo_pdf_path_move_to), (_cairo_pdf_path_line_to),
        (_cairo_pdf_path_close_path), (_cairo_pdf_surface_fill_path),
        (_cairo_pdf_surface_intersect_clip_path),
        (_cairo_pdf_document_add_page):
        * src/cairo-surface.c: (_cairo_surface_get_clip_mode),
        (_cairo_surface_fill_path), (_cairo_surface_reset_clip),
        (_cairo_surface_set_clip_path_recursive),
        (_cairo_surface_set_clip_path):
        * src/cairoint.h: Implement path clipping and refactor
        _cairo_gstate_clip() out in three different functions
        corresponding to the three different clipping modes.

        * src/cairo-glitz-surface.c:
        * src/cairo-ps-surface.c:
        * src/cairo-win32-surface.c:
        * src/cairo-xcb-surface.c:
        * src/cairo-xlib-surface.c:
        * src/cairo-image-surface.c:
        * src/cairo-quartz-surface.c: Add NULL pointers for
        intersect_clip_path.

        * test/Makefile.am:
        * test/pdf-clip.c: New test case to exercise PDF clipping code.


Index: cairo-glitz-surface.c
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo-glitz-surface.c,v
retrieving revision 1.45
retrieving revision 1.46
diff -u -d -r1.45 -r1.46
--- cairo-glitz-surface.c	14 Jun 2005 22:38:15 -0000	1.45
+++ cairo-glitz-surface.c	15 Jun 2005 02:45:23 -0000	1.46
@@ -2132,6 +2132,7 @@
     NULL, /* copy_page */
     NULL, /* show_page */
     _cairo_glitz_surface_set_clip_region,
+    NULL, /* intersect_clip_path */
     _cairo_glitz_surface_get_extents,
     _cairo_glitz_surface_show_glyphs
 };

Index: cairo-gstate-private.h
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo-gstate-private.h,v
retrieving revision 1.11
retrieving revision 1.12
diff -u -d -r1.11 -r1.12
--- cairo-gstate-private.h	3 Jun 2005 22:54:40 -0000	1.11
+++ cairo-gstate-private.h	15 Jun 2005 02:45:23 -0000	1.12
@@ -36,7 +36,19 @@
 #ifndef CAIRO_GSTATE_PRIVATE_H
 #define CAIRO_GSTATE_PRIVATE_H
 
+#include "cairo-path-fixed-private.h"
+
+struct _cairo_clip_path {
+    unsigned int	ref_count;
+    cairo_path_fixed_t	path;
+    cairo_fill_rule_t	fill_rule;
+    double		tolerance;
+    cairo_clip_path_t	*prev;
+};
+
 typedef struct _cairo_clip {
+    cairo_clip_mode_t mode;
+
     /*
      * Mask-based clipping for cases where the backend 
      * clipping isn't sufficiently able.
@@ -59,8 +71,10 @@
      */
     pixman_region16_t *region;
     /*
-     * XXX add clip paths here
+     * If the surface supports path clipping, we store the list of
+     * clipping paths that has been set here as a linked list.
      */
+    cairo_clip_path_t *path;
 } cairo_clip_t;
 
 struct _cairo_gstate {

Index: cairo-gstate.c
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo-gstate.c,v
retrieving revision 1.141
retrieving revision 1.142
diff -u -d -r1.141 -r1.142
--- cairo-gstate.c	13 Jun 2005 23:36:40 -0000	1.141
+++ cairo-gstate.c	15 Jun 2005 02:45:23 -0000	1.142
@@ -70,6 +70,12 @@
 static void
 _cairo_rectangle_intersect (cairo_rectangle_t *dest, cairo_rectangle_t *src);
 
+static void
+_cairo_clip_path_reference (cairo_clip_path_t *clip_path);
+
+static void
+_cairo_clip_path_destroy (cairo_clip_path_t *clip_path);
+
 cairo_gstate_t *
 _cairo_gstate_create (cairo_surface_t *target)
 {
@@ -116,9 +122,11 @@
 			     CAIRO_GSTATE_DEFAULT_FONT_SIZE, 
 			     CAIRO_GSTATE_DEFAULT_FONT_SIZE);
     
+    gstate->clip.mode = _cairo_surface_get_clip_mode (target);
     gstate->clip.region = NULL;
     gstate->clip.surface = NULL;
     gstate->clip.serial = 0;
+    gstate->clip.path = NULL;
 
     _cairo_gstate_identity_matrix (gstate);
 
@@ -168,6 +176,7 @@
     
     cairo_surface_reference (gstate->target);
     cairo_surface_reference (gstate->clip.surface);
+    _cairo_clip_path_reference (gstate->clip.path);
 
     cairo_pattern_reference (gstate->source);
     
@@ -205,6 +214,10 @@
 	cairo_surface_destroy (gstate->clip.surface);
     gstate->clip.surface = NULL;
 
+    if (gstate->clip.path)
+	_cairo_clip_path_destroy (gstate->clip.path);
+    gstate->clip.path = NULL;
+
     if (gstate->clip.region)
 	pixman_region_destroy (gstate->clip.region);
     gstate->clip.region = NULL;
@@ -338,7 +351,10 @@
     if (gstate->clip.serial == _cairo_surface_get_current_clip_serial (surface))
 	return CAIRO_STATUS_SUCCESS;
     
-    /* check for path clipping here */
+    if (gstate->clip.path)
+	return _cairo_surface_set_clip_path (surface,
+					     gstate->clip.path,
+					     gstate->clip.serial);
     
     if (gstate->clip.region)
 	return _cairo_surface_set_clip_region (surface, 
@@ -1142,9 +1158,8 @@
     
     if (num_rects > 1) {
 	
-	status = _cairo_surface_can_clip_region (gstate->target);
-	if (status)
-	    return status;
+	if (gstate->clip.mode != CAIRO_CLIP_MODE_REGION)
+	    return CAIRO_INT_STATUS_UNSUPPORTED;
 	
 	clip_serial = _cairo_surface_allocate_clip_serial (gstate->target);
 	status = _cairo_surface_set_clip_region (gstate->target, 
@@ -1438,7 +1453,9 @@
     status = _cairo_surface_fill_path (gstate->operator,
 				       gstate->source,
 				       gstate->target,
-				       path);
+				       path,
+				       gstate->fill_rule,
+				       gstate->tolerance);
     
     if (status != CAIRO_INT_STATUS_UNSUPPORTED)
 	return status;
@@ -1583,83 +1600,124 @@
     if (gstate->clip.region)
 	pixman_region_destroy (gstate->clip.region);
     gstate->clip.region = NULL;
+
+    if (gstate->clip.path)
+	_cairo_clip_path_destroy (gstate->clip.path);
+    gstate->clip.path = NULL;
+
     gstate->clip.serial = 0;
     
     return CAIRO_STATUS_SUCCESS;
 }
 
-cairo_status_t
-_cairo_gstate_clip (cairo_gstate_t *gstate, cairo_path_fixed_t *path)
+static cairo_status_t
+_cairo_gstate_intersect_clip_path (cairo_gstate_t     *gstate,
+				   cairo_path_fixed_t *path)
 {
+    cairo_clip_path_t *clip_path;
     cairo_status_t status;
-    cairo_pattern_union_t pattern;
-    cairo_traps_t traps;
-    cairo_rectangle_t surface_rect;
-    cairo_box_t extents;
-    cairo_surface_t *surface;
-    pixman_region16_t *region;
 
-    /* Fill the clip region as traps. */
+    if (gstate->clip.mode != CAIRO_CLIP_MODE_PATH)
+	return CAIRO_INT_STATUS_UNSUPPORTED;
 
-    _cairo_traps_init (&traps);
-    status = _cairo_path_fixed_fill_to_traps (path, gstate, &traps);
-    if (status) {
-	_cairo_traps_fini (&traps);
+    clip_path = malloc (sizeof (cairo_clip_path_t));
+    if (clip_path == NULL)
+	return CAIRO_STATUS_NO_MEMORY;
+
+    status = _cairo_path_fixed_init_copy (&clip_path->path, path);
+    if (status)
 	return status;
-    }
 
-    status = _cairo_surface_can_clip_region (gstate->target);
-    
-    if (status != CAIRO_INT_STATUS_UNSUPPORTED) {
-	if (status)
-	    return status;
-    
-	/* Check to see if we can represent these traps as a PixRegion. */
+    clip_path->ref_count = 1;
+    clip_path->fill_rule = gstate->fill_rule;
+    clip_path->tolerance = gstate->tolerance;
+    clip_path->prev = gstate->clip.path;
+    gstate->clip.path = clip_path;
+    gstate->clip.serial = _cairo_surface_allocate_clip_serial (gstate->target);
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static void
+_cairo_clip_path_reference (cairo_clip_path_t *clip_path)
+{
+    if (clip_path == NULL)
+	return;
+
+    clip_path->ref_count++;
+}
+
+static void
+_cairo_clip_path_destroy (cairo_clip_path_t *clip_path)
+{
+    if (clip_path == NULL)
+	return;
+
+    clip_path->ref_count--;
+    if (clip_path->ref_count)
+	return;
+
+    _cairo_path_fixed_fini (&clip_path->path);
+    _cairo_clip_path_destroy (clip_path->prev);
+    free (clip_path);
+}
+
+static cairo_status_t
+_cairo_gstate_intersect_clip_region (cairo_gstate_t *gstate,
+				     cairo_traps_t  *traps)
+{
+    pixman_region16_t *region;
+    cairo_status_t status;
+
+    if (gstate->clip.mode != CAIRO_CLIP_MODE_REGION)
+	return CAIRO_INT_STATUS_UNSUPPORTED;
     
-	status = _cairo_traps_extract_region (&traps, &region);
-	if (status) {
-	    _cairo_traps_fini (&traps);
-	    return status;
-	}
+    status = _cairo_traps_extract_region (traps, &region);
+    if (status)
+	return status;
 	
-	if (region) {
-	    status = CAIRO_STATUS_SUCCESS;
-	    
-	    if (gstate->clip.region == NULL) {
-		gstate->clip.region = region;
-	    } else {
-		pixman_region16_t *intersection = pixman_region_create();
+    if (region == NULL)
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+
+    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);
-	    }
-	    gstate->clip.serial = _cairo_surface_allocate_clip_serial (gstate->target);
-	    
-	    _cairo_traps_fini (&traps);
-	    
-	    return status;
+	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);
     }
+    gstate->clip.serial = _cairo_surface_allocate_clip_serial (gstate->target);
+    return status;
+}
 
-    /* Otherwise represent the clip as a mask surface.  We create a
-     * new surface the size of the intersection of the old mask
-     * surface and the extents of the new clip path. */
+static cairo_status_t
+_cairo_gstate_intersect_clip_mask (cairo_gstate_t *gstate,
+				   cairo_traps_t  *traps)
+{
+    cairo_pattern_union_t pattern;
+    cairo_box_t extents;
+    cairo_rectangle_t surface_rect;
+    cairo_surface_t *surface;
+    cairo_status_t status;
 
-    if (gstate->clip.surface == NULL) {
-	_cairo_traps_extents (&traps, &extents);
-	_cairo_box_round_to_rectangle (&extents, &surface_rect);
-    } else {
-	_cairo_traps_extents (&traps, &extents); 
-	_cairo_box_round_to_rectangle (&extents, &surface_rect);
+    /* Represent the clip as a mask surface.  We create a new surface
+     * the size of the intersection of the old mask surface and the
+     * extents of the new clip path. */
+
+    _cairo_traps_extents (traps, &extents);
+    _cairo_box_round_to_rectangle (&extents, &surface_rect);
+
+    if (gstate->clip.surface != NULL)
 	_cairo_rectangle_intersect (&surface_rect, &gstate->clip.surface_rect);
-    }
 
     surface = _cairo_surface_create_similar_solid (gstate->target,
 						   CAIRO_FORMAT_A8,
@@ -1671,7 +1729,7 @@
 
     /* Render the new clipping path into the new mask surface. */
 
-    translate_traps (&traps, -surface_rect.x, -surface_rect.y);
+    translate_traps (traps, -surface_rect.x, -surface_rect.y);
     _cairo_pattern_init_solid (&pattern.solid, CAIRO_COLOR_WHITE);
     
     status = _cairo_surface_composite_trapezoids (CAIRO_OPERATOR_IN,
@@ -1681,11 +1739,10 @@
 						  0, 0,
 						  surface_rect.width,
 						  surface_rect.height,
-						  traps.traps,
-						  traps.num_traps);
+						  traps->traps,
+						  traps->num_traps);
 
     _cairo_pattern_fini (&pattern.base);
-    _cairo_traps_fini (&traps);
 
     if (status) {
 	cairo_surface_destroy (surface);
@@ -1723,7 +1780,34 @@
     gstate->clip.surface = surface;
     gstate->clip.surface_rect = surface_rect;
 
-    return CAIRO_STATUS_SUCCESS;
+    return status;
+}
+
+cairo_status_t
+_cairo_gstate_clip (cairo_gstate_t *gstate, cairo_path_fixed_t *path)
+{
+    cairo_status_t status;
+    cairo_traps_t traps;
+    
+    status = _cairo_gstate_intersect_clip_path (gstate, path);
+    if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+	return status;
+
+    _cairo_traps_init (&traps);
+    status = _cairo_path_fixed_fill_to_traps (path, gstate, &traps);
+    if (status)
+	goto bail;
+
+    status = _cairo_gstate_intersect_clip_region (gstate, &traps);
+    if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+	goto bail;
+
+    status = _cairo_gstate_intersect_clip_mask (gstate, &traps);
+	
+ bail:
+    _cairo_traps_fini (&traps);
+
+    return status;
 }
 
 static void

Index: cairo-image-surface.c
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo-image-surface.c,v
retrieving revision 1.45
retrieving revision 1.46
diff -u -d -r1.45 -r1.46
--- cairo-image-surface.c	14 Jun 2005 22:38:15 -0000	1.45
+++ cairo-image-surface.c	15 Jun 2005 02:45:23 -0000	1.46
@@ -713,6 +713,7 @@
     NULL, /* copy_page */
     NULL, /* show_page */
     _cairo_image_abstract_surface_set_clip_region,
+    NULL, /* intersect_clip_path */
     _cairo_image_abstract_surface_get_extents,
     NULL /* show_glyphs */
 };

Index: cairo-pdf-surface.c
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo-pdf-surface.c,v
retrieving revision 1.45
retrieving revision 1.46
diff -u -d -r1.45 -r1.46
--- cairo-pdf-surface.c	14 Jun 2005 22:38:15 -0000	1.45
+++ cairo-pdf-surface.c	15 Jun 2005 02:45:23 -0000	1.46
@@ -188,6 +188,7 @@
     cairo_array_t streams;
     cairo_array_t alphas;
     cairo_array_t fonts;
+    cairo_bool_t has_clip;
 };
 
 #define DEFAULT_DPI 300
@@ -989,6 +990,7 @@
     _cairo_array_init (&surface->xobjects, sizeof (cairo_pdf_resource_t));
     _cairo_array_init (&surface->alphas, sizeof (double));
     _cairo_array_init (&surface->fonts, sizeof (cairo_pdf_resource_t));
+    surface->has_clip = FALSE;
 
     return &surface->base;
 }
@@ -1638,6 +1640,7 @@
 typedef struct
 {
     cairo_output_stream_t *output_stream;
+    cairo_bool_t has_current_point;
 } pdf_path_info_t;
 
 static cairo_status_t
@@ -1649,6 +1652,7 @@
 				 "%f %f m ",
 				 _cairo_fixed_to_double (point->x),
 				 _cairo_fixed_to_double (point->y));
+    info->has_current_point = TRUE;
     
     return CAIRO_STATUS_SUCCESS;
 }
@@ -1657,11 +1661,19 @@
 _cairo_pdf_path_line_to (void *closure, cairo_point_t *point)
 {
     pdf_path_info_t *info = closure;
+    const char *pdf_operator;
+
+    if (info->has_current_point)
+	pdf_operator = "l";
+    else
+	pdf_operator = "m";
     
     _cairo_output_stream_printf (info->output_stream,
-				 "%f %f l ",
+				 "%f %f %s ",
 				 _cairo_fixed_to_double (point->x),
-				 _cairo_fixed_to_double (point->y));
+				 _cairo_fixed_to_double (point->y),
+				 pdf_operator);
+    info->has_current_point = TRUE;
 
     return CAIRO_STATUS_SUCCESS;
 }
@@ -1693,6 +1705,7 @@
     
     _cairo_output_stream_printf (info->output_stream,
 				 "h\r\n");
+    info->has_current_point = FALSE;
 
     return CAIRO_STATUS_SUCCESS;
 }
@@ -1701,15 +1714,16 @@
 _cairo_pdf_surface_fill_path (cairo_operator_t		operator,
 			      cairo_pattern_t		*pattern,
 			      void			*abstract_dst,
-			      cairo_path_fixed_t	*path)
+			      cairo_path_fixed_t	*path,
+			      cairo_fill_rule_t		fill_rule,
+			      double			tolerance)
 {
     cairo_pdf_surface_t *surface = abstract_dst;
     cairo_pdf_document_t *document = surface->document;
+    const char *pdf_operator;
     cairo_status_t status;
     pdf_path_info_t info;
 
-    return CAIRO_INT_STATUS_UNSUPPORTED;
-
     emit_pattern (surface, pattern);
 
     /* After the above switch the current stream should belong to this
@@ -1718,6 +1732,7 @@
 	    document->current_stream == surface->current_stream);
 
     info.output_stream = document->output_stream;
+    info.has_current_point = FALSE;
 
     status = _cairo_path_fixed_interpret (path,
 					  CAIRO_DIRECTION_FORWARD,
@@ -1727,8 +1742,20 @@
 					  _cairo_pdf_path_close_path,
 					  &info);
 
+    switch (fill_rule) {
+    case CAIRO_FILL_RULE_WINDING:
+	pdf_operator = "f";
+	break;
+    case CAIRO_FILL_RULE_EVEN_ODD:
+	pdf_operator = "f*";
+	break;
+    default:
+	ASSERT_NOT_REACHED;
+    }
+
     _cairo_output_stream_printf (document->output_stream,
-				 "f\r\n");
+				 "%s\r\n",
+				 pdf_operator);
 
     return status;
 }
@@ -1905,6 +1932,62 @@
     return CAIRO_STATUS_SUCCESS;
 }
 
+static cairo_int_status_t
+_cairo_pdf_surface_intersect_clip_path (void			*dst,
+					cairo_path_fixed_t	*path,
+					cairo_fill_rule_t	fill_rule,
+					double			tolerance)
+{
+    cairo_pdf_surface_t *surface = dst;
+    cairo_pdf_document_t *document = surface->document;
+    cairo_output_stream_t *output = document->output_stream;
+    cairo_status_t status;
+    pdf_path_info_t info;
+    const char *pdf_operator;
+
+    _cairo_pdf_surface_ensure_stream (surface);
+
+    if (path == NULL) {
+	if (surface->has_clip)
+	    _cairo_output_stream_printf (output, "Q\r\n");
+	surface->has_clip = FALSE;
+	return CAIRO_STATUS_SUCCESS;
+    }
+
+    if (!surface->has_clip) {
+	_cairo_output_stream_printf (output, "q ");
+	surface->has_clip = TRUE;
+    }
+
+    info.output_stream = document->output_stream;
+    info.has_current_point = FALSE;
+
+    status = _cairo_path_fixed_interpret (path,
+					  CAIRO_DIRECTION_FORWARD,
+					  _cairo_pdf_path_move_to,
+					  _cairo_pdf_path_line_to,
+					  _cairo_pdf_path_curve_to,
+					  _cairo_pdf_path_close_path,
+					  &info);
+
+    switch (fill_rule) {
+    case CAIRO_FILL_RULE_WINDING:
+	pdf_operator = "W";
+	break;
+    case CAIRO_FILL_RULE_EVEN_ODD:
+	pdf_operator = "W*";
+	break;
+    default:
+	ASSERT_NOT_REACHED;
+    }
+
+    _cairo_output_stream_printf (document->output_stream,
+				 "%s n\r\n",
+				 pdf_operator);
+
+    return status;
+}
+
 static const cairo_surface_backend_t cairo_pdf_surface_backend = {
     _cairo_pdf_surface_create_similar,
     _cairo_pdf_surface_finish,
@@ -1919,6 +2002,7 @@
     _cairo_pdf_surface_copy_page,
     _cairo_pdf_surface_show_page,
     NULL, /* set_clip_region */
+    _cairo_pdf_surface_intersect_clip_path,
     _cairo_pdf_surface_get_extents,
     _cairo_pdf_surface_show_glyphs,
     _cairo_pdf_surface_fill_path
@@ -2237,6 +2321,11 @@
 
     assert (!document->finished);
 
+    _cairo_pdf_surface_ensure_stream (surface);
+
+    if (surface->has_clip)
+	_cairo_output_stream_printf (output, "Q\r\n");
+
     _cairo_pdf_document_close_stream (document);
 
     page_id = _cairo_pdf_document_new_object (document);

Index: cairo-ps-surface.c
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo-ps-surface.c,v
retrieving revision 1.36
retrieving revision 1.37
diff -u -d -r1.36 -r1.37
--- cairo-ps-surface.c	14 Jun 2005 22:38:15 -0000	1.36
+++ cairo-ps-surface.c	15 Jun 2005 02:45:23 -0000	1.37
@@ -372,6 +372,7 @@
     _cairo_ps_surface_copy_page,
     _cairo_ps_surface_show_page,
     _cairo_ps_surface_set_clip_region,
+    NULL, /* intersect_clip_path */
     _cairo_ps_surface_get_extents,
     NULL /* show_glyphs */
 };

Index: cairo-quartz-surface.c
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo-quartz-surface.c,v
retrieving revision 1.11
retrieving revision 1.12
diff -u -d -r1.11 -r1.12
--- cairo-quartz-surface.c	14 Jun 2005 22:38:15 -0000	1.11
+++ cairo-quartz-surface.c	15 Jun 2005 02:45:23 -0000	1.12
@@ -226,6 +226,7 @@
     NULL, /* copy_page */
     NULL, /* show_page */
     _cairo_quartz_surface_set_clip_region,
+    NULL, /* intersect_clip_path */
     _cairo_quartz_surface_get_extents,
     NULL  /* show_glyphs */
 };

Index: cairo-surface.c
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo-surface.c,v
retrieving revision 1.73
retrieving revision 1.74
diff -u -d -r1.73 -r1.74
--- cairo-surface.c	14 Jun 2005 22:38:15 -0000	1.73
+++ cairo-surface.c	15 Jun 2005 02:45:23 -0000	1.74
@@ -38,7 +38,7 @@
 #include <stdlib.h>
 
 #include "cairoint.h"
-
+#include "cairo-gstate-private.h"
 
 void
 _cairo_surface_init (cairo_surface_t			*surface,
@@ -115,6 +115,17 @@
     return surface;
 }
 
+cairo_clip_mode_t
+_cairo_surface_get_clip_mode (cairo_surface_t *surface)
+{
+    if (surface->backend->intersect_clip_path != NULL)
+	return CAIRO_CLIP_MODE_PATH;
+    else if (surface->backend->set_clip_region != NULL)
+	return CAIRO_CLIP_MODE_REGION;
+    else
+	return CAIRO_CLIP_MODE_MASK;
+}
+
 void
 cairo_surface_reference (cairo_surface_t *surface)
 {
@@ -644,13 +655,16 @@
 }
 
 cairo_private cairo_int_status_t
-_cairo_surface_fill_path (cairo_operator_t   operator,
-			  cairo_pattern_t    *pattern,
-			  cairo_surface_t    *dst,
-			  cairo_path_fixed_t *path)
+_cairo_surface_fill_path (cairo_operator_t	operator,
+			  cairo_pattern_t	*pattern,
+			  cairo_surface_t	*dst,
+			  cairo_path_fixed_t	*path,
+			  cairo_fill_rule_t	fill_rule,
+			  double		tolerance)
 {
   if (dst->backend->fill_path)
-    return dst->backend->fill_path (operator, pattern, dst, path);
+    return dst->backend->fill_path (operator, pattern, dst, path,
+				    fill_rule, tolerance);
   else
     return CAIRO_INT_STATUS_UNSUPPORTED;
 }
@@ -837,13 +851,16 @@
 	return CAIRO_STATUS_SURFACE_FINISHED;
     
     surface->current_clip_serial = 0;
-#if 0
-    if (surface->backend->clip_path) {
-	status = surface->backend->clip_path (surface, NULL);
+
+    if (surface->backend->intersect_clip_path) {
+	status = surface->backend->intersect_clip_path (surface,
+							NULL,
+							CAIRO_FILL_RULE_WINDING,
+							0);
 	if (status)
 	    return status;
     }
-#endif
+
     if (surface->backend->set_clip_region != NULL) {
 	status = surface->backend->set_clip_region (surface, NULL);
 	if (status)
@@ -853,23 +870,6 @@
 }
 
 /**
- * _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;
-}
-
-/**
  * _cairo_surface_set_clip_region:
  * @surface: the #cairo_surface_t to reset the clip on
  * @region: the #pixman_region16_t to use for clipping
@@ -893,22 +893,64 @@
     return surface->backend->set_clip_region (surface, region);
 }
 
-#if 0
-/* new interfaces for path-based clipping */
-cairo_private cairo_status_t
-_cairo_surface_can_clip_path (cairo_surface_t	*surface)
+static cairo_status_t
+_cairo_surface_set_clip_path_recursive (cairo_surface_t *surface,
+					cairo_clip_path_t *clip_path)
 {
+    cairo_status_t status;
+
+    if (clip_path == NULL)
+	return CAIRO_STATUS_SUCCESS;
+
+    status = _cairo_surface_set_clip_path_recursive (surface, clip_path->prev);
+    if (status)
+	return status;
+
+    return surface->backend->intersect_clip_path (surface,
+						  &clip_path->path,
+						  clip_path->fill_rule,
+						  clip_path->tolerance);
 }
 
+
+/**
+ * _cairo_surface_set_clip_path:
+ * @surface: the #cairo_surface_t to reset the clip on
+ * @path: the path to intersect against the current clipping path
+ * @fill_rule: fill rule to use for clipping
+ * @tolerance: tesselation to use for tesselating clipping path
+ * @serial: the clip serial number associated with the region
+ * 
+ * Sets the clipping path to be the intersection of the current
+ * clipping path of the surface and the given path.
+ **/
 cairo_private cairo_status_t
-_cairo_surface_clip_path (cairo_surface_t	*surface,
-			  cairo_path_fixed_t	*path,
-			  unsigned int		serial)
+_cairo_surface_set_clip_path (cairo_surface_t	*surface,
+			      cairo_clip_path_t	*clip_path,
+			      unsigned int	serial)
 {
-    surface->current_clip_serial = clip_serial;
-    return surface->backend->clip_path (surface, path);
+    cairo_status_t status;
+
+    if (surface->finished)
+	return CAIRO_STATUS_SURFACE_FINISHED;
+
+    assert (surface->backend->intersect_clip_path != NULL);
+
+    status = surface->backend->intersect_clip_path (surface,
+						    NULL,
+						    CAIRO_FILL_RULE_WINDING,
+						    0);
+    if (status)
+	return status;
+
+    status = _cairo_surface_set_clip_path_recursive (surface, clip_path);
+    if (status)
+	return status;
+
+    surface->current_clip_serial = serial;
+
+    return CAIRO_STATUS_SUCCESS;
 }
-#endif
 
 /**
  * _cairo_surface_get_extents:

Index: cairo-win32-surface.c
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo-win32-surface.c,v
retrieving revision 1.25
retrieving revision 1.26
diff -u -d -r1.25 -r1.26
--- cairo-win32-surface.c	14 Jun 2005 22:38:15 -0000	1.25
+++ cairo-win32-surface.c	15 Jun 2005 02:45:23 -0000	1.26
@@ -941,6 +941,7 @@
     NULL, /* copy_page */
     NULL, /* show_page */
     _cairo_win32_surface_set_clip_region,
+    NULL, /* intersect_clip_path */
     _cairo_win32_surface_get_extents,
     NULL  /* show_glyphs */
 };

Index: cairo-xcb-surface.c
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo-xcb-surface.c,v
retrieving revision 1.35
retrieving revision 1.36
diff -u -d -r1.35 -r1.36
--- cairo-xcb-surface.c	14 Jun 2005 22:38:15 -0000	1.35
+++ cairo-xcb-surface.c	15 Jun 2005 02:45:23 -0000	1.36
@@ -1012,6 +1012,7 @@
     NULL, /* copy_page */
     NULL, /* show_page */
     NULL, /* _cairo_xcb_surface_set_clip_region */
+    NULL, /* intersect_clip_path */
     _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.78
retrieving revision 1.79
diff -u -d -r1.78 -r1.79
--- cairo-xlib-surface.c	14 Jun 2005 22:38:15 -0000	1.78
+++ cairo-xlib-surface.c	15 Jun 2005 02:45:23 -0000	1.79
@@ -1046,6 +1046,7 @@
     NULL, /* copy_page */
     NULL, /* show_page */
     _cairo_xlib_surface_set_clip_region,
+    NULL, /* intersect_clip_path */
     _cairo_xlib_surface_get_extents,
     _cairo_xlib_surface_show_glyphs
 };

Index: cairoint.h
===================================================================
RCS file: /cvs/cairo/cairo/src/cairoint.h,v
retrieving revision 1.154
retrieving revision 1.155
diff -u -d -r1.154 -r1.155
--- cairoint.h	14 Jun 2005 22:38:15 -0000	1.154
+++ cairoint.h	15 Jun 2005 02:45:23 -0000	1.155
@@ -642,10 +642,43 @@
     cairo_int_status_t
     (*show_page)		(void			*surface);
 
+    /* Set given region as the clip region for the surface, replacing
+     * any previously set clip region.  Passing in a NULL region will
+     * clear the surface clip region.
+     *
+     * The surface is expected to store the clip region and clip all
+     * following drawing operations against it until the clip region
+     * is cleared of replaced by another clip region.
+     *
+     * Cairo will call this function whenever a clip path can be
+     * represented as a device pixel aligned set of rectangles.  When
+     * this is not possible, cairo will use mask surfaces for
+     * clipping.
+     */
     cairo_int_status_t
     (*set_clip_region)		(void			*surface,
 				 pixman_region16_t	*region);
 
+    /* Intersect the given path against the clip path currently set in
+     * the surface, using the given fill_rule and tolerance, and set
+     * the result as the new clipping path for the surface.  Passing
+     * in a NULL path will clear the surface clipping path.
+     *
+     * The surface is expected to store the resulting clip path and
+     * clip all following drawing operations against it until the clip
+     * path cleared or intersected with a new path.
+     *
+     * If a surface implements this function, set_clip_region() will
+     * never be called and should not be implemented.  If this
+     * function is not implemented cairo will use set_clip_region()
+     * (if available) and mask surfaces for clipping.
+     */
+    cairo_int_status_t
+    (*intersect_clip_path)	(void			*dst,
+				 cairo_path_fixed_t	*path,
+				 cairo_fill_rule_t	fill_rule,
+				 double			tolerance);
+
     /* Get the extents of the current surface. For many surface types
      * this will be as simple as { x=0, y=0, width=surface->width,
      * height=surface->height}.
@@ -683,7 +716,9 @@
     (*fill_path)		(cairo_operator_t	operator,
  				 cairo_pattern_t	*pattern,
  				 void			*dst,
- 				 cairo_path_fixed_t	*path);
+ 				 cairo_path_fixed_t	*path,
+				 cairo_fill_rule_t	fill_rule,
+				 double			tolerance);
    
 } cairo_surface_backend_t;
 
@@ -695,6 +730,12 @@
     unsigned long blue_mask;
 } cairo_format_masks_t;
 
+typedef enum _cairo_clip_mode {
+    CAIRO_CLIP_MODE_PATH,
+    CAIRO_CLIP_MODE_REGION,
+    CAIRO_CLIP_MODE_MASK
+} cairo_clip_mode_t;
+
 struct _cairo_surface {
     const cairo_surface_backend_t *backend;
 
@@ -1381,6 +1422,9 @@
 _cairo_surface_init (cairo_surface_t			*surface,
 		     const cairo_surface_backend_t	*backend);
 
+cairo_private cairo_clip_mode_t
+_cairo_surface_get_clip_mode (cairo_surface_t *surface);
+
 cairo_private cairo_status_t
 _cairo_surface_fill_rectangle (cairo_surface_t	   *surface,
 			       cairo_operator_t	    operator,
@@ -1412,10 +1456,12 @@
 				int			num_rects);
 
 cairo_private cairo_int_status_t
-_cairo_surface_fill_path (cairo_operator_t   operator,
-			  cairo_pattern_t    *pattern,
-			  cairo_surface_t    *dst,
-			  cairo_path_fixed_t *path);
+_cairo_surface_fill_path (cairo_operator_t	operator,
+			  cairo_pattern_t	*pattern,
+			  cairo_surface_t	*dst,
+			  cairo_path_fixed_t	*path,
+			  cairo_fill_rule_t	fill_rule,
+			  double		tolerance);
   
 cairo_private cairo_status_t
 _cairo_surface_composite_trapezoids (cairo_operator_t	operator,
@@ -1475,23 +1521,16 @@
 _cairo_surface_reset_clip (cairo_surface_t *surface);
 
 cairo_private cairo_status_t
-_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);
+typedef struct _cairo_clip_path cairo_clip_path_t;
 
 cairo_private cairo_status_t
-_cairo_surface_clip_path (cairo_surface_t	*surface,
-			  cairo_path_fixed_t	*path,
-			  unsigned int		serial);
-#endif
+_cairo_surface_set_clip_path (cairo_surface_t	*surface,
+			      cairo_clip_path_t	*clip_path,
+			      unsigned int	serial);
 
 cairo_private cairo_status_t
 _cairo_surface_get_extents (cairo_surface_t   *surface,




More information about the cairo-commit mailing list