Coverage Report

Created: 2026-09-14 07:34

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