[poppler] 2 commits - poppler/Gfx.cc poppler/Gfx.h poppler/GfxState.cc poppler/GfxState.h poppler/Page.cc

Albert Astals Cid aacid at kemper.freedesktop.org
Thu Oct 14 16:01:24 PDT 2010


 poppler/Gfx.cc      |  214 +++++++++++++++++++++++++++++++++++++++++-----------
 poppler/Gfx.h       |    9 +-
 poppler/GfxState.cc |   96 ++++++++++++++++++++++-
 poppler/GfxState.h  |  127 ++++++++++++++++++++++++++++++
 poppler/Page.cc     |   19 ++--
 5 files changed, 409 insertions(+), 56 deletions(-)

New commits:
commit b604a008a2a379a21e5fdfa0799886f80d893a08
Author: Christian Feuersänger <cfeuersaenger at googlemail.com>
Date:   Thu Oct 14 23:56:36 2010 +0100

    Improve rendering of Shading Type 6 and 7

diff --git a/poppler/Gfx.cc b/poppler/Gfx.cc
index 4f4510a..12c0bd2 100644
--- a/poppler/Gfx.cc
+++ b/poppler/Gfx.cc
@@ -32,6 +32,7 @@
 // Copyright (C) 2009 William Bader <williambader at hotmail.com>
 // Copyright (C) 2009, 2010 David Benjamin <davidben at mit.edu>
 // Copyright (C) 2010 Nils Höglund <nils.hoglund at gmail.com>
+// Copyright (C) 2010 Christian Feuersänger <cfeuersaenger at googlemail.com>
 //
 // To see a description of the changes please see the Changelog file that
 // came with your tarball or type make ChangeLog if you are building from git
@@ -99,18 +100,26 @@
 #define radialColorDelta (dblToCol(1 / 256.0))
 
 // Max recursive depth for a Gouraud triangle shading fill.
+//
+// Triangles will be split at most gouraudMaxDepth times (each time into 4
+// smaller ones). That makes pow(4,gouraudMaxDepth) many triangles for
+// every triangle.
 #define gouraudMaxDepth 6
 
 // Max delta allowed in any color component for a Gouraud triangle
 // shading fill.
-#define gouraudColorDelta (dblToCol(1 / 256.0))
+#define gouraudColorDelta (dblToCol(3. / 256.0))
+
+// Gouraud triangle: if the three color parameters differ by at more than this percend of 
+// the total color parameter range, the triangle will be refined
+#define gouraudParameterizedColorDelta 5e-3
 
 // Max recursive depth for a patch mesh shading fill.
 #define patchMaxDepth 6
 
 // Max delta allowed in any color component for a patch mesh shading
 // fill.
-#define patchColorDelta (dblToCol(1 / 256.0))
+#define patchColorDelta (dblToCol((3. / 256.0)))
 
 //------------------------------------------------------------------------
 // Operator table
