[cairo-commit] cairo/src cairo-gstate.c, 1.189, 1.190 cairo-surface-fallback.c, 1.1, 1.2 cairoint.h, 1.235, 1.236

Carl Worth commit at pdx.freedesktop.org
Tue Dec 20 09:37:18 PST 2005


Committed by: cworth

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

Modified Files:
	cairo-gstate.c cairo-surface-fallback.c cairoint.h 
Log Message:

2005-12-20  Carl Worth  <cworth at cworth.org>

        * src/cairoint.h:
        * src/cairo-gstate.c: (_cairo_gstate_get_antialias):
        * src/cairo-surface-fallback.c: (_create_composite_mask_pattern),
        (_clip_and_composite_with_mask), (_clip_and_composite_combine),
        (_clip_and_composite_source), (_cairo_rectangle_empty),
        (_clip_and_composite), (_composite_trap_region),
        (_composite_traps_draw_func), (_clip_and_composite_trapezoids),
        (_cairo_surface_fallback_paint), (_cairo_surface_fallback_mask),
        (_cairo_surface_fallback_stroke), (_cairo_surface_fallback_fill),
        (_cairo_surface_fallback_show_glyphs): Move more fallback code
        from cairo-gstate.c to cairo-surface-fallback.c where it
        belongs. In the process, clean up the function names a bit and
        make the whole mess static.


Index: cairo-gstate.c
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo-gstate.c,v
retrieving revision 1.189
retrieving revision 1.190
diff -u -d -r1.189 -r1.190
--- cairo-gstate.c	19 Dec 2005 23:08:05 -0000	1.189
+++ cairo-gstate.c	20 Dec 2005 17:37:15 -0000	1.190
@@ -838,300 +838,6 @@
     return FALSE;
 }
 
