[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