diff --git a/src/cairo-hash-private.h b/src/cairo-hash-private.h
index 30e51ffe6..b30126b20 100644
--- a/src/cairo-hash-private.h
+++ b/src/cairo-hash-private.h
@@ -84,4 +84,7 @@ _cairo_hash_table_foreach (cairo_hash_table_t *hash_table,
cairo_hash_callback_func_t hash_callback,
void *closure);
+cairo_private unsigned long
+_cairo_hash_table_size (cairo_hash_table_t *hash_table);
+
#endif
diff --git a/src/cairo-hash.c b/src/cairo-hash.c
index 151842eb6..564ca0732 100644
--- a/src/cairo-hash.c
+++ b/src/cairo-hash.c
@@ -576,3 +576,24 @@ _cairo_hash_table_foreach (cairo_hash_table_t *hash_table,
_cairo_hash_table_manage (hash_table);
}
}
+
+/**
+ * _cairo_hash_table_size:
+ * @hash_table: a hash table
+ *
+ * Gets the size of the hash table.
+ *
+ * Return value: the size of the hash table.
+ **/
+unsigned long
+_cairo_hash_table_size (cairo_hash_table_t *hash_table)
+{
+ unsigned long size = 0;
+ for (unsigned long i = 0; i < *hash_table->table_size; i++) {
+ cairo_hash_entry_t *entry = hash_table->entries[i];
+ if (ENTRY_IS_LIVE(entry)) {
+ size++;
+ }
+ }
+ return size;
+}
diff --git a/src/cairo-svg-surface-private.h b/src/cairo-svg-surface-private.h
index f64814fe2..b30948f33 100644
--- a/src/cairo-svg-surface-private.h
+++ b/src/cairo-svg-surface-private.h
@@ -48,16 +48,11 @@
typedef struct cairo_svg_document cairo_svg_document_t;
-typedef struct _cairo_svg_source_surface {
- cairo_hash_entry_t base;
- unsigned int id;
- unsigned char *unique_id;
- unsigned long unique_id_length;
-} cairo_svg_source_surface_t;
-
typedef struct cairo_svg_surface {
cairo_surface_t base;
+ unsigned int source_id;
+
cairo_content_t content;
double width;
@@ -67,13 +62,16 @@ typedef struct cairo_svg_surface {
cairo_svg_document_t *document;
cairo_output_stream_t *xml_node;
- cairo_array_t page_set;
- cairo_hash_table_t *source_surfaces;
+ cairo_array_t page_set;
+
+ cairo_hash_table_t *source_surfaces;
cairo_surface_clipper_t clipper;
cairo_output_stream_t *current_clipper_output_stream;
unsigned int clip_level;
+ cairo_bool_t paint_used;
+
cairo_paginated_mode_t paginated_mode;
cairo_bool_t force_fallbacks;
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,
+ "\n",
+ paint->source_id);
+ _cairo_memory_stream_copy (paint->xml_node, output);
+ _cairo_output_stream_printf (output, "\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,
- "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,
- "