summaryrefslogtreecommitdiff
path: root/Build/source/libs/poppler/poppler-src/splash/Splash.cc
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/libs/poppler/poppler-src/splash/Splash.cc')
-rw-r--r--Build/source/libs/poppler/poppler-src/splash/Splash.cc6479
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;
-}