[cairo-commit] src/cairo-svg-surface.c
Emmanuel Pacaud
emmanuel at kemper.freedesktop.org
Sat May 6 05:57:28 PDT 2006
src/cairo-svg-surface.c | 571 +++++++++++++++++++++++++++++++++++++-----------
1 files changed, 450 insertions(+), 121 deletions(-)
New commits:
diff-tree 1da2ca0f3575fe00e7e3f2ce27cf0e3416517573 (from 09e94c6a31e58ff85c597d4791b6ec5006f73797)
Author: Emmanuel Pacaud <emmanuel.pacaud at free.fr>
Date: Sat May 6 14:56:20 2006 +0200
SVG: Implementation of glyph cache
This is an adaptation of Keith ps-type3 branch for SVG backend.
Main differences with ps stuff are font cache is a property of
document, and there's no need of subfonts.
diff --git a/src/cairo-svg-surface.c b/src/cairo-svg-surface.c
index 2c5066b..2ad4d61 100644
--- a/src/cairo-svg-surface.c
+++ b/src/cairo-svg-surface.c
@@ -73,6 +73,19 @@ static const char * _cairo_svg_internal_
"1.2"
};
+typedef struct cairo_svg_glyph {
+ cairo_hash_entry_t base; /* font glyph index */
+ unsigned int output_glyph; /* font glyph index */
+} cairo_svg_glyph_t;
+
+typedef struct cairo_svg_font {
+ cairo_hash_entry_t base;
+ cairo_scaled_font_t *scaled_font;
+ unsigned int output_font;
+ cairo_hash_table_t *glyphs;
+ unsigned int max_glyph;
+} cairo_svg_font_t;
+
struct cairo_svg_document {
cairo_output_stream_t *output_stream;
unsigned long refcount;
@@ -101,6 +114,9 @@ struct cairo_svg_document {
cairo_array_t meta_snapshots;
cairo_svg_version_t svg_version;
+
+ cairo_hash_table_t *fonts;
+ unsigned int max_font;
};
struct cairo_svg_surface {
@@ -148,36 +164,14 @@ _cairo_svg_surface_create_for_document (
cairo_content_t content,
double width,
double height);
-
-static const cairo_surface_backend_t cairo_svg_surface_backend;
-static const cairo_paginated_surface_backend_t cairo_svg_surface_paginated_backend;
-
static cairo_surface_t *
_cairo_svg_surface_create_for_stream_internal (cairo_output_stream_t *stream,
double width,
double height,
- cairo_svg_version_t version)
-{
- cairo_svg_document_t *document;
- cairo_surface_t *surface;
+ cairo_svg_version_t version);
- document = _cairo_svg_document_create (stream, width, height, version);
- if (document == NULL) {
- _cairo_error (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);
-
- document->owner = surface;
- _cairo_svg_document_destroy (document);
-
- return _cairo_paginated_surface_create (surface,
- CAIRO_CONTENT_COLOR_ALPHA,
- width, height,
- &cairo_svg_surface_paginated_backend);
-}
+static const cairo_surface_backend_t cairo_svg_surface_backend;
+static const cairo_paginated_surface_backend_t cairo_svg_surface_paginated_backend;
/**
* cairo_svg_surface_create_for_stream:
@@ -448,6 +442,372 @@ _cairo_svg_surface_create_for_document (
return &surface->base;
}
+static cairo_surface_t *
+_cairo_svg_surface_create_for_stream_internal (cairo_output_stream_t *stream,
+ double width,
+ double height,
+ cairo_svg_version_t version)
+{
+ cairo_svg_document_t *document;
+ cairo_surface_t *surface;
+
+ document = _cairo_svg_document_create (stream, width, height, version);
+ if (document == NULL) {
+ _cairo_error (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);
+
+ document->owner = surface;
+ _cairo_svg_document_destroy (document);
+
+ return _cairo_paginated_surface_create (surface,
+ CAIRO_CONTENT_COLOR_ALPHA,
+ width, height,
+ &cairo_svg_surface_paginated_backend);
+}
+
+typedef struct
+{
+ cairo_svg_document_t *document;
+ xmlBufferPtr path;
+} svg_path_info_t;
+
+static cairo_status_t
+_cairo_svg_path_move_to (void *closure, cairo_point_t *point)
+{
+ svg_path_info_t *info = closure;
+ xmlBufferPtr path = info->path;
+ char buffer[CAIRO_SVG_DTOSTR_BUFFER_LEN];
+
+ xmlBufferCat (path, CC2XML ("M "));
+ _cairo_dtostr (buffer, sizeof buffer, _cairo_fixed_to_double (point->x));
+ xmlBufferCat (path, CC2XML (buffer));
+ xmlBufferCat (path, CC2XML (" "));
+ _cairo_dtostr (buffer, sizeof buffer, _cairo_fixed_to_double (point->y));
+ xmlBufferCat (path, CC2XML (buffer));
+ xmlBufferCat (path, CC2XML (" "));
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_svg_path_line_to (void *closure, cairo_point_t *point)
+{
+ svg_path_info_t *info = closure;
+ xmlBufferPtr path = info->path;
+ char buffer[CAIRO_SVG_DTOSTR_BUFFER_LEN];
+
+ xmlBufferCat (path, CC2XML ("L "));
+
+ _cairo_dtostr (buffer, sizeof buffer, _cairo_fixed_to_double (point->x));
+ xmlBufferCat (path, CC2XML (buffer));
+ xmlBufferCat (path, CC2XML (" "));
+ _cairo_dtostr (buffer, sizeof buffer, _cairo_fixed_to_double (point->y));
+ xmlBufferCat (path, CC2XML (buffer));
+ xmlBufferCat (path, CC2XML (" "));
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_svg_path_curve_to (void *closure,
+ cairo_point_t *b,
+ cairo_point_t *c,
+ cairo_point_t *d)
+{
+ svg_path_info_t *info = closure;
+ xmlBufferPtr path = info->path;
+ char buffer[CAIRO_SVG_DTOSTR_BUFFER_LEN];
+
+ xmlBufferCat (path, CC2XML ("C "));
+ _cairo_dtostr (buffer, sizeof buffer, _cairo_fixed_to_double (b->x));
+ xmlBufferCat (path, CC2XML (buffer));
+ xmlBufferCat (path, CC2XML (" "));
+ _cairo_dtostr (buffer, sizeof buffer, _cairo_fixed_to_double (b->y));
+ xmlBufferCat (path, CC2XML (buffer));
+ xmlBufferCat (path, CC2XML (" "));
+ _cairo_dtostr (buffer, sizeof buffer, _cairo_fixed_to_double (c->x));
+ xmlBufferCat (path, CC2XML (buffer));
+ xmlBufferCat (path, CC2XML (" "));
+ _cairo_dtostr (buffer, sizeof buffer, _cairo_fixed_to_double (c->y));
+ xmlBufferCat (path, CC2XML (buffer));
+ xmlBufferCat (path, CC2XML (" "));
+ _cairo_dtostr (buffer, sizeof buffer, _cairo_fixed_to_double (d->x));
+ xmlBufferCat (path, CC2XML (buffer));
+ xmlBufferCat (path, CC2XML (" "));
+ _cairo_dtostr (buffer, sizeof buffer, _cairo_fixed_to_double (d->y));
+ xmlBufferCat (path, CC2XML (buffer));
+ xmlBufferCat (path, CC2XML (" "));
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_svg_path_close_path (void *closure)
+{
+ svg_path_info_t *info = closure;
+
+ xmlBufferCat (info->path, CC2XML ("Z "));
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_bool_t
+_cairo_svg_glyph_equal (const void *key_a, const void *key_b)
+{
+ const cairo_svg_glyph_t *svg_glyph_a = key_a;
+ const cairo_svg_glyph_t *svg_glyph_b = key_b;
+
+ return svg_glyph_a->base.hash == svg_glyph_b->base.hash;
+}
+
+static void
+_cairo_svg_glyph_key_init (cairo_svg_glyph_t *svg_glyph,
+ unsigned long index)
+{
+ svg_glyph->base.hash = index;
+}
+
+static cairo_svg_glyph_t *
+_cairo_svg_glyph_create (cairo_svg_font_t *svg_font,
+ unsigned long index)
+{
+ cairo_svg_glyph_t *svg_glyph = malloc (sizeof (cairo_svg_glyph_t));
+
+ if (!svg_glyph)
+ return NULL;
+
+ _cairo_svg_glyph_key_init (svg_glyph, index);
+ svg_glyph->output_glyph = svg_font->max_glyph++;
+
+ return svg_glyph;
+}
+
+static void
+_cairo_svg_glyph_destroy (cairo_svg_glyph_t *svg_glyph)
+{
+ free (svg_glyph);
+}
+
+static cairo_status_t
+_cairo_svg_glyph_find (cairo_svg_font_t *font,
+ cairo_scaled_font_t *scaled_font,
+ unsigned long index,
+ cairo_svg_glyph_t **result)
+{
+ cairo_svg_glyph_t key;
+ cairo_svg_glyph_t *svg_glyph;
+ cairo_status_t status;
+
+ _cairo_svg_glyph_key_init (&key, index);
+ if (!_cairo_hash_table_lookup (font->glyphs,
+ &key.base,
+ (cairo_hash_entry_t **) &svg_glyph)) {
+ svg_glyph = _cairo_svg_glyph_create (font, index);
+ if (!svg_glyph)
+ return CAIRO_STATUS_NO_MEMORY;
+
+ status = _cairo_hash_table_insert (font->glyphs, &svg_glyph->base);
+ if (status)
+ return status;
+ }
+ *result = svg_glyph;
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_bool_t
+_cairo_svg_font_equal (const void *key_a, const void *key_b)
+{
+ const cairo_svg_font_t *svg_font_a = key_a;
+ const cairo_svg_font_t *svg_font_b = key_b;
+
+ return svg_font_a->scaled_font == svg_font_b->scaled_font;
+}
+
+static void
+_cairo_svg_font_key_init (cairo_svg_font_t *svg_font,
+ cairo_scaled_font_t *scaled_font)
+{
+ /* FIXME cast a pointer to unsigned long, really ? */
+ svg_font->base.hash = (unsigned long) scaled_font;
+ svg_font->scaled_font = scaled_font;
+}
+
+static cairo_svg_font_t *
+_cairo_svg_document_font_create (cairo_svg_document_t *document,
+ cairo_scaled_font_t *scaled_font)
+{
+ cairo_svg_font_t *svg_font = malloc (sizeof (cairo_svg_font_t));
+
+ if (!svg_font)
+ return NULL;
+
+ _cairo_svg_font_key_init (svg_font, scaled_font);
+ svg_font->glyphs = _cairo_hash_table_create (_cairo_svg_glyph_equal);
+ if (!svg_font->glyphs) {
+ free (svg_font);
+ return NULL;
+ }
+
+ svg_font->max_glyph = 0;
+ svg_font->output_font = document->max_font++;
+ cairo_scaled_font_reference (svg_font->scaled_font);
+ return svg_font;
+}
+
+static void
+_cairo_svg_font_destroy_glyph (void *entry, void *closure)
+{
+ cairo_svg_glyph_t *svg_glyph = entry;
+ cairo_svg_font_t *svg_font = closure;
+
+ _cairo_hash_table_remove (svg_font->glyphs, &svg_glyph->base);
+ _cairo_svg_glyph_destroy (svg_glyph);
+}
+
+static void
+_cairo_svg_font_destroy (cairo_svg_font_t *svg_font)
+{
+ _cairo_hash_table_foreach (svg_font->glyphs,
+ _cairo_svg_font_destroy_glyph,
+ svg_font);
+ _cairo_hash_table_destroy (svg_font->glyphs);
+ cairo_scaled_font_destroy (svg_font->scaled_font);
+ free (svg_font);
+}
+
+static void
+_cairo_svg_document_destroy_font (cairo_svg_document_t *document,
+ cairo_svg_font_t *svg_font)
+{
+ _cairo_hash_table_remove (document->fonts, &svg_font->base);
+ _cairo_svg_font_destroy (svg_font);
+}
+
+static cairo_status_t
+_cairo_svg_document_font_find (cairo_svg_document_t *document,
+ cairo_scaled_font_t *scaled_font,
+ cairo_svg_font_t **result)
+{
+ cairo_svg_font_t key;
+ cairo_svg_font_t *svg_font;
+ cairo_status_t status;
+
+ _cairo_svg_font_key_init (&key, scaled_font);
+ if (!_cairo_hash_table_lookup (document->fonts, &key.base,
+ (cairo_hash_entry_t **) &svg_font))
+ {
+ svg_font = _cairo_svg_document_font_create (document, scaled_font);
+ if (!svg_font)
+ return CAIRO_STATUS_NO_MEMORY;
+ status = _cairo_hash_table_insert (document->fonts,
+ &svg_font->base);
+ if (status)
+ return status;
+ }
+ *result = svg_font;
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_svg_document_emit_glyph (cairo_svg_document_t *document,
+ cairo_svg_font_t *svg_font,
+ cairo_svg_glyph_t *svg_glyph)
+{
+ cairo_scaled_glyph_t *scaled_glyph;
+ cairo_status_t status;
+ svg_path_info_t info;
+ xmlNodePtr symbol, child;
+ char buffer[CAIRO_SVG_DTOSTR_BUFFER_LEN];
+
+ status = _cairo_scaled_glyph_lookup (svg_font->scaled_font,
+ svg_glyph->base.hash,
+ CAIRO_SCALED_GLYPH_INFO_METRICS|
+ CAIRO_SCALED_GLYPH_INFO_PATH,
+ &scaled_glyph);
+ /*
+ * If that fails, try again but ask for an image instead
+ */
+ if (status)
+ status = _cairo_scaled_glyph_lookup (svg_font->scaled_font,
+ svg_glyph->base.hash,
+ CAIRO_SCALED_GLYPH_INFO_METRICS|
+ CAIRO_SCALED_GLYPH_INFO_SURFACE,
+ &scaled_glyph);
+ if (status)
+ return status;
+
+ info.document = document;
+ info.path = xmlBufferCreate ();
+
+ status = _cairo_path_fixed_interpret (scaled_glyph->path,
+ CAIRO_DIRECTION_FORWARD,
+ _cairo_svg_path_move_to,
+ _cairo_svg_path_line_to,
+ _cairo_svg_path_curve_to,
+ _cairo_svg_path_close_path,
+ &info);
+
+ symbol = xmlNewChild (document->xml_node_defs, NULL, CC2XML ("symbol"), NULL);
+ snprintf (buffer, sizeof buffer, "glyph%d-%d",
+ svg_font->output_font,
+ svg_glyph->output_glyph);
+ xmlSetProp (symbol, CC2XML ("id"), C2XML (buffer));
+ child = xmlNewChild (symbol, NULL, CC2XML ("path"), NULL);
+ xmlSetProp (child, CC2XML ("d"), xmlBufferContent (info.path));
+ xmlSetProp (child, CC2XML ("style"), CC2XML ("stroke: none;"));
+
+ xmlBufferFree (info.path);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+typedef struct {
+ cairo_svg_document_t *document;
+ cairo_svg_font_t *svg_font;
+} emit_glyph_info_t;
+
+static void
+_emit_glyph (void *entry, void *closure)
+{
+ cairo_svg_glyph_t *svg_glyph = entry;
+ emit_glyph_info_t *info = closure;
+
+ _cairo_svg_document_emit_glyph (info->document,
+ info->svg_font,
+ svg_glyph);
+ _cairo_svg_font_destroy_glyph (svg_glyph, info->svg_font);
+}
+
+static void
+_cairo_svg_document_emit_font (void *entry, void *closure)
+{
+ cairo_svg_font_t *svg_font = entry;
+ cairo_svg_document_t *document = closure;
+ emit_glyph_info_t info;
+
+ info.document = document;
+ info.svg_font = svg_font;
+
+ _cairo_hash_table_foreach (svg_font->glyphs,
+ _emit_glyph,
+ &info);
+ _cairo_svg_document_destroy_font (document, svg_font);
+}
+
+static void
+_cairo_svg_document_emit_fonts (cairo_svg_document_t *document)
+{
+ _cairo_hash_table_foreach (document->fonts,
+ _cairo_svg_document_emit_font,
+ document);
+ _cairo_hash_table_destroy (document->fonts);
+ document->fonts = NULL;
+}
+
static cairo_int_status_t
_operation_supported (cairo_svg_surface_t *surface,
cairo_operator_t op,
@@ -1123,92 +1483,6 @@ emit_pattern (cairo_svg_surface_t *surfa
}
}
-typedef struct
-{
- cairo_svg_document_t *document;
- xmlBufferPtr path;
-} svg_path_info_t;
-
-static cairo_status_t
-_cairo_svg_path_move_to (void *closure, cairo_point_t *point)
-{
- svg_path_info_t *info = closure;
- xmlBufferPtr path = info->path;
- char buffer[CAIRO_SVG_DTOSTR_BUFFER_LEN];
-
- xmlBufferCat (path, CC2XML ("M "));
- _cairo_dtostr (buffer, sizeof buffer, _cairo_fixed_to_double (point->x));
- xmlBufferCat (path, CC2XML (buffer));
- xmlBufferCat (path, CC2XML (" "));
- _cairo_dtostr (buffer, sizeof buffer, _cairo_fixed_to_double (point->y));
- xmlBufferCat (path, CC2XML (buffer));
- xmlBufferCat (path, CC2XML (" "));
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_svg_path_line_to (void *closure, cairo_point_t *point)
-{
- svg_path_info_t *info = closure;
- xmlBufferPtr path = info->path;
- char buffer[CAIRO_SVG_DTOSTR_BUFFER_LEN];
-
- xmlBufferCat (path, CC2XML ("L "));
-
- _cairo_dtostr (buffer, sizeof buffer, _cairo_fixed_to_double (point->x));
- xmlBufferCat (path, CC2XML (buffer));
- xmlBufferCat (path, CC2XML (" "));
- _cairo_dtostr (buffer, sizeof buffer, _cairo_fixed_to_double (point->y));
- xmlBufferCat (path, CC2XML (buffer));
- xmlBufferCat (path, CC2XML (" "));
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_svg_path_curve_to (void *closure,
- cairo_point_t *b,
- cairo_point_t *c,
- cairo_point_t *d)
-{
- svg_path_info_t *info = closure;
- xmlBufferPtr path = info->path;
- char buffer[CAIRO_SVG_DTOSTR_BUFFER_LEN];
-
- xmlBufferCat (path, CC2XML ("C "));
- _cairo_dtostr (buffer, sizeof buffer, _cairo_fixed_to_double (b->x));
- xmlBufferCat (path, CC2XML (buffer));
- xmlBufferCat (path, CC2XML (" "));
- _cairo_dtostr (buffer, sizeof buffer, _cairo_fixed_to_double (b->y));
- xmlBufferCat (path, CC2XML (buffer));
- xmlBufferCat (path, CC2XML (" "));
- _cairo_dtostr (buffer, sizeof buffer, _cairo_fixed_to_double (c->x));
- xmlBufferCat (path, CC2XML (buffer));
- xmlBufferCat (path, CC2XML (" "));
- _cairo_dtostr (buffer, sizeof buffer, _cairo_fixed_to_double (c->y));
- xmlBufferCat (path, CC2XML (buffer));
- xmlBufferCat (path, CC2XML (" "));
- _cairo_dtostr (buffer, sizeof buffer, _cairo_fixed_to_double (d->x));
- xmlBufferCat (path, CC2XML (buffer));
- xmlBufferCat (path, CC2XML (" "));
- _cairo_dtostr (buffer, sizeof buffer, _cairo_fixed_to_double (d->y));
- xmlBufferCat (path, CC2XML (buffer));
- xmlBufferCat (path, CC2XML (" "));
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_svg_path_close_path (void *closure)
-{
- svg_path_info_t *info = closure;
-
- xmlBufferCat (info->path, CC2XML ("Z "));
-
- return CAIRO_STATUS_SUCCESS;
-}
-
static cairo_int_status_t
_cairo_svg_surface_fill (void *abstract_surface,
cairo_operator_t op,
@@ -1534,23 +1808,66 @@ _cairo_svg_surface_show_glyphs (void *
cairo_scaled_font_t *scaled_font)
{
cairo_svg_surface_t *surface = abstract_surface;
+ cairo_svg_document_t *document = surface->document;
cairo_path_fixed_t path;
cairo_status_t status;
+ cairo_svg_font_t *svg_font;
+ cairo_svg_glyph_t *svg_glyph;
+ xmlNodePtr glyph_node;
+ xmlNodePtr child;
+ xmlBufferPtr style;
+ char buffer[CAIRO_SVG_DTOSTR_BUFFER_LEN];
+ int i;
if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
return _analyze_operation (surface, op, pattern);
assert (_operation_supported (surface, op, pattern));
- /* FIXME: We don't really want to keep this as is. There's two possibilities:
- * - Use SVG fonts. But support for them seems very rare in SVG renderers.
- * - Or store glyph outlines in <symbol> or <g> elements.
- *
- * It would be also useful to add an early fallback in cairo_show_text and just
- * use <text> element.
- **/
+ if (num_glyphs <= 0)
+ return CAIRO_STATUS_SUCCESS;
+
+ /* FIXME it's probably possible to apply a pattern of a gradient to
+ * a group of symbols, but I don't know how yet. Gradients or patterns
+ * are translated by x and y properties of use element. */
+ if (pattern->type != CAIRO_PATTERN_TYPE_SOLID)
+ goto FALLBACK;
+
+ status = _cairo_svg_document_font_find (document, scaled_font, &svg_font);
+ if (status)
+ goto FALLBACK;
+
+ child = xmlNewChild (surface->xml_node, NULL, CC2XML ("g"), NULL);
+ style = xmlBufferCreate ();
+ emit_pattern (surface, pattern, style, 0);
+ xmlSetProp (child, CC2XML ("style"), xmlBufferContent (style));
+ xmlBufferFree (style);
+
+ for (i = 0; i < num_glyphs; i++) {
+ status = _cairo_svg_glyph_find (svg_font, scaled_font,
+ glyphs[i].index, &svg_glyph);
+ if (status) {
+ glyphs += i;
+ num_glyphs -= i;
+ goto FALLBACK;
+ }
+
+ glyph_node = xmlNewChild (child, NULL, CC2XML ("use"), NULL);
+ snprintf (buffer, sizeof buffer, "#glyph%d-%d",
+ svg_font->output_font,
+ svg_glyph->output_glyph);
+ xmlSetProp (glyph_node, CC2XML ("xlink:href"), C2XML (buffer));
+ _cairo_dtostr (buffer, sizeof buffer, glyphs[i].x);
+ xmlSetProp (glyph_node, CC2XML ("x"), C2XML (buffer));
+ _cairo_dtostr (buffer, sizeof buffer, glyphs[i].y);
+ xmlSetProp (glyph_node, CC2XML ("y"), C2XML (buffer));
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+
+FALLBACK:
- _cairo_path_fixed_init (&path);
+ _cairo_path_fixed_init (&path);
status = _cairo_scaled_font_glyph_path (scaled_font,(cairo_glyph_t *) glyphs, num_glyphs, &path);
@@ -1673,9 +1990,19 @@ _cairo_svg_document_create (cairo_output
char buffer[CAIRO_SVG_DTOSTR_BUFFER_LEN];
document = malloc (sizeof (cairo_svg_document_t));
- if (document == NULL)
+ if (document == NULL) {
+ _cairo_error (CAIRO_STATUS_NO_MEMORY);
return NULL;
+ }
+ document->fonts = _cairo_hash_table_create (_cairo_svg_font_equal);
+ if (!document->fonts) {
+ _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ free (document);
+ return NULL;
+ }
+ document->max_font = 0;
+
document->output_stream = output_stream;
document->refcount = 1;
document->owner = NULL;
@@ -1734,7 +2061,7 @@ _cairo_svg_document_create (cairo_output
_cairo_array_init (&document->meta_snapshots, sizeof (cairo_meta_snapshot_t));
document->svg_version = version;
-
+
return document;
}
@@ -1787,6 +2114,8 @@ _cairo_svg_document_finish (cairo_svg_do
if (document->finished)
return CAIRO_STATUS_SUCCESS;
+ _cairo_svg_document_emit_fonts (document);
+
xmlSetProp (document->xml_node_main, CC2XML ("version"),
CC2XML (_cairo_svg_internal_version_strings [document->svg_version]));
More information about the cairo-commit
mailing list