moved ../../pdf2swf/xpdf to .
[swftools.git] / lib / xpdf / Annot.cc
diff --git a/lib/xpdf/Annot.cc b/lib/xpdf/Annot.cc
new file mode 100644 (file)
index 0000000..68bfb6d
--- /dev/null
@@ -0,0 +1,315 @@
+//========================================================================
+//
+// Annot.cc
+//
+// Copyright 2000-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <stdlib.h>
+#include "gmem.h"
+#include "Object.h"
+#include "Catalog.h"
+#include "Gfx.h"
+#include "Lexer.h"
+#include "Annot.h"
+
+//------------------------------------------------------------------------
+// Annot
+//------------------------------------------------------------------------
+
+Annot::Annot(XRef *xrefA, Dict *acroForm, Dict *dict) {
+  Object apObj, asObj, obj1, obj2;
+  GBool regen, isTextField;
+  double t;
+
+  ok = gFalse;
+  xref = xrefA;
+  appearBuf = NULL;
+
+  if (dict->lookup("Rect", &obj1)->isArray() &&
+      obj1.arrayGetLength() == 4) {
+    //~ should check object types here
+    obj1.arrayGet(0, &obj2);
+    xMin = obj2.getNum();
+    obj2.free();
+    obj1.arrayGet(1, &obj2);
+    yMin = obj2.getNum();
+    obj2.free();
+    obj1.arrayGet(2, &obj2);
+    xMax = obj2.getNum();
+    obj2.free();
+    obj1.arrayGet(3, &obj2);
+    yMax = obj2.getNum();
+    obj2.free();
+    if (xMin > xMax) {
+      t = xMin; xMin = xMax; xMax = t;
+    }
+    if (yMin > yMax) {
+      t = yMin; yMin = yMax; yMax = t;
+    }
+  } else {
+    //~ this should return an error
+    xMin = yMin = 0;
+    xMax = yMax = 1;
+  }
+  obj1.free();
+
+  // check if field apperances need to be regenerated
+  regen = gFalse;
+  if (acroForm) {
+    acroForm->lookup("NeedAppearances", &obj1);
+    if (obj1.isBool() && obj1.getBool()) {
+      regen = gTrue;
+    }
+    obj1.free();
+  }
+
+  // check for a text-type field
+  isTextField = dict->lookup("FT", &obj1)->isName("Tx");
+  obj1.free();
+
+#if 0 //~ appearance stream generation is not finished yet
+  if (regen && isTextField) {
+    generateAppearance(acroForm, dict);
+  } else {
+#endif
+    if (dict->lookup("AP", &apObj)->isDict()) {
+      if (dict->lookup("AS", &asObj)->isName()) {
+       if (apObj.dictLookup("N", &obj1)->isDict()) {
+         if (obj1.dictLookupNF(asObj.getName(), &obj2)->isRef()) {
+           obj2.copy(&appearance);
+           ok = gTrue;
+         } else {
+           obj2.free();
+           if (obj1.dictLookupNF("Off", &obj2)->isRef()) {
+             obj2.copy(&appearance);
+             ok = gTrue;
+           }
+         }
+         obj2.free();
+       }
+       obj1.free();
+      } else {
+       if (apObj.dictLookupNF("N", &obj1)->isRef()) {
+         obj1.copy(&appearance);
+         ok = gTrue;
+       }
+       obj1.free();
+      }
+      asObj.free();
+    }
+    apObj.free();
+#if 0 //~ appearance stream generation is not finished yet
+  }
+#endif
+}
+
+Annot::~Annot() {
+  appearance.free();
+  if (appearBuf) {
+    delete appearBuf;
+  }
+}
+
+void Annot::generateAppearance(Dict *acroForm, Dict *dict) {
+  MemStream *appearStream;
+  Object daObj, vObj, drObj, appearDict, obj1, obj2;
+  GString *daStr, *daStr1, *vStr, *s;
+  char buf[256];
+  double fontSize;
+  int c;
+  int i0, i1;
+
+  //~ DA can be inherited
+  if (dict->lookup("DA", &daObj)->isString()) {
+    daStr = daObj.getString();
+
+    // look for a font size
+    //~ may want to parse the DS entry in place of this (if it exists)
+    daStr1 = NULL;
+    fontSize = 10;
+    for (i1 = daStr->getLength() - 2; i1 >= 0; --i1) {
+      if (daStr->getChar(i1) == 'T' && daStr->getChar(i1+1) == 'f') {
+       for (--i1; i1 >= 0 && Lexer::isSpace(daStr->getChar(i1)); --i1) ;
+       for (i0 = i1; i0 >= 0 && !Lexer::isSpace(daStr->getChar(i0)); --i0) ;
+       if (i0 >= 0) {
+         ++i0;
+         ++i1;
+         s = new GString(daStr, i0, i1 - i0);
+         fontSize = atof(s->getCString());
+         delete s;
+
+         // autosize the font
+         if (fontSize == 0) {
+           fontSize = 0.67 * (yMax - yMin);
+           daStr1 = new GString(daStr, 0, i0);
+           sprintf(buf, "%.2f", fontSize);
+           daStr1->append(buf);
+           daStr1->append(daStr->getCString() + i1,
+                          daStr->getLength() - i1);
+         }
+       }
+       break;
+      }
+    }
+
+    // build the appearance stream contents
+    appearBuf = new GString();
+    appearBuf->append("/Tx BMC\n");
+    appearBuf->append("q BT\n");
+    appearBuf->append(daStr1 ? daStr1 : daStr)->append("\n");
+    if (dict->lookup("V", &vObj)->isString()) {
+      //~ handle quadding -- this requires finding the font and using
+      //~   the encoding and char widths
+      sprintf(buf, "1 0 0 1 %.2f %.2f Tm\n", 2.0, yMax - yMin - fontSize);
+      appearBuf->append(buf);
+      sprintf(buf, "%g TL\n", fontSize);
+      appearBuf->append(buf);
+      vStr = vObj.getString();
+      i0 = 0;
+      while (i0 < vStr->getLength()) {
+       for (i1 = i0;
+            i1 < vStr->getLength() &&
+              vStr->getChar(i1) != '\n' && vStr->getChar(i1) != '\r';
+            ++i1) ;
+       if (i0 > 0) {
+         appearBuf->append("T*\n");
+       }
+       appearBuf->append('(');
+       for (; i0 < i1; ++i0) {
+         c = vStr->getChar(i0);
+         if (c == '(' || c == ')' || c == '\\') {
+           appearBuf->append('\\');
+           appearBuf->append(c);
+         } else if (c < 0x20 || c >= 0x80) {
+           sprintf(buf, "\\%03o", c);
+           appearBuf->append(buf);
+         } else {
+           appearBuf->append(c);
+         }
+       }
+       appearBuf->append(") Tj\n");
+       if (i1 + 1 < vStr->getLength() &&
+           vStr->getChar(i1) == '\r' && vStr->getChar(i1 + 1) == '\n') {
+         i0 = i1 + 2;
+       } else {
+         i0 = i1 + 1;
+       }
+      }
+    }
+    vObj.free();
+    appearBuf->append("ET Q\n");
+    appearBuf->append("EMC\n");
+
+    // build the appearance stream dictionary
+    appearDict.initDict(xref);
+    appearDict.dictAdd(copyString("Length"),
+                      obj1.initInt(appearBuf->getLength()));
+    appearDict.dictAdd(copyString("Subtype"), obj1.initName("Form"));
+    obj1.initArray(xref);
+    obj1.arrayAdd(obj2.initReal(0));
+    obj1.arrayAdd(obj2.initReal(0));
+    obj1.arrayAdd(obj2.initReal(xMax - xMin));
+    obj1.arrayAdd(obj2.initReal(yMax - yMin));
+    appearDict.dictAdd(copyString("BBox"), &obj1);
+
+    // find the resource dictionary
+    dict->lookup("DR", &drObj);
+    if (!drObj.isDict()) {
+      dict->lookup("Parent", &obj1);
+      while (obj1.isDict()) {
+       drObj.free();
+       obj1.dictLookup("DR", &drObj);
+       if (drObj.isDict()) {
+         break;
+       }
+       obj1.dictLookup("Parent", &obj2);
+       obj1.free();
+       obj1 = obj2;
+      }
+      obj1.free();
+      if (!drObj.isDict()) {
+       if (acroForm) {
+         drObj.free();
+         acroForm->lookup("DR", &drObj);
+       }
+      }
+    }
+    if (drObj.isDict()) {
+      appearDict.dictAdd(copyString("Resources"), drObj.copy(&obj1));
+    }
+    drObj.free();
+
+    // build the appearance stream
+    appearStream = new MemStream(appearBuf->getCString(), 0,
+                                appearBuf->getLength(), &appearDict);
+    appearance.initStream(appearStream);
+    ok = gTrue;
+
+    if (daStr1) {
+      delete daStr1;
+    }
+  }
+  daObj.free();
+}
+
+void Annot::draw(Gfx *gfx) {
+  Object obj;
+
+  if (appearance.fetch(xref, &obj)->isStream()) {
+    gfx->doAnnot(&obj, xMin, yMin, xMax, yMax);
+  }
+  obj.free();
+}
+
+//------------------------------------------------------------------------
+// Annots
+//------------------------------------------------------------------------
+
+Annots::Annots(XRef *xref, Catalog *catalog, Object *annotsObj) {
+  Dict *acroForm;
+  Annot *annot;
+  Object obj1;
+  int size;
+  int i;
+
+  annots = NULL;
+  size = 0;
+  nAnnots = 0;
+
+  acroForm = catalog->getAcroForm()->isDict() ?
+               catalog->getAcroForm()->getDict() : NULL;
+  if (annotsObj->isArray()) {
+    for (i = 0; i < annotsObj->arrayGetLength(); ++i) {
+      if (annotsObj->arrayGet(i, &obj1)->isDict()) {
+       annot = new Annot(xref, acroForm, obj1.getDict());
+       if (annot->isOk()) {
+         if (nAnnots >= size) {
+           size += 16;
+           annots = (Annot **)greallocn(annots, size, sizeof(Annot *));
+         }
+         annots[nAnnots++] = annot;
+       } else {
+         delete annot;
+       }
+      }
+      obj1.free();
+    }
+  }
+}
+
+Annots::~Annots() {
+  int i;
+
+  for (i = 0; i < nAnnots; ++i) {
+    delete annots[i];
+  }
+  gfree(annots);
+}