mirror of
https://gitlab.freedesktop.org/cairo/cairo.git
synced 2026-05-08 21:58:04 +02:00
Start implementing correct paints in transformed recording patterns
This commit is contained in:
parent
c2ea2848fd
commit
c5b24a3e12
4 changed files with 313 additions and 165 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
"<g id=\"paint-%d\">\n",
|
||||
paint->source_id);
|
||||
_cairo_memory_stream_copy (paint->xml_node, output);
|
||||
_cairo_output_stream_printf (output, "</g>\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,
|
||||
"<image id=\"image-%d\" x=\"%d\" y=\"%d\" width=\"%d\" height=\"%d\" xlink:href=\"",
|
||||
"<image id=\"source-%d\" x=\"%d\" y=\"%d\" width=\"%d\" height=\"%d\" xlink:href=\"",
|
||||
source_id,
|
||||
extents.x, extents.y,
|
||||
extents.width, extents.height);
|
||||
|
|
@ -1610,15 +1669,16 @@ _cairo_svg_surface_emit_composite_surface_pattern (cairo_output_stream_t *output
|
|||
/* cairo_pattern_set_matrix ensures the matrix is invertible */
|
||||
assert (status == CAIRO_STATUS_SUCCESS);
|
||||
|
||||
unsigned int source_id;
|
||||
cairo_bool_t is_new;
|
||||
cairo_svg_source_surface_t *source_surface;
|
||||
status = _cairo_svg_surface_add_source_surface (surface,
|
||||
pattern->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,
|
||||
"<use xlink:href=\"#image-%d\"",
|
||||
"<use xlink:href=\"#source-%d\"",
|
||||
source_id);
|
||||
if (pattern->surface->content == CAIRO_CONTENT_ALPHA) {
|
||||
_cairo_output_stream_printf (output,
|
||||
|
|
@ -1679,29 +1739,28 @@ _cairo_svg_surface_emit_composite_surface_pattern (cairo_output_stream_t *output
|
|||
}
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_svg_surface_emit_recording_surface (cairo_svg_document_t *document,
|
||||
_cairo_svg_surface_emit_recording_surface (cairo_svg_document_t *document,
|
||||
cairo_recording_surface_t *source,
|
||||
unsigned int source_id)
|
||||
unsigned int source_id,
|
||||
cairo_bool_t *paint_used)
|
||||
{
|
||||
cairo_status_t status;
|
||||
cairo_surface_t *paginated_surface;
|
||||
cairo_svg_surface_t *svg_surface;
|
||||
cairo_array_t *page_set;
|
||||
cairo_rectangle_int_t extents;
|
||||
cairo_bool_t bounded;
|
||||
cairo_output_stream_t *contents;
|
||||
|
||||
bounded = _cairo_surface_get_extents (&source->base, &extents);
|
||||
paginated_surface = _cairo_svg_surface_create_for_document (document,
|
||||
source->base.content,
|
||||
0,
|
||||
0,
|
||||
FALSE);
|
||||
if (unlikely (paginated_surface->status))
|
||||
cairo_surface_t *paginated_surface = _cairo_svg_surface_create_for_document (document,
|
||||
source->base.content,
|
||||
0,
|
||||
0,
|
||||
FALSE);
|
||||
cairo_svg_surface_t *svg_surface = (cairo_svg_surface_t *) _cairo_paginated_surface_get_target (paginated_surface);
|
||||
if (unlikely (paginated_surface->status)) {
|
||||
return paginated_surface->status;
|
||||
}
|
||||
|
||||
svg_surface->source_id = source_id;
|
||||
|
||||
cairo_rectangle_int_t extents;
|
||||
cairo_bool_t bounded = _cairo_surface_get_extents (&source->base, &extents);
|
||||
|
||||
svg_surface = (cairo_svg_surface_t *)
|
||||
_cairo_paginated_surface_get_target (paginated_surface);
|
||||
cairo_surface_set_fallback_resolution (paginated_surface,
|
||||
document->owner->x_fallback_resolution,
|
||||
document->owner->y_fallback_resolution);
|
||||
|
|
@ -1719,12 +1778,15 @@ _cairo_svg_surface_emit_recording_surface (cairo_svg_document_t *document,
|
|||
return status;
|
||||
}
|
||||
|
||||
unsigned int clip_id;
|
||||
if (bounded) {
|
||||
clip_id = document->clip_id++;
|
||||
|
||||
_cairo_output_stream_printf (document->xml_node_defs,
|
||||
"<clipPath id=\"clip-%d\">\n"
|
||||
"<rect x=\"%d\" y=\"%d\" width=\"%d\" height=\"%d\"/>\n"
|
||||
"</clipPath>\n",
|
||||
svg_surface->document->clip_id,
|
||||
clip_id,
|
||||
extents.x,
|
||||
extents.y,
|
||||
extents.width,
|
||||
|
|
@ -1732,13 +1794,13 @@ _cairo_svg_surface_emit_recording_surface (cairo_svg_document_t *document,
|
|||
}
|
||||
|
||||
_cairo_output_stream_printf (document->xml_node_defs,
|
||||
"<g id=\"surface-%d\"",
|
||||
"<g id=\"source-%d\"",
|
||||
source_id);
|
||||
|
||||
if (bounded) {
|
||||
_cairo_output_stream_printf (document->xml_node_defs,
|
||||
" clip-path=\"url(#clip-%d)\"",
|
||||
svg_surface->document->clip_id);
|
||||
clip_id);
|
||||
}
|
||||
|
||||
if (source->base.content == CAIRO_CONTENT_ALPHA) {
|
||||
|
|
@ -1749,14 +1811,7 @@ _cairo_svg_surface_emit_recording_surface (cairo_svg_document_t *document,
|
|||
|
||||
_cairo_output_stream_printf (document->xml_node_defs, ">\n");
|
||||
|
||||
if (bounded) {
|
||||
svg_surface->document->clip_id++;
|
||||
}
|
||||
|
||||
contents = svg_surface->xml_node;
|
||||
page_set = &svg_surface->page_set;
|
||||
|
||||
if (_cairo_memory_stream_length (contents) > 0) {
|
||||
if (_cairo_memory_stream_length (svg_surface->xml_node) > 0) {
|
||||
cairo_svg_page_t *page = _cairo_svg_surface_store_page (svg_surface);
|
||||
if (unlikely (page == NULL)) {
|
||||
cairo_surface_destroy (paginated_surface);
|
||||
|
|
@ -1764,15 +1819,15 @@ _cairo_svg_surface_emit_recording_surface (cairo_svg_document_t *document,
|
|||
}
|
||||
}
|
||||
|
||||
if (page_set->num_elements > 0) {
|
||||
cairo_svg_page_t *page;
|
||||
|
||||
page = _cairo_array_index (page_set, page_set->num_elements - 1);
|
||||
if (svg_surface->page_set.num_elements > 0) {
|
||||
cairo_svg_page_t *page = _cairo_array_index (&svg_surface->page_set, svg_surface->page_set.num_elements - 1);
|
||||
_cairo_memory_stream_copy (page->xml_node, document->xml_node_defs);
|
||||
}
|
||||
|
||||
_cairo_output_stream_printf (document->xml_node_defs, "</g>\n");
|
||||
|
||||
*paint_used = svg_surface->paint_used;
|
||||
|
||||
status = cairo_surface_status (paginated_surface);
|
||||
cairo_surface_destroy (paginated_surface);
|
||||
|
||||
|
|
@ -1804,36 +1859,80 @@ _cairo_svg_surface_svg_clip_or_svg_mask_should_be_used (const cairo_pattern_t *p
|
|||
}
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_svg_surface_emit_composite_recording_pattern (cairo_output_stream_t *output,
|
||||
cairo_svg_surface_t *surface,
|
||||
cairo_surface_pattern_t *pattern,
|
||||
unsigned int pattern_id,
|
||||
const cairo_matrix_t *parent_matrix)
|
||||
_cairo_svg_surface_emit_composite_recording_pattern (cairo_output_stream_t *output,
|
||||
cairo_svg_surface_t *surface,
|
||||
cairo_surface_pattern_t *pattern,
|
||||
unsigned int pattern_id,
|
||||
const cairo_matrix_t *parent_matrix)
|
||||
{
|
||||
cairo_svg_document_t *document = surface->document;
|
||||
cairo_recording_surface_t *recording_surface;
|
||||
cairo_matrix_t p2u;
|
||||
cairo_status_t status;
|
||||
unsigned int source_id;
|
||||
cairo_bool_t is_new;
|
||||
cairo_svg_document_t *document = surface->document;
|
||||
|
||||
p2u = pattern->base.matrix;
|
||||
cairo_matrix_t p2u = pattern->base.matrix;
|
||||
status = cairo_matrix_invert (&p2u);
|
||||
/* cairo_pattern_set_matrix ensures the matrix is invertible */
|
||||
assert (status == CAIRO_STATUS_SUCCESS);
|
||||
|
||||
cairo_bool_t is_new;
|
||||
cairo_svg_source_surface_t *source_surface;
|
||||
status = _cairo_svg_surface_add_source_surface (surface,
|
||||
pattern->surface,
|
||||
&source_id,
|
||||
&is_new);
|
||||
if (unlikely (status))
|
||||
&is_new,
|
||||
&source_surface);
|
||||
if (unlikely (status)) {
|
||||
return status;
|
||||
}
|
||||
unsigned int source_id = source_surface->id;
|
||||
|
||||
recording_surface = _cairo_svg_surface_to_recording_surface (pattern);
|
||||
cairo_recording_surface_t *recording_surface = _cairo_svg_surface_to_recording_surface (pattern);
|
||||
if (is_new) {
|
||||
status = _cairo_svg_surface_emit_recording_surface (document, recording_surface, source_id);
|
||||
if (unlikely (status))
|
||||
status = _cairo_svg_surface_emit_recording_surface (document,
|
||||
recording_surface,
|
||||
source_id,
|
||||
&source_surface->paint_used);
|
||||
if (unlikely (status)) {
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_new && source_surface->paint_used) {
|
||||
cairo_svg_paint_t *paint_entry = malloc (sizeof (cairo_svg_paint_t));
|
||||
if (paint_entry == NULL) {
|
||||
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
||||
}
|
||||
paint_entry->source_id = source_id;
|
||||
paint_entry->xml_node = _cairo_memory_stream_create();
|
||||
_cairo_svg_paint_init_key (paint_entry);
|
||||
status = _cairo_hash_table_insert (document->paints, &paint_entry->base);
|
||||
if (unlikely (status)) {
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
if (source_surface->paint_used) {
|
||||
cairo_svg_paint_t paint_key;
|
||||
paint_key.source_id = source_id;
|
||||
_cairo_svg_paint_init_key (&paint_key);
|
||||
|
||||
cairo_svg_paint_t *found_paint_entry = _cairo_hash_table_lookup (document->paints,
|
||||
&paint_key.base);
|
||||
assert (found_paint_entry);
|
||||
|
||||
_cairo_output_stream_printf (found_paint_entry->xml_node,
|
||||
"<use xlink:href=\"#paint-%d\"",
|
||||
surface->source_id);
|
||||
cairo_matrix_t matrix = pattern->base.matrix;
|
||||
if (parent_matrix != NULL) {
|
||||
cairo_matrix_t parent_matrix_inverse = *parent_matrix;
|
||||
status = cairo_matrix_invert (&parent_matrix_inverse);
|
||||
/* cairo_pattern_set_matrix ensures the matrix is invertible */
|
||||
assert (status == CAIRO_STATUS_SUCCESS);
|
||||
cairo_matrix_multiply (&matrix, &parent_matrix_inverse, &matrix);
|
||||
}
|
||||
_cairo_svg_surface_emit_transform (found_paint_entry->xml_node, "transform", &matrix, NULL);
|
||||
_cairo_output_stream_printf (found_paint_entry->xml_node, "/>\n");
|
||||
|
||||
surface->paint_used = TRUE;
|
||||
}
|
||||
|
||||
if (pattern_id != invalid_pattern_id) {
|
||||
|
|
@ -1857,7 +1956,7 @@ _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=\"#source-%d\"",
|
||||
source_id);
|
||||
|
||||
if (pattern_id == invalid_pattern_id) {
|
||||
|
|
@ -1866,8 +1965,9 @@ _cairo_svg_surface_emit_composite_recording_pattern (cairo_output_stream_t *outp
|
|||
|
||||
_cairo_output_stream_printf (output, "/>\n");
|
||||
|
||||
if (pattern_id != invalid_pattern_id)
|
||||
if (pattern_id != invalid_pattern_id) {
|
||||
_cairo_output_stream_printf (output, "</pattern>\n");
|
||||
}
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
|
@ -2458,9 +2558,10 @@ _cairo_svg_surface_emit_paint (cairo_output_stream_t *output,
|
|||
mask_source ? &mask_source->matrix : NULL);
|
||||
}
|
||||
|
||||
surface->paint_used = TRUE;
|
||||
_cairo_output_stream_printf (output,
|
||||
"<rect x=\"-50%%\" y=\"-50%%\" "
|
||||
"width=\"200%%\" height=\"200%%\"");
|
||||
"<use xlink:href=\"#paint-%d\"",
|
||||
surface->source_id);
|
||||
status = _cairo_svg_surface_emit_pattern (surface, source, output, FALSE, NULL);
|
||||
if (unlikely (status)) {
|
||||
return status;
|
||||
|
|
@ -3505,31 +3606,29 @@ _cairo_svg_document_create (cairo_output_stream_t *output_stream,
|
|||
cairo_svg_document_t **document_out)
|
||||
{
|
||||
cairo_svg_document_t *document;
|
||||
cairo_status_t status;
|
||||
|
||||
if (output_stream->status) {
|
||||
return output_stream->status;
|
||||
}
|
||||
|
||||
document = _cairo_malloc (sizeof (cairo_svg_document_t));
|
||||
if (unlikely (document == NULL))
|
||||
if (unlikely (document == NULL)) {
|
||||
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
document->output_stream = output_stream;
|
||||
document->refcount = 1;
|
||||
document->owner = NULL;
|
||||
document->finished = FALSE;
|
||||
|
||||
document->width = width;
|
||||
document->height = height;
|
||||
document->unit = CAIRO_SVG_UNIT_USER;
|
||||
|
||||
document->xml_node_defs = _cairo_memory_stream_create ();
|
||||
document->xml_node_glyphs = _cairo_memory_stream_create ();
|
||||
document->xml_node_filters = _cairo_memory_stream_create ();
|
||||
|
||||
document->linear_pattern_id = 0;
|
||||
document->radial_pattern_id = 0;
|
||||
document->pattern_id = 0;
|
||||
|
|
@ -3542,18 +3641,30 @@ _cairo_svg_document_create (cairo_output_stream_t *output_stream,
|
|||
document->filters_emitted[filter] = FALSE;
|
||||
}
|
||||
|
||||
document->xml_node_defs = _cairo_memory_stream_create ();
|
||||
document->xml_node_glyphs = _cairo_memory_stream_create ();
|
||||
document->xml_node_filters = _cairo_memory_stream_create ();
|
||||
|
||||
document->svg_version = version;
|
||||
|
||||
/* 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)) {
|
||||
(void) _cairo_output_stream_destroy(document->xml_node_defs);
|
||||
(void) _cairo_output_stream_destroy(document->xml_node_glyphs);
|
||||
(void) _cairo_output_stream_destroy(document->xml_node_filters);
|
||||
free (document);
|
||||
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
||||
}
|
||||
|
||||
document->paints = _cairo_hash_table_create (_cairo_svg_paint_equal);
|
||||
if (unlikely (document->paints == NULL)) {
|
||||
(void) _cairo_output_stream_destroy(document->xml_node_defs);
|
||||
(void) _cairo_output_stream_destroy(document->xml_node_glyphs);
|
||||
(void) _cairo_output_stream_destroy(document->xml_node_filters);
|
||||
_cairo_scaled_font_subsets_destroy (document->font_subsets);
|
||||
free (document);
|
||||
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
||||
}
|
||||
|
||||
*document_out = document;
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
|
||||
cleanup_document:
|
||||
free (document);
|
||||
return status;
|
||||
}
|
||||
|
||||
static cairo_svg_document_t *
|
||||
|
|
@ -3588,7 +3699,7 @@ _cairo_svg_document_finish (cairo_svg_document_t *document)
|
|||
}
|
||||
document->finished = TRUE;
|
||||
|
||||
cairo_status_t status;
|
||||
cairo_status_t status, final_status = CAIRO_STATUS_SUCCESS;
|
||||
|
||||
cairo_output_stream_t *output = document->output_stream;
|
||||
|
||||
|
|
@ -3625,13 +3736,27 @@ _cairo_svg_document_finish (cairo_svg_document_t *document)
|
|||
document->width, document->height);
|
||||
|
||||
status = _cairo_svg_document_emit_font_subsets (document);
|
||||
if (unlikely (status)) {
|
||||
return status;
|
||||
if (final_status == CAIRO_STATUS_SUCCESS) {
|
||||
final_status = status;
|
||||
}
|
||||
|
||||
cairo_svg_surface_t *surface = NULL;
|
||||
if (document->owner != NULL) {
|
||||
surface = (cairo_svg_surface_t *) _cairo_paginated_surface_get_target (document->owner);
|
||||
|
||||
if (surface->xml_node != NULL && _cairo_memory_stream_length (surface->xml_node) > 0) {
|
||||
cairo_svg_page_t *page = _cairo_svg_surface_store_page (surface);
|
||||
if (final_status == CAIRO_STATUS_SUCCESS && page == NULL) {
|
||||
final_status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_cairo_memory_stream_length (document->xml_node_filters) > 0 ||
|
||||
_cairo_memory_stream_length (document->xml_node_glyphs) > 0 ||
|
||||
_cairo_memory_stream_length (document->xml_node_defs) > 0) {
|
||||
_cairo_memory_stream_length (document->xml_node_defs) > 0 ||
|
||||
_cairo_hash_table_size (document->paints) != 0 ||
|
||||
(surface != NULL && surface->paint_used)) {
|
||||
_cairo_output_stream_printf (output, "<defs>\n");
|
||||
_cairo_memory_stream_copy (document->xml_node_filters, output);
|
||||
if (_cairo_memory_stream_length (document->xml_node_glyphs) > 0) {
|
||||
|
|
@ -3640,19 +3765,17 @@ _cairo_svg_document_finish (cairo_svg_document_t *document)
|
|||
_cairo_output_stream_printf (output, "</g>\n");
|
||||
}
|
||||
_cairo_memory_stream_copy (document->xml_node_defs, output);
|
||||
_cairo_hash_table_foreach (document->paints, _cairo_svg_paint_emit, output);
|
||||
if (surface != NULL && surface->paint_used) {
|
||||
_cairo_output_stream_printf (output,
|
||||
"<rect id=\"paint-%d\" x=\"0\" y=\"0\" width=\"%f\" height=\"%f\"/>\n",
|
||||
surface->source_id,
|
||||
document->width, document->height);
|
||||
}
|
||||
_cairo_output_stream_printf (output, "</defs>\n");
|
||||
}
|
||||
|
||||
if (document->owner != NULL) {
|
||||
cairo_svg_surface_t *surface = (cairo_svg_surface_t *) _cairo_paginated_surface_get_target (document->owner);
|
||||
|
||||
if (surface->xml_node != NULL && _cairo_memory_stream_length (surface->xml_node) > 0) {
|
||||
cairo_svg_page_t *page = _cairo_svg_surface_store_page (surface);
|
||||
if (unlikely (page == NULL)) {
|
||||
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
||||
}
|
||||
}
|
||||
|
||||
if (surface->page_set.num_elements == 1) {
|
||||
cairo_svg_page_t *page = _cairo_array_index (&surface->page_set, 0);
|
||||
_cairo_memory_stream_copy (page->xml_node, output);
|
||||
|
|
@ -3670,24 +3793,27 @@ _cairo_svg_document_finish (cairo_svg_document_t *document)
|
|||
|
||||
_cairo_output_stream_printf (output, "</svg>\n");
|
||||
|
||||
status = _cairo_output_stream_destroy (document->xml_node_filters);
|
||||
if (unlikely (status)) {
|
||||
return status;
|
||||
status = _cairo_output_stream_destroy (document->xml_node_defs);
|
||||
if (final_status == CAIRO_STATUS_SUCCESS) {
|
||||
final_status = status;
|
||||
}
|
||||
|
||||
status = _cairo_output_stream_destroy (document->xml_node_glyphs);
|
||||
if (unlikely (status)) {
|
||||
return status;
|
||||
if (final_status == CAIRO_STATUS_SUCCESS) {
|
||||
final_status = status;
|
||||
}
|
||||
|
||||
status = _cairo_output_stream_destroy (document->xml_node_defs);
|
||||
if (unlikely (status)) {
|
||||
return status;
|
||||
status = _cairo_output_stream_destroy (document->xml_node_filters);
|
||||
if (final_status == CAIRO_STATUS_SUCCESS) {
|
||||
final_status = status;
|
||||
}
|
||||
|
||||
_cairo_hash_table_foreach (document->paints, _cairo_svg_paint_pluck, document->paints);
|
||||
_cairo_hash_table_destroy (document->paints);
|
||||
|
||||
status = _cairo_output_stream_destroy (output);
|
||||
if (unlikely (status)) {
|
||||
return status;
|
||||
if (final_status == CAIRO_STATUS_SUCCESS) {
|
||||
final_status = status;
|
||||
}
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue