Coverage Report

Created: 2025-08-28 07:06

/src/ghostpdl/pdf/pdf_annot.c
Line
Count
Source (jump to first uncovered line)
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
178
#define IS_UTF8(str) (!strcmp((char *)(str), "\xef\xbb\xbf"))
50
50.1k
#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.11k
{
77
6.11k
    int code;
78
79
6.11k
    if (!ctx->page.has_transparency)
80
2.73k
        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.38k
    code = gs_clippath(ctx->pgs);
87
3.38k
    if (code < 0)
88
0
        return code;
89
3.38k
    code = pdfi_trans_begin_simple_group(ctx, NULL, false, false, false);
90
3.38k
    (void)gs_newpath(ctx->pgs);
91
3.38k
    return code;
92
3.38k
}
93
94
static int pdfi_annot_end_transparency(pdf_context *ctx, pdf_dict *annot)
95
6.10k
{
96
6.10k
    if (!ctx->page.has_transparency)
97
2.73k
        return 0;
98
99
3.37k
    return pdfi_trans_end_simple_group(ctx);
100
6.10k
}
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
504
{
107
504
    int code;
108
504
    pdf_dict *BS = NULL;
109
110
504
    *width = 1.0;
111
112
504
    code = pdfi_dict_knownget_type(ctx, annot, "BS", PDF_DICT, (pdf_obj **)&BS);
113
504
    if (code <= 0)
114
0
        goto exit;
115
116
504
    code = pdfi_dict_knownget_number(ctx, BS, "W", width);
117
118
504
 exit:
119
504
    pdfi_countdown(BS);
120
504
    return code;
121
504
}
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.36k
{
128
1.36k
    int code = 0;
129
1.36k
    double CA;
130
131
    /* CA -- opacity */
132
1.36k
    code = pdfi_dict_knownget_number(ctx, annot, "CA", &CA);
133
1.36k
    if (code > 0) {
134
656
        code = gs_setstrokeconstantalpha(ctx->pgs, CA);
135
656
        if (code < 0) goto exit;
136
656
        code = gs_setfillconstantalpha(ctx->pgs, CA);
137
656
        goto exit;
138
656
    }
139
    /* If CA not found, we also check for 'ca' even though it's not in the spec */
140
710
    code = pdfi_dict_knownget_number(ctx, annot, "ca", &CA);
141
710
    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.36k
 exit:
147
1.36k
    return code;
148
710
}
149
150
/* Apply RD to provided rect */
151
static int pdfi_annot_applyRD(pdf_context *ctx, pdf_dict *annot, gs_rect *rect)
152
1.87k
{
153
1.87k
    int code;
154
1.87k
    pdf_array *RD = NULL;
155
1.87k
    gs_rect rd;
156
157
1.87k
    code = pdfi_dict_knownget_type(ctx, annot, "RD", PDF_ARRAY, (pdf_obj **)&RD);
158
1.87k
    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.87k
 exit:
169
1.87k
    pdfi_countdown(RD);
170
1.87k
    return code;
171
7
}
172
173
static int pdfi_annot_Rect(pdf_context *ctx, pdf_dict *annot, gs_rect *rect)
174
321k
{
175
321k
    int code;
176
321k
    pdf_array *Rect = NULL;
177
178
321k
    code = pdfi_dict_knownget_type(ctx, annot, "Rect", PDF_ARRAY, (pdf_obj **)&Rect);
179
321k
    if (code < 0) goto exit;
180
181
321k
    code = pdfi_array_to_gs_rect(ctx, Rect, rect);
182
321k
    if (code < 0) goto exit;
183
184
320k
    pdfi_normalize_rect(ctx, rect);
185
186
321k
 exit:
187
321k
    pdfi_countdown(Rect);
188
321k
    return code;
189
320k
}
190
191
static int pdfi_annot_position_AP(pdf_context *ctx, pdf_dict *annot, pdf_stream *AP)
192
208k
{
193
208k
    int code = 0;
194
208k
    gs_rect rect;
195
208k
    pdf_array *BBox = NULL;
196
208k
    gs_rect bbox;
197
208k
    pdf_array *Matrix = NULL;
198
208k
    gs_matrix matrix;
199
208k
    double xscale, yscale;
200
208k
    pdf_dict *Annot_dict;
201
202
208k
    code = pdfi_dict_from_obj(ctx, (pdf_obj *)AP, &Annot_dict);
203
208k
    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
208k
    ctx->text.BlockDepth = 0;
217
    /* TODO: FIXME */
218
219
208k
    code = pdfi_annot_Rect(ctx, annot, &rect);
220
208k
    if (code < 0) goto exit;
221
222
207k
    code = pdfi_dict_knownget_type(ctx, Annot_dict, "BBox", PDF_ARRAY, (pdf_obj **)&BBox);
223
207k
    if (code < 0) goto exit;
224
207k
    code = pdfi_array_to_gs_rect(ctx, BBox, &bbox);
225
207k
    if (code < 0) goto exit;
226
227
207k
    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
156
        pdfi_countdown(BBox);
234
156
        BBox = NULL;
235
156
    }
236
237
207k
    code = pdfi_dict_knownget_type(ctx, Annot_dict, "Matrix", PDF_ARRAY, (pdf_obj **)&Matrix);
238
207k
    if (code < 0) goto exit;
239
207k
    code = pdfi_array_to_gs_matrix(ctx, Matrix, &matrix);
240
207k
    if (code < 0) goto exit;
241
242
207k
    xscale = yscale = 1.0;
243
244
207k
    code = gs_translate(ctx->pgs, rect.p.x, rect.p.y);
245
207k
    if (code < 0) goto exit;
246
247
207k
    if (BBox != NULL) {
248
207k
        pdfi_bbox_transform(ctx, &bbox, &matrix);
249
250
        /* Calculate scale factor */
251
207k
        xscale = (rect.q.x - rect.p.x) / (bbox.q.x - bbox.p.x);
252
207k
        yscale = (rect.q.y - rect.p.y) / (bbox.q.y - bbox.p.y);
253
254
207k
        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
207k
        code = gs_scale(ctx->pgs, xscale, yscale);
261
207k
        if (code < 0) goto exit;
262
263
        /* Compensate for non-zero origin of BBox */
264
207k
        code = gs_translate(ctx->pgs, -bbox.p.x, -bbox.p.y);
265
207k
        if (code < 0) goto exit;
266
207k
    }
267
268
208k
 exit:
269
208k
    pdfi_countdown(BBox);
270
208k
    pdfi_countdown(Matrix);
271
208k
    return code;
272
207k
}
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
209k
{
277
209k
    int code = 0;
278
279
209k
    if (NormAP == NULL)
280
1.93k
        return 0;
281
207k
    if (pdfi_type_of(NormAP) == PDF_NULL)
282
15.7k
        return 0;
283
191k
    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
191k
    code = pdfi_op_q(ctx);
287
191k
    if (code < 0)
288
0
        return code;
289
290
191k
    code = pdfi_annot_position_AP(ctx, annot, (pdf_stream *)NormAP);
291
191k
    if (code < 0)
292
339
        goto exit;
293
294
    /* Render the annotation */
295
191k
    code = pdfi_do_image_or_form(ctx, NULL, ctx->page.CurrentPageDict, NormAP);
296
297
191k
exit:
298
191k
    (void)pdfi_op_Q(ctx);
299
191k
    return code;
300
191k
}
301
302
static int pdfi_annot_setcolor_key(pdf_context *ctx, pdf_dict *annot, const char *key,
303
                                   bool usedefault, bool *drawit)
304
125k
{
305
125k
    int code = 0;
306
125k
    pdf_array *C = NULL;
307
308
125k
    *drawit = true;
309
310
125k
    code = pdfi_dict_knownget_type(ctx, annot, key, PDF_ARRAY, (pdf_obj **)&C);
311
125k
    if (code < 0) goto exit;
312
313
125k
    if (code == 0) {
314
118k
        if (usedefault)
315
1.70k
            code = pdfi_gs_setgray(ctx, 0);
316
116k
        else
317
116k
            *drawit = false;
318
118k
    } else {
319
7.35k
        if (pdfi_array_size(C) == 0) {
320
16
            code = 0;
321
16
            *drawit = false;
322
7.34k
        } else {
323
7.34k
            code = pdfi_setcolor_from_array(ctx, C);
324
7.34k
        }
325
7.35k
    }
326
327
125k
 exit:
328
125k
    if (code < 0)
329
45
        *drawit = false;
330
125k
    pdfi_countdown(C);
331
125k
    return code;
332
125k
}
333
334
static int pdfi_annot_setinteriorcolor(pdf_context *ctx, pdf_dict *annot, bool usedefault, bool *drawit)
335
902
{
336
902
    return pdfi_annot_setcolor_key(ctx, annot, "IC", usedefault, drawit);
337
902
}
338
339
static int pdfi_annot_setcolor(pdf_context *ctx, pdf_dict *annot, bool usedefault, bool *drawit)
340
8.08k
{
341
8.08k
    return pdfi_annot_setcolor_key(ctx, annot, "C", usedefault, drawit);
342
8.08k
}
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
2.45k
{
347
2.45k
    int code = 0;
348
349
2.45k
    if (width <= 0)
350
0
        return 0;
351
352
2.45k
    code = pdfi_setdash_impl(ctx, dash, 0);
353
2.45k
    if (code < 0) goto exit;
354
2.45k
    code = gs_setlinewidth(ctx->pgs, width);
355
2.45k
    if (code < 0) goto exit;
356
357
2.45k
    code = gs_stroke(ctx->pgs);
358
359
2.45k
 exit:
360
2.45k
    return code;
361
2.45k
}
362
363
/* Fill border path */
364
static int pdfi_annot_fillborderpath(pdf_context *ctx, pdf_dict *annot)
365
746
{
366
746
    int code;
367
746
    bool drawit;
368
369
746
    code = pdfi_gsave(ctx);
370
746
    if (code < 0) return code;
371
372
746
    code = pdfi_annot_opacity(ctx, annot);
373
746
    if (code < 0) goto exit;
374
746
    code = pdfi_annot_setinteriorcolor(ctx, annot, false, &drawit);
375
746
    if (code < 0) goto exit;
376
741
    if (drawit)
377
602
        code = gs_fill(ctx->pgs);
378
379
746
 exit:
380
746
    (void)pdfi_grestore(ctx);
381
746
    return code;
382
741
}
383
384
385
/* Draw a path from a rectangle */
386
static int pdfi_annot_rect_path(pdf_context *ctx, gs_rect *rect)
387
88
{
388
88
    int code;
389
390
88
    code = gs_moveto(ctx->pgs, rect->p.x, rect->p.y);
391
88
    if (code < 0) goto exit;
392
88
    code = gs_lineto(ctx->pgs, rect->q.x, rect->p.y);
393
88
    if (code < 0) goto exit;
394
88
    code = gs_lineto(ctx->pgs, rect->q.x, rect->q.y);
395
88
    if (code < 0) goto exit;
396
88
    code = gs_lineto(ctx->pgs, rect->p.x, rect->q.y);
397
88
    if (code < 0) goto exit;
398
88
    code = gs_closepath(ctx->pgs);
399
400
88
 exit:
401
88
    return code;
402
88
}
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
88
{
410
88
    gs_rect rect;
411
88
    int code;
412
413
88
    code = pdfi_annot_Rect(ctx, annot, &rect);
414
88
    if (code < 0) goto exit;
415
416
88
    code = pdfi_annot_applyRD(ctx, annot, &rect);
417
88
    if (code < 0) goto exit;
418
419
88
    code = pdfi_annot_rect_path(ctx, &rect);
420
421
88
 exit:
422
88
    return code;
423
88
}
424
425
/* Adjust rectangle by specified width */
426
static void pdfi_annot_rect_adjust(pdf_context *ctx, gs_rect *rect, double width)
427
1.43k
{
428
1.43k
    rect->p.x += width;
429
1.43k
    rect->p.y += width;
430
1.43k
    rect->q.x -= width;
431
1.43k
    rect->q.y -= width;
432
1.43k
}
433
434
/* Fill Rect with current color */
435
static int pdfi_annot_fillRect(pdf_context *ctx, pdf_dict *annot)
436
51
{
437
51
    int code;
438
51
    gs_rect rect;
439
440
51
    code = pdfi_gsave(ctx);
441
51
    if (code < 0) return code;
442
443
51
    code = pdfi_annot_Rect(ctx, annot, &rect);
444
51
    if (code < 0) goto exit;
445
446
51
    code = gs_rectclip(ctx->pgs, &rect, 1);
447
51
    if (code < 0) goto exit;
448
449
51
    code = pdfi_annot_applyRD(ctx, annot, &rect);
450
51
    if (code < 0) goto exit;
451
452
51
    code = gs_rectfill(ctx->pgs, &rect, 1);
453
51
    if (code < 0) goto exit;
454
455
51
 exit:
456
51
    (void)pdfi_grestore(ctx);
457
51
    return code;
458
51
}
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
3.20k
{
463
3.20k
    int code = 0;
464
3.20k
    gs_rect rect;
465
466
3.20k
    if (width <= 0)
467
1.76k
        return 0;
468
469
1.43k
    code = pdfi_gsave(ctx);
470
471
1.43k
    code = pdfi_setdash_impl(ctx, dash, 0);
472
1.43k
    if (code < 0) goto exit;
473
474
1.43k
    code = gs_setlinewidth(ctx->pgs, width);
475
1.43k
    if (code < 0) goto exit;
476
477
1.43k
    code = pdfi_annot_Rect(ctx, annot, &rect);
478
1.43k
    if (code < 0) goto exit;
479
480
1.43k
    code = pdfi_annot_applyRD(ctx, annot, &rect);
481
1.43k
    if (code < 0) goto exit;
482
483
484
    /* Stroke the rectangle */
485
    /* Adjust rectangle by the width */
486
1.43k
    pdfi_annot_rect_adjust(ctx, &rect, width/2);
487
1.43k
    code = gs_rectstroke(ctx->pgs, &rect, 1, NULL);
488
489
1.43k
 exit:
490
1.43k
    (void)pdfi_grestore(ctx);
491
1.43k
    return code;
492
1.43k
}
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
3.24k
{
499
3.24k
    pdf_array *dash = NULL;
500
3.24k
    int code = 0;
501
3.24k
    uint64_t size = 0;
502
3.24k
    double width = 0;
503
504
3.24k
    if (Border)
505
3.20k
        size = pdfi_array_size(Border);
506
3.24k
    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
3.24k
    if (!Border) {
511
39
        code = pdfi_array_alloc(ctx, 0, &dash);
512
39
        if (code < 0) goto exit;
513
39
        pdfi_countup(dash);
514
39
        width = 1;
515
3.20k
    } else {
516
3.20k
        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
3.20k
        } else {
528
3.20k
            code = pdfi_array_alloc(ctx, 0, &dash);
529
3.20k
            if (code < 0) goto exit;
530
3.20k
            pdfi_countup(dash);
531
3.20k
        }
532
3.20k
        code = pdfi_array_get_number(ctx, Border, 2, &width);
533
3.20k
        if (code < 0) goto exit;
534
3.20k
    }
535
536
    /* At this point we have a dash array (which could be length 0) and a width */
537
3.24k
    if (usepath)
538
206
        code = pdfi_annot_strokeborderpath(ctx, annot, width, dash);
539
3.04k
    else
540
3.04k
        code = pdfi_annot_strokeborder(ctx, annot, width, dash);
541
542
3.24k
 exit:
543
3.24k
    pdfi_countdown(dash);
544
3.24k
    return code;
