[poppler] Annot Improving

Jeff Muizelaar jeff at infidigm.net
Mon Nov 5 18:37:24 PST 2007


On Sun, Nov 04, 2007 at 06:32:26PM +0100, Iñigo Martínez wrote:
> After some time very busy, I got a little time to work again, so I
> have started splitting the huge annotation patch. The idea is to
> implemente everything again slowly.
> 
> These first changes are about the implementation of the AnnotBorder.
> 
> Everything is changed using the official specification.
> 
> 1. There are two types of borders. The old one with Border flag and
> the new one with the BS flag. The border have only styles in the new
> border type, BS.
> 2. I have implemented both using inheritance.
> 3. Colors aren't part of the Border and BS border types, so I have
> taken them out and boxed in another class.
> 
> I have created a new patch, but i'm new to git, so i'm not sure if I
> have created it correctly.

It looks like it was created correctly.

> 
> (I have some tests done in the glib side, but they need the core to be
> more complete than it's actually).
> 
> In the old implementation I did in the summer, I was missing the
> saving feature, I need to implement the setters and I don't understand
> very well that side, so if anyone could help me...

Have you had a look at the saving code by Julien?
http://lists.freedesktop.org/archives/poppler/2007-October/003052.html

Some review follow below.

-Jeff


> diff --git a/poppler/Annot.cc b/poppler/Annot.cc
> index 2e09848..ed5f11f 100644
> --- a/poppler/Annot.cc
> +++ b/poppler/Annot.cc
> @@ -60,25 +60,190 @@
>  #define bezierCircle 0.55228475
>  
>  //------------------------------------------------------------------------
> -// AnnotBorderStyle
> +// AnnotBorder
>  //------------------------------------------------------------------------
> + 
> +AnnotBorder::~AnnotBorder() { 
> +  if (dash)
> +    gfree (dash); 
> +}
> +  
> +//------------------------------------------------------------------------
> +// AnnotBorderArray
> +//------------------------------------------------------------------------
> +
> +AnnotBorderArray::AnnotBorderArray() {
> +  horizontalCorner = 0;
> +  verticalCorner = 0;
> +  width = 1;
> +  dash = NULL;
> +  dashLength = 0;
> +}
> +
> +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();
> +}
>  
> -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;
> +//------------------------------------------------------------------------
> +// AnnotColor
> +//------------------------------------------------------------------------
> +
> +AnnotColor::AnnotColor() {
> +  length = 0;
> +  values = NULL;
>  }
>  
> -AnnotBorderStyle::~AnnotBorderStyle() {
> -  if (dash) {
> -    gfree(dash);
> +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);
>  }
>  
>  //------------------------------------------------------------------------
> @@ -99,11 +264,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;
> @@ -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) {
> @@ -219,105 +378,24 @@ 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);
>  }
>  
>  void Annot::readArrayNum(Object *pdfArray, int key, double *value) {
> @@ -342,9 +420,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) {
> @@ -410,7 +490,7 @@ 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)) {
> @@ -424,80 +504,84 @@ void Annot::generateFieldAppearance(Dict *field, Dict *annot, Dict *acroForm) {
>          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;

Won't the new code not draw a border unless a BS is specified? Whereas
the old code defaulted to a solid border?

Also, shouldn't the AnnotBorderArray class just have a getStyle()
method that returns borderSolid? That way we avoid having to do the
dynamic_cast. Currently there are no dynamic_casts in the core poppler
code. It'd be nice if we could keep it that way, unless there's good
reason to change.

> +          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);
> @@ -831,7 +915,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 +983,7 @@ void Annot::drawText(GooString *text, GooString *da, GfxFontDict *fontDict,
>    }
>  
>    // get the border width
> -  border = borderStyle->getWidth();
> +  borderWidth = border->getWidth();
>  
>    // setup
>    if (txField) {
> @@ -911,7 +995,7 @@ 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 = xMax - xMin - 2 * borderWidth - 4;
>  
>      // compute font autosize
>      if (fontSize == 0) {
> @@ -977,13 +1061,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;
>            break;
>          case fieldQuadRight:
> -          x = xMax - xMin - border - 2 - w;
> +          x = xMax - xMin - borderWidth - 2 - w;
>            break;
>        }
>  
> @@ -1005,11 +1089,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 = (xMax - xMin - 2 * borderWidth) / comb;
>  
>        // compute font autosize
>        if (fontSize == 0) {
> -        fontSize = yMax - yMin - 2 * border;
> +        fontSize = yMax - yMin - 2 * borderWidth;
>          if (w < fontSize) {
>            fontSize = w;
>          }
> @@ -1025,13 +1109,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 = 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;
> @@ -1086,8 +1170,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 = yMax - yMin - 2 * borderWidth;
> +        fontSize2 = (xMax - xMin - 4 - 2 * borderWidth) / w;
>          if (fontSize2 < fontSize) {
>            fontSize = fontSize2;
>          }
> @@ -1104,13 +1188,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;
>            break;
>          case fieldQuadRight:
> -          x = xMax - xMin - border - 2 - w;
> +          x = xMax - xMin - borderWidth - 2 - w;
>            break;
>        }
>        y = 0.5 * (yMax - yMin) - 0.4 * fontSize;
> @@ -1161,7 +1245,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 +1302,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 +1321,8 @@ void Annot::drawListBox(GooString **text, GBool *selection,
>          wMax = w;
>        }
>      }
> -    fontSize = yMax - yMin - 2 * border;
> -    fontSize2 = (xMax - xMin - 4 - 2 * border) / wMax;
> +    fontSize = yMax - yMin - 2 * borderWidth;
> +    fontSize2 = (xMax - xMin - 4 - 2 * borderWidth) / wMax;
>      if (fontSize2 < fontSize) {
>        fontSize = fontSize2;
>      }
> @@ -1259,9 +1343,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,
> +          xMax - xMin - 2 * borderWidth,
>            1.1 * fontSize);
>      }
>  
> @@ -1284,13 +1368,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;
>          break;
>        case fieldQuadRight:
> -        x = xMax - xMin - border - 2 - w;
> +        x = xMax - xMin - borderWidth - 2 - w;
>          break;
>      }
>  
> @@ -1494,7 +1578,7 @@ 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,
> +  gfx->drawAnnot(&obj, isLink ? border : (AnnotBorder *)NULL, color,
>        xMin, yMin, xMax, yMax);
>    obj.free();
>  }
> diff --git a/poppler/Annot.h b/poppler/Annot.h
> index 50f5bfb..470f73e 100644
> --- a/poppler/Annot.h
> +++ b/poppler/Annot.h
> @@ -22,39 +22,93 @@ class GfxFontDict;
>  class FormWidget;
>  
>  //------------------------------------------------------------------------
> -// 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)
> +};
> +
> +//------------------------------------------------------------------------
> +// AnnotBorderBS
> +//------------------------------------------------------------------------
>  
> -  AnnotBorderStyle(AnnotBorderType typeA, double widthA,
> -		   double *dashA, int dashLengthA,
> -		   double rA, double gA, double bA);
> -  ~AnnotBorderStyle();
> +class AnnotBorderBS: public AnnotBorder {
> +public:
>  
> -  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; }
> +  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)
> +};
> +
> +//------------------------------------------------------------------------
> +// AnnotColor
> +//------------------------------------------------------------------------
> +
> +class AnnotColor {
> +public:
>  
> -  AnnotBorderType type;
> -  double width;
> -  double *dash;
> -  int dashLength;
> -  double r, g, b;
> +  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,8 +129,6 @@ 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; }
>  
> @@ -88,6 +140,8 @@ public:
>    double getFontSize() { return fontSize; }
>  
>    GooString *getType() { return type; }
> +  AnnotBorder *getBorder() { return border; }
> +  AnnotColor *getColor() { return color; }
>  
>  private:
>    void setColor(Array *a, GBool fill, int adjust);
> @@ -120,7 +174,8 @@ private:
>    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