summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/cairo-pdf-surface-private.h13
-rw-r--r--src/cairo-pdf-surface.c134
2 files changed, 115 insertions, 32 deletions
diff --git a/src/cairo-pdf-surface-private.h b/src/cairo-pdf-surface-private.h
index d2fa43c4..e64b78ac 100644
--- a/src/cairo-pdf-surface-private.h
+++ b/src/cairo-pdf-surface-private.h
@@ -60,13 +60,19 @@ typedef struct _cairo_pdf_group_resources {
cairo_array_t fonts;
} cairo_pdf_group_resources_t;
+typedef struct _cairo_pdf_pattern_entry {
+ cairo_hash_entry_t base;
+ unsigned int id;
+ cairo_pdf_resource_t pattern_res;
+ cairo_pdf_resource_t gstate_res;
+} cairo_pdf_pattern_entry_t;
+
typedef struct _cairo_pdf_pattern {
double width;
double height;
cairo_rectangle_int_t extents;
cairo_pattern_t *pattern;
- cairo_pdf_resource_t pattern_res;
- cairo_pdf_resource_t gstate_res;
+ cairo_pdf_pattern_entry_t *hash_entry;
} cairo_pdf_pattern_t;
typedef enum _cairo_pdf_operation {
@@ -118,7 +124,8 @@ struct _cairo_pdf_surface {
cairo_array_t pages;
cairo_array_t rgb_linear_functions;
cairo_array_t alpha_linear_functions;
- cairo_array_t patterns;
+ cairo_array_t page_patterns;
+ cairo_hash_table_t *all_patterns;
cairo_array_t smask_groups;
cairo_array_t knockout_group;
diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c
index b1458d8e..29185233 100644
--- a/src/cairo-pdf-surface.c
+++ b/src/cairo-pdf-surface.c
@@ -194,6 +194,9 @@ _cairo_pdf_surface_write_page (cairo_pdf_surface_t *surface);
static cairo_status_t
_cairo_pdf_surface_emit_font_subsets (cairo_pdf_surface_t *surface);
+static cairo_bool_t
+_cairo_pdf_pattern_equal (const void *key_a, const void *key_b);
+
static const cairo_surface_backend_t cairo_pdf_surface_backend;
static const cairo_paginated_surface_backend_t cairo_pdf_surface_paginated_backend;
@@ -268,23 +271,29 @@ _cairo_pdf_surface_create_for_stream_internal (cairo_output_stream_t *output,
_cairo_array_init (&surface->rgb_linear_functions, sizeof (cairo_pdf_rgb_linear_function_t));
_cairo_array_init (&surface->alpha_linear_functions, sizeof (cairo_pdf_alpha_linear_function_t));
_cairo_array_init (&surface->fonts, sizeof (cairo_pdf_font_t));
- _cairo_array_init (&surface->patterns, sizeof (cairo_pdf_pattern_t));
_cairo_array_init (&surface->smask_groups, sizeof (cairo_pdf_smask_group_t *));
_cairo_array_init (&surface->knockout_group, sizeof (cairo_pdf_resource_t));
+ _cairo_array_init (&surface->page_patterns, sizeof (cairo_pdf_pattern_t));
+ surface->all_patterns = _cairo_hash_table_create (_cairo_pdf_pattern_equal);
+ if (unlikely (surface->all_patterns == NULL)) {
+ status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ goto BAIL0;
+ }
+
_cairo_pdf_group_resources_init (&surface->resources);
surface->font_subsets = _cairo_scaled_font_subsets_create_composite ();
if (! surface->font_subsets) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
- goto BAIL0;
+ goto BAIL1;
}
surface->next_available_resource.id = 1;
surface->pages_resource = _cairo_pdf_surface_new_object (surface);
if (surface->pages_resource.id == 0) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
- goto BAIL1;
+ goto BAIL2;
}
surface->pdf_version = CAIRO_PDF_VERSION_1_5;
@@ -324,8 +333,10 @@ _cairo_pdf_surface_create_for_stream_internal (cairo_output_stream_t *output,
return surface->paginated_surface;
}
-BAIL1:
+BAIL2:
_cairo_scaled_font_subsets_destroy (surface->font_subsets);
+BAIL1:
+ _cairo_hash_table_destroy (surface->all_patterns);
BAIL0:
_cairo_array_fini (&surface->objects);
free (surface);
@@ -573,12 +584,12 @@ _cairo_pdf_surface_clear (cairo_pdf_surface_t *surface)
cairo_pdf_pattern_t *pattern;
cairo_pdf_smask_group_t *group;
- size = _cairo_array_num_elements (&surface->patterns);
+ size = _cairo_array_num_elements (&surface->page_patterns);
for (i = 0; i < size; i++) {
- pattern = (cairo_pdf_pattern_t *) _cairo_array_index (&surface->patterns, i);
+ pattern = (cairo_pdf_pattern_t *) _cairo_array_index (&surface->page_patterns, i);
cairo_pattern_destroy (pattern->pattern);
}
- _cairo_array_truncate (&surface->patterns, 0);
+ _cairo_array_truncate (&surface->page_patterns, 0);
size = _cairo_array_num_elements (&surface->smask_groups);
for (i = 0; i < size; i++) {
@@ -861,6 +872,21 @@ _cairo_pdf_surface_add_smask_group (cairo_pdf_surface_t *surface,
return _cairo_array_append (&surface->smask_groups, &group);
}
+static cairo_bool_t
+_cairo_pdf_pattern_equal (const void *key_a, const void *key_b)
+{
+ const cairo_pdf_pattern_entry_t *a = key_a;
+ const cairo_pdf_pattern_entry_t *b = key_b;
+
+ return a->id == b->id;
+}
+
+static void
+_cairo_pdf_pattern_init_key (cairo_pdf_pattern_entry_t *key)
+{
+ key->base.hash = key->id;
+}
+
static cairo_status_t
_cairo_pdf_surface_add_pdf_pattern (cairo_pdf_surface_t *surface,
const cairo_pattern_t *pattern,
@@ -869,6 +895,8 @@ _cairo_pdf_surface_add_pdf_pattern (cairo_pdf_surface_t *surface,
cairo_pdf_resource_t *gstate_res)
{
cairo_pdf_pattern_t pdf_pattern;
+ cairo_pdf_pattern_entry_t pdf_pattern_key;
+ cairo_pdf_pattern_entry_t *pdf_pattern_entry;
cairo_status_t status;
/* Solid colors are emitted into the content stream */
@@ -878,6 +906,7 @@ _cairo_pdf_surface_add_pdf_pattern (cairo_pdf_surface_t *surface,
return CAIRO_STATUS_SUCCESS;
}
+ pdf_pattern_key.id = 0;
if (pattern->type == CAIRO_PATTERN_TYPE_LINEAR ||
pattern->type == CAIRO_PATTERN_TYPE_RADIAL)
{
@@ -897,24 +926,50 @@ _cairo_pdf_surface_add_pdf_pattern (cairo_pdf_surface_t *surface,
}
}
+ if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
+ cairo_surface_pattern_t *surface = (cairo_surface_pattern_t *) pattern;
+
+ pdf_pattern_key.id = surface->surface->unique_id;
+ }
+
+ _cairo_pdf_pattern_init_key (&pdf_pattern_key);
+ if (pdf_pattern_key.base.hash != 0 &&
+ (pdf_pattern_entry = _cairo_hash_table_lookup (surface->all_patterns,
+ &pdf_pattern_key.base)))
+ {
+ *pattern_res = pdf_pattern_entry->pattern_res;
+ *gstate_res = pdf_pattern_entry->gstate_res;
+
+ return CAIRO_STATUS_SUCCESS;
+ }
+
+ pdf_pattern_entry = malloc (sizeof (cairo_pdf_pattern_entry_t));
+ if (pdf_pattern_entry == NULL)
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+ pdf_pattern_entry->id = pdf_pattern_key.id;
+ _cairo_pdf_pattern_init_key (pdf_pattern_entry);
+
+ pdf_pattern.hash_entry = pdf_pattern_entry;
+
status = _cairo_pattern_create_copy (&pdf_pattern.pattern, pattern);
if (unlikely (status))
return status;
- pdf_pattern.pattern_res = _cairo_pdf_surface_new_object (surface);
- if (pdf_pattern.pattern_res.id == 0) {
+ pdf_pattern_entry->pattern_res = _cairo_pdf_surface_new_object (surface);
+ if (pdf_pattern_entry->pattern_res.id == 0) {
cairo_pattern_destroy (pdf_pattern.pattern);
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
- pdf_pattern.gstate_res.id = 0;
+ pdf_pattern_entry->gstate_res.id = 0;
/* gradient patterns require an smask object to implement transparency */
if (pattern->type == CAIRO_PATTERN_TYPE_LINEAR ||
pattern->type == CAIRO_PATTERN_TYPE_RADIAL) {
if (_cairo_pattern_is_opaque (pattern) == FALSE) {
- pdf_pattern.gstate_res = _cairo_pdf_surface_new_object (surface);
- if (pdf_pattern.gstate_res.id == 0) {
+ pdf_pattern_entry->gstate_res = _cairo_pdf_surface_new_object (surface);
+ if (pdf_pattern_entry->gstate_res.id == 0) {
cairo_pattern_destroy (pdf_pattern.pattern);
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
@@ -932,15 +987,22 @@ _cairo_pdf_surface_add_pdf_pattern (cairo_pdf_surface_t *surface,
pdf_pattern.extents.height = surface->height;
}
- *pattern_res = pdf_pattern.pattern_res;
- *gstate_res = pdf_pattern.gstate_res;
+ *pattern_res = pdf_pattern_entry->pattern_res;
+ *gstate_res = pdf_pattern_entry->gstate_res;
- status = _cairo_array_append (&surface->patterns, &pdf_pattern);
+ status = _cairo_array_append (&surface->page_patterns, &pdf_pattern);
if (unlikely (status)) {
cairo_pattern_destroy (pdf_pattern.pattern);
return status;
}
+ if (pdf_pattern_entry->base.hash != 0) {
+ status = _cairo_hash_table_insert (surface->all_patterns,
+ &pdf_pattern_entry->base);
+ if (unlikely (status))
+ return status;
+ }
+
return CAIRO_STATUS_SUCCESS;
}
@@ -1287,6 +1349,16 @@ _cairo_pdf_surface_create_similar (void *abstract_surface,
return _cairo_meta_surface_create (content, width, height);
}
+static void
+_cairo_pdf_pattern_entry_pluck (void *entry, void *closure)
+{
+ cairo_pdf_pattern_entry_t *pattern_entry = entry;
+ cairo_hash_table_t *patterns = closure;
+
+ _cairo_hash_table_remove (patterns, &pattern_entry->base);
+ free (pattern_entry);
+}
+
static cairo_status_t
_cairo_pdf_surface_finish (void *abstract_surface)
{
@@ -1366,7 +1438,11 @@ _cairo_pdf_surface_finish (void *abstract_surface)
_cairo_array_fini (&surface->pages);
_cairo_array_fini (&surface->rgb_linear_functions);
_cairo_array_fini (&surface->alpha_linear_functions);
- _cairo_array_fini (&surface->patterns);
+ _cairo_array_fini (&surface->page_patterns);
+ _cairo_hash_table_foreach (surface->all_patterns,
+ _cairo_pdf_pattern_entry_pluck,
+ surface->all_patterns);
+ _cairo_hash_table_destroy (surface->all_patterns);
_cairo_array_fini (&surface->smask_groups);
_cairo_array_fini (&surface->fonts);
_cairo_array_fini (&surface->knockout_group);
@@ -2062,9 +2138,9 @@ _cairo_pdf_surface_emit_surface_pattern (cairo_pdf_surface_t *surface,
cairo_matrix_translate (&pdf_p2d, 0.0, pattern_height);
cairo_matrix_scale (&pdf_p2d, 1.0, -1.0);
- _cairo_pdf_surface_update_object (surface, pdf_pattern->pattern_res);
+ _cairo_pdf_surface_update_object (surface, pdf_pattern->hash_entry->pattern_res);
status = _cairo_pdf_surface_open_stream (surface,
- &pdf_pattern->pattern_res,
+ &pdf_pattern->hash_entry->pattern_res,
FALSE,
" /PatternType 1\n"
" /BBox [0 0 %d %d]\n"
@@ -2679,7 +2755,7 @@ _cairo_pdf_surface_emit_linear_pattern (cairo_pdf_surface_t *surface,
}
}
- _cairo_pdf_surface_update_object (surface, pdf_pattern->pattern_res);
+ _cairo_pdf_surface_update_object (surface, pdf_pattern->hash_entry->pattern_res);
_cairo_output_stream_printf (surface->output,
"%d 0 obj\n"
"<< /Type /Pattern\n"
@@ -2691,7 +2767,7 @@ _cairo_pdf_surface_emit_linear_pattern (cairo_pdf_surface_t *surface,
" /Coords [ %f %f %f %f ]\n"
" /Domain [ %f %f ]\n"
" /Function %d 0 R\n",
- pdf_pattern->pattern_res.id,
+ pdf_pattern->hash_entry->pattern_res.id,
pat_to_pdf.xx, pat_to_pdf.yx,
pat_to_pdf.xy, pat_to_pdf.yy,
pat_to_pdf.x0, pat_to_pdf.y0,
@@ -2715,7 +2791,7 @@ _cairo_pdf_surface_emit_linear_pattern (cairo_pdf_surface_t *surface,
if (alpha_function.id != 0) {
cairo_pdf_resource_t mask_resource;
- assert (pdf_pattern->gstate_res.id != 0);
+ assert (pdf_pattern->hash_entry->gstate_res.id != 0);
/* Create pattern for SMask. */
mask_resource = _cairo_pdf_surface_new_object (surface);
@@ -2758,7 +2834,7 @@ _cairo_pdf_surface_emit_linear_pattern (cairo_pdf_surface_t *surface,
return status;
status = cairo_pdf_surface_emit_transparency_group (surface,
- pdf_pattern->gstate_res,
+ pdf_pattern->hash_entry->gstate_res,
mask_resource);
if (unlikely (status))
return status;
@@ -2802,7 +2878,7 @@ _cairo_pdf_surface_emit_radial_pattern (cairo_pdf_surface_t *surface,
y2 = _cairo_fixed_to_double (pattern->c2.y);
r2 = _cairo_fixed_to_double (pattern->r2);
- _cairo_pdf_surface_update_object (surface, pdf_pattern->pattern_res);
+ _cairo_pdf_surface_update_object (surface, pdf_pattern->hash_entry->pattern_res);
_cairo_output_stream_printf (surface->output,
"%d 0 obj\n"
@@ -2814,7 +2890,7 @@ _cairo_pdf_surface_emit_radial_pattern (cairo_pdf_surface_t *surface,
" /ColorSpace /DeviceRGB\n"
" /Coords [ %f %f %f %f %f %f ]\n"
" /Function %d 0 R\n",
- pdf_pattern->pattern_res.id,
+ pdf_pattern->hash_entry->pattern_res.id,
pat_to_pdf.xx, pat_to_pdf.yx,
pat_to_pdf.xy, pat_to_pdf.yy,
pat_to_pdf.x0, pat_to_pdf.y0,
@@ -2837,7 +2913,7 @@ _cairo_pdf_surface_emit_radial_pattern (cairo_pdf_surface_t *surface,
if (alpha_function.id != 0) {
cairo_pdf_resource_t mask_resource;
- assert (pdf_pattern->gstate_res.id != 0);
+ assert (pdf_pattern->hash_entry->gstate_res.id != 0);
/* Create pattern for SMask. */
mask_resource = _cairo_pdf_surface_new_object (surface);
@@ -2875,7 +2951,7 @@ _cairo_pdf_surface_emit_radial_pattern (cairo_pdf_surface_t *surface,
"endobj\n");
status = cairo_pdf_surface_emit_transparency_group (surface,
- pdf_pattern->gstate_res,
+ pdf_pattern->hash_entry->gstate_res,
mask_resource);
if (unlikely (status))
return status;
@@ -4522,7 +4598,7 @@ _cairo_pdf_surface_write_patterns_and_smask_groups (cairo_pdf_surface_t *surface
*/
pattern_index = 0;
group_index = 0;
- while ((pattern_index < _cairo_array_num_elements (&surface->patterns)) ||
+ while ((pattern_index < _cairo_array_num_elements (&surface->page_patterns)) ||
(group_index < _cairo_array_num_elements (&surface->smask_groups)))
{
for (; group_index < _cairo_array_num_elements (&surface->smask_groups); group_index++) {
@@ -4532,8 +4608,8 @@ _cairo_pdf_surface_write_patterns_and_smask_groups (cairo_pdf_surface_t *surface
return status;
}
- for (; pattern_index < _cairo_array_num_elements (&surface->patterns); pattern_index++) {
- _cairo_array_copy_element (&surface->patterns, pattern_index, &pattern);
+ for (; pattern_index < _cairo_array_num_elements (&surface->page_patterns); pattern_index++) {
+ _cairo_array_copy_element (&surface->page_patterns, pattern_index, &pattern);
status = _cairo_pdf_surface_emit_pattern (surface, &pattern);
if (unlikely (status))
return status;