Coverage Report

Created: 2022-10-31 07:00

/src/ghostpdl/pdf/pdf_annot.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2019-2022 Artifex Software, Inc.
2
   All Rights Reserved.
3
4
   This software is provided AS-IS with no warranty, either express or
5
   implied.
6
7
   This software is distributed under license and may not be copied,
8
   modified or distributed except as expressly authorized under the terms
9
   of the license contained in the file LICENSE in this distribution.
10
11
   Refer to licensing information at http://www.artifex.com or contact
12
   Artifex Software, Inc.,  1305 Grant Avenue - Suite 200, Novato,
13
   CA 94945, U.S.A., +1(415)492-9861, for further information.
14
*/
15
16
/* Annotation handling for the PDF interpreter */
17
18
#include "pdf_int.h"
19
#include "pdf_stack.h"
20
#include "pdf_annot.h"
21
#include "pdf_file.h"
22
#include "pdf_dict.h"
23
#include "pdf_array.h"
24
#include "pdf_loop_detect.h"
25
#include "pdf_colour.h"
26
#include "pdf_trans.h"
27
#include "pdf_font_types.h"
28
#include "pdf_gstate.h"
29
#include "pdf_misc.h"
30
#include "pdf_optcontent.h"
31
#include "pdf_annot.h"
32
#include "pdf_colour.h"
33
#include "pdf_deref.h"
34
#include "pdf_image.h"
35
#include "pdf_mark.h"
36
#include "pdf_font.h"
37
#include "pdf_text.h"
38
39
#include "gspath2.h"
40
#include "gxfarith.h"
41
#include "gxdevsop.h"               /* For special ops */
42
#include "gsstrtok.h"               /* For gs_strtok */
43
#include "gscoord.h"        /* for gs_concat() and others */
44
#include "gsline.h"         /* For gs_setlinejoin() and friends */
45
#include "gsutil.h"        /* For gs_next_ids() */
46
#include "gspaint.h"        /* For gs_fill() and friends */
47
48
/* Detect if there is a BOM at beginning of string */
49
70
#define IS_UTF8(str) (!strcmp((char *)(str), "\xef\xbb\xbf"))
50
3.92k
#define IS_UTF16(str) (!strcmp((char *)(str), "\xfe\xff"))
51
52
typedef int (*annot_func)(pdf_context *ctx, pdf_dict *annot, pdf_obj *NormAP, bool *render_done);
53
54
typedef struct {
55
    const char *subtype;
56
    annot_func func;
57
    bool simpleAP; /* Just Render AP if it exists? (false means more complicated) */
58
} annot_dispatch_t;
59
60
61
typedef int (*annot_LE_func)(pdf_context *ctx, pdf_dict *annot);
62
63
typedef struct {
64
    const char *name;
65
    annot_LE_func func;
66
} annot_LE_dispatch_t;
67
68
typedef int (*annot_preserve_func)(pdf_context *ctx, pdf_dict *annot, pdf_name *subtype);
69
70
typedef struct {
71
    const char *subtype;
72
    annot_preserve_func func;
73
} annot_preserve_dispatch_t;
74
75
static int pdfi_annot_start_transparency(pdf_context *ctx, pdf_dict *annot)
76
1.34k
{
77
1.34k
    int code;
78
79
1.34k
    if (!ctx->page.has_transparency)
80
751
        return 0;
81
82
    /* TODO: ps code does something with /BM which is apparently the Blend Mode,
83
     * but I am not sure that the value is actually used properly.  Look into it.
84
     * (see pdf_draw.ps/startannottransparency)
85
     */
86
595
    code = gs_clippath(ctx->pgs);
87
595
    if (code < 0)
88
0
        return code;
89
595
    code = pdfi_trans_begin_simple_group(ctx, NULL, false, false, false);
90
595
    (void)gs_newpath(ctx->pgs);
91
595
    return code;
92
595
}
93
94
static int pdfi_annot_end_transparency(pdf_context *ctx, pdf_dict *annot)
95
1.34k
{
96
1.34k
    if (!ctx->page.has_transparency)
97
751
        return 0;
98
99
594
    return pdfi_trans_end_simple_group(ctx);
100
1.34k
}
101
102
/* Get width from BS, if it exists
103
 * Default to 1.0 if not
104
 */
105
static int pdfi_annot_get_BS_width(pdf_context *ctx, pdf_dict *annot, double *width)
106
99
{
107
99
    int code;
108
99
    pdf_dict *BS = NULL;
109
110
99
    *width = 1.0;
111
112
99
    code = pdfi_dict_knownget_type(ctx, annot, "BS", PDF_DICT, (pdf_obj **)&BS);
113
99
    if (code <= 0)
114
0
        goto exit;
115
116
99
    code = pdfi_dict_knownget_number(ctx, BS, "W", width);
117
118
99
 exit:
119
99
    pdfi_countdown(BS);
120
99
    return code;
121
99
}
122
123
/* Set both stroke opacity and fill opacity to either CA or ca
124
 * For annotations, the one value seems to control both.
125
 */
126
static int pdfi_annot_opacity(pdf_context *ctx, pdf_dict *annot)
127
282
{
128
282
    int code = 0;
129
282
    double CA;
130
131
    /* CA -- opacity */
132
282
    code = pdfi_dict_knownget_number(ctx, annot, "CA", &CA);
133
282
    if (code > 0) {
134
136
        code = gs_setstrokeconstantalpha(ctx->pgs, CA);
135
136
        if (code < 0) goto exit;
136
136
        code = gs_setfillconstantalpha(ctx->pgs, CA);
137
136
        goto exit;
138
136
    }
139
    /* If CA not found, we also check for 'ca' even though it's not in the spec */
140
146
    code = pdfi_dict_knownget_number(ctx, annot, "ca", &CA);
141
146
    if (code > 0) {
142
0
        code = gs_setstrokeconstantalpha(ctx->pgs, CA);
143
0
        if (code < 0) goto exit;
144
0
        code = gs_setfillconstantalpha(ctx->pgs, CA);
145
0
    }
146
282
 exit:
147
282
    return code;
148
146
}
149
150
/* Apply RD to provided rect */
151
static int pdfi_annot_applyRD(pdf_context *ctx, pdf_dict *annot, gs_rect *rect)
152
448
{
153
448
    int code;
154
448
    pdf_array *RD = NULL;
155
448
    gs_rect rd;
156
157
448
    code = pdfi_dict_knownget_type(ctx, annot, "RD", PDF_ARRAY, (pdf_obj **)&RD);
158
448
    if (code <= 0) goto exit;
159
160
0
    code = pdfi_array_to_gs_rect(ctx, RD, &rd);
161
0
    if (code < 0) goto exit;
162
163
0
    rect->p.x += rd.p.x;
164
0
    rect->p.y += rd.p.y;
165
0
    rect->q.x -= rd.q.x;
166
0
    rect->q.y -= rd.q.y;
167
168
448
 exit:
169
448
    pdfi_countdown(RD);
170
448
    return code;
171
0
}
172
173
static int pdfi_annot_Rect(pdf_context *ctx, pdf_dict *annot, gs_rect *rect)
174
191k
{
175
191k
    int code;
176
191k
    pdf_array *Rect = NULL;
177
178
191k
    code = pdfi_dict_knownget_type(ctx, annot, "Rect", PDF_ARRAY, (pdf_obj **)&Rect);
179
191k
    if (code < 0) goto exit;
180
181
191k
    code = pdfi_array_to_gs_rect(ctx, Rect, rect);
182
191k
    if (code < 0) goto exit;
183
184
191k
    pdfi_normalize_rect(ctx, rect);
185
186
191k
 exit:
187
191k
    pdfi_countdown(Rect);
188
191k
    return code;
189
191k
}
190
191
static int pdfi_annot_position_AP(pdf_context *ctx, pdf_dict *annot, pdf_stream *AP)
192
152k
{
193
152k
    int code = 0;
194
152k
    gs_rect rect;
195
152k
    pdf_array *BBox = NULL;
196
152k
    gs_rect bbox;
197
152k
    pdf_array *Matrix = NULL;
198
152k
    gs_matrix matrix;
199
152k
    double xscale, yscale;
200
152k
    pdf_dict *Annot_dict;
201
202
152k
    code = pdfi_dict_from_obj(ctx, (pdf_obj *)AP, &Annot_dict);
203
152k
    if (code < 0)
204
0
        return code;
205
206
    /* TODO: graphicsbeginpage, textbeginpage
207
     * These should match what was done at the beginning of the page,
208
     * but current implementation has things kind of mixed around.
209
     * Need to figure out exactly what to do.  I'd like it to be one
210
     * function in both places.
211
     * see pdfi_page_render()
212
     */
213
    /* graphicsbeginpage() */
214
    /* textbeginpage() */
215
    /* code = gs_initgraphics(ctx->pgs); */
216
152k
    ctx->text.BlockDepth = 0;
217
    /* TODO: FIXME */
218
219
152k
    code = pdfi_annot_Rect(ctx, annot, &rect);
220
152k
    if (code < 0) goto exit;
221
222
152k
    code = pdfi_dict_knownget_type(ctx, Annot_dict, "BBox", PDF_ARRAY, (pdf_obj **)&BBox);
223
152k
    if (code < 0) goto exit;
224
152k
    code = pdfi_array_to_gs_rect(ctx, BBox, &bbox);
225
152k
    if (code < 0) goto exit;
226
227
152k
    code = pdfi_dict_knownget_type(ctx, Annot_dict, "Matrix", PDF_ARRAY, (pdf_obj **)&Matrix);
228
152k
    if (code < 0) goto exit;
229
152k
    code = pdfi_array_to_gs_matrix(ctx, Matrix, &matrix);
230
152k
    if (code < 0) goto exit;
231
232
152k
    xscale = yscale = 1.0;
233
234
152k
    code = gs_translate(ctx->pgs, rect.p.x, rect.p.y);
235
152k
    if (code < 0) goto exit;
236
237
152k
    if (BBox != NULL) {
238
152k
        pdfi_bbox_transform(ctx, &bbox, &matrix);
239
240
        /* Calculate scale factor */
241
152k
        xscale = (rect.q.x - rect.p.x) / (bbox.q.x - bbox.p.x);
242
152k
        yscale = (rect.q.y - rect.p.y) / (bbox.q.y - bbox.p.y);
243
244
152k
        if (xscale * yscale <= 0) {
245
0
            dbgmprintf(ctx->memory, "ANNOT: Ignoring annotation with scale factor of 0\n");
246
0
            code = 0;
247
0
            goto exit;
248
0
        }
249
250
        /* Scale it */
251
152k
        code = gs_scale(ctx->pgs, xscale, yscale);
252
152k
        if (code < 0) goto exit;
253
254
        /* Compensate for non-zero origin of BBox */
255
152k
        code = gs_translate(ctx->pgs, -bbox.p.x, -bbox.p.y);
256
152k
        if (code < 0) goto exit;
257
152k
    }
258
259
152k
 exit:
260
152k
    pdfi_countdown(BBox);
261
152k
    pdfi_countdown(Matrix);
262
152k
    return code;
263
152k
}
264
265
/* See pdf_draw.ps/drawwidget (draws the AP for any type of thingy) */
266
static int pdfi_annot_draw_AP(pdf_context *ctx, pdf_dict *annot, pdf_obj *NormAP)
267
134k
{
268
134k
    int code = 0;
269
270
134k
    if (NormAP == NULL)
271
330
        return 0;
272
133k
    if (pdfi_type_of(NormAP) != PDF_STREAM)
273
0
        return_error(gs_error_typecheck);
274
275
133k
    code = pdfi_op_q(ctx);
276
133k
    if (code < 0)
277
0
        return code;
278
279
133k
    code = pdfi_annot_position_AP(ctx, annot, (pdf_stream *)NormAP);
280
133k
    if (code < 0)
281
52
        goto exit;
282
283
    /* Render the annotation */
284
133k
    code = pdfi_do_image_or_form(ctx, NULL, ctx->page.CurrentPageDict, NormAP);
285
286
133k
exit:
287
133k
    (void)pdfi_op_Q(ctx);
288
133k
    return code;
289
133k
}
290
291
static int pdfi_annot_setcolor_key(pdf_context *ctx, pdf_dict *annot, const char *key,
292
                                   bool usedefault, bool *drawit)
293
49.4k
{
294
49.4k
    int code = 0;
295
49.4k
    pdf_array *C = NULL;
296
297
49.4k
    *drawit = true;
298
299
49.4k
    code = pdfi_dict_knownget_type(ctx, annot, key, PDF_ARRAY, (pdf_obj **)&C);
300
49.4k
    if (code < 0) goto exit;
301
302
49.4k
    if (code == 0) {
303
37.9k
        if (usedefault)
304
314
            code = pdfi_gs_setgray(ctx, 0);
305
37.6k
        else
306
37.6k
            *drawit = false;
307
37.9k
    } else {
308
11.5k
        if (pdfi_array_size(C) == 0) {
309
3
            code = 0;
310
3
            *drawit = false;
311
11.5k
        } else {
312
11.5k
            code = pdfi_setcolor_from_array(ctx, C);
313
11.5k
        }
314
11.5k
    }
315
316
49.4k
 exit:
317
49.4k
    if (code < 0)
318
6
        *drawit = false;
319
49.4k
    pdfi_countdown(C);
320
49.4k
    return code;
321
49.4k
}
322
323
static int pdfi_annot_setinteriorcolor(pdf_context *ctx, pdf_dict *annot, bool usedefault, bool *drawit)
324
198
{
325
198
    return pdfi_annot_setcolor_key(ctx, annot, "IC", usedefault, drawit);
326
198
}
327
328
static int pdfi_annot_setcolor(pdf_context *ctx, pdf_dict *annot, bool usedefault, bool *drawit)
329
1.55k
{
330
1.55k
    return pdfi_annot_setcolor_key(ctx, annot, "C", usedefault, drawit);
331
1.55k
}
332
333
/* Stroke border using current path */
334
static int pdfi_annot_strokeborderpath(pdf_context *ctx, pdf_dict *annot, double width, pdf_array *dash)
335
520
{
336
520
    int code = 0;
337
338
520
    if (width <= 0)
339
0
        return 0;
340
341
520
    code = pdfi_setdash_impl(ctx, dash, 0);
342
520
    if (code < 0) goto exit;
343
520
    code = gs_setlinewidth(ctx->pgs, width);
344
520
    if (code < 0) goto exit;
345
346
520
    code = gs_stroke(ctx->pgs);
347
348
520
 exit:
349
520
    return code;
350
520
}
351
352
/* Fill border path */
353
static int pdfi_annot_fillborderpath(pdf_context *ctx, pdf_dict *annot)
354
165
{
355
165
    int code;
356
165
    bool drawit;
357
358
165
    code = pdfi_gsave(ctx);
359
165
    if (code < 0) return code;
360
361
165
    code = pdfi_annot_opacity(ctx, annot);
362
165
    if (code < 0) goto exit;
363
165
    code = pdfi_annot_setinteriorcolor(ctx, annot, false, &drawit);
364
165
    if (code < 0) goto exit;
365
164
    if (drawit)
366
112
        code = gs_fill(ctx->pgs);
367
368
165
 exit:
369
165
    (void)pdfi_grestore(ctx);
370
165
    return code;
371
164
}
372
373
374
/* Draw a path from a rectangle */
375
static int pdfi_annot_rect_path(pdf_context *ctx, gs_rect *rect)
376
15
{
377
15
    int code;
378
379
15
    code = gs_moveto(ctx->pgs, rect->p.x, rect->p.y);
380
15
    if (code < 0) goto exit;
381
15
    code = gs_lineto(ctx->pgs, rect->q.x, rect->p.y);
382
15
    if (code < 0) goto exit;
383
15
    code = gs_lineto(ctx->pgs, rect->q.x, rect->q.y);
384
15
    if (code < 0) goto exit;
385
15
    code = gs_lineto(ctx->pgs, rect->p.x, rect->q.y);
386
15
    if (code < 0) goto exit;
387
15
    code = gs_closepath(ctx->pgs);
388
389
15
 exit:
390
15
    return code;
391
15
}
392
393
/* Make a rectangle path from Rect (see /re, /normal_re in pdf_ops.ps)
394
 * See also /Square
395
 * Not sure if I have to worry about the /inside_text_re here
396
 */
397
static int pdfi_annot_RectRD_path(pdf_context *ctx, pdf_dict *annot)
398
15
{
399
15
    gs_rect rect;
400
15
    int code;
401
402
15
    code = pdfi_annot_Rect(ctx, annot, &rect);
403
15
    if (code < 0) goto exit;
404
405
15
    code = pdfi_annot_applyRD(ctx, annot, &rect);
406
15
    if (code < 0) goto exit;
407
408
15
    code = pdfi_annot_rect_path(ctx, &rect);
409
410
15
 exit:
411
15
    return code;
412
15
}
413
414
/* Adjust rectangle by specified width */
415
static void pdfi_annot_rect_adjust(pdf_context *ctx, gs_rect *rect, double width)
416
349
{
417
349
    rect->p.x += width;
418
349
    rect->p.y += width;
419
349
    rect->q.x -= width;
420
349
    rect->q.y -= width;
421
349
}
422
423
/* Fill Rect with current color */
424
static int pdfi_annot_fillRect(pdf_context *ctx, pdf_dict *annot)
425
13
{
426
13
    int code;
427
13
    gs_rect rect;
428
429
13
    code = pdfi_gsave(ctx);
430
13
    if (code < 0) return code;
431
432
13
    code = pdfi_annot_Rect(ctx, annot, &rect);
433
13
    if (code < 0) goto exit;
434
435
13
    code = gs_rectclip(ctx->pgs, &rect, 1);
436
13
    if (code < 0) goto exit;
437
438
13
    code = pdfi_annot_applyRD(ctx, annot, &rect);
439
13
    if (code < 0) goto exit;
440
441
13
    code = gs_rectfill(ctx->pgs, &rect, 1);
442
13
    if (code < 0) goto exit;
443
444
13
 exit:
445
13
    (void)pdfi_grestore(ctx);
446
13
    return code;
447
13
}
448
449
/* Stroke border, drawing path from rect */
450
static int pdfi_annot_strokeborder(pdf_context *ctx, pdf_dict *annot, double width, pdf_array *dash)
451
666
{
452
666
    int code = 0;
453
666
    gs_rect rect;
454
455
666
    if (width <= 0)
456
317
        return 0;
457
458
349
    code = pdfi_gsave(ctx);
459
460
349
    code = pdfi_setdash_impl(ctx, dash, 0);
461
349
    if (code < 0) goto exit;
462
463
349
    code = gs_setlinewidth(ctx->pgs, width);
464
349
    if (code < 0) goto exit;
465
466
349
    code = pdfi_annot_Rect(ctx, annot, &rect);
467
349
    if (code < 0) goto exit;
468
469
349
    code = pdfi_annot_applyRD(ctx, annot, &rect);
470
349
    if (code < 0) goto exit;
471
472
473
    /* Stroke the rectangle */
474
    /* Adjust rectangle by the width */
475
349
    pdfi_annot_rect_adjust(ctx, &rect, width/2);
476
349
    code = gs_rectstroke(ctx->pgs, &rect, 1, NULL);
477
478
349
 exit:
479
349
    (void)pdfi_grestore(ctx);
480
349
    return code;
481
349
}
482
483
/* Draw border from a Border array
484
 * Note: Border can be null
485
 */
486
static int pdfi_annot_draw_Border(pdf_context *ctx, pdf_dict *annot, pdf_array *Border, bool usepath)
487
689
{
488
689
    pdf_array *dash = NULL;
489
689
    int code = 0;
490
689
    uint64_t size = 0;
491
689
    double width = 0;
492
493
689
    if (Border)
494
675
        size = pdfi_array_size(Border);
495
689
    if (Border &&  size < 3) {
496
0
        pdfi_set_warning(ctx, 0, NULL, W_PDF_ANNOT_ERROR, "pdfi_annot_draw_Border", "WARNING: Annotation Border array invalid");
497
0
        goto exit;
498
0
    }
499
689
    if (!Border) {
500
14
        code = pdfi_array_alloc(ctx, 0, &dash);
501
14
        pdfi_countup(dash);
502
14
        if (code < 0) goto exit;
503
14
        width = 1;
504
675
    } else {
505
675
        if (size > 3) {
506
0
            code = pdfi_array_get_type(ctx, Border, 3, PDF_ARRAY, (pdf_obj **)&dash);
507
0
            if (code < 0) {
508
0
                pdfi_set_warning(ctx, 0, NULL, W_PDF_ANNOT_ERROR,
509
0
                                 "pdfi_annot_draw_Border", "WARNING: Annotation Border Dash array invalid");
510
0
                code = pdfi_array_alloc(ctx, 0, &dash);
511
0
                if (code < 0) goto exit;
512
0
                pdfi_countup(dash);
513
0
            }
514
675
        } else {
515
675
            code = pdfi_array_alloc(ctx, 0, &dash);
516
675
            if (code < 0) goto exit;
517
675
            pdfi_countup(dash);
518
675
        }
519
675
        code = pdfi_array_get_number(ctx, Border, 2, &width);
520
675
        if (code < 0) goto exit;
521
675
    }
522
523
    /* At this point we have a dash array (which could be length 0) and a width */
524
689
    if (usepath)
525
60
        code = pdfi_annot_strokeborderpath(ctx, annot, width, dash);
526
629
    else
527
629
        code = pdfi_annot_strokeborder(ctx, annot, width, dash);
528
529
689
 exit:
530
689
    pdfi_countdown(dash);
531
689
    return code;
532
689
}
533
534
/* Draw border from a BS dict */
535
static int pdfi_annot_draw_BS(pdf_context *ctx, pdf_dict *annot, pdf_dict *BS, bool usepath)
536
497
{
537
497
    double W;
538
497
    int code = 0;
539
497
    pdf_name *S = NULL;
540
497
    pdf_array *dash = NULL;
541
542
    /* Get the width */
543
497
    code = pdfi_dict_knownget_number(ctx, BS, "W", &W);
544
497
    if (code < 0) goto exit;
545
497
    if (code == 0)
546
0
        W = 1; /* Default */
547
548
    /* TODO: Some junk about scaling to UserUnit */
549
    /* ... */
550
551
    /* Lookup border style */
552
497
    code = pdfi_dict_knownget_type(ctx, BS, "S", PDF_NAME, (pdf_obj **)&S);
553
497
    if (code < 0) goto exit;
554
555
497
    if (code > 0 && pdfi_name_is(S, "D")) {
556
        /* Handle Dash array */
557
1
        code = pdfi_dict_knownget_type(ctx, BS, "D", PDF_ARRAY, (pdf_obj **)&dash);
558
1
        if (code < 0) goto exit;
559
560
        /* If there is no Dash array, then create one containing a 3 (the default) */
561
1
        if (code == 0) {
562
1
            code = pdfi_array_alloc(ctx, 1, &dash);
563
1
            if (code < 0) goto exit;
564
1
            pdfi_countup(dash);
565
566
1
            code = pdfi_array_put_int(ctx, dash, 0, 3);
567
1
            if (code < 0) goto exit;
568
1
        }
569
496
    } else {
570
        /* Empty array */
571
496
        code = pdfi_array_alloc(ctx, 0, &dash);
572
496
        if (code < 0) goto exit;
573
496
        pdfi_countup(dash);
574
496
    }
575
576
    /* At this point we have a dash array (which could be length 0) and a width */
577
497
    if (usepath)
578
460
        code = pdfi_annot_strokeborderpath(ctx, annot, W, dash);
579
37
    else
580
37
        code = pdfi_annot_strokeborder(ctx, annot, W, dash);
581
582
497
 exit:
583
497
    pdfi_countdown(S);
584
497
    pdfi_countdown(dash);
585
497
    return code;
586
497
}
587
588
/* Draw the border
589
 * This spec seems to be scattered around.  There might be:
590
 *  /Border -- an array of 3-4 elements, where the optional 4th element is a "dash array"
591
 *   (default value: [0 0 1])
592
 *  /BS -- a Border Style dictionary
593
 *  Spec says /Border would be ignored in favor of /BS
594
 *
595
 * usepath -- indicates whether to stroke existing path, or use Rect to draw a path first
596
 */
597
static int pdfi_annot_draw_border(pdf_context *ctx, pdf_dict *annot, bool usepath)
598
1.18k
{
599
1.18k
    int code, code1;
600
1.18k
    pdf_dict *BS = NULL;
601
1.18k
    pdf_array *Border = NULL;
602
603
1.18k
    code = pdfi_dict_knownget_type(ctx, annot, "BS", PDF_DICT, (pdf_obj **)&BS);
604
1.18k
    if (code < 0) goto exit;
605
1.18k
    code = pdfi_dict_knownget_type(ctx, annot, "Border", PDF_ARRAY, (pdf_obj **)&Border);
606
1.18k
    if (code < 0) goto exit;
607
608
1.18k
    code = pdfi_gsave(ctx);
609
1.18k
    if (code < 0) goto exit;
610
611
1.18k
    if (BS) {
612
497
        code = pdfi_annot_draw_BS(ctx, annot, BS, usepath);
613
689
    } else {
614
        /* Note: Border can be null */
615
689
        code = pdfi_annot_draw_Border(ctx, annot, Border, usepath);
616
689
    }
617
1.18k
    code1 = pdfi_grestore(ctx);
618
1.18k
    if (code == 0) code = code1;
619
620
1.18k
 exit:
621
1.18k
    pdfi_countdown(BS);
622
1.18k
    pdfi_countdown(Border);
623
1.18k
    return code;
624
1.18k
}
625
626
/*********** BEGIN Font/Text ***************/
627
628
/* Set font */
629
static int
630
pdfi_annot_set_font(pdf_context *ctx, const char *font, double size)
631
68
{
632
68
    int code = 0;
633
634
68
    if (font != NULL) {
635
68
        code = pdfi_font_set_internal_string(ctx, font, size);
636
68
        if (code < 0) goto exit;
637
68
    }
638
639
68
 exit:
640
68
    return code;
641
68
}
642
643
/* Get value from a field, or its Parents (recursive)
644
 * If no Parent, will also check ctx->AcroForm
645
 * Returns <0 on error, 0 if not found, >0 if found
646
 */
647
static int pdfi_form_get_inheritable(pdf_context *ctx, pdf_dict *field, const char *Key,
648
                                     pdf_obj_type type, pdf_obj **o)
