[poppler] Annot Improving (II)
Jeff Muizelaar
jeff at infidigm.net
Mon Nov 5 18:21:55 PST 2007
On Tue, Nov 06, 2007 at 12:33:20AM +0100, Iñigo Martínez wrote:
> Here goes another patch related to Annot improvement. It's a simple
> cleaning. I have used PDFRectangle structure for Annotation rectangle.
>
> The changes in yesterdays patch are along with these changes too.
>
> Maybe I should split both changes too ?
Definitely. It makes it much easier to review. I'd suggest looking at
stgit for managing patch sets.
A bit of review follows.
-Jeff
> diff --git a/poppler/Annot.cc b/poppler/Annot.cc
> index 2e09848..c5a377e 100644
> --- a/poppler/Annot.cc
> +++ b/poppler/Annot.cc
> @@ -26,6 +26,7 @@
> #include "CharCodeToUnicode.h"
> #include "Form.h"
> #include "Error.h"
> +#include "Page.h"
>
> #define annotFlagHidden 0x0002
> #define annotFlagPrint 0x0004
> @@ -60,28 +61,193 @@
> #define bezierCircle 0.55228475
>
> //------------------------------------------------------------------------
> -// AnnotBorderStyle
> +// AnnotBorder
> +//------------------------------------------------------------------------
> +
> +AnnotBorder::~AnnotBorder() {
> + if (dash)
> + gfree (dash);
> +}
> +
> +//------------------------------------------------------------------------
> +// AnnotBorderArray
> //------------------------------------------------------------------------
>
> -AnnotBorderStyle::AnnotBorderStyle(AnnotBorderType typeA, double widthA,
> - double *dashA, int dashLengthA,
> - double rA, double gA, double bA) {
> - type = typeA;
> - width = widthA;
> - dash = dashA;
> - dashLength = dashLengthA;
> - r = rA;
> - g = gA;
> - b = bA;
> +AnnotBorderArray::AnnotBorderArray() {
> + horizontalCorner = 0;
> + verticalCorner = 0;
> + width = 1;
> + dash = NULL;
> + dashLength = 0;
> }
>
> -AnnotBorderStyle::~AnnotBorderStyle() {
> - if (dash) {
> - gfree(dash);
> +AnnotBorderArray::AnnotBorderArray(Array *array) {
> + Object obj1;
> + int arrayLength = array->getLength();
> +
> + if (arrayLength >= 3) {
> + if(array->get(0, &obj1)->isNum())
> + horizontalCorner = obj1.getNum();
> + obj1.free();
> +
> + if(array->get(1, &obj1)->isNum())
> + verticalCorner = obj1.getNum();
> + obj1.free();
> +
> + if(array->get(2, &obj1)->isNum())
> + width = obj1.getNum();
> + obj1.free();
> +
> + // TODO: check not all zero ?
> + if(arrayLength > 3) {
> + dashLength = array->getLength() - 3;
> + dash = (double *) gmallocn (dashLength, sizeof (double));
> +
> + for(int i = 0; i < dashLength && i < DASH_LIMIT; i++) {
> +
> + if(array->get((i + 3), &obj1)->isNum()) {
> + dash[i] = obj1.getNum();
> +
> + if (dash[i] < 0)
> + dash[i] = 0;
> +
> + } else {
> + dash[i] = 0;
> + }
> + obj1.free();
> + }
> + } else {
> + dashLength = 0;
> + dash = NULL;
> + }
> + } else {
> + horizontalCorner = 0;
> + verticalCorner = 0;
> + width = 1;
> + dash = NULL;
> + dashLength = 0;
> }
> }
>
> //------------------------------------------------------------------------
> +// AnnotBorderBS
> +//------------------------------------------------------------------------
> +
> +AnnotBorderBS::AnnotBorderBS() {
> + style = borderSolid;
> + width = 1;
> + dash = NULL;
> + dashLength = 0;
> +}
> +
> +AnnotBorderBS::AnnotBorderBS(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;
> + } else if(!styleName->cmp("Dashed")) {
> + style = borderDashed;
> + } else if(!styleName->cmp("Beveled")) {
> + style = borderBeveled;
> + } else if(!styleName->cmp("Inset")) {
> + style = borderInset;
> + } else if(!styleName->cmp("Underlined")) {
> + style = borderUnderlined;
> + } else {
> + style = borderSolid;
> + }
> + delete styleName;
> + } else {
> + style = borderSolid;
> + }
> + obj1.free();
> +
> + // TODO: check not all zero ?
> + if (dict->lookup("D", &obj1)->isArray()) {
> + dashLength = obj1.arrayGetLength();
> + dash = (double *) gmallocn (dashLength, sizeof (double));
> +
> + for(int i = 0; i < dashLength; i++) {
> + Object obj2;
> +
> + if(obj1.arrayGet(i, &obj2)->isNum()) {
> + dash[i] = obj2.getNum();
> +
> + if(dash[i] < 0)
> + dash[i] = 0;
> + } else {
> + dash[i] = 0;
> + }
> + obj2.free();
> + }
> + } else {
> + dashLength = 1;
> + dash = (double *) gmallocn (dashLength, sizeof (double));
> + dash[0] = 3;
> + }
> + obj1.free();
> +}
> +
> +//------------------------------------------------------------------------
> +// AnnotColor
> +//------------------------------------------------------------------------
> +
> +AnnotColor::AnnotColor() {
> + length = 0;
> + values = NULL;
> +}
> +
> +AnnotColor::AnnotColor(Array *array) {
> + if (array->getLength() < 5) {
> + length = array->getLength();
> + values = (double *) gmallocn (length, sizeof(double));
> +
> + for(int i = 0; i < length; i++) {
> + Object obj1;
> +
> + if(array->get(i, &obj1)->isNum()) {
> + values[i] = obj1.getNum();
> +
> + if (values[i] < 0 || values[i] > 1)
> + values[i] = 0;
> + } else {
> + values[i] = 0;
> + }
> + obj1.free();
> + }
> + } else {
> + length = 0;
> + values = NULL;
> + }
> +
> +}
> +
> +AnnotColor::AnnotColorSpace AnnotColor::getSpace() {
> + return (AnnotColor::AnnotColorSpace) length;
> +}
> +
> +double AnnotColor::getValue(int i) {
> + if(i >= 0 && i < length)
> + return values[i];
> + return 0;
> +}
> +
> +AnnotColor::~AnnotColor() {
> + if(values)
> + gfree (values);
> +}
> +
> +//------------------------------------------------------------------------
> // Annot
> //------------------------------------------------------------------------
>
> @@ -99,12 +265,6 @@ Annot::Annot(XRef *xrefA, Dict *acroForm, Dict *dict, Catalog* catalog) {
>
> void Annot::initialize(XRef *xrefA, Dict *acroForm, Dict *dict, Catalog *catalog) {
> Object apObj, asObj, obj1, obj2, obj3;
> - AnnotBorderType borderType;
> - double borderWidth;
> - double *borderDash;
> - int borderDashLength;
> - double borderR, borderG, borderB;
> - double t;
>
> ok = gTrue;
> xref = xrefA;
> @@ -112,7 +272,6 @@ void Annot::initialize(XRef *xrefA, Dict *acroForm, Dict *dict, Catalog *catalog
> fontSize = 0;
> type = NULL;
> widget = NULL;
> - borderStyle = NULL;
>
> //----- get the FormWidget
> if (hasRef) {
> @@ -129,29 +288,32 @@ void Annot::initialize(XRef *xrefA, Dict *acroForm, Dict *dict, Catalog *catalog
> obj1.free();
>
> //----- parse the rectangle
> + rect = new PDFRectangle();
> + if (dict->lookup("Rect", &obj1)->isArray() && obj1.arrayGetLength() == 4) {
> + Object obj2;
> + (obj1.arrayGet(0, &obj2)->isNum() ? rect->x1 = obj2.getNum() : rect->x1 = 0);
> + obj2.free();
> + (obj1.arrayGet(1, &obj2)->isNum() ? rect->y1 = obj2.getNum() : rect->y1 = 0);
> + obj2.free();
> + (obj1.arrayGet(2, &obj2)->isNum() ? rect->x2 = obj2.getNum() : rect->x2 = 1);
> + obj2.free();
> + (obj1.arrayGet(3, &obj2)->isNum() ? rect->y2 = obj2.getNum() : rect->y2 = 1);
> + obj2.free();
The old code defaults to xMax and yMax of 0. Why the change to 1?
>
> - 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);
> - if (ok) {
> - if (xMin > xMax) {
> - t = xMin; xMin = xMax; xMax = t;
> - }
> - if (yMin > yMax) {
> - t = yMin; yMin = yMax; yMax = t;
> - }
> - } else {
> - xMin = yMin = 0;
> - xMax = yMax = 1;
> - error(-1, "Bad bounding box for annotation");
> - ok = gFalse;
> + if (rect->x1 > rect->x2) {
> + double t = rect->x1;
> + rect->x1 = rect->x2;
> + rect->x2 = t;
> + }
> +
> + if (rect->y1 > rect->y2) {
> + double 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;
> }
> @@ -219,105 +381,32 @@ void Annot::initialize(XRef *xrefA, Dict *acroForm, Dict *dict, Catalog *catalog
> apObj.free();
> obj3.free();
>
> - //----- parse the border style
> -
> - borderType = 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 = annotBorderSolid;
> - } else if (obj2.isName("D")) {
> - borderType = annotBorderDashed;
> - } else if (obj2.isName("B")) {
> - borderType = annotBorderBeveled;
> - } else if (obj2.isName("I")) {
> - borderType = annotBorderInset;
> - } else if (obj2.isName("U")) {
> - borderType = annotBorderUnderlined;
> - }
> - }
> - if (obj1.dictLookup("W", &obj3)->isNum()) {
> - borderWidth = obj3.getNum();
> - }
> - // acroread 8 seems to need both W and S entries for
> - // any border to be drawn, even though the spec
> - // doesn't claim anything of that sort. We follow
> - // that behaviour by veryifying both entries exist
> - // otherwise we set the borderWidth to 0
> - // --jrmuizel
> - if (!obj2.isName() || !obj3.isNum()) {
> - borderWidth = 0;
> - }
> - obj3.free();
> - 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();
> + border = new AnnotBorderBS(obj1.getDict());
> } 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 = 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;
> - }
> - }
> - }
> - }
> - obj1.free();
> +
> + if (dict->lookup("Border", &obj1)->isArray())
> + border = new AnnotBorderArray(obj1.getArray());
> + else
> + border = new AnnotBorderArray();
> }
> - 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();
> +
> + if (dict->lookup("C", &obj1)->isArray()) {
> + color = new AnnotColor(obj1.getArray());
> + } else {
> + color = NULL;
> }
> obj1.free();
> - borderStyle = new AnnotBorderStyle(borderType, borderWidth,
> - borderDash, borderDashLength,
> - borderR, borderG, borderB);
> +}
> +
> +double Annot::getXMin() {
> + return rect->x1;
> +}
> +
> +double Annot::getYMin() {
> + return rect->y1;
> }
>
> void Annot::readArrayNum(Object *pdfArray, int key, double *value) {
> @@ -342,9 +431,11 @@ Annot::~Annot() {
> delete appearBuf;
> }
>
> - if (borderStyle) {
> - delete borderStyle;
> - }
> + if (border)
> + delete border;
> +
> + if (color)
> + delete color;
> }
>
> void Annot::generateFieldAppearance(Dict *field, Dict *annot, Dict *acroForm) {
> @@ -392,7 +483,7 @@ void Annot::generateFieldAppearance(Dict *field, Dict *annot, Dict *acroForm) {
> 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();
> }
> @@ -410,94 +501,98 @@ void Annot::generateFieldAppearance(Dict *field, Dict *annot, Dict *acroForm) {
>
> // 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:
> - appearBuf->append("[");
> - borderStyle->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:
> - 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:
> - 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);
> - drawCircleTopLeft(0.5 * dx, 0.5 * dy, r - 0.75 * w);
> - setColor(obj1.getArray(), gFalse,
> - borderStyle->getType() == annotBorderBeveled ? -1 : 1);
> - drawCircleBottomRight(0.5 * dx, 0.5 * dy, r - 0.75 * w);
> - break;
> + AnnotBorderBS *borderBS = dynamic_cast<AnnotBorderBS *> (border);
> + if (borderBS) {
> + r = 0.5 * (dx < dy ? dx : dy);
> + switch (borderBS->getStyle()) {
> + case AnnotBorderBS::borderDashed:
> + appearBuf->append("[");
> + dashLength = border->getDashLength();
> + dash = border->getDash();
> + for (i = 0; i < dashLength; ++i)
> + appearBuf->appendf(" {0:.2f}", dash[i]);
> + appearBuf->append("] 0 d\n");
> + // fall through to the solid case
> + case AnnotBorderBS::borderSolid:
> + case AnnotBorderBS::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 AnnotBorderBS::borderBeveled:
> + case AnnotBorderBS::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, borderBS->getStyle()
> + == AnnotBorderBS::borderBeveled ? 1 : -1);
> + drawCircleTopLeft(0.5 * dx, 0.5 * dy, r - 0.75 * w);
> + setColor(obj1.getArray(), gFalse, borderBS->getStyle()
> + == AnnotBorderBS::borderBeveled ? -1 : 1);
> + drawCircleBottomRight(0.5 * dx, 0.5 * dy, r - 0.75 * w);
> + break;
> + }
> }
> -
> } else {
> - switch (borderStyle->getType()) {
> - case annotBorderDashed:
> - appearBuf->append("[");
> - borderStyle->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:
> - 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:
> - setColor(obj1.getArray(), gTrue,
> - borderStyle->getType() == annotBorderBeveled ? 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);
> - appearBuf->appendf("{0:.2f} {1:.2f} l\n", dx - w, dy - w);
> - appearBuf->appendf("{0:.2f} {1:.2f} l\n", w, dy - w);
> - appearBuf->appendf("{0:.2f} {0:.2f} l\n", w);
> - appearBuf->append("f\n");
> - setColor(obj1.getArray(), gTrue,
> - borderStyle->getType() == annotBorderBeveled ? -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);
> - appearBuf->appendf("{0:.2f} {1:.2f} l\n", dx - w, dy - w);
> - appearBuf->appendf("{0:.2f} {1:.2f} l\n", dx - w, w);
> - appearBuf->appendf("{0:.2f} {0:.2f} l\n", w);
> - appearBuf->append("f\n");
> - break;
> - case annotBorderUnderlined:
> - appearBuf->appendf("{0:.2f} w\n", w);
> - setColor(obj1.getArray(), gFalse, 0);
> - appearBuf->appendf("0 0 m {0:.2f} 0 l s\n", dx);
> - break;
> + AnnotBorderBS *borderBS = dynamic_cast<AnnotBorderBS *> (border);
> + if(borderBS) {
> + switch (borderBS->getStyle()) {
> + case AnnotBorderBS::borderDashed:
> + appearBuf->append("[");
> + dashLength = border->getDashLength();
> + dash = border->getDash();
> + for (i = 0; i < dashLength; ++i)
> + appearBuf->appendf(" {0:.2f}", dash[i]);
> + appearBuf->append("] 0 d\n");
> + // fall through to the solid case
> + case AnnotBorderBS::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 AnnotBorderBS::borderBeveled:
> + case AnnotBorderBS::borderInset:
> + setColor(obj1.getArray(), gTrue, borderBS->getStyle()
> + == AnnotBorderBS::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);
> + appearBuf->appendf("{0:.2f} {1:.2f} l\n", dx - w, dy - w);
> + appearBuf->appendf("{0:.2f} {1:.2f} l\n", w, dy - w);
> + appearBuf->appendf("{0:.2f} {0:.2f} l\n", w);
> + appearBuf->append("f\n");
> + setColor(obj1.getArray(), gTrue, borderBS->getStyle()
> + == AnnotBorderBS::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);
> + appearBuf->appendf("{0:.2f} {1:.2f} l\n", dx - w, dy - w);
> + appearBuf->appendf("{0:.2f} {1:.2f} l\n", dx - w, w);
> + appearBuf->appendf("{0:.2f} {0:.2f} l\n", w);
> + appearBuf->append("f\n");
> + break;
> + case AnnotBorderBS::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);
> + break;
> + }
> }
> -
> // clip to the inside of the border
> appearBuf->appendf("{0:.2f} {0:.2f} {1:.2f} {2:.2f} re W n\n",
> w, dx - 2 * w, dy - 2 * w);
> @@ -554,8 +649,8 @@ void Annot::generateFieldAppearance(Dict *field, Dict *annot, Dict *acroForm) {
> 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);
> @@ -704,8 +799,8 @@ void Annot::generateFieldAppearance(Dict *field, Dict *annot, Dict *acroForm) {
> 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
> @@ -831,7 +926,7 @@ void Annot::drawText(GooString *text, GooString *da, GfxFontDict *fontDict,
> 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;
>
> //~ if there is no MK entry, this should use the existing content stream,
> @@ -899,7 +994,7 @@ void Annot::drawText(GooString *text, GooString *da, GfxFontDict *fontDict,
> }
>
> // get the border width
> - border = borderStyle->getWidth();
> + borderWidth = border->getWidth();
>
> // setup
> if (txField) {
> @@ -911,12 +1006,12 @@ void Annot::drawText(GooString *text, GooString *da, GfxFontDict *fontDict,
> 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()) {
> @@ -942,7 +1037,7 @@ void Annot::drawText(GooString *text, GooString *da, GfxFontDict *fontDict,
> // 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) {
> @@ -977,13 +1072,13 @@ void Annot::drawText(GooString *text, GooString *da, GfxFontDict *fontDict,
> 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;
> }
>
> @@ -1005,11 +1100,11 @@ void Annot::drawText(GooString *text, GooString *da, GfxFontDict *fontDict,
> // 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;
> }
> @@ -1025,16 +1120,16 @@ void Annot::drawText(GooString *text, GooString *da, GfxFontDict *fontDict,
> 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) {
> @@ -1086,8 +1181,8 @@ void Annot::drawText(GooString *text, GooString *da, GfxFontDict *fontDict,
>
> // 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;
> }
> @@ -1104,16 +1199,16 @@ void Annot::drawText(GooString *text, GooString *da, GfxFontDict *fontDict,
> 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) {
> @@ -1161,7 +1256,7 @@ void Annot::drawListBox(GooString **text, GBool *selection,
> 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;
>
> //~ if there is no MK entry, this should use the existing content stream,
> @@ -1218,7 +1313,7 @@ void Annot::drawListBox(GooString **text, GBool *selection,
> }
>
> // get the border width
> - border = borderStyle->getWidth();
> + borderWidth = border->getWidth();
>
> // compute font autosize
> if (fontSize == 0) {
> @@ -1237,8 +1332,8 @@ void Annot::drawListBox(GooString **text, GBool *selection,
> 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;
> }
> @@ -1250,7 +1345,7 @@ void Annot::drawListBox(GooString **text, GBool *selection,
> }
> }
> // 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");
> @@ -1259,9 +1354,9 @@ void Annot::drawListBox(GooString **text, GBool *selection,
> 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);
> }
>
> @@ -1284,13 +1379,13 @@ void Annot::drawListBox(GooString **text, GBool *selection,
> 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;
> }
>
> @@ -1494,8 +1589,8 @@ void Annot::draw(Gfx *gfx, GBool printing) {
> // draw the appearance stream
> isLink = type && !type->cmp("Link");
> appearance.fetch(xref, &obj);
> - gfx->drawAnnot(&obj, isLink ? borderStyle : (AnnotBorderStyle *)NULL,
> - xMin, yMin, xMax, yMax);
> + gfx->drawAnnot(&obj, isLink ? border : (AnnotBorder *)NULL, color,
> + rect->x1, rect->y1, rect->x2, rect->y2);
> obj.free();
> }
>
> diff --git a/poppler/Annot.h b/poppler/Annot.h
> index 50f5bfb..7e75f6a 100644
> --- a/poppler/Annot.h
> +++ b/poppler/Annot.h
> @@ -20,41 +20,96 @@ class CharCodeToUnicode;
> class GfxFont;
> class GfxFontDict;
> class FormWidget;
> +class PDFRectangle;
>
> //------------------------------------------------------------------------
> -// AnnotBorderStyle
> +// AnnotBorder
> //------------------------------------------------------------------------
>
> -enum AnnotBorderType {
> - annotBorderSolid,
> - annotBorderDashed,
> - annotBorderBeveled,
> - annotBorderInset,
> - annotBorderUnderlined
> +class AnnotBorder {
> +public:
> + virtual ~AnnotBorder();
> +
> + virtual double getWidth() { return width; }
> + virtual int getDashLength() { return dashLength; }
> + virtual double *getDash() { return dash; }
> +
> +protected:
> + double width;
> + double *dash;
> + int dashLength;
> };
>
> -class AnnotBorderStyle {
> +//------------------------------------------------------------------------
> +// AnnotBorderArray
> +//------------------------------------------------------------------------
> +
> +class AnnotBorderArray: public AnnotBorder {
> public:
> + AnnotBorderArray();
> + AnnotBorderArray(Array *array);
> +
> + virtual double getHorizontalCorner() { return horizontalCorner; }
> + virtual double getVerticalCorner() { return verticalCorner; }
> +
> +protected:
> + static const int DASH_LIMIT = 10; // implementation note 82 in Appendix H.
> + double horizontalCorner; // (Default 0)
> + double verticalCorner; // (Default 0)
> + // double width; // (Default 1) (inherited from AnnotBorder)
> +};
>
> - AnnotBorderStyle(AnnotBorderType typeA, double widthA,
> - double *dashA, int dashLengthA,
> - double rA, double gA, double bA);
> - ~AnnotBorderStyle();
> +//------------------------------------------------------------------------
> +// AnnotBorderBS
> +//------------------------------------------------------------------------
>
> - AnnotBorderType getType() { return type; }
> - double getWidth() { return width; }
> - void getDash(double **dashA, int *dashLengthA)
> - { *dashA = dash; *dashLengthA = dashLength; }
> - void getColor(double *rA, double *gA, double *bA)
> - { *rA = r; *gA = g; *bA = b; }
> +class AnnotBorderBS: public AnnotBorder {
> +public:
> +
> + enum AnnotBorderStyle {
> + borderSolid, // Solid
> + borderDashed, // Dashed
> + borderBeveled, // Beveled
> + borderInset, // Inset
> + borderUnderlined, // Underlined
> + };
> +
> + AnnotBorderBS();
> + AnnotBorderBS(Dict *dict);
> +
> + AnnotBorderStyle getStyle() { return style; }
>
> private:
> + // double width; // W (Default 1) (inherited from AnnotBorder)
> + AnnotBorderStyle style; // S
> + // double *dash; // D (Default [3]) (inherited from AnnotBorder)
> +};
>
> - AnnotBorderType type;
> - double width;
> - double *dash;
> - int dashLength;
> - double r, g, b;
> +//------------------------------------------------------------------------
> +// AnnotColor
> +//------------------------------------------------------------------------
> +
> +class AnnotColor {
> +public:
> +
> + enum AnnotColorSpace {
> + colorTransparent = 0,
> + colorGray = 1,
> + colorRGB = 3,
> + colorCMYK = 4
> + };
> +
> + AnnotColor();
> + AnnotColor(Array *array);
> + ~AnnotColor();
> +
> + AnnotColorSpace getSpace();
> + double getValue(int i);
> +
> +private:
> +
> + double *values;
> + int length;
> };
>
> //------------------------------------------------------------------------
> @@ -75,19 +130,20 @@ public:
> 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; }
>
> GooString *getType() { return type; }
> + PDFRectangle *getRect() { return rect; }
> + AnnotBorder *getBorder() { return border; }
> + AnnotColor *getColor() { return color; }
>
> private:
> void setColor(Array *a, GBool fill, int adjust);
> @@ -110,6 +166,9 @@ private:
>
> void initialize (XRef *xrefA, Dict *acroForm, Dict *dict, Catalog *catalog);
>
> + // required data
> + PDFRectangle *rect; // Rect
> +
> XRef *xref; // the xref table for this PDF file
> Ref ref; // object ref identifying this annotation
> FormWidget *widget; // FormWidget object for this annotation
> @@ -118,9 +177,9 @@ private:
> // for the normal appearance
> GooString *appearBuf;
> Guint flags;
> - double xMin, yMin, // annotation rectangle
> - xMax, yMax;
> - AnnotBorderStyle *borderStyle;
> +
> + AnnotBorder *border; // Border, BS
> + AnnotColor *color; // C
> double fontSize;
> GBool ok;
> GBool regen, isTextField;
> diff --git a/poppler/Gfx.cc b/poppler/Gfx.cc
> index 37c279e..8aeab7e 100644
> --- a/poppler/Gfx.cc
> +++ b/poppler/Gfx.cc
> @@ -4046,8 +4046,9 @@ void Gfx::opMarkPoint(Object args[], int numArgs) {
> // misc
> //------------------------------------------------------------------------
>
> -void Gfx::drawAnnot(Object *str, AnnotBorderStyle *borderStyle,
> +void Gfx::drawAnnot(Object *str, AnnotBorder *border, AnnotColor *aColor,
> double xMin, double yMin, double xMax, double yMax) {
> + AnnotBorderBS *borderBS;
> Dict *dict, *resDict;
> Object matrixObj, bboxObj, resObj;
> Object obj1;
> @@ -4168,13 +4169,19 @@ void Gfx::drawAnnot(Object *str, AnnotBorderStyle *borderStyle,
> }
>
> // 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);
> + if (aColor && (aColor->getSpace() == AnnotColor::colorRGB)) {
> + r = aColor->getValue(0);
> + g = aColor->getValue(1);
> + b = aColor->getValue(2);
> + } else {
> + r = g = b = 0;
> + };
> color.c[0] = dblToCol(r);
> color.c[1] = dblToCol(g);
> color.c[2] = dblToCol(b);
> @@ -4187,10 +4194,13 @@ void Gfx::drawAnnot(Object *str, AnnotBorderStyle *borderStyle,
> 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) {
> + dashLength = border->getDashLength();
> + dash = border->getDash();
> + borderBS = dynamic_cast<AnnotBorderBS*> (border);
> + if (borderBS && (borderBS->getStyle()
> + == AnnotBorderBS::borderDashed) && (dashLength > 0)) {
> dash2 = (double *)gmallocn(dashLength, sizeof(double));
> for (i = 0; i < dashLength; ++i) {
> dash2[i] = x * dash[i];
> @@ -4202,7 +4212,7 @@ void Gfx::drawAnnot(Object *str, AnnotBorderStyle *borderStyle,
> state->clearPath();
> state->moveTo(annotX0, out->upsideDown() ? annotY1 : annotY0);
> state->lineTo(annotX1, out->upsideDown() ? annotY1 : annotY0);
> - if (borderStyle->getType() != annotBorderUnderlined) {
> + if (borderBS && (borderBS->getStyle() != AnnotBorderBS::borderUnderlined)) {
> state->lineTo(annotX1, out->upsideDown() ? annotY0 : annotY1);
> state->lineTo(annotX0, out->upsideDown() ? annotY0 : annotY1);
> state->closePath();
> diff --git a/poppler/Gfx.h b/poppler/Gfx.h
> index 28d8a3d..b08b35d 100644
> --- a/poppler/Gfx.h
> +++ b/poppler/Gfx.h
> @@ -41,7 +41,9 @@ struct GfxColor;
> class GfxColorSpace;
> class Gfx;
> class PDFRectangle;
> -class AnnotBorderStyle;
> +class Annot;
> +class AnnotBorder;
> +class AnnotColor;
>
> //------------------------------------------------------------------------
>
> @@ -128,7 +130,7 @@ public:
>
> // 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, AnnotColor *aColor,
> double xMin, double yMin, double xMax, double yMax);
>
> // Save graphics state.
> diff --git a/poppler/poppler-config.h.in b/poppler/poppler-config.h.in
> _______________________________________________
> poppler mailing list
> poppler at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/poppler
More information about the poppler
mailing list