summaryrefslogtreecommitdiff
path: root/splash
diff options
context:
space:
mode:
Diffstat (limited to 'splash')
-rw-r--r--splash/Makefile.in10
-rw-r--r--splash/Splash.cc4548
-rw-r--r--splash/Splash.h117
-rw-r--r--splash/SplashBitmap.cc2
-rw-r--r--splash/SplashBitmap.h2
-rw-r--r--splash/SplashClip.cc547
-rw-r--r--splash/SplashClip.h55
-rw-r--r--splash/SplashErrorCodes.h2
-rw-r--r--splash/SplashFTFont.cc31
-rw-r--r--splash/SplashFTFont.h2
-rw-r--r--splash/SplashFTFontEngine.cc243
-rw-r--r--splash/SplashFTFontEngine.h56
-rw-r--r--splash/SplashFTFontFile.cc71
-rw-r--r--splash/SplashFTFontFile.h34
-rw-r--r--splash/SplashFont.cc2
-rw-r--r--splash/SplashFont.h2
-rw-r--r--splash/SplashFontEngine.cc123
-rw-r--r--splash/SplashFontEngine.h63
-rw-r--r--splash/SplashFontFile.cc21
-rw-r--r--splash/SplashFontFile.h15
-rw-r--r--splash/SplashFontFileID.cc2
-rw-r--r--splash/SplashFontFileID.h2
-rw-r--r--splash/SplashGlyphBitmap.h2
-rw-r--r--splash/SplashMath.h93
-rw-r--r--splash/SplashPath.cc3
-rw-r--r--splash/SplashPath.h4
-rw-r--r--splash/SplashPattern.cc2
-rw-r--r--splash/SplashPattern.h2
-rw-r--r--splash/SplashScreen.cc2
-rw-r--r--splash/SplashScreen.h2
-rw-r--r--splash/SplashState.cc48
-rw-r--r--splash/SplashState.h11
-rw-r--r--splash/SplashT1Font.cc290
-rw-r--r--splash/SplashT1Font.h57
-rw-r--r--splash/SplashT1FontEngine.cc124
-rw-r--r--splash/SplashT1FontEngine.h53
-rw-r--r--splash/SplashT1FontFile.cc98
-rw-r--r--splash/SplashT1FontFile.h58
-rw-r--r--splash/SplashTypes.h2
-rw-r--r--splash/SplashXPath.cc346
-rw-r--r--splash/SplashXPath.h63
-rw-r--r--splash/SplashXPathScanner.cc899
-rw-r--r--splash/SplashXPathScanner.h88
-rw-r--r--splash/vms_make.com0
44 files changed, 4880 insertions, 3317 deletions
diff --git a/splash/Makefile.in b/splash/Makefile.in
index 66c449b..6479b15 100644
--- a/splash/Makefile.in
+++ b/splash/Makefile.in
@@ -16,7 +16,7 @@ GOOLIBDIR = ../goo
FOFISRCDIR = $(srcdir)/../fofi
FOFILIBDIR = ../fofi
-CXXFLAGS = @CXXFLAGS@ @DEFS@ -I.. -I$(GOOSRCDIR) -I$(FOFISRCDIR) -I$(srcdir) @t1_CFLAGS@ @freetype2_CFLAGS@
+CXXFLAGS = @CXXFLAGS@ @DEFS@ -I.. -I$(srcdir)/.. -I$(GOOSRCDIR) -I$(FOFISRCDIR) -I$(srcdir) @freetype2_CFLAGS@
CXX = @CXX@
AR = @AR@
@@ -48,9 +48,6 @@ CXX_SRC = \
$(srcdir)/SplashPattern.cc \
$(srcdir)/SplashScreen.cc \
$(srcdir)/SplashState.cc \
- $(srcdir)/SplashT1Font.cc \
- $(srcdir)/SplashT1FontEngine.cc \
- $(srcdir)/SplashT1FontFile.cc \
$(srcdir)/SplashXPath.cc \
$(srcdir)/SplashXPathScanner.cc
@@ -75,9 +72,6 @@ SPLASH_OBJS = \
SplashPattern.o \
SplashScreen.o \
SplashState.o \
- SplashT1Font.o \
- SplashT1FontEngine.o \
- SplashT1FontFile.o \
SplashXPath.o \
SplashXPathScanner.o
@@ -96,4 +90,4 @@ clean:
depend:
$(CXX) $(CXXFLAGS) -MM $(CXX_SRC) >Makefile.dep
-include Makefile.dep
+-include Makefile.dep
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);
}
}
diff --git a/splash/Splash.h b/splash/Splash.h
index 30761fb..7409e0c 100644
--- a/splash/Splash.h
+++ b/splash/Splash.h
@@ -2,6 +2,8 @@
//
// Splash.h
//
+// Copyright 2003-2013 Glyph & Cog, LLC
+//
//========================================================================
#ifndef SPLASH_H
@@ -97,6 +99,7 @@ public:
SplashClip *getClip();
SplashBitmap *getSoftMask();
GBool getInNonIsolatedGroup();
+ GBool getInKnockoutGroup();
//----- state write
@@ -125,8 +128,9 @@ public:
// NB: uses untransformed coordinates.
SplashError clipToPath(SplashPath *path, GBool eo);
void setSoftMask(SplashBitmap *softMask);
- void setInNonIsolatedGroup(SplashBitmap *alpha0BitmapA,
- int alpha0XA, int alpha0YA);
+ void setInTransparencyGroup(SplashBitmap *groupBackBitmapA,
+ int groupBackXA, int groupBackYA,
+ GBool nonIsolated, GBool knockout);
void setTransfer(Guchar *red, Guchar *green, Guchar *blue, Guchar *gray);
void setOverprintMask(Guint overprintMask);
@@ -172,7 +176,7 @@ public:
// top line.
SplashError fillImageMask(SplashImageMaskSource src, void *srcData,
int w, int h, SplashCoord *mat,
- GBool glyphMode);
+ GBool glyphMode, GBool interpolate);
// Draw an image. This will read <h> lines of <w> pixels from
// <src>, starting with the top line. These pixels are assumed to
@@ -182,16 +186,16 @@ public:
// are supported:
// source target
// ------ ------
- // Mono1 Mono1
// Mono8 Mono1 -- with dithering
// Mono8 Mono8
// RGB8 RGB8
- // BGR8 BGR8
+ // BGR8 RGB8
// CMYK8 CMYK8
// The matrix behaves as for fillImageMask.
SplashError drawImage(SplashImageSource src, void *srcData,
SplashColorMode srcMode, GBool srcAlpha,
- int w, int h, SplashCoord *mat);
+ int w, int h, SplashCoord *mat,
+ GBool interpolate);
// Composite a rectangular region from <src> onto this Splash
// object.
@@ -245,37 +249,53 @@ public:
private:
- void pipeInit(SplashPipe *pipe, int x, int y,
- SplashPattern *pattern, SplashColorPtr cSrc,
+ void pipeInit(SplashPipe *pipe, SplashPattern *pattern,
Guchar aInput, GBool usesShape,
GBool nonIsolatedGroup);
- void pipeRun(SplashPipe *pipe);
- void pipeRunSimpleMono1(SplashPipe *pipe);
- void pipeRunSimpleMono8(SplashPipe *pipe);
- void pipeRunSimpleRGB8(SplashPipe *pipe);
- void pipeRunSimpleBGR8(SplashPipe *pipe);
+ void pipeRun(SplashPipe *pipe, int x0, int x1, int y,
+ Guchar *shapePtr, SplashColorPtr cSrcPtr);
+ void pipeRunSimpleMono1(SplashPipe *pipe, int x0, int x1, int y,
+ Guchar *shapePtr, SplashColorPtr cSrcPtr);
+ void pipeRunSimpleMono8(SplashPipe *pipe, int x0, int x1, int y,
+ Guchar *shapePtr, SplashColorPtr cSrcPtr);
+ void pipeRunSimpleRGB8(SplashPipe *pipe, int x0, int x1, int y,
+ Guchar *shapePtr, SplashColorPtr cSrcPtr);
+ void pipeRunSimpleBGR8(SplashPipe *pipe, int x0, int x1, int y,
+ Guchar *shapePtr, SplashColorPtr cSrcPtr);
+#if SPLASH_CMYK
+ void pipeRunSimpleCMYK8(SplashPipe *pipe, int x0, int x1, int y,
+ Guchar *shapePtr, SplashColorPtr cSrcPtr);
+#endif
+ void pipeRunShapeMono1(SplashPipe *pipe, int x0, int x1, int y,
+ Guchar *shapePtr, SplashColorPtr cSrcPtr);
+ void pipeRunShapeMono8(SplashPipe *pipe, int x0, int x1, int y,
+ Guchar *shapePtr, SplashColorPtr cSrcPtr);
+ void pipeRunShapeRGB8(SplashPipe *pipe, int x0, int x1, int y,
+ Guchar *shapePtr, SplashColorPtr cSrcPtr);
+ void pipeRunShapeBGR8(SplashPipe *pipe, int x0, int x1, int y,
+ Guchar *shapePtr, SplashColorPtr cSrcPtr);
#if SPLASH_CMYK
- void pipeRunSimpleCMYK8(SplashPipe *pipe);
+ void pipeRunShapeCMYK8(SplashPipe *pipe, int x0, int x1, int y,
+ Guchar *shapePtr, SplashColorPtr cSrcPtr);
#endif
- void pipeRunAAMono1(SplashPipe *pipe);
- void pipeRunAAMono8(SplashPipe *pipe);
- void pipeRunAARGB8(SplashPipe *pipe);
- void pipeRunAABGR8(SplashPipe *pipe);
+ void pipeRunAAMono1(SplashPipe *pipe, int x0, int x1, int y,
+ Guchar *shapePtr, SplashColorPtr cSrcPtr);
+ void pipeRunAAMono8(SplashPipe *pipe, int x0, int x1, int y,
+ Guchar *shapePtr, SplashColorPtr cSrcPtr);
+ void pipeRunAARGB8(SplashPipe *pipe, int x0, int x1, int y,
+ Guchar *shapePtr, SplashColorPtr cSrcPtr);
+ void pipeRunAABGR8(SplashPipe *pipe, int x0, int x1, int y,
+ Guchar *shapePtr, SplashColorPtr cSrcPtr);
#if SPLASH_CMYK
- void pipeRunAACMYK8(SplashPipe *pipe);
+ void pipeRunAACMYK8(SplashPipe *pipe, int x0, int x1, int y,
+ Guchar *shapePtr, SplashColorPtr cSrcPtr);
#endif
- void pipeSetXY(SplashPipe *pipe, int x, int y);
- void pipeIncX(SplashPipe *pipe);
- void drawPixel(SplashPipe *pipe, int x, int y, GBool noClip);
- void drawAAPixelInit();
- void drawAAPixel(SplashPipe *pipe, int x, int y);
- void drawSpan(SplashPipe *pipe, int x0, int x1, int y, GBool noClip);
- void drawAALine(SplashPipe *pipe, int x0, int x1, int y);
void transform(SplashCoord *matrix, SplashCoord xi, SplashCoord yi,
SplashCoord *xo, SplashCoord *yo);
void updateModX(int x);
void updateModY(int y);
void strokeNarrow(SplashPath *path);
+ void drawStrokeSpan(SplashPipe *pipe, int x0, int x1, int y, GBool noClip);
void strokeWide(SplashPath *path, SplashCoord w);
SplashPath *flattenPath(SplashPath *path, SplashCoord *matrix,
SplashCoord flatness);
@@ -288,14 +308,23 @@ private:
SplashPath *makeDashedPath(SplashPath *xPath);
SplashError fillWithPattern(SplashPath *path, GBool eo,
SplashPattern *pattern, SplashCoord alpha);
+ SplashPath *tweakFillPath(SplashPath *path);
GBool pathAllOutside(SplashPath *path);
SplashError fillGlyph2(int x0, int y0, SplashGlyphBitmap *glyph);
+ void getImageBounds(SplashCoord xyMin, SplashCoord xyMax,
+ int *xyMinI, int *xyMaxI);
+ void upscaleMask(SplashImageMaskSource src, void *srcData,
+ int srcWidth, int srcHeight,
+ SplashCoord *mat, GBool glyphMode,
+ GBool interpolate);
void arbitraryTransformMask(SplashImageMaskSource src, void *srcData,
int srcWidth, int srcHeight,
- SplashCoord *mat, GBool glyphMode);
+ SplashCoord *mat, GBool glyphMode,
+ GBool interpolate);
SplashBitmap *scaleMask(SplashImageMaskSource src, void *srcData,
int srcWidth, int srcHeight,
- int scaledWidth, int scaledHeight);
+ int scaledWidth, int scaledHeight,
+ GBool interpolate);
void scaleMaskYdXd(SplashImageMaskSource src, void *srcData,
int srcWidth, int srcHeight,
int scaledWidth, int scaledHeight,
@@ -312,17 +341,26 @@ private:
int srcWidth, int srcHeight,
int scaledWidth, int scaledHeight,
SplashBitmap *dest);
+ void scaleMaskYuXuI(SplashImageMaskSource src, void *srcData,
+ int srcWidth, int srcHeight,
+ int scaledWidth, int scaledHeight,
+ SplashBitmap *dest);
void blitMask(SplashBitmap *src, int xDest, int yDest,
SplashClipResult clipRes);
+ void upscaleImage(SplashImageSource src, void *srcData,
+ SplashColorMode srcMode, int nComps,
+ GBool srcAlpha, int srcWidth, int srcHeight,
+ SplashCoord *mat, GBool interpolate);
void arbitraryTransformImage(SplashImageSource src, void *srcData,
SplashColorMode srcMode, int nComps,
GBool srcAlpha,
int srcWidth, int srcHeight,
- SplashCoord *mat);
+ SplashCoord *mat, GBool interpolate);
SplashBitmap *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);
void scaleImageYdXd(SplashImageSource src, void *srcData,
SplashColorMode srcMode, int nComps,
GBool srcAlpha, int srcWidth, int srcHeight,
@@ -343,8 +381,15 @@ private:
GBool srcAlpha, int srcWidth, int srcHeight,
int scaledWidth, int scaledHeight,
SplashBitmap *dest);
+ void scaleImageYuXuI(SplashImageSource src, void *srcData,
+ SplashColorMode srcMode, int nComps,
+ GBool srcAlpha, int srcWidth, int srcHeight,
+ int scaledWidth, int scaledHeight,
+ SplashBitmap *dest);
void vertFlipImage(SplashBitmap *img, int width, int height,
int nComps);
+ void horizFlipImage(SplashBitmap *img, int width, int height,
+ int nComps);
void blitImage(SplashBitmap *src, GBool srcAlpha, int xDest, int yDest,
SplashClipResult clipRes);
void blitImageClipped(SplashBitmap *src, GBool srcAlpha,
@@ -359,13 +404,13 @@ private:
static int pipeNonIsoGroupCorrection[];
SplashBitmap *bitmap;
+ int bitmapComps;
SplashState *state;
- SplashBitmap *aaBuf;
- int aaBufY;
- SplashBitmap *alpha0Bitmap; // for non-isolated groups, this is the
- // bitmap containing the alpha0 values
- int alpha0X, alpha0Y; // offset within alpha0Bitmap
- Guchar aaGamma[splashAASize * splashAASize + 1];
+ Guchar *scanBuf;
+ SplashBitmap // for transparency groups, this is the bitmap
+ *groupBackBitmap; // containing the alpha0/color0 values
+ int groupBackX, groupBackY; // offset within groupBackBitmap
+ Guchar aaGamma[256];
SplashCoord minLineWidth;
int modXMin, modYMin, modXMax, modYMax;
SplashClipResult opClipRes;
diff --git a/splash/SplashBitmap.cc b/splash/SplashBitmap.cc
index 9fc7b04..3606a91 100644
--- a/splash/SplashBitmap.cc
+++ b/splash/SplashBitmap.cc
@@ -2,6 +2,8 @@
//
// SplashBitmap.cc
//
+// Copyright 2003-2013 Glyph & Cog, LLC
+//
//========================================================================
#include <aconf.h>
diff --git a/splash/SplashBitmap.h b/splash/SplashBitmap.h
index 78f37d6..3dfc939 100644
--- a/splash/SplashBitmap.h
+++ b/splash/SplashBitmap.h
@@ -2,6 +2,8 @@
//
// SplashBitmap.h
//
+// Copyright 2003-2013 Glyph & Cog, LLC
+//
//========================================================================
#ifndef SPLASHBITMAP_H
diff --git a/splash/SplashClip.cc b/splash/SplashClip.cc
index da85771..6865c57 100644
--- a/splash/SplashClip.cc
+++ b/splash/SplashClip.cc
@@ -2,6 +2,8 @@
//
// SplashClip.cc
//
+// Copyright 2003-2013 Glyph & Cog, LLC
+//
//========================================================================
#include <aconf.h>
@@ -17,52 +19,52 @@
#include "SplashPath.h"
#include "SplashXPath.h"
#include "SplashXPathScanner.h"
-#include "SplashBitmap.h"
#include "SplashClip.h"
//------------------------------------------------------------------------
-// SplashClip.flags
-//------------------------------------------------------------------------
-#define splashClipEO 0x01 // use even-odd rule
+// Compute x * y / 255, where x and y are in [0, 255].
+static inline Guchar mul255(Guchar x, Guchar y) {
+ int z;
+
+ z = (int)x * (int)y;
+ return (Guchar)((z + (z >> 8) + 0x80) >> 8);
+}
//------------------------------------------------------------------------
// SplashClip
//------------------------------------------------------------------------
-SplashClip::SplashClip(SplashCoord x0, SplashCoord y0,
- SplashCoord x1, SplashCoord y1,
- GBool antialiasA) {
- antialias = antialiasA;
- if (x0 < x1) {
- xMin = x0;
- xMax = x1;
- } else {
- xMin = x1;
- xMax = x0;
- }
- if (y0 < y1) {
- yMin = y0;
- yMax = y1;
- } else {
- yMin = y1;
- yMax = y0;
- }
- xMinI = splashFloor(xMin);
- yMinI = splashFloor(yMin);
- xMaxI = splashCeil(xMax) - 1;
- yMaxI = splashCeil(yMax) - 1;
+SplashClip::SplashClip(int hardXMinA, int hardYMinA,
+ int hardXMaxA, int hardYMaxA) {
+ int w;
+
+ hardXMin = hardXMinA;
+ hardYMin = hardYMinA;
+ hardXMax = hardXMaxA;
+ hardYMax = hardYMaxA;
+ xMin = hardXMin;
+ yMin = hardYMin;
+ xMax = hardXMax;
+ yMax = hardYMax;
+ intBoundsValid = gFalse;
paths = NULL;
- flags = NULL;
+ eo = NULL;
scanners = NULL;
length = size = 0;
+ if ((w = hardXMax + 1) <= 0) {
+ w = 1;
+ }
+ buf = (Guchar *)gmalloc(w);
}
SplashClip::SplashClip(SplashClip *clip) {
- int yMinAA, yMaxAA;
- int i;
+ int w, i;
- antialias = clip->antialias;
+ hardXMin = clip->hardXMin;
+ hardYMin = clip->hardYMin;
+ hardXMax = clip->hardXMax;
+ hardYMax = clip->hardYMax;
xMin = clip->xMin;
yMin = clip->yMin;
xMax = clip->xMax;
@@ -71,25 +73,23 @@ SplashClip::SplashClip(SplashClip *clip) {
yMinI = clip->yMinI;
xMaxI = clip->xMaxI;
yMaxI = clip->yMaxI;
+ intBoundsValid = clip->intBoundsValid;
+ intBoundsStrokeAdjust = clip->intBoundsStrokeAdjust;
length = clip->length;
size = clip->size;
paths = (SplashXPath **)gmallocn(size, sizeof(SplashXPath *));
- flags = (Guchar *)gmallocn(size, sizeof(Guchar));
+ eo = (Guchar *)gmallocn(size, sizeof(Guchar));
scanners = (SplashXPathScanner **)
gmallocn(size, sizeof(SplashXPathScanner *));
for (i = 0; i < length; ++i) {
paths[i] = clip->paths[i]->copy();
- flags[i] = clip->flags[i];
- if (antialias) {
- yMinAA = yMinI * splashAASize;
- yMaxAA = (yMaxI + 1) * splashAASize - 1;
- } else {
- yMinAA = yMinI;
- yMaxAA = yMaxI;
- }
- scanners[i] = new SplashXPathScanner(paths[i], flags[i] & splashClipEO,
- yMinAA, yMaxAA);
+ eo[i] = clip->eo[i];
+ scanners[i] = new SplashXPathScanner(paths[i], eo[i], yMinI, yMaxI);
+ }
+ if ((w = splashCeil(xMax)) <= 0) {
+ w = 1;
}
+ buf = (Guchar *)gmalloc(w);
}
SplashClip::~SplashClip() {
@@ -100,8 +100,9 @@ SplashClip::~SplashClip() {
delete scanners[i];
}
gfree(paths);
- gfree(flags);
+ gfree(eo);
gfree(scanners);
+ gfree(buf);
}
void SplashClip::grow(int nPaths) {
@@ -113,7 +114,7 @@ void SplashClip::grow(int nPaths) {
size *= 2;
}
paths = (SplashXPath **)greallocn(paths, size, sizeof(SplashXPath *));
- flags = (Guchar *)greallocn(flags, size, sizeof(Guchar));
+ eo = (Guchar *)greallocn(eo, size, sizeof(Guchar));
scanners = (SplashXPathScanner **)
greallocn(scanners, size, sizeof(SplashXPathScanner *));
}
@@ -121,17 +122,18 @@ void SplashClip::grow(int nPaths) {
void SplashClip::resetToRect(SplashCoord x0, SplashCoord y0,
SplashCoord x1, SplashCoord y1) {
- int i;
+ int w, i;
for (i = 0; i < length; ++i) {
delete paths[i];
delete scanners[i];
}
gfree(paths);
- gfree(flags);
+ gfree(eo);
gfree(scanners);
+ gfree(buf);
paths = NULL;
- flags = NULL;
+ eo = NULL;
scanners = NULL;
length = size = 0;
@@ -149,10 +151,11 @@ void SplashClip::resetToRect(SplashCoord x0, SplashCoord y0,
yMin = y1;
yMax = y0;
}
- xMinI = splashFloor(xMin);
- yMinI = splashFloor(yMin);
- xMaxI = splashCeil(xMax) - 1;
- yMaxI = splashCeil(yMax) - 1;
+ intBoundsValid = gFalse;
+ if ((w = splashCeil(xMax)) <= 0) {
+ w = 1;
+ }
+ buf = (Guchar *)gmalloc(w);
}
SplashError SplashClip::clipToRect(SplashCoord x0, SplashCoord y0,
@@ -160,240 +163,358 @@ SplashError SplashClip::clipToRect(SplashCoord x0, SplashCoord y0,
if (x0 < x1) {
if (x0 > xMin) {
xMin = x0;
- xMinI = splashFloor(xMin);
+ intBoundsValid = gFalse;
}
if (x1 < xMax) {
xMax = x1;
- xMaxI = splashCeil(xMax) - 1;
+ intBoundsValid = gFalse;
}
} else {
if (x1 > xMin) {
xMin = x1;
- xMinI = splashFloor(xMin);
+ intBoundsValid = gFalse;
}
if (x0 < xMax) {
xMax = x0;
- xMaxI = splashCeil(xMax) - 1;
+ intBoundsValid = gFalse;
}
}
if (y0 < y1) {
if (y0 > yMin) {
yMin = y0;
- yMinI = splashFloor(yMin);
+ intBoundsValid = gFalse;
}
if (y1 < yMax) {
yMax = y1;
- yMaxI = splashCeil(yMax) - 1;
+ intBoundsValid = gFalse;
}
} else {
if (y1 > yMin) {
yMin = y1;
- yMinI = splashFloor(yMin);
+ intBoundsValid = gFalse;
}
if (y0 < yMax) {
yMax = y0;
- yMaxI = splashCeil(yMax) - 1;
+ intBoundsValid = gFalse;
}
}
return splashOk;
}
SplashError SplashClip::clipToPath(SplashPath *path, SplashCoord *matrix,
- SplashCoord flatness, GBool eo) {
+ SplashCoord flatness, GBool eoA) {
SplashXPath *xPath;
- int yMinAA, yMaxAA;
+ SplashCoord t;
xPath = new SplashXPath(path, matrix, flatness, gTrue);
// check for an empty path
if (xPath->length == 0) {
- xMax = xMin - 1;
- yMax = yMin - 1;
- xMaxI = splashCeil(xMax) - 1;
- yMaxI = splashCeil(yMax) - 1;
+ xMin = yMin = 1;
+ xMax = yMax = 0;
+ intBoundsValid = gFalse;
delete xPath;
+ return splashOk;
+ }
// check for a rectangle
- } else if (xPath->length == 4 &&
- ((xPath->segs[0].x0 == xPath->segs[0].x1 &&
- xPath->segs[0].x0 == xPath->segs[1].x0 &&
- xPath->segs[0].x0 == xPath->segs[3].x1 &&
- xPath->segs[2].x0 == xPath->segs[2].x1 &&
- xPath->segs[2].x0 == xPath->segs[1].x1 &&
- xPath->segs[2].x0 == xPath->segs[3].x0 &&
- xPath->segs[1].y0 == xPath->segs[1].y1 &&
- xPath->segs[1].y0 == xPath->segs[0].y1 &&
- xPath->segs[1].y0 == xPath->segs[2].y0 &&
- xPath->segs[3].y0 == xPath->segs[3].y1 &&
- xPath->segs[3].y0 == xPath->segs[0].y0 &&
- xPath->segs[3].y0 == xPath->segs[2].y1) ||
- (xPath->segs[0].y0 == xPath->segs[0].y1 &&
- xPath->segs[0].y0 == xPath->segs[1].y0 &&
- xPath->segs[0].y0 == xPath->segs[3].y1 &&
- xPath->segs[2].y0 == xPath->segs[2].y1 &&
- xPath->segs[2].y0 == xPath->segs[1].y1 &&
- xPath->segs[2].y0 == xPath->segs[3].y0 &&
- xPath->segs[1].x0 == xPath->segs[1].x1 &&
- xPath->segs[1].x0 == xPath->segs[0].x1 &&
- xPath->segs[1].x0 == xPath->segs[2].x0 &&
- xPath->segs[3].x0 == xPath->segs[3].x1 &&
- xPath->segs[3].x0 == xPath->segs[0].x0 &&
- xPath->segs[3].x0 == xPath->segs[2].x1))) {
- clipToRect(xPath->segs[0].x0, xPath->segs[0].y0,
- xPath->segs[2].x0, xPath->segs[2].y0);
+ if (xPath->length == 4 &&
+ xPath->segs[0].y0 == xPath->segs[0].y1 &&
+ xPath->segs[1].x0 == xPath->segs[1].x1 &&
+ xPath->segs[2].x0 == xPath->segs[2].x1 &&
+ xPath->segs[3].y0 == xPath->segs[3].y1) {
+ clipToRect(xPath->segs[1].x0, xPath->segs[0].y0,
+ xPath->segs[2].x0, xPath->segs[3].y0);
+ delete xPath;
+ return splashOk;
+ }
+ if (xPath->length == 4 &&
+ xPath->segs[0].x0 == xPath->segs[0].x1 &&
+ xPath->segs[1].y0 == xPath->segs[1].y1 &&
+ xPath->segs[2].x0 == xPath->segs[2].x1 &&
+ xPath->segs[3].y0 == xPath->segs[3].y1) {
+ clipToRect(xPath->segs[0].x0, xPath->segs[1].y0,
+ xPath->segs[2].x0, xPath->segs[3].y0);
delete xPath;
+ return splashOk;
+ }
+ if (xPath->length == 4 &&
+ xPath->segs[0].x0 == xPath->segs[0].x1 &&
+ xPath->segs[1].x0 == xPath->segs[1].x1 &&
+ xPath->segs[2].y0 == xPath->segs[2].y1 &&
+ xPath->segs[3].y0 == xPath->segs[3].y1) {
+ clipToRect(xPath->segs[0].x0, xPath->segs[2].y0,
+ xPath->segs[1].x0, xPath->segs[3].y0);
+ delete xPath;
+ return splashOk;
+ }
+ grow(1);
+ paths[length] = xPath;
+ eo[length] = (Guchar)eoA;
+ if ((t = xPath->getXMin()) > xMin) {
+ xMin = t;
+ }
+ if ((t = xPath->getYMin()) > yMin) {
+ yMin = t;
+ }
+ if ((t = xPath->getXMax() + 1) < xMax) {
+ xMax = t;
+ }
+ if ((t = xPath->getYMax() + 1) < yMax) {
+ yMax = t;
+ }
+ intBoundsValid = gFalse;
+ scanners[length] = new SplashXPathScanner(xPath, eoA, splashFloor(yMin),
+ splashCeil(yMax) - 1);
+ ++length;
+
+ return splashOk;
+}
+
+SplashClipResult SplashClip::testRect(int rectXMin, int rectYMin,
+ int rectXMax, int rectYMax,
+ GBool strokeAdjust) {
+ // In general, this function tests the rectangle:
+ // x = [rectXMin, rectXMax + 1) (note: coords are ints)
+ // y = [rectYMin, rectYMax + 1)
+ // against the clipping region:
+ // x = [xMin, xMax) (note: coords are fp)
+ // y = [yMin, yMax)
+
+ if (strokeAdjust && length == 0) {
+ // special case for stroke adjustment with a simple clipping
+ // rectangle -- the clipping region is:
+ // x = [xMinI, xMaxI + 1)
+ // y = [yMinI, yMaxI + 1)
+ updateIntBounds(strokeAdjust);
+ if (xMinI > xMaxI || yMinI > yMaxI) {
+ return splashClipAllOutside;
+ }
+ if (rectXMax + 1 <= xMinI ||
+ rectXMin >= xMaxI + 1 ||
+ rectYMax + 1 <= yMinI ||
+ rectYMin >= yMaxI + 1) {
+ return splashClipAllOutside;
+ }
+ if (rectXMin >= xMinI &&
+ rectXMax <= xMaxI &&
+ rectYMin >= yMinI &&
+ rectYMax <= yMaxI) {
+ return splashClipAllInside;
+ }
} else {
- grow(1);
- if (antialias) {
- xPath->aaScale();
+ if (xMin >= xMax || yMin >= yMax) {
+ return splashClipAllOutside;
}
- xPath->sort();
- paths[length] = xPath;
- flags[length] = eo ? splashClipEO : 0;
- if (antialias) {
- yMinAA = yMinI * splashAASize;
- yMaxAA = (yMaxI + 1) * splashAASize - 1;
- } else {
- yMinAA = yMinI;
- yMaxAA = yMaxI;
+ if ((SplashCoord)(rectXMax + 1) <= xMin ||
+ (SplashCoord)rectXMin >= xMax ||
+ (SplashCoord)(rectYMax + 1) <= yMin ||
+ (SplashCoord)rectYMin >= yMax) {
+ return splashClipAllOutside;
+ }
+ if (length == 0 &&
+ (SplashCoord)rectXMin >= xMin &&
+ (SplashCoord)(rectXMax + 1) <= xMax &&
+ (SplashCoord)rectYMin >= yMin &&
+ (SplashCoord)(rectYMax + 1) <= yMax) {
+ return splashClipAllInside;
}
- scanners[length] = new SplashXPathScanner(xPath, eo, yMinAA, yMaxAA);
- ++length;
}
-
- return splashOk;
+ return splashClipPartial;
}
-GBool SplashClip::test(int x, int y) {
- int i;
+void SplashClip::clipSpan(Guchar *line, int y, int x0, int x1,
+ GBool strokeAdjust) {
+ SplashCoord d;
+ int x0a, x1a, x, i;
- // check the rectangle
- if (x < xMinI || x > xMaxI || y < yMinI || y > yMaxI) {
- return gFalse;
+ updateIntBounds(strokeAdjust);
+
+ //--- clip to the integer rectangle
+
+ if (y < yMinI || y > yMaxI ||
+ x1 < xMinI || x0 > xMaxI) {
+ memset(line + x0, 0, x1 - x0 + 1);
+ return;
+ }
+
+ if (x0 > xMinI) {
+ x0a = x0;
+ } else {
+ x0a = xMinI;
+ memset(line + x0, 0, x0a - x0);
+ }
+
+ if (x1 < xMaxI) {
+ x1a = x1;
+ } else {
+ x1a = xMaxI;
+ memset(line + x1a + 1, 0, x1 - x1a);
+ }
+
+ if (x0a > x1a) {
+ return;
}
- // check the paths
- if (antialias) {
- for (i = 0; i < length; ++i) {
- if (!scanners[i]->test(x * splashAASize, y * splashAASize)) {
- return gFalse;
+ //--- clip to the floating point rectangle
+ // (if stroke adjustment is disabled)
+
+ if (!strokeAdjust) {
+
+ // clip left edge (xMin)
+ if (x0a == xMinI) {
+ d = (SplashCoord)(xMinI + 1) - xMin;
+ line[x0a] = (Guchar)(int)((SplashCoord)line[x0a] * d);
+ }
+
+ // clip right edge (xMax)
+ if (x1a == xMaxI) {
+ d = xMax - (SplashCoord)xMaxI;
+ line[x1a] = (Guchar)(int)((SplashCoord)line[x1a] * d);
+ }
+
+ // clip top edge (yMin)
+ if (y == yMinI) {
+ d = (SplashCoord)(yMinI + 1) - yMin;
+ for (x = x0a; x <= x1a; ++x) {
+ line[x] = (Guchar)(int)((SplashCoord)line[x] * d);
}
}
- } else {
- for (i = 0; i < length; ++i) {
- if (!scanners[i]->test(x, y)) {
- return gFalse;
+
+ // clip bottom edge (yMax)
+ if (y == yMaxI) {
+ d = yMax - (SplashCoord)yMaxI;
+ for (x = x0a; x <= x1a; ++x) {
+ line[x] = (Guchar)(int)((SplashCoord)line[x] * d);
}
}
}
- return gTrue;
-}
-
-SplashClipResult SplashClip::testRect(int rectXMin, int rectYMin,
- int rectXMax, int rectYMax) {
- // This tests the rectangle:
- // x = [rectXMin, rectXMax + 1) (note: rect coords are ints)
- // y = [rectYMin, rectYMax + 1)
- // against the clipping region:
- // x = [xMin, xMax) (note: clipping coords are fp)
- // y = [yMin, yMax)
- if ((SplashCoord)(rectXMax + 1) <= xMin || (SplashCoord)rectXMin >= xMax ||
- (SplashCoord)(rectYMax + 1) <= yMin || (SplashCoord)rectYMin >= yMax) {
- return splashClipAllOutside;
+ if (length == 0) {
+ return;
}
- if ((SplashCoord)rectXMin >= xMin && (SplashCoord)(rectXMax + 1) <= xMax &&
- (SplashCoord)rectYMin >= yMin && (SplashCoord)(rectYMax + 1) <= yMax &&
- length == 0) {
- return splashClipAllInside;
+
+ //--- clip to the paths
+
+ for (i = 0; i < length; ++i) {
+ scanners[i]->getSpan(buf, y, x0a, x1a);
+ for (x = x0a; x <= x1a; ++x) {
+ line[x] = mul255(line[x], buf[x]);
+ }
}
- return splashClipPartial;
}
-SplashClipResult SplashClip::testSpan(int spanXMin, int spanXMax, int spanY) {
- int i;
+GBool SplashClip::clipSpanBinary(Guchar *line, int y, int x0, int x1,
+ GBool strokeAdjust) {
+ int x0a, x1a, x0b, x1b, x, i;
+ Guchar any;
- // This tests the rectangle:
- // x = [spanXMin, spanXMax + 1) (note: span coords are ints)
- // y = [spanY, spanY + 1)
- // against the clipping region:
- // x = [xMin, xMax) (note: clipping coords are fp)
- // y = [yMin, yMax)
- if ((SplashCoord)(spanXMax + 1) <= xMin || (SplashCoord)spanXMin >= xMax ||
- (SplashCoord)(spanY + 1) <= yMin || (SplashCoord)spanY >= yMax) {
- return splashClipAllOutside;
- }
- if (!((SplashCoord)spanXMin >= xMin && (SplashCoord)(spanXMax + 1) <= xMax &&
- (SplashCoord)spanY >= yMin && (SplashCoord)(spanY + 1) <= yMax)) {
- return splashClipPartial;
- }
- if (antialias) {
- for (i = 0; i < length; ++i) {
- if (!scanners[i]->testSpan(spanXMin * splashAASize,
- spanXMax * splashAASize + (splashAASize - 1),
- spanY * splashAASize)) {
- return splashClipPartial;
- }
+ updateIntBounds(strokeAdjust);
+
+ if (y < yMinI || y > yMaxI ||
+ x1 < xMinI || x0 > xMaxI) {
+ if (x0 <= x1) {
+ memset(line + x0, 0, x1 - x0 + 1);
}
+ return gFalse;
+ }
+
+ if (x0 > xMinI) {
+ x0a = x0;
+ } else {
+ x0a = xMinI;
+ memset(line + x0, 0, x0a - x0);
+ }
+
+ if (x1 < xMaxI) {
+ x1a = x1;
} else {
- for (i = 0; i < length; ++i) {
- if (!scanners[i]->testSpan(spanXMin, spanXMax, spanY)) {
- return splashClipPartial;
+ x1a = xMaxI;
+ memset(line + x1a + 1, 0, x1 - x1a);
+ }
+
+ if (x0a > x1a) {
+ return gFalse;
+ }
+
+ if (length == 0) {
+ for (x = x0a; x <= x1a; ++x) {
+ if (line[x]) {
+ return gTrue;
}
}
+ return gFalse;
}
- return splashClipAllInside;
-}
-void SplashClip::clipAALine(SplashBitmap *aaBuf, int *x0, int *x1, int y) {
- int xx0, xx1, xx, yy, i;
- SplashColorPtr p;
-
- // zero out pixels with x < xMin
- xx0 = *x0 * splashAASize;
- xx1 = splashFloor(xMin * splashAASize);
- if (xx1 > aaBuf->getWidth()) {
- xx1 = aaBuf->getWidth();
- }
- if (xx0 < xx1) {
- xx0 &= ~7;
- for (yy = 0; yy < splashAASize; ++yy) {
- p = aaBuf->getDataPtr() + yy * aaBuf->getRowSize() + (xx0 >> 3);
- for (xx = xx0; xx + 7 < xx1; xx += 8) {
- *p++ = 0;
- }
- if (xx < xx1) {
- *p &= 0xff >> (xx1 & 7);
- }
+ any = 0;
+ for (i = 0; i < length; ++i) {
+ scanners[i]->getSpanBinary(buf, y, x0a, x1a);
+ for (x0b = x0a; x0b <= x1a && !buf[x0b]; ++x0b) ;
+ if (x0a < x0b) {
+ memset(line + x0a, 0, x0b - x0a);
}
- *x0 = splashFloor(xMin);
- }
-
- // zero out pixels with x > xMax
- xx0 = splashFloor(xMax * splashAASize) + 1;
- if (xx0 < 0) {
- xx0 = 0;
- }
- xx1 = (*x1 + 1) * splashAASize;
- if (xx0 < xx1) {
- for (yy = 0; yy < splashAASize; ++yy) {
- p = aaBuf->getDataPtr() + yy * aaBuf->getRowSize() + (xx0 >> 3);
- xx = xx0;
- if (xx & 7) {
- *p &= 0xff00 >> (xx & 7);
- xx = (xx & ~7) + 8;
- ++p;
- }
- for (; xx < xx1; xx += 8) {
- *p++ = 0;
- }
+ for (x1b = x1a; x1b >= x0b && !buf[x1b]; --x1b) ;
+ if (x1b < x1a) {
+ memset(line + x1b + 1, 0, x1a - x1b);
+ }
+ for (x = x0b; x <= x1b; ++x) {
+ line[x] &= buf[x];
+ any |= line[x];
}
- *x1 = splashFloor(xMax);
}
- // check the paths
- for (i = 0; i < length; ++i) {
- scanners[i]->clipAALine(aaBuf, x0, x1, y);
+ return any != 0;
+}
+
+int SplashClip::getXMinI(GBool strokeAdjust) {
+ updateIntBounds(strokeAdjust);
+ return xMinI;
+}
+
+int SplashClip::getXMaxI(GBool strokeAdjust) {
+ updateIntBounds(strokeAdjust);
+ return xMaxI;
+}
+
+int SplashClip::getYMinI(GBool strokeAdjust) {
+ updateIntBounds(strokeAdjust);
+ return yMinI;
+}
+
+int SplashClip::getYMaxI(GBool strokeAdjust) {
+ updateIntBounds(strokeAdjust);
+ return yMaxI;
+}
+
+void SplashClip::updateIntBounds(GBool strokeAdjust) {
+ if (intBoundsValid && strokeAdjust == intBoundsStrokeAdjust) {
+ return;
+ }
+ if (strokeAdjust && length == 0) {
+ splashStrokeAdjust(xMin, xMax, &xMinI, &xMaxI);
+ splashStrokeAdjust(yMin, yMax, &yMinI, &yMaxI);
+ } else {
+ xMinI = splashFloor(xMin);
+ yMinI = splashFloor(yMin);
+ xMaxI = splashCeil(xMax);
+ yMaxI = splashCeil(yMax);
+ }
+ if (xMinI < hardXMin) {
+ xMinI = hardXMin;
+ }
+ if (yMinI < hardYMin) {
+ yMinI = hardYMin;
+ }
+ if (xMaxI > hardXMax) {
+ xMaxI = hardXMax;
+ }
+ if (yMaxI > hardYMax) {
+ yMaxI = hardYMax;
}
+ // the clipping code uses [xMinI, xMaxI] instead of [xMinI, xMaxI)
+ --xMaxI;
+ --yMaxI;
+ intBoundsValid = gTrue;
+ intBoundsStrokeAdjust = strokeAdjust;
}
diff --git a/splash/SplashClip.h b/splash/SplashClip.h
index 6f580f8..4298622 100644
--- a/splash/SplashClip.h
+++ b/splash/SplashClip.h
@@ -2,6 +2,8 @@
//
// SplashClip.h
//
+// Copyright 2003-2013 Glyph & Cog, LLC
+//
//========================================================================
#ifndef SPLASHCLIP_H
@@ -37,9 +39,8 @@ class SplashClip {
public:
// Create a clip, for the given rectangle.
- SplashClip(SplashCoord x0, SplashCoord y0,
- SplashCoord x1, SplashCoord y1,
- GBool antialiasA);
+ SplashClip(int hardXMinA, int hardYMinA,
+ int hardXMaxA, int hardYMaxA);
// Copy a clip.
SplashClip *copy() { return new SplashClip(this); }
@@ -56,10 +57,7 @@ public:
// Interesect the clip with <path>.
SplashError clipToPath(SplashPath *path, SplashCoord *matrix,
- SplashCoord flatness, GBool eo);
-
- // Returns true if (<x>,<y>) is inside the clip.
- GBool test(int x, int y);
+ SplashCoord flatness, GBool eoA);
// Tests a rectangle against the clipping region. Returns one of:
// - splashClipAllInside if the entire rectangle is inside the
@@ -71,15 +69,19 @@ public:
// - splashClipPartial if the rectangle is part inside and part
// outside the clipping region
SplashClipResult testRect(int rectXMin, int rectYMin,
- int rectXMax, int rectYMax);
+ int rectXMax, int rectYMax,
+ GBool strokeAdjust);
- // Similar to testRect, but tests a horizontal span.
- SplashClipResult testSpan(int spanXMin, int spanXMax, int spanY);
+ // Clip a scan line. Modifies line[] by multiplying with clipping
+ // shape values for one scan line: ([x0, x1], y).
+ void clipSpan(Guchar *line, int y, int x0, int x1,
+ GBool strokeAdjust);
- // Clips an anti-aliased line by setting pixels to zero. On entry,
- // all non-zero pixels are between <x0> and <x1>. This function
- // will update <x0> and <x1>.
- void clipAALine(SplashBitmap *aaBuf, int *x0, int *x1, int y);
+ // Like clipSpan(), but uses the values 0 and 255 only.
+ // Returns true if there are any non-zero values in the result
+ // (i.e., returns false if the entire line is clipped out).
+ GBool clipSpanBinary(Guchar *line, int y, int x0, int x1,
+ GBool strokeAdjust);
// Get the rectangle part of the clip region.
SplashCoord getXMin() { return xMin; }
@@ -88,10 +90,10 @@ public:
SplashCoord getYMax() { return yMax; }
// Get the rectangle part of the clip region, in integer coordinates.
- int getXMinI() { return xMinI; }
- int getXMaxI() { return xMaxI; }
- int getYMinI() { return yMinI; }
- int getYMaxI() { return yMaxI; }
+ int getXMinI(GBool strokeAdjust);
+ int getXMaxI(GBool strokeAdjust);
+ int getYMinI(GBool strokeAdjust);
+ int getYMaxI(GBool strokeAdjust);
// Get the number of arbitrary paths used by the clip region.
int getNumPaths() { return length; }
@@ -100,14 +102,25 @@ private:
SplashClip(SplashClip *clip);
void grow(int nPaths);
+ void updateIntBounds(GBool strokeAdjust);
+
+ int hardXMin, hardYMin, // coordinates cannot fall outside of
+ hardXMax, hardYMax; // [hardXMin, hardXMax), [hardYMin, hardYMax)
+
+ SplashCoord xMin, yMin, // current clip bounding rectangle
+ xMax, yMax; // (these coordinates may be adjusted if
+ // stroke adjustment is enabled)
- GBool antialias;
- SplashCoord xMin, yMin, xMax, yMax;
int xMinI, yMinI, xMaxI, yMaxI;
+ GBool intBoundsValid; // true if xMinI, etc. are valid
+ GBool intBoundsStrokeAdjust; // value of strokeAdjust used to compute
+ // xMinI, etc.
+
SplashXPath **paths;
- Guchar *flags;
+ Guchar *eo;
SplashXPathScanner **scanners;
int length, size;
+ Guchar *buf;
};
#endif
diff --git a/splash/SplashErrorCodes.h b/splash/SplashErrorCodes.h
index 2a70d4b..ebe6091 100644
--- a/splash/SplashErrorCodes.h
+++ b/splash/SplashErrorCodes.h
@@ -2,6 +2,8 @@
//
// SplashErrorCodes.h
//
+// Copyright 2003-2013 Glyph & Cog, LLC
+//
//========================================================================
#ifndef SPLASHERRORCODES_H
diff --git a/splash/SplashFTFont.cc b/splash/SplashFTFont.cc
index 218f13e..6fc6b94 100644
--- a/splash/SplashFTFont.cc
+++ b/splash/SplashFTFont.cc
@@ -2,6 +2,8 @@
//
// SplashFTFont.cc
//
+// Copyright 2003-2013 Glyph & Cog, LLC
+//
//========================================================================
#include <aconf.h>
@@ -242,23 +244,24 @@ GBool SplashFTFont::makeGlyph(int c, int xFrac, int yFrac,
return gFalse;
}
- flags = 0;
- if (aa) {
- flags |= FT_LOAD_NO_BITMAP;
- }
+ // Set up the load flags:
+ // * disable bitmaps because they look ugly when scaled, rotated,
+ // etc.
+ // * disable autohinting because it can fail badly with font subsets
+ // that use invalid glyph names (the FreeType autohinter depends
+ // on the glyph name to figure out how to autohint the glyph)
+ // * but enable light autohinting for Type 1 fonts because regular
+ // hinting looks pretty bad, and the invalid glyph name issue
+ // seems to be very rare (Type 1 fonts are mostly used for
+ // substitution, in which case the full font is being used, which
+ // means we have the glyph names)
+ flags = FT_LOAD_NO_BITMAP;
if (ff->engine->flags & splashFTNoHinting) {
flags |= FT_LOAD_NO_HINTING;
- } else if (ff->trueType) {
- // FT2's autohinting doesn't always work very well (especially with
- // font subsets), so turn it off if anti-aliasing is enabled; if
- // anti-aliasing is disabled, this seems to be a tossup - some fonts
- // look better with hinting, some without, so leave hinting on
- if (aa) {
- flags |= FT_LOAD_NO_AUTOHINT;
- }
- } else if (ff->type1) {
- // Type 1 fonts seem to look better with 'light' hinting mode
+ } else if (ff->useLightHinting) {
flags |= FT_LOAD_TARGET_LIGHT;
+ } else {
+ flags |= FT_LOAD_NO_AUTOHINT;
}
if (FT_Load_Glyph(ff->face, gid, flags)) {
return gFalse;
diff --git a/splash/SplashFTFont.h b/splash/SplashFTFont.h
index 8e31d14..560b74c 100644
--- a/splash/SplashFTFont.h
+++ b/splash/SplashFTFont.h
@@ -2,6 +2,8 @@
//
// SplashFTFont.h
//
+// Copyright 2003-2013 Glyph & Cog, LLC
+//
//========================================================================
#ifndef SPLASHFTFONT_H
diff --git a/splash/SplashFTFontEngine.cc b/splash/SplashFTFontEngine.cc
index 9a4533a..3ba033c 100644
--- a/splash/SplashFTFontEngine.cc
+++ b/splash/SplashFTFontEngine.cc
@@ -2,6 +2,8 @@
//
// SplashFTFontEngine.cc
//
+// Copyright 2003-2013 Glyph & Cog, LLC
+//
//========================================================================
#include <aconf.h>
@@ -13,7 +15,7 @@
#endif
#include <stdio.h>
-#ifndef WIN32
+#ifndef _WIN32
# include <unistd.h>
#endif
#include "gmem.h"
@@ -23,6 +25,10 @@
#include "FoFiType1C.h"
#include "SplashFTFontFile.h"
#include "SplashFTFontEngine.h"
+#include FT_MODULE_H
+#ifdef FT_CFF_DRIVER_H
+# include FT_CFF_DRIVER_H
+#endif
#ifdef VMS
#if (__VMS_VER < 70000000)
@@ -36,6 +42,12 @@ static void fileWrite(void *stream, const char *data, int len) {
fwrite(data, 1, len, (FILE *)stream);
}
+#if LOAD_FONTS_FROM_MEM
+static void gstringWrite(void *stream, const char *data, int len) {
+ ((GString *)stream)->append(data, len);
+}
+#endif
+
//------------------------------------------------------------------------
// SplashFTFontEngine
//------------------------------------------------------------------------
@@ -68,29 +80,117 @@ SplashFTFontEngine::~SplashFTFontEngine() {
}
SplashFontFile *SplashFTFontEngine::loadType1Font(SplashFontFileID *idA,
+#if LOAD_FONTS_FROM_MEM
+ GString *fontBuf,
+#else
char *fileName,
GBool deleteFile,
+#endif
const char **enc) {
- return SplashFTFontFile::loadType1Font(this, idA, fileName, deleteFile, enc);
+ return SplashFTFontFile::loadType1Font(this, idA,
+#if LOAD_FONTS_FROM_MEM
+ fontBuf,
+#else
+ fileName, deleteFile,
+#endif
+ enc, gTrue);
}
SplashFontFile *SplashFTFontEngine::loadType1CFont(SplashFontFileID *idA,
+#if LOAD_FONTS_FROM_MEM
+ GString *fontBuf,
+#else
char *fileName,
GBool deleteFile,
+#endif
const char **enc) {
- return SplashFTFontFile::loadType1Font(this, idA, fileName, deleteFile, enc);
+ return SplashFTFontFile::loadType1Font(this, idA,
+#if LOAD_FONTS_FROM_MEM
+ fontBuf,
+#else
+ fileName, deleteFile,
+#endif
+ enc, gFalse);
}
SplashFontFile *SplashFTFontEngine::loadOpenTypeT1CFont(SplashFontFileID *idA,
+#if LOAD_FONTS_FROM_MEM
+ GString *fontBuf,
+#else
char *fileName,
GBool deleteFile,
+#endif
const char **enc) {
- return SplashFTFontFile::loadType1Font(this, idA, fileName, deleteFile, enc);
+ FoFiTrueType *ff;
+#if LOAD_FONTS_FROM_MEM
+ GString *fontBuf2;
+#else
+ GString *tmpFileName;
+ FILE *tmpFile;
+#endif
+ SplashFontFile *ret;
+
+#if LOAD_FONTS_FROM_MEM
+ if (!(ff = FoFiTrueType::make(fontBuf->getCString(), fontBuf->getLength(),
+ 0, gTrue))) {
+#else
+ if (!(ff = FoFiTrueType::load(fileName, 0, gTrue))) {
+#endif
+ return NULL;
+ }
+ if (ff->isHeadlessCFF()) {
+#if LOAD_FONTS_FROM_MEM
+ fontBuf2 = new GString();
+ ff->convertToType1(NULL, enc, gFalse, &gstringWrite, fontBuf2);
+ delete ff;
+ ret = SplashFTFontFile::loadType1Font(this, idA, fontBuf2, enc,
+ gFalse);
+ if (ret) {
+ delete fontBuf;
+ } else {
+ delete fontBuf2;
+ }
+#else
+ tmpFileName = NULL;
+ if (!openTempFile(&tmpFileName, &tmpFile, "wb", NULL)) {
+ delete ff;
+ return NULL;
+ }
+ ff->convertToType1(NULL, enc, gFalse, &fileWrite, tmpFile);
+ delete ff;
+ fclose(tmpFile);
+ ret = SplashFTFontFile::loadType1Font(this, idA, tmpFileName->getCString(),
+ gTrue, enc, gFalse);
+ if (ret) {
+ if (deleteFile) {
+ unlink(fileName);
+ }
+ } else {
+ unlink(tmpFileName->getCString());
+ }
+ delete tmpFileName;
+#endif
+ } else {
+ delete ff;
+ ret = SplashFTFontFile::loadType1Font(this, idA,
+#if LOAD_FONTS_FROM_MEM
+ fontBuf,
+#else
+ fileName, deleteFile,
+#endif
+ enc, gFalse);
+ }
+ return ret;
}
SplashFontFile *SplashFTFontEngine::loadCIDFont(SplashFontFileID *idA,
+#if LOAD_FONTS_FROM_MEM
+ GString *fontBuf
+#else
char *fileName,
- GBool deleteFile) {
+ GBool deleteFile
+#endif
+ ) {
FoFiType1C *ff;
int *cidToGIDMap;
int nCIDs;
@@ -100,14 +200,24 @@ SplashFontFile *SplashFTFontEngine::loadCIDFont(SplashFontFileID *idA,
if (useCIDs) {
cidToGIDMap = NULL;
nCIDs = 0;
+#if LOAD_FONTS_FROM_MEM
+ } else if ((ff = FoFiType1C::make(fontBuf->getCString(),
+ fontBuf->getLength()))) {
+#else
} else if ((ff = FoFiType1C::load(fileName))) {
+#endif
cidToGIDMap = ff->getCIDToGIDMap(&nCIDs);
delete ff;
} else {
cidToGIDMap = NULL;
nCIDs = 0;
}
- ret = SplashFTFontFile::loadCIDFont(this, idA, fileName, deleteFile,
+ ret = SplashFTFontFile::loadCIDFont(this, idA,
+#if LOAD_FONTS_FROM_MEM
+ fontBuf,
+#else
+ fileName, deleteFile,
+#endif
cidToGIDMap, nCIDs);
if (!ret) {
gfree(cidToGIDMap);
@@ -116,32 +226,90 @@ SplashFontFile *SplashFTFontEngine::loadCIDFont(SplashFontFileID *idA,
}
SplashFontFile *SplashFTFontEngine::loadOpenTypeCFFFont(SplashFontFileID *idA,
+#if LOAD_FONTS_FROM_MEM
+ GString *fontBuf,
+#else
char *fileName,
GBool deleteFile,
+#endif
int *codeToGID,
int codeToGIDLen) {
FoFiTrueType *ff;
- GBool isCID;
+#if LOAD_FONTS_FROM_MEM
+ GString *fontBuf2;
+#else
+ GString *tmpFileName;
+ FILE *tmpFile;
+#endif
+ char *cffStart;
+ int cffLength;
int *cidToGIDMap;
int nCIDs;
SplashFontFile *ret;
+#if LOAD_FONTS_FROM_MEM
+ if (!(ff = FoFiTrueType::make(fontBuf->getCString(), fontBuf->getLength(),
+ 0, gTrue))) {
+#else
+ if (!(ff = FoFiTrueType::load(fileName, 0, gTrue))) {
+#endif
+ return NULL;
+ }
cidToGIDMap = NULL;
nCIDs = 0;
- isCID = gFalse;
- if (!codeToGID) {
+ if (ff->isHeadlessCFF()) {
+ if (!ff->getCFFBlock(&cffStart, &cffLength)) {
+ return NULL;
+ }
+#if LOAD_FONTS_FROM_MEM
+ fontBuf2 = new GString(cffStart, cffLength);
+ if (!useCIDs) {
+ cidToGIDMap = ff->getCIDToGIDMap(&nCIDs);
+ }
+ ret = SplashFTFontFile::loadCIDFont(this, idA, fontBuf2,
+ cidToGIDMap, nCIDs);
+ if (ret) {
+ delete fontBuf;
+ } else {
+ delete fontBuf2;
+ }
+#else
+ tmpFileName = NULL;
+ if (!openTempFile(&tmpFileName, &tmpFile, "wb", NULL)) {
+ delete ff;
+ return NULL;
+ }
+ fwrite(cffStart, 1, cffLength, tmpFile);
+ fclose(tmpFile);
if (!useCIDs) {
- if ((ff = FoFiTrueType::load(fileName))) {
- if (ff->isOpenTypeCFF()) {
- cidToGIDMap = ff->getCIDToGIDMap(&nCIDs);
- }
- delete ff;
+ cidToGIDMap = ff->getCIDToGIDMap(&nCIDs);
+ }
+ ret = SplashFTFontFile::loadCIDFont(this, idA,
+ tmpFileName->getCString(), gTrue,
+ cidToGIDMap, nCIDs);
+ if (ret) {
+ if (deleteFile) {
+ unlink(fileName);
}
+ } else {
+ unlink(tmpFileName->getCString());
+ }
+ delete tmpFileName;
+#endif
+ } else {
+ if (!codeToGID && !useCIDs && ff->isOpenTypeCFF()) {
+ cidToGIDMap = ff->getCIDToGIDMap(&nCIDs);
}
+ ret = SplashFTFontFile::loadCIDFont(this, idA,
+#if LOAD_FONTS_FROM_MEM
+ fontBuf,
+#else
+ fileName, deleteFile,
+#endif
+ codeToGID ? codeToGID : cidToGIDMap,
+ codeToGID ? codeToGIDLen : nCIDs);
}
- ret = SplashFTFontFile::loadCIDFont(this, idA, fileName, deleteFile,
- codeToGID ? codeToGID : cidToGIDMap,
- codeToGID ? codeToGIDLen : nCIDs);
+ delete ff;
if (!ret) {
gfree(cidToGIDMap);
}
@@ -149,31 +317,59 @@ SplashFontFile *SplashFTFontEngine::loadOpenTypeCFFFont(SplashFontFileID *idA,
}
SplashFontFile *SplashFTFontEngine::loadTrueTypeFont(SplashFontFileID *idA,
+#if LOAD_FONTS_FROM_MEM
+ GString *fontBuf,
+#else
char *fileName,
- int fontNum,
GBool deleteFile,
+#endif
+ int fontNum,
int *codeToGID,
int codeToGIDLen) {
FoFiTrueType *ff;
+#if LOAD_FONTS_FROM_MEM
+ GString *fontBuf2;
+#else
GString *tmpFileName;
FILE *tmpFile;
+#endif
SplashFontFile *ret;
- //~ this should use fontNum to load the correct font
- if (!(ff = FoFiTrueType::load(fileName))) {
+#if LOAD_FONTS_FROM_MEM
+ if (!(ff = FoFiTrueType::make(fontBuf->getCString(), fontBuf->getLength(),
+ fontNum))) {
+#else
+ if (!(ff = FoFiTrueType::load(fileName, fontNum))) {
+#endif
return NULL;
}
+#if LOAD_FONTS_FROM_MEM
+ fontBuf2 = new GString;
+ ff->writeTTF(&gstringWrite, fontBuf2);
+#else
tmpFileName = NULL;
if (!openTempFile(&tmpFileName, &tmpFile, "wb", NULL)) {
delete ff;
return NULL;
}
ff->writeTTF(&fileWrite, tmpFile);
- delete ff;
fclose(tmpFile);
+#endif
+ delete ff;
ret = SplashFTFontFile::loadTrueTypeFont(this, idA,
- tmpFileName->getCString(), fontNum,
- gTrue, codeToGID, codeToGIDLen);
+#if LOAD_FONTS_FROM_MEM
+ fontBuf2,
+#else
+ tmpFileName->getCString(), gTrue,
+#endif
+ 0, codeToGID, codeToGIDLen);
+#if LOAD_FONTS_FROM_MEM
+ if (ret) {
+ delete fontBuf;
+ } else {
+ delete fontBuf2;
+ }
+#else
if (ret) {
if (deleteFile) {
unlink(fileName);
@@ -182,6 +378,7 @@ SplashFontFile *SplashFTFontEngine::loadTrueTypeFont(SplashFontFileID *idA,
unlink(tmpFileName->getCString());
}
delete tmpFileName;
+#endif
return ret;
}
diff --git a/splash/SplashFTFontEngine.h b/splash/SplashFTFontEngine.h
index 900bff2..37e8820 100644
--- a/splash/SplashFTFontEngine.h
+++ b/splash/SplashFTFontEngine.h
@@ -2,6 +2,8 @@
//
// SplashFTFontEngine.h
//
+// Copyright 2003-2013 Glyph & Cog, LLC
+//
//========================================================================
#ifndef SPLASHFTFONTENGINE_H
@@ -18,6 +20,7 @@
#include <ft2build.h>
#include FT_FREETYPE_H
#include "gtypes.h"
+class GString;
class SplashFontFile;
class SplashFontFileID;
@@ -34,19 +37,48 @@ public:
~SplashFTFontEngine();
// Load fonts.
- SplashFontFile *loadType1Font(SplashFontFileID *idA, char *fileName,
- GBool deleteFile, const char **enc);
- SplashFontFile *loadType1CFont(SplashFontFileID *idA, char *fileName,
- GBool deleteFile, const char **enc);
- SplashFontFile *loadOpenTypeT1CFont(SplashFontFileID *idA, char *fileName,
- GBool deleteFile, const char **enc);
- SplashFontFile *loadCIDFont(SplashFontFileID *idA, char *fileName,
- GBool deleteFile);
- SplashFontFile *loadOpenTypeCFFFont(SplashFontFileID *idA, char *fileName,
- GBool deleteFile,
+ SplashFontFile *loadType1Font(SplashFontFileID *idA,
+#if LOAD_FONTS_FROM_MEM
+ GString *fontBuf,
+#else
+ char *fileName, GBool deleteFile,
+#endif
+ const char **enc);
+ SplashFontFile *loadType1CFont(SplashFontFileID *idA,
+#if LOAD_FONTS_FROM_MEM
+ GString *fontBuf,
+#else
+ char *fileName, GBool deleteFile,
+#endif
+ const char **enc);
+ SplashFontFile *loadOpenTypeT1CFont(SplashFontFileID *idA,
+#if LOAD_FONTS_FROM_MEM
+ GString *fontBuf,
+#else
+ char *fileName, GBool deleteFile,
+#endif
+ const char **enc);
+ SplashFontFile *loadCIDFont(SplashFontFileID *idA,
+#if LOAD_FONTS_FROM_MEM
+ GString *fontBuf
+#else
+ char *fileName, GBool deleteFile
+#endif
+ );
+ SplashFontFile *loadOpenTypeCFFFont(SplashFontFileID *idA,
+#if LOAD_FONTS_FROM_MEM
+ GString *fontBuf,
+#else
+ char *fileName, GBool deleteFile,
+#endif
int *codeToGID, int codeToGIDLen);
- SplashFontFile *loadTrueTypeFont(SplashFontFileID *idA, char *fileName,
- int fontNum, GBool deleteFile,
+ SplashFontFile *loadTrueTypeFont(SplashFontFileID *idA,
+#if LOAD_FONTS_FROM_MEM
+ GString *fontBuf,
+#else
+ char *fileName, GBool deleteFile,
+#endif
+ int fontNum,
int *codeToGID, int codeToGIDLen);
private:
diff --git a/splash/SplashFTFontFile.cc b/splash/SplashFTFontFile.cc
index 5761117..5b01fcf 100644
--- a/splash/SplashFTFontFile.cc
+++ b/splash/SplashFTFontFile.cc
@@ -2,6 +2,8 @@
//
// SplashFTFontFile.cc
//
+// Copyright 2003-2013 Glyph & Cog, LLC
+//
//========================================================================
#include <aconf.h>
@@ -13,6 +15,7 @@
#endif
#include "gmem.h"
+#include "GString.h"
#include "SplashFTFontEngine.h"
#include "SplashFTFont.h"
#include "SplashFTFontFile.h"
@@ -23,15 +26,25 @@
SplashFontFile *SplashFTFontFile::loadType1Font(SplashFTFontEngine *engineA,
SplashFontFileID *idA,
+#if LOAD_FONTS_FROM_MEM
+ GString *fontBufA,
+#else
char *fileNameA,
GBool deleteFileA,
- const char **encA) {
+#endif
+ const char **encA,
+ GBool useLightHintingA) {
FT_Face faceA;
int *codeToGIDA;
const char *name;
int i;
+#if LOAD_FONTS_FROM_MEM
+ if (FT_New_Memory_Face(engineA->lib, (FT_Byte *)fontBufA->getCString(),
+ fontBufA->getLength(), 0, &faceA)) {
+#else
if (FT_New_Face(engineA->lib, fileNameA, 0, &faceA)) {
+#endif
return NULL;
}
codeToGIDA = (int *)gmallocn(256, sizeof(int));
@@ -42,59 +55,101 @@ SplashFontFile *SplashFTFontFile::loadType1Font(SplashFTFontEngine *engineA,
}
}
- return new SplashFTFontFile(engineA, idA, fileNameA, deleteFileA,
- faceA, codeToGIDA, 256, gFalse, gTrue);
+ return new SplashFTFontFile(engineA, idA,
+#if LOAD_FONTS_FROM_MEM
+ fontBufA,
+#else
+ fileNameA, deleteFileA,
+#endif
+ faceA, codeToGIDA, 256,
+ gFalse, useLightHintingA);
}
SplashFontFile *SplashFTFontFile::loadCIDFont(SplashFTFontEngine *engineA,
SplashFontFileID *idA,
+#if LOAD_FONTS_FROM_MEM
+ GString *fontBufA,
+#else
char *fileNameA,
GBool deleteFileA,
+#endif
int *codeToGIDA,
int codeToGIDLenA) {
FT_Face faceA;
+#if LOAD_FONTS_FROM_MEM
+ if (FT_New_Memory_Face(engineA->lib, (FT_Byte *)fontBufA->getCString(),
+ fontBufA->getLength(), 0, &faceA)) {
+#else
if (FT_New_Face(engineA->lib, fileNameA, 0, &faceA)) {
+#endif
return NULL;
}
- return new SplashFTFontFile(engineA, idA, fileNameA, deleteFileA,
+ return new SplashFTFontFile(engineA, idA,
+#if LOAD_FONTS_FROM_MEM
+ fontBufA,
+#else
+ fileNameA, deleteFileA,
+#endif
faceA, codeToGIDA, codeToGIDLenA,
gFalse, gFalse);
}
SplashFontFile *SplashFTFontFile::loadTrueTypeFont(SplashFTFontEngine *engineA,
SplashFontFileID *idA,
+#if LOAD_FONTS_FROM_MEM
+ GString *fontBufA,
+#else
char *fileNameA,
- int fontNum,
GBool deleteFileA,
+#endif
+ int fontNum,
int *codeToGIDA,
int codeToGIDLenA) {
FT_Face faceA;
+#if LOAD_FONTS_FROM_MEM
+ if (FT_New_Memory_Face(engineA->lib, (FT_Byte *)fontBufA->getCString(),
+ fontBufA->getLength(), fontNum, &faceA)) {
+#else
if (FT_New_Face(engineA->lib, fileNameA, fontNum, &faceA)) {
+#endif
return NULL;
}
- return new SplashFTFontFile(engineA, idA, fileNameA, deleteFileA,
+ return new SplashFTFontFile(engineA, idA,
+#if LOAD_FONTS_FROM_MEM
+ fontBufA,
+#else
+ fileNameA, deleteFileA,
+#endif
faceA, codeToGIDA, codeToGIDLenA,
gTrue, gFalse);
}
SplashFTFontFile::SplashFTFontFile(SplashFTFontEngine *engineA,
SplashFontFileID *idA,
+#if LOAD_FONTS_FROM_MEM
+ GString *fontBufA,
+#else
char *fileNameA, GBool deleteFileA,
+#endif
FT_Face faceA,
int *codeToGIDA, int codeToGIDLenA,
- GBool trueTypeA, GBool type1A):
+ GBool trueTypeA, GBool useLightHintingA):
+#if LOAD_FONTS_FROM_MEM
+ SplashFontFile(idA, fontBufA)
+#else
SplashFontFile(idA, fileNameA, deleteFileA)
+#endif
{
engine = engineA;
face = faceA;
codeToGID = codeToGIDA;
codeToGIDLen = codeToGIDLenA;
trueType = trueTypeA;
- type1 = type1A;
+ useLightHinting = useLightHintingA;
}
SplashFTFontFile::~SplashFTFontFile() {
diff --git a/splash/SplashFTFontFile.h b/splash/SplashFTFontFile.h
index 0f45e4f..21fa517 100644
--- a/splash/SplashFTFontFile.h
+++ b/splash/SplashFTFontFile.h
@@ -2,6 +2,8 @@
//
// SplashFTFontFile.h
//
+// Copyright 2003-2013 Glyph & Cog, LLC
+//
//========================================================================
#ifndef SPLASHFTFONTFILE_H
@@ -30,17 +32,31 @@ class SplashFTFontFile: public SplashFontFile {
public:
static SplashFontFile *loadType1Font(SplashFTFontEngine *engineA,
- SplashFontFileID *idA, char *fileNameA,
- GBool deleteFileA, const char **encA);
+ SplashFontFileID *idA,
+#if LOAD_FONTS_FROM_MEM
+ GString *fontBufA,
+#else
+ char *fileNameA, GBool deleteFileA,
+#endif
+ const char **encA,
+ GBool useLightHintingA);
static SplashFontFile *loadCIDFont(SplashFTFontEngine *engineA,
- SplashFontFileID *idA, char *fileNameA,
- GBool deleteFileA,
+ SplashFontFileID *idA,
+#if LOAD_FONTS_FROM_MEM
+ GString *fontBufA,
+#else
+ char *fileNameA, GBool deleteFileA,
+#endif
int *codeToGIDA, int codeToGIDLenA);
static SplashFontFile *loadTrueTypeFont(SplashFTFontEngine *engineA,
SplashFontFileID *idA,
+#if LOAD_FONTS_FROM_MEM
+ GString *fontBufA,
+#else
char *fileNameA,
- int fontNum,
GBool deleteFileA,
+#endif
+ int fontNum,
int *codeToGIDA,
int codeToGIDLenA);
@@ -55,17 +71,21 @@ private:
SplashFTFontFile(SplashFTFontEngine *engineA,
SplashFontFileID *idA,
+#if LOAD_FONTS_FROM_MEM
+ GString *fontBufA,
+#else
char *fileNameA, GBool deleteFileA,
+#endif
FT_Face faceA,
int *codeToGIDA, int codeToGIDLenA,
- GBool trueTypeA, GBool type1A);
+ GBool trueTypeA, GBool useLightHintingA);
SplashFTFontEngine *engine;
FT_Face face;
int *codeToGID;
int codeToGIDLen;
GBool trueType;
- GBool type1;
+ GBool useLightHinting;
friend class SplashFTFont;
};
diff --git a/splash/SplashFont.cc b/splash/SplashFont.cc
index 6ab2ecf..37a3200 100644
--- a/splash/SplashFont.cc
+++ b/splash/SplashFont.cc
@@ -2,6 +2,8 @@
//
// SplashFont.cc
//
+// Copyright 2003-2013 Glyph & Cog, LLC
+//
//========================================================================
#include <aconf.h>
diff --git a/splash/SplashFont.h b/splash/SplashFont.h
index 60a2db7..3d15112 100644
--- a/splash/SplashFont.h
+++ b/splash/SplashFont.h
@@ -2,6 +2,8 @@
//
// SplashFont.h
//
+// Copyright 2003-2013 Glyph & Cog, LLC
+//
//========================================================================
#ifndef SPLASHFONT_H
diff --git a/splash/SplashFontEngine.cc b/splash/SplashFontEngine.cc
index 5f5ad46..d4673a7 100644
--- a/splash/SplashFontEngine.cc
+++ b/splash/SplashFontEngine.cc
@@ -2,6 +2,8 @@
//
// SplashFontEngine.cc
//
+// Copyright 2003-2013 Glyph & Cog, LLC
+//
//========================================================================
#include <aconf.h>
@@ -10,19 +12,14 @@
#pragma implementation
#endif
-#if HAVE_T1LIB_H
-#include <t1lib.h>
-#endif
-
#include <stdlib.h>
#include <stdio.h>
-#ifndef WIN32
+#ifndef _WIN32
# include <unistd.h>
#endif
#include "gmem.h"
#include "GString.h"
#include "SplashMath.h"
-#include "SplashT1FontEngine.h"
#include "SplashFTFontEngine.h"
#include "SplashFontFile.h"
#include "SplashFontFileID.h"
@@ -40,9 +37,6 @@ extern "C" int unlink(char *filename);
//------------------------------------------------------------------------
SplashFontEngine::SplashFontEngine(
-#if HAVE_T1LIB_H
- GBool enableT1lib,
-#endif
#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H
GBool enableFreeType,
Guint freeTypeFlags,
@@ -54,13 +48,6 @@ SplashFontEngine::SplashFontEngine(
fontCache[i] = NULL;
}
-#if HAVE_T1LIB_H
- if (enableT1lib) {
- t1Engine = SplashT1FontEngine::init(aa);
- } else {
- t1Engine = NULL;
- }
-#endif
#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H
if (enableFreeType) {
ftEngine = SplashFTFontEngine::init(aa, freeTypeFlags);
@@ -79,11 +66,6 @@ SplashFontEngine::~SplashFontEngine() {
}
}
-#if HAVE_T1LIB_H
- if (t1Engine) {
- delete t1Engine;
- }
-#endif
#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H
if (ftEngine) {
delete ftEngine;
@@ -107,24 +89,29 @@ SplashFontFile *SplashFontEngine::getFontFile(SplashFontFileID *id) {
}
SplashFontFile *SplashFontEngine::loadType1Font(SplashFontFileID *idA,
+#if LOAD_FONTS_FROM_MEM
+ GString *fontBuf,
+#else
char *fileName,
GBool deleteFile,
+#endif
const char **enc) {
SplashFontFile *fontFile;
fontFile = NULL;
-#if HAVE_T1LIB_H
- if (!fontFile && t1Engine) {
- fontFile = t1Engine->loadType1Font(idA, fileName, deleteFile, enc);
- }
-#endif
#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H
if (!fontFile && ftEngine) {
- fontFile = ftEngine->loadType1Font(idA, fileName, deleteFile, enc);
+ fontFile = ftEngine->loadType1Font(idA,
+#if LOAD_FONTS_FROM_MEM
+ fontBuf,
+#else
+ fileName, deleteFile,
+#endif
+ enc);
}
#endif
-#ifndef WIN32
+#if !LOAD_FONTS_FROM_MEM && !defined(_WIN32)
// delete the (temporary) font file -- with Unix hard link
// semantics, this will remove the last link; otherwise it will
// return an error, leaving the file to be deleted later (if
@@ -138,24 +125,29 @@ SplashFontFile *SplashFontEngine::loadType1Font(SplashFontFileID *idA,
}
SplashFontFile *SplashFontEngine::loadType1CFont(SplashFontFileID *idA,
+#if LOAD_FONTS_FROM_MEM
+ GString *fontBuf,
+#else
char *fileName,
GBool deleteFile,
+#endif
const char **enc) {
SplashFontFile *fontFile;
fontFile = NULL;
-#if HAVE_T1LIB_H
- if (!fontFile && t1Engine) {
- fontFile = t1Engine->loadType1CFont(idA, fileName, deleteFile, enc);
- }
-#endif
#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H
if (!fontFile && ftEngine) {
- fontFile = ftEngine->loadType1CFont(idA, fileName, deleteFile, enc);
+ fontFile = ftEngine->loadType1CFont(idA,
+#if LOAD_FONTS_FROM_MEM
+ fontBuf,
+#else
+ fileName, deleteFile,
+#endif
+ enc);
}
#endif
-#ifndef WIN32
+#if !LOAD_FONTS_FROM_MEM && !defined(_WIN32)
// delete the (temporary) font file -- with Unix hard link
// semantics, this will remove the last link; otherwise it will
// return an error, leaving the file to be deleted later (if
@@ -169,19 +161,29 @@ SplashFontFile *SplashFontEngine::loadType1CFont(SplashFontFileID *idA,
}
SplashFontFile *SplashFontEngine::loadOpenTypeT1CFont(SplashFontFileID *idA,
+#if LOAD_FONTS_FROM_MEM
+ GString *fontBuf,
+#else
char *fileName,
GBool deleteFile,
+#endif
const char **enc) {
SplashFontFile *fontFile;
fontFile = NULL;
#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H
if (!fontFile && ftEngine) {
- fontFile = ftEngine->loadOpenTypeT1CFont(idA, fileName, deleteFile, enc);
+ fontFile = ftEngine->loadOpenTypeT1CFont(idA,
+#if LOAD_FONTS_FROM_MEM
+ fontBuf,
+#else
+ fileName, deleteFile,
+#endif
+ enc);
}
#endif
-#ifndef WIN32
+#if !LOAD_FONTS_FROM_MEM && !defined(_WIN32)
// delete the (temporary) font file -- with Unix hard link
// semantics, this will remove the last link; otherwise it will
// return an error, leaving the file to be deleted later (if
@@ -195,18 +197,29 @@ SplashFontFile *SplashFontEngine::loadOpenTypeT1CFont(SplashFontFileID *idA,
}
SplashFontFile *SplashFontEngine::loadCIDFont(SplashFontFileID *idA,
+#if LOAD_FONTS_FROM_MEM
+ GString *fontBuf
+#else
char *fileName,
- GBool deleteFile) {
+ GBool deleteFile
+#endif
+ ) {
SplashFontFile *fontFile;
fontFile = NULL;
#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H
if (!fontFile && ftEngine) {
- fontFile = ftEngine->loadCIDFont(idA, fileName, deleteFile);
+ fontFile = ftEngine->loadCIDFont(idA,
+#if LOAD_FONTS_FROM_MEM
+ fontBuf
+#else
+ fileName, deleteFile
+#endif
+ );
}
#endif
-#ifndef WIN32
+#if !LOAD_FONTS_FROM_MEM && !defined(_WIN32)
// delete the (temporary) font file -- with Unix hard link
// semantics, this will remove the last link; otherwise it will
// return an error, leaving the file to be deleted later (if
@@ -220,8 +233,12 @@ SplashFontFile *SplashFontEngine::loadCIDFont(SplashFontFileID *idA,
}
SplashFontFile *SplashFontEngine::loadOpenTypeCFFFont(SplashFontFileID *idA,
+#if LOAD_FONTS_FROM_MEM
+ GString *fontBuf,
+#else
char *fileName,
GBool deleteFile,
+#endif
int *codeToGID,
int codeToGIDLen) {
SplashFontFile *fontFile;
@@ -229,12 +246,17 @@ SplashFontFile *SplashFontEngine::loadOpenTypeCFFFont(SplashFontFileID *idA,
fontFile = NULL;
#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H
if (!fontFile && ftEngine) {
- fontFile = ftEngine->loadOpenTypeCFFFont(idA, fileName, deleteFile,
+ fontFile = ftEngine->loadOpenTypeCFFFont(idA,
+#if LOAD_FONTS_FROM_MEM
+ fontBuf,
+#else
+ fileName, deleteFile,
+#endif
codeToGID, codeToGIDLen);
}
#endif
-#ifndef WIN32
+#if !LOAD_FONTS_FROM_MEM && !defined(_WIN32)
// delete the (temporary) font file -- with Unix hard link
// semantics, this will remove the last link; otherwise it will
// return an error, leaving the file to be deleted later (if
@@ -248,9 +270,13 @@ SplashFontFile *SplashFontEngine::loadOpenTypeCFFFont(SplashFontFileID *idA,
}
SplashFontFile *SplashFontEngine::loadTrueTypeFont(SplashFontFileID *idA,
+#if LOAD_FONTS_FROM_MEM
+ GString *fontBuf,
+#else
char *fileName,
- int fontNum,
GBool deleteFile,
+#endif
+ int fontNum,
int *codeToGID,
int codeToGIDLen,
char *fontName) {
@@ -259,8 +285,13 @@ SplashFontFile *SplashFontEngine::loadTrueTypeFont(SplashFontFileID *idA,
fontFile = NULL;
#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H
if (!fontFile && ftEngine) {
- fontFile = ftEngine->loadTrueTypeFont(idA, fileName, fontNum, deleteFile,
- codeToGID, codeToGIDLen);
+ fontFile = ftEngine->loadTrueTypeFont(idA,
+#if LOAD_FONTS_FROM_MEM
+ fontBuf,
+#else
+ fileName, deleteFile,
+#endif
+ fontNum, codeToGID, codeToGIDLen);
}
#endif
@@ -268,7 +299,7 @@ SplashFontFile *SplashFontEngine::loadTrueTypeFont(SplashFontFileID *idA,
gfree(codeToGID);
}
-#ifndef WIN32
+#if !LOAD_FONTS_FROM_MEM && !defined(_WIN32)
// delete the (temporary) font file -- with Unix hard link
// semantics, this will remove the last link; otherwise it will
// return an error, leaving the file to be deleted later (if
diff --git a/splash/SplashFontEngine.h b/splash/SplashFontEngine.h
index a6d0e58..43eb6d3 100644
--- a/splash/SplashFontEngine.h
+++ b/splash/SplashFontEngine.h
@@ -2,6 +2,8 @@
//
// SplashFontEngine.h
//
+// Copyright 2003-2013 Glyph & Cog, LLC
+//
//========================================================================
#ifndef SPLASHFONTENGINE_H
@@ -14,8 +16,8 @@
#endif
#include "gtypes.h"
+class GString;
-class SplashT1FontEngine;
class SplashFTFontEngine;
class SplashDTFontEngine;
class SplashDT4FontEngine;
@@ -40,9 +42,6 @@ public:
// Create a font engine.
SplashFontEngine(
-#if HAVE_T1LIB_H
- GBool enableT1lib,
-#endif
#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H
GBool enableFreeType,
Guint freeTypeFlags,
@@ -56,19 +55,48 @@ public:
SplashFontFile *getFontFile(SplashFontFileID *id);
// Load fonts - these create new SplashFontFile objects.
- SplashFontFile *loadType1Font(SplashFontFileID *idA, char *fileName,
- GBool deleteFile, const char **enc);
- SplashFontFile *loadType1CFont(SplashFontFileID *idA, char *fileName,
- GBool deleteFile, const char **enc);
- SplashFontFile *loadOpenTypeT1CFont(SplashFontFileID *idA, char *fileName,
- GBool deleteFile, const char **enc);
- SplashFontFile *loadCIDFont(SplashFontFileID *idA, char *fileName,
- GBool deleteFile);
- SplashFontFile *loadOpenTypeCFFFont(SplashFontFileID *idA, char *fileName,
- GBool deleteFile,
+ SplashFontFile *loadType1Font(SplashFontFileID *idA,
+#if LOAD_FONTS_FROM_MEM
+ GString *fontBuf,
+#else
+ char *fileName, GBool deleteFile,
+#endif
+ const char **enc);
+ SplashFontFile *loadType1CFont(SplashFontFileID *idA,
+#if LOAD_FONTS_FROM_MEM
+ GString *fontBuf,
+#else
+ char *fileName, GBool deleteFile,
+#endif
+ const char **enc);
+ SplashFontFile *loadOpenTypeT1CFont(SplashFontFileID *idA,
+#if LOAD_FONTS_FROM_MEM
+ GString *fontBuf,
+#else
+ char *fileName, GBool deleteFile,
+#endif
+ const char **enc);
+ SplashFontFile *loadCIDFont(SplashFontFileID *idA,
+#if LOAD_FONTS_FROM_MEM
+ GString *fontBuf
+#else
+ char *fileName, GBool deleteFile
+#endif
+ );
+ SplashFontFile *loadOpenTypeCFFFont(SplashFontFileID *idA,
+#if LOAD_FONTS_FROM_MEM
+ GString *fontBuf,
+#else
+ char *fileName, GBool deleteFile,
+#endif
int *codeToGID, int codeToGIDLen);
- SplashFontFile *loadTrueTypeFont(SplashFontFileID *idA, char *fileName,
- int fontNum, GBool deleteFile,
+ SplashFontFile *loadTrueTypeFont(SplashFontFileID *idA,
+#if LOAD_FONTS_FROM_MEM
+ GString *fontBuf,
+#else
+ char *fileName, GBool deleteFile,
+#endif
+ int fontNum,
int *codeToGID, int codeToGIDLen,
char *fontName);
@@ -87,9 +115,6 @@ private:
SplashFont *fontCache[splashFontCacheSize];
-#if HAVE_T1LIB_H
- SplashT1FontEngine *t1Engine;
-#endif
#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H
SplashFTFontEngine *ftEngine;
#endif
diff --git a/splash/SplashFontFile.cc b/splash/SplashFontFile.cc
index acbc12a..d0e36a2 100644
--- a/splash/SplashFontFile.cc
+++ b/splash/SplashFontFile.cc
@@ -2,6 +2,8 @@
//
// SplashFontFile.cc
//
+// Copyright 2003-2013 Glyph & Cog, LLC
+//
//========================================================================
#include <aconf.h>
@@ -11,7 +13,7 @@
#endif
#include <stdio.h>
-#ifndef WIN32
+#ifndef _WIN32
# include <unistd.h>
#endif
#include "GString.h"
@@ -28,19 +30,32 @@ extern "C" int unlink(char *filename);
// SplashFontFile
//------------------------------------------------------------------------
-SplashFontFile::SplashFontFile(SplashFontFileID *idA, char *fileNameA,
- GBool deleteFileA) {
+SplashFontFile::SplashFontFile(SplashFontFileID *idA,
+#if LOAD_FONTS_FROM_MEM
+ GString *fontBufA
+#else
+ char *fileNameA, GBool deleteFileA
+#endif
+ ) {
id = idA;
+#if LOAD_FONTS_FROM_MEM
+ fontBuf = fontBufA;
+#else
fileName = new GString(fileNameA);
deleteFile = deleteFileA;
+#endif
refCnt = 0;
}
SplashFontFile::~SplashFontFile() {
+#if LOAD_FONTS_FROM_MEM
+ delete fontBuf;
+#else
if (deleteFile) {
unlink(fileName->getCString());
}
delete fileName;
+#endif
delete id;
}
diff --git a/splash/SplashFontFile.h b/splash/SplashFontFile.h
index 9f89312..5f53ece 100644
--- a/splash/SplashFontFile.h
+++ b/splash/SplashFontFile.h
@@ -2,6 +2,8 @@
//
// SplashFontFile.h
//
+// Copyright 2003-2013 Glyph & Cog, LLC
+//
//========================================================================
#ifndef SPLASHFONTFILE_H
@@ -46,12 +48,21 @@ public:
protected:
- SplashFontFile(SplashFontFileID *idA, char *fileNameA,
- GBool deleteFileA);
+ SplashFontFile(SplashFontFileID *idA,
+#if LOAD_FONTS_FROM_MEM
+ GString *fontBufA
+#else
+ char *fileNameA, GBool deleteFileA
+#endif
+ );
SplashFontFileID *id;
+#if LOAD_FONTS_FROM_MEM
+ GString *fontBuf;
+#else
GString *fileName;
GBool deleteFile;
+#endif
int refCnt;
friend class SplashFontEngine;
diff --git a/splash/SplashFontFileID.cc b/splash/SplashFontFileID.cc
index af37cb2..3274847 100644
--- a/splash/SplashFontFileID.cc
+++ b/splash/SplashFontFileID.cc
@@ -2,6 +2,8 @@
//
// SplashFontFileID.cc
//
+// Copyright 2003-2013 Glyph & Cog, LLC
+//
//========================================================================
#include <aconf.h>
diff --git a/splash/SplashFontFileID.h b/splash/SplashFontFileID.h
index bed11d3..384018a 100644
--- a/splash/SplashFontFileID.h
+++ b/splash/SplashFontFileID.h
@@ -2,6 +2,8 @@
//
// SplashFontFileID.h
//
+// Copyright 2003-2013 Glyph & Cog, LLC
+//
//========================================================================
#ifndef SPLASHFONTFILEID_H
diff --git a/splash/SplashGlyphBitmap.h b/splash/SplashGlyphBitmap.h
index 044ba4a..d375b3c 100644
--- a/splash/SplashGlyphBitmap.h
+++ b/splash/SplashGlyphBitmap.h
@@ -2,6 +2,8 @@
//
// SplashGlyphBitmap.h
//
+// Copyright 2003-2013 Glyph & Cog, LLC
+//
//========================================================================
#ifndef SPLASHGLYPHBITMAP_H
diff --git a/splash/SplashMath.h b/splash/SplashMath.h
index 3b82e7a..4b7ab1f 100644
--- a/splash/SplashMath.h
+++ b/splash/SplashMath.h
@@ -2,6 +2,8 @@
//
// SplashMath.h
//
+// Copyright 2003-2013 Glyph & Cog, LLC
+//
//========================================================================
#ifndef SPLASHMATH_H
@@ -35,19 +37,18 @@ static inline int splashFloor(SplashCoord x) {
Gushort oldCW, newCW, t;
int result;
- __asm__ volatile("fldl %4\n"
- "fnstcw %0\n"
+ __asm__ volatile("fnstcw %0\n"
"movw %0, %3\n"
"andw $0xf3ff, %3\n"
"orw $0x0400, %3\n"
"movw %3, %1\n" // round down
"fldcw %1\n"
- "fistpl %2\n"
+ "fistl %2\n"
"fldcw %0\n"
: "=m" (oldCW), "=m" (newCW), "=m" (result), "=r" (t)
- : "m" (x));
+ : "t" (x));
return result;
-#elif defined(WIN32) && defined(_M_IX86)
+#elif defined(_WIN32) && defined(_M_IX86)
// floor() and (int)() are implemented separately, which results
// in changing the FPCW multiple times - so we optimize it with
// some inline assembly
@@ -81,19 +82,18 @@ static inline int splashCeil(SplashCoord x) {
Gushort oldCW, newCW, t;
int result;
- __asm__ volatile("fldl %4\n"
- "fnstcw %0\n"
+ __asm__ volatile("fnstcw %0\n"
"movw %0, %3\n"
"andw $0xf3ff, %3\n"
"orw $0x0800, %3\n"
"movw %3, %1\n" // round up
"fldcw %1\n"
- "fistpl %2\n"
+ "fistl %2\n"
"fldcw %0\n"
: "=m" (oldCW), "=m" (newCW), "=m" (result), "=r" (t)
- : "m" (x));
+ : "t" (x));
return result;
-#elif defined(WIN32) && defined(_M_IX86)
+#elif defined(_WIN32) && defined(_M_IX86)
// ceil() and (int)() are implemented separately, which results
// in changing the FPCW multiple times - so we optimize it with
// some inline assembly
@@ -128,19 +128,18 @@ static inline int splashRound(SplashCoord x) {
int result;
x += 0.5;
- __asm__ volatile("fldl %4\n"
- "fnstcw %0\n"
+ __asm__ volatile("fnstcw %0\n"
"movw %0, %3\n"
"andw $0xf3ff, %3\n"
"orw $0x0400, %3\n"
"movw %3, %1\n" // round down
"fldcw %1\n"
- "fistpl %2\n"
+ "fistl %2\n"
"fldcw %0\n"
: "=m" (oldCW), "=m" (newCW), "=m" (result), "=r" (t)
- : "m" (x));
+ : "t" (x));
return result;
-#elif defined(WIN32) && defined(_M_IX86)
+#elif defined(_WIN32) && defined(_M_IX86)
// this could use round-to-nearest mode and avoid the "+0.5",
// but that produces slightly different results (because i+0.5
// sometimes rounds up and sometimes down using the even rule)
@@ -223,4 +222,68 @@ static inline GBool splashCheckDet(SplashCoord m11, SplashCoord m12,
#endif
}
+// Perform stroke adjustment on a SplashCoord range [xMin, xMax),
+// resulting in an int range [*xMinI, *xMaxI).
+//
+// There are several options:
+//
+// 1. Round both edge coordinates.
+// Pro: adjacent strokes/fills line up without any gaps or
+// overlaps
+// Con: lines with the same original floating point width can
+// end up with different integer widths, e.g.:
+// xMin = 10.1 xMax = 11.3 (width = 1.2)
+// --> xMinI = 10 xMaxI = 11 (width = 1)
+// but
+// xMin = 10.4 xMax = 11.6 (width = 1.2)
+// --> xMinI = 10 xMaxI = 12 (width = 2)
+//
+// 2. Round the min coordinate; add the ceiling of the width.
+// Pro: lines with the same original floating point width will
+// always end up with the same integer width
+// Con: adjacent strokes/fills can have overlaps (which is
+// problematic with transparency)
+// (This could use floor on the min coordinate, instead of
+// rounding, with similar results.)
+// (If the width is rounded instead of using ceiling, the results
+// Are similar, except that adjacent strokes/fills can have gaps
+// as well as overlaps.)
+//
+// 3. Use floor on the min coordinate and ceiling on the max
+// coordinate.
+// Pro: lines always end up at least as wide as the original
+// floating point width
+// Con: adjacent strokes/fills can have overlaps, and lines with
+// the same original floating point width can end up with
+// different integer widths; the integer width can be more
+// than one pixel wider than the original width, e.g.:
+// xMin = 10.9 xMax = 12.1 (width = 1.2)
+// --> xMinI = 10 xMaxI = 13 (width = 3)
+// but
+// xMin = 10.1 xMax = 11.3 (width = 1.2)
+// --> xMinI = 10 xMaxI = 12 (width = 2)
+static inline void splashStrokeAdjust(SplashCoord xMin, SplashCoord xMax,
+ int *xMinI, int *xMaxI) {
+ int x0, x1;
+
+ // NB: enable exactly one of these.
+#if 1 // 1. Round both edge coordinates.
+ x0 = splashRound(xMin);
+ x1 = splashRound(xMax);
+#endif
+#if 0 // 2. Round the min coordinate; add the ceiling of the width.
+ x0 = splashRound(xMin);
+ x1 = x0 + splashCeil(xMax - xMin);
+#endif
+#if 0 // 3. Use floor on the min coord and ceiling on the max coord.
+ x0 = splashFloor(xMin);
+ x1 = splashCeil(xMax);
+#endif
+ if (x1 == x0) {
+ ++x1;
+ }
+ *xMinI = x0;
+ *xMaxI = x1;
+}
+
#endif
diff --git a/splash/SplashPath.cc b/splash/SplashPath.cc
index b4249ed..4ee8be0 100644
--- a/splash/SplashPath.cc
+++ b/splash/SplashPath.cc
@@ -2,6 +2,8 @@
//
// SplashPath.cc
//
+// Copyright 2003-2013 Glyph & Cog, LLC
+//
//========================================================================
#include <aconf.h>
@@ -53,6 +55,7 @@ SplashPath::SplashPath(SplashPath *path) {
memcpy(hints, path->hints, hintsLength * sizeof(SplashPathHint));
} else {
hints = NULL;
+ hintsLength = hintsSize = 0;
}
}
diff --git a/splash/SplashPath.h b/splash/SplashPath.h
index aae51f2..a871530 100644
--- a/splash/SplashPath.h
+++ b/splash/SplashPath.h
@@ -2,6 +2,8 @@
//
// SplashPath.h
//
+// Copyright 2003-2013 Glyph & Cog, LLC
+//
//========================================================================
#ifndef SPLASHPATH_H
@@ -94,7 +96,7 @@ public:
// Get the points on the path.
int getLength() { return length; }
- void getPoint(int i, double *x, double *y, Guchar *f)
+ void getPoint(int i, SplashCoord *x, SplashCoord *y, Guchar *f)
{ *x = pts[i].x; *y = pts[i].y; *f = flags[i]; }
// Get the current point.
diff --git a/splash/SplashPattern.cc b/splash/SplashPattern.cc
index b77658e..6ca4fb2 100644
--- a/splash/SplashPattern.cc
+++ b/splash/SplashPattern.cc
@@ -2,6 +2,8 @@
//
// SplashPattern.cc
//
+// Copyright 2003-2013 Glyph & Cog, LLC
+//
//========================================================================
#include <aconf.h>
diff --git a/splash/SplashPattern.h b/splash/SplashPattern.h
index 0a02e9c..01207bf 100644
--- a/splash/SplashPattern.h
+++ b/splash/SplashPattern.h
@@ -2,6 +2,8 @@
//
// SplashPattern.h
//
+// Copyright 2003-2013 Glyph & Cog, LLC
+//
//========================================================================
#ifndef SPLASHPATTERN_H
diff --git a/splash/SplashScreen.cc b/splash/SplashScreen.cc
index f717173..68a762f 100644
--- a/splash/SplashScreen.cc
+++ b/splash/SplashScreen.cc
@@ -2,6 +2,8 @@
//
// SplashScreen.cc
//
+// Copyright 2003-2013 Glyph & Cog, LLC
+//
//========================================================================
#include <aconf.h>
diff --git a/splash/SplashScreen.h b/splash/SplashScreen.h
index 708c37f..4e9767b 100644
--- a/splash/SplashScreen.h
+++ b/splash/SplashScreen.h
@@ -2,6 +2,8 @@
//
// SplashScreen.h
//
+// Copyright 2003-2013 Glyph & Cog, LLC
+//
//========================================================================
#ifndef SPLASHSCREEN_H
diff --git a/splash/SplashState.cc b/splash/SplashState.cc
index e6dde61..09c1949 100644
--- a/splash/SplashState.cc
+++ b/splash/SplashState.cc
@@ -2,6 +2,8 @@
//
// SplashState.cc
//
+// Copyright 2003-2013 Glyph & Cog, LLC
+//
//========================================================================
#include <aconf.h>
@@ -45,7 +47,7 @@ SplashState::SplashState(int width, int height, GBool vectorAntialias,
blendFunc = NULL;
strokeAlpha = 1;
fillAlpha = 1;
- lineWidth = 0;
+ lineWidth = 1;
lineCap = splashLineCapButt;
lineJoin = splashLineJoinMiter;
miterLimit = 10;
@@ -54,10 +56,12 @@ SplashState::SplashState(int width, int height, GBool vectorAntialias,
lineDashLength = 0;
lineDashPhase = 0;
strokeAdjust = gFalse;
- clip = new SplashClip(0, 0, width, height, vectorAntialias);
+ clip = new SplashClip(0, 0, width, height);
+ clipIsShared = gFalse;
softMask = NULL;
deleteSoftMask = gFalse;
inNonIsolatedGroup = gFalse;
+ inKnockoutGroup = gFalse;
for (i = 0; i < 256; ++i) {
rgbTransferR[i] = (Guchar)i;
rgbTransferG[i] = (Guchar)i;
@@ -87,7 +91,7 @@ SplashState::SplashState(int width, int height, GBool vectorAntialias,
blendFunc = NULL;
strokeAlpha = 1;
fillAlpha = 1;
- lineWidth = 0;
+ lineWidth = 1;
lineCap = splashLineCapButt;
lineJoin = splashLineJoinMiter;
miterLimit = 10;
@@ -96,10 +100,12 @@ SplashState::SplashState(int width, int height, GBool vectorAntialias,
lineDashLength = 0;
lineDashPhase = 0;
strokeAdjust = gFalse;
- clip = new SplashClip(0, 0, width, height, vectorAntialias);
+ clip = new SplashClip(0, 0, width, height);
+ clipIsShared = gFalse;
softMask = NULL;
deleteSoftMask = gFalse;
inNonIsolatedGroup = gFalse;
+ inKnockoutGroup = gFalse;
for (i = 0; i < 256; ++i) {
rgbTransferR[i] = (Guchar)i;
rgbTransferG[i] = (Guchar)i;
@@ -137,10 +143,12 @@ SplashState::SplashState(SplashState *state) {
}
lineDashPhase = state->lineDashPhase;
strokeAdjust = state->strokeAdjust;
- clip = state->clip->copy();
+ clip = state->clip;
+ clipIsShared = gTrue;
softMask = state->softMask;
deleteSoftMask = gFalse;
inNonIsolatedGroup = state->inNonIsolatedGroup;
+ inKnockoutGroup = state->inKnockoutGroup;
memcpy(rgbTransferR, state->rgbTransferR, 256);
memcpy(rgbTransferG, state->rgbTransferG, 256);
memcpy(rgbTransferB, state->rgbTransferB, 256);
@@ -158,7 +166,9 @@ SplashState::~SplashState() {
delete fillPattern;
delete screen;
gfree(lineDash);
- delete clip;
+ if (!clipIsShared) {
+ delete clip;
+ }
if (deleteSoftMask && softMask) {
delete softMask;
}
@@ -192,6 +202,32 @@ void SplashState::setLineDash(SplashCoord *lineDashA, int lineDashLengthA,
lineDashPhase = lineDashPhaseA;
}
+void SplashState::clipResetToRect(SplashCoord x0, SplashCoord y0,
+ SplashCoord x1, SplashCoord y1) {
+ if (clipIsShared) {
+ clip = clip->copy();
+ clipIsShared = gFalse;
+ }
+ clip->resetToRect(x0, y0, x1, y1);
+}
+
+SplashError SplashState::clipToRect(SplashCoord x0, SplashCoord y0,
+ SplashCoord x1, SplashCoord y1) {
+ if (clipIsShared) {
+ clip = clip->copy();
+ clipIsShared = gFalse;
+ }
+ return clip->clipToRect(x0, y0, x1, y1);
+}
+
+SplashError SplashState::clipToPath(SplashPath *path, GBool eo) {
+ if (clipIsShared) {
+ clip = clip->copy();
+ clipIsShared = gFalse;
+ }
+ return clip->clipToPath(path, matrix, flatness, eo);
+}
+
void SplashState::setSoftMask(SplashBitmap *softMaskA) {
if (deleteSoftMask) {
delete softMask;
diff --git a/splash/SplashState.h b/splash/SplashState.h
index 0d1b6c5..fe773a5 100644
--- a/splash/SplashState.h
+++ b/splash/SplashState.h
@@ -2,6 +2,8 @@
//
// SplashState.h
//
+// Copyright 2003-2013 Glyph & Cog, LLC
+//
//========================================================================
#ifndef SPLASHSTATE_H
@@ -19,6 +21,7 @@ class SplashPattern;
class SplashScreen;
class SplashClip;
class SplashBitmap;
+class SplashPath;
//------------------------------------------------------------------------
// line cap values
@@ -67,6 +70,12 @@ public:
void setLineDash(SplashCoord *lineDashA, int lineDashLengthA,
SplashCoord lineDashPhaseA);
+ void clipResetToRect(SplashCoord x0, SplashCoord y0,
+ SplashCoord x1, SplashCoord y1);
+ SplashError clipToRect(SplashCoord x0, SplashCoord y0,
+ SplashCoord x1, SplashCoord y1);
+ SplashError clipToPath(SplashPath *path, GBool eo);
+
// Set the soft mask bitmap.
void setSoftMask(SplashBitmap *softMaskA);
@@ -94,9 +103,11 @@ private:
SplashCoord lineDashPhase;
GBool strokeAdjust;
SplashClip *clip;
+ GBool clipIsShared;
SplashBitmap *softMask;
GBool deleteSoftMask;
GBool inNonIsolatedGroup;
+ GBool inKnockoutGroup;
Guchar rgbTransferR[256],
rgbTransferG[256],
rgbTransferB[256];
diff --git a/splash/SplashT1Font.cc b/splash/SplashT1Font.cc
deleted file mode 100644
index 703aacf..0000000
--- a/splash/SplashT1Font.cc
+++ /dev/null
@@ -1,290 +0,0 @@
-//========================================================================
-//
-// SplashT1Font.cc
-//
-//========================================================================
-
-#include <aconf.h>
-
-#if HAVE_T1LIB_H
-
-#ifdef USE_GCC_PRAGMAS
-#pragma implementation
-#endif
-
-#include <stdlib.h>
-#include <t1lib.h>
-#include "gmem.h"
-#include "SplashMath.h"
-#include "SplashGlyphBitmap.h"
-#include "SplashPath.h"
-#include "SplashT1FontEngine.h"
-#include "SplashT1FontFile.h"
-#include "SplashT1Font.h"
-
-//------------------------------------------------------------------------
-
-static Guchar bitReverse[256] = {
- 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
- 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
- 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
- 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
- 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
- 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
- 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
- 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
- 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
- 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
- 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
- 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
- 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
- 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
- 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
- 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
- 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
- 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
- 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
- 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
- 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
- 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
- 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
- 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
- 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
- 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
- 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
- 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
- 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
- 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
- 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
- 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff
-};
-
-//------------------------------------------------------------------------
-// SplashT1Font
-//------------------------------------------------------------------------
-
-SplashT1Font::SplashT1Font(SplashT1FontFile *fontFileA, SplashCoord *matA,
- SplashCoord *textMatA):
- SplashFont(fontFileA, matA, textMatA, fontFileA->engine->aa)
-{
- T1_TMATRIX matrix;
- BBox bbox;
- SplashCoord bbx0, bby0, bbx1, bby1;
- int x, y;
-
- t1libID = T1_CopyFont(fontFileA->t1libID);
- outlineID = -1;
-
- // compute font size
- size = (float)splashDist(0, 0, mat[2], mat[3]);
-
- // transform the four corners of the font bounding box -- the min
- // and max values form the bounding box of the transformed font
- bbox = T1_GetFontBBox(t1libID);
- bbx0 = 0.001 * bbox.llx;
- bby0 = 0.001 * bbox.lly;
- bbx1 = 0.001 * bbox.urx;
- bby1 = 0.001 * bbox.ury;
- // some fonts are completely broken, so we fake it (with values
- // large enough that most glyphs should fit)
- if (bbx0 == 0 && bby0 == 0 && bbx1 == 0 && bby1 == 0) {
- bbx0 = bby0 = -0.5;
- bbx1 = bby1 = 1.5;
- }
- x = (int)(mat[0] * bbx0 + mat[2] * bby0);
- xMin = xMax = x;
- y = (int)(mat[1] * bbx0 + mat[3] * bby0);
- yMin = yMax = y;
- x = (int)(mat[0] * bbx0 + mat[2] * bby1);
- if (x < xMin) {
- xMin = x;
- } else if (x > xMax) {
- xMax = x;
- }
- y = (int)(mat[1] * bbx0 + mat[3] * bby1);
- if (y < yMin) {
- yMin = y;
- } else if (y > yMax) {
- yMax = y;
- }
- x = (int)(mat[0] * bbx1 + mat[2] * bby0);
- if (x < xMin) {
- xMin = x;
- } else if (x > xMax) {
- xMax = x;
- }
- y = (int)(mat[1] * bbx1 + mat[3] * bby0);
- if (y < yMin) {
- yMin = y;
- } else if (y > yMax) {
- yMax = y;
- }
- x = (int)(mat[0] * bbx1 + mat[2] * bby1);
- if (x < xMin) {
- xMin = x;
- } else if (x > xMax) {
- xMax = x;
- }
- y = (int)(mat[1] * bbx1 + mat[3] * bby1);
- if (y < yMin) {
- yMin = y;
- } else if (y > yMax) {
- yMax = y;
- }
- // This is a kludge: some buggy PDF generators embed fonts with
- // zero bounding boxes.
- if (xMax == xMin) {
- xMin = 0;
- xMax = (int)size;
- }
- if (yMax == yMin) {
- yMin = 0;
- yMax = (int)(1.2 * size);
- }
- // Another kludge: an unusually large xMin or yMin coordinate is
- // probably wrong.
- if (xMin > 0) {
- xMin = 0;
- }
- if (yMin > 0) {
- yMin = 0;
- }
- // Another kludge: t1lib doesn't correctly handle fonts with
- // real (non-integer) bounding box coordinates.
- if (xMax - xMin > 5000) {
- xMin = 0;
- xMax = (int)size;
- }
- if (yMax - yMin > 5000) {
- yMin = 0;
- yMax = (int)(1.2 * size);
- }
-
- // transform the font
- matrix.cxx = (double)mat[0] / size;
- matrix.cxy = (double)mat[1] / size;
- matrix.cyx = (double)mat[2] / size;
- matrix.cyy = (double)mat[3] / size;
- T1_TransformFont(t1libID, &matrix);
-}
-
-SplashT1Font::~SplashT1Font() {
- T1_DeleteFont(t1libID);
- if (outlineID >= 0) {
- T1_DeleteFont(outlineID);
- }
-}
-
-GBool SplashT1Font::getGlyph(int c, int xFrac, int yFrac,
- SplashGlyphBitmap *bitmap) {
- return SplashFont::getGlyph(c, 0, 0, bitmap);
-}
-
-GBool SplashT1Font::makeGlyph(int c, int xFrac, int yFrac,
- SplashGlyphBitmap *bitmap) {
- GLYPH *glyph;
- int n, i;
-
- if (aa) {
- glyph = T1_AASetChar(t1libID, c, size, NULL);
- } else {
- glyph = T1_SetChar(t1libID, c, size, NULL);
- }
- if (!glyph) {
- return gFalse;
- }
-
- bitmap->x = -glyph->metrics.leftSideBearing;
- bitmap->y = glyph->metrics.ascent;
- bitmap->w = glyph->metrics.rightSideBearing - glyph->metrics.leftSideBearing;
- bitmap->h = glyph->metrics.ascent - glyph->metrics.descent;
- bitmap->aa = aa;
- if (aa) {
- bitmap->data = (Guchar *)glyph->bits;
- bitmap->freeData = gFalse;
- } else {
- n = bitmap->h * ((bitmap->w + 7) >> 3);
- bitmap->data = (Guchar *)gmalloc(n);
- for (i = 0; i < n; ++i) {
- bitmap->data[i] = bitReverse[glyph->bits[i] & 0xff];
- }
- bitmap->freeData = gTrue;
- }
-
- return gTrue;
-}
-
-SplashPath *SplashT1Font::getGlyphPath(int c) {
- T1_TMATRIX matrix;
- SplashPath *path;
- T1_OUTLINE *outline;
- T1_PATHSEGMENT *seg;
- T1_BEZIERSEGMENT *bez;
- int x, y, x1, y1;
- GBool needClose;
-
- if (outlineID < 0) {
- outlineID = T1_CopyFont(((SplashT1FontFile *)fontFile)->t1libID);
- outlineSize = (float)splashDist(0, 0, textMat[2], textMat[3]);
- matrix.cxx = (double)textMat[0] / outlineSize;
- matrix.cxy = (double)textMat[1] / outlineSize;
- matrix.cyx = (double)textMat[2] / outlineSize;
- matrix.cyy = (double)textMat[3] / outlineSize;
- // t1lib doesn't seem to handle small sizes correctly here, so set
- // the size to 1000, and scale the resulting coordinates later
- outlineMul = (float)(outlineSize / 65536000.0);
- outlineSize = 1000;
- T1_TransformFont(outlineID, &matrix);
- }
-
- path = new SplashPath();
- if ((outline = T1_GetCharOutline(outlineID, c, outlineSize, NULL))) {
- // NB: t1lib uses integer coordinates here; we keep a running
- // (x,y) total as integers, so that the final point in the path is
- // exactly the same as the first point, thus avoiding weird
- // mitered join glitches
- x = y = 0;
- needClose = gFalse;
- for (seg = outline; seg; seg = seg->link) {
- switch (seg->type) {
- case T1_PATHTYPE_MOVE:
- if (needClose) {
- path->close();
- needClose = gFalse;
- }
- x += seg->dest.x;
- y += seg->dest.y;
- path->moveTo(outlineMul * x, -outlineMul * y);
- break;
- case T1_PATHTYPE_LINE:
- x += seg->dest.x;
- y += seg->dest.y;
- path->lineTo(outlineMul * x, -outlineMul * y);
- needClose = gTrue;
- break;
- case T1_PATHTYPE_BEZIER:
- bez = (T1_BEZIERSEGMENT *)seg;
- x1 = x + bez->dest.x;
- y1 = y + bez->dest.y;
- path->curveTo(outlineMul * (x + bez->B.x),
- -outlineMul * (y + bez->B.y),
- outlineMul * (x + bez->C.x),
- -outlineMul * (y + bez->C.y),
- outlineMul * x1,
- -outlineMul * y1);
- x = x1;
- y = y1;
- needClose = gTrue;
- break;
- }
- }
- if (needClose) {
- path->close();
- }
- T1_FreeOutline(outline);
- }
-
- return path;
-}
-
-#endif // HAVE_T1LIB_H
diff --git a/splash/SplashT1Font.h b/splash/SplashT1Font.h
deleted file mode 100644
index 8ea74de..0000000
--- a/splash/SplashT1Font.h
+++ /dev/null
@@ -1,57 +0,0 @@
-//========================================================================
-//
-// SplashT1Font.h
-//
-//========================================================================
-
-#ifndef SPLASHT1FONT_H
-#define SPLASHT1FONT_H
-
-#include <aconf.h>
-
-#if HAVE_T1LIB_H
-
-#ifdef USE_GCC_PRAGMAS
-#pragma interface
-#endif
-
-#include "SplashFont.h"
-
-class SplashT1FontFile;
-
-//------------------------------------------------------------------------
-// SplashT1Font
-//------------------------------------------------------------------------
-
-class SplashT1Font: public SplashFont {
-public:
-
- SplashT1Font(SplashT1FontFile *fontFileA, SplashCoord *matA,
- SplashCoord *textMatA);
-
- virtual ~SplashT1Font();
-
- // Munge xFrac and yFrac before calling SplashFont::getGlyph.
- virtual GBool getGlyph(int c, int xFrac, int yFrac,
- SplashGlyphBitmap *bitmap);
-
- // Rasterize a glyph. The <xFrac> and <yFrac> values are the same
- // as described for getGlyph.
- virtual GBool makeGlyph(int c, int xFrac, int yFrac,
- SplashGlyphBitmap *bitmap);
-
- // Return the path for a glyph.
- virtual SplashPath *getGlyphPath(int c);
-
-private:
-
- int t1libID; // t1lib font ID
- int outlineID; // t1lib font ID for glyph outlines
- float size;
- float outlineSize; // size for glyph outlines
- float outlineMul;
-};
-
-#endif // HAVE_T1LIB_H
-
-#endif
diff --git a/splash/SplashT1FontEngine.cc b/splash/SplashT1FontEngine.cc
deleted file mode 100644
index 277e2fc..0000000
--- a/splash/SplashT1FontEngine.cc
+++ /dev/null
@@ -1,124 +0,0 @@
-//========================================================================
-//
-// SplashT1FontEngine.cc
-//
-//========================================================================
-
-#include <aconf.h>
-
-#if HAVE_T1LIB_H
-
-#ifdef USE_GCC_PRAGMAS
-#pragma implementation
-#endif
-
-#include <stdlib.h>
-#include <stdio.h>
-#ifndef WIN32
-# include <unistd.h>
-#endif
-#include <t1lib.h>
-#include "GString.h"
-#include "gfile.h"
-#include "FoFiType1C.h"
-#include "SplashT1FontFile.h"
-#include "SplashT1FontEngine.h"
-
-#ifdef VMS
-#if (__VMS_VER < 70000000)
-extern "C" int unlink(char *filename);
-#endif
-#endif
-
-//------------------------------------------------------------------------
-
-int SplashT1FontEngine::t1libInitCount = 0;
-
-//------------------------------------------------------------------------
-
-static void fileWrite(void *stream, const char *data, int len) {
- fwrite(data, 1, len, (FILE *)stream);
-}
-
-//------------------------------------------------------------------------
-// SplashT1FontEngine
-//------------------------------------------------------------------------
-
-SplashT1FontEngine::SplashT1FontEngine(GBool aaA) {
- aa = aaA;
-}
-
-SplashT1FontEngine *SplashT1FontEngine::init(GBool aaA) {
- // grayVals[i] = round(i * 255 / 16)
- static unsigned long grayVals[17] = {
- 0, 16, 32, 48, 64, 80, 96, 112, 128, 143, 159, 175, 191, 207, 223, 239, 255
- };
-
- //~ for multithreading: need a mutex here
- if (t1libInitCount == 0) {
- T1_SetBitmapPad(8);
- if (!T1_InitLib(NO_LOGFILE | IGNORE_CONFIGFILE | IGNORE_FONTDATABASE |
- T1_NO_AFM)) {
- return NULL;
- }
- if (aaA) {
- T1_AASetBitsPerPixel(8);
- T1_AASetLevel(T1_AA_HIGH);
- T1_AAHSetGrayValues(grayVals);
- } else {
- T1_AANSetGrayValues(0, 1);
- }
- }
- ++t1libInitCount;
-
- return new SplashT1FontEngine(aaA);
-}
-
-SplashT1FontEngine::~SplashT1FontEngine() {
- //~ for multithreading: need a mutex here
- if (--t1libInitCount == 0) {
- T1_CloseLib();
- }
-}
-
-SplashFontFile *SplashT1FontEngine::loadType1Font(SplashFontFileID *idA,
- char *fileName,
- GBool deleteFile,
- const char **enc) {
- return SplashT1FontFile::loadType1Font(this, idA, fileName, deleteFile, enc);
-}
-
-SplashFontFile *SplashT1FontEngine::loadType1CFont(SplashFontFileID *idA,
- char *fileName,
- GBool deleteFile,
- const char **enc) {
- FoFiType1C *ff;
- GString *tmpFileName;
- FILE *tmpFile;
- SplashFontFile *ret;
-
- if (!(ff = FoFiType1C::load(fileName))) {
- return NULL;
- }
- tmpFileName = NULL;
- if (!openTempFile(&tmpFileName, &tmpFile, "wb", NULL)) {
- delete ff;
- return NULL;
- }
- ff->convertToType1(NULL, NULL, gTrue, &fileWrite, tmpFile);
- delete ff;
- fclose(tmpFile);
- ret = SplashT1FontFile::loadType1Font(this, idA, tmpFileName->getCString(),
- gTrue, enc);
- if (ret) {
- if (deleteFile) {
- unlink(fileName);
- }
- } else {
- unlink(tmpFileName->getCString());
- }
- delete tmpFileName;
- return ret;
-}
-
-#endif // HAVE_T1LIB_H
diff --git a/splash/SplashT1FontEngine.h b/splash/SplashT1FontEngine.h
deleted file mode 100644
index 8942b85..0000000
--- a/splash/SplashT1FontEngine.h
+++ /dev/null
@@ -1,53 +0,0 @@
-//========================================================================
-//
-// SplashT1FontEngine.h
-//
-//========================================================================
-
-#ifndef SPLASHT1FONTENGINE_H
-#define SPLASHT1FONTENGINE_H
-
-#include <aconf.h>
-
-#if HAVE_T1LIB_H
-
-#ifdef USE_GCC_PRAGMAS
-#pragma interface
-#endif
-
-#include "gtypes.h"
-
-class SplashFontFile;
-class SplashFontFileID;
-
-//------------------------------------------------------------------------
-// SplashT1FontEngine
-//------------------------------------------------------------------------
-
-class SplashT1FontEngine {
-public:
-
- static SplashT1FontEngine *init(GBool aaA);
-
- ~SplashT1FontEngine();
-
- // Load fonts.
- SplashFontFile *loadType1Font(SplashFontFileID *idA, char *fileName,
- GBool deleteFile, const char **enc);
- SplashFontFile *loadType1CFont(SplashFontFileID *idA, char *fileName,
- GBool deleteFile, const char **enc);
-
-private:
-
- SplashT1FontEngine(GBool aaA);
-
- static int t1libInitCount;
- GBool aa;
-
- friend class SplashT1FontFile;
- friend class SplashT1Font;
-};
-
-#endif // HAVE_T1LIB_H
-
-#endif
diff --git a/splash/SplashT1FontFile.cc b/splash/SplashT1FontFile.cc
deleted file mode 100644
index 8cec742..0000000
--- a/splash/SplashT1FontFile.cc
+++ /dev/null
@@ -1,98 +0,0 @@
-//========================================================================
-//
-// SplashT1FontFile.cc
-//
-//========================================================================
-
-#include <aconf.h>
-
-#if HAVE_T1LIB_H
-
-#ifdef USE_GCC_PRAGMAS
-#pragma implementation
-#endif
-
-#include <string.h>
-#include <t1lib.h>
-#include "gmem.h"
-#include "SplashT1FontEngine.h"
-#include "SplashT1Font.h"
-#include "SplashT1FontFile.h"
-
-//------------------------------------------------------------------------
-// SplashT1FontFile
-//------------------------------------------------------------------------
-
-SplashFontFile *SplashT1FontFile::loadType1Font(SplashT1FontEngine *engineA,
- SplashFontFileID *idA,
- char *fileNameA,
- GBool deleteFileA,
- const char **encA) {
- int t1libIDA;
- const char **encTmp;
- char *encStrTmp;
- int encStrSize;
- char *encPtr;
- int i;
-
- // load the font file
- if ((t1libIDA = T1_AddFont(fileNameA)) < 0) {
- return NULL;
- }
- T1_LoadFont(t1libIDA);
-
- // reencode it
- encStrSize = 0;
- for (i = 0; i < 256; ++i) {
- if (encA[i]) {
- encStrSize += strlen(encA[i]) + 1;
- }
- }
- encTmp = (const char **)gmallocn(257, sizeof(char *));
- encStrTmp = (char *)gmallocn(encStrSize, sizeof(char));
- encPtr = encStrTmp;
- for (i = 0; i < 256; ++i) {
- if (encA[i]) {
- strcpy(encPtr, encA[i]);
- encTmp[i] = encPtr;
- encPtr += strlen(encPtr) + 1;
- } else {
- encTmp[i] = ".notdef";
- }
- }
- encTmp[256] = "custom";
- T1_ReencodeFont(t1libIDA, (char **)encTmp);
-
- return new SplashT1FontFile(engineA, idA, fileNameA, deleteFileA,
- t1libIDA, encTmp, encStrTmp);
-}
-
-SplashT1FontFile::SplashT1FontFile(SplashT1FontEngine *engineA,
- SplashFontFileID *idA,
- char *fileNameA, GBool deleteFileA,
- int t1libIDA, const char **encA,
- char *encStrA):
- SplashFontFile(idA, fileNameA, deleteFileA)
-{
- engine = engineA;
- t1libID = t1libIDA;
- enc = encA;
- encStr = encStrA;
-}
-
-SplashT1FontFile::~SplashT1FontFile() {
- gfree(encStr);
- gfree(enc);
- T1_DeleteFont(t1libID);
-}
-
-SplashFont *SplashT1FontFile::makeFont(SplashCoord *mat,
- SplashCoord *textMat) {
- SplashFont *font;
-
- font = new SplashT1Font(this, mat, textMat);
- font->initCache();
- return font;
-}
-
-#endif // HAVE_T1LIB_H
diff --git a/splash/SplashT1FontFile.h b/splash/SplashT1FontFile.h
deleted file mode 100644
index 57de84d..0000000
--- a/splash/SplashT1FontFile.h
+++ /dev/null
@@ -1,58 +0,0 @@
-//========================================================================
-//
-// SplashT1FontFile.h
-//
-//========================================================================
-
-#ifndef SPLASHT1FONTFILE_H
-#define SPLASHT1FONTFILE_H
-
-#include <aconf.h>
-
-#if HAVE_T1LIB_H
-
-#ifdef USE_GCC_PRAGMAS
-#pragma interface
-#endif
-
-#include "SplashFontFile.h"
-
-class SplashT1FontEngine;
-
-//------------------------------------------------------------------------
-// SplashT1FontFile
-//------------------------------------------------------------------------
-
-class SplashT1FontFile: public SplashFontFile {
-public:
-
- static SplashFontFile *loadType1Font(SplashT1FontEngine *engineA,
- SplashFontFileID *idA,
- char *fileNameA, GBool deleteFileA,
- const char **encA);
-
- virtual ~SplashT1FontFile();
-
- // Create a new SplashT1Font, i.e., a scaled instance of this font
- // file.
- virtual SplashFont *makeFont(SplashCoord *mat,
- SplashCoord *textMat);
-
-private:
-
- SplashT1FontFile(SplashT1FontEngine *engineA,
- SplashFontFileID *idA,
- char *fileNameA, GBool deleteFileA,
- int t1libIDA, const char **encA, char *encStrA);
-
- SplashT1FontEngine *engine;
- int t1libID; // t1lib font ID
- const char **enc;
- char *encStr;
-
- friend class SplashT1Font;
-};
-
-#endif // HAVE_T1LIB_H
-
-#endif
diff --git a/splash/SplashTypes.h b/splash/SplashTypes.h
index 6eb2607..240cb6f 100644
--- a/splash/SplashTypes.h
+++ b/splash/SplashTypes.h
@@ -2,6 +2,8 @@
//
// SplashTypes.h
//
+// Copyright 2003-2013 Glyph & Cog, LLC
+//
//========================================================================
#ifndef SPLASHTYPES_H
diff --git a/splash/SplashXPath.cc b/splash/SplashXPath.cc
index 6ed2f4b..a159988 100644
--- a/splash/SplashXPath.cc
+++ b/splash/SplashXPath.cc
@@ -2,6 +2,8 @@
//
// SplashXPath.cc
//
+// Copyright 2003-2013 Glyph & Cog, LLC
+//
//========================================================================
#include <aconf.h>
@@ -54,12 +56,10 @@ inline void SplashXPath::transform(SplashCoord *matrix,
SplashXPath::SplashXPath(SplashPath *path, SplashCoord *matrix,
SplashCoord flatness, GBool closeSubpaths) {
- SplashPathHint *hint;
SplashXPathPoint *pts;
- SplashXPathAdjust *adjusts, *adjust;
SplashCoord x0, y0, x1, y1, x2, y2, x3, y3, xsp, ysp;
- SplashCoord adj0, adj1;
- int curSubpath, curSubpathX, i, j;
+ SplashCoord xMinFP, xMaxFP, yMinFP, yMaxFP;
+ int curSubpath, i;
// transform the points
pts = (SplashXPathPoint *)gmallocn(path->length, sizeof(SplashXPathPoint));
@@ -67,78 +67,16 @@ SplashXPath::SplashXPath(SplashPath *path, SplashCoord *matrix,
transform(matrix, path->pts[i].x, path->pts[i].y, &pts[i].x, &pts[i].y);
}
- // set up the stroke adjustment hints
+ // do stroke adjustment
if (path->hints) {
- adjusts = (SplashXPathAdjust *)gmallocn(path->hintsLength,
- sizeof(SplashXPathAdjust));
- for (i = 0; i < path->hintsLength; ++i) {
- hint = &path->hints[i];
- x0 = pts[hint->ctrl0 ].x; y0 = pts[hint->ctrl0 ].y;
- x1 = pts[hint->ctrl0 + 1].x; y1 = pts[hint->ctrl0 + 1].y;
- x2 = pts[hint->ctrl1 ].x; y2 = pts[hint->ctrl1 ].y;
- x3 = pts[hint->ctrl1 + 1].x; y3 = pts[hint->ctrl1 + 1].y;
- if (x0 == x1 && x2 == x3) {
- adjusts[i].vert = gTrue;
- adj0 = x0;
- adj1 = x2;
- } else if (y0 == y1 && y2 == y3) {
- adjusts[i].vert = gFalse;
- adj0 = y0;
- adj1 = y2;
- } else {
- gfree(adjusts);
- adjusts = NULL;
- break;
- }
- if (adj0 > adj1) {
- x0 = adj0;
- adj0 = adj1;
- adj1 = x0;
- }
- adjusts[i].x0a = adj0 - 0.01;
- adjusts[i].x0b = adj0 + 0.01;
- adjusts[i].xma = (SplashCoord)0.5 * (adj0 + adj1) - 0.01;
- adjusts[i].xmb = (SplashCoord)0.5 * (adj0 + adj1) + 0.01;
- adjusts[i].x1a = adj1 - 0.01;
- adjusts[i].x1b = adj1 + 0.01;
- // rounding both edge coordinates can result in lines of
- // different widths (e.g., adj=10.1, adj1=11.3 --> x0=10, x1=11;
- // adj0=10.4, adj1=11.6 --> x0=10, x1=12), but it has the
- // benefit of making adjacent strokes/fills line up without any
- // gaps between them
- x0 = splashRound(adj0);
- x1 = splashRound(adj1);
- if (x1 == x0) {
- x1 = x1 + 1;
- }
- adjusts[i].x0 = (SplashCoord)x0;
- adjusts[i].x1 = (SplashCoord)x1 - 0.01;
- adjusts[i].xm = (SplashCoord)0.5 * (adjusts[i].x0 + adjusts[i].x1);
- adjusts[i].firstPt = hint->firstPt;
- adjusts[i].lastPt = hint->lastPt;
- }
-
- } else {
- adjusts = NULL;
- }
-
- // perform stroke adjustment
- if (adjusts) {
- for (i = 0, adjust = adjusts; i < path->hintsLength; ++i, ++adjust) {
- for (j = adjust->firstPt; j <= adjust->lastPt; ++j) {
- strokeAdjust(adjust, &pts[j].x, &pts[j].y);
- }
- }
- gfree(adjusts);
+ strokeAdjust(pts, path->hints, path->hintsLength);
}
segs = NULL;
length = size = 0;
x0 = y0 = xsp = ysp = 0; // make gcc happy
- adj0 = adj1 = 0; // make gcc happy
curSubpath = 0;
- curSubpathX = 0;
i = 0;
while (i < path->length) {
@@ -149,7 +87,6 @@ SplashXPath::SplashXPath(SplashPath *path, SplashCoord *matrix,
xsp = x0;
ysp = y0;
curSubpath = i;
- curSubpathX = length;
++i;
} else {
@@ -197,32 +134,130 @@ SplashXPath::SplashXPath(SplashPath *path, SplashCoord *matrix,
}
gfree(pts);
+
+#if HAVE_STD_SORT
+ std::sort(segs, segs + length, SplashXPathSeg::cmpY);
+#else
+ qsort(segs, length, sizeof(SplashXPathSeg), &SplashXPathSeg::cmpY);
+#endif
+
+ if (length == 0) {
+ xMin = yMin = xMax = yMax = 0;
+ } else {
+ if (segs[0].x0 < segs[0].x1) {
+ xMinFP = segs[0].x0;
+ xMaxFP = segs[0].x1;
+ } else {
+ xMinFP = segs[0].x1;
+ xMaxFP = segs[0].x0;
+ }
+ yMinFP = segs[0].y0;
+ yMaxFP = segs[0].y1;
+ for (i = 1; i < length; ++i) {
+ if (segs[i].x0 < xMinFP) {
+ xMinFP = segs[i].x0;
+ } else if (segs[i].x0 > xMaxFP) {
+ xMaxFP = segs[i].x0;
+ }
+ if (segs[i].x1 < xMinFP) {
+ xMinFP = segs[i].x1;
+ } else if (segs[i].x1 > xMaxFP) {
+ xMaxFP = segs[i].x1;
+ }
+ if (segs[i].y1 > yMaxFP) {
+ yMaxFP = segs[i].y1;
+ }
+ }
+ xMin = splashFloor(xMinFP);
+ yMin = splashFloor(yMinFP);
+ xMax = splashFloor(xMaxFP);
+ yMax = splashFloor(yMaxFP);
+ }
}
-// Apply the stroke adjust hints to point <pt>: (*<xp>, *<yp>).
-void SplashXPath::strokeAdjust(SplashXPathAdjust *adjust,
- SplashCoord *xp, SplashCoord *yp) {
- SplashCoord x, y;
+void SplashXPath::strokeAdjust(SplashXPathPoint *pts,
+ SplashPathHint *hints, int nHints) {
+ SplashXPathAdjust *adjusts, *adjust;
+ SplashPathHint *hint;
+ SplashCoord x0, y0, x1, y1, x2, y2, x3, y3;
+ SplashCoord adj0, adj1, d;
+ int xi0, xi1;
+ int i, j;
- if (adjust->vert) {
- x = *xp;
- if (x > adjust->x0a && x < adjust->x0b) {
- *xp = adjust->x0;
- } else if (x > adjust->xma && x < adjust->xmb) {
- *xp = adjust->xm;
- } else if (x > adjust->x1a && x < adjust->x1b) {
- *xp = adjust->x1;
+ // set up the stroke adjustment hints
+ adjusts = (SplashXPathAdjust *)gmallocn(nHints, sizeof(SplashXPathAdjust));
+ for (i = 0; i < nHints; ++i) {
+ hint = &hints[i];
+ x0 = pts[hint->ctrl0 ].x; y0 = pts[hint->ctrl0 ].y;
+ x1 = pts[hint->ctrl0 + 1].x; y1 = pts[hint->ctrl0 + 1].y;
+ x2 = pts[hint->ctrl1 ].x; y2 = pts[hint->ctrl1 ].y;
+ x3 = pts[hint->ctrl1 + 1].x; y3 = pts[hint->ctrl1 + 1].y;
+ if (x0 == x1 && x2 == x3) {
+ adjusts[i].vert = gTrue;
+ adj0 = x0;
+ adj1 = x2;
+ } else if (y0 == y1 && y2 == y3) {
+ adjusts[i].vert = gFalse;
+ adj0 = y0;
+ adj1 = y2;
+ } else {
+ goto done;
}
- } else {
- y = *yp;
- if (y > adjust->x0a && y < adjust->x0b) {
- *yp = adjust->x0;
- } else if (y > adjust->xma && y < adjust->xmb) {
- *yp = adjust->xm;
- } else if (y > adjust->x1a && y < adjust->x1b) {
- *yp = adjust->x1;
+ if (adj0 > adj1) {
+ x0 = adj0;
+ adj0 = adj1;
+ adj1 = x0;
+ }
+ d = adj1 - adj0;
+ if (d > 0.04) {
+ d = 0.01;
+ } else {
+ d *= 0.25;
}
+ adjusts[i].x0a = adj0 - d;
+ adjusts[i].x0b = adj0 + d;
+ adjusts[i].xma = (SplashCoord)0.5 * (adj0 + adj1) - d;
+ adjusts[i].xmb = (SplashCoord)0.5 * (adj0 + adj1) + d;
+ adjusts[i].x1a = adj1 - d;
+ adjusts[i].x1b = adj1 + d;
+ splashStrokeAdjust(adj0, adj1, &xi0, &xi1);
+ adjusts[i].x0 = (SplashCoord)xi0;
+ // the "minus epsilon" thing here is needed when vector
+ // antialiasing is turned off -- otherwise stroke adjusted lines
+ // will touch an extra pixel on one edge
+ adjusts[i].x1 = (SplashCoord)xi1 - 0.001;
+ adjusts[i].xm = (SplashCoord)0.5 * (adjusts[i].x0 + adjusts[i].x1);
+ adjusts[i].firstPt = hint->firstPt;
+ adjusts[i].lastPt = hint->lastPt;
}
+
+ // perform stroke adjustment
+ for (i = 0, adjust = adjusts; i < nHints; ++i, ++adjust) {
+ for (j = adjust->firstPt; j <= adjust->lastPt; ++j) {
+ if (adjust->vert) {
+ x0 = pts[j].x;
+ if (x0 > adjust->x0a && x0 < adjust->x0b) {
+ pts[j].x = adjust->x0;
+ } else if (x0 > adjust->xma && x0 < adjust->xmb) {
+ pts[j].x = adjust->xm;
+ } else if (x0 > adjust->x1a && x0 < adjust->x1b) {
+ pts[j].x = adjust->x1;
+ }
+ } else {
+ y0 = pts[j].y;
+ if (y0 > adjust->x0a && y0 < adjust->x0b) {
+ pts[j].y = adjust->x0;
+ } else if (y0 > adjust->xma && y0 < adjust->xmb) {
+ pts[j].y = adjust->xm;
+ } else if (y0 > adjust->x1a && y0 < adjust->x1b) {
+ pts[j].y = adjust->x1;
+ }
+ }
+ }
+ }
+
+ done:
+ gfree(adjusts);
}
SplashXPath::SplashXPath(SplashXPath *xPath) {
@@ -230,6 +265,10 @@ SplashXPath::SplashXPath(SplashXPath *xPath) {
size = xPath->size;
segs = (SplashXPathSeg *)gmallocn(size, sizeof(SplashXPathSeg));
memcpy(segs, xPath->segs, length * sizeof(SplashXPathSeg));
+ xMin = xPath->xMin;
+ yMin = xPath->yMin;
+ xMax = xPath->xMax;
+ yMax = xPath->yMax;
}
SplashXPath::~SplashXPath() {
@@ -341,115 +380,38 @@ void SplashXPath::addCurve(SplashCoord x0, SplashCoord y0,
void SplashXPath::addSegment(SplashCoord x0, SplashCoord y0,
SplashCoord x1, SplashCoord y1) {
grow(1);
- segs[length].x0 = x0;
- segs[length].y0 = y0;
- segs[length].x1 = x1;
- segs[length].y1 = y1;
- segs[length].flags = 0;
- if (y1 == y0) {
- segs[length].dxdy = segs[length].dydx = 0;
- segs[length].flags |= splashXPathHoriz;
- if (x1 == x0) {
- segs[length].flags |= splashXPathVert;
- }
- } else if (x1 == x0) {
- segs[length].dxdy = segs[length].dydx = 0;
- segs[length].flags |= splashXPathVert;
+ if (y0 <= y1) {
+ segs[length].x0 = x0;
+ segs[length].y0 = y0;
+ segs[length].x1 = x1;
+ segs[length].y1 = y1;
+ segs[length].count = 1;
} else {
+ segs[length].x0 = x1;
+ segs[length].y0 = y1;
+ segs[length].x1 = x0;
+ segs[length].y1 = y0;
+ segs[length].count = -1;
+ }
#if USE_FIXEDPOINT
- if (FixedPoint::divCheck(x1 - x0, y1 - y0, &segs[length].dxdy)) {
- segs[length].dydx = (SplashCoord)1 / segs[length].dxdy;
- } else {
- segs[length].dxdy = segs[length].dydx = 0;
- if (splashAbs(x1 - x0) > splashAbs(y1 - y0)) {
- segs[length].flags |= splashXPathHoriz;
- } else {
- segs[length].flags |= splashXPathVert;
- }
- }
+ if (y0 == y1 || x0 == x1 ||
+ !FixedPoint::divCheck(x1 - x0, y1 - y0, &segs[length].dxdy) ||
+ !FixedPoint::divCheck(y1 - y0, x1 - x0, &segs[length].dydx)) {
+ segs[length].dxdy = 0;
+ segs[length].dydx = 0;
+ }
#else
+ if (y0 == y1 || x0 == x1) {
+ segs[length].dxdy = 0;
+ segs[length].dydx = 0;
+ } else {
segs[length].dxdy = (x1 - x0) / (y1 - y0);
- segs[length].dydx = (SplashCoord)1 / segs[length].dxdy;
-#endif
- }
- if (y0 > y1) {
- segs[length].flags |= splashXPathFlip;
- }
- ++length;
-}
-
-void SplashXPath::aaScale() {
- SplashXPathSeg *seg;
- int i;
-
- for (i = 0, seg = segs; i < length; ++i, ++seg) {
- seg->x0 *= splashAASize;
- seg->y0 *= splashAASize;
- seg->x1 *= splashAASize;
- seg->y1 *= splashAASize;
- }
-}
-
-#if HAVE_STD_SORT
-
-struct cmpXPathSegsFunctor {
- bool operator()(const SplashXPathSeg &seg0, const SplashXPathSeg &seg1) {
- SplashCoord x0, y0, x1, y1;
-
- if (seg0.flags & splashXPathFlip) {
- x0 = seg0.x1;
- y0 = seg0.y1;
+ if (segs[length].dxdy == 0) {
+ segs[length].dydx = 0;
} else {
- x0 = seg0.x0;
- y0 = seg0.y0;
+ segs[length].dydx = 1 / segs[length].dxdy;
}
- if (seg1.flags & splashXPathFlip) {
- x1 = seg1.x1;
- y1 = seg1.y1;
- } else {
- x1 = seg1.x0;
- y1 = seg1.y0;
- }
- return (y0 != y1) ? (y0 < y1) : (x0 < x1);
- }
-};
-
-#else // HAVE_STD_SORT
-
-static int cmpXPathSegs(const void *arg0, const void *arg1) {
- SplashXPathSeg *seg0 = (SplashXPathSeg *)arg0;
- SplashXPathSeg *seg1 = (SplashXPathSeg *)arg1;
- SplashCoord x0, y0, x1, y1;
-
- if (seg0->flags & splashXPathFlip) {
- x0 = seg0->x1;
- y0 = seg0->y1;
- } else {
- x0 = seg0->x0;
- y0 = seg0->y0;
}
- if (seg1->flags & splashXPathFlip) {
- x1 = seg1->x1;
- y1 = seg1->y1;
- } else {
- x1 = seg1->x0;
- y1 = seg1->y0;
- }
- if (y0 != y1) {
- return (y0 > y1) ? 1 : -1;
- }
- if (x0 != x1) {
- return (x0 > x1) ? 1 : -1;
- }
- return 0;
-}
-
-#endif // HAVE_STD_SORT
-
-void SplashXPath::sort() {
-#if HAVE_STD_SORT
- std::sort(segs, segs + length, cmpXPathSegsFunctor());
-#else
- qsort(segs, length, sizeof(SplashXPathSeg), &cmpXPathSegs);
#endif
+ ++length;
}
diff --git a/splash/SplashXPath.h b/splash/SplashXPath.h
index 4e06d82..5bcec61 100644
--- a/splash/SplashXPath.h
+++ b/splash/SplashXPath.h
@@ -2,6 +2,8 @@
//
// SplashXPath.h
//
+// Copyright 2003-2013 Glyph & Cog, LLC
+//
//========================================================================
#ifndef SPLASHXPATH_H
@@ -16,7 +18,8 @@
#include "SplashTypes.h"
class SplashPath;
-struct SplashXPathAdjust;
+struct SplashXPathPoint;
+struct SplashPathHint;
//------------------------------------------------------------------------
@@ -27,18 +30,44 @@ struct SplashXPathAdjust;
//------------------------------------------------------------------------
struct SplashXPathSeg {
- SplashCoord x0, y0; // first endpoint
+ SplashCoord x0, y0; // first endpoint (y0 <= y1)
SplashCoord x1, y1; // second endpoint
SplashCoord dxdy; // slope: delta-x / delta-y
SplashCoord dydx; // slope: delta-y / delta-x
- Guint flags;
-};
+ int count; // EO/NZWN counter increment
+
+ //----- used by SplashXPathScanner
+ SplashCoord xCur0, xCur1; // current x values
+
+#if HAVE_STD_SORT
+ static bool cmpY(const SplashXPathSeg &seg0,
+ const SplashXPathSeg &seg1) {
+ return seg0.y0 < seg1.y0;
+ }
+#else
+ static int cmpY(const void *seg0, const void *seg1) {
+ SplashCoord cmp;
+
+ cmp = ((SplashXPathSeg *)seg0)->y0
+ - ((SplashXPathSeg *)seg1)->y0;
+ return (cmp > 0) ? 1 : (cmp < 0) ? -1 : 0;
+ }
+#endif
+
+ static int cmpX(SplashXPathSeg *seg0, SplashXPathSeg *seg1) {
+ SplashCoord cmp;
-#define splashXPathHoriz 0x01 // segment is vertical (y0 == y1)
- // (dxdy is undef)
-#define splashXPathVert 0x02 // segment is horizontal (x0 == x1)
- // (dydx is undef)
-#define splashXPathFlip 0x04 // y0 > y1
+ if ((cmp = seg0->xCur0 - seg1->xCur0) == 0) {
+ cmp = seg0->dxdy - seg1->dxdy;
+ }
+ return (cmp > 0) ? 1 : (cmp < 0) ? -1 : 0;
+ }
+
+ static int cmpXi(const void *p0, const void *p1) {
+ return cmpX(*(SplashXPathSeg **)p0, *(SplashXPathSeg **)p1);
+ }
+
+};
//------------------------------------------------------------------------
// SplashXPath
@@ -59,20 +88,18 @@ public:
~SplashXPath();
- // Multiply all coordinates by splashAASize, in preparation for
- // anti-aliased rendering.
- void aaScale();
-
- // Sort by upper coordinate (lower y), in y-major order.
- void sort();
+ int getXMin() { return xMin; }
+ int getXMax() { return xMax; }
+ int getYMin() { return yMin; }
+ int getYMax() { return yMax; }
private:
SplashXPath(SplashXPath *xPath);
void transform(SplashCoord *matrix, SplashCoord xi, SplashCoord yi,
SplashCoord *xo, SplashCoord *yo);
- void strokeAdjust(SplashXPathAdjust *adjust,
- SplashCoord *xp, SplashCoord *yp);
+ void strokeAdjust(SplashXPathPoint *pts,
+ SplashPathHint *hints, int nHints);
void grow(int nSegs);
void addCurve(SplashCoord x0, SplashCoord y0,
SplashCoord x1, SplashCoord y1,
@@ -85,6 +112,8 @@ private:
SplashXPathSeg *segs;
int length, size; // length and size of segs array
+ int xMin, xMax;
+ int yMin, yMax;
friend class SplashXPathScanner;
friend class SplashClip;
diff --git a/splash/SplashXPathScanner.cc b/splash/SplashXPathScanner.cc
index abe4593..aee60cc 100644
--- a/splash/SplashXPathScanner.cc
+++ b/splash/SplashXPathScanner.cc
@@ -2,6 +2,8 @@
//
// SplashXPathScanner.cc
//
+// Copyright 2003-2013 Glyph & Cog, LLC
+//
//========================================================================
#include <aconf.h>
@@ -16,523 +18,550 @@
#include <algorithm>
#endif
#include "gmem.h"
+#include "GList.h"
#include "SplashMath.h"
#include "SplashXPath.h"
-#include "SplashBitmap.h"
#include "SplashXPathScanner.h"
//------------------------------------------------------------------------
-struct SplashIntersect {
- int y;
- int x0, x1; // intersection of segment with [y, y+1)
- int count; // EO/NZWN counter increment
-};
-
-#if HAVE_STD_SORT
-
-struct cmpIntersectFunctor {
- bool operator()(const SplashIntersect &i0, const SplashIntersect &i1) {
- return (i0.y != i1.y) ? (i0.y < i1.y) : (i0.x0 < i1.x0);
- }
-};
-
-#else // HAVE_STD_SORT
+#define minVertStep 0.05
-static int cmpIntersect(const void *p0, const void *p1) {
- SplashIntersect *i0 = (SplashIntersect *)p0;
- SplashIntersect *i1 = (SplashIntersect *)p1;
- int cmp;
-
- if ((cmp = i0->y - i1->y) == 0) {
- cmp = i0->x0 - i1->x0;
- }
- return cmp;
-}
-
-#endif // HAVE_STD_SORT
-
-//------------------------------------------------------------------------
-// SplashXPathScanner
//------------------------------------------------------------------------
SplashXPathScanner::SplashXPathScanner(SplashXPath *xPathA, GBool eoA,
- int clipYMin, int clipYMax) {
- SplashXPathSeg *seg;
- SplashCoord xMinFP, yMinFP, xMaxFP, yMaxFP;
- int i;
-
+ int yMinA, int yMaxA) {
xPath = xPathA;
eo = eoA;
- partialClip = gFalse;
+ yMin = yMinA;
+ yMax = yMaxA;
- // compute the bbox
- if (xPath->length == 0) {
- xMin = yMin = 1;
- xMax = yMax = 0;
- } else {
- seg = &xPath->segs[0];
- if (seg->x0 <= seg->x1) {
- xMinFP = seg->x0;
- xMaxFP = seg->x1;
- } else {
- xMinFP = seg->x1;
- xMaxFP = seg->x0;
- }
- if (seg->flags & splashXPathFlip) {
- yMinFP = seg->y1;
- yMaxFP = seg->y0;
- } else {
- yMinFP = seg->y0;
- yMaxFP = seg->y1;
- }
- for (i = 1; i < xPath->length; ++i) {
- seg = &xPath->segs[i];
- if (seg->x0 < xMinFP) {
- xMinFP = seg->x0;
- } else if (seg->x0 > xMaxFP) {
- xMaxFP = seg->x0;
- }
- if (seg->x1 < xMinFP) {
- xMinFP = seg->x1;
- } else if (seg->x1 > xMaxFP) {
- xMaxFP = seg->x1;
+ activeSegs = new GList();
+ nextSeg = 0;
+ yNext = xPath->yMin;
+}
+
+SplashXPathScanner::~SplashXPathScanner() {
+ delete activeSegs;
+}
+
+void SplashXPathScanner::getSpan(Guchar *line, int y, int x0, int x1) {
+ SplashXPathSeg *seg, *seg0;
+ SplashCoord y0, y1, y1p;
+ GBool intersect, last;
+ int eoMask, state0, state1, count, i;
+
+ //--- clear the scan line buffer
+ memset(line + x0, 0, x1 - x0 + 1);
+
+ //--- reset the path
+ if (yNext != y) {
+ delete activeSegs;
+ activeSegs = new GList();
+ nextSeg = 0;
+ while (nextSeg < xPath->length) {
+ seg = &xPath->segs[nextSeg];
+ if (seg->y0 >= y) {
+ break;
}
- if (seg->flags & splashXPathFlip) {
- if (seg->y0 > yMaxFP) {
- yMaxFP = seg->y0;
- }
- } else {
- if (seg->y1 > yMaxFP) {
- yMaxFP = seg->y1;
+ if (seg->y0 != seg->y1 && seg->y1 > y) {
+ if (seg->y0 == y) {
+ seg->xCur0 = seg->x0;
+ } else {
+ seg->xCur0 = seg->x0 + ((SplashCoord)y - seg->y0) * seg->dxdy;
}
+ activeSegs->append(seg);
}
+ ++nextSeg;
}
- xMin = splashFloor(xMinFP);
- xMax = splashFloor(xMaxFP);
- yMin = splashFloor(yMinFP);
- yMax = splashFloor(yMaxFP);
- if (clipYMin > yMin) {
- yMin = clipYMin;
- partialClip = gTrue;
- }
- if (clipYMax < yMax) {
- yMax = clipYMax;
- partialClip = gTrue;
- }
+ activeSegs->sort(&SplashXPathSeg::cmpXi);
}
- allInter = NULL;
- inter = NULL;
- computeIntersections();
- interY = yMin - 1;
-}
+ //--- process the scan line
+ y0 = y;
+ while (y0 < y + 1) {
-SplashXPathScanner::~SplashXPathScanner() {
- gfree(inter);
- gfree(allInter);
-}
+ //--- delete finished segs
+ i = 0;
+ while (i < activeSegs->getLength()) {
+ seg = (SplashXPathSeg *)activeSegs->get(i);
+ if (seg->y1 <= y0) {
+ activeSegs->del(i);
+ } else {
+ ++i;
+ }
+ }
-void SplashXPathScanner::getBBoxAA(int *xMinA, int *yMinA,
- int *xMaxA, int *yMaxA) {
- *xMinA = xMin / splashAASize;
- *yMinA = yMin / splashAASize;
- *xMaxA = xMax / splashAASize;
- *yMaxA = yMax / splashAASize;
-}
+ //--- check for bottom of path
+ if (!activeSegs->getLength() && nextSeg >= xPath->length) {
+ break;
+ }
-void SplashXPathScanner::getSpanBounds(int y, int *spanXMin, int *spanXMax) {
- int interBegin, interEnd, xx, i;
+ //--- sort activeSegs
+ sortActiveSegs();
- if (y < yMin || y > yMax) {
- interBegin = interEnd = 0;
- } else {
- interBegin = inter[y - yMin];
- interEnd = inter[y - yMin + 1];
- }
- if (interBegin < interEnd) {
- *spanXMin = allInter[interBegin].x0;
- xx = allInter[interBegin].x1;
- for (i = interBegin + 1; i < interEnd; ++i) {
- if (allInter[i].x1 > xx) {
- xx = allInter[i].x1;
+ //--- add waiting segs
+ while (nextSeg < xPath->length) {
+ seg = &xPath->segs[nextSeg];
+ if (seg->y0 > y0) {
+ break;
+ }
+ if (seg->y0 != seg->y1) {
+ seg->xCur0 = seg->x0;
+ insertActiveSeg(seg);
}
+ ++nextSeg;
}
- *spanXMax = xx;
- } else {
- *spanXMin = xMax + 1;
- *spanXMax = xMax;
- }
-}
-GBool SplashXPathScanner::test(int x, int y) {
- int interBegin, interEnd, count, i;
-
- if (y < yMin || y > yMax) {
- return gFalse;
- }
- interBegin = inter[y - yMin];
- interEnd = inter[y - yMin + 1];
- count = 0;
- for (i = interBegin; i < interEnd && allInter[i].x0 <= x; ++i) {
- if (x <= allInter[i].x1) {
- return gTrue;
+ //--- get the next "interesting" y value
+ y1 = y + 1;
+ if (nextSeg < xPath->length && xPath->segs[nextSeg].y0 < y1) {
+ y1 = xPath->segs[nextSeg].y0;
+ }
+ for (i = 0; i < activeSegs->getLength(); ++i) {
+ seg = (SplashXPathSeg *)activeSegs->get(i);
+ if (seg->y1 < y1) {
+ y1 = seg->y1;
+ }
}
- count += allInter[i].count;
- }
- return eo ? (count & 1) : (count != 0);
-}
-GBool SplashXPathScanner::testSpan(int x0, int x1, int y) {
- int interBegin, interEnd, count, xx1, i;
+ //--- compute xCur1 values, check for intersections
+ seg0 = NULL;
+ intersect = gFalse;
+ for (i = 0; i < activeSegs->getLength(); ++i) {
+ seg = (SplashXPathSeg *)activeSegs->get(i);
+ if (seg->y1 == y1) {
+ seg->xCur1 = seg->x1;
+ } else {
+ seg->xCur1 = seg->x0 + (y1 - seg->y0) * seg->dxdy;
+ }
+ if (seg0 && seg0->xCur1 > seg->xCur1) {
+ intersect = gTrue;
+ }
+ seg0 = seg;
+ }
- if (y < yMin || y > yMax) {
- return gFalse;
- }
- interBegin = inter[y - yMin];
- interEnd = inter[y - yMin + 1];
- count = 0;
- for (i = interBegin; i < interEnd && allInter[i].x1 < x0; ++i) {
- count += allInter[i].count;
- }
+ //--- draw rectangles
+ if (intersect) {
+ for (; y0 < y1; y0 += minVertStep) {
+ if ((y1p = y0 + minVertStep) >= y1) {
+ y1p = y1;
+ last = gTrue;
+ } else {
+ last = gFalse;
+ }
+ state0 = state1 = count = 0;
+ seg0 = NULL;
+ eoMask = eo ? 1 : 0xffffffff;
+ for (i = 0; i < activeSegs->getLength(); ++i) {
+ seg = (SplashXPathSeg *)activeSegs->get(i);
+ if (last && seg->y1 == y1) {
+ seg->xCur1 = seg->x1;
+ } else {
+ seg->xCur1 = seg->x0 + (y1p - seg->y0) * seg->dxdy;
+ }
+ count += seg->count;
+ state1 = count & eoMask;
+ if (!state0 && state1) {
+ seg0 = seg;
+ } else if (state0 && !state1) {
+ drawRectangle(line, x0, x1, y0, y1p, seg0->xCur0, seg->xCur0);
+ }
+ state0 = state1;
+ }
+ for (i = 0; i < activeSegs->getLength(); ++i) {
+ seg = (SplashXPathSeg *)activeSegs->get(i);
+ seg->xCur0 = seg->xCur1;
+ }
+ sortActiveSegs();
+ }
- // invariant: the subspan [x0,xx1] is inside the path
- xx1 = x0 - 1;
- while (xx1 < x1) {
- if (i >= interEnd) {
- return gFalse;
- }
- if (allInter[i].x0 > xx1 + 1 &&
- !(eo ? (count & 1) : (count != 0))) {
- return gFalse;
- }
- if (allInter[i].x1 > xx1) {
- xx1 = allInter[i].x1;
+ //--- draw trapezoids
+ } else {
+ state0 = state1 = count = 0;
+ seg0 = NULL;
+ eoMask = eo ? 1 : 0xffffffff;
+ for (i = 0; i < activeSegs->getLength(); ++i) {
+ seg = (SplashXPathSeg *)activeSegs->get(i);
+ count += seg->count;
+ state1 = count & eoMask;
+ if (!state0 && state1) {
+ seg0 = seg;
+ } else if (state0 && !state1) {
+ drawTrapezoid(line, x0, x1, y0, y1,
+ seg0->xCur0, seg0->xCur1, seg0->dydx,
+ seg->xCur0, seg->xCur1, seg->dydx);
+ }
+ state0 = state1;
+ }
+ for (i = 0; i < activeSegs->getLength(); ++i) {
+ seg = (SplashXPathSeg *)activeSegs->get(i);
+ seg->xCur0 = seg->xCur1;
+ }
}
- count += allInter[i].count;
- ++i;
+
+ //--- next slice
+ y0 = y1;
}
- return gTrue;
+ yNext = y + 1;
}
-GBool SplashXPathScanner::getNextSpan(int y, int *x0, int *x1) {
- int interEnd, xx0, xx1;
-
- if (y < yMin || y > yMax) {
- return gFalse;
- }
- if (interY != y) {
- interY = y;
- interIdx = inter[y - yMin];
- interCount = 0;
- }
- interEnd = inter[y - yMin + 1];
- if (interIdx >= interEnd) {
- return gFalse;
+void SplashXPathScanner::getSpanBinary(Guchar *line, int y, int x0, int x1) {
+ SplashXPathSeg *seg;
+ int xx0, xx1, xx;
+ int eoMask, state0, state1, count, i;
+
+ //--- clear the scan line buffer
+ memset(line + x0, 0, x1 - x0 + 1);
+
+ //--- reset the path
+ if (yNext != y) {
+ delete activeSegs;
+ activeSegs = new GList();
+ nextSeg = 0;
+ while (nextSeg < xPath->length) {
+ seg = &xPath->segs[nextSeg];
+ if (seg->y0 >= y) {
+ break;
+ }
+ if (seg->y1 > y) {
+ if (seg->y0 == y) {
+ seg->xCur0 = seg->x0;
+ } else {
+ seg->xCur0 = seg->x0 + ((SplashCoord)y - seg->y0) * seg->dxdy;
+ }
+ activeSegs->append(seg);
+ }
+ ++nextSeg;
+ }
+ activeSegs->sort(&SplashXPathSeg::cmpXi);
}
- xx0 = allInter[interIdx].x0;
- xx1 = allInter[interIdx].x1;
- interCount += allInter[interIdx].count;
- ++interIdx;
- while (interIdx < interEnd &&
- (allInter[interIdx].x0 <= xx1 ||
- (eo ? (interCount & 1) : (interCount != 0)))) {
- if (allInter[interIdx].x1 > xx1) {
- xx1 = allInter[interIdx].x1;
+
+ //--- delete finished segs
+ i = 0;
+ while (i < activeSegs->getLength()) {
+ seg = (SplashXPathSeg *)activeSegs->get(i);
+ if (seg->y1 <= y) {
+ activeSegs->del(i);
+ } else {
+ ++i;
}
- interCount += allInter[interIdx].count;
- ++interIdx;
}
- *x0 = xx0;
- *x1 = xx1;
- return gTrue;
-}
-void SplashXPathScanner::computeIntersections() {
- SplashXPathSeg *seg;
- SplashCoord segXMin, segXMax, segYMin, segYMax, xx0, xx1;
- int x, y, y0, y1, i;
+ //--- sort activeSegs
+ sortActiveSegs();
- if (yMin > yMax) {
- return;
+ //--- add waiting segs
+ while (nextSeg < xPath->length) {
+ seg = &xPath->segs[nextSeg];
+ if (seg->y0 >= y + 1) {
+ break;
+ }
+ seg->xCur0 = seg->x0;
+ insertActiveSeg(seg);
+ ++nextSeg;
}
- // build the list of all intersections
- allInterLen = 0;
- allInterSize = 16;
- allInter = (SplashIntersect *)gmallocn(allInterSize,
- sizeof(SplashIntersect));
- for (i = 0; i < xPath->length; ++i) {
- seg = &xPath->segs[i];
- if (seg->flags & splashXPathFlip) {
- segYMin = seg->y1;
- segYMax = seg->y0;
+ //--- compute xCur1 values
+ for (i = 0; i < activeSegs->getLength(); ++i) {
+ seg = (SplashXPathSeg *)activeSegs->get(i);
+ if (seg->y1 <= y + 1) {
+ seg->xCur1 = seg->x1;
} else {
- segYMin = seg->y0;
- segYMax = seg->y1;
+ seg->xCur1 = seg->x0 + ((SplashCoord)(y + 1) - seg->y0) * seg->dxdy;
}
- if (seg->flags & splashXPathHoriz) {
- y = splashFloor(seg->y0);
- if (y >= yMin && y <= yMax) {
- addIntersection(segYMin, segYMax, seg->flags,
- y, splashFloor(seg->x0), splashFloor(seg->x1));
- }
- } else if (seg->flags & splashXPathVert) {
- y0 = splashFloor(segYMin);
- if (y0 < yMin) {
- y0 = yMin;
+ }
+
+ //--- draw spans
+ state0 = state1 = count = 0;
+ eoMask = eo ? 1 : 0xffffffff;
+ xx0 = xx1 = 0; // make gcc happy
+ for (i = 0; i < activeSegs->getLength(); ++i) {
+ seg = (SplashXPathSeg *)activeSegs->get(i);
+ if (seg->y0 <= y && seg->y0 < seg->y1) {
+ count += seg->count;
+ state1 = count & eoMask;
+ }
+ if (state0) {
+ xx = splashCeil(seg->xCur0) - 1;
+ if (xx > xx1) {
+ xx1 = xx;
}
- y1 = splashFloor(segYMax);
- if (y1 > yMax) {
- y1 = yMax;
+ xx = splashFloor(seg->xCur1);
+ if (xx < xx0) {
+ xx0 = xx;
}
- x = splashFloor(seg->x0);
- for (y = y0; y <= y1; ++y) {
- addIntersection(segYMin, segYMax, seg->flags, y, x, x);
+ xx = splashCeil(seg->xCur1) - 1;
+ if (xx > xx1) {
+ xx1 = xx;
}
} else {
- if (seg->x0 < seg->x1) {
- segXMin = seg->x0;
- segXMax = seg->x1;
+ if (seg->xCur0 < seg->xCur1) {
+ xx0 = splashFloor(seg->xCur0);
+ xx1 = splashCeil(seg->xCur1) - 1;
} else {
- segXMin = seg->x1;
- segXMax = seg->x0;
+ xx0 = splashFloor(seg->xCur1);
+ xx1 = splashCeil(seg->xCur0) - 1;
}
- y0 = splashFloor(segYMin);
- if (y0 < yMin) {
- y0 = yMin;
+ }
+ if (!state1) {
+ if (xx0 < x0) {
+ xx0 = x0;
}
- y1 = splashFloor(segYMax);
- if (y1 > yMax) {
- y1 = yMax;
+ if (xx1 > x1) {
+ xx1 = x1;
}
- // this loop could just add seg->dxdy to xx1 on each iteration,
- // but that introduces numerical accuracy problems
- xx1 = seg->x0 + ((SplashCoord)y0 - seg->y0) * seg->dxdy;
- for (y = y0; y <= y1; ++y) {
- xx0 = xx1;
- xx1 = seg->x0 + ((SplashCoord)(y + 1) - seg->y0) * seg->dxdy;
- // the segment may not actually extend to the top and/or bottom edges
- if (xx0 < segXMin) {
- xx0 = segXMin;
- } else if (xx0 > segXMax) {
- xx0 = segXMax;
- }
- if (xx1 < segXMin) {
- xx1 = segXMin;
- } else if (xx1 > segXMax) {
- xx1 = segXMax;
- }
- addIntersection(segYMin, segYMax, seg->flags, y,
- splashFloor(xx0), splashFloor(xx1));
+ for (xx = xx0; xx <= xx1; ++xx) {
+ line[xx] = 0xff;
}
}
+ state0 = state1;
}
-#if HAVE_STD_SORT
- std::sort(allInter, allInter + allInterLen, cmpIntersectFunctor());
-#else
- qsort(allInter, allInterLen, sizeof(SplashIntersect), cmpIntersect);
-#endif
- // build the list of y pointers
- inter = (int *)gmallocn(yMax - yMin + 2, sizeof(int));
- i = 0;
- for (y = yMin; y <= yMax; ++y) {
- inter[y - yMin] = i;
- while (i < allInterLen && allInter[i].y <= y) {
- ++i;
- }
+ //--- update xCur0 values
+ for (i = 0; i < activeSegs->getLength(); ++i) {
+ seg = (SplashXPathSeg *)activeSegs->get(i);
+ seg->xCur0 = seg->xCur1;
}
- inter[yMax - yMin + 1] = i;
+
+ yNext = y + 1;
}
-void SplashXPathScanner::addIntersection(double segYMin, double segYMax,
- Guint segFlags,
- int y, int x0, int x1) {
- if (allInterLen == allInterSize) {
- allInterSize *= 2;
- allInter = (SplashIntersect *)greallocn(allInter, allInterSize,
- sizeof(SplashIntersect));
+inline void SplashXPathScanner::addArea(Guchar *line, int x, SplashCoord a) {
+ int a2, t;
+
+ a2 = splashRound(a * 255);
+ if (a2 <= 0) {
+ return;
+ }
+ t = line[x] + a2;
+ if (t > 255) {
+ t = 255;
+ }
+ line[x] = t;
+}
+
+// Draw a trapezoid with edges:
+// top: (xa0, y0) - (xb0, y0)
+// left: (xa0, y0) - (xa1, y1)
+// right: (xb0, y0) - (xb1, y1)
+// bottom: (xa1, y1) - (xb1, y1)
+void SplashXPathScanner::drawTrapezoid(Guchar *line, int xMin, int xMax,
+ SplashCoord y0, SplashCoord y1,
+ SplashCoord xa0, SplashCoord xa1,
+ SplashCoord dydxa,
+ SplashCoord xb0, SplashCoord xb1,
+ SplashCoord dydxb) {
+ SplashCoord a, dy;
+ int x0, x1, x2, x3, x;
+
+ // check for a rectangle
+ if (dydxa == 0 && dydxb == 0 && xa0 >= xMin && xb0 <= xMax) {
+ x0 = splashFloor(xa0);
+ x3 = splashFloor(xb0);
+ dy = y1 - y0;
+ if (x0 == x3) {
+ addArea(line, x0, (xb0 - xa0) * dy);
+ } else {
+ addArea(line, x0, ((SplashCoord)1 - (xa0 - x0)) * dy);
+ for (x = x0 + 1; x <= x3 - 1; ++x) {
+ addArea(line, x, y1 - y0);
+ }
+ addArea(line, x3, (xb0 - x3) * (y1 - y0));
+ }
+ return;
}
- allInter[allInterLen].y = y;
- if (x0 < x1) {
- allInter[allInterLen].x0 = x0;
- allInter[allInterLen].x1 = x1;
+
+ if (dydxa > 0) {
+ x0 = splashFloor(xa0);
+ x1 = splashFloor(xa1);
} else {
- allInter[allInterLen].x0 = x1;
- allInter[allInterLen].x1 = x0;
+ x0 = splashFloor(xa1);
+ x1 = splashFloor(xa0);
+ }
+ if (x0 < xMin) {
+ x0 = xMin;
}
- if (segYMin <= y &&
- (SplashCoord)y < segYMax &&
- !(segFlags & splashXPathHoriz)) {
- allInter[allInterLen].count = eo ? 1
- : (segFlags & splashXPathFlip) ? 1 : -1;
+ if (dydxb > 0) {
+ x2 = splashFloor(xb0);
+ x3 = splashFloor(xb1);
} else {
- allInter[allInterLen].count = 0;
+ x2 = splashFloor(xb1);
+ x3 = splashFloor(xb0);
+ }
+ if (x3 > xMax) {
+ x3 = xMax;
+ }
+ for (x = x0; x <= x3; ++x) {
+ a = y1 - y0;
+ if (x <= x1) {
+ a -= areaLeft(x, xa0, y0, xa1, y1, dydxa);
+ }
+ if (x >= x2) {
+ a -= areaRight(x, xb0, y0, xb1, y1, dydxb);
+ }
+ addArea(line, x, a);
}
- ++allInterLen;
}
-void SplashXPathScanner::renderAALine(SplashBitmap *aaBuf,
- int *x0, int *x1, int y) {
- int xx0, xx1, xx, xxMin, xxMax, yy, interEnd;
- Guchar mask;
- SplashColorPtr p;
-
- memset(aaBuf->getDataPtr(), 0, aaBuf->getRowSize() * aaBuf->getHeight());
- xxMin = aaBuf->getWidth();
- xxMax = -1;
- if (yMin <= yMax) {
- if (splashAASize * y < yMin) {
- interIdx = inter[0];
- } else if (splashAASize * y > yMax) {
- interIdx = inter[yMax - yMin + 1];
+// Compute area within a pixel slice ((xp,y0)-(xp+1,y1)) to the left
+// of a trapezoid edge ((x0,y0)-(x1,y1)).
+SplashCoord SplashXPathScanner::areaLeft(int xp,
+ SplashCoord x0, SplashCoord y0,
+ SplashCoord x1, SplashCoord y1,
+ SplashCoord dydx) {
+ SplashCoord a, ya, yb;
+
+ if (dydx >= 0) {
+ if (x0 >= xp) {
+ if (x1 <= xp + 1) {
+ a = ((x0 + x1) * 0.5 - xp) * (y1 - y0);
+ } else {
+ yb = y0 + ((SplashCoord)(xp + 1) - x0) * dydx;
+ a = (y1 - y0) - ((SplashCoord)(xp + 1) - x0) * (yb - y0) * 0.5;
+ }
} else {
- interIdx = inter[splashAASize * y - yMin];
+ if (x1 <= xp + 1) {
+ ya = y0 + ((SplashCoord)xp - x0) * dydx;
+ a = (x1 - xp) * (y1 - ya) * 0.5;
+ } else {
+ // ya = y1 - (x1 - xp - 0.5) * dydx;
+ // a = y1 - ya;
+ a = (x1 - xp - 0.5) * dydx;
+ }
}
- for (yy = 0; yy < splashAASize; ++yy) {
- if (splashAASize * y + yy < yMin) {
- interEnd = inter[0];
- } else if (splashAASize * y + yy > yMax) {
- interEnd = inter[yMax - yMin + 1];
+ } else {
+ if (x0 <= xp + 1) {
+ if (x1 >= xp) {
+ a = ((x0 + x1) * 0.5 - xp) * (y1 - y0);
} else {
- interEnd = inter[splashAASize * y + yy - yMin + 1];
+ ya = y0 + ((SplashCoord)xp - x0) * dydx;
+ a = (x0 - xp) * (ya - y0) * 0.5;
}
- interCount = 0;
- while (interIdx < interEnd) {
- xx0 = allInter[interIdx].x0;
- xx1 = allInter[interIdx].x1;
- interCount += allInter[interIdx].count;
- ++interIdx;
- while (interIdx < interEnd &&
- (allInter[interIdx].x0 <= xx1 ||
- (eo ? (interCount & 1) : (interCount != 0)))) {
- if (allInter[interIdx].x1 > xx1) {
- xx1 = allInter[interIdx].x1;
- }
- interCount += allInter[interIdx].count;
- ++interIdx;
- }
- if (xx0 < 0) {
- xx0 = 0;
- }
- ++xx1;
- if (xx1 > aaBuf->getWidth()) {
- xx1 = aaBuf->getWidth();
- }
- // set [xx0, xx1) to 1
- if (xx0 < xx1) {
- xx = xx0;
- p = aaBuf->getDataPtr() + yy * aaBuf->getRowSize() + (xx >> 3);
- if (xx & 7) {
- mask = 0xff >> (xx & 7);
- if ((xx & ~7) == (xx1 & ~7)) {
- mask &= (Guchar)(0xff00 >> (xx1 & 7));
- }
- *p++ |= mask;
- xx = (xx & ~7) + 8;
- }
- for (; xx + 7 < xx1; xx += 8) {
- *p++ |= 0xff;
- }
- if (xx < xx1) {
- *p |= (Guchar)(0xff00 >> (xx1 & 7));
- }
- }
- if (xx0 < xxMin) {
- xxMin = xx0;
- }
- if (xx1 > xxMax) {
- xxMax = xx1;
- }
+ } else {
+ if (x1 >= xp) {
+ yb = y0 + ((SplashCoord)(xp + 1) - x0) * dydx;
+ a = (y1 - y0) - ((SplashCoord)(xp + 1) - x1) * (y1 - yb) * 0.5;
+ } else {
+ // ya = y0 + (xp - x0 + 0.5) * dydx;
+ // a = ya - y0;
+ a = ((SplashCoord)xp - x0 + 0.5) * dydx;
}
}
}
- *x0 = xxMin / splashAASize;
- *x1 = (xxMax - 1) / splashAASize;
+ return a;
}
-void SplashXPathScanner::clipAALine(SplashBitmap *aaBuf,
- int *x0, int *x1, int y) {
- int xx0, xx1, xx, yy, interEnd;
- Guchar mask;
- SplashColorPtr p;
-
- for (yy = 0; yy < splashAASize; ++yy) {
- xx = *x0 * splashAASize;
- if (yMin <= yMax) {
- if (splashAASize * y + yy < yMin) {
- interIdx = interEnd = inter[0];
- } else if (splashAASize * y + yy > yMax) {
- interIdx = interEnd = inter[yMax - yMin + 1];
+// Compute area within a pixel slice ((xp,y0)-(xp+1,y1)) to the left
+// of a trapezoid edge ((x0,y0)-(x1,y1)).
+SplashCoord SplashXPathScanner::areaRight(int xp,
+ SplashCoord x0, SplashCoord y0,
+ SplashCoord x1, SplashCoord y1,
+ SplashCoord dydx) {
+ SplashCoord a, ya, yb;
+
+ if (dydx >= 0) {
+ if (x0 >= xp) {
+ if (x1 <= xp + 1) {
+ a = ((SplashCoord)(xp + 1) - (x0 + x1) * 0.5) * (y1 - y0);
} else {
- interIdx = inter[splashAASize * y + yy - yMin];
- if (splashAASize * y + yy > yMax) {
- interEnd = inter[yMax - yMin + 1];
- } else {
- interEnd = inter[splashAASize * y + yy - yMin + 1];
- }
+ yb = y0 + ((SplashCoord)(xp + 1) - x0) * dydx;
+ a = ((SplashCoord)(xp + 1) - x0) * (yb - y0) * 0.5;
}
- interCount = 0;
- while (interIdx < interEnd && xx < (*x1 + 1) * splashAASize) {
- xx0 = allInter[interIdx].x0;
- xx1 = allInter[interIdx].x1;
- interCount += allInter[interIdx].count;
- ++interIdx;
- while (interIdx < interEnd &&
- (allInter[interIdx].x0 <= xx1 ||
- (eo ? (interCount & 1) : (interCount != 0)))) {
- if (allInter[interIdx].x1 > xx1) {
- xx1 = allInter[interIdx].x1;
- }
- interCount += allInter[interIdx].count;
- ++interIdx;
- }
- if (xx0 > aaBuf->getWidth()) {
- xx0 = aaBuf->getWidth();
- }
- // set [xx, xx0) to 0
- if (xx < xx0) {
- p = aaBuf->getDataPtr() + yy * aaBuf->getRowSize() + (xx >> 3);
- if (xx & 7) {
- mask = (Guchar)(0xff00 >> (xx & 7));
- if ((xx & ~7) == (xx0 & ~7)) {
- mask |= 0xff >> (xx0 & 7);
- }
- *p++ &= mask;
- xx = (xx & ~7) + 8;
- }
- for (; xx + 7 < xx0; xx += 8) {
- *p++ = 0x00;
- }
- if (xx < xx0) {
- *p &= 0xff >> (xx0 & 7);
- }
- }
- if (xx1 >= xx) {
- xx = xx1 + 1;
- }
+ } else {
+ if (x1 <= xp + 1) {
+ ya = y0 + ((SplashCoord)xp - x0) * dydx;
+ a = (y1 - y0) - (x1 - xp) * (y1 - ya) * 0.5;
+ } else {
+ // ya = y0 + (xp - x0 + 0.5) * dydx;
+ // a = ya - y0;
+ a = ((SplashCoord)xp + 0.5 - x0) * dydx;
}
}
- xx0 = (*x1 + 1) * splashAASize;
- // set [xx, xx0) to 0
- if (xx < xx0) {
- p = aaBuf->getDataPtr() + yy * aaBuf->getRowSize() + (xx >> 3);
- if (xx & 7) {
- mask = (Guchar)(0xff00 >> (xx & 7));
- if ((xx & ~7) == (xx0 & ~7)) {
- mask &= 0xff >> (xx0 & 7);
- }
- *p++ &= mask;
- xx = (xx & ~7) + 8;
+ } else {
+ if (x0 <= xp + 1) {
+ if (x1 >= xp) {
+ a = ((SplashCoord)(xp + 1) - (x0 + x1) * 0.5) * (y1 - y0);
+ } else {
+ ya = y0 + ((SplashCoord)xp - x0) * dydx;
+ a = (y1 - y0) - (x0 - xp) * (ya - y0) * 0.5;
}
- for (; xx + 7 < xx0; xx += 8) {
- *p++ = 0x00;
+ } else {
+ if (x1 >= xp) {
+ yb = y0 + ((SplashCoord)(xp + 1) - x0) * dydx;
+ a = ((SplashCoord)(xp + 1) - x1) * (y1 - yb) * 0.5;
+ } else {
+ // ya = y1 - (x1 - xp - 0.5) * dydx;
+ // a = y1 - ya;
+ a = (x1 - xp - 0.5) * dydx;
}
- if (xx < xx0) {
- *p &= 0xff >> (xx0 & 7);
+ }
+ }
+ return a;
+}
+
+void SplashXPathScanner::drawRectangle(Guchar *line, int xMin, int xMax,
+ SplashCoord y0, SplashCoord y1,
+ SplashCoord x0, SplashCoord x1) {
+ SplashCoord dy, a;
+ int xx0, xx1, x;
+
+ xx0 = splashFloor(x0);
+ if (xx0 < xMin) {
+ xx0 = xMin;
+ }
+ xx1 = splashFloor(x1);
+ if (xx1 > xMax) {
+ xx1 = xMax;
+ }
+ dy = y1 - y0;
+ for (x = xx0; x <= xx1; ++x) {
+ a = dy;
+ if ((SplashCoord)x < x0) {
+ a -= (x0 - x) * dy;
+ }
+ if ((SplashCoord)(x + 1) > x1) {
+ a -= ((SplashCoord)(x + 1) - x1) * dy;
+ }
+ addArea(line, x, a);
+ }
+}
+
+void SplashXPathScanner::sortActiveSegs() {
+ SplashXPathSeg *seg0, *seg1;
+ int i, j, k;
+
+ if (activeSegs->getLength() < 2) {
+ return;
+ }
+ seg0 = (SplashXPathSeg *)activeSegs->get(0);
+ for (i = 1; i < activeSegs->getLength(); ++i) {
+ seg1 = (SplashXPathSeg *)activeSegs->get(i);
+ if (SplashXPathSeg::cmpX(seg0, seg1) > 0) {
+ for (j = i - 1; j > 0; --j) {
+ if (SplashXPathSeg::cmpX((SplashXPathSeg *)activeSegs->get(j - 1),
+ seg1) <= 0) {
+ break;
+ }
}
+ for (k = i; k > j; --k) {
+ activeSegs->put(k, activeSegs->get(k-1));
+ }
+ activeSegs->put(j, seg1);
+ } else {
+ seg0 = seg1;
+ }
+ }
+}
+
+void SplashXPathScanner::insertActiveSeg(SplashXPathSeg *seg) {
+ int i;
+
+ for (i = 0; i < activeSegs->getLength(); ++i) {
+ if (SplashXPathSeg::cmpX(seg, (SplashXPathSeg *)activeSegs->get(i)) < 0) {
+ break;
}
}
+ activeSegs->insert(i, seg);
}
diff --git a/splash/SplashXPathScanner.h b/splash/SplashXPathScanner.h
index 5bb3aaf..519ff4d 100644
--- a/splash/SplashXPathScanner.h
+++ b/splash/SplashXPathScanner.h
@@ -2,6 +2,8 @@
//
// SplashXPathScanner.h
//
+// Copyright 2003-2013 Glyph & Cog, LLC
+//
//========================================================================
#ifndef SPLASHXPATHSCANNER_H
@@ -15,9 +17,8 @@
#include "SplashTypes.h"
+class GList;
class SplashXPath;
-class SplashBitmap;
-struct SplashIntersect;
//------------------------------------------------------------------------
// SplashXPathScanner
@@ -28,68 +29,47 @@ public:
// Create a new SplashXPathScanner object. <xPathA> must be sorted.
SplashXPathScanner(SplashXPath *xPathA, GBool eoA,
- int clipYMin, int clipYMax);
+ int yMinA, int yMaxA);
~SplashXPathScanner();
- // Return the path's bounding box.
- void getBBox(int *xMinA, int *yMinA, int *xMaxA, int *yMaxA)
- { *xMinA = xMin; *yMinA = yMin; *xMaxA = xMax; *yMaxA = yMax; }
-
- // Return the path's bounding box.
- void getBBoxAA(int *xMinA, int *yMinA, int *xMaxA, int *yMaxA);
-
- // Returns true if at least part of the path was outside the
- // clipYMin/clipYMax bounds passed to the constructor.
- GBool hasPartialClip() { return partialClip; }
-
- // Return the min/max x values for the span at <y>.
- void getSpanBounds(int y, int *spanXMin, int *spanXMax);
-
- // Returns true if (<x>,<y>) is inside the path.
- GBool test(int x, int y);
+ // Compute shape values for a scan line. Fills in line[] with shape
+ // values for one scan line: ([x0, x1], y). The values are in [0,
+ // 255].
+ void getSpan(Guchar *line, int y, int x0, int x1);
- // Returns true if the entire span ([<x0>,<x1>], <y>) is inside the
- // path.
- GBool testSpan(int x0, int x1, int y);
-
- // Returns the next span inside the path at <y>. If <y> is
- // different than the previous call to getNextSpan, this returns the
- // first span at <y>; otherwise it returns the next span (relative
- // to the previous call to getNextSpan). Returns false if there are
- // no more spans at <y>.
- GBool getNextSpan(int y, int *x0, int *x1);
-
- // Renders one anti-aliased line into <aaBuf>. Returns the min and
- // max x coordinates with non-zero pixels in <x0> and <x1>.
- void renderAALine(SplashBitmap *aaBuf, int *x0, int *x1, int y);
-
- // Clips an anti-aliased line by setting pixels to zero. On entry,
- // all non-zero pixels are between <x0> and <x1>. This function
- // will update <x0> and <x1>.
- void clipAALine(SplashBitmap *aaBuf, int *x0, int *x1, int y);
+ // Like getSpan(), but uses the values 0 and 255 only. Writes 255
+ // for all pixels which include non-zero area inside the path.
+ void getSpanBinary(Guchar *line, int y, int x0, int x1);
private:
- void computeIntersections();
- void addIntersection(double segYMin, double segYMax,
- Guint segFlags,
- int y, int x0, int x1);
+ inline void addArea(Guchar *line, int x, SplashCoord a);
+ void drawTrapezoid(Guchar *line, int xMin, int xMax,
+ SplashCoord y0, SplashCoord y1,
+ SplashCoord xa0, SplashCoord xa1, SplashCoord dydxa,
+ SplashCoord xb0, SplashCoord xb1, SplashCoord dydxb);
+ SplashCoord areaLeft(int xp,
+ SplashCoord x0, SplashCoord y0,
+ SplashCoord x1, SplashCoord y1,
+ SplashCoord dydx);
+ SplashCoord areaRight(int xp,
+ SplashCoord x0, SplashCoord y0,
+ SplashCoord x1, SplashCoord y1,
+ SplashCoord dydx);
+ void drawRectangle(Guchar *line, int xMin, int xMax,
+ SplashCoord y0, SplashCoord y1,
+ SplashCoord x0, SplashCoord x1);
+ void sortActiveSegs();
+ void insertActiveSeg(SplashXPathSeg *seg);
SplashXPath *xPath;
GBool eo;
- int xMin, yMin, xMax, yMax;
- GBool partialClip;
-
- SplashIntersect *allInter; // array of intersections
- int allInterLen; // number of intersections in <allInter>
- int allInterSize; // size of the <allInter> array
- int *inter; // indexes into <allInter> for each y value
- int interY; // current y value - used by getNextSpan
- int interIdx; // current index into <inter> - used by
- // getNextSpan
- int interCount; // current EO/NZWN counter - used by
- // getNextSpan
+ int yMin, yMax;
+
+ GList *activeSegs; // [SplashXPathSeg]
+ int nextSeg;
+ int yNext;
};
#endif
diff --git a/splash/vms_make.com b/splash/vms_make.com
deleted file mode 100644
index e69de29..0000000
--- a/splash/vms_make.com
+++ /dev/null