-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Hello:

I'm trying to improve the Annotations support so I have an idea to
create a good backend for them in poppler using inheritance and sharing
as must code as I can. This could mean mayor changes in the actual
implementation so I have done some changes and I'm sending a patch witch
represents a basic idea of what i want to do.

Actually I have documented the main Annot specification on the file and
do a little implementation. My idea is start implementing the base
Annotations (so i can temporaly move to evince and finnish my soc
proposal) and then trying to improve further Annotations on poppler.

How do you see this idea ?

Any suggestion is welcome as i don't know if I'm going in the right
direction.

Thank you,

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.6 (GNU/Linux)

iD8DBQFGMko0YeZEGfB6+4IRAncnAJ9QT1erAZ4XKygw+wQmY9kNSoDWIwCdHIJo
hJBOT8fKKup8EwZX0k5LvUU=
=fH/G
-----END PGP SIGNATURE-----
Index: poppler/Page.h
===================================================================
RCS file: /cvs/poppler/poppler/poppler/Page.h,v
retrieving revision 1.9
diff -u -r1.9 Page.h
--- poppler/Page.h	25 Apr 2007 19:59:10 -0000	1.9
+++ poppler/Page.h	27 Apr 2007 18:52:10 -0000
@@ -28,6 +28,8 @@
 
 //------------------------------------------------------------------------
 
