[cairo] Inline SVG images and the need to prefix identifiers

Bryce Harrington bryce at osg.samsung.com
Thu Sep 1 02:09:36 UTC 2016


On Sat, Oct 24, 2015 at 10:36:33AM +0200, Christian von Schultz wrote:
> On Fri, 2015-10-23 at 19:59 +0200, Uli Schlachter wrote:
> > This needs a "Since: 1.16".
> 
> New patch attached.
> 
> Cheers,
> Christian

> From c8acd6b6f73a8604e9d45c94fb562495f608a683 Mon Sep 17 00:00:00 2001
> From: Christian von Schultz <christian.git at vonschultz.se>
> Date: Fri, 23 Oct 2015 15:05:29 +0200
> Subject: [PATCH] cairo-svg: Added cairo_svg_surface_set_id_attribute_prefix()
>  and related code.
> 
> Inserts document->idprefix in every id attribute of the generated SVG file.
> This is useful if several SVG files will be merged in a single
> XML document (e.g. XHTML with inline SVG): You can prevent otherwise
> inevitable id clashes by giving the different SVG files different
> idprefix values.
> ---
>  src/cairo-svg-surface.c | 136 ++++++++++++++++++++++++++++++++++++------------
>  src/cairo-svg.h         |   4 ++
>  2 files changed, 108 insertions(+), 32 deletions(-)

Sorry I'm tardy about a year in commenting on this, but this does seem
like it would be a handy feature for the generated SVG files, where
the contents will be merged into another document.  I'd love to see
other people's thoughts.

I did a cursory look through the code and didn't spot any errors, and
agree with the general concept so:

Acked-by: Bryce Harrington <bryce at osg.samsung.com>