-static cairo_status_t
-_create_composite_mask_pattern (cairo_surface_pattern_t *mask_pattern,
-				cairo_clip_t            *clip,
-				cairo_draw_func_t        draw_func,
-				void                    *draw_closure,
-				cairo_surface_t         *dst,
-				const cairo_rectangle_t *extents)
-{
-    cairo_surface_t *mask;
-    cairo_status_t status;
-    
-    mask = cairo_surface_create_similar (dst,
-					 CAIRO_CONTENT_ALPHA,
-					 extents->width,
-					 extents->height);
-    if (mask->status)
-	return CAIRO_STATUS_NO_MEMORY;
-    
-    status = (*draw_func) (draw_closure, CAIRO_OPERATOR_ADD,
-			   NULL, mask,
-			   extents->x, extents->y,
-			   extents);
-    if (status)
-	goto CLEANUP_SURFACE;
-
-    if (clip && clip->surface)
-	status = _cairo_clip_combine_to_surface (clip, CAIRO_OPERATOR_IN,
-						 mask,
-						 extents->x, extents->y,
-						 extents);
-    if (status)
-	goto CLEANUP_SURFACE;
-    
-    _cairo_pattern_init_for_surface (mask_pattern, mask);
-
- CLEANUP_SURFACE:
-    cairo_surface_destroy (mask);
-
-    return status;
-}
-
-/* Handles compositing with a clip surface when the operator allows
- * us to combine the clip with the mask
- */
-static cairo_status_t
-_cairo_gstate_clip_and_composite_with_mask (cairo_clip_t            *clip,
-					    cairo_operator_t         op,
-					    cairo_pattern_t         *src,
-					    cairo_draw_func_t        draw_func,
-					    void                    *draw_closure,
-					    cairo_surface_t         *dst,
-					    const cairo_rectangle_t *extents)
-{
-    cairo_surface_pattern_t mask_pattern;
-    cairo_status_t status;
-
-    status = _create_composite_mask_pattern (&mask_pattern,
-					     clip,
-					     draw_func, draw_closure,
-					     dst, extents);
-    if (status)
-	return status;
-	
-    status = _cairo_surface_composite (op,
-				       src, &mask_pattern.base, dst,
-				       extents->x,     extents->y,
-				       0,              0,
-				       extents->x,     extents->y,
-				       extents->width, extents->height);
-
-    _cairo_pattern_fini (&mask_pattern.base);
-
-    return status;
-}
-
-/* Handles compositing with a clip surface when we have to do the operation
- * in two pieces and combine them together.
- */
-static cairo_status_t
-_cairo_gstate_clip_and_composite_combine (cairo_clip_t            *clip,
-					  cairo_operator_t         op,
-					  cairo_pattern_t         *src,
-					  cairo_draw_func_t        draw_func,
-					  void                    *draw_closure,
-					  cairo_surface_t         *dst,
-					  const cairo_rectangle_t *extents)
-{
-    cairo_surface_t *intermediate;
-    cairo_surface_pattern_t dst_pattern;
-    cairo_surface_pattern_t intermediate_pattern;
-    cairo_status_t status;
-
-    /* We'd be better off here creating a surface identical in format
-     * to dst, but we have no way of getting that information.
-     * A CAIRO_CONTENT_CLONE or something might be useful.
-     * cairo_surface_create_similar() also unnecessarily clears the surface.
-     */
-    intermediate = cairo_surface_create_similar (dst,
-						 CAIRO_CONTENT_COLOR_ALPHA,
-						 extents->width,
-						 extents->height);
-    if (intermediate->status)
-	return CAIRO_STATUS_NO_MEMORY;
-
-    /* Initialize the intermediate surface from the destination surface
-     */
-    _cairo_pattern_init_for_surface (&dst_pattern, dst);
-
-    status = _cairo_surface_composite (CAIRO_OPERATOR_SOURCE,
-				       &dst_pattern.base, NULL, intermediate,
-				       extents->x,     extents->y,
-				       0,              0,
-				       0,              0,
-				       extents->width, extents->height);
-
-    _cairo_pattern_fini (&dst_pattern.base);
-
-    if (status)
-	goto CLEANUP_SURFACE;
-
-    status = (*draw_func) (draw_closure, op,
-			   src, intermediate,
-			   extents->x, extents->y,
-			   extents);
-    if (status)
-	goto CLEANUP_SURFACE;
-
-    /* Combine that with the clip
-     */
-    status = _cairo_clip_combine_to_surface (clip, CAIRO_OPERATOR_DEST_IN,
-					     intermediate,
-					     extents->x, extents->y,					     
-					     extents);
-    if (status)
-	goto CLEANUP_SURFACE;
-
-    /* Punch the clip out of the destination
-     */
-    status = _cairo_clip_combine_to_surface (clip, CAIRO_OPERATOR_DEST_OUT,
-					     dst,
-					     0, 0,
-					     extents);
-    if (status)
-	goto CLEANUP_SURFACE;
-
-    /* Now add the two results together
-     */
-    _cairo_pattern_init_for_surface (&intermediate_pattern, intermediate);
-    
-    status = _cairo_surface_composite (CAIRO_OPERATOR_ADD,
-				       &intermediate_pattern.base, NULL, dst,
-				       0,              0,
-				       0,              0,
-				       extents->x,     extents->y,
-				       extents->width, extents->height);
-
-    _cairo_pattern_fini (&intermediate_pattern.base);
-    
- CLEANUP_SURFACE:
-    cairo_surface_destroy (intermediate);
-
-    return status;
-}
-
-/* Handles compositing for CAIRO_OPERATOR_SOURCE, which is special; it's
- * defined as (src IN mask IN clip) ADD (dst OUT (mask IN clip))
- */
-static cairo_status_t
-_cairo_gstate_clip_and_composite_source (cairo_clip_t            *clip,
-					 cairo_pattern_t         *src,
-					 cairo_draw_func_t        draw_func,
-					 void                    *draw_closure,
-					 cairo_surface_t         *dst,
-					 const cairo_rectangle_t *extents)
-{
-    cairo_surface_pattern_t mask_pattern;
-    cairo_status_t status;
-
-    /* Create a surface that is mask IN clip
-     */
-    status = _create_composite_mask_pattern (&mask_pattern,
-					     clip,
-					     draw_func, draw_closure,
-					     dst, extents);
-    if (status)
-	return status;
-    
-    /* Compute dest' = dest OUT (mask IN clip)
-     */
-    status = _cairo_surface_composite (CAIRO_OPERATOR_DEST_OUT,
-				       &mask_pattern.base, NULL, dst,
-				       0,              0,
-				       0,              0,
-				       extents->x,     extents->y,
-				       extents->width, extents->height);
-
-    if (status)
-	goto CLEANUP_MASK_PATTERN;
-
-    /* Now compute (src IN (mask IN clip)) ADD dest'
-     */
-    status = _cairo_surface_composite (CAIRO_OPERATOR_ADD,
-				       src, &mask_pattern.base, dst,
-				       extents->x,     extents->y,
-				       0,              0,
-				       extents->x,     extents->y,
-				       extents->width, extents->height);
-
- CLEANUP_MASK_PATTERN:
-    _cairo_pattern_fini (&mask_pattern.base);
-    return status;
-}
-
-static int
-_cairo_rectangle_empty (const cairo_rectangle_t *rect)
-{
-    return rect->width == 0 || rect->height == 0;
-}
-
-/**
- * _cairo_gstate_clip_and_composite:
- * @gstate: a #cairo_gstate_t
- * @op: the operator to draw with
- * @src: source pattern
- * @draw_func: function that can be called to draw with the mask onto a surface.
- * @draw_closure: data to pass to @draw_func.
- * @dst: destination surface
- * @extents: rectangle holding a bounding box for the operation; this
- *           rectangle will be used as the size for the temporary
- *           surface.
- *
- * When there is a surface clip, we typically need to create an intermediate
- * surface. This function handles the logic of creating a temporary surface
- * drawing to it, then compositing the result onto the target surface.
- *
- * @draw_func is to called to draw the mask; it will be called no more
- * than once.
- * 
- * Return value: %CAIRO_STATUS_SUCCESS if the drawing succeeded.
- **/
-cairo_status_t
-_cairo_gstate_clip_and_composite (cairo_clip_t            *clip,
-				  cairo_operator_t         op,
-				  cairo_pattern_t         *src,
-				  cairo_draw_func_t        draw_func,
-				  void                    *draw_closure,
-				  cairo_surface_t         *dst,
-				  const cairo_rectangle_t *extents)
-{
-    cairo_pattern_union_t solid_pattern;
-    cairo_status_t status;
-
-    if (_cairo_rectangle_empty (extents))
-	/* Nothing to do */
-	return CAIRO_STATUS_SUCCESS;
-
-    if (op == CAIRO_OPERATOR_CLEAR) {
-	_cairo_pattern_init_solid (&solid_pattern.solid, CAIRO_COLOR_WHITE);
-	src = &solid_pattern.base;
-	op = CAIRO_OPERATOR_DEST_OUT;
-    }
-
-    if ((clip && clip->surface) || op == CAIRO_OPERATOR_SOURCE)
-    {
-	if (op == CAIRO_OPERATOR_SOURCE)
-	    status = _cairo_gstate_clip_and_composite_source (clip,
-							      src,
-							      draw_func, draw_closure,
-							      dst, extents);
-	else if (_cairo_operator_bounded_by_mask (op))
-	    status = _cairo_gstate_clip_and_composite_with_mask (clip, op,
-								 src,
-								 draw_func, draw_closure,
-								 dst, extents);
-	else
-	    status = _cairo_gstate_clip_and_composite_combine (clip, op,
-							       src,
-							       draw_func, draw_closure,
-							       dst, extents);
-    }
-    else
-    {
-	status = (*draw_func) (draw_closure, op,
-			       src, dst,
-			       0, 0,
-			       extents);
-    }
-
-    if (src == &solid_pattern.base)
-	_cairo_pattern_fini (&solid_pattern.base);
-
-    return status;
-}
-
 cairo_status_t
 _cairo_gstate_mask (cairo_gstate_t  *gstate,
 		    cairo_pattern_t *mask)
