Coverage Report

Created: 2025-07-12 07:23

/src/cairo/src/cairo-pdf-interchange.c
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
2
/* cairo - a vector graphics library with display and print output
3
 *
4
 * Copyright © 2016 Adrian Johnson
5
 *
6
 * This library is free software; you can redistribute it and/or
7
 * modify it either under the terms of the GNU Lesser General Public
8
 * License version 2.1 as published by the Free Software Foundation
9
 * (the "LGPL") or, at your option, under the terms of the Mozilla
10
 * Public License Version 1.1 (the "MPL"). If you do not alter this
11
 * notice, a recipient may use your version of this file under either
12
 * the MPL or the LGPL.
13
 *
14
 * You should have received a copy of the LGPL along with this library
15
 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
16
 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
17
 * You should have received a copy of the MPL along with this library
18
 * in the file COPYING-MPL-1.1
19
 *
20
 * The contents of this file are subject to the Mozilla Public License
21
 * Version 1.1 (the "License"); you may not use this file except in
22
 * compliance with the License. You may obtain a copy of the License at
23
 * http://www.mozilla.org/MPL/
24
 *
25
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
26
 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
27
 * the specific language governing rights and limitations.
28
 *
29
 * The Original Code is the cairo graphics library.
30
 *
31
 * The Initial Developer of the Original Code is Adrian Johnson.
32
 *
33
 * Contributor(s):
34
 *  Adrian Johnson <ajohnson@redneon.com>
35
 */
36
37
38
/* PDF Document Interchange features:
39
 *  - metadata
40
 *  - document outline
41
 *  - tagged pdf
42
 *  - hyperlinks
43
 *  - page labels
44
 */
45
46
#define _DEFAULT_SOURCE /* for localtime_r(), gmtime_r(), snprintf(), strdup() */
47
#include "cairoint.h"
48
49
#include "cairo-pdf.h"
50
#include "cairo-pdf-surface-private.h"
51
52
#include "cairo-array-private.h"
53
#include "cairo-error-private.h"
54
#include "cairo-output-stream-private.h"
55
#include "cairo-recording-surface-inline.h"
56
#include "cairo-recording-surface-private.h"
57
#include "cairo-surface-snapshot-inline.h"
58
59
#include <time.h>
60
61
#ifndef HAVE_LOCALTIME_R
62
#define localtime_r(T, BUF) (*(BUF) = *localtime (T))
63
#endif
64
#ifndef HAVE_GMTIME_R
65
#define gmtime_r(T, BUF) (*(BUF) = *gmtime (T))
66
#endif
67
68
/* #define DEBUG_PDF_INTERCHANGE 1 */
69
70
#if DEBUG_PDF_INTERCHANGE
71
static void
72
print_tree (cairo_pdf_surface_t *surface, cairo_pdf_struct_tree_node_t *node);
73
74
static void
75
print_command (cairo_pdf_command_t *command, int indent);
76
77
static void
78
print_command_list(cairo_pdf_command_list_t *command_list);
79
#endif
80
81
static void
82
_cairo_pdf_command_init_key (cairo_pdf_command_entry_t *key)
83
0
{
84
0
    key->base.hash = _cairo_hash_uintptr (_CAIRO_HASH_INIT_VALUE, (uintptr_t)key->recording_id);
85
0
    key->base.hash = _cairo_hash_uintptr (key->base.hash, (uintptr_t)key->command_id);
86
0
}
87
88
static cairo_bool_t
89
_cairo_pdf_command_equal (const void *key_a, const void *key_b)
90
0
{
91
0
    const cairo_pdf_command_entry_t *a = key_a;
92
0
    const cairo_pdf_command_entry_t *b = key_b;
93
94
0
    return a->recording_id == b->recording_id && a->command_id == b->command_id;
95
0
}
96
97
static void
98
_cairo_pdf_command_pluck (void *entry, void *closure)
99
0
{
100
0
    cairo_pdf_command_entry_t *dest = entry;
101
0
    cairo_hash_table_t *table = closure;
102
103
0
    _cairo_hash_table_remove (table, &dest->base);
104
0
    free (dest);
105
0
}
106
107
static cairo_pdf_struct_tree_node_t *
108
lookup_node_for_command (cairo_pdf_surface_t    *surface,
109
       unsigned int            recording_id,
110
       unsigned int            command_id)
111
0
{
112
0
    cairo_pdf_command_entry_t entry_key;
113
0
    cairo_pdf_command_entry_t *entry;
114
0
    cairo_pdf_interchange_t *ic = &surface->interchange;
115
116
0
    entry_key.recording_id = recording_id;
117
0
    entry_key.command_id = command_id;
118
0
    _cairo_pdf_command_init_key (&entry_key);
119
0
    entry = _cairo_hash_table_lookup (ic->command_to_node_map, &entry_key.base);
120
0
    assert (entry != NULL);
121
0
    return entry->node;
122
0
}
123
124
static cairo_int_status_t
125
command_list_add (cairo_pdf_surface_t    *surface,
126
      unsigned int            command_id,
127
      cairo_pdf_operation_t   flags)
128
515k
{
129
515k
    cairo_pdf_interchange_t *ic = &surface->interchange;
130
515k
    cairo_pdf_command_t command;
131
515k
    cairo_int_status_t status;
132
133
515k
    unsigned num_elements = _cairo_array_num_elements (&ic->current_commands->commands);
134
515k
    if (command_id > num_elements) {
135
2.68k
  void *elements;
136
2.68k
  unsigned additional_elements = command_id - num_elements;
137
2.68k
  status = _cairo_array_allocate (&ic->current_commands->commands, additional_elements, &elements);
138
2.68k
  if (unlikely (status))
139
0
      return status;
140
2.68k
  memset (elements, 0, additional_elements * sizeof(cairo_pdf_command_t));
141
2.68k
    }
142
143
515k
    command.group = NULL;
144
515k
    command.node = NULL;
145
515k
    command.command_id = command_id;
146
515k
    command.mcid_index = 0;
147
515k
    command.flags = flags;
148
515k
    return _cairo_array_append (&ic->current_commands->commands, &command);
149
515k
}
150
151
static cairo_int_status_t
152
command_list_push_group (cairo_pdf_surface_t    *surface,
153
       unsigned int            command_id,
154
       cairo_surface_t        *recording_surface,
155
       unsigned int            region_id)
156
0
{
157
0
    cairo_pdf_interchange_t *ic = &surface->interchange;
158
0
    cairo_pdf_command_t *command;
159
0
    cairo_pdf_command_list_t *group;
160
0
    cairo_pdf_recording_surface_commands_t recording_commands;
161
0
    cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
162
163
0
    group = _cairo_calloc (sizeof(cairo_pdf_command_list_t));
164
0
    _cairo_array_init (&group->commands, sizeof(cairo_pdf_command_t));
165
0
    group->parent = ic->current_commands;
166
167
0
    command_list_add (surface, command_id, PDF_GROUP);
168
0
    command = _cairo_array_index (&ic->current_commands->commands, command_id);
169
0
    command->group = group;
170
0
    ic->current_commands = group;
171
172
0
    recording_commands.recording_surface = recording_surface;
173
0
    recording_commands.command_list = group;
174
0
    recording_commands.region_id = region_id;
175
0
    status = _cairo_array_append (&ic->recording_surface_commands, &recording_commands);
176
177
0
    return status;
178
0
}
179
180
static void
181
command_list_pop_group (cairo_pdf_surface_t    *surface)
182
0
{
183
0
    cairo_pdf_interchange_t *ic = &surface->interchange;
184
185
0
    ic->current_commands = ic->current_commands->parent;
186
0
}
187
188
static cairo_bool_t
189
command_list_is_group (cairo_pdf_surface_t    *surface,
190
           unsigned int            command_id)
191
0
{
192
0
    cairo_pdf_interchange_t *ic = &surface->interchange;
193
0
    cairo_pdf_command_t *command;
194
0
    unsigned num_elements = _cairo_array_num_elements (&ic->current_commands->commands);
195
196
0
    if (command_id >= num_elements)
197
0
  return FALSE;
198
199
0
    command = _cairo_array_index (&ic->current_commands->commands, command_id);
200
0
    return command->flags == PDF_GROUP;
201
0
}
202
203
204
/* Is there any content between current command and next
205
 * begin/end/group? */
206
static cairo_bool_t
207
command_list_has_content (cairo_pdf_surface_t    *surface,
208
        unsigned int            command_id,
209
        unsigned int           *content_command_id)
210
0
{
211
0
    cairo_pdf_interchange_t *ic = &surface->interchange;
212
0
    cairo_pdf_command_t *command;
213
0
    unsigned i;
214
0
    unsigned num_elements = _cairo_array_num_elements (&ic->current_commands->commands);
215
216
0
    for (i = command_id + 1; i < num_elements; i++) {
217
0
  command = _cairo_array_index (&ic->current_commands->commands, i);
218
0
  switch (command->flags) {
219
0
      case PDF_CONTENT:
220
0
    if (content_command_id)
221
0
        *content_command_id = i;
222
0
    return TRUE;
223
0
    break;
224
0
      case PDF_BEGIN:
225
0
      case PDF_END:
226
0
      case PDF_GROUP:
227
0
    return FALSE;
228
0
      case PDF_NONE:
229
0
    break;
230
0
  }
231
0
    }
232
0
    return FALSE;
233
0
}
234
235
static void
236
command_list_set_mcid (cairo_pdf_surface_t          *surface,
237
           unsigned int                  command_id,
238
           cairo_pdf_struct_tree_node_t *node,
239
           int                           mcid_index)
240
0
{
241
0
    cairo_pdf_interchange_t *ic = &surface->interchange;
242
0
    cairo_pdf_command_t *command;
243
244
0
    command = _cairo_array_index (&ic->current_commands->commands, command_id);
245
0
    command->node = node;
246
0
    command->mcid_index = mcid_index;
247
0
}
248
249
static void
250
command_list_set_current_recording_commands (cairo_pdf_surface_t    *surface,
251
               cairo_surface_t        *recording_surface,
252
               unsigned int            region_id)
253
0
{
254
0
    cairo_pdf_interchange_t *ic = &surface->interchange;
255
0
    unsigned i;
256
0
    cairo_pdf_recording_surface_commands_t *commands;
257
0
    unsigned num_elements = _cairo_array_num_elements (&ic->recording_surface_commands);
258
259
0
    for (i = 0; i < num_elements; i++) {
260
0
  commands = _cairo_array_index (&ic->recording_surface_commands, i);
261
0
  if (commands->region_id == region_id) {
262
0
      ic->current_commands = commands->command_list;
263
0
      return;
264
0
  }
265
0
    }
266
0
    ASSERT_NOT_REACHED; /* recording_surface not found */
267
0
}
268
269
static void
270
update_mcid_order (cairo_pdf_surface_t       *surface,
271
       cairo_pdf_command_list_t  *command_list)
272
0
{
273
0
    cairo_pdf_interchange_t *ic = &surface->interchange;
274
0
    cairo_pdf_command_t *command;
275
0
    cairo_pdf_page_mcid_t *mcid_elem;
276
0
    unsigned i;
277
0
    unsigned num_elements = _cairo_array_num_elements (&command_list->commands);
278
279
0
    for (i = 0; i < num_elements; i++) {
280
0
  command = _cairo_array_index (&command_list->commands, i);
281
0
  if (command->node) {
282
0
      mcid_elem = _cairo_array_index (&command->node->mcid, command->mcid_index);
283
0
      mcid_elem->order = ic->mcid_order++;
284
0
  }
285
286
0
  if (command->group)
287
0
      update_mcid_order (surface, command->group);
288
0
    }
289
0
}
290
291
static void
292
_cairo_pdf_content_tag_init_key (cairo_pdf_content_tag_t *key)
293
0
{
294
0
    key->base.hash = _cairo_hash_string (key->node->attributes.content.id);
295
0
}
296
297
static cairo_bool_t
298
_cairo_pdf_content_tag_equal (const void *key_a, const void *key_b)
299
0
{
300
0
    const cairo_pdf_content_tag_t *a = key_a;
301
0
    const cairo_pdf_content_tag_t *b = key_b;
302
303
0
    return strcmp (a->node->attributes.content.id, b->node->attributes.content.id) == 0;
304
0
}
305
306
static void
307
_cairo_pdf_content_tag_pluck (void *entry, void *closure)
308
0
{
309
0
    cairo_pdf_content_tag_t *content_tag = entry;
310
0
    cairo_hash_table_t *table = closure;
311
312
0
    _cairo_hash_table_remove (table, &content_tag->base);
313
0
    free (content_tag);
314
0
}
315
316
static cairo_status_t
317
lookup_content_node_for_ref_node (cairo_pdf_surface_t           *surface,
318
          cairo_pdf_struct_tree_node_t  *ref_node,
319
          cairo_pdf_struct_tree_node_t **node)
320
0
{
321
0
    cairo_pdf_content_tag_t entry_key;
322
0
    cairo_pdf_content_tag_t *entry;
323
0
    cairo_pdf_interchange_t *ic = &surface->interchange;
324
325
0
    entry_key.node = ref_node;
326
0
    _cairo_pdf_content_tag_init_key (&entry_key);
327
0
    entry = _cairo_hash_table_lookup (ic->content_tag_map, &entry_key.base);
328
0
    if (!entry) {
329
0
  return _cairo_tag_error ("CONTENT_REF ref='%s' not found",
330
0
         ref_node->attributes.content_ref.ref);
331
0
    }
332
333
0
    *node = entry->node;
334
0
    return CAIRO_STATUS_SUCCESS;
335
0
}
336
337
static void
338
write_rect_to_pdf_quad_points (cairo_output_stream_t   *stream,
339
             const cairo_rectangle_t *rect,
340
             double                   surface_height)
341
0
{
342
0
    _cairo_output_stream_printf (stream,
343
0
         "%f %f %f %f %f %f %f %f",
344
0
         rect->x,
345
0
         surface_height - rect->y,
346
0
         rect->x + rect->width,
347
0
         surface_height - rect->y,
348
0
         rect->x + rect->width,
349
0
         surface_height - (rect->y + rect->height),
350
0
         rect->x,
351
0
         surface_height - (rect->y + rect->height));
352
0
}
353
354
static void
355
write_rect_int_to_pdf_bbox (cairo_output_stream_t       *stream,
356
          const cairo_rectangle_int_t *rect,
357
          double                       surface_height)
358
0
{
359
0
    _cairo_output_stream_printf (stream,
360
0
         "%d %f %d %f",
361
0
         rect->x,
362
0
         surface_height - (rect->y + rect->height),
363
0
         rect->x + rect->width,
364
0
         surface_height - rect->y);
365
0
}
366
367
static cairo_int_status_t
368
add_tree_node (cairo_pdf_surface_t           *surface,
369
         cairo_pdf_struct_tree_node_t  *parent,
370
         const char                    *name,
371
         const char                    *attributes,
372
         cairo_pdf_struct_tree_node_t **new_node)
