Coverage Report

Created: 2023-06-07 06:20

/src/mupdf/source/pdf/pdf-annot.c
Line
Count
Source (jump to first uncovered line)
1
// Copyright (C) 2004-2023 Artifex Software, Inc.
2
//
3
// This file is part of MuPDF.
4
//
5
// MuPDF is free software: you can redistribute it and/or modify it under the
6
// terms of the GNU Affero General Public License as published by the Free
7
// Software Foundation, either version 3 of the License, or (at your option)
8
// any later version.
9
//
10
// MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY
11
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12
// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
13
// details.
14
//
15
// You should have received a copy of the GNU Affero General Public License
16
// along with MuPDF. If not, see <https://www.gnu.org/licenses/agpl-3.0.en.html>
17
//
18
// Alternative licensing terms are available from the licensor.
19
// For commercial licensing, see <https://www.artifex.com/> or contact
20
// Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco,
21
// CA 94129, USA, for further information.
22
23
#include "mupdf/fitz.h"
24
#include "pdf-annot-imp.h"
25
26
#include <string.h>
27
28
pdf_annot *
29
pdf_keep_annot(fz_context *ctx, pdf_annot *annot)
30
0
{
31
0
  return fz_keep_imp(ctx, annot, &annot->refs);
32
0
}
33
34
void
35
pdf_drop_annot(fz_context *ctx, pdf_annot *annot)
36
13.4k
{
37
13.4k
  if (fz_drop_imp(ctx, annot, &annot->refs))
38
13.4k
  {
39
13.4k
    pdf_drop_obj(ctx, annot->obj);
40
13.4k
    fz_free(ctx, annot);
41
13.4k
  }
42
13.4k
}
43
44
void
45
pdf_drop_annots(fz_context *ctx, pdf_annot *annot)
46
17.1k
{
47
18.6k
  while (annot)
48
1.45k
  {
49
1.45k
    pdf_annot *next = annot->next;
50
1.45k
    pdf_drop_annot(ctx, annot);
51
1.45k
    annot = next;
52
1.45k
  }
53
17.1k
}
54
55
pdf_obj *
56
pdf_annot_ap(fz_context *ctx, pdf_annot *annot)
57
63.5k
{
58
63.5k
  int flags = pdf_dict_get_int(ctx, annot->obj, PDF_NAME(F));
59
63.5k
  int readonly = flags & PDF_ANNOT_IS_READ_ONLY;
60
61
63.5k
  pdf_obj *ap = pdf_dict_get(ctx, annot->obj, PDF_NAME(AP));
62
63.5k
  pdf_obj *ap_n = pdf_dict_get(ctx, ap, PDF_NAME(N));
63
63.5k
  pdf_obj *ap_r = pdf_dict_get(ctx, ap, PDF_NAME(R));
64
63.5k
  pdf_obj *ap_d = pdf_dict_get(ctx, ap, PDF_NAME(D));
65
66
63.5k
  if (!readonly && annot->is_hot && annot->is_active && ap_d)
67
0
    ap = ap_d;
68
63.5k
  else if (!readonly && annot->is_hot && ap_r)
69
0
    ap = ap_r;
70
63.5k
  else
71
63.5k
    ap = ap_n;
72
73
  /* AP/N, AP/R and AP/D may be streams, or dictionaries of streams. */
74
75
  /* If it's a stream, we have a winner! */
76
63.5k
  if (pdf_is_indirect(ctx, ap) && pdf_obj_num_is_stream(ctx, annot->page->doc, pdf_to_num(ctx, ap)))
77
50.2k
    return ap;
78
79
  /* If it's not a stream, it may be a dictionary containing
80
   * a range of possible values, that should be indexed by
81
   * AS. */
82
13.3k
  return pdf_dict_get(ctx, ap, pdf_dict_get(ctx, annot->obj, PDF_NAME(AS)));
83
63.5k
}
84
85
int pdf_annot_active(fz_context *ctx, pdf_annot *annot)
86
0
{
87
0
  return annot ? annot->is_active : 0;
88
0
}
89
90
void pdf_set_annot_active(fz_context *ctx, pdf_annot *annot, int active)
91
0
{
92
0
  int old;
93
94
0
  if (!annot)
95
0
    return;
96
97
0
  old = annot->is_active;
98
0
  annot->is_active = !!active;
99
0
  if (old != annot->is_active)
100
0
    pdf_set_annot_has_changed(ctx, annot);
101
0
}
102
103
int pdf_annot_hot(fz_context *ctx, pdf_annot *annot)
104
0
{
105
0
  return annot ? annot->is_hot : 0;
106
0
}
107
108
void pdf_set_annot_hot(fz_context *ctx, pdf_annot *annot, int hot)
109
0
{
110
0
  int old;
111
112
0
  if (!annot)
113
0
    return;
114
115
0
  old = annot->is_hot;
116
0
  annot->is_hot = !!hot;
117
0
  if (old != annot->is_hot)
118
0
    pdf_set_annot_has_changed(ctx, annot);
119
0
}
120
121
fz_matrix
122
pdf_annot_transform(fz_context *ctx, pdf_annot *annot)
123
12.3k
{
124
12.3k
  fz_rect bbox, rect;
125
12.3k
  fz_matrix matrix;
126
12.3k
  float w, h, x, y;
127
12.3k
  pdf_obj *ap = pdf_annot_ap(ctx, annot);
128
129
12.3k
  rect = pdf_dict_get_rect(ctx, annot->obj, PDF_NAME(Rect));
130
12.3k
  bbox = pdf_xobject_bbox(ctx, ap);
131
12.3k
  matrix = pdf_xobject_matrix(ctx, ap);
132
133
12.3k
  bbox = fz_transform_rect(bbox, matrix);
134
12.3k
  if (bbox.x1 == bbox.x0)
135
21
    w = 0;
136
12.2k
  else
137
12.2k
    w = (rect.x1 - rect.x0) / (bbox.x1 - bbox.x0);
138
12.3k
  if (bbox.y1 == bbox.y0)
139
21
    h = 0;
140
12.2k
  else
141
12.2k
    h = (rect.y1 - rect.y0) / (bbox.y1 - bbox.y0);
142
12.3k
  x = rect.x0 - (bbox.x0 * w);
143
12.3k
  y = rect.y0 - (bbox.y0 * h);
144
145
12.3k
  return fz_pre_scale(fz_translate(x, y), w, h);
146
12.3k
}
147
148
/*
149
  Internal function for creating a new pdf annotation.
150
*/
151
static pdf_annot *
152
pdf_new_annot(fz_context *ctx, pdf_page *page, pdf_obj *obj)
153
13.4k
{
154
13.4k
  pdf_annot *annot;
155
156
13.4k
  annot = fz_malloc_struct(ctx, pdf_annot);
157
13.4k
  annot->refs = 1;
158
13.4k
  annot->page = page; /* only borrowed, as the page owns the annot */
159
13.4k
  annot->obj = pdf_keep_obj(ctx, obj);
160
161
13.4k
  return annot;
162
13.4k
}
163
164
void
165
pdf_load_annots(fz_context *ctx, pdf_page *page, pdf_obj *annots)
166
1.56k
{
167
1.56k
  pdf_annot *annot;
168
1.56k
  pdf_obj *subtype;
169
1.56k
  int i, n;
170
171
1.56k
  n = pdf_array_len(ctx, annots);
172
23.2k
  for (i = 0; i < n; ++i)
173
21.7k
  {
174
21.7k
    pdf_obj *obj = pdf_array_get(ctx, annots, i);
175
21.7k
    if (pdf_is_dict(ctx, obj))
176
15.4k
    {
177
15.4k
      subtype = pdf_dict_get(ctx, obj, PDF_NAME(Subtype));
178
15.4k
      if (pdf_name_eq(ctx, subtype, PDF_NAME(Link)))
179
1.60k
        continue;
180
13.8k
      if (pdf_name_eq(ctx, subtype, PDF_NAME(Popup)))
181
451
        continue;
182
183
13.4k
      annot = pdf_new_annot(ctx, page, obj);
184
13.4k
      if (pdf_name_eq(ctx, subtype, PDF_NAME(Widget)))
185
11.9k
      {
186
11.9k
        *page->widget_tailp = annot;
187
11.9k
        page->widget_tailp = &annot->next;
188
11.9k
      }
189
1.45k
      else
190
1.45k
      {
191
1.45k
        *page->annot_tailp = annot;
192
1.45k
        page->annot_tailp = &annot->next;
193
1.45k
      }
194
13.4k
    }
195
21.7k
  }
196
197
  /* We need to run a resynth pass on the annotations on this
198
   * page. That means rerunning it on the complete document. */
199
1.56k
  page->doc->resynth_required = 1;
200
  /* And actually update the page so that any annotations required
201
   * get synthesised. */
202
1.56k
  pdf_update_page(ctx, page);
203
1.56k
}
204
205
pdf_annot *
206
pdf_first_annot(fz_context *ctx, pdf_page *page)
207
1.78k
{
208
1.78k
  return page ? page->annots : NULL;
209
1.78k
}
210
211
pdf_annot *
212
pdf_next_annot(fz_context *ctx, pdf_annot *annot)
213
2.91k
{
214
2.91k
  return annot ? annot->next : NULL;
215
2.91k
}
216
217
pdf_obj *pdf_annot_obj(fz_context *ctx, pdf_annot *annot)
218
0
{
219
0
  return annot ? annot->obj : NULL;
220
0
}
221
222
pdf_page *pdf_annot_page(fz_context *ctx, pdf_annot *annot)
223
0
{
224
0
  return annot ? annot->page : NULL;
225
0
}
226
227
fz_rect
228
pdf_bound_annot(fz_context *ctx, pdf_annot *annot)
229
0
{
230
0
  fz_matrix page_ctm;
231
0
  fz_rect rect;
232
0
  int flags;
233
234
0
  pdf_annot_push_local_xref(ctx, annot);
235
236
0
  fz_try(ctx)
237
0
  {
238
0
    rect = pdf_dict_get_rect(ctx, annot->obj, PDF_NAME(Rect));
239
0
    pdf_page_transform(ctx, annot->page, NULL, &page_ctm);
240
241
0
    flags = pdf_dict_get_int(ctx, annot->obj, PDF_NAME(F));
242
0
    if (flags & PDF_ANNOT_IS_NO_ROTATE)
243
0
    {
244
0
      int rotate = pdf_to_int(ctx, pdf_dict_get_inheritable(ctx, annot->page->obj, PDF_NAME(Rotate)));
245
0
      fz_point tp = fz_transform_point_xy(rect.x0, rect.y1, page_ctm);
246
0
      page_ctm = fz_concat(page_ctm, fz_translate(-tp.x, -tp.y));
247
0
      page_ctm = fz_concat(page_ctm, fz_rotate(-rotate));
248
0
      page_ctm = fz_concat(page_ctm, fz_translate(tp.x, tp.y));
249
0
    }
250
0
  }
251
0
  fz_always(ctx)
252
0
    pdf_annot_pop_local_xref(ctx, annot);
253
0
  fz_catch(ctx)
254
0
    fz_rethrow(ctx);
255
256
0
  return fz_transform_rect(rect, page_ctm);
257
0
}
258
259
void
260
pdf_annot_request_resynthesis(fz_context *ctx, pdf_annot *annot)
261
0
{
262
0
  if (annot == NULL)
263
0
    return;
264
265
  /* If there are no changes, there is no need to request a resynthesis
266
   * (and indeed, we must not, because any changes caused by the resynth
267
   * will go in as implicit changes into a potentially-non-existent
268
   * previous journal fragment). */
269
0
  if (!pdf_has_unsaved_changes(ctx, annot->page->doc))
270
0
    return;
271
272
0
  annot->needs_new_ap = 1;
273
0
  annot->page->doc->resynth_required = 1;
274
0
}
275
276
int
277
pdf_annot_needs_resynthesis(fz_context *ctx, pdf_annot *annot)
278
26.8k
{
279
26.8k
  return annot ? annot->needs_new_ap : 0;
280
26.8k
}
281
282
void pdf_set_annot_resynthesised(fz_context *ctx, pdf_annot *annot)
283
6.82k
{
284
6.82k
  if (annot == NULL)
285
0
    return;
286
287
6.82k
  annot->needs_new_ap = 0;
288
6.82k
  pdf_set_annot_has_changed(ctx, annot);
289
6.82k
}
290
291
void pdf_set_annot_has_changed(fz_context *ctx, pdf_annot *annot)
292
6.82k
{
293
6.82k
  if (annot == NULL)
294
0
    return;
295
296
6.82k
  annot->has_new_ap = 1;
297
6.82k
}
298
299
void
300
pdf_dirty_annot(fz_context *ctx, pdf_annot *annot)
301
0
{
302
0
  pdf_annot_request_resynthesis(ctx, annot);
303
0
}
304
305
const char *
306
pdf_string_from_annot_type(fz_context *ctx, enum pdf_annot_type type)
307
0
{
308
0
  switch (type)
309
0
  {
310
0
  case PDF_ANNOT_TEXT: return "Text";
311
0
  case PDF_ANNOT_LINK: return "Link";
312
0
  case PDF_ANNOT_FREE_TEXT: return "FreeText";
313
0
  case PDF_ANNOT_LINE: return "Line";
314
0
  case PDF_ANNOT_SQUARE: return "Square";
315
0
  case PDF_ANNOT_CIRCLE: return "Circle";
316
0
  case PDF_ANNOT_POLYGON: return "Polygon";
317
0
  case PDF_ANNOT_POLY_LINE: return "PolyLine";
318
0
  case PDF_ANNOT_HIGHLIGHT: return "Highlight";
319
0
  case PDF_ANNOT_UNDERLINE: return "Underline";
320
0
  case PDF_ANNOT_SQUIGGLY: return "Squiggly";
321
0
  case PDF_ANNOT_STRIKE_OUT: return "StrikeOut";
322
0
  case PDF_ANNOT_REDACT: return "Redact";
323
0
  case PDF_ANNOT_STAMP: return "Stamp";
324
0
  case PDF_ANNOT_CARET: return "Caret";
325
0
  case PDF_ANNOT_INK: return "Ink";
326
0
  case PDF_ANNOT_POPUP: return "Popup";
327
0
  case PDF_ANNOT_FILE_ATTACHMENT: return "FileAttachment";
328
0
  case PDF_ANNOT_SOUND: return "Sound";
329
0
  case PDF_ANNOT_MOVIE: return "Movie";
330
0
  case PDF_ANNOT_RICH_MEDIA: return "RichMedia";
331
0
  case PDF_ANNOT_WIDGET: return "Widget";
332
0
  case PDF_ANNOT_SCREEN: return "Screen";
333
0
  case PDF_ANNOT_PRINTER_MARK: return "PrinterMark";
334
0
  case PDF_ANNOT_TRAP_NET: return "TrapNet";
335
0
  case PDF_ANNOT_WATERMARK: return "Watermark";
336
0
  case PDF_ANNOT_3D: return "3D";
337
0
  case PDF_ANNOT_PROJECTION: return "Projection";
338
0
  default: return "UNKNOWN";
339
0
  }
340
0
}
341
342
int
343
pdf_annot_type_from_string(fz_context *ctx, const char *subtype)
344
19.9k
{
345
19.9k
  if (!strcmp("Text", subtype)) return PDF_ANNOT_TEXT;
346
19.5k
  if (!strcmp("Link", subtype)) return PDF_ANNOT_LINK;
347
19.5k
  if (!strcmp("FreeText", subtype)) return PDF_ANNOT_FREE_TEXT;
348
19.4k
  if (!strcmp("Line", subtype)) return PDF_ANNOT_LINE;
349
19.3k
  if (!strcmp("Square", subtype)) return PDF_ANNOT_SQUARE;
350
19.2k
  if (!strcmp("Circle", subtype)) return PDF_ANNOT_CIRCLE;
351
19.2k
  if (!strcmp("Polygon", subtype)) return PDF_ANNOT_POLYGON;
352
19.1k
  if (!strcmp("PolyLine", subtype)) return PDF_ANNOT_POLY_LINE;
353
19.1k
  if (!strcmp("Highlight", subtype)) return PDF_ANNOT_HIGHLIGHT;
354
18.7k
  if (!strcmp("Underline", subtype)) return PDF_ANNOT_UNDERLINE;
355
18.6k
  if (!strcmp("Squiggly", subtype)) return PDF_ANNOT_SQUIGGLY;
356
18.6k
  if (!strcmp("StrikeOut", subtype)) return PDF_ANNOT_STRIKE_OUT;
357
18.5k
  if (!strcmp("Redact", subtype)) return PDF_ANNOT_REDACT;
358
18.5k
  if (!strcmp("Stamp", subtype)) return PDF_ANNOT_STAMP;
359
18.5k
  if (!strcmp("Caret", subtype)) return PDF_ANNOT_CARET;
360
18.4k
  if (!strcmp("Ink", subtype)) return PDF_ANNOT_INK;
361
18.3k
  if (!strcmp("Popup", subtype)) return PDF_ANNOT_POPUP;
362
18.3k
  if (!strcmp("FileAttachment", subtype)) return PDF_ANNOT_FILE_ATTACHMENT;
363
18.3k
  if (!strcmp("Sound", subtype)) return PDF_ANNOT_SOUND;
364
18.3k
  if (!strcmp("Movie", subtype)) return PDF_ANNOT_MOVIE;
365
18.3k
  if (!strcmp("RichMedia", subtype)) return PDF_ANNOT_RICH_MEDIA;
366
18.3k
  if (!strcmp("Widget", subtype)) return PDF_ANNOT_WIDGET;
367
1.41k
  if (!strcmp("Screen", subtype)) return PDF_ANNOT_SCREEN;
368
1.41k
  if (!strcmp("PrinterMark", subtype)) return PDF_ANNOT_PRINTER_MARK;
369
1.41k
  if (!strcmp("TrapNet", subtype)) return PDF_ANNOT_TRAP_NET;
370
1.41k
  if (!strcmp("Watermark", subtype)) return PDF_ANNOT_WATERMARK;
371
1.41k
  if (!strcmp("3D", subtype)) return PDF_ANNOT_3D;
372
1.41k
  if (!strcmp("Projection", subtype)) return PDF_ANNOT_PROJECTION;
373
1.41k
  return PDF_ANNOT_UNKNOWN;
374
1.41k
}
375
376
static void
377
begin_annot_op(fz_context *ctx, pdf_annot *annot, const char *op)
378
5.89k
{
379
5.89k
  pdf_begin_operation(ctx, annot->page->doc, op);
380
5.89k
}
381
382
static void
383
end_annot_op(fz_context *ctx, pdf_annot *annot)
384
5.88k
{
385
5.88k
  pdf_end_operation(ctx, annot->page->doc);
386
5.88k
}
387
388
static void
389
abandon_annot_op(fz_context *ctx, pdf_annot *annot)
390
10
{
391
10
  pdf_abandon_operation(ctx, annot->page->doc);
392
10
}
393
394
static int is_allowed_subtype(fz_context *ctx, pdf_annot *annot, pdf_obj *property, pdf_obj **allowed)
395
333
{
396
333
  pdf_obj *subtype;
397
398
333
  subtype = pdf_dict_get(ctx, annot->obj, PDF_NAME(Subtype));
399
1.09k
  while (*allowed) {
400
1.09k
    if (pdf_name_eq(ctx, subtype, *allowed))
401
333
      return 1;
402
766
    allowed++;
403
766
  }
404
405
0
  return 0;
406
333
}
407
408
static int is_allowed_subtype_wrap(fz_context *ctx, pdf_annot *annot, pdf_obj *property, pdf_obj **allowed)
409
0
{
410
0
  int ret;
411
412
0
  pdf_annot_push_local_xref(ctx, annot);
413
414
0
  fz_try(ctx)
415
0
    ret = is_allowed_subtype(ctx, annot, property, allowed);
416
0
  fz_always(ctx)
417
0
    pdf_annot_pop_local_xref(ctx, annot);
418
0
  fz_catch(ctx)
419
0
    fz_rethrow(ctx);
420
421
0
  return ret;
422
0
}
423
424
static void check_allowed_subtypes(fz_context *ctx, pdf_annot *annot, pdf_obj *property, pdf_obj **allowed)
425
333
{
426
333
  pdf_obj *subtype;
427
428
333
  subtype = pdf_dict_get(ctx, annot->obj, PDF_NAME(Subtype));
429
333
  if (!is_allowed_subtype(ctx, annot, property, allowed))
430
0
    fz_throw(ctx, FZ_ERROR_GENERIC, "%s annotations have no %s property", pdf_to_name(ctx, subtype), pdf_to_name(ctx, property));
431
333
}
432
433
pdf_annot *
434
pdf_create_annot_raw(fz_context *ctx, pdf_page *page, enum pdf_annot_type type)
435
0
{
436
0
  pdf_annot *annot = NULL;
437
0
  pdf_document *doc = page->doc;
438
0
  pdf_obj *annot_obj = pdf_new_dict(ctx, doc, 0);
439
0
  pdf_obj *ind_obj = NULL;
440
441
0
  fz_var(annot);
442
0
  fz_var(ind_obj);
443
0
  fz_try(ctx)
444
0
  {
445
0
    int ind_obj_num;
446
0
    const char *type_str;
447
0
    pdf_obj *annot_arr;
448
449
0
    type_str = pdf_string_from_annot_type(ctx, type);
450
0
    if (type == PDF_ANNOT_UNKNOWN)
451
0
      fz_throw(ctx, FZ_ERROR_GENERIC, "cannot create unknown annotation");
452
453
0
    annot_arr = pdf_dict_get(ctx, page->obj, PDF_NAME(Annots));
454
0
    if (annot_arr == NULL)
455
0
    {
456
0
      annot_arr = pdf_new_array(ctx, doc, 0);
457
0
      pdf_dict_put_drop(ctx, page->obj, PDF_NAME(Annots), annot_arr);
458
0
    }
459
460
0
    pdf_dict_put(ctx, annot_obj, PDF_NAME(Type), PDF_NAME(Annot));
461
0
    pdf_dict_put_name(ctx, annot_obj, PDF_NAME(Subtype), type_str);
462
463
    /*
464
      Both annotation object and annotation structure are now created.
465
      Insert the object in the hierarchy and the structure in the
466
      page's array.
467
    */
468
0
    ind_obj_num = pdf_create_object(ctx, doc);
469
0
    pdf_update_object(ctx, doc, ind_obj_num, annot_obj);
470
0
    ind_obj = pdf_new_indirect(ctx, doc, ind_obj_num, 0);
471
0
    pdf_array_push(ctx, annot_arr, ind_obj);
472
473
0
    annot = pdf_new_annot(ctx, page, ind_obj);
474
475
    /*
476
      Linking must be done after any call that might throw because
477
      pdf_drop_annots below actually frees a list. Put the new annot
478
      at the end of the list, so that it will be drawn last.
479
    */
480
0
    if (type == PDF_ANNOT_WIDGET)
481
0
    {
482
0
      *page->widget_tailp = annot;
483
0
      page->widget_tailp = &annot->next;
484
0
    }
485
0
    else
486
0
    {
487
0
      *page->annot_tailp = annot;
488
0
      page->annot_tailp = &annot->next;
489
0
    }
490
0
  }
491
0
  fz_always(ctx)
492
0
  {
493
0
    pdf_drop_obj(ctx, annot_obj);
494
0
    pdf_drop_obj(ctx, ind_obj);
495
0
  }
496
0
  fz_catch(ctx)
497
0
  {
498
0
    pdf_drop_annots(ctx, annot);
499
0
    fz_rethrow(ctx);
500
0
  }
501
502
0
  return pdf_keep_annot(ctx, annot);
503
0
}
504
505
fz_link *
506
pdf_create_link(fz_context *ctx, pdf_page *page, fz_rect bbox, const char *uri)
507
0
{
508
0
  fz_link *link = NULL;
509
0
  pdf_document *doc = page->doc;
510
0
  pdf_obj *annot_obj = pdf_new_dict(ctx, doc, 0);
511
0
  pdf_obj *ind_obj = NULL;
512
0
  pdf_obj *bs = NULL;
513
0
  pdf_obj *a = NULL;
514
0
  fz_link **linkp;
515
0
  fz_rect page_mediabox;
516
0
  fz_matrix page_ctm;
517
0
  fz_rect rect;
518
519
0
  fz_var(link);
520
0
  fz_var(ind_obj);
521
0
  fz_var(bs);
522
0
  fz_var(a);
523
524
0
  pdf_begin_operation(ctx, page->doc, "Create Link");
525
526
0
  fz_try(ctx)
527
0
  {
528
0
    int ind_obj_num;
529
0
    pdf_obj *annot_arr;
530
531
0
    pdf_page_transform(ctx, page, &page_mediabox, &page_ctm);
532
0
    page_ctm = fz_invert_matrix(page_ctm);
533
0
    rect = fz_transform_rect(bbox, page_ctm);
534
535
0
    annot_arr = pdf_dict_get(ctx, page->obj, PDF_NAME(Annots));
536
0
    if (annot_arr == NULL)
537
0
    {
538
0
      annot_arr = pdf_new_array(ctx, doc, 0);
539
0
      pdf_dict_put_drop(ctx, page->obj, PDF_NAME(Annots), annot_arr);
540
0
    }
541
542
0
    pdf_dict_put(ctx, annot_obj, PDF_NAME(Type), PDF_NAME(Annot));
543
0
    pdf_dict_put(ctx, annot_obj, PDF_NAME(Subtype), PDF_NAME(Link));
544
0
    pdf_dict_put_rect(ctx, annot_obj, PDF_NAME(Rect), rect);
545
0
    bs = pdf_new_dict(ctx, doc, 4);
546
0
    pdf_dict_put(ctx, bs, PDF_NAME(S), PDF_NAME(S));
547
0
    pdf_dict_put(ctx, bs, PDF_NAME(Type), PDF_NAME(Border));
548
0
    pdf_dict_put_int(ctx, bs, PDF_NAME(W), 0);
549
0
    pdf_dict_put(ctx, annot_obj, PDF_NAME(BS), bs);
550
551
0
    pdf_dict_put_drop(ctx, annot_obj, PDF_NAME(A),
552
0
      pdf_new_action_from_link(ctx, doc, uri));
553
554
    /*
555
      Both annotation object and annotation structure are now created.
556
      Insert the object in the hierarchy and the structure in the
557
      page's array.
558
    */
559
0
    ind_obj_num = pdf_create_object(ctx, doc);
560
0
    pdf_update_object(ctx, doc, ind_obj_num, annot_obj);
561
0
    ind_obj = pdf_new_indirect(ctx, doc, ind_obj_num, 0);
562
0
    pdf_array_push(ctx, annot_arr, ind_obj);
563
564
0
    link = (fz_link *) pdf_new_link(ctx, page, bbox, uri, annot_obj);
565
566
0
    linkp = &page->links;
567
568
0
    while (*linkp != NULL)
569
0
      linkp = &(*linkp)->next;
570
571
0
    *linkp = link;
572
0
    pdf_end_operation(ctx, page->doc);
573
0
  }
574
0
  fz_always(ctx)
575
0
  {
576
0
    pdf_drop_obj(ctx, bs);
577
0
    pdf_drop_obj(ctx, annot_obj);
578
0
    pdf_drop_obj(ctx, ind_obj);
579
0
  }
580
0
  fz_catch(ctx)
581
0
  {
582
0
    pdf_abandon_operation(ctx, page->doc);
583
0
    fz_rethrow(ctx);
584
0
  }
585
586
0
  return fz_keep_link(ctx, link);
587
0
}
588
589
void pdf_delete_link(fz_context *ctx, pdf_page *page, fz_link *link)
590
0
{
591
0
  fz_link **linkptr;
592
0
  pdf_obj *annots;
593
0
  int i;
594
595
0
  if (link == NULL || page == NULL || page != ((pdf_link *) link)->page)
596
0
    return;
597
598
0
  for (linkptr = &page->links; *linkptr; linkptr = &((*linkptr)->next))
599
0
  {
600
0
    if (*linkptr == link)
601
0
      break;
602
0
  }
603
604
0
  if (*linkptr == NULL)
605
0
    return;
606
607
0
  pdf_begin_operation(ctx, page->doc, "Delete Link");
608
609
0
  fz_try(ctx)
610
0
  {
611
612
0
    annots = pdf_dict_get(ctx, page->obj, PDF_NAME(Annots));
613
0
    i = pdf_array_find(ctx, annots, ((pdf_link *) link)->obj);
614
0
    if (i >= 0)
615
0
      pdf_array_delete(ctx, annots, i);
616
0
    *linkptr = link->next;
617
0
    link->next = NULL;
618
0
    fz_drop_link(ctx, link);
619
0
    pdf_end_operation(ctx, page->doc);
620
0
  }
621
0
  fz_catch(ctx)
622
0
  {
623
0
    pdf_abandon_operation(ctx, page->doc);
624
0
    fz_rethrow(ctx);
625
0
  }
626
0
}
627
628
static pdf_obj *
629
pdf_add_popup_annot(fz_context *ctx, pdf_annot *annot)
630
0
{
631
0
  pdf_obj *annots, *popup;
632
633
0
  popup = pdf_dict_get(ctx, annot->obj, PDF_NAME(Popup));
634
0
  if (popup)
635
0
    return popup;
636
637
0
  annots = pdf_dict_get(ctx, annot->page->obj, PDF_NAME(Annots));
638
0
  if (!annots)
639
0
    return NULL;
640
641
0
  popup = pdf_add_new_dict(ctx, annot->page->doc, 4);
642
0
  pdf_array_push_drop(ctx, annots, popup);
643
644
0
  pdf_dict_put(ctx, popup, PDF_NAME(Type), PDF_NAME(Annot));
645
0
  pdf_dict_put(ctx, popup, PDF_NAME(Subtype), PDF_NAME(Popup));
646
0
  pdf_dict_put(ctx, popup, PDF_NAME(Parent), annot->obj);
647
0
  pdf_dict_put_rect(ctx, popup, PDF_NAME(Rect), fz_make_rect(0,0,0,0));
648
649
0
  pdf_dict_put(ctx, annot->obj, PDF_NAME(Popup), popup);
650
651
0
  return popup;
652
0
}
653
654
void pdf_set_annot_popup(fz_context *ctx, pdf_annot *annot, fz_rect rect)
655
0
{
656
0
  fz_matrix page_ctm, inv_page_ctm;
657
0
  pdf_obj *popup;
658
0
  pdf_page_transform(ctx, annot->page, NULL, &page_ctm);
659
0
  inv_page_ctm = fz_invert_matrix(page_ctm);
660
0
  rect = fz_transform_rect(rect, inv_page_ctm);
661
0
  popup = pdf_add_popup_annot(ctx, annot);
662
0
  pdf_dict_put_rect(ctx, popup, PDF_NAME(Rect), rect);
663
0
}
664
665
fz_rect pdf_annot_popup(fz_context *ctx, pdf_annot *annot)
666
0
{
667
0
  fz_matrix page_ctm;
668
0
  fz_rect rect;
669
0
  pdf_obj *popup;
670
0
  pdf_page_transform(ctx, annot->page, NULL, &page_ctm);
671
0
  popup = pdf_dict_get(ctx, annot->obj, PDF_NAME(Popup));
672
0
  rect = pdf_dict_get_rect(ctx, popup, PDF_NAME(Rect));
673
0
  return fz_transform_rect(rect, page_ctm);
674
0
}
675
676
pdf_annot *
677
pdf_create_annot(fz_context *ctx, pdf_page *page, enum pdf_annot_type type)
678
0
{
679
0
  static const float black[3] = { 0, 0, 0 };
680
0
  static const float red[3] = { 1, 0, 0 };
681
0
  static const float green[3] = { 0, 1, 0 };
682
0
  static const float blue[3] = { 0, 0, 1 };
683
0
  static const float yellow[3] = { 1, 1, 0 };
684
0
  static const float magenta[3] = { 1, 0, 1 };
685
686
0
  int flags = PDF_ANNOT_IS_PRINT; /* Make printable as default */
687
688
0
  pdf_annot *annot;
689
690
0
  pdf_begin_operation(ctx, page->doc, "Create Annotation");
691
692
0
  fz_try(ctx)
693
0
  {
694
0
    annot = pdf_create_annot_raw(ctx, page, type);
695
696
0
    switch (type)
697
0
    {
698
0
    default:
699
0
      break;
700
701
0
    case PDF_ANNOT_TEXT:
702
0
    case PDF_ANNOT_FILE_ATTACHMENT:
703
0
    case PDF_ANNOT_SOUND:
704
0
      {
705
0
        fz_rect icon_rect = { 12, 12, 12+20, 12+20 };
706
0
        flags = PDF_ANNOT_IS_PRINT | PDF_ANNOT_IS_NO_ZOOM | PDF_ANNOT_IS_NO_ROTATE;
707
0
        pdf_set_annot_rect(ctx, annot, icon_rect);
708
0
        pdf_set_annot_color(ctx, annot, 3, yellow);
709
0
        pdf_set_annot_popup(ctx, annot, fz_make_rect(32, 12, 32+200, 12+100));
710
0
      }
711
0
      break;
712
713
0
    case PDF_ANNOT_FREE_TEXT:
714
0
      {
715
0
        fz_rect text_rect = { 12, 12, 12+200, 12+100 };
716
717
        /* Use undocumented Adobe property to match page rotation. */
718
0
        int rot = pdf_to_int(ctx, pdf_dict_get_inheritable(ctx, page->obj, PDF_NAME(Rotate)));
719
0
        if (rot != 0)
720
0
          pdf_dict_put_int(ctx, annot->obj, PDF_NAME(Rotate), rot);
721
722
0
        pdf_set_annot_rect(ctx, annot, text_rect);
723
0
        pdf_set_annot_border(ctx, annot, 0);
724
0
        pdf_set_annot_default_appearance(ctx, annot, "Helv", 12, nelem(black), black);
725
0
      }
726
0
      break;
727
728
0
    case PDF_ANNOT_STAMP:
729
0
      {
730
0
        fz_rect stamp_rect = { 12, 12, 12+190, 12+50 };
731
0
        pdf_set_annot_rect(ctx, annot, stamp_rect);
732
0
        pdf_set_annot_color(ctx, annot, 3, red);
733
0
        pdf_set_annot_icon_name(ctx, annot, "Draft");
734
0
      }
735
0
      break;
736
737
0
    case PDF_ANNOT_CARET:
738
0
      {
739
0
        fz_rect caret_rect = { 12, 12, 12+18, 12+15 };
740
0
        pdf_set_annot_rect(ctx, annot, caret_rect);
741
0
        pdf_set_annot_color(ctx, annot, 3, blue);
742
0
      }
743
0
      break;
744
745
0
    case PDF_ANNOT_LINE:
746
0
      {
747
0
        fz_point a = { 12, 12 }, b = { 12 + 100, 12 + 50 };
748
0
        pdf_set_annot_line(ctx, annot, a, b);
749
0
        pdf_set_annot_border(ctx, annot, 1);
750
0
        pdf_set_annot_color(ctx, annot, 3, red);
751
0
      }
752
0
      break;
753
754
0
    case PDF_ANNOT_SQUARE:
755
0
    case PDF_ANNOT_CIRCLE:
756
0
      {
757
0
        fz_rect shape_rect = { 12, 12, 12+100, 12+50 };
758
0
        pdf_set_annot_rect(ctx, annot, shape_rect);
759
0
        pdf_set_annot_border(ctx, annot, 1);
760
0
        pdf_set_annot_color(ctx, annot, 3, red);
761
0
      }
762
0
      break;
763
764
0
    case PDF_ANNOT_POLYGON:
765
0
    case PDF_ANNOT_POLY_LINE:
766
0
    case PDF_ANNOT_INK:
767
0
      pdf_set_annot_border(ctx, annot, 1);
768
0
      pdf_set_annot_color(ctx, annot, 3, red);
769
0
      break;
770
771
0
    case PDF_ANNOT_HIGHLIGHT:
772
0
      pdf_set_annot_color(ctx, annot, 3, yellow);
773
0
      break;
774
0
    case PDF_ANNOT_UNDERLINE:
775
0
      pdf_set_annot_color(ctx, annot, 3, green);
776
0
      break;
777
0
    case PDF_ANNOT_STRIKE_OUT:
778
0
      pdf_set_annot_color(ctx, annot, 3, red);
779
0
      break;
780
0
    case PDF_ANNOT_SQUIGGLY:
781
0
      pdf_set_annot_color(ctx, annot, 3, magenta);
782
0
      break;
783
0
    }
784
785
0
    pdf_dict_put(ctx, annot->obj, PDF_NAME(P), page->obj);
786
0
    pdf_dict_put_int(ctx, annot->obj, PDF_NAME(F), flags);
787
0
    pdf_end_operation(ctx, page->doc);
788
0
  }
789
0
  fz_catch(ctx)
790
0
  {
791
0
    pdf_abandon_operation(ctx, page->doc);
792
0
    pdf_drop_annot(ctx, annot);
793
0
    fz_rethrow(ctx);
794
0
  }
795
796
0
  return annot;
797
0
}
798
799
static int
800
remove_from_tree(fz_context *ctx, pdf_obj *arr, pdf_obj *item, pdf_cycle_list *cycle_up)
801
0
{
802
0
  pdf_cycle_list cycle;
803
0
  int i, n, res = 0;
804
805
0
  if (arr == NULL || pdf_cycle(ctx, &cycle, cycle_up, arr))
806
0
    return 0;
807
808
0
  n = pdf_array_len(ctx, arr);
809
0
  for (i = 0; i < n; ++i)
810
0
  {
811
0
    pdf_obj *obj = pdf_array_get(ctx, arr, i);
812
0
    if (obj == item)
813
0
    {
814
0
      pdf_array_delete(ctx, arr, i);
815
0
      res = 1;
816
0
      break;
817
0
    }
818
819
0
    if (remove_from_tree(ctx, pdf_dict_get(ctx, obj, PDF_NAME(Kids)), item, &cycle))
820
0
    {
821
0
      res = 1;
822
0
      break;
823
0
    }
824
0
  }
825
826
0
  return res;
827
0
}
828
829
void
830
pdf_delete_annot(fz_context *ctx, pdf_page *page, pdf_annot *annot)
831
0
{
832
0
  pdf_document *doc;
833
0
  pdf_annot **annotptr;
834
0
  pdf_obj *annot_arr, *popup;
835
0
  int i;
836
0
  int is_widget = 0;
837
838
0
  if (annot == NULL || page == NULL || page != annot->page)
839
0
    return;
840
841
0
  doc = page->doc;
842
843
  /* Look for the annot in the page's list */
844
0
  for (annotptr = &page->annots; *annotptr; annotptr = &(*annotptr)->next)
845
0
  {
846
0
    if (*annotptr == annot)
847
0
      break;
848
0
  }
849
850
0
  if (*annotptr == NULL)
851
0
  {
852
0
    is_widget = 1;
853
854
    /* Look also in the widget list*/
855
0
    for (annotptr = &page->widgets; *annotptr; annotptr = &(*annotptr)->next)
856
0
    {
857
0
      if (*annotptr == annot)
858
0
        break;
859
0
    }
860
0
  }
861
862
  /* Check the passed annotation was of this page */
863
0
  if (*annotptr == NULL)
864
0
    return;
865
866
  /* Remove annot from page's list */
867
0
  *annotptr = annot->next;
868
869
  /* If the removed annotation was the last in the list adjust the end pointer */
870
0
  if (*annotptr == NULL)
871
0
  {
872
0
    if (is_widget)
873
0
      page->widget_tailp = annotptr;
874
0
    else
875
0
      page->annot_tailp = annotptr;
876
0
  }
877
878
0
  pdf_begin_operation(ctx, page->doc, "Delete Annotation");
879
880
0
  fz_try(ctx)
881
0
  {
882
    /* Remove the annot from the "Annots" array. */
883
0
    annot_arr = pdf_dict_get(ctx, page->obj, PDF_NAME(Annots));
884
0
    i = pdf_array_find(ctx, annot_arr, annot->obj);
885
0
    if (i >= 0)
886
0
      pdf_array_delete(ctx, annot_arr, i);
887
888
    /* Remove the associated Popup annotation from the Annots array */
889
0
    popup = pdf_dict_get(ctx, annot->obj, PDF_NAME(Popup));
890
0
    if (popup)
891
0
    {
892
0
      i = pdf_array_find(ctx, annot_arr, popup);
893
0
      if (i >= 0)
894
0
        pdf_array_delete(ctx, annot_arr, i);
895
0
    }
896
897
    /* For a widget, remove also from the AcroForm tree */
898
0
    if (is_widget)
899
0
    {
900
0
      pdf_obj *root = pdf_dict_get(ctx, pdf_trailer(ctx, doc), PDF_NAME(Root));
901
0
      pdf_obj *acroform = pdf_dict_get(ctx, root, PDF_NAME(AcroForm));
902
0
      pdf_obj *fields = pdf_dict_get(ctx, acroform, PDF_NAME(Fields));
903
0
      (void)remove_from_tree(ctx, fields, annot->obj, NULL);
904
0
    }
905
906
    /* The garbage collection pass when saving will remove the annot object,
907
     * removing it here may break files if multiple pages use the same annot. */
908
0
    pdf_end_operation(ctx, page->doc);
909
0
  }
910
0
  fz_always(ctx)
911
0
  {
912
    /* Drop the reference to annot previously held by the page list. */
913
0
    pdf_drop_annot(ctx, annot);
914
0
  }
915
0
  fz_catch(ctx)
916
0
  {
917
0
    pdf_abandon_operation(ctx, page->doc);
918
0
    fz_rethrow(ctx);
919
0
  }
920
0
}
921
922
enum pdf_annot_type
923
pdf_annot_type(fz_context *ctx, pdf_annot *annot)
924
19.9k
{
925
19.9k
  enum pdf_annot_type ret;
926
927
19.9k
  pdf_annot_push_local_xref(ctx, annot);
928
929
39.8k
  fz_try(ctx)
930
39.8k
  {
931
19.9k
    pdf_obj *subtype = pdf_dict_get(ctx, annot->obj, PDF_NAME(Subtype));
932
19.9k
    ret = pdf_annot_type_from_string(ctx, pdf_to_name(ctx, subtype));
933
19.9k
  }
934
39.8k
  fz_always(ctx)
935
19.9k
    pdf_annot_pop_local_xref(ctx, annot);
936
19.9k
  fz_catch(ctx)
937
0
    fz_rethrow(ctx);
938
939
19.9k
  return ret;
940
19.9k
}
941
942
int
943
pdf_annot_flags(fz_context *ctx, pdf_annot *annot)
944
0
{
945
0
  int ret;
946
0
  pdf_annot_push_local_xref(ctx, annot);
947
948
0
  fz_try(ctx)
949
0
    ret = pdf_dict_get_int(ctx, annot->obj, PDF_NAME(F));
950
0
  fz_always(ctx)
951
0
    pdf_annot_pop_local_xref(ctx, annot);
952
0
  fz_catch(ctx)
953
0
    fz_rethrow(ctx);
954
955
0
  return ret;
956
0
}
957
958
void
959
pdf_set_annot_flags(fz_context *ctx, pdf_annot *annot, int flags)
960
0
{
961
0
  begin_annot_op(ctx, annot, "Set flags");
962
963
0
  fz_try(ctx)
964
0
  {
965
0
    pdf_dict_put_int(ctx, annot->obj, PDF_NAME(F), flags);
966
0
    end_annot_op(ctx, annot);
967
0
  }
968
0
  fz_catch(ctx)
969
0
  {
970
0
    abandon_annot_op(ctx, annot);
971
0
    fz_rethrow(ctx);
972
0
  }
973
974
0
  pdf_dirty_annot(ctx, annot);
975
0
}
976
977
static pdf_obj *rect_subtypes[] = {
978
  PDF_NAME(Text),
979
  PDF_NAME(FreeText),
980
  PDF_NAME(Square),
981
  PDF_NAME(Circle),
982
  PDF_NAME(Redact),
983
  PDF_NAME(Stamp),
984
  PDF_NAME(Caret),
985
  PDF_NAME(Popup),
986
  PDF_NAME(FileAttachment),
987
  PDF_NAME(Sound),
988
  PDF_NAME(Movie),
989
  PDF_NAME(Widget),
990
  NULL,
991
};
992
993
int
994
pdf_annot_has_rect(fz_context *ctx, pdf_annot *annot)
995
0
{
996
  /* True for annotations where the user can manipulate the size or location
997
   * of the annotation through the Rect.
998
   * False for annotations where the Rect is computed from other
999
   * annotation data such as InkList, QuadPoints, and Vertices.
1000
   */
1001
0
  return is_allowed_subtype_wrap(ctx, annot, PDF_NAME(Rect), rect_subtypes);
1002
0
}
1003
1004
fz_rect
1005
pdf_annot_rect(fz_context *ctx, pdf_annot *annot)
1006
0
{
1007
0
  fz_matrix page_ctm;
1008
0
  fz_rect annot_rect;
1009
1010
0
  pdf_annot_push_local_xref(ctx, annot);
1011
0
  fz_try(ctx)
1012
0
  {
1013
0
    check_allowed_subtypes(ctx, annot, PDF_NAME(Rect), rect_subtypes);
1014
0
    pdf_page_transform(ctx, annot->page, NULL, &page_ctm);
1015
0
    annot_rect = pdf_dict_get_rect(ctx, annot->obj, PDF_NAME(Rect));
1016
0
  }
1017
0
  fz_always(ctx)
1018
0
    pdf_annot_pop_local_xref(ctx, annot);
1019
0
  fz_catch(ctx)
1020
0
    fz_rethrow(ctx);
1021
0
  return fz_transform_rect(annot_rect, page_ctm);
1022
0
}
1023
1024
void
1025
pdf_set_annot_rect(fz_context *ctx, pdf_annot *annot, fz_rect rect)
1026
0
{
1027
0
  fz_matrix page_ctm, inv_page_ctm;
1028
1029
0
  pdf_begin_operation(ctx, annot->page->doc, "Set rectangle");
1030
1031
0
  fz_try(ctx)
1032
0
  {
1033
0
    check_allowed_subtypes(ctx, annot, PDF_NAME(Rect), rect_subtypes);
1034
1035
0
    pdf_page_transform(ctx, annot->page, NULL, &page_ctm);
1036
0
    inv_page_ctm = fz_invert_matrix(page_ctm);
1037
0
    rect = fz_transform_rect(rect, inv_page_ctm);
1038
1039
0
    pdf_dict_put_rect(ctx, annot->obj, PDF_NAME(Rect), rect);
1040
0
    pdf_dirty_annot(ctx, annot);
1041
0
    pdf_end_operation(ctx, annot->page->doc);
1042
0
  }
1043
0
  fz_catch(ctx)
1044
0
  {
1045
0
    pdf_abandon_operation(ctx, annot->page->doc);
1046
0
    fz_rethrow(ctx);
1047
0
  }
1048
0
}
1049
1050
const char *
1051
pdf_annot_contents(fz_context *ctx, pdf_annot *annot)
1052
39
{
1053
39
  return pdf_dict_get_text_string(ctx, annot->obj, PDF_NAME(Contents));
1054
39
}
1055
1056
void
1057
pdf_set_annot_contents(fz_context *ctx, pdf_annot *annot, const char *text)
1058
0
{
1059
0
  begin_annot_op(ctx, annot, "Set contents");
1060
1061
0
  fz_try(ctx)
1062
0
  {
1063
0
    pdf_dict_put_text_string(ctx, annot->obj, PDF_NAME(Contents), text);
1064
0
    pdf_dict_del(ctx, annot->obj, PDF_NAME(RC)); /* not supported */
1065
0
    pdf_dirty_annot(ctx, annot);
1066
0
    end_annot_op(ctx, annot);
1067
0
  }
1068
0
  fz_catch(ctx)
1069
0
  {
1070
0
    abandon_annot_op(ctx, annot);
1071
0
    fz_rethrow(ctx);
1072
0
  }
1073
0
}
1074
1075
int
1076
pdf_annot_has_open(fz_context *ctx, pdf_annot *annot)
1077
0
{
1078
0
  int ret;
1079
1080
0
  pdf_annot_push_local_xref(ctx, annot);
1081
1082
0
  fz_try(ctx)
1083
0
  {
1084
0
    pdf_obj *subtype = pdf_dict_get(ctx, annot->obj, PDF_NAME(Subtype));
1085
0
    pdf_obj *popup = pdf_dict_get(ctx, annot->obj, PDF_NAME(Popup));
1086
0
    ret = (subtype == PDF_NAME(Text) || popup);
1087
0
  }
1088
0
  fz_always(ctx)
1089
0
    pdf_annot_pop_local_xref(ctx, annot);
1090
0
  fz_catch(ctx)
1091
0
    fz_rethrow(ctx);
1092
1093
0
  return ret;
1094
0
}
1095
1096
int
1097
pdf_annot_is_open(fz_context *ctx, pdf_annot *annot)
1098
0
{
1099
0
  int ret = 0;
1100
1101
0
  pdf_annot_push_local_xref(ctx, annot);
1102
1103
0
  fz_try(ctx)
1104
0
  {
1105
0
    pdf_obj *subtype = pdf_dict_get(ctx, annot->obj, PDF_NAME(Subtype));
1106
0
    pdf_obj *popup = pdf_dict_get(ctx, annot->obj, PDF_NAME(Popup));
1107
0
    if (popup)
1108
0
      ret = pdf_dict_get_bool(ctx, popup, PDF_NAME(Open));
1109
0
    else if (subtype == PDF_NAME(Text))
1110
0
      ret = pdf_dict_get_bool(ctx, annot->obj, PDF_NAME(Open));
1111
0
  }
1112
0
  fz_always(ctx)
1113
0
    pdf_annot_pop_local_xref(ctx, annot);
1114
0
  fz_catch(ctx)
1115
0
    fz_rethrow(ctx);
1116
1117
0
  return ret;
1118
0
}
1119
1120
void
1121
pdf_set_annot_is_open(fz_context *ctx, pdf_annot *annot, int is_open)
1122
0
{
1123
0
  begin_annot_op(ctx, annot, is_open ? "Open" : "Close");
1124
1125
0
  fz_try(ctx)
1126
0
  {
1127
0
    pdf_obj *subtype = pdf_dict_get(ctx, annot->obj, PDF_NAME(Subtype));
1128
0
    pdf_obj *popup = pdf_dict_get(ctx, annot->obj, PDF_NAME(Popup));
1129
0
    if (popup)
1130
0
    {
1131
0
      pdf_dict_put_bool(ctx, popup, PDF_NAME(Open), is_open);
1132
0
      pdf_dirty_annot(ctx, annot);
1133
0
    }
1134
0
    else if (subtype == PDF_NAME(Text))
1135
0
    {
1136
0
      pdf_dict_put_bool(ctx, annot->obj, PDF_NAME(Open), is_open);
1137
0
      pdf_dirty_annot(ctx, annot);
1138
0
    }
1139
0
    end_annot_op(ctx, annot);
1140
0
  }
1141
0
  fz_catch(ctx)
1142
0
  {
1143
0
    abandon_annot_op(ctx, annot);
1144
0
    fz_rethrow(ctx);
1145
0
  }
1146
0
}
1147
1148
static pdf_obj *icon_name_subtypes[] = {
1149
  PDF_NAME(FileAttachment),
1150
  PDF_NAME(Sound),
1151
  PDF_NAME(Stamp),
1152
  PDF_NAME(Text),
1153
  NULL,
1154
};
1155
1156
int
1157
pdf_annot_has_icon_name(fz_context *ctx, pdf_annot *annot)
1158
0
{
1159
0
  return is_allowed_subtype_wrap(ctx, annot, PDF_NAME(Name), icon_name_subtypes);
1160
0
}
1161
1162
const char *
1163
pdf_annot_icon_name(fz_context *ctx, pdf_annot *annot)
1164
39
{
1165
39
  const char *ret;
1166
39
  pdf_obj *name;
1167
1168
39
  pdf_annot_push_local_xref(ctx, annot);
1169
1170
78
  fz_try(ctx)
1171
78
  {
1172
39
    check_allowed_subtypes(ctx, annot, PDF_NAME(Name), icon_name_subtypes);
1173
39
    name = pdf_dict_get(ctx, annot->obj, PDF_NAME(Name));
1174
39
    if (!name)
1175
5
    {
1176
5
      pdf_obj *subtype = pdf_dict_get(ctx, annot->obj, PDF_NAME(Subtype));
1177
5
      if (pdf_name_eq(ctx, subtype, PDF_NAME(Text)))
1178
5
      {
1179
5
        ret = "Note";
1180
5
        break;
1181
5
      }
1182
0
      if (pdf_name_eq(ctx, subtype, PDF_NAME(Stamp)))
1183
0
      {
1184
0
        ret = ""; // Should be "Draft" according to spec
1185
0
        break;
1186
0
      }
1187
0
      if (pdf_name_eq(ctx, subtype, PDF_NAME(FileAttachment)))
1188
0
      {
1189
0
        ret = "PushPin";
1190
0
        break;
1191
0
      }
1192
0
      if (pdf_name_eq(ctx, subtype, PDF_NAME(Sound)))
1193
0
      {
1194
0
        ret = "Speaker";
1195
0
        break;
1196
0
      }
1197
0
    }
1198
34
    ret = pdf_to_name(ctx, name);
1199
34
  }
1200
78
  fz_always(ctx)
1201
39
    pdf_annot_pop_local_xref(ctx, annot);
1202
39
  fz_catch(ctx)
1203
0
    fz_rethrow(ctx);
1204
1205
39
  return ret;
1206
39
}
1207
1208
void
1209
pdf_set_annot_icon_name(fz_context *ctx, pdf_annot *annot, const char *name)
1210
0
{
1211
0
  begin_annot_op(ctx, annot, "Set icon name");
1212
1213
0
  fz_try(ctx)
1214
0
  {
1215
0
    check_allowed_subtypes(ctx, annot, PDF_NAME(Name), icon_name_subtypes);
1216
0
    if (name)
1217
0
      pdf_dict_put_name(ctx, annot->obj, PDF_NAME(Name), name);
1218
0
    else
1219
0
      pdf_dict_del(ctx, annot->obj, PDF_NAME(Name));
1220
0
    end_annot_op(ctx, annot);
1221
0
  }
1222
0
  fz_catch(ctx)
1223
0
  {
1224
0
    abandon_annot_op(ctx, annot);
1225
0
    fz_rethrow(ctx);
1226
0
  }
1227
1228
0
  pdf_dirty_annot(ctx, annot);
1229
0
}
1230
1231
int
1232
pdf_annot_is_standard_stamp(fz_context *ctx, pdf_annot *annot)
1233
0
{
1234
0
  pdf_obj *name = pdf_dict_get(ctx, annot->obj, PDF_NAME(Name));
1235
0
  if (pdf_name_eq(ctx, name, PDF_NAME(Approved))) return 1;
1236
0
  else if (pdf_name_eq(ctx, name, PDF_NAME(AsIs))) return 1;
1237
0
  else if (pdf_name_eq(ctx, name, PDF_NAME(Confidential))) return 1;
1238
0
  else if (pdf_name_eq(ctx, name, PDF_NAME(Departmental))) return 1;
1239
0
  else if (pdf_name_eq(ctx, name, PDF_NAME(Draft))) return 1;
1240
0
  else if (pdf_name_eq(ctx, name, PDF_NAME(Experimental))) return 1;
1241
0
  else if (pdf_name_eq(ctx, name, PDF_NAME(Expired))) return 1;
1242
0
  else if (pdf_name_eq(ctx, name, PDF_NAME(Final))) return 1;
1243
0
  else if (pdf_name_eq(ctx, name, PDF_NAME(ForComment))) return 1;
1244
0
  else if (pdf_name_eq(ctx, name, PDF_NAME(ForPublicRelease))) return 1;
1245
0
  else if (pdf_name_eq(ctx, name, PDF_NAME(NotApproved))) return 1;
1246
0
  else if (pdf_name_eq(ctx, name, PDF_NAME(NotForPublicRelease))) return 1;
1247
0
  else if (pdf_name_eq(ctx, name, PDF_NAME(Sold))) return 1;
1248
0
  else if (pdf_name_eq(ctx, name, PDF_NAME(TopSecret))) return 1;
1249
0
  else return 0;
1250
0
}
1251
1252
enum pdf_line_ending pdf_line_ending_from_name(fz_context *ctx, pdf_obj *end)
1253
0
{
1254
0
  if (pdf_name_eq(ctx, end, PDF_NAME(None))) return PDF_ANNOT_LE_NONE;
1255
0
  else if (pdf_name_eq(ctx, end, PDF_NAME(Square))) return PDF_ANNOT_LE_SQUARE;
1256
0
  else if (pdf_name_eq(ctx, end, PDF_NAME(Circle))) return PDF_ANNOT_LE_CIRCLE;
1257
0
  else if (pdf_name_eq(ctx, end, PDF_NAME(Diamond))) return PDF_ANNOT_LE_DIAMOND;
1258
0
  else if (pdf_name_eq(ctx, end, PDF_NAME(OpenArrow))) return PDF_ANNOT_LE_OPEN_ARROW;
1259
0
  else if (pdf_name_eq(ctx, end, PDF_NAME(ClosedArrow))) return PDF_ANNOT_LE_CLOSED_ARROW;
1260
0
  else if (pdf_name_eq(ctx, end, PDF_NAME(Butt))) return PDF_ANNOT_LE_BUTT;
1261
0
  else if (pdf_name_eq(ctx, end, PDF_NAME(ROpenArrow))) return PDF_ANNOT_LE_R_OPEN_ARROW;
1262
0
  else if (pdf_name_eq(ctx, end, PDF_NAME(RClosedArrow))) return PDF_ANNOT_LE_R_CLOSED_ARROW;
1263
0
  else if (pdf_name_eq(ctx, end, PDF_NAME(Slash))) return PDF_ANNOT_LE_SLASH;
1264
0
  else return PDF_ANNOT_LE_NONE;
1265
0
}
1266
1267
enum pdf_line_ending pdf_line_ending_from_string(fz_context *ctx, const char *end)
1268
0
{
1269
0
  if (!strcmp(end, "None")) return PDF_ANNOT_LE_NONE;
1270
0
  else if (!strcmp(end, "Square")) return PDF_ANNOT_LE_SQUARE;
1271
0
  else if (!strcmp(end, "Circle")) return PDF_ANNOT_LE_CIRCLE;
1272
0
  else if (!strcmp(end, "Diamond")) return PDF_ANNOT_LE_DIAMOND;
1273
0
  else if (!strcmp(end, "OpenArrow")) return PDF_ANNOT_LE_OPEN_ARROW;
1274
0
  else if (!strcmp(end, "ClosedArrow")) return PDF_ANNOT_LE_CLOSED_ARROW;
1275
0
  else if (!strcmp(end, "Butt")) return PDF_ANNOT_LE_BUTT;
1276
0
  else if (!strcmp(end, "ROpenArrow")) return PDF_ANNOT_LE_R_OPEN_ARROW;
1277
0
  else if (!strcmp(end, "RClosedArrow")) return PDF_ANNOT_LE_R_CLOSED_ARROW;
1278
0
  else if (!strcmp(end, "Slash")) return PDF_ANNOT_LE_SLASH;
1279
0
  else return PDF_ANNOT_LE_NONE;
1280
0
}
1281
1282
pdf_obj *pdf_name_from_line_ending(fz_context *ctx, enum pdf_line_ending end)
1283
0
{
1284
0
  switch (end)
1285
0
  {
1286
0
  default:
1287
0
  case PDF_ANNOT_LE_NONE: return PDF_NAME(None);
1288
0
  case PDF_ANNOT_LE_SQUARE: return PDF_NAME(Square);
1289
0
  case PDF_ANNOT_LE_CIRCLE: return PDF_NAME(Circle);
1290
0
  case PDF_ANNOT_LE_DIAMOND: return PDF_NAME(Diamond);
1291
0
  case PDF_ANNOT_LE_OPEN_ARROW: return PDF_NAME(OpenArrow);
1292
0
  case PDF_ANNOT_LE_CLOSED_ARROW: return PDF_NAME(ClosedArrow);
1293
0
  case PDF_ANNOT_LE_BUTT: return PDF_NAME(Butt);
1294
0
  case PDF_ANNOT_LE_R_OPEN_ARROW: return PDF_NAME(ROpenArrow);
1295
0
  case PDF_ANNOT_LE_R_CLOSED_ARROW: return PDF_NAME(RClosedArrow);
1296
0
  case PDF_ANNOT_LE_SLASH: return PDF_NAME(Slash);
1297
0
  }
1298
0
}
1299
1300
const char *pdf_string_from_line_ending(fz_context *ctx, enum pdf_line_ending end)
1301
0
{
1302
0
  switch (end)
1303
0
  {
1304
0
  default:
1305
0
  case PDF_ANNOT_LE_NONE: return "None";
1306
0
  case PDF_ANNOT_LE_SQUARE: return "Square";
1307
0
  case PDF_ANNOT_LE_CIRCLE: return "Circle";
1308
0
  case PDF_ANNOT_LE_DIAMOND: return "Diamond";
1309
0
  case PDF_ANNOT_LE_OPEN_ARROW: return "OpenArrow";
1310
0
  case PDF_ANNOT_LE_CLOSED_ARROW: return "ClosedArrow";
1311
0
  case PDF_ANNOT_LE_BUTT: return "Butt";
1312
0
  case PDF_ANNOT_LE_R_OPEN_ARROW: return "ROpenArrow";
1313
0
  case PDF_ANNOT_LE_R_CLOSED_ARROW: return "RClosedArrow";
1314
0
  case PDF_ANNOT_LE_SLASH: return "Slash";
1315
0
  }
1316
0
}
1317
1318
static pdf_obj *line_ending_subtypes[] = {
1319
  PDF_NAME(FreeText),
1320
  PDF_NAME(Line),
1321
  PDF_NAME(PolyLine),
1322
  PDF_NAME(Polygon),
1323
  NULL,
1324
};
1325
1326
int
1327
pdf_annot_has_line_ending_styles(fz_context *ctx, pdf_annot *annot)
1328
0
{
1329
0
  return is_allowed_subtype_wrap(ctx, annot, PDF_NAME(LE), line_ending_subtypes);
1330
0
}
1331
1332
void
1333
pdf_annot_line_ending_styles(fz_context *ctx, pdf_annot *annot,
1334
    enum pdf_line_ending *start_style,
1335
    enum pdf_line_ending *end_style)
