source: trunk/poppler/mypoppler/poppler/Annot.cc @ 461

Last change on this file since 461 was 461, checked in by Silvan Scherrer, 11 years ago

poppler update to 0.14.2

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