-----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