@@ -3098,22 +3107,52 @@ void Gfx::doRadialShFill(GfxRadialShading *shading) {
 
 void Gfx::doGouraudTriangleShFill(GfxGouraudTriangleShading *shading) {
   double x0, y0, x1, y1, x2, y2;
-  GfxColor color0, color1, color2;
   int i;
 
-  for (i = 0; i < shading->getNTriangles(); ++i) {
-    shading->getTriangle(i, &x0, &y0, &color0,
-			 &x1, &y1, &color1,
-			 &x2, &y2, &color2);
-    gouraudFillTriangle(x0, y0, &color0, x1, y1, &color1, x2, y2, &color2,
-			shading->getColorSpace()->getNComps(), 0);
-  }
+  // preallocate a path (speed improvements)
+  state->moveTo(0., 0.);
+  state->lineTo(1., 0.);
+  state->lineTo(0., 1.);
+  state->closePath();
+
+  GfxState::ReusablePathIterator *reusablePath = state->getReusablePath();
+
+  if (shading->isParameterized()) {
+    // work with parameterized values:
+    double color0, color1, color2;
+    // a relative threshold:
+    const double refineColorThreshold = gouraudParameterizedColorDelta *
+                                        (shading->getParameterDomainMax() - shading->getParameterDomainMin());
+    for (i = 0; i < shading->getNTriangles(); ++i) {
+      shading->getTriangle(i, &x0, &y0, &color0,
+                              &x1, &y1, &color1,
+                              &x2, &y2, &color2);
+      gouraudFillTriangle(x0, y0, color0, x1, y1, color1, x2, y2, color2, refineColorThreshold, 0, shading, reusablePath);
+    }
+
+  } else {
+    // this always produces output -- even for parameterized ranges.
+    // But it ignores the parameterized color map (the function). 
+    //
+    // Note that using this code in for parameterized shadings might be
+    // correct in circumstances (namely if the function is linear in the actual
+    // triangle), but in general, it will simply be wrong.
+    GfxColor color0, color1, color2;
+    for (i = 0; i < shading->getNTriangles(); ++i) {
+      shading->getTriangle(i, &x0, &y0, &color0,
+                              &x1, &y1, &color1,
+                              &x2, &y2, &color2);
+      gouraudFillTriangle(x0, y0, &color0, x1, y1, &color1, x2, y2, &color2, shading->getColorSpace()->getNComps(), 0, reusablePath);
+    }
+  }
+
+  delete reusablePath;
 }
 
 void Gfx::gouraudFillTriangle(double x0, double y0, GfxColor *color0,
 			      double x1, double y1, GfxColor *color1,
 			      double x2, double y2, GfxColor *color2,
-			      int nComps, int depth) {
+			      int nComps, int depth, GfxState::ReusablePathIterator *path) {
   double x01, y01, x12, y12, x20, y20;
   GfxColor color01, color12, color20;
   int i;
@@ -3127,13 +3166,15 @@ void Gfx::gouraudFillTriangle(double x0, double y0, GfxColor *color0,
   if (i == nComps || depth == gouraudMaxDepth) {
     state->setFillColor(color0);
     out->updateFillColor(state);
-    state->moveTo(x0, y0);
-    state->lineTo(x1, y1);
-    state->lineTo(x2, y2);
-    state->closePath();
+
+    path->reset();                         assert(!path->isEnd()); 
+    path->setCoord(x0,y0);  path->next();  assert(!path->isEnd()); 
+    path->setCoord(x1,y1);  path->next();  assert(!path->isEnd()); 
+    path->setCoord(x2,y2);  path->next();  assert(!path->isEnd()); 
+    path->setCoord(x0,y0);  path->next();  assert( path->isEnd()); 
+
     if (!contentIsHidden())
       out->fill(state);
-    state->clearPath();
   } else {
     x01 = 0.5 * (x0 + x1);
     y01 = 0.5 * (y0 + y1);
@@ -3141,21 +3182,74 @@ void Gfx::gouraudFillTriangle(double x0, double y0, GfxColor *color0,
     y12 = 0.5 * (y1 + y2);
     x20 = 0.5 * (x2 + x0);
     y20 = 0.5 * (y2 + y0);
-    //~ if the shading has a Function, this should interpolate on the
-    //~ function parameter, not on the color components
     for (i = 0; i < nComps; ++i) {
       color01.c[i] = (color0->c[i] + color1->c[i]) / 2;
       color12.c[i] = (color1->c[i] + color2->c[i]) / 2;
       color20.c[i] = (color2->c[i] + color0->c[i]) / 2;
     }
     gouraudFillTriangle(x0, y0, color0, x01, y01, &color01,
-			x20, y20, &color20, nComps, depth + 1);
+			x20, y20, &color20, nComps, depth + 1, path);
     gouraudFillTriangle(x01, y01, &color01, x1, y1, color1,
-			x12, y12, &color12, nComps, depth + 1);
+			x12, y12, &color12, nComps, depth + 1, path);
     gouraudFillTriangle(x01, y01, &color01, x12, y12, &color12,
-			x20, y20, &color20, nComps, depth + 1);
+			x20, y20, &color20, nComps, depth + 1, path);
     gouraudFillTriangle(x20, y20, &color20, x12, y12, &color12,
-			x2, y2, color2, nComps, depth + 1);
+			x2, y2, color2, nComps, depth + 1, path);
+  }
+}
+void Gfx::gouraudFillTriangle(double x0, double y0, double color0,
+                              double x1, double y1, double color1,
+                              double x2, double y2, double color2,
+                              double refineColorThreshold, int depth, GfxGouraudTriangleShading *shading, GfxState::ReusablePathIterator *path) {
+  const double meanColor = (color0 + color1 + color2) / 3;
+
+  const bool isFineEnough = 
+       fabs(color0 - meanColor) < refineColorThreshold &&
+       fabs(color1 - meanColor) < refineColorThreshold &&
+       fabs(color2 - meanColor) < refineColorThreshold;
+
+  if (isFineEnough || depth == gouraudMaxDepth) {
+    GfxColor color;
+
+    shading->getParameterizedColor(meanColor, &color);
+    state->setFillColor(&color);
+    out->updateFillColor(state);
+
+    path->reset();                         assert(!path->isEnd()); 
+    path->setCoord(x0,y0);  path->next();  assert(!path->isEnd()); 
+    path->setCoord(x1,y1);  path->next();  assert(!path->isEnd()); 
+    path->setCoord(x2,y2);  path->next();  assert(!path->isEnd()); 
+    path->setCoord(x0,y0);  path->next();  assert( path->isEnd()); 
+
+    if (!contentIsHidden())
+      out->fill(state);
+  } else {
+    const double x01 = 0.5 * (x0 + x1);
+    const double y01 = 0.5 * (y0 + y1);
+    const double x12 = 0.5 * (x1 + x2);
+    const double y12 = 0.5 * (y1 + y2);
+    const double x20 = 0.5 * (x2 + x0);
+    const double y20 = 0.5 * (y2 + y0);
+    const double color01 = (color0 + color1) / 2.;
+    const double color12 = (color1 + color2) / 2.; 
+    const double color20 = (color2 + color0) / 2.;
+    ++depth;
+    gouraudFillTriangle(x0, y0, color0, 
+                        x01, y01, color01,
+                        x20, y20, color20, 
+                        refineColorThreshold, depth, shading, path);
+    gouraudFillTriangle(x01, y01, color01, 
+                        x1, y1, color1,
+                        x12, y12, color12, 
+                        refineColorThreshold, depth, shading, path);
+    gouraudFillTriangle(x01, y01, color01, 
+                        x12, y12, color12,
+                        x20, y20, color20, 
+                        refineColorThreshold, depth, shading, path);
+    gouraudFillTriangle(x20, y20, color20, 
+                        x12, y12, color12,
+                        x2, y2, color2, 
+                        refineColorThreshold, depth, shading, path);
   }
 }
 
