diff --git a/poppler/Function.cc b/poppler/Function.cc index e7383fd..eabf107 100644 --- a/poppler/Function.cc +++ b/poppler/Function.cc @@ -15,6 +15,7 @@ // // Copyright (C) 2006, 2008-2010 Albert Astals Cid // Copyright (C) 2006 Jeff Muizelaar +// Copyright (C) 2010 Christian Feuersänger // // 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 @@ -523,6 +524,7 @@ ExponentialFunction::ExponentialFunction(Object *funcObj, Dict *dict) { e = obj1.getNum(); obj1.free(); + isLinear = fabs(e-1.) < 1e-10; ok = gTrue; return; @@ -553,7 +555,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 2dcccb0..1e3c185 100644 --- a/poppler/Function.h +++ b/poppler/Function.h @@ -14,6 +14,7 @@ // under GPL version 2 or later // // Copyright (C) 2009 Albert Astals Cid +// Copyright (C) 2010 Christian Feuersänger // // 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 @@ -174,6 +175,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 12c0bd2..92ab524 100644 --- a/poppler/Gfx.cc +++ b/poppler/Gfx.cc @@ -2301,7 +2301,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; } @@ -2484,7 +2484,7 @@ void Gfx::doAxialShFill(GfxAxialShading *shading) { } } - if (out->useShadedFills() && + if (out->useShadedFills( shading->getType() ) && out->axialShadedFill(state, shading, tMin, tMax)) { return; } @@ -2758,7 +2758,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; @@ -2836,7 +2836,7 @@ void Gfx::doRadialShFill(GfxRadialShading *shading) { } } - if (out->useShadedFills() && + if (out->useShadedFills( shading->getType() ) && out->radialShadedFill(state, shading, sMin, sMax)) { return; } @@ -3109,6 +3109,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..fa49b1d 100644 --- a/poppler/OutputDev.h +++ b/poppler/OutputDev.h @@ -17,9 +17,10 @@ // Copyright (C) 2006 Thorkild Stray // Copyright (C) 2007 Jeff Muizelaar // Copyright (C) 2007 Adrian Johnson -// Copyright (C) 2009 Thomas Freitag +// Copyright (C) 2009, 2010 Thomas Freitag // Copyright (C) 2009 Carlos Garcia Campos // Copyright (C) 2009 Albert Astals Cid +// Copyright (C) 2010 Christian Feuersänger // // 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; @@ -85,8 +88,13 @@ 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. + // @deprecated, use useShadedFills( int type ) now virtual GBool useShadedFills() { return gFalse; } + // Does this device support specific shading types? + // see gouraudTriangleShadedFill() and patchMeshShadedFill() + virtual GBool useShadedFills( int type ) { return ( type < 4 ) ? useShadedFills() : gFalse; } + // Does this device use FillColorStop()? virtual GBool useFillColorStop() { return gFalse; } @@ -208,6 +216,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/SplashOutputDev.cc b/poppler/SplashOutputDev.cc index 0ae5bc5..2f5be7a 100644 --- a/poppler/SplashOutputDev.cc +++ b/poppler/SplashOutputDev.cc @@ -25,7 +25,8 @@ // Copyright (C) 2009 William Bader // Copyright (C) 2010 Patrick Spendrin // Copyright (C) 2010 Brian Cameron -// Copyright (C) 2010 PaweÅ‚ Wiejacha +// Copyright (C) 2010 Pawel Wiejacha +// Copyright (C) 2010 Christian Feuersänger // // 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,127 @@ 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; + int m; + GfxColorSpace* srcColorSpace = shading->getColorSpace(); + int colorComps = 3; +#if SPLASH_CMYK + if (mode == splashModeCMYK8) + colorComps=4; +#endif + + shading->getParameterizedColor(colorinterp, &src); + + if( bDirectColorTranslation ) { + for( m = 0; mgetCTM (&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. @@ -2033,7 +2155,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()); @@ -2916,7 +3038,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) { @@ -3186,3 +3308,50 @@ 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 + } + SplashGouraudColor *splashShading = new SplashGouraudPattern(bDirectColorTranslation, state, shading); + // restore vector antialias because we support it here + if (shading->isParameterized()) + setVectorAntialias(gTrue); + return splash->gouraudTriangleShadedFill(splashShading); +} + +/* implement shading routines */ +GBool SplashOutputDev::axialShadedFill(GfxState *state, GfxAxialShading *shading, double tMin, double tMax) { + double xMin, yMin, xMax, yMax; + SplashPath *path; + + // 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); + splash->shadedFill(path, shading->getHasBBox(), pattern); + state->clearPath(); + delete path; + + return gTrue; +} diff --git a/poppler/SplashOutputDev.h b/poppler/SplashOutputDev.h index adbd196..289ee5c 100644 --- a/poppler/SplashOutputDev.h +++ b/poppler/SplashOutputDev.h @@ -16,6 +16,7 @@ // Copyright (C) 2005 Takashi Iwai // Copyright (C) 2009, 2010 Thomas Freitag // Copyright (C) 2009 Carlos Garcia Campos +// Copyright (C) 2010 Christian Feuersänger // // 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; } @@ -80,7 +144,6 @@ public: // Does this device use beginType3Char/endType3Char? Otherwise, // text in Type 3 fonts will be drawn with drawChar/drawString. virtual GBool interpretType3Chars() { return gTrue; } - // This device now supports text in pattern colorspace! virtual GBool supportTextCSPattern(GfxState *state) { return state->getFillColorSpace()->getMode() == csPattern; } @@ -121,6 +184,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 5e27d42..23fe3b2 100644 --- a/splash/Splash.cc +++ b/splash/Splash.cc @@ -13,6 +13,8 @@ // // Copyright (C) 2005-2010 Albert Astals Cid // Copyright (C) 2005 Marco Pesenti Gritti +// Copyright (C) 2010 Thomas Freitag +// Copyright (C) 2010 Christian Feuersänger // // 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 #include #include +#include #include "goo/gmem.h" #include "goo/GooLikely.h" #include "SplashErrorCodes.h" @@ -55,6 +58,9 @@ static inline Guchar div255(int x) { return (Guchar)((x + (x >> 8) + 0x80) >> 8); } +template +inline void Guswap( T&a, T&b ) { T tmp = a; a=b; b=tmp; } + //------------------------------------------------------------------------ // SplashPipe //------------------------------------------------------------------------ @@ -245,7 +251,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) { @@ -3182,6 +3213,322 @@ 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 }; + bool hasFurtherSegment = false; + + int X=0,Y=0; + int scanLineOff=0; + int bitmapOff=0; + int scanLimitR=0,scanLimitL=0,Yt=0; + int i=0,m=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(); + bool 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) { + 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); + bool bDirectBlit = (vectorAntialias) ? gFalse : pipe.noTransparency && !state->blendFunc; + if( !bDirectBlit ) { + blitTarget = new SplashBitmap( + bitmap->getWidth(), + bitmap->getHeight(), + bitmap->getRowPad(), + bitmap->getMode(), + true, + bitmap->getRowSize() >= 0 ); + bitmapData = blitTarget->getDataPtr(); + bitmapAlpha = blitTarget->getAlphaPtr(); + + // initialisation seems to be necessary: + int S = bitmap->getWidth() * bitmap->getHeight(); + for( i = 0; iisParameterized() ) { + double color[3]; + double colorinterp; + + for (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( 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]; + + + Y = y[0]; + Yt= y[2]; + hasFurtherSegment = (y[1] < y[2]); + scanLineOff = Y * rowSize; + + for( 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 = false; + } + + 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( 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 false; + } + 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( X = 0; Xsegs[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 (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..d52e74f 100644 --- a/splash/Splash.h +++ b/splash/Splash.h @@ -13,6 +13,8 @@ // // Copyright (C) 2005 Marco Pesenti Gritti // Copyright (C) 2007 Albert Astals Cid +// Copyright (C) 2010 Thomas Freitag +// Copyright (C) 2010 Christian Feuersänger // // 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 @@ -249,6 +251,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 // Copyright (C) 2010 Adrian Johnson // Copyright (C) 2010 Harry Roberts +// Copyright (C) 2010 Christian Feuersänger // // 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 // Copyright (C) 2010 Adrian Johnson // Copyright (C) 2010 Harry Roberts +// Copyright (C) 2010 Christian Feuersänger // // 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 +// +// 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 #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..ad1e8d7 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 +// +// 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,24 @@ 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; + +private: +}; + #endif