? cairo-svg-document-finish.patch Index: cairo-svg-surface.c =================================================================== RCS file: /cvs/cairo/cairo/src/cairo-svg-surface.c,v retrieving revision 1.8 diff -u -p -u -r1.8 cairo-svg-surface.c --- cairo-svg-surface.c 5 Jan 2006 23:00:37 -0000 1.8 +++ cairo-svg-surface.c 28 Jan 2006 21:48:47 -0000 @@ -67,6 +67,7 @@ struct cairo_svg_document { xmlDocPtr xml_doc; xmlNodePtr xml_node_defs; xmlNodePtr xml_node_main; + xmlNodePtr xml_node_svg; unsigned int surface_id; unsigned int linear_pattern_id; @@ -74,6 +75,8 @@ struct cairo_svg_document { unsigned int pattern_id; unsigned int filter_id; unsigned int clip_id; + + cairo_array_t pages; }; struct cairo_svg_surface { @@ -172,15 +175,40 @@ cairo_svg_surface_set_dpi (cairo_surface svg_surface->document->y_dpi = y_dpi; } +static void +_cairo_svg_surface_init_for_page (cairo_svg_surface_t *surface) +{ + xmlNodePtr clip, clip_rect; + int clip_id; + char buffer[CAIRO_SVG_DTOSTR_BUFFER_LEN]; + + surface->id = surface->document->surface_id++; + clip_id = surface->document->clip_id++; + + clip = xmlNewChild (surface->document->xml_node_defs, NULL, CC2XML ("clipPath"), NULL); + snprintf (buffer, sizeof buffer, "clip%d", clip_id); + xmlSetProp (clip, CC2XML ("id"), C2XML (buffer)); + clip_rect = xmlNewChild (clip, NULL, CC2XML ("rect"), NULL); + _cairo_dtostr (buffer, sizeof buffer, surface->width); + xmlSetProp (clip_rect, CC2XML ("width"), C2XML (buffer)); + _cairo_dtostr (buffer, sizeof buffer, surface->height); + xmlSetProp (clip_rect, CC2XML ("height"), C2XML (buffer)); + + surface->xml_node = xmlNewChild (surface->document->xml_node_main, + NULL, CC2XML ("g"), NULL); + + snprintf (buffer, sizeof buffer, "surface%d", surface->id); + xmlSetProp (surface->xml_node, CC2XML ("id"), C2XML (buffer)); + snprintf (buffer, sizeof buffer, "url(#clip%d)", clip_id); + xmlSetProp (surface->xml_node, CC2XML ("clip-path"), C2XML (buffer)); +} + static cairo_surface_t * _cairo_svg_surface_create_for_document (cairo_svg_document_t *document, double width, double height) { cairo_svg_surface_t *surface; - xmlNodePtr clip, clip_rect; - int clip_id; - char buffer[CAIRO_SVG_DTOSTR_BUFFER_LEN]; surface = malloc (sizeof (cairo_svg_surface_t)); if (surface == NULL) @@ -196,27 +224,7 @@ _cairo_svg_surface_create_for_document ( surface->clip_level = 0; - surface->id = document->surface_id++; - clip_id = document->clip_id++; - - clip = xmlNewChild (document->xml_node_defs, NULL, CC2XML ("clipPath"), NULL); - snprintf (buffer, sizeof buffer, "clip%d", clip_id); - xmlSetProp (clip, CC2XML ("id"), C2XML (buffer)); - clip_rect = xmlNewChild (clip, NULL, CC2XML ("rect"), NULL); - _cairo_dtostr (buffer, sizeof buffer, width); - xmlSetProp (clip_rect, CC2XML ("width"), C2XML (buffer)); - _cairo_dtostr (buffer, sizeof buffer, height); - xmlSetProp (clip_rect, CC2XML ("height"), C2XML (buffer)); - - surface->xml_node = xmlNewChild (surface->id == 0 ? - document->xml_node_main : - document->xml_node_defs, - NULL, CC2XML ("g"), NULL); - - snprintf (buffer, sizeof buffer, "surface%d", surface->id); - xmlSetProp (surface->xml_node, CC2XML ("id"), C2XML (buffer)); - snprintf (buffer, sizeof buffer, "url(#clip%d)", clip_id); - xmlSetProp (surface->xml_node, CC2XML ("clip-path"), C2XML (buffer)); + _cairo_svg_surface_init_for_page (surface); return &surface->base; } @@ -1085,6 +1093,53 @@ _cairo_svg_surface_composite_trapezoids return CAIRO_STATUS_SUCCESS; } +static cairo_status_t +_cairo_svg_document_add_page (cairo_svg_document_t *document, + cairo_svg_surface_t *surface) +{ + cairo_status_t status; + assert (!document->finished); + + status = _cairo_array_append (&document->pages, &document->xml_node_main); + if (status) + return status; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +_cairo_svg_surface_copy_page (void *abstract_surface) +{ + cairo_svg_surface_t *surface = abstract_surface; + cairo_svg_document_t *document = surface->document; + cairo_int_status_t status; + + status = _cairo_svg_document_add_page (document, surface); + if (status) + return status; + + document->xml_node_main = xmlCopyNode (document->xml_node_main, 1); + + 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_document_t *document = surface->document; + cairo_int_status_t status; + + status = _cairo_svg_document_add_page (document, surface); + if (status) + return status; + + document->xml_node_main = xmlNewNode (NULL, CC2XML ("g")); + _cairo_svg_surface_init_for_page (surface); + + return CAIRO_STATUS_SUCCESS; +} + static cairo_int_status_t _cairo_svg_surface_get_extents (void *abstract_surface, cairo_rectangle_t *rectangle) @@ -1362,8 +1417,8 @@ static const cairo_surface_backend_t cai _cairo_svg_surface_composite, _cairo_svg_surface_fill_rectangles, _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, @@ -1387,7 +1442,6 @@ _cairo_svg_document_create (cairo_output { cairo_svg_document_t *document; xmlDocPtr doc; - xmlNodePtr node; char buffer[CAIRO_SVG_DTOSTR_BUFFER_LEN]; document = malloc (sizeof (cairo_svg_document_t)); @@ -1410,22 +1464,25 @@ _cairo_svg_document_create (cairo_output document->filter_id = 0; document->clip_id = 0; + _cairo_array_init (&document->pages, sizeof (xmlNodePtr)); + doc = xmlNewDoc (CC2XML ("1.0")); - node = xmlNewNode (NULL, CC2XML ("svg")); + document->xml_node_svg = xmlNewNode (NULL, CC2XML ("svg")); - xmlDocSetRootElement (doc, node); + xmlDocSetRootElement (doc, document->xml_node_svg); document->xml_doc = doc; - document->xml_node_main = node; - document->xml_node_defs = xmlNewChild (node, NULL, CC2XML ("defs"), NULL); + document->xml_node_main = xmlNewNode (NULL, CC2XML ("g")); + document->xml_node_defs = xmlNewChild (document->xml_node_svg, NULL, CC2XML ("defs"), NULL); _cairo_dtostr (buffer, sizeof buffer, width); - xmlSetProp (node, CC2XML ("width"), CC2XML (buffer)); + xmlSetProp (document->xml_node_svg, CC2XML ("width"), CC2XML (buffer)); _cairo_dtostr (buffer, sizeof buffer, height); - xmlSetProp (node, CC2XML ("height"), CC2XML (buffer)); - xmlSetProp (node, CC2XML ("xmlns"), CC2XML ("http://www.w3.org/2000/svg")); - xmlSetProp (node, CC2XML ("xmlns:xlink"), CC2XML ("http://www.w3.org/1999/xlink")); - xmlSetProp (node, CC2XML ("version"), CC2XML ("1.1")); + xmlSetProp (document->xml_node_svg, CC2XML ("height"), CC2XML (buffer)); + xmlSetProp (document->xml_node_svg, CC2XML ("xmlns"), CC2XML ("http://www.w3.org/2000/svg")); + xmlSetProp (document->xml_node_svg, CC2XML ("xmlns:xlink"), CC2XML ("http://www.w3.org/1999/xlink")); + xmlSetProp (document->xml_node_svg, CC2XML ("version"), CC2XML ("1.2")); + xmlSetProp (document->xml_node_svg, CC2XML ("streamable"), CC2XML ("true")); return document; } @@ -1445,6 +1502,7 @@ _cairo_svg_document_destroy (cairo_svg_d _cairo_svg_document_finish (document); + _cairo_array_fini (&document->pages); free (document); } @@ -1455,14 +1513,36 @@ _cairo_svg_document_finish (cairo_svg_do cairo_output_stream_t *output = document->output_stream; xmlChar *xml_buffer; int xml_buffer_size; + xmlNodePtr *pages; + int number_of_pages; if (document->finished) return CAIRO_STATUS_SUCCESS; + pages = _cairo_array_index (&document->pages, 0); + number_of_pages = _cairo_array_num_elements (&document->pages); + + if (number_of_pages == 1) + xmlAddChild (document->xml_node_svg, pages[0]); + else { + xmlNodePtr node_pageset; + int i; + + node_pageset = xmlNewChild (document->xml_node_svg, NULL, CC2XML ("pageSet"), NULL); + + for (i = 0; i < number_of_pages; i++) { + xmlNodePtr node_page; + + node_page = xmlNewChild (node_pageset, NULL, CC2XML ("page"), NULL); + xmlAddChild (node_page, pages[i]); + } + } + /* FIXME: Dumping xml tree in memory is silly. */ xmlDocDumpFormatMemoryEnc (document->xml_doc, &xml_buffer, &xml_buffer_size, "UTF-8", 1); _cairo_output_stream_write (document->output_stream, xml_buffer, xml_buffer_size); xmlFree(xml_buffer); + xmlFreeNode (document->xml_node_main); /* must free, since this is node wasn't added to the tree */ xmlFreeDoc (document->xml_doc); status = _cairo_output_stream_get_status (output);