373
0
{
374
0
    cairo_pdf_struct_tree_node_t *node;
375
0
    cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
376
377
0
    node = _cairo_calloc (sizeof(cairo_pdf_struct_tree_node_t));
378
0
    if (unlikely (node == NULL))
379
0
  return _cairo_error (CAIRO_STATUS_NO_MEMORY);
380
381
0
    node->name = strdup (name);
382
0
    node->res = _cairo_pdf_surface_new_object (surface);
383
0
    if (node->res.id == 0)
384
0
  return _cairo_error (CAIRO_STATUS_NO_MEMORY);
385
386
0
    node->parent = parent;
387
0
    cairo_list_init (&node->children);
388
0
    _cairo_array_init (&node->mcid, sizeof (cairo_pdf_page_mcid_t));
389
0
    node->annot = NULL;
390
0
    node->extents.valid = FALSE;
391
392
0
    cairo_list_add_tail (&node->link, &parent->children);
393
394
0
    if (strcmp (node->name, CAIRO_TAG_CONTENT) == 0) {
395
0
  node->type = PDF_NODE_CONTENT;
396
0
  status = _cairo_tag_parse_content_attributes (attributes, &node->attributes.content);
397
0
    } else if (strcmp (node->name, CAIRO_TAG_CONTENT_REF) == 0) {
398
0
  node->type = PDF_NODE_CONTENT_REF;
399
0
  status = _cairo_tag_parse_content_ref_attributes (attributes, &node->attributes.content_ref);
400
0
    } else if (strcmp (node->name, "Artifact") == 0) {
401
0
  node->type = PDF_NODE_ARTIFACT;
402
0
    } else {
403
0
  node->type = PDF_NODE_STRUCT;
404
0
    }
405
406
0
    *new_node = node;
407
0
    return status;
408
0
}
409
410
static void
411
free_node (cairo_pdf_struct_tree_node_t *node)
412
673
{
413
673
    cairo_pdf_struct_tree_node_t *child, *next;
414
415
673
    if (!node)
416
0
  return;
417
418
673
    cairo_list_foreach_entry_safe (child, next, cairo_pdf_struct_tree_node_t,
419
673
           &node->children,
420
673
           link)
421
0
    {
422
0
  cairo_list_del (&child->link);
423
0
  free_node (child);
424
0
    }
425
673
    free (node->name);
426
673
    _cairo_array_fini (&node->mcid);
427
673
    if (node->type == PDF_NODE_CONTENT)
428
0
  _cairo_tag_free_content_attributes (&node->attributes.content);
429
430
673
    if (node->type == PDF_NODE_CONTENT_REF)
431
0
  _cairo_tag_free_content_ref_attributes (&node->attributes.content_ref);
432
433
673
    free (node);
434
673
}
435
436
static cairo_status_t
437
add_mcid_to_node (cairo_pdf_surface_t          *surface,
438
      cairo_pdf_struct_tree_node_t *node,
439
      unsigned int                  command_id,
440
      int                          *mcid)
441
0
{
442
0
    cairo_pdf_page_mcid_t mcid_elem;
443
0
    cairo_int_status_t status;
444
0
    cairo_pdf_interchange_t *ic = &surface->interchange;
445
446
0
    status = _cairo_array_append (&ic->mcid_to_tree, &node);
447
0
    if (unlikely (status))
448
0
  return status;
449
450
0
    mcid_elem.order = -1;
451
0
    mcid_elem.page = _cairo_array_num_elements (&surface->pages);
452
0
    mcid_elem.xobject_res = ic->current_recording_surface_res;
453
0
    mcid_elem.mcid = _cairo_array_num_elements (&ic->mcid_to_tree) - 1;
454
0
    mcid_elem.child_node = NULL;
455
0
    command_list_set_mcid (surface, command_id, node, _cairo_array_num_elements (&node->mcid));
456
0
    *mcid = mcid_elem.mcid;
457
0
    return _cairo_array_append (&node->mcid, &mcid_elem);
458
0
}
459
460
static cairo_status_t
461
add_child_to_mcid_array (cairo_pdf_surface_t          *surface,
462
       cairo_pdf_struct_tree_node_t *node,
463
       unsigned int                  command_id,
464
       cairo_pdf_struct_tree_node_t *child)
465
0
{
466
0
    cairo_pdf_page_mcid_t mcid_elem;
467
468
0
    mcid_elem.order = -1;
469
0
    mcid_elem.page = 0;
470
0
    mcid_elem.xobject_res.id = 0;
471
0
    mcid_elem.mcid = 0;
472
0
    mcid_elem.child_node = child;
473
0
    command_list_set_mcid (surface, command_id, node, _cairo_array_num_elements (&node->mcid));
474
0
    return _cairo_array_append (&node->mcid, &mcid_elem);
475
0
}
476
477
static cairo_int_status_t
478
add_annotation (cairo_pdf_surface_t           *surface,
479
    cairo_pdf_struct_tree_node_t  *node,
480
    const char                    *name,
481
    const char                    *attributes)
482
0
{
483
0
    cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
484
0
    cairo_pdf_interchange_t *ic = &surface->interchange;
485
0
    cairo_pdf_annotation_t *annot;
486
487
0
    annot = _cairo_calloc (sizeof (cairo_pdf_annotation_t));
488
0
    if (unlikely (annot == NULL))
489
0
  return _cairo_error (CAIRO_STATUS_NO_MEMORY);
490
491
0
    status = _cairo_tag_parse_link_attributes (attributes, &annot->link_attrs);
492
0
    if (unlikely (status)) {
493
0
  free (annot);
494
0
  return status;
495
0
    }
496
497
0
    if (annot->link_attrs.link_page == 0)
498
0
  annot->link_attrs.link_page = _cairo_array_num_elements (&surface->pages);
499
500
0
    annot->node = node;
501
502
0
    annot->res = _cairo_pdf_surface_new_object (surface);
503
0
    if (annot->res.id == 0)
504
0
  return _cairo_error (CAIRO_STATUS_NO_MEMORY);
505
506
0
    node->annot = annot;
507
0
    status = _cairo_array_append (&ic->annots, &annot);
508
509
0
    return status;
510
0
}
511
512
static void
513
free_annotation (cairo_pdf_annotation_t *annot)
514
0
{
515
0
    _cairo_tag_free_link_attributes (&annot->link_attrs);
516
0
    free (annot);
517
0
}
518
519
static void
520
cairo_pdf_interchange_clear_annotations (cairo_pdf_surface_t *surface)
521
673
{
522
673
    cairo_pdf_interchange_t *ic = &surface->interchange;
523
673
    int num_elems, i;
524
525
673
    num_elems = _cairo_array_num_elements (&ic->annots);
526
673
    for (i = 0; i < num_elems; i++) {
527
0
  cairo_pdf_annotation_t * annot;
528
529
0
  _cairo_array_copy_element (&ic->annots, i, &annot);
530
0
  free_annotation (annot);
531
0
    }
532
673
    _cairo_array_truncate (&ic->annots, 0);
533
673
}
534
535
static void
536
cairo_pdf_interchange_write_node_mcid (cairo_pdf_surface_t            *surface,
537
               cairo_pdf_page_mcid_t          *mcid_elem,
538
               int                             page)
539
0
{
540
0
    cairo_pdf_page_info_t *page_info;
541
542
0
    page_info = _cairo_array_index (&surface->pages, mcid_elem->page - 1);
543
0
    if (mcid_elem->page == page && mcid_elem->xobject_res.id == 0) {
544
0
  _cairo_output_stream_printf (surface->object_stream.stream, "%d ", mcid_elem->mcid);
545
0
    } else {
546
0
  _cairo_output_stream_printf (surface->object_stream.stream,
547
0
             "\n       << /Type /MCR ");
548
0
  if (mcid_elem->page != page) {
549
0
      _cairo_output_stream_printf (surface->object_stream.stream,
550
0
           "/Pg %d 0 R ",
551
0
           page_info->page_res.id);
552
0
  }
553
0
  if (mcid_elem->xobject_res.id != 0) {
554
0
      _cairo_output_stream_printf (surface->object_stream.stream,
555
0
           "/Stm %d 0 R ",
556
0
           mcid_elem->xobject_res.id);
557
0
  }
558
0
  _cairo_output_stream_printf (surface->object_stream.stream,
559
0
             "/MCID %d >> ",
560
0
             mcid_elem->mcid);
561
0
    }
562
0
}
563
564
static int
565
_mcid_order_compare (const void *a,
566
         const void *b)
567
0
{
568
0
    const cairo_pdf_page_mcid_t *mcid_a = a;
569
0
    const cairo_pdf_page_mcid_t *mcid_b = b;
570
571
0
    if (mcid_a->order < mcid_b->order)
572
0
  return -1;
573
0
    else if (mcid_a->order > mcid_b->order)
574
0
  return 1;
575
0
    else
576
0
  return 0;
577
0
}
578
579
static cairo_int_status_t
580
cairo_pdf_interchange_write_node_object (cairo_pdf_surface_t            *surface,
581
           cairo_pdf_struct_tree_node_t   *node,
582
           int                             depth)
583
0
{
584
0
    cairo_pdf_page_mcid_t *mcid_elem, *child_mcid_elem;
585
0
    unsigned i, j, num_mcid;
586
0
    int first_page = 0;
587
0
    cairo_pdf_page_info_t *page_info;
588
0
    cairo_int_status_t status;
589
0
    cairo_bool_t has_children = FALSE;
590
591
    /* The Root node is written in cairo_pdf_interchange_write_struct_tree(). */
592
0
    if (!node->parent)
593
0
  return CAIRO_STATUS_SUCCESS;
594
595
0
    if (node->type == PDF_NODE_CONTENT ||
596
0
  node->type == PDF_NODE_CONTENT_REF ||
597
0
  node->type == PDF_NODE_ARTIFACT)
598
0
    {
599
0
  return CAIRO_STATUS_SUCCESS;
600
0
    }
601
602
0
    status = _cairo_pdf_surface_object_begin (surface, node->res);
603
0
    if (unlikely (status))
604
0
  return status;
605
606
0
    _cairo_output_stream_printf (surface->object_stream.stream,
607
0
         "<< /Type /StructElem\n"
608
0
         "   /S /%s\n"
609
0
         "   /P %d 0 R\n",
610
0
         node->name,
611
0
         node->parent->res.id);
612
613
    /* Write /K entry (children of this StructElem) */
614
0
    num_mcid = _cairo_array_num_elements (&node->mcid);
615
0
    if (num_mcid > 0 ) {
616
0
  _cairo_array_sort (&node->mcid, _mcid_order_compare);
617
  /* Find the first MCID element and use the page number to set /Pg */
618
0
  for (i = 0; i < num_mcid; i++) {
619
0
      mcid_elem = _cairo_array_index (&node->mcid, i);
620
0
      assert (mcid_elem->order != -1);
621
0
      if (mcid_elem->child_node) {
622
0
    if (mcid_elem->child_node->type == PDF_NODE_CONTENT_REF) {
623
0
        cairo_pdf_struct_tree_node_t *content_node;
624
0
        status = lookup_content_node_for_ref_node (surface, mcid_elem->child_node, &content_node);
625
0
        if (status)
626
0
      return status;
627
628
        /* CONTENT_REF will not have child nodes */
629
0
        if (_cairo_array_num_elements (&content_node->mcid) > 0) {
630
0
      child_mcid_elem = _cairo_array_index (&content_node->mcid, 0);
631
0
      first_page = child_mcid_elem->page;
632
0
      page_info = _cairo_array_index (&surface->pages, first_page - 1);
633
0
      _cairo_output_stream_printf (surface->object_stream.stream,
634
0
                 "   /Pg %d 0 R\n",
635
0
                 page_info->page_res.id);
636
0
      has_children = TRUE;
637
0
      break;
638
0
        }
639
0
    } else {
640
0
        has_children = TRUE;
641
0
    }
642
0
      } else {
643
0
    first_page = mcid_elem->page;
644
0
    page_info = _cairo_array_index (&surface->pages, first_page - 1);
645
0
    _cairo_output_stream_printf (surface->object_stream.stream,
646
0
               "   /Pg %d 0 R\n",
647
0
               page_info->page_res.id);
648
0
    has_children = TRUE;
649
0
    break;
650
0
      }
651
0
  }
652
653
0
  if (has_children || node->annot) {
654
0
      _cairo_output_stream_printf (surface->object_stream.stream, "   /K ");
655
656
0
      if (num_mcid > 1 || node->annot)
657
0
    _cairo_output_stream_printf (surface->object_stream.stream, "[ ");
658
659
0
      for (i = 0; i < num_mcid; i++) {
660
0
    if (node->annot) {
661
0
        if (node->annot->link_attrs.link_page != first_page) {
662
0
      page_info = _cairo_array_index (&surface->pages, node->annot->link_attrs.link_page - 1);
663
0
      _cairo_output_stream_printf (surface->object_stream.stream,
664
0
                 "<< /Type /OBJR /Pg %d 0 R /Obj %d 0 R >> ",
665
0
                 page_info->page_res.id,
666
0
                 node->annot->res.id);
667
0
        } else {
668
0
      _cairo_output_stream_printf (surface->object_stream.stream,
669
0
                 "<< /Type /OBJR /Obj %d 0 R >> ",
670
0
                 node->annot->res.id);
671
0
        }
672
0
    }
673
0
    mcid_elem = _cairo_array_index (&node->mcid, i);
674
0
    if (mcid_elem->child_node) {
675
0
        if (mcid_elem->child_node->type == PDF_NODE_CONTENT_REF) {
676
0
      cairo_pdf_struct_tree_node_t *content_node;
677
0
      status = lookup_content_node_for_ref_node (surface, mcid_elem->child_node, &content_node);
678
0
      if (status)
679
0
          return status;
680
681
0
      assert (content_node->type == PDF_NODE_CONTENT);
682
683
      /* CONTENT_REF will not have child nodes */
684
0
      for (j = 0; j < _cairo_array_num_elements (&content_node->mcid); j++) {
685
0
          child_mcid_elem = _cairo_array_index (&content_node->mcid, j);
686
0
          cairo_pdf_interchange_write_node_mcid (surface, child_mcid_elem, first_page);
687
0
      }
688
0
        } else if (mcid_elem->child_node->type != PDF_NODE_CONTENT) {
689
0
      _cairo_output_stream_printf (surface->object_stream.stream,
690
0
                 " %d 0 R ",
691
0
                 mcid_elem->child_node->res.id);
692
0
        }
693
0
    } else {
694
0
        cairo_pdf_interchange_write_node_mcid (surface, mcid_elem, first_page);
695
0
    }
696
0
      }
697
698
0
      if (num_mcid > 1 || node->annot)
699
0
    _cairo_output_stream_printf (surface->object_stream.stream, "]");
700
0
  }
701
702
0
  _cairo_output_stream_printf (surface->object_stream.stream, "\n");
703
0
    }
704
705
0
    _cairo_output_stream_printf (surface->object_stream.stream,
706
0
         ">>\n");
707
708
0
    _cairo_pdf_surface_object_end (surface);
709
710
0
    return _cairo_output_stream_get_status (surface->object_stream.stream);
711
0
}
712
713
static void
714
init_named_dest_key (cairo_pdf_named_dest_t *dest)
715
0
{
716
0
    dest->base.hash = _cairo_hash_bytes (_CAIRO_HASH_INIT_VALUE,
717
0
           dest->attrs.name,
718
0
           strlen (dest->attrs.name));
719
0
}
720
721
static cairo_bool_t
722
_named_dest_equal (const void *key_a, const void *key_b)
723
0
{
724
0
    const cairo_pdf_named_dest_t *a = key_a;
725
0
    const cairo_pdf_named_dest_t *b = key_b;
726
727
0
    return strcmp (a->attrs.name, b->attrs.name) == 0;
728
0
}
729
730
static void
731
_named_dest_pluck (void *entry, void *closure)
732
0
{
733
0
    cairo_pdf_named_dest_t *dest = entry;
734
0
    cairo_hash_table_t *table = closure;
735
736
0
    _cairo_hash_table_remove (table, &dest->base);
737
0
    _cairo_tag_free_dest_attributes (&dest->attrs);
738
0
    free (dest);
739
0
}
740
741
static cairo_int_status_t
742
cairo_pdf_interchange_write_explicit_dest (cairo_pdf_surface_t *surface,
743
                                          int                  page,
744
                                          cairo_bool_t         has_pos,
745
                                          double               x,
746
                                          double               y)
747
0
{
748
0
    cairo_pdf_page_info_t *page_info;
749
750
0
    page_info = _cairo_array_index (&surface->pages, page - 1);
751
752
0
    if (has_pos) {
753
0
       _cairo_output_stream_printf (surface->object_stream.stream,
754
0
                                    "[%d 0 R /XYZ %f %f 0]\n",
755
0
                                    page_info->page_res.id,
756
0
                                    x,
757
0
                                    page_info->height - y);
758
0
    } else {
759
0
       _cairo_output_stream_printf (surface->object_stream.stream,
760
0
                                    "[%d 0 R /XYZ null null 0]\n",
761
0
                                    page_info->page_res.id);
762
0
    }
763
764
0
    return CAIRO_STATUS_SUCCESS;
765
0
}
766
767
static cairo_int_status_t
768
cairo_pdf_interchange_write_dest (cairo_pdf_surface_t *surface,
769
          cairo_link_attrs_t  *link_attrs)
