[cairo-commit] 3 commits - src/cairo-composite-rectangles.c src/cairo-composite-rectangles-private.h src/cairo-pdf-surface.c src/cairo-ps-surface.c src/cairo-recording-surface.c

Chris Wilson ickle at kemper.freedesktop.org
Sat Aug 13 05:15:57 PDT 2011


 src/cairo-composite-rectangles-private.h |   12 -
 src/cairo-composite-rectangles.c         |   26 ++
 src/cairo-pdf-surface.c                  |  359 ++++++++++++++++++-------------
 src/cairo-ps-surface.c                   |   18 -
 src/cairo-recording-surface.c            |    7 
 5 files changed, 254 insertions(+), 168 deletions(-)

New commits:
commit 279f6ceb595412bef165a808f05caa3044ef102c
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Sat Aug 13 12:33:21 2011 +0100

    Only reduce the clip if it is not in active use for the operation
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/cairo-composite-rectangles-private.h b/src/cairo-composite-rectangles-private.h
index c6dac30..dd5bd41 100644
--- a/src/cairo-composite-rectangles-private.h
+++ b/src/cairo-composite-rectangles-private.h
@@ -53,11 +53,13 @@ CAIRO_BEGIN_DECLS
 struct _cairo_composite_rectangles {
     cairo_rectangle_int_t source;
     cairo_rectangle_int_t mask;
-    cairo_rectangle_int_t bounded; /* dst */
-    cairo_rectangle_int_t unbounded; /* clip */
+    cairo_rectangle_int_t destination;
+
+    cairo_rectangle_int_t bounded; /* source? IN mask? IN unbounded */
+    cairo_rectangle_int_t unbounded; /* destination IN clip */
     uint32_t is_bounded;
 
-    cairo_clip_t *clip;
+    cairo_clip_t *clip; /* clip will be reduced to the minimal container */
 };
 
 cairo_private cairo_int_status_t
@@ -108,6 +110,10 @@ cairo_private cairo_int_status_t
 _cairo_composite_rectangles_intersect_mask_extents (cairo_composite_rectangles_t *extents,
 						    const cairo_box_t *box);
 
+cairo_private cairo_bool_t
+_cairo_composite_rectangles_can_reduce_clip (cairo_composite_rectangles_t *composite,
+					     cairo_clip_t *clip);
+
 cairo_private void
 _cairo_composite_rectangles_fini (cairo_composite_rectangles_t *extents);
 
