From bd2245f8b87d85f5ea61200838c10de70e776cf5 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 5 Oct 2007 00:45:00 +0100 Subject: [PATCH] [cairo-svg-surface] Review error propagation. Ensure that the error status is propagated and all local resources are freed on the error path. --- src/cairo-svg-surface.c | 374 +++++++++++++++++++++++++++++----------- 1 file changed, 271 insertions(+), 103 deletions(-) diff --git a/src/cairo-svg-surface.c b/src/cairo-svg-surface.c index cc909f5c4..6ec33d741 100644 --- a/src/cairo-svg-surface.c +++ b/src/cairo-svg-surface.c @@ -124,7 +124,7 @@ _cairo_svg_document_create (cairo_output_stream_t *stream, 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 (cairo_svg_document_t *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 (cairo_svg_document_t *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 (cairo_svg_document_t *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_internal (cairo_output_stream_t *stream, { 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_surface_t *surface) { 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, "\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 *abstract_surface) 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 *abstract_surface) { 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_output_stream_t *output, _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_data (cairo_svg_document_t *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_data (cairo_svg_document_t *document, 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_svg_document_t *document, 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, "\n"); + + return CAIRO_STATUS_SUCCESS; } static void @@ -664,12 +713,15 @@ _cairo_svg_document_emit_font_subset (cairo_scaled_font_subset_t *font_subset, { 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 (cairo_svg_document_t *document) 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 *abstract_surface) 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 *abstract_surface) } _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_surface_t *surface, 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_pattern (cairo_output_stream_t *outp 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 (cairo_svg_document_t *document, } } - 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 (cairo_svg_document_t *document, 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 (cairo_svg_document_t *document, 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 (cairo_svg_document_t *document, *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 (cairo_svg_document_t *document, /* 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_pattern (cairo_output_stream_t *output, 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_svg_surface_t *surface, 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 (cairo_svg_surface_t *surface, 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 (cairo_output_stream_t *output, 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 (cairo_output_stream_t *output, 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 (cairo_output_stream_t *output, if (reverse_stops || emulate_reflect) free (stops); + + return CAIRO_STATUS_SUCCESS; } static void @@ -1380,8 +1454,8 @@ _cairo_svg_surface_emit_linear_pattern (cairo_svg_surface_t *surface, 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_t *surface, _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, "\n"); @@ -1455,8 +1533,8 @@ _cairo_svg_surface_emit_radial_pattern (cairo_svg_surface_t *surface, 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 (cairo_svg_surface_t *surface, "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, "num_dashes > 0) { @@ -1696,6 +1783,8 @@ _cairo_svg_surface_emit_stroke_style (cairo_output_stream_t *output, _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 *abstract_surface, cairo_status_t status; _cairo_output_stream_printf (surface->xml_node, "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 *abstract_surface, assert (_cairo_svg_surface_operation_supported (surface, op, source)); _cairo_output_stream_printf (surface->xml_node, "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_output_stream_t *output, 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_output_stream_t *output, "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_output_stream_t *output, _cairo_output_stream_printf (output, "/>\n"); - return CAIRO_STATUS_SUCCESS; } @@ -1844,10 +1950,17 @@ _cairo_svg_surface_paint (void *abstract_surface, 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 *abstract_surface, } } - _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 *abstract_surface, * 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, "\n" " \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, " \n" "\n"); @@ -1907,7 +2028,9 @@ _cairo_svg_surface_mask (void *abstract_surface, 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 *abstract_dst, assert (_cairo_svg_surface_operation_supported (surface, op, source)); _cairo_output_stream_printf (surface->xml_node, "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 *abstract_surface, goto FALLBACK; _cairo_output_stream_printf (surface->xml_node, "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, "\n"); + glyphs += i; num_glyphs -= i; goto FALLBACK; } + if (status) + return status; + _cairo_output_stream_printf (surface->xml_node, " \n", @@ -2001,13 +2135,14 @@ _cairo_svg_surface_show_glyphs (void *abstract_surface, 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 (void *dst, " 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" "\n"); @@ -2056,7 +2194,7 @@ _cairo_svg_surface_intersect_clip_path (void *dst, document->clip_id++; surface->clip_level++; - return status; + return CAIRO_STATUS_SUCCESS; } static void @@ -2111,6 +2249,10 @@ _cairo_svg_document_create (cairo_output_stream_t *output_stream, 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_stream_t *output_stream, /* 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_stream_t *output_stream, 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_stream_t *output_stream, 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_document_t *document) 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_document_t *document) 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_document_t *document) _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_document_t *document) _cairo_output_stream_printf (output, "\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 (document->owner != NULL) { + cairo_svg_surface_t *surface; - if (surface->page_set.num_elements > 1 && - _cairo_svg_version_has_page_set_support (document->svg_version)) { - _cairo_output_stream_printf (output, "\n"); - for (i = 0; i < surface->page_set.num_elements; i++) { - page = _cairo_array_index (&surface->page_set, i); - _cairo_output_stream_printf (output, "\n"); + 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, "\n"); + for (i = 0; i < surface->page_set.num_elements; i++) { + page = _cairo_array_index (&surface->page_set, i); + _cairo_output_stream_printf (output, "\n"); + _cairo_output_stream_printf (output, + "\n", + page->surface_id); + _cairo_memory_stream_copy (page->xml_node, output); + _cairo_output_stream_printf (output, "\n\n"); + } + _cairo_output_stream_printf (output, "\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, "\n", page->surface_id); _cairo_memory_stream_copy (page->xml_node, output); - _cairo_output_stream_printf (output, "\n\n"); + _cairo_output_stream_printf (output, "\n"); } - _cairo_output_stream_printf (output, "\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, - "\n", - page->surface_id); - _cairo_memory_stream_copy (page->xml_node, output); - _cairo_output_stream_printf (output, "\n"); } _cairo_output_stream_printf (output, "\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_document_t *document) 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);