770
0
{
771
0
    cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
772
0
    cairo_pdf_interchange_t *ic = &surface->interchange;
773
774
    /* If the dest is known, emit an explicit dest */
775
0
    if (link_attrs->link_type == TAG_LINK_DEST_AND_URI || link_attrs->link_type == TAG_LINK_DEST) {
776
0
  cairo_pdf_named_dest_t key;
777
0
  cairo_pdf_named_dest_t *named_dest;
778
779
  /* check if we already have this dest */
780
0
  key.attrs.name = link_attrs->dest;
781
0
  init_named_dest_key (&key);
782
0
  named_dest = _cairo_hash_table_lookup (ic->named_dests, &key.base);
783
0
  if (named_dest) {
784
0
      double x = 0;
785
0
      double y = 0;
786
787
0
      if (named_dest->extents.valid) {
788
0
    x = named_dest->extents.extents.x;
789
0
    y = named_dest->extents.extents.y;
790
0
      }
791
792
0
      if (named_dest->attrs.x_valid)
793
0
    x = named_dest->attrs.x;
794
795
0
      if (named_dest->attrs.y_valid)
796
0
    y = named_dest->attrs.y;
797
798
0
      if (named_dest->attrs.internal) {
799
0
    _cairo_output_stream_printf (surface->object_stream.stream, "   /Dest ");
800
0
    status = cairo_pdf_interchange_write_explicit_dest (surface,
801
0
                    named_dest->page,
802
0
                    TRUE,
803
0
                    x, y);
804
0
      } else {
805
0
    char *name = NULL;
806
807
0
    status = _cairo_utf8_to_pdf_string (named_dest->attrs.name, &name);
808
0
    if (unlikely (status))
809
0
        return status;
810
811
0
    _cairo_output_stream_printf (surface->object_stream.stream, "   /Dest %s\n",
812
0
               name);
813
0
    free (name);
814
0
      }
815
0
      return status;
816
0
  }
817
  /* name does not exist */
818
0
  if (link_attrs->link_type == TAG_LINK_DEST_AND_URI) {
819
      /* Don't emit anything. The caller will fallback to emitting a URI destination. */
820
0
      return CAIRO_INT_STATUS_NOTHING_TO_DO;
821
0
  }
822
823
  /* Mising destination. Emit a "do nothing" dest that points to the same page and position. */
824
0
  _cairo_tag_warning ("Link to dest=\"%s\" not found", link_attrs->dest);
825
0
  _cairo_output_stream_printf (surface->object_stream.stream, "   /Dest ");
826
0
  status = cairo_pdf_interchange_write_explicit_dest (surface,
827
0
                  link_attrs->link_page,
828
0
                  FALSE,
829
0
                  0, 0);
830
0
  return status;
831
0
    }
832
833
    /* link_attrs->link_type == TAG_LINK_PAGE */
834
835
0
    if (link_attrs->page < 1)
836
0
  return _cairo_tag_error ("Link attribute: \"page=%d\" page must be >= 1", link_attrs->page);
837
838
0
    if (link_attrs->page > (int)_cairo_array_num_elements (&surface->pages))
839
0
  return _cairo_tag_error ("Link attribute: \"page=%d\" page exceeds page count (%d)",
840
0
         link_attrs->page, _cairo_array_num_elements (&surface->pages));
841
842
0
    _cairo_output_stream_printf (surface->object_stream.stream, "   /Dest ");
843
0
    return cairo_pdf_interchange_write_explicit_dest (surface,
844
0
                  link_attrs->page,
845
0
                  link_attrs->has_pos,
846
0
                  link_attrs->pos.x,
847
0
                  link_attrs->pos.y);
848
0
}
849
850
static cairo_int_status_t
851
_cairo_utf8_to_pdf_utf8_hexstring (const char *utf8, char **str_out)
852
0
{
853
0
    int i;
854
0
    int len;
855
0
    unsigned char *p;
856
0
    cairo_bool_t ascii;
857
0
    char *str;
858
0
    cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
859
860
0
    ascii = TRUE;
861
0
    p = (unsigned char *)utf8;
862
0
    len = 0;
863
0
    while (*p) {
864
0
  if (*p < 32 || *p > 126) {
865
0
      ascii = FALSE;
866
0
  }
867
0
  if (*p == '(' || *p == ')' || *p == '\\')
868
0
      len += 2;
869
0
  else
870
0
      len++;
871
0
  p++;
872
0
    }
873
874
0
    if (ascii) {
875
0
  str = _cairo_malloc (len + 3);
876
0
  if (str == NULL)
877
0
      return _cairo_error (CAIRO_STATUS_NO_MEMORY);
878
879
0
  str[0] = '(';
880
0
  p = (unsigned char *)utf8;
881
0
  i = 1;
882
0
  while (*p) {
883
0
      if (*p == '(' || *p == ')' || *p == '\\')
884
0
    str[i++] = '\\';
885
0
      str[i++] = *p;
886
0
      p++;
887
0
  }
888
0
  str[i++] = ')';
889
0
  str[i++] = 0;
890
0
    } else {
891
0
  str = _cairo_malloc (len*2 + 3);
892
0
  if (str == NULL)
893
0
      return _cairo_error (CAIRO_STATUS_NO_MEMORY);
894
895
0
  str[0] = '<';
896
0
  p = (unsigned char *)utf8;
897
0
  i = 1;
898
0
  while (*p) {
899
0
      if (*p == '\\') {
900
0
    snprintf(str + i, 3, "%02x", '\\');
901
0
    i += 2;
902
0
      }
903
0
      snprintf(str + i, 3, "%02x", *p);
904
0
      i += 2;
905
0
      p++;
906
0
  }
907
0
  str[i++] = '>';
908
0
  str[i++] = 0;
909
0
    }
910
0
    *str_out = str;
911
912
0
    return status;
913
0
}
914
915
static cairo_int_status_t
916
cairo_pdf_interchange_write_link_action (cairo_pdf_surface_t   *surface,
917
           cairo_link_attrs_t    *link_attrs)
918
0
{
919
0
    cairo_int_status_t status;
920
0
    char *dest = NULL;
921
922
0
    if (link_attrs->link_type == TAG_LINK_DEST_AND_URI ||
923
0
  link_attrs->link_type == TAG_LINK_DEST         ||
924
0
  link_attrs->link_type == TAG_LINK_PAGE)
925
0
    {
926
0
  status = cairo_pdf_interchange_write_dest (surface, link_attrs);
927
0
  if (status != CAIRO_INT_STATUS_NOTHING_TO_DO)
928
0
      return status;
929
930
  /* CAIRO_INT_STATUS_NOTHING_TO_DO means that the link type is TAG_LINK_DEST_AND_URI
931
   * and the DEST is missing. Fall through to writing a URI link below.
932
   */
933
0
    }
934
935
0
    if (link_attrs->link_type == TAG_LINK_URI || link_attrs->link_type == TAG_LINK_DEST_AND_URI) {
936
0
  status = _cairo_utf8_to_pdf_string (link_attrs->uri, &dest);
937
0
  if (unlikely (status))
938
0
      return status;
939
940
0
  if (dest[0] != '(') {
941
0
      free (dest);
942
0
      return _cairo_tag_error ("Link attribute: \"url=%s\" URI may only contain ASCII characters",
943
0
             link_attrs->uri);
944
0
  }
945
946
0
  _cairo_output_stream_printf (surface->object_stream.stream,
947
0
             "   /A <<\n"
948
0
             "      /Type /Action\n"
949
0
             "      /S /URI\n"
950
0
             "      /URI %s\n"
951
0
             "   >>\n",
952
0
             dest);
953
0
  free (dest);
954
0
    } else if (link_attrs->link_type == TAG_LINK_FILE) {
955
  /* According to "Developing with PDF", Leonard Rosenthol, 2013,
956
   * The F key is encoded in the "standard encoding for the
957
   * platform on which the document is being viewed. For most
958
   * modern operating systems, that's UTF-8"
959
   *
960
   * As we don't know the target platform, we assume UTF-8. The
961
   * F key may contain multi-byte encodings using the hex
962
   * encoding.
963
   *
964
   * For PDF 1.7 we also include the UF key which uses the
965
   * standard PDF UTF-16BE strings.
966
   */
967
0
  status = _cairo_utf8_to_pdf_utf8_hexstring (link_attrs->file, &dest);
968
0
  if (unlikely (status))
969
0
      return status;
970
971
0
  _cairo_output_stream_printf (surface->object_stream.stream,
972
0
             "   /A <<\n"
973
0
             "      /Type /Action\n"
974
0
             "      /S /GoToR\n"
975
0
             "      /F %s\n",
976
0
             dest);
977
0
  free (dest);
978
979
0
  if (surface->pdf_version >= CAIRO_PDF_VERSION_1_7)
980
0
  {
981
0
      status = _cairo_utf8_to_pdf_string (link_attrs->file, &dest);
982
0
      if (unlikely (status))
983
0
    return status;
984
985
0
      _cairo_output_stream_printf (surface->object_stream.stream,
986
0
             "      /UF %s\n",
987
0
             dest);
988
0
      free (dest);
989
0
  }
990
991
0
  if (link_attrs->dest) {
992
0
      status = _cairo_utf8_to_pdf_string (link_attrs->dest, &dest);
993
0
      if (unlikely (status))
994
0
    return status;
995
996
0
      _cairo_output_stream_printf (surface->object_stream.stream,
997
0
           "      /D %s\n",
998
0
           dest);
999
0
      free (dest);
1000
0
  } else {
1001
0
      if (link_attrs->has_pos) {
1002
0
    _cairo_output_stream_printf (surface->object_stream.stream,
1003
0
               "      /D [%d /XYZ %f %f 0]\n",
1004
0
               link_attrs->page,
1005
0
               link_attrs->pos.x,
1006
0
               link_attrs->pos.y);
1007
0
      } else {
1008
0
    _cairo_output_stream_printf (surface->object_stream.stream,
1009
0
               "      /D [%d /XYZ null null 0]\n",
1010
0
               link_attrs->page);
1011
0
      }
1012
0
  }
1013
0
  _cairo_output_stream_printf (surface->object_stream.stream,
1014
0
             "   >>\n");
1015
0
    }
1016
1017
0
    return CAIRO_STATUS_SUCCESS;
1018
0
}
1019
1020
static cairo_int_status_t
1021
cairo_pdf_interchange_write_annot (cairo_pdf_surface_t    *surface,
1022
           cairo_pdf_annotation_t *annot,
1023
           cairo_bool_t            struct_parents)
1024
0
{
1025
0
    cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
1026
0
    cairo_pdf_interchange_t *ic = &surface->interchange;
1027
0
    cairo_pdf_struct_tree_node_t *node = annot->node;
1028
0
    int sp;
1029
0
    int i, num_rects;
1030
0
    double height;
1031
1032
0
    num_rects = _cairo_array_num_elements (&annot->link_attrs.rects);
1033
0
    if (strcmp (node->name, CAIRO_TAG_LINK) == 0 &&
1034
0
  annot->link_attrs.link_type != TAG_LINK_EMPTY &&
1035
0
  (node->extents.valid || num_rects > 0))
1036
0
    {
1037
0
  status = _cairo_array_append (&ic->parent_tree, &node->res);
1038
0
  if (unlikely (status))
1039
0
      return status;
1040
1041
0
  sp = _cairo_array_num_elements (&ic->parent_tree) - 1;
1042
1043
0
  status = _cairo_pdf_surface_object_begin (surface, annot->res);
1044
0
  if (unlikely (status))
1045
0
      return status;
1046
1047
0
  _cairo_output_stream_printf (surface->object_stream.stream,
1048
0
             "<< /Type /Annot\n"
1049
0
             "   /Subtype /Link\n");
1050
1051
0
  if (struct_parents) {
1052
0
      _cairo_output_stream_printf (surface->object_stream.stream,
1053
0
           "   /StructParent %d\n",
1054
0
           sp);
1055
0
  }
1056
1057
0
  height = surface->height;
1058
0
  if (num_rects > 0) {
1059
0
      cairo_rectangle_int_t bbox_rect;
1060
1061
0
      _cairo_output_stream_printf (surface->object_stream.stream,
1062
0
           "   /QuadPoints [ ");
1063
0
      for (i = 0; i < num_rects; i++) {
1064
0
    cairo_rectangle_t rectf;
1065
0
    cairo_rectangle_int_t recti;
1066
1067
0
    _cairo_array_copy_element (&annot->link_attrs.rects, i, &rectf);
1068
0
    _cairo_rectangle_int_from_double (&recti, &rectf);
1069
0
    if (i == 0)
1070
0
        bbox_rect = recti;
1071
0
    else
1072
0
        _cairo_rectangle_union (&bbox_rect, &recti);
1073
1074
0
    write_rect_to_pdf_quad_points (surface->object_stream.stream, &rectf, height);
1075
0
    _cairo_output_stream_printf (surface->object_stream.stream, " ");
1076
0
      }
1077
0
      _cairo_output_stream_printf (surface->object_stream.stream,
1078
0
           "]\n"
1079
0
           "   /Rect [ ");
1080
0
      write_rect_int_to_pdf_bbox (surface->object_stream.stream, &bbox_rect, height);
1081
0
      _cairo_output_stream_printf (surface->object_stream.stream, " ]\n");
1082
0
  } else {
1083
0
      _cairo_output_stream_printf (surface->object_stream.stream,
1084
0
           "   /Rect [ ");
1085
0
      write_rect_int_to_pdf_bbox (surface->object_stream.stream, &node->extents.extents, height);
1086
0
      _cairo_output_stream_printf (surface->object_stream.stream, " ]\n");
1087
0
  }
1088
1089
0
  status = cairo_pdf_interchange_write_link_action (surface, &annot->link_attrs);
1090
0
  if (unlikely (status))
1091
0
      return status;
1092
1093
0
  _cairo_output_stream_printf (surface->object_stream.stream,
1094
0
             "   /BS << /W 0 >>\n"
1095
0
             ">>\n");
1096
1097
0
  _cairo_pdf_surface_object_end (surface);
1098
0
  status = _cairo_output_stream_get_status (surface->object_stream.stream);
1099
0
    }
1100
1101
0
    return status;
1102
0
}
1103
1104
static cairo_int_status_t
1105
cairo_pdf_interchange_walk_struct_tree (cairo_pdf_surface_t          *surface,
1106
          cairo_pdf_struct_tree_node_t *node,
1107
          int                           depth,
1108
          cairo_int_status_t (*func) (cairo_pdf_surface_t          *surface,
1109
                    cairo_pdf_struct_tree_node_t *node,
1110
                                      int                           depth))
1111
669
{
1112
669
    cairo_int_status_t status;
1113
669
    cairo_pdf_struct_tree_node_t *child;
1114
1115
669
    status = func (surface, node, depth);
1116
669
    if (unlikely (status))
1117
0
  return status;
1118
1119
669
    depth++;
1120
669
    cairo_list_foreach_entry (child, cairo_pdf_struct_tree_node_t,
1121
669
            &node->children, link)
1122
0
    {
1123
0
  status = cairo_pdf_interchange_walk_struct_tree (surface, child, depth, func);
1124
0
  if (unlikely (status))
1125
0
      return status;
1126
0
    }
1127
669
    depth--;
1128
1129
669
    return CAIRO_STATUS_SUCCESS;
1130
669
}
1131
1132
static cairo_int_status_t
1133
cairo_pdf_interchange_write_struct_tree (cairo_pdf_surface_t *surface)
1134
0
{
1135
0
    cairo_pdf_interchange_t *ic = &surface->interchange;
1136
0
    cairo_pdf_struct_tree_node_t *child;
1137
0
    cairo_int_status_t status;
1138
1139
0
    if (cairo_list_is_empty (&ic->struct_root->children))
1140
0
  return CAIRO_STATUS_SUCCESS;
1141
1142
0
    status = cairo_pdf_interchange_walk_struct_tree (surface,
1143
0
                 ic->struct_root,
1144
0
                 0,
1145
0
                 cairo_pdf_interchange_write_node_object);
1146
0
    if (unlikely (status))
1147
0
  return status;
1148
1149
0
    status = _cairo_pdf_surface_object_begin (surface, surface->struct_tree_root);
1150
0
    if (unlikely (status))
1151
0
  return status;
1152
1153
0
    _cairo_output_stream_printf (surface->object_stream.stream,
1154
0
         "<< /Type /StructTreeRoot\n"
1155
0
         "   /ParentTree %d 0 R\n",
1156
0
         ic->parent_tree_res.id);
1157
1158
0
    if (cairo_list_is_singular (&ic->struct_root->children)) {
1159
0
  child = cairo_list_first_entry (&ic->struct_root->children, cairo_pdf_struct_tree_node_t, link);
1160
0
  _cairo_output_stream_printf (surface->object_stream.stream, "   /K [ %d 0 R ]\n", child->res.id);
1161
0
    } else {
1162
0
  _cairo_output_stream_printf (surface->object_stream.stream, "   /K [ ");
1163
1164
0
  cairo_list_foreach_entry (child, cairo_pdf_struct_tree_node_t,
1165
0
          &ic->struct_root->children, link)
1166
0
  {
1167
0
      if (child->type == PDF_NODE_CONTENT || child->type == PDF_NODE_ARTIFACT)
1168
0
    continue;
1169
1170
0
      _cairo_output_stream_printf (surface->object_stream.stream, "%d 0 R ", child->res.id);
1171
0
  }
1172
0
  _cairo_output_stream_printf (surface->object_stream.stream, "]\n");
1173
0
    }
1174
1175
0
    _cairo_output_stream_printf (surface->object_stream.stream,
1176
0
         ">>\n");
1177
0
    _cairo_pdf_surface_object_end (surface);
1178
1179
0
    return CAIRO_STATUS_SUCCESS;
1180
0
}
1181
1182
static cairo_int_status_t
1183
cairo_pdf_interchange_write_annots (cairo_pdf_surface_t *surface,
1184
            cairo_bool_t         struct_parents)