649
52.2k
{
650
52.2k
    int code = 0;
651
52.2k
    pdf_dict *Parent = NULL;
652
52.2k
    bool known = false;
653
654
    /* Check this field */
655
52.2k
    code = pdfi_dict_knownget_type(ctx, field, Key, type, o);
656
52.2k
    if (code != 0) goto exit1;
657
658
12.0k
    code = pdfi_loop_detector_mark(ctx);
659
12.0k
    if (code < 0)
660
0
        goto exit;
661
662
    /* Check for Parent. Do not store the dereferenced Parent back to the dictionary
663
     * as this can cause circular references.
664
     */
665
12.0k
    code = pdfi_dict_known(ctx, field, "Parent", &known);
666
12.0k
    if (code >= 0 && known == true)
667
10.4k
    {
668
10.4k
        code = pdfi_dict_get_no_store_R(ctx, field, "Parent", (pdf_obj **)&Parent);
669
10.4k
        if (code < 0)
670
936
            goto exit;
671
672
9.50k
        if (pdfi_type_of(Parent) != PDF_DICT) {
673
466
            if (pdfi_type_of(Parent) == PDF_INDIRECT) {
674
29
                pdf_indirect_ref *o = (pdf_indirect_ref *)Parent;
675
676
29
                code = pdfi_dereference(ctx, o->ref_object_num, o->ref_generation_num, (pdf_obj **)&Parent);
677
29
                pdfi_countdown(o);
678
29
                goto exit;
679
437
            } else {
680
437
                code = gs_note_error(gs_error_typecheck);
681
437
                goto exit;
682
437
            }
683
466
        }
684
9.04k
        if (Parent->object_num != 0) {
685
            /* It is possible that we might have ended up with an object which has already
686
             * been stored in the /Parent, but contains circular references (if we were careless
687
             * about storing the dereferenced object). See OSS-fuzz 51034.
688
             */
689
9.04k
            if(pdfi_loop_detector_check_object(ctx, Parent->object_num)){
690
9.04k
                code = gs_note_error(gs_error_circular_reference);
691
9.04k
                goto exit;
692
9.04k
            }
693
0
            code = pdfi_loop_detector_add_object(ctx, Parent->object_num);
694
0
            if (code < 0)
695
0
                goto exit;
696
0
        }
697
0
        code = pdfi_form_get_inheritable(ctx, Parent, Key, type, o);
698
0
        if (code <= 0) {
699
0
            if (ctx->AcroForm)
700
0
                code = pdfi_dict_knownget_type(ctx, ctx->AcroForm, Key, type, o);
701
0
        }
702
1.56k
    } else {
703
        /* No Parent, so check AcroForm, if any */
704
1.56k
        if (ctx->AcroForm)
705
1.29k
            code = pdfi_dict_knownget_type(ctx, ctx->AcroForm, Key, type, o);
706
1.56k
    }
707
708
#if 0
709
    /* If not found, recursively check Parent, if any */
710
    code = pdfi_dict_knownget_type(ctx, field, "Parent", PDF_DICT, (pdf_obj **)&Parent);
711
    if (code < 0) goto exit;
712
    if (code > 0) {
713
        /* Check Parent */
714
        code = pdfi_form_get_inheritable(ctx, Parent, Key, type, o);
715
    } else {
716
        /* No Parent, so check AcroForm, if any */
717
        if (ctx->AcroForm)
718
            code = pdfi_dict_knownget_type(ctx, ctx->AcroForm, Key, type, o);
719
    }
720
#endif
721
722
12.0k
exit:
723
12.0k
    (void)pdfi_loop_detector_cleartomark(ctx);
724
725
52.2k
exit1:
726
52.2k
    pdfi_countdown(Parent);
727
52.2k
    return code;
728
12.0k
}
729
730
/* Get int value from a field, or its Parents (recursive)
731
 * Returns <0 on error, 0 if not found, >0 if found
732
 */
733
static int pdfi_form_get_inheritable_int(pdf_context *ctx, pdf_dict *field, const char *Key,
734
                                         int64_t *val)
735
37.7k
{
736
37.7k
    int code = 0;
737
37.7k
    pdf_num *num = NULL;
738
739
37.7k
    *val = 0;
740
37.7k
    code = pdfi_form_get_inheritable(ctx, field, Key, PDF_INT, (pdf_obj **)&num);
741
37.7k
    if (code < 0) goto exit;
742
743
27.3k
    if (code > 0)
744
25.7k
        *val = num->value.i;
745
746
37.7k
 exit:
747
37.7k
    pdfi_countdown(num);
748
37.7k
    return code;
749
27.3k
}
750
751
/* Scan DA to see if font size is 0, if so make a new DA with font size scaled by gs_rect */
752
static int pdfi_form_modDA(pdf_context *ctx, pdf_string *DA, pdf_string **mod_DA, gs_rect *rect)
753
14.4k
{
754
14.4k
    char *token, *prev_token;
755
14.4k
    char *parse_str = NULL;
756
14.4k
    bool did_mod = false;
757
14.4k
    int code = 0;
758
14.4k
    double size;
759
14.4k
    char size_str[20];
760
14.4k
    char *last;
761
14.4k
    pdf_string *newDA = NULL;
762
763
    /* Make a copy of the string because we are going to destructively parse it */
764
14.4k
    parse_str = (char *)gs_alloc_bytes(ctx->memory, DA->length+1, "pdfi_annot_display_text(strbuf)");
765
14.4k
    if (parse_str == NULL) {
766
0
        code = gs_note_error(gs_error_VMerror);
767
0
        goto exit;
768
0
    }
769
14.4k
    memcpy(parse_str, DA->data, DA->length);
770
14.4k
    parse_str[DA->length] = 0; /* Null terminate */
771
772
    /* find the 'Tf' token, if any */
773
14.4k
    token = gs_strtok(parse_str, " ", &last);
774
14.4k
    prev_token = NULL;
775
43.4k
    while (token != NULL) {
776
43.4k
        if (!strcmp(token, "Tf"))
777
14.4k
            break;
778
28.9k
        prev_token = token;
779
28.9k
        token = gs_strtok(NULL, " ", &last);
780
28.9k
    }
781
782
    /* See if we found it */
783
14.4k
    if (!token)
784
5
        goto exit;
785
786
    /* See if there was a prev_token and it was "0" */
787
14.4k
    if (!(prev_token && !strcmp(prev_token, "0")))
788
14.4k
        goto exit;
789
790
    /* Case with '<font> 0 Tf', need to calculate correct size */
791
7
    size = (rect->q.y - rect->p.y) * .75; /* empirical from gs code make_tx_da */
792
793
7
    snprintf(size_str, sizeof(size_str), "%g ", size);
794
795
    /* Create a new DA and reassemble the old DA into it */
796
7
    code = pdfi_object_alloc(ctx, PDF_STRING, DA->length+strlen(size_str)+1, (pdf_obj **)&newDA);
797
7
    if (code < 0)
798
0
        goto exit;
799
7
    pdfi_countup(newDA);
800
801
7
    strncpy((char *)newDA->data, (char *)DA->data, prev_token-parse_str);
802
7
    strncpy((char *)newDA->data + (prev_token-parse_str), size_str, strlen(size_str)+1);
803
7
    strncpy((char *)newDA->data + strlen((char *)newDA->data), (char *)DA->data + (token - parse_str),
804
7
            DA->length-(token-parse_str));
805
7
    newDA->length = strlen((char *)newDA->data);
806
7
    did_mod = true;
807
808
14.4k
 exit:
809
    /* If didn't need to mod it, just copy the original and get a ref */
810
14.4k
    if (did_mod) {
811
7
        *mod_DA = newDA;
812
14.4k
    } else {
813
14.4k
        *mod_DA = DA;
814
14.4k
        pdfi_countup(DA);
815
14.4k
    }
816
817
14.4k
    if (parse_str)
818
14.4k
        gs_free_object(ctx->memory, parse_str, "pdfi_form_modDA(parse_str)");
819
820
14.4k
    return code;
821
7
}
822
823
/* Process the /DA string by either running it through the interpreter
824
 *  or providing a bunch of defaults
825
 *
826
 * According to the spec, if there is a "<fontname> <size> Tf" in the /DA,
827
 * and the <size> = 0, we autosize it using the annotation's rect.  (see PDF1.7, pages 678-679)
828
 *
829
 * rect -- the annotation's rect, for auto-sizing the font
830
 * is_form -- is this a form, so check inheritable?
831
 */
832
static int pdfi_annot_process_DA(pdf_context *ctx, pdf_dict *page_dict, pdf_dict *annot, gs_rect *rect,
833
                                 bool is_form)
834
14.4k
{
835
14.4k
    int code = 0;
836
14.4k
    pdf_string *DA = NULL;
837
14.4k
    pdf_string *mod_DA = NULL;
838
14.4k
    pdf_dict *resource_dict = annot;  /* dict to use for resources, alias no need to refcnt */
839
14.4k
    pdf_dict *DR = NULL;
840
14.4k
    bool known;
841
842
    /* TODO -- see gs code make_tx_da, need to handle case where we need to set a UTF-16 font */
843
844
14.4k
    if (!page_dict)
845
5
        page_dict = ctx->page.CurrentPageDict;
846
847
14.4k
    if (is_form) {
848
14.4k
        code = pdfi_dict_known(ctx, annot, "DR", &known);
849
14.4k
        if (code < 0) goto exit;
850
        /* If there is no "DR" and no Parent in the annotation, have it use the AcroForm instead
851
         * This is a hack.  May need to use fancier inheritance approach.
852
         */
853
14.4k
        if (!known) {
854
14.4k
            code = pdfi_dict_known(ctx, annot, "Parent", &known);
855
14.4k
            if (code < 0) goto exit;
856
14.4k
            if (!known && ctx->AcroForm != NULL)
857
220
                resource_dict = ctx->AcroForm;
858
14.4k
        }
859
14.4k
        code = pdfi_form_get_inheritable(ctx, annot, "DA", PDF_STRING, (pdf_obj **)&DA);
860
14.4k
    } else {
861
5
        code = pdfi_dict_knownget_type(ctx, annot, "DA", PDF_STRING, (pdf_obj **)&DA);
862
5
    }
863
14.4k
    if (code < 0) goto exit;
864
14.4k
    if (code > 0) {
865
14.4k
        if (is_form) {
866
14.4k
            code = pdfi_form_modDA(ctx, DA, &mod_DA, rect);
867
14.4k
            if (code < 0) goto exit;
868
14.4k
        } else {
869
5
            mod_DA = DA;
870
5
            pdfi_countup(mod_DA);
871
5
        }
872
873
14.4k
        code = pdfi_interpret_inner_content_string(ctx, mod_DA, resource_dict,
874
14.4k
                                                   page_dict, false, "DA");
875
14.4k
        if (code < 0) goto exit;
876
        /* If no font got set, set one */
877
14.4k
        if (pdfi_get_current_pdf_font(ctx) == NULL) {
878
8
            code = pdfi_annot_set_font(ctx, "Helvetica", 12.0);
879
8
            if (code < 0) goto exit;
880
8
        }
881
14.4k
    } else {
882
0
        code = pdfi_gs_setgray(ctx, 0);
883
0
        if (code < 0) goto exit;
884
0
        code = pdfi_annot_set_font(ctx, "Helvetica", 12.0);
885
0
        if (code < 0) goto exit;
886
0
    }
887
888
14.4k
 exit:
889
14.4k
    pdfi_countdown(DR);
890
14.4k
    pdfi_countdown(DA);
891
14.4k
    pdfi_countdown(mod_DA);
892
14.4k
    return code;
893
14.4k
}
894
895
/* Put a string into buffer as a hexstring and return ptr to end of it
896
 * Skip over any BOM that is present.
897
 */
898
static char *pdfi_get_hexstring(pdf_context *ctx, char *outbuf, byte *inbuf, int len)
899
1.92k
{
900
1.92k
    int i;
901
1.92k
    char *ptr;
902
903
1.92k
    i = 0;
904
    /* skip over BOM if it's there */
905
1.92k
    if (IS_UTF16(inbuf)) {
906
0
        i += 2; /* UTF-16 */
907
1.92k
    } else if (IS_UTF16(inbuf)) {
908
0
        i += 3; /* UTF-8 */
909
0
    }
910
911
1.92k
    ptr = outbuf;
912
1.92k
    *ptr++ = '<';
913
4.79k
    for ( ; i<len; i++) {
914
2.87k
        snprintf(ptr, 3, "%02X", *(inbuf+i));
915
2.87k
        ptr += 2;
916
2.87k
    }
917
918
1.92k
    *ptr++ = '>';
919
1.92k
    *ptr = 0;
920
921
1.92k
    return ptr;
922
1.92k
}
923
924
/* Display text at current position (inside BT/ET) */
925
static int
926
pdfi_annot_display_nexttext(pdf_context *ctx, pdf_dict *annot, pdf_string *text)
927
1.77k
{
928
1.77k
    char *strbuf = NULL;
929
1.77k
    size_t buflen = 50 + text->length*2; /* 50 to account for formatting, plus the text itself */
930
1.77k
    int code = 0;
931
1.77k
    char *ptr;
932
933
1.77k
    strbuf = (char *)gs_alloc_bytes(ctx->memory, buflen, "pdfi_annot_display_text(strbuf)");
934
1.77k
    if (strbuf == NULL)
935
0
        return_error(gs_error_VMerror);
936
1.77k
    ptr = pdfi_get_hexstring(ctx, strbuf, text->data, text->length);
937
1.77k
    strncpy(ptr, " Tj", buflen-strlen(strbuf));
938
939
1.77k
    code = pdfi_interpret_inner_content_c_string(ctx, strbuf, annot,
940
1.77k
                                               ctx->page.CurrentPageDict, false, "Annot text Tj");
941
1.77k
    if (code < 0) goto exit;
942
943
1.77k
 exit:
944
1.77k
    if (strbuf)
945
1.77k
        gs_free_object(ctx->memory, strbuf, "pdfi_annot_display_text(strbuf)");
946
1.77k
    return code;
947
1.77k
}
948
949
/* Display text with positioning (inside BT/ET) */
950
static int
951
pdfi_annot_display_text(pdf_context *ctx, pdf_dict *annot, double x, double y, pdf_string *text)
952
153
{
953
153
    char *strbuf = NULL;
954
153
    size_t buflen = 50 + text->length*2; /* 50 to account for formatting, plus the text itself */
955
153
    int code = 0;
956
153
    char *ptr;
957
958
153
    strbuf = (char *)gs_alloc_bytes(ctx->memory, buflen, "pdfi_annot_display_text(strbuf)");
959
153
    if (strbuf == NULL)
960
0
        return_error(gs_error_VMerror);
961
153
    snprintf(strbuf, buflen, "%g %g Td ", x, y);
962
153
    ptr = strbuf + strlen(strbuf);
963
153
    ptr = pdfi_get_hexstring(ctx, ptr, text->data, text->length);
964
153
    strncpy(ptr, " Tj", buflen-strlen(strbuf));
965
966
153
    code = pdfi_interpret_inner_content_c_string(ctx, strbuf, annot,
967
153
                                               ctx->page.CurrentPageDict, false, "Annot text Tj");
968
153
    if (code < 0) goto exit;
969
970
153
 exit:
971
153
    if (strbuf)
972
153
        gs_free_object(ctx->memory, strbuf, "pdfi_annot_display_text(strbuf)");
973
153
    return code;
974
153
}
975
976
/* Get Text height for current font (assumes font is already set, inside BT/ET)
977
 * TODO: See /Tform implementation that uses FontBBox and ScaleMatrix instead
978
 * Maybe use this technique as a backup if those entries aren't available?
979
 */
980
static int
981
pdfi_annot_get_text_height(pdf_context *ctx, double *height)
982
73
{
983
73
    int code;
984
73
    pdf_string *temp_string = NULL;
985
73
    gs_rect bbox;
986
73
    gs_point awidth;
987
988
73
    if (ctx->pgs->PDFfontsize == 0) {
989
0
        *height = 0;
990
0
        return 0;
991
0
    }
992
993
73
    code = pdfi_obj_charstr_to_string(ctx, "Hy", &temp_string);
994
73
    if (code < 0)
995
0
        goto exit;
996
997
    /* Find the bbox of the string "Hy" */
998
73
    code = pdfi_string_bbox(ctx, temp_string, &bbox, &awidth, false);
999
73
    if (code < 0)
1000
0
        goto exit;
1001
1002
73
    *height = bbox.q.y - bbox.p.y;
1003
1004
73
 exit:
1005
73
    pdfi_countdown(temp_string);
1006
73
    return code;
1007
73
}
1008
1009
/* Display a simple text string (outside BT/ET) */
1010
static int
1011
pdfi_annot_display_simple_text(pdf_context *ctx, pdf_dict *annot, double x, double y, pdf_string *text)
1012
99
{
1013
99
    int code = 0;
1014
99
    int code1 = 0;
1015
1016
99
    code = pdfi_BT(ctx);
1017
99
    if (code < 0)
1018
0
        return code;
1019
1020
99
    code = pdfi_annot_display_text(ctx, annot, x, y, text);
1021
99
    code1 = pdfi_ET(ctx);
1022
99
    if (code == 0) code = code1;
1023
1024
99
    return code;
1025
99
}
1026
1027
/* Display a centered text string (outside BT/ET) */
1028
static int
1029
pdfi_annot_display_centered_text(pdf_context *ctx, pdf_dict *annot, gs_rect *rect, pdf_string *text)
1030
30
{
1031
30
    int code = 0;
1032
30
    int code1 = 0;
1033
30
    gs_rect bbox;
1034
30
    gs_point awidth;
1035
30
    double x, y;
1036
1037
30
    code = pdfi_BT(ctx);
1038
30
    if (code < 0)
1039
0
        return code;
1040
1041
    /* Get width of the string */
1042
30
    code = pdfi_string_bbox(ctx, text, &bbox, &awidth, false);
1043
30
    if (code < 0) goto exit;
1044
1045
    /* Center the title in the box */
1046
30
    x = rect->p.x + ((rect->q.x - rect->p.x) - awidth.x) / 2;
1047
30
    y = rect->q.y - 11;
1048
1049
30
    code = pdfi_annot_display_text(ctx, annot, x, y, text);
1050
30
    if (code < 0) goto exit;
1051
1052
30
 exit:
1053
30
    code1 = pdfi_ET(ctx);
1054
30
    if (code == 0) code = code1;
1055
30
    return code;
1056
30
}
1057
1058
/* Display a string formatted to fit in rect (outside BT/ET)
1059
 *
1060
 * TODO: I am sharing code between the FreeText and field/Tx implementation.
1061
 * The gs code has completely different implementations for these.
1062
 * I am not sure if there are some different assumptions about font encodings?
1063
 * The Tx field can apparently be UTF8 or UTF16, whereas the FreeText implementation just assumed
1064
 * it was ASCII.
1065
 * If you see some weird behavior with character mappings or line breaks, then
1066
 * this might be something to revisit.
1067
 */
1068
static int
1069
pdfi_annot_display_formatted_text(pdf_context *ctx, pdf_dict *annot,
1070
                                  gs_rect *rect, pdf_string *text, bool is_UTF16)
