[poppler] Branch 'xpdf303merge' - poppler/GfxState.cc poppler/GfxState.h poppler/GlobalParams.cc poppler/GlobalParams.h poppler/GlobalParamsWin.cc poppler/PDFDoc.cc poppler/SplashOutputDev.cc poppler/SplashOutputDev.h splash/Splash.cc splash/SplashClip.cc splash/Splash.h splash/SplashState.cc splash/SplashState.h splash/SplashXPathScanner.cc splash/SplashXPathScanner.h
Albert Astals Cid
aacid at kemper.freedesktop.org
Sat Jan 7 08:14:44 PST 2012
poppler/GfxState.cc | 94 +-
poppler/GfxState.h | 17
poppler/GlobalParams.cc | 7
poppler/GlobalParams.h | 3
poppler/GlobalParamsWin.cc | 2
poppler/PDFDoc.cc | 2
poppler/SplashOutputDev.cc | 134 +++
poppler/SplashOutputDev.h | 8
splash/Splash.cc | 1658 ++++++++++++++++++++++++++++++-------------
splash/Splash.h | 42 -
splash/SplashClip.cc | 57 -
splash/SplashState.cc | 49 +
splash/SplashState.h | 12
splash/SplashXPathScanner.cc | 474 +++++++-----
splash/SplashXPathScanner.h | 24
15 files changed, 1845 insertions(+), 738 deletions(-)
New commits:
commit 34ae382915d9d9b2b3c015fee3c24907a6b52b8b
Author: Albert Astals Cid <aacid at kde.org>
Date: Sat Jan 7 17:14:05 2012 +0100
xpdf303: Merge some stuff in Splash [Thomas Freitag]
1. merge the complete pipe changes
a) including the overprint implementation from Derek used by pipe
b) including the transfer function implementation
2. Two changes (not really a merge) to get it compiled under windows (in
GlobalParams.cc & PDFDoc.cc)
3. merge fill and stroke changes
a) including merge of SplashClip.cc
b) including merge of SplashXPathScanner.cc
diff --git a/poppler/GfxState.cc b/poppler/GfxState.cc
index 67c54b5..224b9cf 100644
--- a/poppler/GfxState.cc
+++ b/poppler/GfxState.cc
@@ -213,6 +213,7 @@ cmsHPROFILE GfxColorSpace::getDisplayProfile() {
//------------------------------------------------------------------------
GfxColorSpace::GfxColorSpace() {
+ overprintMask = 0x0f;
}
GfxColorSpace::~GfxColorSpace() {
@@ -1857,6 +1858,7 @@ GfxIndexedColorSpace::GfxIndexedColorSpace(GfxColorSpace *baseA,
indexHigh = indexHighA;
lookup = (Guchar *)gmallocn((indexHigh + 1) * base->getNComps(),
sizeof(Guchar));
+ overprintMask = base->getOverprintMask();
}
GfxIndexedColorSpace::~GfxIndexedColorSpace() {
@@ -2049,8 +2051,29 @@ GfxSeparationColorSpace::GfxSeparationColorSpace(GooString *nameA,
alt = altA;
func = funcA;
nonMarking = !name->cmp("None");
-}
-
+ if (!name->cmp("Cyan")) {
+ overprintMask = 0x01;
+ } else if (!name->cmp("Magenta")) {
+ overprintMask = 0x02;
+ } else if (!name->cmp("Yellow")) {
+ overprintMask = 0x04;
+ } else if (!name->cmp("Black")) {
+ overprintMask = 0x08;
+ }
+}
+
+GfxSeparationColorSpace::GfxSeparationColorSpace(GooString *nameA,
+ GfxColorSpace *altA,
+ Function *funcA,
+ GBool nonMarkingA,
+ Guint overprintMaskA) {
+ name = nameA;
+ alt = altA;
+ func = funcA;
+ nonMarking = nonMarkingA;
+ overprintMask = overprintMaskA;
+}
+
GfxSeparationColorSpace::~GfxSeparationColorSpace() {
delete name;
delete alt;
@@ -2058,7 +2081,8 @@ GfxSeparationColorSpace::~GfxSeparationColorSpace() {
}
GfxColorSpace *GfxSeparationColorSpace::copy() {
- return new GfxSeparationColorSpace(name->copy(), alt->copy(), func->copy());
+ return new GfxSeparationColorSpace(name->copy(), alt->copy(), func->copy(),
+ nonMarking, overprintMask);
}
//~ handle the 'All' and 'None' colorants
@@ -2153,15 +2177,54 @@ void GfxSeparationColorSpace::getDefaultColor(GfxColor *color) {
// GfxDeviceNColorSpace
//------------------------------------------------------------------------
-GfxDeviceNColorSpace::GfxDeviceNColorSpace(int nCompsA,
- GfxColorSpace *altA,
- Function *funcA) {
+GfxDeviceNColorSpace::GfxDeviceNColorSpace(int nCompsA,
+ GooString **namesA,
+ GfxColorSpace *altA,
+ Function *funcA) {
+ int i;
+
nComps = nCompsA;
alt = altA;
func = funcA;
- nonMarking = gFalse;
-}
-
+ nonMarking = gTrue;
+ overprintMask = 0;
+ for (i = 0; i < nComps; ++i) {
+ names[i] = namesA[i];
+ if (names[i]->cmp("None")) {
+ nonMarking = gFalse;
+ }
+ if (!names[i]->cmp("Cyan")) {
+ overprintMask |= 0x01;
+ } else if (!names[i]->cmp("Magenta")) {
+ overprintMask |= 0x02;
+ } else if (!names[i]->cmp("Yellow")) {
+ overprintMask |= 0x04;
+ } else if (!names[i]->cmp("Black")) {
+ overprintMask |= 0x08;
+ } else {
+ overprintMask = 0x0f;
+ }
+ }
+}
+
+GfxDeviceNColorSpace::GfxDeviceNColorSpace(int nCompsA,
+ GooString **namesA,
+ GfxColorSpace *altA,
+ Function *funcA,
+ GBool nonMarkingA,
+ Guint overprintMaskA) {
+ int i;
+
+ nComps = nCompsA;
+ alt = altA;
+ func = funcA;
+ nonMarking = nonMarkingA;
+ overprintMask = overprintMaskA;
+ for (i = 0; i < nComps; ++i) {
+ names[i] = namesA[i]->copy();
+ }
+}
+
GfxDeviceNColorSpace::~GfxDeviceNColorSpace() {
int i;
@@ -2173,15 +2236,8 @@ GfxDeviceNColorSpace::~GfxDeviceNColorSpace() {
}
GfxColorSpace *GfxDeviceNColorSpace::copy() {
- GfxDeviceNColorSpace *cs;
- int i;
-
- cs = new GfxDeviceNColorSpace(nComps, alt->copy(), func->copy());
- for (i = 0; i < nComps; ++i) {
- cs->names[i] = names[i]->copy();
- }
- cs->nonMarking = nonMarking;
- return cs;
+ return new GfxDeviceNColorSpace(nComps, names, alt->copy(), func->copy(),
+ nonMarking, overprintMask);
}
//~ handle the 'None' colorant
@@ -2229,7 +2285,7 @@ GfxColorSpace *GfxDeviceNColorSpace::parse(Array *arr, Gfx *gfx, int recursion)
goto err4;
}
obj1.free();
- cs = new GfxDeviceNColorSpace(nCompsA, altA, funcA);
+ cs = new GfxDeviceNColorSpace(nCompsA, namesA, altA, funcA);
cs->nonMarking = gTrue;
for (i = 0; i < nCompsA; ++i) {
cs->names[i] = namesA[i];
diff --git a/poppler/GfxState.h b/poppler/GfxState.h
index 95aa434..632acc1 100644
--- a/poppler/GfxState.h
+++ b/poppler/GfxState.h
@@ -227,6 +227,9 @@ public:
// mark the page (e.g., the "None" colorant).
virtual GBool isNonMarking() { return gFalse; }
+ // Return the color space's overprint mask.
+ Guint getOverprintMask() { return overprintMask; }
+
// Return the number of color space modes
static int getNumColorSpaceModes();
@@ -243,6 +246,9 @@ public:
// result will be a cmsHPROFILE
static void *getDisplayProfile();
#endif
+protected:
+
+ Guint overprintMask;
};
//------------------------------------------------------------------------
@@ -580,6 +586,10 @@ public:
private:
+ GfxSeparationColorSpace(GooString *nameA, GfxColorSpace *altA,
+ Function *funcA, GBool nonMarkingA,
+ Guint overprintMaskA);
+
GooString *name; // colorant name
GfxColorSpace *alt; // alternate color space
Function *func; // tint transform (into alternate color space)
@@ -593,7 +603,8 @@ private:
class GfxDeviceNColorSpace: public GfxColorSpace {
public:
- GfxDeviceNColorSpace(int nCompsA, GfxColorSpace *alt, Function *func);
+ GfxDeviceNColorSpace(int nCompsA, GooString **namesA,
+ GfxColorSpace *alt, Function *func);
virtual ~GfxDeviceNColorSpace();
virtual GfxColorSpace *copy();
virtual GfxColorSpaceMode getMode() { return csDeviceN; }
@@ -617,6 +628,10 @@ public:
private:
+ GfxDeviceNColorSpace(int nCompsA, GooString **namesA,
+ GfxColorSpace *alt, Function *func,
+ GBool nonMarkingA, Guint overprintMaskA);
+
int nComps; // number of components
GooString // colorant names
*names[gfxColorMaxComps];
diff --git a/poppler/GlobalParams.cc b/poppler/GlobalParams.cc
index dc08ccc..5757acc 100644
--- a/poppler/GlobalParams.cc
+++ b/poppler/GlobalParams.cc
@@ -694,6 +694,7 @@ GlobalParams::GlobalParams(const char *customPopplerDataDir)
screenGamma = 1.0;
screenBlackThreshold = 0.0;
screenWhiteThreshold = 1.0;
+ overprintPreview = gFalse;
mapNumericCharNames = gTrue;
mapUnknownCharNames = gFalse;
printCommands = gFalse;
@@ -1922,6 +1923,12 @@ void GlobalParams::setScreenWhiteThreshold(double whiteThreshold)
unlockGlobalParams;
}
+void GlobalParams::setOverprintPreview(GBool overprintPreviewA) {
+ lockGlobalParams;
+ overprintPreview = overprintPreviewA;
+ unlockGlobalParams;
+}
+
void GlobalParams::setMapNumericCharNames(GBool map) {
lockGlobalParams;
mapNumericCharNames = map;
diff --git a/poppler/GlobalParams.h b/poppler/GlobalParams.h
index 815269b..f4cb6c1 100644
--- a/poppler/GlobalParams.h
+++ b/poppler/GlobalParams.h
@@ -213,6 +213,7 @@ public:
double getScreenGamma();
double getScreenBlackThreshold();
double getScreenWhiteThreshold();
+ GBool getOverprintPreview() { return overprintPreview; }
GBool getMapNumericCharNames();
GBool getMapUnknownCharNames();
GBool getPrintCommands();
@@ -259,6 +260,7 @@ public:
void setScreenGamma(double gamma);
void setScreenBlackThreshold(double blackThreshold);
void setScreenWhiteThreshold(double whiteThreshold);
+ void setOverprintPreview(GBool overprintPreviewA);
void setMapNumericCharNames(GBool map);
void setMapUnknownCharNames(GBool map);
void setPrintCommands(GBool printCommandsA);
@@ -345,6 +347,7 @@ private:
double screenGamma; // screen gamma correction
double screenBlackThreshold; // screen black clamping threshold
double screenWhiteThreshold; // screen white clamping threshold
+ GBool overprintPreview; // enable overprint preview
GBool mapNumericCharNames; // map numeric char names (from font subsets)?
GBool mapUnknownCharNames; // map unknown char names?
GBool printCommands; // print the drawing commands
diff --git a/poppler/GlobalParamsWin.cc b/poppler/GlobalParamsWin.cc
index 23ea619..5af717a 100644
--- a/poppler/GlobalParamsWin.cc
+++ b/poppler/GlobalParamsWin.cc
@@ -235,7 +235,7 @@ void GlobalParams::setupBaseFonts(char * dir)
GetWindowsFontDir(winFontDir, sizeof(winFontDir));
for (int i = 0; displayFontTab[i].name; ++i) {
- char *fontName = displayFontTab[i].name;
+ char *fontName = (char *) displayFontTab[i].name;
if (displayFonts->lookup(fontName))
continue;
diff --git a/poppler/PDFDoc.cc b/poppler/PDFDoc.cc
index ec0f9be..608b3ab 100644
--- a/poppler/PDFDoc.cc
+++ b/poppler/PDFDoc.cc
@@ -192,7 +192,7 @@ PDFDoc::PDFDoc(wchar_t *fileNameA, int fileNameLen, GooString *ownerPassword,
version.dwOSVersionInfoSize = sizeof(version);
GetVersionEx(&version);
if (version.dwPlatformId == VER_PLATFORM_WIN32_NT) {
- if (_wstat(fileName2, &buf) == 0) {
+ if (_wstat(fileNameU, &buf) == 0) {
size = buf.st_size;
}
file = _wfopen(fileNameU, L"rb");
diff --git a/poppler/SplashOutputDev.cc b/poppler/SplashOutputDev.cc
index 11d8036..52e2bef 100644
--- a/poppler/SplashOutputDev.cc
+++ b/poppler/SplashOutputDev.cc
@@ -1701,6 +1701,41 @@ SplashPattern *SplashOutputDev::getColor(GfxGray gray, GfxRGB *rgb) {
return pattern;
}
+void SplashOutputDev::setOverprintMask(GfxColorSpace *colorSpace,
+ GBool overprintFlag,
+ int overprintMode,
+ GfxColor *singleColor) {
+#if SPLASH_CMYK
+ Guint mask;
+ GfxCMYK cmyk;
+
+ if (overprintFlag && globalParams->getOverprintPreview()) {
+ mask = colorSpace->getOverprintMask();
+ if (singleColor && overprintMode &&
+ (colorSpace->getMode() == csDeviceCMYK ||
+ (colorSpace->getMode() == csICCBased &&
+ colorSpace->getNComps() == 4))) {
+ colorSpace->getCMYK(singleColor, &cmyk);
+ if (cmyk.c == 0) {
+ mask &= ~1;
+ }
+ if (cmyk.m == 0) {
+ mask &= ~2;
+ }
+ if (cmyk.y == 0) {
+ mask &= ~4;
+ }
+ if (cmyk.k == 0) {
+ mask &= ~8;
+ }
+ }
+ } else {
+ mask = 0xffffffff;
+ }
+ splash->setOverprintMask(mask);
+#endif
+}
+
void SplashOutputDev::updateBlendMode(GfxState *state) {
splash->setBlendFunc(splashOutBlendFuncs[state->getBlendMode()]);
}
@@ -1725,6 +1760,51 @@ void SplashOutputDev::updateOverprintMode(GfxState *state) {
splash->setOverprintMode(state->getOverprintMode());
}
+void SplashOutputDev::updateTransfer(GfxState *state) {
+ Function **transfer;
+ Guchar red[256], green[256], blue[256], gray[256];
+ double x, y;
+ int i;
+
+ transfer = state->getTransfer();
+ if (transfer[0] &&
+ transfer[0]->getInputSize() == 1 &&
+ transfer[0]->getOutputSize() == 1) {
+ if (transfer[1] &&
+ transfer[1]->getInputSize() == 1 &&
+ transfer[1]->getOutputSize() == 1 &&
+ transfer[2] &&
+ transfer[2]->getInputSize() == 1 &&
+ transfer[2]->getOutputSize() == 1 &&
+ transfer[3] &&
+ transfer[3]->getInputSize() == 1 &&
+ transfer[3]->getOutputSize() == 1) {
+ for (i = 0; i < 256; ++i) {
+ x = i / 255.0;
+ transfer[0]->transform(&x, &y);
+ red[i] = (Guchar)(y * 255.0 + 0.5);
+ transfer[1]->transform(&x, &y);
+ green[i] = (Guchar)(y * 255.0 + 0.5);
+ transfer[2]->transform(&x, &y);
+ blue[i] = (Guchar)(y * 255.0 + 0.5);
+ transfer[3]->transform(&x, &y);
+ gray[i] = (Guchar)(y * 255.0 + 0.5);
+ }
+ } else {
+ for (i = 0; i < 256; ++i) {
+ x = i / 255.0;
+ transfer[0]->transform(&x, &y);
+ red[i] = green[i] = blue[i] = gray[i] = (Guchar)(y * 255.0 + 0.5);
+ }
+ }
+ } else {
+ for (i = 0; i < 256; ++i) {
+ red[i] = green[i] = blue[i] = gray[i] = (Guchar)i;
+ }
+ }
+ splash->setTransfer(red, green, blue, gray);
+}
+
void SplashOutputDev::updateFont(GfxState * /*state*/) {
needFontUpdate = gTrue;
}
@@ -2011,7 +2091,9 @@ void SplashOutputDev::stroke(GfxState *state) {
if (state->getStrokeColorSpace()->isNonMarking()) {
return;
}
- path = convertPath(state, state->getPath());
+ setOverprintMask(state->getStrokeColorSpace(), state->getStrokeOverprint(),
+ state->getOverprintMode(), state->getStrokeColor());
+ path = convertPath(state, state->getPath(), gFalse);
splash->stroke(path);
delete path;
}
@@ -2022,7 +2104,9 @@ void SplashOutputDev::fill(GfxState *state) {
if (state->getFillColorSpace()->isNonMarking()) {
return;
}
- path = convertPath(state, state->getPath());
+ setOverprintMask(state->getFillColorSpace(), state->getFillOverprint(),
+ state->getOverprintMode(), state->getFillColor());
+ path = convertPath(state, state->getPath(), gTrue);
splash->fill(path, gFalse);
delete path;
}
@@ -2033,7 +2117,9 @@ void SplashOutputDev::eoFill(GfxState *state) {
if (state->getFillColorSpace()->isNonMarking()) {
return;
}
- path = convertPath(state, state->getPath());
+ setOverprintMask(state->getFillColorSpace(), state->getFillOverprint(),
+ state->getOverprintMode(), state->getFillColor());
+ path = convertPath(state, state->getPath(), gTrue);
splash->fill(path, gTrue);
delete path;
}
@@ -2041,7 +2127,7 @@ void SplashOutputDev::eoFill(GfxState *state) {
void SplashOutputDev::clip(GfxState *state) {
SplashPath *path;
- path = convertPath(state, state->getPath());
+ path = convertPath(state, state->getPath(), gTrue);
splash->clipToPath(path, gFalse);
delete path;
}
@@ -2049,7 +2135,7 @@ void SplashOutputDev::clip(GfxState *state) {
void SplashOutputDev::eoClip(GfxState *state) {
SplashPath *path;
- path = convertPath(state, state->getPath());
+ path = convertPath(state, state->getPath(), gTrue);
splash->clipToPath(path, gTrue);
delete path;
}
@@ -2057,22 +2143,24 @@ void SplashOutputDev::eoClip(GfxState *state) {
void SplashOutputDev::clipToStrokePath(GfxState *state) {
SplashPath *path, *path2;
- path = convertPath(state, state->getPath());
- path2 = splash->makeStrokePath(path);
+ path = convertPath(state, state->getPath(), gFalse);
+ path2 = splash->makeStrokePath(path, state->getLineWidth());
delete path;
splash->clipToPath(path2, gFalse);
delete path2;
}
-SplashPath *SplashOutputDev::convertPath(GfxState * /*state*/, GfxPath *path) {
+SplashPath *SplashOutputDev::convertPath(GfxState *state, GfxPath *path,
+ GBool dropEmptySubpaths) {
SplashPath *sPath;
GfxSubpath *subpath;
- int i, j;
+ int n, i, j;
+ n = dropEmptySubpaths ? 1 : 0;
sPath = new SplashPath();
for (i = 0; i < path->getNumSubpaths(); ++i) {
subpath = path->getSubpath(i);
- if (subpath->getNumPoints() > 0) {
+ if (subpath->getNumPoints() > n) {
sPath->moveTo((SplashCoord)subpath->getX(0),
(SplashCoord)subpath->getY(0));
j = 1;
@@ -2126,6 +2214,8 @@ void SplashOutputDev::drawChar(GfxState *state, double x, double y,
// fill
if (!(render & 1)) {
if (!haveCSPattern && !state->getFillColorSpace()->isNonMarking()) {
+ setOverprintMask(state->getFillColorSpace(), state->getFillOverprint(),
+ state->getOverprintMode(), state->getFillColor());
splash->fillChar((SplashCoord)x, (SplashCoord)y, code, font);
}
}
@@ -2135,6 +2225,10 @@ void SplashOutputDev::drawChar(GfxState *state, double x, double y,
if (!state->getStrokeColorSpace()->isNonMarking()) {
if ((path = font->getGlyphPath(code))) {
path->offset((SplashCoord)x, (SplashCoord)y);
+ setOverprintMask(state->getStrokeColorSpace(),
+ state->getStrokeOverprint(),
+ state->getOverprintMode(),
+ state->getStrokeColor());
splash->stroke(path);
delete path;
}
@@ -2264,7 +2358,7 @@ GBool SplashOutputDev::beginType3Char(GfxState *state, double x, double y,
if (t3Font->cacheTags != NULL) {
if ((t3Font->cacheTags[i+j].mru & 0x8000) &&
t3Font->cacheTags[i+j].code == code) {
- drawType3Glyph(t3Font, &t3Font->cacheTags[i+j],
+ drawType3Glyph(state, t3Font, &t3Font->cacheTags[i+j],
t3Font->cacheData + (i+j) * t3Font->glyphSize);
return gTrue;
}
@@ -2298,7 +2392,7 @@ void SplashOutputDev::endType3Char(GfxState *state) {
state->setCTM(ctm[0], ctm[1], ctm[2], ctm[3],
t3GlyphStack->origCTM4, t3GlyphStack->origCTM5);
updateCTM(state, 0, 0, 0, 0, 0, 0);
- drawType3Glyph(t3GlyphStack->cache,
+ drawType3Glyph(state, t3GlyphStack->cache,
t3GlyphStack->cacheTag, t3GlyphStack->cacheData);
}
t3gs = t3GlyphStack;
@@ -2431,10 +2525,12 @@ void SplashOutputDev::type3D1(GfxState *state, double wx, double wy,
updateCTM(state, 0, 0, 0, 0, 0, 0);
}
-void SplashOutputDev::drawType3Glyph(T3FontCache *t3Font,
+void SplashOutputDev::drawType3Glyph(GfxState *state, T3FontCache *t3Font,
T3FontCacheTag * /*tag*/, Guchar *data) {
SplashGlyphBitmap glyph;
+ setOverprintMask(state->getFillColorSpace(), state->getFillOverprint(),
+ state->getOverprintMode(), state->getFillColor());
glyph.x = -t3Font->glyphX;
glyph.y = -t3Font->glyphY;
glyph.w = t3Font->glyphW;
@@ -2523,6 +2619,8 @@ void SplashOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
if (state->getFillColorSpace()->isNonMarking()) {
return;
}
+ setOverprintMask(state->getFillColorSpace(), state->getFillOverprint(),
+ state->getOverprintMode(), state->getFillColor());
ctm = state->getCTM();
for (int i = 0; i < 6; ++i) {
@@ -2919,6 +3017,8 @@ void SplashOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
Guchar pix;
int n, i;
+ setOverprintMask(colorMap->getColorSpace(), state->getFillOverprint(),
+ state->getOverprintMode(), NULL);
ctm = state->getCTM();
for (i = 0; i < 6; ++i) {
if (!isfinite(ctm[i])) return;
@@ -3158,6 +3258,8 @@ void SplashOutputDev::drawMaskedImage(GfxState *state, Object *ref,
Guchar pix;
int n, i;
+ setOverprintMask(colorMap->getColorSpace(), state->getFillOverprint(),
+ state->getOverprintMode(), NULL);
// If the mask is higher resolution than the image, use
// drawSoftMaskedImage() instead.
if (maskWidth > width || maskHeight > height) {
@@ -3327,6 +3429,8 @@ void SplashOutputDev::drawSoftMaskedImage(GfxState *state, Object *ref,
Guchar pix;
int n, i;
+ setOverprintMask(colorMap->getColorSpace(), state->getFillOverprint(),
+ state->getOverprintMode(), NULL);
ctm = state->getCTM();
for (i = 0; i < 6; ++i) {
if (!isfinite(ctm[i])) return;
@@ -3599,6 +3703,7 @@ void SplashOutputDev::paintTransparencyGroup(GfxState * /*state*/, double * /*bb
// paint the transparency group onto the parent bitmap
// - the clip path was set in the parent's state)
+ splash->setOverprintMask(0xffffffff);
splash->composite(tBitmap, 0, 0, tx, ty,
tBitmap->getWidth(), tBitmap->getHeight(),
gFalse, !isolated);
@@ -3948,6 +4053,7 @@ GBool SplashOutputDev::tilingPatternFill(GfxState *state, Catalog *catalog, Obje
matc[1] = ctm[1];
matc[2] = ctm[2];
matc[3] = ctm[3];
+ splash->setOverprintMask(0xffffffff);
splash->drawImage(&tilingBitmapSrc, &imgData, colorMode, gTrue, result_width, result_height, matc);
delete tBitmap;
delete gfx;
@@ -4032,7 +4138,7 @@ GBool SplashOutputDev::univariateShadedFill(GfxState *state, SplashUnivariatePat
state->lineTo(xMax, yMax);
state->lineTo(xMin, yMax);
state->closePath();
- path = convertPath(state, state->getPath());
+ path = convertPath(state, state->getPath(), gTrue);
retVal = (splash->shadedFill(path, pattern->getShading()->getHasBBox(), pattern) == splashOk);
state->clearPath();
diff --git a/poppler/SplashOutputDev.h b/poppler/SplashOutputDev.h
index 49f2b12..8cfdbb1 100644
--- a/poppler/SplashOutputDev.h
+++ b/poppler/SplashOutputDev.h
@@ -264,6 +264,7 @@ public:
virtual void updateFillOverprint(GfxState *state);
virtual void updateStrokeOverprint(GfxState *state);
virtual void updateOverprintMode(GfxState *state);
+ virtual void updateTransfer(GfxState *state);
//----- update text state
virtual void updateFont(GfxState *state);
@@ -389,9 +390,12 @@ private:
#else
SplashPattern *getColor(GfxGray gray, GfxRGB *rgb);
#endif
- SplashPath *convertPath(GfxState *state, GfxPath *path);
+ void setOverprintMask(GfxColorSpace *colorSpace, GBool overprintFlag,
+ int overprintMode, GfxColor *singleColor);
+ SplashPath *convertPath(GfxState *state, GfxPath *path,
+ GBool dropEmptySubpaths);
void doUpdateFont(GfxState *state);
- void drawType3Glyph(T3FontCache *t3Font,
+ void drawType3Glyph(GfxState *state, T3FontCache *t3Font,
T3FontCacheTag *tag, Guchar *data);
static GBool imageMaskSrc(void *data, SplashColorPtr line);
static GBool imageSrc(void *data, SplashColorPtr colorLine,
diff --git a/splash/Splash.cc b/splash/Splash.cc
index 2556652..5091edb 100644
--- a/splash/Splash.cc
+++ b/splash/Splash.cc
@@ -51,6 +51,8 @@
//------------------------------------------------------------------------
+#define splashAAGamma 1.5
+
// distance of Bezier control point from center for circle approximation
// = (4 * (sqrt(2) - 1) / 3) * r
#define bezierCircle ((SplashCoord)0.55228475)
@@ -61,6 +63,11 @@ static inline Guchar div255(int x) {
return (Guchar)((x + (x >> 8) + 0x80) >> 8);
}
+// Clip x to lie in [0, 255].
+static inline Guchar clip255(int x) {
+ return x < 0 ? 0 : x > 255 ? 255 : x;
+}
+
template<typename T>
inline void Guswap( T&a, T&b ) { T tmp = a; a=b; b=tmp; }
@@ -78,9 +85,8 @@ struct SplashPipe {
SplashPattern *pattern;
// source alpha and color
- SplashCoord aInput;
+ Guchar aInput;
GBool usesShape;
- Guchar aSrc;
SplashColorPtr cSrc;
SplashColor cSrcVal;
@@ -96,18 +102,17 @@ struct SplashPipe {
Guchar *destAlphaPtr;
// shape
- SplashCoord shape;
+ Guchar shape;
// result alpha and color
GBool noTransparency;
SplashPipeResultColorCtrl resultColorCtrl;
// non-isolated group correction
- int nonIsolatedGroup;
+ GBool nonIsolatedGroup;
- // stroke / fill operation and pattern for calculate overprint
- GBool stroke;
- SplashPattern *overprintPattern;
+ // the "run" function
+ void (Splash::*run)(SplashPipe *pipe);
};
SplashPipeResultColorCtrl Splash::pipeResultColorNoAlphaBlend[] = {
@@ -192,8 +197,8 @@ inline void Splash::updateModY(int y) {
inline void Splash::pipeInit(SplashPipe *pipe, int x, int y,
SplashPattern *pattern, SplashColorPtr cSrc,
- SplashCoord aInput, GBool usesShape,
- GBool nonIsolatedGroup, SplashPattern *opPattern, GBool strokeA) {
+ Guchar aInput, GBool usesShape,
+ GBool nonIsolatedGroup) {
pipeSetXY(pipe, x, y);
pipe->pattern = NULL;
@@ -211,18 +216,11 @@ inline void Splash::pipeInit(SplashPipe *pipe, int x, int y,
// source alpha
pipe->aInput = aInput;
- if (!state->softMask) {
- if (usesShape) {
- pipe->aInput *= 255;
- } else {
- pipe->aSrc = (Guchar)splashRound(pipe->aInput * 255);
- }
- }
pipe->usesShape = usesShape;
// result alpha
- if (aInput == 1 && !state->softMask && !usesShape &&
- !state->inNonIsolatedGroup) {
+ if (aInput == 255 && !state->softMask && !usesShape &&
+ !state->inNonIsolatedGroup && !nonIsolatedGroup) {
pipe->noTransparency = gTrue;
} else {
pipe->noTransparency = gFalse;
@@ -239,19 +237,58 @@ inline void Splash::pipeInit(SplashPipe *pipe, int x, int y,
}
// non-isolated group correction
- if (nonIsolatedGroup) {
- pipe->nonIsolatedGroup = splashColorModeNComps[bitmap->mode];
- } else {
- pipe->nonIsolatedGroup = 0;
+ pipe->nonIsolatedGroup = nonIsolatedGroup;
+
+ // select the 'run' function
+ pipe->run = &Splash::pipeRun;
+ if (!pipe->pattern && pipe->noTransparency && !state->blendFunc) {
+ if (bitmap->mode == splashModeMono1 && !pipe->destAlphaPtr) {
+ pipe->run = &Splash::pipeRunSimpleMono1;
+ } else if (bitmap->mode == splashModeMono8 && pipe->destAlphaPtr) {
+ pipe->run = &Splash::pipeRunSimpleMono8;
+ } else if (bitmap->mode == splashModeRGB8 && pipe->destAlphaPtr) {
+ pipe->run = &Splash::pipeRunSimpleRGB8;
+ } else if (bitmap->mode == splashModeXBGR8 && pipe->destAlphaPtr) {
+ pipe->run = &Splash::pipeRunSimpleXBGR8;
+ } else if (bitmap->mode == splashModeBGR8 && pipe->destAlphaPtr) {
+ pipe->run = &Splash::pipeRunSimpleBGR8;
+#if SPLASH_CMYK
+ } else if (bitmap->mode == splashModeCMYK8 && pipe->destAlphaPtr) {
+ pipe->run = &Splash::pipeRunSimpleCMYK8;
+#endif
+ }
+ } else if (!pipe->pattern && !pipe->noTransparency && !state->softMask &&
+ pipe->usesShape &&
+ !(state->inNonIsolatedGroup && alpha0Bitmap->alpha) &&
+ !state->blendFunc && !pipe->nonIsolatedGroup) {
+ if (bitmap->mode == splashModeMono1 && !pipe->destAlphaPtr) {
+ pipe->run = &Splash::pipeRunAAMono1;
+ } else if (bitmap->mode == splashModeMono8 && pipe->destAlphaPtr) {
+ pipe->run = &Splash::pipeRunAAMono8;
+ } else if (bitmap->mode == splashModeRGB8 && pipe->destAlphaPtr) {
+ pipe->run = &Splash::pipeRunAARGB8;
+ } else if (bitmap->mode == splashModeXBGR8 && pipe->destAlphaPtr) {
+ pipe->run = &Splash::pipeRunAAXBGR8;
+ } else if (bitmap->mode == splashModeBGR8 && pipe->destAlphaPtr) {
+ pipe->run = &Splash::pipeRunAABGR8;
+#if SPLASH_CMYK
+ } else if (bitmap->mode == splashModeCMYK8 && pipe->destAlphaPtr) {
+ pipe->run = &Splash::pipeRunAACMYK8;
+#endif
+ }
}
- pipe->stroke = strokeA;
- pipe->overprintPattern = opPattern;
}
-inline void Splash::pipeRun(SplashPipe *pipe) {
- Guchar aSrc, aDest, alpha2, alpha0, aResult;
- SplashColor cDest, cBlend;
+// 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;
+#if SPLASH_CMYK
+ SplashColor cSrc2, cDest2;
+#endif
//----- source color
@@ -272,7 +309,7 @@ inline void Splash::pipeRun(SplashPipe *pipe) {
switch (bitmap->mode) {
case splashModeMono1:
- cResult0 = pipe->cSrc[0];
+ cResult0 = state->grayTransfer[pipe->cSrc[0]];
if (state->screen->test(pipe->x, pipe->y, cResult0)) {
*pipe->destColorPtr |= pipe->destColorMask;
} else {
@@ -284,45 +321,39 @@ inline void Splash::pipeRun(SplashPipe *pipe) {
}
break;
case splashModeMono8:
- *pipe->destColorPtr++ = pipe->cSrc[0];
+ *pipe->destColorPtr++ = state->grayTransfer[pipe->cSrc[0]];
break;
case splashModeRGB8:
- *pipe->destColorPtr++ = pipe->cSrc[0];
- *pipe->destColorPtr++ = pipe->cSrc[1];
- *pipe->destColorPtr++ = pipe->cSrc[2];
+ *pipe->destColorPtr++ = state->rgbTransferR[pipe->cSrc[0]];
+ *pipe->destColorPtr++ = state->rgbTransferG[pipe->cSrc[1]];
+ *pipe->destColorPtr++ = state->rgbTransferB[pipe->cSrc[2]];
break;
case splashModeXBGR8:
- *pipe->destColorPtr++ = pipe->cSrc[2];
- *pipe->destColorPtr++ = pipe->cSrc[1];
- *pipe->destColorPtr++ = pipe->cSrc[0];
+ *pipe->destColorPtr++ = state->rgbTransferB[pipe->cSrc[2]];
+ *pipe->destColorPtr++ = state->rgbTransferG[pipe->cSrc[1]];
+ *pipe->destColorPtr++ = state->rgbTransferR[pipe->cSrc[0]];
*pipe->destColorPtr++ = 255;
break;
case splashModeBGR8:
- *pipe->destColorPtr++ = pipe->cSrc[2];
- *pipe->destColorPtr++ = pipe->cSrc[1];
- *pipe->destColorPtr++ = pipe->cSrc[0];
+ *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 (pipe->overprintPattern != NULL &&
- ((pipe->stroke && state->strokeOverprint) ||
- (!pipe->stroke && state->fillOverprint))) {
- SplashColor cResult;
- cDest[0] = pipe->destColorPtr[0];
- cDest[1] = pipe->destColorPtr[1];
- cDest[2] = pipe->destColorPtr[2];
- cDest[3] = pipe->destColorPtr[3];
- pipe->overprintPattern->overprint(state->overprintMode == 1, pipe->aSrc, pipe->cSrc, 255, cDest, cResult);
- *pipe->destColorPtr++ = cResult[0];
- *pipe->destColorPtr++ = cResult[1];
- *pipe->destColorPtr++ = cResult[2];
- *pipe->destColorPtr++ = cResult[3];
- } else {
- *pipe->destColorPtr++ = pipe->cSrc[0];
- *pipe->destColorPtr++ = pipe->cSrc[1];
- *pipe->destColorPtr++ = pipe->cSrc[2];
- *pipe->destColorPtr++ = pipe->cSrc[3];
+ 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]];
}
+ if (state->overprintMask & 8) {
+ pipe->destColorPtr[3] = state->cmykTransferK[pipe->cSrc[3]];
+ }
+ pipe->destColorPtr += 4;
break;
#endif
}
@@ -372,41 +403,99 @@ inline void Splash::pipeRun(SplashPipe *pipe) {
aDest = 0xff;
}
- //----- blend function
-
- if (state->blendFunc) {
- (*state->blendFunc)(pipe->cSrc, cDest, cBlend, bitmap->mode);
- }
-
//----- source alpha
if (state->softMask) {
if (pipe->usesShape) {
- aSrc = (Guchar)splashRound(pipe->aInput * *pipe->softMaskPtr++
- * pipe->shape);
+ aSrc = div255(div255(pipe->aInput * *pipe->softMaskPtr++) *
+ pipe->shape);
} else {
- aSrc = (Guchar)splashRound(pipe->aInput * *pipe->softMaskPtr++);
+ aSrc = div255(pipe->aInput * *pipe->softMaskPtr++);
}
} else if (pipe->usesShape) {
- // pipe->aInput is premultiplied by 255 in pipeInit
- aSrc = (Guchar)splashRound(pipe->aInput * pipe->shape);
+ aSrc = div255(pipe->aInput * pipe->shape);
+ } else {
+ aSrc = pipe->aInput;
+ }
+
+ //----- non-isolated group correction
+
+ if (pipe->nonIsolatedGroup) {
+ // This path is only used when Splash::composite() is called to
+ // composite a non-isolated group onto the backdrop. In this
+ // case, pipe->shape is the source (group) alpha.
+ if (pipe->shape == 0) {
+ // this value will be multiplied by zero later, so it doesn't
+ // matter what we use
+ cSrc = pipe->cSrc;
+ } else {
+ t = (aDest * 255) / pipe->shape - aDest;
+ switch (bitmap->mode) {
+#if SPLASH_CMYK
+ case splashModeCMYK8:
+ cSrcNonIso[3] = clip255(pipe->cSrc[3] +
+ ((pipe->cSrc[3] - cDest[3]) * t) / 255);
+#endif
+ case splashModeRGB8:
+ case splashModeXBGR8:
+ 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);
+ case splashModeMono1:
+ case splashModeMono8:
+ cSrcNonIso[0] = clip255(pipe->cSrc[0] +
+ ((pipe->cSrc[0] - cDest[0]) * t) / 255);
+ break;
+ }
+ cSrc = cSrcNonIso;
+ }
} else {
- // precomputed in pipeInit
- aSrc = pipe->aSrc;
+ cSrc = pipe->cSrc;
+ }
+
+ //----- blend function
+
+ 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
+#endif
+ (*state->blendFunc)(cSrc, cDest, cBlend, bitmap->mode);
}
//----- result alpha and non-isolated group element correction
if (pipe->noTransparency) {
- alpha2 = aResult = 255;
+ alphaI = alphaIm1 = aResult = 255;
} else {
aResult = aSrc + aDest - div255(aSrc * aDest);
+ // alphaI = alpha_i
+ // alphaIm1 = alpha_(i-1)
if (pipe->alpha0Ptr) {
alpha0 = *pipe->alpha0Ptr++;
- alpha2 = aResult + alpha0 - div255(aResult * alpha0);
+ alphaI = aResult + alpha0 - div255(aResult * alpha0);
+ alphaIm1 = alpha0 + aDest - div255(alpha0 * aDest);
} else {
- alpha2 = aResult;
+ alphaI = aResult;
+ alphaIm1 = aDest;
}
}
@@ -416,151 +505,132 @@ inline void Splash::pipeRun(SplashPipe *pipe) {
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;
#if SPLASH_CMYK
case splashPipeResultColorNoAlphaBlendCMYK:
- cResult3 = div255((255 - aDest) * pipe->cSrc[3] + aDest * cBlend[3]);
-#endif
- case splashPipeResultColorNoAlphaBlendRGB:
- cResult2 = div255((255 - aDest) * pipe->cSrc[2] + aDest * cBlend[2]);
- cResult1 = div255((255 - aDest) * pipe->cSrc[1] + aDest * cBlend[1]);
- case splashPipeResultColorNoAlphaBlendMono:
- cResult0 = div255((255 - aDest) * pipe->cSrc[0] + aDest * cBlend[0]);
+ 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 (alpha2 == 0) {
+ if (alphaI == 0) {
cResult0 = 0;
} else {
- cResult0 = (Guchar)(((alpha2 - aSrc) * cDest[0] +
- aSrc * pipe->cSrc[0]) / alpha2);
+ cResult0 = state->grayTransfer[((alphaI - aSrc) * cDest[0] +
+ aSrc * cSrc[0]) / alphaI];
}
break;
case splashPipeResultColorAlphaNoBlendRGB:
- if (alpha2 == 0) {
+ if (alphaI == 0) {
cResult0 = 0;
cResult1 = 0;
cResult2 = 0;
} else {
- cResult0 = (Guchar)(((alpha2 - aSrc) * cDest[0] +
- aSrc * pipe->cSrc[0]) / alpha2);
- cResult1 = (Guchar)(((alpha2 - aSrc) * cDest[1] +
- aSrc * pipe->cSrc[1]) / alpha2);
- cResult2 = (Guchar)(((alpha2 - aSrc) * cDest[2] +
- aSrc * pipe->cSrc[2]) / alpha2);
+ 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 (alpha2 == 0) {
+ if (alphaI == 0) {
cResult0 = 0;
cResult1 = 0;
cResult2 = 0;
cResult3 = 0;
} else {
- if (pipe->overprintPattern != NULL &&
- ((pipe->stroke && state->strokeOverprint) ||
- (!pipe->stroke && state->fillOverprint))) {
- SplashColor cResult;
- pipe->overprintPattern->overprint(state->overprintMode == 1, aSrc, pipe->cSrc, alpha2, cDest, cResult);
- cResult0 = cResult[0];
- cResult1 = cResult[1];
- cResult2 = cResult[2];
- cResult3 = cResult[3];
- } else {
- cResult0 = (Guchar)(((alpha2 - aSrc) * cDest[0] +
- aSrc * pipe->cSrc[0]) / alpha2);
- cResult1 = (Guchar)(((alpha2 - aSrc) * cDest[1] +
- aSrc * pipe->cSrc[1]) / alpha2);
- cResult2 = (Guchar)(((alpha2 - aSrc) * cDest[2] +
- aSrc * pipe->cSrc[2]) / alpha2);
- cResult3 = (Guchar)(((alpha2 - aSrc) * cDest[3] +
- aSrc * pipe->cSrc[3]) / alpha2);
- }
+ 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 (alpha2 == 0) {
+ if (alphaI == 0) {
cResult0 = 0;
} else {
- cResult0 = (Guchar)(((alpha2 - aSrc) * cDest[0] +
- aSrc * ((255 - aDest) * pipe->cSrc[0] +
- aDest * cBlend[0]) / 255) /
- alpha2);
+ cResult0 = state->grayTransfer[((alphaI - aSrc) * cDest[0] +
+ aSrc * ((255 - alphaIm1) * cSrc[0] +
+ alphaIm1 * cBlend[0]) / 255) /
+ alphaI];
}
break;
case splashPipeResultColorAlphaBlendRGB:
- if (alpha2 == 0) {
+ if (alphaI == 0) {
cResult0 = 0;
cResult1 = 0;
cResult2 = 0;
} else {
- cResult0 = (Guchar)(((alpha2 - aSrc) * cDest[0] +
- aSrc * ((255 - aDest) * pipe->cSrc[0] +
- aDest * cBlend[0]) / 255) /
- alpha2);
- cResult1 = (Guchar)(((alpha2 - aSrc) * cDest[1] +
- aSrc * ((255 - aDest) * pipe->cSrc[1] +
- aDest * cBlend[1]) / 255) /
- alpha2);
- cResult2 = (Guchar)(((alpha2 - aSrc) * cDest[2] +
- aSrc * ((255 - aDest) * pipe->cSrc[2] +
- aDest * cBlend[2]) / 255) /
- alpha2);
+ 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 (alpha2 == 0) {
+ if (alphaI == 0) {
cResult0 = 0;
cResult1 = 0;
cResult2 = 0;
cResult3 = 0;
} else {
- cResult0 = (Guchar)(((alpha2 - aSrc) * cDest[0] +
- aSrc * ((255 - aDest) * pipe->cSrc[0] +
- aDest * cBlend[0]) / 255) /
- alpha2);
- cResult1 = (Guchar)(((alpha2 - aSrc) * cDest[1] +
- aSrc * ((255 - aDest) * pipe->cSrc[1] +
- aDest * cBlend[1]) / 255) /
- alpha2);
- cResult2 = (Guchar)(((alpha2 - aSrc) * cDest[2] +
- aSrc * ((255 - aDest) * pipe->cSrc[2] +
- aDest * cBlend[2]) / 255) /
- alpha2);
- cResult3 = (Guchar)(((alpha2 - aSrc) * cDest[3] +
- aSrc * ((255 - aDest) * pipe->cSrc[3] +
- aDest * cBlend[3]) / 255) /
- alpha2);
+ 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
}
- //----- non-isolated group correction
-
- if (aResult != 0) {
- switch (pipe->nonIsolatedGroup) {
-#if SPLASH_CMYK
- case 4:
- cResult3 += (cResult3 - cDest[3]) * aDest *
- (255 - aResult) / (255 * aResult);
-#endif
- case 3:
- cResult2 += (cResult2 - cDest[2]) * aDest *
- (255 - aResult) / (255 * aResult);
- cResult1 += (cResult1 - cDest[1]) * aDest *
- (255 - aResult) / (255 * aResult);
- case 1:
- cResult0 += (cResult0 - cDest[0]) * aDest *
- (255 - aResult) / (255 * aResult);
- case 0:
- break;
- }
- }
-
//----- write destination pixel
switch (bitmap->mode) {
@@ -596,10 +666,19 @@ inline void Splash::pipeRun(SplashPipe *pipe) {
break;
#if SPLASH_CMYK
case splashModeCMYK8:
- *pipe->destColorPtr++ = cResult0;
- *pipe->destColorPtr++ = cResult1;
- *pipe->destColorPtr++ = cResult2;
- *pipe->destColorPtr++ = cResult3;
+ if (state->overprintMask & 1) {
+ pipe->destColorPtr[0] = cResult0;
+ }
+ if (state->overprintMask & 2) {
+ pipe->destColorPtr[1] = cResult1;
+ }
+ if (state->overprintMask & 4) {
+ pipe->destColorPtr[2] = cResult2;
+ }
+ if (state->overprintMask & 8) {
+ pipe->destColorPtr[3] = cResult3;
+ }
+ pipe->destColorPtr += 4;
break;
#endif
}
@@ -612,6 +691,376 @@ inline void Splash::pipeRun(SplashPipe *pipe) {
++pipe->x;
}
+// special case:
+// !pipe->pattern && pipe->noTransparency && !state->blendFunc &&
+// bitmap->mode == splashModeMono1 && !pipe->destAlphaPtr) {
+void Splash::pipeRunSimpleMono1(SplashPipe *pipe) {
+ Guchar cResult0;
+
+ //----- write destination pixel
+ cResult0 = state->grayTransfer[pipe->cSrc[0]];
+ if (state->screen->test(pipe->x, pipe->y, cResult0)) {
+ *pipe->destColorPtr |= pipe->destColorMask;
+ } else {
+ *pipe->destColorPtr &= ~pipe->destColorMask;
+ }
+ if (!(pipe->destColorMask >>= 1)) {
+ pipe->destColorMask = 0x80;
+ ++pipe->destColorPtr;
+ }
+
+ ++pipe->x;
+}
+
+// special case:
+// !pipe->pattern && pipe->noTransparency && !state->blendFunc &&
+// bitmap->mode == splashModeMono8 && pipe->destAlphaPtr) {
+void Splash::pipeRunSimpleMono8(SplashPipe *pipe) {
+ //----- write destination pixel
+ *pipe->destColorPtr++ = state->grayTransfer[pipe->cSrc[0]];
+ *pipe->destAlphaPtr++ = 255;
+
+ ++pipe->x;
+}
+
+// special case:
+// !pipe->pattern && pipe->noTransparency && !state->blendFunc &&
+// bitmap->mode == splashModeRGB8 && pipe->destAlphaPtr) {
+void Splash::pipeRunSimpleRGB8(SplashPipe *pipe) {
+ //----- write destination pixel
+ *pipe->destColorPtr++ = state->rgbTransferR[pipe->cSrc[0]];
+ *pipe->destColorPtr++ = state->rgbTransferG[pipe->cSrc[1]];
+ *pipe->destColorPtr++ = state->rgbTransferB[pipe->cSrc[2]];
+ *pipe->destAlphaPtr++ = 255;
+
+ ++pipe->x;
+}
+
+// special case:
+// !pipe->pattern && pipe->noTransparency && !state->blendFunc &&
+// bitmap->mode == splashModeXBGR8 && pipe->destAlphaPtr) {
+void Splash::pipeRunSimpleXBGR8(SplashPipe *pipe) {
+ //----- write destination pixel
+ *pipe->destColorPtr++ = state->rgbTransferB[pipe->cSrc[2]];
+ *pipe->destColorPtr++ = state->rgbTransferG[pipe->cSrc[1]];
+ *pipe->destColorPtr++ = state->rgbTransferR[pipe->cSrc[0]];
+ *pipe->destColorPtr++ = 255;
+ *pipe->destAlphaPtr++ = 255;
+
+ ++pipe->x;
+}
+
+// special case:
+// !pipe->pattern && pipe->noTransparency && !state->blendFunc &&
+// bitmap->mode == splashModeBGR8 && pipe->destAlphaPtr) {
+void Splash::pipeRunSimpleBGR8(SplashPipe *pipe) {
+ //----- write destination pixel
+ *pipe->destColorPtr++ = state->rgbTransferB[pipe->cSrc[2]];
+ *pipe->destColorPtr++ = state->rgbTransferG[pipe->cSrc[1]];
+ *pipe->destColorPtr++ = state->rgbTransferR[pipe->cSrc[0]];
+ *pipe->destAlphaPtr++ = 255;
+
+ ++pipe->x;
+}
+
+#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]];
+ }
+ if (state->overprintMask & 8) {
+ pipe->destColorPtr[3] = state->cmykTransferK[pipe->cSrc[3]];
+ }
+ pipe->destColorPtr += 4;
+ *pipe->destAlphaPtr++ = 255;
+
+ ++pipe->x;
+}
+#endif
+
+
+// special case:
+// !pipe->pattern && !pipe->noTransparency && !state->softMask &&
+// pipe->usesShape && !pipe->alpha0Ptr && !state->blendFunc &&
+// !pipe->nonIsolatedGroup &&
+// bitmap->mode == splashModeMono1 && !pipe->destAlphaPtr
+void Splash::pipeRunAAMono1(SplashPipe *pipe) {
+ Guchar aSrc;
+ SplashColor cDest;
+ Guchar cResult0;
+
+ //----- read destination pixel
+ cDest[0] = (*pipe->destColorPtr & pipe->destColorMask) ? 0xff : 0x00;
+
+ //----- source alpha
+ aSrc = div255(pipe->aInput * pipe->shape);
+
+ //----- result color
+ // note: aDest = alpha2 = aResult = 0xff
+ cResult0 = state->grayTransfer[(Guchar)div255((0xff - aSrc) * cDest[0] +
+ aSrc * pipe->cSrc[0])];
+
+ //----- write destination pixel
+ if (state->screen->test(pipe->x, pipe->y, cResult0)) {
+ *pipe->destColorPtr |= pipe->destColorMask;
+ } else {
+ *pipe->destColorPtr &= ~pipe->destColorMask;
+ }
+ if (!(pipe->destColorMask >>= 1)) {
+ pipe->destColorMask = 0x80;
+ ++pipe->destColorPtr;
+ }
+
+ ++pipe->x;
+}
+
+// special case:
+// !pipe->pattern && !pipe->noTransparency && !state->softMask &&
+// pipe->usesShape && !pipe->alpha0Ptr && !state->blendFunc &&
+// !pipe->nonIsolatedGroup &&
+// bitmap->mode == splashModeMono8 && pipe->destAlphaPtr
+void Splash::pipeRunAAMono8(SplashPipe *pipe) {
+ Guchar aSrc, aDest, alpha2, aResult;
+ SplashColor cDest;
+ Guchar cResult0;
+
+ //----- read destination pixel
+ cDest[0] = *pipe->destColorPtr;
+ aDest = *pipe->destAlphaPtr;
+
+ //----- source alpha
+ aSrc = div255(pipe->aInput * pipe->shape);
+
+ //----- result alpha and non-isolated group element correction
+ aResult = aSrc + aDest - div255(aSrc * aDest);
+ alpha2 = aResult;
+
+ //----- result color
+ if (alpha2 == 0) {
+ cResult0 = 0;
+ } else {
+ cResult0 = state->grayTransfer[(Guchar)(((alpha2 - aSrc) * cDest[0] +
+ aSrc * pipe->cSrc[0]) / alpha2)];
+ }
+
+ //----- write destination pixel
+ *pipe->destColorPtr++ = cResult0;
+ *pipe->destAlphaPtr++ = aResult;
+
+ ++pipe->x;
+}
+
+// special case:
+// !pipe->pattern && !pipe->noTransparency && !state->softMask &&
+// pipe->usesShape && !pipe->alpha0Ptr && !state->blendFunc &&
+// !pipe->nonIsolatedGroup &&
+// bitmap->mode == splashModeRGB8 && pipe->destAlphaPtr
+void Splash::pipeRunAARGB8(SplashPipe *pipe) {
+ Guchar aSrc, aDest, alpha2, aResult;
+ SplashColor cDest;
+ Guchar cResult0, cResult1, cResult2;
+
+ //----- read destination pixel
+ cDest[0] = pipe->destColorPtr[0];
+ cDest[1] = pipe->destColorPtr[1];
+ cDest[2] = pipe->destColorPtr[2];
+ aDest = *pipe->destAlphaPtr;
+
+ //----- source alpha
+ aSrc = div255(pipe->aInput * pipe->shape);
+
+ //----- result alpha and non-isolated group element correction
+ aResult = aSrc + aDest - div255(aSrc * aDest);
+ alpha2 = aResult;
+
+ //----- result color
+ if (alpha2 == 0) {
+ cResult0 = 0;
+ cResult1 = 0;
+ cResult2 = 0;
+ } else {
+ cResult0 = state->rgbTransferR[(Guchar)(((alpha2 - aSrc) * cDest[0] +
+ aSrc * pipe->cSrc[0]) / alpha2)];
+ cResult1 = state->rgbTransferG[(Guchar)(((alpha2 - aSrc) * cDest[1] +
+ aSrc * pipe->cSrc[1]) / alpha2)];
+ cResult2 = state->rgbTransferB[(Guchar)(((alpha2 - aSrc) * cDest[2] +
+ aSrc * pipe->cSrc[2]) / alpha2)];
+ }
+
+ //----- write destination pixel
+ *pipe->destColorPtr++ = cResult0;
+ *pipe->destColorPtr++ = cResult1;
+ *pipe->destColorPtr++ = cResult2;
+ *pipe->destAlphaPtr++ = aResult;
+
+ ++pipe->x;
+}
+
+// special case:
+// !pipe->pattern && !pipe->noTransparency && !state->softMask &&
+// pipe->usesShape && !pipe->alpha0Ptr && !state->blendFunc &&
+// !pipe->nonIsolatedGroup &&
+// bitmap->mode == splashModeXBGR8 && pipe->destAlphaPtr
+void Splash::pipeRunAAXBGR8(SplashPipe *pipe) {
+ Guchar aSrc, aDest, alpha2, aResult;
+ SplashColor cDest;
+ Guchar cResult0, cResult1, cResult2;
+
+ //----- read destination pixel
+ cDest[0] = pipe->destColorPtr[2];
+ cDest[1] = pipe->destColorPtr[1];
+ cDest[2] = pipe->destColorPtr[0];
+ aDest = *pipe->destAlphaPtr;
+
+ //----- source alpha
+ aSrc = div255(pipe->aInput * pipe->shape);
+
+ //----- result alpha and non-isolated group element correction
+ aResult = aSrc + aDest - div255(aSrc * aDest);
+ alpha2 = aResult;
+
+ //----- result color
+ if (alpha2 == 0) {
+ cResult0 = 0;
+ cResult1 = 0;
+ cResult2 = 0;
+ } else {
+ cResult0 = state->rgbTransferR[(Guchar)(((alpha2 - aSrc) * cDest[0] +
+ aSrc * pipe->cSrc[0]) / alpha2)];
+ cResult1 = state->rgbTransferG[(Guchar)(((alpha2 - aSrc) * cDest[1] +
+ aSrc * pipe->cSrc[1]) / alpha2)];
+ cResult2 = state->rgbTransferB[(Guchar)(((alpha2 - aSrc) * cDest[2] +
+ aSrc * pipe->cSrc[2]) / alpha2)];
+ }
+
+ //----- write destination pixel
+ *pipe->destColorPtr++ = cResult2;
+ *pipe->destColorPtr++ = cResult1;
+ *pipe->destColorPtr++ = cResult0;
+ *pipe->destColorPtr++ = 255;
+ *pipe->destAlphaPtr++ = aResult;
+
+ ++pipe->x;
+}
+
+// special case:
+// !pipe->pattern && !pipe->noTransparency && !state->softMask &&
+// pipe->usesShape && !pipe->alpha0Ptr && !state->blendFunc &&
+// !pipe->nonIsolatedGroup &&
+// bitmap->mode == splashModeBGR8 && pipe->destAlphaPtr
+void Splash::pipeRunAABGR8(SplashPipe *pipe) {
+ Guchar aSrc, aDest, alpha2, aResult;
+ SplashColor cDest;
+ Guchar cResult0, cResult1, cResult2;
+
+ //----- read destination pixel
+ cDest[0] = pipe->destColorPtr[2];
+ cDest[1] = pipe->destColorPtr[1];
+ cDest[2] = pipe->destColorPtr[0];
+ aDest = *pipe->destAlphaPtr;
+
+ //----- source alpha
+ aSrc = div255(pipe->aInput * pipe->shape);
+
+ //----- result alpha and non-isolated group element correction
+ aResult = aSrc + aDest - div255(aSrc * aDest);
+ alpha2 = aResult;
+
+ //----- result color
+ if (alpha2 == 0) {
+ cResult0 = 0;
+ cResult1 = 0;
+ cResult2 = 0;
+ } else {
+ cResult0 = state->rgbTransferR[(Guchar)(((alpha2 - aSrc) * cDest[0] +
+ aSrc * pipe->cSrc[0]) / alpha2)];
+ cResult1 = state->rgbTransferG[(Guchar)(((alpha2 - aSrc) * cDest[1] +
+ aSrc * pipe->cSrc[1]) / alpha2)];
+ cResult2 = state->rgbTransferB[(Guchar)(((alpha2 - aSrc) * cDest[2] +
+ aSrc * pipe->cSrc[2]) / alpha2)];
+ }
+
+ //----- write destination pixel
+ *pipe->destColorPtr++ = cResult2;
+ *pipe->destColorPtr++ = cResult1;
+ *pipe->destColorPtr++ = cResult0;
+ *pipe->destAlphaPtr++ = aResult;
+
+ ++pipe->x;
+}
+
+#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;
+ Guchar cResult0, cResult1, cResult2, cResult3;
+
+ //----- read destination pixel
+ cDest[0] = pipe->destColorPtr[0];
+ cDest[1] = pipe->destColorPtr[1];
+ cDest[2] = pipe->destColorPtr[2];
+ cDest[3] = pipe->destColorPtr[3];
+ aDest = *pipe->destAlphaPtr;
+
+ //----- source alpha
+ aSrc = div255(pipe->aInput * pipe->shape);
+
+ //----- result alpha and non-isolated group element correction
+ aResult = aSrc + aDest - div255(aSrc * aDest);
+ alpha2 = aResult;
+
+ //----- result color
+ if (alpha2 == 0) {
+ cResult0 = 0;
+ cResult1 = 0;
+ cResult2 = 0;
+ cResult3 = 0;
+ } else {
+ cResult0 = state->cmykTransferC[(Guchar)(((alpha2 - aSrc) * cDest[0] +
+ aSrc * pipe->cSrc[0]) / alpha2)];
+ cResult1 = state->cmykTransferM[(Guchar)(((alpha2 - aSrc) * cDest[1] +
+ aSrc * pipe->cSrc[1]) / alpha2)];
+ cResult2 = state->cmykTransferY[(Guchar)(((alpha2 - aSrc) * cDest[2] +
+ aSrc * pipe->cSrc[2]) / alpha2)];
+ cResult3 = state->cmykTransferK[(Guchar)(((alpha2 - aSrc) * cDest[3] +
+ aSrc * pipe->cSrc[3]) / alpha2)];
+ }
+
+ //----- write destination pixel
+ if (state->overprintMask & 1) {
+ pipe->destColorPtr[0] = cResult0;
+ }
+ if (state->overprintMask & 2) {
+ pipe->destColorPtr[1] = cResult1;
+ }
+ if (state->overprintMask & 4) {
+ pipe->destColorPtr[2] = cResult2;
+ }
+ if (state->overprintMask & 8) {
+ pipe->destColorPtr[3] = cResult3;
+ }
+ pipe->destColorPtr += 4;
+ *pipe->destAlphaPtr++ = aResult;
+
+ ++pipe->x;
+}
+#endif
+
inline void Splash::pipeSetXY(SplashPipe *pipe, int x, int y) {
pipe->x = x;
pipe->y = y;
@@ -696,7 +1145,7 @@ inline void Splash::drawPixel(SplashPipe *pipe, int x, int y, GBool noClip) {
if (noClip || state->clip->test(x, y)) {
pipeSetXY(pipe, x, y);
- pipeRun(pipe);
+ (this->*pipe->run)(pipe);
updateModX(x);
updateModY(y);
}
@@ -757,8 +1206,8 @@ inline void Splash::drawAAPixel(SplashPipe *pipe, int x, int y) {
// draw the pixel
if (t != 0) {
pipeSetXY(pipe, x, y);
- pipe->shape *= aaGamma[t];
- pipeRun(pipe);
+ pipe->shape = div255(aaGamma[t] * pipe->shape);
+ (this->*pipe->run)(pipe);
updateModX(x);
updateModY(y);
}
@@ -768,18 +1217,25 @@ inline void Splash::drawSpan(SplashPipe *pipe, int x0, int x1, int y,
GBool noClip) {
int x;
- pipeSetXY(pipe, x0, y);
if (noClip) {
+ pipeSetXY(pipe, x0, y);
for (x = x0; x <= x1; ++x) {
- pipeRun(pipe);
+ (this->*pipe->run)(pipe);
}
updateModX(x0);
updateModX(x1);
updateModY(y);
} else {
+ if (x0 < state->clip->getXMinI()) {
+ x0 = state->clip->getXMinI();
+ }
+ if (x1 > state->clip->getXMaxI()) {
+ x1 = state->clip->getXMaxI();
+ }
+ pipeSetXY(pipe, x0, y);
for (x = x0; x <= x1; ++x) {
if (state->clip->test(x, y)) {
- pipeRun(pipe);
+ (this->*pipe->run)(pipe);
updateModX(x);
updateModY(y);
} else {
@@ -833,7 +1289,7 @@ inline void Splash::drawAALine(SplashPipe *pipe, int x0, int x1, int y) {
if (t != 0) {
pipe->shape = aaGamma[t];
- pipeRun(pipe);
+ (this->*pipe->run)(pipe);
updateModX(x);
updateModY(y);
} else {
@@ -865,19 +1321,22 @@ Splash::Splash(SplashBitmap *bitmapA, GBool vectorAntialiasA,
bitmap = bitmapA;
vectorAntialias = vectorAntialiasA;
+ inShading = gFalse;
state = new SplashState(bitmap->width, bitmap->height, vectorAntialias,
screenParams);
if (vectorAntialias) {
aaBuf = new SplashBitmap(splashAASize * bitmap->width, splashAASize,
1, splashModeMono1, gFalse);
for (i = 0; i <= splashAASize * splashAASize; ++i) {
- aaGamma[i] = splashPow((SplashCoord)i /
- (SplashCoord)(splashAASize * splashAASize),
- 1.5);
+ aaGamma[i] = (Guchar)splashRound(
+ splashPow((SplashCoord)i /
+ (SplashCoord)(splashAASize * splashAASize),
+ splashAAGamma) * 255);
}
} else {
aaBuf = NULL;
}
+ minLineWidth = 0;
clearModRegion();
debugMode = gFalse;
}
@@ -887,6 +1346,7 @@ Splash::Splash(SplashBitmap *bitmapA, GBool vectorAntialiasA,
int i;
bitmap = bitmapA;
+ inShading = gFalse;
vectorAntialias = vectorAntialiasA;
state = new SplashState(bitmap->width, bitmap->height, vectorAntialias,
screenA);
@@ -894,13 +1354,15 @@ Splash::Splash(SplashBitmap *bitmapA, GBool vectorAntialiasA,
aaBuf = new SplashBitmap(splashAASize * bitmap->width, splashAASize,
1, splashModeMono1, gFalse);
for (i = 0; i <= splashAASize * splashAASize; ++i) {
- aaGamma[i] = splashPow((SplashCoord)i /
- (SplashCoord)(splashAASize * splashAASize),
- 1.5);
+ aaGamma[i] = (Guchar)splashRound(
+ splashPow((SplashCoord)i /
+ (SplashCoord)(splashAASize * splashAASize),
+ splashAAGamma) * 255);
}
} else {
aaBuf = NULL;
}
+ minLineWidth = 0;
clearModRegion();
debugMode = gFalse;
}
@@ -979,6 +1441,10 @@ SplashCoord Splash::getLineDashPhase() {
return state->lineDashPhase;
}
+GBool Splash::getStrokeAdjust() {
+ return state->strokeAdjust;
+}
+
SplashClip *Splash::getClip() {
return state->clip;
}
@@ -1094,6 +1560,15 @@ void Splash::setInNonIsolatedGroup(SplashBitmap *alpha0BitmapA,
state->inNonIsolatedGroup = gTrue;
}
+void Splash::setTransfer(Guchar *red, Guchar *green, Guchar *blue,
+ Guchar *gray) {
+ state->setTransfer(red, green, blue, gray);
+}
+
+void Splash::setOverprintMask(Guint overprintMask) {
+ state->overprintMask = overprintMask;
+}
+
//------------------------------------------------------------------------
// state save/restore
//------------------------------------------------------------------------
@@ -1247,6 +1722,7 @@ void Splash::clear(SplashColorPtr color, Guchar alpha) {
SplashError Splash::stroke(SplashPath *path) {
SplashPath *path2, *dPath;
+ SplashCoord d1, d2, t1, t2, w;
if (debugMode) {
printf("stroke [dash:%d] [width:%.2f]:\n",
@@ -1262,12 +1738,44 @@ SplashError Splash::stroke(SplashPath *path) {
dPath = makeDashedPath(path2);
delete path2;
path2 = dPath;
+ if (path2->length == 0) {
+ delete path2;
+ return splashErrEmptyPath;
+ }
+ }
+
+ // transform a unit square, and take the half the max of the two
+ // diagonals; the product of this number and the line width is the
+ // (approximate) transformed line width
+ t1 = state->matrix[0] + state->matrix[2];
+ t2 = state->matrix[1] + state->matrix[3];
+ d1 = t1 * t1 + t2 * t2;
+ t1 = state->matrix[0] - state->matrix[2];
+ t2 = state->matrix[1] - state->matrix[3];
+ d2 = t1 * t1 + t2 * t2;
+ if (d2 > d1) {
+ d1 = d2;
}
- if (state->lineWidth == 0) {
- strokeNarrow(path2);
+ d1 *= 0.5;
+ if (d1 > 0 &&
+ d1 * state->lineWidth * state->lineWidth < minLineWidth * minLineWidth) {
+ w = minLineWidth / splashSqrt(d1);
+ strokeWide(path2, w);
+ } else if (bitmap->mode == splashModeMono1) {
+ // this gets close to Adobe's behavior in mono mode
+ if (d1 <= 2) {
+ strokeNarrow(path2);
+ } else {
+ strokeWide(path2, state->lineWidth);
+ }
} else {
- strokeWide(path2);
+ if (state->lineWidth == 0) {
+ strokeNarrow(path2);
+ } else {
+ strokeWide(path2, state->lineWidth);
+ }
}
+
delete path2;
return splashOk;
}
@@ -1276,8 +1784,8 @@ void Splash::strokeNarrow(SplashPath *path) {
SplashPipe pipe;
SplashXPath *xPath;
SplashXPathSeg *seg;
- int x0, x1, x2, x3, y0, y1, x, y, t;
- SplashCoord dx, dy, dxdy;
+ int x0, x1, y0, y1, xa, xb, y;
+ SplashCoord dxdy;
SplashClipResult clipRes;
int nClipRes[3];
int i;
@@ -1286,86 +1794,75 @@ void Splash::strokeNarrow(SplashPath *path) {
xPath = new SplashXPath(path, state->matrix, state->flatness, gFalse);
- pipeInit(&pipe, 0, 0, state->strokePattern, NULL, state->strokeAlpha,
- gFalse, gFalse, state->strokePattern, gTrue);
+ pipeInit(&pipe, 0, 0, state->strokePattern, NULL,
+ (Guchar)splashRound(state->strokeAlpha * 255),
+ gFalse, gFalse);
for (i = 0, seg = xPath->segs; i < xPath->length; ++i, ++seg) {
-
- x0 = splashFloor(seg->x0);
- x1 = splashFloor(seg->x1);
- y0 = splashFloor(seg->y0);
- y1 = splashFloor(seg->y1);
-
- // horizontal segment
- if (y0 == y1) {
- if (x0 > x1) {
- t = x0; x0 = x1; x1 = t;
- }
- if ((clipRes = state->clip->testSpan(x0, x1, y0))
- != splashClipAllOutside) {
- drawSpan(&pipe, x0, x1, y0, clipRes == splashClipAllInside);
- }
-
- // segment with |dx| > |dy|
- } else if (splashAbs(seg->dxdy) > 1) {
- dx = seg->x1 - seg->x0;
- dy = seg->y1 - seg->y0;
- dxdy = seg->dxdy;
- if (y0 > y1) {
- t = y0; y0 = y1; y1 = t;
- t = x0; x0 = x1; x1 = t;
- dx = -dx;
- dy = -dy;
- }
- if ((clipRes = state->clip->testRect(x0 <= x1 ? x0 : x1, y0,
- x0 <= x1 ? x1 : x0, y1))
- != splashClipAllOutside) {
- if (dx > 0) {
- x2 = x0;
- x3 = splashFloor(seg->x0 + ((SplashCoord)y0 + 1 - seg->y0) * dxdy);
- drawSpan(&pipe, x2, (x2 <= x3 - 1) ? x3 - 1 : x2, y0,
- clipRes == splashClipAllInside);
- x2 = x3;
- for (y = y0 + 1; y <= y1 - 1; ++y) {
- x3 = splashFloor(seg->x0 + ((SplashCoord)y + 1 - seg->y0) * dxdy);
- drawSpan(&pipe, x2, x3 - 1, y, clipRes == splashClipAllInside);
- x2 = x3;
+ if (seg->y0 <= seg->y1) {
+ y0 = splashFloor(seg->y0);
+ y1 = splashFloor(seg->y1);
+ x0 = splashFloor(seg->x0);
+ x1 = splashFloor(seg->x1);
+ } else {
+ y0 = splashFloor(seg->y1);
+ y1 = splashFloor(seg->y0);
+ x0 = splashFloor(seg->x1);
+ x1 = splashFloor(seg->x0);
+ }
+ if ((clipRes = state->clip->testRect(x0 <= x1 ? x0 : x1, y0,
+ x0 <= x1 ? x1 : x0, y1))
+ != splashClipAllOutside) {
+ if (y0 == y1) {
+ if (x0 <= x1) {
+ drawSpan(&pipe, x0, x1, y0, clipRes == splashClipAllInside);
+ } else {
+ drawSpan(&pipe, x1, x0, y0, clipRes == splashClipAllInside);
+ }
+ } else {
+ dxdy = seg->dxdy;
+ if (y0 < state->clip->getYMinI()) {
+ y0 = state->clip->getYMinI();
+ x0 = splashFloor(seg->x0 + ((SplashCoord)y0 - seg->y0) * dxdy);
+ }
+ if (y1 > state->clip->getYMaxI()) {
+ y1 = state->clip->getYMaxI();
+ x1 = splashFloor(seg->x0 + ((SplashCoord)y1 - seg->y0) * dxdy);
+ }
+ if (x0 <= x1) {
+ xa = x0;
+ for (y = y0; y <= y1; ++y) {
+ if (y < y1) {
+ xb = splashFloor(seg->x0 +
+ ((SplashCoord)y + 1 - seg->y0) * dxdy);
+ } else {
+ xb = x1 + 1;
+ }
+ if (xa == xb) {
+ drawPixel(&pipe, xa, y, clipRes == splashClipAllInside);
+ } else {
+ drawSpan(&pipe, xa, xb - 1, y, clipRes == splashClipAllInside);
+ }
+ xa = xb;
}
- drawSpan(&pipe, x2, x2 <= x1 ? x1 : x2, y1,
- clipRes == splashClipAllInside);
} else {
- x2 = x0;
- x3 = splashFloor(seg->x0 + ((SplashCoord)y0 + 1 - seg->y0) * dxdy);
- drawSpan(&pipe, (x3 + 1 <= x2) ? x3 + 1 : x2, x2, y0,
- clipRes == splashClipAllInside);
- x2 = x3;
- for (y = y0 + 1; y <= y1 - 1; ++y) {
- x3 = splashFloor(seg->x0 + ((SplashCoord)y + 1 - seg->y0) * dxdy);
- drawSpan(&pipe, x3 + 1, x2, y, clipRes == splashClipAllInside);
- x2 = x3;
+ xa = x0;
+ for (y = y0; y <= y1; ++y) {
+ if (y < y1) {
+ xb = splashFloor(seg->x0 +
+ ((SplashCoord)y + 1 - seg->y0) * dxdy);
+ } else {
+ xb = x1 - 1;
+ }
+ if (xa == xb) {
+ drawPixel(&pipe, xa, y, clipRes == splashClipAllInside);
+ } else {
+ drawSpan(&pipe, xb + 1, xa, y, clipRes == splashClipAllInside);
+ }
+ xa = xb;
}
- drawSpan(&pipe, x1, (x1 <= x2) ? x2 : x1, y1,
- clipRes == splashClipAllInside);
}
}
-
- // segment with |dy| > |dx|
- } else {
- dxdy = seg->dxdy;
- if (y0 > y1) {
- t = x0; x0 = x1; x1 = t;
- t = y0; y0 = y1; y1 = t;
- }
- if ((clipRes = state->clip->testRect(x0 <= x1 ? x0 : x1, y0,
- x0 <= x1 ? x1 : x0, y1))
- != splashClipAllOutside) {
- drawPixel(&pipe, x0, y0, clipRes == splashClipAllInside);
- for (y = y0 + 1; y <= y1 - 1; ++y) {
- x = splashFloor(seg->x0 + ((SplashCoord)y - seg->y0) * dxdy);
- drawPixel(&pipe, x, y, clipRes == splashClipAllInside);
- }
- drawPixel(&pipe, x1, y1, clipRes == splashClipAllInside);
- }
}
++nClipRes[clipRes];
}
@@ -1381,10 +1878,10 @@ void Splash::strokeNarrow(SplashPath *path) {
delete xPath;
}
-void Splash::strokeWide(SplashPath *path) {
+void Splash::strokeWide(SplashPath *path, SplashCoord w) {
SplashPath *path2;
- path2 = makeStrokePath(path, gFalse);
+ path2 = makeStrokePath(path, w, gFalse);
fillWithPattern(path2, gFalse, state->strokePattern, state->strokeAlpha);
delete path2;
}
@@ -1490,18 +1987,18 @@ void Splash::flattenCurve(SplashCoord x0, SplashCoord y0,
// otherwise, subdivide the curve
} else {
- xl1 = (xl0 + xx1) * 0.5;
- yl1 = (yl0 + yy1) * 0.5;
- xh = (xx1 + xx2) * 0.5;
- yh = (yy1 + yy2) * 0.5;
- xl2 = (xl1 + xh) * 0.5;
- yl2 = (yl1 + yh) * 0.5;
- xr2 = (xx2 + xr3) * 0.5;
- yr2 = (yy2 + yr3) * 0.5;
- xr1 = (xh + xr2) * 0.5;
- yr1 = (yh + yr2) * 0.5;
- xr0 = (xl2 + xr1) * 0.5;
- yr0 = (yl2 + yr1) * 0.5;
+ xl1 = splashAvg(xl0, xx1);
+ yl1 = splashAvg(yl0, yy1);
+ xh = splashAvg(xx1, xx2);
+ yh = splashAvg(yy1, yy2);
+ xl2 = splashAvg(xl1, xh);
+ yl2 = splashAvg(yl1, yh);
+ xr2 = splashAvg(xx2, xr3);
+ yr2 = splashAvg(yy2, yr3);
+ xr1 = splashAvg(xh, xr2);
+ yr1 = splashAvg(yh, yr2);
+ xr0 = splashAvg(xl2, xr1);
+ yr0 = splashAvg(yl2, yr1);
// add the new subdivision points
p3 = (p1 + p2) / 2;
cx[p1][1] = xl1; cy[p1][1] = yl1;
@@ -1528,15 +2025,21 @@ SplashPath *Splash::makeDashedPath(SplashPath *path) {
for (i = 0; i < state->lineDashLength; ++i) {
lineDashTotal += state->lineDash[i];
}
+ // Acrobat simply draws nothing if the dash array is [0]
+ if (lineDashTotal == 0) {
+ return new SplashPath();
+ }
lineDashStartPhase = state->lineDashPhase;
i = splashFloor(lineDashStartPhase / lineDashTotal);
lineDashStartPhase -= (SplashCoord)i * lineDashTotal;
lineDashStartOn = gTrue;
lineDashStartIdx = 0;
- while (lineDashStartPhase >= state->lineDash[lineDashStartIdx]) {
- lineDashStartOn = !lineDashStartOn;
- lineDashStartPhase -= state->lineDash[lineDashStartIdx];
- ++lineDashStartIdx;
+ if (lineDashStartPhase > 0) {
+ while (lineDashStartPhase >= state->lineDash[lineDashStartIdx]) {
+ lineDashStartOn = !lineDashStartOn;
+ lineDashStartPhase -= state->lineDash[lineDashStartIdx];
+ ++lineDashStartIdx;
+ }
}
dPath = new SplashPath();
@@ -1646,15 +2149,49 @@ SplashError Splash::fillWithPattern(SplashPath *path, GBool eo,
if (path->length == 0) {
return splashErrEmptyPath;
}
+ if (pathAllOutside(path)) {
+ opClipRes = splashClipAllOutside;
+ return splashOk;
+ }
+
+ // add stroke adjustment hints for filled rectangles -- this only
+ // applies to paths that consist of a single subpath
+ // (this appears to match Acrobat's behavior)
+ if (state->strokeAdjust && !path->hints) {
+ int n;
+ n = path->getLength();
+ if (n == 4 &&
+ !(path->flags[0] & splashPathClosed) &&
+ !(path->flags[1] & splashPathLast) &&
+ !(path->flags[2] & splashPathLast)) {
+ path->close(gTrue);
+ path->addStrokeAdjustHint(0, 2, 0, 4);
+ path->addStrokeAdjustHint(1, 3, 0, 4);
+ } else if (n == 5 &&
+ (path->flags[0] & splashPathClosed) &&
+ !(path->flags[1] & splashPathLast) &&
+ !(path->flags[2] & splashPathLast) &&
+ !(path->flags[3] & splashPathLast)) {
+ path->addStrokeAdjustHint(0, 2, 0, 4);
+ path->addStrokeAdjustHint(1, 3, 0, 4);
+ }
+ }
+
xPath = new SplashXPath(path, state->matrix, state->flatness, gTrue);
- if (vectorAntialias) {
+ if (vectorAntialias && !inShading) {
xPath->aaScale();
}
xPath->sort();
- scanner = new SplashXPathScanner(xPath, eo);
+ yMinI = state->clip->getYMinI();
+ yMaxI = state->clip->getYMaxI();
+ if (vectorAntialias && !inShading) {
+ yMinI = yMinI * splashAASize;
+ yMaxI = (yMaxI + 1) * splashAASize - 1;
+ }
+ scanner = new SplashXPathScanner(xPath, eo, yMinI, yMaxI);
// get the min and max x and y values
- if (vectorAntialias) {
+ if (vectorAntialias && !inShading) {
scanner->getBBoxAA(&xMinI, &yMinI, &xMaxI, &yMaxI);
} else {
scanner->getBBox(&xMinI, &yMinI, &xMaxI, &yMaxI);
@@ -1663,19 +2200,15 @@ SplashError Splash::fillWithPattern(SplashPath *path, GBool eo,
// check clipping
if ((clipRes = state->clip->testRect(xMinI, yMinI, xMaxI, yMaxI))
!= splashClipAllOutside) {
-
- // limit the y range
- if (yMinI < state->clip->getYMinI()) {
- yMinI = state->clip->getYMinI();
- }
- if (yMaxI > state->clip->getYMaxI()) {
- yMaxI = state->clip->getYMaxI();
+ if (scanner->hasPartialClip()) {
+ clipRes = splashClipPartial;
}
- pipeInit(&pipe, 0, yMinI, pattern, NULL, alpha, vectorAntialias, gFalse, pattern);
+ pipeInit(&pipe, 0, yMinI, pattern, NULL, (Guchar)splashRound(alpha * 255),
+ vectorAntialias && !inShading, gFalse);
// draw the spans
- if (vectorAntialias) {
+ if (vectorAntialias && !inShading) {
for (y = yMinI; y <= yMaxI; ++y) {
scanner->renderAALine(aaBuf, &x0, &x1, y);
if (clipRes != splashClipAllInside) {
@@ -1710,6 +2243,73 @@ SplashError Splash::fillWithPattern(SplashPath *path, GBool eo,
return splashOk;
}
+GBool Splash::pathAllOutside(SplashPath *path) {
+ SplashCoord xMin1, yMin1, xMax1, yMax1;
+ SplashCoord xMin2, yMin2, xMax2, yMax2;
+ SplashCoord x, y;
+ int xMinI, yMinI, xMaxI, yMaxI;
+ int i;
+
+ xMin1 = xMax1 = path->pts[0].x;
+ yMin1 = yMax1 = path->pts[0].y;
+ for (i = 1; i < path->length; ++i) {
+ if (path->pts[i].x < xMin1) {
+ xMin1 = path->pts[i].x;
+ } else if (path->pts[i].x > xMax1) {
+ xMax1 = path->pts[i].x;
+ }
+ if (path->pts[i].y < yMin1) {
+ yMin1 = path->pts[i].y;
+ } else if (path->pts[i].y > yMax1) {
+ yMax1 = path->pts[i].y;
+ }
+ }
+
+ transform(state->matrix, xMin1, yMin1, &x, &y);
+ xMin2 = xMax2 = x;
+ yMin2 = yMax2 = y;
+ transform(state->matrix, xMin1, yMax1, &x, &y);
+ if (x < xMin2) {
+ xMin2 = x;
+ } else if (x > xMax2) {
+ xMax2 = x;
+ }
+ if (y < yMin2) {
+ yMin2 = y;
+ } else if (y > yMax2) {
+ yMax2 = y;
+ }
+ transform(state->matrix, xMax1, yMin1, &x, &y);
+ if (x < xMin2) {
+ xMin2 = x;
+ } else if (x > xMax2) {
+ xMax2 = x;
+ }
+ if (y < yMin2) {
+ yMin2 = y;
+ } else if (y > yMax2) {
+ yMax2 = y;
+ }
+ transform(state->matrix, xMax1, yMax1, &x, &y);
+ if (x < xMin2) {
+ xMin2 = x;
+ } else if (x > xMax2) {
+ xMax2 = x;
+ }
+ if (y < yMin2) {
+ yMin2 = y;
+ } else if (y > yMax2) {
+ yMax2 = y;
+ }
+ xMinI = splashFloor(xMin2);
+ yMinI = splashFloor(yMin2);
+ xMaxI = splashFloor(xMax2);
+ yMaxI = splashFloor(yMax2);
+
+ return state->clip->testRect(xMinI, yMinI, xMaxI, yMaxI) ==
+ splashClipAllOutside;
+}
+
SplashError Splash::xorFill(SplashPath *path, GBool eo) {
SplashPipe pipe;
SplashXPath *xPath;
@@ -1723,7 +2323,8 @@ SplashError Splash::xorFill(SplashPath *path, GBool eo) {
}
xPath = new SplashXPath(path, state->matrix, state->flatness, gTrue);
xPath->sort();
- scanner = new SplashXPathScanner(xPath, eo);
+ 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);
@@ -1731,18 +2332,13 @@ SplashError Splash::xorFill(SplashPath *path, GBool eo) {
// check clipping
if ((clipRes = state->clip->testRect(xMinI, yMinI, xMaxI, yMaxI))
!= splashClipAllOutside) {
-
- // limit the y range
- if (yMinI < state->clip->getYMinI()) {
- yMinI = state->clip->getYMinI();
- }
- if (yMaxI > state->clip->getYMaxI()) {
- yMaxI = state->clip->getYMaxI();
+ if (scanner->hasPartialClip()) {
+ clipRes = splashClipPartial;
}
origBlendFunc = state->blendFunc;
state->blendFunc = &blendXor;
- pipeInit(&pipe, 0, yMinI, state->fillPattern, NULL, 1, gFalse, gFalse, state->fillPattern);
+ pipeInit(&pipe, 0, yMinI, state->fillPattern, NULL, 255, gFalse, gFalse);
// draw the spans
for (y = yMinI; y <= yMaxI; ++y) {
@@ -1856,14 +2452,14 @@ void Splash::fillGlyph2(int x0, int y0, SplashGlyphBitmap *glyph, GBool noClip)
if (noClip) {
if (glyph->aa) {
pipeInit(&pipe, xStart, yStart,
- state->fillPattern, NULL, state->fillAlpha, gTrue, gFalse, state->fillPattern);
+ state->fillPattern, NULL, (Guchar)splashRound(state->fillAlpha * 255), gTrue, gFalse);
for (yy = 0, y1 = yStart; yy < yyLimit; ++yy, ++y1) {
pipeSetXY(&pipe, xStart, y1);
for (xx = 0, x1 = xStart; xx < xxLimit; ++xx, ++x1) {
alpha = p[xx];
if (alpha != 0) {
- pipe.shape = (SplashCoord)(alpha / 255.0);
- pipeRun(&pipe);
+ pipe.shape = alpha;
+ (this->*pipe.run)(&pipe);
updateModX(x1);
updateModY(y1);
} else {
@@ -1876,14 +2472,14 @@ void Splash::fillGlyph2(int x0, int y0, SplashGlyphBitmap *glyph, GBool noClip)
const int widthEight = splashCeil(glyph->w / 8.0);
pipeInit(&pipe, xStart, yStart,
- state->fillPattern, NULL, state->fillAlpha, gFalse, gFalse, state->fillPattern);
+ state->fillPattern, NULL, (Guchar)splashRound(state->fillAlpha * 255), gFalse, gFalse);
for (yy = 0, y1 = yStart; yy < yyLimit; ++yy, ++y1) {
pipeSetXY(&pipe, xStart, y1);
for (xx = 0, x1 = xStart; xx < xxLimit; xx += 8) {
alpha0 = (xShift > 0 ? (p[xx / 8] << xShift) | (p[xx / 8 + 1] >> (8 - xShift)) : p[xx / 8]);
for (xx1 = 0; xx1 < 8 && xx + xx1 < xxLimit; ++xx1, ++x1) {
if (alpha0 & 0x80) {
- pipeRun(&pipe);
+ (this->*pipe.run)(&pipe);
updateModX(x1);
updateModY(y1);
} else {
@@ -1898,15 +2494,15 @@ void Splash::fillGlyph2(int x0, int y0, SplashGlyphBitmap *glyph, GBool noClip)
} else {
if (glyph->aa) {
pipeInit(&pipe, xStart, yStart,
- state->fillPattern, NULL, state->fillAlpha, gTrue, gFalse, state->fillPattern);
+ state->fillPattern, NULL, (Guchar)splashRound(state->fillAlpha * 255), gTrue, gFalse);
for (yy = 0, y1 = yStart; yy < yyLimit; ++yy, ++y1) {
pipeSetXY(&pipe, xStart, y1);
for (xx = 0, x1 = xStart; xx < xxLimit; ++xx, ++x1) {
if (state->clip->test(x1, y1)) {
alpha = p[xx];
if (alpha != 0) {
- pipe.shape = (SplashCoord)(alpha / 255.0);
- pipeRun(&pipe);
+ pipe.shape = alpha;
+ (this->*pipe.run)(&pipe);
updateModX(x1);
updateModY(y1);
} else {
@@ -1922,7 +2518,7 @@ void Splash::fillGlyph2(int x0, int y0, SplashGlyphBitmap *glyph, GBool noClip)
const int widthEight = splashCeil(glyph->w / 8.0);
pipeInit(&pipe, xStart, yStart,
- state->fillPattern, NULL, state->fillAlpha, gFalse, gFalse, state->fillPattern);
+ state->fillPattern, NULL, (Guchar)splashRound(state->fillAlpha * 255), gFalse, gFalse);
for (yy = 0, y1 = yStart; yy < yyLimit; ++yy, ++y1) {
pipeSetXY(&pipe, xStart, y1);
for (xx = 0, x1 = xStart; xx < xxLimit; xx += 8) {
@@ -1930,7 +2526,7 @@ void Splash::fillGlyph2(int x0, int y0, SplashGlyphBitmap *glyph, GBool noClip)
for (xx1 = 0; xx1 < 8 && xx + xx1 < xxLimit; ++xx1, ++x1) {
if (state->clip->test(x1, y1)) {
if (alpha0 & 0x80) {
- pipeRun(&pipe);
+ (this->*pipe.run)(&pipe);
updateModX(x1);
updateModY(y1);
} else {
@@ -2099,8 +2695,8 @@ SplashError Splash::fillImageMask(SplashImageMaskSource src, void *srcData,
pixBuf = (SplashColorPtr)gmallocn((yp + 1), w);
// initialize the pixel pipe
- pipeInit(&pipe, 0, 0, state->fillPattern, NULL, state->fillAlpha,
- gTrue, gFalse, state->fillPattern);
+ pipeInit(&pipe, 0, 0, state->fillPattern, NULL, (Guchar)splashRound(state->fillAlpha * 255),
+ gTrue, gFalse);
if (vectorAntialias) {
drawAAPixelInit();
}
@@ -2206,9 +2802,9 @@ SplashError Splash::fillImageMask(SplashImageMaskSource src, void *srcData,
// blend fill color with background
if (pixAcc != 0) {
- pipe.shape = (pixAcc == n * m)
+ pipe.shape = ((pixAcc == n * m)
? (SplashCoord)1
- : (SplashCoord)pixAcc / (SplashCoord)(n * m);
+ : (SplashCoord)pixAcc / (SplashCoord)(n * m)) * 255;
if (vectorAntialias && clipRes2 != splashClipAllInside) {
drawAAPixel(&pipe, tx + x2, ty + y2);
} else {
@@ -2412,9 +3008,9 @@ SplashError Splash::drawImage(SplashImageSource src, void *srcData,
#endif
// initialize the pixel pipe
- pipeInit(&pipe, 0, 0, NULL, pix, state->fillAlpha,
+ pipeInit(&pipe, 0, 0, NULL, pix, (Guchar)splashRound(state->fillAlpha * 255),
srcAlpha || (vectorAntialias && clipRes != splashClipAllInside),
- gFalse, opImagePattern);
+ gFalse);
if (vectorAntialias) {
drawAAPixelInit();
}
@@ -2531,7 +3127,7 @@ SplashError Splash::drawImage(SplashImageSource src, void *srcData,
}
pixMul = (SplashCoord)1 / (SplashCoord)(n * m);
alphaMul = pixMul * (1.0 / 255.0);
- alpha = (SplashCoord)alphaAcc * alphaMul;
+ alpha = (SplashCoord)alphaAcc * pixMul;
if (alpha > 0) {
pix[0] = (int)((SplashCoord)pixAcc0 * pixMul);
@@ -2597,7 +3193,7 @@ SplashError Splash::drawImage(SplashImageSource src, void *srcData,
}
pixMul = (SplashCoord)1 / (SplashCoord)(n * m);
alphaMul = pixMul * (1.0 / 255.0);
- alpha = (SplashCoord)alphaAcc * alphaMul;
+ alpha = (SplashCoord)alphaAcc * pixMul;
if (alpha > 0) {
pix[0] = (int)((SplashCoord)pixAcc0 * pixMul);
@@ -2664,7 +3260,7 @@ SplashError Splash::drawImage(SplashImageSource src, void *srcData,
}
pixMul = (SplashCoord)1 / (SplashCoord)(n * m);
alphaMul = pixMul * (1.0 / 255.0);
- alpha = (SplashCoord)alphaAcc * alphaMul;
+ alpha = (SplashCoord)alphaAcc * pixMul;
if (alpha > 0) {
pix[0] = (int)((SplashCoord)pixAcc0 * pixMul);
@@ -2735,7 +3331,7 @@ SplashError Splash::drawImage(SplashImageSource src, void *srcData,
}
pixMul = (SplashCoord)1 / (SplashCoord)(n * m);
alphaMul = pixMul * (1.0 / 255.0);
- alpha = (SplashCoord)alphaAcc * alphaMul;
+ alpha = (SplashCoord)alphaAcc * pixMul;
if (alpha > 0) {
pix[0] = (int)((SplashCoord)pixAcc0 * pixMul);
@@ -2877,7 +3473,7 @@ SplashError Splash::drawImage(SplashImageSource src, void *srcData,
// set pixel
if (vectorAntialias && clipRes != splashClipAllInside) {
- pipe.shape = (SplashCoord)1;
+ pipe.shape = (SplashCoord)255;
drawAAPixel(&pipe, tx + x2, ty + y2);
} else {
drawPixel(&pipe, tx + x2, ty + y2,
@@ -2937,7 +3533,7 @@ SplashError Splash::drawImage(SplashImageSource src, void *srcData,
// set pixel
if (vectorAntialias && clipRes != splashClipAllInside) {
- pipe.shape = (SplashCoord)1;
+ pipe.shape = (SplashCoord)255;
drawAAPixel(&pipe, tx + x2, ty + y2);
} else {
drawPixel(&pipe, tx + x2, ty + y2,
@@ -2998,7 +3594,7 @@ SplashError Splash::drawImage(SplashImageSource src, void *srcData,
// set pixel
if (vectorAntialias && clipRes != splashClipAllInside) {
- pipe.shape = (SplashCoord)1;
+ pipe.shape = (SplashCoord)255;
drawAAPixel(&pipe, tx + x2, ty + y2);
} else {
drawPixel(&pipe, tx + x2, ty + y2,
@@ -3060,7 +3656,7 @@ SplashError Splash::drawImage(SplashImageSource src, void *srcData,
// set pixel
if (vectorAntialias && clipRes != splashClipAllInside) {
- pipe.shape = (SplashCoord)1;
+ pipe.shape = (SplashCoord)255;
drawAAPixel(&pipe, tx + x2, ty + y2);
} else {
drawPixel(&pipe, tx + x2, ty + y2,
@@ -3103,7 +3699,7 @@ SplashError Splash::composite(SplashBitmap *src, int xSrc, int ySrc,
}
if (src->alpha) {
- pipeInit(&pipe, xDest, yDest, NULL, pixel, state->fillAlpha,
+ pipeInit(&pipe, xDest, yDest, NULL, pixel, (Guchar)splashRound(state->fillAlpha * 255),
gTrue, nonIsolated);
for (y = 0; y < h; ++y) {
pipeSetXY(&pipe, xDest, yDest + y);
@@ -3114,8 +3710,8 @@ SplashError Splash::composite(SplashBitmap *src, int xSrc, int ySrc,
// this uses shape instead of alpha, which isn't technically
// correct, but works out the same
src->getPixel(xSrc + x, ySrc + y, pixel);
- pipe.shape = (SplashCoord)(alpha / 255.0);
- pipeRun(&pipe);
+ pipe.shape = alpha;
+ (this->*pipe.run)(&pipe);
updateModX(xDest + x);
updateModY(yDest + y);
} else {
@@ -3124,14 +3720,14 @@ SplashError Splash::composite(SplashBitmap *src, int xSrc, int ySrc,
}
}
} else {
- pipeInit(&pipe, xDest, yDest, NULL, pixel, state->fillAlpha,
+ pipeInit(&pipe, xDest, yDest, NULL, pixel, (Guchar)splashRound(state->fillAlpha * 255),
gFalse, nonIsolated);
for (y = 0; y < h; ++y) {
pipeSetXY(&pipe, xDest, yDest + y);
for (x = 0; x < w; ++x) {
if (noClip || state->clip->test(xDest + x, yDest + y)) {
src->getPixel(xSrc + x, ySrc + y, pixel);
- pipeRun(&pipe);
+ (this->*pipe.run)(&pipe);
updateModX(xDest + x);
updateModY(yDest + y);
} else {
@@ -3334,7 +3930,7 @@ GBool Splash::gouraudTriangleShadedFill(SplashGouraudColor *shading)
SplashPipe pipe;
SplashColor cSrcVal;
- pipeInit(&pipe, 0, 0, NULL, cSrcVal, state->strokeAlpha, gFalse, gFalse, NULL, gTrue);
+ pipeInit(&pipe, 0, 0, NULL, cSrcVal, (Guchar)splashRound(state->strokeAlpha * 255), gFalse, gFalse);
if (vectorAntialias) {
if (aaBuf == NULL)
@@ -3675,166 +4271,246 @@ SplashError Splash::blitTransparent(SplashBitmap *src, int xSrc, int ySrc,
return splashOk;
}
-SplashPath *Splash::makeStrokePath(SplashPath *path, GBool flatten) {
- SplashPath *pathIn, *pathOut;
- SplashCoord w, d, dx, dy, wdx, wdy, dxNext, dyNext, wdxNext, wdyNext;
+SplashPath *Splash::makeStrokePath(SplashPath *path, SplashCoord w,
+ GBool flatten) {
+ SplashPath *pathIn, *dashPath, *pathOut;
+ SplashCoord d, dx, dy, wdx, wdy, dxNext, dyNext, wdxNext, wdyNext;
SplashCoord crossprod, dotprod, miter, m;
GBool first, last, closed;
- int subpathStart, next, i;
+ int subpathStart0, subpathStart1, seg, i0, i1, j0, j1, k0, k1;
int left0, left1, left2, right0, right1, right2, join0, join1, join2;
int leftFirst, rightFirst, firstPt;
+ pathOut = new SplashPath();
+
+ if (path->length == 0) {
+ return pathOut;
+ }
+
if (flatten) {
pathIn = flattenPath(path, state->matrix, state->flatness);
if (state->lineDashLength > 0) {
- pathOut = makeDashedPath(pathIn);
+ dashPath = makeDashedPath(pathIn);
delete pathIn;
- pathIn = pathOut;
+ pathIn = dashPath;
+ if (pathIn->length == 0) {
+ delete pathIn;
+ return pathOut;
+ }
}
} else {
pathIn = path;
}
- subpathStart = 0; // make gcc happy
+ subpathStart0 = subpathStart1 = 0; // make gcc happy
+ seg = 0; // make gcc happy
closed = gFalse; // make gcc happy
left0 = left1 = right0 = right1 = join0 = join1 = 0; // make gcc happy
leftFirst = rightFirst = firstPt = 0; // make gcc happy
- pathOut = new SplashPath();
- w = state->lineWidth;
-
- for (i = 0; i < pathIn->length - 1; ++i) {
- if (pathIn->flags[i] & splashPathLast) {
- continue;
+ i0 = 0;
+ for (i1 = i0;
+ !(pathIn->flags[i1] & splashPathLast) &&
+ i1 + 1 < pathIn->length &&
+ pathIn->pts[i1+1].x == pathIn->pts[i1].x &&
+ pathIn->pts[i1+1].y == pathIn->pts[i1].y;
+ ++i1) ;
+
+ while (i1 < pathIn->length) {
+ if ((first = pathIn->flags[i0] & splashPathFirst)) {
+ subpathStart0 = i0;
+ subpathStart1 = i1;
+ seg = 0;
+ closed = pathIn->flags[i0] & splashPathClosed;
}
- if ((first = pathIn->flags[i] & splashPathFirst)) {
- subpathStart = i;
- closed = pathIn->flags[i] & splashPathClosed;
+ j0 = i1 + 1;
+ if (j0 < pathIn->length) {
+ for (j1 = j0;
+ !(pathIn->flags[j1] & splashPathLast) &&
+ j1 + 1 < pathIn->length &&
+ pathIn->pts[j1+1].x == pathIn->pts[j1].x &&
+ pathIn->pts[j1+1].y == pathIn->pts[j1].y;
+ ++j1) ;
+ } else {
+ j1 = j0;
}
- last = pathIn->flags[i+1] & splashPathLast;
-
- // compute the deltas for segment (i, i+1)
- d = splashDist(pathIn->pts[i].x, pathIn->pts[i].y,
- pathIn->pts[i+1].x, pathIn->pts[i+1].y);
- if (d == 0) {
- // we need to draw end caps on zero-length lines
- //~ not clear what the behavior should be for splashLineCapButt
- //~ with d==0
- dx = 0;
- dy = 1;
+ if (pathIn->flags[i1] & splashPathLast) {
+ if (first && state->lineCap == splashLineCapRound) {
+ // special case: zero-length subpath with round line caps -->
+ // draw a circle
+ pathOut->moveTo(pathIn->pts[i0].x + (SplashCoord)0.5 * w,
+ pathIn->pts[i0].y);
+ pathOut->curveTo(pathIn->pts[i0].x + (SplashCoord)0.5 * w,
+ pathIn->pts[i0].y + bezierCircle2 * w,
+ pathIn->pts[i0].x + bezierCircle2 * w,
+ pathIn->pts[i0].y + (SplashCoord)0.5 * w,
+ pathIn->pts[i0].x,
+ pathIn->pts[i0].y + (SplashCoord)0.5 * w);
+ pathOut->curveTo(pathIn->pts[i0].x - bezierCircle2 * w,
+ pathIn->pts[i0].y + (SplashCoord)0.5 * w,
+ pathIn->pts[i0].x - (SplashCoord)0.5 * w,
+ pathIn->pts[i0].y + bezierCircle2 * w,
+ pathIn->pts[i0].x - (SplashCoord)0.5 * w,
+ pathIn->pts[i0].y);
+ pathOut->curveTo(pathIn->pts[i0].x - (SplashCoord)0.5 * w,
+ pathIn->pts[i0].y - bezierCircle2 * w,
+ pathIn->pts[i0].x - bezierCircle2 * w,
+ pathIn->pts[i0].y - (SplashCoord)0.5 * w,
+ pathIn->pts[i0].x,
+ pathIn->pts[i0].y - (SplashCoord)0.5 * w);
+ pathOut->curveTo(pathIn->pts[i0].x + bezierCircle2 * w,
+ pathIn->pts[i0].y - (SplashCoord)0.5 * w,
+ pathIn->pts[i0].x + (SplashCoord)0.5 * w,
+ pathIn->pts[i0].y - bezierCircle2 * w,
+ pathIn->pts[i0].x + (SplashCoord)0.5 * w,
+ pathIn->pts[i0].y);
+ pathOut->close();
+ }
+ i0 = j0;
+ i1 = j1;
+ continue;
+ }
+ last = pathIn->flags[j1] & splashPathLast;
+ if (last) {
+ k0 = subpathStart1 + 1;
} else {
- d = (SplashCoord)1 / d;
- dx = d * (pathIn->pts[i+1].x - pathIn->pts[i].x);
- dy = d * (pathIn->pts[i+1].y - pathIn->pts[i].y);
+ k0 = j1 + 1;
}
+ for (k1 = k0;
+ !(pathIn->flags[k1] & splashPathLast) &&
+ k1 + 1 < pathIn->length &&
+ pathIn->pts[k1+1].x == pathIn->pts[k1].x &&
+ pathIn->pts[k1+1].y == pathIn->pts[k1].y;
+ ++k1) ;
+
+ // compute the deltas for segment (i1, j0)
+#if USE_FIXEDPOINT
+ // the 1/d value can be small, which introduces significant
+ // inaccuracies in fixed point mode
+ d = splashDist(pathIn->pts[i1].x, pathIn->pts[i1].y,
+ pathIn->pts[j0].x, pathIn->pts[j0].y);
+ dx = (pathIn->pts[j0].x - pathIn->pts[i1].x) / d;
+ dy = (pathIn->pts[j0].y - pathIn->pts[i1].y) / d;
+#else
+ d = (SplashCoord)1 / splashDist(pathIn->pts[i1].x, pathIn->pts[i1].y,
+ pathIn->pts[j0].x, pathIn->pts[j0].y);
+ dx = d * (pathIn->pts[j0].x - pathIn->pts[i1].x);
+ dy = d * (pathIn->pts[j0].y - pathIn->pts[i1].y);
+#endif
wdx = (SplashCoord)0.5 * w * dx;
wdy = (SplashCoord)0.5 * w * dy;
- // compute the deltas for segment (i+1, next)
- next = last ? subpathStart + 1 : i + 2;
- d = splashDist(pathIn->pts[i+1].x, pathIn->pts[i+1].y,
- pathIn->pts[next].x, pathIn->pts[next].y);
- if (d == 0) {
- // we need to draw end caps on zero-length lines
- //~ not clear what the behavior should be for splashLineCapButt
- //~ with d==0
- dxNext = 0;
- dyNext = 1;
- } else {
- d = (SplashCoord)1 / d;
- dxNext = d * (pathIn->pts[next].x - pathIn->pts[i+1].x);
- dyNext = d * (pathIn->pts[next].y - pathIn->pts[i+1].y);
- }
- wdxNext = (SplashCoord)0.5 * w * dxNext;
- wdyNext = (SplashCoord)0.5 * w * dyNext;
-
// draw the start cap
- pathOut->moveTo(pathIn->pts[i].x - wdy, pathIn->pts[i].y + wdx);
- if (i == subpathStart) {
+ pathOut->moveTo(pathIn->pts[i0].x - wdy, pathIn->pts[i0].y + wdx);
+ if (i0 == subpathStart0) {
firstPt = pathOut->length - 1;
}
if (first && !closed) {
switch (state->lineCap) {
case splashLineCapButt:
- pathOut->lineTo(pathIn->pts[i].x + wdy, pathIn->pts[i].y - wdx);
+ pathOut->lineTo(pathIn->pts[i0].x + wdy, pathIn->pts[i0].y - wdx);
break;
case splashLineCapRound:
- pathOut->curveTo(pathIn->pts[i].x - wdy - bezierCircle * wdx,
- pathIn->pts[i].y + wdx - bezierCircle * wdy,
- pathIn->pts[i].x - wdx - bezierCircle * wdy,
- pathIn->pts[i].y - wdy + bezierCircle * wdx,
- pathIn->pts[i].x - wdx,
- pathIn->pts[i].y - wdy);
- pathOut->curveTo(pathIn->pts[i].x - wdx + bezierCircle * wdy,
- pathIn->pts[i].y - wdy - bezierCircle * wdx,
- pathIn->pts[i].x + wdy - bezierCircle * wdx,
- pathIn->pts[i].y - wdx - bezierCircle * wdy,
- pathIn->pts[i].x + wdy,
- pathIn->pts[i].y - wdx);
+ pathOut->curveTo(pathIn->pts[i0].x - wdy - bezierCircle * wdx,
+ pathIn->pts[i0].y + wdx - bezierCircle * wdy,
+ pathIn->pts[i0].x - wdx - bezierCircle * wdy,
+ pathIn->pts[i0].y - wdy + bezierCircle * wdx,
+ pathIn->pts[i0].x - wdx,
+ pathIn->pts[i0].y - wdy);
+ pathOut->curveTo(pathIn->pts[i0].x - wdx + bezierCircle * wdy,
+ pathIn->pts[i0].y - wdy - bezierCircle * wdx,
+ pathIn->pts[i0].x + wdy - bezierCircle * wdx,
+ pathIn->pts[i0].y - wdx - bezierCircle * wdy,
+ pathIn->pts[i0].x + wdy,
+ pathIn->pts[i0].y - wdx);
break;
case splashLineCapProjecting:
- pathOut->lineTo(pathIn->pts[i].x - wdx - wdy,
- pathIn->pts[i].y + wdx - wdy);
- pathOut->lineTo(pathIn->pts[i].x - wdx + wdy,
- pathIn->pts[i].y - wdx - wdy);
- pathOut->lineTo(pathIn->pts[i].x + wdy,
- pathIn->pts[i].y - wdx);
+ pathOut->lineTo(pathIn->pts[i0].x - wdx - wdy,
+ pathIn->pts[i0].y + wdx - wdy);
+ pathOut->lineTo(pathIn->pts[i0].x - wdx + wdy,
+ pathIn->pts[i0].y - wdx - wdy);
+ pathOut->lineTo(pathIn->pts[i0].x + wdy,
+ pathIn->pts[i0].y - wdx);
break;
}
} else {
- pathOut->lineTo(pathIn->pts[i].x + wdy, pathIn->pts[i].y - wdx);
+ pathOut->lineTo(pathIn->pts[i0].x + wdy, pathIn->pts[i0].y - wdx);
}
// draw the left side of the segment rectangle
left2 = pathOut->length - 1;
- pathOut->lineTo(pathIn->pts[i+1].x + wdy, pathIn->pts[i+1].y - wdx);
+ pathOut->lineTo(pathIn->pts[j0].x + wdy, pathIn->pts[j0].y - wdx);
// draw the end cap
if (last && !closed) {
switch (state->lineCap) {
case splashLineCapButt:
- pathOut->lineTo(pathIn->pts[i+1].x - wdy, pathIn->pts[i+1].y + wdx);
+ pathOut->lineTo(pathIn->pts[j0].x - wdy, pathIn->pts[j0].y + wdx);
break;
case splashLineCapRound:
- pathOut->curveTo(pathIn->pts[i+1].x + wdy + bezierCircle * wdx,
- pathIn->pts[i+1].y - wdx + bezierCircle * wdy,
- pathIn->pts[i+1].x + wdx + bezierCircle * wdy,
- pathIn->pts[i+1].y + wdy - bezierCircle * wdx,
- pathIn->pts[i+1].x + wdx,
- pathIn->pts[i+1].y + wdy);
- pathOut->curveTo(pathIn->pts[i+1].x + wdx - bezierCircle * wdy,
- pathIn->pts[i+1].y + wdy + bezierCircle * wdx,
- pathIn->pts[i+1].x - wdy + bezierCircle * wdx,
- pathIn->pts[i+1].y + wdx + bezierCircle * wdy,
- pathIn->pts[i+1].x - wdy,
- pathIn->pts[i+1].y + wdx);
+ pathOut->curveTo(pathIn->pts[j0].x + wdy + bezierCircle * wdx,
+ pathIn->pts[j0].y - wdx + bezierCircle * wdy,
+ pathIn->pts[j0].x + wdx + bezierCircle * wdy,
+ pathIn->pts[j0].y + wdy - bezierCircle * wdx,
+ pathIn->pts[j0].x + wdx,
+ pathIn->pts[j0].y + wdy);
+ pathOut->curveTo(pathIn->pts[j0].x + wdx - bezierCircle * wdy,
+ pathIn->pts[j0].y + wdy + bezierCircle * wdx,
+ pathIn->pts[j0].x - wdy + bezierCircle * wdx,
+ pathIn->pts[j0].y + wdx + bezierCircle * wdy,
+ pathIn->pts[j0].x - wdy,
+ pathIn->pts[j0].y + wdx);
break;
case splashLineCapProjecting:
- pathOut->lineTo(pathIn->pts[i+1].x + wdy + wdx,
- pathIn->pts[i+1].y - wdx + wdy);
- pathOut->lineTo(pathIn->pts[i+1].x - wdy + wdx,
- pathIn->pts[i+1].y + wdx + wdy);
- pathOut->lineTo(pathIn->pts[i+1].x - wdy,
- pathIn->pts[i+1].y + wdx);
+ pathOut->lineTo(pathIn->pts[j0].x + wdy + wdx,
+ pathIn->pts[j0].y - wdx + wdy);
+ pathOut->lineTo(pathIn->pts[j0].x - wdy + wdx,
+ pathIn->pts[j0].y + wdx + wdy);
+ pathOut->lineTo(pathIn->pts[j0].x - wdy,
+ pathIn->pts[j0].y + wdx);
break;
}
} else {
- pathOut->lineTo(pathIn->pts[i+1].x - wdy, pathIn->pts[i+1].y + wdx);
+ pathOut->lineTo(pathIn->pts[j0].x - wdy, pathIn->pts[j0].y + wdx);
}
// draw the right side of the segment rectangle
+ // (NB: if stroke adjustment is enabled, the closepath operation MUST
+ // add a segment because this segment is used for a hint)
right2 = pathOut->length - 1;
- pathOut->close();
+ pathOut->close(state->strokeAdjust);
// draw the join
join2 = pathOut->length;
if (!last || closed) {
+
+ // compute the deltas for segment (j1, k0)
+#if USE_FIXEDPOINT
+ // the 1/d value can be small, which introduces significant
+ // inaccuracies in fixed point mode
+ d = splashDist(pathIn->pts[j1].x, pathIn->pts[j1].y,
+ pathIn->pts[k0].x, pathIn->pts[k0].y);
+ dxNext = (pathIn->pts[k0].x - pathIn->pts[j1].x) / d;
+ dyNext = (pathIn->pts[k0].y - pathIn->pts[j1].y) / d;
+#else
+ d = (SplashCoord)1 / splashDist(pathIn->pts[j1].x, pathIn->pts[j1].y,
+ pathIn->pts[k0].x, pathIn->pts[k0].y);
+ dxNext = d * (pathIn->pts[k0].x - pathIn->pts[j1].x);
+ dyNext = d * (pathIn->pts[k0].y - pathIn->pts[j1].y);
+#endif
+ wdxNext = (SplashCoord)0.5 * w * dxNext;
+ wdyNext = (SplashCoord)0.5 * w * dyNext;
+
+ // compute the join parameters
crossprod = dx * dyNext - dy * dxNext;
dotprod = -(dx * dxNext + dy * dyNext);
- if (dotprod > 0.99999) {
+ if (dotprod > 0.9999) {
// avoid a divide-by-zero -- set miter to something arbitrary
// such that sqrt(miter) will exceed miterLimit (and m is never
// used in that situation)
+ // (note: the comparison value (0.9999) has to be less than
+ // 1-epsilon, where epsilon is the smallest value
+ // representable in the fixed point format)
miter = (state->miterLimit + 1) * (state->miterLimit + 1);
m = 0;
} else {
@@ -3848,67 +4524,68 @@ SplashPath *Splash::makeStrokePath(SplashPath *path, GBool flatten) {
// round join
if (state->lineJoin == splashLineJoinRound) {
- pathOut->moveTo(pathIn->pts[i+1].x + (SplashCoord)0.5 * w,
- pathIn->pts[i+1].y);
- pathOut->curveTo(pathIn->pts[i+1].x + (SplashCoord)0.5 * w,
- pathIn->pts[i+1].y + bezierCircle2 * w,
- pathIn->pts[i+1].x + bezierCircle2 * w,
- pathIn->pts[i+1].y + (SplashCoord)0.5 * w,
- pathIn->pts[i+1].x,
- pathIn->pts[i+1].y + (SplashCoord)0.5 * w);
- pathOut->curveTo(pathIn->pts[i+1].x - bezierCircle2 * w,
- pathIn->pts[i+1].y + (SplashCoord)0.5 * w,
- pathIn->pts[i+1].x - (SplashCoord)0.5 * w,
- pathIn->pts[i+1].y + bezierCircle2 * w,
- pathIn->pts[i+1].x - (SplashCoord)0.5 * w,
- pathIn->pts[i+1].y);
- pathOut->curveTo(pathIn->pts[i+1].x - (SplashCoord)0.5 * w,
- pathIn->pts[i+1].y - bezierCircle2 * w,
- pathIn->pts[i+1].x - bezierCircle2 * w,
- pathIn->pts[i+1].y - (SplashCoord)0.5 * w,
- pathIn->pts[i+1].x,
- pathIn->pts[i+1].y - (SplashCoord)0.5 * w);
- pathOut->curveTo(pathIn->pts[i+1].x + bezierCircle2 * w,
- pathIn->pts[i+1].y - (SplashCoord)0.5 * w,
- pathIn->pts[i+1].x + (SplashCoord)0.5 * w,
- pathIn->pts[i+1].y - bezierCircle2 * w,
- pathIn->pts[i+1].x + (SplashCoord)0.5 * w,
- pathIn->pts[i+1].y);
+ pathOut->moveTo(pathIn->pts[j0].x + (SplashCoord)0.5 * w,
+ pathIn->pts[j0].y);
+ pathOut->curveTo(pathIn->pts[j0].x + (SplashCoord)0.5 * w,
+ pathIn->pts[j0].y + bezierCircle2 * w,
+ pathIn->pts[j0].x + bezierCircle2 * w,
+ pathIn->pts[j0].y + (SplashCoord)0.5 * w,
+ pathIn->pts[j0].x,
+ pathIn->pts[j0].y + (SplashCoord)0.5 * w);
+ pathOut->curveTo(pathIn->pts[j0].x - bezierCircle2 * w,
+ pathIn->pts[j0].y + (SplashCoord)0.5 * w,
+ pathIn->pts[j0].x - (SplashCoord)0.5 * w,
+ pathIn->pts[j0].y + bezierCircle2 * w,
+ pathIn->pts[j0].x - (SplashCoord)0.5 * w,
+ pathIn->pts[j0].y);
+ pathOut->curveTo(pathIn->pts[j0].x - (SplashCoord)0.5 * w,
+ pathIn->pts[j0].y - bezierCircle2 * w,
+ pathIn->pts[j0].x - bezierCircle2 * w,
+ pathIn->pts[j0].y - (SplashCoord)0.5 * w,
+ pathIn->pts[j0].x,
+ pathIn->pts[j0].y - (SplashCoord)0.5 * w);
+ pathOut->curveTo(pathIn->pts[j0].x + bezierCircle2 * w,
+ pathIn->pts[j0].y - (SplashCoord)0.5 * w,
+ pathIn->pts[j0].x + (SplashCoord)0.5 * w,
+ pathIn->pts[j0].y - bezierCircle2 * w,
+ pathIn->pts[j0].x + (SplashCoord)0.5 * w,
+ pathIn->pts[j0].y);
} else {
- pathOut->moveTo(pathIn->pts[i+1].x, pathIn->pts[i+1].y);
+ pathOut->moveTo(pathIn->pts[j0].x, pathIn->pts[j0].y);
// angle < 180
if (crossprod < 0) {
- pathOut->lineTo(pathIn->pts[i+1].x - wdyNext,
- pathIn->pts[i+1].y + wdxNext);
+ pathOut->lineTo(pathIn->pts[j0].x - wdyNext,
+ pathIn->pts[j0].y + wdxNext);
// miter join inside limit
if (state->lineJoin == splashLineJoinMiter &&
splashSqrt(miter) <= state->miterLimit) {
- pathOut->lineTo(pathIn->pts[i+1].x - wdy + wdx * m,
- pathIn->pts[i+1].y + wdx + wdy * m);
- pathOut->lineTo(pathIn->pts[i+1].x - wdy,
- pathIn->pts[i+1].y + wdx);
+ pathOut->lineTo(pathIn->pts[j0].x - wdy + wdx * m,
+ pathIn->pts[j0].y + wdx + wdy * m);
+ pathOut->lineTo(pathIn->pts[j0].x - wdy,
+ pathIn->pts[j0].y + wdx);
// bevel join or miter join outside limit
} else {
- pathOut->lineTo(pathIn->pts[i+1].x - wdy, pathIn->pts[i+1].y + wdx);
+ pathOut->lineTo(pathIn->pts[j0].x - wdy,
+ pathIn->pts[j0].y + wdx);
}
// angle >= 180
} else {
- pathOut->lineTo(pathIn->pts[i+1].x + wdy,
- pathIn->pts[i+1].y - wdx);
+ pathOut->lineTo(pathIn->pts[j0].x + wdy,
+ pathIn->pts[j0].y - wdx);
// miter join inside limit
if (state->lineJoin == splashLineJoinMiter &&
splashSqrt(miter) <= state->miterLimit) {
- pathOut->lineTo(pathIn->pts[i+1].x + wdy + wdx * m,
- pathIn->pts[i+1].y - wdx + wdy * m);
- pathOut->lineTo(pathIn->pts[i+1].x + wdyNext,
- pathIn->pts[i+1].y - wdxNext);
+ pathOut->lineTo(pathIn->pts[j0].x + wdy + wdx * m,
+ pathIn->pts[j0].y - wdx + wdy * m);
+ pathOut->lineTo(pathIn->pts[j0].x + wdyNext,
+ pathIn->pts[j0].y - wdxNext);
// bevel join or miter join outside limit
} else {
- pathOut->lineTo(pathIn->pts[i+1].x + wdyNext,
- pathIn->pts[i+1].y - wdxNext);
+ pathOut->lineTo(pathIn->pts[j0].x + wdyNext,
+ pathIn->pts[j0].y - wdxNext);
}
}
}
@@ -3918,8 +4595,28 @@ SplashPath *Splash::makeStrokePath(SplashPath *path, GBool flatten) {
// add stroke adjustment hints
if (state->strokeAdjust) {
- if (i >= subpathStart + 1) {
- if (i >= subpathStart + 2) {
+ if (seg == 0 && !closed) {
+ if (state->lineCap == splashLineCapButt) {
+ pathOut->addStrokeAdjustHint(firstPt, left2 + 1,
+ firstPt, firstPt + 1);
+ if (last) {
+ pathOut->addStrokeAdjustHint(firstPt, left2 + 1,
+ left2 + 1, left2 + 2);
+ }
+ } else if (state->lineCap == splashLineCapProjecting) {
+ if (last) {
+ pathOut->addStrokeAdjustHint(firstPt + 1, left2 + 2,
+ firstPt + 1, firstPt + 2);
+ pathOut->addStrokeAdjustHint(firstPt + 1, left2 + 2,
+ left2 + 2, left2 + 3);
+ } else {
+ pathOut->addStrokeAdjustHint(firstPt + 1, left2 + 1,
+ firstPt + 1, firstPt + 2);
+ }
+ }
+ }
+ if (seg >= 1) {
+ if (seg >= 2) {
pathOut->addStrokeAdjustHint(left1, right1, left0 + 1, right0);
pathOut->addStrokeAdjustHint(left1, right1, join0, left2);
} else {
@@ -3933,12 +4630,12 @@ SplashPath *Splash::makeStrokePath(SplashPath *path, GBool flatten) {
right1 = right2;
join0 = join1;
join1 = join2;
- if (i == subpathStart) {
+ if (seg == 0) {
leftFirst = left2;
rightFirst = right2;
}
if (last) {
- if (i >= subpathStart + 2) {
+ if (seg >= 2) {
pathOut->addStrokeAdjustHint(left1, right1, left0 + 1, right0);
pathOut->addStrokeAdjustHint(left1, right1,
join0, pathOut->length - 1);
@@ -3955,8 +4652,21 @@ SplashPath *Splash::makeStrokePath(SplashPath *path, GBool flatten) {
pathOut->addStrokeAdjustHint(leftFirst, rightFirst,
join1, pathOut->length - 1);
}
+ if (!closed && seg > 0) {
+ if (state->lineCap == splashLineCapButt) {
+ pathOut->addStrokeAdjustHint(left1 - 1, left1 + 1,
+ left1 + 1, left1 + 2);
+ } else if (state->lineCap == splashLineCapProjecting) {
+ pathOut->addStrokeAdjustHint(left1 - 1, left1 + 2,
+ left1 + 2, left1 + 3);
+ }
+ }
}
}
+
+ i0 = j0;
+ i1 = j1;
+ ++seg;
}
if (pathIn != path) {
@@ -4011,7 +4721,13 @@ SplashError Splash::shadedFill(SplashPath *path, GBool hasBBox,
xPath->aaScale();
}
xPath->sort();
- scanner = new SplashXPathScanner(xPath, gFalse);
+ yMinI = state->clip->getYMinI();
+ yMaxI = state->clip->getYMaxI();
+ if (vectorAntialias && !inShading) {
+ yMinI = yMinI * splashAASize;
+ yMaxI = (yMaxI + 1) * splashAASize - 1;
+ }
+ scanner = new SplashXPathScanner(xPath, gFalse, yMinI, yMaxI);
// get the min and max x and y values
if (vectorAntialias) {
@@ -4030,7 +4746,7 @@ SplashError Splash::shadedFill(SplashPath *path, GBool hasBBox,
yMaxI = state->clip->getYMaxI();
}
- pipeInit(&pipe, 0, yMinI, pattern, NULL, state->fillAlpha, vectorAntialias && !hasBBox, gFalse, pattern);
+ pipeInit(&pipe, 0, yMinI, pattern, NULL, (Guchar)splashRound(state->fillAlpha * 255), vectorAntialias && !hasBBox, gFalse);
// draw the spans
if (vectorAntialias) {
diff --git a/splash/Splash.h b/splash/Splash.h
index 85f92ed..e538808 100644
--- a/splash/Splash.h
+++ b/splash/Splash.h
@@ -108,6 +108,7 @@ public:
SplashCoord *getLineDash();
int getLineDashLength();
SplashCoord getLineDashPhase();
+ GBool getStrokeAdjust();
SplashClip *getClip();
SplashBitmap *getSoftMask();
GBool getInNonIsolatedGroup();
@@ -144,6 +145,8 @@ public:
void setSoftMask(SplashBitmap *softMask);
void setInNonIsolatedGroup(SplashBitmap *alpha0BitmapA,
int alpha0XA, int alpha0YA);
+ void setTransfer(Guchar *red, Guchar *green, Guchar *blue, Guchar *gray);
+ void setOverprintMask(Guint overprintMask);
//----- state save/restore
@@ -226,14 +229,19 @@ public:
//----- misc
- // Construct a path for a stroke, given the path to be stroked, and
- // using the current line parameters. If <flatten> is true, this
- // function will first flatten the path and handle the linedash.
- SplashPath *makeStrokePath(SplashPath *path, GBool flatten = gTrue);
+ // Construct a path for a stroke, given the path to be stroked and
+ // the line width <w>. All other stroke parameters are taken from
+ // the current state. If <flatten> is true, this function will
+ // first flatten the path and handle the linedash.
+ SplashPath *makeStrokePath(SplashPath *path, SplashCoord w,
+ GBool flatten = gTrue);
// Return the associated bitmap.
SplashBitmap *getBitmap() { return bitmap; }
+ // Set the minimum line width.
+ void setMinLineWidth(SplashCoord w) { minLineWidth = w; }
+
// Get a bounding box which includes all modifications since the
// last call to clearModRegion.
void getModRegion(int *xMin, int *yMin, int *xMax, int *yMax)
@@ -250,6 +258,7 @@ public:
void setDebugMode(GBool debugModeA) { debugMode = debugModeA; }
#if 1 //~tmp: turn off anti-aliasing temporarily
+ void setInShading(GBool sh) { inShading = sh; }
GBool getVectorAntialias() { return vectorAntialias; }
void setVectorAntialias(GBool vaa) { vectorAntialias = vaa; }
#endif
@@ -264,9 +273,25 @@ private:
void pipeInit(SplashPipe *pipe, int x, int y,
SplashPattern *pattern, SplashColorPtr cSrc,
- SplashCoord aInput, GBool usesShape,
- GBool nonIsolatedGroup, SplashPattern *overprintPattern = NULL, GBool stroke = gFalse);
+ Guchar aInput, GBool usesShape,
+ GBool nonIsolatedGroup);
void pipeRun(SplashPipe *pipe);
+ void pipeRunSimpleMono1(SplashPipe *pipe);
+ void pipeRunSimpleMono8(SplashPipe *pipe);
+ void pipeRunSimpleRGB8(SplashPipe *pipe);
+ void pipeRunSimpleXBGR8(SplashPipe *pipe);
+ void pipeRunSimpleBGR8(SplashPipe *pipe);
+#if SPLASH_CMYK
+ void pipeRunSimpleCMYK8(SplashPipe *pipe);
+#endif
+ void pipeRunAAMono1(SplashPipe *pipe);
+ void pipeRunAAMono8(SplashPipe *pipe);
+ void pipeRunAARGB8(SplashPipe *pipe);
+ void pipeRunAAXBGR8(SplashPipe *pipe);
+ void pipeRunAABGR8(SplashPipe *pipe);
+#if SPLASH_CMYK
+ void pipeRunAACMYK8(SplashPipe *pipe);
+#endif
void pipeSetXY(SplashPipe *pipe, int x, int y);
void pipeIncX(SplashPipe *pipe);
void drawPixel(SplashPipe *pipe, int x, int y, GBool noClip);
@@ -279,7 +304,7 @@ private:
void updateModX(int x);
void updateModY(int y);
void strokeNarrow(SplashPath *path);
- void strokeWide(SplashPath *path);
+ void strokeWide(SplashPath *path, SplashCoord w);
SplashPath *flattenPath(SplashPath *path, SplashCoord *matrix,
SplashCoord flatness);
void flattenCurve(SplashCoord x0, SplashCoord y0,
@@ -291,6 +316,7 @@ private:
SplashPath *makeDashedPath(SplashPath *xPath);
SplashError fillWithPattern(SplashPath *path, GBool eo,
SplashPattern *pattern, SplashCoord alpha);
+ GBool pathAllOutside(SplashPath *path);
void fillGlyph2(int x0, int y0, SplashGlyphBitmap *glyph, GBool noclip);
void dumpPath(SplashPath *path);
void dumpXPath(SplashXPath *path);
@@ -308,9 +334,11 @@ private:
// bitmap containing the alpha0 values
int alpha0X, alpha0Y; // offset within alpha0Bitmap
SplashCoord aaGamma[splashAASize * splashAASize + 1];
+ SplashCoord minLineWidth;
int modXMin, modYMin, modXMax, modYMax;
SplashClipResult opClipRes;
GBool vectorAntialias;
+ GBool inShading;
GBool debugMode;
};
diff --git a/splash/SplashClip.cc b/splash/SplashClip.cc
index 5add152..41b73c8 100644
--- a/splash/SplashClip.cc
+++ b/splash/SplashClip.cc
@@ -64,8 +64,8 @@ SplashClip::SplashClip(SplashCoord x0, SplashCoord y0,
}
xMinI = splashFloor(xMin);
yMinI = splashFloor(yMin);
- xMaxI = splashFloor(xMax);
- yMaxI = splashFloor(yMax);
+ xMaxI = splashCeil(xMax) - 1;
+ yMaxI = splashCeil(yMax) - 1;
paths = NULL;
flags = NULL;
scanners = NULL;
@@ -73,6 +73,7 @@ SplashClip::SplashClip(SplashCoord x0, SplashCoord y0,
}
SplashClip::SplashClip(SplashClip *clip) {
+ int yMinAA, yMaxAA;
int i;
antialias = clip->antialias;
@@ -93,7 +94,15 @@ SplashClip::SplashClip(SplashClip *clip) {
for (i = 0; i < length; ++i) {
paths[i] = clip->paths[i]->copy();
flags[i] = clip->flags[i];
- scanners[i] = new SplashXPathScanner(paths[i], flags[i] & splashClipEO);
+ 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);
}
}
@@ -156,8 +165,8 @@ void SplashClip::resetToRect(SplashCoord x0, SplashCoord y0,
}
xMinI = splashFloor(xMin);
yMinI = splashFloor(yMin);
- xMaxI = splashFloor(xMax);
- yMaxI = splashFloor(yMax);
+ xMaxI = splashCeil(xMax) - 1;
+ yMaxI = splashCeil(yMax) - 1;
}
SplashError SplashClip::clipToRect(SplashCoord x0, SplashCoord y0,
@@ -169,7 +178,7 @@ SplashError SplashClip::clipToRect(SplashCoord x0, SplashCoord y0,
}
if (x1 < xMax) {
xMax = x1;
- xMaxI = splashFloor(xMax);
+ xMaxI = splashCeil(xMax) - 1;
}
} else {
if (x1 > xMin) {
@@ -178,7 +187,7 @@ SplashError SplashClip::clipToRect(SplashCoord x0, SplashCoord y0,
}
if (x0 < xMax) {
xMax = x0;
- xMaxI = splashFloor(xMax);
+ xMaxI = splashCeil(xMax) - 1;
}
}
if (y0 < y1) {
@@ -188,7 +197,7 @@ SplashError SplashClip::clipToRect(SplashCoord x0, SplashCoord y0,
}
if (y1 < yMax) {
yMax = y1;
- yMaxI = splashFloor(yMax);
+ yMaxI = splashCeil(yMax) - 1;
}
} else {
if (y1 > yMin) {
@@ -197,7 +206,7 @@ SplashError SplashClip::clipToRect(SplashCoord x0, SplashCoord y0,
}
if (y0 < yMax) {
yMax = y0;
- yMaxI = splashFloor(yMax);
+ yMaxI = splashCeil(yMax) - 1;
}
}
return splashOk;
@@ -206,6 +215,7 @@ SplashError SplashClip::clipToRect(SplashCoord x0, SplashCoord y0,
SplashError SplashClip::clipToPath(SplashPath *path, SplashCoord *matrix,
SplashCoord flatness, GBool eo) {
SplashXPath *xPath;
+ int yMinAA, yMaxAA;
xPath = new SplashXPath(path, matrix, flatness, gTrue);
@@ -213,8 +223,8 @@ SplashError SplashClip::clipToPath(SplashPath *path, SplashCoord *matrix,
if (xPath->length == 0) {
xMax = xMin - 1;
yMax = yMin - 1;
- xMaxI = splashFloor(xMax);
- yMaxI = splashFloor(yMax);
+ xMaxI = splashCeil(xMax) - 1;
+ yMaxI = splashCeil(yMax) - 1;
delete xPath;
// check for a rectangle
@@ -255,7 +265,14 @@ SplashError SplashClip::clipToPath(SplashPath *path, SplashCoord *matrix,
xPath->sort();
paths[length] = xPath;
flags[length] = eo ? splashClipEO : 0;
- scanners[length] = new SplashXPathScanner(xPath, eo);
+ if (antialias) {
+ yMinAA = yMinI * splashAASize;
+ yMaxAA = (yMaxI + 1) * splashAASize - 1;
+ } else {
+ yMinAA = yMinI;
+ yMaxAA = yMaxI;
+ }
+ scanners[length] = new SplashXPathScanner(xPath, eo, yMinAA, yMaxAA);
++length;
}
@@ -268,10 +285,10 @@ SplashClipResult SplashClip::testRect(int rectXMin, int rectYMin,
// 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) {
+ // x = [xMin, xMax) (note: clipping coords are fp)
+ // y = [yMin, yMax)
+ if ((SplashCoord)(rectXMax + 1) <= xMin || (SplashCoord)rectXMin >= xMax ||
+ (SplashCoord)(rectYMax + 1) <= yMin || (SplashCoord)rectYMin >= yMax) {
return splashClipAllOutside;
}
if ((SplashCoord)rectXMin >= xMin && (SplashCoord)(rectXMax + 1) <= xMax &&
@@ -289,10 +306,10 @@ SplashClipResult SplashClip::testSpan(int spanXMin, int spanXMax, int spanY) {
// 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) {
+ // 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 &&
diff --git a/splash/SplashState.cc b/splash/SplashState.cc
index 15b6a72..7b632b8 100644
--- a/splash/SplashState.cc
+++ b/splash/SplashState.cc
@@ -47,6 +47,7 @@ int splashColorModeNComps[] = {
SplashState::SplashState(int width, int height, GBool vectorAntialias,
SplashScreenParams *screenParams) {
SplashColor color;
+ int i;
matrix[0] = 1; matrix[1] = 0;
matrix[2] = 0; matrix[3] = 1;
@@ -74,12 +75,24 @@ SplashState::SplashState(int width, int height, GBool vectorAntialias,
fillOverprint = gFalse;
strokeOverprint = gFalse;
overprintMode = 0;
+ for (i = 0; i < 256; ++i) {
+ rgbTransferR[i] = (Guchar)i;
+ rgbTransferG[i] = (Guchar)i;
+ rgbTransferB[i] = (Guchar)i;
+ grayTransfer[i] = (Guchar)i;
+ cmykTransferC[i] = (Guchar)i;
+ cmykTransferM[i] = (Guchar)i;
+ cmykTransferY[i] = (Guchar)i;
+ cmykTransferK[i] = (Guchar)i;
+ }
+ overprintMask = 0xffffffff;
next = NULL;
}
SplashState::SplashState(int width, int height, GBool vectorAntialias,
SplashScreen *screenA) {
SplashColor color;
+ int i;
matrix[0] = 1; matrix[1] = 0;
matrix[2] = 0; matrix[3] = 1;
@@ -107,6 +120,17 @@ SplashState::SplashState(int width, int height, GBool vectorAntialias,
fillOverprint = gFalse;
strokeOverprint = gFalse;
overprintMode = 0;
+ for (i = 0; i < 256; ++i) {
+ rgbTransferR[i] = (Guchar)i;
+ rgbTransferG[i] = (Guchar)i;
+ rgbTransferB[i] = (Guchar)i;
+ grayTransfer[i] = (Guchar)i;
+ cmykTransferC[i] = (Guchar)i;
+ cmykTransferM[i] = (Guchar)i;
+ cmykTransferY[i] = (Guchar)i;
+ cmykTransferK[i] = (Guchar)i;
+ }
+ overprintMask = 0xffffffff;
next = NULL;
}
@@ -140,6 +164,15 @@ SplashState::SplashState(SplashState *state) {
fillOverprint = state->fillOverprint;
strokeOverprint = state->strokeOverprint;
overprintMode = state->overprintMode;
+ memcpy(rgbTransferR, state->rgbTransferR, 256);
+ memcpy(rgbTransferG, state->rgbTransferG, 256);
+ memcpy(rgbTransferB, state->rgbTransferB, 256);
+ memcpy(grayTransfer, state->grayTransfer, 256);
+ memcpy(cmykTransferC, state->cmykTransferC, 256);
+ memcpy(cmykTransferM, state->cmykTransferM, 256);
+ memcpy(cmykTransferY, state->cmykTransferY, 256);
+ memcpy(cmykTransferK, state->cmykTransferK, 256);
+ overprintMask = state->overprintMask;
next = NULL;
}
@@ -189,3 +222,19 @@ void SplashState::setSoftMask(SplashBitmap *softMaskA) {
softMask = softMaskA;
deleteSoftMask = gTrue;
}
+
+void SplashState::setTransfer(Guchar *red, Guchar *green, Guchar *blue,
+ Guchar *gray) {
+ int i;
+
+ memcpy(rgbTransferR, red, 256);
+ memcpy(rgbTransferG, green, 256);
+ memcpy(rgbTransferB, blue, 256);
+ memcpy(grayTransfer, gray, 256);
+ for (i = 0; i < 256; ++i) {
+ cmykTransferC[i] = 255 - rgbTransferR[255 - i];
+ cmykTransferM[i] = 255 - rgbTransferG[255 - i];
+ cmykTransferY[i] = 255 - rgbTransferB[255 - i];
+ cmykTransferK[i] = 255 - grayTransfer[255 - i];
+ }
+}
diff --git a/splash/SplashState.h b/splash/SplashState.h
index 63dadc6..214bffa 100644
--- a/splash/SplashState.h
+++ b/splash/SplashState.h
@@ -87,6 +87,9 @@ public:
void setStrokeOverprint(GBool strokeOverprintA) { strokeOverprint = strokeOverprintA; }
void setOverprintMode(int overprintModeA) { overprintMode = overprintModeA; }
+ // Set the transfer function.
+ void setTransfer(Guchar *red, Guchar *green, Guchar *blue, Guchar *gray);
+
private:
SplashState(SplashState *state);
@@ -114,6 +117,15 @@ private:
GBool fillOverprint;
GBool strokeOverprint;
int overprintMode;
+ Guchar rgbTransferR[256],
+ rgbTransferG[256],
+ rgbTransferB[256];
+ Guchar grayTransfer[256];
+ Guchar cmykTransferC[256],
+ cmykTransferM[256],
+ cmykTransferY[256],
+ cmykTransferK[256];
+ Guint overprintMask;
SplashState *next; // used by Splash class
diff --git a/splash/SplashXPathScanner.cc b/splash/SplashXPathScanner.cc
index 33aa392..c9fe5e5 100644
--- a/splash/SplashXPathScanner.cc
+++ b/splash/SplashXPathScanner.cc
@@ -37,25 +37,30 @@
//------------------------------------------------------------------------
struct SplashIntersect {
+ int y;
int x0, x1; // intersection of segment with [y, y+1)
int count; // EO/NZWN counter increment
};
-static bool cmpIntersect(const SplashIntersect &p0, const SplashIntersect &p1) {
- return p0.x0 < p1.x0;
-}
+struct cmpIntersectFunctor {
+ bool operator()(const SplashIntersect &i0, const SplashIntersect &i1) {
+ return (i0.y != i1.y) ? (i0.y < i1.y) : (i0.x0 < i1.x0);
+ }
+};
//------------------------------------------------------------------------
// SplashXPathScanner
//------------------------------------------------------------------------
-SplashXPathScanner::SplashXPathScanner(SplashXPath *xPathA, GBool eoA) {
+SplashXPathScanner::SplashXPathScanner(SplashXPath *xPathA, GBool eoA,
+ int clipYMin, int clipYMax) {
SplashXPathSeg *seg;
SplashCoord xMinFP, yMinFP, xMaxFP, yMaxFP;
int i;
xPath = xPathA;
eo = eoA;
+ partialClip = gFalse;
// compute the bbox
if (xPath->length == 0) {
@@ -103,16 +108,25 @@ SplashXPathScanner::SplashXPathScanner(SplashXPath *xPathA, GBool eoA) {
xMax = splashFloor(xMaxFP);
yMin = splashFloor(yMinFP);
yMax = splashFloor(yMaxFP);
+ if (clipYMin > yMin) {
+ yMin = clipYMin;
+ partialClip = gTrue;
+ }
+ if (clipYMax < yMax) {
+ yMax = clipYMax;
+ partialClip = gTrue;
+ }
}
- interY = yMin - 1;
- xPathIdx = 0;
+ allInter = NULL;
inter = NULL;
- interLen = interSize = 0;
+ computeIntersections();
+ interY = yMin - 1;
}
SplashXPathScanner::~SplashXPathScanner() {
gfree(inter);
+ gfree(allInter);
}
void SplashXPathScanner::getBBoxAA(int *xMinA, int *yMinA,
@@ -124,12 +138,23 @@ void SplashXPathScanner::getBBoxAA(int *xMinA, int *yMinA,
}
void SplashXPathScanner::getSpanBounds(int y, int *spanXMin, int *spanXMax) {
- if (interY != y) {
- computeIntersections(y);
+ int interBegin, interEnd, xx, i;
+
+ if (y < yMin || y > yMax) {
+ interBegin = interEnd = 0;
+ } else {
+ interBegin = inter[y - yMin];
+ interEnd = inter[y - yMin + 1];
}
- if (interLen > 0) {
- *spanXMin = inter[0].x0;
- *spanXMax = inter[interLen - 1].x1;
+ 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;
+ }
+ }
+ *spanXMax = xx;
} else {
*spanXMin = xMax + 1;
*spanXMax = xMax;
@@ -137,47 +162,50 @@ void SplashXPathScanner::getSpanBounds(int y, int *spanXMin, int *spanXMax) {
}
GBool SplashXPathScanner::test(int x, int y) {
- int count, i;
+ int interBegin, interEnd, count, i;
- if (interY != y) {
- computeIntersections(y);
+ if (y < yMin || y > yMax) {
+ return gFalse;
}
+ interBegin = inter[y - yMin];
+ interEnd = inter[y - yMin + 1];
count = 0;
- for (i = 0; i < interLen && inter[i].x0 <= x; ++i) {
- if (x <= inter[i].x1) {
+ for (i = interBegin; i < interEnd && allInter[i].x0 <= x; ++i) {
+ if (x <= allInter[i].x1) {
return gTrue;
}
- count += inter[i].count;
+ count += allInter[i].count;
}
return eo ? (count & 1) : (count != 0);
}
GBool SplashXPathScanner::testSpan(int x0, int x1, int y) {
- int count, xx1, i;
+ int interBegin, interEnd, count, xx1, i;
- if (interY != y) {
- computeIntersections(y);
+ if (y < yMin || y > yMax) {
+ return gFalse;
}
-
+ interBegin = inter[y - yMin];
+ interEnd = inter[y - yMin + 1];
count = 0;
- for (i = 0; i < interLen && inter[i].x1 < x0; ++i) {
- count += inter[i].count;
+ for (i = interBegin; i < interEnd && allInter[i].x1 < x0; ++i) {
+ count += allInter[i].count;
}
// invariant: the subspan [x0,xx1] is inside the path
xx1 = x0 - 1;
while (xx1 < x1) {
- if (i >= interLen) {
+ if (i >= interEnd) {
return gFalse;
}
- if (inter[i].x0 > xx1 + 1 &&
+ if (allInter[i].x0 > xx1 + 1 &&
!(eo ? (count & 1) : (count != 0))) {
return gFalse;
}
- if (inter[i].x1 > xx1) {
- xx1 = inter[i].x1;
+ if (allInter[i].x1 > xx1) {
+ xx1 = allInter[i].x1;
}
- count += inter[i].count;
+ count += allInter[i].count;
++i;
}
@@ -185,25 +213,31 @@ GBool SplashXPathScanner::testSpan(int x0, int x1, int y) {
}
GBool SplashXPathScanner::getNextSpan(int y, int *x0, int *x1) {
- int xx0, xx1;
+ int interEnd, xx0, xx1;
+ if (y < yMin || y > yMax) {
+ return gFalse;
+ }
if (interY != y) {
- computeIntersections(y);
+ interY = y;
+ interIdx = inter[y - yMin];
+ interCount = 0;
}
- if (interIdx >= interLen) {
+ interEnd = inter[y - yMin + 1];
+ if (interIdx >= interEnd) {
return gFalse;
}
- xx0 = inter[interIdx].x0;
- xx1 = inter[interIdx].x1;
- interCount += inter[interIdx].count;
+ xx0 = allInter[interIdx].x0;
+ xx1 = allInter[interIdx].x1;
+ interCount += allInter[interIdx].count;
++interIdx;
- while (interIdx < interLen &&
- (inter[interIdx].x0 <= xx1 ||
+ while (interIdx < interEnd &&
+ (allInter[interIdx].x0 <= xx1 ||
(eo ? (interCount & 1) : (interCount != 0)))) {
- if (inter[interIdx].x1 > xx1) {
- xx1 = inter[interIdx].x1;
+ if (allInter[interIdx].x1 > xx1) {
+ xx1 = allInter[interIdx].x1;
}
- interCount += inter[interIdx].count;
+ interCount += allInter[interIdx].count;
++interIdx;
}
*x0 = xx0;
@@ -211,161 +245,199 @@ GBool SplashXPathScanner::getNextSpan(int y, int *x0, int *x1) {
return gTrue;
}
-void SplashXPathScanner::computeIntersections(int y) {
- SplashCoord xSegMin, xSegMax, ySegMin, ySegMax, xx0, xx1;
+void SplashXPathScanner::computeIntersections() {
SplashXPathSeg *seg;
- int i, j;
+ SplashCoord segXMin, segXMax, segYMin, segYMax, xx0, xx1;
+ int x, y, y0, y1, i;
- // find the first segment that intersects [y, y+1)
- i = (y >= interY) ? xPathIdx : 0;
- while (i < xPath->length &&
- xPath->segs[i].y0 < y && xPath->segs[i].y1 < y) {
- ++i;
+ if (yMin > yMax) {
+ return;
}
- xPathIdx = i;
- // find all of the segments that intersect [y, y+1) and create an
- // Intersect element for each one
- interLen = 0;
- for (j = i; j < xPath->length; ++j) {
- seg = &xPath->segs[j];
+ // 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) {
- ySegMin = seg->y1;
- ySegMax = seg->y0;
+ segYMin = seg->y1;
+ segYMax = seg->y0;
} else {
- ySegMin = seg->y0;
- ySegMax = seg->y1;
- }
-
- // ensure that: ySegMin < y+1
- // y <= ySegMax
- if (ySegMin >= y + 1) {
- break;
+ segYMin = seg->y0;
+ segYMax = seg->y1;
}
- if (ySegMax < y) {
- continue;
- }
-
- if (interLen == interSize) {
- if (interSize == 0) {
- interSize = 16;
- } else {
- interSize *= 2;
- }
- inter = (SplashIntersect *)greallocn(inter, interSize,
- sizeof(SplashIntersect));
- }
-
if (seg->flags & splashXPathHoriz) {
- xx0 = seg->x0;
- xx1 = seg->x1;
+ 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) {
- xx0 = xx1 = seg->x0;
+ y0 = splashFloor(segYMin);
+ if (y0 < yMin) {
+ y0 = yMin;
+ }
+ y1 = splashFloor(segYMax);
+ if (y1 > yMax) {
+ y1 = yMax;
+ }
+ x = splashFloor(seg->x0);
+ for (y = y0; y <= y1; ++y) {
+ addIntersection(segYMin, segYMax, seg->flags, y, x, x);
+ }
} else {
if (seg->x0 < seg->x1) {
- xSegMin = seg->x0;
- xSegMax = seg->x1;
+ segXMin = seg->x0;
+ segXMax = seg->x1;
} else {
- xSegMin = seg->x1;
- xSegMax = seg->x0;
+ segXMin = seg->x1;
+ segXMax = seg->x0;
}
- // intersection with top edge
- xx0 = seg->x0 + ((SplashCoord)y - seg->y0) * seg->dxdy;
- // intersection with bottom edge
- 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 < xSegMin) {
- xx0 = xSegMin;
- } else if (xx0 > xSegMax) {
- xx0 = xSegMax;
+ y0 = splashFloor(segYMin);
+ if (y0 < yMin) {
+ y0 = yMin;
}
- if (xx1 < xSegMin) {
- xx1 = xSegMin;
- } else if (xx1 > xSegMax) {
- xx1 = xSegMax;
+ y1 = splashFloor(segYMax);
+ if (y1 > yMax) {
+ y1 = yMax;
+ }
+ // 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));
}
}
- if (xx0 < xx1) {
- inter[interLen].x0 = splashFloor(xx0);
- inter[interLen].x1 = splashFloor(xx1);
- } else {
- inter[interLen].x0 = splashFloor(xx1);
- inter[interLen].x1 = splashFloor(xx0);
- }
- if (ySegMin <= y &&
- (SplashCoord)y < ySegMax &&
- !(seg->flags & splashXPathHoriz)) {
- inter[interLen].count = eo ? 1
- : (seg->flags & splashXPathFlip) ? 1 : -1;
- } else {
- inter[interLen].count = 0;
+ }
+ std::sort(allInter, allInter + allInterLen, cmpIntersectFunctor());
+
+ // 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;
}
- ++interLen;
}
+ inter[yMax - yMin + 1] = i;
+}
- std::sort(inter, inter + interLen, cmpIntersect);
-
- interY = y;
- interIdx = 0;
- interCount = 0;
+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));
+ }
+ allInter[allInterLen].y = y;
+ if (x0 < x1) {
+ allInter[allInterLen].x0 = x0;
+ allInter[allInterLen].x1 = x1;
+ } else {
+ allInter[allInterLen].x0 = x1;
+ allInter[allInterLen].x1 = x0;
+ }
+ if (segYMin <= y &&
+ (SplashCoord)y < segYMax &&
+ !(segFlags & splashXPathHoriz)) {
+ allInter[allInterLen].count = eo ? 1
+ : (segFlags & splashXPathFlip) ? 1 : -1;
+ } else {
+ allInter[allInterLen].count = 0;
+ }
+ ++allInterLen;
}
void SplashXPathScanner::renderAALine(SplashBitmap *aaBuf,
int *x0, int *x1, int y) {
- int xx0, xx1, xx, xxMin, xxMax, yy;
+ 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;
- for (yy = 0; yy < splashAASize; ++yy) {
- computeIntersections(splashAASize * y + yy);
- while (interIdx < interLen) {
- xx0 = inter[interIdx].x0;
- xx1 = inter[interIdx].x1;
- interCount += inter[interIdx].count;
- ++interIdx;
- while (interIdx < interLen &&
- (inter[interIdx].x0 <= xx1 ||
- (eo ? (interCount & 1) : (interCount != 0)))) {
- if (inter[interIdx].x1 > xx1) {
- xx1 = inter[interIdx].x1;
- }
- interCount += inter[interIdx].count;
- ++interIdx;
- }
- if (xx0 < 0) {
- xx0 = 0;
- }
- ++xx1;
- if (xx1 > aaBuf->getWidth()) {
- xx1 = aaBuf->getWidth();
+ if (yMin <= yMax) {
+ if (splashAASize * y < yMin) {
+ interIdx = inter[0];
+ } else if (splashAASize * y > yMax) {
+ interIdx = inter[yMax - yMin + 1];
+ } else {
+ interIdx = inter[splashAASize * y - yMin];
+ }
+ 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 {
+ interEnd = inter[splashAASize * y + yy - yMin + 1];
}
- // 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));
+ 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;
}
- *p++ |= mask;
- xx = (xx & ~7) + 8;
+ interCount += allInter[interIdx].count;
+ ++interIdx;
}
- for (; xx + 7 < xx1; xx += 8) {
- *p++ |= 0xff;
+ if (xx0 < 0) {
+ xx0 = 0;
}
- if (xx < xx1) {
- *p |= (Guchar)(0xff00 >> (xx1 & 7));
+ ++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;
}
- }
- if (xx0 < xxMin) {
- xxMin = xx0;
- }
- if (xx1 > xxMax) {
- xxMax = xx1;
}
}
}
@@ -375,50 +447,64 @@ void SplashXPathScanner::renderAALine(SplashBitmap *aaBuf,
void SplashXPathScanner::clipAALine(SplashBitmap *aaBuf,
int *x0, int *x1, int y) {
- int xx0, xx1, xx, yy;
+ int xx0, xx1, xx, yy, interEnd;
Guchar mask;
SplashColorPtr p;
for (yy = 0; yy < splashAASize; ++yy) {
xx = *x0 * splashAASize;
- computeIntersections(splashAASize * y + yy);
- while (interIdx < interLen && xx < (*x1 + 1) * splashAASize) {
- xx0 = inter[interIdx].x0;
- xx1 = inter[interIdx].x1;
- interCount += inter[interIdx].count;
- ++interIdx;
- while (interIdx < interLen &&
- (inter[interIdx].x0 <= xx1 ||
- (eo ? (interCount & 1) : (interCount != 0)))) {
- if (inter[interIdx].x1 > xx1) {
- xx1 = inter[interIdx].x1;
+ if (yMin <= yMax) {
+ if (splashAASize * y + yy < yMin) {
+ interIdx = interEnd = inter[0];
+ } else if (splashAASize * y + yy > yMax) {
+ interIdx = interEnd = inter[yMax - yMin + 1];
+ } 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];
}
- interCount += inter[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);
+ 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;
}
- *p++ &= mask;
- xx = (xx & ~7) + 8;
+ interCount += allInter[interIdx].count;
+ ++interIdx;
}
- for (; xx + 7 <= xx0; xx += 8) {
- *p++ = 0x00;
+ if (xx0 > aaBuf->getWidth()) {
+ xx0 = aaBuf->getWidth();
}
+ // set [xx, xx0) to 0
if (xx < xx0) {
- *p &= 0xff >> (xx0 & 7);
+ 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;
}
- }
- if (xx1 >= xx) {
- xx = xx1 + 1;
}
}
xx0 = (*x1 + 1) * splashAASize;
@@ -434,7 +520,7 @@ void SplashXPathScanner::clipAALine(SplashBitmap *aaBuf,
*p++ &= mask;
xx = (xx & ~7) + 8;
}
- for (; xx + 7 <= xx0; xx += 8) {
+ for (; xx + 7 < xx0; xx += 8) {
*p++ = 0x00;
}
if (xx < xx0) {
diff --git a/splash/SplashXPathScanner.h b/splash/SplashXPathScanner.h
index 1cc4f3c..719fae4 100644
--- a/splash/SplashXPathScanner.h
+++ b/splash/SplashXPathScanner.h
@@ -25,7 +25,8 @@ class SplashXPathScanner {
public:
// Create a new SplashXPathScanner object. <xPathA> must be sorted.
- SplashXPathScanner(SplashXPath *xPathA, GBool eoA);
+ SplashXPathScanner(SplashXPath *xPathA, GBool eoA,
+ int clipYMin, int clipYMax);
~SplashXPathScanner();
@@ -36,6 +37,10 @@ public:
// 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);
@@ -64,22 +69,25 @@ public:
private:
- void computeIntersections(int y);
+ void computeIntersections();
+ void addIntersection(double segYMin, double segYMax,
+ Guint segFlags,
+ int y, int x0, int x1);
SplashXPath *xPath;
GBool eo;
int xMin, yMin, xMax, yMax;
+ GBool partialClip;
- int interY; // current y value
+ 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 xPathIdx; // current index into <xPath> - used by
- // computeIntersections
- SplashIntersect *inter; // intersections array for <interY>
- int interLen; // number of intersections in <inter>
- int interSize; // size of the <inter> array
};
#endif
More information about the poppler
mailing list