1185
669
{
1186
669
    cairo_pdf_interchange_t *ic = &surface->interchange;
1187
669
    int num_elems, i, page_num;
1188
669
    cairo_pdf_page_info_t *page_info;
1189
669
    cairo_pdf_annotation_t *annot;
1190
669
    cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
1191
1192
669
    num_elems = _cairo_array_num_elements (&ic->annots);
1193
669
    for (i = 0; i < num_elems; i++) {
1194
0
  _cairo_array_copy_element (&ic->annots, i, &annot);
1195
0
  page_num = annot->link_attrs.link_page;
1196
0
  if (page_num > (int)_cairo_array_num_elements (&surface->pages)) {
1197
0
      return _cairo_tag_error ("Link attribute: \"link_page=%d\" page exceeds page count (%d)",
1198
0
             page_num,
1199
0
             _cairo_array_num_elements (&surface->pages));
1200
0
  }
1201
1202
0
  page_info = _cairo_array_index (&surface->pages, page_num - 1);
1203
0
  status = _cairo_array_append (&page_info->annots, &annot->res);
1204
0
  if (status)
1205
0
      return status;
1206
1207
0
  status = cairo_pdf_interchange_write_annot (surface, annot, struct_parents);
1208
0
  if (unlikely (status))
1209
0
      return status;
1210
0
    }
1211
1212
669
    return status;
1213
669
}
1214
1215
static cairo_int_status_t
1216
cairo_pdf_interchange_write_content_parent_elems (cairo_pdf_surface_t *surface)
1217
2.02k
{
1218
2.02k
    int num_elems, i;
1219
2.02k
    cairo_pdf_struct_tree_node_t *node;
1220
2.02k
    cairo_pdf_interchange_t *ic = &surface->interchange;
1221
2.02k
    cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
1222
1223
2.02k
    num_elems = _cairo_array_num_elements (&ic->mcid_to_tree);
1224
2.02k
    status = _cairo_pdf_surface_object_begin (surface, ic->content_parent_res);
1225
2.02k
    if (unlikely (status))
1226
0
  return status;
1227
1228
2.02k
    _cairo_output_stream_printf (surface->object_stream.stream,
1229
2.02k
             "[\n");
1230
2.02k
    for (i = 0; i < num_elems; i++) {
1231
0
  _cairo_array_copy_element (&ic->mcid_to_tree, i, &node);
1232
0
  _cairo_output_stream_printf (surface->object_stream.stream, "  %d 0 R\n", node->res.id);
1233
0
    }
1234
2.02k
    _cairo_output_stream_printf (surface->object_stream.stream,
1235
2.02k
         "]\n");
1236
2.02k
    _cairo_pdf_surface_object_end (surface);
1237
1238
2.02k
    return status;
1239
2.02k
}
1240
1241
static cairo_int_status_t
1242
cairo_pdf_interchange_apply_extents_from_content_ref (cairo_pdf_surface_t            *surface,
1243
                  cairo_pdf_struct_tree_node_t   *node,
1244
                  int                             depth)
1245
669
{
1246
669
    cairo_int_status_t status;
1247
1248
669
    if (node->type != PDF_NODE_CONTENT_REF)
1249
669
  return CAIRO_STATUS_SUCCESS;
1250
1251
0
    cairo_pdf_struct_tree_node_t *content_node;
1252
0
    status = lookup_content_node_for_ref_node (surface, node, &content_node);
1253
0
    if (status)
1254
0
  return status;
1255
1256
    /* Merge extents with all parent nodes */
1257
0
    node = node->parent;
1258
0
    while (node) {
1259
0
  if (node->extents.valid) {
1260
0
      _cairo_rectangle_union (&node->extents.extents, &content_node->extents.extents);
1261
0
  } else {
1262
0
      node->extents = content_node->extents;
1263
0
  }
1264
0
  node = node->parent;
1265
0
    }
1266
1267
0
    return CAIRO_STATUS_SUCCESS;
1268
0
}
1269
1270
static cairo_int_status_t
1271
cairo_pdf_interchange_update_extents (cairo_pdf_surface_t *surface)
1272
669
{
1273
669
    cairo_pdf_interchange_t *ic = &surface->interchange;
1274
1275
669
    return cairo_pdf_interchange_walk_struct_tree (surface,
1276
669
               ic->struct_root,
1277
669
               0,
1278
669
               cairo_pdf_interchange_apply_extents_from_content_ref);
1279
669
}
1280
1281
static cairo_int_status_t
1282
cairo_pdf_interchange_write_parent_tree (cairo_pdf_surface_t *surface)
1283
0
{
1284
0
    int num_elems, i;
1285
0
    cairo_pdf_resource_t *res;
1286
0
    cairo_pdf_interchange_t *ic = &surface->interchange;
1287
0
    cairo_int_status_t status;
1288
1289
0
    num_elems = _cairo_array_num_elements (&ic->parent_tree);
1290
0
    if (num_elems > 0) {
1291
0
  ic->parent_tree_res = _cairo_pdf_surface_new_object (surface);
1292
0
  if (ic->parent_tree_res.id == 0)
1293
0
      return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1294
1295
0
  status = _cairo_pdf_surface_object_begin (surface, ic->parent_tree_res);
1296
0
  if (unlikely (status))
1297
0
      return status;
1298
1299
0
  _cairo_output_stream_printf (surface->object_stream.stream,
1300
0
             "<< /Nums [\n");
1301
0
  for (i = 0; i < num_elems; i++) {
1302
0
      res = _cairo_array_index (&ic->parent_tree, i);
1303
0
      if (res->id) {
1304
0
    _cairo_output_stream_printf (surface->object_stream.stream,
1305
0
               "   %d %d 0 R\n",
1306
0
               i,
1307
0
               res->id);
1308
0
      }
1309
0
  }
1310
0
  _cairo_output_stream_printf (surface->object_stream.stream,
1311
0
             "  ]\n"
1312
0
             ">>\n");
1313
0
  _cairo_pdf_surface_object_end (surface);
1314
0
    }
1315
1316
0
    return CAIRO_STATUS_SUCCESS;
1317
0
}
1318
1319
static cairo_int_status_t
1320
cairo_pdf_interchange_write_outline (cairo_pdf_surface_t *surface)
1321
669
{
1322
669
    int num_elems, i;
1323
669
    cairo_pdf_outline_entry_t *outline;
1324
669
    cairo_pdf_interchange_t *ic = &surface->interchange;
1325
669
    cairo_int_status_t status;
1326
669
    char *name = NULL;
1327
1328
669
    num_elems = _cairo_array_num_elements (&ic->outline);
1329
669
    if (num_elems < 2)
1330
669
  return CAIRO_INT_STATUS_SUCCESS;
1331
1332
0
    _cairo_array_copy_element (&ic->outline, 0, &outline);
1333
0
    outline->res = _cairo_pdf_surface_new_object (surface);
1334
0
    if (outline->res.id == 0)
1335
0
  return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1336
1337
0
    surface->outlines_dict_res = outline->res;
1338
0
    status = _cairo_pdf_surface_object_begin (surface, outline->res);
1339
0
    if (unlikely (status))
1340
0
  return status;
1341
1342
0
    _cairo_output_stream_printf (surface->object_stream.stream,
1343
0
         "<< /Type /Outlines\n"
1344
0
         "   /First %d 0 R\n"
1345
0
         "   /Last %d 0 R\n"
1346
0
         "   /Count %d\n"
1347
0
         ">>\n",
1348
0
         outline->first_child->res.id,
1349
0
         outline->last_child->res.id,
1350
0
         outline->count);
1351
0
    _cairo_pdf_surface_object_end (surface);
1352
1353
0
    for (i = 1; i < num_elems; i++) {
1354
0
  _cairo_array_copy_element (&ic->outline, i, &outline);
1355
0
  _cairo_pdf_surface_update_object (surface, outline->res);
1356
1357
0
  status = _cairo_utf8_to_pdf_string (outline->name, &name);
1358
0
  if (unlikely (status))
1359
0
      return status;
1360
1361
0
  status = _cairo_pdf_surface_object_begin (surface, outline->res);
1362
0
  if (unlikely (status))
1363
0
      return status;
1364
1365
0
  _cairo_output_stream_printf (surface->object_stream.stream,
1366
0
             "<< /Title %s\n"
1367
0
             "   /Parent %d 0 R\n",
1368
0
             name,
1369
0
             outline->parent->res.id);
1370
0
  free (name);
1371
1372
0
  if (outline->prev) {
1373
0
      _cairo_output_stream_printf (surface->object_stream.stream,
1374
0
           "   /Prev %d 0 R\n",
1375
0
           outline->prev->res.id);
1376
0
  }
1377
1378
0
  if (outline->next) {
1379
0
      _cairo_output_stream_printf (surface->object_stream.stream,
1380
0
           "   /Next %d 0 R\n",
1381
0
           outline->next->res.id);
1382
0
  }
1383
1384
0
  if (outline->first_child) {
1385
0
      _cairo_output_stream_printf (surface->object_stream.stream,
1386
0
           "   /First %d 0 R\n"
1387
0
           "   /Last %d 0 R\n"
1388
0
           "   /Count %d\n",
1389
0
           outline->first_child->res.id,
1390
0
           outline->last_child->res.id,
1391
0
           outline->count);
1392
0
  }
1393
1394
0
  if (outline->flags) {
1395
0
      int flags = 0;
1396
0
      if (outline->flags & CAIRO_PDF_OUTLINE_FLAG_ITALIC)
1397
0
    flags |= 1;
1398
0
      if (outline->flags & CAIRO_PDF_OUTLINE_FLAG_BOLD)
1399
0
    flags |= 2;
1400
0
      _cairo_output_stream_printf (surface->object_stream.stream,
1401
0
           "   /F %d\n",
1402
0
           flags);
1403
0
  }
1404
1405
0
  status = cairo_pdf_interchange_write_link_action (surface, &outline->link_attrs);
1406
0
  if (unlikely (status))
1407
0
      return status;
1408
1409
0
  _cairo_output_stream_printf (surface->object_stream.stream,
1410
0
             ">>\n");
1411
0
  _cairo_pdf_surface_object_end (surface);
1412
0
    }
1413
1414
0
    return status;
1415
0
}
1416
1417
/*
1418
 * Split a page label into a text prefix and numeric suffix. Leading '0's are
1419
 * included in the prefix. eg
1420
 *  "3"     => NULL,    3
1421
 *  "cover" => "cover", 0
1422
 *  "A-2"   => "A-",    2
1423
 *  "A-002" => "A-00",  2
1424
 */