1071
4
{
1072
4
    double x;
1073
4
    double lineheight = 0;
1074
4
    double y_start;
1075
4
    double x_start, x_max;
1076
4
    gs_rect bbox;
1077
4
    gs_point awidth; /* Advance width */
1078
4
    int code = 0;
1079
4
    int code1 = 0;
1080
4
    pdf_string *temp_string = NULL;
1081
4
    int i;
1082
4
    byte ch;
1083
4
    bool firstchar = true;
1084
4
    bool linestart = true;
1085
4
    int charlen;
1086
1087
4
    if (is_UTF16)
1088
0
        charlen = 2;
1089
4
    else
1090
4
        charlen = 1;
1091
1092
4
    if (ctx->pgs->PDFfontsize == 0)
1093
0
        return 0;
1094
1095
4
    code = pdfi_BT(ctx);
1096
4
    if (code < 0)
1097
0
        return code;
1098
1099
    /* Allocate a temp string to use, length 1 char */
1100
4
    code = pdfi_object_alloc(ctx, PDF_STRING, charlen, (pdf_obj **)&temp_string);
1101
4
    if (code < 0) goto exit;
1102
4
    pdfi_countup(temp_string);
1103
1104
4
    code = pdfi_annot_get_text_height(ctx, &lineheight);
1105
4
    if (code < 0) goto exit;
1106
1107
4
    y_start = rect->q.y - lineheight;
1108
4
    x_start = rect->p.x;
1109
4
    x_max = rect->q.x;
1110
4
    x = x_start;
1111
1112
1.81k
    for (i=0; i<text->length; i+=charlen) {
1113
1.80k
        int j;
1114
1115
1.80k
        if (linestart) {
1116
11
            x = x_start;
1117
11
        }
1118
1119
3.61k
        for (j = 0; j < charlen; j++) {
1120
1.80k
            ch = text->data[i+j];
1121
1.80k
            temp_string->data[j] = ch;
1122
1.80k
        }
1123
1124
        /* If EOL character encountered, move down to next line */
1125
1.80k
        if (charlen == 1) { /* Can only check this for ASCII font */
1126
1.80k
            if (ch == '\r' || ch == '\n') {
1127
7
                linestart = true;
1128
7
                continue;
1129
7
            }
1130
1.80k
        }
1131
1132
        /* get size of the character */
1133
1.79k
        code = pdfi_string_bbox(ctx, temp_string, &bbox, &awidth, false);
1134
1.79k
        if (code < 0) goto exit;
1135
1136
1.79k
        if (!linestart && ((x + awidth.x) > x_max)) {
1137
15
            x = x_start;
1138
15
            linestart = true;
1139
15
        }
1140
1141
        /* display the character */
1142
1.79k
        if (firstchar) {
1143
4
            code = pdfi_annot_display_text(ctx, annot, x, y_start, temp_string);
1144
4
            firstchar = false;
1145
1.79k
        } else {
1146
1.79k
            if (linestart)
1147
20
                code = pdfi_annot_display_text(ctx, annot, 0, -lineheight, temp_string);
1148
1.77k
            else
1149
1.77k
                code = pdfi_annot_display_nexttext(ctx, annot, temp_string);
1150
1.79k
        }
1151
1.79k
        if (code < 0) goto exit;
1152
1.79k
        x += awidth.x;
1153
1.79k
        linestart = false;
1154
1.79k
    }
1155
1156
4
 exit:
1157
4
    code1 = pdfi_ET(ctx);
1158
4
    if (code == 0) code = code1;
1159
4
    pdfi_countdown(temp_string);
1160
4
    return code;
1161
4
}
1162
1163
/*********** END Font/Text ***************/
1164
1165
1166
/*********** BEGIN /LE ***************/
1167
1168
/* Draw Butt LE */
1169
static int pdfi_annot_draw_LE_Butt(pdf_context *ctx, pdf_dict *annot)
1170
0
{
1171
0
    int code;
1172
0
    double width;
1173
0
    double seglength;
1174
1175
0
    code = pdfi_annot_get_BS_width(ctx, annot, &width);
1176
0
    if (code < 0) goto exit;
1177
1178
0
    seglength = 3*width;
1179
0
    code = gs_moveto(ctx->pgs, 0, -seglength);
1180
0
    if (code < 0) goto exit;
1181
0
    code = gs_lineto(ctx->pgs, 0, seglength);
1182
0
    if (code < 0) goto exit;
1183
0
    code = pdfi_annot_draw_border(ctx, annot, true);
1184
0
    if (code < 0) goto exit;
1185
1186
0
 exit:
1187
0
    return code;
1188
0
}
1189
1190
/* Draw Circle LE */
1191
static int pdfi_annot_draw_LE_Circle(pdf_context *ctx, pdf_dict *annot)
1192
0
{
1193
0
    double radius;
1194
0
    int code;
1195
0
    double width;
1196
1197
0
    code = pdfi_annot_get_BS_width(ctx, annot, &width);
1198
0
    if (code < 0) goto exit;
1199
1200
0
    code = pdfi_gsave(ctx);
1201
0
    if (code < 0) goto exit;
1202
1203
0
    radius = width * 2.5;
1204
0
    code = gs_moveto(ctx->pgs, radius, 0);
1205
0
    if (code < 0) goto exit_grestore;
1206
0
    code = gs_arc(ctx->pgs, 0, 0, radius, 0, 360);
1207
0
    if (code < 0) goto exit_grestore;
1208
0
    code = pdfi_annot_opacity(ctx, annot);
1209
0
    if (code < 0) goto exit_grestore;
1210
0
    code = pdfi_annot_fillborderpath(ctx, annot);
1211
0
    if (code < 0) goto exit_grestore;
1212
1213
0
    code = pdfi_grestore(ctx);
1214
0
    if (code < 0) goto exit;
1215
1216
0
    radius = width * 3;
1217
0
    code = gs_moveto(ctx->pgs, radius, 0);
1218
0
    if (code < 0) goto exit;
1219
0
    code = gs_arc(ctx->pgs, 0, 0, radius, 0, 360);
1220
0
    if (code < 0) goto exit;
1221
0
    code = pdfi_annot_draw_border(ctx, annot, true);
1222
0
    goto exit;
1223
1224
0
 exit_grestore:
1225
0
    (void)pdfi_grestore(ctx);
1226
0
 exit:
1227
0
    return code;
1228
0
}
1229
1230
/* Draw Diamond LE */
1231
static int pdfi_annot_draw_LE_Diamond(pdf_context *ctx, pdf_dict *annot)
1232
0
{
1233
0
    int code;
1234
0
    double width;
1235
0
    double seglength;
1236
1237
0
    code = pdfi_annot_get_BS_width(ctx, annot, &width);
1238
0
    if (code < 0) goto exit;
1239
1240
0
    code = pdfi_gsave(ctx);
1241
0
    if (code < 0) goto exit;
1242
1243
0
    seglength = width * 2.5;
1244
0
    code = gs_moveto(ctx->pgs, 0, -seglength);
1245
0
    if (code < 0) goto exit_grestore;
1246
0
    code = gs_lineto(ctx->pgs, -seglength, 0);
1247
0
    if (code < 0) goto exit_grestore;
1248
0
    code = gs_lineto(ctx->pgs, 0, seglength);
1249
0
    if (code < 0) goto exit_grestore;
1250
0
    code = gs_lineto(ctx->pgs, seglength, 0);
1251
0
    if (code < 0) goto exit_grestore;
1252
0
    code = gs_closepath(ctx->pgs);
1253
0
    if (code < 0) goto exit_grestore;
1254
0
    code = pdfi_annot_opacity(ctx, annot);
1255
0
    if (code < 0) goto exit_grestore;
1256
0
    code = pdfi_annot_fillborderpath(ctx, annot);
1257
0
    if (code < 0) goto exit_grestore;
1258
1259
0
    code = pdfi_grestore(ctx);
1260
0
    if (code < 0) goto exit;
1261
1262
0
    seglength = width * 3;
1263
0
    code = gs_moveto(ctx->pgs, 0, -seglength);
1264
0
    if (code < 0) goto exit;
1265
0
    code = gs_lineto(ctx->pgs, -seglength, 0);
1266
0
    if (code < 0) goto exit;
1267
0
    code = gs_lineto(ctx->pgs, 0, seglength);
1268
0
    if (code < 0) goto exit;
1269
0
    code = gs_lineto(ctx->pgs, seglength, 0);
1270
0
    if (code < 0) goto exit;
1271
0
    code = gs_closepath(ctx->pgs);
1272
0
    if (code < 0) goto exit;
1273
0
    code = pdfi_annot_draw_border(ctx, annot, true);
1274
0
    goto exit;
1275
1276
0
 exit_grestore:
1277
0
    (void)pdfi_grestore(ctx);
1278
0
 exit:
1279
0
    return code;
1280
0
}
1281
1282
/* Draw Square LE */
1283
static int pdfi_annot_draw_LE_Square(pdf_context *ctx, pdf_dict *annot)
1284
0
{
1285
0
    int code;
1286
0
    double width;
1287
0
    double seglength;
1288
1289
0
    code = pdfi_annot_get_BS_width(ctx, annot, &width);
1290
0
    if (code < 0) goto exit;
1291
1292
0
    code = pdfi_gsave(ctx);
1293
0
    if (code < 0) goto exit;
1294
1295
0
    seglength = width * 2.5;
1296
0
    code = gs_moveto(ctx->pgs, -seglength, -seglength);
1297
0
    if (code < 0) goto exit_grestore;
1298
0
    code = gs_lineto(ctx->pgs, -seglength, seglength);
1299
0
    if (code < 0) goto exit_grestore;
1300
0
    code = gs_lineto(ctx->pgs, seglength, seglength);
1301
0
    if (code < 0) goto exit_grestore;
1302
0
    code = gs_lineto(ctx->pgs, seglength, -seglength);
1303
0
    if (code < 0) goto exit_grestore;
1304
0
    code = gs_closepath(ctx->pgs);
1305
0
    if (code < 0) goto exit_grestore;
1306
0
    code = pdfi_annot_opacity(ctx, annot);
1307
0
    if (code < 0) goto exit_grestore;
1308
0
    code = pdfi_annot_fillborderpath(ctx, annot);
1309
0
    if (code < 0) goto exit_grestore;
1310
1311
0
    code = pdfi_grestore(ctx);
1312
0
    if (code < 0) goto exit;
1313
1314
0
    seglength = width * 3;
1315
0
    code = gs_moveto(ctx->pgs, -seglength, -seglength);
1316
0
    if (code < 0) goto exit;
1317
0
    code = gs_lineto(ctx->pgs, -seglength, seglength);
1318
0
    if (code < 0) goto exit;
1319
0
    code = gs_lineto(ctx->pgs, seglength, seglength);
1320
0
    if (code < 0) goto exit;
1321
0
    code = gs_lineto(ctx->pgs, seglength, -seglength);
1322
0
    if (code < 0) goto exit;
1323
0
    code = gs_closepath(ctx->pgs);
1324
0
    if (code < 0) goto exit;
1325
0
    code = pdfi_annot_draw_border(ctx, annot, true);
1326
0
    goto exit;
1327
1328
0
 exit_grestore:
1329
0
    (void)pdfi_grestore(ctx);
1330
0
 exit:
1331
0
    return code;
1332
0
}
1333
1334
/* Draw Slash LE */
1335
static int pdfi_annot_draw_LE_Slash(pdf_context *ctx, pdf_dict *annot)
1336
0
{
1337
0
    int code;
1338
0
    double width;
1339
0
    double seglength;
1340
1341
0
    code = pdfi_annot_get_BS_width(ctx, annot, &width);
1342
0
    if (code < 0) goto exit;
1343
1344
0
    seglength = 3*width;
1345
0
    code = gs_rotate(ctx->pgs, 330);
1346
0
    if (code < 0) goto exit;
1347
0
    code = gs_moveto(ctx->pgs, 0, -seglength);
1348
0
    if (code < 0) goto exit;
1349
0
    code = gs_lineto(ctx->pgs, 0, seglength);
1350
0
    if (code < 0) goto exit;
1351
0
    code = pdfi_annot_draw_border(ctx, annot, true);
1352
0
    if (code < 0) goto exit;
1353
1354
0
 exit:
1355
0
    return code;
1356
0
}
1357
1358
/* Draw ClosedArrow LE */
1359
static int pdfi_annot_draw_LE_ClosedArrow(pdf_context *ctx, pdf_dict *annot)
1360
99
{
1361
99
    int code;
1362
99
    double width;
1363
99
    double seglen;
1364
1365
99
    code = pdfi_annot_get_BS_width(ctx, annot, &width);
1366
99
    if (code < 0) goto exit;
1367
1368
99
    code = pdfi_gsave(ctx);
1369
99
    if (code < 0) goto exit_grestore;
1370
1371
99
    code = gs_setlinejoin(ctx->pgs, 0);
1372
99
    if (code < 0) goto exit_grestore;
1373
99
    code = gs_moveto(ctx->pgs, -width*6, -width*4);
1374
99
    if (code < 0) goto exit_grestore;
1375
99
    code = gs_lineto(ctx->pgs, -width/1.2, 0);
1376
99
    if (code < 0) goto exit_grestore;
1377
99
    code = gs_lineto(ctx->pgs, -width*6, width*4);
1378
99
    if (code < 0) goto exit_grestore;
1379
99
    code = gs_closepath(ctx->pgs);
1380
99
    if (code < 0) goto exit_grestore;
1381
99
    code = pdfi_annot_draw_border(ctx, annot, true);
1382
99
    if (code < 0) goto exit_grestore;
1383
1384
99
    code = pdfi_grestore(ctx);
1385
99
    if (code < 0) goto exit;
1386
1387
99
    code = gs_translate(ctx->pgs, -1.3*width, 0);
1388
99
    if (code < 0) goto exit;
1389
99
    seglen = width / 2;
1390
99
    code = gs_moveto(ctx->pgs, -seglen*8.4, -seglen*5.9);
1391
99
    if (code < 0) goto exit;
1392
99
    code = gs_lineto(ctx->pgs, -seglen/1.2, 0);
1393
99
    if (code < 0) goto exit;
1394
99
    code = gs_lineto(ctx->pgs, -seglen*8.4, seglen*5.9);
1395
99
    if (code < 0) goto exit;
1396
99
    code = gs_closepath(ctx->pgs);
1397
99
    if (code < 0) goto exit;
1398
99
    code = pdfi_annot_opacity(ctx, annot);
1399
99
    if (code < 0) goto exit;
1400
99
    code = pdfi_annot_fillborderpath(ctx, annot);
1401
99
    goto exit;
1402
1403
0
 exit_grestore:
1404
0
    (void)pdfi_grestore(ctx);
1405
99
 exit:
1406
99
    return code;
1407
0
}
1408
1409
/* Draw OpenArrow LE */
1410
static int pdfi_annot_draw_LE_OpenArrow(pdf_context *ctx, pdf_dict *annot)
1411
0
{
1412
0
    int code;
1413
0
    double width;
1414
1415
0
    code = pdfi_annot_get_BS_width(ctx, annot, &width);
1416
0
    if (code < 0) goto exit;
1417
1418
0
    code = gs_setlinejoin(ctx->pgs, 0);
1419
0
    if (code < 0) goto exit;
1420
1421
0
    code = gs_moveto(ctx->pgs, -width*6, -width*4);
1422
0
    if (code < 0) goto exit;
1423
0
    code = gs_lineto(ctx->pgs, -width/1.2, 0);
1424
0
    if (code < 0) goto exit;
1425
0
    code = gs_lineto(ctx->pgs, -width*6, width*4);
1426
0
    if (code < 0) goto exit;
1427
0
    code = pdfi_annot_draw_border(ctx, annot, true);
1428
0
    if (code < 0) goto exit;
1429
1430
0
 exit:
1431
0
    return code;
1432
0
}
1433
1434
/* Draw RClosedArrow LE */
1435
static int pdfi_annot_draw_LE_RClosedArrow(pdf_context *ctx, pdf_dict *annot)
1436
0
{
1437
0
    int code;
1438
1439
0
    code = gs_rotate(ctx->pgs, 180);
1440
0
    if (code < 0) goto exit;
1441
0
    code = pdfi_annot_draw_LE_ClosedArrow(ctx, annot);
1442
0
    if (code < 0) goto exit;
1443
1444
0
 exit:
1445
0
    return code;
1446
0
}
1447
1448
/* Draw ROpenArrow LE */
1449
static int pdfi_annot_draw_LE_ROpenArrow(pdf_context *ctx, pdf_dict *annot)
1450
0
{
1451
0
    int code;
1452
1453
0
    code = gs_rotate(ctx->pgs, 180);
1454
0
    if (code < 0) goto exit;
1455
0
    code = pdfi_annot_draw_LE_OpenArrow(ctx, annot);
1456
0
    if (code < 0) goto exit;
1457
1458
0
 exit:
1459
0
    return code;
1460
0
}
1461
1462
/* Draw None or null LE (do nothing) */
1463
static int pdfi_annot_draw_LE_None(pdf_context *ctx, pdf_dict *annot)
1464
330
{
1465
330
    return 0;
1466
330
}
1467
1468
annot_LE_dispatch_t annot_LE_dispatch[] = {
1469
    {"Butt", pdfi_annot_draw_LE_Butt},
1470
    {"Circle", pdfi_annot_draw_LE_Circle},
1471
    {"Diamond", pdfi_annot_draw_LE_Diamond},
1472
    {"Slash", pdfi_annot_draw_LE_Slash},
1473
    {"Square", pdfi_annot_draw_LE_Square},
1474
    {"ClosedArrow", pdfi_annot_draw_LE_ClosedArrow},
1475
    {"OpenArrow", pdfi_annot_draw_LE_OpenArrow},
1476
    {"RClosedArrow", pdfi_annot_draw_LE_RClosedArrow},
1477
    {"ROpenArrow", pdfi_annot_draw_LE_ROpenArrow},
1478
    {"None", pdfi_annot_draw_LE_None},
1479
    { NULL, NULL},
1480
};
1481
1482
/* Draw one line ending at (x,y) */
1483
static int pdfi_annot_draw_LE_one(pdf_context *ctx, pdf_dict *annot, pdf_name *LE,
1484
                                  double x, double y, double angle)
1485
436
{
1486
436
    int code;
1487
436
    int code1;
1488
436
    annot_LE_dispatch_t *dispatch_ptr;
1489
1490
436
    code = pdfi_gsave(ctx);
1491
436
    if (code < 0) goto exit1;
1492
1493
436
    code = gs_translate(ctx->pgs, x, y);
1494
436
    code = gs_moveto(ctx->pgs, 0, 0);
1495
436
    code = gs_rotate(ctx->pgs, angle);
1496
1497
    /* Draw the LE */
1498
3.97k
    for (dispatch_ptr = annot_LE_dispatch; dispatch_ptr->name; dispatch_ptr ++) {
1499
3.96k
        if (pdfi_name_is(LE, dispatch_ptr->name)) {
1500
429
            code = dispatch_ptr->func(ctx, annot);
1501
429
            break;
1502
429
        }
1503
3.96k
    }
1504
436
    if (!dispatch_ptr->name) {
1505
7
        char str[100];
1506
7
        memcpy(str, (const char *)LE->data, LE->length < 100 ? LE->length : 99);
1507
7
        str[LE->length < 100 ? LE->length : 99] = '\0';
1508
7
        dbgmprintf1(ctx->memory, "ANNOT: WARNING No handler for LE %s\n", str);
1509
7
    }
1510
1511
436
 exit1:
1512
436
    code1 = pdfi_grestore(ctx);
1513
436
    if (code < 0)
1514
1
        code = code1;
1515
436
    return code;
1516
436
}
1517
1518
/* Draw line endings using LE entry in annotation dictionary
1519
 * Draws one at (x1,y1) and one at (x2,y2)
1520
 * If LE is a name instead of an array, only draws at x2,y2 (but needs x1,y1 for angle)
1521
 *  (defaults to None if not there)
1522
 *
1523
 * which -- tells whether to draw both ends (0) or just the first one (1) or second one (2)
1524
 */
1525
static int pdfi_annot_draw_LE(pdf_context *ctx, pdf_dict *annot,
1526
                              double x1, double y1, double x2, double y2, int which)
1527
450
{
1528
450
    pdf_obj *LE = NULL;
1529
450
    pdf_name *LE1 = NULL;
1530
450
    pdf_name *LE2 = NULL;
1531
450
    double dx, dy;
1532
450
    double angle;
1533
450
    int code;
1534
450
    pdf_obj_type type;
1535
1536
450
    code = pdfi_dict_knownget(ctx, annot, "LE", (pdf_obj **)&LE);
1537
450
    if (code <= 0)
1538
227
        goto exit;
1539
223
    type = pdfi_type_of(LE);
1540
223
    if (type != PDF_ARRAY && type != PDF_NAME) {
1541
0
        code = gs_note_error(gs_error_typecheck);
1542
0
        goto exit;
1543
0
    }
1544
1545
223
    dx = x2 - x1;
1546
223
    dy = y2 - y1;
1547
223
    code = gs_atan2_degrees(dy, dx, &angle);
1548
223
    if (code < 0)
1549
0
        angle = 0;
1550
1551
223
    if (type == PDF_ARRAY) {
1552
223
        code = pdfi_array_get_type(ctx, (pdf_array *)LE, 0, PDF_NAME, (pdf_obj **)&LE1);
1553
223
        if (code < 0) goto exit;
1554
1555
223
        code = pdfi_array_get_type(ctx, (pdf_array *)LE, 1, PDF_NAME, (pdf_obj **)&LE2);
1556
223
        if (code < 0) goto exit;
1557
223
    } else {
1558
0
        LE1 = (pdf_name *)LE;
1559
0
        LE = NULL;
1560
0
    }
1561
222
    if (LE1 && (!which || which == 1)) {
1562
218
        code = pdfi_annot_draw_LE_one(ctx, annot, LE1, x1, y1, angle+180);
1563
218
        if (code < 0) goto exit;
1564
218
    }
1565
1566
222
    if (LE2 && (!which || which == 2)) {
1567
218
        code = pdfi_annot_draw_LE_one(ctx, annot, LE2, x2, y2, angle);
1568
218
        if (code < 0) goto exit;
1569
218
    }
1570
1571
450
 exit:
1572
450
    pdfi_countdown(LE);
1573
450
    pdfi_countdown(LE1);
1574
450
    pdfi_countdown(LE2);
1575
450
    return code;
1576
222
}
1577
/*********** END /LE ***************/
1578
1579
1580
/* Get the Normal AP dictionary/stream, if it exists
1581
 * Not an error if it doesn't exist, it will just be NULL
1582
 */
1583
static int pdfi_annot_get_NormAP(pdf_context *ctx, pdf_dict *annot, pdf_obj **NormAP)
1584
225k
{
1585
225k
    int code;
1586
225k
    pdf_dict *AP_dict = NULL;
1587
225k
    pdf_stream *AP = NULL;
1588
225k
    pdf_obj *baseAP = NULL;
1589
225k
    pdf_name *AS = NULL;
1590
1591
225k
    *NormAP = NULL;
1592
1593
225k
    code = pdfi_dict_knownget_type(ctx, annot, "AP", PDF_DICT, (pdf_obj **)&AP_dict);
1594
225k
    if (code <= 0) goto exit;
1595
1596
193k
    code = pdfi_dict_knownget(ctx, AP_dict, "N", (pdf_obj **)&baseAP);
1597
193k
    if (code < 0) goto exit;
1598
1599
    /* Look for /R and /D if there was no /N */
1600
143k
    if (code == 0) {
1601
7
        pdfi_set_warning(ctx, 0, NULL, W_PDF_ANNOT_AP_ERROR, "pdfi_annot_get_NormAP", "*** Error: Annotation (AP) lacks the mandatory normal (N) appearance");
1602
1603
7
        code = pdfi_dict_knownget(ctx, AP_dict, "R", (pdf_obj **)&baseAP);
1604
7
        if (code < 0) goto exit;
1605
1606
7
        if (code == 0) {
1607
7
            code = pdfi_dict_knownget(ctx, AP_dict, "D", (pdf_obj **)&baseAP);
1608
7
            if (code < 0) goto exit;
1609
7
        }
1610
7
    }
1611
1612
    /* Nothing found */
1613
143k
    if (code == 0) goto exit;
1614
1615
143k
    switch (pdfi_type_of(baseAP)) {
1616
112k
        case PDF_STREAM:
1617
            /* Use baseAP for the AP */
1618
112k
            AP = (pdf_stream *)baseAP;
1619
112k
            baseAP = NULL;
1620
112k
            break;
1621
30.6k
        case PDF_DICT:
1622
30.6k
            code = pdfi_dict_knownget_type(ctx, annot, "AS", PDF_NAME, (pdf_obj **)&AS);
1623
30.6k
            if (code < 0) goto exit;
1624
30.6k
            if (code == 0) {
1625
83
                pdfi_set_warning(ctx, 0, NULL, W_PDF_ANNOT_AP_ERROR, "pdfi_annot_get_NormAP", "WARNING Annotation has non-stream AP but no AS.  Don't know what to render");
1626
83
                goto exit;
1627
83
            }
1628
1629
            /* Lookup the AS in the NormAP and use that as the AP */
1630
30.5k
            code = pdfi_dict_get_by_key(ctx, (pdf_dict *)baseAP, AS, (pdf_obj **)&AP);
1631
30.5k
            if (code < 0) {
1632
                /* Apparently this is not an error, just silently don't have an AP */
1633
8.38k
                code = 0;
1634
8.38k
                goto exit;
1635
8.38k
            }
1636
22.2k
            if (pdfi_type_of(AP) != PDF_STREAM) {
1637
44
                code = gs_note_error(gs_error_typecheck);
1638
44
                goto exit;
1639
44
            }
1640
22.1k
            break;
1641
22.1k
        default:
1642
183
            code = gs_error_typecheck;
1643
183
            goto exit;
1644
143k
    }
1645
1646
134k
   *NormAP = (pdf_obj *)AP;
1647
134k
   pdfi_countup(AP);
1648
1649
225k
 exit:
1650
225k
    pdfi_countdown(AP_dict);
1651
225k
    pdfi_countdown(AP);
1652
225k
    pdfi_countdown(AS);
1653
225k
    pdfi_countdown(baseAP);
1654
225k
    return code;
1655
134k
}
1656
1657
static int pdfi_annot_draw_Link(pdf_context *ctx, pdf_dict *annot, pdf_obj *NormAP, bool *render_done)
1658
648
{
1659
648
    int code;
1660
648
    int code1;
1661
648
    bool drawit;
1662
1663
648
    dbgmprintf(ctx->memory, "ANNOT: Drawing Link\n");
1664
1665
648
    code = pdfi_annot_start_transparency(ctx, annot);
1666
648
    if (code < 0)
1667
0
        return code;
1668
1669
648
    code = pdfi_annot_setcolor(ctx, annot, true, &drawit);
1670
648
    if (code < 0) goto exit;
1671
648
    if (!drawit) goto exit;
1672
1673
648
    code = pdfi_annot_draw_border(ctx, annot, false);
1674
648
    if (code < 0) goto exit;
1675
1676
648
    code = pdfi_annot_draw_AP(ctx, annot, NormAP);
1677
1678
648
 exit:
1679
648
    code1 = pdfi_annot_end_transparency(ctx, annot);
1680
648
    if (code < 0) code = code1;
1681
1682
648
    *render_done = true;
1683
648
    return code;
1684
648
}
1685
1686
/* Draw a path from an InkList
1687
 * see zpdfops.c/zpdfinkpath()
1688
 *
1689
 * Construct a smooth path passing though a number of points  on the stack
1690
 * for PDF ink annotations. The program is based on a very simple method of
1691
 * smoothing polygons by Maxim Shemanarev.
1692
 * http://www.antigrain.com/research/bezier_interpolation/
1693
 *
1694
 * InkList is array of arrays, each representing a stroked path
1695
 */
1696
static int pdfi_annot_draw_InkList(pdf_context *ctx, pdf_dict *annot, pdf_array *InkList)
1697
185
{
1698
185
    int code = 0;
1699
185
    pdf_array *points = NULL;
1700
185
    int i;
1701
185
    int num_points;
1702
185
    double x0, y0, x1, y1, x2, y2, x3, y3, xc1, yc1, xc2, yc2, xc3, yc3;
1703
185
    double len1, len2, len3, k1, k2, xm1, ym1, xm2, ym2;
1704
185
    double ctrl1_x, ctrl1_y, ctrl2_x, ctrl2_y;
1705
185
    const double smooth_value = 1; /* from 0..1 range */
1706
1707
355
    for (i=0; i<pdfi_array_size(InkList); i++) {
1708
185
        int j;
1709
1710
185
        code = pdfi_array_get_type(ctx, InkList, i, PDF_ARRAY, (pdf_obj **)&points);
1711
185
        if (code < 0)
1712
0
            goto exit;
1713
1714
185
        num_points = pdfi_array_size(points);
1715
185
        if (num_points < 2)
1716
0
            goto exit;
1717
1718
185
        code = pdfi_array_get_number(ctx, points, 0, &x1);
1719
185
        if (code < 0) goto exit;
1720
185
        code = pdfi_array_get_number(ctx, points, 1, &y1);
1721
185
        if (code < 0) goto exit;
1722
184
        code = gs_moveto(ctx->pgs, x1, y1);
1723
184
        if (code < 0) goto exit;
1724
184
        if (num_points == 2)
1725
0
            goto stroke;
1726
1727
184
        code = pdfi_array_get_number(ctx, points, 2, &x2);
1728
184
        if (code < 0) goto exit;
1729
184
        code = pdfi_array_get_number(ctx, points, 3, &y2);
1730
184
        if (code < 0) goto exit;
1731
184
        if (num_points == 4) {
1732
0
            code = gs_lineto(ctx->pgs, x2, y2);
1733
0
            if (code < 0)
1734
0
                goto exit;
1735
0
            goto stroke;
1736
0
        }
1737
1738
184
        x0 = 2*x1 - x2;
1739
184
        y0 = 2*y1 - y2;
1740
1741
5.78k
        for (j = 4; j <= num_points; j += 2) {
1742
5.61k
            if (j < num_points) {
1743
5.44k
                code = pdfi_array_get_number(ctx, points, j, &x3);
1744
5.44k
                if (code < 0) goto exit;
1745
5.43k
                code = pdfi_array_get_number(ctx, points, j+1, &y3);
1746
5.43k
                if (code < 0) goto exit;
1747
5.43k
            } else {
1748
170
                x3 = 2*x2 - x1;
1749
170
                y3 = 2*y2 - y1;
1750
170
            }
1751
1752
5.59k
            xc1 = (x0 + x1) / 2.0;
1753
5.59k
            yc1 = (y0 + y1) / 2.0;
1754
5.59k
            xc2 = (x1 + x2) / 2.0;
1755
5.59k
            yc2 = (y1 + y2) / 2.0;
1756
5.59k
            xc3 = (x2 + x3) / 2.0;
1757
5.59k
            yc3 = (y2 + y3) / 2.0;
1758
1759
5.59k
            len1 = hypot(x1 - x0, y1 - y0);
1760
5.59k
            len2 = hypot(x2 - x1, y2 - y1);
1761
5.59k
            len3 = hypot(x3 - x2, y3 - y2);
1762
1763
5.59k
            if ((len1 + len2) == 0)
1764
54
                k1 = 0;
1765
5.54k
            else
1766
5.54k
                k1 = len1 / (len1 + len2);
1767
5.59k
            if ((len2 + len3) == 0)
1768
69
                k2 = 0;
1769
5.53k
            else
1770
5.53k
                k2 = len2 / (len2 + len3);
1771
1772
5.59k
            xm1 = xc1 + (xc2 - xc1) * k1;
1773
5.59k
            ym1 = yc1 + (yc2 - yc1) * k1;
1774
1775
5.59k
            xm2 = xc2 + (xc3 - xc2) * k2;
1776
5.59k
            ym2 = yc2 + (yc3 - yc2) * k2;
1777
1778
5.59k
            ctrl1_x = xm1 + (xc2 - xm1) * smooth_value + x1 - xm1;
1779
5.59k
            ctrl1_y = ym1 + (yc2 - ym1) * smooth_value + y1 - ym1;
1780
1781
5.59k
            ctrl2_x = xm2 + (xc2 - xm2) * smooth_value + x2 - xm2;
1782
5.59k
            ctrl2_y = ym2 + (yc2 - ym2) * smooth_value + y2 - ym2;
1783
1784
5.59k
            code = gs_curveto(ctx->pgs, ctrl1_x, ctrl1_y, ctrl2_x, ctrl2_y, x2, y2);
1785
5.59k
            if (code < 0) goto exit;
1786
1787
5.59k
            x0 = x1, x1 = x2, x2 = x3;
1788
5.59k
            y0 = y1, y1 = y2, y2 = y3;
1789
5.59k
        }
1790
1791
170
    stroke:
1792
170
        code = gs_stroke(ctx->pgs);
1793
170
        if (code < 0) goto exit;
1794
170
        pdfi_countdown(points);
1795
170
        points = NULL;
1796
170
    }
1797
1798
185
 exit:
1799
185
    pdfi_countdown(points);
1800
185
    return code;
1801
185
}
1802
1803
/* Draw a path from a Path array (see 2.0 spec 12.5.6.13)
1804
 * Path is array of arrays.
1805
 * First array is 2 args for moveto
1806
 * The rest of the arrays are either 2 args for lineto or 6 args for curveto
1807
 */
1808
static int pdfi_annot_draw_Path(pdf_context *ctx, pdf_dict *annot, pdf_array *Path)
1809
0
{
1810
0
    int code = 0;
1811
0
    pdf_array *points = NULL;
1812
0
    double array[6];
1813
0
    int i;
1814
0
    int num_points;
1815
1816
0
    for (i=0; i<pdfi_array_size(Path); i++) {
1817
0
        code = pdfi_array_get_type(ctx, Path, i, PDF_ARRAY, (pdf_obj **)&points);
1818
0
        if (code < 0)
1819
0
            goto exit;
1820
1821
0
        num_points = pdfi_array_size(points);
1822
0
        if (num_points != 2 && num_points != 6) {
1823
0
            code = gs_note_error(gs_error_rangecheck);
1824
0
            goto exit;
1825
0
        }
1826
1827
0
        code = pdfi_array_to_num_array(ctx, points, array, 0, num_points);
1828
0
        if (code < 0) goto exit;
1829
1830
0
        if (i == 0) {
1831
0
            code = gs_moveto(ctx->pgs, array[0], array[1]);
1832
0
            if (code < 0) goto exit;
1833
0
        } else {
1834
0
            if (num_points == 2) {
1835
0
                code = gs_lineto(ctx->pgs, array[0], array[1]);
1836
0
                if (code < 0) goto exit;
1837
0
            } else {
1838
0
                code = gs_curveto(ctx->pgs, array[0], array[1],
1839
0
                                  array[2], array[3], array[4], array[5]);
1840
0
                if (code < 0) goto exit;
1841
0
            }
1842
0
        }
1843
1844
0
        pdfi_countdown(points);
1845
0
        points = NULL;
1846
0
    }
1847
1848
0
    code = pdfi_annot_draw_border(ctx, annot, true);
1849
1850
0
 exit:
1851
0
    pdfi_countdown(points);
1852
0
    return code;
1853
0
}
1854
1855
/* Generate appearance (see pdf_draw.ps/Ink
1856
 *
1857
 * If there was an AP it was already handled.
1858
 */