@@ -1274,249 +980,6 @@
     }	
 }
 
-/* Composites a region representing a set of trapezoids.
- */
-static cairo_status_t
-_composite_trap_region (cairo_clip_t      *clip,
-			cairo_pattern_t   *src,
-			cairo_operator_t   op,
-			cairo_surface_t   *dst,
-			pixman_region16_t *trap_region,
-			cairo_rectangle_t *extents)
-{
-    cairo_status_t status;
-    cairo_pattern_union_t solid_pattern;
-    cairo_pattern_union_t mask;
-    int num_rects = pixman_region_num_rects (trap_region);
-    unsigned int clip_serial;
-    cairo_surface_t *clip_surface = clip ? clip->surface : NULL;
-
-    if (clip_surface && op == CAIRO_OPERATOR_CLEAR) {
-	_cairo_pattern_init_solid (&solid_pattern.solid, CAIRO_COLOR_WHITE);
-	src = &solid_pattern.base;
-	op = CAIRO_OPERATOR_DEST_OUT;
-    }
-
-    if (num_rects == 0)
-	return CAIRO_STATUS_SUCCESS;
-    
-    if (num_rects > 1) {
-      if (_cairo_surface_get_clip_mode (dst) != CAIRO_CLIP_MODE_REGION)
-	    return CAIRO_INT_STATUS_UNSUPPORTED;
-	
-	clip_serial = _cairo_surface_allocate_clip_serial (dst);
-	status = _cairo_surface_set_clip_region (dst,
-						 trap_region,
-						 clip_serial);
-	if (status)
-	    return status;
-    }
-    
-    if (clip_surface)
-	_cairo_pattern_init_for_surface (&mask.surface, clip_surface);
-	
-    status = _cairo_surface_composite (op,
-				       src,
-				       clip_surface ? &mask.base : NULL,
-				       dst,
-				       extents->x, extents->y,
-				       extents->x - (clip_surface ? clip->surface_rect.x : 0),
-				       extents->y - (clip_surface ? clip->surface_rect.y : 0),
-				       extents->x, extents->y,
-				       extents->width, extents->height);
-
-    if (clip_surface)
-      _cairo_pattern_fini (&mask.base);
-
-    if (src == &solid_pattern.base)
-	_cairo_pattern_fini (&solid_pattern.base);
-
-    return status;
-}
-
-typedef struct {
-    cairo_traps_t *traps;
-    cairo_antialias_t antialias;
-} cairo_composite_traps_info_t;
-
-static cairo_status_t
-_composite_traps_draw_func (void                    *closure,
-			    cairo_operator_t         op,
-			    cairo_pattern_t         *src,
-			    cairo_surface_t         *dst,
-			    int                      dst_x,
-			    int                      dst_y,
-			    const cairo_rectangle_t *extents)
-{
-    cairo_composite_traps_info_t *info = closure;
-    cairo_pattern_union_t pattern;
-    cairo_status_t status;
-    
-    if (dst_x != 0 || dst_y != 0)
-	_cairo_traps_translate (info->traps, - dst_x, - dst_y);
-
-    _cairo_pattern_init_solid (&pattern.solid, CAIRO_COLOR_WHITE);
-    if (!src)
-	src = &pattern.base;
-    
-    status = _cairo_surface_composite_trapezoids (op,
-						  src, dst, info->antialias,
-						  extents->x,         extents->y,
-						  extents->x - dst_x, extents->y - dst_y,
-						  extents->width,     extents->height,
-						  info->traps->traps,
-						  info->traps->num_traps);
-    _cairo_pattern_fini (&pattern.base);
-
-    return status;
-}
-
-/* Warning: This call modifies the coordinates of traps */
-cairo_status_t
-_cairo_surface_clip_and_composite_trapezoids (cairo_pattern_t *src,
-					      cairo_operator_t op,
-					      cairo_surface_t *dst,
-					      cairo_traps_t *traps,
-					      cairo_clip_t *clip,
-					      cairo_antialias_t antialias)
-{
-    cairo_status_t status;
-    pixman_region16_t *trap_region;
-    pixman_region16_t *clear_region = NULL;
-    cairo_rectangle_t extents;
-    cairo_composite_traps_info_t traps_info;
-    
-    if (traps->num_traps == 0)
-	return CAIRO_STATUS_SUCCESS;
-
-    status = _cairo_traps_extract_region (traps, &trap_region);
-    if (status)
-	return status;
-
-    if (_cairo_operator_bounded_by_mask (op))
-    {
-	if (trap_region) {
-	    status = _cairo_clip_intersect_to_region (clip, trap_region);
-	    _cairo_region_extents_rectangle (trap_region, &extents);
-	} else {
-	    cairo_box_t trap_extents;
-	    _cairo_traps_extents (traps, &trap_extents);
-	    _cairo_box_round_to_rectangle (&trap_extents, &extents);
-	    status = _cairo_clip_intersect_to_rectangle (clip, &extents);
-	}
-    }
-    else
-    {
-	cairo_surface_t *clip_surface = clip ? clip->surface : NULL;
-	
-	status = _cairo_surface_get_extents (dst, &extents);
-	if (status)
-	    return status;
-	
-	if (trap_region && !clip_surface) {
-	    /* If we optimize drawing with an unbounded operator to
-	     * _cairo_surface_fill_rectangles() or to drawing with a
-	     * clip region, then we have an additional region to clear.
-	     */
-	    status = _cairo_surface_get_extents (dst, &extents);
-	    if (status)
-		return status;
-	    
-	    clear_region = _cairo_region_create_from_rectangle (&extents);
-	    status = _cairo_clip_intersect_to_region (clip, clear_region);
-	    if (status)
-		return status;
-	    
-	    _cairo_region_extents_rectangle (clear_region,  &extents);
-	    
-	    if (pixman_region_subtract (clear_region, clear_region, trap_region) != PIXMAN_REGION_STATUS_SUCCESS)
-		return CAIRO_STATUS_NO_MEMORY;
-	    
-	    if (!pixman_region_not_empty (clear_region)) {
-		pixman_region_destroy (clear_region);
-		clear_region = NULL;
-	    }
-	} else {
-	    status = _cairo_clip_intersect_to_rectangle (clip, &extents);
-	    if (status)
-		return status;
-	}
-    }
-	
-    if (status)
-	goto out;
-    
-    if (trap_region)
-    {
-	cairo_surface_t *clip_surface = clip ? clip->surface : NULL;
-	
-	if ((src->type == CAIRO_PATTERN_SOLID || op == CAIRO_OPERATOR_CLEAR) &&
-	    !clip_surface)
-	{
-	    const cairo_color_t *color;
-
-	    if (op == CAIRO_OPERATOR_CLEAR)
-		color = CAIRO_COLOR_TRANSPARENT;
-	    else
-		color = &((cairo_solid_pattern_t *)src)->color;
-	  
-	    /* Solid rectangles special case */
-	    status = _cairo_surface_fill_region (dst, op, color, trap_region);
-	    if (!status && clear_region)
-		status = _cairo_surface_fill_region (dst, CAIRO_OPERATOR_CLEAR,
-						     CAIRO_COLOR_TRANSPARENT,
-						     clear_region);
-
-	    goto out;
-	}
-
-	if ((_cairo_operator_bounded_by_mask (op) && op != CAIRO_OPERATOR_SOURCE) ||
-	    !clip_surface)
-	{
-	    /* For a simple rectangle, we can just use composite(), for more
-	     * rectangles, we have to set a clip region. The cost of rasterizing
-	     * trapezoids is pretty high for most backends currently, so it's
-	     * worthwhile even if a region is needed.
-	     *
-	     * If we have a clip surface, we set it as the mask; this only works
-	     * for bounded operators other than SOURCE; for unbounded operators,
-	     * clip and mask cannot be interchanged. For SOURCE, the operator
-	     * as implemented by the backends is different in it's handling
-	     * of the mask then what we want.
-	     *
-	     * CAIRO_INT_STATUS_UNSUPPORTED will be returned if the region has
-	     * more than rectangle and the destination doesn't support clip
-	     * regions. In that case, we fall through.
-	     */
-	    status = _composite_trap_region (clip, src, op, dst,
-					     trap_region, &extents);
-	    if (status != CAIRO_INT_STATUS_UNSUPPORTED)
-	    {
-		if (!status && clear_region)
-		    status = _cairo_surface_fill_region (dst, CAIRO_OPERATOR_CLEAR,
-							 CAIRO_COLOR_TRANSPARENT,
-							 clear_region);
-		goto out;
-	    }
-	}
-    }
-
-    traps_info.traps = traps;
-    traps_info.antialias = antialias;
-
-    status = _cairo_gstate_clip_and_composite (clip, op, src,
-					       _composite_traps_draw_func, &traps_info,
-					       dst, &extents);
-
- out:
-    if (trap_region)
-	pixman_region_destroy (trap_region);
-    if (clear_region)
-	pixman_region_destroy (clear_region);
-    
-    return status;
-}
-
 cairo_status_t
 _cairo_gstate_fill (cairo_gstate_t *gstate, cairo_path_fixed_t *path)
 {
@@ -2050,4 +1513,3 @@
 {
     return gstate->antialias;
 }
-

Index: cairo-surface-fallback.c
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo-surface-fallback.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -d -r1.1 -r1.2
--- cairo-surface-fallback.c	20 Dec 2005 06:45:42 -0000	1.1
+++ cairo-surface-fallback.c	20 Dec 2005 17:37:15 -0000	1.2
@@ -98,6 +98,551 @@
 				       state->image_extra);
 }
 