1425
static char *
1426
split_label (const char* label, int *num)
1427
0
{
1428
0
    int len, i;
1429
1430
0
    *num = 0;
1431
0
    len = strlen (label);
1432
0
    if (len == 0)
1433
0
  return NULL;
1434
1435
0
    i = len;
1436
0
    while (i > 0 && _cairo_isdigit (label[i-1]))
1437
0
     i--;
1438
1439
0
    while (i < len && label[i] == '0')
1440
0
  i++;
1441
1442
0
    if (i < len)
1443
0
  sscanf (label + i, "%d", num);
1444
1445
0
    if (i > 0) {
1446
0
  char *s;
1447
0
  s = _cairo_malloc (i + 1);
1448
0
  if (!s)
1449
0
      return NULL;
1450
1451
0
  memcpy (s, label, i);
1452
0
  s[i] = 0;
1453
0
  return s;
1454
0
    }
1455
1456
0
    return NULL;
1457
0
}
1458
1459
/* strcmp that handles NULL arguments */
1460
static cairo_bool_t
1461
strcmp_null (const char *s1, const char *s2)
1462
0
{
1463
0
    if (s1 && s2)
1464
0
  return strcmp (s1, s2) == 0;
1465
1466
0
    if (!s1 && !s2)
1467
0
  return TRUE;
1468
1469
0
    return FALSE;
1470
0
}
1471
1472
static cairo_int_status_t
1473
cairo_pdf_interchange_write_page_labels (cairo_pdf_surface_t *surface)
1474
669
{
1475
669
    int num_elems, i;
1476
669
    char *label;
1477
669
    char *prefix;
1478
669
    char *prev_prefix;
1479
669
    int num, prev_num;
1480
669
    cairo_int_status_t status;
1481
669
    cairo_bool_t has_labels;
1482
1483
    /* Check if any labels defined */
1484
669
    num_elems = _cairo_array_num_elements (&surface->page_labels);
1485
669
    has_labels = FALSE;
1486
2.66k
    for (i = 0; i < num_elems; i++) {
1487
1.99k
  _cairo_array_copy_element (&surface->page_labels, i, &label);
1488
1.99k
  if (label) {
1489
0
      has_labels = TRUE;
1490
0
      break;
1491
0
  }
1492
1.99k
    }
1493
1494
669
    if (!has_labels)
1495
669
  return CAIRO_STATUS_SUCCESS;
1496
1497
0
    surface->page_labels_res = _cairo_pdf_surface_new_object (surface);
1498
0
    if (surface->page_labels_res.id == 0)
1499
0
  return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1500
1501
0
    status = _cairo_pdf_surface_object_begin (surface, surface->page_labels_res);
1502
0
    if (unlikely (status))
1503
0
  return status;
1504
1505
0
    _cairo_output_stream_printf (surface->object_stream.stream,
1506
0
         "<< /Nums [\n");
1507
0
    prefix = NULL;
1508
0
    prev_prefix = NULL;
1509
0
    num = 0;
1510
0
    prev_num = 0;
1511
0
    for (i = 0; i < num_elems; i++) {
1512
0
  _cairo_array_copy_element (&surface->page_labels, i, &label);
1513
0
  if (label) {
1514
0
      prefix = split_label (label, &num);
1515
0
  } else {
1516
0
      prefix = NULL;
1517
0
      num = i + 1;
1518
0
  }
1519
1520
0
  if (!strcmp_null (prefix, prev_prefix) || num != prev_num + 1) {
1521
0
      _cairo_output_stream_printf (surface->object_stream.stream,  "   %d << ", i);
1522
1523
0
      if (num)
1524
0
    _cairo_output_stream_printf (surface->object_stream.stream,  "/S /D /St %d ", num);
1525
1526
0
      if (prefix) {
1527
0
    char *s;
1528
0
    status = _cairo_utf8_to_pdf_string (prefix, &s);
1529
0
    if (unlikely (status))
1530
0
        return status;
1531
1532
0
    _cairo_output_stream_printf (surface->object_stream.stream,  "/P %s ", s);
1533
0
    free (s);
1534
0
      }
1535
1536
0
      _cairo_output_stream_printf (surface->object_stream.stream,  ">>\n");
1537
0
  }
1538
0
  free (prev_prefix);
1539
0
  prev_prefix = prefix;
1540
0
  prefix = NULL;
1541
0
  prev_num = num;
1542
0
    }
1543
0
    free (prefix);
1544
0
    free (prev_prefix);
1545
0
    _cairo_output_stream_printf (surface->object_stream.stream,
1546
0
         "  ]\n"
1547
0
         ">>\n");
1548
0
    _cairo_pdf_surface_object_end (surface);
1549
1550
0
    return CAIRO_STATUS_SUCCESS;
1551
0
}
1552
1553
static void
1554
_collect_external_dest (void *entry, void *closure)
1555
0
{
1556
0
    cairo_pdf_named_dest_t *dest = entry;
1557
0
    cairo_pdf_surface_t *surface = closure;
1558
0
    cairo_pdf_interchange_t *ic = &surface->interchange;
1559
1560
0
    if (!dest->attrs.internal)
1561
0
  ic->sorted_dests[ic->num_dests++] = dest;
1562
0
}
1563
1564
static int
1565
_dest_compare (const void *a, const void *b)
1566
0
{
1567
0
    const cairo_pdf_named_dest_t * const *dest_a = a;
1568
0
    const cairo_pdf_named_dest_t * const *dest_b = b;
1569
1570
0
    return strcmp ((*dest_a)->attrs.name, (*dest_b)->attrs.name);
1571
0
}
1572
1573
static cairo_int_status_t
1574
_cairo_pdf_interchange_write_document_dests (cairo_pdf_surface_t *surface)
1575
669
{
1576
669
    int i;
1577
669
    cairo_pdf_interchange_t *ic = &surface->interchange;
1578
669
    cairo_int_status_t status;
1579
669
    cairo_pdf_page_info_t *page_info;
1580
1581
669
    if (ic->num_dests == 0) {
1582
669
  ic->dests_res.id = 0;
1583
669
        return CAIRO_STATUS_SUCCESS;
1584
669
    }
1585
1586
0
    ic->sorted_dests = _cairo_calloc_ab (ic->num_dests, sizeof (cairo_pdf_named_dest_t *));
1587
0
    if (unlikely (ic->sorted_dests == NULL))
1588
0
  return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1589
1590
0
    ic->num_dests = 0;
1591
0
    _cairo_hash_table_foreach (ic->named_dests, _collect_external_dest, surface);
1592
1593
0
    qsort (ic->sorted_dests, ic->num_dests, sizeof (cairo_pdf_named_dest_t *), _dest_compare);
1594
1595
0
    ic->dests_res = _cairo_pdf_surface_new_object (surface);
1596
0
    if (ic->dests_res.id == 0)
1597
0
  return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1598
1599
0
    status = _cairo_pdf_surface_object_begin (surface, ic->dests_res);
1600
0
    if (unlikely (status))
1601
0
  return status;
1602
1603
0
    _cairo_output_stream_printf (surface->object_stream.stream,
1604
0
         "<< /Names [\n");
1605
0
    for (i = 0; i < ic->num_dests; i++) {
1606
0
  cairo_pdf_named_dest_t *dest = ic->sorted_dests[i];
1607
0
  double x = 0;
1608
0
  double y = 0;
1609
0
  char *name = NULL;
1610
1611
0
  if (dest->attrs.internal)
1612
0
      continue;
1613
1614
0
  if (dest->extents.valid) {
1615
0
      x = dest->extents.extents.x;
1616
0
      y = dest->extents.extents.y;
1617
0
  }
1618
1619
0
  if (dest->attrs.x_valid)
1620
0
      x = dest->attrs.x;
1621
1622
0
  if (dest->attrs.y_valid)
1623
0
      y = dest->attrs.y;
1624
1625
0
  status = _cairo_utf8_to_pdf_string (dest->attrs.name, &name);
1626
0
  if (unlikely (status))
1627
0
      return status;
1628
1629
0
  page_info = _cairo_array_index (&surface->pages, dest->page - 1);
1630
0
  _cairo_output_stream_printf (surface->object_stream.stream,
1631
0
             "   %s [%d 0 R /XYZ %f %f 0]\n",
1632
0
             name,
1633
0
             page_info->page_res.id,
1634
0
             x,
1635
0
             page_info->height - y);
1636
0
  free (name);
1637
1638
0
    }
1639
0
    _cairo_output_stream_printf (surface->object_stream.stream,
1640
0
         "  ]\n"
1641
0
         ">>\n");
1642
0
    _cairo_pdf_surface_object_end (surface);
1643
1644
0
    return CAIRO_STATUS_SUCCESS;
1645
0
}
1646
1647
static cairo_int_status_t
1648
cairo_pdf_interchange_write_names_dict (cairo_pdf_surface_t *surface)
1649
669
{
1650
669
    cairo_pdf_interchange_t *ic = &surface->interchange;
1651
669
    cairo_int_status_t status;
1652
1653
669
    status = _cairo_pdf_interchange_write_document_dests (surface);
1654
669
    if (unlikely (status))
1655
0
  return status;
1656
1657
669
    surface->names_dict_res.id = 0;
1658
669
    if (ic->dests_res.id != 0) {
1659
0
  surface->names_dict_res = _cairo_pdf_surface_new_object (surface);
1660
0
  if (surface->names_dict_res.id == 0)
1661
0
      return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1662
1663
0
  status = _cairo_pdf_surface_object_begin (surface, surface->names_dict_res);
1664
0
  if (unlikely (status))
1665
0
      return status;
1666
1667
0
  _cairo_output_stream_printf (surface->object_stream.stream,
1668
0
             "<< /Dests %d 0 R >>\n",
1669
0
             ic->dests_res.id);
1670
0
  _cairo_pdf_surface_object_end (surface);
1671
0
    }
1672
1673
669
    return CAIRO_STATUS_SUCCESS;
1674
669
}
1675
1676
static cairo_int_status_t
1677
cairo_pdf_interchange_write_docinfo (cairo_pdf_surface_t *surface)
1678
669
{
1679
669
    cairo_pdf_interchange_t *ic = &surface->interchange;
1680
669
    cairo_int_status_t status;
1681
669
    unsigned int i, num_elems;
1682
669
    struct metadata *data;
1683
669
    unsigned char *p;
1684
1685
669
    surface->docinfo_res = _cairo_pdf_surface_new_object (surface);
1686
669
    if (surface->docinfo_res.id == 0)
1687
0
  return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1688
1689
669
    status = _cairo_pdf_surface_object_begin (surface, surface->docinfo_res);
1690
669
    if (unlikely (status))
1691
0
  return status;
1692
1693
669
    _cairo_output_stream_printf (surface->object_stream.stream,
1694
669
         "<< /Producer (cairo %s (https://cairographics.org))\n",
1695
669
         cairo_version_string ());
1696
1697
669
    if (ic->docinfo.title)
1698
0
  _cairo_output_stream_printf (surface->object_stream.stream, "   /Title %s\n", ic->docinfo.title);
1699
1700
669
    if (ic->docinfo.author)
1701
0
  _cairo_output_stream_printf (surface->object_stream.stream, "   /Author %s\n", ic->docinfo.author);
1702
1703
669
    if (ic->docinfo.subject)
1704
0
  _cairo_output_stream_printf (surface->object_stream.stream, "   /Subject %s\n", ic->docinfo.subject);
1705
1706
669
    if (ic->docinfo.keywords)
1707
0
  _cairo_output_stream_printf (surface->object_stream.stream, "   /Keywords %s\n", ic->docinfo.keywords);
1708
1709
669
    if (ic->docinfo.creator)
1710
0
  _cairo_output_stream_printf (surface->object_stream.stream, "   /Creator %s\n", ic->docinfo.creator);
1711
1712
669
    if (ic->docinfo.create_date)
1713
669
  _cairo_output_stream_printf (surface->object_stream.stream, "   /CreationDate %s\n", ic->docinfo.create_date);
1714
1715
669
    if (ic->docinfo.mod_date)
1716
0
  _cairo_output_stream_printf (surface->object_stream.stream, "   /ModDate %s\n", ic->docinfo.mod_date);
1717
1718
669
    num_elems = _cairo_array_num_elements (&ic->custom_metadata);
1719
669
    for (i = 0; i < num_elems; i++) {
1720
0
  data = _cairo_array_index (&ic->custom_metadata, i);
1721
0
  if (data->value) {
1722
0
      _cairo_output_stream_printf (surface->object_stream.stream, "   /");
1723
      /* The name can be any utf8 string. Use hex codes as
1724
       * specified in section 7.3.5 of PDF reference
1725
       */
1726
0
      p = (unsigned char *)data->name;
1727
0
      while (*p) {
1728
0
    if (*p < 0x21 || *p > 0x7e || *p == '#' || *p == '/')
1729
0
        _cairo_output_stream_printf (surface->object_stream.stream, "#%02x", *p);
1730
0
    else
1731
0
        _cairo_output_stream_printf (surface->object_stream.stream, "%c", *p);
1732
0
    p++;
1733
0
      }
1734
0
      _cairo_output_stream_printf (surface->object_stream.stream, " %s\n", data->value);
1735
0
  }
1736
0
    }
1737
1738
669
    _cairo_output_stream_printf (surface->object_stream.stream,
1739
669
         ">>\n");
1740
669
    _cairo_pdf_surface_object_end (surface);
1741
1742
669
    return CAIRO_STATUS_SUCCESS;
1743
669
}
1744
1745
static cairo_int_status_t
1746
_cairo_pdf_interchange_begin_structure_tag (cairo_pdf_surface_t    *surface,
1747
              cairo_tag_type_t        tag_type,
1748
              const char             *name,
1749
              const char             *attributes)
1750
0
{
1751
0
    int mcid;
1752
0
    cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
1753
0
    cairo_pdf_interchange_t *ic = &surface->interchange;
1754
0
    cairo_pdf_command_entry_t *command_entry;
1755
0
    cairo_pdf_struct_tree_node_t *parent_node;
1756
0
    unsigned int content_command_id;
1757
1758
0
    if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
1759
0
  ic->content_emitted = FALSE;
1760
0
  status = add_tree_node (surface, ic->current_analyze_node, name, attributes, &ic->current_analyze_node);
1761
0
  if (unlikely (status))
1762
0
      return status;
1763
1764
0
  status = command_list_add (surface, ic->command_id, PDF_BEGIN);
1765
0
  if (unlikely (status))
1766
0
      return status;
1767
1768
  /* Add to command_id to node map. */
1769
0
  command_entry = _cairo_calloc (sizeof(cairo_pdf_command_entry_t));
1770
0
  command_entry->recording_id = ic->recording_id;
1771
0
  command_entry->command_id = ic->command_id;
1772
0
  command_entry->node = ic->current_analyze_node;
1773
0
  _cairo_pdf_command_init_key (command_entry);
1774
0
  status = _cairo_hash_table_insert (ic->command_to_node_map, &command_entry->base);
1775
0
  if (unlikely(status))
1776
0
      return status;
1777
1778
0
  if (tag_type & TAG_TYPE_LINK) {
1779
0
      status = add_annotation (surface, ic->current_analyze_node, name, attributes);
1780
0
      if (unlikely (status))
1781
0
    return status;
1782
0
  }
1783
1784
0
  if (ic->current_analyze_node->type == PDF_NODE_CONTENT) {
1785
0
      cairo_pdf_content_tag_t *content = _cairo_calloc (sizeof(cairo_pdf_content_tag_t));
1786
0
      content->node = ic->current_analyze_node;
1787
0
      _cairo_pdf_content_tag_init_key (content);
1788
0
      status = _cairo_hash_table_insert (ic->content_tag_map, &content->base);
1789
0
      if (unlikely (status))
1790
0
    return status;
1791
0
  }
1792
1793
0
  ic->content_emitted = FALSE;
1794
1795
0
    } else if (surface->paginated_mode == CAIRO_PAGINATED_MODE_RENDER) {
1796
0
  if (ic->marked_content_open) {
1797
0
      status = _cairo_pdf_operators_tag_end (&surface->pdf_operators);
1798
0
      ic->marked_content_open = FALSE;
1799
0
      if (unlikely (status))
1800
0
    return status;
1801
0
  }
1802
1803
0
  ic->current_render_node = lookup_node_for_command (surface, ic->recording_id, ic->command_id);
1804
0
  if (ic->current_render_node->type == PDF_NODE_ARTIFACT) {
1805
0
      if (command_list_has_content (surface, ic->command_id, NULL)) {
1806
0
    status = _cairo_pdf_operators_tag_begin (&surface->pdf_operators, name, -1);
1807
0
    ic->marked_content_open = TRUE;
1808
0
      }
1809
0
  } else if (ic->current_render_node->type == PDF_NODE_CONTENT_REF) {
1810
0
      parent_node = ic->current_render_node->parent;
1811
0
      add_child_to_mcid_array (surface, parent_node, ic->command_id, ic->current_render_node);
1812
0
  } else {
1813
0
      parent_node = ic->current_render_node->parent;
1814
0
      add_child_to_mcid_array (surface, parent_node, ic->command_id, ic->current_render_node);
1815
0
      if (command_list_has_content (surface, ic->command_id, &content_command_id)) {
1816
0
    add_mcid_to_node (surface, ic->current_render_node, content_command_id, &mcid);
1817
0
    const char *tag_name = name;
1818
0
    if (ic->current_render_node->type == PDF_NODE_CONTENT)
1819
0
        tag_name = ic->current_render_node->attributes.content.tag_name;
1820
1821
0
    status = _cairo_pdf_operators_tag_begin (&surface->pdf_operators, tag_name, mcid);
1822
0
    ic->marked_content_open = TRUE;
1823
0
      }
1824
0
  }
1825
0
    }
1826
1827
0
    return status;
1828
0
}
1829
1830
static cairo_int_status_t
1831
_cairo_pdf_interchange_begin_dest_tag (cairo_pdf_surface_t    *surface,
1832
               cairo_tag_type_t        tag_type,
1833
               const char             *name,
1834
               const char             *attributes)
1835
0
{
1836
0
    cairo_pdf_named_dest_t *dest;
1837
0
    cairo_pdf_interchange_t *ic = &surface->interchange;
1838
0
    cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
1839
1840
0
    if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
1841
0
  dest = _cairo_calloc (sizeof (cairo_pdf_named_dest_t));
1842
0
  if (unlikely (dest == NULL))
1843
0
      return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1844
1845
0
  status = _cairo_tag_parse_dest_attributes (attributes, &dest->attrs);
1846
0
  if (unlikely (status))
1847
0
  {
1848
0
      free (dest);
1849
0
      return status;
1850
0
  }
1851
1852
0
  dest->page = _cairo_array_num_elements (&surface->pages);
1853
0
  init_named_dest_key (dest);
1854
0
  status = _cairo_hash_table_insert (ic->named_dests, &dest->base);
1855
0
  if (unlikely (status)) {
1856
0
      free (dest->attrs.name);
1857
0
      free (dest);
1858
0
      return status;
1859
0
  }
1860
1861
0
  _cairo_tag_stack_set_top_data (&ic->analysis_tag_stack, dest);
1862
0
  ic->num_dests++;
1863
0
    }
1864
1865
0
    return status;
1866
0
}
1867
1868
cairo_int_status_t
1869
_cairo_pdf_interchange_tag_begin (cairo_pdf_surface_t    *surface,
1870
          const char             *name,
1871
          const char             *attributes)
1872
0
{
1873
0
    cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
1874
0
    cairo_tag_type_t tag_type;
1875
0
    cairo_pdf_interchange_t *ic = &surface->interchange;
1876
1877
0
    if (ic->ignore_current_surface)
1878
0
        return CAIRO_STATUS_SUCCESS;
1879
1880
0
    if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
1881
0
  status = _cairo_tag_stack_push (&ic->analysis_tag_stack, name, attributes);
1882
1883
0
    } else if (surface->paginated_mode == CAIRO_PAGINATED_MODE_RENDER) {
1884
0
  status = _cairo_tag_stack_push (&ic->render_tag_stack, name, attributes);
1885
0
    }
1886
0
    if (unlikely (status))
1887
0
  return status;
1888
1889
0
    tag_type = _cairo_tag_get_type (name);
1890
0
    if (tag_type & (TAG_TYPE_STRUCTURE|TAG_TYPE_CONTENT|TAG_TYPE_CONTENT_REF|TAG_TYPE_ARTIFACT)) {
1891
0
  status = _cairo_pdf_interchange_begin_structure_tag (surface, tag_type, name, attributes);
1892
0
  if (unlikely (status))
1893
0
      return status;
1894
0
    }
