summaryrefslogtreecommitdiff
path: root/src/cairo-pdf-interchange.c
diff options
context:
space:
mode:
authorAdrian Johnson <ajohnson@redneon.com>2021-07-28 07:18:25 +0930
committerAdrian Johnson <ajohnson@redneon.com>2021-07-29 07:31:31 +0930
commitca1fb44dd367eaa1a544a2655425b0313c758ca2 (patch)
tree123b57ad01e9f0ccf9bb588afd8e2a8552b0b874 /src/cairo-pdf-interchange.c
parent47e6764de620f24a7b0c36f53c1fb8a3b5de8a6c (diff)
downloadcairo-ca1fb44dd367eaa1a544a2655425b0313c758ca2.tar.gz
pdf links: fix forward references to dest names with 'internal' flag
Diffstat (limited to 'src/cairo-pdf-interchange.c')
-rw-r--r--src/cairo-pdf-interchange.c119
1 files changed, 71 insertions, 48 deletions
diff --git a/src/cairo-pdf-interchange.c b/src/cairo-pdf-interchange.c
index 45c9139b4..921952afb 100644
--- a/src/cairo-pdf-interchange.c
+++ b/src/cairo-pdf-interchange.c
@@ -361,21 +361,19 @@ cairo_pdf_interchange_write_dest (cairo_pdf_surface_t *surface,
{
cairo_int_status_t status;
cairo_pdf_interchange_t *ic = &surface->interchange;
- char *dest = NULL;
cairo_pdf_forward_link_t *link;
cairo_pdf_resource_t link_res;
+ /* If the dest is known, emit an explicit dest */
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 */
+ /* check if we already have this 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 */
+ if (named_dest) {
double x = 0;
double y = 0;
@@ -399,49 +397,42 @@ cairo_pdf_interchange_write_dest (cairo_pdf_surface_t *surface,
}
}
- if (link_attrs->dest) {
- status = _cairo_utf8_to_pdf_string (link_attrs->dest, &dest);
- if (unlikely (status))
- return status;
-
- _cairo_output_stream_printf (surface->object_stream.stream,
- " /Dest %s\n",
- dest);
- free (dest);
- } else {
+ /* If the page is known, emit an explicit dest */
+ if (!link_attrs->dest) {
if (link_attrs->page < 1)
return _cairo_tag_error ("Link attribute: \"page=%d\" page must be >= 1", link_attrs->page);
if (link_attrs->page <= (int)_cairo_array_num_elements (&surface->pages)) {
_cairo_output_stream_printf (surface->object_stream.stream, " /Dest ");
- status = cairo_pdf_interchange_write_explicit_dest (surface,
- link_attrs->page,
- link_attrs->has_pos,
- link_attrs->pos.x,
- link_attrs->pos.y);
- } else {
- /* Link refers to a future page. Use an indirect object and
- * write the link at the end of the document */
+ return cairo_pdf_interchange_write_explicit_dest (surface,
+ link_attrs->page,
+ link_attrs->has_pos,
+ link_attrs->pos.x,
+ link_attrs->pos.y);
+ }
+ }
- link = _cairo_malloc (sizeof (cairo_pdf_forward_link_t));
- if (unlikely (link == NULL))
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ /* Link refers to a future or unknown page. Use an indirect object
+ * and write the link at the end of the document */
- link_res = _cairo_pdf_surface_new_object (surface);
- if (link_res.id == 0)
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ link = _cairo_malloc (sizeof (cairo_pdf_forward_link_t));
+ if (unlikely (link == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
- _cairo_output_stream_printf (surface->object_stream.stream,
- " /Dest %d 0 R\n",
- link_res.id);
-
- link->res = link_res;
- link->page = link_attrs->page;
- link->has_pos = link_attrs->has_pos;
- link->pos = link_attrs->pos;
- status = _cairo_array_append (&surface->forward_links, link);
- }
- }
+ link_res = _cairo_pdf_surface_new_object (surface);
+ if (link_res.id == 0)
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+ _cairo_output_stream_printf (surface->object_stream.stream,
+ " /Dest %d 0 R\n",
+ link_res.id);
+
+ link->res = link_res;
+ link->dest = link_attrs->dest ? strdup (link_attrs->dest) : NULL;
+ link->page = link_attrs->page;
+ link->has_pos = link_attrs->has_pos;
+ link->pos = link_attrs->pos;
+ status = _cairo_array_append (&surface->forward_links, link);
return status;
}
@@ -919,6 +910,9 @@ cairo_pdf_interchange_write_forward_links (cairo_pdf_surface_t *surface)
int num_elems, i;
cairo_pdf_forward_link_t *link;
cairo_int_status_t status;
+ cairo_pdf_named_dest_t key;
+ cairo_pdf_named_dest_t *named_dest;
+ cairo_pdf_interchange_t *ic = &surface->interchange;
num_elems = _cairo_array_num_elements (&surface->forward_links);
for (i = 0; i < num_elems; i++) {
@@ -932,12 +926,39 @@ cairo_pdf_interchange_write_forward_links (cairo_pdf_surface_t *surface)
if (unlikely (status))
return status;
- cairo_pdf_interchange_write_explicit_dest (surface,
- link->page,
- link->has_pos,
- link->pos.x,
- link->pos.y);
+ if (link->dest) {
+ key.attrs.name = link->dest;
+ init_named_dest_key (&key);
+ named_dest = _cairo_hash_table_lookup (ic->named_dests, &key.base);
+ if (named_dest) {
+ 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);
+ } else {
+ return _cairo_tag_error ("Link to dest=\"%s\" not found", link->dest);
+ }
+ } else {
+ cairo_pdf_interchange_write_explicit_dest (surface,
+ link->page,
+ link->has_pos,
+ link->pos.x,
+ link->pos.y);
+ }
_cairo_pdf_surface_object_end (surface);
}
@@ -1026,13 +1047,14 @@ cairo_pdf_interchange_write_page_labels (cairo_pdf_surface_t *surface)
}
static void
-_collect_dest (void *entry, void *closure)
+_collect_external_dest (void *entry, void *closure)
{
cairo_pdf_named_dest_t *dest = entry;
cairo_pdf_surface_t *surface = closure;
cairo_pdf_interchange_t *ic = &surface->interchange;
- ic->sorted_dests[ic->num_dests++] = dest;
+ if (!dest->attrs.internal)
+ ic->sorted_dests[ic->num_dests++] = dest;
}
static int
@@ -1061,7 +1083,8 @@ _cairo_pdf_interchange_write_document_dests (cairo_pdf_surface_t *surface)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
ic->num_dests = 0;
- _cairo_hash_table_foreach (ic->named_dests, _collect_dest, surface);
+ _cairo_hash_table_foreach (ic->named_dests, _collect_external_dest, surface);
+
qsort (ic->sorted_dests, ic->num_dests, sizeof (cairo_pdf_named_dest_t *), _dest_compare);
ic->dests_res = _cairo_pdf_surface_new_object (surface);