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-2011 Albert Astals Cid <aacid@kde.org>
19 // Copyright (C) 2007-2011 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 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 //
27 // To see a description of the changes please see the Changelog file that
28 // came with your tarball or type make ChangeLog if you are building from git
29 //
30 //========================================================================
31 
32 #include <config.h>
33 
34 #ifdef USE_GCC_PRAGMAS
35 #pragma implementation
36 #endif
37 
38 #include <stdlib.h>
39 #include <math.h>
40 #include <assert.h>
41 #include "goo/gmem.h"
42 #include "goo/gstrtod.h"
43 #include "GooList.h"
44 #include "Error.h"
45 #include "Object.h"
46 #include "Catalog.h"
47 #include "Gfx.h"
48 #include "Lexer.h"
49 #include "Annot.h"
50 #include "GfxFont.h"
51 #include "CharCodeToUnicode.h"
52 #include "PDFDocEncoding.h"
53 #include "Form.h"
54 #include "Error.h"
55 #include "Page.h"
56 #include "XRef.h"
57 #include "Movie.h"
58 #include "OptionalContent.h"
59 #include "Sound.h"
60 #include "FileSpec.h"
61 #include "DateInfo.h"
62 #include "Link.h"
63 #include <string.h>
64 
65 #define fieldFlagReadOnly           0x00000001
66 #define fieldFlagRequired           0x00000002
67 #define fieldFlagNoExport           0x00000004
68 #define fieldFlagMultiline          0x00001000
69 #define fieldFlagPassword           0x00002000
70 #define fieldFlagNoToggleToOff      0x00004000
71 #define fieldFlagRadio              0x00008000
72 #define fieldFlagPushbutton         0x00010000
73 #define fieldFlagCombo              0x00020000
74 #define fieldFlagEdit               0x00040000
75 #define fieldFlagSort               0x00080000
76 #define fieldFlagFileSelect         0x00100000
77 #define fieldFlagMultiSelect        0x00200000
78 #define fieldFlagDoNotSpellCheck    0x00400000
79 #define fieldFlagDoNotScroll        0x00800000
80 #define fieldFlagComb               0x01000000
81 #define fieldFlagRichText           0x02000000
82 #define fieldFlagRadiosInUnison     0x02000000
83 #define fieldFlagCommitOnSelChange  0x04000000
84 
85 #define fieldQuadLeft   0
86 #define fieldQuadCenter 1
87 #define fieldQuadRight  2
88 
89 // distance of Bezier control point from center for circle approximation
90 // = (4 * (sqrt(2) - 1) / 3) * r
91 #define bezierCircle 0.55228475
92 
93 // Ensures that x is between the limits set by low and high.
94 // If low is greater than high the result is undefined.
95 #define CLAMP(x, low, high)  (((x) > (high)) ? (high) : (((x) < (low)) ? (low) : (x)))
96 
parseAnnotLineEndingStyle(GooString * string)97 AnnotLineEndingStyle parseAnnotLineEndingStyle(GooString *string) {
98   if (string != NULL) {
99     if (!string->cmp("Square")) {
100       return annotLineEndingSquare;
101     } else if (!string->cmp("Circle")) {
102       return annotLineEndingCircle;
103     } else if (!string->cmp("Diamond")) {
104       return annotLineEndingDiamond;
105     } else if (!string->cmp("OpenArrow")) {
106       return annotLineEndingOpenArrow;
107     } else if (!string->cmp("ClosedArrow")) {
108       return annotLineEndingClosedArrow;
109     } else if (!string->cmp("Butt")) {
110       return annotLineEndingButt;
111     } else if (!string->cmp("ROpenArrow")) {
112       return annotLineEndingROpenArrow;
113     } else if (!string->cmp("RClosedArrow")) {
114       return annotLineEndingRClosedArrow;
115     } else if (!string->cmp("Slash")) {
116       return annotLineEndingSlash;
117     } else {
118       return annotLineEndingNone;
119     }
120   } else {
121     return annotLineEndingNone;
122   }
123 }
124 
parseAnnotExternalData(Dict * dict)125 static AnnotExternalDataType parseAnnotExternalData(Dict* dict) {
126   Object obj1;
127   AnnotExternalDataType type;
128 
129   if (dict->lookup("Subtype", &obj1)->isName()) {
130     GooString *typeName = new GooString(obj1.getName());
131 
132     if (!typeName->cmp("Markup3D")) {
133       type = annotExternalDataMarkup3D;
134     } else {
135       type = annotExternalDataMarkupUnknown;
136     }
137     delete typeName;
138   } else {
139     type = annotExternalDataMarkupUnknown;
140   }
141   obj1.free();
142 
143   return type;
144 }
145 
parseDiffRectangle(Array * array,PDFRectangle * rect)146 PDFRectangle *parseDiffRectangle(Array *array, PDFRectangle *rect) {
147   PDFRectangle *newRect = NULL;
148   if (array->getLength() == 4) {
149     // deltas
150     Object obj1;
151     double dx1 = (array->get(0, &obj1)->isNum() ? obj1.getNum() : 0);
152     obj1.free();
153     double dy1 = (array->get(1, &obj1)->isNum() ? obj1.getNum() : 0);
154     obj1.free();
155     double dx2 = (array->get(2, &obj1)->isNum() ? obj1.getNum() : 0);
156     obj1.free();
157     double dy2 = (array->get(3, &obj1)->isNum() ? obj1.getNum() : 0);
158     obj1.free();
159 
160     // checking that the numbers are valid (i.e. >= 0),
161     // and that applying the differences still give us a valid rect
162     if (dx1 >= 0 && dy1 >= 0 && dx2 >= 0 && dy2
163         && (rect->x2 - rect->x1 - dx1 - dx2) >= 0
164         && (rect->y2 - rect->y1 - dy1 - dy2) >= 0) {
165       newRect = new PDFRectangle();
166       newRect->x1 = rect->x1 + dx1;
167       newRect->y1 = rect->y1 + dy1;
168       newRect->x2 = rect->x2 - dx2;
169       newRect->y2 = rect->y2 - dy2;
170     }
171   }
172   return newRect;
173 }
174 
175 //------------------------------------------------------------------------
176 // AnnotBorderEffect
177 //------------------------------------------------------------------------
178 
AnnotBorderEffect(Dict * dict)179 AnnotBorderEffect::AnnotBorderEffect(Dict *dict) {
180   Object obj1;
181 
182   if (dict->lookup("S", &obj1)->isName()) {
183     GooString *effectName = new GooString(obj1.getName());
184 
185     if (!effectName->cmp("C"))
186       effectType = borderEffectCloudy;
187     else
188       effectType = borderEffectNoEffect;
189     delete effectName;
190   } else {
191     effectType = borderEffectNoEffect;
192   }
193   obj1.free();
194 
195   if ((dict->lookup("I", &obj1)->isNum()) && effectType == borderEffectCloudy) {
196     intensity = obj1.getNum();
197   } else {
198     intensity = 0;
199   }
200   obj1.free();
201 }
202 
203 //------------------------------------------------------------------------
204 // AnnotPath
205 //------------------------------------------------------------------------
206 
AnnotPath()207 AnnotPath::AnnotPath() {
208   coords = NULL;
209   coordsLength = 0;
210 }
211 
AnnotPath(Array * array)212 AnnotPath::AnnotPath(Array *array) {
213   coords = NULL;
214   coordsLength = 0;
215   parsePathArray(array);
216 }
217 
AnnotPath(AnnotCoord ** coords,int coordsLength)218 AnnotPath::AnnotPath(AnnotCoord **coords, int coordsLength) {
219   this->coords = coords;
220   this->coordsLength = coordsLength;
221 }
222 
~AnnotPath()223 AnnotPath::~AnnotPath() {
224   if (coords) {
225     for (int i = 0; i < coordsLength; ++i)
226       delete coords[i];
227     gfree(coords);
228   }
229 }
230 
getX(int coord) const231 double AnnotPath::getX(int coord) const {
232   if (coord >= 0 && coord < coordsLength)
233     return coords[coord]->getX();
234   return 0;
235 }
236 
getY(int coord) const237 double AnnotPath::getY(int coord) const {
238   if (coord >= 0 && coord < coordsLength)
239     return coords[coord]->getY();
240   return 0;
241 }
242 
getCoord(int coord) const243 AnnotCoord *AnnotPath::getCoord(int coord) const {
244   if (coord >= 0 && coord < coordsLength)
245     return coords[coord];
246   return NULL;
247 }
248 
parsePathArray(Array * array)249 void AnnotPath::parsePathArray(Array *array) {
250   int tempLength;
251   AnnotCoord **tempCoords;
252   GBool correct = gTrue;
253 
254   if (array->getLength() % 2) {
255     error(-1, "Bad Annot Path");
256     return;
257   }
258 
259   tempLength = array->getLength() / 2;
260   tempCoords = (AnnotCoord **) gmallocn (tempLength, sizeof(AnnotCoord *));
261   memset(tempCoords, 0, tempLength * sizeof(AnnotCoord *));
262   for (int i = 0; i < tempLength && correct; i++) {
263     Object obj1;
264     double x = 0, y = 0;
265 
266     if (array->get(i * 2, &obj1)->isNum()) {
267       x = obj1.getNum();
268     } else {
269       correct = gFalse;
270     }
271     obj1.free();
272 
273     if (array->get((i * 2) + 1, &obj1)->isNum()) {
274       y = obj1.getNum();
275     } else {
276       correct = gFalse;
277     }
278     obj1.free();
279 
280     if (!correct) {
281       for (int j = i - 1; j >= 0; j--)
282         delete tempCoords[j];
283       gfree (tempCoords);
284       return;
285     }
286 
287     tempCoords[i] = new AnnotCoord(x, y);
288   }
289 
290   coords = tempCoords;
291   coordsLength = tempLength;
292 }
293 
294 //------------------------------------------------------------------------
295 // AnnotCalloutLine
296 //------------------------------------------------------------------------
297 
AnnotCalloutLine(double x1,double y1,double x2,double y2)298 AnnotCalloutLine::AnnotCalloutLine(double x1, double y1, double x2, double y2)
299     :  coord1(x1, y1), coord2(x2, y2) {
300 }
301 
302 //------------------------------------------------------------------------
303 // AnnotCalloutMultiLine
304 //------------------------------------------------------------------------
305 
AnnotCalloutMultiLine(double x1,double y1,double x2,double y2,double x3,double y3)306 AnnotCalloutMultiLine::AnnotCalloutMultiLine(double x1, double y1, double x2,
307                                              double y2, double x3, double y3)
308     : AnnotCalloutLine(x1, y1, x2, y2), coord3(x3, y3) {
309 }
310 
311 //------------------------------------------------------------------------
312 // AnnotQuadrilateral
313 //------------------------------------------------------------------------
314 
AnnotQuadrilaterals(Array * array,PDFRectangle * rect)315 AnnotQuadrilaterals::AnnotQuadrilaterals(Array *array, PDFRectangle *rect) {
316   int arrayLength = array->getLength();
317   GBool correct = gTrue;
318   int quadsLength = 0;
319   AnnotQuadrilateral **quads;
320   double quadArray[8];
321 
322   // default values
323   quadrilaterals = NULL;
324   quadrilateralsLength = 0;
325 
326   if ((arrayLength % 8) == 0) {
327     int i;
328 
329     quadsLength = arrayLength / 8;
330     quads = (AnnotQuadrilateral **) gmallocn
331         ((quadsLength), sizeof(AnnotQuadrilateral *));
332     memset(quads, 0, quadsLength * sizeof(AnnotQuadrilateral *));
333 
334     for (i = 0; i < quadsLength; i++) {
335       for (int j = 0; j < 8; j++) {
336         Object obj;
337         if (array->get(i * 8 + j, &obj)->isNum()) {
338           if (j % 2 == 1)
339 	    quadArray[j] = CLAMP (obj.getNum(), rect->y1, rect->y2);
340           else
341 	    quadArray[j] = CLAMP (obj.getNum(), rect->x1, rect->x2);
342         } else {
343             correct = gFalse;
344 	    obj.free();
345 	    error (-1, "Invalid QuadPoint in annot");
346 	    break;
347         }
348         obj.free();
349       }
350 
351       if (!correct)
352         break;
353 
354       quads[i] = new AnnotQuadrilateral(quadArray[0], quadArray[1],
355 					quadArray[2], quadArray[3],
356 					quadArray[4], quadArray[5],
357 					quadArray[6], quadArray[7]);
358     }
359 
360     if (correct) {
361       quadrilateralsLength = quadsLength;
362       quadrilaterals = quads;
363     } else {
364       for (int j = 0; j < i; j++)
365         delete quads[j];
366       gfree (quads);
367     }
368   }
369 }
370 
~AnnotQuadrilaterals()371 AnnotQuadrilaterals::~AnnotQuadrilaterals() {
372   if (quadrilaterals) {
373     for(int i = 0; i < quadrilateralsLength; i++)
374       delete quadrilaterals[i];
375 
376     gfree (quadrilaterals);
377   }
378 }
379 
getX1(int quadrilateral)380 double AnnotQuadrilaterals::getX1(int quadrilateral) {
381   if (quadrilateral >= 0  && quadrilateral < quadrilateralsLength)
382     return quadrilaterals[quadrilateral]->coord1.getX();
383   return 0;
384 }
385 
getY1(int quadrilateral)386 double AnnotQuadrilaterals::getY1(int quadrilateral) {
387   if (quadrilateral >= 0  && quadrilateral < quadrilateralsLength)
388     return quadrilaterals[quadrilateral]->coord1.getY();
389   return 0;
390 }
391 
getX2(int quadrilateral)392 double AnnotQuadrilaterals::getX2(int quadrilateral) {
393   if (quadrilateral >= 0  && quadrilateral < quadrilateralsLength)
394     return quadrilaterals[quadrilateral]->coord2.getX();
395   return 0;
396 }
397 
getY2(int quadrilateral)398 double AnnotQuadrilaterals::getY2(int quadrilateral) {
399   if (quadrilateral >= 0  && quadrilateral < quadrilateralsLength)
400     return quadrilaterals[quadrilateral]->coord2.getY();
401   return 0;
402 }
403 
getX3(int quadrilateral)404 double AnnotQuadrilaterals::getX3(int quadrilateral) {
405   if (quadrilateral >= 0  && quadrilateral < quadrilateralsLength)
406     return quadrilaterals[quadrilateral]->coord3.getX();
407   return 0;
408 }
409 
getY3(int quadrilateral)410 double AnnotQuadrilaterals::getY3(int quadrilateral) {
411   if (quadrilateral >= 0  && quadrilateral < quadrilateralsLength)
412     return quadrilaterals[quadrilateral]->coord3.getY();
413   return 0;
414 }
415 
getX4(int quadrilateral)416 double AnnotQuadrilaterals::getX4(int quadrilateral) {
417   if (quadrilateral >= 0  && quadrilateral < quadrilateralsLength)
418     return quadrilaterals[quadrilateral]->coord4.getX();
419   return 0;
420 }
421 
getY4(int quadrilateral)422 double AnnotQuadrilaterals::getY4(int quadrilateral) {
423   if (quadrilateral >= 0  && quadrilateral < quadrilateralsLength)
424     return quadrilaterals[quadrilateral]->coord4.getY();
425   return 0;
426 }
427 
AnnotQuadrilateral(double x1,double y1,double x2,double y2,double x3,double y3,double x4,double y4)428 AnnotQuadrilaterals::AnnotQuadrilateral::AnnotQuadrilateral(double x1, double y1,
429     double x2, double y2, double x3, double y3, double x4, double y4)
430     : coord1(x1, y1), coord2(x2, y2), coord3(x3, y3), coord4(x4, y4) {
431 }
432 
433 //------------------------------------------------------------------------
434 // AnnotBorder
435 //------------------------------------------------------------------------
AnnotBorder()436 AnnotBorder::AnnotBorder() {
437   type = typeUnknown;
438   width = 1;
439   dashLength = 0;
440   dash = NULL;
441   style = borderSolid;
442 }
443 
~AnnotBorder()444 AnnotBorder::~AnnotBorder() {
445   if (dash)
446     gfree (dash);
447 }
448 
449 //------------------------------------------------------------------------
450 // AnnotBorderArray
451 //------------------------------------------------------------------------
452 
AnnotBorderArray()453 AnnotBorderArray::AnnotBorderArray() {
454   type = typeArray;
455   horizontalCorner = 0;
456   verticalCorner = 0;
457 }
458 
AnnotBorderArray(Array * array)459 AnnotBorderArray::AnnotBorderArray(Array *array) {
460   Object obj1;
461   int arrayLength = array->getLength();
462 
463   GBool correct = gTrue;
464   if (arrayLength == 3 || arrayLength == 4) {
465     // implementation note 81 in Appendix H.
466 
467     if (array->get(0, &obj1)->isNum())
468       horizontalCorner = obj1.getNum();
469     else
470       correct = gFalse;
471     obj1.free();
472 
473     if (array->get(1, &obj1)->isNum())
474       verticalCorner = obj1.getNum();
475     else
476       correct = gFalse;
477     obj1.free();
478 
479     if (array->get(2, &obj1)->isNum())
480       width = obj1.getNum();
481     else
482       correct = gFalse;
483     obj1.free();
484 
485     // TODO: check not all zero ? (Line Dash Pattern Page 217 PDF 8.1)
486     if (arrayLength == 4) {
487       if (array->get(3, &obj1)->isArray()) {
488         Array *dashPattern = obj1.getArray();
489         int tempLength = dashPattern->getLength();
490         double *tempDash = (double *) gmallocn (tempLength, sizeof (double));
491 
492         for(int i = 0; i < tempLength && i < DASH_LIMIT && correct; i++) {
493 
494           if (dashPattern->get(i, &obj1)->isNum()) {
495             tempDash[i] = obj1.getNum();
496 
497             if (tempDash[i] < 0)
498               correct = gFalse;
499 
500           } else {
501             correct = gFalse;
502           }
503           obj1.free();
504         }
505 
506         if (correct) {
507           dashLength = tempLength;
508           dash = tempDash;
509           style = borderDashed;
510         } else {
511           gfree (tempDash);
512         }
513       } else {
514         correct = gFalse;
515       }
516       obj1.free();
517     }
518   } else {
519     correct = gFalse;
520   }
521 
522   if (!correct) {
523     width = 0;
524   }
525 }
526 
527 //------------------------------------------------------------------------
528 // AnnotBorderBS
529 //------------------------------------------------------------------------
530 
AnnotBorderBS()531 AnnotBorderBS::AnnotBorderBS() {
532   type = typeBS;
533 }
534 
AnnotBorderBS(Dict * dict)535 AnnotBorderBS::AnnotBorderBS(Dict *dict) {
536   Object obj1, obj2;
537 
538   // acroread 8 seems to need both W and S entries for
539   // any border to be drawn, even though the spec
540   // doesn't claim anything of that sort. We follow
541   // that behaviour by veryifying both entries exist
542   // otherwise we set the borderWidth to 0
543   // --jrmuizel
544   dict->lookup("W", &obj1);
545   dict->lookup("S", &obj2);
546   if (obj1.isNum() && obj2.isName()) {
547     GooString *styleName = new GooString(obj2.getName());
548 
549     width = obj1.getNum();
550 
551     if (!styleName->cmp("S")) {
552       style = borderSolid;
553     } else if (!styleName->cmp("D")) {
554       style = borderDashed;
555     } else if (!styleName->cmp("B")) {
556       style = borderBeveled;
557     } else if (!styleName->cmp("I")) {
558       style = borderInset;
559     } else if (!styleName->cmp("U")) {
560       style = borderUnderlined;
561     } else {
562       style = borderSolid;
563     }
564     delete styleName;
565   } else {
566     width = 0;
567   }
568   obj2.free();
569   obj1.free();
570 
571   // TODO: check not all zero (Line Dash Pattern Page 217 PDF 8.1)
572   if (dict->lookup("D", &obj1)->isArray()) {
573     GBool correct = gTrue;
574     int tempLength = obj1.arrayGetLength();
575     double *tempDash = (double *) gmallocn (tempLength, sizeof (double));
576 
577     for(int i = 0; i < tempLength && correct; i++) {
578       Object obj2;
579 
580       if (obj1.arrayGet(i, &obj2)->isNum()) {
581         tempDash[i] = obj2.getNum();
582 
583         if (tempDash[i] < 0)
584           correct = gFalse;
585       } else {
586         correct = gFalse;
587       }
588       obj2.free();
589     }
590 
591     if (correct) {
592       dashLength = tempLength;
593       dash = tempDash;
594       style = borderDashed;
595     } else {
596       gfree (tempDash);
597     }
598 
599   }
600 
601   if (!dash) {
602     dashLength = 1;
603     dash = (double *) gmallocn (dashLength, sizeof (double));
604     dash[0] = 3;
605   }
606   obj1.free();
607 }
608 
609 //------------------------------------------------------------------------
610 // AnnotColor
611 //------------------------------------------------------------------------
612 
AnnotColor()613 AnnotColor::AnnotColor() {
614   length = 0;
615 }
616 
AnnotColor(double gray)617 AnnotColor::AnnotColor(double gray) {
618   length = 1;
619 
620   values[0] = gray;
621 }
622 
AnnotColor(double r,double g,double b)623 AnnotColor::AnnotColor(double r, double g, double b) {
624   length = 3;
625 
626   values[0] = r;
627   values[1] = g;
628   values[2] = b;
629 }
630 
AnnotColor(double c,double m,double y,double k)631 AnnotColor::AnnotColor(double c, double m, double y, double k) {
632   length = 4;
633 
634   values[0] = c;
635   values[1] = m;
636   values[2] = y;
637   values[3] = k;
638 }
639 
640 // If <adjust> is +1, color is brightened;
641 // if <adjust> is -1, color is darkened;
642 // otherwise color is not modified.
AnnotColor(Array * array,int adjust)643 AnnotColor::AnnotColor(Array *array, int adjust) {
644   int i;
645 
646   length = array->getLength();
647   if (length > 4)
648     length = 4;
649 
650   for (i = 0; i < length; i++) {
651     Object obj1;
652 
653     if (array->get(i, &obj1)->isNum()) {
654       values[i] = obj1.getNum();
655 
656       if (values[i] < 0 || values[i] > 1)
657         values[i] = 0;
658     } else {
659       values[i] = 0;
660     }
661     obj1.free();
662   }
663 
664   if (length == 4) {
665     adjust = -adjust;
666   }
667   if (adjust > 0) {
668     for (i = 0; i < length; ++i) {
669       values[i] = 0.5 * values[i] + 0.5;
670     }
671   } else if (adjust < 0) {
672     for (i = 0; i < length; ++i) {
673       values[i] = 0.5 * values[i];
674     }
675   }
676 }
677 
678 //------------------------------------------------------------------------
679 // AnnotBorderStyle
680 //------------------------------------------------------------------------
681 
AnnotBorderStyle(AnnotBorderType typeA,double widthA,double * dashA,int dashLengthA,double rA,double gA,double bA)682 AnnotBorderStyle::AnnotBorderStyle(AnnotBorderType typeA, double widthA,
683 				   double *dashA, int dashLengthA,
684 				   double rA, double gA, double bA) {
685   type = typeA;
686   width = widthA;
687   dash = dashA;
688   dashLength = dashLengthA;
689   r = rA;
690   g = gA;
691   b = bA;
692 }
693 
~AnnotBorderStyle()694 AnnotBorderStyle::~AnnotBorderStyle() {
695   if (dash) {
696     gfree(dash);
697   }
698 }
699 
700 //------------------------------------------------------------------------
701 // AnnotIconFit
702 //------------------------------------------------------------------------
703 
AnnotIconFit(Dict * dict)704 AnnotIconFit::AnnotIconFit(Dict* dict) {
705   Object obj1;
706 
707   if (dict->lookup("SW", &obj1)->isName()) {
708     GooString *scaleName = new GooString(obj1.getName());
709 
710     if(!scaleName->cmp("B")) {
711       scaleWhen = scaleBigger;
712     } else if(!scaleName->cmp("S")) {
713       scaleWhen = scaleSmaller;
714     } else if(!scaleName->cmp("N")) {
715       scaleWhen = scaleNever;
716     } else {
717       scaleWhen = scaleAlways;
718     }
719     delete scaleName;
720   } else {
721     scaleWhen = scaleAlways;
722   }
723   obj1.free();
724 
725   if (dict->lookup("S", &obj1)->isName()) {
726     GooString *scaleName = new GooString(obj1.getName());
727 
728     if(!scaleName->cmp("A")) {
729       scale = scaleAnamorphic;
730     } else {
731       scale = scaleProportional;
732     }
733     delete scaleName;
734   } else {
735     scale = scaleProportional;
736   }
737   obj1.free();
738 
739   if (dict->lookup("A", &obj1)->isArray() && obj1.arrayGetLength() == 2) {
740     Object obj2;
741     (obj1.arrayGet(0, &obj2)->isNum() ? left = obj2.getNum() : left = 0);
742     obj2.free();
743     (obj1.arrayGet(1, &obj2)->isNum() ? bottom = obj2.getNum() : bottom = 0);
744     obj2.free();
745 
746     if (left < 0 || left > 1)
747       left = 0.5;
748 
749     if (bottom < 0 || bottom > 1)
750       bottom = 0.5;
751 
752   } else {
753     left = bottom = 0.5;
754   }
755   obj1.free();
756 
757   if (dict->lookup("FB", &obj1)->isBool()) {
758     fullyBounds = obj1.getBool();
759   } else {
760     fullyBounds = gFalse;
761   }
762   obj1.free();
763 }
764 
765 //------------------------------------------------------------------------
766 // AnnotAppearanceCharacs
767 //------------------------------------------------------------------------
768 
AnnotAppearanceCharacs(Dict * dict)769 AnnotAppearanceCharacs::AnnotAppearanceCharacs(Dict *dict) {
770   Object obj1;
771 
772   if (dict->lookup("R", &obj1)->isInt()) {
773     rotation = obj1.getInt();
774   } else {
775     rotation = 0;
776   }
777   obj1.free();
778 
779   if (dict->lookup("BC", &obj1)->isArray()) {
780     borderColor = new AnnotColor(obj1.getArray());
781   } else {
782     borderColor = NULL;
783   }
784   obj1.free();
785 
786   if (dict->lookup("BG", &obj1)->isArray()) {
787     backColor = new AnnotColor(obj1.getArray());
788   } else {
789     backColor = NULL;
790   }
791   obj1.free();
792 
793   if (dict->lookup("CA", &obj1)->isName()) {
794     normalCaption = new GooString(obj1.getName());
795   } else {
796     normalCaption = NULL;
797   }
798   obj1.free();
799 
800   if (dict->lookup("RC", &obj1)->isName()) {
801     rolloverCaption = new GooString(obj1.getName());
802   } else {
803     rolloverCaption = NULL;
804   }
805   obj1.free();
806 
807   if (dict->lookup("AC", &obj1)->isName()) {
808     alternateCaption = new GooString(obj1.getName());
809   } else {
810     alternateCaption = NULL;
811   }
812   obj1.free();
813 
814   if (dict->lookup("IF", &obj1)->isDict()) {
815     iconFit = new AnnotIconFit(obj1.getDict());
816   } else {
817     iconFit = NULL;
818   }
819   obj1.free();
820 
821   if (dict->lookup("TP", &obj1)->isInt()) {
822     position = (AnnotAppearanceCharacsTextPos) obj1.getInt();
823   } else {
824     position = captionNoIcon;
825   }
826   obj1.free();
827 }
828 
~AnnotAppearanceCharacs()829 AnnotAppearanceCharacs::~AnnotAppearanceCharacs() {
830   if (borderColor)
831     delete borderColor;
832 
833   if (backColor)
834     delete backColor;
835 
836   if (normalCaption)
837     delete normalCaption;
838 
839   if (rolloverCaption)
840     delete rolloverCaption;
841 
842   if (alternateCaption)
843     delete alternateCaption;
844 
845   if (iconFit)
846     delete iconFit;
847 }
848 
849 //------------------------------------------------------------------------
850 // Annot
851 //------------------------------------------------------------------------
852 
Annot(XRef * xrefA,PDFRectangle * rectA,Catalog * catalog)853 Annot::Annot(XRef *xrefA, PDFRectangle *rectA, Catalog *catalog) {
854   Object obj1;
855 
856   flags = flagUnknown;
857   type = typeUnknown;
858 
859   obj1.initArray (xrefA);
860   Object obj2;
861   obj1.arrayAdd (obj2.initReal (rectA->x1));
862   obj1.arrayAdd (obj2.initReal (rectA->y1));
863   obj1.arrayAdd (obj2.initReal (rectA->x2));
864   obj1.arrayAdd (obj2.initReal (rectA->y2));
865   obj2.free ();
866 
867   annotObj.initDict (xrefA);
868   annotObj.dictSet ("Type", obj2.initName ("Annot"));
869   annotObj.dictSet ("Rect", &obj1);
870   // obj1 is owned by the dict
871 
872   ref = xrefA->addIndirectObject (&annotObj);
873 
874   initialize (xrefA, annotObj.getDict(), catalog);
875 }
876 
Annot(XRef * xrefA,Dict * dict,Catalog * catalog)877 Annot::Annot(XRef *xrefA, Dict *dict, Catalog* catalog) {
878   hasRef = false;
879   flags = flagUnknown;
880   type = typeUnknown;
881   annotObj.initDict (dict);
882   initialize (xrefA, dict, catalog);
883 }
884 
Annot(XRef * xrefA,Dict * dict,Catalog * catalog,Object * obj)885 Annot::Annot(XRef *xrefA, Dict *dict, Catalog* catalog, Object *obj) {
886   if (obj->isRef()) {
887     hasRef = gTrue;
888     ref = obj->getRef();
889   } else {
890     hasRef = gFalse;
891   }
892   flags = flagUnknown;
893   type = typeUnknown;
894   annotObj.initDict (dict);
895   initialize (xrefA, dict, catalog);
896 }
897 
initialize(XRef * xrefA,Dict * dict,Catalog * catalog)898 void Annot::initialize(XRef *xrefA, Dict *dict, Catalog *catalog) {
899   Object asObj, obj1, obj2, obj3;
900 
901   appRef.num = 0;
902   appRef.gen = 65535;
903   ok = gTrue;
904   xref = xrefA;
905   appearBuf = NULL;
906   fontSize = 0;
907 
908   appearance.initNull();
909 
910   //----- parse the rectangle
911   rect = new PDFRectangle();
912   if (dict->lookup("Rect", &obj1)->isArray() && obj1.arrayGetLength() == 4) {
913     Object obj2;
914     (obj1.arrayGet(0, &obj2)->isNum() ? rect->x1 = obj2.getNum() : rect->x1 = 0);
915     obj2.free();
916     (obj1.arrayGet(1, &obj2)->isNum() ? rect->y1 = obj2.getNum() : rect->y1 = 0);
917     obj2.free();
918     (obj1.arrayGet(2, &obj2)->isNum() ? rect->x2 = obj2.getNum() : rect->x2 = 1);
919     obj2.free();
920     (obj1.arrayGet(3, &obj2)->isNum() ? rect->y2 = obj2.getNum() : rect->y2 = 1);
921     obj2.free();
922 
923     if (rect->x1 > rect->x2) {
924       double t = rect->x1;
925       rect->x1 = rect->x2;
926       rect->x2 = t;
927     }
928 
929     if (rect->y1 > rect->y2) {
930       double t = rect->y1;
931       rect->y1 = rect->y2;
932       rect->y2 = t;
933     }
934   } else {
935     rect->x1 = rect->y1 = 0;
936     rect->x2 = rect->y2 = 1;
937     error(-1, "Bad bounding box for annotation");
938     ok = gFalse;
939   }
940   obj1.free();
941 
942   if (dict->lookup("Contents", &obj1)->isString()) {
943     contents = obj1.getString()->copy();
944   } else {
945     contents = NULL;
946   }
947   obj1.free();
948 
949   if (dict->lookupNF("P", &obj1)->isRef()) {
950     Ref ref = obj1.getRef();
951 
952     page = catalog ? catalog->findPage (ref.num, ref.gen) : -1;
953   } else {
954     page = 0;
955   }
956   obj1.free();
957 
958   if (dict->lookup("NM", &obj1)->isString()) {
959     name = obj1.getString()->copy();
960   } else {
961     name = NULL;
962   }
963   obj1.free();
964 
965   if (dict->lookup("M", &obj1)->isString()) {
966     modified = obj1.getString()->copy();
967   } else {
968     modified = NULL;
969   }
970   obj1.free();
971 
972   //----- get the flags
973   if (dict->lookup("F", &obj1)->isInt()) {
974     flags |= obj1.getInt();
975   } else {
976     flags = flagUnknown;
977   }
978   obj1.free();
979 
980   if (dict->lookup("AP", &obj1)->isDict()) {
981     Object obj2;
982 
983     if (dict->lookup("AS", &obj2)->isName()) {
984       Object obj3;
985 
986       appearState = new GooString(obj2.getName());
987       if (obj1.dictLookup("N", &obj3)->isDict()) {
988         Object obj4;
989 
990         if (obj3.dictLookupNF(appearState->getCString(), &obj4)->isRef()) {
991           obj4.copy(&appearance);
992         } else {
993           obj4.free();
994           if (obj3.dictLookupNF("Off", &obj4)->isRef()) {
995             obj4.copy(&appearance);
996           }
997         }
998         obj4.free();
999       }
1000       obj3.free();
1001     } else {
1002       obj2.free();
1003 
1004       appearState = NULL;
1005       if (obj1.dictLookupNF("N", &obj2)->isRef()) {
1006         obj2.copy(&appearance);
1007       }
1008     }
1009     obj2.free();
1010   } else {
1011     appearState = NULL;
1012   }
1013   obj1.free();
1014 
1015   //----- parse the border style
1016   if (dict->lookup("BS", &obj1)->isDict()) {
1017     border = new AnnotBorderBS(obj1.getDict());
1018   } else {
1019     obj1.free();
1020 
1021     if (dict->lookup("Border", &obj1)->isArray())
1022       border = new AnnotBorderArray(obj1.getArray());
1023     else
1024       // Adobe draws no border at all if the last element is of
1025       // the wrong type.
1026       border = NULL;
1027   }
1028   obj1.free();
1029 
1030   if (dict->lookup("C", &obj1)->isArray()) {
1031     color = new AnnotColor(obj1.getArray());
1032   } else {
1033     color = NULL;
1034   }
1035   obj1.free();
1036 
1037   if (dict->lookup("StructParent", &obj1)->isInt()) {
1038     treeKey = obj1.getInt();
1039   } else {
1040     treeKey = 0;
1041   }
1042   obj1.free();
1043 
1044   optContentConfig = catalog ? catalog->getOptContentConfig() : NULL;
1045   dict->lookupNF("OC", &oc);
1046   if (!oc.isRef() && !oc.isNull()) {
1047     error (-1, "Annotation OC value not null or dict: %i", oc.getType());
1048   }
1049 }
1050 
update(const char * key,Object * value)1051 void Annot::update(const char *key, Object *value) {
1052   /* Set M to current time */
1053   delete modified;
1054   modified = timeToDateString(NULL);
1055 
1056   Object obj1;
1057   obj1.initString (modified->copy());
1058   annotObj.dictSet("M", &obj1);
1059 
1060   annotObj.dictSet(const_cast<char*>(key), value);
1061 
1062   xref->setModifiedObject(&annotObj, ref);
1063 }
1064 
setContents(GooString * new_content)1065 void Annot::setContents(GooString *new_content) {
1066   delete contents;
1067 
1068   if (new_content) {
1069     contents = new GooString(new_content);
1070     //append the unicode marker <FE FF> if needed
1071     if (!contents->hasUnicodeMarker()) {
1072       contents->insert(0, 0xff);
1073       contents->insert(0, 0xfe);
1074     }
1075   } else {
1076     contents = new GooString();
1077   }
1078 
1079   Object obj1;
1080   obj1.initString(contents->copy());
1081   update ("Contents", &obj1);
1082 }
1083 
setColor(AnnotColor * new_color)1084 void Annot::setColor(AnnotColor *new_color) {
1085   delete color;
1086 
1087   if (new_color) {
1088     Object obj1, obj2;
1089     const double *values = new_color->getValues();
1090 
1091     obj1.initArray(xref);
1092     for (int i = 0; i < (int)new_color->getSpace(); i++)
1093       obj1.arrayAdd(obj2.initReal (values[i]));
1094     update ("C", &obj1);
1095     color = new_color;
1096   } else {
1097     color = NULL;
1098   }
1099 }
1100 
setPage(Ref * pageRef,int pageIndex)1101 void Annot::setPage(Ref *pageRef, int pageIndex)
1102 {
1103   Object obj1;
1104 
1105   obj1.initRef(pageRef->num, pageRef->gen);
1106   update("P", &obj1);
1107   page = pageIndex;
1108 }
1109 
getXMin()1110 double Annot::getXMin() {
1111   return rect->x1;
1112 }
1113 
getYMin()1114 double Annot::getYMin() {
1115   return rect->y1;
1116 }
1117 
readArrayNum(Object * pdfArray,int key,double * value)1118 void Annot::readArrayNum(Object *pdfArray, int key, double *value) {
1119   Object valueObject;
1120 
1121   pdfArray->arrayGet(key, &valueObject);
1122   if (valueObject.isNum()) {
1123     *value = valueObject.getNum();
1124   } else {
1125     *value = 0;
1126     ok = gFalse;
1127   }
1128   valueObject.free();
1129 }
1130 
~Annot()1131 Annot::~Annot() {
1132   annotObj.free();
1133 
1134   delete rect;
1135 
1136   if (contents)
1137     delete contents;
1138 
1139   if (name)
1140     delete name;
1141 
1142   if (modified)
1143     delete modified;
1144 
1145   appearance.free();
1146 
1147   if (appearState)
1148     delete appearState;
1149 
1150   if (border)
1151     delete border;
1152 
1153   if (color)
1154     delete color;
1155 
1156   oc.free();
1157 }
1158 
setColor(AnnotColor * color,GBool fill)1159 void Annot::setColor(AnnotColor *color, GBool fill) {
1160   const double *values = color->getValues();
1161 
1162   switch (color->getSpace()) {
1163   case AnnotColor::colorCMYK:
1164     appearBuf->appendf("{0:.2f} {1:.2f} {2:.2f} {3:.2f} {4:c}\n",
1165 		       values[0], values[1], values[2], values[3],
1166 		       fill ? 'k' : 'K');
1167     break;
1168   case AnnotColor::colorRGB:
1169     appearBuf->appendf("{0:.2f} {1:.2f} {2:.2f} {3:s}\n",
1170 		       values[0], values[1], values[2],
1171 		       fill ? "rg" : "RG");
1172     break;
1173   case AnnotColor::colorGray:
1174     appearBuf->appendf("{0:.2f} {1:c}\n",
1175 		       values[0],
1176 		       fill ? 'g' : 'G');
1177     break;
1178   case AnnotColor::colorTransparent:
1179   default:
1180     break;
1181   }
1182 }
1183 
1184 // Draw an (approximate) circle of radius <r> centered at (<cx>, <cy>).
1185 // If <fill> is true, the circle is filled; otherwise it is stroked.
drawCircle(double cx,double cy,double r,GBool fill)1186 void Annot::drawCircle(double cx, double cy, double r, GBool fill) {
1187   appearBuf->appendf("{0:.2f} {1:.2f} m\n",
1188       cx + r, cy);
1189   appearBuf->appendf("{0:.2f} {1:.2f} {2:.2f} {3:.2f} {4:.2f} {5:.2f} c\n",
1190       cx + r, cy + bezierCircle * r,
1191       cx + bezierCircle * r, cy + r,
1192       cx, cy + r);
1193   appearBuf->appendf("{0:.2f} {1:.2f} {2:.2f} {3:.2f} {4:.2f} {5:.2f} c\n",
1194       cx - bezierCircle * r, cy + r,
1195       cx - r, cy + bezierCircle * r,
1196       cx - r, cy);
1197   appearBuf->appendf("{0:.2f} {1:.2f} {2:.2f} {3:.2f} {4:.2f} {5:.2f} c\n",
1198       cx - r, cy - bezierCircle * r,
1199       cx - bezierCircle * r, cy - r,
1200       cx, cy - r);
1201   appearBuf->appendf("{0:.2f} {1:.2f} {2:.2f} {3:.2f} {4:.2f} {5:.2f} c\n",
1202       cx + bezierCircle * r, cy - r,
1203       cx + r, cy - bezierCircle * r,
1204       cx + r, cy);
1205   appearBuf->append(fill ? "f\n" : "s\n");
1206 }
1207 
1208 // Draw the top-left half of an (approximate) circle of radius <r>
1209 // centered at (<cx>, <cy>).
drawCircleTopLeft(double cx,double cy,double r)1210 void Annot::drawCircleTopLeft(double cx, double cy, double r) {
1211   double r2;
1212 
1213   r2 = r / sqrt(2.0);
1214   appearBuf->appendf("{0:.2f} {1:.2f} m\n",
1215       cx + r2, cy + r2);
1216   appearBuf->appendf("{0:.2f} {1:.2f} {2:.2f} {3:.2f} {4:.2f} {5:.2f} c\n",
1217       cx + (1 - bezierCircle) * r2,
1218       cy + (1 + bezierCircle) * r2,
1219       cx - (1 - bezierCircle) * r2,
1220       cy + (1 + bezierCircle) * r2,
1221       cx - r2,
1222       cy + r2);
1223   appearBuf->appendf("{0:.2f} {1:.2f} {2:.2f} {3:.2f} {4:.2f} {5:.2f} c\n",
1224       cx - (1 + bezierCircle) * r2,
1225       cy + (1 - bezierCircle) * r2,
1226       cx - (1 + bezierCircle) * r2,
1227       cy - (1 - bezierCircle) * r2,
1228       cx - r2,
1229       cy - r2);
1230   appearBuf->append("S\n");
1231 }
1232 
1233 // Draw the bottom-right half of an (approximate) circle of radius <r>
1234 // centered at (<cx>, <cy>).
drawCircleBottomRight(double cx,double cy,double r)1235 void Annot::drawCircleBottomRight(double cx, double cy, double r) {
1236   double r2;
1237 
1238   r2 = r / sqrt(2.0);
1239   appearBuf->appendf("{0:.2f} {1:.2f} m\n",
1240       cx - r2, cy - r2);
1241   appearBuf->appendf("{0:.2f} {1:.2f} {2:.2f} {3:.2f} {4:.2f} {5:.2f} c\n",
1242       cx - (1 - bezierCircle) * r2,
1243       cy - (1 + bezierCircle) * r2,
1244       cx + (1 - bezierCircle) * r2,
1245       cy - (1 + bezierCircle) * r2,
1246       cx + r2,
1247       cy - r2);
1248   appearBuf->appendf("{0:.2f} {1:.2f} {2:.2f} {3:.2f} {4:.2f} {5:.2f} c\n",
1249       cx + (1 + bezierCircle) * r2,
1250       cy - (1 - bezierCircle) * r2,
1251       cx + (1 + bezierCircle) * r2,
1252       cy + (1 - bezierCircle) * r2,
1253       cx + r2,
1254       cy + r2);
1255   appearBuf->append("S\n");
1256 }
1257 
createForm(double * bbox,GBool transparencyGroup,Object * resDict,Object * aStream)1258 void Annot::createForm(double *bbox, GBool transparencyGroup, Object *resDict, Object *aStream) {
1259   Object obj1, obj2;
1260   Object appearDict;
1261 
1262   appearDict.initDict(xref);
1263   appearDict.dictSet("Length", obj1.initInt(appearBuf->getLength()));
1264   appearDict.dictSet("Subtype", obj1.initName("Form"));
1265   obj1.initArray(xref);
1266   obj1.arrayAdd(obj2.initReal(bbox[0]));
1267   obj1.arrayAdd(obj2.initReal(bbox[1]));
1268   obj1.arrayAdd(obj2.initReal(bbox[2]));
1269   obj1.arrayAdd(obj2.initReal(bbox[3]));
1270   appearDict.dictSet("BBox", &obj1);
1271   if (transparencyGroup) {
1272     Object transDict;
1273     transDict.initDict(xref);
1274     transDict.dictSet("S", obj1.initName("Transparency"));
1275     appearDict.dictSet("Group", &transDict);
1276   }
1277   if (resDict)
1278     appearDict.dictSet("Resources", resDict);
1279 
1280   MemStream *mStream = new MemStream(copyString(appearBuf->getCString()), 0,
1281 				     appearBuf->getLength(), &appearDict);
1282   mStream->setNeedFree(gTrue);
1283   aStream->initStream(mStream);
1284 }
1285 
createResourcesDict(char * formName,Object * formStream,char * stateName,double opacity,char * blendMode,Object * resDict)1286 void Annot::createResourcesDict(char *formName, Object *formStream,
1287 				char *stateName,
1288 				double opacity,	char *blendMode,
1289 				Object *resDict) {
1290   Object gsDict, stateDict, formDict, obj1;
1291 
1292   gsDict.initDict(xref);
1293   if (opacity != 1) {
1294     gsDict.dictSet("CA", obj1.initReal(opacity));
1295     gsDict.dictSet("ca", obj1.initReal(opacity));
1296   }
1297   if (blendMode)
1298     gsDict.dictSet("BM", obj1.initName(blendMode));
1299   stateDict.initDict(xref);
1300   stateDict.dictSet(stateName, &gsDict);
1301   formDict.initDict(xref);
1302   formDict.dictSet(formName, formStream);
1303 
1304   resDict->initDict(xref);
1305   resDict->dictSet("ExtGState", &stateDict);
1306   resDict->dictSet("XObject", &formDict);
1307 }
1308 
isVisible(GBool printing)1309 GBool Annot::isVisible(GBool printing) {
1310   // check the flags
1311   if ((flags & flagHidden) ||
1312       (printing && !(flags & flagPrint)) ||
1313       (!printing && (flags & flagNoView))) {
1314     return gFalse;
1315   }
1316 
1317   // check the OC
1318   if (optContentConfig && oc.isRef()) {
1319     if (! optContentConfig->optContentIsVisible(&oc))
1320       return gFalse;
1321   }
1322 
1323   return gTrue;
1324 }
1325 
draw(Gfx * gfx,GBool printing)1326 void Annot::draw(Gfx *gfx, GBool printing) {
1327   Object obj;
1328 
1329   if (!isVisible (printing))
1330     return;
1331 
1332   // draw the appearance stream
1333   appearance.fetch(xref, &obj);
1334   gfx->drawAnnot(&obj, (AnnotBorder *)NULL, color,
1335       rect->x1, rect->y1, rect->x2, rect->y2);
1336   obj.free();
1337 }
1338 
1339 //------------------------------------------------------------------------
1340 // AnnotPopup
1341 //------------------------------------------------------------------------
1342 
AnnotPopup(XRef * xrefA,PDFRectangle * rect,Catalog * catalog)1343 AnnotPopup::AnnotPopup(XRef *xrefA, PDFRectangle *rect, Catalog *catalog) :
1344     Annot(xrefA, rect, catalog) {
1345   Object obj1;
1346 
1347   type = typePopup;
1348 
1349   annotObj.dictSet ("Subtype", obj1.initName ("Popup"));
1350   initialize (xrefA, annotObj.getDict(), catalog);
1351 }
1352 
AnnotPopup(XRef * xrefA,Dict * dict,Catalog * catalog,Object * obj)1353 AnnotPopup::AnnotPopup(XRef *xrefA, Dict *dict, Catalog *catalog, Object *obj) :
1354     Annot(xrefA, dict, catalog, obj) {
1355   type = typePopup;
1356   initialize(xrefA, dict, catalog);
1357 }
1358 
~AnnotPopup()1359 AnnotPopup::~AnnotPopup() {
1360   parent.free();
1361 }
1362 
initialize(XRef * xrefA,Dict * dict,Catalog * catalog)1363 void AnnotPopup::initialize(XRef *xrefA, Dict *dict, Catalog *catalog) {
1364   Object obj1;
1365 
1366   if (!dict->lookupNF("Parent", &parent)->isRef()) {
1367     parent.initNull();
1368   }
1369 
1370   if (dict->lookup("Open", &obj1)->isBool()) {
1371     open = obj1.getBool();
1372   } else {
1373     open = gFalse;
1374   }
1375   obj1.free();
1376 }
1377 
setParent(Object * parentA)1378 void AnnotPopup::setParent(Object *parentA) {
1379   parentA->copy(&parent);
1380   update ("Parent", &parent);
1381 }
1382 
setParent(Annot * parentA)1383 void AnnotPopup::setParent(Annot *parentA) {
1384   Ref parentRef = parentA->getRef();
1385   parent.initRef(parentRef.num, parentRef.gen);
1386   update ("Parent", &parent);
1387 }
1388 
setOpen(GBool openA)1389 void AnnotPopup::setOpen(GBool openA) {
1390   Object obj1;
1391 
1392   open = openA;
1393   obj1.initBool(open);
1394   update ("Open", &obj1);
1395 }
1396 
1397 //------------------------------------------------------------------------
1398 // AnnotMarkup
1399 //------------------------------------------------------------------------
AnnotMarkup(XRef * xrefA,PDFRectangle * rect,Catalog * catalog)1400 AnnotMarkup::AnnotMarkup(XRef *xrefA, PDFRectangle *rect, Catalog *catalog) :
1401     Annot(xrefA, rect, catalog) {
1402   initialize(xrefA, annotObj.getDict(), catalog, &annotObj);
1403 }
1404 
AnnotMarkup(XRef * xrefA,Dict * dict,Catalog * catalog,Object * obj)1405 AnnotMarkup::AnnotMarkup(XRef *xrefA, Dict *dict, Catalog *catalog, Object *obj) :
1406     Annot(xrefA, dict, catalog, obj) {
1407   initialize(xrefA, dict, catalog, obj);
1408 }
1409 
~AnnotMarkup()1410 AnnotMarkup::~AnnotMarkup() {
1411   if (label)
1412     delete label;
1413 
1414   if (popup)
1415     delete popup;
1416 
1417   if (date)
1418     delete date;
1419 
1420   if (subject)
1421     delete subject;
1422 }
1423 
initialize(XRef * xrefA,Dict * dict,Catalog * catalog,Object * obj)1424 void AnnotMarkup::initialize(XRef *xrefA, Dict *dict, Catalog *catalog, Object *obj) {
1425   Object obj1;
1426 
1427   if (dict->lookup("T", &obj1)->isString()) {
1428     label = obj1.getString()->copy();
1429   } else {
1430     label = NULL;
1431   }
1432   obj1.free();
1433 
1434   if (dict->lookup("Popup", &obj1)->isDict()) {
1435     popup = new AnnotPopup(xrefA, obj1.getDict(), catalog, obj);
1436   } else {
1437     popup = NULL;
1438   }
1439   obj1.free();
1440 
1441   if (dict->lookup("CA", &obj1)->isNum()) {
1442     opacity = obj1.getNum();
1443   } else {
1444     opacity = 1.0;
1445   }
1446   obj1.free();
1447 
1448   if (dict->lookup("CreationDate", &obj1)->isString()) {
1449     date = obj1.getString()->copy();
1450   } else {
1451     date = NULL;
1452   }
1453   obj1.free();
1454 
1455   if (dict->lookupNF("IRT", &obj1)->isRef()) {
1456     inReplyTo = obj1.getRef();
1457   } else {
1458     inReplyTo.num = 0;
1459     inReplyTo.gen = 0;
1460   }
1461   obj1.free();
1462 
1463   if (dict->lookup("Subj", &obj1)->isString()) {
1464     subject = obj1.getString()->copy();
1465   } else {
1466     subject = NULL;
1467   }
1468   obj1.free();
1469 
1470   if (dict->lookup("RT", &obj1)->isName()) {
1471     GooString *replyName = new GooString(obj1.getName());
1472 
1473     if (!replyName->cmp("R")) {
1474       replyTo = replyTypeR;
1475     } else if (!replyName->cmp("Group")) {
1476       replyTo = replyTypeGroup;
1477     } else {
1478       replyTo = replyTypeR;
1479     }
1480     delete replyName;
1481   } else {
1482     replyTo = replyTypeR;
1483   }
1484   obj1.free();
1485 
1486   if (dict->lookup("ExData", &obj1)->isDict()) {
1487     exData = parseAnnotExternalData(obj1.getDict());
1488   } else {
1489     exData = annotExternalDataMarkupUnknown;
1490   }
1491   obj1.free();
1492 }
1493 
setLabel(GooString * new_label)1494 void AnnotMarkup::setLabel(GooString *new_label) {
1495   delete label;
1496 
1497   if (new_label) {
1498     label = new GooString(new_label);
1499     //append the unicode marker <FE FF> if needed
1500     if (!label->hasUnicodeMarker()) {
1501       label->insert(0, 0xff);
1502       label->insert(0, 0xfe);
1503     }
1504   } else {
1505     label = new GooString();
1506   }
1507 
1508   Object obj1;
1509   obj1.initString(label->copy());
1510   update ("T", &obj1);
1511 }
1512 
setPopup(AnnotPopup * new_popup)1513 void AnnotMarkup::setPopup(AnnotPopup *new_popup) {
1514   delete popup;
1515 
1516   if (new_popup) {
1517     Object obj1;
1518     Ref popupRef = new_popup->getRef();
1519 
1520     obj1.initRef (popupRef.num, popupRef.gen);
1521     update ("Popup", &obj1);
1522 
1523     new_popup->setParent(this);
1524     popup = new_popup;
1525   } else {
1526     popup = NULL;
1527   }
1528 }
1529 
setOpacity(double opacityA)1530 void AnnotMarkup::setOpacity(double opacityA) {
1531   Object obj1;
1532 
1533   opacity = opacityA;
1534   obj1.initReal(opacity);
1535   update ("CA", &obj1);
1536 }
1537 
1538 //------------------------------------------------------------------------
1539 // AnnotText
1540 //------------------------------------------------------------------------
1541 
AnnotText(XRef * xrefA,PDFRectangle * rect,Catalog * catalog)1542 AnnotText::AnnotText(XRef *xrefA, PDFRectangle *rect, Catalog *catalog) :
1543     AnnotMarkup(xrefA, rect, catalog) {
1544   Object obj1;
1545 
1546   type = typeText;
1547   flags |= flagNoZoom | flagNoRotate;
1548 
1549   annotObj.dictSet ("Subtype", obj1.initName ("Text"));
1550   initialize (xrefA, catalog, annotObj.getDict());
1551 }
1552 
AnnotText(XRef * xrefA,Dict * dict,Catalog * catalog,Object * obj)1553 AnnotText::AnnotText(XRef *xrefA, Dict *dict, Catalog *catalog, Object *obj) :
1554     AnnotMarkup(xrefA, dict, catalog, obj) {
1555 
1556   type = typeText;
1557   flags |= flagNoZoom | flagNoRotate;
1558   initialize (xrefA, catalog, dict);
1559 }
1560 
~AnnotText()1561 AnnotText::~AnnotText() {
1562   delete icon;
1563 }
1564 
initialize(XRef * xrefA,Catalog * catalog,Dict * dict)1565 void AnnotText::initialize(XRef *xrefA, Catalog *catalog, Dict *dict) {
1566   Object obj1;
1567 
1568   if (dict->lookup("Open", &obj1)->isBool())
1569     open = obj1.getBool();
1570   else
1571     open = gFalse;
1572   obj1.free();
1573 
1574   if (dict->lookup("Name", &obj1)->isName()) {
1575     icon = new GooString(obj1.getName());
1576   } else {
1577     icon = new GooString("Note");
1578   }
1579   obj1.free();
1580 
1581   if (dict->lookup("StateModel", &obj1)->isString()) {
1582     Object obj2;
1583     GooString *modelName = obj1.getString();
1584 
1585     if (dict->lookup("State", &obj2)->isString()) {
1586       GooString *stateName = obj2.getString();
1587 
1588       if (!stateName->cmp("Marked")) {
1589         state = stateMarked;
1590       } else if (!stateName->cmp("Unmarked")) {
1591         state = stateUnmarked;
1592       } else if (!stateName->cmp("Accepted")) {
1593         state = stateAccepted;
1594       } else if (!stateName->cmp("Rejected")) {
1595         state = stateRejected;
1596       } else if (!stateName->cmp("Cancelled")) {
1597         state = stateCancelled;
1598       } else if (!stateName->cmp("Completed")) {
1599         state = stateCompleted;
1600       } else if (!stateName->cmp("None")) {
1601         state = stateNone;
1602       } else {
1603         state = stateUnknown;
1604       }
1605     } else {
1606       state = stateUnknown;
1607     }
1608     obj2.free();
1609 
1610     if (!modelName->cmp("Marked")) {
1611       switch (state) {
1612         case stateUnknown:
1613           state = stateMarked;
1614           break;
1615         case stateAccepted:
1616         case stateRejected:
1617         case stateCancelled:
1618         case stateCompleted:
1619         case stateNone:
1620           state = stateUnknown;
1621           break;
1622         default:
1623           break;
1624       }
1625     } else if (!modelName->cmp("Review")) {
1626       switch (state) {
1627         case stateUnknown:
1628           state = stateNone;
1629           break;
1630         case stateMarked:
1631         case stateUnmarked:
1632           state = stateUnknown;
1633           break;
1634         default:
1635           break;
1636       }
1637     } else {
1638       state = stateUnknown;
1639     }
1640   } else {
1641     state = stateUnknown;
1642   }
1643   obj1.free();
1644 }
1645 
setOpen(GBool openA)1646 void AnnotText::setOpen(GBool openA) {
1647   Object obj1;
1648 
1649   open = openA;
1650   obj1.initBool(open);
1651   update ("Open", &obj1);
1652 }
1653 
setIcon(GooString * new_icon)1654 void AnnotText::setIcon(GooString *new_icon) {
1655   if (new_icon && icon->cmp(new_icon) == 0)
1656     return;
1657 
1658   delete icon;
1659 
1660   if (new_icon) {
1661     icon = new GooString (new_icon);
1662   } else {
1663     icon = new GooString("Note");
1664   }
1665 
1666   Object obj1;
1667   obj1.initName (icon->getCString());
1668   update("Name", &obj1);
1669 }
1670 
1671 #define ANNOT_TEXT_AP_NOTE                                                    \
1672   "3.602 24 m 20.398 24 l 22.387 24 24 22.387 24 20.398 c 24 3.602 l 24\n"    \
1673   "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"  \
1674   "l 0 22.387 1.613 24 3.602 24 c h\n"                                        \
1675   "3.602 24 m f\n"                                                            \
1676   "0.533333 0.541176 0.521569 RG 2 w\n"                                       \
1677   "1 J\n"                                                                     \
1678   "1 j\n"                                                                     \
1679   "[] 0.0 d\n"                                                                \
1680   "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"      \
1681   "1.5 w\n"                                                                   \
1682   "0 j\n"                                                                     \
1683   "10 16 m 14 21 l S\n"                                                       \
1684   "1.85625 w\n"                                                               \
1685   "1 j\n"                                                                     \
1686   "15.07 20.523 m 15.07 19.672 14.379 18.977 13.523 18.977 c 12.672 18.977\n" \
1687   "11.977 19.672 11.977 20.523 c 11.977 21.379 12.672 22.07 13.523 22.07 c\n" \
1688   "14.379 22.07 15.07 21.379 15.07 20.523 c h\n"                              \
1689   "15.07 20.523 m S\n"                                                        \
1690   "1 w\n"                                                                     \
1691   "0 j\n"                                                                     \
1692   "6.5 13.5 m 15.5 13.5 l S\n"                                                \
1693   "6.5 10.5 m 13.5 10.5 l S\n"                                                \
1694   "6.801 7.5 m 15.5 7.5 l S\n"                                                \
1695   "0.729412 0.741176 0.713725 RG 2 w\n"                                       \
1696   "1 j\n"                                                                     \
1697   "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"          \
1698   "1.5 w\n"                                                                   \
1699   "0 j\n"                                                                     \
1700   "10 17 m 14 22 l S\n"                                                       \
1701   "1.85625 w\n"                                                               \
1702   "1 j\n"                                                                     \
1703   "15.07 21.523 m 15.07 20.672 14.379 19.977 13.523 19.977 c 12.672 19.977\n" \
1704   "11.977 20.672 11.977 21.523 c 11.977 22.379 12.672 23.07 13.523 23.07 c\n" \
1705   "14.379 23.07 15.07 22.379 15.07 21.523 c h\n"                              \
1706   "15.07 21.523 m S\n"                                                        \
1707   "1 w\n"                                                                     \
1708   "0 j\n"                                                                     \
1709   "6.5 14.5 m 15.5 14.5 l S\n"                                                \
1710   "6.5 11.5 m 13.5 11.5 l S\n"                                                \
1711   "6.801 8.5 m 15.5 8.5 l S\n"
1712 
1713 #define ANNOT_TEXT_AP_COMMENT                                                   \
1714   "4.301 23 m 19.699 23 l 21.523 23 23 21.523 23 19.699 c 23 4.301 l 23\n"      \
1715   "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"    \
1716   "l 1 21.523 2.477 23 4.301 23 c h\n"                                          \
1717   "4.301 23 m f\n"                                                              \
1718   "0.533333 0.541176 0.521569 RG 2 w\n"                                         \
1719   "0 J\n"                                                                       \
1720   "1 j\n"                                                                       \
1721   "[] 0.0 d\n"                                                                  \
1722   "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" \
1723   "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"   \
1724   "5.637 20 8 20 c h\n"                                                         \
1725   "8 20 m S\n"                                                                  \
1726   "0.729412 0.741176 0.713725 RG 8 21 m 16 21 l 18.363 21 20 19.215 20 17\n"    \
1727   "c 20 14 l 20 11.785 18.363 10\n"                                             \
1728   "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"     \
1729   "19.215 5.637 21 8 21 c h\n"                                                  \
1730   "8 21 m S\n"
1731 
1732 #define ANNOT_TEXT_AP_KEY                                                    \
1733   "4.301 23 m 19.699 23 l 21.523 23 23 21.523 23 19.699 c 23 4.301 l 23\n"   \
1734   "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" \
1735   "l 1 21.523 2.477 23 4.301 23 c h\n"                                       \
1736   "4.301 23 m f\n"                                                           \
1737   "0.533333 0.541176 0.521569 RG 2 w\n"                                      \
1738   "1 J\n"                                                                    \
1739   "0 j\n"                                                                    \
1740   "[] 0.0 d\n"                                                               \
1741   "4 M 11.895 18.754 m 13.926 20.625 17.09 20.496 18.961 18.465 c 20.832\n"  \
1742   "16.434 20.699 13.27 18.668 11.398 c 17.164 10.016 15.043 9.746 13.281\n"  \
1743   "10.516 c 12.473 9.324 l 11.281 10.078 l 9.547 8.664 l 9.008 6.496 l\n"    \
1744   "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"   \
1745   "10.57 13.457 l 9.949 15.277 10.391 17.367 11.895 18.754 c h\n"            \
1746   "11.895 18.754 m S\n"                                                      \
1747   "1.5 w\n"                                                                  \
1748   "16.059 15.586 m 16.523 15.078 17.316 15.043 17.824 15.512 c 18.332\n"     \
1749   "15.98 18.363 16.77 17.895 17.277 c 17.43 17.785 16.637 17.816 16.129\n"   \
1750   "17.352 c 15.621 16.883 15.59 16.094 16.059 15.586 c h\n"                  \
1751   "16.059 15.586 m S\n"                                                      \
1752   "0.729412 0.741176 0.713725 RG 2 w\n"                                      \
1753   "11.895 19.754 m 13.926 21.625 17.09 21.496 18.961 19.465 c 20.832\n"      \
1754   "17.434 20.699 14.27 18.668 12.398 c 17.164 11.016 15.043 10.746 13.281\n" \
1755   "11.516 c 12.473 10.324 l 11.281 11.078 l 9.547 9.664 l 9.008 7.496 l\n"   \
1756   "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"   \
1757   "10.57 14.457 l 9.949 16.277 10.391 18.367 11.895 19.754 c h\n"            \
1758   "11.895 19.754 m S\n"                                                      \
1759   "1.5 w\n"                                                                  \
1760   "16.059 16.586 m 16.523 16.078 17.316 16.043 17.824 16.512 c 18.332\n"     \
1761   "16.98 18.363 17.77 17.895 18.277 c 17.43 18.785 16.637 18.816 16.129\n"   \
1762   "18.352 c 15.621 17.883 15.59 17.094 16.059 16.586 c h\n"                  \
1763   "16.059 16.586 m S\n"
1764 
1765 #define ANNOT_TEXT_AP_HELP                                                        \
1766   "4.301 23 m 19.699 23 l 21.523 23 23 21.523 23 19.699 c 23 4.301 l 23\n"        \
1767   "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"      \
1768   "l 1 21.523 2.477 23 4.301 23 c h\n"                                            \
1769   "4.301 23 m f\n"                                                                \
1770   "0.533333 0.541176 0.521569 RG 2.5 w\n"                                         \
1771   "1 J\n"                                                                         \
1772   "1 j\n"                                                                         \
1773   "[] 0.0 d\n"                                                                    \
1774   "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" \
1775   "14.328 18.559 15.195 17.406 c 16.062 16.254 16.242 14.723 15.664 13.398\n"     \
1776   "c S\n"                                                                         \
1777   "0 j\n"                                                                         \
1778   "12 8 m 12 12 16 11 16 15 c S\n"                                                \
1779   "1.539286 w\n"                                                                  \
1780   "1 j\n"                                                                         \
1781   "q 1 0 0 -0.999991 0 24 cm\n"                                                   \
1782   "12.684 20.891 m 12.473 21.258 12.004 21.395 11.629 21.196 c 11.254\n"          \
1783   "20.992 11.105 20.531 11.297 20.149 c 11.488 19.77 11.945 19.61 12.332\n"       \
1784   "19.789 c 12.719 19.969 12.891 20.426 12.719 20.817 c S Q\n"                    \
1785   "0.729412 0.741176 0.713725 RG 2.5 w\n"                                         \
1786   "8.289 17.488 m 9.109 19.539 11.438 20.535 13.488 19.711 c 15.539 18.891\n"     \
1787   "16.535 16.562 15.711 14.512 c 15.699 14.473 15.684 14.438 15.664 14.398\n"     \
1788   "c S\n"                                                                         \
1789   "0 j\n"                                                                         \
1790   "12 9 m 12 13 16 12 16 16 c S\n"                                                \
1791   "1.539286 w\n"                                                                  \
1792   "1 j\n"                                                                         \
1793   "q 1 0 0 -0.999991 0 24 cm\n"                                                   \
1794   "12.684 19.891 m 12.473 20.258 12.004 20.395 11.629 20.195 c 11.254\n"          \
1795   "19.992 11.105 19.531 11.297 19.149 c 11.488 18.77 11.945 18.61 12.332\n"       \
1796   "18.789 c 12.719 18.969 12.891 19.426 12.719 19.817 c S Q\n"
1797 
1798 #define ANNOT_TEXT_AP_NEW_PARAGRAPH                                               \
1799   "4.301 23 m 19.699 23 l 21.523 23 23 21.523 23 19.699 c 23 4.301 l 23\n"        \
1800   "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"      \
1801   "l 1 21.523 2.477 23 4.301 23 c h\n"                                            \
1802   "4.301 23 m f\n"                                                                \
1803   "0.533333 0.541176 0.521569 RG 4 w\n"                                           \
1804   "0 J\n"                                                                         \
1805   "2 j\n"                                                                         \
1806   "[] 0.0 d\n"                                                                    \
1807   "4 M q 1 0 0 -1 0 24 cm\n"                                                      \
1808   "9.211 11.988 m 8.449 12.07 7.711 11.707 7.305 11.059 c 6.898 10.41\n"          \
1809   "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"           \
1810   "1.004413 w\n"                                                                  \
1811   "1 J\n"                                                                         \
1812   "1 j\n"                                                                         \
1813   "q 1 0 0 -0.991232 0 24 cm\n"                                                   \
1814   "18.07 11.511 m 15.113 10.014 l 12.199 11.602 l 12.711 8.323 l 10.301\n"        \
1815   "6.045 l 13.574 5.517 l 14.996 2.522 l 16.512 5.474 l 19.801 5.899 l\n"         \
1816   "17.461 8.252 l 18.07 11.511 l h\n"                                             \
1817   "18.07 11.511 m S Q\n"                                                          \
1818   "2 w\n"                                                                         \
1819   "0 j\n"                                                                         \
1820   "11 17 m 10 17 l 10 3 l S\n"                                                    \
1821   "14 3 m 14 13 l S\n"                                                            \
1822   "0.729412 0.741176 0.713725 RG 4 w\n"                                           \
1823   "0 J\n"                                                                         \
1824   "2 j\n"                                                                         \
1825   "q 1 0 0 -1 0 24 cm\n"                                                          \
1826   "9.211 10.988 m 8.109 11.105 7.125 10.309 7.012 9.211 c 6.895 8.109\n"          \
1827   "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"           \
1828   "1.004413 w\n"                                                                  \
1829   "1 J\n"                                                                         \
1830   "1 j\n"                                                                         \
1831   "q 1 0 0 -0.991232 0 24 cm\n"                                                   \
1832   "18.07 10.502 m 15.113 9.005 l 12.199 10.593 l 12.711 7.314 l 10.301\n"         \
1833   "5.036 l 13.574 4.508 l 14.996 1.513 l 16.512 4.465 l 19.801 4.891 l\n"         \
1834   "17.461 7.243 l 18.07 10.502 l h\n"                                             \
1835   "18.07 10.502 m S Q\n"                                                          \
1836   "2 w\n"                                                                         \
1837   "0 j\n"                                                                         \
1838   "11 18 m 10 18 l 10 4 l S\n"                                                    \
1839   "14 4 m 14 14 l S\n"
1840 
1841 #define ANNOT_TEXT_AP_PARAGRAPH                                              \
1842   "4.301 23 m 19.699 23 l 21.523 23 23 21.523 23 19.699 c 23 4.301 l 23\n"   \
1843   "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" \
1844   "l 1 21.523 2.477 23 4.301 23 c h\n"                                       \
1845   "4.301 23 m f\n"                                                           \
1846   "0.533333 0.541176 0.521569 RG 2 w\n"                                      \
1847   "1 J\n"                                                                    \
1848   "1 j\n"                                                                    \
1849   "[] 0.0 d\n"                                                               \
1850   "4 M 15 3 m 15 18 l 11 18 l 11 3 l S\n"                                    \
1851   "4 w\n"                                                                    \
1852   "q 1 0 0 -1 0 24 cm\n"                                                     \
1853   "9.777 10.988 m 8.746 10.871 7.973 9.988 8 8.949 c 8.027 7.91 8.844\n"     \
1854   "7.066 9.879 7.004 c S Q\n"                                                \
1855   "0.729412 0.741176 0.713725 RG 2 w\n"                                      \
1856   "15 4 m 15 19 l 11 19 l 11 4 l S\n"                                        \
1857   "4 w\n"                                                                    \
1858   "q 1 0 0 -1 0 24 cm\n"                                                     \
1859   "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" \
1860   "9.879 6.004 c S Q\n"
1861 
1862 #define ANNOT_TEXT_AP_INSERT                                                 \
1863   "4.301 23 m 19.699 23 l 21.523 23 23 21.523 23 19.699 c 23 4.301 l 23\n"   \
1864   "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" \
1865   "l 1 21.523 2.477 23 4.301 23 c h\n"                                       \
1866   "4.301 23 m f\n"                                                           \
1867   "0.533333 0.541176 0.521569 RG 2 w\n"                                      \
1868   "1 J\n"                                                                    \
1869   "0 j\n"                                                                    \
1870   "[] 0.0 d\n"                                                               \
1871   "4 M 12 18.012 m 20 18 l S\n"                                              \
1872   "9 10 m 17 10 l S\n"                                                       \
1873   "12 14.012 m 20 14 l S\n"                                                  \
1874   "12 6.012 m 20 6.012 l S\n"                                                \
1875   "4 12 m 6 10 l 4 8 l S\n"                                                  \
1876   "4 12 m 4 8 l S\n"                                                         \
1877   "0.729412 0.741176 0.713725 RG 12 19.012 m 20 19 l S\n"                    \
1878   "9 11 m 17 11 l S\n"                                                       \
1879   "12 15.012 m 20 15 l S\n"                                                  \
1880   "12 7.012 m 20 7.012 l S\n"                                                \
1881   "4 13 m 6 11 l 4 9 l S\n"                                                  \
1882   "4 13 m 4 9 l S\n"
1883 
1884 #define ANNOT_TEXT_AP_CROSS                                                  \
1885   "4.301 23 m 19.699 23 l 21.523 23 23 21.523 23 19.699 c 23 4.301 l 23\n"   \
1886   "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" \
1887   "l 1 21.523 2.477 23 4.301 23 c h\n"                                       \
1888   "4.301 23 m f\n"                                                           \
1889   "0.533333 0.541176 0.521569 RG 2.5 w\n"                                    \
1890   "1 J\n"                                                                    \
1891   "0 j\n"                                                                    \
1892   "[] 0.0 d\n"                                                               \
1893   "4 M 18 5 m 6 17 l S\n"                                                    \
1894   "6 5 m 18 17 l S\n"                                                        \
1895   "0.729412 0.741176 0.713725 RG 18 6 m 6 18 l S\n"                          \
1896   "6 6 m 18 18 l S\n"
1897 
1898 #define ANNOT_TEXT_AP_CIRCLE                                                      \
1899   "4.301 23 m 19.699 23 l 21.523 23 23 21.523 23 19.699 c 23 4.301 l 23\n"        \
1900   "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"      \
1901   "l 1 21.523 2.477 23 4.301 23 c h\n"                                            \
1902   "4.301 23 m f\n"                                                                \
1903   "0.533333 0.541176 0.521569 RG 2.5 w\n"                                         \
1904   "1 J\n"                                                                         \
1905   "1 j\n"                                                                         \
1906   "[] 0.0 d\n"                                                                    \
1907   "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" \
1908   "15.641 7.859 19 12 19 c 16.141 19 19.5 15.641 19.5 11.5 c h\n"                 \
1909   "19.5 11.5 m S\n"                                                               \
1910   "0.729412 0.741176 0.713725 RG 19.5 12.5 m 19.5 8.359 16.141 5 12 5 c\n"        \
1911   "7.859 5 4.5 8.359 4.5 12.5 c 4.5\n"                                            \
1912   "16.641 7.859 20 12 20 c 16.141 20 19.5 16.641 19.5 12.5 c h\n"                 \
1913   "19.5 12.5 m S\n"
1914 
draw(Gfx * gfx,GBool printing)1915 void AnnotText::draw(Gfx *gfx, GBool printing) {
1916   Object obj;
1917   double ca = 1;
1918 
1919   if (!isVisible (printing))
1920     return;
1921 
1922   double rectx2 = rect->x2;
1923   double recty2 = rect->y2;
1924   if (appearance.isNull()) {
1925     ca = opacity;
1926 
1927     appearBuf = new GooString ();
1928 
1929     appearBuf->append ("q\n");
1930     if (color)
1931       setColor(color, gTrue);
1932     else
1933       appearBuf->append ("1 1 1 rg\n");
1934     if (!icon->cmp("Note"))
1935       appearBuf->append (ANNOT_TEXT_AP_NOTE);
1936     else if (!icon->cmp("Comment"))
1937       appearBuf->append (ANNOT_TEXT_AP_COMMENT);
1938     else if (!icon->cmp("Key"))
1939       appearBuf->append (ANNOT_TEXT_AP_KEY);
1940     else if (!icon->cmp("Help"))
1941       appearBuf->append (ANNOT_TEXT_AP_HELP);
1942     else if (!icon->cmp("NewParagraph"))
1943       appearBuf->append (ANNOT_TEXT_AP_NEW_PARAGRAPH);
1944     else if (!icon->cmp("Paragraph"))
1945       appearBuf->append (ANNOT_TEXT_AP_PARAGRAPH);
1946     else if (!icon->cmp("Insert"))
1947       appearBuf->append (ANNOT_TEXT_AP_INSERT);
1948     else if (!icon->cmp("Cross"))
1949       appearBuf->append (ANNOT_TEXT_AP_CROSS);
1950     else if (!icon->cmp("Circle"))
1951       appearBuf->append (ANNOT_TEXT_AP_CIRCLE);
1952     appearBuf->append ("Q\n");
1953 
1954     double bbox[4];
1955     bbox[0] = bbox[1] = 0;
1956     bbox[2] = bbox[3] = 24;
1957     if (ca == 1) {
1958       createForm(bbox, gFalse, NULL, &appearance);
1959     } else {
1960       Object aStream, resDict;
1961 
1962       createForm(bbox, gTrue, NULL, &aStream);
1963       delete appearBuf;
1964 
1965       appearBuf = new GooString ("/GS0 gs\n/Fm0 Do");
1966       createResourcesDict("Fm0", &aStream, "GS0", ca, NULL, &resDict);
1967       createForm(bbox, gFalse, &resDict, &appearance);
1968     }
1969     delete appearBuf;
1970 
1971     rectx2 = rect->x1 + 24;
1972     recty2 = rect->y1 + 24;
1973   }
1974 
1975   // draw the appearance stream
1976   appearance.fetch(xref, &obj);
1977   gfx->drawAnnot(&obj, border, color,
1978 		 rect->x1, rect->y1, rectx2, recty2);
1979   obj.free();
1980 }
1981 
1982 //------------------------------------------------------------------------
1983 // AnnotLink
1984 //------------------------------------------------------------------------
AnnotLink(XRef * xrefA,PDFRectangle * rect,Catalog * catalog)1985 AnnotLink::AnnotLink(XRef *xrefA, PDFRectangle *rect, Catalog *catalog) :
1986     Annot(xrefA, rect, catalog) {
1987   Object obj1;
1988 
1989   type = typeLink;
1990   annotObj.dictSet ("Subtype", obj1.initName ("Link"));
1991   initialize (xrefA, catalog, annotObj.getDict());
1992 }
1993 
AnnotLink(XRef * xrefA,Dict * dict,Catalog * catalog,Object * obj)1994 AnnotLink::AnnotLink(XRef *xrefA, Dict *dict, Catalog *catalog, Object *obj) :
1995     Annot(xrefA, dict, catalog, obj) {
1996 
1997   type = typeLink;
1998   initialize (xrefA, catalog, dict);
1999 }
2000 
~AnnotLink()2001 AnnotLink::~AnnotLink() {
2002   /*
2003   if (actionDict)
2004     delete actionDict;
2005   */
2006   dest.free();
2007   /*
2008   if (uriAction)
2009     delete uriAction;
2010   */
2011   if (quadrilaterals)
2012     delete quadrilaterals;
2013 }
2014 
initialize(XRef * xrefA,Catalog * catalog,Dict * dict)2015 void AnnotLink::initialize(XRef *xrefA, Catalog *catalog, Dict *dict) {
2016   Object obj1;
2017   /*
2018   if (dict->lookup("A", &obj1)->isDict()) {
2019     actionDict = NULL;
2020   } else {
2021     actionDict = NULL;
2022   }
2023   obj1.free();
2024   */
2025   dict->lookup("Dest", &dest);
2026   if (dict->lookup("H", &obj1)->isName()) {
2027     GooString *effect = new GooString(obj1.getName());
2028 
2029     if (!effect->cmp("N")) {
2030       linkEffect = effectNone;
2031     } else if (!effect->cmp("I")) {
2032       linkEffect = effectInvert;
2033     } else if (!effect->cmp("O")) {
2034       linkEffect = effectOutline;
2035     } else if (!effect->cmp("P")) {
2036       linkEffect = effectPush;
2037     } else {
2038       linkEffect = effectInvert;
2039     }
2040     delete effect;
2041   } else {
2042     linkEffect = effectInvert;
2043   }
2044   obj1.free();
2045   /*
2046   if (dict->lookup("PA", &obj1)->isDict()) {
2047     uriAction = NULL;
2048   } else {
2049     uriAction = NULL;
2050   }
2051   obj1.free();
2052   */
2053   if (dict->lookup("QuadPoints", &obj1)->isArray()) {
2054     quadrilaterals = new AnnotQuadrilaterals(obj1.getArray(), rect);
2055   } else {
2056     quadrilaterals = NULL;
2057   }
2058   obj1.free();
2059 }
2060 
draw(Gfx * gfx,GBool printing)2061 void AnnotLink::draw(Gfx *gfx, GBool printing) {
2062   Object obj;
2063 
2064   if (!isVisible (printing))
2065     return;
2066 
2067   // draw the appearance stream
2068   appearance.fetch(xref, &obj);
2069   gfx->drawAnnot(&obj, border, color,
2070 		 rect->x1, rect->y1, rect->x2, rect->y2);
2071   obj.free();
2072 }
2073 
2074 //------------------------------------------------------------------------
2075 // AnnotFreeText
2076 //------------------------------------------------------------------------
AnnotFreeText(XRef * xrefA,PDFRectangle * rect,GooString * da,Catalog * catalog)2077 AnnotFreeText::AnnotFreeText(XRef *xrefA, PDFRectangle *rect, GooString *da, Catalog *catalog) :
2078     AnnotMarkup(xrefA, rect, catalog) {
2079   Object obj1;
2080 
2081   type = typeFreeText;
2082 
2083   annotObj.dictSet ("Subtype", obj1.initName ("FreeText"));
2084 
2085   Object obj2;
2086   obj2.initString (da->copy());
2087   annotObj.dictSet("DA", &obj2);
2088 
2089   initialize (xrefA, catalog, annotObj.getDict());
2090 }
2091 
AnnotFreeText(XRef * xrefA,Dict * dict,Catalog * catalog,Object * obj)2092 AnnotFreeText::AnnotFreeText(XRef *xrefA, Dict *dict, Catalog *catalog, Object *obj) :
2093     AnnotMarkup(xrefA, dict, catalog, obj) {
2094   type = typeFreeText;
2095   initialize(xrefA, catalog, dict);
2096 }
2097 
~AnnotFreeText()2098 AnnotFreeText::~AnnotFreeText() {
2099   delete appearanceString;
2100 
2101   if (styleString)
2102     delete styleString;
2103 
2104   if (calloutLine)
2105     delete calloutLine;
2106 
2107   if (borderEffect)
2108     delete borderEffect;
2109 
2110   if (rectangle)
2111     delete rectangle;
2112 }
2113 
initialize(XRef * xrefA,Catalog * catalog,Dict * dict)2114 void AnnotFreeText::initialize(XRef *xrefA, Catalog *catalog, Dict *dict) {
2115   Object obj1;
2116 
2117   if (dict->lookup("DA", &obj1)->isString()) {
2118     appearanceString = obj1.getString()->copy();
2119   } else {
2120     appearanceString = new GooString();
2121     error(-1, "Bad appearance for annotation");
2122     ok = gFalse;
2123   }
2124   obj1.free();
2125 
2126   if (dict->lookup("Q", &obj1)->isInt()) {
2127     quadding = (AnnotFreeTextQuadding) obj1.getInt();
2128   } else {
2129     quadding = quaddingLeftJustified;
2130   }
2131   obj1.free();
2132 
2133   if (dict->lookup("DS", &obj1)->isString()) {
2134     styleString = obj1.getString()->copy();
2135   } else {
2136     styleString = NULL;
2137   }
2138   obj1.free();
2139 
2140   if (dict->lookup("CL", &obj1)->isArray() && obj1.arrayGetLength() >= 4) {
2141     double x1, y1, x2, y2;
2142     Object obj2;
2143 
2144     (obj1.arrayGet(0, &obj2)->isNum() ? x1 = obj2.getNum() : x1 = 0);
2145     obj2.free();
2146     (obj1.arrayGet(1, &obj2)->isNum() ? y1 = obj2.getNum() : y1 = 0);
2147     obj2.free();
2148     (obj1.arrayGet(2, &obj2)->isNum() ? x2 = obj2.getNum() : x2 = 0);
2149     obj2.free();
2150     (obj1.arrayGet(3, &obj2)->isNum() ? y2 = obj2.getNum() : y2 = 0);
2151     obj2.free();
2152 
2153     if (obj1.arrayGetLength() == 6) {
2154       double x3, y3;
2155       (obj1.arrayGet(4, &obj2)->isNum() ? x3 = obj2.getNum() : x3 = 0);
2156       obj2.free();
2157       (obj1.arrayGet(5, &obj2)->isNum() ? y3 = obj2.getNum() : y3 = 0);
2158       obj2.free();
2159       calloutLine = new AnnotCalloutMultiLine(x1, y1, x2, y2, x3, y3);
2160     } else {
2161       calloutLine = new AnnotCalloutLine(x1, y1, x2, y2);
2162     }
2163   } else {
2164     calloutLine = NULL;
2165   }
2166   obj1.free();
2167 
2168   if (dict->lookup("IT", &obj1)->isName()) {
2169     GooString *intentName = new GooString(obj1.getName());
2170 
2171     if (!intentName->cmp("FreeText")) {
2172       intent = intentFreeText;
2173     } else if (!intentName->cmp("FreeTextCallout")) {
2174       intent = intentFreeTextCallout;
2175     } else if (!intentName->cmp("FreeTextTypeWriter")) {
2176       intent = intentFreeTextTypeWriter;
2177     } else {
2178       intent = intentFreeText;
2179     }
2180     delete intentName;
2181   } else {
2182     intent = intentFreeText;
2183   }
2184   obj1.free();
2185 
2186   if (dict->lookup("BE", &obj1)->isDict()) {
2187     borderEffect = new AnnotBorderEffect(obj1.getDict());
2188   } else {
2189     borderEffect = NULL;
2190   }
2191   obj1.free();
2192 
2193   if (dict->lookup("RD", &obj1)->isArray()) {
2194     rectangle = parseDiffRectangle(obj1.getArray(), rect);
2195   } else {
2196     rectangle = NULL;
2197   }
2198   obj1.free();
2199 
2200   if (dict->lookup("LE", &obj1)->isName()) {
2201     GooString *styleName = new GooString(obj1.getName());
2202     endStyle = parseAnnotLineEndingStyle(styleName);
2203     delete styleName;
2204   } else {
2205     endStyle = annotLineEndingNone;
2206   }
2207   obj1.free();
2208 }
2209 
2210 //------------------------------------------------------------------------
2211 // AnnotLine
2212 //------------------------------------------------------------------------
2213 
AnnotLine(XRef * xrefA,PDFRectangle * rect,PDFRectangle * lRect,Catalog * catalog)2214 AnnotLine::AnnotLine(XRef *xrefA, PDFRectangle *rect, PDFRectangle *lRect, Catalog *catalog) :
2215     AnnotMarkup(xrefA, rect, catalog) {
2216   Object obj1;
2217 
2218   type = typeLine;
2219   annotObj.dictSet ("Subtype", obj1.initName ("Line"));
2220 
2221   Object obj2, obj3;
2222   obj2.initArray (xrefA);
2223   obj2.arrayAdd (obj3.initReal (lRect->x1));
2224   obj2.arrayAdd (obj3.initReal (lRect->y1));
2225   obj2.arrayAdd (obj3.initReal (lRect->x2));
2226   obj2.arrayAdd (obj3.initReal (lRect->y2));
2227   annotObj.dictSet ("L", &obj2);
2228 
2229   initialize (xrefA, catalog, annotObj.getDict());
2230 }
2231 
AnnotLine(XRef * xrefA,Dict * dict,Catalog * catalog,Object * obj)2232 AnnotLine::AnnotLine(XRef *xrefA, Dict *dict, Catalog *catalog, Object *obj) :
2233     AnnotMarkup(xrefA, dict, catalog, obj) {
2234   type = typeLine;
2235   initialize(xrefA, catalog, dict);
2236 }
2237 
~AnnotLine()2238 AnnotLine::~AnnotLine() {
2239   delete coord1;
2240   delete coord2;
2241 
2242   if (interiorColor)
2243     delete interiorColor;
2244 
2245   if (measure)
2246     delete measure;
2247 }
2248 
initialize(XRef * xrefA,Catalog * catalog,Dict * dict)2249 void AnnotLine::initialize(XRef *xrefA, Catalog *catalog, Dict *dict) {
2250   Object obj1;
2251 
2252   if (dict->lookup("L", &obj1)->isArray() && obj1.arrayGetLength() == 4) {
2253     Object obj2;
2254     double x1, y1, x2, y2;
2255 
2256     (obj1.arrayGet(0, &obj2)->isNum() ? x1 = obj2.getNum() : x1 = 0);
2257     obj2.free();
2258     (obj1.arrayGet(1, &obj2)->isNum() ? y1 = obj2.getNum() : y1 = 0);
2259     obj2.free();
2260     (obj1.arrayGet(2, &obj2)->isNum() ? x2 = obj2.getNum() : x2 = 0);
2261     obj2.free();
2262     (obj1.arrayGet(3, &obj2)->isNum() ? y2 = obj2.getNum() : y2 = 0);
2263     obj2.free();
2264 
2265     coord1 = new AnnotCoord(x1, y1);
2266     coord2 = new AnnotCoord(x2, y2);
2267   } else {
2268     coord1 = new AnnotCoord();
2269     coord2 = new AnnotCoord();
2270   }
2271   obj1.free();
2272 
2273   if (dict->lookup("LE", &obj1)->isArray() && obj1.arrayGetLength() == 2) {
2274     Object obj2;
2275 
2276     if(obj1.arrayGet(0, &obj2)->isString())
2277       startStyle = parseAnnotLineEndingStyle(obj2.getString());
2278     else
2279       startStyle = annotLineEndingNone;
2280     obj2.free();
2281 
2282     if(obj1.arrayGet(1, &obj2)->isString())
2283       endStyle = parseAnnotLineEndingStyle(obj2.getString());
2284     else
2285       endStyle = annotLineEndingNone;
2286     obj2.free();
2287 
2288   } else {
2289     startStyle = endStyle = annotLineEndingNone;
2290   }
2291   obj1.free();
2292 
2293   if (dict->lookup("IC", &obj1)->isArray()) {
2294     interiorColor = new AnnotColor(obj1.getArray());
2295   } else {
2296     interiorColor = NULL;
2297   }
2298   obj1.free();
2299 
2300   if (dict->lookup("LL", &obj1)->isNum()) {
2301     leaderLineLength = obj1.getNum();
2302   } else {
2303     leaderLineLength = 0;
2304   }
2305   obj1.free();
2306 
2307   if (dict->lookup("LLE", &obj1)->isNum()) {
2308     leaderLineExtension = obj1.getNum();
2309 
2310     if (leaderLineExtension < 0)
2311       leaderLineExtension = 0;
2312   } else {
2313     leaderLineExtension = 0;
2314   }
2315   obj1.free();
2316 
2317   if (dict->lookup("Cap", &obj1)->isBool()) {
2318     caption = obj1.getBool();
2319   } else {
2320     caption = gFalse;
2321   }
2322   obj1.free();
2323 
2324   if (dict->lookup("IT", &obj1)->isName()) {
2325     GooString *intentName = new GooString(obj1.getName());
2326 
2327     if(!intentName->cmp("LineArrow")) {
2328       intent = intentLineArrow;
2329     } else if(!intentName->cmp("LineDimension")) {
2330       intent = intentLineDimension;
2331     } else {
2332       intent = intentLineArrow;
2333     }
2334     delete intentName;
2335   } else {
2336     intent = intentLineArrow;
2337   }
2338   obj1.free();
2339 
2340   if (dict->lookup("LLO", &obj1)->isNum()) {
2341     leaderLineOffset = obj1.getNum();
2342 
2343     if (leaderLineOffset < 0)
2344       leaderLineOffset = 0;
2345   } else {
2346     leaderLineOffset = 0;
2347   }
2348   obj1.free();
2349 
2350   if (dict->lookup("CP", &obj1)->isName()) {
2351     GooString *captionName = new GooString(obj1.getName());
2352 
2353     if(!captionName->cmp("Inline")) {
2354       captionPos = captionPosInline;
2355     } else if(!captionName->cmp("Top")) {
2356       captionPos = captionPosTop;
2357     } else {
2358       captionPos = captionPosInline;
2359     }
2360     delete captionName;
2361   } else {
2362     captionPos = captionPosInline;
2363   }
2364   obj1.free();
2365 
2366   if (dict->lookup("Measure", &obj1)->isDict()) {
2367     measure = NULL;
2368   } else {
2369     measure = NULL;
2370   }
2371   obj1.free();
2372 
2373   if ((dict->lookup("CO", &obj1)->isArray()) && (obj1.arrayGetLength() == 2)) {
2374     Object obj2;
2375 
2376     (obj1.arrayGet(0, &obj2)->isNum() ? captionTextHorizontal = obj2.getNum() :
2377       captionTextHorizontal = 0);
2378     obj2.free();
2379     (obj1.arrayGet(1, &obj2)->isNum() ? captionTextVertical = obj2.getNum() :
2380       captionTextVertical = 0);
2381     obj2.free();
2382   } else {
2383     captionTextHorizontal = captionTextVertical = 0;
2384   }
2385   obj1.free();
2386 }
2387 
draw(Gfx * gfx,GBool printing)2388 void AnnotLine::draw(Gfx *gfx, GBool printing) {
2389   Object obj;
2390   double ca = 1;
2391 
2392   if (!isVisible (printing))
2393     return;
2394 
2395   /* Some documents like pdf_commenting_new.pdf,
2396    * have y1 = y2 but line_width > 0, acroread
2397    * renders the lines in such cases even though
2398    * the annot bbox is empty. We adjust the bbox here
2399    * to avoid having an empty bbox so that lines
2400    * are rendered
2401    */
2402   if (rect->y1 == rect->y2)
2403     rect->y2 += border ? border->getWidth() : 1;
2404 
2405   if (appearance.isNull()) {
2406     ca = opacity;
2407 
2408     appearBuf = new GooString ();
2409     appearBuf->append ("q\n");
2410     if (color)
2411       setColor(color, gFalse);
2412 
2413     if (border) {
2414       int i, dashLength;
2415       double *dash;
2416 
2417       switch (border->getStyle()) {
2418       case AnnotBorder::borderDashed:
2419         appearBuf->append("[");
2420 	dashLength = border->getDashLength();
2421 	dash = border->getDash();
2422 	for (i = 0; i < dashLength; ++i)
2423 	  appearBuf->appendf(" {0:.2f}", dash[i]);
2424 	appearBuf->append(" ] 0 d\n");
2425 	break;
2426       default:
2427         appearBuf->append("[] 0 d\n");
2428         break;
2429       }
2430       appearBuf->appendf("{0:.2f} w\n", border->getWidth());
2431     }
2432     appearBuf->appendf ("{0:.2f} {1:.2f} m\n", coord1->getX() - rect->x1, coord1->getY() - rect->y1);
2433     appearBuf->appendf ("{0:.2f} {1:.2f} l\n", coord2->getX() - rect->x1, coord2->getY() - rect->y1);
2434     // TODO: Line ending, caption, leader lines
2435     appearBuf->append ("S\n");
2436     appearBuf->append ("Q\n");
2437 
2438     double bbox[4];
2439     bbox[0] = bbox[1] = 0;
2440     bbox[2] = rect->x2 - rect->x1;
2441     bbox[3] = rect->y2 - rect->y1;
2442     if (ca == 1) {
2443       createForm(bbox, gFalse, NULL, &appearance);
2444     } else {
2445       Object aStream, resDict;
2446 
2447       createForm(bbox, gTrue, NULL, &aStream);
2448       delete appearBuf;
2449 
2450       appearBuf = new GooString ("/GS0 gs\n/Fm0 Do");
2451       createResourcesDict("Fm0", &aStream, "GS0", ca, NULL, &resDict);
2452       createForm(bbox, gFalse, &resDict, &appearance);
2453     }
2454     delete appearBuf;
2455   }
2456 
2457   // draw the appearance stream
2458   appearance.fetch(xref, &obj);
2459   gfx->drawAnnot(&obj, (AnnotBorder *)NULL, color,
2460 		 rect->x1, rect->y1, rect->x2, rect->y2);
2461   obj.free();
2462 }
2463 
2464 //------------------------------------------------------------------------
2465 // AnnotTextMarkup
2466 //------------------------------------------------------------------------
AnnotTextMarkup(XRef * xrefA,PDFRectangle * rect,AnnotSubtype subType,AnnotQuadrilaterals * quadPoints,Catalog * catalog)2467 AnnotTextMarkup::AnnotTextMarkup(XRef *xrefA, PDFRectangle *rect, AnnotSubtype subType,
2468 				 AnnotQuadrilaterals *quadPoints, Catalog *catalog) :
2469     AnnotMarkup(xrefA, rect, catalog) {
2470   Object obj1;
2471 
2472   switch (subType) {
2473     case typeHighlight:
2474       annotObj.dictSet ("Subtype", obj1.initName ("Highlight"));
2475       break;
2476     case typeUnderline:
2477       annotObj.dictSet ("Subtype", obj1.initName ("Underline"));
2478       break;
2479     case typeSquiggly:
2480       annotObj.dictSet ("Subtype", obj1.initName ("Squiggly"));
2481       break;
2482     case typeStrikeOut:
2483       annotObj.dictSet ("Subtype", obj1.initName ("StrikeOut"));
2484       break;
2485     default:
2486       assert (0 && "Invalid subtype for AnnotTextMarkup\n");
2487   }
2488 
2489   Object obj2;
2490   obj2.initArray (xrefA);
2491 
2492   for (int i = 0; i < quadPoints->getQuadrilateralsLength(); ++i) {
2493     Object obj3;
2494 
2495     obj2.arrayAdd (obj3.initReal (quadPoints->getX1(i)));
2496     obj2.arrayAdd (obj3.initReal (quadPoints->getY1(i)));
2497     obj2.arrayAdd (obj3.initReal (quadPoints->getX2(i)));
2498     obj2.arrayAdd (obj3.initReal (quadPoints->getY2(i)));
2499     obj2.arrayAdd (obj3.initReal (quadPoints->getX3(i)));
2500     obj2.arrayAdd (obj3.initReal (quadPoints->getY3(i)));
2501     obj2.arrayAdd (obj3.initReal (quadPoints->getX4(i)));
2502     obj2.arrayAdd (obj3.initReal (quadPoints->getY4(i)));
2503   }
2504 
2505   annotObj.dictSet ("QuadPoints", &obj2);
2506 
2507   initialize(xrefA, catalog, annotObj.getDict());
2508 }
2509 
AnnotTextMarkup(XRef * xrefA,Dict * dict,Catalog * catalog,Object * obj)2510 AnnotTextMarkup::AnnotTextMarkup(XRef *xrefA, Dict *dict, Catalog *catalog, Object *obj) :
2511   AnnotMarkup(xrefA, dict, catalog, obj) {
2512   // the real type will be read in initialize()
2513   type = typeHighlight;
2514   initialize(xrefA, catalog, dict);
2515 }
2516 
initialize(XRef * xrefA,Catalog * catalog,Dict * dict)2517 void AnnotTextMarkup::initialize(XRef *xrefA, Catalog *catalog, Dict *dict) {
2518   Object obj1;
2519 
2520   if (dict->lookup("Subtype", &obj1)->isName()) {
2521     GooString typeName(obj1.getName());
2522     if (!typeName.cmp("Highlight")) {
2523       type = typeHighlight;
2524     } else if (!typeName.cmp("Underline")) {
2525       type = typeUnderline;
2526     } else if (!typeName.cmp("Squiggly")) {
2527       type = typeSquiggly;
2528     } else if (!typeName.cmp("StrikeOut")) {
2529       type = typeStrikeOut;
2530     }
2531   }
2532   obj1.free();
2533 
2534   if(dict->lookup("QuadPoints", &obj1)->isArray()) {
2535     quadrilaterals = new AnnotQuadrilaterals(obj1.getArray(), rect);
2536   } else {
2537     error(-1, "Bad Annot Text Markup QuadPoints");
2538     quadrilaterals = NULL;
2539     ok = gFalse;
2540   }
2541   obj1.free();
2542 }
2543 
~AnnotTextMarkup()2544 AnnotTextMarkup::~AnnotTextMarkup() {
2545   if(quadrilaterals) {
2546     delete quadrilaterals;
2547   }
2548 }
2549 
2550 
2551 
draw(Gfx * gfx,GBool printing)2552 void AnnotTextMarkup::draw(Gfx *gfx, GBool printing) {
2553   Object obj;
2554   double ca = 1;
2555   int i;
2556   Object obj1, obj2;
2557 
2558   if (!isVisible (printing))
2559     return;
2560 
2561   if (appearance.isNull() || type == typeHighlight) {
2562     ca = opacity;
2563 
2564     appearBuf = new GooString ();
2565 
2566     switch (type) {
2567     case typeUnderline:
2568       if (color) {
2569         setColor(color, gFalse);
2570 	setColor(color, gTrue);
2571       }
2572 
2573       for (i = 0; i < quadrilaterals->getQuadrilateralsLength(); ++i) {
2574         double x1, y1, x2, y2, x3, y3;
2575 	double x, y;
2576 
2577 	x1 = quadrilaterals->getX1(i);
2578 	y1 = quadrilaterals->getY1(i);
2579 	x2 = quadrilaterals->getX2(i);
2580 	y2 = quadrilaterals->getY2(i);
2581 	x3 = quadrilaterals->getX3(i);
2582 	y3 = quadrilaterals->getY3(i);
2583 
2584 	x = x1 - rect->x1;
2585 	y = y3 - rect->y1;
2586 	appearBuf->append ("[]0 d 2 w\n");
2587 	appearBuf->appendf ("{0:.2f} {1:.2f} m\n", x, y);
2588 	appearBuf->appendf ("{0:.2f} {1:.2f} l\n", x + (x2 - x1), y);
2589 	appearBuf->append ("S\n");
2590       }
2591       break;
2592     case typeStrikeOut:
2593       if (color) {
2594         setColor(color, gFalse);
2595 	setColor(color, gTrue);
2596       }
2597 
2598       for (i = 0; i < quadrilaterals->getQuadrilateralsLength(); ++i) {
2599         double x1, y1, x2, y2, x3, y3;
2600 	double x, y;
2601 	double h2;
2602 
2603 	x1 = quadrilaterals->getX1(i);
2604 	y1 = quadrilaterals->getY1(i);
2605 	x2 = quadrilaterals->getX2(i);
2606 	y2 = quadrilaterals->getY2(i);
2607 	x3 = quadrilaterals->getX3(i);
2608 	y3 = quadrilaterals->getY3(i);
2609 	h2 = (y1 - y3) / 2.0;
2610 
2611 	x = x1 - rect->x1;
2612 	y = (y3 - rect->y1) + h2;
2613 	appearBuf->append ("[]0 d 2 w\n");
2614 	appearBuf->appendf ("{0:.2f} {1:.2f} m\n", x, y);
2615 	appearBuf->appendf ("{0:.2f} {1:.2f} l\n", x + (x2 - x1), y);
2616 	appearBuf->append ("S\n");
2617       }
2618       break;
2619     case typeSquiggly:
2620       // TODO
2621     default:
2622     case typeHighlight:
2623       appearance.free();
2624 
2625       if (color)
2626         setColor(color, gTrue);
2627 
2628       for (i = 0; i < quadrilaterals->getQuadrilateralsLength(); ++i) {
2629         double x1, y1, x2, y2, x3, y3, x4, y4;
2630 	double h4;
2631 
2632 	x1 = quadrilaterals->getX1(i);
2633 	y1 = quadrilaterals->getY1(i);
2634 	x2 = quadrilaterals->getX2(i);
2635 	y2 = quadrilaterals->getY2(i);
2636 	x3 = quadrilaterals->getX3(i);
2637 	y3 = quadrilaterals->getY3(i);
2638 	x4 = quadrilaterals->getX4(i);
2639 	y4 = quadrilaterals->getY4(i);
2640 	h4 = abs(y1 - y3) / 4.0;
2641 
2642 	appearBuf->appendf ("{0:.2f} {1:.2f} m\n", x3, y3);
2643 	appearBuf->appendf ("{0:.2f} {1:.2f} {2:.2f} {3:.2f} {4:.2f} {5:.2f} c\n",
2644 			    x3 - h4, y3 + h4, x1 - h4, y1 - h4, x1, y1);
2645 	appearBuf->appendf ("{0:.2f} {1:.2f} l\n", x2, y2);
2646 	appearBuf->appendf ("{0:.2f} {1:.2f} {2:.2f} {3:.2f} {4:.2f} {5:.2f} c\n",
2647 			    x2 + h4, y2 - h4, x4 + h4, y4 + h4, x4, y4);
2648 	appearBuf->append ("f\n");
2649       }
2650 
2651       Object aStream, resDict;
2652       double bbox[4];
2653       bbox[0] = rect->x1;
2654       bbox[1] = rect->y1;
2655       bbox[2] = rect->x2;
2656       bbox[3] = rect->y2;
2657       createForm(bbox, gTrue, NULL, &aStream);
2658       delete appearBuf;
2659 
2660       appearBuf = new GooString ("/GS0 gs\n/Fm0 Do");
2661       createResourcesDict("Fm0", &aStream, "GS0", 1, "Multiply", &resDict);
2662       if (ca == 1) {
2663         createForm(bbox, gFalse, &resDict, &appearance);
2664       } else {
2665         createForm(bbox, gTrue, &resDict, &aStream);
2666 	delete appearBuf;
2667 
2668 	appearBuf = new GooString ("/GS0 gs\n/Fm0 Do");
2669 	createResourcesDict("Fm0", &aStream, "GS0", ca, NULL, &resDict);
2670 	createForm(bbox, gFalse, &resDict, &appearance);
2671       }
2672       delete appearBuf;
2673       break;
2674     }
2675   }
2676 
2677   // draw the appearance stream
2678   appearance.fetch(xref, &obj);
2679   gfx->drawAnnot(&obj, (AnnotBorder *)NULL, color,
2680 		 rect->x1, rect->y1, rect->x2, rect->y2);
2681   obj.free();
2682 }
2683 
2684 //------------------------------------------------------------------------
2685 // AnnotWidget
2686 //------------------------------------------------------------------------
2687 
AnnotWidget(XRef * xrefA,Dict * dict,Catalog * catalog,Object * obj)2688 AnnotWidget::AnnotWidget(XRef *xrefA, Dict *dict, Catalog *catalog, Object *obj) :
2689     Annot(xrefA, dict, catalog, obj) {
2690   type = typeWidget;
2691   widget = NULL;
2692   initialize(xrefA, catalog, dict);
2693 }
2694 
~AnnotWidget()2695 AnnotWidget::~AnnotWidget() {
2696   if (appearCharacs)
2697     delete appearCharacs;
2698 
2699   if (action)
2700     delete action;
2701 
2702   if (additionActions)
2703     delete additionActions;
2704 
2705   if (parent)
2706     delete parent;
2707 }
2708 
initialize(XRef * xrefA,Catalog * catalog,Dict * dict)2709 void AnnotWidget::initialize(XRef *xrefA, Catalog *catalog, Dict *dict) {
2710   Object obj1;
2711 
2712   if ((form = catalog->getForm ())) {
2713     widget = form->findWidgetByRef (ref);
2714 
2715     // check if field apperances need to be regenerated
2716     // Only text or choice fields needs to have appearance regenerated
2717     // see section 8.6.2 "Variable Text" of PDFReference
2718     regen = gFalse;
2719     if (widget != NULL && (widget->getType () == formText || widget->getType () == formChoice)) {
2720       regen = form->getNeedAppearances ();
2721     }
2722   }
2723 
2724   // If field doesn't have an AP we'll have to generate it
2725   if (appearance.isNone () || appearance.isNull ())
2726     regen = gTrue;
2727 
2728   if(dict->lookup("H", &obj1)->isName()) {
2729     GooString *modeName = new GooString(obj1.getName());
2730 
2731     if(!modeName->cmp("N")) {
2732       mode = highlightModeNone;
2733     } else if(!modeName->cmp("O")) {
2734       mode = highlightModeOutline;
2735     } else if(!modeName->cmp("P") || !modeName->cmp("T")) {
2736       mode = highlightModePush;
2737     } else {
2738       mode = highlightModeInvert;
2739     }
2740     delete modeName;
2741   } else {
2742     mode = highlightModeInvert;
2743   }
2744   obj1.free();
2745 
2746   if(dict->lookup("MK", &obj1)->isDict()) {
2747     appearCharacs = new AnnotAppearanceCharacs(obj1.getDict());
2748   } else {
2749     appearCharacs = NULL;
2750   }
2751   obj1.free();
2752 
2753   if(dict->lookup("A", &obj1)->isDict()) {
2754     action = NULL;
2755   } else {
2756     action = NULL;
2757   }
2758   obj1.free();
2759 
2760   if(dict->lookup("AA", &obj1)->isDict()) {
2761     additionActions = NULL;
2762   } else {
2763     additionActions = NULL;
2764   }
2765   obj1.free();
2766 
2767   if(dict->lookup("Parent", &obj1)->isDict()) {
2768     parent = NULL;
2769   } else {
2770     parent = NULL;
2771   }
2772   obj1.free();
2773 }
2774 
2775 // Grand unified handler for preparing text strings to be drawn into form
2776 // fields.  Takes as input a text string (in PDFDocEncoding or UTF-16).
2777 // Converts some or all of this string to the appropriate encoding for the
2778 // specified font, and computes the width of the text.  Can optionally stop
2779 // converting when a specified width has been reached, to perform line-breaking
2780 // for multi-line fields.
2781 //
2782 // Parameters:
2783 //   text: input text string to convert
2784 //   outBuf: buffer for writing re-encoded string
2785 //   i: index at which to start converting; will be updated to point just after
2786 //      last character processed
2787 //   font: the font which will be used for display
2788 //   width: computed width (unscaled by font size) will be stored here
2789 //   widthLimit: if non-zero, stop converting to keep width under this value
2790 //      (should be scaled down by font size)
2791 //   charCount: count of number of characters will be stored here
2792 //   noReencode: if set, do not try to translate the character encoding
2793 //      (useful for Zapf Dingbats or other unusual encodings)
2794 //      can only be used with simple fonts, not CID-keyed fonts
2795 //
2796 // TODO: Handle surrogate pairs in UTF-16.
2797 //       Should be able to generate output for any CID-keyed font.
2798 //       Doesn't handle vertical fonts--should it?
layoutText(GooString * text,GooString * outBuf,int * i,GfxFont * font,double * width,double widthLimit,int * charCount,GBool noReencode)2799 void AnnotWidget::layoutText(GooString *text, GooString *outBuf, int *i,
2800                              GfxFont *font, double *width, double widthLimit,
2801                              int *charCount, GBool noReencode)
2802 {
2803   CharCode c;
2804   Unicode uChar, *uAux;
2805   double w = 0.0;
2806   int uLen, n;
2807   double dx, dy, ox, oy;
2808   GBool unicode = text->hasUnicodeMarker();
2809   GBool spacePrev;              // previous character was a space
2810 
2811   // State for backtracking when more text has been processed than fits within
2812   // widthLimit.  We track for both input (text) and output (outBuf) the offset
2813   // to the first character to discard.
2814   //
2815   // We keep track of several points:
2816   //   1 - end of previous completed word which fits
2817   //   2 - previous character which fit
2818   int last_i1, last_i2, last_o1, last_o2;
2819 
2820   if (unicode && text->getLength() % 2 != 0) {
2821     error(-1, "AnnotWidget::layoutText, bad unicode string");
2822     return;
2823   }
2824 
2825   // skip Unicode marker on string if needed
2826   if (unicode && *i == 0)
2827     *i = 2;
2828 
2829   // Start decoding and copying characters, until either:
2830   //   we reach the end of the string
2831   //   we reach the maximum width
2832   //   we reach a newline character
2833   // As we copy characters, keep track of the last full word to fit, so that we
2834   // can backtrack if we exceed the maximum width.
2835   last_i1 = last_i2 = *i;
2836   last_o1 = last_o2 = 0;
2837   spacePrev = gFalse;
2838   outBuf->clear();
2839 
2840   while (*i < text->getLength()) {
2841     last_i2 = *i;
2842     last_o2 = outBuf->getLength();
2843 
2844     if (unicode) {
2845       uChar = (unsigned char)(text->getChar(*i)) << 8;
2846       uChar += (unsigned char)(text->getChar(*i + 1));
2847       *i += 2;
2848     } else {
2849       if (noReencode)
2850         uChar = text->getChar(*i) & 0xff;
2851       else
2852         uChar = pdfDocEncoding[text->getChar(*i) & 0xff];
2853       *i += 1;
2854     }
2855 
2856     // Explicit line break?
2857     if (uChar == '\r' || uChar == '\n') {
2858       // Treat a <CR><LF> sequence as a single line break
2859       if (uChar == '\r' && *i < text->getLength()) {
2860         if (unicode && text->getChar(*i) == '\0'
2861             && text->getChar(*i + 1) == '\n')
2862           *i += 2;
2863         else if (!unicode && text->getChar(*i) == '\n')
2864           *i += 1;
2865       }
2866 
2867       break;
2868     }
2869 
2870     if (noReencode) {
2871       outBuf->append(uChar);
2872     } else {
2873       CharCodeToUnicode *ccToUnicode = font->getToUnicode();
2874       if (!ccToUnicode) {
2875         // This assumes an identity CMap.
2876         outBuf->append((uChar >> 8) & 0xff);
2877         outBuf->append(uChar & 0xff);
2878       } else if (ccToUnicode->mapToCharCode(&uChar, &c, 1)) {
2879         ccToUnicode->decRefCnt();
2880         if (font->isCIDFont()) {
2881           // TODO: This assumes an identity CMap.  It should be extended to
2882           // handle the general case.
2883           outBuf->append((c >> 8) & 0xff);
2884           outBuf->append(c & 0xff);
2885         } else {
2886           // 8-bit font
2887           outBuf->append(c);
2888         }
2889       } else {
2890         ccToUnicode->decRefCnt();
2891         fprintf(stderr,
2892                 "warning: layoutText: cannot convert U+%04X\n", uChar);
2893       }
2894     }
2895 
2896     // If we see a space, then we have a linebreak opportunity.
2897     if (uChar == ' ') {
2898       last_i1 = *i;
2899       if (!spacePrev)
2900         last_o1 = last_o2;
2901       spacePrev = gTrue;
2902     } else {
2903       spacePrev = gFalse;
2904     }
2905 
2906     // Compute width of character just output
2907     if (outBuf->getLength() > last_o2) {
2908       dx = 0.0;
2909       font->getNextChar(outBuf->getCString() + last_o2,
2910                         outBuf->getLength() - last_o2,
2911                         &c, &uAux, &uLen, &dx, &dy, &ox, &oy);
2912       w += dx;
2913     }
2914 
2915     // Current line over-full now?
2916     if (widthLimit > 0.0 && w > widthLimit) {
2917       if (last_o1 > 0) {
2918         // Back up to the previous word which fit, if there was a previous
2919         // word.
2920         *i = last_i1;
2921         outBuf->del(last_o1, outBuf->getLength() - last_o1);
2922       } else if (last_o2 > 0) {
2923         // Otherwise, back up to the previous character (in the only word on
2924         // this line)
2925         *i = last_i2;
2926         outBuf->del(last_o2, outBuf->getLength() - last_o2);
2927       } else {
2928         // Otherwise, we were trying to fit the first character; include it
2929         // anyway even if it overflows the space--no updates to make.
2930       }
2931       break;
2932     }
2933   }
2934 
2935   // If splitting input into lines because we reached the width limit, then
2936   // consume any remaining trailing spaces that would go on this line from the
2937   // input.  If in doing so we reach a newline, consume that also.  This code
2938   // won't run if we stopped at a newline above, since in that case w <=
2939   // widthLimit still.
2940   if (widthLimit > 0.0 && w > widthLimit) {
2941     if (unicode) {
2942       while (*i < text->getLength()
2943              && text->getChar(*i) == '\0' && text->getChar(*i + 1) == ' ')
2944         *i += 2;
2945       if (*i < text->getLength()
2946           && text->getChar(*i) == '\0' && text->getChar(*i + 1) == '\r')
2947         *i += 2;
2948       if (*i < text->getLength()
2949           && text->getChar(*i) == '\0' && text->getChar(*i + 1) == '\n')
2950         *i += 2;
2951     } else {
2952       while (*i < text->getLength() && text->getChar(*i) == ' ')
2953         *i += 1;
2954       if (*i < text->getLength() && text->getChar(*i) == '\r')
2955         *i += 1;
2956       if (*i < text->getLength() && text->getChar(*i) == '\n')
2957         *i += 1;
2958     }
2959   }
2960 
2961   // Compute the actual width and character count of the final string, based on
2962   // breakpoint, if this information is requested by the caller.
2963   if (width != NULL || charCount != NULL) {
2964     char *s = outBuf->getCString();
2965     int len = outBuf->getLength();
2966 
2967     if (width != NULL)
2968       *width = 0.0;
2969     if (charCount != NULL)
2970       *charCount = 0;
2971 
2972     while (len > 0) {
2973       dx = 0.0;
2974       n = font->getNextChar(s, len, &c, &uAux, &uLen, &dx, &dy, &ox, &oy);
2975 
2976       if (n == 0) {
2977         break;
2978       }
2979 
2980       if (width != NULL)
2981         *width += dx;
2982       if (charCount != NULL)
2983         *charCount += 1;
2984 
2985       s += n;
2986       len -= n;
2987     }
2988   }
2989 }
2990 
2991 // Copy the given string to appearBuf, adding parentheses around it and
2992 // escaping characters as appropriate.
writeString(GooString * str,GooString * appearBuf)2993 void AnnotWidget::writeString(GooString *str, GooString *appearBuf)
2994 {
2995   char c;
2996   int i;
2997 
2998   appearBuf->append('(');
2999 
3000   for (i = 0; i < str->getLength(); ++i) {
3001     c = str->getChar(i);
3002     if (c == '(' || c == ')' || c == '\\') {
3003       appearBuf->append('\\');
3004       appearBuf->append(c);
3005     } else if (c < 0x20) {
3006       appearBuf->appendf("\\{0:03o}", (unsigned char)c);
3007     } else {
3008       appearBuf->append(c);
3009     }
3010   }
3011 
3012   appearBuf->append(')');
3013 }
3014 
3015 // Draw the variable text or caption for a field.
drawText(GooString * text,GooString * da,GfxFontDict * fontDict,GBool multiline,int comb,int quadding,GBool txField,GBool forceZapfDingbats,GBool password)3016 void AnnotWidget::drawText(GooString *text, GooString *da, GfxFontDict *fontDict,
3017     GBool multiline, int comb, int quadding,
3018     GBool txField, GBool forceZapfDingbats,
3019     GBool password) {
3020   GooList *daToks;
3021   GooString *tok, *convertedText;
3022   GfxFont *font;
3023   double fontSize, fontSize2, borderWidth, x, xPrev, y, w, wMax;
3024   int tfPos, tmPos, i, j;
3025   GBool freeText = gFalse;      // true if text should be freed before return
3026   GBool freeFont = gFalse;
3027 
3028   //~ if there is no MK entry, this should use the existing content stream,
3029   //~ and only replace the marked content portion of it
3030   //~ (this is only relevant for Tx fields)
3031 
3032   // parse the default appearance string
3033   tfPos = tmPos = -1;
3034   if (da) {
3035     daToks = new GooList();
3036     i = 0;
3037     while (i < da->getLength()) {
3038       while (i < da->getLength() && Lexer::isSpace(da->getChar(i))) {
3039         ++i;
3040       }
3041       if (i < da->getLength()) {
3042         for (j = i + 1;
3043             j < da->getLength() && !Lexer::isSpace(da->getChar(j));
3044             ++j) ;
3045         daToks->append(new GooString(da, i, j - i));
3046         i = j;
3047       }
3048     }
3049     for (i = 2; i < daToks->getLength(); ++i) {
3050       if (i >= 2 && !((GooString *)daToks->get(i))->cmp("Tf")) {
3051         tfPos = i - 2;
3052       } else if (i >= 6 && !((GooString *)daToks->get(i))->cmp("Tm")) {
3053         tmPos = i - 6;
3054       }
3055     }
3056   } else {
3057     daToks = NULL;
3058   }
3059 
3060   // force ZapfDingbats
3061   if (forceZapfDingbats) {
3062     if (tfPos >= 0) {
3063       tok = (GooString *)daToks->get(tfPos);
3064       if (tok->cmp("/ZaDb")) {
3065         tok->clear();
3066         tok->append("/ZaDb");
3067       }
3068     }
3069   }
3070   // get the font and font size
3071   font = NULL;
3072   fontSize = 0;
3073   if (tfPos >= 0) {
3074     tok = (GooString *)daToks->get(tfPos);
3075     if (tok->getLength() >= 1 && tok->getChar(0) == '/') {
3076       if (!fontDict || !(font = fontDict->lookup(tok->getCString() + 1))) {
3077         if (forceZapfDingbats) {
3078           // We are forcing ZaDb but the font does not exist
3079           // so create a fake one
3080           Ref r; // dummy Ref, it's not used at all in this codepath
3081           r.num = 0;
3082           r.gen = 0;
3083           Dict *d = new Dict(xref);
3084           font = new Gfx8BitFont(xref, "ZaDb", r, new GooString("ZapfDingbats"), fontType1, d);
3085           delete d;
3086           freeFont = gTrue;
3087           addDingbatsResource = gTrue;
3088         } else {
3089           error(-1, "Unknown font in field's DA string");
3090         }
3091       }
3092     } else {
3093       error(-1, "Invalid font name in 'Tf' operator in field's DA string");
3094     }
3095     tok = (GooString *)daToks->get(tfPos + 1);
3096     fontSize = gatof(tok->getCString());
3097   } else {
3098     error(-1, "Missing 'Tf' operator in field's DA string");
3099   }
3100   if (!font) {
3101     if (daToks) {
3102       deleteGooList(daToks, GooString);
3103     }
3104     return;
3105   }
3106 
3107   // get the border width
3108   borderWidth = border ? border->getWidth() : 0;
3109 
3110   // for a password field, replace all characters with asterisks
3111   if (password) {
3112     int len;
3113     if (text->hasUnicodeMarker())
3114       len = (text->getLength() - 2) / 2;
3115     else
3116       len = text->getLength();
3117 
3118     text = new GooString;
3119     for (i = 0; i < len; ++i)
3120       text->append('*');
3121     freeText = gTrue;
3122   }
3123 
3124   convertedText = new GooString;
3125 
3126   // setup
3127   if (txField) {
3128     appearBuf->append("/Tx BMC\n");
3129   }
3130   appearBuf->append("q\n");
3131   appearBuf->append("BT\n");
3132   // multi-line text
3133   if (multiline) {
3134     // note: the comb flag is ignored in multiline mode
3135 
3136     wMax = rect->x2 - rect->x1 - 2 * borderWidth - 4;
3137 
3138     // compute font autosize
3139     if (fontSize == 0) {
3140       for (fontSize = 20; fontSize > 1; --fontSize) {
3141         y = rect->y2 - rect->y1;
3142         i = 0;
3143         while (i < text->getLength()) {
3144           layoutText(text, convertedText, &i, font, &w, wMax / fontSize, NULL,
3145                      forceZapfDingbats);
3146           y -= fontSize;
3147         }
3148         // approximate the descender for the last line
3149         if (y >= 0.33 * fontSize) {
3150           break;
3151         }
3152       }
3153       if (tfPos >= 0) {
3154         tok = (GooString *)daToks->get(tfPos + 1);
3155         tok->clear();
3156         tok->appendf("{0:.2f}", fontSize);
3157       }
3158     }
3159 
3160     // starting y coordinate
3161     // (note: each line of text starts with a Td operator that moves
3162     // down a line)
3163     y = rect->y2 - rect->y1;
3164 
3165     // set the font matrix
3166     if (tmPos >= 0) {
3167       tok = (GooString *)daToks->get(tmPos + 4);
3168       tok->clear();
3169       tok->append('0');
3170       tok = (GooString *)daToks->get(tmPos + 5);
3171       tok->clear();
3172       tok->appendf("{0:.2f}", y);
3173     }
3174 
3175     // write the DA string
3176     if (daToks) {
3177       for (i = 0; i < daToks->getLength(); ++i) {
3178         appearBuf->append((GooString *)daToks->get(i))->append(' ');
3179       }
3180     }
3181 
3182     // write the font matrix (if not part of the DA string)
3183     if (tmPos < 0) {
3184       appearBuf->appendf("1 0 0 1 0 {0:.2f} Tm\n", y);
3185     }
3186 
3187     // write a series of lines of text
3188     i = 0;
3189     xPrev = 0;
3190     while (i < text->getLength()) {
3191       layoutText(text, convertedText, &i, font, &w, wMax / fontSize, NULL,
3192                  forceZapfDingbats);
3193       w *= fontSize;
3194 
3195       // compute text start position
3196       switch (quadding) {
3197         case fieldQuadLeft:
3198         default:
3199           x = borderWidth + 2;
3200           break;
3201         case fieldQuadCenter:
3202           x = (rect->x2 - rect->x1 - w) / 2;
3203           break;
3204         case fieldQuadRight:
3205           x = rect->x2 - rect->x1 - borderWidth - 2 - w;
3206           break;
3207       }
3208 
3209       // draw the line
3210       appearBuf->appendf("{0:.2f} {1:.2f} Td\n", x - xPrev, -fontSize);
3211       writeString(convertedText, appearBuf);
3212       appearBuf->append(" Tj\n");
3213 
3214       // next line
3215       xPrev = x;
3216     }
3217 
3218     // single-line text
3219   } else {
3220     //~ replace newlines with spaces? - what does Acrobat do?
3221 
3222     // comb formatting
3223     if (comb > 0) {
3224       int charCount;
3225 
3226       // compute comb spacing
3227       w = (rect->x2 - rect->x1 - 2 * borderWidth) / comb;
3228 
3229       // compute font autosize
3230       if (fontSize == 0) {
3231         fontSize = rect->y2 - rect->y1 - 2 * borderWidth;
3232         if (w < fontSize) {
3233           fontSize = w;
3234         }
3235         fontSize = floor(fontSize);
3236         if (tfPos >= 0) {
3237           tok = (GooString *)daToks->get(tfPos + 1);
3238           tok->clear();
3239           tok->appendf("{0:.2f}", fontSize);
3240         }
3241       }
3242 
3243       i = 0;
3244       layoutText(text, convertedText, &i, font, NULL, 0.0, &charCount,
3245                  forceZapfDingbats);
3246       if (charCount > comb)
3247         charCount = comb;
3248 
3249       // compute starting text cell
3250       switch (quadding) {
3251         case fieldQuadLeft:
3252         default:
3253           x = borderWidth;
3254           break;
3255         case fieldQuadCenter:
3256           x = borderWidth + (comb - charCount) / 2 * w;
3257           break;
3258         case fieldQuadRight:
3259           x = borderWidth + (comb - charCount) * w;
3260           break;
3261       }
3262       y = 0.5 * (rect->y2 - rect->y1) - 0.4 * fontSize;
3263 
3264       // set the font matrix
3265       if (tmPos >= 0) {
3266         tok = (GooString *)daToks->get(tmPos + 4);
3267         tok->clear();
3268         tok->appendf("{0:.2f}", x);
3269         tok = (GooString *)daToks->get(tmPos + 5);
3270         tok->clear();
3271         tok->appendf("{0:.2f}", y);
3272       }
3273 
3274       // write the DA string
3275       if (daToks) {
3276         for (i = 0; i < daToks->getLength(); ++i) {
3277           appearBuf->append((GooString *)daToks->get(i))->append(' ');
3278         }
3279       }
3280 
3281       // write the font matrix (if not part of the DA string)
3282       if (tmPos < 0) {
3283         appearBuf->appendf("1 0 0 1 {0:.2f} {1:.2f} Tm\n", x, y);
3284       }
3285 
3286       // write the text string
3287       char *s = convertedText->getCString();
3288       int len = convertedText->getLength();
3289       i = 0;
3290       xPrev = w;                // so that first character is placed properly
3291       while (i < comb && len > 0) {
3292         CharCode code;
3293         Unicode *uAux;
3294         int uLen, n;
3295         double dx, dy, ox, oy;
3296 
3297         dx = 0.0;
3298         n = font->getNextChar(s, len, &code, &uAux, &uLen, &dx, &dy, &ox, &oy);
3299         dx *= fontSize;
3300 
3301         // center each character within its cell, by advancing the text
3302         // position the appropriate amount relative to the start of the
3303         // previous character
3304         x = 0.5 * (w - dx);
3305         appearBuf->appendf("{0:.2f} 0 Td\n", x - xPrev + w);
3306 
3307         GooString *charBuf = new GooString(s, n);
3308         writeString(charBuf, appearBuf);
3309         appearBuf->append(" Tj\n");
3310         delete charBuf;
3311 
3312         i++;
3313         s += n;
3314         len -= n;
3315         xPrev = x;
3316       }
3317 
3318       // regular (non-comb) formatting
3319     } else {
3320       i = 0;
3321       layoutText(text, convertedText, &i, font, &w, 0.0, NULL,
3322                  forceZapfDingbats);
3323 
3324       // compute font autosize
3325       if (fontSize == 0) {
3326         fontSize = rect->y2 - rect->y1 - 2 * borderWidth;
3327         fontSize2 = (rect->x2 - rect->x1 - 4 - 2 * borderWidth) / w;
3328         if (fontSize2 < fontSize) {
3329           fontSize = fontSize2;
3330         }
3331         fontSize = floor(fontSize);
3332         if (tfPos >= 0) {
3333           tok = (GooString *)daToks->get(tfPos + 1);
3334           tok->clear();
3335           tok->appendf("{0:.2f}", fontSize);
3336         }
3337       }
3338 
3339       // compute text start position
3340       w *= fontSize;
3341       switch (quadding) {
3342         case fieldQuadLeft:
3343         default:
3344           x = borderWidth + 2;
3345           break;
3346         case fieldQuadCenter:
3347           x = (rect->x2 - rect->x1 - w) / 2;
3348           break;
3349         case fieldQuadRight:
3350           x = rect->x2 - rect->x1 - borderWidth - 2 - w;
3351           break;
3352       }
3353       y = 0.5 * (rect->y2 - rect->y1) - 0.4 * fontSize;
3354 
3355       // set the font matrix
3356       if (tmPos >= 0) {
3357         tok = (GooString *)daToks->get(tmPos + 4);
3358         tok->clear();
3359         tok->appendf("{0:.2f}", x);
3360         tok = (GooString *)daToks->get(tmPos + 5);
3361         tok->clear();
3362         tok->appendf("{0:.2f}", y);
3363       }
3364 
3365       // write the DA string
3366       if (daToks) {
3367         for (i = 0; i < daToks->getLength(); ++i) {
3368           appearBuf->append((GooString *)daToks->get(i))->append(' ');
3369         }
3370       }
3371 
3372       // write the font matrix (if not part of the DA string)
3373       if (tmPos < 0) {
3374         appearBuf->appendf("1 0 0 1 {0:.2f} {1:.2f} Tm\n", x, y);
3375       }
3376 
3377       // write the text string
3378       writeString(convertedText, appearBuf);
3379       appearBuf->append(" Tj\n");
3380     }
3381   }
3382   // cleanup
3383   appearBuf->append("ET\n");
3384   appearBuf->append("Q\n");
3385   if (txField) {
3386     appearBuf->append("EMC\n");
3387   }
3388   if (daToks) {
3389     deleteGooList(daToks, GooString);
3390   }
3391   if (freeText) {
3392     delete text;
3393   }
3394   delete convertedText;
3395   if (freeFont) {
3396     font->decRefCnt();
3397   }
3398 }
3399 
3400 // Draw the variable text or caption for a field.
drawListBox(GooString ** text,GBool * selection,int nOptions,int topIdx,GooString * da,GfxFontDict * fontDict,int quadding)3401 void AnnotWidget::drawListBox(GooString **text, GBool *selection,
3402 			      int nOptions, int topIdx,
3403 			      GooString *da, GfxFontDict *fontDict, int quadding) {
3404   GooList *daToks;
3405   GooString *tok, *convertedText;
3406   GfxFont *font;
3407   double fontSize, fontSize2, borderWidth, x, y, w, wMax;
3408   int tfPos, tmPos, i, j;
3409 
3410   //~ if there is no MK entry, this should use the existing content stream,
3411   //~ and only replace the marked content portion of it
3412   //~ (this is only relevant for Tx fields)
3413 
3414   // parse the default appearance string
3415   tfPos = tmPos = -1;
3416   if (da) {
3417     daToks = new GooList();
3418     i = 0;
3419     while (i < da->getLength()) {
3420       while (i < da->getLength() && Lexer::isSpace(da->getChar(i))) {
3421 	++i;
3422        }
3423       if (i < da->getLength()) {
3424 	for (j = i + 1;
3425 	     j < da->getLength() && !Lexer::isSpace(da->getChar(j));
3426 	     ++j) ;
3427 	daToks->append(new GooString(da, i, j - i));
3428 	i = j;
3429       }
3430     }
3431     for (i = 2; i < daToks->getLength(); ++i) {
3432       if (i >= 2 && !((GooString *)daToks->get(i))->cmp("Tf")) {
3433 	tfPos = i - 2;
3434       } else if (i >= 6 && !((GooString *)daToks->get(i))->cmp("Tm")) {
3435 	tmPos = i - 6;
3436       }
3437     }
3438   } else {
3439     daToks = NULL;
3440   }
3441 
3442   // get the font and font size
3443   font = NULL;
3444   fontSize = 0;
3445   if (tfPos >= 0) {
3446     tok = (GooString *)daToks->get(tfPos);
3447     if (tok->getLength() >= 1 && tok->getChar(0) == '/') {
3448       if (!fontDict || !(font = fontDict->lookup(tok->getCString() + 1))) {
3449         error(-1, "Unknown font in field's DA string");
3450       }
3451     } else {
3452       error(-1, "Invalid font name in 'Tf' operator in field's DA string");
3453     }
3454     tok = (GooString *)daToks->get(tfPos + 1);
3455     fontSize = gatof(tok->getCString());
3456   } else {
3457     error(-1, "Missing 'Tf' operator in field's DA string");
3458   }
3459   if (!font) {
3460     if (daToks) {
3461       deleteGooList(daToks, GooString);
3462     }
3463     return;
3464   }
3465 
3466   convertedText = new GooString;
3467 
3468   // get the border width
3469   borderWidth = border ? border->getWidth() : 0;
3470 
3471   // compute font autosize
3472   if (fontSize == 0) {
3473     wMax = 0;
3474     for (i = 0; i < nOptions; ++i) {
3475       j = 0;
3476       layoutText(text[i], convertedText, &j, font, &w, 0.0, NULL, gFalse);
3477       if (w > wMax) {
3478         wMax = w;
3479       }
3480     }
3481     fontSize = rect->y2 - rect->y1 - 2 * borderWidth;
3482     fontSize2 = (rect->x2 - rect->x1 - 4 - 2 * borderWidth) / wMax;
3483     if (fontSize2 < fontSize) {
3484       fontSize = fontSize2;
3485     }
3486     fontSize = floor(fontSize);
3487     if (tfPos >= 0) {
3488       tok = (GooString *)daToks->get(tfPos + 1);
3489       tok->clear();
3490       tok->appendf("{0:.2f}", fontSize);
3491     }
3492   }
3493   // draw the text
3494   y = rect->y2 - rect->y1 - 1.1 * fontSize;
3495   for (i = topIdx; i < nOptions; ++i) {
3496     // setup
3497     appearBuf->append("q\n");
3498 
3499     // draw the background if selected
3500     if (selection[i]) {
3501       appearBuf->append("0 g f\n");
3502       appearBuf->appendf("{0:.2f} {1:.2f} {2:.2f} {3:.2f} re f\n",
3503           borderWidth,
3504           y - 0.2 * fontSize,
3505           rect->x2 - rect->x1 - 2 * borderWidth,
3506           1.1 * fontSize);
3507     }
3508 
3509     // setup
3510     appearBuf->append("BT\n");
3511 
3512     // compute text width and start position
3513     j = 0;
3514     layoutText(text[i], convertedText, &j, font, &w, 0.0, NULL, gFalse);
3515     w *= fontSize;
3516     switch (quadding) {
3517       case fieldQuadLeft:
3518       default:
3519         x = borderWidth + 2;
3520         break;
3521       case fieldQuadCenter:
3522         x = (rect->x2 - rect->x1 - w) / 2;
3523         break;
3524       case fieldQuadRight:
3525         x = rect->x2 - rect->x1 - borderWidth - 2 - w;
3526         break;
3527     }
3528 
3529     // set the font matrix
3530     if (tmPos >= 0) {
3531       tok = (GooString *)daToks->get(tmPos + 4);
3532       tok->clear();
3533       tok->appendf("{0:.2f}", x);
3534       tok = (GooString *)daToks->get(tmPos + 5);
3535       tok->clear();
3536       tok->appendf("{0:.2f}", y);
3537     }
3538 
3539     // write the DA string
3540     if (daToks) {
3541       for (j = 0; j < daToks->getLength(); ++j) {
3542         appearBuf->append((GooString *)daToks->get(j))->append(' ');
3543       }
3544     }
3545 
3546     // write the font matrix (if not part of the DA string)
3547     if (tmPos < 0) {
3548       appearBuf->appendf("1 0 0 1 {0:.2f} {1:.2f} Tm\n", x, y);
3549     }
3550 
3551     // change the text color if selected
3552     if (selection[i]) {
3553       appearBuf->append("1 g\n");
3554     }
3555 
3556     // write the text string
3557     writeString(convertedText, appearBuf);
3558     appearBuf->append(" Tj\n");
3559 
3560     // cleanup
3561     appearBuf->append("ET\n");
3562     appearBuf->append("Q\n");
3563 
3564     // next line
3565     y -= 1.1 * fontSize;
3566   }
3567 
3568   if (daToks) {
3569     deleteGooList(daToks, GooString);
3570   }
3571 
3572   delete convertedText;
3573 }
3574 
generateFieldAppearance()3575 void AnnotWidget::generateFieldAppearance() {
3576   Object mkObj, ftObj, appearDict, drObj, obj1, obj2, obj3;
3577   Dict *field;
3578   Dict *annot;
3579   Dict *acroForm;
3580   Dict *mkDict;
3581   MemStream *appearStream;
3582   GfxFontDict *fontDict;
3583   GBool hasCaption;
3584   double w, dx, dy, r;
3585   double *dash;
3586   GooString *caption, *da;
3587   GooString **text;
3588   GBool *selection;
3589   int dashLength, ff, quadding, comb, nOptions, topIdx, i, j;
3590   GBool modified;
3591   AnnotColor aColor;
3592 
3593   if (widget == NULL || !widget->getField () || !widget->getField ()->getObj ()->isDict ())
3594     return;
3595 
3596   field = widget->getField ()->getObj ()->getDict ();
3597   annot = widget->getObj ()->getDict ();
3598   acroForm = form->getObj ()->getDict ();
3599 
3600   // do not regenerate appearence if widget has not changed
3601   modified = widget->isModified ();
3602 
3603   // only regenerate when it doesn't have an AP or
3604   // it already has an AP but widget has been modified
3605   if (!regen && !modified) {
3606     return;
3607   }
3608 
3609   appearBuf = new GooString ();
3610   // get the appearance characteristics (MK) dictionary
3611   if (annot->lookup("MK", &mkObj)->isDict()) {
3612     mkDict = mkObj.getDict();
3613   } else {
3614     mkDict = NULL;
3615   }
3616   // draw the background
3617   if (mkDict) {
3618     if (mkDict->lookup("BG", &obj1)->isArray() &&
3619         obj1.arrayGetLength() > 0) {
3620       AnnotColor aColor = AnnotColor (obj1.getArray());
3621       setColor(&aColor, gTrue);
3622       appearBuf->appendf("0 0 {0:.2f} {1:.2f} re f\n",
3623           rect->x2 - rect->x1, rect->y2 - rect->y1);
3624     }
3625     obj1.free();
3626   }
3627 
3628   // get the field type
3629   Form::fieldLookup(field, "FT", &ftObj);
3630 
3631   // get the field flags (Ff) value
3632   if (Form::fieldLookup(field, "Ff", &obj1)->isInt()) {
3633     ff = obj1.getInt();
3634   } else {
3635     ff = 0;
3636   }
3637   obj1.free();
3638 
3639   // draw the border
3640   if (mkDict && border) {
3641     w = border->getWidth();
3642     if (w > 0) {
3643       mkDict->lookup("BC", &obj1);
3644       if (!(obj1.isArray() && obj1.arrayGetLength() > 0)) {
3645         mkDict->lookup("BG", &obj1);
3646       }
3647       if (obj1.isArray() && obj1.arrayGetLength() > 0) {
3648         dx = rect->x2 - rect->x1;
3649         dy = rect->y2 - rect->y1;
3650 
3651         // radio buttons with no caption have a round border
3652         hasCaption = mkDict->lookup("CA", &obj2)->isString();
3653         obj2.free();
3654         if (ftObj.isName("Btn") && (ff & fieldFlagRadio) && !hasCaption) {
3655           r = 0.5 * (dx < dy ? dx : dy);
3656           switch (border->getStyle()) {
3657             case AnnotBorder::borderDashed:
3658               appearBuf->append("[");
3659               dashLength = border->getDashLength();
3660               dash = border->getDash();
3661               for (i = 0; i < dashLength; ++i) {
3662                 appearBuf->appendf(" {0:.2f}", dash[i]);
3663               }
3664               appearBuf->append("] 0 d\n");
3665               // fall through to the solid case
3666             case AnnotBorder::borderSolid:
3667             case AnnotBorder::borderUnderlined:
3668               appearBuf->appendf("{0:.2f} w\n", w);
3669 	      aColor = AnnotColor (obj1.getArray());
3670               setColor(&aColor, gFalse);
3671               drawCircle(0.5 * dx, 0.5 * dy, r - 0.5 * w, gFalse);
3672               break;
3673             case AnnotBorder::borderBeveled:
3674             case AnnotBorder::borderInset:
3675               appearBuf->appendf("{0:.2f} w\n", 0.5 * w);
3676 	      aColor = AnnotColor (obj1.getArray());
3677               setColor(&aColor, gFalse);
3678               drawCircle(0.5 * dx, 0.5 * dy, r - 0.25 * w, gFalse);
3679 	      aColor = AnnotColor (obj1.getArray(),
3680 				   border->getStyle() == AnnotBorder::borderBeveled ? 1 : -1);
3681               setColor(&aColor, gFalse);
3682               drawCircleTopLeft(0.5 * dx, 0.5 * dy, r - 0.75 * w);
3683 	      aColor = AnnotColor (obj1.getArray(),
3684 				   border->getStyle() == AnnotBorder::borderBeveled ? -1 : 1);
3685               setColor(&aColor, gFalse);
3686               drawCircleBottomRight(0.5 * dx, 0.5 * dy, r - 0.75 * w);
3687               break;
3688           }
3689 
3690         } else {
3691           switch (border->getStyle()) {
3692             case AnnotBorder::borderDashed:
3693               appearBuf->append("[");
3694               dashLength = border->getDashLength();
3695               dash = border->getDash();
3696               for (i = 0; i < dashLength; ++i) {
3697                 appearBuf->appendf(" {0:.2f}", dash[i]);
3698               }
3699               appearBuf->append("] 0 d\n");
3700               // fall through to the solid case
3701             case AnnotBorder::borderSolid:
3702               appearBuf->appendf("{0:.2f} w\n", w);
3703 	      aColor = AnnotColor (obj1.getArray());
3704               setColor(&aColor, gFalse);
3705               appearBuf->appendf("{0:.2f} {0:.2f} {1:.2f} {2:.2f} re s\n",
3706                   0.5 * w, dx - w, dy - w);
3707               break;
3708             case AnnotBorder::borderBeveled:
3709             case AnnotBorder::borderInset:
3710 	      aColor = AnnotColor (obj1.getArray(),
3711 				   border->getStyle() == AnnotBorder::borderBeveled ? 1 : -1);
3712 	      setColor(&aColor, gTrue);
3713               appearBuf->append("0 0 m\n");
3714               appearBuf->appendf("0 {0:.2f} l\n", dy);
3715               appearBuf->appendf("{0:.2f} {1:.2f} l\n", dx, dy);
3716               appearBuf->appendf("{0:.2f} {1:.2f} l\n", dx - w, dy - w);
3717               appearBuf->appendf("{0:.2f} {1:.2f} l\n", w, dy - w);
3718               appearBuf->appendf("{0:.2f} {0:.2f} l\n", w);
3719               appearBuf->append("f\n");
3720 	      aColor = AnnotColor (obj1.getArray(),
3721 				   border->getStyle() == AnnotBorder::borderBeveled ? -1 : 1);
3722               setColor(&aColor, gTrue);
3723               appearBuf->append("0 0 m\n");
3724               appearBuf->appendf("{0:.2f} 0 l\n", dx);
3725               appearBuf->appendf("{0:.2f} {1:.2f} l\n", dx, dy);
3726               appearBuf->appendf("{0:.2f} {1:.2f} l\n", dx - w, dy - w);
3727               appearBuf->appendf("{0:.2f} {1:.2f} l\n", dx - w, w);
3728               appearBuf->appendf("{0:.2f} {0:.2f} l\n", w);
3729               appearBuf->append("f\n");
3730               break;
3731             case AnnotBorder::borderUnderlined:
3732               appearBuf->appendf("{0:.2f} w\n", w);
3733 	      aColor = AnnotColor (obj1.getArray());
3734               setColor(&aColor, gFalse);
3735               appearBuf->appendf("0 0 m {0:.2f} 0 l s\n", dx);
3736               break;
3737           }
3738 
3739           // clip to the inside of the border
3740           appearBuf->appendf("{0:.2f} {0:.2f} {1:.2f} {2:.2f} re W n\n",
3741               w, dx - 2 * w, dy - 2 * w);
3742         }
3743       }
3744       obj1.free();
3745     }
3746   }
3747 
3748   // get the resource dictionary
3749   acroForm->lookup("DR", &drObj);
3750 
3751   // build the font dictionary
3752   if (drObj.isDict() && drObj.dictLookup("Font", &obj1)->isDict()) {
3753     fontDict = new GfxFontDict(xref, NULL, obj1.getDict());
3754   } else {
3755     fontDict = NULL;
3756   }
3757   obj1.free();
3758 
3759   // get the default appearance string
3760   if (Form::fieldLookup(field, "DA", &obj1)->isNull()) {
3761     obj1.free();
3762     acroForm->lookup("DA", &obj1);
3763   }
3764   if (obj1.isString()) {
3765     da = obj1.getString()->copy();
3766     //TODO: look for a font size / name HERE
3767     // => create a function
3768   } else {
3769     da = NULL;
3770   }
3771   obj1.free();
3772 
3773   // draw the field contents
3774   if (ftObj.isName("Btn")) {
3775     caption = NULL;
3776     if (mkDict) {
3777       if (mkDict->lookup("CA", &obj1)->isString()) {
3778         caption = obj1.getString()->copy();
3779       }
3780       obj1.free();
3781     }
3782     // radio button
3783     if (ff & fieldFlagRadio) {
3784       //~ Acrobat doesn't draw a caption if there is no AP dict (?)
3785       if (Form::fieldLookup(field, "V", &obj1)->isName()) {
3786         if (annot->lookup("AS", &obj2)->isName(obj1.getName()) &&
3787 	    strcmp (obj1.getName(), "Off") != 0) {
3788           if (caption) {
3789             drawText(caption, da, fontDict, gFalse, 0, fieldQuadCenter,
3790                 gFalse, gTrue);
3791           } else {
3792             if (mkDict) {
3793               if (mkDict->lookup("BC", &obj3)->isArray() &&
3794                   obj3.arrayGetLength() > 0) {
3795                 dx = rect->x2 - rect->x1;
3796                 dy = rect->y2 - rect->y1;
3797 		aColor = AnnotColor (obj3.getArray());
3798                 setColor(&aColor, gTrue);
3799                 drawCircle(0.5 * dx, 0.5 * dy, 0.2 * (dx < dy ? dx : dy),
3800                     gTrue);
3801               }
3802               obj3.free();
3803             }
3804           }
3805         }
3806         obj2.free();
3807       }
3808       obj1.free();
3809       // pushbutton
3810     } else if (ff & fieldFlagPushbutton) {
3811       if (caption) {
3812         drawText(caption, da, fontDict, gFalse, 0, fieldQuadCenter,
3813             gFalse, gFalse);
3814       }
3815       // checkbox
3816     } else {
3817       if (annot->lookup("AS", &obj1)->isName() &&
3818           strcmp(obj1.getName(), "Off") != 0) {
3819         if (!caption) {
3820           caption = new GooString("3"); // ZapfDingbats checkmark
3821         }
3822         drawText(caption, da, fontDict, gFalse, 0, fieldQuadCenter,
3823             gFalse, gTrue);
3824       }
3825       obj1.free();
3826     }
3827     if (caption) {
3828       delete caption;
3829     }
3830   } else if (ftObj.isName("Tx")) {
3831     if (Form::fieldLookup(field, "V", &obj1)->isString()) {
3832       if (Form::fieldLookup(field, "Q", &obj2)->isInt()) {
3833         quadding = obj2.getInt();
3834       } else {
3835         quadding = fieldQuadLeft;
3836       }
3837       obj2.free();
3838       comb = 0;
3839       if (ff & fieldFlagComb) {
3840         if (Form::fieldLookup(field, "MaxLen", &obj2)->isInt()) {
3841           comb = obj2.getInt();
3842         }
3843         obj2.free();
3844       }
3845       drawText(obj1.getString(), da, fontDict,
3846           ff & fieldFlagMultiline, comb, quadding, gTrue, gFalse, ff & fieldFlagPassword);
3847     }
3848     obj1.free();
3849   } else if (ftObj.isName("Ch")) {
3850     if (Form::fieldLookup(field, "Q", &obj1)->isInt()) {
3851       quadding = obj1.getInt();
3852     } else {
3853       quadding = fieldQuadLeft;
3854     }
3855     obj1.free();
3856     // combo box
3857     if (ff & fieldFlagCombo) {
3858       if (Form::fieldLookup(field, "V", &obj1)->isString()) {
3859         drawText(obj1.getString(), da, fontDict,
3860             gFalse, 0, quadding, gTrue, gFalse);
3861         //~ Acrobat draws a popup icon on the right side
3862       }
3863       obj1.free();
3864       // list box
3865     } else {
3866       if (field->lookup("Opt", &obj1)->isArray()) {
3867         nOptions = obj1.arrayGetLength();
3868         // get the option text
3869         text = (GooString **)gmallocn(nOptions, sizeof(GooString *));
3870         for (i = 0; i < nOptions; ++i) {
3871           text[i] = NULL;
3872           obj1.arrayGet(i, &obj2);
3873           if (obj2.isString()) {
3874             text[i] = obj2.getString()->copy();
3875           } else if (obj2.isArray() && obj2.arrayGetLength() == 2) {
3876             if (obj2.arrayGet(1, &obj3)->isString()) {
3877               text[i] = obj3.getString()->copy();
3878             }
3879             obj3.free();
3880           }
3881           obj2.free();
3882           if (!text[i]) {
3883             text[i] = new GooString();
3884           }
3885         }
3886         // get the selected option(s)
3887         selection = (GBool *)gmallocn(nOptions, sizeof(GBool));
3888         //~ need to use the I field in addition to the V field
3889 	Form::fieldLookup(field, "V", &obj2);
3890         for (i = 0; i < nOptions; ++i) {
3891           selection[i] = gFalse;
3892           if (obj2.isString()) {
3893             if (!obj2.getString()->cmp(text[i])) {
3894               selection[i] = gTrue;
3895             }
3896           } else if (obj2.isArray()) {
3897             for (j = 0; j < obj2.arrayGetLength(); ++j) {
3898               if (obj2.arrayGet(j, &obj3)->isString() &&
3899                   !obj3.getString()->cmp(text[i])) {
3900                 selection[i] = gTrue;
3901               }
3902               obj3.free();
3903             }
3904           }
3905         }
3906         obj2.free();
3907         // get the top index
3908         if (field->lookup("TI", &obj2)->isInt()) {
3909           topIdx = obj2.getInt();
3910         } else {
3911           topIdx = 0;
3912         }
3913         obj2.free();
3914         // draw the text
3915         drawListBox(text, selection, nOptions, topIdx, da, fontDict, quadding);
3916         for (i = 0; i < nOptions; ++i) {
3917           delete text[i];
3918         }
3919         gfree(text);
3920         gfree(selection);
3921       }
3922       obj1.free();
3923     }
3924   } else if (ftObj.isName("Sig")) {
3925     //~unimp
3926   } else {
3927     error(-1, "Unknown field type");
3928   }
3929 
3930   if (da) {
3931     delete da;
3932   }
3933 
3934   // build the appearance stream dictionary
3935   appearDict.initDict(xref);
3936   appearDict.dictAdd(copyString("Length"),
3937       obj1.initInt(appearBuf->getLength()));
3938   appearDict.dictAdd(copyString("Subtype"), obj1.initName("Form"));
3939   obj1.initArray(xref);
3940   obj1.arrayAdd(obj2.initReal(0));
3941   obj1.arrayAdd(obj2.initReal(0));
3942   obj1.arrayAdd(obj2.initReal(rect->x2 - rect->x1));
3943   obj1.arrayAdd(obj2.initReal(rect->y2 - rect->y1));
3944   appearDict.dictAdd(copyString("BBox"), &obj1);
3945 
3946   // set the resource dictionary
3947   if (drObj.isDict()) {
3948     appearDict.dictAdd(copyString("Resources"), drObj.copy(&obj1));
3949   }
3950   drObj.free();
3951 
3952   // build the appearance stream
3953   appearStream = new MemStream(strdup(appearBuf->getCString()), 0,
3954       appearBuf->getLength(), &appearDict);
3955   appearance.free();
3956   appearance.initStream(appearStream);
3957   delete appearBuf;
3958 
3959   appearStream->setNeedFree(gTrue);
3960 
3961   if (widget->isModified()) {
3962     //create a new object that will contains the new appearance
3963 
3964     //if we already have a N entry in our AP dict, reuse it
3965     if (annot->lookup("AP", &obj1)->isDict() &&
3966         obj1.dictLookupNF("N", &obj2)->isRef()) {
3967       appRef = obj2.getRef();
3968     }
3969 
3970     obj2.free();
3971     obj1.free();
3972 
3973     // this annot doesn't have an AP yet, create one
3974     if (appRef.num == 0)
3975       appRef = xref->addIndirectObject(&appearance);
3976     else // since we reuse the already existing AP, we have to notify the xref about this update
3977       xref->setModifiedObject(&appearance, appRef);
3978 
3979     // update object's AP and AS
3980     Object apObj;
3981     apObj.initDict(xref);
3982 
3983     Object oaRef;
3984     oaRef.initRef(appRef.num, appRef.gen);
3985 
3986     apObj.dictSet("N", &oaRef);
3987     annot->set("AP", &apObj);
3988     Dict* d = new Dict(annot);
3989     d->decRef();
3990     Object dictObj;
3991     dictObj.initDict(d);
3992 
3993     xref->setModifiedObject(&dictObj, ref);
3994     dictObj.free();
3995   }
3996 
3997   if (fontDict) {
3998     delete fontDict;
3999   }
4000   ftObj.free();
4001   mkObj.free();
4002 }
4003 
4004 
draw(Gfx * gfx,GBool printing)4005 void AnnotWidget::draw(Gfx *gfx, GBool printing) {
4006   Object obj;
4007 
4008   if (!isVisible (printing))
4009     return;
4010 
4011   addDingbatsResource = gFalse;
4012   generateFieldAppearance ();
4013 
4014   // draw the appearance stream
4015   appearance.fetch(xref, &obj);
4016   if (addDingbatsResource) {
4017     // We are forcing ZaDb but the font does not exist
4018     // so create a fake one
4019     Object baseFontObj, subtypeObj;
4020     baseFontObj.initName("ZapfDingbats");
4021     subtypeObj.initName("Type1");
4022 
4023     Object fontDictObj;
4024     Dict *fontDict = new Dict(xref);
4025     fontDict->decRef();
4026     fontDict->add(copyString("BaseFont"), &baseFontObj);
4027     fontDict->add(copyString("Subtype"), &subtypeObj);
4028     fontDictObj.initDict(fontDict);
4029 
4030     Object fontsDictObj;
4031     Dict *fontsDict = new Dict(xref);
4032     fontsDict->decRef();
4033     fontsDict->add(copyString("ZaDb"), &fontDictObj);
4034     fontsDictObj.initDict(fontsDict);
4035 
4036     Dict *dict = new Dict(xref);
4037     dict->add(copyString("Font"), &fontsDictObj);
4038     gfx->pushResources(dict);
4039     delete dict;
4040   }
4041   gfx->drawAnnot(&obj, (AnnotBorder *)NULL, color,
4042 		 rect->x1, rect->y1, rect->x2, rect->y2);
4043   if (addDingbatsResource) {
4044     gfx->popResources();
4045   }
4046   obj.free();
4047 }
4048 
4049 
4050 //------------------------------------------------------------------------
4051 // AnnotMovie
4052 //------------------------------------------------------------------------
AnnotMovie(XRef * xrefA,PDFRectangle * rect,Movie * movieA,Catalog * catalog)4053 AnnotMovie::AnnotMovie(XRef *xrefA, PDFRectangle *rect, Movie *movieA, Catalog *catalog) :
4054     Annot(xrefA, rect, catalog) {
4055   Object obj1;
4056 
4057   type = typeMovie;
4058   annotObj.dictSet ("Subtype", obj1.initName ("Movie"));
4059 
4060   movie = movieA->copy();
4061   // TODO: create movie dict from movieA
4062 
4063   initialize(xrefA, catalog, annotObj.getDict());
4064 }
4065 
AnnotMovie(XRef * xrefA,Dict * dict,Catalog * catalog,Object * obj)4066 AnnotMovie::AnnotMovie(XRef *xrefA, Dict *dict, Catalog *catalog, Object *obj) :
4067   Annot(xrefA, dict, catalog, obj) {
4068   type = typeMovie;
4069   initialize(xrefA, catalog, dict);
4070 }
4071 
~AnnotMovie()4072 AnnotMovie::~AnnotMovie() {
4073   if (title)
4074     delete title;
4075   delete movie;
4076 }
4077 
initialize(XRef * xrefA,Catalog * catalog,Dict * dict)4078 void AnnotMovie::initialize(XRef *xrefA, Catalog *catalog, Dict* dict) {
4079   Object obj1;
4080 
4081   if (dict->lookup("T", &obj1)->isString()) {
4082     title = obj1.getString()->copy();
4083   } else {
4084     title = NULL;
4085   }
4086   obj1.free();
4087 
4088   Object movieDict;
4089   if (dict->lookup("Movie", &movieDict)->isDict()) {
4090     Object obj2;
4091     dict->lookup("A", &obj2);
4092     if (obj2.isDict())
4093       movie = new Movie (&movieDict, &obj2);
4094     else
4095       movie = new Movie (&movieDict);
4096     if (!movie->isOk()) {
4097       delete movie;
4098       movie = NULL;
4099       ok = gFalse;
4100     }
4101     obj2.free();
4102   } else {
4103     error(-1, "Bad Annot Movie");
4104     movie = NULL;
4105     ok = gFalse;
4106   }
4107   movieDict.free();
4108 }
4109 
draw(Gfx * gfx,GBool printing)4110 void AnnotMovie::draw(Gfx *gfx, GBool printing) {
4111   Object obj;
4112 
4113   if (!isVisible (printing))
4114     return;
4115 
4116   if (appearance.isNull() && movie->getShowPoster()) {
4117     int width, height;
4118     Object poster;
4119     movie->getPoster(&poster);
4120     movie->getAspect(&width, &height);
4121 
4122     if (width != -1 && height != -1 && !poster.isNone()) {
4123       MemStream *mStream;
4124 
4125       appearBuf = new GooString ();
4126       appearBuf->append ("q\n");
4127       appearBuf->appendf ("{0:d} 0 0 {1:d} 0 0 cm\n", width, height);
4128       appearBuf->append ("/MImg Do\n");
4129       appearBuf->append ("Q\n");
4130 
4131       Object imgDict;
4132       imgDict.initDict(xref);
4133       imgDict.dictSet ("MImg", &poster);
4134 
4135       Object resDict;
4136       resDict.initDict(xref);
4137       resDict.dictSet ("XObject", &imgDict);
4138 
4139       Object formDict, obj1, obj2;
4140       formDict.initDict(xref);
4141       formDict.dictSet("Length", obj1.initInt(appearBuf->getLength()));
4142       formDict.dictSet("Subtype", obj1.initName("Form"));
4143       formDict.dictSet("Name", obj1.initName("FRM"));
4144       obj1.initArray(xref);
4145       obj1.arrayAdd(obj2.initInt(0));
4146       obj1.arrayAdd(obj2.initInt(0));
4147       obj1.arrayAdd(obj2.initInt(width));
4148       obj1.arrayAdd(obj2.initInt(height));
4149       formDict.dictSet("BBox", &obj1);
4150       obj1.initArray(xref);
4151       obj1.arrayAdd(obj2.initInt(1));
4152       obj1.arrayAdd(obj2.initInt(0));
4153       obj1.arrayAdd(obj2.initInt(0));
4154       obj1.arrayAdd(obj2.initInt(1));
4155       obj1.arrayAdd(obj2.initInt(-width / 2));
4156       obj1.arrayAdd(obj2.initInt(-height / 2));
4157       formDict.dictSet("Matrix", &obj1);
4158       formDict.dictSet("Resources", &resDict);
4159 
4160       Object aStream;
4161       mStream = new MemStream(copyString(appearBuf->getCString()), 0,
4162 			      appearBuf->getLength(), &formDict);
4163       mStream->setNeedFree(gTrue);
4164       aStream.initStream(mStream);
4165       delete appearBuf;
4166 
4167       Object objDict;
4168       objDict.initDict(xref);
4169       objDict.dictSet ("FRM", &aStream);
4170 
4171       resDict.initDict(xref);
4172       resDict.dictSet ("XObject", &objDict);
4173 
4174       appearBuf = new GooString ();
4175       appearBuf->append ("q\n");
4176       appearBuf->appendf ("0 0 {0:d} {1:d} re W n\n", width, height);
4177       appearBuf->append ("q\n");
4178       appearBuf->appendf ("0 0 {0:d} {1:d} re W n\n", width, height);
4179       appearBuf->appendf ("1 0 0 1 {0:d} {1:d} cm\n", width / 2, height / 2);
4180       appearBuf->append ("/FRM Do\n");
4181       appearBuf->append ("Q\n");
4182       appearBuf->append ("Q\n");
4183 
4184       double bbox[4];
4185       bbox[0] = bbox[1] = 0;
4186       bbox[2] = width;
4187       bbox[3] = height;
4188       createForm(bbox, gFalse, &resDict, &appearance);
4189       delete appearBuf;
4190     }
4191     poster.free();
4192   }
4193 
4194   // draw the appearance stream
4195   appearance.fetch(xref, &obj);
4196   gfx->drawAnnot(&obj, (AnnotBorder *)NULL, color,
4197 		 rect->x1, rect->y1, rect->x2, rect->y2);
4198   obj.free();
4199 }
4200 
4201 //------------------------------------------------------------------------
4202 // AnnotScreen
4203 //------------------------------------------------------------------------
AnnotScreen(XRef * xrefA,PDFRectangle * rect,Catalog * catalog)4204 AnnotScreen::AnnotScreen(XRef *xrefA, PDFRectangle *rect, Catalog *catalog) :
4205     Annot(xrefA, rect, catalog) {
4206   Object obj1;
4207 
4208   type = typeScreen;
4209 
4210   annotObj.dictSet ("Subtype", obj1.initName ("Screen"));
4211   initialize(xrefA, catalog, annotObj.getDict());
4212 }
4213 
AnnotScreen(XRef * xrefA,Dict * dict,Catalog * catalog,Object * obj)4214 AnnotScreen::AnnotScreen(XRef *xrefA, Dict *dict, Catalog *catalog, Object *obj) :
4215   Annot(xrefA, dict, catalog, obj) {
4216   type = typeScreen;
4217   initialize(xrefA, catalog, dict);
4218 }
4219 
~AnnotScreen()4220 AnnotScreen::~AnnotScreen() {
4221   if (title)
4222     delete title;
4223   if (appearCharacs)
4224     delete appearCharacs;
4225   if (action)
4226     delete action;
4227 
4228   additionAction.free();
4229 }
4230 
initialize(XRef * xrefA,Catalog * catalog,Dict * dict)4231 void AnnotScreen::initialize(XRef *xrefA, Catalog *catalog, Dict* dict) {
4232   Object obj1;
4233 
4234   title = NULL;
4235   if (dict->lookup("T", &obj1)->isString()) {
4236     title = obj1.getString()->copy();
4237   }
4238   obj1.free();
4239 
4240   action = NULL;
4241   if (dict->lookup("A", &obj1)->isDict()) {
4242     action = LinkAction::parseAction(&obj1, catalog->getBaseURI());
4243     if (action->getKind() == actionRendition && page == 0) {
4244       error (-1, "Invalid Rendition action: associated screen annotation without P");
4245       delete action;
4246       action = NULL;
4247       ok = gFalse;
4248     }
4249   }
4250 
4251   dict->lookup("AA", &additionAction);
4252 
4253   appearCharacs = NULL;
4254   if(dict->lookup("MK", &obj1)->isDict()) {
4255     appearCharacs = new AnnotAppearanceCharacs(obj1.getDict());
4256   }
4257   obj1.free();
4258 
4259 }
4260 
4261 //------------------------------------------------------------------------
4262 // AnnotStamp
4263 //------------------------------------------------------------------------
AnnotStamp(XRef * xrefA,PDFRectangle * rect,Catalog * catalog)4264 AnnotStamp::AnnotStamp(XRef *xrefA, PDFRectangle *rect, Catalog *catalog) :
4265   AnnotMarkup(xrefA, rect, catalog) {
4266   Object obj1;
4267 
4268   type = typeStamp;
4269   annotObj.dictSet ("Subtype", obj1.initName ("Stamp"));
4270   initialize(xrefA, catalog, annotObj.getDict());
4271 }
4272 
AnnotStamp(XRef * xrefA,Dict * dict,Catalog * catalog,Object * obj)4273 AnnotStamp::AnnotStamp(XRef *xrefA, Dict *dict, Catalog *catalog, Object *obj) :
4274   AnnotMarkup(xrefA, dict, catalog, obj) {
4275   type = typeStamp;
4276   initialize(xrefA, catalog, dict);
4277 }
4278 
~AnnotStamp()4279 AnnotStamp::~AnnotStamp() {
4280   delete icon;
4281 }
4282 
initialize(XRef * xrefA,Catalog * catalog,Dict * dict)4283 void AnnotStamp::initialize(XRef *xrefA, Catalog *catalog, Dict* dict) {
4284   Object obj1;
4285 
4286   if (dict->lookup("Name", &obj1)->isName()) {
4287     icon = new GooString(obj1.getName());
4288   } else {
4289     icon = new GooString("Draft");
4290   }
4291   obj1.free();
4292 
4293 }
4294 
4295 //------------------------------------------------------------------------
4296 // AnnotGeometry
4297 //------------------------------------------------------------------------
AnnotGeometry(XRef * xrefA,PDFRectangle * rect,AnnotSubtype subType,Catalog * catalog)4298 AnnotGeometry::AnnotGeometry(XRef *xrefA, PDFRectangle *rect, AnnotSubtype subType, Catalog *catalog) :
4299     AnnotMarkup(xrefA, rect, catalog) {
4300   Object obj1;
4301 
4302   switch (subType) {
4303     case typeSquare:
4304       annotObj.dictSet ("Subtype", obj1.initName ("Square"));
4305       break;
4306     case typeCircle:
4307       annotObj.dictSet ("Subtype", obj1.initName ("Circle"));
4308       break;
4309     default:
4310       assert (0 && "Invalid subtype for AnnotGeometry\n");
4311   }
4312 
4313   initialize(xrefA, catalog, annotObj.getDict());
4314 }
4315 
AnnotGeometry(XRef * xrefA,Dict * dict,Catalog * catalog,Object * obj)4316 AnnotGeometry::AnnotGeometry(XRef *xrefA, Dict *dict, Catalog *catalog, Object *obj) :
4317   AnnotMarkup(xrefA, dict, catalog, obj) {
4318   // the real type will be read in initialize()
4319   type = typeSquare;
4320   initialize(xrefA, catalog, dict);
4321 }
4322 
~AnnotGeometry()4323 AnnotGeometry::~AnnotGeometry() {
4324   delete interiorColor;
4325   delete borderEffect;
4326   delete geometryRect;
4327 }
4328 
initialize(XRef * xrefA,Catalog * catalog,Dict * dict)4329 void AnnotGeometry::initialize(XRef *xrefA, Catalog *catalog, Dict* dict) {
4330   Object obj1;
4331 
4332   if (dict->lookup("Subtype", &obj1)->isName()) {
4333     GooString typeName(obj1.getName());
4334     if (!typeName.cmp("Square")) {
4335       type = typeSquare;
4336     } else if (!typeName.cmp("Circle")) {
4337       type = typeCircle;
4338     }
4339   }
4340   obj1.free();
4341 
4342   if (dict->lookup("IC", &obj1)->isArray()) {
4343     interiorColor = new AnnotColor(obj1.getArray());
4344   } else {
4345     interiorColor = NULL;
4346   }
4347   obj1.free();
4348 
4349   if (dict->lookup("BE", &obj1)->isDict()) {
4350     borderEffect = new AnnotBorderEffect(obj1.getDict());
4351   } else {
4352     borderEffect = NULL;
4353   }
4354   obj1.free();
4355 
4356   geometryRect = NULL;
4357   if (dict->lookup("RD", &obj1)->isArray()) {
4358     geometryRect = parseDiffRectangle(obj1.getArray(), rect);
4359   }
4360   obj1.free();
4361 
4362 }
4363 
draw(Gfx * gfx,GBool printing)4364 void AnnotGeometry::draw(Gfx *gfx, GBool printing) {
4365   Object obj;
4366   double ca = 1;
4367 
4368   if (!isVisible (printing))
4369     return;
4370 
4371   if (appearance.isNull()) {
4372     ca = opacity;
4373 
4374     appearBuf = new GooString ();
4375     appearBuf->append ("q\n");
4376     if (color)
4377       setColor(color, gFalse);
4378 
4379     if (border) {
4380       int i, dashLength;
4381       double *dash;
4382       double borderWidth = border->getWidth();
4383 
4384       switch (border->getStyle()) {
4385       case AnnotBorder::borderDashed:
4386         appearBuf->append("[");
4387 	dashLength = border->getDashLength();
4388 	dash = border->getDash();
4389 	for (i = 0; i < dashLength; ++i)
4390 	  appearBuf->appendf(" {0:.2f}", dash[i]);
4391 	appearBuf->append(" ] 0 d\n");
4392 	break;
4393       default:
4394         appearBuf->append("[] 0 d\n");
4395         break;
4396       }
4397       appearBuf->appendf("{0:.2f} w\n", borderWidth);
4398 
4399       if (interiorColor)
4400         setColor(interiorColor, gTrue);
4401 
4402       if (type == typeSquare) {
4403         appearBuf->appendf ("{0:.2f} {1:.2f} {2:.2f} {3:.2f} re\n",
4404 			    borderWidth / 2.0, borderWidth / 2.0,
4405 			    (rect->x2 - rect->x1) - borderWidth,
4406 			    (rect->y2 - rect->y1) - borderWidth);
4407       } else {
4408         double width, height;
4409 	double b;
4410 	double x1, y1, x2, y2, x3, y3;
4411 
4412 	width = rect->x2 - rect->x1;
4413 	height = rect->y2 - rect->y1;
4414 	b = borderWidth / 2.0;
4415 
4416 	x1 = b;
4417 	y1 = height / 2.0;
4418 	appearBuf->appendf ("{0:.2f} {1:.2f} m\n", x1, y1);
4419 
4420 	y1 += height / 4.0;
4421 	x2 = width / 4.0;
4422 	y2 = height - b;
4423 	x3 = width / 2.0;
4424 	y3 = y2;
4425 	appearBuf->appendf ("{0:.2f} {1:.2f} {2:.2f} {3:.2f} {4:.2f} {5:.2f} c\n",
4426 			    x1, y1, x2, y2, x3, y3);
4427 	x2 = width - b;
4428 	y2 = y1;
4429 	x1 = x3 + (width / 4.0);
4430 	y1 = y3;
4431 	x3 = x2;
4432 	y3 = height / 2.0;
4433 	appearBuf->appendf ("{0:.2f} {1:.2f} {2:.2f} {3:.2f} {4:.2f} {5:.2f} c\n",
4434 			    x1, y1, x2, y2, x3, y3);
4435 
4436 	x2 = x1;
4437 	y2 = b;
4438 	x1 = x3;
4439 	y1 = height / 4.0;
4440 	x3 = width / 2.0;
4441 	y3 = b;
4442 	appearBuf->appendf ("{0:.2f} {1:.2f} {2:.2f} {3:.2f} {4:.2f} {5:.2f} c\n",
4443 			    x1, y1, x2, y2, x3, y3);
4444 
4445 	x2 = b;
4446 	y2 = y1;
4447 	x1 = width / 4.0;
4448 	y1 = b;
4449 	x3 = b;
4450 	y3 = height / 2.0;
4451 	appearBuf->appendf ("{0:.2f} {1:.2f} {2:.2f} {3:.2f} {4:.2f} {5:.2f} c\n",
4452 			    x1, y1, x2, y2, x3, y3);
4453 
4454       }
4455 
4456       if (interiorColor)
4457         appearBuf->append ("b\n");
4458       else
4459         appearBuf->append ("S\n");
4460     }
4461     appearBuf->append ("Q\n");
4462 
4463     double bbox[4];
4464     bbox[0] = bbox[1] = 0;
4465     bbox[2] = rect->x2 - rect->x1;
4466     bbox[3] = rect->y2 - rect->y1;
4467     if (ca == 1) {
4468       createForm(bbox, gFalse, NULL, &appearance);
4469     } else {
4470       Object aStream;
4471 
4472       createForm(bbox, gTrue, NULL, &aStream);
4473       delete appearBuf;
4474 
4475       Object resDict;
4476       appearBuf = new GooString ("/GS0 gs\n/Fm0 Do");
4477       createResourcesDict("Fm0", &aStream, "GS0", ca, NULL, &resDict);
4478       createForm(bbox, gFalse, &resDict, &appearance);
4479     }
4480     delete appearBuf;
4481   }
4482 
4483   // draw the appearance stream
4484   appearance.fetch(xref, &obj);
4485   gfx->drawAnnot(&obj, (AnnotBorder *)NULL, color,
4486 		 rect->x1, rect->y1, rect->x2, rect->y2);
4487   obj.free();
4488 }
4489 
4490 //------------------------------------------------------------------------
4491 // AnnotPolygon
4492 //------------------------------------------------------------------------
AnnotPolygon(XRef * xrefA,PDFRectangle * rect,AnnotSubtype subType,AnnotPath * path,Catalog * catalog)4493 AnnotPolygon::AnnotPolygon(XRef *xrefA, PDFRectangle *rect, AnnotSubtype subType,
4494 			   AnnotPath *path, Catalog *catalog) :
4495     AnnotMarkup(xrefA, rect, catalog) {
4496   Object obj1;
4497 
4498   switch (subType) {
4499     case typePolygon:
4500       annotObj.dictSet ("Subtype", obj1.initName ("Polygon"));
4501       break;
4502     case typePolyLine:
4503       annotObj.dictSet ("Subtype", obj1.initName ("PolyLine"));
4504       break;
4505     default:
4506       assert (0 && "Invalid subtype for AnnotGeometry\n");
4507   }
4508 
4509   Object obj2;
4510   obj2.initArray (xrefA);
4511 
4512   for (int i = 0; i < path->getCoordsLength(); ++i) {
4513     Object obj3;
4514 
4515     obj2.arrayAdd (obj3.initReal (path->getX(i)));
4516     obj2.arrayAdd (obj3.initReal (path->getY(i)));
4517   }
4518 
4519   annotObj.dictSet ("Vertices", &obj2);
4520 
4521   initialize(xrefA, catalog, annotObj.getDict());
4522 }
4523 
AnnotPolygon(XRef * xrefA,Dict * dict,Catalog * catalog,Object * obj)4524 AnnotPolygon::AnnotPolygon(XRef *xrefA, Dict *dict, Catalog *catalog, Object *obj) :
4525   AnnotMarkup(xrefA, dict, catalog, obj) {
4526   // the real type will be read in initialize()
4527   type = typePolygon;
4528   initialize(xrefA, catalog, dict);
4529 }
4530 
~AnnotPolygon()4531 AnnotPolygon::~AnnotPolygon() {
4532   delete vertices;
4533 
4534   if (interiorColor)
4535     delete interiorColor;
4536 
4537   if (borderEffect)
4538     delete borderEffect;
4539 }
4540 
initialize(XRef * xrefA,Catalog * catalog,Dict * dict)4541 void AnnotPolygon::initialize(XRef *xrefA, Catalog *catalog, Dict* dict) {
4542   Object obj1;
4543 
4544   if (dict->lookup("Subtype", &obj1)->isName()) {
4545     GooString typeName(obj1.getName());
4546     if (!typeName.cmp("Polygon")) {
4547       type = typePolygon;
4548     } else if (!typeName.cmp("PolyLine")) {
4549       type = typePolyLine;
4550     }
4551   }
4552   obj1.free();
4553 
4554   if (dict->lookup("Vertices", &obj1)->isArray()) {
4555     vertices = new AnnotPath(obj1.getArray());
4556   } else {
4557     vertices = new AnnotPath();
4558     error(-1, "Bad Annot Polygon Vertices");
4559     ok = gFalse;
4560   }
4561   obj1.free();
4562 
4563   if (dict->lookup("LE", &obj1)->isArray() && obj1.arrayGetLength() == 2) {
4564     Object obj2;
4565 
4566     if(obj1.arrayGet(0, &obj2)->isString())
4567       startStyle = parseAnnotLineEndingStyle(obj2.getString());
4568     else
4569       startStyle = annotLineEndingNone;
4570     obj2.free();
4571 
4572     if(obj1.arrayGet(1, &obj2)->isString())
4573       endStyle = parseAnnotLineEndingStyle(obj2.getString());
4574     else
4575       endStyle = annotLineEndingNone;
4576     obj2.free();
4577 
4578   } else {
4579     startStyle = endStyle = annotLineEndingNone;
4580   }
4581   obj1.free();
4582 
4583   if (dict->lookup("IC", &obj1)->isArray()) {
4584     interiorColor = new AnnotColor(obj1.getArray());
4585   } else {
4586     interiorColor = NULL;
4587   }
4588   obj1.free();
4589 
4590   if (dict->lookup("BE", &obj1)->isDict()) {
4591     borderEffect = new AnnotBorderEffect(obj1.getDict());
4592   } else {
4593     borderEffect = NULL;
4594   }
4595   obj1.free();
4596 
4597   if (dict->lookup("IT", &obj1)->isName()) {
4598     GooString *intentName = new GooString(obj1.getName());
4599 
4600     if(!intentName->cmp("PolygonCloud")) {
4601       intent = polygonCloud;
4602     } else if(!intentName->cmp("PolyLineDimension")) {
4603       intent = polylineDimension;
4604     } else {
4605       intent = polygonDimension;
4606     }
4607     delete intentName;
4608   } else {
4609     intent = polygonCloud;
4610   }
4611   obj1.free();
4612 }
4613 
4614 //------------------------------------------------------------------------
4615 // AnnotCaret
4616 //------------------------------------------------------------------------
AnnotCaret(XRef * xrefA,PDFRectangle * rect,Catalog * catalog)4617 AnnotCaret::AnnotCaret(XRef *xrefA, PDFRectangle *rect, Catalog *catalog) :
4618     AnnotMarkup(xrefA, rect, catalog) {
4619   Object obj1;
4620 
4621   type = typeCaret;
4622 
4623   annotObj.dictSet ("Subtype", obj1.initName ("Caret"));
4624   initialize(xrefA, catalog, annotObj.getDict());
4625 }
4626 
AnnotCaret(XRef * xrefA,Dict * dict,Catalog * catalog,Object * obj)4627 AnnotCaret::AnnotCaret(XRef *xrefA, Dict *dict, Catalog *catalog, Object *obj) :
4628   AnnotMarkup(xrefA, dict, catalog, obj) {
4629   type = typeCaret;
4630   initialize(xrefA, catalog, dict);
4631 }
4632 
~AnnotCaret()4633 AnnotCaret::~AnnotCaret() {
4634   delete caretRect;
4635 }
4636 
initialize(XRef * xrefA,Catalog * catalog,Dict * dict)4637 void AnnotCaret::initialize(XRef *xrefA, Catalog *catalog, Dict* dict) {
4638   Object obj1;
4639 
4640   symbol = symbolNone;
4641   if (dict->lookup("Sy", &obj1)->isName()) {
4642     GooString typeName(obj1.getName());
4643     if (!typeName.cmp("P")) {
4644       symbol = symbolP;
4645     } else if (!typeName.cmp("None")) {
4646       symbol = symbolNone;
4647     }
4648   }
4649   obj1.free();
4650 
4651   if (dict->lookup("RD", &obj1)->isArray()) {
4652     caretRect = parseDiffRectangle(obj1.getArray(), rect);
4653   } else {
4654     caretRect = NULL;
4655   }
4656   obj1.free();
4657 
4658 }
4659 
4660 //------------------------------------------------------------------------
4661 // AnnotInk
4662 //------------------------------------------------------------------------
AnnotInk(XRef * xrefA,PDFRectangle * rect,AnnotPath ** paths,int n_paths,Catalog * catalog)4663 AnnotInk::AnnotInk(XRef *xrefA, PDFRectangle *rect, AnnotPath **paths, int n_paths, Catalog *catalog) :
4664     AnnotMarkup(xrefA, rect, catalog) {
4665   Object obj1;
4666 
4667   type = typeInk;
4668 
4669   annotObj.dictSet ("Subtype", obj1.initName ("Ink"));
4670 
4671   Object obj2;
4672   obj2.initArray (xrefA);
4673 
4674   for (int i = 0; i < n_paths; ++i) {
4675     AnnotPath *path = paths[i];
4676     Object obj3;
4677     obj3.initArray (xrefA);
4678 
4679     for (int j = 0; j < path->getCoordsLength(); ++j) {
4680       Object obj4;
4681 
4682       obj3.arrayAdd (obj4.initReal (path->getX(j)));
4683       obj3.arrayAdd (obj4.initReal (path->getY(j)));
4684     }
4685 
4686     obj2.arrayAdd (&obj3);
4687   }
4688 
4689   annotObj.dictSet ("InkList", &obj2);
4690 
4691   initialize(xrefA, catalog, annotObj.getDict());
4692 }
4693 
AnnotInk(XRef * xrefA,Dict * dict,Catalog * catalog,Object * obj)4694 AnnotInk::AnnotInk(XRef *xrefA, Dict *dict, Catalog *catalog, Object *obj) :
4695   AnnotMarkup(xrefA, dict, catalog, obj) {
4696   type = typeInk;
4697   initialize(xrefA, catalog, dict);
4698 }
4699 
~AnnotInk()4700 AnnotInk::~AnnotInk() {
4701   if (inkList) {
4702     for (int i = 0; i < inkListLength; ++i)
4703       delete inkList[i];
4704     gfree(inkList);
4705   }
4706 }
4707 
initialize(XRef * xrefA,Catalog * catalog,Dict * dict)4708 void AnnotInk::initialize(XRef *xrefA, Catalog *catalog, Dict* dict) {
4709   Object obj1;
4710 
4711   if (dict->lookup("InkList", &obj1)->isArray()) {
4712     Array *array = obj1.getArray();
4713     inkListLength = array->getLength();
4714     inkList = (AnnotPath **) gmallocn ((inkListLength), sizeof(AnnotPath *));
4715     memset(inkList, 0, inkListLength * sizeof(AnnotPath *));
4716     for (int i = 0; i < inkListLength; i++) {
4717       Object obj2;
4718       if (array->get(i, &obj2)->isArray())
4719         inkList[i] = new AnnotPath(obj2.getArray());
4720       obj2.free();
4721     }
4722   } else {
4723     inkListLength = 0;
4724     inkList = NULL;
4725     error(-1, "Bad Annot Ink List");
4726     ok = gFalse;
4727   }
4728   obj1.free();
4729 }
4730 
4731 //------------------------------------------------------------------------
4732 // AnnotFileAttachment
4733 //------------------------------------------------------------------------
AnnotFileAttachment(XRef * xrefA,PDFRectangle * rect,GooString * filename,Catalog * catalog)4734 AnnotFileAttachment::AnnotFileAttachment(XRef *xrefA, PDFRectangle *rect, GooString *filename, Catalog *catalog) :
4735     AnnotMarkup(xrefA, rect, catalog) {
4736   Object obj1;
4737 
4738   type = typeFileAttachment;
4739 
4740   annotObj.dictSet ("Subtype", obj1.initName ("FileAttachment"));
4741 
4742   Object obj2;
4743   obj2.initString(filename->copy());
4744   annotObj.dictSet ("FS", &obj2);
4745 
4746   initialize(xrefA, catalog, annotObj.getDict());
4747 }
4748 
AnnotFileAttachment(XRef * xrefA,Dict * dict,Catalog * catalog,Object * obj)4749 AnnotFileAttachment::AnnotFileAttachment(XRef *xrefA, Dict *dict, Catalog *catalog, Object *obj) :
4750   AnnotMarkup(xrefA, dict, catalog, obj) {
4751   type = typeFileAttachment;
4752   initialize(xrefA, catalog, dict);
4753 }
4754 
~AnnotFileAttachment()4755 AnnotFileAttachment::~AnnotFileAttachment() {
4756   file.free();
4757 
4758   if (name)
4759     delete name;
4760 }
4761 
initialize(XRef * xrefA,Catalog * catalog,Dict * dict)4762 void AnnotFileAttachment::initialize(XRef *xrefA, Catalog *catalog, Dict* dict) {
4763   Object obj1;
4764 
4765   if (dict->lookup("FS", &obj1)->isDict() || dict->lookup("FS", &obj1)->isString()) {
4766     obj1.copy(&file);
4767   } else {
4768     error(-1, "Bad Annot File Attachment");
4769     ok = gFalse;
4770   }
4771   obj1.free();
4772 
4773   if (dict->lookup("Name", &obj1)->isName()) {
4774     name = new GooString(obj1.getName());
4775   } else {
4776     name = new GooString("PushPin");
4777   }
4778   obj1.free();
4779 }
4780 
4781 #define ANNOT_FILE_ATTACHMENT_AP_PUSHPIN                                         \
4782   "4.301 23 m 19.699 23 l 21.523 23 23 21.523 23 19.699 c 23 4.301 l 23\n"       \
4783   "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"     \
4784   "l 1 21.523 2.477 23 4.301 23 c h\n"                                           \
4785   "4.301 23 m f\n"                                                               \
4786   "0.533333 0.541176 0.521569 RG 2 w\n"                                          \
4787   "1 J\n"                                                                        \
4788   "1 j\n"                                                                        \
4789   "[] 0.0 d\n"                                                                   \
4790   "4 M 5 4 m 6 5 l S\n"                                                          \
4791   "2 w\n"                                                                        \
4792   "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"     \
4793   "17 l 11 14 l h\n"                                                             \
4794   "11 14 m S\n"                                                                  \
4795   "3 w\n"                                                                        \
4796   "6 5 m 9 8 l S\n"                                                              \
4797   "0.729412 0.741176 0.713725 RG 2 w\n"                                          \
4798   "5 5 m 6 6 l S\n"                                                              \
4799   "2 w\n"                                                                        \
4800   "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"     \
4801   "18 l 11 15 l h\n"                                                             \
4802   "11 15 m S\n"                                                                  \
4803   "3 w\n"                                                                        \
4804   "6 6 m 9 9 l S\n"
4805 
4806 #define ANNOT_FILE_ATTACHMENT_AP_PAPERCLIP                                       \
4807   "4.301 23 m 19.699 23 l 21.523 23 23 21.523 23 19.699 c 23 4.301 l 23\n"       \
4808   "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"     \
4809   "l 1 21.523 2.477 23 4.301 23 c h\n"                                           \
4810   "4.301 23 m f\n"                                                               \
4811   "0.533333 0.541176 0.521569 RG 2 w\n"                                          \
4812   "1 J\n"                                                                        \
4813   "1 j\n"                                                                        \
4814   "[] 0.0 d\n"                                                                   \
4815   "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" \
4816   "14.133 18.578 l 14.949 19.387 16.867 19.184 17.539 18.465 c 20.551\n"         \
4817   "15.23 l 21.191 14.66 21.336 12.887 20.426 12.102 c 13.18 4.824 l 12.18\n"     \
4818   "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"    \
4819   "17.887 l S\n"                                                                 \
4820   "0.729412 0.741176 0.713725 RG 16.645 13.035 m 12.418 8.707 l\n"               \
4821   "10.902 7.559 6.402 12.203 8.09 13.562 c\n"                                    \
4822   "14.133 19.578 l 14.949 20.387 16.867 20.184 17.539 19.465 c 20.551\n"         \
4823   "16.23 l 21.191 15.66 21.336 13.887 20.426 13.102 c 13.18 5.824 l 12.18\n"     \
4824   "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"    \
4825   "18.887 l S\n"
4826 
4827 #define ANNOT_FILE_ATTACHMENT_AP_GRAPH                                           \
4828   "4.301 23 m 19.699 23 l 21.523 23 23 21.523 23 19.699 c 23 4.301 l 23\n"       \
4829   "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"     \
4830   "l 1 21.523 2.477 23 4.301 23 c h\n"                                           \
4831   "4.301 23 m f\n"                                                               \
4832   "0.533333 0.541176 0.521569 RG 1 w\n"                                          \
4833   "1 J\n"                                                                        \
4834   "0 j\n"                                                                        \
4835   "[] 0.0 d\n"                                                                   \
4836   "4 M 18.5 15.5 m 18.5 13.086 l 16.086 15.5 l 18.5 15.5 l h\n"                  \
4837   "18.5 15.5 m S\n"                                                              \
4838   "7 7 m 10 11 l 13 9 l 18 15 l S\n"                                             \
4839   "0.729412 0.741176 0.713725 RG 7 8 m 10 12 l 13 10 l 18 16 l S\n"              \
4840   "18.5 16.5 m 18.5 14.086 l 16.086 16.5 l 18.5 16.5 l h\n"                      \
4841   "18.5 16.5 m S\n"                                                              \
4842   "0.533333 0.541176 0.521569 RG 2 w\n"                                          \
4843   "1 j\n"                                                                        \
4844   "3 19 m 3 3 l 21 3 l S\n"                                                      \
4845   "0.729412 0.741176 0.713725 RG 3 20 m 3 4 l 21 4 l S\n"
4846 
4847 #define ANNOT_FILE_ATTACHMENT_AP_TAG                                             \
4848   "4.301 23 m 19.699 23 l 21.523 23 23 21.523 23 19.699 c 23 4.301 l 23\n"       \
4849   "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"     \
4850   "l 1 21.523 2.477 23 4.301 23 c h\n"                                           \
4851   "4.301 23 m f\n"                                                               \
4852   "0.533333 0.541176 0.521569 RG 0.999781 w\n"                                   \
4853   "1 J\n"                                                                        \
4854   "1 j\n"                                                                        \
4855   "[] 0.0 d\n"                                                                   \
4856   "4 M q 1 0 0 -1 0 24 cm\n"                                                     \
4857   "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"    \
4858   "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"       \
4859   "8.492 7.879 8.492 8.707 c h\n"                                                \
4860   "8.492 8.707 m S Q\n"                                                          \
4861   "2 w\n"                                                                        \
4862   "20.078 11.414 m 20.891 10.602 20.785 9.293 20.078 8.586 c 14.422 2.93 l\n"    \
4863   "13.715 2.223 12.301 2.223 11.594 2.93 c 3.816 10.707 l 3.109 11.414\n"        \
4864   "2.402 17.781 3.816 19.195 c 5.23 20.609 11.594 19.902 12.301 19.195 c\n"      \
4865   "20.078 11.414 l h\n"                                                          \
4866   "20.078 11.414 m S\n"                                                          \
4867   "0.729412 0.741176 0.713725 RG 20.078 12.414 m\n"                              \
4868   "20.891 11.605 20.785 10.293 20.078 9.586 c 14.422 3.93 l\n"                   \
4869   "13.715 3.223 12.301 3.223 11.594 3.93 c 3.816 11.707 l 3.109 12.414\n"        \
4870   "2.402 18.781 3.816 20.195 c 5.23 21.609 11.594 20.902 12.301 20.195 c\n"      \
4871   "20.078 12.414 l h\n"                                                          \
4872   "20.078 12.414 m S\n"                                                          \
4873   "0.533333 0.541176 0.521569 RG 1 w\n"                                          \
4874   "0 j\n"                                                                        \
4875   "11.949 13.184 m 16.191 8.941 l S\n"                                           \
4876   "0.729412 0.741176 0.713725 RG 11.949 14.184 m 16.191 9.941 l S\n"             \
4877   "0.533333 0.541176 0.521569 RG 14.07 6.82 m 9.828 11.062 l S\n"                \
4878   "0.729412 0.741176 0.713725 RG 14.07 7.82 m 9.828 12.062 l S\n"                \
4879   "0.533333 0.541176 0.521569 RG 6.93 15.141 m 8 20 14.27 20.5 16 20.5 c\n"      \
4880   "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"     \
4881   "0.729412 0.741176 0.713725 RG 0.999781 w\n"                                   \
4882   "1 j\n"                                                                        \
4883   "q 1 0 0 -1 0 24 cm\n"                                                         \
4884   "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"       \
4885   "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"       \
4886   "8.492 6.879 8.492 7.707 c h\n"                                                \
4887   "8.492 7.707 m S Q\n"                                                          \
4888   "1 w\n"                                                                        \
4889   "0 j\n"                                                                        \
4890   "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"    \
4891   "19.5 17.699 20.91 17.418 22.5 17.5 c S\n"
4892 
draw(Gfx * gfx,GBool printing)4893 void AnnotFileAttachment::draw(Gfx *gfx, GBool printing) {
4894   Object obj;
4895   double ca = 1;
4896 
4897   if (!isVisible (printing))
4898     return;
4899 
4900   if (appearance.isNull()) {
4901     ca = opacity;
4902 
4903     appearBuf = new GooString ();
4904 
4905     appearBuf->append ("q\n");
4906     if (color)
4907       setColor(color, gTrue);
4908     else
4909       appearBuf->append ("1 1 1 rg\n");
4910     if (!name->cmp("PushPin"))
4911       appearBuf->append (ANNOT_FILE_ATTACHMENT_AP_PUSHPIN);
4912     else if (!name->cmp("Paperclip"))
4913       appearBuf->append (ANNOT_FILE_ATTACHMENT_AP_PAPERCLIP);
4914     else if (!name->cmp("Graph"))
4915       appearBuf->append (ANNOT_FILE_ATTACHMENT_AP_GRAPH);
4916     else if (!name->cmp("Tag"))
4917       appearBuf->append (ANNOT_FILE_ATTACHMENT_AP_TAG);
4918     appearBuf->append ("Q\n");
4919 
4920     double bbox[4];
4921     bbox[0] = bbox[1] = 0;
4922     bbox[2] = bbox[3] = 24;
4923     if (ca == 1) {
4924       createForm (bbox, gFalse, NULL, &appearance);
4925     } else {
4926       Object aStream;
4927 
4928       createForm (bbox, gTrue, NULL, &aStream);
4929       delete appearBuf;
4930 
4931       Object resDict;
4932       appearBuf = new GooString ("/GS0 gs\n/Fm0 Do");
4933       createResourcesDict("Fm0", &aStream, "GS0", ca, NULL, &resDict);
4934       createForm(bbox, gFalse, &resDict, &appearance);
4935     }
4936     delete appearBuf;
4937   }
4938 
4939   // draw the appearance stream
4940   appearance.fetch(xref, &obj);
4941   gfx->drawAnnot(&obj, border, color,
4942 		 rect->x1, rect->y1, rect->x2, rect->y2);
4943   obj.free();
4944 }
4945 
4946 //------------------------------------------------------------------------
4947 // AnnotSound
4948 //------------------------------------------------------------------------
AnnotSound(XRef * xrefA,PDFRectangle * rect,Sound * soundA,Catalog * catalog)4949 AnnotSound::AnnotSound(XRef *xrefA, PDFRectangle *rect, Sound *soundA, Catalog *catalog) :
4950     AnnotMarkup(xrefA, rect, catalog) {
4951   Object obj1;
4952 
4953   type = typeSound;
4954 
4955   annotObj.dictSet ("Subtype", obj1.initName ("Sound"));
4956 
4957   Object obj2;
4958   Stream *str = soundA->getStream();
4959   obj2.initStream (str);
4960   str->incRef(); //FIXME: initStream should do this?
4961   annotObj.dictSet ("Sound", &obj2);
4962 
4963   initialize(xrefA, catalog, annotObj.getDict());
4964 }
4965 
AnnotSound(XRef * xrefA,Dict * dict,Catalog * catalog,Object * obj)4966 AnnotSound::AnnotSound(XRef *xrefA, Dict *dict, Catalog *catalog, Object *obj) :
4967   AnnotMarkup(xrefA, dict, catalog, obj) {
4968   type = typeSound;
4969   initialize(xrefA, catalog, dict);
4970 }
4971 
~AnnotSound()4972 AnnotSound::~AnnotSound() {
4973   delete sound;
4974 
4975   delete name;
4976 }
4977 
initialize(XRef * xrefA,Catalog * catalog,Dict * dict)4978 void AnnotSound::initialize(XRef *xrefA, Catalog *catalog, Dict* dict) {
4979   Object obj1;
4980 
4981   sound = Sound::parseSound(dict->lookup("Sound", &obj1));
4982   if (!sound) {
4983     error(-1, "Bad Annot Sound");
4984     ok = gFalse;
4985   }
4986   obj1.free();
4987 
4988   if (dict->lookup("Name", &obj1)->isName()) {
4989     name = new GooString(obj1.getName());
4990   } else {
4991     name = new GooString("Speaker");
4992   }
4993   obj1.free();
4994 }
4995 
4996 #define ANNOT_SOUND_AP_SPEAKER                                               \
4997   "4.301 23 m 19.699 23 l 21.523 23 23 21.523 23 19.699 c 23 4.301 l 23\n"   \
4998   "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" \
4999   "l 1 21.523 2.477 23 4.301 23 c h\n"                                       \
5000   "4.301 23 m f\n"                                                           \
5001   "0.533333 0.541176 0.521569 RG 2 w\n"                                      \
5002   "0 J\n"                                                                    \
5003   "1 j\n"                                                                    \
5004   "[] 0.0 d\n"                                                               \
5005   "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"          \
5006   "4 14 m S\n"                                                               \
5007   "1 w\n"                                                                    \
5008   "1 J\n"                                                                    \
5009   "0 j\n"                                                                    \
5010   "13.699 15.398 m 14.699 13.398 14.699 9.398 13.699 7.398 c S\n"            \
5011   "18.199 19.398 m 21.199 17.398 21.199 5.398 18.199 3.398 c S\n"            \
5012   "16 17.398 m 18 16.398 18 7.398 16 5.398 c S\n"                            \
5013   "0.729412 0.741176 0.713725 RG 2 w\n"                                      \
5014   "0 J\n"                                                                    \
5015   "1 j\n"                                                                    \
5016   "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"              \
5017   "4 15 m S\n"                                                               \
5018   "1 w\n"                                                                    \
5019   "1 J\n"                                                                    \
5020   "0 j\n"                                                                    \
5021   "13.699 16 m 14.699 14 14.699 10 13.699 8 c S\n"                           \
5022   "18.199 20 m 21.199 18 21.199 6 18.199 4 c S\n"                            \
5023   "16 18 m 18 17 18 8 16 6 c S\n"
5024 
5025 #define ANNOT_SOUND_AP_MIC                                                        \
5026   "4.301 23 m 19.699 23 l 21.523 23 23 21.523 23 19.699 c 23 4.301 l 23\n"        \
5027   "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"      \
5028   "l 1 21.523 2.477 23 4.301 23 c h\n"                                            \
5029   "4.301 23 m f\n"                                                                \
5030   "0.533333 0.541176 0.521569 RG 2 w\n"                                           \
5031   "1 J\n"                                                                         \
5032   "0 j\n"                                                                         \
5033   "[] 0.0 d\n"                                                                    \
5034   "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" \
5035   "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"      \
5036   "20 c h\n"                                                                      \
5037   "12 20 m S\n"                                                                   \
5038   "1 w\n"                                                                         \
5039   "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"      \
5040   "8.941 6.5 11.973 c 6.5 14.5 l S\n"                                             \
5041   "2 w\n"                                                                         \
5042   "0 J\n"                                                                         \
5043   "12 6.52 m 12 3 l S\n"                                                          \
5044   "1 J\n"                                                                         \
5045   "8 3 m 16 3 l S\n"                                                              \
5046   "0.729412 0.741176 0.713725 RG 12 21 m 12 21 l 13.656 21 15 19.656 15 18 c\n"   \
5047   "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"       \
5048   "9 18 l 9 19.656 10.344 21 12 21 c h\n"                                         \
5049   "12 21 m S\n"                                                                   \
5050   "1 w\n"                                                                         \
5051   "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"      \
5052   "9.941 6.5 12.973 c 6.5 15.5 l S\n"                                             \
5053   "2 w\n"                                                                         \
5054   "0 J\n"                                                                         \
5055   "12 7.52 m 12 4 l S\n"                                                          \
5056   "1 J\n"                                                                         \
5057   "8 4 m 16 4 l S\n"
5058 
draw(Gfx * gfx,GBool printing)5059 void AnnotSound::draw(Gfx *gfx, GBool printing) {
5060   Object obj;
5061   double ca = 1;
5062 
5063   if (!isVisible (printing))
5064     return;
5065 
5066   if (appearance.isNull()) {
5067     ca = opacity;
5068 
5069     appearBuf = new GooString ();
5070 
5071     appearBuf->append ("q\n");
5072     if (color)
5073       setColor(color, gTrue);
5074     else
5075       appearBuf->append ("1 1 1 rg\n");
5076     if (!name->cmp("Speaker"))
5077       appearBuf->append (ANNOT_SOUND_AP_SPEAKER);
5078     else if (!name->cmp("Mic"))
5079       appearBuf->append (ANNOT_SOUND_AP_MIC);
5080     appearBuf->append ("Q\n");
5081 
5082     double bbox[4];
5083     bbox[0] = bbox[1] = 0;
5084     bbox[2] = bbox[3] = 24;
5085     if (ca == 1) {
5086       createForm(bbox, gFalse, NULL, &appearance);
5087     } else {
5088       Object aStream, resDict;
5089 
5090       createForm(bbox, gTrue, NULL, &aStream);
5091       delete appearBuf;
5092 
5093       appearBuf = new GooString ("/GS0 gs\n/Fm0 Do");
5094       createResourcesDict("Fm0", &aStream, "GS0", ca, NULL, &resDict);
5095       createForm(bbox, gFalse, &resDict, &appearance);
5096     }
5097     delete appearBuf;
5098   }
5099 
5100   // draw the appearance stream
5101   appearance.fetch(xref, &obj);
5102   gfx->drawAnnot(&obj, border, color,
5103 		 rect->x1, rect->y1, rect->x2, rect->y2);
5104   obj.free();
5105 }
5106 
5107 //------------------------------------------------------------------------
5108 // Annot3D
5109 //------------------------------------------------------------------------
Annot3D(XRef * xrefA,PDFRectangle * rect,Catalog * catalog)5110 Annot3D::Annot3D(XRef *xrefA, PDFRectangle *rect, Catalog *catalog) :
5111     Annot(xrefA, rect, catalog) {
5112   Object obj1;
5113 
5114   type = type3D;
5115 
5116   annotObj.dictSet ("Subtype", obj1.initName ("3D"));
5117 
5118   initialize(xrefA, catalog, annotObj.getDict());
5119 }
5120 
Annot3D(XRef * xrefA,Dict * dict,Catalog * catalog,Object * obj)5121 Annot3D::Annot3D(XRef *xrefA, Dict *dict, Catalog *catalog, Object *obj) :
5122   Annot(xrefA, dict, catalog, obj) {
5123   type = type3D;
5124   initialize(xrefA, catalog, dict);
5125 }
5126 
~Annot3D()5127 Annot3D::~Annot3D() {
5128   if (activation)
5129     delete activation;
5130 }
5131 
initialize(XRef * xrefA,Catalog * catalog,Dict * dict)5132 void Annot3D::initialize(XRef *xrefA, Catalog *catalog, Dict* dict) {
5133   Object obj1;
5134 
5135   if (dict->lookup("3DA", &obj1)->isDict()) {
5136     activation = new Activation(obj1.getDict());
5137   } else {
5138     activation = NULL;
5139   }
5140   obj1.free();
5141 }
5142 
Activation(Dict * dict)5143 Annot3D::Activation::Activation(Dict *dict) {
5144   Object obj1;
5145 
5146   if (dict->lookup("A", &obj1)->isName()) {
5147     GooString *name = new GooString(obj1.getName());
5148 
5149     if(!name->cmp("PO")) {
5150       aTrigger = aTriggerPageOpened;
5151     } else if(!name->cmp("PV")) {
5152       aTrigger = aTriggerPageVisible;
5153     } else if(!name->cmp("XA")) {
5154       aTrigger = aTriggerUserAction;
5155     } else {
5156       aTrigger = aTriggerUnknown;
5157     }
5158     delete name;
5159   } else {
5160     aTrigger = aTriggerUnknown;
5161   }
5162   obj1.free();
5163 
5164   if(dict->lookup("AIS", &obj1)->isName()) {
5165     GooString *name = new GooString(obj1.getName());
5166 
5167     if(!name->cmp("I")) {
5168       aState = aStateEnabled;
5169     } else if(!name->cmp("L")) {
5170       aState = aStateDisabled;
5171     } else {
5172       aState = aStateUnknown;
5173     }
5174     delete name;
5175   } else {
5176     aState = aStateUnknown;
5177   }
5178   obj1.free();
5179 
5180   if(dict->lookup("D", &obj1)->isName()) {
5181     GooString *name = new GooString(obj1.getName());
5182 
5183     if(!name->cmp("PC")) {
5184       dTrigger = dTriggerPageClosed;
5185     } else if(!name->cmp("PI")) {
5186       dTrigger = dTriggerPageInvisible;
5187     } else if(!name->cmp("XD")) {
5188       dTrigger = dTriggerUserAction;
5189     } else {
5190       dTrigger = dTriggerUnknown;
5191     }
5192     delete name;
5193   } else {
5194     dTrigger = dTriggerUnknown;
5195   }
5196   obj1.free();
5197 
5198   if(dict->lookup("DIS", &obj1)->isName()) {
5199     GooString *name = new GooString(obj1.getName());
5200 
5201     if(!name->cmp("U")) {
5202       dState = dStateUninstantiaded;
5203     } else if(!name->cmp("I")) {
5204       dState = dStateInstantiated;
5205     } else if(!name->cmp("L")) {
5206       dState = dStateLive;
5207     } else {
5208       dState = dStateUnknown;
5209     }
5210     delete name;
5211   } else {
5212     dState = dStateUnknown;
5213   }
5214   obj1.free();
5215 
5216   if (dict->lookup("TB", &obj1)->isBool()) {
5217     displayToolbar = obj1.getBool();
5218   } else {
5219     displayToolbar = gTrue;
5220   }
5221   obj1.free();
5222 
5223   if (dict->lookup("NP", &obj1)->isBool()) {
5224     displayNavigation = obj1.getBool();
5225   } else {
5226     displayNavigation = gFalse;
5227   }
5228   obj1.free();
5229 }
5230 
5231 //------------------------------------------------------------------------
5232 // Annots
5233 //------------------------------------------------------------------------
5234 
Annots(XRef * xref,Catalog * catalog,Object * annotsObj)5235 Annots::Annots(XRef *xref, Catalog *catalog, Object *annotsObj) {
5236   Annot *annot;
5237   Object obj1;
5238   int size;
5239   int i;
5240 
5241   annots = NULL;
5242   size = 0;
5243   nAnnots = 0;
5244 
5245   if (annotsObj->isArray()) {
5246     for (i = 0; i < annotsObj->arrayGetLength(); ++i) {
5247       //get the Ref to this annot and pass it to Annot constructor
5248       //this way, it'll be possible for the annot to retrieve the corresponding
5249       //form widget
5250       Object obj2;
5251       if (annotsObj->arrayGet(i, &obj1)->isDict()) {
5252         annotsObj->arrayGetNF(i, &obj2);
5253         annot = createAnnot (xref, obj1.getDict(), catalog, &obj2);
5254         if (annot && annot->isOk()) {
5255           if (nAnnots >= size) {
5256             size += 16;
5257             annots = (Annot **)greallocn(annots, size, sizeof(Annot *));
5258           }
5259           annots[nAnnots++] = annot;
5260         } else {
5261           delete annot;
5262         }
5263       }
5264       obj2.free();
5265       obj1.free();
5266     }
5267   }
5268 }
5269 
createAnnot(XRef * xref,Dict * dict,Catalog * catalog,Object * obj)5270 Annot *Annots::createAnnot(XRef *xref, Dict* dict, Catalog *catalog, Object *obj) {
5271   Annot *annot;
5272   Object obj1;
5273 
5274   if (dict->lookup("Subtype", &obj1)->isName()) {
5275     GooString *typeName = new GooString(obj1.getName());
5276 
5277     if (!typeName->cmp("Text")) {
5278       annot = new AnnotText(xref, dict, catalog, obj);
5279     } else if (!typeName->cmp("Link")) {
5280       annot = new AnnotLink(xref, dict, catalog, obj);
5281     } else if (!typeName->cmp("FreeText")) {
5282       annot = new AnnotFreeText(xref, dict, catalog, obj);
5283     } else if (!typeName->cmp("Line")) {
5284       annot = new AnnotLine(xref, dict, catalog, obj);
5285     } else if (!typeName->cmp("Square")) {
5286       annot = new AnnotGeometry(xref, dict, catalog, obj);
5287     } else if (!typeName->cmp("Circle")) {
5288       annot = new AnnotGeometry(xref, dict, catalog, obj);
5289     } else if (!typeName->cmp("Polygon")) {
5290       annot = new AnnotPolygon(xref, dict, catalog, obj);
5291     } else if (!typeName->cmp("PolyLine")) {
5292       annot = new AnnotPolygon(xref, dict, catalog, obj);
5293     } else if (!typeName->cmp("Highlight")) {
5294       annot = new AnnotTextMarkup(xref, dict, catalog, obj);
5295     } else if (!typeName->cmp("Underline")) {
5296       annot = new AnnotTextMarkup(xref, dict, catalog, obj);
5297     } else if (!typeName->cmp("Squiggly")) {
5298       annot = new AnnotTextMarkup(xref, dict, catalog, obj);
5299     } else if (!typeName->cmp("StrikeOut")) {
5300       annot = new AnnotTextMarkup(xref, dict, catalog, obj);
5301     } else if (!typeName->cmp("Stamp")) {
5302       annot = new AnnotStamp(xref, dict, catalog, obj);
5303     } else if (!typeName->cmp("Caret")) {
5304       annot = new AnnotCaret(xref, dict, catalog, obj);
5305     } else if (!typeName->cmp("Ink")) {
5306       annot = new AnnotInk(xref, dict, catalog, obj);
5307     } else if (!typeName->cmp("FileAttachment")) {
5308       annot = new AnnotFileAttachment(xref, dict, catalog, obj);
5309     } else if (!typeName->cmp("Sound")) {
5310       annot = new AnnotSound(xref, dict, catalog, obj);
5311     } else if(!typeName->cmp("Movie")) {
5312       annot = new AnnotMovie(xref, dict, catalog, obj);
5313     } else if(!typeName->cmp("Widget")) {
5314       annot = new AnnotWidget(xref, dict, catalog, obj);
5315     } else if(!typeName->cmp("Screen")) {
5316       annot = new AnnotScreen(xref, dict, catalog, obj);
5317     } else if(!typeName->cmp("PrinterMark")) {
5318       annot = new Annot(xref, dict, catalog, obj);
5319     } else if (!typeName->cmp("TrapNet")) {
5320       annot = new Annot(xref, dict, catalog, obj);
5321     } else if (!typeName->cmp("Watermark")) {
5322       annot = new Annot(xref, dict, catalog, obj);
5323     } else if (!typeName->cmp("3D")) {
5324       annot = new Annot3D(xref, dict, catalog, obj);
5325     } else if (!typeName->cmp("Popup")) {
5326       /* Popup annots are already handled by markup annots
5327        * Here we only care about popup annots without a
5328        * markup annotation associated
5329        */
5330       Object obj2;
5331 
5332       if (dict->lookup("Parent", &obj2)->isNull())
5333         annot = new AnnotPopup(xref, dict, catalog, obj);
5334       else
5335         annot = NULL;
5336 
5337       obj2.free();
5338     } else {
5339       annot = new Annot(xref, dict, catalog, obj);
5340     }
5341 
5342     delete typeName;
5343   } else {
5344     annot = NULL;
5345   }
5346   obj1.free();
5347 
5348   return annot;
5349 }
5350 
findAnnot(Ref * ref)5351 Annot *Annots::findAnnot(Ref *ref) {
5352   int i;
5353 
5354   for (i = 0; i < nAnnots; ++i) {
5355     if (annots[i]->match(ref)) {
5356       return annots[i];
5357     }
5358   }
5359   return NULL;
5360 }
5361 
5362 
~Annots()5363 Annots::~Annots() {
5364   int i;
5365 
5366   for (i = 0; i < nAnnots; ++i) {
5367     delete annots[i];
5368   }
5369   gfree(annots);
5370 }
5371