1895
1896
0
    if (tag_type & TAG_TYPE_DEST) {
1897
0
  status = _cairo_pdf_interchange_begin_dest_tag (surface, tag_type, name, attributes);
1898
0
  if (unlikely (status))
1899
0
      return status;
1900
0
    }
1901
1902
0
    return status;
1903
0
}
1904
1905
static cairo_int_status_t
1906
_cairo_pdf_interchange_end_structure_tag (cairo_pdf_surface_t    *surface,
1907
            cairo_tag_type_t        tag_type,
1908
            cairo_tag_stack_elem_t *elem)
1909
0
{
1910
0
    cairo_pdf_interchange_t *ic = &surface->interchange;
1911
0
    cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
1912
0
    int mcid;
1913
0
    unsigned int content_command_id;
1914
1915
0
    if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
1916
0
  assert (ic->current_analyze_node->parent != NULL);
1917
0
  status = command_list_add (surface, ic->command_id, PDF_END);
1918
0
  if (unlikely (status))
1919
0
      return status;
1920
1921
0
  ic->content_emitted = FALSE;
1922
0
  ic->current_analyze_node = ic->current_analyze_node->parent;
1923
1924
0
    } else if (surface->paginated_mode == CAIRO_PAGINATED_MODE_RENDER) {
1925
0
  if (ic->marked_content_open) {
1926
0
      status = _cairo_pdf_operators_tag_end (&surface->pdf_operators);
1927
0
      ic->marked_content_open = FALSE;
1928
0
      if (unlikely (status))
1929
0
    return status;
1930
0
  }
1931
0
  ic->current_render_node = ic->current_render_node->parent;
1932
0
  if (ic->current_render_node->parent &&
1933
0
      command_list_has_content (surface, ic->command_id, &content_command_id))
1934
0
  {
1935
0
      add_mcid_to_node (surface, ic->current_render_node, content_command_id, &mcid);
1936
0
      status = _cairo_pdf_operators_tag_begin (&surface->pdf_operators,
1937
0
                 ic->current_render_node->name, mcid);
1938
0
      ic->marked_content_open = TRUE;
1939
0
  }
1940
0
    }
1941
1942
0
    return status;
1943
0
}
1944
1945
cairo_int_status_t
1946
_cairo_pdf_interchange_tag_end (cairo_pdf_surface_t *surface,
1947
        const char          *name)
1948
0
{
1949
0
    cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
1950
0
    cairo_pdf_interchange_t *ic = &surface->interchange;
1951
0
    cairo_tag_type_t tag_type;
1952
0
    cairo_tag_stack_elem_t *elem;
1953
1954
0
    if (ic->ignore_current_surface)
1955
0
        return CAIRO_STATUS_SUCCESS;
1956
1957
0
    if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
1958
0
  status = _cairo_tag_stack_pop (&ic->analysis_tag_stack, name, &elem);
1959
1960
0
    } else if (surface->paginated_mode == CAIRO_PAGINATED_MODE_RENDER) {
1961
0
  status = _cairo_tag_stack_pop (&ic->render_tag_stack, name, &elem);
1962
0
    } else {
1963
0
  ASSERT_NOT_REACHED;
1964
0
    }
1965
0
    if (unlikely (status))
1966
0
  return status;
1967
1968
0
    tag_type = _cairo_tag_get_type (name);
1969
0
    if (tag_type & (TAG_TYPE_STRUCTURE|TAG_TYPE_CONTENT|TAG_TYPE_CONTENT_REF|TAG_TYPE_ARTIFACT)) {
1970
0
  status = _cairo_pdf_interchange_end_structure_tag (surface, tag_type, elem);
1971
0
  if (unlikely (status))
1972
0
      goto cleanup;
1973
0
    }
1974
1975
0
  cleanup:
1976
0
    _cairo_tag_stack_free_elem (elem);
1977
1978
0
    return status;
1979
0
}
1980
1981
cairo_int_status_t
1982
_cairo_pdf_interchange_command_id (cairo_pdf_surface_t  *surface,
1983
           unsigned int          recording_id,
1984
           unsigned int          command_id)
1985
1.06M
{
1986
1.06M
    cairo_pdf_interchange_t *ic = &surface->interchange;
1987
1.06M
    int mcid;
1988
1.06M
    cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
1989
1990
1.06M
    ic->recording_id = recording_id;
1991
1.06M
    ic->command_id = command_id;
1992
1993
1.06M
    if (surface->paginated_mode == CAIRO_PAGINATED_MODE_RENDER && ic->current_render_node) {
1994
  /* TODO If the group does not have tags we don't need to close the current tag. */
1995
0
  if (command_list_is_group (surface, command_id)) {
1996
      /* A "Do /xnnn" can not be inside a tag (since the
1997
       * XObject may also contain tags). Close the tag.
1998
       */
1999
0
      if (ic->marked_content_open) {
2000
0
    status = _cairo_pdf_operators_tag_end (&surface->pdf_operators);
2001
0
    ic->marked_content_open = FALSE;
2002
0
      }
2003
      /* If there is any more content after this and we are
2004
       * inside a tag (current node is not the root node),
2005
       * ensure that the next command will open the tag.
2006
       */
2007
0
      if (command_list_has_content (surface, command_id, NULL) && ic->current_render_node->parent) {
2008
0
    ic->render_next_command_has_content = TRUE;
2009
0
      }
2010
0
  } else if (ic->render_next_command_has_content) {
2011
      /* After a "Do /xnnn" operation, if there is more content, open the tag. */
2012
0
      add_mcid_to_node (surface, ic->current_render_node, ic->command_id, &mcid);
2013
0
      status = _cairo_pdf_operators_tag_begin (&surface->pdf_operators,
2014
0
                 ic->current_render_node->name, mcid);
2015
0
      ic->marked_content_open = TRUE;
2016
0
      ic->render_next_command_has_content = FALSE;
2017
0
  }
2018
0
    }
2019
2020
1.06M
    return status;
2021
1.06M
}
2022
2023
/* Check if this use of recording surface is or will need to be part of the the struct tree */
2024
cairo_bool_t
2025
_cairo_pdf_interchange_struct_tree_requires_recording_surface (
2026
    cairo_pdf_surface_t           *surface,
2027
    const cairo_surface_pattern_t *recording_surface_pattern,
2028
    cairo_analysis_source_t        source_type)
2029
3.04k
{
2030
3.04k
    cairo_surface_t *recording_surface = recording_surface_pattern->surface;
2031
3.04k
    cairo_surface_t *free_me = NULL;
2032
3.04k
    cairo_bool_t requires_recording = FALSE;
2033
2034
3.04k
    if (recording_surface_pattern->base.extend != CAIRO_EXTEND_NONE)
2035
1.23k
  return FALSE;
2036
2037
1.81k
    if (_cairo_surface_is_snapshot (recording_surface))
2038
1.81k
  free_me = recording_surface = _cairo_surface_snapshot_get_target (recording_surface);
2039
2040
1.81k
    if (_cairo_surface_is_recording (recording_surface) &&
2041
1.81k
  _cairo_recording_surface_has_tags (recording_surface))
2042
0
    {
2043
  /* Check if tags are to be ignored in this source */
2044
0
  switch (source_type) {
2045
0
      case CAIRO_ANALYSIS_SOURCE_PAINT:
2046
0
      case CAIRO_ANALYSIS_SOURCE_FILL:
2047
0
    requires_recording = TRUE;
2048
0
    break;
2049
0
      case CAIRO_ANALYSIS_SOURCE_MASK: /* TODO: allow SOURCE_MASK with solid MASK_MASK */
2050
0
      case CAIRO_ANALYSIS_MASK_MASK:
2051
0
      case CAIRO_ANALYSIS_SOURCE_STROKE:
2052
0
      case CAIRO_ANALYSIS_SOURCE_SHOW_GLYPHS:
2053
0
      case CAIRO_ANALYSIS_SOURCE_NONE:
2054
0
    break;
2055
0
  }
2056
0
    }
2057
2058
1.81k
    cairo_surface_destroy (free_me);
2059
1.81k
    return requires_recording;
2060
1.81k
}
2061
2062
/* Called at the start of a recording group during analyze. This will
2063
 * be called during the analysis of the drawing operation. */
2064
cairo_int_status_t
2065
_cairo_pdf_interchange_recording_source_surface_begin (
2066
    cairo_pdf_surface_t           *surface,
2067
    const cairo_surface_pattern_t *recording_surface_pattern,
2068
    unsigned int                   region_id,
2069
    cairo_analysis_source_t        source_type)
2070
650
{
2071
650
    cairo_pdf_interchange_t *ic = &surface->interchange;
2072
650
    cairo_recording_surface_stack_entry_t element;
2073
650
    cairo_int_status_t status;
2074
2075
    /* A new recording surface is being replayed */
2076
650
    ic->ignore_current_surface = TRUE;
2077
650
    if (_cairo_pdf_interchange_struct_tree_requires_recording_surface (surface,
2078
650
                       recording_surface_pattern,
2079
650
                       source_type))
2080
0
    {
2081
0
  ic->ignore_current_surface = FALSE;
2082
0
    }
2083
2084
650
    element.ignore_surface = ic->ignore_current_surface;
2085
650
    element.current_node = ic->current_analyze_node;
2086
650
    ic->content_emitted = FALSE;
2087
2088
    /* Push to stack so that the current source identifiers can be
2089
     * restored after this recording surface has ended. */
2090
650
    status = _cairo_array_append (&ic->recording_surface_stack, &element);
2091
650
    if (status)
2092
0
  return status;
2093
2094
650
    if (ic->ignore_current_surface)
2095
650
  return CAIRO_STATUS_SUCCESS;
2096
2097
0
    status = command_list_push_group (surface, ic->command_id, recording_surface_pattern->surface, region_id);
2098
0
    if (unlikely (status))
2099
0
  return status;
2100
2101
0
    return CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN;
2102
0
}
2103
2104
/* Called at the end of a recording group during analyze. */
2105
cairo_int_status_t
2106
_cairo_pdf_interchange_recording_source_surface_end (
2107
    cairo_pdf_surface_t           *surface,
2108
    const cairo_surface_pattern_t *recording_surface_pattern,
2109
    unsigned int                   region_id,
2110
    cairo_analysis_source_t        source_type)
2111
650
{
2112
650
    cairo_pdf_interchange_t *ic = &surface->interchange;
2113
650
    cairo_recording_surface_stack_entry_t element;
2114
650
    cairo_recording_surface_stack_entry_t *element_ptr;
2115
2116
650
    if (!ic->ignore_current_surface)
2117
0
  command_list_pop_group (surface);
2118
2119
650
    if (_cairo_array_pop_element (&ic->recording_surface_stack, &element)) {
2120
650
  element_ptr = _cairo_array_last_element (&ic->recording_surface_stack);
2121
650
  if (element_ptr) {
2122
1
      ic->ignore_current_surface = element_ptr->ignore_surface;
2123
1
      assert (ic->current_analyze_node == element_ptr->current_node);
2124
649
  } else {
2125
      /* Back at the page content. */
2126
649
      ic->ignore_current_surface = FALSE;
2127
649
  }
2128
650
  ic->content_emitted = FALSE;
2129
650
  return CAIRO_STATUS_SUCCESS;
2130
650
    }
2131
0
    ASSERT_NOT_REACHED; /* _recording_source_surface_begin/end mismatch */
2132
2133
0
    return CAIRO_STATUS_SUCCESS;
2134
0
}
2135
2136
/* Called at the start of a recording group during render. This will
2137
 * be called after the end of page content. */
2138
cairo_int_status_t
2139
_cairo_pdf_interchange_emit_recording_surface_begin (cairo_pdf_surface_t     *surface,
2140
                 cairo_surface_t         *recording_surface,
2141
                 int                      region_id,
2142
                 cairo_pdf_resource_t     surface_resource,
2143
                 int                     *struct_parents)
2144
650
{
2145
650
    cairo_pdf_interchange_t *ic = &surface->interchange;
2146
650
    cairo_int_status_t status;
2147
2148
    /* When
2149
     * _cairo_pdf_interchange_struct_tree_requires_recording_surface()
2150
     * is false, the region_id of the recording surface is set to 0.
2151
     */
2152
650
    if (region_id == 0) {
2153
650
  ic->ignore_current_surface = TRUE;
2154
650
  return CAIRO_STATUS_SUCCESS;
2155
650
    }
2156
2157
0
    command_list_set_current_recording_commands (surface, recording_surface, region_id);
2158
2159
0
    ic->ignore_current_surface = FALSE;
2160
0
    _cairo_array_truncate (&ic->mcid_to_tree, 0);
2161
0
    ic->current_recording_surface_res = surface_resource;
2162
2163
0
    ic->content_parent_res = _cairo_pdf_surface_new_object (surface);
2164
0
    if (ic->content_parent_res.id == 0)
2165
0
  return _cairo_error (CAIRO_STATUS_NO_MEMORY);
2166
2167
0
    status = _cairo_array_append (&ic->parent_tree, &ic->content_parent_res);
2168
0
    if (unlikely (status))
2169
0
  return status;
2170
2171
0
    *struct_parents = _cairo_array_num_elements (&ic->parent_tree) - 1;
2172
2173
0
    ic->render_next_command_has_content = FALSE;
2174
2175
0
    return CAIRO_STATUS_SUCCESS;
2176
0
}
2177
2178
/* Called at the end of a recording group during render. */
2179
cairo_int_status_t
2180
_cairo_pdf_interchange_emit_recording_surface_end (cairo_pdf_surface_t     *surface,
2181
               cairo_surface_t         *recording_surface)
2182
0
{
2183
0
    cairo_pdf_interchange_t *ic = &surface->interchange;
2184
2185
0
    if (ic->ignore_current_surface)
2186
0
  return CAIRO_STATUS_SUCCESS;
2187
2188
0
    ic->current_recording_surface_res.id = 0;
2189
0
    return cairo_pdf_interchange_write_content_parent_elems (surface);
2190
0
}
2191
2192
static void _add_operation_extents_to_dest_tag (cairo_tag_stack_elem_t *elem,
2193
            void                   *closure)
2194
0
{
2195
0
    const cairo_rectangle_int_t *extents = (const cairo_rectangle_int_t *) closure;
2196
0
    cairo_pdf_named_dest_t *dest;
2197
2198
0
    if (_cairo_tag_get_type (elem->name)  & TAG_TYPE_DEST) {
2199
0
  if (elem->data) {
2200
0
      dest = (cairo_pdf_named_dest_t *) elem->data;
2201
0
      if (dest->extents.valid) {
2202
0
    _cairo_rectangle_union (&dest->extents.extents, extents);
2203
0
      } else {
2204
0
    dest->extents.extents = *extents;
2205
0
    dest->extents.valid = TRUE;
2206
0
      }
2207
0
  }
2208
0
    }
2209
0
}
2210
2211
cairo_int_status_t
2212
_cairo_pdf_interchange_add_operation_extents (cairo_pdf_surface_t         *surface,
2213
                const cairo_rectangle_int_t *extents)
2214
1.06M
{
2215
1.06M
    cairo_pdf_interchange_t *ic = &surface->interchange;
2216
2217
    /* Add extents to current node and all DEST tags on the stack */
2218
1.06M
    if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
2219
531k
  if (ic->current_analyze_node) {
2220
531k
      if (ic->current_analyze_node->extents.valid) {
2221
530k
    _cairo_rectangle_union (&ic->current_analyze_node->extents.extents, extents);
2222
530k
      } else {
2223
79
    ic->current_analyze_node->extents.extents = *extents;
2224
79
    ic->current_analyze_node->extents.valid = TRUE;
2225
79
      }
2226
531k
  }
2227
2228
531k
  _cairo_tag_stack_foreach (&ic->analysis_tag_stack,
2229
531k
          _add_operation_extents_to_dest_tag,
2230
531k
          (void*)extents);
2231
531k
    }
2232
2233
1.06M
    return CAIRO_STATUS_SUCCESS;
2234
1.06M
}
2235
2236
cairo_int_status_t
2237
_cairo_pdf_interchange_add_content (cairo_pdf_surface_t *surface)
2238
1.03M
{
2239
1.03M
    cairo_pdf_interchange_t *ic = &surface->interchange;
2240
1.03M
    cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
2241
2242
1.03M
    if (ic->ignore_current_surface)
2243
0
        return CAIRO_STATUS_SUCCESS;
2244
2245
1.03M
    if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
2246
515k
  status = command_list_add (surface, ic->command_id, PDF_CONTENT);
2247
515k
  if (unlikely (status))
2248
0
      return status;
2249
515k
    }
