summaryrefslogtreecommitdiff
path: root/libs/cairo-1.16.0/src/cairo-pdf-interchange.c
diff options
context:
space:
mode:
authorsanine <sanine.not@pm.me>2023-02-12 23:53:22 -0600
committersanine <sanine.not@pm.me>2023-02-12 23:53:22 -0600
commitf1fe73d1909a2448a004a88362a1a532d0d4f7c3 (patch)
treeab37ae3837e2f858de2932bcee9f26e69fab3db1 /libs/cairo-1.16.0/src/cairo-pdf-interchange.c
parentf567ea1e2798fd3156a416e61f083ea3e6b95719 (diff)
switch to tinyobj and nanovg from assimp and cairo
Diffstat (limited to 'libs/cairo-1.16.0/src/cairo-pdf-interchange.c')
-rw-r--r--libs/cairo-1.16.0/src/cairo-pdf-interchange.c1728
1 files changed, 0 insertions, 1728 deletions
diff --git a/libs/cairo-1.16.0/src/cairo-pdf-interchange.c b/libs/cairo-1.16.0/src/cairo-pdf-interchange.c
deleted file mode 100644
index 7d8981b..0000000
--- a/libs/cairo-1.16.0/src/cairo-pdf-interchange.c
+++ /dev/null
@@ -1,1728 +0,0 @@
-/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
-/* cairo - a vector graphics library with display and print output
- *
- * Copyright © 2016 Adrian Johnson
- *
- * This library is free software; you can redistribute it and/or
- * modify it either under the terms of the GNU Lesser General Public
- * License version 2.1 as published by the Free Software Foundation
- * (the "LGPL") or, at your option, under the terms of the Mozilla
- * Public License Version 1.1 (the "MPL"). If you do not alter this
- * notice, a recipient may use your version of this file under either
- * the MPL or the LGPL.
- *
- * You should have received a copy of the LGPL along with this library
- * in the file COPYING-LGPL-2.1; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
- * You should have received a copy of the MPL along with this library
- * in the file COPYING-MPL-1.1
- *
- * The contents of this file are subject to the Mozilla Public License
- * Version 1.1 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
- * OF ANY KIND, either express or implied. See the LGPL or the MPL for
- * the specific language governing rights and limitations.
- *
- * The Original Code is the cairo graphics library.
- *
- * The Initial Developer of the Original Code is Adrian Johnson.
- *
- * Contributor(s):
- * Adrian Johnson <ajohnson@redneon.com>
- */
-
-
-/* PDF Document Interchange features:
- * - metadata
- * - document outline
- * - tagged pdf
- * - hyperlinks
- * - page labels
- */
-
-#define _DEFAULT_SOURCE /* for localtime_r(), gmtime_r(), snprintf(), strdup() */
-#include "cairoint.h"
-
-#include "cairo-pdf.h"
-#include "cairo-pdf-surface-private.h"
-
-#include "cairo-array-private.h"
-#include "cairo-error-private.h"
-#include "cairo-output-stream-private.h"
-
-#include <time.h>
-
-#ifndef HAVE_LOCALTIME_R
-#define localtime_r(T, BUF) (*(BUF) = *localtime (T))
-#endif
-#ifndef HAVE_GMTIME_R
-#define gmtime_r(T, BUF) (*(BUF) = *gmtime (T))
-#endif
-
-static void
-write_rect_to_pdf_quad_points (cairo_output_stream_t *stream,
- const cairo_rectangle_t *rect,
- double surface_height)
-{
- _cairo_output_stream_printf (stream,
- "%f %f %f %f %f %f %f %f",
- rect->x,
- surface_height - rect->y,
- rect->x + rect->width,
- surface_height - rect->y,
- rect->x + rect->width,
- surface_height - (rect->y + rect->height),
- rect->x,
- surface_height - (rect->y + rect->height));
-}
-
-static void
-write_rect_int_to_pdf_bbox (cairo_output_stream_t *stream,
- const cairo_rectangle_int_t *rect,
- double surface_height)
-{
- _cairo_output_stream_printf (stream,
- "%d %f %d %f",
- rect->x,
- surface_height - (rect->y + rect->height),
- rect->x + rect->width,
- surface_height - rect->y);
-}
-
-static cairo_int_status_t
-add_tree_node (cairo_pdf_surface_t *surface,
- cairo_pdf_struct_tree_node_t *parent,
- const char *name,
- cairo_pdf_struct_tree_node_t **new_node)
-{
- cairo_pdf_struct_tree_node_t *node;
-
- node = _cairo_malloc (sizeof(cairo_pdf_struct_tree_node_t));
- if (unlikely (node == NULL))
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
- node->name = strdup (name);
- node->res = _cairo_pdf_surface_new_object (surface);
- if (node->res.id == 0)
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
- node->parent = parent;
- cairo_list_init (&node->children);
- _cairo_array_init (&node->mcid, sizeof(struct page_mcid));
- node->annot_res.id = 0;
- node->extents.valid = FALSE;
- cairo_list_init (&node->extents.link);
-
- cairo_list_add_tail (&node->link, &parent->children);
-
- *new_node = node;
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_bool_t
-is_leaf_node (cairo_pdf_struct_tree_node_t *node)
-{
- return node->parent && cairo_list_is_empty (&node->children) ;
-}
-
-static void
-free_node (cairo_pdf_struct_tree_node_t *node)
-{
- cairo_pdf_struct_tree_node_t *child, *next;
-
- if (!node)
- return;
-
- cairo_list_foreach_entry_safe (child, next, cairo_pdf_struct_tree_node_t,
- &node->children, link)
- {
- cairo_list_del (&child->link);
- free_node (child);
- }
- free (node->name);
- _cairo_array_fini (&node->mcid);
- free (node);
-}
-
-static cairo_status_t
-add_mcid_to_node (cairo_pdf_surface_t *surface,
- cairo_pdf_struct_tree_node_t *node,
- int page,
- int *mcid)
-{
- struct page_mcid mcid_elem;
- cairo_int_status_t status;
- cairo_pdf_interchange_t *ic = &surface->interchange;
-
- status = _cairo_array_append (&ic->mcid_to_tree, &node);
- if (unlikely (status))
- return status;
-
- mcid_elem.page = page;
- mcid_elem.mcid = _cairo_array_num_elements (&ic->mcid_to_tree) - 1;
- *mcid = mcid_elem.mcid;
- return _cairo_array_append (&node->mcid, &mcid_elem);
-}
-
-static cairo_int_status_t
-add_annotation (cairo_pdf_surface_t *surface,
- cairo_pdf_struct_tree_node_t *node,
- const char *name,
- const char *attributes)
-{
- cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
- cairo_pdf_interchange_t *ic = &surface->interchange;
- cairo_pdf_annotation_t *annot;
-
- annot = malloc (sizeof(cairo_pdf_annotation_t));
- if (unlikely (annot == NULL))
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
- status = _cairo_tag_parse_link_attributes (attributes, &annot->link_attrs);
- if (unlikely (status)) {
- free (annot);
- return status;
- }
-
- annot->node = node;
-
- status = _cairo_array_append (&ic->annots, &annot);
-
- return status;
-}
-
-static void
-free_annotation (cairo_pdf_annotation_t *annot)
-{
- _cairo_array_fini (&annot->link_attrs.rects);
- free (annot->link_attrs.dest);
- free (annot->link_attrs.uri);
- free (annot->link_attrs.file);
- free (annot);
-}
-
-static void
-cairo_pdf_interchange_clear_annotations (cairo_pdf_surface_t *surface)
-{
- cairo_pdf_interchange_t *ic = &surface->interchange;
- int num_elems, i;
-
- num_elems = _cairo_array_num_elements (&ic->annots);
- for (i = 0; i < num_elems; i++) {
- cairo_pdf_annotation_t * annot;
-
- _cairo_array_copy_element (&ic->annots, i, &annot);
- free_annotation (annot);
- }
- _cairo_array_truncate (&ic->annots, 0);
-}
-
-static cairo_int_status_t
-cairo_pdf_interchange_write_node_object (cairo_pdf_surface_t *surface,
- cairo_pdf_struct_tree_node_t *node)
-{
- struct page_mcid *mcid_elem;
- int i, num_mcid, first_page;
- cairo_pdf_resource_t *page_res;
- cairo_pdf_struct_tree_node_t *child;
-
- _cairo_pdf_surface_update_object (surface, node->res);
- _cairo_output_stream_printf (surface->output,
- "%d 0 obj\n"
- "<< /Type /StructElem\n"
- " /S /%s\n"
- " /P %d 0 R\n",
- node->res.id,
- node->name,
- node->parent->res.id);
-
- if (! cairo_list_is_empty (&node->children)) {
- if (cairo_list_is_singular (&node->children) && node->annot_res.id == 0) {
- child = cairo_list_first_entry (&node->children, cairo_pdf_struct_tree_node_t, link);
- _cairo_output_stream_printf (surface->output, " /K %d 0 R\n", child->res.id);
- } else {
- _cairo_output_stream_printf (surface->output, " /K [ ");
- if (node->annot_res.id != 0) {
- _cairo_output_stream_printf (surface->output,
- "<< /Type /OBJR /Obj %d 0 R >> ",
- node->annot_res.id);
- }
- cairo_list_foreach_entry (child, cairo_pdf_struct_tree_node_t,
- &node->children, link)
- {
- _cairo_output_stream_printf (surface->output, "%d 0 R ", child->res.id);
- }
- _cairo_output_stream_printf (surface->output, "]\n");
- }
- } else {
- num_mcid = _cairo_array_num_elements (&node->mcid);
- if (num_mcid > 0 ) {
- mcid_elem = _cairo_array_index (&node->mcid, 0);
- first_page = mcid_elem->page;
- page_res = _cairo_array_index (&surface->pages, first_page - 1);
- _cairo_output_stream_printf (surface->output, " /Pg %d 0 R\n", page_res->id);
-
- if (num_mcid == 1 && node->annot_res.id == 0) {
- _cairo_output_stream_printf (surface->output, " /K %d\n", mcid_elem->mcid);
- } else {
- _cairo_output_stream_printf (surface->output, " /K [ ");
- if (node->annot_res.id != 0) {
- _cairo_output_stream_printf (surface->output,
- "<< /Type /OBJR /Obj %d 0 R >> ",
- node->annot_res.id);
- }
- for (i = 0; i < num_mcid; i++) {
- mcid_elem = _cairo_array_index (&node->mcid, i);
- page_res = _cairo_array_index (&surface->pages, mcid_elem->page - 1);
- if (mcid_elem->page == first_page) {
- _cairo_output_stream_printf (surface->output, "%d ", mcid_elem->mcid);
- } else {
- _cairo_output_stream_printf (surface->output,
- "\n << /Type /MCR /Pg %d 0 R /MCID %d >> ",
- page_res->id,
- mcid_elem->mcid);
- }
- }
- _cairo_output_stream_printf (surface->output, "]\n");
- }
- }
- }
- _cairo_output_stream_printf (surface->output,
- ">>\n"
- "endobj\n");
-
- 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_explicit_dest (cairo_pdf_surface_t *surface,
- int page,
- cairo_bool_t has_pos,
- double x,
- double y)
-{
- 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);
- }
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-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 (link_attrs->link_type == TAG_LINK_DEST) {
- status = cairo_pdf_interchange_write_dest (surface, link_attrs);
- if (unlikely (status))
- return status;
-
- } else if (link_attrs->link_type == TAG_LINK_URI) {
- _cairo_output_stream_printf (surface->output,
- " /A <<\n"
- " /Type /Action\n"
- " /S /URI\n"
- " /URI (%s)\n"
- " >>\n",
- link_attrs->uri);
- } else if (link_attrs->link_type == TAG_LINK_FILE) {
- _cairo_output_stream_printf (surface->output,
- " /A <<\n"
- " /Type /Action\n"
- " /S /GoToR\n"
- " /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,
- " /D [%d %f %f 0]\n",
- link_attrs->page,
- link_attrs->pos.x,
- link_attrs->pos.y);
- } else {
- _cairo_output_stream_printf (surface->output,
- " /D [%d null null 0]\n",
- link_attrs->page);
- }
- }
- _cairo_output_stream_printf (surface->output,
- " >>\n");
- }
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_int_status_t
-cairo_pdf_interchange_write_annot (cairo_pdf_surface_t *surface,
- cairo_pdf_annotation_t *annot)
-{
- cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
- cairo_pdf_interchange_t *ic = &surface->interchange;
- cairo_pdf_struct_tree_node_t *node = annot->node;
- int sp;
- int i, num_rects;
- double height;
-
- num_rects = _cairo_array_num_elements (&annot->link_attrs.rects);
- if (strcmp (node->name, CAIRO_TAG_LINK) == 0 &&
- annot->link_attrs.link_type != TAG_LINK_EMPTY &&
- (node->extents.valid || num_rects > 0))
- {
- status = _cairo_array_append (&ic->parent_tree, &node->res);
- if (unlikely (status))
- return status;
-
- sp = _cairo_array_num_elements (&ic->parent_tree) - 1;
-
- node->annot_res = _cairo_pdf_surface_new_object (surface);
-
- status = _cairo_array_append (&surface->page_annots, &node->annot_res);
- if (unlikely (status))
- return status;
-
- _cairo_pdf_surface_update_object (surface, node->annot_res);
- _cairo_output_stream_printf (surface->output,
- "%d 0 obj\n"
- "<< /Type /Annot\n"
- " /Subtype /Link\n"
- " /StructParent %d\n",
- node->annot_res.id,
- sp);
-
- height = surface->height;
- if (num_rects > 0) {
- cairo_rectangle_int_t bbox_rect;
-
- _cairo_output_stream_printf (surface->output,
- " /QuadPoints [ ");
- for (i = 0; i < num_rects; i++) {
- cairo_rectangle_t rectf;
- cairo_rectangle_int_t recti;
-
- _cairo_array_copy_element (&annot->link_attrs.rects, i, &rectf);
- _cairo_rectangle_int_from_double (&recti, &rectf);
- if (i == 0)
- bbox_rect = recti;
- else
- _cairo_rectangle_union (&bbox_rect, &recti);
-
- write_rect_to_pdf_quad_points (surface->output, &rectf, height);
- _cairo_output_stream_printf (surface->output, " ");
- }
- _cairo_output_stream_printf (surface->output,
- "]\n"
- " /Rect [ ");
- write_rect_int_to_pdf_bbox (surface->output, &bbox_rect, height);
- _cairo_output_stream_printf (surface->output, " ]\n");
- } else {
- _cairo_output_stream_printf (surface->output,
- " /Rect [ ");
- write_rect_int_to_pdf_bbox (surface->output, &node->extents.extents, height);
- _cairo_output_stream_printf (surface->output, " ]\n");
- }
-
- status = cairo_pdf_interchange_write_link_action (surface, &annot->link_attrs);
- if (unlikely (status))
- return status;
-
- _cairo_output_stream_printf (surface->output,
- " /BS << /W 0 >>"
- ">>\n"
- "endobj\n");
-
- status = _cairo_output_stream_get_status (surface->output);
- }
-
- return status;
-}
-
-static cairo_int_status_t
-cairo_pdf_interchange_walk_struct_tree (cairo_pdf_surface_t *surface,
- cairo_pdf_struct_tree_node_t *node,
- cairo_int_status_t (*func) (cairo_pdf_surface_t *surface,
- cairo_pdf_struct_tree_node_t *node))
-{
- cairo_int_status_t status;
- cairo_pdf_struct_tree_node_t *child;
-
- if (node->parent) {
- status = func (surface, node);
- if (unlikely (status))
- return status;
- }
-
- cairo_list_foreach_entry (child, cairo_pdf_struct_tree_node_t,
- &node->children, link)
- {
- status = cairo_pdf_interchange_walk_struct_tree (surface, child, func);
- if (unlikely (status))
- return status;
- }
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_int_status_t
-cairo_pdf_interchange_write_struct_tree (cairo_pdf_surface_t *surface)
-{
- cairo_pdf_interchange_t *ic = &surface->interchange;
- cairo_pdf_struct_tree_node_t *child;
-
- if (cairo_list_is_empty (&ic->struct_root->children))
- return CAIRO_STATUS_SUCCESS;
-
- surface->struct_tree_root = _cairo_pdf_surface_new_object (surface);
- ic->struct_root->res = surface->struct_tree_root;
-
- cairo_pdf_interchange_walk_struct_tree (surface, ic->struct_root, cairo_pdf_interchange_write_node_object);
-
- child = cairo_list_first_entry (&ic->struct_root->children, cairo_pdf_struct_tree_node_t, link);
- _cairo_pdf_surface_update_object (surface, surface->struct_tree_root);
- _cairo_output_stream_printf (surface->output,
- "%d 0 obj\n"
- "<< /Type /StructTreeRoot\n"
- " /ParentTree %d 0 R\n",
- surface->struct_tree_root.id,
- ic->parent_tree_res.id);
-
- if (cairo_list_is_singular (&ic->struct_root->children)) {
- child = cairo_list_first_entry (&ic->struct_root->children, cairo_pdf_struct_tree_node_t, link);
- _cairo_output_stream_printf (surface->output, " /K [ %d 0 R ]\n", child->res.id);
- } else {
- _cairo_output_stream_printf (surface->output, " /K [ ");
-
- cairo_list_foreach_entry (child, cairo_pdf_struct_tree_node_t,
- &ic->struct_root->children, link)
- {
- _cairo_output_stream_printf (surface->output, "%d 0 R ", child->res.id);
- }
- _cairo_output_stream_printf (surface->output, "]\n");
- }
-
- _cairo_output_stream_printf (surface->output,
- ">>\n"
- "endobj\n");
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_int_status_t
-cairo_pdf_interchange_write_page_annots (cairo_pdf_surface_t *surface)
-{
- cairo_pdf_interchange_t *ic = &surface->interchange;
- int num_elems, i;
- cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
-
- num_elems = _cairo_array_num_elements (&ic->annots);
- for (i = 0; i < num_elems; i++) {
- cairo_pdf_annotation_t * annot;
-
- _cairo_array_copy_element (&ic->annots, i, &annot);
- status = cairo_pdf_interchange_write_annot (surface, annot);
- if (unlikely (status))
- return status;
- }
-
- return status;
-}
-
-static cairo_int_status_t
-cairo_pdf_interchange_write_page_parent_elems (cairo_pdf_surface_t *surface)
-{
- int num_elems, i;
- cairo_pdf_struct_tree_node_t *node;
- cairo_pdf_resource_t res;
- cairo_pdf_interchange_t *ic = &surface->interchange;
- cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
-
- surface->page_parent_tree = -1;
- num_elems = _cairo_array_num_elements (&ic->mcid_to_tree);
- if (num_elems > 0) {
- res = _cairo_pdf_surface_new_object (surface);
- _cairo_output_stream_printf (surface->output,
- "%d 0 obj\n"
- "[\n",
- res.id);
- for (i = 0; i < num_elems; i++) {
- _cairo_array_copy_element (&ic->mcid_to_tree, i, &node);
- _cairo_output_stream_printf (surface->output, " %d 0 R\n", node->res.id);
- }
- _cairo_output_stream_printf (surface->output,
- "]\n"
- "endobj\n");
- status = _cairo_array_append (&ic->parent_tree, &res);
- surface->page_parent_tree = _cairo_array_num_elements (&ic->parent_tree) - 1;
- }
-
- return status;
-}
-
-static cairo_int_status_t
-cairo_pdf_interchange_write_parent_tree (cairo_pdf_surface_t *surface)
-{
- int num_elems, i;
- cairo_pdf_resource_t *res;
- cairo_pdf_interchange_t *ic = &surface->interchange;
-
- num_elems = _cairo_array_num_elements (&ic->parent_tree);
- if (num_elems > 0) {
- ic->parent_tree_res = _cairo_pdf_surface_new_object (surface);
- _cairo_output_stream_printf (surface->output,
- "%d 0 obj\n"
- "<< /Nums [\n",
- ic->parent_tree_res.id);
- for (i = 0; i < num_elems; i++) {
- res = _cairo_array_index (&ic->parent_tree, i);
- if (res->id) {
- _cairo_output_stream_printf (surface->output,
- " %d %d 0 R\n",
- i,
- res->id);
- }
- }
- _cairo_output_stream_printf (surface->output,
- " ]\n"
- ">>\n"
- "endobj\n");
- }
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_int_status_t
-cairo_pdf_interchange_write_outline (cairo_pdf_surface_t *surface)
-{
- int num_elems, i;
- cairo_pdf_outline_entry_t *outline;
- cairo_pdf_interchange_t *ic = &surface->interchange;
- cairo_int_status_t status;
- char *name = NULL;
-
- num_elems = _cairo_array_num_elements (&ic->outline);
- if (num_elems < 2)
- return CAIRO_INT_STATUS_SUCCESS;
-
- _cairo_array_copy_element (&ic->outline, 0, &outline);
- outline->res = _cairo_pdf_surface_new_object (surface);
- surface->outlines_dict_res = outline->res;
- _cairo_output_stream_printf (surface->output,
- "%d 0 obj\n"
- "<< /Type /Outlines\n"
- " /First %d 0 R\n"
- " /Last %d 0 R\n"
- " /Count %d\n"
- ">>\n"
- "endobj\n",
- outline->res.id,
- outline->first_child->res.id,
- outline->last_child->res.id,
- outline->count);
-
- for (i = 1; i < num_elems; i++) {
- _cairo_array_copy_element (&ic->outline, i, &outline);
- _cairo_pdf_surface_update_object (surface, outline->res);
-
- status = _cairo_utf8_to_pdf_string (outline->name, &name);
- if (unlikely (status))
- return status;
-
- _cairo_output_stream_printf (surface->output,
- "%d 0 obj\n"
- "<< /Title %s\n"
- " /Parent %d 0 R\n",
- outline->res.id,
- name,
- outline->parent->res.id);
- free (name);
-
- if (outline->prev) {
- _cairo_output_stream_printf (surface->output,
- " /Prev %d 0 R\n",
- outline->prev->res.id);
- }
-
- if (outline->next) {
- _cairo_output_stream_printf (surface->output,
- " /Next %d 0 R\n",
- outline->next->res.id);
- }
-
- if (outline->first_child) {
- _cairo_output_stream_printf (surface->output,
- " /First %d 0 R\n"
- " /Last %d 0 R\n"
- " /Count %d\n",
- outline->first_child->res.id,
- outline->last_child->res.id,
- outline->count);
- }
-
- if (outline->flags) {
- int flags = 0;
- if (outline->flags & CAIRO_PDF_OUTLINE_FLAG_ITALIC)
- flags |= 1;
- if (outline->flags & CAIRO_PDF_OUTLINE_FLAG_BOLD)
- flags |= 2;
- _cairo_output_stream_printf (surface->output,
- " /F %d\n",
- flags);
- }
-
- status = cairo_pdf_interchange_write_link_action (surface, &outline->link_attrs);
- if (unlikely (status))
- return status;
-
- _cairo_output_stream_printf (surface->output,
- ">>\n"
- "endobj\n");
- }
-
- 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) {
- char *s;
- s = _cairo_malloc (i + 1);
- if (!s)
- return NULL;
-
- memcpy (s, label, i);
- s[i] = 0;
- return s;
- }
-
- 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;
- cairo_bool_t has_labels;
-
- /* Check if any labels defined */
- num_elems = _cairo_array_num_elements (&surface->page_labels);
- has_labels = FALSE;
- for (i = 0; i < num_elems; i++) {
- _cairo_array_copy_element (&surface->page_labels, i, &label);
- if (label) {
- has_labels = TRUE;
- break;
- }
- }
-
- if (!has_labels)
- return CAIRO_STATUS_SUCCESS;
-
- 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)
-{
- 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;
-}
-
-static int
-_dest_compare (const void *a, const void *b)
-{
- const cairo_pdf_named_dest_t * const *dest_a = a;
- const cairo_pdf_named_dest_t * const *dest_b = b;
-
- return strcmp ((*dest_a)->attrs.name, (*dest_b)->attrs.name);
-}
-
-static cairo_int_status_t
-_cairo_pdf_interchange_write_document_dests (cairo_pdf_surface_t *surface)
-{
- int i;
- cairo_pdf_interchange_t *ic = &surface->interchange;
-
- if (ic->num_dests == 0) {
- ic->dests_res.id = 0;
- return CAIRO_STATUS_SUCCESS;
- }
-
- ic->sorted_dests = calloc (ic->num_dests, sizeof (cairo_pdf_named_dest_t *));
- if (unlikely (ic->sorted_dests == NULL))
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
- ic->num_dests = 0;
- _cairo_hash_table_foreach (ic->named_dests, _collect_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);
- _cairo_output_stream_printf (surface->output,
- "%d 0 obj\n"
- "<< /Names [\n",
- ic->dests_res.id);
- for (i = 0; i < ic->num_dests; i++) {
- cairo_pdf_named_dest_t *dest = ic->sorted_dests[i];
- cairo_pdf_resource_t page_res;
- double x = 0;
- double y = 0;
- double height;
-
- if (dest->attrs.internal)
- continue;
-
- if (dest->extents.valid) {
- x = dest->extents.extents.x;
- y = dest->extents.extents.y;
- }
-
- if (dest->attrs.x_valid)
- x = dest->attrs.x;
-
- if (dest->attrs.y_valid)
- y = dest->attrs.y;
-
- _cairo_array_copy_element (&surface->pages, dest->page - 1, &page_res);
- _cairo_array_copy_element (&surface->page_heights, dest->page - 1, &height);
- _cairo_output_stream_printf (surface->output,
- " (%s) [%d 0 R /XYZ %f %f 0]\n",
- dest->attrs.name,
- page_res.id,
- x,
- height - y);
- }
- _cairo_output_stream_printf (surface->output,
- " ]\n"
- ">>\n"
- "endobj\n");
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_int_status_t
-cairo_pdf_interchange_write_names_dict (cairo_pdf_surface_t *surface)
-{
- cairo_pdf_interchange_t *ic = &surface->interchange;
- cairo_int_status_t status;
-
- status = _cairo_pdf_interchange_write_document_dests (surface);
- if (unlikely (status))
- return status;
-
- surface->names_dict_res.id = 0;
- if (ic->dests_res.id != 0) {
- surface->names_dict_res = _cairo_pdf_surface_new_object (surface);
- _cairo_output_stream_printf (surface->output,
- "%d 0 obj\n"
- "<< /Dests %d 0 R >>\n"
- "endobj\n",
- surface->names_dict_res.id,
- ic->dests_res.id);
- }
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_int_status_t
-cairo_pdf_interchange_write_docinfo (cairo_pdf_surface_t *surface)
-{
- cairo_pdf_interchange_t *ic = &surface->interchange;
-
- surface->docinfo_res = _cairo_pdf_surface_new_object (surface);
- if (surface->docinfo_res.id == 0)
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
- _cairo_output_stream_printf (surface->output,
- "%d 0 obj\n"
- "<< /Producer (cairo %s (https://cairographics.org))\n",
- surface->docinfo_res.id,
- cairo_version_string ());
-
- if (ic->docinfo.title)
- _cairo_output_stream_printf (surface->output, " /Title %s\n", ic->docinfo.title);
-
- if (ic->docinfo.author)
- _cairo_output_stream_printf (surface->output, " /Author %s\n", ic->docinfo.author);
-
- if (ic->docinfo.subject)
- _cairo_output_stream_printf (surface->output, " /Subject %s\n", ic->docinfo.subject);
-
- if (ic->docinfo.keywords)
- _cairo_output_stream_printf (surface->output, " /Keywords %s\n", ic->docinfo.keywords);
-
- if (ic->docinfo.creator)
- _cairo_output_stream_printf (surface->output, " /Creator %s\n", ic->docinfo.creator);
-
- if (ic->docinfo.create_date)
- _cairo_output_stream_printf (surface->output, " /CreationDate %s\n", ic->docinfo.create_date);
-
- if (ic->docinfo.mod_date)
- _cairo_output_stream_printf (surface->output, " /ModDate %s\n", ic->docinfo.mod_date);
-
- _cairo_output_stream_printf (surface->output,
- ">>\n"
- "endobj\n");
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_int_status_t
-_cairo_pdf_interchange_begin_structure_tag (cairo_pdf_surface_t *surface,
- cairo_tag_type_t tag_type,
- const char *name,
- const char *attributes)
-{
- int page_num, mcid;
- cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
- cairo_pdf_interchange_t *ic = &surface->interchange;
-
- if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
- status = add_tree_node (surface, ic->current_node, name, &ic->current_node);
- if (unlikely (status))
- return status;
-
- _cairo_tag_stack_set_top_data (&ic->analysis_tag_stack, ic->current_node);
-
- if (tag_type & TAG_TYPE_LINK) {
- status = add_annotation (surface, ic->current_node, name, attributes);
- if (unlikely (status))
- return status;
-
- cairo_list_add_tail (&ic->current_node->extents.link, &ic->extents_list);
- }
-
- } else if (surface->paginated_mode == CAIRO_PAGINATED_MODE_RENDER) {
- ic->current_node = _cairo_tag_stack_top_elem (&ic->render_tag_stack)->data;
- assert (ic->current_node != NULL);
- if (is_leaf_node (ic->current_node)) {
- page_num = _cairo_array_num_elements (&surface->pages);
- add_mcid_to_node (surface, ic->current_node, page_num, &mcid);
- status = _cairo_pdf_operators_tag_begin (&surface->pdf_operators, name, mcid);
- }
- }
-
- return status;
-}
-
-static cairo_int_status_t
-_cairo_pdf_interchange_begin_dest_tag (cairo_pdf_surface_t *surface,
- cairo_tag_type_t tag_type,
- const char *name,
- const char *attributes)
-{
- cairo_pdf_named_dest_t *dest;
- cairo_pdf_interchange_t *ic = &surface->interchange;
- cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
-
- if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
- dest = calloc (1, sizeof (cairo_pdf_named_dest_t));
- if (unlikely (dest == NULL))
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
- status = _cairo_tag_parse_dest_attributes (attributes, &dest->attrs);
- if (unlikely (status))
- return status;
-
- dest->page = _cairo_array_num_elements (&surface->pages);
- init_named_dest_key (dest);
- status = _cairo_hash_table_insert (ic->named_dests, &dest->base);
- if (unlikely (status))
- return status;
-
- _cairo_tag_stack_set_top_data (&ic->analysis_tag_stack, dest);
- cairo_list_add_tail (&dest->extents.link, &ic->extents_list);
- ic->num_dests++;
- }
-
- return status;
-}
-
-cairo_int_status_t
-_cairo_pdf_interchange_tag_begin (cairo_pdf_surface_t *surface,
- const char *name,
- const char *attributes)
-{
- cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
- cairo_tag_type_t tag_type;
- cairo_pdf_interchange_t *ic = &surface->interchange;
- void *ptr;
-
- if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
- status = _cairo_tag_stack_push (&ic->analysis_tag_stack, name, attributes);
-
- } else if (surface->paginated_mode == CAIRO_PAGINATED_MODE_RENDER) {
- status = _cairo_tag_stack_push (&ic->render_tag_stack, name, attributes);
- _cairo_array_copy_element (&ic->push_data, ic->push_data_index++, &ptr);
- _cairo_tag_stack_set_top_data (&ic->render_tag_stack, ptr);
- }
-
- if (unlikely (status))
- return status;
-
- tag_type = _cairo_tag_get_type (name);
- if (tag_type & TAG_TYPE_STRUCTURE) {
- status = _cairo_pdf_interchange_begin_structure_tag (surface, tag_type, name, attributes);
- if (unlikely (status))
- return status;
- }
-
- if (tag_type & TAG_TYPE_DEST) {
- status = _cairo_pdf_interchange_begin_dest_tag (surface, tag_type, name, attributes);
- if (unlikely (status))
- return status;
- }
-
- if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
- ptr = _cairo_tag_stack_top_elem (&ic->analysis_tag_stack)->data;
- status = _cairo_array_append (&ic->push_data, &ptr);
- }
-
- return status;
-}
-
-static cairo_int_status_t
-_cairo_pdf_interchange_end_structure_tag (cairo_pdf_surface_t *surface,
- cairo_tag_type_t tag_type,
- cairo_tag_stack_elem_t *elem)
-{
- const cairo_pdf_struct_tree_node_t *node;
- struct tag_extents *tag, *next;
- cairo_pdf_interchange_t *ic = &surface->interchange;
- cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
-
- assert (elem->data != NULL);
- node = elem->data;
- if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
- if (tag_type & TAG_TYPE_LINK) {
- cairo_list_foreach_entry_safe (tag, next, struct tag_extents,
- &ic->extents_list, link) {
- if (tag == &node->extents) {
- cairo_list_del (&tag->link);
- break;
- }
- }
- }
- } else if (surface->paginated_mode == CAIRO_PAGINATED_MODE_RENDER) {
- if (is_leaf_node (ic->current_node)) {
- status = _cairo_pdf_operators_tag_end (&surface->pdf_operators);
- if (unlikely (status))
- return status;
- }
- }
-
- ic->current_node = ic->current_node->parent;
- assert (ic->current_node != NULL);
-
- return status;
-}
-
-static cairo_int_status_t
-_cairo_pdf_interchange_end_dest_tag (cairo_pdf_surface_t *surface,
- cairo_tag_type_t tag_type,
- cairo_tag_stack_elem_t *elem)
-{
- struct tag_extents *tag, *next;
- cairo_pdf_named_dest_t *dest;
- cairo_pdf_interchange_t *ic = &surface->interchange;
-
- if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
- assert (elem->data != NULL);
- dest = (cairo_pdf_named_dest_t *) elem->data;
- cairo_list_foreach_entry_safe (tag, next, struct tag_extents,
- &ic->extents_list, link) {
- if (tag == &dest->extents) {
- cairo_list_del (&tag->link);
- break;
- }
- }
- }
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_int_status_t
-_cairo_pdf_interchange_tag_end (cairo_pdf_surface_t *surface,
- const char *name)
-{
- cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
- cairo_pdf_interchange_t *ic = &surface->interchange;
- cairo_tag_type_t tag_type;
- cairo_tag_stack_elem_t *elem;
-
- if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
- status = _cairo_tag_stack_pop (&ic->analysis_tag_stack, name, &elem);
- else if (surface->paginated_mode == CAIRO_PAGINATED_MODE_RENDER)
- status = _cairo_tag_stack_pop (&ic->render_tag_stack, name, &elem);
-
- if (unlikely (status))
- return status;
-
- tag_type = _cairo_tag_get_type (name);
- if (tag_type & TAG_TYPE_STRUCTURE) {
- status = _cairo_pdf_interchange_end_structure_tag (surface, tag_type, elem);
- if (unlikely (status))
- goto cleanup;
- }
-
- if (tag_type & TAG_TYPE_DEST) {
- status = _cairo_pdf_interchange_end_dest_tag (surface, tag_type, elem);
- if (unlikely (status))
- goto cleanup;
- }
-
- cleanup:
- _cairo_tag_stack_free_elem (elem);
-
- return status;
-}
-
-cairo_int_status_t
-_cairo_pdf_interchange_add_operation_extents (cairo_pdf_surface_t *surface,
- const cairo_rectangle_int_t *extents)
-{
- cairo_pdf_interchange_t *ic = &surface->interchange;
- struct tag_extents *tag;
-
- if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
- cairo_list_foreach_entry (tag, struct tag_extents, &ic->extents_list, link) {
- if (tag->valid) {
- _cairo_rectangle_union (&tag->extents, extents);
- } else {
- tag->extents = *extents;
- tag->valid = TRUE;
- }
- }
- }
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_int_status_t
-_cairo_pdf_interchange_begin_page_content (cairo_pdf_surface_t *surface)
-{
- cairo_pdf_interchange_t *ic = &surface->interchange;
- cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
- int page_num, mcid;
-
- if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
- _cairo_array_truncate (&ic->mcid_to_tree, 0);
- _cairo_array_truncate (&ic->push_data, 0);
- ic->begin_page_node = ic->current_node;
- } else if (surface->paginated_mode == CAIRO_PAGINATED_MODE_RENDER) {
- ic->push_data_index = 0;
- ic->current_node = ic->begin_page_node;
- if (ic->end_page_node && is_leaf_node (ic->end_page_node)) {
- page_num = _cairo_array_num_elements (&surface->pages);
- add_mcid_to_node (surface, ic->end_page_node, page_num, &mcid);
- status = _cairo_pdf_operators_tag_begin (&surface->pdf_operators,
- ic->end_page_node->name,
- mcid);
- }
- }
-
- return status;
-}
-
-cairo_int_status_t
-_cairo_pdf_interchange_end_page_content (cairo_pdf_surface_t *surface)
-{
- cairo_pdf_interchange_t *ic = &surface->interchange;
- cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
-
- if (surface->paginated_mode == CAIRO_PAGINATED_MODE_RENDER) {
- ic->end_page_node = ic->current_node;
- if (is_leaf_node (ic->current_node))
- status = _cairo_pdf_operators_tag_end (&surface->pdf_operators);
- }
-
- return status;
-}
-
-cairo_int_status_t
-_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))
- return status;
-
- cairo_pdf_interchange_clear_annotations (surface);
-
- return cairo_pdf_interchange_write_page_parent_elems (surface);
-}
-
-cairo_int_status_t
-_cairo_pdf_interchange_write_document_objects (cairo_pdf_surface_t *surface)
-{
- cairo_pdf_interchange_t *ic = &surface->interchange;
- cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
- cairo_tag_stack_structure_type_t tag_type;
-
- tag_type = _cairo_tag_stack_get_structure_type (&ic->analysis_tag_stack);
- if (tag_type == TAG_TREE_TYPE_TAGGED || tag_type == TAG_TREE_TYPE_STRUCTURE) {
-
- status = cairo_pdf_interchange_write_parent_tree (surface);
- if (unlikely (status))
- return status;
-
- status = cairo_pdf_interchange_write_struct_tree (surface);
- if (unlikely (status))
- return status;
-
- if (tag_type == TAG_TREE_TYPE_TAGGED)
- surface->tagged = TRUE;
- }
-
- status = cairo_pdf_interchange_write_outline (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;
-
- status = cairo_pdf_interchange_write_docinfo (surface);
-
- return status;
-}
-
-static void
-_cairo_pdf_interchange_set_create_date (cairo_pdf_surface_t *surface)
-{
- time_t utc, local, offset;
- struct tm tm_local, tm_utc;
- char buf[50];
- int buf_size;
- char *p;
- cairo_pdf_interchange_t *ic = &surface->interchange;
-
- utc = time (NULL);
- localtime_r (&utc, &tm_local);
- strftime (buf, sizeof(buf), "(D:%Y%m%d%H%M%S", &tm_local);
-
- /* strftime "%z" is non standard and does not work on windows (it prints zone name, not offset).
- * Calculate time zone offset by comparing local and utc time_t values for the same time.
- */
- gmtime_r (&utc, &tm_utc);
- tm_utc.tm_isdst = tm_local.tm_isdst;
- local = mktime (&tm_utc);
- offset = difftime (utc, local);
-
- if (offset == 0) {
- strcat (buf, "Z");
- } else {
- if (offset > 0) {
- strcat (buf, "+");
- } else {
- strcat (buf, "-");
- offset = -offset;
- }
- p = buf + strlen (buf);
- buf_size = sizeof (buf) - strlen (buf);
- snprintf (p, buf_size, "%02d'%02d", (int)(offset/3600), (int)(offset%3600)/60);
- }
- strcat (buf, ")");
- ic->docinfo.create_date = strdup (buf);
-}
-
-cairo_int_status_t
-_cairo_pdf_interchange_init (cairo_pdf_surface_t *surface)
-{
- cairo_pdf_interchange_t *ic = &surface->interchange;
- cairo_pdf_outline_entry_t *outline_root;
- cairo_int_status_t status;
-
- _cairo_tag_stack_init (&ic->analysis_tag_stack);
- _cairo_tag_stack_init (&ic->render_tag_stack);
- _cairo_array_init (&ic->push_data, sizeof(void *));
- ic->struct_root = calloc (1, sizeof(cairo_pdf_struct_tree_node_t));
- if (unlikely (ic->struct_root == NULL))
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
- cairo_list_init (&ic->struct_root->children);
- _cairo_array_init (&ic->struct_root->mcid, sizeof(struct page_mcid));
- ic->current_node = ic->struct_root;
- ic->begin_page_node = NULL;
- ic->end_page_node = NULL;
- _cairo_array_init (&ic->parent_tree, sizeof(cairo_pdf_resource_t));
- _cairo_array_init (&ic->mcid_to_tree, sizeof(cairo_pdf_struct_tree_node_t *));
- _cairo_array_init (&ic->annots, sizeof(cairo_pdf_annotation_t *));
- ic->parent_tree_res.id = 0;
- cairo_list_init (&ic->extents_list);
- ic->named_dests = _cairo_hash_table_create (_named_dest_equal);
- if (unlikely (ic->named_dests == NULL))
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
- ic->num_dests = 0;
- ic->sorted_dests = NULL;
- ic->dests_res.id = 0;
-
- _cairo_array_init (&ic->outline, sizeof(cairo_pdf_outline_entry_t *));
- outline_root = calloc (1, sizeof(cairo_pdf_outline_entry_t));
- if (unlikely (outline_root == NULL))
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
- memset (&ic->docinfo, 0, sizeof (ic->docinfo));
- _cairo_pdf_interchange_set_create_date (surface);
- status = _cairo_array_append (&ic->outline, &outline_root);
-
- return status;
-}
-
-static void
-_cairo_pdf_interchange_free_outlines (cairo_pdf_surface_t *surface)
-{
- cairo_pdf_interchange_t *ic = &surface->interchange;
- int num_elems, i;
-
- num_elems = _cairo_array_num_elements (&ic->outline);
- for (i = 0; i < num_elems; i++) {
- cairo_pdf_outline_entry_t *outline;
-
- _cairo_array_copy_element (&ic->outline, i, &outline);
- free (outline->name);
- free (outline->link_attrs.dest);
- free (outline->link_attrs.uri);
- free (outline->link_attrs.file);
- free (outline);
- }
- _cairo_array_fini (&ic->outline);
-}
-
-cairo_int_status_t
-_cairo_pdf_interchange_fini (cairo_pdf_surface_t *surface)
-{
- cairo_pdf_interchange_t *ic = &surface->interchange;
-
- _cairo_tag_stack_fini (&ic->analysis_tag_stack);
- _cairo_tag_stack_fini (&ic->render_tag_stack);
- _cairo_array_fini (&ic->push_data);
- free_node (ic->struct_root);
- _cairo_array_fini (&ic->mcid_to_tree);
- cairo_pdf_interchange_clear_annotations (surface);
- _cairo_array_fini (&ic->annots);
- _cairo_array_fini (&ic->parent_tree);
- _cairo_hash_table_foreach (ic->named_dests, _named_dest_pluck, ic->named_dests);
- _cairo_hash_table_destroy (ic->named_dests);
- free (ic->sorted_dests);
- _cairo_pdf_interchange_free_outlines (surface);
- free (ic->docinfo.title);
- free (ic->docinfo.author);
- free (ic->docinfo.subject);
- free (ic->docinfo.keywords);
- free (ic->docinfo.creator);
- free (ic->docinfo.create_date);
- free (ic->docinfo.mod_date);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_int_status_t
-_cairo_pdf_interchange_add_outline (cairo_pdf_surface_t *surface,
- int parent_id,
- const char *name,
- const char *link_attribs,
- cairo_pdf_outline_flags_t flags,
- int *id)
-{
- cairo_pdf_interchange_t *ic = &surface->interchange;
- cairo_pdf_outline_entry_t *outline;
- cairo_pdf_outline_entry_t *parent;
- cairo_int_status_t status;
-
- if (parent_id < 0 || parent_id >= (int)_cairo_array_num_elements (&ic->outline))
- return CAIRO_STATUS_SUCCESS;
-
- outline = _cairo_malloc (sizeof(cairo_pdf_outline_entry_t));
- if (unlikely (outline == NULL))
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
- status = _cairo_tag_parse_link_attributes (link_attribs, &outline->link_attrs);
- if (unlikely (status)) {
- free (outline);
- return status;
- }
-
- outline->res = _cairo_pdf_surface_new_object (surface);
- if (outline->res.id == 0)
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
- outline->name = strdup (name);
- outline->flags = flags;
- outline->count = 0;
-
- _cairo_array_copy_element (&ic->outline, parent_id, &parent);
-
- outline->parent = parent;
- outline->first_child = NULL;
- outline->last_child = NULL;
- outline->next = NULL;
- if (parent->last_child) {
- parent->last_child->next = outline;
- outline->prev = parent->last_child;
- parent->last_child = outline;
- } else {
- parent->first_child = outline;
- parent->last_child = outline;
- outline->prev = NULL;
- }
-
- *id = _cairo_array_num_elements (&ic->outline);
- status = _cairo_array_append (&ic->outline, &outline);
- if (unlikely (status))
- return status;
-
- /* Update Count */
- outline = outline->parent;
- while (outline) {
- if (outline->flags & CAIRO_PDF_OUTLINE_FLAG_OPEN) {
- outline->count++;
- } else {
- outline->count--;
- break;
- }
- outline = outline->parent;
- }
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-/*
- * Date must be in the following format:
- *
- * YYYY-MM-DDThh:mm:ss[Z+-]hh:mm
- *
- * Only the year is required. If a field is included all preceding
- * fields must be included.
- */
-static char *
-iso8601_to_pdf_date_string (const char *iso)
-{
- char buf[40];
- const char *p;
- int i;
-
- /* Check that utf8 contains only the characters "0123456789-T:Z+" */
- p = iso;
- while (*p) {
- if (!_cairo_isdigit (*p) && *p != '-' && *p != 'T' &&
- *p != ':' && *p != 'Z' && *p != '+')
- return NULL;
- p++;
- }
-
- p = iso;
- strcpy (buf, "(");
-
- /* YYYY (required) */
- if (strlen (p) < 4)
- return NULL;
-
- strncat (buf, p, 4);
- p += 4;
-
- /* -MM, -DD, Thh, :mm, :ss */
- for (i = 0; i < 5; i++) {
- if (strlen (p) < 3)
- goto finish;
-
- strncat (buf, p + 1, 2);
- p += 3;
- }
-
- /* Z, +, - */
- if (strlen (p) < 1)
- goto finish;
- strncat (buf, p, 1);
- p += 1;
-
- /* hh */
- if (strlen (p) < 2)
- goto finish;
-
- strncat (buf, p, 2);
- strcat (buf, "'");
- p += 2;
-
- /* :mm */
- if (strlen (p) < 3)
- goto finish;
-
- strncat (buf, p + 1, 3);
-
- finish:
- strcat (buf, ")");
- return strdup (buf);
-}
-
-cairo_int_status_t
-_cairo_pdf_interchange_set_metadata (cairo_pdf_surface_t *surface,
- cairo_pdf_metadata_t metadata,
- const char *utf8)
-{
- cairo_pdf_interchange_t *ic = &surface->interchange;
- cairo_status_t status;
- char *s = NULL;
-
- if (utf8) {
- if (metadata == CAIRO_PDF_METADATA_CREATE_DATE ||
- metadata == CAIRO_PDF_METADATA_MOD_DATE) {
- s = iso8601_to_pdf_date_string (utf8);
- } else {
- status = _cairo_utf8_to_pdf_string (utf8, &s);
- if (unlikely (status))
- return status;
- }
- }
-
- switch (metadata) {
- case CAIRO_PDF_METADATA_TITLE:
- free (ic->docinfo.title);
- ic->docinfo.title = s;
- break;
- case CAIRO_PDF_METADATA_AUTHOR:
- free (ic->docinfo.author);
- ic->docinfo.author = s;
- break;
- case CAIRO_PDF_METADATA_SUBJECT:
- free (ic->docinfo.subject);
- ic->docinfo.subject = s;
- break;
- case CAIRO_PDF_METADATA_KEYWORDS:
- free (ic->docinfo.keywords);
- ic->docinfo.keywords = s;
- break;
- case CAIRO_PDF_METADATA_CREATOR:
- free (ic->docinfo.creator);
- ic->docinfo.creator = s;
- break;
- case CAIRO_PDF_METADATA_CREATE_DATE:
- free (ic->docinfo.create_date);
- ic->docinfo.create_date = s;
- break;
- case CAIRO_PDF_METADATA_MOD_DATE:
- free (ic->docinfo.mod_date);
- ic->docinfo.mod_date = s;
- break;
- }
-
- return CAIRO_STATUS_SUCCESS;
-}