summaryrefslogtreecommitdiff
path: root/splash
diff options
context:
space:
mode:
authorAlbert Astals Cid <aacid@kde.org>2007-04-25 19:59:09 +0000
committerAlbert Astals Cid <aacid@kde.org>2007-04-25 19:59:09 +0000
commitbf7e0e980bf29994021cb1228f89f582adddf284 (patch)
treecec237ed204ceb988a6e74209c8beb2167a898fa /splash
parentba74bb3b0632593d1937911d73709fc870480efd (diff)
Merge xpdf302branch in HEAD as noone vetoed it.
Testing more than welcome
Diffstat (limited to 'splash')
-rw-r--r--splash/Splash.cc4402
-rw-r--r--splash/Splash.h137
-rw-r--r--splash/SplashBitmap.cc110
-rw-r--r--splash/SplashBitmap.h10
-rw-r--r--splash/SplashClip.cc276
-rw-r--r--splash/SplashClip.h28
-rw-r--r--splash/SplashFTFont.cc104
-rw-r--r--splash/SplashFTFont.h5
-rw-r--r--splash/SplashFTFontEngine.cc54
-rw-r--r--splash/SplashFTFontEngine.h9
-rw-r--r--splash/SplashFTFontFile.cc19
-rw-r--r--splash/SplashFTFontFile.h9
-rw-r--r--splash/SplashFont.cc6
-rw-r--r--splash/SplashFont.h13
-rw-r--r--splash/SplashFontEngine.cc72
-rw-r--r--splash/SplashFontEngine.h11
-rw-r--r--splash/SplashFontFile.cc1
-rw-r--r--splash/SplashFontFile.h2
-rw-r--r--splash/SplashMath.h15
-rw-r--r--splash/SplashPath.cc42
-rw-r--r--splash/SplashPath.h31
-rw-r--r--splash/SplashPattern.cc28
-rw-r--r--splash/SplashPattern.h25
-rw-r--r--splash/SplashScreen.cc304
-rw-r--r--splash/SplashScreen.h18
-rw-r--r--splash/SplashState.cc63
-rw-r--r--splash/SplashState.h14
-rw-r--r--splash/SplashT1Font.cc101
-rw-r--r--splash/SplashT1Font.h6
-rw-r--r--splash/SplashT1FontEngine.cc4
-rw-r--r--splash/SplashT1FontFile.cc9
-rw-r--r--splash/SplashT1FontFile.h7
-rw-r--r--splash/SplashTypes.h72
-rw-r--r--splash/SplashXPath.cc353
-rw-r--r--splash/SplashXPath.h26
-rw-r--r--splash/SplashXPathScanner.cc143
-rw-r--r--splash/SplashXPathScanner.h13
37 files changed, 3747 insertions, 2795 deletions
diff --git a/splash/Splash.cc b/splash/Splash.cc
index 403766b0..0be4e581 100644
--- a/splash/Splash.cc
+++ b/splash/Splash.cc
@@ -28,23 +28,812 @@
//------------------------------------------------------------------------
-static void blendNormal(SplashColorPtr src, SplashColorPtr dest,
- SplashColorPtr blend, SplashColorMode cm) {
+// distance of Bezier control point from center for circle approximation
+// = (4 * (sqrt(2) - 1) / 3) * r
+#define bezierCircle ((SplashCoord)0.55228475)
+#define bezierCircle2 ((SplashCoord)(0.5 * 0.55228475))
+
+// Divide a 16-bit value (in [0, 255*255]) by 255, returning an 8-bit result.
+static inline Guchar div255(int x) {
+ return (Guchar)((x + (x >> 8) + 0x80) >> 8);
+}
+
+//------------------------------------------------------------------------
+// SplashPipe
+//------------------------------------------------------------------------
+
+#define splashPipeMaxStages 9
+
+struct SplashPipe {
+ // pixel coordinates
+ int x, y;
+
+ // source pattern
+ SplashPattern *pattern;
+
+ // source alpha and color
+ SplashCoord aInput;
+ GBool usesShape;
+ Guchar aSrc;
+ SplashColorPtr cSrc;
+ SplashColor cSrcVal;
+
+ // non-isolated group alpha0
+ Guchar *alpha0Ptr;
+
+ // soft mask
+ SplashColorPtr softMaskPtr;
+
+ // destination alpha and color
+ SplashColorPtr destColorPtr;
+ int destColorMask;
+ Guchar *destAlphaPtr;
+
+ // shape
+ SplashCoord shape;
+
+ // result alpha and color
+ GBool noTransparency;
+ SplashPipeResultColorCtrl resultColorCtrl;
+
+ // non-isolated group correction
+ int nonIsolatedGroup;
+};
+
+SplashPipeResultColorCtrl Splash::pipeResultColorNoAlphaBlend[] = {
+ splashPipeResultColorNoAlphaBlendMono,
+ splashPipeResultColorNoAlphaBlendMono,
+ splashPipeResultColorNoAlphaBlendRGB,
+ splashPipeResultColorNoAlphaBlendRGB
+#if SPLASH_CMYK
+ ,
+ splashPipeResultColorNoAlphaBlendCMYK
+#endif
+};
+
+SplashPipeResultColorCtrl Splash::pipeResultColorAlphaNoBlend[] = {
+ splashPipeResultColorAlphaNoBlendMono,
+ splashPipeResultColorAlphaNoBlendMono,
+ splashPipeResultColorAlphaNoBlendRGB,
+ splashPipeResultColorAlphaNoBlendRGB
+#if SPLASH_CMYK
+ ,
+ splashPipeResultColorAlphaNoBlendCMYK
+#endif
+};
+
+SplashPipeResultColorCtrl Splash::pipeResultColorAlphaBlend[] = {
+ splashPipeResultColorAlphaBlendMono,
+ splashPipeResultColorAlphaBlendMono,
+ splashPipeResultColorAlphaBlendRGB,
+ splashPipeResultColorAlphaBlendRGB
+#if SPLASH_CMYK
+ ,
+ splashPipeResultColorAlphaBlendCMYK
+#endif
+};
+
+//------------------------------------------------------------------------
+
+static void blendXor(SplashColorPtr src, SplashColorPtr dest,
+ SplashColorPtr blend, SplashColorMode cm) {
int i;
for (i = 0; i < splashColorModeNComps[cm]; ++i) {
- blend[i] = src[i];
+ blend[i] = src[i] ^ dest[i];
+ }
+}
+
+//------------------------------------------------------------------------
+// modified region
+//------------------------------------------------------------------------
+
+void Splash::clearModRegion() {
+ modXMin = bitmap->getWidth();
+ modYMin = bitmap->getHeight();
+ modXMax = -1;
+ modYMax = -1;
+}
+
+inline void Splash::updateModX(int x) {
+ if (x < modXMin) {
+ modXMin = x;
+ }
+ if (x > modXMax) {
+ modXMax = x;
+ }
+}
+
+inline void Splash::updateModY(int y) {
+ if (y < modYMin) {
+ modYMin = y;
+ }
+ if (y > modYMax) {
+ modYMax = y;
+ }
+}
+
+//------------------------------------------------------------------------
+// pipeline
+//------------------------------------------------------------------------
+
+inline void Splash::pipeInit(SplashPipe *pipe, int x, int y,
+ SplashPattern *pattern, SplashColorPtr cSrc,
+ SplashCoord aInput, GBool usesShape,
+ GBool nonIsolatedGroup) {
+ pipeSetXY(pipe, x, y);
+ pipe->pattern = NULL;
+
+ // source color
+ if (pattern) {
+ if (pattern->isStatic()) {
+ pattern->getColor(x, y, pipe->cSrcVal);
+ } else {
+ pipe->pattern = pattern;
+ }
+ pipe->cSrc = pipe->cSrcVal;
+ } else {
+ pipe->cSrc = cSrc;
+ }
+
+ // 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) {
+ pipe->noTransparency = gTrue;
+ } else {
+ pipe->noTransparency = gFalse;
+ }
+
+ // result color
+ if (pipe->noTransparency) {
+ // the !state->blendFunc case is handled separately in pipeRun
+ pipe->resultColorCtrl = pipeResultColorNoAlphaBlend[bitmap->mode];
+ } else if (!state->blendFunc) {
+ pipe->resultColorCtrl = pipeResultColorAlphaNoBlend[bitmap->mode];
+ } else {
+ pipe->resultColorCtrl = pipeResultColorAlphaBlend[bitmap->mode];
+ }
+
+ // non-isolated group correction
+ if (nonIsolatedGroup) {
+ pipe->nonIsolatedGroup = splashColorModeNComps[bitmap->mode];
+ } else {
+ pipe->nonIsolatedGroup = 0;
+ }
+}
+
+inline void Splash::pipeRun(SplashPipe *pipe) {
+ Guchar aSrc, aDest, alpha2, alpha0, aResult;
+ SplashColor cDest, cBlend;
+ Guchar cResult0, cResult1, cResult2, cResult3;
+
+ //----- source color
+
+ // static pattern: handled in pipeInit
+ // fixed color: handled in pipeInit
+
+ // dynamic pattern
+ if (pipe->pattern) {
+ pipe->pattern->getColor(pipe->x, pipe->y, pipe->cSrcVal);
+ }
+
+ if (pipe->noTransparency && !state->blendFunc) {
+
+ //----- write destination pixel
+
+ switch (bitmap->mode) {
+ case splashModeMono1:
+ cResult0 = 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;
+ }
+ break;
+ case splashModeMono8:
+ *pipe->destColorPtr++ = pipe->cSrc[0];
+ break;
+ case splashModeRGB8:
+ *pipe->destColorPtr++ = pipe->cSrc[0];
+ *pipe->destColorPtr++ = pipe->cSrc[1];
+ *pipe->destColorPtr++ = pipe->cSrc[2];
+ break;
+ case splashModeRGBX8:
+ *pipe->destColorPtr++ = pipe->cSrc[0];
+ *pipe->destColorPtr++ = pipe->cSrc[1];
+ *pipe->destColorPtr++ = pipe->cSrc[2];
+ *pipe->destColorPtr++ = 255;
+ break;
+ case splashModeBGR8:
+ *pipe->destColorPtr++ = pipe->cSrc[2];
+ *pipe->destColorPtr++ = pipe->cSrc[1];
+ *pipe->destColorPtr++ = pipe->cSrc[0];
+ break;
+#if SPLASH_CMYK
+ case splashModeCMYK8:
+ *pipe->destColorPtr++ = pipe->cSrc[0];
+ *pipe->destColorPtr++ = pipe->cSrc[1];
+ *pipe->destColorPtr++ = pipe->cSrc[2];
+ *pipe->destColorPtr++ = pipe->cSrc[3];
+ break;
+#endif
+ }
+ if (pipe->destAlphaPtr) {
+ *pipe->destAlphaPtr++ = 255;
+ }
+
+ } else {
+
+ //----- read destination pixel
+
+ switch (bitmap->mode) {
+ case splashModeMono1:
+ cDest[0] = (*pipe->destColorPtr & pipe->destColorMask) ? 0xff : 0x00;
+ break;
+ case splashModeMono8:
+ cDest[0] = *pipe->destColorPtr;
+ break;
+ case splashModeRGB8:
+ cDest[0] = pipe->destColorPtr[0];
+ cDest[1] = pipe->destColorPtr[1];
+ cDest[2] = pipe->destColorPtr[2];
+ break;
+ case splashModeRGBX8:
+ cDest[0] = pipe->destColorPtr[0];
+ cDest[1] = pipe->destColorPtr[1];
+ cDest[2] = pipe->destColorPtr[2];
+ cDest[3] = 255;
+ break;
+ case splashModeBGR8:
+ cDest[0] = pipe->destColorPtr[2];
+ cDest[1] = pipe->destColorPtr[1];
+ cDest[2] = pipe->destColorPtr[0];
+ break;
+#if SPLASH_CMYK
+ case splashModeCMYK8:
+ cDest[0] = pipe->destColorPtr[0];
+ cDest[1] = pipe->destColorPtr[1];
+ cDest[2] = pipe->destColorPtr[2];
+ cDest[3] = pipe->destColorPtr[3];
+ break;
+#endif
+ }
+ if (pipe->destAlphaPtr) {
+ aDest = *pipe->destAlphaPtr;
+ } else {
+ 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);
+ } else {
+ aSrc = (Guchar)splashRound(pipe->aInput * *pipe->softMaskPtr++);
+ }
+ } else if (pipe->usesShape) {
+ // pipe->aInput is premultiplied by 255 in pipeInit
+ aSrc = (Guchar)splashRound(pipe->aInput * pipe->shape);
+ } else {
+ // precomputed in pipeInit
+ aSrc = pipe->aSrc;
+ }
+
+ //----- result alpha and non-isolated group element correction
+
+ if (pipe->noTransparency) {
+ alpha2 = aResult = 255;
+ } else {
+ aResult = aSrc + aDest - div255(aSrc * aDest);
+
+ if (pipe->alpha0Ptr) {
+ alpha0 = *pipe->alpha0Ptr++;
+ alpha2 = aResult + alpha0 - div255(aResult * alpha0);
+ } else {
+ alpha2 = aResult;
+ }
+ }
+
+ //----- result color
+
+ cResult0 = cResult1 = cResult2 = cResult3 = 0; // make gcc happy
+
+ switch (pipe->resultColorCtrl) {
+
+#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]);
+ break;
+
+ case splashPipeResultColorAlphaNoBlendMono:
+ if (alpha2 == 0) {
+ cResult0 = 0;
+ } else {
+ cResult0 = (Guchar)(((alpha2 - aSrc) * cDest[0] +
+ aSrc * pipe->cSrc[0]) / alpha2);
+ }
+ break;
+ case splashPipeResultColorAlphaNoBlendRGB:
+ if (alpha2 == 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);
+ }
+ break;
+#if SPLASH_CMYK
+ case splashPipeResultColorAlphaNoBlendCMYK:
+ if (alpha2 == 0) {
+ cResult0 = 0;
+ cResult1 = 0;
+ cResult2 = 0;
+ cResult3 = 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);
+ cResult3 = (Guchar)(((alpha2 - aSrc) * cDest[3] +
+ aSrc * pipe->cSrc[3]) / alpha2);
+ }
+ break;
+#endif
+
+ case splashPipeResultColorAlphaBlendMono:
+ if (alpha2 == 0) {
+ cResult0 = 0;
+ } else {
+ cResult0 = (Guchar)(((alpha2 - aSrc) * cDest[0] +
+ aSrc * ((255 - aDest) * pipe->cSrc[0] +
+ aDest * cBlend[0]) / 255) /
+ alpha2);
+ }
+ break;
+ case splashPipeResultColorAlphaBlendRGB:
+ if (alpha2 == 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);
+ }
+ break;
+#if SPLASH_CMYK
+ case splashPipeResultColorAlphaBlendCMYK:
+ if (alpha2 == 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);
+ }
+ 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) {
+ case splashModeMono1:
+ if (state->screen->test(pipe->x, pipe->y, cResult0)) {
+ *pipe->destColorPtr |= pipe->destColorMask;
+ } else {
+ *pipe->destColorPtr &= ~pipe->destColorMask;
+ }
+ if (!(pipe->destColorMask >>= 1)) {
+ pipe->destColorMask = 0x80;
+ ++pipe->destColorPtr;
+ }
+ break;
+ case splashModeMono8:
+ *pipe->destColorPtr++ = cResult0;
+ break;
+ case splashModeRGB8:
+ *pipe->destColorPtr++ = cResult0;
+ *pipe->destColorPtr++ = cResult1;
+ *pipe->destColorPtr++ = cResult2;
+ break;
+ case splashModeRGBX8:
+ *pipe->destColorPtr++ = cResult0;
+ *pipe->destColorPtr++ = cResult1;
+ *pipe->destColorPtr++ = cResult2;
+ *pipe->destColorPtr++ = 255;
+ break;
+ case splashModeBGR8:
+ *pipe->destColorPtr++ = cResult2;
+ *pipe->destColorPtr++ = cResult1;
+ *pipe->destColorPtr++ = cResult0;
+ break;
+#if SPLASH_CMYK
+ case splashModeCMYK8:
+ *pipe->destColorPtr++ = cResult0;
+ *pipe->destColorPtr++ = cResult1;
+ *pipe->destColorPtr++ = cResult2;
+ *pipe->destColorPtr++ = cResult3;
+ break;
+#endif
+ }
+ if (pipe->destAlphaPtr) {
+ *pipe->destAlphaPtr++ = aResult;
+ }
+
+ }
+
+ ++pipe->x;
+}
+
+inline void Splash::pipeSetXY(SplashPipe *pipe, int x, int y) {
+ pipe->x = x;
+ pipe->y = y;
+ if (state->softMask) {
+ pipe->softMaskPtr =
+ &state->softMask->data[y * state->softMask->rowSize + x];
+ }
+ switch (bitmap->mode) {
+ case splashModeMono1:
+ pipe->destColorPtr = &bitmap->data[y * bitmap->rowSize + (x >> 3)];
+ pipe->destColorMask = 0x80 >> (x & 7);
+ break;
+ case splashModeMono8:
+ pipe->destColorPtr = &bitmap->data[y * bitmap->rowSize + x];
+ break;
+ case splashModeRGB8:
+ case splashModeBGR8:
+ pipe->destColorPtr = &bitmap->data[y * bitmap->rowSize + 3 * x];
+ break;
+ case splashModeRGBX8:
+ pipe->destColorPtr = &bitmap->data[y * bitmap->rowSize + 4 * x];
+ break;
+#if SPLASH_CMYK
+ case splashModeCMYK8:
+ pipe->destColorPtr = &bitmap->data[y * bitmap->rowSize + 4 * x];
+ break;
+#endif
+ }
+ if (bitmap->alpha) {
+ pipe->destAlphaPtr = &bitmap->alpha[y * bitmap->width + x];
+ } else {
+ pipe->destAlphaPtr = NULL;
+ }
+ if (state->inNonIsolatedGroup && alpha0Bitmap->alpha) {
+ pipe->alpha0Ptr =
+ &alpha0Bitmap->alpha[(alpha0Y + y) * alpha0Bitmap->width +
+ (alpha0X + x)];
+ } else {
+ pipe->alpha0Ptr = NULL;
+ }
+}
+
+inline void Splash::pipeIncX(SplashPipe *pipe) {
+ ++pipe->x;
+ if (state->softMask) {
+ ++pipe->softMaskPtr;
+ }
+ switch (bitmap->mode) {
+ case splashModeMono1:
+ if (!(pipe->destColorMask >>= 1)) {
+ pipe->destColorMask = 0x80;
+ ++pipe->destColorPtr;
+ }
+ break;
+ case splashModeMono8:
+ ++pipe->destColorPtr;
+ break;
+ case splashModeRGB8:
+ case splashModeBGR8:
+ pipe->destColorPtr += 3;
+ break;
+ case splashModeRGBX8:
+ pipe->destColorPtr += 4;
+ break;
+#if SPLASH_CMYK
+ case splashModeCMYK8:
+ pipe->destColorPtr += 4;
+ break;
+#endif
+ }
+ if (pipe->destAlphaPtr) {
+ ++pipe->destAlphaPtr;
+ }
+ if (pipe->alpha0Ptr) {
+ ++pipe->alpha0Ptr;
+ }
+}
+
+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);
+ updateModX(x);
+ updateModY(y);
+ }
+}
+
+inline void Splash::drawAAPixelInit() {
+ aaBufY = -1;
+}
+
+inline void Splash::drawAAPixel(SplashPipe *pipe, int x, int y) {
+#if splashAASize == 4
+ static int bitCount4[16] = { 0, 1, 1, 2, 1, 2, 2, 3,
+ 1, 2, 2, 3, 2, 3, 3, 4 };
+ int w;
+#else
+ int xx, yy;
+#endif
+ SplashColorPtr p;
+ int x0, x1, t;
+
+ if (x < 0 || x >= bitmap->width ||
+ y < state->clip->getYMinI() || y > state->clip->getYMaxI()) {
+ return;
+ }
+
+ // update aaBuf
+ if (y != aaBufY) {
+ memset(aaBuf->getDataPtr(), 0xff,
+ aaBuf->getRowSize() * aaBuf->getHeight());
+ x0 = 0;
+ x1 = bitmap->width - 1;
+ state->clip->clipAALine(aaBuf, &x0, &x1, y);
+ aaBufY = y;
+ }
+
+ // compute the shape value
+#if splashAASize == 4
+ p = aaBuf->getDataPtr() + (x >> 1);
+ w = aaBuf->getRowSize();
+ if (x & 1) {
+ t = bitCount4[*p & 0x0f] + bitCount4[p[w] & 0x0f] +
+ bitCount4[p[2*w] & 0x0f] + bitCount4[p[3*w] & 0x0f];
+ } else {
+ t = bitCount4[*p >> 4] + bitCount4[p[w] >> 4] +
+ bitCount4[p[2*w] >> 4] + bitCount4[p[3*w] >> 4];
+ }
+#else
+ t = 0;
+ for (yy = 0; yy < splashAASize; ++yy) {
+ for (xx = 0; xx < splashAASize; ++xx) {
+ p = aaBuf->getDataPtr() + yy * aaBuf->getRowSize() +
+ ((x * splashAASize + xx) >> 3);
+ t += (*p >> (7 - ((x * splashAASize + xx) & 7))) & 1;
+ }
+ }
+#endif
+
+ // draw the pixel
+ if (t != 0) {
+ pipeSetXY(pipe, x, y);
+ pipe->shape *= aaGamma[t];
+ pipeRun(pipe);
+ updateModX(x);
+ updateModY(y);
+ }
+}
+
+inline void Splash::drawSpan(SplashPipe *pipe, int x0, int x1, int y,
+ GBool noClip) {
+ int x;
+
+ pipeSetXY(pipe, x0, y);
+ if (noClip) {
+ for (x = x0; x <= x1; ++x) {
+ pipeRun(pipe);
+ }
+ updateModX(x0);
+ updateModX(x1);
+ updateModY(y);
+ } else {
+ for (x = x0; x <= x1; ++x) {
+ if (state->clip->test(x, y)) {
+ pipeRun(pipe);
+ updateModX(x);
+ updateModY(y);
+ } else {
+ pipeIncX(pipe);
+ }
+ }
+ }
+}
+
+inline void Splash::drawAALine(SplashPipe *pipe, int x0, int x1, int y) {
+#if splashAASize == 4
+ static int bitCount4[16] = { 0, 1, 1, 2, 1, 2, 2, 3,
+ 1, 2, 2, 3, 2, 3, 3, 4 };
+ SplashColorPtr p0, p1, p2, p3;
+ int t;
+#else
+ SplashColorPtr p;
+ int xx, yy, t;
+#endif
+ int x;
+
+#if splashAASize == 4
+ p0 = aaBuf->getDataPtr() + (x0 >> 1);
+ p1 = p0 + aaBuf->getRowSize();
+ p2 = p1 + aaBuf->getRowSize();
+ p3 = p2 + aaBuf->getRowSize();
+#endif
+ pipeSetXY(pipe, x0, y);
+ for (x = x0; x <= x1; ++x) {
+
+ // compute the shape value
+#if splashAASize == 4
+ if (x & 1) {
+ t = bitCount4[*p0 & 0x0f] + bitCount4[*p1 & 0x0f] +
+ bitCount4[*p2 & 0x0f] + bitCount4[*p3 & 0x0f];
+ ++p0; ++p1; ++p2; ++p3;
+ } else {
+ t = bitCount4[*p0 >> 4] + bitCount4[*p1 >> 4] +
+ bitCount4[*p2 >> 4] + bitCount4[*p3 >> 4];
+ }
+#else
+ t = 0;
+ for (yy = 0; yy < splashAASize; ++yy) {
+ for (xx = 0; xx < splashAASize; ++xx) {
+ p = aaBuf->getDataPtr() + yy * aaBuf->getRowSize() +
+ ((x * splashAASize + xx) >> 3);
+ t += (*p >> (7 - ((x * splashAASize + xx) & 7))) & 1;
+ }
+ }
+#endif
+
+ if (t != 0) {
+ pipe->shape = aaGamma[t];
+ pipeRun(pipe);
+ updateModX(x);
+ updateModY(y);
+ } else {
+ pipeIncX(pipe);
+ }
}
}
//------------------------------------------------------------------------
+
+// Transform a point from user space to device space.
+inline void Splash::transform(SplashCoord *matrix,
+ SplashCoord xi, SplashCoord yi,
+ SplashCoord *xo, SplashCoord *yo) {
+ // [ m[0] m[1] 0 ]
+ // [xo yo 1] = [xi yi 1] * [ m[2] m[3] 0 ]
+ // [ m[4] m[5] 1 ]
+ *xo = xi * matrix[0] + yi * matrix[2] + matrix[4];
+ *yo = xi * matrix[1] + yi * matrix[3] + matrix[5];
+}
+
+//------------------------------------------------------------------------
// Splash
//------------------------------------------------------------------------
-Splash::Splash(SplashBitmap *bitmapA) {
+Splash::Splash(SplashBitmap *bitmapA, GBool vectorAntialiasA,
+ SplashScreenParams *screenParams) {
+ int i;
+
+ bitmap = bitmapA;
+ vectorAntialias = vectorAntialiasA;
+ 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);
+ }
+ } else {
+ aaBuf = NULL;
+ }
+ clearModRegion();
+ debugMode = gFalse;
+}
+
+Splash::Splash(SplashBitmap *bitmapA, GBool vectorAntialiasA,
+ SplashScreen *screenA) {
+ int i;
+
bitmap = bitmapA;
- state = new SplashState(bitmap->width, bitmap->height);
- softMask = NULL;
+ vectorAntialias = vectorAntialiasA;
+ state = new SplashState(bitmap->width, bitmap->height, vectorAntialias,
+ screenA);
+ 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);
+ }
+ } else {
+ aaBuf = NULL;
+ }
clearModRegion();
debugMode = gFalse;
}
@@ -54,8 +843,8 @@ Splash::~Splash() {
restoreState();
}
delete state;
- if (softMask) {
- delete softMask;
+ if (vectorAntialias) {
+ delete aaBuf;
}
}
@@ -63,6 +852,10 @@ Splash::~Splash() {
// state read
//------------------------------------------------------------------------
+SplashCoord *Splash::getMatrix() {
+ return state->matrix;
+}
+
SplashPattern *Splash::getStrokePattern() {
return state->strokePattern;
}
@@ -123,10 +916,22 @@ SplashClip *Splash::getClip() {
return state->clip;
}
+SplashBitmap *Splash::getSoftMask() {
+ return state->softMask;
+}
+
+GBool Splash::getInNonIsolatedGroup() {
+ return state->inNonIsolatedGroup;
+}
+
//------------------------------------------------------------------------
// state write
//------------------------------------------------------------------------
+void Splash::setMatrix(SplashCoord *matrix) {
+ memcpy(state->matrix, matrix, 6 * sizeof(SplashCoord));
+}
+
void Splash::setStrokePattern(SplashPattern *strokePattern) {
state->setStrokePattern(strokePattern);
}
@@ -180,6 +985,10 @@ void Splash::setLineDash(SplashCoord *lineDash, int lineDashLength,
state->setLineDash(lineDash, lineDashLength, lineDashPhase);
}
+void Splash::setStrokeAdjust(GBool strokeAdjust) {
+ state->strokeAdjust = strokeAdjust;
+}
+
void Splash::clipResetToRect(SplashCoord x0, SplashCoord y0,
SplashCoord x1, SplashCoord y1) {
state->clip->resetToRect(x0, y0, x1, y1);
@@ -191,7 +1000,19 @@ SplashError Splash::clipToRect(SplashCoord x0, SplashCoord y0,
}
SplashError Splash::clipToPath(SplashPath *path, GBool eo) {
- return state->clip->clipToPath(path, state->flatness, eo);
+ return state->clip->clipToPath(path, state->matrix, state->flatness, eo);
+}
+
+void Splash::setSoftMask(SplashBitmap *softMask) {
+ state->setSoftMask(softMask);
+}
+
+void Splash::setInNonIsolatedGroup(SplashBitmap *alpha0BitmapA,
+ int alpha0XA, int alpha0YA) {
+ alpha0Bitmap = alpha0BitmapA;
+ alpha0X = alpha0XA;
+ alpha0Y = alpha0YA;
+ state->inNonIsolatedGroup = gTrue;
}
//------------------------------------------------------------------------
@@ -219,57 +1040,17 @@ SplashError Splash::restoreState() {
}
//------------------------------------------------------------------------
-// soft mask
-//------------------------------------------------------------------------
-
-void Splash::setSoftMask(SplashBitmap *softMaskA) {
- if (softMask) {
- delete softMask;
- }
- softMask = softMaskA;
-}
-
-//------------------------------------------------------------------------
-// modified region
-//------------------------------------------------------------------------
-
-void Splash::clearModRegion() {
- modXMin = bitmap->getWidth();
- modYMin = bitmap->getHeight();
- modXMax = -1;
- modYMax = -1;
-}
-
-inline void Splash::updateModX(int x) {
- if (x < modXMin) {
- modXMin = x;
- }
- if (x > modXMax) {
- modXMax = x;
- }
-}
-
-inline void Splash::updateModY(int y) {
- if (y < modYMin) {
- modYMin = y;
- }
- if (y > modYMax) {
- modYMax = y;
- }
-}
-
-//------------------------------------------------------------------------
// drawing operations
//------------------------------------------------------------------------
-void Splash::clear(SplashColorPtr color) {
+void Splash::clear(SplashColorPtr color, Guchar alpha) {
SplashColorPtr row, p;
Guchar mono;
int x, y;
switch (bitmap->mode) {
case splashModeMono1:
- mono = color[0] ? 0xff : 0x00;
+ mono = (color[0] & 0x80) ? 0xff : 0x00;
if (bitmap->rowSize < 0) {
memset(bitmap->data + bitmap->rowSize * (bitmap->height - 1),
mono, -bitmap->rowSize * bitmap->height);
@@ -285,28 +1066,7 @@ void Splash::clear(SplashColorPtr color) {
memset(bitmap->data, color[0], bitmap->rowSize * bitmap->height);
}
break;
- case splashModeAMono8:
- if (color[0] == color[1]) {
- if (bitmap->rowSize < 0) {
- memset(bitmap->data + bitmap->rowSize * (bitmap->height - 1),
- color[0], -bitmap->rowSize * bitmap->height);
- } else {
- memset(bitmap->data, color[0], bitmap->rowSize * bitmap->height);
- }
- } else {
- row = bitmap->data;
- for (y = 0; y < bitmap->height; ++y) {
- p = row;
- for (x = 0; x < bitmap->width; ++x) {
- *p++ = color[0];
- *p++ = color[1];
- }
- row += bitmap->rowSize;
- }
- }
- break;
case splashModeRGB8:
- case splashModeBGR8:
if (color[0] == color[1] && color[1] == color[2]) {
if (bitmap->rowSize < 0) {
memset(bitmap->data + bitmap->rowSize * (bitmap->height - 1),
@@ -319,15 +1079,15 @@ void Splash::clear(SplashColorPtr color) {
for (y = 0; y < bitmap->height; ++y) {
p = row;
for (x = 0; x < bitmap->width; ++x) {
- *p++ = color[0];
- *p++ = color[1];
*p++ = color[2];
+ *p++ = color[1];
+ *p++ = color[0];
}
row += bitmap->rowSize;
}
}
break;
- case splashModeRGB8Qt:
+ case splashModeRGBX8:
if (color[0] == color[1] && color[1] == color[2]) {
if (bitmap->rowSize < 0) {
memset(bitmap->data + bitmap->rowSize * (bitmap->height - 1),
@@ -349,12 +1109,8 @@ void Splash::clear(SplashColorPtr color) {
}
}
break;
- case splashModeARGB8:
- case splashModeBGRA8:
-#if SPLASH_CMYK
- case splashModeCMYK8:
-#endif
- if (color[0] == color[1] && color[1] == color[2] && color[2] == color[3]) {
+ case splashModeBGR8:
+ if (color[0] == color[1] && color[1] == color[2]) {
if (bitmap->rowSize < 0) {
memset(bitmap->data + bitmap->rowSize * (bitmap->height - 1),
color[0], -bitmap->rowSize * bitmap->height);
@@ -369,16 +1125,14 @@ void Splash::clear(SplashColorPtr color) {
*p++ = color[0];
*p++ = color[1];
*p++ = color[2];
- *p++ = color[3];
}
row += bitmap->rowSize;
}
}
break;
#if SPLASH_CMYK
- case splashModeACMYK8:
- if (color[0] == color[1] && color[1] == color[2] &&
- color[2] == color[3] && color[3] == color[4]) {
+ case splashModeCMYK8:
+ if (color[0] == color[1] && color[1] == color[2] && color[2] == color[3]) {
if (bitmap->rowSize < 0) {
memset(bitmap->data + bitmap->rowSize * (bitmap->height - 1),
color[0], -bitmap->rowSize * bitmap->height);
@@ -394,7 +1148,6 @@ void Splash::clear(SplashColorPtr color) {
*p++ = color[1];
*p++ = color[2];
*p++ = color[3];
- *p++ = color[4];
}
row += bitmap->rowSize;
}
@@ -403,6 +1156,10 @@ void Splash::clear(SplashColorPtr color) {
#endif
}
+ if (bitmap->alpha) {
+ memset(bitmap->alpha, alpha, bitmap->width * bitmap->height);
+ }
+
updateModX(0);
updateModY(0);
updateModX(bitmap->width - 1);
@@ -410,7 +1167,7 @@ void Splash::clear(SplashColorPtr color) {
}
SplashError Splash::stroke(SplashPath *path) {
- SplashXPath *xPath, *xPath2;
+ SplashPath *path2, *dPath;
if (debugMode) {
printf("stroke [dash:%d] [width:%.2f]:\n",
@@ -421,33 +1178,38 @@ SplashError Splash::stroke(SplashPath *path) {
if (path->length == 0) {
return splashErrEmptyPath;
}
- xPath = new SplashXPath(path, state->flatness, gFalse);
- if (xPath->length == 0) {
- delete xPath;
- return splashErrEmptyPath;
- }
+ path2 = flattenPath(path, state->matrix, state->flatness);
if (state->lineDashLength > 0) {
- xPath2 = makeDashedPath(xPath);
- delete xPath;
- xPath = xPath2;
+ dPath = makeDashedPath(path2);
+ delete path2;
+ path2 = dPath;
}
- if (state->lineWidth <= 1) {
- strokeNarrow(xPath);
+ if (state->lineWidth == 0) {
+ strokeNarrow(path2);
} else {
- strokeWide(xPath);
+ strokeWide(path2);
}
- delete xPath;
+ delete path2;
return splashOk;
}
-void Splash::strokeNarrow(SplashXPath *xPath) {
+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;
SplashClipResult clipRes;
- int nClipRes[3] = {0, 0, 0};
+ int nClipRes[3];
int i;
+ nClipRes[0] = nClipRes[1] = nClipRes[2] = 0;
+
+ xPath = new SplashXPath(path, state->matrix, state->flatness, gFalse);
+
+ pipeInit(&pipe, 0, 0, state->strokePattern, NULL, state->strokeAlpha,
+ gFalse, gFalse);
+
for (i = 0, seg = xPath->segs; i < xPath->length; ++i, ++seg) {
x0 = splashFloor(seg->x0);
@@ -462,8 +1224,7 @@ void Splash::strokeNarrow(SplashXPath *xPath) {
}
if ((clipRes = state->clip->testSpan(x0, x1, y0))
!= splashClipAllOutside) {
- drawSpan(x0, x1, y0, state->strokePattern, state->strokeAlpha,
- clipRes == splashClipAllInside);
+ drawSpan(&pipe, x0, x1, y0, clipRes == splashClipAllInside);
}
// segment with |dx| > |dy|
@@ -483,31 +1244,29 @@ void Splash::strokeNarrow(SplashXPath *xPath) {
if (dx > 0) {
x2 = x0;
x3 = splashFloor(seg->x0 + ((SplashCoord)y0 + 1 - seg->y0) * dxdy);
- drawSpan(x2, (x2 <= x3 - 1) ? x3 - 1 : x2, y0, state->strokePattern,
- state->strokeAlpha, clipRes == splashClipAllInside);
+ 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(x2, x3 - 1, y, state->strokePattern,
- state->strokeAlpha, clipRes == splashClipAllInside);
+ drawSpan(&pipe, x2, x3 - 1, y, clipRes == splashClipAllInside);
x2 = x3;
}
- drawSpan(x2, x2 <= x1 ? x1 : x2, y1, state->strokePattern,
- state->strokeAlpha, clipRes == splashClipAllInside);
+ drawSpan(&pipe, x2, x2 <= x1 ? x1 : x2, y1,
+ clipRes == splashClipAllInside);
} else {
x2 = x0;
x3 = splashFloor(seg->x0 + ((SplashCoord)y0 + 1 - seg->y0) * dxdy);
- drawSpan((x3 + 1 <= x2) ? x3 + 1 : x2, x2, y0, state->strokePattern,
- state->strokeAlpha, clipRes == splashClipAllInside);
+ 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(x3 + 1, x2, y, state->strokePattern,
- state->strokeAlpha, clipRes == splashClipAllInside);
+ drawSpan(&pipe, x3 + 1, x2, y, clipRes == splashClipAllInside);
x2 = x3;
}
- drawSpan(x1, (x1 <= x2) ? x2 : x1, y1, state->strokePattern,
- state->strokeAlpha, clipRes == splashClipAllInside);
+ drawSpan(&pipe, x1, (x1 <= x2) ? x2 : x1, y1,
+ clipRes == splashClipAllInside);
}
}
@@ -521,16 +1280,13 @@ void Splash::strokeNarrow(SplashXPath *xPath) {
if ((clipRes = state->clip->testRect(x0 <= x1 ? x0 : x1, y0,
x0 <= x1 ? x1 : x0, y1))
!= splashClipAllOutside) {
- drawPixel(x0, y0, state->strokePattern, state->strokeAlpha,
- clipRes == splashClipAllInside);
+ drawPixel(&pipe, x0, y0, clipRes == splashClipAllInside);
for (y = y0 + 1; y <= y1 - 1; ++y) {
x = splashFloor(seg->x0 + ((SplashCoord)y - seg->y0) * dxdy);
- drawPixel(x, y, state->strokePattern, state->strokeAlpha,
- clipRes == splashClipAllInside);
+ drawPixel(&pipe, x, y, clipRes == splashClipAllInside);
}
- drawPixel(x1, y1, state->strokePattern, state->strokeAlpha,
- clipRes == splashClipAllInside);
- }
+ drawPixel(&pipe, x1, y1, clipRes == splashClipAllInside);
+ }
}
++nClipRes[clipRes];
}
@@ -542,187 +1298,140 @@ void Splash::strokeNarrow(SplashXPath *xPath) {
} else {
opClipRes = splashClipAllOutside;
}
-}
-void Splash::strokeWide(SplashXPath *xPath) {
- SplashXPathSeg *seg, *seg2;
- SplashPath *widePath;
- SplashCoord d, dx, dy, wdx, wdy, dxPrev, dyPrev, wdxPrev, wdyPrev;
- SplashCoord dotprod, miter;
- int i, j;
+ delete xPath;
+}
- dx = dy = wdx = wdy = 0; // make gcc happy
- dxPrev = dyPrev = wdxPrev = wdyPrev = 0; // make gcc happy
+void Splash::strokeWide(SplashPath *path) {
+ SplashPath *path2;
- for (i = 0, seg = xPath->segs; i < xPath->length; ++i, ++seg) {
+ path2 = makeStrokePath(path, gFalse);
+ fillWithPattern(path2, gFalse, state->strokePattern, state->strokeAlpha);
+ delete path2;
+}
- // save the deltas for the previous segment; if this is the first
- // segment on a subpath, compute the deltas for the last segment
- // on the subpath (which may be used to draw a line join)
- if (seg->flags & splashXPathFirst) {
- for (j = i + 1, seg2 = &xPath->segs[j]; j < xPath->length; ++j, ++seg2) {
- if (seg2->flags & splashXPathLast) {
- d = splashDist(seg2->x0, seg2->y0, seg2->x1, seg2->y1);
- if (d == 0) {
- //~ not clear what the behavior should be for joins with d==0
- dxPrev = 0;
- dyPrev = 1;
- } else {
- d = (SplashCoord)1 / d;
- dxPrev = d * (seg2->x1 - seg2->x0);
- dyPrev = d * (seg2->y1 - seg2->y0);
- }
- wdxPrev = (SplashCoord)0.5 * state->lineWidth * dxPrev;
- wdyPrev = (SplashCoord)0.5 * state->lineWidth * dyPrev;
- break;
- }
- }
- } else {
- dxPrev = dx;
- dyPrev = dy;
- wdxPrev = wdx;
- wdyPrev = wdy;
- }
+SplashPath *Splash::flattenPath(SplashPath *path, SplashCoord *matrix,
+ SplashCoord flatness) {
+ SplashPath *fPath;
+ SplashCoord flatness2;
+ Guchar flag;
+ int i;
- // compute deltas for this line segment
- d = splashDist(seg->x0, seg->y0, seg->x1, seg->y1);
- 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;
+ fPath = new SplashPath();
+ flatness2 = flatness * flatness;
+ i = 0;
+ while (i < path->length) {
+ flag = path->flags[i];
+ if (flag & splashPathFirst) {
+ fPath->moveTo(path->pts[i].x, path->pts[i].y);
+ ++i;
} else {
- d = (SplashCoord)1 / d;
- dx = d * (seg->x1 - seg->x0);
- dy = d * (seg->y1 - seg->y0);
- }
- wdx = (SplashCoord)0.5 * state->lineWidth * dx;
- wdy = (SplashCoord)0.5 * state->lineWidth * dy;
-
- // initialize the path (which will be filled)
- widePath = new SplashPath();
- widePath->moveTo(seg->x0 - wdy, seg->y0 + wdx);
-
- // draw the start cap
- if (seg->flags & splashXPathEnd0) {
- switch (state->lineCap) {
- case splashLineCapButt:
- widePath->lineTo(seg->x0 + wdy, seg->y0 - wdx);
- break;
- case splashLineCapRound:
- widePath->arcCWTo(seg->x0 + wdy, seg->y0 - wdx, seg->x0, seg->y0);
- break;
- case splashLineCapProjecting:
- widePath->lineTo(seg->x0 - wdx - wdy, seg->y0 + wdx - wdy);
- widePath->lineTo(seg->x0 - wdx + wdy, seg->y0 - wdx - wdy);
- widePath->lineTo(seg->x0 + wdy, seg->y0 - wdx);
- break;
+ if (flag & splashPathCurve) {
+ flattenCurve(path->pts[i-1].x, path->pts[i-1].y,
+ path->pts[i ].x, path->pts[i ].y,
+ path->pts[i+1].x, path->pts[i+1].y,
+ path->pts[i+2].x, path->pts[i+2].y,
+ matrix, flatness2, fPath);
+ i += 3;
+ } else {
+ fPath->lineTo(path->pts[i].x, path->pts[i].y);
+ ++i;
+ }
+ if (path->flags[i-1] & splashPathClosed) {
+ fPath->close();
}
- } else {
- widePath->lineTo(seg->x0 + wdy, seg->y0 - wdx);
}
+ }
+ return fPath;
+}
- // draw the left side of the segment
- widePath->lineTo(seg->x1 + wdy, seg->y1 - wdx);
-
- // draw the end cap
- if (seg->flags & splashXPathEnd1) {
- switch (state->lineCap) {
- case splashLineCapButt:
- widePath->lineTo(seg->x1 - wdy, seg->y1 + wdx);
- break;
- case splashLineCapRound:
- widePath->arcCWTo(seg->x1 - wdy, seg->y1 + wdx, seg->x1, seg->y1);
- break;
- case splashLineCapProjecting:
- widePath->lineTo(seg->x1 + wdx + wdy, seg->y1 - wdx + wdy);
- widePath->lineTo(seg->x1 + wdx - wdy, seg->y1 + wdx + wdy);
- widePath->lineTo(seg->x1 - wdy, seg->y1 + wdx);
- break;
- }
+void Splash::flattenCurve(SplashCoord x0, SplashCoord y0,
+ SplashCoord x1, SplashCoord y1,
+ SplashCoord x2, SplashCoord y2,
+ SplashCoord x3, SplashCoord y3,
+ SplashCoord *matrix, SplashCoord flatness2,
+ SplashPath *fPath) {
+ SplashCoord cx[splashMaxCurveSplits + 1][3];
+ SplashCoord cy[splashMaxCurveSplits + 1][3];
+ int cNext[splashMaxCurveSplits + 1];
+ SplashCoord xl0, xl1, xl2, xr0, xr1, xr2, xr3, xx1, xx2, xh;
+ SplashCoord yl0, yl1, yl2, yr0, yr1, yr2, yr3, yy1, yy2, yh;
+ SplashCoord dx, dy, mx, my, tx, ty, d1, d2;
+ int p1, p2, p3;
+
+ // initial segment
+ p1 = 0;
+ p2 = splashMaxCurveSplits;
+ cx[p1][0] = x0; cy[p1][0] = y0;
+ cx[p1][1] = x1; cy[p1][1] = y1;
+ cx[p1][2] = x2; cy[p1][2] = y2;
+ cx[p2][0] = x3; cy[p2][0] = y3;
+ cNext[p1] = p2;
+
+ while (p1 < splashMaxCurveSplits) {
+
+ // get the next segment
+ xl0 = cx[p1][0]; yl0 = cy[p1][0];
+ xx1 = cx[p1][1]; yy1 = cy[p1][1];
+ xx2 = cx[p1][2]; yy2 = cy[p1][2];
+ p2 = cNext[p1];
+ xr3 = cx[p2][0]; yr3 = cy[p2][0];
+
+ // compute the distances (in device space) from the control points
+ // to the midpoint of the straight line (this is a bit of a hack,
+ // but it's much faster than computing the actual distances to the
+ // line)
+ transform(matrix, (xl0 + xr3) * 0.5, (yl0 + yr3) * 0.5, &mx, &my);
+ transform(matrix, xx1, yy1, &tx, &ty);
+ dx = tx - mx;
+ dy = ty - my;
+ d1 = dx*dx + dy*dy;
+ transform(matrix, xx2, yy2, &tx, &ty);
+ dx = tx - mx;
+ dy = ty - my;
+ d2 = dx*dx + dy*dy;
+
+ // 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)) {
+ fPath->lineTo(xr3, yr3);
+ p1 = p2;
+
+ // otherwise, subdivide the curve
} else {
- widePath->lineTo(seg->x1 - wdy, seg->y1 + wdx);
- }
-
- // draw the right side of the segment
- widePath->lineTo(seg->x0 - wdy, seg->y0 + wdx);
-
- // fill the segment
- fillWithPattern(widePath, gTrue, state->strokePattern, state->strokeAlpha);
- delete widePath;
-
- // draw the line join
- if (!(seg->flags & splashXPathEnd0)) {
- widePath = NULL;
- switch (state->lineJoin) {
- case splashLineJoinMiter:
- dotprod = -(dx * dxPrev + dy * dyPrev);
- if (splashAbs(splashAbs(dotprod) - 1) > 0.01) {
- widePath = new SplashPath();
- widePath->moveTo(seg->x0, seg->y0);
- miter = (SplashCoord)2 / ((SplashCoord)1 - dotprod);
- if (splashSqrt(miter) <= state->miterLimit) {
- miter = splashSqrt(miter - 1);
- if (dy * dxPrev > dx * dyPrev) {
- widePath->lineTo(seg->x0 + wdyPrev, seg->y0 - wdxPrev);
- widePath->lineTo(seg->x0 + wdy - miter * wdx,
- seg->y0 - wdx - miter * wdy);
- widePath->lineTo(seg->x0 + wdy, seg->y0 - wdx);
- } else {
- widePath->lineTo(seg->x0 - wdyPrev, seg->y0 + wdxPrev);
- widePath->lineTo(seg->x0 - wdy - miter * wdx,
- seg->y0 + wdx - miter * wdy);
- widePath->lineTo(seg->x0 - wdy, seg->y0 + wdx);
- }
- } else {
- if (dy * dxPrev > dx * dyPrev) {
- widePath->lineTo(seg->x0 + wdyPrev, seg->y0 - wdxPrev);
- widePath->lineTo(seg->x0 + wdy, seg->y0 - wdx);
- } else {
- widePath->lineTo(seg->x0 - wdyPrev, seg->y0 + wdxPrev);
- widePath->lineTo(seg->x0 - wdy, seg->y0 + wdx);
- }
- }
- }
- break;
- case splashLineJoinRound:
- widePath = new SplashPath();
- widePath->moveTo(seg->x0 + wdy, seg->y0 - wdx);
- widePath->arcCWTo(seg->x0 + wdy, seg->y0 - wdx, seg->x0, seg->y0);
- break;
- case splashLineJoinBevel:
- widePath = new SplashPath();
- widePath->moveTo(seg->x0, seg->y0);
- if (dy * dxPrev > dx * dyPrev) {
- widePath->lineTo(seg->x0 + wdyPrev, seg->y0 - wdxPrev);
- widePath->lineTo(seg->x0 + wdy, seg->y0 - wdx);
- } else {
- widePath->lineTo(seg->x0 - wdyPrev, seg->y0 + wdxPrev);
- widePath->lineTo(seg->x0 - wdy, seg->y0 + wdx);
- }
- break;
- }
- if (widePath) {
- fillWithPattern(widePath, gTrue, state->strokePattern,
- state->strokeAlpha);
- delete widePath;
- }
+ 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;
+ // add the new subdivision points
+ p3 = (p1 + p2) / 2;
+ cx[p1][1] = xl1; cy[p1][1] = yl1;
+ cx[p1][2] = xl2; cy[p1][2] = yl2;
+ cNext[p1] = p3;
+ cx[p3][0] = xr0; cy[p3][0] = yr0;
+ cx[p3][1] = xr1; cy[p3][1] = yr1;
+ cx[p3][2] = xr2; cy[p3][2] = yr2;
+ cNext[p3] = p2;
}
}
}
-SplashXPath *Splash::makeDashedPath(SplashXPath *xPath) {
- SplashXPath *dPath;
- GBool lineDashStartOn, lineDashOn;
- GBool atSegStart, atSegEnd, atDashStart, atDashEnd;
- int lineDashStartIdx, lineDashIdx, subpathStart;
- SplashCoord lineDashTotal, lineDashStartPhase, lineDashDist;
- int segIdx;
- SplashXPathSeg *seg;
- SplashCoord sx0, sy0, sx1, sy1, ax0, ay0, ax1, ay1, dist;
- int i;
-
- dPath = new SplashXPath();
+SplashPath *Splash::makeDashedPath(SplashPath *path) {
+ SplashPath *dPath;
+ SplashCoord lineDashTotal;
+ SplashCoord lineDashStartPhase, lineDashDist, segLen;
+ SplashCoord x0, y0, x1, y1, xa, ya;
+ GBool lineDashStartOn, lineDashOn, newPath;
+ int lineDashStartIdx, lineDashIdx;
+ int i, j, k;
lineDashTotal = 0;
for (i = 0; i < state->lineDashLength; ++i) {
@@ -739,85 +1448,75 @@ SplashXPath *Splash::makeDashedPath(SplashXPath *xPath) {
++lineDashStartIdx;
}
- segIdx = 0;
- seg = xPath->segs;
- sx0 = seg->x0;
- sy0 = seg->y0;
- sx1 = seg->x1;
- sy1 = seg->y1;
- dist = splashDist(sx0, sy0, sx1, sy1);
- lineDashOn = lineDashStartOn;
- lineDashIdx = lineDashStartIdx;
- lineDashDist = state->lineDash[lineDashIdx] - lineDashStartPhase;
- atSegStart = gTrue;
- atDashStart = gTrue;
- subpathStart = dPath->length;
-
- while (segIdx < xPath->length) {
-
- ax0 = sx0;
- ay0 = sy0;
- if (dist <= lineDashDist) {
- ax1 = sx1;
- ay1 = sy1;
- lineDashDist -= dist;
- dist = 0;
- atSegEnd = gTrue;
- atDashEnd = lineDashDist == 0 || (seg->flags & splashXPathLast);
- } else {
- ax1 = sx0 + (lineDashDist / dist) * (sx1 - sx0);
- ay1 = sy0 + (lineDashDist / dist) * (sy1 - sy0);
- sx0 = ax1;
- sy0 = ay1;
- dist -= lineDashDist;
- lineDashDist = 0;
- atSegEnd = gFalse;
- atDashEnd = gTrue;
- }
-
- if (lineDashOn) {
- dPath->addSegment(ax0, ay0, ax1, ay1,
- atDashStart, atDashEnd,
- atDashStart, atDashEnd);
- // end of closed subpath
- if (atSegEnd &&
- (seg->flags & splashXPathLast) &&
- !(seg->flags & splashXPathEnd1)) {
- dPath->segs[subpathStart].flags &= ~splashXPathEnd0;
- dPath->segs[dPath->length - 1].flags &= ~splashXPathEnd1;
- }
- }
-
- if (atDashEnd) {
- lineDashOn = !lineDashOn;
- if (++lineDashIdx == state->lineDashLength) {
- lineDashIdx = 0;
- }
- lineDashDist = state->lineDash[lineDashIdx];
- atDashStart = gTrue;
- } else {
- atDashStart = gFalse;
- }
- if (atSegEnd) {
- if (++segIdx < xPath->length) {
- ++seg;
- sx0 = seg->x0;
- sy0 = seg->y0;
- sx1 = seg->x1;
- sy1 = seg->y1;
- dist = splashDist(sx0, sy0, sx1, sy1);
- if (seg->flags & splashXPathFirst) {
- lineDashOn = lineDashStartOn;
- lineDashIdx = lineDashStartIdx;
- lineDashDist = state->lineDash[lineDashIdx] - lineDashStartPhase;
- atDashStart = gTrue;
- subpathStart = dPath->length;
+ dPath = new SplashPath();
+
+ // process each subpath
+ i = 0;
+ while (i < path->length) {
+
+ // find the end of the subpath
+ for (j = i;
+ j < path->length - 1 && !(path->flags[j] & splashPathLast);
+ ++j) ;
+
+ // initialize the dash parameters
+ lineDashOn = lineDashStartOn;
+ lineDashIdx = lineDashStartIdx;
+ lineDashDist = state->lineDash[lineDashIdx] - lineDashStartPhase;
+
+ // process each segment of the subpath
+ newPath = gTrue;
+ for (k = i; k < j; ++k) {
+
+ // grab the segment
+ x0 = path->pts[k].x;
+ y0 = path->pts[k].y;
+ x1 = path->pts[k+1].x;
+ y1 = path->pts[k+1].y;
+ segLen = splashDist(x0, y0, x1, y1);
+
+ // process the segment
+ while (segLen > 0) {
+
+ if (lineDashDist >= segLen) {
+ if (lineDashOn) {
+ if (newPath) {
+ dPath->moveTo(x0, y0);
+ newPath = gFalse;
+ }
+ dPath->lineTo(x1, y1);
+ }
+ lineDashDist -= segLen;
+ segLen = 0;
+
+ } else {
+ xa = x0 + (lineDashDist / segLen) * (x1 - x0);
+ ya = y0 + (lineDashDist / segLen) * (y1 - y0);
+ if (lineDashOn) {
+ if (newPath) {
+ dPath->moveTo(x0, y0);
+ newPath = gFalse;
+ }
+ dPath->lineTo(xa, ya);
+ }
+ x0 = xa;
+ y0 = ya;
+ segLen -= lineDashDist;
+ lineDashDist = 0;
+ }
+
+ // get the next entry in the dash array
+ if (lineDashDist <= 0) {
+ lineDashOn = !lineDashOn;
+ if (++lineDashIdx == state->lineDashLength) {
+ lineDashIdx = 0;
+ }
+ lineDashDist = state->lineDash[lineDashIdx];
+ newPath = gTrue;
}
}
- atSegStart = gTrue;
- } else {
- atSegStart = gFalse;
}
+ i = j + 1;
}
return dPath;
@@ -834,6 +1533,7 @@ SplashError Splash::fill(SplashPath *path, GBool eo) {
SplashError Splash::fillWithPattern(SplashPath *path, GBool eo,
SplashPattern *pattern,
SplashCoord alpha) {
+ SplashPipe pipe;
SplashXPath *xPath;
SplashXPathScanner *scanner;
int xMinI, yMinI, xMaxI, yMaxI, x0, x1, y;
@@ -842,40 +1542,59 @@ SplashError Splash::fillWithPattern(SplashPath *path, GBool eo,
if (path->length == 0) {
return splashErrEmptyPath;
}
- xPath = new SplashXPath(path, state->flatness, gTrue);
+ xPath = new SplashXPath(path, state->matrix, state->flatness, gTrue);
+ if (vectorAntialias) {
+ xPath->aaScale();
+ }
xPath->sort();
scanner = new SplashXPathScanner(xPath, eo);
// get the min and max x and y values
- scanner->getBBox(&xMinI, &yMinI, &xMaxI, &yMaxI);
+ if (vectorAntialias) {
+ scanner->getBBoxAA(&xMinI, &yMinI, &xMaxI, &yMaxI);
+ } else {
+ scanner->getBBox(&xMinI, &yMinI, &xMaxI, &yMaxI);
+ }
// check clipping
if ((clipRes = state->clip->testRect(xMinI, yMinI, xMaxI, yMaxI))
!= splashClipAllOutside) {
// limit the y range
- if (yMinI < state->clip->getYMin()) {
- yMinI = state->clip->getYMin();
+ if (yMinI < state->clip->getYMinI()) {
+ yMinI = state->clip->getYMinI();
}
- if (yMaxI > state->clip->getYMax()) {
- yMaxI = state->clip->getYMax();
+ if (yMaxI > state->clip->getYMaxI()) {
+ yMaxI = state->clip->getYMaxI();
}
+ pipeInit(&pipe, 0, yMinI, pattern, NULL, alpha, vectorAntialias, gFalse);
+
// draw the spans
- for (y = yMinI; y <= yMaxI; ++y) {
- while (scanner->getNextSpan(y, &x0, &x1)) {
- if (clipRes == splashClipAllInside) {
- drawSpan(x0, x1, y, pattern, alpha, gTrue);
- } else {
- // limit the x range
- if (x0 < state->clip->getXMin()) {
- x0 = state->clip->getXMin();
- }
- if (x1 > state->clip->getXMax()) {
- x1 = state->clip->getXMax();
+ if (vectorAntialias) {
+ for (y = yMinI; y <= yMaxI; ++y) {
+ scanner->renderAALine(aaBuf, &x0, &x1, y);
+ if (clipRes != splashClipAllInside) {
+ state->clip->clipAALine(aaBuf, &x0, &x1, y);
+ }
+ drawAALine(&pipe, x0, x1, y);
+ }
+ } else {
+ for (y = yMinI; y <= yMaxI; ++y) {
+ while (scanner->getNextSpan(y, &x0, &x1)) {
+ if (clipRes == splashClipAllInside) {
+ drawSpan(&pipe, x0, x1, y, gTrue);
+ } else {
+ // limit the x range
+ if (x0 < state->clip->getXMinI()) {
+ x0 = state->clip->getXMinI();
+ }
+ if (x1 > state->clip->getXMaxI()) {
+ x1 = state->clip->getXMaxI();
+ }
+ clipRes2 = state->clip->testSpan(x0, x1, y);
+ drawSpan(&pipe, x0, x1, y, clipRes2 == splashClipAllInside);
}
- clipRes2 = state->clip->testSpan(x0, x1, y);
- drawSpan(x0, x1, y, pattern, alpha, clipRes2 == splashClipAllInside);
}
}
}
@@ -888,15 +1607,17 @@ SplashError Splash::fillWithPattern(SplashPath *path, GBool eo,
}
SplashError Splash::xorFill(SplashPath *path, GBool eo) {
+ SplashPipe pipe;
SplashXPath *xPath;
SplashXPathScanner *scanner;
int xMinI, yMinI, xMaxI, yMaxI, x0, x1, y;
SplashClipResult clipRes, clipRes2;
+ SplashBlendFunc origBlendFunc;
if (path->length == 0) {
return splashErrEmptyPath;
}
- xPath = new SplashXPath(path, state->flatness, gTrue);
+ xPath = new SplashXPath(path, state->matrix, state->flatness, gTrue);
xPath->sort();
scanner = new SplashXPathScanner(xPath, eo);
@@ -908,32 +1629,36 @@ SplashError Splash::xorFill(SplashPath *path, GBool eo) {
!= splashClipAllOutside) {
// limit the y range
- if (yMinI < state->clip->getYMin()) {
- yMinI = state->clip->getYMin();
+ if (yMinI < state->clip->getYMinI()) {
+ yMinI = state->clip->getYMinI();
}
- if (yMaxI > state->clip->getYMax()) {
- yMaxI = state->clip->getYMax();
+ if (yMaxI > state->clip->getYMaxI()) {
+ yMaxI = state->clip->getYMaxI();
}
+ origBlendFunc = state->blendFunc;
+ state->blendFunc = &blendXor;
+ pipeInit(&pipe, 0, yMinI, state->fillPattern, NULL, 1, gFalse, gFalse);
+
// draw the spans
for (y = yMinI; y <= yMaxI; ++y) {
while (scanner->getNextSpan(y, &x0, &x1)) {
if (clipRes == splashClipAllInside) {
- xorSpan(x0, x1, y, state->fillPattern, gTrue);
+ drawSpan(&pipe, x0, x1, y, gTrue);
} else {
// limit the x range
- if (x0 < state->clip->getXMin()) {
- x0 = state->clip->getXMin();
+ if (x0 < state->clip->getXMinI()) {
+ x0 = state->clip->getXMinI();
}
- if (x1 > state->clip->getXMax()) {
- x1 = state->clip->getXMax();
+ if (x1 > state->clip->getXMaxI()) {
+ x1 = state->clip->getXMaxI();
}
clipRes2 = state->clip->testSpan(x0, x1, y);
- xorSpan(x0, x1, y, state->fillPattern,
- clipRes2 == splashClipAllInside);
+ drawSpan(&pipe, x0, x1, y, clipRes2 == splashClipAllInside);
}
}
}
+ state->blendFunc = origBlendFunc;
}
opClipRes = clipRes;
@@ -942,1168 +1667,10 @@ SplashError Splash::xorFill(SplashPath *path, GBool eo) {
return splashOk;
}
-void Splash::drawPixel(int x, int y, SplashColorPtr color,
- SplashCoord alpha, GBool noClip) {
- SplashBlendFunc blendFunc;
- SplashColorPtr p;
- SplashColor dest, blend;
- int alpha2, ialpha2;
- Guchar t;
-
- if (noClip || state->clip->test(x, y)) {
- if (alpha != 1 || softMask || state->blendFunc) {
- blendFunc = state->blendFunc ? state->blendFunc : &blendNormal;
- if (softMask) {
- alpha2 = (int)(alpha * softMask->data[y * softMask->rowSize + x]);
- } else {
- alpha2 = (int)(alpha * 255);
- }
- ialpha2 = 255 - alpha2;
- switch (bitmap->mode) {
- case splashModeMono1:
- p = &bitmap->data[y * bitmap->rowSize + (x >> 3)];
- dest[0] = (*p >> (7 - (x & 7))) & 1;
- (*blendFunc)(color, dest, blend, bitmap->mode);
- t = (alpha2 * blend[0] + ialpha2 * dest[0]) >> 8;
- if (t) {
- *p |= 0x80 >> (x & 7);
- } else {
- *p &= ~(0x80 >> (x & 7));
- }
- break;
- case splashModeMono8:
- p = &bitmap->data[y * bitmap->rowSize + x];
- (*blendFunc)(color, p, blend, bitmap->mode);
- // note: floor(x / 255) = x >> 8 (for 16-bit x)
- p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8;
- break;
- case splashModeAMono8:
- p = &bitmap->data[y * bitmap->rowSize + 2 * x];
- (*blendFunc)(color, p, blend, bitmap->mode);
- p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8;
- p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8;
- break;
- case splashModeRGB8:
- case splashModeBGR8:
- p = &bitmap->data[y * bitmap->rowSize + 3 * x];
- (*blendFunc)(color, p, blend, bitmap->mode);
- p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8;
- p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8;
- p[2] = (alpha2 * blend[2] + ialpha2 * p[2]) >> 8;
- break;
- case splashModeRGB8Qt:
- p = &bitmap->data[y * bitmap->rowSize + 4 * x];
- (*blendFunc)(color, p, blend, bitmap->mode);
- p[0] = (alpha2 * blend[2] + ialpha2 * p[0]) >> 8;
- p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8;
- p[2] = (alpha2 * blend[0] + ialpha2 * p[2]) >> 8;
- break;
- case splashModeARGB8:
- case splashModeBGRA8:
-#if SPLASH_CMYK
- case splashModeCMYK8:
-#endif
- p = &bitmap->data[y * bitmap->rowSize + 4 * x];
- (*blendFunc)(color, p, blend, bitmap->mode);
- p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8;
- p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8;
- p[2] = (alpha2 * blend[2] + ialpha2 * p[2]) >> 8;
- p[3] = (alpha2 * blend[3] + ialpha2 * p[3]) >> 8;
- break;
-#if SPLASH_CMYK
- case splashModeACMYK8:
- p = &bitmap->data[y * bitmap->rowSize + 5 * x];
- (*blendFunc)(color, p, blend, bitmap->mode);
- p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8;
- p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8;
- p[2] = (alpha2 * blend[2] + ialpha2 * p[2]) >> 8;
- p[3] = (alpha2 * blend[3] + ialpha2 * p[3]) >> 8;
- p[4] = (alpha2 * blend[4] + ialpha2 * p[4]) >> 8;
- break;
-#endif
- }
- } else {
- switch (bitmap->mode) {
- case splashModeMono1:
- p = &bitmap->data[y * bitmap->rowSize + (x >> 3)];
- if (color[0]) {
- *p |= 0x80 >> (x & 7);
- } else {
- *p &= ~(0x80 >> (x & 7));
- }
- break;
- case splashModeMono8:
- p = &bitmap->data[y * bitmap->rowSize + x];
- p[0] = color[0];
- break;
- case splashModeAMono8:
- p = &bitmap->data[y * bitmap->rowSize + 2 * x];
- p[0] = color[0];
- p[1] = color[1];
- break;
- case splashModeRGB8:
- case splashModeBGR8:
- p = &bitmap->data[y * bitmap->rowSize + 3 * x];
- p[0] = color[0];
- p[1] = color[1];
- p[2] = color[2];
- break;
- case splashModeRGB8Qt:
- p = &bitmap->data[y * bitmap->rowSize + 4 * x];
- p[0] = color[2];
- p[1] = color[1];
- p[2] = color[0];
- break;
- case splashModeARGB8:
- case splashModeBGRA8:
-#if SPLASH_CMYK
- case splashModeCMYK8:
-#endif
- p = &bitmap->data[y * bitmap->rowSize + 4 * x];
- p[0] = color[0];
- p[1] = color[1];
- p[2] = color[2];
- p[3] = color[3];
- break;
-#if SPLASH_CMYK
- case splashModeACMYK8:
- p = &bitmap->data[y * bitmap->rowSize + 5 * x];
- p[0] = color[0];
- p[1] = color[1];
- p[2] = color[2];
- p[3] = color[3];
- p[4] = color[4];
- break;
-#endif
- }
- }
- updateModX(x);
- updateModY(y);
- }
-}
-
-void Splash::drawPixel(int x, int y, SplashPattern *pattern,
- SplashCoord alpha, GBool noClip) {
- SplashBlendFunc blendFunc;
- SplashColor color;
- SplashColorPtr p;
- SplashColor dest, blend;
- int alpha2, ialpha2;
- Guchar t;
-
- if (noClip || state->clip->test(x, y)) {
- if (alpha != 1 || softMask || state->blendFunc) {
- blendFunc = state->blendFunc ? state->blendFunc : &blendNormal;
- pattern->getColor(x, y, color);
- if (softMask) {
- alpha2 = (int)(alpha * softMask->data[y * softMask->rowSize + x]);
- } else {
- alpha2 = (int)(alpha * 255);
- }
- ialpha2 = 255 - alpha2;
- switch (bitmap->mode) {
- case splashModeMono1:
- p = &bitmap->data[y * bitmap->rowSize + (x >> 3)];
- dest[0] = (*p >> (7 - (x & 7))) & 1;
- (*blendFunc)(color, dest, blend, bitmap->mode);
- t = (alpha2 * blend[0] + ialpha2 * dest[0]) >> 8;
- if (t) {
- *p |= 0x80 >> (x & 7);
- } else {
- *p &= ~(0x80 >> (x & 7));
- }
- break;
- case splashModeMono8:
- p = &bitmap->data[y * bitmap->rowSize + x];
- (*blendFunc)(color, p, blend, bitmap->mode);
- // note: floor(x / 255) = x >> 8 (for 16-bit x)
- p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8;
- break;
- case splashModeAMono8:
- p = &bitmap->data[y * bitmap->rowSize + 2 * x];
- (*blendFunc)(color, p, blend, bitmap->mode);
- p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8;
- p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8;
- break;
- case splashModeRGB8:
- case splashModeBGR8:
- p = &bitmap->data[y * bitmap->rowSize + 3 * x];
- (*blendFunc)(color, p, blend, bitmap->mode);
- p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8;
- p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8;
- p[2] = (alpha2 * blend[2] + ialpha2 * p[2]) >> 8;
- break;
- case splashModeRGB8Qt:
- p = &bitmap->data[y * bitmap->rowSize + 4 * x];
- (*blendFunc)(color, p, blend, bitmap->mode);
- p[0] = (alpha2 * blend[2] + ialpha2 * p[0]) >> 8;
- p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8;
- p[2] = (alpha2 * blend[0] + ialpha2 * p[2]) >> 8;
- break;
- case splashModeARGB8:
- case splashModeBGRA8:
-#if SPLASH_CMYK
- case splashModeCMYK8:
-#endif
- p = &bitmap->data[y * bitmap->rowSize + 4 * x];
- (*blendFunc)(color, p, blend, bitmap->mode);
- p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8;
- p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8;
- p[2] = (alpha2 * blend[2] + ialpha2 * p[2]) >> 8;
- p[3] = (alpha2 * blend[3] + ialpha2 * p[3]) >> 8;
- break;
-#if SPLASH_CMYK
- case splashModeACMYK8:
- p = &bitmap->data[y * bitmap->rowSize + 5 * x];
- (*blendFunc)(color, p, blend, bitmap->mode);
- p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8;
- p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8;
- p[2] = (alpha2 * blend[2] + ialpha2 * p[2]) >> 8;
- p[3] = (alpha2 * blend[3] + ialpha2 * p[3]) >> 8;
- p[4] = (alpha2 * blend[4] + ialpha2 * p[4]) >> 8;
- break;
-#endif
- }
- } else {
- pattern->getColor(x, y, color);
- switch (bitmap->mode) {
- case splashModeMono1:
- p = &bitmap->data[y * bitmap->rowSize + (x >> 3)];
- if (color[0]) {
- *p |= 0x80 >> (x & 7);
- } else {
- *p &= ~(0x80 >> (x & 7));
- }
- break;
- case splashModeMono8:
- p = &bitmap->data[y * bitmap->rowSize + x];
- p[0] = color[0];
- break;
- case splashModeAMono8:
- p = &bitmap->data[y * bitmap->rowSize + 2 * x];
- p[0] = color[0];
- p[1] = color[1];
- break;
- case splashModeRGB8:
- case splashModeBGR8:
- p = &bitmap->data[y * bitmap->rowSize + 3 * x];
- p[0] = color[0];
- p[1] = color[1];
- p[2] = color[2];
- break;
- case splashModeRGB8Qt:
- p = &bitmap->data[y * bitmap->rowSize + 4 * x];
- p[0] = color[2];
- p[1] = color[1];
- p[2] = color[0];
- break;
- case splashModeARGB8:
- case splashModeBGRA8:
-#if SPLASH_CMYK
- case splashModeCMYK8:
-#endif
- p = &bitmap->data[y * bitmap->rowSize + 4 * x];
- p[0] = color[0];
- p[1] = color[1];
- p[2] = color[2];
- p[3] = color[3];
- break;
-#if SPLASH_CMYK
- case splashModeACMYK8:
- p = &bitmap->data[y * bitmap->rowSize + 5 * x];
- p[0] = color[0];
- p[1] = color[1];
- p[2] = color[2];
- p[3] = color[3];
- p[4] = color[4];
- break;
-#endif
- }
- }
- updateModX(x);
- updateModY(y);
- }
-}
-
-void Splash::drawSpan(int x0, int x1, int y, SplashPattern *pattern,
- SplashCoord alpha, GBool noClip) {
- SplashBlendFunc blendFunc;
- SplashColor color;
- SplashColorPtr p;
- SplashColor dest, blend;
- Guchar mask, t;
- int alpha2, ialpha2;
- int i, j, n;
-
- n = x1 - x0 + 1;
-
- if (noClip) {
- updateModX(x0);
- updateModX(x1);
- updateModY(y);
- }
-
- if (alpha != 1 || softMask || state->blendFunc) {
- blendFunc = state->blendFunc ? state->blendFunc : &blendNormal;
- if (softMask) {
- alpha2 = ialpha2 = 0; // make gcc happy
- } else {
- alpha2 = (int)(alpha * 255);
- ialpha2 = 255 - alpha2;
- }
- switch (bitmap->mode) {
- case splashModeMono1:
- p = &bitmap->data[y * bitmap->rowSize + (x0 >> 3)];
- i = 0;
- if (pattern->isStatic()) {
- pattern->getColor(0, 0, color);
- if ((j = x0 & 7)) {
- mask = 0x80 >> j;
- for (; j < 8 && i < n; ++i, ++j) {
- if (noClip || state->clip->test(x0 + i, y)) {
- if (softMask) {
- alpha2 = (int)(alpha *
- softMask->data[y * softMask->rowSize + x0 + i]);
- ialpha2 = 255 - alpha2;
- }
- dest[0] = (*p >> (7 - j)) & 1;
- (*blendFunc)(color, dest, blend, bitmap->mode);
- t = (alpha2 * blend[0] + ialpha2 * dest[0]) >> 8;
- if (t) {
- *p |= mask;
- } else {
- *p &= ~mask;
- }
- if (!noClip) {
- updateModX(x0 + i);
- updateModY(y);
- }
- }
- mask >>= 1;
- }
- ++p;
- }
- while (i < n) {
- mask = 0x80;
- for (j = 0; j < 8 && i < n; ++i, ++j) {
- if (noClip || state->clip->test(x0 + i, y)) {
- if (softMask) {
- alpha2 = (int)(alpha *
- softMask->data[y * softMask->rowSize + x0 + i]);
- ialpha2 = 255 - alpha2;
- }
- dest[0] = (*p >> (7 - j)) & 1;
- (*blendFunc)(color, dest, blend, bitmap->mode);
- t = (alpha2 * blend[0] + ialpha2 * dest[0]) >> 8;
- if (t) {
- *p |= mask;
- } else {
- *p &= ~mask;
- }
- if (!noClip) {
- updateModX(x0 + i);
- updateModY(y);
- }
- }
- mask >>= 1;
- }
- ++p;
- }
- } else {
- if ((j = x0 & 7)) {
- mask = 0x80 >> j;
- for (; j < 8 && i < n; ++i, ++j) {
- if (noClip || state->clip->test(x0 + i, y)) {
- pattern->getColor(x0 + i, y, color);
- if (softMask) {
- alpha2 = (int)(alpha *
- softMask->data[y * softMask->rowSize + x0 + i]);
- ialpha2 = 255 - alpha2;
- }
- dest[0] = (*p >> (7 - j)) & 1;
- (*blendFunc)(color, dest, blend, bitmap->mode);
- t = (alpha2 * blend[0] + ialpha2 * dest[0]) >> 8;
- if (t) {
- *p |= mask;
- } else {
- *p &= ~mask;
- }
- if (!noClip) {
- updateModX(x0 + i);
- updateModY(y);
- }
- }
- mask >>= 1;
- }
- ++p;
- }
- while (i < n) {
- mask = 0x80;
- for (j = 0; j < 8 && i < n; ++i, ++j) {
- if (noClip || state->clip->test(x0 + i, y)) {
- pattern->getColor(x0 + i, y, color);
- if (softMask) {
- alpha2 = (int)(alpha *
- softMask->data[y * softMask->rowSize + x0 + i]);
- ialpha2 = 255 - alpha2;
- }
- dest[0] = (*p >> (7 - j)) & 1;
- (*blendFunc)(color, dest, blend, bitmap->mode);
- t = (alpha2 * blend[0] + ialpha2 * dest[0]) >> 8;
- if (t) {
- *p |= mask;
- } else {
- *p &= ~mask;
- }
- if (!noClip) {
- updateModX(x0 + i);
- updateModY(y);
- }
- }
- mask >>= 1;
- }
- ++p;
- }
- }
- break;
-
- case splashModeMono8:
- p = &bitmap->data[y * bitmap->rowSize + x0];
- if (pattern->isStatic()) {
- pattern->getColor(0, 0, color);
- for (i = 0; i < n; ++i) {
- if (noClip || state->clip->test(x0 + i, y)) {
- if (softMask) {
- alpha2 = (int)(alpha *
- softMask->data[y * softMask->rowSize + x0 + i]);
- ialpha2 = 255 - alpha2;
- }
- (*blendFunc)(color, p, blend, bitmap->mode);
- *p = (alpha2 * blend[0] + ialpha2 * *p) >> 8;
- if (!noClip) {
- updateModX(x0 + i);
- updateModY(y);
- }
- }
- ++p;
- }
- } else {
- for (i = 0; i < n; ++i) {
- if (noClip || state->clip->test(x0 + i, y)) {
- pattern->getColor(x0 + i, y, color);
- if (softMask) {
- alpha2 = (int)(alpha *
- softMask->data[y * softMask->rowSize + x0 + i]);
- ialpha2 = 255 - alpha2;
- }
- (*blendFunc)(color, p, blend, bitmap->mode);
- *p = (alpha2 * blend[0] + ialpha2 * *p) >> 8;
- if (!noClip) {
- updateModX(x0 + i);
- updateModY(y);
- }
- }
- ++p;
- }
- }
- break;
-
- case splashModeAMono8:
- p = &bitmap->data[y * bitmap->rowSize + 2 * x0];
- if (pattern->isStatic()) {
- pattern->getColor(0, 0, color);
- for (i = 0; i < n; ++i) {
- if (noClip || state->clip->test(x0 + i, y)) {
- if (softMask) {
- alpha2 = (int)(alpha *
- softMask->data[y * softMask->rowSize + x0 + i]);
- ialpha2 = 255 - alpha2;
- }
- (*blendFunc)(color, p, blend, bitmap->mode);
- p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8;
- p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8;
- if (!noClip) {
- updateModX(x0 + i);
- updateModY(y);
- }
- }
- p += 2;
- }
- } else {
- for (i = 0; i < n; ++i) {
- if (noClip || state->clip->test(x0 + i, y)) {
- pattern->getColor(x0 + i, y, color);
- if (softMask) {
- alpha2 = (int)(alpha *
- softMask->data[y * softMask->rowSize + x0 + i]);
- ialpha2 = 255 - alpha2;
- }
- (*blendFunc)(color, p, blend, bitmap->mode);
- p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8;
- p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8;
- if (!noClip) {
- updateModX(x0 + i);
- updateModY(y);
- }
- }
- p += 2;
- }
- }
- break;
-
- case splashModeRGB8:
- case splashModeBGR8:
- p = &bitmap->data[y * bitmap->rowSize + 3 * x0];
- if (pattern->isStatic()) {
- pattern->getColor(0, 0, color);
- for (i = 0; i < n; ++i) {
- if (noClip || state->clip->test(x0 + i, y)) {
- if (softMask) {
- alpha2 = (int)(alpha *
- softMask->data[y * softMask->rowSize + x0 + i]);
- ialpha2 = 255 - alpha2;
- }
- (*blendFunc)(color, p, blend, bitmap->mode);
- p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8;
- p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8;
- p[2] = (alpha2 * blend[2] + ialpha2 * p[2]) >> 8;
- if (!noClip) {
- updateModX(x0 + i);
- updateModY(y);
- }
- }
- p += 3;
- }
- } else {
- for (i = 0; i < n; ++i) {
- if (noClip || state->clip->test(x0 + i, y)) {
- pattern->getColor(x0 + i, y, color);
- if (softMask) {
- alpha2 = (int)(alpha *
- softMask->data[y * softMask->rowSize + x0 + i]);
- ialpha2 = 255 - alpha2;
- }
- (*blendFunc)(color, p, blend, bitmap->mode);
- p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8;
- p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8;
- p[2] = (alpha2 * blend[2] + ialpha2 * p[2]) >> 8;
- if (!noClip) {
- updateModX(x0 + i);
- updateModY(y);
- }
- }
- p += 3;
- }
- }
- break;
-
- case splashModeRGB8Qt:
- p = &bitmap->data[y * bitmap->rowSize + 4 * x0];
- if (pattern->isStatic()) {
- pattern->getColor(0, 0, color);
- for (i = 0; i < n; ++i) {
- if (noClip || state->clip->test(x0 + i, y)) {
- if (softMask) {
- alpha2 = (int)(alpha *
- softMask->data[y * softMask->rowSize + x0 + i]);
- ialpha2 = 255 - alpha2;
- }
- (*blendFunc)(color, p, blend, bitmap->mode);
- p[0] = (alpha2 * blend[2] + ialpha2 * p[0]) >> 8;
- p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8;
- p[2] = (alpha2 * blend[0] + ialpha2 * p[2]) >> 8;
- if (!noClip) {
- updateModX(x0 + i);
- updateModY(y);
- }
- }
- p += 4;
- }
- } else {
- for (i = 0; i < n; ++i) {
- if (noClip || state->clip->test(x0 + i, y)) {
- pattern->getColor(x0 + i, y, color);
- if (softMask) {
- alpha2 = (int)(alpha *
- softMask->data[y * softMask->rowSize + x0 + i]);
- ialpha2 = 255 - alpha2;
- }
- (*blendFunc)(color, p, blend, bitmap->mode);
- p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8;
- p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8;
- p[2] = (alpha2 * blend[2] + ialpha2 * p[2]) >> 8;
- if (!noClip) {
- updateModX(x0 + i);
- updateModY(y);
- }
- }
- p += 4;
- }
- }
- break;
-
- case splashModeARGB8:
- case splashModeBGRA8:
-#if SPLASH_CMYK
- case splashModeCMYK8:
-#endif
- p = &bitmap->data[y * bitmap->rowSize + 4 * x0];
- if (pattern->isStatic()) {
- pattern->getColor(0, 0, color);
- for (i = 0; i < n; ++i) {
- if (noClip || state->clip->test(x0 + i, y)) {
- if (softMask) {
- alpha2 = (int)(alpha *
- softMask->data[y * softMask->rowSize + x0 + i]);
- ialpha2 = 255 - alpha2;
- }
- (*blendFunc)(color, p, blend, bitmap->mode);
- p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8;
- p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8;
- p[2] = (alpha2 * blend[2] + ialpha2 * p[2]) >> 8;
- p[3] = (alpha2 * blend[3] + ialpha2 * p[3]) >> 8;
- if (!noClip) {
- updateModX(x0 + i);
- updateModY(y);
- }
- }
- p += 4;
- }
- } else {
- for (i = 0; i < n; ++i) {
- if (noClip || state->clip->test(x0 + i, y)) {
- pattern->getColor(x0 + i, y, color);
- if (softMask) {
- alpha2 = (int)(alpha *
- softMask->data[y * softMask->rowSize + x0 + i]);
- ialpha2 = 255 - alpha2;
- }
- (*blendFunc)(color, p, blend, bitmap->mode);
- p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8;
- p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8;
- p[2] = (alpha2 * blend[2] + ialpha2 * p[2]) >> 8;
- p[3] = (alpha2 * blend[3] + ialpha2 * p[3]) >> 8;
- if (!noClip) {
- updateModX(x0 + i);
- updateModY(y);
- }
- }
- p += 4;
- }
- }
- break;
-#if SPLASH_CMYK
- case splashModeACMYK8:
- p = &bitmap->data[y * bitmap->rowSize + 5 * x0];
- if (pattern->isStatic()) {
- pattern->getColor(0, 0, color);
- for (i = 0; i < n; ++i) {
- if (noClip || state->clip->test(x0 + i, y)) {
- if (softMask) {
- alpha2 = (int)(alpha *
- softMask->data[y * softMask->rowSize + x0 + i]);
- ialpha2 = 255 - alpha2;
- }
- (*blendFunc)(color, p, blend, bitmap->mode);
- p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8;
- p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8;
- p[2] = (alpha2 * blend[2] + ialpha2 * p[2]) >> 8;
- p[3] = (alpha2 * blend[3] + ialpha2 * p[3]) >> 8;
- p[4] = (alpha2 * blend[4] + ialpha2 * p[4]) >> 8;
- if (!noClip) {
- updateModX(x0 + i);
- updateModY(y);
- }
- }
- p += 4;
- }
- } else {
- for (i = 0; i < n; ++i) {
- if (noClip || state->clip->test(x0 + i, y)) {
- pattern->getColor(x0 + i, y, color);
- if (softMask) {
- alpha2 = (int)(alpha *
- softMask->data[y * softMask->rowSize + x0 + i]);
- ialpha2 = 255 - alpha2;
- }
- (*blendFunc)(color, p, blend, bitmap->mode);
- p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8;
- p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8;
- p[2] = (alpha2 * blend[2] + ialpha2 * p[2]) >> 8;
- p[3] = (alpha2 * blend[3] + ialpha2 * p[3]) >> 8;
- p[4] = (alpha2 * blend[4] + ialpha2 * p[4]) >> 8;
- if (!noClip) {
- updateModX(x0 + i);
- updateModY(y);
- }
- }
- p += 4;
- }
- }
- break;
-#endif
- }
-
- } else {
- switch (bitmap->mode) {
- case splashModeMono1:
- p = &bitmap->data[y * bitmap->rowSize + (x0 >> 3)];
- i = 0;
- if (pattern->isStatic()) {
- pattern->getColor(0, 0, color);
- if ((j = x0 & 7)) {
- mask = 0x80 >> j;
- for (; j < 8 && i < n; ++i, ++j) {
- if (noClip || state->clip->test(x0 + i, y)) {
- if (color[0]) {
- *p |= mask;
- } else {
- *p &= ~mask;
- }
- if (!noClip) {
- updateModX(x0 + i);
- updateModY(y);
- }
- }
- mask >>= 1;
- }
- ++p;
- }
- while (i < n) {
- mask = 0x80;
- for (j = 0; j < 8 && i < n; ++i, ++j) {
- if (noClip || state->clip->test(x0 + i, y)) {
- if (color[0]) {
- *p |= mask;
- } else {
- *p &= ~mask;
- }
- if (!noClip) {
- updateModX(x0 + i);
- updateModY(y);
- }
- }
- mask >>= 1;
- }
- ++p;
- }
- } else {
- if ((j = x0 & 7)) {
- mask = 0x80 >> j;
- for (; j < 8 && i < n; ++i, ++j) {
- if (noClip || state->clip->test(x0 + i, y)) {
- pattern->getColor(x0 + i, y, color);
- if (color[0]) {
- *p |= mask;
- } else {
- *p &= ~mask;
- }
- if (!noClip) {
- updateModX(x0 + i);
- updateModY(y);
- }
- }
- mask >>= 1;
- }
- ++p;
- }
- while (i < n) {
- mask = 0x80;
- for (j = 0; j < 8 && i < n; ++i, ++j) {
- if (noClip || state->clip->test(x0 + i, y)) {
- pattern->getColor(x0 + i, y, color);
- if (color[0]) {
- *p |= mask;
- } else {
- *p &= ~mask;
- }
- if (!noClip) {
- updateModX(x0 + i);
- updateModY(y);
- }
- }
- mask >>= 1;
- }
- ++p;
- }
- }
- break;
-
- case splashModeMono8:
- p = &bitmap->data[y * bitmap->rowSize + x0];
- if (pattern->isStatic()) {
- pattern->getColor(0, 0, color);
- for (i = 0; i < n; ++i) {
- if (noClip || state->clip->test(x0 + i, y)) {
- *p = color[0];
- if (!noClip) {
- updateModX(x0 + i);
- updateModY(y);
- }
- }
- ++p;
- }
- } else {
- for (i = 0; i < n; ++i) {
- if (noClip || state->clip->test(x0 + i, y)) {
- pattern->getColor(x0 + i, y, color);
- *p = color[0];
- if (!noClip) {
- updateModX(x0 + i);
- updateModY(y);
- }
- }
- ++p;
- }
- }
- break;
-
- case splashModeAMono8:
- p = &bitmap->data[y * bitmap->rowSize + 2 * x0];
- if (pattern->isStatic()) {
- pattern->getColor(0, 0, color);
- for (i = 0; i < n; ++i) {
- if (noClip || state->clip->test(x0 + i, y)) {
- p[0] = color[0];
- p[1] = color[1];
- if (!noClip) {
- updateModX(x0 + i);
- updateModY(y);
- }
- }
- p += 2;
- }
- } else {
- for (i = 0; i < n; ++i) {
- if (noClip || state->clip->test(x0 + i, y)) {
- pattern->getColor(x0 + i, y, color);
- p[0] = color[0];
- p[1] = color[1];
- if (!noClip) {
- updateModX(x0 + i);
- updateModY(y);
- }
- }
- p += 2;
- }
- }
- break;
-
- case splashModeRGB8:
- case splashModeBGR8:
- p = &bitmap->data[y * bitmap->rowSize + 3 * x0];
- if (pattern->isStatic()) {
- pattern->getColor(0, 0, color);
- for (i = 0; i < n; ++i) {
- if (noClip || state->clip->test(x0 + i, y)) {
- p[0] = color[0];
- p[1] = color[1];
- p[2] = color[2];
- if (!noClip) {
- updateModX(x0 + i);
- updateModY(y);
- }
- }
- p += 3;
- }
- } else {
- for (i = 0; i < n; ++i) {
- if (noClip || state->clip->test(x0 + i, y)) {
- pattern->getColor(x0 + i, y, color);
- p[0] = color[0];
- p[1] = color[1];
- p[2] = color[2];
- if (!noClip) {
- updateModX(x0 + i);
- updateModY(y);
- }
- }
- p += 3;
- }
- }
- break;
-
- case splashModeRGB8Qt:
- p = &bitmap->data[y * bitmap->rowSize + 4 * x0];
- if (pattern->isStatic()) {
- pattern->getColor(0, 0, color);
- for (i = 0; i < n; ++i) {
- if (noClip || state->clip->test(x0 + i, y)) {
- p[0] = color[2];
- p[1] = color[1];
- p[2] = color[0];
- if (!noClip) {
- updateModX(x0 + i);
- updateModY(y);
- }
- }
- p += 4;
- }
- } else {
- for (i = 0; i < n; ++i) {
- if (noClip || state->clip->test(x0 + i, y)) {
- pattern->getColor(x0 + i, y, color);
- p[0] = color[0];
- p[1] = color[1];
- p[2] = color[2];
- if (!noClip) {
- updateModX(x0 + i);
- updateModY(y);
- }
- }
- p += 4;
- }
- }
- break;
-
- case splashModeARGB8:
- case splashModeBGRA8:
-#if SPLASH_CMYK
- case splashModeCMYK8:
-#endif
- p = &bitmap->data[y * bitmap->rowSize + 4 * x0];
- if (pattern->isStatic()) {
- pattern->getColor(0, 0, color);
- for (i = 0; i < n; ++i) {
- if (noClip || state->clip->test(x0 + i, y)) {
- p[0] = color[0];
- p[1] = color[1];
- p[2] = color[2];
- p[3] = color[3];
- if (!noClip) {
- updateModX(x0 + i);
- updateModY(y);
- }
- }
- p += 4;
- }
- } else {
- for (i = 0; i < n; ++i) {
- if (noClip || state->clip->test(x0 + i, y)) {
- pattern->getColor(x0 + i, y, color);
- p[0] = color[0];
- p[1] = color[1];
- p[2] = color[2];
- p[3] = color[3];
- if (!noClip) {
- updateModX(x0 + i);
- updateModY(y);
- }
- }
- p += 4;
- }
- }
- break;
-#if SPLASH_CMYK
- case splashModeACMYK8:
- p = &bitmap->data[y * bitmap->rowSize + 5 * x0];
- if (pattern->isStatic()) {
- pattern->getColor(0, 0, color);
- for (i = 0; i < n; ++i) {
- if (noClip || state->clip->test(x0 + i, y)) {
- p[0] = color[0];
- p[1] = color[1];
- p[2] = color[2];
- p[3] = color[3];
- p[4] = color[4];
- if (!noClip) {
- updateModX(x0 + i);
- updateModY(y);
- }
- }
- p += 4;
- }
- } else {
- for (i = 0; i < n; ++i) {
- if (noClip || state->clip->test(x0 + i, y)) {
- pattern->getColor(x0 + i, y, color);
- p[0] = color[0];
- p[1] = color[1];
- p[2] = color[2];
- p[3] = color[3];
- p[4] = color[4];
- if (!noClip) {
- updateModX(x0 + i);
- updateModY(y);
- }
- }
- p += 4;
- }
- }
- break;
-#endif
- }
- }
-}
-
-void Splash::xorSpan(int x0, int x1, int y, SplashPattern *pattern,
- GBool noClip) {
- SplashColor color;
- SplashColorPtr p;
- Guchar mask;
- int i, j, n;
-
- n = x1 - x0 + 1;
-
- if (noClip) {
- updateModX(x0);
- updateModX(x1);
- updateModY(y);
- }
-
- switch (bitmap->mode) {
- case splashModeMono1:
- p = &bitmap->data[y * bitmap->rowSize + (x0 >> 3)];
- i = 0;
- if ((j = x0 & 7)) {
- mask = 0x80 >> j;
- for (; j < 8 && i < n; ++i, ++j) {
- if (noClip || state->clip->test(x0 + i, y)) {
- pattern->getColor(x0 + i, y, color);
- if (color[0]) {
- *p ^= mask;
- }
- if (!noClip) {
- updateModX(x0 + i);
- updateModY(y);
- }
- }
- mask >>= 1;
- }
- ++p;
- }
- while (i < n) {
- mask = 0x80;
- for (j = 0; j < 8 && i < n; ++i, ++j) {
- if (noClip || state->clip->test(x0 + i, y)) {
- pattern->getColor(x0 + i, y, color);
- if (color[0]) {
- *p ^= mask;
- }
- if (!noClip) {
- updateModX(x0 + i);
- updateModY(y);
- }
- }
- mask >>= 1;
- }
- ++p;
- }
- break;
-
- case splashModeMono8:
- p = &bitmap->data[y * bitmap->rowSize + x0];
- for (i = 0; i < n; ++i) {
- if (noClip || state->clip->test(x0 + i, y)) {
- pattern->getColor(x0 + i, y, color);
- *p ^= color[0];
- if (!noClip) {
- updateModX(x0 + i);
- updateModY(y);
- }
- }
- ++p;
- }
- break;
-
- case splashModeAMono8:
- p = &bitmap->data[y * bitmap->rowSize + 2 * x0];
- for (i = 0; i < n; ++i) {
- if (noClip || state->clip->test(x0 + i, y)) {
- pattern->getColor(x0 + i, y, color);
- p[0] ^= color[0];
- p[1] ^= color[1];
- if (!noClip) {
- updateModX(x0 + i);
- updateModY(y);
- }
- }
- p += 2;
- }
- break;
-
- case splashModeRGB8:
- case splashModeBGR8:
- p = &bitmap->data[y * bitmap->rowSize + 3 * x0];
- for (i = 0; i < n; ++i) {
- if (noClip || state->clip->test(x0 + i, y)) {
- pattern->getColor(x0 + i, y, color);
- p[0] ^= color[0];
- p[1] ^= color[1];
- p[2] ^= color[2];
- if (!noClip) {
- updateModX(x0 + i);
- updateModY(y);
- }
- }
- p += 3;
- }
- break;
-
- case splashModeRGB8Qt:
- p = &bitmap->data[y * bitmap->rowSize + 4 * x0];
- for (i = 0; i < n; ++i) {
- if (noClip || state->clip->test(x0 + i, y)) {
- pattern->getColor(x0 + i, y, color);
- p[0] ^= color[2];
- p[1] ^= color[1];
- p[2] ^= color[0];
- if (!noClip) {
- updateModX(x0 + i);
- updateModY(y);
- }
- }
- p += 4;
- }
- break;
-
- case splashModeARGB8:
- case splashModeBGRA8:
-#if SPLASH_CMYK
- case splashModeCMYK8:
-#endif
- p = &bitmap->data[y * bitmap->rowSize + 4 * x0];
- for (i = 0; i < n; ++i) {
- if (noClip || state->clip->test(x0 + i, y)) {
- pattern->getColor(x0 + i, y, color);
- p[0] ^= color[0];
- p[1] ^= color[1];
- p[2] ^= color[2];
- p[3] ^= color[3];
- if (!noClip) {
- updateModX(x0 + i);
- updateModY(y);
- }
- }
- p += 4;
- }
- break;
-#if SPLASH_CMYK
- case splashModeACMYK8:
- p = &bitmap->data[y * bitmap->rowSize + 5 * x0];
- for (i = 0; i < n; ++i) {
- if (noClip || state->clip->test(x0 + i, y)) {
- pattern->getColor(x0 + i, y, color);
- p[0] ^= color[0];
- p[1] ^= color[1];
- p[2] ^= color[2];
- p[3] ^= color[3];
- p[4] ^= color[4];
- if (!noClip) {
- updateModX(x0 + i);
- updateModY(y);
- }
- }
- p += 4;
- }
- break;
-#endif
- }
-}
-
SplashError Splash::fillChar(SplashCoord x, SplashCoord y,
int c, SplashFont *font) {
SplashGlyphBitmap glyph;
+ SplashCoord xt, yt;
int x0, y0, xFrac, yFrac;
SplashError err;
@@ -2111,14 +1678,15 @@ SplashError Splash::fillChar(SplashCoord x, SplashCoord y,
printf("fillChar: x=%.2f y=%.2f c=%3d=0x%02x='%c'\n",
(double)x, (double)y, c, c, c);
}
- x0 = splashFloor(x);
- xFrac = splashFloor((x - x0) * splashFontFraction);
- y0 = splashFloor(y);
- yFrac = splashFloor((y - y0) * splashFontFraction);
+ transform(state->matrix, x, y, &xt, &yt);
+ x0 = splashFloor(xt);
+ xFrac = splashFloor((xt - x0) * splashFontFraction);
+ y0 = splashFloor(yt);
+ yFrac = splashFloor((yt - y0) * splashFontFraction);
if (!font->getGlyph(c, xFrac, yFrac, &glyph)) {
return splashErrNoGlyph;
}
- err = fillGlyph(x, y, &glyph);
+ err = fillGlyph2(x0, y0, &glyph);
if (glyph.freeData) {
gfree(glyph.data);
}
@@ -2127,18 +1695,22 @@ SplashError Splash::fillChar(SplashCoord x, SplashCoord y,
SplashError Splash::fillGlyph(SplashCoord x, SplashCoord y,
SplashGlyphBitmap *glyph) {
- SplashBlendFunc blendFunc;
- int alpha0, alpha, ialpha;
- Guchar *p;
- SplashColor fg, dest, blend;
- SplashColorPtr pix;
+ SplashCoord xt, yt;
+ int x0, y0;
+
+ transform(state->matrix, x, y, &xt, &yt);
+ x0 = splashFloor(xt);
+ y0 = splashFloor(yt);
+ return fillGlyph2(x0, y0, glyph);
+}
+
+SplashError Splash::fillGlyph2(int x0, int y0, SplashGlyphBitmap *glyph) {
+ SplashPipe pipe;
SplashClipResult clipRes;
GBool noClip;
- Guchar t;
- int x0, y0, x1, y1, xx, xx1, yy;
-
- x0 = splashFloor(x);
- y0 = splashFloor(y);
+ int alpha0, alpha;
+ Guchar *p;
+ int x1, y1, xx, xx1, yy;
if ((clipRes = state->clip->testRect(x0 - glyph->x,
y0 - glyph->y,
@@ -2148,335 +1720,88 @@ SplashError Splash::fillGlyph(SplashCoord x, SplashCoord y,
noClip = clipRes == splashClipAllInside;
if (noClip) {
- updateModX(x0 - glyph->x);
- updateModX(x0 - glyph->x + glyph->w - 1);
- updateModY(y0 - glyph->y);
- updateModY(y0 - glyph->y + glyph->h - 1);
- }
-
- //~ optimize this
- if (state->fillAlpha != 1 || softMask || state->blendFunc) {
- blendFunc = state->blendFunc ? state->blendFunc : &blendNormal;
if (glyph->aa) {
+ pipeInit(&pipe, x0 - glyph->x, y0 - glyph->y,
+ state->fillPattern, NULL, state->fillAlpha, gTrue, gFalse);
p = glyph->data;
for (yy = 0, y1 = y0 - glyph->y; yy < glyph->h; ++yy, ++y1) {
+ pipeSetXY(&pipe, x0 - glyph->x, y1);
for (xx = 0, x1 = x0 - glyph->x; xx < glyph->w; ++xx, ++x1) {
alpha = *p++;
- if (softMask) {
- alpha = (int)(alpha * (float)state->fillAlpha *
- softMask->data[y1 * softMask->rowSize + x1]);
+ if (alpha != 0) {
+ pipe.shape = (SplashCoord)(alpha / 255.0);
+ pipeRun(&pipe);
+ updateModX(x1);
+ updateModY(y1);
} else {
- alpha = (int)(alpha * (float)state->fillAlpha);
- }
- if (alpha > 0) {
- if (noClip || state->clip->test(x1, y1)) {
- ialpha = 255 - alpha;
- state->fillPattern->getColor(x1, y1, fg);
- switch (bitmap->mode) {
- case splashModeMono1:
- pix = &bitmap->data[y1 * bitmap->rowSize + (x1 >> 3)];
- dest[0] = (*pix >> (7 - (x1 & 7))) & 1;
- (*blendFunc)(fg, dest, blend, bitmap->mode);
- t = (alpha * blend[0] + ialpha * dest[0]) >> 8;
- if (t) {
- *pix |= 0x80 >> (x1 & 7);
- } else {
- *pix &= ~(0x80 >> (x1 & 7));
- }
- break;
- case splashModeMono8:
- pix = &bitmap->data[y1 * bitmap->rowSize + x1];
- (*blendFunc)(fg, pix, blend, bitmap->mode);
- // note: floor(x / 255) = x >> 8 (for 16-bit x)
- pix[0] = (alpha * blend[0] + ialpha * pix[0]) >> 8;
- break;
- case splashModeAMono8:
- pix = &bitmap->data[y1 * bitmap->rowSize + 2 * x1];
- (*blendFunc)(fg, pix, blend, bitmap->mode);
- pix[0] = (alpha * blend[0] + ialpha * pix[0]) >> 8;
- pix[1] = (alpha * blend[1] + ialpha * pix[1]) >> 8;
- break;
- case splashModeRGB8:
- case splashModeBGR8:
- pix = &bitmap->data[y1 * bitmap->rowSize + 3 * x1];
- (*blendFunc)(fg, pix, blend, bitmap->mode);
- pix[0] = (alpha * blend[0] + ialpha * pix[0]) >> 8;
- pix[1] = (alpha * blend[1] + ialpha * pix[1]) >> 8;
- pix[2] = (alpha * blend[2] + ialpha * pix[2]) >> 8;
- break;
- case splashModeRGB8Qt:
- pix = &bitmap->data[y1 * bitmap->rowSize + 4 * x1];
- (*blendFunc)(fg, pix, blend, bitmap->mode);
- pix[0] = (alpha * blend[2] + ialpha * pix[0]) >> 8;
- pix[1] = (alpha * blend[1] + ialpha * pix[1]) >> 8;
- pix[2] = (alpha * blend[0] + ialpha * pix[2]) >> 8;
- break;
- case splashModeARGB8:
- case splashModeBGRA8:
-#if SPLASH_CMYK
- case splashModeCMYK8:
-#endif
- pix = &bitmap->data[y1 * bitmap->rowSize + 4 * x1];
- (*blendFunc)(fg, pix, blend, bitmap->mode);
- pix[0] = (alpha * blend[0] + ialpha * pix[0]) >> 8;
- pix[1] = (alpha * blend[1] + ialpha * pix[1]) >> 8;
- pix[2] = (alpha * blend[2] + ialpha * pix[2]) >> 8;
- pix[3] = (alpha * blend[3] + ialpha * pix[3]) >> 8;
- break;
-#if SPLASH_CMYK
- case splashModeACMYK8:
- pix = &bitmap->data[y1 * bitmap->rowSize + 5 * x1];
- (*blendFunc)(fg, pix, blend, bitmap->mode);
- pix[0] = (alpha * blend[0] + ialpha * pix[0]) >> 8;
- pix[1] = (alpha * blend[1] + ialpha * pix[1]) >> 8;
- pix[2] = (alpha * blend[2] + ialpha * pix[2]) >> 8;
- pix[3] = (alpha * blend[3] + ialpha * pix[3]) >> 8;
- pix[4] = (alpha * blend[4] + ialpha * pix[4]) >> 8;
- break;
-#endif
- }
- if (!noClip) {
- updateModX(x1);
- updateModY(y1);
- }
- }
+ pipeIncX(&pipe);
}
}
}
-
} else {
+ pipeInit(&pipe, x0 - glyph->x, y0 - glyph->y,
+ state->fillPattern, NULL, state->fillAlpha, gFalse, gFalse);
p = glyph->data;
for (yy = 0, y1 = y0 - glyph->y; yy < glyph->h; ++yy, ++y1) {
+ pipeSetXY(&pipe, x0 - glyph->x, y1);
for (xx = 0, x1 = x0 - glyph->x; xx < glyph->w; xx += 8) {
alpha0 = *p++;
for (xx1 = 0; xx1 < 8 && xx + xx1 < glyph->w; ++xx1, ++x1) {
if (alpha0 & 0x80) {
- if (noClip || state->clip->test(x1, y1)) {
- if (softMask) {
- alpha = (int)(state->fillAlpha *
- softMask->data[y1 * softMask->rowSize + x1]);
- } else {
- alpha = (int)(state->fillAlpha * 255);
- }
- ialpha = 255 - alpha;
- state->fillPattern->getColor(x1, y1, fg);
- switch (bitmap->mode) {
- case splashModeMono1:
- pix = &bitmap->data[y1 * bitmap->rowSize + (x1 >> 3)];
- dest[0] = (*pix >> (7 - (x1 & 7))) & 1;
- (*blendFunc)(fg, dest, blend, bitmap->mode);
- t = (alpha * blend[0] + ialpha * dest[0]) >> 8;
- if (t) {
- *pix |= 0x80 >> (x1 & 7);
- } else {
- *pix &= ~(0x80 >> (x1 & 7));
- }
- break;
- case splashModeMono8:
- pix = &bitmap->data[y1 * bitmap->rowSize + x1];
- (*blendFunc)(fg, pix, blend, bitmap->mode);
- // note: floor(x / 255) = x >> 8 (for 16-bit x)
- pix[0] = (alpha * blend[0] + ialpha * pix[0]) >> 8;
- break;
- case splashModeAMono8:
- pix = &bitmap->data[y1 * bitmap->rowSize + 2 * x1];
- (*blendFunc)(fg, pix, blend, bitmap->mode);
- pix[0] = (alpha * blend[0] + ialpha * pix[0]) >> 8;
- pix[1] = (alpha * blend[1] + ialpha * pix[1]) >> 8;
- break;
- case splashModeRGB8:
- case splashModeBGR8:
- pix = &bitmap->data[y1 * bitmap->rowSize + 3 * x1];
- (*blendFunc)(fg, pix, blend, bitmap->mode);
- pix[0] = (alpha * blend[0] + ialpha * pix[0]) >> 8;
- pix[1] = (alpha * blend[1] + ialpha * pix[1]) >> 8;
- pix[2] = (alpha * blend[2] + ialpha * pix[2]) >> 8;
- break;
- case splashModeRGB8Qt:
- pix = &bitmap->data[y1 * bitmap->rowSize + 4 * x1];
- (*blendFunc)(fg, pix, blend, bitmap->mode);
- pix[0] = (alpha * blend[2] + ialpha * pix[0]) >> 8;
- pix[1] = (alpha * blend[1] + ialpha * pix[1]) >> 8;
- pix[2] = (alpha * blend[0] + ialpha * pix[2]) >> 8;
- break;
- case splashModeARGB8:
- case splashModeBGRA8:
-#if SPLASH_CMYK
- case splashModeCMYK8:
-#endif
- pix = &bitmap->data[y1 * bitmap->rowSize + 4 * x1];
- (*blendFunc)(fg, pix, blend, bitmap->mode);
- pix[0] = (alpha * blend[0] + ialpha * pix[0]) >> 8;
- pix[1] = (alpha * blend[1] + ialpha * pix[1]) >> 8;
- pix[2] = (alpha * blend[2] + ialpha * pix[2]) >> 8;
- pix[3] = (alpha * blend[3] + ialpha * pix[3]) >> 8;
- break;
-#if SPLASH_CMYK
- case splashModeACMYK8:
- pix = &bitmap->data[y1 * bitmap->rowSize + 5 * x1];
- (*blendFunc)(fg, pix, blend, bitmap->mode);
- pix[0] = (alpha * blend[0] + ialpha * pix[0]) >> 8;
- pix[1] = (alpha * blend[1] + ialpha * pix[1]) >> 8;
- pix[2] = (alpha * blend[2] + ialpha * pix[2]) >> 8;
- pix[3] = (alpha * blend[3] + ialpha * pix[3]) >> 8;
- pix[4] = (alpha * blend[4] + ialpha * pix[4]) >> 8;
- break;
-#endif
- }
- if (!noClip) {
- updateModX(x1);
- updateModY(y1);
- }
- }
+ pipeRun(&pipe);
+ updateModX(x1);
+ updateModY(y1);
+ } else {
+ pipeIncX(&pipe);
}
alpha0 <<= 1;
}
}
}
}
-
} else {
if (glyph->aa) {
+ pipeInit(&pipe, x0 - glyph->x, y0 - glyph->y,
+ state->fillPattern, NULL, state->fillAlpha, gTrue, gFalse);
p = glyph->data;
for (yy = 0, y1 = y0 - glyph->y; yy < glyph->h; ++yy, ++y1) {
+ pipeSetXY(&pipe, x0 - glyph->x, y1);
for (xx = 0, x1 = x0 - glyph->x; xx < glyph->w; ++xx, ++x1) {
- alpha = *p++;
- if (alpha > 0) {
- if (noClip || state->clip->test(x1, y1)) {
- ialpha = 255 - alpha;
- state->fillPattern->getColor(x1, y1, fg);
- switch (bitmap->mode) {
- case splashModeMono1:
- if (alpha >= 0x80) {
- pix = &bitmap->data[y1 * bitmap->rowSize + (x1 >> 3)];
- if (fg[0]) {
- *pix |= 0x80 >> (x1 & 7);
- } else {
- *pix &= ~(0x80 >> (x1 & 7));
- }
- }
- break;
- case splashModeMono8:
- pix = &bitmap->data[y1 * bitmap->rowSize + x1];
- // note: floor(x / 255) = x >> 8 (for 16-bit x)
- pix[0] = (alpha * fg[0] + ialpha * pix[0]) >> 8;
- break;
- case splashModeAMono8:
- pix = &bitmap->data[y1 * bitmap->rowSize + 2 * x1];
- pix[0] = (alpha * fg[0] + ialpha * pix[0]) >> 8;
- pix[1] = (alpha * fg[1] + ialpha * pix[1]) >> 8;
- break;
- case splashModeRGB8:
- case splashModeBGR8:
- pix = &bitmap->data[y1 * bitmap->rowSize + 3 * x1];
- pix[0] = (alpha * fg[0] + ialpha * pix[0]) >> 8;
- pix[1] = (alpha * fg[1] + ialpha * pix[1]) >> 8;
- pix[2] = (alpha * fg[2] + ialpha * pix[2]) >> 8;
- break;
- case splashModeRGB8Qt:
- pix = &bitmap->data[y1 * bitmap->rowSize + 4 * x1];
- pix[0] = (alpha * fg[2] + ialpha * pix[0]) >> 8;
- pix[1] = (alpha * fg[1] + ialpha * pix[1]) >> 8;
- pix[2] = (alpha * fg[0] + ialpha * pix[2]) >> 8;
- break;
- case splashModeARGB8:
- case splashModeBGRA8:
-#if SPLASH_CMYK
- case splashModeCMYK8:
-#endif
- pix = &bitmap->data[y1 * bitmap->rowSize + 4 * x1];
- pix[0] = (alpha * fg[0] + ialpha * pix[0]) >> 8;
- pix[1] = (alpha * fg[1] + ialpha * pix[1]) >> 8;
- pix[2] = (alpha * fg[2] + ialpha * pix[2]) >> 8;
- pix[3] = (alpha * fg[3] + ialpha * pix[3]) >> 8;
- break;
-#if SPLASH_CMYK
- case splashModeACMYK8:
- pix = &bitmap->data[y1 * bitmap->rowSize + 5 * x1];
- pix[0] = (alpha * fg[0] + ialpha * pix[0]) >> 8;
- pix[1] = (alpha * fg[1] + ialpha * pix[1]) >> 8;
- pix[2] = (alpha * fg[2] + ialpha * pix[2]) >> 8;
- pix[3] = (alpha * fg[3] + ialpha * pix[3]) >> 8;
- pix[4] = (alpha * fg[4] + ialpha * pix[4]) >> 8;
- break;
-#endif
- }
- if (!noClip) {
- updateModX(x1);
- updateModY(y1);
- }
+ if (state->clip->test(x1, y1)) {
+ alpha = *p++;
+ if (alpha != 0) {
+ pipe.shape = (SplashCoord)(alpha / 255.0);
+ pipeRun(&pipe);
+ updateModX(x1);
+ updateModY(y1);
+ } else {
+ pipeIncX(&pipe);
}
+ } else {
+ pipeIncX(&pipe);
+ ++p;
}
}
}
-
} else {
+ pipeInit(&pipe, x0 - glyph->x, y0 - glyph->y,
+ state->fillPattern, NULL, state->fillAlpha, gFalse, gFalse);
p = glyph->data;
for (yy = 0, y1 = y0 - glyph->y; yy < glyph->h; ++yy, ++y1) {
+ pipeSetXY(&pipe, x0 - glyph->x, y1);
for (xx = 0, x1 = x0 - glyph->x; xx < glyph->w; xx += 8) {
alpha0 = *p++;
for (xx1 = 0; xx1 < 8 && xx + xx1 < glyph->w; ++xx1, ++x1) {
- if (alpha0 & 0x80) {
- if (noClip || state->clip->test(x1, y1)) {
- state->fillPattern->getColor(x1, y1, fg);
- switch (bitmap->mode) {
- case splashModeMono1:
- pix = &bitmap->data[y1 * bitmap->rowSize + (x1 >> 3)];
- if (fg[0]) {
- *pix |= 0x80 >> (x1 & 7);
- } else {
- *pix &= ~(0x80 >> (x1 & 7));
- }
- break;
- case splashModeMono8:
- pix = &bitmap->data[y1 * bitmap->rowSize + x1];
- pix[0] = fg[0];
- break;
- case splashModeAMono8:
- pix = &bitmap->data[y1 * bitmap->rowSize + 2 * x1];
- pix[0] = fg[0];
- pix[1] = fg[1];
- break;
- case splashModeRGB8:
- case splashModeBGR8:
- pix = &bitmap->data[y1 * bitmap->rowSize + 3 * x1];
- pix[0] = fg[0];
- pix[1] = fg[1];
- pix[2] = fg[2];
- break;
- case splashModeRGB8Qt:
- pix = &bitmap->data[y1 * bitmap->rowSize + 4 * x1];
- pix[0] = fg[2];
- pix[1] = fg[1];
- pix[2] = fg[0];
- break;
- case splashModeARGB8:
- case splashModeBGRA8:
-#if SPLASH_CMYK
- case splashModeCMYK8:
-#endif
- pix = &bitmap->data[y1 * bitmap->rowSize + 4 * x1];
- pix[0] = fg[0];
- pix[1] = fg[1];
- pix[2] = fg[2];
- pix[3] = fg[3];
- break;
-#if SPLASH_CMYK
- case splashModeACMYK8:
- pix = &bitmap->data[y1 * bitmap->rowSize + 5 * x1];
- pix[0] = fg[0];
- pix[1] = fg[1];
- pix[2] = fg[2];
- pix[3] = fg[3];
- pix[4] = fg[4];
- break;
-#endif
- }
- if (!noClip) {
- updateModX(x1);
- updateModY(y1);
- }
+ if (state->clip->test(x1, y1)) {
+ if (alpha0 & 0x80) {
+ pipeRun(&pipe);
+ updateModX(x1);
+ updateModY(y1);
+ } else {
+ pipeIncX(&pipe);
}
+ } else {
+ pipeIncX(&pipe);
}
alpha0 <<= 1;
}
@@ -2491,7 +1816,9 @@ SplashError Splash::fillGlyph(SplashCoord x, SplashCoord y,
}
SplashError Splash::fillImageMask(SplashImageMaskSource src, void *srcData,
- int w, int h, SplashCoord *mat) {
+ 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;
@@ -2504,7 +1831,6 @@ SplashError Splash::fillImageMask(SplashImageMaskSource src, void *srcData,
int k1, spanXMin, spanXMax, spanY;
SplashColorPtr pixBuf, p;
int pixAcc;
- SplashCoord alpha;
int x, y, x1, x2, y2;
SplashCoord y1;
int n, m, i, j;
@@ -2535,38 +1861,54 @@ SplashError Splash::fillImageMask(SplashImageMaskSource src, void *srcData,
xShear = mat[2] / yScale;
yShear = mat[1] / mat[0];
}
- // 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 = splashRound(mat[4] - 0.01);
- tx2 = splashRound(mat[4] + xScale + 0.01) - 1;
+ // 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);
+ }
} else {
- tx = splashRound(mat[4] + 0.01) - 1;
- tx2 = splashRound(mat[4] + xScale - 0.01);
+ 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 (scaledWidth == 0) {
- // technically, this should draw nothing, but it generally seems
- // better to draw a one-pixel-wide stripe rather than throwing it
- // away
- scaledWidth = 1;
- }
- if (yScale >= 0) {
- ty = splashRound(mat[5] - 0.01);
- ty2 = splashRound(mat[5] + yScale + 0.01) - 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);
+ }
} else {
- ty = splashRound(mat[5] + 0.01) - 1;
- ty2 = splashRound(mat[5] + yScale - 0.01);
+ 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);
+ }
}
scaledHeight = abs(ty2 - ty) + 1;
- if (scaledHeight == 0) {
- // technically, this should draw nothing, but it generally seems
- // better to draw a one-pixel-wide stripe rather than throwing it
- // away
- scaledHeight = 1;
- }
xSign = (xScale < 0) ? -1 : 1;
ySign = (yScale < 0) ? -1 : 1;
yShear1 = (SplashCoord)xSign * yShear;
@@ -2620,6 +1962,13 @@ SplashError Splash::fillImageMask(SplashImageMaskSource src, void *srcData,
// allocate pixel buffer
pixBuf = (SplashColorPtr)gmalloc((yp + 1) * w);
+ // initialize the pixel pipe
+ pipeInit(&pipe, 0, 0, state->fillPattern, NULL, state->fillAlpha,
+ gTrue, gFalse);
+ if (vectorAntialias) {
+ drawAAPixelInit();
+ }
+
// init y scale Bresenham
yt = 0;
lastYStep = 1;
@@ -2721,14 +2070,13 @@ SplashError Splash::fillImageMask(SplashImageMaskSource src, void *srcData,
// blend fill color with background
if (pixAcc != 0) {
- if (pixAcc == n * m) {
- drawPixel(tx + x2, ty + y2, state->fillPattern, state->fillAlpha,
- clipRes2 == splashClipAllInside);
+ pipe.shape = (pixAcc == n * m)
+ ? (SplashCoord)1
+ : (SplashCoord)pixAcc / (SplashCoord)(n * m);
+ if (vectorAntialias && clipRes2 != splashClipAllInside) {
+ drawAAPixel(&pipe, tx + x2, ty + y2);
} else {
- alpha = (SplashCoord)pixAcc / (SplashCoord)(n * m);
- drawPixel(tx + x2, ty + y2, state->fillPattern,
- state->fillAlpha * alpha,
- clipRes2 == splashClipAllInside);
+ drawPixel(&pipe, tx + x2, ty + y2, clipRes2 == splashClipAllInside);
}
}
@@ -2750,9 +2098,10 @@ SplashError Splash::fillImageMask(SplashImageMaskSource src, void *srcData,
}
SplashError Splash::drawImage(SplashImageSource src, void *srcData,
- SplashColorMode srcMode,
+ SplashColorMode srcMode, GBool srcAlpha,
int w, int h, SplashCoord *mat) {
- GBool ok, rot, halftone, srcAlpha;
+ 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;
@@ -2762,8 +2111,9 @@ SplashError Splash::drawImage(SplashImageSource src, void *srcData,
int yp, yq, yt, yStep, lastYStep;
int xp, xq, xt, xStep, xSrc;
int k1, spanXMin, spanXMax, spanY;
- SplashColorPtr pixBuf, p;
+ SplashColorPtr colorBuf, p;
SplashColor pix;
+ Guchar *alphaBuf, *q;
#if SPLASH_CMYK
int pixAcc0, pixAcc1, pixAcc2, pixAcc3;
#else
@@ -2776,61 +2126,37 @@ SplashError Splash::drawImage(SplashImageSource src, void *srcData,
int nComps, n, m, i, j;
if (debugMode) {
- printf("drawImage: srcMode=%d w=%d h=%d mat=[%.2f %.2f %.2f %.2f %.2f %.2f]\n",
- srcMode, w, h, (double)mat[0], (double)mat[1], (double)mat[2],
+ printf("drawImage: srcMode=%d srcAlpha=%d w=%d h=%d mat=[%.2f %.2f %.2f %.2f %.2f %.2f]\n",
+ srcMode, srcAlpha, w, h, (double)mat[0], (double)mat[1], (double)mat[2],
(double)mat[3], (double)mat[4], (double)mat[5]);
}
// check color modes
ok = gFalse; // make gcc happy
nComps = 0; // make gcc happy
- halftone = gFalse;
- srcAlpha = gFalse;
switch (bitmap->mode) {
case splashModeMono1:
- ok = srcMode == splashModeMono1 || srcMode == splashModeMono8 ||
- srcMode == splashModeAMono8;
- halftone = srcMode == splashModeMono8 || srcMode == splashModeAMono8;
- srcAlpha = srcMode == splashModeAMono8;
- nComps = srcAlpha ? 2 : 1;
- break;
case splashModeMono8:
- ok = srcMode == splashModeMono8 || srcMode == splashModeAMono8;
- srcAlpha = srcMode == splashModeAMono8;
- nComps = srcAlpha ? 2 : 1;
- break;
- case splashModeAMono8:
- //~ not implemented yet
- ok = gFalse;
- nComps = 2;
- break;
- case splashModeRGB8Qt:
+ ok = srcMode == splashModeMono8;
+ nComps = 1;
case splashModeRGB8:
- ok = srcMode == splashModeRGB8 || srcMode == splashModeARGB8;
- srcAlpha = srcMode == splashModeARGB8;
- nComps = srcAlpha ? 4 : 3;
+ ok = srcMode == splashModeRGB8;
+ nComps = 3;
+ break;
+ case splashModeRGBX8:
+ ok = srcMode == splashModeRGBX8;
+ nComps = 4;
break;
case splashModeBGR8:
- ok = srcMode == splashModeBGR8 || srcMode == splashModeBGRA8;
- srcAlpha = srcMode == splashModeBGRA8;
- nComps = srcAlpha ? 4 : 3;
+ ok = srcMode == splashModeBGR8;
+ nComps = 3;
break;
#if SPLASH_CMYK
case splashModeCMYK8:
- ok = srcMode == splashModeCMYK8 || srcMode == splashModeACMYK8;
- srcAlpha = srcMode == splashModeACMYK8;
- nComps = srcAlpha ? 5 : 4;
- break;
-#endif
- case splashModeARGB8:
- case splashModeBGRA8:
-#if SPLASH_CMYK
- case splashModeACMYK8:
-#endif
- //~ not implemented yet
- ok = gFalse;
+ ok = srcMode == splashModeCMYK8;
nComps = 4;
break;
+#endif
}
if (!ok) {
return splashErrModeMismatch;
@@ -2854,38 +2180,31 @@ SplashError Splash::drawImage(SplashImageSource src, void *srcData,
xShear = mat[2] / yScale;
yShear = mat[1] / mat[0];
}
- // 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)
+ // 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 = splashRound(mat[4] - 0.01);
- tx2 = splashRound(mat[4] + xScale + 0.01) - 1;
+ tx = splashFloor(mat[4] - 0.01);
+ tx2 = splashFloor(mat[4] + xScale + 0.01);
} else {
- tx = splashRound(mat[4] + 0.01) - 1;
- tx2 = splashRound(mat[4] + xScale - 0.01);
+ tx = splashFloor(mat[4] + 0.01);
+ tx2 = splashFloor(mat[4] + xScale - 0.01);
}
scaledWidth = abs(tx2 - tx) + 1;
- if (scaledWidth == 0) {
- // technically, this should draw nothing, but it generally seems
- // better to draw a one-pixel-wide stripe rather than throwing it
- // away
- scaledWidth = 1;
- }
if (yScale >= 0) {
- ty = splashRound(mat[5] - 0.01);
- ty2 = splashRound(mat[5] + yScale + 0.01) - 1;
+ ty = splashFloor(mat[5] - 0.01);
+ ty2 = splashFloor(mat[5] + yScale + 0.01);
} else {
- ty = splashRound(mat[5] + 0.01) - 1;
- ty2 = splashRound(mat[5] + yScale - 0.01);
+ ty = splashFloor(mat[5] + 0.01);
+ ty2 = splashFloor(mat[5] + yScale - 0.01);
}
scaledHeight = abs(ty2 - ty) + 1;
- if (scaledHeight == 0) {
- // technically, this should draw nothing, but it generally seems
- // better to draw a one-pixel-wide stripe rather than throwing it
- // away
- scaledHeight = 1;
- }
xSign = (xScale < 0) ? -1 : 1;
ySign = (yScale < 0) ? -1 : 1;
yShear1 = (SplashCoord)xSign * yShear;
@@ -2939,14 +2258,27 @@ SplashError Splash::drawImage(SplashImageSource src, void *srcData,
xp = w / scaledWidth;
xq = w % scaledWidth;
- // allocate pixel buffer
- pixBuf = (SplashColorPtr)gmalloc((yp + 1) * w * nComps);
+ // allocate pixel buffers
+ colorBuf = (SplashColorPtr)gmalloc((yp + 1) * w * nComps);
+ if (srcAlpha) {
+ alphaBuf = (Guchar *)gmalloc((yp + 1) * w);
+ } else {
+ alphaBuf = NULL;
+ }
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,
+ srcAlpha || (vectorAntialias && clipRes != splashClipAllInside),
+ gFalse);
+ if (vectorAntialias) {
+ drawAAPixelInit();
+ }
+
if (srcAlpha) {
// init y scale Bresenham
@@ -2966,17 +2298,19 @@ SplashError Splash::drawImage(SplashImageSource src, void *srcData,
// read row(s) from image
n = (yp > 0) ? yStep : lastYStep;
if (n > 0) {
- p = pixBuf;
+ p = colorBuf;
+ q = alphaBuf;
for (i = 0; i < n; ++i) {
- (*src)(srcData, p);
+ (*src)(srcData, p, q);
p += w * nComps;
+ q += w;
}
}
lastYStep = yStep;
// loop-invariant constants
k1 = splashRound(xShear * ySign * y);
-
+
// clipping test
if (clipRes != splashClipAllInside &&
!rot &&
@@ -3017,132 +2351,280 @@ SplashError Splash::drawImage(SplashImageSource src, void *srcData,
// loop-invariant constants
n = yStep > 0 ? yStep : 1;
- for (x = 0; x < scaledWidth; ++x) {
+ switch (srcMode) {
- // x scale Bresenham
- xStep = xp;
- xt += xq;
- if (xt >= scaledWidth) {
- xt -= scaledWidth;
- ++xStep;
- }
+ case splashModeMono1:
+ case splashModeMono8:
+ 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;
- }
+ // 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;
- switch (srcMode) {
- case splashModeAMono8:
- p = pixBuf + xSrc * 2;
+ // 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) {
- alphaAcc += *p++;
pixAcc0 += *p++;
+ alphaAcc += *q++;
}
- p += 2 * (w - m);
+ p += w - m;
+ q += w - m;
}
- break;
- case splashModeARGB8:
- p = pixBuf + xSrc * 4;
+ 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);
+
+ // 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;
+ }
+ 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) {
- alphaAcc += *p++;
pixAcc0 += *p++;
pixAcc1 += *p++;
pixAcc2 += *p++;
+ alphaAcc += *q++;
}
- p += 4 * (w - m);
+ p += 3 * (w - m);
+ q += w - m;
}
- break;
- case splashModeBGRA8:
- p = pixBuf + xSrc * 4;
+ 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;
+ }
+ break;
+
+ case splashModeRGBX8:
+ 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++;
- alphaAcc += *p++;
+ *p++;
+ alphaAcc += *q++;
}
p += 4 * (w - m);
+ q += w - m;
}
- break;
+ 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;
+
+ // x shear
+ x1 += xSign;
+
+ // y shear
+ y1 += yShear1;
+ }
+ break;
+
+
#if SPLASH_CMYK
- case splashModeACMYK8:
- p = pixBuf + xSrc * 5;
+ 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) {
- alphaAcc += *p++;
pixAcc0 += *p++;
pixAcc1 += *p++;
pixAcc2 += *p++;
pixAcc3 += *p++;
+ alphaAcc += *q++;
}
- p += 5 * (w - m);
+ p += 4 * (w - m);
+ q += w - m;
}
- break;
-#endif
- default: // make gcc happy
- break;
- }
- pixMul = (SplashCoord)1 / (SplashCoord)(n * m);
- alphaMul = pixMul * (1.0 / 256.0);
- alpha = (SplashCoord)alphaAcc * alphaMul;
+ pixMul = (SplashCoord)1 / (SplashCoord)(n * m);
+ alphaMul = pixMul * (1.0 / 255.0);
+ alpha = (SplashCoord)alphaAcc * alphaMul;
- if (alpha > 0) {
- // mono8 -> mono1 conversion, with halftoning
- if (halftone) {
- pix[0] = state->screen->test(tx + x2, ty + y2,
- (SplashCoord)pixAcc0 * pixMul * (1.0 / 256.0));
+ 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);
- // no conversion, no halftoning
- } else {
- switch (bitmap->mode) {
-#if SPLASH_CMYK
- case splashModeCMYK8:
- pix[3] = (int)((SplashCoord)pixAcc3 * pixMul);
- // fall through
-#endif
- case splashModeRGB8:
- case splashModeBGR8:
- case splashModeRGB8Qt:
- pix[2] = (int)((SplashCoord)pixAcc2 * pixMul);
- pix[1] = (int)((SplashCoord)pixAcc1 * pixMul);
- // fall through
- case splashModeMono1:
- case splashModeMono8:
- pix[0] = (int)((SplashCoord)pixAcc0 * pixMul);
- break;
- default: // make gcc happy
- break;
+ // set pixel
+ pipe.shape = alpha;
+ if (vectorAntialias && clipRes != splashClipAllInside) {
+ drawAAPixel(&pipe, tx + x2, ty + y2);
+ } else {
+ drawPixel(&pipe, tx + x2, ty + y2,
+ clipRes2 == splashClipAllInside);
}
}
- // set pixel
- drawPixel(tx + x2, ty + y2, pix, alpha * state->fillAlpha,
- clipRes2 == splashClipAllInside);
- }
-
- // x scale Bresenham
- xSrc += xStep;
+ // x scale Bresenham
+ xSrc += xStep;
- // x shear
- x1 += xSign;
+ // x shear
+ x1 += xSign;
- // y shear
- y1 += yShear1;
+ // y shear
+ y1 += yShear1;
+ }
+ break;
+#endif // SPLASH_CMYK
}
}
@@ -3165,9 +2647,9 @@ SplashError Splash::drawImage(SplashImageSource src, void *srcData,
// read row(s) from image
n = (yp > 0) ? yStep : lastYStep;
if (n > 0) {
- p = pixBuf;
+ p = colorBuf;
for (i = 0; i < n; ++i) {
- (*src)(srcData, p);
+ (*src)(srcData, p, NULL);
p += w * nComps;
}
}
@@ -3216,32 +2698,33 @@ SplashError Splash::drawImage(SplashImageSource src, void *srcData,
// loop-invariant constants
n = yStep > 0 ? yStep : 1;
- for (x = 0; x < scaledWidth; ++x) {
+ switch (srcMode) {
- // x scale Bresenham
- xStep = xp;
- xt += xq;
- if (xt >= scaledWidth) {
- xt -= scaledWidth;
- ++xStep;
- }
+ case splashModeMono1:
+ case splashModeMono8:
+ 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;
- }
+ // 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;
- switch (srcMode) {
- case splashModeMono1:
- case splashModeMono8:
- p = pixBuf + xSrc;
+ // 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) {
@@ -3249,11 +2732,55 @@ SplashError Splash::drawImage(SplashImageSource src, void *srcData,
}
p += w - m;
}
- break;
- case splashModeRGB8:
- case splashModeBGR8:
- case splashModeRGB8Qt:
- p = pixBuf + xSrc * 3;
+ pixMul = (SplashCoord)1 / (SplashCoord)(n * m);
+
+ pix[0] = (int)((SplashCoord)pixAcc0 * pixMul);
+
+ // 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);
+ }
+
+ // x scale Bresenham
+ xSrc += xStep;
+
+ // x shear
+ x1 += xSign;
+
+ // y shear
+ y1 += yShear1;
+ }
+ 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;
+ p = colorBuf + xSrc * 3;
pixAcc0 = pixAcc1 = pixAcc2 = 0;
for (i = 0; i < n; ++i) {
for (j = 0; j < m; ++j) {
@@ -3263,10 +2790,118 @@ SplashError Splash::drawImage(SplashImageSource src, void *srcData,
}
p += 3 * (w - m);
}
- break;
+ pixMul = (SplashCoord)1 / (SplashCoord)(n * m);
+
+ pix[0] = (int)((SplashCoord)pixAcc0 * pixMul);
+ pix[1] = (int)((SplashCoord)pixAcc1 * pixMul);
+ pix[2] = (int)((SplashCoord)pixAcc2 * pixMul);
+
+ // 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);
+ }
+
+ // x scale Bresenham
+ xSrc += xStep;
+
+ // x shear
+ x1 += xSign;
+
+ // y shear
+ y1 += yShear1;
+ }
+ break;
+
+ case splashModeRGBX8:
+ 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 * 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);
+
+ pix[0] = (int)((SplashCoord)pixAcc0 * pixMul);
+ pix[1] = (int)((SplashCoord)pixAcc1 * pixMul);
+ pix[2] = (int)((SplashCoord)pixAcc2 * pixMul);
+ pix[3] = 255;
+
+ // 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);
+ }
+
+ // x scale Bresenham
+ xSrc += xStep;
+
+ // x shear
+ x1 += xSign;
+
+ // y shear
+ y1 += yShear1;
+ }
+ break;
+
#if SPLASH_CMYK
- case splashModeCMYK8:
- p = pixBuf + xSrc * 4;
+ 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;
+ p = colorBuf + xSrc * 4;
pixAcc0 = pixAcc1 = pixAcc2 = pixAcc3 = 0;
for (i = 0; i < n; ++i) {
for (j = 0; j < m; ++j) {
@@ -3277,74 +2912,595 @@ SplashError Splash::drawImage(SplashImageSource src, void *srcData,
}
p += 4 * (w - m);
}
- break;
-#endif
- default: // make gcc happy
- break;
+ pixMul = (SplashCoord)1 / (SplashCoord)(n * m);
+
+ 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
+ if (vectorAntialias && clipRes != splashClipAllInside) {
+ pipe.shape = (SplashCoord)1;
+ 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;
}
- pixMul = (SplashCoord)1 / (SplashCoord)(n * m);
+ break;
+#endif // SPLASH_CMYK
+ }
+ }
+
+ }
+
+ gfree(colorBuf);
+ gfree(alphaBuf);
+
+ return splashOk;
+}
+
+SplashError Splash::composite(SplashBitmap *src, int xSrc, int ySrc,
+ int xDest, int yDest, int w, int h,
+ GBool noClip, GBool nonIsolated) {
+ SplashPipe pipe;
+ SplashColor pixel;
+ Guchar alpha;
+ Guchar *ap;
+ int x, y;
+
+ if (src->mode != bitmap->mode) {
+ return splashErrModeMismatch;
+ }
+
+ 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) {
+ src->getPixel(xSrc + x, ySrc + y, pixel);
+ alpha = *ap++;
+ if (noClip || 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 = (SplashCoord)(alpha / 255.0);
+ pipeRun(&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) {
+ src->getPixel(xSrc + x, ySrc + y, pixel);
+ if (noClip || state->clip->test(xDest + x, yDest + y)) {
+ pipeRun(&pipe);
+ updateModX(xDest + x);
+ updateModY(yDest + y);
+ } else {
+ pipeIncX(&pipe);
+ }
+ }
+ }
+ }
- // mono8 -> mono1 conversion, with halftoning
- if (halftone) {
- pix[0] = state->screen->test(tx + x2, ty + y2,
- (SplashCoord)pixAcc0 * pixMul * (1.0 / 256.0));
+ return splashOk;
+}
- // no conversion, no halftoning
+void Splash::compositeBackground(SplashColorPtr color) {
+ SplashColorPtr p;
+ Guchar *q;
+ Guchar alpha, alpha1, c, color0, color1, color2, color3;
+ int x, y, mask;
+
+ switch (bitmap->mode) {
+ case splashModeMono1:
+ color0 = color[0];
+ for (y = 0; y < bitmap->height; ++y) {
+ p = &bitmap->data[y * bitmap->rowSize];
+ q = &bitmap->alpha[y * bitmap->width];
+ mask = 0x80;
+ for (x = 0; x < bitmap->width; ++x) {
+ alpha = *q++;
+ alpha1 = 255 - alpha;
+ c = (*p & mask) ? 0xff : 0x00;
+ c = div255(alpha1 * color0 + alpha * c);
+ if (c & 0x80) {
+ *p |= mask;
} else {
- switch (bitmap->mode) {
+ *p &= ~mask;
+ }
+ if (!(mask >>= 1)) {
+ mask = 0x80;
+ ++p;
+ }
+ }
+ }
+ break;
+ case splashModeMono8:
+ color0 = color[0];
+ for (y = 0; y < bitmap->height; ++y) {
+ p = &bitmap->data[y * bitmap->rowSize];
+ 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;
+ }
+ }
+ break;
+ case splashModeRGB8:
+ case splashModeBGR8:
+ color0 = color[0];
+ color1 = color[1];
+ color2 = color[2];
+ for (y = 0; y < bitmap->height; ++y) {
+ p = &bitmap->data[y * bitmap->rowSize];
+ 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;
+ }
+ }
+ break;
+ case splashModeRGBX8:
+ color0 = color[0];
+ color1 = color[1];
+ color2 = color[2];
+ for (y = 0; y < bitmap->height; ++y) {
+ p = &bitmap->data[y * bitmap->rowSize];
+ 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] = 255;
+ p += 4;
+ }
+ }
+ break;
#if SPLASH_CMYK
- case splashModeCMYK8:
- pix[3] = (int)((SplashCoord)pixAcc3 * pixMul);
- // fall through
+ case splashModeCMYK8:
+ color0 = color[0];
+ color1 = color[1];
+ color2 = color[2];
+ color3 = color[3];
+ for (y = 0; y < bitmap->height; ++y) {
+ p = &bitmap->data[y * bitmap->rowSize];
+ 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]);
+ p += 4;
+ }
+ }
+ break;
#endif
- case splashModeRGB8:
- case splashModeRGB8Qt:
- case splashModeBGR8:
- pix[2] = (int)((SplashCoord)pixAcc2 * pixMul);
- pix[1] = (int)((SplashCoord)pixAcc1 * pixMul);
- // fall through
- case splashModeMono1:
- case splashModeMono8:
- pix[0] = (int)((SplashCoord)pixAcc0 * pixMul);
- break;
- default: // make gcc happy
- break;
- }
+ }
+ memset(bitmap->alpha, 255, bitmap->width * bitmap->height);
+}
+
+SplashError Splash::blitTransparent(SplashBitmap *src, int xSrc, int ySrc,
+ int xDest, int yDest, int w, int h) {
+ SplashColor pixel;
+ SplashColorPtr p;
+ Guchar *q;
+ int x, y, mask;
+
+ if (src->mode != bitmap->mode) {
+ return splashErrModeMismatch;
+ }
+
+ switch (bitmap->mode) {
+ case splashModeMono1:
+ for (y = 0; y < h; ++y) {
+ p = &bitmap->data[(yDest + y) * bitmap->rowSize + (xDest >> 3)];
+ mask = 0x80 >> (xDest & 7);
+ for (x = 0; x < w; ++x) {
+ src->getPixel(xSrc + x, ySrc + y, pixel);
+ if (pixel[0]) {
+ *p |= mask;
+ } else {
+ *p &= ~mask;
}
+ if (!(mask >>= 1)) {
+ mask = 0x80;
+ ++p;
+ }
+ }
+ }
+ break;
+ case splashModeMono8:
+ for (y = 0; y < h; ++y) {
+ p = &bitmap->data[(yDest + y) * bitmap->rowSize + xDest];
+ for (x = 0; x < w; ++x) {
+ src->getPixel(xSrc + x, ySrc + y, pixel);
+ *p++ = pixel[0];
+ }
+ }
+ break;
+ case splashModeRGB8:
+ case splashModeBGR8:
+ for (y = 0; y < h; ++y) {
+ p = &bitmap->data[(yDest + y) * bitmap->rowSize + 3 * xDest];
+ for (x = 0; x < w; ++x) {
+ src->getPixel(xSrc + x, ySrc + y, pixel);
+ *p++ = pixel[0];
+ *p++ = pixel[1];
+ *p++ = pixel[2];
+ }
+ }
+ break;
+ case splashModeRGBX8:
+ for (y = 0; y < h; ++y) {
+ p = &bitmap->data[(yDest + y) * bitmap->rowSize + 4 * xDest];
+ for (x = 0; x < w; ++x) {
+ src->getPixel(xSrc + x, ySrc + y, pixel);
+ *p++ = pixel[0];
+ *p++ = pixel[1];
+ *p++ = pixel[2];
+ *p++ = 255;
+ }
+ }
+ break;
+#if SPLASH_CMYK
+ case splashModeCMYK8:
+ for (y = 0; y < h; ++y) {
+ p = &bitmap->data[(yDest + y) * bitmap->rowSize + 4 * xDest];
+ for (x = 0; x < w; ++x) {
+ src->getPixel(xSrc + x, ySrc + y, pixel);
+ *p++ = pixel[0];
+ *p++ = pixel[1];
+ *p++ = pixel[2];
+ *p++ = pixel[3];
+ }
+ }
+ break;
+#endif
+ }
+
+ if (bitmap->alpha) {
+ for (y = 0; y < h; ++y) {
+ q = &bitmap->alpha[(yDest + y) * bitmap->width + xDest];
+ for (x = 0; x < w; ++x) {
+ *q++ = 0x00;
+ }
+ }
+ }
+
+ return splashOk;
+}
+
+SplashPath *Splash::makeStrokePath(SplashPath *path, GBool flatten) {
+ SplashPath *pathIn, *pathOut;
+ SplashCoord w, d, dx, dy, wdx, wdy, dxNext, dyNext, wdxNext, wdyNext;
+ SplashCoord crossprod, dotprod, miter, m;
+ GBool first, last, closed;
+ int subpathStart, next, i;
+ int left0, left1, left2, right0, right1, right2, join0, join1, join2;
+ int leftFirst, rightFirst, firstPt;
+
+ if (flatten) {
+ pathIn = flattenPath(path, state->matrix, state->flatness);
+ if (state->lineDashLength > 0) {
+ pathOut = makeDashedPath(pathIn);
+ delete pathIn;
+ pathIn = pathOut;
+ }
+ } else {
+ pathIn = path;
+ }
+
+ subpathStart = 0; // make gcc happy
+ closed = gFalse; // make gcc happy
+ left0 = left1 = right0 = right1 = join0 = join1 = 0; // make gcc happy
+ leftFirst = rightFirst = firstPt = 0; // make gcc happy
+
+ pathOut = new SplashPath();
+ w = state->lineWidth;
+
+ for (i = 0; i < pathIn->length - 1; ++i) {
+ if (pathIn->flags[i] & splashPathLast) {
+ continue;
+ }
+ 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;
+ } 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);
+ }
+ 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) {
+ firstPt = pathOut->length - 1;
+ }
+ if (first && !closed) {
+ switch (state->lineCap) {
+ case splashLineCapButt:
+ pathOut->lineTo(pathIn->pts[i].x + wdy, pathIn->pts[i].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);
+ 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);
+ break;
+ }
+ } else {
+ pathOut->lineTo(pathIn->pts[i].x + wdy, pathIn->pts[i].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);
- // set pixel
- drawPixel(tx + x2, ty + y2, pix, state->fillAlpha,
- clipRes2 == splashClipAllInside);
+ // 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);
+ 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);
+ 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);
+ break;
+ }
+ } else {
+ pathOut->lineTo(pathIn->pts[i+1].x - wdy, pathIn->pts[i+1].y + wdx);
+ }
- // x scale Bresenham
- xSrc += xStep;
+ // draw the right side of the segment rectangle
+ right2 = pathOut->length - 1;
+ pathOut->close();
+
+ // draw the join
+ join2 = pathOut->length;
+ if (!last || closed) {
+ crossprod = dx * dyNext - dy * dxNext;
+ dotprod = -(dx * dxNext + dy * dyNext);
+ if (dotprod > 0.99999) {
+ // 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)
+ miter = (state->miterLimit + 1) * (state->miterLimit + 1);
+ m = 0;
+ } else {
+ miter = (SplashCoord)2 / ((SplashCoord)1 - dotprod);
+ if (miter < 1) {
+ // this can happen because of floating point inaccuracies
+ miter = 1;
+ }
+ m = splashSqrt(miter - 1);
+ }
+
+ // 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);
- // x shear
- x1 += xSign;
+ } else {
+ pathOut->moveTo(pathIn->pts[i+1].x, pathIn->pts[i+1].y);
+
+ // angle < 180
+ if (crossprod < 0) {
+ pathOut->lineTo(pathIn->pts[i+1].x - wdyNext,
+ pathIn->pts[i+1].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);
+ // bevel join or miter join outside limit
+ } else {
+ pathOut->lineTo(pathIn->pts[i+1].x - wdy, pathIn->pts[i+1].y + wdx);
+ }
- // y shear
- y1 += yShear1;
+ // angle >= 180
+ } else {
+ pathOut->lineTo(pathIn->pts[i+1].x + wdy,
+ pathIn->pts[i+1].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);
+ // bevel join or miter join outside limit
+ } else {
+ pathOut->lineTo(pathIn->pts[i+1].x + wdyNext,
+ pathIn->pts[i+1].y - wdxNext);
+ }
+ }
}
+
+ pathOut->close();
}
+ // add stroke adjustment hints
+ if (state->strokeAdjust) {
+ if (i >= subpathStart + 1) {
+ if (i >= subpathStart + 2) {
+ pathOut->addStrokeAdjustHint(left1, right1, left0 + 1, right0);
+ pathOut->addStrokeAdjustHint(left1, right1, join0, left2);
+ } else {
+ pathOut->addStrokeAdjustHint(left1, right1, firstPt, left2);
+ }
+ pathOut->addStrokeAdjustHint(left1, right1, right2 + 1, right2 + 1);
+ }
+ left0 = left1;
+ left1 = left2;
+ right0 = right1;
+ right1 = right2;
+ join0 = join1;
+ join1 = join2;
+ if (i == subpathStart) {
+ leftFirst = left2;
+ rightFirst = right2;
+ }
+ if (last) {
+ if (i >= subpathStart + 2) {
+ pathOut->addStrokeAdjustHint(left1, right1, left0 + 1, right0);
+ pathOut->addStrokeAdjustHint(left1, right1,
+ join0, pathOut->length - 1);
+ } else {
+ pathOut->addStrokeAdjustHint(left1, right1,
+ firstPt, pathOut->length - 1);
+ }
+ if (closed) {
+ pathOut->addStrokeAdjustHint(left1, right1, firstPt, leftFirst);
+ pathOut->addStrokeAdjustHint(left1, right1,
+ rightFirst + 1, rightFirst + 1);
+ pathOut->addStrokeAdjustHint(leftFirst, rightFirst,
+ left1 + 1, right1);
+ pathOut->addStrokeAdjustHint(leftFirst, rightFirst,
+ join1, pathOut->length - 1);
+ }
+ }
+ }
}
- gfree(pixBuf);
+ if (pathIn != path) {
+ delete pathIn;
+ }
- return splashOk;
+ return pathOut;
}
void Splash::dumpPath(SplashPath *path) {
int i;
for (i = 0; i < path->length; ++i) {
- printf(" %3d: x=%8.2f y=%8.2f%s%s%s%s%s\n",
+ printf(" %3d: x=%8.2f y=%8.2f%s%s%s%s\n",
i, (double)path->pts[i].x, (double)path->pts[i].y,
(path->flags[i] & splashPathFirst) ? " first" : "",
(path->flags[i] & splashPathLast) ? " last" : "",
(path->flags[i] & splashPathClosed) ? " closed" : "",
- (path->flags[i] & splashPathCurve) ? " curve" : "",
- (path->flags[i] & splashPathArcCW) ? " arcCW" : "");
+ (path->flags[i] & splashPathCurve) ? " curve" : "");
}
}
diff --git a/splash/Splash.h b/splash/Splash.h
index 783da8fc..99203b2c 100644
--- a/splash/Splash.h
+++ b/splash/Splash.h
@@ -14,6 +14,7 @@
#include "SplashTypes.h"
#include "SplashClip.h"
+class Splash;
class SplashBitmap;
struct SplashGlyphBitmap;
class SplashState;
@@ -22,6 +23,7 @@ class SplashScreen;
class SplashPath;
class SplashXPath;
class SplashFont;
+struct SplashPipe;
//------------------------------------------------------------------------
@@ -33,7 +35,29 @@ typedef GBool (*SplashImageMaskSource)(void *data, SplashColorPtr pixel);
// Retrieves the next line of pixels in an image. Normally, fills in
// *<line> and returns true. If the image stream is exhausted,
// returns false.
-typedef GBool (*SplashImageSource)(void *data, SplashColorPtr line);
+typedef GBool (*SplashImageSource)(void *data, SplashColorPtr colorLine,
+ Guchar *alphaLine);
+
+//------------------------------------------------------------------------
+
+enum SplashPipeResultColorCtrl {
+#if SPLASH_CMYK
+ splashPipeResultColorNoAlphaBlendCMYK,
+#endif
+ splashPipeResultColorNoAlphaBlendRGB,
+ splashPipeResultColorNoAlphaBlendMono,
+ splashPipeResultColorAlphaNoBlendMono,
+ splashPipeResultColorAlphaNoBlendRGB,
+#if SPLASH_CMYK
+ splashPipeResultColorAlphaNoBlendCMYK,
+#endif
+ splashPipeResultColorAlphaBlendMono,
+ splashPipeResultColorAlphaBlendRGB
+#if SPLASH_CMYK
+ ,
+ splashPipeResultColorAlphaBlendCMYK
+#endif
+};
//------------------------------------------------------------------------
// Splash
@@ -43,12 +67,16 @@ class Splash {
public:
// Create a new rasterizer object.
- Splash(SplashBitmap *bitmapA);
+ Splash(SplashBitmap *bitmapA, GBool vectorAntialiasA,
+ SplashScreenParams *screenParams = NULL);
+ Splash(SplashBitmap *bitmapA, GBool vectorAntialiasA,
+ SplashScreen *screenA);
~Splash();
//----- state read
+ SplashCoord *getMatrix();
SplashPattern *getStrokePattern();
SplashPattern *getFillPattern();
SplashScreen *getScreen();
@@ -64,9 +92,12 @@ public:
int getLineDashLength();
SplashCoord getLineDashPhase();
SplashClip *getClip();
+ SplashBitmap *getSoftMask();
+ GBool getInNonIsolatedGroup();
//----- state write
+ void setMatrix(SplashCoord *matrix);
void setStrokePattern(SplashPattern *strokeColor);
void setFillPattern(SplashPattern *fillColor);
void setScreen(SplashScreen *screen);
@@ -81,25 +112,28 @@ public:
// the <lineDash> array will be copied
void setLineDash(SplashCoord *lineDash, int lineDashLength,
SplashCoord lineDashPhase);
+ void setStrokeAdjust(GBool strokeAdjust);
+ // NB: uses transformed coordinates.
void clipResetToRect(SplashCoord x0, SplashCoord y0,
SplashCoord x1, SplashCoord y1);
+ // NB: uses transformed coordinates.
SplashError clipToRect(SplashCoord x0, SplashCoord y0,
SplashCoord x1, SplashCoord y1);
+ // NB: uses untransformed coordinates.
SplashError clipToPath(SplashPath *path, GBool eo);
+ void setSoftMask(SplashBitmap *softMask);
+ void setInNonIsolatedGroup(SplashBitmap *alpha0BitmapA,
+ int alpha0XA, int alpha0YA);
//----- state save/restore
void saveState();
SplashError restoreState();
- //----- soft mask
-
- void setSoftMask(SplashBitmap *softMaskA);
-
//----- drawing operations
// Fill the bitmap with <color>. This is not subject to clipping.
- void clear(SplashColorPtr color);
+ void clear(SplashColorPtr color, Guchar alpha = 0x00);
// Stroke a path using the current stroke pattern.
SplashError stroke(SplashPath *path);
@@ -132,12 +166,15 @@ public:
// is assumed to produce pixels in raster order, starting from the
// top line.
SplashError fillImageMask(SplashImageMaskSource src, void *srcData,
- int w, int h, SplashCoord *mat);
+ int w, int h, SplashCoord *mat,
+ GBool glyphMode);
// Draw an image. This will read <h> lines of <w> pixels from
// <src>, starting with the top line. These pixels are assumed to
- // be in the source mode, <srcMode>. The following combinations of
- // source and target modes are supported:
+ // be in the source mode, <srcMode>. If <srcAlpha> is true, the
+ // alpha values returned by <src> are used; otherwise they are
+ // ignored. The following combinations of source and target modes
+ // are supported:
// source target
// ------ ------
// Mono1 Mono1
@@ -145,15 +182,35 @@ public:
// Mono8 Mono8
// RGB8 RGB8
// BGR8 BGR8
- // ARGB8 RGB8 -- with source alpha (masking)
- // BGRA8 BGR8 -- with source alpha (masking)
+ // CMYK8 CMYK8
// The matrix behaves as for fillImageMask.
SplashError drawImage(SplashImageSource src, void *srcData,
- SplashColorMode srcMode,
+ SplashColorMode srcMode, GBool srcAlpha,
int w, int h, SplashCoord *mat);
+ // Composite a rectangular region from <src> onto this Splash
+ // object.
+ SplashError composite(SplashBitmap *src, int xSrc, int ySrc,
+ int xDest, int yDest, int w, int h,
+ GBool noClip, GBool nonIsolated);
+
+ // Composite this Splash object onto a background color. The
+ // background alpha is assumed to be 1.
+ void compositeBackground(SplashColorPtr color);
+
+ // Copy a rectangular region from <src> onto the bitmap belonging to
+ // this Splash object. The destination alpha values are all set to
+ // zero.
+ SplashError blitTransparent(SplashBitmap *src, int xSrc, int ySrc,
+ int xDest, int yDest, int w, int h);
+
//----- 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);
+
// Return the associated bitmap.
SplashBitmap *getBitmap() { return bitmap; }
@@ -172,30 +229,62 @@ public:
// Toggle debug mode on or off.
void setDebugMode(GBool debugModeA) { debugMode = debugModeA; }
+#if 1 //~tmp: turn off anti-aliasing temporarily
+ GBool getVectorAntialias() { return vectorAntialias; }
+ void setVectorAntialias(GBool vaa) { vectorAntialias = vaa; }
+#endif
+
private:
+ void pipeInit(SplashPipe *pipe, int x, int y,
+ SplashPattern *pattern, SplashColorPtr cSrc,
+ SplashCoord aInput, GBool usesShape,
+ GBool nonIsolatedGroup);
+ void pipeRun(SplashPipe *pipe);
+ void pipeSetXY(SplashPipe *pipe, int x, int y);
+ void pipeIncX(SplashPipe *pipe);
+ void drawPixel(SplashPipe *pipe, int x, int y, GBool noClip);
+ void drawAAPixelInit();
+ void drawAAPixel(SplashPipe *pipe, int x, int y);
+ void drawSpan(SplashPipe *pipe, int x0, int x1, int y, GBool noClip);
+ void drawAALine(SplashPipe *pipe, int x0, int x1, int y);
+ void transform(SplashCoord *matrix, SplashCoord xi, SplashCoord yi,
+ SplashCoord *xo, SplashCoord *yo);
void updateModX(int x);
void updateModY(int y);
- void strokeNarrow(SplashXPath *xPath);
- void strokeWide(SplashXPath *xPath);
- SplashXPath *makeDashedPath(SplashXPath *xPath);
+ void strokeNarrow(SplashPath *path);
+ void strokeWide(SplashPath *path);
+ SplashPath *flattenPath(SplashPath *path, SplashCoord *matrix,
+ SplashCoord flatness);
+ void flattenCurve(SplashCoord x0, SplashCoord y0,
+ SplashCoord x1, SplashCoord y1,
+ SplashCoord x2, SplashCoord y2,
+ SplashCoord x3, SplashCoord y3,
+ SplashCoord *matrix, SplashCoord flatness2,
+ SplashPath *fPath);
+ SplashPath *makeDashedPath(SplashPath *xPath);
SplashError fillWithPattern(SplashPath *path, GBool eo,
SplashPattern *pattern, SplashCoord alpha);
- void drawPixel(int x, int y, SplashColorPtr color,
- SplashCoord alpha, GBool noClip);
- void drawPixel(int x, int y, SplashPattern *pattern,
- SplashCoord alpha, GBool noClip);
- void drawSpan(int x0, int x1, int y, SplashPattern *pattern,
- SplashCoord alpha, GBool noClip);
- void xorSpan(int x0, int x1, int y, SplashPattern *pattern, GBool noClip);
+ SplashError fillGlyph2(int x0, int y0, SplashGlyphBitmap *glyph);
void dumpPath(SplashPath *path);
void dumpXPath(SplashXPath *path);
+ static SplashPipeResultColorCtrl pipeResultColorNoAlphaBlend[];
+ static SplashPipeResultColorCtrl pipeResultColorAlphaNoBlend[];
+ static SplashPipeResultColorCtrl pipeResultColorAlphaBlend[];
+ static int pipeNonIsoGroupCorrection[];
+
SplashBitmap *bitmap;
SplashState *state;
- SplashBitmap *softMask;
+ SplashBitmap *aaBuf;
+ int aaBufY;
+ SplashBitmap *alpha0Bitmap; // for non-isolated groups, this is the
+ // bitmap containing the alpha0 values
+ int alpha0X, alpha0Y; // offset within alpha0Bitmap
+ SplashCoord aaGamma[splashAASize * splashAASize + 1];
int modXMin, modYMin, modXMax, modYMax;
SplashClipResult opClipRes;
+ GBool vectorAntialias;
GBool debugMode;
};
diff --git a/splash/SplashBitmap.cc b/splash/SplashBitmap.cc
index 989e318d..9420bbed 100644
--- a/splash/SplashBitmap.cc
+++ b/splash/SplashBitmap.cc
@@ -20,7 +20,8 @@
//------------------------------------------------------------------------
SplashBitmap::SplashBitmap(int widthA, int heightA, int rowPad,
- SplashColorMode modeA, GBool topDown) {
+ SplashColorMode modeA, GBool alphaA,
+ GBool topDown) {
width = widthA;
height = heightA;
mode = modeA;
@@ -31,24 +32,16 @@ SplashBitmap::SplashBitmap(int widthA, int heightA, int rowPad,
case splashModeMono8:
rowSize = width;
break;
- case splashModeAMono8:
- rowSize = width * 2;
- break;
case splashModeRGB8:
case splashModeBGR8:
rowSize = width * 3;
break;
- case splashModeRGB8Qt:
- case splashModeARGB8:
- case splashModeBGRA8:
-#if SPLASH_CMYK
- case splashModeCMYK8:
-#endif
+ case splashModeRGBX8:
rowSize = width * 4;
break;
#if SPLASH_CMYK
- case splashModeACMYK8:
- rowSize = width * 5;
+ case splashModeCMYK8:
+ rowSize = width * 4;
break;
#endif
}
@@ -59,6 +52,11 @@ SplashBitmap::SplashBitmap(int widthA, int heightA, int rowPad,
data += (height - 1) * rowSize;
rowSize = -rowSize;
}
+ if (alphaA) {
+ alpha = (Guchar *)gmalloc(width * height);
+ } else {
+ alpha = NULL;
+ }
}
@@ -68,6 +66,7 @@ SplashBitmap::~SplashBitmap() {
} else {
gfree(data);
}
+ gfree(alpha);
}
SplashError SplashBitmap::writePNMFile(char *fileName) {
@@ -107,19 +106,6 @@ SplashError SplashBitmap::writePNMFile(char *fileName) {
}
break;
- case splashModeAMono8:
- 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(splashAMono8M(p), f);
- p += 2;
- }
- row += rowSize;
- }
- break;
-
case splashModeRGB8:
fprintf(f, "P6\n%d %d\n255\n", width, height);
row = data;
@@ -135,22 +121,7 @@ SplashError SplashBitmap::writePNMFile(char *fileName) {
}
break;
- case splashModeBGR8:
- 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(splashBGR8R(p), f);
- fputc(splashBGR8G(p), f);
- fputc(splashBGR8B(p), f);
- p += 3;
- }
- row += rowSize;
- }
- break;
-
- case splashModeRGB8Qt:
+ case splashModeRGBX8:
fprintf(f, "P6\n%d %d\n255\n", width, height);
row = data;
for (y = 0; y < height; ++y) {
@@ -165,31 +136,17 @@ SplashError SplashBitmap::writePNMFile(char *fileName) {
}
break;
- case splashModeARGB8:
- 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(splashARGB8R(p), f);
- fputc(splashARGB8G(p), f);
- fputc(splashARGB8B(p), f);
- p += 4;
- }
- row += rowSize;
- }
- break;
- case splashModeBGRA8:
+ case splashModeBGR8:
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(splashBGRA8R(p), f);
- fputc(splashBGRA8G(p), f);
- fputc(splashBGRA8B(p), f);
- p += 4;
+ fputc(splashBGR8R(p), f);
+ fputc(splashBGR8G(p), f);
+ fputc(splashBGR8B(p), f);
+ p += 3;
}
row += rowSize;
}
@@ -197,7 +154,6 @@ SplashError SplashBitmap::writePNMFile(char *fileName) {
#if SPLASH_CMYK
case splashModeCMYK8:
- case splashModeACMYK8:
// PNM doesn't support CMYK
break;
#endif
@@ -217,49 +173,43 @@ void SplashBitmap::getPixel(int x, int y, SplashColorPtr pixel) {
case splashModeMono1:
p = &data[y * rowSize + (x >> 3)];
pixel[0] = (p[0] >> (7 - (x & 7))) & 1;
+ pixel[0] = (p[0] & (0x80 >> (x & 7))) ? 0xff : 0x00;
break;
case splashModeMono8:
p = &data[y * rowSize + x];
pixel[0] = p[0];
break;
- case splashModeAMono8:
- p = &data[y * rowSize + 2 * x];
- pixel[0] = p[0];
- pixel[1] = p[1];
- break;
case splashModeRGB8:
- case splashModeBGR8:
p = &data[y * rowSize + 3 * x];
pixel[0] = p[0];
pixel[1] = p[1];
pixel[2] = p[2];
break;
- case splashModeRGB8Qt:
+ case splashModeRGBX8:
p = &data[y * rowSize + 4 * x];
+ pixel[0] = p[0];
+ pixel[1] = p[1];
+ pixel[2] = p[2];
+ pixel[3] = p[3];
+ break;
+ case splashModeBGR8:
+ p = &data[y * rowSize + 3 * x];
pixel[0] = p[2];
pixel[1] = p[1];
pixel[2] = p[0];
break;
- case splashModeARGB8:
- case splashModeBGRA8:
#if SPLASH_CMYK
case splashModeCMYK8:
-#endif
p = &data[y * rowSize + 4 * x];
pixel[0] = p[0];
pixel[1] = p[1];
pixel[2] = p[2];
pixel[3] = p[3];
break;
-#if SPLASH_CMYK
- case splashModeACMYK8:
- p = &data[y * rowSize + 5 * x];
- pixel[0] = p[0];
- pixel[1] = p[1];
- pixel[2] = p[2];
- pixel[3] = p[3];
- pixel[4] = p[4];
- break;
#endif
}
}
+
+Guchar SplashBitmap::getAlpha(int x, int y) {
+ return alpha[y * width + x];
+}
diff --git a/splash/SplashBitmap.h b/splash/SplashBitmap.h
index 83f1539f..37022d77 100644
--- a/splash/SplashBitmap.h
+++ b/splash/SplashBitmap.h
@@ -25,19 +25,23 @@ public:
// <rowPad> bytes. If <topDown> is false, the bitmap will be stored
// upside-down, i.e., with the last row first in memory.
SplashBitmap(int widthA, int heightA, int rowPad,
- SplashColorMode modeA, GBool topDown = gTrue);
+ SplashColorMode modeA, GBool alphaA,
+ GBool topDown = gTrue);
~SplashBitmap();
int getWidth() { return width; }
int getHeight() { return height; }
int getRowSize() { return rowSize; }
+ int getAlphaRowSize() { return width; }
SplashColorMode getMode() { return mode; }
SplashColorPtr getDataPtr() { return data; }
+ Guchar *getAlphaPtr() { return alpha; }
SplashError writePNMFile(char *fileName);
void getPixel(int x, int y, SplashColorPtr pixel);
+ Guchar getAlpha(int x, int y);
private:
@@ -45,7 +49,9 @@ private:
int rowSize; // size of one row of data, in bytes
// - negative for bottom-up bitmaps
SplashColorMode mode; // color mode
- SplashColorPtr data; // pointer to row zero of the bitmap data
+ SplashColorPtr data; // pointer to row zero of the color data
+ Guchar *alpha; // pointer to row zero of the alpha data
+ // (always top-down)
friend class Splash;
};
diff --git a/splash/SplashClip.cc b/splash/SplashClip.cc
index 724c65c3..87b0d7ef 100644
--- a/splash/SplashClip.cc
+++ b/splash/SplashClip.cc
@@ -14,10 +14,10 @@
#include <string.h>
#include "goo/gmem.h"
#include "SplashErrorCodes.h"
-#include "SplashMath.h"
#include "SplashPath.h"
#include "SplashXPath.h"
#include "SplashXPathScanner.h"
+#include "SplashBitmap.h"
#include "SplashClip.h"
//------------------------------------------------------------------------
@@ -31,21 +31,27 @@
//------------------------------------------------------------------------
SplashClip::SplashClip(SplashCoord x0, SplashCoord y0,
- SplashCoord x1, SplashCoord y1) {
+ SplashCoord x1, SplashCoord y1,
+ GBool antialiasA) {
+ antialias = antialiasA;
if (x0 < x1) {
- xMin = splashFloor(x0);
- xMax = splashFloor(x1);
+ xMin = x0;
+ xMax = x1;
} else {
- xMin = splashFloor(x1);
- xMax = splashFloor(x0);
+ xMin = x1;
+ xMax = x0;
}
if (y0 < y1) {
- yMin = splashFloor(y0);
- yMax = splashFloor(y1);
+ yMin = y0;
+ yMax = y1;
} else {
- yMin = splashFloor(y1);
- yMax = splashFloor(y0);
+ yMin = y1;
+ yMax = y0;
}
+ xMinI = splashFloor(xMin);
+ yMinI = splashFloor(yMin);
+ xMaxI = splashFloor(xMax);
+ yMaxI = splashFloor(yMax);
paths = NULL;
flags = NULL;
scanners = NULL;
@@ -55,10 +61,15 @@ SplashClip::SplashClip(SplashCoord x0, SplashCoord y0,
SplashClip::SplashClip(SplashClip *clip) {
int i;
+ antialias = clip->antialias;
xMin = clip->xMin;
yMin = clip->yMin;
xMax = clip->xMax;
yMax = clip->yMax;
+ xMinI = clip->xMinI;
+ yMinI = clip->yMinI;
+ xMaxI = clip->xMaxI;
+ yMaxI = clip->yMaxI;
length = clip->length;
size = clip->size;
paths = (SplashXPath **)gmallocn(size, sizeof(SplashXPath *));
@@ -116,98 +127,117 @@ void SplashClip::resetToRect(SplashCoord x0, SplashCoord y0,
length = size = 0;
if (x0 < x1) {
- xMin = splashFloor(x0);
- xMax = splashFloor(x1);
+ xMin = x0;
+ xMax = x1;
} else {
- xMin = splashFloor(x1);
- xMax = splashFloor(x0);
+ xMin = x1;
+ xMax = x0;
}
if (y0 < y1) {
- yMin = splashFloor(y0);
- yMax = splashFloor(y1);
+ yMin = y0;
+ yMax = y1;
} else {
- yMin = splashFloor(y1);
- yMax = splashFloor(y0);
+ yMin = y1;
+ yMax = y0;
}
+ xMinI = splashFloor(xMin);
+ yMinI = splashFloor(yMin);
+ xMaxI = splashFloor(xMax);
+ yMaxI = splashFloor(yMax);
}
SplashError SplashClip::clipToRect(SplashCoord x0, SplashCoord y0,
SplashCoord x1, SplashCoord y1) {
- int x0I, y0I, x1I, y1I;
-
if (x0 < x1) {
- x0I = splashFloor(x0);
- x1I = splashFloor(x1);
+ if (x0 > xMin) {
+ xMin = x0;
+ xMinI = splashFloor(xMin);
+ }
+ if (x1 < xMax) {
+ xMax = x1;
+ xMaxI = splashFloor(xMax);
+ }
} else {
- x0I = splashFloor(x1);
- x1I = splashFloor(x0);
- }
- if (x0I > xMin) {
- xMin = x0I;
- }
- if (x1I < xMax) {
- xMax = x1I;
+ if (x1 > xMin) {
+ xMin = x1;
+ xMinI = splashFloor(xMin);
+ }
+ if (x0 < xMax) {
+ xMax = x0;
+ xMaxI = splashFloor(xMax);
+ }
}
if (y0 < y1) {
- y0I = splashFloor(y0);
- y1I = splashFloor(y1);
+ if (y0 > yMin) {
+ yMin = y0;
+ yMinI = splashFloor(yMin);
+ }
+ if (y1 < yMax) {
+ yMax = y1;
+ yMaxI = splashFloor(yMax);
+ }
} else {
- y0I = splashFloor(y1);
- y1I = splashFloor(y0);
- }
- if (y0I > yMin) {
- yMin = y0I;
- }
- if (y1I < yMax) {
- yMax = y1I;
+ if (y1 > yMin) {
+ yMin = y1;
+ yMinI = splashFloor(yMin);
+ }
+ if (y0 < yMax) {
+ yMax = y0;
+ yMaxI = splashFloor(yMax);
+ }
}
return splashOk;
}
-SplashError SplashClip::clipToPath(SplashPath *path, SplashCoord flatness,
- GBool eo) {
+SplashError SplashClip::clipToPath(SplashPath *path, SplashCoord *matrix,
+ SplashCoord flatness, GBool eo) {
SplashXPath *xPath;
- xPath = new SplashXPath(path, flatness, gTrue);
+ xPath = new SplashXPath(path, matrix, flatness, gTrue);
// check for an empty path
if (xPath->length == 0) {
xMax = xMin - 1;
yMax = yMin - 1;
+ xMaxI = splashFloor(xMax);
+ yMaxI = splashFloor(yMax);
delete xPath;
// check for a rectangle
} else if (xPath->length == 4 &&
- ((xPath->segs[0].x0 == xPath->segs[0].x1 &&
- xPath->segs[0].x0 == xPath->segs[1].x0 &&
- xPath->segs[0].x0 == xPath->segs[3].x1 &&
- xPath->segs[2].x0 == xPath->segs[2].x1 &&
- xPath->segs[2].x0 == xPath->segs[1].x1 &&
- xPath->segs[2].x0 == xPath->segs[3].x0 &&
- xPath->segs[1].y0 == xPath->segs[1].y1 &&
- xPath->segs[1].y0 == xPath->segs[0].y1 &&
- xPath->segs[1].y0 == xPath->segs[2].y0 &&
- xPath->segs[3].y0 == xPath->segs[3].y1 &&
- xPath->segs[3].y0 == xPath->segs[0].y0 &&
- xPath->segs[3].y0 == xPath->segs[2].y1) ||
- (xPath->segs[0].y0 == xPath->segs[0].y1 &&
- xPath->segs[0].y0 == xPath->segs[1].y0 &&
- xPath->segs[0].y0 == xPath->segs[3].y1 &&
- xPath->segs[2].y0 == xPath->segs[2].y1 &&
- xPath->segs[2].y0 == xPath->segs[1].y1 &&
- xPath->segs[2].y0 == xPath->segs[3].y0 &&
- xPath->segs[1].x0 == xPath->segs[1].x1 &&
- xPath->segs[1].x0 == xPath->segs[0].x1 &&
- xPath->segs[1].x0 == xPath->segs[2].x0 &&
- xPath->segs[3].x0 == xPath->segs[3].x1 &&
- xPath->segs[3].x0 == xPath->segs[0].x0 &&
- xPath->segs[3].x0 == xPath->segs[2].x1))) {
+ ((xPath->segs[0].x0 == xPath->segs[0].x1 &&
+ xPath->segs[0].x0 == xPath->segs[1].x0 &&
+ xPath->segs[0].x0 == xPath->segs[3].x1 &&
+ xPath->segs[2].x0 == xPath->segs[2].x1 &&
+ xPath->segs[2].x0 == xPath->segs[1].x1 &&
+ xPath->segs[2].x0 == xPath->segs[3].x0 &&
+ xPath->segs[1].y0 == xPath->segs[1].y1 &&
+ xPath->segs[1].y0 == xPath->segs[0].y1 &&
+ xPath->segs[1].y0 == xPath->segs[2].y0 &&
+ xPath->segs[3].y0 == xPath->segs[3].y1 &&
+ xPath->segs[3].y0 == xPath->segs[0].y0 &&
+ xPath->segs[3].y0 == xPath->segs[2].y1) ||
+ (xPath->segs[0].y0 == xPath->segs[0].y1 &&
+ xPath->segs[0].y0 == xPath->segs[1].y0 &&
+ xPath->segs[0].y0 == xPath->segs[3].y1 &&
+ xPath->segs[2].y0 == xPath->segs[2].y1 &&
+ xPath->segs[2].y0 == xPath->segs[1].y1 &&
+ xPath->segs[2].y0 == xPath->segs[3].y0 &&
+ xPath->segs[1].x0 == xPath->segs[1].x1 &&
+ xPath->segs[1].x0 == xPath->segs[0].x1 &&
+ xPath->segs[1].x0 == xPath->segs[2].x0 &&
+ xPath->segs[3].x0 == xPath->segs[3].x1 &&
+ xPath->segs[3].x0 == xPath->segs[0].x0 &&
+ xPath->segs[3].x0 == xPath->segs[2].x1))) {
clipToRect(xPath->segs[0].x0, xPath->segs[0].y0,
xPath->segs[2].x0, xPath->segs[2].y0);
delete xPath;
} else {
grow(1);
+ if (antialias) {
+ xPath->aaScale();
+ }
xPath->sort();
paths[length] = xPath;
flags[length] = eo ? splashClipEO : 0;
@@ -222,14 +252,22 @@ GBool SplashClip::test(int x, int y) {
int i;
// check the rectangle
- if (x < xMin || x > xMax || y < yMin || y > yMax) {
+ if (x < xMinI || x > xMaxI || y < yMinI || y > yMaxI) {
return gFalse;
}
// check the paths
- for (i = 0; i < length; ++i) {
- if (!scanners[i]->test(x, y)) {
- return gFalse;
+ if (antialias) {
+ for (i = 0; i < length; ++i) {
+ if (!scanners[i]->test(x * splashAASize, y * splashAASize)) {
+ return gFalse;
+ }
+ }
+ } else {
+ for (i = 0; i < length; ++i) {
+ if (!scanners[i]->test(x, y)) {
+ return gFalse;
+ }
}
}
@@ -238,12 +276,18 @@ GBool SplashClip::test(int x, int y) {
SplashClipResult SplashClip::testRect(int rectXMin, int rectYMin,
int rectXMax, int rectYMax) {
- if (rectXMax < xMin || rectXMin > xMax ||
- rectYMax < yMin || rectYMin > yMax) {
+ // This tests the rectangle:
+ // x = [rectXMin, rectXMax + 1) (note: rect coords are ints)
+ // y = [rectYMin, rectYMax + 1)
+ // against the clipping region:
+ // x = [xMin, xMax] (note: clipping coords are fp)
+ // y = [yMin, yMax]
+ if ((SplashCoord)(rectXMax + 1) <= xMin || (SplashCoord)rectXMin > xMax ||
+ (SplashCoord)(rectYMax + 1) <= yMin || (SplashCoord)rectYMin > yMax) {
return splashClipAllOutside;
}
- if (rectXMin >= xMin && rectXMax <= xMax &&
- rectYMin >= yMin && rectYMax <= yMax &&
+ if ((SplashCoord)rectXMin >= xMin && (SplashCoord)(rectXMax + 1) <= xMax &&
+ (SplashCoord)rectYMin >= yMin && (SplashCoord)(rectYMax + 1) <= yMax &&
length == 0) {
return splashClipAllInside;
}
@@ -253,18 +297,86 @@ SplashClipResult SplashClip::testRect(int rectXMin, int rectYMin,
SplashClipResult SplashClip::testSpan(int spanXMin, int spanXMax, int spanY) {
int i;
- if (spanXMax < xMin || spanXMin > xMax ||
- spanY < yMin || spanY > yMax) {
+ // This tests the rectangle:
+ // x = [spanXMin, spanXMax + 1) (note: span coords are ints)
+ // y = [spanY, spanY + 1)
+ // against the clipping region:
+ // x = [xMin, xMax] (note: clipping coords are fp)
+ // y = [yMin, yMax]
+ if ((SplashCoord)(spanXMax + 1) <= xMin || (SplashCoord)spanXMin > xMax ||
+ (SplashCoord)(spanY + 1) <= yMin || (SplashCoord)spanY > yMax) {
return splashClipAllOutside;
}
- if (!(spanXMin >= xMin && spanXMax <= xMax &&
- spanY >= yMin && spanY <= yMax)) {
+ if (!((SplashCoord)spanXMin >= xMin && (SplashCoord)(spanXMax + 1) <= xMax &&
+ (SplashCoord)spanY >= yMin && (SplashCoord)(spanY + 1) <= yMax)) {
return splashClipPartial;
}
- for (i = 0; i < length; ++i) {
- if (!scanners[i]->testSpan(xMin, xMax, spanY)) {
- return splashClipPartial;
+ if (antialias) {
+ for (i = 0; i < length; ++i) {
+ if (!scanners[i]->testSpan(spanXMin * splashAASize,
+ spanXMax * splashAASize + (splashAASize - 1),
+ spanY * splashAASize)) {
+ return splashClipPartial;
+ }
+ }
+ } else {
+ for (i = 0; i < length; ++i) {
+ if (!scanners[i]->testSpan(spanXMin, spanXMax, spanY)) {
+ return splashClipPartial;
+ }
}
}
return splashClipAllInside;
}
+
+void SplashClip::clipAALine(SplashBitmap *aaBuf, int *x0, int *x1, int y) {
+ int xx0, xx1, xx, yy, i;
+ SplashColorPtr p;
+
+ // zero out pixels with x < xMin
+ xx0 = *x0 * splashAASize;
+ xx1 = splashFloor(xMin * splashAASize);
+ if (xx1 > aaBuf->getWidth()) {
+ xx1 = aaBuf->getWidth();
+ }
+ if (xx0 < xx1) {
+ xx0 &= ~7;
+ for (yy = 0; yy < splashAASize; ++yy) {
+ p = aaBuf->getDataPtr() + yy * aaBuf->getRowSize() + (xx0 >> 3);
+ for (xx = xx0; xx + 7 < xx1; xx += 8) {
+ *p++ = 0;
+ }
+ if (xx < xx1) {
+ *p &= 0xff >> (xx1 & 7);
+ }
+ }
+ *x0 = splashFloor(xMin);
+ }
+
+ // zero out pixels with x > xMax
+ xx0 = splashFloor(xMax * splashAASize) + 1;
+ if (xx0 < 0) {
+ xx0 = 0;
+ }
+ xx1 = (*x1 + 1) * splashAASize;
+ if (xx0 < xx1) {
+ for (yy = 0; yy < splashAASize; ++yy) {
+ p = aaBuf->getDataPtr() + yy * aaBuf->getRowSize() + (xx0 >> 3);
+ xx = xx0;
+ if (xx & 7) {
+ *p &= 0xff00 >> (xx & 7);
+ xx = (xx & ~7) + 8;
+ ++p;
+ }
+ for (; xx < xx1; xx += 8) {
+ *p++ = 0;
+ }
+ }
+ *x1 = splashFloor(xMax);
+ }
+
+ // check the paths
+ for (i = 0; i < length; ++i) {
+ scanners[i]->clipAALine(aaBuf, x0, x1, y);
+ }
+}
diff --git a/splash/SplashClip.h b/splash/SplashClip.h
index d27d7ae3..2420f9c4 100644
--- a/splash/SplashClip.h
+++ b/splash/SplashClip.h
@@ -12,10 +12,12 @@
#endif
#include "SplashTypes.h"
+#include "SplashMath.h"
class SplashPath;
class SplashXPath;
class SplashXPathScanner;
+class SplashBitmap;
//------------------------------------------------------------------------
@@ -34,7 +36,8 @@ public:
// Create a clip, for the given rectangle.
SplashClip(SplashCoord x0, SplashCoord y0,
- SplashCoord x1, SplashCoord y1);
+ SplashCoord x1, SplashCoord y1,
+ GBool antialiasA);
// Copy a clip.
SplashClip *copy() { return new SplashClip(this); }
@@ -50,8 +53,8 @@ public:
SplashCoord x1, SplashCoord y1);
// Interesect the clip with <path>.
- SplashError clipToPath(SplashPath *path, SplashCoord flatness,
- GBool eo);
+ SplashError clipToPath(SplashPath *path, SplashCoord *matrix,
+ SplashCoord flatness, GBool eo);
// Returns true if (<x>,<y>) is inside the clip.
GBool test(int x, int y);
@@ -71,11 +74,16 @@ public:
// Similar to testRect, but tests a horizontal span.
SplashClipResult testSpan(int spanXMin, int spanXMax, int spanY);
- // Get the rectangle part of the clip region.
- int getXMin() { return xMin; }
- int getXMax() { return xMax; }
- int getYMin() { return yMin; }
- int getYMax() { return yMax; }
+ // Clips an anti-aliased line by setting pixels to zero. On entry,
+ // all non-zero pixels are between <x0> and <x1>. This function
+ // will update <x0> and <x1>.
+ void clipAALine(SplashBitmap *aaBuf, int *x0, int *x1, int y);
+
+ // Get the rectangle part of the clip region, in integer coordinates.
+ int getXMinI() { return xMinI; }
+ int getXMaxI() { return xMaxI; }
+ int getYMinI() { return yMinI; }
+ int getYMaxI() { return yMaxI; }
// Get the number of arbitrary paths used by the clip region.
int getNumPaths() { return length; }
@@ -85,7 +93,9 @@ private:
SplashClip(SplashClip *clip);
void grow(int nPaths);
- int xMin, yMin, xMax, yMax;
+ GBool antialias;
+ SplashCoord xMin, yMin, xMax, yMax;
+ int xMinI, yMinI, xMaxI, yMaxI;
SplashXPath **paths;
Guchar *flags;
SplashXPathScanner **scanners;
diff --git a/splash/SplashFTFont.cc b/splash/SplashFTFont.cc
index 8ffff8eb..3c7da792 100644
--- a/splash/SplashFTFont.cc
+++ b/splash/SplashFTFont.cc
@@ -12,11 +12,6 @@
#pragma implementation
#endif
-#define MAKE_VERSION( a,b,c ) (((a) << 16) | ((b) << 8) | (c))
-
-#define FREETYPE_VERSION \
- MAKE_VERSION(FREETYPE_MAJOR,FREETYPE_MINOR,FREETYPE_PATCH)
-
#include <ft2build.h>
#include FT_OUTLINE_H
#include FT_SIZES_H
@@ -31,26 +26,20 @@
//------------------------------------------------------------------------
-#if ( FREETYPE_VERSION >= MAKE_VERSION(2,2,0) )
static int glyphPathMoveTo(const FT_Vector *pt, void *path);
static int glyphPathLineTo(const FT_Vector *pt, void *path);
-static int glyphPathConicTo(const FT_Vector *ctrl, const FT_Vector *pt, void *path);
+static int glyphPathConicTo(const FT_Vector *ctrl, const FT_Vector *pt,
+ void *path);
static int glyphPathCubicTo(const FT_Vector *ctrl1, const FT_Vector *ctrl2,
const FT_Vector *pt, void *path);
-#else
-static int glyphPathMoveTo(FT_Vector *pt, void *path);
-static int glyphPathLineTo(FT_Vector *pt, void *path);
-static int glyphPathConicTo(FT_Vector *ctrl, FT_Vector *pt, void *path);
-static int glyphPathCubicTo(FT_Vector *ctrl1, FT_Vector *ctrl2,
- FT_Vector *pt, void *path);
-#endif
//------------------------------------------------------------------------
// SplashFTFont
//------------------------------------------------------------------------
-SplashFTFont::SplashFTFont(SplashFTFontFile *fontFileA, SplashCoord *matA):
- SplashFont(fontFileA, matA, fontFileA->engine->aa)
+SplashFTFont::SplashFTFont(SplashFTFontFile *fontFileA, SplashCoord *matA,
+ SplashCoord *textMatA):
+ SplashFont(fontFileA, matA, textMatA, fontFileA->engine->aa)
{
FT_Face face;
double size, div;
@@ -65,6 +54,9 @@ SplashFTFont::SplashFTFont(SplashFTFontFile *fontFileA, SplashCoord *matA):
if (FT_Set_Pixel_Sizes(face, 0, (int)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;
div = face->bbox.xMax > 20000 ? 65536 : 1;
@@ -135,11 +127,19 @@ SplashFTFont::SplashFTFont(SplashFTFontFile *fontFileA, SplashCoord *matA):
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] / (size * textScale)).getRaw());
+ textMatrix.yx = (FT_Fixed)((textMat[1] / (size * textScale)).getRaw());
+ textMatrix.xy = (FT_Fixed)((textMat[2] / (size * textScale)).getRaw());
+ textMatrix.yy = (FT_Fixed)((textMat[3] / (size * textScale)).getRaw());
#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);
#endif
}
@@ -174,6 +174,10 @@ GBool SplashFTFont::makeGlyph(int c, int xFrac, int yFrac,
} else {
gid = (FT_UInt)c;
}
+ if (ff->trueType && gid == 0) {
+ // skip the TrueType notdef glyph
+ return gFalse;
+ }
// if we have the FT2 bytecode interpreter, autohinting won't be used
#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
@@ -220,15 +224,23 @@ GBool SplashFTFont::makeGlyph(int c, int xFrac, int yFrac,
struct SplashFTFontPath {
SplashPath *path;
+ SplashCoord textScale;
GBool needClose;
};
SplashPath *SplashFTFont::getGlyphPath(int c) {
static FT_Outline_Funcs outlineFuncs = {
+#if FREETYPE_MINOR <= 1
+ (int (*)(FT_Vector *, void *))&glyphPathMoveTo,
+ (int (*)(FT_Vector *, void *))&glyphPathLineTo,
+ (int (*)(FT_Vector *, FT_Vector *, void *))&glyphPathConicTo,
+ (int (*)(FT_Vector *, FT_Vector *, FT_Vector *, void *))&glyphPathCubicTo,
+#else
&glyphPathMoveTo,
&glyphPathLineTo,
&glyphPathConicTo,
&glyphPathCubicTo,
+#endif
0, 0
};
SplashFTFontFile *ff;
@@ -239,13 +251,17 @@ SplashPath *SplashFTFont::getGlyphPath(int c) {
ff = (SplashFTFontFile *)fontFile;
ff->face->size = sizeObj;
- FT_Set_Transform(ff->face, &matrix, NULL);
+ FT_Set_Transform(ff->face, &textMatrix, NULL);
slot = ff->face->glyph;
if (ff->codeToGID && c < ff->codeToGIDLen) {
gid = ff->codeToGID[c];
} else {
gid = (FT_UInt)c;
}
+ if (ff->trueType && gid == 0) {
+ // skip the TrueType notdef glyph
+ return NULL;
+ }
if (FT_Load_Glyph(ff->face, gid, FT_LOAD_NO_BITMAP)) {
return NULL;
}
@@ -253,6 +269,7 @@ SplashPath *SplashFTFont::getGlyphPath(int c) {
return NULL;
}
path.path = new SplashPath();
+ path.textScale = textScale;
path.needClose = gFalse;
FT_Outline_Decompose(&((FT_OutlineGlyph)glyph)->outline,
&outlineFuncs, &path);
@@ -263,51 +280,39 @@ SplashPath *SplashFTFont::getGlyphPath(int c) {
return path.path;
}
-#if ( FREETYPE_VERSION >= MAKE_VERSION(2,2,0) )
-static int glyphPathMoveTo(const FT_Vector *pt, void *path)
-#else
-static int glyphPathMoveTo(FT_Vector *pt, void *path)
-#endif
-{
+static int glyphPathMoveTo(const FT_Vector *pt, void *path) {
SplashFTFontPath *p = (SplashFTFontPath *)path;
if (p->needClose) {
p->path->close();
p->needClose = gFalse;
}
- p->path->moveTo(pt->x / 64.0, -pt->y / 64.0);
+ p->path->moveTo((SplashCoord)pt->x * p->textScale / 64.0,
+ (SplashCoord)pt->y * p->textScale / 64.0);
return 0;
}
-#if ( FREETYPE_VERSION >= MAKE_VERSION(2,2,0) )
-static int glyphPathLineTo(const FT_Vector *pt, void *path)
-#else
-static int glyphPathLineTo(FT_Vector *pt, void *path)
-#endif
-{
+static int glyphPathLineTo(const FT_Vector *pt, void *path) {
SplashFTFontPath *p = (SplashFTFontPath *)path;
- p->path->lineTo(pt->x / 64.0, -pt->y / 64.0);
+ p->path->lineTo((SplashCoord)pt->x * p->textScale / 64.0,
+ (SplashCoord)pt->y * p->textScale / 64.0);
p->needClose = gTrue;
return 0;
}
-#if ( FREETYPE_VERSION >= MAKE_VERSION(2,2,0) )
-static int glyphPathConicTo(const FT_Vector *ctrl, const FT_Vector *pt, void *path)
-#else
-static int glyphPathConicTo(FT_Vector *ctrl, FT_Vector *pt, void *path)
-#endif
-{
+static int glyphPathConicTo(const FT_Vector *ctrl, const FT_Vector *pt,
+ void *path) {
SplashFTFontPath *p = (SplashFTFontPath *)path;
SplashCoord x0, y0, x1, y1, x2, y2, x3, y3, xc, yc;
if (!p->path->getCurPt(&x0, &y0)) {
return 0;
}
- xc = ctrl->x / 64.0;
- yc = -ctrl->y / 64.0;
- x3 = pt->x / 64.0;
- y3 = -pt->y / 64.0;
+ xc = (SplashCoord)ctrl->x * p->textScale / 64.0;
+ yc = (SplashCoord)ctrl->y * p->textScale / 64.0;
+ x3 = (SplashCoord)pt->x * p->textScale / 64.0;
+ y3 = (SplashCoord)pt->y * p->textScale / 64.0;
// A second-order Bezier curve is defined by two endpoints, p0 and
// p3, and one control point, pc:
@@ -335,17 +340,16 @@ static int glyphPathConicTo(FT_Vector *ctrl, FT_Vector *pt, void *path)
return 0;
}
-#if ( FREETYPE_VERSION >= MAKE_VERSION(2,2,0) )
-static int glyphPathCubicTo(const FT_Vector *ctrl1, const FT_Vector *ctrl2, const FT_Vector *pt, void *path)
-#else
-static int glyphPathCubicTo(FT_Vector *ctrl1, FT_Vector *ctrl2, FT_Vector *pt, void *path)
-#endif
-{
+static int glyphPathCubicTo(const FT_Vector *ctrl1, const FT_Vector *ctrl2,
+ const FT_Vector *pt, void *path) {
SplashFTFontPath *p = (SplashFTFontPath *)path;
- p->path->curveTo(ctrl1->x / 64.0, -ctrl1->y / 64.0,
- ctrl2->x / 64.0, -ctrl2->y / 64.0,
- pt->x / 64.0, -pt->y / 64.0);
+ p->path->curveTo((SplashCoord)ctrl1->x * p->textScale / 64.0,
+ (SplashCoord)ctrl1->y * p->textScale / 64.0,
+ (SplashCoord)ctrl2->x * p->textScale / 64.0,
+ (SplashCoord)ctrl2->y * p->textScale / 64.0,
+ (SplashCoord)pt->x * p->textScale / 64.0,
+ (SplashCoord)pt->y * p->textScale / 64.0);
p->needClose = gTrue;
return 0;
}
diff --git a/splash/SplashFTFont.h b/splash/SplashFTFont.h
index ae5b5561..f351b2ff 100644
--- a/splash/SplashFTFont.h
+++ b/splash/SplashFTFont.h
@@ -26,7 +26,8 @@ class SplashFTFontFile;
class SplashFTFont: public SplashFont {
public:
- SplashFTFont(SplashFTFontFile *fontFileA, SplashCoord *matA);
+ SplashFTFont(SplashFTFontFile *fontFileA, SplashCoord *matA,
+ SplashCoord *textMatA);
virtual ~SplashFTFont();
@@ -46,6 +47,8 @@ private:
FT_Size sizeObj;
FT_Matrix matrix;
+ FT_Matrix textMatrix;
+ SplashCoord textScale;
};
#endif // HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H
diff --git a/splash/SplashFTFontEngine.cc b/splash/SplashFTFontEngine.cc
index b4121bf2..066d48db 100644
--- a/splash/SplashFTFontEngine.cc
+++ b/splash/SplashFTFontEngine.cc
@@ -75,6 +75,12 @@ SplashFontFile *SplashFTFontEngine::loadType1CFont(SplashFontFileID *idA,
return SplashFTFontFile::loadType1Font(this, idA, src, enc);
}
+SplashFontFile *SplashFTFontEngine::loadOpenTypeT1CFont(SplashFontFileID *idA,
+ SplashFontSrc *src,
+ char **enc) {
+ return SplashFTFontFile::loadType1Font(this, idA, src, enc);
+}
+
SplashFontFile *SplashFTFontEngine::loadCIDFont(SplashFontFileID *idA,
SplashFontSrc *src) {
FoFiType1C *ff;
@@ -90,15 +96,15 @@ SplashFontFile *SplashFTFontEngine::loadCIDFont(SplashFontFileID *idA,
if (src->isFile) {
ff = FoFiType1C::load(src->fileName->getCString());
} else {
- ff = new FoFiType1C(src->buf, src->bufLen, gFalse);
+ ff = FoFiType1C::make(src->buf, src->bufLen);
}
if (ff) {
- cidToGIDMap = ff->getCIDToGIDMap(&nCIDs);
- delete ff;
- } else {
- cidToGIDMap = NULL;
- nCIDs = 0;
- }
+ cidToGIDMap = ff->getCIDToGIDMap(&nCIDs);
+ delete ff;
+ } else {
+ cidToGIDMap = NULL;
+ nCIDs = 0;
+ }
}
ret = SplashFTFontFile::loadCIDFont(this, idA, src, cidToGIDMap, nCIDs);
if (!ret) {
@@ -107,6 +113,38 @@ SplashFontFile *SplashFTFontEngine::loadCIDFont(SplashFontFileID *idA,
return ret;
}
+SplashFontFile *SplashFTFontEngine::loadOpenTypeCFFFont(SplashFontFileID *idA,
+ SplashFontSrc *src) {
+ FoFiTrueType *ff;
+ GBool isCID;
+ Gushort *cidToGIDMap;
+ int nCIDs;
+ SplashFontFile *ret;
+
+ cidToGIDMap = NULL;
+ nCIDs = 0;
+ isCID = gFalse;
+ 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;
+ }
+ }
+ ret = SplashFTFontFile::loadCIDFont(this, idA, src,
+ cidToGIDMap, nCIDs);
+ if (!ret) {
+ gfree(cidToGIDMap);
+ }
+ return ret;
+}
+
SplashFontFile *SplashFTFontEngine::loadTrueTypeFont(SplashFontFileID *idA,
SplashFontSrc *src,
Gushort *codeToGID,
@@ -118,7 +156,7 @@ SplashFontFile *SplashFTFontEngine::loadTrueTypeFont(SplashFontFileID *idA,
FILE *tmpFile;
SplashFontFile *ret;
- if (!(ff = FoFiTrueType::load(fileName, faceIndex))) {
+ if (!(ff = FoFiTrueType::load(fileName))) {
return NULL;
}
tmpFileName = NULL;
diff --git a/splash/SplashFTFontEngine.h b/splash/SplashFTFontEngine.h
index e6600f58..a0c0b7c6 100644
--- a/splash/SplashFTFontEngine.h
+++ b/splash/SplashFTFontEngine.h
@@ -33,12 +33,13 @@ public:
~SplashFTFontEngine();
// Load fonts.
- SplashFontFile *loadType1Font(SplashFontFileID *idA, SplashFontSrc *src, char **enc);
- SplashFontFile *loadType1CFont(SplashFontFileID *idA, SplashFontSrc *src, char **enc);
+ 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 *loadCIDFont(SplashFontFileID *idA, SplashFontSrc *src);
+ SplashFontFile *loadOpenTypeCFFFont(SplashFontFileID *idA, SplashFontSrc *src);
SplashFontFile *loadTrueTypeFont(SplashFontFileID *idA, SplashFontSrc *src,
- Gushort *codeToGID, int codeToGIDLen,
- int faceIndex=0);
+ Gushort *codeToGID, int codeToGIDLen, int faceIndex = 0);
private:
diff --git a/splash/SplashFTFontFile.cc b/splash/SplashFTFontFile.cc
index 76927660..c6d06593 100644
--- a/splash/SplashFTFontFile.cc
+++ b/splash/SplashFTFontFile.cc
@@ -47,7 +47,7 @@ SplashFontFile *SplashFTFontFile::loadType1Font(SplashFTFontEngine *engineA,
}
return new SplashFTFontFile(engineA, idA, src,
- faceA, codeToGIDA, 256);
+ faceA, codeToGIDA, 256, gFalse);
}
SplashFontFile *SplashFTFontFile::loadCIDFont(SplashFTFontEngine *engineA,
@@ -66,7 +66,7 @@ SplashFontFile *SplashFTFontFile::loadCIDFont(SplashFTFontEngine *engineA,
}
return new SplashFTFontFile(engineA, idA, src,
- faceA, codeToGIDA, codeToGIDLenA);
+ faceA, codeToGIDA, codeToGIDLenA, gFalse);
}
SplashFontFile *SplashFTFontFile::loadTrueTypeFont(SplashFTFontEngine *engineA,
@@ -86,20 +86,22 @@ SplashFontFile *SplashFTFontFile::loadTrueTypeFont(SplashFTFontEngine *engineA,
}
return new SplashFTFontFile(engineA, idA, src,
- faceA, codeToGIDA, codeToGIDLenA);
+ faceA, codeToGIDA, codeToGIDLenA, gTrue);
}
SplashFTFontFile::SplashFTFontFile(SplashFTFontEngine *engineA,
SplashFontFileID *idA,
- SplashFontSrc *srcA,
+ SplashFontSrc *src,
FT_Face faceA,
- Gushort *codeToGIDA, int codeToGIDLenA):
- SplashFontFile(idA, srcA)
+ Gushort *codeToGIDA, int codeToGIDLenA,
+ GBool trueTypeA):
+ SplashFontFile(idA, src)
{
engine = engineA;
face = faceA;
codeToGID = codeToGIDA;
codeToGIDLen = codeToGIDLenA;
+ trueType = trueTypeA;
}
SplashFTFontFile::~SplashFTFontFile() {
@@ -111,10 +113,11 @@ SplashFTFontFile::~SplashFTFontFile() {
}
}
-SplashFont *SplashFTFontFile::makeFont(SplashCoord *mat) {
+SplashFont *SplashFTFontFile::makeFont(SplashCoord *mat,
+ SplashCoord *textMat) {
SplashFont *font;
- font = new SplashFTFont(this, mat);
+ font = new SplashFTFont(this, mat, textMat);
font->initCache();
return font;
}
diff --git a/splash/SplashFTFontFile.h b/splash/SplashFTFontFile.h
index b1d0f41b..19ff2dee 100644
--- a/splash/SplashFTFontFile.h
+++ b/splash/SplashFTFontFile.h
@@ -45,20 +45,23 @@ public:
// Create a new SplashFTFont, i.e., a scaled instance of this font
// file.
- virtual SplashFont *makeFont(SplashCoord *mat);
+ virtual SplashFont *makeFont(SplashCoord *mat,
+ SplashCoord *textMat);
private:
SplashFTFontFile(SplashFTFontEngine *engineA,
SplashFontFileID *idA,
- SplashFontSrc *srcA,
+ SplashFontSrc *src,
FT_Face faceA,
- Gushort *codeToGIDA, int codeToGIDLenA);
+ Gushort *codeToGIDA, int codeToGIDLenA,
+ GBool trueTypeA);
SplashFTFontEngine *engine;
FT_Face face;
Gushort *codeToGID;
int codeToGIDLen;
+ GBool trueType;
friend class SplashFTFont;
};
diff --git a/splash/SplashFont.cc b/splash/SplashFont.cc
index 570a9c16..bea6fc94 100644
--- a/splash/SplashFont.cc
+++ b/splash/SplashFont.cc
@@ -31,13 +31,17 @@ struct SplashFontCacheTag {
//------------------------------------------------------------------------
SplashFont::SplashFont(SplashFontFile *fontFileA, SplashCoord *matA,
- GBool aaA) {
+ SplashCoord *textMatA, GBool aaA) {
fontFile = fontFileA;
fontFile->incRefCnt();
mat[0] = matA[0];
mat[1] = matA[1];
mat[2] = matA[2];
mat[3] = matA[3];
+ textMat[0] = textMatA[0];
+ textMat[1] = textMatA[1];
+ textMat[2] = textMatA[2];
+ textMat[3] = textMatA[3];
aa = aaA;
cache = NULL;
diff --git a/splash/SplashFont.h b/splash/SplashFont.h
index 59bc14e4..d3b03538 100644
--- a/splash/SplashFont.h
+++ b/splash/SplashFont.h
@@ -35,7 +35,8 @@ class SplashPath;
class SplashFont {
public:
- SplashFont(SplashFontFile *fontFileA, SplashCoord *matA, GBool aaA);
+ SplashFont(SplashFontFile *fontFileA, SplashCoord *matA,
+ SplashCoord *textMatA, GBool aaA);
// This must be called after the constructor, so that the subclass
// constructor has a chance to compute the bbox.
@@ -46,10 +47,13 @@ public:
SplashFontFile *getFontFile() { return fontFile; }
// Return true if <this> matches the specified font file and matrix.
- GBool matches(SplashFontFile *fontFileA, SplashCoord *matA) {
+ GBool matches(SplashFontFile *fontFileA, SplashCoord *matA,
+ SplashCoord *textMatA) {
return fontFileA == fontFile &&
matA[0] == mat[0] && matA[1] == mat[1] &&
- matA[2] == mat[2] && matA[3] == mat[3];
+ matA[2] == mat[2] && matA[3] == mat[3] &&
+ textMatA[0] == textMat[0] && textMatA[1] == textMat[1] &&
+ textMatA[2] == textMat[2] && textMatA[3] == textMat[3];
}
// Get a glyph - this does a cache lookup first, and if not found,
@@ -81,6 +85,9 @@ protected:
SplashFontFile *fontFile;
SplashCoord mat[4]; // font transform matrix
+ // (text space -> device space)
+ SplashCoord textMat[4]; // text transform matrix
+ // (text space -> user space)
GBool aa; // anti-aliasing
int xMin, yMin, xMax, yMax; // glyph bounding box
Guchar *cache; // glyph bitmap cache
diff --git a/splash/SplashFontEngine.cc b/splash/SplashFontEngine.cc
index 01b1b6e9..9301b664 100644
--- a/splash/SplashFontEngine.cc
+++ b/splash/SplashFontEngine.cc
@@ -21,6 +21,7 @@
#endif
#include "goo/gmem.h"
#include "goo/GooString.h"
+#include "SplashMath.h"
#include "SplashT1FontEngine.h"
#include "SplashFTFontEngine.h"
#include "SplashFontFile.h"
@@ -34,6 +35,12 @@ extern "C" int unlink(char *filename);
#endif
#endif
+#ifdef VMS
+#if (__VMS_VER < 70000000)
+extern "C" int unlink(char *filename);
+#endif
+#endif
+
//------------------------------------------------------------------------
// SplashFontEngine
//------------------------------------------------------------------------
@@ -141,7 +148,7 @@ SplashFontFile *SplashFontEngine::loadType1CFont(SplashFontFileID *idA,
fontFile = NULL;
#if HAVE_T1LIB_H
if (!fontFile && t1Engine) {
- fontFile = t1Engine->loadType1CFont(idA, src, enc);
+ fontFile = t1Engine->loadType1CFont(idA, sec, enc);
}
#endif
#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H
@@ -162,6 +169,28 @@ SplashFontFile *SplashFontEngine::loadType1CFont(SplashFontFileID *idA,
return fontFile;
}
+SplashFontFile *SplashFontEngine::loadOpenTypeT1CFont(SplashFontFileID *idA,
+ SplashFontSrc *src,
+ char **enc) {
+ SplashFontFile *fontFile;
+
+ fontFile = NULL;
+#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H
+ if (!fontFile && ftEngine) {
+ fontFile = ftEngine->loadOpenTypeT1CFont(idA, src, enc);
+ }
+#endif
+
+ // delete the (temporary) font file -- with Unix hard link
+ // semantics, this will remove the last link; otherwise it will
+ // return an error, leaving the file to be deleted later (if
+ // loadXYZFont failed, the file will always be deleted)
+ if (src->isFile)
+ src->unref();
+
+ return fontFile;
+}
+
SplashFontFile *SplashFontEngine::loadCIDFont(SplashFontFileID *idA,
SplashFontSrc *src) {
SplashFontFile *fontFile;
@@ -185,6 +214,27 @@ SplashFontFile *SplashFontEngine::loadCIDFont(SplashFontFileID *idA,
return fontFile;
}
+SplashFontFile *SplashFontEngine::loadOpenTypeCFFFont(SplashFontFileID *idA,
+ SplashFontSrc *src) {
+ SplashFontFile *fontFile;
+
+ fontFile = NULL;
+#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H
+ if (!fontFile && ftEngine) {
+ fontFile = ftEngine->loadOpenTypeCFFFont(idA, src);
+ }
+#endif
+
+ // delete the (temporary) font file -- with Unix hard link
+ // semantics, this will remove the last link; otherwise it will
+ // return an error, leaving the file to be deleted later (if
+ // loadXYZFont failed, the file will always be deleted)
+ if (src->isFile)
+ src->unref();
+
+ return fontFile;
+}
+
SplashFontFile *SplashFontEngine::loadTrueTypeFont(SplashFontFileID *idA,
SplashFontSrc *src,
Gushort *codeToGID,
@@ -217,17 +267,29 @@ SplashFontFile *SplashFontEngine::loadTrueTypeFont(SplashFontFileID *idA,
}
SplashFont *SplashFontEngine::getFont(SplashFontFile *fontFile,
- SplashCoord *mat) {
+ SplashCoord *textMat,
+ SplashCoord *ctm) {
+ SplashCoord mat[4];
SplashFont *font;
int i, j;
+ mat[0] = textMat[0] * ctm[0] + textMat[1] * ctm[2];
+ 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) {
+ // avoid a singular (or close-to-singular) matrix
+ mat[0] = 0.01; mat[1] = 0;
+ mat[2] = 0; mat[3] = 0.01;
+ }
+
font = fontCache[0];
- if (font && font->matches(fontFile, mat)) {
+ if (font && font->matches(fontFile, mat, textMat)) {
return font;
}
for (i = 1; i < splashFontCacheSize; ++i) {
font = fontCache[i];
- if (font && font->matches(fontFile, mat)) {
+ if (font && font->matches(fontFile, mat, textMat)) {
for (j = i; j > 0; --j) {
fontCache[j] = fontCache[j-1];
}
@@ -235,7 +297,7 @@ SplashFont *SplashFontEngine::getFont(SplashFontFile *fontFile,
return font;
}
}
- font = fontFile->makeFont(mat);
+ font = fontFile->makeFont(mat, textMat);
if (fontCache[splashFontCacheSize - 1]) {
delete fontCache[splashFontCacheSize - 1];
}
diff --git a/splash/SplashFontEngine.h b/splash/SplashFontEngine.h
index 23c49acd..b87d667b 100644
--- a/splash/SplashFontEngine.h
+++ b/splash/SplashFontEngine.h
@@ -16,6 +16,7 @@
class SplashT1FontEngine;
class SplashFTFontEngine;
class SplashDTFontEngine;
+class SplashDT4FontEngine;
class SplashFontFile;
class SplashFontFileID;
class SplashFont;
@@ -51,20 +52,22 @@ public:
// 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 *loadCIDFont(SplashFontFileID *idA, SplashFontSrc *src);
+ SplashFontFile *loadOpenTypeCFFFont(SplashFontFileID *idA, SplashFontSrc *src);
SplashFontFile *loadTrueTypeFont(SplashFontFileID *idA, SplashFontSrc *src,
- Gushort *codeToGID, int codeToGIDLen,
- int faceIndex=0);
+ Gushort *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
- // matrix:
+ // matrix, mat = textMat * ctm:
// [ mat[0] mat[1] ]
// [ mat[2] mat[3] ]
// specifies the font transform in PostScript style:
// [x' y'] = [x y] * mat
// Note that the Splash y axis points downward.
- SplashFont *getFont(SplashFontFile *fontFile, SplashCoord *mat);
+ SplashFont *getFont(SplashFontFile *fontFile,
+ SplashCoord *textMat, SplashCoord *ctm);
private:
diff --git a/splash/SplashFontFile.cc b/splash/SplashFontFile.cc
index b92dd1b2..9dabd1fd 100644
--- a/splash/SplashFontFile.cc
+++ b/splash/SplashFontFile.cc
@@ -104,4 +104,3 @@ void SplashFontSrc::setBuf(char *bufA, int bufLenA, GBool del)
bufLen = bufLenA;
deleteSrc = del;
}
-
diff --git a/splash/SplashFontFile.h b/splash/SplashFontFile.h
index e434b9b2..ad2bc89b 100644
--- a/splash/SplashFontFile.h
+++ b/splash/SplashFontFile.h
@@ -49,7 +49,7 @@ public:
// Create a new SplashFont, i.e., a scaled instance of this font
// file.
- virtual SplashFont *makeFont(SplashCoord *mat) = 0;
+ virtual SplashFont *makeFont(SplashCoord *mat, SplashCoord *textMat) = 0;
// Get the font file ID.
SplashFontFileID *getID() { return id; }
diff --git a/splash/SplashMath.h b/splash/SplashMath.h
index 1d4e2264..17d05cda 100644
--- a/splash/SplashMath.h
+++ b/splash/SplashMath.h
@@ -7,7 +7,7 @@
#ifndef SPLASHMATH_H
#define SPLASHMATH_H
-#if USE_FIXEDPONT
+#if USE_FIXEDPOINT
#include "FixedPoint.h"
#else
#include <math.h>
@@ -68,7 +68,18 @@ static inline SplashCoord splashDist(SplashCoord x0, SplashCoord y0,
dx = x1 - x0;
dy = y1 - y0;
#if USE_FIXEDPOINT
- return FixedPoint::sqrt(dx * dx + dy * dy);
+ // 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;
+ dxa = splashAbs(dx);
+ dya = splashAbs(dy);
+ if (dxa == 0 && dya == 0) {
+ return 0;
+ } else if (dxa > dya) {
+ return dxa * FixedPoint::sqrt(dya / dxa + 1);
+ } else {
+ return dya * FixedPoint::sqrt(dxa / dya + 1);
+ }
#else
return sqrt(dx * dx + dy * dy);
#endif
diff --git a/splash/SplashPath.cc b/splash/SplashPath.cc
index 1f0f80dd..261f7788 100644
--- a/splash/SplashPath.cc
+++ b/splash/SplashPath.cc
@@ -35,6 +35,8 @@ SplashPath::SplashPath() {
flags = NULL;
length = size = 0;
curSubpath = 0;
+ hints = NULL;
+ hintsLength = hintsSize = 0;
}
SplashPath::SplashPath(SplashPath *path) {
@@ -45,11 +47,19 @@ SplashPath::SplashPath(SplashPath *path) {
memcpy(pts, path->pts, length * sizeof(SplashPathPoint));
memcpy(flags, path->flags, length * sizeof(Guchar));
curSubpath = path->curSubpath;
+ if (path->hints) {
+ hintsLength = hintsSize = path->hintsLength;
+ hints = (SplashPathHint *)gmallocn(hintsSize, sizeof(SplashPathHint));
+ memcpy(hints, path->hints, hintsLength * sizeof(SplashPathHint));
+ } else {
+ hints = NULL;
+ }
}
SplashPath::~SplashPath() {
gfree(pts);
gfree(flags);
+ gfree(hints);
}
// Add space for <nPts> more points.
@@ -126,24 +136,6 @@ SplashError SplashPath::curveTo(SplashCoord x1, SplashCoord y1,
return splashOk;
}
-SplashError SplashPath::arcCWTo(SplashCoord x1, SplashCoord y1,
- SplashCoord xc, SplashCoord yc) {
- if (noCurrentPoint()) {
- return splashErrNoCurPt;
- }
- flags[length-1] &= ~splashPathLast;
- grow(2);
- pts[length].x = xc;
- pts[length].y = yc;
- flags[length] = splashPathArcCW;
- ++length;
- pts[length].x = x1;
- pts[length].y = y1;
- flags[length] = splashPathLast;
- ++length;
- return splashOk;
-}
-
SplashError SplashPath::close() {
if (noCurrentPoint()) {
return splashErrNoCurPt;
@@ -159,6 +151,20 @@ SplashError SplashPath::close() {
return splashOk;
}
+void SplashPath::addStrokeAdjustHint(int ctrl0, int ctrl1,
+ int firstPt, int lastPt) {
+ if (hintsLength == hintsSize) {
+ hintsSize = hintsLength ? 2 * hintsLength : 8;
+ hints = (SplashPathHint *)greallocn(hints, hintsSize,
+ sizeof(SplashPathHint));
+ }
+ hints[hintsLength].ctrl0 = ctrl0;
+ hints[hintsLength].ctrl1 = ctrl1;
+ hints[hintsLength].firstPt = firstPt;
+ hints[hintsLength].lastPt = lastPt;
+ ++hintsLength;
+}
+
void SplashPath::offset(SplashCoord dx, SplashCoord dy) {
int i;
diff --git a/splash/SplashPath.h b/splash/SplashPath.h
index 1b7362a5..ea58af0c 100644
--- a/splash/SplashPath.h
+++ b/splash/SplashPath.h
@@ -26,20 +26,26 @@ struct SplashPathPoint {
//------------------------------------------------------------------------
// first point on each subpath sets this flag
-#define splashPathFirst 0x01
+#define splashPathFirst 0x01
// last point on each subpath sets this flag
-#define splashPathLast 0x02
+#define splashPathLast 0x02
// if the subpath is closed, its first and last points must be
// identical, and must set this flag
-#define splashPathClosed 0x04
+#define splashPathClosed 0x04
// curve control points set this flag
-#define splashPathCurve 0x08
+#define splashPathCurve 0x08
-// clockwise arc center points set this flag
-#define splashPathArcCW 0x10
+//------------------------------------------------------------------------
+// SplashPathHint
+//------------------------------------------------------------------------
+
+struct SplashPathHint {
+ int ctrl0, ctrl1;
+ int firstPt, lastPt;
+};
//------------------------------------------------------------------------
// SplashPath
@@ -71,14 +77,14 @@ public:
SplashCoord x2, SplashCoord y2,
SplashCoord x3, SplashCoord y3);
- // Add a clockwise circular arc with center (xc, yc) and endpoint
- // (x1, y1).
- SplashError arcCWTo(SplashCoord x1, SplashCoord y1,
- SplashCoord xc, SplashCoord yc);
-
// Close the last subpath, adding a line segment if necessary.
SplashError close();
+ // Add a stroke adjustment hint. The controlling segments are
+ // <ctrl0> and <ctrl1> (where segments are identified by their first
+ // point), and the points to be adjusted are <firstPt> .. <lastPt>.
+ void addStrokeAdjustHint(int ctrl0, int ctrl1, int firstPt, int lastPt);
+
// Add (<dx>, <dy>) to every point on this path.
void offset(SplashCoord dx, SplashCoord dy);
@@ -103,6 +109,9 @@ private:
int length, size; // length/size of the pts and flags arrays
int curSubpath; // index of first point in last subpath
+ SplashPathHint *hints; // list of hints
+ int hintsLength, hintsSize;
+
friend class SplashXPath;
friend class Splash;
// this is a temporary hack, until we read FreeType paths directly
diff --git a/splash/SplashPattern.cc b/splash/SplashPattern.cc
index 38f39943..ce490785 100644
--- a/splash/SplashPattern.cc
+++ b/splash/SplashPattern.cc
@@ -38,31 +38,3 @@ SplashSolidColor::~SplashSolidColor() {
void SplashSolidColor::getColor(int x, int y, SplashColorPtr c) {
splashColorCopy(c, color);
}
-
-//------------------------------------------------------------------------
-// SplashHalftone
-//------------------------------------------------------------------------
-
-SplashHalftone::SplashHalftone(SplashColorPtr color0A, SplashColorPtr color1A,
- SplashScreen *screenA, SplashCoord valueA) {
- splashColorCopy(color0, color0A);
- splashColorCopy(color1, color1A);
- screen = screenA;
- value = valueA;
-}
-
-SplashPattern *SplashHalftone::copy() {
- return new SplashHalftone(color0, color1, screen->copy(), value);
-}
-
-SplashHalftone::~SplashHalftone() {
- delete screen;
-}
-
-void SplashHalftone::getColor(int x, int y, SplashColorPtr c) {
- splashColorCopy(c, screen->test(x, y, value) ? color1 : color0);
-}
-
-GBool SplashHalftone::isStatic() {
- return screen->isStatic(value);
-}
diff --git a/splash/SplashPattern.h b/splash/SplashPattern.h
index 2e50c43b..4e3d9abb 100644
--- a/splash/SplashPattern.h
+++ b/splash/SplashPattern.h
@@ -60,29 +60,4 @@ private:
SplashColor color;
};
-//------------------------------------------------------------------------
-// SplashHalftone
-//------------------------------------------------------------------------
-
-class SplashHalftone: public SplashPattern {
-public:
-
- SplashHalftone(SplashColorPtr color0A, SplashColorPtr color1A,
- SplashScreen *screenA, SplashCoord valueA);
-
- virtual SplashPattern *copy();
-
- virtual ~SplashHalftone();
-
- virtual void getColor(int x, int y, SplashColorPtr c);
-
- virtual GBool isStatic();
-
-private:
-
- SplashColor color0, color1;
- SplashScreen *screen;
- SplashCoord value;
-};
-
#endif
diff --git a/splash/SplashScreen.cc b/splash/SplashScreen.cc
index 221296fd..4fa84883 100644
--- a/splash/SplashScreen.cc
+++ b/splash/SplashScreen.cc
@@ -10,34 +10,139 @@
#pragma implementation
#endif
+#include <stdlib.h>
#include <string.h>
#include "goo/gmem.h"
#include "SplashMath.h"
#include "SplashScreen.h"
+static SplashScreenParams defaultParams = {
+ splashScreenDispersed, // type
+ 2, // size
+ 2, // dotRadius
+ 1.0, // gamma
+ 0.0, // blackThreshold
+ 1.0 // whiteThreshold
+};
+
+//------------------------------------------------------------------------
+
+struct SplashScreenPoint {
+ int x, y;
+ int dist;
+};
+
+static int cmpDistances(const void *p0, const void *p1) {
+ return ((SplashScreenPoint *)p0)->dist - ((SplashScreenPoint *)p1)->dist;
+}
+
//------------------------------------------------------------------------
// SplashScreen
//------------------------------------------------------------------------
-// This generates a 45 degree screen using a circular dot spot
-// function. DPI = resolution / ((size / 2) * sqrt(2)).
-// Gamma correction (gamma = 1 / 1.33) is also computed here.
-SplashScreen::SplashScreen(int sizeA) {
+// If <clustered> is true, this generates a 45 degree screen using a
+// circular dot spot function. DPI = resolution / ((size / 2) *
+// sqrt(2)). If <clustered> is false, this generates an optimal
+// threshold matrix using recursive tesselation. Gamma correction
+// (gamma = 1 / 1.33) is also computed here.
+SplashScreen::SplashScreen(SplashScreenParams *params) {
+ Guchar u, black, white;
+ int i;
+
+ if (!params) {
+ params = &defaultParams;
+ }
+
+ 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;
+ }
+ mat = (Guchar *)gmallocn(size * size, sizeof(Guchar));
+ buildSCDMatrix(params->dotRadius);
+ break;
+ }
+
+ // do gamma correction and compute minVal/maxVal
+ minVal = 255;
+ maxVal = 0;
+ black = splashRound((SplashCoord)255.0 * params->blackThreshold);
+ if (black < 1) {
+ black = 1;
+ }
+ int whiteAux = splashRound((SplashCoord)255.0 * params->whiteThreshold);
+ if (whiteAux > 255) {
+ white = 255;
+ } else {
+ white = whiteAux;
+ }
+ for (i = 0; i < size * size; ++i) {
+ u = splashRound((SplashCoord)255.0 *
+ splashPow((SplashCoord)mat[i] / 255.0, params->gamma));
+ if (u < black) {
+ u = black;
+ } else if (u >= white) {
+ u = white;
+ }
+ mat[i] = u;
+ if (u < minVal) {
+ minVal = u;
+ } else if (u > maxVal) {
+ maxVal = u;
+ }
+ }
+}
+
+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);
+ } else {
+ buildDispersedMatrix(i, j,
+ val, delta / 2, 4*offset);
+ buildDispersedMatrix((i + delta) % size, (j + delta) % size,
+ val + offset, delta / 2, 4*offset);
+ buildDispersedMatrix((i + delta) % size, j,
+ val + 2*offset, delta / 2, 4*offset);
+ buildDispersedMatrix((i + 2*delta) % size, (j + delta) % size,
+ val + 3*offset, delta / 2, 4*offset);
+ }
+}
+
+void SplashScreen::buildClusteredMatrix() {
SplashCoord *dist;
- SplashCoord u, v, d, val;
+ SplashCoord u, v, d;
+ Guchar val;
int size2, x, y, x1, y1, i;
- size2 = sizeA >> 1;
- if (size2 < 1) {
- size2 = 1;
- }
- size = size2 << 1;
+ size2 = size >> 1;
// initialize the threshold matrix
- mat = (SplashCoord *)gmallocn(size * size, sizeof(SplashCoord));
for (y = 0; y < size; ++y) {
for (x = 0; x < size; ++x) {
- mat[y * size + x] = -1;
+ mat[y * size + x] = 0;
}
}
@@ -72,27 +177,22 @@ SplashScreen::SplashScreen(int sizeA) {
minVal = 1;
maxVal = 0;
x1 = y1 = 0; // make gcc happy
- for (i = 1; i <= size * size2; ++i) {
- d = size * size2;
+ 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 &&
- dist[y * size2 + x] < d) {
+ if (mat[y * size + x] == 0 &&
+ dist[y * size2 + x] > d) {
x1 = x;
y1 = y;
d = dist[y1 * size2 + x1];
}
}
}
- u = (SplashCoord)1 - (SplashCoord)i / (SplashCoord)(size * size2 + 1);
- val = splashPow(u, 1.33);
- if (val < minVal) {
- minVal = val;
- }
- if (val > maxVal) {
- maxVal = val;
- }
+ // map values in [0, 2*size*size2-1] --> [1, 255]
+ val = 1 + (254 * (2*i)) / (2*size*size2 - 1);
mat[y1 * size + x1] = val;
+ val = 1 + (254 * (2*i+1)) / (2*size*size2 - 1);
if (y1 < size2) {
mat[(y1 + size2) * size + x1 + size2] = val;
} else {
@@ -103,13 +203,155 @@ SplashScreen::SplashScreen(int sizeA) {
gfree(dist);
}
-SplashScreen::SplashScreen(SplashScreen *screen) {
- int n;
+// Compute the distance between two points on a toroid.
+int SplashScreen::distance(int x0, int y0, int x1, int y1) {
+ int dx0, dx1, dx, dy0, dy1, dy;
+
+ dx0 = abs(x0 - x1);
+ dx1 = size - dx0;
+ dx = dx0 < dx1 ? dx0 : dx1;
+ dy0 = abs(y0 - y1);
+ dy1 = size - dy0;
+ dy = dy0 < dy1 ? dy0 : dy1;
+ return dx * dx + dy * dy;
+}
+
+// Algorithm taken from:
+// Victor Ostromoukhov and Roger D. Hersch, "Stochastic Clustered-Dot
+// Dithering" in Color Imaging: Device-Independent Color, Color
+// Hardcopy, and Graphic Arts IV, SPIE Vol. 3648, pp. 496-505, 1999.
+void SplashScreen::buildSCDMatrix(int r) {
+ SplashScreenPoint *dots, *pts;
+ int dotsLen, dotsSize;
+ char *tmpl;
+ char *grid;
+ int *region, *dist;
+ int x, y, xx, yy, x0, x1, y0, y1, i, j, d, iMin, dMin, n;
+
+ //~ this should probably happen somewhere else
+ srand(123);
+
+ // generate the random space-filling curve
+ pts = (SplashScreenPoint *)gmallocn(size * size, sizeof(SplashScreenPoint));
+ i = 0;
+ for (y = 0; y < size; ++y) {
+ for (x = 0; x < size; ++x) {
+ pts[i].x = x;
+ pts[i].y = y;
+ ++i;
+ }
+ }
+ for (i = 0; i < size * size; ++i) {
+ j = i + (int)((double)(size * size - i) *
+ (double)rand() / ((double)RAND_MAX + 1.0));
+ x = pts[i].x;
+ y = pts[i].y;
+ pts[i].x = pts[j].x;
+ pts[i].y = pts[j].y;
+ pts[j].x = x;
+ pts[j].y = y;
+ }
+
+ // construct the circle template
+ tmpl = (char *)gmallocn((r+1)*(r+1), sizeof(char));
+ for (y = 0; y <= r; ++y) {
+ for (x = 0; x <= r; ++x) {
+ tmpl[y*(r+1) + x] = (x * y <= r * r) ? 1 : 0;
+ }
+ }
+
+ // mark all grid cells as free
+ grid = (char *)gmallocn(size * size, sizeof(char));
+ for (y = 0; y < size; ++y) {
+ for (x = 0; x < size; ++x) {
+ grid[y*size + x] = 0;
+ }
+ }
+
+ // walk the space-filling curve, adding dots
+ dotsLen = 0;
+ dotsSize = 32;
+ dots = (SplashScreenPoint *)gmallocn(dotsSize, sizeof(SplashScreenPoint));
+ for (i = 0; i < size * size; ++i) {
+ x = pts[i].x;
+ y = pts[i].y;
+ if (!grid[y*size + x]) {
+ if (dotsLen == dotsSize) {
+ dotsSize *= 2;
+ dots = (SplashScreenPoint *)greallocn(dots, dotsSize,
+ sizeof(SplashScreenPoint));
+ }
+ dots[dotsLen++] = pts[i];
+ for (yy = 0; yy <= r; ++yy) {
+ y0 = (y + yy) % size;
+ y1 = (y - yy + size) % size;
+ for (xx = 0; xx <= r; ++xx) {
+ 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;
+ }
+ }
+ }
+ }
+ }
+
+ gfree(tmpl);
+ gfree(grid);
+ // assign each cell to a dot, compute distance to center of dot
+ region = (int *)gmallocn(size * size, sizeof(int));
+ dist = (int *)gmallocn(size * size, sizeof(int));
+ for (y = 0; y < size; ++y) {
+ for (x = 0; x < size; ++x) {
+ iMin = 0;
+ dMin = distance(dots[0].x, dots[0].y, x, y);
+ for (i = 1; i < dotsLen; ++i) {
+ d = distance(dots[i].x, dots[i].y, x, y);
+ if (d < dMin) {
+ iMin = i;
+ dMin = d;
+ }
+ }
+ region[y*size + x] = iMin;
+ dist[y*size + x] = dMin;
+ }
+ }
+
+ // compute threshold values
+ for (i = 0; i < dotsLen; ++i) {
+ n = 0;
+ for (y = 0; y < size; ++y) {
+ for (x = 0; x < size; ++x) {
+ if (region[y*size + x] == i) {
+ pts[n].x = x;
+ pts[n].y = y;
+ pts[n].dist = distance(dots[i].x, dots[i].y, x, y);
+ ++n;
+ }
+ }
+ }
+ qsort(pts, n, sizeof(SplashScreenPoint), &cmpDistances);
+ 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);
+ }
+ }
+
+ gfree(pts);
+ gfree(region);
+ gfree(dist);
+
+ gfree(dots);
+}
+
+SplashScreen::SplashScreen(SplashScreen *screen) {
size = screen->size;
- n = size * size * sizeof(SplashCoord);
- mat = (SplashCoord *)gmalloc(n);
- memcpy(mat, screen->mat, n);
+ mat = (Guchar *)gmallocn(size * size, sizeof(Guchar));
+ memcpy(mat, screen->mat, size * size * sizeof(Guchar));
minVal = screen->minVal;
maxVal = screen->maxVal;
}
@@ -118,7 +360,7 @@ SplashScreen::~SplashScreen() {
gfree(mat);
}
-int SplashScreen::test(int x, int y, SplashCoord value) {
+int SplashScreen::test(int x, int y, Guchar value) {
int xx, yy;
if (value < minVal) {
@@ -136,6 +378,6 @@ int SplashScreen::test(int x, int y, SplashCoord value) {
return value < mat[yy * size + xx] ? 0 : 1;
}
-GBool SplashScreen::isStatic(SplashCoord value) {
+GBool SplashScreen::isStatic(Guchar value) {
return value < minVal || value >= maxVal;
}
diff --git a/splash/SplashScreen.h b/splash/SplashScreen.h
index e0df8bbd..4174c80e 100644
--- a/splash/SplashScreen.h
+++ b/splash/SplashScreen.h
@@ -20,7 +20,7 @@
class SplashScreen {
public:
- SplashScreen(int sizeA);
+ SplashScreen(SplashScreenParams *params);
SplashScreen(SplashScreen *screen);
~SplashScreen();
@@ -28,20 +28,26 @@ public:
// Return the computed pixel value (0=black, 1=white) for the gray
// level <value> at (<x>, <y>).
- int test(int x, int y, SplashCoord value);
+ int test(int x, int y, Guchar value);
// 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(SplashCoord value);
+ GBool isStatic(Guchar value);
private:
- SplashCoord *mat; // threshold matrix
+ void buildDispersedMatrix(int i, int j, int val,
+ int delta, int offset);
+ void buildClusteredMatrix();
+ int distance(int x0, int y0, int x1, int y1);
+ void buildSCDMatrix(int r);
+
+ Guchar *mat; // threshold matrix
int size; // size of the threshold matrix
- SplashCoord minVal; // any pixel value below minVal generates
+ Guchar minVal; // any pixel value below minVal generates
// solid black
- SplashCoord maxVal; // any pixel value above maxVal generates
+ Guchar maxVal; // any pixel value above maxVal generates
// solid white
};
diff --git a/splash/SplashState.cc b/splash/SplashState.cc
index dd011c01..70a79acc 100644
--- a/splash/SplashState.cc
+++ b/splash/SplashState.cc
@@ -15,6 +15,7 @@
#include "SplashPattern.h"
#include "SplashScreen.h"
#include "SplashClip.h"
+#include "SplashBitmap.h"
#include "SplashState.h"
//------------------------------------------------------------------------
@@ -23,16 +24,20 @@
// number of components in each color mode
int splashColorModeNComps[] = {
- 1, 1, 2, 3, 3, 4, 4
+ 1, 1, 3, 3, 4
};
-SplashState::SplashState(int width, int height) {
+SplashState::SplashState(int width, int height, GBool vectorAntialias,
+ SplashScreenParams *screenParams) {
SplashColor color;
+ matrix[0] = 1; matrix[1] = 0;
+ matrix[2] = 0; matrix[3] = 1;
+ matrix[4] = 0; matrix[5] = 0;
memset(&color, 0, sizeof(SplashColor));
strokePattern = new SplashSolidColor(color);
fillPattern = new SplashSolidColor(color);
- screen = new SplashScreen(10);
+ screen = new SplashScreen(screenParams);
blendFunc = NULL;
strokeAlpha = 1;
fillAlpha = 1;
@@ -44,11 +49,46 @@ SplashState::SplashState(int width, int height) {
lineDash = NULL;
lineDashLength = 0;
lineDashPhase = 0;
- clip = new SplashClip(0, 0, width - 1, height - 1);
+ strokeAdjust = gFalse;
+ clip = new SplashClip(0, 0, width - 0.001, height - 0.001, vectorAntialias);
+ softMask = NULL;
+ deleteSoftMask = gFalse;
+ inNonIsolatedGroup = gFalse;
+ next = NULL;
+}
+
+SplashState::SplashState(int width, int height, GBool vectorAntialias,
+ SplashScreen *screenA) {
+ SplashColor color;
+
+ matrix[0] = 1; matrix[1] = 0;
+ matrix[2] = 0; matrix[3] = 1;
+ matrix[4] = 0; matrix[5] = 0;
+ memset(&color, 0, sizeof(SplashColor));
+ strokePattern = new SplashSolidColor(color);
+ fillPattern = new SplashSolidColor(color);
+ screen = screenA->copy();
+ blendFunc = NULL;
+ strokeAlpha = 1;
+ fillAlpha = 1;
+ lineWidth = 0;
+ lineCap = splashLineCapButt;
+ lineJoin = splashLineJoinMiter;
+ miterLimit = 10;
+ flatness = 1;
+ lineDash = NULL;
+ lineDashLength = 0;
+ lineDashPhase = 0;
+ strokeAdjust = gFalse;
+ clip = new SplashClip(0, 0, width - 0.001, height - 0.001, vectorAntialias);
+ softMask = NULL;
+ deleteSoftMask = gFalse;
+ inNonIsolatedGroup = gFalse;
next = NULL;
}
SplashState::SplashState(SplashState *state) {
+ memcpy(matrix, state->matrix, 6 * sizeof(SplashCoord));
strokePattern = state->strokePattern->copy();
fillPattern = state->fillPattern->copy();
screen = state->screen->copy();
@@ -69,7 +109,11 @@ SplashState::SplashState(SplashState *state) {
lineDashLength = 0;
}
lineDashPhase = state->lineDashPhase;
+ strokeAdjust = state->strokeAdjust;
clip = state->clip->copy();
+ softMask = state->softMask;
+ deleteSoftMask = gFalse;
+ inNonIsolatedGroup = state->inNonIsolatedGroup;
next = NULL;
}
@@ -79,6 +123,9 @@ SplashState::~SplashState() {
delete screen;
gfree(lineDash);
delete clip;
+ if (deleteSoftMask && softMask) {
+ delete softMask;
+ }
}
void SplashState::setStrokePattern(SplashPattern *strokePatternA) {
@@ -108,3 +155,11 @@ void SplashState::setLineDash(SplashCoord *lineDashA, int lineDashLengthA,
}
lineDashPhase = lineDashPhaseA;
}
+
+void SplashState::setSoftMask(SplashBitmap *softMaskA) {
+ if (deleteSoftMask) {
+ delete softMask;
+ }
+ softMask = softMaskA;
+ deleteSoftMask = gTrue;
+}
diff --git a/splash/SplashState.h b/splash/SplashState.h
index d00de08a..d0e05df3 100644
--- a/splash/SplashState.h
+++ b/splash/SplashState.h
@@ -16,6 +16,7 @@
class SplashPattern;
class SplashScreen;
class SplashClip;
+class SplashBitmap;
//------------------------------------------------------------------------
// line cap values
@@ -41,7 +42,10 @@ class SplashState {
public:
// Create a new state object, initialized with default settings.
- SplashState(int width, int height);
+ SplashState(int width, int height, GBool vectorAntialias,
+ SplashScreenParams *screenParams);
+ SplashState(int width, int height, GBool vectorAntialias,
+ SplashScreen *screenA);
// Copy a state object.
SplashState *copy() { return new SplashState(this); }
@@ -61,10 +65,14 @@ public:
void setLineDash(SplashCoord *lineDashA, int lineDashLengthA,
SplashCoord lineDashPhaseA);
+ // Set the soft mask bitmap.
+ void setSoftMask(SplashBitmap *softMaskA);
+
private:
SplashState(SplashState *state);
+ SplashCoord matrix[6];
SplashPattern *strokePattern;
SplashPattern *fillPattern;
SplashScreen *screen;
@@ -79,7 +87,11 @@ private:
SplashCoord *lineDash;
int lineDashLength;
SplashCoord lineDashPhase;
+ GBool strokeAdjust;
SplashClip *clip;
+ SplashBitmap *softMask;
+ GBool deleteSoftMask;
+ GBool inNonIsolatedGroup;
SplashState *next; // used by Splash class
diff --git a/splash/SplashT1Font.cc b/splash/SplashT1Font.cc
index 708cc261..b30c0fc7 100644
--- a/splash/SplashT1Font.cc
+++ b/splash/SplashT1Font.cc
@@ -63,8 +63,9 @@ static Guchar bitReverse[256] = {
// SplashT1Font
//------------------------------------------------------------------------
-SplashT1Font::SplashT1Font(SplashT1FontFile *fontFileA, SplashCoord *matA):
- SplashFont(fontFileA, matA, ((SplashT1FontFile *)fontFileA)->engine->aa)
+SplashT1Font::SplashT1Font(SplashT1FontFile *fontFileA, SplashCoord *matA,
+ SplashCoord *textMatA):
+ SplashFont(fontFileA, matA, textMatA, fontFileA->engine->aa)
{
T1_TMATRIX matrix;
BBox bbox;
@@ -72,6 +73,7 @@ SplashT1Font::SplashT1Font(SplashT1FontFile *fontFileA, SplashCoord *matA):
int x, y;
t1libID = T1_CopyFont(fontFileA->t1libID);
+ outlineID = -1;
// compute font size
size = (float)splashSqrt(mat[2]*mat[2] + mat[3]*mat[3]);
@@ -168,6 +170,9 @@ SplashT1Font::SplashT1Font(SplashT1FontFile *fontFileA, SplashCoord *matA):
SplashT1Font::~SplashT1Font() {
T1_DeleteFont(t1libID);
+ if (outlineID >= 0) {
+ T1_DeleteFont(outlineID);
+ }
}
GBool SplashT1Font::getGlyph(int c, int xFrac, int yFrac,
@@ -210,6 +215,7 @@ GBool SplashT1Font::makeGlyph(int c, int xFrac, int yFrac,
}
SplashPath *SplashT1Font::getGlyphPath(int c) {
+ T1_TMATRIX matrix;
SplashPath *path;
T1_OUTLINE *outline;
T1_PATHSEGMENT *seg;
@@ -217,47 +223,64 @@ SplashPath *SplashT1Font::getGlyphPath(int c) {
SplashCoord x, y, x1, y1;
GBool needClose;
- path = new SplashPath();
- if (!(outline = T1_GetCharOutline(t1libID, c, size, NULL))) {
- return path;
+ if (outlineID < 0) {
+ outlineID = T1_CopyFont(((SplashT1FontFile *)fontFile)->t1libID);
+ outlineSize = (float)splashSqrt(textMat[2]*textMat[2] +
+ textMat[3]*textMat[3]);
+ matrix.cxx = (double)textMat[0] / outlineSize;
+ matrix.cxy = (double)textMat[1] / outlineSize;
+ matrix.cyx = (double)textMat[2] / outlineSize;
+ matrix.cyy = (double)textMat[3] / outlineSize;
+ // t1lib doesn't seem to handle small sizes correctly here, so set
+ // the size to 1000, and scale the resulting coordinates later
+ outlineMul = (float)(outlineSize / 65536000.0);
+ outlineSize = 1000;
+ T1_TransformFont(outlineID, &matrix);
}
- x = 0;
- y = 0;
- needClose = gFalse;
- for (seg = outline; seg; seg = seg->link) {
- switch (seg->type) {
- case T1_PATHTYPE_MOVE:
- if (needClose) {
- path->close();
- needClose = gFalse;
+
+ path = new SplashPath();
+ if ((outline = T1_GetCharOutline(outlineID, c, outlineSize, NULL))) {
+ x = 0;
+ y = 0;
+ needClose = gFalse;
+ for (seg = outline; seg; seg = seg->link) {
+ switch (seg->type) {
+ case T1_PATHTYPE_MOVE:
+ if (needClose) {
+ path->close();
+ needClose = gFalse;
+ }
+ x += seg->dest.x * outlineMul;
+ y += seg->dest.y * outlineMul;
+ path->moveTo(x, -y);
+ break;
+ case T1_PATHTYPE_LINE:
+ x += seg->dest.x * outlineMul;
+ y += seg->dest.y * outlineMul;
+ path->lineTo(x, -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);
+ x = x1;
+ y = y1;
+ needClose = gTrue;
+ break;
}
- x += seg->dest.x / 65536.0;
- y += seg->dest.y / 65536.0;
- path->moveTo(x, y);
- break;
- case T1_PATHTYPE_LINE:
- x += seg->dest.x / 65536.0;
- y += seg->dest.y / 65536.0;
- path->lineTo(x, y);
- needClose = gTrue;
- break;
- case T1_PATHTYPE_BEZIER:
- bez = (T1_BEZIERSEGMENT *)seg;
- x1 = x + bez->dest.x / 65536.0;
- y1 = y + bez->dest.y / 65536.0;
- path->curveTo(x + bez->B.x / 65536.0, y + bez->B.y / 65536.0,
- x + bez->C.x / 65536.0, y + bez->C.y / 65536.0,
- x1, y1);
- x = x1;
- y = y1;
- needClose = gTrue;
- break;
}
+ if (needClose) {
+ path->close();
+ }
+ T1_FreeOutline(outline);
}
- if (needClose) {
- path->close();
- }
- T1_FreeOutline(outline);
+
return path;
}
diff --git a/splash/SplashT1Font.h b/splash/SplashT1Font.h
index 18cd6501..919dc032 100644
--- a/splash/SplashT1Font.h
+++ b/splash/SplashT1Font.h
@@ -24,7 +24,8 @@ class SplashT1FontFile;
class SplashT1Font: public SplashFont {
public:
- SplashT1Font(SplashT1FontFile *fontFileA, SplashCoord *matA);
+ SplashT1Font(SplashT1FontFile *fontFileA, SplashCoord *matA,
+ SplashCoord *textMatA);
virtual ~SplashT1Font();
@@ -43,7 +44,10 @@ public:
private:
int t1libID; // t1lib font ID
+ int outlineID; // t1lib font ID for glyph outlines
float size;
+ float outlineSize; // size for glyph outlines
+ float outlineMul;
};
#endif // HAVE_T1LIB_H
diff --git a/splash/SplashT1FontEngine.cc b/splash/SplashT1FontEngine.cc
index d180a5a8..a19d1bce 100644
--- a/splash/SplashT1FontEngine.cc
+++ b/splash/SplashT1FontEngine.cc
@@ -84,7 +84,7 @@ SplashT1FontEngine::~SplashT1FontEngine() {
SplashFontFile *SplashT1FontEngine::loadType1Font(SplashFontFileID *idA,
SplashFontSrc *src,
char **enc) {
- return SplashT1FontFile::loadType1Font(this, idA, src, enc);
+ return SplashT1FontFile::loadType1Font(this, idA, fileName, deleteFile, enc);
}
SplashFontFile *SplashT1FontEngine::loadType1CFont(SplashFontFileID *idA,
@@ -109,7 +109,7 @@ SplashFontFile *SplashT1FontEngine::loadType1CFont(SplashFontFileID *idA,
delete ff;
return NULL;
}
- ff->convertToType1(NULL, gTrue, &fileWrite, tmpFile);
+ ff->convertToType1(NULL, NULL, gTrue, &fileWrite, tmpFile);
delete ff;
fclose(tmpFile);
newsrc = new SplashFontSrc;
diff --git a/splash/SplashT1FontFile.cc b/splash/SplashT1FontFile.cc
index c5e9f5fe..16a1473c 100644
--- a/splash/SplashT1FontFile.cc
+++ b/splash/SplashT1FontFile.cc
@@ -33,6 +33,7 @@ SplashFontFile *SplashT1FontFile::loadType1Font(SplashT1FontEngine *engineA,
int encStrSize;
char *encPtr;
int i;
+
GString *fileNameA;
SplashFontSrc *newsrc = NULL;
SplashFontFile *ff;
@@ -52,8 +53,7 @@ SplashFontFile *SplashT1FontFile::loadType1Font(SplashT1FontEngine *engineA,
fileNameA = src->fileName;
// load the font file
if ((t1libIDA = T1_AddFont(fileNameA)) < 0) {
- if (newsrc)
- delete newsrc;
+ delete newsrc;
return NULL;
}
T1_LoadFont(t1libIDA);
@@ -105,10 +105,11 @@ SplashT1FontFile::~SplashT1FontFile() {
T1_DeleteFont(t1libID);
}
-SplashFont *SplashT1FontFile::makeFont(SplashCoord *mat) {
+SplashFont *SplashT1FontFile::makeFont(SplashCoord *mat,
+ SplashCoord *textMat) {
SplashFont *font;
- font = new SplashT1Font(this, mat);
+ font = new SplashT1Font(this, mat, textMat);
font->initCache();
return font;
}
diff --git a/splash/SplashT1FontFile.h b/splash/SplashT1FontFile.h
index 2ab72167..2282deae 100644
--- a/splash/SplashT1FontFile.h
+++ b/splash/SplashT1FontFile.h
@@ -26,20 +26,21 @@ public:
static SplashFontFile *loadType1Font(SplashT1FontEngine *engineA,
SplashFontFileID *idA,
- SplashFontSrc *src,
+ char *fileNameA,
char **encA);
virtual ~SplashT1FontFile();
// Create a new SplashT1Font, i.e., a scaled instance of this font
// file.
- virtual SplashFont *makeFont(SplashCoord *mat);
+ virtual SplashFont *makeFont(SplashCoord *mat,
+ SplashCoord *textMat);
private:
SplashT1FontFile(SplashT1FontEngine *engineA,
SplashFontFileID *idA,
- SplashFontSrc *src,
+ char *fileNameA,
int t1libIDA, char **encA, char *encStrA);
SplashT1FontEngine *engine;
diff --git a/splash/SplashTypes.h b/splash/SplashTypes.h
index 82aeb8ed..f367be72 100644
--- a/splash/SplashTypes.h
+++ b/splash/SplashTypes.h
@@ -21,6 +21,12 @@ typedef double SplashCoord;
#endif
//------------------------------------------------------------------------
+// antialiasing
+//------------------------------------------------------------------------
+
+#define splashAASize 4
+
+//------------------------------------------------------------------------
// colors
//------------------------------------------------------------------------
@@ -28,24 +34,16 @@ enum SplashColorMode {
splashModeMono1, // 1 bit per component, 8 pixels per byte,
// MSbit is on the left
splashModeMono8, // 1 byte per component, 1 byte per pixel
- splashModeAMono8, // 1 byte per component, 2 bytes per pixel:
- // AMAM...
splashModeRGB8, // 1 byte per component, 3 bytes per pixel:
// RGBRGB...
splashModeBGR8, // 1 byte per component, 3 bytes per pixel:
// BGRBGR...
- splashModeARGB8, // 1 byte per component, 4 bytes per pixel:
- // ARGBARGB...
- splashModeRGB8Qt, // 1 byte per component, 4 bytes per pixel:
- // Specially hacked to use in Qt frontends
- splashModeBGRA8 // 1 byte per component, 4 bytes per pixel:
- // BGRABGRA...
+ splashModeRGBX8, // 1 byte per component, 4 bytes per pixel:
+ // RGBXRGBX...
#if SPLASH_CMYK
,
- splashModeCMYK8, // 1 byte per component, 4 bytes per pixel:
+ splashModeCMYK8 // 1 byte per component, 4 bytes per pixel:
// CMYKCMYK...
- splashModeACMYK8 // 1 byte per component, 5 bytes per pixel:
- // ACMYKACMYK
#endif
};
@@ -55,18 +53,14 @@ extern int splashColorModeNComps[];
// max number of components in any SplashColor
#if SPLASH_CMYK
-# define splashMaxColorComps 5
-#else
# define splashMaxColorComps 4
+#else
+# define splashMaxColorComps 3
#endif
typedef Guchar SplashColor[splashMaxColorComps];
typedef Guchar *SplashColorPtr;
-// AMono8
-static inline Guchar splashAMono8A(SplashColorPtr am8) { return am8[0]; }
-static inline Guchar splashAMono8M(SplashColorPtr am8) { return am8[1]; }
-
// RGB8
static inline Guchar splashRGB8R(SplashColorPtr rgb8) { return rgb8[0]; }
static inline Guchar splashRGB8G(SplashColorPtr rgb8) { return rgb8[1]; }
@@ -77,40 +71,20 @@ static inline Guchar splashBGR8R(SplashColorPtr bgr8) { return bgr8[2]; }
static inline Guchar splashBGR8G(SplashColorPtr bgr8) { return bgr8[1]; }
static inline Guchar splashBGR8B(SplashColorPtr bgr8) { return bgr8[0]; }
-// ARGB8
-static inline Guchar splashARGB8A(SplashColorPtr argb8) { return argb8[0]; }
-static inline Guchar splashARGB8R(SplashColorPtr argb8) { return argb8[1]; }
-static inline Guchar splashARGB8G(SplashColorPtr argb8) { return argb8[2]; }
-static inline Guchar splashARGB8B(SplashColorPtr argb8) { return argb8[3]; }
-
-// ARGB8
-static inline Guchar splashBGRA8A(SplashColorPtr bgra8) { return bgra8[3]; }
-static inline Guchar splashBGRA8R(SplashColorPtr bgra8) { return bgra8[2]; }
-static inline Guchar splashBGRA8G(SplashColorPtr bgra8) { return bgra8[1]; }
-static inline Guchar splashBGRA8B(SplashColorPtr bgra8) { return bgra8[0]; }
-
#if SPLASH_CMYK
// CMYK8
static inline Guchar splashCMYK8C(SplashColorPtr cmyk8) { return cmyk8[0]; }
static inline Guchar splashCMYK8M(SplashColorPtr cmyk8) { return cmyk8[1]; }
static inline Guchar splashCMYK8Y(SplashColorPtr cmyk8) { return cmyk8[2]; }
static inline Guchar splashCMYK8K(SplashColorPtr cmyk8) { return cmyk8[3]; }
-
-// ACMYK8
-static inline Guchar splashACMYK8A(SplashColorPtr acmyk8) { return acmyk8[0]; }
-static inline Guchar splashACMYK8C(SplashColorPtr acmyk8) { return acmyk8[1]; }
-static inline Guchar splashACMYK8M(SplashColorPtr acmyk8) { return acmyk8[2]; }
-static inline Guchar splashACMYK8Y(SplashColorPtr acmyk8) { return acmyk8[3]; }
-static inline Guchar splashACMYK8K(SplashColorPtr acmyk8) { return acmyk8[4]; }
#endif
static inline void splashColorCopy(SplashColorPtr dest, SplashColorPtr src) {
dest[0] = src[0];
dest[1] = src[1];
dest[2] = src[2];
- dest[3] = src[3];
#if SPLASH_CMYK
- dest[4] = src[4];
+ dest[3] = src[3];
#endif
}
@@ -118,9 +92,8 @@ static inline void splashColorXor(SplashColorPtr dest, SplashColorPtr src) {
dest[0] ^= src[0];
dest[1] ^= src[1];
dest[2] ^= src[2];
- dest[3] ^= src[3];
#if SPLASH_CMYK
- dest[4] ^= src[4];
+ dest[3] ^= src[3];
#endif
}
@@ -132,6 +105,25 @@ typedef void (*SplashBlendFunc)(SplashColorPtr src, SplashColorPtr dest,
SplashColorPtr blend, SplashColorMode cm);
//------------------------------------------------------------------------
+// screen parameters
+//------------------------------------------------------------------------
+
+enum SplashScreenType {
+ splashScreenDispersed,
+ splashScreenClustered,
+ splashScreenStochasticClustered
+};
+
+struct SplashScreenParams {
+ SplashScreenType type;
+ int size;
+ int dotRadius;
+ SplashCoord gamma;
+ SplashCoord blackThreshold;
+ SplashCoord whiteThreshold;
+};
+
+//------------------------------------------------------------------------
// error results
//------------------------------------------------------------------------
diff --git a/splash/SplashXPath.cc b/splash/SplashXPath.cc
index 7fa0865a..d7e114d5 100644
--- a/splash/SplashXPath.cc
+++ b/splash/SplashXPath.cc
@@ -19,7 +19,31 @@
//------------------------------------------------------------------------
-#define maxCurveSplits (1 << 10)
+struct SplashXPathPoint {
+ SplashCoord x, y;
+};
+
+struct SplashXPathAdjust {
+ int firstPt, lastPt; // range of points
+ GBool vert; // vertical or horizontal hint
+ SplashCoord x0a, x0b, // hint boundaries
+ xma, xmb,
+ x1a, x1b;
+ SplashCoord x0, x1, xm; // adjusted coordinates
+};
+
+//------------------------------------------------------------------------
+
+// Transform a point from user space to device space.
+inline void SplashXPath::transform(SplashCoord *matrix,
+ SplashCoord xi, SplashCoord yi,
+ SplashCoord *xo, SplashCoord *yo) {
+ // [ m[0] m[1] 0 ]
+ // [xo yo 1] = [xi yi 1] * [ m[2] m[3] 0 ]
+ // [ m[4] m[5] 1 ]
+ *xo = xi * matrix[0] + yi * matrix[2] + matrix[4];
+ *yo = xi * matrix[1] + yi * matrix[3] + matrix[5];
+}
//------------------------------------------------------------------------
// SplashXPath
@@ -30,32 +54,118 @@ SplashXPath::SplashXPath() {
length = size = 0;
}
-SplashXPath::SplashXPath(SplashPath *path, SplashCoord flatness,
- GBool closeSubpaths) {
- SplashCoord xc, yc, dx, dy, r, x0, y0, x1, y1;
- int quad0, quad1, quad;
- int curSubpath, n, i, j;
+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;
+ int curSubpath, curSubpathX, i, j;
+
+ // transform the points
+ pts = (SplashXPathPoint *)gmallocn(path->length, sizeof(SplashXPathPoint));
+ for (i = 0; i < path->length; ++i) {
+ transform(matrix, path->pts[i].x, path->pts[i].y, &pts[i].x, &pts[i].y);
+ }
+
+ // set up the stroke adjustment hints
+ if (path->hints) {
+ adjusts = (SplashXPathAdjust *)gmallocn(path->hintsLength,
+ sizeof(SplashXPathAdjust));
+ for (i = 0; i < path->hintsLength; ++i) {
+ hint = &path->hints[i];
+ if (hint->ctrl0 + 1 >= path->length || hint->ctrl1 + 1 >= path->length) {
+ gfree(adjusts);
+ adjusts = NULL;
+ break;
+ }
+ x0 = pts[hint->ctrl0 ].x; y0 = pts[hint->ctrl0 ].y;
+ x1 = pts[hint->ctrl0 + 1].x; y1 = pts[hint->ctrl0 + 1].y;
+ x2 = pts[hint->ctrl1 ].x; y2 = pts[hint->ctrl1 ].y;
+ x3 = pts[hint->ctrl1 + 1].x; y3 = pts[hint->ctrl1 + 1].y;
+ if (x0 == x1 && x2 == x3) {
+ adjusts[i].vert = gTrue;
+ adj0 = x0;
+ adj1 = x2;
+ } else if (y0 == y1 && y2 == y3) {
+ adjusts[i].vert = gFalse;
+ adj0 = y0;
+ adj1 = y2;
+ } else {
+ gfree(adjusts);
+ adjusts = NULL;
+ break;
+ }
+ if (adj0 > adj1) {
+ x0 = adj0;
+ adj0 = adj1;
+ adj1 = x0;
+ }
+ 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;
+ adjusts[i].xm = (SplashCoord)0.5 * (adjusts[i].x0 + adjusts[i].x1);
+ adjusts[i].firstPt = hint->firstPt;
+ adjusts[i].lastPt = hint->lastPt;
+ }
+
+ } else {
+ adjusts = NULL;
+ }
+
+ // perform stroke adjustment
+ if (adjusts) {
+ for (i = 0, adjust = adjusts; i < path->hintsLength; ++i, ++adjust) {
+ for (j = adjust->firstPt; j <= adjust->lastPt; ++j) {
+ strokeAdjust(adjust, &pts[j].x, &pts[j].y);
+ }
+ }
+ gfree(adjusts);
+ }
segs = NULL;
length = size = 0;
- i = 0;
+ x0 = y0 = xsp = ysp = 0; // make gcc happy
+ adj0 = adj1 = 0; // make gcc happy
curSubpath = 0;
+ curSubpathX = 0;
+ i = 0;
while (i < path->length) {
// first point in subpath - skip it
if (path->flags[i] & splashPathFirst) {
+ x0 = pts[i].x;
+ y0 = pts[i].y;
+ xsp = x0;
+ ysp = y0;
curSubpath = i;
+ curSubpathX = length;
++i;
} else {
// curve segment
if (path->flags[i] & splashPathCurve) {
- addCurve(path->pts[i-1].x, path->pts[i-1].y,
- path->pts[i ].x, path->pts[i ].y,
- path->pts[i+1].x, path->pts[i+1].y,
- path->pts[i+2].x, path->pts[i+2].y,
+ x1 = pts[i].x;
+ y1 = pts[i].y;
+ x2 = pts[i+1].x;
+ y2 = pts[i+1].y;
+ x3 = pts[i+2].x;
+ y3 = pts[i+2].y;
+ addCurve(x0, y0, x1, y1, x2, y2, x3, y3,
flatness,
(path->flags[i-1] & splashPathFirst),
(path->flags[i+2] & splashPathLast),
@@ -65,83 +175,15 @@ SplashXPath::SplashXPath(SplashPath *path, SplashCoord flatness,
!closeSubpaths &&
(path->flags[i+2] & splashPathLast) &&
!(path->flags[i+2] & splashPathClosed));
+ x0 = x3;
+ y0 = y3;
i += 3;
- // clockwise circular arc
- } else if (path->flags[i] & splashPathArcCW) {
- xc = path->pts[i].x;
- yc = path->pts[i].y;
- dx = path->pts[i+1].x - xc;
- dy = path->pts[i+1].y - yc;
- r = splashSqrt(dx * dx + dy * dy);
- if (path->pts[i-1].x < xc && path->pts[i-1].y <= yc) {
- quad0 = 0;
- } else if (path->pts[i-1].x >= xc && path->pts[i-1].y < yc) {
- quad0 = 1;
- } else if (path->pts[i-1].x > xc && path->pts[i-1].y >= yc) {
- quad0 = 2;
- } else {
- quad0 = 3;
- }
- if (path->pts[i+1].x <= xc && path->pts[i+1].y < yc) {
- quad1 = 0;
- } else if (path->pts[i+1].x > xc && path->pts[i+1].y <= yc) {
- quad1 = 1;
- } else if (path->pts[i+1].x >= xc && path->pts[i+1].y > yc) {
- quad1 = 2;
- } else {
- quad1 = 3;
- }
- n = 0; // make gcc happy
- if (quad0 == quad1) {
- switch (quad0) {
- case 0:
- case 1: n = path->pts[i-1].x < path->pts[i+1].x ? 0 : 4; break;
- case 2:
- case 3: n = path->pts[i-1].x > path->pts[i+1].x ? 0 : 4; break;
- }
- } else {
- n = (quad1 - quad0) & 3;
- }
- x0 = path->pts[i-1].x;
- y0 = path->pts[i-1].y;
- x1 = y1 = 0; // make gcc happy
- quad = quad0;
- for (j = 0; j < n; ++j) {
- switch (quad) {
- case 0: x1 = xc; y1 = yc - r; break;
- case 1: x1 = xc + r; y1 = yc; break;
- case 2: x1 = xc; y1 = yc + r; break;
- case 3: x1 = xc - r; y1 = yc; break;
- }
- addArc(x0, y0, x1, y1,
- xc, yc, r, quad, flatness,
- quad == quad0 && (path->flags[i-1] & splashPathFirst),
- gFalse,
- quad == quad0 && !closeSubpaths &&
- (path->flags[i-1] & splashPathFirst) &&
- !(path->flags[i-1] & splashPathClosed),
- gFalse);
- x0 = x1;
- y0 = y1;
- quad = (quad + 1) & 3;
- }
- addArc(x0, y0, path->pts[i+1].x, path->pts[i+1].y,
- xc, yc, r, quad, flatness,
- quad == quad0 && (path->flags[i-1] & splashPathFirst),
- (path->flags[i+1] & splashPathLast),
- quad == quad0 && !closeSubpaths &&
- (path->flags[i-1] & splashPathFirst) &&
- !(path->flags[i-1] & splashPathClosed),
- !closeSubpaths &&
- (path->flags[i+1] & splashPathLast) &&
- !(path->flags[i+1] & splashPathClosed));
- i += 2;
-
// line segment
} else {
- addSegment(path->pts[i-1].x, path->pts[i-1].y,
- path->pts[i].x, path->pts[i].y,
+ x1 = pts[i].x;
+ y1 = pts[i].y;
+ addSegment(x0, y0, x1, y1,
path->flags[i-1] & splashPathFirst,
path->flags[i] & splashPathLast,
!closeSubpaths &&
@@ -150,20 +192,49 @@ SplashXPath::SplashXPath(SplashPath *path, SplashCoord flatness,
!closeSubpaths &&
(path->flags[i] & splashPathLast) &&
!(path->flags[i] & splashPathClosed));
+ x0 = x1;
+ y0 = y1;
++i;
}
// close a subpath
if (closeSubpaths &&
(path->flags[i-1] & splashPathLast) &&
- (path->pts[i-1].x != path->pts[curSubpath].x ||
- path->pts[i-1].y != path->pts[curSubpath]. y)) {
- addSegment(path->pts[i-1].x, path->pts[i-1].y,
- path->pts[curSubpath].x, path->pts[curSubpath].y,
+ (pts[i-1].x != pts[curSubpath].x ||
+ pts[i-1].y != pts[curSubpath].y)) {
+ addSegment(x0, y0, xsp, ysp,
gFalse, gTrue, gFalse, gFalse);
}
}
}
+
+ gfree(pts);
+}
+
+// Apply the stroke adjust hints to point <pt>: (*<xp>, *<yp>).
+void SplashXPath::strokeAdjust(SplashXPathAdjust *adjust,
+ SplashCoord *xp, SplashCoord *yp) {
+ SplashCoord x, y;
+
+ if (adjust->vert) {
+ x = *xp;
+ if (x > adjust->x0a && x < adjust->x0b) {
+ *xp = adjust->x0;
+ } else if (x > adjust->xma && x < adjust->xmb) {
+ *xp = adjust->xm;
+ } else if (x > adjust->x1a && x < adjust->x1b) {
+ *xp = adjust->x1;
+ }
+ } else {
+ y = *yp;
+ if (y > adjust->x0a && y < adjust->x0b) {
+ *yp = adjust->x0;
+ } else if (y > adjust->xma && y < adjust->xmb) {
+ *yp = adjust->xm;
+ } else if (y > adjust->x1a && y < adjust->x1b) {
+ *yp = adjust->x1;
+ }
+ }
}
SplashXPath::SplashXPath(SplashXPath *xPath) {
@@ -196,9 +267,9 @@ void SplashXPath::addCurve(SplashCoord x0, SplashCoord y0,
SplashCoord x3, SplashCoord y3,
SplashCoord flatness,
GBool first, GBool last, GBool end0, GBool end1) {
- SplashCoord cx[maxCurveSplits + 1][3];
- SplashCoord cy[maxCurveSplits + 1][3];
- int cNext[maxCurveSplits + 1];
+ SplashCoord cx[splashMaxCurveSplits + 1][3];
+ SplashCoord cy[splashMaxCurveSplits + 1][3];
+ int cNext[splashMaxCurveSplits + 1];
SplashCoord xl0, xl1, xl2, xr0, xr1, xr2, xr3, xx1, xx2, xh;
SplashCoord yl0, yl1, yl2, yr0, yr1, yr2, yr3, yy1, yy2, yh;
SplashCoord dx, dy, mx, my, d1, d2, flatness2;
@@ -208,14 +279,14 @@ void SplashXPath::addCurve(SplashCoord x0, SplashCoord y0,
// initial segment
p1 = 0;
- p2 = maxCurveSplits;
+ p2 = splashMaxCurveSplits;
cx[p1][0] = x0; cy[p1][0] = y0;
cx[p1][1] = x1; cy[p1][1] = y1;
cx[p1][2] = x2; cy[p1][2] = y2;
cx[p2][0] = x3; cy[p2][0] = y3;
cNext[p1] = p2;
- while (p1 < maxCurveSplits) {
+ while (p1 < splashMaxCurveSplits) {
// get the next segment
xl0 = cx[p1][0]; yl0 = cy[p1][0];
@@ -242,9 +313,9 @@ void SplashXPath::addCurve(SplashCoord x0, SplashCoord y0,
if (p2 - p1 == 1 || (d1 <= flatness2 && d2 <= flatness2)) {
addSegment(xl0, yl0, xr3, yr3,
p1 == 0 && first,
- p2 == maxCurveSplits && last,
+ p2 == splashMaxCurveSplits && last,
p1 == 0 && end0,
- p2 == maxCurveSplits && end1);
+ p2 == splashMaxCurveSplits && end1);
p1 = p2;
// otherwise, subdivide the curve
@@ -274,73 +345,6 @@ void SplashXPath::addCurve(SplashCoord x0, SplashCoord y0,
}
}
-void SplashXPath::addArc(SplashCoord x0, SplashCoord y0,
- SplashCoord x1, SplashCoord y1,
- SplashCoord xc, SplashCoord yc,
- SplashCoord r, int quad,
- SplashCoord flatness,
- GBool first, GBool last, GBool end0, GBool end1) {
- SplashCoord px[maxCurveSplits + 1];
- SplashCoord py[maxCurveSplits + 1];
- int pNext[maxCurveSplits + 1];
- SplashCoord r2, flatness2;
- SplashCoord xx0, yy0, xx1, yy1, xm, ym, t, dx, dy;
- int p1, p2, p3;
-
- r2 = r * r;
- flatness2 = flatness * flatness;
-
- // initial segment
- p1 = 0;
- p2 = maxCurveSplits;
- px[p1] = x0; py[p1] = y0;
- px[p2] = x1; py[p2] = y1;
- pNext[p1] = p2;
-
- while (p1 < maxCurveSplits) {
-
- // get the next segment
- xx0 = px[p1]; yy0 = py[p1];
- p2 = pNext[p1];
- xx1 = px[p2]; yy1 = py[p2];
-
- // compute the arc midpoint
- t = (xx0 - xc) * (xx1 - xc) - (yy0 - yc) * (yy1 - yc);
- xm = splashSqrt((SplashCoord)0.5 * (r2 + t));
- ym = splashSqrt((SplashCoord)0.5 * (r2 - t));
- switch (quad) {
- case 0: xm = xc - xm; ym = yc - ym; break;
- case 1: xm = xc + xm; ym = yc - ym; break;
- case 2: xm = xc + xm; ym = yc + ym; break;
- case 3: xm = xc - xm; ym = yc + ym; break;
- }
-
- // compute distance from midpoint of straight segment to midpoint
- // of arc
- dx = (SplashCoord)0.5 * (xx0 + xx1) - xm;
- dy = (SplashCoord)0.5 * (yy0 + yy1) - ym;
-
- // if the arc is flat enough, or no more subdivisions are allowed,
- // add the straight line segment
- if (p2 - p1 == 1 || dx * dx + dy * dy <= flatness2) {
- addSegment(xx0, yy0, xx1, yy1,
- p1 == 0 && first,
- p2 == maxCurveSplits && last,
- p1 == 0 && end0,
- p2 == maxCurveSplits && end1);
- p1 = p2;
-
- // otherwise, subdivide the arc
- } else {
- p3 = (p1 + p2) / 2;
- px[p3] = xm;
- py[p3] = ym;
- pNext[p1] = p3;
- pNext[p3] = p2;
- }
- }
-}
-
void SplashXPath::addSegment(SplashCoord x0, SplashCoord y0,
SplashCoord x1, SplashCoord y1,
GBool first, GBool last, GBool end0, GBool end1) {
@@ -372,8 +376,21 @@ void SplashXPath::addSegment(SplashCoord x0, SplashCoord y0,
segs[length].dxdy = segs[length].dydx = 0;
segs[length].flags |= splashXPathVert;
} else {
+#if USE_FIXEDPOINT
+ if (FixedPoint::divCheck(x1 - x0, y1 - y0, &segs[length].dxdy)) {
+ segs[length].dydx = (SplashCoord)1 / segs[length].dxdy;
+ } else {
+ segs[length].dxdy = segs[length].dydx = 0;
+ if (splashAbs(x1 - x0) > splashAbs(y1 - y0)) {
+ segs[length].flags |= splashXPathHoriz;
+ } else {
+ segs[length].flags |= splashXPathVert;
+ }
+ }
+#else
segs[length].dxdy = (x1 - x0) / (y1 - y0);
segs[length].dydx = (SplashCoord)1 / segs[length].dxdy;
+#endif
}
if (y0 > y1) {
segs[length].flags |= splashXPathFlip;
@@ -409,6 +426,18 @@ static int cmpXPathSegs(const void *arg0, const void *arg1) {
return 0;
}
+void SplashXPath::aaScale() {
+ SplashXPathSeg *seg;
+ int i;
+
+ for (i = 0, seg = segs; i < length; ++i, ++seg) {
+ seg->x0 *= splashAASize;
+ seg->y0 *= splashAASize;
+ seg->x1 *= splashAASize;
+ seg->y1 *= splashAASize;
+ }
+}
+
void SplashXPath::sort() {
qsort(segs, length, sizeof(SplashXPathSeg), &cmpXPathSegs);
}
diff --git a/splash/SplashXPath.h b/splash/SplashXPath.h
index a72d5633..942104fb 100644
--- a/splash/SplashXPath.h
+++ b/splash/SplashXPath.h
@@ -14,6 +14,11 @@
#include "SplashTypes.h"
class SplashPath;
+struct SplashXPathAdjust;
+
+//------------------------------------------------------------------------
+
+#define splashMaxCurveSplits (1 << 10)
//------------------------------------------------------------------------
// SplashXPathSeg
@@ -45,16 +50,21 @@ class SplashXPath {
public:
// Expands (converts to segments) and flattens (converts curves to
- // lines) <path>. If <closeSubpaths> is true, closes all open
+ // lines) <path>. Transforms all points from user space to device
+ // space, via <matrix>. If <closeSubpaths> is true, closes all open
// subpaths.
- SplashXPath(SplashPath *path, SplashCoord flatness,
- GBool closeSubpaths);
+ SplashXPath(SplashPath *path, SplashCoord *matrix,
+ SplashCoord flatness, GBool closeSubpaths);
// Copy an expanded path.
SplashXPath *copy() { return new SplashXPath(this); }
~SplashXPath();
+ // Multiply all coordinates by splashAASize, in preparation for
+ // anti-aliased rendering.
+ void aaScale();
+
// Sort by upper coordinate (lower y), in y-major order.
void sort();
@@ -62,6 +72,10 @@ private:
SplashXPath();
SplashXPath(SplashXPath *xPath);
+ void transform(SplashCoord *matrix, SplashCoord xi, SplashCoord yi,
+ SplashCoord *xo, SplashCoord *yo);
+ void strokeAdjust(SplashXPathAdjust *adjust,
+ SplashCoord *xp, SplashCoord *yp);
void grow(int nSegs);
void addCurve(SplashCoord x0, SplashCoord y0,
SplashCoord x1, SplashCoord y1,
@@ -69,12 +83,6 @@ private:
SplashCoord x3, SplashCoord y3,
SplashCoord flatness,
GBool first, GBool last, GBool end0, GBool end1);
- void addArc(SplashCoord x0, SplashCoord y0,
- SplashCoord x1, SplashCoord y1,
- SplashCoord xc, SplashCoord yc,
- SplashCoord r, int quad,
- 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);
diff --git a/splash/SplashXPathScanner.cc b/splash/SplashXPathScanner.cc
index 9b1c1c4f..99a0ce87 100644
--- a/splash/SplashXPathScanner.cc
+++ b/splash/SplashXPathScanner.cc
@@ -11,9 +11,11 @@
#endif
#include <stdlib.h>
+#include <string.h>
#include "goo/gmem.h"
#include "SplashMath.h"
#include "SplashXPath.h"
+#include "SplashBitmap.h"
#include "SplashXPathScanner.h"
//------------------------------------------------------------------------
@@ -97,6 +99,14 @@ SplashXPathScanner::~SplashXPathScanner() {
gfree(inter);
}
+void SplashXPathScanner::getBBoxAA(int *xMinA, int *yMinA,
+ int *xMaxA, int *yMaxA) {
+ *xMinA = xMin / splashAASize;
+ *yMinA = yMin / splashAASize;
+ *xMaxA = xMax / splashAASize;
+ *yMaxA = yMax / splashAASize;
+}
+
void SplashXPathScanner::getSpanBounds(int y, int *spanXMin, int *spanXMax) {
if (interY != y) {
computeIntersections(y);
@@ -283,3 +293,136 @@ void SplashXPathScanner::computeIntersections(int y) {
interIdx = 0;
interCount = 0;
}
+
+void SplashXPathScanner::renderAALine(SplashBitmap *aaBuf,
+ int *x0, int *x1, int y) {
+ int xx0, xx1, xx, xxMin, xxMax, yy;
+ 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();
+ }
+ // 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;
+ }
+ }
+ }
+ *x0 = xxMin / splashAASize;
+ *x1 = (xxMax - 1) / splashAASize;
+}
+
+void SplashXPathScanner::clipAALine(SplashBitmap *aaBuf,
+ int *x0, int *x1, int y) {
+ int xx0, xx1, xx, yy;
+ 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;
+ }
+ 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);
+ }
+ *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;
+ }
+ }
+ xx0 = (*x1 + 1) * splashAASize;
+ // set [xx, xx0) to 0
+ if (xx < xx0) {
+ p = aaBuf->getDataPtr() + yy * aaBuf->getRowSize() + (xx >> 3);
+ if (xx & 7) {
+ mask = (Guchar)(0xff00 >> (xx & 7));
+ if ((xx & ~7) == (xx0 & ~7)) {
+ mask &= 0xff >> (xx0 & 7);
+ }
+ *p++ &= mask;
+ xx = (xx & ~7) + 8;
+ }
+ for (; xx + 7 <= xx0; xx += 8) {
+ *p++ = 0x00;
+ }
+ if (xx <= xx0) {
+ *p &= 0xff >> (xx0 & 7);
+ }
+ }
+ }
+}
diff --git a/splash/SplashXPathScanner.h b/splash/SplashXPathScanner.h
index 169d4b0c..1cc4f3cd 100644
--- a/splash/SplashXPathScanner.h
+++ b/splash/SplashXPathScanner.h
@@ -14,6 +14,7 @@
#include "SplashTypes.h"
class SplashXPath;
+class SplashBitmap;
struct SplashIntersect;
//------------------------------------------------------------------------
@@ -32,6 +33,9 @@ public:
void getBBox(int *xMinA, int *yMinA, int *xMaxA, int *yMaxA)
{ *xMinA = xMin; *yMinA = yMin; *xMaxA = xMax; *yMaxA = yMax; }
+ // Return the path's bounding box.
+ void getBBoxAA(int *xMinA, int *yMinA, int *xMaxA, int *yMaxA);
+
// Return the min/max x values for the span at <y>.
void getSpanBounds(int y, int *spanXMin, int *spanXMax);
@@ -49,6 +53,15 @@ public:
// no more spans at <y>.
GBool getNextSpan(int y, int *x0, int *x1);
+ // Renders one anti-aliased line into <aaBuf>. Returns the min and
+ // max x coordinates with non-zero pixels in <x0> and <x1>.
+ void renderAALine(SplashBitmap *aaBuf, int *x0, int *x1, int y);
+
+ // Clips an anti-aliased line by setting pixels to zero. On entry,
+ // all non-zero pixels are between <x0> and <x1>. This function
+ // will update <x0> and <x1>.
+ void clipAALine(SplashBitmap *aaBuf, int *x0, int *x1, int y);
+
private:
void computeIntersections(int y);