2250
2251
1.03M
    return status;
2252
1.03M
}
2253
2254
/* Called at the start of 1emiting the page content during analyze or render */
2255
cairo_int_status_t
2256
_cairo_pdf_interchange_begin_page_content (cairo_pdf_surface_t *surface)
2257
4.04k
{
2258
4.04k
    cairo_pdf_interchange_t *ic = &surface->interchange;
2259
4.04k
    cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
2260
4.04k
    int mcid;
2261
4.04k
    unsigned int content_command_id;
2262
4.04k
    cairo_pdf_command_list_t *page_commands;
2263
2264
4.04k
    if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
2265
2.02k
  status = _cairo_array_allocate (&ic->page_commands, 1, (void**)&page_commands);
2266
2.02k
  if (unlikely (status))
2267
0
      return status;
2268
2269
2.02k
  _cairo_array_init (&page_commands->commands, sizeof(cairo_pdf_command_t));
2270
2.02k
  page_commands->parent = NULL;
2271
2.02k
  ic->current_commands = page_commands;
2272
2.02k
  ic->ignore_current_surface = FALSE;
2273
2.02k
    } else if (surface->paginated_mode == CAIRO_PAGINATED_MODE_RENDER) {
2274
2.02k
  ic->current_commands = _cairo_array_last_element (&ic->page_commands);
2275
  /* Each page has its own parent tree to map MCID to nodes. */
2276
2.02k
  _cairo_array_truncate (&ic->mcid_to_tree, 0);
2277
2.02k
  ic->ignore_current_surface = FALSE;
2278
2.02k
  ic->content_parent_res = _cairo_pdf_surface_new_object (surface);
2279
2.02k
  if (ic->content_parent_res.id == 0)
2280
0
      return _cairo_error (CAIRO_STATUS_NO_MEMORY);
2281
2282
2.02k
  status = _cairo_array_append (&ic->parent_tree, &ic->content_parent_res);
2283
2.02k
  if (unlikely (status))
2284
0
      return status;
2285
2286
2.02k
  surface->page_parent_tree = _cairo_array_num_elements (&ic->parent_tree) - 1;
2287
2288
2.02k
  if (ic->next_page_render_node && ic->next_page_render_node->parent &&
2289
2.02k
      command_list_has_content (surface, -1, &content_command_id))
2290
0
  {
2291
0
      add_mcid_to_node (surface, ic->next_page_render_node, content_command_id, &mcid);
2292
0
      const char *tag_name = ic->next_page_render_node->name;
2293
0
      if (ic->next_page_render_node->type == PDF_NODE_CONTENT)
2294
0
    tag_name = ic->next_page_render_node->attributes.content.tag_name;
2295
2296
0
      status = _cairo_pdf_operators_tag_begin (&surface->pdf_operators, tag_name, mcid);
2297
0
      ic->marked_content_open = TRUE;
2298
0
  }
2299
2.02k
  ic->render_next_command_has_content = FALSE;
2300
2.02k
    }
2301
2302
4.04k
    return status;
2303
4.04k
}
2304
2305
/* Called at the end of emiting the page content during analyze or render */
2306
cairo_int_status_t
2307
_cairo_pdf_interchange_end_page_content (cairo_pdf_surface_t *surface)
2308
4.04k
{
2309
4.04k
    cairo_pdf_interchange_t *ic = &surface->interchange;
2310
4.04k
    cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
2311
2312
4.04k
    if (surface->paginated_mode == CAIRO_PAGINATED_MODE_RENDER) {
2313
  /* If a content tag is open across pages, the old page needs an EMC emitted. */
2314
2.02k
  if (ic->marked_content_open) {
2315
0
      status = _cairo_pdf_operators_tag_end (&surface->pdf_operators);
2316
0
      ic->marked_content_open = FALSE;
2317
0
  }
2318
2.02k
  ic->next_page_render_node = ic->current_render_node;
2319
2.02k
    }
2320
2321
4.04k
    return status;
2322
4.04k
}
2323
2324
cairo_int_status_t
2325
_cairo_pdf_interchange_write_page_objects (cairo_pdf_surface_t *surface)
2326
2.02k
{
2327
2.02k
    return cairo_pdf_interchange_write_content_parent_elems (surface);
2328
2.02k
}
2329
2330
cairo_int_status_t
2331
_cairo_pdf_interchange_write_document_objects (cairo_pdf_surface_t *surface)
2332
669
{
2333
669
    cairo_pdf_interchange_t *ic = &surface->interchange;
2334
669
    cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
2335
669
    cairo_tag_stack_structure_type_t tag_type;
2336
669
    cairo_bool_t write_struct_tree = FALSE;
2337
2338
669
    status = cairo_pdf_interchange_update_extents (surface);
2339
669
    if (unlikely (status))
2340
0
  return status;
2341
2342
669
    tag_type = _cairo_tag_stack_get_structure_type (&ic->analysis_tag_stack);
2343
669
    if (tag_type == TAG_TREE_TYPE_TAGGED || tag_type == TAG_TREE_TYPE_STRUCTURE ||
2344
669
  tag_type == TAG_TREE_TYPE_LINK_ONLY)
2345
0
    {
2346
0
  write_struct_tree = TRUE;
2347
0
    }
2348
2349
669
    status = cairo_pdf_interchange_write_annots (surface, write_struct_tree);
2350
669
    if (unlikely (status))
2351
0
  return status;
2352
2353
669
    if (write_struct_tree) {
2354
0
  surface->struct_tree_root = _cairo_pdf_surface_new_object (surface);
2355
0
  if (surface->struct_tree_root.id == 0)
2356
0
      return _cairo_error (CAIRO_STATUS_NO_MEMORY);
2357
2358
0
  ic->struct_root->res = surface->struct_tree_root;
2359
2360
0
  status = cairo_pdf_interchange_write_parent_tree (surface);
2361
0
  if (unlikely (status))
2362
0
      return status;
2363
2364
0
  unsigned num_pages = _cairo_array_num_elements (&ic->page_commands);
2365
0
  for (unsigned i = 0; i < num_pages; i++) {
2366
0
      cairo_pdf_command_list_t *command_list;
2367
0
      command_list = _cairo_array_index (&ic->page_commands, i);
2368
0
      update_mcid_order (surface, command_list);
2369
0
  }
2370
2371
0
  status = cairo_pdf_interchange_write_struct_tree (surface);
2372
0
  if (unlikely (status))
2373
0
      return status;
2374
2375
0
  if (tag_type == TAG_TREE_TYPE_TAGGED)
2376
0
      surface->tagged = TRUE;
2377
0
    }
2378
2379
669
    status = cairo_pdf_interchange_write_outline (surface);
2380
669
    if (unlikely (status))
2381
0
  return status;
2382
2383
669
    status = cairo_pdf_interchange_write_page_labels (surface);
2384
669
    if (unlikely (status))
2385
0
  return status;
2386
2387
669
    status = cairo_pdf_interchange_write_names_dict (surface);
2388
669
    if (unlikely (status))
2389
0
  return status;
2390
2391
669
    status = cairo_pdf_interchange_write_docinfo (surface);
2392
2393
669
    return status;
2394
669
}
2395
2396
static void
2397
_cairo_pdf_interchange_set_create_date (cairo_pdf_surface_t *surface)
2398
673
{
2399
673
    time_t utc, local, offset;
2400
673
    struct tm tm_local, tm_utc;
2401
673
    char buf[50];
2402
673
    int buf_size;
2403
673
    char *p;
2404
673
    cairo_pdf_interchange_t *ic = &surface->interchange;
2405
2406
673
    utc = time (NULL);
2407
673
    localtime_r (&utc, &tm_local);
2408
673
    strftime (buf, sizeof(buf), "(D:%Y%m%d%H%M%S", &tm_local);
2409
2410
    /* strftime "%z" is non standard and does not work on windows (it prints zone name, not offset).
2411
     * Calculate time zone offset by comparing local and utc time_t values for the same time.
2412
     */
2413
673
    gmtime_r (&utc, &tm_utc);
2414
673
    tm_utc.tm_isdst = tm_local.tm_isdst;
2415
673
    local = mktime (&tm_utc);
2416
673
    offset = difftime (utc, local);
2417
2418
673
    if (offset == 0) {
2419
673
  strcat (buf, "Z");
2420
673
    } else {
2421
0
  if (offset > 0) {
2422
0
      strcat (buf, "+");
2423
0
  } else {
2424
0
      strcat (buf, "-");
2425
0
      offset = -offset;
2426
0
  }
2427
0
  p = buf + strlen (buf);
2428
0
  buf_size = sizeof (buf) - strlen (buf);
2429
0
  snprintf (p, buf_size, "%02d'%02d", (int)(offset/3600), (int)(offset%3600)/60);
2430
0
    }
2431
673
    strcat (buf, ")");
2432
673
    ic->docinfo.create_date = strdup (buf);
2433
673
}
2434
2435
cairo_int_status_t
2436
_cairo_pdf_interchange_init (cairo_pdf_surface_t *surface)
2437
673
{
2438
673
    cairo_pdf_interchange_t *ic = &surface->interchange;
2439
673
    cairo_pdf_outline_entry_t *outline_root;
2440
673
    cairo_int_status_t status;
2441
2442
673
    _cairo_tag_stack_init (&ic->analysis_tag_stack);
2443
673
    _cairo_tag_stack_init (&ic->render_tag_stack);
2444
673
    ic->struct_root = _cairo_calloc (sizeof(cairo_pdf_struct_tree_node_t));
2445
673
    if (unlikely (ic->struct_root == NULL))
2446
0
  return _cairo_error (CAIRO_STATUS_NO_MEMORY);
2447
2448
673
    ic->struct_root->res.id = 0;
2449
673
    cairo_list_init (&ic->struct_root->children);
2450
673
    _cairo_array_init (&ic->struct_root->mcid, sizeof(cairo_pdf_page_mcid_t));
2451
2452
673
    ic->current_analyze_node = ic->struct_root;
2453
673
    ic->current_render_node = NULL;
2454
673
    ic->next_page_render_node = ic->struct_root;
2455
673
    _cairo_array_init (&ic->recording_surface_stack, sizeof(cairo_recording_surface_stack_entry_t));
2456
673
    ic->current_recording_surface_res.id = 0;
2457
673
    ic->command_to_node_map = _cairo_hash_table_create (_cairo_pdf_command_equal);
2458
673
    if (unlikely (ic->command_to_node_map == NULL))
2459
0
  return _cairo_error (CAIRO_STATUS_NO_MEMORY);
2460
2461
673
    ic->content_tag_map = _cairo_hash_table_create (_cairo_pdf_content_tag_equal);
2462
673
    if (unlikely (ic->content_tag_map == NULL))
2463
0
  return _cairo_error (CAIRO_STATUS_NO_MEMORY);
2464
2465
673
    _cairo_array_init (&ic->parent_tree, sizeof(cairo_pdf_resource_t));
2466
673
    _cairo_array_init (&ic->mcid_to_tree, sizeof(cairo_pdf_struct_tree_node_t *));
2467
673
    _cairo_array_init (&ic->annots, sizeof(cairo_pdf_annotation_t *));
2468
673
    ic->parent_tree_res.id = 0;
2469
673
    cairo_list_init (&ic->extents_list);
2470
673
    ic->named_dests = _cairo_hash_table_create (_named_dest_equal);
2471
673
    if (unlikely (ic->named_dests == NULL))
2472
0
  return _cairo_error (CAIRO_STATUS_NO_MEMORY);
2473
2474
673
    _cairo_array_init (&ic->page_commands, sizeof(cairo_pdf_command_list_t));
2475
673
    ic->current_commands = NULL;
2476
673
    _cairo_array_init (&ic->recording_surface_commands, sizeof(cairo_pdf_recording_surface_commands_t));
2477
2478
673
    ic->num_dests = 0;
2479
673
    ic->sorted_dests = NULL;
2480
673
    ic->dests_res.id = 0;
2481
673
    ic->ignore_current_surface = FALSE;
2482
673
    ic->content_emitted = FALSE;
2483
673
    ic->marked_content_open = FALSE;
2484
673
    ic->render_next_command_has_content = FALSE;
2485
673
    ic->mcid_order = 0;
2486
2487
673
    _cairo_array_init (&ic->outline, sizeof(cairo_pdf_outline_entry_t *));
2488
673
    outline_root = _cairo_calloc (sizeof(cairo_pdf_outline_entry_t));
2489
673
    if (unlikely (outline_root == NULL))
2490
0
  return _cairo_error (CAIRO_STATUS_NO_MEMORY);
2491
2492
673
    memset (&ic->docinfo, 0, sizeof (ic->docinfo));
2493
673
    _cairo_array_init (&ic->custom_metadata, sizeof(struct metadata));
2494
673
    _cairo_pdf_interchange_set_create_date (surface);
2495
673
    status = _cairo_array_append (&ic->outline, &outline_root);
2496
2497
673
    return status;
2498
673
}
2499
2500
static void
2501
_cairo_pdf_interchange_free_outlines (cairo_pdf_surface_t *surface)
2502
673
{
2503
673
    cairo_pdf_interchange_t *ic = &surface->interchange;
2504
673
    int num_elems, i;
2505
2506
673
    num_elems = _cairo_array_num_elements (&ic->outline);
2507
1.34k
    for (i = 0; i < num_elems; i++) {
2508
673
  cairo_pdf_outline_entry_t *outline;
2509
2510
673
  _cairo_array_copy_element (&ic->outline, i, &outline);
2511
673
  free (outline->name);
2512
673
  _cairo_tag_free_link_attributes (&outline->link_attrs);
2513
673
  free (outline);
2514
673
    }
2515
673
    _cairo_array_fini (&ic->outline);
2516
673
}
2517
2518
void
2519
_cairo_pdf_interchange_fini (cairo_pdf_surface_t *surface)
2520
673
{
2521
673
    cairo_pdf_interchange_t *ic = &surface->interchange;
2522
673
    unsigned int i, num_elems;
2523
673
    struct metadata *data;
2524
2525
673
    _cairo_tag_stack_fini (&ic->analysis_tag_stack);
2526
673
    _cairo_tag_stack_fini (&ic->render_tag_stack);
2527
673
    _cairo_array_fini (&ic->mcid_to_tree);
2528
673
    cairo_pdf_interchange_clear_annotations (surface);
2529
673
    _cairo_array_fini (&ic->annots);
2530
2531
673
    _cairo_array_fini (&ic->recording_surface_stack);
2532
673
    _cairo_array_fini (&ic->parent_tree);
2533
2534
673
    _cairo_hash_table_foreach (ic->command_to_node_map,
2535
673
             _cairo_pdf_command_pluck,
2536
673
             ic->command_to_node_map);
2537
673
    _cairo_hash_table_destroy (ic->command_to_node_map);
2538
2539
673
    _cairo_hash_table_foreach (ic->named_dests, _named_dest_pluck, ic->named_dests);
2540
673
    _cairo_hash_table_destroy (ic->named_dests);
2541
2542
673
    _cairo_hash_table_foreach (ic->content_tag_map, _cairo_pdf_content_tag_pluck, ic->content_tag_map);
2543
673
    _cairo_hash_table_destroy(ic->content_tag_map);
2544
2545
673
    free_node (ic->struct_root);
2546
2547
673
    num_elems = _cairo_array_num_elements (&ic->recording_surface_commands);
2548
673
    for (i = 0; i < num_elems; i++) {
2549
0
  cairo_pdf_recording_surface_commands_t *recording_command;
2550
0
  cairo_pdf_command_list_t *command_list;
2551
2552
0
  recording_command = _cairo_array_index (&ic->recording_surface_commands, i);
2553
0
  command_list = recording_command->command_list;
2554
0
  _cairo_array_fini (&command_list->commands);
2555
0
  free (command_list);
2556
0
    }
2557
673
    _cairo_array_fini (&ic->recording_surface_commands);
2558
2559
673
    num_elems = _cairo_array_num_elements (&ic->page_commands);
2560
2.69k
    for (i = 0; i < num_elems; i++) {
2561
2.02k
  cairo_pdf_command_list_t *command_list;
2562
2.02k
  command_list = _cairo_array_index (&ic->page_commands, i);
2563
2.02k
  _cairo_array_fini (&command_list->commands);
2564
2.02k
    }
2565
673
    _cairo_array_fini (&ic->page_commands);
2566
2567
673
    free (ic->sorted_dests);
2568
673
    _cairo_pdf_interchange_free_outlines (surface);
2569
673
    free (ic->docinfo.title);
2570
673
    free (ic->docinfo.author);
2571
673
    free (ic->docinfo.subject);
2572
673
    free (ic->docinfo.keywords);
2573
673
    free (ic->docinfo.creator);
2574
673
    free (ic->docinfo.create_date);
2575
673
    free (ic->docinfo.mod_date);
2576
2577
673
    num_elems = _cairo_array_num_elements (&ic->custom_metadata);
2578
673
    for (i = 0; i < num_elems; i++) {
2579
0
  data = _cairo_array_index (&ic->custom_metadata, i);
2580
0
  free (data->name);
2581
0
  free (data->value);
2582
0
    }
2583
673
    _cairo_array_fini (&ic->custom_metadata);
2584
673
}
2585
2586
cairo_int_status_t
2587
_cairo_pdf_interchange_add_outline (cairo_pdf_surface_t        *surface,
2588
            int                         parent_id,
2589
            const char                 *name,
2590
            const char                 *link_attribs,
2591
            cairo_pdf_outline_flags_t   flags,
2592
            int                        *id)
