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

Last change on this file since 2 was 2, checked in by Eugene Romanenko, 15 years ago

First import

File size: 7.5 KB
Line 
1//========================================================================
2//
3// Annot.cc
4//
5// Copyright 2000-2003 Glyph & Cog, LLC
6//
7//========================================================================
8
9#include <config.h>
10
11#ifdef USE_GCC_PRAGMAS
12#pragma implementation
13#endif
14
15#include <stdlib.h>
16#include "goo/gmem.h"
17#include "Object.h"
18#include "Catalog.h"
19#include "Gfx.h"
20#include "Lexer.h"
21#include "UGooString.h"
22#include "Annot.h"
23
24//------------------------------------------------------------------------
25// Annot
26//------------------------------------------------------------------------
27
28Annot::Annot(XRef *xrefA, Dict *acroForm, Dict *dict) {
29  Object apObj, asObj, obj1, obj2;
30  GBool regen, isTextField;
31  double t;
32
33  ok = gFalse;
34  xref = xrefA;
35  appearBuf = NULL;
36
37  if (dict->lookup("Rect", &obj1)->isArray() &&
38      obj1.arrayGetLength() == 4) {
39    //~ should check object types here
40    obj1.arrayGet(0, &obj2);
41    xMin = obj2.getNum();
42    obj2.free();
43    obj1.arrayGet(1, &obj2);
44    yMin = obj2.getNum();
45    obj2.free();
46    obj1.arrayGet(2, &obj2);
47    xMax = obj2.getNum();
48    obj2.free();
49    obj1.arrayGet(3, &obj2);
50    yMax = obj2.getNum();
51    obj2.free();
52    if (xMin > xMax) {
53      t = xMin; xMin = xMax; xMax = t;
54    }
55    if (yMin > yMax) {
56      t = yMin; yMin = yMax; yMax = t;
57    }
58  } else {
59    //~ this should return an error
60    xMin = yMin = 0;
61    xMax = yMax = 1;
62  }
63  obj1.free();
64
65  // check if field apperances need to be regenerated
66  regen = gFalse;
67  if (acroForm) {
68    acroForm->lookup("NeedAppearances", &obj1);
69    if (obj1.isBool() && obj1.getBool()) {
70      regen = gTrue;
71    }
72    obj1.free();
73  }
74
75  // check for a text-type field
76  isTextField = dict->lookup("FT", &obj1)->isName("Tx");
77  obj1.free();
78
79#if 0 //~ appearance stream generation is not finished yet
80  if (regen && isTextField) {
81    generateAppearance(acroForm, dict);
82  } else {
83#endif
84    if (dict->lookup("AP", &apObj)->isDict()) {
85      if (dict->lookup("AS", &asObj)->isName()) {
86        if (apObj.dictLookup("N", &obj1)->isDict()) {
87          if (obj1.dictLookupNF(asObj.getName(), &obj2)->isRef()) {
88            obj2.copy(&appearance);
89            ok = gTrue;
90          } else {
91            obj2.free();
92            if (obj1.dictLookupNF("Off", &obj2)->isRef()) {
93              obj2.copy(&appearance);
94              ok = gTrue;
95            }
96          }
97          obj2.free();
98        }
99        obj1.free();
100      } else {
101        if (apObj.dictLookupNF("N", &obj1)->isRef()) {
102          obj1.copy(&appearance);
103          ok = gTrue;
104        }
105        obj1.free();
106      }
107      asObj.free();
108    }
109    apObj.free();
110#if 0 //~ appearance stream generation is not finished yet
111  }
112#endif
113}
114
115Annot::~Annot() {
116  appearance.free();
117  if (appearBuf) {
118    delete appearBuf;
119  }
120}
121
122void Annot::generateAppearance(Dict *acroForm, Dict *dict) {
123  MemStream *appearStream;
124  Object daObj, vObj, drObj, appearDict, obj1, obj2;
125  GooString *daStr, *daStr1, *vStr, *s;
126  char buf[256];
127  double fontSize;
128  int c;
129  int i0, i1;
130
131  //~ DA can be inherited
132  if (dict->lookup("DA", &daObj)->isString()) {
133    daStr = daObj.getString();
134
135    // look for a font size
136    //~ may want to parse the DS entry in place of this (if it exists)
137    daStr1 = NULL;
138    fontSize = 10;
139    for (i1 = daStr->getLength() - 2; i1 >= 0; --i1) {
140      if (daStr->getChar(i1) == 'T' && daStr->getChar(i1+1) == 'f') {
141        for (--i1; i1 >= 0 && Lexer::isSpace(daStr->getChar(i1)); --i1) ;
142        for (i0 = i1; i0 >= 0 && !Lexer::isSpace(daStr->getChar(i0)); --i0) ;
143        if (i0 >= 0) {
144          ++i0;
145          ++i1;
146          s = new GooString(daStr, i0, i1 - i0);
147          fontSize = atof(s->getCString());
148          delete s;
149
150          // autosize the font
151          if (fontSize == 0) {
152            fontSize = 0.67 * (yMax - yMin);
153            daStr1 = new GooString(daStr, 0, i0);
154            sprintf(buf, "%.2f", fontSize);
155            daStr1->append(buf);
156            daStr1->append(daStr->getCString() + i1,
157                           daStr->getLength() - i1);
158          }
159        }
160        break;
161      }
162    }
163
164    // build the appearance stream contents
165    appearBuf = new GooString();
166    appearBuf->append("/Tx BMC\n");
167    appearBuf->append("q BT\n");
168    appearBuf->append(daStr1 ? daStr1 : daStr)->append("\n");
169    if (dict->lookup("V", &vObj)->isString()) {
170      //~ handle quadding -- this requires finding the font and using
171      //~   the encoding and char widths
172      sprintf(buf, "1 0 0 1 %.2f %.2f Tm\n", 2.0, yMax - yMin - fontSize);
173      appearBuf->append(buf);
174      sprintf(buf, "%g TL\n", fontSize);
175      appearBuf->append(buf);
176      vStr = vObj.getString();
177      i0 = 0;
178      while (i0 < vStr->getLength()) {
179        for (i1 = i0;
180             i1 < vStr->getLength() &&
181               vStr->getChar(i1) != '\n' && vStr->getChar(i1) != '\r';
182             ++i1) ;
183        if (i0 > 0) {
184          appearBuf->append("T*\n");
185        }
186        appearBuf->append('(');
187        for (; i0 < i1; ++i0) {
188          c = vStr->getChar(i0);
189          if (c == '(' || c == ')' || c == '\\') {
190            appearBuf->append('\\');
191            appearBuf->append(c);
192          } else if (c < 0x20 || c >= 0x80) {
193            sprintf(buf, "\\%03o", c);
194            appearBuf->append(buf);
195          } else {
196            appearBuf->append(c);
197          }
198        }
199        appearBuf->append(") Tj\n");
200        if (i1 + 1 < vStr->getLength() &&
201            vStr->getChar(i1) == '\r' && vStr->getChar(i1 + 1) == '\n') {
202          i0 = i1 + 2;
203        } else {
204          i0 = i1 + 1;
205        }
206      }
207    }
208    vObj.free();
209    appearBuf->append("ET Q\n");
210    appearBuf->append("EMC\n");
211
212    // build the appearance stream dictionary
213    appearDict.initDict(xref);
214    appearDict.dictAdd("Length", obj1.initInt(appearBuf->getLength()));
215    appearDict.dictAdd("Subtype", obj1.initName("Form"));
216    obj1.initArray(xref);
217    obj1.arrayAdd(obj2.initReal(0));
218    obj1.arrayAdd(obj2.initReal(0));
219    obj1.arrayAdd(obj2.initReal(xMax - xMin));
220    obj1.arrayAdd(obj2.initReal(yMax - yMin));
221    appearDict.dictAdd("BBox", &obj1);
222
223    // find the resource dictionary
224    dict->lookup("DR", &drObj);
225    if (!drObj.isDict()) {
226      dict->lookup("Parent", &obj1);
227      while (obj1.isDict()) {
228        drObj.free();
229        obj1.dictLookup("DR", &drObj);
230        if (drObj.isDict()) {
231          break;
232        }
233        obj1.dictLookup("Parent", &obj2);
234        obj1.free();
235        obj1 = obj2;
236      }
237      obj1.free();
238      if (!drObj.isDict()) {
239        if (acroForm) {
240          drObj.free();
241          acroForm->lookup("DR", &drObj);
242        }
243      }
244    }
245    if (drObj.isDict()) {
246      appearDict.dictAdd("Resources", drObj.copy(&obj1));
247    }
248    drObj.free();
249
250    // build the appearance stream
251    appearStream = new MemStream(appearBuf->getCString(), 0,
252                                 appearBuf->getLength(), &appearDict);
253    appearance.initStream(appearStream);
254    ok = gTrue;
255
256    if (daStr1) {
257      delete daStr1;
258    }
259  }
260  daObj.free();
261}
262
263void Annot::draw(Gfx *gfx) {
264  Object obj;
265
266  if (appearance.fetch(xref, &obj)->isStream()) {
267    gfx->doAnnot(&obj, xMin, yMin, xMax, yMax);
268  }
269  obj.free();
270}
271
272//------------------------------------------------------------------------
273// Annots
274//------------------------------------------------------------------------
275
276Annots::Annots(XRef *xref, Catalog *catalog, Object *annotsObj) {
277  Dict *acroForm;
278  Annot *annot;
279  Object obj1;
280  int size;
281  int i;
282
283  annots = NULL;
284  size = 0;
285  nAnnots = 0;
286
287  acroForm = catalog->getAcroForm()->isDict() ?
288               catalog->getAcroForm()->getDict() : NULL;
289  if (annotsObj->isArray()) {
290    for (i = 0; i < annotsObj->arrayGetLength(); ++i) {
291      if (annotsObj->arrayGet(i, &obj1)->isDict()) {
292        annot = new Annot(xref, acroForm, obj1.getDict());
293        if (annot->isOk()) {
294          if (nAnnots >= size) {
295            size += 16;
296            annots = (Annot **)greallocn(annots, size, sizeof(Annot *));
297          }
298          annots[nAnnots++] = annot;
299        } else {
300          delete annot;
301        }
302      }
303      obj1.free();
304    }
305  }
306}
307
308Annots::~Annots() {
309  int i;
310
311  for (i = 0; i < nAnnots; ++i) {
312    delete annots[i];
313  }
314  gfree(annots);
315}
Note: See TracBrowser for help on using the repository browser.