1859
static int pdfi_annot_draw_Ink(pdf_context *ctx, pdf_dict *annot, pdf_obj *NormAP, bool *render_done)
1860
187
{
1861
187
    int code = 0;
1862
187
    int code1 = 0;
1863
187
    bool drawit;
1864
187
    pdf_array *array = NULL;
1865
1866
187
    code = pdfi_annot_setcolor(ctx, annot, false, &drawit);
1867
187
    if (code <0 || !drawit)
1868
0
        goto exit1;
1869
1870
187
    code = pdfi_annot_start_transparency(ctx, annot);
1871
187
    if (code < 0) goto exit1;
1872
1873
187
    code = gs_setlinewidth(ctx->pgs, 1);
1874
187
    if (code < 0) goto exit;
1875
187
    code = gs_setlinecap(ctx->pgs, 1);
1876
187
    if (code < 0) goto exit;
1877
187
    code = gs_setlinejoin(ctx->pgs, 1);
1878
187
    if (code < 0) goto exit;
1879
1880
187
    code = pdfi_dict_knownget_type(ctx, annot, "InkList", PDF_ARRAY, (pdf_obj **)&array);
1881
187
    if (code < 0) goto exit;
1882
187
    if (code > 0) {
1883
185
        code = pdfi_annot_draw_InkList(ctx, annot, array);
1884
185
        goto exit;
1885
185
    }
1886
2
    code = pdfi_dict_knownget_type(ctx, annot, "Path", PDF_ARRAY, (pdf_obj **)&array);
1887
2
    if (code < 0) goto exit;
1888
2
    if (code > 0) {
1889
0
        code = pdfi_annot_draw_Path(ctx, annot, array);
1890
0
        goto exit;
1891
0
    }
1892
1893
187
 exit:
1894
187
    code1 = pdfi_annot_end_transparency(ctx, annot);
1895
187
    if (code >= 0)
1896
172
        code = code1;
1897
187
 exit1:
1898
187
    pdfi_countdown(array);
1899
187
    *render_done = true;
1900
187
    return code;
1901
187
}
1902
1903
/* from pdf_draw.ps/drawellipse
1904
 * "Don Lancaster's code for drawing an ellipse"
1905
 * https://www.tinaja.com/glib/ellipse4.pdf
1906
 *
1907
/magic 0.55228475 0.00045 sub store  % improved value
1908
/drawellipse {
1909
2 div /yrad exch store
1910
2 div /xrad exch store
1911
/xmag xrad magic mul store
1912
/ymag yrad magic mul store xrad
1913
neg 0 moveto
1914
xrad neg ymag xmag neg yrad 0 yrad curveto
1915
xmag  yrad xrad ymag xrad 0 curveto
1916
xrad ymag neg  xmag yrad neg 0  yrad neg curveto
1917
xmag neg yrad neg xrad neg ymag neg xrad neg  0 curveto
1918
} bind def
1919
1920
 */
1921
static int pdfi_annot_drawellipse(pdf_context *ctx, double width, double height)
1922
66
{
1923
66
    int code = 0;
1924
66
    double magic = .55228475 - .00045; /* Magic value */
1925
66
    double xrad = width / 2;
1926
66
    double yrad = height / 2;
1927
66
    double xmag = xrad * magic;
1928
66
    double ymag = yrad * magic;
1929
1930
66
    code = gs_moveto(ctx->pgs, -xrad, 0);
1931
66
    if (code < 0) return code;
1932
66
    code = gs_curveto(ctx->pgs, -xrad, ymag, -xmag, yrad, 0, yrad);
1933
66
    if (code < 0) return code;
1934
66
    code = gs_curveto(ctx->pgs, xmag, yrad, xrad, ymag, xrad, 0);
1935
66
    if (code < 0) return code;
1936
66
    code = gs_curveto(ctx->pgs, xrad, -ymag, xmag, -yrad, 0, -yrad);
1937
66
    if (code < 0) return code;
1938
66
    code = gs_curveto(ctx->pgs, -xmag, -yrad, -xrad, -ymag, -xrad, 0);
1939
1940
66
    return code;
1941
66
}
1942
1943
/* Generate appearance (see pdf_draw.ps/Circle)
1944
 *
1945
 * If there was an AP it was already handled.
1946
 */
1947
static int pdfi_annot_draw_Circle(pdf_context *ctx, pdf_dict *annot, pdf_obj *NormAP, bool *render_done)
1948
66
{
1949
66
    int code = 0;
1950
66
    int code1 = 0;
1951
66
    gs_rect rect;
1952
66
    bool drawit;
1953
66
    double width, height;
1954
1955
66
    code = pdfi_annot_start_transparency(ctx, annot);
1956
66
    if (code < 0) goto exit1;
1957
1958
66
    code = pdfi_annot_Rect(ctx, annot, &rect);
1959
66
    if (code < 0) goto exit;
1960
1961
66
    code = pdfi_annot_applyRD(ctx, annot, &rect);
1962
66
    if (code < 0) goto exit;
1963
1964
    /* Translate to the center of the ellipse */
1965
66
    width = rect.q.x - rect.p.x;
1966
66
    height = rect.q.y - rect.p.y;
1967
66
    code = gs_translate(ctx->pgs, rect.p.x + width/2, rect.p.y + height/2);
1968
66
    if (code < 0) goto exit;
1969
1970
    /* Draw the ellipse */
1971
66
    code = pdfi_annot_drawellipse(ctx, width, height);
1972
66
    if (code < 0) goto exit;
1973
1974
66
    code = pdfi_annot_fillborderpath(ctx, annot);
1975
66
    if (code < 0) goto exit;
1976
1977
66
    code = pdfi_annot_setcolor(ctx, annot, false, &drawit);
1978
66
    if (code < 0) goto exit;
1979
1980
66
    if (drawit) {
1981
65
        code = pdfi_annot_draw_border(ctx, annot, true);
1982
65
        if (code < 0) goto exit;
1983
65
    }
1984
1985
66
 exit:
1986
66
    code1 = pdfi_annot_end_transparency(ctx, annot);
1987
66
    if (code >= 0)
1988
66
        code = code1;
1989
66
 exit1:
1990
66
    *render_done = true;
1991
66
    return code;
1992
66
}
1993
1994
1995
/*********** BEGIN /Stamp ***************/
1996
typedef struct {
1997
    double r,g,b;
1998
} pdfi_annot_stamp_rgb_t;
1999
2000
#define STAMP_RED {0xef/255.,0x40/255.,0x23/255.}
2001
#define STAMP_GREEN {0x2f/255.,0xae/255.,0x49/255.}
2002
#define STAMP_BLUE {0x00/255.,0x72/255.,0xbc/255.}
2003
2004
typedef struct {
2005
    const char *text;
2006
    double y;
2007
    double h;
2008
} pdfi_annot_stamp_text_t;
2009
2010
typedef struct {
2011
    const char *type;
2012
    pdfi_annot_stamp_rgb_t rgb;
2013
    pdfi_annot_stamp_text_t text[2];
2014
} pdfi_annot_stamp_type_t;
2015
2016
#define STAMP_1LINE(text,y,h) {{text,y,h},{0}}
2017
#define STAMP_2LINE(text,y,h,text2,y2,h2) {{text,y,h},{text2,y2,h2}}
2018
2019
static pdfi_annot_stamp_type_t pdfi_annot_stamp_types[] = {
2020
    {"Approved", STAMP_GREEN, STAMP_1LINE("APPROVED", 13, 30)},
2021
    {"AsIs", STAMP_RED, STAMP_1LINE("AS IS", 13, 30)},
2022
    {"Confidential", STAMP_RED, STAMP_1LINE("CONFIDENTIAL", 17, 20)},
2023
    {"Departmental", STAMP_BLUE, STAMP_1LINE("DEPARTMENTAL", 17, 20)},
2024
    {"Draft", STAMP_RED, STAMP_1LINE("DRAFT", 13, 30)},
2025
    {"Experimental", STAMP_BLUE, STAMP_1LINE("EXPERIMENTAL", 17, 20)},
2026
    {"Expired", STAMP_RED, STAMP_1LINE("EXPIRED", 13, 30)},
2027
    {"Final", STAMP_RED, STAMP_1LINE("FINAL", 13, 30)},
2028
    {"ForComment", STAMP_GREEN, STAMP_1LINE("FOR COMMENT", 17, 20)},
2029
    {"ForPublicRelease", STAMP_GREEN, STAMP_2LINE("FOR PUBLIC",26,18,"RELEASE",8.5,18)},
2030
    {"NotApproved", STAMP_RED, STAMP_1LINE("NOT APPROVED", 17, 20)},
2031
    {"NotForPublicRelease", STAMP_RED, STAMP_2LINE("NOT FOR",26,18,"PUBLIC RELEASE",8.5,18)},
2032
    {"Sold", STAMP_BLUE, STAMP_1LINE("SOLD", 13, 30)},
2033
    {"TopSecret", STAMP_RED, STAMP_1LINE("TOP SECRET", 14, 26)},
2034
    {0}
2035
};
2036
/* Use "Draft" if not found, make sure this value is correct if above array changes */
2037
#define STAMP_DRAFT_INDEX 4
2038
2039
/* Draw the frame for the stamp.  This is taken straight form the PS code. */
2040
static int pdfi_annot_draw_stamp_frame(pdf_context *ctx)
2041
0
{
2042
0
    int code;
2043
2044
0
    code = gs_moveto(ctx->pgs, 6.0, 0.0);
2045
0
    if (code < 0) goto exit;
2046
0
    code = gs_arcto(ctx->pgs, 190, 0, 190, 6, 6, 0);
2047
0
    if (code < 0) goto exit;
2048
0
    code = gs_arcto(ctx->pgs, 190, 47, 184, 47, 6, 0);
2049
0
    if (code < 0) goto exit;
2050
0
    code = gs_arcto(ctx->pgs, 0, 47, 0, 41, 6, 0);
2051
0
    if (code < 0) goto exit;
2052
0
    code = gs_arcto(ctx->pgs, 0, 0, 6, 0, 6, 0);
2053
0
    if (code < 0) goto exit;
2054
0
    code = gs_closepath(ctx->pgs);
2055
0
    if (code < 0) goto exit;
2056
2057
0
    code = gs_moveto(ctx->pgs, 10, 4);
2058
0
    if (code < 0) goto exit;
2059
0
    code = gs_arcto(ctx->pgs, 185, 4, 185, 9, 5, 0);
2060
0
    if (code < 0) goto exit;
2061
0
    code = gs_arcto(ctx->pgs, 185, 43, 180, 43, 5, 0);
2062
0
    if (code < 0) goto exit;
2063
0
    code = gs_arcto(ctx->pgs, 5, 43, 5, 38, 5, 0);
2064
0
    if (code < 0) goto exit;
2065
0
    code = gs_arcto(ctx->pgs, 5, 4, 9, 4, 5, 0);
2066
0
    if (code < 0) goto exit;
2067
0
    code = gs_closepath(ctx->pgs);
2068
0
    if (code < 0) goto exit;
2069
0
    code = gs_eofill(ctx->pgs);
2070
0
    if (code < 0) goto exit;
2071
2072
0
 exit:
2073
0
    return code;
2074
0
}
2075
2076
/* draw text for stamp */
2077
static int pdfi_annot_draw_stamp_text(pdf_context *ctx, pdf_dict *annot, gs_rect *rect,
2078
                                      pdfi_annot_stamp_text_t *text)
2079
0
{
2080
0
    int code = 0;
2081
0
    int code1 = 0;
2082
0
    pdf_string *string = NULL;
2083
0
    gs_rect bbox;
2084
0
    gs_point awidth;
2085
0
    double x,y;
2086
2087
0
    if (!text->text)
2088
0
        return 0;
2089
2090
0
    code = pdfi_BT(ctx);
2091
0
    if (code < 0)
2092
0
        return code;
2093
2094
0
    code = pdfi_annot_set_font(ctx, "Times-Bold", text->h);
2095
0
    if (code < 0) goto exit;
2096
2097
0
    code = pdfi_obj_charstr_to_string(ctx, text->text, &string);
2098
0
    if (code < 0) goto exit;
2099
2100
2101
    /* At this point the graphics state is slightly rotated and current position
2102
     * is at the lower left corner of the stamp's box.
2103
     * The math here matches what the gs code does, so it's kind of confusing.
2104
     */
2105
    /* Get width of the string */
2106
0
    code = pdfi_string_bbox(ctx, string, &bbox, &awidth, false);
2107
0
    if (code < 0) goto exit;
2108
2109
    /* Calculate offset from corner (95 is hard-coded value based on size of the stamp I think) */
2110
0
    x = 95 - (bbox.q.x-bbox.p.x)/2; /* hard-coded value taken from gs code */
2111
0
    y = text->y;
2112
2113
0
    code = pdfi_gsave(ctx);
2114
0
    code = pdfi_gs_setgray(ctx, .75);
2115
0
    code = pdfi_annot_display_simple_text(ctx, annot, x+1, y-1, string);
2116
0
    if (code < 0) goto exit;
2117
0
    code = pdfi_grestore(ctx);
2118
2119
0
    code = pdfi_annot_display_simple_text(ctx, annot, x, y, string);
2120
0
    if (code < 0) goto exit;
2121
2122
0
 exit:
2123
0
    code1 = pdfi_ET(ctx);
2124
0
    if (code == 0) code = code1;
2125
0
    pdfi_countdown(string);
2126
0
    return 0;
2127
0
}
2128
2129
/* Generate appearance (see pdf_draw.ps/Stamp)
2130
 *
2131
 * If there was an AP it was already handled.
2132
 * For testing, see tests_private/pdf/PDF_1.7_FTS/fts_32_3204.pdf
2133
 */
2134
static int pdfi_annot_draw_Stamp(pdf_context *ctx, pdf_dict *annot, pdf_obj *NormAP, bool *render_done)
2135
29
{
2136
29
    int code = 0;
2137
29
    int code1 = 0;
2138
29
    gs_rect rect;
2139
29
    double width, height;
2140
29
    pdfi_annot_stamp_type_t *stamp_type;
2141
29
    pdf_name *Name = NULL;
2142
29
    double xscale, yscale;
2143
29
    double angle;
2144
29
    int i;
2145
2146
29
    code = pdfi_annot_start_transparency(ctx, annot);
2147
29
    if (code < 0) goto exit1;
2148
2149
29
    code = pdfi_annot_Rect(ctx, annot, &rect);
2150
29
    if (code < 0) goto exit;
2151
2152
23
    code = pdfi_dict_knownget_type(ctx, annot, "Name", PDF_NAME, (pdf_obj **)&Name);
2153
23
    if (code <= 0) goto exit;
2154
2155
    /* Translate to the center of Rect */
2156
23
    width = rect.q.x - rect.p.x;
2157
23
    height = rect.q.y - rect.p.y;
2158
23
    code = gs_translate(ctx->pgs, rect.p.x + width/2, rect.p.y + height/2);
2159
23
    if (code < 0) goto exit;
2160
2161
    /* This math comes from the PS code.  I assume the values are related to
2162
       the h and y values in the various Stamp type data.
2163
    */
2164
    /* Scale by the minimum of the two ratios, but make sure it's not 0 */
2165
23
    yscale = height / 50.;
2166
23
    xscale = width / 190.;
2167
23
    if (xscale < yscale)
2168
9
        yscale = xscale;
2169
23
    if (yscale <= 0.0)
2170
0
        yscale = 1.0;
2171
23
    code = gs_scale(ctx->pgs, yscale, yscale);
2172
23
    if (code < 0) goto exit;
2173
2174
    /* Search through types and find a match, if no match use Draft */
2175
345
    for (stamp_type = pdfi_annot_stamp_types; stamp_type->type; stamp_type ++) {
2176
322
        if (Name && pdfi_name_is(Name, stamp_type->type))
2177
0
            break;
2178
322
    }
2179
2180
    /* TODO: There are a bunch of Stamp Names built into AR that are not part of
2181
     * the spec.  Since we don't know about them, we will just display nothing.
2182
     * Example: the "Faces" stamps, such as FacesZippy
2183
     * See file tests_private/pdf/uploads/annots-noAP.pdf
2184
     */
2185
23
    if (!stamp_type->type) {
2186
23
        pdfi_set_warning(ctx, 0, NULL, W_PDF_ANNOT_ERROR, "pdfi_annot_draw_Stamp", "WARNING: Annotation: No AP, unknown Stamp Name, omitting");
2187
23
        code = 0;
2188
23
        goto exit;
2189
23
    }
2190
2191
    /* Draw the frame */
2192
0
    code = pdfi_gs_setrgbcolor(ctx, stamp_type->rgb.r, stamp_type->rgb.g,
2193
0
                               stamp_type->rgb.b);
2194
0
    if (code < 0) goto exit;
2195
2196
0
    code = gs_translate(ctx->pgs, -95, -25);
2197
0
    if (code < 0) goto exit;
2198
0
    code = gs_atan2_degrees(2.0, 190.0, &angle);
2199
0
    if (code < 0) goto exit;
2200
0
    code = gs_rotate(ctx->pgs, angle);
2201
0
    if (code < 0) goto exit;
2202
2203
    /* Draw frame in gray */
2204
0
    code = pdfi_gsave(ctx);
2205
0
    code = gs_translate(ctx->pgs, 1, -1);
2206
0
    code = pdfi_gs_setgray(ctx, 0.75);
2207
0
    code = pdfi_annot_draw_stamp_frame(ctx);
2208
0
    code = pdfi_grestore(ctx);
2209
2210
    /* Draw frame colored */
2211
0
    code = pdfi_annot_draw_stamp_frame(ctx);
2212
2213
    /* Draw the text */
2214
0
    for (i=0; i<2; i++) {
2215
0
        code = pdfi_annot_draw_stamp_text(ctx, annot, &rect, &stamp_type->text[i]);
2216
0
        if (code < 0) goto exit;
2217
0
    }
2218
2219
29
 exit:
2220
29
    code1 = pdfi_annot_end_transparency(ctx, annot);
2221
29
    if (code >= 0)
2222
23
        code = code1;
2223
29
 exit1:
2224
29
    pdfi_countdown(Name);
2225
29
    *render_done = true;
2226
29
    return code;
2227
29
}
2228
/*********** END /Stamp ***************/
2229
2230
2231
/* Draw Callout Line (CL) */
2232
static int pdfi_annot_draw_CL(pdf_context *ctx, pdf_dict *annot)
2233
5
{
2234
5
    int code;
2235
5
    pdf_array *CL = NULL;
2236
5
    double array[6];
2237
5
    int length;
2238
2239
5
    code = pdfi_dict_knownget_type(ctx, annot, "CL", PDF_ARRAY, (pdf_obj **)&CL);
2240
5
    if (code <= 0) goto exit;
2241
2242
0
    length = pdfi_array_size(CL);
2243
2244
0
    if (length != 4 && length != 6) {
2245
0
        code = gs_note_error(gs_error_syntaxerror);
2246
0
        goto exit;
2247
0
    }
2248
2249
0
    code = pdfi_array_to_num_array(ctx, CL, array, 0, length);
2250
0
    if (code < 0) goto exit;
2251
2252
    /* Draw the line */
2253
0
    code = gs_moveto(ctx->pgs, array[0], array[1]);
2254
0
    if (code < 0) goto exit;
2255
0
    code = gs_lineto(ctx->pgs, array[2], array[3]);
2256
0
    if (code < 0) goto exit;
2257
0
    if (length == 6) {
2258
0
        code = gs_lineto(ctx->pgs, array[4], array[5]);
2259
0
        if (code < 0) goto exit;
2260
0
    }
2261
0
    code = gs_stroke(ctx->pgs);
2262
2263
    /* Line ending
2264
     * NOTE: This renders a different arrow than the gs code, but I used the
2265
     * same LE code I used elsewhere, which is clearly better.  So there will be diffs...
2266
     */
2267
0
    code = pdfi_annot_draw_LE(ctx, annot, array[0], array[1], array[2], array[3], 1);
2268
0
    if (code < 0) goto exit;
2269
2270
5
 exit:
2271
5
    pdfi_countdown(CL);
2272
5
    return code;
2273
0
}
2274
2275
/* FreeText -- Draw text with border around it.
2276
 *
2277
 * See pdf_draw.ps/FreeText
2278
 * If there was an AP it was already handled
2279
 */
2280
static int pdfi_annot_draw_FreeText(pdf_context *ctx, pdf_dict *annot, pdf_obj *NormAP, bool *render_done)
2281
5
{
2282
5
    int code = 0;
2283
5
    int code1 = 0;
2284
5
    bool drawbackground;
2285
5
    pdf_dict *BS = NULL;
2286
5
    pdf_string *Contents = NULL;
2287
5
    gs_rect annotrect, modrect;
2288
5
    int64_t Rotate;
2289
2290
5
    *render_done = false;
2291
2292
5
    code = pdfi_annot_start_transparency(ctx, annot);
2293
5
    if (code < 0) goto exit1;
2294
2295
5
    code = pdfi_annot_opacity(ctx, annot);
2296
5
    if (code < 0) goto exit;
2297
2298
5
    code = pdfi_annot_Rect(ctx, annot, &annotrect);
2299
5
    if (code < 0) goto exit;
2300
2301
    /* Set the (background?) color if applicable */
2302
5
    code = pdfi_annot_setcolor(ctx, annot, false, &drawbackground);
2303
5
    if (code < 0) goto exit;
2304
2305
    /* Only draw rectangle if a color was specified */
2306
5
    if (drawbackground) {
2307
0
        code = pdfi_annot_fillRect(ctx, annot);
2308
0
        if (code < 0) goto exit;
2309
0
    }
2310
2311
    /* Set DA (Default Appearance)
2312
     * This will generally set a color and font.
2313
     *
2314
     * TODO: Unclear if this is supposed to also determine the color
2315
     * of the border box, but it seems like it does in gs, so we set the DA
2316
     * before drawing the border, like gs does.
2317
     */
2318
5
    code = pdfi_annot_process_DA(ctx, NULL, annot, &annotrect, false);
2319
5
    if (code < 0) goto exit;
2320
2321
    /* Draw border around text */
2322
    /* TODO: gs-compatible implementation is commented out.  Would rather just delete it... */
2323
5
#if 1
2324
    /* TODO: Prefer to do it this way! */
2325
5
    code = pdfi_annot_draw_border(ctx, annot, false);
2326
5
    if (code < 0) goto exit;
2327
#else
2328
    /* NOTE: I would really like to just call pdfi_annot_draw_border()
2329
     * without checking for BS, but the implementation in gs is subtly different (see below)
2330
     * and I want to make it possible to bmpcmp.
2331
     */
2332
    code = pdfi_dict_knownget_type(ctx, annot, "BS", PDF_DICT, (pdf_obj **)&BS);
2333
    if (code < 0) goto exit;
2334
    if (BS) {
2335
        code = pdfi_annot_draw_border(ctx, annot, false);
2336
        if (code < 0) goto exit;
2337
    } else {
2338
        gs_rect rect;
2339
2340
        /* Draw our own border */
2341
        code = pdfi_gs_setgray(ctx, 0);
2342
        if (code < 0) goto exit;
2343
2344
        /* NOTE: This is almost identical to pdfi_annot_strokeborder() with a width=1.0
2345
         * except it adjusts the rectangle by 1.0 instead of 0.5.
2346
         * Should probably just call that function, but I want to match gs implementation
2347
         * exactly for bmpcmp purposes.
2348
         */
2349
        code = gs_setlinewidth(ctx->pgs, 1);
2350
        if (code < 0) goto exit;
2351
2352
        code = pdfi_annot_Rect(ctx, annot, &rect);
2353
        if (code < 0) goto exit;
2354
2355
        pdfi_annot_rect_adjust(ctx, &rect, 1);
2356
        code = gs_rectstroke(ctx->pgs, &rect, 1, NULL);
2357
        if (code < 0) goto exit;
2358
    }
2359
#endif
2360
2361
5
    code = pdfi_annot_draw_CL(ctx, annot);
2362
5
    if (code < 0) goto exit;
2363
2364
    /* Modify rect by RD if applicable */
2365
5
    code = pdfi_annot_applyRD(ctx, annot, &annotrect);
2366
5
    if (code < 0) goto exit;
2367
2368
    /* /Rotate */
2369
5
    code = pdfi_dict_get_int_def(ctx, annot, "Rotate", &Rotate, 0);
2370
5
    if (code < 0) goto exit;
2371
2372
5
    modrect = annotrect; /* structure copy */
2373
    /* TODO: I think this can all be done in a generic way using gs_transform() but it
2374
     * makes my head explode...
2375
     */
2376
5
    switch(Rotate) {
2377
0
    case 270:
2378
0
        code = gs_moveto(ctx->pgs, modrect.q.y, modrect.q.x);
2379
0
        if (code < 0) goto exit;
2380
0
        code = gs_rotate(ctx->pgs, 270.0);
2381
0
        modrect.p.x = -annotrect.q.y;
2382
0
        modrect.q.x = -annotrect.p.y;
2383
0
        modrect.p.y = annotrect.p.x;
2384
0
        modrect.q.y = annotrect.q.x;
2385
0
        break;
2386
0
    case 180:
2387
0
        code = gs_moveto(ctx->pgs, modrect.q.x, modrect.p.y);
2388
0
        if (code < 0) goto exit;
2389
0
        code = gs_rotate(ctx->pgs, 180.0);
2390
0
        modrect.p.x = -annotrect.q.x;
2391
0
        modrect.q.x = -annotrect.p.x;
2392
0
        modrect.p.y = -annotrect.q.y;
2393
0
        modrect.q.y = -annotrect.p.y;
2394
0
        break;
2395
0
        break;
2396
0
    case 90:
2397
0
        code = gs_moveto(ctx->pgs, modrect.p.y, modrect.p.x);
2398
0
        if (code < 0) goto exit;
2399
0
        code = gs_rotate(ctx->pgs, 90.0);
2400
0
        modrect.p.x = annotrect.p.y;
2401
0
        modrect.q.x = annotrect.q.y;
2402
0
        modrect.p.y = -annotrect.q.x;
2403
0
        modrect.q.y = -annotrect.p.x;
2404
0
        break;
2405
5
    case 0:
2406
5
    default:
2407
5
        modrect.p.x += 2;
2408
5
        modrect.p.y += 2;
2409
5
        modrect.q.x -= 2;
2410
5
        modrect.q.y -= 2;
2411
2412
        /* Move to initial position (slightly offset from the corner of the rect) */
2413
5
        code = gs_moveto(ctx->pgs, modrect.p.x, modrect.q.y);
2414
5
        if (code < 0) goto exit;
2415
5
        break;
2416
5
    }
2417
2418
    /* /Contents */
2419
5
    code = pdfi_dict_knownget_type(ctx, annot, "Contents", PDF_STRING, (pdf_obj **)&Contents);
2420
5
    if (code < 0) goto exit;
2421
5
    if (code > 0) {
2422
3
        code = pdfi_annot_display_formatted_text(ctx, annot, &modrect, Contents, false);
2423
3
        if (code < 0) goto exit;
2424
3
    }
2425
2426
5
 exit:
2427
5
    code1 = pdfi_annot_end_transparency(ctx, annot);
2428
5
    if (code >= 0)
2429
5
        code = code1;
2430
5
 exit1:
2431
5
    *render_done = true;
2432
5
    pdfi_countdown(BS);
2433
5
    pdfi_countdown(Contents);
2434
5
    return code;
2435
5
}
2436
2437
/* Generate appearance (see pdf_draw.ps/Text)
2438
 * This draws the default "Note" thingy which looks like a little page.
2439
 * TODO: Spec lists a whole bunch of different /Name with different appearances that we don't handle.
2440
 * See page 1 of tests_private/pdf/sumatra/annotations_without_appearance_streams.pdf
2441
 *
2442
 * If there was an AP it was already handled.
2443
 */