@@ -3171,32 +3265,68 @@ void Gfx::doPatchMeshShFill(GfxPatchMeshShading *shading) {
   } else {
     start = 0;
   }
+  /*
+   * Parameterized shadings take one parameter [t_0,t_e]
+   * and map it into the color space.
+   *
+   * Consequently, all color values are stored as doubles.
+   *
+   * These color values are interpreted as parameters for parameterized
+   * shadings and as colorspace entities otherwise.
+   *
+   * The only difference is that color space entities are stored into
+   * DOUBLE arrays, not into arrays of type GfxColorComp.
+   */
+  const int colorComps = shading->getColorSpace()->getNComps();
+  double refineColorThreshold;
+  if( shading->isParameterized() ) {
+	  refineColorThreshold = gouraudParameterizedColorDelta *
+		  (shading->getParameterDomainMax() - shading->getParameterDomainMin());
+
+  } else {
+	  refineColorThreshold = patchColorDelta;
+  }
+
   for (i = 0; i < shading->getNPatches(); ++i) {
-    fillPatch(shading->getPatch(i), shading->getColorSpace()->getNComps(),
-	      start);
+    fillPatch(shading->getPatch(i),
+             colorComps, 
+             shading->isParameterized() ? 1 : colorComps,
+             refineColorThreshold,
+             start,
+             shading);
   }
 }
 