545
3.24k
}
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
2.41k
{
550
2.41k
    double W;
551
2.41k
    int code = 0;
552
2.41k
    pdf_name *S = NULL;
553
2.41k
    pdf_array *dash = NULL;
554
555
    /* Get the width */
556
2.41k
    code = pdfi_dict_knownget_number(ctx, BS, "W", &W);
557
2.41k
    if (code < 0) goto exit;
558
2.41k
    if (code == 0)
559
8
        W = 1; /* Default */
560
561
    /* TODO: Some junk about scaling to UserUnit */
562
    /* ... */
563
564
    /* Lookup border style */
565
2.41k
    code = pdfi_dict_knownget_type(ctx, BS, "S", PDF_NAME, (pdf_obj **)&S);
566
2.41k
    if (code < 0) goto exit;
567
568
2.41k
    if (code > 0 && pdfi_name_is(S, "D")) {
569
        /* Handle Dash array */
570
10
        code = pdfi_dict_knownget_type(ctx, BS, "D", PDF_ARRAY, (pdf_obj **)&dash);
571
10
        if (code < 0) goto exit;
572
573
        /* If there is no Dash array, then create one containing a 3 (the default) */
574
10
        if (code == 0) {
575
10
            code = pdfi_array_alloc(ctx, 1, &dash);
576
10
            if (code < 0) goto exit;
577
10
            pdfi_countup(dash);
578
579
10
            code = pdfi_array_put_int(ctx, dash, 0, 3);
580
10
            if (code < 0) goto exit;
581
10
        }
582
2.40k
    } else {
583
        /* Empty array */
584
2.40k
        code = pdfi_array_alloc(ctx, 0, &dash);
585
2.40k
        if (code < 0) goto exit;
586
2.40k
        pdfi_countup(dash);
587
2.40k
    }
588
589
    /* At this point we have a dash array (which could be length 0) and a width */
590
2.41k
    if (usepath)
591
2.25k
        code = pdfi_annot_strokeborderpath(ctx, annot, W, dash);
592
160
    else
593
160
        code = pdfi_annot_strokeborder(ctx, annot, W, dash);
594
595
2.41k
 exit:
596
2.41k
    pdfi_countdown(S);
597
2.41k
    pdfi_countdown(dash);
598
2.41k
    return code;
599
2.41k
}
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.66k
{
612
5.66k
    int code, code1;
613
5.66k
    pdf_dict *BS = NULL;
614
5.66k
    pdf_array *Border = NULL;
615
616
5.66k
    code = pdfi_dict_knownget_type(ctx, annot, "BS", PDF_DICT, (pdf_obj **)&BS);
617
5.66k
    if (code < 0) goto exit;
618
5.65k
    code = pdfi_dict_knownget_type(ctx, annot, "Border", PDF_ARRAY, (pdf_obj **)&Border);
619
5.65k
    if (code < 0) goto exit;
620
621
5.65k
    code = pdfi_gsave(ctx);
622
5.65k
    if (code < 0) goto exit;
623
624
5.65k
    if (BS) {
625
2.41k
        code = pdfi_annot_draw_BS(ctx, annot, BS, usepath);
626
3.24k
    } else {
627
        /* Note: Border can be null */
628
3.24k
        code = pdfi_annot_draw_Border(ctx, annot, Border, usepath);
629
3.24k
    }
630
5.65k
    code1 = pdfi_grestore(ctx);
631
5.65k
    if (code == 0) code = code1;
632
633
5.66k
 exit:
634
5.66k
    pdfi_countdown(BS);
635
5.66k
    pdfi_countdown(Border);
636
5.66k
    return code;
637
5.65k
}
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
461
{
645
461
    int code = 0;
646
647
461
    if (font != NULL) {
648
461
        code = pdfi_font_set_internal_string(ctx, font, size);
649
461
        if (code < 0) goto exit;
650
461
    }
651
652
461
 exit:
653
461
    return code;
654
461
}
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
249k
{
663
249k
    int code = 0;
664
249k
    pdf_dict *Parent = NULL;
665
249k
    bool known = false;
666
667
    /* Check this field */
668
249k
    code = pdfi_dict_knownget_type(ctx, field, Key, type, o);
669
249k
    if (code != 0) goto exit1;
670
671
82.4k
    code = pdfi_loop_detector_mark(ctx);
672
82.4k
    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
82.4k
    code = pdfi_dict_known(ctx, field, "Parent", &known);
679
82.4k
    if (code >= 0 && known == true)
680
57.9k
    {
681
57.9k
        code = pdfi_dict_get_no_store_R(ctx, field, "Parent", (pdf_obj **)&Parent);
682
57.9k
        if (code < 0)
683
8.96k
            goto exit;
684
685
49.0k
        if (pdfi_type_of(Parent) != PDF_DICT) {
686
109
            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
109
            } else {
693
109
                code = gs_note_error(gs_error_typecheck);
694
109
                goto exit;
695
109
            }
696
109
        }
697
48.9k
        code = pdfi_form_get_inheritable(ctx, Parent, Key, type, o);
698
48.9k
        if (code <= 0) {
699
48.8k
            if (ctx->AcroForm)
700
48.7k
                code = pdfi_dict_knownget_type(ctx, ctx->AcroForm, Key, type, o);
701
48.8k
        }
702
48.9k
    } else {
703
        /* No Parent, so check AcroForm, if any */
704
24.4k
        if (ctx->AcroForm)
705
24.1k
            code = pdfi_dict_knownget_type(ctx, ctx->AcroForm, Key, type, o);
706
24.4k
    }
707
708
82.4k
exit:
709
82.4k
    (void)pdfi_loop_detector_cleartomark(ctx);
710
711
249k
exit1:
712
249k
    pdfi_countdown(Parent);
713
249k
    return code;