2444
static int pdfi_annot_draw_Text(pdf_context *ctx, pdf_dict *annot, pdf_obj *NormAP, bool *render_done)
2445
8
{
2446
8
    int code = 0;
2447
8
    int code1 = 0;
2448
8
    gs_rect rect;
2449
2450
8
    code = pdfi_annot_start_transparency(ctx, annot);
2451
8
    if (code < 0) goto exit1;
2452
2453
7
    code = pdfi_annot_Rect(ctx, annot, &rect);
2454
7
    if (code < 0) goto exit;
2455
7
    code = gs_translate(ctx->pgs, rect.p.x, rect.p.y);
2456
7
    if (code < 0) goto exit;
2457
2458
    /* Draw a page icon (/Note) */
2459
    /* TODO: All the other /Name appearances */
2460
7
    code = gs_translate(ctx->pgs, 0.5, (rect.q.y-rect.p.y)-18.5);
2461
7
    if (code < 0) goto exit;
2462
7
    code = gs_setlinewidth(ctx->pgs, 1.0);
2463
7
    if (code < 0) goto exit;
2464
7
    code = pdfi_gs_setgray(ctx, 0.75);
2465
7
    if (code < 0) goto exit;
2466
7
    code = gs_moveto(ctx->pgs, 0.5, -1);
2467
7
    if (code < 0) goto exit;
2468
7
    code = gs_lineto(ctx->pgs, 10, -1);
2469
7
    if (code < 0) goto exit;
2470
7
    code = gs_lineto(ctx->pgs, 15, 4);
2471
7
    if (code < 0) goto exit;
2472
7
    code = gs_lineto(ctx->pgs, 15, 17.5);
2473
7
    if (code < 0) goto exit;
2474
7
    code = gs_stroke(ctx->pgs);
2475
7
    if (code < 0) goto exit;
2476
2477
7
    code = gs_moveto(ctx->pgs, 0, 0);
2478
7
    if (code < 0) goto exit;
2479
7
    code = gs_lineto(ctx->pgs, 9, 0);
2480
7
    if (code < 0) goto exit;
2481
7
    code = gs_lineto(ctx->pgs, 14, 5);
2482
7
    if (code < 0) goto exit;
2483
7
    code = gs_lineto(ctx->pgs, 14, 18);
2484
7
    if (code < 0) goto exit;
2485
7
    code = gs_lineto(ctx->pgs, 0, 18);
2486
7
    if (code < 0) goto exit;
2487
7
    code = gs_closepath(ctx->pgs);
2488
7
    if (code < 0) goto exit;
2489
2490
7
    code = pdfi_gsave(ctx);
2491
7
    if (code >= 0) {
2492
7
        code = pdfi_gs_setgray(ctx, 0.5);
2493
7
        code = gs_fill(ctx->pgs);
2494
7
        code = pdfi_grestore(ctx);
2495
7
    } else
2496
0
        goto exit;
2497
2498
7
    code = pdfi_gs_setgray(ctx, 0);
2499
7
    if (code < 0) goto exit;
2500
7
    code = gs_stroke(ctx->pgs);
2501
7
    if (code < 0) goto exit;
2502
2503
7
    code = gs_moveto(ctx->pgs, 3, 8);
2504
7
    if (code < 0) goto exit;
2505
7
    code = gs_lineto(ctx->pgs, 7.5, 8);
2506
7
    if (code < 0) goto exit;
2507
7
    code = gs_moveto(ctx->pgs, 3, 11);
2508
7
    if (code < 0) goto exit;
2509
7
    code = gs_lineto(ctx->pgs, 10, 11);
2510
7
    if (code < 0) goto exit;
2511
7
    code = gs_moveto(ctx->pgs, 3, 14);
2512
7
    if (code < 0) goto exit;
2513
7
    code = gs_lineto(ctx->pgs, 10, 14);
2514
7
    if (code < 0) goto exit;
2515
7
    code = gs_moveto(ctx->pgs, 9, 0);
2516
7
    if (code < 0) goto exit;
2517
7
    code = gs_lineto(ctx->pgs, 9, 5);
2518
7
    if (code < 0) goto exit;
2519
7
    code = gs_lineto(ctx->pgs, 14, 5);
2520
7
    if (code < 0) goto exit;
2521
7
    code = gs_stroke(ctx->pgs);
2522
7
    if (code < 0) goto exit;
2523
2524
7
 exit:
2525
7
    code1 = pdfi_annot_end_transparency(ctx, annot);
2526
7
    if (code >= 0)
2527
7
        code = code1;
2528
8
 exit1:
2529
8
    *render_done = true;
2530
8
    return code;
2531
7
}
2532
2533
/* Converts array of 4 points to a basis and 2 dimensions (6 values altogether)
2534
 *    x0 y0 x1 y1 x2 y2 x3 y3 -> x0 y0 x1-x0 y1-y0 x2-x0 y2-y0
2535
 *
2536
 *  ^
2537
 *  |
2538
 *  * (x2,y2)    * (x3,y3)
2539
 *  |
2540
 *  |
2541
 *  *------------*->
2542
 *  (x0,y0)      (x1,y1)
2543
 */
2544
static void pdfi_annot_quadpoints2basis(pdf_context *ctx, double *array,
2545
                                        double *px0, double *py0,
2546
                                        double *dx1, double *dy1,
2547
                                        double *dx2, double *dy2)
2548
1.22k
{
2549
1.22k
    double x0,x1,x2,x3,y0,y1,y2,y3;
2550
1.22k
    double minx, miny;
2551
1.22k
    int i, mindex;
2552
2553
    /* comment from the PS code
2554
    % The text is oriented with respect to the vertex with the smallest
2555
    % y value (or the leftmost of those, if there are two such vertices)
2556
    % (x0, y0) and the next vertex in a counterclockwise direction
2557
    % (x1, y1), regardless of whether these are the first two points in
2558
    % the QuadPoints array.
2559
    */
2560
2561
    /* starting min point */
2562
1.22k
    minx = array[0];
2563
1.22k
    miny = array[1];
2564
1.22k
    mindex = 0;
2565
    /* This finds the index of the point with miny and if there were two points with same
2566
     * miny, it finds the one with minx
2567
     */
2568
4.89k
    for (i=2; i<8; i+=2) {
2569
3.66k
        if ((array[i+1] == miny && array[i] < minx) ||  (array[i+1] < miny)) {
2570
            /* Set new min point */
2571
105
            miny = array[i+1];
2572
105
            minx = array[i];
2573
105
            mindex = i;
2574
105
        }
2575
3.66k
    }
2576
2577
    /* Pull out the points such that x0 = minx, y0 = miny, etc */
2578
1.22k
    i = mindex;
2579
1.22k
    x0 = array[i];
2580
1.22k
    y0 = array[i+1];
2581
1.22k
    i += 2;
2582
1.22k
    if (i == 8) i = 0;
2583
1.22k
    x1 = array[i];
2584
1.22k
    y1 = array[i+1];
2585
1.22k
    i += 2;
2586
1.22k
    if (i == 8) i = 0;
2587
1.22k
    x2 = array[i];
2588
1.22k
    y2 = array[i+1];
2589
1.22k
    i += 2;
2590
1.22k
    if (i == 8) i = 0;
2591
1.22k
    x3 = array[i];
2592
1.22k
    y3 = array[i+1];
2593
2594
    /* Make it go counterclockwise by picking lower of these 2 points */
2595
1.22k
    if (y3 < y1) {
2596
10
        y1 = y3;
2597
10
        x1 = x3;
2598
10
    }
2599
2600
    /* Convert into a starting point and two sets of lengths */
2601
1.22k
    *px0 = x0;
2602
1.22k
    *py0 = y0;
2603
1.22k
    *dx1 = x1 - x0;
2604
1.22k
    *dy1 = y1 - y0;
2605
1.22k
    *dx2 = x2 - x0;
2606
1.22k
    *dy2 = y2 - y0;
2607
1.22k
}
2608
2609
/* Generate appearance for Underline or StrikeOut (see pdf_draw.ps/Underline and Strikeout)
2610
 *
2611
 * offset -- how far above the QuadPoints box bottom to draw the line
2612
 *
2613
 */
2614
static int pdfi_annot_draw_line_offset(pdf_context *ctx, pdf_dict *annot, double offset)
2615
108
{
2616
108
    int code = 0;
2617
108
    bool drawit;
2618
108
    pdf_array *QuadPoints = NULL;
2619
108
    double array[8];
2620
108
    int size;
2621
108
    int num_quads;
2622
108
    int i;
2623
108
    double x0, y0, dx1, dy1, dx2, dy2;
2624
108
    double linewidth;
2625
2626
108
    code = pdfi_annot_setcolor(ctx, annot, false, &drawit);
2627
108
    if (code <0 || !drawit)
2628
2
        goto exit;
2629
2630
106
    code = pdfi_dict_knownget_type(ctx, annot, "QuadPoints", PDF_ARRAY, (pdf_obj **)&QuadPoints);
2631
106
    if (code <= 0) goto exit;
2632
2633
106
    size = pdfi_array_size(QuadPoints);
2634
106
    num_quads = size / 8;
2635
2636
1.29k
    for (i=0; i<num_quads; i++) {
2637
1.18k
        code = pdfi_array_to_num_array(ctx, QuadPoints, array, i*8, 8);
2638
1.18k
        if (code < 0) goto exit;
2639
2640
1.18k
        pdfi_annot_quadpoints2basis(ctx, array, &x0, &y0, &dx1, &dy1, &dx2, &dy2);
2641
2642
        /* Acrobat draws the line at offset-ratio of the box width from the bottom of the box
2643
         * and 1/16 thick of the box width.  /Rect is ignored.
2644
         */
2645
1.18k
        linewidth = sqrt((dx2*dx2) + (dy2*dy2)) / 16.;
2646
1.18k
        code = gs_setlinewidth(ctx->pgs, linewidth);
2647
1.18k
        if (code < 0) goto exit;
2648
1.18k
        code = gs_moveto(ctx->pgs, dx2*offset + x0 , dy2*offset + y0);
2649
1.18k
        if (code < 0) goto exit;
2650
1.18k
        code = gs_lineto(ctx->pgs, dx2*offset + x0 + dx1, dy2*offset + y0 + dy1);
2651
1.18k
        if (code < 0) goto exit;
2652
1.18k
        code = gs_stroke(ctx->pgs);
2653
1.18k
        if (code < 0) goto exit;
2654
1.18k
    }
2655
2656
108
 exit:
2657
108
    pdfi_countdown(QuadPoints);
2658
108
    return code;
2659
106
}
2660
2661
/* Generate appearance (see pdf_draw.ps/StrikeOut)
2662
 *
2663
 * If there was an AP it was already handled.
2664
 */
2665
static int pdfi_annot_draw_StrikeOut(pdf_context *ctx, pdf_dict *annot, pdf_obj *NormAP, bool *render_done)
2666
91
{
2667
91
    *render_done = true;
2668
91
    return pdfi_annot_draw_line_offset(ctx, annot, 3/7.);
2669
91
}
2670
2671
/* Generate appearance (see pdf_draw.ps/Underline)
2672
 *
2673
 * If there was an AP it was already handled.
2674
 */
2675
static int pdfi_annot_draw_Underline(pdf_context *ctx, pdf_dict *annot, pdf_obj *NormAP, bool *render_done)
2676
17
{
2677
17
    *render_done = true;
2678
17
    return pdfi_annot_draw_line_offset(ctx, annot, 1/7.);
2679
17
}
2680
2681
/* Connect 2 points with an arc that has max distance from the line segment to the arc
2682
 * equal to 1/4 of the radius.
2683
 */
2684
static int pdfi_annot_highlight_arc(pdf_context *ctx, double x0, double y0,
2685
                                    double x1, double y1)
2686
1.33k
{
2687
1.33k
    int code = 0;
2688
1.33k
    double dx, dy;
2689
1.33k
    double xc, yc, r, a1, a2;
2690
2691
1.33k
    dx = x1 - x0;
2692
1.33k
    dy = y1 - y0;
2693
2694
1.33k
    yc = (y1+y0)/2. - 15./16.*dx;
2695
1.33k
    xc = (x1+x0)/2. + 15./16.*dy;
2696
1.33k
    r = sqrt((y1-yc)*(y1-yc) + (x1-xc)*(x1-xc));
2697
1.33k
    code = gs_atan2_degrees(y1-yc, x1-xc, &a1);
2698
1.33k
    if (code < 0)
2699
4
        a1 = 0;
2700
1.33k
    code = gs_atan2_degrees(y0-yc, x0-xc, &a2);
2701
1.33k
    if (code < 0)
2702
4
        a2 = 0;
2703
1.33k
    code = gs_arcn(ctx->pgs, xc, yc, r, a2, a1);
2704
2705
1.33k
    return code;
2706
1.33k
}
2707
2708
/* Generate appearance (see pdf_draw.ps/Highlight)
2709
 *
2710
 * If there was an AP it was already handled.
2711
 */
2712
static int pdfi_annot_draw_Highlight(pdf_context *ctx, pdf_dict *annot, pdf_obj *NormAP, bool *render_done)
2713
122
{
2714
122
    int code = 0;
2715
122
    bool drawit;
2716
122
    pdf_array *QuadPoints = NULL;
2717
122
    double array[8];
2718
122
    int size;
2719
122
    int num_quads;
2720
122
    int i;
2721
2722
122
    code = pdfi_annot_setcolor(ctx, annot, false, &drawit);
2723
122
    if (code <0 || !drawit)
2724
0
        goto exit;
2725
2726
122
    code = gs_setlinecap(ctx->pgs, 1);
2727
122
    if (code < 0) goto exit;
2728
2729
122
    code = pdfi_dict_knownget_type(ctx, annot, "QuadPoints", PDF_ARRAY, (pdf_obj **)&QuadPoints);
2730
122
    if (code <= 0) goto exit;
2731
2732
122
    size = pdfi_array_size(QuadPoints);
2733
122
    num_quads = size / 8;
2734
2735
785
    for (i=0; i<num_quads; i++) {
2736
672
        code = pdfi_array_to_num_array(ctx, QuadPoints, array, i*8, 8);
2737
672
        if (code < 0) goto exit;
2738
2739
672
        code = gs_moveto(ctx->pgs, array[2], array[3]);
2740
672
        if (code < 0) goto exit;
2741
2742
672
        code = pdfi_annot_highlight_arc(ctx, array[2], array[3], array[6], array[7]);
2743
672
        if (code < 0) goto exit;
2744
2745
665
        code = gs_lineto(ctx->pgs, array[4], array[5]);
2746
665
        if (code < 0) goto exit;
2747
2748
665
        code = pdfi_annot_highlight_arc(ctx, array[4], array[5], array[0], array[1]);
2749
665
        if (code < 0) goto exit;
2750
2751
663
        code = gs_closepath(ctx->pgs);
2752
663
        if (code < 0) goto exit;
2753
2754
663
        if (ctx->page.has_transparency) {
2755
663
            code = pdfi_trans_begin_simple_group(ctx, NULL, false, false, false);
2756
663
            if (code < 0) goto exit;
2757
2758
663
            code = gs_setblendmode(ctx->pgs, BLEND_MODE_Multiply);
2759
663
            if (code < 0) {
2760
0
                (void)pdfi_trans_end_simple_group(ctx);
2761
0
                goto exit;
2762
0
            }
2763
663
            code = gs_fill(ctx->pgs);
2764
663
            (void)pdfi_trans_end_simple_group(ctx);
2765
663
            if (code < 0) goto exit;
2766
663
        } else {
2767
0
            code = gs_stroke(ctx->pgs);
2768
0
            if (code < 0) goto exit;
2769
2770
0
            code = gs_newpath(ctx->pgs);
2771
0
            if (code < 0) goto exit;
2772
0
        }
2773
663
    }
2774
2775
122
 exit:
2776
122
    pdfi_countdown(QuadPoints);
2777
122
    return code;
2778
122
}
2779
2780
/* Generate appearance (see pdf_draw.ps/Squiggly)
2781
 *
2782
 * If there was an AP it was already handled.
2783
 */
2784
static int pdfi_annot_draw_Squiggly(pdf_context *ctx, pdf_dict *annot, pdf_obj *NormAP, bool *render_done)
2785
14
{
2786
14
    int code = 0;
2787
14
    bool drawit;
2788
14
    pdf_array *QuadPoints = NULL;
2789
14
    double array[8];
2790
14
    int size;
2791
14
    int num_quads;
2792
14
    int i;
2793
14
    double x0, y0, dx1, dy1, dx2, dy2;
2794
14
    double p1, p2, p12;
2795
14
    int count;
2796
14
    bool need_grestore = false;
2797
14
    gs_matrix matrix;
2798
2799
14
    code = pdfi_annot_setcolor(ctx, annot, false, &drawit);
2800
14
    if (code <0 || !drawit)
2801
0
        goto exit;
2802
2803
14
    code = gs_setlinecap(ctx->pgs, gs_cap_round);
2804
14
    if (code < 0) goto exit;
2805
14
    code = gs_setlinejoin(ctx->pgs, gs_join_round);
2806
14
    if (code < 0) goto exit;
2807
14
    code = gs_setlinewidth(ctx->pgs, 1.0);
2808
14
    if (code < 0) goto exit;
2809
2810
14
    code = pdfi_dict_knownget_type(ctx, annot, "QuadPoints", PDF_ARRAY, (pdf_obj **)&QuadPoints);
2811
14
    if (code <= 0) goto exit;
2812
2813
14
    size = pdfi_array_size(QuadPoints);
2814
14
    num_quads = size / 8;
2815
2816
49
    for (i=0; i<num_quads; i++) {
2817
35
        code = pdfi_array_to_num_array(ctx, QuadPoints, array, i*8, 8);
2818
35
        if (code < 0) goto exit;
2819
2820
35
        code = pdfi_gsave(ctx);
2821
35
        if (code < 0) goto exit;
2822
35
        need_grestore = true;
2823
2824
        /* Make clipping region */
2825
35
        code = gs_moveto(ctx->pgs, array[6], array[7]);
2826
35
        if (code < 0) goto exit;
2827
35
        code = gs_lineto(ctx->pgs, array[4], array[5]);
2828
35
        if (code < 0) goto exit;
2829
35
        code = gs_lineto(ctx->pgs, array[0], array[1]);
2830
35
        if (code < 0) goto exit;
2831
35
        code = gs_lineto(ctx->pgs, array[2], array[3]);
2832
35
        if (code < 0) goto exit;
2833
35
        code = gs_closepath(ctx->pgs);
2834
35
        if (code < 0) goto exit;
2835
35
        code = gs_clip(ctx->pgs);
2836
35
        if (code < 0) goto exit;
2837
35
        code = gs_newpath(ctx->pgs);
2838
35
        if (code < 0) goto exit;
2839
2840
35
        pdfi_annot_quadpoints2basis(ctx, array, &x0, &y0, &dx1, &dy1, &dx2, &dy2);
2841
2842
35
        code = gs_translate(ctx->pgs, x0+dx2/56+dx2/72, y0+dy2/56+dy2/72);
2843
35
        if (code < 0) goto exit;
2844
2845
35
        p2 = sqrt(dx2*dx2 + dy2*dy2);
2846
35
        p1 = sqrt(dx1*dx1 + dy1*dy1);
2847
2848
35
        if (p2 > 0 && p1 > 0) {
2849
35
            p12 = p2 / p1;
2850
2851
35
            count = (int)((1/p12) * 4 + 1);
2852
2853
35
            matrix.xx = dx1 * p12;
2854
35
            matrix.xy = dy1 * p12;
2855
35
            matrix.yx = dx2;
2856
35
            matrix.yy = dy2;
2857
35
            matrix.tx = 0.0;
2858
35
            matrix.ty = 0.0;
2859
35
            code = gs_concat(ctx->pgs, &matrix);
2860
35
            if (code < 0) goto exit;
2861
2862
35
            code = gs_scale(ctx->pgs, 1/40., 1/72.);
2863
35
            if (code < 0) goto exit;
2864
2865
35
            code = gs_moveto(ctx->pgs, 0, 0);
2866
35
            if (code < 0) goto exit;
2867
2868
4.31k
            while (count >= 0) {
2869
4.27k
                code = gs_lineto(ctx->pgs, 5, 10);
2870
4.27k
                if (code < 0) goto exit;
2871
4.27k
                code = gs_lineto(ctx->pgs, 10, 0);
2872
4.27k
                if (code < 0) goto exit;
2873
4.27k
                code = gs_translate(ctx->pgs, 10, 0);
2874
4.27k
                if (code < 0) goto exit;
2875
2876
4.27k
                count --;
2877
4.27k
            }
2878
35
            code = gs_stroke(ctx->pgs);
2879
35
            if (code < 0) goto exit;
2880
35
        }
2881
2882
35
        need_grestore = false;
2883
35
        code = pdfi_grestore(ctx);
2884
35
        if (code < 0) goto exit;
2885
35
    }
2886
2887
14
 exit:
2888
14
    if (need_grestore)
2889
0
        (void)pdfi_grestore(ctx);
2890
14
    pdfi_countdown(QuadPoints);
2891
14
    *render_done = true;
2892
14
    return code;
2893
14
}
2894
2895
/* Generate appearance (see pdf_draw.ps/Redact)
2896
 *
2897
 * If there was an AP it was already handled.
2898
 */
2899
static int pdfi_annot_draw_Redact(pdf_context *ctx, pdf_dict *annot, pdf_obj *NormAP, bool *render_done)
2900
0
{
2901
    /* comment from PS code:
2902
    %% Redact annotations are part of a process, a Redact annotation is only present
2903
    %% until the content is removed, before that the content should be present and
2904
    %% I believe we should print it. So take no action for Redact annotations if they
2905
    %% have no appearance.
2906
    */
2907
    /* Render nothing, don't print warning */
2908
0
    *render_done = true;
2909
0
    return 0;
2910
0
}
2911
2912
/* Handle PopUp (see pdf_draw.ps/Popup)
2913
 * Renders only if /Open=true
2914
 *
2915
 * If there's an AP, caller will handle it on return
2916
 */
2917
static int pdfi_annot_draw_Popup(pdf_context *ctx, pdf_dict *annot, pdf_obj *NormAP, bool *render_done)
2918
1.60k
{
2919
1.60k
    int code = 0, code1 = 0;
2920
1.60k
    bool Open = false;
2921
1.60k
    pdf_dict *Parent = NULL;
2922
1.60k
    pdf_string *Contents = NULL;
2923
1.60k
    pdf_string *T = NULL;
2924
1.60k
    bool has_color;
2925
1.60k
    gs_rect rect, rect2;
2926
1.60k
    bool need_grestore = false;
2927
1.60k
    double x, y;
2928
2929
    /* Render only if open */
2930
1.60k
    code = pdfi_dict_get_bool(ctx, annot, "Open", &Open);
2931
1.60k
    if (code < 0 && (code != gs_error_undefined))
2932
0
        goto exit1;
2933
2934
1.60k
    code = 0;
2935
2936
    /* Don't render if not Open */
2937
1.60k
    if (!Open) {
2938
1.57k
        *render_done = true;
2939
1.57k
        goto exit1;
2940
1.57k
    }
2941
2942
    /* Let caller render if there is an AP */
2943
30
    if (NormAP) {
2944
0
        *render_done = false;
2945
0
        goto exit1;
2946
0
    }
2947
2948
    /* regardless what happens next, tell caller we rendered it */
2949
30
    *render_done = true;
2950
2951
30
    code = pdfi_annot_start_transparency(ctx, annot);
2952
30
    if (code < 0) goto exit1;
2953
2954
30
    code = gs_setlinewidth(ctx->pgs, 0.05);
2955
2956
    /* Use Parent to get color */
2957
30
    code = pdfi_dict_knownget_type(ctx, annot, "Parent", PDF_DICT, (pdf_obj **)&Parent);
2958
30
    if (code < 0) goto exit;
2959
30
    if (code == 0) {
2960
0
        code = pdfi_dict_knownget_type(ctx, annot, "P", PDF_DICT, (pdf_obj **)&Parent);
2961
0
        if (code < 0) goto exit;
2962
0
    }
2963
30
    if (code == 0) {
2964
        /* If no parent, we will use the annotation itself */
2965
0
        Parent = annot;
2966
0
        pdfi_countup(Parent);
2967
0
    }
2968
2969
    /* Set color if there is one specified */
2970
30
    code = pdfi_annot_setcolor(ctx, Parent, false, &has_color);
2971
30
    if (code < 0) goto exit;
2972
2973
    /* Set a default color if nothing specified */
2974
30
    if (!has_color) {
2975
0
        code = pdfi_gs_setrgbcolor(ctx, 1.0, 1.0, 0);
2976
0
        if (code < 0) goto exit;
2977
0
    }
2978
2979
30
    code = pdfi_annot_Rect(ctx, annot, &rect);
2980
30
    if (code < 0) goto exit;
2981
2982
    /* Draw big box (the frame around the /Contents) */
2983
30
    code = pdfi_gsave(ctx);
2984
30
    if (code < 0) goto exit;
2985
30
    need_grestore = true;
2986
30
    code = pdfi_gs_setgray(ctx, 1);
2987
30
    if (code < 0) goto exit;
2988
30
    code = gs_rectfill(ctx->pgs, &rect, 1);
2989
30
    if (code < 0) goto exit;
2990
30
    code = pdfi_gs_setgray(ctx, 0);
2991
30
    if (code < 0) goto exit;
2992
30
    code = gs_rectstroke(ctx->pgs, &rect, 1, NULL);
2993
30
    if (code < 0) goto exit;
2994
30
    code = pdfi_grestore(ctx);
2995
30
    need_grestore = false;
2996
30
    if (code < 0) goto exit;
2997
2998
    /* Display /Contents in Helvetica */
2999
30
    code = pdfi_dict_knownget_type(ctx, Parent, "Contents", PDF_STRING, (pdf_obj **)&Contents);
3000
30
    if (code < 0) goto exit;
3001
30
    if (code > 0) {
3002
30
        code = pdfi_gsave(ctx);
3003
30
        if (code < 0) goto exit;
3004
30
        need_grestore = true;
3005
30
        code = pdfi_gs_setgray(ctx, 0);
3006
30
        if (code < 0) goto exit;
3007
30
        x = rect.p.x + 5;
3008
30
        y = rect.q.y - 30;
3009
3010
30
        code = pdfi_annot_set_font(ctx, "Helvetica", 9);
3011
30
        if (code < 0) goto exit;
3012
3013
30
        code = pdfi_annot_display_simple_text(ctx, annot, x, y, Contents);
3014
30
        if (code < 0) goto exit;
3015
3016
30
        code = pdfi_grestore(ctx);
3017
30
        need_grestore = false;
3018
30
        if (code < 0) goto exit;
3019
30
    }
3020
3021
    /* Draw small, thin box (the frame around the top /T text) */
3022
30
    rect2.p.x = rect.p.x;
3023
30
    rect2.p.y = rect.q.y - 15;
3024
30
    rect2.q.x = rect.q.x;
3025
30
    rect2.q.y = rect.p.y + (rect.q.y - rect.p.y);
3026
3027
30
    code = gs_rectfill(ctx->pgs, &rect2, 1);
3028
30
    if (code < 0) goto exit;
3029
30
    code = pdfi_gs_setgray(ctx, 0);
3030
30
    if (code < 0) goto exit;
3031
30
    code = gs_rectstroke(ctx->pgs, &rect2, 1, NULL);
3032
30
    if (code < 0) goto exit;
3033
3034
    /* Display /T in Helvetica */
3035
30
    code = pdfi_dict_knownget_type(ctx, Parent, "T", PDF_STRING, (pdf_obj **)&T);
3036
30
    if (code < 0) goto exit;
3037
30
    if (code > 0) {
3038
30
        code = pdfi_annot_set_font(ctx, "Helvetica", 9);
3039
30
        if (code < 0) goto exit;
3040
3041
30
        code = pdfi_annot_display_centered_text(ctx, annot, &rect, T);
3042
30
        if (code < 0) goto exit;
3043
3044
30
    }
3045
3046
30
 exit:
3047
30
    if (need_grestore) {
3048
0
        code1= pdfi_grestore(ctx);
3049
0
        if (code == 0) code = code1;
3050
0
    }
3051
30
    code1 = pdfi_annot_end_transparency(ctx, annot);
3052
30
    if (code == 0) code = code1;
3053
1.60k
 exit1:
3054
1.60k
    pdfi_countdown(Parent);
3055
1.60k
    pdfi_countdown(Contents);
3056
1.60k
    pdfi_countdown(T);
3057
1.60k
    return code;
3058
30
}
3059
3060
/* Generate appearance (see pdf_draw.ps/Line)
3061
 *
3062
 * If there was an AP it was already handled.
3063
 */
