diff options
Diffstat (limited to 'Build/source/libs/poppler/poppler-src/splash/Splash.cc')
-rw-r--r-- | Build/source/libs/poppler/poppler-src/splash/Splash.cc | 6479 |
1 files changed, 0 insertions, 6479 deletions
diff --git a/Build/source/libs/poppler/poppler-src/splash/Splash.cc b/Build/source/libs/poppler/poppler-src/splash/Splash.cc deleted file mode 100644 index 129d01f02ce..00000000000 --- a/Build/source/libs/poppler/poppler-src/splash/Splash.cc +++ /dev/null @@ -1,6479 +0,0 @@ -//======================================================================== -// -// Splash.cc -// -//======================================================================== - -//======================================================================== -// -// 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) 2005-2017 Albert Astals Cid <aacid@kde.org> -// Copyright (C) 2005 Marco Pesenti Gritti <mpg@redhat.com> -// Copyright (C) 2010-2016 Thomas Freitag <Thomas.Freitag@alfa.de> -// Copyright (C) 2010 Christian Feuersänger <cfeuersaenger@googlemail.com> -// Copyright (C) 2011-2013, 2015 William Bader <williambader@hotmail.com> -// Copyright (C) 2012 Markus Trippelsdorf <markus@trippelsdorf.de> -// Copyright (C) 2012, 2017 Adrian Johnson <ajohnson@redneon.com> -// Copyright (C) 2012 Matthias Kramm <kramm@quiss.org> -// -// 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 -#pragma implementation -#endif - -#include <stdlib.h> -#include <string.h> -#include <limits.h> -#include <assert.h> -#include <math.h> -#include "goo/gmem.h" -#include "goo/GooLikely.h" -#include "goo/GooList.h" -#include "poppler/Error.h" -#include "SplashErrorCodes.h" -#include "SplashMath.h" -#include "SplashBitmap.h" -#include "SplashState.h" -#include "SplashPath.h" -#include "SplashXPath.h" -#include "SplashXPathScanner.h" -#include "SplashPattern.h" -#include "SplashScreen.h" -#include "SplashFont.h" -#include "SplashGlyphBitmap.h" -#include "Splash.h" -#include <algorithm> - -//------------------------------------------------------------------------ - -#define splashAAGamma 1.5 - -// distance of Bezier control point from center for circle approximation -// = (4 * (sqrt(2) - 1) / 3) * r -#define bezierCircle ((SplashCoord)0.55228475) -#define bezierCircle2 ((SplashCoord)(0.5 * 0.55228475)) - -// Divide a 16-bit value (in [0, 255*255]) by 255, returning an 8-bit result. -static inline Guchar div255(int x) { - return (Guchar)((x + (x >> 8) + 0x80) >> 8); -} - -// Clip x to lie in [0, 255]. -static inline Guchar clip255(int x) { - return x < 0 ? 0 : x > 255 ? 255 : x; -} - -template<typename T> -inline void Guswap( T&a, T&b ) { T tmp = a; a=b; b=tmp; } - -// The PDF spec says that all pixels whose *centers* lie within the -// image target region get painted, so we want to round n+0.5 down to -// n. But this causes problems, e.g., with PDF files that fill a -// rectangle with black and then draw an image to the exact same -// rectangle, so we instead use the fill scan conversion rule. -// However, the correct rule works better for glyphs, so we also -// provide that option in fillImageMask. -#if 0 -static inline int imgCoordMungeLower(SplashCoord x) { - return splashCeil(x + 0.5) - 1; -} -static inline int imgCoordMungeUpper(SplashCoord x) { - return splashCeil(x + 0.5) - 1; -} -#else -static inline int imgCoordMungeLower(SplashCoord x) { - return splashFloor(x); -} -static inline int imgCoordMungeUpper(SplashCoord x) { - return splashFloor(x) + 1; -} -static inline int imgCoordMungeLowerC(SplashCoord x, GBool glyphMode) { - return glyphMode ? (splashCeil(x + 0.5) - 1) : splashFloor(x); -} -static inline int imgCoordMungeUpperC(SplashCoord x, GBool glyphMode) { - return glyphMode ? (splashCeil(x + 0.5) - 1) : (splashFloor(x) + 1); -} -#endif - -// Used by drawImage and fillImageMask to divide the target -// quadrilateral into sections. -struct ImageSection { - int y0, y1; // actual y range - int ia0, ia1; // vertex indices for edge A - int ib0, ib1; // vertex indices for edge A - SplashCoord xa0, ya0, xa1, ya1; // edge A - SplashCoord dxdya; // slope of edge A - SplashCoord xb0, yb0, xb1, yb1; // edge B - SplashCoord dxdyb; // slope of edge B -}; - -//------------------------------------------------------------------------ -// SplashPipe -//------------------------------------------------------------------------ - -#define splashPipeMaxStages 9 - -struct SplashPipe { - // pixel coordinates - int x, y; - - // source pattern - SplashPattern *pattern; - - // source alpha and color - Guchar aInput; - GBool usesShape; - SplashColorPtr cSrc; - SplashColor cSrcVal; - - // non-isolated group alpha0 - Guchar *alpha0Ptr; - - // knockout groups - GBool knockout; - Guchar knockoutOpacity; - - // soft mask - SplashColorPtr softMaskPtr; - - // destination alpha and color - SplashColorPtr destColorPtr; - int destColorMask; - Guchar *destAlphaPtr; - - // shape - Guchar shape; - - // result alpha and color - GBool noTransparency; - SplashPipeResultColorCtrl resultColorCtrl; - - // non-isolated group correction - GBool nonIsolatedGroup; - - // the "run" function - void (Splash::*run)(SplashPipe *pipe); -}; - -SplashPipeResultColorCtrl Splash::pipeResultColorNoAlphaBlend[] = { - splashPipeResultColorNoAlphaBlendMono, - splashPipeResultColorNoAlphaBlendMono, - splashPipeResultColorNoAlphaBlendRGB, - splashPipeResultColorNoAlphaBlendRGB, - splashPipeResultColorNoAlphaBlendRGB -#ifdef SPLASH_CMYK - , - splashPipeResultColorNoAlphaBlendCMYK, - splashPipeResultColorNoAlphaBlendDeviceN -#endif -}; - -SplashPipeResultColorCtrl Splash::pipeResultColorAlphaNoBlend[] = { - splashPipeResultColorAlphaNoBlendMono, - splashPipeResultColorAlphaNoBlendMono, - splashPipeResultColorAlphaNoBlendRGB, - splashPipeResultColorAlphaNoBlendRGB, - splashPipeResultColorAlphaNoBlendRGB -#ifdef SPLASH_CMYK - , - splashPipeResultColorAlphaNoBlendCMYK, - splashPipeResultColorAlphaNoBlendDeviceN -#endif -}; - -SplashPipeResultColorCtrl Splash::pipeResultColorAlphaBlend[] = { - splashPipeResultColorAlphaBlendMono, - splashPipeResultColorAlphaBlendMono, - splashPipeResultColorAlphaBlendRGB, - splashPipeResultColorAlphaBlendRGB, - splashPipeResultColorAlphaBlendRGB -#ifdef SPLASH_CMYK - , - splashPipeResultColorAlphaBlendCMYK, - splashPipeResultColorAlphaBlendDeviceN -#endif -}; - -//------------------------------------------------------------------------ - -static void blendXor(SplashColorPtr src, SplashColorPtr dest, - SplashColorPtr blend, SplashColorMode cm) { - int i; - - for (i = 0; i < splashColorModeNComps[cm]; ++i) { - blend[i] = src[i] ^ dest[i]; - } -} - -//------------------------------------------------------------------------ -// modified region -//------------------------------------------------------------------------ - -void Splash::clearModRegion() { - modXMin = bitmap->getWidth(); - modYMin = bitmap->getHeight(); - modXMax = -1; - modYMax = -1; -} - -inline void Splash::updateModX(int x) { - if (x < modXMin) { - modXMin = x; - } - if (x > modXMax) { - modXMax = x; - } -} - -inline void Splash::updateModY(int y) { - if (y < modYMin) { - modYMin = y; - } - if (y > modYMax) { - modYMax = y; - } -} - -//------------------------------------------------------------------------ -// pipeline -//------------------------------------------------------------------------ - -inline void Splash::pipeInit(SplashPipe *pipe, int x, int y, - SplashPattern *pattern, SplashColorPtr cSrc, - Guchar aInput, GBool usesShape, - GBool nonIsolatedGroup, - GBool knockout, Guchar knockoutOpacity) { - pipeSetXY(pipe, x, y); - pipe->pattern = NULL; - - // source color - if (pattern) { - if (pattern->isStatic()) { - pattern->getColor(x, y, pipe->cSrcVal); - } else { - pipe->pattern = pattern; - } - pipe->cSrc = pipe->cSrcVal; - } else { - pipe->cSrc = cSrc; - } - - // source alpha - pipe->aInput = aInput; - pipe->usesShape = usesShape; - pipe->shape = 0; - - // knockout - pipe->knockout = knockout; - pipe->knockoutOpacity = knockoutOpacity; - - // result alpha - if (aInput == 255 && !state->softMask && !usesShape && - !state->inNonIsolatedGroup && !nonIsolatedGroup) { - pipe->noTransparency = gTrue; - } else { - pipe->noTransparency = gFalse; - } - - // result color - if (pipe->noTransparency) { - // the !state->blendFunc case is handled separately in pipeRun - pipe->resultColorCtrl = pipeResultColorNoAlphaBlend[bitmap->mode]; - } else if (!state->blendFunc) { - pipe->resultColorCtrl = pipeResultColorAlphaNoBlend[bitmap->mode]; - } else { - pipe->resultColorCtrl = pipeResultColorAlphaBlend[bitmap->mode]; - } - - // non-isolated group correction - pipe->nonIsolatedGroup = nonIsolatedGroup; - - // select the 'run' function - pipe->run = &Splash::pipeRun; - if (!pipe->pattern && pipe->noTransparency && !state->blendFunc) { - if (bitmap->mode == splashModeMono1 && !pipe->destAlphaPtr) { - pipe->run = &Splash::pipeRunSimpleMono1; - } else if (bitmap->mode == splashModeMono8 && pipe->destAlphaPtr) { - pipe->run = &Splash::pipeRunSimpleMono8; - } else if (bitmap->mode == splashModeRGB8 && pipe->destAlphaPtr) { - pipe->run = &Splash::pipeRunSimpleRGB8; - } else if (bitmap->mode == splashModeXBGR8 && pipe->destAlphaPtr) { - pipe->run = &Splash::pipeRunSimpleXBGR8; - } else if (bitmap->mode == splashModeBGR8 && pipe->destAlphaPtr) { - pipe->run = &Splash::pipeRunSimpleBGR8; -#ifdef SPLASH_CMYK - } else if (bitmap->mode == splashModeCMYK8 && pipe->destAlphaPtr) { - pipe->run = &Splash::pipeRunSimpleCMYK8; - } else if (bitmap->mode == splashModeDeviceN8 && pipe->destAlphaPtr) { - pipe->run = &Splash::pipeRunSimpleDeviceN8; -#endif - } - } else if (!pipe->pattern && !pipe->noTransparency && !state->softMask && - pipe->usesShape && - !(state->inNonIsolatedGroup && alpha0Bitmap->alpha) && - !state->blendFunc && !pipe->nonIsolatedGroup) { - if (bitmap->mode == splashModeMono1 && !pipe->destAlphaPtr) { - pipe->run = &Splash::pipeRunAAMono1; - } else if (bitmap->mode == splashModeMono8 && pipe->destAlphaPtr) { - pipe->run = &Splash::pipeRunAAMono8; - } else if (bitmap->mode == splashModeRGB8 && pipe->destAlphaPtr) { - pipe->run = &Splash::pipeRunAARGB8; - } else if (bitmap->mode == splashModeXBGR8 && pipe->destAlphaPtr) { - pipe->run = &Splash::pipeRunAAXBGR8; - } else if (bitmap->mode == splashModeBGR8 && pipe->destAlphaPtr) { - pipe->run = &Splash::pipeRunAABGR8; -#ifdef SPLASH_CMYK - } else if (bitmap->mode == splashModeCMYK8 && pipe->destAlphaPtr) { - pipe->run = &Splash::pipeRunAACMYK8; - } else if (bitmap->mode == splashModeDeviceN8 && pipe->destAlphaPtr) { - pipe->run = &Splash::pipeRunAADeviceN8; -#endif - } - } -} - -// general case -void Splash::pipeRun(SplashPipe *pipe) { - Guchar aSrc, aDest, alphaI, alphaIm1, alpha0, aResult; - SplashColor cSrcNonIso, cDest, cBlend; - SplashColorPtr cSrc; - Guchar cResult0, cResult1, cResult2, cResult3; - int t; -#ifdef SPLASH_CMYK - int cp, mask; - Guchar cResult[SPOT_NCOMPS+4]; -#endif - - //----- source color - - // static pattern: handled in pipeInit - // fixed color: handled in pipeInit - - // dynamic pattern - if (pipe->pattern) { - if (!pipe->pattern->getColor(pipe->x, pipe->y, pipe->cSrcVal)) { - pipeIncX(pipe); - return; - } -#ifdef SPLASH_CMYK - if (bitmap->mode == splashModeCMYK8 || bitmap->mode == splashModeDeviceN8) { - if (state->fillOverprint && state->overprintMode && pipe->pattern->isCMYK()) { - Guint mask = 15; - if (pipe->cSrcVal[0] == 0) { - mask &= ~1; - } - if (pipe->cSrcVal[1] == 0) { - mask &= ~2; - } - if (pipe->cSrcVal[2] == 0) { - mask &= ~4; - } - if (pipe->cSrcVal[3] == 0) { - mask &= ~8; - } - state->overprintMask = mask; - } - } -#endif - } - - if (pipe->noTransparency && !state->blendFunc) { - - //----- write destination pixel - - switch (bitmap->mode) { - case splashModeMono1: - cResult0 = state->grayTransfer[pipe->cSrc[0]]; - if (state->screen->test(pipe->x, pipe->y, cResult0)) { - *pipe->destColorPtr |= pipe->destColorMask; - } else { - *pipe->destColorPtr &= ~pipe->destColorMask; - } - if (!(pipe->destColorMask >>= 1)) { - pipe->destColorMask = 0x80; - ++pipe->destColorPtr; - } - break; - case splashModeMono8: - *pipe->destColorPtr++ = state->grayTransfer[pipe->cSrc[0]]; - break; - case splashModeRGB8: - *pipe->destColorPtr++ = state->rgbTransferR[pipe->cSrc[0]]; - *pipe->destColorPtr++ = state->rgbTransferG[pipe->cSrc[1]]; - *pipe->destColorPtr++ = state->rgbTransferB[pipe->cSrc[2]]; - break; - case splashModeXBGR8: - *pipe->destColorPtr++ = state->rgbTransferB[pipe->cSrc[2]]; - *pipe->destColorPtr++ = state->rgbTransferG[pipe->cSrc[1]]; - *pipe->destColorPtr++ = state->rgbTransferR[pipe->cSrc[0]]; - *pipe->destColorPtr++ = 255; - break; - case splashModeBGR8: - *pipe->destColorPtr++ = state->rgbTransferB[pipe->cSrc[2]]; - *pipe->destColorPtr++ = state->rgbTransferG[pipe->cSrc[1]]; - *pipe->destColorPtr++ = state->rgbTransferR[pipe->cSrc[0]]; - break; -#ifdef SPLASH_CMYK - case splashModeCMYK8: - if (state->overprintMask & 1) { - pipe->destColorPtr[0] = (state->overprintAdditive) ? - std::min<int>(pipe->destColorPtr[0] + state->cmykTransferC[pipe->cSrc[0]], 255) : - state->cmykTransferC[pipe->cSrc[0]]; - } - if (state->overprintMask & 2) { - pipe->destColorPtr[1] = (state->overprintAdditive) ? - std::min<int>(pipe->destColorPtr[1] + state->cmykTransferM[pipe->cSrc[1]], 255) : - state->cmykTransferM[pipe->cSrc[1]]; - } - if (state->overprintMask & 4) { - pipe->destColorPtr[2] = (state->overprintAdditive) ? - std::min<int>(pipe->destColorPtr[2] + state->cmykTransferY[pipe->cSrc[2]], 255) : - state->cmykTransferY[pipe->cSrc[2]]; - } - if (state->overprintMask & 8) { - pipe->destColorPtr[3] = (state->overprintAdditive) ? - std::min<int>(pipe->destColorPtr[3] + state->cmykTransferK[pipe->cSrc[3]], 255) : - state->cmykTransferK[pipe->cSrc[3]]; - } - pipe->destColorPtr += 4; - break; - case splashModeDeviceN8: - mask = 1; - for (cp = 0; cp < SPOT_NCOMPS + 4; cp ++) { - if (state->overprintMask & mask) { - pipe->destColorPtr[cp] = state->deviceNTransfer[cp][pipe->cSrc[cp]]; - } - mask <<= 1; - } - pipe->destColorPtr += (SPOT_NCOMPS+4); - break; -#endif - } - if (pipe->destAlphaPtr) { - *pipe->destAlphaPtr++ = 255; - } - - } else { - - //----- read destination pixel - - Guchar *destColorPtr; - if (pipe->shape && state->blendFunc && pipe->knockout && alpha0Bitmap != NULL) { - destColorPtr = alpha0Bitmap->data + (alpha0Y+pipe->y)*alpha0Bitmap->rowSize; - switch (bitmap->mode) { - case splashModeMono1: - destColorPtr += (alpha0X+pipe->x) / 8; - break; - case splashModeMono8: - destColorPtr += (alpha0X+pipe->x); - break; - case splashModeRGB8: - case splashModeBGR8: - destColorPtr += (alpha0X+pipe->x) * 3; - break; - case splashModeXBGR8: -#ifdef SPLASH_CMYK - case splashModeCMYK8: -#endif - destColorPtr += (alpha0X+pipe->x) * 4; - break; -#ifdef SPLASH_CMYK - case splashModeDeviceN8: - destColorPtr += (alpha0X+pipe->x) * (SPOT_NCOMPS + 4); - break; -#endif - } - } else { - destColorPtr = pipe->destColorPtr; - } - switch (bitmap->mode) { - case splashModeMono1: - cDest[0] = (*destColorPtr & pipe->destColorMask) ? 0xff : 0x00; - break; - case splashModeMono8: - cDest[0] = *destColorPtr; - break; - case splashModeRGB8: - cDest[0] = destColorPtr[0]; - cDest[1] = destColorPtr[1]; - cDest[2] = destColorPtr[2]; - break; - case splashModeXBGR8: - cDest[0] = destColorPtr[2]; - cDest[1] = destColorPtr[1]; - cDest[2] = destColorPtr[0]; - cDest[3] = 255; - break; - case splashModeBGR8: - cDest[0] = destColorPtr[2]; - cDest[1] = destColorPtr[1]; - cDest[2] = destColorPtr[0]; - break; -#ifdef SPLASH_CMYK - case splashModeCMYK8: - cDest[0] = destColorPtr[0]; - cDest[1] = destColorPtr[1]; - cDest[2] = destColorPtr[2]; - cDest[3] = destColorPtr[3]; - break; - case splashModeDeviceN8: - for (cp = 0; cp < SPOT_NCOMPS + 4; cp++) - cDest[cp] = destColorPtr[cp]; - break; -#endif - } - if (pipe->destAlphaPtr) { - aDest = *pipe->destAlphaPtr; - } else { - aDest = 0xff; - } - - //----- source alpha - - if (state->softMask) { - if (pipe->usesShape) { - aSrc = div255(div255(pipe->aInput * *pipe->softMaskPtr++) * - pipe->shape); - } else { - aSrc = div255(pipe->aInput * *pipe->softMaskPtr++); - } - } else if (pipe->usesShape) { - aSrc = div255(pipe->aInput * pipe->shape); - } else { - aSrc = pipe->aInput; - } - - //----- non-isolated group correction - - if (pipe->nonIsolatedGroup) { - // This path is only used when Splash::composite() is called to - // composite a non-isolated group onto the backdrop. In this - // case, pipe->shape is the source (group) alpha. - if (pipe->shape == 0) { - // this value will be multiplied by zero later, so it doesn't - // matter what we use - cSrc = pipe->cSrc; - } else { - t = (aDest * 255) / pipe->shape - aDest; - switch (bitmap->mode) { -#ifdef SPLASH_CMYK - case splashModeDeviceN8: - for (cp = 0; cp < SPOT_NCOMPS + 4; cp++) - cSrcNonIso[cp] = clip255(pipe->cSrc[cp] + - ((pipe->cSrc[cp] - cDest[cp]) * t) / 255); - break; - case splashModeCMYK8: - for (cp = 0; cp < 4; cp++) - cSrcNonIso[cp] = clip255(pipe->cSrc[cp] + - ((pipe->cSrc[cp] - cDest[cp]) * t) / 255); - break; -#endif - case splashModeXBGR8: - cSrcNonIso[3] = 255; - // fallthrough - case splashModeRGB8: - case splashModeBGR8: - cSrcNonIso[2] = clip255(pipe->cSrc[2] + - ((pipe->cSrc[2] - cDest[2]) * t) / 255); - cSrcNonIso[1] = clip255(pipe->cSrc[1] + - ((pipe->cSrc[1] - cDest[1]) * t) / 255); - // fallthrough - case splashModeMono1: - case splashModeMono8: - cSrcNonIso[0] = clip255(pipe->cSrc[0] + - ((pipe->cSrc[0] - cDest[0]) * t) / 255); - break; - } - cSrc = cSrcNonIso; - // knockout: remove backdrop color - if (pipe->knockout && pipe->shape >= pipe->knockoutOpacity) { - aDest = 0; - } - } - } else { - cSrc = pipe->cSrc; - } - - //----- blend function - - if (state->blendFunc) { -#ifdef SPLASH_CMYK - if (bitmap->mode == splashModeDeviceN8) { - for (int k = 4; k < 4 + SPOT_NCOMPS; k++) { - cBlend[k] = 0; - } - } -#endif - (*state->blendFunc)(cSrc, cDest, cBlend, bitmap->mode); - } - - //----- result alpha and non-isolated group element correction - - if (pipe->noTransparency) { - alphaI = alphaIm1 = aResult = 255; - } else { - aResult = aSrc + aDest - div255(aSrc * aDest); - - // alphaI = alpha_i - // alphaIm1 = alpha_(i-1) - if (pipe->alpha0Ptr) { - alpha0 = *pipe->alpha0Ptr++; - alphaI = aResult + alpha0 - div255(aResult * alpha0); - alphaIm1 = alpha0 + aDest - div255(alpha0 * aDest); - } else { - alphaI = aResult; - alphaIm1 = aDest; - } - } - - //----- result color - - cResult0 = cResult1 = cResult2 = cResult3 = 0; // make gcc happy - - switch (pipe->resultColorCtrl) { - - case splashPipeResultColorNoAlphaBlendMono: - cResult0 = state->grayTransfer[div255((255 - aDest) * cSrc[0] + - aDest * cBlend[0])]; - break; - case splashPipeResultColorNoAlphaBlendRGB: - cResult0 = state->rgbTransferR[div255((255 - aDest) * cSrc[0] + - aDest * cBlend[0])]; - cResult1 = state->rgbTransferG[div255((255 - aDest) * cSrc[1] + - aDest * cBlend[1])]; - cResult2 = state->rgbTransferB[div255((255 - aDest) * cSrc[2] + - aDest * cBlend[2])]; - break; -#ifdef SPLASH_CMYK - case splashPipeResultColorNoAlphaBlendCMYK: - cResult0 = state->cmykTransferC[div255((255 - aDest) * cSrc[0] + - aDest * cBlend[0])]; - cResult1 = state->cmykTransferM[div255((255 - aDest) * cSrc[1] + - aDest * cBlend[1])]; - cResult2 = state->cmykTransferY[div255((255 - aDest) * cSrc[2] + - aDest * cBlend[2])]; - cResult3 = state->cmykTransferK[div255((255 - aDest) * cSrc[3] + - aDest * cBlend[3])]; - break; - case splashPipeResultColorNoAlphaBlendDeviceN: - for (cp = 0; cp < SPOT_NCOMPS+4; cp++) - cResult[cp] = state->deviceNTransfer[cp][div255((255 - aDest) * cSrc[cp] + - aDest * cBlend[cp])]; - break; -#endif - - case splashPipeResultColorAlphaNoBlendMono: - if (alphaI == 0) { - cResult0 = 0; - } else { - cResult0 = state->grayTransfer[((alphaI - aSrc) * cDest[0] + - aSrc * cSrc[0]) / alphaI]; - } - break; - case splashPipeResultColorAlphaNoBlendRGB: - if (alphaI == 0) { - cResult0 = 0; - cResult1 = 0; - cResult2 = 0; - } else { - cResult0 = state->rgbTransferR[((alphaI - aSrc) * cDest[0] + - aSrc * cSrc[0]) / alphaI]; - cResult1 = state->rgbTransferG[((alphaI - aSrc) * cDest[1] + - aSrc * cSrc[1]) / alphaI]; - cResult2 = state->rgbTransferB[((alphaI - aSrc) * cDest[2] + - aSrc * cSrc[2]) / alphaI]; - } - break; -#ifdef SPLASH_CMYK - case splashPipeResultColorAlphaNoBlendCMYK: - if (alphaI == 0) { - cResult0 = 0; - cResult1 = 0; - cResult2 = 0; - cResult3 = 0; - } else { - cResult0 = state->cmykTransferC[((alphaI - aSrc) * cDest[0] + - aSrc * cSrc[0]) / alphaI]; - cResult1 = state->cmykTransferM[((alphaI - aSrc) * cDest[1] + - aSrc * cSrc[1]) / alphaI]; - cResult2 = state->cmykTransferY[((alphaI - aSrc) * cDest[2] + - aSrc * cSrc[2]) / alphaI]; - cResult3 = state->cmykTransferK[((alphaI - aSrc) * cDest[3] + - aSrc * cSrc[3]) / alphaI]; - } - break; - case splashPipeResultColorAlphaNoBlendDeviceN: - if (alphaI == 0) { - for (cp = 0; cp < SPOT_NCOMPS+4; cp++) - cResult[cp] = 0; - } else { - for (cp = 0; cp < SPOT_NCOMPS+4; cp++) - cResult[cp] = state->deviceNTransfer[cp][((alphaI - aSrc) * cDest[cp] + - aSrc * cSrc[cp]) / alphaI]; - } - break; -#endif - - case splashPipeResultColorAlphaBlendMono: - if (alphaI == 0) { - cResult0 = 0; - } else { - cResult0 = state->grayTransfer[((alphaI - aSrc) * cDest[0] + - aSrc * ((255 - alphaIm1) * cSrc[0] + - alphaIm1 * cBlend[0]) / 255) / - alphaI]; - } - break; - case splashPipeResultColorAlphaBlendRGB: - if (alphaI == 0) { - cResult0 = 0; - cResult1 = 0; - cResult2 = 0; - } else { - cResult0 = state->rgbTransferR[((alphaI - aSrc) * cDest[0] + - aSrc * ((255 - alphaIm1) * cSrc[0] + - alphaIm1 * cBlend[0]) / 255) / - alphaI]; - cResult1 = state->rgbTransferG[((alphaI - aSrc) * cDest[1] + - aSrc * ((255 - alphaIm1) * cSrc[1] + - alphaIm1 * cBlend[1]) / 255) / - alphaI]; - cResult2 = state->rgbTransferB[((alphaI - aSrc) * cDest[2] + - aSrc * ((255 - alphaIm1) * cSrc[2] + - alphaIm1 * cBlend[2]) / 255) / - alphaI]; - } - break; -#ifdef SPLASH_CMYK - case splashPipeResultColorAlphaBlendCMYK: - if (alphaI == 0) { - cResult0 = 0; - cResult1 = 0; - cResult2 = 0; - cResult3 = 0; - } else { - cResult0 = state->cmykTransferC[((alphaI - aSrc) * cDest[0] + - aSrc * ((255 - alphaIm1) * cSrc[0] + - alphaIm1 * cBlend[0]) / 255) / - alphaI]; - cResult1 = state->cmykTransferM[((alphaI - aSrc) * cDest[1] + - aSrc * ((255 - alphaIm1) * cSrc[1] + - alphaIm1 * cBlend[1]) / 255) / - alphaI]; - cResult2 = state->cmykTransferY[((alphaI - aSrc) * cDest[2] + - aSrc * ((255 - alphaIm1) * cSrc[2] + - alphaIm1 * cBlend[2]) / 255) / - alphaI]; - cResult3 = state->cmykTransferK[((alphaI - aSrc) * cDest[3] + - aSrc * ((255 - alphaIm1) * cSrc[3] + - alphaIm1 * cBlend[3]) / 255) / - alphaI]; - } - break; - case splashPipeResultColorAlphaBlendDeviceN: - if (alphaI == 0) { - for (cp = 0; cp < SPOT_NCOMPS+4; cp++) - cResult[cp] = 0; - } else { - for (cp = 0; cp < SPOT_NCOMPS+4; cp++) - cResult[cp] = state->deviceNTransfer[cp][((alphaI - aSrc) * cDest[cp] + - aSrc * ((255 - alphaIm1) * cSrc[cp] + - alphaIm1 * cBlend[cp]) / 255) / - alphaI]; - } - break; -#endif - } - - //----- write destination pixel - - switch (bitmap->mode) { - case splashModeMono1: - if (state->screen->test(pipe->x, pipe->y, cResult0)) { - *pipe->destColorPtr |= pipe->destColorMask; - } else { - *pipe->destColorPtr &= ~pipe->destColorMask; - } - if (!(pipe->destColorMask >>= 1)) { - pipe->destColorMask = 0x80; - ++pipe->destColorPtr; - } - break; - case splashModeMono8: - *pipe->destColorPtr++ = cResult0; - break; - case splashModeRGB8: - *pipe->destColorPtr++ = cResult0; - *pipe->destColorPtr++ = cResult1; - *pipe->destColorPtr++ = cResult2; - break; - case splashModeXBGR8: - *pipe->destColorPtr++ = cResult2; - *pipe->destColorPtr++ = cResult1; - *pipe->destColorPtr++ = cResult0; - *pipe->destColorPtr++ = 255; - break; - case splashModeBGR8: - *pipe->destColorPtr++ = cResult2; - *pipe->destColorPtr++ = cResult1; - *pipe->destColorPtr++ = cResult0; - break; -#ifdef SPLASH_CMYK - case splashModeCMYK8: - if (state->overprintMask & 1) { - pipe->destColorPtr[0] = (state->overprintAdditive) ? - std::min<int>(pipe->destColorPtr[0] + cResult0, 255) : - cResult0; - } - if (state->overprintMask & 2) { - pipe->destColorPtr[1] = (state->overprintAdditive) ? - std::min<int>(pipe->destColorPtr[1] + cResult1, 255) : - cResult1; - } - if (state->overprintMask & 4) { - pipe->destColorPtr[2] = (state->overprintAdditive) ? - std::min<int>(pipe->destColorPtr[2] + cResult2, 255) : - cResult2; - } - if (state->overprintMask & 8) { - pipe->destColorPtr[3] = (state->overprintAdditive) ? - std::min<int>(pipe->destColorPtr[3] + cResult3, 255) : - cResult3; - } - pipe->destColorPtr += 4; - break; - case splashModeDeviceN8: - mask = 1; - for (cp = 0; cp < SPOT_NCOMPS+4; cp++) { - if (state->overprintMask & mask) { - pipe->destColorPtr[cp] = cResult[cp]; - } - mask <<=1; - } - pipe->destColorPtr += (SPOT_NCOMPS+4); - break; -#endif - } - if (pipe->destAlphaPtr) { - *pipe->destAlphaPtr++ = aResult; - } - - } - - ++pipe->x; -} - -// special case: -// !pipe->pattern && pipe->noTransparency && !state->blendFunc && -// bitmap->mode == splashModeMono1 && !pipe->destAlphaPtr) { -void Splash::pipeRunSimpleMono1(SplashPipe *pipe) { - Guchar cResult0; - - //----- write destination pixel - cResult0 = state->grayTransfer[pipe->cSrc[0]]; - if (state->screen->test(pipe->x, pipe->y, cResult0)) { - *pipe->destColorPtr |= pipe->destColorMask; - } else { - *pipe->destColorPtr &= ~pipe->destColorMask; - } - if (!(pipe->destColorMask >>= 1)) { - pipe->destColorMask = 0x80; - ++pipe->destColorPtr; - } - - ++pipe->x; -} - -// special case: -// !pipe->pattern && pipe->noTransparency && !state->blendFunc && -// bitmap->mode == splashModeMono8 && pipe->destAlphaPtr) { -void Splash::pipeRunSimpleMono8(SplashPipe *pipe) { - //----- write destination pixel - *pipe->destColorPtr++ = state->grayTransfer[pipe->cSrc[0]]; - *pipe->destAlphaPtr++ = 255; - - ++pipe->x; -} - -// special case: -// !pipe->pattern && pipe->noTransparency && !state->blendFunc && -// bitmap->mode == splashModeRGB8 && pipe->destAlphaPtr) { -void Splash::pipeRunSimpleRGB8(SplashPipe *pipe) { - //----- write destination pixel - *pipe->destColorPtr++ = state->rgbTransferR[pipe->cSrc[0]]; - *pipe->destColorPtr++ = state->rgbTransferG[pipe->cSrc[1]]; - *pipe->destColorPtr++ = state->rgbTransferB[pipe->cSrc[2]]; - *pipe->destAlphaPtr++ = 255; - - ++pipe->x; -} - -// special case: -// !pipe->pattern && pipe->noTransparency && !state->blendFunc && -// bitmap->mode == splashModeXBGR8 && pipe->destAlphaPtr) { -void Splash::pipeRunSimpleXBGR8(SplashPipe *pipe) { - //----- write destination pixel - *pipe->destColorPtr++ = state->rgbTransferB[pipe->cSrc[2]]; - *pipe->destColorPtr++ = state->rgbTransferG[pipe->cSrc[1]]; - *pipe->destColorPtr++ = state->rgbTransferR[pipe->cSrc[0]]; - *pipe->destColorPtr++ = 255; - *pipe->destAlphaPtr++ = 255; - - ++pipe->x; -} - -// special case: -// !pipe->pattern && pipe->noTransparency && !state->blendFunc && -// bitmap->mode == splashModeBGR8 && pipe->destAlphaPtr) { -void Splash::pipeRunSimpleBGR8(SplashPipe *pipe) { - //----- write destination pixel - *pipe->destColorPtr++ = state->rgbTransferB[pipe->cSrc[2]]; - *pipe->destColorPtr++ = state->rgbTransferG[pipe->cSrc[1]]; - *pipe->destColorPtr++ = state->rgbTransferR[pipe->cSrc[0]]; - *pipe->destAlphaPtr++ = 255; - - ++pipe->x; -} - -#ifdef SPLASH_CMYK -// special case: -// !pipe->pattern && pipe->noTransparency && !state->blendFunc && -// bitmap->mode == splashModeCMYK8 && pipe->destAlphaPtr) { -void Splash::pipeRunSimpleCMYK8(SplashPipe *pipe) { - //----- write destination pixel - if (state->overprintMask & 1) { - pipe->destColorPtr[0] = (state->overprintAdditive) ? - std::min<int>(pipe->destColorPtr[0] + state->cmykTransferC[pipe->cSrc[0]], 255) : - state->cmykTransferC[pipe->cSrc[0]]; - } - if (state->overprintMask & 2) { - pipe->destColorPtr[1] = (state->overprintAdditive) ? - std::min<int>(pipe->destColorPtr[1] + state->cmykTransferM[pipe->cSrc[1]], 255) : - state->cmykTransferM[pipe->cSrc[1]]; - } - if (state->overprintMask & 4) { - pipe->destColorPtr[2] = (state->overprintAdditive) ? - std::min<int>(pipe->destColorPtr[2] + state->cmykTransferY[pipe->cSrc[2]], 255) : - state->cmykTransferY[pipe->cSrc[2]]; - } - if (state->overprintMask & 8) { - pipe->destColorPtr[3] = (state->overprintAdditive) ? - std::min<int>(pipe->destColorPtr[3] + state->cmykTransferK[pipe->cSrc[3]], 255) : - state->cmykTransferK[pipe->cSrc[3]]; - } - pipe->destColorPtr += 4; - *pipe->destAlphaPtr++ = 255; - - ++pipe->x; -} - -// special case: -// !pipe->pattern && pipe->noTransparency && !state->blendFunc && -// bitmap->mode == splashModeDeviceN8 && pipe->destAlphaPtr) { -void Splash::pipeRunSimpleDeviceN8(SplashPipe *pipe) { - //----- write destination pixel - int mask = 1; - for (int cp = 0; cp < SPOT_NCOMPS+4; cp++) { - if (state->overprintMask & mask) { - pipe->destColorPtr[cp] = state->deviceNTransfer[cp][pipe->cSrc[cp]]; - } - mask <<=1; - } - pipe->destColorPtr += (SPOT_NCOMPS+4); - *pipe->destAlphaPtr++ = 255; - - ++pipe->x; -} -#endif - -// special case: -// !pipe->pattern && !pipe->noTransparency && !state->softMask && -// pipe->usesShape && !pipe->alpha0Ptr && !state->blendFunc && -// !pipe->nonIsolatedGroup && -// bitmap->mode == splashModeMono1 && !pipe->destAlphaPtr -void Splash::pipeRunAAMono1(SplashPipe *pipe) { - Guchar aSrc; - SplashColor cDest; - Guchar cResult0; - - //----- read destination pixel - cDest[0] = (*pipe->destColorPtr & pipe->destColorMask) ? 0xff : 0x00; - - //----- source alpha - aSrc = div255(pipe->aInput * pipe->shape); - - //----- result color - // note: aDest = alpha2 = aResult = 0xff - cResult0 = state->grayTransfer[(Guchar)div255((0xff - aSrc) * cDest[0] + - aSrc * pipe->cSrc[0])]; - - //----- write destination pixel - if (state->screen->test(pipe->x, pipe->y, cResult0)) { - *pipe->destColorPtr |= pipe->destColorMask; - } else { - *pipe->destColorPtr &= ~pipe->destColorMask; - } - if (!(pipe->destColorMask >>= 1)) { - pipe->destColorMask = 0x80; - ++pipe->destColorPtr; - } - - ++pipe->x; -} - -// special case: -// !pipe->pattern && !pipe->noTransparency && !state->softMask && -// pipe->usesShape && !pipe->alpha0Ptr && !state->blendFunc && -// !pipe->nonIsolatedGroup && -// bitmap->mode == splashModeMono8 && pipe->destAlphaPtr -void Splash::pipeRunAAMono8(SplashPipe *pipe) { - Guchar aSrc, aDest, alpha2, aResult; - SplashColor cDest; - Guchar cResult0; - - //----- read destination pixel - cDest[0] = *pipe->destColorPtr; - aDest = *pipe->destAlphaPtr; - - //----- source alpha - aSrc = div255(pipe->aInput * pipe->shape); - - //----- result alpha and non-isolated group element correction - aResult = aSrc + aDest - div255(aSrc * aDest); - alpha2 = aResult; - - //----- result color - if (alpha2 == 0) { - cResult0 = 0; - } else { - cResult0 = state->grayTransfer[(Guchar)(((alpha2 - aSrc) * cDest[0] + - aSrc * pipe->cSrc[0]) / alpha2)]; - } - - //----- write destination pixel - *pipe->destColorPtr++ = cResult0; - *pipe->destAlphaPtr++ = aResult; - - ++pipe->x; -} - -// special case: -// !pipe->pattern && !pipe->noTransparency && !state->softMask && -// pipe->usesShape && !pipe->alpha0Ptr && !state->blendFunc && -// !pipe->nonIsolatedGroup && -// bitmap->mode == splashModeRGB8 && pipe->destAlphaPtr -void Splash::pipeRunAARGB8(SplashPipe *pipe) { - Guchar aSrc, aDest, alpha2, aResult; - SplashColor cDest; - Guchar cResult0, cResult1, cResult2; - - //----- read destination pixel - cDest[0] = pipe->destColorPtr[0]; - cDest[1] = pipe->destColorPtr[1]; - cDest[2] = pipe->destColorPtr[2]; - aDest = *pipe->destAlphaPtr; - - //----- source alpha - aSrc = div255(pipe->aInput * pipe->shape); - - //----- result alpha and non-isolated group element correction - aResult = aSrc + aDest - div255(aSrc * aDest); - alpha2 = aResult; - - //----- result color - if (alpha2 == 0) { - cResult0 = 0; - cResult1 = 0; - cResult2 = 0; - } else { - cResult0 = state->rgbTransferR[(Guchar)(((alpha2 - aSrc) * cDest[0] + - aSrc * pipe->cSrc[0]) / alpha2)]; - cResult1 = state->rgbTransferG[(Guchar)(((alpha2 - aSrc) * cDest[1] + - aSrc * pipe->cSrc[1]) / alpha2)]; - cResult2 = state->rgbTransferB[(Guchar)(((alpha2 - aSrc) * cDest[2] + - aSrc * pipe->cSrc[2]) / alpha2)]; - } - - //----- write destination pixel - *pipe->destColorPtr++ = cResult0; - *pipe->destColorPtr++ = cResult1; - *pipe->destColorPtr++ = cResult2; - *pipe->destAlphaPtr++ = aResult; - - ++pipe->x; -} - -// special case: -// !pipe->pattern && !pipe->noTransparency && !state->softMask && -// pipe->usesShape && !pipe->alpha0Ptr && !state->blendFunc && -// !pipe->nonIsolatedGroup && -// bitmap->mode == splashModeXBGR8 && pipe->destAlphaPtr -void Splash::pipeRunAAXBGR8(SplashPipe *pipe) { - Guchar aSrc, aDest, alpha2, aResult; - SplashColor cDest; - Guchar cResult0, cResult1, cResult2; - - //----- read destination pixel - cDest[0] = pipe->destColorPtr[2]; - cDest[1] = pipe->destColorPtr[1]; - cDest[2] = pipe->destColorPtr[0]; - aDest = *pipe->destAlphaPtr; - - //----- source alpha - aSrc = div255(pipe->aInput * pipe->shape); - - //----- result alpha and non-isolated group element correction - aResult = aSrc + aDest - div255(aSrc * aDest); - alpha2 = aResult; - - //----- result color - if (alpha2 == 0) { - cResult0 = 0; - cResult1 = 0; - cResult2 = 0; - } else { - cResult0 = state->rgbTransferR[(Guchar)(((alpha2 - aSrc) * cDest[0] + - aSrc * pipe->cSrc[0]) / alpha2)]; - cResult1 = state->rgbTransferG[(Guchar)(((alpha2 - aSrc) * cDest[1] + - aSrc * pipe->cSrc[1]) / alpha2)]; - cResult2 = state->rgbTransferB[(Guchar)(((alpha2 - aSrc) * cDest[2] + - aSrc * pipe->cSrc[2]) / alpha2)]; - } - - //----- write destination pixel - *pipe->destColorPtr++ = cResult2; - *pipe->destColorPtr++ = cResult1; - *pipe->destColorPtr++ = cResult0; - *pipe->destColorPtr++ = 255; - *pipe->destAlphaPtr++ = aResult; - - ++pipe->x; -} - -// special case: -// !pipe->pattern && !pipe->noTransparency && !state->softMask && -// pipe->usesShape && !pipe->alpha0Ptr && !state->blendFunc && -// !pipe->nonIsolatedGroup && -// bitmap->mode == splashModeBGR8 && pipe->destAlphaPtr -void Splash::pipeRunAABGR8(SplashPipe *pipe) { - Guchar aSrc, aDest, alpha2, aResult; - SplashColor cDest; - Guchar cResult0, cResult1, cResult2; - - //----- read destination pixel - cDest[0] = pipe->destColorPtr[2]; - cDest[1] = pipe->destColorPtr[1]; - cDest[2] = pipe->destColorPtr[0]; - aDest = *pipe->destAlphaPtr; - - //----- source alpha - aSrc = div255(pipe->aInput * pipe->shape); - - //----- result alpha and non-isolated group element correction - aResult = aSrc + aDest - div255(aSrc * aDest); - alpha2 = aResult; - - //----- result color - if (alpha2 == 0) { - cResult0 = 0; - cResult1 = 0; - cResult2 = 0; - } else { - cResult0 = state->rgbTransferR[(Guchar)(((alpha2 - aSrc) * cDest[0] + - aSrc * pipe->cSrc[0]) / alpha2)]; - cResult1 = state->rgbTransferG[(Guchar)(((alpha2 - aSrc) * cDest[1] + - aSrc * pipe->cSrc[1]) / alpha2)]; - cResult2 = state->rgbTransferB[(Guchar)(((alpha2 - aSrc) * cDest[2] + - aSrc * pipe->cSrc[2]) / alpha2)]; - } - - //----- write destination pixel - *pipe->destColorPtr++ = cResult2; - *pipe->destColorPtr++ = cResult1; - *pipe->destColorPtr++ = cResult0; - *pipe->destAlphaPtr++ = aResult; - - ++pipe->x; -} - -#ifdef SPLASH_CMYK -// special case: -// !pipe->pattern && !pipe->noTransparency && !state->softMask && -// pipe->usesShape && !pipe->alpha0Ptr && !state->blendFunc && -// !pipe->nonIsolatedGroup && -// bitmap->mode == splashModeCMYK8 && pipe->destAlphaPtr -void Splash::pipeRunAACMYK8(SplashPipe *pipe) { - Guchar aSrc, aDest, alpha2, aResult; - SplashColor cDest; - Guchar cResult0, cResult1, cResult2, cResult3; - - //----- read destination pixel - cDest[0] = pipe->destColorPtr[0]; - cDest[1] = pipe->destColorPtr[1]; - cDest[2] = pipe->destColorPtr[2]; - cDest[3] = pipe->destColorPtr[3]; - aDest = *pipe->destAlphaPtr; - - //----- source alpha - aSrc = div255(pipe->aInput * pipe->shape); - - //----- result alpha and non-isolated group element correction - aResult = aSrc + aDest - div255(aSrc * aDest); - alpha2 = aResult; - - //----- result color - if (alpha2 == 0) { - cResult0 = 0; - cResult1 = 0; - cResult2 = 0; - cResult3 = 0; - } else { - cResult0 = state->cmykTransferC[(Guchar)(((alpha2 - aSrc) * cDest[0] + - aSrc * pipe->cSrc[0]) / alpha2)]; - cResult1 = state->cmykTransferM[(Guchar)(((alpha2 - aSrc) * cDest[1] + - aSrc * pipe->cSrc[1]) / alpha2)]; - cResult2 = state->cmykTransferY[(Guchar)(((alpha2 - aSrc) * cDest[2] + - aSrc * pipe->cSrc[2]) / alpha2)]; - cResult3 = state->cmykTransferK[(Guchar)(((alpha2 - aSrc) * cDest[3] + - aSrc * pipe->cSrc[3]) / alpha2)]; - } - - //----- write destination pixel - if (state->overprintMask & 1) { - pipe->destColorPtr[0] = (state->overprintAdditive && pipe->shape != 0) ? - std::min<int>(pipe->destColorPtr[0] + cResult0, 255) : - cResult0; - } - if (state->overprintMask & 2) { - pipe->destColorPtr[1] = (state->overprintAdditive && pipe->shape != 0) ? - std::min<int>(pipe->destColorPtr[1] + cResult1, 255) : - cResult1; - } - if (state->overprintMask & 4) { - pipe->destColorPtr[2] = (state->overprintAdditive && pipe->shape != 0) ? - std::min<int>(pipe->destColorPtr[2] + cResult2, 255) : - cResult2; - } - if (state->overprintMask & 8) { - pipe->destColorPtr[3] = (state->overprintAdditive && pipe->shape != 0) ? - std::min<int>(pipe->destColorPtr[3] + cResult3, 255) : - cResult3; - } - pipe->destColorPtr += 4; - *pipe->destAlphaPtr++ = aResult; - - ++pipe->x; -} - -// special case: -// !pipe->pattern && !pipe->noTransparency && !state->softMask && -// pipe->usesShape && !pipe->alpha0Ptr && !state->blendFunc && -// !pipe->nonIsolatedGroup && -// bitmap->mode == splashModeDeviceN8 && pipe->destAlphaPtr -void Splash::pipeRunAADeviceN8(SplashPipe *pipe) { - Guchar aSrc, aDest, alpha2, aResult; - SplashColor cDest; - Guchar cResult[SPOT_NCOMPS+4]; - int cp, mask; - - //----- read destination pixel - for (cp=0; cp < SPOT_NCOMPS+4; cp++) - cDest[cp] = pipe->destColorPtr[cp]; - aDest = *pipe->destAlphaPtr; - - //----- source alpha - aSrc = div255(pipe->aInput * pipe->shape); - - //----- result alpha and non-isolated group element correction - aResult = aSrc + aDest - div255(aSrc * aDest); - alpha2 = aResult; - - //----- result color - if (alpha2 == 0) { - for (cp=0; cp < SPOT_NCOMPS+4; cp++) - cResult[cp] = 0; - } else { - for (cp=0; cp < SPOT_NCOMPS+4; cp++) - cResult[cp] = state->deviceNTransfer[cp][(Guchar)(((alpha2 - aSrc) * cDest[cp] + - aSrc * pipe->cSrc[cp]) / alpha2)]; - } - - //----- write destination pixel - mask = 1; - for (cp=0; cp < SPOT_NCOMPS+4; cp++) { - if (state->overprintMask & mask) { - pipe->destColorPtr[cp] = cResult[cp]; - } - mask <<= 1; - } - pipe->destColorPtr += (SPOT_NCOMPS+4); - *pipe->destAlphaPtr++ = aResult; - - ++pipe->x; -} -#endif - -inline void Splash::pipeSetXY(SplashPipe *pipe, int x, int y) { - pipe->x = x; - pipe->y = y; - if (state->softMask) { - pipe->softMaskPtr = - &state->softMask->data[y * state->softMask->rowSize + x]; - } - switch (bitmap->mode) { - case splashModeMono1: - pipe->destColorPtr = &bitmap->data[y * bitmap->rowSize + (x >> 3)]; - pipe->destColorMask = 0x80 >> (x & 7); - break; - case splashModeMono8: - pipe->destColorPtr = &bitmap->data[y * bitmap->rowSize + x]; - break; - case splashModeRGB8: - case splashModeBGR8: - pipe->destColorPtr = &bitmap->data[y * bitmap->rowSize + 3 * x]; - break; - case splashModeXBGR8: - pipe->destColorPtr = &bitmap->data[y * bitmap->rowSize + 4 * x]; - break; -#ifdef SPLASH_CMYK - case splashModeCMYK8: - pipe->destColorPtr = &bitmap->data[y * bitmap->rowSize + 4 * x]; - break; - case splashModeDeviceN8: - pipe->destColorPtr = &bitmap->data[y * bitmap->rowSize + (SPOT_NCOMPS + 4) * x]; - break; -#endif - } - if (bitmap->alpha) { - pipe->destAlphaPtr = &bitmap->alpha[y * bitmap->width + x]; - } else { - pipe->destAlphaPtr = NULL; - } - if (state->inNonIsolatedGroup && alpha0Bitmap->alpha) { - pipe->alpha0Ptr = - &alpha0Bitmap->alpha[(alpha0Y + y) * alpha0Bitmap->width + - (alpha0X + x)]; - } else { - pipe->alpha0Ptr = NULL; - } -} - -inline void Splash::pipeIncX(SplashPipe *pipe) { - ++pipe->x; - if (state->softMask) { - ++pipe->softMaskPtr; - } - switch (bitmap->mode) { - case splashModeMono1: - if (!(pipe->destColorMask >>= 1)) { - pipe->destColorMask = 0x80; - ++pipe->destColorPtr; - } - break; - case splashModeMono8: - ++pipe->destColorPtr; - break; - case splashModeRGB8: - case splashModeBGR8: - pipe->destColorPtr += 3; - break; - case splashModeXBGR8: - pipe->destColorPtr += 4; - break; -#ifdef SPLASH_CMYK - case splashModeCMYK8: - pipe->destColorPtr += 4; - break; - case splashModeDeviceN8: - pipe->destColorPtr += (SPOT_NCOMPS+4); - break; -#endif - } - if (pipe->destAlphaPtr) { - ++pipe->destAlphaPtr; - } - if (pipe->alpha0Ptr) { - ++pipe->alpha0Ptr; - } -} - -inline void Splash::drawPixel(SplashPipe *pipe, int x, int y, GBool noClip) { - if (unlikely(y < 0)) - return; - - if (noClip || state->clip->test(x, y)) { - pipeSetXY(pipe, x, y); - (this->*pipe->run)(pipe); - updateModX(x); - updateModY(y); - } -} - -inline void Splash::drawAAPixelInit() { - aaBufY = -1; -} - -inline void Splash::drawAAPixel(SplashPipe *pipe, int x, int y) { -#if splashAASize == 4 - static int bitCount4[16] = { 0, 1, 1, 2, 1, 2, 2, 3, - 1, 2, 2, 3, 2, 3, 3, 4 }; - int w; -#else - int xx, yy; -#endif - SplashColorPtr p; - int x0, x1, t; - - if (x < 0 || x >= bitmap->width || - y < state->clip->getYMinI() || y > state->clip->getYMaxI()) { - return; - } - - // update aaBuf - if (y != aaBufY) { - memset(aaBuf->getDataPtr(), 0xff, - aaBuf->getRowSize() * aaBuf->getHeight()); - x0 = 0; - x1 = bitmap->width - 1; - state->clip->clipAALine(aaBuf, &x0, &x1, y); - aaBufY = y; - } - - // compute the shape value -#if splashAASize == 4 - p = aaBuf->getDataPtr() + (x >> 1); - w = aaBuf->getRowSize(); - if (x & 1) { - t = bitCount4[*p & 0x0f] + bitCount4[p[w] & 0x0f] + - bitCount4[p[2*w] & 0x0f] + bitCount4[p[3*w] & 0x0f]; - } else { - t = bitCount4[*p >> 4] + bitCount4[p[w] >> 4] + - bitCount4[p[2*w] >> 4] + bitCount4[p[3*w] >> 4]; - } -#else - t = 0; - for (yy = 0; yy < splashAASize; ++yy) { - for (xx = 0; xx < splashAASize; ++xx) { - p = aaBuf->getDataPtr() + yy * aaBuf->getRowSize() + - ((x * splashAASize + xx) >> 3); - t += (*p >> (7 - ((x * splashAASize + xx) & 7))) & 1; - } - } -#endif - - // draw the pixel - if (t != 0) { - pipeSetXY(pipe, x, y); - pipe->shape = div255(aaGamma[t] * pipe->shape); - (this->*pipe->run)(pipe); - updateModX(x); - updateModY(y); - } -} - -inline void Splash::drawSpan(SplashPipe *pipe, int x0, int x1, int y, - GBool noClip) { - int x; - - if (noClip) { - pipeSetXY(pipe, x0, y); - for (x = x0; x <= x1; ++x) { - (this->*pipe->run)(pipe); - } - updateModX(x0); - updateModX(x1); - updateModY(y); - } else { - if (x0 < state->clip->getXMinI()) { - x0 = state->clip->getXMinI(); - } - if (x1 > state->clip->getXMaxI()) { - x1 = state->clip->getXMaxI(); - } - pipeSetXY(pipe, x0, y); - for (x = x0; x <= x1; ++x) { - if (state->clip->test(x, y)) { - (this->*pipe->run)(pipe); - updateModX(x); - updateModY(y); - } else { - pipeIncX(pipe); - } - } - } -} - -inline void Splash::drawAALine(SplashPipe *pipe, int x0, int x1, int y, GBool adjustLine, Guchar lineOpacity) { -#if splashAASize == 4 - static int bitCount4[16] = { 0, 1, 1, 2, 1, 2, 2, 3, - 1, 2, 2, 3, 2, 3, 3, 4 }; - SplashColorPtr p0, p1, p2, p3; - int t; -#else - SplashColorPtr p; - int xx, yy, t; -#endif - int x; - -#if splashAASize == 4 - p0 = aaBuf->getDataPtr() + (x0 >> 1); - p1 = p0 + aaBuf->getRowSize(); - p2 = p1 + aaBuf->getRowSize(); - p3 = p2 + aaBuf->getRowSize(); -#endif - pipeSetXY(pipe, x0, y); - for (x = x0; x <= x1; ++x) { - - // compute the shape value -#if splashAASize == 4 - if (x & 1) { - t = bitCount4[*p0 & 0x0f] + bitCount4[*p1 & 0x0f] + - bitCount4[*p2 & 0x0f] + bitCount4[*p3 & 0x0f]; - ++p0; ++p1; ++p2; ++p3; - } else { - t = bitCount4[*p0 >> 4] + bitCount4[*p1 >> 4] + - bitCount4[*p2 >> 4] + bitCount4[*p3 >> 4]; - } -#else - t = 0; - for (yy = 0; yy < splashAASize; ++yy) { - for (xx = 0; xx < splashAASize; ++xx) { - p = aaBuf->getDataPtr() + yy * aaBuf->getRowSize() + - ((x * splashAASize + xx) >> 3); - t += (*p >> (7 - ((x * splashAASize + xx) & 7))) & 1; - } - } -#endif - - if (t != 0) { - pipe->shape = (adjustLine) ? div255((int) lineOpacity * (double)aaGamma[t]) : (double)aaGamma[t]; - (this->*pipe->run)(pipe); - updateModX(x); - updateModY(y); - } else { - pipeIncX(pipe); - } - } -} - -//------------------------------------------------------------------------ - -// Transform a point from user space to device space. -inline void Splash::transform(SplashCoord *matrix, - SplashCoord xi, SplashCoord yi, - SplashCoord *xo, SplashCoord *yo) { - // [ m[0] m[1] 0 ] - // [xo yo 1] = [xi yi 1] * [ m[2] m[3] 0 ] - // [ m[4] m[5] 1 ] - *xo = xi * matrix[0] + yi * matrix[2] + matrix[4]; - *yo = xi * matrix[1] + yi * matrix[3] + matrix[5]; -} - -//------------------------------------------------------------------------ -// Splash -//------------------------------------------------------------------------ - -Splash::Splash(SplashBitmap *bitmapA, GBool vectorAntialiasA, - SplashScreenParams *screenParams) { - int i; - - bitmap = bitmapA; - vectorAntialias = vectorAntialiasA; - inShading = gFalse; - state = new SplashState(bitmap->width, bitmap->height, vectorAntialias, - screenParams); - if (vectorAntialias) { - aaBuf = new SplashBitmap(splashAASize * bitmap->width, splashAASize, - 1, splashModeMono1, gFalse); - for (i = 0; i <= splashAASize * splashAASize; ++i) { - aaGamma[i] = (Guchar)splashRound( - splashPow((SplashCoord)i / - (SplashCoord)(splashAASize * splashAASize), - splashAAGamma) * 255); - } - } else { - aaBuf = NULL; - } - minLineWidth = 0; - thinLineMode = splashThinLineDefault; - clearModRegion(); - debugMode = gFalse; - alpha0Bitmap = NULL; -} - -Splash::Splash(SplashBitmap *bitmapA, GBool vectorAntialiasA, - SplashScreen *screenA) { - int i; - - bitmap = bitmapA; - inShading = gFalse; - vectorAntialias = vectorAntialiasA; - state = new SplashState(bitmap->width, bitmap->height, vectorAntialias, - screenA); - if (vectorAntialias) { - aaBuf = new SplashBitmap(splashAASize * bitmap->width, splashAASize, - 1, splashModeMono1, gFalse); - for (i = 0; i <= splashAASize * splashAASize; ++i) { - aaGamma[i] = (Guchar)splashRound( - splashPow((SplashCoord)i / - (SplashCoord)(splashAASize * splashAASize), - splashAAGamma) * 255); - } - } else { - aaBuf = NULL; - } - minLineWidth = 0; - thinLineMode = splashThinLineDefault; - clearModRegion(); - debugMode = gFalse; - alpha0Bitmap = NULL; -} - -Splash::~Splash() { - while (state->next) { - restoreState(); - } - delete state; - delete aaBuf; -} - -//------------------------------------------------------------------------ -// state read -//------------------------------------------------------------------------ - -SplashCoord *Splash::getMatrix() { - return state->matrix; -} - -SplashPattern *Splash::getStrokePattern() { - return state->strokePattern; -} - -SplashPattern *Splash::getFillPattern() { - return state->fillPattern; -} - -SplashScreen *Splash::getScreen() { - return state->screen; -} - -SplashBlendFunc Splash::getBlendFunc() { - return state->blendFunc; -} - -SplashCoord Splash::getStrokeAlpha() { - return state->strokeAlpha; -} - -SplashCoord Splash::getFillAlpha() { - return state->fillAlpha; -} - -SplashCoord Splash::getLineWidth() { - return state->lineWidth; -} - -int Splash::getLineCap() { - return state->lineCap; -} - -int Splash::getLineJoin() { - return state->lineJoin; -} - -SplashCoord Splash::getMiterLimit() { - return state->miterLimit; -} - -SplashCoord Splash::getFlatness() { - return state->flatness; -} - -SplashCoord *Splash::getLineDash() { - return state->lineDash; -} - -int Splash::getLineDashLength() { - return state->lineDashLength; -} - -SplashCoord Splash::getLineDashPhase() { - return state->lineDashPhase; -} - -GBool Splash::getStrokeAdjust() { - return state->strokeAdjust; -} - -SplashClip *Splash::getClip() { - return state->clip; -} - -SplashBitmap *Splash::getSoftMask() { - return state->softMask; -} - -GBool Splash::getInNonIsolatedGroup() { - return state->inNonIsolatedGroup; -} - -//------------------------------------------------------------------------ -// state write -//------------------------------------------------------------------------ - -void Splash::setMatrix(SplashCoord *matrix) { - memcpy(state->matrix, matrix, 6 * sizeof(SplashCoord)); -} - -void Splash::setStrokePattern(SplashPattern *strokePattern) { - state->setStrokePattern(strokePattern); -} - -void Splash::setFillPattern(SplashPattern *fillPattern) { - state->setFillPattern(fillPattern); -} - -void Splash::setScreen(SplashScreen *screen) { - state->setScreen(screen); -} - -void Splash::setBlendFunc(SplashBlendFunc func) { - state->blendFunc = func; -} - -void Splash::setStrokeAlpha(SplashCoord alpha) { - state->strokeAlpha = (state->multiplyPatternAlpha) ? alpha * state->patternStrokeAlpha : alpha; -} - -void Splash::setFillAlpha(SplashCoord alpha) { - state->fillAlpha = (state->multiplyPatternAlpha) ? alpha * state->patternFillAlpha : alpha; -} - -void Splash::setPatternAlpha(SplashCoord strokeAlpha, SplashCoord fillAlpha) { - state->patternStrokeAlpha = strokeAlpha; - state->patternFillAlpha = fillAlpha; - state->multiplyPatternAlpha = gTrue; -} - -void Splash::clearPatternAlpha() { - state->patternStrokeAlpha = 1; - state->patternFillAlpha = 1; - state->multiplyPatternAlpha = gFalse; -} - -void Splash::setFillOverprint(GBool fop) { - state->fillOverprint = fop; -} - -void Splash::setStrokeOverprint(GBool gop) { - state->strokeOverprint = gop; -} - -void Splash::setOverprintMode(int opm) { - state->overprintMode = opm; -} - -void Splash::setLineWidth(SplashCoord lineWidth) { - state->lineWidth = lineWidth; -} - -void Splash::setLineCap(int lineCap) { - state->lineCap = lineCap; -} - -void Splash::setLineJoin(int lineJoin) { - state->lineJoin = lineJoin; -} - -void Splash::setMiterLimit(SplashCoord miterLimit) { - state->miterLimit = miterLimit; -} - -void Splash::setFlatness(SplashCoord flatness) { - if (flatness < 1) { - state->flatness = 1; - } else { - state->flatness = flatness; - } -} - -void Splash::setLineDash(SplashCoord *lineDash, int lineDashLength, - SplashCoord lineDashPhase) { - state->setLineDash(lineDash, lineDashLength, lineDashPhase); -} - -void Splash::setStrokeAdjust(GBool strokeAdjust) { - state->strokeAdjust = strokeAdjust; -} - -void Splash::clipResetToRect(SplashCoord x0, SplashCoord y0, - SplashCoord x1, SplashCoord y1) { - state->clip->resetToRect(x0, y0, x1, y1); -} - -SplashError Splash::clipToRect(SplashCoord x0, SplashCoord y0, - SplashCoord x1, SplashCoord y1) { - return state->clip->clipToRect(x0, y0, x1, y1); -} - -SplashError Splash::clipToPath(SplashPath *path, GBool eo) { - return state->clip->clipToPath(path, state->matrix, state->flatness, eo); -} - -void Splash::setSoftMask(SplashBitmap *softMask) { - state->setSoftMask(softMask); -} - -void Splash::setInNonIsolatedGroup(SplashBitmap *alpha0BitmapA, - int alpha0XA, int alpha0YA) { - alpha0Bitmap = alpha0BitmapA; - alpha0X = alpha0XA; - alpha0Y = alpha0YA; - state->inNonIsolatedGroup = gTrue; -} - -void Splash::setTransfer(Guchar *red, Guchar *green, Guchar *blue, - Guchar *gray) { - state->setTransfer(red, green, blue, gray); -} - -void Splash::setOverprintMask(Guint overprintMask, GBool additive) { - state->overprintMask = overprintMask; - state->overprintAdditive = additive; -} - -//------------------------------------------------------------------------ -// state save/restore -//------------------------------------------------------------------------ - -void Splash::saveState() { - SplashState *newState; - - newState = state->copy(); - newState->next = state; - state = newState; -} - -SplashError Splash::restoreState() { - SplashState *oldState; - - if (!state->next) { - return splashErrNoSave; - } - oldState = state; - state = state->next; - delete oldState; - return splashOk; -} - -//------------------------------------------------------------------------ -// drawing operations -//------------------------------------------------------------------------ - -void Splash::clear(SplashColorPtr color, Guchar alpha) { - SplashColorPtr row, p; - Guchar mono; - int x, y; - - switch (bitmap->mode) { - case splashModeMono1: - mono = (color[0] & 0x80) ? 0xff : 0x00; - if (bitmap->rowSize < 0) { - memset(bitmap->data + bitmap->rowSize * (bitmap->height - 1), - mono, -bitmap->rowSize * bitmap->height); - } else { - memset(bitmap->data, mono, bitmap->rowSize * bitmap->height); - } - break; - case splashModeMono8: - if (bitmap->rowSize < 0) { - memset(bitmap->data + bitmap->rowSize * (bitmap->height - 1), - color[0], -bitmap->rowSize * bitmap->height); - } else { - memset(bitmap->data, color[0], bitmap->rowSize * bitmap->height); - } - break; - case splashModeRGB8: - if (color[0] == color[1] && color[1] == color[2]) { - if (bitmap->rowSize < 0) { - memset(bitmap->data + bitmap->rowSize * (bitmap->height - 1), - color[0], -bitmap->rowSize * bitmap->height); - } else { - memset(bitmap->data, color[0], bitmap->rowSize * bitmap->height); - } - } else { - row = bitmap->data; - for (y = 0; y < bitmap->height; ++y) { - p = row; - for (x = 0; x < bitmap->width; ++x) { - *p++ = color[2]; - *p++ = color[1]; - *p++ = color[0]; - } - row += bitmap->rowSize; - } - } - break; - case splashModeXBGR8: - if (color[0] == color[1] && color[1] == color[2]) { - if (bitmap->rowSize < 0) { - memset(bitmap->data + bitmap->rowSize * (bitmap->height - 1), - color[0], -bitmap->rowSize * bitmap->height); - } else { - memset(bitmap->data, color[0], bitmap->rowSize * bitmap->height); - } - } else { - row = bitmap->data; - for (y = 0; y < bitmap->height; ++y) { - p = row; - for (x = 0; x < bitmap->width; ++x) { - *p++ = color[0]; - *p++ = color[1]; - *p++ = color[2]; - *p++ = 255; - } - row += bitmap->rowSize; - } - } - break; - case splashModeBGR8: - if (color[0] == color[1] && color[1] == color[2]) { - if (bitmap->rowSize < 0) { - memset(bitmap->data + bitmap->rowSize * (bitmap->height - 1), - color[0], -bitmap->rowSize * bitmap->height); - } else { - memset(bitmap->data, color[0], bitmap->rowSize * bitmap->height); - } - } else { - row = bitmap->data; - for (y = 0; y < bitmap->height; ++y) { - p = row; - for (x = 0; x < bitmap->width; ++x) { - *p++ = color[0]; - *p++ = color[1]; - *p++ = color[2]; - } - row += bitmap->rowSize; - } - } - break; -#ifdef SPLASH_CMYK - case splashModeCMYK8: - if (color[0] == color[1] && color[1] == color[2] && color[2] == color[3]) { - if (bitmap->rowSize < 0) { - memset(bitmap->data + bitmap->rowSize * (bitmap->height - 1), - color[0], -bitmap->rowSize * bitmap->height); - } else { - memset(bitmap->data, color[0], bitmap->rowSize * bitmap->height); - } - } else { - row = bitmap->data; - for (y = 0; y < bitmap->height; ++y) { - p = row; - for (x = 0; x < bitmap->width; ++x) { - *p++ = color[0]; - *p++ = color[1]; - *p++ = color[2]; - *p++ = color[3]; - } - row += bitmap->rowSize; - } - } - break; - case splashModeDeviceN8: - row = bitmap->data; - for (y = 0; y < bitmap->height; ++y) { - p = row; - for (x = 0; x < bitmap->width; ++x) { - for (int cp = 0; cp < SPOT_NCOMPS+4; cp++) - *p++ = color[cp]; - } - row += bitmap->rowSize; - } - break; -#endif - } - - if (bitmap->alpha) { - memset(bitmap->alpha, alpha, bitmap->width * bitmap->height); - } - - updateModX(0); - updateModY(0); - updateModX(bitmap->width - 1); - updateModY(bitmap->height - 1); -} - -SplashError Splash::stroke(SplashPath *path) { - SplashPath *path2, *dPath; - SplashCoord d1, d2, t1, t2, w; - - if (debugMode) { - printf("stroke [dash:%d] [width:%.2f]:\n", - state->lineDashLength, (double)state->lineWidth); - dumpPath(path); - } - opClipRes = splashClipAllOutside; - if (path->length == 0) { - return splashErrEmptyPath; - } - path2 = flattenPath(path, state->matrix, state->flatness); - if (state->lineDashLength > 0) { - dPath = makeDashedPath(path2); - delete path2; - path2 = dPath; - if (path2->length == 0) { - delete path2; - return splashErrEmptyPath; - } - } - - // transform a unit square, and take the half the max of the two - // diagonals; the product of this number and the line width is the - // (approximate) transformed line width - t1 = state->matrix[0] + state->matrix[2]; - t2 = state->matrix[1] + state->matrix[3]; - d1 = t1 * t1 + t2 * t2; - t1 = state->matrix[0] - state->matrix[2]; - t2 = state->matrix[1] - state->matrix[3]; - d2 = t1 * t1 + t2 * t2; - if (d2 > d1) { - d1 = d2; - } - d1 *= 0.5; - if (d1 > 0 && - d1 * state->lineWidth * state->lineWidth < minLineWidth * minLineWidth) { - w = minLineWidth / splashSqrt(d1); - strokeWide(path2, w); - } else if (bitmap->mode == splashModeMono1) { - // this gets close to Adobe's behavior in mono mode - if (d1 * state->lineWidth <= 2) { - strokeNarrow(path2); - } else { - strokeWide(path2, state->lineWidth); - } - } else { - if (state->lineWidth == 0) { - strokeNarrow(path2); - } else { - strokeWide(path2, state->lineWidth); - } - } - - delete path2; - return splashOk; -} - -void Splash::strokeNarrow(SplashPath *path) { - SplashPipe pipe; - SplashXPath *xPath; - SplashXPathSeg *seg; - int x0, x1, y0, y1, xa, xb, y; - SplashCoord dxdy; - SplashClipResult clipRes; - int nClipRes[3]; - int i; - - nClipRes[0] = nClipRes[1] = nClipRes[2] = 0; - - xPath = new SplashXPath(path, state->matrix, state->flatness, gFalse); - - pipeInit(&pipe, 0, 0, state->strokePattern, NULL, - (Guchar)splashRound(state->strokeAlpha * 255), - gFalse, gFalse); - - for (i = 0, seg = xPath->segs; i < xPath->length; ++i, ++seg) { - if (seg->y0 <= seg->y1) { - y0 = splashFloor(seg->y0); - y1 = splashFloor(seg->y1); - x0 = splashFloor(seg->x0); - x1 = splashFloor(seg->x1); - } else { - y0 = splashFloor(seg->y1); - y1 = splashFloor(seg->y0); - x0 = splashFloor(seg->x1); - x1 = splashFloor(seg->x0); - } - if ((clipRes = state->clip->testRect(x0 <= x1 ? x0 : x1, y0, - x0 <= x1 ? x1 : x0, y1)) - != splashClipAllOutside) { - if (y0 == y1) { - if (x0 <= x1) { - drawSpan(&pipe, x0, x1, y0, clipRes == splashClipAllInside); - } else { - drawSpan(&pipe, x1, x0, y0, clipRes == splashClipAllInside); - } - } else { - dxdy = seg->dxdy; - if (y0 < state->clip->getYMinI()) { - y0 = state->clip->getYMinI(); - x0 = splashFloor(seg->x0 + ((SplashCoord)y0 - seg->y0) * dxdy); - } - if (y1 > state->clip->getYMaxI()) { - y1 = state->clip->getYMaxI(); - x1 = splashFloor(seg->x0 + ((SplashCoord)y1 - seg->y0) * dxdy); - } - if (x0 <= x1) { - xa = x0; - for (y = y0; y <= y1; ++y) { - if (y < y1) { - xb = splashFloor(seg->x0 + - ((SplashCoord)y + 1 - seg->y0) * dxdy); - } else { - xb = x1 + 1; - } - if (xa == xb) { - drawPixel(&pipe, xa, y, clipRes == splashClipAllInside); - } else { - drawSpan(&pipe, xa, xb - 1, y, clipRes == splashClipAllInside); - } - xa = xb; - } - } else { - xa = x0; - for (y = y0; y <= y1; ++y) { - if (y < y1) { - xb = splashFloor(seg->x0 + - ((SplashCoord)y + 1 - seg->y0) * dxdy); - } else { - xb = x1 - 1; - } - if (xa == xb) { - drawPixel(&pipe, xa, y, clipRes == splashClipAllInside); - } else { - drawSpan(&pipe, xb + 1, xa, y, clipRes == splashClipAllInside); - } - xa = xb; - } - } - } - } - ++nClipRes[clipRes]; - } - if (nClipRes[splashClipPartial] || - (nClipRes[splashClipAllInside] && nClipRes[splashClipAllOutside])) { - opClipRes = splashClipPartial; - } else if (nClipRes[splashClipAllInside]) { - opClipRes = splashClipAllInside; - } else { - opClipRes = splashClipAllOutside; - } - - delete xPath; -} - -void Splash::strokeWide(SplashPath *path, SplashCoord w) { - SplashPath *path2; - - path2 = makeStrokePath(path, w, gFalse); - fillWithPattern(path2, gFalse, state->strokePattern, state->strokeAlpha); - delete path2; -} - -SplashPath *Splash::flattenPath(SplashPath *path, SplashCoord *matrix, - SplashCoord flatness) { - SplashPath *fPath; - SplashCoord flatness2; - Guchar flag; - int i; - - fPath = new SplashPath(); -#ifdef USE_FIXEDPOINT - flatness2 = flatness; -#else - flatness2 = flatness * flatness; -#endif - i = 0; - while (i < path->length) { - flag = path->flags[i]; - if (flag & splashPathFirst) { - fPath->moveTo(path->pts[i].x, path->pts[i].y); - ++i; - } else { - if (flag & splashPathCurve) { - flattenCurve(path->pts[i-1].x, path->pts[i-1].y, - path->pts[i ].x, path->pts[i ].y, - path->pts[i+1].x, path->pts[i+1].y, - path->pts[i+2].x, path->pts[i+2].y, - matrix, flatness2, fPath); - i += 3; - } else { - fPath->lineTo(path->pts[i].x, path->pts[i].y); - ++i; - } - if (path->flags[i-1] & splashPathClosed) { - fPath->close(); - } - } - } - return fPath; -} - -void Splash::flattenCurve(SplashCoord x0, SplashCoord y0, - SplashCoord x1, SplashCoord y1, - SplashCoord x2, SplashCoord y2, - SplashCoord x3, SplashCoord y3, - SplashCoord *matrix, SplashCoord flatness2, - SplashPath *fPath) { - SplashCoord cx[splashMaxCurveSplits + 1][3]; - SplashCoord cy[splashMaxCurveSplits + 1][3]; - int cNext[splashMaxCurveSplits + 1]; - SplashCoord xl0, xl1, xl2, xr0, xr1, xr2, xr3, xx1, xx2, xh; - SplashCoord yl0, yl1, yl2, yr0, yr1, yr2, yr3, yy1, yy2, yh; - SplashCoord dx, dy, mx, my, tx, ty, d1, d2; - int p1, p2, p3; - - // initial segment - p1 = 0; - p2 = splashMaxCurveSplits; - cx[p1][0] = x0; cy[p1][0] = y0; - cx[p1][1] = x1; cy[p1][1] = y1; - cx[p1][2] = x2; cy[p1][2] = y2; - cx[p2][0] = x3; cy[p2][0] = y3; - cNext[p1] = p2; - - while (p1 < splashMaxCurveSplits) { - - // get the next segment - xl0 = cx[p1][0]; yl0 = cy[p1][0]; - xx1 = cx[p1][1]; yy1 = cy[p1][1]; - xx2 = cx[p1][2]; yy2 = cy[p1][2]; - p2 = cNext[p1]; - xr3 = cx[p2][0]; yr3 = cy[p2][0]; - - // compute the distances (in device space) from the control points - // to the midpoint of the straight line (this is a bit of a hack, - // but it's much faster than computing the actual distances to the - // line) - transform(matrix, (xl0 + xr3) * 0.5, (yl0 + yr3) * 0.5, &mx, &my); - transform(matrix, xx1, yy1, &tx, &ty); -#ifdef USE_FIXEDPOINT - d1 = splashDist(tx, ty, mx, my); -#else - dx = tx - mx; - dy = ty - my; - d1 = dx*dx + dy*dy; -#endif - transform(matrix, xx2, yy2, &tx, &ty); -#ifdef USE_FIXEDPOINT - d2 = splashDist(tx, ty, mx, my); -#else - dx = tx - mx; - dy = ty - my; - d2 = dx*dx + dy*dy; -#endif - - // if the curve is flat enough, or no more subdivisions are - // allowed, add the straight line segment - if (p2 - p1 == 1 || (d1 <= flatness2 && d2 <= flatness2)) { - fPath->lineTo(xr3, yr3); - p1 = p2; - - // otherwise, subdivide the curve - } else { - xl1 = splashAvg(xl0, xx1); - yl1 = splashAvg(yl0, yy1); - xh = splashAvg(xx1, xx2); - yh = splashAvg(yy1, yy2); - xl2 = splashAvg(xl1, xh); - yl2 = splashAvg(yl1, yh); - xr2 = splashAvg(xx2, xr3); - yr2 = splashAvg(yy2, yr3); - xr1 = splashAvg(xh, xr2); - yr1 = splashAvg(yh, yr2); - xr0 = splashAvg(xl2, xr1); - yr0 = splashAvg(yl2, yr1); - // add the new subdivision points - p3 = (p1 + p2) / 2; - cx[p1][1] = xl1; cy[p1][1] = yl1; - cx[p1][2] = xl2; cy[p1][2] = yl2; - cNext[p1] = p3; - cx[p3][0] = xr0; cy[p3][0] = yr0; - cx[p3][1] = xr1; cy[p3][1] = yr1; - cx[p3][2] = xr2; cy[p3][2] = yr2; - cNext[p3] = p2; - } - } -} - -SplashPath *Splash::makeDashedPath(SplashPath *path) { - SplashPath *dPath; - SplashCoord lineDashTotal; - SplashCoord lineDashStartPhase, lineDashDist, segLen; - SplashCoord x0, y0, x1, y1, xa, ya; - GBool lineDashStartOn, lineDashOn, newPath; - int lineDashStartIdx, lineDashIdx; - int i, j, k; - - lineDashTotal = 0; - for (i = 0; i < state->lineDashLength; ++i) { - lineDashTotal += state->lineDash[i]; - } - // Acrobat simply draws nothing if the dash array is [0] - if (lineDashTotal == 0) { - return new SplashPath(); - } - lineDashStartPhase = state->lineDashPhase; - i = splashFloor(lineDashStartPhase / lineDashTotal); - lineDashStartPhase -= (SplashCoord)i * lineDashTotal; - lineDashStartOn = gTrue; - lineDashStartIdx = 0; - if (lineDashStartPhase > 0) { - while (lineDashStartIdx < state->lineDashLength && lineDashStartPhase >= state->lineDash[lineDashStartIdx]) { - lineDashStartOn = !lineDashStartOn; - lineDashStartPhase -= state->lineDash[lineDashStartIdx]; - ++lineDashStartIdx; - } - if (unlikely(lineDashStartIdx == state->lineDashLength)) { - return new SplashPath(); - } - } - - dPath = new SplashPath(); - - // process each subpath - i = 0; - while (i < path->length) { - - // find the end of the subpath - for (j = i; - j < path->length - 1 && !(path->flags[j] & splashPathLast); - ++j) ; - - // initialize the dash parameters - lineDashOn = lineDashStartOn; - lineDashIdx = lineDashStartIdx; - lineDashDist = state->lineDash[lineDashIdx] - lineDashStartPhase; - - // process each segment of the subpath - newPath = gTrue; - for (k = i; k < j; ++k) { - - // grab the segment - x0 = path->pts[k].x; - y0 = path->pts[k].y; - x1 = path->pts[k+1].x; - y1 = path->pts[k+1].y; - segLen = splashDist(x0, y0, x1, y1); - - // process the segment - while (segLen > 0) { - - if (lineDashDist >= segLen) { - if (lineDashOn) { - if (newPath) { - dPath->moveTo(x0, y0); - newPath = gFalse; - } - dPath->lineTo(x1, y1); - } - lineDashDist -= segLen; - segLen = 0; - - } else { - xa = x0 + (lineDashDist / segLen) * (x1 - x0); - ya = y0 + (lineDashDist / segLen) * (y1 - y0); - if (lineDashOn) { - if (newPath) { - dPath->moveTo(x0, y0); - newPath = gFalse; - } - dPath->lineTo(xa, ya); - } - x0 = xa; - y0 = ya; - segLen -= lineDashDist; - lineDashDist = 0; - } - - // get the next entry in the dash array - if (lineDashDist <= 0) { - lineDashOn = !lineDashOn; - if (++lineDashIdx == state->lineDashLength) { - lineDashIdx = 0; - } - lineDashDist = state->lineDash[lineDashIdx]; - newPath = gTrue; - } - } - } - i = j + 1; - } - - if (dPath->length == 0) { - GBool allSame = gTrue; - for (int i = 0; allSame && i < path->length - 1; ++i) { - allSame = path->pts[i].x == path->pts[i + 1].x && path->pts[i].y == path->pts[i + 1].y; - } - if (allSame) { - x0 = path->pts[0].x; - y0 = path->pts[0].y; - dPath->moveTo(x0, y0); - dPath->lineTo(x0, y0); - } - } - - return dPath; -} - -SplashError Splash::fill(SplashPath *path, GBool eo) { - if (debugMode) { - printf("fill [eo:%d]:\n", eo); - dumpPath(path); - } - return fillWithPattern(path, eo, state->fillPattern, state->fillAlpha); -} - -inline void Splash::getBBoxFP(SplashPath *path, SplashCoord *xMinA, SplashCoord *yMinA, - SplashCoord *xMaxA, SplashCoord *yMaxA) { - SplashCoord xMinFP, yMinFP, xMaxFP, yMaxFP, tx, ty; - - // make compiler happy: - xMinFP = xMaxFP = yMinFP = yMaxFP = 0; - for (int i = 0; i < path->length; ++i) { - transform(state->matrix, path->pts[i].x, path->pts[i].y, &tx, &ty); - if (i == 0) { - xMinFP = xMaxFP = tx; - yMinFP = yMaxFP = ty; - } else { - if (tx < xMinFP) xMinFP = tx; - if (tx > xMaxFP) xMaxFP = tx; - if (ty < yMinFP) yMinFP = ty; - if (ty > yMaxFP) yMaxFP = ty; - } - } - - *xMinA = xMinFP; - *yMinA = yMinFP; - *xMaxA = xMaxFP; - *yMaxA = yMaxFP; -} - -SplashError Splash::fillWithPattern(SplashPath *path, GBool eo, - SplashPattern *pattern, - SplashCoord alpha) { - SplashPipe pipe; - SplashXPath *xPath; - SplashXPathScanner *scanner; - int xMinI, yMinI, xMaxI, yMaxI, x0, x1, y; - SplashClipResult clipRes, clipRes2; - GBool adjustLine = gFalse; - int linePosI = 0; - - if (path->length == 0) { - return splashErrEmptyPath; - } - if (pathAllOutside(path)) { - opClipRes = splashClipAllOutside; - return splashOk; - } - - // add stroke adjustment hints for filled rectangles -- this only - // applies to paths that consist of a single subpath - // (this appears to match Acrobat's behavior) - if (state->strokeAdjust && !path->hints) { - int n; - n = path->getLength(); - if (n == 4 && - !(path->flags[0] & splashPathClosed) && - !(path->flags[1] & splashPathLast) && - !(path->flags[2] & splashPathLast)) { - path->close(gTrue); - path->addStrokeAdjustHint(0, 2, 0, 4); - path->addStrokeAdjustHint(1, 3, 0, 4); - } else if (n == 5 && - (path->flags[0] & splashPathClosed) && - !(path->flags[1] & splashPathLast) && - !(path->flags[2] & splashPathLast) && - !(path->flags[3] & splashPathLast)) { - path->addStrokeAdjustHint(0, 2, 0, 4); - path->addStrokeAdjustHint(1, 3, 0, 4); - } - } - - if (thinLineMode != splashThinLineDefault) { - if (state->clip->getXMinI() == state->clip->getXMaxI()) { - linePosI = state->clip->getXMinI(); - adjustLine = gTrue; - } else if (state->clip->getXMinI() == state->clip->getXMaxI() - 1) { - adjustLine = gTrue; - linePosI = splashFloor(state->clip->getXMin() + state->lineWidth); - } else if (state->clip->getYMinI() == state->clip->getYMaxI()) { - linePosI = state->clip->getYMinI(); - adjustLine = gTrue; - } else if (state->clip->getYMinI() == state->clip->getYMaxI() - 1) { - adjustLine = gTrue; - linePosI = splashFloor(state->clip->getYMin() + state->lineWidth); - } - } - - xPath = new SplashXPath(path, state->matrix, state->flatness, gTrue, - adjustLine, linePosI); - if (vectorAntialias && !inShading) { - xPath->aaScale(); - } - xPath->sort(); - yMinI = state->clip->getYMinI(); - yMaxI = state->clip->getYMaxI(); - if (vectorAntialias && !inShading) { - yMinI = yMinI * splashAASize; - yMaxI = (yMaxI + 1) * splashAASize - 1; - } - scanner = new SplashXPathScanner(xPath, eo, yMinI, yMaxI); - - // get the min and max x and y values - if (vectorAntialias && !inShading) { - scanner->getBBoxAA(&xMinI, &yMinI, &xMaxI, &yMaxI); - } else { - scanner->getBBox(&xMinI, &yMinI, &xMaxI, &yMaxI); - } - - if (eo && (yMinI == yMaxI || xMinI == xMaxI) && thinLineMode != splashThinLineDefault) { - SplashCoord delta, xMinFP, yMinFP, xMaxFP, yMaxFP; - getBBoxFP(path, &xMinFP, &yMinFP, &xMaxFP, &yMaxFP); - delta = (yMinI == yMaxI) ? yMaxFP - yMinFP : xMaxFP - xMinFP; - if (delta < 0.2) { - opClipRes = splashClipAllOutside; - delete scanner; - delete xPath; - return splashOk; - } - } - - // check clipping - if ((clipRes = state->clip->testRect(xMinI, yMinI, xMaxI, yMaxI)) - != splashClipAllOutside) { - if (scanner->hasPartialClip()) { - clipRes = splashClipPartial; - } - - pipeInit(&pipe, 0, yMinI, pattern, NULL, (Guchar)splashRound(alpha * 255), - vectorAntialias && !inShading, gFalse); - - // draw the spans - if (vectorAntialias && !inShading) { - for (y = yMinI; y <= yMaxI; ++y) { - scanner->renderAALine(aaBuf, &x0, &x1, y, thinLineMode != splashThinLineDefault && xMinI == xMaxI); - if (clipRes != splashClipAllInside) { - state->clip->clipAALine(aaBuf, &x0, &x1, y, thinLineMode != splashThinLineDefault && xMinI == xMaxI); - } - Guchar lineShape = 255; - GBool adjustLine = gFalse; - if (thinLineMode == splashThinLineShape && (xMinI == xMaxI || yMinI == yMaxI)) { - // compute line shape for thin lines: - SplashCoord mx, my, delta; - transform(state->matrix, 0, 0, &mx, &my); - transform(state->matrix, state->lineWidth, 0, &delta, &my); - adjustLine = gTrue; - lineShape = clip255((delta - mx) * 255); - } - drawAALine(&pipe, x0, x1, y, adjustLine, lineShape); - } - } else { - for (y = yMinI; y <= yMaxI; ++y) { - while (scanner->getNextSpan(y, &x0, &x1)) { - if (clipRes == splashClipAllInside) { - drawSpan(&pipe, x0, x1, y, gTrue); - } else { - // limit the x range - if (x0 < state->clip->getXMinI()) { - x0 = state->clip->getXMinI(); - } - if (x1 > state->clip->getXMaxI()) { - x1 = state->clip->getXMaxI(); - } - clipRes2 = state->clip->testSpan(x0, x1, y); - drawSpan(&pipe, x0, x1, y, clipRes2 == splashClipAllInside); - } - } - } - } - } - opClipRes = clipRes; - - delete scanner; - delete xPath; - return splashOk; -} - -GBool Splash::pathAllOutside(SplashPath *path) { - SplashCoord xMin1, yMin1, xMax1, yMax1; - SplashCoord xMin2, yMin2, xMax2, yMax2; - SplashCoord x, y; - int xMinI, yMinI, xMaxI, yMaxI; - int i; - - xMin1 = xMax1 = path->pts[0].x; - yMin1 = yMax1 = path->pts[0].y; - for (i = 1; i < path->length; ++i) { - if (path->pts[i].x < xMin1) { - xMin1 = path->pts[i].x; - } else if (path->pts[i].x > xMax1) { - xMax1 = path->pts[i].x; - } - if (path->pts[i].y < yMin1) { - yMin1 = path->pts[i].y; - } else if (path->pts[i].y > yMax1) { - yMax1 = path->pts[i].y; - } - } - - transform(state->matrix, xMin1, yMin1, &x, &y); - xMin2 = xMax2 = x; - yMin2 = yMax2 = y; - transform(state->matrix, xMin1, yMax1, &x, &y); - if (x < xMin2) { - xMin2 = x; - } else if (x > xMax2) { - xMax2 = x; - } - if (y < yMin2) { - yMin2 = y; - } else if (y > yMax2) { - yMax2 = y; - } - transform(state->matrix, xMax1, yMin1, &x, &y); - if (x < xMin2) { - xMin2 = x; - } else if (x > xMax2) { - xMax2 = x; - } - if (y < yMin2) { - yMin2 = y; - } else if (y > yMax2) { - yMax2 = y; - } - transform(state->matrix, xMax1, yMax1, &x, &y); - if (x < xMin2) { - xMin2 = x; - } else if (x > xMax2) { - xMax2 = x; - } - if (y < yMin2) { - yMin2 = y; - } else if (y > yMax2) { - yMax2 = y; - } - xMinI = splashFloor(xMin2); - yMinI = splashFloor(yMin2); - xMaxI = splashFloor(xMax2); - yMaxI = splashFloor(yMax2); - - return state->clip->testRect(xMinI, yMinI, xMaxI, yMaxI) == - splashClipAllOutside; -} - -SplashError Splash::xorFill(SplashPath *path, GBool eo) { - SplashPipe pipe; - SplashXPath *xPath; - SplashXPathScanner *scanner; - int xMinI, yMinI, xMaxI, yMaxI, x0, x1, y; - SplashClipResult clipRes, clipRes2; - SplashBlendFunc origBlendFunc; - - if (path->length == 0) { - return splashErrEmptyPath; - } - xPath = new SplashXPath(path, state->matrix, state->flatness, gTrue); - xPath->sort(); - scanner = new SplashXPathScanner(xPath, eo, state->clip->getYMinI(), - state->clip->getYMaxI()); - - // get the min and max x and y values - scanner->getBBox(&xMinI, &yMinI, &xMaxI, &yMaxI); - - // check clipping - if ((clipRes = state->clip->testRect(xMinI, yMinI, xMaxI, yMaxI)) - != splashClipAllOutside) { - if (scanner->hasPartialClip()) { - clipRes = splashClipPartial; - } - - origBlendFunc = state->blendFunc; - state->blendFunc = &blendXor; - pipeInit(&pipe, 0, yMinI, state->fillPattern, NULL, 255, gFalse, gFalse); - - // draw the spans - for (y = yMinI; y <= yMaxI; ++y) { - while (scanner->getNextSpan(y, &x0, &x1)) { - if (clipRes == splashClipAllInside) { - drawSpan(&pipe, x0, x1, y, gTrue); - } else { - // limit the x range - if (x0 < state->clip->getXMinI()) { - x0 = state->clip->getXMinI(); - } - if (x1 > state->clip->getXMaxI()) { - x1 = state->clip->getXMaxI(); - } - clipRes2 = state->clip->testSpan(x0, x1, y); - drawSpan(&pipe, x0, x1, y, clipRes2 == splashClipAllInside); - } - } - } - state->blendFunc = origBlendFunc; - } - opClipRes = clipRes; - - delete scanner; - delete xPath; - return splashOk; -} - -SplashError Splash::fillChar(SplashCoord x, SplashCoord y, - int c, SplashFont *font) { - SplashGlyphBitmap glyph; - SplashCoord xt, yt; - int x0, y0, xFrac, yFrac; - SplashClipResult clipRes; - - if (debugMode) { - printf("fillChar: x=%.2f y=%.2f c=%3d=0x%02x='%c'\n", - (double)x, (double)y, c, c, c); - } - transform(state->matrix, x, y, &xt, &yt); - x0 = splashFloor(xt); - xFrac = splashFloor((xt - x0) * splashFontFraction); - y0 = splashFloor(yt); - yFrac = splashFloor((yt - y0) * splashFontFraction); - if (!font->getGlyph(c, xFrac, yFrac, &glyph, x0, y0, state->clip, &clipRes)) { - return splashErrNoGlyph; - } - if (clipRes != splashClipAllOutside) { - fillGlyph2(x0, y0, &glyph, clipRes == splashClipAllInside); - } - opClipRes = clipRes; - if (glyph.freeData) { - gfree(glyph.data); - } - return splashOk; -} - -void Splash::fillGlyph(SplashCoord x, SplashCoord y, - SplashGlyphBitmap *glyph) { - SplashCoord xt, yt; - int x0, y0; - - transform(state->matrix, x, y, &xt, &yt); - x0 = splashFloor(xt); - y0 = splashFloor(yt); - SplashClipResult clipRes = state->clip->testRect(x0 - glyph->x, - y0 - glyph->y, - x0 - glyph->x + glyph->w - 1, - y0 - glyph->y + glyph->h - 1); - if (clipRes != splashClipAllOutside) { - fillGlyph2(x0, y0, glyph, clipRes == splashClipAllInside); - } - opClipRes = clipRes; -} - -void Splash::fillGlyph2(int x0, int y0, SplashGlyphBitmap *glyph, GBool noClip) { - SplashPipe pipe; - int alpha0; - Guchar alpha; - Guchar *p; - int x1, y1, xx, xx1, yy; - - p = glyph->data; - int xStart = x0 - glyph->x; - int yStart = y0 - glyph->y; - int xxLimit = glyph->w; - int yyLimit = glyph->h; - int xShift = 0; - - if (yStart < 0) - { - p += (glyph->aa ? glyph->w : splashCeil(glyph->w / 8.0)) * -yStart; // move p to the beginning of the first painted row - yyLimit += yStart; - yStart = 0; - } - - if (xStart < 0) - { - if (glyph->aa) { - p += -xStart; - } else { - p += (-xStart) / 8; - xShift = (-xStart) % 8; - } - xxLimit += xStart; - xStart = 0; - } - - if (xxLimit + xStart >= bitmap->width) xxLimit = bitmap->width - xStart; - if (yyLimit + yStart >= bitmap->height) yyLimit = bitmap->height - yStart; - - if (noClip) { - if (glyph->aa) { - pipeInit(&pipe, xStart, yStart, - state->fillPattern, NULL, (Guchar)splashRound(state->fillAlpha * 255), gTrue, gFalse); - for (yy = 0, y1 = yStart; yy < yyLimit; ++yy, ++y1) { - pipeSetXY(&pipe, xStart, y1); - for (xx = 0, x1 = xStart; xx < xxLimit; ++xx, ++x1) { - alpha = p[xx]; - if (alpha != 0) { - pipe.shape = alpha; - (this->*pipe.run)(&pipe); - updateModX(x1); - updateModY(y1); - } else { - pipeIncX(&pipe); - } - } - p += glyph->w; - } - } else { - const int widthEight = splashCeil(glyph->w / 8.0); - - pipeInit(&pipe, xStart, yStart, - state->fillPattern, NULL, (Guchar)splashRound(state->fillAlpha * 255), gFalse, gFalse); - for (yy = 0, y1 = yStart; yy < yyLimit; ++yy, ++y1) { - pipeSetXY(&pipe, xStart, y1); - for (xx = 0, x1 = xStart; xx < xxLimit; xx += 8) { - alpha0 = (xShift > 0 ? (p[xx / 8] << xShift) | (p[xx / 8 + 1] >> (8 - xShift)) : p[xx / 8]); - for (xx1 = 0; xx1 < 8 && xx + xx1 < xxLimit; ++xx1, ++x1) { - if (alpha0 & 0x80) { - (this->*pipe.run)(&pipe); - updateModX(x1); - updateModY(y1); - } else { - pipeIncX(&pipe); - } - alpha0 <<= 1; - } - } - p += widthEight; - } - } - } else { - if (glyph->aa) { - pipeInit(&pipe, xStart, yStart, - state->fillPattern, NULL, (Guchar)splashRound(state->fillAlpha * 255), gTrue, gFalse); - for (yy = 0, y1 = yStart; yy < yyLimit; ++yy, ++y1) { - pipeSetXY(&pipe, xStart, y1); - for (xx = 0, x1 = xStart; xx < xxLimit; ++xx, ++x1) { - if (state->clip->test(x1, y1)) { - alpha = p[xx]; - if (alpha != 0) { - pipe.shape = alpha; - (this->*pipe.run)(&pipe); - updateModX(x1); - updateModY(y1); - } else { - pipeIncX(&pipe); - } - } else { - pipeIncX(&pipe); - } - } - p += glyph->w; - } - } else { - const int widthEight = splashCeil(glyph->w / 8.0); - - pipeInit(&pipe, xStart, yStart, - state->fillPattern, NULL, (Guchar)splashRound(state->fillAlpha * 255), gFalse, gFalse); - for (yy = 0, y1 = yStart; yy < yyLimit; ++yy, ++y1) { - pipeSetXY(&pipe, xStart, y1); - for (xx = 0, x1 = xStart; xx < xxLimit; xx += 8) { - alpha0 = (xShift > 0 ? (p[xx / 8] << xShift) | (p[xx / 8 + 1] >> (8 - xShift)) : p[xx / 8]); - for (xx1 = 0; xx1 < 8 && xx + xx1 < xxLimit; ++xx1, ++x1) { - if (state->clip->test(x1, y1)) { - if (alpha0 & 0x80) { - (this->*pipe.run)(&pipe); - updateModX(x1); - updateModY(y1); - } else { - pipeIncX(&pipe); - } - } else { - pipeIncX(&pipe); - } - alpha0 <<= 1; - } - } - p += widthEight; - } - } - } -} - -SplashError Splash::fillImageMask(SplashImageMaskSource src, void *srcData, - int w, int h, SplashCoord *mat, - GBool glyphMode) { - SplashBitmap *scaledMask; - SplashClipResult clipRes; - GBool minorAxisZero; - int x0, y0, x1, y1, scaledWidth, scaledHeight; - int yp; - - if (debugMode) { - printf("fillImageMask: w=%d h=%d mat=[%.2f %.2f %.2f %.2f %.2f %.2f]\n", - w, h, (double)mat[0], (double)mat[1], (double)mat[2], - (double)mat[3], (double)mat[4], (double)mat[5]); - } - - if (w == 0 && h == 0) return splashErrZeroImage; - - // check for singular matrix - if (!splashCheckDet(mat[0], mat[1], mat[2], mat[3], 0.000001)) { - return splashErrSingularMatrix; - } - - minorAxisZero = mat[1] == 0 && mat[2] == 0; - - // scaling only - if (mat[0] > 0 && minorAxisZero && mat[3] > 0) { - x0 = imgCoordMungeLowerC(mat[4], glyphMode); - y0 = imgCoordMungeLowerC(mat[5], glyphMode); - x1 = imgCoordMungeUpperC(mat[0] + mat[4], glyphMode); - y1 = imgCoordMungeUpperC(mat[3] + mat[5], glyphMode); - // make sure narrow images cover at least one pixel - if (x0 == x1) { - ++x1; - } - if (y0 == y1) { - ++y1; - } - clipRes = state->clip->testRect(x0, y0, x1 - 1, y1 - 1); - opClipRes = clipRes; - if (clipRes != splashClipAllOutside) { - scaledWidth = x1 - x0; - scaledHeight = y1 - y0; - yp = h / scaledHeight; - if (yp < 0 || yp > INT_MAX - 1) { - return splashErrBadArg; - } - scaledMask = scaleMask(src, srcData, w, h, scaledWidth, scaledHeight); - blitMask(scaledMask, x0, y0, clipRes); - delete scaledMask; - } - - // scaling plus vertical flip - } else if (mat[0] > 0 && minorAxisZero && mat[3] < 0) { - x0 = imgCoordMungeLowerC(mat[4], glyphMode); - y0 = imgCoordMungeLowerC(mat[3] + mat[5], glyphMode); - x1 = imgCoordMungeUpperC(mat[0] + mat[4], glyphMode); - y1 = imgCoordMungeUpperC(mat[5], glyphMode); - // make sure narrow images cover at least one pixel - if (x0 == x1) { - ++x1; - } - if (y0 == y1) { - ++y1; - } - clipRes = state->clip->testRect(x0, y0, x1 - 1, y1 - 1); - opClipRes = clipRes; - if (clipRes != splashClipAllOutside) { - scaledWidth = x1 - x0; - scaledHeight = y1 - y0; - yp = h / scaledHeight; - if (yp < 0 || yp > INT_MAX - 1) { - return splashErrBadArg; - } - scaledMask = scaleMask(src, srcData, w, h, scaledWidth, scaledHeight); - vertFlipImage(scaledMask, scaledWidth, scaledHeight, 1); - blitMask(scaledMask, x0, y0, clipRes); - delete scaledMask; - } - - // all other cases - } else { - arbitraryTransformMask(src, srcData, w, h, mat, glyphMode); - } - - return splashOk; -} - -void Splash::arbitraryTransformMask(SplashImageMaskSource src, void *srcData, - int srcWidth, int srcHeight, - SplashCoord *mat, GBool glyphMode) { - SplashBitmap *scaledMask; - SplashClipResult clipRes, clipRes2; - SplashPipe pipe; - int scaledWidth, scaledHeight, t0, t1; - SplashCoord r00, r01, r10, r11, det, ir00, ir01, ir10, ir11; - SplashCoord vx[4], vy[4]; - int xMin, yMin, xMax, yMax; - ImageSection section[3]; - int nSections; - int y, xa, xb, x, i, xx, yy; - - // compute the four vertices of the target quadrilateral - vx[0] = mat[4]; vy[0] = mat[5]; - vx[1] = mat[2] + mat[4]; vy[1] = mat[3] + mat[5]; - vx[2] = mat[0] + mat[2] + mat[4]; vy[2] = mat[1] + mat[3] + mat[5]; - vx[3] = mat[0] + mat[4]; vy[3] = mat[1] + mat[5]; - - // clipping - xMin = imgCoordMungeLowerC(vx[0], glyphMode); - xMax = imgCoordMungeUpperC(vx[0], glyphMode); - yMin = imgCoordMungeLowerC(vy[0], glyphMode); - yMax = imgCoordMungeUpperC(vy[0], glyphMode); - for (i = 1; i < 4; ++i) { - t0 = imgCoordMungeLowerC(vx[i], glyphMode); - if (t0 < xMin) { - xMin = t0; - } - t0 = imgCoordMungeUpperC(vx[i], glyphMode); - if (t0 > xMax) { - xMax = t0; - } - t1 = imgCoordMungeLowerC(vy[i], glyphMode); - if (t1 < yMin) { - yMin = t1; - } - t1 = imgCoordMungeUpperC(vy[i], glyphMode); - if (t1 > yMax) { - yMax = t1; - } - } - clipRes = state->clip->testRect(xMin, yMin, xMax - 1, yMax - 1); - opClipRes = clipRes; - if (clipRes == splashClipAllOutside) { - return; - } - - // compute the scale factors - if (mat[0] >= 0) { - t0 = imgCoordMungeUpperC(mat[0] + mat[4], glyphMode) - - imgCoordMungeLowerC(mat[4], glyphMode); - } else { - t0 = imgCoordMungeUpperC(mat[4], glyphMode) - - imgCoordMungeLowerC(mat[0] + mat[4], glyphMode); - } - if (mat[1] >= 0) { - t1 = imgCoordMungeUpperC(mat[1] + mat[5], glyphMode) - - imgCoordMungeLowerC(mat[5], glyphMode); - } else { - t1 = imgCoordMungeUpperC(mat[5], glyphMode) - - imgCoordMungeLowerC(mat[1] + mat[5], glyphMode); - } - scaledWidth = t0 > t1 ? t0 : t1; - if (mat[2] >= 0) { - t0 = imgCoordMungeUpperC(mat[2] + mat[4], glyphMode) - - imgCoordMungeLowerC(mat[4], glyphMode); - } else { - t0 = imgCoordMungeUpperC(mat[4], glyphMode) - - imgCoordMungeLowerC(mat[2] + mat[4], glyphMode); - } - if (mat[3] >= 0) { - t1 = imgCoordMungeUpperC(mat[3] + mat[5], glyphMode) - - imgCoordMungeLowerC(mat[5], glyphMode); - } else { - t1 = imgCoordMungeUpperC(mat[5], glyphMode) - - imgCoordMungeLowerC(mat[3] + mat[5], glyphMode); - } - scaledHeight = t0 > t1 ? t0 : t1; - if (scaledWidth == 0) { - scaledWidth = 1; - } - if (scaledHeight == 0) { - scaledHeight = 1; - } - - // compute the inverse transform (after scaling) matrix - r00 = mat[0] / scaledWidth; - r01 = mat[1] / scaledWidth; - r10 = mat[2] / scaledHeight; - r11 = mat[3] / scaledHeight; - det = r00 * r11 - r01 * r10; - if (splashAbs(det) < 1e-6) { - // this should be caught by the singular matrix check in fillImageMask - return; - } - ir00 = r11 / det; - ir01 = -r01 / det; - ir10 = -r10 / det; - ir11 = r00 / det; - - // scale the input image - scaledMask = scaleMask(src, srcData, srcWidth, srcHeight, - scaledWidth, scaledHeight); - if (scaledMask->data == NULL) { - error(errInternal, -1, "scaledMask->data is NULL in Splash::arbitraryTransformMask"); - delete scaledMask; - return; - } - - // construct the three sections - i = (vy[2] <= vy[3]) ? 2 : 3; - if (vy[1] <= vy[i]) { - i = 1; - } - if (vy[0] < vy[i] || (i != 3 && vy[0] == vy[i])) { - i = 0; - } - if (vy[i] == vy[(i+1) & 3]) { - section[0].y0 = imgCoordMungeLowerC(vy[i], glyphMode); - section[0].y1 = imgCoordMungeUpperC(vy[(i+2) & 3], glyphMode) - 1; - if (vx[i] < vx[(i+1) & 3]) { - section[0].ia0 = i; - section[0].ia1 = (i+3) & 3; - section[0].ib0 = (i+1) & 3; - section[0].ib1 = (i+2) & 3; - } else { - section[0].ia0 = (i+1) & 3; - section[0].ia1 = (i+2) & 3; - section[0].ib0 = i; - section[0].ib1 = (i+3) & 3; - } - nSections = 1; - } else { - section[0].y0 = imgCoordMungeLowerC(vy[i], glyphMode); - section[2].y1 = imgCoordMungeUpperC(vy[(i+2) & 3], glyphMode) - 1; - section[0].ia0 = section[0].ib0 = i; - section[2].ia1 = section[2].ib1 = (i+2) & 3; - if (vx[(i+1) & 3] < vx[(i+3) & 3]) { - section[0].ia1 = section[2].ia0 = (i+1) & 3; - section[0].ib1 = section[2].ib0 = (i+3) & 3; - } else { - section[0].ia1 = section[2].ia0 = (i+3) & 3; - section[0].ib1 = section[2].ib0 = (i+1) & 3; - } - if (vy[(i+1) & 3] < vy[(i+3) & 3]) { - section[1].y0 = imgCoordMungeLowerC(vy[(i+1) & 3], glyphMode); - section[2].y0 = imgCoordMungeUpperC(vy[(i+3) & 3], glyphMode); - if (vx[(i+1) & 3] < vx[(i+3) & 3]) { - section[1].ia0 = (i+1) & 3; - section[1].ia1 = (i+2) & 3; - section[1].ib0 = i; - section[1].ib1 = (i+3) & 3; - } else { - section[1].ia0 = i; - section[1].ia1 = (i+3) & 3; - section[1].ib0 = (i+1) & 3; - section[1].ib1 = (i+2) & 3; - } - } else { - section[1].y0 = imgCoordMungeLowerC(vy[(i+3) & 3], glyphMode); - section[2].y0 = imgCoordMungeUpperC(vy[(i+1) & 3], glyphMode); - if (vx[(i+1) & 3] < vx[(i+3) & 3]) { - section[1].ia0 = i; - section[1].ia1 = (i+1) & 3; - section[1].ib0 = (i+3) & 3; - section[1].ib1 = (i+2) & 3; - } else { - section[1].ia0 = (i+3) & 3; - section[1].ia1 = (i+2) & 3; - section[1].ib0 = i; - section[1].ib1 = (i+1) & 3; - } - } - section[0].y1 = section[1].y0 - 1; - section[1].y1 = section[2].y0 - 1; - nSections = 3; - } - for (i = 0; i < nSections; ++i) { - section[i].xa0 = vx[section[i].ia0]; - section[i].ya0 = vy[section[i].ia0]; - section[i].xa1 = vx[section[i].ia1]; - section[i].ya1 = vy[section[i].ia1]; - section[i].xb0 = vx[section[i].ib0]; - section[i].yb0 = vy[section[i].ib0]; - section[i].xb1 = vx[section[i].ib1]; - section[i].yb1 = vy[section[i].ib1]; - section[i].dxdya = (section[i].xa1 - section[i].xa0) / - (section[i].ya1 - section[i].ya0); - section[i].dxdyb = (section[i].xb1 - section[i].xb0) / - (section[i].yb1 - section[i].yb0); - } - - // initialize the pixel pipe - pipeInit(&pipe, 0, 0, state->fillPattern, NULL, - (Guchar)splashRound(state->fillAlpha * 255), gTrue, gFalse); - if (vectorAntialias) { - drawAAPixelInit(); - } - - // make sure narrow images cover at least one pixel - if (nSections == 1) { - if (section[0].y0 == section[0].y1) { - ++section[0].y1; - clipRes = opClipRes = splashClipPartial; - } - } else { - if (section[0].y0 == section[2].y1) { - ++section[1].y1; - clipRes = opClipRes = splashClipPartial; - } - } - - // scan all pixels inside the target region - for (i = 0; i < nSections; ++i) { - for (y = section[i].y0; y <= section[i].y1; ++y) { - xa = imgCoordMungeLowerC(section[i].xa0 + - ((SplashCoord)y + 0.5 - section[i].ya0) * - section[i].dxdya, - glyphMode); - xb = imgCoordMungeUpperC(section[i].xb0 + - ((SplashCoord)y + 0.5 - section[i].yb0) * - section[i].dxdyb, - glyphMode); - if (unlikely(xa < 0)) - xa = 0; - // make sure narrow images cover at least one pixel - if (xa == xb) { - ++xb; - } - if (clipRes != splashClipAllInside) { - clipRes2 = state->clip->testSpan(xa, xb - 1, y); - } else { - clipRes2 = clipRes; - } - for (x = xa; x < xb; ++x) { - // map (x+0.5, y+0.5) back to the scaled image - xx = splashFloor(((SplashCoord)x + 0.5 - mat[4]) * ir00 + - ((SplashCoord)y + 0.5 - mat[5]) * ir10); - yy = splashFloor(((SplashCoord)x + 0.5 - mat[4]) * ir01 + - ((SplashCoord)y + 0.5 - mat[5]) * ir11); - // xx should always be within bounds, but floating point - // inaccuracy can cause problems - if (xx < 0) { - xx = 0; - } else if (xx >= scaledWidth) { - xx = scaledWidth - 1; - } - if (yy < 0) { - yy = 0; - } else if (yy >= scaledHeight) { - yy = scaledHeight - 1; - } - pipe.shape = scaledMask->data[yy * scaledWidth + xx]; - if (vectorAntialias && clipRes2 != splashClipAllInside) { - drawAAPixel(&pipe, x, y); - } else { - drawPixel(&pipe, x, y, clipRes2 == splashClipAllInside); - } - } - } - } - - delete scaledMask; -} - -// Scale an image mask into a SplashBitmap. -SplashBitmap *Splash::scaleMask(SplashImageMaskSource src, void *srcData, - int srcWidth, int srcHeight, - int scaledWidth, int scaledHeight) { - SplashBitmap *dest; - - dest = new SplashBitmap(scaledWidth, scaledHeight, 1, splashModeMono8, - gFalse); - if (scaledHeight < srcHeight) { - if (scaledWidth < srcWidth) { - scaleMaskYdXd(src, srcData, srcWidth, srcHeight, - scaledWidth, scaledHeight, dest); - } else { - scaleMaskYdXu(src, srcData, srcWidth, srcHeight, - scaledWidth, scaledHeight, dest); - } - } else { - if (scaledWidth < srcWidth) { - scaleMaskYuXd(src, srcData, srcWidth, srcHeight, - scaledWidth, scaledHeight, dest); - } else { - scaleMaskYuXu(src, srcData, srcWidth, srcHeight, - scaledWidth, scaledHeight, dest); - } - } - return dest; -} - -void Splash::scaleMaskYdXd(SplashImageMaskSource src, void *srcData, - int srcWidth, int srcHeight, - int scaledWidth, int scaledHeight, - SplashBitmap *dest) { - Guchar *lineBuf; - Guint *pixBuf; - Guint pix; - Guchar *destPtr; - int yp, yq, xp, xq, yt, y, yStep, xt, x, xStep, xx, d, d0, d1; - int i, j; - - // Bresenham parameters for y scale - yp = srcHeight / scaledHeight; - yq = srcHeight % scaledHeight; - - // Bresenham parameters for x scale - xp = srcWidth / scaledWidth; - xq = srcWidth % scaledWidth; - - // allocate buffers - lineBuf = (Guchar *)gmalloc(srcWidth); - pixBuf = (Guint *)gmallocn(srcWidth, sizeof(int)); - - // init y scale Bresenham - yt = 0; - - destPtr = dest->data; - for (y = 0; y < scaledHeight; ++y) { - - // y scale Bresenham - if ((yt += yq) >= scaledHeight) { - yt -= scaledHeight; - yStep = yp + 1; - } else { - yStep = yp; - } - - // read rows from image - memset(pixBuf, 0, srcWidth * sizeof(int)); - for (i = 0; i < yStep; ++i) { - (*src)(srcData, lineBuf); - for (j = 0; j < srcWidth; ++j) { - pixBuf[j] += lineBuf[j]; - } - } - - // init x scale Bresenham - xt = 0; - d0 = (255 << 23) / (yStep * xp); - d1 = (255 << 23) / (yStep * (xp + 1)); - - xx = 0; - for (x = 0; x < scaledWidth; ++x) { - - // x scale Bresenham - if ((xt += xq) >= scaledWidth) { - xt -= scaledWidth; - xStep = xp + 1; - d = d1; - } else { - xStep = xp; - d = d0; - } - - // compute the final pixel - pix = 0; - for (i = 0; i < xStep; ++i) { - pix += pixBuf[xx++]; - } - // (255 * pix) / xStep * yStep - pix = (pix * d) >> 23; - - // store the pixel - *destPtr++ = (Guchar)pix; - } - } - - gfree(pixBuf); - gfree(lineBuf); -} - -void Splash::scaleMaskYdXu(SplashImageMaskSource src, void *srcData, - int srcWidth, int srcHeight, - int scaledWidth, int scaledHeight, - SplashBitmap *dest) { - Guchar *lineBuf; - Guint *pixBuf; - Guint pix; - Guchar *destPtr; - int yp, yq, xp, xq, yt, y, yStep, xt, x, xStep, d; - int i, j; - - destPtr = dest->data; - if (destPtr == NULL) { - error(errInternal, -1, "dest->data is NULL in Splash::scaleMaskYdXu"); - return; - } - - // Bresenham parameters for y scale - yp = srcHeight / scaledHeight; - yq = srcHeight % scaledHeight; - - // Bresenham parameters for x scale - xp = scaledWidth / srcWidth; - xq = scaledWidth % srcWidth; - - // allocate buffers - lineBuf = (Guchar *)gmalloc(srcWidth); - pixBuf = (Guint *)gmallocn(srcWidth, sizeof(int)); - - // init y scale Bresenham - yt = 0; - - for (y = 0; y < scaledHeight; ++y) { - - // y scale Bresenham - if ((yt += yq) >= scaledHeight) { - yt -= scaledHeight; - yStep = yp + 1; - } else { - yStep = yp; - } - - // read rows from image - memset(pixBuf, 0, srcWidth * sizeof(int)); - for (i = 0; i < yStep; ++i) { - (*src)(srcData, lineBuf); - for (j = 0; j < srcWidth; ++j) { - pixBuf[j] += lineBuf[j]; - } - } - - // init x scale Bresenham - xt = 0; - d = (255 << 23) / yStep; - - for (x = 0; x < srcWidth; ++x) { - - // x scale Bresenham - if ((xt += xq) >= srcWidth) { - xt -= srcWidth; - xStep = xp + 1; - } else { - xStep = xp; - } - - // compute the final pixel - pix = pixBuf[x]; - // (255 * pix) / yStep - pix = (pix * d) >> 23; - - // store the pixel - for (i = 0; i < xStep; ++i) { - *destPtr++ = (Guchar)pix; - } - } - } - - gfree(pixBuf); - gfree(lineBuf); -} - -void Splash::scaleMaskYuXd(SplashImageMaskSource src, void *srcData, - int srcWidth, int srcHeight, - int scaledWidth, int scaledHeight, - SplashBitmap *dest) { - Guchar *lineBuf; - Guint pix; - Guchar *destPtr0, *destPtr; - int yp, yq, xp, xq, yt, y, yStep, xt, x, xStep, xx, d, d0, d1; - int i; - - destPtr0 = dest->data; - if (destPtr0 == NULL) { - error(errInternal, -1, "dest->data is NULL in Splash::scaleMaskYuXd"); - return; - } - - // Bresenham parameters for y scale - yp = scaledHeight / srcHeight; - yq = scaledHeight % srcHeight; - - // Bresenham parameters for x scale - xp = srcWidth / scaledWidth; - xq = srcWidth % scaledWidth; - - // allocate buffers - lineBuf = (Guchar *)gmalloc(srcWidth); - - // init y scale Bresenham - yt = 0; - - for (y = 0; y < srcHeight; ++y) { - - // y scale Bresenham - if ((yt += yq) >= srcHeight) { - yt -= srcHeight; - yStep = yp + 1; - } else { - yStep = yp; - } - - // read row from image - (*src)(srcData, lineBuf); - - // init x scale Bresenham - xt = 0; - d0 = (255 << 23) / xp; - d1 = (255 << 23) / (xp + 1); - - xx = 0; - for (x = 0; x < scaledWidth; ++x) { - - // x scale Bresenham - if ((xt += xq) >= scaledWidth) { - xt -= scaledWidth; - xStep = xp + 1; - d = d1; - } else { - xStep = xp; - d = d0; - } - - // compute the final pixel - pix = 0; - for (i = 0; i < xStep; ++i) { - pix += lineBuf[xx++]; - } - // (255 * pix) / xStep - pix = (pix * d) >> 23; - - // store the pixel - for (i = 0; i < yStep; ++i) { - destPtr = destPtr0 + i * scaledWidth + x; - *destPtr = (Guchar)pix; - } - } - - destPtr0 += yStep * scaledWidth; - } - - gfree(lineBuf); -} - -void Splash::scaleMaskYuXu(SplashImageMaskSource src, void *srcData, - int srcWidth, int srcHeight, - int scaledWidth, int scaledHeight, - SplashBitmap *dest) { - Guchar *lineBuf; - Guint pix; - Guchar *destPtr0, *destPtr; - int yp, yq, xp, xq, yt, y, yStep, xt, x, xStep, xx; - int i, j; - - destPtr0 = dest->data; - if (destPtr0 == NULL) { - error(errInternal, -1, "dest->data is NULL in Splash::scaleMaskYuXu"); - return; - } - - // Bresenham parameters for y scale - yp = scaledHeight / srcHeight; - yq = scaledHeight % srcHeight; - - // Bresenham parameters for x scale - xp = scaledWidth / srcWidth; - xq = scaledWidth % srcWidth; - - // allocate buffers - lineBuf = (Guchar *)gmalloc(srcWidth); - - // init y scale Bresenham - yt = 0; - - for (y = 0; y < srcHeight; ++y) { - - // y scale Bresenham - if ((yt += yq) >= srcHeight) { - yt -= srcHeight; - yStep = yp + 1; - } else { - yStep = yp; - } - - // read row from image - (*src)(srcData, lineBuf); - - // init x scale Bresenham - xt = 0; - - xx = 0; - for (x = 0; x < srcWidth; ++x) { - - // x scale Bresenham - if ((xt += xq) >= srcWidth) { - xt -= srcWidth; - xStep = xp + 1; - } else { - xStep = xp; - } - - // compute the final pixel - pix = lineBuf[x] ? 255 : 0; - - // store the pixel - for (i = 0; i < yStep; ++i) { - for (j = 0; j < xStep; ++j) { - destPtr = destPtr0 + i * scaledWidth + xx + j; - *destPtr++ = (Guchar)pix; - } - } - - xx += xStep; - } - - destPtr0 += yStep * scaledWidth; - } - - gfree(lineBuf); -} - -void Splash::blitMask(SplashBitmap *src, int xDest, int yDest, - SplashClipResult clipRes) { - SplashPipe pipe; - Guchar *p; - int w, h, x, y; - - w = src->getWidth(); - h = src->getHeight(); - p = src->getDataPtr(); - if (p == NULL) { - error(errInternal, -1, "src->getDataPtr() is NULL in Splash::blitMask"); - return; - } - if (vectorAntialias && clipRes != splashClipAllInside) { - pipeInit(&pipe, xDest, yDest, state->fillPattern, NULL, - (Guchar)splashRound(state->fillAlpha * 255), gTrue, gFalse); - drawAAPixelInit(); - for (y = 0; y < h; ++y) { - for (x = 0; x < w; ++x) { - pipe.shape = *p++; - drawAAPixel(&pipe, xDest + x, yDest + y); - } - } - } else { - pipeInit(&pipe, xDest, yDest, state->fillPattern, NULL, - (Guchar)splashRound(state->fillAlpha * 255), gTrue, gFalse); - if (clipRes == splashClipAllInside) { - for (y = 0; y < h; ++y) { - pipeSetXY(&pipe, xDest, yDest + y); - for (x = 0; x < w; ++x) { - if (*p) { - pipe.shape = *p; - (this->*pipe.run)(&pipe); - } else { - pipeIncX(&pipe); - } - ++p; - } - } - updateModX(xDest); - updateModX(xDest + w - 1); - updateModY(yDest); - updateModY(yDest + h - 1); - } else { - for (y = 0; y < h; ++y) { - pipeSetXY(&pipe, xDest, yDest + y); - for (x = 0; x < w; ++x) { - if (*p && state->clip->test(xDest + x, yDest + y)) { - pipe.shape = *p; - (this->*pipe.run)(&pipe); - updateModX(xDest + x); - updateModY(yDest + y); - } else { - pipeIncX(&pipe); - } - ++p; - } - } - } - } -} - -SplashError Splash::drawImage(SplashImageSource src, SplashICCTransform tf, void *srcData, - SplashColorMode srcMode, GBool srcAlpha, - int w, int h, SplashCoord *mat, GBool interpolate, - GBool tilingPattern) { - GBool ok; - SplashBitmap *scaledImg; - SplashClipResult clipRes; - GBool minorAxisZero; - int x0, y0, x1, y1, scaledWidth, scaledHeight; - int nComps; - int yp; - - if (debugMode) { - printf("drawImage: srcMode=%d srcAlpha=%d w=%d h=%d mat=[%.2f %.2f %.2f %.2f %.2f %.2f]\n", - srcMode, srcAlpha, w, h, (double)mat[0], (double)mat[1], (double)mat[2], - (double)mat[3], (double)mat[4], (double)mat[5]); - } - - // check color modes - ok = gFalse; // make gcc happy - nComps = 0; // make gcc happy - switch (bitmap->mode) { - case splashModeMono1: - case splashModeMono8: - ok = srcMode == splashModeMono8; - nComps = 1; - break; - case splashModeRGB8: - ok = srcMode == splashModeRGB8; - nComps = 3; - break; - case splashModeXBGR8: - ok = srcMode == splashModeXBGR8; - nComps = 4; - break; - case splashModeBGR8: - ok = srcMode == splashModeBGR8; - nComps = 3; - break; -#ifdef SPLASH_CMYK - case splashModeCMYK8: - ok = srcMode == splashModeCMYK8; - nComps = 4; - break; - case splashModeDeviceN8: - ok = srcMode == splashModeDeviceN8; - nComps = SPOT_NCOMPS+4; - break; -#endif - default: - ok = gFalse; - break; - } - if (!ok) { - return splashErrModeMismatch; - } - - // check for singular matrix - if (!splashCheckDet(mat[0], mat[1], mat[2], mat[3], 0.000001)) { - return splashErrSingularMatrix; - } - - minorAxisZero = mat[1] == 0 && mat[2] == 0; - - // scaling only - if (mat[0] > 0 && minorAxisZero && mat[3] > 0) { - x0 = imgCoordMungeLower(mat[4]); - y0 = imgCoordMungeLower(mat[5]); - x1 = imgCoordMungeUpper(mat[0] + mat[4]); - y1 = imgCoordMungeUpper(mat[3] + mat[5]); - // make sure narrow images cover at least one pixel - if (x0 == x1) { - ++x1; - } - if (y0 == y1) { - ++y1; - } - clipRes = state->clip->testRect(x0, y0, x1 - 1, y1 - 1); - opClipRes = clipRes; - if (clipRes != splashClipAllOutside) { - scaledWidth = x1 - x0; - scaledHeight = y1 - y0; - yp = h / scaledHeight; - if (yp < 0 || yp > INT_MAX - 1) { - return splashErrBadArg; - } - scaledImg = scaleImage(src, srcData, srcMode, nComps, srcAlpha, w, h, - scaledWidth, scaledHeight, interpolate, tilingPattern); - if (scaledImg == NULL) { - return splashErrBadArg; - } - if (tf != NULL) { - (*tf)(srcData, scaledImg); - } - blitImage(scaledImg, srcAlpha, x0, y0, clipRes); - delete scaledImg; - } - - // scaling plus vertical flip - } else if (mat[0] > 0 && minorAxisZero && mat[3] < 0) { - x0 = imgCoordMungeLower(mat[4]); - y0 = imgCoordMungeLower(mat[3] + mat[5]); - x1 = imgCoordMungeUpper(mat[0] + mat[4]); - y1 = imgCoordMungeUpper(mat[5]); - if (x0 == x1) { - if (mat[4] + mat[0] * 0.5 < x0) { - --x0; - } else { - ++x1; - } - } - if (y0 == y1) { - if (mat[5] + mat[1] * 0.5 < y0) { - --y0; - } else { - ++y1; - } - } - clipRes = state->clip->testRect(x0, y0, x1 - 1, y1 - 1); - opClipRes = clipRes; - if (clipRes != splashClipAllOutside) { - scaledWidth = x1 - x0; - scaledHeight = y1 - y0; - yp = h / scaledHeight; - if (yp < 0 || yp > INT_MAX - 1) { - return splashErrBadArg; - } - scaledImg = scaleImage(src, srcData, srcMode, nComps, srcAlpha, w, h, - scaledWidth, scaledHeight, interpolate, tilingPattern); - if (scaledImg == NULL) { - return splashErrBadArg; - } - if (tf != NULL) { - (*tf)(srcData, scaledImg); - } - vertFlipImage(scaledImg, scaledWidth, scaledHeight, nComps); - blitImage(scaledImg, srcAlpha, x0, y0, clipRes); - delete scaledImg; - } - - // all other cases - } else { - return arbitraryTransformImage(src, tf, srcData, srcMode, nComps, srcAlpha, - w, h, mat, interpolate, tilingPattern); - } - - return splashOk; -} - -SplashError Splash::arbitraryTransformImage(SplashImageSource src, SplashICCTransform tf, void *srcData, - SplashColorMode srcMode, int nComps, - GBool srcAlpha, - int srcWidth, int srcHeight, - SplashCoord *mat, GBool interpolate, - GBool tilingPattern) { - SplashBitmap *scaledImg; - SplashClipResult clipRes, clipRes2; - SplashPipe pipe; - SplashColor pixel; - int scaledWidth, scaledHeight, t0, t1, th; - SplashCoord r00, r01, r10, r11, det, ir00, ir01, ir10, ir11; - SplashCoord vx[4], vy[4]; - int xMin, yMin, xMax, yMax; - ImageSection section[3]; - int nSections; - int y, xa, xb, x, i, xx, yy, yp; - - // compute the four vertices of the target quadrilateral - vx[0] = mat[4]; vy[0] = mat[5]; - vx[1] = mat[2] + mat[4]; vy[1] = mat[3] + mat[5]; - vx[2] = mat[0] + mat[2] + mat[4]; vy[2] = mat[1] + mat[3] + mat[5]; - vx[3] = mat[0] + mat[4]; vy[3] = mat[1] + mat[5]; - - // clipping - xMin = imgCoordMungeLower(vx[0]); - xMax = imgCoordMungeUpper(vx[0]); - yMin = imgCoordMungeLower(vy[0]); - yMax = imgCoordMungeUpper(vy[0]); - for (i = 1; i < 4; ++i) { - t0 = imgCoordMungeLower(vx[i]); - if (t0 < xMin) { - xMin = t0; - } - t0 = imgCoordMungeUpper(vx[i]); - if (t0 > xMax) { - xMax = t0; - } - t1 = imgCoordMungeLower(vy[i]); - if (t1 < yMin) { - yMin = t1; - } - t1 = imgCoordMungeUpper(vy[i]); - if (t1 > yMax) { - yMax = t1; - } - } - clipRes = state->clip->testRect(xMin, yMin, xMax, yMax); - opClipRes = clipRes; - if (clipRes == splashClipAllOutside) { - return splashOk; - } - - // compute the scale factors - if (splashAbs(mat[0]) >= splashAbs(mat[1])) { - scaledWidth = xMax - xMin; - scaledHeight = yMax - yMin; - } else { - scaledWidth = yMax - yMin; - scaledHeight = xMax - xMin; - } - if (scaledHeight <= 1 || scaledWidth <= 1 || tilingPattern) { - if (mat[0] >= 0) { - t0 = imgCoordMungeUpper(mat[0] + mat[4]) - imgCoordMungeLower(mat[4]); - } else { - t0 = imgCoordMungeUpper(mat[4]) - imgCoordMungeLower(mat[0] + mat[4]); - } - if (mat[1] >= 0) { - t1 = imgCoordMungeUpper(mat[1] + mat[5]) - imgCoordMungeLower(mat[5]); - } else { - t1 = imgCoordMungeUpper(mat[5]) - imgCoordMungeLower(mat[1] + mat[5]); - } - scaledWidth = t0 > t1 ? t0 : t1; - if (mat[2] >= 0) { - t0 = imgCoordMungeUpper(mat[2] + mat[4]) - imgCoordMungeLower(mat[4]); - if (splashAbs(mat[1]) >= 1) { - th = imgCoordMungeUpper(mat[2]) - imgCoordMungeLower(mat[0] * mat[3] / mat[1]); - if (th > t0) t0 = th; - } - } else { - t0 = imgCoordMungeUpper(mat[4]) - imgCoordMungeLower(mat[2] + mat[4]); - if (splashAbs(mat[1]) >= 1) { - th = imgCoordMungeUpper(mat[0] * mat[3] / mat[1]) - imgCoordMungeLower(mat[2]); - if (th > t0) t0 = th; - } - } - if (mat[3] >= 0) { - t1 = imgCoordMungeUpper(mat[3] + mat[5]) - imgCoordMungeLower(mat[5]); - if (splashAbs(mat[0]) >= 1) { - th = imgCoordMungeUpper(mat[3]) - imgCoordMungeLower(mat[1] * mat[2] / mat[0]); - if (th > t1) t1 = th; - } - } else { - t1 = imgCoordMungeUpper(mat[5]) - imgCoordMungeLower(mat[3] + mat[5]); - if (splashAbs(mat[0]) >= 1) { - th = imgCoordMungeUpper(mat[1] * mat[2] / mat[0]) - imgCoordMungeLower(mat[3]); - if (th > t1) t1 = th; - } - } - scaledHeight = t0 > t1 ? t0 : t1; - } - if (scaledWidth == 0) { - scaledWidth = 1; - } - if (scaledHeight == 0) { - scaledHeight = 1; - } - - // compute the inverse transform (after scaling) matrix - r00 = mat[0] / scaledWidth; - r01 = mat[1] / scaledWidth; - r10 = mat[2] / scaledHeight; - r11 = mat[3] / scaledHeight; - det = r00 * r11 - r01 * r10; - if (splashAbs(det) < 1e-6) { - // this should be caught by the singular matrix check in drawImage - return splashErrBadArg; - } - ir00 = r11 / det; - ir01 = -r01 / det; - ir10 = -r10 / det; - ir11 = r00 / det; - - // scale the input image - yp = srcHeight / scaledHeight; - if (yp < 0 || yp > INT_MAX - 1) { - return splashErrBadArg; - } - scaledImg = scaleImage(src, srcData, srcMode, nComps, srcAlpha, - srcWidth, srcHeight, scaledWidth, scaledHeight, interpolate); - - if (scaledImg == NULL) { - return splashErrBadArg; - } - - if (tf != NULL) { - (*tf)(srcData, scaledImg); - } - // construct the three sections - i = 0; - if (vy[1] < vy[i]) { - i = 1; - } - if (vy[2] < vy[i]) { - i = 2; - } - if (vy[3] < vy[i]) { - i = 3; - } - // NB: if using fixed point, 0.000001 will be truncated to zero, - // so these two comparisons must be <=, not < - if (splashAbs(vy[i] - vy[(i-1) & 3]) <= 0.000001 && - vy[(i-1) & 3] < vy[(i+1) & 3]) { - i = (i-1) & 3; - } - if (splashAbs(vy[i] - vy[(i+1) & 3]) <= 0.000001) { - section[0].y0 = imgCoordMungeLower(vy[i]); - section[0].y1 = imgCoordMungeUpper(vy[(i+2) & 3]) - 1; - if (vx[i] < vx[(i+1) & 3]) { - section[0].ia0 = i; - section[0].ia1 = (i+3) & 3; - section[0].ib0 = (i+1) & 3; - section[0].ib1 = (i+2) & 3; - } else { - section[0].ia0 = (i+1) & 3; - section[0].ia1 = (i+2) & 3; - section[0].ib0 = i; - section[0].ib1 = (i+3) & 3; - } - nSections = 1; - } else { - section[0].y0 = imgCoordMungeLower(vy[i]); - section[2].y1 = imgCoordMungeUpper(vy[(i+2) & 3]) - 1; - section[0].ia0 = section[0].ib0 = i; - section[2].ia1 = section[2].ib1 = (i+2) & 3; - if (vx[(i+1) & 3] < vx[(i+3) & 3]) { - section[0].ia1 = section[2].ia0 = (i+1) & 3; - section[0].ib1 = section[2].ib0 = (i+3) & 3; - } else { - section[0].ia1 = section[2].ia0 = (i+3) & 3; - section[0].ib1 = section[2].ib0 = (i+1) & 3; - } - if (vy[(i+1) & 3] < vy[(i+3) & 3]) { - section[1].y0 = imgCoordMungeLower(vy[(i+1) & 3]); - section[2].y0 = imgCoordMungeUpper(vy[(i+3) & 3]); - if (vx[(i+1) & 3] < vx[(i+3) & 3]) { - section[1].ia0 = (i+1) & 3; - section[1].ia1 = (i+2) & 3; - section[1].ib0 = i; - section[1].ib1 = (i+3) & 3; - } else { - section[1].ia0 = i; - section[1].ia1 = (i+3) & 3; - section[1].ib0 = (i+1) & 3; - section[1].ib1 = (i+2) & 3; - } - } else { - section[1].y0 = imgCoordMungeLower(vy[(i+3) & 3]); - section[2].y0 = imgCoordMungeUpper(vy[(i+1) & 3]); - if (vx[(i+1) & 3] < vx[(i+3) & 3]) { - section[1].ia0 = i; - section[1].ia1 = (i+1) & 3; - section[1].ib0 = (i+3) & 3; - section[1].ib1 = (i+2) & 3; - } else { - section[1].ia0 = (i+3) & 3; - section[1].ia1 = (i+2) & 3; - section[1].ib0 = i; - section[1].ib1 = (i+1) & 3; - } - } - section[0].y1 = section[1].y0 - 1; - section[1].y1 = section[2].y0 - 1; - nSections = 3; - } - for (i = 0; i < nSections; ++i) { - section[i].xa0 = vx[section[i].ia0]; - section[i].ya0 = vy[section[i].ia0]; - section[i].xa1 = vx[section[i].ia1]; - section[i].ya1 = vy[section[i].ia1]; - section[i].xb0 = vx[section[i].ib0]; - section[i].yb0 = vy[section[i].ib0]; - section[i].xb1 = vx[section[i].ib1]; - section[i].yb1 = vy[section[i].ib1]; - section[i].dxdya = (section[i].xa1 - section[i].xa0) / - (section[i].ya1 - section[i].ya0); - section[i].dxdyb = (section[i].xb1 - section[i].xb0) / - (section[i].yb1 - section[i].yb0); - } - - // initialize the pixel pipe - pipeInit(&pipe, 0, 0, NULL, pixel, - (Guchar)splashRound(state->fillAlpha * 255), - srcAlpha || (vectorAntialias && clipRes != splashClipAllInside), - gFalse); - if (vectorAntialias) { - drawAAPixelInit(); - } - - // make sure narrow images cover at least one pixel - if (nSections == 1) { - if (section[0].y0 == section[0].y1) { - ++section[0].y1; - clipRes = opClipRes = splashClipPartial; - } - } else { - if (section[0].y0 == section[2].y1) { - ++section[1].y1; - clipRes = opClipRes = splashClipPartial; - } - } - - // scan all pixels inside the target region - for (i = 0; i < nSections; ++i) { - for (y = section[i].y0; y <= section[i].y1; ++y) { - xa = imgCoordMungeLower(section[i].xa0 + - ((SplashCoord)y + 0.5 - section[i].ya0) * - section[i].dxdya); - if (unlikely(xa < 0)) - xa = 0; - xb = imgCoordMungeUpper(section[i].xb0 + - ((SplashCoord)y + 0.5 - section[i].yb0) * - section[i].dxdyb); - // make sure narrow images cover at least one pixel - if (xa == xb) { - ++xb; - } - if (clipRes != splashClipAllInside) { - clipRes2 = state->clip->testSpan(xa, xb - 1, y); - } else { - clipRes2 = clipRes; - } - for (x = xa; x < xb; ++x) { - // map (x+0.5, y+0.5) back to the scaled image - xx = splashFloor(((SplashCoord)x + 0.5 - mat[4]) * ir00 + - ((SplashCoord)y + 0.5 - mat[5]) * ir10); - yy = splashFloor(((SplashCoord)x + 0.5 - mat[4]) * ir01 + - ((SplashCoord)y + 0.5 - mat[5]) * ir11); - // xx should always be within bounds, but floating point - // inaccuracy can cause problems - if (xx < 0) { - xx = 0; - } else if (xx >= scaledWidth) { - xx = scaledWidth - 1; - } - if (yy < 0) { - yy = 0; - } else if (yy >= scaledHeight) { - yy = scaledHeight - 1; - } - scaledImg->getPixel(xx, yy, pixel); - if (srcAlpha) { - pipe.shape = scaledImg->alpha[yy * scaledWidth + xx]; - } else { - pipe.shape = 255; - } - if (vectorAntialias && clipRes2 != splashClipAllInside) { - drawAAPixel(&pipe, x, y); - } else { - drawPixel(&pipe, x, y, clipRes2 == splashClipAllInside); - } - } - } - } - - delete scaledImg; - return splashOk; -} - -// determine if a scaled image requires interpolation based on the scale and -// the interpolate flag from the image dictionary -static GBool isImageInterpolationRequired(int srcWidth, int srcHeight, - int scaledWidth, int scaledHeight, - GBool interpolate) { - if (interpolate || srcWidth == 0 || srcHeight == 0) - return gTrue; - - /* When scale factor is >= 400% we don't interpolate. See bugs #25268, #9860 */ - if (scaledWidth / srcWidth >= 4 || scaledHeight / srcHeight >= 4) - return gFalse; - - return gTrue; -} - -// Scale an image into a SplashBitmap. -SplashBitmap *Splash::scaleImage(SplashImageSource src, void *srcData, - SplashColorMode srcMode, int nComps, - GBool srcAlpha, int srcWidth, int srcHeight, - int scaledWidth, int scaledHeight, GBool interpolate, GBool tilingPattern) { - SplashBitmap *dest; - - dest = new SplashBitmap(scaledWidth, scaledHeight, 1, srcMode, srcAlpha, gTrue, bitmap->getSeparationList()); - if (dest->getDataPtr() != NULL && srcHeight > 0 && srcWidth > 0) { - if (scaledHeight < srcHeight) { - if (scaledWidth < srcWidth) { - scaleImageYdXd(src, srcData, srcMode, nComps, srcAlpha, - srcWidth, srcHeight, scaledWidth, scaledHeight, dest); - } else { - scaleImageYdXu(src, srcData, srcMode, nComps, srcAlpha, - srcWidth, srcHeight, scaledWidth, scaledHeight, dest); - } - } else { - if (scaledWidth < srcWidth) { - scaleImageYuXd(src, srcData, srcMode, nComps, srcAlpha, - srcWidth, srcHeight, scaledWidth, scaledHeight, dest); - } else { - if (!tilingPattern && isImageInterpolationRequired(srcWidth, srcHeight, scaledWidth, scaledHeight, interpolate)) { - scaleImageYuXuBilinear(src, srcData, srcMode, nComps, srcAlpha, - srcWidth, srcHeight, scaledWidth, scaledHeight, dest); - } else { - scaleImageYuXu(src, srcData, srcMode, nComps, srcAlpha, - srcWidth, srcHeight, scaledWidth, scaledHeight, dest); - } - } - } - } else { - delete dest; - dest = NULL; - } - return dest; -} - -void Splash::scaleImageYdXd(SplashImageSource src, void *srcData, - SplashColorMode srcMode, int nComps, - GBool srcAlpha, int srcWidth, int srcHeight, - int scaledWidth, int scaledHeight, - SplashBitmap *dest) { - Guchar *lineBuf, *alphaLineBuf; - Guint *pixBuf, *alphaPixBuf; - Guint pix0, pix1, pix2; -#ifdef SPLASH_CMYK - Guint pix3; - Guint pix[SPOT_NCOMPS+4], cp; -#endif - Guint alpha; - Guchar *destPtr, *destAlphaPtr; - int yp, yq, xp, xq, yt, y, yStep, xt, x, xStep, xx, xxa, d, d0, d1; - int i, j; - - // Bresenham parameters for y scale - yp = srcHeight / scaledHeight; - yq = srcHeight % scaledHeight; - - // Bresenham parameters for x scale - xp = srcWidth / scaledWidth; - xq = srcWidth % scaledWidth; - - // allocate buffers - lineBuf = (Guchar *)gmallocn(srcWidth, nComps); - pixBuf = (Guint *)gmallocn(srcWidth, nComps * sizeof(int)); - if (srcAlpha) { - alphaLineBuf = (Guchar *)gmalloc(srcWidth); - alphaPixBuf = (Guint *)gmallocn(srcWidth, sizeof(int)); - } else { - alphaLineBuf = NULL; - alphaPixBuf = NULL; - } - - // init y scale Bresenham - yt = 0; - - destPtr = dest->data; - destAlphaPtr = dest->alpha; - for (y = 0; y < scaledHeight; ++y) { - - // y scale Bresenham - if ((yt += yq) >= scaledHeight) { - yt -= scaledHeight; - yStep = yp + 1; - } else { - yStep = yp; - } - - // read rows from image - memset(pixBuf, 0, srcWidth * nComps * sizeof(int)); - if (srcAlpha) { - memset(alphaPixBuf, 0, srcWidth * sizeof(int)); - } - for (i = 0; i < yStep; ++i) { - (*src)(srcData, lineBuf, alphaLineBuf); - for (j = 0; j < srcWidth * nComps; ++j) { - pixBuf[j] += lineBuf[j]; - } - if (srcAlpha) { - for (j = 0; j < srcWidth; ++j) { - alphaPixBuf[j] += alphaLineBuf[j]; - } - } - } - - // init x scale Bresenham - xt = 0; - d0 = (1 << 23) / (yStep * xp); - d1 = (1 << 23) / (yStep * (xp + 1)); - - xx = xxa = 0; - for (x = 0; x < scaledWidth; ++x) { - - // x scale Bresenham - if ((xt += xq) >= scaledWidth) { - xt -= scaledWidth; - xStep = xp + 1; - d = d1; - } else { - xStep = xp; - d = d0; - } - - switch (srcMode) { - - case splashModeMono8: - - // compute the final pixel - pix0 = 0; - for (i = 0; i < xStep; ++i) { - pix0 += pixBuf[xx++]; - } - // pix / xStep * yStep - pix0 = (pix0 * d) >> 23; - - // store the pixel - *destPtr++ = (Guchar)pix0; - break; - - case splashModeRGB8: - - // compute the final pixel - pix0 = pix1 = pix2 = 0; - for (i = 0; i < xStep; ++i) { - pix0 += pixBuf[xx]; - pix1 += pixBuf[xx+1]; - pix2 += pixBuf[xx+2]; - xx += 3; - } - // pix / xStep * yStep - pix0 = (pix0 * d) >> 23; - pix1 = (pix1 * d) >> 23; - pix2 = (pix2 * d) >> 23; - - // store the pixel - *destPtr++ = (Guchar)pix0; - *destPtr++ = (Guchar)pix1; - *destPtr++ = (Guchar)pix2; - break; - - case splashModeXBGR8: - - // compute the final pixel - pix0 = pix1 = pix2 = 0; - for (i = 0; i < xStep; ++i) { - pix0 += pixBuf[xx]; - pix1 += pixBuf[xx+1]; - pix2 += pixBuf[xx+2]; - xx += 4; - } - // pix / xStep * yStep - pix0 = (pix0 * d) >> 23; - pix1 = (pix1 * d) >> 23; - pix2 = (pix2 * d) >> 23; - - // store the pixel - *destPtr++ = (Guchar)pix2; - *destPtr++ = (Guchar)pix1; - *destPtr++ = (Guchar)pix0; - *destPtr++ = (Guchar)255; - break; - - case splashModeBGR8: - - // compute the final pixel - pix0 = pix1 = pix2 = 0; - for (i = 0; i < xStep; ++i) { - pix0 += pixBuf[xx]; - pix1 += pixBuf[xx+1]; - pix2 += pixBuf[xx+2]; - xx += 3; - } - // pix / xStep * yStep - pix0 = (pix0 * d) >> 23; - pix1 = (pix1 * d) >> 23; - pix2 = (pix2 * d) >> 23; - - // store the pixel - *destPtr++ = (Guchar)pix2; - *destPtr++ = (Guchar)pix1; - *destPtr++ = (Guchar)pix0; - break; - -#ifdef SPLASH_CMYK - case splashModeCMYK8: - - // compute the final pixel - pix0 = pix1 = pix2 = pix3 = 0; - for (i = 0; i < xStep; ++i) { - pix0 += pixBuf[xx]; - pix1 += pixBuf[xx+1]; - pix2 += pixBuf[xx+2]; - pix3 += pixBuf[xx+3]; - xx += 4; - } - // pix / xStep * yStep - pix0 = (pix0 * d) >> 23; - pix1 = (pix1 * d) >> 23; - pix2 = (pix2 * d) >> 23; - pix3 = (pix3 * d) >> 23; - - // store the pixel - *destPtr++ = (Guchar)pix0; - *destPtr++ = (Guchar)pix1; - *destPtr++ = (Guchar)pix2; - *destPtr++ = (Guchar)pix3; - break; - case splashModeDeviceN8: - - // compute the final pixel - for (cp = 0; cp < SPOT_NCOMPS+4; cp++) - pix[cp] = 0; - for (i = 0; i < xStep; ++i) { - for (cp = 0; cp < SPOT_NCOMPS+4; cp++) { - pix[cp] += pixBuf[xx + cp]; - } - xx += (SPOT_NCOMPS+4); - } - // pix / xStep * yStep - for (cp = 0; cp < SPOT_NCOMPS+4; cp++) - pix[cp] = (pix[cp] * d) >> 23; - - // store the pixel - for (cp = 0; cp < SPOT_NCOMPS+4; cp++) - *destPtr++ = (Guchar)pix[cp]; - break; -#endif - - - case splashModeMono1: // mono1 is not allowed - default: - break; - } - - // process alpha - if (srcAlpha) { - alpha = 0; - for (i = 0; i < xStep; ++i, ++xxa) { - alpha += alphaPixBuf[xxa]; - } - // alpha / xStep * yStep - alpha = (alpha * d) >> 23; - *destAlphaPtr++ = (Guchar)alpha; - } - } - } - - gfree(alphaPixBuf); - gfree(alphaLineBuf); - gfree(pixBuf); - gfree(lineBuf); -} - -void Splash::scaleImageYdXu(SplashImageSource src, void *srcData, - SplashColorMode srcMode, int nComps, - GBool srcAlpha, int srcWidth, int srcHeight, - int scaledWidth, int scaledHeight, - SplashBitmap *dest) { - Guchar *lineBuf, *alphaLineBuf; - Guint *pixBuf, *alphaPixBuf; - Guint pix[splashMaxColorComps]; - Guint alpha; - Guchar *destPtr, *destAlphaPtr; - int yp, yq, xp, xq, yt, y, yStep, xt, x, xStep, d; - int i, j; - - // Bresenham parameters for y scale - yp = srcHeight / scaledHeight; - yq = srcHeight % scaledHeight; - - // Bresenham parameters for x scale - xp = scaledWidth / srcWidth; - xq = scaledWidth % srcWidth; - - // allocate buffers - lineBuf = (Guchar *)gmallocn(srcWidth, nComps); - pixBuf = (Guint *)gmallocn(srcWidth, nComps * sizeof(int)); - if (srcAlpha) { - alphaLineBuf = (Guchar *)gmalloc(srcWidth); - alphaPixBuf = (Guint *)gmallocn(srcWidth, sizeof(int)); - } else { - alphaLineBuf = NULL; - alphaPixBuf = NULL; - } - - // init y scale Bresenham - yt = 0; - - destPtr = dest->data; - destAlphaPtr = dest->alpha; - for (y = 0; y < scaledHeight; ++y) { - - // y scale Bresenham - if ((yt += yq) >= scaledHeight) { - yt -= scaledHeight; - yStep = yp + 1; - } else { - yStep = yp; - } - - // read rows from image - memset(pixBuf, 0, srcWidth * nComps * sizeof(int)); - if (srcAlpha) { - memset(alphaPixBuf, 0, srcWidth * sizeof(int)); - } - for (i = 0; i < yStep; ++i) { - (*src)(srcData, lineBuf, alphaLineBuf); - for (j = 0; j < srcWidth * nComps; ++j) { - pixBuf[j] += lineBuf[j]; - } - if (srcAlpha) { - for (j = 0; j < srcWidth; ++j) { - alphaPixBuf[j] += alphaLineBuf[j]; - } - } - } - - // init x scale Bresenham - xt = 0; - d = (1 << 23) / yStep; - - for (x = 0; x < srcWidth; ++x) { - - // x scale Bresenham - if ((xt += xq) >= srcWidth) { - xt -= srcWidth; - xStep = xp + 1; - } else { - xStep = xp; - } - - // compute the final pixel - for (i = 0; i < nComps; ++i) { - // pixBuf[] / yStep - pix[i] = (pixBuf[x * nComps + i] * d) >> 23; - } - - // store the pixel - switch (srcMode) { - case splashModeMono1: // mono1 is not allowed - break; - case splashModeMono8: - for (i = 0; i < xStep; ++i) { - *destPtr++ = (Guchar)pix[0]; - } - break; - case splashModeRGB8: - for (i = 0; i < xStep; ++i) { - *destPtr++ = (Guchar)pix[0]; - *destPtr++ = (Guchar)pix[1]; - *destPtr++ = (Guchar)pix[2]; - } - break; - case splashModeXBGR8: - for (i = 0; i < xStep; ++i) { - *destPtr++ = (Guchar)pix[2]; - *destPtr++ = (Guchar)pix[1]; - *destPtr++ = (Guchar)pix[0]; - *destPtr++ = (Guchar)255; - } - break; - case splashModeBGR8: - for (i = 0; i < xStep; ++i) { - *destPtr++ = (Guchar)pix[2]; - *destPtr++ = (Guchar)pix[1]; - *destPtr++ = (Guchar)pix[0]; - } - break; -#ifdef SPLASH_CMYK - case splashModeCMYK8: - for (i = 0; i < xStep; ++i) { - *destPtr++ = (Guchar)pix[0]; - *destPtr++ = (Guchar)pix[1]; - *destPtr++ = (Guchar)pix[2]; - *destPtr++ = (Guchar)pix[3]; - } - break; - case splashModeDeviceN8: - for (i = 0; i < xStep; ++i) { - for (int cp = 0; cp < SPOT_NCOMPS+4; cp++) - *destPtr++ = (Guchar)pix[cp]; - } - break; -#endif - } - - // process alpha - if (srcAlpha) { - // alphaPixBuf[] / yStep - alpha = (alphaPixBuf[x] * d) >> 23; - for (i = 0; i < xStep; ++i) { - *destAlphaPtr++ = (Guchar)alpha; - } - } - } - } - - gfree(alphaPixBuf); - gfree(alphaLineBuf); - gfree(pixBuf); - gfree(lineBuf); -} - -void Splash::scaleImageYuXd(SplashImageSource src, void *srcData, - SplashColorMode srcMode, int nComps, - GBool srcAlpha, int srcWidth, int srcHeight, - int scaledWidth, int scaledHeight, - SplashBitmap *dest) { - Guchar *lineBuf, *alphaLineBuf; - Guint pix[splashMaxColorComps]; - Guint alpha; - Guchar *destPtr0, *destPtr, *destAlphaPtr0, *destAlphaPtr; - int yp, yq, xp, xq, yt, y, yStep, xt, x, xStep, xx, xxa, d, d0, d1; - int i, j; - - // Bresenham parameters for y scale - yp = scaledHeight / srcHeight; - yq = scaledHeight % srcHeight; - - // Bresenham parameters for x scale - xp = srcWidth / scaledWidth; - xq = srcWidth % scaledWidth; - - // allocate buffers - lineBuf = (Guchar *)gmallocn_checkoverflow(srcWidth, nComps); - if (unlikely(!lineBuf)) - return; - if (srcAlpha) { - alphaLineBuf = (Guchar *)gmalloc(srcWidth); - } else { - alphaLineBuf = NULL; - } - - // init y scale Bresenham - yt = 0; - - destPtr0 = dest->data; - destAlphaPtr0 = dest->alpha; - for (y = 0; y < srcHeight; ++y) { - - // y scale Bresenham - if ((yt += yq) >= srcHeight) { - yt -= srcHeight; - yStep = yp + 1; - } else { - yStep = yp; - } - - // read row from image - (*src)(srcData, lineBuf, alphaLineBuf); - - // init x scale Bresenham - xt = 0; - d0 = (1 << 23) / xp; - d1 = (1 << 23) / (xp + 1); - - xx = xxa = 0; - for (x = 0; x < scaledWidth; ++x) { - - // x scale Bresenham - if ((xt += xq) >= scaledWidth) { - xt -= scaledWidth; - xStep = xp + 1; - d = d1; - } else { - xStep = xp; - d = d0; - } - - // compute the final pixel - for (i = 0; i < nComps; ++i) { - pix[i] = 0; - } - for (i = 0; i < xStep; ++i) { - for (j = 0; j < nComps; ++j, ++xx) { - pix[j] += lineBuf[xx]; - } - } - for (i = 0; i < nComps; ++i) { - // pix[] / xStep - pix[i] = (pix[i] * d) >> 23; - } - - // store the pixel - switch (srcMode) { - case splashModeMono1: // mono1 is not allowed - break; - case splashModeMono8: - for (i = 0; i < yStep; ++i) { - destPtr = destPtr0 + (i * scaledWidth + x) * nComps; - *destPtr++ = (Guchar)pix[0]; - } - break; - case splashModeRGB8: - for (i = 0; i < yStep; ++i) { - destPtr = destPtr0 + (i * scaledWidth + x) * nComps; - *destPtr++ = (Guchar)pix[0]; - *destPtr++ = (Guchar)pix[1]; - *destPtr++ = (Guchar)pix[2]; - } - break; - case splashModeXBGR8: - for (i = 0; i < yStep; ++i) { - destPtr = destPtr0 + (i * scaledWidth + x) * nComps; - *destPtr++ = (Guchar)pix[2]; - *destPtr++ = (Guchar)pix[1]; - *destPtr++ = (Guchar)pix[0]; - *destPtr++ = (Guchar)255; - } - break; - case splashModeBGR8: - for (i = 0; i < yStep; ++i) { - destPtr = destPtr0 + (i * scaledWidth + x) * nComps; - *destPtr++ = (Guchar)pix[2]; - *destPtr++ = (Guchar)pix[1]; - *destPtr++ = (Guchar)pix[0]; - } - break; -#ifdef SPLASH_CMYK - case splashModeCMYK8: - for (i = 0; i < yStep; ++i) { - destPtr = destPtr0 + (i * scaledWidth + x) * nComps; - *destPtr++ = (Guchar)pix[0]; - *destPtr++ = (Guchar)pix[1]; - *destPtr++ = (Guchar)pix[2]; - *destPtr++ = (Guchar)pix[3]; - } - break; - case splashModeDeviceN8: - for (i = 0; i < yStep; ++i) { - destPtr = destPtr0 + (i * scaledWidth + x) * nComps; - for (int cp = 0; cp < SPOT_NCOMPS+4; cp++) - *destPtr++ = (Guchar)pix[cp]; - } - break; -#endif - } - - // process alpha - if (srcAlpha) { - alpha = 0; - for (i = 0; i < xStep; ++i, ++xxa) { - alpha += alphaLineBuf[xxa]; - } - // alpha / xStep - alpha = (alpha * d) >> 23; - for (i = 0; i < yStep; ++i) { - destAlphaPtr = destAlphaPtr0 + i * scaledWidth + x; - *destAlphaPtr = (Guchar)alpha; - } - } - } - - destPtr0 += yStep * scaledWidth * nComps; - if (srcAlpha) { - destAlphaPtr0 += yStep * scaledWidth; - } - } - - gfree(alphaLineBuf); - gfree(lineBuf); -} - -void Splash::scaleImageYuXu(SplashImageSource src, void *srcData, - SplashColorMode srcMode, int nComps, - GBool srcAlpha, int srcWidth, int srcHeight, - int scaledWidth, int scaledHeight, - SplashBitmap *dest) { - Guchar *lineBuf, *alphaLineBuf; - Guint pix[splashMaxColorComps]; - Guint alpha; - Guchar *destPtr0, *destPtr, *destAlphaPtr0, *destAlphaPtr; - int yp, yq, xp, xq, yt, y, yStep, xt, x, xStep, xx; - int i, j; - - // Bresenham parameters for y scale - yp = scaledHeight / srcHeight; - yq = scaledHeight % srcHeight; - - // Bresenham parameters for x scale - xp = scaledWidth / srcWidth; - xq = scaledWidth % srcWidth; - - // allocate buffers - lineBuf = (Guchar *)gmallocn(srcWidth, nComps); - if (srcAlpha) { - alphaLineBuf = (Guchar *)gmalloc(srcWidth); - } else { - alphaLineBuf = NULL; - } - - // init y scale Bresenham - yt = 0; - - destPtr0 = dest->data; - destAlphaPtr0 = dest->alpha; - for (y = 0; y < srcHeight; ++y) { - - // y scale Bresenham - if ((yt += yq) >= srcHeight) { - yt -= srcHeight; - yStep = yp + 1; - } else { - yStep = yp; - } - - // read row from image - (*src)(srcData, lineBuf, alphaLineBuf); - - // init x scale Bresenham - xt = 0; - - xx = 0; - for (x = 0; x < srcWidth; ++x) { - - // x scale Bresenham - if ((xt += xq) >= srcWidth) { - xt -= srcWidth; - xStep = xp + 1; - } else { - xStep = xp; - } - - // compute the final pixel - for (i = 0; i < nComps; ++i) { - pix[i] = lineBuf[x * nComps + i]; - } - - // store the pixel - switch (srcMode) { - case splashModeMono1: // mono1 is not allowed - break; - case splashModeMono8: - for (i = 0; i < yStep; ++i) { - for (j = 0; j < xStep; ++j) { - destPtr = destPtr0 + (i * scaledWidth + xx + j) * nComps; - *destPtr++ = (Guchar)pix[0]; - } - } - break; - case splashModeRGB8: - for (i = 0; i < yStep; ++i) { - for (j = 0; j < xStep; ++j) { - destPtr = destPtr0 + (i * scaledWidth + xx + j) * nComps; - *destPtr++ = (Guchar)pix[0]; - *destPtr++ = (Guchar)pix[1]; - *destPtr++ = (Guchar)pix[2]; - } - } - break; - case splashModeXBGR8: - for (i = 0; i < yStep; ++i) { - for (j = 0; j < xStep; ++j) { - destPtr = destPtr0 + (i * scaledWidth + xx + j) * nComps; - *destPtr++ = (Guchar)pix[2]; - *destPtr++ = (Guchar)pix[1]; - *destPtr++ = (Guchar)pix[0]; - *destPtr++ = (Guchar)255; - } - } - break; - case splashModeBGR8: - for (i = 0; i < yStep; ++i) { - for (j = 0; j < xStep; ++j) { - destPtr = destPtr0 + (i * scaledWidth + xx + j) * nComps; - *destPtr++ = (Guchar)pix[2]; - *destPtr++ = (Guchar)pix[1]; - *destPtr++ = (Guchar)pix[0]; - } - } - break; -#ifdef SPLASH_CMYK - case splashModeCMYK8: - for (i = 0; i < yStep; ++i) { - for (j = 0; j < xStep; ++j) { - destPtr = destPtr0 + (i * scaledWidth + xx + j) * nComps; - *destPtr++ = (Guchar)pix[0]; - *destPtr++ = (Guchar)pix[1]; - *destPtr++ = (Guchar)pix[2]; - *destPtr++ = (Guchar)pix[3]; - } - } - break; - case splashModeDeviceN8: - for (i = 0; i < yStep; ++i) { - for (j = 0; j < xStep; ++j) { - destPtr = destPtr0 + (i * scaledWidth + xx + j) * nComps; - for (int cp = 0; cp < SPOT_NCOMPS+4; cp++) - *destPtr++ = (Guchar)pix[cp]; - } - } - break; -#endif - } - - // process alpha - if (srcAlpha) { - alpha = alphaLineBuf[x]; - for (i = 0; i < yStep; ++i) { - for (j = 0; j < xStep; ++j) { - destAlphaPtr = destAlphaPtr0 + i * scaledWidth + xx + j; - *destAlphaPtr = (Guchar)alpha; - } - } - } - - xx += xStep; - } - - destPtr0 += yStep * scaledWidth * nComps; - if (srcAlpha) { - destAlphaPtr0 += yStep * scaledWidth; - } - } - - gfree(alphaLineBuf); - gfree(lineBuf); -} - -// expand source row to scaledWidth using linear interpolation -static void expandRow(Guchar *srcBuf, Guchar *dstBuf, int srcWidth, int scaledWidth, int nComps) -{ - double xStep = (double)srcWidth/scaledWidth; - double xSrc = 0.0; - double xFrac, xInt; - int p; - - // pad the source with an extra pixel equal to the last pixel - // so that when xStep is inside the last pixel we still have two - // pixels to interpolate between. - for (int i = 0; i < nComps; i++) - srcBuf[srcWidth*nComps + i] = srcBuf[(srcWidth-1)*nComps + i]; - - for (int x = 0; x < scaledWidth; x++) { - xFrac = modf(xSrc, &xInt); - p = (int)xInt; - for (int c = 0; c < nComps; c++) { - dstBuf[nComps*x + c] = srcBuf[nComps*p + c]*(1.0 - xFrac) + srcBuf[nComps*(p+1) + c]*xFrac; - } - xSrc += xStep; - } -} - -// Scale up image using bilinear interpolation -void Splash::scaleImageYuXuBilinear(SplashImageSource src, void *srcData, - SplashColorMode srcMode, int nComps, - GBool srcAlpha, int srcWidth, int srcHeight, - int scaledWidth, int scaledHeight, - SplashBitmap *dest) { - Guchar *srcBuf, *lineBuf1, *lineBuf2, *alphaSrcBuf, *alphaLineBuf1, *alphaLineBuf2; - Guint pix[splashMaxColorComps]; - Guchar *destPtr0, *destPtr, *destAlphaPtr0, *destAlphaPtr; - int i; - - if (srcWidth < 1 || srcHeight < 1) - return; - - // allocate buffers - srcBuf = (Guchar *)gmallocn(srcWidth+1, nComps); // + 1 pixel of padding - lineBuf1 = (Guchar *)gmallocn(scaledWidth, nComps); - lineBuf2 = (Guchar *)gmallocn(scaledWidth, nComps); - if (srcAlpha) { - alphaSrcBuf = (Guchar *)gmalloc(srcWidth+1); // + 1 pixel of padding - alphaLineBuf1 = (Guchar *)gmalloc(scaledWidth); - alphaLineBuf2 = (Guchar *)gmalloc(scaledWidth); - } else { - alphaSrcBuf = NULL; - alphaLineBuf1 = NULL; - alphaLineBuf2 = NULL; - } - - double ySrc = 0.0; - double yStep = (double)srcHeight/scaledHeight; - double yFrac, yInt; - int currentSrcRow = -1; - (*src)(srcData, srcBuf, alphaSrcBuf); - expandRow(srcBuf, lineBuf2, srcWidth, scaledWidth, nComps); - if (srcAlpha) - expandRow(alphaSrcBuf, alphaLineBuf2, srcWidth, scaledWidth, 1); - - destPtr0 = dest->data; - destAlphaPtr0 = dest->alpha; - for (int y = 0; y < scaledHeight; y++) { - yFrac = modf(ySrc, &yInt); - if ((int)yInt > currentSrcRow) { - currentSrcRow++; - // Copy line2 data to line1 and get next line2 data. - // If line2 already contains the last source row we don't touch it. - // This effectively adds an extra row of padding for interpolating the - // last source row with. - memcpy(lineBuf1, lineBuf2, scaledWidth * nComps); - if (srcAlpha) - memcpy(alphaLineBuf1, alphaLineBuf2, scaledWidth); - if (currentSrcRow < srcHeight) { - (*src)(srcData, srcBuf, alphaSrcBuf); - expandRow(srcBuf, lineBuf2, srcWidth, scaledWidth, nComps); - if (srcAlpha) - expandRow(alphaSrcBuf, alphaLineBuf2, srcWidth, scaledWidth, 1); - } - } - - // write row y using linear interpolation on lineBuf1 and lineBuf2 - for (int x = 0; x < scaledWidth; ++x) { - // compute the final pixel - for (i = 0; i < nComps; ++i) { - pix[i] = lineBuf1[x*nComps + i]*(1.0 - yFrac) + lineBuf2[x*nComps + i]*yFrac; - } - - // store the pixel - destPtr = destPtr0 + (y * scaledWidth + x) * nComps; - switch (srcMode) { - case splashModeMono1: // mono1 is not allowed - break; - case splashModeMono8: - *destPtr++ = (Guchar)pix[0]; - break; - case splashModeRGB8: - *destPtr++ = (Guchar)pix[0]; - *destPtr++ = (Guchar)pix[1]; - *destPtr++ = (Guchar)pix[2]; - break; - case splashModeXBGR8: - *destPtr++ = (Guchar)pix[2]; - *destPtr++ = (Guchar)pix[1]; - *destPtr++ = (Guchar)pix[0]; - *destPtr++ = (Guchar)255; - break; - case splashModeBGR8: - *destPtr++ = (Guchar)pix[2]; - *destPtr++ = (Guchar)pix[1]; - *destPtr++ = (Guchar)pix[0]; - break; -#ifdef SPLASH_CMYK - case splashModeCMYK8: - *destPtr++ = (Guchar)pix[0]; - *destPtr++ = (Guchar)pix[1]; - *destPtr++ = (Guchar)pix[2]; - *destPtr++ = (Guchar)pix[3]; - break; - case splashModeDeviceN8: - for (int cp = 0; cp < SPOT_NCOMPS+4; cp++) - *destPtr++ = (Guchar)pix[cp]; - break; -#endif - } - - // process alpha - if (srcAlpha) { - destAlphaPtr = destAlphaPtr0 + y*scaledWidth + x; - *destAlphaPtr = alphaLineBuf1[x]*(1.0 - yFrac) + alphaLineBuf2[x]*yFrac; - } - } - - ySrc += yStep; - } - - gfree(alphaSrcBuf); - gfree(alphaLineBuf1); - gfree(alphaLineBuf2); - gfree(srcBuf); - gfree(lineBuf1); - gfree(lineBuf2); -} - -void Splash::vertFlipImage(SplashBitmap *img, int width, int height, - int nComps) { - Guchar *lineBuf; - Guchar *p0, *p1; - int w; - - if (unlikely(img->data == NULL)) { - error(errInternal, -1, "img->data is NULL in Splash::vertFlipImage"); - return; - } - - w = width * nComps; - lineBuf = (Guchar *)gmalloc(w); - for (p0 = img->data, p1 = img->data + (height - 1) * w; - p0 < p1; - p0 += w, p1 -= w) { - memcpy(lineBuf, p0, w); - memcpy(p0, p1, w); - memcpy(p1, lineBuf, w); - } - if (img->alpha) { - for (p0 = img->alpha, p1 = img->alpha + (height - 1) * width; - p0 < p1; - p0 += width, p1 -= width) { - memcpy(lineBuf, p0, width); - memcpy(p0, p1, width); - memcpy(p1, lineBuf, width); - } - } - gfree(lineBuf); -} - -void Splash::blitImage(SplashBitmap *src, GBool srcAlpha, int xDest, int yDest) { - SplashClipResult clipRes = state->clip->testRect(xDest, yDest, xDest + src->getWidth() - 1, yDest + src->getHeight() - 1); - if (clipRes != splashClipAllOutside) { - blitImage(src, srcAlpha, xDest, yDest, clipRes); - } -} - -void Splash::blitImage(SplashBitmap *src, GBool srcAlpha, int xDest, int yDest, - SplashClipResult clipRes) { - SplashPipe pipe; - SplashColor pixel; - Guchar *ap; - int w, h, x0, y0, x1, y1, x, y; - - // split the image into clipped and unclipped regions - w = src->getWidth(); - h = src->getHeight(); - if (clipRes == splashClipAllInside) { - x0 = 0; - y0 = 0; - x1 = w; - y1 = h; - } else { - if (state->clip->getNumPaths()) { - x0 = x1 = w; - y0 = y1 = h; - } else { - if ((x0 = splashCeil(state->clip->getXMin()) - xDest) < 0) { - x0 = 0; - } - if ((y0 = splashCeil(state->clip->getYMin()) - yDest) < 0) { - y0 = 0; - } - if ((x1 = splashFloor(state->clip->getXMax()) - xDest) > w) { - x1 = w; - } - if (x1 < x0) { - x1 = x0; - } - if ((y1 = splashFloor(state->clip->getYMax()) - yDest) > h) { - y1 = h; - } - if (y1 < y0) { - y1 = y0; - } - } - } - - // draw the unclipped region - if (x0 < w && y0 < h && x0 < x1 && y0 < y1) { - pipeInit(&pipe, xDest + x0, yDest + y0, NULL, pixel, - (Guchar)splashRound(state->fillAlpha * 255), srcAlpha, gFalse); - if (srcAlpha) { - for (y = y0; y < y1; ++y) { - pipeSetXY(&pipe, xDest + x0, yDest + y); - ap = src->getAlphaPtr() + y * w + x0; - for (x = x0; x < x1; ++x) { - src->getPixel(x, y, pixel); - pipe.shape = *ap++; - (this->*pipe.run)(&pipe); - } - } - } else { - for (y = y0; y < y1; ++y) { - pipeSetXY(&pipe, xDest + x0, yDest + y); - for (x = x0; x < x1; ++x) { - src->getPixel(x, y, pixel); - (this->*pipe.run)(&pipe); - } - } - } - updateModX(xDest + x0); - updateModX(xDest + x1 - 1); - updateModY(yDest + y0); - updateModY(yDest + y1 - 1); - } - - // draw the clipped regions - if (y0 > 0) { - blitImageClipped(src, srcAlpha, 0, 0, xDest, yDest, w, y0); - } - if (y1 < h) { - blitImageClipped(src, srcAlpha, 0, y1, xDest, yDest + y1, w, h - y1); - } - if (x0 > 0 && y0 < y1) { - blitImageClipped(src, srcAlpha, 0, y0, xDest, yDest + y0, x0, y1 - y0); - } - if (x1 < w && y0 < y1) { - blitImageClipped(src, srcAlpha, x1, y0, xDest + x1, yDest + y0, - w - x1, y1 - y0); - } -} - -void Splash::blitImageClipped(SplashBitmap *src, GBool srcAlpha, - int xSrc, int ySrc, int xDest, int yDest, - int w, int h) { - SplashPipe pipe; - SplashColor pixel; - Guchar *ap; - int x, y; - - if (vectorAntialias) { - pipeInit(&pipe, xDest, yDest, NULL, pixel, - (Guchar)splashRound(state->fillAlpha * 255), gTrue, gFalse); - drawAAPixelInit(); - if (srcAlpha) { - for (y = 0; y < h; ++y) { - ap = src->getAlphaPtr() + (ySrc + y) * src->getWidth() + xSrc; - for (x = 0; x < w; ++x) { - src->getPixel(xSrc + x, ySrc + y, pixel); - pipe.shape = *ap++; - drawAAPixel(&pipe, xDest + x, yDest + y); - } - } - } else { - for (y = 0; y < h; ++y) { - for (x = 0; x < w; ++x) { - src->getPixel(xSrc + x, ySrc + y, pixel); - pipe.shape = 255; - drawAAPixel(&pipe, xDest + x, yDest + y); - } - } - } - } else { - pipeInit(&pipe, xDest, yDest, NULL, pixel, - (Guchar)splashRound(state->fillAlpha * 255), srcAlpha, gFalse); - if (srcAlpha) { - for (y = 0; y < h; ++y) { - ap = src->getAlphaPtr() + (ySrc + y) * src->getWidth() + xSrc; - pipeSetXY(&pipe, xDest, yDest + y); - for (x = 0; x < w; ++x) { - if (state->clip->test(xDest + x, yDest + y)) { - src->getPixel(xSrc + x, ySrc + y, pixel); - pipe.shape = *ap++; - (this->*pipe.run)(&pipe); - updateModX(xDest + x); - updateModY(yDest + y); - } else { - pipeIncX(&pipe); - ++ap; - } - } - } - } else { - for (y = 0; y < h; ++y) { - pipeSetXY(&pipe, xDest, yDest + y); - for (x = 0; x < w; ++x) { - if (state->clip->test(xDest + x, yDest + y)) { - src->getPixel(xSrc + x, ySrc + y, pixel); - (this->*pipe.run)(&pipe); - updateModX(xDest + x); - updateModY(yDest + y); - } else { - pipeIncX(&pipe); - } - } - } - } - } -} - -SplashError Splash::composite(SplashBitmap *src, int xSrc, int ySrc, - int xDest, int yDest, int w, int h, - GBool noClip, GBool nonIsolated, - GBool knockout, SplashCoord knockoutOpacity) { - SplashPipe pipe; - SplashColor pixel; - Guchar alpha; - Guchar *ap; - int x, y; - - if (src->mode != bitmap->mode) { - return splashErrModeMismatch; - } - - if (unlikely(!bitmap->data)) { - return splashErrZeroImage; - } - - if(src->getSeparationList()->getLength() > bitmap->getSeparationList()->getLength()) { - for (x = bitmap->getSeparationList()->getLength(); x < src->getSeparationList()->getLength(); x++) - bitmap->getSeparationList()->append(((GfxSeparationColorSpace *)src->getSeparationList()->get(x))->copy()); - } - if (src->alpha) { - pipeInit(&pipe, xDest, yDest, NULL, pixel, - (Guchar)splashRound(state->fillAlpha * 255), gTrue, nonIsolated, - knockout, (Guchar)splashRound(knockoutOpacity * 255)); - if (noClip) { - for (y = 0; y < h; ++y) { - pipeSetXY(&pipe, xDest, yDest + y); - ap = src->getAlphaPtr() + (ySrc + y) * src->getWidth() + xSrc; - for (x = 0; x < w; ++x) { - src->getPixel(xSrc + x, ySrc + y, pixel); - alpha = *ap++; - // this uses shape instead of alpha, which isn't technically - // correct, but works out the same - pipe.shape = alpha; - (this->*pipe.run)(&pipe); - } - } - updateModX(xDest); - updateModX(xDest + w - 1); - updateModY(yDest); - updateModY(yDest + h - 1); - } else { - for (y = 0; y < h; ++y) { - pipeSetXY(&pipe, xDest, yDest + y); - ap = src->getAlphaPtr() + (ySrc + y) * src->getWidth() + xSrc; - for (x = 0; x < w; ++x) { - src->getPixel(xSrc + x, ySrc + y, pixel); - alpha = *ap++; - if (state->clip->test(xDest + x, yDest + y)) { - // this uses shape instead of alpha, which isn't technically - // correct, but works out the same - pipe.shape = alpha; - (this->*pipe.run)(&pipe); - updateModX(xDest + x); - updateModY(yDest + y); - } else { - pipeIncX(&pipe); - } - } - } - } - } else { - pipeInit(&pipe, xDest, yDest, NULL, pixel, - (Guchar)splashRound(state->fillAlpha * 255), gFalse, nonIsolated); - if (noClip) { - for (y = 0; y < h; ++y) { - pipeSetXY(&pipe, xDest, yDest + y); - for (x = 0; x < w; ++x) { - src->getPixel(xSrc + x, ySrc + y, pixel); - (this->*pipe.run)(&pipe); - } - } - updateModX(xDest); - updateModX(xDest + w - 1); - updateModY(yDest); - updateModY(yDest + h - 1); - } else { - for (y = 0; y < h; ++y) { - pipeSetXY(&pipe, xDest, yDest + y); - for (x = 0; x < w; ++x) { - src->getPixel(xSrc + x, ySrc + y, pixel); - if (state->clip->test(xDest + x, yDest + y)) { - (this->*pipe.run)(&pipe); - updateModX(xDest + x); - updateModY(yDest + y); - } else { - pipeIncX(&pipe); - } - } - } - } - } - - return splashOk; -} - -void Splash::compositeBackground(SplashColorPtr color) { - SplashColorPtr p; - Guchar *q; - Guchar alpha, alpha1, c, color0, color1, color2; -#ifdef SPLASH_CMYK - Guchar color3; - Guchar colorsp[SPOT_NCOMPS+4], cp; -#endif - int x, y, mask; - - if (unlikely(bitmap->alpha == NULL)) { - error(errInternal, -1, "bitmap->alpha is NULL in Splash::compositeBackground"); - return; - } - - switch (bitmap->mode) { - case splashModeMono1: - color0 = color[0]; - for (y = 0; y < bitmap->height; ++y) { - p = &bitmap->data[y * bitmap->rowSize]; - q = &bitmap->alpha[y * bitmap->width]; - mask = 0x80; - for (x = 0; x < bitmap->width; ++x) { - alpha = *q++; - alpha1 = 255 - alpha; - c = (*p & mask) ? 0xff : 0x00; - c = div255(alpha1 * color0 + alpha * c); - if (c & 0x80) { - *p |= mask; - } else { - *p &= ~mask; - } - if (!(mask >>= 1)) { - mask = 0x80; - ++p; - } - } - } - break; - case splashModeMono8: - color0 = color[0]; - for (y = 0; y < bitmap->height; ++y) { - p = &bitmap->data[y * bitmap->rowSize]; - q = &bitmap->alpha[y * bitmap->width]; - for (x = 0; x < bitmap->width; ++x) { - alpha = *q++; - alpha1 = 255 - alpha; - p[0] = div255(alpha1 * color0 + alpha * p[0]); - ++p; - } - } - break; - case splashModeRGB8: - case splashModeBGR8: - color0 = color[0]; - color1 = color[1]; - color2 = color[2]; - for (y = 0; y < bitmap->height; ++y) { - p = &bitmap->data[y * bitmap->rowSize]; - q = &bitmap->alpha[y * bitmap->width]; - for (x = 0; x < bitmap->width; ++x) { - alpha = *q++; - if (alpha == 0) - { - p[0] = color0; - p[1] = color1; - p[2] = color2; - } - else if (alpha != 255) - { - alpha1 = 255 - alpha; - p[0] = div255(alpha1 * color0 + alpha * p[0]); - p[1] = div255(alpha1 * color1 + alpha * p[1]); - p[2] = div255(alpha1 * color2 + alpha * p[2]); - } - p += 3; - } - } - break; - case splashModeXBGR8: - color0 = color[0]; - color1 = color[1]; - color2 = color[2]; - for (y = 0; y < bitmap->height; ++y) { - p = &bitmap->data[y * bitmap->rowSize]; - q = &bitmap->alpha[y * bitmap->width]; - for (x = 0; x < bitmap->width; ++x) { - alpha = *q++; - if (alpha == 0) - { - p[0] = color0; - p[1] = color1; - p[2] = color2; - } - else if (alpha != 255) - { - alpha1 = 255 - alpha; - p[0] = div255(alpha1 * color0 + alpha * p[0]); - p[1] = div255(alpha1 * color1 + alpha * p[1]); - p[2] = div255(alpha1 * color2 + alpha * p[2]); - } - p[3] = 255; - p += 4; - } - } - break; -#ifdef SPLASH_CMYK - case splashModeCMYK8: - color0 = color[0]; - color1 = color[1]; - color2 = color[2]; - color3 = color[3]; - for (y = 0; y < bitmap->height; ++y) { - p = &bitmap->data[y * bitmap->rowSize]; - q = &bitmap->alpha[y * bitmap->width]; - for (x = 0; x < bitmap->width; ++x) { - alpha = *q++; - if (alpha == 0) - { - p[0] = color0; - p[1] = color1; - p[2] = color2; - p[3] = color3; - } - else if (alpha != 255) - { - alpha1 = 255 - alpha; - p[0] = div255(alpha1 * color0 + alpha * p[0]); - p[1] = div255(alpha1 * color1 + alpha * p[1]); - p[2] = div255(alpha1 * color2 + alpha * p[2]); - p[3] = div255(alpha1 * color3 + alpha * p[3]); - } - p += 4; - } - } - break; - case splashModeDeviceN8: - for (cp = 0; cp < SPOT_NCOMPS+4; cp++) - colorsp[cp] = color[cp]; - for (y = 0; y < bitmap->height; ++y) { - p = &bitmap->data[y * bitmap->rowSize]; - q = &bitmap->alpha[y * bitmap->width]; - for (x = 0; x < bitmap->width; ++x) { - alpha = *q++; - if (alpha == 0) - { - for (cp = 0; cp < SPOT_NCOMPS+4; cp++) - p[cp] = colorsp[cp]; - } - else if (alpha != 255) - { - alpha1 = 255 - alpha; - for (cp = 0; cp < SPOT_NCOMPS+4; cp++) - p[cp] = div255(alpha1 * colorsp[cp] + alpha * p[cp]); - } - p += (SPOT_NCOMPS+4); - } - } - break; -#endif - } - 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; - - int bitmapWidth = bitmap->getWidth(); - SplashClip* clip = getClip(); - SplashBitmap *blitTarget = bitmap; - SplashColorPtr bitmapData = bitmap->getDataPtr(); - int bitmapOffLimit = bitmap->getHeight() * bitmap->getRowSize(); - 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; -#ifdef SPLASH_CMYK - case splashModeCMYK8: - colorComps=4; - break; - case splashModeDeviceN8: - colorComps=SPOT_NCOMPS+4; - break; -#endif - } - - SplashPipe pipe; - SplashColor cSrcVal; - - pipeInit(&pipe, 0, 0, NULL, cSrcVal, (Guchar)splashRound(state->strokeAlpha * 255), 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] * (double)userToCanvasMatrix[0] + ydbl[m] * (double)userToCanvasMatrix[2] + (double)userToCanvasMatrix[4]; - yt = xdbl[m] * (double)userToCanvasMatrix[1] + ydbl[m] * (double)userToCanvasMatrix[3] + (double)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]; - - 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; - if (likely(bitmapOff >= 0)) { - for (int X = scanLimitL; X <= scanLimitR && bitmapOff + colorComps <= bitmapOffLimit; ++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 { - if (!bDirectBlit) { - delete blitTarget; - } - 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) { - SplashColorPtr p, sp; - Guchar *q; - int x, y, mask, srcMask; - - if (src->mode != bitmap->mode) { - return splashErrModeMismatch; - } - - if (unlikely(!bitmap->data)) { - return splashErrZeroImage; - } - - switch (bitmap->mode) { - case splashModeMono1: - for (y = 0; y < h; ++y) { - p = &bitmap->data[(yDest + y) * bitmap->rowSize + (xDest >> 3)]; - mask = 0x80 >> (xDest & 7); - sp = &src->data[(ySrc + y) * src->rowSize + (xSrc >> 3)]; - srcMask = 0x80 >> (xSrc & 7); - for (x = 0; x < w; ++x) { - if (*sp & srcMask) { - *p |= mask; - } else { - *p &= ~mask; - } - if (!(mask >>= 1)) { - mask = 0x80; - ++p; - } - if (!(srcMask >>= 1)) { - srcMask = 0x80; - ++sp; - } - } - } - break; - case splashModeMono8: - for (y = 0; y < h; ++y) { - p = &bitmap->data[(yDest + y) * bitmap->rowSize + xDest]; - sp = &src->data[(ySrc + y) * bitmap->rowSize + xSrc]; - for (x = 0; x < w; ++x) { - *p++ = *sp++; - } - } - break; - case splashModeRGB8: - case splashModeBGR8: - for (y = 0; y < h; ++y) { - p = &bitmap->data[(yDest + y) * bitmap->rowSize + 3 * xDest]; - sp = &src->data[(ySrc + y) * src->rowSize + 3 * xSrc]; - for (x = 0; x < w; ++x) { - *p++ = *sp++; - *p++ = *sp++; - *p++ = *sp++; - } - } - break; - case splashModeXBGR8: - for (y = 0; y < h; ++y) { - p = &bitmap->data[(yDest + y) * bitmap->rowSize + 4 * xDest]; - sp = &src->data[(ySrc + y) * src->rowSize + 4 * xSrc]; - for (x = 0; x < w; ++x) { - *p++ = *sp++; - *p++ = *sp++; - *p++ = *sp++; - *p++ = 255; - sp++; - } - } - break; -#ifdef SPLASH_CMYK - case splashModeCMYK8: - for (y = 0; y < h; ++y) { - p = &bitmap->data[(yDest + y) * bitmap->rowSize + 4 * xDest]; - sp = &src->data[(ySrc + y) * src->rowSize + 4 * xSrc]; - for (x = 0; x < w; ++x) { - *p++ = *sp++; - *p++ = *sp++; - *p++ = *sp++; - *p++ = *sp++; - } - } - break; - case splashModeDeviceN8: - for (y = 0; y < h; ++y) { - p = &bitmap->data[(yDest + y) * bitmap->rowSize + (SPOT_NCOMPS+4) * xDest]; - sp = &src->data[(ySrc + y) * src->rowSize + (SPOT_NCOMPS+4) * xSrc]; - for (x = 0; x < w; ++x) { - for (int cp=0; cp < SPOT_NCOMPS+4; cp++) - *p++ = *sp++; - } - } - break; -#endif - } - - if (bitmap->alpha) { - for (y = 0; y < h; ++y) { - q = &bitmap->alpha[(yDest + y) * bitmap->width + xDest]; - memset(q, 0x00, w); - } - } - - return splashOk; -} - -SplashPath *Splash::makeStrokePath(SplashPath *path, SplashCoord w, - GBool flatten) { -SplashPath *pathIn, *dashPath, *pathOut; - SplashCoord d, dx, dy, wdx, wdy, dxNext, dyNext, wdxNext, wdyNext; - SplashCoord crossprod, dotprod, miter, m; - GBool first, last, closed, hasangle; - int subpathStart0, subpathStart1, seg, i0, i1, j0, j1, k0, k1; - int left0, left1, left2, right0, right1, right2, join0, join1, join2; - int leftFirst, rightFirst, firstPt; - - pathOut = new SplashPath(); - - if (path->length == 0) { - return pathOut; - } - - if (flatten) { - pathIn = flattenPath(path, state->matrix, state->flatness); - if (state->lineDashLength > 0) { - dashPath = makeDashedPath(pathIn); - delete pathIn; - pathIn = dashPath; - if (pathIn->length == 0) { - delete pathIn; - return pathOut; - } - } - } else { - pathIn = path; - } - - subpathStart0 = subpathStart1 = 0; // make gcc happy - seg = 0; // make gcc happy - closed = gFalse; // make gcc happy - left0 = left1 = right0 = right1 = join0 = join1 = 0; // make gcc happy - leftFirst = rightFirst = firstPt = 0; // make gcc happy - - i0 = 0; - for (i1 = i0; - !(pathIn->flags[i1] & splashPathLast) && - i1 + 1 < pathIn->length && - pathIn->pts[i1+1].x == pathIn->pts[i1].x && - pathIn->pts[i1+1].y == pathIn->pts[i1].y; - ++i1) ; - - while (i1 < pathIn->length) { - if ((first = pathIn->flags[i0] & splashPathFirst)) { - subpathStart0 = i0; - subpathStart1 = i1; - seg = 0; - closed = pathIn->flags[i0] & splashPathClosed; - } - j0 = i1 + 1; - if (j0 < pathIn->length) { - for (j1 = j0; - !(pathIn->flags[j1] & splashPathLast) && - j1 + 1 < pathIn->length && - pathIn->pts[j1+1].x == pathIn->pts[j1].x && - pathIn->pts[j1+1].y == pathIn->pts[j1].y; - ++j1) ; - } else { - j1 = j0; - } - if (pathIn->flags[i1] & splashPathLast) { - if (first && state->lineCap == splashLineCapRound) { - // special case: zero-length subpath with round line caps --> - // draw a circle - pathOut->moveTo(pathIn->pts[i0].x + (SplashCoord)0.5 * w, - pathIn->pts[i0].y); - pathOut->curveTo(pathIn->pts[i0].x + (SplashCoord)0.5 * w, - pathIn->pts[i0].y + bezierCircle2 * w, - pathIn->pts[i0].x + bezierCircle2 * w, - pathIn->pts[i0].y + (SplashCoord)0.5 * w, - pathIn->pts[i0].x, - pathIn->pts[i0].y + (SplashCoord)0.5 * w); - pathOut->curveTo(pathIn->pts[i0].x - bezierCircle2 * w, - pathIn->pts[i0].y + (SplashCoord)0.5 * w, - pathIn->pts[i0].x - (SplashCoord)0.5 * w, - pathIn->pts[i0].y + bezierCircle2 * w, - pathIn->pts[i0].x - (SplashCoord)0.5 * w, - pathIn->pts[i0].y); - pathOut->curveTo(pathIn->pts[i0].x - (SplashCoord)0.5 * w, - pathIn->pts[i0].y - bezierCircle2 * w, - pathIn->pts[i0].x - bezierCircle2 * w, - pathIn->pts[i0].y - (SplashCoord)0.5 * w, - pathIn->pts[i0].x, - pathIn->pts[i0].y - (SplashCoord)0.5 * w); - pathOut->curveTo(pathIn->pts[i0].x + bezierCircle2 * w, - pathIn->pts[i0].y - (SplashCoord)0.5 * w, - pathIn->pts[i0].x + (SplashCoord)0.5 * w, - pathIn->pts[i0].y - bezierCircle2 * w, - pathIn->pts[i0].x + (SplashCoord)0.5 * w, - pathIn->pts[i0].y); - pathOut->close(); - } - i0 = j0; - i1 = j1; - continue; - } - last = pathIn->flags[j1] & splashPathLast; - if (last) { - k0 = subpathStart1 + 1; - } else { - k0 = j1 + 1; - } - for (k1 = k0; - !(pathIn->flags[k1] & splashPathLast) && - k1 + 1 < pathIn->length && - pathIn->pts[k1+1].x == pathIn->pts[k1].x && - pathIn->pts[k1+1].y == pathIn->pts[k1].y; - ++k1) ; - - // compute the deltas for segment (i1, j0) -#ifdef USE_FIXEDPOINT - // the 1/d value can be small, which introduces significant - // inaccuracies in fixed point mode - d = splashDist(pathIn->pts[i1].x, pathIn->pts[i1].y, - pathIn->pts[j0].x, pathIn->pts[j0].y); - dx = (pathIn->pts[j0].x - pathIn->pts[i1].x) / d; - dy = (pathIn->pts[j0].y - pathIn->pts[i1].y) / d; -#else - d = (SplashCoord)1 / splashDist(pathIn->pts[i1].x, pathIn->pts[i1].y, - pathIn->pts[j0].x, pathIn->pts[j0].y); - dx = d * (pathIn->pts[j0].x - pathIn->pts[i1].x); - dy = d * (pathIn->pts[j0].y - pathIn->pts[i1].y); -#endif - wdx = (SplashCoord)0.5 * w * dx; - wdy = (SplashCoord)0.5 * w * dy; - - // draw the start cap - pathOut->moveTo(pathIn->pts[i0].x - wdy, pathIn->pts[i0].y + wdx); - if (i0 == subpathStart0) { - firstPt = pathOut->length - 1; - } - if (first && !closed) { - switch (state->lineCap) { - case splashLineCapButt: - pathOut->lineTo(pathIn->pts[i0].x + wdy, pathIn->pts[i0].y - wdx); - break; - case splashLineCapRound: - pathOut->curveTo(pathIn->pts[i0].x - wdy - bezierCircle * wdx, - pathIn->pts[i0].y + wdx - bezierCircle * wdy, - pathIn->pts[i0].x - wdx - bezierCircle * wdy, - pathIn->pts[i0].y - wdy + bezierCircle * wdx, - pathIn->pts[i0].x - wdx, - pathIn->pts[i0].y - wdy); - pathOut->curveTo(pathIn->pts[i0].x - wdx + bezierCircle * wdy, - pathIn->pts[i0].y - wdy - bezierCircle * wdx, - pathIn->pts[i0].x + wdy - bezierCircle * wdx, - pathIn->pts[i0].y - wdx - bezierCircle * wdy, - pathIn->pts[i0].x + wdy, - pathIn->pts[i0].y - wdx); - break; - case splashLineCapProjecting: - pathOut->lineTo(pathIn->pts[i0].x - wdx - wdy, - pathIn->pts[i0].y + wdx - wdy); - pathOut->lineTo(pathIn->pts[i0].x - wdx + wdy, - pathIn->pts[i0].y - wdx - wdy); - pathOut->lineTo(pathIn->pts[i0].x + wdy, - pathIn->pts[i0].y - wdx); - break; - } - } else { - pathOut->lineTo(pathIn->pts[i0].x + wdy, pathIn->pts[i0].y - wdx); - } - - // draw the left side of the segment rectangle - left2 = pathOut->length - 1; - pathOut->lineTo(pathIn->pts[j0].x + wdy, pathIn->pts[j0].y - wdx); - - // draw the end cap - if (last && !closed) { - switch (state->lineCap) { - case splashLineCapButt: - pathOut->lineTo(pathIn->pts[j0].x - wdy, pathIn->pts[j0].y + wdx); - break; - case splashLineCapRound: - pathOut->curveTo(pathIn->pts[j0].x + wdy + bezierCircle * wdx, - pathIn->pts[j0].y - wdx + bezierCircle * wdy, - pathIn->pts[j0].x + wdx + bezierCircle * wdy, - pathIn->pts[j0].y + wdy - bezierCircle * wdx, - pathIn->pts[j0].x + wdx, - pathIn->pts[j0].y + wdy); - pathOut->curveTo(pathIn->pts[j0].x + wdx - bezierCircle * wdy, - pathIn->pts[j0].y + wdy + bezierCircle * wdx, - pathIn->pts[j0].x - wdy + bezierCircle * wdx, - pathIn->pts[j0].y + wdx + bezierCircle * wdy, - pathIn->pts[j0].x - wdy, - pathIn->pts[j0].y + wdx); - break; - case splashLineCapProjecting: - pathOut->lineTo(pathIn->pts[j0].x + wdy + wdx, - pathIn->pts[j0].y - wdx + wdy); - pathOut->lineTo(pathIn->pts[j0].x - wdy + wdx, - pathIn->pts[j0].y + wdx + wdy); - pathOut->lineTo(pathIn->pts[j0].x - wdy, - pathIn->pts[j0].y + wdx); - break; - } - } else { - pathOut->lineTo(pathIn->pts[j0].x - wdy, pathIn->pts[j0].y + wdx); - } - - // draw the right side of the segment rectangle - // (NB: if stroke adjustment is enabled, the closepath operation MUST - // add a segment because this segment is used for a hint) - right2 = pathOut->length - 1; - pathOut->close(state->strokeAdjust); - - // draw the join - join2 = pathOut->length; - if (!last || closed) { - - // compute the deltas for segment (j1, k0) -#ifdef USE_FIXEDPOINT - // the 1/d value can be small, which introduces significant - // inaccuracies in fixed point mode - d = splashDist(pathIn->pts[j1].x, pathIn->pts[j1].y, - pathIn->pts[k0].x, pathIn->pts[k0].y); - dxNext = (pathIn->pts[k0].x - pathIn->pts[j1].x) / d; - dyNext = (pathIn->pts[k0].y - pathIn->pts[j1].y) / d; -#else - d = (SplashCoord)1 / splashDist(pathIn->pts[j1].x, pathIn->pts[j1].y, - pathIn->pts[k0].x, pathIn->pts[k0].y); - dxNext = d * (pathIn->pts[k0].x - pathIn->pts[j1].x); - dyNext = d * (pathIn->pts[k0].y - pathIn->pts[j1].y); -#endif - wdxNext = (SplashCoord)0.5 * w * dxNext; - wdyNext = (SplashCoord)0.5 * w * dyNext; - - // compute the join parameters - crossprod = dx * dyNext - dy * dxNext; - dotprod = -(dx * dxNext + dy * dyNext); - hasangle = crossprod != 0 || dx * dxNext < 0 || dy * dyNext < 0; - if (dotprod > 0.9999) { - // avoid a divide-by-zero -- set miter to something arbitrary - // such that sqrt(miter) will exceed miterLimit (and m is never - // used in that situation) - // (note: the comparison value (0.9999) has to be less than - // 1-epsilon, where epsilon is the smallest value - // representable in the fixed point format) - miter = (state->miterLimit + 1) * (state->miterLimit + 1); - m = 0; - } else { - miter = (SplashCoord)2 / ((SplashCoord)1 - dotprod); - if (miter < 1) { - // this can happen because of floating point inaccuracies - miter = 1; - } - m = splashSqrt(miter - 1); - } - - // round join - if (hasangle && state->lineJoin == splashLineJoinRound) { - pathOut->moveTo(pathIn->pts[j0].x + (SplashCoord)0.5 * w, - pathIn->pts[j0].y); - pathOut->curveTo(pathIn->pts[j0].x + (SplashCoord)0.5 * w, - pathIn->pts[j0].y + bezierCircle2 * w, - pathIn->pts[j0].x + bezierCircle2 * w, - pathIn->pts[j0].y + (SplashCoord)0.5 * w, - pathIn->pts[j0].x, - pathIn->pts[j0].y + (SplashCoord)0.5 * w); - pathOut->curveTo(pathIn->pts[j0].x - bezierCircle2 * w, - pathIn->pts[j0].y + (SplashCoord)0.5 * w, - pathIn->pts[j0].x - (SplashCoord)0.5 * w, - pathIn->pts[j0].y + bezierCircle2 * w, - pathIn->pts[j0].x - (SplashCoord)0.5 * w, - pathIn->pts[j0].y); - pathOut->curveTo(pathIn->pts[j0].x - (SplashCoord)0.5 * w, - pathIn->pts[j0].y - bezierCircle2 * w, - pathIn->pts[j0].x - bezierCircle2 * w, - pathIn->pts[j0].y - (SplashCoord)0.5 * w, - pathIn->pts[j0].x, - pathIn->pts[j0].y - (SplashCoord)0.5 * w); - pathOut->curveTo(pathIn->pts[j0].x + bezierCircle2 * w, - pathIn->pts[j0].y - (SplashCoord)0.5 * w, - pathIn->pts[j0].x + (SplashCoord)0.5 * w, - pathIn->pts[j0].y - bezierCircle2 * w, - pathIn->pts[j0].x + (SplashCoord)0.5 * w, - pathIn->pts[j0].y); - - } else if (hasangle) { - pathOut->moveTo(pathIn->pts[j0].x, pathIn->pts[j0].y); - - // angle < 180 - if (crossprod < 0) { - pathOut->lineTo(pathIn->pts[j0].x - wdyNext, - pathIn->pts[j0].y + wdxNext); - // miter join inside limit - if (state->lineJoin == splashLineJoinMiter && - splashSqrt(miter) <= state->miterLimit) { - pathOut->lineTo(pathIn->pts[j0].x - wdy + wdx * m, - pathIn->pts[j0].y + wdx + wdy * m); - pathOut->lineTo(pathIn->pts[j0].x - wdy, - pathIn->pts[j0].y + wdx); - // bevel join or miter join outside limit - } else { - pathOut->lineTo(pathIn->pts[j0].x - wdy, - pathIn->pts[j0].y + wdx); - } - - // angle >= 180 - } else { - pathOut->lineTo(pathIn->pts[j0].x + wdy, - pathIn->pts[j0].y - wdx); - // miter join inside limit - if (state->lineJoin == splashLineJoinMiter && - splashSqrt(miter) <= state->miterLimit) { - pathOut->lineTo(pathIn->pts[j0].x + wdy + wdx * m, - pathIn->pts[j0].y - wdx + wdy * m); - pathOut->lineTo(pathIn->pts[j0].x + wdyNext, - pathIn->pts[j0].y - wdxNext); - // bevel join or miter join outside limit - } else { - pathOut->lineTo(pathIn->pts[j0].x + wdyNext, - pathIn->pts[j0].y - wdxNext); - } - } - } - - pathOut->close(); - } - - // add stroke adjustment hints - if (state->strokeAdjust) { - if (seg == 0 && !closed) { - if (state->lineCap == splashLineCapButt) { - pathOut->addStrokeAdjustHint(firstPt, left2 + 1, - firstPt, firstPt + 1); - if (last) { - pathOut->addStrokeAdjustHint(firstPt, left2 + 1, - left2 + 1, left2 + 2); - } - } else if (state->lineCap == splashLineCapProjecting) { - if (last) { - pathOut->addStrokeAdjustHint(firstPt + 1, left2 + 2, - firstPt + 1, firstPt + 2); - pathOut->addStrokeAdjustHint(firstPt + 1, left2 + 2, - left2 + 2, left2 + 3); - } else { - pathOut->addStrokeAdjustHint(firstPt + 1, left2 + 1, - firstPt + 1, firstPt + 2); - } - } - } - if (seg >= 1) { - if (seg >= 2) { - pathOut->addStrokeAdjustHint(left1, right1, left0 + 1, right0); - pathOut->addStrokeAdjustHint(left1, right1, join0, left2); - } else { - pathOut->addStrokeAdjustHint(left1, right1, firstPt, left2); - } - pathOut->addStrokeAdjustHint(left1, right1, right2 + 1, right2 + 1); - } - left0 = left1; - left1 = left2; - right0 = right1; - right1 = right2; - join0 = join1; - join1 = join2; - if (seg == 0) { - leftFirst = left2; - rightFirst = right2; - } - if (last) { - if (seg >= 2) { - pathOut->addStrokeAdjustHint(left1, right1, left0 + 1, right0); - pathOut->addStrokeAdjustHint(left1, right1, - join0, pathOut->length - 1); - } else { - pathOut->addStrokeAdjustHint(left1, right1, - firstPt, pathOut->length - 1); - } - if (closed) { - pathOut->addStrokeAdjustHint(left1, right1, firstPt, leftFirst); - pathOut->addStrokeAdjustHint(left1, right1, - rightFirst + 1, rightFirst + 1); - pathOut->addStrokeAdjustHint(leftFirst, rightFirst, - left1 + 1, right1); - pathOut->addStrokeAdjustHint(leftFirst, rightFirst, - join1, pathOut->length - 1); - } - if (!closed && seg > 0) { - if (state->lineCap == splashLineCapButt) { - pathOut->addStrokeAdjustHint(left1 - 1, left1 + 1, - left1 + 1, left1 + 2); - } else if (state->lineCap == splashLineCapProjecting) { - pathOut->addStrokeAdjustHint(left1 - 1, left1 + 2, - left1 + 2, left1 + 3); - } - } - } - } - - i0 = j0; - i1 = j1; - ++seg; - } - - if (pathIn != path) { - delete pathIn; - } - - return pathOut; -} - -void Splash::dumpPath(SplashPath *path) { - int i; - - for (i = 0; i < path->length; ++i) { - printf(" %3d: x=%8.2f y=%8.2f%s%s%s%s\n", - i, (double)path->pts[i].x, (double)path->pts[i].y, - (path->flags[i] & splashPathFirst) ? " first" : "", - (path->flags[i] & splashPathLast) ? " last" : "", - (path->flags[i] & splashPathClosed) ? " closed" : "", - (path->flags[i] & splashPathCurve) ? " curve" : ""); - } -} - -void Splash::dumpXPath(SplashXPath *path) { - int i; - - for (i = 0; i < path->length; ++i) { - printf(" %4d: x0=%8.2f y0=%8.2f x1=%8.2f y1=%8.2f %s%s%s\n", - i, (double)path->segs[i].x0, (double)path->segs[i].y0, - (double)path->segs[i].x1, (double)path->segs[i].y1, - (path->segs[i].flags & splashXPathHoriz) ? "H" : " ", - (path->segs[i].flags & splashXPathVert) ? "V" : " ", - (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 (vectorAntialias && 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); - if (vectorAntialias) { - xPath->aaScale(); - } - xPath->sort(); - yMinI = state->clip->getYMinI(); - yMaxI = state->clip->getYMaxI(); - if (vectorAntialias && !inShading) { - yMinI = yMinI * splashAASize; - yMaxI = (yMaxI + 1) * splashAASize - 1; - } - scanner = new SplashXPathScanner(xPath, gFalse, yMinI, yMaxI); - - // get the min and max x and y values - if (vectorAntialias) { - scanner->getBBoxAA(&xMinI, &yMinI, &xMaxI, &yMaxI); - } else { - scanner->getBBox(&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, (Guchar)splashRound(state->fillAlpha * 255), vectorAntialias && !hasBBox, gFalse); - - // draw the spans - if (vectorAntialias) { - for (y = yMinI; y <= yMaxI; ++y) { - scanner->renderAALine(aaBuf, &x0, &x1, y); - if (clipRes != splashClipAllInside) { - state->clip->clipAALine(aaBuf, &x0, &x1, y); - } -#if splashAASize == 4 - if (!hasBBox && y > yMinI && y < yMaxI) { - // correct shape on left side if clip is - // vertical through the middle of shading: - Guchar *p0, *p1, *p2, *p3; - Guchar c1, c2, c3, c4; - p0 = aaBuf->getDataPtr() + (x0 >> 1); - p1 = p0 + aaBuf->getRowSize(); - p2 = p1 + aaBuf->getRowSize(); - p3 = p2 + aaBuf->getRowSize(); - if (x0 & 1) { - c1 = (*p0 & 0x0f); c2 =(*p1 & 0x0f); c3 = (*p2 & 0x0f) ; c4 = (*p3 & 0x0f); - } else { - c1 = (*p0 >> 4); c2 = (*p1 >> 4); c3 = (*p2 >> 4); c4 = (*p3 >> 4); - } - if ( (c1 & 0x03) == 0x03 && (c2 & 0x03) == 0x03 && (c3 & 0x03) == 0x03 && (c4 & 0x03) == 0x03 - && c1 == c2 && c2 == c3 && c3 == c4 && - pattern->testPosition(x0 - 1, y) ) - { - Guchar shapeCorrection = (x0 & 1) ? 0x0f : 0xf0; - *p0 |= shapeCorrection; - *p1 |= shapeCorrection; - *p2 |= shapeCorrection; - *p3 |= shapeCorrection; - } - // correct shape on right side if clip is - // through the middle of shading: - p0 = aaBuf->getDataPtr() + (x1 >> 1); - p1 = p0 + aaBuf->getRowSize(); - p2 = p1 + aaBuf->getRowSize(); - p3 = p2 + aaBuf->getRowSize(); - if (x1 & 1) { - c1 = (*p0 & 0x0f); c2 =(*p1 & 0x0f); c3 = (*p2 & 0x0f) ; c4 = (*p3 & 0x0f); - } else { - c1 = (*p0 >> 4); c2 = (*p1 >> 4); c3 = (*p2 >> 4); c4 = (*p3 >> 4); - } - - if ( (c1 & 0xc) == 0x0c && (c2 & 0x0c) == 0x0c && (c3 & 0x0c) == 0x0c && (c4 & 0x0c) == 0x0c - && c1 == c2 && c2 == c3 && c3 == c4 && - pattern->testPosition(x1 + 1, y) ) - { - Guchar shapeCorrection = (x1 & 1) ? 0x0f : 0xf0; - *p0 |= shapeCorrection; - *p1 |= shapeCorrection; - *p2 |= shapeCorrection; - *p3 |= shapeCorrection; - } - } -#endif - drawAALine(&pipe, x0, x1, y); - } - } else { - SplashClipResult clipRes2; - for (y = yMinI; y <= yMaxI; ++y) { - while (scanner->getNextSpan(y, &x0, &x1)) { - if (clipRes == splashClipAllInside) { - drawSpan(&pipe, x0, x1, y, gTrue); - } else { - // limit the x range - if (x0 < state->clip->getXMinI()) { - x0 = state->clip->getXMinI(); - } - if (x1 > state->clip->getXMaxI()) { - x1 = state->clip->getXMaxI(); - } - clipRes2 = state->clip->testSpan(x0, x1, y); - drawSpan(&pipe, x0, x1, y, clipRes2 == splashClipAllInside); - } - } - } - } - } - opClipRes = clipRes; - - delete scanner; - delete xPath; - return splashOk; -} |