summaryrefslogtreecommitdiff
path: root/splash
diff options
context:
space:
mode:
authorAlbert Astals Cid <aacid@kde.org>2020-07-03 23:51:42 +0200
committerAlbert Astals Cid <aacid@kde.org>2020-07-03 23:51:42 +0200
commit814fbda28cc8a37fed3134c2db8da28f86fb5ee0 (patch)
tree77872b408199925ebba6a68b0dccaa0d29274c3f /splash
parent0d48722746b9702e219df58ad14cee6184a62bef (diff)
Run clang-format
find . \( -name "*.cpp" -or -name "*.h" -or -name "*.c" -or -name "*.cc" \) -exec clang-format -i {} \; If you reached this file doing a git blame, please see README.contributors (instructions added 2 commits in the future to this one)
Diffstat (limited to 'splash')
-rw-r--r--splash/Splash.cc11556
-rw-r--r--splash/Splash.h598
-rw-r--r--splash/SplashBitmap.cc1357
-rw-r--r--splash/SplashBitmap.h147
-rw-r--r--splash/SplashClip.cc652
-rw-r--r--splash/SplashClip.h153
-rw-r--r--splash/SplashErrorCodes.h24
-rw-r--r--splash/SplashFTFont.cc712
-rw-r--r--splash/SplashFTFont.h46
-rw-r--r--splash/SplashFTFontEngine.cc190
-rw-r--r--splash/SplashFTFontEngine.h49
-rw-r--r--splash/SplashFTFontFile.cc165
-rw-r--r--splash/SplashFTFontFile.h51
-rw-r--r--splash/SplashFont.cc321
-rw-r--r--splash/SplashFont.h118
-rw-r--r--splash/SplashFontEngine.cc315
-rw-r--r--splash/SplashFontEngine.h78
-rw-r--r--splash/SplashFontFile.cc104
-rw-r--r--splash/SplashFontFile.h76
-rw-r--r--splash/SplashFontFileID.cc6
-rw-r--r--splash/SplashFontFileID.h14
-rw-r--r--splash/SplashGlyphBitmap.h13
-rw-r--r--splash/SplashMath.h227
-rw-r--r--splash/SplashPath.cc315
-rw-r--r--splash/SplashPath.h133
-rw-r--r--splash/SplashPattern.cc21
-rw-r--r--splash/SplashPattern.h71
-rw-r--r--splash/SplashScreen.cc577
-rw-r--r--splash/SplashScreen.h78
-rw-r--r--splash/SplashState.cc406
-rw-r--r--splash/SplashState.h147
-rw-r--r--splash/SplashTypes.h230
-rw-r--r--splash/SplashXPath.cc736
-rw-r--r--splash/SplashXPath.h96
-rw-r--r--splash/SplashXPathScanner.cc855
-rw-r--r--splash/SplashXPathScanner.h121
36 files changed, 10146 insertions, 10612 deletions
diff --git a/splash/Splash.cc b/splash/Splash.cc
index feb738bb..26586615 100644
--- a/splash/Splash.cc
+++ b/splash/Splash.cc
@@ -63,17 +63,24 @@
#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 unsigned char div255(int x) {
- return (unsigned char)((x + (x >> 8) + 0x80) >> 8);
+static inline unsigned char div255(int x)
+{
+ return (unsigned char)((x + (x >> 8) + 0x80) >> 8);
}
// Clip x to lie in [0, 255].
-static inline unsigned char clip255(int x) {
- return x < 0 ? 0 : x > 255 ? 255 : x;
+static inline unsigned char 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; }
+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
@@ -90,30 +97,35 @@ 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 imgCoordMungeLower(SplashCoord x)
+{
+ return splashFloor(x);
}
-static inline int imgCoordMungeUpper(SplashCoord x) {
- return splashFloor(x) + 1;
+static inline int imgCoordMungeUpper(SplashCoord x)
+{
+ return splashFloor(x) + 1;
}
-static inline int imgCoordMungeLowerC(SplashCoord x, bool glyphMode) {
- return glyphMode ? (splashCeil(x + 0.5) - 1) : splashFloor(x);
+static inline int imgCoordMungeLowerC(SplashCoord x, bool glyphMode)
+{
+ return glyphMode ? (splashCeil(x + 0.5) - 1) : splashFloor(x);
}
-static inline int imgCoordMungeUpperC(SplashCoord x, bool glyphMode) {
- return glyphMode ? (splashCeil(x + 0.5) - 1) : (splashFloor(x) + 1);
+static inline int imgCoordMungeUpperC(SplashCoord x, bool 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
+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
};
//------------------------------------------------------------------------
@@ -122,809 +134,714 @@ struct ImageSection {
#define splashPipeMaxStages 9
-struct SplashPipe {
- // pixel coordinates
- int x, y;
+struct SplashPipe
+{
+ // pixel coordinates
+ int x, y;
- // source pattern
- SplashPattern *pattern;
+ // source pattern
+ SplashPattern *pattern;
- // source alpha and color
- unsigned char aInput;
- bool usesShape;
- SplashColorPtr cSrc;
- SplashColor cSrcVal = {};
+ // source alpha and color
+ unsigned char aInput;
+ bool usesShape;
+ SplashColorPtr cSrc;
+ SplashColor cSrcVal = {};
- // non-isolated group alpha0
- unsigned char *alpha0Ptr;
+ // non-isolated group alpha0
+ unsigned char *alpha0Ptr;
- // knockout groups
- bool knockout;
- unsigned char knockoutOpacity;
+ // knockout groups
+ bool knockout;
+ unsigned char knockoutOpacity;
- // soft mask
- SplashColorPtr softMaskPtr;
+ // soft mask
+ SplashColorPtr softMaskPtr;
- // destination alpha and color
- SplashColorPtr destColorPtr;
- int destColorMask;
- unsigned char *destAlphaPtr;
+ // destination alpha and color
+ SplashColorPtr destColorPtr;
+ int destColorMask;
+ unsigned char *destAlphaPtr;
- // shape
- unsigned char shape;
+ // shape
+ unsigned char shape;
- // result alpha and color
- bool noTransparency;
- SplashPipeResultColorCtrl resultColorCtrl;
+ // result alpha and color
+ bool noTransparency;
+ SplashPipeResultColorCtrl resultColorCtrl;
- // non-isolated group correction
- bool nonIsolatedGroup;
+ // non-isolated group correction
+ bool nonIsolatedGroup;
- // the "run" function
- void (Splash::*run)(SplashPipe *pipe);
+ // the "run" function
+ void (Splash::*run)(SplashPipe *pipe);
};
-SplashPipeResultColorCtrl Splash::pipeResultColorNoAlphaBlend[] = {
- splashPipeResultColorNoAlphaBlendMono,
- splashPipeResultColorNoAlphaBlendMono,
- splashPipeResultColorNoAlphaBlendRGB,
- splashPipeResultColorNoAlphaBlendRGB,
- splashPipeResultColorNoAlphaBlendRGB,
- splashPipeResultColorNoAlphaBlendCMYK,
- splashPipeResultColorNoAlphaBlendDeviceN
-};
+SplashPipeResultColorCtrl Splash::pipeResultColorNoAlphaBlend[] = { splashPipeResultColorNoAlphaBlendMono, splashPipeResultColorNoAlphaBlendMono, splashPipeResultColorNoAlphaBlendRGB, splashPipeResultColorNoAlphaBlendRGB,
+ splashPipeResultColorNoAlphaBlendRGB, splashPipeResultColorNoAlphaBlendCMYK, splashPipeResultColorNoAlphaBlendDeviceN };
-SplashPipeResultColorCtrl Splash::pipeResultColorAlphaNoBlend[] = {
- splashPipeResultColorAlphaNoBlendMono,
- splashPipeResultColorAlphaNoBlendMono,
- splashPipeResultColorAlphaNoBlendRGB,
- splashPipeResultColorAlphaNoBlendRGB,
- splashPipeResultColorAlphaNoBlendRGB,
- splashPipeResultColorAlphaNoBlendCMYK,
- splashPipeResultColorAlphaNoBlendDeviceN
-};
+SplashPipeResultColorCtrl Splash::pipeResultColorAlphaNoBlend[] = { splashPipeResultColorAlphaNoBlendMono, splashPipeResultColorAlphaNoBlendMono, splashPipeResultColorAlphaNoBlendRGB, splashPipeResultColorAlphaNoBlendRGB,
+ splashPipeResultColorAlphaNoBlendRGB, splashPipeResultColorAlphaNoBlendCMYK, splashPipeResultColorAlphaNoBlendDeviceN };
-SplashPipeResultColorCtrl Splash::pipeResultColorAlphaBlend[] = {
- splashPipeResultColorAlphaBlendMono,
- splashPipeResultColorAlphaBlendMono,
- splashPipeResultColorAlphaBlendRGB,
- splashPipeResultColorAlphaBlendRGB,
- splashPipeResultColorAlphaBlendRGB,
- splashPipeResultColorAlphaBlendCMYK,
- splashPipeResultColorAlphaBlendDeviceN
-};
+SplashPipeResultColorCtrl Splash::pipeResultColorAlphaBlend[] = { splashPipeResultColorAlphaBlendMono, splashPipeResultColorAlphaBlendMono, splashPipeResultColorAlphaBlendRGB, splashPipeResultColorAlphaBlendRGB,
+ splashPipeResultColorAlphaBlendRGB, splashPipeResultColorAlphaBlendCMYK, splashPipeResultColorAlphaBlendDeviceN };
//------------------------------------------------------------------------
-static void blendXor(SplashColorPtr src, SplashColorPtr dest,
- SplashColorPtr blend, SplashColorMode cm) {
- int i;
+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];
- }
+ for (i = 0; i < splashColorModeNComps[cm]; ++i) {
+ blend[i] = src[i] ^ dest[i];
+ }
}
//------------------------------------------------------------------------
// pipeline
//------------------------------------------------------------------------
-inline void Splash::pipeInit(SplashPipe *pipe, int x, int y,
- SplashPattern *pattern, SplashColorPtr cSrc,
- unsigned char aInput, bool usesShape,
- bool nonIsolatedGroup,
- bool knockout, unsigned char knockoutOpacity) {
- pipeSetXY(pipe, x, y);
- pipe->pattern = nullptr;
-
- // 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 = true;
- } else {
- pipe->noTransparency = false;
- }
-
- // 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;
- } else if (bitmap->mode == splashModeCMYK8 && pipe->destAlphaPtr) {
- pipe->run = &Splash::pipeRunSimpleCMYK8;
- } else if (bitmap->mode == splashModeDeviceN8 && pipe->destAlphaPtr) {
- pipe->run = &Splash::pipeRunSimpleDeviceN8;
- }
- } 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;
- } else if (bitmap->mode == splashModeCMYK8 && pipe->destAlphaPtr) {
- pipe->run = &Splash::pipeRunAACMYK8;
- } else if (bitmap->mode == splashModeDeviceN8 && pipe->destAlphaPtr) {
- pipe->run = &Splash::pipeRunAADeviceN8;
- }
- }
-}
+inline void Splash::pipeInit(SplashPipe *pipe, int x, int y, SplashPattern *pattern, SplashColorPtr cSrc, unsigned char aInput, bool usesShape, bool nonIsolatedGroup, bool knockout, unsigned char knockoutOpacity)
+{
+ pipeSetXY(pipe, x, y);
+ pipe->pattern = nullptr;
-// general case
-void Splash::pipeRun(SplashPipe *pipe) {
- unsigned char aSrc, aDest, alphaI, alphaIm1, alpha0, aResult;
- SplashColor cSrcNonIso, cDest, cBlend;
- SplashColorPtr cSrc;
- unsigned char cResult0, cResult1, cResult2, cResult3;
- int t;
- int cp, mask;
- unsigned char cResult[SPOT_NCOMPS+4];
+ // 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 color
+ // source alpha
+ pipe->aInput = aInput;
+ pipe->usesShape = usesShape;
+ pipe->shape = 0;
- // static pattern: handled in pipeInit
- // fixed color: handled in pipeInit
+ // knockout
+ pipe->knockout = knockout;
+ pipe->knockoutOpacity = knockoutOpacity;
- // dynamic pattern
- if (pipe->pattern) {
- if (!pipe->pattern->getColor(pipe->x, pipe->y, pipe->cSrcVal)) {
- pipeIncX(pipe);
- return;
+ // result alpha
+ if (aInput == 255 && !state->softMask && !usesShape && !state->inNonIsolatedGroup && !nonIsolatedGroup) {
+ pipe->noTransparency = true;
+ } else {
+ pipe->noTransparency = false;
}
- if (bitmap->mode == splashModeCMYK8 || bitmap->mode == splashModeDeviceN8) {
- if (state->fillOverprint && state->overprintMode && pipe->pattern->isCMYK()) {
- unsigned int overprintMask = 15;
- if (pipe->cSrcVal[0] == 0) {
- overprintMask &= ~1;
+
+ // 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;
+ } else if (bitmap->mode == splashModeCMYK8 && pipe->destAlphaPtr) {
+ pipe->run = &Splash::pipeRunSimpleCMYK8;
+ } else if (bitmap->mode == splashModeDeviceN8 && pipe->destAlphaPtr) {
+ pipe->run = &Splash::pipeRunSimpleDeviceN8;
}
- if (pipe->cSrcVal[1] == 0) {
- overprintMask &= ~2;
+ } 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;
+ } else if (bitmap->mode == splashModeCMYK8 && pipe->destAlphaPtr) {
+ pipe->run = &Splash::pipeRunAACMYK8;
+ } else if (bitmap->mode == splashModeDeviceN8 && pipe->destAlphaPtr) {
+ pipe->run = &Splash::pipeRunAADeviceN8;
}
- if (pipe->cSrcVal[2] == 0) {
- overprintMask &= ~4;
+ }
+}
+
+// general case
+void Splash::pipeRun(SplashPipe *pipe)
+{
+ unsigned char aSrc, aDest, alphaI, alphaIm1, alpha0, aResult;
+ SplashColor cSrcNonIso, cDest, cBlend;
+ SplashColorPtr cSrc;
+ unsigned char cResult0, cResult1, cResult2, cResult3;
+ int t;
+ int cp, mask;
+ unsigned char cResult[SPOT_NCOMPS + 4];
+
+ //----- 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;
}
- if (pipe->cSrcVal[3] == 0) {
- overprintMask &= ~8;
+ if (bitmap->mode == splashModeCMYK8 || bitmap->mode == splashModeDeviceN8) {
+ if (state->fillOverprint && state->overprintMode && pipe->pattern->isCMYK()) {
+ unsigned int overprintMask = 15;
+ if (pipe->cSrcVal[0] == 0) {
+ overprintMask &= ~1;
+ }
+ if (pipe->cSrcVal[1] == 0) {
+ overprintMask &= ~2;
+ }
+ if (pipe->cSrcVal[2] == 0) {
+ overprintMask &= ~4;
+ }
+ if (pipe->cSrcVal[3] == 0) {
+ overprintMask &= ~8;
+ }
+ state->overprintMask = overprintMask;
+ }
}
- state->overprintMask = overprintMask;
- }
}
- }
- if (pipe->noTransparency && !state->blendFunc) {
+ if (pipe->noTransparency && !state->blendFunc) {
- //----- write destination pixel
+ //----- 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;
- 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]];
+ 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;
+ 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;
+ }
+ if (pipe->destAlphaPtr) {
+ *pipe->destAlphaPtr++ = 255;
}
- mask <<= 1;
- }
- pipe->destColorPtr += (SPOT_NCOMPS+4);
- break;
- }
- if (pipe->destAlphaPtr) {
- *pipe->destAlphaPtr++ = 255;
- }
-
- } else {
- //----- read destination pixel
+ } else {
- unsigned char *destColorPtr;
- if (pipe->shape && state->blendFunc && pipe->knockout && alpha0Bitmap != nullptr) {
- destColorPtr = alpha0Bitmap->data + (alpha0Y+pipe->y)*alpha0Bitmap->rowSize;
- switch (bitmap->mode) {
+ //----- read destination pixel
+
+ unsigned char *destColorPtr;
+ if (pipe->shape && state->blendFunc && pipe->knockout && alpha0Bitmap != nullptr) {
+ 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:
+ case splashModeCMYK8:
+ destColorPtr += (alpha0X + pipe->x) * 4;
+ break;
+ case splashModeDeviceN8:
+ destColorPtr += (alpha0X + pipe->x) * (SPOT_NCOMPS + 4);
+ break;
+ }
+ } else {
+ destColorPtr = pipe->destColorPtr;
+ }
+ switch (bitmap->mode) {
case splashModeMono1:
- destColorPtr += (alpha0X+pipe->x) / 8;
- break;
+ cDest[0] = (*destColorPtr & pipe->destColorMask) ? 0xff : 0x00;
+ break;
case splashModeMono8:
- destColorPtr += (alpha0X+pipe->x);
- break;
+ cDest[0] = *destColorPtr;
+ break;
case splashModeRGB8:
- case splashModeBGR8:
- destColorPtr += (alpha0X+pipe->x) * 3;
- break;
+ 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;
case splashModeCMYK8:
- destColorPtr += (alpha0X+pipe->x) * 4;
- break;
+ cDest[0] = destColorPtr[0];
+ cDest[1] = destColorPtr[1];
+ cDest[2] = destColorPtr[2];
+ cDest[3] = destColorPtr[3];
+ break;
case splashModeDeviceN8:
- destColorPtr += (alpha0X+pipe->x) * (SPOT_NCOMPS + 4);
- break;
- }
- } 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;
- 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;
- }
- if (pipe->destAlphaPtr) {
- aDest = *pipe->destAlphaPtr;
- } else {
- aDest = 0xff;
- }
+ for (cp = 0; cp < SPOT_NCOMPS + 4; cp++)
+ cDest[cp] = destColorPtr[cp];
+ break;
+ }
+ if (pipe->destAlphaPtr) {
+ aDest = *pipe->destAlphaPtr;
+ } else {
+ aDest = 0xff;
+ }
- //----- source alpha
+ //----- 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) {
- 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;
- 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;
- }
+ 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;
+ }
- //----- blend function
+ //----- non-isolated group correction
- if (state->blendFunc) {
- if (bitmap->mode == splashModeDeviceN8) {
- for (int k = 4; k < 4 + SPOT_NCOMPS; k++) {
- cBlend[k] = 0;
+ 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) {
+ 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;
+ 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;
}
- }
- (*state->blendFunc)(cSrc, cDest, cBlend, bitmap->mode);
- }
- //----- result alpha and non-isolated group element correction
+ //----- blend function
- if (pipe->noTransparency) {
- alphaI = alphaIm1 = aResult = 255;
- } else {
- aResult = aSrc + aDest - div255(aSrc * aDest);
+ if (state->blendFunc) {
+ if (bitmap->mode == splashModeDeviceN8) {
+ for (int k = 4; k < 4 + SPOT_NCOMPS; k++) {
+ cBlend[k] = 0;
+ }
+ }
+ (*state->blendFunc)(cSrc, cDest, cBlend, bitmap->mode);
+ }
- // 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 alpha and non-isolated group element correction
- //----- result color
+ 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;
+ }
+ }
- 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;
- 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;
-
- 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;
- 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;
-
- 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;
- 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;
- }
+ //----- 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;
+ 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;
+
+ 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;
+ 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;
- //----- write destination pixel
+ 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;
+ 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;
+ }
- 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;
- 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];
+ //----- 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;
+ 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;
+ }
+ if (pipe->destAlphaPtr) {
+ *pipe->destAlphaPtr++ = aResult;
}
- mask <<=1;
- }
- pipe->destColorPtr += (SPOT_NCOMPS+4);
- break;
- }
- if (pipe->destAlphaPtr) {
- *pipe->destAlphaPtr++ = aResult;
}
- }
-
- ++pipe->x;
+ ++pipe->x;
}
// special case:
// !pipe->pattern && pipe->noTransparency && !state->blendFunc &&
// bitmap->mode == splashModeMono1 && !pipe->destAlphaPtr) {
-void Splash::pipeRunSimpleMono1(SplashPipe *pipe) {
- unsigned char cResult0;
+void Splash::pipeRunSimpleMono1(SplashPipe *pipe)
+{
+ unsigned char 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;
- }
+ //----- 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;
+ ++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;
+void Splash::pipeRunSimpleMono8(SplashPipe *pipe)
+{
+ //----- write destination pixel
+ *pipe->destColorPtr++ = state->grayTransfer[pipe->cSrc[0]];
+ *pipe->destAlphaPtr++ = 255;
- ++pipe->x;
+ ++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;
+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;
+ ++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;
+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;
+ ++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;
+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;
+ ++pipe->x;
}
// 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;
+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]];
+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;
}
- mask <<=1;
- }
- pipe->destColorPtr += (SPOT_NCOMPS+4);
- *pipe->destAlphaPtr++ = 255;
+ pipe->destColorPtr += (SPOT_NCOMPS + 4);
+ *pipe->destAlphaPtr++ = 255;
- ++pipe->x;
+ ++pipe->x;
}
// special case:
@@ -932,34 +849,34 @@ void Splash::pipeRunSimpleDeviceN8(SplashPipe *pipe) {
// pipe->usesShape && !pipe->alpha0Ptr && !state->blendFunc &&
// !pipe->nonIsolatedGroup &&
// bitmap->mode == splashModeMono1 && !pipe->destAlphaPtr
-void Splash::pipeRunAAMono1(SplashPipe *pipe) {
- unsigned char aSrc;
- SplashColor cDest;
- unsigned char cResult0;
+void Splash::pipeRunAAMono1(SplashPipe *pipe)
+{
+ unsigned char aSrc;
+ SplashColor cDest;
+ unsigned char cResult0;
- //----- read destination pixel
- cDest[0] = (*pipe->destColorPtr & pipe->destColorMask) ? 0xff : 0x00;
+ //----- read destination pixel
+ cDest[0] = (*pipe->destColorPtr & pipe->destColorMask) ? 0xff : 0x00;
- //----- source alpha
- aSrc = div255(pipe->aInput * pipe->shape);
+ //----- source alpha
+ aSrc = div255(pipe->aInput * pipe->shape);
- //----- result color
- // note: aDest = alpha2 = aResult = 0xff
- cResult0 = state->grayTransfer[(unsigned char)div255((0xff - aSrc) * cDest[0] +
- aSrc * pipe->cSrc[0])];
+ //----- result color
+ // note: aDest = alpha2 = aResult = 0xff
+ cResult0 = state->grayTransfer[(unsigned char)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;
- }
+ //----- 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;
+ ++pipe->x;
}
// special case:
@@ -967,35 +884,35 @@ void Splash::pipeRunAAMono1(SplashPipe *pipe) {
// pipe->usesShape && !pipe->alpha0Ptr && !state->blendFunc &&
// !pipe->nonIsolatedGroup &&
// bitmap->mode == splashModeMono8 && pipe->destAlphaPtr
-void Splash::pipeRunAAMono8(SplashPipe *pipe) {
- unsigned char aSrc, aDest, alpha2, aResult;
- SplashColor cDest;
- unsigned char cResult0;
+void Splash::pipeRunAAMono8(SplashPipe *pipe)
+{
+ unsigned char aSrc, aDest, alpha2, aResult;
+ SplashColor cDest;
+ unsigned char cResult0;
- //----- read destination pixel
- cDest[0] = *pipe->destColorPtr;
- aDest = *pipe->destAlphaPtr;
+ //----- read destination pixel
+ cDest[0] = *pipe->destColorPtr;
+ aDest = *pipe->destAlphaPtr;
- //----- source alpha
- aSrc = div255(pipe->aInput * pipe->shape);
+ //----- 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 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[(unsigned char)(((alpha2 - aSrc) * cDest[0] +
- aSrc * pipe->cSrc[0]) / alpha2)];
- }
+ //----- result color
+ if (alpha2 == 0) {
+ cResult0 = 0;
+ } else {
+ cResult0 = state->grayTransfer[(unsigned char)(((alpha2 - aSrc) * cDest[0] + aSrc * pipe->cSrc[0]) / alpha2)];
+ }
- //----- write destination pixel
- *pipe->destColorPtr++ = cResult0;
- *pipe->destAlphaPtr++ = aResult;
+ //----- write destination pixel
+ *pipe->destColorPtr++ = cResult0;
+ *pipe->destAlphaPtr++ = aResult;
- ++pipe->x;
+ ++pipe->x;
}
// special case:
@@ -1003,55 +920,53 @@ void Splash::pipeRunAAMono8(SplashPipe *pipe) {
// pipe->usesShape && !pipe->alpha0Ptr && !state->blendFunc &&
// !pipe->nonIsolatedGroup &&
// bitmap->mode == splashModeRGB8 && pipe->destAlphaPtr
-void Splash::pipeRunAARGB8(SplashPipe *pipe) {
- unsigned char aSrc, aDest, alpha2, aResult;
- SplashColor cDest;
- unsigned char cResult0, cResult1, cResult2;
-
- //----- read destination alpha
- aDest = *pipe->destAlphaPtr;
-
- //----- source alpha
- aSrc = div255(pipe->aInput * pipe->shape);
-
- //----- result color
- if (aSrc == 255) {
- cResult0 = state->rgbTransferR[pipe->cSrc[0]];
- cResult1 = state->rgbTransferG[pipe->cSrc[1]];
- cResult2 = state->rgbTransferB[pipe->cSrc[2]];
- aResult = 255;
-
- } else if (aSrc == 0 && aDest == 0) {
- cResult0 = 0;
- cResult1 = 0;
- cResult2 = 0;
- aResult = 0;
-
- } else {
- //----- read destination pixel
- cDest[0] = pipe->destColorPtr[0];
- cDest[1] = pipe->destColorPtr[1];
- cDest[2] = pipe->destColorPtr[2];
+void Splash::pipeRunAARGB8(SplashPipe *pipe)
+{
+ unsigned char aSrc, aDest, alpha2, aResult;
+ SplashColor cDest;
+ unsigned char cResult0, cResult1, cResult2;
- //----- result alpha and non-isolated group element correction
- aResult = aSrc + aDest - div255(aSrc * aDest);
- alpha2 = aResult;
+ //----- read destination alpha
+ aDest = *pipe->destAlphaPtr;
+
+ //----- source alpha
+ aSrc = div255(pipe->aInput * pipe->shape);
- cResult0 = state->rgbTransferR[(unsigned char)(((alpha2 - aSrc) * cDest[0] +
- aSrc * pipe->cSrc[0]) / alpha2)];
- cResult1 = state->rgbTransferG[(unsigned char)(((alpha2 - aSrc) * cDest[1] +
- aSrc * pipe->cSrc[1]) / alpha2)];
- cResult2 = state->rgbTransferB[(unsigned char)(((alpha2 - aSrc) * cDest[2] +
- aSrc * pipe->cSrc[2]) / alpha2)];
- }
+ //----- result color
+ if (aSrc == 255) {
+ cResult0 = state->rgbTransferR[pipe->cSrc[0]];
+ cResult1 = state->rgbTransferG[pipe->cSrc[1]];
+ cResult2 = state->rgbTransferB[pipe->cSrc[2]];
+ aResult = 255;
+
+ } else if (aSrc == 0 && aDest == 0) {
+ cResult0 = 0;
+ cResult1 = 0;
+ cResult2 = 0;
+ aResult = 0;
+
+ } else {
+ //----- read destination pixel
+ cDest[0] = pipe->destColorPtr[0];
+ cDest[1] = pipe->destColorPtr[1];
+ cDest[2] = pipe->destColorPtr[2];
- //----- write destination pixel
- *pipe->destColorPtr++ = cResult0;
- *pipe->destColorPtr++ = cResult1;
- *pipe->destColorPtr++ = cResult2;
- *pipe->destAlphaPtr++ = aResult;
+ //----- result alpha and non-isolated group element correction
+ aResult = aSrc + aDest - div255(aSrc * aDest);
+ alpha2 = aResult;
- ++pipe->x;
+ cResult0 = state->rgbTransferR[(unsigned char)(((alpha2 - aSrc) * cDest[0] + aSrc * pipe->cSrc[0]) / alpha2)];
+ cResult1 = state->rgbTransferG[(unsigned char)(((alpha2 - aSrc) * cDest[1] + aSrc * pipe->cSrc[1]) / alpha2)];
+ cResult2 = state->rgbTransferB[(unsigned char)(((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:
@@ -1059,56 +974,54 @@ void Splash::pipeRunAARGB8(SplashPipe *pipe) {
// pipe->usesShape && !pipe->alpha0Ptr && !state->blendFunc &&
// !pipe->nonIsolatedGroup &&
// bitmap->mode == splashModeXBGR8 && pipe->destAlphaPtr
-void Splash::pipeRunAAXBGR8(SplashPipe *pipe) {
- unsigned char aSrc, aDest, alpha2, aResult;
- SplashColor cDest;
- unsigned char cResult0, cResult1, cResult2;
-
- //----- read destination alpha
- aDest = *pipe->destAlphaPtr;
-
- //----- source alpha
- aSrc = div255(pipe->aInput * pipe->shape);
-
- //----- result color
- if (aSrc == 255) {
- cResult0 = state->rgbTransferR[pipe->cSrc[0]];
- cResult1 = state->rgbTransferG[pipe->cSrc[1]];
- cResult2 = state->rgbTransferB[pipe->cSrc[2]];
- aResult = 255;
-
- } else if (aSrc == 0 && aDest == 0) {
- cResult0 = 0;
- cResult1 = 0;
- cResult2 = 0;
- aResult = 0;
-
- } else {
- //----- read destination color
- cDest[0] = pipe->destColorPtr[2];
- cDest[1] = pipe->destColorPtr[1];
- cDest[2] = pipe->destColorPtr[0];
+void Splash::pipeRunAAXBGR8(SplashPipe *pipe)
+{
+ unsigned char aSrc, aDest, alpha2, aResult;
+ SplashColor cDest;
+ unsigned char cResult0, cResult1, cResult2;
- //----- result alpha and non-isolated group element correction
- aResult = aSrc + aDest - div255(aSrc * aDest);
- alpha2 = aResult;
+ //----- read destination alpha
+ aDest = *pipe->destAlphaPtr;
- cResult0 = state->rgbTransferR[(unsigned char)(((alpha2 - aSrc) * cDest[0] +
- aSrc * pipe->cSrc[0]) / alpha2)];
- cResult1 = state->rgbTransferG[(unsigned char)(((alpha2 - aSrc) * cDest[1] +
- aSrc * pipe->cSrc[1]) / alpha2)];
- cResult2 = state->rgbTransferB[(unsigned char)(((alpha2 - aSrc) * cDest[2] +
- aSrc * pipe->cSrc[2]) / alpha2)];
- }
+ //----- source alpha
+ aSrc = div255(pipe->aInput * pipe->shape);
- //----- write destination pixel
- *pipe->destColorPtr++ = cResult2;
- *pipe->destColorPtr++ = cResult1;
- *pipe->destColorPtr++ = cResult0;
- *pipe->destColorPtr++ = 255;
- *pipe->destAlphaPtr++ = aResult;
+ //----- result color
+ if (aSrc == 255) {
+ cResult0 = state->rgbTransferR[pipe->cSrc[0]];
+ cResult1 = state->rgbTransferG[pipe->cSrc[1]];
+ cResult2 = state->rgbTransferB[pipe->cSrc[2]];
+ aResult = 255;
+
+ } else if (aSrc == 0 && aDest == 0) {
+ cResult0 = 0;
+ cResult1 = 0;
+ cResult2 = 0;
+ aResult = 0;
+
+ } else {
+ //----- read destination color
+ cDest[0] = pipe->destColorPtr[2];
+ cDest[1] = pipe->destColorPtr[1];
+ cDest[2] = pipe->destColorPtr[0];
+
+ //----- result alpha and non-isolated group element correction
+ aResult = aSrc + aDest - div255(aSrc * aDest);
+ alpha2 = aResult;
+
+ cResult0 = state->rgbTransferR[(unsigned char)(((alpha2 - aSrc) * cDest[0] + aSrc * pipe->cSrc[0]) / alpha2)];
+ cResult1 = state->rgbTransferG[(unsigned char)(((alpha2 - aSrc) * cDest[1] + aSrc * pipe->cSrc[1]) / alpha2)];
+ cResult2 = state->rgbTransferB[(unsigned char)(((alpha2 - aSrc) * cDest[2] + aSrc * pipe->cSrc[2]) / alpha2)];
+ }
- ++pipe->x;
+ //----- write destination pixel
+ *pipe->destColorPtr++ = cResult2;
+ *pipe->destColorPtr++ = cResult1;
+ *pipe->destColorPtr++ = cResult0;
+ *pipe->destColorPtr++ = 255;
+ *pipe->destAlphaPtr++ = aResult;
+
+ ++pipe->x;
}
// special case:
@@ -1116,55 +1029,53 @@ void Splash::pipeRunAAXBGR8(SplashPipe *pipe) {
// pipe->usesShape && !pipe->alpha0Ptr && !state->blendFunc &&
// !pipe->nonIsolatedGroup &&
// bitmap->mode == splashModeBGR8 && pipe->destAlphaPtr
-void Splash::pipeRunAABGR8(SplashPipe *pipe) {
- unsigned char aSrc, aDest, alpha2, aResult;
- SplashColor cDest;
- unsigned char cResult0, cResult1, cResult2;
-
- //----- read destination alpha
- aDest = *pipe->destAlphaPtr;
-
- //----- source alpha
- aSrc = div255(pipe->aInput * pipe->shape);
-
- //----- result color
- if (aSrc == 255) {
- cResult0 = state->rgbTransferR[pipe->cSrc[0]];
- cResult1 = state->rgbTransferG[pipe->cSrc[1]];
- cResult2 = state->rgbTransferB[pipe->cSrc[2]];
- aResult = 255;
-
- } else if (aSrc == 0 && aDest == 0) {
- cResult0 = 0;
- cResult1 = 0;
- cResult2 = 0;
- aResult = 0;
-
- } else {
- //----- read destination color
- cDest[0] = pipe->destColorPtr[2];
- cDest[1] = pipe->destColorPtr[1];
- cDest[2] = pipe->destColorPtr[0];
+void Splash::pipeRunAABGR8(SplashPipe *pipe)
+{
+ unsigned char aSrc, aDest, alpha2, aResult;
+ SplashColor cDest;
+ unsigned char cResult0, cResult1, cResult2;
- //----- result alpha and non-isolated group element correction
- aResult = aSrc + aDest - div255(aSrc * aDest);
- alpha2 = aResult;
+ //----- read destination alpha
+ aDest = *pipe->destAlphaPtr;
- cResult0 = state->rgbTransferR[(unsigned char)(((alpha2 - aSrc) * cDest[0] +
- aSrc * pipe->cSrc[0]) / alpha2)];
- cResult1 = state->rgbTransferG[(unsigned char)(((alpha2 - aSrc) * cDest[1] +
- aSrc * pipe->cSrc[1]) / alpha2)];
- cResult2 = state->rgbTransferB[(unsigned char)(((alpha2 - aSrc) * cDest[2] +
- aSrc * pipe->cSrc[2]) / alpha2)];
- }
+ //----- source alpha
+ aSrc = div255(pipe->aInput * pipe->shape);
- //----- write destination pixel
- *pipe->destColorPtr++ = cResult2;
- *pipe->destColorPtr++ = cResult1;
- *pipe->destColorPtr++ = cResult0;
- *pipe->destAlphaPtr++ = aResult;
+ //----- result color
+ if (aSrc == 255) {
+ cResult0 = state->rgbTransferR[pipe->cSrc[0]];
+ cResult1 = state->rgbTransferG[pipe->cSrc[1]];
+ cResult2 = state->rgbTransferB[pipe->cSrc[2]];
+ aResult = 255;
+
+ } else if (aSrc == 0 && aDest == 0) {
+ cResult0 = 0;
+ cResult1 = 0;
+ cResult2 = 0;
+ aResult = 0;
+
+ } else {
+ //----- read destination color
+ cDest[0] = pipe->destColorPtr[2];
+ cDest[1] = pipe->destColorPtr[1];
+ cDest[2] = pipe->destColorPtr[0];
- ++pipe->x;
+ //----- result alpha and non-isolated group element correction
+ aResult = aSrc + aDest - div255(aSrc * aDest);
+ alpha2 = aResult;
+
+ cResult0 = state->rgbTransferR[(unsigned char)(((alpha2 - aSrc) * cDest[0] + aSrc * pipe->cSrc[0]) / alpha2)];
+ cResult1 = state->rgbTransferG[(unsigned char)(((alpha2 - aSrc) * cDest[1] + aSrc * pipe->cSrc[1]) / alpha2)];
+ cResult2 = state->rgbTransferB[(unsigned char)(((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;
}
// special case:
@@ -1172,67 +1083,56 @@ void Splash::pipeRunAABGR8(SplashPipe *pipe) {
// pipe->usesShape && !pipe->alpha0Ptr && !state->blendFunc &&
// !pipe->nonIsolatedGroup &&
// bitmap->mode == splashModeCMYK8 && pipe->destAlphaPtr
-void Splash::pipeRunAACMYK8(SplashPipe *pipe) {
- unsigned char aSrc, aDest, alpha2, aResult;
- SplashColor cDest;
- unsigned char 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[(unsigned char)(((alpha2 - aSrc) * cDest[0] +
- aSrc * pipe->cSrc[0]) / alpha2)];
- cResult1 = state->cmykTransferM[(unsigned char)(((alpha2 - aSrc) * cDest[1] +
- aSrc * pipe->cSrc[1]) / alpha2)];
- cResult2 = state->cmykTransferY[(unsigned char)(((alpha2 - aSrc) * cDest[2] +
- aSrc * pipe->cSrc[2]) / alpha2)];
- cResult3 = state->cmykTransferK[(unsigned char)(((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;
+void Splash::pipeRunAACMYK8(SplashPipe *pipe)
+{
+ unsigned char aSrc, aDest, alpha2, aResult;
+ SplashColor cDest;
+ unsigned char 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[(unsigned char)(((alpha2 - aSrc) * cDest[0] + aSrc * pipe->cSrc[0]) / alpha2)];
+ cResult1 = state->cmykTransferM[(unsigned char)(((alpha2 - aSrc) * cDest[1] + aSrc * pipe->cSrc[1]) / alpha2)];
+ cResult2 = state->cmykTransferY[(unsigned char)(((alpha2 - aSrc) * cDest[2] + aSrc * pipe->cSrc[2]) / alpha2)];
+ cResult3 = state->cmykTransferK[(unsigned char)(((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:
@@ -1240,5248 +1140,5066 @@ void Splash::pipeRunAACMYK8(SplashPipe *pipe) {
// pipe->usesShape && !pipe->alpha0Ptr && !state->blendFunc &&
// !pipe->nonIsolatedGroup &&
// bitmap->mode == splashModeDeviceN8 && pipe->destAlphaPtr
-void Splash::pipeRunAADeviceN8(SplashPipe *pipe) {
- unsigned char aSrc, aDest, alpha2, aResult;
- SplashColor cDest;
- unsigned char 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][(unsigned char)(((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;
-}
-
-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;
- 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;
- }
- if (bitmap->alpha) {
- pipe->destAlphaPtr = &bitmap->alpha[y * bitmap->width + x];
- } else {
- pipe->destAlphaPtr = nullptr;
- }
- if (state->inNonIsolatedGroup && alpha0Bitmap->alpha) {
- pipe->alpha0Ptr =
- &alpha0Bitmap->alpha[(alpha0Y + y) * alpha0Bitmap->width +
- (alpha0X + x)];
- } else {
- pipe->alpha0Ptr = nullptr;
- }
-}
-
-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;
- case splashModeCMYK8:
- pipe->destColorPtr += 4;
- break;
- case splashModeDeviceN8:
- pipe->destColorPtr += (SPOT_NCOMPS+4);
- break;
- }
- if (pipe->destAlphaPtr) {
- ++pipe->destAlphaPtr;
- }
- if (pipe->alpha0Ptr) {
- ++pipe->alpha0Ptr;
- }
-}
-
-inline void Splash::drawPixel(SplashPipe *pipe, int x, int y, bool noClip) {
- if (unlikely(y < 0))
- return;
-
- if (noClip || state->clip->test(x, y)) {
- pipeSetXY(pipe, x, y);
- (this->*pipe->run)(pipe);
- }
-}
+void Splash::pipeRunAADeviceN8(SplashPipe *pipe)
+{
+ unsigned char aSrc, aDest, alpha2, aResult;
+ SplashColor cDest;
+ unsigned char cResult[SPOT_NCOMPS + 4];
+ int cp, mask;
-inline void Splash::drawAAPixelInit() {
- aaBufY = -1;
-}
+ //----- read destination pixel
+ for (cp = 0; cp < SPOT_NCOMPS + 4; cp++)
+ cDest[cp] = pipe->destColorPtr[cp];
+ aDest = *pipe->destAlphaPtr;
-inline void Splash::drawAAPixel(SplashPipe *pipe, int x, int y) {
-#if splashAASize == 4
- static const 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
+ //----- source alpha
+ aSrc = div255(pipe->aInput * pipe->shape);
- // draw the pixel
- if (t != 0) {
- pipeSetXY(pipe, x, y);
- pipe->shape = div255(aaGamma[t] * pipe->shape);
- (this->*pipe->run)(pipe);
- }
+ //----- 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][(unsigned char)(((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;
}
-inline void Splash::drawSpan(SplashPipe *pipe, int x0, int x1, int y,
- bool noClip) {
- int x;
+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;
+ 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;
+ }
+ if (bitmap->alpha) {
+ pipe->destAlphaPtr = &bitmap->alpha[y * bitmap->width + x];
+ } else {
+ pipe->destAlphaPtr = nullptr;
+ }
+ if (state->inNonIsolatedGroup && alpha0Bitmap->alpha) {
+ pipe->alpha0Ptr = &alpha0Bitmap->alpha[(alpha0Y + y) * alpha0Bitmap->width + (alpha0X + x)];
+ } else {
+ pipe->alpha0Ptr = nullptr;
+ }
+}
- if (noClip) {
- pipeSetXY(pipe, x0, y);
- for (x = x0; x <= x1; ++x) {
- (this->*pipe->run)(pipe);
+inline void Splash::pipeIncX(SplashPipe *pipe)
+{
+ ++pipe->x;
+ if (state->softMask) {
+ ++pipe->softMaskPtr;
}
- } else {
- if (x0 < state->clip->getXMinI()) {
- x0 = state->clip->getXMinI();
+ 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;
+ case splashModeCMYK8:
+ pipe->destColorPtr += 4;
+ break;
+ case splashModeDeviceN8:
+ pipe->destColorPtr += (SPOT_NCOMPS + 4);
+ break;
}
- if (x1 > state->clip->getXMaxI()) {
- x1 = state->clip->getXMaxI();
+ if (pipe->destAlphaPtr) {
+ ++pipe->destAlphaPtr;
}
- pipeSetXY(pipe, x0, y);
- for (x = x0; x <= x1; ++x) {
- if (state->clip->test(x, y)) {
- (this->*pipe->run)(pipe);
- } else {
- pipeIncX(pipe);
- }
+ if (pipe->alpha0Ptr) {
+ ++pipe->alpha0Ptr;
+ }
+}
+
+inline void Splash::drawPixel(SplashPipe *pipe, int x, int y, bool noClip)
+{
+ if (unlikely(y < 0))
+ return;
+
+ if (noClip || state->clip->test(x, y)) {
+ pipeSetXY(pipe, x, y);
+ (this->*pipe->run)(pipe);
}
- }
}
-inline void Splash::drawAALine(SplashPipe *pipe, int x0, int x1, int y, bool adjustLine, unsigned char lineOpacity) {
+inline void Splash::drawAAPixelInit()
+{
+ aaBufY = -1;
+}
+
+inline void Splash::drawAAPixel(SplashPipe *pipe, int x, int y)
+{
#if splashAASize == 4
- static const 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;
+ static const int bitCount4[16] = { 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4 };
+ int w;
#else
- SplashColorPtr p;
- int xx, yy, t;
+ int xx, yy;
#endif
- int x;
+ SplashColorPtr p;
+ int x0, x1, t;
-#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) {
+ 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[*p0 & 0x0f] + bitCount4[*p1 & 0x0f] +
- bitCount4[*p2 & 0x0f] + bitCount4[*p3 & 0x0f];
- ++p0; ++p1; ++p2; ++p3;
+ t = bitCount4[*p & 0x0f] + bitCount4[p[w] & 0x0f] + bitCount4[p[2 * w] & 0x0f] + bitCount4[p[3 * w] & 0x0f];
} else {
- t = bitCount4[*p0 >> 4] + bitCount4[*p1 >> 4] +
- bitCount4[*p2 >> 4] + bitCount4[*p3 >> 4];
+ 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;
- }
+ 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) {
- pipe->shape = (adjustLine) ? div255((int) lineOpacity * (double)aaGamma[t]) : (double)aaGamma[t];
- (this->*pipe->run)(pipe);
+ pipeSetXY(pipe, x, y);
+ pipe->shape = div255(aaGamma[t] * pipe->shape);
+ (this->*pipe->run)(pipe);
+ }
+}
+
+inline void Splash::drawSpan(SplashPipe *pipe, int x0, int x1, int y, bool noClip)
+{
+ int x;
+
+ if (noClip) {
+ pipeSetXY(pipe, x0, y);
+ for (x = x0; x <= x1; ++x) {
+ (this->*pipe->run)(pipe);
+ }
} else {
- pipeIncX(pipe);
+ 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);
+ } else {
+ pipeIncX(pipe);
+ }
+ }
+ }
+}
+
+inline void Splash::drawAALine(SplashPipe *pipe, int x0, int x1, int y, bool adjustLine, unsigned char lineOpacity)
+{
+#if splashAASize == 4
+ static const 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);
+ } else {
+ pipeIncX(pipe);
+ }
}
- }
}
//------------------------------------------------------------------------
// Transform a point from user space to device space.
-inline void Splash::transform(const 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];
+inline void Splash::transform(const 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, bool vectorAntialiasA,
- SplashScreenParams *screenParams) {
- int i;
-
- bitmap = bitmapA;
- vectorAntialias = vectorAntialiasA;
- inShading = false;
- state = new SplashState(bitmap->width, bitmap->height, vectorAntialias,
- screenParams);
- if (vectorAntialias) {
- aaBuf = new SplashBitmap(splashAASize * bitmap->width, splashAASize,
- 1, splashModeMono1, false);
- for (i = 0; i <= splashAASize * splashAASize; ++i) {
- aaGamma[i] = (unsigned char)splashRound(
- splashPow((SplashCoord)i /
- (SplashCoord)(splashAASize * splashAASize),
- splashAAGamma) * 255);
- }
- } else {
- aaBuf = nullptr;
- }
- minLineWidth = 0;
- thinLineMode = splashThinLineDefault;
- debugMode = false;
- alpha0Bitmap = nullptr;
-}
-
-Splash::Splash(SplashBitmap *bitmapA, bool vectorAntialiasA,
- SplashScreen *screenA) {
- int i;
-
- bitmap = bitmapA;
- inShading = false;
- vectorAntialias = vectorAntialiasA;
- state = new SplashState(bitmap->width, bitmap->height, vectorAntialias,
- screenA);
- if (vectorAntialias) {
- aaBuf = new SplashBitmap(splashAASize * bitmap->width, splashAASize,
- 1, splashModeMono1, false);
- for (i = 0; i <= splashAASize * splashAASize; ++i) {
- aaGamma[i] = (unsigned char)splashRound(
- splashPow((SplashCoord)i /
- (SplashCoord)(splashAASize * splashAASize),
- splashAAGamma) * 255);
- }
- } else {
- aaBuf = nullptr;
- }
- minLineWidth = 0;
- thinLineMode = splashThinLineDefault;
- debugMode = false;
- alpha0Bitmap = nullptr;
-}
-
-Splash::~Splash() {
- while (state->next) {
- restoreState();
- }
- delete state;
- delete aaBuf;
+Splash::Splash(SplashBitmap *bitmapA, bool vectorAntialiasA, SplashScreenParams *screenParams)
+{
+ int i;
+
+ bitmap = bitmapA;
+ vectorAntialias = vectorAntialiasA;
+ inShading = false;
+ state = new SplashState(bitmap->width, bitmap->height, vectorAntialias, screenParams);
+ if (vectorAntialias) {
+ aaBuf = new SplashBitmap(splashAASize * bitmap->width, splashAASize, 1, splashModeMono1, false);
+ for (i = 0; i <= splashAASize * splashAASize; ++i) {
+ aaGamma[i] = (unsigned char)splashRound(splashPow((SplashCoord)i / (SplashCoord)(splashAASize * splashAASize), splashAAGamma) * 255);
+ }
+ } else {
+ aaBuf = nullptr;
+ }
+ minLineWidth = 0;
+ thinLineMode = splashThinLineDefault;
+ debugMode = false;
+ alpha0Bitmap = nullptr;
+}
+
+Splash::Splash(SplashBitmap *bitmapA, bool vectorAntialiasA, SplashScreen *screenA)
+{
+ int i;
+
+ bitmap = bitmapA;
+ inShading = false;
+ vectorAntialias = vectorAntialiasA;
+ state = new SplashState(bitmap->width, bitmap->height, vectorAntialias, screenA);
+ if (vectorAntialias) {
+ aaBuf = new SplashBitmap(splashAASize * bitmap->width, splashAASize, 1, splashModeMono1, false);
+ for (i = 0; i <= splashAASize * splashAASize; ++i) {
+ aaGamma[i] = (unsigned char)splashRound(splashPow((SplashCoord)i / (SplashCoord)(splashAASize * splashAASize), splashAAGamma) * 255);
+ }
+ } else {
+ aaBuf = nullptr;
+ }
+ minLineWidth = 0;
+ thinLineMode = splashThinLineDefault;
+ debugMode = false;
+ alpha0Bitmap = nullptr;
+}
+
+Splash::~Splash()
+{
+ while (state->next) {
+ restoreState();
+ }
+ delete state;
+ delete aaBuf;
}
//------------------------------------------------------------------------
// state read
//------------------------------------------------------------------------
-SplashCoord *Splash::getMatrix() {
- return state->matrix;
+SplashCoord *Splash::getMatrix()
+{
+ return state->matrix;
}
-SplashPattern *Splash::getStrokePattern() {
- return state->strokePattern;
+SplashPattern *Splash::getStrokePattern()
+{
+ return state->strokePattern;
}
-SplashPattern *Splash::getFillPattern() {
- return state->fillPattern;
+SplashPattern *Splash::getFillPattern()
+{
+ return state->fillPattern;
}
-SplashScreen *Splash::getScreen() {
- return state->screen;
+SplashScreen *Splash::getScreen()
+{
+ return state->screen;
}
-SplashBlendFunc Splash::getBlendFunc() {
- return state->blendFunc;
+SplashBlendFunc Splash::getBlendFunc()
+{
+ return state->blendFunc;
}
-SplashCoord Splash::getStrokeAlpha() {
- return state->strokeAlpha;
+SplashCoord Splash::getStrokeAlpha()
+{
+ return state->strokeAlpha;
}
-SplashCoord Splash::getFillAlpha() {
- return state->fillAlpha;
+SplashCoord Splash::getFillAlpha()
+{
+ return state->fillAlpha;
}
-SplashCoord Splash::getLineWidth() {
- return state->lineWidth;
+SplashCoord Splash::getLineWidth()
+{
+ return state->lineWidth;
}
-int Splash::getLineCap() {
- return state->lineCap;
+int Splash::getLineCap()
+{
+ return state->lineCap;
}
-int Splash::getLineJoin() {
- return state->lineJoin;
+int Splash::getLineJoin()
+{
+ return state->lineJoin;
}
-SplashCoord Splash::getMiterLimit() {
- return state->miterLimit;
+SplashCoord Splash::getMiterLimit()
+{
+ return state->miterLimit;
}
-SplashCoord Splash::getFlatness() {
- return state->flatness;
+SplashCoord Splash::getFlatness()
+{
+ return state->flatness;
}
-SplashCoord *Splash::getLineDash() {
- return state->lineDash;
+SplashCoord *Splash::getLineDash()
+{
+ return state->lineDash;
}
-int Splash::getLineDashLength() {
- return state->lineDashLength;
+int Splash::getLineDashLength()
+{
+ return state->lineDashLength;
}
-SplashCoord Splash::getLineDashPhase() {
- return state->lineDashPhase;
+SplashCoord Splash::getLineDashPhase()
+{
+ return state->lineDashPhase;
}
-bool Splash::getStrokeAdjust() {
- return state->strokeAdjust;
+bool Splash::getStrokeAdjust()
+{
+ return state->strokeAdjust;
}
-SplashClip *Splash::getClip() {
- return state->clip;
+SplashClip *Splash::getClip()
+{
+ return state->clip;
}
-SplashBitmap *Splash::getSoftMask() {
- return state->softMask;
+SplashBitmap *Splash::getSoftMask()
+{
+ return state->softMask;
}
-bool Splash::getInNonIsolatedGroup() {
- return state->inNonIsolatedGroup;
+bool Splash::getInNonIsolatedGroup()
+{
+ return state->inNonIsolatedGroup;
}
//------------------------------------------------------------------------
// state write
//------------------------------------------------------------------------
-void Splash::setMatrix(SplashCoord *matrix) {
- memcpy(state->matrix, matrix, 6 * sizeof(SplashCoord));
+void Splash::setMatrix(SplashCoord *matrix)
+{
+ memcpy(state->matrix, matrix, 6 * sizeof(SplashCoord));
}
-void Splash::setStrokePattern(SplashPattern *strokePattern) {
- state->setStrokePattern(strokePattern);
+void Splash::setStrokePattern(SplashPattern *strokePattern)
+{
+ state->setStrokePattern(strokePattern);
}
-void Splash::setFillPattern(SplashPattern *fillPattern) {
- state->setFillPattern(fillPattern);
+void Splash::setFillPattern(SplashPattern *fillPattern)
+{
+ state->setFillPattern(fillPattern);
}
-void Splash::setScreen(SplashScreen *screen) {
- state->setScreen(screen);
+void Splash::setScreen(SplashScreen *screen)
+{
+ state->setScreen(screen);
}
-void Splash::setBlendFunc(SplashBlendFunc func) {
- state->blendFunc = func;
+void Splash::setBlendFunc(SplashBlendFunc func)
+{
+ state->blendFunc = func;
}
-void Splash::setStrokeAlpha(SplashCoord alpha) {
- state->strokeAlpha = (state->multiplyPatternAlpha) ? alpha * state->patternStrokeAlpha : alpha;
+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::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 = true;
+void Splash::setPatternAlpha(SplashCoord strokeAlpha, SplashCoord fillAlpha)
+{
+ state->patternStrokeAlpha = strokeAlpha;
+ state->patternFillAlpha = fillAlpha;
+ state->multiplyPatternAlpha = true;
}
-void Splash::clearPatternAlpha() {
- state->patternStrokeAlpha = 1;
- state->patternFillAlpha = 1;
- state->multiplyPatternAlpha = false;
+void Splash::clearPatternAlpha()
+{
+ state->patternStrokeAlpha = 1;
+ state->patternFillAlpha = 1;
+ state->multiplyPatternAlpha = false;
}
-void Splash::setFillOverprint(bool fop) {
- state->fillOverprint = fop;
+void Splash::setFillOverprint(bool fop)
+{
+ state->fillOverprint = fop;
}
-void Splash::setStrokeOverprint(bool sop) {
- state->strokeOverprint = sop;
+void Splash::setStrokeOverprint(bool sop)
+{
+ state->strokeOverprint = sop;
}
-void Splash::setOverprintMode(int opm) {
- state->overprintMode = opm;
+void Splash::setOverprintMode(int opm)
+{
+ state->overprintMode = opm;
}
-void Splash::setLineWidth(SplashCoord lineWidth) {
- state->lineWidth = lineWidth;
+void Splash::setLineWidth(SplashCoord lineWidth)
+{
+ state->lineWidth = lineWidth;
}
-void Splash::setLineCap(int lineCap) {
- state->lineCap = lineCap;
+void Splash::setLineCap(int lineCap)
+{
+ state->lineCap = lineCap;
}
-void Splash::setLineJoin(int lineJoin) {
- state->lineJoin = lineJoin;
+void Splash::setLineJoin(int lineJoin)
+{
+ state->lineJoin = lineJoin;
}
-void Splash::setMiterLimit(SplashCoord miterLimit) {
- state->miterLimit = miterLimit;
+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::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::setLineDash(SplashCoord *lineDash, int lineDashLength, SplashCoord lineDashPhase)
+{
+ state->setLineDash(lineDash, lineDashLength, lineDashPhase);
}
-void Splash::setStrokeAdjust(bool strokeAdjust) {
- state->strokeAdjust = strokeAdjust;
+void Splash::setStrokeAdjust(bool strokeAdjust)
+{
+ state->strokeAdjust = strokeAdjust;
}
-void Splash::clipResetToRect(SplashCoord x0, SplashCoord y0,
- SplashCoord x1, SplashCoord y1) {
- state->clip->resetToRect(x0, y0, x1, y1);
+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::clipToRect(SplashCoord x0, SplashCoord y0, SplashCoord x1, SplashCoord y1)
+{
+ return state->clip->clipToRect(x0, y0, x1, y1);
}
-SplashError Splash::clipToPath(SplashPath *path, bool eo) {
- return state->clip->clipToPath(path, state->matrix, state->flatness, eo);
+SplashError Splash::clipToPath(SplashPath *path, bool eo)
+{
+ return state->clip->clipToPath(path, state->matrix, state->flatness, eo);
}
-void Splash::setSoftMask(SplashBitmap *softMask) {
- state->setSoftMask(softMask);
+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 = true;
+void Splash::setInNonIsolatedGroup(SplashBitmap *alpha0BitmapA, int alpha0XA, int alpha0YA)
+{
+ alpha0Bitmap = alpha0BitmapA;
+ alpha0X = alpha0XA;
+ alpha0Y = alpha0YA;
+ state->inNonIsolatedGroup = true;
}
-void Splash::setTransfer(unsigned char *red, unsigned char *green, unsigned char *blue,
- unsigned char *gray) {
- state->setTransfer(red, green, blue, gray);
+void Splash::setTransfer(unsigned char *red, unsigned char *green, unsigned char *blue, unsigned char *gray)
+{
+ state->setTransfer(red, green, blue, gray);
}
-void Splash::setOverprintMask(unsigned int overprintMask, bool additive) {
- state->overprintMask = overprintMask;
- state->overprintAdditive = additive;
+void Splash::setOverprintMask(unsigned int overprintMask, bool additive)
+{
+ state->overprintMask = overprintMask;
+ state->overprintAdditive = additive;
}
//------------------------------------------------------------------------
// state save/restore
//------------------------------------------------------------------------
-void Splash::saveState() {
- SplashState *newState;
+void Splash::saveState()
+{
+ SplashState *newState;
- newState = state->copy();
- newState->next = state;
- state = newState;
+ newState = state->copy();
+ newState->next = state;
+ state = newState;
}
-SplashError Splash::restoreState() {
- SplashState *oldState;
+SplashError Splash::restoreState()
+{
+ SplashState *oldState;
- if (!state->next) {
- return splashErrNoSave;
- }
- oldState = state;
- state = state->next;
- delete oldState;
- return splashOk;
+ if (!state->next) {
+ return splashErrNoSave;
+ }
+ oldState = state;
+ state = state->next;
+ delete oldState;
+ return splashOk;
}
//------------------------------------------------------------------------
// drawing operations
//------------------------------------------------------------------------
-void Splash::clear(SplashColorPtr color, unsigned char alpha) {
- SplashColorPtr row, p;
- unsigned char 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);
+void Splash::clear(SplashColorPtr color, unsigned char alpha)
+{
+ SplashColorPtr row, p;
+ unsigned char 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;
+ 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;
}
- 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;
- 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);
- }
+
+ if (bitmap->alpha) {
+ memset(bitmap->alpha, alpha, bitmap->width * bitmap->height);
+ }
+}
+
+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 {
- 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;
- }
-
- if (bitmap->alpha) {
- memset(bitmap->alpha, alpha, bitmap->width * bitmap->height);
- }
-}
-
-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);
+ if (state->lineWidth == 0) {
+ strokeNarrow(path2);
+ } else {
+ strokeWide(path2, state->lineWidth);
+ }
+ }
+
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);
+ return splashOk;
+}
+
+void Splash::strokeNarrow(SplashPath *path)
+{
+ SplashPipe pipe;
+ 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;
+
+ SplashXPath xPath(path, state->matrix, state->flatness, false);
+
+ pipeInit(&pipe, 0, 0, state->strokePattern, nullptr, (unsigned char)splashRound(state->strokeAlpha * 255), false, false);
+
+ 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];
}
- } else {
- if (state->lineWidth == 0) {
- strokeNarrow(path2);
+ if (nClipRes[splashClipPartial] || (nClipRes[splashClipAllInside] && nClipRes[splashClipAllOutside])) {
+ opClipRes = splashClipPartial;
+ } else if (nClipRes[splashClipAllInside]) {
+ opClipRes = splashClipAllInside;
} else {
- strokeWide(path2, state->lineWidth);
+ opClipRes = splashClipAllOutside;
}
- }
-
- delete path2;
- return splashOk;
}
-void Splash::strokeNarrow(SplashPath *path) {
- SplashPipe pipe;
- SplashXPathSeg *seg;
- int x0, x1, y0, y1, xa, xb, y;
- SplashCoord dxdy;
- SplashClipResult clipRes;
- int nClipRes[3];
- int i;
+void Splash::strokeWide(SplashPath *path, SplashCoord w)
+{
+ SplashPath *path2;
- nClipRes[0] = nClipRes[1] = nClipRes[2] = 0;
+ path2 = makeStrokePath(path, w, false);
+ fillWithPattern(path2, false, state->strokePattern, state->strokeAlpha);
+ delete path2;
+}
- SplashXPath xPath(path, state->matrix, state->flatness, false);
+SplashPath *Splash::flattenPath(SplashPath *path, SplashCoord *matrix, SplashCoord flatness)
+{
+ SplashPath *fPath;
+ SplashCoord flatness2;
+ unsigned char flag;
+ int i;
- pipeInit(&pipe, 0, 0, state->strokePattern, nullptr,
- (unsigned char)splashRound(state->strokeAlpha * 255),
- false, false);
+ fPath = new SplashPath();
+ flatness2 = flatness * flatness;
+ 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;
+}
- 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;
- }
+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);
+ dx = tx - mx;
+ dy = ty - my;
+ d1 = dx * dx + dy * dy;
+ transform(matrix, xx2, yy2, &tx, &ty);
+ dx = tx - mx;
+ dy = ty - my;
+ d2 = dx * dx + dy * dy;
+
+ // 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;
+ }
+ }
}
-void Splash::strokeWide(SplashPath *path, SplashCoord w) {
- SplashPath *path2;
+SplashPath *Splash::makeDashedPath(SplashPath *path)
+{
+ SplashPath *dPath;
+ SplashCoord lineDashTotal;
+ SplashCoord lineDashStartPhase, lineDashDist, segLen;
+ SplashCoord x0, y0, x1, y1, xa, ya;
+ bool 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 = true;
+ 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 = true;
+ 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 = false;
+ }
+ 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 = false;
+ }
+ 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 = true;
+ }
+ }
+ }
+ i = j + 1;
+ }
+
+ if (dPath->length == 0) {
+ bool allSame = true;
+ for (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);
+ }
+ }
- path2 = makeStrokePath(path, w, false);
- fillWithPattern(path2, false, state->strokePattern, state->strokeAlpha);
- delete path2;
+ return dPath;
}
-SplashPath *Splash::flattenPath(SplashPath *path, SplashCoord *matrix,
- SplashCoord flatness) {
- SplashPath *fPath;
- SplashCoord flatness2;
- unsigned char flag;
- int i;
+SplashError Splash::fill(SplashPath *path, bool eo)
+{
+ if (debugMode) {
+ printf("fill [eo:%d]:\n", eo);
+ dumpPath(path);
+ }
+ return fillWithPattern(path, eo, state->fillPattern, state->fillAlpha);
+}
- fPath = new SplashPath();
- flatness2 = flatness * flatness;
- 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);
- dx = tx - mx;
- dy = ty - my;
- d1 = dx*dx + dy*dy;
- transform(matrix, xx2, yy2, &tx, &ty);
- dx = tx - mx;
- dy = ty - my;
- d2 = dx*dx + dy*dy;
-
- // 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;
- bool 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 = true;
- 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 = true;
- 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 = false;
- }
- 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 = false;
- }
- 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 = true;
- }
- }
- }
- i = j + 1;
- }
-
- if (dPath->length == 0) {
- bool allSame = true;
- for (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, bool 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, bool eo,
- SplashPattern *pattern,
- SplashCoord alpha) {
- SplashPipe pipe = {};
- int xMinI, yMinI, xMaxI, yMaxI, x0, x1, y;
- SplashClipResult clipRes, clipRes2;
- bool adjustLine = false;
- 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(true);
- 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 = true;
- } else if (state->clip->getXMinI() == state->clip->getXMaxI() - 1) {
- adjustLine = true;
- linePosI = splashFloor(state->clip->getXMin() + state->lineWidth);
- } else if (state->clip->getYMinI() == state->clip->getYMaxI()) {
- linePosI = state->clip->getYMinI();
- adjustLine = true;
- } else if (state->clip->getYMinI() == state->clip->getYMaxI() - 1) {
- adjustLine = true;
- linePosI = splashFloor(state->clip->getYMin() + state->lineWidth);
- }
- }
-
- SplashXPath xPath(path, state->matrix, state->flatness, true,
- 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;
- }
- SplashXPathScanner scanner(&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);
- }
+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;
+ }
+ }
- 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;
- return splashOk;
+ *xMinA = xMinFP;
+ *yMinA = yMinFP;
+ *xMaxA = xMaxFP;
+ *yMaxA = yMaxFP;
+}
+
+SplashError Splash::fillWithPattern(SplashPath *path, bool eo, SplashPattern *pattern, SplashCoord alpha)
+{
+ SplashPipe pipe = {};
+ int xMinI, yMinI, xMaxI, yMaxI, x0, x1, y;
+ SplashClipResult clipRes, clipRes2;
+ bool adjustLine = false;
+ 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(true);
+ 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);
+ }
}
- }
- // check clipping
- if ((clipRes = state->clip->testRect(xMinI, yMinI, xMaxI, yMaxI))
- != splashClipAllOutside) {
- if (scanner.hasPartialClip()) {
- clipRes = splashClipPartial;
+ if (thinLineMode != splashThinLineDefault) {
+ if (state->clip->getXMinI() == state->clip->getXMaxI()) {
+ linePosI = state->clip->getXMinI();
+ adjustLine = true;
+ } else if (state->clip->getXMinI() == state->clip->getXMaxI() - 1) {
+ adjustLine = true;
+ linePosI = splashFloor(state->clip->getXMin() + state->lineWidth);
+ } else if (state->clip->getYMinI() == state->clip->getYMaxI()) {
+ linePosI = state->clip->getYMinI();
+ adjustLine = true;
+ } else if (state->clip->getYMinI() == state->clip->getYMaxI() - 1) {
+ adjustLine = true;
+ linePosI = splashFloor(state->clip->getYMin() + state->lineWidth);
+ }
}
- pipeInit(&pipe, 0, yMinI, pattern, nullptr, (unsigned char)splashRound(alpha * 255),
- vectorAntialias && !inShading, false);
+ SplashXPath xPath(path, state->matrix, state->flatness, true, 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;
+ }
+ SplashXPathScanner scanner(&xPath, eo, yMinI, yMaxI);
- // draw the spans
+ // get the min and max x and y values
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);
- }
- unsigned char lineShape = 255;
- bool doAdjustLine = false;
- 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);
- doAdjustLine = true;
- lineShape = clip255((delta - mx) * 255);
- }
- drawAALine(&pipe, x0, x1, y, doAdjustLine, lineShape);
- }
+ scanner.getBBoxAA(&xMinI, &yMinI, &xMaxI, &yMaxI);
} else {
- for (y = yMinI; y <= yMaxI; ++y) {
- SplashXPathScanIterator iterator(scanner, y);
- while (iterator.getNextSpan(&x0, &x1)) {
- if (clipRes == splashClipAllInside) {
- drawSpan(&pipe, x0, x1, y, true);
- } 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;
-
- return splashOk;
-}
-
-bool 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, bool eo) {
- SplashPipe pipe;
- int xMinI, yMinI, xMaxI, yMaxI, x0, x1, y;
- SplashClipResult clipRes, clipRes2;
- SplashBlendFunc origBlendFunc;
-
- if (path->length == 0) {
- return splashErrEmptyPath;
- }
- SplashXPath xPath(path, state->matrix, state->flatness, true);
- xPath.sort();
- SplashXPathScanner scanner(&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, nullptr, 255, false, false);
-
- // draw the spans
- for (y = yMinI; y <= yMaxI; ++y) {
- SplashXPathScanIterator iterator(scanner, y);
- while (iterator.getNextSpan(&x0, &x1)) {
- if (clipRes == splashClipAllInside) {
- drawSpan(&pipe, x0, x1, y, true);
- } 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;
-
- 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, bool noClip) {
- SplashPipe pipe;
- int alpha0;
- unsigned char alpha;
- unsigned char *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, nullptr, (unsigned char)splashRound(state->fillAlpha * 255), true, false);
- 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);
- } else {
- pipeIncX(&pipe);
- }
- }
- p += glyph->w;
- }
- } else {
- const int widthEight = splashCeil(glyph->w / 8.0);
-
- pipeInit(&pipe, xStart, yStart,
- state->fillPattern, nullptr, (unsigned char)splashRound(state->fillAlpha * 255), false, false);
- 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 && xx < xxLimit - 8 ? (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);
- } else {
- pipeIncX(&pipe);
- }
- alpha0 <<= 1;
- }
- }
- p += widthEight;
- }
- }
- } else {
- if (glyph->aa) {
- pipeInit(&pipe, xStart, yStart,
- state->fillPattern, nullptr, (unsigned char)splashRound(state->fillAlpha * 255), true, false);
- 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);
- } else {
- pipeIncX(&pipe);
- }
- } else {
- pipeIncX(&pipe);
- }
+ 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;
+ return splashOk;
}
- p += glyph->w;
- }
- } else {
- const int widthEight = splashCeil(glyph->w / 8.0);
-
- pipeInit(&pipe, xStart, yStart,
- state->fillPattern, nullptr, (unsigned char)splashRound(state->fillAlpha * 255), false, false);
- 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 && xx < xxLimit - 8 ? (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);
- } else {
- pipeIncX(&pipe);
- }
- } else {
- pipeIncX(&pipe);
+ }
+
+ // check clipping
+ if ((clipRes = state->clip->testRect(xMinI, yMinI, xMaxI, yMaxI)) != splashClipAllOutside) {
+ if (scanner.hasPartialClip()) {
+ clipRes = splashClipPartial;
+ }
+
+ pipeInit(&pipe, 0, yMinI, pattern, nullptr, (unsigned char)splashRound(alpha * 255), vectorAntialias && !inShading, false);
+
+ // 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);
+ }
+ unsigned char lineShape = 255;
+ bool doAdjustLine = false;
+ 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);
+ doAdjustLine = true;
+ lineShape = clip255((delta - mx) * 255);
+ }
+ drawAALine(&pipe, x0, x1, y, doAdjustLine, lineShape);
+ }
+ } else {
+ for (y = yMinI; y <= yMaxI; ++y) {
+ SplashXPathScanIterator iterator(scanner, y);
+ while (iterator.getNextSpan(&x0, &x1)) {
+ if (clipRes == splashClipAllInside) {
+ drawSpan(&pipe, x0, x1, y, true);
+ } 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);
+ }
+ }
}
- alpha0 <<= 1;
- }
}
- p += widthEight;
- }
}
- }
-}
+ opClipRes = clipRes;
-SplashError Splash::fillImageMask(SplashImageMaskSource src, void *srcData,
- int w, int h, SplashCoord *mat,
- bool glyphMode) {
- SplashBitmap *scaledMask;
- SplashClipResult clipRes;
- bool minorAxisZero;
- int x0, y0, x1, y1, scaledWidth, scaledHeight;
- int yp;
+ return splashOk;
+}
- 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]);
- }
+bool 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;
+ }
+ }
- if (w == 0 && h == 0) return splashErrZeroImage;
+ 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);
- // check for singular matrix
- if (!splashCheckDet(mat[0], mat[1], mat[2], mat[3], 0.000001)) {
- return splashErrSingularMatrix;
- }
+ return state->clip->testRect(xMinI, yMinI, xMaxI, yMaxI) == splashClipAllOutside;
+}
- minorAxisZero = mat[1] == 0 && mat[2] == 0;
+SplashError Splash::xorFill(SplashPath *path, bool eo)
+{
+ SplashPipe pipe;
+ int xMinI, yMinI, xMaxI, yMaxI, x0, x1, y;
+ SplashClipResult clipRes, clipRes2;
+ SplashBlendFunc origBlendFunc;
- // 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 (path->length == 0) {
+ return splashErrEmptyPath;
}
- if (y0 == y1) {
- ++y1;
+ SplashXPath xPath(path, state->matrix, state->flatness, true);
+ xPath.sort();
+ SplashXPathScanner scanner(&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, nullptr, 255, false, false);
+
+ // draw the spans
+ for (y = yMinI; y <= yMaxI; ++y) {
+ SplashXPathScanIterator iterator(scanner, y);
+ while (iterator.getNextSpan(&x0, &x1)) {
+ if (clipRes == splashClipAllInside) {
+ drawSpan(&pipe, x0, x1, y, true);
+ } 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;
}
- 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;
+
+ 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 (y0 == y1) {
- ++y1;
+ if (clipRes != splashClipAllOutside) {
+ fillGlyph2(x0, y0, &glyph, clipRes == splashClipAllInside);
}
- clipRes = state->clip->testRect(x0, y0, x1 - 1, y1 - 1);
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) {
- 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, bool 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 == nullptr) {
- 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, nullptr,
- (unsigned char)splashRound(state->fillAlpha * 255), true, false);
- 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 (unlikely(xx < 0)) {
- xx = 0;
- clipRes2 = splashClipPartial;
- } else if (unlikely(xx >= scaledWidth)) {
- xx = scaledWidth - 1;
- clipRes2 = splashClipPartial;
- }
- if (unlikely(yy < 0)) {
- yy = 0;
- clipRes2 = splashClipPartial;
- } else if (unlikely(yy >= scaledHeight)) {
- yy = scaledHeight - 1;
- clipRes2 = splashClipPartial;
- }
- pipe.shape = scaledMask->data[yy * scaledWidth + xx];
- if (vectorAntialias && clipRes2 != splashClipAllInside) {
- drawAAPixel(&pipe, x, y);
- } else {
- drawPixel(&pipe, x, y, clipRes2 == splashClipAllInside);
- }
- }
- }
- }
-
- delete scaledMask;
+ fillGlyph2(x0, y0, glyph, clipRes == splashClipAllInside);
+ }
+ opClipRes = clipRes;
}
-// 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,
- false);
- if (scaledHeight < srcHeight) {
- if (scaledWidth < srcWidth) {
- scaleMaskYdXd(src, srcData, srcWidth, srcHeight,
- scaledWidth, scaledHeight, dest);
- } else {
- scaleMaskYdXu(src, srcData, srcWidth, srcHeight,
- scaledWidth, scaledHeight, dest);
+void Splash::fillGlyph2(int x0, int y0, SplashGlyphBitmap *glyph, bool noClip)
+{
+ SplashPipe pipe;
+ int alpha0;
+ unsigned char alpha;
+ unsigned char *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;
}
- } 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) {
- unsigned char *lineBuf;
- unsigned int *pixBuf;
- unsigned int pix;
- unsigned char *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 = (unsigned char *)gmalloc(srcWidth);
- pixBuf = (unsigned int *)gmallocn_checkoverflow(srcWidth, sizeof(int));
- if (unlikely(!pixBuf)) {
- error(errInternal, -1, "Couldn't allocate memory for pixBux in Splash::scaleMaskYdXd");
- gfree(lineBuf);
- return;
- }
-
- // 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++ = (unsigned char)pix;
- }
- }
-
- gfree(pixBuf);
- gfree(lineBuf);
-}
-
-void Splash::scaleMaskYdXu(SplashImageMaskSource src, void *srcData,
- int srcWidth, int srcHeight,
- int scaledWidth, int scaledHeight,
- SplashBitmap *dest) {
- unsigned char *lineBuf;
- unsigned int *pixBuf;
- unsigned int pix;
- unsigned char *destPtr;
- int yp, yq, xp, xq, yt, y, yStep, xt, x, xStep, d;
- int i, j;
-
- destPtr = dest->data;
- if (destPtr == nullptr) {
- 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 = (unsigned char *)gmalloc(srcWidth);
- pixBuf = (unsigned int *)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++ = (unsigned char)pix;
- }
- }
- }
-
- gfree(pixBuf);
- gfree(lineBuf);
-}
-
-void Splash::scaleMaskYuXd(SplashImageMaskSource src, void *srcData,
- int srcWidth, int srcHeight,
- int scaledWidth, int scaledHeight,
- SplashBitmap *dest) {
- unsigned char *lineBuf;
- unsigned int pix;
- unsigned char *destPtr0, *destPtr;
- int yp, yq, xp, xq, yt, y, yStep, xt, x, xStep, xx, d, d0, d1;
- int i;
-
- destPtr0 = dest->data;
- if (destPtr0 == nullptr) {
- 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 = (unsigned char *)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 = (unsigned char)pix;
- }
- }
-
- destPtr0 += yStep * scaledWidth;
- }
-
- gfree(lineBuf);
-}
-
-void Splash::scaleMaskYuXu(SplashImageMaskSource src, void *srcData,
- int srcWidth, int srcHeight,
- int scaledWidth, int scaledHeight,
- SplashBitmap *dest) {
- unsigned char *lineBuf;
- unsigned int pix;
- unsigned char *destPtr0, *destPtr;
- int yp, yq, xp, xq, yt, y, yStep, xt, x, xStep, xx;
- int i, j;
-
- destPtr0 = dest->data;
- if (destPtr0 == nullptr) {
- error(errInternal, -1, "dest->data is NULL in Splash::scaleMaskYuXu");
- return;
- }
-
- if (unlikely(srcWidth <= 0 || srcHeight <= 0)) {
- error(errSyntaxError, -1, "srcWidth <= 0 || srcHeight <= 0 in Splash::scaleMaskYuXu");
- gfree(dest->takeData());
- 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 = (unsigned char *)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;
+
+ 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, nullptr, (unsigned char)splashRound(state->fillAlpha * 255), true, false);
+ 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);
+ } else {
+ pipeIncX(&pipe);
+ }
+ }
+ p += glyph->w;
+ }
+ } else {
+ const int widthEight = splashCeil(glyph->w / 8.0);
+
+ pipeInit(&pipe, xStart, yStart, state->fillPattern, nullptr, (unsigned char)splashRound(state->fillAlpha * 255), false, false);
+ 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 && xx < xxLimit - 8 ? (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);
+ } else {
+ pipeIncX(&pipe);
+ }
+ alpha0 <<= 1;
+ }
+ }
+ p += widthEight;
+ }
+ }
} 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++ = (unsigned char)pix;
- }
- }
-
- xx += xStep;
- }
-
- destPtr0 += yStep * scaledWidth;
- }
-
- gfree(lineBuf);
-}
-
-void Splash::blitMask(SplashBitmap *src, int xDest, int yDest,
- SplashClipResult clipRes) {
- SplashPipe pipe;
- unsigned char *p;
- int w, h, x, y;
-
- w = src->getWidth();
- h = src->getHeight();
- p = src->getDataPtr();
- if (p == nullptr) {
- error(errInternal, -1, "src->getDataPtr() is NULL in Splash::blitMask");
- return;
- }
- if (vectorAntialias && clipRes != splashClipAllInside) {
- pipeInit(&pipe, xDest, yDest, state->fillPattern, nullptr,
- (unsigned char)splashRound(state->fillAlpha * 255), true, false);
- 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, nullptr,
- (unsigned char)splashRound(state->fillAlpha * 255), true, false);
- 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;
- }
- }
+ if (glyph->aa) {
+ pipeInit(&pipe, xStart, yStart, state->fillPattern, nullptr, (unsigned char)splashRound(state->fillAlpha * 255), true, false);
+ 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);
+ } else {
+ pipeIncX(&pipe);
+ }
+ } else {
+ pipeIncX(&pipe);
+ }
+ }
+ p += glyph->w;
+ }
+ } else {
+ const int widthEight = splashCeil(glyph->w / 8.0);
+
+ pipeInit(&pipe, xStart, yStart, state->fillPattern, nullptr, (unsigned char)splashRound(state->fillAlpha * 255), false, false);
+ 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 && xx < xxLimit - 8 ? (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);
+ } else {
+ pipeIncX(&pipe);
+ }
+ } else {
+ pipeIncX(&pipe);
+ }
+ alpha0 <<= 1;
+ }
+ }
+ p += widthEight;
+ }
+ }
+ }
+}
+
+SplashError Splash::fillImageMask(SplashImageMaskSource src, void *srcData, int w, int h, SplashCoord *mat, bool glyphMode)
+{
+ SplashBitmap *scaledMask;
+ SplashClipResult clipRes;
+ bool 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 {
- 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);
- } else {
- pipeIncX(&pipe);
- }
- ++p;
- }
- }
- }
- }
-}
-
-SplashError Splash::drawImage(SplashImageSource src, SplashICCTransform tf, void *srcData,
- SplashColorMode srcMode, bool srcAlpha,
- int w, int h, SplashCoord *mat, bool interpolate,
- bool tilingPattern) {
- bool ok;
- SplashBitmap *scaledImg;
- SplashClipResult clipRes;
- bool 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 = false; // 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;
- case splashModeCMYK8:
- ok = srcMode == splashModeCMYK8;
- nComps = 4;
- break;
- case splashModeDeviceN8:
- ok = srcMode == splashModeDeviceN8;
- nComps = SPOT_NCOMPS+4;
- break;
- default:
- ok = false;
- 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;
+ arbitraryTransformMask(src, srcData, w, h, mat, glyphMode);
}
- if (y0 == y1) {
- ++y1;
+
+ return splashOk;
+}
+
+void Splash::arbitraryTransformMask(SplashImageMaskSource src, void *srcData, int srcWidth, int srcHeight, SplashCoord *mat, bool 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(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 == nullptr) {
- return splashErrBadArg;
- }
- if (tf != nullptr) {
- (*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);
+ clipRes = state->clip->testRect(xMin, yMin, xMax - 1, yMax - 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 == nullptr) {
- return splashErrBadArg;
- }
- if (tf != nullptr) {
- (*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,
- bool srcAlpha,
- int srcWidth, int srcHeight,
- SplashCoord *mat, bool interpolate,
- bool 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 (clipRes == splashClipAllOutside) {
+ return;
+ }
+
+ // compute the scale factors
if (mat[0] >= 0) {
- t0 = imgCoordMungeUpper(mat[0] + mat[4]) - imgCoordMungeLower(mat[4]);
+ t0 = imgCoordMungeUpperC(mat[0] + mat[4], glyphMode) - imgCoordMungeLowerC(mat[4], glyphMode);
} else {
- t0 = imgCoordMungeUpper(mat[4]) - imgCoordMungeLower(mat[0] + mat[4]);
+ t0 = imgCoordMungeUpperC(mat[4], glyphMode) - imgCoordMungeLowerC(mat[0] + mat[4], glyphMode);
}
if (mat[1] >= 0) {
- t1 = imgCoordMungeUpper(mat[1] + mat[5]) - imgCoordMungeLower(mat[5]);
+ t1 = imgCoordMungeUpperC(mat[1] + mat[5], glyphMode) - imgCoordMungeLowerC(mat[5], glyphMode);
} else {
- t1 = imgCoordMungeUpper(mat[5]) - imgCoordMungeLower(mat[1] + mat[5]);
+ t1 = imgCoordMungeUpperC(mat[5], glyphMode) - imgCoordMungeLowerC(mat[1] + mat[5], glyphMode);
}
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;
- }
+ t0 = imgCoordMungeUpperC(mat[2] + mat[4], glyphMode) - imgCoordMungeLowerC(mat[4], glyphMode);
} 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;
- }
+ t0 = imgCoordMungeUpperC(mat[4], glyphMode) - imgCoordMungeLowerC(mat[2] + mat[4], glyphMode);
}
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;
- }
+ t1 = imgCoordMungeUpperC(mat[3] + mat[5], glyphMode) - imgCoordMungeLowerC(mat[5], glyphMode);
} 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;
- }
+ 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 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 == nullptr) {
- return splashErrBadArg;
- }
-
- if (tf != nullptr) {
- (*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;
+ 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 == nullptr) {
+ 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].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;
+ 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, nullptr, (unsigned char)splashRound(state->fillAlpha * 255), true, false);
+ 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 {
- 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;
- }
+ 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 (unlikely(xx < 0)) {
+ xx = 0;
+ clipRes2 = splashClipPartial;
+ } else if (unlikely(xx >= scaledWidth)) {
+ xx = scaledWidth - 1;
+ clipRes2 = splashClipPartial;
+ }
+ if (unlikely(yy < 0)) {
+ yy = 0;
+ clipRes2 = splashClipPartial;
+ } else if (unlikely(yy >= scaledHeight)) {
+ yy = scaledHeight - 1;
+ clipRes2 = splashClipPartial;
+ }
+ 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, false);
+ if (scaledHeight < srcHeight) {
+ if (scaledWidth < srcWidth) {
+ scaleMaskYdXd(src, srcData, srcWidth, srcHeight, scaledWidth, scaledHeight, dest);
+ } else {
+ scaleMaskYdXu(src, srcData, srcWidth, srcHeight, scaledWidth, scaledHeight, dest);
+ }
} 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, nullptr, pixel,
- (unsigned char)splashRound(state->fillAlpha * 255),
- srcAlpha || (vectorAntialias && clipRes != splashClipAllInside),
- false);
- 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;
+ 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)
+{
+ unsigned char *lineBuf;
+ unsigned int *pixBuf;
+ unsigned int pix;
+ unsigned char *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 = (unsigned char *)gmalloc(srcWidth);
+ pixBuf = (unsigned int *)gmallocn_checkoverflow(srcWidth, sizeof(int));
+ if (unlikely(!pixBuf)) {
+ error(errInternal, -1, "Couldn't allocate memory for pixBux in Splash::scaleMaskYdXd");
+ gfree(lineBuf);
+ return;
+ }
+
+ // 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++ = (unsigned char)pix;
+ }
+ }
+
+ gfree(pixBuf);
+ gfree(lineBuf);
+}
+
+void Splash::scaleMaskYdXu(SplashImageMaskSource src, void *srcData, int srcWidth, int srcHeight, int scaledWidth, int scaledHeight, SplashBitmap *dest)
+{
+ unsigned char *lineBuf;
+ unsigned int *pixBuf;
+ unsigned int pix;
+ unsigned char *destPtr;
+ int yp, yq, xp, xq, yt, y, yStep, xt, x, xStep, d;
+ int i, j;
+
+ destPtr = dest->data;
+ if (destPtr == nullptr) {
+ 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 = (unsigned char *)gmalloc(srcWidth);
+ pixBuf = (unsigned int *)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++ = (unsigned char)pix;
+ }
+ }
+ }
+
+ gfree(pixBuf);
+ gfree(lineBuf);
+}
+
+void Splash::scaleMaskYuXd(SplashImageMaskSource src, void *srcData, int srcWidth, int srcHeight, int scaledWidth, int scaledHeight, SplashBitmap *dest)
+{
+ unsigned char *lineBuf;
+ unsigned int pix;
+ unsigned char *destPtr0, *destPtr;
+ int yp, yq, xp, xq, yt, y, yStep, xt, x, xStep, xx, d, d0, d1;
+ int i;
+
+ destPtr0 = dest->data;
+ if (destPtr0 == nullptr) {
+ 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 = (unsigned char *)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 = (unsigned char)pix;
+ }
+ }
+
+ destPtr0 += yStep * scaledWidth;
+ }
+
+ gfree(lineBuf);
+}
+
+void Splash::scaleMaskYuXu(SplashImageMaskSource src, void *srcData, int srcWidth, int srcHeight, int scaledWidth, int scaledHeight, SplashBitmap *dest)
+{
+ unsigned char *lineBuf;
+ unsigned int pix;
+ unsigned char *destPtr0, *destPtr;
+ int yp, yq, xp, xq, yt, y, yStep, xt, x, xStep, xx;
+ int i, j;
+
+ destPtr0 = dest->data;
+ if (destPtr0 == nullptr) {
+ error(errInternal, -1, "dest->data is NULL in Splash::scaleMaskYuXu");
+ return;
+ }
+
+ if (unlikely(srcWidth <= 0 || srcHeight <= 0)) {
+ error(errSyntaxError, -1, "srcWidth <= 0 || srcHeight <= 0 in Splash::scaleMaskYuXu");
+ gfree(dest->takeData());
+ 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 = (unsigned char *)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++ = (unsigned char)pix;
+ }
+ }
+
+ xx += xStep;
+ }
+
+ destPtr0 += yStep * scaledWidth;
+ }
+
+ gfree(lineBuf);
+}
+
+void Splash::blitMask(SplashBitmap *src, int xDest, int yDest, SplashClipResult clipRes)
+{
+ SplashPipe pipe;
+ unsigned char *p;
+ int w, h, x, y;
+
+ w = src->getWidth();
+ h = src->getHeight();
+ p = src->getDataPtr();
+ if (p == nullptr) {
+ error(errInternal, -1, "src->getDataPtr() is NULL in Splash::blitMask");
+ return;
+ }
+ if (vectorAntialias && clipRes != splashClipAllInside) {
+ pipeInit(&pipe, xDest, yDest, state->fillPattern, nullptr, (unsigned char)splashRound(state->fillAlpha * 255), true, false);
+ 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, nullptr, (unsigned char)splashRound(state->fillAlpha * 255), true, false);
+ 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;
+ }
+ }
+ } 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);
+ } else {
+ pipeIncX(&pipe);
+ }
+ ++p;
+ }
+ }
+ }
+ }
+}
+
+SplashError Splash::drawImage(SplashImageSource src, SplashICCTransform tf, void *srcData, SplashColorMode srcMode, bool srcAlpha, int w, int h, SplashCoord *mat, bool interpolate, bool tilingPattern)
+{
+ bool ok;
+ SplashBitmap *scaledImg;
+ SplashClipResult clipRes;
+ bool 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 = false; // 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;
+ case splashModeCMYK8:
+ ok = srcMode == splashModeCMYK8;
+ nComps = 4;
+ break;
+ case splashModeDeviceN8:
+ ok = srcMode == splashModeDeviceN8;
+ nComps = SPOT_NCOMPS + 4;
+ break;
+ default:
+ ok = false;
+ 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 == nullptr) {
+ return splashErrBadArg;
+ }
+ if (tf != nullptr) {
+ (*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 == nullptr) {
+ return splashErrBadArg;
+ }
+ if (tf != nullptr) {
+ (*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, bool srcAlpha, int srcWidth, int srcHeight, SplashCoord *mat, bool interpolate,
+ bool 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 == nullptr) {
+ return splashErrBadArg;
+ }
+
+ if (tf != nullptr) {
+ (*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, nullptr, pixel, (unsigned char)splashRound(state->fillAlpha * 255), srcAlpha || (vectorAntialias && clipRes != splashClipAllInside), false);
+ 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 bool isImageInterpolationRequired(int srcWidth, int srcHeight,
- int scaledWidth, int scaledHeight,
- bool interpolate) {
- if (interpolate || srcWidth == 0 || srcHeight == 0)
- return true;
+static bool isImageInterpolationRequired(int srcWidth, int srcHeight, int scaledWidth, int scaledHeight, bool interpolate)
+{
+ if (interpolate || srcWidth == 0 || srcHeight == 0)
+ return true;
- /* When scale factor is >= 400% we don't interpolate. See bugs #25268, #9860 */
- if (scaledWidth / srcWidth >= 4 || scaledHeight / srcHeight >= 4)
- return false;
+ /* When scale factor is >= 400% we don't interpolate. See bugs #25268, #9860 */
+ if (scaledWidth / srcWidth >= 4 || scaledHeight / srcHeight >= 4)
+ return false;
- return true;
+ return true;
}
// Scale an image into a SplashBitmap.
-SplashBitmap *Splash::scaleImage(SplashImageSource src, void *srcData,
- SplashColorMode srcMode, int nComps,
- bool srcAlpha, int srcWidth, int srcHeight,
- int scaledWidth, int scaledHeight, bool interpolate, bool tilingPattern) {
- SplashBitmap *dest;
-
- dest = new SplashBitmap(scaledWidth, scaledHeight, 1, srcMode, srcAlpha, true, bitmap->getSeparationList());
- if (dest->getDataPtr() != nullptr && 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 = nullptr;
- }
- return dest;
-}
-
-void Splash::scaleImageYdXd(SplashImageSource src, void *srcData,
- SplashColorMode srcMode, int nComps,
- bool srcAlpha, int srcWidth, int srcHeight,
- int scaledWidth, int scaledHeight,
- SplashBitmap *dest) {
- unsigned char *lineBuf, *alphaLineBuf;
- unsigned int *pixBuf, *alphaPixBuf;
- unsigned int pix0, pix1, pix2;
- unsigned int pix3;
- unsigned int pix[SPOT_NCOMPS+4], cp;
- unsigned int alpha;
- unsigned char *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 = (unsigned char *)gmallocn_checkoverflow(srcWidth, nComps);
- if (unlikely(!lineBuf)) {
- return;
- }
- pixBuf = (unsigned int *)gmallocn_checkoverflow(srcWidth, nComps * sizeof(int));
- if (unlikely(!pixBuf)) {
- gfree(lineBuf);
- return;
- }
- if (srcAlpha) {
- alphaLineBuf = (unsigned char *)gmalloc(srcWidth);
- alphaPixBuf = (unsigned int *)gmallocn(srcWidth, sizeof(int));
- } else {
- alphaLineBuf = nullptr;
- alphaPixBuf = nullptr;
- }
-
- // 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;
+SplashBitmap *Splash::scaleImage(SplashImageSource src, void *srcData, SplashColorMode srcMode, int nComps, bool srcAlpha, int srcWidth, int srcHeight, int scaledWidth, int scaledHeight, bool interpolate, bool tilingPattern)
+{
+ SplashBitmap *dest;
+
+ dest = new SplashBitmap(scaledWidth, scaledHeight, 1, srcMode, srcAlpha, true, bitmap->getSeparationList());
+ if (dest->getDataPtr() != nullptr && 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 {
- yStep = yp;
+ delete dest;
+ dest = nullptr;
}
+ return dest;
+}
- // read rows from image
- memset(pixBuf, 0, srcWidth * nComps * sizeof(int));
+void Splash::scaleImageYdXd(SplashImageSource src, void *srcData, SplashColorMode srcMode, int nComps, bool srcAlpha, int srcWidth, int srcHeight, int scaledWidth, int scaledHeight, SplashBitmap *dest)
+{
+ unsigned char *lineBuf, *alphaLineBuf;
+ unsigned int *pixBuf, *alphaPixBuf;
+ unsigned int pix0, pix1, pix2;
+ unsigned int pix3;
+ unsigned int pix[SPOT_NCOMPS + 4], cp;
+ unsigned int alpha;
+ unsigned char *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 = (unsigned char *)gmallocn_checkoverflow(srcWidth, nComps);
+ if (unlikely(!lineBuf)) {
+ return;
+ }
+ pixBuf = (unsigned int *)gmallocn_checkoverflow(srcWidth, nComps * sizeof(int));
+ if (unlikely(!pixBuf)) {
+ gfree(lineBuf);
+ return;
+ }
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++ = (unsigned char)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++ = (unsigned char)pix0;
- *destPtr++ = (unsigned char)pix1;
- *destPtr++ = (unsigned char)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++ = (unsigned char)pix2;
- *destPtr++ = (unsigned char)pix1;
- *destPtr++ = (unsigned char)pix0;
- *destPtr++ = (unsigned char)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++ = (unsigned char)pix2;
- *destPtr++ = (unsigned char)pix1;
- *destPtr++ = (unsigned char)pix0;
- break;
-
- 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++ = (unsigned char)pix0;
- *destPtr++ = (unsigned char)pix1;
- *destPtr++ = (unsigned char)pix2;
- *destPtr++ = (unsigned char)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++ = (unsigned char)pix[cp];
- break;
-
-
- 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++ = (unsigned char)alpha;
- }
- }
- }
-
- gfree(alphaPixBuf);
- gfree(alphaLineBuf);
- gfree(pixBuf);
- gfree(lineBuf);
-}
-
-void Splash::scaleImageYdXu(SplashImageSource src, void *srcData,
- SplashColorMode srcMode, int nComps,
- bool srcAlpha, int srcWidth, int srcHeight,
- int scaledWidth, int scaledHeight,
- SplashBitmap *dest) {
- unsigned char *lineBuf, *alphaLineBuf;
- unsigned int *pixBuf, *alphaPixBuf;
- unsigned int pix[splashMaxColorComps];
- unsigned int alpha;
- unsigned char *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
- pixBuf = (unsigned int *)gmallocn_checkoverflow(srcWidth, nComps * sizeof(int));
- if (unlikely(!pixBuf)) {
- error(errInternal, -1, "Splash::scaleImageYdXu. Couldn't allocate pixBuf memory");
- return;
- }
- lineBuf = (unsigned char *)gmallocn(srcWidth, nComps);
- if (srcAlpha) {
- alphaLineBuf = (unsigned char *)gmalloc(srcWidth);
- alphaPixBuf = (unsigned int *)gmallocn(srcWidth, sizeof(int));
- } else {
- alphaLineBuf = nullptr;
- alphaPixBuf = nullptr;
- }
-
- // 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;
+ alphaLineBuf = (unsigned char *)gmalloc(srcWidth);
+ alphaPixBuf = (unsigned int *)gmallocn(srcWidth, sizeof(int));
} else {
- yStep = yp;
+ alphaLineBuf = nullptr;
+ alphaPixBuf = nullptr;
+ }
+
+ // 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++ = (unsigned char)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++ = (unsigned char)pix0;
+ *destPtr++ = (unsigned char)pix1;
+ *destPtr++ = (unsigned char)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++ = (unsigned char)pix2;
+ *destPtr++ = (unsigned char)pix1;
+ *destPtr++ = (unsigned char)pix0;
+ *destPtr++ = (unsigned char)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++ = (unsigned char)pix2;
+ *destPtr++ = (unsigned char)pix1;
+ *destPtr++ = (unsigned char)pix0;
+ break;
+
+ 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++ = (unsigned char)pix0;
+ *destPtr++ = (unsigned char)pix1;
+ *destPtr++ = (unsigned char)pix2;
+ *destPtr++ = (unsigned char)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++ = (unsigned char)pix[cp];
+ break;
+
+ 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++ = (unsigned char)alpha;
+ }
+ }
}
- // read rows from image
- memset(pixBuf, 0, srcWidth * nComps * sizeof(int));
+ gfree(alphaPixBuf);
+ gfree(alphaLineBuf);
+ gfree(pixBuf);
+ gfree(lineBuf);
+}
+
+void Splash::scaleImageYdXu(SplashImageSource src, void *srcData, SplashColorMode srcMode, int nComps, bool srcAlpha, int srcWidth, int srcHeight, int scaledWidth, int scaledHeight, SplashBitmap *dest)
+{
+ unsigned char *lineBuf, *alphaLineBuf;
+ unsigned int *pixBuf, *alphaPixBuf;
+ unsigned int pix[splashMaxColorComps];
+ unsigned int alpha;
+ unsigned char *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
+ pixBuf = (unsigned int *)gmallocn_checkoverflow(srcWidth, nComps * sizeof(int));
+ if (unlikely(!pixBuf)) {
+ error(errInternal, -1, "Splash::scaleImageYdXu. Couldn't allocate pixBuf memory");
+ return;
+ }
+ lineBuf = (unsigned char *)gmallocn(srcWidth, nComps);
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++ = (unsigned char)pix[0];
- }
- break;
- case splashModeRGB8:
- for (i = 0; i < xStep; ++i) {
- *destPtr++ = (unsigned char)pix[0];
- *destPtr++ = (unsigned char)pix[1];
- *destPtr++ = (unsigned char)pix[2];
- }
- break;
- case splashModeXBGR8:
- for (i = 0; i < xStep; ++i) {
- *destPtr++ = (unsigned char)pix[2];
- *destPtr++ = (unsigned char)pix[1];
- *destPtr++ = (unsigned char)pix[0];
- *destPtr++ = (unsigned char)255;
- }
- break;
- case splashModeBGR8:
- for (i = 0; i < xStep; ++i) {
- *destPtr++ = (unsigned char)pix[2];
- *destPtr++ = (unsigned char)pix[1];
- *destPtr++ = (unsigned char)pix[0];
- }
- break;
- case splashModeCMYK8:
- for (i = 0; i < xStep; ++i) {
- *destPtr++ = (unsigned char)pix[0];
- *destPtr++ = (unsigned char)pix[1];
- *destPtr++ = (unsigned char)pix[2];
- *destPtr++ = (unsigned char)pix[3];
- }
- break;
- case splashModeDeviceN8:
- for (i = 0; i < xStep; ++i) {
- for (unsigned int cp : pix)
- *destPtr++ = (unsigned char)cp;
- }
- break;
- }
-
- // process alpha
- if (srcAlpha) {
- // alphaPixBuf[] / yStep
- alpha = (alphaPixBuf[x] * d) >> 23;
- for (i = 0; i < xStep; ++i) {
- *destAlphaPtr++ = (unsigned char)alpha;
- }
- }
- }
- }
-
- gfree(alphaPixBuf);
- gfree(alphaLineBuf);
- gfree(pixBuf);
- gfree(lineBuf);
-}
-
-void Splash::scaleImageYuXd(SplashImageSource src, void *srcData,
- SplashColorMode srcMode, int nComps,
- bool srcAlpha, int srcWidth, int srcHeight,
- int scaledWidth, int scaledHeight,
- SplashBitmap *dest) {
- unsigned char *lineBuf, *alphaLineBuf;
- unsigned int pix[splashMaxColorComps];
- unsigned int alpha;
- unsigned char *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 = (unsigned char *)gmallocn_checkoverflow(srcWidth, nComps);
- if (unlikely(!lineBuf)) {
- gfree(dest->takeData());
- return;
- }
- if (srcAlpha) {
- alphaLineBuf = (unsigned char *)gmalloc(srcWidth);
- } else {
- alphaLineBuf = nullptr;
- }
-
- // 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;
+ alphaLineBuf = (unsigned char *)gmalloc(srcWidth);
+ alphaPixBuf = (unsigned int *)gmallocn(srcWidth, sizeof(int));
} 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++ = (unsigned char)pix[0];
- }
- break;
- case splashModeRGB8:
- for (i = 0; i < yStep; ++i) {
- destPtr = destPtr0 + (i * scaledWidth + x) * nComps;
- *destPtr++ = (unsigned char)pix[0];
- *destPtr++ = (unsigned char)pix[1];
- *destPtr++ = (unsigned char)pix[2];
- }
- break;
- case splashModeXBGR8:
- for (i = 0; i < yStep; ++i) {
- destPtr = destPtr0 + (i * scaledWidth + x) * nComps;
- *destPtr++ = (unsigned char)pix[2];
- *destPtr++ = (unsigned char)pix[1];
- *destPtr++ = (unsigned char)pix[0];
- *destPtr++ = (unsigned char)255;
- }
- break;
- case splashModeBGR8:
- for (i = 0; i < yStep; ++i) {
- destPtr = destPtr0 + (i * scaledWidth + x) * nComps;
- *destPtr++ = (unsigned char)pix[2];
- *destPtr++ = (unsigned char)pix[1];
- *destPtr++ = (unsigned char)pix[0];
- }
- break;
- case splashModeCMYK8:
- for (i = 0; i < yStep; ++i) {
- destPtr = destPtr0 + (i * scaledWidth + x) * nComps;
- *destPtr++ = (unsigned char)pix[0];
- *destPtr++ = (unsigned char)pix[1];
- *destPtr++ = (unsigned char)pix[2];
- *destPtr++ = (unsigned char)pix[3];
- }
- break;
- case splashModeDeviceN8:
- for (i = 0; i < yStep; ++i) {
- destPtr = destPtr0 + (i * scaledWidth + x) * nComps;
- for (unsigned int cp : pix)
- *destPtr++ = (unsigned char)cp;
- }
- break;
- }
-
- // 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 = (unsigned char)alpha;
- }
- }
- }
-
- destPtr0 += yStep * scaledWidth * nComps;
+ alphaLineBuf = nullptr;
+ alphaPixBuf = nullptr;
+ }
+
+ // 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++ = (unsigned char)pix[0];
+ }
+ break;
+ case splashModeRGB8:
+ for (i = 0; i < xStep; ++i) {
+ *destPtr++ = (unsigned char)pix[0];
+ *destPtr++ = (unsigned char)pix[1];
+ *destPtr++ = (unsigned char)pix[2];
+ }
+ break;
+ case splashModeXBGR8:
+ for (i = 0; i < xStep; ++i) {
+ *destPtr++ = (unsigned char)pix[2];
+ *destPtr++ = (unsigned char)pix[1];
+ *destPtr++ = (unsigned char)pix[0];
+ *destPtr++ = (unsigned char)255;
+ }
+ break;
+ case splashModeBGR8:
+ for (i = 0; i < xStep; ++i) {
+ *destPtr++ = (unsigned char)pix[2];
+ *destPtr++ = (unsigned char)pix[1];
+ *destPtr++ = (unsigned char)pix[0];
+ }
+ break;
+ case splashModeCMYK8:
+ for (i = 0; i < xStep; ++i) {
+ *destPtr++ = (unsigned char)pix[0];
+ *destPtr++ = (unsigned char)pix[1];
+ *destPtr++ = (unsigned char)pix[2];
+ *destPtr++ = (unsigned char)pix[3];
+ }
+ break;
+ case splashModeDeviceN8:
+ for (i = 0; i < xStep; ++i) {
+ for (unsigned int cp : pix)
+ *destPtr++ = (unsigned char)cp;
+ }
+ break;
+ }
+
+ // process alpha
+ if (srcAlpha) {
+ // alphaPixBuf[] / yStep
+ alpha = (alphaPixBuf[x] * d) >> 23;
+ for (i = 0; i < xStep; ++i) {
+ *destAlphaPtr++ = (unsigned char)alpha;
+ }
+ }
+ }
+ }
+
+ gfree(alphaPixBuf);
+ gfree(alphaLineBuf);
+ gfree(pixBuf);
+ gfree(lineBuf);
+}
+
+void Splash::scaleImageYuXd(SplashImageSource src, void *srcData, SplashColorMode srcMode, int nComps, bool srcAlpha, int srcWidth, int srcHeight, int scaledWidth, int scaledHeight, SplashBitmap *dest)
+{
+ unsigned char *lineBuf, *alphaLineBuf;
+ unsigned int pix[splashMaxColorComps];
+ unsigned int alpha;
+ unsigned char *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 = (unsigned char *)gmallocn_checkoverflow(srcWidth, nComps);
+ if (unlikely(!lineBuf)) {
+ gfree(dest->takeData());
+ return;
+ }
if (srcAlpha) {
- destAlphaPtr0 += yStep * scaledWidth;
- }
- }
-
- gfree(alphaLineBuf);
- gfree(lineBuf);
-}
-
-void Splash::scaleImageYuXu(SplashImageSource src, void *srcData,
- SplashColorMode srcMode, int nComps,
- bool srcAlpha, int srcWidth, int srcHeight,
- int scaledWidth, int scaledHeight,
- SplashBitmap *dest) {
- unsigned char *lineBuf, *alphaLineBuf;
- unsigned int pix[splashMaxColorComps];
- unsigned int alpha;
- unsigned char *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 = (unsigned char *)gmallocn(srcWidth, nComps);
- if (srcAlpha) {
- alphaLineBuf = (unsigned char *)gmalloc(srcWidth);
- } else {
- alphaLineBuf = nullptr;
- }
-
- // 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;
+ alphaLineBuf = (unsigned char *)gmalloc(srcWidth);
} 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++ = (unsigned char)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++ = (unsigned char)pix[0];
- *destPtr++ = (unsigned char)pix[1];
- *destPtr++ = (unsigned char)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++ = (unsigned char)pix[2];
- *destPtr++ = (unsigned char)pix[1];
- *destPtr++ = (unsigned char)pix[0];
- *destPtr++ = (unsigned char)255;
- }
- }
- break;
- case splashModeBGR8:
- for (i = 0; i < yStep; ++i) {
- for (j = 0; j < xStep; ++j) {
- destPtr = destPtr0 + (i * scaledWidth + xx + j) * nComps;
- *destPtr++ = (unsigned char)pix[2];
- *destPtr++ = (unsigned char)pix[1];
- *destPtr++ = (unsigned char)pix[0];
- }
- }
- break;
- case splashModeCMYK8:
- for (i = 0; i < yStep; ++i) {
- for (j = 0; j < xStep; ++j) {
- destPtr = destPtr0 + (i * scaledWidth + xx + j) * nComps;
- *destPtr++ = (unsigned char)pix[0];
- *destPtr++ = (unsigned char)pix[1];
- *destPtr++ = (unsigned char)pix[2];
- *destPtr++ = (unsigned char)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 (unsigned int cp : pix)
- *destPtr++ = (unsigned char)cp;
- }
- }
- break;
- }
-
- // 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 = (unsigned char)alpha;
- }
- }
- }
-
- xx += xStep;
- }
-
- destPtr0 += yStep * scaledWidth * nComps;
+ alphaLineBuf = nullptr;
+ }
+
+ // 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++ = (unsigned char)pix[0];
+ }
+ break;
+ case splashModeRGB8:
+ for (i = 0; i < yStep; ++i) {
+ destPtr = destPtr0 + (i * scaledWidth + x) * nComps;
+ *destPtr++ = (unsigned char)pix[0];
+ *destPtr++ = (unsigned char)pix[1];
+ *destPtr++ = (unsigned char)pix[2];
+ }
+ break;
+ case splashModeXBGR8:
+ for (i = 0; i < yStep; ++i) {
+ destPtr = destPtr0 + (i * scaledWidth + x) * nComps;
+ *destPtr++ = (unsigned char)pix[2];
+ *destPtr++ = (unsigned char)pix[1];
+ *destPtr++ = (unsigned char)pix[0];
+ *destPtr++ = (unsigned char)255;
+ }
+ break;
+ case splashModeBGR8:
+ for (i = 0; i < yStep; ++i) {
+ destPtr = destPtr0 + (i * scaledWidth + x) * nComps;
+ *destPtr++ = (unsigned char)pix[2];
+ *destPtr++ = (unsigned char)pix[1];
+ *destPtr++ = (unsigned char)pix[0];
+ }
+ break;
+ case splashModeCMYK8:
+ for (i = 0; i < yStep; ++i) {
+ destPtr = destPtr0 + (i * scaledWidth + x) * nComps;
+ *destPtr++ = (unsigned char)pix[0];
+ *destPtr++ = (unsigned char)pix[1];
+ *destPtr++ = (unsigned char)pix[2];
+ *destPtr++ = (unsigned char)pix[3];
+ }
+ break;
+ case splashModeDeviceN8:
+ for (i = 0; i < yStep; ++i) {
+ destPtr = destPtr0 + (i * scaledWidth + x) * nComps;
+ for (unsigned int cp : pix)
+ *destPtr++ = (unsigned char)cp;
+ }
+ break;
+ }
+
+ // 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 = (unsigned char)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, bool srcAlpha, int srcWidth, int srcHeight, int scaledWidth, int scaledHeight, SplashBitmap *dest)
+{
+ unsigned char *lineBuf, *alphaLineBuf;
+ unsigned int pix[splashMaxColorComps];
+ unsigned int alpha;
+ unsigned char *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 = (unsigned char *)gmallocn(srcWidth, nComps);
if (srcAlpha) {
- destAlphaPtr0 += yStep * scaledWidth;
+ alphaLineBuf = (unsigned char *)gmalloc(srcWidth);
+ } else {
+ alphaLineBuf = nullptr;
}
- }
- gfree(alphaLineBuf);
- gfree(lineBuf);
+ // 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++ = (unsigned char)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++ = (unsigned char)pix[0];
+ *destPtr++ = (unsigned char)pix[1];
+ *destPtr++ = (unsigned char)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++ = (unsigned char)pix[2];
+ *destPtr++ = (unsigned char)pix[1];
+ *destPtr++ = (unsigned char)pix[0];
+ *destPtr++ = (unsigned char)255;
+ }
+ }
+ break;
+ case splashModeBGR8:
+ for (i = 0; i < yStep; ++i) {
+ for (j = 0; j < xStep; ++j) {
+ destPtr = destPtr0 + (i * scaledWidth + xx + j) * nComps;
+ *destPtr++ = (unsigned char)pix[2];
+ *destPtr++ = (unsigned char)pix[1];
+ *destPtr++ = (unsigned char)pix[0];
+ }
+ }
+ break;
+ case splashModeCMYK8:
+ for (i = 0; i < yStep; ++i) {
+ for (j = 0; j < xStep; ++j) {
+ destPtr = destPtr0 + (i * scaledWidth + xx + j) * nComps;
+ *destPtr++ = (unsigned char)pix[0];
+ *destPtr++ = (unsigned char)pix[1];
+ *destPtr++ = (unsigned char)pix[2];
+ *destPtr++ = (unsigned char)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 (unsigned int cp : pix)
+ *destPtr++ = (unsigned char)cp;
+ }
+ }
+ break;
+ }
+
+ // 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 = (unsigned char)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(unsigned char *srcBuf, unsigned char *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;
+ 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;
}
- xSrc += xStep;
- }
}
// Scale up image using bilinear interpolation
-void Splash::scaleImageYuXuBilinear(SplashImageSource src, void *srcData,
- SplashColorMode srcMode, int nComps,
- bool srcAlpha, int srcWidth, int srcHeight,
- int scaledWidth, int scaledHeight,
- SplashBitmap *dest) {
- unsigned char *srcBuf, *lineBuf1, *lineBuf2, *alphaSrcBuf, *alphaLineBuf1, *alphaLineBuf2;
- unsigned int pix[splashMaxColorComps];
- unsigned char *destPtr0, *destPtr, *destAlphaPtr0, *destAlphaPtr;
- int i;
-
- if (srcWidth < 1 || srcHeight < 1)
- return;
-
- // allocate buffers
- srcBuf = (unsigned char *)gmallocn(srcWidth+1, nComps); // + 1 pixel of padding
- lineBuf1 = (unsigned char *)gmallocn(scaledWidth, nComps);
- lineBuf2 = (unsigned char *)gmallocn(scaledWidth, nComps);
- if (srcAlpha) {
- alphaSrcBuf = (unsigned char *)gmalloc(srcWidth+1); // + 1 pixel of padding
- alphaLineBuf1 = (unsigned char *)gmalloc(scaledWidth);
- alphaLineBuf2 = (unsigned char *)gmalloc(scaledWidth);
- } else {
- alphaSrcBuf = nullptr;
- alphaLineBuf1 = nullptr;
- alphaLineBuf2 = nullptr;
- }
-
- 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++ = (unsigned char)pix[0];
- break;
- case splashModeRGB8:
- *destPtr++ = (unsigned char)pix[0];
- *destPtr++ = (unsigned char)pix[1];
- *destPtr++ = (unsigned char)pix[2];
- break;
- case splashModeXBGR8:
- *destPtr++ = (unsigned char)pix[2];
- *destPtr++ = (unsigned char)pix[1];
- *destPtr++ = (unsigned char)pix[0];
- *destPtr++ = (unsigned char)255;
- break;
- case splashModeBGR8:
- *destPtr++ = (unsigned char)pix[2];
- *destPtr++ = (unsigned char)pix[1];
- *destPtr++ = (unsigned char)pix[0];
- break;
- case splashModeCMYK8:
- *destPtr++ = (unsigned char)pix[0];
- *destPtr++ = (unsigned char)pix[1];
- *destPtr++ = (unsigned char)pix[2];
- *destPtr++ = (unsigned char)pix[3];
- break;
- case splashModeDeviceN8:
- for (unsigned int cp : pix)
- *destPtr++ = (unsigned char)cp;
- break;
- }
-
- // 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) {
- unsigned char *lineBuf;
- unsigned char *p0, *p1;
- int w;
-
- if (unlikely(img->data == nullptr)) {
- error(errInternal, -1, "img->data is NULL in Splash::vertFlipImage");
- return;
- }
-
- w = width * nComps;
- lineBuf = (unsigned char *)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, bool 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, bool srcAlpha, int xDest, int yDest,
- SplashClipResult clipRes) {
- SplashPipe pipe;
- SplashColor pixel = {};
- unsigned char *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, nullptr, pixel,
- (unsigned char)splashRound(state->fillAlpha * 255), srcAlpha, false);
- 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);
- }
- }
- }
- }
-
- // 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, bool srcAlpha,
- int xSrc, int ySrc, int xDest, int yDest,
- int w, int h) {
- SplashPipe pipe;
- SplashColor pixel = {};
- unsigned char *ap;
- int x, y;
-
- if (vectorAntialias) {
- pipeInit(&pipe, xDest, yDest, nullptr, pixel,
- (unsigned char)splashRound(state->fillAlpha * 255), true, false);
- drawAAPixelInit();
+void Splash::scaleImageYuXuBilinear(SplashImageSource src, void *srcData, SplashColorMode srcMode, int nComps, bool srcAlpha, int srcWidth, int srcHeight, int scaledWidth, int scaledHeight, SplashBitmap *dest)
+{
+ unsigned char *srcBuf, *lineBuf1, *lineBuf2, *alphaSrcBuf, *alphaLineBuf1, *alphaLineBuf2;
+ unsigned int pix[splashMaxColorComps];
+ unsigned char *destPtr0, *destPtr, *destAlphaPtr0, *destAlphaPtr;
+ int i;
+
+ if (srcWidth < 1 || srcHeight < 1)
+ return;
+
+ // allocate buffers
+ srcBuf = (unsigned char *)gmallocn(srcWidth + 1, nComps); // + 1 pixel of padding
+ lineBuf1 = (unsigned char *)gmallocn(scaledWidth, nComps);
+ lineBuf2 = (unsigned char *)gmallocn(scaledWidth, nComps);
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);
- }
- }
+ alphaSrcBuf = (unsigned char *)gmalloc(srcWidth + 1); // + 1 pixel of padding
+ alphaLineBuf1 = (unsigned char *)gmalloc(scaledWidth);
+ alphaLineBuf2 = (unsigned char *)gmalloc(scaledWidth);
} 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, nullptr, pixel,
- (unsigned char)splashRound(state->fillAlpha * 255), srcAlpha, false);
- 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);
- } else {
- pipeIncX(&pipe);
- ++ap;
- }
- }
- }
+ alphaSrcBuf = nullptr;
+ alphaLineBuf1 = nullptr;
+ alphaLineBuf2 = nullptr;
+ }
+
+ 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++ = (unsigned char)pix[0];
+ break;
+ case splashModeRGB8:
+ *destPtr++ = (unsigned char)pix[0];
+ *destPtr++ = (unsigned char)pix[1];
+ *destPtr++ = (unsigned char)pix[2];
+ break;
+ case splashModeXBGR8:
+ *destPtr++ = (unsigned char)pix[2];
+ *destPtr++ = (unsigned char)pix[1];
+ *destPtr++ = (unsigned char)pix[0];
+ *destPtr++ = (unsigned char)255;
+ break;
+ case splashModeBGR8:
+ *destPtr++ = (unsigned char)pix[2];
+ *destPtr++ = (unsigned char)pix[1];
+ *destPtr++ = (unsigned char)pix[0];
+ break;
+ case splashModeCMYK8:
+ *destPtr++ = (unsigned char)pix[0];
+ *destPtr++ = (unsigned char)pix[1];
+ *destPtr++ = (unsigned char)pix[2];
+ *destPtr++ = (unsigned char)pix[3];
+ break;
+ case splashModeDeviceN8:
+ for (unsigned int cp : pix)
+ *destPtr++ = (unsigned char)cp;
+ break;
+ }
+
+ // 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)
+{
+ unsigned char *lineBuf;
+ unsigned char *p0, *p1;
+ int w;
+
+ if (unlikely(img->data == nullptr)) {
+ error(errInternal, -1, "img->data is NULL in Splash::vertFlipImage");
+ return;
+ }
+
+ w = width * nComps;
+ lineBuf = (unsigned char *)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, bool 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, bool srcAlpha, int xDest, int yDest, SplashClipResult clipRes)
+{
+ SplashPipe pipe;
+ SplashColor pixel = {};
+ unsigned char *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 {
- 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);
- } else {
- pipeIncX(&pipe);
- }
- }
- }
- }
- }
-}
-
-SplashError Splash::composite(SplashBitmap *src, int xSrc, int ySrc,
- int xDest, int yDest, int w, int h,
- bool noClip, bool nonIsolated,
- bool knockout, SplashCoord knockoutOpacity) {
- SplashPipe pipe;
- SplashColor pixel;
- unsigned char alpha;
- unsigned char *ap;
- int x, y;
-
- if (src->mode != bitmap->mode) {
- return splashErrModeMismatch;
- }
-
- if (unlikely(!bitmap->data)) {
- return splashErrZeroImage;
- }
-
- if(src->getSeparationList()->size() > bitmap->getSeparationList()->size()) {
- for (x = bitmap->getSeparationList()->size(); x < (int)src->getSeparationList()->size(); x++)
- bitmap->getSeparationList()->push_back((GfxSeparationColorSpace *)((*src->getSeparationList())[x])->copy());
- }
- if (src->alpha) {
- pipeInit(&pipe, xDest, yDest, nullptr, pixel,
- (unsigned char)splashRound(state->fillAlpha * 255), true, nonIsolated,
- knockout, (unsigned char)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);
- }
- }
+ 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, nullptr, pixel, (unsigned char)splashRound(state->fillAlpha * 255), srcAlpha, false);
+ 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);
+ }
+ }
+ }
+ }
+
+ // 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, bool srcAlpha, int xSrc, int ySrc, int xDest, int yDest, int w, int h)
+{
+ SplashPipe pipe;
+ SplashColor pixel = {};
+ unsigned char *ap;
+ int x, y;
+
+ if (vectorAntialias) {
+ pipeInit(&pipe, xDest, yDest, nullptr, pixel, (unsigned char)splashRound(state->fillAlpha * 255), true, false);
+ 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 {
- 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);
- } else {
- pipeIncX(&pipe);
- }
- }
- }
- }
- } else {
- pipeInit(&pipe, xDest, yDest, nullptr, pixel,
- (unsigned char)splashRound(state->fillAlpha * 255), false, 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);
- }
- }
+ pipeInit(&pipe, xDest, yDest, nullptr, pixel, (unsigned char)splashRound(state->fillAlpha * 255), srcAlpha, false);
+ 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);
+ } 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);
+ } else {
+ pipeIncX(&pipe);
+ }
+ }
+ }
+ }
+ }
+}
+
+SplashError Splash::composite(SplashBitmap *src, int xSrc, int ySrc, int xDest, int yDest, int w, int h, bool noClip, bool nonIsolated, bool knockout, SplashCoord knockoutOpacity)
+{
+ SplashPipe pipe;
+ SplashColor pixel;
+ unsigned char alpha;
+ unsigned char *ap;
+ int x, y;
+
+ if (src->mode != bitmap->mode) {
+ return splashErrModeMismatch;
+ }
+
+ if (unlikely(!bitmap->data)) {
+ return splashErrZeroImage;
+ }
+
+ if (src->getSeparationList()->size() > bitmap->getSeparationList()->size()) {
+ for (x = bitmap->getSeparationList()->size(); x < (int)src->getSeparationList()->size(); x++)
+ bitmap->getSeparationList()->push_back((GfxSeparationColorSpace *)((*src->getSeparationList())[x])->copy());
+ }
+ if (src->alpha) {
+ pipeInit(&pipe, xDest, yDest, nullptr, pixel, (unsigned char)splashRound(state->fillAlpha * 255), true, nonIsolated, knockout, (unsigned char)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);
+ }
+ }
+ } 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);
+ } else {
+ pipeIncX(&pipe);
+ }
+ }
+ }
+ }
} 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);
- } else {
- pipeIncX(&pipe);
- }
- }
- }
- }
- }
-
- return splashOk;
-}
-
-void Splash::compositeBackground(SplashColorConstPtr color) {
- SplashColorPtr p;
- unsigned char *q;
- unsigned char alpha, alpha1, c, color0, color1, color2;
- unsigned char color3;
- unsigned char colorsp[SPOT_NCOMPS+4], cp;
- int x, y, mask;
-
- if (unlikely(bitmap->alpha == nullptr)) {
- 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;
- 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;
- }
- memset(bitmap->alpha, 255, bitmap->width * bitmap->height);
+ pipeInit(&pipe, xDest, yDest, nullptr, pixel, (unsigned char)splashRound(state->fillAlpha * 255), false, 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);
+ }
+ }
+ } 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);
+ } else {
+ pipeIncX(&pipe);
+ }
+ }
+ }
+ }
+ }
+
+ return splashOk;
+}
+
+void Splash::compositeBackground(SplashColorConstPtr color)
+{
+ SplashColorPtr p;
+ unsigned char *q;
+ unsigned char alpha, alpha1, c, color0, color1, color2;
+ unsigned char color3;
+ unsigned char colorsp[SPOT_NCOMPS + 4], cp;
+ int x, y, mask;
+
+ if (unlikely(bitmap->alpha == nullptr)) {
+ 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;
+ 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;
+ }
+ memset(bitmap->alpha, 255, bitmap->width * bitmap->height);
}
bool 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.;
-
- const int bitmapWidth = bitmap->getWidth();
- SplashClip* clip = getClip();
- SplashBitmap *blitTarget = bitmap;
- SplashColorPtr bitmapData = bitmap->getDataPtr();
- const int bitmapOffLimit = bitmap->getHeight() * bitmap->getRowSize();
- SplashColorPtr bitmapAlpha = bitmap->getAlphaPtr();
- SplashCoord* userToCanvasMatrix = getMatrix();
- const SplashColorMode bitmapMode = bitmap->getMode();
- bool hasAlpha = (bitmapAlpha != nullptr);
- const int rowSize = bitmap->getRowSize();
- const int colorComps = splashColorModeNComps[bitmapMode];
-
- SplashPipe pipe;
- SplashColor cSrcVal;
-
- pipeInit(&pipe, 0, 0, nullptr, cSrcVal, (unsigned char)splashRound(state->fillAlpha * 255), false, false);
-
- if (vectorAntialias) {
- if (aaBuf == nullptr)
- return false; // 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);
- const bool bDirectBlit = vectorAntialias ? false : pipe.noTransparency && !state->blendFunc && !shading->isParameterized();
- if (!bDirectBlit) {
- blitTarget = new SplashBitmap(bitmap->getWidth(),
- bitmap->getHeight(),
- bitmap->getRowPad(),
- bitmap->getMode(),
- true,
- bitmap->getRowSize() >= 0);
- bitmapData = blitTarget->getDataPtr();
- bitmapAlpha = blitTarget->getAlphaPtr();
-
- // initialisation seems to be necessary:
- const int S = bitmap->getWidth() * bitmap->getHeight();
- for (int i = 0; i < S; ++i)
- bitmapAlpha[i] = 0;
- hasAlpha = true;
- }
-
- if (shading->isParameterized()) {
- double color[3];
- double scanLimitMapL[2] = {0., 0.};
- double scanLimitMapR[2] = {0., 0.};
- double scanColorMapL[2] = {0., 0.};
- double scanColorMapR[2] = {0., 0.};
- int scanEdgeL[2] = { 0, 0 };
- int scanEdgeR[2] = { 0, 0 };
-
- for (int i = 0; i < shading->getNTriangles(); ++i) {
- shading->getParametrizedTriangle(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]) {
- const int tmpX = x[2];
- const int tmpY = y[2];
- const 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];
-
- bool hasFurtherSegment = (y[1] < y[2]);
- int 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;
+ 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.;
+
+ const int bitmapWidth = bitmap->getWidth();
+ SplashClip *clip = getClip();
+ SplashBitmap *blitTarget = bitmap;
+ SplashColorPtr bitmapData = bitmap->getDataPtr();
+ const int bitmapOffLimit = bitmap->getHeight() * bitmap->getRowSize();
+ SplashColorPtr bitmapAlpha = bitmap->getAlphaPtr();
+ SplashCoord *userToCanvasMatrix = getMatrix();
+ const SplashColorMode bitmapMode = bitmap->getMode();
+ bool hasAlpha = (bitmapAlpha != nullptr);
+ const int rowSize = bitmap->getRowSize();
+ const int colorComps = splashColorModeNComps[bitmapMode];
+
+ SplashPipe pipe;
+ SplashColor cSrcVal;
+
+ pipeInit(&pipe, 0, 0, nullptr, cSrcVal, (unsigned char)splashRound(state->fillAlpha * 255), false, false);
+
+ if (vectorAntialias) {
+ if (aaBuf == nullptr)
+ return false; // 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);
+ const bool bDirectBlit = vectorAntialias ? false : pipe.noTransparency && !state->blendFunc && !shading->isParameterized();
+ if (!bDirectBlit) {
+ blitTarget = new SplashBitmap(bitmap->getWidth(), bitmap->getHeight(), bitmap->getRowPad(), bitmap->getMode(), true, bitmap->getRowSize() >= 0);
+ bitmapData = blitTarget->getDataPtr();
+ bitmapAlpha = blitTarget->getAlphaPtr();
+
+ // initialisation seems to be necessary:
+ const int S = bitmap->getWidth() * bitmap->getHeight();
+ for (int i = 0; i < S; ++i)
+ bitmapAlpha[i] = 0;
+ hasAlpha = true;
+ }
+
+ if (shading->isParameterized()) {
+ double color[3];
+ double scanLimitMapL[2] = { 0., 0. };
+ double scanLimitMapR[2] = { 0., 0. };
+ double scanColorMapL[2] = { 0., 0. };
+ double scanColorMapR[2] = { 0., 0. };
+ int scanEdgeL[2] = { 0, 0 };
+ int scanEdgeR[2] = { 0, 0 };
+
+ for (int i = 0; i < shading->getNTriangles(); ++i) {
+ shading->getParametrizedTriangle(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]) {
+ const int tmpX = x[2];
+ const int tmpY = y[2];
+ const 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];
-
- 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];
+ 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];
- }
- assert( y[scanEdgeL[0]] < y[scanEdgeL[1]] );
- assert( y[scanEdgeR[0]] < y[scanEdgeR[1]] );
- hasFurtherSegment = false;
- }
-
- yt = Y;
-
- xa = yt * scanLimitMapL[0] + scanLimitMapL[1];
- xt = yt * scanLimitMapR[0] + scanLimitMapR[1];
-
- const double ca = yt * scanColorMapL[0] + scanColorMapL[1];
- const double ct = yt * scanColorMapR[0] + scanColorMapR[1];
-
- const int scanLimitL = splashRound(xa);
- const int scanLimitR = splashRound(xt);
-
- // Ok. Now: init the color interpolation depending on the X
- // coordinate inside of the current scanline:
- const double scanColorMap0 = (scanLimitR == scanLimitL) ? 0. : ((ct - ca) / (scanLimitR - scanLimitL));
- const double scanColorMap1 = ca - scanLimitL * scanColorMap0;
-
- // handled by clipping:
- // assert( scanLimitL >= 0 && scanLimitR < bitmap->getWidth() );
- assert(scanLimitL <= scanLimitR || abs(scanLimitL - scanLimitR) <= 2); // allow rounding inaccuracies
- assert(scanLineOff == Y * rowSize);
-
- double colorinterp = scanColorMap0 * scanLimitL + scanColorMap1;
-
- int bitmapOff = scanLineOff + scanLimitL * colorComps;
- if (likely(bitmapOff >= 0)) {
- for (int X = scanLimitL; X <= scanLimitR && bitmapOff + colorComps <= bitmapOffLimit; ++X, colorinterp += scanColorMap0, 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 - (scanColorMap0 * X + scanColorMap1)) < 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 {
- SplashColor color, auxColor1, auxColor2;
- double scanLimitMapL[2] = {0., 0.};
- double scanLimitMapR[2] = {0., 0.};
- int scanEdgeL[2] = { 0, 0 };
- int scanEdgeR[2] = { 0, 0 };
-
- for (int i = 0; i < shading->getNTriangles(); ++i) {
- // Sadly this current algorithm only supports shadings where the three triangle vertices have the same color
- shading->getNonParametrizedTriangle(i, bitmapMode,
- xdbl + 0, ydbl + 0, (SplashColorPtr)&color,
- xdbl + 1, ydbl + 1, (SplashColorPtr)&auxColor1,
- xdbl + 2, ydbl + 2, (SplashColorPtr)&auxColor2);
- if (!splashColorEqual(color, auxColor1) ||
- !splashColorEqual(color, auxColor2))
- {
- delete blitTarget;
- return false;
- }
- 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]);
- }
- // first two are sorted.
- assert(y[0] <= y[1]);
- if (y[1] > y[2]) {
- const int tmpX = x[2];
- const int tmpY = y[2];
- x[2] = x[1]; y[2] = y[1];
-
- if (y[0] > tmpY) {
- x[1] = x[0]; y[1] = y[0];
- x[0] = tmpX; y[0] = tmpY;
- } else {
- x[1] = tmpX; y[1] = tmpY;
- }
- }
- // 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.
- }
-
- bool hasFurtherSegment = (y[1] < y[2]);
- int 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;
+
+ bool hasFurtherSegment = (y[1] < y[2]);
+ int 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 = false;
+ }
+
+ yt = Y;
+
+ xa = yt * scanLimitMapL[0] + scanLimitMapL[1];
+ xt = yt * scanLimitMapR[0] + scanLimitMapR[1];
+
+ const double ca = yt * scanColorMapL[0] + scanColorMapL[1];
+ const double ct = yt * scanColorMapR[0] + scanColorMapR[1];
+
+ const int scanLimitL = splashRound(xa);
+ const int scanLimitR = splashRound(xt);
+
+ // Ok. Now: init the color interpolation depending on the X
+ // coordinate inside of the current scanline:
+ const double scanColorMap0 = (scanLimitR == scanLimitL) ? 0. : ((ct - ca) / (scanLimitR - scanLimitL));
+ const double scanColorMap1 = ca - scanLimitL * scanColorMap0;
+
+ // handled by clipping:
+ // assert( scanLimitL >= 0 && scanLimitR < bitmap->getWidth() );
+ assert(scanLimitL <= scanLimitR || abs(scanLimitL - scanLimitR) <= 2); // allow rounding inaccuracies
+ assert(scanLineOff == Y * rowSize);
+
+ double colorinterp = scanColorMap0 * scanLimitL + scanColorMap1;
+
+ int bitmapOff = scanLineOff + scanLimitL * colorComps;
+ if (likely(bitmapOff >= 0)) {
+ for (int X = scanLimitL; X <= scanLimitR && bitmapOff + colorComps <= bitmapOffLimit; ++X, colorinterp += scanColorMap0, 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 - (scanColorMap0 * X + scanColorMap1)) < 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 {
+ SplashColor color, auxColor1, auxColor2;
+ double scanLimitMapL[2] = { 0., 0. };
+ double scanLimitMapR[2] = { 0., 0. };
+ int scanEdgeL[2] = { 0, 0 };
+ int scanEdgeR[2] = { 0, 0 };
+
+ for (int i = 0; i < shading->getNTriangles(); ++i) {
+ // Sadly this current algorithm only supports shadings where the three triangle vertices have the same color
+ shading->getNonParametrizedTriangle(i, bitmapMode, xdbl + 0, ydbl + 0, (SplashColorPtr)&color, xdbl + 1, ydbl + 1, (SplashColorPtr)&auxColor1, xdbl + 2, ydbl + 2, (SplashColorPtr)&auxColor2);
+ if (!splashColorEqual(color, auxColor1) || !splashColorEqual(color, auxColor2)) {
+ delete blitTarget;
+ return false;
+ }
+ 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]);
+ }
+ // first two are sorted.
+ assert(y[0] <= y[1]);
+ if (y[1] > y[2]) {
+ const int tmpX = x[2];
+ const int tmpY = y[2];
+ x[2] = x[1];
+ y[2] = y[1];
+
+ if (y[0] > tmpY) {
+ x[1] = x[0];
+ y[1] = y[0];
+ x[0] = tmpX;
+ y[0] = tmpY;
+ } else {
+ x[1] = tmpX;
+ y[1] = tmpY;
+ }
+ }
+ // 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];
- } 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];
- }
- assert( y[scanEdgeL[0]] < y[scanEdgeL[1]] );
- assert( y[scanEdgeR[0]] < y[scanEdgeR[1]] );
- hasFurtherSegment = false;
- }
-
- yt = Y;
-
- xa = yt * scanLimitMapL[0] + scanLimitMapL[1];
- xt = yt * scanLimitMapR[0] + scanLimitMapR[1];
-
- const int scanLimitL = splashRound(xa);
- const int scanLimitR = splashRound(xt);
-
- // handled by clipping:
- // assert( scanLimitL >= 0 && scanLimitR < bitmap->getWidth() );
- assert(scanLimitL <= scanLimitR || abs(scanLimitL - scanLimitR) <= 2); // allow rounding inaccuracies
- assert(scanLineOff == Y * rowSize);
-
- int bitmapOff = scanLineOff + scanLimitL * colorComps;
- if (likely(bitmapOff >= 0)) {
- for (int X = scanLimitL; X <= scanLimitR && bitmapOff + colorComps <= bitmapOffLimit; ++X, 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(bitmapOff == Y * rowSize + colorComps * X && scanLineOff == Y * rowSize);
-
- for (int k = 0; k < colorComps; ++k) {
- bitmapData[bitmapOff + k] = color[k];
- }
-
- // 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;
- }
- }
- }
- }
- }
-
- if (!bDirectBlit) {
- // ok. Finalize the stuff by blitting the shading into the final
- // geometry, this time respecting the rendering pipe.
- const int W = blitTarget->getWidth();
- const int H = blitTarget->getHeight();
- SplashColorPtr 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!
- const int bitmapOff = Y * rowSize + colorComps * X;
-
- for (int m = 0; m < colorComps; ++m)
- cur[m] = bitmapData[bitmapOff + m];
- if (vectorAntialias) {
- drawAAPixel(&pipe, X, Y);
+
+ 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.
+ }
+
+ bool hasFurtherSegment = (y[1] < y[2]);
+ int 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];
+ } 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];
+ }
+ assert(y[scanEdgeL[0]] < y[scanEdgeL[1]]);
+ assert(y[scanEdgeR[0]] < y[scanEdgeR[1]]);
+ hasFurtherSegment = false;
+ }
+
+ yt = Y;
+
+ xa = yt * scanLimitMapL[0] + scanLimitMapL[1];
+ xt = yt * scanLimitMapR[0] + scanLimitMapR[1];
+
+ const int scanLimitL = splashRound(xa);
+ const int scanLimitR = splashRound(xt);
+
+ // handled by clipping:
+ // assert( scanLimitL >= 0 && scanLimitR < bitmap->getWidth() );
+ assert(scanLimitL <= scanLimitR || abs(scanLimitL - scanLimitR) <= 2); // allow rounding inaccuracies
+ assert(scanLineOff == Y * rowSize);
+
+ int bitmapOff = scanLineOff + scanLimitL * colorComps;
+ if (likely(bitmapOff >= 0)) {
+ for (int X = scanLimitL; X <= scanLimitR && bitmapOff + colorComps <= bitmapOffLimit; ++X, 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(bitmapOff == Y * rowSize + colorComps * X && scanLineOff == Y * rowSize);
+
+ for (int k = 0; k < colorComps; ++k) {
+ bitmapData[bitmapOff + k] = color[k];
+ }
+
+ // 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;
+ }
+ }
+ }
+ }
+ }
+
+ if (!bDirectBlit) {
+ // ok. Finalize the stuff by blitting the shading into the final
+ // geometry, this time respecting the rendering pipe.
+ const int W = blitTarget->getWidth();
+ const int H = blitTarget->getHeight();
+ SplashColorPtr 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!
+ const int 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, true); // no clipping - has already been done.
+ }
+ }
+ }
+
+ delete blitTarget;
+ blitTarget = nullptr;
+ }
+
+ return true;
+}
+
+SplashError Splash::blitTransparent(SplashBitmap *src, int xSrc, int ySrc, int xDest, int yDest, int w, int h)
+{
+ SplashColorPtr p, sp;
+ unsigned char *q;
+ int x, y, mask, srcMask, width = w, height = h;
+
+ if (src->mode != bitmap->mode) {
+ return splashErrModeMismatch;
+ }
+
+ if (unlikely(!bitmap->data)) {
+ return splashErrZeroImage;
+ }
+
+ if (src->getWidth() - xSrc < width)
+ width = src->getWidth() - xSrc;
+
+ if (src->getHeight() - ySrc < height)
+ height = src->getHeight() - ySrc;
+
+ if (bitmap->getWidth() - xDest < width)
+ width = bitmap->getWidth() - xDest;
+
+ if (bitmap->getHeight() - yDest < height)
+ height = bitmap->getHeight() - yDest;
+
+ if (width < 0)
+ width = 0;
+
+ if (height < 0)
+ height = 0;
+
+ switch (bitmap->mode) {
+ case splashModeMono1:
+ for (y = 0; y < height; ++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 < width; ++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 < height; ++y) {
+ p = &bitmap->data[(yDest + y) * bitmap->rowSize + xDest];
+ sp = &src->data[(ySrc + y) * bitmap->rowSize + xSrc];
+ for (x = 0; x < width; ++x) {
+ *p++ = *sp++;
+ }
+ }
+ break;
+ case splashModeRGB8:
+ case splashModeBGR8:
+ for (y = 0; y < height; ++y) {
+ p = &bitmap->data[(yDest + y) * bitmap->rowSize + 3 * xDest];
+ sp = &src->data[(ySrc + y) * src->rowSize + 3 * xSrc];
+ for (x = 0; x < width; ++x) {
+ *p++ = *sp++;
+ *p++ = *sp++;
+ *p++ = *sp++;
+ }
+ }
+ break;
+ case splashModeXBGR8:
+ for (y = 0; y < height; ++y) {
+ p = &bitmap->data[(yDest + y) * bitmap->rowSize + 4 * xDest];
+ sp = &src->data[(ySrc + y) * src->rowSize + 4 * xSrc];
+ for (x = 0; x < width; ++x) {
+ *p++ = *sp++;
+ *p++ = *sp++;
+ *p++ = *sp++;
+ *p++ = 255;
+ sp++;
+ }
+ }
+ break;
+ case splashModeCMYK8:
+ for (y = 0; y < height; ++y) {
+ p = &bitmap->data[(yDest + y) * bitmap->rowSize + 4 * xDest];
+ sp = &src->data[(ySrc + y) * src->rowSize + 4 * xSrc];
+ for (x = 0; x < width; ++x) {
+ *p++ = *sp++;
+ *p++ = *sp++;
+ *p++ = *sp++;
+ *p++ = *sp++;
+ }
+ }
+ break;
+ case splashModeDeviceN8:
+ for (y = 0; y < height; ++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 < width; ++x) {
+ for (int cp = 0; cp < SPOT_NCOMPS + 4; cp++)
+ *p++ = *sp++;
+ }
+ }
+ break;
+ }
+
+ if (bitmap->alpha) {
+ for (y = 0; y < height; ++y) {
+ q = &bitmap->alpha[(yDest + y) * bitmap->width + xDest];
+ memset(q, 0x00, width);
+ }
+ }
+
+ return splashOk;
+}
+
+SplashPath *Splash::makeStrokePath(SplashPath *path, SplashCoord w, bool flatten)
+{
+ SplashPath *pathIn, *dashPath, *pathOut;
+ SplashCoord d, dx, dy, wdx, wdy, dxNext, dyNext, wdxNext, wdyNext;
+ SplashCoord crossprod, dotprod, miter, m;
+ bool 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 = false; // 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 {
- drawPixel(&pipe, X, Y, true); // no clipping - has already been done.
- }
- }
- }
-
- delete blitTarget;
- blitTarget = nullptr;
- }
-
- return true;
-}
-
-SplashError Splash::blitTransparent(SplashBitmap *src, int xSrc, int ySrc,
- int xDest, int yDest, int w, int h) {
- SplashColorPtr p, sp;
- unsigned char *q;
- int x, y, mask, srcMask, width = w, height = h;
-
- if (src->mode != bitmap->mode) {
- return splashErrModeMismatch;
- }
-
- if (unlikely(!bitmap->data)) {
- return splashErrZeroImage;
- }
-
- if (src->getWidth() - xSrc < width)
- width = src->getWidth() - xSrc;
-
- if (src->getHeight() - ySrc < height)
- height = src->getHeight() - ySrc;
-
- if (bitmap->getWidth() - xDest < width)
- width = bitmap->getWidth() - xDest;
-
- if (bitmap->getHeight() - yDest < height)
- height = bitmap->getHeight() - yDest;
-
- if (width < 0)
- width = 0;
-
- if (height < 0)
- height = 0;
-
- switch (bitmap->mode) {
- case splashModeMono1:
- for (y = 0; y < height; ++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 < width; ++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 < height; ++y) {
- p = &bitmap->data[(yDest + y) * bitmap->rowSize + xDest];
- sp = &src->data[(ySrc + y) * bitmap->rowSize + xSrc];
- for (x = 0; x < width; ++x) {
- *p++ = *sp++;
- }
- }
- break;
- case splashModeRGB8:
- case splashModeBGR8:
- for (y = 0; y < height; ++y) {
- p = &bitmap->data[(yDest + y) * bitmap->rowSize + 3 * xDest];
- sp = &src->data[(ySrc + y) * src->rowSize + 3 * xSrc];
- for (x = 0; x < width; ++x) {
- *p++ = *sp++;
- *p++ = *sp++;
- *p++ = *sp++;
- }
- }
- break;
- case splashModeXBGR8:
- for (y = 0; y < height; ++y) {
- p = &bitmap->data[(yDest + y) * bitmap->rowSize + 4 * xDest];
- sp = &src->data[(ySrc + y) * src->rowSize + 4 * xSrc];
- for (x = 0; x < width; ++x) {
- *p++ = *sp++;
- *p++ = *sp++;
- *p++ = *sp++;
- *p++ = 255;
- sp++;
- }
- }
- break;
- case splashModeCMYK8:
- for (y = 0; y < height; ++y) {
- p = &bitmap->data[(yDest + y) * bitmap->rowSize + 4 * xDest];
- sp = &src->data[(ySrc + y) * src->rowSize + 4 * xSrc];
- for (x = 0; x < width; ++x) {
- *p++ = *sp++;
- *p++ = *sp++;
- *p++ = *sp++;
- *p++ = *sp++;
- }
- }
- break;
- case splashModeDeviceN8:
- for (y = 0; y < height; ++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 < width; ++x) {
- for (int cp=0; cp < SPOT_NCOMPS+4; cp++)
- *p++ = *sp++;
- }
- }
- break;
- }
-
- if (bitmap->alpha) {
- for (y = 0; y < height; ++y) {
- q = &bitmap->alpha[(yDest + y) * bitmap->width + xDest];
- memset(q, 0x00, width);
- }
- }
-
- return splashOk;
-}
-
-SplashPath *Splash::makeStrokePath(SplashPath *path, SplashCoord w,
- bool flatten) {
-SplashPath *pathIn, *dashPath, *pathOut;
- SplashCoord d, dx, dy, wdx, wdy, dxNext, dyNext, wdxNext, wdyNext;
- SplashCoord crossprod, dotprod, miter, m;
- bool 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) {
+ 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)
+ 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);
+ 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)
+ 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);
+ 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;
- }
+}
- 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 = false; // 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)
- 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);
- 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)
- 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);
- 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, bool hasBBox,
- SplashPattern *pattern,
- bool clipToStrokePath) {
- SplashPipe pipe;
- int xMinI, yMinI, xMaxI, yMaxI, x0, x1, y;
- SplashClipResult clipRes;
-
- if (vectorAntialias && aaBuf == nullptr) { // should not happen, but to be secure
- return splashErrGeneric;
- }
- if (path->length == 0) {
- return splashErrEmptyPath;
- }
- SplashXPath xPath(path, state->matrix, state->flatness, true);
- 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;
- }
- SplashXPathScanner scanner(&xPath, false, 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);
- }
+void Splash::dumpPath(SplashPath *path)
+{
+ int i;
- // 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();
+ 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" : "");
}
- if (yMaxI > state->clip->getYMaxI()) {
- yMaxI = state->clip->getYMaxI();
+}
+
+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" : " ");
}
+}
- unsigned char alpha = splashRound((clipToStrokePath) ? state->strokeAlpha * 255 : state->fillAlpha * 255);
- pipeInit(&pipe, 0, yMinI, pattern, nullptr, alpha, vectorAntialias && !hasBBox, false);
+SplashError Splash::shadedFill(SplashPath *path, bool hasBBox, SplashPattern *pattern, bool clipToStrokePath)
+{
+ SplashPipe pipe;
+ int xMinI, yMinI, xMaxI, yMaxI, x0, x1, y;
+ SplashClipResult clipRes;
- // draw the spans
+ if (vectorAntialias && aaBuf == nullptr) { // should not happen, but to be secure
+ return splashErrGeneric;
+ }
+ if (path->length == 0) {
+ return splashErrEmptyPath;
+ }
+ SplashXPath xPath(path, state->matrix, state->flatness, true);
if (vectorAntialias) {
- for (y = yMinI; y <= yMaxI; ++y) {
- scanner.renderAALine(aaBuf, &x0, &x1, y);
- if (clipRes != splashClipAllInside) {
- state->clip->clipAALine(aaBuf, &x0, &x1, y);
+ xPath.aaScale();
+ }
+ xPath.sort();
+ yMinI = state->clip->getYMinI();
+ yMaxI = state->clip->getYMaxI();
+ if (vectorAntialias && !inShading) {
+ yMinI = yMinI * splashAASize;
+ yMaxI = (yMaxI + 1) * splashAASize - 1;
+ }
+ SplashXPathScanner scanner(&xPath, false, 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 splashAASize == 4
- if (!hasBBox && y > yMinI && y < yMaxI) {
- // correct shape on left side if clip is
- // vertical through the middle of shading:
- unsigned char *p0, *p1, *p2, *p3;
- unsigned char 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) )
- {
- unsigned char 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) )
- {
- unsigned char shapeCorrection = (x1 & 1) ? 0x0f : 0xf0;
- *p0 |= shapeCorrection;
- *p1 |= shapeCorrection;
- *p2 |= shapeCorrection;
- *p3 |= shapeCorrection;
- }
+ if (yMaxI > state->clip->getYMaxI()) {
+ yMaxI = state->clip->getYMaxI();
}
+
+ unsigned char alpha = splashRound((clipToStrokePath) ? state->strokeAlpha * 255 : state->fillAlpha * 255);
+ pipeInit(&pipe, 0, yMinI, pattern, nullptr, alpha, vectorAntialias && !hasBBox, false);
+
+ // 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:
+ unsigned char *p0, *p1, *p2, *p3;
+ unsigned char 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)) {
+ unsigned char 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)) {
+ unsigned char 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) {
- SplashXPathScanIterator iterator(scanner, y);
- while (iterator.getNextSpan(&x0, &x1)) {
- if (clipRes == splashClipAllInside) {
- drawSpan(&pipe, x0, x1, y, true);
- } 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;
-
- return splashOk;
+ drawAALine(&pipe, x0, x1, y);
+ }
+ } else {
+ SplashClipResult clipRes2;
+ for (y = yMinI; y <= yMaxI; ++y) {
+ SplashXPathScanIterator iterator(scanner, y);
+ while (iterator.getNextSpan(&x0, &x1)) {
+ if (clipRes == splashClipAllInside) {
+ drawSpan(&pipe, x0, x1, y, true);
+ } 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;
+
+ return splashOk;
}
diff --git a/splash/Splash.h b/splash/Splash.h
index 16b41c0a..4b7b3818 100644
--- a/splash/Splash.h
+++ b/splash/Splash.h
@@ -50,363 +50,285 @@ typedef bool (*SplashImageMaskSource)(void *data, SplashColorPtr pixel);
// Retrieves the next line of pixels in an image. Normally, fills in
// *<line> and returns true. If the image stream is exhausted,
// returns false.
-typedef bool (*SplashImageSource)(void *data, SplashColorPtr colorLine,
- unsigned char *alphaLine);
+typedef bool (*SplashImageSource)(void *data, SplashColorPtr colorLine, unsigned char *alphaLine);
// Use ICCColorSpace to transform a bitmap
typedef void (*SplashICCTransform)(void *data, SplashBitmap *bitmap);
//------------------------------------------------------------------------
-enum SplashPipeResultColorCtrl {
- splashPipeResultColorNoAlphaBlendCMYK,
- splashPipeResultColorNoAlphaBlendDeviceN,
- splashPipeResultColorNoAlphaBlendRGB,
- splashPipeResultColorNoAlphaBlendMono,
- splashPipeResultColorAlphaNoBlendMono,
- splashPipeResultColorAlphaNoBlendRGB,
- splashPipeResultColorAlphaNoBlendCMYK,
- splashPipeResultColorAlphaNoBlendDeviceN,
- splashPipeResultColorAlphaBlendMono,
- splashPipeResultColorAlphaBlendRGB,
- splashPipeResultColorAlphaBlendCMYK,
- splashPipeResultColorAlphaBlendDeviceN
+enum SplashPipeResultColorCtrl
+{
+ splashPipeResultColorNoAlphaBlendCMYK,
+ splashPipeResultColorNoAlphaBlendDeviceN,
+ splashPipeResultColorNoAlphaBlendRGB,
+ splashPipeResultColorNoAlphaBlendMono,
+ splashPipeResultColorAlphaNoBlendMono,
+ splashPipeResultColorAlphaNoBlendRGB,
+ splashPipeResultColorAlphaNoBlendCMYK,
+ splashPipeResultColorAlphaNoBlendDeviceN,
+ splashPipeResultColorAlphaBlendMono,
+ splashPipeResultColorAlphaBlendRGB,
+ splashPipeResultColorAlphaBlendCMYK,
+ splashPipeResultColorAlphaBlendDeviceN
};
//------------------------------------------------------------------------
// Splash
//------------------------------------------------------------------------
-class Splash {
+class Splash
+{
public:
-
- // Create a new rasterizer object.
- Splash(SplashBitmap *bitmapA, bool vectorAntialiasA,
- SplashScreenParams *screenParams = nullptr);
- Splash(SplashBitmap *bitmapA, bool vectorAntialiasA,
- SplashScreen *screenA);
-
- ~Splash();
-
- Splash(const Splash &) = delete;
- Splash& operator=(const Splash &) = delete;
-
- //----- state read
-
- SplashCoord *getMatrix();
- SplashPattern *getStrokePattern();
- SplashPattern *getFillPattern();
- SplashScreen *getScreen();
- SplashBlendFunc getBlendFunc();
- SplashCoord getStrokeAlpha();
- SplashCoord getFillAlpha();
- SplashCoord getLineWidth();
- int getLineCap();
- int getLineJoin();
- SplashCoord getMiterLimit();
- SplashCoord getFlatness();
- SplashCoord *getLineDash();
- int getLineDashLength();
- SplashCoord getLineDashPhase();
- bool getStrokeAdjust();
- SplashClip *getClip();
- SplashBitmap *getSoftMask();
- bool getInNonIsolatedGroup();
-
- //----- state write
-
- void setMatrix(SplashCoord *matrix);
- void setStrokePattern(SplashPattern *strokePattern);
- void setFillPattern(SplashPattern *fillPattern);
- void setScreen(SplashScreen *screen);
- void setBlendFunc(SplashBlendFunc func);
- void setStrokeAlpha(SplashCoord alpha);
- void setFillAlpha(SplashCoord alpha);
- void setPatternAlpha(SplashCoord strokeAlpha, SplashCoord fillAlpha);
- void clearPatternAlpha();
- void setFillOverprint(bool fop);
- void setStrokeOverprint(bool sop);
- void setOverprintMode(int opm);
- void setLineWidth(SplashCoord lineWidth);
- void setLineCap(int lineCap);
- void setLineJoin(int lineJoin);
- void setMiterLimit(SplashCoord miterLimit);
- void setFlatness(SplashCoord flatness);
- // the <lineDash> array will be copied
- void setLineDash(SplashCoord *lineDash, int lineDashLength,
- SplashCoord lineDashPhase);
- void setStrokeAdjust(bool strokeAdjust);
- // NB: uses transformed coordinates.
- void clipResetToRect(SplashCoord x0, SplashCoord y0,
- SplashCoord x1, SplashCoord y1);
- // NB: uses transformed coordinates.
- SplashError clipToRect(SplashCoord x0, SplashCoord y0,
- SplashCoord x1, SplashCoord y1);
- // NB: uses untransformed coordinates.
- SplashError clipToPath(SplashPath *path, bool eo);
- void setSoftMask(SplashBitmap *softMask);
- void setInNonIsolatedGroup(SplashBitmap *alpha0BitmapA,
- int alpha0XA, int alpha0YA);
- void setTransfer(unsigned char *red, unsigned char *green, unsigned char *blue, unsigned char *gray);
- void setOverprintMask(unsigned int overprintMask, bool additive);
-
- //----- state save/restore
-
- void saveState();
- SplashError restoreState();
-
- //----- drawing operations
-
- // Fill the bitmap with <color>. This is not subject to clipping.
- void clear(SplashColorPtr color, unsigned char alpha = 0x00);
-
- // Stroke a path using the current stroke pattern.
- SplashError stroke(SplashPath *path);
-
- // Fill a path using the current fill pattern.
- SplashError fill(SplashPath *path, bool eo);
-
- // Fill a path, XORing with the current fill pattern.
- SplashError xorFill(SplashPath *path, bool eo);
-
- // Draw a character, using the current fill pattern.
- SplashError fillChar(SplashCoord x, SplashCoord y, int c, SplashFont *font);
-
- // Draw a glyph, using the current fill pattern. This function does
- // not free any data, i.e., it ignores glyph->freeData.
- void fillGlyph(SplashCoord x, SplashCoord y,
- SplashGlyphBitmap *glyph);
-
- // Draws an image mask using the fill color. This will read <h>
- // lines of <w> pixels from <src>, starting with the top line. "1"
- // pixels will be drawn with the current fill color; "0" pixels are
- // transparent. The matrix:
- // [ mat[0] mat[1] 0 ]
- // [ mat[2] mat[3] 0 ]
- // [ mat[4] mat[5] 1 ]
- // maps a unit square to the desired destination for the image, in
- // PostScript style:
- // [x' y' 1] = [x y 1] * mat
- // Note that the Splash y axis points downward, and the image source
- // is assumed to produce pixels in raster order, starting from the
- // top line.
- SplashError fillImageMask(SplashImageMaskSource src, void *srcData,
- int w, int h, SplashCoord *mat,
- bool glyphMode);
-
- // Draw an image. This will read <h> lines of <w> pixels from
- // <src>, starting with the top line. These pixels are assumed to
- // be in the source mode, <srcMode>. If <srcAlpha> is true, the
- // alpha values returned by <src> are used; otherwise they are
- // ignored. The following combinations of source and target modes
- // are supported:
- // source target
- // ------ ------
- // Mono1 Mono1
- // Mono8 Mono1 -- with dithering
- // Mono8 Mono8
- // RGB8 RGB8
- // BGR8 BGR8
- // CMYK8 CMYK8
- // The matrix behaves as for fillImageMask.
- SplashError drawImage(SplashImageSource src, SplashICCTransform tf, void *srcData,
- SplashColorMode srcMode, bool srcAlpha,
- int w, int h, SplashCoord *mat, bool interpolate,
- bool tilingPattern = false);
-
- // Composite a rectangular region from <src> onto this Splash
- // object.
- SplashError composite(SplashBitmap *src, int xSrc, int ySrc,
- int xDest, int yDest, int w, int h,
- bool noClip, bool nonIsolated,
- bool knockout = false, SplashCoord knockoutOpacity = 1.0);
-
- // Composite this Splash object onto a background color. The
- // background alpha is assumed to be 1.
- void compositeBackground(SplashColorConstPtr color);
-
- // Copy a rectangular region from <src> onto the bitmap belonging to
- // this Splash object. The destination alpha values are all set to
- // zero.
- SplashError blitTransparent(SplashBitmap *src, int xSrc, int ySrc,
- int xDest, int yDest, int w, int h);
- void blitImage(SplashBitmap *src, bool srcAlpha, int xDest, int yDest);
-
- //----- misc
-
- // Construct a path for a stroke, given the path to be stroked and
- // the line width <w>. All other stroke parameters are taken from
- // the current state. If <flatten> is true, this function will
- // first flatten the path and handle the linedash.
- SplashPath *makeStrokePath(SplashPath *path, SplashCoord w,
- bool flatten = true);
-
- // Return the associated bitmap.
- SplashBitmap *getBitmap() { return bitmap; }
-
- // Set the minimum line width.
- void setMinLineWidth(SplashCoord w) { minLineWidth = w; }
-
- // Setter/Getter for thin line mode
- void setThinLineMode(SplashThinLineMode thinLineModeA) { thinLineMode = thinLineModeA; }
- SplashThinLineMode getThinLineMode() { return thinLineMode; }
-
- // Get clipping status for the last drawing operation subject to
- // clipping.
- SplashClipResult getClipRes() { return opClipRes; }
-
- // Toggle debug mode on or off.
- void setDebugMode(bool debugModeA) { debugMode = debugModeA; }
+ // Create a new rasterizer object.
+ Splash(SplashBitmap *bitmapA, bool vectorAntialiasA, SplashScreenParams *screenParams = nullptr);
+ Splash(SplashBitmap *bitmapA, bool vectorAntialiasA, SplashScreen *screenA);
+
+ ~Splash();
+
+ Splash(const Splash &) = delete;
+ Splash &operator=(const Splash &) = delete;
+
+ //----- state read
+
+ SplashCoord *getMatrix();
+ SplashPattern *getStrokePattern();
+ SplashPattern *getFillPattern();
+ SplashScreen *getScreen();
+ SplashBlendFunc getBlendFunc();
+ SplashCoord getStrokeAlpha();
+ SplashCoord getFillAlpha();
+ SplashCoord getLineWidth();
+ int getLineCap();
+ int getLineJoin();
+ SplashCoord getMiterLimit();
+ SplashCoord getFlatness();
+ SplashCoord *getLineDash();
+ int getLineDashLength();
+ SplashCoord getLineDashPhase();
+ bool getStrokeAdjust();
+ SplashClip *getClip();
+ SplashBitmap *getSoftMask();
+ bool getInNonIsolatedGroup();
+
+ //----- state write
+
+ void setMatrix(SplashCoord *matrix);
+ void setStrokePattern(SplashPattern *strokePattern);
+ void setFillPattern(SplashPattern *fillPattern);
+ void setScreen(SplashScreen *screen);
+ void setBlendFunc(SplashBlendFunc func);
+ void setStrokeAlpha(SplashCoord alpha);
+ void setFillAlpha(SplashCoord alpha);
+ void setPatternAlpha(SplashCoord strokeAlpha, SplashCoord fillAlpha);
+ void clearPatternAlpha();
+ void setFillOverprint(bool fop);
+ void setStrokeOverprint(bool sop);
+ void setOverprintMode(int opm);
+ void setLineWidth(SplashCoord lineWidth);
+ void setLineCap(int lineCap);
+ void setLineJoin(int lineJoin);
+ void setMiterLimit(SplashCoord miterLimit);
+ void setFlatness(SplashCoord flatness);
+ // the <lineDash> array will be copied
+ void setLineDash(SplashCoord *lineDash, int lineDashLength, SplashCoord lineDashPhase);
+ void setStrokeAdjust(bool strokeAdjust);
+ // NB: uses transformed coordinates.
+ void clipResetToRect(SplashCoord x0, SplashCoord y0, SplashCoord x1, SplashCoord y1);
+ // NB: uses transformed coordinates.
+ SplashError clipToRect(SplashCoord x0, SplashCoord y0, SplashCoord x1, SplashCoord y1);
+ // NB: uses untransformed coordinates.
+ SplashError clipToPath(SplashPath *path, bool eo);
+ void setSoftMask(SplashBitmap *softMask);
+ void setInNonIsolatedGroup(SplashBitmap *alpha0BitmapA, int alpha0XA, int alpha0YA);
+ void setTransfer(unsigned char *red, unsigned char *green, unsigned char *blue, unsigned char *gray);
+ void setOverprintMask(unsigned int overprintMask, bool additive);
+
+ //----- state save/restore
+
+ void saveState();
+ SplashError restoreState();
+
+ //----- drawing operations
+
+ // Fill the bitmap with <color>. This is not subject to clipping.
+ void clear(SplashColorPtr color, unsigned char alpha = 0x00);
+
+ // Stroke a path using the current stroke pattern.
+ SplashError stroke(SplashPath *path);
+
+ // Fill a path using the current fill pattern.
+ SplashError fill(SplashPath *path, bool eo);
+
+ // Fill a path, XORing with the current fill pattern.
+ SplashError xorFill(SplashPath *path, bool eo);
+
+ // Draw a character, using the current fill pattern.
+ SplashError fillChar(SplashCoord x, SplashCoord y, int c, SplashFont *font);
+
+ // Draw a glyph, using the current fill pattern. This function does
+ // not free any data, i.e., it ignores glyph->freeData.
+ void fillGlyph(SplashCoord x, SplashCoord y, SplashGlyphBitmap *glyph);
+
+ // Draws an image mask using the fill color. This will read <h>
+ // lines of <w> pixels from <src>, starting with the top line. "1"
+ // pixels will be drawn with the current fill color; "0" pixels are
+ // transparent. The matrix:
+ // [ mat[0] mat[1] 0 ]
+ // [ mat[2] mat[3] 0 ]
+ // [ mat[4] mat[5] 1 ]
+ // maps a unit square to the desired destination for the image, in
+ // PostScript style:
+ // [x' y' 1] = [x y 1] * mat
+ // Note that the Splash y axis points downward, and the image source
+ // is assumed to produce pixels in raster order, starting from the
+ // top line.
+ SplashError fillImageMask(SplashImageMaskSource src, void *srcData, int w, int h, SplashCoord *mat, bool glyphMode);
+
+ // Draw an image. This will read <h> lines of <w> pixels from
+ // <src>, starting with the top line. These pixels are assumed to
+ // be in the source mode, <srcMode>. If <srcAlpha> is true, the
+ // alpha values returned by <src> are used; otherwise they are
+ // ignored. The following combinations of source and target modes
+ // are supported:
+ // source target
+ // ------ ------
+ // Mono1 Mono1
+ // Mono8 Mono1 -- with dithering
+ // Mono8 Mono8
+ // RGB8 RGB8
+ // BGR8 BGR8
+ // CMYK8 CMYK8
+ // The matrix behaves as for fillImageMask.
+ SplashError drawImage(SplashImageSource src, SplashICCTransform tf, void *srcData, SplashColorMode srcMode, bool srcAlpha, int w, int h, SplashCoord *mat, bool interpolate, bool tilingPattern = false);
+
+ // Composite a rectangular region from <src> onto this Splash
+ // object.
+ SplashError composite(SplashBitmap *src, int xSrc, int ySrc, int xDest, int yDest, int w, int h, bool noClip, bool nonIsolated, bool knockout = false, SplashCoord knockoutOpacity = 1.0);
+
+ // Composite this Splash object onto a background color. The
+ // background alpha is assumed to be 1.
+ void compositeBackground(SplashColorConstPtr color);
+
+ // Copy a rectangular region from <src> onto the bitmap belonging to
+ // this Splash object. The destination alpha values are all set to
+ // zero.
+ SplashError blitTransparent(SplashBitmap *src, int xSrc, int ySrc, int xDest, int yDest, int w, int h);
+ void blitImage(SplashBitmap *src, bool srcAlpha, int xDest, int yDest);
+
+ //----- misc
+
+ // Construct a path for a stroke, given the path to be stroked and
+ // the line width <w>. All other stroke parameters are taken from
+ // the current state. If <flatten> is true, this function will
+ // first flatten the path and handle the linedash.
+ SplashPath *makeStrokePath(SplashPath *path, SplashCoord w, bool flatten = true);
+
+ // Return the associated bitmap.
+ SplashBitmap *getBitmap() { return bitmap; }
+
+ // Set the minimum line width.
+ void setMinLineWidth(SplashCoord w) { minLineWidth = w; }
+
+ // Setter/Getter for thin line mode
+ void setThinLineMode(SplashThinLineMode thinLineModeA) { thinLineMode = thinLineModeA; }
+ SplashThinLineMode getThinLineMode() { return thinLineMode; }
+
+ // Get clipping status for the last drawing operation subject to
+ // clipping.
+ SplashClipResult getClipRes() { return opClipRes; }
+
+ // Toggle debug mode on or off.
+ void setDebugMode(bool debugModeA) { debugMode = debugModeA; }
#if 1 //~tmp: turn off anti-aliasing temporarily
- void setInShading(bool sh) { inShading = sh; }
- bool getVectorAntialias() { return vectorAntialias; }
- void setVectorAntialias(bool vaa) { vectorAntialias = vaa; }
+ void setInShading(bool sh) { inShading = sh; }
+ bool getVectorAntialias() { return vectorAntialias; }
+ void setVectorAntialias(bool vaa) { vectorAntialias = vaa; }
#endif
- // Do shaded fills with dynamic patterns
- //
- // clipToStrokePath: Whether the current clip region is a stroke path.
- // In that case, strokeAlpha is used rather than fillAlpha.
- SplashError shadedFill(SplashPath *path, bool hasBBox,
- SplashPattern *pattern, bool clipToStrokePath);
- // Draw a gouraud triangle shading.
- bool gouraudTriangleShadedFill(SplashGouraudColor *shading);
+ // Do shaded fills with dynamic patterns
+ //
+ // clipToStrokePath: Whether the current clip region is a stroke path.
+ // In that case, strokeAlpha is used rather than fillAlpha.
+ SplashError shadedFill(SplashPath *path, bool hasBBox, SplashPattern *pattern, bool clipToStrokePath);
+ // Draw a gouraud triangle shading.
+ bool gouraudTriangleShadedFill(SplashGouraudColor *shading);
private:
-
- void pipeInit(SplashPipe *pipe, int x, int y,
- SplashPattern *pattern, SplashColorPtr cSrc,
- unsigned char aInput, bool usesShape,
- bool nonIsolatedGroup,
- bool knockout = false, unsigned char knockoutOpacity = 255);
- void pipeRun(SplashPipe *pipe);
- void pipeRunSimpleMono1(SplashPipe *pipe);
- void pipeRunSimpleMono8(SplashPipe *pipe);
- void pipeRunSimpleRGB8(SplashPipe *pipe);
- void pipeRunSimpleXBGR8(SplashPipe *pipe);
- void pipeRunSimpleBGR8(SplashPipe *pipe);
- void pipeRunSimpleCMYK8(SplashPipe *pipe);
- void pipeRunSimpleDeviceN8(SplashPipe *pipe);
- void pipeRunAAMono1(SplashPipe *pipe);
- void pipeRunAAMono8(SplashPipe *pipe);
- void pipeRunAARGB8(SplashPipe *pipe);
- void pipeRunAAXBGR8(SplashPipe *pipe);
- void pipeRunAABGR8(SplashPipe *pipe);
- void pipeRunAACMYK8(SplashPipe *pipe);
- void pipeRunAADeviceN8(SplashPipe *pipe);
- void pipeSetXY(SplashPipe *pipe, int x, int y);
- void pipeIncX(SplashPipe *pipe);
- void drawPixel(SplashPipe *pipe, int x, int y, bool noClip);
- void drawAAPixelInit();
- void drawAAPixel(SplashPipe *pipe, int x, int y);
- void drawSpan(SplashPipe *pipe, int x0, int x1, int y, bool noClip);
- void drawAALine(SplashPipe *pipe, int x0, int x1, int y, bool adjustLine = false, unsigned char lineOpacity = 0);
- void transform(const SplashCoord *matrix, SplashCoord xi, SplashCoord yi,
- SplashCoord *xo, SplashCoord *yo);
- void strokeNarrow(SplashPath *path);
- void strokeWide(SplashPath *path, SplashCoord w);
- SplashPath *flattenPath(SplashPath *path, SplashCoord *matrix,
- SplashCoord flatness);
- void flattenCurve(SplashCoord x0, SplashCoord y0,
- SplashCoord x1, SplashCoord y1,
- SplashCoord x2, SplashCoord y2,
- SplashCoord x3, SplashCoord y3,
- SplashCoord *matrix, SplashCoord flatness2,
- SplashPath *fPath);
- SplashPath *makeDashedPath(SplashPath *xPath);
- void getBBoxFP(SplashPath *path, SplashCoord *xMinA, SplashCoord *yMinA, SplashCoord *xMaxA, SplashCoord *yMaxA);
- SplashError fillWithPattern(SplashPath *path, bool eo,
- SplashPattern *pattern, SplashCoord alpha);
- bool pathAllOutside(SplashPath *path);
- void fillGlyph2(int x0, int y0, SplashGlyphBitmap *glyph, bool noclip);
- void arbitraryTransformMask(SplashImageMaskSource src, void *srcData,
- int srcWidth, int srcHeight,
- SplashCoord *mat, bool glyphMode);
- SplashBitmap *scaleMask(SplashImageMaskSource src, void *srcData,
- int srcWidth, int srcHeight,
- int scaledWidth, int scaledHeight);
- void scaleMaskYdXd(SplashImageMaskSource src, void *srcData,
- int srcWidth, int srcHeight,
- int scaledWidth, int scaledHeight,
- SplashBitmap *dest);
- void scaleMaskYdXu(SplashImageMaskSource src, void *srcData,
- int srcWidth, int srcHeight,
- int scaledWidth, int scaledHeight,
- SplashBitmap *dest);
- void scaleMaskYuXd(SplashImageMaskSource src, void *srcData,
- int srcWidth, int srcHeight,
- int scaledWidth, int scaledHeight,
- SplashBitmap *dest);
- void scaleMaskYuXu(SplashImageMaskSource src, void *srcData,
- int srcWidth, int srcHeight,
- int scaledWidth, int scaledHeight,
- SplashBitmap *dest);
- void blitMask(SplashBitmap *src, int xDest, int yDest,
- SplashClipResult clipRes);
- SplashError arbitraryTransformImage(SplashImageSource src, SplashICCTransform tf, void *srcData,
- SplashColorMode srcMode, int nComps,
- bool srcAlpha,
- int srcWidth, int srcHeight,
- SplashCoord *mat, bool interpolate, bool tilingPattern = false);
- SplashBitmap *scaleImage(SplashImageSource src, void *srcData,
- SplashColorMode srcMode, int nComps,
- bool srcAlpha, int srcWidth, int srcHeight,
- int scaledWidth, int scaledHeight, bool interpolate, bool tilingPattern = false);
- void scaleImageYdXd(SplashImageSource src, void *srcData,
- SplashColorMode srcMode, int nComps,
- bool srcAlpha, int srcWidth, int srcHeight,
- int scaledWidth, int scaledHeight,
- SplashBitmap *dest);
- void scaleImageYdXu(SplashImageSource src, void *srcData,
- SplashColorMode srcMode, int nComps,
- bool srcAlpha, int srcWidth, int srcHeight,
- int scaledWidth, int scaledHeight,
- SplashBitmap *dest);
- void scaleImageYuXd(SplashImageSource src, void *srcData,
- SplashColorMode srcMode, int nComps,
- bool srcAlpha, int srcWidth, int srcHeight,
- int scaledWidth, int scaledHeight,
- SplashBitmap *dest);
- void scaleImageYuXu(SplashImageSource src, void *srcData,
- SplashColorMode srcMode, int nComps,
- bool srcAlpha, int srcWidth, int srcHeight,
- int scaledWidth, int scaledHeight,
- SplashBitmap *dest);
- void scaleImageYuXuBilinear(SplashImageSource src, void *srcData,
- SplashColorMode srcMode, int nComps,
- bool srcAlpha, int srcWidth, int srcHeight,
- int scaledWidth, int scaledHeight,
- SplashBitmap *dest);
- void vertFlipImage(SplashBitmap *img, int width, int height,
- int nComps);
- void blitImage(SplashBitmap *src, bool srcAlpha, int xDest, int yDest,
- SplashClipResult clipRes);
- void blitImageClipped(SplashBitmap *src, bool srcAlpha,
- int xSrc, int ySrc, int xDest, int yDest,
- int w, int h);
- void dumpPath(SplashPath *path);
- void dumpXPath(SplashXPath *path);
-
- static SplashPipeResultColorCtrl pipeResultColorNoAlphaBlend[];
- static SplashPipeResultColorCtrl pipeResultColorAlphaNoBlend[];
- static SplashPipeResultColorCtrl pipeResultColorAlphaBlend[];
- static int pipeNonIsoGroupCorrection[];
-
- SplashBitmap *bitmap;
- SplashState *state;
- SplashBitmap *aaBuf;
- int aaBufY;
- SplashBitmap *alpha0Bitmap; // for non-isolated groups, this is the
- // bitmap containing the alpha0 values
- int alpha0X, alpha0Y; // offset within alpha0Bitmap
- SplashCoord aaGamma[splashAASize * splashAASize + 1];
- SplashCoord minLineWidth;
- SplashThinLineMode thinLineMode;
- SplashClipResult opClipRes;
- bool vectorAntialias;
- bool inShading;
- bool debugMode;
+ void pipeInit(SplashPipe *pipe, int x, int y, SplashPattern *pattern, SplashColorPtr cSrc, unsigned char aInput, bool usesShape, bool nonIsolatedGroup, bool knockout = false, unsigned char knockoutOpacity = 255);
+ void pipeRun(SplashPipe *pipe);
+ void pipeRunSimpleMono1(SplashPipe *pipe);
+ void pipeRunSimpleMono8(SplashPipe *pipe);
+ void pipeRunSimpleRGB8(SplashPipe *pipe);
+ void pipeRunSimpleXBGR8(SplashPipe *pipe);
+ void pipeRunSimpleBGR8(SplashPipe *pipe);
+ void pipeRunSimpleCMYK8(SplashPipe *pipe);
+ void pipeRunSimpleDeviceN8(SplashPipe *pipe);
+ void pipeRunAAMono1(SplashPipe *pipe);
+ void pipeRunAAMono8(SplashPipe *pipe);
+ void pipeRunAARGB8(SplashPipe *pipe);
+ void pipeRunAAXBGR8(SplashPipe *pipe);
+ void pipeRunAABGR8(SplashPipe *pipe);
+ void pipeRunAACMYK8(SplashPipe *pipe);
+ void pipeRunAADeviceN8(SplashPipe *pipe);
+ void pipeSetXY(SplashPipe *pipe, int x, int y);
+ void pipeIncX(SplashPipe *pipe);
+ void drawPixel(SplashPipe *pipe, int x, int y, bool noClip);
+ void drawAAPixelInit();
+ void drawAAPixel(SplashPipe *pipe, int x, int y);
+ void drawSpan(SplashPipe *pipe, int x0, int x1, int y, bool noClip);
+ void drawAALine(SplashPipe *pipe, int x0, int x1, int y, bool adjustLine = false, unsigned char lineOpacity = 0);
+ void transform(const SplashCoord *matrix, SplashCoord xi, SplashCoord yi, SplashCoord *xo, SplashCoord *yo);
+ void strokeNarrow(SplashPath *path);
+ void strokeWide(SplashPath *path, SplashCoord w);
+ SplashPath *flattenPath(SplashPath *path, SplashCoord *matrix, SplashCoord flatness);
+ void flattenCurve(SplashCoord x0, SplashCoord y0, SplashCoord x1, SplashCoord y1, SplashCoord x2, SplashCoord y2, SplashCoord x3, SplashCoord y3, SplashCoord *matrix, SplashCoord flatness2, SplashPath *fPath);
+ SplashPath *makeDashedPath(SplashPath *xPath);
+ void getBBoxFP(SplashPath *path, SplashCoord *xMinA, SplashCoord *yMinA, SplashCoord *xMaxA, SplashCoord *yMaxA);
+ SplashError fillWithPattern(SplashPath *path, bool eo, SplashPattern *pattern, SplashCoord alpha);
+ bool pathAllOutside(SplashPath *path);
+ void fillGlyph2(int x0, int y0, SplashGlyphBitmap *glyph, bool noclip);
+ void arbitraryTransformMask(SplashImageMaskSource src, void *srcData, int srcWidth, int srcHeight, SplashCoord *mat, bool glyphMode);
+ SplashBitmap *scaleMask(SplashImageMaskSource src, void *srcData, int srcWidth, int srcHeight, int scaledWidth, int scaledHeight);
+ void scaleMaskYdXd(SplashImageMaskSource src, void *srcData, int srcWidth, int srcHeight, int scaledWidth, int scaledHeight, SplashBitmap *dest);
+ void scaleMaskYdXu(SplashImageMaskSource src, void *srcData, int srcWidth, int srcHeight, int scaledWidth, int scaledHeight, SplashBitmap *dest);
+ void scaleMaskYuXd(SplashImageMaskSource src, void *srcData, int srcWidth, int srcHeight, int scaledWidth, int scaledHeight, SplashBitmap *dest);
+ void scaleMaskYuXu(SplashImageMaskSource src, void *srcData, int srcWidth, int srcHeight, int scaledWidth, int scaledHeight, SplashBitmap *dest);
+ void blitMask(SplashBitmap *src, int xDest, int yDest, SplashClipResult clipRes);
+ SplashError arbitraryTransformImage(SplashImageSource src, SplashICCTransform tf, void *srcData, SplashColorMode srcMode, int nComps, bool srcAlpha, int srcWidth, int srcHeight, SplashCoord *mat, bool interpolate,
+ bool tilingPattern = false);
+ SplashBitmap *scaleImage(SplashImageSource src, void *srcData, SplashColorMode srcMode, int nComps, bool srcAlpha, int srcWidth, int srcHeight, int scaledWidth, int scaledHeight, bool interpolate, bool tilingPattern = false);
+ void scaleImageYdXd(SplashImageSource src, void *srcData, SplashColorMode srcMode, int nComps, bool srcAlpha, int srcWidth, int srcHeight, int scaledWidth, int scaledHeight, SplashBitmap *dest);
+ void scaleImageYdXu(SplashImageSource src, void *srcData, SplashColorMode srcMode, int nComps, bool srcAlpha, int srcWidth, int srcHeight, int scaledWidth, int scaledHeight, SplashBitmap *dest);
+ void scaleImageYuXd(SplashImageSource src, void *srcData, SplashColorMode srcMode, int nComps, bool srcAlpha, int srcWidth, int srcHeight, int scaledWidth, int scaledHeight, SplashBitmap *dest);
+ void scaleImageYuXu(SplashImageSource src, void *srcData, SplashColorMode srcMode, int nComps, bool srcAlpha, int srcWidth, int srcHeight, int scaledWidth, int scaledHeight, SplashBitmap *dest);
+ void scaleImageYuXuBilinear(SplashImageSource src, void *srcData, SplashColorMode srcMode, int nComps, bool srcAlpha, int srcWidth, int srcHeight, int scaledWidth, int scaledHeight, SplashBitmap *dest);
+ void vertFlipImage(SplashBitmap *img, int width, int height, int nComps);
+ void blitImage(SplashBitmap *src, bool srcAlpha, int xDest, int yDest, SplashClipResult clipRes);
+ void blitImageClipped(SplashBitmap *src, bool srcAlpha, int xSrc, int ySrc, int xDest, int yDest, int w, int h);
+ void dumpPath(SplashPath *path);
+ void dumpXPath(SplashXPath *path);
+
+ static SplashPipeResultColorCtrl pipeResultColorNoAlphaBlend[];
+ static SplashPipeResultColorCtrl pipeResultColorAlphaNoBlend[];
+ static SplashPipeResultColorCtrl pipeResultColorAlphaBlend[];
+ static int pipeNonIsoGroupCorrection[];
+
+ SplashBitmap *bitmap;
+ SplashState *state;
+ SplashBitmap *aaBuf;
+ int aaBufY;
+ SplashBitmap *alpha0Bitmap; // for non-isolated groups, this is the
+ // bitmap containing the alpha0 values
+ int alpha0X, alpha0Y; // offset within alpha0Bitmap
+ SplashCoord aaGamma[splashAASize * splashAASize + 1];
+ SplashCoord minLineWidth;
+ SplashThinLineMode thinLineMode;
+ SplashClipResult opClipRes;
+ bool vectorAntialias;
+ bool inShading;
+ bool debugMode;
};
#endif
diff --git a/splash/SplashBitmap.cc b/splash/SplashBitmap.cc
index b2661206..71916e71 100644
--- a/splash/SplashBitmap.cc
+++ b/splash/SplashBitmap.cc
@@ -52,785 +52,790 @@
// SplashBitmap
//------------------------------------------------------------------------
-SplashBitmap::SplashBitmap(int widthA, int heightA, int rowPadA,
- SplashColorMode modeA, bool alphaA,
- bool topDown, std::vector<GfxSeparationColorSpace*> *separationListA) {
- width = widthA;
- height = heightA;
- mode = modeA;
- rowPad = rowPadA;
- switch (mode) {
- case splashModeMono1:
- if (width > 0) {
- rowSize = (width + 7) >> 3;
- } else {
- rowSize = -1;
- }
- break;
- case splashModeMono8:
- if (width > 0) {
- rowSize = width;
- } else {
- rowSize = -1;
+SplashBitmap::SplashBitmap(int widthA, int heightA, int rowPadA, SplashColorMode modeA, bool alphaA, bool topDown, std::vector<GfxSeparationColorSpace *> *separationListA)
+{
+ width = widthA;
+ height = heightA;
+ mode = modeA;
+ rowPad = rowPadA;
+ switch (mode) {
+ case splashModeMono1:
+ if (width > 0) {
+ rowSize = (width + 7) >> 3;
+ } else {
+ rowSize = -1;
+ }
+ break;
+ case splashModeMono8:
+ if (width > 0) {
+ rowSize = width;
+ } else {
+ rowSize = -1;
+ }
+ break;
+ case splashModeRGB8:
+ case splashModeBGR8:
+ if (width > 0 && width <= INT_MAX / 3) {
+ rowSize = width * 3;
+ } else {
+ rowSize = -1;
+ }
+ break;
+ case splashModeXBGR8:
+ if (width > 0 && width <= INT_MAX / 4) {
+ rowSize = width * 4;
+ } else {
+ rowSize = -1;
+ }
+ break;
+ case splashModeCMYK8:
+ if (width > 0 && width <= INT_MAX / 4) {
+ rowSize = width * 4;
+ } else {
+ rowSize = -1;
+ }
+ break;
+ case splashModeDeviceN8:
+ if (width > 0 && width <= static_cast<int>(INT_MAX / splashMaxColorComps)) {
+ rowSize = width * splashMaxColorComps;
+ } else {
+ rowSize = -1;
+ }
+ break;
}
- break;
- case splashModeRGB8:
- case splashModeBGR8:
- if (width > 0 && width <= INT_MAX / 3) {
- rowSize = width * 3;
- } else {
- rowSize = -1;
+ if (rowSize > 0) {
+ rowSize += rowPad - 1;
+ rowSize -= rowSize % rowPad;
}
- break;
- case splashModeXBGR8:
- if (width > 0 && width <= INT_MAX / 4) {
- rowSize = width * 4;
+ data = (SplashColorPtr)gmallocn_checkoverflow(rowSize, height);
+ if (data != nullptr) {
+ if (!topDown) {
+ data += (height - 1) * rowSize;
+ rowSize = -rowSize;
+ }
+ if (alphaA) {
+ alpha = (unsigned char *)gmallocn(width, height);
+ } else {
+ alpha = nullptr;
+ }
} else {
- rowSize = -1;
+ alpha = nullptr;
}
- break;
- case splashModeCMYK8:
- if (width > 0 && width <= INT_MAX / 4) {
- rowSize = width * 4;
+ separationList = new std::vector<GfxSeparationColorSpace *>();
+ if (separationListA != nullptr)
+ for (const GfxSeparationColorSpace *separation : *separationListA)
+ separationList->push_back((GfxSeparationColorSpace *)separation->copy());
+}
+
+SplashBitmap *SplashBitmap::copy(SplashBitmap *src)
+{
+ SplashBitmap *result = new SplashBitmap(src->getWidth(), src->getHeight(), src->getRowPad(), src->getMode(), src->getAlphaPtr() != nullptr, src->getRowSize() >= 0, src->getSeparationList());
+ unsigned char *dataSource = src->getDataPtr();
+ unsigned char *dataDest = result->getDataPtr();
+ int amount = src->getRowSize();
+ if (amount < 0) {
+ dataSource = dataSource + (src->getHeight() - 1) * amount;
+ dataDest = dataDest + (src->getHeight() - 1) * amount;
+ amount *= -src->getHeight();
} else {
- rowSize = -1;
+ amount *= src->getHeight();
}
- break;
- case splashModeDeviceN8:
- if (width > 0 && width <= static_cast<int>(INT_MAX / splashMaxColorComps)) {
- rowSize = width * splashMaxColorComps;
- } else {
- rowSize = -1;
+ memcpy(dataDest, dataSource, amount);
+ if (src->getAlphaPtr() != nullptr) {
+ memcpy(result->getAlphaPtr(), src->getAlphaPtr(), src->getWidth() * src->getHeight());
}
- break;
- }
- if (rowSize > 0) {
- rowSize += rowPad - 1;
- rowSize -= rowSize % rowPad;
- }
- data = (SplashColorPtr)gmallocn_checkoverflow(rowSize, height);
- if (data != nullptr) {
- if (!topDown) {
- data += (height - 1) * rowSize;
- rowSize = -rowSize;
+ return result;
+}
+
+SplashBitmap::~SplashBitmap()
+{
+ if (data) {
+ if (rowSize < 0) {
+ gfree(data + (height - 1) * rowSize);
+ } else {
+ gfree(data);
+ }
}
- if (alphaA) {
- alpha = (unsigned char *)gmallocn(width, height);
- } else {
- alpha = nullptr;
+ gfree(alpha);
+ for (auto entry : *separationList) {
+ delete entry;
}
- } else {
- alpha = nullptr;
- }
- separationList = new std::vector<GfxSeparationColorSpace*>();
- if (separationListA != nullptr)
- for (const GfxSeparationColorSpace *separation : *separationListA)
- separationList->push_back((GfxSeparationColorSpace*)separation->copy());
+ delete separationList;
}
-SplashBitmap *SplashBitmap::copy(SplashBitmap *src) {
- SplashBitmap *result = new SplashBitmap(src->getWidth(), src->getHeight(), src->getRowPad(),
- src->getMode(), src->getAlphaPtr() != nullptr, src->getRowSize() >= 0, src->getSeparationList());
- unsigned char *dataSource = src->getDataPtr();
- unsigned char *dataDest = result->getDataPtr();
- int amount = src->getRowSize();
- if (amount < 0) {
- dataSource = dataSource + (src->getHeight() - 1) * amount;
- dataDest = dataDest + (src->getHeight() - 1) * amount;
- amount *= -src->getHeight();
- } else {
- amount *= src->getHeight();
- }
- memcpy(dataDest, dataSource, amount);
- if (src->getAlphaPtr() != nullptr) {
- memcpy(result->getAlphaPtr(), src->getAlphaPtr(), src->getWidth() * src->getHeight());
- }
- return result;
-}
+SplashError SplashBitmap::writePNMFile(char *fileName)
+{
+ FILE *f;
+ SplashError e;
-SplashBitmap::~SplashBitmap() {
- if (data) {
- if (rowSize < 0) {
- gfree(data + (height - 1) * rowSize);
- } else {
- gfree(data);
+ if (!(f = openFile(fileName, "wb"))) {
+ return splashErrOpenFile;
}
- }
- gfree(alpha);
- for (auto entry : *separationList) {
- delete entry;
- }
- delete separationList;
+
+ e = this->writePNMFile(f);
+
+ fclose(f);
+ return e;
}
+SplashError SplashBitmap::writePNMFile(FILE *f)
+{
+ SplashColorPtr row, p;
+ int x, y;
-SplashError SplashBitmap::writePNMFile(char *fileName) {
- FILE *f;
- SplashError e;
+ switch (mode) {
- if (!(f = openFile(fileName, "wb"))) {
- return splashErrOpenFile;
- }
+ case splashModeMono1:
+ fprintf(f, "P4\n%d %d\n", width, height);
+ row = data;
+ for (y = 0; y < height; ++y) {
+ p = row;
+ for (x = 0; x < width; x += 8) {
+ fputc(*p ^ 0xff, f);
+ ++p;
+ }
+ row += rowSize;
+ }
+ break;
- e = this->writePNMFile(f);
-
- fclose(f);
- return e;
-}
+ case splashModeMono8:
+ fprintf(f, "P5\n%d %d\n255\n", width, height);
+ row = data;
+ for (y = 0; y < height; ++y) {
+ fwrite(row, 1, width, f);
+ row += rowSize;
+ }
+ break;
+ case splashModeRGB8:
+ fprintf(f, "P6\n%d %d\n255\n", width, height);
+ row = data;
+ for (y = 0; y < height; ++y) {
+ fwrite(row, 1, 3 * width, f);
+ row += rowSize;
+ }
+ break;
-SplashError SplashBitmap::writePNMFile(FILE *f) {
- SplashColorPtr row, p;
- int x, y;
+ case splashModeXBGR8:
+ fprintf(f, "P6\n%d %d\n255\n", width, height);
+ row = data;
+ for (y = 0; y < height; ++y) {
+ p = row;
+ for (x = 0; x < width; ++x) {
+ fputc(splashBGR8R(p), f);
+ fputc(splashBGR8G(p), f);
+ fputc(splashBGR8B(p), f);
+ p += 4;
+ }
+ row += rowSize;
+ }
+ break;
- switch (mode) {
+ case splashModeBGR8:
+ fprintf(f, "P6\n%d %d\n255\n", width, height);
+ row = data;
+ for (y = 0; y < height; ++y) {
+ p = row;
+ for (x = 0; x < width; ++x) {
+ fputc(splashBGR8R(p), f);
+ fputc(splashBGR8G(p), f);
+ fputc(splashBGR8B(p), f);
+ p += 3;
+ }
+ row += rowSize;
+ }
+ break;
- case splashModeMono1:
- fprintf(f, "P4\n%d %d\n", width, height);
- row = data;
- for (y = 0; y < height; ++y) {
- p = row;
- for (x = 0; x < width; x += 8) {
- fputc(*p ^ 0xff, f);
- ++p;
- }
- row += rowSize;
+ case splashModeCMYK8:
+ case splashModeDeviceN8:
+ // PNM doesn't support CMYK
+ error(errInternal, -1, "unsupported SplashBitmap mode");
+ return splashErrGeneric;
+ break;
}
- break;
+ return splashOk;
+}
- case splashModeMono8:
- fprintf(f, "P5\n%d %d\n255\n", width, height);
- row = data;
- for (y = 0; y < height; ++y) {
- fwrite(row, 1, width, f);
- row += rowSize;
- }
- break;
-
- case splashModeRGB8:
- fprintf(f, "P6\n%d %d\n255\n", width, height);
- row = data;
- for (y = 0; y < height; ++y) {
- fwrite(row, 1, 3 * width, f);
- row += rowSize;
- }
- break;
-
- case splashModeXBGR8:
- fprintf(f, "P6\n%d %d\n255\n", width, height);
- row = data;
- for (y = 0; y < height; ++y) {
- p = row;
- for (x = 0; x < width; ++x) {
- fputc(splashBGR8R(p), f);
- fputc(splashBGR8G(p), f);
- fputc(splashBGR8B(p), f);
- p += 4;
- }
- row += rowSize;
+SplashError SplashBitmap::writeAlphaPGMFile(char *fileName)
+{
+ FILE *f;
+
+ if (!alpha) {
+ return splashErrModeMismatch;
}
- break;
-
-
- case splashModeBGR8:
- fprintf(f, "P6\n%d %d\n255\n", width, height);
- row = data;
- for (y = 0; y < height; ++y) {
- p = row;
- for (x = 0; x < width; ++x) {
- fputc(splashBGR8R(p), f);
- fputc(splashBGR8G(p), f);
- fputc(splashBGR8B(p), f);
- p += 3;
- }
- row += rowSize;
+ if (!(f = openFile(fileName, "wb"))) {
+ return splashErrOpenFile;
}
- break;
-
- case splashModeCMYK8:
- case splashModeDeviceN8:
- // PNM doesn't support CMYK
- error(errInternal, -1, "unsupported SplashBitmap mode");
- return splashErrGeneric;
- break;
- }
- return splashOk;
+ fprintf(f, "P5\n%d %d\n255\n", width, height);
+ fwrite(alpha, 1, width * height, f);
+ fclose(f);
+ return splashOk;
}
-SplashError SplashBitmap::writeAlphaPGMFile(char *fileName) {
- FILE *f;
-
- if (!alpha) {
- return splashErrModeMismatch;
- }
- if (!(f = openFile(fileName, "wb"))) {
- return splashErrOpenFile;
- }
- fprintf(f, "P5\n%d %d\n255\n", width, height);
- fwrite(alpha, 1, width * height, f);
- fclose(f);
- return splashOk;
-}
+void SplashBitmap::getPixel(int x, int y, SplashColorPtr pixel)
+{
+ SplashColorPtr p;
-void SplashBitmap::getPixel(int x, int y, SplashColorPtr pixel) {
- SplashColorPtr p;
-
- if (y < 0 || y >= height || x < 0 || x >= width || !data) {
- return;
- }
- switch (mode) {
- case splashModeMono1:
- p = &data[y * rowSize + (x >> 3)];
- pixel[0] = (p[0] & (0x80 >> (x & 7))) ? 0xff : 0x00;
- break;
- case splashModeMono8:
- p = &data[y * rowSize + x];
- pixel[0] = p[0];
- break;
- case splashModeRGB8:
- p = &data[y * rowSize + 3 * x];
- pixel[0] = p[0];
- pixel[1] = p[1];
- pixel[2] = p[2];
- break;
- case splashModeXBGR8:
- p = &data[y * rowSize + 4 * x];
- pixel[0] = p[2];
- pixel[1] = p[1];
- pixel[2] = p[0];
- pixel[3] = p[3];
- break;
- case splashModeBGR8:
- p = &data[y * rowSize + 3 * x];
- pixel[0] = p[2];
- pixel[1] = p[1];
- pixel[2] = p[0];
- break;
- case splashModeCMYK8:
- p = &data[y * rowSize + 4 * x];
- pixel[0] = p[0];
- pixel[1] = p[1];
- pixel[2] = p[2];
- pixel[3] = p[3];
- break;
- case splashModeDeviceN8:
- p = &data[y * rowSize + (SPOT_NCOMPS + 4) * x];
- for (int cp = 0; cp < SPOT_NCOMPS + 4; cp++)
- pixel[cp] = p[cp];
- break;
- }
+ if (y < 0 || y >= height || x < 0 || x >= width || !data) {
+ return;
+ }
+ switch (mode) {
+ case splashModeMono1:
+ p = &data[y * rowSize + (x >> 3)];
+ pixel[0] = (p[0] & (0x80 >> (x & 7))) ? 0xff : 0x00;
+ break;
+ case splashModeMono8:
+ p = &data[y * rowSize + x];
+ pixel[0] = p[0];
+ break;
+ case splashModeRGB8:
+ p = &data[y * rowSize + 3 * x];
+ pixel[0] = p[0];
+ pixel[1] = p[1];
+ pixel[2] = p[2];
+ break;
+ case splashModeXBGR8:
+ p = &data[y * rowSize + 4 * x];
+ pixel[0] = p[2];
+ pixel[1] = p[1];
+ pixel[2] = p[0];
+ pixel[3] = p[3];
+ break;
+ case splashModeBGR8:
+ p = &data[y * rowSize + 3 * x];
+ pixel[0] = p[2];
+ pixel[1] = p[1];
+ pixel[2] = p[0];
+ break;
+ case splashModeCMYK8:
+ p = &data[y * rowSize + 4 * x];
+ pixel[0] = p[0];
+ pixel[1] = p[1];
+ pixel[2] = p[2];
+ pixel[3] = p[3];
+ break;
+ case splashModeDeviceN8:
+ p = &data[y * rowSize + (SPOT_NCOMPS + 4) * x];
+ for (int cp = 0; cp < SPOT_NCOMPS + 4; cp++)
+ pixel[cp] = p[cp];
+ break;
+ }
}
-unsigned char SplashBitmap::getAlpha(int x, int y) {
- return alpha[y * width + x];
+unsigned char SplashBitmap::getAlpha(int x, int y)
+{
+ return alpha[y * width + x];
}
-SplashColorPtr SplashBitmap::takeData() {
- SplashColorPtr data2;
+SplashColorPtr SplashBitmap::takeData()
+{
+ SplashColorPtr data2;
- data2 = data;
- data = nullptr;
- return data2;
+ data2 = data;
+ data = nullptr;
+ return data2;
}
-SplashError SplashBitmap::writeImgFile(SplashImageFileFormat format, const char *fileName, int hDPI, int vDPI, WriteImgParams* params) {
- FILE *f;
- SplashError e;
+SplashError SplashBitmap::writeImgFile(SplashImageFileFormat format, const char *fileName, int hDPI, int vDPI, WriteImgParams *params)
+{
+ FILE *f;
+ SplashError e;
- if (!(f = openFile(fileName, "wb"))) {
- return splashErrOpenFile;
- }
+ if (!(f = openFile(fileName, "wb"))) {
+ return splashErrOpenFile;
+ }
- e = writeImgFile(format, f, hDPI, vDPI, params);
+ e = writeImgFile(format, f, hDPI, vDPI, params);
- fclose(f);
- return e;
+ fclose(f);
+ return e;
}
-void SplashBitmap::setJpegParams(ImgWriter *writer, WriteImgParams* params)
+void SplashBitmap::setJpegParams(ImgWriter *writer, WriteImgParams *params)
{
#ifdef ENABLE_LIBJPEG
- if (params) {
- static_cast<JpegWriter*>(writer)->setProgressive(params->jpegProgressive);
- static_cast<JpegWriter*>(writer)->setOptimize(params->jpegOptimize);
- if (params->jpegQuality >= 0)
- static_cast<JpegWriter*>(writer)->setQuality(params->jpegQuality);
- }
+ if (params) {
+ static_cast<JpegWriter *>(writer)->setProgressive(params->jpegProgressive);
+ static_cast<JpegWriter *>(writer)->setOptimize(params->jpegOptimize);
+ if (params->jpegQuality >= 0)
+ static_cast<JpegWriter *>(writer)->setQuality(params->jpegQuality);
+ }
#endif
}
-SplashError SplashBitmap::writeImgFile(SplashImageFileFormat format, FILE *f, int hDPI, int vDPI, WriteImgParams* params) {
- ImgWriter *writer;
- SplashError e;
-
- SplashColorMode imageWriterFormat = splashModeRGB8;
+SplashError SplashBitmap::writeImgFile(SplashImageFileFormat format, FILE *f, int hDPI, int vDPI, WriteImgParams *params)
+{
+ ImgWriter *writer;
+ SplashError e;
+
+ SplashColorMode imageWriterFormat = splashModeRGB8;
- switch (format) {
- #ifdef ENABLE_LIBPNG
+ switch (format) {
+#ifdef ENABLE_LIBPNG
case splashFormatPng:
- writer = new PNGWriter();
- break;
- #endif
+ writer = new PNGWriter();
+ break;
+#endif
- #ifdef ENABLE_LIBJPEG
+#ifdef ENABLE_LIBJPEG
case splashFormatJpegCMYK:
- writer = new JpegWriter(JpegWriter::CMYK);
- setJpegParams(writer, params);
- break;
- case splashFormatJpeg:
- writer = new JpegWriter();
- setJpegParams(writer, params);
- break;
- #endif
-
- #ifdef ENABLE_LIBTIFF
- case splashFormatTiff:
- switch (mode) {
- case splashModeMono1:
- writer = new TiffWriter(TiffWriter::MONOCHROME);
- imageWriterFormat = splashModeMono1;
- break;
- case splashModeMono8:
- writer = new TiffWriter(TiffWriter::GRAY);
- imageWriterFormat = splashModeMono8;
+ writer = new JpegWriter(JpegWriter::CMYK);
+ setJpegParams(writer, params);
break;
- case splashModeRGB8:
- case splashModeBGR8:
- writer = new TiffWriter(TiffWriter::RGB);
+ case splashFormatJpeg:
+ writer = new JpegWriter();
+ setJpegParams(writer, params);
break;
- case splashModeCMYK8:
- case splashModeDeviceN8:
- writer = new TiffWriter(TiffWriter::CMYK);
+#endif
+
+#ifdef ENABLE_LIBTIFF
+ case splashFormatTiff:
+ switch (mode) {
+ case splashModeMono1:
+ writer = new TiffWriter(TiffWriter::MONOCHROME);
+ imageWriterFormat = splashModeMono1;
+ break;
+ case splashModeMono8:
+ writer = new TiffWriter(TiffWriter::GRAY);
+ imageWriterFormat = splashModeMono8;
+ break;
+ case splashModeRGB8:
+ case splashModeBGR8:
+ writer = new TiffWriter(TiffWriter::RGB);
+ break;
+ case splashModeCMYK8:
+ case splashModeDeviceN8:
+ writer = new TiffWriter(TiffWriter::CMYK);
+ break;
+ default:
+ fprintf(stderr, "TiffWriter: Mode %d not supported\n", mode);
+ writer = new TiffWriter();
+ }
+ if (writer && params) {
+ ((TiffWriter *)writer)->setCompressionString(params->tiffCompression.c_str());
+ }
break;
- default:
- fprintf(stderr, "TiffWriter: Mode %d not supported\n", mode);
- writer = new TiffWriter();
- }
- if (writer && params) {
- ((TiffWriter *)writer)->setCompressionString(params->tiffCompression.c_str());
- }
- break;
- #endif
+#endif
default:
- // Not the greatest error message, but users of this function should
- // have already checked whether their desired format is compiled in.
- error(errInternal, -1, "Support for this image type not compiled in");
- return splashErrGeneric;
- }
-
- e = writeImgFile(writer, f, hDPI, vDPI, imageWriterFormat);
- delete writer;
- return e;
+ // Not the greatest error message, but users of this function should
+ // have already checked whether their desired format is compiled in.
+ error(errInternal, -1, "Support for this image type not compiled in");
+ return splashErrGeneric;
+ }
+
+ e = writeImgFile(writer, f, hDPI, vDPI, imageWriterFormat);
+ delete writer;
+ return e;
}
#include "poppler/GfxState_helpers.h"
-void SplashBitmap::getRGBLine(int yl, SplashColorPtr line) {
- SplashColor col;
- double c, m, y, k, c1, m1, y1, k1, r, g, b;
-
- for (int x = 0; x < width; x++) {
- getPixel(x, yl, col);
- c = byteToDbl(col[0]);
- m = byteToDbl(col[1]);
- y = byteToDbl(col[2]);
- k = byteToDbl(col[3]);
- if (separationList->size() > 0) {
- for (std::size_t i = 0; i < separationList->size(); i++) {
- if (col[i+4] > 0) {
- GfxCMYK cmyk;
- GfxColor input;
- input.c[0] = byteToCol(col[i+4]);
- GfxSeparationColorSpace *sepCS = (GfxSeparationColorSpace *)((*separationList)[i]);
- sepCS->getCMYK(&input, &cmyk);
- col[0] = colToByte(cmyk.c);
- col[1] = colToByte(cmyk.m);
- col[2] = colToByte(cmyk.y);
- col[3] = colToByte(cmyk.k);
- c += byteToDbl(col[0]);
- m += byteToDbl(col[1]);
- y += byteToDbl(col[2]);
- k += byteToDbl(col[3]);
- }
- }
- if (c > 1) c = 1;
- if (m > 1) m = 1;
- if (y > 1) y = 1;
- if (k > 1) k = 1;
+void SplashBitmap::getRGBLine(int yl, SplashColorPtr line)
+{
+ SplashColor col;
+ double c, m, y, k, c1, m1, y1, k1, r, g, b;
+
+ for (int x = 0; x < width; x++) {
+ getPixel(x, yl, col);
+ c = byteToDbl(col[0]);
+ m = byteToDbl(col[1]);
+ y = byteToDbl(col[2]);
+ k = byteToDbl(col[3]);
+ if (separationList->size() > 0) {
+ for (std::size_t i = 0; i < separationList->size(); i++) {
+ if (col[i + 4] > 0) {
+ GfxCMYK cmyk;
+ GfxColor input;
+ input.c[0] = byteToCol(col[i + 4]);
+ GfxSeparationColorSpace *sepCS = (GfxSeparationColorSpace *)((*separationList)[i]);
+ sepCS->getCMYK(&input, &cmyk);
+ col[0] = colToByte(cmyk.c);
+ col[1] = colToByte(cmyk.m);
+ col[2] = colToByte(cmyk.y);
+ col[3] = colToByte(cmyk.k);
+ c += byteToDbl(col[0]);
+ m += byteToDbl(col[1]);
+ y += byteToDbl(col[2]);
+ k += byteToDbl(col[3]);
+ }
+ }
+ if (c > 1)
+ c = 1;
+ if (m > 1)
+ m = 1;
+ if (y > 1)
+ y = 1;
+ if (k > 1)
+ k = 1;
+ }
+ c1 = 1 - c;
+ m1 = 1 - m;
+ y1 = 1 - y;
+ k1 = 1 - k;
+ cmykToRGBMatrixMultiplication(c, m, y, k, c1, m1, y1, k1, r, g, b);
+ *line++ = dblToByte(clip01(r));
+ *line++ = dblToByte(clip01(g));
+ *line++ = dblToByte(clip01(b));
}
- c1 = 1 - c;
- m1 = 1 - m;
- y1 = 1 - y;
- k1 = 1 - k;
- cmykToRGBMatrixMultiplication(c, m, y, k, c1, m1, y1, k1, r, g, b);
- *line++ = dblToByte(clip01(r));
- *line++ = dblToByte(clip01(g));
- *line++ = dblToByte(clip01(b));
- }
}
-void SplashBitmap::getXBGRLine(int yl, SplashColorPtr line, ConversionMode conversionMode) {
- SplashColor col;
- double c, m, y, k, c1, m1, y1, k1, r, g, b;
-
- for (int x = 0; x < width; x++) {
- getPixel(x, yl, col);
- c = byteToDbl(col[0]);
- m = byteToDbl(col[1]);
- y = byteToDbl(col[2]);
- k = byteToDbl(col[3]);
- if (separationList->size() > 0) {
- for (std::size_t i = 0; i < separationList->size(); i++) {
- if (col[i+4] > 0) {
- GfxCMYK cmyk;
- GfxColor input;
- input.c[0] = byteToCol(col[i+4]);
- GfxSeparationColorSpace *sepCS = (GfxSeparationColorSpace *)((*separationList)[i]);
- sepCS->getCMYK(&input, &cmyk);
- col[0] = colToByte(cmyk.c);
- col[1] = colToByte(cmyk.m);
- col[2] = colToByte(cmyk.y);
- col[3] = colToByte(cmyk.k);
- c += byteToDbl(col[0]);
- m += byteToDbl(col[1]);
- y += byteToDbl(col[2]);
- k += byteToDbl(col[3]);
- }
- }
- if (c > 1) c = 1;
- if (m > 1) m = 1;
- if (y > 1) y = 1;
- if (k > 1) k = 1;
- }
- c1 = 1 - c;
- m1 = 1 - m;
- y1 = 1 - y;
- k1 = 1 - k;
- cmykToRGBMatrixMultiplication(c, m, y, k, c1, m1, y1, k1, r, g, b);
-
- if (conversionMode == conversionAlphaPremultiplied) {
- const double a = getAlpha(x, yl) / 255.0;
-
- *line++ = dblToByte(clip01(b * a));
- *line++ = dblToByte(clip01(g * a));
- *line++ = dblToByte(clip01(r * a));
- } else {
- *line++ = dblToByte(clip01(b));
- *line++ = dblToByte(clip01(g));
- *line++ = dblToByte(clip01(r));
- }
+void SplashBitmap::getXBGRLine(int yl, SplashColorPtr line, ConversionMode conversionMode)
+{
+ SplashColor col;
+ double c, m, y, k, c1, m1, y1, k1, r, g, b;
+
+ for (int x = 0; x < width; x++) {
+ getPixel(x, yl, col);
+ c = byteToDbl(col[0]);
+ m = byteToDbl(col[1]);
+ y = byteToDbl(col[2]);
+ k = byteToDbl(col[3]);
+ if (separationList->size() > 0) {
+ for (std::size_t i = 0; i < separationList->size(); i++) {
+ if (col[i + 4] > 0) {
+ GfxCMYK cmyk;
+ GfxColor input;
+ input.c[0] = byteToCol(col[i + 4]);
+ GfxSeparationColorSpace *sepCS = (GfxSeparationColorSpace *)((*separationList)[i]);
+ sepCS->getCMYK(&input, &cmyk);
+ col[0] = colToByte(cmyk.c);
+ col[1] = colToByte(cmyk.m);
+ col[2] = colToByte(cmyk.y);
+ col[3] = colToByte(cmyk.k);
+ c += byteToDbl(col[0]);
+ m += byteToDbl(col[1]);
+ y += byteToDbl(col[2]);
+ k += byteToDbl(col[3]);
+ }
+ }
+ if (c > 1)
+ c = 1;
+ if (m > 1)
+ m = 1;
+ if (y > 1)
+ y = 1;
+ if (k > 1)
+ k = 1;
+ }
+ c1 = 1 - c;
+ m1 = 1 - m;
+ y1 = 1 - y;
+ k1 = 1 - k;
+ cmykToRGBMatrixMultiplication(c, m, y, k, c1, m1, y1, k1, r, g, b);
+
+ if (conversionMode == conversionAlphaPremultiplied) {
+ const double a = getAlpha(x, yl) / 255.0;
+
+ *line++ = dblToByte(clip01(b * a));
+ *line++ = dblToByte(clip01(g * a));
+ *line++ = dblToByte(clip01(r * a));
+ } else {
+ *line++ = dblToByte(clip01(b));
+ *line++ = dblToByte(clip01(g));
+ *line++ = dblToByte(clip01(r));
+ }
- if (conversionMode != conversionOpaque) {
- *line++ = getAlpha(x, yl);
- } else {
- *line++ = 255;
+ if (conversionMode != conversionOpaque) {
+ *line++ = getAlpha(x, yl);
+ } else {
+ *line++ = 255;
+ }
}
- }
}
-static inline unsigned char div255(int x) {
- return (unsigned char)((x + (x >> 8) + 0x80) >> 8);
+static inline unsigned char div255(int x)
+{
+ return (unsigned char)((x + (x >> 8) + 0x80) >> 8);
}
-bool SplashBitmap::convertToXBGR(ConversionMode conversionMode) {
- if (mode == splashModeXBGR8) {
- if (conversionMode != conversionOpaque) {
- // Copy the alpha channel into the fourth component so that XBGR becomes ABGR.
- const SplashColorPtr dbegin = data;
- const SplashColorPtr dend = data + rowSize * height;
-
- unsigned char *const abegin = alpha;
- unsigned char *const aend = alpha + width * height;
-
- SplashColorPtr d = dbegin;
- unsigned char *a = abegin;
-
- if (conversionMode == conversionAlphaPremultiplied) {
- for (; d < dend && a < aend; d += 4, a += 1) {
- d[0] = div255(d[0] * *a);
- d[1] = div255(d[1] * *a);
- d[2] = div255(d[2] * *a);
- d[3] = *a;
- }
- } else {
- for (d += 3; d < dend && a < aend; d += 4, a += 1) {
- *d = *a;
- }
- }
- }
+bool SplashBitmap::convertToXBGR(ConversionMode conversionMode)
+{
+ if (mode == splashModeXBGR8) {
+ if (conversionMode != conversionOpaque) {
+ // Copy the alpha channel into the fourth component so that XBGR becomes ABGR.
+ const SplashColorPtr dbegin = data;
+ const SplashColorPtr dend = data + rowSize * height;
+
+ unsigned char *const abegin = alpha;
+ unsigned char *const aend = alpha + width * height;
+
+ SplashColorPtr d = dbegin;
+ unsigned char *a = abegin;
+
+ if (conversionMode == conversionAlphaPremultiplied) {
+ for (; d < dend && a < aend; d += 4, a += 1) {
+ d[0] = div255(d[0] * *a);
+ d[1] = div255(d[1] * *a);
+ d[2] = div255(d[2] * *a);
+ d[3] = *a;
+ }
+ } else {
+ for (d += 3; d < dend && a < aend; d += 4, a += 1) {
+ *d = *a;
+ }
+ }
+ }
- return true;
- }
-
- int newrowSize = width * 4;
- SplashColorPtr newdata = (SplashColorPtr)gmallocn_checkoverflow(newrowSize, height);
- if (newdata != nullptr) {
- for (int y = 0; y < height; y++) {
- unsigned char *row = newdata + y * newrowSize;
- getXBGRLine(y, row, conversionMode);
+ return true;
}
- if (rowSize < 0) {
- gfree(data + (height - 1) * rowSize);
- } else {
- gfree(data);
+
+ int newrowSize = width * 4;
+ SplashColorPtr newdata = (SplashColorPtr)gmallocn_checkoverflow(newrowSize, height);
+ if (newdata != nullptr) {
+ for (int y = 0; y < height; y++) {
+ unsigned char *row = newdata + y * newrowSize;
+ getXBGRLine(y, row, conversionMode);
+ }
+ if (rowSize < 0) {
+ gfree(data + (height - 1) * rowSize);
+ } else {
+ gfree(data);
+ }
+ data = newdata;
+ rowSize = newrowSize;
+ mode = splashModeXBGR8;
}
- data = newdata;
- rowSize = newrowSize;
- mode = splashModeXBGR8;
- }
- return newdata != nullptr;
+ return newdata != nullptr;
}
-void SplashBitmap::getCMYKLine(int yl, SplashColorPtr line) {
- SplashColor col;
-
- for (int x = 0; x < width; x++) {
- getPixel(x, yl, col);
- if (separationList->size() > 0) {
- double c, m, y, k;
- c = byteToDbl(col[0]);
- m = byteToDbl(col[1]);
- y = byteToDbl(col[2]);
- k = byteToDbl(col[3]);
- for (std::size_t i = 0; i < separationList->size(); i++) {
- if (col[i+4] > 0) {
- GfxCMYK cmyk;
- GfxColor input;
- input.c[0] = byteToCol(col[i+4]);
- GfxSeparationColorSpace *sepCS = (GfxSeparationColorSpace *)((*separationList)[i]);
- sepCS->getCMYK(&input, &cmyk);
- col[0] = colToByte(cmyk.c);
- col[1] = colToByte(cmyk.m);
- col[2] = colToByte(cmyk.y);
- col[3] = colToByte(cmyk.k);
- c += byteToDbl(col[0]);
- m += byteToDbl(col[1]);
- y += byteToDbl(col[2]);
- k += byteToDbl(col[3]);
- }
- }
- col[0] = dblToByte(clip01(c));
- col[1] = dblToByte(clip01(m));
- col[2] = dblToByte(clip01(y));
- col[3] = dblToByte(clip01(k));
+void SplashBitmap::getCMYKLine(int yl, SplashColorPtr line)
+{
+ SplashColor col;
+
+ for (int x = 0; x < width; x++) {
+ getPixel(x, yl, col);
+ if (separationList->size() > 0) {
+ double c, m, y, k;
+ c = byteToDbl(col[0]);
+ m = byteToDbl(col[1]);
+ y = byteToDbl(col[2]);
+ k = byteToDbl(col[3]);
+ for (std::size_t i = 0; i < separationList->size(); i++) {
+ if (col[i + 4] > 0) {
+ GfxCMYK cmyk;
+ GfxColor input;
+ input.c[0] = byteToCol(col[i + 4]);
+ GfxSeparationColorSpace *sepCS = (GfxSeparationColorSpace *)((*separationList)[i]);
+ sepCS->getCMYK(&input, &cmyk);
+ col[0] = colToByte(cmyk.c);
+ col[1] = colToByte(cmyk.m);
+ col[2] = colToByte(cmyk.y);
+ col[3] = colToByte(cmyk.k);
+ c += byteToDbl(col[0]);
+ m += byteToDbl(col[1]);
+ y += byteToDbl(col[2]);
+ k += byteToDbl(col[3]);
+ }
+ }
+ col[0] = dblToByte(clip01(c));
+ col[1] = dblToByte(clip01(m));
+ col[2] = dblToByte(clip01(y));
+ col[3] = dblToByte(clip01(k));
+ }
+ *line++ = col[0];
+ *line++ = col[1];
+ *line++ = col[2];
+ *line++ = col[3];
}
- *line++ = col[0];
- *line++ = col[1];
- *line++ = col[2];
- *line++ = col[3];
- }
}
-SplashError SplashBitmap::writeImgFile(ImgWriter *writer, FILE *f, int hDPI, int vDPI, SplashColorMode imageWriterFormat) {
- if (mode != splashModeRGB8 && mode != splashModeMono8 && mode != splashModeMono1 && mode != splashModeXBGR8 && mode != splashModeBGR8
- && mode != splashModeCMYK8 && mode != splashModeDeviceN8
- ) {
- error(errInternal, -1, "unsupported SplashBitmap mode");
- return splashErrGeneric;
- }
+SplashError SplashBitmap::writeImgFile(ImgWriter *writer, FILE *f, int hDPI, int vDPI, SplashColorMode imageWriterFormat)
+{
+ if (mode != splashModeRGB8 && mode != splashModeMono8 && mode != splashModeMono1 && mode != splashModeXBGR8 && mode != splashModeBGR8 && mode != splashModeCMYK8 && mode != splashModeDeviceN8) {
+ error(errInternal, -1, "unsupported SplashBitmap mode");
+ return splashErrGeneric;
+ }
- if (!writer->init(f, width, height, hDPI, vDPI)) {
- return splashErrGeneric;
- }
+ if (!writer->init(f, width, height, hDPI, vDPI)) {
+ return splashErrGeneric;
+ }
- switch (mode) {
+ switch (mode) {
case splashModeCMYK8:
- if (writer->supportCMYK()) {
- SplashColorPtr row;
- unsigned char **row_pointers = new unsigned char*[height];
- row = data;
-
- for (int y = 0; y < height; ++y) {
- row_pointers[y] = row;
- row += rowSize;
- }
- if (!writer->writePointers(row_pointers, height)) {
- delete[] row_pointers;
- return splashErrGeneric;
- }
- delete[] row_pointers;
- } else {
- unsigned char *row = new unsigned char[3 * width];
- for (int y = 0; y < height; y++) {
- getRGBLine(y, row);
- if (!writer->writeRow(&row)) {
+ if (writer->supportCMYK()) {
+ SplashColorPtr row;
+ unsigned char **row_pointers = new unsigned char *[height];
+ row = data;
+
+ for (int y = 0; y < height; ++y) {
+ row_pointers[y] = row;
+ row += rowSize;
+ }
+ if (!writer->writePointers(row_pointers, height)) {
+ delete[] row_pointers;
+ return splashErrGeneric;
+ }
+ delete[] row_pointers;
+ } else {
+ unsigned char *row = new unsigned char[3 * width];
+ for (int y = 0; y < height; y++) {
+ getRGBLine(y, row);
+ if (!writer->writeRow(&row)) {
+ delete[] row;
+ return splashErrGeneric;
+ }
+ }
delete[] row;
- return splashErrGeneric;
- }
}
- delete[] row;
- }
- break;
+ break;
case splashModeDeviceN8:
- if (writer->supportCMYK()) {
- unsigned char *row = new unsigned char[4 * width];
- for (int y = 0; y < height; y++) {
- getCMYKLine(y, row);
- if (!writer->writeRow(&row)) {
+ if (writer->supportCMYK()) {
+ unsigned char *row = new unsigned char[4 * width];
+ for (int y = 0; y < height; y++) {
+ getCMYKLine(y, row);
+ if (!writer->writeRow(&row)) {
+ delete[] row;
+ return splashErrGeneric;
+ }
+ }
delete[] row;
- return splashErrGeneric;
- }
- }
- delete[] row;
- } else {
- unsigned char *row = new unsigned char[3 * width];
- for (int y = 0; y < height; y++) {
- getRGBLine(y, row);
- if (!writer->writeRow(&row)) {
+ } else {
+ unsigned char *row = new unsigned char[3 * width];
+ for (int y = 0; y < height; y++) {
+ getRGBLine(y, row);
+ if (!writer->writeRow(&row)) {
+ delete[] row;
+ return splashErrGeneric;
+ }
+ }
delete[] row;
- return splashErrGeneric;
- }
}
- delete[] row;
- }
- break;
- case splashModeRGB8:
- {
- SplashColorPtr row;
- unsigned char **row_pointers = new unsigned char*[height];
- row = data;
-
- for (int y = 0; y < height; ++y) {
- row_pointers[y] = row;
- row += rowSize;
- }
- if (!writer->writePointers(row_pointers, height)) {
- delete[] row_pointers;
- return splashErrGeneric;
- }
- delete[] row_pointers;
- }
- break;
-
- case splashModeBGR8:
- {
- unsigned char *row = new unsigned char[3 * width];
- for (int y = 0; y < height; y++) {
- // Convert into a PNG row
- for (int x = 0; x < width; x++) {
- row[3*x] = data[y * rowSize + x * 3 + 2];
- row[3*x+1] = data[y * rowSize + x * 3 + 1];
- row[3*x+2] = data[y * rowSize + x * 3];
- }
-
- if (!writer->writeRow(&row)) {
- delete[] row;
- return splashErrGeneric;
- }
- }
- delete[] row;
- }
- break;
-
- case splashModeXBGR8:
- {
- unsigned char *row = new unsigned char[3 * width];
- for (int y = 0; y < height; y++) {
- // Convert into a PNG row
- for (int x = 0; x < width; x++) {
- row[3*x] = data[y * rowSize + x * 4 + 2];
- row[3*x+1] = data[y * rowSize + x * 4 + 1];
- row[3*x+2] = data[y * rowSize + x * 4];
- }
-
- if (!writer->writeRow(&row)) {
- delete[] row;
- return splashErrGeneric;
- }
- }
- delete[] row;
- }
- break;
-
- case splashModeMono8:
- {
- if (imageWriterFormat == splashModeMono8) {
+ break;
+ case splashModeRGB8: {
SplashColorPtr row;
- unsigned char **row_pointers = new unsigned char*[height];
+ unsigned char **row_pointers = new unsigned char *[height];
row = data;
for (int y = 0; y < height; ++y) {
- row_pointers[y] = row;
- row += rowSize;
+ row_pointers[y] = row;
+ row += rowSize;
}
if (!writer->writePointers(row_pointers, height)) {
- delete[] row_pointers;
- return splashErrGeneric;
+ delete[] row_pointers;
+ return splashErrGeneric;
}
delete[] row_pointers;
- } else if (imageWriterFormat == splashModeRGB8) {
+ } break;
+
+ case splashModeBGR8: {
unsigned char *row = new unsigned char[3 * width];
for (int y = 0; y < height; y++) {
- // Convert into a PNG row
- for (int x = 0; x < width; x++) {
- row[3*x] = data[y * rowSize + x];
- row[3*x+1] = data[y * rowSize + x];
- row[3*x+2] = data[y * rowSize + x];
- }
-
- if (!writer->writeRow(&row)) {
- delete[] row;
- return splashErrGeneric;
- }
+ // Convert into a PNG row
+ for (int x = 0; x < width; x++) {
+ row[3 * x] = data[y * rowSize + x * 3 + 2];
+ row[3 * x + 1] = data[y * rowSize + x * 3 + 1];
+ row[3 * x + 2] = data[y * rowSize + x * 3];
+ }
+
+ if (!writer->writeRow(&row)) {
+ delete[] row;
+ return splashErrGeneric;
+ }
}
delete[] row;
- }
- else {
- // only splashModeMono8 or splashModeRGB8
- return splashErrGeneric;
- }
- }
- break;
-
- case splashModeMono1:
- {
- if (imageWriterFormat == splashModeMono1) {
- SplashColorPtr row;
- unsigned char **row_pointers = new unsigned char*[height];
- row = data;
+ } break;
- for (int y = 0; y < height; ++y) {
- row_pointers[y] = row;
- row += rowSize;
- }
- if (!writer->writePointers(row_pointers, height)) {
- delete[] row_pointers;
- return splashErrGeneric;
- }
- delete[] row_pointers;
- } else if (imageWriterFormat == splashModeRGB8) {
+ case splashModeXBGR8: {
unsigned char *row = new unsigned char[3 * width];
for (int y = 0; y < height; y++) {
- // Convert into a PNG row
- for (int x = 0; x < width; x++) {
- getPixel(x, y, &row[3*x]);
- row[3*x+1] = row[3*x];
- row[3*x+2] = row[3*x];
- }
-
- if (!writer->writeRow(&row)) {
+ // Convert into a PNG row
+ for (int x = 0; x < width; x++) {
+ row[3 * x] = data[y * rowSize + x * 4 + 2];
+ row[3 * x + 1] = data[y * rowSize + x * 4 + 1];
+ row[3 * x + 2] = data[y * rowSize + x * 4];
+ }
+
+ if (!writer->writeRow(&row)) {
+ delete[] row;
+ return splashErrGeneric;
+ }
+ }
+ delete[] row;
+ } break;
+
+ case splashModeMono8: {
+ if (imageWriterFormat == splashModeMono8) {
+ SplashColorPtr row;
+ unsigned char **row_pointers = new unsigned char *[height];
+ row = data;
+
+ for (int y = 0; y < height; ++y) {
+ row_pointers[y] = row;
+ row += rowSize;
+ }
+ if (!writer->writePointers(row_pointers, height)) {
+ delete[] row_pointers;
+ return splashErrGeneric;
+ }
+ delete[] row_pointers;
+ } else if (imageWriterFormat == splashModeRGB8) {
+ unsigned char *row = new unsigned char[3 * width];
+ for (int y = 0; y < height; y++) {
+ // Convert into a PNG row
+ for (int x = 0; x < width; x++) {
+ row[3 * x] = data[y * rowSize + x];
+ row[3 * x + 1] = data[y * rowSize + x];
+ row[3 * x + 2] = data[y * rowSize + x];
+ }
+
+ if (!writer->writeRow(&row)) {
+ delete[] row;
+ return splashErrGeneric;
+ }
+ }
delete[] row;
+ } else {
+ // only splashModeMono8 or splashModeRGB8
return splashErrGeneric;
- }
}
- delete[] row;
- }
- else {
- // only splashModeMono1 or splashModeRGB8
+ } break;
+
+ case splashModeMono1: {
+ if (imageWriterFormat == splashModeMono1) {
+ SplashColorPtr row;
+ unsigned char **row_pointers = new unsigned char *[height];
+ row = data;
+
+ for (int y = 0; y < height; ++y) {
+ row_pointers[y] = row;
+ row += rowSize;
+ }
+ if (!writer->writePointers(row_pointers, height)) {
+ delete[] row_pointers;
+ return splashErrGeneric;
+ }
+ delete[] row_pointers;
+ } else if (imageWriterFormat == splashModeRGB8) {
+ unsigned char *row = new unsigned char[3 * width];
+ for (int y = 0; y < height; y++) {
+ // Convert into a PNG row
+ for (int x = 0; x < width; x++) {
+ getPixel(x, y, &row[3 * x]);
+ row[3 * x + 1] = row[3 * x];
+ row[3 * x + 2] = row[3 * x];
+ }
+
+ if (!writer->writeRow(&row)) {
+ delete[] row;
+ return splashErrGeneric;
+ }
+ }
+ delete[] row;
+ } else {
+ // only splashModeMono1 or splashModeRGB8
+ return splashErrGeneric;
+ }
+ } break;
+
+ default:
+ // can't happen
+ break;
+ }
+
+ if (!writer->close()) {
return splashErrGeneric;
- }
}
- break;
-
- default:
- // can't happen
- break;
- }
-
- if (!writer->close()) {
- return splashErrGeneric;
- }
-
- return splashOk;
+
+ return splashOk;
}
diff --git a/splash/SplashBitmap.h b/splash/SplashBitmap.h
index cd2ea3a0..454f0519 100644
--- a/splash/SplashBitmap.h
+++ b/splash/SplashBitmap.h
@@ -43,84 +43,81 @@ class ImgWriter;
// SplashBitmap
//------------------------------------------------------------------------
-class SplashBitmap {
+class SplashBitmap
+{
public:
-
- // Create a new bitmap. It will have <widthA> x <heightA> pixels in
- // color mode <modeA>. Rows will be padded out to a multiple of
- // <rowPad> bytes. If <topDown> is false, the bitmap will be stored
- // upside-down, i.e., with the last row first in memory.
- SplashBitmap(int widthA, int heightA, int rowPad,
- SplashColorMode modeA, bool alphaA,
- bool topDown = true, std::vector<GfxSeparationColorSpace*> *separationList = nullptr);
- static SplashBitmap *copy(SplashBitmap *src);
-
- ~SplashBitmap();
-
- SplashBitmap(const SplashBitmap &) = delete;
- SplashBitmap& operator=(const SplashBitmap &) = delete;
-
- int getWidth() { return width; }
- int getHeight() { return height; }
- int getRowSize() { return rowSize; }
- int getAlphaRowSize() { return width; }
- int getRowPad() { return rowPad; }
- SplashColorMode getMode() { return mode; }
- SplashColorPtr getDataPtr() { return data; }
- unsigned char *getAlphaPtr() { return alpha; }
- std::vector<GfxSeparationColorSpace*> *getSeparationList() { return separationList; }
-
- SplashError writePNMFile(char *fileName);
- SplashError writePNMFile(FILE *f);
- SplashError writeAlphaPGMFile(char *fileName);
-
- struct WriteImgParams
- {
- int jpegQuality = -1;
- bool jpegProgressive = false;
- GooString tiffCompression;
- bool jpegOptimize = false;
- };
-
- SplashError writeImgFile(SplashImageFileFormat format, const char *fileName, int hDPI, int vDPI, WriteImgParams* params = nullptr);
- SplashError writeImgFile(SplashImageFileFormat format, FILE *f, int hDPI, int vDPI, WriteImgParams* params = nullptr);
- SplashError writeImgFile(ImgWriter *writer, FILE *f, int hDPI, int vDPI, SplashColorMode imageWriterFormat);
-
- enum ConversionMode
- {
- conversionOpaque,
- conversionAlpha,
- conversionAlphaPremultiplied
- };
-
- bool convertToXBGR(ConversionMode conversionMode = conversionOpaque);
-
- void getPixel(int x, int y, SplashColorPtr pixel);
- void getRGBLine(int y, SplashColorPtr line);
- void getXBGRLine(int y, SplashColorPtr line, ConversionMode conversionMode = conversionOpaque);
- void getCMYKLine(int y, SplashColorPtr line);
- unsigned char getAlpha(int x, int y);
-
- // Caller takes ownership of the bitmap data. The SplashBitmap
- // object is no longer valid -- the next call should be to the
- // destructor.
- SplashColorPtr takeData();
+ // Create a new bitmap. It will have <widthA> x <heightA> pixels in
+ // color mode <modeA>. Rows will be padded out to a multiple of
+ // <rowPad> bytes. If <topDown> is false, the bitmap will be stored
+ // upside-down, i.e., with the last row first in memory.
+ SplashBitmap(int widthA, int heightA, int rowPad, SplashColorMode modeA, bool alphaA, bool topDown = true, std::vector<GfxSeparationColorSpace *> *separationList = nullptr);
+ static SplashBitmap *copy(SplashBitmap *src);
+
+ ~SplashBitmap();
+
+ SplashBitmap(const SplashBitmap &) = delete;
+ SplashBitmap &operator=(const SplashBitmap &) = delete;
+
+ int getWidth() { return width; }
+ int getHeight() { return height; }
+ int getRowSize() { return rowSize; }
+ int getAlphaRowSize() { return width; }
+ int getRowPad() { return rowPad; }
+ SplashColorMode getMode() { return mode; }
+ SplashColorPtr getDataPtr() { return data; }
+ unsigned char *getAlphaPtr() { return alpha; }
+ std::vector<GfxSeparationColorSpace *> *getSeparationList() { return separationList; }
+
+ SplashError writePNMFile(char *fileName);
+ SplashError writePNMFile(FILE *f);
+ SplashError writeAlphaPGMFile(char *fileName);
+
+ struct WriteImgParams
+ {
+ int jpegQuality = -1;
+ bool jpegProgressive = false;
+ GooString tiffCompression;
+ bool jpegOptimize = false;
+ };
+
+ SplashError writeImgFile(SplashImageFileFormat format, const char *fileName, int hDPI, int vDPI, WriteImgParams *params = nullptr);
+ SplashError writeImgFile(SplashImageFileFormat format, FILE *f, int hDPI, int vDPI, WriteImgParams *params = nullptr);
+ SplashError writeImgFile(ImgWriter *writer, FILE *f, int hDPI, int vDPI, SplashColorMode imageWriterFormat);
+
+ enum ConversionMode
+ {
+ conversionOpaque,
+ conversionAlpha,
+ conversionAlphaPremultiplied
+ };
+
+ bool convertToXBGR(ConversionMode conversionMode = conversionOpaque);
+
+ void getPixel(int x, int y, SplashColorPtr pixel);
+ void getRGBLine(int y, SplashColorPtr line);
+ void getXBGRLine(int y, SplashColorPtr line, ConversionMode conversionMode = conversionOpaque);
+ void getCMYKLine(int y, SplashColorPtr line);
+ unsigned char getAlpha(int x, int y);
+
+ // Caller takes ownership of the bitmap data. The SplashBitmap
+ // object is no longer valid -- the next call should be to the
+ // destructor.
+ SplashColorPtr takeData();
private:
-
- int width, height; // size of bitmap
- int rowPad;
- int rowSize; // size of one row of data, in bytes
- // - negative for bottom-up bitmaps
- SplashColorMode mode; // color mode
- SplashColorPtr data; // pointer to row zero of the color data
- unsigned char *alpha; // pointer to row zero of the alpha data
- // (always top-down)
- std::vector<GfxSeparationColorSpace*> *separationList; // list of spot colorants and their mapping functions
-
- friend class Splash;
-
- void setJpegParams(ImgWriter *writer, WriteImgParams* params);
+ int width, height; // size of bitmap
+ int rowPad;
+ int rowSize; // size of one row of data, in bytes
+ // - negative for bottom-up bitmaps
+ SplashColorMode mode; // color mode
+ SplashColorPtr data; // pointer to row zero of the color data
+ unsigned char *alpha; // pointer to row zero of the alpha data
+ // (always top-down)
+ std::vector<GfxSeparationColorSpace *> *separationList; // list of spot colorants and their mapping functions
+
+ friend class Splash;
+
+ void setJpegParams(ImgWriter *writer, WriteImgParams *params);
};
#endif
diff --git a/splash/SplashClip.cc b/splash/SplashClip.cc
index d4010710..71256735 100644
--- a/splash/SplashClip.cc
+++ b/splash/SplashClip.cc
@@ -37,388 +37,364 @@
// SplashClip.flags
//------------------------------------------------------------------------
-#define splashClipEO 0x01 // use even-odd rule
+#define splashClipEO 0x01 // use even-odd rule
//------------------------------------------------------------------------
// SplashClip
//------------------------------------------------------------------------
-SplashClip::SplashClip(SplashCoord x0, SplashCoord y0,
- SplashCoord x1, SplashCoord y1,
- bool antialiasA) {
- antialias = antialiasA;
- if (x0 < x1) {
- xMin = x0;
- xMax = x1;
- } else {
- xMin = x1;
- xMax = x0;
- }
- if (y0 < y1) {
- yMin = y0;
- yMax = y1;
- } else {
- yMin = y1;
- yMax = y0;
- }
- xMinI = splashFloor(xMin);
- yMinI = splashFloor(yMin);
- xMaxI = splashCeil(xMax) - 1;
- yMaxI = splashCeil(yMax) - 1;
- paths = nullptr;
- flags = nullptr;
- scanners = nullptr;
- length = size = 0;
+SplashClip::SplashClip(SplashCoord x0, SplashCoord y0, SplashCoord x1, SplashCoord y1, bool antialiasA)
+{
+ antialias = antialiasA;
+ if (x0 < x1) {
+ xMin = x0;
+ xMax = x1;
+ } else {
+ xMin = x1;
+ xMax = x0;
+ }
+ if (y0 < y1) {
+ yMin = y0;
+ yMax = y1;
+ } else {
+ yMin = y1;
+ yMax = y0;
+ }
+ xMinI = splashFloor(xMin);
+ yMinI = splashFloor(yMin);
+ xMaxI = splashCeil(xMax) - 1;
+ yMaxI = splashCeil(yMax) - 1;
+ paths = nullptr;
+ flags = nullptr;
+ scanners = nullptr;
+ length = size = 0;
}
-SplashClip::SplashClip(SplashClip *clip) {
- int yMinAA, yMaxAA;
- int i;
-
- antialias = clip->antialias;
- xMin = clip->xMin;
- yMin = clip->yMin;
- xMax = clip->xMax;
- yMax = clip->yMax;
- xMinI = clip->xMinI;
- yMinI = clip->yMinI;
- xMaxI = clip->xMaxI;
- yMaxI = clip->yMaxI;
- length = clip->length;
- size = clip->size;
- paths = (SplashXPath **)gmallocn(size, sizeof(SplashXPath *));
- flags = (unsigned char *)gmallocn(size, sizeof(unsigned char));
- scanners = (SplashXPathScanner **)
- gmallocn(size, sizeof(SplashXPathScanner *));
- for (i = 0; i < length; ++i) {
- paths[i] = clip->paths[i]->copy();
- flags[i] = clip->flags[i];
- if (antialias) {
- yMinAA = yMinI * splashAASize;
- yMaxAA = (yMaxI + 1) * splashAASize - 1;
- } else {
- yMinAA = yMinI;
- yMaxAA = yMaxI;
+SplashClip::SplashClip(SplashClip *clip)
+{
+ int yMinAA, yMaxAA;
+ int i;
+
+ antialias = clip->antialias;
+ xMin = clip->xMin;
+ yMin = clip->yMin;
+ xMax = clip->xMax;
+ yMax = clip->yMax;
+ xMinI = clip->xMinI;
+ yMinI = clip->yMinI;
+ xMaxI = clip->xMaxI;
+ yMaxI = clip->yMaxI;
+ length = clip->length;
+ size = clip->size;
+ paths = (SplashXPath **)gmallocn(size, sizeof(SplashXPath *));
+ flags = (unsigned char *)gmallocn(size, sizeof(unsigned char));
+ scanners = (SplashXPathScanner **)gmallocn(size, sizeof(SplashXPathScanner *));
+ for (i = 0; i < length; ++i) {
+ paths[i] = clip->paths[i]->copy();
+ flags[i] = clip->flags[i];
+ if (antialias) {
+ yMinAA = yMinI * splashAASize;
+ yMaxAA = (yMaxI + 1) * splashAASize - 1;
+ } else {
+ yMinAA = yMinI;
+ yMaxAA = yMaxI;
+ }
+ scanners[i] = new SplashXPathScanner(paths[i], flags[i] & splashClipEO, yMinAA, yMaxAA);
}
- scanners[i] = new SplashXPathScanner(paths[i], flags[i] & splashClipEO,
- yMinAA, yMaxAA);
- }
}
-SplashClip::~SplashClip() {
- int i;
+SplashClip::~SplashClip()
+{
+ int i;
- for (i = 0; i < length; ++i) {
- delete paths[i];
- delete scanners[i];
- }
- gfree(paths);
- gfree(flags);
- gfree(scanners);
+ for (i = 0; i < length; ++i) {
+ delete paths[i];
+ delete scanners[i];
+ }
+ gfree(paths);
+ gfree(flags);
+ gfree(scanners);
}
-void SplashClip::grow(int nPaths) {
- if (length + nPaths > size) {
- if (size == 0) {
- size = 32;
- }
- while (size < length + nPaths) {
- size *= 2;
+void SplashClip::grow(int nPaths)
+{
+ if (length + nPaths > size) {
+ if (size == 0) {
+ size = 32;
+ }
+ while (size < length + nPaths) {
+ size *= 2;
+ }
+ paths = (SplashXPath **)greallocn(paths, size, sizeof(SplashXPath *));
+ flags = (unsigned char *)greallocn(flags, size, sizeof(unsigned char));
+ scanners = (SplashXPathScanner **)greallocn(scanners, size, sizeof(SplashXPathScanner *));
}
- paths = (SplashXPath **)greallocn(paths, size, sizeof(SplashXPath *));
- flags = (unsigned char *)greallocn(flags, size, sizeof(unsigned char));
- scanners = (SplashXPathScanner **)
- greallocn(scanners, size, sizeof(SplashXPathScanner *));
- }
}
-void SplashClip::resetToRect(SplashCoord x0, SplashCoord y0,
- SplashCoord x1, SplashCoord y1) {
- int i;
-
- for (i = 0; i < length; ++i) {
- delete paths[i];
- delete scanners[i];
- }
- gfree(paths);
- gfree(flags);
- gfree(scanners);
- paths = nullptr;
- flags = nullptr;
- scanners = nullptr;
- length = size = 0;
-
- if (x0 < x1) {
- xMin = x0;
- xMax = x1;
- } else {
- xMin = x1;
- xMax = x0;
- }
- if (y0 < y1) {
- yMin = y0;
- yMax = y1;
- } else {
- yMin = y1;
- yMax = y0;
- }
- xMinI = splashFloor(xMin);
- yMinI = splashFloor(yMin);
- xMaxI = splashCeil(xMax) - 1;
- yMaxI = splashCeil(yMax) - 1;
-}
+void SplashClip::resetToRect(SplashCoord x0, SplashCoord y0, SplashCoord x1, SplashCoord y1)
+{
+ int i;
-SplashError SplashClip::clipToRect(SplashCoord x0, SplashCoord y0,
- SplashCoord x1, SplashCoord y1) {
- if (x0 < x1) {
- if (x0 > xMin) {
- xMin = x0;
- xMinI = splashFloor(xMin);
+ for (i = 0; i < length; ++i) {
+ delete paths[i];
+ delete scanners[i];
}
- if (x1 < xMax) {
- xMax = x1;
- xMaxI = splashCeil(xMax) - 1;
+ gfree(paths);
+ gfree(flags);
+ gfree(scanners);
+ paths = nullptr;
+ flags = nullptr;
+ scanners = nullptr;
+ length = size = 0;
+
+ if (x0 < x1) {
+ xMin = x0;
+ xMax = x1;
+ } else {
+ xMin = x1;
+ xMax = x0;
}
- } else {
- if (x1 > xMin) {
- xMin = x1;
- xMinI = splashFloor(xMin);
+ if (y0 < y1) {
+ yMin = y0;
+ yMax = y1;
+ } else {
+ yMin = y1;
+ yMax = y0;
}
- if (x0 < xMax) {
- xMax = x0;
- xMaxI = splashCeil(xMax) - 1;
+ xMinI = splashFloor(xMin);
+ yMinI = splashFloor(yMin);
+ xMaxI = splashCeil(xMax) - 1;
+ yMaxI = splashCeil(yMax) - 1;
+}
+
+SplashError SplashClip::clipToRect(SplashCoord x0, SplashCoord y0, SplashCoord x1, SplashCoord y1)
+{
+ if (x0 < x1) {
+ if (x0 > xMin) {
+ xMin = x0;
+ xMinI = splashFloor(xMin);
+ }
+ if (x1 < xMax) {
+ xMax = x1;
+ xMaxI = splashCeil(xMax) - 1;
+ }
+ } else {
+ if (x1 > xMin) {
+ xMin = x1;
+ xMinI = splashFloor(xMin);
+ }
+ if (x0 < xMax) {
+ xMax = x0;
+ xMaxI = splashCeil(xMax) - 1;
+ }
}
- }
- if (y0 < y1) {
- if (y0 > yMin) {
- yMin = y0;
- yMinI = splashFloor(yMin);
+ if (y0 < y1) {
+ if (y0 > yMin) {
+ yMin = y0;
+ yMinI = splashFloor(yMin);
+ }
+ if (y1 < yMax) {
+ yMax = y1;
+ yMaxI = splashCeil(yMax) - 1;
+ }
+ } else {
+ if (y1 > yMin) {
+ yMin = y1;
+ yMinI = splashFloor(yMin);
+ }
+ if (y0 < yMax) {
+ yMax = y0;
+ yMaxI = splashCeil(yMax) - 1;
+ }
}
- if (y1 < yMax) {
- yMax = y1;
- yMaxI = splashCeil(yMax) - 1;
+ return splashOk;
+}
+
+SplashError SplashClip::clipToPath(SplashPath *path, SplashCoord *matrix, SplashCoord flatness, bool eo)
+{
+ SplashXPath *xPath;
+ int yMinAA, yMaxAA;
+
+ xPath = new SplashXPath(path, matrix, flatness, true);
+
+ // check for an empty path
+ if (xPath->length == 0) {
+ xMax = xMin - 1;
+ yMax = yMin - 1;
+ xMaxI = splashCeil(xMax) - 1;
+ yMaxI = splashCeil(yMax) - 1;
+ delete xPath;
+
+ // check for a rectangle
+ } else if (xPath->length == 4
+ && ((xPath->segs[0].x0 == xPath->segs[0].x1 && xPath->segs[0].x0 == xPath->segs[1].x0 && xPath->segs[0].x0 == xPath->segs[3].x1 && xPath->segs[2].x0 == xPath->segs[2].x1 && xPath->segs[2].x0 == xPath->segs[1].x1
+ && xPath->segs[2].x0 == xPath->segs[3].x0 && xPath->segs[1].y0 == xPath->segs[1].y1 && xPath->segs[1].y0 == xPath->segs[0].y1 && xPath->segs[1].y0 == xPath->segs[2].y0 && xPath->segs[3].y0 == xPath->segs[3].y1
+ && xPath->segs[3].y0 == xPath->segs[0].y0 && xPath->segs[3].y0 == xPath->segs[2].y1)
+ || (xPath->segs[0].y0 == xPath->segs[0].y1 && xPath->segs[0].y0 == xPath->segs[1].y0 && xPath->segs[0].y0 == xPath->segs[3].y1 && xPath->segs[2].y0 == xPath->segs[2].y1 && xPath->segs[2].y0 == xPath->segs[1].y1
+ && xPath->segs[2].y0 == xPath->segs[3].y0 && xPath->segs[1].x0 == xPath->segs[1].x1 && xPath->segs[1].x0 == xPath->segs[0].x1 && xPath->segs[1].x0 == xPath->segs[2].x0 && xPath->segs[3].x0 == xPath->segs[3].x1
+ && xPath->segs[3].x0 == xPath->segs[0].x0 && xPath->segs[3].x0 == xPath->segs[2].x1))) {
+ clipToRect(xPath->segs[0].x0, xPath->segs[0].y0, xPath->segs[2].x0, xPath->segs[2].y0);
+ delete xPath;
+
+ } else {
+ grow(1);
+ if (antialias) {
+ xPath->aaScale();
+ }
+ xPath->sort();
+ paths[length] = xPath;
+ flags[length] = eo ? splashClipEO : 0;
+ if (antialias) {
+ yMinAA = yMinI * splashAASize;
+ yMaxAA = (yMaxI + 1) * splashAASize - 1;
+ } else {
+ yMinAA = yMinI;
+ yMaxAA = yMaxI;
+ }
+ scanners[length] = new SplashXPathScanner(xPath, eo, yMinAA, yMaxAA);
+ ++length;
}
- } else {
- if (y1 > yMin) {
- yMin = y1;
- yMinI = splashFloor(yMin);
+
+ return splashOk;
+}
+
+SplashClipResult SplashClip::testRect(int rectXMin, int rectYMin, int rectXMax, int rectYMax)
+{
+ // This tests the rectangle:
+ // x = [rectXMin, rectXMax + 1) (note: rect coords are ints)
+ // y = [rectYMin, rectYMax + 1)
+ // against the clipping region:
+ // x = [xMin, xMax) (note: clipping coords are fp)
+ // y = [yMin, yMax)
+ if ((SplashCoord)(rectXMax + 1) <= xMin || (SplashCoord)rectXMin >= xMax || (SplashCoord)(rectYMax + 1) <= yMin || (SplashCoord)rectYMin >= yMax) {
+ return splashClipAllOutside;
}
- if (y0 < yMax) {
- yMax = y0;
- yMaxI = splashCeil(yMax) - 1;
+ if ((SplashCoord)rectXMin >= xMin && (SplashCoord)(rectXMax + 1) <= xMax && (SplashCoord)rectYMin >= yMin && (SplashCoord)(rectYMax + 1) <= yMax && length == 0) {
+ return splashClipAllInside;
}
- }
- return splashOk;
+ return splashClipPartial;
}
-SplashError SplashClip::clipToPath(SplashPath *path, SplashCoord *matrix,
- SplashCoord flatness, bool eo) {
- SplashXPath *xPath;
- int yMinAA, yMaxAA;
-
- xPath = new SplashXPath(path, matrix, flatness, true);
-
- // check for an empty path
- if (xPath->length == 0) {
- xMax = xMin - 1;
- yMax = yMin - 1;
- xMaxI = splashCeil(xMax) - 1;
- yMaxI = splashCeil(yMax) - 1;
- delete xPath;
-
- // check for a rectangle
- } else if (xPath->length == 4 &&
- ((xPath->segs[0].x0 == xPath->segs[0].x1 &&
- xPath->segs[0].x0 == xPath->segs[1].x0 &&
- xPath->segs[0].x0 == xPath->segs[3].x1 &&
- xPath->segs[2].x0 == xPath->segs[2].x1 &&
- xPath->segs[2].x0 == xPath->segs[1].x1 &&
- xPath->segs[2].x0 == xPath->segs[3].x0 &&
- xPath->segs[1].y0 == xPath->segs[1].y1 &&
- xPath->segs[1].y0 == xPath->segs[0].y1 &&
- xPath->segs[1].y0 == xPath->segs[2].y0 &&
- xPath->segs[3].y0 == xPath->segs[3].y1 &&
- xPath->segs[3].y0 == xPath->segs[0].y0 &&
- xPath->segs[3].y0 == xPath->segs[2].y1) ||
- (xPath->segs[0].y0 == xPath->segs[0].y1 &&
- xPath->segs[0].y0 == xPath->segs[1].y0 &&
- xPath->segs[0].y0 == xPath->segs[3].y1 &&
- xPath->segs[2].y0 == xPath->segs[2].y1 &&
- xPath->segs[2].y0 == xPath->segs[1].y1 &&
- xPath->segs[2].y0 == xPath->segs[3].y0 &&
- xPath->segs[1].x0 == xPath->segs[1].x1 &&
- xPath->segs[1].x0 == xPath->segs[0].x1 &&
- xPath->segs[1].x0 == xPath->segs[2].x0 &&
- xPath->segs[3].x0 == xPath->segs[3].x1 &&
- xPath->segs[3].x0 == xPath->segs[0].x0 &&
- xPath->segs[3].x0 == xPath->segs[2].x1))) {
- clipToRect(xPath->segs[0].x0, xPath->segs[0].y0,
- xPath->segs[2].x0, xPath->segs[2].y0);
- delete xPath;
-
- } else {
- grow(1);
- if (antialias) {
- xPath->aaScale();
+SplashClipResult SplashClip::testSpan(int spanXMin, int spanXMax, int spanY)
+{
+ int i;
+
+ // This tests the rectangle:
+ // x = [spanXMin, spanXMax + 1) (note: span coords are ints)
+ // y = [spanY, spanY + 1)
+ // against the clipping region:
+ // x = [xMin, xMax) (note: clipping coords are fp)
+ // y = [yMin, yMax)
+ if ((SplashCoord)(spanXMax + 1) <= xMin || (SplashCoord)spanXMin >= xMax || (SplashCoord)(spanY + 1) <= yMin || (SplashCoord)spanY >= yMax) {
+ return splashClipAllOutside;
+ }
+ if (!((SplashCoord)spanXMin >= xMin && (SplashCoord)(spanXMax + 1) <= xMax && (SplashCoord)spanY >= yMin && (SplashCoord)(spanY + 1) <= yMax)) {
+ return splashClipPartial;
}
- xPath->sort();
- paths[length] = xPath;
- flags[length] = eo ? splashClipEO : 0;
if (antialias) {
- yMinAA = yMinI * splashAASize;
- yMaxAA = (yMaxI + 1) * splashAASize - 1;
+ for (i = 0; i < length; ++i) {
+ if (!scanners[i]->testSpan(spanXMin * splashAASize, spanXMax * splashAASize + (splashAASize - 1), spanY * splashAASize)) {
+ return splashClipPartial;
+ }
+ }
} else {
- yMinAA = yMinI;
- yMaxAA = yMaxI;
+ for (i = 0; i < length; ++i) {
+ if (!scanners[i]->testSpan(spanXMin, spanXMax, spanY)) {
+ return splashClipPartial;
+ }
+ }
}
- scanners[length] = new SplashXPathScanner(xPath, eo, yMinAA, yMaxAA);
- ++length;
- }
-
- return splashOk;
-}
-
-SplashClipResult SplashClip::testRect(int rectXMin, int rectYMin,
- int rectXMax, int rectYMax) {
- // This tests the rectangle:
- // x = [rectXMin, rectXMax + 1) (note: rect coords are ints)
- // y = [rectYMin, rectYMax + 1)
- // against the clipping region:
- // x = [xMin, xMax) (note: clipping coords are fp)
- // y = [yMin, yMax)
- if ((SplashCoord)(rectXMax + 1) <= xMin || (SplashCoord)rectXMin >= xMax ||
- (SplashCoord)(rectYMax + 1) <= yMin || (SplashCoord)rectYMin >= yMax) {
- return splashClipAllOutside;
- }
- if ((SplashCoord)rectXMin >= xMin && (SplashCoord)(rectXMax + 1) <= xMax &&
- (SplashCoord)rectYMin >= yMin && (SplashCoord)(rectYMax + 1) <= yMax &&
- length == 0) {
return splashClipAllInside;
- }
- return splashClipPartial;
}
-SplashClipResult SplashClip::testSpan(int spanXMin, int spanXMax, int spanY) {
- int i;
-
- // This tests the rectangle:
- // x = [spanXMin, spanXMax + 1) (note: span coords are ints)
- // y = [spanY, spanY + 1)
- // against the clipping region:
- // x = [xMin, xMax) (note: clipping coords are fp)
- // y = [yMin, yMax)
- if ((SplashCoord)(spanXMax + 1) <= xMin || (SplashCoord)spanXMin >= xMax ||
- (SplashCoord)(spanY + 1) <= yMin || (SplashCoord)spanY >= yMax) {
- return splashClipAllOutside;
- }
- if (!((SplashCoord)spanXMin >= xMin && (SplashCoord)(spanXMax + 1) <= xMax &&
- (SplashCoord)spanY >= yMin && (SplashCoord)(spanY + 1) <= yMax)) {
- return splashClipPartial;
- }
- if (antialias) {
- for (i = 0; i < length; ++i) {
- if (!scanners[i]->testSpan(spanXMin * splashAASize,
- spanXMax * splashAASize + (splashAASize - 1),
- spanY * splashAASize)) {
- return splashClipPartial;
- }
+void SplashClip::clipAALine(SplashBitmap *aaBuf, int *x0, int *x1, int y, bool adjustVertLine)
+{
+ int xx0, xx1, xx, yy, i;
+ SplashColorPtr p;
+
+ // zero out pixels with x < xMin
+ xx0 = *x0 * splashAASize;
+ xx1 = splashFloor(xMin * splashAASize);
+ if (xx1 > aaBuf->getWidth()) {
+ xx1 = aaBuf->getWidth();
}
- } else {
- for (i = 0; i < length; ++i) {
- if (!scanners[i]->testSpan(spanXMin, spanXMax, spanY)) {
- return splashClipPartial;
- }
+ if (xx0 < xx1) {
+ xx0 &= ~7;
+ for (yy = 0; yy < splashAASize; ++yy) {
+ p = aaBuf->getDataPtr() + yy * aaBuf->getRowSize() + (xx0 >> 3);
+ for (xx = xx0; xx + 7 < xx1; xx += 8) {
+ *p++ = 0;
+ }
+ if (xx < xx1 && !adjustVertLine) {
+ *p &= 0xff >> (xx1 & 7);
+ }
+ }
+ *x0 = splashFloor(xMin);
}
- }
- return splashClipAllInside;
-}
-void SplashClip::clipAALine(SplashBitmap *aaBuf, int *x0, int *x1, int y, bool adjustVertLine) {
- int xx0, xx1, xx, yy, i;
- SplashColorPtr p;
-
- // zero out pixels with x < xMin
- xx0 = *x0 * splashAASize;
- xx1 = splashFloor(xMin * splashAASize);
- if (xx1 > aaBuf->getWidth()) {
- xx1 = aaBuf->getWidth();
- }
- if (xx0 < xx1) {
- xx0 &= ~7;
- for (yy = 0; yy < splashAASize; ++yy) {
- p = aaBuf->getDataPtr() + yy * aaBuf->getRowSize() + (xx0 >> 3);
- for (xx = xx0; xx + 7 < xx1; xx += 8) {
- *p++ = 0;
- }
- if (xx < xx1 && !adjustVertLine) {
- *p &= 0xff >> (xx1 & 7);
- }
+ // zero out pixels with x > xMax
+ xx0 = splashFloor(xMax * splashAASize) + 1;
+ if (xx0 < 0) {
+ xx0 = 0;
}
- *x0 = splashFloor(xMin);
- }
-
- // zero out pixels with x > xMax
- xx0 = splashFloor(xMax * splashAASize) + 1;
- if (xx0 < 0) {
- xx0 = 0;
- }
- xx1 = (*x1 + 1) * splashAASize;
- if (xx0 < xx1 && !adjustVertLine) {
- for (yy = 0; yy < splashAASize; ++yy) {
- p = aaBuf->getDataPtr() + yy * aaBuf->getRowSize() + (xx0 >> 3);
- xx = xx0;
- if (xx & 7) {
- *p &= 0xff00 >> (xx & 7);
- xx = (xx & ~7) + 8;
- ++p;
- }
- for (; xx < xx1; xx += 8) {
- *p++ = 0;
- }
+ xx1 = (*x1 + 1) * splashAASize;
+ if (xx0 < xx1 && !adjustVertLine) {
+ for (yy = 0; yy < splashAASize; ++yy) {
+ p = aaBuf->getDataPtr() + yy * aaBuf->getRowSize() + (xx0 >> 3);
+ xx = xx0;
+ if (xx & 7) {
+ *p &= 0xff00 >> (xx & 7);
+ xx = (xx & ~7) + 8;
+ ++p;
+ }
+ for (; xx < xx1; xx += 8) {
+ *p++ = 0;
+ }
+ }
+ *x1 = splashFloor(xMax);
}
- *x1 = splashFloor(xMax);
- }
-
- // check the paths
- for (i = 0; i < length; ++i) {
- scanners[i]->clipAALine(aaBuf, x0, x1, y);
- }
- if (*x0 > *x1) {
- *x0 = *x1;
- }
- if (*x0 < 0) {
- *x0 = 0;
- }
- if ((*x0>>1) >= aaBuf->getRowSize()) {
- xx0 = *x0;
- *x0 = (aaBuf->getRowSize() - 1) << 1;
- if (xx0 & 1) {
- *x0 = *x0 + 1;
+
+ // check the paths
+ for (i = 0; i < length; ++i) {
+ scanners[i]->clipAALine(aaBuf, x0, x1, y);
}
- }
- if (*x1 < *x0) {
- *x1 = *x0;
- }
- if ((*x1>>1) >= aaBuf->getRowSize()) {
- xx0 = *x1;
- *x1 = (aaBuf->getRowSize() - 1) << 1;
- if (xx0 & 1) {
- *x1 = *x1 + 1;
+ if (*x0 > *x1) {
+ *x0 = *x1;
+ }
+ if (*x0 < 0) {
+ *x0 = 0;
+ }
+ if ((*x0 >> 1) >= aaBuf->getRowSize()) {
+ xx0 = *x0;
+ *x0 = (aaBuf->getRowSize() - 1) << 1;
+ if (xx0 & 1) {
+ *x0 = *x0 + 1;
+ }
+ }
+ if (*x1 < *x0) {
+ *x1 = *x0;
+ }
+ if ((*x1 >> 1) >= aaBuf->getRowSize()) {
+ xx0 = *x1;
+ *x1 = (aaBuf->getRowSize() - 1) << 1;
+ if (xx0 & 1) {
+ *x1 = *x1 + 1;
+ }
}
- }
}
-bool SplashClip::testClipPaths(int x, int y) {
- if (antialias) {
- x *= splashAASize;
- y *= splashAASize;
- }
+bool SplashClip::testClipPaths(int x, int y)
+{
+ if (antialias) {
+ x *= splashAASize;
+ y *= splashAASize;
+ }
- for (int i = 0; i < length; ++i) {
- if (!scanners[i]->test(x, y)) {
- return false;
+ for (int i = 0; i < length; ++i) {
+ if (!scanners[i]->test(x, y)) {
+ return false;
+ }
}
- }
- return true;
+ return true;
}
diff --git a/splash/SplashClip.h b/splash/SplashClip.h
index f91df1fb..a85f8642 100644
--- a/splash/SplashClip.h
+++ b/splash/SplashClip.h
@@ -32,105 +32,98 @@ class SplashBitmap;
//------------------------------------------------------------------------
-enum SplashClipResult {
- splashClipAllInside,
- splashClipAllOutside,
- splashClipPartial
+enum SplashClipResult
+{
+ splashClipAllInside,
+ splashClipAllOutside,
+ splashClipPartial
};
//------------------------------------------------------------------------
// SplashClip
//------------------------------------------------------------------------
-class SplashClip {
+class SplashClip
+{
public:
+ // Create a clip, for the given rectangle.
+ SplashClip(SplashCoord x0, SplashCoord y0, SplashCoord x1, SplashCoord y1, bool antialiasA);
- // Create a clip, for the given rectangle.
- SplashClip(SplashCoord x0, SplashCoord y0,
- SplashCoord x1, SplashCoord y1,
- bool antialiasA);
+ // Copy a clip.
+ SplashClip *copy() { return new SplashClip(this); }
- // Copy a clip.
- SplashClip *copy() { return new SplashClip(this); }
+ ~SplashClip();
- ~SplashClip();
+ SplashClip(const SplashClip &) = delete;
+ SplashClip &operator=(const SplashClip &) = delete;
- SplashClip(const SplashClip &) = delete;
- SplashClip& operator=(const SplashClip &) = delete;
+ // Reset the clip to a rectangle.
+ void resetToRect(SplashCoord x0, SplashCoord y0, SplashCoord x1, SplashCoord y1);
- // Reset the clip to a rectangle.
- void resetToRect(SplashCoord x0, SplashCoord y0,
- SplashCoord x1, SplashCoord y1);
+ // Intersect the clip with a rectangle.
+ SplashError clipToRect(SplashCoord x0, SplashCoord y0, SplashCoord x1, SplashCoord y1);
- // Intersect the clip with a rectangle.
- SplashError clipToRect(SplashCoord x0, SplashCoord y0,
- SplashCoord x1, SplashCoord y1);
+ // Intersect the clip with <path>.
+ SplashError clipToPath(SplashPath *path, SplashCoord *matrix, SplashCoord flatness, bool eo);
- // Intersect the clip with <path>.
- SplashError clipToPath(SplashPath *path, SplashCoord *matrix,
- SplashCoord flatness, bool eo);
+ // Returns true if (<x>,<y>) is inside the clip.
+ bool test(int x, int y)
+ {
+ // check the rectangle
+ if (x < xMinI || x > xMaxI || y < yMinI || y > yMaxI) {
+ return false;
+ }
- // Returns true if (<x>,<y>) is inside the clip.
- bool test(int x, int y)
- {
- // check the rectangle
- if (x < xMinI || x > xMaxI || y < yMinI || y > yMaxI) {
- return false;
+ // check the paths
+ return testClipPaths(x, y);
}
- // check the paths
- return testClipPaths(x, y);
- }
-
- // Tests a rectangle against the clipping region. Returns one of:
- // - splashClipAllInside if the entire rectangle is inside the
- // clipping region, i.e., all pixels in the rectangle are
- // visible
- // - splashClipAllOutside if the entire rectangle is outside the
- // clipping region, i.e., all the pixels in the rectangle are
- // clipped
- // - splashClipPartial if the rectangle is part inside and part
- // outside the clipping region
- SplashClipResult testRect(int rectXMin, int rectYMin,
- int rectXMax, int rectYMax);
-
- // Similar to testRect, but tests a horizontal span.
- SplashClipResult testSpan(int spanXMin, int spanXMax, int spanY);
-
- // Clips an anti-aliased line by setting pixels to zero. On entry,
- // all non-zero pixels are between <x0> and <x1>. This function
- // will update <x0> and <x1>.
- void clipAALine(SplashBitmap *aaBuf, int *x0, int *x1, int y,
- bool adjustVertLine = false);
-
- // Get the rectangle part of the clip region.
- SplashCoord getXMin() { return xMin; }
- SplashCoord getXMax() { return xMax; }
- SplashCoord getYMin() { return yMin; }
- SplashCoord getYMax() { return yMax; }
-
- // Get the rectangle part of the clip region, in integer coordinates.
- int getXMinI() { return xMinI; }
- int getXMaxI() { return xMaxI; }
- int getYMinI() { return yMinI; }
- int getYMaxI() { return yMaxI; }
-
- // Get the number of arbitrary paths used by the clip region.
- int getNumPaths() { return length; }
+ // Tests a rectangle against the clipping region. Returns one of:
+ // - splashClipAllInside if the entire rectangle is inside the
+ // clipping region, i.e., all pixels in the rectangle are
+ // visible
+ // - splashClipAllOutside if the entire rectangle is outside the
+ // clipping region, i.e., all the pixels in the rectangle are
+ // clipped
+ // - splashClipPartial if the rectangle is part inside and part
+ // outside the clipping region
+ SplashClipResult testRect(int rectXMin, int rectYMin, int rectXMax, int rectYMax);
+
+ // Similar to testRect, but tests a horizontal span.
+ SplashClipResult testSpan(int spanXMin, int spanXMax, int spanY);
+
+ // Clips an anti-aliased line by setting pixels to zero. On entry,
+ // all non-zero pixels are between <x0> and <x1>. This function
+ // will update <x0> and <x1>.
+ void clipAALine(SplashBitmap *aaBuf, int *x0, int *x1, int y, bool adjustVertLine = false);
+
+ // Get the rectangle part of the clip region.
+ SplashCoord getXMin() { return xMin; }
+ SplashCoord getXMax() { return xMax; }
+ SplashCoord getYMin() { return yMin; }
+ SplashCoord getYMax() { return yMax; }
+
+ // Get the rectangle part of the clip region, in integer coordinates.
+ int getXMinI() { return xMinI; }
+ int getXMaxI() { return xMaxI; }
+ int getYMinI() { return yMinI; }
+ int getYMaxI() { return yMaxI; }
+
+ // Get the number of arbitrary paths used by the clip region.
+ int getNumPaths() { return length; }
protected:
-
- SplashClip(SplashClip *clip);
- void grow(int nPaths);
- bool testClipPaths(int x, int y);
-
- bool antialias;
- SplashCoord xMin, yMin, xMax, yMax;
- int xMinI, yMinI, xMaxI, yMaxI;
- SplashXPath **paths;
- unsigned char *flags;
- SplashXPathScanner **scanners;
- int length, size;
+ SplashClip(SplashClip *clip);
+ void grow(int nPaths);
+ bool testClipPaths(int x, int y);
+
+ bool antialias;
+ SplashCoord xMin, yMin, xMax, yMax;
+ int xMinI, yMinI, xMaxI, yMaxI;
+ SplashXPath **paths;
+ unsigned char *flags;
+ SplashXPathScanner **scanners;
+ int length, size;
};
#endif
diff --git a/splash/SplashErrorCodes.h b/splash/SplashErrorCodes.h
index d1f81f85..10efd6db 100644
--- a/splash/SplashErrorCodes.h
+++ b/splash/SplashErrorCodes.h
@@ -23,28 +23,28 @@
//------------------------------------------------------------------------
-#define splashOk 0 // no error
+#define splashOk 0 // no error
-#define splashErrNoCurPt 1 // no current point
+#define splashErrNoCurPt 1 // no current point
-#define splashErrEmptyPath 2 // zero points in path
+#define splashErrEmptyPath 2 // zero points in path
-#define splashErrBogusPath 3 // only one point in subpath
+#define splashErrBogusPath 3 // only one point in subpath
-#define splashErrNoSave 4 // state stack is empty
+#define splashErrNoSave 4 // state stack is empty
-#define splashErrOpenFile 5 // couldn't open file
+#define splashErrOpenFile 5 // couldn't open file
-#define splashErrNoGlyph 6 // couldn't get the requested glyph
+#define splashErrNoGlyph 6 // couldn't get the requested glyph
-#define splashErrModeMismatch 7 // invalid combination of color modes
+#define splashErrModeMismatch 7 // invalid combination of color modes
-#define splashErrSingularMatrix 8 // matrix is singular
+#define splashErrSingularMatrix 8 // matrix is singular
-#define splashErrBadArg 9 // bad argument
+#define splashErrBadArg 9 // bad argument
-#define splashErrZeroImage 254 // image of 0x0
+#define splashErrZeroImage 254 // image of 0x0
-#define splashErrGeneric 255
+#define splashErrGeneric 255
#endif
diff --git a/splash/SplashFTFont.cc b/splash/SplashFTFont.cc
index 48cfb39d..4cafbba4 100644
--- a/splash/SplashFTFont.cc
+++ b/splash/SplashFTFont.cc
@@ -45,412 +45,388 @@
static int glyphPathMoveTo(const FT_Vector *pt, void *path);
static int glyphPathLineTo(const FT_Vector *pt, void *path);
-static int glyphPathConicTo(const FT_Vector *ctrl, const FT_Vector *pt,
- void *path);
-static int glyphPathCubicTo(const FT_Vector *ctrl1, const FT_Vector *ctrl2,
- const FT_Vector *pt, void *path);
+static int glyphPathConicTo(const FT_Vector *ctrl, const FT_Vector *pt, void *path);
+static int glyphPathCubicTo(const FT_Vector *ctrl1, const FT_Vector *ctrl2, const FT_Vector *pt, void *path);
//------------------------------------------------------------------------
// SplashFTFont
//------------------------------------------------------------------------
-SplashFTFont::SplashFTFont(SplashFTFontFile *fontFileA, SplashCoord *matA,
- const SplashCoord *textMatA):
- SplashFont(fontFileA, matA, textMatA, fontFileA->engine->aa),
- textScale(0),
- enableFreeTypeHinting(fontFileA->engine->enableFreeTypeHinting),
- enableSlightHinting(fontFileA->engine->enableSlightHinting),
- isOk(false)
+SplashFTFont::SplashFTFont(SplashFTFontFile *fontFileA, SplashCoord *matA, const SplashCoord *textMatA)
+ : SplashFont(fontFileA, matA, textMatA, fontFileA->engine->aa), textScale(0), enableFreeTypeHinting(fontFileA->engine->enableFreeTypeHinting), enableSlightHinting(fontFileA->engine->enableSlightHinting), isOk(false)
{
- FT_Face face;
- int div;
- int x, y;
-
- face = fontFileA->face;
- if (FT_New_Size(face, &sizeObj)) {
- return;
- }
- face->size = sizeObj;
- size = splashRound(splashDist(0, 0, mat[2], mat[3]));
- if (size < 1) {
- size = 1;
- }
- if (FT_Set_Pixel_Sizes(face, 0, size)) {
- return;
- }
- // if the textMat values are too small, FreeType's fixed point
- // arithmetic doesn't work so well
- textScale = splashDist(0, 0, textMat[2], textMat[3]) / size;
-
- if (unlikely(textScale == 0 || face->units_per_EM == 0)) {
- return;
- }
-
- div = face->bbox.xMax > 20000 ? 65536 : 1;
-
- // transform the four corners of the font bounding box -- the min
- // and max values form the bounding box of the transformed font
- x = (int)((mat[0] * face->bbox.xMin + mat[2] * face->bbox.yMin) /
- (div * face->units_per_EM));
- xMin = xMax = x;
- y = (int)((mat[1] * face->bbox.xMin + mat[3] * face->bbox.yMin) /
- (div * face->units_per_EM));
- yMin = yMax = y;
- x = (int)((mat[0] * face->bbox.xMin + mat[2] * face->bbox.yMax) /
- (div * face->units_per_EM));
- if (x < xMin) {
- xMin = x;
- } else if (x > xMax) {
- xMax = x;
- }
- y = (int)((mat[1] * face->bbox.xMin + mat[3] * face->bbox.yMax) /
- (div * face->units_per_EM));
- if (y < yMin) {
- yMin = y;
- } else if (y > yMax) {
- yMax = y;
- }
- x = (int)((mat[0] * face->bbox.xMax + mat[2] * face->bbox.yMin) /
- (div * face->units_per_EM));
- if (x < xMin) {
- xMin = x;
- } else if (x > xMax) {
- xMax = x;
- }
- y = (int)((mat[1] * face->bbox.xMax + mat[3] * face->bbox.yMin) /
- (div * face->units_per_EM));
- if (y < yMin) {
- yMin = y;
- } else if (y > yMax) {
- yMax = y;
- }
- x = (int)((mat[0] * face->bbox.xMax + mat[2] * face->bbox.yMax) /
- (div * face->units_per_EM));
- if (x < xMin) {
- xMin = x;
- } else if (x > xMax) {
- xMax = x;
- }
- y = (int)((mat[1] * face->bbox.xMax + mat[3] * face->bbox.yMax) /
- (div * face->units_per_EM));
- if (y < yMin) {
- yMin = y;
- } else if (y > yMax) {
- yMax = y;
- }
- // This is a kludge: some buggy PDF generators embed fonts with
- // zero bounding boxes.
- if (xMax == xMin) {
- xMin = 0;
- xMax = size;
- }
- if (yMax == yMin) {
- yMin = 0;
- yMax = (int)((SplashCoord)1.2 * size);
- }
-
- // compute the transform matrix
- matrix.xx = (FT_Fixed)((mat[0] / size) * 65536);
- matrix.yx = (FT_Fixed)((mat[1] / size) * 65536);
- matrix.xy = (FT_Fixed)((mat[2] / size) * 65536);
- matrix.yy = (FT_Fixed)((mat[3] / size) * 65536);
- textMatrix.xx = (FT_Fixed)((textMat[0] / (textScale * size)) * 65536);
- textMatrix.yx = (FT_Fixed)((textMat[1] / (textScale * size)) * 65536);
- textMatrix.xy = (FT_Fixed)((textMat[2] / (textScale * size)) * 65536);
- textMatrix.yy = (FT_Fixed)((textMat[3] / (textScale * size)) * 65536);
-
- isOk = true;
-}
+ FT_Face face;
+ int div;
+ int x, y;
+
+ face = fontFileA->face;
+ if (FT_New_Size(face, &sizeObj)) {
+ return;
+ }
+ face->size = sizeObj;
+ size = splashRound(splashDist(0, 0, mat[2], mat[3]));
+ if (size < 1) {
+ size = 1;
+ }
+ if (FT_Set_Pixel_Sizes(face, 0, size)) {
+ return;
+ }
+ // if the textMat values are too small, FreeType's fixed point
+ // arithmetic doesn't work so well
+ textScale = splashDist(0, 0, textMat[2], textMat[3]) / size;
+
+ if (unlikely(textScale == 0 || face->units_per_EM == 0)) {
+ return;
+ }
+
+ div = face->bbox.xMax > 20000 ? 65536 : 1;
+
+ // transform the four corners of the font bounding box -- the min
+ // and max values form the bounding box of the transformed font
+ x = (int)((mat[0] * face->bbox.xMin + mat[2] * face->bbox.yMin) / (div * face->units_per_EM));
+ xMin = xMax = x;
+ y = (int)((mat[1] * face->bbox.xMin + mat[3] * face->bbox.yMin) / (div * face->units_per_EM));
+ yMin = yMax = y;
+ x = (int)((mat[0] * face->bbox.xMin + mat[2] * face->bbox.yMax) / (div * face->units_per_EM));
+ if (x < xMin) {
+ xMin = x;
+ } else if (x > xMax) {
+ xMax = x;
+ }
+ y = (int)((mat[1] * face->bbox.xMin + mat[3] * face->bbox.yMax) / (div * face->units_per_EM));
+ if (y < yMin) {
+ yMin = y;
+ } else if (y > yMax) {
+ yMax = y;
+ }
+ x = (int)((mat[0] * face->bbox.xMax + mat[2] * face->bbox.yMin) / (div * face->units_per_EM));
+ if (x < xMin) {
+ xMin = x;
+ } else if (x > xMax) {
+ xMax = x;
+ }
+ y = (int)((mat[1] * face->bbox.xMax + mat[3] * face->bbox.yMin) / (div * face->units_per_EM));
+ if (y < yMin) {
+ yMin = y;
+ } else if (y > yMax) {
+ yMax = y;
+ }
+ x = (int)((mat[0] * face->bbox.xMax + mat[2] * face->bbox.yMax) / (div * face->units_per_EM));
+ if (x < xMin) {
+ xMin = x;
+ } else if (x > xMax) {
+ xMax = x;
+ }
+ y = (int)((mat[1] * face->bbox.xMax + mat[3] * face->bbox.yMax) / (div * face->units_per_EM));
+ if (y < yMin) {
+ yMin = y;
+ } else if (y > yMax) {
+ yMax = y;
+ }
+ // This is a kludge: some buggy PDF generators embed fonts with
+ // zero bounding boxes.
+ if (xMax == xMin) {
+ xMin = 0;
+ xMax = size;
+ }
+ if (yMax == yMin) {
+ yMin = 0;
+ yMax = (int)((SplashCoord)1.2 * size);
+ }
-SplashFTFont::~SplashFTFont() {
+ // compute the transform matrix
+ matrix.xx = (FT_Fixed)((mat[0] / size) * 65536);
+ matrix.yx = (FT_Fixed)((mat[1] / size) * 65536);
+ matrix.xy = (FT_Fixed)((mat[2] / size) * 65536);
+ matrix.yy = (FT_Fixed)((mat[3] / size) * 65536);
+ textMatrix.xx = (FT_Fixed)((textMat[0] / (textScale * size)) * 65536);
+ textMatrix.yx = (FT_Fixed)((textMat[1] / (textScale * size)) * 65536);
+ textMatrix.xy = (FT_Fixed)((textMat[2] / (textScale * size)) * 65536);
+ textMatrix.yy = (FT_Fixed)((textMat[3] / (textScale * size)) * 65536);
+
+ isOk = true;
}
-bool SplashFTFont::getGlyph(int c, int xFrac, int yFrac,
- SplashGlyphBitmap *bitmap, int x0, int y0, SplashClip *clip, SplashClipResult *clipRes) {
- return SplashFont::getGlyph(c, xFrac, 0, bitmap, x0, y0, clip, clipRes);
+SplashFTFont::~SplashFTFont() { }
+
+bool SplashFTFont::getGlyph(int c, int xFrac, int yFrac, SplashGlyphBitmap *bitmap, int x0, int y0, SplashClip *clip, SplashClipResult *clipRes)
+{
+ return SplashFont::getGlyph(c, xFrac, 0, bitmap, x0, y0, clip, clipRes);
}
static FT_Int32 getFTLoadFlags(bool type1, bool trueType, bool aa, bool enableFreeTypeHinting, bool enableSlightHinting)
{
- int ret = FT_LOAD_DEFAULT;
- if (aa)
- ret |= FT_LOAD_NO_BITMAP;
-
- if (enableFreeTypeHinting) {
- if (enableSlightHinting) {
- ret |= FT_LOAD_TARGET_LIGHT;
+ int ret = FT_LOAD_DEFAULT;
+ if (aa)
+ ret |= FT_LOAD_NO_BITMAP;
+
+ if (enableFreeTypeHinting) {
+ if (enableSlightHinting) {
+ ret |= FT_LOAD_TARGET_LIGHT;
+ } else {
+ if (trueType) {
+ // FT2's autohinting doesn't always work very well (especially with
+ // font subsets), so turn it off if anti-aliasing is enabled; if
+ // anti-aliasing is disabled, this seems to be a tossup - some fonts
+ // look better with hinting, some without, so leave hinting on
+ if (aa) {
+ ret |= FT_LOAD_NO_AUTOHINT;
+ }
+ } else if (type1) {
+ // Type 1 fonts seem to look better with 'light' hinting mode
+ ret |= FT_LOAD_TARGET_LIGHT;
+ }
+ }
} else {
- if (trueType) {
- // FT2's autohinting doesn't always work very well (especially with
- // font subsets), so turn it off if anti-aliasing is enabled; if
- // anti-aliasing is disabled, this seems to be a tossup - some fonts
- // look better with hinting, some without, so leave hinting on
- if (aa) {
- ret |= FT_LOAD_NO_AUTOHINT;
- }
- } else if (type1) {
- // Type 1 fonts seem to look better with 'light' hinting mode
- ret |= FT_LOAD_TARGET_LIGHT;
- }
- }
- } else {
- ret |= FT_LOAD_NO_HINTING;
- }
- return ret;
+ ret |= FT_LOAD_NO_HINTING;
+ }
+ return ret;
}
-bool SplashFTFont::makeGlyph(int c, int xFrac, int yFrac,
- SplashGlyphBitmap *bitmap, int x0, int y0, SplashClip *clip, SplashClipResult *clipRes) {
- SplashFTFontFile *ff;
- FT_Vector offset;
- FT_GlyphSlot slot;
- FT_UInt gid;
- int rowSize;
- unsigned char *p, *q;
- int i;
-
- if (unlikely(!isOk)) {
- return false;
- }
-
- ff = (SplashFTFontFile *)fontFile;
-
- ff->face->size = sizeObj;
- offset.x = (FT_Pos)(int)((SplashCoord)xFrac * splashFontFractionMul * 64);
- offset.y = 0;
- FT_Set_Transform(ff->face, &matrix, &offset);
- slot = ff->face->glyph;
-
- if (ff->codeToGID && c < ff->codeToGIDLen && c >= 0) {
- gid = (FT_UInt)ff->codeToGID[c];
- } else {
- gid = (FT_UInt)c;
- }
-
- if (FT_Load_Glyph(ff->face, gid, getFTLoadFlags(ff->type1, ff->trueType, aa, enableFreeTypeHinting, enableSlightHinting))) {
- return false;
- }
-
- // prelimirary values based on FT_Outline_Get_CBox
- // we add two pixels to each side to be in the safe side
- FT_BBox cbox;
- FT_Outline_Get_CBox(&ff->face->glyph->outline, &cbox);
- bitmap->x = -(cbox.xMin / 64) + 2;
- bitmap->y = (cbox.yMax / 64) + 2;
- bitmap->w = ((cbox.xMax - cbox.xMin) / 64) + 4;
- bitmap->h = ((cbox.yMax - cbox.yMin) / 64) + 4;
-
- *clipRes = clip->testRect(x0 - bitmap->x,
- y0 - bitmap->y,
- x0 - bitmap->x + bitmap->w,
- y0 - bitmap->y + bitmap->h);
- if (*clipRes == splashClipAllOutside) {
- bitmap->freeData = false;
+bool SplashFTFont::makeGlyph(int c, int xFrac, int yFrac, SplashGlyphBitmap *bitmap, int x0, int y0, SplashClip *clip, SplashClipResult *clipRes)
+{
+ SplashFTFontFile *ff;
+ FT_Vector offset;
+ FT_GlyphSlot slot;
+ FT_UInt gid;
+ int rowSize;
+ unsigned char *p, *q;
+ int i;
+
+ if (unlikely(!isOk)) {
+ return false;
+ }
+
+ ff = (SplashFTFontFile *)fontFile;
+
+ ff->face->size = sizeObj;
+ offset.x = (FT_Pos)(int)((SplashCoord)xFrac * splashFontFractionMul * 64);
+ offset.y = 0;
+ FT_Set_Transform(ff->face, &matrix, &offset);
+ slot = ff->face->glyph;
+
+ if (ff->codeToGID && c < ff->codeToGIDLen && c >= 0) {
+ gid = (FT_UInt)ff->codeToGID[c];
+ } else {
+ gid = (FT_UInt)c;
+ }
+
+ if (FT_Load_Glyph(ff->face, gid, getFTLoadFlags(ff->type1, ff->trueType, aa, enableFreeTypeHinting, enableSlightHinting))) {
+ return false;
+ }
+
+ // prelimirary values based on FT_Outline_Get_CBox
+ // we add two pixels to each side to be in the safe side
+ FT_BBox cbox;
+ FT_Outline_Get_CBox(&ff->face->glyph->outline, &cbox);
+ bitmap->x = -(cbox.xMin / 64) + 2;
+ bitmap->y = (cbox.yMax / 64) + 2;
+ bitmap->w = ((cbox.xMax - cbox.xMin) / 64) + 4;
+ bitmap->h = ((cbox.yMax - cbox.yMin) / 64) + 4;
+
+ *clipRes = clip->testRect(x0 - bitmap->x, y0 - bitmap->y, x0 - bitmap->x + bitmap->w, y0 - bitmap->y + bitmap->h);
+ if (*clipRes == splashClipAllOutside) {
+ bitmap->freeData = false;
+ return true;
+ }
+
+ if (FT_Render_Glyph(slot, aa ? ft_render_mode_normal : ft_render_mode_mono)) {
+ return false;
+ }
+
+ if (slot->bitmap.width == 0 || slot->bitmap.rows == 0) {
+ // this can happen if (a) the glyph is really tiny or (b) the
+ // metrics in the TrueType file are broken
+ return false;
+ }
+
+ bitmap->x = -slot->bitmap_left;
+ bitmap->y = slot->bitmap_top;
+ bitmap->w = slot->bitmap.width;
+ bitmap->h = slot->bitmap.rows;
+ bitmap->aa = aa;
+ if (aa) {
+ rowSize = bitmap->w;
+ } else {
+ rowSize = (bitmap->w + 7) >> 3;
+ }
+ bitmap->data = (unsigned char *)gmallocn_checkoverflow(rowSize, bitmap->h);
+ if (!bitmap->data) {
+ return false;
+ }
+ bitmap->freeData = true;
+ for (i = 0, p = bitmap->data, q = slot->bitmap.buffer; i < bitmap->h; ++i, p += rowSize, q += slot->bitmap.pitch) {
+ memcpy(p, q, rowSize);
+ }
+
return true;
- }
-
- if (FT_Render_Glyph(slot, aa ? ft_render_mode_normal
- : ft_render_mode_mono)) {
- return false;
- }
-
- if (slot->bitmap.width == 0 || slot->bitmap.rows == 0) {
- // this can happen if (a) the glyph is really tiny or (b) the
- // metrics in the TrueType file are broken
- return false;
- }
-
- bitmap->x = -slot->bitmap_left;
- bitmap->y = slot->bitmap_top;
- bitmap->w = slot->bitmap.width;
- bitmap->h = slot->bitmap.rows;
- bitmap->aa = aa;
- if (aa) {
- rowSize = bitmap->w;
- } else {
- rowSize = (bitmap->w + 7) >> 3;
- }
- bitmap->data = (unsigned char *)gmallocn_checkoverflow(rowSize, bitmap->h);
- if (!bitmap->data) {
- return false;
- }
- bitmap->freeData = true;
- for (i = 0, p = bitmap->data, q = slot->bitmap.buffer;
- i < bitmap->h;
- ++i, p += rowSize, q += slot->bitmap.pitch) {
- memcpy(p, q, rowSize);
- }
-
- return true;
}
double SplashFTFont::getGlyphAdvance(int c)
{
- SplashFTFontFile *ff;
- FT_Vector offset;
- FT_UInt gid;
- FT_Matrix identityMatrix;
-
- ff = (SplashFTFontFile *)fontFile;
-
- // init the matrix
- identityMatrix.xx = 65536; // 1 in 16.16 format
- identityMatrix.xy = 0;
- identityMatrix.yx = 0;
- identityMatrix.yy = 65536; // 1 in 16.16 format
-
- // init the offset
- offset.x = 0;
- offset.y = 0;
-
- ff->face->size = sizeObj;
- FT_Set_Transform(ff->face, &identityMatrix, &offset);
-
- if (ff->codeToGID && c < ff->codeToGIDLen) {
- gid = (FT_UInt)ff->codeToGID[c];
- } else {
- gid = (FT_UInt)c;
- }
-
- if (FT_Load_Glyph(ff->face, gid, getFTLoadFlags(ff->type1, ff->trueType, aa, enableFreeTypeHinting, enableSlightHinting))) {
- return -1;
- }
-
- // 64.0 is 1 in 26.6 format
- return ff->face->glyph->metrics.horiAdvance / 64.0 / size;
+ SplashFTFontFile *ff;
+ FT_Vector offset;
+ FT_UInt gid;
+ FT_Matrix identityMatrix;
+
+ ff = (SplashFTFontFile *)fontFile;
+
+ // init the matrix
+ identityMatrix.xx = 65536; // 1 in 16.16 format
+ identityMatrix.xy = 0;
+ identityMatrix.yx = 0;
+ identityMatrix.yy = 65536; // 1 in 16.16 format
+
+ // init the offset
+ offset.x = 0;
+ offset.y = 0;
+
+ ff->face->size = sizeObj;
+ FT_Set_Transform(ff->face, &identityMatrix, &offset);
+
+ if (ff->codeToGID && c < ff->codeToGIDLen) {
+ gid = (FT_UInt)ff->codeToGID[c];
+ } else {
+ gid = (FT_UInt)c;
+ }
+
+ if (FT_Load_Glyph(ff->face, gid, getFTLoadFlags(ff->type1, ff->trueType, aa, enableFreeTypeHinting, enableSlightHinting))) {
+ return -1;
+ }
+
+ // 64.0 is 1 in 26.6 format
+ return ff->face->glyph->metrics.horiAdvance / 64.0 / size;
}
-struct SplashFTFontPath {
- SplashPath *path;
- SplashCoord textScale;
- bool needClose;
+struct SplashFTFontPath
+{
+ SplashPath *path;
+ SplashCoord textScale;
+ bool needClose;
};
-SplashPath *SplashFTFont::getGlyphPath(int c) {
- static const FT_Outline_Funcs outlineFuncs = {
+SplashPath *SplashFTFont::getGlyphPath(int c)
+{
+ static const FT_Outline_Funcs outlineFuncs = {
#if FREETYPE_MINOR <= 1
- (int (*)(FT_Vector *, void *))&glyphPathMoveTo,
- (int (*)(FT_Vector *, void *))&glyphPathLineTo,
- (int (*)(FT_Vector *, FT_Vector *, void *))&glyphPathConicTo,
- (int (*)(FT_Vector *, FT_Vector *, FT_Vector *, void *))&glyphPathCubicTo,
+ (int (*)(FT_Vector *, void *)) & glyphPathMoveTo,
+ (int (*)(FT_Vector *, void *)) & glyphPathLineTo,
+ (int (*)(FT_Vector *, FT_Vector *, void *)) & glyphPathConicTo,
+ (int (*)(FT_Vector *, FT_Vector *, FT_Vector *, void *)) & glyphPathCubicTo,
#else
- &glyphPathMoveTo,
- &glyphPathLineTo,
- &glyphPathConicTo,
- &glyphPathCubicTo,
+ &glyphPathMoveTo,
+ &glyphPathLineTo,
+ &glyphPathConicTo,
+ &glyphPathCubicTo,
#endif
- 0, 0
- };
- SplashFTFontFile *ff;
- SplashFTFontPath path;
- FT_GlyphSlot slot;
- FT_UInt gid;
- FT_Glyph glyph;
-
- if (unlikely(textScale == 0)) {
- return nullptr;
- }
-
- ff = (SplashFTFontFile *)fontFile;
- ff->face->size = sizeObj;
- FT_Set_Transform(ff->face, &textMatrix, nullptr);
- slot = ff->face->glyph;
- if (ff->codeToGID && c < ff->codeToGIDLen && c >= 0) {
- gid = ff->codeToGID[c];
- } else {
- gid = (FT_UInt)c;
- }
- if (FT_Load_Glyph(ff->face, gid, getFTLoadFlags(ff->type1, ff->trueType, aa, enableFreeTypeHinting, enableSlightHinting))) {
- return nullptr;
- }
- if (FT_Get_Glyph(slot, &glyph)) {
- return nullptr;
- }
- if (FT_Outline_Check(&((FT_OutlineGlyph)glyph)->outline)) {
- return nullptr;
- }
- path.path = new SplashPath();
- path.textScale = textScale;
- path.needClose = false;
- FT_Outline_Decompose(&((FT_OutlineGlyph)glyph)->outline,
- &outlineFuncs, &path);
- if (path.needClose) {
- path.path->close();
- }
- FT_Done_Glyph(glyph);
- return path.path;
+ 0,
+ 0
+ };
+ SplashFTFontFile *ff;
+ SplashFTFontPath path;
+ FT_GlyphSlot slot;
+ FT_UInt gid;
+ FT_Glyph glyph;
+
+ if (unlikely(textScale == 0)) {
+ return nullptr;
+ }
+
+ ff = (SplashFTFontFile *)fontFile;
+ ff->face->size = sizeObj;
+ FT_Set_Transform(ff->face, &textMatrix, nullptr);
+ slot = ff->face->glyph;
+ if (ff->codeToGID && c < ff->codeToGIDLen && c >= 0) {
+ gid = ff->codeToGID[c];
+ } else {
+ gid = (FT_UInt)c;
+ }
+ if (FT_Load_Glyph(ff->face, gid, getFTLoadFlags(ff->type1, ff->trueType, aa, enableFreeTypeHinting, enableSlightHinting))) {
+ return nullptr;
+ }
+ if (FT_Get_Glyph(slot, &glyph)) {
+ return nullptr;
+ }
+ if (FT_Outline_Check(&((FT_OutlineGlyph)glyph)->outline)) {
+ return nullptr;
+ }
+ path.path = new SplashPath();
+ path.textScale = textScale;
+ path.needClose = false;
+ FT_Outline_Decompose(&((FT_OutlineGlyph)glyph)->outline, &outlineFuncs, &path);
+ if (path.needClose) {
+ path.path->close();
+ }
+ FT_Done_Glyph(glyph);
+ return path.path;
}
-static int glyphPathMoveTo(const FT_Vector *pt, void *path) {
- SplashFTFontPath *p = (SplashFTFontPath *)path;
+static int glyphPathMoveTo(const FT_Vector *pt, void *path)
+{
+ SplashFTFontPath *p = (SplashFTFontPath *)path;
- if (p->needClose) {
- p->path->close();
- p->needClose = false;
- }
- p->path->moveTo((SplashCoord)pt->x * p->textScale / 64.0,
- (SplashCoord)pt->y * p->textScale / 64.0);
- return 0;
+ if (p->needClose) {
+ p->path->close();
+ p->needClose = false;
+ }
+ p->path->moveTo((SplashCoord)pt->x * p->textScale / 64.0, (SplashCoord)pt->y * p->textScale / 64.0);
+ return 0;
}
-static int glyphPathLineTo(const FT_Vector *pt, void *path) {
- SplashFTFontPath *p = (SplashFTFontPath *)path;
+static int glyphPathLineTo(const FT_Vector *pt, void *path)
+{
+ SplashFTFontPath *p = (SplashFTFontPath *)path;
- p->path->lineTo((SplashCoord)pt->x * p->textScale / 64.0,
- (SplashCoord)pt->y * p->textScale / 64.0);
- p->needClose = true;
- return 0;
+ p->path->lineTo((SplashCoord)pt->x * p->textScale / 64.0, (SplashCoord)pt->y * p->textScale / 64.0);
+ p->needClose = true;
+ return 0;
}
-static int glyphPathConicTo(const FT_Vector *ctrl, const FT_Vector *pt,
- void *path) {
- SplashFTFontPath *p = (SplashFTFontPath *)path;
- SplashCoord x0, y0, x1, y1, x2, y2, x3, y3, xc, yc;
+static int glyphPathConicTo(const FT_Vector *ctrl, const FT_Vector *pt, void *path)
+{
+ SplashFTFontPath *p = (SplashFTFontPath *)path;
+ SplashCoord x0, y0, x1, y1, x2, y2, x3, y3, xc, yc;
- if (!p->path->getCurPt(&x0, &y0)) {
+ if (!p->path->getCurPt(&x0, &y0)) {
+ return 0;
+ }
+ xc = (SplashCoord)ctrl->x * p->textScale / 64.0;
+ yc = (SplashCoord)ctrl->y * p->textScale / 64.0;
+ x3 = (SplashCoord)pt->x * p->textScale / 64.0;
+ y3 = (SplashCoord)pt->y * p->textScale / 64.0;
+
+ // A second-order Bezier curve is defined by two endpoints, p0 and
+ // p3, and one control point, pc:
+ //
+ // p(t) = (1-t)^2*p0 + t*(1-t)*pc + t^2*p3
+ //
+ // A third-order Bezier curve is defined by the same two endpoints,
+ // p0 and p3, and two control points, p1 and p2:
+ //
+ // p(t) = (1-t)^3*p0 + 3t*(1-t)^2*p1 + 3t^2*(1-t)*p2 + t^3*p3
+ //
+ // Applying some algebra, we can convert a second-order curve to a
+ // third-order curve:
+ //
+ // p1 = (1/3) * (p0 + 2pc)
+ // p2 = (1/3) * (2pc + p3)
+
+ x1 = (SplashCoord)(1.0 / 3.0) * (x0 + (SplashCoord)2 * xc);
+ y1 = (SplashCoord)(1.0 / 3.0) * (y0 + (SplashCoord)2 * yc);
+ x2 = (SplashCoord)(1.0 / 3.0) * ((SplashCoord)2 * xc + x3);
+ y2 = (SplashCoord)(1.0 / 3.0) * ((SplashCoord)2 * yc + y3);
+
+ p->path->curveTo(x1, y1, x2, y2, x3, y3);
+ p->needClose = true;
return 0;
- }
- xc = (SplashCoord)ctrl->x * p->textScale / 64.0;
- yc = (SplashCoord)ctrl->y * p->textScale / 64.0;
- x3 = (SplashCoord)pt->x * p->textScale / 64.0;
- y3 = (SplashCoord)pt->y * p->textScale / 64.0;
-
- // A second-order Bezier curve is defined by two endpoints, p0 and
- // p3, and one control point, pc:
- //
- // p(t) = (1-t)^2*p0 + t*(1-t)*pc + t^2*p3
- //
- // A third-order Bezier curve is defined by the same two endpoints,
- // p0 and p3, and two control points, p1 and p2:
- //
- // p(t) = (1-t)^3*p0 + 3t*(1-t)^2*p1 + 3t^2*(1-t)*p2 + t^3*p3
- //
- // Applying some algebra, we can convert a second-order curve to a
- // third-order curve:
- //
- // p1 = (1/3) * (p0 + 2pc)
- // p2 = (1/3) * (2pc + p3)
-
- x1 = (SplashCoord)(1.0 / 3.0) * (x0 + (SplashCoord)2 * xc);
- y1 = (SplashCoord)(1.0 / 3.0) * (y0 + (SplashCoord)2 * yc);
- x2 = (SplashCoord)(1.0 / 3.0) * ((SplashCoord)2 * xc + x3);
- y2 = (SplashCoord)(1.0 / 3.0) * ((SplashCoord)2 * yc + y3);
-
- p->path->curveTo(x1, y1, x2, y2, x3, y3);
- p->needClose = true;
- return 0;
}
-static int glyphPathCubicTo(const FT_Vector *ctrl1, const FT_Vector *ctrl2,
- const FT_Vector *pt, void *path) {
- SplashFTFontPath *p = (SplashFTFontPath *)path;
-
- p->path->curveTo((SplashCoord)ctrl1->x * p->textScale / 64.0,
- (SplashCoord)ctrl1->y * p->textScale / 64.0,
- (SplashCoord)ctrl2->x * p->textScale / 64.0,
- (SplashCoord)ctrl2->y * p->textScale / 64.0,
- (SplashCoord)pt->x * p->textScale / 64.0,
- (SplashCoord)pt->y * p->textScale / 64.0);
- p->needClose = true;
- return 0;
+static int glyphPathCubicTo(const FT_Vector *ctrl1, const FT_Vector *ctrl2, const FT_Vector *pt, void *path)
+{
+ SplashFTFontPath *p = (SplashFTFontPath *)path;
+
+ p->path->curveTo((SplashCoord)ctrl1->x * p->textScale / 64.0, (SplashCoord)ctrl1->y * p->textScale / 64.0, (SplashCoord)ctrl2->x * p->textScale / 64.0, (SplashCoord)ctrl2->y * p->textScale / 64.0,
+ (SplashCoord)pt->x * p->textScale / 64.0, (SplashCoord)pt->y * p->textScale / 64.0);
+ p->needClose = true;
+ return 0;
}
diff --git a/splash/SplashFTFont.h b/splash/SplashFTFont.h
index 70e697f9..ae656b9c 100644
--- a/splash/SplashFTFont.h
+++ b/splash/SplashFTFont.h
@@ -37,39 +37,35 @@ class SplashFTFontFile;
// SplashFTFont
//------------------------------------------------------------------------
-class SplashFTFont: public SplashFont {
+class SplashFTFont : public SplashFont
+{
public:
+ SplashFTFont(SplashFTFontFile *fontFileA, SplashCoord *matA, const SplashCoord *textMatA);
- SplashFTFont(SplashFTFontFile *fontFileA, SplashCoord *matA,
- const SplashCoord *textMatA);
+ ~SplashFTFont() override;
- ~SplashFTFont() override;
+ // Munge xFrac and yFrac before calling SplashFont::getGlyph.
+ bool getGlyph(int c, int xFrac, int yFrac, SplashGlyphBitmap *bitmap, int x0, int y0, SplashClip *clip, SplashClipResult *clipRes) override;
- // Munge xFrac and yFrac before calling SplashFont::getGlyph.
- bool getGlyph(int c, int xFrac, int yFrac,
- SplashGlyphBitmap *bitmap, int x0, int y0, SplashClip *clip, SplashClipResult *clipRes) override;
+ // Rasterize a glyph. The <xFrac> and <yFrac> values are the same
+ // as described for getGlyph.
+ bool makeGlyph(int c, int xFrac, int yFrac, SplashGlyphBitmap *bitmap, int x0, int y0, SplashClip *clip, SplashClipResult *clipRes) override;
- // Rasterize a glyph. The <xFrac> and <yFrac> values are the same
- // as described for getGlyph.
- bool makeGlyph(int c, int xFrac, int yFrac,
- SplashGlyphBitmap *bitmap, int x0, int y0, SplashClip *clip, SplashClipResult *clipRes) override;
+ // Return the path for a glyph.
+ SplashPath *getGlyphPath(int c) override;
- // Return the path for a glyph.
- SplashPath *getGlyphPath(int c) override;
-
- // Return the advance of a glyph. (in 0..1 range)
- double getGlyphAdvance(int c) override;
+ // Return the advance of a glyph. (in 0..1 range)
+ double getGlyphAdvance(int c) override;
private:
-
- FT_Size sizeObj;
- FT_Matrix matrix;
- FT_Matrix textMatrix;
- SplashCoord textScale;
- int size;
- bool enableFreeTypeHinting;
- bool enableSlightHinting;
- bool isOk;
+ FT_Size sizeObj;
+ FT_Matrix matrix;
+ FT_Matrix textMatrix;
+ SplashCoord textScale;
+ int size;
+ bool enableFreeTypeHinting;
+ bool enableSlightHinting;
+ bool isOk;
};
#endif
diff --git a/splash/SplashFTFontEngine.cc b/splash/SplashFTFontEngine.cc
index ad43c15b..de0ca1ee 100644
--- a/splash/SplashFTFontEngine.cc
+++ b/splash/SplashFTFontEngine.cc
@@ -27,7 +27,7 @@
#include <cstdio>
#ifdef HAVE_UNISTD_H
-#include <unistd.h>
+# include <unistd.h>
#endif
#include "goo/gmem.h"
#include "goo/GooString.h"
@@ -41,128 +41,116 @@
// SplashFTFontEngine
//------------------------------------------------------------------------
-SplashFTFontEngine::SplashFTFontEngine(bool aaA, bool enableFreeTypeHintingA,
- bool enableSlightHintingA, FT_Library libA) {
- FT_Int major, minor, patch;
+SplashFTFontEngine::SplashFTFontEngine(bool aaA, bool enableFreeTypeHintingA, bool enableSlightHintingA, FT_Library libA)
+{
+ FT_Int major, minor, patch;
- aa = aaA;
- enableFreeTypeHinting = enableFreeTypeHintingA;
- enableSlightHinting = enableSlightHintingA;
- lib = libA;
+ aa = aaA;
+ enableFreeTypeHinting = enableFreeTypeHintingA;
+ enableSlightHinting = enableSlightHintingA;
+ lib = libA;
- // as of FT 2.1.8, CID fonts are indexed by CID instead of GID
- FT_Library_Version(lib, &major, &minor, &patch);
- useCIDs = major > 2 ||
- (major == 2 && (minor > 1 || (minor == 1 && patch > 7)));
+ // as of FT 2.1.8, CID fonts are indexed by CID instead of GID
+ FT_Library_Version(lib, &major, &minor, &patch);
+ useCIDs = major > 2 || (major == 2 && (minor > 1 || (minor == 1 && patch > 7)));
}
-SplashFTFontEngine *SplashFTFontEngine::init(bool aaA, bool enableFreeTypeHintingA,
- bool enableSlightHintingA) {
- FT_Library libA;
+SplashFTFontEngine *SplashFTFontEngine::init(bool aaA, bool enableFreeTypeHintingA, bool enableSlightHintingA)
+{
+ FT_Library libA;
- if (FT_Init_FreeType(&libA)) {
- return nullptr;
- }
- return new SplashFTFontEngine(aaA, enableFreeTypeHintingA, enableSlightHintingA, libA);
+ if (FT_Init_FreeType(&libA)) {
+ return nullptr;
+ }
+ return new SplashFTFontEngine(aaA, enableFreeTypeHintingA, enableSlightHintingA, libA);
}
-SplashFTFontEngine::~SplashFTFontEngine() {
- FT_Done_FreeType(lib);
+SplashFTFontEngine::~SplashFTFontEngine()
+{
+ FT_Done_FreeType(lib);
}
-SplashFontFile *SplashFTFontEngine::loadType1Font(SplashFontFileID *idA,
- SplashFontSrc *src,
- const char **enc) {
- return SplashFTFontFile::loadType1Font(this, idA, src, enc);
+SplashFontFile *SplashFTFontEngine::loadType1Font(SplashFontFileID *idA, SplashFontSrc *src, const char **enc)
+{
+ return SplashFTFontFile::loadType1Font(this, idA, src, enc);
}
-SplashFontFile *SplashFTFontEngine::loadType1CFont(SplashFontFileID *idA,
- SplashFontSrc *src,
- const char **enc) {
- return SplashFTFontFile::loadType1Font(this, idA, src, enc);
+SplashFontFile *SplashFTFontEngine::loadType1CFont(SplashFontFileID *idA, SplashFontSrc *src, const char **enc)
+{
+ return SplashFTFontFile::loadType1Font(this, idA, src, enc);
}
-SplashFontFile *SplashFTFontEngine::loadOpenTypeT1CFont(SplashFontFileID *idA,
- SplashFontSrc *src,
- const char **enc) {
- return SplashFTFontFile::loadType1Font(this, idA, src, enc);
+SplashFontFile *SplashFTFontEngine::loadOpenTypeT1CFont(SplashFontFileID *idA, SplashFontSrc *src, const char **enc)
+{
+ return SplashFTFontFile::loadType1Font(this, idA, src, enc);
}
-SplashFontFile *SplashFTFontEngine::loadCIDFont(SplashFontFileID *idA,
- SplashFontSrc *src) {
- FoFiType1C *ff;
- int *cidToGIDMap;
- int nCIDs;
- SplashFontFile *ret;
-
- // check for a CFF font
- if (useCIDs) {
- cidToGIDMap = nullptr;
- nCIDs = 0;
- } else {
- if (src->isFile) {
- ff = FoFiType1C::load(src->fileName->c_str());
+SplashFontFile *SplashFTFontEngine::loadCIDFont(SplashFontFileID *idA, SplashFontSrc *src)
+{
+ FoFiType1C *ff;
+ int *cidToGIDMap;
+ int nCIDs;
+ SplashFontFile *ret;
+
+ // check for a CFF font
+ if (useCIDs) {
+ cidToGIDMap = nullptr;
+ nCIDs = 0;
} else {
- ff = FoFiType1C::make(src->buf, src->bufLen);
+ if (src->isFile) {
+ ff = FoFiType1C::load(src->fileName->c_str());
+ } else {
+ ff = FoFiType1C::make(src->buf, src->bufLen);
+ }
+ if (ff) {
+ cidToGIDMap = ff->getCIDToGIDMap(&nCIDs);
+ delete ff;
+ } else {
+ cidToGIDMap = nullptr;
+ nCIDs = 0;
+ }
}
- if (ff) {
- cidToGIDMap = ff->getCIDToGIDMap(&nCIDs);
- delete ff;
- } else {
- cidToGIDMap = nullptr;
- nCIDs = 0;
+ ret = SplashFTFontFile::loadCIDFont(this, idA, src, cidToGIDMap, nCIDs);
+ if (!ret) {
+ gfree(cidToGIDMap);
}
- }
- ret = SplashFTFontFile::loadCIDFont(this, idA, src, cidToGIDMap, nCIDs);
- if (!ret) {
- gfree(cidToGIDMap);
- }
- return ret;
+ return ret;
}
-SplashFontFile *SplashFTFontEngine::loadOpenTypeCFFFont(SplashFontFileID *idA,
- SplashFontSrc *src,
- int *codeToGID,
- int codeToGIDLen) {
- FoFiTrueType *ff;
- int *cidToGIDMap;
- int nCIDs;
- SplashFontFile *ret;
-
- cidToGIDMap = nullptr;
- nCIDs = 0;
- if (!codeToGID) {
- if (!useCIDs) {
- if (src->isFile) {
- ff = FoFiTrueType::load(src->fileName->c_str());
- } else {
- ff = FoFiTrueType::make(src->buf, src->bufLen);
- }
- if (ff) {
- if (ff->isOpenTypeCFF()) {
- cidToGIDMap = ff->getCIDToGIDMap(&nCIDs);
+SplashFontFile *SplashFTFontEngine::loadOpenTypeCFFFont(SplashFontFileID *idA, SplashFontSrc *src, int *codeToGID, int codeToGIDLen)
+{
+ FoFiTrueType *ff;
+ int *cidToGIDMap;
+ int nCIDs;
+ SplashFontFile *ret;
+
+ cidToGIDMap = nullptr;
+ nCIDs = 0;
+ if (!codeToGID) {
+ if (!useCIDs) {
+ if (src->isFile) {
+ ff = FoFiTrueType::load(src->fileName->c_str());
+ } else {
+ ff = FoFiTrueType::make(src->buf, src->bufLen);
+ }
+ if (ff) {
+ if (ff->isOpenTypeCFF()) {
+ cidToGIDMap = ff->getCIDToGIDMap(&nCIDs);
+ }
+ delete ff;
+ }
}
- delete ff;
- }
}
- }
- ret = SplashFTFontFile::loadCIDFont(this, idA, src,
- codeToGID ? codeToGID : cidToGIDMap,
- codeToGID ? codeToGIDLen : nCIDs);
- if (!ret) {
- gfree(cidToGIDMap);
- }
- return ret;
+ ret = SplashFTFontFile::loadCIDFont(this, idA, src, codeToGID ? codeToGID : cidToGIDMap, codeToGID ? codeToGIDLen : nCIDs);
+ if (!ret) {
+ gfree(cidToGIDMap);
+ }
+ return ret;
}
-SplashFontFile *SplashFTFontEngine::loadTrueTypeFont(SplashFontFileID *idA,
- SplashFontSrc *src,
- int *codeToGID,
- int codeToGIDLen,
- int faceIndex) {
- SplashFontFile *ret;
- ret = SplashFTFontFile::loadTrueTypeFont(this, idA, src,
- codeToGID, codeToGIDLen,
- faceIndex);
- return ret;
+SplashFontFile *SplashFTFontEngine::loadTrueTypeFont(SplashFontFileID *idA, SplashFontSrc *src, int *codeToGID, int codeToGIDLen, int faceIndex)
+{
+ SplashFontFile *ret;
+ ret = SplashFTFontFile::loadTrueTypeFont(this, idA, src, codeToGID, codeToGIDLen, faceIndex);
+ return ret;
}
diff --git a/splash/SplashFTFontEngine.h b/splash/SplashFTFontEngine.h
index 5e1d595d..32e670c6 100644
--- a/splash/SplashFTFontEngine.h
+++ b/splash/SplashFTFontEngine.h
@@ -37,40 +37,37 @@ class SplashFontSrc;
// SplashFTFontEngine
//------------------------------------------------------------------------
-class SplashFTFontEngine {
+class SplashFTFontEngine
+{
public:
+ static SplashFTFontEngine *init(bool aaA, bool enableFreeTypeHintingA, bool enableSlightHinting);
- static SplashFTFontEngine *init(bool aaA, bool enableFreeTypeHintingA, bool enableSlightHinting);
+ ~SplashFTFontEngine();
- ~SplashFTFontEngine();
+ SplashFTFontEngine(const SplashFTFontEngine &) = delete;
+ SplashFTFontEngine &operator=(const SplashFTFontEngine &) = delete;
- SplashFTFontEngine(const SplashFTFontEngine&) = delete;
- SplashFTFontEngine& operator=(const SplashFTFontEngine&) = delete;
-
- // Load fonts.
- SplashFontFile *loadType1Font(SplashFontFileID *idA, SplashFontSrc *src, const char **enc);
- SplashFontFile *loadType1CFont(SplashFontFileID *idA, SplashFontSrc *src, const char **enc);
- SplashFontFile *loadOpenTypeT1CFont(SplashFontFileID *idA, SplashFontSrc *src, const char **enc);
- SplashFontFile *loadCIDFont(SplashFontFileID *idA, SplashFontSrc *src);
- SplashFontFile *loadOpenTypeCFFFont(SplashFontFileID *idA, SplashFontSrc *src,
- int *codeToGID, int codeToGIDLen);
- SplashFontFile *loadTrueTypeFont(SplashFontFileID *idA, SplashFontSrc *src,
- int *codeToGID, int codeToGIDLen, int faceIndex = 0);
- bool getAA() { return aa; }
- void setAA(bool aaA) { aa = aaA; }
+ // Load fonts.
+ SplashFontFile *loadType1Font(SplashFontFileID *idA, SplashFontSrc *src, const char **enc);
+ SplashFontFile *loadType1CFont(SplashFontFileID *idA, SplashFontSrc *src, const char **enc);
+ SplashFontFile *loadOpenTypeT1CFont(SplashFontFileID *idA, SplashFontSrc *src, const char **enc);
+ SplashFontFile *loadCIDFont(SplashFontFileID *idA, SplashFontSrc *src);
+ SplashFontFile *loadOpenTypeCFFFont(SplashFontFileID *idA, SplashFontSrc *src, int *codeToGID, int codeToGIDLen);
+ SplashFontFile *loadTrueTypeFont(SplashFontFileID *idA, SplashFontSrc *src, int *codeToGID, int codeToGIDLen, int faceIndex = 0);
+ bool getAA() { return aa; }
+ void setAA(bool aaA) { aa = aaA; }
private:
+ SplashFTFontEngine(bool aaA, bool enableFreeTypeHintingA, bool enableSlightHintingA, FT_Library libA);
- SplashFTFontEngine(bool aaA, bool enableFreeTypeHintingA, bool enableSlightHintingA, FT_Library libA);
-
- bool aa;
- bool enableFreeTypeHinting;
- bool enableSlightHinting;
- FT_Library lib;
- bool useCIDs;
+ bool aa;
+ bool enableFreeTypeHinting;
+ bool enableSlightHinting;
+ FT_Library lib;
+ bool useCIDs;
- friend class SplashFTFontFile;
- friend class SplashFTFont;
+ friend class SplashFTFontFile;
+ friend class SplashFTFont;
};
#endif
diff --git a/splash/SplashFTFontFile.cc b/splash/SplashFTFontFile.cc
index 7e3c34fc..d85c7207 100644
--- a/splash/SplashFTFontFile.cc
+++ b/splash/SplashFTFontFile.cc
@@ -34,109 +34,92 @@
// SplashFTFontFile
//------------------------------------------------------------------------
-SplashFontFile *SplashFTFontFile::loadType1Font(SplashFTFontEngine *engineA,
- SplashFontFileID *idA,
- SplashFontSrc *src,
- const char **encA) {
- FT_Face faceA;
- int *codeToGIDA;
- const char *name;
- int i;
-
- if (src->isFile) {
- if (FT_New_Face(engineA->lib, src->fileName->c_str(), 0, &faceA))
- return nullptr;
- } else {
- if (FT_New_Memory_Face(engineA->lib, (const FT_Byte *)src->buf, src->bufLen, 0, &faceA))
- return nullptr;
- }
- codeToGIDA = (int *)gmallocn(256, sizeof(int));
- for (i = 0; i < 256; ++i) {
- codeToGIDA[i] = 0;
- if ((name = encA[i])) {
- codeToGIDA[i] = (int)FT_Get_Name_Index(faceA, (char *)name);
- if (codeToGIDA[i] == 0) {
- name = GfxFont::getAlternateName(name);
- if (name) {
- codeToGIDA[i] = FT_Get_Name_Index(faceA, (char *)name);
- }
- }
+SplashFontFile *SplashFTFontFile::loadType1Font(SplashFTFontEngine *engineA, SplashFontFileID *idA, SplashFontSrc *src, const char **encA)
+{
+ FT_Face faceA;
+ int *codeToGIDA;
+ const char *name;
+ int i;
+
+ if (src->isFile) {
+ if (FT_New_Face(engineA->lib, src->fileName->c_str(), 0, &faceA))
+ return nullptr;
+ } else {
+ if (FT_New_Memory_Face(engineA->lib, (const FT_Byte *)src->buf, src->bufLen, 0, &faceA))
+ return nullptr;
+ }
+ codeToGIDA = (int *)gmallocn(256, sizeof(int));
+ for (i = 0; i < 256; ++i) {
+ codeToGIDA[i] = 0;
+ if ((name = encA[i])) {
+ codeToGIDA[i] = (int)FT_Get_Name_Index(faceA, (char *)name);
+ if (codeToGIDA[i] == 0) {
+ name = GfxFont::getAlternateName(name);
+ if (name) {
+ codeToGIDA[i] = FT_Get_Name_Index(faceA, (char *)name);
+ }
+ }
+ }
}
- }
- return new SplashFTFontFile(engineA, idA, src,
- faceA, codeToGIDA, 256, false, true);
+ return new SplashFTFontFile(engineA, idA, src, faceA, codeToGIDA, 256, false, true);
}
-SplashFontFile *SplashFTFontFile::loadCIDFont(SplashFTFontEngine *engineA,
- SplashFontFileID *idA,
- SplashFontSrc *src,
- int *codeToGIDA,
- int codeToGIDLenA) {
- FT_Face faceA;
-
- if (src->isFile) {
- if (FT_New_Face(engineA->lib, src->fileName->c_str(), 0, &faceA))
- return nullptr;
- } else {
- if (FT_New_Memory_Face(engineA->lib, (const FT_Byte *)src->buf, src->bufLen, 0, &faceA))
- return nullptr;
- }
-
- return new SplashFTFontFile(engineA, idA, src,
- faceA, codeToGIDA, codeToGIDLenA, false, false);
+SplashFontFile *SplashFTFontFile::loadCIDFont(SplashFTFontEngine *engineA, SplashFontFileID *idA, SplashFontSrc *src, int *codeToGIDA, int codeToGIDLenA)
+{
+ FT_Face faceA;
+
+ if (src->isFile) {
+ if (FT_New_Face(engineA->lib, src->fileName->c_str(), 0, &faceA))
+ return nullptr;
+ } else {
+ if (FT_New_Memory_Face(engineA->lib, (const FT_Byte *)src->buf, src->bufLen, 0, &faceA))
+ return nullptr;
+ }
+
+ return new SplashFTFontFile(engineA, idA, src, faceA, codeToGIDA, codeToGIDLenA, false, false);
}
-SplashFontFile *SplashFTFontFile::loadTrueTypeFont(SplashFTFontEngine *engineA,
- SplashFontFileID *idA,
- SplashFontSrc *src,
- int *codeToGIDA,
- int codeToGIDLenA,
- int faceIndexA) {
- FT_Face faceA;
-
- if (src->isFile) {
- if (FT_New_Face(engineA->lib, src->fileName->c_str(), faceIndexA, &faceA))
- return nullptr;
- } else {
- if (FT_New_Memory_Face(engineA->lib, (const FT_Byte *)src->buf, src->bufLen, faceIndexA, &faceA))
- return nullptr;
- }
-
- return new SplashFTFontFile(engineA, idA, src,
- faceA, codeToGIDA, codeToGIDLenA, true, false);
+SplashFontFile *SplashFTFontFile::loadTrueTypeFont(SplashFTFontEngine *engineA, SplashFontFileID *idA, SplashFontSrc *src, int *codeToGIDA, int codeToGIDLenA, int faceIndexA)
+{
+ FT_Face faceA;
+
+ if (src->isFile) {
+ if (FT_New_Face(engineA->lib, src->fileName->c_str(), faceIndexA, &faceA))
+ return nullptr;
+ } else {
+ if (FT_New_Memory_Face(engineA->lib, (const FT_Byte *)src->buf, src->bufLen, faceIndexA, &faceA))
+ return nullptr;
+ }
+
+ return new SplashFTFontFile(engineA, idA, src, faceA, codeToGIDA, codeToGIDLenA, true, false);
}
-SplashFTFontFile::SplashFTFontFile(SplashFTFontEngine *engineA,
- SplashFontFileID *idA,
- SplashFontSrc *srcA,
- FT_Face faceA,
- int *codeToGIDA, int codeToGIDLenA,
- bool trueTypeA, bool type1A):
- SplashFontFile(idA, srcA)
+SplashFTFontFile::SplashFTFontFile(SplashFTFontEngine *engineA, SplashFontFileID *idA, SplashFontSrc *srcA, FT_Face faceA, int *codeToGIDA, int codeToGIDLenA, bool trueTypeA, bool type1A) : SplashFontFile(idA, srcA)
{
- engine = engineA;
- face = faceA;
- codeToGID = codeToGIDA;
- codeToGIDLen = codeToGIDLenA;
- trueType = trueTypeA;
- type1 = type1A;
+ engine = engineA;
+ face = faceA;
+ codeToGID = codeToGIDA;
+ codeToGIDLen = codeToGIDLenA;
+ trueType = trueTypeA;
+ type1 = type1A;
}
-SplashFTFontFile::~SplashFTFontFile() {
- if (face) {
- FT_Done_Face(face);
- }
- if (codeToGID) {
- gfree(codeToGID);
- }
+SplashFTFontFile::~SplashFTFontFile()
+{
+ if (face) {
+ FT_Done_Face(face);
+ }
+ if (codeToGID) {
+ gfree(codeToGID);
+ }
}
-SplashFont *SplashFTFontFile::makeFont(SplashCoord *mat,
- const SplashCoord *textMat) {
- SplashFont *font;
+SplashFont *SplashFTFontFile::makeFont(SplashCoord *mat, const SplashCoord *textMat)
+{
+ SplashFont *font;
- font = new SplashFTFont(this, mat, textMat);
- font->initCache();
- return font;
+ font = new SplashFTFont(this, mat, textMat);
+ font->initCache();
+ return font;
}
diff --git a/splash/SplashFTFontFile.h b/splash/SplashFTFontFile.h
index 141702a2..3e52dd85 100644
--- a/splash/SplashFTFontFile.h
+++ b/splash/SplashFTFontFile.h
@@ -35,47 +35,30 @@ class SplashFTFontEngine;
// SplashFTFontFile
//------------------------------------------------------------------------
-class SplashFTFontFile: public SplashFontFile {
+class SplashFTFontFile : public SplashFontFile
+{
public:
+ static SplashFontFile *loadType1Font(SplashFTFontEngine *engineA, SplashFontFileID *idA, SplashFontSrc *src, const char **encA);
+ static SplashFontFile *loadCIDFont(SplashFTFontEngine *engineA, SplashFontFileID *idA, SplashFontSrc *src, int *codeToGIDA, int codeToGIDLenA);
+ static SplashFontFile *loadTrueTypeFont(SplashFTFontEngine *engineA, SplashFontFileID *idA, SplashFontSrc *src, int *codeToGIDA, int codeToGIDLenA, int faceIndexA = 0);
- static SplashFontFile *loadType1Font(SplashFTFontEngine *engineA,
- SplashFontFileID *idA,
- SplashFontSrc *src, const char **encA);
- static SplashFontFile *loadCIDFont(SplashFTFontEngine *engineA,
- SplashFontFileID *idA,
- SplashFontSrc *src,
- int *codeToGIDA, int codeToGIDLenA);
- static SplashFontFile *loadTrueTypeFont(SplashFTFontEngine *engineA,
- SplashFontFileID *idA,
- SplashFontSrc *src,
- int *codeToGIDA,
- int codeToGIDLenA,
- int faceIndexA=0);
+ ~SplashFTFontFile() override;
- ~SplashFTFontFile() override;
-
- // Create a new SplashFTFont, i.e., a scaled instance of this font
- // file.
- SplashFont *makeFont(SplashCoord *mat,
- const SplashCoord *textMat) override;
+ // Create a new SplashFTFont, i.e., a scaled instance of this font
+ // file.
+ SplashFont *makeFont(SplashCoord *mat, const SplashCoord *textMat) override;
private:
+ SplashFTFontFile(SplashFTFontEngine *engineA, SplashFontFileID *idA, SplashFontSrc *src, FT_Face faceA, int *codeToGIDA, int codeToGIDLenA, bool trueTypeA, bool type1A);
- SplashFTFontFile(SplashFTFontEngine *engineA,
- SplashFontFileID *idA,
- SplashFontSrc *src,
- FT_Face faceA,
- int *codeToGIDA, int codeToGIDLenA,
- bool trueTypeA, bool type1A);
-
- SplashFTFontEngine *engine;
- FT_Face face;
- int *codeToGID;
- int codeToGIDLen;
- bool trueType;
- bool type1;
+ SplashFTFontEngine *engine;
+ FT_Face face;
+ int *codeToGID;
+ int codeToGIDLen;
+ bool trueType;
+ bool type1;
- friend class SplashFTFont;
+ friend class SplashFTFont;
};
#endif
diff --git a/splash/SplashFont.cc b/splash/SplashFont.cc
index ffaa66a7..bd4da233 100644
--- a/splash/SplashFont.cc
+++ b/splash/SplashFont.cc
@@ -31,191 +31,182 @@
//------------------------------------------------------------------------
-struct SplashFontCacheTag {
- int c;
- short xFrac, yFrac; // x and y fractions
- int mru; // valid bit (0x80000000) and MRU index
- int x, y, w, h; // offset and size of glyph
+struct SplashFontCacheTag
+{
+ int c;
+ short xFrac, yFrac; // x and y fractions
+ int mru; // valid bit (0x80000000) and MRU index
+ int x, y, w, h; // offset and size of glyph
};
//------------------------------------------------------------------------
// SplashFont
//------------------------------------------------------------------------
-SplashFont::SplashFont(SplashFontFile *fontFileA, const SplashCoord *matA,
- const SplashCoord *textMatA, bool aaA) {
- fontFile = fontFileA;
- fontFile->incRefCnt();
- mat[0] = matA[0];
- mat[1] = matA[1];
- mat[2] = matA[2];
- mat[3] = matA[3];
- textMat[0] = textMatA[0];
- textMat[1] = textMatA[1];
- textMat[2] = textMatA[2];
- textMat[3] = textMatA[3];
- aa = aaA;
-
- cache = nullptr;
- cacheTags = nullptr;
-
- xMin = yMin = xMax = yMax = 0;
+SplashFont::SplashFont(SplashFontFile *fontFileA, const SplashCoord *matA, const SplashCoord *textMatA, bool aaA)
+{
+ fontFile = fontFileA;
+ fontFile->incRefCnt();
+ mat[0] = matA[0];
+ mat[1] = matA[1];
+ mat[2] = matA[2];
+ mat[3] = matA[3];
+ textMat[0] = textMatA[0];
+ textMat[1] = textMatA[1];
+ textMat[2] = textMatA[2];
+ textMat[3] = textMatA[3];
+ aa = aaA;
+
+ cache = nullptr;
+ cacheTags = nullptr;
+
+ xMin = yMin = xMax = yMax = 0;
}
-void SplashFont::initCache() {
- int i;
+void SplashFont::initCache()
+{
+ int i;
- // this should be (max - min + 1), but we add some padding to
- // deal with rounding errors
- glyphW = xMax - xMin + 3;
- glyphH = yMax - yMin + 3;
- if (glyphW > INT_MAX / glyphH) {
- glyphSize = -1;
- } else {
- if (aa) {
- glyphSize = glyphW * glyphH;
+ // this should be (max - min + 1), but we add some padding to
+ // deal with rounding errors
+ glyphW = xMax - xMin + 3;
+ glyphH = yMax - yMin + 3;
+ if (glyphW > INT_MAX / glyphH) {
+ glyphSize = -1;
+ } else {
+ if (aa) {
+ glyphSize = glyphW * glyphH;
+ } else {
+ glyphSize = ((glyphW + 7) >> 3) * glyphH;
+ }
+ }
+
+ // set up the glyph pixmap cache
+ cacheAssoc = 8;
+ if (glyphSize <= 64) {
+ cacheSets = 32;
+ } else if (glyphSize <= 128) {
+ cacheSets = 16;
+ } else if (glyphSize <= 256) {
+ cacheSets = 8;
+ } else if (glyphSize <= 512) {
+ cacheSets = 4;
+ } else if (glyphSize <= 1024) {
+ cacheSets = 2;
} else {
- glyphSize = ((glyphW + 7) >> 3) * glyphH;
+ cacheSets = 1;
}
- }
-
- // set up the glyph pixmap cache
- cacheAssoc = 8;
- if (glyphSize <= 64) {
- cacheSets = 32;
- } else if (glyphSize <= 128) {
- cacheSets = 16;
- } else if (glyphSize <= 256) {
- cacheSets = 8;
- } else if (glyphSize <= 512) {
- cacheSets = 4;
- } else if (glyphSize <= 1024) {
- cacheSets = 2;
- } else {
- cacheSets = 1;
- }
- cache = (unsigned char *)gmallocn_checkoverflow(cacheSets* cacheAssoc, glyphSize);
- if (cache != nullptr) {
- cacheTags = (SplashFontCacheTag *)gmallocn(cacheSets * cacheAssoc,
- sizeof(SplashFontCacheTag));
- for (i = 0; i < cacheSets * cacheAssoc; ++i) {
- cacheTags[i].mru = i & (cacheAssoc - 1);
+ cache = (unsigned char *)gmallocn_checkoverflow(cacheSets * cacheAssoc, glyphSize);
+ if (cache != nullptr) {
+ cacheTags = (SplashFontCacheTag *)gmallocn(cacheSets * cacheAssoc, sizeof(SplashFontCacheTag));
+ for (i = 0; i < cacheSets * cacheAssoc; ++i) {
+ cacheTags[i].mru = i & (cacheAssoc - 1);
+ }
+ } else {
+ cacheAssoc = 0;
}
- } else {
- cacheAssoc = 0;
- }
}
-SplashFont::~SplashFont() {
- fontFile->decRefCnt();
- if (cache) {
- gfree(cache);
- }
- if (cacheTags) {
- gfree(cacheTags);
- }
+SplashFont::~SplashFont()
+{
+ fontFile->decRefCnt();
+ if (cache) {
+ gfree(cache);
+ }
+ if (cacheTags) {
+ gfree(cacheTags);
+ }
}
-bool SplashFont::getGlyph(int c, int xFrac, int yFrac,
- SplashGlyphBitmap *bitmap, int x0, int y0, SplashClip *clip, SplashClipResult *clipRes) {
- SplashGlyphBitmap bitmap2;
- int size;
- unsigned char *p;
- int i, j, k;
-
- // no fractional coordinates for large glyphs or non-anti-aliased
- // glyphs
- if (!aa || glyphH > 50) {
- xFrac = yFrac = 0;
- }
-
- // check the cache
- i = (c & (cacheSets - 1)) * cacheAssoc;
- for (j = 0; j < cacheAssoc; ++j) {
- if ((cacheTags[i+j].mru & 0x80000000) &&
- cacheTags[i+j].c == c &&
- (int)cacheTags[i+j].xFrac == xFrac &&
- (int)cacheTags[i+j].yFrac == yFrac) {
- bitmap->x = cacheTags[i+j].x;
- bitmap->y = cacheTags[i+j].y;
- bitmap->w = cacheTags[i+j].w;
- bitmap->h = cacheTags[i+j].h;
- for (k = 0; k < cacheAssoc; ++k) {
- if (k != j &&
- (cacheTags[i+k].mru & 0x7fffffff) <
- (cacheTags[i+j].mru & 0x7fffffff)) {
- ++cacheTags[i+k].mru;
- }
- }
- cacheTags[i+j].mru = 0x80000000;
- bitmap->aa = aa;
- bitmap->data = cache + (i+j) * glyphSize;
- bitmap->freeData = false;
-
- *clipRes = clip->testRect(x0 - bitmap->x,
- y0 - bitmap->y,
- x0 - bitmap->x + bitmap->w - 1,
- y0 - bitmap->y + bitmap->h - 1);
-
- return true;
+bool SplashFont::getGlyph(int c, int xFrac, int yFrac, SplashGlyphBitmap *bitmap, int x0, int y0, SplashClip *clip, SplashClipResult *clipRes)
+{
+ SplashGlyphBitmap bitmap2;
+ int size;
+ unsigned char *p;
+ int i, j, k;
+
+ // no fractional coordinates for large glyphs or non-anti-aliased
+ // glyphs
+ if (!aa || glyphH > 50) {
+ xFrac = yFrac = 0;
}
- }
- // generate the glyph bitmap
- if (!makeGlyph(c, xFrac, yFrac, &bitmap2, x0, y0, clip, clipRes)) {
- return false;
- }
+ // check the cache
+ i = (c & (cacheSets - 1)) * cacheAssoc;
+ for (j = 0; j < cacheAssoc; ++j) {
+ if ((cacheTags[i + j].mru & 0x80000000) && cacheTags[i + j].c == c && (int)cacheTags[i + j].xFrac == xFrac && (int)cacheTags[i + j].yFrac == yFrac) {
+ bitmap->x = cacheTags[i + j].x;
+ bitmap->y = cacheTags[i + j].y;
+ bitmap->w = cacheTags[i + j].w;
+ bitmap->h = cacheTags[i + j].h;
+ for (k = 0; k < cacheAssoc; ++k) {
+ if (k != j && (cacheTags[i + k].mru & 0x7fffffff) < (cacheTags[i + j].mru & 0x7fffffff)) {
+ ++cacheTags[i + k].mru;
+ }
+ }
+ cacheTags[i + j].mru = 0x80000000;
+ bitmap->aa = aa;
+ bitmap->data = cache + (i + j) * glyphSize;
+ bitmap->freeData = false;
+
+ *clipRes = clip->testRect(x0 - bitmap->x, y0 - bitmap->y, x0 - bitmap->x + bitmap->w - 1, y0 - bitmap->y + bitmap->h - 1);
+
+ return true;
+ }
+ }
- if (*clipRes == splashClipAllOutside)
- {
- bitmap->freeData = false;
- if (bitmap2.freeData) gfree(bitmap2.data);
- return true;
- }
+ // generate the glyph bitmap
+ if (!makeGlyph(c, xFrac, yFrac, &bitmap2, x0, y0, clip, clipRes)) {
+ return false;
+ }
- // if the glyph doesn't fit in the bounding box, return a temporary
- // uncached bitmap
- if (bitmap2.w > glyphW || bitmap2.h > glyphH) {
- *bitmap = bitmap2;
- return true;
- }
-
- // insert glyph pixmap in cache
- if (aa) {
- size = bitmap2.w * bitmap2.h;
- } else {
- size = ((bitmap2.w + 7) >> 3) * bitmap2.h;
- }
- p = nullptr; // make gcc happy
- if (cacheAssoc == 0)
- {
- // we had problems on the malloc of the cache, so ignore it
- *bitmap = bitmap2;
- }
- else
- {
- for (j = 0; j < cacheAssoc; ++j) {
- if ((cacheTags[i+j].mru & 0x7fffffff) == cacheAssoc - 1) {
- cacheTags[i+j].mru = 0x80000000;
- cacheTags[i+j].c = c;
- cacheTags[i+j].xFrac = (short)xFrac;
- cacheTags[i+j].yFrac = (short)yFrac;
- cacheTags[i+j].x = bitmap2.x;
- cacheTags[i+j].y = bitmap2.y;
- cacheTags[i+j].w = bitmap2.w;
- cacheTags[i+j].h = bitmap2.h;
- p = cache + (i+j) * glyphSize;
- memcpy(p, bitmap2.data, size);
- } else {
- ++cacheTags[i+j].mru;
- }
+ if (*clipRes == splashClipAllOutside) {
+ bitmap->freeData = false;
+ if (bitmap2.freeData)
+ gfree(bitmap2.data);
+ return true;
+ }
+
+ // if the glyph doesn't fit in the bounding box, return a temporary
+ // uncached bitmap
+ if (bitmap2.w > glyphW || bitmap2.h > glyphH) {
+ *bitmap = bitmap2;
+ return true;
+ }
+
+ // insert glyph pixmap in cache
+ if (aa) {
+ size = bitmap2.w * bitmap2.h;
+ } else {
+ size = ((bitmap2.w + 7) >> 3) * bitmap2.h;
}
- *bitmap = bitmap2;
- bitmap->data = p;
- bitmap->freeData = false;
- if (bitmap2.freeData) {
- gfree(bitmap2.data);
+ p = nullptr; // make gcc happy
+ if (cacheAssoc == 0) {
+ // we had problems on the malloc of the cache, so ignore it
+ *bitmap = bitmap2;
+ } else {
+ for (j = 0; j < cacheAssoc; ++j) {
+ if ((cacheTags[i + j].mru & 0x7fffffff) == cacheAssoc - 1) {
+ cacheTags[i + j].mru = 0x80000000;
+ cacheTags[i + j].c = c;
+ cacheTags[i + j].xFrac = (short)xFrac;
+ cacheTags[i + j].yFrac = (short)yFrac;
+ cacheTags[i + j].x = bitmap2.x;
+ cacheTags[i + j].y = bitmap2.y;
+ cacheTags[i + j].w = bitmap2.w;
+ cacheTags[i + j].h = bitmap2.h;
+ p = cache + (i + j) * glyphSize;
+ memcpy(p, bitmap2.data, size);
+ } else {
+ ++cacheTags[i + j].mru;
+ }
+ }
+ *bitmap = bitmap2;
+ bitmap->data = p;
+ bitmap->freeData = false;
+ if (bitmap2.freeData) {
+ gfree(bitmap2.data);
+ }
}
- }
- return true;
+ return true;
}
diff --git a/splash/SplashFont.h b/splash/SplashFont.h
index b393aeb3..8c54b08f 100644
--- a/splash/SplashFont.h
+++ b/splash/SplashFont.h
@@ -35,86 +35,82 @@ class SplashPath;
// Fractional positioning uses this many bits to the right of the
// decimal points.
#define splashFontFractionBits 2
-#define splashFontFraction (1 << splashFontFractionBits)
-#define splashFontFractionMul \
- ((SplashCoord)1 / (SplashCoord)splashFontFraction)
+#define splashFontFraction (1 << splashFontFractionBits)
+#define splashFontFractionMul ((SplashCoord)1 / (SplashCoord)splashFontFraction)
//------------------------------------------------------------------------
// SplashFont
//------------------------------------------------------------------------
-class SplashFont {
+class SplashFont
+{
public:
+ SplashFont(SplashFontFile *fontFileA, const SplashCoord *matA, const SplashCoord *textMatA, bool aaA);
- SplashFont(SplashFontFile *fontFileA, const SplashCoord *matA,
- const SplashCoord *textMatA, bool aaA);
+ // This must be called after the constructor, so that the subclass
+ // constructor has a chance to compute the bbox.
+ void initCache();
- // This must be called after the constructor, so that the subclass
- // constructor has a chance to compute the bbox.
- void initCache();
+ virtual ~SplashFont();
- virtual ~SplashFont();
+ SplashFont(const SplashFont &) = delete;
+ SplashFont &operator=(const SplashFont &) = delete;
- SplashFont(const SplashFont &) = delete;
- SplashFont& operator=(const SplashFont &) = delete;
+ SplashFontFile *getFontFile() { return fontFile; }
- SplashFontFile *getFontFile() { return fontFile; }
+ // Return true if <this> matches the specified font file and matrix.
+ bool matches(SplashFontFile *fontFileA, const SplashCoord *matA, const SplashCoord *textMatA) const
+ {
+ return fontFileA == fontFile && matA[0] == mat[0] && matA[1] == mat[1] && matA[2] == mat[2] && matA[3] == mat[3] && textMatA[0] == textMat[0] && textMatA[1] == textMat[1] && textMatA[2] == textMat[2] && textMatA[3] == textMat[3];
+ }
- // Return true if <this> matches the specified font file and matrix.
- bool matches(SplashFontFile *fontFileA, const SplashCoord *matA,
- const SplashCoord *textMatA) const {
- return fontFileA == fontFile &&
- matA[0] == mat[0] && matA[1] == mat[1] &&
- matA[2] == mat[2] && matA[3] == mat[3] &&
- textMatA[0] == textMat[0] && textMatA[1] == textMat[1] &&
- textMatA[2] == textMat[2] && textMatA[3] == textMat[3];
- }
+ // Get a glyph - this does a cache lookup first, and if not found,
+ // creates a new bitmap and adds it to the cache. The <xFrac> and
+ // <yFrac> values are splashFontFractionBits bits each, representing
+ // the numerators of fractions in [0, 1), where the denominator is
+ // splashFontFraction = 1 << splashFontFractionBits. Subclasses
+ // should override this to zero out xFrac and/or yFrac if they don't
+ // support fractional coordinates.
+ virtual bool getGlyph(int c, int xFrac, int yFrac, SplashGlyphBitmap *bitmap, int x0, int y0, SplashClip *clip, SplashClipResult *clipRes);
- // Get a glyph - this does a cache lookup first, and if not found,
- // creates a new bitmap and adds it to the cache. The <xFrac> and
- // <yFrac> values are splashFontFractionBits bits each, representing
- // the numerators of fractions in [0, 1), where the denominator is
- // splashFontFraction = 1 << splashFontFractionBits. Subclasses
- // should override this to zero out xFrac and/or yFrac if they don't
- // support fractional coordinates.
- virtual bool getGlyph(int c, int xFrac, int yFrac,
- SplashGlyphBitmap *bitmap, int x0, int y0, SplashClip *clip, SplashClipResult *clipRes);
+ // Rasterize a glyph. The <xFrac> and <yFrac> values are the same
+ // as described for getGlyph.
+ virtual bool makeGlyph(int c, int xFrac, int yFrac, SplashGlyphBitmap *bitmap, int x0, int y0, SplashClip *clip, SplashClipResult *clipRes) = 0;
- // Rasterize a glyph. The <xFrac> and <yFrac> values are the same
- // as described for getGlyph.
- virtual bool makeGlyph(int c, int xFrac, int yFrac,
- SplashGlyphBitmap *bitmap, int x0, int y0, SplashClip *clip, SplashClipResult *clipRes) = 0;
+ // Return the path for a glyph.
+ virtual SplashPath *getGlyphPath(int c) = 0;
- // Return the path for a glyph.
- virtual SplashPath *getGlyphPath(int c) = 0;
+ // Return the advance of a glyph. (in 0..1 range)
+ // < 0 means not known
+ virtual double getGlyphAdvance(int c) { return -1; }
- // Return the advance of a glyph. (in 0..1 range)
- // < 0 means not known
- virtual double getGlyphAdvance(int c) { return -1; }
+ // Return the font transform matrix.
+ SplashCoord *getMatrix() { return mat; }
- // Return the font transform matrix.
- SplashCoord *getMatrix() { return mat; }
-
- // Return the glyph bounding box.
- void getBBox(int *xMinA, int *yMinA, int *xMaxA, int *yMaxA)
- { *xMinA = xMin; *yMinA = yMin; *xMaxA = xMax; *yMaxA = yMax; }
+ // Return the glyph bounding box.
+ void getBBox(int *xMinA, int *yMinA, int *xMaxA, int *yMaxA)
+ {
+ *xMinA = xMin;
+ *yMinA = yMin;
+ *xMaxA = xMax;
+ *yMaxA = yMax;
+ }
protected:
-
- SplashFontFile *fontFile;
- SplashCoord mat[4]; // font transform matrix
- // (text space -> device space)
- SplashCoord textMat[4]; // text transform matrix
- // (text space -> user space)
- bool aa; // anti-aliasing
- int xMin, yMin, xMax, yMax; // glyph bounding box
- unsigned char *cache; // glyph bitmap cache
- SplashFontCacheTag * // cache tags
- cacheTags;
- int glyphW, glyphH; // size of glyph bitmaps
- int glyphSize; // size of glyph bitmaps, in bytes
- int cacheSets; // number of sets in cache
- int cacheAssoc; // cache associativity (glyphs per set)
+ SplashFontFile *fontFile;
+ SplashCoord mat[4]; // font transform matrix
+ // (text space -> device space)
+ SplashCoord textMat[4]; // text transform matrix
+ // (text space -> user space)
+ bool aa; // anti-aliasing
+ int xMin, yMin, xMax, yMax; // glyph bounding box
+ unsigned char *cache; // glyph bitmap cache
+ SplashFontCacheTag * // cache tags
+ cacheTags;
+ int glyphW, glyphH; // size of glyph bitmaps
+ int glyphSize; // size of glyph bitmaps, in bytes
+ int cacheSets; // number of sets in cache
+ int cacheAssoc; // cache associativity (glyphs per set)
};
#endif
diff --git a/splash/SplashFontEngine.cc b/splash/SplashFontEngine.cc
index 40e24225..b95beee5 100644
--- a/splash/SplashFontEngine.cc
+++ b/splash/SplashFontEngine.cc
@@ -32,7 +32,7 @@
#include <cstdlib>
#include <cstdio>
#ifdef HAVE_UNISTD_H
-# include <unistd.h>
+# include <unistd.h>
#endif
#include <algorithm>
@@ -49,206 +49,197 @@
// SplashFontEngine
//------------------------------------------------------------------------
-SplashFontEngine::SplashFontEngine(
- bool enableFreeType,
- bool enableFreeTypeHinting,
- bool enableSlightHinting,
- bool aa) {
- std::fill(fontCache.begin(), fontCache.end(), nullptr);
-
- if (enableFreeType) {
- ftEngine = SplashFTFontEngine::init(aa, enableFreeTypeHinting, enableSlightHinting);
- } else {
- ftEngine = nullptr;
- }
+SplashFontEngine::SplashFontEngine(bool enableFreeType, bool enableFreeTypeHinting, bool enableSlightHinting, bool aa)
+{
+ std::fill(fontCache.begin(), fontCache.end(), nullptr);
+
+ if (enableFreeType) {
+ ftEngine = SplashFTFontEngine::init(aa, enableFreeTypeHinting, enableSlightHinting);
+ } else {
+ ftEngine = nullptr;
+ }
}
-SplashFontEngine::~SplashFontEngine() {
- for (auto font : fontCache) {
- delete font;
- }
+SplashFontEngine::~SplashFontEngine()
+{
+ for (auto font : fontCache) {
+ delete font;
+ }
- if (ftEngine) {
- delete ftEngine;
- }
+ if (ftEngine) {
+ delete ftEngine;
+ }
}
-SplashFontFile *SplashFontEngine::getFontFile(SplashFontFileID *id) {
- for (auto font : fontCache) {
- if (font) {
- SplashFontFile *fontFile = font->getFontFile();
- if (fontFile && fontFile->getID()->matches(id)) {
- return fontFile;
- }
+SplashFontFile *SplashFontEngine::getFontFile(SplashFontFileID *id)
+{
+ for (auto font : fontCache) {
+ if (font) {
+ SplashFontFile *fontFile = font->getFontFile();
+ if (fontFile && fontFile->getID()->matches(id)) {
+ return fontFile;
+ }
+ }
}
- }
- return nullptr;
+ return nullptr;
}
-SplashFontFile *SplashFontEngine::loadType1Font(SplashFontFileID *idA,
- SplashFontSrc *src,
- const char **enc) {
- SplashFontFile *fontFile = nullptr;
+SplashFontFile *SplashFontEngine::loadType1Font(SplashFontFileID *idA, SplashFontSrc *src, const char **enc)
+{
+ SplashFontFile *fontFile = nullptr;
- if (ftEngine) {
- fontFile = ftEngine->loadType1Font(idA, src, enc);
- }
+ if (ftEngine) {
+ fontFile = ftEngine->loadType1Font(idA, src, enc);
+ }
- // delete the (temporary) font file -- with Unix hard link
- // semantics, this will remove the last link; otherwise it will
- // return an error, leaving the file to be deleted later (if
- // loadXYZFont failed, the file will always be deleted)
- if (src->isFile)
- src->unref();
+ // delete the (temporary) font file -- with Unix hard link
+ // semantics, this will remove the last link; otherwise it will
+ // return an error, leaving the file to be deleted later (if
+ // loadXYZFont failed, the file will always be deleted)
+ if (src->isFile)
+ src->unref();
- return fontFile;
+ return fontFile;
}
-SplashFontFile *SplashFontEngine::loadType1CFont(SplashFontFileID *idA,
- SplashFontSrc *src,
- const char **enc) {
- SplashFontFile *fontFile = nullptr;
+SplashFontFile *SplashFontEngine::loadType1CFont(SplashFontFileID *idA, SplashFontSrc *src, const char **enc)
+{
+ SplashFontFile *fontFile = nullptr;
- if (ftEngine) {
- fontFile = ftEngine->loadType1CFont(idA, src, enc);
- }
+ if (ftEngine) {
+ fontFile = ftEngine->loadType1CFont(idA, src, enc);
+ }
- // delete the (temporary) font file -- with Unix hard link
- // semantics, this will remove the last link; otherwise it will
- // return an error, leaving the file to be deleted later (if
- // loadXYZFont failed, the file will always be deleted)
- if (src->isFile)
- src->unref();
+ // delete the (temporary) font file -- with Unix hard link
+ // semantics, this will remove the last link; otherwise it will
+ // return an error, leaving the file to be deleted later (if
+ // loadXYZFont failed, the file will always be deleted)
+ if (src->isFile)
+ src->unref();
- return fontFile;
+ return fontFile;
}
-SplashFontFile *SplashFontEngine::loadOpenTypeT1CFont(SplashFontFileID *idA,
- SplashFontSrc *src,
- const char **enc) {
- SplashFontFile *fontFile = nullptr;
+SplashFontFile *SplashFontEngine::loadOpenTypeT1CFont(SplashFontFileID *idA, SplashFontSrc *src, const char **enc)
+{
+ SplashFontFile *fontFile = nullptr;
- if (ftEngine) {
- fontFile = ftEngine->loadOpenTypeT1CFont(idA, src, enc);
- }
+ if (ftEngine) {
+ fontFile = ftEngine->loadOpenTypeT1CFont(idA, src, enc);
+ }
- // delete the (temporary) font file -- with Unix hard link
- // semantics, this will remove the last link; otherwise it will
- // return an error, leaving the file to be deleted later (if
- // loadXYZFont failed, the file will always be deleted)
- if (src->isFile)
- src->unref();
+ // delete the (temporary) font file -- with Unix hard link
+ // semantics, this will remove the last link; otherwise it will
+ // return an error, leaving the file to be deleted later (if
+ // loadXYZFont failed, the file will always be deleted)
+ if (src->isFile)
+ src->unref();
- return fontFile;
+ return fontFile;
}
-SplashFontFile *SplashFontEngine::loadCIDFont(SplashFontFileID *idA,
- SplashFontSrc *src) {
- SplashFontFile *fontFile = nullptr;
+SplashFontFile *SplashFontEngine::loadCIDFont(SplashFontFileID *idA, SplashFontSrc *src)
+{
+ SplashFontFile *fontFile = nullptr;
- if (ftEngine) {
- fontFile = ftEngine->loadCIDFont(idA, src);
- }
+ if (ftEngine) {
+ fontFile = ftEngine->loadCIDFont(idA, src);
+ }
- // delete the (temporary) font file -- with Unix hard link
- // semantics, this will remove the last link; otherwise it will
- // return an error, leaving the file to be deleted later (if
- // loadXYZFont failed, the file will always be deleted)
- if (src->isFile)
- src->unref();
+ // delete the (temporary) font file -- with Unix hard link
+ // semantics, this will remove the last link; otherwise it will
+ // return an error, leaving the file to be deleted later (if
+ // loadXYZFont failed, the file will always be deleted)
+ if (src->isFile)
+ src->unref();
- return fontFile;
+ return fontFile;
}
-SplashFontFile *SplashFontEngine::loadOpenTypeCFFFont(SplashFontFileID *idA,
- SplashFontSrc *src,
- int *codeToGID,
- int codeToGIDLen) {
- SplashFontFile *fontFile = nullptr;
+SplashFontFile *SplashFontEngine::loadOpenTypeCFFFont(SplashFontFileID *idA, SplashFontSrc *src, int *codeToGID, int codeToGIDLen)
+{
+ SplashFontFile *fontFile = nullptr;
- if (ftEngine) {
- fontFile = ftEngine->loadOpenTypeCFFFont(idA, src, codeToGID, codeToGIDLen);
- }
+ if (ftEngine) {
+ fontFile = ftEngine->loadOpenTypeCFFFont(idA, src, codeToGID, codeToGIDLen);
+ }
- // delete the (temporary) font file -- with Unix hard link
- // semantics, this will remove the last link; otherwise it will
- // return an error, leaving the file to be deleted later (if
- // loadXYZFont failed, the file will always be deleted)
- if (src->isFile)
- src->unref();
+ // delete the (temporary) font file -- with Unix hard link
+ // semantics, this will remove the last link; otherwise it will
+ // return an error, leaving the file to be deleted later (if
+ // loadXYZFont failed, the file will always be deleted)
+ if (src->isFile)
+ src->unref();
- return fontFile;
+ return fontFile;
}
-SplashFontFile *SplashFontEngine::loadTrueTypeFont(SplashFontFileID *idA,
- SplashFontSrc *src,
- int *codeToGID,
- int codeToGIDLen,
- int faceIndex) {
- SplashFontFile *fontFile = nullptr;
-
- if (ftEngine) {
- fontFile = ftEngine->loadTrueTypeFont(idA, src,
- codeToGID, codeToGIDLen, faceIndex);
- }
-
- if (!fontFile) {
- gfree(codeToGID);
- }
-
- // delete the (temporary) font file -- with Unix hard link
- // semantics, this will remove the last link; otherwise it will
- // return an error, leaving the file to be deleted later (if
- // loadXYZFont failed, the file will always be deleted)
- if (src->isFile)
- src->unref();
-
- return fontFile;
+SplashFontFile *SplashFontEngine::loadTrueTypeFont(SplashFontFileID *idA, SplashFontSrc *src, int *codeToGID, int codeToGIDLen, int faceIndex)
+{
+ SplashFontFile *fontFile = nullptr;
+
+ if (ftEngine) {
+ fontFile = ftEngine->loadTrueTypeFont(idA, src, codeToGID, codeToGIDLen, faceIndex);
+ }
+
+ if (!fontFile) {
+ gfree(codeToGID);
+ }
+
+ // delete the (temporary) font file -- with Unix hard link
+ // semantics, this will remove the last link; otherwise it will
+ // return an error, leaving the file to be deleted later (if
+ // loadXYZFont failed, the file will always be deleted)
+ if (src->isFile)
+ src->unref();
+
+ return fontFile;
}
-bool SplashFontEngine::getAA() {
- return (ftEngine == nullptr) ? false : ftEngine->getAA();
+bool SplashFontEngine::getAA()
+{
+ return (ftEngine == nullptr) ? false : ftEngine->getAA();
}
-void SplashFontEngine::setAA(bool aa) {
- if (ftEngine != nullptr) {
- ftEngine->setAA(aa);
- }
+void SplashFontEngine::setAA(bool aa)
+{
+ if (ftEngine != nullptr) {
+ ftEngine->setAA(aa);
+ }
}
-SplashFont *SplashFontEngine::getFont(SplashFontFile *fontFile,
- const SplashCoord *textMat,
- const SplashCoord *ctm) {
- SplashCoord mat[4];
-
- mat[0] = textMat[0] * ctm[0] + textMat[1] * ctm[2];
- mat[1] = -(textMat[0] * ctm[1] + textMat[1] * ctm[3]);
- mat[2] = textMat[2] * ctm[0] + textMat[3] * ctm[2];
- mat[3] = -(textMat[2] * ctm[1] + textMat[3] * ctm[3]);
- if (!splashCheckDet(mat[0], mat[1], mat[2], mat[3], 0.01)) {
- // avoid a singular (or close-to-singular) matrix
- mat[0] = 0.01; mat[1] = 0;
- mat[2] = 0; mat[3] = 0.01;
- }
-
- // Try to find the font in the cache
- auto fontIt = std::find_if(fontCache.begin(), fontCache.end(),
- [&](const SplashFont* font){return font && font->matches(fontFile, mat, textMat);}
- );
-
- // The requested font has been found in the cache
- if (fontIt != fontCache.end()) {
- std::rotate(fontCache.begin(), fontIt, fontIt+1);
- return fontCache[0];
- }
+SplashFont *SplashFontEngine::getFont(SplashFontFile *fontFile, const SplashCoord *textMat, const SplashCoord *ctm)
+{
+ SplashCoord mat[4];
+
+ mat[0] = textMat[0] * ctm[0] + textMat[1] * ctm[2];
+ mat[1] = -(textMat[0] * ctm[1] + textMat[1] * ctm[3]);
+ mat[2] = textMat[2] * ctm[0] + textMat[3] * ctm[2];
+ mat[3] = -(textMat[2] * ctm[1] + textMat[3] * ctm[3]);
+ if (!splashCheckDet(mat[0], mat[1], mat[2], mat[3], 0.01)) {
+ // avoid a singular (or close-to-singular) matrix
+ mat[0] = 0.01;
+ mat[1] = 0;
+ mat[2] = 0;
+ mat[3] = 0.01;
+ }
- // The requested font has not been found in the cache
- auto newFont = fontFile->makeFont(mat, textMat);
- if (fontCache.back()) {
- delete fontCache.back();
- }
- std::rotate(fontCache.begin(), fontCache.end()-1, fontCache.end());
+ // Try to find the font in the cache
+ auto fontIt = std::find_if(fontCache.begin(), fontCache.end(), [&](const SplashFont *font) { return font && font->matches(fontFile, mat, textMat); });
- fontCache[0] = newFont;
- return fontCache[0];
+ // The requested font has been found in the cache
+ if (fontIt != fontCache.end()) {
+ std::rotate(fontCache.begin(), fontIt, fontIt + 1);
+ return fontCache[0];
+ }
+
+ // The requested font has not been found in the cache
+ auto newFont = fontFile->makeFont(mat, textMat);
+ if (fontCache.back()) {
+ delete fontCache.back();
+ }
+ std::rotate(fontCache.begin(), fontCache.end() - 1, fontCache.end());
+
+ fontCache[0] = newFont;
+ return fontCache[0];
}
diff --git a/splash/SplashFontEngine.h b/splash/SplashFontEngine.h
index 44396af1..becc0d9c 100644
--- a/splash/SplashFontEngine.h
+++ b/splash/SplashFontEngine.h
@@ -44,53 +44,45 @@ class SplashFontSrc;
// SplashFontEngine
//------------------------------------------------------------------------
-class SplashFontEngine {
+class SplashFontEngine
+{
public:
-
- // Create a font engine.
- SplashFontEngine(
- bool enableFreeType,
- bool enableFreeTypeHinting,
- bool enableSlightHinting,
- bool aa);
-
- ~SplashFontEngine();
-
- SplashFontEngine(const SplashFontEngine &) = delete;
- SplashFontEngine& operator=(const SplashFontEngine &) = delete;
-
- // Get a font file from the cache. Returns NULL if there is no
- // matching entry in the cache.
- SplashFontFile *getFontFile(SplashFontFileID *id);
-
- // Load fonts - these create new SplashFontFile objects.
- SplashFontFile *loadType1Font(SplashFontFileID *idA, SplashFontSrc *src, const char **enc);
- SplashFontFile *loadType1CFont(SplashFontFileID *idA, SplashFontSrc *src, const char **enc);
- SplashFontFile *loadOpenTypeT1CFont(SplashFontFileID *idA, SplashFontSrc *src, const char **enc);
- SplashFontFile *loadCIDFont(SplashFontFileID *idA, SplashFontSrc *src);
- SplashFontFile *loadOpenTypeCFFFont(SplashFontFileID *idA, SplashFontSrc *src,
- int *codeToGID, int codeToGIDLen);
- SplashFontFile *loadTrueTypeFont(SplashFontFileID *idA, SplashFontSrc *src,
- int *codeToGID, int codeToGIDLen, int faceIndex = 0);
-
- // Get a font - this does a cache lookup first, and if not found,
- // creates a new SplashFont object and adds it to the cache. The
- // matrix, mat = textMat * ctm:
- // [ mat[0] mat[1] ]
- // [ mat[2] mat[3] ]
- // specifies the font transform in PostScript style:
- // [x' y'] = [x y] * mat
- // Note that the Splash y axis points downward.
- SplashFont *getFont(SplashFontFile *fontFile,
- const SplashCoord *textMat, const SplashCoord *ctm);
- bool getAA();
- void setAA(bool aa);
+ // Create a font engine.
+ SplashFontEngine(bool enableFreeType, bool enableFreeTypeHinting, bool enableSlightHinting, bool aa);
+
+ ~SplashFontEngine();
+
+ SplashFontEngine(const SplashFontEngine &) = delete;
+ SplashFontEngine &operator=(const SplashFontEngine &) = delete;
+
+ // Get a font file from the cache. Returns NULL if there is no
+ // matching entry in the cache.
+ SplashFontFile *getFontFile(SplashFontFileID *id);
+
+ // Load fonts - these create new SplashFontFile objects.
+ SplashFontFile *loadType1Font(SplashFontFileID *idA, SplashFontSrc *src, const char **enc);
+ SplashFontFile *loadType1CFont(SplashFontFileID *idA, SplashFontSrc *src, const char **enc);
+ SplashFontFile *loadOpenTypeT1CFont(SplashFontFileID *idA, SplashFontSrc *src, const char **enc);
+ SplashFontFile *loadCIDFont(SplashFontFileID *idA, SplashFontSrc *src);
+ SplashFontFile *loadOpenTypeCFFFont(SplashFontFileID *idA, SplashFontSrc *src, int *codeToGID, int codeToGIDLen);
+ SplashFontFile *loadTrueTypeFont(SplashFontFileID *idA, SplashFontSrc *src, int *codeToGID, int codeToGIDLen, int faceIndex = 0);
+
+ // Get a font - this does a cache lookup first, and if not found,
+ // creates a new SplashFont object and adds it to the cache. The
+ // matrix, mat = textMat * ctm:
+ // [ mat[0] mat[1] ]
+ // [ mat[2] mat[3] ]
+ // specifies the font transform in PostScript style:
+ // [x' y'] = [x y] * mat
+ // Note that the Splash y axis points downward.
+ SplashFont *getFont(SplashFontFile *fontFile, const SplashCoord *textMat, const SplashCoord *ctm);
+ bool getAA();
+ void setAA(bool aa);
private:
+ std::array<SplashFont *, 16> fontCache;
- std::array<SplashFont*,16> fontCache;
-
- SplashFTFontEngine *ftEngine;
+ SplashFTFontEngine *ftEngine;
};
#endif
diff --git a/splash/SplashFontFile.cc b/splash/SplashFontFile.cc
index 2e7474cd..d1c2ed0e 100644
--- a/splash/SplashFontFile.cc
+++ b/splash/SplashFontFile.cc
@@ -24,7 +24,7 @@
#include <cstdio>
#ifdef HAVE_UNISTD_H
-#include <unistd.h>
+# include <unistd.h>
#endif
#include "goo/gmem.h"
#include "goo/GooString.h"
@@ -35,81 +35,89 @@
// SplashFontFile
//------------------------------------------------------------------------
-SplashFontFile::SplashFontFile(SplashFontFileID *idA, SplashFontSrc *srcA) {
- id = idA;
- src = srcA;
- src->ref();
- refCnt = 0;
- doAdjustMatrix = false;
+SplashFontFile::SplashFontFile(SplashFontFileID *idA, SplashFontSrc *srcA)
+{
+ id = idA;
+ src = srcA;
+ src->ref();
+ refCnt = 0;
+ doAdjustMatrix = false;
}
-SplashFontFile::~SplashFontFile() {
- src->unref();
- delete id;
+SplashFontFile::~SplashFontFile()
+{
+ src->unref();
+ delete id;
}
-void SplashFontFile::incRefCnt() {
- ++refCnt;
+void SplashFontFile::incRefCnt()
+{
+ ++refCnt;
}
-void SplashFontFile::decRefCnt() {
- if (!--refCnt) {
- delete this;
- }
+void SplashFontFile::decRefCnt()
+{
+ if (!--refCnt) {
+ delete this;
+ }
}
//
-SplashFontSrc::SplashFontSrc() {
- isFile = false;
- deleteSrc = false;
- fileName = nullptr;
- buf = nullptr;
- refcnt = 1;
+SplashFontSrc::SplashFontSrc()
+{
+ isFile = false;
+ deleteSrc = false;
+ fileName = nullptr;
+ buf = nullptr;
+ refcnt = 1;
}
-SplashFontSrc::~SplashFontSrc() {
- if (deleteSrc) {
- if (isFile) {
- if (fileName)
- unlink(fileName->c_str());
- } else {
- if (buf)
- gfree(buf);
+SplashFontSrc::~SplashFontSrc()
+{
+ if (deleteSrc) {
+ if (isFile) {
+ if (fileName)
+ unlink(fileName->c_str());
+ } else {
+ if (buf)
+ gfree(buf);
+ }
}
- }
- if (isFile && fileName)
- delete fileName;
+ if (isFile && fileName)
+ delete fileName;
}
-void SplashFontSrc::ref() {
- refcnt++;
+void SplashFontSrc::ref()
+{
+ refcnt++;
}
-void SplashFontSrc::unref() {
- if (! --refcnt)
- delete this;
+void SplashFontSrc::unref()
+{
+ if (!--refcnt)
+ delete this;
}
void SplashFontSrc::setFile(GooString *file, bool del)
{
- isFile = true;
- fileName = file->copy();
- deleteSrc = del;
+ isFile = true;
+ fileName = file->copy();
+ deleteSrc = del;
}
void SplashFontSrc::setFile(const char *file, bool del)
{
- isFile = true;
- fileName = new GooString(file);
- deleteSrc = del;
+ isFile = true;
+ fileName = new GooString(file);
+ deleteSrc = del;
}
void SplashFontSrc::setBuf(char *bufA, int bufLenA, bool del)
{
- isFile = false;
- buf = bufA;
- bufLen = bufLenA;
- deleteSrc = del;
+ isFile = false;
+ buf = bufA;
+ bufLen = bufLenA;
+ deleteSrc = del;
}
diff --git a/splash/SplashFontFile.h b/splash/SplashFontFile.h
index 133a1441..598fd832 100644
--- a/splash/SplashFontFile.h
+++ b/splash/SplashFontFile.h
@@ -33,64 +33,64 @@ class SplashFontFileID;
// SplashFontFile
//------------------------------------------------------------------------
-class SplashFontSrc {
+class SplashFontSrc
+{
public:
- SplashFontSrc();
+ SplashFontSrc();
- SplashFontSrc(const SplashFontSrc &) = delete;
- SplashFontSrc& operator=(const SplashFontSrc&) = delete;
+ SplashFontSrc(const SplashFontSrc &) = delete;
+ SplashFontSrc &operator=(const SplashFontSrc &) = delete;
- void setFile(GooString *file, bool del);
- void setFile(const char *file, bool del);
- void setBuf(char *bufA, int buflenA, bool del);
+ void setFile(GooString *file, bool del);
+ void setFile(const char *file, bool del);
+ void setBuf(char *bufA, int buflenA, bool del);
- void ref();
- void unref();
+ void ref();
+ void unref();
- bool isFile;
- GooString *fileName;
- char *buf;
- int bufLen;
+ bool isFile;
+ GooString *fileName;
+ char *buf;
+ int bufLen;
private:
- ~SplashFontSrc();
- int refcnt;