summaryrefslogtreecommitdiff
path: root/splash/Splash.cc
diff options
context:
space:
mode:
Diffstat (limited to 'splash/Splash.cc')
-rw-r--r--splash/Splash.cc4548
1 files changed, 3043 insertions, 1505 deletions
diff --git a/splash/Splash.cc b/splash/Splash.cc
index 879a4f2..d9035b3 100644
--- a/splash/Splash.cc
+++ b/splash/Splash.cc
@@ -2,6 +2,8 @@
//
// Splash.cc
//
+// Copyright 2003-2013 Glyph & Cog, LLC
+//
//========================================================================
#include <aconf.h>
@@ -29,7 +31,7 @@
//------------------------------------------------------------------------
-#define splashAAGamma 1.5
+#define splashAAGamma 0.67
// distance of Bezier control point from center for circle approximation
// = (4 * (sqrt(2) - 1) / 3) * r
@@ -46,41 +48,12 @@ static inline Guchar clip255(int x) {
return x < 0 ? 0 : x > 255 ? 255 : x;
}
-// The PDF spec says that all pixels whose *centers* lie within the
-// image target region get painted, so we want to round n+0.5 down to
-// n. But this causes problems, e.g., with PDF files that fill a
-// rectangle with black and then draw an image to the exact same
-// rectangle, so we instead use the fill scan conversion rule.
-// However, the correct rule works better for glyphs, so we also
-// provide that option in fillImageMask.
-#if 0
-static inline int imgCoordMungeLower(SplashCoord x) {
- return splashCeil(x + 0.5) - 1;
-}
-static inline int imgCoordMungeUpper(SplashCoord x) {
- return splashCeil(x + 0.5) - 1;
-}
-#else
-static inline int imgCoordMungeLower(SplashCoord x) {
- return splashFloor(x);
-}
-static inline int imgCoordMungeUpper(SplashCoord x) {
- return splashFloor(x) + 1;
-}
-static inline int imgCoordMungeLowerC(SplashCoord x, GBool glyphMode) {
- return glyphMode ? (splashCeil(x + 0.5) - 1) : splashFloor(x);
-}
-static inline int imgCoordMungeUpperC(SplashCoord x, GBool glyphMode) {
- return glyphMode ? (splashCeil(x + 0.5) - 1) : (splashFloor(x) + 1);
-}
-#endif
-
// Used by drawImage and fillImageMask to divide the target
// quadrilateral into sections.
struct ImageSection {
int y0, y1; // actual y range
int ia0, ia1; // vertex indices for edge A
- int ib0, ib1; // vertex indices for edge A
+ int ib0, ib1; // vertex indices for edge B
SplashCoord xa0, ya0, xa1, ya1; // edge A
SplashCoord dxdya; // slope of edge A
SplashCoord xb0, yb0, xb1, yb1; // edge B
@@ -94,41 +67,26 @@ struct ImageSection {
#define splashPipeMaxStages 9
struct SplashPipe {
- // pixel coordinates
- int x, y;
-
// source pattern
SplashPattern *pattern;
// source alpha and color
Guchar aInput;
- GBool usesShape;
- SplashColorPtr cSrc;
SplashColor cSrcVal;
- // non-isolated group alpha0
- Guchar *alpha0Ptr;
-
- // soft mask
- SplashColorPtr softMaskPtr;
-
- // destination alpha and color
- SplashColorPtr destColorPtr;
- int destColorMask;
- Guchar *destAlphaPtr;
-
- // shape
- Guchar shape;
-
- // result alpha and color
+ // special cases and result color
GBool noTransparency;
+ GBool shapeOnly;
SplashPipeResultColorCtrl resultColorCtrl;
// non-isolated group correction
+ // (this is only used when Splash::composite() is called to composite
+ // a non-isolated group onto the backdrop)
GBool nonIsolatedGroup;
// the "run" function
- void (Splash::*run)(SplashPipe *pipe);
+ void (Splash::*run)(SplashPipe *pipe, int x0, int x1, int y,
+ Guchar *shapePtr, SplashColorPtr cSrcPtr);
};
SplashPipeResultColorCtrl Splash::pipeResultColorNoAlphaBlend[] = {
@@ -208,36 +166,37 @@ inline void Splash::updateModY(int y) {
// pipeline
//------------------------------------------------------------------------
-inline void Splash::pipeInit(SplashPipe *pipe, int x, int y,
- SplashPattern *pattern, SplashColorPtr cSrc,
+inline void Splash::pipeInit(SplashPipe *pipe, SplashPattern *pattern,
Guchar aInput, GBool usesShape,
GBool nonIsolatedGroup) {
- pipeSetXY(pipe, x, y);
pipe->pattern = NULL;
// source color
- if (pattern) {
- if (pattern->isStatic()) {
- pattern->getColor(x, y, pipe->cSrcVal);
- } else {
- pipe->pattern = pattern;
- }
- pipe->cSrc = pipe->cSrcVal;
+ if (pattern && pattern->isStatic()) {
+ pattern->getColor(0, 0, pipe->cSrcVal);
+ pipe->pattern = NULL;
} else {
- pipe->cSrc = cSrc;
+ pipe->pattern = pattern;
}
// source alpha
pipe->aInput = aInput;
- pipe->usesShape = usesShape;
- // result alpha
- if (aInput == 255 && !state->softMask && !usesShape &&
- !state->inNonIsolatedGroup && !nonIsolatedGroup) {
- pipe->noTransparency = gTrue;
- } else {
- pipe->noTransparency = gFalse;
- }
+ // special cases
+ pipe->noTransparency = aInput == 255 &&
+ !state->softMask &&
+ !usesShape &&
+ !state->inNonIsolatedGroup &&
+ !state->inKnockoutGroup &&
+ !nonIsolatedGroup &&
+ state->overprintMask == 0xffffffff;
+ pipe->shapeOnly = aInput == 255 &&
+ !state->softMask &&
+ usesShape &&
+ !state->inNonIsolatedGroup &&
+ !state->inKnockoutGroup &&
+ !nonIsolatedGroup &&
+ state->overprintMask == 0xffffffff;
// result color
if (pipe->noTransparency) {
@@ -255,33 +214,48 @@ inline void Splash::pipeInit(SplashPipe *pipe, int x, int y,
// select the 'run' function
pipe->run = &Splash::pipeRun;
if (!pipe->pattern && pipe->noTransparency && !state->blendFunc) {
- if (bitmap->mode == splashModeMono1 && !pipe->destAlphaPtr) {
+ if (bitmap->mode == splashModeMono1 && !bitmap->alpha) {
pipe->run = &Splash::pipeRunSimpleMono1;
- } else if (bitmap->mode == splashModeMono8 && pipe->destAlphaPtr) {
+ } else if (bitmap->mode == splashModeMono8 && bitmap->alpha) {
pipe->run = &Splash::pipeRunSimpleMono8;
- } else if (bitmap->mode == splashModeRGB8 && pipe->destAlphaPtr) {
+ } else if (bitmap->mode == splashModeRGB8 && bitmap->alpha) {
pipe->run = &Splash::pipeRunSimpleRGB8;
- } else if (bitmap->mode == splashModeBGR8 && pipe->destAlphaPtr) {
+ } else if (bitmap->mode == splashModeBGR8 && bitmap->alpha) {
pipe->run = &Splash::pipeRunSimpleBGR8;
#if SPLASH_CMYK
- } else if (bitmap->mode == splashModeCMYK8 && pipe->destAlphaPtr) {
+ } else if (bitmap->mode == splashModeCMYK8 && bitmap->alpha) {
pipe->run = &Splash::pipeRunSimpleCMYK8;
#endif
}
+ } else if (!pipe->pattern && pipe->shapeOnly && !state->blendFunc) {
+ if (bitmap->mode == splashModeMono1 && !bitmap->alpha) {
+ pipe->run = &Splash::pipeRunShapeMono1;
+ } else if (bitmap->mode == splashModeMono8 && bitmap->alpha) {
+ pipe->run = &Splash::pipeRunShapeMono8;
+ } else if (bitmap->mode == splashModeRGB8 && bitmap->alpha) {
+ pipe->run = &Splash::pipeRunShapeRGB8;
+ } else if (bitmap->mode == splashModeBGR8 && bitmap->alpha) {
+ pipe->run = &Splash::pipeRunShapeBGR8;
+#if SPLASH_CMYK
+ } else if (bitmap->mode == splashModeCMYK8 && bitmap->alpha) {
+ pipe->run = &Splash::pipeRunShapeCMYK8;
+#endif
+ }
} else if (!pipe->pattern && !pipe->noTransparency && !state->softMask &&
- pipe->usesShape &&
- !(state->inNonIsolatedGroup && alpha0Bitmap->alpha) &&
+ usesShape &&
+ !(state->inNonIsolatedGroup && groupBackBitmap->alpha) &&
+ !state->inKnockoutGroup &&
!state->blendFunc && !pipe->nonIsolatedGroup) {
- if (bitmap->mode == splashModeMono1 && !pipe->destAlphaPtr) {
+ if (bitmap->mode == splashModeMono1 && !bitmap->alpha) {
pipe->run = &Splash::pipeRunAAMono1;
- } else if (bitmap->mode == splashModeMono8 && pipe->destAlphaPtr) {
+ } else if (bitmap->mode == splashModeMono8 && bitmap->alpha) {
pipe->run = &Splash::pipeRunAAMono8;
- } else if (bitmap->mode == splashModeRGB8 && pipe->destAlphaPtr) {
+ } else if (bitmap->mode == splashModeRGB8 && bitmap->alpha) {
pipe->run = &Splash::pipeRunAARGB8;
- } else if (bitmap->mode == splashModeBGR8 && pipe->destAlphaPtr) {
+ } else if (bitmap->mode == splashModeBGR8 && bitmap->alpha) {
pipe->run = &Splash::pipeRunAABGR8;
#if SPLASH_CMYK
- } else if (bitmap->mode == splashModeCMYK8 && pipe->destAlphaPtr) {
+ } else if (bitmap->mode == splashModeCMYK8 && bitmap->alpha) {
pipe->run = &Splash::pipeRunAACMYK8;
#endif
}
@@ -289,932 +263,1654 @@ inline void Splash::pipeInit(SplashPipe *pipe, int x, int y,
}
// general case
-void Splash::pipeRun(SplashPipe *pipe) {
- Guchar aSrc, aDest, alphaI, alphaIm1, alpha0, aResult;
- SplashColor cSrcNonIso, cDest, cBlend;
- SplashColorPtr cSrc;
- Guchar cResult0, cResult1, cResult2, cResult3;
- int t;
+void Splash::pipeRun(SplashPipe *pipe, int x0, int x1, int y,
+ Guchar *shapePtr, SplashColorPtr cSrcPtr) {
+ Guchar *shapePtr2;
+ Guchar shape, aSrc, aDest, alphaI, alphaIm1, alpha0, aResult;
+ SplashColor cSrc, cDest, cBlend;
+ Guchar shapeVal, cResult0, cResult1, cResult2, cResult3;
+ int cSrcStride, shapeStride, x, lastX, t, i;
+ SplashColorPtr destColorPtr;
+ Guchar destColorMask;
+ Guchar *destAlphaPtr;
+ SplashColorPtr color0Ptr;
+ Guchar color0Mask;
+ Guchar *alpha0Ptr;
+ SplashColorPtr softMaskPtr;
#if SPLASH_CMYK
SplashColor cSrc2, cDest2;
#endif
- //----- source color
+ if (cSrcPtr && !pipe->pattern) {
+ cSrcStride = bitmapComps;
+ } else {
+ cSrcPtr = pipe->cSrcVal;
+ cSrcStride = 0;
+ }
- // static pattern: handled in pipeInit
- // fixed color: handled in pipeInit
+ if (shapePtr) {
+ shapePtr2 = shapePtr;
+ shapeStride = 1;
+ for (; x0 <= x1; ++x0) {
+ if (*shapePtr2) {
+ break;
+ }
+ cSrcPtr += cSrcStride;
+ ++shapePtr2;
+ }
+ } else {
+ shapeVal = 0xff;
+ shapePtr2 = &shapeVal;
+ shapeStride = 0;
+ }
+ if (x0 > x1) {
+ return;
+ }
+ updateModX(x0);
+ updateModY(y);
+ lastX = x0;
- // dynamic pattern
- if (pipe->pattern) {
- pipe->pattern->getColor(pipe->x, pipe->y, pipe->cSrcVal);
+ if (bitmap->mode == splashModeMono1) {
+ destColorPtr = &bitmap->data[y * bitmap->rowSize + (x0 >> 3)];
+ destColorMask = 0x80 >> (x0 & 7);
+ } else {
+ destColorPtr = &bitmap->data[y * bitmap->rowSize + x0 * bitmapComps];
+ destColorMask = 0; // make gcc happy
+ }
+ if (bitmap->alpha) {
+ destAlphaPtr = &bitmap->alpha[y * bitmap->width + x0];
+ } else {
+ destAlphaPtr = NULL;
+ }
+ if (state->softMask) {
+ softMaskPtr = &state->softMask->data[y * state->softMask->rowSize + x0];
+ } else {
+ softMaskPtr = NULL;
+ }
+ if (state->inKnockoutGroup) {
+ if (bitmap->mode == splashModeMono1) {
+ color0Ptr =
+ &groupBackBitmap->data[(groupBackY + y) * groupBackBitmap->rowSize +
+ ((groupBackX + x0) >> 3)];
+ color0Mask = 0x80 >> ((groupBackX + x0) & 7);
+ } else {
+ color0Ptr =
+ &groupBackBitmap->data[(groupBackY + y) * groupBackBitmap->rowSize +
+ (groupBackX + x0) * bitmapComps];
+ color0Mask = 0; // make gcc happy
+ }
+ } else {
+ color0Ptr = NULL;
+ color0Mask = 0; // make gcc happy
+ }
+ if (state->inNonIsolatedGroup && groupBackBitmap->alpha) {
+ alpha0Ptr =
+ &groupBackBitmap->alpha[(groupBackY + y) * groupBackBitmap->width +
+ (groupBackX + x0)];
+ } else {
+ alpha0Ptr = NULL;
}
- if (pipe->noTransparency && !state->blendFunc) {
+ for (x = x0; x <= x1; ++x) {
- //----- write destination pixel
+ //----- shape
- switch (bitmap->mode) {
- case splashModeMono1:
- cResult0 = state->grayTransfer[pipe->cSrc[0]];
- if (state->screen->test(pipe->x, pipe->y, cResult0)) {
- *pipe->destColorPtr |= pipe->destColorMask;
+ shape = *shapePtr2;
+ if (!shape) {
+ if (bitmap->mode == splashModeMono1) {
+ destColorPtr += destColorMask & 1;
+ destColorMask = (destColorMask << 7) | (destColorMask >> 1);
} else {
- *pipe->destColorPtr &= ~pipe->destColorMask;
+ destColorPtr += bitmapComps;
}
- 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 splashModeBGR8:
- *pipe->destColorPtr++ = state->rgbTransferB[pipe->cSrc[2]];
- *pipe->destColorPtr++ = state->rgbTransferG[pipe->cSrc[1]];
- *pipe->destColorPtr++ = state->rgbTransferR[pipe->cSrc[0]];
- break;
-#if SPLASH_CMYK
- case splashModeCMYK8:
- if (state->overprintMask & 1) {
- pipe->destColorPtr[0] = state->cmykTransferC[pipe->cSrc[0]];
+ if (destAlphaPtr) {
+ ++destAlphaPtr;
}
- if (state->overprintMask & 2) {
- pipe->destColorPtr[1] = state->cmykTransferM[pipe->cSrc[1]];
+ if (softMaskPtr) {
+ ++softMaskPtr;
}
- if (state->overprintMask & 4) {
- pipe->destColorPtr[2] = state->cmykTransferY[pipe->cSrc[2]];
+ if (color0Ptr) {
+ if (bitmap->mode == splashModeMono1) {
+ color0Ptr += color0Mask & 1;
+ color0Mask = (color0Mask << 7) | (color0Mask >> 1);
+ } else {
+ color0Ptr += bitmapComps;
+ }
}
- if (state->overprintMask & 8) {
- pipe->destColorPtr[3] = state->cmykTransferK[pipe->cSrc[3]];
+ if (alpha0Ptr) {
+ ++alpha0Ptr;
}
- pipe->destColorPtr += 4;
- break;
-#endif
+ cSrcPtr += cSrcStride;
+ shapePtr2 += shapeStride;
+ continue;
}
- if (pipe->destAlphaPtr) {
- *pipe->destAlphaPtr++ = 255;
+ lastX = x;
+
+ //----- source color
+
+ // static pattern: handled in pipeInit
+ // fixed color: handled in pipeInit
+
+ // dynamic pattern
+ if (pipe->pattern) {
+ pipe->pattern->getColor(x, y, pipe->cSrcVal);
}
- } else {
+ if (pipe->noTransparency && !state->blendFunc) {
- //----- read destination pixel
+ //----- write destination pixel
- switch (bitmap->mode) {
- case splashModeMono1:
- cDest[0] = (*pipe->destColorPtr & pipe->destColorMask) ? 0xff : 0x00;
- break;
- case splashModeMono8:
- cDest[0] = *pipe->destColorPtr;
- break;
- case splashModeRGB8:
- cDest[0] = pipe->destColorPtr[0];
- cDest[1] = pipe->destColorPtr[1];
- cDest[2] = pipe->destColorPtr[2];
- break;
- case splashModeBGR8:
- cDest[0] = pipe->destColorPtr[2];
- cDest[1] = pipe->destColorPtr[1];
- cDest[2] = pipe->destColorPtr[0];
- break;
+ switch (bitmap->mode) {
+ case splashModeMono1:
+ cResult0 = state->grayTransfer[cSrcPtr[0]];
+ if (state->screen->test(x, y, cResult0)) {
+ *destColorPtr |= destColorMask;
+ } else {
+ *destColorPtr &= ~destColorMask;
+ }
+ destColorPtr += destColorMask & 1;
+ destColorMask = (destColorMask << 7) | (destColorMask >> 1);
+ break;
+ case splashModeMono8:
+ *destColorPtr++ = state->grayTransfer[cSrcPtr[0]];
+ break;
+ case splashModeRGB8:
+ destColorPtr[0] = state->rgbTransferR[cSrcPtr[0]];
+ destColorPtr[1] = state->rgbTransferG[cSrcPtr[1]];
+ destColorPtr[2] = state->rgbTransferB[cSrcPtr[2]];
+ destColorPtr += 3;
+ break;
+ case splashModeBGR8:
+ destColorPtr[0] = state->rgbTransferB[cSrcPtr[2]];
+ destColorPtr[1] = state->rgbTransferG[cSrcPtr[1]];
+ destColorPtr[2] = state->rgbTransferR[cSrcPtr[0]];
+ destColorPtr += 3;
+ break;
#if SPLASH_CMYK
- case splashModeCMYK8:
- cDest[0] = pipe->destColorPtr[0];
- cDest[1] = pipe->destColorPtr[1];
- cDest[2] = pipe->destColorPtr[2];
- cDest[3] = pipe->destColorPtr[3];
- break;
+ case splashModeCMYK8:
+ destColorPtr[0] = state->cmykTransferC[cSrcPtr[0]];
+ destColorPtr[1] = state->cmykTransferM[cSrcPtr[1]];
+ destColorPtr[2] = state->cmykTransferY[cSrcPtr[2]];
+ destColorPtr[3] = state->cmykTransferK[cSrcPtr[3]];
+ destColorPtr += 4;
+ break;
#endif
- }
- if (pipe->destAlphaPtr) {
- aDest = *pipe->destAlphaPtr;
- } else {
- aDest = 0xff;
- }
+ }
+ if (destAlphaPtr) {
+ *destAlphaPtr++ = 255;
+ }
- //----- source alpha
+ } else { // if (noTransparency && !blendFunc)
+
+ //----- read destination pixel
+ // (or backdrop color, for knockout groups)
+
+ if (color0Ptr) {
+
+ switch (bitmap->mode) {
+ case splashModeMono1:
+ cDest[0] = (*color0Ptr & color0Mask) ? 0xff : 0x00;
+ color0Ptr += color0Mask & 1;
+ color0Mask = (color0Mask << 7) | (color0Mask >> 1);
+ break;
+ case splashModeMono8:
+ cDest[0] = *color0Ptr++;
+ break;
+ case splashModeRGB8:
+ cDest[0] = color0Ptr[0];
+ cDest[1] = color0Ptr[1];
+ cDest[2] = color0Ptr[2];
+ color0Ptr += 3;
+ break;
+ case splashModeBGR8:
+ cDest[2] = color0Ptr[0];
+ cDest[1] = color0Ptr[1];
+ cDest[0] = color0Ptr[2];
+ color0Ptr += 3;
+ break;
+#if SPLASH_CMYK
+ case splashModeCMYK8:
+ cDest[0] = color0Ptr[0];
+ cDest[1] = color0Ptr[1];
+ cDest[2] = color0Ptr[2];
+ cDest[3] = color0Ptr[3];
+ color0Ptr += 4;
+ break;
+#endif
+ }
- if (state->softMask) {
- if (pipe->usesShape) {
- aSrc = div255(div255(pipe->aInput * *pipe->softMaskPtr++) *
- pipe->shape);
} else {
- aSrc = div255(pipe->aInput * *pipe->softMaskPtr++);
+
+ switch (bitmap->mode) {
+ case splashModeMono1:
+ cDest[0] = (*destColorPtr & 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 splashModeBGR8:
+ cDest[0] = destColorPtr[2];
+ cDest[1] = destColorPtr[1];
+ cDest[2] = destColorPtr[0];
+ break;
+#if SPLASH_CMYK
+ case splashModeCMYK8:
+ cDest[0] = destColorPtr[0];
+ cDest[1] = destColorPtr[1];
+ cDest[2] = destColorPtr[2];
+ cDest[3] = destColorPtr[3];
+ break;
+#endif
+ }
+
}
- } else if (pipe->usesShape) {
- aSrc = div255(pipe->aInput * pipe->shape);
- } else {
- aSrc = pipe->aInput;
- }
- //----- non-isolated group correction
+ if (destAlphaPtr) {
+ aDest = *destAlphaPtr;
+ } else {
+ aDest = 0xff;
+ }
+
+ //----- overprint
- 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;
+ for (i = 0; i < bitmapComps; ++i) {
+#if SPLASH_CMYK
+ if (state->overprintMask & (1 << i)) {
+ cSrc[i] = cSrcPtr[i];
+ } else {
+ cSrc[i] = div255(aDest * cDest[i]);
+ }
+#else
+ cSrc[i] = cSrcPtr[i];
+#endif
+ }
+
+ //----- source alpha
+
+ if (softMaskPtr) {
+ if (shapePtr) {
+ aSrc = div255(div255(pipe->aInput * *softMaskPtr++) * shape);
+ } else {
+ aSrc = div255(pipe->aInput * *softMaskPtr++);
+ }
+ } else if (shapePtr) {
+ aSrc = div255(pipe->aInput * shape);
} else {
- t = (aDest * 255) / pipe->shape - aDest;
+ 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, shape is the source (group) alpha.
+ t = (aDest * 255) / shape - aDest;
switch (bitmap->mode) {
#if SPLASH_CMYK
case splashModeCMYK8:
- cSrcNonIso[3] = clip255(pipe->cSrc[3] +
- ((pipe->cSrc[3] - cDest[3]) * t) / 255);
+ cSrc[3] = clip255(cSrc[3] + ((cSrc[3] - cDest[3]) * t) / 255);
#endif
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);
+ cSrc[2] = clip255(cSrc[2] + ((cSrc[2] - cDest[2]) * t) / 255);
+ cSrc[1] = clip255(cSrc[1] + ((cSrc[1] - cDest[1]) * t) / 255);
case splashModeMono1:
case splashModeMono8:
- cSrcNonIso[0] = clip255(pipe->cSrc[0] +
- ((pipe->cSrc[0] - cDest[0]) * t) / 255);
+ cSrc[0] = clip255(cSrc[0] + ((cSrc[0] - cDest[0]) * t) / 255);
break;
}
- cSrc = cSrcNonIso;
}
- } else {
- cSrc = pipe->cSrc;
- }
- //----- blend function
+ //----- blend function
- if (state->blendFunc) {
+ if (state->blendFunc) {
#if SPLASH_CMYK
- if (bitmap->mode == splashModeCMYK8) {
- // convert colors to additive
- cSrc2[0] = 0xff - cSrc[0];
- cSrc2[1] = 0xff - cSrc[1];
- cSrc2[2] = 0xff - cSrc[2];
- cSrc2[3] = 0xff - cSrc[3];
- cDest2[0] = 0xff - cDest[0];
- cDest2[1] = 0xff - cDest[1];
- cDest2[2] = 0xff - cDest[2];
- cDest2[3] = 0xff - cDest[3];
- (*state->blendFunc)(cSrc2, cDest2, cBlend, bitmap->mode);
- // convert result back to subtractive
- cBlend[0] = 0xff - cBlend[0];
- cBlend[1] = 0xff - cBlend[1];
- cBlend[2] = 0xff - cBlend[2];
- cBlend[3] = 0xff - cBlend[3];
- } else
+ if (bitmap->mode == splashModeCMYK8) {
+ // convert colors to additive
+ cSrc2[0] = 0xff - cSrc[0];
+ cSrc2[1] = 0xff - cSrc[1];
+ cSrc2[2] = 0xff - cSrc[2];
+ cSrc2[3] = 0xff - cSrc[3];
+ cDest2[0] = 0xff - cDest[0];
+ cDest2[1] = 0xff - cDest[1];
+ cDest2[2] = 0xff - cDest[2];
+ cDest2[3] = 0xff - cDest[3];
+ (*state->blendFunc)(cSrc2, cDest2, cBlend, bitmap->mode);
+ // convert result back to subtractive
+ cBlend[0] = 0xff - cBlend[0];
+ cBlend[1] = 0xff - cBlend[1];
+ cBlend[2] = 0xff - cBlend[2];
+ cBlend[3] = 0xff - cBlend[3];
+ } else
#endif
- (*state->blendFunc)(cSrc, cDest, cBlend, bitmap->mode);
- }
-
- //----- result alpha and non-isolated group element correction
+ (*state->blendFunc)(cSrc, cDest, cBlend, bitmap->mode);
+ }
- if (pipe->noTransparency) {
- alphaI = alphaIm1 = aResult = 255;
- } else {
- aResult = aSrc + aDest - div255(aSrc * aDest);
+ //----- result alpha and non-isolated group element correction
// 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);
+
+ if (pipe->noTransparency) {
+ alphaI = alphaIm1 = aResult = 255;
+ } else if (alpha0Ptr) {
+ if (color0Ptr) {
+ // non-isolated, knockout
+ aResult = aSrc;
+ alpha0 = *alpha0Ptr++;
+ alphaI = aSrc + alpha0 - div255(aSrc * alpha0);
+ alphaIm1 = alpha0;
+ } else {
+ // non-isolated, non-knockout
+ aResult = aSrc + aDest - div255(aSrc * aDest);
+ alpha0 = *alpha0Ptr++;
+ alphaI = aResult + alpha0 - div255(aResult * alpha0);
+ alphaIm1 = alpha0 + aDest - div255(alpha0 * aDest);
+ }
} else {
- alphaI = aResult;
- alphaIm1 = aDest;
+ if (color0Ptr) {
+ // isolated, knockout
+ aResult = aSrc;
+ alphaI = aSrc;
+ alphaIm1 = 0;
+ } else {
+ // isolated, non-knockout
+ aResult = aSrc + aDest - div255(aSrc * aDest);
+ alphaI = aResult;
+ alphaIm1 = aDest;
+ }
}
- }
- //----- result color
+ //----- result color
- cResult0 = cResult1 = cResult2 = cResult3 = 0; // make gcc happy
+ cResult0 = cResult1 = cResult2 = cResult3 = 0; // make gcc happy
- switch (pipe->resultColorCtrl) {
+ 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 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;
#if SPLASH_CMYK
- case splashPipeResultColorNoAlphaBlendCMYK:
- cResult0 = state->cmykTransferC[div255((255 - aDest) * cSrc[0] +
- aDest * cBlend[0])];
- cResult1 = state->cmykTransferM[div255((255 - aDest) * cSrc[1] +
- aDest * cBlend[1])];
- cResult2 = state->cmykTransferY[div255((255 - aDest) * cSrc[2] +
- aDest * cBlend[2])];
- cResult3 = state->cmykTransferK[div255((255 - aDest) * cSrc[3] +
- aDest * cBlend[3])];
- break;
+ case 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;
#endif
- case splashPipeResultColorAlphaNoBlendMono:
- if (alphaI == 0) {
- cResult0 = 0;
- } else {
- cResult0 = state->grayTransfer[((alphaI - aSrc) * cDest[0] +
- aSrc * cSrc[0]) / alphaI];
- }
- break;
- case splashPipeResultColorAlphaNoBlendRGB:
- if (alphaI == 0) {
- cResult0 = 0;
- cResult1 = 0;
- cResult2 = 0;
- } else {
- cResult0 = state->rgbTransferR[((alphaI - aSrc) * cDest[0] +
- aSrc * cSrc[0]) / alphaI];
- cResult1 = state->rgbTransferG[((alphaI - aSrc) * cDest[1] +
- aSrc * cSrc[1]) / alphaI];
- cResult2 = state->rgbTransferB[((alphaI - aSrc) * cDest[2] +
- aSrc * cSrc[2]) / alphaI];
- }
- break;
+ 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;
#if SPLASH_CMYK
- case splashPipeResultColorAlphaNoBlendCMYK:
- if (alphaI == 0) {
- cResult0 = 0;
- cResult1 = 0;
- cResult2 = 0;
- cResult3 = 0;
- } else {
- cResult0 = state->cmykTransferC[((alphaI - aSrc) * cDest[0] +
- aSrc * cSrc[0]) / alphaI];
- cResult1 = state->cmykTransferM[((alphaI - aSrc) * cDest[1] +
- aSrc * cSrc[1]) / alphaI];
- cResult2 = state->cmykTransferY[((alphaI - aSrc) * cDest[2] +
- aSrc * cSrc[2]) / alphaI];
- cResult3 = state->cmykTransferK[((alphaI - aSrc) * cDest[3] +
- aSrc * cSrc[3]) / alphaI];
- }
- break;
+ case 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;
#endif
- case splashPipeResultColorAlphaBlendMono:
- if (alphaI == 0) {
- cResult0 = 0;
- } else {
- cResult0 = state->grayTransfer[((alphaI - aSrc) * cDest[0] +
- aSrc * ((255 - alphaIm1) * cSrc[0] +
- alphaIm1 * cBlend[0]) / 255) /
- alphaI];
- }
- break;
- case splashPipeResultColorAlphaBlendRGB:
- if (alphaI == 0) {
- cResult0 = 0;
- cResult1 = 0;
- cResult2 = 0;
- } else {
- cResult0 = state->rgbTransferR[((alphaI - aSrc) * cDest[0] +
- aSrc * ((255 - alphaIm1) * cSrc[0] +
- alphaIm1 * cBlend[0]) / 255) /
- alphaI];
- cResult1 = state->rgbTransferG[((alphaI - aSrc) * cDest[1] +
- aSrc * ((255 - alphaIm1) * cSrc[1] +
- alphaIm1 * cBlend[1]) / 255) /
- alphaI];
- cResult2 = state->rgbTransferB[((alphaI - aSrc) * cDest[2] +
- aSrc * ((255 - alphaIm1) * cSrc[2] +
- alphaIm1 * cBlend[2]) / 255) /
- alphaI];
- }
- break;
+ 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;
#if SPLASH_CMYK
- case splashPipeResultColorAlphaBlendCMYK:
- if (alphaI == 0) {
- cResult0 = 0;
- cResult1 = 0;
- cResult2 = 0;
- cResult3 = 0;
- } else {
- cResult0 = state->cmykTransferC[((alphaI - aSrc) * cDest[0] +
- aSrc * ((255 - alphaIm1) * cSrc[0] +
- alphaIm1 * cBlend[0]) / 255) /
- alphaI];
- cResult1 = state->cmykTransferM[((alphaI - aSrc) * cDest[1] +
- aSrc * ((255 - alphaIm1) * cSrc[1] +
- alphaIm1 * cBlend[1]) / 255) /
- alphaI];
- cResult2 = state->cmykTransferY[((alphaI - aSrc) * cDest[2] +
- aSrc * ((255 - alphaIm1) * cSrc[2] +
- alphaIm1 * cBlend[2]) / 255) /
- alphaI];
- cResult3 = state->cmykTransferK[((alphaI - aSrc) * cDest[3] +
- aSrc * ((255 - alphaIm1) * cSrc[3] +
- alphaIm1 * cBlend[3]) / 255) /
- alphaI];
- }
- break;
+ case 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;
#endif
- }
+ }
- //----- write destination pixel
+ //----- 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 splashModeBGR8:
- *pipe->destColorPtr++ = cResult2;
- *pipe->destColorPtr++ = cResult1;
- *pipe->destColorPtr++ = cResult0;
- break;
+ switch (bitmap->mode) {
+ case splashModeMono1:
+ if (state->screen->test(x, y, cResult0)) {
+ *destColorPtr |= destColorMask;
+ } else {
+ *destColorPtr &= ~destColorMask;
+ }
+ destColorPtr += destColorMask & 1;
+ destColorMask = (destColorMask << 7) | (destColorMask >> 1);
+ break;
+ case splashModeMono8:
+ *destColorPtr++ = cResult0;
+ break;
+ case splashModeRGB8:
+ destColorPtr[0] = cResult0;
+ destColorPtr[1] = cResult1;
+ destColorPtr[2] = cResult2;
+ destColorPtr += 3;
+ break;
+ case splashModeBGR8:
+ destColorPtr[0] = cResult2;
+ destColorPtr[1] = cResult1;
+ destColorPtr[2] = cResult0;
+ destColorPtr += 3;
+ break;
#if SPLASH_CMYK
- case splashModeCMYK8:
- if (state->overprintMask & 1) {
- pipe->destColorPtr[0] = cResult0;
- }
- if (state->overprintMask & 2) {
- pipe->destColorPtr[1] = cResult1;
- }
- if (state->overprintMask & 4) {
- pipe->destColorPtr[2] = cResult2;
+ case splashModeCMYK8:
+ destColorPtr[0] = cResult0;
+ destColorPtr[1] = cResult1;
+ destColorPtr[2] = cResult2;
+ destColorPtr[3] = cResult3;
+ destColorPtr += 4;
+ break;
+#endif
}
- if (state->overprintMask & 8) {
- pipe->destColorPtr[3] = cResult3;
+ if (destAlphaPtr) {
+ *destAlphaPtr++ = aResult;
}
- pipe->destColorPtr += 4;
- break;
-#endif
- }
- if (pipe->destAlphaPtr) {
- *pipe->destAlphaPtr++ = aResult;
- }
- }
+ } // if (noTransparency && !blendFunc)
+
+ cSrcPtr += cSrcStride;
+ shapePtr2 += shapeStride;
+ } // for (x ...)
- ++pipe->x;
+ updateModX(lastX);
}
// special case:
// !pipe->pattern && pipe->noTransparency && !state->blendFunc &&
-// bitmap->mode == splashModeMono1 && !pipe->destAlphaPtr) {
-void Splash::pipeRunSimpleMono1(SplashPipe *pipe) {
+// bitmap->mode == splashModeMono1 && !bitmap->alpha) {
+void Splash::pipeRunSimpleMono1(SplashPipe *pipe, int x0, int x1, int y,
+ Guchar *shapePtr, SplashColorPtr cSrcPtr) {
Guchar cResult0;
+ SplashColorPtr destColorPtr;
+ Guchar destColorMask;
+ int cSrcStride, x;
- //----- write destination pixel
- cResult0 = state->grayTransfer[pipe->cSrc[0]];
- if (state->screen->test(pipe->x, pipe->y, cResult0)) {
- *pipe->destColorPtr |= pipe->destColorMask;
+ if (cSrcPtr) {
+ cSrcStride = 1;
} else {
- *pipe->destColorPtr &= ~pipe->destColorMask;
+ cSrcPtr = pipe->cSrcVal;
+ cSrcStride = 0;
}
- if (!(pipe->destColorMask >>= 1)) {
- pipe->destColorMask = 0x80;
- ++pipe->destColorPtr;
+ if (x0 > x1) {
+ return;
}
+ updateModX(x0);
+ updateModX(x1);
+ updateModY(y);
- ++pipe->x;
+ destColorPtr = &bitmap->data[y * bitmap->rowSize + (x0 >> 3)];
+ destColorMask = 0x80 >> (x0 & 7);
+
+ for (x = x0; x <= x1; ++x) {
+
+ //----- write destination pixel
+ cResult0 = state->grayTransfer[cSrcPtr[0]];
+ if (state->screen->test(x, y, cResult0)) {
+ *destColorPtr |= destColorMask;
+ } else {
+ *destColorPtr &= ~destColorMask;
+ }
+ destColorPtr += destColorMask & 1;
+ destColorMask = (destColorMask << 7) | (destColorMask >> 1);
+
+ cSrcPtr += cSrcStride;
+ }
}
// 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;
+// bitmap->mode == splashModeMono8 && bitmap->alpha) {
+void Splash::pipeRunSimpleMono8(SplashPipe *pipe, int x0, int x1, int y,
+ Guchar *shapePtr, SplashColorPtr cSrcPtr) {
+ SplashColorPtr destColorPtr;
+ Guchar *destAlphaPtr;
+ int cSrcStride, x;
+
+ if (cSrcPtr) {
+ cSrcStride = 1;
+ } else {
+ cSrcPtr = pipe->cSrcVal;
+ cSrcStride = 0;
+ }
+ if (x0 > x1) {
+ return;
+ }
+ updateModX(x0);
+ updateModX(x1);
+ updateModY(y);
+
+ destColorPtr = &bitmap->data[y * bitmap->rowSize + x0];
+ destAlphaPtr = &bitmap->alpha[y * bitmap->width + x0];
+
+ for (x = x0; x <= x1; ++x) {
+
+ //----- write destination pixel
+ *destColorPtr++ = state->grayTransfer[cSrcPtr[0]];
+ *destAlphaPtr++ = 255;
- ++pipe->x;
+ cSrcPtr += cSrcStride;
+ }
}
// special case:
// !pipe->pattern && pipe->noTransparency && !state->blendFunc &&
-// bitmap->mode == splashModeRGB8 && pipe->destAlphaPtr) {
-void Splash::pipeRunSimpleRGB8(SplashPipe *pipe) {
- //----- write destination pixel
- *pipe->destColorPtr++ = state->rgbTransferR[pipe->cSrc[0]];
- *pipe->destColorPtr++ = state->rgbTransferG[pipe->cSrc[1]];
- *pipe->destColorPtr++ = state->rgbTransferB[pipe->cSrc[2]];
- *pipe->destAlphaPtr++ = 255;
-
- ++pipe->x;
+// bitmap->mode == splashModeRGB8 && bitmap->alpha) {
+void Splash::pipeRunSimpleRGB8(SplashPipe *pipe, int x0, int x1, int y,
+ Guchar *shapePtr, SplashColorPtr cSrcPtr) {
+ SplashColorPtr destColorPtr;
+ Guchar *destAlphaPtr;
+ int cSrcStride, x;
+
+ if (cSrcPtr) {
+ cSrcStride = 3;
+ } else {
+ cSrcPtr = pipe->cSrcVal;
+ cSrcStride = 0;
+ }
+ if (x0 > x1) {
+ return;
+ }
+ updateModX(x0);
+ updateModX(x1);
+ updateModY(y);
+
+ destColorPtr = &bitmap->data[y * bitmap->rowSize + 3 * x0];
+ destAlphaPtr = &bitmap->alpha[y * bitmap->width + x0];
+
+ for (x = x0; x <= x1; ++x) {
+
+ //----- write destination pixel
+ destColorPtr[0] = state->rgbTransferR[cSrcPtr[0]];
+ destColorPtr[1] = state->rgbTransferG[cSrcPtr[1]];
+ destColorPtr[2] = state->rgbTransferB[cSrcPtr[2]];
+ destColorPtr += 3;
+ *destAlphaPtr++ = 255;
+
+ cSrcPtr += cSrcStride;
+ }
}
// special case:
// !pipe->pattern && pipe->noTransparency && !state->blendFunc &&
-// bitmap->mode == splashModeBGR8 && pipe->destAlphaPtr) {
-void Splash::pipeRunSimpleBGR8(SplashPipe *pipe) {
- //----- write destination pixel
- *pipe->destColorPtr++ = state->rgbTransferB[pipe->cSrc[2]];
- *pipe->destColorPtr++ = state->rgbTransferG[pipe->cSrc[1]];
- *pipe->destColorPtr++ = state->rgbTransferR[pipe->cSrc[0]];
- *pipe->destAlphaPtr++ = 255;
-
- ++pipe->x;
+// bitmap->mode == splashModeBGR8 && bitmap->alpha) {
+void Splash::pipeRunSimpleBGR8(SplashPipe *pipe, int x0, int x1, int y,
+ Guchar *shapePtr, SplashColorPtr cSrcPtr) {
+ SplashColorPtr destColorPtr;
+ Guchar *destAlphaPtr;
+ int cSrcStride, x;
+
+ if (cSrcPtr) {
+ cSrcStride = 3;
+ } else {
+ cSrcPtr = pipe->cSrcVal;
+ cSrcStride = 0;
+ }
+ if (x0 > x1) {
+ return;
+ }
+ updateModX(x0);
+ updateModX(x1);
+ updateModY(y);
+
+ destColorPtr = &bitmap->data[y * bitmap->rowSize + 3 * x0];
+ destAlphaPtr = &bitmap->alpha[y * bitmap->width + x0];
+
+ for (x = x0; x <= x1; ++x) {
+
+ //----- write destination pixel
+ destColorPtr[0] = state->rgbTransferB[cSrcPtr[2]];
+ destColorPtr[1] = state->rgbTransferG[cSrcPtr[1]];
+ destColorPtr[2] = state->rgbTransferR[cSrcPtr[0]];
+ destColorPtr += 3;
+ *destAlphaPtr++ = 255;
+
+ cSrcPtr += cSrcStride;
+ }
}
#if SPLASH_CMYK
// special case:
// !pipe->pattern && pipe->noTransparency && !state->blendFunc &&
-// bitmap->mode == splashModeCMYK8 && pipe->destAlphaPtr) {
-void Splash::pipeRunSimpleCMYK8(SplashPipe *pipe) {
- //----- write destination pixel
- if (state->overprintMask & 1) {
- pipe->destColorPtr[0] = state->cmykTransferC[pipe->cSrc[0]];
- }
- if (state->overprintMask & 2) {
- pipe->destColorPtr[1] = state->cmykTransferM[pipe->cSrc[1]];
- }
- if (state->overprintMask & 4) {
- pipe->destColorPtr[2] = state->cmykTransferY[pipe->cSrc[2]];
+// bitmap->mode == splashModeCMYK8 && bitmap->alpha) {
+void Splash::pipeRunSimpleCMYK8(SplashPipe *pipe, int x0, int x1, int y,
+ Guchar *shapePtr, SplashColorPtr cSrcPtr) {
+ SplashColorPtr destColorPtr;
+ Guchar *destAlphaPtr;
+ int cSrcStride, x;
+
+ if (cSrcPtr) {
+ cSrcStride = 4;
+ } else {
+ cSrcPtr = pipe->cSrcVal;
+ cSrcStride = 0;
}
- if (state->overprintMask & 8) {
- pipe->destColorPtr[3] = state->cmykTransferK[pipe->cSrc[3]];
+ if (x0 > x1) {
+ return;
}
- pipe->destColorPtr += 4;
- *pipe->destAlphaPtr++ = 255;
+ updateModX(x0);
+ updateModX(x1);
+ updateModY(y);
+
+ destColorPtr = &bitmap->data[y * bitmap->rowSize + 4 * x0];
+ destAlphaPtr = &bitmap->alpha[y * bitmap->width + x0];
+
+ for (x = x0; x <= x1; ++x) {
+
+ //----- write destination pixel
+ destColorPtr[0] = state->cmykTransferC[cSrcPtr[0]];
+ destColorPtr[1] = state->cmykTransferM[cSrcPtr[1]];
+ destColorPtr[2] = state->cmykTransferY[cSrcPtr[2]];
+ destColorPtr[3] = state->cmykTransferK[cSrcPtr[3]];
+ destColorPtr += 4;
+ *destAlphaPtr++ = 255;
- ++pipe->x;
+ cSrcPtr += cSrcStride;
+ }
}
#endif
// special case:
-// !pipe->pattern && !pipe->noTransparency && !state->softMask &&
-// pipe->usesShape && !pipe->alpha0Ptr && !state->blendFunc &&
-// !pipe->nonIsolatedGroup &&
-// bitmap->mode == splashModeMono1 && !pipe->destAlphaPtr
-void Splash::pipeRunAAMono1(SplashPipe *pipe) {
- Guchar aSrc;
- SplashColor cDest;
- Guchar cResult0;
+// !pipe->pattern && pipe->shapeOnly && !state->blendFunc &&
+// bitmap->mode == splashModeMono1 && !bitmap->alpha
+void Splash::pipeRunShapeMono1(SplashPipe *pipe, int x0, int x1, int y,
+ Guchar *shapePtr, SplashColorPtr cSrcPtr) {
+ Guchar shape, aSrc, cDest0, cResult0;
+ SplashColorPtr destColorPtr;
+ Guchar destColorMask;
+ int cSrcStride, x, lastX;
+
+ if (cSrcPtr) {
+ cSrcStride = 1;
+ } else {
+ cSrcPtr = pipe->cSrcVal;
+ cSrcStride = 0;
+ }
+ for (; x0 <= x1; ++x0) {
+ if (*shapePtr) {
+ break;
+ }
+ cSrcPtr += cSrcStride;
+ ++shapePtr;
+ }
+ if (x0 > x1) {
+ return;
+ }
+ updateModX(x0);
+ updateModY(y);
+ lastX = x0;
- //----- read destination pixel
- cDest[0] = (*pipe->destColorPtr & pipe->destColorMask) ? 0xff : 0x00;
+ destColorPtr = &bitmap->data[y * bitmap->rowSize + (x0 >> 3)];
+ destColorMask = 0x80 >> (x0 & 7);
- //----- source alpha
- aSrc = div255(pipe->aInput * pipe->shape);
+ for (x = x0; x <= x1; ++x) {
- //----- result color
- // note: aDest = alpha2 = aResult = 0xff
- cResult0 = state->grayTransfer[(Guchar)div255((0xff - aSrc) * cDest[0] +
- aSrc * pipe->cSrc[0])];
+ //----- shape
+ shape = *shapePtr;
+ if (!shape) {
+ destColorPtr += destColorMask & 1;
+ destColorMask = (destColorMask << 7) | (destColorMask >> 1);
+ cSrcPtr += cSrcStride;
+ ++shapePtr;
+ continue;
+ }
+ lastX = x;
- //----- 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;
+ //----- read destination pixel
+ cDest0 = (*destColorPtr & destColorMask) ? 0xff : 0x00;
+
+ //----- source alpha
+ aSrc = shape;
+
+ //----- result color
+ // note: aDest = alphaI = aResult = 0xff
+ cResult0 = state->grayTransfer[(Guchar)div255((0xff - aSrc) * cDest0 +
+ aSrc * cSrcPtr[0])];
+
+ //----- write destination pixel
+ if (state->screen->test(x, y, cResult0)) {
+ *destColorPtr |= destColorMask;
+ } else {
+ *destColorPtr &= ~destColorMask;
+ }
+ destColorPtr += destColorMask & 1;
+ destColorMask = (destColorMask << 7) | (destColorMask >> 1);
+
+ cSrcPtr += cSrcStride;
+ ++shapePtr;
}
- ++pipe->x;
+ updateModX(lastX);
}
// special case:
-// !pipe->pattern && !pipe->noTransparency && !state->softMask &&
-// pipe->usesShape && !pipe->alpha0Ptr && !state->blendFunc &&
-// !pipe->nonIsolatedGroup &&
-// bitmap->mode == splashModeMono8 && pipe->destAlphaPtr
-void Splash::pipeRunAAMono8(SplashPipe *pipe) {
- Guchar aSrc, aDest, alpha2, aResult;
- SplashColor cDest;
- Guchar cResult0;
+// !pipe->pattern && pipe->shapeOnly && !state->blendFunc &&
+// bitmap->mode == splashModeMono8 && bitmap->alpha
+void Splash::pipeRunShapeMono8(SplashPipe *pipe, int x0, int x1, int y,
+ Guchar *shapePtr, SplashColorPtr cSrcPtr) {
+ Guchar shape, aSrc, aDest, alphaI, aResult, cDest0, cResult0;
+ SplashColorPtr destColorPtr;
+ Guchar *destAlphaPtr;
+ int cSrcStride, x, lastX;
- //----- read destination pixel
- cDest[0] = *pipe->destColorPtr;
- aDest = *pipe->destAlphaPtr;
+ if (cSrcPtr) {
+ cSrcStride = 1;
+ } else {
+ cSrcPtr = pipe->cSrcVal;
+ cSrcStride = 0;
+ }
+ for (; x0 <= x1; ++x0) {
+ if (*shapePtr) {
+ break;
+ }
+ cSrcPtr += cSrcStride;
+ ++shapePtr;
+ }
+ if (x0 > x1) {
+ return;
+ }
+ updateModX(x0);
+ updateModY(y);
+ lastX = x0;
- //----- source alpha
- aSrc = div255(pipe->aInput * pipe->shape);
+ destColorPtr = &bitmap->data[y * bitmap->rowSize + x0];
+ destAlphaPtr = &bitmap->alpha[y * bitmap->width + x0];
- //----- result alpha and non-isolated group element correction
- aResult = aSrc + aDest - div255(aSrc * aDest);
- alpha2 = aResult;
+ for (x = x0; x <= x1; ++x) {
- //----- result color
- if (alpha2 == 0) {
- cResult0 = 0;
- } else {
- cResult0 = state->grayTransfer[(Guchar)(((alpha2 - aSrc) * cDest[0] +
- aSrc * pipe->cSrc[0]) / alpha2)];
- }
+ //----- shape
+ shape = *shapePtr;
+ if (!shape) {
+ ++destColorPtr;
+ ++destAlphaPtr;
+ cSrcPtr += cSrcStride;
+ ++shapePtr;
+ continue;
+ }
+ lastX = x;
- //----- write destination pixel
- *pipe->destColorPtr++ = cResult0;
- *pipe->destAlphaPtr++ = aResult;
+ //----- read destination pixel
+ cDest0 = *destColorPtr;
+ aDest = *destAlphaPtr;
+
+ //----- source alpha
+ aSrc = shape;
+
+ //----- result alpha and non-isolated group element correction
+ aResult = aSrc + aDest - div255(aSrc * aDest);
+ alphaI = aResult;
- ++pipe->x;
+ //----- result color
+ if (alphaI == 0) {
+ cResult0 = 0;
+ } else {
+ cResult0 = state->grayTransfer[(Guchar)(((alphaI - aSrc) * cDest0 +
+ aSrc * cSrcPtr[0]) / alphaI)];
+ }
+
+ //----- write destination pixel
+ *destColorPtr++ = cResult0;
+ *destAlphaPtr++ = aResult;
+
+ cSrcPtr += cSrcStride;
+ ++shapePtr;
+ }
+
+ updateModX(lastX);
}
// special case:
-// !pipe->pattern && !pipe->noTransparency && !state->softMask &&
-// pipe->usesShape && !pipe->alpha0Ptr && !state->blendFunc &&
-// !pipe->nonIsolatedGroup &&
-// bitmap->mode == splashModeRGB8 && pipe->destAlphaPtr
-void Splash::pipeRunAARGB8(SplashPipe *pipe) {
- Guchar aSrc, aDest, alpha2, aResult;
- SplashColor cDest;
+// !pipe->pattern && pipe->shapeOnly && !state->blendFunc &&
+// bitmap->mode == splashModeRGB8 && bitmap->alpha
+void Splash::pipeRunShapeRGB8(SplashPipe *pipe, int x0, int x1, int y,
+ Guchar *shapePtr, SplashColorPtr cSrcPtr) {
+ Guchar shape, aSrc, aDest, alphaI, aResult;
+ Guchar cDest0, cDest1, cDest2;
Guchar cResult0, cResult1, cResult2;
+ SplashColorPtr destColorPtr;
+ Guchar *destAlphaPtr;
+ int cSrcStride, x, lastX;
+
+ if (cSrcPtr) {
+ cSrcStride = 3;
+ } else {
+ cSrcPtr = pipe->cSrcVal;
+ cSrcStride = 0;
+ }
+ for (; x0 <= x1; ++x0) {
+ if (*shapePtr) {
+ break;
+ }
+ cSrcPtr += cSrcStride;
+ ++shapePtr;
+ }
+ if (x0 > x1) {
+ return;
+ }
+ updateModX(x0);
+ updateModY(y);
+ lastX = x0;
- //----- read destination pixel
- cDest[0] = pipe->destColorPtr[0];
- cDest[1] = pipe->destColorPtr[1];
- cDest[2] = pipe->destColorPtr[2];
- aDest = *pipe->destAlphaPtr;
+ destColorPtr = &bitmap->data[y * bitmap->rowSize + 3 * x0];
+ destAlphaPtr = &bitmap->alpha[y * bitmap->width + x0];
- //----- source alpha
- aSrc = div255(pipe->aInput * pipe->shape);
+ for (x = x0; x <= x1; ++x) {
- //----- result alpha and non-isolated group element correction
- aResult = aSrc + aDest - div255(aSrc * aDest);
- alpha2 = aResult;
+ //----- shape
+ shape = *shapePtr;
+ if (!shape) {
+ destColorPtr += 3;
+ ++destAlphaPtr;
+ cSrcPtr += cSrcStride;
+ ++shapePtr;
+ continue;
+ }
+ lastX = x;
- //----- result color
- if (alpha2 == 0) {
- cResult0 = 0;
- cResult1 = 0;
- cResult2 = 0;
- } else {
- cResult0 = state->rgbTransferR[(Guchar)(((alpha2 - aSrc) * cDest[0] +
- aSrc * pipe->cSrc[0]) / alpha2)];
- cResult1 = state->rgbTransferG[(Guchar)(((alpha2 - aSrc) * cDest[1] +
- aSrc * pipe->cSrc[1]) / alpha2)];
- cResult2 = state->rgbTransferB[(Guchar)(((alpha2 - aSrc) * cDest[2] +
- aSrc * pipe->cSrc[2]) / alpha2)];
- }
+ //----- read destination pixel
+ cDest0 = destColorPtr[0];
+ cDest1 = destColorPtr[1];
+ cDest2 = destColorPtr[2];
+ aDest = *destAlphaPtr;
- //----- write destination pixel
- *pipe->destColorPtr++ = cResult0;
- *pipe->destColorPtr++ = cResult1;
- *pipe->destColorPtr++ = cResult2;
- *pipe->destAlphaPtr++ = aResult;
+ //----- source alpha
+ aSrc = shape;
- ++pipe->x;
+ //----- result alpha and non-isolated group element correction
+ aResult = aSrc + aDest - div255(aSrc * aDest);
+ alphaI = aResult;
+
+ //----- result color
+ if (alphaI == 0) {
+ cResult0 = 0;
+ cResult1 = 0;
+ cResult2 = 0;
+ } else {
+ cResult0 = state->rgbTransferR[(Guchar)(((alphaI - aSrc) * cDest0 +
+ aSrc * cSrcPtr[0]) / alphaI)];
+ cResult1 = state->rgbTransferG[(Guchar)(((alphaI - aSrc) * cDest1 +
+ aSrc * cSrcPtr[1]) / alphaI)];
+ cResult2 = state->rgbTransferB[(Guchar)(((alphaI - aSrc) * cDest2 +
+ aSrc * cSrcPtr[2]) / alphaI)];
+ }
+
+ //----- write destination pixel
+ destColorPtr[0] = cResult0;
+ destColorPtr[1] = cResult1;
+ destColorPtr[2] = cResult2;
+ destColorPtr += 3;
+ *destAlphaPtr++ = aResult;
+
+ cSrcPtr += cSrcStride;
+ ++shapePtr;
+ }
+
+ updateModX(lastX);
}
// special case:
-// !pipe->pattern && !pipe->noTransparency && !state->softMask &&
-// pipe->usesShape && !pipe->alpha0Ptr && !state->blendFunc &&
-// !pipe->nonIsolatedGroup &&
-// bitmap->mode == splashModeBGR8 && pipe->destAlphaPtr
-void Splash::pipeRunAABGR8(SplashPipe *pipe) {
- Guchar aSrc, aDest, alpha2, aResult;
- SplashColor cDest;
+// !pipe->pattern && pipe->shapeOnly && !state->blendFunc &&
+// bitmap->mode == splashModeBGR8 && bitmap->alpha
+void Splash::pipeRunShapeBGR8(SplashPipe *pipe, int x0, int x1, int y,
+ Guchar *shapePtr, SplashColorPtr cSrcPtr) {
+ Guchar shape, aSrc, aDest, alphaI, aResult;
+ Guchar cDest0, cDest1, cDest2;
Guchar cResult0, cResult1, cResult2;
+ SplashColorPtr destColorPtr;
+ Guchar *destAlphaPtr;
+ int cSrcStride, x, lastX;
- //----- read destination pixel
- cDest[0] = pipe->destColorPtr[2];
- cDest[1] = pipe->destColorPtr[1];
- cDest[2] = pipe->destColorPtr[0];
- aDest = *pipe->destAlphaPtr;
+ if (cSrcPtr) {
+ cSrcStride = 3;
+ } else {
+ cSrcPtr = pipe->cSrcVal;
+ cSrcStride = 0;
+ }
+ for (; x0 <= x1; ++x0) {
+ if (*shapePtr) {
+ break;
+ }
+ cSrcPtr += cSrcStride;
+ ++shapePtr;
+ }
+ if (x0 > x1) {
+ return;
+ }
+ updateModX(x0);
+ updateModY(y);
+ lastX = x0;
- //----- source alpha
- aSrc = div255(pipe->aInput * pipe->shape);
+ destColorPtr = &bitmap->data[y * bitmap->rowSize + 3 * x0];
+ destAlphaPtr = &bitmap->alpha[y * bitmap->width + x0];
- //----- result alpha and non-isolated group element correction
- aResult = aSrc + aDest - div255(aSrc * aDest);
- alpha2 = aResult;
+ for (x = x0; x <= x1; ++x) {
- //----- result color
- if (alpha2 == 0) {
- cResult0 = 0;
- cResult1 = 0;
- cResult2 = 0;
- } else {
- cResult0 = state->rgbTransferR[(Guchar)(((alpha2 - aSrc) * cDest[0] +
- aSrc * pipe->cSrc[0]) / alpha2)];
- cResult1 = state->rgbTransferG[(Guchar)(((alpha2 - aSrc) * cDest[1] +
- aSrc * pipe->cSrc[1]) / alpha2)];
- cResult2 = state->rgbTransferB[(Guchar)(((alpha2 - aSrc) * cDest[2] +
- aSrc * pipe->cSrc[2]) / alpha2)];
- }
+ //----- shape
+ shape = *shapePtr;
+ if (!shape) {
+ destColorPtr += 3;
+ ++destAlphaPtr;
+ cSrcPtr += cSrcStride;
+ ++shapePtr;
+ continue;
+ }
+ lastX = x;
+
+ //----- read destination pixel
+ cDest0 = destColorPtr[2];
+ cDest1 = destColorPtr[1];
+ cDest2 = destColorPtr[0];
+ aDest = *destAlphaPtr;
- //----- write destination pixel
- *pipe->destColorPtr++ = cResult2;
- *pipe->destColorPtr++ = cResult1;
- *pipe->destColorPtr++ = cResult0;
- *pipe->destAlphaPtr++ = aResult;
+ //----- source alpha
+ aSrc = shape;
+
+ //----- result alpha and non-isolated group element correction
+ aResult = aSrc + aDest - div255(aSrc * aDest);
+ alphaI = aResult;
- ++pipe->x;
+ //----- result color
+ if (alphaI == 0) {
+ cResult0 = 0;
+ cResult1 = 0;
+ cResult2 = 0;
+ } else {
+ cResult0 = state->rgbTransferR[(Guchar)(((alphaI - aSrc) * cDest0 +
+ aSrc * cSrcPtr[0]) / alphaI)];
+ cResult1 = state->rgbTransferG[(Guchar)(((alphaI - aSrc) * cDest1 +
+ aSrc * cSrcPtr[1]) / alphaI)];
+ cResult2 = state->rgbTransferB[(Guchar)(((alphaI - aSrc) * cDest2 +
+ aSrc * cSrcPtr[2]) / alphaI)];
+ }
+
+ //----- write destination pixel
+ destColorPtr[0] = cResult2;
+ destColorPtr[1] = cResult1;
+ destColorPtr[2] = cResult0;
+ destColorPtr += 3;
+ *destAlphaPtr++ = aResult;
+
+ cSrcPtr += cSrcStride;
+ ++shapePtr;
+ }
+
+ updateModX(lastX);
}
#if SPLASH_CMYK
// special case:
-// !pipe->pattern && !pipe->noTransparency && !state->softMask &&
-// pipe->usesShape && !pipe->alpha0Ptr && !state->blendFunc &&
-// !pipe->nonIsolatedGroup &&
-// bitmap->mode == splashModeCMYK8 && pipe->destAlphaPtr
-void Splash::pipeRunAACMYK8(SplashPipe *pipe) {
- Guchar aSrc, aDest, alpha2, aResult;
- SplashColor cDest;
+// !pipe->pattern && pipe->shapeOnly && !state->blendFunc &&
+// bitmap->mode == splashModeCMYK8 && bitmap->alpha
+void Splash::pipeRunShapeCMYK8(SplashPipe *pipe, int x0, int x1, int y,
+ Guchar *shapePtr, SplashColorPtr cSrcPtr) {
+ Guchar shape, aSrc, aDest, alphaI, aResult;
+ Guchar cSrc0, cSrc1, cSrc2, cSrc3;
+ Guchar cDest0, cDest1, cDest2, cDest3;
Guchar cResult0, cResult1, cResult2, cResult3;
+ SplashColorPtr destColorPtr;
+ Guchar *destAlphaPtr;
+ int cSrcStride, x, lastX;
- //----- 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;
+ if (cSrcPtr) {
+ cSrcStride = 4;
} else {
- cResult0 = state->cmykTransferC[(Guchar)(((alpha2 - aSrc) * cDest[0] +
- aSrc * pipe->cSrc[0]) / alpha2)];
- cResult1 = state->cmykTransferM[(Guchar)(((alpha2 - aSrc) * cDest[1] +
- aSrc * pipe->cSrc[1]) / alpha2)];
- cResult2 = state->cmykTransferY[(Guchar)(((alpha2 - aSrc) * cDest[2] +
- aSrc * pipe->cSrc[2]) / alpha2)];
- cResult3 = state->cmykTransferK[(Guchar)(((alpha2 - aSrc) * cDest[3] +
- aSrc * pipe->cSrc[3]) / alpha2)];
+ cSrcPtr = pipe->cSrcVal;
+ cSrcStride = 0;
}
-
- //----- write destination pixel
- if (state->overprintMask & 1) {
- pipe->destColorPtr[0] = cResult0;
- }
- if (state->overprintMask & 2) {
- pipe->destColorPtr[1] = cResult1;
+ for (; x0 <= x1; ++x0) {
+ if (*shapePtr) {
+ break;
+ }
+ cSrcPtr += cSrcStride;
+ ++shapePtr;
}
- if (state->overprintMask & 4) {
- pipe->destColorPtr[2] = cResult2;
+ if (x0 > x1) {
+ return;
}
- if (state->overprintMask & 8) {
- pipe->destColorPtr[3] = cResult3;
+ updateModX(x0);
+ updateModY(y);
+ lastX = x0;
+
+ destColorPtr = &bitmap->data[y * bitmap->rowSize + 4 * x0];
+ destAlphaPtr = &bitmap->alpha[y * bitmap->width + x0];
+
+ for (x = x0; x <= x1; ++x) {
+
+ //----- shape
+ shape = *shapePtr;
+ if (!shape) {
+ destColorPtr += 4;
+ ++destAlphaPtr;
+ cSrcPtr += cSrcStride;
+ ++shapePtr;
+ continue;
+ }
+ lastX = x;
+
+ //----- read destination pixel
+ cDest0 = destColorPtr[0];
+ cDest1 = destColorPtr[1];
+ cDest2 = destColorPtr[2];
+ cDest3 = destColorPtr[3];
+ aDest = *destAlphaPtr;
+
+ //----- overprint
+ if (state->overprintMask & 1) {
+ cSrc0 = cSrcPtr[0];
+ } else {
+ cSrc0 = div255(aDest * cDest0);
+ }
+ if (state->overprintMask & 2) {
+ cSrc1 = cSrcPtr[1];
+ } else {
+ cSrc1 = div255(aDest * cDest1);
+ }
+ if (state->overprintMask & 4) {
+ cSrc2 = cSrcPtr[2];
+ } else {
+ cSrc2 = div255(aDest * cDest2);
+ }
+ if (state->overprintMask & 8) {
+ cSrc3 = cSrcPtr[3];
+ } else {
+ cSrc3 = div255(aDest * cDest3);
+ }
+
+ //----- source alpha
+ aSrc = shape;
+
+ //----- result alpha and non-isolated group element correction
+ aResult = aSrc + aDest - div255(aSrc * aDest);
+ alphaI = aResult;
+
+ //----- result color
+ if (alphaI == 0) {
+ cResult0 = 0;
+ cResult1 = 0;
+ cResult2 = 0;
+ cResult3 = 0;
+ } else {
+ cResult0 = state->cmykTransferC[(Guchar)(((alphaI - aSrc) * cDest0 +
+ aSrc * cSrc0) / alphaI)];
+ cResult1 = state->cmykTransferM[(Guchar)(((alphaI - aSrc) * cDest1 +
+ aSrc * cSrc1) / alphaI)];
+ cResult2 = state->cmykTransferY[(Guchar)(((alphaI - aSrc) * cDest2 +
+ aSrc * cSrc2) / alphaI)];
+ cResult3 = state->cmykTransferK[(Guchar)(((alphaI - aSrc) * cDest3 +
+ aSrc * cSrc3) / alphaI)];
+ }
+
+ //----- write destination pixel
+ destColorPtr[0] = cResult0;
+ destColorPtr[1] = cResult1;
+ destColorPtr[2] = cResult2;
+ destColorPtr[3] = cResult3;
+ destColorPtr += 4;
+ *destAlphaPtr++ = aResult;
+
+ cSrcPtr += cSrcStride;
+ ++shapePtr;
}
- pipe->destColorPtr += 4;
- *pipe->destAlphaPtr++ = aResult;
- ++pipe->x;
+ updateModX(lastX);
}
#endif
-inline void Splash::pipeSetXY(SplashPipe *pipe, int x, int y) {
- pipe->x = x;
- pipe->y = y;
- if (state->softMask) {
- pipe->softMaskPtr =
- &state->softMask->data[y * state->softMask->rowSize + x];
+// special case:
+// !pipe->pattern && !pipe->noTransparency && !state->softMask &&
+// pipe->usesShape && !pipe->alpha0Ptr && !state->blendFunc &&
+// !pipe->nonIsolatedGroup &&
+// bitmap->mode == splashModeMono1 && !bitmap->alpha
+void Splash::pipeRunAAMono1(SplashPipe *pipe, int x0, int x1, int y,
+ Guchar *shapePtr, SplashColorPtr cSrcPtr) {
+ Guchar shape, aSrc, cDest0, cResult0;
+ SplashColorPtr destColorPtr;
+ Guchar destColorMask;
+ int cSrcStride, x, lastX;
+
+ if (cSrcPtr) {
+ cSrcStride = 1;
+ } else {
+ cSrcPtr = pipe->cSrcVal;
+ cSrcStride = 0;
}
- 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;
-#if SPLASH_CMYK
- case splashModeCMYK8:
- pipe->destColorPtr = &bitmap->data[y * bitmap->rowSize + 4 * x];
- break;
-#endif
+ for (; x0 <= x1; ++x0) {
+ if (*shapePtr) {
+ break;
+ }
+ cSrcPtr += cSrcStride;
+ ++shapePtr;
}
- if (bitmap->alpha) {
- pipe->destAlphaPtr = &bitmap->alpha[y * bitmap->width + x];
- } else {
- pipe->destAlphaPtr = NULL;
+ if (x0 > x1) {
+ return;
}
- if (state->inNonIsolatedGroup && alpha0Bitmap->alpha) {
- pipe->alpha0Ptr =
- &alpha0Bitmap->alpha[(alpha0Y + y) * alpha0Bitmap->width +
- (alpha0X + x)];
- } else {
- pipe->alpha0Ptr = NULL;
+ updateModX(x0);
+ updateModY(y);
+ lastX = x0;
+
+ destColorPtr = &bitmap->data[y * bitmap->rowSize + (x0 >> 3)];
+ destColorMask = 0x80 >> (x0 & 7);
+
+ for (x = x0; x <= x1; ++x) {
+
+ //----- shape
+ shape = *shapePtr;
+ if (!shape) {
+ destColorPtr += destColorMask & 1;
+ destColorMask = (destColorMask << 7) | (destColorMask >> 1);
+ cSrcPtr += cSrcStride;
+ ++shapePtr;
+ continue;
+ }
+ lastX = x;
+
+ //----- read destination pixel
+ cDest0 = (*destColorPtr & destColorMask) ? 0xff : 0x00;
+
+ //----- source alpha
+ aSrc = div255(pipe->aInput * shape);
+
+ //----- result color
+ // note: aDest = alphaI = aResult = 0xff
+ cResult0 = state->grayTransfer[(Guchar)div255((0xff - aSrc) * cDest0 +
+ aSrc * cSrcPtr[0])];
+
+ //----- write destination pixel
+ if (state->screen->test(x, y, cResult0)) {
+ *destColorPtr |= destColorMask;
+ } else {
+ *destColorPtr &= ~destColorMask;
+ }
+ destColorPtr += destColorMask & 1;
+ destColorMask = (destColorMask << 7) | (destColorMask >> 1);
+
+ cSrcPtr += cSrcStride;
+ ++shapePtr;
}
+
+ updateModX(lastX);
}
-inline void Splash::pipeIncX(SplashPipe *pipe) {
- ++pipe->x;
- if (state->softMask) {
- ++pipe->softMaskPtr;
+// special case:
+// !pipe->pattern && !pipe->noTransparency && !state->softMask &&
+// pipe->usesShape && !pipe->alpha0Ptr && !state->blendFunc &&
+// !pipe->nonIsolatedGroup &&
+// bitmap->mode == splashModeMono8 && bitmap->alpha
+void Splash::pipeRunAAMono8(SplashPipe *pipe, int x0, int x1, int y,
+ Guchar *shapePtr, SplashColorPtr cSrcPtr) {
+ Guchar shape, aSrc, aDest, alphaI, aResult, cDest0, cResult0;
+ SplashColorPtr destColorPtr;
+ Guchar *destAlphaPtr;
+ int cSrcStride, x, lastX;
+
+ if (cSrcPtr) {
+ cSrcStride = 1;
+ } else {
+ cSrcPtr = pipe->cSrcVal;
+ cSrcStride = 0;
}
- switch (bitmap->mode) {
- case splashModeMono1:
- if (!(pipe->destColorMask >>= 1)) {
- pipe->destColorMask = 0x80;
- ++pipe->destColorPtr;
+ for (; x0 <= x1; ++x0) {
+ if (*shapePtr) {
+ break;
}
- break;
- case splashModeMono8:
- ++pipe->destColorPtr;
- break;
- case splashModeRGB8:
- case splashModeBGR8:
- pipe->destColorPtr += 3;
- break;
-#if SPLASH_CMYK
- case splashModeCMYK8:
- pipe->destColorPtr += 4;
- break;
-#endif
- }
- if (pipe->destAlphaPtr) {
- ++pipe->destAlphaPtr;
+ cSrcPtr += cSrcStride;
+ ++shapePtr;
}
- if (pipe->alpha0Ptr) {
- ++pipe->alpha0Ptr;
+ if (x0 > x1) {
+ return;
}
-}
+ updateModX(x0);
+ updateModY(y);
+ lastX = x0;
+
+ destColorPtr = &bitmap->data[y * bitmap->rowSize + x0];
+ destAlphaPtr = &bitmap->alpha[y * bitmap->width + x0];
+
+ for (x = x0; x <= x1; ++x) {
+
+ //----- shape
+ shape = *shapePtr;
+ if (!shape) {
+ ++destColorPtr;
+ ++destAlphaPtr;
+ cSrcPtr += cSrcStride;
+ ++shapePtr;
+ continue;
+ }
+ lastX = x;
+
+ //----- read destination pixel
+ cDest0 = *destColorPtr;
+ aDest = *destAlphaPtr;
+
+ //----- source alpha
+ aSrc = div255(pipe->aInput * shape);
-inline void Splash::drawPixel(SplashPipe *pipe, int x, int y, GBool noClip) {
- if (noClip || state->clip->test(x, y)) {
- pipeSetXY(pipe, x, y);
- (this->*pipe->run)(pipe);
- updateModX(x);
- updateModY(y);
+ //----- result alpha and non-isolated group element correction
+ aResult = aSrc + aDest - div255(aSrc * aDest);
+ alphaI = aResult;
+
+ //----- result color
+ if (alphaI == 0) {
+ cResult0 = 0;
+ } else {
+ cResult0 = state->grayTransfer[(Guchar)(((alphaI - aSrc) * cDest0 +
+ aSrc * cSrcPtr[0]) / alphaI)];
+ }
+
+ //----- write destination pixel
+ *destColorPtr++ = cResult0;
+ *destAlphaPtr++ = aResult;
+
+ cSrcPtr += cSrcStride;
+ ++shapePtr;
}
-}
-inline void Splash::drawAAPixelInit() {
- aaBufY = -1;
+ updateModX(lastX);
}
-inline void Splash::drawAAPixel(SplashPipe *pipe, int x, int y) {
-#if splashAASize == 4
- static int bitCount4[16] = { 0, 1, 1, 2, 1, 2, 2, 3,
- 1, 2, 2, 3, 2, 3, 3, 4 };
- int w;
-#else
- int xx, yy;
-#endif
- SplashColorPtr p;
- int x0, x1, t;
+// special case:
+// !pipe->pattern && !pipe->noTransparency && !state->softMask &&
+// pipe->usesShape && !pipe->alpha0Ptr && !state->blendFunc &&
+// !pipe->nonIsolatedGroup &&
+// bitmap->mode == splashModeRGB8 && bitmap->alpha
+void Splash::pipeRunAARGB8(SplashPipe *pipe, int x0, int x1, int y,
+ Guchar *shapePtr, SplashColorPtr cSrcPtr) {
+ Guchar shape, aSrc, aDest, alphaI, aResult;
+ Guchar cDest0, cDest1, cDest2;
+ Guchar cResult0, cResult1, cResult2;
+ SplashColorPtr destColorPtr;
+ Guchar *destAlphaPtr;
+ int cSrcStride, x, lastX;
- if (x < 0 || x >= bitmap->width ||
- y < state->clip->getYMinI() || y > state->clip->getYMaxI()) {
+ if (cSrcPtr) {
+ cSrcStride = 3;
+ } else {
+ cSrcPtr = pipe->cSrcVal;
+ cSrcStride = 0;
+ }
+ for (; x0 <= x1; ++x0) {
+ if (*shapePtr) {
+ break;
+ }
+ cSrcPtr += cSrcStride;
+ ++shapePtr;
+ }
+ if (x0 > x1) {
return;
}
+ updateModX(x0);
+ updateModY(y);
+ lastX = x0;
- // 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];
+ destColorPtr = &bitmap->data[y * bitmap->rowSize + 3 * x0];
+ destAlphaPtr = &bitmap->alpha[y * bitmap->width + x0];
+
+ for (x = x0; x <= x1; ++x) {
+
+ //----- shape
+ shape = *shapePtr;
+ if (!shape) {
+ destColorPtr += 3;
+ ++destAlphaPtr;
+ cSrcPtr += cSrcStride;
+ ++shapePtr;
+ continue;
+ }
+ lastX = x;
+
+ //----- read destination pixel
+ cDest0 = destColorPtr[0];
+ cDest1 = destColorPtr[1];
+ cDest2 = destColorPtr[2];
+ aDest = *destAlphaPtr;
+
+ //----- source alpha
+ aSrc = div255(pipe->aInput * shape);
+
+ //----- result alpha and non-isolated group element correction
+ aResult = aSrc + aDest - div255(aSrc * aDest);
+ alphaI = aResult;
+
+ //----- result color
+ if (alphaI == 0) {
+ cResult0 = 0;
+ cResult1 = 0;
+ cResult2 = 0;
+ } else {
+ cResult0 = state->rgbTransferR[(Guchar)(((alphaI - aSrc) * cDest0 +
+ aSrc * cSrcPtr[0]) / alphaI)];
+ cResult1 = state->rgbTransferG[(Guchar)(((alphaI - aSrc) * cDest1 +
+ aSrc * cSrcPtr[1]) / alphaI)];
+ cResult2 = state->rgbTransferB[(Guchar)(((alphaI - aSrc) * cDest2 +
+ aSrc * cSrcPtr[2]) / alphaI)];
+ }
+
+ //----- write destination pixel
+ destColorPtr[0] = cResult0;
+ destColorPtr[1] = cResult1;
+ destColorPtr[2] = cResult2;
+ destColorPtr += 3;
+ *destAlphaPtr++ = aResult;
+
+ cSrcPtr += cSrcStride;
+ ++shapePtr;
+ }
+
+ updateModX(lastX);
+}
+
+// special case:
+// !pipe->pattern && !pipe->noTransparency && !state->softMask &&
+// pipe->usesShape && !pipe->alpha0Ptr && !state->blendFunc &&
+// !pipe->nonIsolatedGroup &&
+// bitmap->mode == splashModeBGR8 && bitmap->alpha
+void Splash::pipeRunAABGR8(SplashPipe *pipe, int x0, int x1, int y,
+ Guchar *shapePtr, SplashColorPtr cSrcPtr) {
+ Guchar shape, aSrc, aDest, alphaI, aResult;
+ Guchar cDest0, cDest1, cDest2;
+ Guchar cResult0, cResult1, cResult2;
+ SplashColorPtr destColorPtr;
+ Guchar *destAlphaPtr;
+ int cSrcStride, x, lastX;
+
+ if (cSrcPtr) {
+ cSrcStride = 3;
} else {
- t = bitCount4[*p >> 4] + bitCount4[p[w] >> 4] +
- bitCount4[p[2*w] >> 4] + bitCount4[p[3*w] >> 4];
+ cSrcPtr = pipe->cSrcVal;
+ cSrcStride = 0;
}
-#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 (; x0 <= x1; ++x0) {
+ if (*shapePtr) {
+ break;
}
+ cSrcPtr += cSrcStride;
+ ++shapePtr;
}
-#endif
+ if (x0 > x1) {
+ return;
+ }
+ updateModX(x0);
+ updateModY(y);
+ lastX = x0;
+
+ destColorPtr = &bitmap->data[y * bitmap->rowSize + 3 * x0];
+ destAlphaPtr = &bitmap->alpha[y * bitmap->width + x0];
+
+ for (x = x0; x <= x1; ++x) {
+
+ //----- shape
+ shape = *shapePtr;
+ if (!shape) {
+ destColorPtr += 3;
+ ++destAlphaPtr;
+ cSrcPtr += cSrcStride;
+ ++shapePtr;
+ continue;
+ }
+ lastX = x;
+
+ //----- read destination pixel
+ cDest0 = destColorPtr[2];
+ cDest1 = destColorPtr[1];
+ cDest2 = destColorPtr[0];
+ aDest = *destAlphaPtr;
+
+ //----- source alpha
+ aSrc = div255(pipe->aInput * shape);
+
+ //----- result alpha and non-isolated group element correction
+ aResult = aSrc + aDest - div255(aSrc * aDest);
+ alphaI = aResult;
+
+ //----- result color
+ if (alphaI == 0) {
+ cResult0 = 0;
+ cResult1 = 0;
+ cResult2 = 0;
+ } else {
+ cResult0 = state->rgbTransferR[(Guchar)(((alphaI - aSrc) * cDest0 +
+ aSrc * cSrcPtr[0]) / alphaI)];
+ cResult1 = state->rgbTransferG[(Guchar)(((alphaI - aSrc) * cDest1 +
+ aSrc * cSrcPtr[1]) / alphaI)];
+ cResult2 = state->rgbTransferB[(Guchar)(((alphaI - aSrc) * cDest2 +
+ aSrc * cSrcPtr[2]) / alphaI)];
+ }
- // draw the pixel
- if (t != 0) {
- pipeSetXY(pipe, x, y);
- pipe->shape = div255(aaGamma[t] * pipe->shape);
- (this->*pipe->run)(pipe);
- updateModX(x);
- updateModY(y);
+ //----- write destination pixel
+ destColorPtr[0] = cResult2;
+ destColorPtr[1] = cResult1;
+ destColorPtr[2] = cResult0;
+ destColorPtr += 3;
+ *destAlphaPtr++ = aResult;
+
+ cSrcPtr += cSrcStride;
+ ++shapePtr;
}
+
+ updateModX(lastX);
}
-inline void Splash::drawSpan(SplashPipe *pipe, int x0, int x1, int y,
- GBool noClip) {
- int x;
+#if SPLASH_CMYK
+// special case:
+// !pipe->pattern && !pipe->noTransparency && !state->softMask &&
+// pipe->usesShape && !pipe->alpha0Ptr && !state->blendFunc &&
+// !pipe->nonIsolatedGroup &&
+// bitmap->mode == splashModeCMYK8 && bitmap->alpha
+void Splash::pipeRunAACMYK8(SplashPipe *pipe, int x0, int x1, int y,
+ Guchar *shapePtr, SplashColorPtr cSrcPtr) {
+ Guchar shape, aSrc, aDest, alphaI, aResult;
+ Guchar cSrc0, cSrc1, cSrc2, cSrc3;
+ Guchar cDest0, cDest1, cDest2, cDest3;
+ Guchar cResult0, cResult1, cResult2, cResult3;
+ SplashColorPtr destColorPtr;
+ Guchar *destAlphaPtr;
+ int cSrcStride, x, lastX;
- if (noClip) {
- pipeSetXY(pipe, x0, y);
- for (x = x0; x <= x1; ++x) {
- (this->*pipe->run)(pipe);
- }
- updateModX(x0);
- updateModX(x1);
- updateModY(y);
+ if (cSrcPtr) {
+ cSrcStride = 4;
} else {
- if (x0 < state->clip->getXMinI()) {
- x0 = state->clip->getXMinI();
- }
- if (x1 > state->clip->getXMaxI()) {
- x1 = state->clip->getXMaxI();
- }
- pipeSetXY(pipe, x0, y);
- for (x = x0; x <= x1; ++x) {
- if (state->clip->test(x, y)) {
- (this->*pipe->run)(pipe);
- updateModX(x);
- updateModY(y);
- } else {
- pipeIncX(pipe);
- }
+ cSrcPtr = pipe->cSrcVal;
+ cSrcStride = 0;
+ }
+ for (; x0 <= x1; ++x0) {
+ if (*shapePtr) {
+ break;
}
+ cSrcPtr += cSrcStride;
+ ++shapePtr;
}
-}
+ if (x0 > x1) {
+ return;
+ }
+ updateModX(x0);
+ updateModY(y);
+ lastX = x0;
-inline void Splash::drawAALine(SplashPipe *pipe, int x0, int x1, int y) {
-#if splashAASize == 4
- static int bitCount4[16] = { 0, 1, 1, 2, 1, 2, 2, 3,
- 1, 2, 2, 3, 2, 3, 3, 4 };
- SplashColorPtr p0, p1, p2, p3;
- int t;
-#else
- SplashColorPtr p;
- int xx, yy, t;
-#endif
- int x;
+ destColorPtr = &bitmap->data[y * bitmap->rowSize + 4 * x0];
+ destAlphaPtr = &bitmap->alpha[y * bitmap->width + x0];
-#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;
+ //----- shape
+ shape = *shapePtr;
+ if (!shape) {
+ destColorPtr += 4;
+ ++destAlphaPtr;
+ cSrcPtr += cSrcStride;
+ ++shapePtr;
+ continue;
+ }
+ lastX = x;
+
+ //----- read destination pixel
+ cDest0 = destColorPtr[0];
+ cDest1 = destColorPtr[1];
+ cDest2 = destColorPtr[2];
+ cDest3 = destColorPtr[3];
+ aDest = *destAlphaPtr;
+
+ //----- overprint
+ if (state->overprintMask & 1) {
+ cSrc0 = cSrcPtr[0];
} else {
- t = bitCount4[*p0 >> 4] + bitCount4[*p1 >> 4] +
- bitCount4[*p2 >> 4] + bitCount4[*p3 >> 4];
+ cSrc0 = div255(aDest * cDest0);
}
-#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;
- }
+ if (state->overprintMask & 2) {
+ cSrc1 = cSrcPtr[1];
+ } else {
+ cSrc1 = div255(aDest * cDest1);
}
-#endif
+ if (state->overprintMask & 4) {
+ cSrc2 = cSrcPtr[2];
+ } else {
+ cSrc2 = div255(aDest * cDest2);
+ }
+ if (state->overprintMask & 8) {
+ cSrc3 = cSrcPtr[3];
+ } else {
+ cSrc3 = div255(aDest * cDest3);
+ }
+
+ //----- source alpha
+ aSrc = div255(pipe->aInput * shape);
+
+ //----- result alpha and non-isolated group element correction
+ aResult = aSrc + aDest - div255(aSrc * aDest);
+ alphaI = aResult;
- if (t != 0) {
- pipe->shape = aaGamma[t];
- (this->*pipe->run)(pipe);
- updateModX(x);
- updateModY(y);
+ //----- result color
+ if (alphaI == 0) {
+ cResult0 = 0;
+ cResult1 = 0;
+ cResult2 = 0;
+ cResult3 = 0;
} else {
- pipeIncX(pipe);
+ cResult0 = state->cmykTransferC[(Guchar)(((alphaI - aSrc) * cDest0 +
+ aSrc * cSrc0) / alphaI)];
+ cResult1 = state->cmykTransferM[(Guchar)(((alphaI - aSrc) * cDest1 +
+ aSrc * cSrc1) / alphaI)];
+ cResult2 = state->cmykTransferY[(Guchar)(((alphaI - aSrc) * cDest2 +
+ aSrc * cSrc2) / alphaI)];
+ cResult3 = state->cmykTransferK[(Guchar)(((alphaI - aSrc) * cDest3 +
+ aSrc * cSrc3) / alphaI)];
}
+
+ //----- write destination pixel
+ destColorPtr[0] = cResult0;
+ destColorPtr[1] = cResult1;
+ destColorPtr[2] = cResult2;
+ destColorPtr[3] = cResult3;
+ destColorPtr += 4;
+ *destAlphaPtr++ = aResult;
+
+ cSrcPtr += cSrcStride;
+ ++shapePtr;
}
+
+ updateModX(lastX);
}
+#endif
+
//------------------------------------------------------------------------
@@ -1238,21 +1934,18 @@ Splash::Splash(SplashBitmap *bitmapA, GBool vectorAntialiasA,
int i;
bitmap = bitmapA;
+ bitmapComps = splashColorModeNComps[bitmap->mode];
vectorAntialias = vectorAntialiasA;
inShading = gFalse;
state = new SplashState(bitmap->width, bitmap->height, vectorAntialias,
screenParams);
+ scanBuf = (Guchar *)gmalloc(bitmap->width);
if (vectorAntialias) {
- aaBuf = new SplashBitmap(splashAASize * bitmap->width, splashAASize,
- 1, splashModeMono1, gFalse);
- for (i = 0; i <= splashAASize * splashAASize; ++i) {
+ for (i = 0; i <= 255; ++i) {
aaGamma[i] = (Guchar)splashRound(
- splashPow((SplashCoord)i /
- (SplashCoord)(splashAASize * splashAASize),
- splashAAGamma) * 255);
+ splashPow((SplashCoord)i / (SplashCoord)255,
+ splashAAGamma) * 255);
}
- } else {
- aaBuf = NULL;
}
minLineWidth = 0;
clearModRegion();
@@ -1264,21 +1957,18 @@ Splash::Splash(SplashBitmap *bitmapA, GBool vectorAntialiasA,
int i;
bitmap = bitmapA;
+ bitmapComps = splashColorModeNComps[bitmap->mode];
vectorAntialias = vectorAntialiasA;
inShading = gFalse;
state = new SplashState(bitmap->width, bitmap->height, vectorAntialias,
screenA);
+ scanBuf = (Guchar *)gmalloc(bitmap->width);
if (vectorAntialias) {
- aaBuf = new SplashBitmap(splashAASize * bitmap->width, splashAASize,
- 1, splashModeMono1, gFalse);
- for (i = 0; i <= splashAASize * splashAASize; ++i) {
+ for (i = 0; i <= 255; ++i) {
aaGamma[i] = (Guchar)splashRound(
- splashPow((SplashCoord)i /
- (SplashCoord)(splashAASize * splashAASize),
- splashAAGamma) * 255);
+ splashPow((SplashCoord)i / (SplashCoord)255,
+ splashAAGamma) * 255);
}
- } else {
- aaBuf = NULL;
}
minLineWidth = 0;
clearModRegion();
@@ -1290,9 +1980,7 @@ Splash::~Splash() {
restoreState();
}
delete state;
- if (vectorAntialias) {
- delete aaBuf;
- }
+ gfree(scanBuf);
}
//------------------------------------------------------------------------
@@ -1375,6 +2063,10 @@ GBool Splash::getInNonIsolatedGroup() {
return state->inNonIsolatedGroup;
}
+GBool Splash::getInKnockoutGroup() {
+ return state->inKnockoutGroup;
+}
+
//------------------------------------------------------------------------
// state write
//------------------------------------------------------------------------
@@ -1442,28 +2134,30 @@ void Splash::setStrokeAdjust(GBool strokeAdjust) {
void Splash::clipResetToRect(SplashCoord x0, SplashCoord y0,
SplashCoord x1, SplashCoord y1) {
- state->clip->resetToRect(x0, y0, x1, y1);
+ state->clipResetToRect(x0, y0, x1, y1);
}
SplashError Splash::clipToRect(SplashCoord x0, SplashCoord y0,
SplashCoord x1, SplashCoord y1) {
- return state->clip->clipToRect(x0, y0, x1, y1);
+ return state->clipToRect(x0, y0, x1, y1);
}
SplashError Splash::clipToPath(SplashPath *path, GBool eo) {
- return state->clip->clipToPath(path, state->matrix, state->flatness, eo);
+ return state->clipToPath(path, eo);
}
void Splash::setSoftMask(SplashBitmap *softMask) {
state->setSoftMask(softMask);
}
-void Splash::setInNonIsolatedGroup(SplashBitmap *alpha0BitmapA,
- int alpha0XA, int alpha0YA) {
- alpha0Bitmap = alpha0BitmapA;
- alpha0X = alpha0XA;
- alpha0Y = alpha0YA;
- state->inNonIsolatedGroup = gTrue;
+void Splash::setInTransparencyGroup(SplashBitmap *groupBackBitmapA,
+ int groupBackXA, int groupBackYA,
+ GBool nonIsolated, GBool knockout) {
+ groupBackBitmap = groupBackBitmapA;
+ groupBackX = groupBackXA;
+ groupBackY = groupBackYA;
+ state->inNonIsolatedGroup = nonIsolated;
+ state->inKnockoutGroup = knockout;
}
void Splash::setTransfer(Guchar *red, Guchar *green, Guchar *blue,
@@ -1539,9 +2233,9 @@ void Splash::clear(SplashColorPtr color, Guchar alpha) {
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];
+ *p++ = color[1];
+ *p++ = color[2];
}
row += bitmap->rowSize;
}
@@ -1560,9 +2254,9 @@ void Splash::clear(SplashColorPtr color, Guchar alpha) {
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[1];
+ *p++ = color[0];
}
row += bitmap->rowSize;
}
@@ -1606,7 +2300,7 @@ void Splash::clear(SplashColorPtr color, Guchar alpha) {
SplashError Splash::stroke(SplashPath *path) {
SplashPath *path2, *dPath;
- SplashCoord d1, d2, t1, t2, w;
+ SplashCoord t0, t1, t2, t3, w, w2;
if (debugMode) {
printf("stroke [dash:%d] [width:%.2f]:\n",
@@ -1628,31 +2322,41 @@ SplashError Splash::stroke(SplashPath *path) {
}
}
- // 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);
+ // Compute an approximation of the transformed line width.
+ // Given a CTM of [m0 m1],
+ // [m2 m3]
+ // if |m0|*|m3| >= |m1|*|m2| then use min{|m0|,|m3|}, else
+ // use min{|m1|,|m2|}.
+ // This handles the common cases -- [s 0 ] and [0 s] --
+ // [0 +/-s] [+/-s 0]
+ // well, and still does something reasonable for the uncommon
+ // case transforms.
+ t0 = splashAbs(state->matrix[0]);
+ t1 = splashAbs(state->matrix[1]);
+ t2 = splashAbs(state->matrix[2]);
+ t3 = splashAbs(state->matrix[3]);
+ if (t0 * t3 >= t1 * t2) {
+ w = (t0 < t3) ? t0 : t3;
+ } else {
+ w = (t1 < t2) ? t1 : t2;
+ }
+ w2 = w * state->lineWidth;
+ // if there is a min line width set, and the transformed line width
+ // is smaller, use the min line width
+ if (w > 0 && w2 < minLineWidth) {
+ strokeWide(path2, minLineWidth / w);
} else if (bitmap->mode == splashModeMono1) {
- // this gets close to Adobe's behavior in mono mode
- if (d1 <= 2) {
+ // in monochrome mode, use 0-width lines for any transformed line
+ // width <= 1 -- lines less than 1 pixel wide look too fat without
+ // antialiasing
+ if (w2 < 1.001) {
strokeNarrow(path2);
} else {
strokeWide(path2, state->lineWidth);
}
} else {
+ // in gray and color modes, only use 0-width lines if the line
+ // width is explicitly set to 0
if (state->lineWidth == 0) {
strokeNarrow(path2);
} else {
@@ -1678,9 +2382,9 @@ void Splash::strokeNarrow(SplashPath *path) {
xPath = new SplashXPath(path, state->matrix, state->flatness, gFalse);
- pipeInit(&pipe, 0, 0, state->strokePattern, NULL,
+ pipeInit(&pipe, state->strokePattern,
(Guchar)splashRound(state->strokeAlpha * 255),
- gFalse, gFalse);
+ gTrue, gFalse);
for (i = 0, seg = xPath->segs; i < xPath->length; ++i, ++seg) {
if (seg->y0 <= seg->y1) {
@@ -1695,22 +2399,25 @@ void Splash::strokeNarrow(SplashPath *path) {
x1 = splashFloor(seg->x0);
}
if ((clipRes = state->clip->testRect(x0 <= x1 ? x0 : x1, y0,
- x0 <= x1 ? x1 : x0, y1))
+ x0 <= x1 ? x1 : x0, y1,
+ state->strokeAdjust))
!= splashClipAllOutside) {
if (y0 == y1) {
if (x0 <= x1) {
- drawSpan(&pipe, x0, x1, y0, clipRes == splashClipAllInside);
+ drawStrokeSpan(&pipe, x0, x1, y0, clipRes == splashClipAllInside);
} else {
- drawSpan(&pipe, x1, x0, y0, clipRes == splashClipAllInside);
+ drawStrokeSpan(&pipe, x1, x0, y0, clipRes == splashClipAllInside);
}
} else {
dxdy = seg->dxdy;
- if (y0 < state->clip->getYMinI()) {
- y0 = state->clip->getYMinI();
+ y = state->clip->getYMinI(state->strokeAdjust);
+ if (y0 < y) {
+ y0 = y;
x0 = splashFloor(seg->x0 + ((SplashCoord)y0 - seg->y0) * dxdy);
}
- if (y1 > state->clip->getYMaxI()) {
- y1 = state->clip->getYMaxI();
+ y = state->clip->getYMaxI(state->strokeAdjust);
+ if (y1 > y) {
+ y1 = y;
x1 = splashFloor(seg->x0 + ((SplashCoord)y1 - seg->y0) * dxdy);
}
if (x0 <= x1) {
@@ -1723,9 +2430,10 @@ void Splash::strokeNarrow(SplashPath *path) {
xb = x1 + 1;
}
if (xa == xb) {
- drawPixel(&pipe, xa, y, clipRes == splashClipAllInside);
+ drawStrokeSpan(&pipe, xa, xa, y, clipRes == splashClipAllInside);
} else {
- drawSpan(&pipe, xa, xb - 1, y, clipRes == splashClipAllInside);
+ drawStrokeSpan(&pipe, xa, xb - 1, y,
+ clipRes == splashClipAllInside);
}
xa = xb;
}
@@ -1739,9 +2447,10 @@ void Splash::strokeNarrow(SplashPath *path) {
xb = x1 - 1;
}
if (xa == xb) {
- drawPixel(&pipe, xa, y, clipRes == splashClipAllInside);
+ drawStrokeSpan(&pipe, xa, xa, y, clipRes == splashClipAllInside);
} else {
- drawSpan(&pipe, xb + 1, xa, y, clipRes == splashClipAllInside);
+ drawStrokeSpan(&pipe, xb + 1, xa, y,
+ clipRes == splashClipAllInside);
}
xa = xb;
}
@@ -1762,6 +2471,32 @@ void Splash::strokeNarrow(SplashPath *path) {
delete xPath;
}
+void Splash::drawStrokeSpan(SplashPipe *pipe, int x0, int x1, int y,
+ GBool noClip) {
+ int x;
+
+ x = state->clip->getXMinI(state->strokeAdjust);
+ if (x > x0) {
+ x0 = x;
+ }
+ x = state->clip->getXMaxI(state->strokeAdjust);
+ if (x < x1) {
+ x1 = x;
+ }
+ if (x0 > x1) {
+ return;
+ }
+ for (x = x0; x <= x1; ++x) {
+ scanBuf[x] = 0xff;
+ }
+ if (!noClip) {
+ if (!state->clip->clipSpanBinary(scanBuf, y, x0, x1, state->strokeAdjust)) {
+ return;
+ }
+ }
+ (this->*pipe->run)(pipe, x0, x1, y, scanBuf + x0, NULL);
+}
+
void Splash::strokeWide(SplashPath *path, SplashCoord w) {
SplashPath *path2;
@@ -2012,10 +2747,11 @@ SplashError Splash::fillWithPattern(SplashPath *path, GBool eo,
SplashPattern *pattern,
SplashCoord alpha) {
SplashPipe pipe;
+ SplashPath *path2;
SplashXPath *xPath;
SplashXPathScanner *scanner;
- int xMinI, yMinI, xMaxI, yMaxI, x0, x1, y;
- SplashClipResult clipRes, clipRes2;
+ int xMin, yMin, xMax, yMax, x, y, t;
+ SplashClipResult clipRes;
if (path->length == 0) {
return splashErrEmptyPath;
@@ -2025,85 +2761,68 @@ SplashError Splash::fillWithPattern(SplashPath *path, GBool eo,
return splashOk;
}
- // add stroke adjustment hints for filled rectangles -- this only
- // applies to paths that consist of a single subpath
- // (this appears to match Acrobat's behavior)
- if (state->strokeAdjust && !path->hints) {
- int n;
- n = path->getLength();
- if (n == 4 &&
- !(path->flags[0] & splashPathClosed) &&
- !(path->flags[1] & splashPathLast) &&
- !(path->flags[2] & splashPathLast)) {
- path->close(gTrue);
- path->addStrokeAdjustHint(0, 2, 0, 4);
- path->addStrokeAdjustHint(1, 3, 0, 4);
- } else if (n == 5 &&
- (path->flags[0] & splashPathClosed) &&
- !(path->flags[1] & splashPathLast) &&
- !(path->flags[2] & splashPathLast) &&
- !(path->flags[3] & splashPathLast)) {
- path->addStrokeAdjustHint(0, 2, 0, 4);
- path->addStrokeAdjustHint(1, 3, 0, 4);
- }
- }
+ path2 = tweakFillPath(path);
- xPath = new SplashXPath(path, state->matrix, state->flatness, gTrue);
- 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;
+ xPath = new SplashXPath(path2, state->matrix, state->flatness, gTrue);
+ if (path2 != path) {
+ delete path2;
}
- scanner = new SplashXPathScanner(xPath, eo, yMinI, yMaxI);
-
- // get the min and max x and y values
- if (vectorAntialias && !inShading) {
- scanner->getBBoxAA(&xMinI, &yMinI, &xMaxI, &yMaxI);
- } else {
- scanner->getBBox(&xMinI, &yMinI, &xMaxI, &yMaxI);
+ xMin = xPath->getXMin();
+ yMin = xPath->getYMin();
+ xMax = xPath->getXMax();
+ yMax = xPath->getYMax();
+ if (xMin > xMax || yMin > yMax) {
+ delete xPath;
+ return splashOk;
}
+ scanner = new SplashXPathScanner(xPath, eo, yMin, yMax);
// check clipping
- if ((clipRes = state->clip->testRect(xMinI, yMinI, xMaxI, yMaxI))
+ if ((clipRes = state->clip->testRect(xMin, yMin, xMax, yMax,
+ state->strokeAdjust))
!= splashClipAllOutside) {
- if (scanner->hasPartialClip()) {
- clipRes = splashClipPartial;
+
+ if ((t = state->clip->getXMinI(state->strokeAdjust)) > xMin) {
+ xMin = t;
+ }
+ if ((t = state->clip->getXMaxI(state->strokeAdjust)) < xMax) {
+ xMax = t;
+ }
+ if ((t = state->clip->getYMinI(state->strokeAdjust)) > yMin) {
+ yMin = t;
+ }
+ if ((t = state->clip->getYMaxI(state->strokeAdjust)) < yMax) {
+ yMax = t;
+ }
+ if (xMin > xMax || yMin > yMax) {
+ delete scanner;
+ delete xPath;
+ return splashOk;
}
- pipeInit(&pipe, 0, yMinI, pattern, NULL, (Guchar)splashRound(alpha * 255),
- vectorAntialias && !inShading, gFalse);
+ pipeInit(&pipe, pattern, (Guchar)splashRound(alpha * 255),
+ gTrue, gFalse);
// draw the spans
if (vectorAntialias && !inShading) {
- for (y = yMinI; y <= yMaxI; ++y) {
- scanner->renderAALine(aaBuf, &x0, &x1, y);
+ for (y = yMin; y <= yMax; ++y) {
+ scanner->getSpan(scanBuf, y, xMin, xMax);
if (clipRes != splashClipAllInside) {
- state->clip->clipAALine(aaBuf, &x0, &x1, y);
+ state->clip->clipSpan(scanBuf, y, xMin, xMax, state->strokeAdjust);
+ }
+ for (x = xMin; x <= xMax; ++x) {
+ scanBuf[x] = aaGamma[scanBuf[x]];
}
- drawAALine(&pipe, x0, x1, y);
+ (this->*pipe.run)(&pipe, xMin, xMax, y, scanBuf + xMin, NULL);
}
} else {
- for (y = yMinI; y <= yMaxI; ++y) {
- while (scanner->getNextSpan(y, &x0, &x1)) {
- if (clipRes == splashClipAllInside) {
- drawSpan(&pipe, x0, x1, y, gTrue);
- } else {
- // limit the x range
- if (x0 < state->clip->getXMinI()) {
- x0 = state->clip->getXMinI();
- }
- if (x1 > state->clip->getXMaxI()) {
- x1 = state->clip->getXMaxI();
- }
- clipRes2 = state->clip->testSpan(x0, x1, y);
- drawSpan(&pipe, x0, x1, y, clipRes2 == splashClipAllInside);
- }
+ for (y = yMin; y <= yMax; ++y) {
+ scanner->getSpanBinary(scanBuf, y, xMin, xMax);
+ if (clipRes != splashClipAllInside) {
+ state->clip->clipSpanBinary(scanBuf, y, xMin, xMax,
+ state->strokeAdjust);
}
+ (this->*pipe.run)(&pipe, xMin, xMax, y, scanBuf + xMin, NULL);
}
}
}
@@ -2114,6 +2833,110 @@ SplashError Splash::fillWithPattern(SplashPath *path, GBool eo,
return splashOk;
}
+// Applies various tweaks to a fill path:
+// (1) add stroke adjust hints to a filled rectangle
+// (2) applies a minimum width to a zero-width filled rectangle (so
+// stroke adjustment works correctly
+// (3) convert a degenerate fill ('moveto lineto fill' and 'moveto
+// lineto closepath fill') to a minimum-width filled rectangle
+//
+// These tweaks only apply to paths with a single subpath.
+//
+// Returns either the unchanged input path or a new path (in which
+// case the returned path must be deleted by the caller).
+SplashPath *Splash::tweakFillPath(SplashPath *path) {
+ SplashPath *path2;
+ SplashCoord xx0, yy0, xx1, yy1, dx, dy, d, wx, wy, w;
+ int n;
+
+ if (!state->strokeAdjust || path->hints) {
+ return path;
+ }
+
+ n = path->getLength();
+ if (!((n == 2) ||
+ (n == 3 &&
+ path->flags[1] == 0) ||
+ (n == 4 &&
+ path->flags[1] == 0 &&
+ path->flags[2] == 0) ||
+ (n == 5 &&
+ path->flags[1] == 0 &&
+ path->flags[2] == 0 &&
+ path->flags[3] == 0))) {
+ return path;
+ }
+
+ path2 = path;
+
+ // degenerate fill (2 or 3 points) or rectangle of (nearly) zero
+ // width --> replace with a min-width rectangle and hint
+ if (n == 2 ||
+ (n == 3 && (path->flags[0] & splashPathClosed)) ||
+ (n == 3 && (splashAbs(path->pts[0].x - path->pts[2].x) < 0.001 &&
+ splashAbs(path->pts[0].y - path->pts[2].y) < 0.001)) ||
+ ((n == 4 ||
+ (n == 5 && (path->flags[0] & splashPathClosed))) &&
+ ((splashAbs(path->pts[0].x - path->pts[1].x) < 0.001 &&
+ splashAbs(path->pts[0].y - path->pts[1].y) < 0.001 &&
+ splashAbs(path->pts[2].x - path->pts[3].x) < 0.001 &&
+ splashAbs(path->pts[2].y - path->pts[3].y) < 0.001) ||
+ (splashAbs(path->pts[0].x - path->pts[3].x) < 0.001 &&
+ splashAbs(path->pts[0].y - path->pts[3].y) < 0.001 &&
+ splashAbs(path->pts[1].x - path->pts[2].x) < 0.001 &&
+ splashAbs(path->pts[1].y - path->pts[2].y) < 0.001)))) {
+ wx = state->matrix[0] + state->matrix[2];
+ wy = state->matrix[1] + state->matrix[3];
+ w = sqrt(wx*wx + wy*wy);
+ if (w < 0.001) {
+ w = 0;
+ } else {
+ // min width is 0.1 -- this constant is minWidth * sqrt(2)
+ w = (SplashCoord)0.1414 / w;
+ }
+ xx0 = path->pts[0].x;
+ yy0 = path->pts[0].y;
+ if (n <= 3) {
+ xx1 = path->pts[1].x;
+ yy1 = path->pts[1].y;
+ } else {
+ xx1 = path->pts[2].x;
+ yy1 = path->pts[2].y;
+ }
+ dx = xx1 - xx0;
+ dy = yy1 - yy0;
+ d = sqrt(dx * dx + dy * dy);
+ if (d < 0.001) {
+ d = 0;
+ } else {
+ d = w / d;
+ }
+ dx *= d;
+ dy *= d;
+ path2 = new SplashPath();
+ path2->moveTo(xx0 + dy, yy0 - dx);
+ path2->lineTo(xx1 + dy, yy1 - dx);
+ path2->lineTo(xx1 - dy, yy1 + dx);
+ path2->lineTo(xx0 - dy, yy0 + dx);
+ path2->close(gTrue);
+ path2->addStrokeAdjustHint(0, 2, 0, 4);
+ path2->addStrokeAdjustHint(1, 3, 0, 4);
+
+ // unclosed rectangle --> close and hint
+ } else if (n == 4 && !(path->flags[0] & splashPathClosed)) {
+ path2->close(gTrue);
+ path2->addStrokeAdjustHint(0, 2, 0, 4);
+ path2->addStrokeAdjustHint(1, 3, 0, 4);
+
+ // closed rectangle --> hint
+ } else if (n == 5 && (path->flags[0] & splashPathClosed)) {
+ path2->addStrokeAdjustHint(0, 2, 0, 4);
+ path2->addStrokeAdjustHint(1, 3, 0, 4);
+ }
+
+ return path2;
+}
+
GBool Splash::pathAllOutside(SplashPath *path) {
SplashCoord xMin1, yMin1, xMax1, yMax1;
SplashCoord xMin2, yMin2, xMax2, yMax2;
@@ -2177,7 +3000,8 @@ GBool Splash::pathAllOutside(SplashPath *path) {
xMaxI = splashFloor(xMax2);
yMaxI = splashFloor(yMax2);
- return state->clip->testRect(xMinI, yMinI, xMaxI, yMaxI) ==
+ return state->clip->testRect(xMinI, yMinI, xMaxI, yMaxI,
+ state->strokeAdjust) ==
splashClipAllOutside;
}
@@ -2185,49 +3009,63 @@ SplashError Splash::xorFill(SplashPath *path, GBool eo) {
SplashPipe pipe;
SplashXPath *xPath;
SplashXPathScanner *scanner;
- int xMinI, yMinI, xMaxI, yMaxI, x0, x1, y;
- SplashClipResult clipRes, clipRes2;
+ int xMin, yMin, xMax, yMax, y, t;
+ SplashClipResult clipRes;
SplashBlendFunc origBlendFunc;
if (path->length == 0) {
return splashErrEmptyPath;
}
+ if (pathAllOutside(path)) {
+ opClipRes = splashClipAllOutside;
+ return splashOk;
+ }
xPath = new SplashXPath(path, state->matrix, state->flatness, gTrue);
- xPath->sort();
- scanner = new SplashXPathScanner(xPath, eo, state->clip->getYMinI(),
- state->clip->getYMaxI());
-
- // get the min and max x and y values
- scanner->getBBox(&xMinI, &yMinI, &xMaxI, &yMaxI);
+ xMin = xPath->getXMin();
+ yMin = xPath->getYMin();
+ xMax = xPath->getXMax();
+ yMax = xPath->getYMax();
+ if (xMin > xMax || yMin > yMax) {
+ delete xPath;
+ return splashOk;
+ }
+ scanner = new SplashXPathScanner(xPath, eo, yMin, yMax);
// check clipping
- if ((clipRes = state->clip->testRect(xMinI, yMinI, xMaxI, yMaxI))
+ if ((clipRes = state->clip->testRect(xMin, yMin, xMax, yMax,
+ state->strokeAdjust))
!= splashClipAllOutside) {
- if (scanner->hasPartialClip()) {
- clipRes = splashClipPartial;
+
+ if ((t = state->clip->getXMinI(state->strokeAdjust)) > xMin) {
+ xMin = t;
+ }
+ if ((t = state->clip->getXMaxI(state->strokeAdjust)) < xMax) {
+ xMax = t;
+ }
+ if ((t = state->clip->getYMinI(state->strokeAdjust)) > yMin) {
+ yMin = t;
+ }
+ if ((t = state->clip->getYMaxI(state->strokeAdjust)) < yMax) {
+ yMax = t;
+ }
+ if (xMin > xMax || yMin > yMax) {
+ delete scanner;
+ delete xPath;
+ return splashOk;
}
origBlendFunc = state->blendFunc;
state->blendFunc = &blendXor;
- pipeInit(&pipe, 0, yMinI, state->fillPattern, NULL, 255, gFalse, gFalse);
+ pipeInit(&pipe, state->fillPattern, 255, gTrue, gFalse);
// draw the spans
- for (y = yMinI; y <= yMaxI; ++y) {
- while (scanner->getNextSpan(y, &x0, &x1)) {
- if (clipRes == splashClipAllInside) {
- drawSpan(&pipe, x0, x1, y, gTrue);
- } else {
- // limit the x range
- if (x0 < state->clip->getXMinI()) {
- x0 = state->clip->getXMinI();
- }
- if (x1 > state->clip->getXMaxI()) {
- x1 = state->clip->getXMaxI();
- }
- clipRes2 = state->clip->testSpan(x0, x1, y);
- drawSpan(&pipe, x0, x1, y, clipRes2 == splashClipAllInside);
- }
+ for (y = yMin; y <= yMax; ++y) {
+ scanner->getSpanBinary(scanBuf, y, xMin, xMax);
+ if (clipRes != splashClipAllInside) {
+ state->clip->clipSpanBinary(scanBuf, y, xMin, xMax,
+ state->strokeAdjust);
}
+ (this->*pipe.run)(&pipe, xMin, xMax, y, scanBuf + xMin, NULL);
}
state->blendFunc = origBlendFunc;
}
@@ -2278,105 +3116,86 @@ SplashError Splash::fillGlyph(SplashCoord x, SplashCoord y,
SplashError Splash::fillGlyph2(int x0, int y0, SplashGlyphBitmap *glyph) {
SplashPipe pipe;
SplashClipResult clipRes;
- GBool noClip;
- int alpha0;
Guchar alpha;
Guchar *p;
- int x1, y1, xx, xx1, yy;
-
- if ((clipRes = state->clip->testRect(x0 - glyph->x,
- y0 - glyph->y,
- x0 - glyph->x + glyph->w - 1,
- y0 - glyph->y + glyph->h - 1))
+ int xMin, yMin, xMax, yMax;
+ int x, y, xg, yg, xx, t;
+
+ xg = x0 - glyph->x;
+ yg = y0 - glyph->y;
+ xMin = xg;
+ xMax = xg + glyph->w - 1;
+ yMin = yg;
+ yMax = yg + glyph->h - 1;
+ if ((clipRes = state->clip->testRect(xMin, yMin, xMax, yMax,
+ state->strokeAdjust))
!= splashClipAllOutside) {
- noClip = clipRes == splashClipAllInside;
-
- if (noClip) {
+ pipeInit(&pipe, state->fillPattern,
+ (Guchar)splashRound(state->fillAlpha * 255),
+ gTrue, gFalse);
+ if (clipRes == splashClipAllInside) {
if (glyph->aa) {
- pipeInit(&pipe, x0 - glyph->x, y0 - glyph->y, state->fillPattern, NULL,
- (Guchar)splashRound(state->fillAlpha * 255), gTrue, gFalse);
p = glyph->data;
- for (yy = 0, y1 = y0 - glyph->y; yy < glyph->h; ++yy, ++y1) {
- pipeSetXY(&pipe, x0 - glyph->x, y1);
- for (xx = 0, x1 = x0 - glyph->x; xx < glyph->w; ++xx, ++x1) {
- alpha = *p++;
- if (alpha != 0) {
- pipe.shape = alpha;
- (this->*pipe.run)(&pipe);
- updateModX(x1);
- updateModY(y1);
- } else {
- pipeIncX(&pipe);
- }
- }
+ for (y = yMin; y <= yMax; ++y) {
+ (this->*pipe.run)(&pipe, xMin, xMax, y,
+ glyph->data + (y - yMin) * glyph->w, NULL);
}
} else {
- pipeInit(&pipe, x0 - glyph->x, y0 - glyph->y, state->fillPattern, NULL,
- (Guchar)splashRound(state->fillAlpha * 255), gFalse, gFalse);
p = glyph->data;
- for (yy = 0, y1 = y0 - glyph->y; yy < glyph->h; ++yy, ++y1) {
- pipeSetXY(&pipe, x0 - glyph->x, y1);
- for (xx = 0, x1 = x0 - glyph->x; xx < glyph->w; xx += 8) {
- alpha0 = *p++;
- for (xx1 = 0; xx1 < 8 && xx + xx1 < glyph->w; ++xx1, ++x1) {
- if (alpha0 & 0x80) {
- (this->*pipe.run)(&pipe);
- updateModX(x1);
- updateModY(y1);
- } else {
- pipeIncX(&pipe);
- }
- alpha0 <<= 1;
+ for (y = yMin; y <= yMax; ++y) {
+ for (x = xMin; x <= xMax; x += 8) {
+ alpha = *p++;
+ for (xx = 0; xx < 8 && x + xx <= xMax; ++xx) {
+ scanBuf[x + xx] = (alpha & 0x80) ? 0xff : 0x00;
+ alpha <<= 1;
}
}
+ (this->*pipe.run)(&pipe, xMin, xMax, y, scanBuf + xMin, NULL);
}
}
} else {
- if (glyph->aa) {
- pipeInit(&pipe, x0 - glyph->x, y0 - glyph->y, state->fillPattern, NULL,
- (Guchar)splashRound(state->fillAlpha * 255), gTrue, gFalse);
- p = glyph->data;
- for (yy = 0, y1 = y0 - glyph->y; yy < glyph->h; ++yy, ++y1) {
- pipeSetXY(&pipe, x0 - glyph->x, y1);
- for (xx = 0, x1 = x0 - glyph->x; xx < glyph->w; ++xx, ++x1) {
- if (state->clip->test(x1, y1)) {
- alpha = *p++;
- if (alpha != 0) {
- pipe.shape = alpha;
- (this->*pipe.run)(&pipe);
- updateModX(x1);
- updateModY(y1);
- } else {
- pipeIncX(&pipe);
- }
- } else {
- pipeIncX(&pipe);
- ++p;
- }
+ if ((t = state->clip->getXMinI(state->strokeAdjust)) > xMin) {
+ xMin = t;
+ }
+ if ((t = state->clip->getXMaxI(state->strokeAdjust)) < xMax) {
+ xMax = t;
+ }
+ if ((t = state->clip->getYMinI(state->strokeAdjust)) > yMin) {
+ yMin = t;
+ }
+ if ((t = state->clip->getYMaxI(state->strokeAdjust)) < yMax) {
+ yMax = t;
+ }
+ if (xMin <= xMax && yMin <= yMax) {
+ if (glyph->aa) {
+ for (y = yMin; y <= yMax; ++y) {
+ p = glyph->data + (y - yg) * glyph->w + (xMin - xg);
+ memcpy(scanBuf + xMin, p, xMax - xMin + 1);
+ state->clip->clipSpan(scanBuf, y, xMin, xMax,
+ state->strokeAdjust);
+ (this->*pipe.run)(&pipe, xMin, xMax, y, scanBuf + xMin, NULL);
}
- }
- } else {
- pipeInit(&pipe, x0 - glyph->x, y0 - glyph->y, state->fillPattern, NULL,
- (Guchar)splashRound(state->fillAlpha * 255), gFalse, gFalse);
- p = glyph->data;
- for (yy = 0, y1 = y0 - glyph->y; yy < glyph->h; ++yy, ++y1) {
- pipeSetXY(&pipe, x0 - glyph->x, y1);
- for (xx = 0, x1 = x0 - glyph->x; xx < glyph->w; xx += 8) {
- alpha0 = *p++;
- for (xx1 = 0; xx1 < 8 && xx + xx1 < glyph->w; ++xx1, ++x1) {
- if (state->clip->test(x1, y1)) {
- if (alpha0 & 0x80) {
- (this->*pipe.run)(&pipe);
- updateModX(x1);
- updateModY(y1);
- } else {
- pipeIncX(&pipe);
- }
- } else {
- pipeIncX(&pipe);
+ } else {
+ for (y = yMin; y <= yMax; ++y) {
+ p = glyph->data + (y - yg) * ((glyph->w + 7) >> 3)
+ + ((xMin - xg) >> 3);
+ alpha = *p++;
+ xx = (xMin - xg) & 7;
+ alpha <<= xx;
+ for (x = xMin; xx < 8 && x <= xMax; ++x, ++xx) {
+ scanBuf[x] = (alpha & 0x80) ? 255 : 0;
+ alpha <<= 1;
+ }
+ for (; x <= xMax; x += 8) {
+ alpha = *p++;
+ for (xx = 0; xx < 8 && x + xx <= xMax; ++xx) {
+ scanBuf[x + xx] = (alpha & 0x80) ? 255 : 0;
+ alpha <<= 1;
}
- alpha0 <<= 1;
}
+ state->clip->clipSpanBinary(scanBuf, y, xMin, xMax,
+ state->strokeAdjust);
+ (this->*pipe.run)(&pipe, xMin, xMax, y, scanBuf + xMin, NULL);
}
}
}
@@ -2387,12 +3206,28 @@ SplashError Splash::fillGlyph2(int x0, int y0, SplashGlyphBitmap *glyph) {
return splashOk;
}
+void Splash::getImageBounds(SplashCoord xyMin, SplashCoord xyMax,
+ int *xyMinI, int *xyMaxI) {
+ if (state->strokeAdjust) {
+ splashStrokeAdjust(xyMin, xyMax, xyMinI, xyMaxI);
+ } else {
+ *xyMinI = splashFloor(xyMin);
+ *xyMaxI = splashFloor(xyMax);
+ if (*xyMaxI <= *xyMinI) {
+ *xyMaxI = *xyMinI + 1;
+ }
+ }
+}
+
+// The glyphMode flag is not currently used, but may be useful if the
+// stroke adjustment behavior is changed.
SplashError Splash::fillImageMask(SplashImageMaskSource src, void *srcData,
int w, int h, SplashCoord *mat,
- GBool glyphMode) {
+ GBool glyphMode, GBool interpolate) {
SplashBitmap *scaledMask;
SplashClipResult clipRes;
GBool minorAxisZero;
+ SplashCoord wSize, hSize, t0, t1;
int x0, y0, x1, y1, scaledWidth, scaledHeight;
if (debugMode) {
@@ -2406,68 +3241,269 @@ SplashError Splash::fillImageMask(SplashImageMaskSource src, void *srcData,
return splashErrSingularMatrix;
}
- minorAxisZero = mat[1] == 0 && mat[2] == 0;
+ minorAxisZero = splashAbs(mat[1]) <= 0.0001 && splashAbs(mat[2]) <= 0.0001;
+
+ // rough estimate of size of scaled mask
+ t0 = splashAbs(mat[0]);
+ t1 = splashAbs(mat[1]);
+ wSize = t0 > t1 ? t0 : t1;
+ t0 = splashAbs(mat[2]);
+ t1 = splashAbs(mat[3]);
+ hSize = t0 > t1 ? t0 : t1;
+
+ // stream-mode upscaling -- this is slower, so we only use it if the
+ // upscaled mask is large (in which case clipping should remove many
+ // pixels)
+ if (wSize > 2 * w && hSize > 2 * h && wSize * hSize > 1000000) {
+ upscaleMask(src, srcData, w, h, mat, glyphMode, interpolate);
// 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);
+ } else if (mat[0] > 0 && minorAxisZero && mat[3] > 0) {
+ getImageBounds(mat[4], mat[0] + mat[4], &x0, &x1);
+ getImageBounds(mat[5], mat[3] + mat[5], &y0, &y1);
+ clipRes = state->clip->testRect(x0, y0, x1 - 1, y1 - 1,
+ state->strokeAdjust);
opClipRes = clipRes;
if (clipRes != splashClipAllOutside) {
scaledWidth = x1 - x0;
scaledHeight = y1 - y0;
- scaledMask = scaleMask(src, srcData, w, h, scaledWidth, scaledHeight);
+ scaledMask = scaleMask(src, srcData, w, h, scaledWidth, scaledHeight,
+ interpolate);
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);
+ getImageBounds(mat[4], mat[0] + mat[4], &x0, &x1);
+ getImageBounds(mat[3] + mat[5], mat[5], &y0, &y1);
+ clipRes = state->clip->testRect(x0, y0, x1 - 1, y1 - 1,
+ state->strokeAdjust);
+ opClipRes = clipRes;
+ if (clipRes != splashClipAllOutside) {
+ scaledWidth = x1 - x0;
+ scaledHeight = y1 - y0;
+ scaledMask = scaleMask(src, srcData, w, h, scaledWidth, scaledHeight,
+ interpolate);
+ vertFlipImage(scaledMask, scaledWidth, scaledHeight, 1);
+ blitMask(scaledMask, x0, y0, clipRes);
+ delete scaledMask;
+ }
+
+ // scaling plus horizontal flip
+ } else if (mat[0] < 0 && minorAxisZero && mat[3] > 0) {
+ getImageBounds(mat[0] + mat[4], mat[4], &x0, &x1);
+ getImageBounds(mat[5], mat[3] + mat[5], &y0, &y1);
+ clipRes = state->clip->testRect(x0, y0, x1 - 1, y1 - 1,
+ state->strokeAdjust);
+ opClipRes = clipRes;
+ if (clipRes != splashClipAllOutside) {
+ scaledWidth = x1 - x0;
+ scaledHeight = y1 - y0;
+ scaledMask = scaleMask(src, srcData, w, h, scaledWidth, scaledHeight,
+ interpolate);
+ horizFlipImage(scaledMask, scaledWidth, scaledHeight, 1);
+ blitMask(scaledMask, x0, y0, clipRes);
+ delete scaledMask;
+ }
+
+ // scaling plus horizontal and vertical flips
+ } else if (mat[0] < 0 && minorAxisZero && mat[3] < 0) {
+ getImageBounds(mat[0] + mat[4], mat[4], &x0, &x1);
+ getImageBounds(mat[3] + mat[5], mat[5], &y0, &y1);
+ clipRes = state->clip->testRect(x0, y0, x1 - 1, y1 - 1,
+ state->strokeAdjust);
opClipRes = clipRes;
if (clipRes != splashClipAllOutside) {
scaledWidth = x1 - x0;
scaledHeight = y1 - y0;
- scaledMask = scaleMask(src, srcData, w, h, scaledWidth, scaledHeight);
+ scaledMask = scaleMask(src, srcData, w, h, scaledWidth, scaledHeight,
+ interpolate);
vertFlipImage(scaledMask, scaledWidth, scaledHeight, 1);
+ horizFlipImage(scaledMask, scaledWidth, scaledHeight, 1);
blitMask(scaledMask, x0, y0, clipRes);
delete scaledMask;
}
// all other cases
} else {
- arbitraryTransformMask(src, srcData, w, h, mat, glyphMode);
+ arbitraryTransformMask(src, srcData, w, h, mat, glyphMode, interpolate);
}
return splashOk;
}
+// The glyphMode flag is not currently used, but may be useful if the
+// stroke adjustment behavior is changed.
+void Splash::upscaleMask(SplashImageMaskSource src, void *srcData,
+ int srcWidth, int srcHeight,
+ SplashCoord *mat, GBool glyphMode,
+ GBool interpolate) {
+ SplashClipResult clipRes;
+ SplashPipe pipe;
+ Guchar *unscaledImage, *p;
+ SplashCoord xMin, yMin, xMax, yMax, t;
+ SplashCoord mi0, mi1, mi2, mi3, mi4, mi5, det;
+ SplashCoord ix, iy, sx, sy, pix0, pix1;
+ int xMinI, yMinI, xMaxI, yMaxI, x, y, x0, y0, x1, y1, tt;
+
+ // compute the bbox of the target quadrilateral
+ xMin = xMax = mat[4];
+ t = mat[2] + mat[4];
+ if (t < xMin) {
+ xMin = t;
+ } else if (t > xMax) {
+ xMax = t;
+ }
+ t = mat[0] + mat[2] + mat[4];
+ if (t < xMin) {
+ xMin = t;
+ } else if (t > xMax) {
+ xMax = t;
+ }
+ t = mat[0] + mat[4];
+ if (t < xMin) {
+ xMin = t;
+ } else if (t > xMax) {
+ xMax = t;
+ }
+ getImageBounds(xMin, xMax, &xMinI, &xMaxI);
+ yMin = yMax = mat[5];
+ t = mat[3] + mat[5];
+ if (t < yMin) {
+ yMin = t;
+ } else if (t > yMax) {
+ yMax = t;
+ }
+ t = mat[1] + mat[3] + mat[5];
+ if (t < yMin) {
+ yMin = t;
+ } else if (t > yMax) {
+ yMax = t;
+ }
+ t = mat[1] + mat[5];
+ if (t < yMin) {
+ yMin = t;
+ } else if (t > yMax) {
+ yMax = t;
+ }
+ getImageBounds(yMin, yMax, &yMinI, &yMaxI);
+
+ // clipping
+ clipRes = state->clip->testRect(xMinI, yMinI, xMaxI - 1, yMaxI - 1,
+ state->strokeAdjust);
+ opClipRes = clipRes;
+ if (clipRes == splashClipAllOutside) {
+ return;
+ }
+ if (clipRes != splashClipAllInside) {
+ if ((tt = state->clip->getXMinI(state->strokeAdjust)) > xMinI) {
+ xMinI = tt;
+ }
+ if ((tt = state->clip->getXMaxI(state->strokeAdjust) + 1) < xMaxI) {
+ xMaxI = tt;
+ }
+ if ((tt = state->clip->getYMinI(state->strokeAdjust)) > yMinI) {
+ yMinI = tt;
+ }
+ if ((tt = state->clip->getYMaxI(state->strokeAdjust) + 1) < yMaxI) {
+ yMaxI = tt;
+ }
+ }
+
+ // invert the matrix
+ det = mat[0] * mat[3] - mat[1] * mat[2];
+ if (splashAbs(det) < 1e-6) {
+ // this should be caught by the singular matrix check in fillImageMask
+ return;
+ }
+ det = (SplashCoord)1 / det;
+ mi0 = det * mat[3] * srcWidth;
+ mi1 = -det * mat[1] * srcHeight;
+ mi2 = -det * mat[2] * srcWidth;
+ mi3 = det * mat[0] * srcHeight;
+ mi4 = det * (mat[2] * mat[5] - mat[3] * mat[4]) * srcWidth;
+ mi5 = -det * (mat[0] * mat[5] - mat[1] * mat[4]) * srcHeight;
+
+ // grab the image
+ unscaledImage = (Guchar *)gmallocn(srcWidth, srcHeight);
+ for (y = 0, p = unscaledImage; y < srcHeight; ++y, p += srcWidth) {
+ (*src)(srcData, p);
+ for (x = 0; x < srcWidth; ++x) {
+ p[x] *= 255;
+ }
+ }
+
+ // draw it
+ pipeInit(&pipe, state->fillPattern,
+ (Guchar)splashRound(state->fillAlpha * 255),
+ gTrue, gFalse);
+ for (y = yMinI; y < yMaxI; ++y) {
+ for (x = xMinI; x < xMaxI; ++x) {
+ ix = ((SplashCoord)x + 0.5) * mi0 + ((SplashCoord)y + 0.5) * mi2 + mi4;
+ iy = ((SplashCoord)x + 0.5) * mi1 + ((SplashCoord)y + 0.5) * mi3 + mi5;
+ if (interpolate) {
+ if (ix >= 0 && ix < srcWidth && iy >= 0 && iy < srcHeight) {
+ x0 = splashFloor(ix - 0.5);
+ x1 = x0 + 1;
+ sx = (ix - 0.5) - x0;
+ y0 = splashFloor(iy - 0.5);
+ y1 = y0 + 1;
+ sy = (iy - 0.5) - y0;
+ if (x0 < 0) {
+ x0 = 0;
+ }
+ if (x1 >= srcWidth) {
+ x1 = srcWidth - 1;
+ }
+ if (y0 < 0) {
+ y0 = 0;
+ }
+ if (y1 >= srcHeight) {
+ y1 = srcHeight - 1;
+ }
+ pix0 = ((SplashCoord)1 - sx) * unscaledImage[y0 * srcWidth + x0]
+ + sx * unscaledImage[y0 * srcWidth + x1];
+ pix1 = ((SplashCoord)1 - sx) * unscaledImage[y1 * srcWidth + x0]
+ + sx * unscaledImage[y1 * srcWidth + x1];
+ scanBuf[x] = (Guchar)splashRound(((SplashCoord)1 - sy) * pix0
+ + sy * pix1);
+ } else {
+ scanBuf[x] = 0;
+ }
+ } else {
+ x0 = splashFloor(ix);
+ y0 = splashFloor(iy);
+ if (x0 >= 0 && x0 < srcWidth && y0 >= 0 && y0 < srcHeight) {
+ scanBuf[x] = unscaledImage[y0 * srcWidth + x0];
+ } else {
+ scanBuf[x] = 0;
+ }
+ }
+ }
+ if (clipRes != splashClipAllInside) {
+ if (vectorAntialias) {
+ state->clip->clipSpan(scanBuf, y, xMinI, xMaxI - 1,
+ state->strokeAdjust);
+ } else {
+ state->clip->clipSpanBinary(scanBuf, y, xMinI, xMaxI - 1,
+ state->strokeAdjust);
+ }
+ }
+ (this->*pipe.run)(&pipe, xMinI, xMaxI - 1, y, scanBuf + xMinI, NULL);
+ }
+
+ gfree(unscaledImage);
+}
+
+// The glyphMode flag is not currently used, but may be useful if the
+// stroke adjustment behavior is changed.
void Splash::arbitraryTransformMask(SplashImageMaskSource src, void *srcData,
int srcWidth, int srcHeight,
- SplashCoord *mat, GBool glyphMode) {
+ SplashCoord *mat, GBool glyphMode,
+ GBool interpolate) {
SplashBitmap *scaledMask;
- SplashClipResult clipRes, clipRes2;
+ SplashClipResult clipRes;
SplashPipe pipe;
int scaledWidth, scaledHeight, t0, t1;
SplashCoord r00, r01, r10, r11, det, ir00, ir01, ir10, ir11;
@@ -2484,29 +3520,26 @@ void Splash::arbitraryTransformMask(SplashImageMaskSource src, void *srcData,
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);
+ xMin = splashRound(vx[0]);
+ xMax = splashRound(vx[0]);
+ yMin = splashRound(vy[0]);
+ yMax = splashRound(vy[0]);
for (i = 1; i < 4; ++i) {
- t0 = imgCoordMungeLowerC(vx[i], glyphMode);
+ t0 = splashRound(vx[i]);
if (t0 < xMin) {
xMin = t0;
- }
- t0 = imgCoordMungeUpperC(vx[i], glyphMode);
- if (t0 > xMax) {
+ } else if (t0 > xMax) {
xMax = t0;
}
- t1 = imgCoordMungeLowerC(vy[i], glyphMode);
+ t1 = splashRound(vy[i]);
if (t1 < yMin) {
yMin = t1;
- }
- t1 = imgCoordMungeUpperC(vy[i], glyphMode);
- if (t1 > yMax) {
+ } else if (t1 > yMax) {
yMax = t1;
}
}
- clipRes = state->clip->testRect(xMin, yMin, xMax - 1, yMax - 1);
+ clipRes = state->clip->testRect(xMin, yMin, xMax - 1, yMax - 1,
+ state->strokeAdjust);
opClipRes = clipRes;
if (clipRes == splashClipAllOutside) {
return;
@@ -2514,33 +3547,25 @@ void Splash::arbitraryTransformMask(SplashImageMaskSource src, void *srcData,
// compute the scale factors
if (mat[0] >= 0) {
- t0 = imgCoordMungeUpperC(mat[0] + mat[4], glyphMode) -
- imgCoordMungeLowerC(mat[4], glyphMode);
+ t0 = splashRound(mat[0] + mat[4]) - splashRound(mat[4]);
} else {
- t0 = imgCoordMungeUpperC(mat[4], glyphMode) -
- imgCoordMungeLowerC(mat[0] + mat[4], glyphMode);
+ t0 = splashRound(mat[4]) - splashRound(mat[0] + mat[4]);
}
if (mat[1] >= 0) {
- t1 = imgCoordMungeUpperC(mat[1] + mat[5], glyphMode) -
- imgCoordMungeLowerC(mat[5], glyphMode);
+ t1 = splashRound(mat[1] + mat[5]) - splashRound(mat[5]);
} else {
- t1 = imgCoordMungeUpperC(mat[5], glyphMode) -
- imgCoordMungeLowerC(mat[1] + mat[5], glyphMode);
+ t1 = splashRound(mat[5]) - splashRound(mat[1] + mat[5]);
}
scaledWidth = t0 > t1 ? t0 : t1;
if (mat[2] >= 0) {
- t0 = imgCoordMungeUpperC(mat[2] + mat[4], glyphMode) -
- imgCoordMungeLowerC(mat[4], glyphMode);
+ t0 = splashRound(mat[2] + mat[4]) - splashRound(mat[4]);
} else {
- t0 = imgCoordMungeUpperC(mat[4], glyphMode) -
- imgCoordMungeLowerC(mat[2] + mat[4], glyphMode);
+ t0 = splashRound(mat[4]) - splashRound(mat[2] + mat[4]);
}
if (mat[3] >= 0) {
- t1 = imgCoordMungeUpperC(mat[3] + mat[5], glyphMode) -
- imgCoordMungeLowerC(mat[5], glyphMode);
+ t1 = splashRound(mat[3] + mat[5]) - splashRound(mat[5]);
} else {
- t1 = imgCoordMungeUpperC(mat[5], glyphMode) -
- imgCoordMungeLowerC(mat[3] + mat[5], glyphMode);
+ t1 = splashRound(mat[5]) - splashRound(mat[3] + mat[5]);
}
scaledHeight = t0 > t1 ? t0 : t1;
if (scaledWidth == 0) {
@@ -2567,19 +3592,28 @@ void Splash::arbitraryTransformMask(SplashImageMaskSource src, void *srcData,
// scale the input image
scaledMask = scaleMask(src, srcData, srcWidth, srcHeight,
- scaledWidth, scaledHeight);
+ scaledWidth, scaledHeight, interpolate);
// construct the three sections
- i = (vy[2] <= vy[3]) ? 2 : 3;
- if (vy[1] <= vy[i]) {
+ i = 0;
+ if (vy[1] < vy[i]) {
i = 1;
}
- if (vy[0] < vy[i] || (i != 3 && vy[0] == vy[i])) {
- i = 0;
+ if (vy[2] < vy[i]) {
+ i = 2;
}
- 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 (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 = splashRound(vy[i]);
+ section[0].y1 = splashRound(vy[(i+2) & 3]) - 1;
if (vx[i] < vx[(i+1) & 3]) {
section[0].ia0 = i;
section[0].ia1 = (i+3) & 3;
@@ -2593,8 +3627,8 @@ void Splash::arbitraryTransformMask(SplashImageMaskSource src, void *srcData,
}
nSections = 1;
} else {
- section[0].y0 = imgCoordMungeLowerC(vy[i], glyphMode);
- section[2].y1 = imgCoordMungeUpperC(vy[(i+2) & 3], glyphMode) - 1;
+ section[0].y0 = splashRound(vy[i]);
+ section[2].y1 = splashRound(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]) {
@@ -2605,8 +3639,8 @@ void Splash::arbitraryTransformMask(SplashImageMaskSource src, void *srcData,
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);
+ section[1].y0 = splashRound(vy[(i+1) & 3]);
+ section[2].y0 = splashRound(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;
@@ -2619,8 +3653,8 @@ void Splash::arbitraryTransformMask(SplashImageMaskSource src, void *srcData,
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);
+ section[1].y0 = splashRound(vy[(i+3) & 3]);
+ section[2].y0 = splashRound(vy[(i+1) & 3]);
if (vx[(i+1) & 3] < vx[(i+3) & 3]) {
section[1].ia0 = i;
section[1].ia1 = (i+1) & 3;
@@ -2653,11 +3687,9 @@ void Splash::arbitraryTransformMask(SplashImageMaskSource src, void *srcData,
}
// initialize the pixel pipe
- pipeInit(&pipe, 0, 0, state->fillPattern, NULL,
- (Guchar)splashRound(state->fillAlpha * 255), gTrue, gFalse);
- if (vectorAntialias) {
- drawAAPixelInit();
- }
+ pipeInit(&pipe, state->fillPattern,
+ (Guchar)splashRound(state->fillAlpha * 255),
+ gTrue, gFalse);
// make sure narrow images cover at least one pixel
if (nSections == 1) {
@@ -2675,23 +3707,30 @@ void Splash::arbitraryTransformMask(SplashImageMaskSource src, void *srcData,
// 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);
+ xa = splashRound(section[i].xa0 +
+ ((SplashCoord)y + 0.5 - section[i].ya0) *
+ section[i].dxdya);
+ xb = splashRound(section[i].xb0 +
+ ((SplashCoord)y + 0.5 - section[i].yb0) *
+ section[i].dxdyb);
+ if (xa > xb) {
+ continue;
+ }
// 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;
+ // check the scanBuf bounds
+ if (xa >= bitmap->width || xb < 0) {
+ continue;
+ }
+ if (xa < 0) {
+ xa = 0;
}
+ if (xb > bitmap->width) {
+ xb = bitmap->width;
+ }
+ // get the scan line
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 +
@@ -2710,13 +3749,19 @@ void Splash::arbitraryTransformMask(SplashImageMaskSource src, void *srcData,
} else if (yy >= scaledHeight) {
yy = scaledHeight - 1;
}
- pipe.shape = scaledMask->data[yy * scaledWidth + xx];
- if (vectorAntialias && clipRes2 != splashClipAllInside) {
- drawAAPixel(&pipe, x, y);
+ scanBuf[x] = scaledMask->data[yy * scaledWidth + xx];
+ }
+ // clip the scan line
+ if (clipRes != splashClipAllInside) {
+ if (vectorAntialias) {
+ state->clip->clipSpan(scanBuf, y, xa, xb - 1, state->strokeAdjust);
} else {
- drawPixel(&pipe, x, y, clipRes2 == splashClipAllInside);
+ state->clip->clipSpanBinary(scanBuf, y, xa, xb - 1,
+ state->strokeAdjust);
}
}
+ // draw the scan line
+ (this->*pipe.run)(&pipe, xa, xb - 1, y, scanBuf + xa, NULL);
}
}
@@ -2726,7 +3771,8 @@ void Splash::arbitraryTransformMask(SplashImageMaskSource src, void *srcData,
// Scale an image mask into a SplashBitmap.
SplashBitmap *Splash::scaleMask(SplashImageMaskSource src, void *srcData,
int srcWidth, int srcHeight,
- int scaledWidth, int scaledHeight) {
+ int scaledWidth, int scaledHeight,
+ GBool interpolate) {
SplashBitmap *dest;
dest = new SplashBitmap(scaledWidth, scaledHeight, 1, splashModeMono8,
@@ -2744,8 +3790,13 @@ SplashBitmap *Splash::scaleMask(SplashImageMaskSource src, void *srcData,
scaleMaskYuXd(src, srcData, srcWidth, srcHeight,
scaledWidth, scaledHeight, dest);
} else {
- scaleMaskYuXu(src, srcData, srcWidth, srcHeight,
- scaledWidth, scaledHeight, dest);
+ if (interpolate) {
+ scaleMaskYuXuI(src, srcData, srcWidth, srcHeight,
+ scaledWidth, scaledHeight, dest);
+ } else {
+ scaleMaskYuXu(src, srcData, srcWidth, srcHeight,
+ scaledWidth, scaledHeight, dest);
+ }
}
}
return dest;
@@ -3057,60 +4108,158 @@ void Splash::scaleMaskYuXu(SplashImageMaskSource src, void *srcData,
gfree(lineBuf);
}
+void Splash::scaleMaskYuXuI(SplashImageMaskSource src, void *srcData,
+ int srcWidth, int srcHeight,
+ int scaledWidth, int scaledHeight,
+ SplashBitmap *dest) {
+ Guchar *lineBuf0, *lineBuf1, *tBuf;
+ Guchar pix;
+ SplashCoord yr, xr, ys, xs, ySrc, xSrc;
+ int ySrc0, ySrc1, yBuf, xSrc0, xSrc1, y, x;
+ Guchar *destPtr;
+
+ // ratios
+ yr = (SplashCoord)srcHeight / (SplashCoord)scaledHeight;
+ xr = (SplashCoord)srcWidth / (SplashCoord)scaledWidth;
+
+ // allocate buffers
+ lineBuf0 = (Guchar *)gmalloc(scaledWidth);
+ lineBuf1 = (Guchar *)gmalloc(scaledWidth);
+
+ // read first two rows
+ (*src)(srcData, lineBuf0);
+ if (srcHeight > 1) {
+ (*src)(srcData, lineBuf1);
+ yBuf = 1;
+ } else {
+ memcpy(lineBuf1, lineBuf0, srcWidth);
+ yBuf = 0;
+ }
+
+ // interpolate first two rows
+ for (x = scaledWidth - 1; x >= 0; --x) {
+ xSrc = xr * x;
+ xSrc0 = splashFloor(xSrc + xr * 0.5 - 0.5);
+ xSrc1 = xSrc0 + 1;
+ xs = ((SplashCoord)xSrc1 + 0.5) - (xSrc + xr * 0.5);
+ if (xSrc0 < 0) {
+ xSrc0 = 0;
+ }
+ if (xSrc1 >= srcWidth) {
+ xSrc1 = srcWidth - 1;
+ }
+ lineBuf0[x] = (Guchar)(int)
+ ((xs * lineBuf0[xSrc0] +
+ ((SplashCoord)1 - xs) * lineBuf0[xSrc1]) * 255);
+ lineBuf1[x] = (Guchar)(int)
+ ((xs * lineBuf1[xSrc0] +
+ ((SplashCoord)1 - xs) * lineBuf1[xSrc1]) * 255);
+ }
+
+ destPtr = dest->data;
+ for (y = 0; y < scaledHeight; ++y) {
+
+ // compute vertical interpolation parameters
+ ySrc = yr * y;
+ ySrc0 = splashFloor(ySrc + yr * 0.5 - 0.5);
+ ySrc1 = ySrc0 + 1;
+ ys = ((SplashCoord)ySrc1 + 0.5) - (ySrc + yr * 0.5);
+ if (ySrc0 < 0) {
+ ySrc0 = 0;
+ ys = 1;
+ }
+ if (ySrc1 >= srcHeight) {
+ ySrc1 = srcHeight - 1;
+ ys = 0;
+ }
+
+ // read another row (if necessary)
+ if (ySrc1 > yBuf) {
+ tBuf = lineBuf0;
+ lineBuf0 = lineBuf1;
+ lineBuf1 = tBuf;
+ (*src)(srcData, lineBuf1);
+
+ // interpolate the row
+ for (x = scaledWidth - 1; x >= 0; --x) {
+ xSrc = xr * x;
+ xSrc0 = splashFloor(xSrc + xr * 0.5 - 0.5);
+ xSrc1 = xSrc0 + 1;
+ xs = ((SplashCoord)xSrc1 + 0.5) - (xSrc + xr * 0.5);
+ if (xSrc0 < 0) {
+ xSrc0 = 0;
+ }
+ if (xSrc1 >= srcWidth) {
+ xSrc1 = srcWidth - 1;
+ }
+ lineBuf1[x] = (Guchar)(int)
+ ((xs * lineBuf1[xSrc0] +
+ ((SplashCoord)1 - xs) * lineBuf1[xSrc1]) * 255);
+ }
+
+ ++yBuf;
+ }
+
+ // do the vertical interpolation
+ for (x = 0; x < scaledWidth; ++x) {
+
+ pix = (Guchar)(int)(ys * lineBuf0[x] +
+ ((SplashCoord)1 - ys) * lineBuf1[x]);
+
+ // store the pixel
+ *destPtr++ = pix;
+ }
+ }
+
+ gfree(lineBuf1);
+ gfree(lineBuf0);
+}
+
void Splash::blitMask(SplashBitmap *src, int xDest, int yDest,
SplashClipResult clipRes) {
SplashPipe pipe;
- Guchar *p;
- int w, h, x, y;
+ int w, h, x0, x1, y0, y1, y, t;
w = src->getWidth();
h = src->getHeight();
- if (vectorAntialias && clipRes != splashClipAllInside) {
- pipeInit(&pipe, xDest, yDest, state->fillPattern, NULL,
- (Guchar)splashRound(state->fillAlpha * 255), gTrue, gFalse);
- drawAAPixelInit();
- p = src->getDataPtr();
+ pipeInit(&pipe, state->fillPattern,
+ (Guchar)splashRound(state->fillAlpha * 255),
+ gTrue, gFalse);
+ if (clipRes == splashClipAllInside) {
for (y = 0; y < h; ++y) {
- for (x = 0; x < w; ++x) {
- pipe.shape = *p++;
- drawAAPixel(&pipe, xDest + x, yDest + y);
- }
+ (this->*pipe.run)(&pipe, xDest, xDest + w - 1, yDest + y,
+ src->getDataPtr() + y * w, NULL);
}
} else {
- pipeInit(&pipe, xDest, yDest, state->fillPattern, NULL,
- (Guchar)splashRound(state->fillAlpha * 255), gTrue, gFalse);
- p = src->getDataPtr();
- if (clipRes == splashClipAllInside) {
- for (y = 0; y < h; ++y) {
- pipeSetXY(&pipe, xDest, yDest + y);
- for (x = 0; x < w; ++x) {
- if (*p) {
- pipe.shape = *p;
- (this->*pipe.run)(&pipe);
- } else {
- pipeIncX(&pipe);
- }
- ++p;
- }
- }
- updateModX(xDest);
- updateModX(xDest + w - 1);
- updateModY(yDest);
- updateModY(yDest + h - 1);
- } else {
- for (y = 0; y < h; ++y) {
- pipeSetXY(&pipe, xDest, yDest + y);
- for (x = 0; x < w; ++x) {
- if (*p && state->clip->test(xDest + x, yDest + y)) {
- pipe.shape = *p;
- (this->*pipe.run)(&pipe);
- updateModX(xDest + x);
- updateModY(yDest + y);
- } else {
- pipeIncX(&pipe);
- }
- ++p;
+ x0 = xDest;
+ if ((t = state->clip->getXMinI(state->strokeAdjust)) > x0) {
+ x0 = t;
+ }
+ x1 = xDest + w;
+ if ((t = state->clip->getXMaxI(state->strokeAdjust) + 1) < x1) {
+ x1 = t;
+ }
+ y0 = yDest;
+ if ((t = state->clip->getYMinI(state->strokeAdjust)) > y0) {
+ y0 = t;
+ }
+ y1 = yDest + h;
+ if ((t = state->clip->getYMaxI(state->strokeAdjust) + 1) < y1) {
+ y1 = t;
+ }
+ if (x0 < x1 && y0 < y1) {
+ for (y = y0; y < y1; ++y) {
+ memcpy(scanBuf + x0,
+ src->getDataPtr() + (y - yDest) * w + (x0 - xDest),
+ x1 - x0);
+ if (vectorAntialias) {
+ state->clip->clipSpan(scanBuf, y, x0, x1 - 1,
+ state->strokeAdjust);
+ } else {
+ state->clip->clipSpanBinary(scanBuf, y, x0, x1 - 1,
+ state->strokeAdjust);
}
+ (this->*pipe.run)(&pipe, x0, x1 - 1, y, scanBuf + x0, NULL);
}
}
}
@@ -3118,11 +4267,13 @@ void Splash::blitMask(SplashBitmap *src, int xDest, int yDest,
SplashError Splash::drawImage(SplashImageSource src, void *srcData,
SplashColorMode srcMode, GBool srcAlpha,
- int w, int h, SplashCoord *mat) {
+ int w, int h, SplashCoord *mat,
+ GBool interpolate) {
GBool ok;
SplashBitmap *scaledImg;
SplashClipResult clipRes;
GBool minorAxisZero;
+ SplashCoord wSize, hSize, t0, t1;
int x0, y0, x1, y1, scaledWidth, scaledHeight;
int nComps;
@@ -3142,11 +4293,8 @@ SplashError Splash::drawImage(SplashImageSource src, void *srcData,
nComps = 1;
break;
case splashModeRGB8:
- ok = srcMode == splashModeRGB8;
- nComps = 3;
- break;
case splashModeBGR8:
- ok = srcMode == splashModeBGR8;
+ ok = srcMode == splashModeRGB8;
nComps = 3;
break;
#if SPLASH_CMYK
@@ -3168,60 +4316,87 @@ SplashError Splash::drawImage(SplashImageSource src, void *srcData,
return splashErrSingularMatrix;
}
- minorAxisZero = mat[1] == 0 && mat[2] == 0;
+ minorAxisZero = splashAbs(mat[1]) <= 0.0001 && splashAbs(mat[2]) <= 0.0001;
+
+ // rough estimate of size of scaled image
+ t0 = splashAbs(mat[0]);
+ t1 = splashAbs(mat[1]);
+ wSize = t0 > t1 ? t0 : t1;
+ t0 = splashAbs(mat[2]);
+ t1 = splashAbs(mat[3]);
+ hSize = t0 > t1 ? t0 : t1;
+
+ // stream-mode upscaling -- this is slower, so we only use it if the
+ // upscaled image is large (in which case clipping should remove
+ // many pixels)
+ if (wSize > 2 * w && hSize > 2 * h && wSize * hSize > 1000000) {
+ upscaleImage(src, srcData, srcMode, nComps, srcAlpha,
+ w, h, mat, interpolate);
// 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);
+ } else if (mat[0] > 0 && minorAxisZero && mat[3] > 0) {
+ getImageBounds(mat[4], mat[0] + mat[4], &x0, &x1);
+ getImageBounds(mat[5], mat[3] + mat[5], &y0, &y1);
+ clipRes = state->clip->testRect(x0, y0, x1 - 1, y1 - 1,
+ state->strokeAdjust);
opClipRes = clipRes;
if (clipRes != splashClipAllOutside) {
scaledWidth = x1 - x0;
scaledHeight = y1 - y0;
scaledImg = scaleImage(src, srcData, srcMode, nComps, srcAlpha, w, h,
- scaledWidth, scaledHeight);
+ scaledWidth, scaledHeight, interpolate);
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;
- }
+ getImageBounds(mat[4], mat[0] + mat[4], &x0, &x1);
+ getImageBounds(mat[3] + mat[5], mat[5], &y0, &y1);
+ clipRes = state->clip->testRect(x0, y0, x1 - 1, y1 - 1,
+ state->strokeAdjust);
+ opClipRes = clipRes;
+ if (clipRes != splashClipAllOutside) {
+ scaledWidth = x1 - x0;
+ scaledHeight = y1 - y0;
+ scaledImg = scaleImage(src, srcData, srcMode, nComps, srcAlpha, w, h,
+ scaledWidth, scaledHeight, interpolate);
+ vertFlipImage(scaledImg, scaledWidth, scaledHeight, nComps);
+ blitImage(scaledImg, srcAlpha, x0, y0, clipRes);
+ delete scaledImg;
}
- if (y0 == y1) {
- if (mat[5] + mat[1] * 0.5 < y0) {
- --y0;
- } else {
- ++y1;
- }
+
+ // scaling plus horizontal flip
+ } else if (mat[0] > 0 && minorAxisZero && mat[3] > 0) {
+ getImageBounds(mat[0] + mat[4], mat[4], &x0, &x1);
+ getImageBounds(mat[5], mat[3] + mat[5], &y0, &y1);
+ clipRes = state->clip->testRect(x0, y0, x1 - 1, y1 - 1,
+ state->strokeAdjust);
+ opClipRes = clipRes;
+ if (clipRes != splashClipAllOutside) {
+ scaledWidth = x1 - x0;
+ scaledHeight = y1 - y0;
+ scaledImg = scaleImage(src, srcData, srcMode, nComps, srcAlpha, w, h,
+ scaledWidth, scaledHeight, interpolate);
+ horizFlipImage(scaledImg, scaledWidth, scaledHeight, nComps);
+ blitImage(scaledImg, srcAlpha, x0, y0, clipRes);
+ delete scaledImg;
}
- clipRes = state->clip->testRect(x0, y0, x1 - 1, y1 - 1);
+
+ // scaling plus horizontal and vertical flips
+ } else if (mat[0] > 0 && minorAxisZero && mat[3] < 0) {
+ getImageBounds(mat[0] + mat[4], mat[4], &x0, &x1);
+ getImageBounds(mat[3] + mat[5], mat[5], &y0, &y1);
+ clipRes = state->clip->testRect(x0, y0, x1 - 1, y1 - 1,
+ state->strokeAdjust);
opClipRes = clipRes;
if (clipRes != splashClipAllOutside) {
scaledWidth = x1 - x0;
scaledHeight = y1 - y0;
scaledImg = scaleImage(src, srcData, srcMode, nComps, srcAlpha, w, h,
- scaledWidth, scaledHeight);
+ scaledWidth, scaledHeight, interpolate);
vertFlipImage(scaledImg, scaledWidth, scaledHeight, nComps);
+ horizFlipImage(scaledImg, scaledWidth, scaledHeight, nComps);
blitImage(scaledImg, srcAlpha, x0, y0, clipRes);
delete scaledImg;
}
@@ -3229,21 +4404,227 @@ SplashError Splash::drawImage(SplashImageSource src, void *srcData,
// all other cases
} else {
arbitraryTransformImage(src, srcData, srcMode, nComps, srcAlpha,
- w, h, mat);
+ w, h, mat, interpolate);
}
return splashOk;
}
+void Splash::upscaleImage(SplashImageSource src, void *srcData,
+ SplashColorMode srcMode, int nComps,
+ GBool srcAlpha, int srcWidth, int srcHeight,
+ SplashCoord *mat, GBool interpolate) {
+ SplashClipResult clipRes;
+ SplashPipe pipe;
+ SplashColorPtr unscaledImage, pixelBuf, p, q, q00, q01, q10, q11;
+ Guchar *unscaledAlpha, *alphaPtr;
+ SplashCoord xMin, yMin, xMax, yMax, t;
+ SplashCoord mi0, mi1, mi2, mi3, mi4, mi5, det;
+ SplashCoord ix, iy, sx, sy, pix0, pix1;
+ int rowSize, xMinI, yMinI, xMaxI, yMaxI, x, y, x0, y0, x1, y1, tt, i;
+
+ // compute the bbox of the target quadrilateral
+ xMin = xMax = mat[4];
+ t = mat[2] + mat[4];
+ if (t < xMin) {
+ xMin = t;
+ } else if (t > xMax) {
+ xMax = t;
+ }
+ t = mat[0] + mat[2] + mat[4];
+ if (t < xMin) {
+ xMin = t;
+ } else if (t > xMax) {
+ xMax = t;
+ }
+ t = mat[0] + mat[4];
+ if (t < xMin) {
+ xMin = t;
+ } else if (t > xMax) {
+ xMax = t;
+ }
+ getImageBounds(xMin, xMax, &xMinI, &xMaxI);
+ yMin = yMax = mat[5];
+ t = mat[3] + mat[5];
+ if (t < yMin) {
+ yMin = t;
+ } else if (t > yMax) {
+ yMax = t;
+ }
+ t = mat[1] + mat[3] + mat[5];
+ if (t < yMin) {
+ yMin = t;
+ } else if (t > yMax) {
+ yMax = t;
+ }
+ t = mat[1] + mat[5];
+ if (t < yMin) {
+ yMin = t;
+ } else if (t > yMax) {
+ yMax = t;
+ }
+ getImageBounds(yMin, yMax, &yMinI, &yMaxI);
+
+ // clipping
+ clipRes = state->clip->testRect(xMinI, yMinI, xMaxI - 1, yMaxI - 1,
+ state->strokeAdjust);
+ opClipRes = clipRes;
+ if (clipRes == splashClipAllOutside) {
+ return;
+ }
+ if (clipRes != splashClipAllInside) {
+ if ((tt = state->clip->getXMinI(state->strokeAdjust)) > xMinI) {
+ xMinI = tt;
+ }
+ if ((tt = state->clip->getXMaxI(state->strokeAdjust) + 1) < xMaxI) {
+ xMaxI = tt;
+ }
+ if ((tt = state->clip->getYMinI(state->strokeAdjust)) > yMinI) {
+ yMinI = tt;
+ }
+ if ((tt = state->clip->getYMaxI(state->strokeAdjust) + 1) < yMaxI) {
+ yMaxI = tt;
+ }
+ }
+
+ // invert the matrix
+ det = mat[0] * mat[3] - mat[1] * mat[2];
+ if (splashAbs(det) < 1e-6) {
+ // this should be caught by the singular matrix check in fillImageMask
+ return;
+ }
+ det = (SplashCoord)1 / det;
+ mi0 = det * mat[3] * srcWidth;
+ mi1 = -det * mat[1] * srcHeight;
+ mi2 = -det * mat[2] * srcWidth;
+ mi3 = det * mat[0] * srcHeight;
+ mi4 = det * (mat[2] * mat[5] - mat[3] * mat[4]) * srcWidth;
+ mi5 = -det * (mat[0] * mat[5] - mat[1] * mat[4]) * srcHeight;
+
+ // grab the image
+ if (srcWidth > INT_MAX / nComps) {
+ rowSize = -1;
+ } else {
+ rowSize = srcWidth * nComps;
+ }
+ unscaledImage = (SplashColorPtr)gmallocn(srcHeight, rowSize);
+ if (srcAlpha) {
+ unscaledAlpha = (Guchar *)gmallocn(srcHeight, srcWidth);
+ for (y = 0, p = unscaledImage, alphaPtr = unscaledAlpha;
+ y < srcHeight;
+ ++y, p += rowSize, alphaPtr += srcWidth) {
+ (*src)(srcData, p, alphaPtr);
+ }
+ } else {
+ unscaledAlpha = NULL;
+ for (y = 0, p = unscaledImage; y < srcHeight; ++y, p += srcWidth * nComps) {
+ (*src)(srcData, p, NULL);
+ }
+ }
+
+ // draw it
+ pixelBuf = (SplashColorPtr)gmallocn(xMaxI - xMinI, nComps);
+ pipeInit(&pipe, NULL,
+ (Guchar)splashRound(state->fillAlpha * 255),
+ gTrue, gFalse);
+ for (y = yMinI; y < yMaxI; ++y) {
+ p = pixelBuf;
+ for (x = xMinI; x < xMaxI; ++x) {
+ ix = ((SplashCoord)x + 0.5) * mi0 + ((SplashCoord)y + 0.5) * mi2 + mi4;
+ iy = ((SplashCoord)x + 0.5) * mi1 + ((SplashCoord)y + 0.5) * mi3 + mi5;
+ if (interpolate) {
+ if (ix >= 0 && ix < srcWidth && iy >= 0 && iy < srcHeight) {
+ x0 = splashFloor(ix - 0.5);
+ x1 = x0 + 1;
+ sx = (ix - 0.5) - x0;
+ y0 = splashFloor(iy - 0.5);
+ y1 = y0 + 1;
+ sy = (iy - 0.5) - y0;
+ if (x0 < 0) {
+ x0 = 0;
+ }
+ if (x1 >= srcWidth) {
+ x1 = srcWidth - 1;
+ }
+ if (y0 < 0) {
+ y0 = 0;
+ }
+ if (y1 >= srcHeight) {
+ y1 = srcHeight - 1;
+ }
+ q00 = &unscaledImage[(y0 * srcWidth + x0) * nComps];
+ q01 = &unscaledImage[(y0 * srcWidth + x1) * nComps];
+ q10 = &unscaledImage[(y1 * srcWidth + x0) * nComps];
+ q11 = &unscaledImage[(y1 * srcWidth + x1) * nComps];
+ for (i = 0; i < nComps; ++i) {
+ pix0 = ((SplashCoord)1 - sx) * *q00++ + sx * *q01++;
+ pix1 = ((SplashCoord)1 - sx) * *q10++ + sx * *q11++;
+ *p++ = (Guchar)splashRound(((SplashCoord)1 - sy) * pix0
+ + sy * pix1);
+ }
+ if (srcAlpha) {
+ pix0 = ((SplashCoord)1 - sx) * unscaledAlpha[y0 * srcWidth + x0]
+ + sx * unscaledAlpha[y0 * srcWidth + x1];
+ pix1 = ((SplashCoord)1 - sx) * unscaledAlpha[y1 * srcWidth + x0]
+ + sx * unscaledAlpha[y1 * srcWidth + x1];
+ scanBuf[x] = (Guchar)splashRound(((SplashCoord)1 - sy) * pix0
+ + sy * pix1);
+ } else {
+ scanBuf[x] = 0xff;
+ }
+ } else {
+ for (i = 0; i < nComps; ++i) {
+ *p++ = 0;
+ }
+ scanBuf[x] = 0;
+ }
+ } else {
+ x0 = splashFloor(ix);
+ y0 = splashFloor(iy);
+ if (x0 >= 0 && x0 < srcWidth && y0 >= 0 && y0 < srcHeight) {
+ q = &unscaledImage[(y0 * srcWidth + x0) * nComps];
+ for (i = 0; i < nComps; ++i) {
+ *p++ = *q++;
+ }
+ if (srcAlpha) {
+ scanBuf[x] = unscaledAlpha[y0 * srcWidth + x0];
+ } else {
+ scanBuf[x] = 0xff;
+ }
+ } else {
+ for (i = 0; i < nComps; ++i) {
+ *p++ = 0;
+ }
+ scanBuf[x] = 0;
+ }
+ }
+ }
+ if (clipRes != splashClipAllInside) {
+ if (vectorAntialias) {
+ state->clip->clipSpan(scanBuf, y, xMinI, xMaxI - 1,
+ state->strokeAdjust);
+ } else {
+ state->clip->clipSpanBinary(scanBuf, y, xMinI, xMaxI - 1,
+ state->strokeAdjust);
+ }
+ }
+ (this->*pipe.run)(&pipe, xMinI, xMaxI - 1, y, scanBuf + xMinI, pixelBuf);
+ }
+
+ gfree(pixelBuf);
+ gfree(unscaledImage);
+ gfree(unscaledAlpha);
+}
+
void Splash::arbitraryTransformImage(SplashImageSource src, void *srcData,
SplashColorMode srcMode, int nComps,
GBool srcAlpha,
int srcWidth, int srcHeight,
- SplashCoord *mat) {
+ SplashCoord *mat, GBool interpolate) {
SplashBitmap *scaledImg;
- SplashClipResult clipRes, clipRes2;
+ SplashClipResult clipRes;
SplashPipe pipe;
- SplashColor pixel;
+ SplashColorPtr pixelBuf;
int scaledWidth, scaledHeight, t0, t1;
SplashCoord r00, r01, r10, r11, det, ir00, ir01, ir10, ir11;
SplashCoord vx[4], vy[4];
@@ -3259,29 +4640,26 @@ void Splash::arbitraryTransformImage(SplashImageSource src, void *srcData,
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]);
+ xMin = splashRound(vx[0]);
+ xMax = splashRound(vx[0]);
+ yMin = splashRound(vy[0]);
+ yMax = splashRound(vy[0]);
for (i = 1; i < 4; ++i) {
- t0 = imgCoordMungeLower(vx[i]);
+ t0 = splashRound(vx[i]);
if (t0 < xMin) {
xMin = t0;
- }
- t0 = imgCoordMungeUpper(vx[i]);
- if (t0 > xMax) {
+ } else if (t0 > xMax) {
xMax = t0;
}
- t1 = imgCoordMungeLower(vy[i]);
+ t1 = splashRound(vy[i]);
if (t1 < yMin) {
yMin = t1;
- }
- t1 = imgCoordMungeUpper(vy[i]);
- if (t1 > yMax) {
+ } else if (t1 > yMax) {
yMax = t1;
}
}
- clipRes = state->clip->testRect(xMin, yMin, xMax - 1, yMax - 1);
+ clipRes = state->clip->testRect(xMin, yMin, xMax - 1, yMax - 1,
+ state->strokeAdjust);
opClipRes = clipRes;
if (clipRes == splashClipAllOutside) {
return;
@@ -3289,25 +4667,25 @@ void Splash::arbitraryTransformImage(SplashImageSource src, void *srcData,
// compute the scale factors
if (mat[0] >= 0) {
- t0 = imgCoordMungeUpper(mat[0] + mat[4]) - imgCoordMungeLower(mat[4]);
+ t0 = splashRound(mat[0] + mat[4]) - splashRound(mat[4]);
} else {
- t0 = imgCoordMungeUpper(mat[4]) - imgCoordMungeLower(mat[0] + mat[4]);
+ t0 = splashRound(mat[4]) - splashRound(mat[0] + mat[4]);
}
if (mat[1] >= 0) {
- t1 = imgCoordMungeUpper(mat[1] + mat[5]) - imgCoordMungeLower(mat[5]);
+ t1 = splashRound(mat[1] + mat[5]) - splashRound(mat[5]);
} else {
- t1 = imgCoordMungeUpper(mat[5]) - imgCoordMungeLower(mat[1] + mat[5]);
+ t1 = splashRound(mat[5]) - splashRound(mat[1] + mat[5]);
}
scaledWidth = t0 > t1 ? t0 : t1;
if (mat[2] >= 0) {
- t0 = imgCoordMungeUpper(mat[2] + mat[4]) - imgCoordMungeLower(mat[4]);
+ t0 = splashRound(mat[2] + mat[4]) - splashRound(mat[4]);
} else {
- t0 = imgCoordMungeUpper(mat[4]) - imgCoordMungeLower(mat[2] + mat[4]);
+ t0 = splashRound(mat[4]) - splashRound(mat[2] + mat[4]);
}
if (mat[3] >= 0) {
- t1 = imgCoordMungeUpper(mat[3] + mat[5]) - imgCoordMungeLower(mat[5]);
+ t1 = splashRound(mat[3] + mat[5]) - splashRound(mat[5]);
} else {
- t1 = imgCoordMungeUpper(mat[5]) - imgCoordMungeLower(mat[3] + mat[5]);
+ t1 = splashRound(mat[5]) - splashRound(mat[3] + mat[5]);
}
scaledHeight = t0 > t1 ? t0 : t1;
if (scaledWidth == 0) {
@@ -3334,7 +4712,8 @@ void Splash::arbitraryTransformImage(SplashImageSource src, void *srcData,
// scale the input image
scaledImg = scaleImage(src, srcData, srcMode, nComps, srcAlpha,
- srcWidth, srcHeight, scaledWidth, scaledHeight);
+ srcWidth, srcHeight, scaledWidth, scaledHeight,
+ interpolate);
// construct the three sections
i = 0;
@@ -3354,8 +4733,8 @@ void Splash::arbitraryTransformImage(SplashImageSource src, void *srcData,
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;
+ section[0].y0 = splashRound(vy[i]);
+ section[0].y1 = splashRound(vy[(i+2) & 3]) - 1;
if (vx[i] < vx[(i+1) & 3]) {
section[0].ia0 = i;
section[0].ia1 = (i+3) & 3;
@@ -3369,8 +4748,8 @@ void Splash::arbitraryTransformImage(SplashImageSource src, void *srcData,
}
nSections = 1;
} else {
- section[0].y0 = imgCoordMungeLower(vy[i]);
- section[2].y1 = imgCoordMungeUpper(vy[(i+2) & 3]) - 1;
+ section[0].y0 = splashRound(vy[i]);
+ section[2].y1 = splashRound(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]) {
@@ -3381,8 +4760,8 @@ void Splash::arbitraryTransformImage(SplashImageSource src, void *srcData,
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]);
+ section[1].y0 = splashRound(vy[(i+1) & 3]);
+ section[2].y0 = splashRound(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;
@@ -3395,8 +4774,8 @@ void Splash::arbitraryTransformImage(SplashImageSource src, void *srcData,
section[1].ib1 = (i+2) & 3;
}
} else {
- section[1].y0 = imgCoordMungeLower(vy[(i+3) & 3]);
- section[2].y0 = imgCoordMungeUpper(vy[(i+1) & 3]);
+ section[1].y0 = splashRound(vy[(i+3) & 3]);
+ section[2].y0 = splashRound(vy[(i+1) & 3]);
if (vx[(i+1) & 3] < vx[(i+3) & 3]) {
section[1].ia0 = i;
section[1].ia1 = (i+1) & 3;
@@ -3429,13 +4808,9 @@ void Splash::arbitraryTransformImage(SplashImageSource src, void *srcData,
}
// initialize the pixel pipe
- pipeInit(&pipe, 0, 0, NULL, pixel,
+ pipeInit(&pipe, NULL,
(Guchar)splashRound(state->fillAlpha * 255),
- srcAlpha || (vectorAntialias && clipRes != splashClipAllInside),
- gFalse);
- if (vectorAntialias) {
- drawAAPixelInit();
- }
+ gTrue, gFalse);
// make sure narrow images cover at least one pixel
if (nSections == 1) {
@@ -3450,24 +4825,46 @@ void Splash::arbitraryTransformImage(SplashImageSource src, void *srcData,
}
}
+ pixelBuf = (SplashColorPtr)gmallocn(xMax - xMin + 1, bitmapComps);
+
// 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);
- xb = imgCoordMungeUpper(section[i].xb0 +
- ((SplashCoord)y + 0.5 - section[i].yb0) *
- section[i].dxdyb);
+ xa = splashRound(section[i].xa0 +
+ ((SplashCoord)y + 0.5 - section[i].ya0) *
+ section[i].dxdya);
+ xb = splashRound(section[i].xb0 +
+ ((SplashCoord)y + 0.5 - section[i].yb0) *
+ section[i].dxdyb);
+ if (xa > xb) {
+ continue;
+ }
// make sure narrow images cover at least one pixel
if (xa == xb) {
++xb;
}
+ // check the scanBuf bounds
+ if (xa >= bitmap->width || xb < 0) {
+ continue;
+ }
+ if (xa < 0) {
+ xa = 0;
+ }
+ if (xb > bitmap->width) {
+ xb = bitmap->width;
+ }
+ // clip the scan line
+ memset(scanBuf + xa, 0xff, xb - xa);
if (clipRes != splashClipAllInside) {
- clipRes2 = state->clip->testSpan(xa, xb - 1, y);
- } else {
- clipRes2 = clipRes;
+ if (vectorAntialias) {
+ state->clip->clipSpan(scanBuf, y, xa, xb - 1,
+ state->strokeAdjust);
+ } else {
+ state->clip->clipSpanBinary(scanBuf, y, xa, xb - 1,
+ state->strokeAdjust);
+ }
}
+ // draw the scan line
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 +
@@ -3486,21 +4883,19 @@ void Splash::arbitraryTransformImage(SplashImageSource src, void *srcData,
} else if (yy >= scaledHeight) {
yy = scaledHeight - 1;
}
- scaledImg->getPixel(xx, yy, pixel);
+ // get the color
+ scaledImg->getPixel(xx, yy, pixelBuf + (x - xa) * bitmapComps);
+ // apply alpha
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);
+ scanBuf[x] = div255(scanBuf[x] *
+ scaledImg->alpha[yy * scaledWidth + xx]);
}
}
+ (this->*pipe.run)(&pipe, xa, xb - 1, y, scanBuf + xa, pixelBuf);
}
}
+ gfree(pixelBuf);
delete scaledImg;
}
@@ -3508,7 +4903,8 @@ void Splash::arbitraryTransformImage(SplashImageSource src, void *srcData,
SplashBitmap *Splash::scaleImage(SplashImageSource src, void *srcData,
SplashColorMode srcMode, int nComps,
GBool srcAlpha, int srcWidth, int srcHeight,
- int scaledWidth, int scaledHeight) {
+ int scaledWidth, int scaledHeight,
+ GBool interpolate) {
SplashBitmap *dest;
dest = new SplashBitmap(scaledWidth, scaledHeight, 1, srcMode, srcAlpha);
@@ -3525,8 +4921,13 @@ SplashBitmap *Splash::scaleImage(SplashImageSource src, void *srcData,
scaleImageYuXd(src, srcData, srcMode, nComps, srcAlpha,
srcWidth, srcHeight, scaledWidth, scaledHeight, dest);
} else {
- scaleImageYuXu(src, srcData, srcMode, nComps, srcAlpha,
- srcWidth, srcHeight, scaledWidth, scaledHeight, dest);
+ if (interpolate) {
+ scaleImageYuXuI(src, srcData, srcMode, nComps, srcAlpha,
+ srcWidth, srcHeight, scaledWidth, scaledHeight, dest);
+ } else {
+ scaleImageYuXu(src, srcData, srcMode, nComps, srcAlpha,
+ srcWidth, srcHeight, scaledWidth, scaledHeight, dest);
+ }
}
}
return dest;
@@ -3654,27 +5055,6 @@ void Splash::scaleImageYdXd(SplashImageSource src, void *srcData,
*destPtr++ = (Guchar)pix2;
break;
- case splashModeBGR8:
-
- // compute the final pixel
- pix0 = pix1 = pix2 = 0;
- for (i = 0; i < xStep; ++i) {
- pix0 += pixBuf[xx];
- pix1 += pixBuf[xx+1];
- pix2 += pixBuf[xx+2];
- xx += 3;
- }
- // pix / xStep * yStep
- pix0 = (pix0 * d) >> 23;
- pix1 = (pix1 * d) >> 23;
- pix2 = (pix2 * d) >> 23;
-
- // store the pixel
- *destPtr++ = (Guchar)pix2;
- *destPtr++ = (Guchar)pix1;
- *destPtr++ = (Guchar)pix0;
- break;
-
#if SPLASH_CMYK
case splashModeCMYK8:
@@ -3703,6 +5083,7 @@ void Splash::scaleImageYdXd(SplashImageSource src, void *srcData,
case splashModeMono1: // mono1 is not allowed
+ case splashModeBGR8: // bgr8 is not allowed
default:
break;
}
@@ -3812,8 +5193,6 @@ void Splash::scaleImageYdXu(SplashImageSource src, void *srcData,
// store the pixel
switch (srcMode) {
- case splashModeMono1: // mono1 is not allowed
- break;
case splashModeMono8:
for (i = 0; i < xStep; ++i) {
*destPtr++ = (Guchar)pix[0];
@@ -3826,13 +5205,6 @@ void Splash::scaleImageYdXu(SplashImageSource src, void *srcData,
*destPtr++ = (Guchar)pix[2];
}
break;
- case splashModeBGR8:
- for (i = 0; i < xStep; ++i) {
- *destPtr++ = (Guchar)pix[2];
- *destPtr++ = (Guchar)pix[1];
- *destPtr++ = (Guchar)pix[0];
- }
- break;
#if SPLASH_CMYK
case splashModeCMYK8:
for (i = 0; i < xStep; ++i) {
@@ -3843,6 +5215,10 @@ void Splash::scaleImageYdXu(SplashImageSource src, void *srcData,
}
break;
#endif
+ case splashModeMono1: // mono1 is not allowed
+ case splashModeBGR8: // BGR8 is not allowed
+ default:
+ break;
}
// process alpha
@@ -3942,8 +5318,6 @@ void Splash::scaleImageYuXd(SplashImageSource src, void *srcData,
// 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;
@@ -3958,14 +5332,6 @@ void Splash::scaleImageYuXd(SplashImageSource src, void *srcData,
*destPtr++ = (Guchar)pix[2];
}
break;
- case splashModeBGR8:
- for (i = 0; i < yStep; ++i) {
- destPtr = destPtr0 + (i * scaledWidth + x) * nComps;
- *destPtr++ = (Guchar)pix[2];
- *destPtr++ = (Guchar)pix[1];
- *destPtr++ = (Guchar)pix[0];
- }
- break;
#if SPLASH_CMYK
case splashModeCMYK8:
for (i = 0; i < yStep; ++i) {
@@ -3977,6 +5343,10 @@ void Splash::scaleImageYuXd(SplashImageSource src, void *srcData,
}
break;
#endif
+ case splashModeMono1: // mono1 is not allowed
+ case splashModeBGR8: // BGR8 is not allowed
+ default:
+ break;
}
// process alpha
@@ -4071,8 +5441,6 @@ void Splash::scaleImageYuXu(SplashImageSource src, void *srcData,
// 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) {
@@ -4091,16 +5459,6 @@ void Splash::scaleImageYuXu(SplashImageSource src, void *srcData,
}
}
break;
- case splashModeBGR8:
- for (i = 0; i < yStep; ++i) {
- for (j = 0; j < xStep; ++j) {
- destPtr = destPtr0 + (i * scaledWidth + xx + j) * nComps;
- *destPtr++ = (Guchar)pix[2];
- *destPtr++ = (Guchar)pix[1];
- *destPtr++ = (Guchar)pix[0];
- }
- }
- break;
#if SPLASH_CMYK
case splashModeCMYK8:
for (i = 0; i < yStep; ++i) {
@@ -4114,6 +5472,10 @@ void Splash::scaleImageYuXu(SplashImageSource src, void *srcData,
}
break;
#endif
+ case splashModeMono1: // mono1 is not allowed
+ case splashModeBGR8: // BGR8 is not allowed
+ default:
+ break;
}
// process alpha
@@ -4140,6 +5502,177 @@ void Splash::scaleImageYuXu(SplashImageSource src, void *srcData,
gfree(lineBuf);
}
+void Splash::scaleImageYuXuI(SplashImageSource src, void *srcData,
+ SplashColorMode srcMode, int nComps,
+ GBool srcAlpha, int srcWidth, int srcHeight,
+ int scaledWidth, int scaledHeight,
+ SplashBitmap *dest) {
+ Guchar *lineBuf0, *lineBuf1, *alphaLineBuf0, *alphaLineBuf1, *tBuf;
+ Guchar pix[splashMaxColorComps];
+ SplashCoord yr, xr, ys, xs, ySrc, xSrc;
+ int ySrc0, ySrc1, yBuf, xSrc0, xSrc1, y, x, i;
+ Guchar *destPtr, *destAlphaPtr;
+
+ // ratios
+ yr = (SplashCoord)srcHeight / (SplashCoord)scaledHeight;
+ xr = (SplashCoord)srcWidth / (SplashCoord)scaledWidth;
+
+ // allocate buffers
+ lineBuf0 = (Guchar *)gmallocn(scaledWidth, nComps);
+ lineBuf1 = (Guchar *)gmallocn(scaledWidth, nComps);
+ if (srcAlpha) {
+ alphaLineBuf0 = (Guchar *)gmalloc(scaledWidth);
+ alphaLineBuf1 = (Guchar *)gmalloc(scaledWidth);
+ } else {
+ alphaLineBuf0 = NULL;
+ alphaLineBuf1 = NULL;
+ }
+
+ // read first two rows
+ (*src)(srcData, lineBuf0, alphaLineBuf0);
+ if (srcHeight > 1) {
+ (*src)(srcData, lineBuf1, alphaLineBuf1);
+ yBuf = 1;
+ } else {
+ memcpy(lineBuf1, lineBuf0, srcWidth * nComps);
+ if (srcAlpha) {
+ memcpy(alphaLineBuf1, alphaLineBuf0, srcWidth);
+ }
+ yBuf = 0;
+ }
+
+ // interpolate first two rows
+ for (x = scaledWidth - 1; x >= 0; --x) {
+ xSrc = xr * x;
+ xSrc0 = splashFloor(xSrc + xr * 0.5 - 0.5);
+ xSrc1 = xSrc0 + 1;
+ xs = ((SplashCoord)xSrc1 + 0.5) - (xSrc + xr * 0.5);
+ if (xSrc0 < 0) {
+ xSrc0 = 0;
+ }
+ if (xSrc1 >= srcWidth) {
+ xSrc1 = srcWidth - 1;
+ }
+ for (i = 0; i < nComps; ++i) {
+ lineBuf0[x*nComps+i] = (Guchar)(int)
+ (xs * lineBuf0[xSrc0*nComps+i] +
+ ((SplashCoord)1 - xs) * lineBuf0[xSrc1*nComps+i]);
+ lineBuf1[x*nComps+i] = (Guchar)(int)
+ (xs * lineBuf1[xSrc0*nComps+i] +
+ ((SplashCoord)1 - xs) * lineBuf1[xSrc1*nComps+i]);
+ }
+ if (srcAlpha) {
+ alphaLineBuf0[x] = (Guchar)(int)
+ (xs * alphaLineBuf0[xSrc0] +
+ ((SplashCoord)1 - xs) * alphaLineBuf0[xSrc1]);
+ alphaLineBuf1[x] = (Guchar)(int)
+ (xs * alphaLineBuf1[xSrc0] +
+ ((SplashCoord)1 - xs) * alphaLineBuf1[xSrc1]);
+ }
+ }
+
+ destPtr = dest->data;
+ destAlphaPtr = dest->alpha;
+ for (y = 0; y < scaledHeight; ++y) {
+
+ // compute vertical interpolation parameters
+ ySrc = yr * y;
+ ySrc0 = splashFloor(ySrc + yr * 0.5 - 0.5);
+ ySrc1 = ySrc0 + 1;
+ ys = ((SplashCoord)ySrc1 + 0.5) - (ySrc + yr * 0.5);
+ if (ySrc0 < 0) {
+ ySrc0 = 0;
+ ys = 1;
+ }
+ if (ySrc1 >= srcHeight) {
+ ySrc1 = srcHeight - 1;
+ ys = 0;
+ }
+
+ // read another row (if necessary)
+ if (ySrc1 > yBuf) {
+ tBuf = lineBuf0;
+ lineBuf0 = lineBuf1;
+ lineBuf1 = tBuf;
+ tBuf = alphaLineBuf0;
+ alphaLineBuf0 = alphaLineBuf1;
+ alphaLineBuf1 = tBuf;
+ (*src)(srcData, lineBuf1, alphaLineBuf1);
+
+ // interpolate the row
+ for (x = scaledWidth - 1; x >= 0; --x) {
+ xSrc = xr * x;
+ xSrc0 = splashFloor(xSrc + xr * 0.5 - 0.5);
+ xSrc1 = xSrc0 + 1;
+ xs = ((SplashCoord)xSrc1 + 0.5) - (xSrc + xr * 0.5);
+ if (xSrc0 < 0) {
+ xSrc0 = 0;
+ }
+ if (xSrc1 >= srcWidth) {
+ xSrc1 = srcWidth - 1;
+ }
+ for (i = 0; i < nComps; ++i) {
+ lineBuf1[x*nComps+i] =
+ (Guchar)(int)(xs * lineBuf1[xSrc0*nComps+i] +
+ ((SplashCoord)1 - xs) * lineBuf1[xSrc1*nComps+i]);
+ }
+ if (srcAlpha) {
+ alphaLineBuf1[x] =
+ (Guchar)(int)(xs * alphaLineBuf1[xSrc0] +
+ ((SplashCoord)1 - xs) * alphaLineBuf1[xSrc1]);
+ }
+ }
+
+ ++yBuf;
+ }
+
+ // do the vertical interpolation
+ for (x = 0; x < scaledWidth; ++x) {
+
+ for (i = 0; i < nComps; ++i) {
+ pix[i] = (Guchar)(int)(ys * lineBuf0[x*nComps+i] +
+ ((SplashCoord)1 - ys) * lineBuf1[x*nComps+i]);
+ }
+
+ // store the pixel
+ switch (srcMode) {
+ case splashModeMono8:
+ *destPtr++ = pix[0];
+ break;
+ case splashModeRGB8:
+ *destPtr++ = pix[0];
+ *destPtr++ = pix[1];
+ *destPtr++ = pix[2];
+ break;
+#if SPLASH_CMYK
+ case splashModeCMYK8:
+ *destPtr++ = pix[0];
+ *destPtr++ = pix[1];
+ *destPtr++ = pix[2];
+ *destPtr++ = pix[3];
+ break;
+#endif
+ case splashModeMono1: // mono1 is not allowed
+ case splashModeBGR8: // BGR8 is not allowed
+ default:
+ break;
+ }
+
+ // process alpha
+ if (srcAlpha) {
+ *destAlphaPtr++ = (Guchar)(int)
+ (ys * alphaLineBuf0[x] +
+ ((SplashCoord)1 - ys) * alphaLineBuf1[x]);
+ }
+ }
+ }
+
+ gfree(alphaLineBuf1);
+ gfree(alphaLineBuf0);
+ gfree(lineBuf1);
+ gfree(lineBuf0);
+}
+
void Splash::vertFlipImage(SplashBitmap *img, int width, int height,
int nComps) {
Guchar *lineBuf;
@@ -4167,12 +5700,43 @@ void Splash::vertFlipImage(SplashBitmap *img, int width, int height,
gfree(lineBuf);
}
+void Splash::horizFlipImage(SplashBitmap *img, int width, int height,
+ int nComps) {
+ Guchar *lineBuf;
+ SplashColorPtr p0, p1, p2;
+ int w, x, y, i;
+
+ w = width * nComps;
+ lineBuf = (Guchar *)gmalloc(w);
+ for (y = 0, p0 = img->data; y < height; ++y, p0 += img->rowSize) {
+ memcpy(lineBuf, p0, w);
+ p1 = p0;
+ p2 = lineBuf + (w - nComps);
+ for (x = 0; x < width; ++x) {
+ for (i = 0; i < nComps; ++i) {
+ p1[i] = p2[i];
+ }
+ p1 += nComps;
+ p2 -= nComps;
+ }
+ }
+ if (img->alpha) {
+ for (y = 0, p0 = img->alpha; y < height; ++y, p0 += width) {
+ memcpy(lineBuf, p0, width);
+ p1 = p0;
+ p2 = lineBuf + (width - 1);
+ for (x = 0; x < width; ++x) {
+ *p1++ = *p2--;
+ }
+ }
+ }
+ gfree(lineBuf);
+}
+
void Splash::blitImage(SplashBitmap *src, GBool srcAlpha, int xDest, int yDest,
SplashClipResult clipRes) {
SplashPipe pipe;
- SplashColor pixel;
- Guchar *ap;
- int w, h, x0, y0, x1, y1, x, y;
+ int w, h, x0, y0, x1, y1, y;
// split the image into clipped and unclipped regions
w = src->getWidth();
@@ -4200,8 +5764,8 @@ void Splash::blitImage(SplashBitmap *src, GBool srcAlpha, int xDest, int yDest,
x1 = x0;
}
if ((y1 = splashFloor(state->clip->getYMax()) - yDest) > h) {
- y1 = h;
- }
+ y1 = h;
+ }
if (y1 < y0) {
y1 = y0;
}
@@ -4210,31 +5774,24 @@ void Splash::blitImage(SplashBitmap *src, GBool srcAlpha, int xDest, int yDest,
// draw the unclipped region
if (x0 < w && y0 < h && x0 < x1 && y0 < y1) {
- pipeInit(&pipe, xDest + x0, yDest + y0, NULL, pixel,
- (Guchar)splashRound(state->fillAlpha * 255), srcAlpha, gFalse);
+ pipeInit(&pipe, NULL,
+ (Guchar)splashRound(state->fillAlpha * 255),
+ srcAlpha, gFalse);
if (srcAlpha) {
for (y = y0; y < y1; ++y) {
- pipeSetXY(&pipe, xDest + x0, yDest + y);
- ap = src->getAlphaPtr() + y * w + x0;
- for (x = x0; x < x1; ++x) {
- src->getPixel(x, y, pixel);
- pipe.shape = *ap++;
- (this->*pipe.run)(&pipe);
- }
+ (this->*pipe.run)(&pipe, xDest + x0, xDest + x1 - 1, yDest + y,
+ src->getAlphaPtr() + y * w + x0,
+ src->getDataPtr() + y * src->getRowSize() +
+ x0 * bitmapComps);
}
} 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);
- }
+ (this->*pipe.run)(&pipe, xDest + x0, xDest + x1 - 1, yDest + y,
+ NULL,
+ src->getDataPtr() + y * src->getRowSize() +
+ x0 * bitmapComps);
}
}
- updateModX(xDest + x0);
- updateModX(xDest + x1 - 1);
- updateModY(yDest + y0);
- updateModY(yDest + y1 - 1);
}
// draw the clipped regions
@@ -4257,66 +5814,62 @@ void Splash::blitImageClipped(SplashBitmap *src, GBool srcAlpha,
int xSrc, int ySrc, int xDest, int yDest,
int w, int h) {
SplashPipe pipe;
- SplashColor pixel;
- Guchar *ap;
- int x, y;
+ int y;
- if (vectorAntialias) {
- pipeInit(&pipe, xDest, yDest, NULL, pixel,
- (Guchar)splashRound(state->fillAlpha * 255), gTrue, gFalse);
- drawAAPixelInit();
- if (srcAlpha) {
- for (y = 0; y < h; ++y) {
- ap = src->getAlphaPtr() + (ySrc + y) * src->getWidth() + xSrc;
- for (x = 0; x < w; ++x) {
- src->getPixel(xSrc + x, ySrc + y, pixel);
- pipe.shape = *ap++;
- drawAAPixel(&pipe, xDest + x, yDest + y);
- }
- }
- } else {
- for (y = 0; y < h; ++y) {
- for (x = 0; x < w; ++x) {
- src->getPixel(xSrc + x, ySrc + y, pixel);
- pipe.shape = 255;
- drawAAPixel(&pipe, xDest + x, yDest + y);
- }
+ if (xDest < 0) {
+ xSrc -= xDest;
+ w += xDest;
+ xDest = 0;
+ }
+ if (xDest + w > bitmap->width) {
+ w = bitmap->width - xDest;
+ }
+ if (yDest < 0) {
+ ySrc -= yDest;
+ h += yDest;
+ yDest = 0;
+ }
+ if (yDest + h > bitmap->height) {
+ h = bitmap->height - yDest;
+ }
+ if (w <= 0 || h <= 0) {
+ return;
+ }
+
+ pipeInit(&pipe, NULL,
+ (Guchar)splashRound(state->fillAlpha * 255),
+ gTrue, gFalse);
+ if (srcAlpha) {
+ for (y = 0; y < h; ++y) {
+ memcpy(scanBuf + xDest,
+ src->getAlphaPtr() + (ySrc + y) * src->getWidth() + xSrc,
+ w);
+ if (vectorAntialias) {
+ state->clip->clipSpan(scanBuf, yDest + y, xDest, xDest + w - 1,
+ state->strokeAdjust);
+ } else {
+ state->clip->clipSpanBinary(scanBuf, yDest + y, xDest, xDest + w - 1,
+ state->strokeAdjust);
}
+ (this->*pipe.run)(&pipe, xDest, xDest + w - 1, yDest + y,
+ scanBuf + xDest,
+ src->getDataPtr() + (ySrc + y) * src->getRowSize() +
+ xSrc * bitmapComps);
}
} else {
- pipeInit(&pipe, xDest, yDest, NULL, pixel,
- (Guchar)splashRound(state->fillAlpha * 255), srcAlpha, gFalse);
- if (srcAlpha) {
- for (y = 0; y < h; ++y) {
- ap = src->getAlphaPtr() + (ySrc + y) * src->getWidth() + xSrc;
- pipeSetXY(&pipe, xDest, yDest + y);
- for (x = 0; x < w; ++x) {
- if (state->clip->test(xDest + x, yDest + y)) {
- src->getPixel(xSrc + x, ySrc + y, pixel);
- pipe.shape = *ap++;
- (this->*pipe.run)(&pipe);
- updateModX(xDest + x);
- updateModY(yDest + y);
- } else {
- pipeIncX(&pipe);
- ++ap;
- }
- }
- }
- } else {
- for (y = 0; y < h; ++y) {
- pipeSetXY(&pipe, xDest, yDest + y);
- for (x = 0; x < w; ++x) {
- if (state->clip->test(xDest + x, yDest + y)) {
- src->getPixel(xSrc + x, ySrc + y, pixel);
- (this->*pipe.run)(&pipe);
- updateModX(xDest + x);
- updateModY(yDest + y);
- } else {
- pipeIncX(&pipe);
- }
- }
+ for (y = 0; y < h; ++y) {
+ memset(scanBuf + xDest, 0xff, w);
+ if (vectorAntialias) {
+ state->clip->clipSpan(scanBuf, yDest + y, xDest, xDest + w - 1,
+ state->strokeAdjust);
+ } else {
+ state->clip->clipSpanBinary(scanBuf, yDest + y, xDest, xDest + w - 1,
+ state->strokeAdjust);
}
+ (this->*pipe.run)(&pipe, xDest, xDest + w - 1, yDest + y,
+ scanBuf + xDest,
+ src->getDataPtr() + (ySrc + y) * src->getRowSize() +
+ xSrc * bitmapComps);
}
}
}
@@ -4325,82 +5878,82 @@ SplashError Splash::composite(SplashBitmap *src, int xSrc, int ySrc,
int xDest, int yDest, int w, int h,
GBool noClip, GBool nonIsolated) {
SplashPipe pipe;
- SplashColor pixel;
- Guchar alpha;
- Guchar *ap;
- int x, y;
+ int x0, x1, y0, y1, y, t;
if (src->mode != bitmap->mode) {
return splashErrModeMismatch;
}
- if (src->alpha) {
- pipeInit(&pipe, xDest, yDest, NULL, pixel,
- (Guchar)splashRound(state->fillAlpha * 255), gTrue, nonIsolated);
- if (noClip) {
+ pipeInit(&pipe, NULL,
+ (Guchar)splashRound(state->fillAlpha * 255),
+ !noClip || src->alpha != NULL, nonIsolated);
+ if (noClip) {
+ if (src->alpha) {
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);
- }
+ // this uses shape instead of alpha, which isn't technically
+ // correct, but works out the same
+ (this->*pipe.run)(&pipe, xDest, xDest + w - 1, yDest + y,
+ src->getAlphaPtr() +
+ (ySrc + y) * src->getWidth() + xSrc,
+ src->getDataPtr() + (ySrc + y) * src->getRowSize() +
+ xSrc * bitmapComps);
}
- updateModX(xDest);
- updateModX(xDest + w - 1);
- updateModY(yDest);
- updateModY(yDest + h - 1);
} else {
for (y = 0; y < h; ++y) {
- pipeSetXY(&pipe, xDest, yDest + y);
- ap = src->getAlphaPtr() + (ySrc + y) * src->getWidth() + xSrc;
- for (x = 0; x < w; ++x) {
- src->getPixel(xSrc + x, ySrc + y, pixel);
- alpha = *ap++;
- if (state->clip->test(xDest + x, yDest + y)) {
- // this uses shape instead of alpha, which isn't technically
- // correct, but works out the same
- pipe.shape = alpha;
- (this->*pipe.run)(&pipe);
- updateModX(xDest + x);
- updateModY(yDest + y);
- } else {
- pipeIncX(&pipe);
- }
- }
+ (this->*pipe.run)(&pipe, xDest, xDest + w - 1, yDest + y,
+ NULL,
+ src->getDataPtr() + (ySrc + y) * src->getRowSize() +
+ xSrc * bitmapComps);
}
}
} else {
- pipeInit(&pipe, xDest, yDest, NULL, pixel,
- (Guchar)splashRound(state->fillAlpha * 255), gFalse, nonIsolated);
- if (noClip) {
- for (y = 0; y < h; ++y) {
- pipeSetXY(&pipe, xDest, yDest + y);
- for (x = 0; x < w; ++x) {
- src->getPixel(xSrc + x, ySrc + y, pixel);
- (this->*pipe.run)(&pipe);
+ x0 = xDest;
+ if ((t = state->clip->getXMinI(state->strokeAdjust)) > x0) {
+ x0 = t;
+ }
+ x1 = xDest + w;
+ if ((t = state->clip->getXMaxI(state->strokeAdjust) + 1) < x1) {
+ x1 = t;
+ }
+ y0 = yDest;
+ if ((t = state->clip->getYMinI(state->strokeAdjust)) > y0) {
+ y0 = t;
+ }
+ y1 = yDest + h;
+ if ((t = state->clip->getYMaxI(state->strokeAdjust) + 1) < y1) {
+ y1 = t;
+ }
+ if (x0 < x1 && y0 < y1) {
+ if (src->alpha) {
+ for (y = y0; y < y1; ++y) {
+ memcpy(scanBuf + x0,
+ src->getAlphaPtr() + (ySrc + y - yDest) * src->getWidth() +
+ (xSrc + x0 - xDest),
+ x1 - x0);
+ if (!state->clip->clipSpanBinary(scanBuf, y, x0, x1 - 1,
+ state->strokeAdjust)) {
+ continue;
+ }
+ // this uses shape instead of alpha, which isn't technically
+ // correct, but works out the same
+ (this->*pipe.run)(&pipe, x0, x1 - 1, y,
+ scanBuf + x0,
+ src->getDataPtr() +
+ (ySrc + y - yDest) * src->getRowSize() +
+ (xSrc + x0 - xDest) * bitmapComps);
}
- }
- updateModX(xDest);
- updateModX(xDest + w - 1);
- updateModY(yDest);
- updateModY(yDest + h - 1);
- } else {
- for (y = 0; y < h; ++y) {
- pipeSetXY(&pipe, xDest, yDest + y);
- for (x = 0; x < w; ++x) {
- src->getPixel(xSrc + x, ySrc + y, pixel);
- if (state->clip->test(xDest + x, yDest + y)) {
- (this->*pipe.run)(&pipe);
- updateModX(xDest + x);
- updateModY(yDest + y);
- } else {
- pipeIncX(&pipe);
+ } else {
+ for (y = y0; y < y1; ++y) {
+ memset(scanBuf + x0, 0xff, x1 - x0);
+ if (!state->clip->clipSpanBinary(scanBuf, y, x0, x1 - 1,
+ state->strokeAdjust)) {
+ continue;
}
+ (this->*pipe.run)(&pipe, xDest, xDest + w - 1, yDest + y,
+ scanBuf + x0,
+ src->getDataPtr() +
+ (ySrc + y - yDest) * src->getRowSize() +
+ (xSrc - xDest) * bitmapComps);
}
}
}
@@ -4535,9 +6088,7 @@ SplashError Splash::blitTransparent(SplashBitmap *src, int xSrc, int ySrc,
for (y = 0; y < h; ++y) {
p = &bitmap->data[(yDest + y) * bitmap->rowSize + xDest];
q = &src->data[(ySrc + y) * src->rowSize + xSrc];
- for (x = 0; x < w; ++x) {
- *p++ = *q++;
- }
+ memcpy(p, q, w);
}
break;
case splashModeRGB8:
@@ -4545,11 +6096,7 @@ SplashError Splash::blitTransparent(SplashBitmap *src, int xSrc, int ySrc,
for (y = 0; y < h; ++y) {
p = &bitmap->data[(yDest + y) * bitmap->rowSize + 3 * xDest];
q = &src->data[(ySrc + y) * src->rowSize + 3 * xSrc];
- for (x = 0; x < w; ++x) {
- *p++ = *q++;
- *p++ = *q++;
- *p++ = *q++;
- }
+ memcpy(p, q, 3 * w);
}
break;
#if SPLASH_CMYK
@@ -4557,12 +6104,7 @@ SplashError Splash::blitTransparent(SplashBitmap *src, int xSrc, int ySrc,
for (y = 0; y < h; ++y) {
p = &bitmap->data[(yDest + y) * bitmap->rowSize + 4 * xDest];
q = &src->data[(ySrc + y) * src->rowSize + 4 * xSrc];
- for (x = 0; x < w; ++x) {
- *p++ = *q++;
- *p++ = *q++;
- *p++ = *q++;
- *p++ = *q++;
- }
+ memcpy(p, q, 4 * w);
}
break;
#endif
@@ -4571,9 +6113,7 @@ SplashError Splash::blitTransparent(SplashBitmap *src, int xSrc, int ySrc,
if (bitmap->alpha) {
for (y = 0; y < h; ++y) {
q = &bitmap->alpha[(yDest + y) * bitmap->width + xDest];
- for (x = 0; x < w; ++x) {
- *q++ = 0x00;
- }
+ memset(q, 0, w);
}
}
@@ -5002,11 +6542,9 @@ 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",
+ printf(" %4d: x0=%8.2f y0=%8.2f x1=%8.2f y1=%8.2f count=%d\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" : " ");
+ path->segs[i].count);
}
}