+typedef cairo_status_t (*cairo_draw_func_t) (void                    *closure,
+					     cairo_operator_t         op,
+					     cairo_pattern_t         *src,
+					     cairo_surface_t         *dst,
+					     int                      dst_x,
+					     int                      dst_y,
+					     const cairo_rectangle_t *extents);
+
+static cairo_status_t
+_create_composite_mask_pattern (cairo_surface_pattern_t *mask_pattern,
+				cairo_clip_t            *clip,
+				cairo_draw_func_t        draw_func,
+				void                    *draw_closure,
+				cairo_surface_t         *dst,
+				const cairo_rectangle_t *extents)
+{
+    cairo_surface_t *mask;
+    cairo_status_t status;
+    
+    mask = cairo_surface_create_similar (dst,
+					 CAIRO_CONTENT_ALPHA,
+					 extents->width,
+					 extents->height);
+    if (mask->status)
+	return CAIRO_STATUS_NO_MEMORY;
+    
+    status = (*draw_func) (draw_closure, CAIRO_OPERATOR_ADD,
+			   NULL, mask,
+			   extents->x, extents->y,
+			   extents);
+    if (status)
+	goto CLEANUP_SURFACE;
+
+    if (clip && clip->surface)
+	status = _cairo_clip_combine_to_surface (clip, CAIRO_OPERATOR_IN,
+						 mask,
+						 extents->x, extents->y,
+						 extents);
+    if (status)
+	goto CLEANUP_SURFACE;
+    
+    _cairo_pattern_init_for_surface (mask_pattern, mask);
+
+ CLEANUP_SURFACE:
+    cairo_surface_destroy (mask);
+
+    return status;
+}
+
+/* Handles compositing with a clip surface when the operator allows
+ * us to combine the clip with the mask
+ */
+static cairo_status_t
+_clip_and_composite_with_mask (cairo_clip_t            *clip,
+			       cairo_operator_t         op,
+			       cairo_pattern_t         *src,
+			       cairo_draw_func_t        draw_func,
+			       void                    *draw_closure,
+			       cairo_surface_t         *dst,
+			       const cairo_rectangle_t *extents)
+{
+    cairo_surface_pattern_t mask_pattern;
+    cairo_status_t status;
+
+    status = _create_composite_mask_pattern (&mask_pattern,
+					     clip,
+					     draw_func, draw_closure,
+					     dst, extents);
+    if (status)
+	return status;
+	
+    status = _cairo_surface_composite (op,
+				       src, &mask_pattern.base, dst,
+				       extents->x,     extents->y,
+				       0,              0,
+				       extents->x,     extents->y,
+				       extents->width, extents->height);
+
+    _cairo_pattern_fini (&mask_pattern.base);
+
+    return status;
+}
+
+/* Handles compositing with a clip surface when we have to do the operation
+ * in two pieces and combine them together.
+ */
+static cairo_status_t
+_clip_and_composite_combine (cairo_clip_t            *clip,
+			     cairo_operator_t         op,
+			     cairo_pattern_t         *src,
+			     cairo_draw_func_t        draw_func,
+			     void                    *draw_closure,
+			     cairo_surface_t         *dst,
+			     const cairo_rectangle_t *extents)
+{
+    cairo_surface_t *intermediate;
+    cairo_surface_pattern_t dst_pattern;
+    cairo_surface_pattern_t intermediate_pattern;
+    cairo_status_t status;
+
+    /* We'd be better off here creating a surface identical in format
+     * to dst, but we have no way of getting that information.
+     * A CAIRO_CONTENT_CLONE or something might be useful.
+     * cairo_surface_create_similar() also unnecessarily clears the surface.
+     */
+    intermediate = cairo_surface_create_similar (dst,
+						 CAIRO_CONTENT_COLOR_ALPHA,
+						 extents->width,
+						 extents->height);
+    if (intermediate->status)
+	return CAIRO_STATUS_NO_MEMORY;
+
+    /* Initialize the intermediate surface from the destination surface
+     */
+    _cairo_pattern_init_for_surface (&dst_pattern, dst);
+
+    status = _cairo_surface_composite (CAIRO_OPERATOR_SOURCE,
+				       &dst_pattern.base, NULL, intermediate,
+				       extents->x,     extents->y,
+				       0,              0,
+				       0,              0,
+				       extents->width, extents->height);
+
+    _cairo_pattern_fini (&dst_pattern.base);
+
+    if (status)
+	goto CLEANUP_SURFACE;
+
+    status = (*draw_func) (draw_closure, op,
+			   src, intermediate,
+			   extents->x, extents->y,
+			   extents);
+    if (status)
+	goto CLEANUP_SURFACE;
+
+    /* Combine that with the clip
+     */
+    status = _cairo_clip_combine_to_surface (clip, CAIRO_OPERATOR_DEST_IN,
+					     intermediate,
+					     extents->x, extents->y,					     
+					     extents);
+    if (status)
+	goto CLEANUP_SURFACE;
+
+    /* Punch the clip out of the destination
+     */
+    status = _cairo_clip_combine_to_surface (clip, CAIRO_OPERATOR_DEST_OUT,
+					     dst,
+					     0, 0,
+					     extents);
+    if (status)
+	goto CLEANUP_SURFACE;
+
+    /* Now add the two results together
+     */
+    _cairo_pattern_init_for_surface (&intermediate_pattern, intermediate);
+    
+    status = _cairo_surface_composite (CAIRO_OPERATOR_ADD,
+				       &intermediate_pattern.base, NULL, dst,
+				       0,              0,
+				       0,              0,
+				       extents->x,     extents->y,
+				       extents->width, extents->height);
+
+    _cairo_pattern_fini (&intermediate_pattern.base);
+    
+ CLEANUP_SURFACE:
+    cairo_surface_destroy (intermediate);
+
+    return status;
+}
+
+/* Handles compositing for CAIRO_OPERATOR_SOURCE, which is special; it's
+ * defined as (src IN mask IN clip) ADD (dst OUT (mask IN clip))
+ */
+static cairo_status_t
+_clip_and_composite_source (cairo_clip_t            *clip,
+			    cairo_pattern_t         *src,
+			    cairo_draw_func_t        draw_func,
+			    void                    *draw_closure,
+			    cairo_surface_t         *dst,
+			    const cairo_rectangle_t *extents)
+{
+    cairo_surface_pattern_t mask_pattern;
+    cairo_status_t status;
+
+    /* Create a surface that is mask IN clip
+     */
+    status = _create_composite_mask_pattern (&mask_pattern,
+					     clip,
+					     draw_func, draw_closure,
+					     dst, extents);
+    if (status)
+	return status;
+    
+    /* Compute dest' = dest OUT (mask IN clip)
+     */
+    status = _cairo_surface_composite (CAIRO_OPERATOR_DEST_OUT,
+				       &mask_pattern.base, NULL, dst,
+				       0,              0,
+				       0,              0,
+				       extents->x,     extents->y,
+				       extents->width, extents->height);
+
+    if (status)
+	goto CLEANUP_MASK_PATTERN;
+
+    /* Now compute (src IN (mask IN clip)) ADD dest'
+     */
+    status = _cairo_surface_composite (CAIRO_OPERATOR_ADD,
+				       src, &mask_pattern.base, dst,
+				       extents->x,     extents->y,
+				       0,              0,
+				       extents->x,     extents->y,
+				       extents->width, extents->height);
+
+ CLEANUP_MASK_PATTERN:
+    _cairo_pattern_fini (&mask_pattern.base);
+    return status;
+}
+
+static int
+_cairo_rectangle_empty (const cairo_rectangle_t *rect)
+{
+    return rect->width == 0 || rect->height == 0;
+}
+
+/**
+ * _clip_and_composite:
+ * @clip: a #cairo_clip_t
+ * @op: the operator to draw with
+ * @src: source pattern
+ * @draw_func: function that can be called to draw with the mask onto a surface.
+ * @draw_closure: data to pass to @draw_func.
+ * @dst: destination surface
+ * @extents: rectangle holding a bounding box for the operation; this
+ *           rectangle will be used as the size for the temporary
+ *           surface.
+ *
+ * When there is a surface clip, we typically need to create an intermediate
+ * surface. This function handles the logic of creating a temporary surface
+ * drawing to it, then compositing the result onto the target surface.
+ *
+ * @draw_func is to called to draw the mask; it will be called no more
+ * than once.
+ * 
+ * Return value: %CAIRO_STATUS_SUCCESS if the drawing succeeded.
+ **/
+static cairo_status_t
+_clip_and_composite (cairo_clip_t            *clip,
+		     cairo_operator_t         op,
+		     cairo_pattern_t         *src,
+		     cairo_draw_func_t        draw_func,
+		     void                    *draw_closure,
+		     cairo_surface_t         *dst,
+		     const cairo_rectangle_t *extents)
+{
+    cairo_pattern_union_t solid_pattern;
+    cairo_status_t status;
+
+    if (_cairo_rectangle_empty (extents))
+	/* Nothing to do */
+	return CAIRO_STATUS_SUCCESS;
+
+    if (op == CAIRO_OPERATOR_CLEAR) {
+	_cairo_pattern_init_solid (&solid_pattern.solid, CAIRO_COLOR_WHITE);
+	src = &solid_pattern.base;
+	op = CAIRO_OPERATOR_DEST_OUT;
+    }
+
+    if ((clip && clip->surface) || op == CAIRO_OPERATOR_SOURCE)
+    {
+	if (op == CAIRO_OPERATOR_SOURCE)
+	    status = _clip_and_composite_source (clip,
+						 src,
+						 draw_func, draw_closure,
+						 dst, extents);
+	else if (_cairo_operator_bounded_by_mask (op))
+	    status = _clip_and_composite_with_mask (clip, op,
+						    src,
+						    draw_func, draw_closure,
+						    dst, extents);
+	else
+	    status = _clip_and_composite_combine (clip, op,
+						  src,
+						  draw_func, draw_closure,
+						  dst, extents);
+    }
+    else
+    {
+	status = (*draw_func) (draw_closure, op,
+			       src, dst,
+			       0, 0,
+			       extents);
+    }
+
+    if (src == &solid_pattern.base)
+	_cairo_pattern_fini (&solid_pattern.base);
+
+    return status;
+}
+
+/* Composites a region representing a set of trapezoids.
+ */
+static cairo_status_t
+_composite_trap_region (cairo_clip_t      *clip,
+			cairo_pattern_t   *src,
+			cairo_operator_t   op,
+			cairo_surface_t   *dst,
+			pixman_region16_t *trap_region,
+			cairo_rectangle_t *extents)
+{
+    cairo_status_t status;
+    cairo_pattern_union_t solid_pattern;
+    cairo_pattern_union_t mask;
+    int num_rects = pixman_region_num_rects (trap_region);
+    unsigned int clip_serial;
+    cairo_surface_t *clip_surface = clip ? clip->surface : NULL;
+
+    if (clip_surface && op == CAIRO_OPERATOR_CLEAR) {
+	_cairo_pattern_init_solid (&solid_pattern.solid, CAIRO_COLOR_WHITE);
+	src = &solid_pattern.base;
+	op = CAIRO_OPERATOR_DEST_OUT;
+    }
+
+    if (num_rects == 0)
+	return CAIRO_STATUS_SUCCESS;
+    
+    if (num_rects > 1) {
+      if (_cairo_surface_get_clip_mode (dst) != CAIRO_CLIP_MODE_REGION)
+	    return CAIRO_INT_STATUS_UNSUPPORTED;
+	
+	clip_serial = _cairo_surface_allocate_clip_serial (dst);
+	status = _cairo_surface_set_clip_region (dst,
+						 trap_region,
+						 clip_serial);
+	if (status)
+	    return status;
+    }
+    
+    if (clip_surface)
+	_cairo_pattern_init_for_surface (&mask.surface, clip_surface);
+	
+    status = _cairo_surface_composite (op,
+				       src,
+				       clip_surface ? &mask.base : NULL,
+				       dst,
+				       extents->x, extents->y,
+				       extents->x - (clip_surface ? clip->surface_rect.x : 0),
+				       extents->y - (clip_surface ? clip->surface_rect.y : 0),
+				       extents->x, extents->y,
+				       extents->width, extents->height);
+
+    if (clip_surface)
+      _cairo_pattern_fini (&mask.base);
+
+    if (src == &solid_pattern.base)
+	_cairo_pattern_fini (&solid_pattern.base);
+
+    return status;
+}
+
+typedef struct {
+    cairo_traps_t *traps;
+    cairo_antialias_t antialias;
+} cairo_composite_traps_info_t;
+
+static cairo_status_t
+_composite_traps_draw_func (void                    *closure,
+			    cairo_operator_t         op,
+			    cairo_pattern_t         *src,
+			    cairo_surface_t         *dst,
+			    int                      dst_x,
+			    int                      dst_y,
+			    const cairo_rectangle_t *extents)
+{
+    cairo_composite_traps_info_t *info = closure;
+    cairo_pattern_union_t pattern;
+    cairo_status_t status;
+    
+    if (dst_x != 0 || dst_y != 0)
+	_cairo_traps_translate (info->traps, - dst_x, - dst_y);
+
+    _cairo_pattern_init_solid (&pattern.solid, CAIRO_COLOR_WHITE);
+    if (!src)
+	src = &pattern.base;
+    
+    status = _cairo_surface_composite_trapezoids (op,
+						  src, dst, info->antialias,
+						  extents->x,         extents->y,
+						  extents->x - dst_x, extents->y - dst_y,
+						  extents->width,     extents->height,
+						  info->traps->traps,
+						  info->traps->num_traps);
+    _cairo_pattern_fini (&pattern.base);
+
+    return status;
+}
+
+/* Warning: This call modifies the coordinates of traps */
+static cairo_status_t
+_clip_and_composite_trapezoids (cairo_pattern_t *src,
+				cairo_operator_t op,
+				cairo_surface_t *dst,
+				cairo_traps_t *traps,
+				cairo_clip_t *clip,
+				cairo_antialias_t antialias)
+{
+    cairo_status_t status;
+    pixman_region16_t *trap_region;
+    pixman_region16_t *clear_region = NULL;
+    cairo_rectangle_t extents;
+    cairo_composite_traps_info_t traps_info;
+    
+    if (traps->num_traps == 0)
+	return CAIRO_STATUS_SUCCESS;
+
+    status = _cairo_traps_extract_region (traps, &trap_region);
+    if (status)
+	return status;
+
+    if (_cairo_operator_bounded_by_mask (op))
+    {
+	if (trap_region) {
+	    status = _cairo_clip_intersect_to_region (clip, trap_region);
+	    _cairo_region_extents_rectangle (trap_region, &extents);
+	} else {
+	    cairo_box_t trap_extents;
+	    _cairo_traps_extents (traps, &trap_extents);
+	    _cairo_box_round_to_rectangle (&trap_extents, &extents);
+	    status = _cairo_clip_intersect_to_rectangle (clip, &extents);
+	}
+    }
+    else
+    {
+	cairo_surface_t *clip_surface = clip ? clip->surface : NULL;
+	
+	status = _cairo_surface_get_extents (dst, &extents);
+	if (status)
+	    return status;
+	
+	if (trap_region && !clip_surface) {
+	    /* If we optimize drawing with an unbounded operator to
+	     * _cairo_surface_fill_rectangles() or to drawing with a
+	     * clip region, then we have an additional region to clear.
+	     */
+	    status = _cairo_surface_get_extents (dst, &extents);
+	    if (status)
+		return status;
+	    
+	    clear_region = _cairo_region_create_from_rectangle (&extents);
+	    status = _cairo_clip_intersect_to_region (clip, clear_region);
+	    if (status)
+		return status;
+	    
+	    _cairo_region_extents_rectangle (clear_region,  &extents);
+	    
+	    if (pixman_region_subtract (clear_region, clear_region, trap_region) != PIXMAN_REGION_STATUS_SUCCESS)
+		return CAIRO_STATUS_NO_MEMORY;
+	    
+	    if (!pixman_region_not_empty (clear_region)) {
+		pixman_region_destroy (clear_region);
+		clear_region = NULL;
+	    }
+	} else {
+	    status = _cairo_clip_intersect_to_rectangle (clip, &extents);
+	    if (status)
+		return status;
+	}
+    }
+	
+    if (status)
+	goto out;
+    
+    if (trap_region)
+    {
+	cairo_surface_t *clip_surface = clip ? clip->surface : NULL;
+	
+	if ((src->type == CAIRO_PATTERN_SOLID || op == CAIRO_OPERATOR_CLEAR) &&
+	    !clip_surface)
+	{
+	    const cairo_color_t *color;
+
+	    if (op == CAIRO_OPERATOR_CLEAR)
+		color = CAIRO_COLOR_TRANSPARENT;
+	    else
+		color = &((cairo_solid_pattern_t *)src)->color;
+	  
+	    /* Solid rectangles special case */
+	    status = _cairo_surface_fill_region (dst, op, color, trap_region);
+	    if (!status && clear_region)
+		status = _cairo_surface_fill_region (dst, CAIRO_OPERATOR_CLEAR,
+						     CAIRO_COLOR_TRANSPARENT,
+						     clear_region);
+
+	    goto out;
+	}
+
+	if ((_cairo_operator_bounded_by_mask (op) && op != CAIRO_OPERATOR_SOURCE) ||
+	    !clip_surface)
+	{
+	    /* For a simple rectangle, we can just use composite(), for more
+	     * rectangles, we have to set a clip region. The cost of rasterizing
+	     * trapezoids is pretty high for most backends currently, so it's
+	     * worthwhile even if a region is needed.
+	     *
+	     * If we have a clip surface, we set it as the mask; this only works
+	     * for bounded operators other than SOURCE; for unbounded operators,
+	     * clip and mask cannot be interchanged. For SOURCE, the operator
+	     * as implemented by the backends is different in it's handling
+	     * of the mask then what we want.
+	     *
+	     * CAIRO_INT_STATUS_UNSUPPORTED will be returned if the region has
+	     * more than rectangle and the destination doesn't support clip
+	     * regions. In that case, we fall through.
+	     */
+	    status = _composite_trap_region (clip, src, op, dst,
+					     trap_region, &extents);
+	    if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+	    {
+		if (!status && clear_region)
+		    status = _cairo_surface_fill_region (dst, CAIRO_OPERATOR_CLEAR,
+							 CAIRO_COLOR_TRANSPARENT,
+							 clear_region);
+		goto out;
+	    }
+	}
+    }
+
+    traps_info.traps = traps;
+    traps_info.antialias = antialias;
+
+    status = _clip_and_composite (clip, op, src,
+				  _composite_traps_draw_func, &traps_info,
+				  dst, &extents);
+
+ out:
+    if (trap_region)
+	pixman_region_destroy (trap_region);
+    if (clear_region)
+	pixman_region_destroy (clear_region);
+    
+    return status;
+}
+
 cairo_status_t
 _cairo_surface_fallback_paint (cairo_surface_t	*surface,
 			       cairo_operator_t	 op,
@@ -134,12 +679,12 @@
     if (status)
 	return status;
     
-    _cairo_surface_clip_and_composite_trapezoids (source,
-						  op,
-						  surface,
-						  &traps,
-						  surface->clip,
-						  CAIRO_ANTIALIAS_NONE);
+    _clip_and_composite_trapezoids (source,
+				    op,
+				    surface,
+				    &traps,
+				    surface->clip,
+				    CAIRO_ANTIALIAS_NONE);
 
     _cairo_traps_fini (&traps);
 
@@ -206,12 +751,12 @@
     if (status)
 	return status;
 
-    status = _cairo_gstate_clip_and_composite (surface->clip, op,
-					       source,
-					       _cairo_surface_mask_draw_func,
-					       mask,
-					       surface,
-					       &extents);
+    status = _clip_and_composite (surface->clip, op,
+				  source,
+				  _cairo_surface_mask_draw_func,
+				  mask,
+				  surface,
+				  &extents);
 
     return status;
 }
