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