714
82.4k
}
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
147k
{
722
147k
    int code = 0;
723
147k
    pdf_num *num = NULL;
724
725
147k
    *val = 0;
726
147k
    code = pdfi_form_get_inheritable(ctx, field, Key, PDF_INT, (pdf_obj **)&num);
727
147k
    if (code < 0) goto exit;
728
729
139k
    if (code > 0)
730
114k
        *val = num->value.i;
731
732
147k
 exit:
733
147k
    pdfi_countdown(num);
734
147k
    return code;
735
139k
}
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
52.3k
{
740
52.3k
    char *token, *prev_token;
741
52.3k
    char *parse_str = NULL;
742
52.3k
    bool did_mod = false;
743
52.3k
    int code = 0;
744
52.3k
    double size;
745
52.3k
    char size_str[20];
746
52.3k
    char *last;
747
52.3k
    pdf_string *newDA = NULL;
748
749
    /* Make a copy of the string because we are going to destructively parse it */
750
52.3k
    parse_str = (char *)gs_alloc_bytes(ctx->memory, (size_t)DA->length+1, "pdfi_annot_display_text(strbuf)");
751
52.3k
    if (parse_str == NULL) {
752
0
        code = gs_note_error(gs_error_VMerror);
753
0
        goto exit;
754
0
    }
755
52.3k
    memcpy(parse_str, DA->data, DA->length);
756
52.3k
    parse_str[DA->length] = 0; /* Null terminate */
757
758
    /* find the 'Tf' token, if any */
759
52.3k
    token = gs_strtok(parse_str, " ", &last);
760
52.3k
    prev_token = NULL;
761
157k
    while (token != NULL) {
762
157k
        if (!strcmp(token, "Tf"))
763
52.3k
            break;
764
104k
        prev_token = token;
765
104k
        token = gs_strtok(NULL, " ", &last);
766
104k
    }
767
768
    /* See if we found it */
769
52.3k
    if (!token)
770
51
        goto exit;
771
772
    /* See if there was a prev_token and it was "0" */
773
52.3k
    if (!(prev_token && !strcmp(prev_token, "0")))
774
52.3k
        goto exit;
775
776
    /* Case with '<font> 0 Tf', need to calculate correct size */
777
18
    size = (rect->q.y - rect->p.y) * .75; /* empirical from gs code make_tx_da */
778
779
18
    snprintf(size_str, sizeof(size_str), "%g ", size);
780
781
    /* Create a new DA and reassemble the old DA into it */
782
18
    code = pdfi_object_alloc(ctx, PDF_STRING, (size_t)DA->length+strlen(size_str)+1, (pdf_obj **)&newDA);
783
18
    if (code < 0)
784
0
        goto exit;
785
18
    pdfi_countup(newDA);
786
787
18
    strncpy((char *)newDA->data, (char *)DA->data, prev_token-parse_str);
788
18
    strncpy((char *)newDA->data + (prev_token-parse_str), size_str, strlen(size_str)+1);
789
18
    strncpy((char *)newDA->data + strlen((char *)newDA->data), (char *)DA->data + (token - parse_str),
790
18
            DA->length-(token-parse_str));
791
18
    newDA->length = strlen((char *)newDA->data);
792
18
    did_mod = true;
793
794
52.3k
 exit:
795
    /* If didn't need to mod it, just copy the original and get a ref */
796
52.3k
    if (did_mod) {
797
18
        *mod_DA = newDA;
798
52.3k
    } else {
799
52.3k
        *mod_DA = DA;
800
52.3k
        pdfi_countup(DA);
801
52.3k
    }
802
803
52.3k
    if (parse_str)
804
52.3k
        gs_free_object(ctx->memory, parse_str, "pdfi_form_modDA(parse_str)");
805
806
52.3k
    return code;
807
18
}
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
52.4k
{
821
52.4k
    int code = 0;
822
52.4k
    pdf_string *DA = NULL;
823
52.4k
    pdf_string *mod_DA = NULL;
824
52.4k
    pdf_dict *resource_dict = annot;  /* dict to use for resources, alias no need to refcnt */
825
52.4k
    pdf_dict *DR = NULL;
826
52.4k
    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
52.4k
    if (!page_dict)
831
65
        page_dict = ctx->page.CurrentPageDict;
832
833
52.4k
    if (is_form) {
834
52.4k
        code = pdfi_dict_known(ctx, annot, "DR", &known);
835
52.4k
        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
52.4k
        if (!known) {
840
52.3k
            code = pdfi_dict_known(ctx, annot, "Parent", &known);
841
52.3k
            if (code < 0) goto exit;
842
52.3k
            if (!known && ctx->AcroForm != NULL)
843
1.03k
                resource_dict = ctx->AcroForm;
844
52.3k
        }
845
52.4k
        code = pdfi_form_get_inheritable(ctx, annot, "DA", PDF_STRING, (pdf_obj **)&DA);
846
52.4k
    } else {
847
65
        code = pdfi_dict_knownget_type(ctx, annot, "DA", PDF_STRING, (pdf_obj **)&DA);
848
65
    }
849
52.4k
    if (code < 0) goto exit;
850
52.4k
    if (code > 0) {
851
52.4k
        if (is_form) {
852
52.3k
            code = pdfi_form_modDA(ctx, DA, &mod_DA, rect);
853
52.3k
            if (code < 0) goto exit;
854
52.3k
        } else {
855
62
            mod_DA = DA;
856
62
            pdfi_countup(mod_DA);
857
62
        }
858
859
52.4k
        code = pdfi_interpret_inner_content_string(ctx, mod_DA, resource_dict,
860
52.4k
                                                   page_dict, false, "DA");
861
52.4k
        if (code < 0) goto exit;
862
        /* If no font got set, set one */
863
52.4k
        if (pdfi_get_current_pdf_font(ctx) == NULL) {
864
87
            code = pdfi_annot_set_font(ctx, "Helvetica", 12.0);
865
87
            if (code < 0) goto exit;
866
87
        }
867
52.4k
    } else {
868
10
        code = pdfi_gs_setgray(ctx, 0);
869
10
        if (code < 0) goto exit;
870
10
        code = pdfi_annot_set_font(ctx, "Helvetica", 12.0);
871
10
        if (code < 0) goto exit;
872
10
    }
873
874
52.4k
 exit:
875
52.4k
    pdfi_countdown(DR);
876
52.4k
    pdfi_countdown(DA);
877
52.4k
    pdfi_countdown(mod_DA);
878
52.4k
    return code;
879
52.4k
}
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
24.9k
{
886
24.9k
    int i;
887
24.9k
    char *ptr;
888
889
24.9k
    i = 0;
890
    /* skip over BOM if it's there */
891
24.9k
    if (IS_UTF16(inbuf)) {
892
0
        i += 2; /* UTF-16 */
893
24.9k
    } else if (IS_UTF16(inbuf)) {
894
0
        i += 3; /* UTF-8 */
895
0
    }
896
897
24.9k
    ptr = outbuf;
898
24.9k
    *ptr++ = '<';
899
51.9k
    for ( ; i<len; i++) {
900
26.9k
        snprintf(ptr, 3, "%02X", *(inbuf+i));
901
26.9k
        ptr += 2;
902
26.9k
    }
903
904
24.9k
    *ptr++ = '>';
905
24.9k
    *ptr = 0;
906
907
24.9k
    return ptr;
908
24.9k
}
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
23.2k
{
914
23.2k
    char *strbuf = NULL;
915
23.2k
    size_t buflen = 50 + text->length*2; /* 50 to account for formatting, plus the text itself */
916
23.2k
    int code = 0;
917
23.2k
    char *ptr;
918
919
23.2k
    strbuf = (char *)gs_alloc_bytes(ctx->memory, buflen, "pdfi_annot_display_text(strbuf)");
920
23.2k
    if (strbuf == NULL)
921
0
        return_error(gs_error_VMerror);
922
23.2k
    ptr = pdfi_get_hexstring(ctx, strbuf, text->data, text->length);
923
23.2k
    strncpy(ptr, " Tj", buflen-strlen(strbuf));
924
925
23.2k
    code = pdfi_interpret_inner_content_c_string(ctx, strbuf, annot,
926
23.2k
                                               ctx->page.CurrentPageDict, false, "Annot text Tj");
927
23.2k
    if (code < 0) goto exit;
928
929
23.2k
 exit:
930
23.2k
    if (strbuf)
931
23.2k
        gs_free_object(ctx->memory, strbuf, "pdfi_annot_display_text(strbuf)");
932
23.2k
    return code;
933
23.2k
}
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.72k
{
939
1.72k
    char *strbuf = NULL;
940
1.72k
    size_t buflen = 50 + text->length*2; /* 50 to account for formatting, plus the text itself */
941
1.72k
    int code = 0;
942
1.72k
    char *ptr;
943
944
1.72k
    strbuf = (char *)gs_alloc_bytes(ctx->memory, buflen, "pdfi_annot_display_text(strbuf)");
945
1.72k
    if (strbuf == NULL)
946
0
        return_error(gs_error_VMerror);
947
1.72k
    snprintf(strbuf, buflen, "%g %g Td ", x, y);
948
1.72k
    ptr = strbuf + strlen(strbuf);
949
1.72k
    ptr = pdfi_get_hexstring(ctx, ptr, text->data, text->length);
950
1.72k
    strncpy(ptr, " Tj", buflen-strlen(strbuf));
951
952
1.72k
    code = pdfi_interpret_inner_content_c_string(ctx, strbuf, annot,
953
1.72k
                                               ctx->page.CurrentPageDict, false, "Annot text Tj");
954
1.72k
    if (code < 0) goto exit;
955
956
1.72k
 exit:
957
1.72k
    if (strbuf)
958
1.72k
        gs_free_object(ctx->memory, strbuf, "pdfi_annot_display_text(strbuf)");
959
1.72k
    return code;
960
1.72k
}
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
415
{
969
415
    int code;
970
415
    pdf_string *temp_string = NULL;
971
415
    gs_rect bbox;
972
415
    gs_point awidth;
973
974
415
    if (ctx->pgs->PDFfontsize == 0) {
975
0
        *height = 0;
976
0
        return 0;
977
0
    }
978
979
415
    code = pdfi_obj_charstr_to_string(ctx, "Hy", &temp_string);
980
415
    if (code < 0)
981
0
        goto exit;
982
983
    /* Find the bbox of the string "Hy" */
984
415
    code = pdfi_string_bbox(ctx, temp_string, &bbox, &awidth, false);
985
415
    if (code < 0)
986
0
        goto exit;
987
988
415
    *height = bbox.q.y - bbox.p.y;
989
990
415
 exit:
991
415
    pdfi_countdown(temp_string);
992
415
    return code;
993
415
}
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
186
{
999
186
    int code = 0;
1000
186
    int code1 = 0;
1001
1002
186
    code = pdfi_BT(ctx);
1003
186
    if (code < 0)
1004
0
        return code;
1005
1006
186
    code = pdfi_annot_display_text(ctx, annot, x, y, text);
1007
186
    code1 = pdfi_ET(ctx);
1008
186
    if (code == 0) code = code1;
1009
1010
186
    return code;
1011
186
}
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
180
{
1017
180
    int code = 0;
1018
180
    int code1 = 0;
1019
180
    gs_rect bbox;
1020
180
    gs_point awidth;
1021
180
    double x, y;
1022
1023
180
    code = pdfi_BT(ctx);
1024
180
    if (code < 0)
1025
0
        return code;
1026
1027
    /* Get width of the string */
1028
180
    code = pdfi_string_bbox(ctx, text, &bbox, &awidth, false);
1029
180
    if (code < 0) goto exit;
1030
1031
    /* Center the title in the box */
1032
180
    x = rect->p.x + ((rect->q.x - rect->p.x) - awidth.x) / 2;
1033
180
    y = rect->q.y - 11;
1034
1035
180
    code = pdfi_annot_display_text(ctx, annot, x, y, text);
1036
180
    if (code < 0) goto exit;
1037
1038
180
 exit:
1039
180
    code1 = pdfi_ET(ctx);
1040
180
    if (code == 0) code = code1;
1041
180
    return code;
1042
180
}
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
239
{
1058
239
    double x;
1059
239
    double lineheight = 0;
1060
239
    double y_start;
1061
239
    double x_start, x_max;
1062
239
    gs_rect bbox;
1063
239
    gs_point awidth; /* Advance width */
1064
239
    int code = 0;
1065
239
    int code1 = 0;
1066
239
    pdf_string *temp_string = NULL;
1067
239
    int i;
1068
239
    byte ch;
1069
239
    bool firstchar = true;
1070
239
    bool linestart = true;
1071
239
    int charlen;
1072
1073
239
    if (is_UTF16)
1074
0
        charlen = 2;
1075
239
    else
1076
239
        charlen = 1;
1077
1078
239
    if (ctx->pgs->PDFfontsize == 0)
1079
0
        return 0;
1080
1081
239
    code = pdfi_BT(ctx);
1082
239
    if (code < 0)
1083
0
        return code;
1084
1085
    /* Allocate a temp string to use, length 1 char */
1086
239
    code = pdfi_object_alloc(ctx, PDF_STRING, charlen, (pdf_obj **)&temp_string);
1087
239
    if (code < 0) goto exit;
1088
239
    pdfi_countup(temp_string);
1089
1090
239
    code = pdfi_annot_get_text_height(ctx, &lineheight);
1091
239
    if (code < 0) goto exit;
1092
1093
239
    y_start = rect->q.y - lineheight;
1094
239
    x_start = rect->p.x;
1095
239
    x_max = rect->q.x;
1096
239
    x = x_start;
1097
1098
25.3k
    for (i=0; i<text->length; i+=charlen) {
1099
25.0k
        int j;
1100
1101
25.0k
        if (linestart) {
1102
713
            x = x_start;
1103
713
        }
1104
1105
50.1k
        for (j = 0; j < charlen; j++) {
1106
25.0k
            ch = text->data[i+j];
1107
25.0k
            temp_string->data[j] = ch;
1108
25.0k
        }
1109
1110
        /* If EOL character encountered, move down to next line */
1111
25.0k
        if (charlen == 1) { /* Can only check this for ASCII font */
1112
25.0k
            if (ch == '\r' || ch == '\n') {
1113
474
                if (linestart == true) {
1114
0
                    pdf_string dummy;
1115
1116
0
                    dummy.length = 0;
1117
0
                    code = pdfi_annot_display_text(ctx, annot, 0, -lineheight, &dummy);
1118
0
                    if (code < 0) goto exit;
1119
0
                }
1120
474
                linestart = true;
1121
474
                continue;
1122
474
            }
1123
25.0k
        }
1124
1125
        /* get size of the character */
1126
24.6k
        code = pdfi_string_bbox(ctx, temp_string, &bbox, &awidth, false);
1127
24.6k
        if (code < 0) goto exit;
1128
1129
24.6k
        if (!linestart && ((x + awidth.x) > x_max)) {
1130
645
            x = x_start;
1131
645
            linestart = true;
1132
645
        }
1133
1134
        /* display the character */
1135
24.6k
        if (firstchar) {
1136
239
            code = pdfi_annot_display_text(ctx, annot, x, y_start, temp_string);
1137
239
            firstchar = false;
1138
24.3k
        } else {
1139
24.3k
            if (linestart)
1140
1.11k
                code = pdfi_annot_display_text(ctx, annot, 0, -lineheight, temp_string);
1141
23.2k
            else
1142
23.2k
                code = pdfi_annot_display_nexttext(ctx, annot, temp_string);
1143
24.3k
        }
1144
24.6k
        if (code < 0) goto exit;
1145
24.6k
        x += awidth.x;
1146
24.6k
        linestart = false;
1147
24.6k
    }
1148
1149
239
 exit:
1150
239
    code1 = pdfi_ET(ctx);
1151
239
    if (code == 0) code = code1;
1152
239
    pdfi_countdown(temp_string);
1153
239
    return code;
1154
239
}
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
504
{
1354
504
    int code;
1355
504
    double width;
1356
504
    double seglen;
1357
1358
504
    code = pdfi_annot_get_BS_width(ctx, annot, &width);
1359
504
    if (code < 0) goto exit;
1360
1361
504
    code = pdfi_gsave(ctx);
1362
504
    if (code < 0) goto exit_grestore;
1363
1364
504
    code = gs_setlinejoin(ctx->pgs, 0);
1365
504
    if (code < 0) goto exit_grestore;
1366
504
    code = gs_moveto(ctx->pgs, -width*6, -width*4);
1367
504
    if (code < 0) goto exit_grestore;
1368
504
    code = gs_lineto(ctx->pgs, -width/1.2, 0);
1369
504
    if (code < 0) goto exit_grestore;
1370
504
    code = gs_lineto(ctx->pgs, -width*6, width*4);
1371
504
    if (code < 0) goto exit_grestore;
1372
504
    code = gs_closepath(ctx->pgs);
1373
504
    if (code < 0) goto exit_grestore;
1374
504
    code = pdfi_annot_draw_border(ctx, annot, true);
1375
504
    if (code < 0) goto exit_grestore;
1376
1377
504
    code = pdfi_grestore(ctx);
1378
504
    if (code < 0) goto exit;
1379
1380
504
    code = gs_translate(ctx->pgs, -1.3*width, 0);
1381
504
    if (code < 0) goto exit;
1382
504
    seglen = width / 2;
1383
504
    code = gs_moveto(ctx->pgs, -seglen*8.4, -seglen*5.9);
1384
504
    if (code < 0) goto exit;
1385
504
    code = gs_lineto(ctx->pgs, -seglen/1.2, 0);
1386
504
    if (code < 0) goto exit;
1387
504
    code = gs_lineto(ctx->pgs, -seglen*8.4, seglen*5.9);
1388
504
    if (code < 0) goto exit;
1389
504
    code = gs_closepath(ctx->pgs);
1390
504
    if (code < 0) goto exit;
1391
504
    code = pdfi_annot_opacity(ctx, annot);
1392
504
    if (code < 0) goto exit;
1393
504
    code = pdfi_annot_fillborderpath(ctx, annot);
1394
504
    goto exit;
1395
1396
0
 exit_grestore:
1397
0
    (void)pdfi_grestore(ctx);
1398
504
 exit:
1399
504
    return code;
1400
0
}
1401
1402
/* Draw OpenArrow LE */
1403
static int pdfi_annot_draw_LE_OpenArrow(pdf_context *ctx, pdf_dict *annot)
1404
0
{
1405
0
    int code;
1406
0
    double width;
1407
1408
0
    code = pdfi_annot_get_BS_width(ctx, annot, &width);
1409
0
    if (code < 0) goto exit;
1410
1411
0
    code = gs_setlinejoin(ctx->pgs, 0);
1412
0
    if (code < 0) goto exit;
1413
1414
0
    code = gs_moveto(ctx->pgs, -width*6, -width*4);
1415
0
    if (code < 0) goto exit;
1416
0
    code = gs_lineto(ctx->pgs, -width/1.2, 0);
1417
0
    if (code < 0) goto exit;
1418
0
    code = gs_lineto(ctx->pgs, -width*6, width*4);
1419
0
    if (code < 0) goto exit;
1420
0
    code = pdfi_annot_draw_border(ctx, annot, true);
1421
0
    if (code < 0) goto exit;
1422
1423
0
 exit:
1424
0
    return code;
1425
0
}
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.59k
{
1458
1.59k
    return 0;
1459
1.59k
}
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
2.13k
{
1479
2.13k
    int code;
1480
2.13k
    int code1;
1481
2.13k
    annot_LE_dispatch_t *dispatch_ptr;
1482
1483
2.13k
    code = pdfi_gsave(ctx);
1484
2.13k
    if (code < 0) goto exit1;
1485
1486
2.13k
    code = gs_translate(ctx->pgs, x, y);
1487
2.13k
    code = gs_moveto(ctx->pgs, 0, 0);
1488
2.13k
    code = gs_rotate(ctx->pgs, angle);
1489
1490
    /* Draw the LE */
1491
19.3k
    for (dispatch_ptr = annot_LE_dispatch; dispatch_ptr->name; dispatch_ptr ++) {
1492
19.3k
        if (pdfi_name_is(LE, dispatch_ptr->name)) {
1493
2.10k
            code = dispatch_ptr->func(ctx, annot);
1494
2.10k
            break;
1495
2.10k
        }
1496
19.3k
    }
1497
2.13k
    if (!dispatch_ptr->name) {
1498
34
        char str[100];
1499
34
        memcpy(str, (const char *)LE->data, LE->length < 100 ? LE->length : 99);
1500
34
        str[LE->length < 100 ? LE->length : 99] = '\0';
1501
34
        dbgmprintf1(ctx->memory, "ANNOT: WARNING No handler for LE %s\n", str);
1502
34
    }
1503
1504
2.13k
 exit1:
1505
2.13k
    code1 = pdfi_grestore(ctx);
1506
2.13k
    if (code < 0)
1507
5
        code = code1;
1508
2.13k
    return code;
1509
2.13k
}
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
2.13k
{
1521
2.13k
    pdf_obj *LE = NULL;
1522
2.13k
    pdf_name *LE1 = NULL;
1523
2.13k
    pdf_name *LE2 = NULL;
1524
2.13k
    double dx, dy;
1525
2.13k
    double angle;
1526
2.13k
    int code;
1527
2.13k
    pdf_obj_type type;
1528
1529
2.13k
    code = pdfi_dict_knownget(ctx, annot, "LE", (pdf_obj **)&LE);
1530
2.13k
    if (code <= 0)
1531
1.05k
        goto exit;
1532
1.08k
    type = pdfi_type_of(LE);
1533
1.08k
    if (type != PDF_ARRAY && type != PDF_NAME) {
1534
0
        code = gs_note_error(gs_error_typecheck);
1535
0
        goto exit;
1536
0
    }
1537
1538
1.08k
    dx = x2 - x1;
1539
1.08k
    dy = y2 - y1;
1540
1.08k
    code = gs_atan2_degrees(dy, dx, &angle);
1541
1.08k
    if (code < 0)
1542
0
        angle = 0;
1543
1544
1.08k
    if (type == PDF_ARRAY) {
1545
1.08k
        code = pdfi_array_get_type(ctx, (pdf_array *)LE, 0, PDF_NAME, (pdf_obj **)&LE1);
1546
1.08k
        if (code < 0) goto exit;
1547
1548
1.08k
        code = pdfi_array_get_type(ctx, (pdf_array *)LE, 1, PDF_NAME, (pdf_obj **)&LE2);
1549
1.08k
        if (code < 0) goto exit;
1550
1.08k
    } else {
1551
0
        LE1 = (pdf_name *)LE;
1552
0
        LE = NULL;
1553
0
    }
1554
1.07k
    if (LE1 && (!which || which == 1)) {
1555
1.06k
        code = pdfi_annot_draw_LE_one(ctx, annot, LE1, x1, y1, angle+180);
1556
1.06k
        if (code < 0) goto exit;
1557
1.06k
    }
1558
1559
1.07k
    if (LE2 && (!which || which == 2)) {
1560
1.06k
        code = pdfi_annot_draw_LE_one(ctx, annot, LE2, x2, y2, angle);
1561
1.06k
        if (code < 0) goto exit;
1562
1.06k
    }
1563
1564
2.13k
 exit:
1565
2.13k
    pdfi_countdown(LE);
1566
2.13k
    pdfi_countdown(LE1);
1567
2.13k
    pdfi_countdown(LE2);
1568
2.13k
    return code;
1569
1.07k
}
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
348k
{
1578
348k
    int code;
1579
348k
    pdf_dict *AP_dict = NULL;
1580
348k
    pdf_stream *AP = NULL;
1581
348k
    pdf_obj *baseAP = NULL;
1582
348k
    pdf_name *AS = NULL;
1583
1584
348k
    *NormAP = NULL;
1585
1586
348k
    code = pdfi_dict_knownget_type(ctx, annot, "AP", PDF_DICT, (pdf_obj **)&AP_dict);
1587
348k
    if (code <= 0) goto exit;
1588
1589
266k
    code = pdfi_dict_knownget(ctx, AP_dict, "N", (pdf_obj **)&baseAP);
1590
266k
    if (code < 0) goto exit;
1591
1592
    /* Look for /R and /D if there was no /N */
1593
212k
    if (code == 0) {
1594
40
        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
40
        code = pdfi_dict_knownget(ctx, AP_dict, "R", (pdf_obj **)&baseAP);
1598
40
        if (code < 0) goto exit;
1599
1600
40
        if (code == 0) {
1601
39
            code = pdfi_dict_knownget(ctx, AP_dict, "D", (pdf_obj **)&baseAP);
1602
39
            if (code < 0) goto exit;
1603
39
        }
1604
40
    }
1605
1606
    /* Nothing found */
1607
212k
    if (code == 0) goto exit;
1608
1609
212k
    switch (pdfi_type_of(baseAP)) {
1610
169k
        case PDF_STREAM:
1611
            /* Use baseAP for the AP */
1612
169k
            AP = (pdf_stream *)baseAP;
1613
169k
            baseAP = NULL;
1614
169k
            break;
1615
43.2k
        case PDF_DICT:
1616
43.2k
            code = pdfi_dict_knownget_type(ctx, annot, "AS", PDF_NAME, (pdf_obj **)&AS);
1617
43.2k
            if (code < 0) goto exit;
1618
43.2k
            if (code == 0) {
1619
494
                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
494
                goto exit;
1621
494
            }
1622
1623
            /* Lookup the AS in the NormAP and use that as the AP */
1624
42.7k
            code = pdfi_dict_get_by_key(ctx, (pdf_dict *)baseAP, AS, (pdf_obj **)&AP);
1625
42.7k
            if (code < 0) {
1626
                /* Apparently this is not an error, just silently don't have an AP */
1627
16.9k
                *NormAP = (pdf_obj *)TOKEN_null;
1628
16.9k
                code = 0;
1629
16.9k
                goto exit;
1630
16.9k
            }
1631
25.7k
            if (pdfi_type_of(AP) != PDF_STREAM) {
1632
75
                code = gs_note_error(gs_error_typecheck);
1633
75
                goto exit;
1634
75
            }
1635
25.6k
            break;
1636
25.6k
        default:
1637
127
            code = gs_error_typecheck;
1638
127
            goto exit;
1639
212k
    }
1640
1641
195k
   *NormAP = (pdf_obj *)AP;
1642
195k
   pdfi_countup(AP);
1643
1644
348k
 exit:
1645
348k
    pdfi_countdown(AP_dict);
1646
348k
    pdfi_countdown(AP);
1647
348k
    pdfi_countdown(AS);
1648
348k
    pdfi_countdown(baseAP);
1649
348k
    return code;
1650
195k
}
1651
1652
static int pdfi_annot_draw_Link(pdf_context *ctx, pdf_dict *annot, pdf_obj *NormAP, bool *render_done)
1653
3.08k
{
1654
3.08k
    int code;
1655
3.08k
    int code1;
1656
3.08k
    bool drawit;
1657
1658
3.08k
    dbgmprintf(ctx->memory, "ANNOT: Drawing Link\n");
1659
1660
3.08k
    code = pdfi_annot_start_transparency(ctx, annot);
1661
3.08k
    if (code < 0)
1662
0
        return code;
1663
1664
3.08k
    code = pdfi_annot_setcolor(ctx, annot, true, &drawit);
1665
3.08k
    if (code < 0) goto exit;
1666
3.08k
    if (!drawit) goto exit;
1667
1668
3.08k
    code = pdfi_annot_draw_border(ctx, annot, false);
1669
3.08k
    if (code < 0) goto exit;
1670
1671
3.08k
    code = pdfi_annot_draw_AP(ctx, annot, NormAP);
1672
1673
3.08k
 exit:
1674
3.08k
    code1 = pdfi_annot_end_transparency(ctx, annot);
1675
3.08k
    if (code == 0) code = code1;
1676
1677
3.08k
    *render_done = true;
1678
3.08k
    return code;
1679
3.08k
}
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
648
{
1693
648
    int code = 0;
1694
648
    pdf_array *points = NULL;
1695
648
    int i;
1696
648
    int num_points;
1697
648
    double x1, y1, x2, y2;
1698
1699
1.22k
    for (i=0; i<pdfi_array_size(InkList); i++) {
1700
648
        int j;
1701
1702
648
        code = pdfi_array_get_type(ctx, InkList, i, PDF_ARRAY, (pdf_obj **)&points);
1703
648
        if (code < 0)
1704
0
            goto exit;
1705
1706
648
        num_points = pdfi_array_size(points);
1707
648
        if (num_points < 2)
1708
0
            goto exit;
1709
1710
648
        code = pdfi_array_get_number(ctx, points, 0, &x1);
1711
648
        if (code < 0) goto exit;
1712
648
        code = pdfi_array_get_number(ctx, points, 1, &y1);
1713
648
        if (code < 0) goto exit;
1714
647
        code = gs_moveto(ctx->pgs, x1, y1);
1715
647
        if (code < 0) goto exit;
1716
647
        if (num_points == 2)
1717
0
            goto stroke;
1718
1719
22.0k
        for (j = 2; j < num_points; j += 2) {
1720
21.4k
            code = pdfi_array_get_number(ctx, points, j, &x2);
1721
21.4k
            if (code < 0) goto exit;
1722
21.4k
            code = pdfi_array_get_number(ctx, points, j+1, &y2);
1723
21.4k
            if (code < 0) goto exit;
1724
21.4k
            code = gs_lineto(ctx->pgs, x2, y2);
1725
21.4k
            if (code < 0) goto exit;
1726
21.4k
        }
1727
1728
576
    stroke:
1729
576
        code = gs_stroke(ctx->pgs);
1730
576
        if (code < 0) goto exit;
1731
576
        pdfi_countdown(points);
1732
576
        points = NULL;
1733
576
    }
1734
1735
648
 exit:
1736
648
    pdfi_countdown(points);
1737
648
    return code;
1738
648
}
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
671
{
1798
671
    int code = 0;
1799
671
    int code1 = 0;
1800
671
    bool drawit;
1801
671
    pdf_array *array = NULL;
1802
1803
671
    code = pdfi_annot_setcolor(ctx, annot, false, &drawit);
1804
671
    if (code <0 || !drawit)
1805
11
        goto exit1;
1806
1807
660
    code = pdfi_annot_start_transparency(ctx, annot);
1808
660
    if (code < 0) goto exit1;
1809
1810
660
    code = gs_setlinewidth(ctx->pgs, 1);
1811
660
    if (code < 0) goto exit;
1812
660
    code = gs_setlinecap(ctx->pgs, 1);
1813
660
    if (code < 0) goto exit;
1814
660
    code = gs_setlinejoin(ctx->pgs, 1);
1815
660
    if (code < 0) goto exit;
1816
1817
660
    code = pdfi_dict_knownget_type(ctx, annot, "InkList", PDF_ARRAY, (pdf_obj **)&array);
1818
660
    if (code < 0) goto exit;
1819
660
    if (code > 0) {
1820
648
        code = pdfi_annot_draw_InkList(ctx, annot, array);
1821
648
        goto exit;
1822
648
    }
1823
12
    code = pdfi_dict_knownget_type(ctx, annot, "Path", PDF_ARRAY, (pdf_obj **)&array);
1824
12
    if (code < 0) goto exit;
1825
12
    if (code > 0) {
1826
0
        code = pdfi_annot_draw_Path(ctx, annot, array);
1827
0
        goto exit;
1828
0
    }
1829
1830
660
 exit:
1831
660
    code1 = pdfi_annot_end_transparency(ctx, annot);
1832
660
    if (code >= 0)
1833
588
        code = code1;
1834
671
 exit1:
1835
671
    pdfi_countdown(array);
1836
671
    *render_done = true;
1837
671
    return code;
1838
660
}
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
242
{
1860
242
    int code = 0;
1861
242
    double magic = .55228475 - .00045; /* Magic value */
1862
242
    double xrad = width / 2;
1863
242
    double yrad = height / 2;
1864
242
    double xmag = xrad * magic;
1865
242
    double ymag = yrad * magic;
1866
1867
242
    code = gs_moveto(ctx->pgs, -xrad, 0);
1868
242
    if (code < 0) return code;
1869
242
    code = gs_curveto(ctx->pgs, -xrad, ymag, -xmag, yrad, 0, yrad);
1870
242
    if (code < 0) return code;
1871
242
    code = gs_curveto(ctx->pgs, xmag, yrad, xrad, ymag, xrad, 0);
1872
242
    if (code < 0) return code;
1873
242
    code = gs_curveto(ctx->pgs, xrad, -ymag, xmag, -yrad, 0, -yrad);
1874
242
    if (code < 0) return code;
1875
242
    code = gs_curveto(ctx->pgs, -xmag, -yrad, -xrad, -ymag, -xrad, 0);
1876
1877
242
    return code;
1878
242
}
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
242
{
1886
242
    int code = 0;
1887
242
    int code1 = 0;
1888
242
    gs_rect rect;
1889
242
    bool drawit;
1890
242
    double width, height;
1891
1892
242
    code = pdfi_annot_start_transparency(ctx, annot);
1893
242
    if (code < 0) goto exit1;
1894
1895
242
    code = pdfi_annot_Rect(ctx, annot, &rect);
1896
242
    if (code < 0) goto exit;
1897
1898
242
    code = pdfi_annot_applyRD(ctx, annot, &rect);
1899
242
    if (code < 0) goto exit;
1900
1901
    /* Translate to the center of the ellipse */
1902
242
    width = rect.q.x - rect.p.x;
1903
242
    height = rect.q.y - rect.p.y;
1904
242
    code = gs_translate(ctx->pgs, rect.p.x + width/2, rect.p.y + height/2);
1905
242
    if (code < 0) goto exit;
1906
1907
    /* Draw the ellipse */
1908
242
    code = pdfi_annot_drawellipse(ctx, width, height);
1909
242
    if (code < 0) goto exit;
1910
1911
242
    code = pdfi_annot_fillborderpath(ctx, annot);
1912
242
    if (code < 0) goto exit;
1913
1914
242
    code = pdfi_annot_setcolor(ctx, annot, false, &drawit);
1915
242
    if (code < 0) goto exit;
1916
1917
242
    if (drawit) {
1918
236
        code = pdfi_annot_draw_border(ctx, annot, true);
1919
236
        if (code < 0) goto exit;
1920
236
    }
1921
1922
242
 exit:
1923
242
    code1 = pdfi_annot_end_transparency(ctx, annot);
1924
242
    if (code >= 0)
1925
242
        code = code1;
1926
242
 exit1:
1927
242
    *render_done = true;
1928
242
    return code;
1929
242
}
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
35
{
2073
35
    int code = 0;
2074
35
    int code1 = 0;
2075
35
    gs_rect rect;
2076
35
    double width, height;
2077
35
    pdfi_annot_stamp_type_t *stamp_type;
2078
35
    pdf_name *Name = NULL;
2079
35
    double xscale, yscale;
2080
35
    double angle;
2081
35
    int i;
2082
2083
35
    code = pdfi_annot_start_transparency(ctx, annot);
2084
35
    if (code < 0) goto exit1;
2085
2086
35
    code = pdfi_annot_Rect(ctx, annot, &rect);
2087
35
    if (code < 0) goto exit;
2088
2089
28
    code = pdfi_dict_knownget_type(ctx, annot, "Name", PDF_NAME, (pdf_obj **)&Name);
2090
28
    if (code <= 0) goto exit;
2091
2092
    /* Translate to the center of Rect */
2093
28
    width = rect.q.x - rect.p.x;
2094
28
    height = rect.q.y - rect.p.y;
2095
28
    code = gs_translate(ctx->pgs, rect.p.x + width/2, rect.p.y + height/2);
2096
28
    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
28
    yscale = height / 50.;
2103
28
    xscale = width / 190.;
2104
28
    if (xscale < yscale)
2105
13
        yscale = xscale;
2106
28
    if (yscale <= 0.0)
2107
0
        yscale = 1.0;
2108
28
    code = gs_scale(ctx->pgs, yscale, yscale);
2109
28
    if (code < 0) goto exit;
2110
2111
    /* Search through types and find a match, if no match use Draft */
2112
376
    for (stamp_type = pdfi_annot_stamp_types; stamp_type->type; stamp_type ++) {
2113
353
        if (Name && pdfi_name_is(Name, stamp_type->type))
2114
5
            break;
2115
353
    }
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
28
    if (!stamp_type->type) {
2123
23
        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
23
        goto exit;
2125
23
    }
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
35
 exit:
2156
35
    code1 = pdfi_annot_end_transparency(ctx, annot);
2157
35
    if (code >= 0)
2158
28
        code = code1;
2159
35
 exit1:
2160
35
    pdfi_countdown(Name);
2161
35
    *render_done = true;
2162
35
    return code;
2163
35
}
2164
/*********** END /Stamp ***************/
2165
2166
2167
/* Draw Callout Line (CL) */
2168
static int pdfi_annot_draw_CL(pdf_context *ctx, pdf_dict *annot)
2169
65
{
2170
65
    int code;
2171
65
    pdf_array *CL = NULL;
2172
65
    double array[6];
2173
65
    int length;
2174
2175
65
    code = pdfi_dict_knownget_type(ctx, annot, "CL", PDF_ARRAY, (pdf_obj **)&CL);
2176
65
    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
65
 exit:
2207
65
    pdfi_countdown(CL);
2208
65
    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
65
{
2218
65
    int code = 0;
2219
65
    int code1 = 0;
2220
65
    bool drawbackground;
2221
65
    pdf_dict *BS = NULL;
2222
65
    pdf_string *Contents = NULL;
2223
65
    gs_rect annotrect, modrect;
2224
65
    int64_t Rotate;
2225
2226
65
    *render_done = false;
2227
2228
65
    code = pdfi_annot_start_transparency(ctx, annot);
2229
65
    if (code < 0) goto exit1;
2230
2231
65
    code = pdfi_annot_opacity(ctx, annot);
2232
65
    if (code < 0) goto exit;
2233
2234
65
    code = pdfi_annot_Rect(ctx, annot, &annotrect);
2235
65
    if (code < 0) goto exit;
2236
2237
    /* Set the (background?) color if applicable */
2238
65
    code = pdfi_annot_setcolor(ctx, annot, false, &drawbackground);
2239
65
    if (code < 0) goto exit;
2240
2241
    /* Only draw rectangle if a color was specified */
2242
65
    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
65
    code = pdfi_annot_process_DA(ctx, NULL, annot, &annotrect, false);
2255
65
    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
65
#if 1
2260
    /* TODO: Prefer to do it this way! */
2261
65
    code = pdfi_annot_draw_border(ctx, annot, false);
2262
65
    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
65
    code = pdfi_annot_draw_CL(ctx, annot);
2298
65
    if (code < 0) goto exit;
2299
2300
    /* Modify rect by RD if applicable */
2301
65
    code = pdfi_annot_applyRD(ctx, annot, &annotrect);
2302
65
    if (code < 0) goto exit;
2303
2304
    /* /Rotate */
2305
65
    code = pdfi_dict_get_int_def(ctx, annot, "Rotate", &Rotate, 0);
2306
65
    if (code < 0) goto exit;
2307
2308
65
    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
65
    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
65
    case 0:
2342
65
    default:
2343
65
        modrect.p.x += 2;
2344
65
        modrect.p.y += 2;
2345
65
        modrect.q.x -= 2;
2346
65
        modrect.q.y -= 2;
2347
2348
        /* Move to initial position (slightly offset from the corner of the rect) */
2349
65
        code = gs_moveto(ctx->pgs, modrect.p.x, modrect.q.y);
2350
65
        if (code < 0) goto exit;
2351
65
        break;
2352
65
    }
2353
2354
    /* /Contents */
2355
65
    code = pdfi_dict_knownget_type(ctx, annot, "Contents", PDF_STRING, (pdf_obj **)&Contents);
2356
65
    if (code < 0) goto exit;
2357
65
    if (code > 0) {
2358
58
        code = pdfi_annot_display_formatted_text(ctx, annot, &modrect, Contents, false);
2359
58
        if (code < 0) goto exit;
2360
58
    }
2361
2362
65
 exit:
2363
65
    code1 = pdfi_annot_end_transparency(ctx, annot);
2364
65
    if (code >= 0)
2365
65
        code = code1;
2366
65
 exit1:
2367
65
    *render_done = true;
2368
65
    pdfi_countdown(BS);
2369
65
    pdfi_countdown(Contents);
2370
65
    return code;
2371
65
}
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
29
{
2382
29
    int code = 0;
2383
29
    int code1 = 0;
2384
29
    gs_rect rect;
2385
2386
29
    code = pdfi_annot_start_transparency(ctx, annot);
2387
29
    if (code < 0) goto exit1;
2388
2389
29
    code = pdfi_annot_Rect(ctx, annot, &rect);
2390
29
    if (code < 0) goto exit;
2391
29
    code = gs_translate(ctx->pgs, rect.p.x, rect.p.y);
2392
29
    if (code < 0) goto exit;
2393
2394
    /* Draw a page icon (/Note) */
2395
    /* TODO: All the other /Name appearances */
2396
29
    code = gs_translate(ctx->pgs, 0.5, (rect.q.y-rect.p.y)-18.5);
2397
29
    if (code < 0) goto exit;
2398
29
    code = gs_setlinewidth(ctx->pgs, 1.0);
2399
29
    if (code < 0) goto exit;
2400
29
    code = pdfi_gs_setgray(ctx, 0.75);
2401
29
    if (code < 0) goto exit;
2402
29
    code = gs_moveto(ctx->pgs, 0.5, -1);
2403
29
    if (code < 0) goto exit;
2404
29
    code = gs_lineto(ctx->pgs, 10, -1);
2405
29
    if (code < 0) goto exit;
2406
29
    code = gs_lineto(ctx->pgs, 15, 4);
2407
29
    if (code < 0) goto exit;
2408
29
    code = gs_lineto(ctx->pgs, 15, 17.5);
2409
29
    if (code < 0) goto exit;
2410
29
    code = gs_stroke(ctx->pgs);
2411
29
    if (code < 0) goto exit;
2412
2413
29
    code = gs_moveto(ctx->pgs, 0, 0);
2414
29
    if (code < 0) goto exit;
2415
29
    code = gs_lineto(ctx->pgs, 9, 0);
2416
29
    if (code < 0) goto exit;
2417
29
    code = gs_lineto(ctx->pgs, 14, 5);
2418
29
    if (code < 0) goto exit;
2419
29
    code = gs_lineto(ctx->pgs, 14, 18);
2420
29
    if (code < 0) goto exit;
2421
29
    code = gs_lineto(ctx->pgs, 0, 18);
2422
29
    if (code < 0) goto exit;
2423
29
    code = gs_closepath(ctx->pgs);
2424
29
    if (code < 0) goto exit;
2425
2426
29
    code = pdfi_gsave(ctx);
2427
29
    if (code >= 0) {
2428
29
        code = pdfi_gs_setgray(ctx, 0.5);
2429
29
        code = gs_fill(ctx->pgs);
2430
29
        code = pdfi_grestore(ctx);
2431
29
    } else
2432
0
        goto exit;
2433
2434
29
    code = pdfi_gs_setgray(ctx, 0);
2435
29
    if (code < 0) goto exit;
2436
29
    code = gs_stroke(ctx->pgs);
2437
29
    if (code < 0) goto exit;
2438
2439
29
    code = gs_moveto(ctx->pgs, 3, 8);
2440
29
    if (code < 0) goto exit;
2441
29
    code = gs_lineto(ctx->pgs, 7.5, 8);
2442
29
    if (code < 0) goto exit;
2443
29
    code = gs_moveto(ctx->pgs, 3, 11);
2444
29
    if (code < 0) goto exit;
2445
29
    code = gs_lineto(ctx->pgs, 10, 11);
2446
29
    if (code < 0) goto exit;
2447
29
    code = gs_moveto(ctx->pgs, 3, 14);
2448
29
    if (code < 0) goto exit;
2449
29
    code = gs_lineto(ctx->pgs, 10, 14);
2450
29
    if (code < 0) goto exit;
2451
29
    code = gs_moveto(ctx->pgs, 9, 0);
2452
29
    if (code < 0) goto exit;
2453
29
    code = gs_lineto(ctx->pgs, 9, 5);
2454
29
    if (code < 0) goto exit;
2455
29
    code = gs_lineto(ctx->pgs, 14, 5);
2456
29
    if (code < 0) goto exit;
2457
29
    code = gs_stroke(ctx->pgs);
2458
29
    if (code < 0) goto exit;
2459
2460
29
 exit:
2461
29
    code1 = pdfi_annot_end_transparency(ctx, annot);
2462
29
    if (code >= 0)
2463
29
        code = code1;
2464
29
 exit1:
2465
29
    *render_done = true;
2466
29
    return code;
2467
29
}
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
7.65k
{
2485
7.65k
    double x0,x1,x2,x3,y0,y1,y2,y3;
2486
7.65k
    double minx, miny;
2487
7.65k
    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
7.65k
    minx = array[0];
2499
7.65k
    miny = array[1];
2500
7.65k
    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
30.6k
    for (i=2; i<8; i+=2) {
2505
22.9k
        if ((array[i+1] == miny && array[i] < minx) ||  (array[i+1] < miny)) {
2506
            /* Set new min point */
2507
1.26k
            miny = array[i+1];
2508
1.26k
            minx = array[i];
2509
1.26k
            mindex = i;
2510
1.26k
        }
2511
22.9k
    }
2512
2513
    /* Pull out the points such that x0 = minx, y0 = miny, etc */
2514
7.65k
    i = mindex;
2515
7.65k
    x0 = array[i];
2516
7.65k
    y0 = array[i+1];
2517
7.65k
    i += 2;
2518
7.65k
    if (i == 8) i = 0;
2519
7.65k
    x1 = array[i];
2520
7.65k
    y1 = array[i+1];
2521
7.65k
    i += 2;
2522
7.65k
    if (i == 8) i = 0;
2523
7.65k
    x2 = array[i];
2524
7.65k
    y2 = array[i+1];
2525
7.65k
    i += 2;
2526
7.65k
    if (i == 8) i = 0;
2527
7.65k
    x3 = array[i];
2528
7.65k
    y3 = array[i+1];
2529
2530
    /* Make it go counterclockwise by picking lower of these 2 points */
2531
7.65k
    if (y3 < y1) {
2532
227
        y1 = y3;
2533
227
        x1 = x3;
2534
227
    }
2535
2536
    /* Convert into a starting point and two sets of lengths */
2537
7.65k
    *px0 = x0;
2538
7.65k
    *py0 = y0;
2539
7.65k
    *dx1 = x1 - x0;
2540
7.65k
    *dy1 = y1 - y0;
2541
7.65k
    *dx2 = x2 - x0;
2542
7.65k
    *dy2 = y2 - y0;
2543
7.65k
}
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
574
{
2552
574
    int code = 0;
2553
574
    bool drawit;
2554
574
    pdf_array *QuadPoints = NULL;
2555
574
    double array[8];
2556
574
    int size;
2557
574
    int num_quads;
2558
574
    int i;
2559
574
    double x0, y0, dx1, dy1, dx2, dy2;
2560
574
    double linewidth;
2561
2562
574
    code = pdfi_annot_setcolor(ctx, annot, false, &drawit);
2563
574
    if (code <0 || !drawit)
2564
16
        goto exit;
2565
2566
558
    code = pdfi_dict_knownget_type(ctx, annot, "QuadPoints", PDF_ARRAY, (pdf_obj **)&QuadPoints);
2567
558
    if (code <= 0) goto exit;
2568
2569
558
    size = pdfi_array_size(QuadPoints);
2570
558
    num_quads = size / 8;
2571
2572
7.37k
    for (i=0; i<num_quads; i++) {
2573
6.82k
        code = pdfi_array_to_num_array(ctx, QuadPoints, array, i*8, 8);
2574
6.82k
        if (code < 0) goto exit;
2575
2576
6.82k
        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
6.82k
        linewidth = sqrt((dx2*dx2) + (dy2*dy2)) / 16.;
2582
6.82k
        code = gs_setlinewidth(ctx->pgs, linewidth);
2583
6.82k
        if (code < 0) goto exit;
2584
6.82k
        code = gs_moveto(ctx->pgs, dx2*offset + x0 , dy2*offset + y0);
2585
6.82k
        if (code < 0) goto exit;
2586
6.82k
        code = gs_lineto(ctx->pgs, dx2*offset + x0 + dx1, dy2*offset + y0 + dy1);
2587
6.82k
        if (code < 0) goto exit;
2588
6.82k
        code = gs_stroke(ctx->pgs);
2589
6.82k
        if (code < 0) goto exit;
2590
6.82k
    }
2591
2592
574
 exit:
2593
574
    pdfi_countdown(QuadPoints);
2594
574
    return code;
2595
558
}
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
505
{
2603
505
    *render_done = true;
2604
505
    return pdfi_annot_draw_line_offset(ctx, annot, 3/7.);
2605
505
}
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
69
{
2613
69
    *render_done = true;
2614
69
    return pdfi_annot_draw_line_offset(ctx, annot, 1/7.);
2615
69
}
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
12.4k
{
2623
12.4k
    int code = 0;
2624
12.4k
    double dx, dy;
2625
12.4k
    double xc, yc, r, a1, a2;
2626
2627
12.4k
    dx = x1 - x0;
2628
12.4k
    dy = y1 - y0;
2629
2630
12.4k
    yc = (y1+y0)/2. - 15./16.*dx;
2631
12.4k
    xc = (x1+x0)/2. + 15./16.*dy;
2632
12.4k
    r = sqrt((y1-yc)*(y1-yc) + (x1-xc)*(x1-xc));
2633
12.4k
    code = gs_atan2_degrees(y1-yc, x1-xc, &a1);
2634
12.4k
    if (code < 0)
2635
92
        a1 = 0;
2636
12.4k
    code = gs_atan2_degrees(y0-yc, x0-xc, &a2);
2637
12.4k
    if (code < 0)
2638
92
        a2 = 0;
2639
12.4k
    code = gs_arcn(ctx->pgs, xc, yc, r, a2, a1);
2640
2641
12.4k
    return code;
2642
12.4k
}
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
1.14k
{
2650
1.14k
    int code = 0;
2651
1.14k
    bool drawit;
2652
1.14k
    pdf_array *QuadPoints = NULL;
2653
1.14k
    double array[8];
2654
1.14k
    int size;
2655
1.14k
    int num_quads;
2656
1.14k
    int i;
2657
2658
1.14k
    code = pdfi_annot_setcolor(ctx, annot, false, &drawit);
2659
1.14k
    if (code <0 || !drawit)
2660
25
        goto exit;
2661
2662
1.11k
    code = gs_setlinecap(ctx->pgs, 1);
2663
1.11k
    if (code < 0) goto exit;
2664
2665
1.11k
    code = pdfi_dict_knownget_type(ctx, annot, "QuadPoints", PDF_ARRAY, (pdf_obj **)&QuadPoints);
2666
1.11k
    if (code <= 0) goto exit;
2667
2668
1.10k
    size = pdfi_array_size(QuadPoints);
2669
1.10k
    num_quads = size / 8;
2670
2671
7.25k
    for (i=0; i<num_quads; i++) {
2672
6.27k
        code = pdfi_array_to_num_array(ctx, QuadPoints, array, i*8, 8);
2673
6.27k
        if (code < 0) goto exit;
2674
2675
6.22k
        code = gs_moveto(ctx->pgs, array[2], array[3]);
2676
6.22k
        if (code < 0) goto exit;
2677
2678
6.22k
        code = pdfi_annot_highlight_arc(ctx, array[2], array[3], array[6], array[7]);
2679
6.22k
        if (code < 0) goto exit;
2680
2681
6.20k
        code = gs_lineto(ctx->pgs, array[4], array[5]);
2682
6.20k
        if (code < 0) goto exit;
2683
2684
6.20k
        code = pdfi_annot_highlight_arc(ctx, array[4], array[5], array[0], array[1]);
2685
6.20k
        if (code < 0) goto exit;
2686
2687
6.15k
        code = gs_closepath(ctx->pgs);
2688
6.15k
        if (code < 0) goto exit;
2689
2690
6.15k
        if (ctx->page.has_transparency) {
2691
6.15k
            code = pdfi_trans_begin_simple_group(ctx, NULL, false, false, false);
2692
6.15k
            if (code < 0) goto exit;
2693
2694
6.15k
            code = gs_setblendmode(ctx->pgs, BLEND_MODE_Multiply);
2695
6.15k
            if (code < 0) {
2696
0
                (void)pdfi_trans_end_simple_group(ctx);
2697
0
                goto exit;
2698
0
            }
2699
6.15k
            code = gs_fill(ctx->pgs);
2700
6.15k
            (void)pdfi_trans_end_simple_group(ctx);
2701
6.15k
            if (code < 0) goto exit;
2702
6.15k
        } 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
6.15k
    }
2710
2711
1.14k
 exit:
2712
1.14k
    pdfi_countdown(QuadPoints);
2713
1.14k
    return code;
2714
1.10k
}
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
341
{
2722
341
    int code = 0;
2723
341
    bool drawit;
2724
341
    pdf_array *QuadPoints = NULL;
2725
341
    double array[8];
2726
341
    int size;
2727
341
    int num_quads;
2728
341
    int i;
2729
341
    double x0, y0, dx1, dy1, dx2, dy2;
2730
341
    double p1, p2, p12;
2731
341
    int count;
2732
341
    bool need_grestore = false;
2733
341
    gs_matrix matrix;
2734
2735
341
    code = pdfi_annot_setcolor(ctx, annot, false, &drawit);
2736
341
    if (code <0 || !drawit)
2737
8
        goto exit;
2738
2739
333
    code = gs_setlinecap(ctx->pgs, gs_cap_round);
2740
333
    if (code < 0) goto exit;
2741
333
    code = gs_setlinejoin(ctx->pgs, gs_join_round);
2742
333
    if (code < 0) goto exit;
2743
333
    code = gs_setlinewidth(ctx->pgs, 1.0);
2744
333
    if (code < 0) goto exit;
2745
2746
333
    code = pdfi_dict_knownget_type(ctx, annot, "QuadPoints", PDF_ARRAY, (pdf_obj **)&QuadPoints);
2747
333
    if (code <= 0) goto exit;
2748
2749
328
    size = pdfi_array_size(QuadPoints);
2750
328
    num_quads = size / 8;
2751
2752
1.15k
    for (i=0; i<num_quads; i++) {
2753
840
        code = pdfi_array_to_num_array(ctx, QuadPoints, array, i*8, 8);
2754
840
        if (code < 0) goto exit;
2755
2756
829
        code = pdfi_gsave(ctx);
2757
829
        if (code < 0) goto exit;
2758
829
        need_grestore = true;
2759
2760
        /* Make clipping region */
2761
829
        code = gs_moveto(ctx->pgs, array[6], array[7]);
2762
829
        if (code < 0) goto exit;
2763
829
        code = gs_lineto(ctx->pgs, array[4], array[5]);
2764
829
        if (code < 0) goto exit;
2765
829
        code = gs_lineto(ctx->pgs, array[0], array[1]);
2766
829
        if (code < 0) goto exit;
2767
829
        code = gs_lineto(ctx->pgs, array[2], array[3]);
2768
829
        if (code < 0) goto exit;
2769
829
        code = gs_closepath(ctx->pgs);
2770
829
        if (code < 0) goto exit;
2771
829
        code = gs_clip(ctx->pgs);
2772
829
        if (code < 0) goto exit;
2773
829
        code = gs_newpath(ctx->pgs);
2774
829
        if (code < 0) goto exit;
2775
2776
829
        pdfi_annot_quadpoints2basis(ctx, array, &x0, &y0, &dx1, &dy1, &dx2, &dy2);
2777
2778
829
        code = gs_translate(ctx->pgs, x0+dx2/56+dx2/72, y0+dy2/56+dy2/72);
2779
829
        if (code < 0) goto exit;
2780
2781
829
        p2 = sqrt(dx2*dx2 + dy2*dy2);
2782
829
        p1 = sqrt(dx1*dx1 + dy1*dy1);
2783
2784
829
        if (p2 > 0 && p1 > 0) {
2785
825
            p12 = p2 / p1;
2786
2787
825
            count = (int)((1/p12) * 4 + 1);
2788
2789
825
            matrix.xx = dx1 * p12;
2790
825
            matrix.xy = dy1 * p12;
2791
825
            matrix.yx = dx2;
2792
825
            matrix.yy = dy2;
2793
825
            matrix.tx = 0.0;
2794
825
            matrix.ty = 0.0;
2795
825
            code = gs_concat(ctx->pgs, &matrix);
2796
825
            if (code < 0) goto exit;
2797
2798
825
            code = gs_scale(ctx->pgs, 1/40., 1/72.);
2799
825
            if (code < 0) goto exit;
2800
2801
825
            code = gs_moveto(ctx->pgs, 0, 0);
2802
825
            if (code < 0) goto exit;
2803
2804
236k
            while (count >= 0) {
2805
235k
                code = gs_lineto(ctx->pgs, 5, 10);
2806
235k
                if (code < 0) goto exit;
2807
235k
                code = gs_lineto(ctx->pgs, 10, 0);
2808
235k
                if (code < 0) goto exit;
2809
235k
                code = gs_translate(ctx->pgs, 10, 0);
2810
235k
                if (code < 0) goto exit;
2811
2812
235k
                count --;
2813
235k
            }
2814
825
            code = gs_stroke(ctx->pgs);
2815
825
            if (code < 0) goto exit;
2816
825
        }
2817
2818
829
        need_grestore = false;
2819
829
        code = pdfi_grestore(ctx);
2820
829
        if (code < 0) goto exit;
2821
829
    }
2822
2823
341
 exit:
2824
341
    if (need_grestore)
2825
0
        (void)pdfi_grestore(ctx);
2826
341
    pdfi_countdown(QuadPoints);
2827
341
    *render_done = true;
2828
341
    return code;
2829
328
}
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
7.59k
{
2855
7.59k
    int code = 0, code1 = 0;
2856
7.59k
    bool Open = false;
2857
7.59k
    pdf_dict *Parent = NULL;
2858
7.59k
    pdf_string *Contents = NULL;
2859
7.59k
    pdf_string *T = NULL;
2860
7.59k
    bool has_color;
2861
7.59k
    gs_rect rect, rect2;
2862
7.59k
    bool need_grestore = false;
2863
2864
    /* Render only if open */
2865
7.59k
    code = pdfi_dict_get_bool(ctx, annot, "Open", &Open);
2866
7.59k
    if (code < 0 && (code != gs_error_undefined))
2867
0
        goto exit1;
2868
2869
7.59k
    code = 0;
2870
2871
    /* Don't render if not Open */
2872
7.59k
    if (!Open) {
2873
7.40k
        *render_done = true;
2874
7.40k
        goto exit1;
2875
7.40k
    }
2876
2877
    /* Let caller render if there is an AP */
2878
190
    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
190
    *render_done = true;
2885
2886
190
    code = pdfi_annot_start_transparency(ctx, annot);
2887
190
    if (code < 0) goto exit1;
2888
2889
190
    code = gs_setlinewidth(ctx->pgs, 0.05);
2890
2891
190
    code = pdfi_loop_detector_mark(ctx);
2892
190
    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
190
    code = pdfi_dict_knownget_type_no_store_R(ctx, annot, "Parent", PDF_DICT, (pdf_obj **)&Parent);
2901
190
    if (code < 0) goto exit;
2902
180
    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
180
    (void)pdfi_loop_detector_cleartomark(ctx);
2907
2908
180
    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
180
    code = pdfi_annot_setcolor(ctx, Parent, false, &has_color);
2916
180
    if (code < 0) goto exit;
2917
2918
    /* Set a default color if nothing specified */
2919
180
    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
180
    code = pdfi_annot_Rect(ctx, annot, &rect);
2925
180
    if (code < 0) goto exit;
2926
2927
    /* Draw big box (the frame around the /Contents) */
2928
180
    code = pdfi_gsave(ctx);
2929
180
    if (code < 0) goto exit;
2930
180
    need_grestore = true;
2931
180
    code = pdfi_gs_setgray(ctx, 1);
2932
180
    if (code < 0) goto exit;
2933
180
    code = gs_rectfill(ctx->pgs, &rect, 1);
2934
180
    if (code < 0) goto exit;
2935
180
    code = pdfi_gs_setgray(ctx, 0);
2936
180
    if (code < 0) goto exit;
2937
180
    code = gs_rectstroke(ctx->pgs, &rect, 1, NULL);
2938
180
    if (code < 0) goto exit;
2939
180
    code = pdfi_grestore(ctx);
2940
180
    need_grestore = false;
2941
180
    if (code < 0) goto exit;
2942
2943
    /* Display /Contents in Helvetica */
2944
180
    code = pdfi_dict_knownget_type(ctx, Parent, "Contents", PDF_STRING, (pdf_obj **)&Contents);
2945
180
    if (code < 0) goto exit;
2946
180
    if (code > 0) {
2947
179
        gs_rect text_rect;
2948
2949
179
        code = pdfi_gsave(ctx);
2950
179
        if (code < 0) goto exit;
2951
179
        need_grestore = true;
2952
179
        code = pdfi_gs_setgray(ctx, 0);
2953
179
        if (code < 0) goto exit;
2954
2955
179
        text_rect.p.x = rect.p.x + 3;
2956
179
        text_rect.q.x = rect.q.x - 3;
2957
179
        text_rect.p.y = rect.p.y + 3;
2958
179
        text_rect.q.y = rect.q.y - 18;
2959
2960
179
        code = pdfi_annot_set_font(ctx, "Helvetica", 9);
2961
179
        if (code < 0) goto exit;
2962
2963
179
        code = pdfi_annot_display_formatted_text(ctx, annot, &text_rect, Contents, false);
2964
179
        if (code < 0) goto exit;
2965
2966
179
        code = pdfi_grestore(ctx);
2967
179
        need_grestore = false;
2968
179
        if (code < 0) goto exit;
2969
179
    }
2970
2971
    /* Draw small, thin box (the frame around the top /T text) */
2972
180
    rect2.p.x = rect.p.x;
2973
180
    rect2.p.y = rect.q.y - 15;
2974
180
    rect2.q.x = rect.q.x;
2975
180
    rect2.q.y = rect.p.y + (rect.q.y - rect.p.y);
2976
2977
180
    code = gs_rectfill(ctx->pgs, &rect2, 1);
2978
180
    if (code < 0) goto exit;
2979
180
    code = pdfi_gs_setgray(ctx, 0);
2980
180
    if (code < 0) goto exit;
2981
180
    code = gs_rectstroke(ctx->pgs, &rect2, 1, NULL);
2982
180
    if (code < 0) goto exit;
2983
2984
    /* Display /T in Helvetica */
2985
180
    code = pdfi_dict_knownget_type(ctx, Parent, "T", PDF_STRING, (pdf_obj **)&T);
2986
180
    if (code < 0) goto exit;
2987
180
    if (code > 0) {
2988
180
        code = pdfi_annot_set_font(ctx, "Helvetica", 9);
2989
180
        if (code < 0) goto exit;
2990
2991
180
        code = pdfi_annot_display_centered_text(ctx, annot, &rect, T);
2992
180
        if (code < 0) goto exit;
2993
2994
180
    }
2995
2996
190
 exit:
2997
190
    if (need_grestore) {
2998
0
        code1= pdfi_grestore(ctx);
2999
0
        if (code == 0) code = code1;
3000
0
    }
3001
190
    code1 = pdfi_annot_end_transparency(ctx, annot);
3002
190
    if (code == 0) code = code1;
3003
7.59k
 exit1:
3004
7.59k
    pdfi_countdown(Parent);
3005
7.59k
    pdfi_countdown(Contents);
3006
7.59k
    pdfi_countdown(T);
3007
7.59k
    return code;
3008
190
}
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
1.13k
{
3016
1.13k
    int code = 0;
3017
1.13k
    int code1 = 0;
3018
1.13k
    gs_rect lrect;
3019
1.13k
    pdf_array *L = NULL;
3020
1.13k
    bool drawit;
3021
3022
1.13k
    code = pdfi_annot_start_transparency(ctx, annot);
3023
1.13k
    if (code < 0) goto exit1;
3024
3025
1.13k
    code = pdfi_dict_knownget_type(ctx, annot, "L", PDF_ARRAY, (pdf_obj **)&L);
3026
1.13k
    if (code < 0) goto exit;
3027
3028
1.13k
    code = pdfi_array_to_gs_rect(ctx, L, &lrect);
3029
1.13k
    if (code < 0) goto exit;
3030
3031
1.13k
    code = pdfi_annot_setcolor(ctx, annot, false, &drawit);
3032
1.13k
    if (code < 0) goto exit;
3033
3034
    /* Handle LE */
3035
1.13k
    code = pdfi_annot_draw_LE(ctx, annot, lrect.p.x, lrect.p.y, lrect.q.x, lrect.q.y, 0);
3036
1.13k
    if (code < 0) goto exit;
3037
3038
    /* Draw the actual line */
3039
1.12k
    code = gs_moveto(ctx->pgs, lrect.p.x, lrect.p.y);
3040
1.12k
    if (code < 0) goto exit;
3041
1.12k
    code = gs_lineto(ctx->pgs, lrect.q.x, lrect.q.y);
3042
1.12k
    if (code < 0) goto exit;
3043
1.12k
    code = pdfi_annot_draw_border(ctx, annot, true);
3044
1.12k
    if (code < 0) goto exit;
3045
3046
1.13k
 exit:
3047
1.13k
    code1 = pdfi_annot_end_transparency(ctx, annot);
3048
1.13k
    if (code >= 0)
3049
1.11k
        code = code1;
3050
1.13k
 exit1:
3051
1.13k
    *render_done = true;
3052
1.13k
    pdfi_countdown(L);
3053
1.13k
    return code;
3054
1.13k
}
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
529
{
3059
529
    int code = 0;
3060
529
    int i;
3061
3062
2.80k
    for (i=0; i<pdfi_array_size(Vertices); i+=2) {
3063
2.28k
        double x,y;
3064
3065
2.28k
        code = pdfi_array_get_number(ctx, Vertices, i, &x);
3066
2.28k
        if (code < 0) goto exit;
3067
2.28k
        code = pdfi_array_get_number(ctx, Vertices, i+1, &y);
3068
2.28k
        if (code < 0) goto exit;
3069
3070
2.27k
        if (i == 0) {
3071
529
            code = gs_moveto(ctx->pgs, x, y);
3072
529
            if (code < 0) goto exit;
3073
1.74k
        } else {
3074
1.74k
            code = gs_lineto(ctx->pgs, x, y);
3075
1.74k
            if (code < 0) goto exit;
3076
1.74k
        }
3077
2.27k
    }
3078
3079
529
 exit:
3080
529
    return code;
3081
529
}
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
516
{
3090
516
    int code = 0;
3091
516
    int code1 = 0;
3092
516
    pdf_array *Vertices = NULL, *Path = NULL, *Line = NULL;
3093
516
    bool drawit;
3094
516
    int size;
3095
516
    double x1, y1, x2, y2, x3, y3, ends[8];
3096
516
    bool Vertices_known = false, Path_known = false;
3097
3098
516
    code = pdfi_annot_start_transparency(ctx, annot);
3099
516
    if (code < 0) goto exit1;
3100
3101
516
    code = pdfi_dict_known(ctx, annot, "Vertices", &Vertices_known);
3102
516
    if (code < 0) goto exit1;
3103
516
    code = pdfi_dict_known(ctx, annot, "Path", &Path_known);
3104
516
    if (code < 0) goto exit1;
3105
3106
516
    code = pdfi_gsave(ctx);
3107
516
    if (code < 0) goto exit1;
3108
3109
    /* If both are known, or neither are known, then there is a problem */
3110
516
    if (Vertices_known == Path_known) {
3111
4
        code = gs_note_error(gs_error_undefined);
3112
4
        goto exit;
3113
4
    }
3114
3115
512
    if (Vertices_known) {
3116
512
        code = pdfi_dict_get_type(ctx, annot, "Vertices", PDF_ARRAY, (pdf_obj **)&Vertices);
3117
512
        if (code < 0) goto exit;
3118
3119
512
        size = pdfi_array_size(Vertices);
3120
512
        if (size == 0) {
3121
0
            code = 0;
3122
0
            goto exit;
3123
0
        }
3124
512
        code = pdfi_annot_path_array(ctx, annot, Vertices);
3125
512
        if (code < 0) goto exit1;
3126
3127
503
        code = pdfi_annot_setcolor(ctx, annot, false, &drawit);
3128
503
        if (code < 0) goto exit;
3129
3130
503
        code = pdfi_annot_draw_border(ctx, annot, true);
3131
503
        if (code < 0) goto exit;
3132
3133
503
        if (size >= 4) {
3134
503
            code = pdfi_array_get_number(ctx, Vertices, 0, &x1);
3135
503
            if (code < 0) goto exit;
3136
503
            code = pdfi_array_get_number(ctx, Vertices, 1, &y1);
3137
503
            if (code < 0) goto exit;
3138
503
            code = pdfi_array_get_number(ctx, Vertices, 2, &x2);
3139
503
            if (code < 0) goto exit;
3140
503
            code = pdfi_array_get_number(ctx, Vertices, 3, &y2);
3141
503
            if (code < 0) goto exit;
3142
503
            code = pdfi_annot_draw_LE(ctx, annot, x1, y1, x2, y2, 1);
3143
503
            if (code < 0) goto exit;
3144
3145
503
            code = pdfi_array_get_number(ctx, Vertices, size-4, &x1);
3146
503
            if (code < 0) goto exit;
3147
503
            code = pdfi_array_get_number(ctx, Vertices, size-3, &y1);
3148
503
            if (code < 0) goto exit;
3149
503
            code = pdfi_array_get_number(ctx, Vertices, size-2, &x2);
3150
503
            if (code < 0) goto exit;
3151
503
            code = pdfi_array_get_number(ctx, Vertices, size-1, &y2);
3152
503
            if (code < 0) goto exit;
3153
503
            code = pdfi_annot_draw_LE(ctx, annot, x1, y1, x2, y2, 2);
3154
503
            if (code < 0) goto exit;
3155
503
        }
3156
503
    } 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
507
 exit:
3265
507
    code1 = pdfi_annot_end_transparency(ctx, annot);
3266
507
    if (code >= 0)
3267
503
        code = code1;
3268
507
    code1 = pdfi_grestore(ctx);
3269
507
    if (code >= 0) code = code1;
3270
3271
516
 exit1:
3272
516
    *render_done = true;
3273
516
    pdfi_countdown(Line);
3274
516
    pdfi_countdown(Vertices);
3275
516
    pdfi_countdown(Path);
3276
516
    return code;
3277
507
}
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
17
{
3285
17
    int code = 0;
3286
17
    int code1 = 0;
3287
17
    pdf_array *Vertices = NULL;
3288
17
    bool drawit;
3289
3290
17
    code = pdfi_annot_start_transparency(ctx, annot);
3291
17
    if (code < 0) goto exit1;
3292
3293
17
    code = pdfi_dict_knownget_type(ctx, annot, "Vertices", PDF_ARRAY, (pdf_obj **)&Vertices);
3294
17
    if (code <= 0) goto exit;
3295
3296
17
    code = pdfi_annot_path_array(ctx, annot, Vertices);
3297
17
    if (code < 0) goto exit1;
3298
3299
17
    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
17
    code = pdfi_annot_setinteriorcolor(ctx, annot, false, &drawit);
3306
17
    if (code < 0) goto exit;
3307
17
    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
17
    code = pdfi_annot_setcolor(ctx, annot, false, &drawit);
3314
17
    if (code < 0) goto exit;
3315
17
    if (drawit) {
3316
17
        code = pdfi_annot_draw_border(ctx, annot, true);
3317
17
        if (code < 0) goto exit;
3318
17
    }
3319
3320
17
 exit:
3321
17
    code1 = pdfi_annot_end_transparency(ctx, annot);
3322
17
    if (code >= 0)
3323
17
        code = code1;
3324
17
 exit1:
3325
17
    *render_done = true;
3326
17
    pdfi_countdown(Vertices);
3327
17
    return code;
3328
17
}
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
139
{
3336
139
    int code = 0;
3337
139
    int code1 = 0;
3338
139
    bool drawit;
3339
3340
139
    code = pdfi_annot_start_transparency(ctx, annot);
3341
139
    if (code < 0) goto exit1;
3342
3343
139
    code = pdfi_annot_setinteriorcolor(ctx, annot, false, &drawit);
3344
139
    if (code < 0) goto exit;
3345
139
    if (drawit) {
3346
51
        code = pdfi_annot_opacity(ctx, annot);
3347
51
        if (code < 0) goto exit;
3348
51
        code = pdfi_annot_fillRect(ctx, annot);
3349
51
        if (code < 0) goto exit;
3350
3351
51
        code = pdfi_annot_setcolor(ctx, annot, false, &drawit);
3352
51
        if (code < 0) goto exit;
3353
3354
51
        if (drawit) {
3355
51
            code = pdfi_annot_draw_border(ctx, annot, false);
3356
51
            if (code < 0) goto exit;
3357
51
        }
3358
88
    } else {
3359
88
        code = pdfi_annot_RectRD_path(ctx, annot);
3360
88
        if (code < 0) goto exit;
3361
3362
88
        code = pdfi_annot_setcolor(ctx, annot, false, &drawit);
3363
88
        if (code < 0) goto exit;
3364
3365
80
        if (drawit) {
3366
80
            code = pdfi_annot_draw_border(ctx, annot, true);
3367
80
            if (code < 0) goto exit;
3368
80
        }
3369
80
    }
3370
3371
139
 exit:
3372
139
    code1 = pdfi_annot_end_transparency(ctx, annot);
3373
139
    if (code >= 0)
3374
131
        code = code1;
3375
139
 exit1:
3376
139
    *render_done = true;
3377
139
    return code;
3378
139
}
3379
3380
static int pdfi_annot_render_MK_box(pdf_context *ctx, pdf_dict *annot, pdf_dict *MK)
3381
58.2k
{
3382
58.2k
    int code = 0;
3383
58.2k
    bool drawit = false;
3384
58.2k
    gs_rect rect;
3385
58.2k
    bool need_grestore = false;
3386
3387
    /* Basically just render the rectangle around the widget for now */
3388
58.2k
    code = pdfi_annot_Rect(ctx, annot, &rect);
3389
58.2k
    if (code < 0) goto exit;
3390
3391
58.1k
    code = pdfi_gsave(ctx);
3392
58.1k
    if (code < 0) goto exit;
3393
58.1k
    need_grestore = true;
3394
58.1k
    code = pdfi_annot_setcolor_key(ctx, MK, "BG", false, &drawit);
3395
58.1k
    if (code < 0) goto exit;
3396
58.1k
    if (drawit)
3397
200
        code = gs_rectfill(ctx->pgs, &rect, 1);
3398
58.1k
    if (code < 0) goto exit;
3399
58.1k
    need_grestore = false;
3400
58.1k
    code = pdfi_grestore(ctx);
3401
58.1k
    if (code < 0) goto exit;
3402
3403
58.1k
    code = pdfi_gsave(ctx);
3404
58.1k
    if (code < 0) goto exit;
3405
58.1k
    need_grestore = true;
3406
58.1k
    code = pdfi_annot_setcolor_key(ctx, MK, "BC", false, &drawit);
3407
58.1k
    if (code < 0) goto exit;
3408
58.1k
    if (drawit)
3409
279
        code = gs_rectstroke(ctx->pgs, &rect, 1, NULL);
3410
58.1k
    if (code < 0) goto exit;
3411
58.1k
    need_grestore = false;
3412
58.1k
    code = pdfi_grestore(ctx);
3413
58.1k
    if (code < 0) goto exit;
3414
3415
    /* TODO: Stuff with can-regenerate-ap ?? */
3416
3417
58.2k
 exit:
3418
58.2k
    if (need_grestore)
3419
0
        (void)pdfi_grestore(ctx);
3420
58.2k
    return code;
3421
58.1k
}
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
191
{
3447
191
    int code;
3448
#ifdef DEBUG
3449
    bool Radio = false;
3450
    bool Pushbutton = false;
3451
#endif
3452
191
    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
191
    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
191
    code = pdfi_form_get_inheritable_int(ctx, field, "Ff", &value);
3464
191
    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
191
 exit:
3476
191
    return 0;
3477
191
}
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
178
{
3482
178
    bool did_mod = false;
3483
178
    int code = 0;
3484
178
    int skip = 0;
3485
178
    pdf_string *newV = NULL;
3486
3487
178
    *is_UTF16 = false;
3488
3489
178
    if (IS_UTF8(V->data)) {
3490
0
        skip = 3;
3491
178
    } else if (IS_UTF16(V->data)) {
3492
3
        skip = 2;
3493
3
        *is_UTF16 = true;
3494
3
    }
3495
3496
178
    if (skip == 0)
3497
175
        goto exit;
3498
3499
    /* Create a new V that skips over the BOM */
3500
3
    code = pdfi_object_alloc(ctx, PDF_STRING, V->length-skip, (pdf_obj **)&newV);
3501
3
    if (code < 0)
3502
0
        goto exit;
3503
3
    pdfi_countup(newV);
3504
3505
3
    memcpy(newV->data, V->data+skip, newV->length);
3506
3
    did_mod = true;
3507
3508
178
 exit:
3509
    /* If didn't need to mod it, just copy the original and get a ref */
3510
178
    if (did_mod) {
3511
3
        *mod_V = newV;
3512
175
    } else {
3513
175
        *mod_V = V;
3514
175
        pdfi_countup(V);
3515
175
    }
3516
178
    return code;
3517
3
}
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
176
{
3523
176
    int code = 0;
3524
176
    gs_rect modrect;
3525
176
    double lineheight = 0;
3526
176
    gs_rect bbox;
3527
176
    gs_point awidth;
3528
176
    double y_adjust = 0.0f, x_adjust = 0.0f;
3529
3530
176
    modrect = *rect; /* structure copy */
3531
3532
176
    code = pdfi_annot_get_text_height(ctx, &lineheight);
3533
176
    if (code < 0) goto exit;
3534
3535
    /* text placement adjustments */
3536
176
    switch (Q) {
3537
176
    case 0: /* Left-justified */
3538
176
        x_adjust = 2; /* empirical value */
3539
176
        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
176
    }
3553
3554
    /* Center vertically */
3555
176
    y_adjust = ((rect->q.y - rect->p.y) - lineheight) / 2;
3556
3557
176
    modrect.p.x += x_adjust;
3558
176
    modrect.p.y += y_adjust;
3559
176
    modrect.p.y += (lineheight + 6.) / 10.; /* empirical */
3560
3561
176
    code = pdfi_annot_display_simple_text(ctx, annot, modrect.p.x, modrect.p.y, V);
3562
176
    if (code < 0) goto exit;
3563
176
 exit:
3564
176
    return code;
3565
176
}
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
178
{
3605
178
    int code = 0;
3606
178
    pdf_string *modV = NULL;
3607
178
    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
178
    code = pdfi_form_modV(ctx, V, &modV, &is_UTF16);
3615
178
    if (code < 0) goto exit;
3616
3617
178
    if (Ff & PDFI_FORM_FF_MULTILINE) {
3618
2
        code = pdfi_form_Tx_multiline(ctx, annot, rect, modV, Ff, Q, is_UTF16);
3619
176
    } else if (Ff & PDFI_FORM_FF_COMB) {
3620
0
        code = pdfi_form_Tx_comb(ctx, annot, rect, modV, Ff, Q, MaxLen, is_UTF16);
3621
176
    } else {
3622
176
        code = pdfi_form_Tx_simple(ctx, annot, rect, modV, Ff, Q, is_UTF16);
3623
176
    }
3624
3625
178
 exit:
3626
178
    pdfi_countdown(modV);
3627
178
    return code;
3628
178
}
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
52.4k
{
3634
52.4k
    int code = 0;
3635
52.4k
    pdf_string *V = NULL;
3636
52.4k
    gs_rect annotrect;
3637
52.4k
    int64_t Ff;
3638
52.4k
    int64_t MaxLen;
3639
52.4k
    int64_t Q;
3640
3641
52.4k
    code = pdfi_annot_Rect(ctx, annot, &annotrect);
3642
52.4k
    if (code < 0) goto exit;
3643
3644
    /* Set DA (Default Appearance)
3645
     * This will generally set a color and font.
3646
     */
3647
52.4k
    code = pdfi_annot_process_DA(ctx, annot, annot, &annotrect, true);
3648
52.4k
    if (code < 0) goto exit;
3649
3650
52.3k
    code = pdfi_form_get_inheritable_int(ctx, annot, "Ff", &Ff);
3651
52.3k
    if (code < 0) goto exit;
3652
3653
51.0k
    code = pdfi_form_get_inheritable_int(ctx, annot, "MaxLen", &MaxLen);
3654
51.0k
    if (code < 0) goto exit;
3655
3656
44.1k
    code = pdfi_form_get_inheritable_int(ctx, annot, "Q", &Q);
3657
44.1k
    if (code < 0) goto exit;
3658
3659
44.0k
    code = pdfi_dict_knownget_type(ctx, annot, "V", PDF_STRING, (pdf_obj **)&V);
3660
44.0k
    if (code < 0) goto exit;
3661
44.0k
    if (code > 0) {
3662
178
        code = pdfi_form_display_Tx(ctx, annot, &annotrect, V, Ff, Q, MaxLen);
3663
178
        if (code < 0) goto exit;
3664
178
    }
3665
3666
52.4k
 exit:
3667
52.4k
    pdfi_countdown(V);
3668
52.4k
    return code;
3669
44.0k
}
3670
3671
/* draw field Tx */
3672
static int pdfi_form_draw_Tx(pdf_context *ctx, pdf_dict *annot, pdf_obj *AP)
3673
52.2k
{
3674
52.2k
    if (AP != NULL)
3675
0
        return pdfi_annot_draw_AP(ctx, annot, AP);
3676
3677
52.2k
    return pdfi_form_draw_Tx_Ch(ctx, annot);
3678
52.2k
}
3679
3680
/* draw field Ch */
3681
static int pdfi_form_draw_Ch(pdf_context *ctx, pdf_dict *field, pdf_obj *AP)
3682
120
{
3683
120
    if (!ctx->NeedAppearances && AP != NULL)
3684
0
        return pdfi_annot_draw_AP(ctx, field, AP);
3685
3686
120
    return pdfi_form_draw_Tx_Ch(ctx, field);
3687
120
}
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
52.6k
{
3715
52.6k
    int code;
3716
3717
52.6k
    if (pdfi_name_is(FT, "Btn")) {
3718
191
        code = pdfi_form_draw_Btn(ctx, field, AP);
3719
52.4k
    } else if (pdfi_name_is(FT, "Tx")) {
3720
52.2k
        code = pdfi_form_draw_Tx(ctx, field, AP);
3721
52.2k
    } else if (pdfi_name_is(FT, "Ch")) {
3722
120
        code = pdfi_form_draw_Ch(ctx, field, AP);
3723
120
    } else if (pdfi_name_is(FT, "Sig")) {
3724
0
        code = pdfi_form_draw_Sig(ctx, field, AP);
3725
14
    } else {
3726
14
        errprintf(ctx->memory, "*** WARNING unknown field FT ignored\n");
3727
        /* TODO: Handle warning better */
3728
14
        code = 0;
3729
14
    }
3730
3731
52.6k
    return code;
3732
52.6k
}
3733
3734
/* Render Widget with no AP
3735
 */
