[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