summaryrefslogtreecommitdiff
path: root/splash
diff options
context:
space:
mode:
authorAlbert Astals Cid <aacid@kde.org>2012-01-07 17:14:05 +0100
committerAlbert Astals Cid <aacid@kde.org>2012-01-07 17:14:05 +0100
commit34ae382915d9d9b2b3c015fee3c24907a6b52b8b (patch)
tree90e98ce35e2e8b2c610a96eab4d8e41064ab2929 /splash
parent51ca2b7c7dec5430d29860fd887ad5c5d9b3f574 (diff)
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
Diffstat (limited to 'splash')
-rw-r--r--splash/Splash.cc1658
-rw-r--r--splash/Splash.h42
-rw-r--r--splash/SplashClip.cc57
-rw-r--r--splash/SplashState.cc49
-rw-r--r--splash/SplashState.h12
-rw-r--r--splash/SplashXPathScanner.cc474
-rw-r--r--splash/SplashXPathScanner.h24
7 files changed, 1616 insertions, 700 deletions
diff --git a/splash/Splash.cc b/splash/Splash.cc
index 25566524..5091edb7 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 85f92ed9..e538808f 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 5add1523..41b73c84 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 15b6a72a..7b632b84 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 63dadc62..214bffa1 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 33aa3923..c9fe5e5d 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 1cc4f3cd..719fae48 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