3064
static int pdfi_annot_draw_Line(pdf_context *ctx, pdf_dict *annot, pdf_obj *NormAP, bool *render_done)
3065
225
{
3066
225
    int code = 0;
3067
225
    int code1 = 0;
3068
225
    gs_rect lrect;
3069
225
    pdf_array *L = NULL;
3070
225
    bool drawit;
3071
3072
225
    code = pdfi_annot_start_transparency(ctx, annot);
3073
225
    if (code < 0) goto exit1;
3074
3075
225
    code = pdfi_dict_knownget_type(ctx, annot, "L", PDF_ARRAY, (pdf_obj **)&L);
3076
225
    if (code < 0) goto exit;
3077
3078
225
    code = pdfi_array_to_gs_rect(ctx, L, &lrect);
3079
225
    if (code < 0) goto exit;
3080
3081
224
    code = pdfi_annot_setcolor(ctx, annot, false, &drawit);
3082
224
    if (code < 0) goto exit;
3083
3084
    /* Handle LE */
3085
224
    code = pdfi_annot_draw_LE(ctx, annot, lrect.p.x, lrect.p.y, lrect.q.x, lrect.q.y, 0);
3086
224
    if (code < 0) goto exit;
3087
3088
    /* Draw the actual line */
3089
223
    code = gs_moveto(ctx->pgs, lrect.p.x, lrect.p.y);
3090
223
    if (code < 0) goto exit;
3091
223
    code = gs_lineto(ctx->pgs, lrect.q.x, lrect.q.y);
3092
223
    if (code < 0) goto exit;
3093
223
    code = pdfi_annot_draw_border(ctx, annot, true);
3094
223
    if (code < 0) goto exit;
3095
3096
225
 exit:
3097
225
    code1 = pdfi_annot_end_transparency(ctx, annot);
3098
225
    if (code >= 0)
3099
223
        code = code1;
3100
225
 exit1:
3101
225
    *render_done = true;
3102
225
    pdfi_countdown(L);
3103
225
    return code;
3104
225
}
3105
3106
/* Create a path from an array of points */
3107
static int pdfi_annot_path_array(pdf_context *ctx, pdf_dict *annot, pdf_array *Vertices)
3108
118
{
3109
118
    int code = 0;
3110
118
    int i;
3111
3112
648
    for (i=0; i<pdfi_array_size(Vertices); i+=2) {
3113
530
        double x,y;
3114
3115
530
        code = pdfi_array_get_number(ctx, Vertices, i, &x);
3116
530
        if (code < 0) goto exit;
3117
530
        code = pdfi_array_get_number(ctx, Vertices, i+1, &y);
3118
530
        if (code < 0) goto exit;
3119
3120
530
        if (i == 0) {
3121
118
            code = gs_moveto(ctx->pgs, x, y);
3122
118
            if (code < 0) goto exit;
3123
412
        } else {
3124
412
            code = gs_lineto(ctx->pgs, x, y);
3125
412
            if (code < 0) goto exit;
3126
412
        }
3127
530
    }
3128
3129
118
 exit:
3130
118
    return code;
3131
118
}
3132
3133
/* Generate appearance (see pdf_draw.ps/PolyLine)
3134
 * NOTE: as of 5-7-20, the gs implementation of this is actually broken
3135
 *
3136
 * If there was an AP it was already handled.
3137
 */
3138
static int pdfi_annot_draw_PolyLine(pdf_context *ctx, pdf_dict *annot, pdf_obj *NormAP, bool *render_done)
3139
115
{
3140
115
    int code = 0;
3141
115
    int code1 = 0;
3142
115
    pdf_array *Vertices = NULL;
3143
115
    bool drawit;
3144
115
    int size;
3145
115
    double x1, y1, x2, y2;
3146
3147
115
    code = pdfi_annot_start_transparency(ctx, annot);
3148
115
    if (code < 0) goto exit1;
3149
3150
115
    code = pdfi_dict_knownget_type(ctx, annot, "Vertices", PDF_ARRAY, (pdf_obj **)&Vertices);
3151
115
    if (code < 0) goto exit;
3152
3153
115
    if (code == 0) {
3154
2
        code = gs_note_error(gs_error_undefined);
3155
2
        goto exit;
3156
2
    }
3157
3158
113
    size = pdfi_array_size(Vertices);
3159
113
    if (size == 0) {
3160
0
        code = 0;
3161
0
        goto exit;
3162
0
    }
3163
113
    code = pdfi_annot_path_array(ctx, annot, Vertices);
3164
113
    if (code < 0) goto exit1;
3165
3166
113
    code = pdfi_annot_setcolor(ctx, annot, false, &drawit);
3167
113
    if (code < 0) goto exit;
3168
3169
113
    code = pdfi_annot_draw_border(ctx, annot, true);
3170
113
    if (code < 0) goto exit;
3171
3172
113
    if (size >= 4) {
3173
113
        code = pdfi_array_get_number(ctx, Vertices, 0, &x1);
3174
113
        if (code < 0) goto exit;
3175
113
        code = pdfi_array_get_number(ctx, Vertices, 1, &y1);
3176
113
        if (code < 0) goto exit;
3177
113
        code = pdfi_array_get_number(ctx, Vertices, 2, &x2);
3178
113
        if (code < 0) goto exit;
3179
113
        code = pdfi_array_get_number(ctx, Vertices, 3, &y2);
3180
113
        if (code < 0) goto exit;
3181
113
        code = pdfi_annot_draw_LE(ctx, annot, x1, y1, x2, y2, 1);
3182
113
        if (code < 0) goto exit;
3183
3184
113
        code = pdfi_array_get_number(ctx, Vertices, size-4, &x1);
3185
113
        if (code < 0) goto exit;
3186
113
        code = pdfi_array_get_number(ctx, Vertices, size-3, &y1);
3187
113
        if (code < 0) goto exit;
3188
113
        code = pdfi_array_get_number(ctx, Vertices, size-2, &x2);
3189
113
        if (code < 0) goto exit;
3190
113
        code = pdfi_array_get_number(ctx, Vertices, size-1, &y2);
3191
113
        if (code < 0) goto exit;
3192
113
        code = pdfi_annot_draw_LE(ctx, annot, x1, y1, x2, y2, 2);
3193
113
        if (code < 0) goto exit;
3194
113
    }
3195
3196
115
 exit:
3197
115
    code1 = pdfi_annot_end_transparency(ctx, annot);
3198
115
    if (code >= 0)
3199
113
        code = code1;
3200
3201
115
 exit1:
3202
115
    *render_done = true;
3203
115
    pdfi_countdown(Vertices);
3204
115
    return code;
3205
115
}
3206
3207
/* Generate appearance (see pdf_draw.ps/Polygon)
3208
 *
3209
 * If there was an AP it was already handled.
3210
 */
3211
static int pdfi_annot_draw_Polygon(pdf_context *ctx, pdf_dict *annot, pdf_obj *NormAP, bool *render_done)
3212
5
{
3213
5
    int code = 0;
3214
5
    int code1 = 0;
3215
5
    pdf_array *Vertices = NULL;
3216
5
    bool drawit;
3217
3218
5
    code = pdfi_annot_start_transparency(ctx, annot);
3219
5
    if (code < 0) goto exit1;
3220
3221
5
    code = pdfi_dict_knownget_type(ctx, annot, "Vertices", PDF_ARRAY, (pdf_obj **)&Vertices);
3222
5
    if (code <= 0) goto exit;
3223
3224
5
    code = pdfi_annot_path_array(ctx, annot, Vertices);
3225
5
    if (code < 0) goto exit1;
3226
3227
5
    code = gs_closepath(ctx->pgs);
3228
3229
    /* NOTE: The logic here seems a bit wonky.  Why only set opacity if there was a fill?
3230
     * Anyway, it is based on the ps code (pdf_draw.ps/Polygon).
3231
     * Maybe can be improved.
3232
     */
3233
5
    code = pdfi_annot_setinteriorcolor(ctx, annot, false, &drawit);
3234
5
    if (code < 0) goto exit;
3235
5
    if (drawit) {
3236
0
        code = pdfi_annot_fillborderpath(ctx, annot);
3237
0
        if (code < 0) goto exit;
3238
0
        code = pdfi_annot_opacity(ctx, annot); /* TODO: Why only on this path? */
3239
0
        if (code < 0) goto exit;
3240
0
    }
3241
5
    code = pdfi_annot_setcolor(ctx, annot, false, &drawit);
3242
5
    if (code < 0) goto exit;
3243
5
    if (drawit) {
3244
5
        code = pdfi_annot_draw_border(ctx, annot, true);
3245
5
        if (code < 0) goto exit;
3246
5
    }
3247
3248
5
 exit:
3249
5
    code1 = pdfi_annot_end_transparency(ctx, annot);
3250
5
    if (code >= 0)
3251
5
        code = code1;
3252
5
 exit1:
3253
5
    *render_done = true;
3254
5
    pdfi_countdown(Vertices);
3255
5
    return code;
3256
5
}
3257
3258
/* Generate appearance (see pdf_draw.ps/Square)
3259
 *
3260
 * If there was an AP it was already handled.
3261
 */
3262
static int pdfi_annot_draw_Square(pdf_context *ctx, pdf_dict *annot, pdf_obj *NormAP, bool *render_done)
3263
28
{
3264
28
    int code = 0;
3265
28
    int code1 = 0;
3266
28
    bool drawit;
3267
3268
28
    code = pdfi_annot_start_transparency(ctx, annot);
3269
28
    if (code < 0) goto exit1;
3270
3271
28
    code = pdfi_annot_setinteriorcolor(ctx, annot, false, &drawit);
3272
28
    if (code < 0) goto exit;
3273
28
    if (drawit) {
3274
13
        code = pdfi_annot_opacity(ctx, annot);
3275
13
        if (code < 0) goto exit;
3276
13
        code = pdfi_annot_fillRect(ctx, annot);
3277
13
        if (code < 0) goto exit;
3278
3279
13
        code = pdfi_annot_setcolor(ctx, annot, false, &drawit);
3280
13
        if (code < 0) goto exit;
3281
3282
13
        if (drawit) {
3283
13
            code = pdfi_annot_draw_border(ctx, annot, false);
3284
13
            if (code < 0) goto exit;
3285
13
        }
3286
15
    } else {
3287
15
        code = pdfi_annot_RectRD_path(ctx, annot);
3288
15
        if (code < 0) goto exit;
3289
3290
15
        code = pdfi_annot_setcolor(ctx, annot, false, &drawit);
3291
15
        if (code < 0) goto exit;
3292
3293
15
        if (drawit) {
3294
15
            code = pdfi_annot_draw_border(ctx, annot, true);
3295
15
            if (code < 0) goto exit;
3296
15
        }
3297
15
    }
3298
3299
28
 exit:
3300
28
    code1 = pdfi_annot_end_transparency(ctx, annot);
3301
28
    if (code >= 0)
3302
28
        code = code1;
3303
28
 exit1:
3304
28
    *render_done = true;
3305
28
    return code;
3306
28
}
3307
3308
static int pdfi_annot_render_MK_box(pdf_context *ctx, pdf_dict *annot, pdf_dict *MK)
3309
23.8k
{
3310
23.8k
    int code = 0;
3311
23.8k
    bool drawit = false;
3312
23.8k
    gs_rect rect;
3313
23.8k
    bool need_grestore = false;
3314
3315
    /* Basically just render the rectangle around the widget for now */
3316
23.8k
    code = pdfi_annot_Rect(ctx, annot, &rect);
3317
23.8k
    if (code < 0) goto exit;
3318
3319
23.8k
    code = pdfi_gsave(ctx);
3320
23.8k
    if (code < 0) goto exit;
3321
23.8k
    need_grestore = true;
3322
23.8k
    code = pdfi_annot_setcolor_key(ctx, MK, "BG", false, &drawit);
3323
23.8k
    if (code < 0) goto exit;
3324
23.8k
    if (drawit)
3325
5.10k
        code = gs_rectfill(ctx->pgs, &rect, 1);
3326
23.8k
    if (code < 0) goto exit;
3327
23.8k
    need_grestore = false;
3328
23.8k
    code = pdfi_grestore(ctx);
3329
23.8k
    if (code < 0) goto exit;
3330
3331
23.8k
    code = pdfi_gsave(ctx);
3332
23.8k
    if (code < 0) goto exit;
3333
23.8k
    need_grestore = true;
3334
23.8k
    code = pdfi_annot_setcolor_key(ctx, MK, "BC", false, &drawit);
3335
23.8k
    if (code < 0) goto exit;
3336
23.8k
    if (drawit)
3337
5.12k
        code = gs_rectstroke(ctx->pgs, &rect, 1, NULL);
3338
23.8k
    if (code < 0) goto exit;
3339
23.8k
    need_grestore = false;
3340
23.8k
    code = pdfi_grestore(ctx);
3341
23.8k
    if (code < 0) goto exit;
3342
3343
    /* TODO: Stuff with can-regenerate-ap ?? */
3344
3345
23.8k
 exit:
3346
23.8k
    if (need_grestore)
3347
3
        (void)pdfi_grestore(ctx);
3348
23.8k
    return code;
3349
23.8k
}
3350
3351
typedef enum {
3352
    PDFI_FORM_FF_READONLY = 1, /* Bit 1 */
3353
    PDFI_FORM_FF_REQUIRED = 1 << 1, /* Bit 2 */
3354
    PDFI_FORM_FF_NOEXPORT = 1 << 2, /* Bit 3 */
3355
    PDFI_FORM_FF_MULTILINE = 1 << 12, /* Bit 13 */
3356
    PDFI_FORM_FF_PASSWORD = 1 << 13, /* Bit 14 */
3357
    PDFI_FORM_FF_NOTOGGLETOOFF = 1 << 14, /* Bit 15 */
3358
    PDFI_FORM_FF_RADIO = 1 << 15, /* Bit 16 */
3359
    PDFI_FORM_FF_PUSHBUTTON = 1 << 16, /* Bit 17 */
3360
    PDFI_FORM_FF_COMBO = 1 << 17, /* Bit 18 */
3361
    PDFI_FORM_FF_EDIT = 1 << 18, /* Bit 19 */
3362
    PDFI_FORM_FF_SORT = 1 << 19, /* Bit 20 */
3363
    PDFI_FORM_FF_FILESELECT = 1 << 20, /* Bit 21 */
3364
    PDFI_FORM_FF_MULTISELECT = 1 << 21, /* Bit 22 */
3365
    PDFI_FORM_FF_DONOTSPELLCHECK = 1 << 22, /* Bit 23 */
3366
    PDFI_FORM_FF_DONOTSCROLL = 1 << 23, /* Bit 24 */
3367
    PDFI_FORM_FF_COMB = 1 << 24, /* Bit 25 */
3368
    PDFI_FORM_FF_RICHTEXT = 1 << 25, /* Bit 26 */ /* also PDFI_FORM_FF_RADIOSINUNISON */
3369
    PDFI_FORM_FF_COMMITONSELCHANGE = 1 << 26, /* Bit 27 */
3370
} pdfi_form_Ff;
3371
3372
/* draw field Btn */
3373
static int pdfi_form_draw_Btn(pdf_context *ctx, pdf_dict *field, pdf_obj *AP)
3374
3.54k
{
3375
3.54k
    int code;
3376
3.54k
    bool Radio = false;
3377
3.54k
    bool Pushbutton = false;
3378
3.54k
    int64_t value;
3379
3380
    /* TODO: There can be Kids array. I think it should be handled in caller.
3381
     * Need an example...
3382
     */
3383
3.54k
    if (AP != NULL) {
3384
0
        code = pdfi_annot_draw_AP(ctx, field, AP);
3385
0
        goto exit;
3386
0
    }
3387
3388
    /* Get Ff field (default is 0) */
3389
3.54k
    code = pdfi_form_get_inheritable_int(ctx, field, "Ff", &value);
3390
3.54k
    if (code < 0) goto exit;
3391
3392
1.35k
    Radio = value & PDFI_FORM_FF_RADIO;
3393
1.35k
    Pushbutton = value & PDFI_FORM_FF_PUSHBUTTON;
3394
3395
1.35k
    dmprintf(ctx->memory, "WARNING: AcroForm field 'Btn' with no AP not implemented.\n");
3396
1.35k
    dmprintf2(ctx->memory, "       : Radio = %s, Pushbutton = %s.\n",
3397
1.35k
              Radio ? "TRUE" : "FALSE", Pushbutton ? "TRUE" : "FALSE");
3398
3.54k
 exit:
3399
3.54k
    return 0;
3400
1.35k
}
3401
3402
/* Modify V from Tx widget to skip past the BOM and indicate if UTF-16 was found */
3403
static int pdfi_form_modV(pdf_context *ctx, pdf_string *V, pdf_string **mod_V, bool *is_UTF16)
3404
70
{
3405
70
    bool did_mod = false;
3406
70
    int code = 0;
3407
70
    int skip = 0;
3408
70
    pdf_string *newV = NULL;
3409
3410
70
    *is_UTF16 = false;
3411
3412
70
    if (IS_UTF8(V->data)) {
3413
0
        skip = 3;
3414
70
    } else if (IS_UTF16(V->data)) {
3415
0
        skip = 2;
3416
0
        *is_UTF16 = true;
3417
0
    }
3418
3419
70
    if (skip == 0)
3420
70
        goto exit;
3421
3422
    /* Create a new V that skips over the BOM */
3423
0
    code = pdfi_object_alloc(ctx, PDF_STRING, V->length-skip, (pdf_obj **)&newV);
3424
0
    if (code < 0)
3425
0
        goto exit;
3426
0
    pdfi_countup(newV);
3427
3428
0
    memcpy(newV->data, V->data+skip, newV->length);
3429
0
    did_mod = true;
3430
3431
70
 exit:
3432
    /* If didn't need to mod it, just copy the original and get a ref */
3433
70
    if (did_mod) {
3434
0
        *mod_V = newV;
3435
70
    } else {
3436
70
        *mod_V = V;
3437
70
        pdfi_countup(V);
3438
70
    }
3439
70
    return code;
3440
0
}
3441
3442
/* Display simple text (no multiline or comb) */
3443
static int pdfi_form_Tx_simple(pdf_context *ctx, pdf_dict *annot, gs_rect *rect, pdf_string *V,
3444
                               int64_t Ff, int64_t Q, bool is_UTF16)
3445
69
{
3446
69
    int code = 0;
3447
69
    gs_rect modrect;
3448
69
    double lineheight = 0;
3449
69
    gs_rect bbox;
3450
69
    gs_point awidth;
3451
69
    double y_adjust = 0.0f, x_adjust = 0.0f;
3452
3453
69
    modrect = *rect; /* structure copy */
3454
3455
69
    code = pdfi_annot_get_text_height(ctx, &lineheight);
3456
69
    if (code < 0) goto exit;
3457
3458
    /* text placement adjustments */
3459
69
    switch (Q) {
3460
69
    case 0: /* Left-justified */
3461
69
        x_adjust = 2; /* empirical value */
3462
69
        break;
3463
0
    case 1: /* Centered */
3464
        /* Get width of the string */
3465
0
        code = pdfi_string_bbox(ctx, V, &bbox, &awidth, false);
3466
0
        if (code < 0) goto exit;
3467
0
        x_adjust = ((rect->q.x - rect->p.x) - awidth.x) / 2;
3468
0
        break;
3469
0
    case 2: /* Right-justified */
3470
        /* Get width of the string */
3471
0
        code = pdfi_string_bbox(ctx, V, &bbox, &awidth, false);
3472
0
        if (code < 0) goto exit;
3473
0
        x_adjust = rect->q.x - awidth.x;
3474
0
        break;
3475
69
    }
3476
3477
    /* Center vertically */
3478
69
    y_adjust = ((rect->q.y - rect->p.y) - lineheight) / 2;
3479
3480
69
    modrect.p.x += x_adjust;
3481
69
    modrect.p.y += y_adjust;
3482
69
    modrect.p.y += (lineheight + 6.) / 10.; /* empirical */
3483
3484
69
    code = pdfi_annot_display_simple_text(ctx, annot, modrect.p.x, modrect.p.y, V);
3485
69
    if (code < 0) goto exit;
3486
69
 exit:
3487
69
    return code;
3488
69
}
3489
3490
/* Display text from Tx MULTILINE */
3491
static int pdfi_form_Tx_multiline(pdf_context *ctx, pdf_dict *annot, gs_rect *rect, pdf_string *V,
3492
                                  int64_t Ff, int64_t Q, bool is_UTF16)
3493
1
{
3494
1
    int code = 0;
3495
1
    gs_rect modrect;
3496
3497
1
    modrect = *rect; /* structure copy */
3498
    /* empirical tweaks */
3499
1
    modrect.p.x += 2;
3500
1
    modrect.p.y += 2;
3501
1
    modrect.q.x -= 2;
3502
1
    modrect.q.y -= 2;
3503
3504
1
    code = pdfi_annot_display_formatted_text(ctx, annot, &modrect, V, is_UTF16);
3505
1
    if (code < 0) goto exit;
3506
3507
1
 exit:
3508
1
    return code;
3509
1
}
3510
3511
3512
/* Display text from Tx COMB */
3513
static int pdfi_form_Tx_comb(pdf_context *ctx, pdf_dict *annot, gs_rect *rect, pdf_string *V,
3514
                             int64_t Ff, int64_t Q, int64_t MaxLen, bool is_UTF16)
3515
0
{
3516
0
    int code = 0;
3517
3518
    /* TODO: Implement... Need a sample that uses COMB! */
3519
0
    code = pdfi_form_Tx_simple(ctx, annot, rect, V, Ff, Q, is_UTF16);
3520
0
    return code;
3521
0
}
3522
3523
3524
/* Display text from Tx in a field or widget */
3525
static int pdfi_form_display_Tx(pdf_context *ctx, pdf_dict *annot, gs_rect *rect, pdf_string *V,
3526
                                  int64_t Ff, int64_t Q, int64_t MaxLen)