diff --git a/src/cairo-composite-rectangles.c b/src/cairo-composite-rectangles.c
index 439f453..6083973 100644
--- a/src/cairo-composite-rectangles.c
+++ b/src/cairo-composite-rectangles.c
@@ -54,11 +54,12 @@ _cairo_composite_rectangles_init (cairo_composite_rectangles_t *extents,
 				  const cairo_clip_t *clip)
 {
     extents->clip = NULL;
+    extents->destination = *unbounded;
 
     if (_cairo_clip_is_all_clipped (clip))
 	return FALSE;
 
-    extents->unbounded = *unbounded;
+    extents->unbounded = extents->destination;
     if (clip != NULL) {
 	if (! _cairo_rectangle_intersect (&extents->unbounded,
 					  _cairo_clip_get_extents (clip)))
@@ -247,3 +248,26 @@ _cairo_composite_rectangles_init_for_glyphs (cairo_composite_rectangles_t *exten
 
     return _cairo_composite_rectangles_intersect (extents, clip);
 }
+
+cairo_bool_t
+_cairo_composite_rectangles_can_reduce_clip (cairo_composite_rectangles_t *composite,
+					     cairo_clip_t *clip)
+{
+    cairo_rectangle_int_t extents;
+
+    if (clip == NULL)
+	return TRUE;
+
+    /* XXX In the not a region case, we could still search through the boxes */
+    if (! _cairo_clip_is_region (clip))
+	return FALSE;
+
+    extents = composite->destination;
+    if (composite->is_bounded & CAIRO_OPERATOR_BOUND_BY_SOURCE)
+	_cairo_rectangle_intersect (&extents, &composite->source);
+    if (composite->is_bounded & CAIRO_OPERATOR_BOUND_BY_MASK)
+	_cairo_rectangle_intersect (&extents, &composite->mask);
+
+    return cairo_region_contains_rectangle (_cairo_clip_get_region (clip),
+					    &extents) == CAIRO_REGION_OVERLAP_IN;
+}
diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c
index ca3a4d2..dd5f68c 100644
--- a/src/cairo-pdf-surface.c
+++ b/src/cairo-pdf-surface.c
@@ -5793,22 +5793,13 @@ _cairo_pdf_surface_set_clip (cairo_pdf_surface_t *surface,
 {
     cairo_clip_t *clip = composite->clip;
 
-    if (_cairo_clip_is_region (clip) &&
-	cairo_region_contains_rectangle (_cairo_clip_get_region (clip),
-					 &composite->unbounded) == CAIRO_REGION_OVERLAP_IN)
-    {
-	    clip = NULL;
-    }
+    if (_cairo_composite_rectangles_can_reduce_clip (composite, clip))
+	clip = NULL;
 
     if (clip == NULL) {
-	cairo_clip_t *current = surface->clipper.clip;
-
-	if (current && _cairo_clip_is_region (current) &&
-	    cairo_region_contains_rectangle (_cairo_clip_get_region (current),
-					     &composite->unbounded) == CAIRO_REGION_OVERLAP_IN)
-	{
+	if (_cairo_composite_rectangles_can_reduce_clip (composite,
+							 surface->clipper.clip))
 	    return CAIRO_STATUS_SUCCESS;
-	}
     }
 
     return _cairo_surface_clipper_set_clip (&surface->clipper, clip);
diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c
index 267fd59..a9961fe 100644
--- a/src/cairo-ps-surface.c
+++ b/src/cairo-ps-surface.c
@@ -3617,28 +3617,18 @@ _cairo_ps_surface_set_clip (cairo_ps_surface_t *surface,
 {
     cairo_clip_t *clip = composite->clip;
 
-    if (_cairo_clip_is_region (clip) &&
-	cairo_region_contains_rectangle (_cairo_clip_get_region (clip),
-					 &composite->unbounded) == CAIRO_REGION_OVERLAP_IN)
-    {
-	    clip = NULL;
-    }
+    if (_cairo_composite_rectangles_can_reduce_clip (composite, clip))
+	clip = NULL;
 
     if (clip == NULL) {
-	cairo_clip_t *current = surface->clipper.clip;
-
-	if (current && _cairo_clip_is_region (current) &&
-	    cairo_region_contains_rectangle (_cairo_clip_get_region (current),
-					     &composite->unbounded) == CAIRO_REGION_OVERLAP_IN)
-	{
+	if (_cairo_composite_rectangles_can_reduce_clip (composite,
+							 surface->clipper.clip))
 	    return CAIRO_STATUS_SUCCESS;
-	}
     }
 
     return _cairo_surface_clipper_set_clip (&surface->clipper, clip);
 }
 
-
 static cairo_int_status_t
 _cairo_ps_surface_paint (void			*abstract_surface,
 			 cairo_operator_t	 op,
diff --git a/src/cairo-recording-surface.c b/src/cairo-recording-surface.c
index 87b9119..0daf675 100644
--- a/src/cairo-recording-surface.c
+++ b/src/cairo-recording-surface.c
@@ -587,11 +587,8 @@ _command_init (cairo_recording_surface_t *surface,
 
     /* steal the clip */
     command->clip = NULL;
-    if (! _cairo_clip_is_region (composite->clip) ||
-	composite->mask.width > composite->unbounded.width ||
-	composite->mask.height > composite->unbounded.height ||
-	cairo_region_contains_rectangle (_cairo_clip_get_region (composite->clip),
-					 &composite->unbounded) != CAIRO_REGION_OVERLAP_IN)
+    if (! _cairo_composite_rectangles_can_reduce_clip (composite,
+						       composite->clip))
     {
 	command->clip = composite->clip;
 	composite->clip = NULL;
commit d391f0908c404344aa6873fbca2b7bd6499009e0
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Sat Aug 13 12:26:30 2011 +0100

    pdf: composite-rectangles now require freeing after use
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c
index da6e8f5..ca3a4d2 100644
--- a/src/cairo-pdf-surface.c
+++ b/src/cairo-pdf-surface.c
@@ -5834,26 +5834,27 @@ _cairo_pdf_surface_paint (void			*abstract_surface,
 	return status;
 
     if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
-	return _cairo_pdf_surface_analyze_operation (surface, op, source, &extents.bounded);
+	status = _cairo_pdf_surface_analyze_operation (surface, op, source, &extents.bounded);
+	goto cleanup;
     } else if (surface->paginated_mode == CAIRO_PAGINATED_MODE_FALLBACK) {
 	status = _cairo_pdf_surface_start_fallback (surface);
 	if (unlikely (status))
-	    return status;
+	    goto cleanup;
     }
 
     assert (_cairo_pdf_surface_operation_supported (surface, op, source, &extents.bounded));
 
     status = _cairo_pdf_surface_set_clip (surface, &extents);
     if (unlikely (status))
-	return status;
+	goto cleanup;
 
     status = _cairo_pdf_surface_select_operator (surface, op);
     if (unlikely (status))
-	return status;
+	goto cleanup;
 
     status = _cairo_pdf_operators_flush (&surface->pdf_operators);
     if (unlikely (status))
-	return status;
+	goto cleanup;
 
     if (source->type == CAIRO_PATTERN_TYPE_SURFACE &&
 	source->extend == CAIRO_EXTEND_NONE)
@@ -5863,9 +5864,10 @@ _cairo_pdf_surface_paint (void			*abstract_surface,
 							   (cairo_surface_pattern_t *) source,
 							   FALSE);
 	if (unlikely (status))
-	    return status;
+	    goto cleanup;
 
 	_cairo_output_stream_printf (surface->output, "Q\n");
+	_cairo_composite_rectangles_fini (&extents);
 	return _cairo_output_stream_get_status (surface->output);
     }
 
@@ -5875,33 +5877,35 @@ _cairo_pdf_surface_paint (void			*abstract_surface,
 						 &extents.bounded,
 						 &pattern_res, &gstate_res);
     if (unlikely (status))
-	return status;
+	goto cleanup;
 
     if (gstate_res.id != 0) {
 	group = _cairo_pdf_surface_create_smask_group (surface);
-	if (unlikely (group == NULL))
-	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+	if (unlikely (group == NULL)) {
+	    status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+	    goto cleanup;
+	}
 
 	group->operation = PDF_PAINT;
 	status = _cairo_pattern_create_copy (&group->source, source);
 	if (unlikely (status)) {
 	    _cairo_pdf_smask_group_destroy (group);
-	    return status;
+	    goto cleanup;
 	}
 	group->source_res = pattern_res;
 	status = _cairo_pdf_surface_add_smask_group (surface, group);
 	if (unlikely (status)) {
 	    _cairo_pdf_smask_group_destroy (group);
-	    return status;
+	    goto cleanup;
 	}
 
 	status = _cairo_pdf_surface_add_smask (surface, gstate_res);
 	if (unlikely (status))
-	    return status;
+	    goto cleanup;
 
 	status = _cairo_pdf_surface_add_xobject (surface, group->group_res);
 	if (unlikely (status))
-	    return status;
+	    goto cleanup;
 
 	_cairo_output_stream_printf (surface->output,
 				     "q /s%d gs /x%d Do Q\n",
@@ -5911,7 +5915,7 @@ _cairo_pdf_surface_paint (void			*abstract_surface,
 	status = _cairo_pdf_surface_select_pattern (surface, source,
 						    pattern_res, FALSE);
 	if (unlikely (status))
-	    return status;
+	    goto cleanup;
 
 	_cairo_output_stream_printf (surface->output,
 				     "0 0 %f %f re f\n",
@@ -5919,10 +5923,15 @@ _cairo_pdf_surface_paint (void			*abstract_surface,
 
 	status = _cairo_pdf_surface_unselect_pattern (surface);
 	if (unlikely (status))
-	    return status;
+	    goto cleanup;
     }
 
+    _cairo_composite_rectangles_fini (&extents);
     return _cairo_output_stream_get_status (surface->output);
+
+cleanup:
+    _cairo_composite_rectangles_fini (&extents);
+    return status;
 }
 
 static cairo_int_status_t
@@ -5947,24 +5956,27 @@ _cairo_pdf_surface_mask (void			*abstract_surface,
     if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
 	cairo_status_t source_status, mask_status;
 
-	source_status = _cairo_pdf_surface_analyze_operation (surface, op, source, &extents.bounded);
-	if (_cairo_status_is_error (source_status))
-	    return source_status;
+	status = _cairo_pdf_surface_analyze_operation (surface, op, source, &extents.bounded);
+	if (_cairo_status_is_error (status))
+	    goto cleanup;
+	source_status = status;
 
 	if (mask->has_component_alpha) {
-	    mask_status = CAIRO_INT_STATUS_UNSUPPORTED;
+	    status = CAIRO_INT_STATUS_UNSUPPORTED;
 	} else {
-	    mask_status = _cairo_pdf_surface_analyze_operation (surface, op, mask, &extents.bounded);
-	    if (_cairo_status_is_error (mask_status))
-		return mask_status;
+	    status = _cairo_pdf_surface_analyze_operation (surface, op, mask, &extents.bounded);
+	    if (_cairo_status_is_error (status))
+		goto cleanup;
 	}
+	mask_status = status;
 
+	_cairo_composite_rectangles_fini (&extents);
 	return _cairo_analysis_surface_merge_status (source_status,
 						     mask_status);
     } else if (surface->paginated_mode == CAIRO_PAGINATED_MODE_FALLBACK) {
 	status = _cairo_pdf_surface_start_fallback (surface);
 	if (unlikely (status))
-	    return status;
+	    goto cleanup;
     }
 
     assert (_cairo_pdf_surface_operation_supported (surface, op, source, &extents.bounded));
@@ -5972,62 +5984,70 @@ _cairo_pdf_surface_mask (void			*abstract_surface,
 
     status = _cairo_pdf_surface_set_clip (surface, &extents);
     if (unlikely (status))
-	return status;
+	goto cleanup;
 
     status = _cairo_pdf_surface_select_operator (surface, op);
     if (unlikely (status))
-	return status;
+	goto cleanup;
 
     /* Check if we can use a stencil mask */
     status = _cairo_pdf_surface_emit_stencil_mask (surface, source, mask);
     if (status != CAIRO_INT_STATUS_UNSUPPORTED)
-	return status;
+	goto cleanup;
 
     group = _cairo_pdf_surface_create_smask_group (surface);
-    if (unlikely (group == NULL))
-	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+    if (unlikely (group == NULL)) {
+	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+	goto cleanup;
+    }
 
     group->operation = PDF_MASK;
     status = _cairo_pattern_create_copy (&group->source, source);
     if (unlikely (status)) {
 	_cairo_pdf_smask_group_destroy (group);
-	return status;
+	goto cleanup;
     }
     status = _cairo_pattern_create_copy (&group->mask, mask);
     if (unlikely (status)) {
 	_cairo_pdf_smask_group_destroy (group);
-	return status;
+	goto cleanup;
     }
     group->source_res = _cairo_pdf_surface_new_object (surface);
     if (group->source_res.id == 0) {
 	_cairo_pdf_smask_group_destroy (group);
-	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+	goto cleanup;
     }
 
     status = _cairo_pdf_surface_add_smask_group (surface, group);
     if (unlikely (status)) {
 	_cairo_pdf_smask_group_destroy (group);
-	return status;
+	goto cleanup;
     }
 
     status = _cairo_pdf_surface_add_smask (surface, group->group_res);
     if (unlikely (status))
-	return status;
+	goto cleanup;
 
     status = _cairo_pdf_surface_add_xobject (surface, group->source_res);
     if (unlikely (status))
-	return status;
+	goto cleanup;
 
     status = _cairo_pdf_operators_flush (&surface->pdf_operators);
     if (unlikely (status))
-	return status;
+	goto cleanup;
 
     _cairo_output_stream_printf (surface->output,
 				 "q /s%d gs /x%d Do Q\n",
 				 group->group_res.id,
 				 group->source_res.id);
 
+    _cairo_composite_rectangles_fini (&extents);
     return _cairo_output_stream_get_status (surface->output);
+
+cleanup:
+    _cairo_composite_rectangles_fini (&extents);
+    return status;
 }
 
 static cairo_int_status_t
@@ -6059,25 +6079,33 @@ _cairo_pdf_surface_stroke (void			*abstract_surface,
 
     /* use the more accurate extents */
     if (extents.is_bounded) {
+	cairo_rectangle_int_t mask;
+	cairo_box_t box;
+
 	status = _cairo_path_fixed_stroke_extents (path, style,
 						   ctm, ctm_inverse,
 						   tolerance,
-						   &extents.mask);
+						   &mask);
 	if (unlikely (status))
-	    return status;
+	    goto cleanup;
 
-	if (! _cairo_rectangle_intersect (&extents.bounded, &extents.mask))
-	    return CAIRO_INT_STATUS_SUCCESS;
+	_cairo_box_from_rectangle (&box, &mask);
+	status = _cairo_composite_rectangles_intersect_mask_extents (&extents,
+								     &box);
+	if (unlikely (status))
+	    goto cleanup;
     }
 
-    if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
-	return _cairo_pdf_surface_analyze_operation (surface, op, source, &extents.bounded);
+    if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
+	status = _cairo_pdf_surface_analyze_operation (surface, op, source, &extents.bounded);
+	goto cleanup;
+    }
 
     assert (_cairo_pdf_surface_operation_supported (surface, op, source, &extents.bounded));
 
     status = _cairo_pdf_surface_set_clip (surface, &extents);
     if (unlikely (status))
-	return status;
+	goto cleanup;
 
     pattern_res.id = 0;
     gstate_res.id = 0;
@@ -6085,28 +6113,30 @@ _cairo_pdf_surface_stroke (void			*abstract_surface,
 						 &extents.bounded,
 						 &pattern_res, &gstate_res);
     if (unlikely (status))
-	return status;
+	goto cleanup;
 
     status = _cairo_pdf_surface_select_operator (surface, op);
     if (unlikely (status))
-	return status;
+	goto cleanup;
 
     if (gstate_res.id != 0) {
 	group = _cairo_pdf_surface_create_smask_group (surface);
-	if (unlikely (group == NULL))
-	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+	if (unlikely (group == NULL)) {
+	    status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+	    goto cleanup;
+	}
 
 	group->operation = PDF_STROKE;
 	status = _cairo_pattern_create_copy (&group->source, source);
 	if (unlikely (status)) {
 	    _cairo_pdf_smask_group_destroy (group);
-	    return status;
+	    goto cleanup;
 	}
 	group->source_res = pattern_res;
 	status = _cairo_path_fixed_init_copy (&group->path, path);
 	if (unlikely (status)) {
 	    _cairo_pdf_smask_group_destroy (group);
-	    return status;
+	    goto cleanup;
 	}
 
 	group->style = *style;
@@ -6115,20 +6145,20 @@ _cairo_pdf_surface_stroke (void			*abstract_surface,
 	status = _cairo_pdf_surface_add_smask_group (surface, group);
 	if (unlikely (status)) {
 	    _cairo_pdf_smask_group_destroy (group);
-	    return status;
+	    goto cleanup;
 	}
 
 	status = _cairo_pdf_surface_add_smask (surface, gstate_res);
 	if (unlikely (status))
-	    return status;
+	    goto cleanup;
 
 	status = _cairo_pdf_surface_add_xobject (surface, group->group_res);
 	if (unlikely (status))
-	    return status;
+	    goto cleanup;
 
 	status = _cairo_pdf_operators_flush (&surface->pdf_operators);
 	if (unlikely (status))
-	    return status;
+	    goto cleanup;
 
 	_cairo_output_stream_printf (surface->output,
 				     "q /s%d gs /x%d Do Q\n",
@@ -6137,7 +6167,7 @@ _cairo_pdf_surface_stroke (void			*abstract_surface,
     } else {
 	status = _cairo_pdf_surface_select_pattern (surface, source, pattern_res, TRUE);
 	if (unlikely (status))
-	    return status;
+	    goto cleanup;
 
 	status = _cairo_pdf_operators_stroke (&surface->pdf_operators,
 					      path,
@@ -6145,14 +6175,19 @@ _cairo_pdf_surface_stroke (void			*abstract_surface,
 					      ctm,
 					      ctm_inverse);
 	if (unlikely (status))
-	    return status;
+	    goto cleanup;
 
 	status = _cairo_pdf_surface_unselect_pattern (surface);
 	if (unlikely (status))
-	    return status;
+	    goto cleanup;
     }
 
+    _cairo_composite_rectangles_fini (&extents);
     return _cairo_output_stream_get_status (surface->output);
+
+cleanup:
+    _cairo_composite_rectangles_fini (&extents);
+    return status;
 }
 
 static cairo_int_status_t
@@ -6181,55 +6216,63 @@ _cairo_pdf_surface_fill (void			*abstract_surface,
 
     /* use the more accurate extents */
     if (extents.is_bounded) {
+	cairo_rectangle_int_t mask;
+	cairo_box_t box;
+
 	_cairo_path_fixed_fill_extents (path,
 					fill_rule,
 					tolerance,
-					&extents.mask);
+					&mask);
 
-	if (! _cairo_rectangle_intersect (&extents.bounded, &extents.mask))
-	    return CAIRO_INT_STATUS_SUCCESS;
+	_cairo_box_from_rectangle (&box, &mask);
+	status = _cairo_composite_rectangles_intersect_mask_extents (&extents,
+								     &box);
+	if (unlikely (status))
+	    goto cleanup;
     }
 
     if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
-	return _cairo_pdf_surface_analyze_operation (surface, op, source, &extents.bounded);
+	status = _cairo_pdf_surface_analyze_operation (surface, op, source, &extents.bounded);
+	goto cleanup;
     } else if (surface->paginated_mode == CAIRO_PAGINATED_MODE_FALLBACK) {
 	status = _cairo_pdf_surface_start_fallback (surface);
 	if (unlikely (status))
-	    return status;
+	    goto cleanup;
     }
 
     assert (_cairo_pdf_surface_operation_supported (surface, op, source, &extents.bounded));
 
     status = _cairo_pdf_surface_set_clip (surface, &extents);
     if (unlikely (status))
-	return status;
+	goto cleanup;
 
     status = _cairo_pdf_surface_select_operator (surface, op);
     if (unlikely (status))
-	return status;
+	goto cleanup;
 
     if (source->type == CAIRO_PATTERN_TYPE_SURFACE &&
 	source->extend == CAIRO_EXTEND_NONE)
     {
 	status = _cairo_pdf_operators_flush (&surface->pdf_operators);
 	if (unlikely (status))
-	    return status;
+	    goto cleanup;
 
 	_cairo_output_stream_printf (surface->output, "q\n");
 	status =  _cairo_pdf_operators_clip (&surface->pdf_operators,
 					     path,
 					     fill_rule);
 	if (unlikely (status))
-	    return status;
+	    goto cleanup;
 
 	status = _cairo_pdf_surface_paint_surface_pattern (surface,
 							   (cairo_surface_pattern_t *) source,
 							   FALSE);
 	if (unlikely (status))
-	    return status;
+	    goto cleanup;
 
 	_cairo_output_stream_printf (surface->output, "Q\n");
-	return _cairo_output_stream_get_status (surface->output);
+	status = _cairo_output_stream_get_status (surface->output);
+	goto cleanup;
     }
 
     pattern_res.id = 0;
@@ -6238,44 +6281,46 @@ _cairo_pdf_surface_fill (void			*abstract_surface,
 						 &extents.bounded,
 						 &pattern_res, &gstate_res);
     if (unlikely (status))
-	return status;
+	goto cleanup;
 
     if (gstate_res.id != 0) {
 	group = _cairo_pdf_surface_create_smask_group (surface);
-	if (unlikely (group == NULL))
-	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+	if (unlikely (group == NULL)) {
+	    status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+	    goto cleanup;
+	}
 
 	group->operation = PDF_FILL;
 	status = _cairo_pattern_create_copy (&group->source, source);
 	if (unlikely (status)) {
 	    _cairo_pdf_smask_group_destroy (group);
-	    return status;
+	    goto cleanup;
 	}
 	group->source_res = pattern_res;
 	status = _cairo_path_fixed_init_copy (&group->path, path);
 	if (unlikely (status)) {
 	    _cairo_pdf_smask_group_destroy (group);
-	    return status;
+	    goto cleanup;
 	}
 
 	group->fill_rule = fill_rule;
 	status = _cairo_pdf_surface_add_smask_group (surface, group);
 	if (unlikely (status)) {
 	    _cairo_pdf_smask_group_destroy (group);
-	    return status;
+	    goto cleanup;
 	}
 
 	status = _cairo_pdf_surface_add_smask (surface, gstate_res);
 	if (unlikely (status))
-	    return status;
+	    goto cleanup;
 
 	status = _cairo_pdf_surface_add_xobject (surface, group->group_res);
 	if (unlikely (status))
-	    return status;
+	    goto cleanup;
 
 	status = _cairo_pdf_operators_flush (&surface->pdf_operators);
 	if (unlikely (status))
-	    return status;
+	    goto cleanup;
 
 	_cairo_output_stream_printf (surface->output,
 				     "q /s%d gs /x%d Do Q\n",
@@ -6284,20 +6329,25 @@ _cairo_pdf_surface_fill (void			*abstract_surface,
     } else {
 	status = _cairo_pdf_surface_select_pattern (surface, source, pattern_res, FALSE);
 	if (unlikely (status))
-	    return status;
+	    goto cleanup;
 
 	status = _cairo_pdf_operators_fill (&surface->pdf_operators,
 					    path,
 					    fill_rule);
 	if (unlikely (status))
-	    return status;
+	    goto cleanup;
 
 	status = _cairo_pdf_surface_unselect_pattern (surface);
 	if (unlikely (status))
-	    return status;
+	    goto cleanup;
     }
 
+    _cairo_composite_rectangles_fini (&extents);
     return _cairo_output_stream_get_status (surface->output);
+
+cleanup:
+    _cairo_composite_rectangles_fini (&extents);
+    return status;
 }
 
 static cairo_int_status_t
@@ -6358,32 +6408,46 @@ _cairo_pdf_surface_fill_stroke (void			*abstract_surface,
 
     /* use the more accurate extents */
     if (extents.is_bounded) {
+	cairo_rectangle_int_t mask;
+	cairo_box_t box;
+
 	status = _cairo_path_fixed_stroke_extents (path, stroke_style,
 						   stroke_ctm, stroke_ctm_inverse,
 						   stroke_tolerance,
-						   &extents.mask);
+						   &mask);
 	if (unlikely (status))
-	    return status;
+	    goto cleanup;
 
-	_cairo_rectangle_intersect (&extents.bounded, &extents.mask);
+	_cairo_box_from_rectangle (&box, &mask);
+	status = _cairo_composite_rectangles_intersect_mask_extents (&extents,
+								     &box);
+	if (unlikely (status))
+	    goto cleanup;
     }
 
     status = _cairo_pdf_surface_set_clip (surface, &extents);
     if (unlikely (status))
-	return status;
+	goto cleanup;
 
     status = _cairo_pdf_surface_select_operator (surface, fill_op);
     if (unlikely (status))
-	return status;
+	goto cleanup;
 
     /* use the more accurate extents */
     if (extents.is_bounded) {
+	cairo_rectangle_int_t mask;
+	cairo_box_t box;
+
 	_cairo_path_fixed_fill_extents (path,
 					fill_rule,
 					fill_tolerance,
-					&extents.mask);
+					&mask);
 
-	_cairo_rectangle_intersect (&extents.bounded, &extents.mask);
+	_cairo_box_from_rectangle (&box, &mask);
+	status = _cairo_composite_rectangles_intersect_mask_extents (&extents,
+								     &box);
+	if (unlikely (status))
+	    goto cleanup;
     }
 
     fill_pattern_res.id = 0;
@@ -6393,7 +6457,7 @@ _cairo_pdf_surface_fill_stroke (void			*abstract_surface,
 						 &fill_pattern_res,
 						 &gstate_res);
     if (unlikely (status))
-	return status;
+	goto cleanup;
 
     assert (gstate_res.id == 0);
 
@@ -6405,7 +6469,7 @@ _cairo_pdf_surface_fill_stroke (void			*abstract_surface,
 						 &stroke_pattern_res,
 						 &gstate_res);
     if (unlikely (status))
-	return status;
+	goto cleanup;
 
     assert (gstate_res.id == 0);
 
@@ -6414,12 +6478,12 @@ _cairo_pdf_surface_fill_stroke (void			*abstract_surface,
     status = _cairo_pdf_surface_select_pattern (surface, fill_source,
 						fill_pattern_res, FALSE);
     if (unlikely (status))
-	return status;
+	goto cleanup;
 
     status = _cairo_pdf_surface_select_pattern (surface, stroke_source,
 						stroke_pattern_res, TRUE);
     if (unlikely (status))
-	return status;
+	goto cleanup;
 
     status = _cairo_pdf_operators_fill_stroke (&surface->pdf_operators,
 					       path,
@@ -6428,13 +6492,18 @@ _cairo_pdf_surface_fill_stroke (void			*abstract_surface,
 					       stroke_ctm,
 					       stroke_ctm_inverse);
     if (unlikely (status))
-	return status;
+	goto cleanup;
 
     status = _cairo_pdf_surface_unselect_pattern (surface);
     if (unlikely (status))
-	return status;
+	goto cleanup;
 
+    _cairo_composite_rectangles_fini (&extents);
     return _cairo_output_stream_get_status (surface->output);
+
+cleanup:
+    _cairo_composite_rectangles_fini (&extents);
+    return status;
 }
 
 static cairo_bool_t
@@ -6475,14 +6544,16 @@ _cairo_pdf_surface_show_text_glyphs (void			*abstract_surface,
     if (unlikely (status))
 	return status;
 
-    if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
-	return _cairo_pdf_surface_analyze_operation (surface, op, source, &extents.bounded);
+    if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
+	status = _cairo_pdf_surface_analyze_operation (surface, op, source, &extents.bounded);
+	goto cleanup;
+    }
 
     assert (_cairo_pdf_surface_operation_supported (surface, op, source, &extents.bounded));
 
     status = _cairo_pdf_surface_set_clip (surface, &extents);
     if (unlikely (status))
-	return status;
+	goto cleanup;
 
     pattern_res.id = 0;
     gstate_res.id = 0;
@@ -6490,22 +6561,24 @@ _cairo_pdf_surface_show_text_glyphs (void			*abstract_surface,
 						 &extents.bounded,
 						 &pattern_res, &gstate_res);
     if (unlikely (status))
-	return status;
+	goto cleanup;
 
     status = _cairo_pdf_surface_select_operator (surface, op);
     if (unlikely (status))
-	return status;
+	goto cleanup;
 
     if (gstate_res.id != 0) {
 	group = _cairo_pdf_surface_create_smask_group (surface);
-	if (unlikely (group == NULL))
-	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+	if (unlikely (group == NULL)) {
+	    status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+	    goto cleanup;
+	}
 
 	group->operation = PDF_SHOW_GLYPHS;
 	status = _cairo_pattern_create_copy (&group->source, source);
 	if (unlikely (status)) {
 	    _cairo_pdf_smask_group_destroy (group);
-	    return status;
+	    goto cleanup;
 	}
 	group->source_res = pattern_res;
 
@@ -6513,7 +6586,8 @@ _cairo_pdf_surface_show_text_glyphs (void			*abstract_surface,
 	    group->utf8 = malloc (utf8_len);
 	    if (unlikely (group->utf8 == NULL)) {
 		_cairo_pdf_smask_group_destroy (group);
-		return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+		status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+		goto cleanup;
 	    }
 	    memcpy (group->utf8, utf8, utf8_len);
 	}
@@ -6523,7 +6597,8 @@ _cairo_pdf_surface_show_text_glyphs (void			*abstract_surface,
 	    group->glyphs = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t));
 	    if (unlikely (group->glyphs == NULL)) {
 		_cairo_pdf_smask_group_destroy (group);
-		return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+		status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+		goto cleanup;
 	    }
 	    memcpy (group->glyphs, glyphs, sizeof (cairo_glyph_t) * num_glyphs);
 	}
@@ -6533,7 +6608,8 @@ _cairo_pdf_surface_show_text_glyphs (void			*abstract_surface,
 	    group->clusters = _cairo_malloc_ab (num_clusters, sizeof (cairo_text_cluster_t));
 	    if (unlikely (group->clusters == NULL)) {
 		_cairo_pdf_smask_group_destroy (group);
-		return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+		status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+		goto cleanup;
 	    }
 	    memcpy (group->clusters, clusters, sizeof (cairo_text_cluster_t) * num_clusters);
 	}
@@ -6543,20 +6619,20 @@ _cairo_pdf_surface_show_text_glyphs (void			*abstract_surface,
 	status = _cairo_pdf_surface_add_smask_group (surface, group);
 	if (unlikely (status)) {
 	    _cairo_pdf_smask_group_destroy (group);
-	    return status;
+	    goto cleanup;
 	}
 
 	status = _cairo_pdf_surface_add_smask (surface, gstate_res);
 	if (unlikely (status))
-	    return status;
+	    goto cleanup;
 
 	status = _cairo_pdf_surface_add_xobject (surface, group->group_res);
 	if (unlikely (status))
-	    return status;
+	    goto cleanup;
 
 	status = _cairo_pdf_operators_flush (&surface->pdf_operators);
 	if (unlikely (status))
-	    return status;
+	    goto cleanup;
 
 	_cairo_output_stream_printf (surface->output,
 				     "q /s%d gs /x%d Do Q\n",
@@ -6565,7 +6641,7 @@ _cairo_pdf_surface_show_text_glyphs (void			*abstract_surface,
     } else {
 	status = _cairo_pdf_surface_select_pattern (surface, source, pattern_res, FALSE);
 	if (unlikely (status))
-	    return status;
+	    goto cleanup;
 
 	/* Each call to show_glyphs() with a transclucent pattern must
 	 * be in a separate text object otherwise overlapping text
@@ -6574,7 +6650,7 @@ _cairo_pdf_surface_show_text_glyphs (void			*abstract_surface,
 	if (! _cairo_pattern_is_opaque (source, &extents.bounded)) {
 	    status = _cairo_pdf_operators_flush (&surface->pdf_operators);
 	    if (unlikely (status))
-		return status;
+		goto cleanup;
 	}
 
 	status = _cairo_pdf_operators_show_text_glyphs (&surface->pdf_operators,
@@ -6584,14 +6660,19 @@ _cairo_pdf_surface_show_text_glyphs (void			*abstract_surface,
 							cluster_flags,
 							scaled_font);
 	if (unlikely (status))
-	    return status;
+	    goto cleanup;
 
 	status = _cairo_pdf_surface_unselect_pattern (surface);
 	if (unlikely (status))
-	    return status;
+	    goto cleanup;
     }
 
+    _cairo_composite_rectangles_fini (&extents);
     return _cairo_output_stream_get_status (surface->output);
+
+cleanup:
+    _cairo_composite_rectangles_fini (&extents);
+    return status;
 }
 
 
commit afe84fa77f392a9748319efee01db6b3c6d870fb
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Sat Aug 13 12:09:08 2011 +0100

    pdf: Compute fill-stroke extents first before trying to use it to set the clip
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c
index 3a10ef3..da6e8f5 100644
--- a/src/cairo-pdf-surface.c
+++ b/src/cairo-pdf-surface.c
@@ -6345,18 +6345,34 @@ _cairo_pdf_surface_fill_stroke (void			*abstract_surface,
     if (fill_op != stroke_op)
 	return CAIRO_INT_STATUS_UNSUPPORTED;
 
-    status = _cairo_pdf_surface_set_clip (surface, &extents);
+    /* Compute the operation extents using the stroke which will naturally
+     * be larger than the fill extents.
+     */
+    _cairo_pdf_surface_get_extents (surface, &unbounded);
+    status = _cairo_composite_rectangles_init_for_stroke (&extents, &unbounded,
+							  stroke_op, stroke_source,
+							  path, stroke_style, stroke_ctm,
+							  clip);
     if (unlikely (status))
 	return status;
 
-    status = _cairo_pdf_surface_select_operator (surface, fill_op);
+    /* use the more accurate extents */
+    if (extents.is_bounded) {
+	status = _cairo_path_fixed_stroke_extents (path, stroke_style,
+						   stroke_ctm, stroke_ctm_inverse,
+						   stroke_tolerance,
+						   &extents.mask);
+	if (unlikely (status))
+	    return status;
+
+	_cairo_rectangle_intersect (&extents.bounded, &extents.mask);
+    }
+
+    status = _cairo_pdf_surface_set_clip (surface, &extents);
     if (unlikely (status))
 	return status;
 
-    _cairo_pdf_surface_get_extents (surface, &unbounded);
-    status = _cairo_composite_rectangles_init_for_fill (&extents, &unbounded,
-							fill_op, fill_source, path,
-							clip);
+    status = _cairo_pdf_surface_select_operator (surface, fill_op);
     if (unlikely (status))
 	return status;
 
@@ -6381,25 +6397,6 @@ _cairo_pdf_surface_fill_stroke (void			*abstract_surface,
 
     assert (gstate_res.id == 0);
 
-    status = _cairo_composite_rectangles_init_for_stroke (&extents, &unbounded,
-							  stroke_op, stroke_source,
-							  path, stroke_style, stroke_ctm,
-							  clip);
-    if (unlikely (status))
-	return status;
-
-    /* use the more accurate extents */
-    if (extents.is_bounded) {
-	status = _cairo_path_fixed_stroke_extents (path, stroke_style,
-						   stroke_ctm, stroke_ctm_inverse,
-						   stroke_tolerance,
-						   &extents.mask);
-	if (unlikely (status))
-	    return status;
-
-	_cairo_rectangle_intersect (&extents.bounded, &extents.mask);
-    }
-
     stroke_pattern_res.id = 0;
     gstate_res.id = 0;
     status = _cairo_pdf_surface_add_pdf_pattern (surface,


More information about the cairo-commit mailing list