[poppler] Branch 'xpdf303merge' - poppler/Gfx.cc

Carlos Garcia Campos carlosgc at kemper.freedesktop.org
Sun Sep 4 04:57:41 PDT 2011


 poppler/Gfx.cc |  143 +++++++++++++++++++++++++++++----------------------------
 1 file changed, 75 insertions(+), 68 deletions(-)

New commits:
commit f7d307b818bca9553a05b5d43deb429abbf04824
Author: Carlos Garcia Campos <carlosgc at gnome.org>
Date:   Sun Sep 4 13:56:35 2011 +0200

    xpdf303: Rewrote the code that handles annotation transforms
    
    It was not handling non-rectangular transforms correctly.

diff --git a/poppler/Gfx.cc b/poppler/Gfx.cc
index 11c86c9..eb5dac4 100644
--- a/poppler/Gfx.cc
+++ b/poppler/Gfx.cc
@@ -4863,45 +4863,23 @@ void Gfx::opMarkPoint(Object args[], int numArgs) {
 void Gfx::drawAnnot(Object *str, AnnotBorder *border, AnnotColor *aColor,
 		    double xMin, double yMin, double xMax, double yMax) {
   Dict *dict, *resDict;
-  Object matrixObj, bboxObj, resObj;
-  Object obj1;
-  double m[6], bbox[4], ictm[6];
-  double *ctm;
-  double formX0, formY0, formX1, formY1;
-  double annotX0, annotY0, annotX1, annotY1;
-  double det, x, y, sx, sy;
+  Object matrixObj, bboxObj, resObj, obj1;
+  double formXMin, formYMin, formXMax, formYMax;
+  double x, y, sx, sy, tx, ty;
+  double m[6], bbox[4];
   double r, g, b;
   GfxColor color;
   double *dash, *dash2;
   int dashLength;
   int i;
 
-  //~ can we assume that we're in default user space?
-  //~ (i.e., baseMatrix = ctm)
+  // this function assumes that we are in the default user space,
+  // i.e., baseMatrix = ctm
 
-  // transform the annotation bbox from default user space to user
-  // space: (bbox * baseMatrix) * iCTM
-  ctm = state->getCTM();
-  det = 1 / (ctm[0] * ctm[3] - ctm[1] * ctm[2]);
-  ictm[0] = ctm[3] * det;
-  ictm[1] = -ctm[1] * det;
-  ictm[2] = -ctm[2] * det;
-  ictm[3] = ctm[0] * det;
-  ictm[4] = (ctm[2] * ctm[5] - ctm[3] * ctm[4]) * det;
-  ictm[5] = (ctm[1] * ctm[4] - ctm[0] * ctm[5]) * det;
-  x = baseMatrix[0] * xMin + baseMatrix[2] * yMin + baseMatrix[4];
-  y = baseMatrix[1] * xMin + baseMatrix[3] * yMin + baseMatrix[5];
-  annotX0 = ictm[0] * x + ictm[2] * y + ictm[4];
-  annotY0 = ictm[1] * x + ictm[3] * y + ictm[5];
-  x = baseMatrix[0] * xMax + baseMatrix[2] * yMax + baseMatrix[4];
-  y = baseMatrix[1] * xMax + baseMatrix[3] * yMax + baseMatrix[5];
-  annotX1 = ictm[0] * x + ictm[2] * y + ictm[4];
-  annotY1 = ictm[1] * x + ictm[3] * y + ictm[5];
-  if (annotX0 > annotX1) {
-    x = annotX0; annotX0 = annotX1; annotX1 = x;
-  }
-  if (annotY0 > annotY1) {
-    y = annotY0; annotY0 = annotY1; annotY1 = y;
+  // if the bounding box has zero width or height, don't draw anything
+  // at all
+  if (xMin == xMax || yMin == yMax) {
+    return;
   }
 
   // draw the appearance stream (if there is one)
@@ -4945,39 +4923,77 @@ void Gfx::drawAnnot(Object *str, AnnotBorder *border, AnnotColor *aColor,
     }
     matrixObj.free();
 
-    // transform the form bbox from form space to user space
-    formX0 = bbox[0] * m[0] + bbox[1] * m[2] + m[4];
-    formY0 = bbox[0] * m[1] + bbox[1] * m[3] + m[5];
-    formX1 = bbox[2] * m[0] + bbox[3] * m[2] + m[4];
-    formY1 = bbox[2] * m[1] + bbox[3] * m[3] + m[5];
-    if (formX0 > formX1) {
-      x = formX0; formX0 = formX1; formX1 = x;
-    }
-    if (formY0 > formY1) {
-      y = formY0; formY0 = formY1; formY1 = y;
-    }
-
-    // scale the form to fit the annotation bbox
-    if (formX1 == formX0) {
+    // transform the four corners of the form bbox to default user
+    // space, and construct the transformed bbox
+    x = bbox[0] * m[0] + bbox[1] * m[2] + m[4];
+    y = bbox[0] * m[1] + bbox[1] * m[3] + m[5];
+    formXMin = formXMax = x;
+    formYMin = formYMax = y;
+    x = bbox[0] * m[0] + bbox[3] * m[2] + m[4];
+    y = bbox[0] * m[1] + bbox[3] * m[3] + m[5];
+    if (x < formXMin) {
+      formXMin = x;
+    } else if (x > formXMax) {
+      formXMax = x;
+    }
+    if (y < formYMin) {
+      formYMin = y;
+    } else if (y > formYMax) {
+      formYMax = y;
+    }
+    x = bbox[2] * m[0] + bbox[1] * m[2] + m[4];
+    y = bbox[2] * m[1] + bbox[1] * m[3] + m[5];
+    if (x < formXMin) {
+      formXMin = x;
+    } else if (x > formXMax) {
+      formXMax = x;
+    }
+    if (y < formYMin) {
+      formYMin = y;
+    } else if (y > formYMax) {
+      formYMax = y;
+    }
+    x = bbox[2] * m[0] + bbox[3] * m[2] + m[4];
+    y = bbox[2] * m[1] + bbox[3] * m[3] + m[5];
+    if (x < formXMin) {
+      formXMin = x;
+    } else if (x > formXMax) {
+      formXMax = x;
+    }
+    if (y < formYMin) {
+      formYMin = y;
+    } else if (y > formYMax) {
+      formYMax = y;
+    }
+
+    // construct a mapping matrix, [sx 0  0], which maps the transformed
+    //                             [0  sy 0]
+    //                             [tx ty 1]
+    // bbox to the annotation rectangle
+    if (formXMin == formXMax) {
       // this shouldn't happen
       sx = 1;
     } else {
-      sx = (annotX1 - annotX0) / (formX1 - formX0);
+      sx = (xMax - xMin) / (formXMax - formXMin);
     }
-    if (formY1 == formY0) {
+    if (formYMin == formYMax) {
       // this shouldn't happen
       sy = 1;
     } else {
-      sy = (annotY1 - annotY0) / (formY1 - formY0);
+      sy = (yMax - yMin) / (formYMax - formYMin);
     }
+    tx = -formXMin * sx + xMin;
+    ty = -formYMin * sy + yMin;
+
+    // the final transform matrix is (form matrix) * (mapping matrix)
     m[0] *= sx;
-    m[2] *= sx;
-    m[4] = (m[4] - formX0) * sx + annotX0;
     m[1] *= sy;
+    m[2] *= sx;
     m[3] *= sy;
-    m[5] = (m[5] - formY0) * sy + annotY0;
+    m[4] = m[4] * sx + tx;
+    m[5] = m[5] * sy + ty;
 
-    // get resources
+    // get the resources
     dict->lookup("Resources", &resObj);
     resDict = resObj.isDict() ? resObj.getDict() : (Dict *)NULL;
 
@@ -5007,32 +5023,23 @@ void Gfx::drawAnnot(Object *str, AnnotBorder *border, AnnotColor *aColor,
     color.c[2] = dblToCol(b);
     state->setStrokeColor(&color);
     out->updateStrokeColor(state);
-    // compute the width scale factor when going from default user
-    // space to user space
-    x = (baseMatrix[0] + baseMatrix[2]) * ictm[0] +
-        (baseMatrix[1] + baseMatrix[3]) * ictm[2];
-    y = (baseMatrix[0] + baseMatrix[2]) * ictm[1] +
-        (baseMatrix[1] + baseMatrix[3]) * ictm[3];
-    x = sqrt(0.5 * (x * x + y * y));
-    state->setLineWidth(x * border->getWidth());
+    state->setLineWidth(border->getWidth());
     out->updateLineWidth(state);
     dashLength = border->getDashLength();
     dash = border->getDash();
     if (border->getStyle() == AnnotBorder::borderDashed && dashLength > 0) {
       dash2 = (double *)gmallocn(dashLength, sizeof(double));
-      for (i = 0; i < dashLength; ++i) {
-	dash2[i] = x * dash[i];
-      }
+      memcpy(dash2, dash, dashLength * sizeof(double));
       state->setLineDash(dash2, dashLength, 0);
       out->updateLineDash(state);
     }
     //~ this doesn't currently handle the beveled and engraved styles
     state->clearPath();
-    state->moveTo(annotX0, out->upsideDown() ? annotY0 : annotY1);
-    state->lineTo(annotX1, out->upsideDown() ? annotY0 : annotY1);
+    state->moveTo(xMin, yMin);
+    state->lineTo(xMax, yMin);
     if (border->getStyle() != AnnotBorder::borderUnderlined) {
-      state->lineTo(annotX1, out->upsideDown() ? annotY1 : annotY0);
-      state->lineTo(annotX0, out->upsideDown() ? annotY1 : annotY0);
+      state->lineTo(xMax, yMax);
+      state->lineTo(xMin, yMax);
       state->closePath();
     }
     out->stroke(state);


More information about the poppler mailing list