3527
70
{
3528
70
    int code = 0;
3529
70
    pdf_string *modV = NULL;
3530
70
    bool is_UTF16;
3531
3532
    /* TODO: If we wanted to preserve this for pdfwrite, we would have to generate
3533
     * a stream for the AP.  See PDF1.7 spec, Variable Text (page 677).
3534
     */
3535
3536
    /* Get modified V that skips the BOM, if any */
3537
70
    code = pdfi_form_modV(ctx, V, &modV, &is_UTF16);
3538
70
    if (code < 0) goto exit;
3539
3540
70
    if (Ff & PDFI_FORM_FF_MULTILINE) {
3541
1
        code = pdfi_form_Tx_multiline(ctx, annot, rect, modV, Ff, Q, is_UTF16);
3542
69
    } else if (Ff & PDFI_FORM_FF_COMB) {
3543
0
        code = pdfi_form_Tx_comb(ctx, annot, rect, modV, Ff, Q, MaxLen, is_UTF16);
3544
69
    } else {
3545
69
        code = pdfi_form_Tx_simple(ctx, annot, rect, modV, Ff, Q, is_UTF16);
3546
69
    }
3547
3548
70
 exit:
3549
70
    pdfi_countdown(modV);
3550
70
    return code;
3551
70
}
3552
3553
3554
/* At least for now, Tx and Ch are handled the same */
3555
static int pdfi_form_draw_Tx_Ch(pdf_context *ctx, pdf_dict *annot)
3556
14.4k
{
3557
14.4k
    int code = 0;
3558
14.4k
    pdf_string *V = NULL;
3559
14.4k
    gs_rect annotrect;
3560
14.4k
    int64_t Ff;
3561
14.4k
    int64_t MaxLen;
3562
14.4k
    int64_t Q;
3563
3564
14.4k
    code = pdfi_annot_Rect(ctx, annot, &annotrect);
3565
14.4k
    if (code < 0) goto exit;
3566
3567
    /* Set DA (Default Appearance)
3568
     * This will generally set a color and font.
3569
     */
3570
14.4k
    code = pdfi_annot_process_DA(ctx, annot, annot, &annotrect, true);
3571
14.4k
    if (code < 0) goto exit;
3572
3573
14.4k
    code = pdfi_form_get_inheritable_int(ctx, annot, "Ff", &Ff);
3574
14.4k
    if (code < 0) goto exit;
3575
3576
13.5k
    code = pdfi_form_get_inheritable_int(ctx, annot, "MaxLen", &MaxLen);
3577
13.5k
    if (code < 0) goto exit;
3578
3579
6.21k
    code = pdfi_form_get_inheritable_int(ctx, annot, "Q", &Q);
3580
6.21k
    if (code < 0) goto exit;
3581
3582
6.21k
    code = pdfi_dict_knownget_type(ctx, annot, "V", PDF_STRING, (pdf_obj **)&V);
3583
6.21k
    if (code < 0) goto exit;
3584
6.21k
    if (code > 0) {
3585
70
        code = pdfi_form_display_Tx(ctx, annot, &annotrect, V, Ff, Q, MaxLen);
3586
70
        if (code < 0) goto exit;
3587
70
    }
3588
3589
14.4k
 exit:
3590
14.4k
    pdfi_countdown(V);
3591
14.4k
    return code;
3592
6.21k
}
3593
3594
/* draw field Tx */
3595
static int pdfi_form_draw_Tx(pdf_context *ctx, pdf_dict *annot, pdf_obj *AP)
3596
14.4k
{
3597
14.4k
    if (AP != NULL)
3598
0
        return pdfi_annot_draw_AP(ctx, annot, AP);
3599
3600
14.4k
    return pdfi_form_draw_Tx_Ch(ctx, annot);
3601
14.4k
}
3602
3603
/* draw field Ch */
3604
static int pdfi_form_draw_Ch(pdf_context *ctx, pdf_dict *field, pdf_obj *AP)
3605
31
{
3606
31
    if (!ctx->NeedAppearances && AP != NULL)
3607
0
        return pdfi_annot_draw_AP(ctx, field, AP);
3608
3609
31
    return pdfi_form_draw_Tx_Ch(ctx, field);
3610
31
}
3611
3612
/* draw field Sig */
3613
static int pdfi_form_draw_Sig(pdf_context *ctx, pdf_dict *field, pdf_obj *AP)
3614
0
{
3615
0
    int code = 0;
3616
3617
0
    if (!ctx->NeedAppearances && AP != NULL)
3618
0
        return pdfi_annot_draw_AP(ctx, field, AP);
3619
3620
0
    dmprintf(ctx->memory, "WARNING: AcroForm field 'Sig' with no AP not implemented.\n");
3621
3622
0
    return code;
3623
0
}
3624
3625
/* TODO: The spec handles "regenerate appearance", which it does by generating
3626
 * a new AP stream for the field, and then rendering it as a form.
3627
 * The gs code does try to handle this case.
3628
 * For now I am just going to generate the data inline, without building it as a Form/Stream.
3629
 * If we have want to preserve the AP (i.e. for pdfwrite device, generate the AP and include
3630
 * it in the output, rather than just rendering it into the output) then this needs to change.
3631
 * Currently gs doesn't try to preserve AcroForms, so we aren't losing any functionality by
3632
 * not doing this.  But it is a place for a future enhancement.
3633
 *
3634
 * See also, the comment on pdfi_annot_preserve_Widget().
3635
 */
3636
static int pdfi_annot_render_field(pdf_context *ctx, pdf_dict *field, pdf_name *FT, pdf_obj *AP)
3637
18.0k
{
3638
18.0k
    int code;
3639
3640
18.0k
    if (pdfi_name_is(FT, "Btn")) {
3641
3.54k
        code = pdfi_form_draw_Btn(ctx, field, AP);
3642
14.4k
    } else if (pdfi_name_is(FT, "Tx")) {
3643
14.4k
        code = pdfi_form_draw_Tx(ctx, field, AP);
3644
14.4k
    } else if (pdfi_name_is(FT, "Ch")) {
3645
31
        code = pdfi_form_draw_Ch(ctx, field, AP);
3646
31
    } else if (pdfi_name_is(FT, "Sig")) {
3647
0
        code = pdfi_form_draw_Sig(ctx, field, AP);
3648
0
    } else {
3649
0
        dmprintf(ctx->memory, "*** WARNING unknown field FT ignored\n");
3650
        /* TODO: Handle warning better */
3651
0
        code = 0;
3652
0
    }
3653
3654
18.0k
    return code;
3655
18.0k
}
3656
3657
/* Render Widget with no AP
3658
 */
3659
static int pdfi_annot_render_Widget(pdf_context *ctx, pdf_dict *annot)
3660
23.8k
{
3661
23.8k
    int code = 0;
3662
23.8k
    pdf_dict *MK = NULL;
3663
23.8k
    pdf_name *FT = NULL;
3664
3665
    /* Render box around the widget using MK */
3666
23.8k
    code = pdfi_dict_knownget_type(ctx, annot, "MK", PDF_DICT, (pdf_obj **)&MK);
3667
23.8k
    if (code < 0) goto exit;
3668
23.8k
    if (code > 0) {
3669
23.8k
        code = pdfi_annot_render_MK_box(ctx, annot, MK);
3670
23.8k
        if (code < 0) goto exit;
3671
23.8k
    }
3672
3673
    /* Render the other contents */
3674
23.8k
    code = pdfi_dict_knownget_type(ctx, annot, "FT", PDF_NAME, (pdf_obj **)&FT);
3675
23.8k
    if (code < 0) goto exit;
3676
23.8k
    if (code > 0) {
3677
18.0k
        code = pdfi_annot_render_field(ctx, annot, FT, NULL);
3678
18.0k
        if (code < 0) goto exit;
3679
18.0k
    }
3680
3681
23.8k
 exit:
3682
23.8k
    pdfi_countdown(FT);
3683
23.8k
    pdfi_countdown(MK);
3684
23.8k
    return code;
3685
23.8k
}
3686
3687
/* Draws a thing of type /Widget */
3688
static int pdfi_annot_draw_Widget(pdf_context *ctx, pdf_dict *annot, pdf_obj *NormAP, bool *render_done)
3689
57.8k
{
3690
57.8k
    int code = 0;
3691
57.8k
    bool found_T = false;
3692
57.8k
    bool found_FT = false, known = false;
3693
57.8k
    pdf_obj *T = NULL;
3694
57.8k
    pdf_obj *FT = NULL;
3695
57.8k
    pdf_dict *Parent = NULL;
3696
57.8k
    pdf_dict *currdict = NULL;
3697
3698
    /* From pdf_draw.ps/drawwidget:
3699
  % Acrobat doesn't draw Widget annotations unles they have both /FT
3700
  % (which is defined as required) and /T keys present. Annoyingly
3701
  % these can either be inherited from the Form Definition Field
3702
  % dictionary (via the AcroForm tree) or present directly in the
3703
  % annotation, so we need to check the annotation to make sure its
3704
  % a Widget, then follow any /Parent key up to the root node
3705
  % extracting and storing any FT or T keys as we go (we only care if
3706
  % these are present, their value is immaterial). If after all that
3707
  % both keys are not present, then we don't draw the annotation.
3708
    */
3709
3710
    /* TODO: See top part of pdf_draw.ps/drawwidget
3711
     * check for /FT and /T and stuff
3712
     */
3713
57.8k
    code = pdfi_loop_detector_mark(ctx);
3714
57.8k
    if (code < 0)
3715
0
        goto exit;
3716
3717
57.8k
    currdict = annot;
3718
57.8k
    pdfi_countup(currdict);
3719
83.9k
    while (true) {
3720
83.9k
        if (currdict->object_num != 0) {
3721
83.9k
            code = pdfi_loop_detector_add_object(ctx, currdict->object_num);
3722
83.9k
            if (code < 0)
3723
0
                break;
3724
83.9k
        }
3725
3726
83.9k
        code = pdfi_dict_knownget(ctx, currdict, "T", &T);
3727
83.9k
        if (code < 0) goto exit;
3728
83.9k
        if (code > 0) {
3729
56.4k
            found_T = true;
3730
56.4k
            pdfi_countdown(T);
3731
56.4k
            T = NULL;
3732
56.4k
            if (found_FT)
3733
7
                break;
3734
56.4k
        }
3735
83.9k
        code = pdfi_dict_knownget(ctx, currdict, "FT", &FT);
3736
83.9k
        if (code < 0) goto exit;
3737
83.9k
        if (code > 0) {
3738
56.4k
            found_FT = true;
3739
56.4k
            pdfi_countdown(FT);
3740
56.4k
            FT = NULL;
3741
56.4k
            if (found_T)
3742
56.4k
                break;
3743
56.4k
        }
3744
        /* Check for Parent. Do not store the dereferenced Parent back to the dictionary
3745
         * as this can cause circular references.
3746
         */
3747
27.4k
        code = pdfi_dict_known(ctx, currdict, "Parent", &known);
3748
27.4k
        if (code >= 0 && known == true)
3749
27.2k
        {
3750
27.2k
            code = pdfi_dict_get_no_store_R(ctx, currdict, "Parent", (pdf_obj **)&Parent);
3751
27.2k
            if (code < 0) {
3752
1.18k
                (void)pdfi_loop_detector_cleartomark(ctx);
3753
1.18k
                goto exit;
3754
1.18k
            }
3755
26.1k
            if (pdfi_type_of(Parent) != PDF_DICT) {
3756
101
                if (pdfi_type_of(Parent) == PDF_INDIRECT) {
3757
5
                    pdf_indirect_ref *o = (pdf_indirect_ref *)Parent;
3758
3759
5
                    code = pdfi_dereference(ctx, o->ref_object_num, o->ref_generation_num, (pdf_obj **)&Parent);
3760
5
                    pdfi_countdown(o);
3761
5
                    if (code < 0)
3762
1
                        break;
3763
96
                } else {
3764
96
                    break;
3765
96
                }
3766
101
            }
3767
26.0k
            pdfi_countdown(currdict);
3768
26.0k
            currdict = Parent;
3769
26.0k
            Parent = NULL;
3770
26.0k
        } else
3771
184
            break;
3772
27.4k
    }
3773
3774
56.7k
    (void)pdfi_loop_detector_cleartomark(ctx);
3775
3776
56.7k
    code = 0;
3777
56.7k
    if (!found_T || !found_FT) {
3778
281
        *render_done = true;
3779
281
        dmprintf(ctx->memory, "**** Warning: A Widget annotation dictionary lacks either the FT or T key.\n");
3780
281
        dmprintf(ctx->memory, "              Acrobat ignores such annoataions, annotation will not be rendered.\n");
3781
281
        dmprintf(ctx->memory, "              Output may not be as expected.\n");
3782
281
        goto exit;
3783
281
    }
3784
3785
56.4k
    if (NormAP) {
3786
        /* Let caller render it */
3787
32.5k
        *render_done = false;
3788
32.5k
        goto exit;
3789
32.5k
    }
3790
3791
    /* No AP, try to render the Widget ourselves */
3792
23.8k
    code = pdfi_annot_render_Widget(ctx, annot);
3793
23.8k
    *render_done = true;
3794
3795
57.8k
 exit:
3796
57.8k
    pdfi_countdown(Parent);
3797
57.8k
    pdfi_countdown(currdict);
3798
57.8k
    return code;
3799
23.8k
}
3800
3801
/* Handle Annotations that are not implemented */
3802
static int pdfi_annot_draw_NotImplemented(pdf_context *ctx, pdf_dict *annot, pdf_obj *NormAP, bool *render_done)
3803
2
{
3804
2
    int code = 0;
3805
2
    pdf_name *Subtype = NULL;
3806
2
    char str[100];
3807
3808
2
    code = pdfi_dict_get_type(ctx, annot, "Subtype", PDF_NAME, (pdf_obj **)&Subtype);
3809
2
    if (code < 0) goto exit;
3810
3811
2
    memcpy(str, (const char *)Subtype->data, Subtype->length < 100 ? Subtype->length : 99);
3812
2
    str[Subtype->length < 100 ? Subtype->length : 99] = '\0';
3813
2
    dbgmprintf1(ctx->memory, "ANNOT: No AP, default appearance for Subtype %s Not Implemented\n", str);
3814
3815
2
 exit:
3816
2
    *render_done = false;
3817
2
    pdfi_countdown(Subtype);
3818
2
    return code;
3819
2
}
3820
3821
annot_dispatch_t annot_dispatch[] = {
3822
    /* These are in the same order as the PDF 2.0 spec 12.5.6.1 */
3823
    {"Text", pdfi_annot_draw_Text, true},
3824
    {"Link", pdfi_annot_draw_Link, false},
3825
    {"FreeText", pdfi_annot_draw_FreeText, true},
3826
    {"Line", pdfi_annot_draw_Line, true},
3827
    {"Square", pdfi_annot_draw_Square, true},
3828
    {"Circle", pdfi_annot_draw_Circle, true},
3829
    {"Polygon", pdfi_annot_draw_Polygon, true},
3830
    {"PolyLine", pdfi_annot_draw_PolyLine, true},
3831
    {"Highlight", pdfi_annot_draw_Highlight, true},
3832
    {"Underline", pdfi_annot_draw_Underline, true},
3833
    {"Squiggly", pdfi_annot_draw_Squiggly, true},
3834
    {"StrikeOut", pdfi_annot_draw_StrikeOut, true},
3835
    {"Caret", pdfi_annot_draw_NotImplemented, true},
3836
    {"Stamp", pdfi_annot_draw_Stamp, true},
3837
    {"Ink", pdfi_annot_draw_Ink, true},
3838
    {"Popup", pdfi_annot_draw_Popup, false},
3839
    {"FileAttachment", pdfi_annot_draw_NotImplemented, true},
3840
    {"Sound", pdfi_annot_draw_NotImplemented, true},
3841
    {"Movie", pdfi_annot_draw_NotImplemented, true},
3842
    {"Screen", pdfi_annot_draw_NotImplemented, true},
3843
    {"Widget", pdfi_annot_draw_Widget, false},
3844
    {"PrinterMark", pdfi_annot_draw_NotImplemented, true},
3845
    {"TrapNet", pdfi_annot_draw_NotImplemented, true},
3846
    {"Watermark", pdfi_annot_draw_NotImplemented, true},
3847
    {"3D", pdfi_annot_draw_NotImplemented, true},
3848
    {"Redact", pdfi_annot_draw_Redact, true},
3849
    {"Projection", pdfi_annot_draw_NotImplemented, true},
3850
    {"RichMedia", pdfi_annot_draw_NotImplemented, true},
3851
    { NULL, NULL},
3852
};
3853
3854
/* Check if annotation is visible
3855
 * (from ps code:)
3856
%
3857
%   The PDF annotation F (flags) integer is bit encoded.
3858
%   Bit 1 (LSB) Invisible:  1 --> Do not display if no handler.
3859
%         Note:  We have no handlers but we ignore this bit.
3860
%   Bit 2 Hidden:  1 --> Do not display.  We will not display if this bit is set.
3861
%   Bit 3 Print:  1 --> Display if printing.  We will display if this bit set
3862
%         (and not hidden) and Printed is true
3863
%   Bit 4 NoZoom:  1 --> Do not zoom annotation even if image is zoomed.
3864
%   Bit 5 NoRotate:  1 --> Do not rotate annotation even if image is rotated.
3865
%   Bit 6 NoView:  0 --> Display if this is a 'viewer'.  We will display
3866
%         if this bit is not set (and not hidden) and Printed is false
3867
%   Bit 7 Read Only - 1 --> No interaction.  We ignore this bit
3868
%
3869
%   AR8 and AR9 print 3D annotations even if Print flag is off. Bug 691486.
3870
%
3871
*/
3872
static bool pdfi_annot_visible(pdf_context *ctx, pdf_dict *annot, pdf_name *subtype)
3873
428k
{
3874
428k
    int code;
3875
428k
    bool is_3D = false;
3876
428k
    bool is_visible = true;
3877
428k
    int64_t F;
3878
3879
428k
    if (pdfi_name_is(subtype, "3D"))
3880
0
        is_3D = true;
3881
3882
428k
    code = pdfi_dict_get_int(ctx, annot, "F", &F);
3883
428k
    if (code < 0)
3884
46.6k
        F = 0;
3885
3886
428k
    if ((F & 0x2) != 0) { /* Bit 2 -- Hidden */
3887
156k
        is_visible = false; /* Hidden */
3888
156k
        goto exit;
3889
156k
    }
3890
3891
271k
    if (ctx->args.printed) {
3892
        /* Even if Print flag (bit 3) is off, will print if 3D */
3893
271k
        is_visible = ((F & 0x4) != 0) || is_3D;
3894
271k
    } else {
3895
        /* Not NoView (bit 7) */
3896
0
        is_visible = (F & 0x80) == 0;
3897
0
    }
3898
3899
428k
 exit:
3900
428k
    return is_visible;
3901
271k
}
3902
3903
/* Check to see if subtype is on the ShowAnnotTypes list
3904
 * Defaults to true if there is no list
3905
 */
3906
static bool pdfi_annot_check_type(pdf_context *ctx, pdf_name *subtype)
3907
225k
{
3908
225k
    char **ptr;
3909
3910
    /* True if no list */
3911
225k
    if (!ctx->args.showannottypes)
3912
225k
        return true;
3913
3914
    /* Null terminated list, return true if subtype is on the list */
3915
0
    ptr = ctx->args.showannottypes;
3916
0
    while (*ptr) {
3917
0
        char *str = *ptr;
3918
0
        if (pdfi_name_is(subtype, str))
3919
0
            return true;
3920
0
        ptr ++;
3921
0
    }
3922
    /* List exists, but subtype is not on it */
3923
0
    return false;
3924
0
}
3925
3926
/* Check to see if subtype is on the PreserveAnnotTypes list
3927
 * Defaults to true if there is no list
3928
 */
3929
static bool pdfi_annot_preserve_type(pdf_context *ctx, pdf_name *subtype)
3930
74.2k
{
3931
74.2k
    char **ptr;
3932
3933
    /* True if no list */
3934
74.2k
    if (!ctx->args.preserveannottypes)
3935
74.2k
        return true;
3936
3937
    /* Null terminated list, return true if subtype is on the list */
3938
0
    ptr = ctx->args.preserveannottypes;
3939
0
    while (*ptr) {
3940
0
        char *str = *ptr;
3941
0
        if (pdfi_name_is(subtype, str))
3942
0
            return true;
3943
0
        ptr ++;
3944
0
    }
3945
    /* List exists, but subtype is not on it */
3946
0
    return false;
3947
0
}
3948
3949
static int pdfi_annot_draw(pdf_context *ctx, pdf_dict *annot, pdf_name *subtype)
3950
428k
{
3951
428k
    pdf_obj *NormAP = NULL;
3952
428k
    int code = 0;
3953
428k
    annot_dispatch_t *dispatch_ptr;
3954
428k
    bool render_done = true;
3955
3956
    /* See if annotation is visible */
3957
428k
    if (!pdfi_annot_visible(ctx, annot, subtype))
3958
203k
        goto exit;
3959
3960
    /* See if we are rendering this type of annotation */
3961
225k
    if (!pdfi_annot_check_type(ctx, subtype))
3962
0
        goto exit;
3963
3964
    /* Get the Normal AP, if it exists */
3965
225k
    code = pdfi_annot_get_NormAP(ctx, annot, &NormAP);
3966
225k
    if (code < 0) goto exit;
3967
3968
162k
    code = pdfi_gsave(ctx);
3969
162k
    if (code < 0) goto exit;
3970
3971
    /* Draw the annotation */
3972
2.24M
    for (dispatch_ptr = annot_dispatch; dispatch_ptr->subtype; dispatch_ptr ++) {
3973
2.24M
        if (pdfi_name_is(subtype, dispatch_ptr->subtype)) {
3974
161k
            if (NormAP && dispatch_ptr->simpleAP)
3975
100k
                render_done = false;
3976
61.0k
            else
3977
61.0k
                code = dispatch_ptr->func(ctx, annot, NormAP, &render_done);
3978
161k
            break;
3979
161k
        }
3980
2.24M
    }
3981
162k
    if (!dispatch_ptr->subtype) {
3982
27
        char str[100];
3983
27
        memcpy(str, (const char *)subtype->data, subtype->length < 100 ? subtype->length : 99);
3984
27
        str[subtype->length < 100 ? subtype->length : 99] = '\0';
3985
27
        dbgmprintf1(ctx->memory, "ANNOT: No handler for subtype %s\n", str);
3986
3987
        /* Not necessarily an error? We can just render the AP if there is one */
3988
27
        render_done = false;
3989
27
    }
3990
3991
162k
    if (!render_done)
3992
133k
        code = pdfi_annot_draw_AP(ctx, annot, NormAP);
3993
3994
162k
    (void)pdfi_grestore(ctx);
3995
3996
428k
 exit:
3997
428k
    pdfi_countdown(NormAP);
3998
428k
    return code;
3999
162k
}
4000
4001
/* Create a string containing form label
4002
 * I don't think the format actually matters, though it probably needs to be unique
4003
 * Just use a counter to ensure uniqueness
4004
 *
4005
 * Format: {FormName%d}
4006
 */
4007
static int pdfi_annot_preserve_nextformlabel(pdf_context *ctx, byte **data, int *len)
4008
19.1k
{
4009
19.1k
    int size = 40;
4010
19.1k
    char *buf;
4011
19.1k
    gs_id counter = gs_next_ids(ctx->memory, 1);
4012
4013
19.1k
    buf = (char *)gs_alloc_bytes(ctx->memory, size, "pdfi_annot_preserve_nextformlabel(buf)");
4014
19.1k
    if (buf == NULL)
4015
0
        return_error(gs_error_VMerror);
4016
19.1k
    snprintf(buf, size, "{FN%ld}", counter);
4017
19.1k
    *len = strlen(buf);
4018
19.1k
    *data = (byte *)buf;
4019
19.1k
    return 0;
4020
19.1k
}
4021
4022
/* Modify the QuadPoints array to correct for some BS in the pdfwrite driver.
4023
 * comment from gs code (pdf_draw.ps/ApplyCMTToQuadPoints()):
4024
  %% Nasty hackery here really. We need to undo the HWResolution scaling which
4025
  %% is done by pdfwrite. Default is 720 dpi, so 0.1. We also need to make
4026
  %% sure that any translation of the page (because its been rotated for example)
4027
  %% is also modified by the requisite amount. SO we ned to calculate a matrix
4028
  %% which does the scaling and concatenate it with the current matrix.
4029
  %% Do this inside a gsave/grestore pair to avoid side effects!
4030
 *
4031
 * TODO: In practice, when I was debugging this code I found that it does nothing
4032
 * useful, since the matrice it calculates is essentially the identity matrix.
4033
 * I am not sure under what circumstance it is needed?
4034
 */
4035
static int pdfi_annot_preserve_modQP(pdf_context *ctx, pdf_dict *annot, pdf_name *QP_key)
4036
70
{
4037
70
    int code = 0;
4038
70
    pdf_array *QP = NULL;
4039
70
    gx_device *device = gs_currentdevice(ctx->pgs);
4040
70
    gs_matrix devmatrix, ctm, matrix;
4041
70
    uint64_t arraysize, index;
4042
70
    double old_x, old_y;
4043
70
    gs_point point;
4044
4045
70
    code = pdfi_dict_get(ctx, annot, "QuadPoints", (pdf_obj **)&QP);
4046
70
    if (code < 0) goto exit;
4047
4048
70
    if (pdfi_type_of(QP) != PDF_ARRAY) {
4049
        /* Invalid QuadPoints, just delete it because I dunno what to do...
4050
         * TODO: Should flag a warning here
4051
         */
4052
0
        code = pdfi_dict_delete_pair(ctx, annot, QP_key);
4053
0
        goto exit;
4054
0
    }
4055
4056
70
    arraysize = pdfi_array_size(QP);
4057
70
    if (arraysize % 8 != 0) {
4058
        /* TODO: Flag a warning -- must be sets of 8 values (4 points) */
4059
0
        code = gs_note_error(gs_error_syntaxerror);
4060
0
        goto exit;
4061
0
    }
4062
4063
4064
    /* Get device matrix and adjust by default 72.0 (no idea, just following PS code...) */
4065
70
    devmatrix.xx = 72.0 / device->HWResolution[0];
4066
70
    devmatrix.xy = 0;
4067
70
    devmatrix.yx = 0;
4068
70
    devmatrix.yy = 72.0 / device->HWResolution[1];
4069
70
    devmatrix.tx = 0;
4070
70
    devmatrix.ty = 0;
4071
4072
    /* Get the CTM */
4073
70
    gs_currentmatrix(ctx->pgs, &ctm);
4074
4075
    /* Get matrix to adjust the QuadPoints */
4076
70
    code = gs_matrix_multiply(&ctm, &devmatrix, &matrix);
4077
70
    if (code < 0) goto exit;
4078
4079
    /* Transform all the points by the calculated matrix */
4080
830
    for (index = 0; index < arraysize; index += 2) {
4081
760
        code = pdfi_array_get_number(ctx, QP, index, &old_x);
4082
760
        if (code < 0) goto exit;
4083
760
        code = pdfi_array_get_number(ctx, QP, index+1, &old_y);
4084
760
        if (code < 0) goto exit;
4085
4086
760
        code = gs_point_transform(old_x, old_y, &matrix, &point);
4087
760
        if (code < 0) goto exit;
4088
4089
760
        code = pdfi_array_put_real(ctx, QP, index, point.x);
4090
760
        if (code < 0) goto exit;
4091
760
        code = pdfi_array_put_real(ctx, QP, index+1, point.y);
4092
760
        if (code < 0) goto exit;
4093
760
    }
4094
4095
4096
70
 exit:
4097
70
    pdfi_countdown(QP);
4098
70
    return code;
4099
70
}
4100
4101
/* Build a high level form for the AP and replace it with an indirect reference
4102
 *
4103
 * There can multiple AP in the dictionary, so do all of them.
4104
 */