1336
0
{
1337
0
  pdf_obj *style;
1338
1339
0
  pdf_annot_push_local_xref(ctx, annot);
1340
1341
0
  fz_try(ctx)
1342
0
  {
1343
0
    check_allowed_subtypes(ctx, annot, PDF_NAME(LE), line_ending_subtypes);
1344
1345
0
    style = pdf_dict_get(ctx, annot->obj, PDF_NAME(LE));
1346
0
    *start_style = pdf_line_ending_from_name(ctx, pdf_array_get(ctx, style, 0));
1347
0
    *end_style = pdf_line_ending_from_name(ctx, pdf_array_get(ctx, style, 1));
1348
0
  }
1349
0
  fz_always(ctx)
1350
0
    pdf_annot_pop_local_xref(ctx, annot);
1351
0
  fz_catch(ctx)
1352
0
    fz_rethrow(ctx);
1353
0
}
1354
1355
enum pdf_line_ending
1356
pdf_annot_line_start_style(fz_context *ctx, pdf_annot *annot)
1357
0
{
1358
0
  pdf_obj *le = pdf_dict_get(ctx, annot->obj, PDF_NAME(LE));
1359
0
  return pdf_line_ending_from_name(ctx, pdf_array_get(ctx, le, 0));
1360
0
}
1361
1362
enum pdf_line_ending
1363
pdf_annot_line_end_style(fz_context *ctx, pdf_annot *annot)
1364
0
{
1365
0
  pdf_obj *le = pdf_dict_get(ctx, annot->obj, PDF_NAME(LE));
1366
0
  return pdf_line_ending_from_name(ctx, pdf_array_get(ctx, le, 1));
1367
0
}
1368
1369
void
1370
pdf_set_annot_line_ending_styles(fz_context *ctx, pdf_annot *annot,
1371
    enum pdf_line_ending start_style,
1372
    enum pdf_line_ending end_style)