3736
static int pdfi_annot_render_Widget(pdf_context *ctx, pdf_dict *annot)
3737
58.8k
{
3738
58.8k
    int code = 0;
3739
58.8k
    pdf_dict *MK = NULL;
3740
58.8k
    pdf_name *FT = NULL;
3741
3742
    /* Render box around the widget using MK */
3743
58.8k
    code = pdfi_dict_knownget_type(ctx, annot, "MK", PDF_DICT, (pdf_obj **)&MK);
3744
58.8k
    if (code < 0) goto exit;
3745
58.8k
    if (code > 0) {
3746
58.2k
        code = pdfi_annot_render_MK_box(ctx, annot, MK);
3747
58.2k
        if (code < 0) goto exit;
3748
58.2k
    }
3749
3750
    /* Render the other contents */
3751
58.7k
    code = pdfi_dict_knownget_type(ctx, annot, "FT", PDF_NAME, (pdf_obj **)&FT);
3752
58.7k
    if (code < 0) goto exit;
3753
58.7k
    if (code > 0) {
3754
52.6k
        code = pdfi_annot_render_field(ctx, annot, FT, NULL);
3755
52.6k
        if (code < 0) goto exit;
3756
52.6k
    }
3757
3758
58.8k
 exit:
3759
58.8k
    pdfi_countdown(FT);
3760
58.8k
    pdfi_countdown(MK);
3761
58.8k
    return code;
3762
58.7k
}
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
152k
{
3767
152k
    int code = 0;
3768
152k
    bool found_T = false;
3769
152k
    bool found_FT = false, known = false;
3770
152k
    pdf_obj *T = NULL;
3771
152k
    pdf_obj *FT = NULL;
3772
152k
    pdf_dict *Parent = NULL;
3773
152k
    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
152k
    code = pdfi_loop_detector_mark(ctx);
3791
152k
    if (code < 0)
3792
0
        goto exit;
3793
3794
152k
    currdict = annot;
3795
152k
    pdfi_countup(currdict);
3796
196k
    while (true) {
3797
196k
        if (currdict->object_num != 0) {
3798
196k
            code = pdfi_loop_detector_add_object(ctx, currdict->object_num);
3799
196k
            if (code < 0)
3800
0
                break;
3801
196k
        }
3802
3803
196k
        code = pdfi_dict_knownget(ctx, currdict, "T", &T);
3804
196k
        if (code < 0) goto exit;
3805
196k
        if (code > 0) {
3806
147k
            found_T = true;
3807
147k
            pdfi_countdown(T);
3808
147k
            T = NULL;
3809
147k
            if (found_FT)
3810
195
                break;
3811
147k
        }
3812
196k
        code = pdfi_dict_knownget(ctx, currdict, "FT", &FT);
3813
196k
        if (code < 0) goto exit;
3814
196k
        if (code > 0) {
3815
147k
            found_FT = true;
3816
147k
            pdfi_countdown(FT);
3817
147k
            FT = NULL;
3818
147k
            if (found_T)
3819
147k
                break;
3820
147k
        }
3821
        /* Check for Parent. Do not store the dereferenced Parent back to the dictionary
3822
         * as this can cause circular references.
3823
         */
3824
48.6k
        code = pdfi_dict_known(ctx, currdict, "Parent", &known);
3825
48.6k
        if (code >= 0 && known == true)
3826
45.9k
        {
3827
45.9k
            code = pdfi_dict_get_no_store_R(ctx, currdict, "Parent", (pdf_obj **)&Parent);
3828
45.9k
            if (code < 0) {
3829
2.28k
                (void)pdfi_loop_detector_cleartomark(ctx);
3830
2.28k
                goto exit;
3831
2.28k
            }
3832
43.6k
            if (pdfi_type_of(Parent) != PDF_DICT) {
3833
284
                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
284
                } else {
3841
284
                    break;
3842
284
                }
3843
284
            }
3844
43.3k
            pdfi_countdown(currdict);
3845
43.3k
            currdict = Parent;
3846
43.3k
            Parent = NULL;
3847
43.3k
        } else
3848
2.71k
            break;
3849
48.6k
    }