2593
0
{
2594
0
    cairo_pdf_interchange_t *ic = &surface->interchange;
2595
0
    cairo_pdf_outline_entry_t *outline;
2596
0
    cairo_pdf_outline_entry_t *parent;
2597
0
    cairo_int_status_t status;
2598
2599
0
    if (parent_id < 0 || parent_id >= (int)_cairo_array_num_elements (&ic->outline))
2600
0
  return CAIRO_STATUS_SUCCESS;
2601
2602
0
    outline = _cairo_calloc (sizeof(cairo_pdf_outline_entry_t));
2603
0
    if (unlikely (outline == NULL))
2604
0
  return _cairo_error (CAIRO_STATUS_NO_MEMORY);
2605
2606
0
    status = _cairo_tag_parse_link_attributes (link_attribs, &outline->link_attrs);
2607
0
    if (unlikely (status)) {
2608
0
  free (outline);
2609
0
  return status;
2610
0
    }
2611
2612
0
    outline->res = _cairo_pdf_surface_new_object (surface);
2613
0
    if (outline->res.id == 0)
2614
0
  return _cairo_error (CAIRO_STATUS_NO_MEMORY);
2615
2616
0
    outline->name = strdup (name);
2617
0
    outline->flags = flags;
2618
0
    outline->count = 0;
2619
2620
0
    _cairo_array_copy_element (&ic->outline, parent_id, &parent);
2621
2622
0
    outline->parent = parent;
2623
0
    outline->first_child = NULL;
2624
0
    outline->last_child = NULL;
2625
0
    outline->next = NULL;
2626
0
    if (parent->last_child) {
2627
0
  parent->last_child->next = outline;
2628
0
  outline->prev = parent->last_child;
2629
0
  parent->last_child = outline;
2630
0
    } else {
2631
0
  parent->first_child = outline;
2632
0
  parent->last_child = outline;
2633
0
  outline->prev = NULL;
2634
0
    }
2635
2636
0
    *id = _cairo_array_num_elements (&ic->outline);
2637
0
    status = _cairo_array_append (&ic->outline, &outline);
2638
0
    if (unlikely (status))
2639
0
  return status;
2640
2641
    /* Update Count */
2642
0
    outline = outline->parent;
2643
0
    while (outline) {
2644
0
  if (outline->flags & CAIRO_PDF_OUTLINE_FLAG_OPEN) {
2645
0
      outline->count++;
2646
0
  } else {
2647
0
      outline->count--;
2648
0
      break;
2649
0
  }
2650
0
  outline = outline->parent;
2651
0
    }
2652
2653
0
    return CAIRO_STATUS_SUCCESS;
2654
0
}
2655
2656
/*
2657
 * Date must be in the following format:
2658
 *
2659
 *     YYYY-MM-DDThh:mm:ss[Z+-]hh:mm
2660
 *
2661
 * Only the year is required. If a field is included all preceding
2662
 * fields must be included.
2663
 */
2664
static char *
2665
iso8601_to_pdf_date_string (const char *iso)
2666
0
{
2667
0
    char buf[40];
2668
0
    const char *p;
2669
0
    int i;
2670
2671
    /* Check that utf8 contains only the characters "0123456789-T:Z+" */
2672
0
    p = iso;
2673
0
    while (*p) {
2674
0
       if (!_cairo_isdigit (*p) && *p != '-' && *p != 'T' &&
2675
0
           *p != ':' && *p != 'Z' && *p != '+')
2676
0
           return NULL;
2677
0
       p++;
2678
0
    }
2679
2680
0
    p = iso;
2681
0
    strcpy (buf, "(");
2682
2683
   /* YYYY (required) */
2684
0
    if (strlen (p) < 4)
2685
0
       return NULL;
2686
2687
0
    strncat (buf, p, 4);
2688
0
    p += 4;
2689
2690
    /* -MM, -DD, Thh, :mm, :ss */
2691
0
    for (i = 0; i < 5; i++) {
2692
0
  if (strlen (p) < 3)
2693
0
      goto finish;
2694
2695
0
  strncat (buf, p + 1, 2);
2696
0
  p += 3;
2697
0
    }
2698
2699
    /* Z, +, - */
2700
0
    if (strlen (p) < 1)
2701
0
       goto finish;
2702
0
    strncat (buf, p, 1);
2703
0
    p += 1;
2704
2705
    /* hh */
2706
0
    if (strlen (p) < 2)
2707
0
  goto finish;
2708
2709
0
    strncat (buf, p, 2);
2710
0
    strcat (buf, "'");
2711
0
    p += 2;
2712
2713
    /* :mm */
2714
0
    if (strlen (p) < 3)
2715
0
  goto finish;
2716
2717
0
    strncat (buf, p + 1, 2);
2718
0
    strcat (buf, "'");
2719
2720
0
  finish:
2721
0
    strcat (buf, ")");
2722
0
    return strdup (buf);
2723
0
}
2724
2725
cairo_int_status_t
2726
_cairo_pdf_interchange_set_metadata (cairo_pdf_surface_t  *surface,
2727
             cairo_pdf_metadata_t  metadata,
2728
             const char           *utf8)
2729
0
{
2730
0
    cairo_pdf_interchange_t *ic = &surface->interchange;
2731
0
    cairo_status_t status;
2732
0
    char *s = NULL;
2733
2734
0
    if (utf8) {
2735
0
  if (metadata == CAIRO_PDF_METADATA_CREATE_DATE ||
2736
0
      metadata == CAIRO_PDF_METADATA_MOD_DATE) {
2737
0
      s = iso8601_to_pdf_date_string (utf8);
2738
0
  } else {
2739
0
      status = _cairo_utf8_to_pdf_string (utf8, &s);
2740
0
      if (unlikely (status))
2741
0
    return status;
2742
0
  }
2743
0
    }
2744
2745
0
    switch (metadata) {
2746
0
  case CAIRO_PDF_METADATA_TITLE:
2747
0
      free (ic->docinfo.title);
2748
0
      ic->docinfo.title = s;
2749
0
      break;
2750
0
  case CAIRO_PDF_METADATA_AUTHOR:
2751
0
      free (ic->docinfo.author);
2752
0
      ic->docinfo.author = s;
2753
0
      break;
2754
0
  case CAIRO_PDF_METADATA_SUBJECT:
2755
0
      free (ic->docinfo.subject);
2756
0
      ic->docinfo.subject = s;
2757
0
      break;
2758
0
  case CAIRO_PDF_METADATA_KEYWORDS:
2759
0
      free (ic->docinfo.keywords);
2760
0
      ic->docinfo.keywords = s;
2761
0
      break;
2762
0
  case CAIRO_PDF_METADATA_CREATOR:
2763
0
      free (ic->docinfo.creator);
2764
0
      ic->docinfo.creator = s;
2765
0
      break;
2766
0
  case CAIRO_PDF_METADATA_CREATE_DATE:
2767
0
      free (ic->docinfo.create_date);
2768
0
      ic->docinfo.create_date = s;
2769
0
      break;
2770
0
  case CAIRO_PDF_METADATA_MOD_DATE:
2771
0
      free (ic->docinfo.mod_date);
2772
0
      ic->docinfo.mod_date = s;
2773
0
      break;
2774
0
    }
2775
2776
0
    return CAIRO_STATUS_SUCCESS;
2777
0
}
2778
2779
static const char *reserved_metadata_names[] = {
2780
    "",
2781
    "Title",
2782
    "Author",
2783
    "Subject",
2784
    "Keywords",
2785
    "Creator",
2786
    "Producer",
2787
    "CreationDate",
2788
    "ModDate",
2789
    "Trapped",
2790
};
2791
2792
cairo_int_status_t
2793
_cairo_pdf_interchange_set_custom_metadata (cairo_pdf_surface_t  *surface,
2794
              const char           *name,
2795
              const char           *value)
2796
0
{
2797
0
    cairo_pdf_interchange_t *ic = &surface->interchange;
2798
0
    struct metadata *data;
2799
0
    struct metadata new_data;
2800
0
    int i, num_elems;
2801
0
    cairo_int_status_t status;
2802
0
    char *s = NULL;
2803
2804
0
    if (name == NULL)
2805
0
  return CAIRO_STATUS_NULL_POINTER;
2806
2807
0
    for (i = 0; i < ARRAY_LENGTH (reserved_metadata_names); i++) {
2808
0
  if (strcmp(name, reserved_metadata_names[i]) == 0)
2809
0
      return CAIRO_STATUS_INVALID_STRING;
2810
0
    }
2811
2812
    /* First check if we already have an entry for this name. If so,
2813
     * update the value. A NULL value means the entry has been removed
2814
     * and will not be emitted. */
2815
0
    num_elems = _cairo_array_num_elements (&ic->custom_metadata);
2816
0
    for (i = 0; i < num_elems; i++) {
2817
0
  data = _cairo_array_index (&ic->custom_metadata, i);
2818
0
  if (strcmp(name, data->name) == 0) {
2819
0
      free (data->value);
2820
0
      data->value = NULL;
2821
0
      if (value && strlen(value)) {
2822
0
    status = _cairo_utf8_to_pdf_string (value, &s);
2823
0
    if (unlikely (status))
2824
0
        return status;
2825
0
    data->value = s;
2826
0
      }
2827
0
      return CAIRO_STATUS_SUCCESS;
2828
0
  }
2829
0
    }
2830
2831
    /* Add new entry */
2832
0
    status = CAIRO_STATUS_SUCCESS;
2833
0
    if (value && strlen(value)) {
2834
0
  new_data.name = strdup (name);
2835
0
  status = _cairo_utf8_to_pdf_string (value, &s);
2836
0
  if (unlikely (status)) {
2837
0
            free (new_data.name);
2838
0
      return status;
2839
0
        }
2840
0
  new_data.value = s;
2841
0
  status = _cairo_array_append (&ic->custom_metadata, &new_data);
2842
0
    }
2843
2844
0
    return status;
2845
0
}
2846
2847
#if DEBUG_PDF_INTERCHANGE
2848
static cairo_int_status_t
2849
print_node (cairo_pdf_surface_t          *surface,
2850
      cairo_pdf_struct_tree_node_t *node,
2851
      int                           depth)
2852
{
2853
    if (node == NULL) {
2854
  printf("%*sNode: ptr: NULL\n", depth*2, "");
2855
    } else if (node == surface->interchange.struct_root) {
2856
       printf("%*sNode: ptr: %p root\n", depth*2, "", node);
2857
    } else {
2858
       printf("%*sNode: ptr: %p name: '%s'\n", depth*2, "", node, node->name);
2859
    }
2860
    depth++;
2861
    printf("%*sType: ", depth*2, "");
2862
    switch (node->type) {
2863
  case PDF_NODE_STRUCT:
2864
      printf("STRUCT\n");
2865
      break;
2866
  case PDF_NODE_CONTENT:
2867
      printf("CONTENT\n");
2868
      printf("%*sContent.id: %s\n", depth*2, "", node->attributes.content.id);
2869
      printf("%*sContent.tag_name: %s\n", depth*2, "", node->attributes.content.tag_name);
2870
      break;
2871
  case PDF_NODE_CONTENT_REF:
2872
      printf("CONTENT_REF\n");
2873
      printf("%*sContent_Ref.ref: %s\n", depth*2, "", node->attributes.content_ref.ref);
2874
      break;
2875
  case PDF_NODE_ARTIFACT:
2876
      printf("ARTIFACT\n");
2877
      break;
2878
    }
2879
    printf("%*sres: %d\n", depth*2, "", node->res.id);
2880
    printf("%*sparent: %p\n", depth*2, "", node->parent);
2881
    printf("%*sannot:", depth*2, "");
2882
    if (node->annot)
2883
  printf(" node: %p res: %d", node->annot->node,  node->annot->res.id);
2884
    printf("\n");
2885
    printf("%*sextents: ", depth*2, "");
2886
    if (node->extents.valid) {
2887
  printf("x: %d  y: %d  w: %d  h: %d\n",
2888
         node->extents.extents.x,
2889
         node->extents.extents.y,
2890
         node->extents.extents.width,
2891
         node->extents.extents.height);
2892
    } else {
2893
  printf("not valid\n");
2894
    }
2895
2896
    printf("%*smcid: ", depth*2, "");
2897
    int num_mcid = _cairo_array_num_elements (&node->mcid);
2898
    for (int i = 0; i < num_mcid; i++) {
2899
  cairo_pdf_page_mcid_t *mcid_elem = _cairo_array_index (&node->mcid, i);
2900
  if (mcid_elem->child_node) {
2901
      printf("(order: %d, %p) ", mcid_elem->order, mcid_elem->child_node);
2902
  } else {
2903
      printf("(order: %d, pg: %d, xobject_res: %d, mcid: %d) ",
2904
       mcid_elem->order, mcid_elem->page, mcid_elem->xobject_res.id, mcid_elem->mcid);
2905
  }
2906
    }
2907
    printf("\n");
2908
    return CAIRO_STATUS_SUCCESS;
2909
}
2910
2911
static void
2912
print_tree (cairo_pdf_surface_t          *surface,
2913
      cairo_pdf_struct_tree_node_t *node)
2914
{
2915
    printf("Structure Tree:\n");
2916
    cairo_pdf_interchange_walk_struct_tree (surface, node, 0, print_node);
2917
}
2918
2919
static void
2920
print_command (cairo_pdf_command_t *command, int indent)
2921
{
2922
    printf("%*s%d  ", indent*2, "", command->command_id);
2923
    switch (command->flags) {
2924
  case PDF_CONTENT:
2925
      printf("CONTENT");
2926
      break;
2927
  case PDF_BEGIN:
2928
      printf("BEGIN");
2929
      break;
2930
  case PDF_END:
2931
      printf("END");
2932
    break;
2933
  case PDF_GROUP:
2934
      printf("GROUP: %p", command->group);
2935
      break;
2936
  case PDF_NONE:
2937
      printf("NONE");
2938
      break;
2939
    }
2940
    printf("  node: %p index: %d\n", command->node, command->mcid_index);
2941
}
2942
2943
static void
2944
print_commands (cairo_pdf_command_list_t *command_list, int indent)
2945
{
2946
    cairo_pdf_command_t *command;
2947
    unsigned i;
2948
    unsigned num_elements = _cairo_array_num_elements (&command_list->commands);
2949
2950
    for (i = 0; i < num_elements; i++) {
2951
  command = _cairo_array_index (&command_list->commands, i);
2952
  print_command (command, indent);
2953
  if (command->flags == PDF_GROUP)
2954
      print_commands (command->group, indent + 1);
2955
    }
2956
}
2957
2958
static void
2959
print_command_list(cairo_pdf_command_list_t *command_list)
2960
{
2961
    printf("Command List: %p\n", command_list);
2962
    print_commands (command_list, 0);
2963
    printf("end\n");
2964
}
2965
#endif