[cairo-commit] src/cairo-svg-surface.c

Chris Wilson ickle at kemper.freedesktop.org
Thu Oct 4 16:45:10 PDT 2007


 src/cairo-svg-surface.c |  376 ++++++++++++++++++++++++++++++++++--------------
 1 file changed, 272 insertions(+), 104 deletions(-)

New commits:
diff-tree bd2245f8b87d85f5ea61200838c10de70e776cf5 (from 853b29c56fdb50c627b27fc3a767300c7551dba0)
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Fri Oct 5 00:45:00 2007 +0100

    [cairo-svg-surface] Review error propagation.
    
    Ensure that the error status is propagated and all local resources
    are freed on the error path.

diff --git a/src/cairo-svg-surface.c b/src/cairo-svg-surface.c
index cc909f5..6ec33d7 100644
--- a/src/cairo-svg-surface.c
+++ b/src/cairo-svg-surface.c
@@ -124,7 +124,7 @@ _cairo_svg_document_create (cairo_output
 			    double		     height,
 			    cairo_svg_version_t	     version);
 
-static void
+static cairo_status_t
 _cairo_svg_document_destroy (cairo_svg_document_t *document);
 
 static cairo_status_t
@@ -331,6 +331,8 @@ _cairo_svg_surface_create_for_document (
 					double			 height)
 {
     cairo_svg_surface_t *surface;
+    cairo_surface_t *paginated;
+    cairo_status_t status;
 
     surface = malloc (sizeof (cairo_svg_surface_t));
     if (surface == NULL) {
@@ -353,6 +355,9 @@ _cairo_svg_surface_create_for_document (
     surface->is_base_clip_emitted = FALSE;
 
     surface->xml_node = _cairo_memory_stream_create ();
+    if (_cairo_output_stream_get_status (surface->xml_node))
+	goto CLEANUP_DOCUMENT;
+
     _cairo_array_init (&surface->page_set, sizeof (cairo_svg_page_t));
 
     if (content == CAIRO_CONTENT_COLOR) {
@@ -361,16 +366,31 @@ _cairo_svg_surface_create_for_document (
 				     "style=\"opacity: 1; stroke: none; "
 				     "fill: rgb(0,0,0);\"/>\n",
 				     width, height);
+	if (_cairo_output_stream_get_status (surface->xml_node))
+	    goto CLEANUP_STREAM;
     }
 
     surface->paginated_mode = CAIRO_PAGINATED_MODE_ANALYZE;
     surface->force_fallbacks = FALSE;
     surface->content = content;
 
-    return _cairo_paginated_surface_create (&surface->base,
-					    surface->content,
-					    surface->width, surface->height,
-					    &cairo_svg_surface_paginated_backend);
+    paginated = _cairo_paginated_surface_create (&surface->base,
+					         surface->content,
+					         surface->width,
+						 surface->height,
+						 &cairo_svg_surface_paginated_backend);
+    if (! paginated->status)
+	return paginated;
+
+    /* ignore status as we are on the error path */
+CLEANUP_STREAM:
+    status = _cairo_output_stream_destroy (surface->xml_node);
+CLEANUP_DOCUMENT:
+    status = _cairo_svg_document_destroy (document);
+
+    free (surface);
+    _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
+    return (cairo_surface_t*) &_cairo_surface_nil;
 }
 
 static cairo_surface_t *
@@ -381,18 +401,27 @@ _cairo_svg_surface_create_for_stream_int
 {
     cairo_svg_document_t *document;
     cairo_surface_t *surface;
+    cairo_status_t status;
 
     document = _cairo_svg_document_create (stream, width, height, version);
     if (document == NULL) {
+	/* consume the output stream on behalf of caller */
+	status = _cairo_output_stream_destroy (stream);
 	_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
 	return (cairo_surface_t *) &_cairo_surface_nil;
     }
 
     surface = _cairo_svg_surface_create_for_document (document, CAIRO_CONTENT_COLOR_ALPHA,
 						      width, height);
+    if (surface->status) {
+	status = _cairo_svg_document_destroy (document);
+	return (cairo_surface_t *) &_cairo_surface_nil;
+    }
 
     document->owner = surface;
-    _cairo_svg_document_destroy (document);
+    status = _cairo_svg_document_destroy (document);
+    /* the ref count should be 2 at this point */
+    assert (status == CAIRO_STATUS_SUCCESS);
 
     return surface;
 }
@@ -402,20 +431,29 @@ _cairo_svg_surface_store_page (cairo_svg
 {
     unsigned int i;
     cairo_svg_page_t page;
+    cairo_output_stream_t *stream;
+
+    stream = _cairo_memory_stream_create ();
+    if (stream->status)
+	return NULL;
 
     page.surface_id = surface->id;
     page.clip_level = surface->clip_level;
     page.xml_node = surface->xml_node;
 
-    surface->xml_node = _cairo_memory_stream_create ();
+    if (_cairo_array_append (&surface->page_set, &page) != CAIRO_STATUS_SUCCESS)
+    {
+	cairo_status_t status = _cairo_output_stream_destroy (stream);
+	return NULL;
+	(void) status;
+    }
+
+    surface->xml_node = stream;
     surface->clip_level = 0;
 
     for (i = 0; i < page.clip_level; i++)
 	_cairo_output_stream_printf (page.xml_node, "</g>\n");
 
-    if (_cairo_array_append (&surface->page_set, &page) != CAIRO_STATUS_SUCCESS)
-	return NULL;
-
     return _cairo_array_index (&surface->page_set, surface->page_set.num_elements - 1);
 }
 
@@ -426,6 +464,8 @@ _cairo_svg_surface_copy_page (void *abst
     cairo_svg_page_t *page;
 
     page = _cairo_svg_surface_store_page (surface);
+    if (page == NULL)
+	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
     _cairo_memory_stream_copy (page->xml_node, surface->xml_node);
     surface->clip_level = page->clip_level;
@@ -438,7 +478,8 @@ _cairo_svg_surface_show_page (void *abst
 {
     cairo_svg_surface_t *surface = abstract_surface;
 
-    _cairo_svg_surface_store_page (surface);
+    if (_cairo_svg_surface_store_page (surface) == NULL)
+	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
     return CAIRO_STATUS_SUCCESS;
 }
@@ -549,6 +590,8 @@ _cairo_svg_surface_emit_path (cairo_outp
 					  _cairo_svg_path_curve_to,
 					  _cairo_svg_path_close_path,
 					  &info);
+    if (status)
+	return status;
 
     _cairo_output_stream_printf (output, "\"");
 
@@ -575,6 +618,8 @@ _cairo_svg_document_emit_outline_glyph_d
 				 "<path style=\"stroke: none;\" ");
 
     status = _cairo_svg_surface_emit_path (document->xml_node_glyphs, scaled_glyph->path, NULL);
+    if (status)
+	return status;
 
     _cairo_output_stream_printf (document->xml_node_glyphs,
 				 "/>\n");
@@ -633,7 +678,7 @@ _cairo_svg_document_emit_bitmap_glyph_da
     return CAIRO_STATUS_SUCCESS;
 }
 
-static void
+static cairo_status_t
 _cairo_svg_document_emit_glyph (cairo_svg_document_t	*document,
 				cairo_scaled_font_t	*scaled_font,
 				unsigned long		 scaled_font_glyph_index,
@@ -654,8 +699,12 @@ _cairo_svg_document_emit_glyph (cairo_sv
 	status = _cairo_svg_document_emit_bitmap_glyph_data (document,
 							     scaled_font,
 							     scaled_font_glyph_index);
+    if (status)
+	return status;
 
     _cairo_output_stream_printf (document->xml_node_glyphs, "</symbol>\n");
+
+    return CAIRO_STATUS_SUCCESS;
 }
 
 static void
@@ -664,12 +713,15 @@ _cairo_svg_document_emit_font_subset (ca
 {
     cairo_svg_document_t *document = closure;
     unsigned int i;
+    cairo_status_t status;
 
     for (i = 0; i < font_subset->num_glyphs; i++) {
-	_cairo_svg_document_emit_glyph (document,
-					font_subset->scaled_font,
-					font_subset->glyphs[i],
-					font_subset->font_id, i);
+	status = _cairo_svg_document_emit_glyph (document,
+					         font_subset->scaled_font,
+					         font_subset->glyphs[i],
+					         font_subset->font_id, i);
+	if (status)
+	    break;
     }
 }
 
@@ -681,13 +733,11 @@ _cairo_svg_document_emit_font_subsets (c
     status = _cairo_scaled_font_subsets_foreach_scaled (document->font_subsets,
                                                         _cairo_svg_document_emit_font_subset,
                                                         document);
-    if (status)
-	return status;
 
     _cairo_scaled_font_subsets_destroy (document->font_subsets);
     document->font_subsets = NULL;
 
-    return CAIRO_STATUS_SUCCESS;
+    return status;
 }
 
 static cairo_bool_t cairo_svg_force_fallbacks = FALSE;
@@ -743,9 +793,11 @@ _cairo_svg_surface_finish (void *abstrac
     else
 	status = CAIRO_STATUS_SUCCESS;
 
-    status2 = _cairo_output_stream_destroy (surface->xml_node);
-    if (status == CAIRO_STATUS_SUCCESS)
-	status = status2;
+    if (surface->xml_node != NULL) {
+	status2 = _cairo_output_stream_destroy (surface->xml_node);
+	if (status == CAIRO_STATUS_SUCCESS)
+	    status = status2;
+    }
 
     for (i = 0; i < surface->page_set.num_elements; i++) {
 	page = _cairo_array_index (&surface->page_set, i);
@@ -755,7 +807,9 @@ _cairo_svg_surface_finish (void *abstrac
     }
     _cairo_array_fini (&surface->page_set);
 
-    _cairo_svg_document_destroy (document);
+    status2 = _cairo_svg_document_destroy (document);
+    if (status == CAIRO_STATUS_SUCCESS)
+	status = status2;
 
     return status;
 }
@@ -869,10 +923,10 @@ _cairo_surface_base64_encode (cairo_surf
 	    info.src[i] = '\x0';
 	info.trailing = 3 - info.in_mem;
 	info.in_mem = 3;
-	base64_write_func (&info, NULL, 0);
+	status = base64_write_func (&info, NULL, 0);
     }
 
-    return CAIRO_STATUS_SUCCESS;
+    return status;
 }
 
 static cairo_status_t
@@ -896,14 +950,13 @@ _cairo_svg_surface_emit_composite_image_
 	return status;
 
     status = _cairo_surface_get_extents (surface, &extents);
-
     if (status)
 	return status;
 
     p2u = pattern->base.matrix;
     status = cairo_matrix_invert (&p2u);
-    if (status)
-	return status;
+    /* cairo_pattern_set_matrix ensures the matrix is invertible */
+    assert (status == CAIRO_STATUS_SUCCESS);
 
     if (pattern_id != invalid_pattern_id) {
 	_cairo_output_stream_printf (output,
@@ -970,25 +1023,32 @@ _cairo_svg_surface_emit_meta_surface (ca
 	}
     }
 
-    meta = (cairo_meta_surface_t *) _cairo_surface_snapshot ((cairo_surface_t *)surface);
+    meta = (cairo_meta_surface_t *) _cairo_surface_snapshot (&surface->base);
     paginated_surface = _cairo_svg_surface_create_for_document (document,
 								meta->content,
 								meta->width_pixels,
 								meta->height_pixels);
+    if (paginated_surface->status) {
+	cairo_surface_destroy (&meta->base);
+	return CAIRO_STATUS_NO_MEMORY;
+    }
+
     svg_surface = (cairo_svg_surface_t *) _cairo_paginated_surface_get_target (paginated_surface);
     cairo_surface_set_fallback_resolution (paginated_surface,
 					   document->owner->x_fallback_resolution,
 					   document->owner->y_fallback_resolution);
 
-    status = _cairo_meta_surface_replay ((cairo_surface_t *)meta, paginated_surface);
+    status = _cairo_meta_surface_replay (&meta->base, paginated_surface);
     if (status) {
 	cairo_surface_destroy (&meta->base);
+	cairo_surface_destroy (paginated_surface);
 	return status;
     }
 
     status = cairo_surface_show_page (paginated_surface);
     if (status) {
 	cairo_surface_destroy (&meta->base);
+	cairo_surface_destroy (paginated_surface);
 	return status;
     }
 
@@ -997,6 +1057,7 @@ _cairo_svg_surface_emit_meta_surface (ca
     status = _cairo_array_append (&document->meta_snapshots, &new_snapshot);
     if (status) {
 	cairo_surface_destroy (&meta->base);
+	cairo_surface_destroy (paginated_surface);
 	return status;
     }
 
@@ -1030,8 +1091,12 @@ _cairo_svg_surface_emit_meta_surface (ca
     contents = svg_surface->xml_node;
     page_set = &svg_surface->page_set;
 
-    if (_cairo_memory_stream_length (contents) > 0)
-	_cairo_svg_surface_store_page (svg_surface);
+    if (_cairo_memory_stream_length (contents) > 0) {
+	if (_cairo_svg_surface_store_page (svg_surface) == NULL) {
+	    cairo_surface_destroy (paginated_surface);
+	    return CAIRO_STATUS_NO_MEMORY;
+	}
+    }
 
     if (page_set->num_elements > 0) {
 	cairo_svg_page_t *page;
@@ -1044,6 +1109,7 @@ _cairo_svg_surface_emit_meta_surface (ca
 
     *id = new_snapshot.id;
 
+    status = cairo_surface_status (paginated_surface);
     cairo_surface_destroy (paginated_surface);
 
     /* FIXME: cairo_paginated_surface doesn't take a ref to the
@@ -1053,7 +1119,7 @@ _cairo_svg_surface_emit_meta_surface (ca
 
     /* cairo_surface_destroy (svg_surface); */
 
-    return CAIRO_STATUS_SUCCESS;
+    return status;
 }
 
 static cairo_status_t
@@ -1071,8 +1137,8 @@ _cairo_svg_surface_emit_composite_meta_p
 
     p2u = pattern->base.matrix;
     status = cairo_matrix_invert (&p2u);
-    if (status)
-	return status;
+    /* cairo_pattern_set_matrix ensures the matrix is invertible */
+    assert (status == CAIRO_STATUS_SUCCESS);
 
     meta_surface = (cairo_meta_surface_t *) pattern->surface;
 
@@ -1174,11 +1240,15 @@ _cairo_svg_surface_emit_surface_pattern 
 		      cairo_bool_t		 is_stroke)
 {
     cairo_svg_document_t *document = surface->document;
+    cairo_status_t status;
     int pattern_id;
 
     pattern_id = document->pattern_id++;
-    _cairo_svg_surface_emit_composite_pattern (document->xml_node_defs, surface, pattern,
-			    pattern_id, NULL);
+    status = _cairo_svg_surface_emit_composite_pattern (document->xml_node_defs,
+	                                                surface, pattern,
+							pattern_id, NULL);
+    if (status)
+	return status;
 
     _cairo_output_stream_printf (style,
 				 "%s: url(#pattern%d);",
@@ -1188,7 +1258,7 @@ _cairo_svg_surface_emit_surface_pattern 
     return CAIRO_STATUS_SUCCESS;
 }
 
-static void
+static cairo_status_t
 _cairo_svg_surface_emit_pattern_stops (cairo_output_stream_t *output,
 		    cairo_gradient_pattern_t const *pattern,
 		    double start_offset,
@@ -1201,7 +1271,7 @@ _cairo_svg_surface_emit_pattern_stops (c
     unsigned int i;
 
     if (pattern->n_stops < 1)
-	return;
+	return CAIRO_STATUS_SUCCESS;
 
     if (pattern->n_stops == 1) {
 	    _cairo_output_stream_printf (output,
@@ -1213,12 +1283,14 @@ _cairo_svg_surface_emit_pattern_stops (c
 					 pattern->stops[0].color.green * 100.0,
 					 pattern->stops[0].color.blue  * 100.0,
 					 pattern->stops[0].color.alpha);
-	    return;
+	    return CAIRO_STATUS_SUCCESS;
     }
 
     if (emulate_reflect || reverse_stops) {
 	n_stops = emulate_reflect ? pattern->n_stops * 2 - 2: pattern->n_stops;
 	stops = _cairo_malloc_ab (n_stops, sizeof (cairo_gradient_stop_t));
+	if (stops == NULL)
+	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
 	for (i = 0; i < pattern->n_stops; i++) {
 	    if (reverse_stops) {
@@ -1348,6 +1420,8 @@ _cairo_svg_surface_emit_pattern_stops (c
 
     if (reverse_stops || emulate_reflect)
 	free (stops);
+
+    return CAIRO_STATUS_SUCCESS;
 }
 
 static void
@@ -1380,8 +1454,8 @@ _cairo_svg_surface_emit_linear_pattern (
 
     p2u = pattern->base.base.matrix;
     status = cairo_matrix_invert (&p2u);
-    if (status)
-	return status;
+    /* cairo_pattern_set_matrix ensures the matrix is invertible */
+    assert (status == CAIRO_STATUS_SUCCESS);
 
     x0 = _cairo_fixed_to_double (pattern->p1.x);
     y0 = _cairo_fixed_to_double (pattern->p1.y);
@@ -1399,7 +1473,11 @@ _cairo_svg_surface_emit_linear_pattern (
     _cairo_svg_surface_emit_transform (document->xml_node_defs, "gradientTransform", &p2u);
     _cairo_output_stream_printf (document->xml_node_defs, ">\n");
 
-    _cairo_svg_surface_emit_pattern_stops (document->xml_node_defs ,&pattern->base, 0.0, FALSE, FALSE);
+    status = _cairo_svg_surface_emit_pattern_stops (document->xml_node_defs,
+	                                            &pattern->base, 0.0,
+						    FALSE, FALSE);
+    if (status)
+	return status;
 
     _cairo_output_stream_printf (document->xml_node_defs,
 				 "</linearGradient>\n");
@@ -1455,8 +1533,8 @@ _cairo_svg_surface_emit_radial_pattern (
 
     p2u = pattern->base.base.matrix;
     status = cairo_matrix_invert (&p2u);
-    if (status)
-	return status;
+    /* cairo_pattern_set_matrix ensures the matrix is invertible */
+    assert (status == CAIRO_STATUS_SUCCESS);
 
     if (pattern->r1 == pattern->r2) {
 	_cairo_output_stream_printf (document->xml_node_defs,
@@ -1570,8 +1648,13 @@ _cairo_svg_surface_emit_radial_pattern (
 					     "stop-opacity: 0;\"/>\n",
 					     r0 / r1);
 	}
-	_cairo_svg_surface_emit_pattern_stops (document->xml_node_defs, &pattern->base, offset,
-			    reverse_stops, emulate_reflect);
+	status = _cairo_svg_surface_emit_pattern_stops (document->xml_node_defs,
+		                                        &pattern->base, offset,
+							reverse_stops,
+							emulate_reflect);
+	if (status)
+	    return status;
+
 	if (pattern->base.base.extend == CAIRO_EXTEND_NONE)
 	    _cairo_output_stream_printf (document->xml_node_defs,
 					 "<stop offset=\"1.0\" style=\""
@@ -1609,10 +1692,10 @@ _cairo_svg_surface_emit_pattern (cairo_s
     case CAIRO_PATTERN_TYPE_RADIAL:
 	return _cairo_svg_surface_emit_radial_pattern (surface, (cairo_radial_pattern_t *) pattern, output, is_stroke);
     }
-    return CAIRO_STATUS_SUCCESS;
+    return _cairo_error (CAIRO_STATUS_PATTERN_TYPE_MISMATCH);
 }
 
-static void
+static cairo_status_t
 _cairo_svg_surface_emit_fill_style (cairo_output_stream_t *output,
 				    cairo_svg_surface_t *surface,
 				    cairo_operator_t op,
@@ -1624,16 +1707,17 @@ _cairo_svg_surface_emit_fill_style (cair
 				 fill_rule == CAIRO_FILL_RULE_EVEN_ODD ?
 				 "evenodd" : "nonzero");
     _cairo_svg_surface_emit_operator (output, surface, op);
-    _cairo_svg_surface_emit_pattern (surface, source, output, FALSE);
+    return _cairo_svg_surface_emit_pattern (surface, source, output, FALSE);
 }
 
-static void
+static cairo_status_t
 _cairo_svg_surface_emit_stroke_style (cairo_output_stream_t *output,
 				      cairo_svg_surface_t   *surface,
 				      cairo_operator_t	     op,
 				      cairo_pattern_t	    *source,
 				      cairo_stroke_style_t  *stroke_style)
 {
+    cairo_status_t status;
     const char *line_cap, *line_join;
     unsigned int i;
 
@@ -1673,7 +1757,10 @@ _cairo_svg_surface_emit_stroke_style (ca
 				 line_cap,
 				 line_join);
 
-     _cairo_svg_surface_emit_pattern (surface, source, output, TRUE);
+     status = _cairo_svg_surface_emit_pattern (surface, source, output, TRUE);
+     if (status)
+	 return status;
+
      _cairo_svg_surface_emit_operator (output, surface, op);
 
     if (stroke_style->num_dashes > 0) {
@@ -1696,6 +1783,8 @@ _cairo_svg_surface_emit_stroke_style (ca
     _cairo_output_stream_printf (output,
 				 "stroke-miterlimit: %f; ",
 				 stroke_style->miter_limit);
+
+    return CAIRO_STATUS_SUCCESS;
 }
 
 static cairo_int_status_t
@@ -1718,16 +1807,24 @@ _cairo_svg_surface_fill_stroke (void			*
     cairo_status_t status;
 
     _cairo_output_stream_printf (surface->xml_node, "<path style=\"");
-    _cairo_svg_surface_emit_fill_style (surface->xml_node, surface, fill_op, fill_source, fill_rule);
-    _cairo_svg_surface_emit_stroke_style (surface->xml_node, surface, stroke_op, stroke_source, stroke_style);
+    status = _cairo_svg_surface_emit_fill_style (surface->xml_node, surface, fill_op, fill_source, fill_rule);
+    if (status)
+	return status;
+
+    status = _cairo_svg_surface_emit_stroke_style (surface->xml_node, surface, stroke_op, stroke_source, stroke_style);
+    if (status)
+	return status;
+
     _cairo_output_stream_printf (surface->xml_node, "\" ");
 
     status = _cairo_svg_surface_emit_path (surface->xml_node, path, stroke_ctm_inverse);
+    if (status)
+	return status;
 
     _cairo_svg_surface_emit_transform (surface->xml_node, " transform", stroke_ctm);
     _cairo_output_stream_printf (surface->xml_node, "/>\n");
 
-    return status;
+    return CAIRO_STATUS_SUCCESS;
 }
 
 static cairo_int_status_t
@@ -1748,14 +1845,19 @@ _cairo_svg_surface_fill (void			*abstrac
     assert (_cairo_svg_surface_operation_supported (surface, op, source));
 
     _cairo_output_stream_printf (surface->xml_node, "<path style=\" stroke:none;");
-    _cairo_svg_surface_emit_fill_style (surface->xml_node, surface, op, source, fill_rule);
+    status = _cairo_svg_surface_emit_fill_style (surface->xml_node, surface, op, source, fill_rule);
+    if (status)
+	return status;
+
     _cairo_output_stream_printf (surface->xml_node, "\" ");
 
     status = _cairo_svg_surface_emit_path (surface->xml_node, path, NULL);
+    if (status)
+	return status;
 
     _cairo_output_stream_printf (surface->xml_node, "/>\n");
 
-    return status;
+    return CAIRO_STATUS_SUCCESS;
 }
 
 static cairo_int_status_t
@@ -1784,6 +1886,8 @@ _cairo_svg_surface_emit_paint (cairo_out
 	    cairo_pattern_t	  *source,
 	    const char		  *extra_attributes)
 {
+    cairo_status_t status;
+
     if (source->type == CAIRO_PATTERN_TYPE_SURFACE &&
 	source->extend == CAIRO_EXTEND_NONE)
 	return _cairo_svg_surface_emit_composite_pattern (output,
@@ -1798,7 +1902,10 @@ _cairo_svg_surface_emit_paint (cairo_out
 				 "style=\"",
 				 surface->width, surface->height);
     _cairo_svg_surface_emit_operator (output, surface, op);
-    _cairo_svg_surface_emit_pattern (surface, source, output, FALSE);
+    status = _cairo_svg_surface_emit_pattern (surface, source, output, FALSE);
+    if (status)
+	return status;
+
     _cairo_output_stream_printf (output, " stroke: none;\"");
 
     if (extra_attributes)
@@ -1806,7 +1913,6 @@ _cairo_svg_surface_emit_paint (cairo_out
 
     _cairo_output_stream_printf (output, "/>\n");
 
-
     return CAIRO_STATUS_SUCCESS;
 }
 
@@ -1844,10 +1950,17 @@ _cairo_svg_surface_paint (void		    *abs
 	 op == CAIRO_OPERATOR_SOURCE))
     {
 	status = _cairo_output_stream_destroy (surface->xml_node);
-	if (status)
+	if (status) {
+	    surface->xml_node = NULL;
 	    return status;
+	}
 
 	surface->xml_node = _cairo_memory_stream_create ();
+	status = _cairo_output_stream_get_status (surface->xml_node);
+	if (status) {
+	    surface->xml_node = NULL;
+	    return status;
+	}
 
 	if (op == CAIRO_OPERATOR_CLEAR) {
 	    if (surface->content == CAIRO_CONTENT_COLOR) {
@@ -1863,9 +1976,7 @@ _cairo_svg_surface_paint (void		    *abs
 	}
     }
 
-    _cairo_svg_surface_emit_paint (surface->xml_node, surface, op, source, NULL);
-
-    return CAIRO_STATUS_SUCCESS;
+    return _cairo_svg_surface_emit_paint (surface->xml_node, surface, op, source, NULL);
 }
 
 static cairo_int_status_t
@@ -1891,11 +2002,21 @@ _cairo_svg_surface_mask (void		    *abst
      * document->xml_node_defs so we need to write the mask element to
      * a temporary stream and then copy that to xml_node_defs. */
     mask_stream = _cairo_memory_stream_create ();
+    status = _cairo_output_stream_get_status (mask_stream);
+    if (status)
+	return status;
+
     _cairo_output_stream_printf (mask_stream,
 				 "<mask id=\"mask%d\">\n"
 				 "  <g filter=\"url(#alpha)\">\n",
 				 document->mask_id);
-    _cairo_svg_surface_emit_paint (mask_stream, surface, op, mask, NULL);
+    status = _cairo_svg_surface_emit_paint (mask_stream, surface, op, mask, NULL);
+    if (status) {
+	cairo_status_t ignore = _cairo_output_stream_destroy (mask_stream);
+	return status;
+	(void) ignore;
+    }
+
     _cairo_output_stream_printf (mask_stream,
 				 "  </g>\n"
 				 "</mask>\n");
@@ -1907,7 +2028,9 @@ _cairo_svg_surface_mask (void		    *abst
 
     snprintf (buffer, sizeof buffer, "mask=\"url(#mask%d);\"",
 	      document->mask_id);
-    _cairo_svg_surface_emit_paint (surface->xml_node, surface, op, source, buffer);
+    status = _cairo_svg_surface_emit_paint (surface->xml_node, surface, op, source, buffer);
+    if (status)
+	return status;
 
     document->mask_id++;
 
@@ -1934,15 +2057,17 @@ _cairo_svg_surface_stroke (void			*abstr
     assert (_cairo_svg_surface_operation_supported (surface, op, source));
 
     _cairo_output_stream_printf (surface->xml_node, "<path style=\"fill: none; ");
-    _cairo_svg_surface_emit_stroke_style (surface->xml_node, surface, op, source, stroke_style);
+    status = _cairo_svg_surface_emit_stroke_style (surface->xml_node, surface, op, source, stroke_style);
     _cairo_output_stream_printf (surface->xml_node, "\" ");
 
     status = _cairo_svg_surface_emit_path (surface->xml_node, path, ctm_inverse);
+    if (status)
+	return status;
 
     _cairo_svg_surface_emit_transform (surface->xml_node, " transform", ctm);
     _cairo_output_stream_printf (surface->xml_node, "/>\n");
 
-    return status;
+    return CAIRO_STATUS_SUCCESS;
 }
 
 static cairo_int_status_t
@@ -1975,19 +2100,28 @@ _cairo_svg_surface_show_glyphs (void			*
 	goto FALLBACK;
 
     _cairo_output_stream_printf (surface->xml_node, "<g style=\"");
-    _cairo_svg_surface_emit_pattern (surface, pattern, surface->xml_node, FALSE);
+    status = _cairo_svg_surface_emit_pattern (surface, pattern,
+	                                      surface->xml_node, FALSE);
+    if (status)
+	return status;
+
     _cairo_output_stream_printf (surface->xml_node, "\">\n");
 
     for (i = 0; i < num_glyphs; i++) {
 	status = _cairo_scaled_font_subsets_map_glyph (document->font_subsets,
 						       scaled_font, glyphs[i].index,
                                                        &subset_glyph);
-	if (status) {
+	if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
+	    _cairo_output_stream_printf (surface->xml_node, "</g>\n");
+
 	    glyphs += i;
 	    num_glyphs -= i;
 	    goto FALLBACK;
 	}
 
+	if (status)
+	    return status;
+
 	_cairo_output_stream_printf (surface->xml_node,
 				     "  <use xlink:href=\"#glyph%d-%d\" "
 				     "x=\"%f\" y=\"%f\"/>\n",
@@ -2001,13 +2135,14 @@ _cairo_svg_surface_show_glyphs (void			*
     return CAIRO_STATUS_SUCCESS;
 
 FALLBACK:
-
    _cairo_path_fixed_init (&path);
 
     status = _cairo_scaled_font_glyph_path (scaled_font,(cairo_glyph_t *) glyphs, num_glyphs, &path);
 
-    if (status)
-	    return status;
+    if (status) {
+	_cairo_path_fixed_fini (&path);
+	return status;
+    }
 
     status = _cairo_svg_surface_fill (abstract_surface, op, pattern,
 				      &path, CAIRO_FILL_RULE_WINDING, 0.0, CAIRO_ANTIALIAS_SUBPIXEL);
@@ -2042,6 +2177,9 @@ _cairo_svg_surface_intersect_clip_path (
  				 "  <path ",
  				 document->clip_id);
     status = _cairo_svg_surface_emit_path (document->xml_node_defs, path, NULL);
+    if (status)
+	return status;
+
     _cairo_output_stream_printf (document->xml_node_defs,
  				 "/>\n"
  				 "</clipPath>\n");
@@ -2056,7 +2194,7 @@ _cairo_svg_surface_intersect_clip_path (
     document->clip_id++;
     surface->clip_level++;
 
-    return status;
+    return CAIRO_STATUS_SUCCESS;
 }
 
 static void
@@ -2111,6 +2249,10 @@ _cairo_svg_document_create (cairo_output
 			    cairo_svg_version_t		 version)
 {
     cairo_svg_document_t *document;
+    cairo_status_t status;
+
+    if (output_stream->status)
+	return NULL;
 
     document = malloc (sizeof (cairo_svg_document_t));
     if (document == NULL) {
@@ -2120,10 +2262,8 @@ _cairo_svg_document_create (cairo_output
 
     /* The use of defs for font glyphs imposes no per-subset limit. */
     document->font_subsets = _cairo_scaled_font_subsets_create_scaled ();
-    if (document->font_subsets == NULL) {
-	free (document);
-	return NULL;
-    }
+    if (document->font_subsets == NULL)
+	goto CLEANUP_DOCUMENT;
 
     document->output_stream = output_stream;
     document->refcount = 1;
@@ -2141,7 +2281,12 @@ _cairo_svg_document_create (cairo_output
     document->mask_id = 0;
 
     document->xml_node_defs = _cairo_memory_stream_create ();
+    if (_cairo_output_stream_get_status (document->xml_node_defs))
+	goto CLEANUP_FONT_SUBSETS;
+
     document->xml_node_glyphs = _cairo_memory_stream_create ();
+    if (_cairo_output_stream_get_status (document->xml_node_glyphs))
+	goto CLEANUP_NODE_DEFS;
 
     document->alpha_filter = FALSE;
 
@@ -2151,6 +2296,14 @@ _cairo_svg_document_create (cairo_output
     document->svg_version = version;
 
     return document;
+
+  CLEANUP_NODE_DEFS:
+    status = _cairo_output_stream_destroy (document->xml_node_defs);
+  CLEANUP_FONT_SUBSETS:
+    _cairo_scaled_font_subsets_destroy (document->font_subsets);
+  CLEANUP_DOCUMENT:
+    free (document);
+    return NULL;
 }
 
 static cairo_svg_document_t *
@@ -2161,16 +2314,20 @@ _cairo_svg_document_reference (cairo_svg
     return document;
 }
 
-static void
+static cairo_status_t
 _cairo_svg_document_destroy (cairo_svg_document_t *document)
 {
+    cairo_status_t status;
+
     document->refcount--;
     if (document->refcount > 0)
-      return;
+      return CAIRO_STATUS_SUCCESS;
 
-    _cairo_svg_document_finish (document);
+    status = _cairo_svg_document_finish (document);
 
     free (document);
+
+    return status;
 }
 
 static cairo_status_t
@@ -2179,7 +2336,6 @@ _cairo_svg_document_finish (cairo_svg_do
     cairo_status_t status, status2;
     cairo_output_stream_t *output = document->output_stream;
     cairo_meta_snapshot_t *snapshot;
-    cairo_svg_surface_t *surface;
     cairo_svg_page_t *page;
     unsigned int i;
 
@@ -2197,8 +2353,6 @@ _cairo_svg_document_finish (cairo_svg_do
 				 _cairo_svg_internal_version_strings [document->svg_version]);
 
     status = _cairo_svg_document_emit_font_subsets (document);
-    if (status)
-	return status;
 
     if (_cairo_memory_stream_length (document->xml_node_glyphs) > 0 ||
 	_cairo_memory_stream_length (document->xml_node_defs) > 0) {
@@ -2212,35 +2366,46 @@ _cairo_svg_document_finish (cairo_svg_do
 	_cairo_output_stream_printf (output, "</defs>\n");
     }
 
-    surface = (cairo_svg_surface_t *) _cairo_paginated_surface_get_target (document->owner);
-    if (_cairo_memory_stream_length (surface->xml_node) > 0)
-	_cairo_svg_surface_store_page (surface);
-
-    if (surface->page_set.num_elements > 1 &&
-	_cairo_svg_version_has_page_set_support (document->svg_version)) {
-	_cairo_output_stream_printf (output, "<pageSet>\n");
-	for (i = 0; i < surface->page_set.num_elements; i++) {
-	    page = _cairo_array_index (&surface->page_set, i);
-	    _cairo_output_stream_printf (output, "<page>\n");
+    if (document->owner != NULL) {
+	cairo_svg_surface_t *surface;
+
+	surface = (cairo_svg_surface_t *) _cairo_paginated_surface_get_target (document->owner);
+	if (surface->xml_node != NULL &&
+		_cairo_memory_stream_length (surface->xml_node) > 0) {
+	    if (_cairo_svg_surface_store_page (surface) == NULL) {
+		if (status == CAIRO_STATUS_SUCCESS)
+		    status = CAIRO_STATUS_NO_MEMORY;
+	    }
+	}
+
+	if (surface->page_set.num_elements > 1 &&
+	    _cairo_svg_version_has_page_set_support (document->svg_version)) {
+	    _cairo_output_stream_printf (output, "<pageSet>\n");
+	    for (i = 0; i < surface->page_set.num_elements; i++) {
+		page = _cairo_array_index (&surface->page_set, i);
+		_cairo_output_stream_printf (output, "<page>\n");
+		_cairo_output_stream_printf (output,
+					     "<g id=\"surface%d\">\n",
+					     page->surface_id);
+		_cairo_memory_stream_copy (page->xml_node, output);
+		_cairo_output_stream_printf (output, "</g>\n</page>\n");
+	    }
+	    _cairo_output_stream_printf (output, "</pageSet>\n");
+	} else if (surface->page_set.num_elements > 0) {
+	    page = _cairo_array_index (&surface->page_set, surface->page_set.num_elements - 1);
 	    _cairo_output_stream_printf (output,
 					 "<g id=\"surface%d\">\n",
 					 page->surface_id);
 	    _cairo_memory_stream_copy (page->xml_node, output);
-	    _cairo_output_stream_printf (output, "</g>\n</page>\n");
+	    _cairo_output_stream_printf (output, "</g>\n");
 	}
-	_cairo_output_stream_printf (output, "</pageSet>\n");
-    } else if (surface->page_set.num_elements > 0) {
-	page = _cairo_array_index (&surface->page_set, surface->page_set.num_elements - 1);
-	_cairo_output_stream_printf (output,
-				     "<g id=\"surface%d\">\n",
-				     page->surface_id);
-	_cairo_memory_stream_copy (page->xml_node, output);
-	_cairo_output_stream_printf (output, "</g>\n");
     }
 
     _cairo_output_stream_printf (output, "</svg>\n");
 
-    status = _cairo_output_stream_destroy (document->xml_node_glyphs);
+    status2 = _cairo_output_stream_destroy (document->xml_node_glyphs);
+    if (status == CAIRO_STATUS_SUCCESS)
+	status = status2;
 
     status2 = _cairo_output_stream_destroy (document->xml_node_defs);
     if (status == CAIRO_STATUS_SUCCESS)
@@ -2252,7 +2417,10 @@ _cairo_svg_document_finish (cairo_svg_do
 
     for (i = 0; i < document->meta_snapshots.num_elements; i++) {
 	snapshot = _cairo_array_index (&document->meta_snapshots, i);
-	cairo_surface_destroy ((cairo_surface_t *) snapshot->meta);
+	status2 = cairo_surface_status (&snapshot->meta->base);
+	cairo_surface_destroy (&snapshot->meta->base);
+	if (status == CAIRO_STATUS_SUCCESS)
+	    status = status2;
     }
     _cairo_array_fini (&document->meta_snapshots);
 


More information about the cairo-commit mailing list