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