diff --git a/src/cairo-svg-surface.c b/src/cairo-svg-surface.c index d4c60b6..258fe24 100644 --- a/src/cairo-svg-surface.c +++ b/src/cairo-svg-surface.c @@ -49,6 +49,7 @@ #include "cairo-output-stream-private.h" typedef struct cairo_svg_document cairo_svg_document_t; typedef struct cairo_svg_surface cairo_svg_surface_t; +typedef struct cairo_svg_page cairo_svg_page_t; static const int invalid_pattern_id = -1; @@ -60,6 +61,12 @@ static const cairo_svg_version_t _cairo_ #define CAIRO_SVG_VERSION_LAST ((int)(sizeof (_cairo_svg_versions) / sizeof (_cairo_svg_versions[0]))) +static cairo_bool_t +_cairo_svg_version_has_page_set_support (cairo_svg_version_t version) +{ + return version > CAIRO_SVG_VERSION_1_1; +} + static const char * _cairo_svg_version_strings[CAIRO_SVG_VERSION_LAST] = { "SVG 1.1", @@ -72,6 +79,13 @@ static const char * _cairo_svg_internal_ "1.2" }; +struct cairo_svg_page { + unsigned int surface_id; + unsigned int clip_id; + unsigned int clip_level; + cairo_output_stream_t *xml_node; +}; + struct cairo_svg_document { cairo_output_stream_t *output_stream; unsigned long refcount; @@ -114,6 +128,7 @@ struct cairo_svg_surface { cairo_svg_document_t *document; cairo_output_stream_t *xml_node; + cairo_array_t page_set; unsigned int clip_level; unsigned int base_clip; @@ -370,6 +385,7 @@ _cairo_svg_surface_create_for_document ( width, height); surface->xml_node = _cairo_memory_stream_create (); + _cairo_array_init (&surface->page_set, sizeof (cairo_svg_page_t)); if (content == CAIRO_CONTENT_COLOR) { _cairo_output_stream_printf (surface->xml_node, @@ -412,6 +428,53 @@ _cairo_svg_surface_create_for_stream_int return surface; } +static cairo_svg_page_t * +_cairo_svg_surface_store_page (cairo_svg_surface_t *surface) +{ + unsigned int i; + cairo_svg_page_t page; + + page.xml_node = _cairo_memory_stream_create (); + page.surface_id = surface->id; + page.clip_id = surface->base_clip; + page.clip_level = surface->clip_level; + + page.xml_node = surface->xml_node; + surface->xml_node = _cairo_memory_stream_create (); + surface->clip_level = 0; + + for (i = 0; i < page.clip_level; i++) + _cairo_output_stream_printf (page.xml_node, "\n"); + + _cairo_array_append (&surface->page_set, &page); + + return _cairo_array_index (&surface->page_set, surface->page_set.num_elements - 1); +} + +static cairo_int_status_t +_cairo_svg_surface_copy_page (void *abstract_surface) +{ + cairo_svg_surface_t *surface = abstract_surface; + cairo_svg_page_t *page; + + page = _cairo_svg_surface_store_page (surface); + + _cairo_memory_stream_copy (page->xml_node, surface->xml_node); + surface->clip_level = page->clip_level; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +_cairo_svg_surface_show_page (void *abstract_surface) +{ + cairo_svg_surface_t *surface = abstract_surface; + + _cairo_svg_surface_store_page (surface); + + return CAIRO_STATUS_SUCCESS; +} + static void emit_transform (cairo_output_stream_t *output, char const *attribute_str, @@ -716,6 +779,8 @@ _cairo_svg_surface_finish (void *abstrac cairo_status_t status; cairo_svg_surface_t *surface = abstract_surface; cairo_svg_document_t *document = surface->document; + cairo_svg_page_t *page; + unsigned int i; if (_cairo_paginated_surface_get_target (document->owner) == &surface->base) status = _cairo_svg_document_finish (document); @@ -724,6 +789,12 @@ _cairo_svg_surface_finish (void *abstrac _cairo_output_stream_destroy (surface->xml_node); + for (i = 0; i < surface->page_set.num_elements; i++) { + page = _cairo_array_index (&surface->page_set, i); + _cairo_output_stream_destroy (page->xml_node); + } + _cairo_array_fini (&surface->page_set); + _cairo_svg_document_destroy (document); return status; @@ -923,6 +994,7 @@ emit_meta_surface (cairo_svg_document_t cairo_surface_t *paginated_surface; cairo_surface_t *svg_surface; cairo_meta_snapshot_t new_snapshot; + cairo_array_t *page_set; meta = (cairo_meta_surface_t *) _cairo_surface_snapshot ((cairo_surface_t *)surface); paginated_surface = _cairo_svg_surface_create_for_document (document, @@ -957,10 +1029,17 @@ emit_meta_surface (cairo_svg_document_t } contents = ((cairo_svg_surface_t *) svg_surface)->xml_node; - _cairo_memory_stream_copy (contents, document->xml_node_defs); + page_set = &((cairo_svg_surface_t *) svg_surface)->page_set; + + if (_cairo_memory_stream_length (contents) > 0) + _cairo_svg_surface_store_page ((cairo_svg_surface_t *) svg_surface); - for (i = 0; i < ((cairo_svg_surface_t *) svg_surface)->clip_level; i++) - _cairo_output_stream_printf (document->xml_node_defs, "\n"); + if (page_set->num_elements > 0) { + cairo_svg_page_t *page; + + page = _cairo_array_index (page_set, page_set->num_elements - 1); + _cairo_memory_stream_copy (page->xml_node, document->xml_node_defs); + } _cairo_output_stream_printf (document->xml_node_defs, "\n"); @@ -1664,8 +1743,8 @@ static const cairo_surface_backend_t cai NULL, /* _cairo_svg_surface_composite, */ NULL, /* _cairo_svg_surface_fill_rectangles, */ NULL, /* _cairo_svg_surface_composite_trapezoids,*/ - NULL, /* copy_page */ - NULL, /* show_page */ + _cairo_svg_surface_copy_page, + _cairo_svg_surface_show_page, NULL, /* set_clip_region */ _cairo_svg_surface_intersect_clip_path, _cairo_svg_surface_get_extents, @@ -1759,6 +1838,7 @@ _cairo_svg_document_finish (cairo_svg_do 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; if (document->finished) @@ -1788,17 +1868,36 @@ _cairo_svg_document_finish (cairo_svg_do } surface = (cairo_svg_surface_t *) _cairo_paginated_surface_get_target (document->owner); - _cairo_output_stream_printf (output, - "\n", - surface->id, - surface->base_clip); - _cairo_memory_stream_copy (surface->xml_node, output); - - for (i = 0; i < surface->clip_level; i++) + 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, "\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, + page->clip_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, + page->clip_id); + _cairo_memory_stream_copy (page->xml_node, output); _cairo_output_stream_printf (output, "\n"); + } - _cairo_output_stream_printf (output, "\n\n"); + _cairo_output_stream_printf (output, "\n"); _cairo_output_stream_destroy (document->xml_node_glyphs); _cairo_output_stream_destroy (document->xml_node_defs); diff --git a/test/fallback-resolution.c b/test/fallback-resolution.c index 25cdcdc..5448765 100644 --- a/test/fallback-resolution.c +++ b/test/fallback-resolution.c @@ -112,7 +112,8 @@ main (void) break; case SVG: surface = cairo_svg_surface_create (backend_filename[backend], - SIZE, SIZE * num_pages); + SIZE, SIZE); + cairo_svg_surface_restrict_to_version (surface, CAIRO_SVG_VERSION_1_2); _cairo_svg_test_force_fallbacks (); break; } @@ -125,35 +126,7 @@ main (void) draw_with_ppi (cr, SIZE, SIZE, ppi[page]); - /* Backend-specific means of "advancing a page" */ - switch (backend) { - case PDF: - case PS: - cairo_show_page (cr); - break; - case SVG: - /* Since the SVG backend doesn't natively support multiple - * pages, we just move further down for each logical - * page, then finally do a show_page at the end. */ - if (page < num_pages - 1) { - cairo_translate (cr, 0, SIZE); - } else { - /* XXX: The goal of this test is to show the - * effect of several different fallback - * resolutions in a single output document. But - * since fallback_resolution only takes effect at - * the time of show_page, we only get once for the - * SVG backend. I'm just re-setting the first one - * here so we actually get legible output. - * - * To fix this properly we'll need some sort of - * multi-page support in the SVG backend I think. - */ - cairo_surface_set_fallback_resolution (surface, ppi[0], ppi[0]); - cairo_show_page (cr); - } - break; - } + cairo_show_page (cr); } status = cairo_status (cr); diff --git a/test/pixman-rotate.c b/test/pixman-rotate.c index 425f883..ca4d961 100644 --- a/test/pixman-rotate.c +++ b/test/pixman-rotate.c @@ -63,8 +63,6 @@ #endif cairo_set_source_surface (cr, stamp, 0, 0); cairo_paint (cr); - cairo_show_page (cr); - cairo_surface_destroy (stamp); return CAIRO_TEST_SUCCESS;