[poppler] poppler/CairoOutputDev.h poppler/Function.cc poppler/Function.h poppler/Gfx.cc poppler/OutputDev.h poppler/PSOutputDev.h poppler/SplashOutputDev.cc poppler/SplashOutputDev.h splash/SplashBitmap.cc splash/SplashBitmap.h splash/Splash.cc splash/Splash.h splash/SplashPattern.cc splash/SplashPattern.h
Albert Astals Cid
aacid at kemper.freedesktop.org
Thu Nov 4 14:00:46 PDT 2010
poppler/CairoOutputDev.h | 5
poppler/Function.cc | 4
poppler/Function.h | 2
poppler/Gfx.cc | 12 -
poppler/OutputDev.h | 16 +
poppler/PSOutputDev.h | 4
poppler/SplashOutputDev.cc | 182 ++++++++++++++++++++
poppler/SplashOutputDev.h | 68 +++++++
splash/Splash.cc | 395 ++++++++++++++++++++++++++++++++++++++++++++-
splash/Splash.h | 11 +
splash/SplashBitmap.cc | 4
splash/SplashBitmap.h | 3
splash/SplashPattern.cc | 17 +
splash/SplashPattern.h | 36 +++-
14 files changed, 735 insertions(+), 24 deletions(-)
New commits:
commit fa7c41cb9c52ecd3d7c574455b1258a3021b8c75
Author: Albert Astals Cid <aacid at kde.org>
Date: Thu Nov 4 20:55:34 2010 +0000
Improvements to the splash backend
Antialias and shadings.
Code by Thomas Freitag <Thomas.Freitag at alfa.de> and Christian Feuersänger <cfeuersaenger at googlemail.com>
More info at bug 30436
diff --git a/poppler/CairoOutputDev.h b/poppler/CairoOutputDev.h
index e003d83..26efadc 100644
--- a/poppler/CairoOutputDev.h
+++ b/poppler/CairoOutputDev.h
@@ -20,6 +20,7 @@
// Copyright (C) 2006-2010 Carlos Garcia Campos <carlosgc at gnome.org>
// Copyright (C) 2008, 2009 Adrian Johnson <ajohnson at redneon.com>
// Copyright (C) 2008 Michael Vrable <mvrable at cs.ucsd.edu>
+// Copyright (C) 2010 Thomas Freitag <Thomas.Freitag at alfa.de>
//
// 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
@@ -106,7 +107,7 @@ public:
// Does this device use functionShadedFill(), axialShadedFill(), and
// radialShadedFill()? If this returns false, these shaded fills
// will be reduced to a series of other drawing operations.
- virtual GBool useShadedFills() { return gTrue; }
+ virtual GBool useShadedFills(int type) { return type < 4; }
// Does this device use FillColorStop()?
virtual GBool useFillColorStop() { return gTrue; }
@@ -360,7 +361,7 @@ public:
// Does this device use functionShadedFill(), axialShadedFill(), and
// radialShadedFill()? If this returns false, these shaded fills
// will be reduced to a series of other drawing operations.
- virtual GBool useShadedFills() { return gTrue; }
+ virtual GBool useShadedFills(int type) { return type < 4; }
// Does this device use FillColorStop()?
virtual GBool useFillColorStop() { return gFalse; }
diff --git a/poppler/Function.cc b/poppler/Function.cc
index 4ab32cb..0a72278 100644
--- a/poppler/Function.cc
+++ b/poppler/Function.cc
@@ -15,6 +15,7 @@
//
// Copyright (C) 2006, 2008-2010 Albert Astals Cid <aacid at kde.org>
// Copyright (C) 2006 Jeff Muizelaar <jeff at infidigm.net>
+// 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
@@ -528,6 +529,7 @@ ExponentialFunction::ExponentialFunction(Object *funcObj, Dict *dict) {
e = obj1.getNum();
obj1.free();
+ isLinear = fabs(e-1.) < 1e-10;
ok = gTrue;
return;
@@ -558,7 +560,7 @@ void ExponentialFunction::transform(double *in, double *out) {
x = in[0];
}
for (i = 0; i < n; ++i) {
- out[i] = c0[i] + pow(x, e) * (c1[i] - c0[i]);
+ out[i] = c0[i] + (isLinear ? x : pow(x, e)) * (c1[i] - c0[i]);
if (hasRange) {
if (out[i] < range[i][0]) {
out[i] = range[i][0];
diff --git a/poppler/Function.h b/poppler/Function.h
index 297401c..3541775 100644
--- a/poppler/Function.h
+++ b/poppler/Function.h
@@ -14,6 +14,7 @@
// under GPL version 2 or later
//
// 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
@@ -176,6 +177,7 @@ private:
double c0[funcMaxOutputs];
double c1[funcMaxOutputs];
double e;
+ bool isLinear;
GBool ok;
};
diff --git a/poppler/Gfx.cc b/poppler/Gfx.cc
index d11845c..825d98c 100644
--- a/poppler/Gfx.cc
+++ b/poppler/Gfx.cc
@@ -2307,7 +2307,7 @@ void Gfx::doFunctionShFill(GfxFunctionShading *shading) {
double x0, y0, x1, y1;
GfxColor colors[4];
- if (out->useShadedFills() &&
+ if (out->useShadedFills( shading->getType() ) &&
out->functionShadedFill(state, shading)) {
return;
}
@@ -2490,7 +2490,7 @@ void Gfx::doAxialShFill(GfxAxialShading *shading) {
}
}
- if (out->useShadedFills() &&
+ if (out->useShadedFills( shading->getType() ) &&
out->axialShadedFill(state, shading, tMin, tMax)) {
return;
}
@@ -2764,7 +2764,7 @@ void Gfx::doRadialShFill(GfxRadialShading *shading) {
theta = 0;
sz = 0; // make gcc happy
} else {
- sz = -r0 / (r1 - r0);
+ sz = (r1 > r0) ? -r0 / (r1 - r0) : -r1 / (r0 - r1);
xz = x0 + sz * (x1 - x0);
yz = y0 + sz * (y1 - y0);
enclosed = (xz - x0) * (xz - x0) + (yz - y0) * (yz - y0) <= r0 * r0;
@@ -2842,7 +2842,7 @@ void Gfx::doRadialShFill(GfxRadialShading *shading) {
}
}
- if (out->useShadedFills() &&
+ if (out->useShadedFills( shading->getType() ) &&
out->radialShadedFill(state, shading, sMin, sMax)) {
return;
}
@@ -3115,6 +3115,10 @@ void Gfx::doGouraudTriangleShFill(GfxGouraudTriangleShading *shading) {
double x0, y0, x1, y1, x2, y2;
int i;
+ if( out->useShadedFills( shading->getType() ) ) {
+ if( out->gouraudTriangleShadedFill( state, shading ) )
+ return;
+ }
// preallocate a path (speed improvements)
state->moveTo(0., 0.);
state->lineTo(1., 0.);
diff --git a/poppler/OutputDev.h b/poppler/OutputDev.h
index cdc74cf..057d84a 100644
--- a/poppler/OutputDev.h
+++ b/poppler/OutputDev.h
@@ -17,9 +17,10 @@
// Copyright (C) 2006 Thorkild Stray <thorkild at ifi.uio.no>
// Copyright (C) 2007 Jeff Muizelaar <jeff at infidigm.net>
// Copyright (C) 2007 Adrian Johnson <ajohnson at redneon.com>
-// Copyright (C) 2009 Thomas Freitag <Thomas.Freitag at alfa.de>
+// Copyright (C) 2009, 2010 Thomas Freitag <Thomas.Freitag at alfa.de>
// Copyright (C) 2009 Carlos Garcia Campos <carlosgc at gnome.org>
// Copyright (C) 2009 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
@@ -47,6 +48,8 @@ class GfxColorSpace;
class GfxImageColorMap;
class GfxFunctionShading;
class GfxAxialShading;
+class GfxGouraudTriangleShading;
+class GfxPatchMeshShading;
class GfxRadialShading;
class Stream;
class Links;
@@ -82,10 +85,9 @@ public:
// operations.
virtual GBool useTilingPatternFill() { return gFalse; }
- // Does this device use functionShadedFill(), axialShadedFill(), and
- // radialShadedFill()? If this returns false, these shaded fills
- // will be reduced to a series of other drawing operations.
- virtual GBool useShadedFills() { return gFalse; }
+ // Does this device support specific shading types?
+ // see gouraudTriangleShadedFill() and patchMeshShadedFill()
+ virtual GBool useShadedFills(int type) { return gFalse; }
// Does this device use FillColorStop()?
virtual GBool useFillColorStop() { return gFalse; }
@@ -208,6 +210,10 @@ public:
{ return gFalse; }
virtual GBool radialShadedSupportExtend(GfxState * /*state*/, GfxRadialShading * /*shading*/)
{ return gFalse; }
+ virtual GBool gouraudTriangleShadedFill(GfxState *state, GfxGouraudTriangleShading *shading)
+ { return gFalse; }
+ virtual GBool patchMeshShadedFill(GfxState *state, GfxPatchMeshShading *shading)
+ { return gFalse; }
//----- path clipping
virtual void clip(GfxState * /*state*/) {}
diff --git a/poppler/PSOutputDev.h b/poppler/PSOutputDev.h
index 2ac7b13..02160b7 100644
--- a/poppler/PSOutputDev.h
+++ b/poppler/PSOutputDev.h
@@ -120,8 +120,8 @@ public:
// Does this device use functionShadedFill(), axialShadedFill(), and
// radialShadedFill()? If this returns false, these shaded fills
// will be reduced to a series of other drawing operations.
- virtual GBool useShadedFills()
- { return level >= psLevel2; }
+ virtual GBool useShadedFills(int type)
+ { return type < 4 && level >= psLevel2; }
// Does this device use drawForm()? If this returns false,
// form-type XObjects will be interpreted (i.e., unrolled).
diff --git a/poppler/SplashOutputDev.cc b/poppler/SplashOutputDev.cc
index 33cef9e..0b3722a 100644
--- a/poppler/SplashOutputDev.cc
+++ b/poppler/SplashOutputDev.cc
@@ -26,6 +26,7 @@
// Copyright (C) 2010 Patrick Spendrin <ps_ml at gmx.de>
// Copyright (C) 2010 Brian Cameron <brian.cameron at oracle.com>
// 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
@@ -79,6 +80,126 @@ extern "C" int unlink(char *filename);
#define isfinite(x) finite(x)
#endif
+static inline void convertGfxColor(SplashColorPtr dest,
+ SplashColorMode colorMode,
+ GfxColorSpace *colorSpace,
+ GfxColor *src) {
+ SplashColor color;
+ GfxGray gray;
+ GfxRGB rgb;
+#if SPLASH_CMYK
+ GfxCMYK cmyk;
+#endif
+
+ switch (colorMode) {
+ case splashModeMono1:
+ case splashModeMono8:
+ colorSpace->getGray(src, &gray);
+ color[0] = colToByte(gray);
+ break;
+ case splashModeXBGR8:
+ color[3] = 255;
+ case splashModeBGR8:
+ case splashModeRGB8:
+ colorSpace->getRGB(src, &rgb);
+ color[0] = colToByte(rgb.r);
+ color[1] = colToByte(rgb.g);
+ color[2] = colToByte(rgb.b);
+ break;
+#if SPLASH_CMYK
+ case splashModeCMYK8:
+ colorSpace->getCMYK(src, &cmyk);
+ color[0] = colToByte(cmyk.c);
+ color[1] = colToByte(cmyk.m);
+ color[2] = colToByte(cmyk.y);
+ color[3] = colToByte(cmyk.k);
+ break;
+#endif
+ }
+ splashColorCopy(dest, color);
+}
+
+
+//------------------------------------------------------------------------
+// SplashGouraudPattern
+//------------------------------------------------------------------------
+SplashGouraudPattern::SplashGouraudPattern(GBool bDirectColorTranslationA,
+ GfxState *stateA, GfxGouraudTriangleShading *shadingA) {
+ state = stateA;
+ shading = shadingA;
+ bDirectColorTranslation = bDirectColorTranslationA;
+}
+
+SplashGouraudPattern::~SplashGouraudPattern() {
+}
+
+void SplashGouraudPattern::getParameterizedColor(double colorinterp, SplashColorMode mode, SplashColorPtr dest) {
+ GfxColor src;
+ GfxColorSpace* srcColorSpace = shading->getColorSpace();
+ int colorComps = 3;
+#if SPLASH_CMYK
+ if (mode == splashModeCMYK8)
+ colorComps=4;
+#endif
+
+ shading->getParameterizedColor(colorinterp, &src);
+
+ if (bDirectColorTranslation) {
+ for (int m = 0; m < colorComps; ++m)
+ dest[m] = colToByte(src.c[m]);
+ } else {
+ convertGfxColor(dest, mode, srcColorSpace, &src);
+ }
+}
+
+//------------------------------------------------------------------------
+// SplashAxialPattern
+//------------------------------------------------------------------------
+
+SplashAxialPattern::SplashAxialPattern(SplashColorMode colorModeA, GfxState *stateA, GfxAxialShading *shadingA) {
+ Matrix ctm;
+
+ shading = shadingA;
+ state = stateA;
+ colorMode = colorModeA;
+ state->getCTM(&ctm);
+ ctm.invertTo(&ictm);
+
+ shading->getCoords(&x0, &y0, &x1, &y1);
+ dx = x1 - x0;
+ dy = y1 - y0;
+ mul = 1 / (dx * dx + dy * dy);
+
+ // get the function domain
+ t0 = shading->getDomain0();
+ t1 = shading->getDomain1();
+}
+
+SplashAxialPattern::~SplashAxialPattern() {
+}
+
+GBool SplashAxialPattern::getColor(int x, int y, SplashColorPtr c) {
+ GfxColor gfxColor;
+ double tt;
+ double xc, yc, xaxis;
+
+ ictm.transform(x, y, &xc, &yc);
+ xaxis = ((xc - x0) * dx + (yc - y0) * dy) * mul;
+ if (xaxis < 0 && shading->getExtend0()) {
+ tt = t0;
+ } else if (xaxis > 1 && shading->getExtend1()) {
+ tt = t1;
+ } else if (xaxis >= 0 && xaxis <= 1) {
+ tt = t0 + (t1 -t0) * xaxis;
+ } else
+ return gFalse;
+
+ shading->getColor(tt, &gfxColor);
+ state->setFillColor(&gfxColor);
+ convertGfxColor(c, colorMode, state->getFillColorSpace(), state->getFillColor());
+ return gTrue;
+}
+
//------------------------------------------------------------------------
// Divide a 16-bit value (in [0, 255*255]) by 255, returning an 8-bit result.
@@ -2048,7 +2169,7 @@ void SplashOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
//~ this ignores the blendingColorSpace arg
// create the temporary bitmap
bitmap = new SplashBitmap(bitmap->getWidth(), bitmap->getHeight(), bitmapRowPad, colorMode, gTrue,
- bitmapTopDown);
+ bitmapTopDown);
splash = new Splash(bitmap, vectorAntialias,
transpGroup->origSplash->getScreen());
splash->blitTransparent(transpGroup->origBitmap, 0, 0, 0, 0, bitmap->getWidth(), bitmap->getHeight());
@@ -2931,7 +3052,7 @@ void SplashOutputDev::beginTransparencyGroup(GfxState *state, double *bbox,
// create the temporary bitmap
bitmap = new SplashBitmap(w, h, bitmapRowPad, colorMode, gTrue,
- bitmapTopDown);
+ bitmapTopDown);
splash = new Splash(bitmap, vectorAntialias,
transpGroup->origSplash->getScreen());
if (isolated) {
@@ -3201,3 +3322,60 @@ void SplashOutputDev::setFreeTypeHinting(GBool enable)
{
enableFreeTypeHinting = enable;
}
+
+GBool SplashOutputDev::gouraudTriangleShadedFill(GfxState *state, GfxGouraudTriangleShading *shading)
+{
+ GfxColorSpaceMode shadingMode = shading->getColorSpace()->getMode();
+ GBool bDirectColorTranslation = gFalse; // triggers an optimization.
+ switch (colorMode) {
+ case splashModeRGB8:
+ bDirectColorTranslation = (shadingMode == csDeviceRGB);
+ break;
+#if SPLASH_CMYK
+ case splashModeCMYK8:
+ bDirectColorTranslation = (shadingMode == csDeviceCMYK);
+ break;
+#endif
+ default:
+ break;
+ }
+ SplashGouraudColor *splashShading = new SplashGouraudPattern(bDirectColorTranslation, state, shading);
+ // restore vector antialias because we support it here
+ if (shading->isParameterized()) {
+ GBool vaa = getVectorAntialias();
+ GBool retVal = gFalse;
+ setVectorAntialias(gTrue);
+ retVal = splash->gouraudTriangleShadedFill(splashShading);
+ setVectorAntialias(vaa);
+ return retVal;
+ }
+ return gFalse;
+}
+
+GBool SplashOutputDev::axialShadedFill(GfxState *state, GfxAxialShading *shading, double tMin, double tMax) {
+ double xMin, yMin, xMax, yMax;
+ SplashPath *path;
+
+ GBool vaa = getVectorAntialias();
+ GBool retVal = gFalse;
+ // restore vector antialias because we support it here
+ setVectorAntialias(gTrue);
+ // get the clip region bbox
+ state->getUserClipBBox(&xMin, &yMin, &xMax, &yMax);
+
+ // fill the region
+ state->moveTo(xMin, yMin);
+ state->lineTo(xMax, yMin);
+ state->lineTo(xMax, yMax);
+ state->lineTo(xMin, yMax);
+ state->closePath();
+ path = convertPath(state, state->getPath());
+
+ SplashPattern *pattern = new SplashAxialPattern(colorMode, state, shading);
+ retVal = (splash->shadedFill(path, shading->getHasBBox(), pattern) == splashOk);
+ setVectorAntialias(vaa);
+ state->clearPath();
+ delete path;
+
+ return retVal;
+}
diff --git a/poppler/SplashOutputDev.h b/poppler/SplashOutputDev.h
index adbd196..570d036 100644
--- a/poppler/SplashOutputDev.h
+++ b/poppler/SplashOutputDev.h
@@ -16,6 +16,7 @@
// Copyright (C) 2005 Takashi Iwai <tiwai at suse.de>
// Copyright (C) 2009, 2010 Thomas Freitag <Thomas.Freitag at alfa.de>
// Copyright (C) 2009 Carlos Garcia Campos <carlosgc at gnome.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
@@ -31,6 +32,7 @@
#include "goo/gtypes.h"
#include "splash/SplashTypes.h"
+#include "splash/SplashPattern.h"
#include "poppler-config.h"
#include "OutputDev.h"
#include "GfxState.h"
@@ -39,7 +41,6 @@ class Gfx8BitFont;
class SplashBitmap;
class Splash;
class SplashPath;
-class SplashPattern;
class SplashFontEngine;
class SplashFont;
class T3FontCache;
@@ -48,6 +49,63 @@ struct T3GlyphStack;
struct SplashTransparencyGroup;
//------------------------------------------------------------------------
+// Splash dynamic pattern
+//------------------------------------------------------------------------
+
+class SplashAxialPattern: public SplashPattern {
+public:
+
+ SplashAxialPattern(SplashColorMode colorMode, GfxState *state, GfxAxialShading *shading);
+
+ virtual SplashPattern *copy() { return new SplashAxialPattern(colorMode, state, shading); }
+
+ virtual ~SplashAxialPattern();
+
+ virtual GBool getColor(int x, int y, SplashColorPtr c);
+
+ virtual GBool isStatic() { return gFalse; }
+
+private:
+ Matrix ictm;
+ double x0, y0, x1, y1;
+ double dx, dy, mul;
+ double t0, t1;
+ GfxAxialShading *shading;
+ GfxState *state;
+ SplashColorMode colorMode;
+ double *bbox;
+};
+
+// see GfxState.h, GfxGouraudTriangleShading
+class SplashGouraudPattern: public SplashGouraudColor {
+public:
+
+ SplashGouraudPattern(GBool bDirectColorTranslation, GfxState *state, GfxGouraudTriangleShading *shading);
+
+ virtual SplashPattern *copy() { return new SplashGouraudPattern(bDirectColorTranslation, state, shading); }
+
+ virtual ~SplashGouraudPattern();
+
+ virtual GBool getColor(int x, int y, SplashColorPtr c) { return gFalse; }
+
+ virtual GBool isStatic() { return gFalse; }
+
+ virtual GBool isParameterized() { return shading->isParameterized(); }
+ virtual int getNTriangles() { return shading->getNTriangles(); }
+ virtual void getTriangle(int i, double *x0, double *y0, double *color0,
+ double *x1, double *y1, double *color1,
+ double *x2, double *y2, double *color2)
+ { return shading->getTriangle(i, x0, y0, color0, x1, y1, color1, x2, y2, color2); }
+
+ virtual void getParameterizedColor(double t, SplashColorMode mode, SplashColorPtr c);
+
+private:
+ GfxGouraudTriangleShading *shading;
+ GfxState *state;
+ GBool bDirectColorTranslation;
+};
+
+//------------------------------------------------------------------------
// number of Type 3 fonts to cache
#define splashOutT3FontCacheSize 8
@@ -70,6 +128,12 @@ public:
//----- get info about output device
+ // Does this device use functionShadedFill(), axialShadedFill(), and
+ // radialShadedFill()? If this returns false, these shaded fills
+ // will be reduced to a series of other drawing operations.
+ virtual GBool useShadedFills(int type)
+ { return (type == 2 || type == 4 || type == 5 ) ? gTrue : gFalse; }
+
// Does this device use upside-down coordinates?
// (Upside-down means (0,0) is the top left corner of the page.)
virtual GBool upsideDown() { return gTrue; }
@@ -121,6 +185,8 @@ public:
virtual void stroke(GfxState *state);
virtual void fill(GfxState *state);
virtual void eoFill(GfxState *state);
+ virtual GBool axialShadedFill(GfxState *state, GfxAxialShading *shading, double tMin, double tMax);
+ virtual GBool gouraudTriangleShadedFill(GfxState *state, GfxGouraudTriangleShading *shading);
//----- path clipping
virtual void clip(GfxState *state);
diff --git a/splash/Splash.cc b/splash/Splash.cc
index d3e48fa..f36f616 100644
--- a/splash/Splash.cc
+++ b/splash/Splash.cc
@@ -13,6 +13,8 @@
//
// Copyright (C) 2005-2010 Albert Astals Cid <aacid at kde.org>
// Copyright (C) 2005 Marco Pesenti Gritti <mpg at redhat.com>
+// Copyright (C) 2010 Thomas Freitag <Thomas.Freitag at alfa.de>
+// 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
@@ -28,6 +30,7 @@
#include <stdlib.h>
#include <string.h>
#include <limits.h>
+#include <assert.h>
#include "goo/gmem.h"
#include "goo/GooLikely.h"
#include "poppler/Error.h"
@@ -56,6 +59,9 @@ static inline Guchar div255(int x) {
return (Guchar)((x + (x >> 8) + 0x80) >> 8);
}
+template<typename T>
+inline void Guswap( T&a, T&b ) { T tmp = a; a=b; b=tmp; }
+
//------------------------------------------------------------------------
// SplashPipe
//------------------------------------------------------------------------
@@ -246,7 +252,32 @@ inline void Splash::pipeRun(SplashPipe *pipe) {
// dynamic pattern
if (pipe->pattern) {
- pipe->pattern->getColor(pipe->x, pipe->y, pipe->cSrcVal);
+ if (!pipe->pattern->getColor(pipe->x, pipe->y, pipe->cSrcVal)) {
+ switch (bitmap->mode) {
+ case splashModeMono1:
+ if (!(pipe->destColorMask >>= 1))
+ ++pipe->destColorPtr;
+ break;
+ case splashModeMono8:
+ ++pipe->destColorPtr;
+ break;
+ case splashModeBGR8:
+ case splashModeRGB8:
+ pipe->destColorPtr += 3;
+ break;
+ case splashModeXBGR8:
+#if SPLASH_CMYK
+ case splashModeCMYK8:
+#endif
+ pipe->destColorPtr += 4;
+ break;
+ }
+ if (pipe->destAlphaPtr) {
+ ++pipe->destAlphaPtr;
+ }
+ ++pipe->x;
+ return;
+ }
}
if (pipe->noTransparency && !state->blendFunc) {
@@ -3188,6 +3219,318 @@ void Splash::compositeBackground(SplashColorPtr color) {
memset(bitmap->alpha, 255, bitmap->width * bitmap->height);
}
+GBool Splash::gouraudTriangleShadedFill(SplashGouraudColor *shading)
+{
+ double xdbl[3] = {0., 0., 0.};
+ double ydbl[3] = {0., 0., 0.};
+ int x[3] = {0, 0, 0};
+ int y[3] = {0, 0, 0};
+ double xt=0., xa=0., yt=0.;
+ double ca=0., ct=0.;
+
+ // triangle interpolation:
+ //
+ double scanLimitMapL[2] = {0., 0.};
+ double scanLimitMapR[2] = {0., 0.};
+ double scanColorMapL[2] = {0., 0.};
+ double scanColorMapR[2] = {0., 0.};
+ double scanColorMap[2] = {0., 0.};
+ int scanEdgeL[2] = { 0, 0 };
+ int scanEdgeR[2] = { 0, 0 };
+ GBool hasFurtherSegment = gFalse;
+
+ int scanLineOff = 0;
+ int bitmapOff = 0;
+ int scanLimitR = 0, scanLimitL = 0, Yt = 0;
+
+ int bitmapWidth = bitmap->getWidth();
+ SplashClip* clip = getClip();
+ SplashBitmap *blitTarget = bitmap;
+ SplashColorPtr bitmapData = bitmap->getDataPtr();
+ SplashColorPtr bitmapAlpha = bitmap->getAlphaPtr();
+ SplashColorPtr cur = NULL;
+ SplashCoord* userToCanvasMatrix = getMatrix();
+ SplashColorMode bitmapMode = bitmap->getMode();
+ GBool hasAlpha = (bitmapAlpha != NULL);
+ int rowSize = bitmap->getRowSize();
+ int colorComps = 0;
+ switch (bitmapMode) {
+ case splashModeMono1:
+ break;
+ case splashModeMono8:
+ colorComps=1;
+ break;
+ case splashModeRGB8:
+ colorComps=3;
+ break;
+ case splashModeBGR8:
+ colorComps=3;
+ break;
+ case splashModeXBGR8:
+ colorComps=4;
+ break;
+#if SPLASH_CMYK
+ case splashModeCMYK8:
+ colorComps=4;
+ break;
+#endif
+ }
+
+ SplashPipe pipe;
+ SplashColor cSrcVal;
+
+ pipeInit(&pipe, 0, 0, NULL, cSrcVal, state->strokeAlpha, gFalse, gFalse);
+
+ if (vectorAntialias) {
+ if (aaBuf == NULL)
+ return gFalse; // fall back to old behaviour
+ drawAAPixelInit();
+ }
+
+ // idea:
+ // 1. If pipe->noTransparency && !state->blendFunc
+ // -> blit directly into the drawing surface!
+ // -> disable alpha manually.
+ // 2. Otherwise:
+ // - blit also directly, but into an intermediate surface.
+ // Afterwards, blit the intermediate surface using the drawing pipeline.
+ // This is necessary because triangle elements can be on top of each
+ // other, so the complete shading needs to be drawn before opacity is
+ // applied.
+ // - the final step, is performed using a SplashPipe:
+ // - assign the actual color into cSrcVal: pipe uses cSrcVal by reference
+ // - invoke drawPixel(&pipe,X,Y,bNoClip);
+ GBool bDirectBlit = vectorAntialias ? gFalse : pipe.noTransparency && !state->blendFunc;
+ if (!bDirectBlit) {
+ blitTarget = new SplashBitmap(bitmap->getWidth(),
+ bitmap->getHeight(),
+ bitmap->getRowPad(),
+ bitmap->getMode(),
+ gTrue,
+ bitmap->getRowSize() >= 0);
+ bitmapData = blitTarget->getDataPtr();
+ bitmapAlpha = blitTarget->getAlphaPtr();
+
+ // initialisation seems to be necessary:
+ int S = bitmap->getWidth() * bitmap->getHeight();
+ for (int i = 0; i < S; ++i)
+ bitmapAlpha[i] = 0;
+ hasAlpha = gTrue;
+ }
+
+ if (shading->isParameterized()) {
+ double color[3];
+ double colorinterp;
+
+ for (int i = 0; i < shading->getNTriangles(); ++i) {
+ shading->getTriangle(i,
+ xdbl + 0, ydbl + 0, color + 0,
+ xdbl + 1, ydbl + 1, color + 1,
+ xdbl + 2, ydbl + 2, color + 2);
+ for (int m = 0; m < 3; ++m) {
+ xt = xdbl[m] * userToCanvasMatrix[0] + ydbl[m] * userToCanvasMatrix[2] + userToCanvasMatrix[4];
+ yt = xdbl[m] * userToCanvasMatrix[1] + ydbl[m] * userToCanvasMatrix[3] + userToCanvasMatrix[5];
+ xdbl[m] = xt;
+ ydbl[m] = yt;
+ // we operate on scanlines which are integer offsets into the
+ // raster image. The double offsets are of no use here.
+ x[m] = splashRound(xt);
+ y[m] = splashRound(yt);
+ }
+ // sort according to y coordinate to simplify sweep through scanlines:
+ // INSERTION SORT.
+ if (y[0] > y[1]) {
+ Guswap(x[0], x[1]);
+ Guswap(y[0], y[1]);
+ Guswap(color[0], color[1]);
+ }
+ // first two are sorted.
+ assert(y[0] <= y[1]);
+ if (y[1] > y[2]) {
+ int tmpX = x[2];
+ int tmpY = y[2];
+ double tmpC = color[2];
+ x[2] = x[1]; y[2] = y[1]; color[2] = color[1];
+
+ if (y[0] > tmpY) {
+ x[1] = x[0]; y[1] = y[0]; color[1] = color[0];
+ x[0] = tmpX; y[0] = tmpY; color[0] = tmpC;
+ } else {
+ x[1] = tmpX; y[1] = tmpY; color[1] = tmpC;
+ }
+ }
+ // first three are sorted
+ assert(y[0] <= y[1]);
+ assert(y[1] <= y[2]);
+ /////
+
+ // this here is det( T ) == 0
+ // where T is the matrix to map to barycentric coordinates.
+ if ((x[0] - x[2]) * (y[1] - y[2]) - (x[1] - x[2]) * (y[0] - y[2]) == 0)
+ continue; // degenerate triangle.
+
+ // this here initialises the scanline generation.
+ // We start with low Y coordinates and sweep up to the large Y
+ // coordinates.
+ //
+ // scanEdgeL[m] in {0,1,2} m=0,1
+ // scanEdgeR[m] in {0,1,2} m=0,1
+ //
+ // are the two edges between which scanlines are (currently)
+ // sweeped. The values {0,1,2} are indices into 'x' and 'y'.
+ // scanEdgeL[0] = 0 means: the left scan edge has (x[0],y[0]) as vertex.
+ //
+ scanEdgeL[0] = 0;
+ scanEdgeR[0] = 0;
+ if (y[0] == y[1]) {
+ scanEdgeL[0] = 1;
+ scanEdgeL[1] = scanEdgeR[1] = 2;
+
+ } else {
+ scanEdgeL[1] = 1; scanEdgeR[1] = 2;
+ }
+ assert(y[scanEdgeL[0]] < y[scanEdgeL[1]]);
+ assert(y[scanEdgeR[0]] < y[scanEdgeR[1]]);
+
+ // Ok. Now prepare the linear maps which map the y coordinate of
+ // the current scanline to the corresponding LEFT and RIGHT x
+ // coordinate (which define the scanline).
+ scanLimitMapL[0] = double(x[scanEdgeL[1]] - x[scanEdgeL[0]]) / (y[scanEdgeL[1]] - y[scanEdgeL[0]]);
+ scanLimitMapL[1] = x[scanEdgeL[0]] - y[scanEdgeL[0]] * scanLimitMapL[0];
+ scanLimitMapR[0] = double(x[scanEdgeR[1]] - x[scanEdgeR[0]]) / (y[scanEdgeR[1]] - y[scanEdgeR[0]]);
+ scanLimitMapR[1] = x[scanEdgeR[0]] - y[scanEdgeR[0]] * scanLimitMapR[0];
+
+ xa = y[1] * scanLimitMapL[0] + scanLimitMapL[1];
+ xt = y[1] * scanLimitMapR[0] + scanLimitMapR[1];
+ if (xa > xt) {
+ // I have "left" is to the right of "right".
+ // Exchange sides!
+ Guswap(scanEdgeL[0], scanEdgeR[0]);
+ Guswap(scanEdgeL[1], scanEdgeR[1]);
+ Guswap(scanLimitMapL[0], scanLimitMapR[0]);
+ Guswap(scanLimitMapL[1], scanLimitMapR[1]);
+ // FIXME I'm sure there is a more efficient way to check this.
+ }
+
+ // Same game: we can linearly interpolate the color based on the
+ // current y coordinate (that's correct for triangle
+ // interpolation due to linearity. We could also have done it in
+ // barycentric coordinates, but that's slightly more involved)
+ scanColorMapL[0] = (color[scanEdgeL[1]] - color[scanEdgeL[0]]) / (y[scanEdgeL[1]] - y[scanEdgeL[0]]);
+ scanColorMapL[1] = color[scanEdgeL[0]] - y[scanEdgeL[0]] * scanColorMapL[0];
+ scanColorMapR[0] = (color[scanEdgeR[1]] - color[scanEdgeR[0]]) / (y[scanEdgeR[1]] - y[scanEdgeR[0]]);
+ scanColorMapR[1] = color[scanEdgeR[0]] - y[scanEdgeR[0]] * scanColorMapR[0];
+
+ Yt = y[2];
+ hasFurtherSegment = (y[1] < y[2]);
+ scanLineOff = y[0] * rowSize;
+
+ for (int Y = y[0]; Y <= y[2]; ++Y, scanLineOff += rowSize) {
+ if (hasFurtherSegment && Y == y[1]) {
+ // SWEEP EVENT: we encountered the next segment.
+ //
+ // switch to next segment, either at left end or at right
+ // end:
+ if (scanEdgeL[1] == 1) {
+ scanEdgeL[0] = 1;
+ scanEdgeL[1] = 2;
+ scanLimitMapL[0] = double(x[scanEdgeL[1]] - x[scanEdgeL[0]]) / (y[scanEdgeL[1]] - y[scanEdgeL[0]]);
+ scanLimitMapL[1] = x[scanEdgeL[0]] - y[scanEdgeL[0]] * scanLimitMapL[0];
+
+ scanColorMapL[0] = (color[scanEdgeL[1]] - color[scanEdgeL[0]]) / (y[scanEdgeL[1]] - y[scanEdgeL[0]]);
+ scanColorMapL[1] = color[scanEdgeL[0]] - y[scanEdgeL[0]] * scanColorMapL[0];
+ } else if (scanEdgeR[1] == 1) {
+ scanEdgeR[0] = 1;
+ scanEdgeR[1] = 2;
+ scanLimitMapR[0] = double(x[scanEdgeR[1]] - x[scanEdgeR[0]]) / (y[scanEdgeR[1]] - y[scanEdgeR[0]]);
+ scanLimitMapR[1] = x[scanEdgeR[0]] - y[scanEdgeR[0]] * scanLimitMapR[0];
+
+ scanColorMapR[0] = (color[scanEdgeR[1]] - color[scanEdgeR[0]]) / (y[scanEdgeR[1]] - y[scanEdgeR[0]]);
+ scanColorMapR[1] = color[scanEdgeR[0]] - y[scanEdgeR[0]] * scanColorMapR[0];
+ }
+ assert( y[scanEdgeL[0]] < y[scanEdgeL[1]] );
+ assert( y[scanEdgeR[0]] < y[scanEdgeR[1]] );
+ hasFurtherSegment = gFalse;
+ }
+
+ yt = Y;
+
+ xa = yt * scanLimitMapL[0] + scanLimitMapL[1];
+ xt = yt * scanLimitMapR[0] + scanLimitMapR[1];
+
+ ca = yt * scanColorMapL[0] + scanColorMapL[1];
+ ct = yt * scanColorMapR[0] + scanColorMapR[1];
+
+ scanLimitL = splashRound(xa);
+ scanLimitR = splashRound(xt);
+
+ // Ok. Now: init the color interpolation depending on the X
+ // coordinate inside of the current scanline:
+ scanColorMap[0] = (scanLimitR == scanLimitL) ? 0. : ((ct - ca) / (scanLimitR - scanLimitL));
+ scanColorMap[1] = ca - scanLimitL * scanColorMap[0];
+
+ // handled by clipping:
+ // assert( scanLimitL >= 0 && scanLimitR < bitmap->getWidth() );
+ assert(scanLimitL <= scanLimitR || abs(scanLimitL - scanLimitR) <= 2); // allow rounding inaccuracies
+ assert(scanLineOff == Y * rowSize);
+
+ colorinterp = scanColorMap[0] * scanLimitL + scanColorMap[1];
+
+ bitmapOff = scanLineOff + scanLimitL * colorComps;
+ for (int X = scanLimitL; X <= scanLimitR; ++X, colorinterp += scanColorMap[0], bitmapOff += colorComps) {
+ // FIXME : standard rectangular clipping can be done for a
+ // complete scanline which is faster
+ // --> see SplashClip and its methods
+ if (!clip->test(X, Y))
+ continue;
+
+ assert(fabs(colorinterp - (scanColorMap[0] * X + scanColorMap[1])) < 1e-10);
+ assert(bitmapOff == Y * rowSize + colorComps * X && scanLineOff == Y * rowSize);
+
+ shading->getParameterizedColor(colorinterp, bitmapMode, &bitmapData[bitmapOff]);
+
+ // make the shading visible.
+ // Note that opacity is handled by the bDirectBlit stuff, see
+ // above for comments and below for implementation.
+ if (hasAlpha)
+ bitmapAlpha[Y * bitmapWidth + X] = 255;
+ }
+ }
+ }
+ } else {
+ return gFalse;
+ }
+
+ if (!bDirectBlit) {
+ // ok. Finalize the stuff by blitting the shading into the final
+ // geometry, this time respecting the rendering pipe.
+ int W = blitTarget->getWidth();
+ int H = blitTarget->getHeight();
+ cur = cSrcVal;
+
+ for (int X = 0; X < W; ++X) {
+ for (int Y = 0; Y < H; ++Y) {
+ if (!bitmapAlpha[Y * bitmapWidth + X])
+ continue; // draw only parts of the shading!
+ bitmapOff = Y * rowSize + colorComps * X;
+
+ for (int m = 0; m < colorComps; ++m)
+ cur[m] = bitmapData[bitmapOff + m];
+ if (vectorAntialias) {
+ drawAAPixel(&pipe, X, Y);
+ } else {
+ drawPixel(&pipe, X, Y, gTrue); // no clipping - has already been done.
+ }
+ }
+ }
+
+ delete blitTarget;
+ blitTarget = NULL;
+ }
+
+ return gTrue;
+}
+
SplashError Splash::blitTransparent(SplashBitmap *src, int xSrc, int ySrc,
int xDest, int yDest, int w, int h) {
SplashColor pixel;
@@ -3598,3 +3941,53 @@ void Splash::dumpXPath(SplashXPath *path) {
(path->segs[i].flags & splashXPathFlip) ? "P" : " ");
}
}
+
+SplashError Splash::shadedFill(SplashPath *path, GBool hasBBox,
+ SplashPattern *pattern) {
+ SplashPipe pipe;
+ SplashXPath *xPath;
+ SplashXPathScanner *scanner;
+ int xMinI, yMinI, xMaxI, yMaxI, x0, x1, y;
+ SplashClipResult clipRes;
+
+ if (aaBuf == NULL) { // should not happen, but to be secure
+ return splashErrGeneric;
+ }
+ if (path->length == 0) {
+ return splashErrEmptyPath;
+ }
+ xPath = new SplashXPath(path, state->matrix, state->flatness, gTrue);
+ xPath->aaScale();
+ xPath->sort();
+ scanner = new SplashXPathScanner(xPath, gFalse);
+
+ // get the min and max x and y values
+ scanner->getBBoxAA(&xMinI, &yMinI, &xMaxI, &yMaxI);
+
+ // check clipping
+ if ((clipRes = state->clip->testRect(xMinI, yMinI, xMaxI, yMaxI)) != splashClipAllOutside) {
+ // limit the y range
+ if (yMinI < state->clip->getYMinI()) {
+ yMinI = state->clip->getYMinI();
+ }
+ if (yMaxI > state->clip->getYMaxI()) {
+ yMaxI = state->clip->getYMaxI();
+ }
+
+ pipeInit(&pipe, 0, yMinI, pattern, NULL, state->fillAlpha, vectorAntialias && !hasBBox, gFalse);
+
+ // draw the spans
+ for (y = yMinI; y <= yMaxI; ++y) {
+ scanner->renderAALine(aaBuf, &x0, &x1, y);
+ if (clipRes != splashClipAllInside) {
+ state->clip->clipAALine(aaBuf, &x0, &x1, y);
+ }
+ drawAALine(&pipe, x0, x1, y);
+ }
+ }
+ opClipRes = clipRes;
+
+ delete scanner;
+ delete xPath;
+ return splashOk;
+}
diff --git a/splash/Splash.h b/splash/Splash.h
index c9d57cc..a52dc13 100644
--- a/splash/Splash.h
+++ b/splash/Splash.h
@@ -13,6 +13,8 @@
//
// Copyright (C) 2005 Marco Pesenti Gritti <mpg at redhat.com>
// Copyright (C) 2007 Albert Astals Cid <aacid at kde.org>
+// Copyright (C) 2010 Thomas Freitag <Thomas.Freitag at alfa.de>
+// 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
@@ -28,12 +30,11 @@
#include "SplashTypes.h"
#include "SplashClip.h"
+#include "SplashPattern.h"
-class Splash;
class SplashBitmap;
struct SplashGlyphBitmap;
class SplashState;
-class SplashPattern;
class SplashScreen;
class SplashPath;
class SplashXPath;
@@ -249,6 +250,12 @@ public:
void setVectorAntialias(GBool vaa) { vectorAntialias = vaa; }
#endif
+ // Do shaded fills with dynamic patterns
+ SplashError shadedFill(SplashPath *path, GBool hasBBox,
+ SplashPattern *pattern);
+ // Draw a gouraud triangle shading.
+ GBool gouraudTriangleShadedFill(SplashGouraudColor *shading);
+
private:
void pipeInit(SplashPipe *pipe, int x, int y,
diff --git a/splash/SplashBitmap.cc b/splash/SplashBitmap.cc
index f983439..51e48d3 100644
--- a/splash/SplashBitmap.cc
+++ b/splash/SplashBitmap.cc
@@ -17,6 +17,7 @@
// Copyright (C) 2009 Stefan Thomas <thomas at eload24.com>
// Copyright (C) 2010 Adrian Johnson <ajohnson at redneon.com>
// Copyright (C) 2010 Harry Roberts <harry.roberts at midnight-labs.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
@@ -44,12 +45,13 @@
// SplashBitmap
//------------------------------------------------------------------------
-SplashBitmap::SplashBitmap(int widthA, int heightA, int rowPad,
+SplashBitmap::SplashBitmap(int widthA, int heightA, int rowPadA,
SplashColorMode modeA, GBool alphaA,
GBool topDown) {
width = widthA;
height = heightA;
mode = modeA;
+ rowPad = rowPadA;
switch (mode) {
case splashModeMono1:
if (width > 0) {
diff --git a/splash/SplashBitmap.h b/splash/SplashBitmap.h
index e741a91..1c19421 100644
--- a/splash/SplashBitmap.h
+++ b/splash/SplashBitmap.h
@@ -17,6 +17,7 @@
// Copyright (C) 2009 Stefan Thomas <thomas at eload24.com>
// Copyright (C) 2010 Adrian Johnson <ajohnson at redneon.com>
// Copyright (C) 2010 Harry Roberts <harry.roberts at midnight-labs.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
@@ -56,6 +57,7 @@ public:
int getHeight() { return height; }
int getRowSize() { return rowSize; }
int getAlphaRowSize() { return width; }
+ int getRowPad() { return rowPad; }
SplashColorMode getMode() { return mode; }
SplashColorPtr getDataPtr() { return data; }
Guchar *getAlphaPtr() { return alpha; }
@@ -73,6 +75,7 @@ public:
private:
int width, height; // size of bitmap
+ int rowPad;
int rowSize; // size of one row of data, in bytes
// - negative for bottom-up bitmaps
SplashColorMode mode; // color mode
diff --git a/splash/SplashPattern.cc b/splash/SplashPattern.cc
index ce49078..b42714d 100644
--- a/splash/SplashPattern.cc
+++ b/splash/SplashPattern.cc
@@ -4,6 +4,20 @@
//
//========================================================================
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2010 Thomas Freitag <Thomas.Freitag at alfa.de>
+//
+// 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
+//
+//========================================================================
+
#include <config.h>
#ifdef USE_GCC_PRAGMAS
@@ -35,6 +49,7 @@ SplashSolidColor::SplashSolidColor(SplashColorPtr colorA) {
SplashSolidColor::~SplashSolidColor() {
}
-void SplashSolidColor::getColor(int x, int y, SplashColorPtr c) {
+GBool SplashSolidColor::getColor(int x, int y, SplashColorPtr c) {
splashColorCopy(c, color);
+ return gTrue;
}
diff --git a/splash/SplashPattern.h b/splash/SplashPattern.h
index 4e3d9ab..09e9b1a 100644
--- a/splash/SplashPattern.h
+++ b/splash/SplashPattern.h
@@ -4,6 +4,20 @@
//
//========================================================================
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2010 Thomas Freitag <Thomas.Freitag at alfa.de>
+//
+// 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
+//
+//========================================================================
+
#ifndef SPLASHPATTERN_H
#define SPLASHPATTERN_H
@@ -29,7 +43,7 @@ public:
virtual ~SplashPattern();
// Return the color value for a specific pixel.
- virtual void getColor(int x, int y, SplashColorPtr c) = 0;
+ virtual GBool getColor(int x, int y, SplashColorPtr c) = 0;
// Returns true if this pattern object will return the same color
// value for all pixels.
@@ -51,7 +65,7 @@ public:
virtual ~SplashSolidColor();
- virtual void getColor(int x, int y, SplashColorPtr c);
+ virtual GBool getColor(int x, int y, SplashColorPtr c);
virtual GBool isStatic() { return gTrue; }
@@ -60,4 +74,22 @@ private:
SplashColor color;
};
+//------------------------------------------------------------------------
+// SplashGouraudColor (needed for gouraudTriangleShadedFill)
+//------------------------------------------------------------------------
+
+class SplashGouraudColor: public SplashPattern {
+public:
+
+ virtual GBool isParameterized() = 0;
+
+ virtual int getNTriangles() = 0;
+
+ virtual void getTriangle(int i, double *x0, double *y0, double *color0,
+ double *x1, double *y1, double *color1,
+ double *x2, double *y2, double *color2) = 0;
+
+ virtual void getParameterizedColor(double t, SplashColorMode mode, SplashColorPtr c) = 0;
+};
+
#endif
More information about the poppler
mailing list