diff options
author | sanine <sanine.not@pm.me> | 2023-02-12 23:53:22 -0600 |
---|---|---|
committer | sanine <sanine.not@pm.me> | 2023-02-12 23:53:22 -0600 |
commit | f1fe73d1909a2448a004a88362a1a532d0d4f7c3 (patch) | |
tree | ab37ae3837e2f858de2932bcee9f26e69fab3db1 /libs/cairo-1.16.0/src/cairo-pdf-interchange.c | |
parent | f567ea1e2798fd3156a416e61f083ea3e6b95719 (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.c | 1728 |
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; -} |