3850
3851
150k
    (void)pdfi_loop_detector_cleartomark(ctx);
3852
3853
150k
    code = 0;
3854
150k
    if (!found_T || !found_FT) {
3855
3.00k
        *render_done = true;
3856
3.00k
        outprintf(ctx->memory, "**** Warning: A Widget annotation dictionary lacks either the FT or T key.\n");
3857
3.00k
        outprintf(ctx->memory, "              Acrobat ignores such annoataions, annotation will not be rendered.\n");
3858
3.00k
        outprintf(ctx->memory, "              Output may not be as expected.\n");
3859
3.00k
        goto exit;
3860
3.00k
    }
3861
3862
147k
    if (NormAP) {
3863
        /* Let caller render it */
3864
88.7k
        *render_done = false;
3865
88.7k
        goto exit;
3866
88.7k
    }
3867
3868
    /* No AP, try to render the Widget ourselves */
3869
58.8k
    code = pdfi_annot_render_Widget(ctx, annot);
3870
58.8k
    *render_done = true;
3871
3872
152k
 exit:
3873
152k
    pdfi_countdown(Parent);
3874
152k
    pdfi_countdown(currdict);
3875
152k
    return code;
3876
58.8k
}
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
6
{
3881
6
    int code = 0;
3882
6
    pdf_name *Subtype = NULL;
3883
6
    char str[100];
3884
3885
6
    code = pdfi_dict_get_type(ctx, annot, "Subtype", PDF_NAME, (pdf_obj **)&Subtype);
3886
6
    if (code < 0) goto exit;
3887
3888
6
    memcpy(str, (const char *)Subtype->data, Subtype->length < 100 ? Subtype->length : 99);
3889
6
    str[Subtype->length < 100 ? Subtype->length : 99] = '\0';
3890
6
    dbgmprintf1(ctx->memory, "ANNOT: No AP, default appearance for Subtype %s Not Implemented\n", str);
3891
3892
6
 exit:
3893
6
    *render_done = false;
3894
6
    pdfi_countdown(Subtype);
3895
6
    return code;
3896
6
}
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
561k
{
3951
561k
    int code;
3952
561k
    bool is_3D = false;
3953
561k
    bool is_visible = true;
3954
561k
    int64_t F;
3955
3956
561k
    if (pdfi_name_is(subtype, "3D"))
3957
0
        is_3D = true;
3958
3959
561k
    code = pdfi_dict_get_int(ctx, annot, "F", &F);
3960
561k
    if (code < 0)
3961
54.7k
        F = 0;
3962
3963
561k
    if ((F & 0x2) != 0) { /* Bit 2 -- Hidden */
3964
158k
        is_visible = false; /* Hidden */
3965
158k
        goto exit;
3966
158k
    }
3967
3968
403k
    if (ctx->args.printed) {
3969
        /* Even if Print flag (bit 3) is off, will print if 3D */
3970
403k
        is_visible = ((F & 0x4) != 0) || is_3D;
3971
403k
    } else {
3972
        /* Not NoView (bit 6) */
3973
0
        is_visible = (F & 0x20) == 0;
3974
0
    }
3975
3976
561k
 exit:
3977
561k
    return is_visible;
3978
403k
}
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
348k
{
3985
348k
    char **ptr;
3986
3987
    /* True if no list */
3988
348k
    if (!ctx->args.showannottypes)
3989
348k
        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
76.1k
{
4008
76.1k
    char **ptr;
4009
4010
    /* True if no list */
4011
76.1k
    if (!ctx->args.preserveannottypes)
4012
76.1k
        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
561k
{
4028
561k
    pdf_obj *NormAP = NULL;
4029
561k
    int code = 0;
4030
561k
    annot_dispatch_t *dispatch_ptr;
4031
561k
    bool render_done = true;
4032
4033
    /* See if annotation is visible */
4034
561k
    if (!pdfi_annot_visible(ctx, annot, subtype))
4035
213k
        goto exit;
4036
4037
    /* See if we are rendering this type of annotation */
4038
348k
    if (!pdfi_annot_check_type(ctx, subtype))
4039
0
        goto exit;
4040
4041
    /* Get the Normal AP, if it exists */
4042
348k
    code = pdfi_annot_get_NormAP(ctx, annot, &NormAP);
4043
348k
    if (code < 0) goto exit;
4044
4045
285k
    code = pdfi_gsave(ctx);
4046
285k
    if (code < 0) goto exit;
4047
4048
    /* Draw the annotation */
4049
4.48M
    for (dispatch_ptr = annot_dispatch; dispatch_ptr->subtype; dispatch_ptr ++) {
4050
4.48M
        if (pdfi_name_is(subtype, dispatch_ptr->subtype)) {
4051
285k
            if (NormAP && dispatch_ptr->simpleAP)
4052
117k
                render_done = false;
4053
168k
            else
4054
168k
                code = dispatch_ptr->func(ctx, annot, NormAP, &render_done);
4055
285k
            break;
4056
285k
        }
4057
4.48M
    }
4058
285k
    if (!dispatch_ptr->subtype) {
4059
163
        char str[100];
4060
163
        memcpy(str, (const char *)subtype->data, subtype->length < 100 ? subtype->length : 99);
4061
163
        str[subtype->length < 100 ? subtype->length : 99] = '\0';
4062
163
        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
163
        render_done = false;
4066
163
    }
4067
4068
285k
    if (!render_done)
4069
205k
        code = pdfi_annot_draw_AP(ctx, annot, NormAP);
4070
4071
285k
    (void)pdfi_grestore(ctx);
4072
4073
561k
 exit:
4074
561k
    pdfi_countdown(NormAP);
4075
561k
    return code;
4076
285k
}
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
16.8k
{
4086
16.8k
    int size = 40;
4087
16.8k
    char *buf;
4088
16.8k
    gs_id counter = gs_next_ids(ctx->memory, 1);
4089
4090
16.8k
    buf = (char *)gs_alloc_bytes(ctx->memory, size, "pdfi_annot_preserve_nextformlabel(buf)");
4091
16.8k
    if (buf == NULL)
4092
0
        return_error(gs_error_VMerror);
4093
16.8k
    snprintf(buf, size, "{FN%ld}", counter);
4094
16.8k
    *len = strlen(buf);
4095
16.8k
    *data = (byte *)buf;
4096
16.8k
    return 0;
4097
16.8k
}
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
629
{
4114
629
    int code = 0;
4115
629
    pdf_array *QP = NULL;
4116
629
    gx_device *device = gs_currentdevice(ctx->pgs);
4117
629
    gs_matrix devmatrix, ctm, matrix;
4118
629
    uint64_t arraysize, index;
4119
629
    double old_x, old_y;
4120
629
    gs_point point;
4121
4122
629
    code = pdfi_dict_get(ctx, annot, "QuadPoints", (pdf_obj **)&QP);
4123
629
    if (code < 0) goto exit;
4124
4125
629
    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
629
    arraysize = pdfi_array_size(QP);
4134
629
    if (arraysize % 8 != 0) {
4135
        /* TODO: Flag a warning -- must be sets of 8 values (4 points) */
4136
8
        code = gs_note_error(gs_error_syntaxerror);
4137
8
        goto exit;
4138
8
    }
4139
4140
4141
    /* Get device matrix and adjust by default 72.0 (no idea, just following PS code...) */
4142
621
    devmatrix.xx = 72.0 / device->HWResolution[0];
4143
621
    devmatrix.xy = 0;
4144
621
    devmatrix.yx = 0;
4145
621
    devmatrix.yy = 72.0 / device->HWResolution[1];
4146
621
    devmatrix.tx = 0;
4147
621
    devmatrix.ty = 0;
4148
4149
    /* Get the CTM */
4150
621
    gs_currentmatrix(ctx->pgs, &ctm);
4151
4152
    /* Get matrix to adjust the QuadPoints */
4153
621
    code = gs_matrix_multiply(&ctm, &devmatrix, &matrix);
4154
621
    if (code < 0) goto exit;
4155
4156
    /* Transform all the points by the calculated matrix */
4157
7.39k
    for (index = 0; index < arraysize; index += 2) {
4158
6.77k
        code = pdfi_array_get_number(ctx, QP, index, &old_x);
4159
6.77k
        if (code < 0) goto exit;
4160
6.77k
        code = pdfi_array_get_number(ctx, QP, index+1, &old_y);
4161
6.77k
        if (code < 0) goto exit;
4162
4163
6.77k
        code = gs_point_transform(old_x, old_y, &matrix, &point);
4164
6.77k
        if (code < 0) goto exit;
4165
4166
6.77k
        code = pdfi_array_put_real(ctx, QP, index, point.x);
4167
6.77k
        if (code < 0) goto exit;
4168
6.77k
        code = pdfi_array_put_real(ctx, QP, index+1, point.y);
4169
6.77k
        if (code < 0) goto exit;
4170
6.77k
    }
4171
4172
4173
629
 exit:
4174
629
    pdfi_countdown(QP);
4175
629
    return code;
4176
621
}
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
26.3k
{
4184
26.3k
    int code = 0;
4185
26.3k
    pdf_dict *AP = NULL;
4186
26.3k
    uint64_t index;
4187
26.3k
    pdf_name *Key = NULL;
4188
26.3k
    pdf_indirect_ref *Value = NULL;
4189
26.3k
    byte *labeldata = NULL;
4190
26.3k
    int labellen;
4191
26.3k
    int form_id;
4192
26.3k
    gx_device *device = gs_currentdevice(ctx->pgs);
4193
26.3k
    bool found_ap = false; /* found at least one AP stream? */
4194
26.3k
    pdf_obj *object = NULL;
4195
4196
26.3k
    code = pdfi_dict_get(ctx, annot, "AP", (pdf_obj **)&AP);
4197
26.3k
    if (code < 0) goto exit;
4198
4199
25.4k
    if (pdfi_type_of(AP) != PDF_DICT) {
4200
        /* This is an invalid AP, we will flag and delete it below */
4201
120
        found_ap = false;
4202
120
        goto exit;
4203
120
    }
4204
4205
25.2k
    code = pdfi_dict_key_first(ctx, AP, (pdf_obj **)&Key, &index);
4206
25.3k
    while (code >= 0) {
4207
25.3k
        found_ap = true;
4208
25.3k
        code = pdfi_dict_get_no_deref(ctx, AP, Key, (pdf_obj **)&Value);
4209
25.3k
        if (code < 0) goto exit;
4210
4211
        /* Handle indirect object */
4212
25.3k
        if (pdfi_type_of(Value) != PDF_INDIRECT)
4213
8
            goto loop_continue;
4214
4215
        /* Dereference it */
4216
25.3k
        code = pdfi_dereference(ctx, Value->ref_object_num, Value->ref_generation_num, &object);
4217
25.3k
        if (code < 0) goto exit;
4218
4219
16.9k
        if (pdfi_type_of(object) == PDF_STREAM) {
4220
            /* Get a form label */
4221
16.8k
            code = pdfi_annot_preserve_nextformlabel(ctx, &labeldata, &labellen);
4222
16.8k
            if (code < 0) goto exit;
4223
4224
            /* Notify the driver of the label name */
4225
16.8k
            code = (*dev_proc(device, dev_spec_op))
4226
16.8k
                (device, gxdso_pdf_form_name, labeldata, labellen);
4227
4228
16.8k
            code = pdfi_op_q(ctx);
4229
16.8k
            if (code < 0)
4230
0
                goto exit;
4231
4232
16.8k
            code = pdfi_annot_position_AP(ctx, annot, (pdf_stream *)object);
4233
            /* Draw the high-level form */
4234
16.8k
            code = pdfi_do_highlevel_form(ctx, ctx->page.CurrentPageDict, (pdf_stream *)object);
4235
16.8k
            (void)pdfi_op_Q(ctx);
4236
16.8k
            if (code < 0) goto exit;
4237
4238
            /* Get the object number (form_id) of the high level form */
4239
16.8k
            code = (*dev_proc(device, dev_spec_op))
4240
16.8k
                (device, gxdso_get_form_ID, &form_id, sizeof(int));
4241
4242
            /* Save the highlevel form info for pdfi_obj_indirect_str() */
4243
16.8k
            Value->highlevel_object_num = form_id;
4244
16.8k
            Value->is_highlevelform = true;
4245
4246
16.8k
        }
4247
4248
16.9k
    loop_continue:
4249
16.9k
        pdfi_countdown(Key);
4250
16.9k
        Key = NULL;
4251
16.9k
        pdfi_countdown(Value);
4252
16.9k
        Value = NULL;
4253
16.9k
        pdfi_countdown(object);
4254
16.9k
        object = NULL;
4255
16.9k
        gs_free_object(ctx->memory, labeldata, "pdfi_annot_preserve_modAP(labeldata)");
4256
16.9k
        labeldata = NULL;
4257
4258
16.9k
        code = pdfi_dict_key_next(ctx, AP, (pdf_obj **)&Key, &index);
4259
16.9k
        if (code == gs_error_undefined) {
4260
16.9k
            code = 0;
4261
16.9k
            break;
4262
16.9k
        }
4263
16.9k
    }
4264
16.9k
    if (code < 0) goto exit;
4265
4266
26.3k
 exit:
4267
    /* If there was no AP found, then delete the key completely.
4268
     * (Bug697951.pdf)
4269
     */
4270
26.3k
    if (!found_ap) {
4271
        /* TODO: Flag a warning for broken file? */
4272
1.03k
        code = pdfi_dict_delete_pair(ctx, annot, AP_key);
4273
1.03k
    }
4274
4275
26.3k
    if (labeldata)
4276
4
        gs_free_object(ctx->memory, labeldata, "pdfi_annot_preserve_modAP(labeldata)");
4277
26.3k
    pdfi_countdown(AP);
4278
26.3k
    pdfi_countdown(Key);
4279
26.3k
    pdfi_countdown(Value);
4280
26.3k
    pdfi_countdown(object);
4281
26.3k
    return code;
4282
16.9k
}
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
460k
{
4389
460k
    int i = 0;
4390
4391
8.23M
    for (i = 0; i < sizeof(PermittedKeys) / sizeof (const char *); i++) {
4392
8.17M
        if (pdfi_name_is(Key, PermittedKeys[i]))
4393
399k
            return 1;
4394
8.17M
    }
4395
60.4k
    return 0;
4396
460k
}
4397
4398
static int pdfi_annot_preserve_mark(pdf_context *ctx, pdf_dict *annot, pdf_name *subtype)
4399
60.7k
{
4400
60.7k
    int code = 0;
4401
60.7k
    gs_matrix ctm;
4402
60.7k
    pdf_dict *tempdict = NULL;
4403
60.7k
    uint64_t dictsize;
4404
60.7k
    uint64_t index;
4405
60.7k
    pdf_name *Key = NULL;
4406
60.7k
    pdf_obj *Value = NULL;
4407
60.7k
    bool resolve = false;
4408
4409
    /* Create a temporary copy of the annot dict */
4410
60.7k
    dictsize = pdfi_dict_entries(annot);
4411
60.7k
    code = pdfi_dict_alloc(ctx, dictsize, &tempdict);
4412
60.7k
    if (code < 0) goto exit;
4413
60.7k
    pdfi_countup(tempdict);
4414
60.7k
    code = pdfi_dict_copy(ctx, tempdict, annot);
4415
60.7k
    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
60.7k
    code = pdfi_dict_key_first(ctx, annot, (pdf_obj **)&Key, &index);
4424
460k
    while (code >= 0) {
4425
460k
        resolve = false;
4426
4427
460k
        if (!isKnownKey(ctx, Key)) {
4428
60.4k
            code = pdfi_dict_delete_pair(ctx, tempdict, Key);
4429
60.4k
            if (code < 0) goto exit;
4430
399k
        } else {
4431
399k
            if (pdfi_name_is(Key, "AP")) {
4432
                /* Special handling for AP -- have fun! */
4433
26.3k
                code = pdfi_annot_preserve_modAP(ctx, tempdict, Key);
4434
26.3k
                if (code < 0) goto exit;
4435
373k
            } else if (pdfi_name_is(Key, "QuadPoints")) {
4436
629
                code = pdfi_annot_preserve_modQP(ctx, tempdict, Key);
4437
629
                if (code < 0) goto exit;
4438
373k
            } else if (pdfi_name_is(Key, "A")) {
4439
8.79k
                code = pdfi_pdfmark_modA(ctx, tempdict);
4440
8.79k
                if (code < 0) goto exit;
4441
364k
            } else if (pdfi_name_is(Key, "Dest")) {
4442
45
                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
45
                code = pdfi_pdfmark_modDest(ctx, tempdict);
4448
45
                if (code < 0) goto exit;
4449
364k
            } 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
364k
            } else if (pdfi_name_is(Key, "Sound") || pdfi_name_is(Key, "Movie")) {
4460
0
                resolve = false;
4461
364k
            } else {
4462
364k
                resolve = true;
4463
364k
            }
4464
399k
        }
4465
451k
        if (resolve) {
4466
364k
            code = pdfi_dict_get_by_key(ctx, annot, (const pdf_name *)Key, &Value);
4467
364k
            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
364k
            code = pdfi_resolve_indirect_loop_detect(ctx, (pdf_obj *)annot, Value, false);
4476
364k
            if (code < 0) goto exit;
4477
364k
        }
4478
4479
451k
        pdfi_countdown(Key);
4480
451k
        Key = NULL;
4481
451k
        pdfi_countdown(Value);
4482
451k
        Value = NULL;
4483
4484
451k
        code = pdfi_dict_key_next(ctx, annot, (pdf_obj **)&Key, &index);
4485
451k
        if (code == gs_error_undefined) {
4486
51.5k
            code = 0;
4487
51.5k
            break;
4488
51.5k
        }
4489
451k
    }
4490
51.5k
    if (code < 0) goto exit;
4491
4492
    /* Do pdfmark from the tempdict */
4493
51.5k
    gs_currentmatrix(ctx->pgs, &ctm);
4494
4495
51.5k
    if (pdfi_name_is(subtype, "Link"))
4496
8.01k
        code = pdfi_pdfmark_from_dict(ctx, tempdict, &ctm, "LNK");
4497
43.5k
    else
4498
43.5k
        code = pdfi_pdfmark_from_dict(ctx, tempdict, &ctm, "ANN");
4499
51.5k
    if (code < 0) goto exit;
4500
4501
60.7k
 exit:
4502
60.7k
    pdfi_countdown(tempdict);
4503
60.7k
    pdfi_countdown(Key);
4504
60.7k
    pdfi_countdown(Value);
4505
60.7k
    return code;
4506
51.5k
}
4507
4508
static int pdfi_annot_preserve_default(pdf_context *ctx, pdf_dict *annot, pdf_name *subtype)
4509
51.9k
{
4510
51.9k
    return pdfi_annot_preserve_mark(ctx, annot, subtype);
4511
51.9k
}
4512
4513
static int pdfi_annot_preserve_Link(pdf_context *ctx, pdf_dict *annot, pdf_name *subtype)
4514
8.84k
{
4515
8.84k
    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
8.84k
    code = pdfi_annot_preserve_mark(ctx, annot, subtype);
4522
8.84k
    return code;
4523
8.84k
}
4524
4525
static int pdfi_annot_preserve_Widget(pdf_context *ctx, pdf_dict *annot, pdf_name *subtype)
4526
15.2k
{
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
15.2k
    return pdfi_annot_draw(ctx, annot, subtype);
4537
15.2k
}
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
    /*    {"Screen", pdfi_annot_preserve_default},  /* TODO: fts_07_0709.pdf */
4556
    {"Sound", pdfi_annot_preserve_default},
4557
    {"Square", pdfi_annot_preserve_default},
4558
    {"Squiggly", pdfi_annot_preserve_default},
4559
    {"StrikeOut", pdfi_annot_preserve_default},
4560
    {"Underline", pdfi_annot_preserve_default},
4561
    {"Stamp", pdfi_annot_preserve_default},
4562
    {"Text", pdfi_annot_preserve_default},
4563
    {"TrapNet", pdfi_annot_preserve_default},
4564
    { NULL, NULL},
4565
};
4566
4567
static int pdfi_annot_preserve(pdf_context *ctx, pdf_dict *annot, pdf_name *subtype)
4568
76.1k
{
4569
76.1k
    int code = 0;
4570
76.1k
    annot_preserve_dispatch_t *dispatch_ptr;
4571
4572
    /* If not preserving this subtype, draw it instead */
4573
76.1k
    if (!pdfi_annot_preserve_type(ctx, subtype))
4574
0
        return pdfi_annot_draw(ctx, annot, subtype);
4575
4576
    /* Handle the annotation */
4577
655k
    for (dispatch_ptr = annot_preserve_dispatch; dispatch_ptr->subtype; dispatch_ptr ++) {
4578
655k
        if (pdfi_name_is(subtype, dispatch_ptr->subtype)) {
4579
76.0k
            code = dispatch_ptr->func(ctx, annot, subtype);
4580
76.0k
            break;
4581
76.0k
        }
4582
655k
    }
4583
4584
    /* If there is no handler, just draw it */
4585
    /* NOTE: gs does a drawwidget here instead (?) */
4586
76.1k
    if (!dispatch_ptr->subtype)
4587
91
        code = pdfi_annot_draw(ctx, annot, subtype);
4588
4589
76.1k
    return code;
4590
76.1k
}
4591
4592
static int pdfi_annot_handle(pdf_context *ctx, pdf_dict *annot)
4593
623k
{
4594
623k
    int code = 0;
4595
623k
    pdf_name *Subtype = NULL;
4596
4597
623k
    code = pdfi_dict_get_type(ctx, annot, "Subtype", PDF_NAME, (pdf_obj **)&Subtype);
4598
623k
    if (code != 0) {
4599
        /* TODO: Set warning flag */
4600
1.07k
        dbgmprintf(ctx->memory, "WARNING: Ignoring annotation with missing Subtype\n");
4601
1.07k
        code = 0;
4602
1.07k
        goto exit;
4603
1.07k
    }
4604
4605
622k
    if (ctx->args.preserveannots && ctx->device_state.annotations_preserved)
4606
76.1k
        code = pdfi_annot_preserve(ctx, annot, Subtype);
4607
546k
    else
4608
546k
        code = pdfi_annot_draw(ctx, annot, Subtype);
4609
4610
623k
 exit:
4611
623k
    pdfi_countdown(Subtype);
4612
623k
    if (code < 0) {
4613
83.5k
        code = pdfi_set_error_stop(ctx, code, NULL, E_PDF_BAD_ANNOTATION, "pdfi_annot_handle", "Error handling annotation");
4614
83.5k
    }
4615
623k
    return code;
4616
622k
}
4617
4618
int pdfi_do_annotations(pdf_context *ctx, pdf_dict *page_dict)
4619
123k
{
4620
123k
    int code = 0;
4621
123k
    pdf_array *Annots = NULL;
4622
123k
    pdf_dict *annot = NULL;
4623
123k
    int i;
4624
4625
123k
    if (!ctx->args.showannots)
4626
0
        return 0;
4627
4628
123k
    code = pdfi_dict_knownget_type(ctx, page_dict, "Annots", PDF_ARRAY, (pdf_obj **)&Annots);
4629
123k
    if (code <= 0)
4630
91.4k
        return code;
4631
4632
748k
    for (i = 0; i < pdfi_array_size(Annots); i++) {
4633
717k
        code = pdfi_array_get_type(ctx, Annots, i, PDF_DICT, (pdf_obj **)&annot);
4634
717k
        if (code < 0) {
4635
93.2k
            if ((code = pdfi_set_warning_stop(ctx, code, NULL, W_PDF_ANNOT_BAD_TYPE, "pdfi_do_annotations", "")) < 0)
4636
0
                goto exit;
4637
93.2k
            continue;
4638
93.2k
        }
4639
623k
        code = pdfi_annot_handle(ctx, annot);
4640
623k
        if (code < 0 &&
4641
623k
           ((code = pdfi_set_error_stop(ctx, code, NULL, E_PDF_BAD_ANNOTATION, "pdfi_annot_handle", "Error handling annotation")) < 0)) {
4642
1
            goto exit;
4643
1
        }
4644
623k
        pdfi_countdown(annot);
4645
623k
        annot = NULL;
4646
623k
    }
4647
4648
31.8k
 exit:
4649
31.8k
    pdfi_countdown(annot);
4650
31.8k
    pdfi_countdown(Annots);
4651
31.8k
    return code;
4652
31.8k
}
4653
4654
/* draw terminal field */
4655
static int pdfi_form_draw_terminal(pdf_context *ctx, pdf_dict *Page, pdf_dict *field)
4656
0
{
4657
0
    int code = 0;
4658
0
    pdf_indirect_ref *P = NULL;
4659
0
    pdf_name *FT = NULL;
4660
0
    pdf_obj *AP = NULL;
4661
4662
    /* See if the field goes on this page */
4663
    /* NOTE: We know the "P" is an indirect ref, so just fetch it that way.
4664
     * If we fetch the actual object, it will result in a cyclical reference in the cache
4665
     * that causes a memory leak, so don't do that.
4666
     * (The cyclical reference is because the object containing P is actually inside P)
4667
     */
4668
0
    code = pdfi_dict_get_ref(ctx, field, "P", &P);
4669
0
    if (code < 0) {
4670
0
        if (code == gs_error_undefined)
4671
0
            code = 0;
4672
0
        goto exit;
4673
0
    }
4674
4675
0
    if (P->ref_object_num != Page->object_num) {
4676
        /* Not this page */
4677
0
        code = 0;
4678
0
        goto exit;
4679
0
    }
4680
4681
    /* Render the field */
4682
4683
    /* NOTE: The spec says the FT is inheritable, implying it might be present in
4684
     * a Parent and not explicitly in a Child.  The gs implementation doesn't seem
4685
     * to handle this case, but I am going to go ahead and handle it.  We will figure
4686
     * out if this causes diffs later, if ever...
4687
     */
4688
0
    code = pdfi_form_get_inheritable(ctx, field, "FT", PDF_NAME, (pdf_obj **)&FT);
4689
0
    if (code <= 0) goto exit;
4690
4691
0
    code = pdfi_annot_get_NormAP(ctx, field, &AP);
4692
0
    if (code < 0) goto exit;
4693
4694
0
    code = pdfi_annot_render_field(ctx, field, FT, AP);
4695
0
    if (code < 0) goto exit;
4696
4697
0
 exit:
4698
0
    pdfi_countdown(FT);
4699
0
    pdfi_countdown(P);
4700
0
    pdfi_countdown(AP);
4701
0
    return code;
4702
0
}
4703
4704
/* From pdf_draw.ps/draw_form_field():
4705
% We distinguish 4 types of nodes on the form field tree:
4706
%  - non-terminal field - has a kid that refers to the parent (or anywhere else)
4707
%  - terminal field with separate widget annotations - has a kid that doesn't have a parent
4708
%  - terminal field with a merged widget annotation - has no kids
4709
%  - widget annotation - has /Subtype and /Rect
4710
%
4711
% The recursive enumeration of the form fields doesn't descend into widget annotations.
4712
*/
4713
static int pdfi_form_draw_field(pdf_context *ctx, pdf_dict *Page, pdf_dict *field)
4714
0
{
4715
0
    int code = 0;
4716
0
    pdf_array *Kids = NULL;
4717
0
    pdf_dict *child = NULL;
4718
0
    pdf_dict *Parent = NULL;
4719
0
    int i;
4720
4721
0
    code = pdfi_dict_knownget_type(ctx, field, "Kids", PDF_ARRAY, (pdf_obj **)&Kids);
4722
0
    if (code < 0) goto exit;
4723
0
    if (code == 0) {
4724
0
        code = pdfi_form_draw_terminal(ctx, Page, field);
4725
0
        goto exit;
4726
0
    }
4727
4728
    /* Handle Kids */
4729
0
    if (pdfi_array_size(Kids) <= 0) {
4730
0
        code = pdfi_set_error_stop(ctx, gs_note_error(gs_error_undefined), NULL, E_PDF_EMPTY_FORM_KIDS, "pdfi_form_draw_field", "");
4731
0
        goto exit;
4732
0
    }
4733
4734
    /* Check first child to see if it has a parent */
4735
0
    code = pdfi_array_get_type(ctx, Kids, 0, PDF_DICT, (pdf_obj **)&child);
4736
0
    if (code < 0) goto exit;
4737
0
    code = pdfi_dict_knownget_type(ctx, child, "Parent", PDF_DICT, (pdf_obj **)&Parent);
4738
0
    if (code < 0) goto exit;
4739
4740
    /* If kid has no parent, then treat this as terminal field */
4741
0
    if (code == 0) {
4742
        /* TODO: This case isn't tested because no examples available.
4743
         * I think it's only relevant for Btn, and not sure if it
4744
         * should be dealt with here or in Btn routine.
4745
         */
4746
0
        code = pdfi_form_draw_terminal(ctx, Page, field);
4747
0
        goto exit;
4748
0
    }
4749
4750
0
    pdfi_countdown(child);
4751
0
    child = NULL;
4752
    /* Render the Kids (recursive) */
4753
0
    for (i=0; i<pdfi_array_size(Kids); i++) {
4754
0
        code = pdfi_array_get_type(ctx, Kids, i, PDF_DICT, (pdf_obj **)&child);
4755
0
        if (code < 0) goto exit;
4756
4757
0
        code = pdfi_form_draw_field(ctx, Page, child);
4758
0
        if (code < 0) goto exit;
4759
4760
0
        pdfi_countdown(child);
4761
0
        child = NULL;
4762
0
    }
4763
4764
0
 exit:
4765
0
    pdfi_countdown(child);
4766
0
    pdfi_countdown(Kids);
4767
0
    pdfi_countdown(Parent);
4768
0
    return code;
4769
0
}
4770
4771
int pdfi_do_acroform(pdf_context *ctx, pdf_dict *page_dict)
4772
123k
{
4773
123k
    int code = 0;
4774
123k
    pdf_array *Fields = NULL;
4775
123k
    pdf_dict *field = NULL;
4776
123k
    int i;
4777
4778
123k
    if (!ctx->args.showacroform)
4779
123k
        return 0;
4780
4781
0
    if (!ctx->AcroForm)
4782
0
        return 0;
4783
4784
0
    code = pdfi_dict_knownget_type(ctx, ctx->AcroForm, "Fields", PDF_ARRAY, (pdf_obj **)&Fields);
4785
0
    if (code <= 0)
4786
0
        goto exit;
4787
4788
0
    for (i=0; i<pdfi_array_size(Fields); i++) {
4789
0
        code = pdfi_array_get_type(ctx, Fields, i, PDF_DICT, (pdf_obj **)&field);
4790
0
        if (code < 0)
4791
0
            continue;
4792
0
        code = pdfi_form_draw_field(ctx, page_dict, field);
4793
0
        if (code < 0)
4794
0
            goto exit;
4795
0
        pdfi_countdown(field);
4796
0
        field = NULL;
4797
0
    }
4798
4799
0
 exit:
4800
0
    pdfi_countdown(field);
4801
0
    pdfi_countdown(Fields);
4802
0
    return code;
4803
0
}