diff options
author | Anton Danilkin <afdw@yandex.ru> | 2021-04-11 19:48:50 +0200 |
---|---|---|
committer | Anton Danilkin <afdw@yandex.ru> | 2021-04-11 23:59:47 +0200 |
commit | c5b24a3e12815fce328997a9b5825d732329cc4b (patch) | |
tree | 2bfb5de9fd66160dce984bece9b39b25428e43a1 /src/cairo-svg-surface.c | |
parent | c2ea2848fd52c23023f31f35f1a16693f8b50313 (diff) | |
download | cairo-c5b24a3e12815fce328997a9b5825d732329cc4b.tar.gz |
Start implementing correct paints in transformed recording patterns
Diffstat (limited to 'src/cairo-svg-surface.c')
-rw-r--r-- | src/cairo-svg-surface.c | 440 |
1 files changed, 283 insertions, 157 deletions
diff --git a/src/cairo-svg-surface.c b/src/cairo-svg-surface.c index a10c47792..bc0b06a9f 100644 --- a/src/cairo-svg-surface.c +++ b/src/cairo-svg-surface.c @@ -75,8 +75,6 @@ * Since: 1.2 **/ -typedef struct cairo_svg_page cairo_svg_page_t; - static const int invalid_pattern_id = -1; static const cairo_svg_version_t _cairo_svg_versions[] = @@ -149,9 +147,23 @@ enum cairo_svg_filter { CAIRO_SVG_FILTER_LUMINOSITY, }; -struct cairo_svg_page { +typedef struct _cairo_svg_source_surface { + cairo_hash_entry_t base; + unsigned int id; + unsigned char *unique_id; + unsigned long unique_id_length; + cairo_bool_t paint_used; +} cairo_svg_source_surface_t; + +typedef struct _cairo_svg_paint { + cairo_hash_entry_t base; + unsigned int source_id; cairo_output_stream_t *xml_node; -}; +} cairo_svg_paint_t; + +typedef struct cairo_svg_page { + cairo_output_stream_t *xml_node; +} cairo_svg_page_t; struct cairo_svg_document { cairo_output_stream_t *output_stream; @@ -180,6 +192,8 @@ struct cairo_svg_document { cairo_svg_version_t svg_version; cairo_scaled_font_subsets_t *font_subsets; + + cairo_hash_table_t *paints; }; static cairo_status_t @@ -488,13 +502,14 @@ cairo_svg_surface_get_document_unit (cairo_surface_t *abstract_surface) } static void -_cairo_svg_source_surface_init_key (cairo_svg_source_surface_t *key) +_cairo_svg_source_surface_init_key (cairo_svg_source_surface_t *source_surface) { - if (key->unique_id && key->unique_id_length > 0) { - key->base.hash = _cairo_hash_bytes (_CAIRO_HASH_INIT_VALUE, - key->unique_id, key->unique_id_length); + if (source_surface->unique_id && source_surface->unique_id_length > 0) { + source_surface->base.hash = _cairo_hash_bytes (_CAIRO_HASH_INIT_VALUE, + source_surface->unique_id, + source_surface->unique_id_length); } else { - key->base.hash = key->id; + source_surface->base.hash = source_surface->id; } } @@ -504,82 +519,123 @@ _cairo_svg_source_surface_equal (const void *key_a, const void *key_b) const cairo_svg_source_surface_t *a = key_a; const cairo_svg_source_surface_t *b = key_b; - if (a->unique_id && b->unique_id && a->unique_id_length == b->unique_id_length) - return (memcmp (a->unique_id, b->unique_id, a->unique_id_length) == 0); + if (a->unique_id && b->unique_id && a->unique_id_length == b->unique_id_length) { + return memcmp (a->unique_id, b->unique_id, a->unique_id_length) == 0; + } - return (a->id == b->id); + return a->id == b->id; } static void _cairo_svg_source_surface_pluck (void *entry, void *closure) { - cairo_svg_source_surface_t *surface_entry = entry; + cairo_svg_source_surface_t *source_surface = entry; cairo_hash_table_t *patterns = closure; - _cairo_hash_table_remove (patterns, &surface_entry->base); - free (surface_entry->unique_id); - free (surface_entry); + _cairo_hash_table_remove (patterns, &source_surface->base); + free (source_surface->unique_id); + free (source_surface); +} + +static void +_cairo_svg_paint_init_key (cairo_svg_paint_t *paint) +{ + paint->base.hash = paint->source_id; +} + +static cairo_bool_t +_cairo_svg_paint_equal (const void *key_a, const void *key_b) +{ + const cairo_svg_paint_t *a = key_a; + const cairo_svg_paint_t *b = key_b; + + return a->source_id == b->source_id; +} + +static void +_cairo_svg_paint_pluck (void *entry, void *closure) +{ + cairo_svg_paint_t *paint = entry; + cairo_hash_table_t *patterns = closure; + + _cairo_hash_table_remove (patterns, &paint->base); + (void) _cairo_output_stream_destroy (paint->xml_node); + free (paint); +} + +static void +_cairo_svg_paint_emit (void *entry, void *closure) +{ + cairo_svg_paint_t *paint = entry; + cairo_output_stream_t *output = closure; + + _cairo_output_stream_printf (output, + "<g id=\"paint-%d\">\n", + paint->source_id); + _cairo_memory_stream_copy (paint->xml_node, output); + _cairo_output_stream_printf (output, "</g>\n"); } static cairo_status_t -_cairo_svg_surface_add_source_surface (cairo_svg_surface_t *surface, - cairo_surface_t *source_surface, - unsigned int *source_id, - cairo_bool_t *is_new) +_cairo_svg_surface_add_source_surface (cairo_svg_surface_t *surface, + cairo_surface_t *source_surface, + cairo_bool_t *is_new, + cairo_svg_source_surface_t **result_source_surface) { - cairo_svg_source_surface_t source_key; - cairo_svg_source_surface_t *source_entry; - unsigned char *unique_id = NULL; - unsigned long unique_id_length = 0; cairo_status_t status; - source_key.id = source_surface->unique_id; - cairo_surface_get_mime_data (source_surface, CAIRO_MIME_TYPE_UNIQUE_ID, - (const unsigned char **) &source_key.unique_id, - &source_key.unique_id_length); - _cairo_svg_source_surface_init_key (&source_key); - source_entry = _cairo_hash_table_lookup (surface->source_surfaces, &source_key.base); - if (source_entry) { - *source_id = source_entry->id; + cairo_svg_source_surface_t source_surface_key; + source_surface_key.id = source_surface->unique_id; + cairo_surface_get_mime_data (source_surface, + CAIRO_MIME_TYPE_UNIQUE_ID, + (const unsigned char **) &source_surface_key.unique_id, + &source_surface_key.unique_id_length); + _cairo_svg_source_surface_init_key (&source_surface_key); + + cairo_svg_source_surface_t *found_source_surface_entry = _cairo_hash_table_lookup (surface->source_surfaces, + &source_surface_key.base); + if (found_source_surface_entry) { *is_new = FALSE; + *result_source_surface = found_source_surface_entry; return CAIRO_STATUS_SUCCESS; } - if (source_key.unique_id && source_key.unique_id_length > 0) { - unique_id = _cairo_malloc (source_key.unique_id_length); + unsigned char *unique_id = NULL; + unsigned long unique_id_length = 0; + if (source_surface_key.unique_id && source_surface_key.unique_id_length > 0) { + unique_id = _cairo_malloc (source_surface_key.unique_id_length); if (unique_id == NULL) { return _cairo_error (CAIRO_STATUS_NO_MEMORY); } - unique_id_length = source_key.unique_id_length; - memcpy (unique_id, source_key.unique_id, unique_id_length); + unique_id_length = source_surface_key.unique_id_length; + memcpy (unique_id, source_surface_key.unique_id, unique_id_length); } else { unique_id = NULL; unique_id_length = 0; } - source_entry = malloc (sizeof (cairo_svg_source_surface_t)); - if (source_entry == NULL) { + cairo_svg_source_surface_t *source_surface_entry = malloc (sizeof (cairo_svg_source_surface_t)); + if (source_surface_entry == NULL) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); goto fail; } - - source_entry->id = source_key.id; - source_entry->unique_id_length = unique_id_length; - source_entry->unique_id = unique_id; - _cairo_svg_source_surface_init_key (source_entry); - status = _cairo_hash_table_insert (surface->source_surfaces, &source_entry->base); + source_surface_entry->id = source_surface_key.id; + source_surface_entry->unique_id_length = unique_id_length; + source_surface_entry->unique_id = unique_id; + _cairo_svg_source_surface_init_key (source_surface_entry); + status = _cairo_hash_table_insert (surface->source_surfaces, &source_surface_entry->base); if (unlikely (status)) { goto fail; } *is_new = TRUE; - *source_id = source_entry->id; + *result_source_surface = source_surface_entry; return CAIRO_STATUS_SUCCESS; - fail: + fail: free (unique_id); - free (source_entry); + free (source_surface_entry); return status; } @@ -689,30 +745,35 @@ _cairo_svg_surface_create_for_document (cairo_svg_document_t *document, content, TRUE); /* is_vector */ + surface->source_id = surface->base.unique_id; + + surface->content = content; + surface->width = width; surface->height = height; surface->surface_bounded = bounded; surface->document = _cairo_svg_document_reference (document); - _cairo_surface_clipper_init (&surface->clipper, _cairo_svg_surface_clipper_intersect_clip_path); - surface->current_clipper_output_stream = NULL; - surface->clip_level = 0; - surface->xml_node = _cairo_memory_stream_create (); - _cairo_array_init (&surface->page_set, sizeof (cairo_svg_page_t)); - surface->paginated_mode = CAIRO_PAGINATED_MODE_ANALYZE; - surface->force_fallbacks = FALSE; - surface->content = content; - surface->source_surfaces = _cairo_hash_table_create (_cairo_svg_source_surface_equal); if (unlikely (surface->source_surfaces == NULL)) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); goto CLEANUP; } + _cairo_surface_clipper_init (&surface->clipper, _cairo_svg_surface_clipper_intersect_clip_path); + surface->current_clipper_output_stream = NULL; + surface->clip_level = 0; + surface->paint_used = FALSE; + + surface->paginated_mode = CAIRO_PAGINATED_MODE_ANALYZE; + + surface->force_fallbacks = FALSE; + + paginated = _cairo_paginated_surface_create (&surface->base, surface->content, &cairo_svg_surface_paginated_backend); @@ -1153,9 +1214,7 @@ _cairo_svg_surface_finish (void *abstract_surface) _cairo_surface_clipper_reset (&surface->clipper); - _cairo_hash_table_foreach (surface->source_surfaces, - _cairo_svg_source_surface_pluck, - surface->source_surfaces); + _cairo_hash_table_foreach (surface->source_surfaces, _cairo_svg_source_surface_pluck, surface->source_surfaces); _cairo_hash_table_destroy (surface->source_surfaces); status2 = _cairo_svg_document_destroy (document); @@ -1574,7 +1633,7 @@ _cairo_svg_surface_emit_surface (cairo_svg_document_t *document, assert (is_bounded); _cairo_output_stream_printf (document->xml_node_defs, - "<image id=\"image-%d\" x=\"%d\" y=\"%d\" width=\"%d\" height=\"%d\" xlink:href=\"", + "<image id=\"source-%d\" x=\"%d\" y=\"%d\" width=\"%d\" height=\"%d\" xlink:href=\"", source_id, extents.x, extents.y, extents.width, extents.height); @@ -1610,15 +1669,16 @@ _cairo_svg_surface_emit_composite_surface_pattern (cairo_output_stream_t *output /* cairo_pattern_set_matrix ensures the matrix is invertible */ assert (status == CAIRO_STATUS_SUCCESS); - unsigned int source_id; cairo_bool_t is_new; + cairo_svg_source_surface_t *source_surface; status = _cairo_svg_surface_add_source_surface (surface, pattern->surface, - &source_id, - &is_new); + &is_new, + &source_surface); if (unlikely (status)) { return status; } + unsigned int source_id = source_surface->id; if (is_new) { status = _cairo_svg_surface_emit_surface (surface->document, @@ -1655,7 +1715,7 @@ _cairo_svg_surface_emit_composite_surface_pattern (cairo_output_stream_t *output } _cairo_output_stream_printf (output, - "<use xlink:href=\"#image-%d\"", + "<use xlink:href=\"#source-%d\"", source_id); if (pattern->surface->content == CAIRO_CONTENT_ALPHA) { _cairo_output_stream_printf (output, @@ -1679,29 +1739,28 @@ _cairo_svg_surface_emit_composite_surface_pattern (cairo_output_stream_t *output } static cairo_status_t -_cairo_svg_surface_emit_recording_surface (cairo_svg_document_t *document, +_cairo_svg_surface_emit_recording_surface (cairo_svg_document_t *document, cairo_recording_surface_t *source, - unsigned int source_id) + unsigned int source_id, + cairo_bool_t *paint_used) { cairo_status_t status; - cairo_surface_t *paginated_surface; - cairo_svg_surface_t *svg_surface; - cairo_array_t *page_set; - cairo_rectangle_int_t extents; - cairo_bool_t bounded; - cairo_output_stream_t *contents; - - bounded = _cairo_surface_get_extents (&source->base, &extents); - paginated_surface = _cairo_svg_surface_create_for_document (document, - source->base.content, - 0, - 0, - FALSE); - if (unlikely (paginated_surface->status)) + + cairo_surface_t *paginated_surface = _cairo_svg_surface_create_for_document (document, + source->base.content, + 0, + 0, + FALSE); + cairo_svg_surface_t *svg_surface = (cairo_svg_surface_t *) _cairo_paginated_surface_get_target (paginated_surface); + if (unlikely (paginated_surface->status)) { return paginated_surface->status; + } + + svg_surface->source_id = source_id; + + cairo_rectangle_int_t extents; + cairo_bool_t bounded = _cairo_surface_get_extents (&source->base, &extents); - 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); @@ -1719,12 +1778,15 @@ _cairo_svg_surface_emit_recording_surface (cairo_svg_document_t *document, return status; } + unsigned int clip_id; if (bounded) { + clip_id = document->clip_id++; + _cairo_output_stream_printf (document->xml_node_defs, "<clipPath id=\"clip-%d\">\n" "<rect x=\"%d\" y=\"%d\" width=\"%d\" height=\"%d\"/>\n" "</clipPath>\n", - svg_surface->document->clip_id, + clip_id, extents.x, extents.y, extents.width, @@ -1732,13 +1794,13 @@ _cairo_svg_surface_emit_recording_surface (cairo_svg_document_t *document, } _cairo_output_stream_printf (document->xml_node_defs, - "<g id=\"surface-%d\"", + "<g id=\"source-%d\"", source_id); if (bounded) { _cairo_output_stream_printf (document->xml_node_defs, " clip-path=\"url(#clip-%d)\"", - svg_surface->document->clip_id); + clip_id); } if (source->base.content == CAIRO_CONTENT_ALPHA) { @@ -1749,14 +1811,7 @@ _cairo_svg_surface_emit_recording_surface (cairo_svg_document_t *document, _cairo_output_stream_printf (document->xml_node_defs, ">\n"); - if (bounded) { - svg_surface->document->clip_id++; - } - - contents = svg_surface->xml_node; - page_set = &svg_surface->page_set; - - if (_cairo_memory_stream_length (contents) > 0) { + if (_cairo_memory_stream_length (svg_surface->xml_node) > 0) { cairo_svg_page_t *page = _cairo_svg_surface_store_page (svg_surface); if (unlikely (page == NULL)) { cairo_surface_destroy (paginated_surface); @@ -1764,15 +1819,15 @@ _cairo_svg_surface_emit_recording_surface (cairo_svg_document_t *document, } } - if (page_set->num_elements > 0) { - cairo_svg_page_t *page; - - page = _cairo_array_index (page_set, page_set->num_elements - 1); + if (svg_surface->page_set.num_elements > 0) { + cairo_svg_page_t *page = _cairo_array_index (&svg_surface->page_set, svg_surface->page_set.num_elements - 1); _cairo_memory_stream_copy (page->xml_node, document->xml_node_defs); } _cairo_output_stream_printf (document->xml_node_defs, "</g>\n"); + *paint_used = svg_surface->paint_used; + status = cairo_surface_status (paginated_surface); cairo_surface_destroy (paginated_surface); @@ -1804,36 +1859,80 @@ _cairo_svg_surface_svg_clip_or_svg_mask_should_be_used (const cairo_pattern_t *p } static cairo_status_t -_cairo_svg_surface_emit_composite_recording_pattern (cairo_output_stream_t *output, - cairo_svg_surface_t *surface, - cairo_surface_pattern_t *pattern, - unsigned int pattern_id, - const cairo_matrix_t *parent_matrix) +_cairo_svg_surface_emit_composite_recording_pattern (cairo_output_stream_t *output, + cairo_svg_surface_t *surface, + cairo_surface_pattern_t *pattern, + unsigned int pattern_id, + const cairo_matrix_t *parent_matrix) { - cairo_svg_document_t *document = surface->document; - cairo_recording_surface_t *recording_surface; - cairo_matrix_t p2u; cairo_status_t status; - unsigned int source_id; - cairo_bool_t is_new; + cairo_svg_document_t *document = surface->document; - p2u = pattern->base.matrix; + cairo_matrix_t p2u = pattern->base.matrix; status = cairo_matrix_invert (&p2u); /* cairo_pattern_set_matrix ensures the matrix is invertible */ assert (status == CAIRO_STATUS_SUCCESS); + cairo_bool_t is_new; + cairo_svg_source_surface_t *source_surface; status = _cairo_svg_surface_add_source_surface (surface, pattern->surface, - &source_id, - &is_new); - if (unlikely (status)) + &is_new, + &source_surface); + if (unlikely (status)) { return status; + } + unsigned int source_id = source_surface->id; - recording_surface = _cairo_svg_surface_to_recording_surface (pattern); + cairo_recording_surface_t *recording_surface = _cairo_svg_surface_to_recording_surface (pattern); if (is_new) { - status = _cairo_svg_surface_emit_recording_surface (document, recording_surface, source_id); - if (unlikely (status)) + status = _cairo_svg_surface_emit_recording_surface (document, + recording_surface, + source_id, + &source_surface->paint_used); + if (unlikely (status)) { + return status; + } + } + + if (is_new && source_surface->paint_used) { + cairo_svg_paint_t *paint_entry = malloc (sizeof (cairo_svg_paint_t)); + if (paint_entry == NULL) { + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + paint_entry->source_id = source_id; + paint_entry->xml_node = _cairo_memory_stream_create(); + _cairo_svg_paint_init_key (paint_entry); + status = _cairo_hash_table_insert (document->paints, &paint_entry->base); + if (unlikely (status)) { return status; + } + } + + if (source_surface->paint_used) { + cairo_svg_paint_t paint_key; + paint_key.source_id = source_id; + _cairo_svg_paint_init_key (&paint_key); + + cairo_svg_paint_t *found_paint_entry = _cairo_hash_table_lookup (document->paints, + &paint_key.base); + assert (found_paint_entry); + + _cairo_output_stream_printf (found_paint_entry->xml_node, + "<use xlink:href=\"#paint-%d\"", + surface->source_id); + cairo_matrix_t matrix = pattern->base.matrix; + if (parent_matrix != NULL) { + cairo_matrix_t parent_matrix_inverse = *parent_matrix; + status = cairo_matrix_invert (&parent_matrix_inverse); + /* cairo_pattern_set_matrix ensures the matrix is invertible */ + assert (status == CAIRO_STATUS_SUCCESS); + cairo_matrix_multiply (&matrix, &parent_matrix_inverse, &matrix); + } + _cairo_svg_surface_emit_transform (found_paint_entry->xml_node, "transform", &matrix, NULL); + _cairo_output_stream_printf (found_paint_entry->xml_node, "/>\n"); + + surface->paint_used = TRUE; } if (pattern_id != invalid_pattern_id) { @@ -1857,7 +1956,7 @@ _cairo_svg_surface_emit_composite_recording_pattern (cairo_output_stream_t *outp } _cairo_output_stream_printf (output, - "<use xlink:href=\"#surface-%d\"", + "<use xlink:href=\"#source-%d\"", source_id); if (pattern_id == invalid_pattern_id) { @@ -1866,8 +1965,9 @@ _cairo_svg_surface_emit_composite_recording_pattern (cairo_output_stream_t *outp _cairo_output_stream_printf (output, "/>\n"); - if (pattern_id != invalid_pattern_id) + if (pattern_id != invalid_pattern_id) { _cairo_output_stream_printf (output, "</pattern>\n"); + } return CAIRO_STATUS_SUCCESS; } @@ -2458,9 +2558,10 @@ _cairo_svg_surface_emit_paint (cairo_output_stream_t *output, mask_source ? &mask_source->matrix : NULL); } + surface->paint_used = TRUE; _cairo_output_stream_printf (output, - "<rect x=\"-50%%\" y=\"-50%%\" " - "width=\"200%%\" height=\"200%%\""); + "<use xlink:href=\"#paint-%d\"", + surface->source_id); status = _cairo_svg_surface_emit_pattern (surface, source, output, FALSE, NULL); if (unlikely (status)) { return status; @@ -3505,31 +3606,29 @@ _cairo_svg_document_create (cairo_output_stream_t *output_stream, cairo_svg_document_t **document_out) { cairo_svg_document_t *document; - cairo_status_t status; if (output_stream->status) { return output_stream->status; } document = _cairo_malloc (sizeof (cairo_svg_document_t)); - if (unlikely (document == NULL)) + if (unlikely (document == NULL)) { return _cairo_error (CAIRO_STATUS_NO_MEMORY); - - /* The use of defs for font glyphs imposes no per-subset limit. */ - document->font_subsets = _cairo_scaled_font_subsets_create_scaled (); - if (unlikely (document->font_subsets == NULL)) { - status = _cairo_error (CAIRO_STATUS_NO_MEMORY); - goto cleanup_document; } document->output_stream = output_stream; document->refcount = 1; document->owner = NULL; document->finished = FALSE; + document->width = width; document->height = height; document->unit = CAIRO_SVG_UNIT_USER; + document->xml_node_defs = _cairo_memory_stream_create (); + document->xml_node_glyphs = _cairo_memory_stream_create (); + document->xml_node_filters = _cairo_memory_stream_create (); + document->linear_pattern_id = 0; document->radial_pattern_id = 0; document->pattern_id = 0; @@ -3542,18 +3641,30 @@ _cairo_svg_document_create (cairo_output_stream_t *output_stream, document->filters_emitted[filter] = FALSE; } - document->xml_node_defs = _cairo_memory_stream_create (); - document->xml_node_glyphs = _cairo_memory_stream_create (); - document->xml_node_filters = _cairo_memory_stream_create (); - document->svg_version = version; + /* The use of defs for font glyphs imposes no per-subset limit. */ + document->font_subsets = _cairo_scaled_font_subsets_create_scaled (); + if (unlikely (document->font_subsets == NULL)) { + (void) _cairo_output_stream_destroy(document->xml_node_defs); + (void) _cairo_output_stream_destroy(document->xml_node_glyphs); + (void) _cairo_output_stream_destroy(document->xml_node_filters); + free (document); + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + + document->paints = _cairo_hash_table_create (_cairo_svg_paint_equal); + if (unlikely (document->paints == NULL)) { + (void) _cairo_output_stream_destroy(document->xml_node_defs); + (void) _cairo_output_stream_destroy(document->xml_node_glyphs); + (void) _cairo_output_stream_destroy(document->xml_node_filters); + _cairo_scaled_font_subsets_destroy (document->font_subsets); + free (document); + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + *document_out = document; return CAIRO_STATUS_SUCCESS; - - cleanup_document: - free (document); - return status; } static cairo_svg_document_t * @@ -3588,7 +3699,7 @@ _cairo_svg_document_finish (cairo_svg_document_t *document) } document->finished = TRUE; - cairo_status_t status; + cairo_status_t status, final_status = CAIRO_STATUS_SUCCESS; cairo_output_stream_t *output = document->output_stream; @@ -3625,13 +3736,27 @@ _cairo_svg_document_finish (cairo_svg_document_t *document) document->width, document->height); status = _cairo_svg_document_emit_font_subsets (document); - if (unlikely (status)) { - return status; + if (final_status == CAIRO_STATUS_SUCCESS) { + final_status = status; + } + + cairo_svg_surface_t *surface = NULL; + if (document->owner != NULL) { + 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) { + cairo_svg_page_t *page = _cairo_svg_surface_store_page (surface); + if (final_status == CAIRO_STATUS_SUCCESS && page == NULL) { + final_status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + } } if (_cairo_memory_stream_length (document->xml_node_filters) > 0 || _cairo_memory_stream_length (document->xml_node_glyphs) > 0 || - _cairo_memory_stream_length (document->xml_node_defs) > 0) { + _cairo_memory_stream_length (document->xml_node_defs) > 0 || + _cairo_hash_table_size (document->paints) != 0 || + (surface != NULL && surface->paint_used)) { _cairo_output_stream_printf (output, "<defs>\n"); _cairo_memory_stream_copy (document->xml_node_filters, output); if (_cairo_memory_stream_length (document->xml_node_glyphs) > 0) { @@ -3640,19 +3765,17 @@ _cairo_svg_document_finish (cairo_svg_document_t *document) _cairo_output_stream_printf (output, "</g>\n"); } _cairo_memory_stream_copy (document->xml_node_defs, output); + _cairo_hash_table_foreach (document->paints, _cairo_svg_paint_emit, output); + if (surface != NULL && surface->paint_used) { + _cairo_output_stream_printf (output, + "<rect id=\"paint-%d\" x=\"0\" y=\"0\" width=\"%f\" height=\"%f\"/>\n", + surface->source_id, + document->width, document->height); + } _cairo_output_stream_printf (output, "</defs>\n"); } if (document->owner != NULL) { - cairo_svg_surface_t *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) { - cairo_svg_page_t *page = _cairo_svg_surface_store_page (surface); - if (unlikely (page == NULL)) { - return _cairo_error (CAIRO_STATUS_NO_MEMORY); - } - } - if (surface->page_set.num_elements == 1) { cairo_svg_page_t *page = _cairo_array_index (&surface->page_set, 0); _cairo_memory_stream_copy (page->xml_node, output); @@ -3670,24 +3793,27 @@ _cairo_svg_document_finish (cairo_svg_document_t *document) _cairo_output_stream_printf (output, "</svg>\n"); - status = _cairo_output_stream_destroy (document->xml_node_filters); - if (unlikely (status)) { - return status; + status = _cairo_output_stream_destroy (document->xml_node_defs); + if (final_status == CAIRO_STATUS_SUCCESS) { + final_status = status; } status = _cairo_output_stream_destroy (document->xml_node_glyphs); - if (unlikely (status)) { - return status; + if (final_status == CAIRO_STATUS_SUCCESS) { + final_status = status; } - status = _cairo_output_stream_destroy (document->xml_node_defs); - if (unlikely (status)) { - return status; + status = _cairo_output_stream_destroy (document->xml_node_filters); + if (final_status == CAIRO_STATUS_SUCCESS) { + final_status = status; } + _cairo_hash_table_foreach (document->paints, _cairo_svg_paint_pluck, document->paints); + _cairo_hash_table_destroy (document->paints); + status = _cairo_output_stream_destroy (output); - if (unlikely (status)) { - return status; + if (final_status == CAIRO_STATUS_SUCCESS) { + final_status = status; } return CAIRO_STATUS_SUCCESS; |