> diff --git a/src/cairo-svg-surface.c b/src/cairo-svg-surface.c
> index 2e023b3..9f3c111 100644
> --- a/src/cairo-svg-surface.c
> +++ b/src/cairo-svg-surface.c
> @@ -139,6 +139,8 @@ struct cairo_svg_document {
>      cairo_output_stream_t *xml_node_defs;
>      cairo_output_stream_t *xml_node_glyphs;
>  
> +    char *idprefix;
> +
>      unsigned int linear_pattern_id;
>      unsigned int radial_pattern_id;
>      unsigned int pattern_id;
> @@ -330,6 +332,38 @@ _extract_svg_surface (cairo_surface_t		 *surface,
>  }
>  
>  /**
> + * cairo_svg_surface_set_id_attribute_prefix:
> + * @surface: a SVG #cairo_surface_t
> + * @prefix:  a char*
> + *
> + * Inserts @prefix in every id attribute of the generated SVG file.
> + * This is useful if several SVG files will be merged in a single
> + * XML document (e.g. XHTML with inline SVG): You can prevent otherwise
> + * inevitable id clashes by giving the different SVG files different
> + * @prefix values.
> + *
> + * Since: 1.16
> + **/
> +cairo_status_t
> +cairo_svg_surface_set_id_attribute_prefix (cairo_surface_t	*abstract_surface,
> +					   const char		*prefix)
> +{
> +    cairo_svg_surface_t *surface = NULL; /* hide compiler warning */
> +    size_t size;
> +
> +    if (! _extract_svg_surface (abstract_surface, &surface))
> +	return CAIRO_STATUS_SURFACE_TYPE_MISMATCH;
> +
> +    size = strlen(prefix) + 1;
> +    surface->document->idprefix = realloc (surface->document->idprefix, size);
> +    if (unlikely (surface->document->idprefix == NULL))
> +	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
> +    strncpy(surface->document->idprefix, prefix, size);
> +
> +    return CAIRO_STATUS_SUCCESS;
> +}
> +
> +/**
>   * cairo_svg_surface_restrict_to_version:
>   * @surface: a SVG #cairo_surface_t
>   * @version: SVG version
> @@ -444,8 +478,9 @@ _cairo_svg_surface_clipper_intersect_clip_path (cairo_surface_clipper_t *clipper
>  	return CAIRO_STATUS_SUCCESS;
>  
>      _cairo_output_stream_printf (document->xml_node_defs,
> -				 "<clipPath id=\"clip%d\">\n"
> +				 "<clipPath id=\"%sclip%d\">\n"
>  				 "  <path ",
> +				 document->idprefix,
>  				 document->clip_id);
>      _cairo_svg_surface_emit_path (document->xml_node_defs, path, NULL);
>  
> @@ -454,8 +489,9 @@ _cairo_svg_surface_clipper_intersect_clip_path (cairo_surface_clipper_t *clipper
>  				 "</clipPath>\n");
>  
>      _cairo_output_stream_printf (surface->xml_node,
> -				 "<g clip-path=\"url(#clip%d)\" "
> +				 "<g clip-path=\"url(#%sclip%d)\" "
>  				 "clip-rule=\"%s\">\n",
> +				 document->idprefix,
>  				 document->clip_id,
>  				 fill_rule == CAIRO_FILL_RULE_EVEN_ODD ?
>  				 "evenodd" : "nonzero");
> @@ -840,7 +876,8 @@ _cairo_svg_document_emit_glyph (cairo_svg_document_t	*document,
>      cairo_int_status_t	     status;
>  
>      _cairo_output_stream_printf (document->xml_node_glyphs,
> -				 "<symbol overflow=\"visible\" id=\"glyph%d-%d\">\n",
> +				 "<symbol overflow=\"visible\" id=\"%sglyph%d-%d\">\n",
> +				 document->idprefix,
>  				 font_id,
>  				 subset_glyph_index);
>  
> @@ -1026,14 +1063,15 @@ _cairo_svg_surface_emit_alpha_filter (cairo_svg_document_t *document)
>  	return;
>  
>      _cairo_output_stream_printf (document->xml_node_defs,
> -				 "<filter id=\"alpha\" "
> +				 "<filter id=\"%salpha\" "
>  				 "filterUnits=\"objectBoundingBox\" "
>  				 "x=\"0%%\" y=\"0%%\" "
>  				 "width=\"100%%\" height=\"100%%\">\n"
>  				 "  <feColorMatrix type=\"matrix\" "
>  				 "in=\"SourceGraphic\" "
>  				 "values=\"0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0\"/>\n"
> -				 "</filter>\n");
> +				 "</filter>\n",
> +				 document->idprefix);
>  
>      document->alpha_filter = TRUE;
>  }
> @@ -1300,7 +1338,8 @@ _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\" width=\"%d\" height=\"%d\"",
> +				 "<image id=\"%simage%d\" width=\"%d\" height=\"%d\"",
> +				 document->idprefix,
>  				 surface->unique_id,
>  				 extents.width, extents.height);
>  
> @@ -1356,9 +1395,10 @@ _cairo_svg_surface_emit_composite_surface_pattern (cairo_output_stream_t   *outp
>  	assert (is_bounded);
>  
>  	_cairo_output_stream_printf (output,
> -				     "<pattern id=\"pattern%d\" "
> +				     "<pattern id=\"%spattern%d\" "
>  				     "patternUnits=\"userSpaceOnUse\" "
>  				     "width=\"%d\" height=\"%d\" ",
> +				     svg_surface->document->idprefix,
>  				     pattern_id,
>  				     extents.width, extents.height);
>  	_cairo_svg_surface_emit_transform (output,
> @@ -1368,7 +1408,8 @@ _cairo_svg_surface_emit_composite_surface_pattern (cairo_output_stream_t   *outp
>      }
>  
>      _cairo_output_stream_printf (output,
> -				 "<use xlink:href=\"#image%d\"",
> +				 "<use xlink:href=\"#%simage%d\"",
> +				 svg_surface->document->idprefix,
>  				 pattern->surface->unique_id);
>      if (extra_attributes)
>  	_cairo_output_stream_printf (output, " %s", extra_attributes);
> @@ -1437,9 +1478,10 @@ _cairo_svg_surface_emit_recording_surface (cairo_svg_document_t      *document,
>      if (! svg_surface->is_base_clip_emitted) {
>  	svg_surface->is_base_clip_emitted = TRUE;
>  	_cairo_output_stream_printf (document->xml_node_defs,
> -				     "<clipPath id=\"clip%d\">\n"
> +				     "<clipPath id=\"%sclip%d\">\n"
>  				     "  <rect width=\"%f\" height=\"%f\"/>\n"
>  				     "</clipPath>\n",
> +				     document->idprefix,
>  				     svg_surface->base_clip,
>  				     svg_surface->width,
>  				     svg_surface->height);
> @@ -1448,16 +1490,21 @@ _cairo_svg_surface_emit_recording_surface (cairo_svg_document_t      *document,
>      if (source->base.content == CAIRO_CONTENT_ALPHA) {
>  	_cairo_svg_surface_emit_alpha_filter (document);
>  	_cairo_output_stream_printf (document->xml_node_defs,
> -				     "<g id=\"surface%d\" "
> -				     "clip-path=\"url(#clip%d)\" "
> -				     "filter=\"url(#alpha)\">\n",
> +				     "<g id=\"%ssurface%d\" "
> +				     "clip-path=\"url(#%sclip%d)\" "
> +				     "filter=\"url(#%salpha)\">\n",
> +				     document->idprefix,
>  				     source->base.unique_id,
> -				     svg_surface->base_clip);
> +				     document->idprefix,
> +				     svg_surface->base_clip,
> +				     document->idprefix);
>      } else {
>  	_cairo_output_stream_printf (document->xml_node_defs,
> -				     "<g id=\"surface%d\" "
> -				     "clip-path=\"url(#clip%d)\">\n",
> +				     "<g id=\"%ssurface%d\" "
> +				     "clip-path=\"url(#%sclip%d)\">\n",
> +				     document->idprefix,
>  				     source->base.unique_id,
> +				     document->idprefix,
>  				     svg_surface->base_clip);
>      }
>  
> @@ -1529,9 +1576,10 @@ _cairo_svg_surface_emit_composite_recording_pattern (cairo_output_stream_t	*outp
>  
>      if (pattern_id != invalid_pattern_id) {
>  	_cairo_output_stream_printf (output,
> -				     "<pattern id=\"pattern%d\" "
> +				     "<pattern id=\"%spattern%d\" "
>  				     "patternUnits=\"userSpaceOnUse\" "
>  				     "width=\"%d\" height=\"%d\"",
> +				     document->idprefix,
>  				     pattern_id,
>  				     recording_surface->extents.width,
>  				     recording_surface->extents.height);
> @@ -1540,7 +1588,8 @@ _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=\"#%ssurface%d\"",
> +				 document->idprefix,
>  				 recording_surface->base.unique_id);
>  
>      if (pattern_id == invalid_pattern_id) {
> @@ -1620,8 +1669,9 @@ _cairo_svg_surface_emit_surface_pattern (cairo_svg_surface_t	 *surface,
>  	return status;
>  
>      _cairo_output_stream_printf (style,
> -				 "%s:url(#pattern%d);",
> +				 "%s:url(#%spattern%d);",
>  				 is_stroke ? "stroke" : "fill",
> +				 document->idprefix,
>  				 pattern_id);
>  
>      return CAIRO_STATUS_SUCCESS;
> @@ -1824,9 +1874,10 @@ _cairo_svg_surface_emit_linear_pattern (cairo_svg_surface_t    *surface,
>      assert (status == CAIRO_STATUS_SUCCESS);
>  
>      _cairo_output_stream_printf (document->xml_node_defs,
> -				 "<linearGradient id=\"linear%d\" "
> +				 "<linearGradient id=\"%slinear%d\" "
>  				 "gradientUnits=\"userSpaceOnUse\" "
>  				 "x1=\"%f\" y1=\"%f\" x2=\"%f\" y2=\"%f\" ",
> +				 document->idprefix,
>  				 document->linear_pattern_id,
>  				 pattern->pd1.x, pattern->pd1.y,
>  				 pattern->pd2.x, pattern->pd2.y);
> @@ -1845,8 +1896,9 @@ _cairo_svg_surface_emit_linear_pattern (cairo_svg_surface_t    *surface,
>  				 "</linearGradient>\n");
>  
>      _cairo_output_stream_printf (style,
> -				 "%s:url(#linear%d);",
> +				 "%s:url(#%slinear%d);",
>  				 is_stroke ? "stroke" : "fill",
> +				 document->idprefix,
>  				 document->linear_pattern_id);
>  
>      document->linear_pattern_id++;
> @@ -1898,10 +1950,11 @@ _cairo_svg_surface_emit_radial_pattern (cairo_svg_surface_t    *surface,
>  	unsigned int n_stops = pattern->base.n_stops;
>  
>  	_cairo_output_stream_printf (document->xml_node_defs,
> -				     "<radialGradient id=\"radial%d\" "
> +				     "<radialGradient id=\"%sradial%d\" "
>  				     "gradientUnits=\"userSpaceOnUse\" "
>  				     "cx=\"%f\" cy=\"%f\" "
>  				     "fx=\"%f\" fy=\"%f\" r=\"%f\" ",
> +				     document->idprefix,
>  				     document->radial_pattern_id,
>  				     x1, y1,
>  				     x1, y1, r1);
> @@ -1979,10 +2032,11 @@ _cairo_svg_surface_emit_radial_pattern (cairo_svg_surface_t    *surface,
>  	}
>  
>  	_cairo_output_stream_printf (document->xml_node_defs,
> -				     "<radialGradient id=\"radial%d\" "
> +				     "<radialGradient id=\"%sradial%d\" "
>  				     "gradientUnits=\"userSpaceOnUse\" "
>  				     "cx=\"%f\" cy=\"%f\" "
>  				     "fx=\"%f\" fy=\"%f\" r=\"%f\" ",
> +				     document->idprefix,
>  				     document->radial_pattern_id,
>  				     x1, y1,
>  				     fx, fy, r1);
> @@ -2027,8 +2081,9 @@ _cairo_svg_surface_emit_radial_pattern (cairo_svg_surface_t    *surface,
>  				 "</radialGradient>\n");
>  
>      _cairo_output_stream_printf (style,
> -				 "%s:url(#radial%d);",
> +				 "%s:url(#%sradial%d);",
>  				 is_stroke ? "stroke" : "fill",
> +				 document->idprefix,
>  				 document->radial_pattern_id);
>  
>      document->radial_pattern_id++;
> @@ -2427,10 +2482,14 @@ _cairo_svg_surface_mask (void		    *abstract_surface,
>      mask_id = _cairo_svg_document_allocate_mask_id (document);
>  
>      _cairo_output_stream_printf (mask_stream,
> -				 "<mask id=\"mask%d\">\n"
> -				 "%s",
> -				 mask_id,
> -				 discard_filter ? "" : "  <g filter=\"url(#alpha)\">\n");
> +				 "<mask id=\"%smask%d\">\n",
> +				 document->idprefix,
> +				 mask_id);
> +    if (!discard_filter) {
> +	_cairo_output_stream_printf (mask_stream,
> +				     "  <g filter=\"url(#%salpha)\">\n",
> +				     document->idprefix);
> +    }
>      status = _cairo_svg_surface_emit_paint (mask_stream, surface, CAIRO_OPERATOR_OVER, mask, source, NULL);
>      if (unlikely (status)) {
>  	cairo_status_t ignore = _cairo_output_stream_destroy (mask_stream);
> @@ -2448,7 +2507,8 @@ _cairo_svg_surface_mask (void		    *abstract_surface,
>      if (unlikely (status))
>  	return status;
>  
> -    snprintf (buffer, sizeof buffer, "mask=\"url(#mask%d)\"",
> +    snprintf (buffer, sizeof buffer, "mask=\"url(#%smask%d)\"",
> +	      document->idprefix,
>  	      mask_id);
>      status = _cairo_svg_surface_emit_paint (surface->xml_node, surface, op, source, 0, buffer);
>      if (unlikely (status))
> @@ -2558,8 +2618,9 @@ _cairo_svg_surface_show_glyphs (void			*abstract_surface,
>  	    return status;
>  
>  	_cairo_output_stream_printf (surface->xml_node,
> -				     "  <use xlink:href=\"#glyph%d-%d\" "
> +				     "  <use xlink:href=\"#%sglyph%d-%d\" "
>  				     "x=\"%f\" y=\"%f\"/>\n",
> +				     document->idprefix,
>  				     subset_glyph.font_id,
>                                       subset_glyph.subset_glyph_index,
>  				     glyphs[i].x, glyphs[i].y);
> @@ -2663,11 +2724,17 @@ _cairo_svg_document_create (cairo_output_stream_t	 *output_stream,
>      if (unlikely (document == NULL))
>  	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
>  
> +    document->idprefix = strdup("");
> +    if (unlikely (document->idprefix == NULL)) {
> +	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
> +	goto CLEANUP_DOCUMENT;
> +    }
> +
>      /* 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;
> +	goto CLEANUP_IDPREFIX;
>      }
>  
>      document->output_stream = output_stream;
> @@ -2706,6 +2773,8 @@ _cairo_svg_document_create (cairo_output_stream_t	 *output_stream,
>    CLEANUP_NODE_DEFS:
>      status_ignored = _cairo_output_stream_destroy (document->xml_node_defs);
>      _cairo_scaled_font_subsets_destroy (document->font_subsets);
> +  CLEANUP_IDPREFIX:
> +    free (document->idprefix);
>    CLEANUP_DOCUMENT:
>      free (document);
>      return status;
> @@ -2736,6 +2805,7 @@ _cairo_svg_document_destroy (cairo_svg_document_t *document)
>  
>      status = _cairo_svg_document_finish (document);
>  
> +    free (document->idprefix);
>      free (document);
>  
>      return status;
> @@ -2817,7 +2887,8 @@ _cairo_svg_document_finish (cairo_svg_document_t *document)
>  		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",
> +					     "<g id=\"%ssurface%d\">\n",
> +					     document->idprefix,
>  					     page->surface_id);
>  		_cairo_memory_stream_copy (page->xml_node, output);
>  		_cairo_output_stream_printf (output, "</g>\n</page>\n");
> @@ -2826,7 +2897,8 @@ _cairo_svg_document_finish (cairo_svg_document_t *document)
>  	} 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",
> +					 "<g id=\"%ssurface%d\">\n",
> +					 document->idprefix,
>  					 page->surface_id);
>  	    _cairo_memory_stream_copy (page->xml_node, output);
>  	    _cairo_output_stream_printf (output, "</g>\n");
> diff --git a/src/cairo-svg.h b/src/cairo-svg.h
> index 592c645..71ac4f5 100644
> --- a/src/cairo-svg.h
> +++ b/src/cairo-svg.h
> @@ -64,6 +64,10 @@ cairo_svg_surface_create_for_stream (cairo_write_func_t	write_func,
>  				     double		width_in_points,
>  				     double		height_in_points);
>  
> +cairo_public cairo_status_t
> +cairo_svg_surface_set_id_attribute_prefix (cairo_surface_t	*abstract_surface,
> +					   const char		*prefix);
> +
>  cairo_public void
>  cairo_svg_surface_restrict_to_version (cairo_surface_t 		*surface,
>  				       cairo_svg_version_t  	 version);
> -- 
> 2.4.10
> 

> -- 
> cairo mailing list
> cairo at cairographics.org
> http://lists.cairographics.org/mailman/listinfo/cairo



More information about the cairo mailing list