4105
static int pdfi_annot_preserve_modAP(pdf_context *ctx, pdf_dict *annot, pdf_name *AP_key)
4106
29.6k
{
4107
29.6k
    int code = 0;
4108
29.6k
    pdf_dict *AP = NULL;
4109
29.6k
    uint64_t index;
4110
29.6k
    pdf_name *Key = NULL;
4111
29.6k
    pdf_indirect_ref *Value = NULL;
4112
29.6k
    byte *labeldata = NULL;
4113
29.6k
    int labellen;
4114
29.6k
    int form_id;
4115
29.6k
    gx_device *device = gs_currentdevice(ctx->pgs);
4116
29.6k
    bool found_ap = false; /* found at least one AP stream? */
4117
29.6k
    pdf_obj *object = NULL;
4118
4119
29.6k
    code = pdfi_dict_get(ctx, annot, "AP", (pdf_obj **)&AP);
4120
29.6k
    if (code < 0) goto exit;
4121
4122
28.9k
    if (pdfi_type_of(AP) != PDF_DICT) {
4123
        /* This is an invalid AP, we will flag and delete it below */
4124
172
        found_ap = false;
4125
172
        goto exit;
4126
172
    }
4127
4128
28.7k
    code = pdfi_dict_key_first(ctx, AP, (pdf_obj **)&Key, &index);
4129
28.7k
    while (code >= 0) {
4130
28.7k
        found_ap = true;
4131
28.7k
        code = pdfi_dict_get_no_deref(ctx, AP, Key, (pdf_obj **)&Value);
4132
28.7k
        if (code < 0) goto exit;
4133
4134
        /* Handle indirect object */
4135
28.7k
        if (pdfi_type_of(Value) != PDF_INDIRECT)
4136
0
            goto loop_continue;
4137
4138
        /* Dereference it */
4139
28.7k
        code = pdfi_dereference(ctx, Value->ref_object_num, Value->ref_generation_num, &object);
4140
28.7k
        if (code < 0) goto exit;
4141
4142
19.1k
        if (pdfi_type_of(object) == PDF_STREAM) {
4143
            /* Get a form label */
4144
19.1k
            code = pdfi_annot_preserve_nextformlabel(ctx, &labeldata, &labellen);
4145
19.1k
            if (code < 0) goto exit;
4146
4147
            /* Notify the driver of the label name */
4148
19.1k
            code = (*dev_proc(device, dev_spec_op))
4149
19.1k
                (device, gxdso_pdf_form_name, labeldata, labellen);
4150
4151
19.1k
            code = pdfi_op_q(ctx);
4152
19.1k
            if (code < 0)
4153
0
                goto exit;
4154
4155
19.1k
            code = pdfi_annot_position_AP(ctx, annot, (pdf_stream *)object);
4156
            /* Draw the high-level form */
4157
19.1k
            code = pdfi_do_highlevel_form(ctx, ctx->page.CurrentPageDict, (pdf_stream *)object);
4158
19.1k
            (void)pdfi_op_Q(ctx);
4159
19.1k
            if (code < 0) goto exit;
4160
4161
            /* Get the object number (form_id) of the high level form */
4162
19.1k
            code = (*dev_proc(device, dev_spec_op))
4163
19.1k
                (device, gxdso_get_form_ID, &form_id, sizeof(int));
4164
4165
            /* Save the highlevel form info for pdfi_obj_indirect_str() */
4166
19.1k
            Value->highlevel_object_num = form_id;
4167
19.1k
            Value->is_highlevelform = true;
4168
4169
19.1k
        }
4170
4171
19.1k
    loop_continue:
4172
19.1k
        pdfi_countdown(Key);
4173
19.1k
        Key = NULL;
4174
19.1k
        pdfi_countdown(Value);
4175
19.1k
        Value = NULL;
4176
19.1k
        pdfi_countdown(object);
4177
19.1k
        object = NULL;
4178
19.1k
        gs_free_object(ctx->memory, labeldata, "pdfi_annot_preserve_modAP(labeldata)");
4179
19.1k
        labeldata = NULL;
4180
4181
19.1k
        code = pdfi_dict_key_next(ctx, AP, (pdf_obj **)&Key, &index);
4182
19.1k
        if (code == gs_error_undefined) {
4183
19.1k
            code = 0;
4184
19.1k
            break;
4185
19.1k
        }
4186
19.1k
    }
4187
19.1k
    if (code < 0) goto exit;
4188
4189
29.6k
 exit:
4190
    /* If there was no AP found, then delete the key completely.
4191
     * (Bug697951.pdf)
4192
     */
4193
29.6k
    if (!found_ap) {
4194
        /* TODO: Flag a warning for broken file? */
4195
863
        code = pdfi_dict_delete_pair(ctx, annot, AP_key);
4196
863
    }
4197
4198
29.6k
    if (labeldata)
4199
0
        gs_free_object(ctx->memory, labeldata, "pdfi_annot_preserve_modAP(labeldata)");
4200
29.6k
    pdfi_countdown(AP);
4201
29.6k
    pdfi_countdown(Key);
4202
29.6k
    pdfi_countdown(Value);
4203
29.6k
    pdfi_countdown(object);
4204
29.6k
    return code;
4205
19.1k
}
4206
4207
/* Make a temporary copy of the annotation dict with some fields left out or
4208
 * modified, then do a pdfmark on it
4209
 */
4210
4211
const char *PermittedKeys[] = {
4212
    /* These keys are valid for all annotation types, we specifically do not allow /P or /Parent */
4213
    "Type",
4214
    "Subtype",
4215
    "Rect",
4216
    "Contents",
4217
    "NM",
4218
    "M",
4219
    "F",
4220
    "AP",
4221
    "AS",
4222
    "Border",
4223
    "C",
4224
    "StructParent",
4225
    "OC",
4226
    "AF",
4227
    "ca",
4228
    "CA",
4229
    "BM",
4230
    "Lang",
4231
    /* Keys by annotation type (some are common to more than one type, only one entry per key) */
4232
    /* Markup Annotations we specifically do not permit RT, IRT or Popup */
4233
    "T",
4234
    "RC",
4235
    "CreationDate",
4236
    "Subj",
4237
    "IT",
4238
    "ExData",
4239
    /* Text annotations */
4240
    "Open",
4241
    "Name",
4242
    "State",
4243
    "StateModel",
4244
    /* This isn't specified as being allowed, but Acrobat does something with it, so we need to preserve it */
4245
    "Rotate",
4246
    /* Link annotations */
4247
    "A",
4248
    "Dest",
4249
    "H",
4250
    "PA",
4251
    "QuadPoints",
4252
    /* FreeText annotations */
4253
    "DA",
4254
    "Q",
4255
    "DS",
4256
    "CL",
4257
    "IT",
4258
    "BE",
4259
    "RD",
4260
    "BS",
4261
    "LE",
4262
    /* Line Annotations */
4263
    "L",
4264
    "LE",
4265
    "IC",
4266
    "LL",
4267
    "LLE",
4268
    "Cap",
4269
    "LLO",
4270
    "CP",
4271
    "Measure",
4272
    "CO",
4273
    /* Square and Circle annotations */
4274
    "Path",
4275
    /* Polygon and PolyLine annotations */
4276
    "Vertices",
4277
    /* Text Markup annotations */
4278
    /* Caret annotations */
4279
    "Sy",
4280
    /* Rubber Stamp annotations */
4281
    /* Ink annotations */
4282
    "InkList",
4283
    /* Popup annotations */
4284
    "Open",
4285
    /* File attachment annotation */
4286
    "FS",
4287
    /* Sound annotations */
4288
    "Sound",
4289
    /* Movie annotations */
4290
    "Movie",
4291
    /* Screen annotations */
4292
    "MK",
4293
    "AA",
4294
    /* We don't handle Widget annotations as annotations, we draw them */
4295
    /* Printer's Mark annotations */
4296
    /* Trap Network annotations */
4297
    /* Watermark annotations */
4298
    "FixedPrint",
4299
    "Matrix",
4300
    "H",
4301
    "V",
4302
    /* Redaction annotations */
4303
    "RO",
4304
    "OverlayText",
4305
    "Repeat",
4306
    /* Projection annotations */
4307
    /* 3D and RichMedia annotations */
4308
};
4309
4310
static int isKnownKey(pdf_context *ctx, pdf_name *Key)
4311
507k
{
4312
507k
    int i = 0;
4313
4314
9.14M
    for (i = 0; i < sizeof(PermittedKeys) / sizeof (const char *); i++) {
4315
9.07M
        if (pdfi_name_is(Key, PermittedKeys[i]))
4316
438k
            return 1;
4317
9.07M
    }
4318
69.0k
    return 0;
4319
507k
}
4320
4321
static int pdfi_annot_preserve_mark(pdf_context *ctx, pdf_dict *annot, pdf_name *subtype)
4322
67.1k
{
4323
67.1k
    int code = 0;
4324
67.1k
    gs_matrix ctm;
4325
67.1k
    pdf_dict *tempdict = NULL;
4326
67.1k
    uint64_t dictsize;
4327
67.1k
    uint64_t index;
4328
67.1k
    pdf_name *Key = NULL;
4329
67.1k
    pdf_obj *Value = NULL;
4330
67.1k
    bool resolve = false;
4331
4332
    /* Create a temporary copy of the annot dict */
4333
67.1k
    dictsize = pdfi_dict_entries(annot);
4334
67.1k
    code = pdfi_dict_alloc(ctx, dictsize, &tempdict);
4335
67.1k
    if (code < 0) goto exit;
4336
67.1k
    pdfi_countup(tempdict);
4337
67.1k
    code = pdfi_dict_copy(ctx, tempdict, annot);
4338
67.1k
    if (code < 0) goto exit;
4339
4340
4341
     /* see also: 'loadannot' in gs code */
4342
    /* Go through the dict, deleting and modifying some entries
4343
     * Note that I am iterating through the original dict because I will
4344
     * be deleting some keys from tempdict and the iterators wouldn't work right.
4345
     */
4346
67.1k
    code = pdfi_dict_key_first(ctx, annot, (pdf_obj **)&Key, &index);
4347
507k
    while (code >= 0) {
4348
507k
        resolve = false;
4349
4350
507k
        if (!isKnownKey(ctx, Key)) {
4351
69.0k
            code = pdfi_dict_delete_pair(ctx, tempdict, Key);
4352
69.0k
            if (code < 0) goto exit;
4353
438k
        } else {
4354
438k
            if (pdfi_name_is(Key, "AP")) {
4355
                /* Special handling for AP -- have fun! */
4356
29.6k
                code = pdfi_annot_preserve_modAP(ctx, tempdict, Key);
4357
29.6k
                if (code < 0) goto exit;
4358
408k
            } else if (pdfi_name_is(Key, "QuadPoints")) {
4359
70
                code = pdfi_annot_preserve_modQP(ctx, tempdict, Key);
4360
70
                if (code < 0) goto exit;
4361
408k
            } else if (pdfi_name_is(Key, "A")) {
4362
8.18k
                code = pdfi_pdfmark_modA(ctx, tempdict);
4363
8.18k
                if (code < 0) goto exit;
4364
400k
            } else if (pdfi_name_is(Key, "Dest")) {
4365
4
                if (ctx->args.no_pdfmark_dests) {
4366
                    /* If omitting dests, such as for multi-page output, then omit this whole annotation */
4367
0
                    code = 0;
4368
0
                    goto exit;
4369
0
                }
4370
4
                code = pdfi_pdfmark_modDest(ctx, tempdict);
4371
4
                if (code < 0) goto exit;
4372
400k
            } else if (pdfi_name_is(Key, "StructTreeRoot")) {
4373
                /* TODO: Bug691785 has Link annots with /StructTreeRoot
4374
                 * It is super-circular, and causes issues.
4375
                 * GS code only adds in certain values for Link so it doesn't
4376
                 * run into a problem.  I am just going to delete it.
4377
                 * There should be a better solution to handle circular stuff
4378
                 * generically.
4379
                 */
4380
0
                code = pdfi_dict_delete_pair(ctx, tempdict, Key);
4381
0
                if (code < 0) goto exit;
4382
400k
            } else if (pdfi_name_is(Key, "Sound") || pdfi_name_is(Key, "Movie")) {
4383
0
                resolve = false;
4384
400k
            } else {
4385
400k
                resolve = true;
4386
400k
            }
4387
438k
        }
4388
497k
        if (resolve) {
4389
400k
            code = pdfi_dict_get_by_key(ctx, annot, (const pdf_name *)Key, &Value);
4390
400k
            if (code < 0) goto exit;
4391
4392
            /* Pre-resolve indirect references of any arrays/dicts
4393
             * TODO: I am doing this because the gs code does it, but I
4394
             * noticed it only goes down one level, not recursively through
4395
             * everything.  I am not sure what the point is in that case.
4396
             * For now, also doing only one level.
4397
             */
4398
400k
            code = pdfi_resolve_indirect_loop_detect(ctx, (pdf_obj *)annot, Value, false);
4399
400k
            if (code < 0) goto exit;
4400
400k
        }
4401
4402
497k
        pdfi_countdown(Key);
4403
497k
        Key = NULL;
4404
497k
        pdfi_countdown(Value);
4405
497k
        Value = NULL;
4406
4407
497k
        code = pdfi_dict_key_next(ctx, annot, (pdf_obj **)&Key, &index);
4408
497k
        if (code == gs_error_undefined) {
4409
57.3k
            code = 0;
4410
57.3k
            break;
4411
57.3k
        }
4412
497k
    }
4413
57.3k
    if (code < 0) goto exit;
4414
4415
    /* Do pdfmark from the tempdict */
4416
57.3k
    gs_currentmatrix(ctx->pgs, &ctm);
4417
4418
57.3k
    if (pdfi_name_is(subtype, "Link"))
4419
8.00k
        code = pdfi_pdfmark_from_dict(ctx, tempdict, &ctm, "LNK");
4420
49.3k
    else
4421
49.3k
        code = pdfi_pdfmark_from_dict(ctx, tempdict, &ctm, "ANN");
4422
57.3k
    if (code < 0) goto exit;
4423
4424
67.1k
 exit:
4425
67.1k
    pdfi_countdown(tempdict);
4426
67.1k
    pdfi_countdown(Key);
4427
67.1k
    pdfi_countdown(Value);
4428
67.1k
    return code;
4429
57.3k
}
4430
4431
static int pdfi_annot_preserve_default(pdf_context *ctx, pdf_dict *annot, pdf_name *subtype)
4432
58.9k
{
4433
58.9k
    return pdfi_annot_preserve_mark(ctx, annot, subtype);
4434
58.9k
}
4435
4436
static int pdfi_annot_preserve_Link(pdf_context *ctx, pdf_dict *annot, pdf_name *subtype)
4437
8.19k
{
4438
8.19k
    int code = 0;
4439
4440
    /* TODO: The gs code does a whole bunch of stuff I don't understand yet.
4441
     * I think doing the default behavior might work in most cases?
4442
     * See: pdf_draw.ps/preserveannottypes dict/Link()
4443
     */
4444
8.19k
    code = pdfi_annot_preserve_mark(ctx, annot, subtype);
4445
8.19k
    return code;
4446
8.19k
}
4447
4448
static int pdfi_annot_preserve_Widget(pdf_context *ctx, pdf_dict *annot, pdf_name *subtype)
4449
7.11k
{
4450
    /* According to the gs implementation:
4451
%% Widget annotations are only used with AcroForms, and since we don't preserve AcroForms
4452
%% we don't want to preserve widget annotations either, because the consumer of the new
4453
%% PDF won't know what values they should take. So we draw widget annotations instead. If we
4454
%% ever preserve AcroForms then we should alter this to preserve Widgets as well.
4455
     *
4456
     * TODO: See also, comment on pdfi_annot_render_field().
4457
     */
4458
4459
7.11k
    return pdfi_annot_draw(ctx, annot, subtype);
4460
7.11k
}
4461
4462
/* TODO: When I started writing this, I thought these handlers were necessary because
4463
 * the PS code has a bunch of special cases.  As it turns out, I think it could easily have
4464
 * been done without the handlers.   Maybe they should be taken out...
4465
 */
4466
annot_preserve_dispatch_t annot_preserve_dispatch[] = {
4467
    {"Link", pdfi_annot_preserve_Link},
4468
    {"Widget", pdfi_annot_preserve_Widget},
4469
    {"Circle", pdfi_annot_preserve_default},
4470
    {"FileAttachment", pdfi_annot_preserve_default},
4471
    {"FreeText", pdfi_annot_preserve_default},
4472
    {"Highlight", pdfi_annot_preserve_default},
4473
    {"Ink", pdfi_annot_preserve_default},
4474
    {"Line", pdfi_annot_preserve_default},
4475
    {"Movie", pdfi_annot_preserve_default},
4476
    {"PolyLine", pdfi_annot_preserve_default},
4477
    {"Popup", pdfi_annot_preserve_default},
4478
    //    {"Screen", pdfi_annot_preserve_default},  /* TODO: fts_07_0709.pdf */
4479
    {"Sound", pdfi_annot_preserve_default},
4480
    {"Square", pdfi_annot_preserve_default},
4481
    {"Squiggly", pdfi_annot_preserve_default},
4482
    {"StrikeOut", pdfi_annot_preserve_default},
4483
    {"Underline", pdfi_annot_preserve_default},
4484
    {"Stamp", pdfi_annot_preserve_default},
4485
    {"Text", pdfi_annot_preserve_default},
4486
    {"TrapNet", pdfi_annot_preserve_default},
4487
    { NULL, NULL},
4488
};
4489
4490
static int pdfi_annot_preserve(pdf_context *ctx, pdf_dict *annot, pdf_name *subtype)
4491
74.2k
{
4492
74.2k
    int code = 0;
4493
74.2k
    annot_preserve_dispatch_t *dispatch_ptr;
4494
4495
    /* If not preserving this subtype, draw it instead */
4496
74.2k
    if (!pdfi_annot_preserve_type(ctx, subtype))
4497
0
        return pdfi_annot_draw(ctx, annot, subtype);
4498
4499
    /* Handle the annotation */
4500
718k
    for (dispatch_ptr = annot_preserve_dispatch; dispatch_ptr->subtype; dispatch_ptr ++) {
4501
718k
        if (pdfi_name_is(subtype, dispatch_ptr->subtype)) {
4502
74.2k
            code = dispatch_ptr->func(ctx, annot, subtype);
4503
74.2k
            break;
4504
74.2k
        }
4505
718k
    }
4506
4507
    /* If there is no handler, just draw it */
4508
    /* NOTE: gs does a drawwidget here instead (?) */
4509
74.2k
    if (!dispatch_ptr->subtype)
4510
10
        code = pdfi_annot_draw(ctx, annot, subtype);
4511
4512
74.2k
    return code;
4513
74.2k
}
4514
4515
static int pdfi_annot_handle(pdf_context *ctx, pdf_dict *annot)
4516
495k
{
4517
495k
    int code = 0;
4518
495k
    pdf_name *Subtype = NULL;
4519
4520
495k
    code = pdfi_dict_get_type(ctx, annot, "Subtype", PDF_NAME, (pdf_obj **)&Subtype);
4521
495k
    if (code != 0) {
4522
        /* TODO: Set warning flag */
4523
287
        dbgmprintf(ctx->memory, "WARNING: Ignoring annotation with missing Subtype\n");
4524
287
        code = 0;
4525
287
        goto exit;
4526
287
    }
4527
4528
495k
    if (ctx->args.preserveannots && ctx->device_state.annotations_preserved)
4529
74.2k
        code = pdfi_annot_preserve(ctx, annot, Subtype);
4530
421k
    else
4531
421k
        code = pdfi_annot_draw(ctx, annot, Subtype);
4532
4533
495k
 exit:
4534
495k
    pdfi_countdown(Subtype);
4535
495k
    return code;
4536
495k
}
4537
4538
int pdfi_do_annotations(pdf_context *ctx, pdf_dict *page_dict)
4539
43.3k
{
4540
43.3k
    int code = 0;
4541
43.3k
    pdf_array *Annots = NULL;
4542
43.3k
    pdf_dict *annot = NULL;
4543
43.3k
    int i;
4544
4545
43.3k
    if (!ctx->args.showannots)
4546
0
        return 0;
4547
4548
43.3k
    code = pdfi_dict_knownget_type(ctx, page_dict, "Annots", PDF_ARRAY, (pdf_obj **)&Annots);
4549
43.3k
    if (code <= 0)
4550
25.3k
        return code;
4551
4552
548k
    for (i = 0; i < pdfi_array_size(Annots); i++) {
4553
530k
        code = pdfi_array_get_type(ctx, Annots, i, PDF_DICT, (pdf_obj **)&annot);
4554
530k
        if (code < 0)
4555
35.0k
            continue;
4556
495k
        code = pdfi_annot_handle(ctx, annot);
4557
495k
        if (code < 0 && ctx->args.pdfstoponerror)
4558
0
            goto exit;
4559
495k
        pdfi_countdown(annot);
4560
495k
        annot = NULL;
4561
495k
    }
4562
4563
18.0k
 exit:
4564
18.0k
    pdfi_countdown(annot);
4565
18.0k
    pdfi_countdown(Annots);
4566
18.0k
    return code;
4567
18.0k
}
4568
4569
/* draw terminal field */
4570
static int pdfi_form_draw_terminal(pdf_context *ctx, pdf_dict *Page, pdf_dict *field)
4571
0
{
4572
0
    int code = 0;
4573
0
    pdf_indirect_ref *P = NULL;
4574
0
    pdf_name *FT = NULL;
4575
0
    pdf_obj *AP = NULL;
4576
4577
    /* See if the field goes on this page */
4578
    /* NOTE: We know the "P" is an indirect ref, so just fetch it that way.
4579
     * If we fetch the actual object, it will result in a cyclical reference in the cache
4580
     * that causes a memory leak, so don't do that.
4581
     * (The cyclical reference is because the object containing P is actually inside P)
4582
     */
4583
0
    code = pdfi_dict_get_ref(ctx, field, "P", &P);
4584
0
    if (code < 0) {
4585
0
        if (code == gs_error_undefined)
4586
0
            code = 0;
4587
0
        goto exit;
4588
0
    }
4589
4590
0
    if (P->ref_object_num != Page->object_num) {
4591
        /* Not this page */
4592
0
        code = 0;
4593
0
        goto exit;
4594
0
    }
4595
4596
    /* Render the field */
4597
4598
    /* NOTE: The spec says the FT is inheritable, implying it might be present in
4599
     * a Parent and not explicitly in a Child.  The gs implementation doesn't seem
4600
     * to handle this case, but I am going to go ahead and handle it.  We will figure
4601
     * out if this causes diffs later, if ever...
4602
     */
4603
0
    code = pdfi_form_get_inheritable(ctx, field, "FT", PDF_NAME, (pdf_obj **)&FT);
4604
0
    if (code <= 0) goto exit;
4605
4606
0
    code = pdfi_annot_get_NormAP(ctx, field, &AP);
4607
0
    if (code < 0) goto exit;
4608
4609
0
    code = pdfi_annot_render_field(ctx, field, FT, AP);
4610
0
    if (code < 0) goto exit;
4611
4612
0
 exit:
4613
0
    pdfi_countdown(FT);
4614
0
    pdfi_countdown(P);
4615
0
    pdfi_countdown(AP);
4616
0
    return code;
4617
0
}
4618
4619
/* From pdf_draw.ps/draw_form_field():
4620
% We distinguish 4 types of nodes on the form field tree:
4621
%  - non-terminal field - has a kid that refers to the parent (or anywhere else)
4622
%  - terminal field with separate widget annotations - has a kid that doesn't have a parent
4623
%  - terminal field with a merged widget annotation - has no kids
4624
%  - widget annotation - has /Subtype and /Rect
4625
%
4626
% The recursive enumeration of the form fields doesn't descend into widget annotations.
4627
*/
4628
static int pdfi_form_draw_field(pdf_context *ctx, pdf_dict *Page, pdf_dict *field)
4629
0
{
4630
0
    int code = 0;
4631
0
    pdf_array *Kids = NULL;
4632
0
    pdf_dict *child = NULL;
4633
0
    pdf_dict *Parent = NULL;
4634
0
    int i;
4635
4636
0
    code = pdfi_dict_knownget_type(ctx, field, "Kids", PDF_ARRAY, (pdf_obj **)&Kids);
4637
0
    if (code < 0) goto exit;
4638
0
    if (code == 0) {
4639
0
        code = pdfi_form_draw_terminal(ctx, Page, field);
4640
0
        goto exit;
4641
0
    }
4642
4643
    /* Handle Kids */
4644
0
    if (pdfi_array_size(Kids) <= 0) {
4645
0
        dmprintf(ctx->memory, "*** Error: Ignoring empty /Kids array in Form field.\n");
4646
0
        dmprintf(ctx->memory, "    Output may be incorrect.\n");
4647
        /* TODO: Set warning flag */
4648
0
        code = 0;
4649
0
        goto exit;
4650
0
    }
4651
4652
    /* Check first child to see if it has a parent */
4653
0
    code = pdfi_array_get_type(ctx, Kids, 0, PDF_DICT, (pdf_obj **)&child);
4654
0
    if (code < 0) goto exit;
4655
0
    code = pdfi_dict_knownget_type(ctx, child, "Parent", PDF_DICT, (pdf_obj **)&Parent);
4656
0
    if (code < 0) goto exit;
4657
4658
    /* If kid has no parent, then treat this as terminal field */
4659
0
    if (code == 0) {
4660
        /* TODO: This case isn't tested because no examples available.
4661
         * I think it's only relevant for Btn, and not sure if it
4662
         * should be dealt with here or in Btn routine.
4663
         */
4664
0
        code = pdfi_form_draw_terminal(ctx, Page, field);
4665
0
        goto exit;
4666
0
    }
4667
4668
0
    pdfi_countdown(child);
4669
0
    child = NULL;
4670
    /* Render the Kids (recursive) */
4671
0
    for (i=0; i<pdfi_array_size(Kids); i++) {
4672
0
        code = pdfi_array_get_type(ctx, Kids, i, PDF_DICT, (pdf_obj **)&child);
4673
0
        if (code < 0) goto exit;
4674
4675
0
        code = pdfi_form_draw_field(ctx, Page, child);
4676
0
        if (code < 0) goto exit;
4677
4678
0
        pdfi_countdown(child);
4679
0
        child = NULL;
4680
0
    }
4681
4682
0
 exit:
4683
0
    pdfi_countdown(child);
4684
0
    pdfi_countdown(Kids);
4685
0
    pdfi_countdown(Parent);
4686
0
    return code;
4687
0
}
4688
4689
int pdfi_do_acroform(pdf_context *ctx, pdf_dict *page_dict)
4690
43.3k
{
4691
43.3k
    int code = 0;
4692
43.3k
    pdf_array *Fields = NULL;
4693
43.3k
    pdf_dict *field = NULL;
4694
43.3k
    int i;
4695
4696
43.3k
    if (!ctx->args.showacroform)
4697
43.3k
        return 0;
4698
4699
0
    if (!ctx->AcroForm)
4700
0
        return 0;
4701
4702
0
    code = pdfi_dict_knownget_type(ctx, ctx->AcroForm, "Fields", PDF_ARRAY, (pdf_obj **)&Fields);
4703
0
    if (code <= 0)
4704
0
        goto exit;
4705
4706
0
    for (i=0; i<pdfi_array_size(Fields); i++) {
4707
0
        code = pdfi_array_get_type(ctx, Fields, i, PDF_DICT, (pdf_obj **)&field);
4708
0
        if (code < 0)
4709
0
            continue;
4710
0
        code = pdfi_form_draw_field(ctx, page_dict, field);
4711
0
        if (code < 0)
4712
0
            goto exit;
4713
0
        pdfi_countdown(field);
4714
0
        field = NULL;
4715
0
    }
4716
4717
0
 exit:
4718
0
    pdfi_countdown(field);
4719
0
    pdfi_countdown(Fields);
4720
0
    return code;
4721
0
}