diff options
author | Adrian Johnson <ajohnson@redneon.com> | 2021-07-28 07:18:25 +0930 |
---|---|---|
committer | Adrian Johnson <ajohnson@redneon.com> | 2021-07-29 07:31:31 +0930 |
commit | ca1fb44dd367eaa1a544a2655425b0313c758ca2 (patch) | |
tree | 123b57ad01e9f0ccf9bb588afd8e2a8552b0b874 /src/cairo-pdf-interchange.c | |
parent | 47e6764de620f24a7b0c36f53c1fb8a3b5de8a6c (diff) | |
download | cairo-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.c | 119 |
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); |