-void Gfx::fillPatch(GfxPatch *patch, int nComps, int depth) {
+
+void Gfx::fillPatch(GfxPatch *patch, int colorComps, int patchColorComps, double refineColorThreshold, int depth, GfxPatchMeshShading *shading) {
   GfxPatch patch00, patch01, patch10, patch11;
   double xx[4][8], yy[4][8];
   double xxm, yym;
   int i;
 
-  for (i = 0; i < nComps; ++i) {
-    if (abs(patch->color[0][0].c[i] - patch->color[0][1].c[i])
-	  > patchColorDelta ||
-	abs(patch->color[0][1].c[i] - patch->color[1][1].c[i])
-	  > patchColorDelta ||
-	abs(patch->color[1][1].c[i] - patch->color[1][0].c[i])
-	  > patchColorDelta ||
-	abs(patch->color[1][0].c[i] - patch->color[0][0].c[i])
-	  > patchColorDelta) {
+  for (i = 0; i < patchColorComps; ++i) {
+    // these comparisons are done in double arithmetics.
+    //
+    // For non-parameterized shadings, they are done in color space
+    // components.
+    if (fabs(patch->color[0][0].c[i] - patch->color[0][1].c[i]) > refineColorThreshold ||
+        fabs(patch->color[0][1].c[i] - patch->color[1][1].c[i]) > refineColorThreshold ||
+        fabs(patch->color[1][1].c[i] - patch->color[1][0].c[i]) > refineColorThreshold ||
+        fabs(patch->color[1][0].c[i] - patch->color[0][0].c[i]) > refineColorThreshold) {
       break;
     }
   }
-  if (i == nComps || depth == patchMaxDepth) {
-    state->setFillColor(&patch->color[0][0]);
+  if (i == patchColorComps || depth == patchMaxDepth) {
+    GfxColor flatColor;
+    if( shading->isParameterized() ) {
+      shading->getParameterizedColor( patch->color[0][0].c[0], &flatColor );
+    } else {
+      for( i = 0; i<colorComps; ++i ) {
+        // simply cast to the desired type; that's all what is needed.
+        flatColor.c[i] = GfxColorComp(patch->color[0][0].c[i]);
+      }
+    }
+    state->setFillColor(&flatColor);
     out->updateFillColor(state);
     state->moveTo(patch->x[0][0], patch->y[0][0]);
     state->curveTo(patch->x[0][1], patch->y[0][1],
@@ -3274,9 +3404,7 @@ void Gfx::fillPatch(GfxPatch *patch, int nComps, int depth) {
       patch11.x[3][i-4] = xx[3][i];
       patch11.y[3][i-4] = yy[3][i];
     }
-    //~ if the shading has a Function, this should interpolate on the
-    //~ function parameter, not on the color components
-    for (i = 0; i < nComps; ++i) {
+    for (i = 0; i < patchColorComps; ++i) {
       patch00.color[0][0].c[i] = patch->color[0][0].c[i];
       patch00.color[0][1].c[i] = (patch->color[0][0].c[i] +
 				  patch->color[0][1].c[i]) / 2;
@@ -3299,10 +3427,10 @@ void Gfx::fillPatch(GfxPatch *patch, int nComps, int depth) {
       patch11.color[0][0].c[i] = patch00.color[1][1].c[i];
       patch10.color[0][1].c[i] = patch00.color[1][1].c[i];
     }
-    fillPatch(&patch00, nComps, depth + 1);
-    fillPatch(&patch10, nComps, depth + 1);
-    fillPatch(&patch01, nComps, depth + 1);
-    fillPatch(&patch11, nComps, depth + 1);
+    fillPatch(&patch00, colorComps, patchColorComps, refineColorThreshold, depth + 1, shading);
+    fillPatch(&patch10, colorComps, patchColorComps, refineColorThreshold, depth + 1, shading);
+    fillPatch(&patch01, colorComps, patchColorComps, refineColorThreshold, depth + 1, shading);
+    fillPatch(&patch11, colorComps, patchColorComps, refineColorThreshold, depth + 1, shading);
   }
 }
 
diff --git a/poppler/Gfx.h b/poppler/Gfx.h
index cb42b5c..adabe7d 100644
--- a/poppler/Gfx.h
+++ b/poppler/Gfx.h
@@ -20,6 +20,7 @@
 // Copyright (C) 2009 Albert Astals Cid <aacid at kde.org>
 // Copyright (C) 2009, 2010 Thomas Freitag <Thomas.Freitag at alfa.de>
 // Copyright (C) 2010 David Benjamin <davidben at mit.edu>
+// Copyright (C) 2010 Christian Feuersänger <cfeuersaenger at googlemail.com>
 //
 // To see a description of the changes please see the Changelog file that
 // came with your tarball or type make ChangeLog if you are building from git
@@ -299,9 +300,13 @@ private:
   void gouraudFillTriangle(double x0, double y0, GfxColor *color0,
 			   double x1, double y1, GfxColor *color1,
 			   double x2, double y2, GfxColor *color2,
-			   int nComps, int depth);
+			   int nComps, int depth, GfxState::ReusablePathIterator *path);
+  void gouraudFillTriangle(double x0, double y0, double color0,
+			   double x1, double y1, double color1,
+			   double x2, double y2, double color2,
+			   double refineColorThreshold, int depth, GfxGouraudTriangleShading *shading, GfxState::ReusablePathIterator *path);
   void doPatchMeshShFill(GfxPatchMeshShading *shading);
-  void fillPatch(GfxPatch *patch, int nComps, int depth);
+  void fillPatch(GfxPatch *patch, int colorComps, int patchColorComps, double refineColorThreshold, int depth, GfxPatchMeshShading *shading);
   void doEndPath();
 
   // path clipping operators
diff --git a/poppler/GfxState.cc b/poppler/GfxState.cc
index 59a8863..c750d2d 100644
--- a/poppler/GfxState.cc
+++ b/poppler/GfxState.cc
@@ -21,6 +21,7 @@
 // Copyright (C) 2009 Thomas Freitag <Thomas.Freitag at alfa.de>
 // Copyright (C) 2009 Christian Persch <chpe at gnome.org>
 // Copyright (C) 2010 Paweł Wiejacha <pawel.wiejacha at gmail.com>
+// Copyright (C) 2010 Christian Feuersänger <cfeuersaenger at googlemail.com>
 //
 // To see a description of the changes please see the Changelog file that
 // came with your tarball or type make ChangeLog if you are building from git
@@ -3350,6 +3351,8 @@ void GfxGouraudTriangleShading::getTriangle(
   double out[gfxColorMaxComps];
   int v, j;
 
+  assert(!isParameterized()); 
+
   v = triangles[i][0];
   *x0 = vertices[v].x;
   *y0 = vertices[v].y;
@@ -3394,6 +3397,39 @@ void GfxGouraudTriangleShading::getTriangle(
   }
 }
 
+void GfxGouraudTriangleShading::getParameterizedColor(double t, GfxColor *color) {
+  double out[gfxColorMaxComps];
+
+  for (int j = 0; j < nFuncs; ++j) {
+    funcs[j]->transform(&t, &out[j]);
+  }
+  for (int j = 0; j < gfxColorMaxComps; ++j) {
+    color->c[j] = dblToCol(out[j]);
+  }
+}
+
+void GfxGouraudTriangleShading::getTriangle(int i,
+                                            double *x0, double *y0, double *color0,
+                                            double *x1, double *y1, double *color1,
+                                            double *x2, double *y2, double *color2) {
+  int v;
+
+  assert(isParameterized()); 
+
+  v = triangles[i][0];
+  *x0 = vertices[v].x;
+  *y0 = vertices[v].y;
+  *color0 = colToDbl(vertices[v].color.c[0]);
+  v = triangles[i][1];
+  *x1 = vertices[v].x;
+  *y1 = vertices[v].y;
+  *color1 = colToDbl(vertices[v].color.c[0]);
+  v = triangles[i][2];
+  *x2 = vertices[v].x;
+  *y2 = vertices[v].y;
+  *color2 = colToDbl(vertices[v].color.c[0]);
+}
+
 //------------------------------------------------------------------------
 // GfxPatchMeshShading
 //------------------------------------------------------------------------
@@ -3451,7 +3487,7 @@ GfxPatchMeshShading *GfxPatchMeshShading::parse(int typeA, Dict *dict,
   Guint flag;
   double x[16], y[16];
   Guint xi, yi;
-  GfxColorComp c[4][gfxColorMaxComps];
+  double c[4][gfxColorMaxComps];
   Guint ci[4];
   GfxShadingBitBuf *bitBuf;
   Object obj1, obj2;
@@ -3573,7 +3609,12 @@ GfxPatchMeshShading *GfxPatchMeshShading::parse(int typeA, Dict *dict,
 	if (!bitBuf->getBits(compBits, &ci[j])) {
 	  break;
 	}
-	c[i][j] = dblToCol(cMin[j] + cMul[j] * (double)ci[j]);
+	c[i][j] = cMin[j] + cMul[j] * (double)ci[j];
+	if( nFuncsA == 0 ) {
+	  // ... and colorspace values can also be stored into doubles.
+	  // They will be casted later.
+	  c[i][j] = dblToCol(c[i][j]);
+	}
       }
       if (j < nComps) {
 	break;
@@ -3950,6 +3991,17 @@ GfxPatchMeshShading *GfxPatchMeshShading::parse(int typeA, Dict *dict,
   return NULL;
 }
 
+void GfxPatchMeshShading::getParameterizedColor(double t, GfxColor *color) {
+  double out[gfxColorMaxComps];
+
+  for (int j = 0; j < nFuncs; ++j) {
+    funcs[j]->transform(&t, &out[j]);
+  }
+  for (int j = 0; j < gfxColorMaxComps; ++j) {
+    color->c[j] = dblToCol(out[j]);
+  }
+}
+
 GfxShading *GfxPatchMeshShading::copy() {
   return new GfxPatchMeshShading(this);
 }
@@ -4506,6 +4558,46 @@ void GfxPath::offset(double dx, double dy) {
 //------------------------------------------------------------------------
 // GfxState
 //------------------------------------------------------------------------
+GfxState::ReusablePathIterator::ReusablePathIterator(GfxPath *path)
+ : path(path),
+   subPathOff(0),
+   coordOff(0),
+   numCoords(0),
+   curSubPath(NULL)
+{
+  if( path->getNumSubpaths() ) {
+    curSubPath = path->getSubpath(subPathOff);
+    numCoords = curSubPath->getNumPoints();
+  }
+}
+
+bool GfxState::ReusablePathIterator::isEnd() const {
+   return coordOff >= numCoords;
+}
+
+void GfxState::ReusablePathIterator::next() {
+  ++coordOff;
+  if (coordOff == numCoords) {
+    ++subPathOff;
+    if (subPathOff < path->getNumSubpaths()) {
+      coordOff = 0;
+      curSubPath = path->getSubpath(subPathOff);
+      numCoords = curSubPath->getNumPoints();
+    }
+  }
+}
+
+void GfxState::ReusablePathIterator::setCoord(double x, double y) {
+  curSubPath->setX(coordOff, x);
+  curSubPath->setY(coordOff, y);
+}
+
+void GfxState::ReusablePathIterator::reset() {
+  coordOff = 0;
+  subPathOff = 0;
+  curSubPath = path->getSubpath(0);
+  numCoords = curSubPath->getNumPoints();
+}
 
 GfxState::GfxState(double hDPIA, double vDPIA, PDFRectangle *pageBox,
 		   int rotateA, GBool upsideDown) {
diff --git a/poppler/GfxState.h b/poppler/GfxState.h
index 900214d..b425b4a 100644
--- a/poppler/GfxState.h
+++ b/poppler/GfxState.h
@@ -18,6 +18,7 @@
 // Copyright (C) 2006 Carlos Garcia Campos <carlosgc at gnome.org>
 // Copyright (C) 2009 Koji Otani <sho at bbr.jp>
 // Copyright (C) 2009, 2010 Albert Astals Cid <aacid at kde.org>
+// Copyright (C) 2010 Christian Feuersänger <cfeuersaenger at googlemail.com>
 //
 // To see a description of the changes please see the Changelog file that
 // came with your tarball or type make ChangeLog if you are building from git
@@ -35,6 +36,8 @@
 #include "Object.h"
 #include "Function.h"
 
+#include <assert.h>
+
 class Array;
 class Gfx;
 class GfxFont;
@@ -876,10 +879,37 @@ public:
   virtual GfxShading *copy();
 
   int getNTriangles() { return nTriangles; }
+
+  bool isParameterized() const { return nFuncs > 0; }
+
+  /**
+   * @precondition isParameterized() == true
+   */
+  double getParameterDomainMin() const { assert(isParameterized()); return funcs[0]->getDomainMin(0); }
+
+  /**
+   * @precondition isParameterized() == true
+   */
+  double getParameterDomainMax() const { assert(isParameterized()); return funcs[0]->getDomainMax(0); }
+
+  /**
+   * @precondition isParameterized() == false
+   */
   void getTriangle(int i, double *x0, double *y0, GfxColor *color0,
 		   double *x1, double *y1, GfxColor *color1,
 		   double *x2, double *y2, GfxColor *color2);
 
+  /**
+   * Variant for functions.
+   *
+   * @precondition isParameterized() == true
+   */
+  void getTriangle(int i, double *x0, double *y0, double *color0,
+		   double *x1, double *y1, double *color1,
+		   double *x2, double *y2, double *color2);
+
+  void getParameterizedColor(double t, GfxColor *color);
+
 private:
 
   GfxGouraudVertex *vertices;
@@ -894,10 +924,32 @@ private:
 // GfxPatchMeshShading
 //------------------------------------------------------------------------
 
+/**
+ * A tensor product cubic bezier patch consisting of 4x4 points and 4 color
+ * values.
+ *
+ * See the Shading Type 7 specifications. Note that Shading Type 6 is also
+ * represented using GfxPatch.
+ */
 struct GfxPatch {
+  /**
+   * Represents a single color value for the patch.
+   */
+  struct ColorValue {
+    /**
+     * For parameterized patches, only element 0 is valid; it contains
+     * the single parameter.
+     *
+     * For non-parameterized patches, c contains all color components
+     * as decoded from the input stream. In this case, you will need to
+     * use dblToCol() before assigning them to GfxColor.
+     */
+    double c[gfxColorMaxComps];
+  };
+
   double x[4][4];
   double y[4][4];
-  GfxColor color[2][2];
+  ColorValue color[2][2];
 };
 
 class GfxPatchMeshShading: public GfxShading {
@@ -915,6 +967,20 @@ public:
   int getNPatches() { return nPatches; }
   GfxPatch *getPatch(int i) { return &patches[i]; }
 
+  bool isParameterized() const { return nFuncs > 0; }
+
+  /**
+   * @precondition isParameterized() == true
+   */
+  double getParameterDomainMin() const { assert(isParameterized()); return funcs[0]->getDomainMin(0); }
+
+  /**
+   * @precondition isParameterized() == true
+   */
+  double getParameterDomainMax() const { assert(isParameterized()); return funcs[0]->getDomainMax(0); }
+
+  void getParameterizedColor(double t, GfxColor *color);
+
 private:
 
   GfxPatch *patches;
@@ -1004,6 +1070,9 @@ public:
   double getY(int i) { return y[i]; }
   GBool getCurve(int i) { return curve[i]; }
 
+  void setX(int i, double a) { x[i] = a; }
+  void setY(int i, double a) { y[i] = a; }
+
   // Get last point.
   double getLastX() { return x[n-1]; }
   double getLastY() { return y[n-1]; }
@@ -1098,6 +1167,61 @@ private:
 
 class GfxState {
 public:
+  /**
+   * When GfxState::getReusablePath() is invoked, the currently active
+   * path is taken per reference and its coordinates can be re-edited.
+   *
+   * A ReusablePathIterator is intented to reduce overhead when the same
+   * path type is used a lot of times, only with different coordinates. It
+   * allows just to update the coordinates (occuring in the same order as
+   * in the original path).
+   */
+  class ReusablePathIterator {
+  public:
+    /**
+     * Creates the ReusablePathIterator. This should only be done from
+     * GfxState::getReusablePath().
+     *
+     * @param path the path as it is used so far. Changing this path,
+     * deleting it or starting a new path from scratch will most likely
+     * invalidate the iterator (and may cause serious problems). Make
+     * sure the path's memory structure is not changed during the
+     * lifetime of the ReusablePathIterator.
+     */
+    ReusablePathIterator( GfxPath* path );
+
+    /**
+     * Returns true if and only if the current iterator position is
+     * beyond the last valid point.
+     *
+     * A call to setCoord() will be undefined.
+     */
+    bool isEnd() const;
+
+    /**
+     * Advances the iterator.
+     */
+    void next();
+
+     /**
+     * Updates the coordinates associated to the current iterator
+     * position.
+     */
+     void setCoord( double x, double y );
+
+    /**
+     * Resets the iterator.
+     */
+    void reset();
+  private:
+    GfxPath *path;
+    int subPathOff;
+
+    int coordOff;
+    int numCoords;
+
+    GfxSubpath *curSubPath;
+  };
 
   // Construct a default GfxState, for a device with resolution <hDPI>
   // x <vDPI>, page box <pageBox>, page rotation <rotateA>, and
@@ -1276,6 +1400,7 @@ public:
   // Misc
   GBool parseBlendMode(Object *obj, GfxBlendMode *mode);
 
+  ReusablePathIterator *getReusablePath() { return new ReusablePathIterator(path); }
 private:
 
   double hDPI, vDPI;		// resolution
commit c6bb63b31c268e4e842532e6839b15edb31cf25c
Author: Albert Astals Cid <aacid at kde.org>
Date:   Thu Oct 14 23:33:13 2010 +0100

    Only clip boxes to mediabox if we are at the page level
    
    Fixes bug 30784

diff --git a/poppler/Page.cc b/poppler/Page.cc
index 3c2d880..caf233f 100644
--- a/poppler/Page.cc
+++ b/poppler/Page.cc
@@ -15,7 +15,7 @@
 //
 // Copyright (C) 2005 Kristian Høgsberg <krh at redhat.com>
 // Copyright (C) 2005 Jeff Muizelaar <jeff at infidigm.net>
-// Copyright (C) 2005-2009 Albert Astals Cid <aacid at kde.org>
+// Copyright (C) 2005-2010 Albert Astals Cid <aacid at kde.org>
 // Copyright (C) 2006-2008 Pino Toscano <pino at kde.org>
 // Copyright (C) 2006 Nickolay V. Shmyrev <nshmyrev at yandex.ru>
 // Copyright (C) 2006 Scott Turner <scotty1024 at mac.com>
@@ -91,6 +91,7 @@ void PDFRectangle::clipTo(PDFRectangle *rect) {
 PageAttrs::PageAttrs(PageAttrs *attrs, Dict *dict) {
   Object obj1;
   PDFRectangle mBox;
+  const GBool isPage = dict->is("Page");
 
   // get old/default values
   if (attrs) {
@@ -124,8 +125,8 @@ PageAttrs::PageAttrs(PageAttrs *attrs, Dict *dict) {
   if (!haveCropBox) {
     cropBox = mediaBox;
   }
-  else
-  {
+
+  if (isPage) {
     // cropBox can not be bigger than mediaBox
     if (cropBox.x2 - cropBox.x1 > mediaBox.x2 - mediaBox.x1)
     {
@@ -147,11 +148,13 @@ PageAttrs::PageAttrs(PageAttrs *attrs, Dict *dict) {
   artBox = cropBox;
   readBox(dict, "ArtBox", &artBox);
 
-  // clip all other boxes to the media box
-  cropBox.clipTo(&mediaBox);
-  bleedBox.clipTo(&mediaBox);
-  trimBox.clipTo(&mediaBox);
-  artBox.clipTo(&mediaBox);
+  if (isPage) {
+    // clip all other boxes to the media box
+    cropBox.clipTo(&mediaBox);
+    bleedBox.clipTo(&mediaBox);
+    trimBox.clipTo(&mediaBox);
+    artBox.clipTo(&mediaBox);
+  }
 
   // rotate
   dict->lookup("Rotate", &obj1);


More information about the poppler mailing list