1 //========================================================================
2 //
3 // Annot.cc
4 //
5 // Copyright 2000-2003 Glyph & Cog, LLC
6 //
7 //========================================================================
8 
9 //========================================================================
10 //
11 // Modified under the Poppler project - http://poppler.freedesktop.org
12 //
13 // All changes made under the Poppler project to this file are licensed
14 // under GPL version 2 or later
15 //
16 // Copyright (C) 2006 Scott Turner <scotty1024@mac.com>
17 // Copyright (C) 2007, 2008 Julien Rebetez <julienr@svn.gnome.org>
18 // Copyright (C) 2007-2013, 2015-2021 Albert Astals Cid <aacid@kde.org>
19 // Copyright (C) 2007-2013, 2018 Carlos Garcia Campos <carlosgc@gnome.org>
20 // Copyright (C) 2007, 2008 Iñigo Martínez <inigomartinez@gmail.com>
21 // Copyright (C) 2007 Jeff Muizelaar <jeff@infidigm.net>
22 // Copyright (C) 2008, 2011 Pino Toscano <pino@kde.org>
23 // Copyright (C) 2008 Michael Vrable <mvrable@cs.ucsd.edu>
24 // Copyright (C) 2008 Hugo Mercier <hmercier31@gmail.com>
25 // Copyright (C) 2009 Ilya Gorenbein <igorenbein@finjan.com>
26 // Copyright (C) 2011, 2013, 2019 José Aliste <jaliste@src.gnome.org>
27 // Copyright (C) 2012, 2013 Fabio D'Urso <fabiodurso@hotmail.it>
28 // Copyright (C) 2012, 2013 Thomas Freitag <Thomas.Freitag@alfa.de>
29 // Copyright (C) 2012, 2015 Tobias Koenig <tokoe@kdab.com>
30 // Copyright (C) 2013 Peter Breitenlohner <peb@mppmu.mpg.de>
31 // Copyright (C) 2013, 2017 Adrian Johnson <ajohnson@redneon.com>
32 // Copyright (C) 2014, 2015 Marek Kasik <mkasik@redhat.com>
33 // Copyright (C) 2014 Jiri Slaby <jirislaby@gmail.com>
34 // Copyright (C) 2014 Anuj Khare <khareanuj18@gmail.com>
35 // Copyright (C) 2015 Petr Gajdos <pgajdos@suse.cz>
36 // Copyright (C) 2015 Philipp Reinkemeier <philipp.reinkemeier@offis.de>
37 // Copyright (C) 2015 Tamas Szekeres <szekerest@gmail.com>
38 // Copyright (C) 2017 Hans-Ulrich Jüttner <huj@froreich-bioscientia.de>
39 // Copyright (C) 2018 Klarälvdalens Datakonsult AB, a KDAB Group company, <info@kdab.com>. Work sponsored by the LiMux project of the city of Munich
40 // Copyright 2018 Andre Heinecke <aheinecke@intevation.de>
41 // Copyright (C) 2018 Adam Reichold <adam.reichold@t-online.de>
42 // Copyright (C) 2018 Dileep Sankhla <sankhla.dileep96@gmail.com>
43 // Copyright (C) 2018-2020 Tobias Deiminger <haxtibal@posteo.de>
44 // Copyright (C) 2018-2020 Oliver Sander <oliver.sander@tu-dresden.de>
45 // Copyright (C) 2019 Umang Malik <umang99m@gmail.com>
46 // Copyright (C) 2019 João Netto <joaonetto901@gmail.com>
47 // Copyright (C) 2020 Klarälvdalens Datakonsult AB, a KDAB Group company, <info@kdab.com>. Work sponsored by Technische Universität Dresden
48 // Copyright (C) 2020 Katarina Behrens <Katarina.Behrens@cib.de>
49 // Copyright (C) 2020 Thorsten Behrens <Thorsten.Behrens@CIB.de>
50 // Copyright (C) 2020 Nelson Benítez León <nbenitezl@gmail.com>
51 // Copyright (C) 2021 Klarälvdalens Datakonsult AB, a KDAB Group company, <info@kdab.com>.
52 // Copyright (C) 2021 Zachary Travis <ztravis@everlaw.com>
53 // Copyright (C) 2021 Mahmoud Ahmed Khalil <mahmoudkhalil11@gmail.com>
54 // Copyright (C) 2021 Georgiy Sgibnev <georgiy@sgibnev.com>. Work sponsored by lab50.net.
55 //
56 // To see a description of the changes please see the Changelog file that
57 // came with your tarball or type make ChangeLog if you are building from git
58 //
59 //========================================================================
60 
61 #include <config.h>
62 
63 #include <cstdlib>
64 #include <cmath>
65 #include <cassert>
66 #include "goo/gmem.h"
67 #include "goo/gstrtod.h"
68 #include "Error.h"
69 #include "Object.h"
70 #include "Catalog.h"
71 #include "Gfx.h"
72 #include "Lexer.h"
73 #include "PDFDoc.h"
74 #include "Page.h"
75 #include "Annot.h"
76 #include "GfxFont.h"
77 #include "CharCodeToUnicode.h"
78 #include "PDFDocEncoding.h"
79 #include "Form.h"
80 #include "Error.h"
81 #include "XRef.h"
82 #include "Movie.h"
83 #include "OptionalContent.h"
84 #include "Sound.h"
85 #include "FileSpec.h"
86 #include "DateInfo.h"
87 #include "Link.h"
88 #include <cstring>
89 #include <algorithm>
90 
91 #include "annot_stamp_approved.h"
92 #include "annot_stamp_as_is.h"
93 #include "annot_stamp_confidential.h"
94 #include "annot_stamp_departmental.h"
95 #include "annot_stamp_final.h"
96 #include "annot_stamp_for_comment.h"
97 #include "annot_stamp_experimental.h"
98 #include "annot_stamp_expired.h"
99 #include "annot_stamp_not_approved.h"
100 #include "annot_stamp_not_for_public_release.h"
101 #include "annot_stamp_sold.h"
102 #include "annot_stamp_top_secret.h"
103 #include "annot_stamp_for_public_release.h"
104 #include "annot_stamp_draft.h"
105 
106 #ifndef M_PI
107 #    define M_PI 3.14159265358979323846
108 #endif
109 
110 #define fieldFlagReadOnly 0x00000001
111 #define fieldFlagRequired 0x00000002
112 #define fieldFlagNoExport 0x00000004
113 #define fieldFlagMultiline 0x00001000
114 #define fieldFlagPassword 0x00002000
115 #define fieldFlagNoToggleToOff 0x00004000
116 #define fieldFlagRadio 0x00008000
117 #define fieldFlagPushbutton 0x00010000
118 #define fieldFlagCombo 0x00020000
119 #define fieldFlagEdit 0x00040000
120 #define fieldFlagSort 0x00080000
121 #define fieldFlagFileSelect 0x00100000
122 #define fieldFlagMultiSelect 0x00200000
123 #define fieldFlagDoNotSpellCheck 0x00400000
124 #define fieldFlagDoNotScroll 0x00800000
125 #define fieldFlagComb 0x01000000
126 #define fieldFlagRichText 0x02000000
127 #define fieldFlagRadiosInUnison 0x02000000
128 #define fieldFlagCommitOnSelChange 0x04000000
129 
130 #define fieldQuadLeft 0
131 #define fieldQuadCenter 1
132 #define fieldQuadRight 2
133 
134 // distance of Bezier control point from center for circle approximation
135 // = (4 * (sqrt(2) - 1) / 3) * r
136 #define bezierCircle 0.55228475
137 
parseAnnotLineEndingStyle(const GooString * string)138 static AnnotLineEndingStyle parseAnnotLineEndingStyle(const GooString *string)
139 {
140     if (string != nullptr) {
141         if (!string->cmp("Square")) {
142             return annotLineEndingSquare;
143         } else if (!string->cmp("Circle")) {
144             return annotLineEndingCircle;
145         } else if (!string->cmp("Diamond")) {
146             return annotLineEndingDiamond;
147         } else if (!string->cmp("OpenArrow")) {
148             return annotLineEndingOpenArrow;
149         } else if (!string->cmp("ClosedArrow")) {
150             return annotLineEndingClosedArrow;
151         } else if (!string->cmp("Butt")) {
152             return annotLineEndingButt;
153         } else if (!string->cmp("ROpenArrow")) {
154             return annotLineEndingROpenArrow;
155         } else if (!string->cmp("RClosedArrow")) {
156             return annotLineEndingRClosedArrow;
157         } else if (!string->cmp("Slash")) {
158             return annotLineEndingSlash;
159         } else {
160             return annotLineEndingNone;
161         }
162     } else {
163         return annotLineEndingNone;
164     }
165 }
166 
convertAnnotLineEndingStyle(AnnotLineEndingStyle style)167 static const char *convertAnnotLineEndingStyle(AnnotLineEndingStyle style)
168 {
169     switch (style) {
170     case annotLineEndingSquare:
171         return "Square";
172     case annotLineEndingCircle:
173         return "Circle";
174     case annotLineEndingDiamond:
175         return "Diamond";
176     case annotLineEndingOpenArrow:
177         return "OpenArrow";
178     case annotLineEndingClosedArrow:
179         return "ClosedArrow";
180     case annotLineEndingButt:
181         return "Butt";
182     case annotLineEndingROpenArrow:
183         return "ROpenArrow";
184     case annotLineEndingRClosedArrow:
185         return "RClosedArrow";
186     case annotLineEndingSlash:
187         return "Slash";
188     default:
189         return "None";
190     }
191 }
192 
parseAnnotExternalData(Dict * dict)193 static AnnotExternalDataType parseAnnotExternalData(Dict *dict)
194 {
195     AnnotExternalDataType type;
196 
197     Object obj1 = dict->lookup("Subtype");
198     if (obj1.isName()) {
199         const char *typeName = obj1.getName();
200 
201         if (!strcmp(typeName, "Markup3D")) {
202             type = annotExternalDataMarkup3D;
203         } else {
204             type = annotExternalDataMarkupUnknown;
205         }
206     } else {
207         type = annotExternalDataMarkupUnknown;
208     }
209 
210     return type;
211 }
212 
parseDiffRectangle(Array * array,PDFRectangle * rect)213 static std::unique_ptr<PDFRectangle> parseDiffRectangle(Array *array, PDFRectangle *rect)
214 {
215     if (array->getLength() == 4) {
216         // deltas
217         const double dx1 = array->get(0).getNumWithDefaultValue(0);
218         const double dy1 = array->get(1).getNumWithDefaultValue(0);
219         const double dx2 = array->get(2).getNumWithDefaultValue(0);
220         const double dy2 = array->get(3).getNumWithDefaultValue(0);
221 
222         // checking that the numbers are valid (i.e. >= 0),
223         // and that applying the differences still give us a valid rect
224         if (dx1 >= 0 && dy1 >= 0 && dx2 >= 0 && dy2 && (rect->x2 - rect->x1 - dx1 - dx2) >= 0 && (rect->y2 - rect->y1 - dy1 - dy2) >= 0) {
225             auto newRect = std::make_unique<PDFRectangle>();
226             newRect->x1 = rect->x1 + dx1;
227             newRect->y1 = rect->y1 + dy1;
228             newRect->x2 = rect->x2 - dx2;
229             newRect->y2 = rect->y2 - dy2;
230             return newRect;
231         }
232     }
233     return nullptr;
234 }
235 
getAdditionalAction(Annot::AdditionalActionsType type,Object * additionalActions,PDFDoc * doc)236 static std::unique_ptr<LinkAction> getAdditionalAction(Annot::AdditionalActionsType type, Object *additionalActions, PDFDoc *doc)
237 {
238     Object additionalActionsObject = additionalActions->fetch(doc->getXRef());
239 
240     if (additionalActionsObject.isDict()) {
241         const char *key = (type == Annot::actionCursorEntering          ? "E"
242                                    : type == Annot::actionCursorLeaving ? "X"
243                                    : type == Annot::actionMousePressed  ? "D"
244                                    : type == Annot::actionMouseReleased ? "U"
245                                    : type == Annot::actionFocusIn       ? "Fo"
246                                    : type == Annot::actionFocusOut      ? "Bl"
247                                    : type == Annot::actionPageOpening   ? "PO"
248                                    : type == Annot::actionPageClosing   ? "PC"
249                                    : type == Annot::actionPageVisible   ? "PV"
250                                    : type == Annot::actionPageInvisible ? "PI"
251                                                                         : nullptr);
252 
253         Object actionObject = additionalActionsObject.dictLookup(key);
254         if (actionObject.isDict())
255             return LinkAction::parseAction(&actionObject, doc->getCatalog()->getBaseURI());
256     }
257 
258     return nullptr;
259 }
260 
getFormAdditionalActionKey(Annot::FormAdditionalActionsType type)261 static const char *getFormAdditionalActionKey(Annot::FormAdditionalActionsType type)
262 {
263     return (type == Annot::actionFieldModified ? "K" : type == Annot::actionFormatField ? "F" : type == Annot::actionValidateField ? "V" : type == Annot::actionCalculateField ? "C" : nullptr);
264 }
265 
determineFallbackFont(const std::string & tok,const char * defaultFallback)266 static const char *determineFallbackFont(const std::string &tok, const char *defaultFallback)
267 {
268     // TODO: adjust these based on other example PDFs.
269     if (tok == "/ZaDb") {
270         return "ZapfDingbats";
271     } else if (tok == "/Cour") {
272         return "Courier";
273     } else if (tok == "/TiRo") {
274         return "TimesNewRoman";
275     } else if (tok == "/Helvetica-Bold") {
276         return "Helvetica-Bold";
277     }
278     return defaultFallback;
279 }
280 
281 //------------------------------------------------------------------------
282 // AnnotBorderEffect
283 //------------------------------------------------------------------------
284 
AnnotBorderEffect(Dict * dict)285 AnnotBorderEffect::AnnotBorderEffect(Dict *dict)
286 {
287     Object obj1;
288 
289     obj1 = dict->lookup("S");
290     if (obj1.isName()) {
291         const char *effectName = obj1.getName();
292 
293         if (!strcmp(effectName, "C"))
294             effectType = borderEffectCloudy;
295         else
296             effectType = borderEffectNoEffect;
297     } else {
298         effectType = borderEffectNoEffect;
299     }
300 
301     if (effectType == borderEffectCloudy) {
302         intensity = dict->lookup("I").getNumWithDefaultValue(0);
303     } else {
304         intensity = 0;
305     }
306 }
307 
308 //------------------------------------------------------------------------
309 // AnnotPath
310 //------------------------------------------------------------------------
311 
312 AnnotPath::AnnotPath() = default;
313 
AnnotPath(Array * array)314 AnnotPath::AnnotPath(Array *array)
315 {
316     parsePathArray(array);
317 }
318 
AnnotPath(std::vector<AnnotCoord> && coordsA)319 AnnotPath::AnnotPath(std::vector<AnnotCoord> &&coordsA)
320 {
321     coords = std::move(coordsA);
322 }
323 
324 AnnotPath::~AnnotPath() = default;
325 
getX(int coord) const326 double AnnotPath::getX(int coord) const
327 {
328     if (coord >= 0 && coord < getCoordsLength())
329         return coords[coord].getX();
330     return 0;
331 }
332 
getY(int coord) const333 double AnnotPath::getY(int coord) const
334 {
335     if (coord >= 0 && coord < getCoordsLength())
336         return coords[coord].getY();
337     return 0;
338 }
339 
getCoord(int coord)340 AnnotCoord *AnnotPath::getCoord(int coord)
341 {
342     if (coord >= 0 && coord < getCoordsLength())
343         return &coords[coord];
344     return nullptr;
345 }
346 
parsePathArray(Array * array)347 void AnnotPath::parsePathArray(Array *array)
348 {
349     if (array->getLength() % 2) {
350         error(errSyntaxError, -1, "Bad Annot Path");
351         return;
352     }
353 
354     const auto tempLength = array->getLength() / 2;
355     std::vector<AnnotCoord> tempCoords;
356     tempCoords.reserve(tempLength);
357     for (int i = 0; i < tempLength; i++) {
358         double x = 0, y = 0;
359 
360         Object obj1 = array->get(i * 2);
361         if (obj1.isNum()) {
362             x = obj1.getNum();
363         } else {
364             return;
365         }
366 
367         obj1 = array->get((i * 2) + 1);
368         if (obj1.isNum()) {
369             y = obj1.getNum();
370         } else {
371             return;
372         }
373 
374         tempCoords.emplace_back(x, y);
375     }
376 
377     coords = std::move(tempCoords);
378 }
379 
380 //------------------------------------------------------------------------
381 // AnnotCalloutLine
382 //------------------------------------------------------------------------
383 
AnnotCalloutLine(double x1,double y1,double x2,double y2)384 AnnotCalloutLine::AnnotCalloutLine(double x1, double y1, double x2, double y2) : coord1(x1, y1), coord2(x2, y2) { }
385 
386 AnnotCalloutLine::~AnnotCalloutLine() = default;
387 
388 //------------------------------------------------------------------------
389 // AnnotCalloutMultiLine
390 //------------------------------------------------------------------------
391 
AnnotCalloutMultiLine(double x1,double y1,double x2,double y2,double x3,double y3)392 AnnotCalloutMultiLine::AnnotCalloutMultiLine(double x1, double y1, double x2, double y2, double x3, double y3) : AnnotCalloutLine(x1, y1, x2, y2), coord3(x3, y3) { }
393 
394 AnnotCalloutMultiLine::~AnnotCalloutMultiLine() = default;
395 
396 //------------------------------------------------------------------------
397 // AnnotQuadrilateral
398 //------------------------------------------------------------------------
399 
AnnotQuadrilaterals(Array * array,PDFRectangle * rect)400 AnnotQuadrilaterals::AnnotQuadrilaterals(Array *array, PDFRectangle *rect)
401 {
402     int arrayLength = array->getLength();
403     int quadsLength = 0;
404     double quadArray[8];
405 
406     // default values
407     quadrilateralsLength = 0;
408 
409     if ((arrayLength % 8) == 0) {
410         int i;
411 
412         quadsLength = arrayLength / 8;
413         auto quads = std::make_unique<AnnotQuadrilateral[]>(quadsLength);
414         for (i = 0; i < quadsLength; i++) {
415             for (int j = 0; j < 8; j++) {
416                 Object obj = array->get(i * 8 + j);
417                 if (obj.isNum()) {
418                     quadArray[j] = obj.getNum();
419                 } else {
420                     error(errSyntaxError, -1, "Invalid QuadPoint in annot");
421                     return;
422                 }
423             }
424 
425             quads[i] = AnnotQuadrilateral(quadArray[0], quadArray[1], quadArray[2], quadArray[3], quadArray[4], quadArray[5], quadArray[6], quadArray[7]);
426         }
427 
428         quadrilateralsLength = quadsLength;
429         quadrilaterals = std::move(quads);
430     }
431 }
432 
AnnotQuadrilaterals(std::unique_ptr<AnnotQuadrilateral[]> && quads,int quadsLength)433 AnnotQuadrilaterals::AnnotQuadrilaterals(std::unique_ptr<AnnotQuadrilateral[]> &&quads, int quadsLength)
434 {
435     quadrilaterals = std::move(quads);
436     quadrilateralsLength = quadsLength;
437 }
438 
439 AnnotQuadrilaterals::~AnnotQuadrilaterals() = default;
440 
getX1(int quadrilateral)441 double AnnotQuadrilaterals::getX1(int quadrilateral)
442 {
443     if (quadrilateral >= 0 && quadrilateral < quadrilateralsLength)
444         return quadrilaterals[quadrilateral].coord1.getX();
445     return 0;
446 }
447 
getY1(int quadrilateral)448 double AnnotQuadrilaterals::getY1(int quadrilateral)
449 {
450     if (quadrilateral >= 0 && quadrilateral < quadrilateralsLength)
451         return quadrilaterals[quadrilateral].coord1.getY();
452     return 0;
453 }
454 
getX2(int quadrilateral)455 double AnnotQuadrilaterals::getX2(int quadrilateral)
456 {
457     if (quadrilateral >= 0 && quadrilateral < quadrilateralsLength)
458         return quadrilaterals[quadrilateral].coord2.getX();
459     return 0;
460 }
461 
getY2(int quadrilateral)462 double AnnotQuadrilaterals::getY2(int quadrilateral)
463 {
464     if (quadrilateral >= 0 && quadrilateral < quadrilateralsLength)
465         return quadrilaterals[quadrilateral].coord2.getY();
466     return 0;
467 }
468 
getX3(int quadrilateral)469 double AnnotQuadrilaterals::getX3(int quadrilateral)
470 {
471     if (quadrilateral >= 0 && quadrilateral < quadrilateralsLength)
472         return quadrilaterals[quadrilateral].coord3.getX();
473     return 0;
474 }
475 
getY3(int quadrilateral)476 double AnnotQuadrilaterals::getY3(int quadrilateral)
477 {
478     if (quadrilateral >= 0 && quadrilateral < quadrilateralsLength)
479         return quadrilaterals[quadrilateral].coord3.getY();
480     return 0;
481 }
482 
getX4(int quadrilateral)483 double AnnotQuadrilaterals::getX4(int quadrilateral)
484 {
485     if (quadrilateral >= 0 && quadrilateral < quadrilateralsLength)
486         return quadrilaterals[quadrilateral].coord4.getX();
487     return 0;
488 }
489 
getY4(int quadrilateral)490 double AnnotQuadrilaterals::getY4(int quadrilateral)
491 {
492     if (quadrilateral >= 0 && quadrilateral < quadrilateralsLength)
493         return quadrilaterals[quadrilateral].coord4.getY();
494     return 0;
495 }
496 
497 AnnotQuadrilaterals::AnnotQuadrilateral::AnnotQuadrilateral() = default;
498 
AnnotQuadrilateral(double x1,double y1,double x2,double y2,double x3,double y3,double x4,double y4)499 AnnotQuadrilaterals::AnnotQuadrilateral::AnnotQuadrilateral(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4) : coord1(x1, y1), coord2(x2, y2), coord3(x3, y3), coord4(x4, y4) { }
500 
501 //------------------------------------------------------------------------
502 // AnnotBorder
503 //------------------------------------------------------------------------
AnnotBorder()504 AnnotBorder::AnnotBorder()
505 {
506     width = 1;
507     dashLength = 0;
508     dash = nullptr;
509     style = borderSolid;
510 }
511 
parseDashArray(Object * dashObj)512 bool AnnotBorder::parseDashArray(Object *dashObj)
513 {
514     bool correct = true;
515     const int tempLength = dashObj->arrayGetLength();
516     double *tempDash = (double *)gmallocn(tempLength, sizeof(double));
517 
518     // TODO: check not all zero (Line Dash Pattern Page 217 PDF 8.1)
519     for (int i = 0; i < tempLength && i < DASH_LIMIT && correct; i++) {
520         const Object obj1 = dashObj->arrayGet(i);
521         if (obj1.isNum()) {
522             tempDash[i] = obj1.getNum();
523 
524             correct = tempDash[i] >= 0;
525         } else {
526             correct = false;
527         }
528     }
529 
530     if (correct) {
531         dashLength = tempLength;
532         dash = tempDash;
533         style = borderDashed;
534     } else {
535         gfree(tempDash);
536     }
537 
538     return correct;
539 }
540 
~AnnotBorder()541 AnnotBorder::~AnnotBorder()
542 {
543     if (dash)
544         gfree(dash);
545 }
546 
547 //------------------------------------------------------------------------
548 // AnnotBorderArray
549 //------------------------------------------------------------------------
550 
AnnotBorderArray()551 AnnotBorderArray::AnnotBorderArray()
552 {
553     horizontalCorner = 0;
554     verticalCorner = 0;
555 }
556 
AnnotBorderArray(Array * array)557 AnnotBorderArray::AnnotBorderArray(Array *array)
558 {
559     Object obj1;
560     int arrayLength = array->getLength();
561 
562     bool correct = true;
563     if (arrayLength == 3 || arrayLength == 4) {
564         // implementation note 81 in Appendix H.
565 
566         obj1 = array->get(0);
567         if (obj1.isNum())
568             horizontalCorner = obj1.getNum();
569         else
570             correct = false;
571 
572         obj1 = array->get(1);
573         if (obj1.isNum())
574             verticalCorner = obj1.getNum();
575         else
576             correct = false;
577 
578         obj1 = array->get(2);
579         if (obj1.isNum())
580             width = obj1.getNum();
581         else
582             correct = false;
583 
584         if (arrayLength == 4) {
585             obj1 = array->get(3);
586             if (obj1.isArray())
587                 correct = parseDashArray(&obj1);
588             else
589                 correct = false;
590         }
591     } else {
592         correct = false;
593     }
594 
595     if (!correct) {
596         width = 0;
597     }
598 }
599 
writeToObject(XRef * xref) const600 Object AnnotBorderArray::writeToObject(XRef *xref) const
601 {
602     Array *borderArray = new Array(xref);
603     borderArray->add(Object(horizontalCorner));
604     borderArray->add(Object(verticalCorner));
605     borderArray->add(Object(width));
606 
607     if (dashLength > 0) {
608         Array *a = new Array(xref);
609 
610         for (int i = 0; i < dashLength; i++)
611             a->add(Object(dash[i]));
612 
613         borderArray->add(Object(a));
614     }
615 
616     return Object(borderArray);
617 }
618 
619 //------------------------------------------------------------------------
620 // AnnotBorderBS
621 //------------------------------------------------------------------------
622 
AnnotBorderBS()623 AnnotBorderBS::AnnotBorderBS() { }
624 
AnnotBorderBS(Dict * dict)625 AnnotBorderBS::AnnotBorderBS(Dict *dict)
626 {
627     // Border width (in points)
628     Object obj1 = dict->lookup("W");
629     width = obj1.getNumWithDefaultValue(1.0);
630 
631     // Border style
632     obj1 = dict->lookup("S");
633     if (obj1.isName()) {
634         const char *styleName = obj1.getName();
635 
636         if (!strcmp(styleName, "S")) {
637             style = borderSolid;
638         } else if (!strcmp(styleName, "D")) {
639             style = borderDashed;
640         } else if (!strcmp(styleName, "B")) {
641             style = borderBeveled;
642         } else if (!strcmp(styleName, "I")) {
643             style = borderInset;
644         } else if (!strcmp(styleName, "U")) {
645             style = borderUnderlined;
646         } else {
647             style = borderSolid;
648         }
649     } else {
650         style = borderSolid;
651     }
652 
653     // Border dash style
654     if (style == borderDashed) {
655         obj1 = dict->lookup("D");
656         if (obj1.isArray())
657             parseDashArray(&obj1);
658 
659         if (!dash) {
660             dashLength = 1;
661             dash = (double *)gmallocn(dashLength, sizeof(double));
662             dash[0] = 3;
663         }
664     }
665 }
666 
getStyleName() const667 const char *AnnotBorderBS::getStyleName() const
668 {
669     switch (style) {
670     case borderSolid:
671         return "S";
672     case borderDashed:
673         return "D";
674     case borderBeveled:
675         return "B";
676     case borderInset:
677         return "I";
678     case borderUnderlined:
679         return "U";
680     }
681 
682     return "S";
683 }
684 
writeToObject(XRef * xref) const685 Object AnnotBorderBS::writeToObject(XRef *xref) const
686 {
687     Dict *dict = new Dict(xref);
688     dict->set("W", Object(width));
689     dict->set("S", Object(objName, getStyleName()));
690     if (style == borderDashed && dashLength > 0) {
691         Array *a = new Array(xref);
692 
693         for (int i = 0; i < dashLength; i++)
694             a->add(Object(dash[i]));
695         dict->set("D", Object(a));
696     }
697     return Object(dict);
698 }
699 
700 //------------------------------------------------------------------------
701 // AnnotColor
702 //------------------------------------------------------------------------
703 
AnnotColor()704 AnnotColor::AnnotColor()
705 {
706     length = 0;
707 }
708 
AnnotColor(double gray)709 AnnotColor::AnnotColor(double gray)
710 {
711     length = 1;
712 
713     values[0] = gray;
714 }
715 
AnnotColor(double r,double g,double b)716 AnnotColor::AnnotColor(double r, double g, double b)
717 {
718     length = 3;
719 
720     values[0] = r;
721     values[1] = g;
722     values[2] = b;
723 }
724 
AnnotColor(double c,double m,double y,double k)725 AnnotColor::AnnotColor(double c, double m, double y, double k)
726 {
727     length = 4;
728 
729     values[0] = c;
730     values[1] = m;
731     values[2] = y;
732     values[3] = k;
733 }
734 
735 // If <adjust> is +1, color is brightened;
736 // if <adjust> is -1, color is darkened;
737 // otherwise color is not modified.
AnnotColor(Array * array,int adjust)738 AnnotColor::AnnotColor(Array *array, int adjust)
739 {
740     int i;
741 
742     length = array->getLength();
743     if (length > 4)
744         length = 4;
745 
746     for (i = 0; i < length; i++) {
747         Object obj1 = array->get(i);
748         if (obj1.isNum()) {
749             values[i] = obj1.getNum();
750 
751             if (values[i] < 0 || values[i] > 1)
752                 values[i] = 0;
753         } else {
754             values[i] = 0;
755         }
756     }
757 
758     if (adjust != 0)
759         adjustColor(adjust);
760 }
761 
adjustColor(int adjust)762 void AnnotColor::adjustColor(int adjust)
763 {
764     int i;
765 
766     if (length == 4) {
767         adjust = -adjust;
768     }
769     if (adjust > 0) {
770         for (i = 0; i < length; ++i) {
771             values[i] = 0.5 * values[i] + 0.5;
772         }
773     } else if (adjust < 0) {
774         for (i = 0; i < length; ++i) {
775             values[i] = 0.5 * values[i];
776         }
777     }
778 }
779 
writeToObject(XRef * xref) const780 Object AnnotColor::writeToObject(XRef *xref) const
781 {
782     if (length == 0) {
783         return Object(objNull); // Transparent (no color)
784     } else {
785         Array *a = new Array(xref);
786         for (int i = 0; i < length; ++i)
787             a->add(Object(values[i]));
788         return Object(a);
789     }
790 }
791 
792 //------------------------------------------------------------------------
793 // DefaultAppearance
794 //------------------------------------------------------------------------
795 
DefaultAppearance(Object && fontNameA,double fontPtSizeA,std::unique_ptr<AnnotColor> && fontColorA)796 DefaultAppearance::DefaultAppearance(Object &&fontNameA, double fontPtSizeA, std::unique_ptr<AnnotColor> &&fontColorA) : fontName(std::move(fontNameA)), fontPtSize(fontPtSizeA), fontColor(std::move(fontColorA)) { }
797 
DefaultAppearance(const GooString * da)798 DefaultAppearance::DefaultAppearance(const GooString *da)
799 {
800     fontPtSize = -1;
801 
802     if (da) {
803         std::vector<std::string> daToks;
804         int i = FormFieldText::tokenizeDA(da->toStr(), &daToks, "Tf");
805 
806         if (i >= 1) {
807             fontPtSize = gatof(daToks[i - 1].c_str());
808         }
809         if (i >= 2) {
810             // We are expecting a name, therefore the first letter should be '/'.
811             const std::string &fontToken = daToks[i - 2];
812             if (fontToken.size() > 1 && fontToken[0] == '/') {
813                 // The +1 is here to skip the leading '/'.
814                 fontName = Object(objName, fontToken.c_str() + 1);
815             }
816         }
817         // Scan backwards: we are looking for the last set value
818         for (i = daToks.size() - 1; i >= 0; --i) {
819             if (!fontColor) {
820                 if (daToks[i] == "g" && i >= 1) {
821                     fontColor = std::make_unique<AnnotColor>(gatof(daToks[i - 1].c_str()));
822                 } else if (daToks[i] == "rg" && i >= 3) {
823                     fontColor = std::make_unique<AnnotColor>(gatof(daToks[i - 3].c_str()), gatof(daToks[i - 2].c_str()), gatof(daToks[i - 1].c_str()));
824                 } else if (daToks[i] == "k" && i >= 4) {
825                     fontColor = std::make_unique<AnnotColor>(gatof(daToks[i - 4].c_str()), gatof(daToks[i - 3].c_str()), gatof(daToks[i - 2].c_str()), gatof(daToks[i - 1].c_str()));
826                 }
827             }
828         }
829     }
830 }
831 
setFontName(Object && fontNameA)832 void DefaultAppearance::setFontName(Object &&fontNameA)
833 {
834     fontName = std::move(fontNameA);
835 }
836 
setFontPtSize(double fontPtSizeA)837 void DefaultAppearance::setFontPtSize(double fontPtSizeA)
838 {
839     fontPtSize = fontPtSizeA;
840 }
841 
setFontColor(std::unique_ptr<AnnotColor> fontColorA)842 void DefaultAppearance::setFontColor(std::unique_ptr<AnnotColor> fontColorA)
843 {
844     fontColor = std::move(fontColorA);
845 }
846 
toAppearanceString() const847 GooString *DefaultAppearance::toAppearanceString() const
848 {
849     AnnotAppearanceBuilder appearBuilder;
850     if (fontColor) {
851         appearBuilder.setDrawColor(fontColor.get(), true);
852     }
853     appearBuilder.setTextFont(fontName, fontPtSize);
854     return appearBuilder.buffer()->copy();
855 }
856 
857 //------------------------------------------------------------------------
858 // AnnotIconFit
859 //------------------------------------------------------------------------
860 
AnnotIconFit(Dict * dict)861 AnnotIconFit::AnnotIconFit(Dict *dict)
862 {
863     Object obj1;
864 
865     obj1 = dict->lookup("SW");
866     if (obj1.isName()) {
867         const char *scaleName = obj1.getName();
868 
869         if (!strcmp(scaleName, "B")) {
870             scaleWhen = scaleBigger;
871         } else if (!strcmp(scaleName, "S")) {
872             scaleWhen = scaleSmaller;
873         } else if (!strcmp(scaleName, "N")) {
874             scaleWhen = scaleNever;
875         } else {
876             scaleWhen = scaleAlways;
877         }
878     } else {
879         scaleWhen = scaleAlways;
880     }
881 
882     obj1 = dict->lookup("S");
883     if (obj1.isName()) {
884         const char *scaleName = obj1.getName();
885 
886         if (!strcmp(scaleName, "A")) {
887             scale = scaleAnamorphic;
888         } else {
889             scale = scaleProportional;
890         }
891     } else {
892         scale = scaleProportional;
893     }
894 
895     obj1 = dict->lookup("A");
896     if (obj1.isArray() && obj1.arrayGetLength() == 2) {
897         left = obj1.arrayGet(0).getNumWithDefaultValue(0);
898         bottom = obj1.arrayGet(1).getNumWithDefaultValue(0);
899 
900         if (left < 0 || left > 1)
901             left = 0.5;
902 
903         if (bottom < 0 || bottom > 1)
904             bottom = 0.5;
905 
906     } else {
907         left = bottom = 0.5;
908     }
909 
910     fullyBounds = dict->lookup("FB").getBoolWithDefaultValue(false);
911 }
912 
913 //------------------------------------------------------------------------
914 // AnnotAppearance
915 //------------------------------------------------------------------------
916 
AnnotAppearance(PDFDoc * docA,Object * dict)917 AnnotAppearance::AnnotAppearance(PDFDoc *docA, Object *dict)
918 {
919     assert(dict->isDict());
920     doc = docA;
921     appearDict = dict->copy();
922 }
923 
~AnnotAppearance()924 AnnotAppearance::~AnnotAppearance() { }
925 
getAppearanceStream(AnnotAppearanceType type,const char * state)926 Object AnnotAppearance::getAppearanceStream(AnnotAppearanceType type, const char *state)
927 {
928     Object apData;
929 
930     // Obtain dictionary or stream associated to appearance type
931     switch (type) {
932     case appearRollover:
933         apData = appearDict.dictLookupNF("R").copy();
934         if (apData.isNull())
935             apData = appearDict.dictLookupNF("N").copy();
936         break;
937     case appearDown:
938         apData = appearDict.dictLookupNF("D").copy();
939         if (apData.isNull())
940             apData = appearDict.dictLookupNF("N").copy();
941         break;
942     case appearNormal:
943         apData = appearDict.dictLookupNF("N").copy();
944         break;
945     }
946 
947     if (apData.isDict() && state)
948         return apData.dictLookupNF(state).copy();
949     else if (apData.isRef())
950         return apData;
951 
952     return Object();
953 }
954 
getStateKey(int i)955 std::unique_ptr<GooString> AnnotAppearance::getStateKey(int i)
956 {
957     const Object &obj1 = appearDict.dictLookupNF("N");
958     if (obj1.isDict())
959         return std::make_unique<GooString>(obj1.dictGetKey(i));
960     return nullptr;
961 }
962 
getNumStates()963 int AnnotAppearance::getNumStates()
964 {
965     int res = 0;
966     const Object &obj1 = appearDict.dictLookupNF("N");
967     if (obj1.isDict())
968         res = obj1.dictGetLength();
969     return res;
970 }
971 
972 // Test if stateObj (a Ref or a Dict) points to the specified stream
referencesStream(const Object * stateObj,Ref refToStream)973 bool AnnotAppearance::referencesStream(const Object *stateObj, Ref refToStream)
974 {
975     if (stateObj->isRef()) {
976         const Ref r = stateObj->getRef();
977         if (r == refToStream) {
978             return true;
979         }
980     } else if (stateObj->isDict()) { // Test each value
981         const int size = stateObj->dictGetLength();
982         for (int i = 0; i < size; ++i) {
983             const Object &obj1 = stateObj->dictGetValNF(i);
984             if (obj1.isRef()) {
985                 const Ref r = obj1.getRef();
986                 if (r == refToStream) {
987                     return true;
988                 }
989             }
990         }
991     }
992     return false; // Not found
993 }
994 
995 // Test if this AnnotAppearance references the specified stream
referencesStream(Ref refToStream)996 bool AnnotAppearance::referencesStream(Ref refToStream)
997 {
998     bool found;
999 
1000     // Scan each state's ref/subdictionary
1001     const Object &objN = appearDict.dictLookupNF("N");
1002     found = referencesStream(&objN, refToStream);
1003     if (found)
1004         return true;
1005 
1006     const Object &objR = appearDict.dictLookupNF("R");
1007     found = referencesStream(&objR, refToStream);
1008     if (found)
1009         return true;
1010 
1011     const Object &objD = appearDict.dictLookupNF("D");
1012     found = referencesStream(&objD, refToStream);
1013     return found;
1014 }
1015 
1016 // If this is the only annotation in the document that references the
1017 // specified appearance stream, remove the appearance stream
removeStream(Ref refToStream)1018 void AnnotAppearance::removeStream(Ref refToStream)
1019 {
1020     const int lastpage = doc->getNumPages();
1021     for (int pg = 1; pg <= lastpage; ++pg) { // Scan all annotations in the document
1022         Page *page = doc->getPage(pg);
1023         if (!page) {
1024             error(errSyntaxError, -1, "Failed check for shared annotation stream at page {0:d}", pg);
1025             continue;
1026         }
1027         Annots *annots = page->getAnnots();
1028         for (int i = 0; i < annots->getNumAnnots(); ++i) {
1029             AnnotAppearance *annotAp = annots->getAnnot(i)->getAppearStreams();
1030             if (annotAp && annotAp != this && annotAp->referencesStream(refToStream)) {
1031                 return; // Another annotation points to the stream -> Don't delete it
1032             }
1033         }
1034     }
1035 
1036     // TODO: stream resources (e.g. font), AP name tree
1037     doc->getXRef()->removeIndirectObject(refToStream);
1038 }
1039 
1040 // Removes stream if obj is a Ref, or removes pointed streams if obj is a Dict
removeStateStreams(const Object * state)1041 void AnnotAppearance::removeStateStreams(const Object *state)
1042 {
1043     if (state->isRef()) {
1044         removeStream(state->getRef());
1045     } else if (state->isDict()) {
1046         const int size = state->dictGetLength();
1047         for (int i = 0; i < size; ++i) {
1048             const Object &obj2 = state->dictGetValNF(i);
1049             if (obj2.isRef()) {
1050                 removeStream(obj2.getRef());
1051             }
1052         }
1053     }
1054 }
1055 
removeAllStreams()1056 void AnnotAppearance::removeAllStreams()
1057 {
1058     const Object &objN = appearDict.dictLookupNF("N");
1059     removeStateStreams(&objN);
1060     const Object &objR = appearDict.dictLookupNF("R");
1061     removeStateStreams(&objR);
1062     const Object &objD = appearDict.dictLookupNF("D");
1063     removeStateStreams(&objD);
1064 }
1065 
1066 //------------------------------------------------------------------------
1067 // AnnotAppearanceCharacs
1068 //------------------------------------------------------------------------
1069 
AnnotAppearanceCharacs(Dict * dict)1070 AnnotAppearanceCharacs::AnnotAppearanceCharacs(Dict *dict)
1071 {
1072     Object obj1;
1073 
1074     obj1 = dict->lookup("R");
1075     if (obj1.isInt()) {
1076         rotation = obj1.getInt();
1077     } else {
1078         rotation = 0;
1079     }
1080 
1081     obj1 = dict->lookup("BC");
1082     if (obj1.isArray()) {
1083         Array *colorComponents = obj1.getArray();
1084         if (colorComponents->getLength() > 0) {
1085             borderColor = std::make_unique<AnnotColor>(colorComponents);
1086         }
1087     }
1088 
1089     obj1 = dict->lookup("BG");
1090     if (obj1.isArray()) {
1091         Array *colorComponents = obj1.getArray();
1092         if (colorComponents->getLength() > 0) {
1093             backColor = std::make_unique<AnnotColor>(colorComponents);
1094         }
1095     }
1096 
1097     obj1 = dict->lookup("CA");
1098     if (obj1.isString()) {
1099         normalCaption = std::make_unique<GooString>(obj1.getString());
1100     }
1101 
1102     obj1 = dict->lookup("RC");
1103     if (obj1.isString()) {
1104         rolloverCaption = std::make_unique<GooString>(obj1.getString());
1105     }
1106 
1107     obj1 = dict->lookup("AC");
1108     if (obj1.isString()) {
1109         alternateCaption = std::make_unique<GooString>(obj1.getString());
1110     }
1111 
1112     obj1 = dict->lookup("IF");
1113     if (obj1.isDict()) {
1114         iconFit = std::make_unique<AnnotIconFit>(obj1.getDict());
1115     }
1116 
1117     obj1 = dict->lookup("TP");
1118     if (obj1.isInt()) {
1119         position = (AnnotAppearanceCharacsTextPos)obj1.getInt();
1120     } else {
1121         position = captionNoIcon;
1122     }
1123 }
1124 
1125 AnnotAppearanceCharacs::~AnnotAppearanceCharacs() = default;
1126 
1127 //------------------------------------------------------------------------
1128 // AnnotAppearanceBBox
1129 //------------------------------------------------------------------------
1130 
AnnotAppearanceBBox(PDFRectangle * rect)1131 AnnotAppearanceBBox::AnnotAppearanceBBox(PDFRectangle *rect)
1132 {
1133     origX = rect->x1;
1134     origY = rect->y1;
1135     borderWidth = 0;
1136 
1137     // Initially set the same size as rect
1138     minX = 0;
1139     minY = 0;
1140     maxX = rect->x2 - rect->x1;
1141     maxY = rect->y2 - rect->y1;
1142 }
1143 
extendTo(double x,double y)1144 void AnnotAppearanceBBox::extendTo(double x, double y)
1145 {
1146     if (x < minX) {
1147         minX = x;
1148     } else if (x > maxX) {
1149         maxX = x;
1150     }
1151     if (y < minY) {
1152         minY = y;
1153     } else if (y > maxY) {
1154         maxY = y;
1155     }
1156 }
1157 
getBBoxRect(double bbox[4]) const1158 void AnnotAppearanceBBox::getBBoxRect(double bbox[4]) const
1159 {
1160     bbox[0] = minX - borderWidth;
1161     bbox[1] = minY - borderWidth;
1162     bbox[2] = maxX + borderWidth;
1163     bbox[3] = maxY + borderWidth;
1164 }
1165 
getPageXMin() const1166 double AnnotAppearanceBBox::getPageXMin() const
1167 {
1168     return origX + minX - borderWidth;
1169 }
1170 
getPageYMin() const1171 double AnnotAppearanceBBox::getPageYMin() const
1172 {
1173     return origY + minY - borderWidth;
1174 }
1175 
getPageXMax() const1176 double AnnotAppearanceBBox::getPageXMax() const
1177 {
1178     return origX + maxX + borderWidth;
1179 }
1180 
getPageYMax() const1181 double AnnotAppearanceBBox::getPageYMax() const
1182 {
1183     return origY + maxY + borderWidth;
1184 }
1185 
1186 //------------------------------------------------------------------------
1187 // Annot
1188 //------------------------------------------------------------------------
1189 
1190 #define annotLocker() std::unique_lock<std::recursive_mutex> locker(mutex)
1191 
Annot(PDFDoc * docA,PDFRectangle * rectA)1192 Annot::Annot(PDFDoc *docA, PDFRectangle *rectA)
1193 {
1194 
1195     refCnt = 1;
1196     flags = flagUnknown;
1197     type = typeUnknown;
1198 
1199     Array *a = new Array(docA->getXRef());
1200     a->add(Object(rectA->x1));
1201     a->add(Object(rectA->y1));
1202     a->add(Object(rectA->x2));
1203     a->add(Object(rectA->y2));
1204 
1205     annotObj = Object(new Dict(docA->getXRef()));
1206     annotObj.dictSet("Type", Object(objName, "Annot"));
1207     annotObj.dictSet("Rect", Object(a));
1208 
1209     ref = docA->getXRef()->addIndirectObject(annotObj);
1210 
1211     initialize(docA, annotObj.getDict());
1212 }
1213 
Annot(PDFDoc * docA,Object && dictObject)1214 Annot::Annot(PDFDoc *docA, Object &&dictObject)
1215 {
1216     refCnt = 1;
1217     hasRef = false;
1218     flags = flagUnknown;
1219     type = typeUnknown;
1220     annotObj = std::move(dictObject);
1221     initialize(docA, annotObj.getDict());
1222 }
1223 
Annot(PDFDoc * docA,Object && dictObject,const Object * obj)1224 Annot::Annot(PDFDoc *docA, Object &&dictObject, const Object *obj)
1225 {
1226     refCnt = 1;
1227     if (obj->isRef()) {
1228         hasRef = true;
1229         ref = obj->getRef();
1230     } else {
1231         hasRef = false;
1232     }
1233     flags = flagUnknown;
1234     type = typeUnknown;
1235     annotObj = std::move(dictObject);
1236     initialize(docA, annotObj.getDict());
1237 }
1238 
initialize(PDFDoc * docA,Dict * dict)1239 void Annot::initialize(PDFDoc *docA, Dict *dict)
1240 {
1241     Object apObj, asObj, obj1;
1242 
1243     ok = true;
1244     doc = docA;
1245 
1246     appearance.setToNull();
1247 
1248     //----- parse the rectangle
1249     rect = std::make_unique<PDFRectangle>();
1250     obj1 = dict->lookup("Rect");
1251     if (obj1.isArray() && obj1.arrayGetLength() == 4) {
1252         rect->x1 = obj1.arrayGet(0).getNumWithDefaultValue(0);
1253         rect->y1 = obj1.arrayGet(1).getNumWithDefaultValue(0);
1254         rect->x2 = obj1.arrayGet(2).getNumWithDefaultValue(1);
1255         rect->y2 = obj1.arrayGet(3).getNumWithDefaultValue(1);
1256 
1257         if (rect->x1 > rect->x2) {
1258             double t = rect->x1;
1259             rect->x1 = rect->x2;
1260             rect->x2 = t;
1261         }
1262 
1263         if (rect->y1 > rect->y2) {
1264             double t = rect->y1;
1265             rect->y1 = rect->y2;
1266             rect->y2 = t;
1267         }
1268     } else {
1269         rect->x1 = rect->y1 = 0;
1270         rect->x2 = rect->y2 = 1;
1271         error(errSyntaxError, -1, "Bad bounding box for annotation");
1272         ok = false;
1273     }
1274 
1275     obj1 = dict->lookup("Contents");
1276     if (obj1.isString()) {
1277         contents.reset(obj1.getString()->copy());
1278     } else {
1279         contents = std::make_unique<GooString>();
1280     }
1281 
1282     // Note: This value is overwritten by Annots ctor
1283     const Object &pObj = dict->lookupNF("P");
1284     if (pObj.isRef()) {
1285         const Ref pRef = pObj.getRef();
1286 
1287         page = doc->getCatalog()->findPage(pRef);
1288     } else {
1289         page = 0;
1290     }
1291 
1292     obj1 = dict->lookup("NM");
1293     if (obj1.isString()) {
1294         name.reset(obj1.getString()->copy());
1295     }
1296 
1297     obj1 = dict->lookup("M");
1298     if (obj1.isString()) {
1299         modified.reset(obj1.getString()->copy());
1300     }
1301 
1302     //----- get the flags
1303     obj1 = dict->lookup("F");
1304     if (obj1.isInt()) {
1305         flags |= obj1.getInt();
1306     } else {
1307         flags = flagUnknown;
1308     }
1309 
1310     //----- get the annotation appearance dictionary
1311     apObj = dict->lookup("AP");
1312     if (apObj.isDict()) {
1313         appearStreams = std::make_unique<AnnotAppearance>(doc, &apObj);
1314     }
1315 
1316     //----- get the appearance state
1317     asObj = dict->lookup("AS");
1318     if (asObj.isName()) {
1319         appearState = std::make_unique<GooString>(asObj.getName());
1320     } else if (appearStreams && appearStreams->getNumStates() != 0) {
1321         error(errSyntaxError, -1, "Invalid or missing AS value in annotation containing one or more appearance subdictionaries");
1322         // AS value is required in this case, but if the
1323         // N dictionary contains only one entry
1324         // take it as default appearance.
1325         if (appearStreams->getNumStates() == 1) {
1326             appearState = appearStreams->getStateKey(0);
1327         }
1328     }
1329     if (!appearState) {
1330         appearState = std::make_unique<GooString>("Off");
1331     }
1332 
1333     //----- get the annotation appearance
1334     if (appearStreams) {
1335         appearance = appearStreams->getAppearanceStream(AnnotAppearance::appearNormal, appearState->c_str());
1336     }
1337 
1338     //----- parse the border style
1339     // According to the spec if neither the Border nor the BS entry is present,
1340     // the border shall be drawn as a solid line with a width of 1 point. But acroread
1341     // seems to ignore the Border entry for annots that can't have a BS entry. So, we only
1342     // follow this rule for annots tha can have a BS entry.
1343     obj1 = dict->lookup("Border");
1344     if (obj1.isArray()) {
1345         border = std::make_unique<AnnotBorderArray>(obj1.getArray());
1346     }
1347 
1348     obj1 = dict->lookup("C");
1349     if (obj1.isArray()) {
1350         color = std::make_unique<AnnotColor>(obj1.getArray());
1351     }
1352 
1353     obj1 = dict->lookup("StructParent");
1354     if (obj1.isInt()) {
1355         treeKey = obj1.getInt();
1356     } else {
1357         treeKey = 0;
1358     }
1359 
1360     oc = dict->lookupNF("OC").copy();
1361 }
1362 
getRect(double * x1,double * y1,double * x2,double * y2) const1363 void Annot::getRect(double *x1, double *y1, double *x2, double *y2) const
1364 {
1365     *x1 = rect->x1;
1366     *y1 = rect->y1;
1367     *x2 = rect->x2;
1368     *y2 = rect->y2;
1369 }
1370 
setRect(const PDFRectangle * rectA)1371 void Annot::setRect(const PDFRectangle *rectA)
1372 {
1373     setRect(rectA->x1, rectA->y1, rectA->x2, rectA->y2);
1374 }
1375 
setRect(double x1,double y1,double x2,double y2)1376 void Annot::setRect(double x1, double y1, double x2, double y2)
1377 {
1378     if (x1 < x2) {
1379         rect->x1 = x1;
1380         rect->x2 = x2;
1381     } else {
1382         rect->x1 = x2;
1383         rect->x2 = x1;
1384     }
1385 
1386     if (y1 < y2) {
1387         rect->y1 = y1;
1388         rect->y2 = y2;
1389     } else {
1390         rect->y1 = y2;
1391         rect->y2 = y1;
1392     }
1393 
1394     Array *a = new Array(doc->getXRef());
1395     a->add(Object(rect->x1));
1396     a->add(Object(rect->y1));
1397     a->add(Object(rect->x2));
1398     a->add(Object(rect->y2));
1399 
1400     update("Rect", Object(a));
1401     invalidateAppearance();
1402 }
1403 
inRect(double x,double y) const1404 bool Annot::inRect(double x, double y) const
1405 {
1406     return rect->contains(x, y);
1407 }
1408 
update(const char * key,Object && value)1409 void Annot::update(const char *key, Object &&value)
1410 {
1411     annotLocker();
1412     /* Set M to current time, unless we are updating M itself */
1413     if (strcmp(key, "M") != 0) {
1414         modified.reset(timeToDateString(nullptr));
1415 
1416         annotObj.dictSet("M", Object(modified->copy()));
1417     }
1418 
1419     annotObj.dictSet(const_cast<char *>(key), std::move(value));
1420 
1421     doc->getXRef()->setModifiedObject(&annotObj, ref);
1422 }
1423 
setContents(GooString * new_content)1424 void Annot::setContents(GooString *new_content)
1425 {
1426     annotLocker();
1427 
1428     if (new_content) {
1429         contents = std::make_unique<GooString>(new_content);
1430         // append the unicode marker <FE FF> if needed
1431         if (!contents->hasUnicodeMarker()) {
1432             contents->prependUnicodeMarker();
1433         }
1434     } else {
1435         contents = std::make_unique<GooString>();
1436     }
1437 
1438     update("Contents", Object(contents->copy()));
1439 }
1440 
setName(GooString * new_name)1441 void Annot::setName(GooString *new_name)
1442 {
1443     annotLocker();
1444 
1445     if (new_name) {
1446         name = std::make_unique<GooString>(new_name);
1447     } else {
1448         name = std::make_unique<GooString>();
1449     }
1450 
1451     update("NM", Object(name->copy()));
1452 }
1453 
setModified(GooString * new_modified)1454 void Annot::setModified(GooString *new_modified)
1455 {
1456     annotLocker();
1457 
1458     if (new_modified) {
1459         modified = std::make_unique<GooString>(new_modified);
1460         update("M", Object(modified->copy()));
1461     } else {
1462         modified.reset(nullptr);
1463         update("M", Object(objNull));
1464     }
1465 }
1466 
setFlags(unsigned int new_flags)1467 void Annot::setFlags(unsigned int new_flags)
1468 {
1469     annotLocker();
1470     flags = new_flags;
1471     update("F", Object(int(flags)));
1472 }
1473 
setBorder(std::unique_ptr<AnnotBorder> && new_border)1474 void Annot::setBorder(std::unique_ptr<AnnotBorder> &&new_border)
1475 {
1476     annotLocker();
1477 
1478     if (new_border) {
1479         Object obj1 = new_border->writeToObject(doc->getXRef());
1480         update(new_border->getType() == AnnotBorder::typeArray ? "Border" : "BS", std::move(obj1));
1481         border = std::move(new_border);
1482     } else {
1483         border = nullptr;
1484     }
1485     invalidateAppearance();
1486 }
1487 
setColor(std::unique_ptr<AnnotColor> && new_color)1488 void Annot::setColor(std::unique_ptr<AnnotColor> &&new_color)
1489 {
1490     annotLocker();
1491 
1492     if (new_color) {
1493         Object obj1 = new_color->writeToObject(doc->getXRef());
1494         update("C", std::move(obj1));
1495         color = std::move(new_color);
1496     } else {
1497         color = nullptr;
1498     }
1499     invalidateAppearance();
1500 }
1501 
setPage(int pageIndex,bool updateP)1502 void Annot::setPage(int pageIndex, bool updateP)
1503 {
1504     annotLocker();
1505     Page *pageobj = doc->getPage(pageIndex);
1506     Object obj1(objNull);
1507 
1508     if (pageobj) {
1509         const Ref pageRef = pageobj->getRef();
1510         obj1 = Object(pageRef);
1511         page = pageIndex;
1512     } else {
1513         page = 0;
1514     }
1515 
1516     if (updateP) {
1517         update("P", std::move(obj1));
1518     }
1519 }
1520 
setAppearanceState(const char * state)1521 void Annot::setAppearanceState(const char *state)
1522 {
1523     annotLocker();
1524     if (!state)
1525         return;
1526 
1527     appearState = std::make_unique<GooString>(state);
1528     appearBBox = nullptr;
1529 
1530     update("AS", Object(objName, state));
1531 
1532     // The appearance state determines the current appearance stream
1533     if (appearStreams) {
1534         appearance = appearStreams->getAppearanceStream(AnnotAppearance::appearNormal, appearState->c_str());
1535     } else {
1536         appearance.setToNull();
1537     }
1538 }
1539 
invalidateAppearance()1540 void Annot::invalidateAppearance()
1541 {
1542     annotLocker();
1543     if (appearStreams) { // Remove existing appearance streams
1544         appearStreams->removeAllStreams();
1545     }
1546     appearStreams = nullptr;
1547     appearState = nullptr;
1548     appearBBox = nullptr;
1549     appearance.setToNull();
1550 
1551     Object obj2 = annotObj.dictLookup("AP");
1552     if (!obj2.isNull())
1553         update("AP", Object(objNull)); // Remove AP
1554 
1555     obj2 = annotObj.dictLookup("AS");
1556     if (!obj2.isNull())
1557         update("AS", Object(objNull)); // Remove AS
1558 }
1559 
getXMin()1560 double Annot::getXMin()
1561 {
1562     return rect->x1;
1563 }
1564 
getYMin()1565 double Annot::getYMin()
1566 {
1567     return rect->y1;
1568 }
1569 
getXMax()1570 double Annot::getXMax()
1571 {
1572     return rect->x2;
1573 }
1574 
getYMax()1575 double Annot::getYMax()
1576 {
1577     return rect->y2;
1578 }
1579 
readArrayNum(Object * pdfArray,int key,double * value)1580 void Annot::readArrayNum(Object *pdfArray, int key, double *value)
1581 {
1582     Object valueObject = pdfArray->arrayGet(key);
1583     if (valueObject.isNum()) {
1584         *value = valueObject.getNum();
1585     } else {
1586         *value = 0;
1587         ok = false;
1588     }
1589 }
1590 
removeReferencedObjects()1591 void Annot::removeReferencedObjects()
1592 {
1593     // Remove appearance streams (if any)
1594     invalidateAppearance();
1595 }
1596 
incRefCnt()1597 void Annot::incRefCnt()
1598 {
1599     refCnt++;
1600 }
1601 
decRefCnt()1602 void Annot::decRefCnt()
1603 {
1604     if (--refCnt == 0) {
1605         delete this;
1606     }
1607 }
1608 
~Annot()1609 Annot::~Annot() { }
1610 
setDrawColor(const AnnotColor * drawColor,bool fill)1611 void AnnotAppearanceBuilder::setDrawColor(const AnnotColor *drawColor, bool fill)
1612 {
1613     const double *values = drawColor->getValues();
1614 
1615     switch (drawColor->getSpace()) {
1616     case AnnotColor::colorCMYK:
1617         appearBuf->appendf("{0:.5f} {1:.5f} {2:.5f} {3:.5f} {4:c}\n", values[0], values[1], values[2], values[3], fill ? 'k' : 'K');
1618         break;
1619     case AnnotColor::colorRGB:
1620         appearBuf->appendf("{0:.5f} {1:.5f} {2:.5f} {3:s}\n", values[0], values[1], values[2], fill ? "rg" : "RG");
1621         break;
1622     case AnnotColor::colorGray:
1623         appearBuf->appendf("{0:.5f} {1:c}\n", values[0], fill ? 'g' : 'G');
1624         break;
1625     case AnnotColor::colorTransparent:
1626     default:
1627         break;
1628     }
1629 }
1630 
setTextFont(const Object & fontName,double fontSize)1631 void AnnotAppearanceBuilder::setTextFont(const Object &fontName, double fontSize)
1632 {
1633     if (fontName.isName() && strlen(fontName.getName()) > 0)
1634         appearBuf->appendf("/{0:s} {1:.2f} Tf\n", fontName.getName(), fontSize);
1635 }
1636 
setLineStyleForBorder(const AnnotBorder * border)1637 void AnnotAppearanceBuilder::setLineStyleForBorder(const AnnotBorder *border)
1638 {
1639     int i, dashLength;
1640     double *dash;
1641 
1642     switch (border->getStyle()) {
1643     case AnnotBorder::borderDashed:
1644         appearBuf->append("[");
1645         dashLength = border->getDashLength();
1646         dash = border->getDash();
1647         for (i = 0; i < dashLength; ++i)
1648             appearBuf->appendf(" {0:.2f}", dash[i]);
1649         appearBuf->append(" ] 0 d\n");
1650         break;
1651     default:
1652         appearBuf->append("[] 0 d\n");
1653         break;
1654     }
1655     appearBuf->appendf("{0:.2f} w\n", border->getWidth());
1656 }
1657 
1658 // Draw an (approximate) circle of radius <r> centered at (<cx>, <cy>).
1659 // If <fill> is true, the circle is filled; otherwise it is stroked.
drawCircle(double cx,double cy,double r,bool fill)1660 void AnnotAppearanceBuilder::drawCircle(double cx, double cy, double r, bool fill)
1661 {
1662     if (fill)
1663         drawEllipse(cx, cy, r, r, true, false);
1664     else
1665         drawEllipse(cx, cy, r, r, false, true);
1666 }
1667 
1668 // Draw an (approximate) ellipse of radius <rx> on x-axis and <ry> on y-axis, centered at (<cx>, <cy>).
1669 // If <fill> is true, the ellipse is filled with current color for non-stroking operations.
1670 // If <stroke> is true, the ellipse path ist stroked with current color and color space for stroking operations.
1671 // Path will be closed if either fill or stroke is true; otherwise it's left open.
drawEllipse(double cx,double cy,double rx,double ry,bool fill,bool stroke)1672 void AnnotAppearanceBuilder::drawEllipse(double cx, double cy, double rx, double ry, bool fill, bool stroke)
1673 {
1674     appearBuf->appendf("{0:.2f} {1:.2f} m\n", cx + rx, cy);
1675     appearBuf->appendf("{0:.2f} {1:.2f} {2:.2f} {3:.2f} {4:.2f} {5:.2f} c\n", cx + rx, cy + bezierCircle * ry, cx + bezierCircle * rx, cy + ry, cx, cy + ry);
1676     appearBuf->appendf("{0:.2f} {1:.2f} {2:.2f} {3:.2f} {4:.2f} {5:.2f} c\n", cx - bezierCircle * rx, cy + ry, cx - rx, cy + bezierCircle * ry, cx - rx, cy);
1677     appearBuf->appendf("{0:.2f} {1:.2f} {2:.2f} {3:.2f} {4:.2f} {5:.2f} c\n", cx - rx, cy - bezierCircle * ry, cx - bezierCircle * rx, cy - ry, cx, cy - ry);
1678     appearBuf->appendf("{0:.2f} {1:.2f} {2:.2f} {3:.2f} {4:.2f} {5:.2f} c\n", cx + bezierCircle * rx, cy - ry, cx + rx, cy - bezierCircle * ry, cx + rx, cy);
1679     if (!fill && stroke)
1680         appearBuf->append("s\n");
1681     else if (fill && !stroke)
1682         appearBuf->append("f\n");
1683     else if (fill && stroke)
1684         appearBuf->append("b\n");
1685 }
1686 
1687 // Draw the top-left half of an (approximate) circle of radius <r>
1688 // centered at (<cx>, <cy>).
drawCircleTopLeft(double cx,double cy,double r)1689 void AnnotAppearanceBuilder::drawCircleTopLeft(double cx, double cy, double r)
1690 {
1691     double r2;
1692 
1693     r2 = r / sqrt(2.0);
1694     appearBuf->appendf("{0:.2f} {1:.2f} m\n", cx + r2, cy + r2);
1695     appearBuf->appendf("{0:.2f} {1:.2f} {2:.2f} {3:.2f} {4:.2f} {5:.2f} c\n", cx + (1 - bezierCircle) * r2, cy + (1 + bezierCircle) * r2, cx - (1 - bezierCircle) * r2, cy + (1 + bezierCircle) * r2, cx - r2, cy + r2);
1696     appearBuf->appendf("{0:.2f} {1:.2f} {2:.2f} {3:.2f} {4:.2f} {5:.2f} c\n", cx - (1 + bezierCircle) * r2, cy + (1 - bezierCircle) * r2, cx - (1 + bezierCircle) * r2, cy - (1 - bezierCircle) * r2, cx - r2, cy - r2);
1697     appearBuf->append("S\n");
1698 }
1699 
1700 // Draw the bottom-right half of an (approximate) circle of radius <r>
1701 // centered at (<cx>, <cy>).
drawCircleBottomRight(double cx,double cy,double r)1702 void AnnotAppearanceBuilder::drawCircleBottomRight(double cx, double cy, double r)
1703 {
1704     double r2;
1705 
1706     r2 = r / sqrt(2.0);
1707     appearBuf->appendf("{0:.2f} {1:.2f} m\n", cx - r2, cy - r2);
1708     appearBuf->appendf("{0:.2f} {1:.2f} {2:.2f} {3:.2f} {4:.2f} {5:.2f} c\n", cx - (1 - bezierCircle) * r2, cy - (1 + bezierCircle) * r2, cx + (1 - bezierCircle) * r2, cy - (1 + bezierCircle) * r2, cx + r2, cy - r2);
1709     appearBuf->appendf("{0:.2f} {1:.2f} {2:.2f} {3:.2f} {4:.2f} {5:.2f} c\n", cx + (1 + bezierCircle) * r2, cy - (1 - bezierCircle) * r2, cx + (1 + bezierCircle) * r2, cy + (1 - bezierCircle) * r2, cx + r2, cy + r2);
1710     appearBuf->append("S\n");
1711 }
1712 
drawLineEndSquare(double x,double y,double size,bool fill,const Matrix & m)1713 void AnnotAppearanceBuilder::drawLineEndSquare(double x, double y, double size, bool fill, const Matrix &m)
1714 {
1715     const double halfSize { size / 2. };
1716     const double x1[3] { x - size, x - size, x };
1717     const double y1[3] { y + halfSize, y - halfSize, y - halfSize };
1718     double tx, ty;
1719 
1720     m.transform(x, y + halfSize, &tx, &ty);
1721     appendf("{0:.2f} {1:.2f} m\n", tx, ty);
1722     for (int i = 0; i < 3; i++) {
1723         m.transform(x1[i], y1[i], &tx, &ty);
1724         appendf("{0:.2f} {1:.2f} l\n", tx, ty);
1725     }
1726     appearBuf->append(fill ? "b\n" : "s\n");
1727 }
1728 
drawLineEndCircle(double x,double y,double size,bool fill,const Matrix & m)1729 void AnnotAppearanceBuilder::drawLineEndCircle(double x, double y, double size, bool fill, const Matrix &m)
1730 {
1731     const double halfSize { size / 2. };
1732     const double x1[4] { x, x - halfSize - bezierCircle * halfSize, x - size, x - halfSize + bezierCircle * halfSize };
1733     const double x2[4] { x - halfSize + bezierCircle * halfSize, x - size, x - halfSize - bezierCircle * halfSize, x };
1734     const double x3[4] { x - halfSize, x - size, x - halfSize, x };
1735     const double y1[4] { y + bezierCircle * halfSize, y + halfSize, y - bezierCircle * halfSize, y - halfSize };
1736     const double y2[4] { y + halfSize, y + bezierCircle * halfSize, y - halfSize, y - bezierCircle * halfSize };
1737     const double y3[4] { y + halfSize, y, y - halfSize, y };
1738     double tx[3];
1739     double ty[3];
1740 
1741     m.transform(x, y, &tx[0], &ty[0]);
1742     appearBuf->appendf("{0:.2f} {1:.2f} m\n", tx[0], ty[0]);
1743     for (int i = 0; i < 4; i++) {
1744         m.transform(x1[i], y1[i], &tx[0], &ty[0]);
1745         m.transform(x2[i], y2[i], &tx[1], &ty[1]);
1746         m.transform(x3[i], y3[i], &tx[2], &ty[2]);
1747         appearBuf->appendf("{0:.2f} {1:.2f} {2:.2f} {3:.2f} {4:.2f} {5:.2f} c\n", tx[0], ty[0], tx[1], ty[1], tx[2], ty[2]);
1748     }
1749     appearBuf->append(fill ? "b\n" : "s\n");
1750 }
1751 
drawLineEndDiamond(double x,double y,double size,bool fill,const Matrix & m)1752 void AnnotAppearanceBuilder::drawLineEndDiamond(double x, double y, double size, bool fill, const Matrix &m)
1753 {
1754     const double halfSize { size / 2. };
1755     const double x1[3] { x - halfSize, x - size, x - halfSize };
1756     const double y1[3] { y + halfSize, y, y - halfSize };
1757     double tx, ty;
1758 
1759     m.transform(x, y, &tx, &ty);
1760     appendf("{0:.2f} {1:.2f} m\n", tx, ty);
1761     for (int i = 0; i < 3; i++) {
1762         m.transform(x1[i], y1[i], &tx, &ty);
1763         appendf("{0:.2f} {1:.2f} l\n", tx, ty);
1764     }
1765     appearBuf->append(fill ? "b\n" : "s\n");
1766 }
1767 
drawLineEndArrow(double x,double y,double size,int orientation,bool isOpen,bool fill,const Matrix & m)1768 void AnnotAppearanceBuilder::drawLineEndArrow(double x, double y, double size, int orientation, bool isOpen, bool fill, const Matrix &m)
1769 {
1770     const double alpha { M_PI / 6. };
1771     const double xOffs { orientation * size };
1772     const double yOffs { tan(alpha) * size };
1773     double tx, ty;
1774 
1775     m.transform(x - xOffs, y + yOffs, &tx, &ty);
1776     appendf("{0:.2f} {1:.2f} m\n", tx, ty);
1777     m.transform(x, y, &tx, &ty);
1778     appendf("{0:.2f} {1:.2f} l\n", tx, ty);
1779     m.transform(x - xOffs, y - yOffs, &tx, &ty);
1780     appendf("{0:.2f} {1:.2f} l\n", tx, ty);
1781 
1782     if (isOpen) {
1783         appearBuf->append("S\n");
1784     } else {
1785         appearBuf->append(fill ? "b\n" : "s\n");
1786     }
1787 }
1788 
drawLineEndSlash(double x,double y,double size,const Matrix & m)1789 void AnnotAppearanceBuilder::drawLineEndSlash(double x, double y, double size, const Matrix &m)
1790 {
1791     const double halfSize { size / 2. };
1792     const double xOffs { cos(M_PI / 3.) * halfSize };
1793     double tx, ty;
1794 
1795     m.transform(x - xOffs, y - halfSize, &tx, &ty);
1796     appendf("{0:.2f} {1:.2f} m\n", tx, ty);
1797     m.transform(x + xOffs, y + halfSize, &tx, &ty);
1798     appendf("{0:.2f} {1:.2f} l\n", tx, ty);
1799     appearBuf->append("S\n");
1800 }
1801 
drawLineEnding(AnnotLineEndingStyle endingStyle,double x,double y,double size,bool fill,const Matrix & m)1802 void AnnotAppearanceBuilder::drawLineEnding(AnnotLineEndingStyle endingStyle, double x, double y, double size, bool fill, const Matrix &m)
1803 {
1804     switch (endingStyle) {
1805     case annotLineEndingSquare:
1806         drawLineEndSquare(x, y, size, fill, m);
1807         break;
1808     case annotLineEndingCircle:
1809         drawLineEndCircle(x, y, size, fill, m);
1810         break;
1811     case annotLineEndingDiamond:
1812         drawLineEndDiamond(x, y, size, fill, m);
1813         break;
1814     case annotLineEndingOpenArrow:
1815         drawLineEndArrow(x, y, size, 1, true, fill, m);
1816         break;
1817     case annotLineEndingClosedArrow:
1818         drawLineEndArrow(x, y, size, 1, false, fill, m);
1819         break;
1820     case annotLineEndingButt: {
1821         const double halfSize { size / 2. };
1822         double tx, ty;
1823         m.transform(x, y + halfSize, &tx, &ty);
1824         appendf("{0:.2f} {1:.2f} m\n", tx, ty);
1825         m.transform(x, y - halfSize, &tx, &ty);
1826         appendf("{0:.2f} {1:.2f} l S\n", tx, ty);
1827     } break;
1828     case annotLineEndingROpenArrow:
1829         drawLineEndArrow(x, y, size, -1, true, fill, m);
1830         break;
1831     case annotLineEndingRClosedArrow:
1832         drawLineEndArrow(x, y, size, -1, false, fill, m);
1833         break;
1834     case annotLineEndingSlash:
1835         drawLineEndSlash(x, y, size, m);
1836         break;
1837     default:
1838         break;
1839     }
1840 }
1841 
lineEndingXShorten(AnnotLineEndingStyle endingStyle,double size)1842 double AnnotAppearanceBuilder::lineEndingXShorten(AnnotLineEndingStyle endingStyle, double size)
1843 {
1844     switch (endingStyle) {
1845     case annotLineEndingCircle:
1846     case annotLineEndingClosedArrow:
1847     case annotLineEndingDiamond:
1848     case annotLineEndingSquare:
1849         return size;
1850     default:
1851         break;
1852     }
1853     return 0;
1854 }
1855 
lineEndingXExtendBBox(AnnotLineEndingStyle endingStyle,double size)1856 double AnnotAppearanceBuilder::lineEndingXExtendBBox(AnnotLineEndingStyle endingStyle, double size)
1857 {
1858     switch (endingStyle) {
1859     case annotLineEndingRClosedArrow:
1860     case annotLineEndingROpenArrow:
1861         return size;
1862     case annotLineEndingSlash:
1863         return cos(M_PI / 3.) * size / 2.;
1864     default:
1865         break;
1866     }
1867     return 0;
1868 }
1869 
createForm(const GooString * appearBuf,const double * bbox,bool transparencyGroup,Dict * resDict)1870 Object Annot::createForm(const GooString *appearBuf, const double *bbox, bool transparencyGroup, Dict *resDict)
1871 {
1872     return createForm(appearBuf, bbox, transparencyGroup, resDict ? Object(resDict) : Object());
1873 }
1874 
createForm(const GooString * appearBuf,const double * bbox,bool transparencyGroup,Object && resDictObject)1875 Object Annot::createForm(const GooString *appearBuf, const double *bbox, bool transparencyGroup, Object &&resDictObject)
1876 {
1877     Dict *appearDict = new Dict(doc->getXRef());
1878     appearDict->set("Length", Object(appearBuf->getLength()));
1879     appearDict->set("Subtype", Object(objName, "Form"));
1880 
1881     Array *a = new Array(doc->getXRef());
1882     a->add(Object(bbox[0]));
1883     a->add(Object(bbox[1]));
1884     a->add(Object(bbox[2]));
1885     a->add(Object(bbox[3]));
1886     appearDict->set("BBox", Object(a));
1887     if (transparencyGroup) {
1888         Dict *d = new Dict(doc->getXRef());
1889         d->set("S", Object(objName, "Transparency"));
1890         appearDict->set("Group", Object(d));
1891     }
1892     if (resDictObject.isDict())
1893         appearDict->set("Resources", std::move(resDictObject));
1894 
1895     Stream *mStream = new AutoFreeMemStream(copyString(appearBuf->c_str()), 0, appearBuf->getLength(), Object(appearDict));
1896     return Object(mStream);
1897 }
1898 
createResourcesDict(const char * formName,Object && formStream,const char * stateName,double opacity,const char * blendMode)1899 Dict *Annot::createResourcesDict(const char *formName, Object &&formStream, const char *stateName, double opacity, const char *blendMode)
1900 {
1901     Dict *gsDict = new Dict(doc->getXRef());
1902     if (opacity != 1) {
1903         gsDict->set("CA", Object(opacity));
1904         gsDict->set("ca", Object(opacity));
1905     }
1906     if (blendMode)
1907         gsDict->set("BM", Object(objName, blendMode));
1908     Dict *stateDict = new Dict(doc->getXRef());
1909     stateDict->set(stateName, Object(gsDict));
1910     Dict *formDict = new Dict(doc->getXRef());
1911     formDict->set(formName, std::move(formStream));
1912 
1913     Dict *resDict = new Dict(doc->getXRef());
1914     resDict->set("ExtGState", Object(stateDict));
1915     resDict->set("XObject", Object(formDict));
1916 
1917     return resDict;
1918 }
1919 
getAppearanceResDict()1920 Object Annot::getAppearanceResDict()
1921 {
1922     Object obj1, obj2;
1923 
1924     // Fetch appearance's resource dict (if any)
1925     obj1 = appearance.fetch(doc->getXRef());
1926     if (obj1.isStream()) {
1927         obj2 = obj1.streamGetDict()->lookup("Resources");
1928         if (obj2.isDict()) {
1929             return obj2;
1930         }
1931     }
1932 
1933     return Object(objNull);
1934 }
1935 
isVisible(bool printing)1936 bool Annot::isVisible(bool printing)
1937 {
1938     // check the flags
1939     if ((flags & flagHidden) || (printing && !(flags & flagPrint)) || (!printing && (flags & flagNoView))) {
1940         return false;
1941     }
1942 
1943     // check the OC
1944     OCGs *optContentConfig = doc->getCatalog()->getOptContentConfig();
1945     if (optContentConfig) {
1946         if (!optContentConfig->optContentIsVisible(&oc))
1947             return false;
1948     }
1949 
1950     return true;
1951 }
1952 
getRotation() const1953 int Annot::getRotation() const
1954 {
1955     Page *pageobj = doc->getPage(page);
1956     assert(pageobj != nullptr);
1957 
1958     if (flags & flagNoRotate) {
1959         return (360 - pageobj->getRotate()) % 360;
1960     } else {
1961         return 0;
1962     }
1963 }
1964 
draw(Gfx * gfx,bool printing)1965 void Annot::draw(Gfx *gfx, bool printing)
1966 {
1967     annotLocker();
1968     if (!isVisible(printing))
1969         return;
1970 
1971     // draw the appearance stream
1972     Object obj = appearance.fetch(gfx->getXRef());
1973     gfx->drawAnnot(&obj, nullptr, color.get(), rect->x1, rect->y1, rect->x2, rect->y2, getRotation());
1974 }
1975 
setNewAppearance(Object && newAppearance)1976 void Annot::setNewAppearance(Object &&newAppearance)
1977 {
1978     if (newAppearance.isNull())
1979         return;
1980 
1981     annotLocker();
1982     if (newAppearance.getType() == ObjType::objStream) {
1983         invalidateAppearance();
1984         appearance = std::move(newAppearance);
1985 
1986         Ref updatedAppearanceStream = doc->getXRef()->addIndirectObject(appearance);
1987 
1988         Object obj1 = Object(new Dict(doc->getXRef()));
1989         obj1.dictAdd("N", Object(updatedAppearanceStream));
1990         update("AP", std::move(obj1));
1991 
1992         Object updatedAP = annotObj.dictLookup("AP");
1993         appearStreams = std::make_unique<AnnotAppearance>(doc, &updatedAP);
1994     } else {
1995         appearStreams = std::make_unique<AnnotAppearance>(doc, &newAppearance);
1996         update("AP", std::move(newAppearance));
1997 
1998         if (appearStreams)
1999             appearance = appearStreams->getAppearanceStream(AnnotAppearance::appearNormal, appearState->c_str());
2000     }
2001 }
2002 
getAppearance() const2003 Object Annot::getAppearance() const
2004 {
2005     return appearance.fetch(doc->getXRef());
2006 }
2007 
2008 //------------------------------------------------------------------------
2009 // AnnotPopup
2010 //------------------------------------------------------------------------
2011 
AnnotPopup(PDFDoc * docA,PDFRectangle * rectA)2012 AnnotPopup::AnnotPopup(PDFDoc *docA, PDFRectangle *rectA) : Annot(docA, rectA)
2013 {
2014     type = typePopup;
2015 
2016     annotObj.dictSet("Subtype", Object(objName, "Popup"));
2017     initialize(docA, annotObj.getDict());
2018 }
2019 
AnnotPopup(PDFDoc * docA,Object && dictObject,const Object * obj)2020 AnnotPopup::AnnotPopup(PDFDoc *docA, Object &&dictObject, const Object *obj) : Annot(docA, std::move(dictObject), obj)
2021 {
2022     type = typePopup;
2023     initialize(docA, annotObj.getDict());
2024 }
2025 
~AnnotPopup()2026 AnnotPopup::~AnnotPopup() { }
2027 
initialize(PDFDoc * docA,Dict * dict)2028 void AnnotPopup::initialize(PDFDoc *docA, Dict *dict)
2029 {
2030     const Object &parentObj = dict->lookupNF("Parent");
2031     if (parentObj.isRef()) {
2032         parentRef = parentObj.getRef();
2033     } else {
2034         parentRef = Ref::INVALID();
2035     }
2036 
2037     open = dict->lookup("Open").getBoolWithDefaultValue(false);
2038 }
2039 
setParent(Annot * parentA)2040 void AnnotPopup::setParent(Annot *parentA)
2041 {
2042     parentRef = parentA->getRef();
2043     update("Parent", Object(parentRef));
2044 }
2045 
setOpen(bool openA)2046 void AnnotPopup::setOpen(bool openA)
2047 {
2048     open = openA;
2049     update("Open", Object(open));
2050 }
2051 
2052 //------------------------------------------------------------------------
2053 // AnnotMarkup
2054 //------------------------------------------------------------------------
AnnotMarkup(PDFDoc * docA,PDFRectangle * rectA)2055 AnnotMarkup::AnnotMarkup(PDFDoc *docA, PDFRectangle *rectA) : Annot(docA, rectA)
2056 {
2057     initialize(docA, annotObj.getDict());
2058 }
2059 
AnnotMarkup(PDFDoc * docA,Object && dictObject,const Object * obj)2060 AnnotMarkup::AnnotMarkup(PDFDoc *docA, Object &&dictObject, const Object *obj) : Annot(docA, std::move(dictObject), obj)
2061 {
2062     initialize(docA, annotObj.getDict());
2063 }
2064 
2065 AnnotMarkup::~AnnotMarkup() = default;
2066 
initialize(PDFDoc * docA,Dict * dict)2067 void AnnotMarkup::initialize(PDFDoc *docA, Dict *dict)
2068 {
2069     Object obj1;
2070 
2071     obj1 = dict->lookup("T");
2072     if (obj1.isString()) {
2073         label.reset(obj1.getString()->copy());
2074     }
2075 
2076     Object popupObj = dict->lookup("Popup");
2077     const Object &obj2 = dict->lookupNF("Popup");
2078     if (popupObj.isDict() && obj2.isRef()) {
2079         popup = std::make_unique<AnnotPopup>(docA, std::move(popupObj), &obj2);
2080     }
2081 
2082     opacity = dict->lookup("CA").getNumWithDefaultValue(1.0);
2083 
2084     obj1 = dict->lookup("CreationDate");
2085     if (obj1.isString()) {
2086         date.reset(obj1.getString()->copy());
2087     }
2088 
2089     const Object &irtObj = dict->lookupNF("IRT");
2090     if (irtObj.isRef()) {
2091         inReplyTo = irtObj.getRef();
2092     } else {
2093         inReplyTo = Ref::INVALID();
2094     }
2095 
2096     obj1 = dict->lookup("Subj");
2097     if (obj1.isString()) {
2098         subject.reset(obj1.getString()->copy());
2099     }
2100 
2101     obj1 = dict->lookup("RT");
2102     if (obj1.isName()) {
2103         const char *replyName = obj1.getName();
2104 
2105         if (!strcmp(replyName, "R")) {
2106             replyTo = replyTypeR;
2107         } else if (!strcmp(replyName, "Group")) {
2108             replyTo = replyTypeGroup;
2109         } else {
2110             replyTo = replyTypeR;
2111         }
2112     } else {
2113         replyTo = replyTypeR;
2114     }
2115 
2116     obj1 = dict->lookup("ExData");
2117     if (obj1.isDict()) {
2118         exData = parseAnnotExternalData(obj1.getDict());
2119     } else {
2120         exData = annotExternalDataMarkupUnknown;
2121     }
2122 }
2123 
setLabel(GooString * new_label)2124 void AnnotMarkup::setLabel(GooString *new_label)
2125 {
2126     if (new_label) {
2127         label = std::make_unique<GooString>(new_label);
2128         // append the unicode marker <FE FF> if needed
2129         if (!label->hasUnicodeMarker()) {
2130             label->prependUnicodeMarker();
2131         }
2132     } else {
2133         label = std::make_unique<GooString>();
2134     }
2135 
2136     update("T", Object(label->copy()));
2137 }
2138 
setPopup(std::unique_ptr<AnnotPopup> && new_popup)2139 void AnnotMarkup::setPopup(std::unique_ptr<AnnotPopup> &&new_popup)
2140 {
2141     // If there exists an old popup annotation that is already
2142     // associated with a page, then we need to remove that
2143     // popup annotation from the page. Otherwise we would have
2144     // dangling references to it.
2145     if (popup && popup->getPageNum() != 0) {
2146         Page *pageobj = doc->getPage(popup->getPageNum());
2147         if (pageobj) {
2148             pageobj->removeAnnot(popup.get());
2149         }
2150     }
2151 
2152     if (new_popup) {
2153         const Ref popupRef = new_popup->getRef();
2154         update("Popup", Object(popupRef));
2155 
2156         new_popup->setParent(this);
2157         popup = std::move(new_popup);
2158 
2159         // If this annotation is already added to a page, then we
2160         // add the new popup annotation to the same page.
2161         if (page != 0) {
2162             Page *pageobj = doc->getPage(page);
2163             assert(pageobj != nullptr); // pageobj should exist in doc (see setPage())
2164 
2165             pageobj->addAnnot(popup.get());
2166         }
2167     } else {
2168         popup = nullptr;
2169     }
2170 }
2171 
setOpacity(double opacityA)2172 void AnnotMarkup::setOpacity(double opacityA)
2173 {
2174     opacity = opacityA;
2175     update("CA", Object(opacity));
2176     invalidateAppearance();
2177 }
2178 
setDate(GooString * new_date)2179 void AnnotMarkup::setDate(GooString *new_date)
2180 {
2181     if (new_date) {
2182         date = std::make_unique<GooString>(new_date);
2183         update("CreationDate", Object(date->copy()));
2184     } else {
2185         date.reset(nullptr);
2186         update("CreationDate", Object(objNull));
2187     }
2188 }
2189 
removeReferencedObjects()2190 void AnnotMarkup::removeReferencedObjects()
2191 {
2192     Page *pageobj = doc->getPage(page);
2193     assert(pageobj != nullptr); // We're called when removing an annot from a page
2194 
2195     // Remove popup
2196     if (popup) {
2197         pageobj->removeAnnot(popup.get());
2198     }
2199 
2200     Annot::removeReferencedObjects();
2201 }
2202 
2203 //------------------------------------------------------------------------
2204 // AnnotText
2205 //------------------------------------------------------------------------
2206 
AnnotText(PDFDoc * docA,PDFRectangle * rectA)2207 AnnotText::AnnotText(PDFDoc *docA, PDFRectangle *rectA) : AnnotMarkup(docA, rectA)
2208 {
2209     type = typeText;
2210     flags |= flagNoZoom | flagNoRotate;
2211 
2212     annotObj.dictSet("Subtype", Object(objName, "Text"));
2213     initialize(docA, annotObj.getDict());
2214 }
2215 
AnnotText(PDFDoc * docA,Object && dictObject,const Object * obj)2216 AnnotText::AnnotText(PDFDoc *docA, Object &&dictObject, const Object *obj) : AnnotMarkup(docA, std::move(dictObject), obj)
2217 {
2218 
2219     type = typeText;
2220     flags |= flagNoZoom | flagNoRotate;
2221     initialize(docA, annotObj.getDict());
2222 }
2223 
2224 AnnotText::~AnnotText() = default;
2225 
initialize(PDFDoc * docA,Dict * dict)2226 void AnnotText::initialize(PDFDoc *docA, Dict *dict)
2227 {
2228     Object obj1;
2229 
2230     open = dict->lookup("Open").getBoolWithDefaultValue(false);
2231 
2232     obj1 = dict->lookup("Name");
2233     if (obj1.isName()) {
2234         icon = std::make_unique<GooString>(obj1.getName());
2235     } else {
2236         icon = std::make_unique<GooString>("Note");
2237     }
2238 
2239     obj1 = dict->lookup("StateModel");
2240     if (obj1.isString()) {
2241         const GooString *modelName = obj1.getString();
2242 
2243         Object obj2 = dict->lookup("State");
2244         if (obj2.isString()) {
2245             const GooString *stateName = obj2.getString();
2246 
2247             if (!stateName->cmp("Marked")) {
2248                 state = stateMarked;
2249             } else if (!stateName->cmp("Unmarked")) {
2250                 state = stateUnmarked;
2251             } else if (!stateName->cmp("Accepted")) {
2252                 state = stateAccepted;
2253             } else if (!stateName->cmp("Rejected")) {
2254                 state = stateRejected;
2255             } else if (!stateName->cmp("Cancelled")) {
2256                 state = stateCancelled;
2257             } else if (!stateName->cmp("Completed")) {
2258                 state = stateCompleted;
2259             } else if (!stateName->cmp("None")) {
2260                 state = stateNone;
2261             } else {
2262                 state = stateUnknown;
2263             }
2264         } else {
2265             state = stateUnknown;
2266         }
2267 
2268         if (!modelName->cmp("Marked")) {
2269             switch (state) {
2270             case stateUnknown:
2271                 state = stateMarked;
2272                 break;
2273             case stateAccepted:
2274             case stateRejected:
2275             case stateCancelled:
2276             case stateCompleted:
2277             case stateNone:
2278                 state = stateUnknown;
2279                 break;
2280             default:
2281                 break;
2282             }
2283         } else if (!modelName->cmp("Review")) {
2284             switch (state) {
2285             case stateUnknown:
2286                 state = stateNone;
2287                 break;
2288             case stateMarked:
2289             case stateUnmarked:
2290                 state = stateUnknown;
2291                 break;
2292             default:
2293                 break;
2294             }
2295         } else {
2296             state = stateUnknown;
2297         }
2298     } else {
2299         state = stateUnknown;
2300     }
2301 }
2302 
setOpen(bool openA)2303 void AnnotText::setOpen(bool openA)
2304 {
2305     open = openA;
2306     update("Open", Object(open));
2307 }
2308 
setIcon(GooString * new_icon)2309 void AnnotText::setIcon(GooString *new_icon)
2310 {
2311     if (new_icon && icon->cmp(new_icon) == 0)
2312         return;
2313 
2314     if (new_icon) {
2315         icon = std::make_unique<GooString>(new_icon);
2316     } else {
2317         icon = std::make_unique<GooString>("Note");
2318     }
2319 
2320     update("Name", Object(objName, icon->c_str()));
2321     invalidateAppearance();
2322 }
2323 
2324 #define ANNOT_TEXT_AP_NOTE                                                                                                                                                                                                                     \
2325     "3.602 24 m 20.398 24 l 22.387 24 24 22.387 24 20.398 c 24 3.602 l 24\n"                                                                                                                                                                   \
2326     "1.613 22.387 0 20.398 0 c 3.602 0 l 1.613 0 0 1.613 0 3.602 c 0 20.398\n"                                                                                                                                                                 \
2327     "l 0 22.387 1.613 24 3.602 24 c h\n"                                                                                                                                                                                                       \
2328     "3.602 24 m f\n"                                                                                                                                                                                                                           \
2329     "0.533333 0.541176 0.521569 RG 2 w\n"                                                                                                                                                                                                      \
2330     "1 J\n"                                                                                                                                                                                                                                    \
2331     "1 j\n"                                                                                                                                                                                                                                    \
2332     "[] 0.0 d\n"                                                                                                                                                                                                                               \
2333     "4 M 9 18 m 4 18 l 4 7 4 4 6 3 c 20 3 l 18 4 18 7 18 18 c 17 18 l S\n"                                                                                                                                                                     \
2334     "1.5 w\n"                                                                                                                                                                                                                                  \
2335     "0 j\n"                                                                                                                                                                                                                                    \
2336     "10 16 m 14 21 l S\n"                                                                                                                                                                                                                      \
2337     "1.85625 w\n"                                                                                                                                                                                                                              \
2338     "1 j\n"                                                                                                                                                                                                                                    \
2339     "15.07 20.523 m 15.07 19.672 14.379 18.977 13.523 18.977 c 12.672 18.977\n"                                                                                                                                                                \
2340     "11.977 19.672 11.977 20.523 c 11.977 21.379 12.672 22.07 13.523 22.07 c\n"                                                                                                                                                                \
2341     "14.379 22.07 15.07 21.379 15.07 20.523 c h\n"                                                                                                                                                                                             \
2342     "15.07 20.523 m S\n"                                                                                                                                                                                                                       \
2343     "1 w\n"                                                                                                                                                                                                                                    \
2344     "0 j\n"                                                                                                                                                                                                                                    \
2345     "6.5 13.5 m 15.5 13.5 l S\n"                                                                                                                                                                                                               \
2346     "6.5 10.5 m 13.5 10.5 l S\n"                                                                                                                                                                                                               \
2347     "6.801 7.5 m 15.5 7.5 l S\n"                                                                                                                                                                                                               \
2348     "0.729412 0.741176 0.713725 RG 2 w\n"                                                                                                                                                                                                      \
2349     "1 j\n"                                                                                                                                                                                                                                    \
2350     "9 19 m 4 19 l 4 8 4 5 6 4 c 20 4 l 18 5 18 8 18 19 c 17 19 l S\n"                                                                                                                                                                         \
2351     "1.5 w\n"                                                                                                                                                                                                                                  \
2352     "0 j\n"                                                                                                                                                                                                                                    \
2353     "10 17 m 14 22 l S\n"                                                                                                                                                                                                                      \
2354     "1.85625 w\n"                                                                                                                                                                                                                              \
2355     "1 j\n"                                                                                                                                                                                                                                    \
2356     "15.07 21.523 m 15.07 20.672 14.379 19.977 13.523 19.977 c 12.672 19.977\n"                                                                                                                                                                \
2357     "11.977 20.672 11.977 21.523 c 11.977 22.379 12.672 23.07 13.523 23.07 c\n"                                                                                                                                                                \
2358     "14.379 23.07 15.07 22.379 15.07 21.523 c h\n"                                                                                                                                                                                             \
2359     "15.07 21.523 m S\n"                                                                                                                                                                                                                       \
2360     "1 w\n"                                                                                                                                                                                                                                    \
2361     "0 j\n"                                                                                                                                                                                                                                    \
2362     "6.5 14.5 m 15.5 14.5 l S\n"                                                                                                                                                                                                               \
2363     "6.5 11.5 m 13.5 11.5 l S\n"                                                                                                                                                                                                               \
2364     "6.801 8.5 m 15.5 8.5 l S\n"
2365 
2366 #define ANNOT_TEXT_AP_COMMENT                                                                                                                                                                                                                  \
2367     "4.301 23 m 19.699 23 l 21.523 23 23 21.523 23 19.699 c 23 4.301 l 23\n"                                                                                                                                                                   \
2368     "2.477 21.523 1 19.699 1 c 4.301 1 l 2.477 1 1 2.477 1 4.301 c 1 19.699\n"                                                                                                                                                                 \
2369     "l 1 21.523 2.477 23 4.301 23 c h\n"                                                                                                                                                                                                       \
2370     "4.301 23 m f\n"                                                                                                                                                                                                                           \
2371     "0.533333 0.541176 0.521569 RG 2 w\n"                                                                                                                                                                                                      \
2372     "0 J\n"                                                                                                                                                                                                                                    \
2373     "1 j\n"                                                                                                                                                                                                                                    \
2374     "[] 0.0 d\n"                                                                                                                                                                                                                               \
2375     "4 M 8 20 m 16 20 l 18.363 20 20 18.215 20 16 c 20 13 l 20 10.785 18.363 9\n"                                                                                                                                                              \
2376     "16 9 c 13 9 l 8 3 l 8 9 l 8 9 l 5.637 9 4 10.785 4 13 c 4 16 l 4 18.215\n"                                                                                                                                                                \
2377     "5.637 20 8 20 c h\n"                                                                                                                                                                                                                      \
2378     "8 20 m S\n"                                                                                                                                                                                                                               \
2379     "0.729412 0.741176 0.713725 RG 8 21 m 16 21 l 18.363 21 20 19.215 20 17\n"                                                                                                                                                                 \
2380     "c 20 14 l 20 11.785 18.363 10\n"                                                                                                                                                                                                          \
2381     "16 10 c 13 10 l 8 4 l 8 10 l 8 10 l 5.637 10 4 11.785 4 14 c 4 17 l 4\n"                                                                                                                                                                  \
2382     "19.215 5.637 21 8 21 c h\n"                                                                                                                                                                                                               \
2383     "8 21 m S\n"
2384 
2385 #define ANNOT_TEXT_AP_KEY                                                                                                                                                                                                                      \
2386     "4.301 23 m 19.699 23 l 21.523 23 23 21.523 23 19.699 c 23 4.301 l 23\n"                                                                                                                                                                   \
2387     "2.477 21.523 1 19.699 1 c 4.301 1 l 2.477 1 1 2.477 1 4.301 c 1 19.699\n"                                                                                                                                                                 \
2388     "l 1 21.523 2.477 23 4.301 23 c h\n"                                                                                                                                                                                                       \
2389     "4.301 23 m f\n"                                                                                                                                                                                                                           \
2390     "0.533333 0.541176 0.521569 RG 2 w\n"                                                                                                                                                                                                      \
2391     "1 J\n"                                                                                                                                                                                                                                    \
2392     "0 j\n"                                                                                                                                                                                                                                    \
2393     "[] 0.0 d\n"                                                                                                                                                                                                                               \
2394     "4 M 11.895 18.754 m 13.926 20.625 17.09 20.496 18.961 18.465 c 20.832\n"                                                                                                                                                                  \
2395     "16.434 20.699 13.27 18.668 11.398 c 17.164 10.016 15.043 9.746 13.281\n"                                                                                                                                                                  \
2396     "10.516 c 12.473 9.324 l 11.281 10.078 l 9.547 8.664 l 9.008 6.496 l\n"                                                                                                                                                                    \
2397     "7.059 6.059 l 6.34 4.121 l 5.543 3.668 l 3.375 4.207 l 2.938 6.156 l\n"                                                                                                                                                                   \
2398     "10.57 13.457 l 9.949 15.277 10.391 17.367 11.895 18.754 c h\n"                                                                                                                                                                            \
2399     "11.895 18.754 m S\n"                                                                                                                                                                                                                      \
2400     "1.5 w\n"                                                                                                                                                                                                                                  \
2401     "16.059 15.586 m 16.523 15.078 17.316 15.043 17.824 15.512 c 18.332\n"                                                                                                                                                                     \
2402     "15.98 18.363 16.77 17.895 17.277 c 17.43 17.785 16.637 17.816 16.129\n"                                                                                                                                                                   \
2403     "17.352 c 15.621 16.883 15.59 16.094 16.059 15.586 c h\n"                                                                                                                                                                                  \
2404     "16.059 15.586 m S\n"                                                                                                                                                                                                                      \
2405     "0.729412 0.741176 0.713725 RG 2 w\n"                                                                                                                                                                                                      \
2406     "11.895 19.754 m 13.926 21.625 17.09 21.496 18.961 19.465 c 20.832\n"                                                                                                                                                                      \
2407     "17.434 20.699 14.27 18.668 12.398 c 17.164 11.016 15.043 10.746 13.281\n"                                                                                                                                                                 \
2408     "11.516 c 12.473 10.324 l 11.281 11.078 l 9.547 9.664 l 9.008 7.496 l\n"                                                                                                                                                                   \
2409     "7.059 7.059 l 6.34 5.121 l 5.543 4.668 l 3.375 5.207 l 2.938 7.156 l\n"                                                                                                                                                                   \
2410     "10.57 14.457 l 9.949 16.277 10.391 18.367 11.895 19.754 c h\n"                                                                                                                                                                            \
2411     "11.895 19.754 m S\n"                                                                                                                                                                                                                      \
2412     "1.5 w\n"                                                                                                                                                                                                                                  \
2413     "16.059 16.586 m 16.523 16.078 17.316 16.043 17.824 16.512 c 18.332\n"                                                                                                                                                                     \
2414     "16.98 18.363 17.77 17.895 18.277 c 17.43 18.785 16.637 18.816 16.129\n"                                                                                                                                                                   \
2415     "18.352 c 15.621 17.883 15.59 17.094 16.059 16.586 c h\n"                                                                                                                                                                                  \
2416     "16.059 16.586 m S\n"
2417 
2418 #define ANNOT_TEXT_AP_HELP                                                                                                                                                                                                                     \
2419     "4.301 23 m 19.699 23 l 21.523 23 23 21.523 23 19.699 c 23 4.301 l 23\n"                                                                                                                                                                   \
2420     "2.477 21.523 1 19.699 1 c 4.301 1 l 2.477 1 1 2.477 1 4.301 c 1 19.699\n"                                                                                                                                                                 \
2421     "l 1 21.523 2.477 23 4.301 23 c h\n"                                                                                                                                                                                                       \
2422     "4.301 23 m f\n"                                                                                                                                                                                                                           \
2423     "0.533333 0.541176 0.521569 RG 2.5 w\n"                                                                                                                                                                                                    \
2424     "1 J\n"                                                                                                                                                                                                                                    \
2425     "1 j\n"                                                                                                                                                                                                                                    \
2426     "[] 0.0 d\n"                                                                                                                                                                                                                               \
2427     "4 M 8.289 16.488 m 8.824 17.828 10.043 18.773 11.473 18.965 c 12.902 19.156\n"                                                                                                                                                            \
2428     "14.328 18.559 15.195 17.406 c 16.062 16.254 16.242 14.723 15.664 13.398\n"                                                                                                                                                                \
2429     "c S\n"                                                                                                                                                                                                                                    \
2430     "0 j\n"                                                                                                                                                                                                                                    \
2431     "12 8 m 12 12 16 11 16 15 c S\n"                                                                                                                                                                                                           \
2432     "1.539286 w\n"                                                                                                                                                                                                                             \
2433     "1 j\n"                                                                                                                                                                                                                                    \
2434     "q 1 0 0 -0.999991 0 24 cm\n"                                                                                                                                                                                                              \
2435     "12.684 20.891 m 12.473 21.258 12.004 21.395 11.629 21.196 c 11.254\n"                                                                                                                                                                     \
2436     "20.992 11.105 20.531 11.297 20.149 c 11.488 19.77 11.945 19.61 12.332\n"                                                                                                                                                                  \
2437     "19.789 c 12.719 19.969 12.891 20.426 12.719 20.817 c S Q\n"                                                                                                                                                                               \
2438     "0.729412 0.741176 0.713725 RG 2.5 w\n"                                                                                                                                                                                                    \
2439     "8.289 17.488 m 9.109 19.539 11.438 20.535 13.488 19.711 c 15.539 18.891\n"                                                                                                                                                                \
2440     "16.535 16.562 15.711 14.512 c 15.699 14.473 15.684 14.438 15.664 14.398\n"                                                                                                                                                                \
2441     "c S\n"                                                                                                                                                                                                                                    \
2442     "0 j\n"                                                                                                                                                                                                                                    \
2443     "12 9 m 12 13 16 12 16 16 c S\n"                                                                                                                                                                                                           \
2444     "1.539286 w\n"                                                                                                                                                                                                                             \
2445     "1 j\n"                                                                                                                                                                                                                                    \
2446     "q 1 0 0 -0.999991 0 24 cm\n"                                                                                                                                                                                                              \
2447     "12.684 19.891 m 12.473 20.258 12.004 20.395 11.629 20.195 c 11.254\n"                                                                                                                                                                     \
2448     "19.992 11.105 19.531 11.297 19.149 c 11.488 18.77 11.945 18.61 12.332\n"                                                                                                                                                                  \
2449     "18.789 c 12.719 18.969 12.891 19.426 12.719 19.817 c S Q\n"
2450 
2451 #define ANNOT_TEXT_AP_NEW_PARAGRAPH                                                                                                                                                                                                            \
2452     "4.301 23 m 19.699 23 l 21.523 23 23 21.523 23 19.699 c 23 4.301 l 23\n"                                                                                                                                                                   \
2453     "2.477 21.523 1 19.699 1 c 4.301 1 l 2.477 1 1 2.477 1 4.301 c 1 19.699\n"                                                                                                                                                                 \
2454     "l 1 21.523 2.477 23 4.301 23 c h\n"                                                                                                                                                                                                       \
2455     "4.301 23 m f\n"                                                                                                                                                                                                                           \
2456     "0.533333 0.541176 0.521569 RG 4 w\n"                                                                                                                                                                                                      \
2457     "0 J\n"                                                                                                                                                                                                                                    \
2458     "2 j\n"                                                                                                                                                                                                                                    \
2459     "[] 0.0 d\n"                                                                                                                                                                                                                               \
2460     "4 M q 1 0 0 -1 0 24 cm\n"                                                                                                                                                                                                                 \
2461     "9.211 11.988 m 8.449 12.07 7.711 11.707 7.305 11.059 c 6.898 10.41\n"                                                                                                                                                                     \
2462     "6.898 9.59 7.305 8.941 c 7.711 8.293 8.449 7.93 9.211 8.012 c S Q\n"                                                                                                                                                                      \
2463     "1.004413 w\n"                                                                                                                                                                                                                             \
2464     "1 J\n"                                                                                                                                                                                                                                    \
2465     "1 j\n"                                                                                                                                                                                                                                    \
2466     "q 1 0 0 -0.991232 0 24 cm\n"                                                                                                                                                                                                              \
2467     "18.07 11.511 m 15.113 10.014 l 12.199 11.602 l 12.711 8.323 l 10.301\n"                                                                                                                                                                   \
2468     "6.045 l 13.574 5.517 l 14.996 2.522 l 16.512 5.474 l 19.801 5.899 l\n"                                                                                                                                                                    \
2469     "17.461 8.252 l 18.07 11.511 l h\n"                                                                                                                                                                                                        \
2470     "18.07 11.511 m S Q\n"                                                                                                                                                                                                                     \
2471     "2 w\n"                                                                                                                                                                                                                                    \
2472     "0 j\n"                                                                                                                                                                                                                                    \
2473     "11 17 m 10 17 l 10 3 l S\n"                                                                                                                                                                                                               \
2474     "14 3 m 14 13 l S\n"                                                                                                                                                                                                                       \
2475     "0.729412 0.741176 0.713725 RG 4 w\n"                                                                                                                                                                                                      \
2476     "0 J\n"                                                                                                                                                                                                                                    \
2477     "2 j\n"                                                                                                                                                                                                                                    \
2478     "q 1 0 0 -1 0 24 cm\n"                                                                                                                                                                                                                     \
2479     "9.211 10.988 m 8.109 11.105 7.125 10.309 7.012 9.211 c 6.895 8.109\n"                                                                                                                                                                     \
2480     "7.691 7.125 8.789 7.012 c 8.93 6.996 9.07 6.996 9.211 7.012 c S Q\n"                                                                                                                                                                      \
2481     "1.004413 w\n"                                                                                                                                                                                                                             \
2482     "1 J\n"                                                                                                                                                                                                                                    \
2483     "1 j\n"                                                                                                                                                                                                                                    \
2484     "q 1 0 0 -0.991232 0 24 cm\n"                                                                                                                                                                                                              \
2485     "18.07 10.502 m 15.113 9.005 l 12.199 10.593 l 12.711 7.314 l 10.301\n"                                                                                                                                                                    \
2486     "5.036 l 13.574 4.508 l 14.996 1.513 l 16.512 4.465 l 19.801 4.891 l\n"                                                                                                                                                                    \
2487     "17.461 7.243 l 18.07 10.502 l h\n"                                                                                                                                                                                                        \
2488     "18.07 10.502 m S Q\n"                                                                                                                                                                                                                     \
2489     "2 w\n"                                                                                                                                                                                                                                    \
2490     "0 j\n"                                                                                                                                                                                                                                    \
2491     "11 18 m 10 18 l 10 4 l S\n"                                                                                                                                                                                                               \
2492     "14 4 m 14 14 l S\n"
2493 
2494 #define ANNOT_TEXT_AP_PARAGRAPH                                                                                                                                                                                                                \
2495     "4.301 23 m 19.699 23 l 21.523 23 23 21.523 23 19.699 c 23 4.301 l 23\n"                                                                                                                                                                   \
2496     "2.477 21.523 1 19.699 1 c 4.301 1 l 2.477 1 1 2.477 1 4.301 c 1 19.699\n"                                                                                                                                                                 \
2497     "l 1 21.523 2.477 23 4.301 23 c h\n"                                                                                                                                                                                                       \
2498     "4.301 23 m f\n"                                                                                                                                                                                                                           \
2499     "0.533333 0.541176 0.521569 RG 2 w\n"                                                                                                                                                                                                      \
2500     "1 J\n"                                                                                                                                                                                                                                    \
2501     "1 j\n"                                                                                                                                                                                                                                    \
2502     "[] 0.0 d\n"                                                                                                                                                                                                                               \
2503     "4 M 15 3 m 15 18 l 11 18 l 11 3 l S\n"                                                                                                                                                                                                    \
2504     "4 w\n"                                                                                                                                                                                                                                    \
2505     "q 1 0 0 -1 0 24 cm\n"                                                                                                                                                                                                                     \
2506     "9.777 10.988 m 8.746 10.871 7.973 9.988 8 8.949 c 8.027 7.91 8.844\n"                                                                                                                                                                     \
2507     "7.066 9.879 7.004 c S Q\n"                                                                                                                                                                                                                \
2508     "0.729412 0.741176 0.713725 RG 2 w\n"                                                                                                                                                                                                      \
2509     "15 4 m 15 19 l 11 19 l 11 4 l S\n"                                                                                                                                                                                                        \
2510     "4 w\n"                                                                                                                                                                                                                                    \
2511     "q 1 0 0 -1 0 24 cm\n"                                                                                                                                                                                                                     \
2512     "9.777 9.988 m 8.746 9.871 7.973 8.988 8 7.949 c 8.027 6.91 8.844 6.066\n"                                                                                                                                                                 \
2513     "9.879 6.004 c S Q\n"
2514 
2515 #define ANNOT_TEXT_AP_INSERT                                                                                                                                                                                                                   \
2516     "4.301 23 m 19.699 23 l 21.523 23 23 21.523 23 19.699 c 23 4.301 l 23\n"                                                                                                                                                                   \
2517     "2.477 21.523 1 19.699 1 c 4.301 1 l 2.477 1 1 2.477 1 4.301 c 1 19.699\n"                                                                                                                                                                 \
2518     "l 1 21.523 2.477 23 4.301 23 c h\n"                                                                                                                                                                                                       \
2519     "4.301 23 m f\n"                                                                                                                                                                                                                           \
2520     "0.533333 0.541176 0.521569 RG 2 w\n"                                                                                                                                                                                                      \
2521     "1 J\n"                                                                                                                                                                                                                                    \
2522     "0 j\n"                                                                                                                                                                                                                                    \
2523     "[] 0.0 d\n"                                                                                                                                                                                                                               \
2524     "4 M 12 18.012 m 20 18 l S\n"                                                                                                                                                                                                              \
2525     "9 10 m 17 10 l S\n"                                                                                                                                                                                                                       \
2526     "12 14.012 m 20 14 l S\n"                                                                                                                                                                                                                  \
2527     "12 6.012 m 20 6.012 l S\n"                                                                                                                                                                                                                \
2528     "4 12 m 6 10 l 4 8 l S\n"                                                                                                                                                                                                                  \
2529     "4 12 m 4 8 l S\n"                                                                                                                                                                                                                         \
2530     "0.729412 0.741176 0.713725 RG 12 19.012 m 20 19 l S\n"                                                                                                                                                                                    \
2531     "9 11 m 17 11 l S\n"                                                                                                                                                                                                                       \
2532     "12 15.012 m 20 15 l S\n"                                                                                                                                                                                                                  \
2533     "12 7.012 m 20 7.012 l S\n"                                                                                                                                                                                                                \
2534     "4 13 m 6 11 l 4 9 l S\n"                                                                                                                                                                                                                  \
2535     "4 13 m 4 9 l S\n"
2536 
2537 #define ANNOT_TEXT_AP_CROSS                                                                                                                                                                                                                    \
2538     "4.301 23 m 19.699 23 l 21.523 23 23 21.523 23 19.699 c 23 4.301 l 23\n"                                                                                                                                                                   \
2539     "2.477 21.523 1 19.699 1 c 4.301 1 l 2.477 1 1 2.477 1 4.301 c 1 19.699\n"                                                                                                                                                                 \
2540     "l 1 21.523 2.477 23 4.301 23 c h\n"                                                                                                                                                                                                       \
2541     "4.301 23 m f\n"                                                                                                                                                                                                                           \
2542     "0.533333 0.541176 0.521569 RG 2.5 w\n"                                                                                                                                                                                                    \
2543     "1 J\n"                                                                                                                                                                                                                                    \
2544     "0 j\n"                                                                                                                                                                                                                                    \
2545     "[] 0.0 d\n"                                                                                                                                                                                                                               \
2546     "4 M 18 5 m 6 17 l S\n"                                                                                                                                                                                                                    \
2547     "6 5 m 18 17 l S\n"                                                                                                                                                                                                                        \
2548     "0.729412 0.741176 0.713725 RG 18 6 m 6 18 l S\n"                                                                                                                                                                                          \
2549     "6 6 m 18 18 l S\n"
2550 
2551 #define ANNOT_TEXT_AP_CIRCLE                                                                                                                                                                                                                   \
2552     "4.301 23 m 19.699 23 l 21.523 23 23 21.523 23 19.699 c 23 4.301 l 23\n"                                                                                                                                                                   \
2553     "2.477 21.523 1 19.699 1 c 4.301 1 l 2.477 1 1 2.477 1 4.301 c 1 19.699\n"                                                                                                                                                                 \
2554     "l 1 21.523 2.477 23 4.301 23 c h\n"                                                                                                                                                                                                       \
2555     "4.301 23 m f\n"                                                                                                                                                                                                                           \
2556     "0.533333 0.541176 0.521569 RG 2.5 w\n"                                                                                                                                                                                                    \
2557     "1 J\n"                                                                                                                                                                                                                                    \
2558     "1 j\n"                                                                                                                                                                                                                                    \
2559     "[] 0.0 d\n"                                                                                                                                                                                                                               \
2560     "4 M 19.5 11.5 m 19.5 7.359 16.141 4 12 4 c 7.859 4 4.5 7.359 4.5 11.5 c 4.5\n"                                                                                                                                                            \
2561     "15.641 7.859 19 12 19 c 16.141 19 19.5 15.641 19.5 11.5 c h\n"                                                                                                                                                                            \
2562     "19.5 11.5 m S\n"                                                                                                                                                                                                                          \
2563     "0.729412 0.741176 0.713725 RG 19.5 12.5 m 19.5 8.359 16.141 5 12 5 c\n"                                                                                                                                                                   \
2564     "7.859 5 4.5 8.359 4.5 12.5 c 4.5\n"                                                                                                                                                                                                       \
2565     "16.641 7.859 20 12 20 c 16.141 20 19.5 16.641 19.5 12.5 c h\n"                                                                                                                                                                            \
2566     "19.5 12.5 m S\n"
2567 
draw(Gfx * gfx,bool printing)2568 void AnnotText::draw(Gfx *gfx, bool printing)
2569 {
2570     double ca = 1;
2571 
2572     if (!isVisible(printing))
2573         return;
2574 
2575     annotLocker();
2576     if (appearance.isNull()) {
2577         ca = opacity;
2578 
2579         AnnotAppearanceBuilder appearBuilder;
2580 
2581         appearBuilder.append("q\n");
2582         if (color)
2583             appearBuilder.setDrawColor(color.get(), true);
2584         else
2585             appearBuilder.append("1 1 1 rg\n");
2586         if (!icon->cmp("Note"))
2587             appearBuilder.append(ANNOT_TEXT_AP_NOTE);
2588         else if (!icon->cmp("Comment"))
2589             appearBuilder.append(ANNOT_TEXT_AP_COMMENT);
2590         else if (!icon->cmp("Key"))
2591             appearBuilder.append(ANNOT_TEXT_AP_KEY);
2592         else if (!icon->cmp("Help"))
2593             appearBuilder.append(ANNOT_TEXT_AP_HELP);
2594         else if (!icon->cmp("NewParagraph"))
2595             appearBuilder.append(ANNOT_TEXT_AP_NEW_PARAGRAPH);
2596         else if (!icon->cmp("Paragraph"))
2597             appearBuilder.append(ANNOT_TEXT_AP_PARAGRAPH);
2598         else if (!icon->cmp("Insert"))
2599             appearBuilder.append(ANNOT_TEXT_AP_INSERT);
2600         else if (!icon->cmp("Cross"))
2601             appearBuilder.append(ANNOT_TEXT_AP_CROSS);
2602         else if (!icon->cmp("Circle"))
2603             appearBuilder.append(ANNOT_TEXT_AP_CIRCLE);
2604         appearBuilder.append("Q\n");
2605 
2606         // Force 24x24 rectangle
2607         PDFRectangle fixedRect(rect->x1, rect->y2 - 24, rect->x1 + 24, rect->y2);
2608         appearBBox = std::make_unique<AnnotAppearanceBBox>(&fixedRect);
2609         double bbox[4];
2610         appearBBox->getBBoxRect(bbox);
2611         if (ca == 1) {
2612             appearance = createForm(appearBuilder.buffer(), bbox, false, nullptr);
2613         } else {
2614             Object aStream = createForm(appearBuilder.buffer(), bbox, true, nullptr);
2615 
2616             GooString appearBuf("/GS0 gs\n/Fm0 Do");
2617             Dict *resDict = createResourcesDict("Fm0", std::move(aStream), "GS0", ca, nullptr);
2618             appearance = createForm(&appearBuf, bbox, false, resDict);
2619         }
2620     }
2621 
2622     // draw the appearance stream
2623     Object obj = appearance.fetch(gfx->getXRef());
2624     if (appearBBox) {
2625         gfx->drawAnnot(&obj, nullptr, color.get(), appearBBox->getPageXMin(), appearBBox->getPageYMin(), appearBBox->getPageXMax(), appearBBox->getPageYMax(), getRotation());
2626     } else {
2627         gfx->drawAnnot(&obj, nullptr, color.get(), rect->x1, rect->y1, rect->x2, rect->y2, getRotation());
2628     }
2629 }
2630 
2631 //------------------------------------------------------------------------
2632 // AnnotLink
2633 //------------------------------------------------------------------------
AnnotLink(PDFDoc * docA,PDFRectangle * rectA)2634 AnnotLink::AnnotLink(PDFDoc *docA, PDFRectangle *rectA) : Annot(docA, rectA)
2635 {
2636     type = typeLink;
2637     annotObj.dictSet("Subtype", Object(objName, "Link"));
2638     initialize(docA, annotObj.getDict());
2639 }
2640 
AnnotLink(PDFDoc * docA,Object && dictObject,const Object * obj)2641 AnnotLink::AnnotLink(PDFDoc *docA, Object &&dictObject, const Object *obj) : Annot(docA, std::move(dictObject), obj)
2642 {
2643 
2644     type = typeLink;
2645     initialize(docA, annotObj.getDict());
2646 }
2647 
2648 AnnotLink::~AnnotLink() = default;
2649 
initialize(PDFDoc * docA,Dict * dict)2650 void AnnotLink::initialize(PDFDoc *docA, Dict *dict)
2651 {
2652     Object obj1;
2653 
2654     // look for destination
2655     obj1 = dict->lookup("Dest");
2656     if (!obj1.isNull()) {
2657         action = LinkAction::parseDest(&obj1);
2658         // look for action
2659     } else {
2660         obj1 = dict->lookup("A");
2661         if (obj1.isDict()) {
2662             action = LinkAction::parseAction(&obj1, doc->getCatalog()->getBaseURI());
2663         }
2664     }
2665 
2666     obj1 = dict->lookup("H");
2667     if (obj1.isName()) {
2668         const char *effect = obj1.getName();
2669 
2670         if (!strcmp(effect, "N")) {
2671             linkEffect = effectNone;
2672         } else if (!strcmp(effect, "I")) {
2673             linkEffect = effectInvert;
2674         } else if (!strcmp(effect, "O")) {
2675             linkEffect = effectOutline;
2676         } else if (!strcmp(effect, "P")) {
2677             linkEffect = effectPush;
2678         } else {
2679             linkEffect = effectInvert;
2680         }
2681     } else {
2682         linkEffect = effectInvert;
2683     }
2684     /*
2685     obj1 = dict->lookup("PA");
2686     if (obj1.isDict()) {
2687       uriAction = NULL;
2688     } else {
2689       uriAction = NULL;
2690     }
2691     obj1.free();
2692     */
2693     obj1 = dict->lookup("QuadPoints");
2694     if (obj1.isArray()) {
2695         quadrilaterals = std::make_unique<AnnotQuadrilaterals>(obj1.getArray(), rect.get());
2696     }
2697 
2698     obj1 = dict->lookup("BS");
2699     if (obj1.isDict()) {
2700         border = std::make_unique<AnnotBorderBS>(obj1.getDict());
2701     } else if (!border) {
2702         border = std::make_unique<AnnotBorderBS>();
2703     }
2704 }
2705 
draw(Gfx * gfx,bool printing)2706 void AnnotLink::draw(Gfx *gfx, bool printing)
2707 {
2708     if (!isVisible(printing))
2709         return;
2710 
2711     annotLocker();
2712     // draw the appearance stream
2713     Object obj = appearance.fetch(gfx->getXRef());
2714     gfx->drawAnnot(&obj, border.get(), color.get(), rect->x1, rect->y1, rect->x2, rect->y2, getRotation());
2715 }
2716 
2717 //------------------------------------------------------------------------
2718 // AnnotFreeText
2719 //------------------------------------------------------------------------
2720 const double AnnotFreeText::undefinedFontPtSize = 10.;
2721 
AnnotFreeText(PDFDoc * docA,PDFRectangle * rectA,const DefaultAppearance & da)2722 AnnotFreeText::AnnotFreeText(PDFDoc *docA, PDFRectangle *rectA, const DefaultAppearance &da) : AnnotMarkup(docA, rectA)
2723 {
2724     type = typeFreeText;
2725 
2726     GooString *daStr = da.toAppearanceString();
2727     annotObj.dictSet("Subtype", Object(objName, "FreeText"));
2728     annotObj.dictSet("DA", Object(daStr));
2729 
2730     initialize(docA, annotObj.getDict());
2731 }
2732 
AnnotFreeText(PDFDoc * docA,Object && dictObject,const Object * obj)2733 AnnotFreeText::AnnotFreeText(PDFDoc *docA, Object &&dictObject, const Object *obj) : AnnotMarkup(docA, std::move(dictObject), obj)
2734 {
2735     type = typeFreeText;
2736     initialize(docA, annotObj.getDict());
2737 }
2738 
2739 AnnotFreeText::~AnnotFreeText() = default;
2740 
initialize(PDFDoc * docA,Dict * dict)2741 void AnnotFreeText::initialize(PDFDoc *docA, Dict *dict)
2742 {
2743     Object obj1;
2744 
2745     obj1 = dict->lookup("DA");
2746     if (obj1.isString()) {
2747         appearanceString.reset(obj1.getString()->copy());
2748     } else {
2749         appearanceString = std::make_unique<GooString>();
2750         error(errSyntaxWarning, -1, "Bad appearance for annotation");
2751     }
2752 
2753     obj1 = dict->lookup("Q");
2754     if (obj1.isInt()) {
2755         quadding = (AnnotFreeTextQuadding)obj1.getInt();
2756     } else {
2757         quadding = quaddingLeftJustified;
2758     }
2759 
2760     obj1 = dict->lookup("DS");
2761     if (obj1.isString()) {
2762         styleString.reset(obj1.getString()->copy());
2763     }
2764 
2765     obj1 = dict->lookup("CL");
2766     if (obj1.isArray() && obj1.arrayGetLength() >= 4) {
2767         const double x1 = obj1.arrayGet(0).getNumWithDefaultValue(0);
2768         const double y1 = obj1.arrayGet(1).getNumWithDefaultValue(0);
2769         const double x2 = obj1.arrayGet(2).getNumWithDefaultValue(0);
2770         const double y2 = obj1.arrayGet(3).getNumWithDefaultValue(0);
2771 
2772         if (obj1.arrayGetLength() == 6) {
2773             const double x3 = obj1.arrayGet(4).getNumWithDefaultValue(0);
2774             const double y3 = obj1.arrayGet(5).getNumWithDefaultValue(0);
2775             calloutLine = std::make_unique<AnnotCalloutMultiLine>(x1, y1, x2, y2, x3, y3);
2776         } else {
2777             calloutLine = std::make_unique<AnnotCalloutLine>(x1, y1, x2, y2);
2778         }
2779     }
2780 
2781     obj1 = dict->lookup("IT");
2782     if (obj1.isName()) {
2783         const char *intentName = obj1.getName();
2784 
2785         if (!strcmp(intentName, "FreeText")) {
2786             intent = intentFreeText;
2787         } else if (!strcmp(intentName, "FreeTextCallout")) {
2788             intent = intentFreeTextCallout;
2789         } else if (!strcmp(intentName, "FreeTextTypeWriter")) {
2790             intent = intentFreeTextTypeWriter;
2791         } else {
2792             intent = intentFreeText;
2793         }
2794     } else {
2795         intent = intentFreeText;
2796     }
2797 
2798     obj1 = dict->lookup("BS");
2799     if (obj1.isDict()) {
2800         border = std::make_unique<AnnotBorderBS>(obj1.getDict());
2801     } else if (!border) {
2802         border = std::make_unique<AnnotBorderBS>();
2803     }
2804 
2805     obj1 = dict->lookup("BE");
2806     if (obj1.isDict()) {
2807         borderEffect = std::make_unique<AnnotBorderEffect>(obj1.getDict());
2808     }
2809 
2810     obj1 = dict->lookup("RD");
2811     if (obj1.isArray()) {
2812         rectangle = parseDiffRectangle(obj1.getArray(), rect.get());
2813     }
2814 
2815     obj1 = dict->lookup("LE");
2816     if (obj1.isName()) {
2817         GooString styleName(obj1.getName());
2818         endStyle = parseAnnotLineEndingStyle(&styleName);
2819     } else {
2820         endStyle = annotLineEndingNone;
2821     }
2822 }
2823 
setContents(GooString * new_content)2824 void AnnotFreeText::setContents(GooString *new_content)
2825 {
2826     Annot::setContents(new_content);
2827     invalidateAppearance();
2828 }
2829 
setDefaultAppearance(const DefaultAppearance & da)2830 void AnnotFreeText::setDefaultAppearance(const DefaultAppearance &da)
2831 {
2832     appearanceString = std::unique_ptr<GooString>(da.toAppearanceString());
2833 
2834     update("DA", Object(appearanceString->copy()));
2835     invalidateAppearance();
2836 }
2837 
setQuadding(AnnotFreeTextQuadding new_quadding)2838 void AnnotFreeText::setQuadding(AnnotFreeTextQuadding new_quadding)
2839 {
2840     quadding = new_quadding;
2841     update("Q", Object((int)quadding));
2842     invalidateAppearance();
2843 }
2844 
setStyleString(GooString * new_string)2845 void AnnotFreeText::setStyleString(GooString *new_string)
2846 {
2847     if (new_string) {
2848         styleString = std::make_unique<GooString>(new_string);
2849         // append the unicode marker <FE FF> if needed
2850         if (!styleString->hasUnicodeMarker()) {
2851             styleString->prependUnicodeMarker();
2852         }
2853     } else {
2854         styleString = std::make_unique<GooString>();
2855     }
2856 
2857     update("DS", Object(styleString->copy()));
2858 }
2859 
setCalloutLine(AnnotCalloutLine * line)2860 void AnnotFreeText::setCalloutLine(AnnotCalloutLine *line)
2861 {
2862     Object obj1;
2863     if (line == nullptr) {
2864         obj1.setToNull();
2865         calloutLine = nullptr;
2866     } else {
2867         double x1 = line->getX1(), y1 = line->getY1();
2868         double x2 = line->getX2(), y2 = line->getY2();
2869         obj1 = Object(new Array(doc->getXRef()));
2870         obj1.arrayAdd(Object(x1));
2871         obj1.arrayAdd(Object(y1));
2872         obj1.arrayAdd(Object(x2));
2873         obj1.arrayAdd(Object(y2));
2874 
2875         AnnotCalloutMultiLine *mline = dynamic_cast<AnnotCalloutMultiLine *>(line);
2876         if (mline) {
2877             double x3 = mline->getX3(), y3 = mline->getY3();
2878             obj1.arrayAdd(Object(x3));
2879             obj1.arrayAdd(Object(y3));
2880             calloutLine = std::make_unique<AnnotCalloutMultiLine>(x1, y1, x2, y2, x3, y3);
2881         } else {
2882             calloutLine = std::make_unique<AnnotCalloutLine>(x1, y1, x2, y2);
2883         }
2884     }
2885 
2886     update("CL", std::move(obj1));
2887     invalidateAppearance();
2888 }
2889 
setIntent(AnnotFreeTextIntent new_intent)2890 void AnnotFreeText::setIntent(AnnotFreeTextIntent new_intent)
2891 {
2892     const char *intentName;
2893 
2894     intent = new_intent;
2895     if (new_intent == intentFreeText)
2896         intentName = "FreeText";
2897     else if (new_intent == intentFreeTextCallout)
2898         intentName = "FreeTextCallout";
2899     else // intentFreeTextTypeWriter
2900         intentName = "FreeTextTypeWriter";
2901     update("IT", Object(objName, intentName));
2902 }
2903 
getDefaultAppearance() const2904 std::unique_ptr<DefaultAppearance> AnnotFreeText::getDefaultAppearance() const
2905 {
2906     return std::make_unique<DefaultAppearance>(appearanceString.get());
2907 }
2908 
createAnnotDrawFont(XRef * xref,Dict * fontParentDict,const char * resourceName="AnnotDrawFont",const char * fontname="Helvetica")2909 static GfxFont *createAnnotDrawFont(XRef *xref, Dict *fontParentDict, const char *resourceName = "AnnotDrawFont", const char *fontname = "Helvetica")
2910 {
2911     const Ref dummyRef = { -1, -1 };
2912 
2913     Dict *fontDict = new Dict(xref);
2914     fontDict->add("BaseFont", Object(objName, fontname));
2915     fontDict->add("Subtype", Object(objName, "Type1"));
2916     if (strcmp(fontname, "ZapfDingbats") && strcmp(fontname, "Symbol")) {
2917         fontDict->add("Encoding", Object(objName, "WinAnsiEncoding"));
2918     }
2919 
2920     Object fontsDictObj = fontParentDict->lookup("Font");
2921     if (!fontsDictObj.isDict()) {
2922         fontsDictObj = Object(new Dict(xref));
2923         fontParentDict->add("Font", fontsDictObj.copy()); // This is not a copy it's a ref
2924     }
2925 
2926     fontsDictObj.dictSet(resourceName, Object(fontDict));
2927 
2928     return GfxFont::makeFont(xref, resourceName, dummyRef, fontDict);
2929 }
2930 
generateFreeTextAppearance()2931 void AnnotFreeText::generateFreeTextAppearance()
2932 {
2933     double borderWidth, ca = opacity;
2934 
2935     AnnotAppearanceBuilder appearBuilder;
2936     appearBuilder.append("q\n");
2937 
2938     borderWidth = border->getWidth();
2939     if (borderWidth > 0)
2940         appearBuilder.setLineStyleForBorder(border.get());
2941 
2942     // Box size
2943     const double width = rect->x2 - rect->x1;
2944     const double height = rect->y2 - rect->y1;
2945 
2946     // Parse some properties from the appearance string
2947     DefaultAppearance da { appearanceString.get() };
2948 
2949     // Default values
2950     if (!da.getFontName().isName())
2951         da.setFontName(Object(objName, "AnnotDrawFont"));
2952     if (da.getFontPtSize() <= 0)
2953         da.setFontPtSize(undefinedFontPtSize);
2954     if (!da.getFontColor())
2955         da.setFontColor(std::make_unique<AnnotColor>(0, 0, 0));
2956     if (!contents)
2957         contents = std::make_unique<GooString>();
2958 
2959     // Draw box
2960     bool doFill = (color && color->getSpace() != AnnotColor::colorTransparent);
2961     bool doStroke = (borderWidth != 0);
2962     if (doFill || doStroke) {
2963         if (doStroke) {
2964             appearBuilder.setDrawColor(da.getFontColor(), false); // Border color: same as font color
2965         }
2966         appearBuilder.appendf("{0:.2f} {0:.2f} {1:.2f} {2:.2f} re\n", borderWidth / 2, width - borderWidth, height - borderWidth);
2967         if (doFill) {
2968             appearBuilder.setDrawColor(color.get(), true);
2969             appearBuilder.append(doStroke ? "B\n" : "f\n");
2970         } else {
2971             appearBuilder.append("S\n");
2972         }
2973     }
2974 
2975     // Setup text clipping
2976     const double textmargin = borderWidth * 2;
2977     const double textwidth = width - 2 * textmargin;
2978     appearBuilder.appendf("{0:.2f} {0:.2f} {1:.2f} {2:.2f} re W n\n", textmargin, textwidth, height - 2 * textmargin);
2979 
2980     GfxFont *font = nullptr;
2981 
2982     // look for font name in the default resources
2983     Form *form = doc->getCatalog()->getForm(); // form is owned by catalog, no need to clean it up
2984 
2985     Object resourceObj;
2986     if (form && form->getDefaultResourcesObj() && form->getDefaultResourcesObj()->isDict()) {
2987         resourceObj = form->getDefaultResourcesObj()->copy(); // No real copy, but increment refcount of /DR Dict
2988 
2989         Dict *resDict = resourceObj.getDict();
2990         Object fontResources = resDict->lookup("Font"); // The 'Font' subdictionary
2991 
2992         if (!fontResources.isDict()) {
2993             error(errSyntaxWarning, -1, "Font subdictionary is not a dictionary");
2994         } else {
2995             // Get the font dictionary for the actual requested font
2996             Ref fontReference;
2997             Object fontDictionary = fontResources.getDict()->lookup(da.getFontName().getName(), &fontReference);
2998 
2999             if (fontDictionary.isDict()) {
3000                 font = GfxFont::makeFont(doc->getXRef(), da.getFontName().getName(), fontReference, fontDictionary.getDict());
3001             } else {
3002                 error(errSyntaxWarning, -1, "Font dictionary is not a dictionary");
3003             }
3004         }
3005     }
3006 
3007     // if fontname is not in the default resources, create a Helvetica fake font
3008     if (!font) {
3009         Dict *fontResDict = new Dict(doc->getXRef());
3010         resourceObj = Object(fontResDict);
3011         font = createAnnotDrawFont(doc->getXRef(), fontResDict, da.getFontName().getName());
3012     }
3013 
3014     // Set font state
3015     appearBuilder.setDrawColor(da.getFontColor(), true);
3016     appearBuilder.appendf("BT 1 0 0 1 {0:.2f} {1:.2f} Tm\n", textmargin, height - textmargin - da.getFontPtSize() * font->getDescent());
3017     appearBuilder.setTextFont(da.getFontName(), da.getFontPtSize());
3018 
3019     int i = 0;
3020     double xposPrev = 0;
3021     while (i < contents->getLength()) {
3022         GooString out;
3023         double linewidth, xpos;
3024         layoutText(contents.get(), &out, &i, font, &linewidth, textwidth / da.getFontPtSize(), nullptr, false);
3025         linewidth *= da.getFontPtSize();
3026         switch (quadding) {
3027         case quaddingCentered:
3028             xpos = (textwidth - linewidth) / 2;
3029             break;
3030         case quaddingRightJustified:
3031             xpos = textwidth - linewidth;
3032             break;
3033         default: // quaddingLeftJustified:
3034             xpos = 0;
3035             break;
3036         }
3037         appearBuilder.appendf("{0:.2f} {1:.2f} Td\n", xpos - xposPrev, -da.getFontPtSize());
3038         appearBuilder.writeString(out);
3039         appearBuilder.append("Tj\n");
3040         xposPrev = xpos;
3041     }
3042 
3043     font->decRefCnt();
3044     appearBuilder.append("ET Q\n");
3045 
3046     double bbox[4];
3047     bbox[0] = bbox[1] = 0;
3048     bbox[2] = rect->x2 - rect->x1;
3049     bbox[3] = rect->y2 - rect->y1;
3050 
3051     if (ca == 1) {
3052         appearance = createForm(appearBuilder.buffer(), bbox, false, std::move(resourceObj));
3053     } else {
3054         Object aStream = createForm(appearBuilder.buffer(), bbox, true, std::move(resourceObj));
3055 
3056         GooString appearBuf("/GS0 gs\n/Fm0 Do");
3057         Dict *resDict = createResourcesDict("Fm0", std::move(aStream), "GS0", ca, nullptr);
3058         appearance = createForm(&appearBuf, bbox, false, resDict);
3059     }
3060 }
3061 
draw(Gfx * gfx,bool printing)3062 void AnnotFreeText::draw(Gfx *gfx, bool printing)
3063 {
3064     if (!isVisible(printing))
3065         return;
3066 
3067     annotLocker();
3068     if (appearance.isNull()) {
3069         generateFreeTextAppearance();
3070     }
3071 
3072     // draw the appearance stream
3073     Object obj = appearance.fetch(gfx->getXRef());
3074     gfx->drawAnnot(&obj, nullptr, color.get(), rect->x1, rect->y1, rect->x2, rect->y2, getRotation());
3075 }
3076 
3077 // Before retrieving the res dict, regenerate the appearance stream if needed,
3078 // because AnnotFreeText::draw needs to store font info in the res dict
getAppearanceResDict()3079 Object AnnotFreeText::getAppearanceResDict()
3080 {
3081     if (appearance.isNull()) {
3082         generateFreeTextAppearance();
3083     }
3084     return Annot::getAppearanceResDict();
3085 }
3086 
3087 //------------------------------------------------------------------------
3088 // AnnotLine
3089 //------------------------------------------------------------------------
3090 
AnnotLine(PDFDoc * docA,PDFRectangle * rectA)3091 AnnotLine::AnnotLine(PDFDoc *docA, PDFRectangle *rectA) : AnnotMarkup(docA, rectA)
3092 {
3093     type = typeLine;
3094     annotObj.dictSet("Subtype", Object(objName, "Line"));
3095 
3096     initialize(docA, annotObj.getDict());
3097 }
3098 
AnnotLine(PDFDoc * docA,Object && dictObject,const Object * obj)3099 AnnotLine::AnnotLine(PDFDoc *docA, Object &&dictObject, const Object *obj) : AnnotMarkup(docA, std::move(dictObject), obj)
3100 {
3101     type = typeLine;
3102     initialize(docA, annotObj.getDict());
3103 }
3104 
3105 AnnotLine::~AnnotLine() = default;
3106 
initialize(PDFDoc * docA,Dict * dict)3107 void AnnotLine::initialize(PDFDoc *docA, Dict *dict)
3108 {
3109     Object obj1;
3110 
3111     obj1 = dict->lookup("L");
3112     if (obj1.isArray() && obj1.arrayGetLength() == 4) {
3113         const double x1 = obj1.arrayGet(0).getNumWithDefaultValue(0);
3114         const double y1 = obj1.arrayGet(1).getNumWithDefaultValue(0);
3115         const double x2 = obj1.arrayGet(2).getNumWithDefaultValue(0);
3116         const double y2 = obj1.arrayGet(3).getNumWithDefaultValue(0);
3117 
3118         coord1 = std::make_unique<AnnotCoord>(x1, y1);
3119         coord2 = std::make_unique<AnnotCoord>(x2, y2);
3120     } else {
3121         coord1 = std::make_unique<AnnotCoord>();
3122         coord2 = std::make_unique<AnnotCoord>();
3123     }
3124 
3125     obj1 = dict->lookup("LE");
3126     if (obj1.isArray() && obj1.arrayGetLength() == 2) {
3127         Object obj2;
3128 
3129         obj2 = obj1.arrayGet(0);
3130         if (obj2.isName()) {
3131             GooString leName(obj2.getName());
3132             startStyle = parseAnnotLineEndingStyle(&leName);
3133         } else {
3134             startStyle = annotLineEndingNone;
3135         }
3136 
3137         obj2 = obj1.arrayGet(1);
3138         if (obj2.isName()) {
3139             GooString leName(obj2.getName());
3140             endStyle = parseAnnotLineEndingStyle(&leName);
3141         } else {
3142             endStyle = annotLineEndingNone;
3143         }
3144 
3145     } else {
3146         startStyle = endStyle = annotLineEndingNone;
3147     }
3148 
3149     obj1 = dict->lookup("IC");
3150     if (obj1.isArray()) {
3151         interiorColor = std::make_unique<AnnotColor>(obj1.getArray());
3152     }
3153 
3154     leaderLineLength = dict->lookup("LL").getNumWithDefaultValue(0);
3155 
3156     leaderLineExtension = dict->lookup("LLE").getNumWithDefaultValue(0);
3157     if (leaderLineExtension < 0)
3158         leaderLineExtension = 0;
3159 
3160     caption = dict->lookup("Cap").getBoolWithDefaultValue(false);
3161 
3162     obj1 = dict->lookup("IT");
3163     if (obj1.isName()) {
3164         const char *intentName = obj1.getName();
3165 
3166         if (!strcmp(intentName, "LineArrow")) {
3167             intent = intentLineArrow;
3168         } else if (!strcmp(intentName, "LineDimension")) {
3169             intent = intentLineDimension;
3170         } else {
3171             intent = intentLineArrow;
3172         }
3173     } else {
3174         intent = intentLineArrow;
3175     }
3176 
3177     leaderLineOffset = dict->lookup("LLO").getNumWithDefaultValue(0);
3178     if (leaderLineOffset < 0)
3179         leaderLineOffset = 0;
3180 
3181     obj1 = dict->lookup("CP");
3182     if (obj1.isName()) {
3183         const char *captionName = obj1.getName();
3184 
3185         if (!strcmp(captionName, "Inline")) {
3186             captionPos = captionPosInline;
3187         } else if (!strcmp(captionName, "Top")) {
3188             captionPos = captionPosTop;
3189         } else {
3190             captionPos = captionPosInline;
3191         }
3192     } else {
3193         captionPos = captionPosInline;
3194     }
3195 
3196     obj1 = dict->lookup("Measure");
3197     if (obj1.isDict()) {
3198         measure = nullptr;
3199     } else {
3200         measure = nullptr;
3201     }
3202 
3203     obj1 = dict->lookup("CO");
3204     if (obj1.isArray() && (obj1.arrayGetLength() == 2)) {
3205         captionTextHorizontal = obj1.arrayGet(0).getNumWithDefaultValue(0);
3206         captionTextVertical = obj1.arrayGet(1).getNumWithDefaultValue(0);
3207     } else {
3208         captionTextHorizontal = captionTextVertical = 0;
3209     }
3210 
3211     obj1 = dict->lookup("BS");
3212     if (obj1.isDict()) {
3213         border = std::make_unique<AnnotBorderBS>(obj1.getDict());
3214     } else if (!border) {
3215         border = std::make_unique<AnnotBorderBS>();
3216     }
3217 }
3218 
setContents(GooString * new_content)3219 void AnnotLine::setContents(GooString *new_content)
3220 {
3221     Annot::setContents(new_content);
3222     if (caption)
3223         invalidateAppearance();
3224 }
3225 
setVertices(double x1,double y1,double x2,double y2)3226 void AnnotLine::setVertices(double x1, double y1, double x2, double y2)
3227 {
3228     coord1 = std::make_unique<AnnotCoord>(x1, y1);
3229     coord2 = std::make_unique<AnnotCoord>(x2, y2);
3230 
3231     Array *lArray = new Array(doc->getXRef());
3232     lArray->add(Object(x1));
3233     lArray->add(Object(y1));
3234     lArray->add(Object(x2));
3235     lArray->add(Object(y2));
3236 
3237     update("L", Object(lArray));
3238     invalidateAppearance();
3239 }
3240 
setStartEndStyle(AnnotLineEndingStyle start,AnnotLineEndingStyle end)3241 void AnnotLine::setStartEndStyle(AnnotLineEndingStyle start, AnnotLineEndingStyle end)
3242 {
3243     startStyle = start;
3244     endStyle = end;
3245 
3246     Array *leArray = new Array(doc->getXRef());
3247     leArray->add(Object(objName, convertAnnotLineEndingStyle(startStyle)));
3248     leArray->add(Object(objName, convertAnnotLineEndingStyle(endStyle)));
3249 
3250     update("LE", Object(leArray));
3251     invalidateAppearance();
3252 }
3253 
setInteriorColor(std::unique_ptr<AnnotColor> && new_color)3254 void AnnotLine::setInteriorColor(std::unique_ptr<AnnotColor> &&new_color)
3255 {
3256     if (new_color) {
3257         Object obj1 = new_color->writeToObject(doc->getXRef());
3258         update("IC", std::move(obj1));
3259         interiorColor = std::move(new_color);
3260     } else {
3261         interiorColor = nullptr;
3262     }
3263     invalidateAppearance();
3264 }
3265 
setLeaderLineLength(double len)3266 void AnnotLine::setLeaderLineLength(double len)
3267 {
3268     leaderLineLength = len;
3269     update("LL", Object(len));
3270     invalidateAppearance();
3271 }
3272 
setLeaderLineExtension(double len)3273 void AnnotLine::setLeaderLineExtension(double len)
3274 {
3275     leaderLineExtension = len;
3276     update("LLE", Object(len));
3277 
3278     // LL is required if LLE is present
3279     update("LL", Object(leaderLineLength));
3280     invalidateAppearance();
3281 }
3282 
setCaption(bool new_cap)3283 void AnnotLine::setCaption(bool new_cap)
3284 {
3285     caption = new_cap;
3286     update("Cap", Object(new_cap));
3287     invalidateAppearance();
3288 }
3289 
setIntent(AnnotLineIntent new_intent)3290 void AnnotLine::setIntent(AnnotLineIntent new_intent)
3291 {
3292     const char *intentName;
3293 
3294     intent = new_intent;
3295     if (new_intent == intentLineArrow)
3296         intentName = "LineArrow";
3297     else // intentLineDimension
3298         intentName = "LineDimension";
3299     update("IT", Object(objName, intentName));
3300 }
3301 
generateLineAppearance()3302 void AnnotLine::generateLineAppearance()
3303 {
3304     double borderWidth, ca = opacity;
3305     bool fill = false;
3306 
3307     appearBBox = std::make_unique<AnnotAppearanceBBox>(rect.get());
3308     AnnotAppearanceBuilder appearBuilder;
3309     appearBuilder.append("q\n");
3310     if (color) {
3311         appearBuilder.setDrawColor(color.get(), false);
3312     }
3313     if (interiorColor) {
3314         appearBuilder.setDrawColor(interiorColor.get(), true);
3315         fill = true;
3316     }
3317     appearBuilder.setLineStyleForBorder(border.get());
3318     borderWidth = border->getWidth();
3319     appearBBox->setBorderWidth(std::max(1., borderWidth));
3320 
3321     const double x1 = coord1->getX();
3322     const double y1 = coord1->getY();
3323     const double x2 = coord2->getX();
3324     const double y2 = coord2->getY();
3325 
3326     // Main segment length
3327     const double main_len = sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
3328 
3329     // Main segment becomes positive x direction, coord1 becomes (0,0)
3330     Matrix matr;
3331     const double angle = atan2(y2 - y1, x2 - x1);
3332     matr.m[0] = matr.m[3] = cos(angle);
3333     matr.m[1] = sin(angle);
3334     matr.m[2] = -matr.m[1];
3335     matr.m[4] = x1 - rect->x1;
3336     matr.m[5] = y1 - rect->y1;
3337 
3338     double tx, ty, captionwidth = 0, captionheight = 0;
3339     AnnotLineCaptionPos actualCaptionPos = captionPos;
3340     const double fontsize = 9;
3341     const double captionhmargin = 2; // Left and right margin (inline caption only)
3342     const double captionmaxwidth = main_len - 2 * captionhmargin;
3343     const double lineendingSize = std::min(6. * borderWidth, main_len / 2);
3344 
3345     Dict *fontResDict;
3346     GfxFont *font;
3347 
3348     // Calculate caption width and height
3349     if (caption) {
3350         fontResDict = new Dict(doc->getXRef());
3351         font = createAnnotDrawFont(doc->getXRef(), fontResDict);
3352         int lines = 0;
3353         int i = 0;
3354         while (i < contents->getLength()) {
3355             GooString out;
3356             double linewidth;
3357             layoutText(contents.get(), &out, &i, font, &linewidth, 0, nullptr, false);
3358             linewidth *= fontsize;
3359             if (linewidth > captionwidth) {
3360                 captionwidth = linewidth;
3361             }
3362             ++lines;
3363         }
3364         captionheight = lines * fontsize;
3365         // If text is longer than available space, turn into captionPosTop
3366         if (captionwidth > captionmaxwidth) {
3367             actualCaptionPos = captionPosTop;
3368         }
3369     } else {
3370         fontResDict = nullptr;
3371         font = nullptr;
3372     }
3373 
3374     // Draw main segment
3375     matr.transform(AnnotAppearanceBuilder::lineEndingXShorten(startStyle, lineendingSize), leaderLineLength, &tx, &ty);
3376     appearBuilder.appendf("{0:.2f} {1:.2f} m\n", tx, ty);
3377     appearBBox->extendTo(tx, ty);
3378 
3379     if (captionwidth != 0 && actualCaptionPos == captionPosInline) { // Break in the middle
3380         matr.transform((main_len - captionwidth) / 2 - captionhmargin, leaderLineLength, &tx, &ty);
3381         appearBuilder.appendf("{0:.2f} {1:.2f} l S\n", tx, ty);
3382 
3383         matr.transform((main_len + captionwidth) / 2 + captionhmargin, leaderLineLength, &tx, &ty);
3384         appearBuilder.appendf("{0:.2f} {1:.2f} m\n", tx, ty);
3385     }
3386 
3387     matr.transform(main_len - AnnotAppearanceBuilder::lineEndingXShorten(endStyle, lineendingSize), leaderLineLength, &tx, &ty);
3388     appearBuilder.appendf("{0:.2f} {1:.2f} l S\n", tx, ty);
3389     appearBBox->extendTo(tx, ty);
3390 
3391     if (startStyle != annotLineEndingNone) {
3392         const double extendX { -AnnotAppearanceBuilder::lineEndingXExtendBBox(startStyle, lineendingSize) };
3393         appearBuilder.drawLineEnding(startStyle, 0, leaderLineLength, -lineendingSize, fill, matr);
3394         matr.transform(extendX, leaderLineLength + lineendingSize / 2., &tx, &ty);
3395         appearBBox->extendTo(tx, ty);
3396         matr.transform(extendX, leaderLineLength - lineendingSize / 2., &tx, &ty);
3397         appearBBox->extendTo(tx, ty);
3398     }
3399 
3400     if (endStyle != annotLineEndingNone) {
3401         const double extendX { AnnotAppearanceBuilder::lineEndingXExtendBBox(endStyle, lineendingSize) };
3402         appearBuilder.drawLineEnding(endStyle, main_len, leaderLineLength, lineendingSize, fill, matr);
3403         matr.transform(main_len + extendX, leaderLineLength + lineendingSize / 2., &tx, &ty);
3404         appearBBox->extendTo(tx, ty);
3405         matr.transform(main_len + extendX, leaderLineLength - lineendingSize / 2., &tx, &ty);
3406         appearBBox->extendTo(tx, ty);
3407     }
3408 
3409     // Draw caption text
3410     if (caption) {
3411         double tlx = (main_len - captionwidth) / 2, tly; // Top-left coords
3412         if (actualCaptionPos == captionPosInline) {
3413             tly = leaderLineLength + captionheight / 2;
3414         } else {
3415             tly = leaderLineLength + captionheight + 2 * borderWidth;
3416         }
3417 
3418         tlx += captionTextHorizontal;
3419         tly += captionTextVertical;
3420 
3421         // Adjust bounding box
3422         matr.transform(tlx, tly - captionheight, &tx, &ty);
3423         appearBBox->extendTo(tx, ty);
3424         matr.transform(tlx + captionwidth, tly - captionheight, &tx, &ty);
3425         appearBBox->extendTo(tx, ty);
3426         matr.transform(tlx + captionwidth, tly, &tx, &ty);
3427         appearBBox->extendTo(tx, ty);
3428         matr.transform(tlx, tly, &tx, &ty);
3429         appearBBox->extendTo(tx, ty);
3430 
3431         // Setup text state (reusing transformed top-left coord)
3432         appearBuilder.appendf("0 g BT /AnnotDrawFont {0:.2f} Tf\n", fontsize); // Font color: black
3433         appearBuilder.appendf("{0:.2f} {1:.2f} {2:.2f} {3:.2f} {4:.2f} {5:.2f} Tm\n", matr.m[0], matr.m[1], matr.m[2], matr.m[3], tx, ty);
3434         appearBuilder.appendf("0 {0:.2f} Td\n", -fontsize * font->getDescent());
3435         // Draw text
3436         int i = 0;
3437         double xposPrev = 0;
3438         while (i < contents->getLength()) {
3439             GooString out;
3440             double linewidth, xpos;
3441             layoutText(contents.get(), &out, &i, font, &linewidth, 0, nullptr, false);
3442             linewidth *= fontsize;
3443             xpos = (captionwidth - linewidth) / 2;
3444             appearBuilder.appendf("{0:.2f} {1:.2f} Td\n", xpos - xposPrev, -fontsize);
3445             appearBuilder.writeString(out);
3446             appearBuilder.append("Tj\n");
3447             xposPrev = xpos;
3448         }
3449         appearBuilder.append("ET\n");
3450         font->decRefCnt();
3451     }
3452 
3453     // Draw leader lines
3454     double ll_len = fabs(leaderLineLength) + leaderLineExtension;
3455     double sign = leaderLineLength >= 0 ? 1 : -1;
3456     if (ll_len != 0) {
3457         matr.transform(0, 0, &tx, &ty);
3458         appearBuilder.appendf("{0:.2f} {1:.2f} m\n", tx, ty);
3459         appearBBox->extendTo(tx, ty);
3460         matr.transform(0, sign * ll_len, &tx, &ty);
3461         appearBuilder.appendf("{0:.2f} {1:.2f} l S\n", tx, ty);
3462         appearBBox->extendTo(tx, ty);
3463 
3464         matr.transform(main_len, 0, &tx, &ty);
3465         appearBuilder.appendf("{0:.2f} {1:.2f} m\n", tx, ty);
3466         appearBBox->extendTo(tx, ty);
3467         matr.transform(main_len, sign * ll_len, &tx, &ty);
3468         appearBuilder.appendf("{0:.2f} {1:.2f} l S\n", tx, ty);
3469         appearBBox->extendTo(tx, ty);
3470     }
3471 
3472     appearBuilder.append("Q\n");
3473 
3474     double bbox[4];
3475     appearBBox->getBBoxRect(bbox);
3476     if (ca == 1) {
3477         appearance = createForm(appearBuilder.buffer(), bbox, false, fontResDict);
3478     } else {
3479         Object aStream = createForm(appearBuilder.buffer(), bbox, true, fontResDict);
3480 
3481         GooString appearBuf("/GS0 gs\n/Fm0 Do");
3482         Dict *resDict = createResourcesDict("Fm0", std::move(aStream), "GS0", ca, nullptr);
3483         appearance = createForm(&appearBuf, bbox, false, resDict);
3484     }
3485 }
3486 
draw(Gfx * gfx,bool printing)3487 void AnnotLine::draw(Gfx *gfx, bool printing)
3488 {
3489     if (!isVisible(printing))
3490         return;
3491 
3492     annotLocker();
3493     if (appearance.isNull()) {
3494         generateLineAppearance();
3495     }
3496 
3497     // draw the appearance stream
3498     Object obj = appearance.fetch(gfx->getXRef());
3499     if (appearBBox) {
3500         gfx->drawAnnot(&obj, nullptr, color.get(), appearBBox->getPageXMin(), appearBBox->getPageYMin(), appearBBox->getPageXMax(), appearBBox->getPageYMax(), getRotation());
3501     } else {
3502         gfx->drawAnnot(&obj, nullptr, color.get(), rect->x1, rect->y1, rect->x2, rect->y2, getRotation());
3503     }
3504 }
3505 
3506 // Before retrieving the res dict, regenerate the appearance stream if needed,
3507 // because AnnotLine::draw may need to store font info in the res dict
getAppearanceResDict()3508 Object AnnotLine::getAppearanceResDict()
3509 {
3510     if (appearance.isNull()) {
3511         generateLineAppearance();
3512     }
3513     return Annot::getAppearanceResDict();
3514 }
3515 
3516 //------------------------------------------------------------------------
3517 // AnnotTextMarkup
3518 //------------------------------------------------------------------------
AnnotTextMarkup(PDFDoc * docA,PDFRectangle * rectA,AnnotSubtype subType)3519 AnnotTextMarkup::AnnotTextMarkup(PDFDoc *docA, PDFRectangle *rectA, AnnotSubtype subType) : AnnotMarkup(docA, rectA)
3520 {
3521     switch (subType) {
3522     case typeHighlight:
3523         annotObj.dictSet("Subtype", Object(objName, "Highlight"));
3524         break;
3525     case typeUnderline:
3526         annotObj.dictSet("Subtype", Object(objName, "Underline"));
3527         break;
3528     case typeSquiggly:
3529         annotObj.dictSet("Subtype", Object(objName, "Squiggly"));
3530         break;
3531     case typeStrikeOut:
3532         annotObj.dictSet("Subtype", Object(objName, "StrikeOut"));
3533         break;
3534     default:
3535         assert(0 && "Invalid subtype for AnnotTextMarkup\n");
3536     }
3537 
3538     // Store dummy quadrilateral with null coordinates
3539     Array *quadPoints = new Array(doc->getXRef());
3540     for (int i = 0; i < 4 * 2; ++i) {
3541         quadPoints->add(Object(0.));
3542     }
3543     annotObj.dictSet("QuadPoints", Object(quadPoints));
3544 
3545     initialize(docA, annotObj.getDict());
3546 }
3547 
AnnotTextMarkup(PDFDoc * docA,Object && dictObject,const Object * obj)3548 AnnotTextMarkup::AnnotTextMarkup(PDFDoc *docA, Object &&dictObject, const Object *obj) : AnnotMarkup(docA, std::move(dictObject), obj)
3549 {
3550     // the real type will be read in initialize()
3551     type = typeHighlight;
3552     initialize(docA, annotObj.getDict());
3553 }
3554 
3555 AnnotTextMarkup::~AnnotTextMarkup() = default;
3556 
initialize(PDFDoc * docA,Dict * dict)3557 void AnnotTextMarkup::initialize(PDFDoc *docA, Dict *dict)
3558 {
3559     Object obj1;
3560 
3561     obj1 = dict->lookup("Subtype");
3562     if (obj1.isName()) {
3563         GooString typeName(obj1.getName());
3564         if (!typeName.cmp("Highlight")) {
3565             type = typeHighlight;
3566         } else if (!typeName.cmp("Underline")) {
3567             type = typeUnderline;
3568         } else if (!typeName.cmp("Squiggly")) {
3569             type = typeSquiggly;
3570         } else if (!typeName.cmp("StrikeOut")) {
3571             type = typeStrikeOut;
3572         }
3573     }
3574 
3575     obj1 = dict->lookup("QuadPoints");
3576     if (obj1.isArray()) {
3577         quadrilaterals = std::make_unique<AnnotQuadrilaterals>(obj1.getArray(), rect.get());
3578     } else {
3579         error(errSyntaxError, -1, "Bad Annot Text Markup QuadPoints");
3580         ok = false;
3581     }
3582 }
3583 
setType(AnnotSubtype new_type)3584 void AnnotTextMarkup::setType(AnnotSubtype new_type)
3585 {
3586     const char *typeName = nullptr; /* squelch bogus compiler warning */
3587 
3588     switch (new_type) {
3589     case typeHighlight:
3590         typeName = "Highlight";
3591         break;
3592     case typeUnderline:
3593         typeName = "Underline";
3594         break;
3595     case typeSquiggly:
3596         typeName = "Squiggly";
3597         break;
3598     case typeStrikeOut:
3599         typeName = "StrikeOut";
3600         break;
3601     default:
3602         assert(!"Invalid subtype");
3603     }
3604 
3605     type = new_type;
3606     update("Subtype", Object(objName, typeName));
3607     invalidateAppearance();
3608 }
3609 
setQuadrilaterals(AnnotQuadrilaterals * quadPoints)3610 void AnnotTextMarkup::setQuadrilaterals(AnnotQuadrilaterals *quadPoints)
3611 {
3612     Array *a = new Array(doc->getXRef());
3613 
3614     for (int i = 0; i < quadPoints->getQuadrilateralsLength(); ++i) {
3615         a->add(Object(quadPoints->getX1(i)));
3616         a->add(Object(quadPoints->getY1(i)));
3617         a->add(Object(quadPoints->getX2(i)));
3618         a->add(Object(quadPoints->getY2(i)));
3619         a->add(Object(quadPoints->getX3(i)));
3620         a->add(Object(quadPoints->getY3(i)));
3621         a->add(Object(quadPoints->getX4(i)));
3622         a->add(Object(quadPoints->getY4(i)));
3623     }
3624 
3625     quadrilaterals = std::make_unique<AnnotQuadrilaterals>(a, rect.get());
3626 
3627     annotObj.dictSet("QuadPoints", Object(a));
3628     invalidateAppearance();
3629 }
3630 
shouldCreateApperance(Gfx * gfx) const3631 bool AnnotTextMarkup::shouldCreateApperance(Gfx *gfx) const
3632 {
3633     if (appearance.isNull())
3634         return true;
3635 
3636     // Adobe Reader seems to have a complex condition for when to use the
3637     // appearance stream of typeHighlight, which is "use it if it has a Resources dictionary with ExtGState"
3638     // this is reverse engineering of me editing a file by hand and checking what it does so the real
3639     // condition may be more or less complex
3640     if (type == typeHighlight) {
3641         XRef *xref = gfx->getXRef();
3642         const Object fetchedApperance = appearance.fetch(xref);
3643         if (fetchedApperance.isStream()) {
3644             const Object resources = fetchedApperance.streamGetDict()->lookup("Resources");
3645             if (resources.isDict()) {
3646                 if (resources.dictLookup("ExtGState").isDict()) {
3647                     return false;
3648                 }
3649             }
3650         }
3651         return true;
3652     }
3653 
3654     return false;
3655 }
3656 
draw(Gfx * gfx,bool printing)3657 void AnnotTextMarkup::draw(Gfx *gfx, bool printing)
3658 {
3659     double ca = 1;
3660     int i;
3661 
3662     if (!isVisible(printing))
3663         return;
3664 
3665     annotLocker();
3666     if (shouldCreateApperance(gfx)) {
3667         bool blendMultiply = true;
3668         ca = opacity;
3669 
3670         AnnotAppearanceBuilder appearBuilder;
3671         appearBuilder.append("q\n");
3672 
3673         /* Adjust BBox */
3674         appearBBox = std::make_unique<AnnotAppearanceBBox>(rect.get());
3675         for (i = 0; i < quadrilaterals->getQuadrilateralsLength(); ++i) {
3676             appearBBox->extendTo(quadrilaterals->getX1(i) - rect->x1, quadrilaterals->getY1(i) - rect->y1);
3677             appearBBox->extendTo(quadrilaterals->getX2(i) - rect->x1, quadrilaterals->getY2(i) - rect->y1);
3678             appearBBox->extendTo(quadrilaterals->getX3(i) - rect->x1, quadrilaterals->getY3(i) - rect->y1);
3679             appearBBox->extendTo(quadrilaterals->getX4(i) - rect->x1, quadrilaterals->getY4(i) - rect->y1);
3680         }
3681 
3682         switch (type) {
3683         case typeUnderline:
3684             if (color) {
3685                 appearBuilder.setDrawColor(color.get(), false);
3686             }
3687             appearBuilder.append("[] 0 d 1 w\n");
3688 
3689             for (i = 0; i < quadrilaterals->getQuadrilateralsLength(); ++i) {
3690                 double x3, y3, x4, y4;
3691 
3692                 x3 = quadrilaterals->getX3(i);
3693                 y3 = quadrilaterals->getY3(i);
3694                 x4 = quadrilaterals->getX4(i);
3695                 y4 = quadrilaterals->getY4(i);
3696 
3697                 appearBuilder.appendf("{0:.2f} {1:.2f} m\n", x3, y3);
3698                 appearBuilder.appendf("{0:.2f} {1:.2f} l\n", x4, y4);
3699                 appearBuilder.append("S\n");
3700             }
3701             break;
3702         case typeStrikeOut:
3703             if (color) {
3704                 appearBuilder.setDrawColor(color.get(), false);
3705             }
3706             blendMultiply = false;
3707             appearBuilder.append("[] 0 d 1 w\n");
3708 
3709             for (i = 0; i < quadrilaterals->getQuadrilateralsLength(); ++i) {
3710                 double x1, y1, x2, y2;
3711                 double x3, y3, x4, y4;
3712 
3713                 x1 = quadrilaterals->getX1(i);
3714                 y1 = quadrilaterals->getY1(i);
3715                 x2 = quadrilaterals->getX2(i);
3716                 y2 = quadrilaterals->getY2(i);
3717 
3718                 x3 = quadrilaterals->getX3(i);
3719                 y3 = quadrilaterals->getY3(i);
3720                 x4 = quadrilaterals->getX4(i);
3721                 y4 = quadrilaterals->getY4(i);
3722 
3723                 appearBuilder.appendf("{0:.2f} {1:.2f} m\n", (x1 + x3) / 2., (y1 + y3) / 2.);
3724                 appearBuilder.appendf("{0:.2f} {1:.2f} l\n", (x2 + x4) / 2., (y2 + y4) / 2.);
3725                 appearBuilder.append("S\n");
3726             }
3727             break;
3728         case typeSquiggly:
3729             if (color) {
3730                 appearBuilder.setDrawColor(color.get(), false);
3731             }
3732             appearBuilder.append("[] 0 d 1 w\n");
3733 
3734             for (i = 0; i < quadrilaterals->getQuadrilateralsLength(); ++i) {
3735                 double x1, y1, x2, y3;
3736                 double h6;
3737 
3738                 x1 = quadrilaterals->getX1(i);
3739                 y1 = quadrilaterals->getY1(i);
3740                 x2 = quadrilaterals->getX2(i);
3741                 y3 = quadrilaterals->getY3(i);
3742                 h6 = (y1 - y3) / 6.0;
3743 
3744                 appearBuilder.appendf("{0:.2f} {1:.2f} m\n", x1, y3 + h6);
3745                 bool down = false;
3746                 do {
3747                     down = !down; // Zigzag line
3748                     x1 += 2;
3749                     appearBuilder.appendf("{0:.2f} {1:.2f} l\n", x1, y3 + (down ? 0 : h6));
3750                 } while (x1 < x2);
3751                 appearBuilder.append("S\n");
3752             }
3753             break;
3754         default:
3755         case typeHighlight:
3756             if (color)
3757                 appearBuilder.setDrawColor(color.get(), true);
3758 
3759             double biggestBorder = 0;
3760             for (i = 0; i < quadrilaterals->getQuadrilateralsLength(); ++i) {
3761                 double x1, y1, x2, y2, x3, y3, x4, y4;
3762                 double h4;
3763 
3764                 x1 = quadrilaterals->getX1(i);
3765                 y1 = quadrilaterals->getY1(i);
3766                 x2 = quadrilaterals->getX2(i);
3767                 y2 = quadrilaterals->getY2(i);
3768                 x3 = quadrilaterals->getX3(i);
3769                 y3 = quadrilaterals->getY3(i);
3770                 x4 = quadrilaterals->getX4(i);
3771                 y4 = quadrilaterals->getY4(i);
3772                 h4 = fabs(y1 - y3) / 4.0;
3773 
3774                 if (h4 > biggestBorder) {
3775                     biggestBorder = h4;
3776                 }
3777 
3778                 appearBuilder.appendf("{0:.2f} {1:.2f} m\n", x3, y3);
3779                 appearBuilder.appendf("{0:.2f} {1:.2f} {2:.2f} {3:.2f} {4:.2f} {5:.2f} c\n", x3 - h4, y3 + h4, x1 - h4, y1 - h4, x1, y1);
3780                 appearBuilder.appendf("{0:.2f} {1:.2f} l\n", x2, y2);
3781                 appearBuilder.appendf("{0:.2f} {1:.2f} {2:.2f} {3:.2f} {4:.2f} {5:.2f} c\n", x2 + h4, y2 - h4, x4 + h4, y4 + h4, x4, y4);
3782                 appearBuilder.append("f\n");
3783             }
3784             appearBBox->setBorderWidth(biggestBorder);
3785             break;
3786         }
3787         appearBuilder.append("Q\n");
3788 
3789         double bbox[4];
3790         bbox[0] = appearBBox->getPageXMin();
3791         bbox[1] = appearBBox->getPageYMin();
3792         bbox[2] = appearBBox->getPageXMax();
3793         bbox[3] = appearBBox->getPageYMax();
3794         Object aStream = createForm(appearBuilder.buffer(), bbox, true, nullptr);
3795 
3796         GooString appearBuf("/GS0 gs\n/Fm0 Do");
3797         Dict *resDict = createResourcesDict("Fm0", std::move(aStream), "GS0", 1, blendMultiply ? "Multiply" : nullptr);
3798         if (ca == 1) {
3799             appearance = createForm(&appearBuf, bbox, false, resDict);
3800         } else {
3801             aStream = createForm(&appearBuf, bbox, true, resDict);
3802 
3803             Dict *resDict2 = createResourcesDict("Fm0", std::move(aStream), "GS0", ca, nullptr);
3804             appearance = createForm(&appearBuf, bbox, false, resDict2);
3805         }
3806     }
3807 
3808     // draw the appearance stream
3809     Object obj = appearance.fetch(gfx->getXRef());
3810     if (appearBBox) {
3811         gfx->drawAnnot(&obj, nullptr, color.get(), appearBBox->getPageXMin(), appearBBox->getPageYMin(), appearBBox->getPageXMax(), appearBBox->getPageYMax(), getRotation());
3812     } else {
3813         gfx->drawAnnot(&obj, nullptr, color.get(), rect->x1, rect->y1, rect->x2, rect->y2, getRotation());
3814     }
3815 }
3816 
3817 //------------------------------------------------------------------------
3818 // AnnotWidget
3819 //------------------------------------------------------------------------
3820 
AnnotWidget(PDFDoc * docA,Object && dictObject,const Object * obj)3821 AnnotWidget::AnnotWidget(PDFDoc *docA, Object &&dictObject, const Object *obj) : Annot(docA, std::move(dictObject), obj)
3822 {
3823     type = typeWidget;
3824     field = nullptr;
3825     initialize(docA, annotObj.getDict());
3826 }
3827 
AnnotWidget(PDFDoc * docA,Object * dictObject,Object * obj,FormField * fieldA)3828 AnnotWidget::AnnotWidget(PDFDoc *docA, Object *dictObject, Object *obj, FormField *fieldA) : Annot(docA, dictObject->copy(), obj)
3829 {
3830     type = typeWidget;
3831     field = fieldA;
3832     initialize(docA, dictObject->getDict());
3833 }
3834 
3835 AnnotWidget::~AnnotWidget() = default;
3836 
initialize(PDFDoc * docA,Dict * dict)3837 void AnnotWidget::initialize(PDFDoc *docA, Dict *dict)
3838 {
3839     Object obj1;
3840 
3841     form = doc->getCatalog()->getForm();
3842 
3843     obj1 = dict->lookup("H");
3844     if (obj1.isName()) {
3845         const char *modeName = obj1.getName();
3846 
3847         if (!strcmp(modeName, "N")) {
3848             mode = highlightModeNone;
3849         } else if (!strcmp(modeName, "O")) {
3850             mode = highlightModeOutline;
3851         } else if (!strcmp(modeName, "P") || !strcmp(modeName, "T")) {
3852             mode = highlightModePush;
3853         } else {
3854             mode = highlightModeInvert;
3855         }
3856     } else {
3857         mode = highlightModeInvert;
3858     }
3859 
3860     obj1 = dict->lookup("MK");
3861     if (obj1.isDict()) {
3862         appearCharacs = std::make_unique<AnnotAppearanceCharacs>(obj1.getDict());
3863     }
3864 
3865     obj1 = dict->lookup("A");
3866     if (obj1.isDict()) {
3867         action = LinkAction::parseAction(&obj1, doc->getCatalog()->getBaseURI());
3868     }
3869 
3870     additionalActions = dict->lookupNF("AA").copy();
3871 
3872     obj1 = dict->lookup("Parent");
3873     if (obj1.isDict()) {
3874         parent = nullptr;
3875     } else {
3876         parent = nullptr;
3877     }
3878 
3879     obj1 = dict->lookup("BS");
3880     if (obj1.isDict()) {
3881         border = std::make_unique<AnnotBorderBS>(obj1.getDict());
3882     }
3883 
3884     updatedAppearanceStream = Ref::INVALID();
3885 }
3886 
getAdditionalAction(AdditionalActionsType additionalActionType)3887 std::unique_ptr<LinkAction> AnnotWidget::getAdditionalAction(AdditionalActionsType additionalActionType)
3888 {
3889     return ::getAdditionalAction(additionalActionType, &additionalActions, doc);
3890 }
3891 
getFormAdditionalAction(FormAdditionalActionsType formAdditionalActionType)3892 std::unique_ptr<LinkAction> AnnotWidget::getFormAdditionalAction(FormAdditionalActionsType formAdditionalActionType)
3893 {
3894     Object additionalActionsObject = additionalActions.fetch(doc->getXRef());
3895 
3896     if (additionalActionsObject.isDict()) {
3897         const char *key = getFormAdditionalActionKey(formAdditionalActionType);
3898 
3899         Object actionObject = additionalActionsObject.dictLookup(key);
3900         if (actionObject.isDict())
3901             return LinkAction::parseAction(&actionObject, doc->getCatalog()->getBaseURI());
3902     }
3903 
3904     return nullptr;
3905 }
3906 
setFormAdditionalAction(FormAdditionalActionsType formAdditionalActionType,const GooString & js)3907 bool AnnotWidget::setFormAdditionalAction(FormAdditionalActionsType formAdditionalActionType, const GooString &js)
3908 {
3909     Object additionalActionsObject = additionalActions.fetch(doc->getXRef());
3910 
3911     if (!additionalActionsObject.isDict()) {
3912         additionalActionsObject = Object(new Dict(doc->getXRef()));
3913         annotObj.dictSet("AA", additionalActionsObject.copy());
3914     }
3915 
3916     additionalActionsObject.dictSet(getFormAdditionalActionKey(formAdditionalActionType), LinkJavaScript::createObject(doc->getXRef(), js));
3917 
3918     if (additionalActions.isRef()) {
3919         doc->getXRef()->setModifiedObject(&additionalActionsObject, additionalActions.getRef());
3920     } else if (hasRef) {
3921         doc->getXRef()->setModifiedObject(&annotObj, ref);
3922     } else {
3923         error(errInternal, -1, "AnnotWidget::setFormAdditionalAction, where neither additionalActions is ref nor annotobj itself is ref");
3924         return false;
3925     }
3926     return true;
3927 }
3928 
3929 // Grand unified handler for preparing text strings to be drawn into form
3930 // fields.  Takes as input a text string (in PDFDocEncoding or UTF-16).
3931 // Converts some or all of this string to the appropriate encoding for the
3932 // specified font, and computes the width of the text.  Can optionally stop
3933 // converting when a specified width has been reached, to perform line-breaking
3934 // for multi-line fields.
3935 //
3936 // Parameters:
3937 //   text: input text string to convert
3938 //   outBuf: buffer for writing re-encoded string
3939 //   i: index at which to start converting; will be updated to point just after
3940 //      last character processed
3941 //   font: the font which will be used for display
3942 //   width: computed width (unscaled by font size) will be stored here
3943 //   widthLimit: if non-zero, stop converting to keep width under this value
3944 //      (should be scaled down by font size)
3945 //   charCount: count of number of characters will be stored here
3946 //   noReencode: if set, do not try to translate the character encoding
3947 //      (useful for Zapf Dingbats or other unusual encodings)
3948 //      can only be used with simple fonts, not CID-keyed fonts
3949 //
3950 // TODO: Handle surrogate pairs in UTF-16.
3951 //       Should be able to generate output for any CID-keyed font.
3952 //       Doesn't handle vertical fonts--should it?
layoutText(const GooString * text,GooString * outBuf,int * i,const GfxFont * font,double * width,double widthLimit,int * charCount,bool noReencode)3953 void Annot::layoutText(const GooString *text, GooString *outBuf, int *i, const GfxFont *font, double *width, double widthLimit, int *charCount, bool noReencode)
3954 {
3955     CharCode c;
3956     Unicode uChar;
3957     const Unicode *uAux;
3958     double w = 0.0;
3959     int uLen, n;
3960     double dx, dy, ox, oy;
3961 
3962     if (width != nullptr)
3963         *width = 0.0;
3964     if (charCount != nullptr)
3965         *charCount = 0;
3966 
3967     if (!text) {
3968         return;
3969     }
3970     bool unicode = text->hasUnicodeMarker();
3971     bool spacePrev; // previous character was a space
3972 
3973     // State for backtracking when more text has been processed than fits within
3974     // widthLimit.  We track for both input (text) and output (outBuf) the offset
3975     // to the first character to discard.
3976     //
3977     // We keep track of several points:
3978     //   1 - end of previous completed word which fits
3979     //   2 - previous character which fit
3980     int last_i1, last_i2, last_o1, last_o2;
3981 
3982     if (unicode && text->getLength() % 2 != 0) {
3983         error(errSyntaxError, -1, "AnnotWidget::layoutText, bad unicode string");
3984         return;
3985     }
3986 
3987     // skip Unicode marker on string if needed
3988     if (unicode && *i == 0)
3989         *i = 2;
3990 
3991     // Start decoding and copying characters, until either:
3992     //   we reach the end of the string
3993     //   we reach the maximum width
3994     //   we reach a newline character
3995     // As we copy characters, keep track of the last full word to fit, so that we
3996     // can backtrack if we exceed the maximum width.
3997     last_i1 = last_i2 = *i;
3998     last_o1 = last_o2 = 0;
3999     spacePrev = false;
4000     outBuf->clear();
4001 
4002     while (*i < text->getLength()) {
4003         last_i2 = *i;
4004         last_o2 = outBuf->getLength();
4005 
4006         if (unicode) {
4007             uChar = (unsigned char)(text->getChar(*i)) << 8;
4008             uChar += (unsigned char)(text->getChar(*i + 1));
4009             *i += 2;
4010         } else {
4011             if (noReencode)
4012                 uChar = text->getChar(*i) & 0xff;
4013             else
4014                 uChar = pdfDocEncoding[text->getChar(*i) & 0xff];
4015             *i += 1;
4016         }
4017 
4018         // Explicit line break?
4019         if (uChar == '\r' || uChar == '\n') {
4020             // Treat a <CR><LF> sequence as a single line break
4021             if (uChar == '\r' && *i < text->getLength()) {
4022                 if (unicode && text->getChar(*i) == '\0' && text->getChar(*i + 1) == '\n')
4023                     *i += 2;
4024                 else if (!unicode && text->getChar(*i) == '\n')
4025                     *i += 1;
4026             }
4027 
4028             break;
4029         }
4030 
4031         if (noReencode) {
4032             outBuf->append(uChar);
4033         } else {
4034             const CharCodeToUnicode *ccToUnicode = font->getToUnicode();
4035             if (!ccToUnicode) {
4036                 // This assumes an identity CMap.
4037                 outBuf->append((uChar >> 8) & 0xff);
4038                 outBuf->append(uChar & 0xff);
4039             } else if (ccToUnicode->mapToCharCode(&uChar, &c, 1)) {
4040                 if (font->isCIDFont()) {
4041                     // TODO: This assumes an identity CMap.  It should be extended to
4042                     // handle the general case.
4043                     outBuf->append((c >> 8) & 0xff);
4044                     outBuf->append(c & 0xff);
4045                 } else {
4046                     // 8-bit font
4047                     outBuf->append(c);
4048                 }
4049             } else {
4050                 error(errSyntaxError, -1, "AnnotWidget::layoutText, cannot convert U+{0:04uX}", uChar);
4051             }
4052         }
4053 
4054         // If we see a space, then we have a linebreak opportunity.
4055         if (uChar == ' ') {
4056             last_i1 = *i;
4057             if (!spacePrev)
4058                 last_o1 = last_o2;
4059             spacePrev = true;
4060         } else {
4061             spacePrev = false;
4062         }
4063 
4064         // Compute width of character just output
4065         if (outBuf->getLength() > last_o2) {
4066             dx = 0.0;
4067             font->getNextChar(outBuf->c_str() + last_o2, outBuf->getLength() - last_o2, &c, &uAux, &uLen, &dx, &dy, &ox, &oy);
4068             w += dx;
4069         }
4070 
4071         // Current line over-full now?
4072         if (widthLimit > 0.0 && w > widthLimit) {
4073             if (last_o1 > 0) {
4074                 // Back up to the previous word which fit, if there was a previous
4075                 // word.
4076                 *i = last_i1;
4077                 outBuf->del(last_o1, outBuf->getLength() - last_o1);
4078             } else if (last_o2 > 0) {
4079                 // Otherwise, back up to the previous character (in the only word on
4080                 // this line)
4081                 *i = last_i2;
4082                 outBuf->del(last_o2, outBuf->getLength() - last_o2);
4083             } else {
4084                 // Otherwise, we were trying to fit the first character; include it
4085                 // anyway even if it overflows the space--no updates to make.
4086             }
4087             break;
4088         }
4089     }
4090 
4091     // If splitting input into lines because we reached the width limit, then
4092     // consume any remaining trailing spaces that would go on this line from the
4093     // input.  If in doing so we reach a newline, consume that also.  This code
4094     // won't run if we stopped at a newline above, since in that case w <=
4095     // widthLimit still.
4096     if (widthLimit > 0.0 && w > widthLimit) {
4097         if (unicode) {
4098             while (*i < text->getLength() && text->getChar(*i) == '\0' && text->getChar(*i + 1) == ' ')
4099                 *i += 2;
4100             if (*i < text->getLength() && text->getChar(*i) == '\0' && text->getChar(*i + 1) == '\r')
4101                 *i += 2;
4102             if (*i < text->getLength() && text->getChar(*i) == '\0' && text->getChar(*i + 1) == '\n')
4103                 *i += 2;
4104         } else {
4105             while (*i < text->getLength() && text->getChar(*i) == ' ')
4106                 *i += 1;
4107             if (*i < text->getLength() && text->getChar(*i) == '\r')
4108                 *i += 1;
4109             if (*i < text->getLength() && text->getChar(*i) == '\n')
4110                 *i += 1;
4111         }
4112     }
4113 
4114     // Compute the actual width and character count of the final string, based on
4115     // breakpoint, if this information is requested by the caller.
4116     if (width != nullptr || charCount != nullptr) {
4117         const char *s = outBuf->c_str();
4118         int len = outBuf->getLength();
4119 
4120         while (len > 0) {
4121             dx = 0.0;
4122             n = font->getNextChar(s, len, &c, &uAux, &uLen, &dx, &dy, &ox, &oy);
4123 
4124             if (n == 0) {
4125                 break;
4126             }
4127 
4128             if (width != nullptr)
4129                 *width += dx;
4130             if (charCount != nullptr)
4131                 *charCount += 1;
4132 
4133             s += n;
4134             len -= n;
4135         }
4136     }
4137 }
4138 
4139 // Copy the given string to appearBuf, adding parentheses around it and
4140 // escaping characters as appropriate.
writeString(const GooString & str)4141 void AnnotAppearanceBuilder::writeString(const GooString &str)
4142 {
4143     char c;
4144     int i;
4145 
4146     appearBuf->append('(');
4147 
4148     for (i = 0; i < str.getLength(); ++i) {
4149         c = str.getChar(i);
4150         if (c == '(' || c == ')' || c == '\\') {
4151             appearBuf->append('\\');
4152             appearBuf->append(c);
4153         } else if (c < 0x20) {
4154             appearBuf->appendf("\\{0:03o}", (unsigned char)c);
4155         } else {
4156             appearBuf->append(c);
4157         }
4158     }
4159 
4160     appearBuf->append(')');
4161 }
4162 
4163 // Draw the variable text or caption for a field.
drawText(const GooString * text,const GooString * da,const GfxResources * resources,const AnnotBorder * border,const AnnotAppearanceCharacs * appearCharacs,const PDFRectangle * rect,bool multiline,int comb,int quadding,bool txField,bool forceZapfDingbats,XRef * xref,bool password,Dict * resourcesDict,const char * defaultFallback)4164 bool AnnotAppearanceBuilder::drawText(const GooString *text, const GooString *da, const GfxResources *resources, const AnnotBorder *border, const AnnotAppearanceCharacs *appearCharacs, const PDFRectangle *rect, bool multiline, int comb,
4165                                       int quadding, bool txField, bool forceZapfDingbats, XRef *xref, bool password, Dict *resourcesDict, const char *defaultFallback)
4166 {
4167     std::vector<GooString *> daToks;
4168     GooString *tok;
4169     GooString convertedText;
4170     const GfxFont *font;
4171     double dx, dy;
4172     double fontSize, borderWidth, x, xPrev, y, w, wMax;
4173     int tfPos, tmPos, j;
4174     int rot;
4175     bool freeText = false; // true if text should be freed before return
4176     GfxFont *fontToFree = nullptr;
4177 
4178     //~ if there is no MK entry, this should use the existing content stream,
4179     //~ and only replace the marked content portion of it
4180     //~ (this is only relevant for Tx fields)
4181 
4182     // parse the default appearance string
4183     tfPos = tmPos = -1;
4184     if (da) {
4185         int i = 0;
4186         while (i < da->getLength()) {
4187             while (i < da->getLength() && Lexer::isSpace(da->getChar(i))) {
4188                 ++i;
4189             }
4190             if (i < da->getLength()) {
4191                 for (j = i + 1; j < da->getLength() && !Lexer::isSpace(da->getChar(j)); ++j)
4192                     ;
4193                 daToks.push_back(new GooString(da, i, j - i));
4194                 i = j;
4195             }
4196         }
4197         for (i = 2; i < (int)daToks.size(); ++i) {
4198             if (i >= 2 && !(daToks[i])->cmp("Tf")) {
4199                 tfPos = i - 2;
4200             } else if (i >= 6 && !(daToks[i])->cmp("Tm")) {
4201                 tmPos = i - 6;
4202             }
4203         }
4204     }
4205 
4206     // get the font and font size
4207     font = nullptr;
4208     fontSize = 0;
4209     if (tfPos >= 0) {
4210         tok = daToks[tfPos];
4211         if (forceZapfDingbats) {
4212             assert(xref != nullptr);
4213             if (tok->cmp("/ZaDb")) {
4214                 tok->clear();
4215                 tok->append("/ZaDb");
4216             }
4217         }
4218         if (tok->getLength() >= 1 && tok->getChar(0) == '/') {
4219             if (!resources || !(font = resources->lookupFont(tok->c_str() + 1))) {
4220                 if (xref != nullptr && resourcesDict != nullptr) {
4221                     const char *fallback = determineFallbackFont(tok->toStr(), defaultFallback);
4222                     fontToFree = createAnnotDrawFont(xref, resourcesDict, tok->c_str() + 1, fallback);
4223                     font = fontToFree;
4224                 } else {
4225                     error(errSyntaxError, -1, "Unknown font in field's DA string");
4226                 }
4227             }
4228         } else {
4229             error(errSyntaxError, -1, "Invalid font name in 'Tf' operator in field's DA string");
4230         }
4231         tok = daToks[tfPos + 1];
4232         fontSize = gatof(tok->c_str());
4233     } else {
4234         error(errSyntaxError, -1, "Missing 'Tf' operator in field's DA string");
4235     }
4236     if (!font) {
4237         for (auto entry : daToks) {
4238             delete entry;
4239         }
4240         return false;
4241     }
4242 
4243     // get the border width
4244     borderWidth = border ? border->getWidth() : 0;
4245 
4246     // for a password field, replace all characters with asterisks
4247     if (password) {
4248         int len;
4249         if (text->hasUnicodeMarker())
4250             len = (text->getLength() - 2) / 2;
4251         else
4252             len = text->getLength();
4253 
4254         GooString *newText = new GooString;
4255         for (int i = 0; i < len; ++i)
4256             newText->append('*');
4257         text = newText;
4258         freeText = true;
4259     }
4260 
4261     // setup
4262     if (txField) {
4263         appearBuf->append("/Tx BMC\n");
4264     }
4265     appearBuf->append("q\n");
4266     rot = appearCharacs ? appearCharacs->getRotation() : 0;
4267     switch (rot) {
4268     case 90:
4269         appearBuf->appendf("0 1 -1 0 {0:.2f} 0 cm\n", rect->x2 - rect->x1);
4270         dx = rect->y2 - rect->y1;
4271         dy = rect->x2 - rect->x1;
4272         break;
4273     case 180:
4274         appearBuf->appendf("-1 0 0 -1 {0:.2f} {1:.2f} cm\n", rect->x2 - rect->x1, rect->y2 - rect->y1);
4275         dx = rect->x2 - rect->y2;
4276         dy = rect->y2 - rect->y1;
4277         break;
4278     case 270:
4279         appearBuf->appendf("0 -1 1 0 0 {0:.2f} cm\n", rect->y2 - rect->y1);
4280         dx = rect->y2 - rect->y1;
4281         dy = rect->x2 - rect->x1;
4282         break;
4283     default: // assume rot == 0
4284         dx = rect->x2 - rect->x1;
4285         dy = rect->y2 - rect->y1;
4286         break;
4287     }
4288     appearBuf->append("BT\n");
4289     // multi-line text
4290     if (multiline) {
4291         // note: the comb flag is ignored in multiline mode
4292 
4293         wMax = dx - 2 * borderWidth - 4;
4294 
4295         // compute font autosize
4296         if (fontSize == 0) {
4297             for (fontSize = 20; fontSize > 1; --fontSize) {
4298                 y = dy - 3;
4299                 int i = 0;
4300                 while (i < text->getLength()) {
4301                     Annot::layoutText(text, &convertedText, &i, font, &w, wMax / fontSize, nullptr, forceZapfDingbats);
4302                     y -= fontSize;
4303                 }
4304                 // approximate the descender for the last line
4305                 if (y >= 0.33 * fontSize) {
4306                     break;
4307                 }
4308             }
4309             if (tfPos >= 0) {
4310                 tok = daToks[tfPos + 1];
4311                 tok->clear();
4312                 tok->appendf("{0:.2f}", fontSize);
4313             }
4314         }
4315 
4316         // starting y coordinate
4317         // (note: each line of text starts with a Td operator that moves
4318         // down a line)
4319         y = dy - 3;
4320 
4321         // set the font matrix
4322         if (tmPos >= 0) {
4323             tok = daToks[tmPos + 4];
4324             tok->clear();
4325             tok->append('0');
4326             tok = daToks[tmPos + 5];
4327             tok->clear();
4328             tok->appendf("{0:.2f}", y);
4329         }
4330 
4331         // write the DA string
4332         for (const GooString *daTok : daToks) {
4333             appearBuf->append(daTok)->append(' ');
4334         }
4335 
4336         // write the font matrix (if not part of the DA string)
4337         if (tmPos < 0) {
4338             appearBuf->appendf("1 0 0 1 0 {0:.2f} Tm\n", y);
4339         }
4340 
4341         // write a series of lines of text
4342         int i = 0;
4343         xPrev = 0;
4344         while (i < text->getLength()) {
4345             Annot::layoutText(text, &convertedText, &i, font, &w, wMax / fontSize, nullptr, forceZapfDingbats);
4346             w *= fontSize;
4347 
4348             // compute text start position
4349             switch (quadding) {
4350             case quaddingLeftJustified:
4351             default:
4352                 x = borderWidth + 2;
4353                 break;
4354             case quaddingCentered:
4355                 x = (dx - w) / 2;
4356                 break;
4357             case quaddingRightJustified:
4358                 x = dx - borderWidth - 2 - w;
4359                 break;
4360             }
4361 
4362             // draw the line
4363             appearBuf->appendf("{0:.2f} {1:.2f} Td\n", x - xPrev, -fontSize);
4364             writeString(convertedText);
4365             appearBuf->append(" Tj\n");
4366 
4367             // next line
4368             xPrev = x;
4369         }
4370 
4371         // single-line text
4372     } else {
4373         //~ replace newlines with spaces? - what does Acrobat do?
4374 
4375         // comb formatting
4376         if (comb > 0) {
4377             int charCount;
4378 
4379             // compute comb spacing
4380             w = (dx - 2 * borderWidth) / comb;
4381 
4382             // compute font autosize
4383             if (fontSize == 0) {
4384                 fontSize = dy - 2 * borderWidth;
4385                 if (w < fontSize) {
4386                     fontSize = w;
4387                 }
4388                 fontSize = floor(fontSize);
4389                 if (tfPos >= 0) {
4390                     tok = daToks[tfPos + 1];
4391                     tok->clear();
4392                     tok->appendf("{0:.2f}", fontSize);
4393                 }
4394             }
4395 
4396             int i = 0;
4397             Annot::layoutText(text, &convertedText, &i, font, nullptr, 0.0, &charCount, forceZapfDingbats);
4398             if (charCount > comb)
4399                 charCount = comb;
4400 
4401             // compute starting text cell
4402             switch (quadding) {
4403             case quaddingLeftJustified:
4404             default:
4405                 x = borderWidth;
4406                 break;
4407             case quaddingCentered:
4408                 x = borderWidth + (comb - charCount) / 2.0 * w;
4409                 break;
4410             case quaddingRightJustified:
4411                 x = borderWidth + (comb - charCount) * w;
4412                 break;
4413             }
4414             y = 0.5 * dy - 0.4 * fontSize;
4415 
4416             // set the font matrix
4417             if (tmPos >= 0) {
4418                 tok = daToks[tmPos + 4];
4419                 tok->clear();
4420                 tok->appendf("{0:.2f}", x);
4421                 tok = daToks[tmPos + 5];
4422                 tok->clear();
4423                 tok->appendf("{0:.2f}", y);
4424             }
4425 
4426             // write the DA string
4427             for (i = 0; i < (int)daToks.size(); ++i) {
4428                 appearBuf->append(daToks[i])->append(' ');
4429             }
4430 
4431             // write the font matrix (if not part of the DA string)
4432             if (tmPos < 0) {
4433                 appearBuf->appendf("1 0 0 1 {0:.2f} {1:.2f} Tm\n", x, y);
4434             }
4435 
4436             // write the text string
4437             const char *s = convertedText.c_str();
4438             int len = convertedText.getLength();
4439             i = 0;
4440             xPrev = w; // so that first character is placed properly
4441             while (i < comb && len > 0) {
4442                 CharCode code;
4443                 const Unicode *uAux;
4444                 int uLen, n;
4445                 double char_dx, char_dy, ox, oy;
4446 
4447                 char_dx = 0.0;
4448                 n = font->getNextChar(s, len, &code, &uAux, &uLen, &char_dx, &char_dy, &ox, &oy);
4449                 char_dx *= fontSize;
4450 
4451                 // center each character within its cell, by advancing the text
4452                 // position the appropriate amount relative to the start of the
4453                 // previous character
4454                 x = 0.5 * (w - char_dx);
4455                 appearBuf->appendf("{0:.2f} 0 Td\n", x - xPrev + w);
4456 
4457                 GooString charBuf(s, n);
4458                 writeString(charBuf);
4459                 appearBuf->append(" Tj\n");
4460 
4461                 i++;
4462                 s += n;
4463                 len -= n;
4464                 xPrev = x;
4465             }
4466 
4467             // regular (non-comb) formatting
4468         } else {
4469             int ii = 0;
4470             Annot::layoutText(text, &convertedText, &ii, font, &w, 0.0, nullptr, forceZapfDingbats);
4471 
4472             // compute font autosize
4473             if (fontSize == 0) {
4474                 fontSize = dy - 2 * borderWidth;
4475                 if (w > 0) {
4476                     const double fontSize2 = (dx - 4 - 2 * borderWidth) / w;
4477                     if (fontSize2 < fontSize) {
4478                         fontSize = fontSize2;
4479                     }
4480                 }
4481                 fontSize = floor(fontSize);
4482                 if (tfPos >= 0) {
4483                     tok = daToks[tfPos + 1];
4484                     tok->clear();
4485                     tok->appendf("{0:.2f}", fontSize);
4486                 }
4487             }
4488 
4489             // compute text start position
4490             w *= fontSize;
4491             switch (quadding) {
4492             case quaddingLeftJustified:
4493             default:
4494                 x = borderWidth + 2;
4495                 break;
4496             case quaddingCentered:
4497                 x = (dx - w) / 2;
4498                 break;
4499             case quaddingRightJustified:
4500                 x = dx - borderWidth - 2 - w;
4501                 break;
4502             }
4503             y = 0.5 * dy - 0.4 * fontSize;
4504 
4505             // set the font matrix
4506             if (tmPos >= 0) {
4507                 tok = daToks[tmPos + 4];
4508                 tok->clear();
4509                 tok->appendf("{0:.2f}", x);
4510                 tok = daToks[tmPos + 5];
4511                 tok->clear();
4512                 tok->appendf("{0:.2f}", y);
4513             }
4514 
4515             // write the DA string
4516             for (const GooString *daTok : daToks) {
4517                 appearBuf->append(daTok)->append(' ');
4518             }
4519 
4520             // write the font matrix (if not part of the DA string)
4521             if (tmPos < 0) {
4522                 appearBuf->appendf("1 0 0 1 {0:.2f} {1:.2f} Tm\n", x, y);
4523             }
4524 
4525             // write the text string
4526             writeString(convertedText);
4527             appearBuf->append(" Tj\n");
4528         }
4529     }
4530     // cleanup
4531     appearBuf->append("ET\n");
4532     appearBuf->append("Q\n");
4533     if (txField) {
4534         appearBuf->append("EMC\n");
4535     }
4536     for (auto entry : daToks) {
4537         delete entry;
4538     }
4539     if (freeText) {
4540         delete text;
4541     }
4542     if (fontToFree) {
4543         fontToFree->decRefCnt();
4544     }
4545 
4546     return true;
4547 }
4548 
4549 // Draw the variable text or caption for a field.
drawListBox(const FormFieldChoice * fieldChoice,const AnnotBorder * border,const PDFRectangle * rect,const GooString * da,const GfxResources * resources,int quadding,XRef * xref,Dict * resourcesDict)4550 bool AnnotAppearanceBuilder::drawListBox(const FormFieldChoice *fieldChoice, const AnnotBorder *border, const PDFRectangle *rect, const GooString *da, const GfxResources *resources, int quadding, XRef *xref, Dict *resourcesDict)
4551 {
4552     std::vector<GooString *> daToks;
4553     GooString *tok;
4554     GooString convertedText;
4555     const GfxFont *font;
4556     double fontSize, borderWidth, x, y, w, wMax;
4557     int tfPos, tmPos, i, j;
4558     GfxFont *fontToFree = nullptr;
4559 
4560     //~ if there is no MK entry, this should use the existing content stream,
4561     //~ and only replace the marked content portion of it
4562     //~ (this is only relevant for Tx fields)
4563 
4564     // parse the default appearance string
4565     tfPos = tmPos = -1;
4566     if (da) {
4567         i = 0;
4568         while (i < da->getLength()) {
4569             while (i < da->getLength() && Lexer::isSpace(da->getChar(i))) {
4570                 ++i;
4571             }
4572             if (i < da->getLength()) {
4573                 for (j = i + 1; j < da->getLength() && !Lexer::isSpace(da->getChar(j)); ++j)
4574                     ;
4575                 daToks.push_back(new GooString(da, i, j - i));
4576                 i = j;
4577             }
4578         }
4579         for (std::size_t k = 2; k < daToks.size(); ++k) {
4580             if (k >= 2 && !(daToks[k])->cmp("Tf")) {
4581                 tfPos = k - 2;
4582             } else if (k >= 6 && !(daToks[k])->cmp("Tm")) {
4583                 tmPos = k - 6;
4584             }
4585         }
4586     }
4587 
4588     // get the font and font size
4589     font = nullptr;
4590     fontSize = 0;
4591     if (tfPos >= 0) {
4592         tok = daToks[tfPos];
4593         if (tok->getLength() >= 1 && tok->getChar(0) == '/') {
4594             if (!resources || !(font = resources->lookupFont(tok->c_str() + 1))) {
4595                 if (xref != nullptr && resourcesDict != nullptr) {
4596                     const char *fallback = determineFallbackFont(tok->toStr(), "Helvetica");
4597                     fontToFree = createAnnotDrawFont(xref, resourcesDict, tok->c_str() + 1, fallback);
4598                     font = fontToFree;
4599                 } else {
4600                     error(errSyntaxError, -1, "Unknown font in field's DA string");
4601                 }
4602             }
4603         } else {
4604             error(errSyntaxError, -1, "Invalid font name in 'Tf' operator in field's DA string");
4605         }
4606         tok = daToks[tfPos + 1];
4607         fontSize = gatof(tok->c_str());
4608     } else {
4609         error(errSyntaxError, -1, "Missing 'Tf' operator in field's DA string");
4610     }
4611     if (!font) {
4612         for (auto entry : daToks) {
4613             delete entry;
4614         }
4615         return false;
4616     }
4617 
4618     // get the border width
4619     borderWidth = border ? border->getWidth() : 0;
4620 
4621     // compute font autosize
4622     if (fontSize == 0) {
4623         wMax = 0;
4624         for (i = 0; i < fieldChoice->getNumChoices(); ++i) {
4625             j = 0;
4626             if (fieldChoice->getChoice(i) == nullptr) {
4627                 error(errSyntaxError, -1, "Invalid annotation listbox");
4628                 for (auto entry : daToks) {
4629                     delete entry;
4630                 }
4631                 if (fontToFree) {
4632                     fontToFree->decRefCnt();
4633                 }
4634                 return false;
4635             }
4636             Annot::layoutText(fieldChoice->getChoice(i), &convertedText, &j, font, &w, 0.0, nullptr, false);
4637             if (w > wMax) {
4638                 wMax = w;
4639             }
4640         }
4641         fontSize = rect->y2 - rect->y1 - 2 * borderWidth;
4642         const double fontSize2 = (rect->x2 - rect->x1 - 4 - 2 * borderWidth) / wMax;
4643         if (fontSize2 < fontSize) {
4644             fontSize = fontSize2;
4645         }
4646         fontSize = floor(fontSize);
4647         if (tfPos >= 0) {
4648             tok = daToks[tfPos + 1];
4649             tok->clear();
4650             tok->appendf("{0:.2f}", fontSize);
4651         }
4652     }
4653     // draw the text
4654     y = rect->y2 - rect->y1 - 1.1 * fontSize;
4655     for (i = fieldChoice->getTopIndex(); i < fieldChoice->getNumChoices(); ++i) {
4656         // setup
4657         appearBuf->append("q\n");
4658 
4659         // draw the background if selected
4660         if (fieldChoice->isSelected(i)) {
4661             appearBuf->append("0 g f\n");
4662             appearBuf->appendf("{0:.2f} {1:.2f} {2:.2f} {3:.2f} re f\n", borderWidth, y - 0.2 * fontSize, rect->x2 - rect->x1 - 2 * borderWidth, 1.1 * fontSize);
4663         }
4664 
4665         // setup
4666         appearBuf->append("BT\n");
4667 
4668         // compute text width and start position
4669         j = 0;
4670         Annot::layoutText(fieldChoice->getChoice(i), &convertedText, &j, font, &w, 0.0, nullptr, false);
4671         w *= fontSize;
4672         switch (quadding) {
4673         case quaddingLeftJustified:
4674         default:
4675             x = borderWidth + 2;
4676             break;
4677         case quaddingCentered:
4678             x = (rect->x2 - rect->x1 - w) / 2;
4679             break;
4680         case quaddingRightJustified:
4681             x = rect->x2 - rect->x1 - borderWidth - 2 - w;
4682             break;
4683         }
4684 
4685         // set the font matrix
4686         if (tmPos >= 0) {
4687             tok = daToks[tmPos + 4];
4688             tok->clear();
4689             tok->appendf("{0:.2f}", x);
4690             tok = daToks[tmPos + 5];
4691             tok->clear();
4692             tok->appendf("{0:.2f}", y);
4693         }
4694 
4695         // write the DA string
4696         for (const GooString *daTok : daToks) {
4697             appearBuf->append(daTok)->append(' ');
4698         }
4699 
4700         // write the font matrix (if not part of the DA string)
4701         if (tmPos < 0) {
4702             appearBuf->appendf("1 0 0 1 {0:.2f} {1:.2f} Tm\n", x, y);
4703         }
4704 
4705         // change the text color if selected
4706         if (fieldChoice->isSelected(i)) {
4707             appearBuf->append("1 g\n");
4708         }
4709 
4710         // write the text string
4711         writeString(convertedText);
4712         appearBuf->append(" Tj\n");
4713 
4714         // cleanup
4715         appearBuf->append("ET\n");
4716         appearBuf->append("Q\n");
4717 
4718         // next line
4719         y -= 1.1 * fontSize;
4720     }
4721 
4722     for (auto entry : daToks) {
4723         delete entry;
4724     }
4725     if (fontToFree) {
4726         fontToFree->decRefCnt();
4727     }
4728 
4729     return true;
4730 }
4731 
drawFieldBorder(const FormField * field,const AnnotBorder * border,const AnnotAppearanceCharacs * appearCharacs,const PDFRectangle * rect)4732 void AnnotAppearanceBuilder::drawFieldBorder(const FormField *field, const AnnotBorder *border, const AnnotAppearanceCharacs *appearCharacs, const PDFRectangle *rect)
4733 {
4734     int dashLength;
4735     double *dash;
4736     AnnotColor adjustedColor;
4737     const double w = border->getWidth();
4738 
4739     const AnnotColor *aColor = appearCharacs->getBorderColor();
4740     if (!aColor)
4741         aColor = appearCharacs->getBackColor();
4742     if (!aColor)
4743         return;
4744 
4745     const double dx = rect->x2 - rect->x1;
4746     const double dy = rect->y2 - rect->y1;
4747 
4748     // radio buttons with no caption have a round border
4749     const bool hasCaption = appearCharacs->getNormalCaption() != nullptr;
4750     if (field->getType() == formButton && static_cast<const FormFieldButton *>(field)->getButtonType() == formButtonRadio && !hasCaption) {
4751         double r = 0.5 * (dx < dy ? dx : dy);
4752         switch (border->getStyle()) {
4753         case AnnotBorder::borderDashed:
4754             appearBuf->append("[");
4755             dashLength = border->getDashLength();
4756             dash = border->getDash();
4757             for (int i = 0; i < dashLength; ++i) {
4758                 appearBuf->appendf(" {0:.2f}", dash[i]);
4759             }
4760             appearBuf->append("] 0 d\n");
4761             // fallthrough
4762         case AnnotBorder::borderSolid:
4763         case AnnotBorder::borderUnderlined:
4764             appearBuf->appendf("{0:.2f} w\n", w);
4765             setDrawColor(aColor, false);
4766             drawCircle(0.5 * dx, 0.5 * dy, r - 0.5 * w, false);
4767             break;
4768         case AnnotBorder::borderBeveled:
4769         case AnnotBorder::borderInset:
4770             appearBuf->appendf("{0:.2f} w\n", 0.5 * w);
4771             setDrawColor(aColor, false);
4772             drawCircle(0.5 * dx, 0.5 * dy, r - 0.25 * w, false);
4773             adjustedColor = AnnotColor(*aColor);
4774             adjustedColor.adjustColor(border->getStyle() == AnnotBorder::borderBeveled ? 1 : -1);
4775             setDrawColor(&adjustedColor, false);
4776             drawCircleTopLeft(0.5 * dx, 0.5 * dy, r - 0.75 * w);
4777             adjustedColor = AnnotColor(*aColor);
4778             adjustedColor.adjustColor(border->getStyle() == AnnotBorder::borderBeveled ? -1 : 1);
4779             setDrawColor(&adjustedColor, false);
4780             drawCircleBottomRight(0.5 * dx, 0.5 * dy, r - 0.75 * w);
4781             break;
4782         }
4783     } else {
4784         switch (border->getStyle()) {
4785         case AnnotBorder::borderDashed:
4786             appearBuf->append("[");
4787             dashLength = border->getDashLength();
4788             dash = border->getDash();
4789             for (int i = 0; i < dashLength; ++i) {
4790                 appearBuf->appendf(" {0:.2f}", dash[i]);
4791             }
4792             appearBuf->append("] 0 d\n");
4793             // fallthrough
4794         case AnnotBorder::borderSolid:
4795             appearBuf->appendf("{0:.2f} w\n", w);
4796             setDrawColor(aColor, false);
4797             appearBuf->appendf("{0:.2f} {0:.2f} {1:.2f} {2:.2f} re s\n", 0.5 * w, dx - w, dy - w);
4798             break;
4799         case AnnotBorder::borderBeveled:
4800         case AnnotBorder::borderInset:
4801             adjustedColor = AnnotColor(*aColor);
4802             adjustedColor.adjustColor(border->getStyle() == AnnotBorder::borderBeveled ? 1 : -1);
4803             setDrawColor(&adjustedColor, true);
4804             appearBuf->append("0 0 m\n");
4805             appearBuf->appendf("0 {0:.2f} l\n", dy);
4806             appearBuf->appendf("{0:.2f} {1:.2f} l\n", dx, dy);
4807             appearBuf->appendf("{0:.2f} {1:.2f} l\n", dx - w, dy - w);
4808             appearBuf->appendf("{0:.2f} {1:.2f} l\n", w, dy - w);
4809             appearBuf->appendf("{0:.2f} {0:.2f} l\n", w);
4810             appearBuf->append("f\n");
4811             adjustedColor = AnnotColor(*aColor);
4812             adjustedColor.adjustColor(border->getStyle() == AnnotBorder::borderBeveled ? -1 : 1);
4813             setDrawColor(&adjustedColor, true);
4814             appearBuf->append("0 0 m\n");
4815             appearBuf->appendf("{0:.2f} 0 l\n", dx);
4816             appearBuf->appendf("{0:.2f} {1:.2f} l\n", dx, dy);
4817             appearBuf->appendf("{0:.2f} {1:.2f} l\n", dx - w, dy - w);
4818             appearBuf->appendf("{0:.2f} {1:.2f} l\n", dx - w, w);
4819             appearBuf->appendf("{0:.2f} {0:.2f} l\n", w);
4820             appearBuf->append("f\n");
4821             break;
4822         case AnnotBorder::borderUnderlined:
4823             appearBuf->appendf("{0:.2f} w\n", w);
4824             setDrawColor(aColor, false);
4825             appearBuf->appendf("0 0 m {0:.2f} 0 l s\n", dx);
4826             break;
4827         }
4828 
4829         // clip to the inside of the border
4830         appearBuf->appendf("{0:.2f} {0:.2f} {1:.2f} {2:.2f} re W n\n", w, dx - 2 * w, dy - 2 * w);
4831     }
4832 }
4833 
drawFormField(const FormField * field,const Form * form,const GfxResources * resources,const GooString * da,const AnnotBorder * border,const AnnotAppearanceCharacs * appearCharacs,const PDFRectangle * rect,const GooString * appearState,XRef * xref,Dict * resourcesDict)4834 bool AnnotAppearanceBuilder::drawFormField(const FormField *field, const Form *form, const GfxResources *resources, const GooString *da, const AnnotBorder *border, const AnnotAppearanceCharacs *appearCharacs, const PDFRectangle *rect,
4835                                            const GooString *appearState, XRef *xref, Dict *resourcesDict)
4836 {
4837     // draw the field contents
4838     switch (field->getType()) {
4839     case formButton:
4840         return drawFormFieldButton(static_cast<const FormFieldButton *>(field), resources, da, border, appearCharacs, rect, appearState, xref, resourcesDict);
4841         break;
4842     case formText:
4843         return drawFormFieldText(static_cast<const FormFieldText *>(field), form, resources, da, border, appearCharacs, rect, xref, resourcesDict);
4844     case formChoice:
4845         return drawFormFieldChoice(static_cast<const FormFieldChoice *>(field), form, resources, da, border, appearCharacs, rect, xref, resourcesDict);
4846         break;
4847     case formSignature:
4848         return drawSignatureFieldText(static_cast<const FormFieldSignature *>(field), form, resources, da, border, appearCharacs, rect, xref, resourcesDict);
4849         break;
4850     case formUndef:
4851     default:
4852         error(errSyntaxError, -1, "Unknown field type");
4853     }
4854 
4855     return false;
4856 }
4857 
drawFormFieldButton(const FormFieldButton * field,const GfxResources * resources,const GooString * da,const AnnotBorder * border,const AnnotAppearanceCharacs * appearCharacs,const PDFRectangle * rect,const GooString * appearState,XRef * xref,Dict * resourcesDict)4858 bool AnnotAppearanceBuilder::drawFormFieldButton(const FormFieldButton *field, const GfxResources *resources, const GooString *da, const AnnotBorder *border, const AnnotAppearanceCharacs *appearCharacs, const PDFRectangle *rect,
4859                                                  const GooString *appearState, XRef *xref, Dict *resourcesDict)
4860 {
4861     const GooString *caption = nullptr;
4862     if (appearCharacs)
4863         caption = appearCharacs->getNormalCaption();
4864 
4865     switch (field->getButtonType()) {
4866     case formButtonRadio: {
4867         //~ Acrobat doesn't draw a caption if there is no AP dict (?)
4868         if (appearState && appearState->cmp("Off") != 0 && field->getState(appearState->c_str())) {
4869             if (caption) {
4870                 return drawText(caption, da, resources, border, appearCharacs, rect, false, 0, fieldQuadCenter, false, true, xref, false, resourcesDict, "ZapfDingbats");
4871             } else if (appearCharacs) {
4872                 const AnnotColor *aColor = appearCharacs->getBorderColor();
4873                 if (aColor) {
4874                     const double dx = rect->x2 - rect->x1;
4875                     const double dy = rect->y2 - rect->y1;
4876                     setDrawColor(aColor, true);
4877                     drawCircle(0.5 * dx, 0.5 * dy, 0.2 * (dx < dy ? dx : dy), true);
4878                 }
4879                 return true;
4880             }
4881         }
4882     } break;
4883     case formButtonPush:
4884         if (caption)
4885             return drawText(caption, da, resources, border, appearCharacs, rect, false, 0, fieldQuadCenter, false, false, xref, false, resourcesDict);
4886         break;
4887     case formButtonCheck:
4888         if (appearState && appearState->cmp("Off") != 0) {
4889             if (!caption) {
4890                 GooString checkMark("3");
4891                 return drawText(&checkMark, da, resources, border, appearCharacs, rect, false, 0, fieldQuadCenter, false, true, xref, false, resourcesDict, "ZapfDingbats");
4892             } else {
4893                 return drawText(caption, da, resources, border, appearCharacs, rect, false, 0, fieldQuadCenter, false, true, xref, false, resourcesDict, "ZapfDingbats");
4894             }
4895         }
4896         break;
4897     }
4898 
4899     return true;
4900 }
4901 
drawFormFieldText(const FormFieldText * fieldText,const Form * form,const GfxResources * resources,const GooString * da,const AnnotBorder * border,const AnnotAppearanceCharacs * appearCharacs,const PDFRectangle * rect,XRef * xref,Dict * resourcesDict)4902 bool AnnotAppearanceBuilder::drawFormFieldText(const FormFieldText *fieldText, const Form *form, const GfxResources *resources, const GooString *da, const AnnotBorder *border, const AnnotAppearanceCharacs *appearCharacs,
4903                                                const PDFRectangle *rect, XRef *xref, Dict *resourcesDict)
4904 {
4905     VariableTextQuadding quadding;
4906     const GooString *contents;
4907 
4908     contents = fieldText->getAppearanceContent();
4909     if (contents) {
4910         if (fieldText->hasTextQuadding()) {
4911             quadding = fieldText->getTextQuadding();
4912         } else if (form) {
4913             quadding = form->getTextQuadding();
4914         } else {
4915             quadding = quaddingLeftJustified;
4916         }
4917 
4918         int comb = 0;
4919         if (fieldText->isComb())
4920             comb = fieldText->getMaxLen();
4921 
4922         return drawText(contents, da, resources, border, appearCharacs, rect, fieldText->isMultiline(), comb, quadding, true, false, xref, fieldText->isPassword(), resourcesDict);
4923     }
4924 
4925     return true;
4926 }
4927 
drawSignatureFieldText(const FormFieldSignature * field,const Form * form,const GfxResources * resources,const GooString * _da,const AnnotBorder * border,const AnnotAppearanceCharacs * appearCharacs,const PDFRectangle * rect,XRef * xref,Dict * resourcesDict)4928 bool AnnotAppearanceBuilder::drawSignatureFieldText(const FormFieldSignature *field, const Form *form, const GfxResources *resources, const GooString *_da, const AnnotBorder *border, const AnnotAppearanceCharacs *appearCharacs,
4929                                                     const PDFRectangle *rect, XRef *xref, Dict *resourcesDict)
4930 {
4931     const GooString &contents = field->getCustomAppearanceContent();
4932     if (contents.toStr().empty())
4933         return false;
4934 
4935     const GooString &leftText = field->getCustomAppearanceLeftContent();
4936     if (leftText.toStr().empty()) {
4937         drawSignatureFieldText(contents, DefaultAppearance(_da), border, rect, xref, resourcesDict, 0, false /* don't center vertically */, false /* don't center horizontally */, field->getImageResource());
4938     } else {
4939         DefaultAppearance daLeft(_da);
4940         daLeft.setFontPtSize(field->getCustomAppearanceLeftFontSize());
4941         const double halfWidth = (rect->x2 - rect->x1) / 2;
4942         PDFRectangle rectLeft(rect->x1, rect->y1, rect->x1 + halfWidth, rect->y2);
4943         drawSignatureFieldText(leftText, daLeft, border, &rectLeft, xref, resourcesDict, 0, true /* center vertically */, true /* center horizontally */);
4944 
4945         PDFRectangle rectRight(rectLeft.x2, rect->y1, rect->x2, rect->y2);
4946         drawSignatureFieldText(contents, DefaultAppearance(_da), border, &rectRight, xref, resourcesDict, halfWidth, true /* center vertically */, false /* don't center horizontally */);
4947     }
4948 
4949     return true;
4950 }
4951 
setChildDictEntryValue(Dict * parentDict,const char * childDictName,const char * childDictEntryName,const Ref childDictEntryValue,XRef * xref)4952 static void setChildDictEntryValue(Dict *parentDict, const char *childDictName, const char *childDictEntryName, const Ref childDictEntryValue, XRef *xref)
4953 {
4954     Object childDictionaryObj = parentDict->lookup(childDictName);
4955     if (!childDictionaryObj.isDict()) {
4956         childDictionaryObj = Object(new Dict(xref));
4957         parentDict->set(childDictName, childDictionaryObj.copy());
4958     }
4959     childDictionaryObj.dictSet(childDictEntryName, Object(childDictEntryValue));
4960 }
4961 
drawSignatureFieldText(const GooString & text,const DefaultAppearance & da,const AnnotBorder * border,const PDFRectangle * rect,XRef * xref,Dict * resourcesDict,double leftMargin,bool centerVertically,bool centerHorizontally,const Ref imageResourceRef)4962 void AnnotAppearanceBuilder::drawSignatureFieldText(const GooString &text, const DefaultAppearance &da, const AnnotBorder *border, const PDFRectangle *rect, XRef *xref, Dict *resourcesDict, double leftMargin, bool centerVertically,
4963                                                     bool centerHorizontally, const Ref imageResourceRef)
4964 {
4965     double borderWidth = 0;
4966     append("q\n");
4967 
4968     if (border) {
4969         borderWidth = border->getWidth();
4970         if (borderWidth > 0)
4971             setLineStyleForBorder(border);
4972     }
4973 
4974     // Box size
4975     const double width = rect->x2 - rect->x1;
4976     const double height = rect->y2 - rect->y1;
4977     const double textmargin = borderWidth * 2;
4978     const double textwidth = width - 2 * textmargin;
4979 
4980     // Print a background image.
4981     if (imageResourceRef != Ref::INVALID()) {
4982         static const char *imageResourceId = "SigImg";
4983         setChildDictEntryValue(resourcesDict, "XObject", imageResourceId, imageResourceRef, xref);
4984 
4985         Matrix matrix = { 1.0, 0.0, 0.0, 1.0, 0.0, 0.0 };
4986         matrix.scale(width, height);
4987         static const char *IMG_TMPL = "\nq {0:.1g} {1:.1g} {2:.1g} {3:.1g} {4:.1g} {5:.1g} cm /{6:s} Do Q\n";
4988         const GooString *imgBuffer = GooString::format(IMG_TMPL, matrix.m[0], matrix.m[1], matrix.m[2], matrix.m[3], matrix.m[4], matrix.m[5], imageResourceId);
4989         append(imgBuffer->c_str());
4990         delete imgBuffer;
4991     }
4992 
4993     // create a Helvetica fake font
4994     GfxFont *font = createAnnotDrawFont(xref, resourcesDict, da.getFontName().getName());
4995 
4996     // calculate the string tokenization
4997     int i = 0;
4998     std::vector<std::pair<std::string, double>> outTexts;
4999     while (i < text.getLength()) {
5000         GooString out;
5001         double textWidth;
5002         Annot::layoutText(&text, &out, &i, font, &textWidth, textwidth / da.getFontPtSize(), nullptr, false);
5003         outTexts.emplace_back(out.toStr(), textWidth * da.getFontPtSize());
5004     }
5005 
5006     // Setup text clipping
5007     appendf("{0:.2f} {1:.2f} {2:.2f} {3:.2f} re W n\n", leftMargin + textmargin, textmargin, textwidth, height - 2 * textmargin);
5008 
5009     // Set font state
5010     setDrawColor(da.getFontColor(), true);
5011     appendf("BT 1 0 0 1 {0:.2f} {1:.2f} Tm\n", textmargin, height - textmargin - da.getFontPtSize() * font->getDescent());
5012     setTextFont(da.getFontName(), da.getFontPtSize());
5013 
5014     double xDelta = centerHorizontally ? 0 : leftMargin;
5015     double currentX = 0;
5016     double yDelta = -da.getFontPtSize();
5017     if (centerVertically) {
5018         const double outTextHeight = outTexts.size() * da.getFontPtSize();
5019         if (outTextHeight < height) {
5020             yDelta -= (height - outTextHeight) / 2;
5021         }
5022     }
5023     for (const std::pair<std::string, double> &outText : outTexts) {
5024         if (centerHorizontally) {
5025             const double lineX = (width - outText.second) / 2;
5026             xDelta = (lineX - currentX);
5027             currentX += xDelta;
5028         }
5029 
5030         appendf("{0:.2f} {1:.2f} Td\n", xDelta, yDelta);
5031         writeString(GooString(outText.first));
5032         append("Tj\n");
5033 
5034         if (!centerHorizontally) {
5035             xDelta = 0;
5036         }
5037         yDelta = -da.getFontPtSize();
5038     }
5039 
5040     font->decRefCnt();
5041     append("ET Q\n");
5042 }
5043 
drawFormFieldChoice(const FormFieldChoice * fieldChoice,const Form * form,const GfxResources * resources,const GooString * da,const AnnotBorder * border,const AnnotAppearanceCharacs * appearCharacs,const PDFRectangle * rect,XRef * xref,Dict * resourcesDict)5044 bool AnnotAppearanceBuilder::drawFormFieldChoice(const FormFieldChoice *fieldChoice, const Form *form, const GfxResources *resources, const GooString *da, const AnnotBorder *border, const AnnotAppearanceCharacs *appearCharacs,
5045                                                  const PDFRectangle *rect, XRef *xref, Dict *resourcesDict)
5046 {
5047     const GooString *selected;
5048     VariableTextQuadding quadding;
5049 
5050     if (fieldChoice->hasTextQuadding()) {
5051         quadding = fieldChoice->getTextQuadding();
5052     } else if (form) {
5053         quadding = form->getTextQuadding();
5054     } else {
5055         quadding = quaddingLeftJustified;
5056     }
5057 
5058     if (fieldChoice->isCombo()) {
5059         selected = fieldChoice->getSelectedChoice();
5060         if (selected) {
5061             return drawText(selected, da, resources, border, appearCharacs, rect, false, 0, quadding, true, false, xref, false, resourcesDict);
5062             //~ Acrobat draws a popup icon on the right side
5063         }
5064         // list box
5065     } else {
5066         return drawListBox(fieldChoice, border, rect, da, resources, quadding, xref, resourcesDict);
5067     }
5068 
5069     return true;
5070 }
5071 
generateFieldAppearance()5072 void AnnotWidget::generateFieldAppearance()
5073 {
5074     const GooString *da;
5075 
5076     AnnotAppearanceBuilder appearBuilder;
5077 
5078     // draw the background
5079     if (appearCharacs) {
5080         const AnnotColor *aColor = appearCharacs->getBackColor();
5081         if (aColor) {
5082             appearBuilder.setDrawColor(aColor, true);
5083             appearBuilder.appendf("0 0 {0:.2f} {1:.2f} re f\n", rect->x2 - rect->x1, rect->y2 - rect->y1);
5084         }
5085     }
5086 
5087     // draw the border
5088     if (appearCharacs && border && border->getWidth() > 0)
5089         appearBuilder.drawFieldBorder(field, border.get(), appearCharacs.get(), rect.get());
5090 
5091     da = field->getDefaultAppearance();
5092     if (!da && form)
5093         da = form->getDefaultAppearance();
5094 
5095     Dict *appearDict = new Dict(doc->getXRef());
5096 
5097     // Let's init resourcesDictObj and resources.
5098     // In PDF 1.2, an additional entry in the field dictionary, DR, was defined.
5099     // Beginning with PDF 1.5, this entry is obsolete.
5100     // And yet Acrobat Reader seems to be taking a field's DR into account.
5101     Object resourcesDictObj;
5102     const GfxResources *resources = nullptr;
5103     GfxResources *resourcesToFree = nullptr;
5104     if (field->getObj() && field->getObj()->isDict()) {
5105         // Let's use a field's resource dictionary.
5106         resourcesDictObj = field->getObj()->dictLookup("DR");
5107         if (resourcesDictObj.isDict()) {
5108             resourcesToFree = new GfxResources(doc->getXRef(), resourcesDictObj.getDict(), form ? form->getDefaultResources() : nullptr);
5109             resources = resourcesToFree;
5110         }
5111     }
5112     if (!resourcesDictObj.isDict()) {
5113         // No luck with a field's resource dictionary. Let's use an AcroForm's resource dictionary.
5114         if (form && form->getDefaultResourcesObj()->isDict()) {
5115             resourcesDictObj = form->getDefaultResourcesObj()->deepCopy();
5116             resources = form->getDefaultResources();
5117         }
5118     }
5119     if (!resourcesDictObj.isDict()) {
5120         resourcesDictObj = Object(new Dict(doc->getXRef()));
5121     }
5122 
5123     const bool success = appearBuilder.drawFormField(field, form, resources, da, border.get(), appearCharacs.get(), rect.get(), appearState.get(), doc->getXRef(), resourcesDictObj.getDict());
5124     if (!success && form && da != form->getDefaultAppearance()) {
5125         da = form->getDefaultAppearance();
5126         appearBuilder.drawFormField(field, form, resources, da, border.get(), appearCharacs.get(), rect.get(), appearState.get(), doc->getXRef(), resourcesDictObj.getDict());
5127     }
5128 
5129     const GooString *appearBuf = appearBuilder.buffer();
5130     // fill the appearance stream dictionary
5131     appearDict->add("Length", Object(appearBuf->getLength()));
5132     appearDict->add("Subtype", Object(objName, "Form"));
5133     Array *bbox = new Array(doc->getXRef());
5134     bbox->add(Object(0));
5135     bbox->add(Object(0));
5136     bbox->add(Object(rect->x2 - rect->x1));
5137     bbox->add(Object(rect->y2 - rect->y1));
5138     appearDict->add("BBox", Object(bbox));
5139 
5140     // set the resource dictionary
5141     if (resourcesDictObj.getDict()->getLength() > 0) {
5142         appearDict->set("Resources", std::move(resourcesDictObj));
5143     }
5144 
5145     // build the appearance stream
5146     Stream *appearStream = new AutoFreeMemStream(copyString(appearBuf->c_str()), 0, appearBuf->getLength(), Object(appearDict));
5147     appearance = Object(appearStream);
5148 
5149     if (resourcesToFree) {
5150         delete resourcesToFree;
5151     }
5152 }
5153 
updateAppearanceStream()5154 void AnnotWidget::updateAppearanceStream()
5155 {
5156     // If this the first time updateAppearanceStream() is called on this widget,
5157     // destroy the AP dictionary because we are going to create a new one.
5158     if (updatedAppearanceStream == Ref::INVALID()) {
5159         invalidateAppearance(); // Delete AP dictionary and all referenced streams
5160     }
5161 
5162     // There's no need to create a new appearance stream if NeedAppearances is
5163     // set, because it will be ignored next time anyway.
5164     if (form && form->getNeedAppearances())
5165         return;
5166 
5167     // Create the new appearance
5168     generateFieldAppearance();
5169 
5170     // Fetch the appearance stream we've just created
5171     Object obj1 = appearance.fetch(doc->getXRef());
5172 
5173     // If this the first time updateAppearanceStream() is called on this widget,
5174     // create a new AP dictionary containing the new appearance stream.
5175     // Otherwise, just update the stream we had created previously.
5176     if (updatedAppearanceStream == Ref::INVALID()) {
5177         // Write the appearance stream
5178         updatedAppearanceStream = doc->getXRef()->addIndirectObject(obj1);
5179 
5180         // Write the AP dictionary
5181         obj1 = Object(new Dict(doc->getXRef()));
5182         obj1.dictAdd("N", Object(updatedAppearanceStream));
5183 
5184         // Update our internal pointers to the appearance dictionary
5185         appearStreams = std::make_unique<AnnotAppearance>(doc, &obj1);
5186 
5187         update("AP", std::move(obj1));
5188     } else {
5189         // Replace the existing appearance stream
5190         doc->getXRef()->setModifiedObject(&obj1, updatedAppearanceStream);
5191     }
5192 }
5193 
draw(Gfx * gfx,bool printing)5194 void AnnotWidget::draw(Gfx *gfx, bool printing)
5195 {
5196     if (!isVisible(printing))
5197         return;
5198 
5199     annotLocker();
5200 
5201     // Only construct the appearance stream when
5202     // - annot doesn't have an AP or
5203     // - NeedAppearances is true
5204     if (field) {
5205         if (appearance.isNull() || (form && form->getNeedAppearances())) {
5206             generateFieldAppearance();
5207         }
5208     }
5209 
5210     // draw the appearance stream
5211     Object obj = appearance.fetch(gfx->getXRef());
5212     gfx->drawAnnot(&obj, nullptr, color.get(), rect->x1, rect->y1, rect->x2, rect->y2, getRotation());
5213 }
5214 
invalidateAppearance()5215 void AnnotWidget::invalidateAppearance()
5216 {
5217     updatedAppearanceStream = Ref::INVALID();
5218     Annot::invalidateAppearance();
5219 }
5220 
5221 //------------------------------------------------------------------------
5222 // AnnotMovie
5223 //------------------------------------------------------------------------
AnnotMovie(PDFDoc * docA,PDFRectangle * rectA,Movie * movieA)5224 AnnotMovie::AnnotMovie(PDFDoc *docA, PDFRectangle *rectA, Movie *movieA) : Annot(docA, rectA)
5225 {
5226     type = typeMovie;
5227     annotObj.dictSet("Subtype", Object(objName, "Movie"));
5228 
5229     movie.reset(movieA->copy());
5230     // TODO: create movie dict from movieA
5231 
5232     initialize(docA, annotObj.getDict());
5233 }
5234 
AnnotMovie(PDFDoc * docA,Object && dictObject,const Object * obj)5235 AnnotMovie::AnnotMovie(PDFDoc *docA, Object &&dictObject, const Object *obj) : Annot(docA, std::move(dictObject), obj)
5236 {
5237     type = typeMovie;
5238     initialize(docA, annotObj.getDict());
5239 }
5240 
5241 AnnotMovie::~AnnotMovie() = default;
5242 
initialize(PDFDoc * docA,Dict * dict)5243 void AnnotMovie::initialize(PDFDoc *docA, Dict *dict)
5244 {
5245     Object obj1;
5246 
5247     obj1 = dict->lookup("T");
5248     if (obj1.isString()) {
5249         title.reset(obj1.getString()->copy());
5250     }
5251 
5252     Object movieDict = dict->lookup("Movie");
5253     if (movieDict.isDict()) {
5254         Object obj2 = dict->lookup("A");
5255         if (obj2.isDict())
5256             movie = std::make_unique<Movie>(&movieDict, &obj2);
5257         else
5258             movie = std::make_unique<Movie>(&movieDict);
5259         if (!movie->isOk()) {
5260             movie = nullptr;
5261             ok = false;
5262         }
5263     } else {
5264         error(errSyntaxError, -1, "Bad Annot Movie");
5265         ok = false;
5266     }
5267 }
5268 
draw(Gfx * gfx,bool printing)5269 void AnnotMovie::draw(Gfx *gfx, bool printing)
5270 {
5271     if (!isVisible(printing))
5272         return;
5273 
5274     annotLocker();
5275     if (appearance.isNull() && movie->getShowPoster()) {
5276         int width, height;
5277         Object poster = movie->getPoster();
5278         movie->getAspect(&width, &height);
5279 
5280         if (width != -1 && height != -1 && !poster.isNone()) {
5281             auto appearBuf = std::make_unique<GooString>();
5282             appearBuf->append("q\n");
5283             appearBuf->appendf("{0:d} 0 0 {1:d} 0 0 cm\n", width, height);
5284             appearBuf->append("/MImg Do\n");
5285             appearBuf->append("Q\n");
5286 
5287             Dict *imgDict = new Dict(gfx->getXRef());
5288             imgDict->set("MImg", std::move(poster));
5289 
5290             Dict *resDict = new Dict(gfx->getXRef());
5291             resDict->set("XObject", Object(imgDict));
5292 
5293             Dict *formDict = new Dict(gfx->getXRef());
5294             formDict->set("Length", Object(appearBuf->getLength()));
5295             formDict->set("Subtype", Object(objName, "Form"));
5296             formDict->set("Name", Object(objName, "FRM"));
5297             Array *bboxArray = new Array(gfx->getXRef());
5298             bboxArray->add(Object(0));
5299             bboxArray->add(Object(0));
5300             bboxArray->add(Object(width));
5301             bboxArray->add(Object(height));
5302             formDict->set("BBox", Object(bboxArray));
5303             Array *matrix = new Array(gfx->getXRef());
5304             matrix->add(Object(1));
5305             matrix->add(Object(0));
5306             matrix->add(Object(0));
5307             matrix->add(Object(1));
5308             matrix->add(Object(-width / 2));
5309             matrix->add(Object(-height / 2));
5310             formDict->set("Matrix", Object(matrix));
5311             formDict->set("Resources", Object(resDict));
5312 
5313             Stream *mStream = new AutoFreeMemStream(copyString(appearBuf->c_str()), 0, appearBuf->getLength(), Object(formDict));
5314 
5315             Dict *dict = new Dict(gfx->getXRef());
5316             dict->set("FRM", Object(mStream));
5317 
5318             Dict *resDict2 = new Dict(gfx->getXRef());
5319             resDict2->set("XObject", Object(dict));
5320 
5321             appearBuf = std::make_unique<GooString>();
5322             appearBuf->append("q\n");
5323             appearBuf->appendf("0 0 {0:d} {1:d} re W n\n", width, height);
5324             appearBuf->append("q\n");
5325             appearBuf->appendf("0 0 {0:d} {1:d} re W n\n", width, height);
5326             appearBuf->appendf("1 0 0 1 {0:d} {1:d} cm\n", width / 2, height / 2);
5327             appearBuf->append("/FRM Do\n");
5328             appearBuf->append("Q\n");
5329             appearBuf->append("Q\n");
5330 
5331             double bbox[4];
5332             bbox[0] = bbox[1] = 0;
5333             bbox[2] = width;
5334             bbox[3] = height;
5335             appearance = createForm(appearBuf.get(), bbox, false, resDict2);
5336         }
5337     }
5338 
5339     // draw the appearance stream
5340     Object obj = appearance.fetch(gfx->getXRef());
5341     gfx->drawAnnot(&obj, nullptr, color.get(), rect->x1, rect->y1, rect->x2, rect->y2, getRotation());
5342 }
5343 
5344 //------------------------------------------------------------------------
5345 // AnnotScreen
5346 //------------------------------------------------------------------------
AnnotScreen(PDFDoc * docA,PDFRectangle * rectA)5347 AnnotScreen::AnnotScreen(PDFDoc *docA, PDFRectangle *rectA) : Annot(docA, rectA)
5348 {
5349     type = typeScreen;
5350 
5351     annotObj.dictSet("Subtype", Object(objName, "Screen"));
5352     initialize(docA, annotObj.getDict());
5353 }
5354 
AnnotScreen(PDFDoc * docA,Object && dictObject,const Object * obj)5355 AnnotScreen::AnnotScreen(PDFDoc *docA, Object &&dictObject, const Object *obj) : Annot(docA, std::move(dictObject), obj)
5356 {
5357     type = typeScreen;
5358     initialize(docA, annotObj.getDict());
5359 }
5360 
5361 AnnotScreen::~AnnotScreen() = default;
5362 
initialize(PDFDoc * docA,Dict * dict)5363 void AnnotScreen::initialize(PDFDoc *docA, Dict *dict)
5364 {
5365     Object obj1;
5366 
5367     obj1 = dict->lookup("T");
5368     if (obj1.isString()) {
5369         title.reset(obj1.getString()->copy());
5370     }
5371 
5372     obj1 = dict->lookup("A");
5373     if (obj1.isDict()) {
5374         action = LinkAction::parseAction(&obj1, doc->getCatalog()->getBaseURI());
5375         if (action && action->getKind() == actionRendition && page == 0) {
5376             error(errSyntaxError, -1, "Invalid Rendition action: associated screen annotation without P");
5377             action = nullptr;
5378             ok = false;
5379         }
5380     }
5381 
5382     additionalActions = dict->lookupNF("AA").copy();
5383 
5384     obj1 = dict->lookup("MK");
5385     if (obj1.isDict()) {
5386         appearCharacs = std::make_unique<AnnotAppearanceCharacs>(obj1.getDict());
5387     }
5388 }
5389 
getAdditionalAction(AdditionalActionsType additionalActionType)5390 std::unique_ptr<LinkAction> AnnotScreen::getAdditionalAction(AdditionalActionsType additionalActionType)
5391 {
5392     if (additionalActionType == actionFocusIn || additionalActionType == actionFocusOut) // not defined for screen annotation
5393         return nullptr;
5394 
5395     return ::getAdditionalAction(additionalActionType, &additionalActions, doc);
5396 }
5397 
5398 //------------------------------------------------------------------------
5399 // AnnotStamp
5400 //------------------------------------------------------------------------
AnnotStamp(PDFDoc * docA,PDFRectangle * rectA)5401 AnnotStamp::AnnotStamp(PDFDoc *docA, PDFRectangle *rectA) : AnnotMarkup(docA, rectA)
5402 {
5403     type = typeStamp;
5404     annotObj.dictSet("Subtype", Object(objName, "Stamp"));
5405     initialize(docA, annotObj.getDict());
5406 }
5407 
AnnotStamp(PDFDoc * docA,Object && dictObject,const Object * obj)5408 AnnotStamp::AnnotStamp(PDFDoc *docA, Object &&dictObject, const Object *obj) : AnnotMarkup(docA, std::move(dictObject), obj)
5409 {
5410     type = typeStamp;
5411     initialize(docA, annotObj.getDict());
5412 }
5413 
~AnnotStamp()5414 AnnotStamp::~AnnotStamp()
5415 {
5416     delete stampImageHelper;
5417 }
5418 
initialize(PDFDoc * docA,Dict * dict)5419 void AnnotStamp::initialize(PDFDoc *docA, Dict *dict)
5420 {
5421     Object obj1 = dict->lookup("Name");
5422     if (obj1.isName()) {
5423         icon = std::make_unique<GooString>(obj1.getName());
5424     } else {
5425         icon = std::make_unique<GooString>("Draft");
5426     }
5427 
5428     stampImageHelper = nullptr;
5429     updatedAppearanceStream = Ref::INVALID();
5430 }
5431 
generateStampCustomAppearance()5432 void AnnotStamp::generateStampCustomAppearance()
5433 {
5434     Ref imgRef = stampImageHelper->getRef();
5435     const std::string imgStrName = "X" + std::to_string(imgRef.num);
5436 
5437     AnnotAppearanceBuilder appearBuilder;
5438     appearBuilder.append("q\n");
5439     appearBuilder.append("/GS0 gs\n");
5440     appearBuilder.appendf("{0:.3f} 0 0 {1:.3f} 0 0 cm\n", rect->x2 - rect->x1, rect->y2 - rect->y1);
5441     appearBuilder.append("/");
5442     appearBuilder.append(imgStrName.c_str());
5443     appearBuilder.append(" Do\n");
5444     appearBuilder.append("Q\n");
5445 
5446     Dict *resDict = createResourcesDict(imgStrName.c_str(), Object(imgRef), "GS0", opacity, nullptr);
5447 
5448     const double bboxArray[4] = { 0, 0, rect->x2 - rect->x1, rect->y2 - rect->y1 };
5449     const GooString *appearBuf = appearBuilder.buffer();
5450     appearance = createForm(appearBuf, bboxArray, false, resDict);
5451 }
5452 
generateStampDefaultAppearance()5453 void AnnotStamp::generateStampDefaultAppearance()
5454 {
5455     Dict *extGStateDict = nullptr;
5456     AnnotAppearanceBuilder defaultAppearanceBuilder;
5457 
5458     double stampUnscaledWidth;
5459     double stampUnscaledHeight;
5460     const char *stampCode;
5461     if (!icon->cmp("Approved")) {
5462         stampUnscaledWidth = ANNOT_STAMP_APPROVED_WIDTH;
5463         stampUnscaledHeight = ANNOT_STAMP_APPROVED_HEIGHT;
5464         stampCode = ANNOT_STAMP_APPROVED;
5465         extGStateDict = getApprovedStampExtGStateDict(doc);
5466     } else if (!icon->cmp("AsIs")) {
5467         stampUnscaledWidth = ANNOT_STAMP_AS_IS_WIDTH;
5468         stampUnscaledHeight = ANNOT_STAMP_AS_IS_HEIGHT;
5469         stampCode = ANNOT_STAMP_AS_IS;
5470         extGStateDict = getAsIsStampExtGStateDict(doc);
5471     } else if (!icon->cmp("Confidential")) {
5472         stampUnscaledWidth = ANNOT_STAMP_CONFIDENTIAL_WIDTH;
5473         stampUnscaledHeight = ANNOT_STAMP_CONFIDENTIAL_HEIGHT;
5474         stampCode = ANNOT_STAMP_CONFIDENTIAL;
5475         extGStateDict = getConfidentialStampExtGStateDict(doc);
5476     } else if (!icon->cmp("Final")) {
5477         stampUnscaledWidth = ANNOT_STAMP_FINAL_WIDTH;
5478         stampUnscaledHeight = ANNOT_STAMP_FINAL_HEIGHT;
5479         stampCode = ANNOT_STAMP_FINAL;
5480         extGStateDict = getFinalStampExtGStateDict(doc);
5481     } else if (!icon->cmp("Experimental")) {
5482         stampUnscaledWidth = ANNOT_STAMP_EXPERIMENTAL_WIDTH;
5483         stampUnscaledHeight = ANNOT_STAMP_EXPERIMENTAL_HEIGHT;
5484         stampCode = ANNOT_STAMP_EXPERIMENTAL;
5485         extGStateDict = getExperimentalStampExtGStateDict(doc);
5486     } else if (!icon->cmp("Expired")) {
5487         stampUnscaledWidth = ANNOT_STAMP_EXPIRED_WIDTH;
5488         stampUnscaledHeight = ANNOT_STAMP_EXPIRED_HEIGHT;
5489         stampCode = ANNOT_STAMP_EXPIRED;
5490         extGStateDict = getExpiredStampExtGStateDict(doc);
5491     } else if (!icon->cmp("NotApproved")) {
5492         stampUnscaledWidth = ANNOT_STAMP_NOT_APPROVED_WIDTH;
5493         stampUnscaledHeight = ANNOT_STAMP_NOT_APPROVED_HEIGHT;
5494         stampCode = ANNOT_STAMP_NOT_APPROVED;
5495         extGStateDict = getNotApprovedStampExtGStateDict(doc);
5496     } else if (!icon->cmp("NotForPublicRelease")) {
5497         stampUnscaledWidth = ANNOT_STAMP_NOT_FOR_PUBLIC_RELEASE_WIDTH;
5498         stampUnscaledHeight = ANNOT_STAMP_NOT_FOR_PUBLIC_RELEASE_HEIGHT;
5499         stampCode = ANNOT_STAMP_NOT_FOR_PUBLIC_RELEASE;
5500         extGStateDict = getNotForPublicReleaseStampExtGStateDict(doc);
5501     } else if (!icon->cmp("Sold")) {
5502         stampUnscaledWidth = ANNOT_STAMP_SOLD_WIDTH;
5503         stampUnscaledHeight = ANNOT_STAMP_SOLD_HEIGHT;
5504         stampCode = ANNOT_STAMP_SOLD;
5505         extGStateDict = getSoldStampExtGStateDict(doc);
5506     } else if (!icon->cmp("Departmental")) {
5507         stampUnscaledWidth = ANNOT_STAMP_DEPARTMENTAL_WIDTH;
5508         stampUnscaledHeight = ANNOT_STAMP_DEPARTMENTAL_HEIGHT;
5509         stampCode = ANNOT_STAMP_DEPARTMENTAL;
5510         extGStateDict = getDepartmentalStampExtGStateDict(doc);
5511     } else if (!icon->cmp("ForComment")) {
5512         stampUnscaledWidth = ANNOT_STAMP_FOR_COMMENT_WIDTH;
5513         stampUnscaledHeight = ANNOT_STAMP_FOR_COMMENT_HEIGHT;
5514         stampCode = ANNOT_STAMP_FOR_COMMENT;
5515         extGStateDict = getForCommentStampExtGStateDict(doc);
5516     } else if (!icon->cmp("ForPublicRelease")) {
5517         stampUnscaledWidth = ANNOT_STAMP_FOR_PUBLIC_RELEASE_WIDTH;
5518         stampUnscaledHeight = ANNOT_STAMP_FOR_PUBLIC_RELEASE_HEIGHT;
5519         stampCode = ANNOT_STAMP_FOR_PUBLIC_RELEASE;
5520         extGStateDict = getForPublicReleaseStampExtGStateDict(doc);
5521     } else if (!icon->cmp("TopSecret")) {
5522         stampUnscaledWidth = ANNOT_STAMP_TOP_SECRET_WIDTH;
5523         stampUnscaledHeight = ANNOT_STAMP_TOP_SECRET_HEIGHT;
5524         stampCode = ANNOT_STAMP_TOP_SECRET;
5525         extGStateDict = getTopSecretStampExtGStateDict(doc);
5526     } else {
5527         stampUnscaledWidth = ANNOT_STAMP_DRAFT_WIDTH;
5528         stampUnscaledHeight = ANNOT_STAMP_DRAFT_HEIGHT;
5529         stampCode = ANNOT_STAMP_DRAFT;
5530         extGStateDict = getDraftStampExtGStateDict(doc);
5531     }
5532 
5533     const double bboxArray[4] = { 0, 0, rect->x2 - rect->x1, rect->y2 - rect->y1 };
5534     const GooString *scale = GooString::format("{0:.6g} 0 0 {1:.6g} 0 0 cm\nq\n", bboxArray[2] / stampUnscaledWidth, bboxArray[3] / stampUnscaledHeight);
5535     defaultAppearanceBuilder.append(scale->c_str());
5536     defaultAppearanceBuilder.append(stampCode);
5537     defaultAppearanceBuilder.append("Q\n");
5538     delete scale;
5539 
5540     Dict *resDict = new Dict(doc->getXRef());
5541     resDict->add("ExtGState", Object(extGStateDict));
5542 
5543     Object aStream = createForm(defaultAppearanceBuilder.buffer(), bboxArray, true, resDict);
5544 
5545     AnnotAppearanceBuilder appearanceBuilder;
5546     appearanceBuilder.append("/GS0 gs\n/Fm0 Do");
5547     resDict = createResourcesDict("Fm0", std::move(aStream), "GS0", opacity, nullptr);
5548     appearance = createForm(appearanceBuilder.buffer(), bboxArray, false, resDict);
5549 }
5550 
draw(Gfx * gfx,bool printing)5551 void AnnotStamp::draw(Gfx *gfx, bool printing)
5552 {
5553     if (!isVisible(printing))
5554         return;
5555 
5556     annotLocker();
5557     if (appearance.isNull()) {
5558         if (stampImageHelper != nullptr)
5559             generateStampCustomAppearance();
5560         else
5561             generateStampDefaultAppearance();
5562     }
5563 
5564     // draw the appearance stream
5565     Object obj = appearance.fetch(gfx->getXRef());
5566     if (appearBBox) {
5567         gfx->drawAnnot(&obj, nullptr, color.get(), appearBBox->getPageXMin(), appearBBox->getPageYMin(), appearBBox->getPageXMax(), appearBBox->getPageYMax(), getRotation());
5568     } else {
5569         gfx->drawAnnot(&obj, nullptr, color.get(), rect->x1, rect->y1, rect->x2, rect->y2, getRotation());
5570     }
5571 }
5572 
setIcon(GooString * new_icon)5573 void AnnotStamp::setIcon(GooString *new_icon)
5574 {
5575     if (new_icon) {
5576         icon = std::make_unique<GooString>(new_icon);
5577     } else {
5578         icon = std::make_unique<GooString>();
5579     }
5580 
5581     update("Name", Object(objName, icon->c_str()));
5582     invalidateAppearance();
5583 }
5584 
setCustomImage(AnnotStampImageHelper * stampImageHelperA)5585 void AnnotStamp::setCustomImage(AnnotStampImageHelper *stampImageHelperA)
5586 {
5587     if (!stampImageHelperA)
5588         return;
5589 
5590     annotLocker();
5591     clearCustomImage();
5592 
5593     stampImageHelper = stampImageHelperA;
5594     generateStampCustomAppearance();
5595 
5596     if (updatedAppearanceStream == Ref::INVALID()) {
5597         updatedAppearanceStream = doc->getXRef()->addIndirectObject(appearance);
5598     } else {
5599         Object obj1 = appearance.fetch(doc->getXRef());
5600         doc->getXRef()->setModifiedObject(&obj1, updatedAppearanceStream);
5601     }
5602 
5603     Object obj1 = Object(new Dict(doc->getXRef()));
5604     obj1.dictAdd("N", Object(updatedAppearanceStream));
5605     update("AP", std::move(obj1));
5606 }
5607 
clearCustomImage()5608 void AnnotStamp::clearCustomImage()
5609 {
5610     if (stampImageHelper != nullptr) {
5611         stampImageHelper->removeAnnotStampImageObject();
5612         delete stampImageHelper;
5613         stampImageHelper = nullptr;
5614         invalidateAppearance();
5615     }
5616 }
5617 
5618 //------------------------------------------------------------------------
5619 // AnnotGeometry
5620 //------------------------------------------------------------------------
AnnotGeometry(PDFDoc * docA,PDFRectangle * rectA,AnnotSubtype subType)5621 AnnotGeometry::AnnotGeometry(PDFDoc *docA, PDFRectangle *rectA, AnnotSubtype subType) : AnnotMarkup(docA, rectA)
5622 {
5623     switch (subType) {
5624     case typeSquare:
5625         annotObj.dictSet("Subtype", Object(objName, "Square"));
5626         break;
5627     case typeCircle:
5628         annotObj.dictSet("Subtype", Object(objName, "Circle"));
5629         break;
5630     default:
5631         assert(0 && "Invalid subtype for AnnotGeometry\n");
5632     }
5633 
5634     initialize(docA, annotObj.getDict());
5635 }
5636 
AnnotGeometry(PDFDoc * docA,Object && dictObject,const Object * obj)5637 AnnotGeometry::AnnotGeometry(PDFDoc *docA, Object &&dictObject, const Object *obj) : AnnotMarkup(docA, std::move(dictObject), obj)
5638 {
5639     // the real type will be read in initialize()
5640     type = typeSquare;
5641     initialize(docA, annotObj.getDict());
5642 }
5643 
5644 AnnotGeometry::~AnnotGeometry() = default;
5645 
initialize(PDFDoc * docA,Dict * dict)5646 void AnnotGeometry::initialize(PDFDoc *docA, Dict *dict)
5647 {
5648     Object obj1;
5649 
5650     obj1 = dict->lookup("Subtype");
5651     if (obj1.isName()) {
5652         GooString typeName(obj1.getName());
5653         if (!typeName.cmp("Square")) {
5654             type = typeSquare;
5655         } else if (!typeName.cmp("Circle")) {
5656             type = typeCircle;
5657         }
5658     }
5659 
5660     obj1 = dict->lookup("IC");
5661     if (obj1.isArray()) {
5662         interiorColor = std::make_unique<AnnotColor>(obj1.getArray());
5663     }
5664 
5665     obj1 = dict->lookup("BS");
5666     if (obj1.isDict()) {
5667         border = std::make_unique<AnnotBorderBS>(obj1.getDict());
5668     } else if (!border) {
5669         border = std::make_unique<AnnotBorderBS>();
5670     }
5671 
5672     obj1 = dict->lookup("BE");
5673     if (obj1.isDict()) {
5674         borderEffect = std::make_unique<AnnotBorderEffect>(obj1.getDict());
5675     }
5676 
5677     obj1 = dict->lookup("RD");
5678     if (obj1.isArray()) {
5679         geometryRect = parseDiffRectangle(obj1.getArray(), rect.get());
5680     }
5681 }
5682 
setType(AnnotSubtype new_type)5683 void AnnotGeometry::setType(AnnotSubtype new_type)
5684 {
5685     const char *typeName = nullptr; /* squelch bogus compiler warning */
5686 
5687     switch (new_type) {
5688     case typeSquare:
5689         typeName = "Square";
5690         break;
5691     case typeCircle:
5692         typeName = "Circle";
5693         break;
5694     default:
5695         assert(!"Invalid subtype");
5696     }
5697 
5698     type = new_type;
5699     update("Subtype", Object(objName, typeName));
5700     invalidateAppearance();
5701 }
5702 
setInteriorColor(std::unique_ptr<AnnotColor> && new_color)5703 void AnnotGeometry::setInteriorColor(std::unique_ptr<AnnotColor> &&new_color)
5704 {
5705     if (new_color) {
5706         Object obj1 = new_color->writeToObject(doc->getXRef());
5707         update("IC", std::move(obj1));
5708         interiorColor = std::move(new_color);
5709     } else {
5710         interiorColor = nullptr;
5711     }
5712     invalidateAppearance();
5713 }
5714 
draw(Gfx * gfx,bool printing)5715 void AnnotGeometry::draw(Gfx *gfx, bool printing)
5716 {
5717     double ca = 1;
5718 
5719     if (!isVisible(printing))
5720         return;
5721 
5722     annotLocker();
5723     if (appearance.isNull()) {
5724         const bool fill = interiorColor && interiorColor->getSpace() != AnnotColor::colorTransparent;
5725         ca = opacity;
5726 
5727         AnnotAppearanceBuilder appearBuilder;
5728         appearBuilder.append("q\n");
5729         if (color)
5730             appearBuilder.setDrawColor(color.get(), false);
5731 
5732         double borderWidth = border->getWidth();
5733         appearBuilder.setLineStyleForBorder(border.get());
5734 
5735         if (interiorColor)
5736             appearBuilder.setDrawColor(interiorColor.get(), true);
5737 
5738         if (type == typeSquare) {
5739             appearBuilder.appendf("{0:.2f} {1:.2f} {2:.2f} {3:.2f} re\n", borderWidth / 2.0, borderWidth / 2.0, (rect->x2 - rect->x1) - borderWidth, (rect->y2 - rect->y1) - borderWidth);
5740             if (fill) {
5741                 if (borderWidth > 0) {
5742                     appearBuilder.append("b\n");
5743                 } else {
5744                     appearBuilder.append("f\n");
5745                 }
5746             } else if (borderWidth > 0) {
5747                 appearBuilder.append("S\n");
5748             }
5749         } else {
5750             const double rx { (rect->x2 - rect->x1) / 2. };
5751             const double ry { (rect->y2 - rect->y1) / 2. };
5752             const double bwHalf { borderWidth / 2.0 };
5753             appearBuilder.drawEllipse(rx, ry, rx - bwHalf, ry - bwHalf, fill, borderWidth > 0);
5754         }
5755         appearBuilder.append("Q\n");
5756 
5757         double bbox[4];
5758         bbox[0] = bbox[1] = 0;
5759         bbox[2] = rect->x2 - rect->x1;
5760         bbox[3] = rect->y2 - rect->y1;
5761         if (ca == 1) {
5762             appearance = createForm(appearBuilder.buffer(), bbox, false, nullptr);
5763         } else {
5764             Object aStream = createForm(appearBuilder.buffer(), bbox, true, nullptr);
5765 
5766             GooString appearBuf("/GS0 gs\n/Fm0 Do");
5767             Dict *resDict = createResourcesDict("Fm0", std::move(aStream), "GS0", ca, nullptr);
5768             appearance = createForm(&appearBuf, bbox, false, resDict);
5769         }
5770     }
5771 
5772     // draw the appearance stream
5773     Object obj = appearance.fetch(gfx->getXRef());
5774     gfx->drawAnnot(&obj, nullptr, color.get(), rect->x1, rect->y1, rect->x2, rect->y2, getRotation());
5775 }
5776 
5777 //------------------------------------------------------------------------
5778 // AnnotPolygon
5779 //------------------------------------------------------------------------
AnnotPolygon(PDFDoc * docA,PDFRectangle * rectA,AnnotSubtype subType)5780 AnnotPolygon::AnnotPolygon(PDFDoc *docA, PDFRectangle *rectA, AnnotSubtype subType) : AnnotMarkup(docA, rectA)
5781 {
5782     switch (subType) {
5783     case typePolygon:
5784         annotObj.dictSet("Subtype", Object(objName, "Polygon"));
5785         break;
5786     case typePolyLine:
5787         annotObj.dictSet("Subtype", Object(objName, "PolyLine"));
5788         break;
5789     default:
5790         assert(0 && "Invalid subtype for AnnotGeometry\n");
5791     }
5792 
5793     // Store dummy path with one null vertex only
5794     Array *a = new Array(doc->getXRef());
5795     a->add(Object(0.));
5796     a->add(Object(0.));
5797     annotObj.dictSet("Vertices", Object(a));
5798 
5799     initialize(docA, annotObj.getDict());
5800 }
5801 
AnnotPolygon(PDFDoc * docA,Object && dictObject,const Object * obj)5802 AnnotPolygon::AnnotPolygon(PDFDoc *docA, Object &&dictObject, const Object *obj) : AnnotMarkup(docA, std::move(dictObject), obj)
5803 {
5804     // the real type will be read in initialize()
5805     type = typePolygon;
5806     initialize(docA, annotObj.getDict());
5807 }
5808 
5809 AnnotPolygon::~AnnotPolygon() = default;
5810 
initialize(PDFDoc * docA,Dict * dict)5811 void AnnotPolygon::initialize(PDFDoc *docA, Dict *dict)
5812 {
5813     Object obj1;
5814 
5815     obj1 = dict->lookup("Subtype");
5816     if (obj1.isName()) {
5817         GooString typeName(obj1.getName());
5818         if (!typeName.cmp("Polygon")) {
5819             type = typePolygon;
5820         } else if (!typeName.cmp("PolyLine")) {
5821             type = typePolyLine;
5822         }
5823     }
5824 
5825     obj1 = dict->lookup("Vertices");
5826     if (obj1.isArray()) {
5827         vertices = std::make_unique<AnnotPath>(obj1.getArray());
5828     } else {
5829         vertices = std::make_unique<AnnotPath>();
5830         error(errSyntaxError, -1, "Bad Annot Polygon Vertices");
5831         ok = false;
5832     }
5833 
5834     obj1 = dict->lookup("LE");
5835     if (obj1.isArray() && obj1.arrayGetLength() == 2) {
5836         Object obj2 = obj1.arrayGet(0);
5837         if (obj2.isName()) {
5838             const GooString leName(obj2.getName());
5839             startStyle = parseAnnotLineEndingStyle(&leName);
5840         } else {
5841             startStyle = annotLineEndingNone;
5842         }
5843         obj2 = obj1.arrayGet(1);
5844         if (obj2.isName()) {
5845             const GooString leName(obj2.getName());
5846             endStyle = parseAnnotLineEndingStyle(&leName);
5847         } else {
5848             endStyle = annotLineEndingNone;
5849         }
5850     } else {
5851         startStyle = endStyle = annotLineEndingNone;
5852     }
5853 
5854     obj1 = dict->lookup("IC");
5855     if (obj1.isArray()) {
5856         interiorColor = std::make_unique<AnnotColor>(obj1.getArray());
5857     }
5858 
5859     obj1 = dict->lookup("BS");
5860     if (obj1.isDict()) {
5861         border = std::make_unique<AnnotBorderBS>(obj1.getDict());
5862     } else if (!border) {
5863         border = std::make_unique<AnnotBorderBS>();
5864     }
5865 
5866     obj1 = dict->lookup("BE");
5867     if (obj1.isDict()) {
5868         borderEffect = std::make_unique<AnnotBorderEffect>(obj1.getDict());
5869     }
5870 
5871     obj1 = dict->lookup("IT");
5872     if (obj1.isName()) {
5873         const char *intentName = obj1.getName();
5874 
5875         if (!strcmp(intentName, "PolygonCloud")) {
5876             intent = polygonCloud;
5877         } else if (!strcmp(intentName, "PolyLineDimension")) {
5878             intent = polylineDimension;
5879         } else {
5880             intent = polygonDimension;
5881         }
5882     } else {
5883         intent = polygonCloud;
5884     }
5885 }
5886 
setType(AnnotSubtype new_type)5887 void AnnotPolygon::setType(AnnotSubtype new_type)
5888 {
5889     const char *typeName = nullptr; /* squelch bogus compiler warning */
5890 
5891     switch (new_type) {
5892     case typePolygon:
5893         typeName = "Polygon";
5894         break;
5895     case typePolyLine:
5896         typeName = "PolyLine";
5897         break;
5898     default:
5899         assert(!"Invalid subtype");
5900     }
5901 
5902     type = new_type;
5903     update("Subtype", Object(objName, typeName));
5904     invalidateAppearance();
5905 }
5906 
setVertices(AnnotPath * path)5907 void AnnotPolygon::setVertices(AnnotPath *path)
5908 {
5909     Array *a = new Array(doc->getXRef());
5910     for (int i = 0; i < path->getCoordsLength(); i++) {
5911         a->add(Object(path->getX(i)));
5912         a->add(Object(path->getY(i)));
5913     }
5914 
5915     vertices = std::make_unique<AnnotPath>(a);
5916 
5917     update("Vertices", Object(a));
5918     invalidateAppearance();
5919 }
5920 
setStartEndStyle(AnnotLineEndingStyle start,AnnotLineEndingStyle end)5921 void AnnotPolygon::setStartEndStyle(AnnotLineEndingStyle start, AnnotLineEndingStyle end)
5922 {
5923     startStyle = start;
5924     endStyle = end;
5925 
5926     Array *a = new Array(doc->getXRef());
5927     a->add(Object(objName, convertAnnotLineEndingStyle(startStyle)));
5928     a->add(Object(objName, convertAnnotLineEndingStyle(endStyle)));
5929 
5930     update("LE", Object(a));
5931     invalidateAppearance();
5932 }
5933 
setInteriorColor(std::unique_ptr<AnnotColor> && new_color)5934 void AnnotPolygon::setInteriorColor(std::unique_ptr<AnnotColor> &&new_color)
5935 {
5936     if (new_color) {
5937         Object obj1 = new_color->writeToObject(doc->getXRef());
5938         update("IC", std::move(obj1));
5939         interiorColor = std::move(new_color);
5940     }
5941     invalidateAppearance();
5942 }
5943 
setIntent(AnnotPolygonIntent new_intent)5944 void AnnotPolygon::setIntent(AnnotPolygonIntent new_intent)
5945 {
5946     const char *intentName;
5947 
5948     intent = new_intent;
5949     if (new_intent == polygonCloud)
5950         intentName = "PolygonCloud";
5951     else if (new_intent == polylineDimension)
5952         intentName = "PolyLineDimension";
5953     else // polygonDimension
5954         intentName = "PolygonDimension";
5955     update("IT", Object(objName, intentName));
5956 }
5957 
generatePolyLineAppearance(AnnotAppearanceBuilder * appearBuilder)5958 void AnnotPolygon::generatePolyLineAppearance(AnnotAppearanceBuilder *appearBuilder)
5959 {
5960     const bool fill = (bool)interiorColor;
5961     const double x1 = vertices->getX(0);
5962     const double y1 = vertices->getY(0);
5963     const double x2 = vertices->getX(1);
5964     const double y2 = vertices->getY(1);
5965     const double x3 = vertices->getX(vertices->getCoordsLength() - 2);
5966     const double y3 = vertices->getY(vertices->getCoordsLength() - 2);
5967     const double x4 = vertices->getX(vertices->getCoordsLength() - 1);
5968     const double y4 = vertices->getY(vertices->getCoordsLength() - 1);
5969 
5970     const double len_1 = sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
5971     // length of last segment
5972     const double len_2 = sqrt((x4 - x3) * (x4 - x3) + (y4 - y3) * (y4 - y3));
5973 
5974     // segments become positive x direction, coord1 becomes (0,0).
5975     Matrix matr1, matr2;
5976     const double angle1 = atan2(y2 - y1, x2 - x1);
5977     const double angle2 = atan2(y4 - y3, x4 - x3);
5978 
5979     matr1.m[0] = matr1.m[3] = cos(angle1);
5980     matr1.m[1] = sin(angle1);
5981     matr1.m[2] = -matr1.m[1];
5982     matr1.m[4] = x1 - rect->x1;
5983     matr1.m[5] = y1 - rect->y1;
5984 
5985     matr2.m[0] = matr2.m[3] = cos(angle2);
5986     matr2.m[1] = sin(angle2);
5987     matr2.m[2] = -matr2.m[1];
5988     matr2.m[4] = x3 - rect->x1;
5989     matr2.m[5] = y3 - rect->y1;
5990 
5991     const double lineEndingSize1 { std::min(6. * border->getWidth(), len_1 / 2) };
5992     const double lineEndingSize2 { std::min(6. * border->getWidth(), len_2 / 2) };
5993 
5994     if (vertices->getCoordsLength() != 0) {
5995         double tx, ty;
5996         matr1.transform(AnnotAppearanceBuilder::lineEndingXShorten(startStyle, lineEndingSize1), 0, &tx, &ty);
5997         appearBuilder->appendf("{0:.2f} {1:.2f} m\n", tx, ty);
5998         appearBBox->extendTo(tx, ty);
5999 
6000         for (int i = 1; i < vertices->getCoordsLength() - 1; ++i) {
6001             appearBuilder->appendf("{0:.2f} {1:.2f} l\n", vertices->getX(i) - rect->x1, vertices->getY(i) - rect->y1);
6002             appearBBox->extendTo(vertices->getX(i) - rect->x1, vertices->getY(i) - rect->y1);
6003         }
6004 
6005         if (vertices->getCoordsLength() > 1) {
6006             matr2.transform(len_2 - AnnotAppearanceBuilder::lineEndingXShorten(endStyle, lineEndingSize2), 0, &tx, &ty);
6007             appearBuilder->appendf("{0:.2f} {1:.2f} l S\n", tx, ty);
6008             appearBBox->extendTo(tx, ty);
6009         }
6010     }
6011 
6012     if (startStyle != annotLineEndingNone) {
6013         const double extendX { -AnnotAppearanceBuilder::lineEndingXExtendBBox(startStyle, lineEndingSize1) };
6014         double tx, ty;
6015         appearBuilder->drawLineEnding(startStyle, 0, 0, -lineEndingSize1, fill, matr1);
6016         matr1.transform(extendX, lineEndingSize1 / 2., &tx, &ty);
6017         appearBBox->extendTo(tx, ty);
6018         matr1.transform(extendX, -lineEndingSize1 / 2., &tx, &ty);
6019         appearBBox->extendTo(tx, ty);
6020     }
6021 
6022     if (endStyle != annotLineEndingNone) {
6023         const double extendX { AnnotAppearanceBuilder::lineEndingXExtendBBox(endStyle, lineEndingSize2) };
6024         double tx, ty;
6025         appearBuilder->drawLineEnding(endStyle, len_2, 0, lineEndingSize2, fill, matr2);
6026         matr2.transform(len_2 + extendX, lineEndingSize2 / 2., &tx, &ty);
6027         appearBBox->extendTo(tx, ty);
6028         matr2.transform(len_2 + extendX, -lineEndingSize2 / 2., &tx, &ty);
6029         appearBBox->extendTo(tx, ty);
6030     }
6031 }
6032 
draw(Gfx * gfx,bool printing)6033 void AnnotPolygon::draw(Gfx *gfx, bool printing)
6034 {
6035     double ca = 1;
6036 
6037     if (!isVisible(printing))
6038         return;
6039 
6040     annotLocker();
6041     if (appearance.isNull()) {
6042         appearBBox = std::make_unique<AnnotAppearanceBBox>(rect.get());
6043         ca = opacity;
6044 
6045         AnnotAppearanceBuilder appearBuilder;
6046         appearBuilder.append("q\n");
6047 
6048         if (color) {
6049             appearBuilder.setDrawColor(color.get(), false);
6050         }
6051 
6052         appearBuilder.setLineStyleForBorder(border.get());
6053         appearBBox->setBorderWidth(std::max(1., border->getWidth()));
6054 
6055         if (interiorColor) {
6056             appearBuilder.setDrawColor(interiorColor.get(), true);
6057         }
6058 
6059         if (type == typePolyLine) {
6060             generatePolyLineAppearance(&appearBuilder);
6061         } else {
6062             if (vertices->getCoordsLength() != 0) {
6063                 appearBuilder.appendf("{0:.2f} {1:.2f} m\n", vertices->getX(0) - rect->x1, vertices->getY(0) - rect->y1);
6064                 appearBBox->extendTo(vertices->getX(0) - rect->x1, vertices->getY(0) - rect->y1);
6065 
6066                 for (int i = 1; i < vertices->getCoordsLength(); ++i) {
6067                     appearBuilder.appendf("{0:.2f} {1:.2f} l\n", vertices->getX(i) - rect->x1, vertices->getY(i) - rect->y1);
6068                     appearBBox->extendTo(vertices->getX(i) - rect->x1, vertices->getY(i) - rect->y1);
6069                 }
6070 
6071                 const double borderWidth = border->getWidth();
6072                 if (interiorColor && interiorColor->getSpace() != AnnotColor::colorTransparent) {
6073                     if (borderWidth > 0) {
6074                         appearBuilder.append("b\n");
6075                     } else {
6076                         appearBuilder.append("f\n");
6077                     }
6078                 } else if (borderWidth > 0) {
6079                     appearBuilder.append("s\n");
6080                 }
6081             }
6082         }
6083         appearBuilder.append("Q\n");
6084 
6085         double bbox[4];
6086         appearBBox->getBBoxRect(bbox);
6087         if (ca == 1) {
6088             appearance = createForm(appearBuilder.buffer(), bbox, false, nullptr);
6089         } else {
6090             Object aStream = createForm(appearBuilder.buffer(), bbox, true, nullptr);
6091 
6092             GooString appearBuf("/GS0 gs\n/Fm0 Do");
6093             Dict *resDict = createResourcesDict("Fm0", std::move(aStream), "GS0", ca, nullptr);
6094             appearance = createForm(&appearBuf, bbox, false, resDict);
6095         }
6096     }
6097 
6098     // draw the appearance stream
6099     Object obj = appearance.fetch(gfx->getXRef());
6100     if (appearBBox) {
6101         gfx->drawAnnot(&obj, nullptr, color.get(), appearBBox->getPageXMin(), appearBBox->getPageYMin(), appearBBox->getPageXMax(), appearBBox->getPageYMax(), getRotation());
6102     } else {
6103         gfx->drawAnnot(&obj, nullptr, color.get(), rect->x1, rect->y1, rect->x2, rect->y2, getRotation());
6104     }
6105 }
6106 
6107 //------------------------------------------------------------------------
6108 // AnnotCaret
6109 //------------------------------------------------------------------------
AnnotCaret(PDFDoc * docA,PDFRectangle * rectA)6110 AnnotCaret::AnnotCaret(PDFDoc *docA, PDFRectangle *rectA) : AnnotMarkup(docA, rectA)
6111 {
6112     type = typeCaret;
6113 
6114     annotObj.dictSet("Subtype", Object(objName, "Caret"));
6115     initialize(docA, annotObj.getDict());
6116 }
6117 
AnnotCaret(PDFDoc * docA,Object && dictObject,const Object * obj)6118 AnnotCaret::AnnotCaret(PDFDoc *docA, Object &&dictObject, const Object *obj) : AnnotMarkup(docA, std::move(dictObject), obj)
6119 {
6120     type = typeCaret;
6121     initialize(docA, annotObj.getDict());
6122 }
6123 
6124 AnnotCaret::~AnnotCaret() = default;
6125 
initialize(PDFDoc * docA,Dict * dict)6126 void AnnotCaret::initialize(PDFDoc *docA, Dict *dict)
6127 {
6128     Object obj1;
6129 
6130     symbol = symbolNone;
6131     obj1 = dict->lookup("Sy");
6132     if (obj1.isName()) {
6133         GooString typeName(obj1.getName());
6134         if (!typeName.cmp("P")) {
6135             symbol = symbolP;
6136         } else if (!typeName.cmp("None")) {
6137             symbol = symbolNone;
6138         }
6139     }
6140 
6141     obj1 = dict->lookup("RD");
6142     if (obj1.isArray()) {
6143         caretRect = parseDiffRectangle(obj1.getArray(), rect.get());
6144     }
6145 }
6146 
setSymbol(AnnotCaretSymbol new_symbol)6147 void AnnotCaret::setSymbol(AnnotCaretSymbol new_symbol)
6148 {
6149     symbol = new_symbol;
6150     update("Sy", Object(objName, new_symbol == symbolP ? "P" : "None"));
6151     invalidateAppearance();
6152 }
6153 
6154 //------------------------------------------------------------------------
6155 // AnnotInk
6156 //------------------------------------------------------------------------
AnnotInk(PDFDoc * docA,PDFRectangle * rectA)6157 AnnotInk::AnnotInk(PDFDoc *docA, PDFRectangle *rectA) : AnnotMarkup(docA, rectA)
6158 {
6159     type = typeInk;
6160 
6161     annotObj.dictSet("Subtype", Object(objName, "Ink"));
6162 
6163     // Store dummy path with one null vertex only
6164     Array *inkListArray = new Array(doc->getXRef());
6165     Array *vList = new Array(doc->getXRef());
6166     vList->add(Object(0.));
6167     vList->add(Object(0.));
6168     inkListArray->add(Object(vList));
6169     annotObj.dictSet("InkList", Object(inkListArray));
6170 
6171     initialize(docA, annotObj.getDict());
6172 }
6173 
AnnotInk(PDFDoc * docA,Object && dictObject,const Object * obj)6174 AnnotInk::AnnotInk(PDFDoc *docA, Object &&dictObject, const Object *obj) : AnnotMarkup(docA, std::move(dictObject), obj)
6175 {
6176     type = typeInk;
6177     initialize(docA, annotObj.getDict());
6178 }
6179 
~AnnotInk()6180 AnnotInk::~AnnotInk()
6181 {
6182     freeInkList();
6183 }
6184 
initialize(PDFDoc * docA,Dict * dict)6185 void AnnotInk::initialize(PDFDoc *docA, Dict *dict)
6186 {
6187     Object obj1;
6188 
6189     obj1 = dict->lookup("InkList");
6190     if (obj1.isArray()) {
6191         parseInkList(obj1.getArray());
6192     } else {
6193         inkListLength = 0;
6194         inkList = nullptr;
6195         error(errSyntaxError, -1, "Bad Annot Ink List");
6196 
6197         obj1 = dict->lookup("AP");
6198         // Although InkList is required, it should be ignored
6199         // when there is an AP entry in the Annot, so do not fail
6200         // when that happens
6201         if (!obj1.isDict()) {
6202             ok = false;
6203         }
6204     }
6205 
6206     obj1 = dict->lookup("BS");
6207     if (obj1.isDict()) {
6208         border = std::make_unique<AnnotBorderBS>(obj1.getDict());
6209     } else if (!border) {
6210         border = std::make_unique<AnnotBorderBS>();
6211     }
6212 }
6213 
writeInkList(AnnotPath ** paths,int n_paths,Array * dest_array)6214 void AnnotInk::writeInkList(AnnotPath **paths, int n_paths, Array *dest_array)
6215 {
6216     for (int i = 0; i < n_paths; ++i) {
6217         AnnotPath *path = paths[i];
6218         Array *a = new Array(doc->getXRef());
6219         for (int j = 0; j < path->getCoordsLength(); ++j) {
6220             a->add(Object(path->getX(j)));
6221             a->add(Object(path->getY(j)));
6222         }
6223         dest_array->add(Object(a));
6224     }
6225 }
6226 
parseInkList(Array * array)6227 void AnnotInk::parseInkList(Array *array)
6228 {
6229     inkListLength = array->getLength();
6230     inkList = (AnnotPath **)gmallocn((inkListLength), sizeof(AnnotPath *));
6231     memset(inkList, 0, inkListLength * sizeof(AnnotPath *));
6232     for (int i = 0; i < inkListLength; i++) {
6233         Object obj2 = array->get(i);
6234         if (obj2.isArray())
6235             inkList[i] = new AnnotPath(obj2.getArray());
6236     }
6237 }
6238 
freeInkList()6239 void AnnotInk::freeInkList()
6240 {
6241     if (inkList) {
6242         for (int i = 0; i < inkListLength; ++i)
6243             delete inkList[i];
6244         gfree(inkList);
6245     }
6246 }
6247 
setInkList(AnnotPath ** paths,int n_paths)6248 void AnnotInk::setInkList(AnnotPath **paths, int n_paths)
6249 {
6250     freeInkList();
6251 
6252     Array *a = new Array(doc->getXRef());
6253     writeInkList(paths, n_paths, a);
6254 
6255     parseInkList(a);
6256     annotObj.dictSet("InkList", Object(a));
6257     invalidateAppearance();
6258 }
6259 
draw(Gfx * gfx,bool printing)6260 void AnnotInk::draw(Gfx *gfx, bool printing)
6261 {
6262     double ca = 1;
6263 
6264     if (!isVisible(printing))
6265         return;
6266 
6267     annotLocker();
6268     if (appearance.isNull()) {
6269         appearBBox = std::make_unique<AnnotAppearanceBBox>(rect.get());
6270         ca = opacity;
6271 
6272         AnnotAppearanceBuilder appearBuilder;
6273         appearBuilder.append("q\n");
6274 
6275         if (color) {
6276             appearBuilder.setDrawColor(color.get(), false);
6277         }
6278 
6279         appearBuilder.setLineStyleForBorder(border.get());
6280         appearBBox->setBorderWidth(std::max(1., border->getWidth()));
6281 
6282         for (int i = 0; i < inkListLength; ++i) {
6283             const AnnotPath *path = inkList[i];
6284             if (path && path->getCoordsLength() != 0) {
6285                 appearBuilder.appendf("{0:.2f} {1:.2f} m\n", path->getX(0) - rect->x1, path->getY(0) - rect->y1);
6286                 appearBBox->extendTo(path->getX(0) - rect->x1, path->getY(0) - rect->y1);
6287 
6288                 for (int j = 1; j < path->getCoordsLength(); ++j) {
6289                     appearBuilder.appendf("{0:.2f} {1:.2f} l\n", path->getX(j) - rect->x1, path->getY(j) - rect->y1);
6290                     appearBBox->extendTo(path->getX(j) - rect->x1, path->getY(j) - rect->y1);
6291                 }
6292 
6293                 appearBuilder.append("S\n");
6294             }
6295         }
6296 
6297         appearBuilder.append("Q\n");
6298 
6299         double bbox[4];
6300         appearBBox->getBBoxRect(bbox);
6301         if (ca == 1) {
6302             appearance = createForm(appearBuilder.buffer(), bbox, false, nullptr);
6303         } else {
6304             Object aStream = createForm(appearBuilder.buffer(), bbox, true, nullptr);
6305 
6306             GooString appearBuf("/GS0 gs\n/Fm0 Do");
6307             Dict *resDict = createResourcesDict("Fm0", std::move(aStream), "GS0", ca, nullptr);
6308             appearance = createForm(&appearBuf, bbox, false, resDict);
6309         }
6310     }
6311 
6312     // draw the appearance stream
6313     Object obj = appearance.fetch(gfx->getXRef());
6314     if (appearBBox) {
6315         gfx->drawAnnot(&obj, nullptr, color.get(), appearBBox->getPageXMin(), appearBBox->getPageYMin(), appearBBox->getPageXMax(), appearBBox->getPageYMax(), getRotation());
6316     } else {
6317         gfx->drawAnnot(&obj, nullptr, color.get(), rect->x1, rect->y1, rect->x2, rect->y2, getRotation());
6318     }
6319 }
6320 
6321 //------------------------------------------------------------------------
6322 // AnnotFileAttachment
6323 //------------------------------------------------------------------------
AnnotFileAttachment(PDFDoc * docA,PDFRectangle * rectA,GooString * filename)6324 AnnotFileAttachment::AnnotFileAttachment(PDFDoc *docA, PDFRectangle *rectA, GooString *filename) : AnnotMarkup(docA, rectA)
6325 {
6326     type = typeFileAttachment;
6327 
6328     annotObj.dictSet("Subtype", Object(objName, "FileAttachment"));
6329     annotObj.dictSet("FS", Object(filename->copy()));
6330 
6331     initialize(docA, annotObj.getDict());
6332 }
6333 
AnnotFileAttachment(PDFDoc * docA,Object && dictObject,const Object * obj)6334 AnnotFileAttachment::AnnotFileAttachment(PDFDoc *docA, Object &&dictObject, const Object *obj) : AnnotMarkup(docA, std::move(dictObject), obj)
6335 {
6336     type = typeFileAttachment;
6337     initialize(docA, annotObj.getDict());
6338 }
6339 
6340 AnnotFileAttachment::~AnnotFileAttachment() = default;
6341 
initialize(PDFDoc * docA,Dict * dict)6342 void AnnotFileAttachment::initialize(PDFDoc *docA, Dict *dict)
6343 {
6344     Object objFS = dict->lookup("FS");
6345     if (objFS.isDict() || objFS.isString()) {
6346         file = std::move(objFS);
6347     } else {
6348         error(errSyntaxError, -1, "Bad Annot File Attachment");
6349         ok = false;
6350     }
6351 
6352     Object objName = dict->lookup("Name");
6353     if (objName.isName()) {
6354         name = std::make_unique<GooString>(objName.getName());
6355     } else {
6356         name = std::make_unique<GooString>("PushPin");
6357     }
6358 }
6359 
6360 #define ANNOT_FILE_ATTACHMENT_AP_PUSHPIN                                                                                                                                                                                                       \
6361     "4.301 23 m 19.699 23 l 21.523 23 23 21.523 23 19.699 c 23 4.301 l 23\n"                                                                                                                                                                   \
6362     "2.477 21.523 1 19.699 1 c 4.301 1 l 2.477 1 1 2.477 1 4.301 c 1 19.699\n"                                                                                                                                                                 \
6363     "l 1 21.523 2.477 23 4.301 23 c h\n"                                                                                                                                                                                                       \
6364     "4.301 23 m f\n"                                                                                                                                                                                                                           \
6365     "0.533333 0.541176 0.521569 RG 2 w\n"                                                                                                                                                                                                      \
6366     "1 J\n"                                                                                                                                                                                                                                    \
6367     "1 j\n"                                                                                                                                                                                                                                    \
6368     "[] 0.0 d\n"                                                                                                                                                                                                                               \
6369     "4 M 5 4 m 6 5 l S\n"                                                                                                                                                                                                                      \
6370     "2 w\n"                                                                                                                                                                                                                                    \
6371     "11 14 m 9 12 l 6 12 l 13 5 l 13 8 l 15 10 l 18 11 l 20 11 l 12 19 l 12\n"                                                                                                                                                                 \
6372     "17 l 11 14 l h\n"                                                                                                                                                                                                                         \
6373     "11 14 m S\n"                                                                                                                                                                                                                              \
6374     "3 w\n"                                                                                                                                                                                                                                    \
6375     "6 5 m 9 8 l S\n"                                                                                                                                                                                                                          \
6376     "0.729412 0.741176 0.713725 RG 2 w\n"                                                                                                                                                                                                      \
6377     "5 5 m 6 6 l S\n"                                                                                                                                                                                                                          \
6378     "2 w\n"                                                                                                                                                                                                                                    \
6379     "11 15 m 9 13 l 6 13 l 13 6 l 13 9 l 15 11 l 18 12 l 20 12 l 12 20 l 12\n"                                                                                                                                                                 \
6380     "18 l 11 15 l h\n"                                                                                                                                                                                                                         \
6381     "11 15 m S\n"                                                                                                                                                                                                                              \
6382     "3 w\n"                                                                                                                                                                                                                                    \
6383     "6 6 m 9 9 l S\n"
6384 
6385 #define ANNOT_FILE_ATTACHMENT_AP_PAPERCLIP                                                                                                                                                                                                     \
6386     "4.301 23 m 19.699 23 l 21.523 23 23 21.523 23 19.699 c 23 4.301 l 23\n"                                                                                                                                                                   \
6387     "2.477 21.523 1 19.699 1 c 4.301 1 l 2.477 1 1 2.477 1 4.301 c 1 19.699\n"                                                                                                                                                                 \
6388     "l 1 21.523 2.477 23 4.301 23 c h\n"                                                                                                                                                                                                       \
6389     "4.301 23 m f\n"                                                                                                                                                                                                                           \
6390     "0.533333 0.541176 0.521569 RG 2 w\n"                                                                                                                                                                                                      \
6391     "1 J\n"                                                                                                                                                                                                                                    \
6392     "1 j\n"                                                                                                                                                                                                                                    \
6393     "[] 0.0 d\n"                                                                                                                                                                                                                               \
6394     "4 M 16.645 12.035 m 12.418 7.707 l 10.902 6.559 6.402 11.203 8.09 12.562 c\n"                                                                                                                                                             \
6395     "14.133 18.578 l 14.949 19.387 16.867 19.184 17.539 18.465 c 20.551\n"                                                                                                                                                                     \
6396     "15.23 l 21.191 14.66 21.336 12.887 20.426 12.102 c 13.18 4.824 l 12.18\n"                                                                                                                                                                 \
6397     "3.82 6.25 2.566 4.324 4.461 c 3 6.395 3.383 11.438 4.711 12.801 c 9.648\n"                                                                                                                                                                \
6398     "17.887 l S\n"                                                                                                                                                                                                                             \
6399     "0.729412 0.741176 0.713725 RG 16.645 13.035 m 12.418 8.707 l\n"                                                                                                                                                                           \
6400     "10.902 7.559 6.402 12.203 8.09 13.562 c\n"                                                                                                                                                                                                \
6401     "14.133 19.578 l 14.949 20.387 16.867 20.184 17.539 19.465 c 20.551\n"                                                                                                                                                                     \
6402     "16.23 l 21.191 15.66 21.336 13.887 20.426 13.102 c 13.18 5.824 l 12.18\n"                                                                                                                                                                 \
6403     "4.82 6.25 3.566 4.324 5.461 c 3 7.395 3.383 12.438 4.711 13.801 c 9.648\n"                                                                                                                                                                \
6404     "18.887 l S\n"
6405 
6406 #define ANNOT_FILE_ATTACHMENT_AP_GRAPH                                                                                                                                                                                                         \
6407     "4.301 23 m 19.699 23 l 21.523 23 23 21.523 23 19.699 c 23 4.301 l 23\n"                                                                                                                                                                   \
6408     "2.477 21.523 1 19.699 1 c 4.301 1 l 2.477 1 1 2.477 1 4.301 c 1 19.699\n"                                                                                                                                                                 \
6409     "l 1 21.523 2.477 23 4.301 23 c h\n"                                                                                                                                                                                                       \
6410     "4.301 23 m f\n"                                                                                                                                                                                                                           \
6411     "0.533333 0.541176 0.521569 RG 1 w\n"                                                                                                                                                                                                      \
6412     "1 J\n"                                                                                                                                                                                                                                    \
6413     "0 j\n"                                                                                                                                                                                                                                    \
6414     "[] 0.0 d\n"                                                                                                                                                                                                                               \
6415     "4 M 18.5 15.5 m 18.5 13.086 l 16.086 15.5 l 18.5 15.5 l h\n"                                                                                                                                                                              \
6416     "18.5 15.5 m S\n"                                                                                                                                                                                                                          \
6417     "7 7 m 10 11 l 13 9 l 18 15 l S\n"                                                                                                                                                                                                         \
6418     "0.729412 0.741176 0.713725 RG 7 8 m 10 12 l 13 10 l 18 16 l S\n"                                                                                                                                                                          \
6419     "18.5 16.5 m 18.5 14.086 l 16.086 16.5 l 18.5 16.5 l h\n"                                                                                                                                                                                  \
6420     "18.5 16.5 m S\n"                                                                                                                                                                                                                          \
6421     "0.533333 0.541176 0.521569 RG 2 w\n"                                                                                                                                                                                                      \
6422     "1 j\n"                                                                                                                                                                                                                                    \
6423     "3 19 m 3 3 l 21 3 l S\n"                                                                                                                                                                                                                  \
6424     "0.729412 0.741176 0.713725 RG 3 20 m 3 4 l 21 4 l S\n"
6425 
6426 #define ANNOT_FILE_ATTACHMENT_AP_TAG                                                                                                                                                                                                           \
6427     "4.301 23 m 19.699 23 l 21.523 23 23 21.523 23 19.699 c 23 4.301 l 23\n"                                                                                                                                                                   \
6428     "2.477 21.523 1 19.699 1 c 4.301 1 l 2.477 1 1 2.477 1 4.301 c 1 19.699\n"                                                                                                                                                                 \
6429     "l 1 21.523 2.477 23 4.301 23 c h\n"                                                                                                                                                                                                       \
6430     "4.301 23 m f\n"                                                                                                                                                                                                                           \
6431     "0.533333 0.541176 0.521569 RG 0.999781 w\n"                                                                                                                                                                                               \
6432     "1 J\n"                                                                                                                                                                                                                                    \
6433     "1 j\n"                                                                                                                                                                                                                                    \
6434     "[] 0.0 d\n"                                                                                                                                                                                                                               \
6435     "4 M q 1 0 0 -1 0 24 cm\n"                                                                                                                                                                                                                 \
6436     "8.492 8.707 m 8.492 9.535 7.82 10.207 6.992 10.207 c 6.164 10.207 5.492\n"                                                                                                                                                                \
6437     "9.535 5.492 8.707 c 5.492 7.879 6.164 7.207 6.992 7.207 c 7.82 7.207\n"                                                                                                                                                                   \
6438     "8.492 7.879 8.492 8.707 c h\n"                                                                                                                                                                                                            \
6439     "8.492 8.707 m S Q\n"                                                                                                                                                                                                                      \
6440     "2 w\n"                                                                                                                                                                                                                                    \
6441     "20.078 11.414 m 20.891 10.602 20.785 9.293 20.078 8.586 c 14.422 2.93 l\n"                                                                                                                                                                \
6442     "13.715 2.223 12.301 2.223 11.594 2.93 c 3.816 10.707 l 3.109 11.414\n"                                                                                                                                                                    \
6443     "2.402 17.781 3.816 19.195 c 5.23 20.609 11.594 19.902 12.301 19.195 c\n"                                                                                                                                                                  \
6444     "20.078 11.414 l h\n"                                                                                                                                                                                                                      \
6445     "20.078 11.414 m S\n"                                                                                                                                                                                                                      \
6446     "0.729412 0.741176 0.713725 RG 20.078 12.414 m\n"                                                                                                                                                                                          \
6447     "20.891 11.605 20.785 10.293 20.078 9.586 c 14.422 3.93 l\n"                                                                                                                                                                               \
6448     "13.715 3.223 12.301 3.223 11.594 3.93 c 3.816 11.707 l 3.109 12.414\n"                                                                                                                                                                    \
6449     "2.402 18.781 3.816 20.195 c 5.23 21.609 11.594 20.902 12.301 20.195 c\n"                                                                                                                                                                  \
6450     "20.078 12.414 l h\n"                                                                                                                                                                                                                      \
6451     "20.078 12.414 m S\n"                                                                                                                                                                                                                      \
6452     "0.533333 0.541176 0.521569 RG 1 w\n"                                                                                                                                                                                                      \
6453     "0 j\n"                                                                                                                                                                                                                                    \
6454     "11.949 13.184 m 16.191 8.941 l S\n"                                                                                                                                                                                                       \
6455     "0.729412 0.741176 0.713725 RG 11.949 14.184 m 16.191 9.941 l S\n"                                                                                                                                                                         \
6456     "0.533333 0.541176 0.521569 RG 14.07 6.82 m 9.828 11.062 l S\n"                                                                                                                                                                            \
6457     "0.729412 0.741176 0.713725 RG 14.07 7.82 m 9.828 12.062 l S\n"                                                                                                                                                                            \
6458     "0.533333 0.541176 0.521569 RG 6.93 15.141 m 8 20 14.27 20.5 16 20.5 c\n"                                                                                                                                                                  \
6459     "18.094 20.504 19.5 20 19.5 18 c 19.5 16.699 20.91 16.418 22.5 16.5 c S\n"                                                                                                                                                                 \
6460     "0.729412 0.741176 0.713725 RG 0.999781 w\n"                                                                                                                                                                                               \
6461     "1 j\n"                                                                                                                                                                                                                                    \
6462     "q 1 0 0 -1 0 24 cm\n"                                                                                                                                                                                                                     \
6463     "8.492 7.707 m 8.492 8.535 7.82 9.207 6.992 9.207 c 6.164 9.207 5.492\n"                                                                                                                                                                   \
6464     "8.535 5.492 7.707 c 5.492 6.879 6.164 6.207 6.992 6.207 c 7.82 6.207\n"                                                                                                                                                                   \
6465     "8.492 6.879 8.492 7.707 c h\n"                                                                                                                                                                                                            \
6466     "8.492 7.707 m S Q\n"                                                                                                                                                                                                                      \
6467     "1 w\n"                                                                                                                                                                                                                                    \
6468     "0 j\n"                                                                                                                                                                                                                                    \
6469     "6.93 16.141 m 8 21 14.27 21.5 16 21.5 c 18.094 21.504 19.5 21 19.5 19 c\n"                                                                                                                                                                \
6470     "19.5 17.699 20.91 17.418 22.5 17.5 c S\n"
6471 
draw(Gfx * gfx,bool printing)6472 void AnnotFileAttachment::draw(Gfx *gfx, bool printing)
6473 {
6474     double ca = 1;
6475 
6476     if (!isVisible(printing))
6477         return;
6478 
6479     annotLocker();
6480     if (appearance.isNull()) {
6481         ca = opacity;
6482 
6483         AnnotAppearanceBuilder appearBuilder;
6484 
6485         appearBuilder.append("q\n");
6486         if (color)
6487             appearBuilder.setDrawColor(color.get(), true);
6488         else
6489             appearBuilder.append("1 1 1 rg\n");
6490         if (!name->cmp("PushPin"))
6491             appearBuilder.append(ANNOT_FILE_ATTACHMENT_AP_PUSHPIN);
6492         else if (!name->cmp("Paperclip"))
6493             appearBuilder.append(ANNOT_FILE_ATTACHMENT_AP_PAPERCLIP);
6494         else if (!name->cmp("Graph"))
6495             appearBuilder.append(ANNOT_FILE_ATTACHMENT_AP_GRAPH);
6496         else if (!name->cmp("Tag"))
6497             appearBuilder.append(ANNOT_FILE_ATTACHMENT_AP_TAG);
6498         appearBuilder.append("Q\n");
6499 
6500         double bbox[4];
6501         bbox[0] = bbox[1] = 0;
6502         bbox[2] = bbox[3] = 24;
6503         if (ca == 1) {
6504             appearance = createForm(appearBuilder.buffer(), bbox, false, nullptr);
6505         } else {
6506             Object aStream = createForm(appearBuilder.buffer(), bbox, true, nullptr);
6507 
6508             GooString appearBuf("/GS0 gs\n/Fm0 Do");
6509             Dict *resDict = createResourcesDict("Fm0", std::move(aStream), "GS0", ca, nullptr);
6510             appearance = createForm(&appearBuf, bbox, false, resDict);
6511         }
6512     }
6513 
6514     // draw the appearance stream
6515     Object obj = appearance.fetch(gfx->getXRef());
6516     gfx->drawAnnot(&obj, nullptr, color.get(), rect->x1, rect->y1, rect->x2, rect->y2, getRotation());
6517 }
6518 
6519 //------------------------------------------------------------------------
6520 // AnnotSound
6521 //------------------------------------------------------------------------
AnnotSound(PDFDoc * docA,PDFRectangle * rectA,Sound * soundA)6522 AnnotSound::AnnotSound(PDFDoc *docA, PDFRectangle *rectA, Sound *soundA) : AnnotMarkup(docA, rectA)
6523 {
6524     type = typeSound;
6525 
6526     annotObj.dictSet("Subtype", Object(objName, "Sound"));
6527     annotObj.dictSet("Sound", soundA->getObject()->copy());
6528 
6529     initialize(docA, annotObj.getDict());
6530 }
6531 
AnnotSound(PDFDoc * docA,Object && dictObject,const Object * obj)6532 AnnotSound::AnnotSound(PDFDoc *docA, Object &&dictObject, const Object *obj) : AnnotMarkup(docA, std::move(dictObject), obj)
6533 {
6534     type = typeSound;
6535     initialize(docA, annotObj.getDict());
6536 }
6537 
6538 AnnotSound::~AnnotSound() = default;
6539 
initialize(PDFDoc * docA,Dict * dict)6540 void AnnotSound::initialize(PDFDoc *docA, Dict *dict)
6541 {
6542     Object obj1 = dict->lookup("Sound");
6543 
6544     sound = Sound::parseSound(&obj1);
6545     if (!sound) {
6546         error(errSyntaxError, -1, "Bad Annot Sound");
6547         ok = false;
6548     }
6549 
6550     obj1 = dict->lookup("Name");
6551     if (obj1.isName()) {
6552         name = std::make_unique<GooString>(obj1.getName());
6553     } else {
6554         name = std::make_unique<GooString>("Speaker");
6555     }
6556 }
6557 
6558 #define ANNOT_SOUND_AP_SPEAKER                                                                                                                                                                                                                 \
6559     "4.301 23 m 19.699 23 l 21.523 23 23 21.523 23 19.699 c 23 4.301 l 23\n"                                                                                                                                                                   \
6560     "2.477 21.523 1 19.699 1 c 4.301 1 l 2.477 1 1 2.477 1 4.301 c 1 19.699\n"                                                                                                                                                                 \
6561     "l 1 21.523 2.477 23 4.301 23 c h\n"                                                                                                                                                                                                       \
6562     "4.301 23 m f\n"                                                                                                                                                                                                                           \
6563     "0.533333 0.541176 0.521569 RG 2 w\n"                                                                                                                                                                                                      \
6564     "0 J\n"                                                                                                                                                                                                                                    \
6565     "1 j\n"                                                                                                                                                                                                                                    \
6566     "[] 0.0 d\n"                                                                                                                                                                                                                               \
6567     "4 M 4 14 m 4.086 8.043 l 7 8 l 11 4 l 11 18 l 7 14 l 4 14 l h\n"                                                                                                                                                                          \
6568     "4 14 m S\n"                                                                                                                                                                                                                               \
6569     "1 w\n"                                                                                                                                                                                                                                    \
6570     "1 J\n"                                                                                                                                                                                                                                    \
6571     "0 j\n"                                                                                                                                                                                                                                    \
6572     "13.699 15.398 m 14.699 13.398 14.699 9.398 13.699 7.398 c S\n"                                                                                                                                                                            \
6573     "18.199 19.398 m 21.199 17.398 21.199 5.398 18.199 3.398 c S\n"                                                                                                                                                                            \
6574     "16 17.398 m 18 16.398 18 7.398 16 5.398 c S\n"                                                                                                                                                                                            \
6575     "0.729412 0.741176 0.713725 RG 2 w\n"                                                                                                                                                                                                      \
6576     "0 J\n"                                                                                                                                                                                                                                    \
6577     "1 j\n"                                                                                                                                                                                                                                    \
6578     "4 15 m 4.086 9.043 l 7 9 l 11 5 l 11 19 l 7 15 l 4 15 l h\n"                                                                                                                                                                              \
6579     "4 15 m S\n"                                                                                                                                                                                                                               \
6580     "1 w\n"                                                                                                                                                                                                                                    \
6581     "1 J\n"                                                                                                                                                                                                                                    \
6582     "0 j\n"                                                                                                                                                                                                                                    \
6583     "13.699 16 m 14.699 14 14.699 10 13.699 8 c S\n"                                                                                                                                                                                           \
6584     "18.199 20 m 21.199 18 21.199 6 18.199 4 c S\n"                                                                                                                                                                                            \
6585     "16 18 m 18 17 18 8 16 6 c S\n"
6586 
6587 #define ANNOT_SOUND_AP_MIC                                                                                                                                                                                                                     \
6588     "4.301 23 m 19.699 23 l 21.523 23 23 21.523 23 19.699 c 23 4.301 l 23\n"                                                                                                                                                                   \
6589     "2.477 21.523 1 19.699 1 c 4.301 1 l 2.477 1 1 2.477 1 4.301 c 1 19.699\n"                                                                                                                                                                 \
6590     "l 1 21.523 2.477 23 4.301 23 c h\n"                                                                                                                                                                                                       \
6591     "4.301 23 m f\n"                                                                                                                                                                                                                           \
6592     "0.533333 0.541176 0.521569 RG 2 w\n"                                                                                                                                                                                                      \
6593     "1 J\n"                                                                                                                                                                                                                                    \
6594     "0 j\n"                                                                                                                                                                                                                                    \
6595     "[] 0.0 d\n"                                                                                                                                                                                                                               \
6596     "4 M 12 20 m 12 20 l 13.656 20 15 18.656 15 17 c 15 13 l 15 11.344 13.656 10\n"                                                                                                                                                            \
6597     "12 10 c 12 10 l 10.344 10 9 11.344 9 13 c 9 17 l 9 18.656 10.344 20 12\n"                                                                                                                                                                 \
6598     "20 c h\n"                                                                                                                                                                                                                                 \
6599     "12 20 m S\n"                                                                                                                                                                                                                              \
6600     "1 w\n"                                                                                                                                                                                                                                    \
6601     "17.5 14.5 m 17.5 11.973 l 17.5 8.941 15.047 6.5 12 6.5 c 8.953 6.5 6.5\n"                                                                                                                                                                 \
6602     "8.941 6.5 11.973 c 6.5 14.5 l S\n"                                                                                                                                                                                                        \
6603     "2 w\n"                                                                                                                                                                                                                                    \
6604     "0 J\n"                                                                                                                                                                                                                                    \
6605     "12 6.52 m 12 3 l S\n"                                                                                                                                                                                                                     \
6606     "1 J\n"                                                                                                                                                                                                                                    \
6607     "8 3 m 16 3 l S\n"                                                                                                                                                                                                                         \
6608     "0.729412 0.741176 0.713725 RG 12 21 m 12 21 l 13.656 21 15 19.656 15 18 c\n"                                                                                                                                                              \
6609     "15 14 l 15 12.344 13.656 11 12 11 c 12 11 l 10.344 11 9 12.344 9 14 c\n"                                                                                                                                                                  \
6610     "9 18 l 9 19.656 10.344 21 12 21 c h\n"                                                                                                                                                                                                    \
6611     "12 21 m S\n"                                                                                                                                                                                                                              \
6612     "1 w\n"                                                                                                                                                                                                                                    \
6613     "17.5 15.5 m 17.5 12.973 l 17.5 9.941 15.047 7.5 12 7.5 c 8.953 7.5 6.5\n"                                                                                                                                                                 \
6614     "9.941 6.5 12.973 c 6.5 15.5 l S\n"                                                                                                                                                                                                        \
6615     "2 w\n"                                                                                                                                                                                                                                    \
6616     "0 J\n"                                                                                                                                                                                                                                    \
6617     "12 7.52 m 12 4 l S\n"                                                                                                                                                                                                                     \
6618     "1 J\n"                                                                                                                                                                                                                                    \
6619     "8 4 m 16 4 l S\n"
6620 
draw(Gfx * gfx,bool printing)6621 void AnnotSound::draw(Gfx *gfx, bool printing)
6622 {
6623     Object obj;
6624     double ca = 1;
6625 
6626     if (!isVisible(printing))
6627         return;
6628 
6629     annotLocker();
6630     if (appearance.isNull()) {
6631         ca = opacity;
6632 
6633         AnnotAppearanceBuilder appearBuilder;
6634 
6635         appearBuilder.append("q\n");
6636         if (color)
6637             appearBuilder.setDrawColor(color.get(), true);
6638         else
6639             appearBuilder.append("1 1 1 rg\n");
6640         if (!name->cmp("Speaker"))
6641             appearBuilder.append(ANNOT_SOUND_AP_SPEAKER);
6642         else if (!name->cmp("Mic"))
6643             appearBuilder.append(ANNOT_SOUND_AP_MIC);
6644         appearBuilder.append("Q\n");
6645 
6646         double bbox[4];
6647         bbox[0] = bbox[1] = 0;
6648         bbox[2] = bbox[3] = 24;
6649         if (ca == 1) {
6650             appearance = createForm(appearBuilder.buffer(), bbox, false, nullptr);
6651         } else {
6652             Object aStream = createForm(appearBuilder.buffer(), bbox, true, nullptr);
6653 
6654             GooString appearBuf("/GS0 gs\n/Fm0 Do");
6655             Dict *resDict = createResourcesDict("Fm0", std::move(aStream), "GS0", ca, nullptr);
6656             appearance = createForm(&appearBuf, bbox, false, resDict);
6657         }
6658     }
6659 
6660     // draw the appearance stream
6661     obj = appearance.fetch(gfx->getXRef());
6662     gfx->drawAnnot(&obj, nullptr, color.get(), rect->x1, rect->y1, rect->x2, rect->y2, getRotation());
6663 }
6664 
6665 //------------------------------------------------------------------------
6666 // Annot3D
6667 //------------------------------------------------------------------------
Annot3D(PDFDoc * docA,PDFRectangle * rectA)6668 Annot3D::Annot3D(PDFDoc *docA, PDFRectangle *rectA) : Annot(docA, rectA)
6669 {
6670     type = type3D;
6671 
6672     annotObj.dictSet("Subtype", Object(objName, "3D"));
6673 
6674     initialize(docA, annotObj.getDict());
6675 }
6676 
Annot3D(PDFDoc * docA,Object && dictObject,const Object * obj)6677 Annot3D::Annot3D(PDFDoc *docA, Object &&dictObject, const Object *obj) : Annot(docA, std::move(dictObject), obj)
6678 {
6679     type = type3D;
6680     initialize(docA, annotObj.getDict());
6681 }
6682 
6683 Annot3D::~Annot3D() = default;
6684 
initialize(PDFDoc * docA,Dict * dict)6685 void Annot3D::initialize(PDFDoc *docA, Dict *dict)
6686 {
6687     Object obj1 = dict->lookup("3DA");
6688     if (obj1.isDict()) {
6689         activation = std::make_unique<Activation>(obj1.getDict());
6690     }
6691 }
6692 
Activation(Dict * dict)6693 Annot3D::Activation::Activation(Dict *dict)
6694 {
6695     Object obj1;
6696 
6697     obj1 = dict->lookup("A");
6698     if (obj1.isName()) {
6699         const char *name = obj1.getName();
6700 
6701         if (!strcmp(name, "PO")) {
6702             aTrigger = aTriggerPageOpened;
6703         } else if (!strcmp(name, "PV")) {
6704             aTrigger = aTriggerPageVisible;
6705         } else if (!strcmp(name, "XA")) {
6706             aTrigger = aTriggerUserAction;
6707         } else {
6708             aTrigger = aTriggerUnknown;
6709         }
6710     } else {
6711         aTrigger = aTriggerUnknown;
6712     }
6713 
6714     obj1 = dict->lookup("AIS");
6715     if (obj1.isName()) {
6716         const char *name = obj1.getName();
6717 
6718         if (!strcmp(name, "I")) {
6719             aState = aStateEnabled;
6720         } else if (!strcmp(name, "L")) {
6721             aState = aStateDisabled;
6722         } else {
6723             aState = aStateUnknown;
6724         }
6725     } else {
6726         aState = aStateUnknown;
6727     }
6728 
6729     obj1 = dict->lookup("D");
6730     if (obj1.isName()) {
6731         const char *name = obj1.getName();
6732 
6733         if (!strcmp(name, "PC")) {
6734             dTrigger = dTriggerPageClosed;
6735         } else if (!strcmp(name, "PI")) {
6736             dTrigger = dTriggerPageInvisible;
6737         } else if (!strcmp(name, "XD")) {
6738             dTrigger = dTriggerUserAction;
6739         } else {
6740             dTrigger = dTriggerUnknown;
6741         }
6742     } else {
6743         dTrigger = dTriggerUnknown;
6744     }
6745 
6746     obj1 = dict->lookup("DIS");
6747     if (obj1.isName()) {
6748         const char *name = obj1.getName();
6749 
6750         if (!strcmp(name, "U")) {
6751             dState = dStateUninstantiaded;
6752         } else if (!strcmp(name, "I")) {
6753             dState = dStateInstantiated;
6754         } else if (!strcmp(name, "L")) {
6755             dState = dStateLive;
6756         } else {
6757             dState = dStateUnknown;
6758         }
6759     } else {
6760         dState = dStateUnknown;
6761     }
6762 
6763     displayToolbar = dict->lookup("TB").getBoolWithDefaultValue(true);
6764 
6765     displayNavigation = dict->lookup("NP").getBoolWithDefaultValue(false);
6766 }
6767 
6768 //------------------------------------------------------------------------
6769 // AnnotRichMedia
6770 //------------------------------------------------------------------------
AnnotRichMedia(PDFDoc * docA,PDFRectangle * rectA)6771 AnnotRichMedia::AnnotRichMedia(PDFDoc *docA, PDFRectangle *rectA) : Annot(docA, rectA)
6772 {
6773     type = typeRichMedia;
6774 
6775     annotObj.dictSet("Subtype", Object(objName, "RichMedia"));
6776 
6777     initialize(docA, annotObj.getDict());
6778 }
6779 
AnnotRichMedia(PDFDoc * docA,Object && dictObject,const Object * obj)6780 AnnotRichMedia::AnnotRichMedia(PDFDoc *docA, Object &&dictObject, const Object *obj) : Annot(docA, std::move(dictObject), obj)
6781 {
6782     type = typeRichMedia;
6783     initialize(docA, annotObj.getDict());
6784 }
6785 
6786 AnnotRichMedia::~AnnotRichMedia() = default;
6787 
initialize(PDFDoc * docA,Dict * dict)6788 void AnnotRichMedia::initialize(PDFDoc *docA, Dict *dict)
6789 {
6790     Object obj1 = dict->lookup("RichMediaContent");
6791     if (obj1.isDict()) {
6792         content = std::make_unique<AnnotRichMedia::Content>(obj1.getDict());
6793     }
6794 
6795     obj1 = dict->lookup("RichMediaSettings");
6796     if (obj1.isDict()) {
6797         settings = std::make_unique<AnnotRichMedia::Settings>(obj1.getDict());
6798     }
6799 }
6800 
getContent() const6801 AnnotRichMedia::Content *AnnotRichMedia::getContent() const
6802 {
6803     return content.get();
6804 }
6805 
getSettings() const6806 AnnotRichMedia::Settings *AnnotRichMedia::getSettings() const
6807 {
6808     return settings.get();
6809 }
6810 
Settings(Dict * dict)6811 AnnotRichMedia::Settings::Settings(Dict *dict)
6812 {
6813     Object obj1 = dict->lookup("Activation");
6814     if (obj1.isDict()) {
6815         activation = std::make_unique<AnnotRichMedia::Activation>(obj1.getDict());
6816     }
6817 
6818     obj1 = dict->lookup("Deactivation");
6819     if (obj1.isDict()) {
6820         deactivation = std::make_unique<AnnotRichMedia::Deactivation>(obj1.getDict());
6821     }
6822 }
6823 
6824 AnnotRichMedia::Settings::~Settings() = default;
6825 
getActivation() const6826 AnnotRichMedia::Activation *AnnotRichMedia::Settings::getActivation() const
6827 {
6828     return activation.get();
6829 }
6830 
getDeactivation() const6831 AnnotRichMedia::Deactivation *AnnotRichMedia::Settings::getDeactivation() const
6832 {
6833     return deactivation.get();
6834 }
6835 
Activation(Dict * dict)6836 AnnotRichMedia::Activation::Activation(Dict *dict)
6837 {
6838     Object obj1 = dict->lookup("Condition");
6839     if (obj1.isName()) {
6840         const char *name = obj1.getName();
6841 
6842         if (!strcmp(name, "PO")) {
6843             condition = conditionPageOpened;
6844         } else if (!strcmp(name, "PV")) {
6845             condition = conditionPageVisible;
6846         } else if (!strcmp(name, "XA")) {
6847             condition = conditionUserAction;
6848         } else {
6849             condition = conditionUserAction;
6850         }
6851     } else {
6852         condition = conditionUserAction;
6853     }
6854 }
6855 
getCondition() const6856 AnnotRichMedia::Activation::Condition AnnotRichMedia::Activation::getCondition() const
6857 {
6858     return condition;
6859 }
6860 
Deactivation(Dict * dict)6861 AnnotRichMedia::Deactivation::Deactivation(Dict *dict)
6862 {
6863     Object obj1 = dict->lookup("Condition");
6864     if (obj1.isName()) {
6865         const char *name = obj1.getName();
6866 
6867         if (!strcmp(name, "PC")) {
6868             condition = conditionPageClosed;
6869         } else if (!strcmp(name, "PI")) {
6870             condition = conditionPageInvisible;
6871         } else if (!strcmp(name, "XD")) {
6872             condition = conditionUserAction;
6873         } else {
6874             condition = conditionUserAction;
6875         }
6876     } else {
6877         condition = conditionUserAction;
6878     }
6879 }
6880 
getCondition() const6881 AnnotRichMedia::Deactivation::Condition AnnotRichMedia::Deactivation::getCondition() const
6882 {
6883     return condition;
6884 }
6885 
Content(Dict * dict)6886 AnnotRichMedia::Content::Content(Dict *dict)
6887 {
6888     Object obj1 = dict->lookup("Configurations");
6889     if (obj1.isArray()) {
6890         nConfigurations = obj1.arrayGetLength();
6891 
6892         configurations = (Configuration **)gmallocn(nConfigurations, sizeof(Configuration *));
6893 
6894         for (int i = 0; i < nConfigurations; ++i) {
6895             Object obj2 = obj1.arrayGet(i);
6896             if (obj2.isDict()) {
6897                 configurations[i] = new AnnotRichMedia::Configuration(obj2.getDict());
6898             } else {
6899                 configurations[i] = nullptr;
6900             }
6901         }
6902     } else {
6903         nConfigurations = 0;
6904         configurations = nullptr;
6905     }
6906 
6907     nAssets = 0;
6908     assets = nullptr;
6909     obj1 = dict->lookup("Assets");
6910     if (obj1.isDict()) {
6911         Object obj2 = obj1.getDict()->lookup("Names");
6912         if (obj2.isArray()) {
6913             const int length = obj2.arrayGetLength() / 2;
6914 
6915             assets = (Asset **)gmallocn(length, sizeof(Asset *));
6916             for (int i = 0; i < length; ++i) {
6917                 Object objKey = obj2.arrayGet(2 * i);
6918                 Object objVal = obj2.arrayGet(2 * i + 1);
6919 
6920                 if (!objKey.isString() || objVal.isNull()) {
6921                     error(errSyntaxError, -1, "Bad Annot Asset");
6922                     continue;
6923                 }
6924 
6925                 assets[nAssets] = new AnnotRichMedia::Asset;
6926                 assets[nAssets]->name = std::make_unique<GooString>(objKey.getString());
6927                 assets[nAssets]->fileSpec = std::move(objVal);
6928                 ++nAssets;
6929             }
6930         }
6931     }
6932 }
6933 
~Content()6934 AnnotRichMedia::Content::~Content()
6935 {
6936     if (configurations) {
6937         for (int i = 0; i < nConfigurations; ++i)
6938             delete configurations[i];
6939         gfree(configurations);
6940     }
6941 
6942     if (assets) {
6943         for (int i = 0; i < nAssets; ++i)
6944             delete assets[i];
6945         gfree(assets);
6946     }
6947 }
6948 
getConfigurationsCount() const6949 int AnnotRichMedia::Content::getConfigurationsCount() const
6950 {
6951     return nConfigurations;
6952 }
6953 
getConfiguration(int index) const6954 AnnotRichMedia::Configuration *AnnotRichMedia::Content::getConfiguration(int index) const
6955 {
6956     if (index < 0 || index >= nConfigurations)
6957         return nullptr;
6958 
6959     return configurations[index];
6960 }
6961 
getAssetsCount() const6962 int AnnotRichMedia::Content::getAssetsCount() const
6963 {
6964     return nAssets;
6965 }
6966 
getAsset(int index) const6967 AnnotRichMedia::Asset *AnnotRichMedia::Content::getAsset(int index) const
6968 {
6969     if (index < 0 || index >= nAssets)
6970         return nullptr;
6971 
6972     return assets[index];
6973 }
6974 
6975 AnnotRichMedia::Asset::Asset() = default;
6976 
6977 AnnotRichMedia::Asset::~Asset() = default;
6978 
getName() const6979 const GooString *AnnotRichMedia::Asset::getName() const
6980 {
6981     return name.get();
6982 }
6983 
getFileSpec() const6984 Object *AnnotRichMedia::Asset::getFileSpec() const
6985 {
6986     return const_cast<Object *>(&fileSpec);
6987 }
6988 
Configuration(Dict * dict)6989 AnnotRichMedia::Configuration::Configuration(Dict *dict)
6990 {
6991     Object obj1 = dict->lookup("Instances");
6992     if (obj1.isArray()) {
6993         nInstances = obj1.arrayGetLength();
6994 
6995         instances = (Instance **)gmallocn(nInstances, sizeof(Instance *));
6996 
6997         for (int i = 0; i < nInstances; ++i) {
6998             Object obj2 = obj1.arrayGet(i);
6999             if (obj2.isDict()) {
7000                 instances[i] = new AnnotRichMedia::Instance(obj2.getDict());
7001             } else {
7002                 instances[i] = nullptr;
7003             }
7004         }
7005     } else {
7006         instances = nullptr;
7007     }
7008 
7009     obj1 = dict->lookup("Name");
7010     if (obj1.isString()) {
7011         name = std::make_unique<GooString>(obj1.getString());
7012     }
7013 
7014     obj1 = dict->lookup("Subtype");
7015     if (obj1.isName()) {
7016         const char *subtypeName = obj1.getName();
7017 
7018         if (!strcmp(subtypeName, "3D")) {
7019             type = type3D;
7020         } else if (!strcmp(subtypeName, "Flash")) {
7021             type = typeFlash;
7022         } else if (!strcmp(subtypeName, "Sound")) {
7023             type = typeSound;
7024         } else if (!strcmp(subtypeName, "Video")) {
7025             type = typeVideo;
7026         } else {
7027             // determine from first non null instance
7028             type = typeFlash; // default in case all instances are null
7029             if (instances && nInstances > 0) {
7030                 for (int i = 0; i < nInstances; ++i) {
7031                     AnnotRichMedia::Instance *instance = instances[i];
7032                     if (instance) {
7033                         switch (instance->getType()) {
7034                         case AnnotRichMedia::Instance::type3D:
7035                             type = type3D;
7036                             break;
7037                         case AnnotRichMedia::Instance::typeFlash:
7038                             type = typeFlash;
7039                             break;
7040                         case AnnotRichMedia::Instance::typeSound:
7041                             type = typeSound;
7042                             break;
7043                         case AnnotRichMedia::Instance::typeVideo:
7044                             type = typeVideo;
7045                             break;
7046                         }
7047                         // break the loop since we found the first non null instance
7048                         break;
7049                     }
7050                 }
7051             }
7052         }
7053     }
7054 }
7055 
~Configuration()7056 AnnotRichMedia::Configuration::~Configuration()
7057 {
7058     if (instances) {
7059         for (int i = 0; i < nInstances; ++i)
7060             delete instances[i];
7061         gfree(instances);
7062     }
7063 }
7064 
getInstancesCount() const7065 int AnnotRichMedia::Configuration::getInstancesCount() const
7066 {
7067     return nInstances;
7068 }
7069 
getInstance(int index) const7070 AnnotRichMedia::Instance *AnnotRichMedia::Configuration::getInstance(int index) const
7071 {
7072     if (index < 0 || index >= nInstances)
7073         return nullptr;
7074 
7075     return instances[index];
7076 }
7077 
getName() const7078 const GooString *AnnotRichMedia::Configuration::getName() const
7079 {
7080     return name.get();
7081 }
7082 
getType() const7083 AnnotRichMedia::Configuration::Type AnnotRichMedia::Configuration::getType() const
7084 {
7085     return type;
7086 }
7087 
Instance(Dict * dict)7088 AnnotRichMedia::Instance::Instance(Dict *dict)
7089 {
7090     Object obj1 = dict->lookup("Subtype");
7091     const char *name = obj1.isName() ? obj1.getName() : "";
7092 
7093     if (!strcmp(name, "3D")) {
7094         type = type3D;
7095     } else if (!strcmp(name, "Flash")) {
7096         type = typeFlash;
7097     } else if (!strcmp(name, "Sound")) {
7098         type = typeSound;
7099     } else if (!strcmp(name, "Video")) {
7100         type = typeVideo;
7101     } else {
7102         type = typeFlash;
7103     }
7104 
7105     obj1 = dict->lookup("Params");
7106     if (obj1.isDict()) {
7107         params = std::make_unique<AnnotRichMedia::Params>(obj1.getDict());
7108     }
7109 }
7110 
7111 AnnotRichMedia::Instance::~Instance() = default;
7112 
getType() const7113 AnnotRichMedia::Instance::Type AnnotRichMedia::Instance::getType() const
7114 {
7115     return type;
7116 }
7117 
getParams() const7118 AnnotRichMedia::Params *AnnotRichMedia::Instance::getParams() const
7119 {
7120     return params.get();
7121 }
7122 
Params(Dict * dict)7123 AnnotRichMedia::Params::Params(Dict *dict)
7124 {
7125     Object obj1 = dict->lookup("FlashVars");
7126     if (obj1.isString()) {
7127         flashVars = std::make_unique<GooString>(obj1.getString());
7128     }
7129 }
7130 
7131 AnnotRichMedia::Params::~Params() = default;
7132 
getFlashVars() const7133 const GooString *AnnotRichMedia::Params::getFlashVars() const
7134 {
7135     return flashVars.get();
7136 }
7137 
7138 //------------------------------------------------------------------------
7139 // Annots
7140 //------------------------------------------------------------------------
7141 
Annots(PDFDoc * docA,int page,Object * annotsObj)7142 Annots::Annots(PDFDoc *docA, int page, Object *annotsObj)
7143 {
7144     Annot *annot;
7145     int i;
7146 
7147     doc = docA;
7148 
7149     if (annotsObj->isArray()) {
7150         for (i = 0; i < annotsObj->arrayGetLength(); ++i) {
7151             // get the Ref to this annot and pass it to Annot constructor
7152             // this way, it'll be possible for the annot to retrieve the corresponding
7153             // form widget
7154             Object obj1 = annotsObj->arrayGet(i);
7155             if (obj1.isDict()) {
7156                 const Object &obj2 = annotsObj->arrayGetNF(i);
7157                 annot = createAnnot(std::move(obj1), &obj2);
7158                 if (annot) {
7159                     if (annot->isOk()) {
7160                         annot->setPage(page, false); // Don't change /P
7161                         appendAnnot(annot);
7162                     }
7163                     annot->decRefCnt();
7164                 }
7165             }
7166         }
7167     }
7168 }
7169 
appendAnnot(Annot * annot)7170 void Annots::appendAnnot(Annot *annot)
7171 {
7172     if (annot && annot->isOk()) {
7173         annots.push_back(annot);
7174         annot->incRefCnt();
7175     }
7176 }
7177 
removeAnnot(Annot * annot)7178 bool Annots::removeAnnot(Annot *annot)
7179 {
7180     auto idx = std::find(annots.begin(), annots.end(), annot);
7181 
7182     if (idx == annots.end()) {
7183         return false;
7184     } else {
7185         annot->decRefCnt();
7186         annots.erase(idx);
7187         return true;
7188     }
7189 }
7190 
createAnnot(Object && dictObject,const Object * obj)7191 Annot *Annots::createAnnot(Object &&dictObject, const Object *obj)
7192 {
7193     Annot *annot = nullptr;
7194     Object obj1 = dictObject.dictLookup("Subtype");
7195     if (obj1.isName()) {
7196         const char *typeName = obj1.getName();
7197 
7198         if (!strcmp(typeName, "Text")) {
7199             annot = new AnnotText(doc, std::move(dictObject), obj);
7200         } else if (!strcmp(typeName, "Link")) {
7201             annot = new AnnotLink(doc, std::move(dictObject), obj);
7202         } else if (!strcmp(typeName, "FreeText")) {
7203             annot = new AnnotFreeText(doc, std::move(dictObject), obj);
7204         } else if (!strcmp(typeName, "Line")) {
7205             annot = new AnnotLine(doc, std::move(dictObject), obj);
7206         } else if (!strcmp(typeName, "Square")) {
7207             annot = new AnnotGeometry(doc, std::move(dictObject), obj);
7208         } else if (!strcmp(typeName, "Circle")) {
7209             annot = new AnnotGeometry(doc, std::move(dictObject), obj);
7210         } else if (!strcmp(typeName, "Polygon")) {
7211             annot = new AnnotPolygon(doc, std::move(dictObject), obj);
7212         } else if (!strcmp(typeName, "PolyLine")) {
7213             annot = new AnnotPolygon(doc, std::move(dictObject), obj);
7214         } else if (!strcmp(typeName, "Highlight")) {
7215             annot = new AnnotTextMarkup(doc, std::move(dictObject), obj);
7216         } else if (!strcmp(typeName, "Underline")) {
7217             annot = new AnnotTextMarkup(doc, std::move(dictObject), obj);
7218         } else if (!strcmp(typeName, "Squiggly")) {
7219             annot = new AnnotTextMarkup(doc, std::move(dictObject), obj);
7220         } else if (!strcmp(typeName, "StrikeOut")) {
7221             annot = new AnnotTextMarkup(doc, std::move(dictObject), obj);
7222         } else if (!strcmp(typeName, "Stamp")) {
7223             annot = new AnnotStamp(doc, std::move(dictObject), obj);
7224         } else if (!strcmp(typeName, "Caret")) {
7225             annot = new AnnotCaret(doc, std::move(dictObject), obj);
7226         } else if (!strcmp(typeName, "Ink")) {
7227             annot = new AnnotInk(doc, std::move(dictObject), obj);
7228         } else if (!strcmp(typeName, "FileAttachment")) {
7229             annot = new AnnotFileAttachment(doc, std::move(dictObject), obj);
7230         } else if (!strcmp(typeName, "Sound")) {
7231             annot = new AnnotSound(doc, std::move(dictObject), obj);
7232         } else if (!strcmp(typeName, "Movie")) {
7233             annot = new AnnotMovie(doc, std::move(dictObject), obj);
7234         } else if (!strcmp(typeName, "Widget")) {
7235             // Find the annot in forms
7236             if (obj->isRef()) {
7237                 Form *form = doc->getCatalog()->getForm();
7238                 if (form) {
7239                     FormWidget *widget = form->findWidgetByRef(obj->getRef());
7240                     if (widget) {
7241                         annot = widget->getWidgetAnnotation();
7242                         annot->incRefCnt();
7243                     }
7244                 }
7245             }
7246             if (!annot)
7247                 annot = new AnnotWidget(doc, std::move(dictObject), obj);
7248         } else if (!strcmp(typeName, "Screen")) {
7249             annot = new AnnotScreen(doc, std::move(dictObject), obj);
7250         } else if (!strcmp(typeName, "PrinterMark")) {
7251             annot = new Annot(doc, std::move(dictObject), obj);
7252         } else if (!strcmp(typeName, "TrapNet")) {
7253             annot = new Annot(doc, std::move(dictObject), obj);
7254         } else if (!strcmp(typeName, "Watermark")) {
7255             annot = new Annot(doc, std::move(dictObject), obj);
7256         } else if (!strcmp(typeName, "3D")) {
7257             annot = new Annot3D(doc, std::move(dictObject), obj);
7258         } else if (!strcmp(typeName, "RichMedia")) {
7259             annot = new AnnotRichMedia(doc, std::move(dictObject), obj);
7260         } else if (!strcmp(typeName, "Popup")) {
7261             /* Popup annots are already handled by markup annots
7262              * Here we only care about popup annots without a
7263              * markup annotation associated
7264              */
7265             Object obj2 = dictObject.dictLookup("Parent");
7266             if (obj2.isNull())
7267                 annot = new AnnotPopup(doc, std::move(dictObject), obj);
7268             else
7269                 annot = nullptr;
7270         } else {
7271             annot = new Annot(doc, std::move(dictObject), obj);
7272         }
7273     }
7274 
7275     return annot;
7276 }
7277 
findAnnot(Ref * ref)7278 Annot *Annots::findAnnot(Ref *ref)
7279 {
7280     for (auto *annot : annots) {
7281         if (annot->match(ref)) {
7282             return annot;
7283         }
7284     }
7285     return nullptr;
7286 }
7287 
~Annots()7288 Annots::~Annots()
7289 {
7290     for (auto *annot : annots) {
7291         annot->decRefCnt();
7292     }
7293 }
7294 
7295 //------------------------------------------------------------------------
7296 // AnnotAppearanceBuilder
7297 //------------------------------------------------------------------------
7298 
AnnotAppearanceBuilder()7299 AnnotAppearanceBuilder::AnnotAppearanceBuilder() : appearBuf(new GooString()) { }
7300 
~AnnotAppearanceBuilder()7301 AnnotAppearanceBuilder::~AnnotAppearanceBuilder()
7302 {
7303     delete appearBuf;
7304 }
7305 
append(const char * text)7306 void AnnotAppearanceBuilder::append(const char *text)
7307 {
7308     appearBuf->append(text);
7309 }
7310 
appendf(const char * fmt,...)7311 void AnnotAppearanceBuilder::appendf(const char *fmt, ...) GOOSTRING_FORMAT
7312 {
7313     va_list argList;
7314 
7315     va_start(argList, fmt);
7316     appearBuf->appendfv(fmt, argList);
7317     va_end(argList);
7318 }
7319 
buffer() const7320 const GooString *AnnotAppearanceBuilder::buffer() const
7321 {
7322     return appearBuf;
7323 }
7324