summaryrefslogtreecommitdiff
path: root/src/cairo-pdf-interchange.c
diff options
context:
space:
mode:
authorAdrian Johnson <ajohnson@redneon.com>2021-07-24 21:26:22 +0930
committerAdrian Johnson <ajohnson@redneon.com>2021-07-24 21:33:09 +0930
commitf7c7bcb6030aa36677adcc4887c8f9f8964431d6 (patch)
tree50c40a46d769f202e239263a99d0f43080f70104 /src/cairo-pdf-interchange.c
parent994eccefc0a778d291a8dbbb4143280b38a7ad80 (diff)
downloadcairo-f7c7bcb6030aa36677adcc4887c8f9f8964431d6.tar.gz
tags: allow links to page numbers not yet created
Previously, forward references were required to use named destinations. This patch is based on the patch in #336 by Guillaume Ayoub <guillaume.ayoub@kozea.fr> that converted all links to indirect objects written at the end of the document. I have reworked the patch so that only forward references to future page numbers are written as indirect objects. Backward references and named destinations remain as they are. This is to minimize the number of objects written to the PDF file. Fixes #336
Diffstat (limited to 'src/cairo-pdf-interchange.c')
-rw-r--r--src/cairo-pdf-interchange.c93
1 files changed, 77 insertions, 16 deletions
diff --git a/src/cairo-pdf-interchange.c b/src/cairo-pdf-interchange.c
index ad4072e63..8158161fb 100644
--- a/src/cairo-pdf-interchange.c
+++ b/src/cairo-pdf-interchange.c
@@ -335,20 +335,17 @@ cairo_pdf_interchange_write_explicit_dest (cairo_pdf_surface_t *surface,
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",
+ "[%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",
+ "[%d 0 R /XYZ null null 0]\n",
res.id);
}
@@ -362,6 +359,8 @@ 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 (link_attrs->dest) {
cairo_pdf_named_dest_t key;
@@ -388,10 +387,11 @@ cairo_pdf_interchange_write_dest (cairo_pdf_surface_t *surface,
if (named_dest->attrs.y_valid)
y = named_dest->attrs.y;
+ _cairo_output_stream_printf (surface->output, " /Dest ");
status = cairo_pdf_interchange_write_explicit_dest (surface,
- named_dest->page,
- TRUE,
- x, y);
+ named_dest->page,
+ TRUE,
+ x, y);
return status;
}
}
@@ -406,14 +406,41 @@ cairo_pdf_interchange_write_dest (cairo_pdf_surface_t *surface,
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->page < 1)
+ return CAIRO_INT_STATUS_TAG_ERROR;
+
+ if (link_attrs->page <= (int)_cairo_array_num_elements (&surface->pages)) {
+ _cairo_output_stream_printf (surface->output, " /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 */
+
+ link = _cairo_malloc (sizeof (cairo_pdf_forward_link_t));
+ if (unlikely (link == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+ 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->output,
+ " /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);
+ }
}
- return CAIRO_STATUS_SUCCESS;
+ return status;
}
static cairo_int_status_t
@@ -856,6 +883,36 @@ strcmp_null (const char *s1, const char *s2)
}
static cairo_int_status_t
+cairo_pdf_interchange_write_forward_links (cairo_pdf_surface_t *surface)
+{
+ int num_elems, i;
+ cairo_pdf_forward_link_t *link;
+
+ num_elems = _cairo_array_num_elements (&surface->forward_links);
+ for (i = 0; i < num_elems; i++) {
+ link = _cairo_array_index (&surface->forward_links, i);
+ if (link->page > (int)_cairo_array_num_elements (&surface->pages))
+ return CAIRO_INT_STATUS_TAG_ERROR;
+
+ _cairo_pdf_surface_update_object (surface, link->res);
+ _cairo_output_stream_printf (surface->output,
+ "%d 0 obj\n",
+ link->res.id);
+
+ cairo_pdf_interchange_write_explicit_dest (surface,
+ link->page,
+ link->has_pos,
+ link->pos.x,
+ link->pos.y);
+
+ _cairo_output_stream_printf (surface->output,
+ "endobj\n");
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
cairo_pdf_interchange_write_page_labels (cairo_pdf_surface_t *surface)
{
int num_elems, i;
@@ -1364,10 +1421,10 @@ _cairo_pdf_interchange_write_page_objects (cairo_pdf_surface_t *surface)
cairo_int_status_t status;
status = cairo_pdf_interchange_write_page_annots (surface);
- if (unlikely (status))
+ if (unlikely (status))
return status;
- cairo_pdf_interchange_clear_annotations (surface);
+ cairo_pdf_interchange_clear_annotations (surface);
return cairo_pdf_interchange_write_page_parent_elems (surface);
}
@@ -1403,6 +1460,10 @@ _cairo_pdf_interchange_write_document_objects (cairo_pdf_surface_t *surface)
if (unlikely (status))
return status;
+ status = cairo_pdf_interchange_write_forward_links (surface);
+ if (unlikely (status))
+ return status;
+
status = cairo_pdf_interchange_write_names_dict (surface);
if (unlikely (status))
return status;