1373
0
{
1374
0
  pdf_document *doc = annot->page->doc;
1375
0
  pdf_obj *style;
1376
1377
0
  begin_annot_op(ctx, annot, "Set line endings");
1378
1379
0
  fz_try(ctx)
1380
0
  {
1381
0
    check_allowed_subtypes(ctx, annot, PDF_NAME(LE), line_ending_subtypes);
1382
0
    style = pdf_new_array(ctx, doc, 2);
1383
0
    pdf_dict_put_drop(ctx, annot->obj, PDF_NAME(LE), style);
1384
0
    pdf_array_put_drop(ctx, style, 0, pdf_name_from_line_ending(ctx, start_style));
1385
0
    pdf_array_put_drop(ctx, style, 1, pdf_name_from_line_ending(ctx, end_style));
1386
0
    end_annot_op(ctx, annot);
1387
0
  }
1388
0
  fz_catch(ctx)
1389
0
  {
1390
0
    abandon_annot_op(ctx, annot);
1391
0
    fz_rethrow(ctx);
1392
0
  }
1393
1394
0
  pdf_dirty_annot(ctx, annot);
1395
0
}
1396
1397
void
1398
pdf_set_annot_line_start_style(fz_context *ctx, pdf_annot *annot, enum pdf_line_ending s)
1399
0
{
1400
0
  enum pdf_line_ending e = pdf_annot_line_end_style(ctx, annot);
1401
0
  pdf_set_annot_line_ending_styles(ctx, annot, s, e);
1402
0
}
1403
1404
void
1405
pdf_set_annot_line_end_style(fz_context *ctx, pdf_annot *annot, enum pdf_line_ending e)
1406
0
{
1407
0
  enum pdf_line_ending s = pdf_annot_line_start_style(ctx, annot);
1408
0
  pdf_set_annot_line_ending_styles(ctx, annot, s, e);
1409
0
}
1410
1411
float
1412
pdf_annot_border(fz_context *ctx, pdf_annot *annot)
1413
7.53k
{
1414
7.53k
  pdf_obj *bs, *bs_w, *border;
1415
7.53k
  float ret = 1;
1416
1417
7.53k
  pdf_annot_push_local_xref(ctx, annot);
1418
1419
15.0k
  fz_try(ctx)
1420
15.0k
  {
1421
7.53k
    bs = pdf_dict_get(ctx, annot->obj, PDF_NAME(BS));
1422
7.53k
    bs_w = pdf_dict_get(ctx, bs, PDF_NAME(W));
1423
7.53k
    if (pdf_is_number(ctx, bs_w))
1424
193
    {
1425
193
      ret = pdf_to_real(ctx, bs_w);
1426
193
      break;
1427
193
    }
1428
7.34k
    border = pdf_dict_get(ctx, annot->obj, PDF_NAME(Border));
1429
7.34k
    bs_w = pdf_array_get(ctx, border, 2);
1430
7.34k
    if (pdf_is_number(ctx, bs_w))
1431
43
      ret = pdf_to_real(ctx, bs_w);
1432
7.34k
  }
1433
15.0k
  fz_always(ctx)
1434
7.53k
    pdf_annot_pop_local_xref(ctx, annot);
1435
7.53k
  fz_catch(ctx)
1436
0
    fz_rethrow(ctx);
1437
1438
7.53k
  return ret;
1439
7.53k
}
1440
1441
void
1442
pdf_set_annot_border(fz_context *ctx, pdf_annot *annot, float w)
1443
0
{
1444
0
  begin_annot_op(ctx, annot, "Set border");
1445
1446
0
  fz_try(ctx)
1447
0
  {
1448
0
    pdf_obj *bs = pdf_dict_get(ctx, annot->obj, PDF_NAME(BS));
1449
0
    if (!pdf_is_dict(ctx, bs))
1450
0
      bs = pdf_dict_put_dict(ctx, annot->obj, PDF_NAME(BS), 1);
1451
0
    pdf_dict_put(ctx, bs, PDF_NAME(Type), PDF_NAME(Border));
1452
0
    pdf_dict_put_real(ctx, bs, PDF_NAME(W), w);
1453
1454
0
    pdf_dict_del(ctx, annot->obj, PDF_NAME(Border)); /* deprecated */
1455
0
    pdf_dict_del(ctx, annot->obj, PDF_NAME(BE)); /* no effect */
1456
0
    end_annot_op(ctx, annot);
1457
0
  }
1458
0
  fz_catch(ctx)
1459
0
  {
1460
0
    abandon_annot_op(ctx, annot);
1461
0
    fz_rethrow(ctx);
1462
0
  }
1463
1464
0
  pdf_dirty_annot(ctx, annot);
1465
0
}
1466
1467
static pdf_obj *border_style_subtypes[] = {
1468
  PDF_NAME(Circle),
1469
  PDF_NAME(FreeText),
1470
  PDF_NAME(Ink),
1471
  PDF_NAME(Line),
1472
  PDF_NAME(Polygon),
1473
  PDF_NAME(PolyLine),
1474
  PDF_NAME(Square),
1475
  NULL,
1476
};
1477
1478
static pdf_obj *border_effect_subtypes[] = {
1479
  PDF_NAME(Circle),
1480
  PDF_NAME(FreeText),
1481
  PDF_NAME(Polygon),
1482
  PDF_NAME(Square),
1483
  NULL,
1484
};
1485
1486
int
1487
pdf_annot_has_border(fz_context *ctx, pdf_annot *annot)
1488
0
{
1489
0
  return is_allowed_subtype_wrap(ctx, annot, PDF_NAME(BS), border_style_subtypes);
1490
0
}
1491
1492
int
1493
pdf_annot_has_border_effect(fz_context *ctx, pdf_annot *annot)
1494
0
{
1495
0
  return is_allowed_subtype_wrap(ctx, annot, PDF_NAME(BE), border_effect_subtypes);
1496
0
}
1497
1498
enum pdf_border_style
1499
pdf_annot_border_style(fz_context *ctx, pdf_annot *annot)
1500
0
{
1501
0
  pdf_obj *bs, *s;
1502
0
  enum pdf_border_style style;
1503
1504
0
  pdf_annot_push_local_xref(ctx, annot);
1505
1506
0
  fz_try(ctx)
1507
0
  {
1508
0
    check_allowed_subtypes(ctx, annot, PDF_NAME(BS), border_style_subtypes);
1509
0
    bs = pdf_dict_get(ctx, annot->obj, PDF_NAME(BS));
1510
0
    s = pdf_dict_get(ctx, bs, PDF_NAME(S));
1511
1512
0
    if (s == PDF_NAME(D))
1513
0
      style = PDF_BORDER_STYLE_DASHED;
1514
0
    else if (s == PDF_NAME(B))
1515
0
      style = PDF_BORDER_STYLE_BEVELED;
1516
0
    else if (s == PDF_NAME(I))
1517
0
      style = PDF_BORDER_STYLE_INSET;
1518
0
    else if (s == PDF_NAME(U))
1519
0
      style = PDF_BORDER_STYLE_UNDERLINE;
1520
0
    else
1521
0
      style = PDF_BORDER_STYLE_SOLID;
1522
0
  }
1523
0
  fz_always(ctx)
1524
0
    pdf_annot_pop_local_xref(ctx, annot);
1525
0
  fz_catch(ctx)
1526
0
    fz_rethrow(ctx);
1527
1528
0
  return style;
1529
0
}
1530
1531
float
1532
pdf_annot_border_width(fz_context *ctx, pdf_annot *annot)
1533
0
{
1534
0
  pdf_obj *border, *bs, *w;
1535
0
  float width;
1536
1537
0
  pdf_annot_push_local_xref(ctx, annot);
1538
1539
0
  fz_try(ctx)
1540
0
  {
1541
0
    check_allowed_subtypes(ctx, annot, PDF_NAME(BS), border_style_subtypes);
1542
1543
    /* if values missing, fall back to deprecated /Border array */
1544
0
    border = pdf_dict_get(ctx, annot->obj, PDF_NAME(Border));
1545
0
    bs = pdf_dict_get(ctx, annot->obj, PDF_NAME(BS));
1546
0
    w = pdf_dict_get(ctx, bs, PDF_NAME(W));
1547
0
    if (!pdf_is_number(ctx, w) && pdf_is_dict(ctx, border))
1548
0
      w = pdf_array_get(ctx, border, 2);
1549
0
    width = pdf_to_real(ctx, w);
1550
0
  }
1551
0
  fz_always(ctx)
1552
0
    pdf_annot_pop_local_xref(ctx, annot);
1553
0
  fz_catch(ctx)
1554
0
    fz_rethrow(ctx);
1555
1556
0
  return width;
1557
0
}
1558
1559
int
1560
pdf_annot_border_dash_count(fz_context *ctx, pdf_annot *annot)
1561
216
{
1562
216
  pdf_obj *bs, *d;
1563
216
  int count;
1564
1565
216
  pdf_annot_push_local_xref(ctx, annot);
1566
1567
432
  fz_try(ctx)
1568
432
  {
1569
216
    check_allowed_subtypes(ctx, annot, PDF_NAME(BS), border_style_subtypes);
1570
216
    bs = pdf_dict_get(ctx, annot->obj, PDF_NAME(BS));
1571
216
    d = pdf_dict_get(ctx, bs, PDF_NAME(D));
1572
216
    count = pdf_array_len(ctx, d);
1573
216
  }
1574
432
  fz_always(ctx)
1575
216
    pdf_annot_pop_local_xref(ctx, annot);
1576
216
  fz_catch(ctx)
1577
0
    fz_rethrow(ctx);
1578
1579
216
  return count;
1580
216
}
1581
1582
float
1583
pdf_annot_border_dash_item(fz_context *ctx, pdf_annot *annot, int i)
1584
35
{
1585
35
  pdf_obj *bs, *d;
1586
35
  float length;
1587
1588
35
  pdf_annot_push_local_xref(ctx, annot);
1589
1590
70
  fz_try(ctx)
1591
70
  {
1592
35
    check_allowed_subtypes(ctx, annot, PDF_NAME(BS), border_style_subtypes);
1593
35
    bs = pdf_dict_get(ctx, annot->obj, PDF_NAME(BS));
1594
35
    d = pdf_dict_get(ctx, bs, PDF_NAME(D));
1595
35
    length = pdf_array_get_real(ctx, d, i);
1596
35
  }
1597
70
  fz_always(ctx)
1598
35
    pdf_annot_pop_local_xref(ctx, annot);
1599
35
  fz_catch(ctx)
1600
0
    fz_rethrow(ctx);
1601
1602
35
  return length;
1603
35
}
1604
1605
enum pdf_border_effect
1606
pdf_annot_border_effect(fz_context *ctx, pdf_annot *annot)
1607
43
{
1608
43
  pdf_obj *be;
1609
43
  enum pdf_border_effect effect;
1610
1611
43
  pdf_annot_push_local_xref(ctx, annot);
1612
1613
86
  fz_try(ctx)
1614
86
  {
1615
43
    check_allowed_subtypes(ctx, annot, PDF_NAME(BE), border_effect_subtypes);
1616
43
    be = pdf_dict_get(ctx, annot->obj, PDF_NAME(BE));
1617
43
    if (pdf_dict_get(ctx, be, PDF_NAME(S)) == PDF_NAME(C))
1618
0
      effect = PDF_BORDER_EFFECT_CLOUDY;
1619
43
    else
1620
43
      effect = PDF_BORDER_EFFECT_NONE;
1621
43
  }
1622
86
  fz_always(ctx)
1623
43
    pdf_annot_pop_local_xref(ctx, annot);
1624
43
  fz_catch(ctx)
1625
0
    fz_rethrow(ctx);
1626
1627
43
  return effect;
1628
43
}
1629
1630
float
1631
pdf_annot_border_effect_intensity(fz_context *ctx, pdf_annot *annot)
1632
0
{
1633
0
  pdf_obj *be;
1634
0
  float intensity;
1635
1636
0
  pdf_annot_push_local_xref(ctx, annot);
1637
1638
0
  fz_try(ctx)
1639
0
  {
1640
0
    check_allowed_subtypes(ctx, annot, PDF_NAME(BE), border_effect_subtypes);
1641
0
    be = pdf_dict_get(ctx, annot->obj, PDF_NAME(BE));
1642
0
    intensity = pdf_dict_get_real(ctx, be, PDF_NAME(I));
1643
0
  }
1644
0
  fz_always(ctx)
1645
0
    pdf_annot_pop_local_xref(ctx, annot);
1646
0
  fz_catch(ctx)
1647
0
    fz_rethrow(ctx);
1648
1649
0
  return intensity;
1650
0
}
1651
1652
void
1653
pdf_set_annot_border_width(fz_context *ctx, pdf_annot *annot, float width)
1654
0
{
1655
0
  pdf_obj *bs;
1656
1657
0
  begin_annot_op(ctx, annot, "Set border width");
1658
1659
0
  fz_try(ctx)
1660
0
  {
1661
0
    check_allowed_subtypes(ctx, annot, PDF_NAME(BS), border_style_subtypes);
1662
0
    bs = pdf_dict_get(ctx, annot->obj, PDF_NAME(BS));
1663
0
    if (!pdf_is_dict(ctx, bs))
1664
0
      bs = pdf_dict_put_dict(ctx, annot->obj, PDF_NAME(BS), 1);
1665
0
    pdf_dict_put(ctx, bs, PDF_NAME(Type), PDF_NAME(Border));
1666
0
    pdf_dict_put_real(ctx, bs, PDF_NAME(W), width);
1667
0
    pdf_dict_del(ctx, annot->obj, PDF_NAME(Border)); /* deprecated */
1668
0
    end_annot_op(ctx, annot);
1669
0
  }
1670
0
  fz_catch(ctx)
1671
0
  {
1672
0
    abandon_annot_op(ctx, annot);
1673
0
    fz_rethrow(ctx);
1674
0
  }
1675
1676
0
  pdf_dirty_annot(ctx, annot);
1677
0
}
1678
1679
void
1680
pdf_set_annot_border_style(fz_context *ctx, pdf_annot *annot, enum pdf_border_style style)
1681
0
{
1682
0
  pdf_obj *bs, *s;
1683
1684
0
  begin_annot_op(ctx, annot, "Set border style");
1685
1686
0
  fz_try(ctx)
1687
0
  {
1688
0
    check_allowed_subtypes(ctx, annot, PDF_NAME(BS), border_style_subtypes);
1689
0
    bs = pdf_dict_get(ctx, annot->obj, PDF_NAME(BS));
1690
0
    if (!pdf_is_dict(ctx, bs))
1691
0
      bs = pdf_dict_put_dict(ctx, annot->obj, PDF_NAME(BS), 1);
1692
0
    pdf_dict_put(ctx, bs, PDF_NAME(Type), PDF_NAME(Border));
1693
0
    switch (style)
1694
0
    {
1695
0
    default:
1696
0
    case PDF_BORDER_STYLE_SOLID: s = PDF_NAME(S); break;
1697
0
    case PDF_BORDER_STYLE_DASHED: s = PDF_NAME(D); break;
1698
0
    case PDF_BORDER_STYLE_BEVELED: s = PDF_NAME(B); break;
1699
0
    case PDF_BORDER_STYLE_INSET: s = PDF_NAME(I); break;
1700
0
    case PDF_BORDER_STYLE_UNDERLINE: s = PDF_NAME(U); break;
1701
0
    }
1702
0
    pdf_dict_put(ctx, bs, PDF_NAME(S), s);
1703
0
    end_annot_op(ctx, annot);
1704
0
  }
1705
0
  fz_catch(ctx)
1706
0
  {
1707
0
    abandon_annot_op(ctx, annot);
1708
0
    fz_rethrow(ctx);
1709
0
  }
1710
1711
0
  pdf_dirty_annot(ctx, annot);
1712
0
}
1713
1714
void
1715
pdf_clear_annot_border_dash(fz_context *ctx, pdf_annot *annot)
1716
0
{
1717
0
  pdf_obj *bs;
1718
1719
0
  begin_annot_op(ctx, annot, "Clear border dash pattern");
1720
1721
0
  fz_try(ctx)
1722
0
  {
1723
0
    check_allowed_subtypes(ctx, annot, PDF_NAME(BS), border_style_subtypes);
1724
0
    bs = pdf_dict_get(ctx, annot->obj, PDF_NAME(BS));
1725
0
    if (!pdf_is_dict(ctx, bs))
1726
0
      bs = pdf_dict_put_dict(ctx, annot->obj, PDF_NAME(BS), 1);
1727
0
    pdf_dict_del(ctx, bs, PDF_NAME(D));
1728
0
    end_annot_op(ctx, annot);
1729
0
  }
1730
0
  fz_catch(ctx)
1731
0
  {
1732
0
    abandon_annot_op(ctx, annot);
1733
0
    fz_rethrow(ctx);
1734
0
  }
1735
1736
0
  pdf_dirty_annot(ctx, annot);
1737
0
}
1738
1739
void
1740
pdf_add_annot_border_dash_item(fz_context *ctx, pdf_annot *annot, float length)
1741
0
{
1742
0
  pdf_obj *bs, *d;
1743
1744
0
  begin_annot_op(ctx, annot, "Add border dash pattern item");
1745
1746
0
  fz_try(ctx)
1747
0
  {
1748
0
    check_allowed_subtypes(ctx, annot, PDF_NAME(BS), border_style_subtypes);
1749
0
    bs = pdf_dict_get(ctx, annot->obj, PDF_NAME(BS));
1750
0
    if (!pdf_is_dict(ctx, bs))
1751
0
      bs = pdf_dict_put_dict(ctx, annot->obj, PDF_NAME(BS), 1);
1752
0
    d = pdf_dict_get(ctx, bs, PDF_NAME(D));
1753
0
    if (!pdf_is_array(ctx, d))
1754
0
      d = pdf_dict_put_array(ctx, bs, PDF_NAME(D), 1);
1755
0
    pdf_array_push_real(ctx, d, length);
1756
0
    end_annot_op(ctx, annot);
1757
0
  }
1758
0
  fz_catch(ctx)
1759
0
  {
1760
0
    abandon_annot_op(ctx, annot);
1761
0
    fz_rethrow(ctx);
1762
0
  }
1763
1764
0
  pdf_dirty_annot(ctx, annot);
1765
0
}
1766
1767
void
1768
pdf_set_annot_border_effect(fz_context *ctx, pdf_annot *annot, enum pdf_border_effect effect)
1769
0
{
1770
0
  pdf_obj *be, *s;
1771
1772
0
  begin_annot_op(ctx, annot, "Set border effect");
1773
1774
0
  fz_try(ctx)
1775
0
  {
1776
0
    check_allowed_subtypes(ctx, annot, PDF_NAME(BE), border_effect_subtypes);
1777
0
    be = pdf_dict_get(ctx, annot->obj, PDF_NAME(BE));
1778
0
    if (!pdf_is_dict(ctx, be))
1779
0
      be = pdf_dict_put_dict(ctx, annot->obj, PDF_NAME(BE), 1);
1780
0
    switch (effect)
1781
0
    {
1782
0
    default:
1783
0
    case PDF_BORDER_EFFECT_NONE: s = PDF_NAME(S); break;
1784
0
    case PDF_BORDER_EFFECT_CLOUDY: s = PDF_NAME(C); break;
1785
0
    }
1786
0
    pdf_dict_put(ctx, be, PDF_NAME(S), s);
1787
0
    end_annot_op(ctx, annot);
1788
0
  }
1789
0
  fz_catch(ctx)
1790
0
  {
1791
0
    abandon_annot_op(ctx, annot);
1792
0
    fz_rethrow(ctx);
1793
0
  }
1794
1795
0
  pdf_dirty_annot(ctx, annot);
1796
0
}
1797
1798
void
1799
pdf_set_annot_border_effect_intensity(fz_context *ctx, pdf_annot *annot, float intensity)
1800
0
{
1801
0
  pdf_obj *be;
1802
1803
0
  begin_annot_op(ctx, annot, "Set border effect intensity");
1804
1805
0
  fz_try(ctx)
1806
0
  {
1807
0
    check_allowed_subtypes(ctx, annot, PDF_NAME(BE), border_effect_subtypes);
1808
0
    be = pdf_dict_get(ctx, annot->obj, PDF_NAME(BE));
1809
0
    if (!pdf_is_dict(ctx, be))
1810
0
      be = pdf_dict_put_dict(ctx, annot->obj, PDF_NAME(BE), 1);
1811
0
    pdf_dict_put_real(ctx, be, PDF_NAME(I), intensity);
1812
0
    end_annot_op(ctx, annot);
1813
0
  }
1814
0
  fz_catch(ctx)
1815
0
  {
1816
0
    abandon_annot_op(ctx, annot);
1817
0
    fz_rethrow(ctx);
1818
0
  }
1819
1820
0
  pdf_dirty_annot(ctx, annot);
1821
0
}
1822
1823
fz_text_language
1824
pdf_document_language(fz_context *ctx, pdf_document *doc)
1825
5.48k
{
1826
5.48k
  pdf_obj *trailer = pdf_trailer(ctx, doc);
1827
5.48k
  pdf_obj *root = pdf_dict_get(ctx, trailer, PDF_NAME(Root));
1828
5.48k
  pdf_obj *lang = pdf_dict_get(ctx, root, PDF_NAME(Lang));
1829
5.48k
  return fz_text_language_from_string(pdf_to_text_string(ctx, lang));
1830
5.48k
}
1831
1832
void pdf_set_document_language(fz_context *ctx, pdf_document *doc, fz_text_language lang)
1833
0
{
1834
0
  pdf_obj *trailer = pdf_trailer(ctx, doc);
1835
0
  pdf_obj *root = pdf_dict_get(ctx, trailer, PDF_NAME(Root));
1836
0
  char buf[8];
1837
0
  if (lang == FZ_LANG_UNSET)
1838
0
    pdf_dict_del(ctx, root, PDF_NAME(Lang));
1839
0
  else
1840
0
    pdf_dict_put_text_string(ctx, root, PDF_NAME(Lang), fz_string_from_text_language(buf, lang));
1841
0
}
1842
1843
fz_text_language
1844
pdf_annot_language(fz_context *ctx, pdf_annot *annot)
1845
5.48k
{
1846
5.48k
  fz_text_language ret;
1847
1848
5.48k
  pdf_annot_push_local_xref(ctx, annot);
1849
1850
10.9k
  fz_try(ctx)
1851
10.9k
  {
1852
5.48k
    pdf_obj *lang = pdf_dict_get_inheritable(ctx, annot->obj, PDF_NAME(Lang));
1853
5.48k
    if (lang)
1854
0
      ret = fz_text_language_from_string(pdf_to_str_buf(ctx, lang));
1855
5.48k
    else
1856
5.48k
      ret = pdf_document_language(ctx, annot->page->doc);
1857
5.48k
  }
1858
10.9k
  fz_always(ctx)
1859
5.48k
    pdf_annot_pop_local_xref(ctx, annot);
1860
5.48k
  fz_catch(ctx)
1861
4
    fz_rethrow(ctx);
1862
1863
5.48k
  return ret;
1864
5.48k
}
1865
1866
void
1867
pdf_set_annot_language(fz_context *ctx, pdf_annot *annot, fz_text_language lang)
1868
0
{
1869
0
  char buf[8];
1870
1871
0
  begin_annot_op(ctx, annot, "Set language");
1872
1873
0
  fz_try(ctx)
1874
0
  {
1875
0
    if (lang == FZ_LANG_UNSET)
1876
0
      pdf_dict_del(ctx, annot->obj, PDF_NAME(Lang));
1877
0
    else
1878
0
      pdf_dict_put_text_string(ctx, annot->obj, PDF_NAME(Lang), fz_string_from_text_language(buf, lang));
1879
0
    end_annot_op(ctx, annot);
1880
0
  }
1881
0
  fz_catch(ctx)
1882
0
  {
1883
0
    abandon_annot_op(ctx, annot);
1884
0
    fz_rethrow(ctx);
1885
0
  }
1886
1887
0
  pdf_dirty_annot(ctx, annot);
1888
0
}
1889
1890
int
1891
pdf_annot_quadding(fz_context *ctx, pdf_annot *annot)
1892
5.48k
{
1893
5.48k
  int q = pdf_dict_get_int(ctx, annot->obj, PDF_NAME(Q));
1894
5.48k
  return (q < 0 || q > 2) ? 0 : q;
1895
5.48k
}
1896
1897
void
1898
pdf_set_annot_quadding(fz_context *ctx, pdf_annot *annot, int q)
1899
0
{
1900
0
  q = (q < 0 || q > 2) ? 0 : q;
1901
1902
0
  begin_annot_op(ctx, annot, "Set quadding");
1903
1904
0
  fz_try(ctx)
1905
0
  {
1906
0
    pdf_dict_put_int(ctx, annot->obj, PDF_NAME(Q), q);
1907
0
    end_annot_op(ctx, annot);
1908
0
  }
1909
0
  fz_catch(ctx)
1910
0
  {
1911
0
    abandon_annot_op(ctx, annot);
1912
0
    fz_rethrow(ctx);
1913
0
  }
1914
1915
0
  pdf_dirty_annot(ctx, annot);
1916
0
}
1917
1918
float pdf_annot_opacity(fz_context *ctx, pdf_annot *annot)
1919
457
{
1920
457
  float ret = 1;
1921
1922
457
  pdf_annot_push_local_xref(ctx, annot);
1923
1924
914
  fz_try(ctx)
1925
914
  {
1926
457
    pdf_obj *ca = pdf_dict_get(ctx, annot->obj, PDF_NAME(CA));
1927
457
    if (pdf_is_number(ctx, ca))
1928
162
      ret = pdf_to_real(ctx, ca);
1929
457
  }
1930
914
  fz_always(ctx)
1931
457
    pdf_annot_pop_local_xref(ctx, annot);
1932
457
  fz_catch(ctx)
1933
0
    fz_rethrow(ctx);
1934
1935
457
  return ret;
1936
457
}
1937
1938
void pdf_set_annot_opacity(fz_context *ctx, pdf_annot *annot, float opacity)
1939
0
{
1940
0
  begin_annot_op(ctx, annot, "Set opacity");
1941
1942
0
  fz_try(ctx)
1943
0
  {
1944
0
    if (opacity != 1)
1945
0
      pdf_dict_put_real(ctx, annot->obj, PDF_NAME(CA), opacity);
1946
0
    else
1947
0
      pdf_dict_del(ctx, annot->obj, PDF_NAME(CA));
1948
0
    end_annot_op(ctx, annot);
1949
0
  }
1950
0
  fz_catch(ctx)
1951
0
  {
1952
0
    abandon_annot_op(ctx, annot);
1953
0
    fz_rethrow(ctx);
1954
0
  }
1955
1956
0
  pdf_dirty_annot(ctx, annot);
1957
0
}
1958
1959
static void pdf_annot_color_imp(fz_context *ctx, pdf_obj *arr, int *n, float color[4])
1960
15.2k
{
1961
15.2k
  switch (pdf_array_len(ctx, arr))
1962
15.2k
  {
1963
14.6k
  case 0:
1964
14.6k
    if (n)
1965
14.6k
      *n = 0;
1966
14.6k
    break;
1967
65
  case 1:
1968
65
  case 2:
1969
65
    if (n)
1970
65
      *n = 1;
1971
65
    if (color)
1972
65
      color[0] = pdf_array_get_real(ctx, arr, 0);
1973
65
    break;
1974
562
  case 3:
1975
562
    if (n)
1976
562
      *n = 3;
1977
562
    if (color)
1978
562
    {
1979
562
      color[0] = pdf_array_get_real(ctx, arr, 0);
1980
562
      color[1] = pdf_array_get_real(ctx, arr, 1);
1981
562
      color[2] = pdf_array_get_real(ctx, arr, 2);
1982
562
    }
1983
562
    break;
1984
0
  case 4:
1985
0
  default:
1986
0
    if (n)
1987
0
      *n = 4;
1988
0
    if (color)
1989
0
    {
1990
0
      color[0] = pdf_array_get_real(ctx, arr, 0);
1991
0
      color[1] = pdf_array_get_real(ctx, arr, 1);
1992
0
      color[2] = pdf_array_get_real(ctx, arr, 2);
1993
0
      color[3] = pdf_array_get_real(ctx, arr, 3);
1994
0
    }
1995
0
    break;
1996
15.2k
  }
1997
15.2k
}
1998
1999
static int pdf_annot_color_rgb(fz_context *ctx, pdf_obj *arr, float rgb[3])
2000
236
{
2001
236
  float color[4];
2002
236
  int n;
2003
236
  pdf_annot_color_imp(ctx, arr, &n, color);
2004
236
  if (n == 0)
2005
182
  {
2006
182
    return 0;
2007
182
  }
2008
54
  else if (n == 1)
2009
38
  {
2010
38
    rgb[0] = rgb[1] = rgb[2] = color[0];
2011
38
  }
2012
16
  else if (n == 3)
2013
16
  {
2014
16
    rgb[0] = color[0];
2015
16
    rgb[1] = color[1];
2016
16
    rgb[2] = color[2];
2017
16
  }
2018
0
  else if (n == 4)
2019
0
  {
2020
0
    rgb[0] = 1 - fz_min(1, color[0] + color[3]);
2021
0
    rgb[1] = 1 - fz_min(1, color[1] + color[3]);
2022
0
    rgb[2] = 1 - fz_min(1, color[2] + color[3]);
2023
0
  }
2024
54
  return 1;
2025
236
}
2026
2027
static void pdf_set_annot_color_imp(fz_context *ctx, pdf_annot *annot, pdf_obj *key, int n, const float *color, pdf_obj **allowed)
2028
0
{
2029
0
  pdf_document *doc = annot->page->doc;
2030
0
  pdf_obj *arr;
2031
2032
0
  if (allowed)
2033
0
    check_allowed_subtypes(ctx, annot, key, allowed);
2034
0
  if (n != 0 && n != 1 && n != 3 && n != 4)
2035
0
    fz_throw(ctx, FZ_ERROR_GENERIC, "color must be 0, 1, 3 or 4 components");
2036
0
  if (!color)
2037
0
    fz_throw(ctx, FZ_ERROR_GENERIC, "no color given");
2038
2039
0
  arr = pdf_new_array(ctx, doc, n);
2040
0
  fz_try(ctx)
2041
0
  {
2042
0
    switch (n)
2043
0
    {
2044
0
    case 1:
2045
0
      pdf_array_push_real(ctx, arr, color[0]);
2046
0
      break;
2047
0
    case 3:
2048
0
      pdf_array_push_real(ctx, arr, color[0]);
2049
0
      pdf_array_push_real(ctx, arr, color[1]);
2050
0
      pdf_array_push_real(ctx, arr, color[2]);
2051
0
      break;
2052
0
    case 4:
2053
0
      pdf_array_push_real(ctx, arr, color[0]);
2054
0
      pdf_array_push_real(ctx, arr, color[1]);
2055
0
      pdf_array_push_real(ctx, arr, color[2]);
2056
0
      pdf_array_push_real(ctx, arr, color[3]);
2057
0
      break;
2058
0
    }
2059
0
  }
2060
0
  fz_catch(ctx)
2061
0
  {
2062
0
    pdf_drop_obj(ctx, arr);
2063
0
    fz_rethrow(ctx);
2064
0
  }
2065
2066
0
  pdf_dict_put_drop(ctx, annot->obj, key, arr);
2067
0
  pdf_dirty_annot(ctx, annot);
2068
0
}
2069
2070
void
2071
pdf_annot_color(fz_context *ctx, pdf_annot *annot, int *n, float color[4])
2072
496
{
2073
496
  pdf_annot_push_local_xref(ctx, annot);
2074
2075
992
  fz_try(ctx)
2076
992
  {
2077
496
    pdf_obj *c = pdf_dict_get(ctx, annot->obj, PDF_NAME(C));
2078
496
    pdf_annot_color_imp(ctx, c, n, color);
2079
496
  }
2080
992
  fz_always(ctx)
2081
496
    pdf_annot_pop_local_xref(ctx, annot);
2082
496
  fz_catch(ctx)
2083
0
    fz_rethrow(ctx);
2084
496
}
2085
2086
void
2087
pdf_annot_MK_BG(fz_context *ctx, pdf_annot *annot, int *n, float color[4])
2088
7.20k
{
2089
7.20k
  pdf_annot_push_local_xref(ctx, annot);
2090
2091
14.4k
  fz_try(ctx)
2092
14.4k
  {
2093
7.20k
    pdf_obj *mk_bg = pdf_dict_get(ctx, pdf_dict_get(ctx, annot->obj, PDF_NAME(MK)), PDF_NAME(BG));
2094
7.20k
    pdf_annot_color_imp(ctx, mk_bg, n, color);
2095
7.20k
  }
2096
14.4k
  fz_always(ctx)
2097
7.20k
    pdf_annot_pop_local_xref(ctx, annot);
2098
7.20k
  fz_catch(ctx)
2099
0
    fz_rethrow(ctx);
2100
7.20k
}
2101
2102
int
2103
pdf_annot_MK_BG_rgb(fz_context *ctx, pdf_annot *annot, float rgb[3])
2104
118
{
2105
118
  int ret;
2106
2107
118
  pdf_annot_push_local_xref(ctx, annot);
2108
2109
236
  fz_try(ctx)
2110
236
  {
2111
118
    pdf_obj *mk_bg = pdf_dict_get(ctx, pdf_dict_get(ctx, annot->obj, PDF_NAME(MK)), PDF_NAME(BG));
2112
118
    ret = pdf_annot_color_rgb(ctx, mk_bg, rgb);
2113
118
  }
2114
236
  fz_always(ctx)
2115
118
    pdf_annot_pop_local_xref(ctx, annot);
2116
118
  fz_catch(ctx)
2117
0
    fz_rethrow(ctx);
2118
2119
118
  return ret;
2120
118
}
2121
2122
void
2123
pdf_annot_MK_BC(fz_context *ctx, pdf_annot *annot, int *n, float color[4])
2124
7.20k
{
2125
7.20k
  pdf_annot_push_local_xref(ctx, annot);
2126
2127
14.4k
  fz_try(ctx)
2128
14.4k
  {
2129
7.20k
    pdf_obj *mk_bc = pdf_dict_get(ctx, pdf_dict_get(ctx, annot->obj, PDF_NAME(MK)), PDF_NAME(BC));
2130
7.20k
    pdf_annot_color_imp(ctx, mk_bc, n, color);
2131
7.20k
  }
2132
14.4k
  fz_always(ctx)
2133
7.20k
    pdf_annot_pop_local_xref(ctx, annot);
2134
7.20k
  fz_catch(ctx)
2135
0
    fz_rethrow(ctx);
2136
7.20k
}
2137
2138
int
2139
pdf_annot_MK_BC_rgb(fz_context *ctx, pdf_annot *annot, float rgb[3])
2140
118
{
2141
118
  int ret;
2142
2143
118
  pdf_annot_push_local_xref(ctx, annot);
2144
2145
236
  fz_try(ctx)
2146
236
  {
2147
118
    pdf_obj *mk_bc = pdf_dict_get(ctx, pdf_dict_get(ctx, annot->obj, PDF_NAME(MK)), PDF_NAME(BC));
2148
118
    ret = pdf_annot_color_rgb(ctx, mk_bc, rgb);
2149
118
  }
2150
236
  fz_always(ctx)
2151
118
    pdf_annot_pop_local_xref(ctx, annot);
2152
118
  fz_catch(ctx)
2153
0
    fz_rethrow(ctx);
2154
2155
118
  return ret;
2156
118
}
2157
2158
void
2159
pdf_set_annot_color(fz_context *ctx, pdf_annot *annot, int n, const float *color)
2160
0
{
2161
0
  begin_annot_op(ctx, annot, "Set color");
2162
2163
0
  fz_try(ctx)
2164
0
  {
2165
0
    pdf_set_annot_color_imp(ctx, annot, PDF_NAME(C), n, color, NULL);
2166
0
    end_annot_op(ctx, annot);
2167
0
  }
2168
0
  fz_catch(ctx)
2169
0
  {
2170
0
    abandon_annot_op(ctx, annot);
2171
0
    fz_rethrow(ctx);
2172
0
  }
2173
0
}
2174
2175
static pdf_obj *interior_color_subtypes[] = {
2176
  PDF_NAME(Circle),
2177
  PDF_NAME(Line),
2178
  PDF_NAME(PolyLine),
2179
  PDF_NAME(Polygon),
2180
  PDF_NAME(Square),
2181
  NULL,
2182
};
2183
2184
int
2185
pdf_annot_has_interior_color(fz_context *ctx, pdf_annot *annot)
2186
0
{
2187
0
  return is_allowed_subtype_wrap(ctx, annot, PDF_NAME(IC), interior_color_subtypes);
2188
0
}
2189
2190
void
2191
pdf_annot_interior_color(fz_context *ctx, pdf_annot *annot, int *n, float color[4])
2192
116
{
2193
116
  pdf_annot_push_local_xref(ctx, annot);
2194
2195
232
  fz_try(ctx)
2196
232
  {
2197
116
    pdf_obj *ic = pdf_dict_get(ctx, annot->obj, PDF_NAME(IC));
2198
116
    pdf_annot_color_imp(ctx, ic, n, color);
2199
116
  }
2200
232
  fz_always(ctx)
2201
116
    pdf_annot_pop_local_xref(ctx, annot);
2202
116
  fz_catch(ctx)
2203
0
    fz_rethrow(ctx);
2204
116
}
2205
2206
void
2207
pdf_set_annot_interior_color(fz_context *ctx, pdf_annot *annot, int n, const float *color)
2208
0
{
2209
0
  begin_annot_op(ctx, annot, "Set interior color");
2210
2211
0
  fz_try(ctx)
2212
0
  {
2213
0
    pdf_set_annot_color_imp(ctx, annot, PDF_NAME(IC), n, color, interior_color_subtypes);
2214
0
    end_annot_op(ctx, annot);
2215
0
  }
2216
0
  fz_catch(ctx)
2217
0
  {
2218
0
    abandon_annot_op(ctx, annot);
2219
0
    fz_rethrow(ctx);
2220
0
  }
2221
0
}
2222
2223
static pdf_obj *line_subtypes[] = {
2224
  PDF_NAME(Line),
2225
  NULL,
2226
};
2227
2228
int
2229
pdf_annot_has_line(fz_context *ctx, pdf_annot *annot)
2230
0
{
2231
0
  return is_allowed_subtype_wrap(ctx, annot, PDF_NAME(L), line_subtypes);
2232
0
}
2233
2234
void
2235
pdf_annot_line(fz_context *ctx, pdf_annot *annot, fz_point *a, fz_point *b)
2236
0
{
2237
0
  fz_matrix page_ctm;
2238
0
  pdf_obj *line;
2239
2240
0
  pdf_annot_push_local_xref(ctx, annot);
2241
2242
0
  fz_try(ctx)
2243
0
  {
2244
0
    check_allowed_subtypes(ctx, annot, PDF_NAME(L), line_subtypes);
2245
2246
0
    pdf_page_transform(ctx, annot->page, NULL, &page_ctm);
2247
2248
0
    line = pdf_dict_get(ctx, annot->obj, PDF_NAME(L));
2249
0
    a->x = pdf_array_get_real(ctx, line, 0);
2250
0
    a->y = pdf_array_get_real(ctx, line, 1);
2251
0
    b->x = pdf_array_get_real(ctx, line, 2);
2252
0
    b->y = pdf_array_get_real(ctx, line, 3);
2253
0
    *a = fz_transform_point(*a, page_ctm);
2254
0
    *b = fz_transform_point(*b, page_ctm);
2255
0
  }
2256
0
  fz_always(ctx)
2257
0
    pdf_annot_pop_local_xref(ctx, annot);
2258
0
  fz_catch(ctx)
2259
0
    fz_rethrow(ctx);
2260
0
}
2261
2262
void
2263
pdf_set_annot_line(fz_context *ctx, pdf_annot *annot, fz_point a, fz_point b)
2264
0
{
2265
0
  fz_matrix page_ctm, inv_page_ctm;
2266
0
  pdf_obj *line;
2267
2268
0
  begin_annot_op(ctx, annot, "Set line");
2269
2270
0
  fz_try(ctx)
2271
0
  {
2272
0
    check_allowed_subtypes(ctx, annot, PDF_NAME(L), line_subtypes);
2273
2274
0
    pdf_page_transform(ctx, annot->page, NULL, &page_ctm);
2275
0
    inv_page_ctm = fz_invert_matrix(page_ctm);
2276
2277
0
    a = fz_transform_point(a, inv_page_ctm);
2278
0
    b = fz_transform_point(b, inv_page_ctm);
2279
2280
0
    line = pdf_new_array(ctx, annot->page->doc, 4);
2281
0
    pdf_dict_put_drop(ctx, annot->obj, PDF_NAME(L), line);
2282
0
    pdf_array_push_real(ctx, line, a.x);
2283
0
    pdf_array_push_real(ctx, line, a.y);
2284
0
    pdf_array_push_real(ctx, line, b.x);
2285
0
    pdf_array_push_real(ctx, line, b.y);
2286
0
    end_annot_op(ctx, annot);
2287
0
  }
2288
0
  fz_catch(ctx)
2289
0
  {
2290
0
    abandon_annot_op(ctx, annot);
2291
0
    fz_rethrow(ctx);
2292
0
  }
2293
2294
0
  pdf_dirty_annot(ctx, annot);
2295
0
}
2296
2297
static pdf_obj *vertices_subtypes[] = {
2298
  PDF_NAME(PolyLine),
2299
  PDF_NAME(Polygon),
2300
  NULL,
2301
};
2302
2303
int
2304
pdf_annot_has_vertices(fz_context *ctx, pdf_annot *annot)
2305
0
{
2306
0
  return is_allowed_subtype_wrap(ctx, annot, PDF_NAME(Vertices), vertices_subtypes);
2307
0
}
2308
2309
int
2310
pdf_annot_vertex_count(fz_context *ctx, pdf_annot *annot)
2311
0
{
2312
0
  pdf_obj *vertices;
2313
0
  int ret;
2314
2315
0
  pdf_annot_push_local_xref(ctx, annot);
2316
2317
0
  fz_try(ctx)
2318
0
  {
2319
0
    check_allowed_subtypes(ctx, annot, PDF_NAME(Vertices), vertices_subtypes);
2320
0
    vertices = pdf_dict_get(ctx, annot->obj, PDF_NAME(Vertices));
2321
0
    ret = pdf_array_len(ctx, vertices) / 2;
2322
0
  }
2323
0
  fz_always(ctx)
2324
0
    pdf_annot_pop_local_xref(ctx, annot);
2325
0
  fz_catch(ctx)
2326
0
    fz_rethrow(ctx);
2327
2328
0
  return ret;
2329
0
}
2330
2331
fz_point
2332
pdf_annot_vertex(fz_context *ctx, pdf_annot *annot, int i)
2333
0
{
2334
0
  pdf_obj *vertices;
2335
0
  fz_matrix page_ctm;
2336
0
  fz_point point;
2337
2338
0
  pdf_annot_push_local_xref(ctx, annot);
2339
2340
0
  fz_try(ctx)
2341
0
  {
2342
0
    check_allowed_subtypes(ctx, annot, PDF_NAME(Vertices), vertices_subtypes);
2343
2344
0
    vertices = pdf_dict_get(ctx, annot->obj, PDF_NAME(Vertices));
2345
2346
0
    pdf_page_transform(ctx, annot->page, NULL, &page_ctm);
2347
2348
0
    point.x = pdf_array_get_real(ctx, vertices, i * 2);
2349
0
    point.y = pdf_array_get_real(ctx, vertices, i * 2 + 1);
2350
0
  }
2351
0
  fz_always(ctx)
2352
0
    pdf_annot_pop_local_xref(ctx, annot);
2353
0
  fz_catch(ctx)
2354
0
    fz_rethrow(ctx);
2355
2356
0
  return fz_transform_point(point, page_ctm);
2357
0
}
2358
2359
void
2360
pdf_set_annot_vertices(fz_context *ctx, pdf_annot *annot, int n, const fz_point *v)
2361
0
{
2362
0
  pdf_document *doc = annot->page->doc;
2363
0
  fz_matrix page_ctm, inv_page_ctm;
2364
0
  pdf_obj *vertices;
2365
0
  fz_point point;
2366
0
  int i;
2367
2368
0
  begin_annot_op(ctx, annot, "Set points");
2369
2370
0
  fz_try(ctx)
2371
0
  {
2372
0
    check_allowed_subtypes(ctx, annot, PDF_NAME(Vertices), vertices_subtypes);
2373
0
    if (n <= 0 || !v)
2374
0
      fz_throw(ctx, FZ_ERROR_GENERIC, "invalid number of vertices");
2375
2376
0
    pdf_page_transform(ctx, annot->page, NULL, &page_ctm);
2377
0
    inv_page_ctm = fz_invert_matrix(page_ctm);
2378
2379
0
    vertices = pdf_new_array(ctx, doc, n * 2);
2380
0
    for (i = 0; i < n; ++i)
2381
0
    {
2382
0
      point = fz_transform_point(v[i], inv_page_ctm);
2383
0
      pdf_array_push_real(ctx, vertices, point.x);
2384
0
      pdf_array_push_real(ctx, vertices, point.y);
2385
0
    }
2386
0
    pdf_dict_put_drop(ctx, annot->obj, PDF_NAME(Vertices), vertices);
2387
0
    end_annot_op(ctx, annot);
2388
0
  }
2389
0
  fz_catch(ctx)
2390
0
  {
2391
0
    abandon_annot_op(ctx, annot);
2392
0
    fz_rethrow(ctx);
2393
0
  }
2394
2395
0
  pdf_dirty_annot(ctx, annot);
2396
0
}
2397
2398
void pdf_clear_annot_vertices(fz_context *ctx, pdf_annot *annot)
2399
0
{
2400
0
  begin_annot_op(ctx, annot, "Clear vertices");
2401
2402
0
  fz_try(ctx)
2403
0
  {
2404
0
    check_allowed_subtypes(ctx, annot, PDF_NAME(Vertices), vertices_subtypes);
2405
0
    pdf_dict_del(ctx, annot->obj, PDF_NAME(Vertices));
2406
0
    end_annot_op(ctx, annot);
2407
0
  }
2408
0
  fz_catch(ctx)
2409
0
  {
2410
0
    abandon_annot_op(ctx, annot);
2411
0
    fz_rethrow(ctx);
2412
0
  }
2413
2414
0
  pdf_dirty_annot(ctx, annot);
2415
0
}
2416
2417
void pdf_add_annot_vertex(fz_context *ctx, pdf_annot *annot, fz_point p)
2418
0
{
2419
0
  pdf_document *doc = annot->page->doc;
2420
0
  fz_matrix page_ctm, inv_page_ctm;
2421
0
  pdf_obj *vertices;
2422
2423
0
  begin_annot_op(ctx, annot, "Add point");
2424
2425
0
  fz_try(ctx)
2426
0
  {
2427
0
    check_allowed_subtypes(ctx, annot, PDF_NAME(Vertices), vertices_subtypes);
2428
2429
0
    pdf_page_transform(ctx, annot->page, NULL, &page_ctm);
2430
0
    inv_page_ctm = fz_invert_matrix(page_ctm);
2431
2432
0
    vertices = pdf_dict_get(ctx, annot->obj, PDF_NAME(Vertices));
2433
0
    if (!pdf_is_array(ctx, vertices))
2434
0
    {
2435
0
      vertices = pdf_new_array(ctx, doc, 32);
2436
0
      pdf_dict_put_drop(ctx, annot->obj, PDF_NAME(Vertices), vertices);
2437
0
    }
2438
2439
0
    p = fz_transform_point(p, inv_page_ctm);
2440
0
    pdf_array_push_real(ctx, vertices, p.x);
2441
0
    pdf_array_push_real(ctx, vertices, p.y);
2442
0
    end_annot_op(ctx, annot);
2443
0
  }
2444
0
  fz_catch(ctx)
2445
0
  {
2446
0
    abandon_annot_op(ctx, annot);
2447
0
    fz_rethrow(ctx);
2448
0
  }
2449
2450
0
  pdf_dirty_annot(ctx, annot);
2451
0
}
2452
2453
void pdf_set_annot_vertex(fz_context *ctx, pdf_annot *annot, int i, fz_point p)
2454
0
{
2455
0
  fz_matrix page_ctm, inv_page_ctm;
2456
0
  pdf_obj *vertices;
2457
2458
0
  begin_annot_op(ctx, annot, "Set point");
2459
2460
0
  fz_try(ctx)
2461
0
  {
2462
0
    check_allowed_subtypes(ctx, annot, PDF_NAME(Vertices), vertices_subtypes);
2463
2464
0
    pdf_page_transform(ctx, annot->page, NULL, &page_ctm);
2465
0
    inv_page_ctm = fz_invert_matrix(page_ctm);
2466
2467
0
    p = fz_transform_point(p, inv_page_ctm);
2468
2469
0
    vertices = pdf_dict_get(ctx, annot->obj, PDF_NAME(Vertices));
2470
0
    pdf_array_put_drop(ctx, vertices, i * 2 + 0, pdf_new_real(ctx, p.x));
2471
0
    pdf_array_put_drop(ctx, vertices, i * 2 + 1, pdf_new_real(ctx, p.y));
2472
0
    end_annot_op(ctx, annot);
2473
0
  }
2474
0
  fz_catch(ctx)
2475
0
  {
2476
0
    abandon_annot_op(ctx, annot);
2477
0
    fz_rethrow(ctx);
2478
0
  }
2479
0
}
2480
2481
static pdf_obj *quad_point_subtypes[] = {
2482
  PDF_NAME(Highlight),
2483
  PDF_NAME(Link),
2484
  PDF_NAME(Squiggly),
2485
  PDF_NAME(StrikeOut),
2486
  PDF_NAME(Underline),
2487
  PDF_NAME(Redact),
2488
  NULL,
2489
};
2490
2491
int
2492
pdf_annot_has_quad_points(fz_context *ctx, pdf_annot *annot)
2493
0
{
2494
0
  return is_allowed_subtype_wrap(ctx, annot, PDF_NAME(QuadPoints), quad_point_subtypes);
2495
0
}
2496
2497
int
2498
pdf_annot_quad_point_count(fz_context *ctx, pdf_annot *annot)
2499
0
{
2500
0
  pdf_obj *quad_points;
2501
0
  int ret;
2502
2503
0
  pdf_annot_push_local_xref(ctx, annot);
2504
2505
0
  fz_try(ctx)
2506
0
  {
2507
0
    check_allowed_subtypes(ctx, annot, PDF_NAME(QuadPoints), quad_point_subtypes);
2508
0
    quad_points = pdf_dict_get(ctx, annot->obj, PDF_NAME(QuadPoints));
2509
0
    ret = pdf_array_len(ctx, quad_points) / 8;
2510
0
  }
2511
0
  fz_always(ctx)
2512
0
    pdf_annot_pop_local_xref(ctx, annot);
2513
0
  fz_catch(ctx)
2514
0
    fz_rethrow(ctx);
2515
2516
0
  return ret;
2517
0
}
2518
2519
fz_quad
2520
pdf_annot_quad_point(fz_context *ctx, pdf_annot *annot, int idx)
2521
0
{
2522
0
  pdf_obj *quad_points;
2523
0
  fz_matrix page_ctm;
2524
0
  float v[8];
2525
0
  int i;
2526
2527
0
  pdf_annot_push_local_xref(ctx, annot);
2528
2529
0
  fz_try(ctx)
2530
0
  {
2531
0
    check_allowed_subtypes(ctx, annot, PDF_NAME(QuadPoints), quad_point_subtypes);
2532
0
    quad_points = pdf_dict_get(ctx, annot->obj, PDF_NAME(QuadPoints));
2533
0
    pdf_page_transform(ctx, annot->page, NULL, &page_ctm);
2534
2535
0
    for (i = 0; i < 8; i += 2)
2536
0
    {
2537
0
      fz_point point;
2538
0
      point.x = pdf_array_get_real(ctx, quad_points, idx * 8 + i + 0);
2539
0
      point.y = pdf_array_get_real(ctx, quad_points, idx * 8 + i + 1);
2540
0
      point = fz_transform_point(point, page_ctm);
2541
0
      v[i+0] = point.x;
2542
0
      v[i+1] = point.y;
2543
0
    }
2544
0
  }
2545
0
  fz_always(ctx)
2546
0
    pdf_annot_pop_local_xref(ctx, annot);
2547
0
  fz_catch(ctx)
2548
0
    fz_rethrow(ctx);
2549
2550
0
  return fz_make_quad(v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7]);