+// TODO: the class should provide public getters and move attributes to private
+// section so the object could be encapsulated.
 class PDFRectangle {
 public:
   double x1, y1, x2, y2;
Index: poppler/Gfx.cc
===================================================================
RCS file: /cvs/poppler/poppler/poppler/Gfx.cc,v
retrieving revision 1.15
diff -u -r1.15 Gfx.cc
--- poppler/Gfx.cc	25 Apr 2007 19:59:10 -0000	1.15
+++ poppler/Gfx.cc	27 Apr 2007 18:52:08 -0000
@@ -4051,7 +4051,7 @@
 // misc
 //------------------------------------------------------------------------
 
-void Gfx::drawAnnot(Object *str, AnnotBorderStyle *borderStyle,
+void Gfx::drawAnnot(Object *str, AnnotBorder *border,
 		    double xMin, double yMin, double xMax, double yMax) {
   Dict *dict, *resDict;
   Object matrixObj, bboxObj, resObj;
@@ -4173,13 +4173,13 @@
   }
 
   // draw the border
-  if (borderStyle && borderStyle->getWidth() > 0) {
+  if (border && border->getWidth() > 0) {
     if (state->getStrokeColorSpace()->getMode() != csDeviceRGB) {
       state->setStrokePattern(NULL);
       state->setStrokeColorSpace(new GfxDeviceRGBColorSpace());
       out->updateStrokeColorSpace(state);
     }
-    borderStyle->getColor(&r, &g, &b);
+    border->getColor(&r, &g, &b);
     color.c[0] = dblToCol(r);
     color.c[1] = dblToCol(g);
     color.c[2] = dblToCol(b);
@@ -4192,10 +4192,11 @@
     y = (baseMatrix[0] + baseMatrix[2]) * ictm[1] +
         (baseMatrix[1] + baseMatrix[3]) * ictm[3];
     x = sqrt(0.5 * (x * x + y * y));
-    state->setLineWidth(x * borderStyle->getWidth());
+    state->setLineWidth(x * border->getWidth());
     out->updateLineWidth(state);
-    borderStyle->getDash(&dash, &dashLength);
-    if (borderStyle->getType() == annotBorderDashed && dashLength > 0) {
+    border->getDash(&dash, &dashLength);
+    if ((border->getStyle() == AnnotBorder::borderDashed)
+        && dashLength > 0) {
       dash2 = (double *)gmallocn(dashLength, sizeof(double));
       for (i = 0; i < dashLength; ++i) {
 	dash2[i] = x * dash[i];
@@ -4207,7 +4208,7 @@
     state->clearPath();
     state->moveTo(annotX0, out->upsideDown() ? annotY1 : annotY0);
     state->lineTo(annotX1, out->upsideDown() ? annotY1 : annotY0);
-    if (borderStyle->getType() != annotBorderUnderlined) {
+    if (border->getStyle() != AnnotBorder::borderUnderlined) {
       state->lineTo(annotX1, out->upsideDown() ? annotY0 : annotY1);
       state->lineTo(annotX0, out->upsideDown() ? annotY0 : annotY1);
       state->closePath();
Index: poppler/Annot.h
===================================================================
RCS file: /cvs/poppler/poppler/poppler/Annot.h,v
retrieving revision 1.6
diff -u -r1.6 Annot.h
--- poppler/Annot.h	25 Apr 2007 19:59:10 -0000	1.6
+++ poppler/Annot.h	27 Apr 2007 18:52:02 -0000
@@ -13,59 +13,191 @@
 #pragma interface
 #endif
 
+#include "goo/GooVector.h"
+
 class XRef;
 class Gfx;
 class Catalog;
 class CharCodeToUnicode;
 class GfxFont;
 class GfxFontDict;
+class PDFRectangle;
+
+#define fieldFlagReadOnly           0x00000001
+#define fieldFlagRequired           0x00000002
+#define fieldFlagNoExport           0x00000004
+#define fieldFlagMultiline          0x00001000
+#define fieldFlagPassword           0x00002000
+#define fieldFlagNoToggleToOff      0x00004000
+#define fieldFlagRadio              0x00008000
+#define fieldFlagPushbutton         0x00010000
+#define fieldFlagCombo              0x00020000
+#define fieldFlagEdit               0x00040000
+#define fieldFlagSort               0x00080000
+#define fieldFlagFileSelect         0x00100000
+#define fieldFlagMultiSelect        0x00200000
+#define fieldFlagDoNotSpellCheck    0x00400000
+#define fieldFlagDoNotScroll        0x00800000
+#define fieldFlagComb               0x01000000
+#define fieldFlagRichText           0x02000000
+#define fieldFlagRadiosInUnison     0x02000000
+#define fieldFlagCommitOnSelChange  0x04000000
+
+#define fieldQuadLeft   0
+#define fieldQuadCenter 1
+#define fieldQuadRight  2
+
+// distance of Bezier control point from center for circle approximation
+// = (4 * (sqrt(2) - 1) / 3) * r
+#define bezierCircle 0.55228475
 
 //------------------------------------------------------------------------
-// AnnotBorderStyle
+// AnnotBorderEffect
 //------------------------------------------------------------------------
 
-enum AnnotBorderType {
-  annotBorderSolid,
-  annotBorderDashed,
-  annotBorderBeveled,
-  annotBorderInset,
-  annotBorderUnderlined
+class AnnotBorderEffect {
+public:
+  
+  enum AnnotBorderEffectType {
+    borderEffectNoEffect,
+    borderEffectCloudy
+  };
+  
+  AnnotBorderEffect(Dict*& dict);
+  ~AnnotBorderEffect();
+
+  AnnotBorderEffectType getEffectType() { return effectType; }
+  double getIntensity() { return intensity; }
+
+private:
+
+  AnnotBorderEffectType effectType;
+  double intensity;
 };
 
-class AnnotBorderStyle {
+//------------------------------------------------------------------------
+// AnnotBorder
+//------------------------------------------------------------------------
+
+class AnnotBorder {
 public:
 
-  AnnotBorderStyle(AnnotBorderType typeA, double widthA,
+
+  enum AnnotBorderStyle {
+    borderSolid,
+    borderDashed,
+    borderBeveled,
+    borderInset,
+    borderUnderlined,
+  };
+  
+  AnnotBorder(Dict*& dict);
+  
+  AnnotBorder(AnnotBorderStyle typeA, double widthA,
 		   double *dashA, int dashLengthA,
 		   double rA, double gA, double bA);
-  ~AnnotBorderStyle();
+  ~AnnotBorder();
 
-  AnnotBorderType getType() { return type; }
+  AnnotBorderStyle getStyle() { return style; }
   double getWidth() { return width; }
   void getDash(double **dashA, int *dashLengthA)
     { *dashA = dash; *dashLengthA = dashLength; }
+    
+  // this property should be caught from the annotation
   void getColor(double *rA, double *gA, double *bA)
     { *rA = r; *gA = g; *bA = b; }
 
 private:
 
-  AnnotBorderType type;
-  double width;
-  double *dash;
+  double width;           // W
+  AnnotBorderStyle style; // S
+  double *dash;           // D
   int dashLength;
   double r, g, b;
 };
 
 //------------------------------------------------------------------------
+// AnnotColor
+//------------------------------------------------------------------------
+
+class AnnotColor {
+public:
+
+  enum AnnotColorSpace {
+    colorTransparent = 0,
+    colorGary        = 1,
+    colorRGB         = 3,
+    colorCMYK        = 4
+  };
+  
+  AnnotColor(int size, double colors[]);
+  ~AnnotColor();
+
+  AnnotColorSpace getSpace();
+  double getValue(int i);
+
+private:
+
+  double* values;
+  int size;
+};
+
+//------------------------------------------------------------------------
 // Annot
 //------------------------------------------------------------------------
 
 class Annot {
 public:
 
+  enum flag {
+    flagUnknown        = 0x0000,
+    flagInvisible      = 0x0001,
+    flagHidden         = 0x0002,
+    flagPrint          = 0x0004,
+    flagNoZoom         = 0x0008,
+    flagNoRotate       = 0x0010,
+    flagNoView         = 0x0020,
+    flagReadOnly       = 0x0040,
+    flagLocked         = 0x0080,
+    flagToggleNoView   = 0x0100,
+    flagLockedContents = 0x0200
+  };
+
+  enum AnnotSubtype {
+    typeText,
+    typeLink,
+    typeFreeText,
+    typeLine,
+    typeSquare,
+    typeCircle,
+    typePolygon,
+    typePolyLine,
+    typeHighlight,
+    typeUnderline,
+    typeSquiggly,
+    typeStrikeOut,
+    typeStamp,
+    typeCaret,
+    typeInk,
+    typePopup,
+    typeFileAttachment,
+    typeSound,
+    typeMovie,
+    typeWidget,
+    typeScreen,
+    typePrinterMark,
+    typeTrapNet,
+    typeWatermark,
+    type3D,
+    typeUnknown
+  };
+  
+  Annot(const Ref& ref, Dict* dict);
+    
   Annot(XRef *xrefA, Dict *acroForm, Dict *dict, Catalog *catalog);
   Annot(XRef *xrefA, Dict *acroForm, Dict *dict, const Ref& aref, Catalog *catalog);
-  ~Annot();
+  virtual ~Annot();
+  
   GBool isOk() { return ok; }
 
   void draw(Gfx *gfx, GBool printing);
@@ -74,18 +206,33 @@
   Object *getAppearance(Object *obj) { return appearance.fetch(xref, obj); }
   GBool textField() { return isTextField; }
 
-  AnnotBorderStyle *getBorderStyle () { return borderStyle; }
-
   GBool match(Ref *refA)
     { return ref.num == refA->num && ref.gen == refA->gen; }
 
   void generateFieldAppearance(Dict *field, Dict *annot, Dict *acroForm);
 
-  double getXMin() { return xMin; }
-  double getYMin() { return yMin; }
+  double getXMin();
+  double getYMin();
 
   double getFontSize() { return fontSize; }
 
+  virtual void initialize (Dict*& dict);
+  
+  // getters
+  AnnotSubtype getType() { return type; }
+  PDFRectangle* getRect() { return rect; }
+  GooString* getContents() { return contents; }
+  Dict* getPageDict() { return pageDict; }
+  GooString* getAnnotName() { return annotName; }
+  GooString* getModified() { return modified; }
+  Guint getFlags() { return flags; }
+  Dict* getAppearDict() { return appearDict; }
+  GooString* getAppearState() { return appearState; }
+  AnnotBorder* getBorder() { return border; }
+  AnnotColor* getAnnotColor() { return color; }
+  int getTreeKey() { return treeKey; }
+  Dict* getOptionalContent() { return optionalContent; }
+    
 private:
 //  void writeTextString (GooString* vStr, CharCodeToUnicode* ccToUnicode, GooString* appearBuf, GfxFont* font);
 //  void generateAppearance(Dict *acroForm, Dict *dict);
@@ -108,17 +255,34 @@
   void writeTextString (GooString *text, GooString *appearBuf, int *i, int j, CharCodeToUnicode *ccToUnicode); 
 
   void initialize (XRef *xrefA, Dict *acroForm, Dict *dict, Catalog *catalog);
-
+  
+  // required data
+  AnnotSubtype type;                // annotation type
+  PDFRectangle* rect;               // Rect
+  
+  // optional data
+  GooString* contents;              // Contents
+  Dict* pageDict;                   // P
+  GooString* annotName;             // NM
+  GooString* modified;              // M
+  Guint flags;                      // F (must be a 32 bit unsigned int)
+  Dict* appearDict;                 // AP
+  GooString* appearState;           // AS
+  AnnotBorder* border;              // Border
+  AnnotColor* color;                // C
+  int treeKey;                      // Struct Parent;
+  Dict* optionalContent;            // OC
+  
+  // in  recent versions
+  AnnotBorder* borderNew;           // BS
+  AnnotBorderEffect* borderEffect;  // BE
+  
+  
   XRef *xref;			// the xref table for this PDF file
   Ref ref; // object ref identifying this annotation
-  GooString *type; // annotation type
   Object appearance;		// a reference to the Form XObject stream
 				//   for the normal appearance
   GooString *appearBuf;
-  Guint flags;
-  double xMin, yMin,		// annotation rectangle
-         xMax, yMax;
-  AnnotBorderStyle *borderStyle;
   double fontSize; 
   GBool ok;
   GBool regen, isTextField;
@@ -129,6 +293,33 @@
 };
 
 //------------------------------------------------------------------------
+// AnnotText
+//------------------------------------------------------------------------
+
+class AnnotText: public Annot {
+public:
+  AnnotText(const Ref& ref, Dict* dict);
+};
+
+//------------------------------------------------------------------------
+// AnnotLink
+//------------------------------------------------------------------------
+
+class AnnotLink: public Annot {
+public:
+  AnnotLink(const Ref& ref, Dict* dict);
+};
+
+//------------------------------------------------------------------------
+// AnnotWidget
+//------------------------------------------------------------------------
+
+class AnnotWidget: public Annot {
+public:
+  AnnotWidget(const Ref& ref, Dict* dict);
+};
+
+//------------------------------------------------------------------------
 // Annots
 //------------------------------------------------------------------------
 
Index: poppler/Annot.cc
===================================================================
RCS file: /cvs/poppler/poppler/poppler/Annot.cc,v
retrieving revision 1.10
diff -u -r1.10 Annot.cc
--- poppler/Annot.cc	25 Apr 2007 19:59:10 -0000	1.10
+++ poppler/Annot.cc	27 Apr 2007 18:52:02 -0000
@@ -16,6 +16,7 @@
 #include <math.h>
 #include "goo/gmem.h"
 #include "GooList.h"
+#include "GooVector.h"
 #include "Error.h"
 #include "Object.h"
 #include "Catalog.h"
@@ -26,47 +27,90 @@
 #include "CharCodeToUnicode.h"
 #include "Form.h"
 #include "Error.h"
+#include "Page.h"
 
-#define annotFlagHidden    0x0002
-#define annotFlagPrint     0x0004
-#define annotFlagNoView    0x0020
-
-#define fieldFlagReadOnly           0x00000001
-#define fieldFlagRequired           0x00000002
-#define fieldFlagNoExport           0x00000004
-#define fieldFlagMultiline          0x00001000
-#define fieldFlagPassword           0x00002000
-#define fieldFlagNoToggleToOff      0x00004000
-#define fieldFlagRadio              0x00008000
-#define fieldFlagPushbutton         0x00010000
-#define fieldFlagCombo              0x00020000
-#define fieldFlagEdit               0x00040000
-#define fieldFlagSort               0x00080000
-#define fieldFlagFileSelect         0x00100000
-#define fieldFlagMultiSelect        0x00200000
-#define fieldFlagDoNotSpellCheck    0x00400000
-#define fieldFlagDoNotScroll        0x00800000
-#define fieldFlagComb               0x01000000
-#define fieldFlagRichText           0x02000000
-#define fieldFlagRadiosInUnison     0x02000000
-#define fieldFlagCommitOnSelChange  0x04000000
-
-#define fieldQuadLeft   0
-#define fieldQuadCenter 1
-#define fieldQuadRight  2
-
-// distance of Bezier control point from center for circle approximation
-// = (4 * (sqrt(2) - 1) / 3) * r
-#define bezierCircle 0.55228475
+//------------------------------------------------------------------------
+// AnnotBorderEffect
+//------------------------------------------------------------------------
+
+AnnotBorderEffect::AnnotBorderEffect(Dict*& dict) {
+  Object obj1;
+  
+  if (dict->lookup("S", &obj1)->isName()) {
+    GooString* effectName = new GooString(obj1.getName());
+    if(effectName->cmp("S"))
+      effectType = borderEffectNoEffect;
+    if(effectName->cmp("C"))
+      effectType = borderEffectCloudy;
+  } else {
+    effectType = borderEffectNoEffect;
+  }
+  obj1.free();
+  
+  if ((dict->lookup("I", &obj1)->isNum())
+      && (effectType = borderEffectCloudy)) {
+    intensity = obj1.getNum();
+  } else {
+    intensity = 0;
+  }
+  obj1.free();
+}
 
 //------------------------------------------------------------------------
-// AnnotBorderStyle
+// AnnotBorder
 //------------------------------------------------------------------------
 
-AnnotBorderStyle::AnnotBorderStyle(AnnotBorderType typeA, double widthA,
+AnnotBorder::AnnotBorder(Dict*& dict) {
+  Object obj1;
+  if (dict->lookup("W", &obj1)->isNum()) {
+    width = obj1.getNum();
+  } else {
+    width = 1;
+  }
+  obj1.free();
+  
+  if (dict->lookup("S", &obj1)->isName()) {
+    GooString* styleName = new GooString(obj1.getName());
+    if(styleName->cmp("Solid"))
+      style = borderSolid;
+    if(styleName->cmp("Dashed"))
+      style = borderDashed;
+    if(styleName->cmp("Beveled"))
+      style = borderBeveled;
+    if(styleName->cmp("Inset"))
+      style = borderInset;
+    if(styleName->cmp("Underlined"))
+      style = borderUnderlined;
+  } else {
+    style = borderSolid;
+  }
+  obj1.free();
+  
+  if (dict->lookup("D", &obj1)->isArray()) {
+    Object obj2;
+    dashLength = obj1.arrayGetLength();
+    dash = new double[dashLength];
+    for(int i = 0; i < dashLength; i++) {
+      if(obj1.arrayGet(i, &obj2)->isNum())
+        dash[i] = obj2.getNum();
+      obj2.free();
+    }
+  } else {
+    dashLength = 1;
+    dash = new double[dashLength];
+    dash[0] = 3;
+  }
+  obj1.free();
+}
+
+AnnotBorder::AnnotBorder(AnnotBorderStyle styleA, double widthA,
 				   double *dashA, int dashLengthA,
 				   double rA, double gA, double bA) {
-  type = typeA;
+  
+  width = 1;
+  
+  
+  style = styleA;
   width = widthA;
   dash = dashA;
   dashLength = dashLengthA;
@@ -75,16 +119,62 @@
   b = bA;
 }
 
-AnnotBorderStyle::~AnnotBorderStyle() {
+AnnotBorder::~AnnotBorder() {
   if (dash) {
     gfree(dash);
   }
 }
 
 //------------------------------------------------------------------------
+// AnnotColor
+//------------------------------------------------------------------------
+
+AnnotColor::AnnotColor(int i, double* colors) {
+  size = i;
+  values = colors;
+}
+
+AnnotColor::AnnotColorSpace AnnotColor::getSpace() {
+  return (AnnotColor::AnnotColorSpace) size;
+}
+
+double AnnotColor:: getValue(int i) {
+  if(i >= 0 && i < size) 
+    values[i];
+  return 0;
+}
+  
+AnnotColor::~AnnotColor() {
+  delete values;
+}
+    
+//------------------------------------------------------------------------
 // Annot
 //------------------------------------------------------------------------
 
+Annot::Annot(const Ref& ref, Dict* dict) {
+  Object obj1;
+  double t;
+
+  type = typeUnknown;
+    //----- parse the type
+  // this should be done outside of the Annot class so we can create derivated
+  // specialized classes.
+  if (dict->lookup("Subtype", &obj1)->isName()) {
+    GooString *subtype = new GooString(obj1.getName());
+    if(!subtype->cmp("Text"))
+      type = typeText;
+    if(!subtype->cmp("Link"))
+      type = typeLink;
+    // ...
+    if(!subtype->cmp("Widget"))
+      type = typeWidget;
+  }
+  obj1.free();
+  
+  initialize(dict);
+}
+
 Annot::Annot(XRef *xrefA, Dict *acroForm, Dict *dict, const Ref& aref, Catalog* catalog)
 {
   hasRef = true;
@@ -97,9 +187,210 @@
   initialize (xrefA, acroForm, dict, catalog);
 }
 
+void Annot::initialize(Dict*& dict) {
+  AnnotBorder::AnnotBorderStyle borderStyle;
+  Object obj1, obj2, obj3;
+  double t;
+  
+  rect = new PDFRectangle();  
+  if (dict->lookup("Rect", &obj1)->isArray() && obj1.arrayGetLength() == 4) {
+    readArrayNum(&obj1, 0, &rect->x1);
+    readArrayNum(&obj1, 1, &rect->y1);
+    readArrayNum(&obj1, 2, &rect->x2);
+    readArrayNum(&obj1, 3, &rect->y2);
+    if (rect->x1 > rect->x2) {
+      t = rect->x1; rect->x1 = rect->x2; rect->x2 = t;
+    }
+    if (rect->y1 > rect->y2) {
+      t = rect->y1; rect->y1 = rect->y2; rect->y2 = t;
+    }
+  } else {
+    rect->x2 = rect->y2 = 1;
+    error(-1, "Bad bounding box for annotation");
+    ok = gFalse;
+  }
+  obj1.free();
+    
+  if (dict->lookup("Contents", &obj1)->isString()) {
+    contents = new GooString(obj1.getString());
+  } else {
+    contents = NULL;
+  }
+  obj1.free();
+    
+  if (dict->lookup("P", &obj1)->isDict()) {
+    pageDict = obj1.getDict();
+  } else {
+    pageDict = NULL;
+  }
+  obj1.free();
+  
+  if (dict->lookup("NM", &obj1)->isString()) {
+    annotName = new GooString(obj1.getString());
+  } else {
+    annotName = NULL;
+  }
+  obj1.free();
+  
+  if (dict->lookup("M", &obj1)->isString()) {
+    modified = new GooString(obj1.getString());
+  } else {
+    modified = NULL;
+  }
+  obj1.free();
+  
+  if (dict->lookup("F", &obj1)->isInt()) {
+    flags = obj1.getInt();
+  } else {
+    flags = flagUnknown;
+  }
+  obj1.free();
+  
+  if (dict->lookup("F", &obj1)->isInt()) {
+    flags = obj1.getInt();
+  } else {
+    flags = flagUnknown;
+  }
+  obj1.free();
+  
+  if (dict->lookup("AP", &obj1)->isDict()) {
+    appearDict = obj1.getDict();
+  } else {
+    appearDict = NULL;
+  }
+  obj1.free();
+  
+  if (dict->lookup("AS", &obj1)->isName()) {
+    // here we should create a derivated class instead of specifying the type
+    // attrib 
+    appearState = new GooString(obj1.getName());
+  } else {
+    appearState = NULL;
+  }
+  obj1.free();
+
+  if (dict->lookup("C", &obj1)->isArray()) {
+    Object obj2;
+    int length = obj1.arrayGetLength();
+    double* values = new double[length];
+    for(int i = 0; i < length; i++) {
+      if(obj1.arrayGet(i, &obj2)->isNum())
+        values[i] = obj2.getNum();
+      obj2.free();
+    }
+    color = new AnnotColor(length, values);
+  }
+  obj1.free();
+  
+  if (dict->lookup("StructParent", &obj1)->isInt()) {
+    treeKey = obj1.getInt();
+  } else {
+    treeKey = 0;
+  }
+  obj1.free();
+  
+  if (dict->lookup("OC", &obj1)->isDict()) {
+    optionalContent = obj1.getDict();
+  } else {
+    optionalContent = NULL;
+  }
+  obj1.free();
+  
+    //----- parse the border style
+  /*
+  borderType = AnnotBorderStyle::annotBorderSolid;
+  borderWidth = 1;
+  borderDash = NULL;
+  borderDashLength = 0;
+  borderR = 0;
+  borderG = 0;
+  borderB = 1;
+  if (dict->lookup("BS", &obj1)->isDict()) {
+    if (obj1.dictLookup("S", &obj2)->isName()) {
+      if (obj2.isName("S")) {
+        borderType = AnnotBorderStyle::annotBorderSolid;
+      } else if (obj2.isName("D")) {
+        borderType = AnnotBorderStyle::annotBorderDashed;
+      } else if (obj2.isName("B")) {
+        borderType = AnnotBorderStyle::annotBorderBeveled;
+      } else if (obj2.isName("I")) {
+        borderType = AnnotBorderStyle::annotBorderInset;
+      } else if (obj2.isName("U")) {
+        borderType = AnnotBorderStyle::annotBorderUnderlined;
+      }
+    }
+    obj2.free();
+    if (obj1.dictLookup("W", &obj2)->isNum()) {
+      borderWidth = obj2.getNum();
+    }
+    obj2.free();
+    if (obj1.dictLookup("D", &obj2)->isArray()) {
+      borderDashLength = obj2.arrayGetLength();
+      borderDash = (double *)gmallocn(borderDashLength, sizeof(double));
+      for (int i = 0; i < borderDashLength; ++i) {
+        if (obj2.arrayGet(i, &obj3)->isNum()) {
+          borderDash[i] = obj3.getNum();
+        } else {
+          borderDash[i] = 1;
+        }
+        obj3.free();
+      }
+    }
+    obj2.free();
+  } else {
+    obj1.free();
+    if (dict->lookup("Border", &obj1)->isArray()) {
+      if (obj1.arrayGetLength() >= 3) {
+        if (obj1.arrayGet(2, &obj2)->isNum()) {
+          borderWidth = obj2.getNum();
+        }
+        obj2.free();
+        if (obj1.arrayGetLength() >= 4) {
+          if (obj1.arrayGet(3, &obj2)->isArray()) {
+            borderType = AnnotBorderStyle::annotBorderDashed;
+            borderDashLength = obj2.arrayGetLength();
+            borderDash = (double *)gmallocn(borderDashLength, sizeof(double));
+            for (int i = 0; i < borderDashLength; ++i) {
+              if (obj2.arrayGet(i, &obj3)->isNum()) {
+                borderDash[i] = obj3.getNum();
+              } else {
+                borderDash[i] = 1;
+              }
+              obj3.free();
+            }
+          } else {
+            // Adobe draws no border at all if the last element is of
+            // the wrong type.
+            borderWidth = 0;
+          }
+        }
+      }
+    }
+  }
+  if (dict->lookup("C", &obj1)->isArray() && obj1.arrayGetLength() == 3) {
+    if (obj1.arrayGet(0, &obj2)->isNum()) {
+      borderR = obj2.getNum();
+    }
+    obj1.free();
+    if (obj1.arrayGet(1, &obj2)->isNum()) {
+      borderG = obj2.getNum();
+    }
+    obj1.free();
+    if (obj1.arrayGet(2, &obj2)->isNum()) {
+      borderB = obj2.getNum();
+    }
+    obj1.free();
+  }
+  obj1.free();
+  borderStyle = new AnnotBorderStyle(borderType, borderWidth,
+      borderDash, borderDashLength,
+      borderR, borderG, borderB);
+      */
+}
+
 void Annot::initialize(XRef *xrefA, Dict *acroForm, Dict *dict, Catalog *catalog) {
   Object apObj, asObj, obj1, obj2, obj3;
-  AnnotBorderType borderType;
+  AnnotBorder::AnnotBorderStyle borderStyle;
   double borderWidth;
   double *borderDash;
   int borderDashLength;
@@ -110,14 +401,16 @@
   xref = xrefA;
   appearBuf = NULL;
   fontSize = 0;
-  type = NULL;
+  type = typeText;
   //widget = NULL;
-  borderStyle = NULL;
+  borderStyle = AnnotBorder::borderSolid;
 
   //----- parse the type
 
   if (dict->lookup("Subtype", &obj1)->isName()) {
-    type = new GooString(obj1.getName());
+    GooString * name = new GooString(obj1.getName()); 
+    if(name->cmp("Text"))
+      type = typeText;
   }
   obj1.free();
 
@@ -125,26 +418,26 @@
 
   if (dict->lookup("Rect", &obj1)->isArray() &&
       obj1.arrayGetLength() == 4) {
-    readArrayNum(&obj1, 0, &xMin);
-    readArrayNum(&obj1, 1, &yMin);
-    readArrayNum(&obj1, 2, &xMax);
-    readArrayNum(&obj1, 3, &yMax);
+    readArrayNum(&obj1, 0, &rect->x1);
+    readArrayNum(&obj1, 1, &rect->y1);
+    readArrayNum(&obj1, 2, &rect->x2);
+    readArrayNum(&obj1, 3, &rect->y2);
     if (ok) {
-      if (xMin > xMax) {
-        t = xMin; xMin = xMax; xMax = t;
+      if (rect->x1 > rect->x2) {
+        t = rect->x1; rect->x1 = rect->x2; rect->x2 = t;
       }
-      if (yMin > yMax) {
-        t = yMin; yMin = yMax; yMax = t;
+      if (rect->y1 > rect->y2) {
+        t = rect->y1; rect->y1 = rect->y2; rect->y2 = t;
       }
     } else {
-      xMin = yMin = 0;
-      xMax = yMax = 1;
+      rect->x1 = rect->y1 = 0;
+      rect->x2 = rect->y2 = 1;
       error(-1, "Bad bounding box for annotation");
       ok = gFalse;
     }
   } else {
-    xMin = yMin = 0;
-    xMax = yMax = 1;
+    rect->x1 = rect->y1 = 0;
+    rect->x2 = rect->y2 = 1;
     error(-1, "Bad bounding box for annotation");
     ok = gFalse;
   }
@@ -178,7 +471,7 @@
 
   //----- parse the border style
 
-  borderType = annotBorderSolid;
+  borderStyle = AnnotBorder::borderSolid;
   borderWidth = 1;
   borderDash = NULL;
   borderDashLength = 0;
@@ -188,15 +481,15 @@
   if (dict->lookup("BS", &obj1)->isDict()) {
     if (obj1.dictLookup("S", &obj2)->isName()) {
       if (obj2.isName("S")) {
-        borderType = annotBorderSolid;
+        borderStyle = AnnotBorder::borderSolid;
       } else if (obj2.isName("D")) {
-        borderType = annotBorderDashed;
+        borderStyle = AnnotBorder::borderDashed;
       } else if (obj2.isName("B")) {
-        borderType = annotBorderBeveled;
+        borderStyle = AnnotBorder::borderBeveled;
       } else if (obj2.isName("I")) {
-        borderType = annotBorderInset;
+        borderStyle = AnnotBorder::borderInset;
       } else if (obj2.isName("U")) {
-        borderType = annotBorderUnderlined;
+        borderStyle = AnnotBorder::borderUnderlined;
       }
     }
     obj2.free();
@@ -227,7 +520,7 @@
         obj2.free();
         if (obj1.arrayGetLength() >= 4) {
           if (obj1.arrayGet(3, &obj2)->isArray()) {
-            borderType = annotBorderDashed;
+            borderStyle = AnnotBorder::borderDashed;
             borderDashLength = obj2.arrayGetLength();
             borderDash = (double *)gmallocn(borderDashLength, sizeof(double));
             for (int i = 0; i < borderDashLength; ++i) {
@@ -262,7 +555,7 @@
     obj1.free();
   }
   obj1.free();
-  borderStyle = new AnnotBorderStyle(borderType, borderWidth,
+  border = new AnnotBorder(borderStyle, borderWidth,
       borderDash, borderDashLength,
       borderR, borderG, borderB);
 }
@@ -280,18 +573,48 @@
   valueObject.free();
 }
 
+double Annot::getXMin() {
+  return rect->x1;
+}
+
+double Annot::getYMin() {
+  return rect->y1;
+}
+  
 Annot::~Annot() {
-  if (type) {
-    delete type;
-  }
+  
+  delete rect;
+  
+  if (contents)
+    delete contents;
+  
+  if (pageDict)
+    delete pageDict;
+  
+  if(annotName)
+    delete annotName;
+  
+  if (modified)
+    delete modified;
+  
   appearance.free();
-  if (appearBuf) {
+  if(appearDict)
+    delete appearDict;
+  
+  if(appearState)
+    delete appearState;
+    
+  if (appearBuf)
     delete appearBuf;
-  }
-
-  if (borderStyle) {
-    delete borderStyle;
-  }
+  
+  if (border)
+    delete border;
+    
+  if (color)
+    delete color;
+    
+  if (optionalContent)
+    delete optionalContent;
 }
 
 void Annot::generateFieldAppearance(Dict *field, Dict *annot, Dict *acroForm) {
@@ -307,7 +630,7 @@
   GBool *selection;
   int dashLength, ff, quadding, comb, nOptions, topIdx, i, j;
   // must be a Widget annotation
-  if (type->cmp("Widget")) {
+  if (type == typeWidget) {
     return;
   }
   appearBuf = new GooString ();
@@ -323,7 +646,7 @@
         obj1.arrayGetLength() > 0) {
       setColor(obj1.getArray(), gTrue, 0);
       appearBuf->appendf("0 0 {0:.2f} {1:.2f} re f\n",
-          xMax - xMin, yMax - yMin);
+          rect->x2 - rect->x1, rect->y2 - rect->y1);
     }
     obj1.free();
   }
@@ -341,70 +664,70 @@
 
   // draw the border
   if (mkDict) {
-    w = borderStyle->getWidth();
+    w = border->getWidth();
     if (w > 0) {
       mkDict->lookup("BC", &obj1);
       if (!(obj1.isArray() && obj1.arrayGetLength() > 0)) {
         mkDict->lookup("BG", &obj1);
       }
       if (obj1.isArray() && obj1.arrayGetLength() > 0) {
-        dx = xMax - xMin;
-        dy = yMax - yMin;
+        dx = rect->x2 - rect->x1;
+        dy = rect->y2 - rect->y1;
 
         // radio buttons with no caption have a round border
         hasCaption = mkDict->lookup("CA", &obj2)->isString();
         obj2.free();
         if (ftObj.isName("Btn") && (ff & fieldFlagRadio) && !hasCaption) {
           r = 0.5 * (dx < dy ? dx : dy);
-          switch (borderStyle->getType()) {
-            case annotBorderDashed:
+          switch (border->getStyle()) {
+            case AnnotBorder::borderDashed:
               appearBuf->append("[");
-              borderStyle->getDash(&dash, &dashLength);
+              border->getDash(&dash, &dashLength);
               for (i = 0; i < dashLength; ++i) {
                 appearBuf->appendf(" {0:.2f}", dash[i]);
               }
               appearBuf->append("] 0 d\n");
               // fall through to the solid case
-            case annotBorderSolid:
-            case annotBorderUnderlined:
+            case AnnotBorder::borderSolid:
+            case AnnotBorder::borderUnderlined:
               appearBuf->appendf("{0:.2f} w\n", w);
               setColor(obj1.getArray(), gFalse, 0);
               drawCircle(0.5 * dx, 0.5 * dy, r - 0.5 * w, gFalse);
               break;
-            case annotBorderBeveled:
-            case annotBorderInset:
+            case AnnotBorder::borderBeveled:
+            case AnnotBorder::borderInset:
               appearBuf->appendf("{0:.2f} w\n", 0.5 * w);
               setColor(obj1.getArray(), gFalse, 0);
               drawCircle(0.5 * dx, 0.5 * dy, r - 0.25 * w, gFalse);
               setColor(obj1.getArray(), gFalse,
-                  borderStyle->getType() == annotBorderBeveled ? 1 : -1);
+                  border->getStyle() == AnnotBorder::borderBeveled ? 1 : -1);
               drawCircleTopLeft(0.5 * dx, 0.5 * dy, r - 0.75 * w);
               setColor(obj1.getArray(), gFalse,
-                  borderStyle->getType() == annotBorderBeveled ? -1 : 1);
+                  border->getStyle() == AnnotBorder::borderBeveled ? -1 : 1);
               drawCircleBottomRight(0.5 * dx, 0.5 * dy, r - 0.75 * w);
               break;
           }
 
         } else {
-          switch (borderStyle->getType()) {
-            case annotBorderDashed:
+          switch (border->getStyle()) {
+            case AnnotBorder::borderDashed:
               appearBuf->append("[");
-              borderStyle->getDash(&dash, &dashLength);
+              border->getDash(&dash, &dashLength);
               for (i = 0; i < dashLength; ++i) {
                 appearBuf->appendf(" {0:.2f}", dash[i]);
               }
               appearBuf->append("] 0 d\n");
               // fall through to the solid case
-            case annotBorderSolid:
+            case AnnotBorder::borderSolid:
               appearBuf->appendf("{0:.2f} w\n", w);
               setColor(obj1.getArray(), gFalse, 0);
               appearBuf->appendf("{0:.2f} {0:.2f} {1:.2f} {2:.2f} re s\n",
                   0.5 * w, dx - w, dy - w);
               break;
-            case annotBorderBeveled:
-            case annotBorderInset:
+            case AnnotBorder::borderBeveled:
+            case AnnotBorder::borderInset:
               setColor(obj1.getArray(), gTrue,
-                  borderStyle->getType() == annotBorderBeveled ? 1 : -1);
+                  border->getStyle() == AnnotBorder::borderBeveled ? 1 : -1);
               appearBuf->append("0 0 m\n");
               appearBuf->appendf("0 {0:.2f} l\n", dy);
               appearBuf->appendf("{0:.2f} {1:.2f} l\n", dx, dy);
@@ -413,7 +736,7 @@
               appearBuf->appendf("{0:.2f} {0:.2f} l\n", w);
               appearBuf->append("f\n");
               setColor(obj1.getArray(), gTrue,
-                  borderStyle->getType() == annotBorderBeveled ? -1 : 1);
+                  border->getStyle() == AnnotBorder::borderBeveled ? -1 : 1);
               appearBuf->append("0 0 m\n");
               appearBuf->appendf("{0:.2f} 0 l\n", dx);
               appearBuf->appendf("{0:.2f} {1:.2f} l\n", dx, dy);
@@ -422,7 +745,7 @@
               appearBuf->appendf("{0:.2f} {0:.2f} l\n", w);
               appearBuf->append("f\n");
               break;
-            case annotBorderUnderlined:
+            case AnnotBorder::borderUnderlined:
               appearBuf->appendf("{0:.2f} w\n", w);
               setColor(obj1.getArray(), gFalse, 0);
               appearBuf->appendf("0 0 m {0:.2f} 0 l s\n", dx);
@@ -484,8 +807,8 @@
             if (mkDict) {
               if (mkDict->lookup("BC", &obj3)->isArray() &&
                   obj3.arrayGetLength() > 0) {
-                dx = xMax - xMin;
-                dy = yMax - yMin;
+                dx = rect->x2 - rect->x1;
+                dy = rect->y2 - rect->y1;
                 setColor(obj3.getArray(), gTrue, 0);
                 drawCircle(0.5 * dx, 0.5 * dy, 0.2 * (dx < dy ? dx : dy),
                     gTrue);
@@ -634,8 +957,8 @@
   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));
+  obj1.arrayAdd(obj2.initReal(rect->x2 - rect->x1));
+  obj1.arrayAdd(obj2.initReal(rect->y2 - rect->y1));
   appearDict.dictAdd(copyString("BBox"), &obj1);
 
   // set the resource dictionary
@@ -755,7 +1078,7 @@
   GooList *daToks;
   GooString *tok;
   GfxFont *font;
-  double fontSize, fontSize2, border, x, xPrev, y, w, w2, wMax;
+  double fontSize, fontSize2, borderWidth, x, xPrev, y, w, w2, wMax;
   int tfPos, tmPos, i, j, k, c;
 
   //~ if there is no MK entry, this should use the existing content stream,
@@ -820,7 +1143,7 @@
   }
 
   // get the border width
-  border = borderStyle->getWidth();
+  borderWidth = border->getWidth();
 
   // setup
   if (txField) {
@@ -832,12 +1155,12 @@
   if (multiline) {
     // note: the comb flag is ignored in multiline mode
 
-    wMax = xMax - xMin - 2 * border - 4;
+    wMax = rect->x2 - rect->x1 - 2 * borderWidth - 4;
 
     // compute font autosize
     if (fontSize == 0) {
       for (fontSize = 20; fontSize > 1; --fontSize) {
-        y = yMax - yMin;
+        y = rect->y2 - rect->y1;
         w2 = 0;
         i = 0;
         while (i < text->getLength()) {
@@ -863,7 +1186,7 @@
     // starting y coordinate
     // (note: each line of text starts with a Td operator that moves
     // down a line)
-    y = yMax - yMin;
+    y = rect->y2 - rect->y1;
 
     // set the font matrix
     if (tmPos >= 0) {
@@ -898,13 +1221,13 @@
       switch (quadding) {
         case fieldQuadLeft:
         default:
-          x = border + 2;
+          x = borderWidth + 2;
           break;
         case fieldQuadCenter:
-          x = (xMax - xMin - w) / 2;
+          x = (rect->x2 - rect->x1 - w) / 2;
           break;
         case fieldQuadRight:
-          x = xMax - xMin - border - 2 - w;
+          x = rect->x2 - rect->x1 - borderWidth - 2 - w;
           break;
       }
 
@@ -926,11 +1249,11 @@
     // comb formatting
     if (comb > 0) {
       // compute comb spacing
-      w = (xMax - xMin - 2 * border) / comb;
+      w = (rect->x2 - rect->x1 - 2 * borderWidth) / comb;
 
       // compute font autosize
       if (fontSize == 0) {
-        fontSize = yMax - yMin - 2 * border;
+        fontSize = rect->y2 - rect->y1 - 2 * borderWidth;
         if (w < fontSize) {
           fontSize = w;
         }
@@ -946,16 +1269,16 @@
       switch (quadding) {
         case fieldQuadLeft:
         default:
-          x = border + 2;
+          x = borderWidth + 2;
           break;
         case fieldQuadCenter:
-          x = border + 2 + 0.5 * (comb - text->getLength()) * w;
+          x = borderWidth + 2 + 0.5 * (comb - text->getLength()) * w;
           break;
         case fieldQuadRight:
-          x = border + 2 + (comb - text->getLength()) * w;
+          x = borderWidth + 2 + (comb - text->getLength()) * w;
           break;
       }
-      y = 0.5 * (yMax - yMin) - 0.4 * fontSize;
+      y = 0.5 * (rect->y2 - rect->y1) - 0.4 * fontSize;
 
       // set the font matrix
       if (tmPos >= 0) {
@@ -1007,8 +1330,8 @@
 
       // compute font autosize
       if (fontSize == 0) {
-        fontSize = yMax - yMin - 2 * border;
-        fontSize2 = (xMax - xMin - 4 - 2 * border) / w;
+        fontSize = rect->y2 - rect->y1 - 2 * borderWidth;
+        fontSize2 = (rect->x2 - rect->x1 - 4 - 2 * borderWidth) / w;
         if (fontSize2 < fontSize) {
           fontSize = fontSize2;
         }
@@ -1025,16 +1348,16 @@
       switch (quadding) {
         case fieldQuadLeft:
         default:
-          x = border + 2;
+          x = borderWidth + 2;
           break;
         case fieldQuadCenter:
-          x = (xMax - xMin - w) / 2;
+          x = (rect->x2 - rect->x1 - w) / 2;
           break;
         case fieldQuadRight:
-          x = xMax - xMin - border - 2 - w;
+          x = rect->x2 - rect->x1 - borderWidth - 2 - w;
           break;
       }
-      y = 0.5 * (yMax - yMin) - 0.4 * fontSize;
+      y = 0.5 * (rect->y2 - rect->y1) - 0.4 * fontSize;
 
       // set the font matrix
       if (tmPos >= 0) {
@@ -1082,7 +1405,7 @@
   GooList *daToks;
   GooString *tok;
   GfxFont *font;
-  double fontSize, fontSize2, border, x, y, w, wMax;
+  double fontSize, fontSize2, borderWidth, x, y, w, wMax;
   int tfPos, tmPos, i, j, c;
 
   //~ if there is no MK entry, this should use the existing content stream,
@@ -1136,7 +1459,7 @@
   }
 
   // get the border width
-  border = borderStyle->getWidth();
+  borderWidth = border->getWidth();
 
   // compute font autosize
   if (fontSize == 0) {
@@ -1155,8 +1478,8 @@
         wMax = w;
       }
     }
-    fontSize = yMax - yMin - 2 * border;
-    fontSize2 = (xMax - xMin - 4 - 2 * border) / wMax;
+    fontSize = rect->y2 - rect->y1 - 2 * borderWidth;
+    fontSize2 = (rect->x2 - rect->x1 - 4 - 2 * borderWidth) / wMax;
     if (fontSize2 < fontSize) {
       fontSize = fontSize2;
     }
@@ -1168,7 +1491,7 @@
     }
   }
   // draw the text
-  y = yMax - yMin - 1.1 * fontSize;
+  y = rect->y2 - rect->y1 - 1.1 * fontSize;
   for (i = topIdx; i < nOptions; ++i) {
     // setup
     appearBuf->append("q\n");
@@ -1177,9 +1500,9 @@
     if (selection[i]) {
       appearBuf->append("0 g f\n");
       appearBuf->appendf("{0:.2f} {1:.2f} {2:.2f} {3:.2f} re f\n",
-          border,
+          borderWidth,
           y - 0.2 * fontSize,
-          xMax - xMin - 2 * border,
+          rect->x2 - rect->x1 - 2 * borderWidth,
           1.1 * fontSize);
     }
 
@@ -1202,13 +1525,13 @@
     switch (quadding) {
       case fieldQuadLeft:
       default:
-        x = border + 2;
+        x = borderWidth + 2;
         break;
       case fieldQuadCenter:
-        x = (xMax - xMin - w) / 2;
+        x = (rect->x2 - rect->x1 - w) / 2;
         break;
       case fieldQuadRight:
-        x = xMax - xMin - border - 2 - w;
+        x = rect->x2 - rect->x1 - borderWidth - 2 - w;
         break;
     }
 
@@ -1422,22 +1745,48 @@
   GBool isLink;
 
   // check the flags
-  if ((flags & annotFlagHidden) ||
-      (printing && !(flags & annotFlagPrint)) ||
-      (!printing && (flags & annotFlagNoView))) {
+  if ((flags & flagHidden) ||
+      (printing && !(flags & flagPrint)) ||
+      (!printing && (flags & flagNoView))) {
     return;
   }
 
   // draw the appearance stream
-  isLink = type && !type->cmp("Link");
+  isLink = type && !(type == typeLink);
   appearance.fetch(xref, &obj);
-  gfx->drawAnnot(&obj, isLink ? borderStyle : (AnnotBorderStyle *)NULL,
-      xMin, yMin, xMax, yMax);
+  gfx->drawAnnot(&obj, isLink ? border : (AnnotBorder *)NULL,
+      rect->x1, rect->y1, rect->x2, rect->y2);
   obj.free();
 }
 
 
 //------------------------------------------------------------------------
+// AnnotText
+//------------------------------------------------------------------------
+
+AnnotText::AnnotText(const Ref& ref, Dict* dict) : Annot(ref, dict) {
+  
+}
+
+
+//------------------------------------------------------------------------
+// AnnotLink
+//------------------------------------------------------------------------
+
+AnnotLink::AnnotLink(const Ref& ref, Dict* dict) : Annot(ref, dict) {
+
+}
+
+//------------------------------------------------------------------------
+// AnnotWidget
+//------------------------------------------------------------------------
+
+AnnotWidget::AnnotWidget(const Ref& ref, Dict* dict) : Annot(ref, dict) {
+
+}
+
+
+//------------------------------------------------------------------------
 // Annots
 //------------------------------------------------------------------------
 
@@ -1556,7 +1905,6 @@
   return NULL;
 }
 
-
 Annots::~Annots() {
   int i;
 
Index: poppler/Gfx.h
===================================================================
RCS file: /cvs/poppler/poppler/poppler/Gfx.h,v
retrieving revision 1.4
diff -u -r1.4 Gfx.h
--- poppler/Gfx.h	25 Apr 2007 19:59:10 -0000	1.4
+++ poppler/Gfx.h	27 Apr 2007 18:52:09 -0000
@@ -41,7 +41,7 @@
 class GfxColorSpace;
 class Gfx;
 class PDFRectangle;
-class AnnotBorderStyle;
+class AnnotBorder;
 
 //------------------------------------------------------------------------
 
@@ -128,7 +128,7 @@
 
   // Display an annotation, given its appearance (a Form XObject),
   // border style, and bounding box (in default user space).
-  void drawAnnot(Object *str, AnnotBorderStyle *borderStyle,
+  void drawAnnot(Object *str, AnnotBorder *border,
 		 double xMin, double yMin, double xMax, double yMax);
 
   // Save graphics state.
_______________________________________________
poppler mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/poppler

Reply via email to