@@ -242,12 +787,12 @@
 	return status;
     }
 
-    _cairo_surface_clip_and_composite_trapezoids (source,
-						  op,
-						  surface,
-						  &traps,
-						  surface->clip,
-						  antialias);
+    _clip_and_composite_trapezoids (source,
+				    op,
+				    surface,
+				    &traps,
+				    surface->clip,
+				    antialias);
 
     _cairo_traps_fini (&traps);
 
@@ -277,12 +822,12 @@
 	return status;
     }
 
-    status = _cairo_surface_clip_and_composite_trapezoids (source,
-							   op,
-							   surface,
-							   &traps,
-							   surface->clip,
-							   antialias);
+    status = _clip_and_composite_trapezoids (source,
+					     op,
+					     surface,
+					     &traps,
+					     surface->clip,
+					     antialias);
 
     _cairo_traps_fini (&traps);
 
@@ -389,13 +934,13 @@
     glyph_info.glyphs = glyphs;
     glyph_info.num_glyphs = num_glyphs;
     
-    status = _cairo_gstate_clip_and_composite (surface->clip,
-					       op,
-					       source,
-					       _cairo_surface_old_show_glyphs_draw_func,
-					       &glyph_info,
-					       surface,
-					       &extents);
+    status = _clip_and_composite (surface->clip,
+				  op,
+				  source,
+				  _cairo_surface_old_show_glyphs_draw_func,
+				  &glyph_info,
+				  surface,
+				  &extents);
     
     return status;
 }