2551
0
}
2552
2553
void
2554
pdf_set_annot_quad_points(fz_context *ctx, pdf_annot *annot, int n, const fz_quad *q)
2555
0
{
2556
0
  pdf_document *doc = annot->page->doc;
2557
0
  fz_matrix page_ctm, inv_page_ctm;
2558
0
  pdf_obj *quad_points;
2559
0
  fz_quad quad;
2560
0
  int i;
2561
2562
0
  begin_annot_op(ctx, annot, "Set quad points");
2563
2564
0
  fz_try(ctx)
2565
0
  {
2566
0
    check_allowed_subtypes(ctx, annot, PDF_NAME(QuadPoints), quad_point_subtypes);
2567
0
    if (n <= 0 || !q)
2568
0
      fz_throw(ctx, FZ_ERROR_GENERIC, "invalid number of quadrilaterals");
2569
2570
0
    pdf_page_transform(ctx, annot->page, NULL, &page_ctm);
2571
0
    inv_page_ctm = fz_invert_matrix(page_ctm);
2572
2573
0
    quad_points = pdf_new_array(ctx, doc, n);
2574
0
    for (i = 0; i < n; ++i)
2575
0
    {
2576
0
      quad = fz_transform_quad(q[i], inv_page_ctm);
2577
0
      pdf_array_push_real(ctx, quad_points, quad.ul.x);
2578
0
      pdf_array_push_real(ctx, quad_points, quad.ul.y);
2579
0
      pdf_array_push_real(ctx, quad_points, quad.ur.x);
2580
0
      pdf_array_push_real(ctx, quad_points, quad.ur.y);
2581
0
      pdf_array_push_real(ctx, quad_points, quad.ll.x);
2582
0
      pdf_array_push_real(ctx, quad_points, quad.ll.y);
2583
0
      pdf_array_push_real(ctx, quad_points, quad.lr.x);
2584
0
      pdf_array_push_real(ctx, quad_points, quad.lr.y);
2585
0
    }
2586
0
    pdf_dict_put_drop(ctx, annot->obj, PDF_NAME(QuadPoints), quad_points);
2587
0
    end_annot_op(ctx, annot);
2588
0
  }
2589
0
  fz_catch(ctx)
2590
0
  {
2591
0
    abandon_annot_op(ctx, annot);
2592
0
    fz_rethrow(ctx);
2593
0
  }
2594
2595
0
  pdf_dirty_annot(ctx, annot);
2596
0
}
2597
2598
void
2599
pdf_clear_annot_quad_points(fz_context *ctx, pdf_annot *annot)
2600
0
{
2601
0
  begin_annot_op(ctx, annot, "Clear quad points");
2602
2603
0
  fz_try(ctx)
2604
0
  {
2605
0
    check_allowed_subtypes(ctx, annot, PDF_NAME(QuadPoints), quad_point_subtypes);
2606
0
    pdf_dict_del(ctx, annot->obj, PDF_NAME(QuadPoints));
2607
0
    end_annot_op(ctx, annot);
2608
0
  }
2609
0
  fz_catch(ctx)
2610
0
  {
2611
0
    abandon_annot_op(ctx, annot);
2612
0
    fz_rethrow(ctx);
2613
0
  }
2614
2615
0
  pdf_dirty_annot(ctx, annot);
2616
0
}
2617
2618
void
2619
pdf_add_annot_quad_point(fz_context *ctx, pdf_annot *annot, fz_quad quad)
2620
0
{
2621
0
  pdf_document *doc = annot->page->doc;
2622
0
  fz_matrix page_ctm, inv_page_ctm;
2623
0
  pdf_obj *quad_points;
2624
2625
0
  begin_annot_op(ctx, annot, "Add quad point");
2626
2627
0
  fz_try(ctx)
2628
0
  {
2629
0
    check_allowed_subtypes(ctx, annot, PDF_NAME(QuadPoints), quad_point_subtypes);
2630
2631
0
    pdf_page_transform(ctx, annot->page, NULL, &page_ctm);
2632
0
    inv_page_ctm = fz_invert_matrix(page_ctm);
2633
2634
0
    quad_points = pdf_dict_get(ctx, annot->obj, PDF_NAME(QuadPoints));
2635
0
    if (!pdf_is_array(ctx, quad_points))
2636
0
    {
2637
0
      quad_points = pdf_new_array(ctx, doc, 8);
2638
0
      pdf_dict_put_drop(ctx, annot->obj, PDF_NAME(QuadPoints), quad_points);
2639
0
    }
2640
2641
    /* Contrary to the specification, the points within a QuadPoint are NOT ordered
2642
     * in a counterclockwise fashion. Experiments with Adobe's implementation
2643
     * indicates a cross-wise ordering is intended: ul, ur, ll, lr.
2644
     */
2645
0
    quad = fz_transform_quad(quad, inv_page_ctm);
2646
0
    pdf_array_push_real(ctx, quad_points, quad.ul.x);
2647
0
    pdf_array_push_real(ctx, quad_points, quad.ul.y);
2648
0
    pdf_array_push_real(ctx, quad_points, quad.ur.x);
2649
0
    pdf_array_push_real(ctx, quad_points, quad.ur.y);
2650
0
    pdf_array_push_real(ctx, quad_points, quad.ll.x);
2651
0
    pdf_array_push_real(ctx, quad_points, quad.ll.y);
2652
0
    pdf_array_push_real(ctx, quad_points, quad.lr.x);
2653
0
    pdf_array_push_real(ctx, quad_points, quad.lr.y);
2654
0
    end_annot_op(ctx, annot);
2655
0
  }
2656
0
  fz_catch(ctx)
2657
0
  {
2658
0
    abandon_annot_op(ctx, annot);
2659
0
    fz_rethrow(ctx);
2660
0
  }
2661
2662
0
  pdf_dirty_annot(ctx, annot);
2663
0
}
2664
2665
static pdf_obj *ink_list_subtypes[] = {
2666
  PDF_NAME(Ink),
2667
  NULL,
2668
};
2669
2670
int
2671
pdf_annot_has_ink_list(fz_context *ctx, pdf_annot *annot)
2672
0
{
2673
0
  return is_allowed_subtype_wrap(ctx, annot, PDF_NAME(InkList), ink_list_subtypes);
2674
0
}
2675
2676
int
2677
pdf_annot_ink_list_count(fz_context *ctx, pdf_annot *annot)
2678
0
{
2679
0
  int ret;
2680
2681
0
  pdf_annot_push_local_xref(ctx, annot);
2682
2683
0
  fz_try(ctx)
2684
0
  {
2685
0
    pdf_obj *ink_list;
2686
0
    check_allowed_subtypes(ctx, annot, PDF_NAME(InkList), ink_list_subtypes);
2687
0
    ink_list = pdf_dict_get(ctx, annot->obj, PDF_NAME(InkList));
2688
0
    ret = pdf_array_len(ctx, ink_list);
2689
0
  }
2690
0
  fz_always(ctx)
2691
0
    pdf_annot_pop_local_xref(ctx, annot);
2692
0
  fz_catch(ctx)
2693
0
    fz_rethrow(ctx);
2694
2695
0
  return ret;
2696
0
}
2697
2698
int
2699
pdf_annot_ink_list_stroke_count(fz_context *ctx, pdf_annot *annot, int i)
2700
0
{
2701
0
  pdf_obj *ink_list;
2702
0
  pdf_obj *stroke;
2703
0
  int ret;
2704
2705
0
  pdf_annot_push_local_xref(ctx, annot);
2706
2707
0
  fz_try(ctx)
2708
0
  {
2709
0
    check_allowed_subtypes(ctx, annot, PDF_NAME(InkList), ink_list_subtypes);
2710
0
    ink_list = pdf_dict_get(ctx, annot->obj, PDF_NAME(InkList));
2711
0
    stroke = pdf_array_get(ctx, ink_list, i);
2712
0
    ret = pdf_array_len(ctx, stroke) / 2;
2713
0
  }
2714
0
  fz_always(ctx)
2715
0
    pdf_annot_pop_local_xref(ctx, annot);
2716
0
  fz_catch(ctx)
2717
0
    fz_rethrow(ctx);
2718
2719
0
  return ret;
2720
0
}
2721
2722
fz_point
2723
pdf_annot_ink_list_stroke_vertex(fz_context *ctx, pdf_annot *annot, int i, int k)
2724
0
{
2725
0
  pdf_obj *ink_list;
2726
0
  pdf_obj *stroke;
2727
0
  fz_matrix page_ctm;
2728
0
  fz_point point;
2729
2730
0
  pdf_annot_push_local_xref(ctx, annot);
2731
2732
0
  fz_try(ctx)
2733
0
  {
2734
0
    check_allowed_subtypes(ctx, annot, PDF_NAME(InkList), ink_list_subtypes);
2735
2736
0
    ink_list = pdf_dict_get(ctx, annot->obj, PDF_NAME(InkList));
2737
0
    stroke = pdf_array_get(ctx, ink_list, i);
2738
2739
0
    pdf_page_transform(ctx, annot->page, NULL, &page_ctm);
2740
2741
0
    point.x = pdf_array_get_real(ctx, stroke, k * 2 + 0);
2742
0
    point.y = pdf_array_get_real(ctx, stroke, k * 2 + 1);
2743
0
  }
2744
0
  fz_always(ctx)
2745
0
    pdf_annot_pop_local_xref(ctx, annot);
2746
0
  fz_catch(ctx)
2747
0
    fz_rethrow(ctx);
2748
2749
0
  return fz_transform_point(point, page_ctm);
2750
0
}
2751
2752
/* FIXME: try/catch required for memory exhaustion */
2753
void
2754
pdf_set_annot_ink_list(fz_context *ctx, pdf_annot *annot, int n, const int *count, const fz_point *v)
2755
0
{
2756
0
  pdf_document *doc = annot->page->doc;
2757
0
  fz_matrix page_ctm, inv_page_ctm;
2758
0
  pdf_obj *ink_list = NULL, *stroke;
2759
0
  fz_point point;
2760
0
  int i, k;
2761
2762
0
  fz_var(ink_list);
2763
2764
0
  begin_annot_op(ctx, annot, "Set ink list");
2765
2766
0
  fz_try(ctx)
2767
0
  {
2768
0
    check_allowed_subtypes(ctx, annot, PDF_NAME(InkList), ink_list_subtypes);
2769
2770
0
    pdf_page_transform(ctx, annot->page, NULL, &page_ctm);
2771
0
    inv_page_ctm = fz_invert_matrix(page_ctm);
2772
2773
0
    ink_list = pdf_new_array(ctx, doc, n);
2774
0
    for (i = 0; i < n; ++i)
2775
0
    {
2776
0
      stroke = pdf_new_array(ctx, doc, count[i] * 2);
2777
0
      pdf_array_push_drop(ctx, ink_list, stroke);
2778
      /* Although we have dropped our reference to stroke,
2779
       * it's still valid because we ink_list holds one, and
2780
       * we hold a reference to that. */
2781
0
      for (k = 0; k < count[i]; ++k)
2782
0
      {
2783
0
        point = fz_transform_point(*v++, inv_page_ctm);
2784
0
        pdf_array_push_real(ctx, stroke, point.x);
2785
0
        pdf_array_push_real(ctx, stroke, point.y);
2786
0
      }
2787
0
    }
2788
0
    pdf_dict_put_drop(ctx, annot->obj, PDF_NAME(InkList), ink_list);
2789
0
    ink_list = NULL;
2790
0
    end_annot_op(ctx, annot);
2791
0
  }
2792
0
  fz_always(ctx)
2793
0
    pdf_drop_obj(ctx, ink_list);
2794
0
  fz_catch(ctx)
2795
0
  {
2796
0
    abandon_annot_op(ctx, annot);
2797
0
    fz_rethrow(ctx);
2798
0
  }
2799
2800
0
  pdf_dirty_annot(ctx, annot);
2801
0
}
2802
2803
void
2804
pdf_clear_annot_ink_list(fz_context *ctx, pdf_annot *annot)
2805
0
{
2806
0
  begin_annot_op(ctx, annot, "Clear ink list");
2807
2808
0
  fz_try(ctx)
2809
0
  {
2810
0
    pdf_dict_del(ctx, annot->obj, PDF_NAME(InkList));
2811
0
    end_annot_op(ctx, annot);
2812
0
  }
2813
0
  fz_catch(ctx)
2814
0
  {
2815
0
    abandon_annot_op(ctx, annot);
2816
0
    fz_rethrow(ctx);
2817
0
  }
2818
2819
0
  pdf_dirty_annot(ctx, annot);
2820
0
}
2821
2822
void pdf_add_annot_ink_list_stroke(fz_context *ctx, pdf_annot *annot)
2823
0
{
2824
0
  pdf_obj *ink_list;
2825
2826
0
  begin_annot_op(ctx, annot, "Add ink list stroke");
2827
2828
0
  fz_try(ctx)
2829
0
  {
2830
0
    ink_list = pdf_dict_get(ctx, annot->obj, PDF_NAME(InkList));
2831
0
    if (!pdf_is_array(ctx, ink_list))
2832
0
      ink_list = pdf_dict_put_array(ctx, annot->obj, PDF_NAME(InkList), 10);
2833
2834
0
    pdf_array_push_array(ctx, ink_list, 16);
2835
0
    end_annot_op(ctx, annot);
2836
0
  }
2837
0
  fz_catch(ctx)
2838
0
  {
2839
0
    abandon_annot_op(ctx, annot);
2840
0
    fz_rethrow(ctx);
2841
0
  }
2842
2843
0
  pdf_dirty_annot(ctx, annot);
2844
0
}
2845
2846
void pdf_add_annot_ink_list_stroke_vertex(fz_context *ctx, pdf_annot *annot, fz_point p)
2847
0
{
2848
0
  fz_matrix page_ctm, inv_page_ctm;
2849
0
  pdf_obj *ink_list, *stroke;
2850
2851
0
  begin_annot_op(ctx, annot, "Add ink list stroke point");
2852
2853
0
  fz_try(ctx)
2854
0
  {
2855
0
    pdf_page_transform(ctx, annot->page, NULL, &page_ctm);
2856
0
    inv_page_ctm = fz_invert_matrix(page_ctm);
2857
2858
0
    ink_list = pdf_dict_get(ctx, annot->obj, PDF_NAME(InkList));
2859
0
    stroke = pdf_array_get(ctx, ink_list, pdf_array_len(ctx, ink_list)-1);
2860
2861
0
    p = fz_transform_point(p, inv_page_ctm);
2862
0
    pdf_array_push_real(ctx, stroke, p.x);
2863
0
    pdf_array_push_real(ctx, stroke, p.y);
2864
0
    end_annot_op(ctx, annot);
2865
0
  }
2866
0
  fz_catch(ctx)
2867
0
  {
2868
0
    abandon_annot_op(ctx, annot);
2869
0
    fz_rethrow(ctx);
2870
0
  }
2871
2872
0
  pdf_dirty_annot(ctx, annot);
2873
0
}
2874
2875
void
2876
pdf_add_annot_ink_list(fz_context *ctx, pdf_annot *annot, int n, fz_point p[])
2877
0
{
2878
0
  fz_matrix page_ctm, inv_page_ctm;
2879
0
  pdf_obj *ink_list, *stroke;
2880
0
  int i;
2881
2882
0
  begin_annot_op(ctx, annot, "Add ink list");
2883
2884
0
  fz_try(ctx)
2885
0
  {
2886
0
    check_allowed_subtypes(ctx, annot, PDF_NAME(InkList), ink_list_subtypes);
2887
2888
0
    pdf_page_transform(ctx, annot->page, NULL, &page_ctm);
2889
0
    inv_page_ctm = fz_invert_matrix(page_ctm);
2890
2891
0
    ink_list = pdf_dict_get(ctx, annot->obj, PDF_NAME(InkList));
2892
0
    if (!pdf_is_array(ctx, ink_list))
2893
0
      ink_list = pdf_dict_put_array(ctx, annot->obj, PDF_NAME(InkList), 10);
2894
2895
0
    stroke = pdf_array_push_array(ctx, ink_list, n * 2);
2896
0
    for (i = 0; i < n; ++i)
2897
0
    {
2898
0
      fz_point tp = fz_transform_point(p[i], inv_page_ctm);
2899
0
      pdf_array_push_real(ctx, stroke, tp.x);
2900
0
      pdf_array_push_real(ctx, stroke, tp.y);
2901
0
    }
2902
0
    end_annot_op(ctx, annot);
2903
0
  }
2904
0
  fz_catch(ctx)
2905
0
  {
2906
0
    abandon_annot_op(ctx, annot);
2907
0
    fz_rethrow(ctx);
2908
0
  }
2909
2910
0
  pdf_dirty_annot(ctx, annot);
2911
0
}
2912
2913
static pdf_obj *markup_subtypes[] = {
2914
  PDF_NAME(Text),
2915
  PDF_NAME(FreeText),
2916
  PDF_NAME(Line),
2917
  PDF_NAME(Square),
2918
  PDF_NAME(Circle),
2919
  PDF_NAME(Polygon),
2920
  PDF_NAME(PolyLine),
2921
  PDF_NAME(Highlight),
2922
  PDF_NAME(Underline),
2923
  PDF_NAME(Squiggly),
2924
  PDF_NAME(StrikeOut),
2925
  PDF_NAME(Redact),
2926
  PDF_NAME(Stamp),
2927
  PDF_NAME(Caret),
2928
  PDF_NAME(Ink),
2929
  PDF_NAME(FileAttachment),
2930
  PDF_NAME(Sound),
2931
  NULL,
2932
};
2933
2934
/*
2935
  Get annotation's modification date in seconds since the epoch.
2936
*/
2937
int64_t
2938
pdf_annot_modification_date(fz_context *ctx, pdf_annot *annot)
2939
0
{
2940
0
  int64_t ret;
2941
2942
0
  pdf_annot_push_local_xref(ctx, annot);
2943
2944
0
  fz_try(ctx)
2945
0
  {
2946
0
    ret = pdf_dict_get_date(ctx, annot->obj, PDF_NAME(M));
2947
0
  }
2948
0
  fz_always(ctx)
2949
0
    pdf_annot_pop_local_xref(ctx, annot);
2950
0
  fz_catch(ctx)
2951
0
    fz_rethrow(ctx);
2952
2953
0
  return ret;
2954
0
}
2955
2956
/*
2957
  Get annotation's creation date in seconds since the epoch.
2958
*/
2959
int64_t
2960
pdf_annot_creation_date(fz_context *ctx, pdf_annot *annot)
2961
0
{
2962
0
  int64_t ret;
2963
2964
0
  pdf_annot_push_local_xref(ctx, annot);
2965
2966
0
  fz_try(ctx)
2967
0
    ret = pdf_dict_get_date(ctx, annot->obj, PDF_NAME(CreationDate));
2968
0
  fz_always(ctx)
2969
0
    pdf_annot_pop_local_xref(ctx, annot);
2970
0
  fz_catch(ctx)
2971
0
    fz_rethrow(ctx);
2972
2973
0
  return ret;
2974
0
}
2975
2976
/*
2977
  Set annotation's modification date in seconds since the epoch.
2978
*/
2979
void
2980
pdf_set_annot_modification_date(fz_context *ctx, pdf_annot *annot, int64_t secs)
2981
0
{
2982
0
  begin_annot_op(ctx, annot, "Set modification date");
2983
2984
0
  fz_try(ctx)
2985
0
  {
2986
0
    check_allowed_subtypes(ctx, annot, PDF_NAME(M), markup_subtypes);
2987
0
    pdf_dict_put_date(ctx, annot->obj, PDF_NAME(M), secs);
2988
0
    end_annot_op(ctx, annot);
2989
0
  }
2990
0
  fz_catch(ctx)
2991
0
  {
2992
0
    abandon_annot_op(ctx, annot);
2993
0
    fz_rethrow(ctx);
2994
0
  }
2995
2996
0
  pdf_dirty_annot(ctx, annot);
2997
0
}
2998
2999
/*
3000
  Set annotation's creation date in seconds since the epoch.
3001
*/
3002
void
3003
pdf_set_annot_creation_date(fz_context *ctx, pdf_annot *annot, int64_t secs)
3004
0
{
3005
0
  begin_annot_op(ctx, annot, "Set creation date");
3006
3007
0
  fz_try(ctx)
3008
0
  {
3009
0
    check_allowed_subtypes(ctx, annot, PDF_NAME(CreationDate), markup_subtypes);
3010
0
    pdf_dict_put_date(ctx, annot->obj, PDF_NAME(CreationDate), secs);
3011
0
    end_annot_op(ctx, annot);
3012
0
  }
3013
0
  fz_catch(ctx)
3014
0
  {
3015
0
    abandon_annot_op(ctx, annot);
3016
0
    fz_rethrow(ctx);
3017
0
  }
3018
3019
0
  pdf_dirty_annot(ctx, annot);
3020
0
}
3021
3022
int
3023
pdf_annot_has_author(fz_context *ctx, pdf_annot *annot)
3024
0
{
3025
0
  return is_allowed_subtype_wrap(ctx, annot, PDF_NAME(T), markup_subtypes);
3026
0
}
3027
3028
const char *
3029
pdf_annot_author(fz_context *ctx, pdf_annot *annot)
3030
0
{
3031
0
  const char *ret;
3032
3033
0
  pdf_annot_push_local_xref(ctx, annot);
3034
3035
0
  fz_try(ctx)
3036
0
  {
3037
0
    check_allowed_subtypes(ctx, annot, PDF_NAME(T), markup_subtypes);
3038
0
    ret = pdf_dict_get_text_string(ctx, annot->obj, PDF_NAME(T));
3039
0
  }
3040
0
  fz_always(ctx)
3041
0
    pdf_annot_pop_local_xref(ctx, annot);
3042
0
  fz_catch(ctx)
3043
0
    fz_rethrow(ctx);
3044
3045
0
  return ret;
3046
0
}
3047
3048
void
3049
pdf_set_annot_author(fz_context *ctx, pdf_annot *annot, const char *author)
3050
0
{
3051
0
  begin_annot_op(ctx, annot, "Set author");
3052
3053
0
  fz_try(ctx)
3054
0
  {
3055
0
    check_allowed_subtypes(ctx, annot, PDF_NAME(T), markup_subtypes);
3056
0
    pdf_dict_put_text_string(ctx, annot->obj, PDF_NAME(T), author);
3057
0
    pdf_dirty_annot(ctx, annot);
3058
0
    end_annot_op(ctx, annot);
3059
0
  }
3060
0
  fz_catch(ctx)
3061
0
  {
3062
0
    abandon_annot_op(ctx, annot);
3063
0
    fz_rethrow(ctx);
3064
0
  }
3065
0
}
3066
3067
void
3068
pdf_parse_default_appearance(fz_context *ctx, const char *da, const char **font, float *size, int *n, float color[4])
3069
5.54k
{
3070
5.54k
  char buf[100], *p = buf, *tok, *end;
3071
5.54k
  float stack[4] = { 0, 0, 0, 0 };
3072
5.54k
  int top = 0;
3073
3074
5.54k
  *font = "Helv";
3075
5.54k
  *size = 12;
3076
5.54k
  *n = 0;
3077
5.54k
  color[0] = color[1] = color[2] = color[3] = 0;
3078
3079
5.54k
  fz_strlcpy(buf, da, sizeof buf);
3080
40.6k
  while ((tok = fz_strsep(&p, " \n\r\t")) != NULL)
3081
35.0k
  {
3082
35.0k
    if (tok[0] == 0)
3083
77
      ;
3084
34.9k
    else if (tok[0] == '/')
3085
5.50k
    {
3086
5.50k
      if (!strcmp(tok+1, "Cour")) *font = "Cour";
3087
5.50k
      if (!strcmp(tok+1, "Helv")) *font = "Helv";
3088
5.50k
      if (!strcmp(tok+1, "TiRo")) *font = "TiRo";
3089
5.50k
      if (!strcmp(tok+1, "Symb")) *font = "Symb";
3090
5.50k
      if (!strcmp(tok+1, "ZaDb")) *font = "ZaDb";
3091
5.50k
    }
3092
29.4k
    else if (!strcmp(tok, "Tf"))
3093
5.49k
    {
3094
5.49k
      *size = stack[0];
3095
5.49k
      top = 0;
3096
5.49k
    }
3097
23.9k
    else if (!strcmp(tok, "g"))
3098
1.77k
    {
3099
1.77k
      *n = 1;
3100
1.77k
      color[0] = stack[0];
3101
1.77k
      top = 0;
3102
1.77k
    }
3103
22.2k
    else if (!strcmp(tok, "rg"))
3104
3.72k
    {
3105
3.72k
      *n = 3;
3106
3.72k
      color[0] = stack[0];
3107
3.72k
      color[1] = stack[1];
3108
3.72k
      color[2] = stack[2];
3109
3.72k
      top=0;
3110
3.72k
    }
3111
18.4k
    else if (!strcmp(tok, "k"))
3112
0
    {
3113
0
      *n = 4;
3114
0
      color[0] = stack[0];
3115
0
      color[1] = stack[1];
3116
0
      color[2] = stack[2];
3117
0
      color[3] = stack[3];
3118
0
      top=0;
3119
0
    }
3120
18.4k
    else
3121
18.4k
    {
3122
18.4k
      float v = fz_strtof(tok, &end);
3123
18.4k
      if (top < 4)
3124
18.4k
        stack[top] = v;
3125
18.4k
      if (*end == 0)
3126
18.4k
        ++top;
3127
43
      else
3128
43
        top = 0;
3129
18.4k
    }
3130
35.0k
  }
3131
5.54k
}
3132
3133
void
3134
pdf_print_default_appearance(fz_context *ctx, char *buf, int nbuf, const char *font, float size, int n, const float *color)
3135
0
{
3136
0
  if (n == 4)
3137
0
    fz_snprintf(buf, nbuf, "/%s %g Tf %g %g %g %g k", font, size, color[0], color[1], color[2], color[3]);
3138
0
  else if (n == 3)
3139
0
    fz_snprintf(buf, nbuf, "/%s %g Tf %g %g %g rg", font, size, color[0], color[1], color[2]);
3140
0
  else if (n == 1)
3141
0
    fz_snprintf(buf, nbuf, "/%s %g Tf %g g", font, size, color[0]);
3142
0
  else
3143
0
    fz_snprintf(buf, nbuf, "/%s %g Tf", font, size);
3144
0
}
3145
3146
void
3147
pdf_annot_default_appearance(fz_context *ctx, pdf_annot *annot, const char **font, float *size, int *n, float color[4])
3148
5.54k
{
3149
5.54k
  pdf_obj *da = pdf_dict_get_inheritable(ctx, annot->obj, PDF_NAME(DA));
3150
5.54k
  if (!da)
3151
54
  {
3152
54
    pdf_obj *trailer = pdf_trailer(ctx, annot->page->doc);
3153
54
    da = pdf_dict_getl(ctx, trailer, PDF_NAME(Root), PDF_NAME(AcroForm), PDF_NAME(DA), NULL);
3154
54
  }
3155
5.54k
  pdf_parse_default_appearance(ctx, pdf_to_str_buf(ctx, da), font, size, n, color);
3156
5.54k
}
3157
3158
void
3159
pdf_set_annot_default_appearance(fz_context *ctx, pdf_annot *annot, const char *font, float size, int n, const float *color)
3160
0
{
3161
0
  char buf[100];
3162
3163
0
  begin_annot_op(ctx, annot, "Set default appearance");
3164
3165
0
  fz_try(ctx)
3166
0
  {
3167
0
    pdf_print_default_appearance(ctx, buf, sizeof buf, font, size, n, color);
3168
3169
0
    pdf_dict_put_string(ctx, annot->obj, PDF_NAME(DA), buf, strlen(buf));
3170
3171
0
    pdf_dict_del(ctx, annot->obj, PDF_NAME(DS)); /* not supported */
3172
0
    pdf_dict_del(ctx, annot->obj, PDF_NAME(RC)); /* not supported */
3173
0
    end_annot_op(ctx, annot);
3174
0
  }
3175
0
  fz_catch(ctx)
3176
0
  {
3177
0
    abandon_annot_op(ctx, annot);
3178
0
    fz_rethrow(ctx);
3179
0
  }
3180
3181
0
  pdf_dirty_annot(ctx, annot);
3182
0
}
3183
3184
int pdf_annot_field_flags(fz_context *ctx, pdf_annot *annot)
3185
0
{
3186
0
  int ret;
3187
3188
0
  pdf_annot_push_local_xref(ctx, annot);
3189
3190
0
  fz_try(ctx)
3191
0
    ret = pdf_field_flags(ctx, annot->obj);
3192
0
  fz_always(ctx)
3193
0
    pdf_annot_pop_local_xref(ctx, annot);
3194
0
  fz_catch(ctx)
3195
0
    fz_rethrow(ctx);
3196
3197
0
  return ret;
3198
0
}
3199
3200
const char *pdf_annot_field_value(fz_context *ctx, pdf_annot *widget)
3201
0
{
3202
0
  const char *ret;
3203
3204
0
  pdf_annot_push_local_xref(ctx, widget);
3205
3206
0
  fz_try(ctx)
3207
0
    ret = pdf_field_value(ctx, widget->obj);
3208
0
  fz_always(ctx)
3209
0
    pdf_annot_pop_local_xref(ctx, widget);
3210
0
  fz_catch(ctx)
3211
0
    fz_rethrow(ctx);
3212
3213
0
  return ret;
3214
0
}
3215
3216
const char *pdf_annot_field_label(fz_context *ctx, pdf_annot *widget)
3217
0
{
3218
0
  const char *ret;
3219
3220
0
  pdf_annot_push_local_xref(ctx, widget);
3221
3222
0
  fz_try(ctx)
3223
0
    ret = pdf_field_label(ctx, widget->obj);
3224
0
  fz_always(ctx)
3225
0
    pdf_annot_pop_local_xref(ctx, widget);
3226
0
  fz_catch(ctx)
3227
0
    fz_rethrow(ctx);
3228
3229
0
  return ret;
3230
0
}
3231
3232
int pdf_set_annot_field_value(fz_context *ctx, pdf_document *doc, pdf_annot *annot, const char *text, int ignore_trigger_events)
3233
0
{
3234
0
  int ret;
3235
3236
0
  begin_annot_op(ctx, annot, "Set field value");
3237
3238
0
  fz_try(ctx)
3239
0
  {
3240
0
    ret = pdf_set_field_value(ctx, doc, annot->obj, text, ignore_trigger_events);
3241
0
    end_annot_op(ctx, annot);
3242
0
  }
3243
0
  fz_catch(ctx)
3244
0
  {
3245
0
    abandon_annot_op(ctx, annot);
3246
0
    fz_rethrow(ctx);
3247
0
  }
3248
3249
0
  pdf_dirty_annot(ctx, annot);
3250
3251
0
  return ret;
3252
0
}
3253
3254
void
3255
pdf_set_annot_appearance(fz_context *ctx, pdf_annot *annot, const char *appearance, const char *state, fz_matrix ctm, fz_rect bbox, pdf_obj *res, fz_buffer *contents)
3256
5.89k
{
3257
5.89k
  pdf_obj *form = NULL;
3258
5.89k
  pdf_obj *ap, *app;
3259
5.89k
  pdf_obj *app_name = NULL;
3260
3261
5.89k
  begin_annot_op(ctx, annot, "Set appearance stream");
3262
3263
5.89k
  if (!appearance)
3264
0
    appearance = "N";
3265
3266
5.89k
  fz_var(form);
3267
5.89k
  fz_var(app_name);
3268
3269
11.7k
  fz_try(ctx)
3270
11.7k
  {
3271
5.89k
    ap = pdf_dict_get(ctx, annot->obj, PDF_NAME(AP));
3272
5.89k
    if (!ap)
3273
5.66k
      ap = pdf_dict_put_dict(ctx, annot->obj, PDF_NAME(AP), 1);
3274
3275
5.89k
    if (!state)
3276
5.89k
      form = pdf_keep_obj(ctx, pdf_dict_gets(ctx, ap, appearance));
3277
0
    else
3278
0
    {
3279
0
      if (strcmp(appearance, "N") && strcmp(appearance, "R") && strcmp(appearance, "D"))
3280
0
        fz_throw(ctx, FZ_ERROR_GENERIC, "Unknown annotation appearance");
3281
3282
0
      app_name = pdf_new_name(ctx, appearance);
3283
0
      app = pdf_dict_get(ctx, ap, app_name);
3284
0
      if (!app)
3285
0
        app = pdf_dict_put_dict(ctx, ap, app_name, 2);
3286
0
      form = pdf_keep_obj(ctx, pdf_dict_gets(ctx, ap, appearance));
3287
0
    }
3288
    /* Care required here. Some files have multiple annotations, which share
3289
     * appearance streams. As such, we must NOT reuse such appearance streams.
3290
     * On the other hand, we cannot afford to always recreate appearance
3291
     * streams, as this can lead to leakage of partial edits into the document.
3292
     * Any appearance we generate will be in the incremental section, and we
3293
     * will never generate shared appearances. As such, we can reuse an
3294
     * appearance object only if it is in the incremental section. */
3295
5.89k
    if (!pdf_obj_is_incremental(ctx, form))
3296
5.89k
    {
3297
5.89k
      pdf_drop_obj(ctx, form);
3298
5.89k
      form = NULL;
3299
5.89k
    }
3300
5.89k
    if (!form)
3301
5.89k
      form = pdf_new_xobject(ctx, annot->page->doc, bbox, ctm, res, contents);
3302
0
    else
3303
0
      pdf_update_xobject(ctx, annot->page->doc, form, bbox, ctm, res, contents);
3304
3305
5.89k
    if (!state)
3306
5.89k
      pdf_dict_puts(ctx, ap, appearance, form);
3307
0
    else
3308
0
      pdf_dict_puts(ctx, app, state, form);
3309
5.89k
    end_annot_op(ctx, annot);
3310
5.89k
  }
3311
11.7k
  fz_always(ctx)
3312
5.89k
  {
3313
5.89k
    pdf_drop_obj(ctx, form);
3314
5.89k
    pdf_drop_obj(ctx, app_name);
3315
5.89k
  }
3316
5.89k
  fz_catch(ctx)
3317
10
  {
3318
10
    abandon_annot_op(ctx, annot);
3319
10
    fz_rethrow(ctx);
3320
10
  }
3321
3322
5.88k
  pdf_set_annot_resynthesised(ctx, annot);
3323
5.88k
}
3324
3325
void
3326
pdf_set_annot_appearance_from_display_list(fz_context *ctx, pdf_annot *annot, const char *appearance, const char *state, fz_matrix ctm, fz_display_list *list)
3327
0
{
3328
0
  pdf_document *doc = annot->page->doc;
3329
0
  fz_device *dev = NULL;
3330
0
  pdf_obj *res = NULL;
3331
0
  fz_buffer *contents = NULL;
3332
3333
  /* Convert fitz-space mediabox to pdf-space bbox */
3334
0
  fz_rect mediabox = fz_bound_display_list(ctx, list);
3335
0
  fz_matrix transform = { 1, 0, 0, -1, -mediabox.x0, mediabox.y1 };
3336
0
  fz_rect bbox = fz_transform_rect(mediabox, transform);
3337
3338
0
  fz_var(dev);
3339
0
  fz_var(contents);
3340
0
  fz_var(res);
3341
3342
0
  begin_annot_op(ctx, annot, "Set appearance stream");
3343
3344
0
  fz_try(ctx)
3345
0
  {
3346
0
    res = pdf_new_dict(ctx, doc, 1);
3347
0
    contents = fz_new_buffer(ctx, 0);
3348
0
    dev = pdf_new_pdf_device(ctx, doc, transform, res, contents);
3349
0
    fz_run_display_list(ctx, list, dev, fz_identity, fz_infinite_rect, NULL);
3350
0
    fz_close_device(ctx, dev);
3351
0
    fz_drop_device(ctx, dev);
3352
0
    dev = NULL;
3353
3354
0
    pdf_set_annot_appearance(ctx, annot, appearance, state, ctm, bbox, res, contents);
3355
0
    end_annot_op(ctx, annot);
3356
0
  }
3357
0
  fz_always(ctx)
3358
0
  {
3359
0
    fz_drop_device(ctx, dev);
3360
0
    fz_drop_buffer(ctx, contents);
3361
0
    pdf_drop_obj(ctx, res);
3362
0
  }
3363
0
  fz_catch(ctx)
3364
0
  {
3365
0
    abandon_annot_op(ctx, annot);
3366
0
    fz_rethrow(ctx);
3367
0
  }
3368
0
}
3369
3370
void pdf_set_annot_stamp_image(fz_context *ctx, pdf_annot *annot, fz_image *img)
3371
0
{
3372
0
  pdf_document *doc = annot->page->doc;
3373
0
  fz_buffer *buf = NULL;
3374
0
  pdf_obj *res = NULL;
3375
0
  pdf_obj *res_xobj;
3376
3377
0
  begin_annot_op(ctx, annot, "Set stamp image");
3378
3379
0
  fz_var(res);
3380
0
  fz_var(buf);
3381
3382
0
  fz_try(ctx)
3383
0
  {
3384
    // Shrink Rect to fit image, maintaining aspect ratio.
3385
0
    fz_rect rect = pdf_bound_annot(ctx, annot);
3386
0
    float s = fz_min((rect.x1 - rect.x0) / img->w, (rect.y1 - rect.y0) / img->h);
3387
0
    rect.x1 = rect.x0 + img->w * s;
3388
0
    rect.y1 = rect.y0 + img->h * s;
3389
3390
    // Add image resource
3391
0
    res = pdf_add_new_dict(ctx, doc, 1);
3392
0
    res_xobj = pdf_dict_put_dict(ctx, res, PDF_NAME(XObject), 1);
3393
0
    pdf_dict_put_drop(ctx, res_xobj, PDF_NAME(I), pdf_add_image(ctx, doc, img));
3394
3395
0
    buf = fz_new_buffer_from_shared_data(ctx, (const unsigned char*)"/I Do\n", 6);
3396
3397
0
    pdf_set_annot_appearance(ctx, annot, "N", NULL, fz_identity, fz_unit_rect, res, buf);
3398
0
    pdf_set_annot_rect(ctx, annot, rect);
3399
0
    end_annot_op(ctx, annot);
3400
0
  }
3401
0
  fz_always(ctx)
3402
0
  {
3403
0
    fz_drop_buffer(ctx, buf);
3404
0
    pdf_drop_obj(ctx, res);
3405
0
  }
3406
0
  fz_catch(ctx)
3407
0
  {
3408
0
    abandon_annot_op(ctx, annot);
3409
0
    fz_rethrow(ctx);
3410
0
  }
3411
0
}
3412
3413
static pdf_obj *filespec_subtypes[] = {
3414
  PDF_NAME(FileAttachment),
3415
  NULL,
3416
};
3417
3418
int
3419
pdf_annot_has_filespec(fz_context *ctx, pdf_annot *annot)
3420
0
{
3421
0
  return is_allowed_subtype_wrap(ctx, annot, PDF_NAME(FS), filespec_subtypes);
3422
0
}
3423
3424
pdf_obj *
3425
pdf_annot_filespec(fz_context *ctx, pdf_annot *annot)
3426
0
{
3427
0
  pdf_obj *filespec;
3428
3429
0
  pdf_annot_push_local_xref(ctx, annot);
3430
3431
0
  fz_try(ctx)
3432
0
  {
3433
0
    check_allowed_subtypes(ctx, annot, PDF_NAME(FS), filespec_subtypes);
3434
0
    filespec = pdf_dict_get(ctx, annot->obj, PDF_NAME(FS));
3435
0
  }
3436
0
  fz_always(ctx)
3437
0
    pdf_annot_pop_local_xref(ctx, annot);
3438
0
  fz_catch(ctx)
3439
0
    fz_rethrow(ctx);
3440
3441
0
  return filespec;
3442
0
}
3443
3444
void
3445
pdf_set_annot_filespec(fz_context *ctx, pdf_annot *annot, pdf_obj *fs)
3446
0
{
3447
0
  if (!pdf_is_embedded_file(ctx, fs))
3448
0
    fz_throw(ctx, FZ_ERROR_GENERIC, "cannot set non-filespec as annotation filespec");
3449
3450
0
  begin_annot_op(ctx, annot, "Set filespec");
3451
3452
0
  fz_try(ctx)
3453
0
  {
3454
0
    check_allowed_subtypes(ctx, annot, PDF_NAME(M), filespec_subtypes);
3455
0
    pdf_dict_put(ctx, pdf_annot_obj(ctx, annot), PDF_NAME(FS), fs);
3456
0
    end_annot_op(ctx, annot);
3457
0
  }
3458
0
  fz_catch(ctx)
3459
0
  {
3460
0
    abandon_annot_op(ctx, annot);
3461
0
    fz_rethrow(ctx);
3462
0
  }
3463
3464
0
  pdf_dirty_annot(ctx, annot);
3465
0
}
3466
3467
int
3468
pdf_annot_hidden_for_editing(fz_context *ctx, pdf_annot *annot)
3469
0
{
3470
0
  return annot->hidden_editing;
3471
0
}
3472
3473
void
3474
pdf_set_annot_hidden_for_editing(fz_context *ctx, pdf_annot *annot, int hidden)
3475
0
{
3476
0
  annot->hidden_editing = hidden;
3477
0
}