summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdrian Johnson <ajohnson@redneon.com>2016-10-01 22:44:22 +0930
committerAdrian Johnson <ajohnson@redneon.com>2016-10-01 22:44:22 +0930
commit26b3f83ff652a284b79557ec1555b398c566a7eb (patch)
tree8a5aff3112e7853293a401f0f3ea023230b3e6c3
parent5bfadd5530623d3b12fadf8cd22f95cec4132b65 (diff)
pdf: page label API
-rw-r--r--doc/public/cairo-sections.txt1
-rw-r--r--src/cairo-pdf-interchange.c115
-rw-r--r--src/cairo-pdf-surface-private.h3
-rw-r--r--src/cairo-pdf-surface.c43
-rw-r--r--src/cairo-pdf.h4
5 files changed, 166 insertions, 0 deletions
diff --git a/doc/public/cairo-sections.txt b/doc/public/cairo-sections.txt
index 200c9b21d..51bf48c72 100644
--- a/doc/public/cairo-sections.txt
+++ b/doc/public/cairo-sections.txt
@@ -80,6 +80,7 @@ cairo_pdf_version_to_string
cairo_pdf_surface_set_size
cairo_pdf_surface_add_outline
cairo_pdf_surface_set_metadata
+cairo_pdf_surface_set_page_label
</SECTION>
<SECTION>
diff --git a/src/cairo-pdf-interchange.c b/src/cairo-pdf-interchange.c
index a84f0ccfa..622f3b3f3 100644
--- a/src/cairo-pdf-interchange.c
+++ b/src/cairo-pdf-interchange.c
@@ -599,6 +599,117 @@ cairo_pdf_interchange_write_outline (cairo_pdf_surface_t *surface)
return status;
}
+/*
+ * Split a page label into a text prefix and numeric suffix. Leading '0's are
+ * included in the prefix. eg
+ * "3" => NULL, 3
+ * "cover" => "cover", 0
+ * "A-2" => "A-", 2
+ * "A-002" => "A-00", 2
+ */
+static char *
+split_label (const char* label, int *num)
+{
+ int len, i;
+
+ *num = 0;
+ len = strlen (label);
+ if (len == 0)
+ return NULL;
+
+ i = len;
+ while (i > 0 && _cairo_isdigit (label[i-1]))
+ i--;
+
+ while (i < len && label[i] == '0')
+ i++;
+
+ if (i < len)
+ sscanf (label + i, "%d", num);
+
+ if (i > 0)
+ return strndup (label, i);
+
+ return NULL;
+}
+
+/* strcmp that handles NULL arguments */
+static cairo_bool_t
+strcmp_null (const char *s1, const char *s2)
+{
+ if (s1 && s2)
+ return strcmp (s1, s2) == 0;
+
+ if (!s1 && !s2)
+ return TRUE;
+
+ return FALSE;
+}
+
+static cairo_int_status_t
+cairo_pdf_interchange_write_page_labels (cairo_pdf_surface_t *surface)
+{
+ int num_elems, i;
+ char *label;
+ char *prefix;
+ char *prev_prefix;
+ int num, prev_num;
+ cairo_int_status_t status;
+
+ num_elems = _cairo_array_num_elements (&surface->page_labels);
+ if (num_elems > 0) {
+ surface->page_labels_res = _cairo_pdf_surface_new_object (surface);
+ _cairo_output_stream_printf (surface->output,
+ "%d 0 obj\n"
+ "<< /Nums [\n",
+ surface->page_labels_res.id);
+ prefix = NULL;
+ prev_prefix = NULL;
+ num = 0;
+ prev_num = 0;
+ for (i = 0; i < num_elems; i++) {
+ _cairo_array_copy_element (&surface->page_labels, i, &label);
+ if (label) {
+ prefix = split_label (label, &num);
+ } else {
+ prefix = NULL;
+ num = i + 1;
+ }
+
+ if (!strcmp_null (prefix, prev_prefix) || num != prev_num + 1) {
+ _cairo_output_stream_printf (surface->output, " %d << ", i);
+
+ if (num)
+ _cairo_output_stream_printf (surface->output, "/S /D /St %d ", num);
+
+ if (prefix) {
+ char *s;
+ status = _cairo_utf8_to_pdf_string (prefix, &s);
+ if (unlikely (status))
+ return status;
+
+ _cairo_output_stream_printf (surface->output, "/P %s ", s);
+ free (s);
+ }
+
+ _cairo_output_stream_printf (surface->output, ">>\n");
+ }
+ free (prev_prefix);
+ prev_prefix = prefix;
+ prefix = NULL;
+ prev_num = num;
+ }
+ free (prefix);
+ free (prev_prefix);
+ _cairo_output_stream_printf (surface->output,
+ " ]\n"
+ ">>\n"
+ "endobj\n");
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
static void
_collect_dest (void *entry, void *closure)
{
@@ -1077,6 +1188,10 @@ _cairo_pdf_interchange_write_document_objects (cairo_pdf_surface_t *surface)
if (unlikely (status))
return status;
+ status = cairo_pdf_interchange_write_page_labels (surface);
+ if (unlikely (status))
+ return status;
+
status = cairo_pdf_interchange_write_names_dict (surface);
if (unlikely (status))
return status;
diff --git a/src/cairo-pdf-surface-private.h b/src/cairo-pdf-surface-private.h
index a3d45d0ad..960e07cd9 100644
--- a/src/cairo-pdf-surface-private.h
+++ b/src/cairo-pdf-surface-private.h
@@ -323,9 +323,12 @@ struct _cairo_pdf_surface {
int page_parent_tree; /* -1 if not used */
cairo_array_t page_annots;
cairo_bool_t tagged;
+ char *current_page_label;
+ cairo_array_t page_labels;
cairo_pdf_resource_t outlines_dict_res;
cairo_pdf_resource_t names_dict_res;
cairo_pdf_resource_t docinfo_res;
+ cairo_pdf_resource_t page_labels_res;
cairo_surface_t *paginated_surface;
};
diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c
index 3a125e74f..900055431 100644
--- a/src/cairo-pdf-surface.c
+++ b/src/cairo-pdf-surface.c
@@ -447,8 +447,12 @@ _cairo_pdf_surface_create_for_stream_internal (cairo_output_stream_t *output,
surface->page_parent_tree = -1;
_cairo_array_init (&surface->page_annots, sizeof (cairo_pdf_resource_t));
surface->tagged = FALSE;
+ surface->current_page_label = NULL;
+ _cairo_array_init (&surface->page_labels, sizeof (char *));
surface->outlines_dict_res.id = 0;
surface->names_dict_res.id = 0;
+ surface->docinfo_res.id = 0;
+ surface->page_labels_res.id = 0;
surface->paginated_surface = _cairo_paginated_surface_create (
&surface->base,
@@ -806,6 +810,28 @@ cairo_pdf_surface_set_metadata (cairo_surface_t *surface,
status = _cairo_surface_set_error (surface, status);
}
+/**
+ * cairo_pdf_surface_set_page_label:
+ * @surface: a PDF #cairo_surface_t
+ * @utf8: The page label.
+ *
+ * Set page label for the current page.
+ *
+ * Since: 1.16
+ **/
+void
+cairo_pdf_surface_set_page_label (cairo_surface_t *surface,
+ const char *utf8)
+{
+ cairo_pdf_surface_t *pdf_surface = NULL; /* hide compiler warning */
+
+ if (! _extract_pdf_surface (surface, &pdf_surface))
+ return;
+
+ free (pdf_surface->current_page_label);
+ pdf_surface->current_page_label = utf8 ? strdup (utf8) : NULL;
+}
+
static void
_cairo_pdf_surface_clear (cairo_pdf_surface_t *surface)
{
@@ -2158,6 +2184,7 @@ _cairo_pdf_surface_finish (void *abstract_surface)
cairo_status_t status, status2;
int size, i;
cairo_pdf_jbig2_global_t *global;
+ char *label;
status = surface->base.status;
if (status == CAIRO_STATUS_SUCCESS)
@@ -2255,6 +2282,13 @@ _cairo_pdf_surface_finish (void *abstract_surface)
}
_cairo_array_fini (&surface->jbig2_global);
+ size = _cairo_array_num_elements (&surface->page_labels);
+ for (i = 0; i < size; i++) {
+ _cairo_array_copy_element (&surface->page_labels, i, &label);
+ free (label);
+ }
+ _cairo_array_fini (&surface->page_labels);
+
_cairo_array_truncate (&surface->page_surfaces, 0);
_cairo_surface_clipper_reset (&surface->clipper);
@@ -4783,6 +4817,9 @@ _cairo_pdf_surface_show_page (void *abstract_surface)
cairo_pdf_surface_t *surface = abstract_surface;
cairo_int_status_t status;
+ status = _cairo_array_append (&surface->page_labels, &surface->current_page_label);
+ surface->current_page_label = NULL;
+
status = _cairo_pdf_interchange_end_page_content (surface);
if (unlikely (status))
return status;
@@ -6173,6 +6210,12 @@ _cairo_pdf_surface_write_catalog (cairo_pdf_surface_t *surface)
surface->outlines_dict_res.id);
}
+ if (surface->page_labels_res.id != 0) {
+ _cairo_output_stream_printf (surface->output,
+ " /PageLabels %d 0 R\n",
+ surface->page_labels_res.id);
+ }
+
if (surface->names_dict_res.id != 0) {
_cairo_output_stream_printf (surface->output,
" /Names %d 0 R\n",
diff --git a/src/cairo-pdf.h b/src/cairo-pdf.h
index 0589ba53a..9bf69fedd 100644
--- a/src/cairo-pdf.h
+++ b/src/cairo-pdf.h
@@ -144,6 +144,10 @@ cairo_pdf_surface_set_metadata (cairo_surface_t *surface,
cairo_pdf_metadata_t metadata,
const char *utf8);
+void
+cairo_pdf_surface_set_page_label (cairo_surface_t *surface,
+ const char *utf8);
+
CAIRO_END_DECLS
#else /* CAIRO_HAS_PDF_SURFACE */