Index: cairoint.h
===================================================================
RCS file: /cvs/cairo/cairo/src/cairoint.h,v
retrieving revision 1.235
retrieving revision 1.236
diff -u -d -r1.235 -r1.236
--- cairoint.h	19 Dec 2005 01:20:06 -0000	1.235
+++ cairoint.h	20 Dec 2005 17:37:15 -0000	1.236
@@ -1297,23 +1297,6 @@
 			  int		      num_glyphs,
 			  cairo_path_fixed_t *path);
 
-typedef cairo_status_t (*cairo_draw_func_t) (void                    *closure,
-					     cairo_operator_t         op,
-					     cairo_pattern_t         *src,
-					     cairo_surface_t         *dst,
-					     int                      dst_x,
-					     int                      dst_y,
-					     const cairo_rectangle_t *extents);
-
-cairo_private cairo_status_t
-_cairo_gstate_clip_and_composite (cairo_clip_t            *clip,
-				  cairo_operator_t         op,
-				  cairo_pattern_t         *src,
-				  cairo_draw_func_t        draw_func,
-				  void                    *draw_closure,
-				  cairo_surface_t         *dst,
-				  const cairo_rectangle_t *extents);
-
 cairo_private cairo_bool_t
 _cairo_operator_bounded_by_mask (cairo_operator_t op);
 
@@ -1715,14 +1698,6 @@
 				     int		ntraps);
 
 cairo_private cairo_status_t
-_cairo_surface_clip_and_composite_trapezoids (cairo_pattern_t *src,
-					      cairo_operator_t op,
-					      cairo_surface_t *dst,
-					      cairo_traps_t *traps,
-					      cairo_clip_t *clip,
-					      cairo_antialias_t antialias);
-
-cairo_private cairo_status_t
 _cairo_surface_copy_page (cairo_surface_t *surface);
 
 cairo_private cairo_status_t



More information about the cairo-commit mailing list