summaryrefslogtreecommitdiff
path: root/splash
diff options
context:
space:
mode:
Diffstat (limited to 'splash')
-rw-r--r--splash/Splash.cc4461
-rw-r--r--splash/Splash.h104
-rw-r--r--splash/SplashBitmap.cc53
-rw-r--r--splash/SplashBitmap.h6
-rw-r--r--splash/SplashClip.cc57
-rw-r--r--splash/SplashClip.h6
-rw-r--r--splash/SplashFTFont.cc130
-rw-r--r--splash/SplashFTFont.h3
-rw-r--r--splash/SplashFTFontEngine.cc50
-rw-r--r--splash/SplashFTFontEngine.h16
-rw-r--r--splash/SplashFTFontFile.cc25
-rw-r--r--splash/SplashFTFontFile.h13
-rw-r--r--splash/SplashFontEngine.cc19
-rw-r--r--splash/SplashFontEngine.h12
-rw-r--r--splash/SplashMath.h136
-rw-r--r--splash/SplashPath.cc5
-rw-r--r--splash/SplashPath.h6
-rw-r--r--splash/SplashPattern.cc14
-rw-r--r--splash/SplashPattern.h7
-rw-r--r--splash/SplashScreen.cc101
-rw-r--r--splash/SplashScreen.h14
-rw-r--r--splash/SplashState.cc49
-rw-r--r--splash/SplashState.h12
-rw-r--r--splash/SplashT1Font.cc41
-rw-r--r--splash/SplashT1FontEngine.cc6
-rw-r--r--splash/SplashT1FontEngine.h4
-rw-r--r--splash/SplashT1FontFile.cc10
-rw-r--r--splash/SplashT1FontFile.h6
-rw-r--r--splash/SplashXPath.cc114
-rw-r--r--splash/SplashXPath.h14
-rw-r--r--splash/SplashXPathScanner.cc474
-rw-r--r--splash/SplashXPathScanner.h24
32 files changed, 4073 insertions, 1919 deletions
diff --git a/splash/Splash.cc b/splash/Splash.cc
index 9deec105..fcab28c3 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,9 +63,55 @@ 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; }
+// The PDF spec says that all pixels whose *centers* lie within the
+// image target region get painted, so we want to round n+0.5 down to
+// n. But this causes problems, e.g., with PDF files that fill a
+// rectangle with black and then draw an image to the exact same
+// rectangle, so we instead use the fill scan conversion rule.
+// However, the correct rule works better for glyphs, so we also
+// provide that option in fillImageMask.
+#if 0
+static inline int imgCoordMungeLower(SplashCoord x) {
+ return splashCeil(x + 0.5) - 1;
+}
+static inline int imgCoordMungeUpper(SplashCoord x) {
+ return splashCeil(x + 0.5) - 1;
+}
+#else
+static inline int imgCoordMungeLower(SplashCoord x) {
+ return splashFloor(x);
+}
+static inline int imgCoordMungeUpper(SplashCoord x) {
+ return splashFloor(x) + 1;
+}
+static inline int imgCoordMungeLowerC(SplashCoord x, GBool glyphMode) {
+ return glyphMode ? (splashCeil(x + 0.5) - 1) : splashFloor(x);
+}
+static inline int imgCoordMungeUpperC(SplashCoord x, GBool glyphMode) {
+ return glyphMode ? (splashCeil(x + 0.5) - 1) : (splashFloor(x) + 1);
+}
+#endif
+
+// Used by drawImage and fillImageMask to divide the target
+// quadrilateral into sections.
+struct ImageSection {
+ int y0, y1; // actual y range
+ int ia0, ia1; // vertex indices for edge A
+ int ib0, ib1; // vertex indices for edge A
+ SplashCoord xa0, ya0, xa1, ya1; // edge A
+ SplashCoord dxdya; // slope of edge A
+ SplashCoord xb0, yb0, xb1, yb1; // edge B
+ SplashCoord dxdyb; // slope of edge B
+};
+
//------------------------------------------------------------------------
// SplashPipe
//------------------------------------------------------------------------
@@ -78,9 +126,8 @@ struct SplashPipe {
SplashPattern *pattern;
// source alpha and color
- SplashCoord aInput;
+ Guchar aInput;
GBool usesShape;
- Guchar aSrc;
SplashColorPtr cSrc;
SplashColor cSrcVal;
@@ -96,18 +143,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 +238,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 +257,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 +278,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 +350,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 +362,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 +444,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 +546,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 +707,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 +732,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 +1186,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 +1247,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 +1258,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 +1330,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 +1362,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 +1387,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 +1395,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 +1482,10 @@ SplashCoord Splash::getLineDashPhase() {
return state->lineDashPhase;
}
+GBool Splash::getStrokeAdjust() {
+ return state->strokeAdjust;
+}
+
SplashClip *Splash::getClip() {
return state->clip;
}
@@ -1094,6 +1601,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 +1763,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 +1779,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 +1825,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 +1835,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 +1919,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;
}
@@ -1397,7 +1935,11 @@ SplashPath *Splash::flattenPath(SplashPath *path, SplashCoord *matrix,
int i;
fPath = new SplashPath();
+#if USE_FIXEDPOINT
+ flatness2 = flatness;
+#else
flatness2 = flatness * flatness;
+#endif
i = 0;
while (i < path->length) {
flag = path->flags[i];
@@ -1462,13 +2004,21 @@ void Splash::flattenCurve(SplashCoord x0, SplashCoord y0,
// line)
transform(matrix, (xl0 + xr3) * 0.5, (yl0 + yr3) * 0.5, &mx, &my);
transform(matrix, xx1, yy1, &tx, &ty);
+#if USE_FIXEDPOINT
+ d1 = splashDist(tx, ty, mx, my);
+#else
dx = tx - mx;
dy = ty - my;
d1 = dx*dx + dy*dy;
+#endif
transform(matrix, xx2, yy2, &tx, &ty);
+#if USE_FIXEDPOINT
+ d2 = splashDist(tx, ty, mx, my);
+#else
dx = tx - mx;
dy = ty - my;
d2 = dx*dx + dy*dy;
+#endif
// if the curve is flat enough, or no more subdivisions are
// allowed, add the straight line segment
@@ -1478,18 +2028,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;
@@ -1516,15 +2066,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();
@@ -1634,15 +2190,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);
@@ -1651,19 +2241,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) {
@@ -1698,6 +2284,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;
@@ -1711,7 +2364,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);
@@ -1719,18 +2373,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) {
@@ -1808,7 +2457,8 @@ void Splash::fillGlyph(SplashCoord x, SplashCoord y,
void Splash::fillGlyph2(int x0, int y0, SplashGlyphBitmap *glyph, GBool noClip) {
SplashPipe pipe;
- int alpha0, alpha;
+ int alpha0;
+ Guchar alpha;
Guchar *p;
int x1, y1, xx, xx1, yy;
@@ -1844,14 +2494,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 {
@@ -1864,14 +2514,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 {
@@ -1886,15 +2536,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 {
@@ -1910,7 +2560,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) {
@@ -1918,7 +2568,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 {
@@ -1939,22 +2589,11 @@ void Splash::fillGlyph2(int x0, int y0, SplashGlyphBitmap *glyph, GBool noClip)
SplashError Splash::fillImageMask(SplashImageMaskSource src, void *srcData,
int w, int h, SplashCoord *mat,
GBool glyphMode) {
- SplashPipe pipe;
- GBool rot;
- SplashCoord xScale, yScale, xShear, yShear, yShear1;
- int tx, tx2, ty, ty2, scaledWidth, scaledHeight, xSign, ySign;
- int ulx, uly, llx, lly, urx, ury, lrx, lry;
- int ulx1, uly1, llx1, lly1, urx1, ury1, lrx1, lry1;
- int xMin, xMax, yMin, yMax;
- SplashClipResult clipRes, clipRes2;
- int yp, yq, yt, yStep, lastYStep;
- int xp, xq, xt, xStep, xSrc;
- int k1, spanXMin, spanXMax, spanY;
- SplashColorPtr pixBuf, p;
- int pixAcc;
- int x, y, x1, x2, y2;
- SplashCoord y1;
- int n, m, i, j;
+ SplashBitmap *scaledMask;
+ SplashClipResult clipRes;
+ GBool minorAxisZero;
+ int x0, y0, x1, y1, scaledWidth, scaledHeight;
+ int yp;
if (debugMode) {
printf("fillImageMask: w=%d h=%d mat=[%.2f %.2f %.2f %.2f %.2f %.2f]\n",
@@ -1965,289 +2604,738 @@ SplashError Splash::fillImageMask(SplashImageMaskSource src, void *srcData,
if (w == 0 && h == 0) return splashErrZeroImage;
// check for singular matrix
- if (splashAbs(mat[0] * mat[3] - mat[1] * mat[2]) < 0.000001) {
+ if (!splashCheckDet(mat[0], mat[1], mat[2], mat[3], 0.000001)) {
return splashErrSingularMatrix;
}
- // compute scale, shear, rotation, translation parameters
- rot = splashAbs(mat[1]) > splashAbs(mat[0]);
- if (rot) {
- xScale = -mat[1];
- yScale = mat[2] - (mat[0] * mat[3]) / mat[1];
- xShear = -mat[3] / yScale;
- yShear = -mat[0] / mat[1];
- } else {
- xScale = mat[0];
- yScale = mat[3] - (mat[1] * mat[2]) / mat[0];
- xShear = mat[2] / yScale;
- yShear = mat[1] / mat[0];
- }
- // Note 1: The PDF spec says that all pixels whose *centers* lie
- // within the region get painted -- but that doesn't seem to match
- // up with what Acrobat actually does: it ends up leaving gaps
- // between image stripes. So we use the same rule here as for
- // fills: any pixel that overlaps the region gets painted.
- // Note 2: The "glyphMode" flag is a kludge: it switches back to
- // "correct" behavior (matching the spec), for use in rendering Type
- // 3 fonts.
- // Note 3: The +/-0.01 in these computations is to avoid floating
- // point precision problems which can lead to gaps between image
- // stripes (it can cause image stripes to overlap, but that's a much
- // less visible problem).
- if (glyphMode) {
- if (xScale >= 0) {
- tx = splashRound(mat[4]);
- tx2 = splashRound(mat[4] + xScale) - 1;
- } else {
- tx = splashRound(mat[4]) - 1;
- tx2 = splashRound(mat[4] + xScale);
+ minorAxisZero = mat[1] == 0 && mat[2] == 0;
+
+ // scaling only
+ if (mat[0] > 0 && minorAxisZero && mat[3] > 0) {
+ x0 = imgCoordMungeLowerC(mat[4], glyphMode);
+ y0 = imgCoordMungeLowerC(mat[5], glyphMode);
+ x1 = imgCoordMungeUpperC(mat[0] + mat[4], glyphMode);
+ y1 = imgCoordMungeUpperC(mat[3] + mat[5], glyphMode);
+ // make sure narrow images cover at least one pixel
+ if (x0 == x1) {
+ ++x1;
}
- } else {
- if (xScale >= 0) {
- tx = splashFloor(mat[4] - 0.01);
- tx2 = splashFloor(mat[4] + xScale + 0.01);
- } else {
- tx = splashFloor(mat[4] + 0.01);
- tx2 = splashFloor(mat[4] + xScale - 0.01);
+ if (y0 == y1) {
+ ++y1;
}
- }
- scaledWidth = abs(tx2 - tx) + 1;
- if (glyphMode) {
- if (yScale >= 0) {
- ty = splashRound(mat[5]);
- ty2 = splashRound(mat[5] + yScale) - 1;
- } else {
- ty = splashRound(mat[5]) - 1;
- ty2 = splashRound(mat[5] + yScale);
+ clipRes = state->clip->testRect(x0, y0, x1 - 1, y1 - 1);
+ opClipRes = clipRes;
+ if (clipRes != splashClipAllOutside) {
+ scaledWidth = x1 - x0;
+ scaledHeight = y1 - y0;
+ yp = h / scaledHeight;
+ if (yp < 0 || yp > INT_MAX - 1) {
+ return splashErrBadArg;
+ }
+ scaledMask = scaleMask(src, srcData, w, h, scaledWidth, scaledHeight);
+ blitMask(scaledMask, x0, y0, clipRes);
+ delete scaledMask;
}
- } else {
- if (yScale >= 0) {
- ty = splashFloor(mat[5] - 0.01);
- ty2 = splashFloor(mat[5] + yScale + 0.01);
- } else {
- ty = splashFloor(mat[5] + 0.01);
- ty2 = splashFloor(mat[5] + yScale - 0.01);
+
+ // scaling plus vertical flip
+ } else if (mat[0] > 0 && minorAxisZero && mat[3] < 0) {
+ x0 = imgCoordMungeLowerC(mat[4], glyphMode);
+ y0 = imgCoordMungeLowerC(mat[3] + mat[5], glyphMode);
+ x1 = imgCoordMungeUpperC(mat[0] + mat[4], glyphMode);
+ y1 = imgCoordMungeUpperC(mat[5], glyphMode);
+ // make sure narrow images cover at least one pixel
+ if (x0 == x1) {
+ ++x1;
+ }
+ if (y0 == y1) {
+ ++y1;
+ }
+ clipRes = state->clip->testRect(x0, y0, x1 - 1, y1 - 1);
+ opClipRes = clipRes;
+ if (clipRes != splashClipAllOutside) {
+ scaledWidth = x1 - x0;
+ scaledHeight = y1 - y0;
+ yp = h / scaledHeight;
+ if (yp < 0 || yp > INT_MAX - 1) {
+ return splashErrBadArg;
+ }
+ scaledMask = scaleMask(src, srcData, w, h, scaledWidth, scaledHeight);
+ vertFlipImage(scaledMask, scaledWidth, scaledHeight, 1);
+ blitMask(scaledMask, x0, y0, clipRes);
+ delete scaledMask;
}
+
+ // all other cases
+ } else {
+ arbitraryTransformMask(src, srcData, w, h, mat, glyphMode);
}
- scaledHeight = abs(ty2 - ty) + 1;
- xSign = (xScale < 0) ? -1 : 1;
- ySign = (yScale < 0) ? -1 : 1;
- yShear1 = (SplashCoord)xSign * yShear;
+
+ return splashOk;
+}
+
+void Splash::arbitraryTransformMask(SplashImageMaskSource src, void *srcData,
+ int srcWidth, int srcHeight,
+ SplashCoord *mat, GBool glyphMode) {
+ SplashBitmap *scaledMask;
+ SplashClipResult clipRes, clipRes2;
+ SplashPipe pipe;
+ int scaledWidth, scaledHeight, t0, t1;
+ SplashCoord r00, r01, r10, r11, det, ir00, ir01, ir10, ir11;
+ SplashCoord vx[4], vy[4];
+ int xMin, yMin, xMax, yMax;
+ ImageSection section[3];
+ int nSections;
+ int y, xa, xb, x, i, xx, yy;
+
+ // compute the four vertices of the target quadrilateral
+ vx[0] = mat[4]; vy[0] = mat[5];
+ vx[1] = mat[2] + mat[4]; vy[1] = mat[3] + mat[5];
+ vx[2] = mat[0] + mat[2] + mat[4]; vy[2] = mat[1] + mat[3] + mat[5];
+ vx[3] = mat[0] + mat[4]; vy[3] = mat[1] + mat[5];
// clipping
- ulx1 = 0;
- uly1 = 0;
- urx1 = xSign * (scaledWidth - 1);
- ury1 = (int)(yShear * urx1);
- llx1 = splashRound(xShear * ySign * (scaledHeight - 1));
- lly1 = ySign * (scaledHeight - 1) + (int)(yShear * llx1);
- lrx1 = xSign * (scaledWidth - 1) +
- splashRound(xShear * ySign * (scaledHeight - 1));
- lry1 = ySign * (scaledHeight - 1) + (int)(yShear * lrx1);
- if (rot) {
- ulx = tx + uly1; uly = ty - ulx1;
- urx = tx + ury1; ury = ty - urx1;
- llx = tx + lly1; lly = ty - llx1;
- lrx = tx + lry1; lry = ty - lrx1;
- } else {
- ulx = tx + ulx1; uly = ty + uly1;
- urx = tx + urx1; ury = ty + ury1;
- llx = tx + llx1; lly = ty + lly1;
- lrx = tx + lrx1; lry = ty + lry1;
- }
- xMin = (ulx < urx) ? (ulx < llx) ? (ulx < lrx) ? ulx : lrx
- : (llx < lrx) ? llx : lrx
- : (urx < llx) ? (urx < lrx) ? urx : lrx
- : (llx < lrx) ? llx : lrx;
- xMax = (ulx > urx) ? (ulx > llx) ? (ulx > lrx) ? ulx : lrx
- : (llx > lrx) ? llx : lrx
- : (urx > llx) ? (urx > lrx) ? urx : lrx
- : (llx > lrx) ? llx : lrx;
- yMin = (uly < ury) ? (uly < lly) ? (uly < lry) ? uly : lry
- : (lly < lry) ? lly : lry
- : (ury < lly) ? (ury < lry) ? ury : lry
- : (lly < lry) ? lly : lry;
- yMax = (uly > ury) ? (uly > lly) ? (uly > lry) ? uly : lry
- : (lly > lry) ? lly : lry
- : (ury > lly) ? (ury > lry) ? ury : lry
- : (lly > lry) ? lly : lry;
- clipRes = state->clip->testRect(xMin, yMin, xMax, yMax);
+ xMin = imgCoordMungeLowerC(vx[0], glyphMode);
+ xMax = imgCoordMungeUpperC(vx[0], glyphMode);
+ yMin = imgCoordMungeLowerC(vy[0], glyphMode);
+ yMax = imgCoordMungeUpperC(vy[0], glyphMode);
+ for (i = 1; i < 4; ++i) {
+ t0 = imgCoordMungeLowerC(vx[i], glyphMode);
+ if (t0 < xMin) {
+ xMin = t0;
+ }
+ t0 = imgCoordMungeUpperC(vx[i], glyphMode);
+ if (t0 > xMax) {
+ xMax = t0;
+ }
+ t1 = imgCoordMungeLowerC(vy[i], glyphMode);
+ if (t1 < yMin) {
+ yMin = t1;
+ }
+ t1 = imgCoordMungeUpperC(vy[i], glyphMode);
+ if (t1 > yMax) {
+ yMax = t1;
+ }
+ }
+ clipRes = state->clip->testRect(xMin, yMin, xMax - 1, yMax - 1);
opClipRes = clipRes;
+ if (clipRes == splashClipAllOutside) {
+ return;
+ }
- // compute Bresenham parameters for x and y scaling
- yp = h / scaledHeight;
- yq = h % scaledHeight;
- xp = w / scaledWidth;
- xq = w % scaledWidth;
+ // compute the scale factors
+ if (mat[0] >= 0) {
+ t0 = imgCoordMungeUpperC(mat[0] + mat[4], glyphMode) -
+ imgCoordMungeLowerC(mat[4], glyphMode);
+ } else {
+ t0 = imgCoordMungeUpperC(mat[4], glyphMode) -
+ imgCoordMungeLowerC(mat[0] + mat[4], glyphMode);
+ }
+ if (mat[1] >= 0) {
+ t1 = imgCoordMungeUpperC(mat[1] + mat[5], glyphMode) -
+ imgCoordMungeLowerC(mat[5], glyphMode);
+ } else {
+ t1 = imgCoordMungeUpperC(mat[5], glyphMode) -
+ imgCoordMungeLowerC(mat[1] + mat[5], glyphMode);
+ }
+ scaledWidth = t0 > t1 ? t0 : t1;
+ if (mat[2] >= 0) {
+ t0 = imgCoordMungeUpperC(mat[2] + mat[4], glyphMode) -
+ imgCoordMungeLowerC(mat[4], glyphMode);
+ } else {
+ t0 = imgCoordMungeUpperC(mat[4], glyphMode) -
+ imgCoordMungeLowerC(mat[2] + mat[4], glyphMode);
+ }
+ if (mat[3] >= 0) {
+ t1 = imgCoordMungeUpperC(mat[3] + mat[5], glyphMode) -
+ imgCoordMungeLowerC(mat[5], glyphMode);
+ } else {
+ t1 = imgCoordMungeUpperC(mat[5], glyphMode) -
+ imgCoordMungeLowerC(mat[3] + mat[5], glyphMode);
+ }
+ scaledHeight = t0 > t1 ? t0 : t1;
+ if (scaledWidth == 0) {
+ scaledWidth = 1;
+ }
+ if (scaledHeight == 0) {
+ scaledHeight = 1;
+ }
- // allocate pixel buffer
- if (yp < 0 || yp > INT_MAX - 1) {
- return splashErrBadArg;
+ // compute the inverse transform (after scaling) matrix
+ r00 = mat[0] / scaledWidth;
+ r01 = mat[1] / scaledWidth;
+ r10 = mat[2] / scaledHeight;
+ r11 = mat[3] / scaledHeight;
+ det = r00 * r11 - r01 * r10;
+ if (splashAbs(det) < 1e-6) {
+ // this should be caught by the singular matrix check in fillImageMask
+ return;
+ }
+ ir00 = r11 / det;
+ ir01 = -r01 / det;
+ ir10 = -r10 / det;
+ ir11 = r00 / det;
+
+ // scale the input image
+ scaledMask = scaleMask(src, srcData, srcWidth, srcHeight,
+ scaledWidth, scaledHeight);
+
+ // construct the three sections
+ i = (vy[2] <= vy[3]) ? 2 : 3;
+ if (vy[1] <= vy[i]) {
+ i = 1;
+ }
+ if (vy[0] < vy[i] || (i != 3 && vy[0] == vy[i])) {
+ i = 0;
+ }
+ if (vy[i] == vy[(i+1) & 3]) {
+ section[0].y0 = imgCoordMungeLowerC(vy[i], glyphMode);
+ section[0].y1 = imgCoordMungeUpperC(vy[(i+2) & 3], glyphMode) - 1;
+ if (vx[i] < vx[(i+1) & 3]) {
+ section[0].ia0 = i;
+ section[0].ia1 = (i+3) & 3;
+ section[0].ib0 = (i+1) & 3;
+ section[0].ib1 = (i+2) & 3;
+ } else {
+ section[0].ia0 = (i+1) & 3;
+ section[0].ia1 = (i+2) & 3;
+ section[0].ib0 = i;
+ section[0].ib1 = (i+3) & 3;
+ }
+ nSections = 1;
+ } else {
+ section[0].y0 = imgCoordMungeLowerC(vy[i], glyphMode);
+ section[2].y1 = imgCoordMungeUpperC(vy[(i+2) & 3], glyphMode) - 1;
+ section[0].ia0 = section[0].ib0 = i;
+ section[2].ia1 = section[2].ib1 = (i+2) & 3;
+ if (vx[(i+1) & 3] < vx[(i+3) & 3]) {
+ section[0].ia1 = section[2].ia0 = (i+1) & 3;
+ section[0].ib1 = section[2].ib0 = (i+3) & 3;
+ } else {
+ section[0].ia1 = section[2].ia0 = (i+3) & 3;
+ section[0].ib1 = section[2].ib0 = (i+1) & 3;
+ }
+ if (vy[(i+1) & 3] < vy[(i+3) & 3]) {
+ section[1].y0 = imgCoordMungeLowerC(vy[(i+1) & 3], glyphMode);
+ section[2].y0 = imgCoordMungeUpperC(vy[(i+3) & 3], glyphMode);
+ if (vx[(i+1) & 3] < vx[(i+3) & 3]) {
+ section[1].ia0 = (i+1) & 3;
+ section[1].ia1 = (i+2) & 3;
+ section[1].ib0 = i;
+ section[1].ib1 = (i+3) & 3;
+ } else {
+ section[1].ia0 = i;
+ section[1].ia1 = (i+3) & 3;
+ section[1].ib0 = (i+1) & 3;
+ section[1].ib1 = (i+2) & 3;
+ }
+ } else {
+ section[1].y0 = imgCoordMungeLowerC(vy[(i+3) & 3], glyphMode);
+ section[2].y0 = imgCoordMungeUpperC(vy[(i+1) & 3], glyphMode);
+ if (vx[(i+1) & 3] < vx[(i+3) & 3]) {
+ section[1].ia0 = i;
+ section[1].ia1 = (i+1) & 3;
+ section[1].ib0 = (i+3) & 3;
+ section[1].ib1 = (i+2) & 3;
+ } else {
+ section[1].ia0 = (i+3) & 3;
+ section[1].ia1 = (i+2) & 3;
+ section[1].ib0 = i;
+ section[1].ib1 = (i+1) & 3;
+ }
+ }
+ section[0].y1 = section[1].y0 - 1;
+ section[1].y1 = section[2].y0 - 1;
+ nSections = 3;
+ }
+ for (i = 0; i < nSections; ++i) {
+ section[i].xa0 = vx[section[i].ia0];
+ section[i].ya0 = vy[section[i].ia0];
+ section[i].xa1 = vx[section[i].ia1];
+ section[i].ya1 = vy[section[i].ia1];
+ section[i].xb0 = vx[section[i].ib0];
+ section[i].yb0 = vy[section[i].ib0];
+ section[i].xb1 = vx[section[i].ib1];
+ section[i].yb1 = vy[section[i].ib1];
+ section[i].dxdya = (section[i].xa1 - section[i].xa0) /
+ (section[i].ya1 - section[i].ya0);
+ section[i].dxdyb = (section[i].xb1 - section[i].xb0) /
+ (section[i].yb1 - section[i].yb0);
}
- 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();
}
+ // make sure narrow images cover at least one pixel
+ if (nSections == 1) {
+ if (section[0].y0 == section[0].y1) {
+ ++section[0].y1;
+ clipRes = opClipRes = splashClipPartial;
+ }
+ } else {
+ if (section[0].y0 == section[2].y1) {
+ ++section[1].y1;
+ clipRes = opClipRes = splashClipPartial;
+ }
+ }
+
+ // scan all pixels inside the target region
+ for (i = 0; i < nSections; ++i) {
+ for (y = section[i].y0; y <= section[i].y1; ++y) {
+ xa = imgCoordMungeLowerC(section[i].xa0 +
+ ((SplashCoord)y + 0.5 - section[i].ya0) *
+ section[i].dxdya,
+ glyphMode);
+ xb = imgCoordMungeUpperC(section[i].xb0 +
+ ((SplashCoord)y + 0.5 - section[i].yb0) *
+ section[i].dxdyb,
+ glyphMode);
+ // make sure narrow images cover at least one pixel
+ if (xa == xb) {
+ ++xb;
+ }
+ if (clipRes != splashClipAllInside) {
+ clipRes2 = state->clip->testSpan(xa, xb - 1, y);
+ } else {
+ clipRes2 = clipRes;
+ }
+ for (x = xa; x < xb; ++x) {
+ // map (x+0.5, y+0.5) back to the scaled image
+ xx = splashFloor(((SplashCoord)x + 0.5 - mat[4]) * ir00 +
+ ((SplashCoord)y + 0.5 - mat[5]) * ir10);
+ yy = splashFloor(((SplashCoord)x + 0.5 - mat[4]) * ir01 +
+ ((SplashCoord)y + 0.5 - mat[5]) * ir11);
+ // xx should always be within bounds, but floating point
+ // inaccuracy can cause problems
+ if (xx < 0) {
+ xx = 0;
+ } else if (xx >= scaledWidth) {
+ xx = scaledWidth - 1;
+ }
+ if (yy < 0) {
+ yy = 0;
+ } else if (yy >= scaledHeight) {
+ yy = scaledHeight - 1;
+ }
+ pipe.shape = scaledMask->data[yy * scaledWidth + xx];
+ if (vectorAntialias && clipRes2 != splashClipAllInside) {
+ drawAAPixel(&pipe, x, y);
+ } else {
+ drawPixel(&pipe, x, y, clipRes2 == splashClipAllInside);
+ }
+ }
+ }
+ }
+
+ delete scaledMask;
+}
+
+// Scale an image mask into a SplashBitmap.
+SplashBitmap *Splash::scaleMask(SplashImageMaskSource src, void *srcData,
+ int srcWidth, int srcHeight,
+ int scaledWidth, int scaledHeight) {
+ SplashBitmap *dest;
+
+ dest = new SplashBitmap(scaledWidth, scaledHeight, 1, splashModeMono8,
+ gFalse);
+ if (scaledHeight < srcHeight) {
+ if (scaledWidth < srcWidth) {
+ scaleMaskYdXd(src, srcData, srcWidth, srcHeight,
+ scaledWidth, scaledHeight, dest);
+ } else {
+ scaleMaskYdXu(src, srcData, srcWidth, srcHeight,
+ scaledWidth, scaledHeight, dest);
+ }
+ } else {
+ if (scaledWidth < srcWidth) {
+ scaleMaskYuXd(src, srcData, srcWidth, srcHeight,
+ scaledWidth, scaledHeight, dest);
+ } else {
+ scaleMaskYuXu(src, srcData, srcWidth, srcHeight,
+ scaledWidth, scaledHeight, dest);
+ }
+ }
+ return dest;
+}
+
+void Splash::scaleMaskYdXd(SplashImageMaskSource src, void *srcData,
+ int srcWidth, int srcHeight,
+ int scaledWidth, int scaledHeight,
+ SplashBitmap *dest) {
+ Guchar *lineBuf;
+ Guint *pixBuf;
+ Guint pix;
+ Guchar *destPtr;
+ int yp, yq, xp, xq, yt, y, yStep, xt, x, xStep, xx, d, d0, d1;
+ int i, j;
+
+ // Bresenham parameters for y scale
+ yp = srcHeight / scaledHeight;
+ yq = srcHeight % scaledHeight;
+
+ // Bresenham parameters for x scale
+ xp = srcWidth / scaledWidth;
+ xq = srcWidth % scaledWidth;
+
+ // allocate buffers
+ lineBuf = (Guchar *)gmalloc(srcWidth);
+ pixBuf = (Guint *)gmallocn(srcWidth, sizeof(int));
+
// init y scale Bresenham
yt = 0;
- lastYStep = 1;
+ destPtr = dest->data;
for (y = 0; y < scaledHeight; ++y) {
// y scale Bresenham
- yStep = yp;
- yt += yq;
- if (yt >= scaledHeight) {
+ if ((yt += yq) >= scaledHeight) {
yt -= scaledHeight;
- ++yStep;
+ yStep = yp + 1;
+ } else {
+ yStep = yp;
}
- // read row(s) from image
- n = (yp > 0) ? yStep : lastYStep;
- if (n > 0) {
- p = pixBuf;
- for (i = 0; i < n; ++i) {
- (*src)(srcData, p);
- p += w;
+ // read rows from image
+ memset(pixBuf, 0, srcWidth * sizeof(int));
+ for (i = 0; i < yStep; ++i) {
+ (*src)(srcData, lineBuf);
+ for (j = 0; j < srcWidth; ++j) {
+ pixBuf[j] += lineBuf[j];
}
}
- lastYStep = yStep;
- // loop-invariant constants
- k1 = splashRound(xShear * ySign * y);
+ // init x scale Bresenham
+ xt = 0;
+ d0 = (255 << 23) / (yStep * xp);
+ d1 = (255 << 23) / (yStep * (xp + 1));
- // clipping test
- if (clipRes != splashClipAllInside &&
- !rot &&
- (int)(yShear * k1) ==
- (int)(yShear * (xSign * (scaledWidth - 1) + k1))) {
- if (xSign > 0) {
- spanXMin = tx + k1;
- spanXMax = spanXMin + (scaledWidth - 1);
+ xx = 0;
+ for (x = 0; x < scaledWidth; ++x) {
+
+ // x scale Bresenham
+ if ((xt += xq) >= scaledWidth) {
+ xt -= scaledWidth;
+ xStep = xp + 1;
+ d = d1;
} else {
- spanXMax = tx + k1;
- spanXMin = spanXMax - (scaledWidth - 1);
+ xStep = xp;
+ d = d0;
}
- spanY = ty + ySign * y + (int)(yShear * k1);
- clipRes2 = state->clip->testSpan(spanXMin, spanXMax, spanY);
- if (clipRes2 == splashClipAllOutside) {
- continue;
+
+ // compute the final pixel
+ pix = 0;
+ for (i = 0; i < xStep; ++i) {
+ pix += pixBuf[xx++];
}
+ // (255 * pix) / xStep * yStep
+ pix = (pix * d) >> 23;
+
+ // store the pixel
+ *destPtr++ = (Guchar)pix;
+ }
+ }
+
+ gfree(pixBuf);
+ gfree(lineBuf);
+}
+
+void Splash::scaleMaskYdXu(SplashImageMaskSource src, void *srcData,
+ int srcWidth, int srcHeight,
+ int scaledWidth, int scaledHeight,
+ SplashBitmap *dest) {
+ Guchar *lineBuf;
+ Guint *pixBuf;
+ Guint pix;
+ Guchar *destPtr;
+ int yp, yq, xp, xq, yt, y, yStep, xt, x, xStep, d;
+ int i, j;
+
+ // Bresenham parameters for y scale
+ yp = srcHeight / scaledHeight;
+ yq = srcHeight % scaledHeight;
+
+ // Bresenham parameters for x scale
+ xp = scaledWidth / srcWidth;
+ xq = scaledWidth % srcWidth;
+
+ // allocate buffers
+ lineBuf = (Guchar *)gmalloc(srcWidth);
+ pixBuf = (Guint *)gmallocn(srcWidth, sizeof(int));
+
+ // init y scale Bresenham
+ yt = 0;
+
+ destPtr = dest->data;
+ for (y = 0; y < scaledHeight; ++y) {
+
+ // y scale Bresenham
+ if ((yt += yq) >= scaledHeight) {
+ yt -= scaledHeight;
+ yStep = yp + 1;
} else {
- clipRes2 = clipRes;
+ yStep = yp;
+ }
+
+ // read rows from image
+ memset(pixBuf, 0, srcWidth * sizeof(int));
+ for (i = 0; i < yStep; ++i) {
+ (*src)(srcData, lineBuf);
+ for (j = 0; j < srcWidth; ++j) {
+ pixBuf[j] += lineBuf[j];
+ }
}
// init x scale Bresenham
xt = 0;
- xSrc = 0;
+ d = (255 << 23) / yStep;
+
+ for (x = 0; x < srcWidth; ++x) {
+
+ // x scale Bresenham
+ if ((xt += xq) >= srcWidth) {
+ xt -= srcWidth;
+ xStep = xp + 1;
+ } else {
+ xStep = xp;
+ }
+
+ // compute the final pixel
+ pix = pixBuf[x];
+ // (255 * pix) / yStep
+ pix = (pix * d) >> 23;
+
+ // store the pixel
+ for (i = 0; i < xStep; ++i) {
+ *destPtr++ = (Guchar)pix;
+ }
+ }
+ }
- // x shear
- x1 = k1;
+ gfree(pixBuf);
+ gfree(lineBuf);
+}
+
+void Splash::scaleMaskYuXd(SplashImageMaskSource src, void *srcData,
+ int srcWidth, int srcHeight,
+ int scaledWidth, int scaledHeight,
+ SplashBitmap *dest) {
+ Guchar *lineBuf;
+ Guint pix;
+ Guchar *destPtr0, *destPtr;
+ int yp, yq, xp, xq, yt, y, yStep, xt, x, xStep, xx, d, d0, d1;
+ int i;
- // y shear
- y1 = (SplashCoord)ySign * y + yShear * x1;
- // this is a kludge: if yShear1 is negative, then (int)y1 would
- // change immediately after the first pixel, which is not what we
- // want
- if (yShear1 < 0) {
- y1 += 0.999;
+ // Bresenham parameters for y scale
+ yp = scaledHeight / srcHeight;
+ yq = scaledHeight % srcHeight;
+
+ // Bresenham parameters for x scale
+ xp = srcWidth / scaledWidth;
+ xq = srcWidth % scaledWidth;
+
+ // allocate buffers
+ lineBuf = (Guchar *)gmalloc(srcWidth);
+
+ // init y scale Bresenham
+ yt = 0;
+
+ destPtr0 = dest->data;
+ for (y = 0; y < srcHeight; ++y) {
+
+ // y scale Bresenham
+ if ((yt += yq) >= srcHeight) {
+ yt -= srcHeight;
+ yStep = yp + 1;
+ } else {
+ yStep = yp;
}
- // loop-invariant constants
- n = yStep > 0 ? yStep : 1;
+ // read row from image
+ (*src)(srcData, lineBuf);
+
+ // init x scale Bresenham
+ xt = 0;
+ d0 = (255 << 23) / xp;
+ d1 = (255 << 23) / (xp + 1);
+ xx = 0;
for (x = 0; x < scaledWidth; ++x) {
// x scale Bresenham
- xStep = xp;
- xt += xq;
- if (xt >= scaledWidth) {
+ if ((xt += xq) >= scaledWidth) {
xt -= scaledWidth;
- ++xStep;
+ xStep = xp + 1;
+ d = d1;
+ } else {
+ xStep = xp;
+ d = d0;
}
- // rotation
- if (rot) {
- x2 = (int)y1;
- y2 = -x1;
- } else {
- x2 = x1;
- y2 = (int)y1;
- }
-
- // compute the alpha value for (x,y) after the x and y scaling
- // operations
- m = xStep > 0 ? xStep : 1;
- p = pixBuf + xSrc;
- pixAcc = 0;
- for (i = 0; i < n; ++i) {
- for (j = 0; j < m; ++j) {
- pixAcc += *p++;
- }
- p += w - m;
+ // compute the final pixel
+ pix = 0;
+ for (i = 0; i < xStep; ++i) {
+ pix += lineBuf[xx++];
}
+ // (255 * pix) / xStep
+ pix = (pix * d) >> 23;
- // blend fill color with background
- if (pixAcc != 0) {
- pipe.shape = (pixAcc == n * m)
- ? (SplashCoord)1
- : (SplashCoord)pixAcc / (SplashCoord)(n * m);
- if (vectorAntialias && clipRes2 != splashClipAllInside) {
- drawAAPixel(&pipe, tx + x2, ty + y2);
- } else {
- drawPixel(&pipe, tx + x2, ty + y2, clipRes2 == splashClipAllInside);
- }
+ // store the pixel
+ for (i = 0; i < yStep; ++i) {
+ destPtr = destPtr0 + i * scaledWidth + x;
+ *destPtr = (Guchar)pix;
}
+ }
+
+ destPtr0 += yStep * scaledWidth;
+ }
+
+ gfree(lineBuf);
+}
+
+void Splash::scaleMaskYuXu(SplashImageMaskSource src, void *srcData,
+ int srcWidth, int srcHeight,
+ int scaledWidth, int scaledHeight,
+ SplashBitmap *dest) {
+ Guchar *lineBuf;
+ Guint pix;
+ Guchar *destPtr0, *destPtr;
+ int yp, yq, xp, xq, yt, y, yStep, xt, x, xStep, xx;
+ int i, j;
+
+ // Bresenham parameters for y scale
+ yp = scaledHeight / srcHeight;
+ yq = scaledHeight % srcHeight;
+
+ // Bresenham parameters for x scale
+ xp = scaledWidth / srcWidth;
+ xq = scaledWidth % srcWidth;
+
+ // allocate buffers
+ lineBuf = (Guchar *)gmalloc(srcWidth);
+
+ // init y scale Bresenham
+ yt = 0;
+
+ destPtr0 = dest->data;
+ for (y = 0; y < srcHeight; ++y) {
+
+ // y scale Bresenham
+ if ((yt += yq) >= srcHeight) {
+ yt -= srcHeight;
+ yStep = yp + 1;
+ } else {
+ yStep = yp;
+ }
+
+ // read row from image
+ (*src)(srcData, lineBuf);
+
+ // init x scale Bresenham
+ xt = 0;
+
+ xx = 0;
+ for (x = 0; x < srcWidth; ++x) {
// x scale Bresenham
- xSrc += xStep;
+ if ((xt += xq) >= srcWidth) {
+ xt -= srcWidth;
+ xStep = xp + 1;
+ } else {
+ xStep = xp;
+ }
+
+ // compute the final pixel
+ pix = lineBuf[x] ? 255 : 0;
- // x shear
- x1 += xSign;
+ // store the pixel
+ for (i = 0; i < yStep; ++i) {
+ for (j = 0; j < xStep; ++j) {
+ destPtr = destPtr0 + i * scaledWidth + xx + j;
+ *destPtr++ = (Guchar)pix;
+ }
+ }
- // y shear
- y1 += yShear1;
+ xx += xStep;
}
+
+ destPtr0 += yStep * scaledWidth;
}
- // free memory
- gfree(pixBuf);
+ gfree(lineBuf);
+}
- return splashOk;
+void Splash::blitMask(SplashBitmap *src, int xDest, int yDest,
+ SplashClipResult clipRes) {
+ SplashPipe pipe;
+ Guchar *p;
+ int w, h, x, y;
+
+ w = src->getWidth();
+ h = src->getHeight();
+ if (vectorAntialias && clipRes != splashClipAllInside) {
+ pipeInit(&pipe, xDest, yDest, state->fillPattern, NULL,
+ (Guchar)splashRound(state->fillAlpha * 255), gTrue, gFalse);
+ drawAAPixelInit();
+ p = src->getDataPtr();
+ for (y = 0; y < h; ++y) {
+ for (x = 0; x < w; ++x) {
+ pipe.shape = *p++;
+ drawAAPixel(&pipe, xDest + x, yDest + y);
+ }
+ }
+ } else {
+ pipeInit(&pipe, xDest, yDest, state->fillPattern, NULL,
+ (Guchar)splashRound(state->fillAlpha * 255), gTrue, gFalse);
+ p = src->getDataPtr();
+ if (clipRes == splashClipAllInside) {
+ for (y = 0; y < h; ++y) {
+ pipeSetXY(&pipe, xDest, yDest + y);
+ for (x = 0; x < w; ++x) {
+ if (*p) {
+ pipe.shape = *p;
+ (this->*pipe.run)(&pipe);
+ } else {
+ pipeIncX(&pipe);
+ }
+ ++p;
+ }
+ }
+ updateModX(xDest);
+ updateModX(xDest + w - 1);
+ updateModY(yDest);
+ updateModY(yDest + h - 1);
+ } else {
+ for (y = 0; y < h; ++y) {
+ pipeSetXY(&pipe, xDest, yDest + y);
+ for (x = 0; x < w; ++x) {
+ if (*p && state->clip->test(xDest + x, yDest + y)) {
+ pipe.shape = *p;
+ (this->*pipe.run)(&pipe);
+ updateModX(xDest + x);
+ updateModY(yDest + y);
+ } else {
+ pipeIncX(&pipe);
+ }
+ ++p;
+ }
+ }
+ }
+ }
}
SplashError Splash::drawImage(SplashImageSource src, void *srcData,
SplashColorMode srcMode, GBool srcAlpha,
- int w, int h, SplashCoord *mat, SplashPattern *opImagePattern) {
- SplashPipe pipe;
- GBool ok, rot;
- SplashCoord xScale, yScale, xShear, yShear, yShear1;
- int tx, tx2, ty, ty2, scaledWidth, scaledHeight, xSign, ySign;
- int ulx, uly, llx, lly, urx, ury, lrx, lry;
- int ulx1, uly1, llx1, lly1, urx1, ury1, lrx1, lry1;
- int xMin, xMax, yMin, yMax;
- SplashClipResult clipRes, clipRes2;
- int yp, yq, yt, yStep, lastYStep;
- int xp, xq, xt, xStep, xSrc;
- int k1, spanXMin, spanXMax, spanY;
- SplashColorPtr colorBuf, p;
- SplashColor pix;
- Guchar *alphaBuf, *q;
-#if SPLASH_CMYK
- int pixAcc0, pixAcc1, pixAcc2, pixAcc3;
-#else
- int pixAcc0, pixAcc1, pixAcc2;
-#endif
- int alphaAcc;
- SplashCoord pixMul, alphaMul, alpha;
- int x, y, x1, x2, y2;
- SplashCoord y1;
- int nComps, n, m, i, j;
+ int w, int h, SplashCoord *mat) {
+ GBool ok;
+ SplashBitmap *scaledImg;
+ SplashClipResult clipRes;
+ GBool minorAxisZero;
+ int x0, y0, x1, y1, scaledWidth, scaledHeight;
+ int nComps;
+ int yp;
if (debugMode) {
printf("drawImage: srcMode=%d srcAlpha=%d w=%d h=%d mat=[%.2f %.2f %.2f %.2f %.2f %.2f]\n",
@@ -2282,799 +3370,1249 @@ SplashError Splash::drawImage(SplashImageSource src, void *srcData,
nComps = 4;
break;
#endif
+ default:
+ ok = gFalse;
+ break;
}
if (!ok) {
return splashErrModeMismatch;
}
// check for singular matrix
- if (splashAbs(mat[0] * mat[3] - mat[1] * mat[2]) < 0.000001) {
+ if (!splashCheckDet(mat[0], mat[1], mat[2], mat[3], 0.000001)) {
return splashErrSingularMatrix;
}
- // compute scale, shear, rotation, translation parameters
- rot = splashAbs(mat[1]) > splashAbs(mat[0]);
- if (rot) {
- xScale = -mat[1];
- yScale = mat[2] - (mat[0] * mat[3]) / mat[1];
- xShear = -mat[3] / yScale;
- yShear = -mat[0] / mat[1];
- } else {
- xScale = mat[0];
- yScale = mat[3] - (mat[1] * mat[2]) / mat[0];
- xShear = mat[2] / yScale;
- yShear = mat[1] / mat[0];
- }
- // Note 1: The PDF spec says that all pixels whose *centers* lie
- // within the region get painted -- but that doesn't seem to match
- // up with what Acrobat actually does: it ends up leaving gaps
- // between image stripes. So we use the same rule here as for
- // fills: any pixel that overlaps the region gets painted.
- // Note 2: The +/-0.01 in these computations is to avoid floating
- // point precision problems which can lead to gaps between image
- // stripes (it can cause image stripes to overlap, but that's a much
- // less visible problem).
- if (xScale >= 0) {
- tx = splashFloor(mat[4] - 0.01);
- tx2 = splashFloor(mat[4] + xScale + 0.01);
- } else {
- tx = splashFloor(mat[4] + 0.01);
- tx2 = splashFloor(mat[4] + xScale - 0.01);
- }
- scaledWidth = abs(tx2 - tx) + 1;
- if (yScale >= 0) {
- ty = splashFloor(mat[5] - 0.01);
- ty2 = splashFloor(mat[5] + yScale + 0.01);
+ minorAxisZero = mat[1] == 0 && mat[2] == 0;
+
+ // scaling only
+ if (mat[0] > 0 && minorAxisZero && mat[3] > 0) {
+ x0 = imgCoordMungeLower(mat[4]);
+ y0 = imgCoordMungeLower(mat[5]);
+ x1 = imgCoordMungeUpper(mat[0] + mat[4]);
+ y1 = imgCoordMungeUpper(mat[3] + mat[5]);
+ // make sure narrow images cover at least one pixel
+ if (x0 == x1) {
+ ++x1;
+ }
+ if (y0 == y1) {
+ ++y1;
+ }
+ clipRes = state->clip->testRect(x0, y0, x1 - 1, y1 - 1);
+ opClipRes = clipRes;
+ if (clipRes != splashClipAllOutside) {
+ scaledWidth = x1 - x0;
+ scaledHeight = y1 - y0;
+ yp = h / scaledHeight;
+ if (yp < 0 || yp > INT_MAX - 1) {
+ return splashErrBadArg;
+ }
+ scaledImg = scaleImage(src, srcData, srcMode, nComps, srcAlpha, w, h,
+ scaledWidth, scaledHeight);
+ blitImage(scaledImg, srcAlpha, x0, y0, clipRes);
+ delete scaledImg;
+ }
+
+ // scaling plus vertical flip
+ } else if (mat[0] > 0 && minorAxisZero && mat[3] < 0) {
+ x0 = imgCoordMungeLower(mat[4]);
+ y0 = imgCoordMungeLower(mat[3] + mat[5]);
+ x1 = imgCoordMungeUpper(mat[0] + mat[4]);
+ y1 = imgCoordMungeUpper(mat[5]);
+ if (x0 == x1) {
+ if (mat[4] + mat[0] * 0.5 < x0) {
+ --x0;
+ } else {
+ ++x1;
+ }
+ }
+ if (y0 == y1) {
+ if (mat[5] + mat[1] * 0.5 < y0) {
+ --y0;
+ } else {
+ ++y1;
+ }
+ }
+ clipRes = state->clip->testRect(x0, y0, x1 - 1, y1 - 1);
+ opClipRes = clipRes;
+ if (clipRes != splashClipAllOutside) {
+ scaledWidth = x1 - x0;
+ scaledHeight = y1 - y0;
+ yp = h / scaledHeight;
+ if (yp < 0 || yp > INT_MAX - 1) {
+ return splashErrBadArg;
+ }
+ scaledImg = scaleImage(src, srcData, srcMode, nComps, srcAlpha, w, h,
+ scaledWidth, scaledHeight);
+ vertFlipImage(scaledImg, scaledWidth, scaledHeight, nComps);
+ blitImage(scaledImg, srcAlpha, x0, y0, clipRes);
+ delete scaledImg;
+ }
+
+ // all other cases
} else {
- ty = splashFloor(mat[5] + 0.01);
- ty2 = splashFloor(mat[5] + yScale - 0.01);
+ return arbitraryTransformImage(src, srcData, srcMode, nComps, srcAlpha,
+ w, h, mat);
}
- scaledHeight = abs(ty2 - ty) + 1;
- xSign = (xScale < 0) ? -1 : 1;
- ySign = (yScale < 0) ? -1 : 1;
- yShear1 = (SplashCoord)xSign * yShear;
+
+ return splashOk;
+}
+
+SplashError Splash::arbitraryTransformImage(SplashImageSource src, void *srcData,
+ SplashColorMode srcMode, int nComps,
+ GBool srcAlpha,
+ int srcWidth, int srcHeight,
+ SplashCoord *mat) {
+ SplashBitmap *scaledImg;
+ SplashClipResult clipRes, clipRes2;
+ SplashPipe pipe;
+ SplashColor pixel;
+ int scaledWidth, scaledHeight, t0, t1, th;
+ SplashCoord r00, r01, r10, r11, det, ir00, ir01, ir10, ir11;
+ SplashCoord vx[4], vy[4];
+ int xMin, yMin, xMax, yMax;
+ ImageSection section[3];
+ int nSections;
+ int y, xa, xb, x, i, xx, yy, yp;
+
+ // compute the four vertices of the target quadrilateral
+ vx[0] = mat[4]; vy[0] = mat[5];
+ vx[1] = mat[2] + mat[4]; vy[1] = mat[3] + mat[5];
+ vx[2] = mat[0] + mat[2] + mat[4]; vy[2] = mat[1] + mat[3] + mat[5];
+ vx[3] = mat[0] + mat[4]; vy[3] = mat[1] + mat[5];
// clipping
- ulx1 = 0;
- uly1 = 0;
- urx1 = xSign * (scaledWidth - 1);
- ury1 = (int)(yShear * urx1);
- llx1 = splashRound(xShear * ySign * (scaledHeight - 1));
- lly1 = ySign * (scaledHeight - 1) + (int)(yShear * llx1);
- lrx1 = xSign * (scaledWidth - 1) +
- splashRound(xShear * ySign * (scaledHeight - 1));
- lry1 = ySign * (scaledHeight - 1) + (int)(yShear * lrx1);
- if (rot) {
- ulx = tx + uly1; uly = ty - ulx1;
- urx = tx + ury1; ury = ty - urx1;
- llx = tx + lly1; lly = ty - llx1;
- lrx = tx + lry1; lry = ty - lrx1;
- } else {
- ulx = tx + ulx1; uly = ty + uly1;
- urx = tx + urx1; ury = ty + ury1;
- llx = tx + llx1; lly = ty + lly1;
- lrx = tx + lrx1; lry = ty + lry1;
- }
- xMin = (ulx < urx) ? (ulx < llx) ? (ulx < lrx) ? ulx : lrx
- : (llx < lrx) ? llx : lrx
- : (urx < llx) ? (urx < lrx) ? urx : lrx
- : (llx < lrx) ? llx : lrx;
- xMax = (ulx > urx) ? (ulx > llx) ? (ulx > lrx) ? ulx : lrx
- : (llx > lrx) ? llx : lrx
- : (urx > llx) ? (urx > lrx) ? urx : lrx
- : (llx > lrx) ? llx : lrx;
- yMin = (uly < ury) ? (uly < lly) ? (uly < lry) ? uly : lry
- : (lly < lry) ? lly : lry
- : (ury < lly) ? (ury < lry) ? ury : lry
- : (lly < lry) ? lly : lry;
- yMax = (uly > ury) ? (uly > lly) ? (uly > lry) ? uly : lry
- : (lly > lry) ? lly : lry
- : (ury > lly) ? (ury > lry) ? ury : lry
- : (lly > lry) ? lly : lry;
- clipRes = state->clip->testRect(xMin, yMin, xMax, yMax);
+ xMin = imgCoordMungeLower(vx[0]);
+ xMax = imgCoordMungeUpper(vx[0]);
+ yMin = imgCoordMungeLower(vy[0]);
+ yMax = imgCoordMungeUpper(vy[0]);
+ for (i = 1; i < 4; ++i) {
+ t0 = imgCoordMungeLower(vx[i]);
+ if (t0 < xMin) {
+ xMin = t0;
+ }
+ t0 = imgCoordMungeUpper(vx[i]);
+ if (t0 > xMax) {
+ xMax = t0;
+ }
+ t1 = imgCoordMungeLower(vy[i]);
+ if (t1 < yMin) {
+ yMin = t1;
+ }
+ t1 = imgCoordMungeUpper(vy[i]);
+ if (t1 > yMax) {
+ yMax = t1;
+ }
+ }
+ clipRes = state->clip->testRect(xMin, yMin, xMax - 1, yMax - 1);
opClipRes = clipRes;
if (clipRes == splashClipAllOutside) {
return splashOk;
}
- // compute Bresenham parameters for x and y scaling
- yp = h / scaledHeight;
- yq = h % scaledHeight;
- xp = w / scaledWidth;
- xq = w % scaledWidth;
+ // compute the scale factors
+ if (mat[0] >= 0) {
+ t0 = imgCoordMungeUpper(mat[0] + mat[4]) - imgCoordMungeLower(mat[4]);
+ } else {
+ t0 = imgCoordMungeUpper(mat[4]) - imgCoordMungeLower(mat[0] + mat[4]);
+ }
+ if (mat[1] >= 0) {
+ t1 = imgCoordMungeUpper(mat[1] + mat[5]) - imgCoordMungeLower(mat[5]);
+ } else {
+ t1 = imgCoordMungeUpper(mat[5]) - imgCoordMungeLower(mat[1] + mat[5]);
+ }
+ scaledWidth = t0 > t1 ? t0 : t1;
+ if (mat[2] >= 0) {
+ t0 = imgCoordMungeUpper(mat[2] + mat[4]) - imgCoordMungeLower(mat[4]);
+ if (splashAbs(mat[1]) >= 1) {
+ th = imgCoordMungeUpper(mat[2]) - imgCoordMungeLower(mat[0] * mat[3] / mat[1]);
+ if (th > t0) t0 = th;
+ }
+ } else {
+ t0 = imgCoordMungeUpper(mat[4]) - imgCoordMungeLower(mat[2] + mat[4]);
+ if (splashAbs(mat[1]) >= 1) {
+ th = imgCoordMungeUpper(mat[0] * mat[3] / mat[1]) - imgCoordMungeLower(mat[2]);
+ if (th > t0) t0 = th;
+ }
+ }
+ if (mat[3] >= 0) {
+ t1 = imgCoordMungeUpper(mat[3] + mat[5]) - imgCoordMungeLower(mat[5]);
+ if (splashAbs(mat[0]) >= 1) {
+ th = imgCoordMungeUpper(mat[3]) - imgCoordMungeLower(mat[1] * mat[2] / mat[0]);
+ if (th > t1) t1 = th;
+ }
+ } else {
+ t1 = imgCoordMungeUpper(mat[5]) - imgCoordMungeLower(mat[3] + mat[5]);
+ if (splashAbs(mat[0]) >= 1) {
+ th = imgCoordMungeUpper(mat[1] * mat[2] / mat[0]) - imgCoordMungeLower(mat[3]);
+ if (th > t1) t1 = th;
+ }
+ }
+ scaledHeight = t0 > t1 ? t0 : t1;
+ if (scaledWidth == 0) {
+ scaledWidth = 1;
+ }
+ if (scaledHeight == 0) {
+ scaledHeight = 1;
+ }
+
+ // compute the inverse transform (after scaling) matrix
+ r00 = mat[0] / scaledWidth;
+ r01 = mat[1] / scaledWidth;
+ r10 = mat[2] / scaledHeight;
+ r11 = mat[3] / scaledHeight;
+ det = r00 * r11 - r01 * r10;
+ if (splashAbs(det) < 1e-6) {
+ // this should be caught by the singular matrix check in drawImage
+ return splashErrBadArg;
+ }
+ ir00 = r11 / det;
+ ir01 = -r01 / det;
+ ir10 = -r10 / det;
+ ir11 = r00 / det;
- // allocate pixel buffers
+ // scale the input image
+ yp = srcHeight / scaledHeight;
if (yp < 0 || yp > INT_MAX - 1) {
return splashErrBadArg;
}
- colorBuf = (SplashColorPtr)gmallocn3((yp + 1), w, nComps);
- if (srcAlpha) {
- alphaBuf = (Guchar *)gmallocn((yp + 1), w);
+ scaledImg = scaleImage(src, srcData, srcMode, nComps, srcAlpha,
+ srcWidth, srcHeight, scaledWidth, scaledHeight);
+
+ // construct the three sections
+ i = 0;
+ if (vy[1] < vy[i]) {
+ i = 1;
+ }
+ if (vy[2] < vy[i]) {
+ i = 2;
+ }
+ if (vy[3] < vy[i]) {
+ i = 3;
+ }
+ // NB: if using fixed point, 0.000001 will be truncated to zero,
+ // so these two comparisons must be <=, not <
+ if (splashAbs(vy[i] - vy[(i-1) & 3]) <= 0.000001 &&
+ vy[(i-1) & 3] < vy[(i+1) & 3]) {
+ i = (i-1) & 3;
+ }
+ if (splashAbs(vy[i] - vy[(i+1) & 3]) <= 0.000001) {
+ section[0].y0 = imgCoordMungeLower(vy[i]);
+ section[0].y1 = imgCoordMungeUpper(vy[(i+2) & 3]) - 1;
+ if (vx[i] < vx[(i+1) & 3]) {
+ section[0].ia0 = i;
+ section[0].ia1 = (i+3) & 3;
+ section[0].ib0 = (i+1) & 3;
+ section[0].ib1 = (i+2) & 3;
+ } else {
+ section[0].ia0 = (i+1) & 3;
+ section[0].ia1 = (i+2) & 3;
+ section[0].ib0 = i;
+ section[0].ib1 = (i+3) & 3;
+ }
+ nSections = 1;
} else {
- alphaBuf = NULL;
+ section[0].y0 = imgCoordMungeLower(vy[i]);
+ section[2].y1 = imgCoordMungeUpper(vy[(i+2) & 3]) - 1;
+ section[0].ia0 = section[0].ib0 = i;
+ section[2].ia1 = section[2].ib1 = (i+2) & 3;
+ if (vx[(i+1) & 3] < vx[(i+3) & 3]) {
+ section[0].ia1 = section[2].ia0 = (i+1) & 3;
+ section[0].ib1 = section[2].ib0 = (i+3) & 3;
+ } else {
+ section[0].ia1 = section[2].ia0 = (i+3) & 3;
+ section[0].ib1 = section[2].ib0 = (i+1) & 3;
+ }
+ if (vy[(i+1) & 3] < vy[(i+3) & 3]) {
+ section[1].y0 = imgCoordMungeLower(vy[(i+1) & 3]);
+ section[2].y0 = imgCoordMungeUpper(vy[(i+3) & 3]);
+ if (vx[(i+1) & 3] < vx[(i+3) & 3]) {
+ section[1].ia0 = (i+1) & 3;
+ section[1].ia1 = (i+2) & 3;
+ section[1].ib0 = i;
+ section[1].ib1 = (i+3) & 3;
+ } else {
+ section[1].ia0 = i;
+ section[1].ia1 = (i+3) & 3;
+ section[1].ib0 = (i+1) & 3;
+ section[1].ib1 = (i+2) & 3;
+ }
+ } else {
+ section[1].y0 = imgCoordMungeLower(vy[(i+3) & 3]);
+ section[2].y0 = imgCoordMungeUpper(vy[(i+1) & 3]);
+ if (vx[(i+1) & 3] < vx[(i+3) & 3]) {
+ section[1].ia0 = i;
+ section[1].ia1 = (i+1) & 3;
+ section[1].ib0 = (i+3) & 3;
+ section[1].ib1 = (i+2) & 3;
+ } else {
+ section[1].ia0 = (i+3) & 3;
+ section[1].ia1 = (i+2) & 3;
+ section[1].ib0 = i;
+ section[1].ib1 = (i+1) & 3;
+ }
+ }
+ section[0].y1 = section[1].y0 - 1;
+ section[1].y1 = section[2].y0 - 1;
+ nSections = 3;
+ }
+ for (i = 0; i < nSections; ++i) {
+ section[i].xa0 = vx[section[i].ia0];
+ section[i].ya0 = vy[section[i].ia0];
+ section[i].xa1 = vx[section[i].ia1];
+ section[i].ya1 = vy[section[i].ia1];
+ section[i].xb0 = vx[section[i].ib0];
+ section[i].yb0 = vy[section[i].ib0];
+ section[i].xb1 = vx[section[i].ib1];
+ section[i].yb1 = vy[section[i].ib1];
+ section[i].dxdya = (section[i].xa1 - section[i].xa0) /
+ (section[i].ya1 - section[i].ya0);
+ section[i].dxdyb = (section[i].xb1 - section[i].xb0) /
+ (section[i].yb1 - section[i].yb0);
}
-
- pixAcc0 = pixAcc1 = pixAcc2 = 0; // make gcc happy
-#if SPLASH_CMYK
- pixAcc3 = 0; // make gcc happy
-#endif
// initialize the pixel pipe
- pipeInit(&pipe, 0, 0, NULL, pix, state->fillAlpha,
+ pipeInit(&pipe, 0, 0, NULL, pixel,
+ (Guchar)splashRound(state->fillAlpha * 255),
srcAlpha || (vectorAntialias && clipRes != splashClipAllInside),
- gFalse, opImagePattern);
+ gFalse);
if (vectorAntialias) {
drawAAPixelInit();
}
- if (srcAlpha) {
-
- // init y scale Bresenham
- yt = 0;
- lastYStep = 1;
-
- for (y = 0; y < scaledHeight; ++y) {
+ // make sure narrow images cover at least one pixel
+ if (nSections == 1) {
+ if (section[0].y0 == section[0].y1) {
+ ++section[0].y1;
+ clipRes = opClipRes = splashClipPartial;
+ }
+ } else {
+ if (section[0].y0 == section[2].y1) {
+ ++section[1].y1;
+ clipRes = opClipRes = splashClipPartial;
+ }
+ }
- // y scale Bresenham
- yStep = yp;
- yt += yq;
- if (yt >= scaledHeight) {
- yt -= scaledHeight;
- ++yStep;
- }
-
- // read row(s) from image
- n = (yp > 0) ? yStep : lastYStep;
- if (n > 0) {
- p = colorBuf;
- q = alphaBuf;
- for (i = 0; i < n; ++i) {
- (*src)(srcData, p, q);
- p += w * nComps;
- q += w;
- }
+ // scan all pixels inside the target region
+ for (i = 0; i < nSections; ++i) {
+ for (y = section[i].y0; y <= section[i].y1; ++y) {
+ xa = imgCoordMungeLower(section[i].xa0 +
+ ((SplashCoord)y + 0.5 - section[i].ya0) *
+ section[i].dxdya);
+ xb = imgCoordMungeUpper(section[i].xb0 +
+ ((SplashCoord)y + 0.5 - section[i].yb0) *
+ section[i].dxdyb);
+ // make sure narrow images cover at least one pixel
+ if (xa == xb) {
+ ++xb;
}
- lastYStep = yStep;
-
- // loop-invariant constants
- k1 = splashRound(xShear * ySign * y);
-
- // clipping test
- if (clipRes != splashClipAllInside &&
- !rot &&
- (int)(yShear * k1) ==
- (int)(yShear * (xSign * (scaledWidth - 1) + k1))) {
- if (xSign > 0) {
- spanXMin = tx + k1;
- spanXMax = spanXMin + (scaledWidth - 1);
+ if (clipRes != splashClipAllInside) {
+ clipRes2 = state->clip->testSpan(xa, xb - 1, y);
+ } else {
+ clipRes2 = clipRes;
+ }
+ for (x = xa; x < xb; ++x) {
+ // map (x+0.5, y+0.5) back to the scaled image
+ xx = splashFloor(((SplashCoord)x + 0.5 - mat[4]) * ir00 +
+ ((SplashCoord)y + 0.5 - mat[5]) * ir10);
+ yy = splashFloor(((SplashCoord)x + 0.5 - mat[4]) * ir01 +
+ ((SplashCoord)y + 0.5 - mat[5]) * ir11);
+ // xx should always be within bounds, but floating point
+ // inaccuracy can cause problems
+ if (xx < 0) {
+ xx = 0;
+ } else if (xx >= scaledWidth) {
+ xx = scaledWidth - 1;
+ }
+ if (yy < 0) {
+ yy = 0;
+ } else if (yy >= scaledHeight) {
+ yy = scaledHeight - 1;
+ }
+ scaledImg->getPixel(xx, yy, pixel);
+ if (srcAlpha) {
+ pipe.shape = scaledImg->alpha[yy * scaledWidth + xx];
} else {
- spanXMax = tx + k1;
- spanXMin = spanXMax - (scaledWidth - 1);
+ pipe.shape = 255;
}
- spanY = ty + ySign * y + (int)(yShear * k1);
- clipRes2 = state->clip->testSpan(spanXMin, spanXMax, spanY);
- if (clipRes2 == splashClipAllOutside) {
- continue;
+ if (vectorAntialias && clipRes2 != splashClipAllInside) {
+ drawAAPixel(&pipe, x, y);
+ } else {
+ drawPixel(&pipe, x, y, clipRes2 == splashClipAllInside);
}
- } else {
- clipRes2 = clipRes;
}
+ }
+ }
- // init x scale Bresenham
- xt = 0;
- xSrc = 0;
+ delete scaledImg;
+ return splashOk;
+}
- // x shear
- x1 = k1;
+// Scale an image into a SplashBitmap.
+SplashBitmap *Splash::scaleImage(SplashImageSource src, void *srcData,
+ SplashColorMode srcMode, int nComps,
+ GBool srcAlpha, int srcWidth, int srcHeight,
+ int scaledWidth, int scaledHeight) {
+ SplashBitmap *dest;
+
+ dest = new SplashBitmap(scaledWidth, scaledHeight, 1, srcMode, srcAlpha);
+ if (scaledHeight < srcHeight) {
+ if (scaledWidth < srcWidth) {
+ scaleImageYdXd(src, srcData, srcMode, nComps, srcAlpha,
+ srcWidth, srcHeight, scaledWidth, scaledHeight, dest);
+ } else {
+ scaleImageYdXu(src, srcData, srcMode, nComps, srcAlpha,
+ srcWidth, srcHeight, scaledWidth, scaledHeight, dest);
+ }
+ } else {
+ if (scaledWidth < srcWidth) {
+ scaleImageYuXd(src, srcData, srcMode, nComps, srcAlpha,
+ srcWidth, srcHeight, scaledWidth, scaledHeight, dest);
+ } else {
+ scaleImageYuXu(src, srcData, srcMode, nComps, srcAlpha,
+ srcWidth, srcHeight, scaledWidth, scaledHeight, dest);
+ }
+ }
+ return dest;
+}
- // y shear
- y1 = (SplashCoord)ySign * y + yShear * x1;
- // this is a kludge: if yShear1 is negative, then (int)y1 would
- // change immediately after the first pixel, which is not what
- // we want
- if (yShear1 < 0) {
- y1 += 0.999;
- }
+void Splash::scaleImageYdXd(SplashImageSource src, void *srcData,
+ SplashColorMode srcMode, int nComps,
+ GBool srcAlpha, int srcWidth, int srcHeight,
+ int scaledWidth, int scaledHeight,
+ SplashBitmap *dest) {
+ Guchar *lineBuf, *alphaLineBuf;
+ Guint *pixBuf, *alphaPixBuf;
+ Guint pix0, pix1, pix2;
+#if SPLASH_CMYK
+ Guint pix3;
+#endif
+ Guint alpha;
+ Guchar *destPtr, *destAlphaPtr;
+ int yp, yq, xp, xq, yt, y, yStep, xt, x, xStep, xx, xxa, d, d0, d1;
+ int i, j;
+
+ // Bresenham parameters for y scale
+ yp = srcHeight / scaledHeight;
+ yq = srcHeight % scaledHeight;
+
+ // Bresenham parameters for x scale
+ xp = srcWidth / scaledWidth;
+ xq = srcWidth % scaledWidth;
+
+ // allocate buffers
+ lineBuf = (Guchar *)gmallocn(srcWidth, nComps);
+ pixBuf = (Guint *)gmallocn(srcWidth, nComps * sizeof(int));
+ if (srcAlpha) {
+ alphaLineBuf = (Guchar *)gmalloc(srcWidth);
+ alphaPixBuf = (Guint *)gmallocn(srcWidth, sizeof(int));
+ } else {
+ alphaLineBuf = NULL;
+ alphaPixBuf = NULL;
+ }
- // loop-invariant constants
- n = yStep > 0 ? yStep : 1;
+ // init y scale Bresenham
+ yt = 0;
- switch (srcMode) {
+ destPtr = dest->data;
+ destAlphaPtr = dest->alpha;
+ for (y = 0; y < scaledHeight; ++y) {
- case splashModeMono1:
- case splashModeMono8:
- for (x = 0; x < scaledWidth; ++x) {
-
- // x scale Bresenham
- xStep = xp;
- xt += xq;
- if (xt >= scaledWidth) {
- xt -= scaledWidth;
- ++xStep;
- }
+ // y scale Bresenham
+ if ((yt += yq) >= scaledHeight) {
+ yt -= scaledHeight;
+ yStep = yp + 1;
+ } else {
+ yStep = yp;
+ }
- // rotation
- if (rot) {
- x2 = (int)y1;
- y2 = -x1;
- } else {
- x2 = x1;
- y2 = (int)y1;
- }
+ // read rows from image
+ memset(pixBuf, 0, srcWidth * nComps * sizeof(int));
+ if (srcAlpha) {
+ memset(alphaPixBuf, 0, srcWidth * sizeof(int));
+ }
+ for (i = 0; i < yStep; ++i) {
+ (*src)(srcData, lineBuf, alphaLineBuf);
+ for (j = 0; j < srcWidth * nComps; ++j) {
+ pixBuf[j] += lineBuf[j];
+ }
+ if (srcAlpha) {
+ for (j = 0; j < srcWidth; ++j) {
+ alphaPixBuf[j] += alphaLineBuf[j];
+ }
+ }
+ }
- // compute the filtered pixel at (x,y) after the x and y scaling
- // operations
- m = xStep > 0 ? xStep : 1;
- alphaAcc = 0;
- p = colorBuf + xSrc;
- q = alphaBuf + xSrc;
- pixAcc0 = 0;
- for (i = 0; i < n; ++i) {
- for (j = 0; j < m; ++j) {
- pixAcc0 += *p++;
- alphaAcc += *q++;
- }
- p += w - m;
- q += w - m;
- }
- pixMul = (SplashCoord)1 / (SplashCoord)(n * m);
- alphaMul = pixMul * (1.0 / 255.0);
- alpha = (SplashCoord)alphaAcc * alphaMul;
+ // init x scale Bresenham
+ xt = 0;
+ d0 = (1 << 23) / (yStep * xp);
+ d1 = (1 << 23) / (yStep * (xp + 1));
- if (alpha > 0) {
- pix[0] = (int)((SplashCoord)pixAcc0 * pixMul);
+ xx = xxa = 0;
+ for (x = 0; x < scaledWidth; ++x) {
- // set pixel
- pipe.shape = alpha;
- if (vectorAntialias && clipRes != splashClipAllInside) {
- drawAAPixel(&pipe, tx + x2, ty + y2);
- } else {
- drawPixel(&pipe, tx + x2, ty + y2,
- clipRes2 == splashClipAllInside);
- }
- }
+ // x scale Bresenham
+ if ((xt += xq) >= scaledWidth) {
+ xt -= scaledWidth;
+ xStep = xp + 1;
+ d = d1;
+ } else {
+ xStep = xp;
+ d = d0;
+ }
- // x scale Bresenham
- xSrc += xStep;
+ switch (srcMode) {
- // x shear
- x1 += xSign;
+ case splashModeMono8:
- // y shear
- y1 += yShear1;
+ // compute the final pixel
+ pix0 = 0;
+ for (i = 0; i < xStep; ++i) {
+ pix0 += pixBuf[xx++];
}
+ // pix / xStep * yStep
+ pix0 = (pix0 * d) >> 23;
+
+ // store the pixel
+ *destPtr++ = (Guchar)pix0;
break;
case splashModeRGB8:
- case splashModeBGR8:
- for (x = 0; x < scaledWidth; ++x) {
-
- // x scale Bresenham
- xStep = xp;
- xt += xq;
- if (xt >= scaledWidth) {
- xt -= scaledWidth;
- ++xStep;
- }
-
- // rotation
- if (rot) {
- x2 = (int)y1;
- y2 = -x1;
- } else {
- x2 = x1;
- y2 = (int)y1;
- }
-
- // compute the filtered pixel at (x,y) after the x and y scaling
- // operations
- m = xStep > 0 ? xStep : 1;
- alphaAcc = 0;
- p = colorBuf + xSrc * 3;
- q = alphaBuf + xSrc;
- pixAcc0 = pixAcc1 = pixAcc2 = 0;
- for (i = 0; i < n; ++i) {
- for (j = 0; j < m; ++j) {
- pixAcc0 += *p++;
- pixAcc1 += *p++;
- pixAcc2 += *p++;
- alphaAcc += *q++;
- }
- p += 3 * (w - m);
- q += w - m;
- }
- pixMul = (SplashCoord)1 / (SplashCoord)(n * m);
- alphaMul = pixMul * (1.0 / 255.0);
- alpha = (SplashCoord)alphaAcc * alphaMul;
-
- if (alpha > 0) {
- pix[0] = (int)((SplashCoord)pixAcc0 * pixMul);
- pix[1] = (int)((SplashCoord)pixAcc1 * pixMul);
- pix[2] = (int)((SplashCoord)pixAcc2 * pixMul);
-
- // set pixel
- pipe.shape = alpha;
- if (vectorAntialias && clipRes != splashClipAllInside) {
- drawAAPixel(&pipe, tx + x2, ty + y2);
- } else {
- drawPixel(&pipe, tx + x2, ty + y2,
- clipRes2 == splashClipAllInside);
- }
- }
-
- // x scale Bresenham
- xSrc += xStep;
- // x shear
- x1 += xSign;
-
- // y shear
- y1 += yShear1;
+ // compute the final pixel
+ pix0 = pix1 = pix2 = 0;
+ for (i = 0; i < xStep; ++i) {
+ pix0 += pixBuf[xx];
+ pix1 += pixBuf[xx+1];
+ pix2 += pixBuf[xx+2];
+ xx += 3;
}
+ // pix / xStep * yStep
+ pix0 = (pix0 * d) >> 23;
+ pix1 = (pix1 * d) >> 23;
+ pix2 = (pix2 * d) >> 23;
+
+ // store the pixel
+ *destPtr++ = (Guchar)pix0;
+ *destPtr++ = (Guchar)pix1;
+ *destPtr++ = (Guchar)pix2;
break;
case splashModeXBGR8:
- for (x = 0; x < scaledWidth; ++x) {
- // x scale Bresenham
- xStep = xp;
- xt += xq;
- if (xt >= scaledWidth) {
- xt -= scaledWidth;
- ++xStep;
- }
-
- // rotation
- if (rot) {
- x2 = (int)y1;
- y2 = -x1;
- } else {
- x2 = x1;
- y2 = (int)y1;
- }
-
- // compute the filtered pixel at (x,y) after the x and y scaling
- // operations
- m = xStep > 0 ? xStep : 1;
- alphaAcc = 0;
- p = colorBuf + xSrc * 4;
- q = alphaBuf + xSrc;
- pixAcc0 = pixAcc1 = pixAcc2 = 0;
- for (i = 0; i < n; ++i) {
- for (j = 0; j < m; ++j) {
- pixAcc0 += *p++;
- pixAcc1 += *p++;
- pixAcc2 += *p++;
- p++;
- alphaAcc += *q++;
- }
- p += 4 * (w - m);
- q += w - m;
- }
- pixMul = (SplashCoord)1 / (SplashCoord)(n * m);
- alphaMul = pixMul * (1.0 / 255.0);
- alpha = (SplashCoord)alphaAcc * alphaMul;
- if (alpha > 0) {
- pix[0] = (int)((SplashCoord)pixAcc0 * pixMul);
- pix[1] = (int)((SplashCoord)pixAcc1 * pixMul);
- pix[2] = (int)((SplashCoord)pixAcc2 * pixMul);
- pix[3] = 255;
-
- // set pixel
- pipe.shape = alpha;
- if (vectorAntialias && clipRes != splashClipAllInside) {
- drawAAPixel(&pipe, tx + x2, ty + y2);
- } else {
- drawPixel(&pipe, tx + x2, ty + y2,
- clipRes2 == splashClipAllInside);
- }
- }
-
- // x scale Bresenham
- xSrc += xStep;
+ // compute the final pixel
+ pix0 = pix1 = pix2 = 0;
+ for (i = 0; i < xStep; ++i) {
+ pix0 += pixBuf[xx];
+ pix1 += pixBuf[xx+1];
+ pix2 += pixBuf[xx+2];
+ xx += 4;
+ }
+ // pix / xStep * yStep
+ pix0 = (pix0 * d) >> 23;
+ pix1 = (pix1 * d) >> 23;
+ pix2 = (pix2 * d) >> 23;
+
+ // store the pixel
+ *destPtr++ = (Guchar)pix2;
+ *destPtr++ = (Guchar)pix1;
+ *destPtr++ = (Guchar)pix0;
+ *destPtr++ = (Guchar)255;
+ break;
- // x shear
- x1 += xSign;
+ case splashModeBGR8:
- // y shear
- y1 += yShear1;
+ // compute the final pixel
+ pix0 = pix1 = pix2 = 0;
+ for (i = 0; i < xStep; ++i) {
+ pix0 += pixBuf[xx];
+ pix1 += pixBuf[xx+1];
+ pix2 += pixBuf[xx+2];
+ xx += 3;
}
+ // pix / xStep * yStep
+ pix0 = (pix0 * d) >> 23;
+ pix1 = (pix1 * d) >> 23;
+ pix2 = (pix2 * d) >> 23;
+
+ // store the pixel
+ *destPtr++ = (Guchar)pix2;
+ *destPtr++ = (Guchar)pix1;
+ *destPtr++ = (Guchar)pix0;
break;
-
#if SPLASH_CMYK
case splashModeCMYK8:
- for (x = 0; x < scaledWidth; ++x) {
-
- // x scale Bresenham
- xStep = xp;
- xt += xq;
- if (xt >= scaledWidth) {
- xt -= scaledWidth;
- ++xStep;
- }
- // rotation
- if (rot) {
- x2 = (int)y1;
- y2 = -x1;
- } else {
- x2 = x1;
- y2 = (int)y1;
- }
-
- // compute the filtered pixel at (x,y) after the x and y scaling
- // operations
- m = xStep > 0 ? xStep : 1;
- alphaAcc = 0;
- p = colorBuf + xSrc * 4;
- q = alphaBuf + xSrc;
- pixAcc0 = pixAcc1 = pixAcc2 = pixAcc3 = 0;
- for (i = 0; i < n; ++i) {
- for (j = 0; j < m; ++j) {
- pixAcc0 += *p++;
- pixAcc1 += *p++;
- pixAcc2 += *p++;
- pixAcc3 += *p++;
- alphaAcc += *q++;
- }
- p += 4 * (w - m);
- q += w - m;
- }
- pixMul = (SplashCoord)1 / (SplashCoord)(n * m);
- alphaMul = pixMul * (1.0 / 255.0);
- alpha = (SplashCoord)alphaAcc * alphaMul;
-
- if (alpha > 0) {
- pix[0] = (int)((SplashCoord)pixAcc0 * pixMul);
- pix[1] = (int)((SplashCoord)pixAcc1 * pixMul);
- pix[2] = (int)((SplashCoord)pixAcc2 * pixMul);
- pix[3] = (int)((SplashCoord)pixAcc3 * pixMul);
-
- // set pixel
- pipe.shape = alpha;
- if (vectorAntialias && clipRes != splashClipAllInside) {
- drawAAPixel(&pipe, tx + x2, ty + y2);
- } else {
- drawPixel(&pipe, tx + x2, ty + y2,
- clipRes2 == splashClipAllInside);
- }
- }
+ // compute the final pixel
+ pix0 = pix1 = pix2 = pix3 = 0;
+ for (i = 0; i < xStep; ++i) {
+ pix0 += pixBuf[xx];
+ pix1 += pixBuf[xx+1];
+ pix2 += pixBuf[xx+2];
+ pix3 += pixBuf[xx+3];
+ xx += 4;
+ }
+ // pix / xStep * yStep
+ pix0 = (pix0 * d) >> 23;
+ pix1 = (pix1 * d) >> 23;
+ pix2 = (pix2 * d) >> 23;
+ pix3 = (pix3 * d) >> 23;
+
+ // store the pixel
+ *destPtr++ = (Guchar)pix0;
+ *destPtr++ = (Guchar)pix1;
+ *destPtr++ = (Guchar)pix2;
+ *destPtr++ = (Guchar)pix3;
+ break;
+#endif
- // x scale Bresenham
- xSrc += xStep;
- // x shear
- x1 += xSign;
+ case splashModeMono1: // mono1 is not allowed
+ default:
+ break;
+ }
- // y shear
- y1 += yShear1;
+ // process alpha
+ if (srcAlpha) {
+ alpha = 0;
+ for (i = 0; i < xStep; ++i, ++xxa) {
+ alpha += alphaPixBuf[xxa];
}
- break;
-#endif // SPLASH_CMYK
+ // alpha / xStep * yStep
+ alpha = (alpha * d) >> 23;
+ *destAlphaPtr++ = (Guchar)alpha;
}
}
+ }
+ gfree(alphaPixBuf);
+ gfree(alphaLineBuf);
+ gfree(pixBuf);
+ gfree(lineBuf);
+}
+
+void Splash::scaleImageYdXu(SplashImageSource src, void *srcData,
+ SplashColorMode srcMode, int nComps,
+ GBool srcAlpha, int srcWidth, int srcHeight,
+ int scaledWidth, int scaledHeight,
+ SplashBitmap *dest) {
+ Guchar *lineBuf, *alphaLineBuf;
+ Guint *pixBuf, *alphaPixBuf;
+ Guint pix[splashMaxColorComps];
+ Guint alpha;
+ Guchar *destPtr, *destAlphaPtr;
+ int yp, yq, xp, xq, yt, y, yStep, xt, x, xStep, d;
+ int i, j;
+
+ // Bresenham parameters for y scale
+ yp = srcHeight / scaledHeight;
+ yq = srcHeight % scaledHeight;
+
+ // Bresenham parameters for x scale
+ xp = scaledWidth / srcWidth;
+ xq = scaledWidth % srcWidth;
+
+ // allocate buffers
+ lineBuf = (Guchar *)gmallocn(srcWidth, nComps);
+ pixBuf = (Guint *)gmallocn(srcWidth, nComps * sizeof(int));
+ if (srcAlpha) {
+ alphaLineBuf = (Guchar *)gmalloc(srcWidth);
+ alphaPixBuf = (Guint *)gmallocn(srcWidth, sizeof(int));
} else {
+ alphaLineBuf = NULL;
+ alphaPixBuf = NULL;
+ }
- // init y scale Bresenham
- yt = 0;
- lastYStep = 1;
+ // init y scale Bresenham
+ yt = 0;
- for (y = 0; y < scaledHeight; ++y) {
+ destPtr = dest->data;
+ destAlphaPtr = dest->alpha;
+ for (y = 0; y < scaledHeight; ++y) {
- // y scale Bresenham
+ // y scale Bresenham
+ if ((yt += yq) >= scaledHeight) {
+ yt -= scaledHeight;
+ yStep = yp + 1;
+ } else {
yStep = yp;
- yt += yq;
- if (yt >= scaledHeight) {
- yt -= scaledHeight;
- ++yStep;
- }
-
- // read row(s) from image
- n = (yp > 0) ? yStep : lastYStep;
- if (n > 0) {
- p = colorBuf;
- for (i = 0; i < n; ++i) {
- (*src)(srcData, p, NULL);
- p += w * nComps;
+ }
+
+ // read rows from image
+ memset(pixBuf, 0, srcWidth * nComps * sizeof(int));
+ if (srcAlpha) {
+ memset(alphaPixBuf, 0, srcWidth * sizeof(int));
+ }
+ for (i = 0; i < yStep; ++i) {
+ (*src)(srcData, lineBuf, alphaLineBuf);
+ for (j = 0; j < srcWidth * nComps; ++j) {
+ pixBuf[j] += lineBuf[j];
+ }
+ if (srcAlpha) {
+ for (j = 0; j < srcWidth; ++j) {
+ alphaPixBuf[j] += alphaLineBuf[j];
}
}
- lastYStep = yStep;
+ }
- // loop-invariant constants
- k1 = splashRound(xShear * ySign * y);
+ // init x scale Bresenham
+ xt = 0;
+ d = (1 << 23) / yStep;
- // clipping test
- if (clipRes != splashClipAllInside &&
- !rot &&
- (int)(yShear * k1) ==
- (int)(yShear * (xSign * (scaledWidth - 1) + k1))) {
- if (xSign > 0) {
- spanXMin = tx + k1;
- spanXMax = spanXMin + (scaledWidth - 1);
- } else {
- spanXMax = tx + k1;
- spanXMin = spanXMax - (scaledWidth - 1);
- }
- spanY = ty + ySign * y + (int)(yShear * k1);
- clipRes2 = state->clip->testSpan(spanXMin, spanXMax, spanY);
- if (clipRes2 == splashClipAllOutside) {
- continue;
- }
+ for (x = 0; x < srcWidth; ++x) {
+
+ // x scale Bresenham
+ if ((xt += xq) >= srcWidth) {
+ xt -= srcWidth;
+ xStep = xp + 1;
} else {
- clipRes2 = clipRes;
+ xStep = xp;
}
- // init x scale Bresenham
- xt = 0;
- xSrc = 0;
+ // compute the final pixel
+ for (i = 0; i < nComps; ++i) {
+ // pixBuf[] / yStep
+ pix[i] = (pixBuf[x * nComps + i] * d) >> 23;
+ }
- // x shear
- x1 = k1;
+ // store the pixel
+ switch (srcMode) {
+ case splashModeMono1: // mono1 is not allowed
+ break;
+ case splashModeMono8:
+ for (i = 0; i < xStep; ++i) {
+ *destPtr++ = (Guchar)pix[0];
+ }
+ break;
+ case splashModeRGB8:
+ for (i = 0; i < xStep; ++i) {
+ *destPtr++ = (Guchar)pix[0];
+ *destPtr++ = (Guchar)pix[1];
+ *destPtr++ = (Guchar)pix[2];
+ }
+ break;
+ case splashModeXBGR8:
+ for (i = 0; i < xStep; ++i) {
+ *destPtr++ = (Guchar)pix[2];
+ *destPtr++ = (Guchar)pix[1];
+ *destPtr++ = (Guchar)pix[0];
+ *destPtr++ = (Guchar)255;
+ }
+ break;
+ case splashModeBGR8:
+ for (i = 0; i < xStep; ++i) {
+ *destPtr++ = (Guchar)pix[2];
+ *destPtr++ = (Guchar)pix[1];
+ *destPtr++ = (Guchar)pix[0];
+ }
+ break;
+#if SPLASH_CMYK
+ case splashModeCMYK8:
+ for (i = 0; i < xStep; ++i) {
+ *destPtr++ = (Guchar)pix[0];
+ *destPtr++ = (Guchar)pix[1];
+ *destPtr++ = (Guchar)pix[2];
+ *destPtr++ = (Guchar)pix[3];
+ }
+ break;
+#endif
+ }
- // y shear
- y1 = (SplashCoord)ySign * y + yShear * x1;
- // this is a kludge: if yShear1 is negative, then (int)y1 would
- // change immediately after the first pixel, which is not what
- // we want
- if (yShear1 < 0) {
- y1 += 0.999;
+ // process alpha
+ if (srcAlpha) {
+ // alphaPixBuf[] / yStep
+ alpha = (alphaPixBuf[x] * d) >> 23;
+ for (i = 0; i < xStep; ++i) {
+ *destAlphaPtr++ = (Guchar)alpha;
+ }
}
+ }
+ }
- // loop-invariant constants
- n = yStep > 0 ? yStep : 1;
+ gfree(alphaPixBuf);
+ gfree(alphaLineBuf);
+ gfree(pixBuf);
+ gfree(lineBuf);
+}
- switch (srcMode) {
+void Splash::scaleImageYuXd(SplashImageSource src, void *srcData,
+ SplashColorMode srcMode, int nComps,
+ GBool srcAlpha, int srcWidth, int srcHeight,
+ int scaledWidth, int scaledHeight,
+ SplashBitmap *dest) {
+ Guchar *lineBuf, *alphaLineBuf;
+ Guint pix[splashMaxColorComps];
+ Guint alpha;
+ Guchar *destPtr0, *destPtr, *destAlphaPtr0, *destAlphaPtr;
+ int yp, yq, xp, xq, yt, y, yStep, xt, x, xStep, xx, xxa, d, d0, d1;
+ int i, j;
+
+ // Bresenham parameters for y scale
+ yp = scaledHeight / srcHeight;
+ yq = scaledHeight % srcHeight;
+
+ // Bresenham parameters for x scale
+ xp = srcWidth / scaledWidth;
+ xq = srcWidth % scaledWidth;
+
+ // allocate buffers
+ lineBuf = (Guchar *)gmallocn(srcWidth, nComps);
+ if (srcAlpha) {
+ alphaLineBuf = (Guchar *)gmalloc(srcWidth);
+ } else {
+ alphaLineBuf = NULL;
+ }
- case splashModeMono1:
- case splashModeMono8:
- for (x = 0; x < scaledWidth; ++x) {
-
- // x scale Bresenham
- xStep = xp;
- xt += xq;
- if (xt >= scaledWidth) {
- xt -= scaledWidth;
- ++xStep;
- }
+ // init y scale Bresenham
+ yt = 0;
- // rotation
- if (rot) {
- x2 = (int)y1;
- y2 = -x1;
- } else {
- x2 = x1;
- y2 = (int)y1;
- }
+ destPtr0 = dest->data;
+ destAlphaPtr0 = dest->alpha;
+ for (y = 0; y < srcHeight; ++y) {
- // compute the filtered pixel at (x,y) after the x and y scaling
- // operations
- m = xStep > 0 ? xStep : 1;
- p = colorBuf + xSrc;
- pixAcc0 = 0;
- for (i = 0; i < n; ++i) {
- for (j = 0; j < m; ++j) {
- pixAcc0 += *p++;
- }
- p += w - m;
- }
- pixMul = (SplashCoord)1 / (SplashCoord)(n * m);
+ // y scale Bresenham
+ if ((yt += yq) >= srcHeight) {
+ yt -= srcHeight;
+ yStep = yp + 1;
+ } else {
+ yStep = yp;
+ }
- pix[0] = (int)((SplashCoord)pixAcc0 * pixMul);
+ // read row from image
+ (*src)(srcData, lineBuf, alphaLineBuf);
- // set pixel
- if (vectorAntialias && clipRes != splashClipAllInside) {
- pipe.shape = (SplashCoord)1;
- drawAAPixel(&pipe, tx + x2, ty + y2);
- } else {
- drawPixel(&pipe, tx + x2, ty + y2,
- clipRes2 == splashClipAllInside);
- }
+ // init x scale Bresenham
+ xt = 0;
+ d0 = (1 << 23) / xp;
+ d1 = (1 << 23) / (xp + 1);
- // x scale Bresenham
- xSrc += xStep;
+ xx = xxa = 0;
+ for (x = 0; x < scaledWidth; ++x) {
- // x shear
- x1 += xSign;
+ // x scale Bresenham
+ if ((xt += xq) >= scaledWidth) {
+ xt -= scaledWidth;
+ xStep = xp + 1;
+ d = d1;
+ } else {
+ xStep = xp;
+ d = d0;
+ }
- // y shear
- y1 += yShear1;
+ // compute the final pixel
+ for (i = 0; i < nComps; ++i) {
+ pix[i] = 0;
+ }
+ for (i = 0; i < xStep; ++i) {
+ for (j = 0; j < nComps; ++j, ++xx) {
+ pix[j] += lineBuf[xx];
}
- break;
+ }
+ for (i = 0; i < nComps; ++i) {
+ // pix[] / xStep
+ pix[i] = (pix[i] * d) >> 23;
+ }
+ // store the pixel
+ switch (srcMode) {
+ case splashModeMono1: // mono1 is not allowed
+ break;
+ case splashModeMono8:
+ for (i = 0; i < yStep; ++i) {
+ destPtr = destPtr0 + (i * scaledWidth + x) * nComps;
+ *destPtr++ = (Guchar)pix[0];
+ }
+ break;
case splashModeRGB8:
+ for (i = 0; i < yStep; ++i) {
+ destPtr = destPtr0 + (i * scaledWidth + x) * nComps;
+ *destPtr++ = (Guchar)pix[0];
+ *destPtr++ = (Guchar)pix[1];
+ *destPtr++ = (Guchar)pix[2];
+ }
+ break;
+ case splashModeXBGR8:
+ for (i = 0; i < yStep; ++i) {
+ destPtr = destPtr0 + (i * scaledWidth + x) * nComps;
+ *destPtr++ = (Guchar)pix[2];
+ *destPtr++ = (Guchar)pix[1];
+ *destPtr++ = (Guchar)pix[0];
+ *destPtr++ = (Guchar)255;
+ }
+ break;
case splashModeBGR8:
- for (x = 0; x < scaledWidth; ++x) {
-
- // x scale Bresenham
- xStep = xp;
- xt += xq;
- if (xt >= scaledWidth) {
- xt -= scaledWidth;
- ++xStep;
- }
-
- // rotation
- if (rot) {
- x2 = (int)y1;
- y2 = -x1;
- } else {
- x2 = x1;
- y2 = (int)y1;
- }
-
- // compute the filtered pixel at (x,y) after the x and y scaling
- // operations
- m = xStep > 0 ? xStep : 1;
- p = colorBuf + xSrc * 3;
- pixAcc0 = pixAcc1 = pixAcc2 = 0;
- for (i = 0; i < n; ++i) {
- for (j = 0; j < m; ++j) {
- pixAcc0 += *p++;
- pixAcc1 += *p++;
- pixAcc2 += *p++;
- }
- p += 3 * (w - m);
- }
- pixMul = (SplashCoord)1 / (SplashCoord)(n * m);
+ for (i = 0; i < yStep; ++i) {
+ destPtr = destPtr0 + (i * scaledWidth + x) * nComps;
+ *destPtr++ = (Guchar)pix[2];
+ *destPtr++ = (Guchar)pix[1];
+ *destPtr++ = (Guchar)pix[0];
+ }
+ break;
+#if SPLASH_CMYK
+ case splashModeCMYK8:
+ for (i = 0; i < yStep; ++i) {
+ destPtr = destPtr0 + (i * scaledWidth + x) * nComps;
+ *destPtr++ = (Guchar)pix[0];
+ *destPtr++ = (Guchar)pix[1];
+ *destPtr++ = (Guchar)pix[2];
+ *destPtr++ = (Guchar)pix[3];
+ }
+ break;
+#endif
+ }
- pix[0] = (int)((SplashCoord)pixAcc0 * pixMul);
- pix[1] = (int)((SplashCoord)pixAcc1 * pixMul);
- pix[2] = (int)((SplashCoord)pixAcc2 * pixMul);
+ // process alpha
+ if (srcAlpha) {
+ alpha = 0;
+ for (i = 0; i < xStep; ++i, ++xxa) {
+ alpha += alphaLineBuf[xxa];
+ }
+ // alpha / xStep
+ alpha = (alpha * d) >> 23;
+ for (i = 0; i < yStep; ++i) {
+ destAlphaPtr = destAlphaPtr0 + i * scaledWidth + x;
+ *destAlphaPtr = (Guchar)alpha;
+ }
+ }
+ }
- // set pixel
- if (vectorAntialias && clipRes != splashClipAllInside) {
- pipe.shape = (SplashCoord)1;
- drawAAPixel(&pipe, tx + x2, ty + y2);
- } else {
- drawPixel(&pipe, tx + x2, ty + y2,
- clipRes2 == splashClipAllInside);
- }
+ destPtr0 += yStep * scaledWidth * nComps;
+ if (srcAlpha) {
+ destAlphaPtr0 += yStep * scaledWidth;
+ }
+ }
- // x scale Bresenham
- xSrc += xStep;
+ gfree(alphaLineBuf);
+ gfree(lineBuf);
+}
- // x shear
- x1 += xSign;
+void Splash::scaleImageYuXu(SplashImageSource src, void *srcData,
+ SplashColorMode srcMode, int nComps,
+ GBool srcAlpha, int srcWidth, int srcHeight,
+ int scaledWidth, int scaledHeight,
+ SplashBitmap *dest) {
+ Guchar *lineBuf, *alphaLineBuf;
+ Guint pix[splashMaxColorComps];
+ Guint alpha;
+ Guchar *destPtr0, *destPtr, *destAlphaPtr0, *destAlphaPtr;
+ int yp, yq, xp, xq, yt, y, yStep, xt, x, xStep, xx;
+ int i, j;
+
+ // Bresenham parameters for y scale
+ yp = scaledHeight / srcHeight;
+ yq = scaledHeight % srcHeight;
+
+ // Bresenham parameters for x scale
+ xp = scaledWidth / srcWidth;
+ xq = scaledWidth % srcWidth;
+
+ // allocate buffers
+ lineBuf = (Guchar *)gmallocn(srcWidth, nComps);
+ if (srcAlpha) {
+ alphaLineBuf = (Guchar *)gmalloc(srcWidth);
+ } else {
+ alphaLineBuf = NULL;
+ }
- // y shear
- y1 += yShear1;
- }
- break;
+ // init y scale Bresenham
+ yt = 0;
- case splashModeXBGR8:
- for (x = 0; x < scaledWidth; ++x) {
-
- // x scale Bresenham
- xStep = xp;
- xt += xq;
- if (xt >= scaledWidth) {
- xt -= scaledWidth;
- ++xStep;
- }
+ destPtr0 = dest->data;
+ destAlphaPtr0 = dest->alpha;
+ for (y = 0; y < srcHeight; ++y) {
- // rotation
- if (rot) {
- x2 = (int)y1;
- y2 = -x1;
- } else {
- x2 = x1;
- y2 = (int)y1;
- }
+ // y scale Bresenham
+ if ((yt += yq) >= srcHeight) {
+ yt -= srcHeight;
+ yStep = yp + 1;
+ } else {
+ yStep = yp;
+ }
- // compute the filtered pixel at (x,y) after the x and y scaling
- // operations
- m = xStep > 0 ? xStep : 1;
- p = colorBuf + xSrc * 4;
- pixAcc0 = pixAcc1 = pixAcc2 = 0;
- for (i = 0; i < n; ++i) {
- for (j = 0; j < m; ++j) {
- pixAcc0 += *p++;
- pixAcc1 += *p++;
- pixAcc2 += *p++;
- p++;
- }
- p += 4 * (w - m);
- }
- pixMul = (SplashCoord)1 / (SplashCoord)(n * m);
+ // read row from image
+ (*src)(srcData, lineBuf, alphaLineBuf);
- pix[0] = (int)((SplashCoord)pixAcc0 * pixMul);
- pix[1] = (int)((SplashCoord)pixAcc1 * pixMul);
- pix[2] = (int)((SplashCoord)pixAcc2 * pixMul);
- pix[3] = 255;
+ // init x scale Bresenham
+ xt = 0;
- // set pixel
- if (vectorAntialias && clipRes != splashClipAllInside) {
- pipe.shape = (SplashCoord)1;
- drawAAPixel(&pipe, tx + x2, ty + y2);
- } else {
- drawPixel(&pipe, tx + x2, ty + y2,
- clipRes2 == splashClipAllInside);
- }
+ xx = 0;
+ for (x = 0; x < srcWidth; ++x) {
- // x scale Bresenham
- xSrc += xStep;
+ // x scale Bresenham
+ if ((xt += xq) >= srcWidth) {
+ xt -= srcWidth;
+ xStep = xp + 1;
+ } else {
+ xStep = xp;
+ }
- // x shear
- x1 += xSign;
+ // compute the final pixel
+ for (i = 0; i < nComps; ++i) {
+ pix[i] = lineBuf[x * nComps + i];
+ }
- // y shear
- y1 += yShear1;
+ // store the pixel
+ switch (srcMode) {
+ case splashModeMono1: // mono1 is not allowed
+ break;
+ case splashModeMono8:
+ for (i = 0; i < yStep; ++i) {
+ for (j = 0; j < xStep; ++j) {
+ destPtr = destPtr0 + (i * scaledWidth + xx + j) * nComps;
+ *destPtr++ = (Guchar)pix[0];
+ }
+ }
+ break;
+ case splashModeRGB8:
+ for (i = 0; i < yStep; ++i) {
+ for (j = 0; j < xStep; ++j) {
+ destPtr = destPtr0 + (i * scaledWidth + xx + j) * nComps;
+ *destPtr++ = (Guchar)pix[0];
+ *destPtr++ = (Guchar)pix[1];
+ *destPtr++ = (Guchar)pix[2];
+ }
+ }
+ break;
+ case splashModeXBGR8:
+ for (i = 0; i < yStep; ++i) {
+ for (j = 0; j < xStep; ++j) {
+ destPtr = destPtr0 + (i * scaledWidth + xx + j) * nComps;
+ *destPtr++ = (Guchar)pix[2];
+ *destPtr++ = (Guchar)pix[1];
+ *destPtr++ = (Guchar)pix[0];
+ *destPtr++ = (Guchar)255;
+ }
+ }
+ break;
+ case splashModeBGR8:
+ for (i = 0; i < yStep; ++i) {
+ for (j = 0; j < xStep; ++j) {
+ destPtr = destPtr0 + (i * scaledWidth + xx + j) * nComps;
+ *destPtr++ = (Guchar)pix[2];
+ *destPtr++ = (Guchar)pix[1];
+ *destPtr++ = (Guchar)pix[0];
+ }
}
break;
-
#if SPLASH_CMYK
case splashModeCMYK8:
- for (x = 0; x < scaledWidth; ++x) {
-
- // x scale Bresenham
- xStep = xp;
- xt += xq;
- if (xt >= scaledWidth) {
- xt -= scaledWidth;
- ++xStep;
+ for (i = 0; i < yStep; ++i) {
+ for (j = 0; j < xStep; ++j) {
+ destPtr = destPtr0 + (i * scaledWidth + xx + j) * nComps;
+ *destPtr++ = (Guchar)pix[0];
+ *destPtr++ = (Guchar)pix[1];
+ *destPtr++ = (Guchar)pix[2];
+ *destPtr++ = (Guchar)pix[3];
}
+ }
+ break;
+#endif
+ }
- // rotation
- if (rot) {
- x2 = (int)y1;
- y2 = -x1;
- } else {
- x2 = x1;
- y2 = (int)y1;
+ // process alpha
+ if (srcAlpha) {
+ alpha = alphaLineBuf[x];
+ for (i = 0; i < yStep; ++i) {
+ for (j = 0; j < xStep; ++j) {
+ destAlphaPtr = destAlphaPtr0 + i * scaledWidth + xx + j;
+ *destAlphaPtr = (Guchar)alpha;
}
+ }
+ }
- // compute the filtered pixel at (x,y) after the x and y scaling
- // operations
- m = xStep > 0 ? xStep : 1;
- p = colorBuf + xSrc * 4;
- pixAcc0 = pixAcc1 = pixAcc2 = pixAcc3 = 0;
- for (i = 0; i < n; ++i) {
- for (j = 0; j < m; ++j) {
- pixAcc0 += *p++;
- pixAcc1 += *p++;
- pixAcc2 += *p++;
- pixAcc3 += *p++;
- }
- p += 4 * (w - m);
- }
- pixMul = (SplashCoord)1 / (SplashCoord)(n * m);
+ xx += xStep;
+ }
- pix[0] = (int)((SplashCoord)pixAcc0 * pixMul);
- pix[1] = (int)((SplashCoord)pixAcc1 * pixMul);
- pix[2] = (int)((SplashCoord)pixAcc2 * pixMul);
- pix[3] = (int)((SplashCoord)pixAcc3 * pixMul);
+ destPtr0 += yStep * scaledWidth * nComps;
+ if (srcAlpha) {
+ destAlphaPtr0 += yStep * scaledWidth;
+ }
+ }
- // set pixel
- if (vectorAntialias && clipRes != splashClipAllInside) {
- pipe.shape = (SplashCoord)1;
- drawAAPixel(&pipe, tx + x2, ty + y2);
- } else {
- drawPixel(&pipe, tx + x2, ty + y2,
- clipRes2 == splashClipAllInside);
- }
+ gfree(alphaLineBuf);
+ gfree(lineBuf);
+}
+
+void Splash::vertFlipImage(SplashBitmap *img, int width, int height,
+ int nComps) {
+ Guchar *lineBuf;
+ Guchar *p0, *p1;
+ int w;
+
+ w = width * nComps;
+ lineBuf = (Guchar *)gmalloc(w);
+ for (p0 = img->data, p1 = img->data + (height - 1) * w;
+ p0 < p1;
+ p0 += w, p1 -= w) {
+ memcpy(lineBuf, p0, w);
+ memcpy(p0, p1, w);
+ memcpy(p1, lineBuf, w);
+ }
+ if (img->alpha) {
+ for (p0 = img->alpha, p1 = img->alpha + (height - 1) * width;
+ p0 < p1;
+ p0 += width, p1 -= width) {
+ memcpy(lineBuf, p0, width);
+ memcpy(p0, p1, width);
+ memcpy(p1, lineBuf, width);
+ }
+ }
+ gfree(lineBuf);
+}
- // x scale Bresenham
- xSrc += xStep;
+void Splash::blitImage(SplashBitmap *src, GBool srcAlpha, int xDest, int yDest,
+ SplashClipResult clipRes) {
+ SplashPipe pipe;
+ SplashColor pixel;
+ Guchar *ap;
+ int w, h, x0, y0, x1, y1, x, y;
- // x shear
- x1 += xSign;
+ // split the image into clipped and unclipped regions
+ w = src->getWidth();
+ h = src->getHeight();
+ if (clipRes == splashClipAllInside) {
+ x0 = 0;
+ y0 = 0;
+ x1 = w;
+ y1 = h;
+ } else {
+ if (state->clip->getNumPaths()) {
+ x0 = x1 = w;
+ y0 = y1 = h;
+ } else {
+ if ((x0 = splashCeil(state->clip->getXMin()) - xDest) < 0) {
+ x0 = 0;
+ }
+ if ((y0 = splashCeil(state->clip->getYMin()) - yDest) < 0) {
+ y0 = 0;
+ }
+ if ((x1 = splashFloor(state->clip->getXMax()) - xDest) > w) {
+ x1 = w;
+ }
+ if (x1 < x0) {
+ x1 = x0;
+ }
+ if ((y1 = splashFloor(state->clip->getYMax()) - yDest) > h) {
+ y1 = h;
+ }
+ if (y1 < y0) {
+ y1 = y0;
+ }
+ }
+ }
- // y shear
- y1 += yShear1;
+ // draw the unclipped region
+ if (x0 < w && y0 < h && x0 < x1 && y0 < y1) {
+ pipeInit(&pipe, xDest + x0, yDest + y0, NULL, pixel,
+ (Guchar)splashRound(state->fillAlpha * 255), srcAlpha, gFalse);
+ if (srcAlpha) {
+ for (y = y0; y < y1; ++y) {
+ pipeSetXY(&pipe, xDest + x0, yDest + y);
+ ap = src->getAlphaPtr() + y * w + x0;
+ for (x = x0; x < x1; ++x) {
+ src->getPixel(x, y, pixel);
+ pipe.shape = *ap++;
+ (this->*pipe.run)(&pipe);
+ }
+ }
+ } else {
+ for (y = y0; y < y1; ++y) {
+ pipeSetXY(&pipe, xDest + x0, yDest + y);
+ for (x = x0; x < x1; ++x) {
+ src->getPixel(x, y, pixel);
+ (this->*pipe.run)(&pipe);
}
- break;
-#endif // SPLASH_CMYK
}
}
+ updateModX(xDest + x0);
+ updateModX(xDest + x1 - 1);
+ updateModY(yDest + y0);
+ updateModY(yDest + y1 - 1);
+ }
+ // draw the clipped regions
+ if (y0 > 0) {
+ blitImageClipped(src, srcAlpha, 0, 0, xDest, yDest, w, y0);
}
+ if (y1 < h) {
+ blitImageClipped(src, srcAlpha, 0, y1, xDest, yDest + y1, w, h - y1);
+ }
+ if (x0 > 0 && y0 < y1) {
+ blitImageClipped(src, srcAlpha, 0, y0, xDest, yDest + y0, x0, y1 - y0);
+ }
+ if (x1 < w && y0 < y1) {
+ blitImageClipped(src, srcAlpha, x1, y0, xDest + x1, yDest + y0,
+ w - x1, y1 - y0);
+ }
+}
- gfree(colorBuf);
- gfree(alphaBuf);
+void Splash::blitImageClipped(SplashBitmap *src, GBool srcAlpha,
+ int xSrc, int ySrc, int xDest, int yDest,
+ int w, int h) {
+ SplashPipe pipe;
+ SplashColor pixel;
+ Guchar *ap;
+ int x, y;
- return splashOk;
+ if (vectorAntialias) {
+ pipeInit(&pipe, xDest, yDest, NULL, pixel,
+ (Guchar)splashRound(state->fillAlpha * 255), gTrue, gFalse);
+ drawAAPixelInit();
+ if (srcAlpha) {
+ for (y = 0; y < h; ++y) {
+ ap = src->getAlphaPtr() + (ySrc + y) * src->getWidth() + xSrc;
+ for (x = 0; x < w; ++x) {
+ src->getPixel(xSrc + x, ySrc + y, pixel);
+ pipe.shape = *ap++;
+ drawAAPixel(&pipe, xDest + x, yDest + y);
+ }
+ }
+ } else {
+ for (y = 0; y < h; ++y) {
+ for (x = 0; x < w; ++x) {
+ src->getPixel(xSrc + x, ySrc + y, pixel);
+ pipe.shape = 255;
+ drawAAPixel(&pipe, xDest + x, yDest + y);
+ }
+ }
+ }
+ } else {
+ pipeInit(&pipe, xDest, yDest, NULL, pixel,
+ (Guchar)splashRound(state->fillAlpha * 255), srcAlpha, gFalse);
+ if (srcAlpha) {
+ for (y = 0; y < h; ++y) {
+ ap = src->getAlphaPtr() + (ySrc + y) * src->getWidth() + xSrc;
+ pipeSetXY(&pipe, xDest, yDest + y);
+ for (x = 0; x < w; ++x) {
+ if (state->clip->test(xDest + x, yDest + y)) {
+ src->getPixel(xSrc + x, ySrc + y, pixel);
+ pipe.shape = *ap++;
+ (this->*pipe.run)(&pipe);
+ updateModX(xDest + x);
+ updateModY(yDest + y);
+ } else {
+ pipeIncX(&pipe);
+ ++ap;
+ }
+ }
+ }
+ } else {
+ for (y = 0; y < h; ++y) {
+ pipeSetXY(&pipe, xDest, yDest + y);
+ for (x = 0; x < w; ++x) {
+ if (state->clip->test(xDest + x, yDest + y)) {
+ src->getPixel(xSrc + x, ySrc + y, pixel);
+ (this->*pipe.run)(&pipe);
+ updateModX(xDest + x);
+ updateModY(yDest + y);
+ } else {
+ pipeIncX(&pipe);
+ }
+ }
+ }
+ }
+ }
}
SplashError Splash::composite(SplashBitmap *src, int xSrc, int ySrc,
@@ -3091,39 +4629,72 @@ SplashError Splash::composite(SplashBitmap *src, int xSrc, int ySrc,
}
if (src->alpha) {
- pipeInit(&pipe, xDest, yDest, NULL, pixel, state->fillAlpha,
- gTrue, nonIsolated);
- for (y = 0; y < h; ++y) {
- pipeSetXY(&pipe, xDest, yDest + y);
- ap = src->getAlphaPtr() + (ySrc + y) * src->getWidth() + xSrc;
- for (x = 0; x < w; ++x) {
- alpha = *ap++;
- if (noClip || state->clip->test(xDest + x, yDest + y)) {
+ pipeInit(&pipe, xDest, yDest, NULL, pixel,
+ (Guchar)splashRound(state->fillAlpha * 255), gTrue, nonIsolated);
+ if (noClip) {
+ for (y = 0; y < h; ++y) {
+ pipeSetXY(&pipe, xDest, yDest + y);
+ ap = src->getAlphaPtr() + (ySrc + y) * src->getWidth() + xSrc;
+ for (x = 0; x < w; ++x) {
+ src->getPixel(xSrc + x, ySrc + y, pixel);
+ alpha = *ap++;
// this uses shape instead of alpha, which isn't technically
// correct, but works out the same
+ pipe.shape = alpha;
+ (this->*pipe.run)(&pipe);
+ }
+ }
+ updateModX(xDest);
+ updateModX(xDest + w - 1);
+ updateModY(yDest);
+ updateModY(yDest + h - 1);
+ } else {
+ for (y = 0; y < h; ++y) {
+ pipeSetXY(&pipe, xDest, yDest + y);
+ ap = src->getAlphaPtr() + (ySrc + y) * src->getWidth() + xSrc;
+ for (x = 0; x < w; ++x) {
src->getPixel(xSrc + x, ySrc + y, pixel);
- pipe.shape = (SplashCoord)(alpha / 255.0);
- pipeRun(&pipe);
- updateModX(xDest + x);
- updateModY(yDest + y);
- } else {
- pipeIncX(&pipe);
+ alpha = *ap++;
+ if (state->clip->test(xDest + x, yDest + y)) {
+ // this uses shape instead of alpha, which isn't technically
+ // correct, but works out the same
+ pipe.shape = alpha;
+ (this->*pipe.run)(&pipe);
+ updateModX(xDest + x);
+ updateModY(yDest + y);
+ } else {
+ pipeIncX(&pipe);
+ }
}
}
}
} else {
- pipeInit(&pipe, xDest, yDest, NULL, pixel, state->fillAlpha,
- 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)) {
+ pipeInit(&pipe, xDest, yDest, NULL, pixel,
+ (Guchar)splashRound(state->fillAlpha * 255), gFalse, nonIsolated);
+ if (noClip) {
+ for (y = 0; y < h; ++y) {
+ pipeSetXY(&pipe, xDest, yDest + y);
+ for (x = 0; x < w; ++x) {
src->getPixel(xSrc + x, ySrc + y, pixel);
- pipeRun(&pipe);
- updateModX(xDest + x);
- updateModY(yDest + y);
- } else {
- pipeIncX(&pipe);
+ (this->*pipe.run)(&pipe);
+ }
+ }
+ updateModX(xDest);
+ updateModX(xDest + w - 1);
+ updateModY(yDest);
+ updateModY(yDest + h - 1);
+ } else {
+ for (y = 0; y < h; ++y) {
+ pipeSetXY(&pipe, xDest, yDest + y);
+ for (x = 0; x < w; ++x) {
+ src->getPixel(xSrc + x, ySrc + y, pixel);
+ if (state->clip->test(xDest + x, yDest + y)) {
+ (this->*pipe.run)(&pipe);
+ updateModX(xDest + x);
+ updateModY(yDest + y);
+ } else {
+ pipeIncX(&pipe);
+ }
}
}
}
@@ -3142,7 +4713,7 @@ void Splash::compositeBackground(SplashColorPtr color) {
int x, y, mask;
if (unlikely(bitmap->alpha == NULL)) {
- error(-1, "bitmap->alpha is NULL in Splash::compositeBackground");
+ error(errInternal, -1, "bitmap->alpha is NULL in Splash::compositeBackground");
return;
}
@@ -3248,11 +4819,21 @@ void Splash::compositeBackground(SplashColorPtr color) {
q = &bitmap->alpha[y * bitmap->width];
for (x = 0; x < bitmap->width; ++x) {
alpha = *q++;
- alpha1 = 255 - alpha;
- p[0] = div255(alpha1 * color0 + alpha * p[0]);
- p[1] = div255(alpha1 * color1 + alpha * p[1]);
- p[2] = div255(alpha1 * color2 + alpha * p[2]);
- p[3] = div255(alpha1 * color3 + alpha * p[3]);
+ if (alpha == 0)
+ {
+ p[0] = color0;
+ p[1] = color1;
+ p[2] = color2;
+ p[3] = color3;
+ }
+ else if (alpha != 255)
+ {
+ alpha1 = 255 - alpha;
+ p[0] = div255(alpha1 * color0 + alpha * p[0]);
+ p[1] = div255(alpha1 * color1 + alpha * p[1]);
+ p[2] = div255(alpha1 * color2 + alpha * p[2]);
+ p[3] = div255(alpha1 * color3 + alpha * p[3]);
+ }
p += 4;
}
}
@@ -3322,7 +4903,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)
@@ -3577,7 +5158,7 @@ SplashError Splash::blitTransparent(SplashBitmap *src, int xSrc, int ySrc,
int xDest, int yDest, int w, int h) {
SplashColorPtr p, sp;
Guchar *q;
- int x, y, mask;
+ int x, y, mask, srcMask;
if (src->mode != bitmap->mode) {
return splashErrModeMismatch;
@@ -3587,10 +5168,11 @@ SplashError Splash::blitTransparent(SplashBitmap *src, int xSrc, int ySrc,
case splashModeMono1:
for (y = 0; y < h; ++y) {
p = &bitmap->data[(yDest + y) * bitmap->rowSize + (xDest >> 3)];
- sp = &src->data[(ySrc + y) * bitmap->rowSize + (xSrc >> 3)];
mask = 0x80 >> (xDest & 7);
+ sp = &src->data[(ySrc + y) * src->rowSize + (xSrc >> 3)];
+ srcMask = 0x80 >> (xSrc & 7);
for (x = 0; x < w; ++x) {
- if (sp[0] & (0x80 >> (x & 7))) {
+ if (*sp & srcMask) {
*p |= mask;
} else {
*p &= ~mask;
@@ -3598,6 +5180,9 @@ SplashError Splash::blitTransparent(SplashBitmap *src, int xSrc, int ySrc,
if (!(mask >>= 1)) {
mask = 0x80;
++p;
+ }
+ if (!(srcMask >>= 1)) {
+ srcMask = 0x80;
++sp;
}
}
@@ -3663,166 +5248,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) {
+ i0 = 0;
+ for (i1 = i0;
+ !(pathIn->flags[i1] & splashPathLast) &&
+ i1 + 1 < pathIn->length &&
+ pathIn->pts[i1+1].x == pathIn->pts[i1].x &&
+ pathIn->pts[i1+1].y == pathIn->pts[i1].y;
+ ++i1) ;
+
+ while (i1 < pathIn->length) {
+ if ((first = pathIn->flags[i0] & splashPathFirst)) {
+ subpathStart0 = i0;
+ subpathStart1 = i1;
+ seg = 0;
+ closed = pathIn->flags[i0] & splashPathClosed;
+ }
+ j0 = i1 + 1;
+ if (j0 < pathIn->length) {
+ for (j1 = j0;
+ !(pathIn->flags[j1] & splashPathLast) &&
+ j1 + 1 < pathIn->length &&
+ pathIn->pts[j1+1].x == pathIn->pts[j1].x &&
+ pathIn->pts[j1+1].y == pathIn->pts[j1].y;
+ ++j1) ;
+ } else {
+ j1 = j0;
+ }
+ if (pathIn->flags[i1] & splashPathLast) {
+ if (first && state->lineCap == splashLineCapRound) {
+ // special case: zero-length subpath with round line caps -->
+ // draw a circle
+ pathOut->moveTo(pathIn->pts[i0].x + (SplashCoord)0.5 * w,
+ pathIn->pts[i0].y);
+ pathOut->curveTo(pathIn->pts[i0].x + (SplashCoord)0.5 * w,
+ pathIn->pts[i0].y + bezierCircle2 * w,
+ pathIn->pts[i0].x + bezierCircle2 * w,
+ pathIn->pts[i0].y + (SplashCoord)0.5 * w,
+ pathIn->pts[i0].x,
+ pathIn->pts[i0].y + (SplashCoord)0.5 * w);
+ pathOut->curveTo(pathIn->pts[i0].x - bezierCircle2 * w,
+ pathIn->pts[i0].y + (SplashCoord)0.5 * w,
+ pathIn->pts[i0].x - (SplashCoord)0.5 * w,
+ pathIn->pts[i0].y + bezierCircle2 * w,
+ pathIn->pts[i0].x - (SplashCoord)0.5 * w,
+ pathIn->pts[i0].y);
+ pathOut->curveTo(pathIn->pts[i0].x - (SplashCoord)0.5 * w,
+ pathIn->pts[i0].y - bezierCircle2 * w,
+ pathIn->pts[i0].x - bezierCircle2 * w,
+ pathIn->pts[i0].y - (SplashCoord)0.5 * w,
+ pathIn->pts[i0].x,
+ pathIn->pts[i0].y - (SplashCoord)0.5 * w);
+ pathOut->curveTo(pathIn->pts[i0].x + bezierCircle2 * w,
+ pathIn->pts[i0].y - (SplashCoord)0.5 * w,
+ pathIn->pts[i0].x + (SplashCoord)0.5 * w,
+ pathIn->pts[i0].y - bezierCircle2 * w,
+ pathIn->pts[i0].x + (SplashCoord)0.5 * w,
+ pathIn->pts[i0].y);
+ pathOut->close();
+ }
+ i0 = j0;
+ i1 = j1;
continue;
}
- if ((first = pathIn->flags[i] & splashPathFirst)) {
- subpathStart = i;
- closed = pathIn->flags[i] & splashPathClosed;
- }
- 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;
+ 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 {
@@ -3836,67 +5501,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);
}
}
}
@@ -3906,8 +5572,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 {
@@ -3921,12 +5607,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);
@@ -3943,8 +5629,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) {
@@ -3971,13 +5670,9 @@ void Splash::dumpXPath(SplashXPath *path) {
int i;
for (i = 0; i < path->length; ++i) {
- printf(" %4d: x0=%8.2f y0=%8.2f x1=%8.2f y1=%8.2f %s%s%s%s%s%s%s\n",
+ printf(" %4d: x0=%8.2f y0=%8.2f x1=%8.2f y1=%8.2f %s%s%s\n",
i, (double)path->segs[i].x0, (double)path->segs[i].y0,
(double)path->segs[i].x1, (double)path->segs[i].y1,
- (path->segs[i].flags & splashXPathFirst) ? "F" : " ",
- (path->segs[i].flags & splashXPathLast) ? "L" : " ",
- (path->segs[i].flags & splashXPathEnd0) ? "0" : " ",
- (path->segs[i].flags & splashXPathEnd1) ? "1" : " ",
(path->segs[i].flags & splashXPathHoriz) ? "H" : " ",
(path->segs[i].flags & splashXPathVert) ? "V" : " ",
(path->segs[i].flags & splashXPathFlip) ? "P" : " ");
@@ -4003,7 +5698,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) {
@@ -4022,7 +5723,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..3c2bf9f1 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
@@ -206,7 +209,7 @@ public:
// The matrix behaves as for fillImageMask.
SplashError drawImage(SplashImageSource src, void *srcData,
SplashColorMode srcMode, GBool srcAlpha,
- int w, int h, SplashCoord *mat, SplashPattern *overprintPattern = NULL);
+ int w, int h, SplashCoord *mat);
// Composite a rectangular region from <src> onto this Splash
// object.
@@ -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,7 +316,68 @@ 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 arbitraryTransformMask(SplashImageMaskSource src, void *srcData,
+ int srcWidth, int srcHeight,
+ SplashCoord *mat, GBool glyphMode);
+ SplashBitmap *scaleMask(SplashImageMaskSource src, void *srcData,
+ int srcWidth, int srcHeight,
+ int scaledWidth, int scaledHeight);
+ void scaleMaskYdXd(SplashImageMaskSource src, void *srcData,
+ int srcWidth, int srcHeight,
+ int scaledWidth, int scaledHeight,
+ SplashBitmap *dest);
+ void scaleMaskYdXu(SplashImageMaskSource src, void *srcData,
+ int srcWidth, int srcHeight,
+ int scaledWidth, int scaledHeight,
+ SplashBitmap *dest);
+ void scaleMaskYuXd(SplashImageMaskSource src, void *srcData,
+ int srcWidth, int srcHeight,
+ int scaledWidth, int scaledHeight,
+ SplashBitmap *dest);
+ void scaleMaskYuXu(SplashImageMaskSource src, void *srcData,
+ int srcWidth, int srcHeight,
+ int scaledWidth, int scaledHeight,
+ SplashBitmap *dest);
+ void blitMask(SplashBitmap *src, int xDest, int yDest,
+ SplashClipResult clipRes);
+ SplashError arbitraryTransformImage(SplashImageSource src, void *srcData,
+ SplashColorMode srcMode, int nComps,
+ GBool srcAlpha,
+ int srcWidth, int srcHeight,
+ SplashCoord *mat);
+ SplashBitmap *scaleImage(SplashImageSource src, void *srcData,
+ SplashColorMode srcMode, int nComps,
+ GBool srcAlpha, int srcWidth, int srcHeight,
+ int scaledWidth, int scaledHeight);
+ void scaleImageYdXd(SplashImageSource src, void *srcData,
+ SplashColorMode srcMode, int nComps,
+ GBool srcAlpha, int srcWidth, int srcHeight,
+ int scaledWidth, int scaledHeight,
+ SplashBitmap *dest);
+ void scaleImageYdXu(SplashImageSource src, void *srcData,
+ SplashColorMode srcMode, int nComps,
+ GBool srcAlpha, int srcWidth, int srcHeight,
+ int scaledWidth, int scaledHeight,
+ SplashBitmap *dest);
+ void scaleImageYuXd(SplashImageSource src, void *srcData,
+ SplashColorMode srcMode, int nComps,
+ GBool srcAlpha, int srcWidth, int srcHeight,
+ int scaledWidth, int scaledHeight,
+ SplashBitmap *dest);
+ void scaleImageYuXu(SplashImageSource src, void *srcData,
+ SplashColorMode srcMode, int nComps,
+ GBool srcAlpha, int srcWidth, int srcHeight,
+ int scaledWidth, int scaledHeight,
+ SplashBitmap *dest);
+ void vertFlipImage(SplashBitmap *img, int width, int height,
+ int nComps);
+ void blitImage(SplashBitmap *src, GBool srcAlpha, int xDest, int yDest,
+ SplashClipResult clipRes);
+ void blitImageClipped(SplashBitmap *src, GBool srcAlpha,
+ int xSrc, int ySrc, int xDest, int yDest,
+ int w, int h);
void dumpPath(SplashPath *path);
void dumpXPath(SplashXPath *path);
@@ -308,9 +394,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/SplashBitmap.cc b/splash/SplashBitmap.cc
index 562fbdad..ab5176e5 100644
--- a/splash/SplashBitmap.cc
+++ b/splash/SplashBitmap.cc
@@ -111,12 +111,13 @@ SplashBitmap::SplashBitmap(int widthA, int heightA, int rowPadA,
}
}
-
SplashBitmap::~SplashBitmap() {
- if (rowSize < 0) {
- gfree(data + (height - 1) * rowSize);
- } else {
- gfree(data);
+ if (data) {
+ if (rowSize < 0) {
+ gfree(data + (height - 1) * rowSize);
+ } else {
+ gfree(data);
+ }
}
gfree(alpha);
}
@@ -160,11 +161,7 @@ SplashError SplashBitmap::writePNMFile(FILE *f) {
fprintf(f, "P5\n%d %d\n255\n", width, height);
row = data;
for (y = 0; y < height; ++y) {
- p = row;
- for (x = 0; x < width; ++x) {
- fputc(*p, f);
- ++p;
- }
+ fwrite(row, 1, width, f);
row += rowSize;
}
break;
@@ -173,13 +170,7 @@ SplashError SplashBitmap::writePNMFile(FILE *f) {
fprintf(f, "P6\n%d %d\n255\n", width, height);
row = data;
for (y = 0; y < height; ++y) {
- p = row;
- for (x = 0; x < width; ++x) {
- fputc(splashRGB8R(p), f);
- fputc(splashRGB8G(p), f);
- fputc(splashRGB8B(p), f);
- p += 3;
- }
+ fwrite(row, 1, 3 * width, f);
row += rowSize;
}
break;
@@ -218,7 +209,7 @@ SplashError SplashBitmap::writePNMFile(FILE *f) {
#if SPLASH_CMYK
case splashModeCMYK8:
// PNM doesn't support CMYK
- error(-1, "unsupported SplashBitmap mode");
+ error(errInternal, -1, "unsupported SplashBitmap mode");
return splashErrGeneric;
break;
#endif
@@ -226,6 +217,20 @@ SplashError SplashBitmap::writePNMFile(FILE *f) {
return splashOk;
}
+SplashError SplashBitmap::writeAlphaPGMFile(char *fileName) {
+ FILE *f;
+
+ if (!alpha) {
+ return splashErrModeMismatch;
+ }
+ if (!(f = fopen(fileName, "wb"))) {
+ return splashErrOpenFile;
+ }
+ fprintf(f, "P5\n%d %d\n255\n", width, height);
+ fwrite(alpha, 1, width * height, f);
+ fclose(f);
+ return splashOk;
+}
void SplashBitmap::getPixel(int x, int y, SplashColorPtr pixel) {
SplashColorPtr p;
@@ -277,6 +282,14 @@ Guchar SplashBitmap::getAlpha(int x, int y) {
return alpha[y * width + x];
}
+SplashColorPtr SplashBitmap::takeData() {
+ SplashColorPtr data2;
+
+ data2 = data;
+ data = NULL;
+ return data2;
+}
+
SplashError SplashBitmap::writeImgFile(SplashImageFileFormat format, char *fileName, int hDPI, int vDPI, const char *compressionString) {
FILE *f;
SplashError e;
@@ -326,7 +339,7 @@ SplashError SplashBitmap::writeImgFile(SplashImageFileFormat format, FILE *f, in
default:
// Not the greatest error message, but users of this function should
// have already checked whether their desired format is compiled in.
- error(-1, "Support for this image type not compiled in");
+ error(errInternal, -1, "Support for this image type not compiled in");
return splashErrGeneric;
}
@@ -364,7 +377,7 @@ SplashError SplashBitmap::writeImgFile(ImgWriter *writer, FILE *f, int hDPI, int
&& mode != splashModeCMYK8
#endif
) {
- error(-1, "unsupported SplashBitmap mode");
+ error(errInternal, -1, "unsupported SplashBitmap mode");
return splashErrGeneric;
}
diff --git a/splash/SplashBitmap.h b/splash/SplashBitmap.h
index 33365074..8bcc9418 100644
--- a/splash/SplashBitmap.h
+++ b/splash/SplashBitmap.h
@@ -65,6 +65,7 @@ public:
SplashError writePNMFile(char *fileName);
SplashError writePNMFile(FILE *f);
+ SplashError writeAlphaPGMFile(char *fileName);
SplashError writeImgFile(SplashImageFileFormat format, char *fileName, int hDPI, int vDPI, const char *compressionString = "");
SplashError writeImgFile(SplashImageFileFormat format, FILE *f, int hDPI, int vDPI, const char *compressionString = "");
@@ -74,6 +75,11 @@ public:
void getRGBLine(int y, SplashColorPtr line);
Guchar getAlpha(int x, int y);
+ // Caller takes ownership of the bitmap data. The SplashBitmap
+ // object is no longer valid -- the next call should be to the
+ // destructor.
+ SplashColorPtr takeData();
+
private:
int width, height; // size of bitmap
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/SplashClip.h b/splash/SplashClip.h
index 7933017f..3eb2d780 100644
--- a/splash/SplashClip.h
+++ b/splash/SplashClip.h
@@ -118,6 +118,12 @@ public:
// will update <x0> and <x1>.
void clipAALine(SplashBitmap *aaBuf, int *x0, int *x1, int y);
+ // Get the rectangle part of the clip region.
+ SplashCoord getXMin() { return xMin; }
+ SplashCoord getXMax() { return xMax; }
+ SplashCoord getYMin() { return yMin; }
+ SplashCoord getYMax() { return yMax; }
+
// Get the rectangle part of the clip region, in integer coordinates.
int getXMinI() { return xMinI; }
int getXMaxI() { return xMaxI; }
diff --git a/splash/SplashFTFont.cc b/splash/SplashFTFont.cc
index eea3d641..b511c96c 100644
--- a/splash/SplashFTFont.cc
+++ b/splash/SplashFTFont.cc
@@ -58,31 +58,89 @@ static int glyphPathCubicTo(const FT_Vector *ctrl1, const FT_Vector *ctrl2,
SplashFTFont::SplashFTFont(SplashFTFontFile *fontFileA, SplashCoord *matA,
SplashCoord *textMatA):
SplashFont(fontFileA, matA, textMatA, fontFileA->engine->aa),
+ enableAutoHinting(fontFileA->engine->enableAutoHinting),
enableFreeTypeHinting(fontFileA->engine->enableFreeTypeHinting),
enableSlightHinting(fontFileA->engine->enableSlightHinting)
{
FT_Face face;
- double div;
+ int div;
int x, y;
+#if USE_FIXEDPOINT
+ SplashCoord scale;
+#endif
face = fontFileA->face;
if (FT_New_Size(face, &sizeObj)) {
return;
}
face->size = sizeObj;
- size = splashSqrt(mat[2]*mat[2] + mat[3]*mat[3]);
- if ((int)size < 1) {
+ size = splashRound(splashDist(0, 0, mat[2], mat[3]));
+ if (size < 1) {
size = 1;
}
- if (FT_Set_Pixel_Sizes(face, 0, (int)size)) {
+ if (FT_Set_Pixel_Sizes(face, 0, size)) {
return;
}
// if the textMat values are too small, FreeType's fixed point
// arithmetic doesn't work so well
- textScale = splashSqrt(textMat[2]*textMat[2] + textMat[3]*textMat[3]) / size;
+ textScale = splashDist(0, 0, textMat[2], textMat[3]) / size;
div = face->bbox.xMax > 20000 ? 65536 : 1;
+#if USE_FIXEDPOINT
+ scale = (SplashCoord)1 / (SplashCoord)face->units_per_EM;
+
+ // transform the four corners of the font bounding box -- the min
+ // and max values form the bounding box of the transformed font
+ x = (int)(mat[0] * (scale * (face->bbox.xMin / div)) +
+ mat[2] * (scale * (face->bbox.yMin / div)));
+ xMin = xMax = x;
+ y = (int)(mat[1] * (scale * (face->bbox.xMin / div)) +
+ mat[3] * (scale * (face->bbox.yMin / div)));
+ yMin = yMax = y;
+ x = (int)(mat[0] * (scale * (face->bbox.xMin / div)) +
+ mat[2] * (scale * (face->bbox.yMax / div)));
+ if (x < xMin) {
+ xMin = x;
+ } else if (x > xMax) {
+ xMax = x;
+ }
+ y = (int)(mat[1] * (scale * (face->bbox.xMin / div)) +
+ mat[3] * (scale * (face->bbox.yMax / div)));
+ if (y < yMin) {
+ yMin = y;
+ } else if (y > yMax) {
+ yMax = y;
+ }
+ x = (int)(mat[0] * (scale * (face->bbox.xMax / div)) +
+ mat[2] * (scale * (face->bbox.yMin / div)));
+ if (x < xMin) {
+ xMin = x;
+ } else if (x > xMax) {
+ xMax = x;
+ }
+ y = (int)(mat[1] * (scale * (face->bbox.xMax / div)) +
+ mat[3] * (scale * (face->bbox.yMin / div)));
+ if (y < yMin) {
+ yMin = y;
+ } else if (y > yMax) {
+ yMax = y;
+ }
+ x = (int)(mat[0] * (scale * (face->bbox.xMax / div)) +
+ mat[2] * (scale * (face->bbox.yMax / div)));
+ if (x < xMin) {
+ xMin = x;
+ } else if (x > xMax) {
+ xMax = x;
+ }
+ y = (int)(mat[1] * (scale * (face->bbox.xMax / div)) +
+ mat[3] * (scale * (face->bbox.yMax / div)));
+ if (y < yMin) {
+ yMin = y;
+ } else if (y > yMax) {
+ yMax = y;
+ }
+#else // USE_FIXEDPOINT
// transform the four corners of the font bounding box -- the min
// and max values form the bounding box of the transformed font
x = (int)((mat[0] * face->bbox.xMin + mat[2] * face->bbox.yMin) /
@@ -133,11 +191,12 @@ SplashFTFont::SplashFTFont(SplashFTFontFile *fontFileA, SplashCoord *matA,
} else if (y > yMax) {
yMax = y;
}
+#endif // USE_FIXEDPOINT
// This is a kludge: some buggy PDF generators embed fonts with
// zero bounding boxes.
if (xMax == xMin) {
xMin = 0;
- xMax = (int)size;
+ xMax = size;
}
if (yMax == yMin) {
yMin = 0;
@@ -146,23 +205,23 @@ SplashFTFont::SplashFTFont(SplashFTFontFile *fontFileA, SplashCoord *matA,
// compute the transform matrix
#if USE_FIXEDPOINT
- matrix.xx = (FT_Fixed)((mat[0] / size).getRaw());
- matrix.yx = (FT_Fixed)((mat[1] / size).getRaw());
- matrix.xy = (FT_Fixed)((mat[2] / size).getRaw());
- matrix.yy = (FT_Fixed)((mat[3] / size).getRaw());
- textMatrix.xx = (FT_Fixed)((textMat[0] / (textScale * size)).getRaw());
- textMatrix.yx = (FT_Fixed)((textMat[1] / (textScale * size)).getRaw());
- textMatrix.xy = (FT_Fixed)((textMat[2] / (textScale * size)).getRaw());
- textMatrix.yy = (FT_Fixed)((textMat[3] / (textScale * size)).getRaw());
+ matrix.xx = (FT_Fixed)((mat[0] / size).get16Dot16());
+ matrix.yx = (FT_Fixed)((mat[1] / size).get16Dot16());
+ matrix.xy = (FT_Fixed)((mat[2] / size).get16Dot16());
+ matrix.yy = (FT_Fixed)((mat[3] / size).get16Dot16());
+ textMatrix.xx = (FT_Fixed)((textMat[0] / (textScale * size)).get16Dot16());
+ textMatrix.yx = (FT_Fixed)((textMat[1] / (textScale * size)).get16Dot16());
+ textMatrix.xy = (FT_Fixed)((textMat[2] / (textScale * size)).get16Dot16());
+ textMatrix.yy = (FT_Fixed)((textMat[3] / (textScale * size)).get16Dot16());
#else
matrix.xx = (FT_Fixed)((mat[0] / size) * 65536);
matrix.yx = (FT_Fixed)((mat[1] / size) * 65536);
matrix.xy = (FT_Fixed)((mat[2] / size) * 65536);
matrix.yy = (FT_Fixed)((mat[3] / size) * 65536);
- textMatrix.xx = (FT_Fixed)((textMat[0] / (size * textScale)) * 65536);
- textMatrix.yx = (FT_Fixed)((textMat[1] / (size * textScale)) * 65536);
- textMatrix.xy = (FT_Fixed)((textMat[2] / (size * textScale)) * 65536);
- textMatrix.yy = (FT_Fixed)((textMat[3] / (size * textScale)) * 65536);
+ textMatrix.xx = (FT_Fixed)((textMat[0] / (textScale * size)) * 65536);
+ textMatrix.yx = (FT_Fixed)((textMat[1] / (textScale * size)) * 65536);
+ textMatrix.xy = (FT_Fixed)((textMat[2] / (textScale * size)) * 65536);
+ textMatrix.yy = (FT_Fixed)((textMat[3] / (textScale * size)) * 65536);
#endif
}
@@ -174,13 +233,28 @@ GBool SplashFTFont::getGlyph(int c, int xFrac, int yFrac,
return SplashFont::getGlyph(c, xFrac, 0, bitmap, x0, y0, clip, clipRes);
}
-static FT_Int32 getFTLoadFlags(GBool aa, GBool enableFreeTypeHinting, GBool enableSlightHinting)
+static FT_Int32 getFTLoadFlags(GBool type1, GBool trueType, GBool aa,
+ GBool enableAutoHinting, GBool enableFreeTypeHinting, GBool enableSlightHinting)
{
int ret = FT_LOAD_DEFAULT;
if (aa)
ret |= FT_LOAD_NO_BITMAP;
- if (enableFreeTypeHinting) {
+ if (enableAutoHinting) {
+ if (trueType) {
+ // FT2's autohinting doesn't always work very well (especially with
+ // font subsets), so turn it off if anti-aliasing is enabled; if
+ // anti-aliasing is disabled, this seems to be a tossup - some fonts
+ // look better with hinting, some without, so leave hinting on
+ if (aa) {
+ ret |= FT_LOAD_NO_AUTOHINT;
+ }
+ } else if (type1) {
+ // Type 1 fonts seem to look better with 'light' hinting mode
+ ret |= FT_LOAD_TARGET_LIGHT;
+ }
+
+ } else if (enableFreeTypeHinting) {
if (enableSlightHinting)
ret |= FT_LOAD_TARGET_LIGHT;
} else {
@@ -213,7 +287,7 @@ GBool SplashFTFont::makeGlyph(int c, int xFrac, int yFrac,
gid = (FT_UInt)c;
}
- if (FT_Load_Glyph(ff->face, gid, getFTLoadFlags(aa, enableFreeTypeHinting, enableSlightHinting))) {
+ if (FT_Load_Glyph(ff->face, gid, getFTLoadFlags(ff->type1, ff->trueType, aa, enableAutoHinting, enableFreeTypeHinting, enableSlightHinting))) {
return gFalse;
}
@@ -240,6 +314,12 @@ GBool SplashFTFont::makeGlyph(int c, int xFrac, int yFrac,
return gFalse;
}
+ if (slot->bitmap.width == 0 || slot->bitmap.rows == 0) {
+ // this can happen if (a) the glyph is really tiny or (b) the
+ // metrics in the TrueType file are broken
+ return gFalse;
+ }
+
bitmap->x = -slot->bitmap_left;
bitmap->y = slot->bitmap_top;
bitmap->w = slot->bitmap.width;
@@ -291,12 +371,12 @@ double SplashFTFont::getGlyphAdvance(int c)
} else {
gid = (FT_UInt)c;
}
- if (ff->trueType && gid == 0) {
+ if (ff->trueType && gid < 0) {
// skip the TrueType notdef glyph
return -1;
}
- if (FT_Load_Glyph(ff->face, gid, getFTLoadFlags(aa, enableFreeTypeHinting, enableSlightHinting))) {
+ if (FT_Load_Glyph(ff->face, gid, getFTLoadFlags(ff->type1, ff->trueType, aa, enableAutoHinting, enableFreeTypeHinting, enableSlightHinting))) {
return -1;
}
@@ -340,11 +420,11 @@ SplashPath *SplashFTFont::getGlyphPath(int c) {
} else {
gid = (FT_UInt)c;
}
- if (ff->trueType && gid == 0) {
+ if (ff->trueType && gid < 0) {
// skip the TrueType notdef glyph
return NULL;
}
- if (FT_Load_Glyph(ff->face, gid, getFTLoadFlags(aa, enableFreeTypeHinting, enableSlightHinting))) {
+ if (FT_Load_Glyph(ff->face, gid, getFTLoadFlags(ff->type1, ff->trueType, aa, enableAutoHinting, enableFreeTypeHinting, enableSlightHinting))) {
return NULL;
}
if (FT_Get_Glyph(slot, &glyph)) {
diff --git a/splash/SplashFTFont.h b/splash/SplashFTFont.h
index 157eff33..17458079 100644
--- a/splash/SplashFTFont.h
+++ b/splash/SplashFTFont.h
@@ -70,7 +70,8 @@ private:
FT_Matrix matrix;
FT_Matrix textMatrix;
SplashCoord textScale;
- double size;
+ int size;
+ GBool enableAutoHinting;
GBool enableFreeTypeHinting;
GBool enableSlightHinting;
};
diff --git a/splash/SplashFTFontEngine.cc b/splash/SplashFTFontEngine.cc
index 144f8f4b..dee57286 100644
--- a/splash/SplashFTFontEngine.cc
+++ b/splash/SplashFTFontEngine.cc
@@ -50,7 +50,7 @@ extern "C" int unlink(char *filename);
//------------------------------------------------------------------------
#if 0
-static void fileWrite(void *stream, char *data, int len) {
+static void fileWrite(void *stream, const char *data, int len) {
fwrite(data, 1, len, (FILE *)stream);
}
#endif
@@ -59,11 +59,12 @@ static void fileWrite(void *stream, char *data, int len) {
// SplashFTFontEngine
//------------------------------------------------------------------------
-SplashFTFontEngine::SplashFTFontEngine(GBool aaA, GBool enableFreeTypeHintingA,
+SplashFTFontEngine::SplashFTFontEngine(GBool aaA, GBool enableAutoHintingA, GBool enableFreeTypeHintingA,
GBool enableSlightHintingA, FT_Library libA) {
FT_Int major, minor, patch;
aa = aaA;
+ enableAutoHinting = enableAutoHintingA;
enableFreeTypeHinting = enableFreeTypeHintingA;
enableSlightHinting = enableSlightHintingA;
lib = libA;
@@ -74,14 +75,14 @@ SplashFTFontEngine::SplashFTFontEngine(GBool aaA, GBool enableFreeTypeHintingA,
(major == 2 && (minor > 1 || (minor == 1 && patch > 7)));
}
-SplashFTFontEngine *SplashFTFontEngine::init(GBool aaA, GBool enableFreeTypeHintingA,
+SplashFTFontEngine *SplashFTFontEngine::init(GBool aaA, GBool enableAutoHintingA, GBool enableFreeTypeHintingA,
GBool enableSlightHintingA) {
FT_Library libA;
if (FT_Init_FreeType(&libA)) {
return NULL;
}
- return new SplashFTFontEngine(aaA, enableFreeTypeHintingA, enableSlightHintingA, libA);
+ return new SplashFTFontEngine(aaA, enableAutoHintingA, enableFreeTypeHintingA, enableSlightHintingA, libA);
}
SplashFTFontEngine::~SplashFTFontEngine() {
@@ -90,26 +91,26 @@ SplashFTFontEngine::~SplashFTFontEngine() {
SplashFontFile *SplashFTFontEngine::loadType1Font(SplashFontFileID *idA,
SplashFontSrc *src,
- char **enc) {
+ const char **enc) {
return SplashFTFontFile::loadType1Font(this, idA, src, enc);
}
SplashFontFile *SplashFTFontEngine::loadType1CFont(SplashFontFileID *idA,
SplashFontSrc *src,
- char **enc) {
+ const char **enc) {
return SplashFTFontFile::loadType1Font(this, idA, src, enc);
}
SplashFontFile *SplashFTFontEngine::loadOpenTypeT1CFont(SplashFontFileID *idA,
SplashFontSrc *src,
- char **enc) {
+ const char **enc) {
return SplashFTFontFile::loadType1Font(this, idA, src, enc);
}
SplashFontFile *SplashFTFontEngine::loadCIDFont(SplashFontFileID *idA,
SplashFontSrc *src) {
FoFiType1C *ff;
- Gushort *cidToGIDMap;
+ int *cidToGIDMap;
int nCIDs;
SplashFontFile *ret;
@@ -139,29 +140,34 @@ SplashFontFile *SplashFTFontEngine::loadCIDFont(SplashFontFileID *idA,
}
SplashFontFile *SplashFTFontEngine::loadOpenTypeCFFFont(SplashFontFileID *idA,
- SplashFontSrc *src) {
+ SplashFontSrc *src,
+ int *codeToGID,
+ int codeToGIDLen) {
FoFiTrueType *ff;
- Gushort *cidToGIDMap;
+ int *cidToGIDMap;
int nCIDs;
SplashFontFile *ret;
cidToGIDMap = NULL;
nCIDs = 0;
- if (!useCIDs) {
- if (src->isFile) {
- ff = FoFiTrueType::load(src->fileName->getCString());
- } else {
- ff = FoFiTrueType::make(src->buf, src->bufLen);
- }
- if (ff) {
- if (ff->isOpenTypeCFF()) {
- cidToGIDMap = ff->getCIDToGIDMap(&nCIDs);
+ if (!codeToGID) {
+ if (!useCIDs) {
+ if (src->isFile) {
+ ff = FoFiTrueType::load(src->fileName->getCString());
+ } else {
+ ff = FoFiTrueType::make(src->buf, src->bufLen);
+ }
+ if (ff) {
+ if (ff->isOpenTypeCFF()) {
+ cidToGIDMap = ff->getCIDToGIDMap(&nCIDs);
+ }
+ delete ff;
}
- delete ff;
}
}
ret = SplashFTFontFile::loadCIDFont(this, idA, src,
- cidToGIDMap, nCIDs);
+ codeToGID ? codeToGID : cidToGIDMap,
+ codeToGID ? codeToGIDLen : nCIDs);
if (!ret) {
gfree(cidToGIDMap);
}
@@ -170,7 +176,7 @@ SplashFontFile *SplashFTFontEngine::loadOpenTypeCFFFont(SplashFontFileID *idA,
SplashFontFile *SplashFTFontEngine::loadTrueTypeFont(SplashFontFileID *idA,
SplashFontSrc *src,
- Gushort *codeToGID,
+ int *codeToGID,
int codeToGIDLen,
int faceIndex) {
#if 0
diff --git a/splash/SplashFTFontEngine.h b/splash/SplashFTFontEngine.h
index 42207fb0..d236e4fc 100644
--- a/splash/SplashFTFontEngine.h
+++ b/splash/SplashFTFontEngine.h
@@ -45,24 +45,26 @@ class SplashFontSrc;
class SplashFTFontEngine {
public:
- static SplashFTFontEngine *init(GBool aaA, GBool enableFreeTypeHintingA, GBool enableSlightHinting);
+ static SplashFTFontEngine *init(GBool aaA, GBool enableAutoHintingA, GBool enableFreeTypeHintingA, GBool enableSlightHinting);
~SplashFTFontEngine();
// Load fonts.
- SplashFontFile *loadType1Font(SplashFontFileID *idA, SplashFontSrc *src, char **enc);
- SplashFontFile *loadType1CFont(SplashFontFileID *idA, SplashFontSrc *src, char **enc);
- SplashFontFile *loadOpenTypeT1CFont(SplashFontFileID *idA, SplashFontSrc *src, char **enc);
+ SplashFontFile *loadType1Font(SplashFontFileID *idA, SplashFontSrc *src, const char **enc);
+ SplashFontFile *loadType1CFont(SplashFontFileID *idA, SplashFontSrc *src, const char **enc);
+ SplashFontFile *loadOpenTypeT1CFont(SplashFontFileID *idA, SplashFontSrc *src, const char **enc);
SplashFontFile *loadCIDFont(SplashFontFileID *idA, SplashFontSrc *src);
- SplashFontFile *loadOpenTypeCFFFont(SplashFontFileID *idA, SplashFontSrc *src);
+ SplashFontFile *loadOpenTypeCFFFont(SplashFontFileID *idA, SplashFontSrc *src,
+ int *codeToGID, int codeToGIDLen);
SplashFontFile *loadTrueTypeFont(SplashFontFileID *idA, SplashFontSrc *src,
- Gushort *codeToGID, int codeToGIDLen, int faceIndex = 0);
+ int *codeToGID, int codeToGIDLen, int faceIndex = 0);
private:
- SplashFTFontEngine(GBool aaA, GBool enableFreeTypeHintingA, GBool enableSlightHintingA, FT_Library libA);
+ SplashFTFontEngine(GBool aaA, GBool enableAutoHintingA, GBool enableFreeTypeHintingA, GBool enableSlightHintingA, FT_Library libA);
GBool aa;
+ GBool enableAutoHinting;
GBool enableFreeTypeHinting;
GBool enableSlightHinting;
FT_Library lib;
diff --git a/splash/SplashFTFontFile.cc b/splash/SplashFTFontFile.cc
index 160481e7..34f6ce5c 100644
--- a/splash/SplashFTFontFile.cc
+++ b/splash/SplashFTFontFile.cc
@@ -39,10 +39,10 @@
SplashFontFile *SplashFTFontFile::loadType1Font(SplashFTFontEngine *engineA,
SplashFontFileID *idA,
SplashFontSrc *src,
- char **encA) {
+ const char **encA) {
FT_Face faceA;
- Gushort *codeToGIDA;
- char *name;
+ int *codeToGIDA;
+ const char *name;
int i;
if (src->isFile) {
@@ -52,22 +52,22 @@ SplashFontFile *SplashFTFontFile::loadType1Font(SplashFTFontEngine *engineA,
if (FT_New_Memory_Face(engineA->lib, (const FT_Byte *)src->buf, src->bufLen, 0, &faceA))
return NULL;
}
- codeToGIDA = (Gushort *)gmallocn(256, sizeof(int));
+ codeToGIDA = (int *)gmallocn(256, sizeof(int));
for (i = 0; i < 256; ++i) {
codeToGIDA[i] = 0;
if ((name = encA[i])) {
- codeToGIDA[i] = (Gushort)FT_Get_Name_Index(faceA, name);
+ codeToGIDA[i] = (int)FT_Get_Name_Index(faceA, (char *)name);
}
}
return new SplashFTFontFile(engineA, idA, src,
- faceA, codeToGIDA, 256, gFalse);
+ faceA, codeToGIDA, 256, gFalse, gTrue);
}
SplashFontFile *SplashFTFontFile::loadCIDFont(SplashFTFontEngine *engineA,
SplashFontFileID *idA,
SplashFontSrc *src,
- Gushort *codeToGIDA,
+ int *codeToGIDA,
int codeToGIDLenA) {
FT_Face faceA;
@@ -80,13 +80,13 @@ SplashFontFile *SplashFTFontFile::loadCIDFont(SplashFTFontEngine *engineA,
}
return new SplashFTFontFile(engineA, idA, src,
- faceA, codeToGIDA, codeToGIDLenA, gFalse);
+ faceA, codeToGIDA, codeToGIDLenA, gFalse, gFalse);
}
SplashFontFile *SplashFTFontFile::loadTrueTypeFont(SplashFTFontEngine *engineA,
SplashFontFileID *idA,
SplashFontSrc *src,
- Gushort *codeToGIDA,
+ int *codeToGIDA,
int codeToGIDLenA,
int faceIndexA) {
FT_Face faceA;
@@ -100,15 +100,15 @@ SplashFontFile *SplashFTFontFile::loadTrueTypeFont(SplashFTFontEngine *engineA,
}
return new SplashFTFontFile(engineA, idA, src,
- faceA, codeToGIDA, codeToGIDLenA, gTrue);
+ faceA, codeToGIDA, codeToGIDLenA, gTrue, gFalse);
}
SplashFTFontFile::SplashFTFontFile(SplashFTFontEngine *engineA,
SplashFontFileID *idA,
SplashFontSrc *src,
FT_Face faceA,
- Gushort *codeToGIDA, int codeToGIDLenA,
- GBool trueTypeA):
+ int *codeToGIDA, int codeToGIDLenA,
+ GBool trueTypeA, GBool type1A):
SplashFontFile(idA, src)
{
engine = engineA;
@@ -116,6 +116,7 @@ SplashFTFontFile::SplashFTFontFile(SplashFTFontEngine *engineA,
codeToGID = codeToGIDA;
codeToGIDLen = codeToGIDLenA;
trueType = trueTypeA;
+ type1 = type1A;
}
SplashFTFontFile::~SplashFTFontFile() {
diff --git a/splash/SplashFTFontFile.h b/splash/SplashFTFontFile.h
index 079fb1cb..d642af0a 100644
--- a/splash/SplashFTFontFile.h
+++ b/splash/SplashFTFontFile.h
@@ -43,15 +43,15 @@ public:
static SplashFontFile *loadType1Font(SplashFTFontEngine *engineA,
SplashFontFileID *idA,
- SplashFontSrc *src, char **encA);
+ SplashFontSrc *src, const char **encA);
static SplashFontFile *loadCIDFont(SplashFTFontEngine *engineA,
SplashFontFileID *idA,
SplashFontSrc *src,
- Gushort *codeToCIDA, int codeToGIDLenA);
+ int *codeToCIDA, int codeToGIDLenA);
static SplashFontFile *loadTrueTypeFont(SplashFTFontEngine *engineA,
SplashFontFileID *idA,
SplashFontSrc *src,
- Gushort *codeToGIDA,
+ int *codeToGIDA,
int codeToGIDLenA,
int faceIndexA=0);
@@ -68,14 +68,15 @@ private:
SplashFontFileID *idA,
SplashFontSrc *src,
FT_Face faceA,
- Gushort *codeToGIDA, int codeToGIDLenA,
- GBool trueTypeA);
+ int *codeToGIDA, int codeToGIDLenA,
+ GBool trueTypeA, GBool type1A);
SplashFTFontEngine *engine;
FT_Face face;
- Gushort *codeToGID;
+ int *codeToGID;
int codeToGIDLen;
GBool trueType;
+ GBool type1;
friend class SplashFTFont;
};
diff --git a/splash/SplashFontEngine.cc b/splash/SplashFontEngine.cc
index 5fe8aeb5..ab9beb91 100644
--- a/splash/SplashFontEngine.cc
+++ b/splash/SplashFontEngine.cc
@@ -69,6 +69,7 @@ SplashFontEngine::SplashFontEngine(
#endif
#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H
GBool enableFreeType,
+ GBool enableAutoHinting,
GBool enableFreeTypeHinting,
GBool enableSlightHinting,
#endif
@@ -88,7 +89,7 @@ SplashFontEngine::SplashFontEngine(
#endif
#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H
if (enableFreeType) {
- ftEngine = SplashFTFontEngine::init(aa, enableFreeTypeHinting, enableSlightHinting);
+ ftEngine = SplashFTFontEngine::init(aa, enableAutoHinting, enableFreeTypeHinting, enableSlightHinting);
} else {
ftEngine = NULL;
}
@@ -133,7 +134,7 @@ SplashFontFile *SplashFontEngine::getFontFile(SplashFontFileID *id) {
SplashFontFile *SplashFontEngine::loadType1Font(SplashFontFileID *idA,
SplashFontSrc *src,
- char **enc) {
+ const char **enc) {
SplashFontFile *fontFile;
fontFile = NULL;
@@ -162,7 +163,7 @@ SplashFontFile *SplashFontEngine::loadType1Font(SplashFontFileID *idA,
SplashFontFile *SplashFontEngine::loadType1CFont(SplashFontFileID *idA,
SplashFontSrc *src,
- char **enc) {
+ const char **enc) {
SplashFontFile *fontFile;
fontFile = NULL;
@@ -191,7 +192,7 @@ SplashFontFile *SplashFontEngine::loadType1CFont(SplashFontFileID *idA,
SplashFontFile *SplashFontEngine::loadOpenTypeT1CFont(SplashFontFileID *idA,
SplashFontSrc *src,
- char **enc) {
+ const char **enc) {
SplashFontFile *fontFile;
fontFile = NULL;
@@ -235,13 +236,15 @@ SplashFontFile *SplashFontEngine::loadCIDFont(SplashFontFileID *idA,
}
SplashFontFile *SplashFontEngine::loadOpenTypeCFFFont(SplashFontFileID *idA,
- SplashFontSrc *src) {
+ SplashFontSrc *src,
+ int *codeToGID,
+ int codeToGIDLen) {
SplashFontFile *fontFile;
fontFile = NULL;
#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H
if (!fontFile && ftEngine) {
- fontFile = ftEngine->loadOpenTypeCFFFont(idA, src);
+ fontFile = ftEngine->loadOpenTypeCFFFont(idA, src, codeToGID, codeToGIDLen);
}
#endif
@@ -257,7 +260,7 @@ SplashFontFile *SplashFontEngine::loadOpenTypeCFFFont(SplashFontFileID *idA,
SplashFontFile *SplashFontEngine::loadTrueTypeFont(SplashFontFileID *idA,
SplashFontSrc *src,
- Gushort *codeToGID,
+ int *codeToGID,
int codeToGIDLen,
int faceIndex) {
SplashFontFile *fontFile;
@@ -297,7 +300,7 @@ SplashFont *SplashFontEngine::getFont(SplashFontFile *fontFile,
mat[1] = -(textMat[0] * ctm[1] + textMat[1] * ctm[3]);
mat[2] = textMat[2] * ctm[0] + textMat[3] * ctm[2];
mat[3] = -(textMat[2] * ctm[1] + textMat[3] * ctm[3]);
- if (splashAbs(mat[0] * mat[3] - mat[1] * mat[2]) < 0.01) {
+ if (!splashCheckDet(mat[0], mat[1], mat[2], mat[3], 0.01)) {
// avoid a singular (or close-to-singular) matrix
mat[0] = 0.01; mat[1] = 0;
mat[2] = 0; mat[3] = 0.01;
diff --git a/splash/SplashFontEngine.h b/splash/SplashFontEngine.h
index 38efa48a..f0340a5c 100644
--- a/splash/SplashFontEngine.h
+++ b/splash/SplashFontEngine.h
@@ -58,6 +58,7 @@ public:
#endif
#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H
GBool enableFreeType,
+ GBool enabbleAutoHinting,
GBool enableFreeTypeHinting,
GBool enableSlightHinting,
#endif
@@ -70,13 +71,14 @@ public:
SplashFontFile *getFontFile(SplashFontFileID *id);
// Load fonts - these create new SplashFontFile objects.
- SplashFontFile *loadType1Font(SplashFontFileID *idA, SplashFontSrc *src, char **enc);
- SplashFontFile *loadType1CFont(SplashFontFileID *idA, SplashFontSrc *src, char **enc);
- SplashFontFile *loadOpenTypeT1CFont(SplashFontFileID *idA, SplashFontSrc *src, char **enc);
+ SplashFontFile *loadType1Font(SplashFontFileID *idA, SplashFontSrc *src, const char **enc);
+ SplashFontFile *loadType1CFont(SplashFontFileID *idA, SplashFontSrc *src, const char **enc);
+ SplashFontFile *loadOpenTypeT1CFont(SplashFontFileID *idA, SplashFontSrc *src, const char **enc);
SplashFontFile *loadCIDFont(SplashFontFileID *idA, SplashFontSrc *src);
- SplashFontFile *loadOpenTypeCFFFont(SplashFontFileID *idA, SplashFontSrc *src);
+ SplashFontFile *loadOpenTypeCFFFont(SplashFontFileID *idA, SplashFontSrc *src,
+ int *codeToGID, int codeToGIDLen);
SplashFontFile *loadTrueTypeFont(SplashFontFileID *idA, SplashFontSrc *src,
- Gushort *codeToGID, int codeToGIDLen, int faceIndex = 0);
+ int *codeToGID, int codeToGIDLen, int faceIndex = 0);
// Get a font - this does a cache lookup first, and if not found,
// creates a new SplashFont object and adds it to the cache. The
diff --git a/splash/SplashMath.h b/splash/SplashMath.h
index 924af6aa..1886dec6 100644
--- a/splash/SplashMath.h
+++ b/splash/SplashMath.h
@@ -45,6 +45,42 @@ static inline int splashFloor(SplashCoord x) {
return FixedPoint::floor(x);
#elif USE_FLOAT
return (int)floorf(x);
+ #elif __GNUC__ && __i386__
+ // floor() and (int)() are implemented separately, which results
+ // in changing the FPCW multiple times - so we optimize it with
+ // some inline assembly
+ Gushort oldCW, newCW, t;
+ int result;
+
+ __asm__ volatile("fldl %4\n"
+ "fnstcw %0\n"
+ "movw %0, %3\n"
+ "andw $0xf3ff, %3\n"
+ "orw $0x0400, %3\n"
+ "movw %3, %1\n" // round down
+ "fldcw %1\n"
+ "fistpl %2\n"
+ "fldcw %0\n"
+ : "=m" (oldCW), "=m" (newCW), "=m" (result), "=r" (t)
+ : "m" (x));
+ return result;
+ #elif defined(WIN32) && defined(_M_IX86)
+ // floor() and (int)() are implemented separately, which results
+ // in changing the FPCW multiple times - so we optimize it with
+ // some inline assembly
+ Gushort oldCW, newCW;
+ int result;
+
+ __asm fld QWORD PTR x
+ __asm fnstcw WORD PTR oldCW
+ __asm mov ax, WORD PTR oldCW
+ __asm and ax, 0xf3ff
+ __asm or ax, 0x0400
+ __asm mov WORD PTR newCW, ax // round down
+ __asm fldcw WORD PTR newCW
+ __asm fistp DWORD PTR result
+ __asm fldcw WORD PTR oldCW
+ return result;
#else
if (x > 0) return (int)x;
else return (int)floor(x);
@@ -56,6 +92,42 @@ static inline int splashCeil(SplashCoord x) {
return FixedPoint::ceil(x);
#elif USE_FLOAT
return (int)ceilf(x);
+#elif __GNUC__ && __i386__
+ // ceil() and (int)() are implemented separately, which results
+ // in changing the FPCW multiple times - so we optimize it with
+ // some inline assembly
+ Gushort oldCW, newCW, t;
+ int result;
+
+ __asm__ volatile("fldl %4\n"
+ "fnstcw %0\n"
+ "movw %0, %3\n"
+ "andw $0xf3ff, %3\n"
+ "orw $0x0800, %3\n"
+ "movw %3, %1\n" // round up
+ "fldcw %1\n"
+ "fistpl %2\n"
+ "fldcw %0\n"
+ : "=m" (oldCW), "=m" (newCW), "=m" (result), "=r" (t)
+ : "m" (x));
+ return result;
+#elif defined(WIN32) && defined(_M_IX86)
+ // ceil() and (int)() are implemented separately, which results
+ // in changing the FPCW multiple times - so we optimize it with
+ // some inline assembly
+ Gushort oldCW, newCW;
+ int result;
+
+ __asm fld QWORD PTR x
+ __asm fnstcw WORD PTR oldCW
+ __asm mov ax, WORD PTR oldCW
+ __asm and ax, 0xf3ff
+ __asm or ax, 0x0800
+ __asm mov WORD PTR newCW, ax // round up
+ __asm fldcw WORD PTR newCW
+ __asm fistp DWORD PTR result
+ __asm fldcw WORD PTR oldCW
+ return result;
#else
return (int)ceil(x);
#endif
@@ -64,11 +136,57 @@ static inline int splashCeil(SplashCoord x) {
static inline int splashRound(SplashCoord x) {
#if USE_FIXEDPOINT
return FixedPoint::round(x);
+#elif __GNUC__ && __i386__
+ // this could use round-to-nearest mode and avoid the "+0.5",
+ // but that produces slightly different results (because i+0.5
+ // sometimes rounds up and sometimes down using the even rule)
+ Gushort oldCW, newCW, t;
+ int result;
+
+ x += 0.5;
+ __asm__ volatile("fldl %4\n"
+ "fnstcw %0\n"
+ "movw %0, %3\n"
+ "andw $0xf3ff, %3\n"
+ "orw $0x0400, %3\n"
+ "movw %3, %1\n" // round down
+ "fldcw %1\n"
+ "fistpl %2\n"
+ "fldcw %0\n"
+ : "=m" (oldCW), "=m" (newCW), "=m" (result), "=r" (t)
+ : "m" (x));
+ return result;
+#elif defined(WIN32) && defined(_M_IX86)
+ // this could use round-to-nearest mode and avoid the "+0.5",
+ // but that produces slightly different results (because i+0.5
+ // sometimes rounds up and sometimes down using the even rule)
+ Gushort oldCW, newCW;
+ int result;
+
+ x += 0.5;
+ __asm fld QWORD PTR x
+ __asm fnstcw WORD PTR oldCW
+ __asm mov ax, WORD PTR oldCW
+ __asm and ax, 0xf3ff
+ __asm or ax, 0x0400
+ __asm mov WORD PTR newCW, ax // round down
+ __asm fldcw WORD PTR newCW
+ __asm fistp DWORD PTR result
+ __asm fldcw WORD PTR oldCW
+ return result;
#else
return (int)splashFloor(x + 0.5);
#endif
}
+static inline SplashCoord splashAvg(SplashCoord x, SplashCoord y) {
+#if USE_FIXEDPOINT
+ return FixedPoint::avg(x, y);
+#else
+ return 0.5 * (x + y);
+#endif
+}
+
static inline SplashCoord splashSqrt(SplashCoord x) {
#if USE_FIXEDPOINT
return FixedPoint::sqrt(x);
@@ -97,19 +215,31 @@ static inline SplashCoord splashDist(SplashCoord x0, SplashCoord y0,
#if USE_FIXEDPOINT
// this handles the situation where dx*dx or dy*dy is too large to
// fit in the 16.16 fixed point format
- SplashCoord dxa, dya;
+ SplashCoord dxa, dya, d;
dxa = splashAbs(dx);
dya = splashAbs(dy);
if (dxa == 0 && dya == 0) {
return 0;
} else if (dxa > dya) {
- return dxa * FixedPoint::sqrt(dya / dxa + 1);
+ d = dya / dxa;
+ return dxa * FixedPoint::sqrt(d*d + 1);
} else {
- return dya * FixedPoint::sqrt(dxa / dya + 1);
+ d = dxa / dya;
+ return dya * FixedPoint::sqrt(d*d + 1);
}
#else
return splashSqrt(dx * dx + dy * dy);
#endif
}
+static inline GBool splashCheckDet(SplashCoord m11, SplashCoord m12,
+ SplashCoord m21, SplashCoord m22,
+ SplashCoord epsilon) {
+#if USE_FIXEDPOINT
+ return FixedPoint::checkDet(m11, m12, m21, m22, epsilon);
+#else
+ return fabs(m11 * m22 - m12 * m21) >= epsilon;
+#endif
+}
+
#endif
diff --git a/splash/SplashPath.cc b/splash/SplashPath.cc
index 261f7788..bc4ccd52 100644
--- a/splash/SplashPath.cc
+++ b/splash/SplashPath.cc
@@ -136,11 +136,12 @@ SplashError SplashPath::curveTo(SplashCoord x1, SplashCoord y1,
return splashOk;
}
-SplashError SplashPath::close() {
+SplashError SplashPath::close(GBool force) {
if (noCurrentPoint()) {
return splashErrNoCurPt;
}
- if (curSubpath == length - 1 ||
+ if (force ||
+ curSubpath == length - 1 ||
pts[length - 1].x != pts[curSubpath].x ||
pts[length - 1].y != pts[curSubpath].y) {
lineTo(pts[curSubpath].x, pts[curSubpath].y);
diff --git a/splash/SplashPath.h b/splash/SplashPath.h
index 991e1143..81273c61 100644
--- a/splash/SplashPath.h
+++ b/splash/SplashPath.h
@@ -77,8 +77,10 @@ public:
SplashCoord x2, SplashCoord y2,
SplashCoord x3, SplashCoord y3);
- // Close the last subpath, adding a line segment if necessary.
- SplashError close();
+ // Close the last subpath, adding a line segment if necessary. If
+ // <force> is true, this adds a line segment even if the current
+ // point is equal to the first point in the subpath.
+ SplashError close(GBool force = gFalse);
// Add a stroke adjustment hint. The controlling segments are
// <ctrl0> and <ctrl1> (where segments are identified by their first
diff --git a/splash/SplashPattern.cc b/splash/SplashPattern.cc
index 67479734..28ca4995 100644
--- a/splash/SplashPattern.cc
+++ b/splash/SplashPattern.cc
@@ -53,17 +53,3 @@ GBool SplashSolidColor::getColor(int x, int y, SplashColorPtr c) {
splashColorCopy(c, color);
return gTrue;
}
-
-void SplashSolidColor::overprint(GBool op, Guchar aSrc, SplashColorPtr cSrc,
- Guchar aDest, SplashColorPtr cDest,
- SplashColorPtr colorResult) {
- // default for overprint is knockout:
- colorResult[0] = (Guchar)(((aDest - aSrc) * cDest[0] +
- aSrc * cSrc[0]) / aDest);
- colorResult[1] = (Guchar)(((aDest - aSrc) * cDest[1] +
- aSrc * cSrc[1]) / aDest);
- colorResult[2] = (Guchar)(((aDest - aSrc) * cDest[2] +
- aSrc * cSrc[2]) / aDest);
- colorResult[3] = (Guchar)(((aDest - aSrc) * cDest[3] +
- aSrc * cSrc[3]) / aDest);
-}
diff --git a/splash/SplashPattern.h b/splash/SplashPattern.h
index de1f8877..42c1660f 100644
--- a/splash/SplashPattern.h
+++ b/splash/SplashPattern.h
@@ -52,10 +52,6 @@ public:
// value for all pixels.
virtual GBool isStatic() = 0;
- // calculate destination color if overprint is enables
- virtual void overprint(GBool op, Guchar alphaSrc, SplashColorPtr colorSrc,
- Guchar alphaDest, SplashColorPtr colorDest, SplashColorPtr colorResult) = 0;
-
private:
};
@@ -78,9 +74,6 @@ public:
virtual GBool isStatic() { return gTrue; }
- virtual void overprint(GBool op, Guchar alphaSrc, SplashColorPtr colorSrc,
- Guchar alphaDest, SplashColorPtr colorDest, SplashColorPtr colorResult);
-
private:
SplashColor color;
diff --git a/splash/SplashScreen.cc b/splash/SplashScreen.cc
index 6b75c0ca..d7412469 100644
--- a/splash/SplashScreen.cc
+++ b/splash/SplashScreen.cc
@@ -26,6 +26,7 @@
#include <stdlib.h>
#include <string.h>
+#include <algorithm>
#include "goo/gmem.h"
#include "SplashMath.h"
#include "SplashScreen.h"
@@ -46,9 +47,12 @@ struct SplashScreenPoint {
int dist;
};
-static int cmpDistances(const void *p0, const void *p1) {
- return ((SplashScreenPoint *)p0)->dist - ((SplashScreenPoint *)p1)->dist;
-}
+
+struct cmpDistancesFunctor {
+ bool operator()(const SplashScreenPoint &p0, const SplashScreenPoint &p1) {
+ return p0.dist < p1.dist;
+ }
+};
//------------------------------------------------------------------------
// SplashScreen
@@ -74,41 +78,38 @@ SplashScreen::SplashScreen(SplashScreenParams *params) {
void SplashScreen::createMatrix()
{
- Guchar u, black, white;
- int i;
+ Guchar u;
+ int black, white, i;
SplashScreenParams *params = screenParams;
+ // size must be a power of 2, and at least 2
+ for (size = 2, log2Size = 1; size < params->size; size <<= 1, ++log2Size) ;
+
switch (params->type) {
case splashScreenDispersed:
- // size must be a power of 2
- for (size = 1; size < params->size; size <<= 1) ;
mat = (Guchar *)gmallocn(size * size, sizeof(Guchar));
buildDispersedMatrix(size/2, size/2, 1, size/2, 1);
break;
case splashScreenClustered:
- // size must be even
- size = (params->size >> 1) << 1;
- if (size < 2) {
- size = 2;
- }
mat = (Guchar *)gmallocn(size * size, sizeof(Guchar));
buildClusteredMatrix();
break;
case splashScreenStochasticClustered:
// size must be at least 2*r
- if (params->size < 2 * params->dotRadius) {
- size = 2 * params->dotRadius;
- } else {
- size = params->size;
+ while (size < (params->dotRadius << 1)) {
+ size <<= 1;
+ ++log2Size;
}
mat = (Guchar *)gmallocn(size * size, sizeof(Guchar));
buildSCDMatrix(params->dotRadius);
break;
}
+
+ sizeM1 = size - 1;
// do gamma correction and compute minVal/maxVal
minVal = 255;
@@ -127,9 +128,9 @@ void SplashScreen::createMatrix()
u = splashRound((SplashCoord)255.0 *
splashPow((SplashCoord)mat[i] / 255.0, params->gamma));
if (u < black) {
- u = black;
+ u = (Guchar)black;
} else if (u >= white) {
- u = white;
+ u = (Guchar)white;
}
mat[i] = u;
if (u < minVal) {
@@ -144,7 +145,7 @@ void SplashScreen::buildDispersedMatrix(int i, int j, int val,
int delta, int offset) {
if (delta == 0) {
// map values in [1, size^2] --> [1, 255]
- mat[i * size + j] = 1 + (254 * (val - 1)) / (size * size - 1);
+ mat[(i << log2Size) + j] = 1 + (254 * (val - 1)) / (size * size - 1);
} else {
buildDispersedMatrix(i, j,
val, delta / 2, 4*offset);
@@ -168,7 +169,7 @@ void SplashScreen::buildClusteredMatrix() {
// initialize the threshold matrix
for (y = 0; y < size; ++y) {
for (x = 0; x < size; ++x) {
- mat[y * size + x] = 0;
+ mat[(y << log2Size) + x] = 0;
}
}
@@ -200,14 +201,12 @@ void SplashScreen::buildClusteredMatrix() {
}
// build the threshold matrix
- minVal = 1;
- maxVal = 0;
x1 = y1 = 0; // make gcc happy
for (i = 0; i < size * size2; ++i) {
d = -1;
for (y = 0; y < size; ++y) {
for (x = 0; x < size2; ++x) {
- if (mat[y * size + x] == 0 &&
+ if (mat[(y << log2Size) + x] == 0 &&
dist[y * size2 + x] > d) {
x1 = x;
y1 = y;
@@ -217,12 +216,12 @@ void SplashScreen::buildClusteredMatrix() {
}
// map values in [0, 2*size*size2-1] --> [1, 255]
val = 1 + (254 * (2*i)) / (2*size*size2 - 1);
- mat[y1 * size + x1] = val;
+ mat[(y1 << log2Size) + x1] = val;
val = 1 + (254 * (2*i+1)) / (2*size*size2 - 1);
if (y1 < size2) {
- mat[(y1 + size2) * size + x1 + size2] = val;
+ mat[((y1 + size2) << log2Size) + x1 + size2] = val;
} else {
- mat[(y1 - size2) * size + x1 + size2] = val;
+ mat[((y1 - size2) << log2Size) + x1 + size2] = val;
}
}
@@ -290,7 +289,7 @@ void SplashScreen::buildSCDMatrix(int r) {
grid = (char *)gmallocn(size * size, sizeof(char));
for (y = 0; y < size; ++y) {
for (x = 0; x < size; ++x) {
- grid[y*size + x] = 0;
+ grid[(y << log2Size) + x] = 0;
}
}
@@ -301,7 +300,7 @@ void SplashScreen::buildSCDMatrix(int r) {
for (i = 0; i < size * size; ++i) {
x = pts[i].x;
y = pts[i].y;
- if (!grid[y*size + x]) {
+ if (!grid[(y << log2Size) + x]) {
if (dotsLen == dotsSize) {
dotsSize *= 2;
dots = (SplashScreenPoint *)greallocn(dots, dotsSize,
@@ -315,10 +314,10 @@ void SplashScreen::buildSCDMatrix(int r) {
if (tmpl[yy*(r+1) + xx]) {
x0 = (x + xx) % size;
x1 = (x - xx + size) % size;
- grid[y0*size + x0] = 1;
- grid[y0*size + x1] = 1;
- grid[y1*size + x0] = 1;
- grid[y1*size + x1] = 1;
+ grid[(y0 << log2Size) + x0] = 1;
+ grid[(y0 << log2Size) + x1] = 1;
+ grid[(y1 << log2Size) + x0] = 1;
+ grid[(y1 << log2Size) + x1] = 1;
}
}
}
@@ -342,8 +341,8 @@ void SplashScreen::buildSCDMatrix(int r) {
dMin = d;
}
}
- region[y*size + x] = iMin;
- dist[y*size + x] = dMin;
+ region[(y << log2Size) + x] = iMin;
+ dist[(y << log2Size) + x] = dMin;
}
}
@@ -352,7 +351,7 @@ void SplashScreen::buildSCDMatrix(int r) {
n = 0;
for (y = 0; y < size; ++y) {
for (x = 0; x < size; ++x) {
- if (region[y*size + x] == i) {
+ if (region[(y << log2Size) + x] == i) {
pts[n].x = x;
pts[n].y = y;
pts[n].dist = distance(dots[i].x, dots[i].y, x, y);
@@ -360,10 +359,10 @@ void SplashScreen::buildSCDMatrix(int r) {
}
}
}
- qsort(pts, n, sizeof(SplashScreenPoint), &cmpDistances);
+ std::sort(pts, pts + n, cmpDistancesFunctor());
for (j = 0; j < n; ++j) {
// map values in [0 .. n-1] --> [255 .. 1]
- mat[pts[j].y * size + pts[j].x] = 255 - (254 * j) / (n - 1);
+ mat[(pts[j].y << log2Size) + pts[j].x] = 255 - (254 * j) / (n - 1);
}
}
@@ -377,6 +376,8 @@ void SplashScreen::buildSCDMatrix(int r) {
SplashScreen::SplashScreen(SplashScreen *screen) {
screenParams = screen->screenParams;
size = screen->size;
+ sizeM1 = screen->sizeM1;
+ log2Size = screen->log2Size;
mat = (Guchar *)gmallocn(size * size, sizeof(Guchar));
memcpy(mat, screen->mat, size * size * sizeof(Guchar));
minVal = screen->minVal;
@@ -386,29 +387,3 @@ SplashScreen::SplashScreen(SplashScreen *screen) {
SplashScreen::~SplashScreen() {
gfree(mat);
}
-
-int SplashScreen::test(int x, int y, Guchar value) {
- int xx, yy;
-
- if (mat == NULL) createMatrix();
-
- if (value < minVal) {
- return 0;
- }
- if (value >= maxVal) {
- return 1;
- }
- if ((xx = x % size) < 0) {
- xx = -xx;
- }
- if ((yy = y % size) < 0) {
- yy = -yy;
- }
- return value < mat[yy * size + xx] ? 0 : 1;
-}
-
-GBool SplashScreen::isStatic(Guchar value) {
- if (mat == NULL) createMatrix();
-
- return value < minVal || value >= maxVal;
-}
diff --git a/splash/SplashScreen.h b/splash/SplashScreen.h
index fe3b5c81..a7fc4559 100644
--- a/splash/SplashScreen.h
+++ b/splash/SplashScreen.h
@@ -27,6 +27,8 @@
#include "SplashTypes.h"
+#include <stdlib.h>
+
//------------------------------------------------------------------------
// SplashScreen
//------------------------------------------------------------------------
@@ -42,12 +44,18 @@ public:
// Return the computed pixel value (0=black, 1=white) for the gray
// level <value> at (<x>, <y>).
- int test(int x, int y, Guchar value);
+ int test(int x, int y, Guchar value) {
+ int xx, yy;
+ if (mat == NULL) createMatrix();
+ xx = x & sizeM1;
+ yy = y & sizeM1;
+ return value < mat[(yy << log2Size) + xx] ? 0 : 1;
+ }
// Returns true if value is above the white threshold or below the
// black threshold, i.e., if the corresponding halftone will be
// solid white or black.
- GBool isStatic(Guchar value);
+ GBool isStatic(Guchar value) { if (mat == NULL) createMatrix(); return value < minVal || value >= maxVal; }
private:
void createMatrix();
@@ -61,6 +69,8 @@ private:
SplashScreenParams *screenParams; // params to create the other members
Guchar *mat; // threshold matrix
int size; // size of the threshold matrix
+ int sizeM1; // size - 1
+ int log2Size; // log2(size)
Guchar minVal; // any pixel value below minVal generates
// solid black
Guchar maxVal; // any pixel value above maxVal generates
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/SplashT1Font.cc b/splash/SplashT1Font.cc
index 536c5605..0fdfaaf5 100644
--- a/splash/SplashT1Font.cc
+++ b/splash/SplashT1Font.cc
@@ -90,7 +90,7 @@ SplashT1Font::SplashT1Font(SplashT1FontFile *fontFileA, SplashCoord *matA,
outlineID = -1;
// compute font size
- size = (float)splashSqrt(mat[2]*mat[2] + mat[3]*mat[3]);
+ size = (float)splashDist(0, 0, mat[2], mat[3]);
// transform the four corners of the font bounding box -- the min
// and max values form the bounding box of the transformed font
@@ -239,13 +239,12 @@ SplashPath *SplashT1Font::getGlyphPath(int c) {
T1_OUTLINE *outline;
T1_PATHSEGMENT *seg;
T1_BEZIERSEGMENT *bez;
- SplashCoord x, y, x1, y1;
+ int x, y, x1, y1;
GBool needClose;
if (outlineID < 0) {
outlineID = T1_CopyFont(((SplashT1FontFile *)fontFile)->t1libID);
- outlineSize = (float)splashSqrt(textMat[2]*textMat[2] +
- textMat[3]*textMat[3]);
+ outlineSize = (float)splashDist(0, 0, textMat[2], textMat[3]);
matrix.cxx = (double)textMat[0] / outlineSize;
matrix.cxy = (double)textMat[1] / outlineSize;
matrix.cyx = (double)textMat[2] / outlineSize;
@@ -259,8 +258,11 @@ SplashPath *SplashT1Font::getGlyphPath(int c) {
path = new SplashPath();
if ((outline = T1_GetCharOutline(outlineID, c, outlineSize, NULL))) {
- x = 0;
- y = 0;
+ // NB: t1lib uses integer coordinates here; we keep a running
+ // (x,y) total as integers, so that the final point in the path is
+ // exactly the same as the first point, thus avoiding weird
+ // mitered join glitches
+ x = y = 0;
needClose = gFalse;
for (seg = outline; seg; seg = seg->link) {
switch (seg->type) {
@@ -269,25 +271,26 @@ SplashPath *SplashT1Font::getGlyphPath(int c) {
path->close();
needClose = gFalse;
}
- x += seg->dest.x * outlineMul;
- y += seg->dest.y * outlineMul;
- path->moveTo(x, -y);
+ x += seg->dest.x;
+ y += seg->dest.y;
+ path->moveTo(outlineMul * x, -outlineMul * y);
break;
case T1_PATHTYPE_LINE:
- x += seg->dest.x * outlineMul;
- y += seg->dest.y * outlineMul;
- path->lineTo(x, -y);
+ x += seg->dest.x;
+ y += seg->dest.y;
+ path->lineTo(outlineMul * x, -outlineMul * y);
needClose = gTrue;
break;
case T1_PATHTYPE_BEZIER:
bez = (T1_BEZIERSEGMENT *)seg;
- x1 = x + (SplashCoord)(bez->dest.x * outlineMul);
- y1 = y + (SplashCoord)(bez->dest.y * outlineMul);
- path->curveTo(x + (SplashCoord)(bez->B.x * outlineMul),
- -(y + (SplashCoord)(bez->B.y * outlineMul)),
- x + (SplashCoord)(bez->C.x * outlineMul),
- -(y + (SplashCoord)(bez->C.y * outlineMul)),
- x1, -y1);
+ x1 = x + bez->dest.x;
+ y1 = y + bez->dest.y;
+ path->curveTo(outlineMul * (x + bez->B.x),
+ -outlineMul * (y + bez->B.y),
+ outlineMul * (x + bez->C.x),
+ -outlineMul * (y + bez->C.y),
+ outlineMul * x1,
+ -outlineMul * y1);
x = x1;
y = y1;
needClose = gTrue;
diff --git a/splash/SplashT1FontEngine.cc b/splash/SplashT1FontEngine.cc
index a09a8839..fb4b38da 100644
--- a/splash/SplashT1FontEngine.cc
+++ b/splash/SplashT1FontEngine.cc
@@ -51,7 +51,7 @@ int SplashT1FontEngine::t1libInitCount = 0;
//------------------------------------------------------------------------
-static void fileWrite(void *stream, char *data, int len) {
+static void fileWrite(void *stream, const char *data, int len) {
fwrite(data, 1, len, (FILE *)stream);
}
@@ -98,13 +98,13 @@ SplashT1FontEngine::~SplashT1FontEngine() {
SplashFontFile *SplashT1FontEngine::loadType1Font(SplashFontFileID *idA,
SplashFontSrc *src,
- char **enc) {
+ const char **enc) {
return SplashT1FontFile::loadType1Font(this, idA, src, enc);
}
SplashFontFile *SplashT1FontEngine::loadType1CFont(SplashFontFileID *idA,
SplashFontSrc *src,
- char **enc) {
+ const char **enc) {
FoFiType1C *ff;
GooString *tmpFileName;
FILE *tmpFile;
diff --git a/splash/SplashT1FontEngine.h b/splash/SplashT1FontEngine.h
index ffc285bd..268a0147 100644
--- a/splash/SplashT1FontEngine.h
+++ b/splash/SplashT1FontEngine.h
@@ -31,8 +31,8 @@ public:
~SplashT1FontEngine();
// Load fonts.
- SplashFontFile *loadType1Font(SplashFontFileID *idA, SplashFontSrc *src, char **enc);
- SplashFontFile *loadType1CFont(SplashFontFileID *idA, SplashFontSrc *src, char **enc);
+ SplashFontFile *loadType1Font(SplashFontFileID *idA, SplashFontSrc *src, const char **enc);
+ SplashFontFile *loadType1CFont(SplashFontFileID *idA, SplashFontSrc *src, const char **enc);
private:
diff --git a/splash/SplashT1FontFile.cc b/splash/SplashT1FontFile.cc
index 3f46ba63..1832a916 100644
--- a/splash/SplashT1FontFile.cc
+++ b/splash/SplashT1FontFile.cc
@@ -43,9 +43,9 @@
SplashFontFile *SplashT1FontFile::loadType1Font(SplashT1FontEngine *engineA,
SplashFontFileID *idA,
SplashFontSrc *src,
- char **encA) {
+ const char **encA) {
int t1libIDA;
- char **encTmp;
+ const char **encTmp;
char *encStrTmp;
int encStrSize;
char *encPtr;
@@ -82,7 +82,7 @@ SplashFontFile *SplashT1FontFile::loadType1Font(SplashT1FontEngine *engineA,
encStrSize += strlen(encA[i]) + 1;
}
}
- encTmp = (char **)gmallocn(257, sizeof(char *));
+ encTmp = (const char **)gmallocn(257, sizeof(char *));
encStrTmp = (char *)gmallocn(encStrSize, sizeof(char));
encPtr = encStrTmp;
for (i = 0; i < 256; ++i) {
@@ -95,7 +95,7 @@ SplashFontFile *SplashT1FontFile::loadType1Font(SplashT1FontEngine *engineA,
}
}
encTmp[256] = "custom";
- T1_ReencodeFont(t1libIDA, encTmp);
+ T1_ReencodeFont(t1libIDA, (char **)encTmp);
ff = new SplashT1FontFile(engineA, idA, src,
t1libIDA, encTmp, encStrTmp);
@@ -107,7 +107,7 @@ SplashFontFile *SplashT1FontFile::loadType1Font(SplashT1FontEngine *engineA,
SplashT1FontFile::SplashT1FontFile(SplashT1FontEngine *engineA,
SplashFontFileID *idA,
SplashFontSrc *srcA,
- int t1libIDA, char **encA, char *encStrA):
+ int t1libIDA, const char **encA, char *encStrA):
SplashFontFile(idA, srcA)
{
engine = engineA;
diff --git a/splash/SplashT1FontFile.h b/splash/SplashT1FontFile.h
index 24c958bc..c094b6d8 100644
--- a/splash/SplashT1FontFile.h
+++ b/splash/SplashT1FontFile.h
@@ -41,7 +41,7 @@ public:
static SplashFontFile *loadType1Font(SplashT1FontEngine *engineA,
SplashFontFileID *idA,
SplashFontSrc *src,
- char **encA);
+ const char **encA);
virtual ~SplashT1FontFile();
@@ -55,11 +55,11 @@ private:
SplashT1FontFile(SplashT1FontEngine *engineA,
SplashFontFileID *idA,
SplashFontSrc *src,
- int t1libIDA, char **encA, char *encStrA);
+ int t1libIDA, const char **encA, char *encStrA);
SplashT1FontEngine *engine;
int t1libID; // t1lib font ID
- char **enc;
+ const char **enc;
char *encStr;
friend class SplashT1Font;
diff --git a/splash/SplashXPath.cc b/splash/SplashXPath.cc
index 4950de4e..b82d3559 100644
--- a/splash/SplashXPath.cc
+++ b/splash/SplashXPath.cc
@@ -65,19 +65,13 @@ inline void SplashXPath::transform(SplashCoord *matrix,
// SplashXPath
//------------------------------------------------------------------------
-SplashXPath::SplashXPath() {
- segs = NULL;
- length = size = 0;
-}
-
SplashXPath::SplashXPath(SplashPath *path, SplashCoord *matrix,
SplashCoord flatness, GBool closeSubpaths) {
SplashPathHint *hint;
SplashXPathPoint *pts;
SplashXPathAdjust *adjusts, *adjust;
SplashCoord x0, y0, x1, y1, x2, y2, x3, y3, xsp, ysp;
- SplashCoord adj0, adj1, w;
- int ww;
+ SplashCoord adj0, adj1;
int curSubpath, i, j;
// transform the points
@@ -119,19 +113,24 @@ SplashXPath::SplashXPath(SplashPath *path, SplashCoord *matrix,
adj0 = adj1;
adj1 = x0;
}
- w = adj1 - adj0;
- ww = splashRound(w);
- if (ww == 0) {
- ww = 1;
- }
adjusts[i].x0a = adj0 - 0.01;
adjusts[i].x0b = adj0 + 0.01;
adjusts[i].xma = (SplashCoord)0.5 * (adj0 + adj1) - 0.01;
adjusts[i].xmb = (SplashCoord)0.5 * (adj0 + adj1) + 0.01;
adjusts[i].x1a = adj1 - 0.01;
adjusts[i].x1b = adj1 + 0.01;
- adjusts[i].x0 = (SplashCoord)splashRound(adj0);
- adjusts[i].x1 = adjusts[i].x0 + ww - 0.01;
+ // rounding both edge coordinates can result in lines of
+ // different widths (e.g., adj=10.1, adj1=11.3 --> x0=10, x1=11;
+ // adj0=10.4, adj1=11.6 --> x0=10, x1=12), but it has the
+ // benefit of making adjacent strokes/fills line up without any
+ // gaps between them
+ x0 = splashRound(adj0);
+ x1 = splashRound(adj1);
+ if (x1 == x0) {
+ x1 = x1 + 1;
+ }
+ adjusts[i].x0 = (SplashCoord)x0;
+ adjusts[i].x1 = (SplashCoord)x1 - 0.01;
adjusts[i].xm = (SplashCoord)0.5 * (adjusts[i].x0 + adjusts[i].x1);
adjusts[i].firstPt = hint->firstPt;
adjusts[i].lastPt = hint->lastPt;
@@ -197,15 +196,7 @@ SplashXPath::SplashXPath(SplashPath *path, SplashCoord *matrix,
} else {
x1 = pts[i].x;
y1 = pts[i].y;
- addSegment(x0, y0, x1, y1,
- path->flags[i-1] & splashPathFirst,
- path->flags[i] & splashPathLast,
- !closeSubpaths &&
- (path->flags[i-1] & splashPathFirst) &&
- !(path->flags[i-1] & splashPathClosed),
- !closeSubpaths &&
- (path->flags[i] & splashPathLast) &&
- !(path->flags[i] & splashPathClosed));
+ addSegment(x0, y0, x1, y1);
x0 = x1;
y0 = y1;
++i;
@@ -216,8 +207,7 @@ SplashXPath::SplashXPath(SplashPath *path, SplashCoord *matrix,
(path->flags[i-1] & splashPathLast) &&
(pts[i-1].x != pts[curSubpath].x ||
pts[i-1].y != pts[curSubpath].y)) {
- addSegment(x0, y0, xsp, ysp,
- gFalse, gTrue, gFalse, gFalse);
+ addSegment(x0, y0, xsp, ysp);
}
}
}
@@ -289,7 +279,11 @@ void SplashXPath::addCurve(SplashCoord x0, SplashCoord y0,
SplashCoord dx, dy, mx, my, d1, d2, flatness2;
int p1, p2, p3;
+#if USE_FIXEDPOINT
+ flatness2 = flatness;
+#else
flatness2 = flatness * flatness;
+#endif
// initial segment
p1 = 0;
@@ -329,21 +323,22 @@ void SplashXPath::addCurve(SplashCoord x0, SplashCoord y0,
// line)
mx = (xl0 + xr3) * 0.5;
my = (yl0 + yr3) * 0.5;
+#if USE_FIXEDPOINT
+ d1 = splashDist(xx1, yy1, mx, my);
+ d2 = splashDist(xx2, yy2, mx, my);
+#else
dx = xx1 - mx;
dy = yy1 - my;
d1 = dx*dx + dy*dy;
dx = xx2 - mx;
dy = yy2 - my;
d2 = dx*dx + dy*dy;
+#endif
// if the curve is flat enough, or no more subdivisions are
// allowed, add the straight line segment
if (p2 - p1 == 1 || (d1 <= flatness2 && d2 <= flatness2)) {
- addSegment(xl0, yl0, xr3, yr3,
- p1 == 0 && first,
- p2 == splashMaxCurveSplits && last,
- p1 == 0 && end0,
- p2 == splashMaxCurveSplits && end1);
+ addSegment(xl0, yl0, xr3, yr3);
p1 = p2;
// otherwise, subdivide the curve
@@ -389,26 +384,13 @@ void SplashXPath::addCurve(SplashCoord x0, SplashCoord y0,
}
void SplashXPath::addSegment(SplashCoord x0, SplashCoord y0,
- SplashCoord x1, SplashCoord y1,
- GBool first, GBool last, GBool end0, GBool end1) {
+ SplashCoord x1, SplashCoord y1) {
grow(1);
segs[length].x0 = x0;
segs[length].y0 = y0;
segs[length].x1 = x1;
segs[length].y1 = y1;
segs[length].flags = 0;
- if (first) {
- segs[length].flags |= splashXPathFirst;
- }
- if (last) {
- segs[length].flags |= splashXPathLast;
- }
- if (end0) {
- segs[length].flags |= splashXPathEnd0;
- }
- if (end1) {
- segs[length].flags |= splashXPathEnd1;
- }
if (y1 == y0) {
segs[length].dxdy = segs[length].dydx = 0;
segs[length].flags |= splashXPathHoriz;
@@ -441,31 +423,27 @@ void SplashXPath::addSegment(SplashCoord x0, SplashCoord y0,
++length;
}
-static bool cmpXPathSegs(const SplashXPathSeg &seg0, const SplashXPathSeg &seg1) {
- SplashCoord x0, y0, x1, y1;
+struct cmpXPathSegsFunctor {
+ bool operator()(const SplashXPathSeg &seg0, const SplashXPathSeg &seg1) {
+ SplashCoord x0, y0, x1, y1;
- if (seg0.flags & splashXPathFlip) {
- x0 = seg0.x1;
- y0 = seg0.y1;
- } else {
- x0 = seg0.x0;
- y0 = seg0.y0;
- }
- if (seg1.flags & splashXPathFlip) {
- x1 = seg1.x1;
- y1 = seg1.y1;
- } else {
- x1 = seg1.x0;
- y1 = seg1.y0;
- }
- if (y0 != y1) {
- return (y0 < y1) ? true : false;
- }
- if (x0 != x1) {
- return (x0 < x1) ? true : false;
+ if (seg0.flags & splashXPathFlip) {
+ x0 = seg0.x1;
+ y0 = seg0.y1;
+ } else {
+ x0 = seg0.x0;
+ y0 = seg0.y0;
+ }
+ if (seg1.flags & splashXPathFlip) {
+ x1 = seg1.x1;
+ y1 = seg1.y1;
+ } else {
+ x1 = seg1.x0;
+ y1 = seg1.y0;
+ }
+ return (y0 != y1) ? (y0 < y1) : (x0 < x1);
}
- return false;
-}
+};
void SplashXPath::aaScale() {
SplashXPathSeg *seg;
@@ -480,5 +458,5 @@ void SplashXPath::aaScale() {
}
void SplashXPath::sort() {
- std::sort(segs, segs + length, &cmpXPathSegs);
+ std::sort(segs, segs + length, cmpXPathSegsFunctor());
}
diff --git a/splash/SplashXPath.h b/splash/SplashXPath.h
index 64c47969..db06978a 100644
--- a/splash/SplashXPath.h
+++ b/splash/SplashXPath.h
@@ -32,15 +32,11 @@ struct SplashXPathSeg {
Guint flags;
};
-#define splashXPathFirst 0x01 // first segment of a subpath
-#define splashXPathLast 0x02 // last segment of a subpath
-#define splashXPathEnd0 0x04 // first endpoint is end of an open subpath
-#define splashXPathEnd1 0x08 // second endpoint is end of an open subpath
-#define splashXPathHoriz 0x10 // segment is vertical (y0 == y1)
+#define splashXPathHoriz 0x01 // segment is vertical (y0 == y1)
// (dxdy is undef)
-#define splashXPathVert 0x20 // segment is horizontal (x0 == x1)
+#define splashXPathVert 0x02 // segment is horizontal (x0 == x1)
// (dydx is undef)
-#define splashXPathFlip 0x40 // y0 > y1
+#define splashXPathFlip 0x04 // y0 > y1
//------------------------------------------------------------------------
// SplashXPath
@@ -70,7 +66,6 @@ public:
protected:
- SplashXPath();
SplashXPath(SplashXPath *xPath);
void transform(SplashCoord *matrix, SplashCoord xi, SplashCoord yi,
SplashCoord *xo, SplashCoord *yo);
@@ -84,8 +79,7 @@ protected:
SplashCoord flatness,
GBool first, GBool last, GBool end0, GBool end1);
void addSegment(SplashCoord x0, SplashCoord y0,
- SplashCoord x1, SplashCoord y1,
- GBool first, GBool last, GBool end0, GBool end1);
+ SplashCoord x1, SplashCoord y1);
SplashXPathSeg *segs;
int length, size; // length and size of segs array
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