summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdrian Johnson <ajohnson@redneon.com>2017-08-29 21:40:52 +0930
committerAdrian Johnson <ajohnson@redneon.com>2017-08-29 21:43:07 +0930
commit609261bcbc3bf3d4911749353fbcc01ced70534f (patch)
tree5137ce44ac4383f16096636cc5667cb5572fa8f7
parent12b875aef374636d1693a631524dd3b622277415 (diff)
pdf: use explicit dest instead of named dest when 'internal' attribute is set
-rw-r--r--src/cairo-pdf-interchange.c181
-rw-r--r--src/cairo-pdf-surface-private.h1
-rw-r--r--test/pdf-tagged-text.c2
3 files changed, 126 insertions, 58 deletions
diff --git a/src/cairo-pdf-interchange.c b/src/cairo-pdf-interchange.c
index 460f483e6..c6ba056aa 100644
--- a/src/cairo-pdf-interchange.c
+++ b/src/cairo-pdf-interchange.c
@@ -229,47 +229,137 @@ cairo_pdf_interchange_write_node_object (cairo_pdf_surface_t *surface
return _cairo_output_stream_get_status (surface->output);
}
+static void
+init_named_dest_key (cairo_pdf_named_dest_t *dest)
+{
+ dest->base.hash = _cairo_hash_bytes (_CAIRO_HASH_INIT_VALUE,
+ dest->attrs.name,
+ strlen (dest->attrs.name));
+}
+
+static cairo_bool_t
+_named_dest_equal (const void *key_a, const void *key_b)
+{
+ const cairo_pdf_named_dest_t *a = key_a;
+ const cairo_pdf_named_dest_t *b = key_b;
+
+ return strcmp (a->attrs.name, b->attrs.name) == 0;
+}
+
+static void
+_named_dest_pluck (void *entry, void *closure)
+{
+ cairo_pdf_named_dest_t *dest = entry;
+ cairo_hash_table_t *table = closure;
+
+ _cairo_hash_table_remove (table, &dest->base);
+ free (dest->attrs.name);
+ free (dest);
+}
+
static cairo_int_status_t
-cairo_pdf_interchange_write_link_action (cairo_pdf_surface_t *surface,
- cairo_link_attrs_t *link_attrs)
+cairo_pdf_interchange_write_explicit_dest (cairo_pdf_surface_t *surface,
+ int page,
+ cairo_bool_t has_pos,
+ double x,
+ double y)
{
- cairo_int_status_t status;
+ cairo_pdf_resource_t res;
double height;
+
+ if (page < 1 || page > (int)_cairo_array_num_elements (&surface->pages))
+ return CAIRO_INT_STATUS_TAG_ERROR;
+
+ _cairo_array_copy_element (&surface->page_heights, page - 1, &height);
+ _cairo_array_copy_element (&surface->pages, page - 1, &res);
+ if (has_pos) {
+ _cairo_output_stream_printf (surface->output,
+ " /Dest [%d 0 R /XYZ %f %f 0]\n",
+ res.id,
+ x,
+ height - y);
+ } else {
+ _cairo_output_stream_printf (surface->output,
+ " /Dest [%d 0 R /XYZ null null 0]\n",
+ res.id);
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+cairo_pdf_interchange_write_dest (cairo_pdf_surface_t *surface,
+ cairo_link_attrs_t *link_attrs)
+{
+ cairo_int_status_t status;
+ cairo_pdf_interchange_t *ic = &surface->interchange;
char *dest = NULL;
if (link_attrs->dest) {
+ cairo_pdf_named_dest_t key;
+ cairo_pdf_named_dest_t *named_dest;
+
+ /* check if this is a link to an internal named dest */
+ key.attrs.name = link_attrs->dest;
+ init_named_dest_key (&key);
+ named_dest = _cairo_hash_table_lookup (ic->named_dests, &key.base);
+ if (named_dest && named_dest->attrs.internal) {
+ /* if dests exists and has internal attribute, use a direct
+ * reference instead of the name */
+ double x = 0;
+ double y = 0;
+
+ if (named_dest->extents.valid) {
+ x = named_dest->extents.extents.x;
+ y = named_dest->extents.extents.y;
+ }
+
+ if (named_dest->attrs.x_valid)
+ x = named_dest->attrs.x;
+
+ if (named_dest->attrs.y_valid)
+ y = named_dest->attrs.y;
+
+ status = cairo_pdf_interchange_write_explicit_dest (surface,
+ named_dest->page,
+ TRUE,
+ x, y);
+ return status;
+ }
+ }
+
+ if (link_attrs->dest) {
status = _cairo_utf8_to_pdf_string (link_attrs->dest, &dest);
if (unlikely (status))
return status;
+
+ _cairo_output_stream_printf (surface->output,
+ " /Dest %s\n",
+ dest);
+ free (dest);
+ } else {
+ status = cairo_pdf_interchange_write_explicit_dest (surface,
+ link_attrs->page,
+ link_attrs->has_pos,
+ link_attrs->pos.x,
+ link_attrs->pos.y);
}
- if (link_attrs->link_type == TAG_LINK_DEST) {
+ return CAIRO_STATUS_SUCCESS;
+}
- if (link_attrs->dest) {
- _cairo_output_stream_printf (surface->output,
- " /Dest %s\n",
- dest);
- } else {
- cairo_pdf_resource_t res;
- int page = link_attrs->page;
+static cairo_int_status_t
+cairo_pdf_interchange_write_link_action (cairo_pdf_surface_t *surface,
+ cairo_link_attrs_t *link_attrs)
+{
+ cairo_int_status_t status;
+ char *dest = NULL;
- if (page < 1 || page > (int)_cairo_array_num_elements (&surface->pages))
- return CAIRO_INT_STATUS_TAG_ERROR;
+ if (link_attrs->link_type == TAG_LINK_DEST) {
+ status = cairo_pdf_interchange_write_dest (surface, link_attrs);
+ if (unlikely (status))
+ return status;
- _cairo_array_copy_element (&surface->page_heights, page - 1, &height);
- _cairo_array_copy_element (&surface->pages, page - 1, &res);
- if (link_attrs->has_pos) {
- _cairo_output_stream_printf (surface->output,
- " /Dest [%d 0 R /XYZ %f %f 0]\n",
- res.id,
- link_attrs->pos.x,
- height - link_attrs->pos.y);
- } else {
- _cairo_output_stream_printf (surface->output,
- " /Dest [%d 0 R /XYZ null null 0]\n",
- res.id);
- }
- }
} else if (link_attrs->link_type == TAG_LINK_URI) {
_cairo_output_stream_printf (surface->output,
" /A <<\n"
@@ -286,9 +376,14 @@ cairo_pdf_interchange_write_link_action (cairo_pdf_surface_t *surface,
" /F (%s)\n",
link_attrs->file);
if (link_attrs->dest) {
+ status = _cairo_utf8_to_pdf_string (link_attrs->dest, &dest);
+ if (unlikely (status))
+ return status;
+
_cairo_output_stream_printf (surface->output,
" /D %s\n",
dest);
+ free (dest);
} else {
if (link_attrs->has_pos) {
_cairo_output_stream_printf (surface->output,
@@ -305,7 +400,6 @@ cairo_pdf_interchange_write_link_action (cairo_pdf_surface_t *surface,
_cairo_output_stream_printf (surface->output,
" >>\n");
}
- free (dest);
return CAIRO_STATUS_SUCCESS;
}
@@ -796,6 +890,9 @@ _cairo_pdf_interchange_write_document_dests (cairo_pdf_surface_t *surface)
double y = 0;
double height;
+ if (dest->attrs.internal)
+ continue;
+
if (dest->extents.valid) {
x = dest->extents.extents.x;
y = dest->extents.extents.y;
@@ -891,34 +988,6 @@ cairo_pdf_interchange_write_docinfo (cairo_pdf_surface_t *surface)
return CAIRO_STATUS_SUCCESS;
}
-static void
-init_named_dest_key (cairo_pdf_named_dest_t *dest)
-{
- dest->base.hash = _cairo_hash_bytes (_CAIRO_HASH_INIT_VALUE,
- dest->attrs.name,
- strlen (dest->attrs.name));
-}
-
-static cairo_bool_t
-_named_dest_equal (const void *key_a, const void *key_b)
-{
- const cairo_pdf_named_dest_t *a = key_a;
- const cairo_pdf_named_dest_t *b = key_b;
-
- return strcmp (a->attrs.name, b->attrs.name) == 0;
-}
-
-static void
-_named_dest_pluck (void *entry, void *closure)
-{
- cairo_pdf_named_dest_t *dest = entry;
- cairo_hash_table_t *table = closure;
-
- _cairo_hash_table_remove (table, &dest->base);
- free (dest->attrs.name);
- free (dest);
-}
-
static cairo_int_status_t
_cairo_pdf_interchange_begin_structure_tag (cairo_pdf_surface_t *surface,
cairo_tag_type_t tag_type,
diff --git a/src/cairo-pdf-surface-private.h b/src/cairo-pdf-surface-private.h
index 09262e0d3..a84ea9573 100644
--- a/src/cairo-pdf-surface-private.h
+++ b/src/cairo-pdf-surface-private.h
@@ -189,7 +189,6 @@ typedef struct _cairo_pdf_named_dest {
struct tag_extents extents;
cairo_dest_attrs_t attrs;
int page;
- cairo_bool_t referenced;
} cairo_pdf_named_dest_t;
typedef struct _cairo_pdf_outline_entry {
diff --git a/test/pdf-tagged-text.c b/test/pdf-tagged-text.c
index afadd6b87..5c1b82bc2 100644
--- a/test/pdf-tagged-text.c
+++ b/test/pdf-tagged-text.c
@@ -344,7 +344,7 @@ create_document (cairo_surface_t *surface, cairo_t *cr)
"Contents", "dest='TOC'",
CAIRO_PDF_OUTLINE_FLAG_BOLD);
- cairo_tag_begin (cr, CAIRO_TAG_DEST, "name='TOC'");
+ cairo_tag_begin (cr, CAIRO_TAG_DEST, "name='TOC' internal");
cairo_tag_begin (cr, "TOC", NULL);
const struct section *sect = contents;
while (sect->heading) {