diff options
author | Akira Kakuto <kakuto@fuk.kindai.ac.jp> | 2017-08-13 07:14:48 +0000 |
---|---|---|
committer | Akira Kakuto <kakuto@fuk.kindai.ac.jp> | 2017-08-13 07:14:48 +0000 |
commit | 4b4995cda35627e06c43e25ecbe07c1bc1859bb5 (patch) | |
tree | 143ed02a389bab62f44043a54cbc70f69e312e2f /Build/source/libs/xpdf/xpdf-src/splash | |
parent | 00d00899c484b81967558f43c4fe4a896ffdf610 (diff) |
xpdf 4.00
git-svn-id: svn://tug.org/texlive/trunk@45031 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Build/source/libs/xpdf/xpdf-src/splash')
34 files changed, 2736 insertions, 1585 deletions
diff --git a/Build/source/libs/xpdf/xpdf-src/splash/CMakeLists.txt b/Build/source/libs/xpdf/xpdf-src/splash/CMakeLists.txt new file mode 100644 index 00000000000..f84968cfb2a --- /dev/null +++ b/Build/source/libs/xpdf/xpdf-src/splash/CMakeLists.txt @@ -0,0 +1,47 @@ +#======================================================================== +# +# splash/CMakeLists.txt +# +# CMake script for the splash library. +# +# Copyright 2015 Glyph & Cog, LLC +# +#======================================================================== + +if (HAVE_SPLASH) + include_directories("${PROJECT_SOURCE_DIR}") + include_directories("${PROJECT_BINARY_DIR}") + include_directories("${PROJECT_SOURCE_DIR}/goo") + include_directories("${PROJECT_SOURCE_DIR}/fofi") + include_directories("${FREETYPE_INCLUDE_DIRS}") + + if (HAVE_DTYPE4_H) + include_directories("${DTYPE_INCLUDE_DIR}") + set(DTYPE_SRCS + SplashDT4Font.cc SplashDT4FontEngine.cc SplashDT4FontFile.cc) + endif () + + add_library(splash_objs OBJECT + Splash.cc + SplashBitmap.cc + SplashClip.cc + SplashFTFont.cc + SplashFTFontEngine.cc + SplashFTFontFile.cc + SplashFont.cc + SplashFontEngine.cc + SplashFontFile.cc + SplashFontFileID.cc + SplashPath.cc + SplashPattern.cc + SplashScreen.cc + SplashState.cc + SplashXPath.cc + SplashXPathScanner.cc + ${DTYPE_SRCS} + ) + + add_library(splash + $<TARGET_OBJECTS:splash_objs> + ) +endif () diff --git a/Build/source/libs/xpdf/xpdf-src/splash/Makefile.dep b/Build/source/libs/xpdf/xpdf-src/splash/Makefile.dep deleted file mode 100644 index e69de29bb2d..00000000000 --- a/Build/source/libs/xpdf/xpdf-src/splash/Makefile.dep +++ /dev/null diff --git a/Build/source/libs/xpdf/xpdf-src/splash/Makefile.in b/Build/source/libs/xpdf/xpdf-src/splash/Makefile.in deleted file mode 100644 index 6479b1543ee..00000000000 --- a/Build/source/libs/xpdf/xpdf-src/splash/Makefile.in +++ /dev/null @@ -1,93 +0,0 @@ -#======================================================================== -# -# Splash library Makefile -# -# Copyright 2003 Glyph & Cog, LLC -# -#======================================================================== - -SHELL = /bin/sh - -srcdir = @srcdir@ -VPATH = @srcdir@ - -GOOSRCDIR = $(srcdir)/../goo -GOOLIBDIR = ../goo -FOFISRCDIR = $(srcdir)/../fofi -FOFILIBDIR = ../fofi - -CXXFLAGS = @CXXFLAGS@ @DEFS@ -I.. -I$(srcdir)/.. -I$(GOOSRCDIR) -I$(FOFISRCDIR) -I$(srcdir) @freetype2_CFLAGS@ - -CXX = @CXX@ -AR = @AR@ -RANLIB = @RANLIB@ - -LIBPREFIX = @LIBPREFIX@ - -#------------------------------------------------------------------------ - -.SUFFIXES: .cc - -.cc.o: - $(CXX) $(CXXFLAGS) -c $< - -#------------------------------------------------------------------------ - -CXX_SRC = \ - $(srcdir)/Splash.cc \ - $(srcdir)/SplashBitmap.cc \ - $(srcdir)/SplashClip.cc \ - $(srcdir)/SplashFTFont.cc \ - $(srcdir)/SplashFTFontEngine.cc \ - $(srcdir)/SplashFTFontFile.cc \ - $(srcdir)/SplashFont.cc \ - $(srcdir)/SplashFontEngine.cc \ - $(srcdir)/SplashFontFile.cc \ - $(srcdir)/SplashFontFileID.cc \ - $(srcdir)/SplashPath.cc \ - $(srcdir)/SplashPattern.cc \ - $(srcdir)/SplashScreen.cc \ - $(srcdir)/SplashState.cc \ - $(srcdir)/SplashXPath.cc \ - $(srcdir)/SplashXPathScanner.cc - -#------------------------------------------------------------------------ - -all: $(LIBPREFIX)splash.a - -#------------------------------------------------------------------------ - -SPLASH_OBJS = \ - Splash.o \ - SplashBitmap.o \ - SplashClip.o \ - SplashFTFont.o \ - SplashFTFontEngine.o \ - SplashFTFontFile.o \ - SplashFont.o \ - SplashFontEngine.o \ - SplashFontFile.o \ - SplashFontFileID.o \ - SplashPath.o \ - SplashPattern.o \ - SplashScreen.o \ - SplashState.o \ - SplashXPath.o \ - SplashXPathScanner.o - -$(LIBPREFIX)splash.a: $(SPLASH_OBJS) - rm -f $(LIBPREFIX)splash.a - $(AR) $(LIBPREFIX)splash.a $(SPLASH_OBJS) - $(RANLIB) $(LIBPREFIX)splash.a - -#------------------------------------------------------------------------ - -clean: - rm -f $(SPLASH_OBJS) $(LIBPREFIX)splash.a - -#------------------------------------------------------------------------ - -depend: - $(CXX) $(CXXFLAGS) -MM $(CXX_SRC) >Makefile.dep - --include Makefile.dep diff --git a/Build/source/libs/xpdf/xpdf-src/splash/Splash.cc b/Build/source/libs/xpdf/xpdf-src/splash/Splash.cc index d9035b37aa9..0810fbc3bd2 100644 --- a/Build/source/libs/xpdf/xpdf-src/splash/Splash.cc +++ b/Build/source/libs/xpdf/xpdf-src/splash/Splash.cc @@ -15,7 +15,9 @@ #include <stdlib.h> #include <string.h> #include <limits.h> +#include <math.h> #include "gmem.h" +#include "gmempp.h" #include "SplashErrorCodes.h" #include "SplashMath.h" #include "SplashBitmap.h" @@ -29,9 +31,12 @@ #include "SplashGlyphBitmap.h" #include "Splash.h" -//------------------------------------------------------------------------ +// the MSVC math.h doesn't define this +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif -#define splashAAGamma 0.67 +//------------------------------------------------------------------------ // distance of Bezier control point from center for circle approximation // = (4 * (sqrt(2) - 1) / 3) * r @@ -123,17 +128,6 @@ SplashPipeResultColorCtrl Splash::pipeResultColorAlphaBlend[] = { }; //------------------------------------------------------------------------ - -static void blendXor(SplashColorPtr src, SplashColorPtr dest, - SplashColorPtr blend, SplashColorMode cm) { - int i; - - for (i = 0; i < splashColorModeNComps[cm]; ++i) { - blend[i] = src[i] ^ dest[i]; - } -} - -//------------------------------------------------------------------------ // modified region //------------------------------------------------------------------------ @@ -269,7 +263,7 @@ void Splash::pipeRun(SplashPipe *pipe, int x0, int x1, int y, Guchar shape, aSrc, aDest, alphaI, alphaIm1, alpha0, aResult; SplashColor cSrc, cDest, cBlend; Guchar shapeVal, cResult0, cResult1, cResult2, cResult3; - int cSrcStride, shapeStride, x, lastX, t, i; + int cSrcStride, shapeStride, x, lastX, t; SplashColorPtr destColorPtr; Guchar destColorMask; Guchar *destAlphaPtr; @@ -396,49 +390,33 @@ void Splash::pipeRun(SplashPipe *pipe, int x0, int x1, int y, pipe->pattern->getColor(x, y, pipe->cSrcVal); } + cResult0 = cResult1 = cResult2 = cResult3 = 0; // make gcc happy + if (pipe->noTransparency && !state->blendFunc) { - //----- write destination pixel + //----- result color switch (bitmap->mode) { case splashModeMono1: - cResult0 = state->grayTransfer[cSrcPtr[0]]; - if (state->screen->test(x, y, cResult0)) { - *destColorPtr |= destColorMask; - } else { - *destColorPtr &= ~destColorMask; - } - destColorPtr += destColorMask & 1; - destColorMask = (destColorMask << 7) | (destColorMask >> 1); - break; case splashModeMono8: - *destColorPtr++ = state->grayTransfer[cSrcPtr[0]]; + cResult0 = state->grayTransfer[cSrcPtr[0]]; break; case splashModeRGB8: - destColorPtr[0] = state->rgbTransferR[cSrcPtr[0]]; - destColorPtr[1] = state->rgbTransferG[cSrcPtr[1]]; - destColorPtr[2] = state->rgbTransferB[cSrcPtr[2]]; - destColorPtr += 3; - break; case splashModeBGR8: - destColorPtr[0] = state->rgbTransferB[cSrcPtr[2]]; - destColorPtr[1] = state->rgbTransferG[cSrcPtr[1]]; - destColorPtr[2] = state->rgbTransferR[cSrcPtr[0]]; - destColorPtr += 3; + cResult0 = state->rgbTransferR[cSrcPtr[0]]; + cResult1 = state->rgbTransferG[cSrcPtr[1]]; + cResult2 = state->rgbTransferB[cSrcPtr[2]]; break; #if SPLASH_CMYK case splashModeCMYK8: - destColorPtr[0] = state->cmykTransferC[cSrcPtr[0]]; - destColorPtr[1] = state->cmykTransferM[cSrcPtr[1]]; - destColorPtr[2] = state->cmykTransferY[cSrcPtr[2]]; - destColorPtr[3] = state->cmykTransferK[cSrcPtr[3]]; - destColorPtr += 4; + cResult0 = state->cmykTransferC[cSrcPtr[0]]; + cResult1 = state->cmykTransferM[cSrcPtr[1]]; + cResult2 = state->cmykTransferY[cSrcPtr[2]]; + cResult3 = state->cmykTransferK[cSrcPtr[3]]; break; #endif } - if (destAlphaPtr) { - *destAlphaPtr++ = 255; - } + aResult = 255; } else { // if (noTransparency && !blendFunc) @@ -516,17 +494,42 @@ void Splash::pipeRun(SplashPipe *pipe, int x0, int x1, int y, aDest = 0xff; } - //----- overprint + //----- read source color; handle overprint - for (i = 0; i < bitmapComps; ++i) { + switch (bitmap->mode) { + case splashModeMono1: + case splashModeMono8: + cSrc[0] = state->grayTransfer[cSrcPtr[0]]; + break; + case splashModeRGB8: + case splashModeBGR8: + cSrc[0] = state->rgbTransferR[cSrcPtr[0]]; + cSrc[1] = state->rgbTransferG[cSrcPtr[1]]; + cSrc[2] = state->rgbTransferB[cSrcPtr[2]]; + break; #if SPLASH_CMYK - if (state->overprintMask & (1 << i)) { - cSrc[i] = cSrcPtr[i]; + case splashModeCMYK8: + if (state->overprintMask & 0x01) { + cSrc[0] = state->cmykTransferC[cSrcPtr[0]]; } else { - cSrc[i] = div255(aDest * cDest[i]); + cSrc[0] = div255(aDest * cDest[0]); } -#else - cSrc[i] = cSrcPtr[i]; + if (state->overprintMask & 0x02) { + cSrc[1] = state->cmykTransferM[cSrcPtr[1]]; + } else { + cSrc[1] = div255(aDest * cDest[1]); + } + if (state->overprintMask & 0x04) { + cSrc[2] = state->cmykTransferY[cSrcPtr[2]]; + } else { + cSrc[2] = div255(aDest * cDest[2]); + } + if (state->overprintMask & 0x08) { + cSrc[3] = state->cmykTransferK[cSrcPtr[3]]; + } else { + cSrc[3] = div255(aDest * cDest[3]); + } + break; #endif } @@ -629,32 +632,22 @@ void Splash::pipeRun(SplashPipe *pipe, int x0, int x1, int y, //----- result color - cResult0 = cResult1 = cResult2 = cResult3 = 0; // make gcc happy - switch (pipe->resultColorCtrl) { case splashPipeResultColorNoAlphaBlendMono: - cResult0 = state->grayTransfer[div255((255 - aDest) * cSrc[0] + - aDest * cBlend[0])]; + cResult0 = div255((255 - aDest) * cSrc[0] + aDest * cBlend[0]); break; case splashPipeResultColorNoAlphaBlendRGB: - cResult0 = state->rgbTransferR[div255((255 - aDest) * cSrc[0] + - aDest * cBlend[0])]; - cResult1 = state->rgbTransferG[div255((255 - aDest) * cSrc[1] + - aDest * cBlend[1])]; - cResult2 = state->rgbTransferB[div255((255 - aDest) * cSrc[2] + - aDest * cBlend[2])]; + cResult0 = div255((255 - aDest) * cSrc[0] + aDest * cBlend[0]); + cResult1 = div255((255 - aDest) * cSrc[1] + aDest * cBlend[1]); + cResult2 = div255((255 - aDest) * cSrc[2] + aDest * cBlend[2]); break; #if SPLASH_CMYK case splashPipeResultColorNoAlphaBlendCMYK: - cResult0 = state->cmykTransferC[div255((255 - aDest) * cSrc[0] + - aDest * cBlend[0])]; - cResult1 = state->cmykTransferM[div255((255 - aDest) * cSrc[1] + - aDest * cBlend[1])]; - cResult2 = state->cmykTransferY[div255((255 - aDest) * cSrc[2] + - aDest * cBlend[2])]; - cResult3 = state->cmykTransferK[div255((255 - aDest) * cSrc[3] + - aDest * cBlend[3])]; + cResult0 = div255((255 - aDest) * cSrc[0] + aDest * cBlend[0]); + cResult1 = div255((255 - aDest) * cSrc[1] + aDest * cBlend[1]); + cResult2 = div255((255 - aDest) * cSrc[2] + aDest * cBlend[2]); + cResult3 = div255((255 - aDest) * cSrc[3] + aDest * cBlend[3]); break; #endif @@ -662,8 +655,7 @@ void Splash::pipeRun(SplashPipe *pipe, int x0, int x1, int y, if (alphaI == 0) { cResult0 = 0; } else { - cResult0 = state->grayTransfer[((alphaI - aSrc) * cDest[0] + - aSrc * cSrc[0]) / alphaI]; + cResult0 = ((alphaI - aSrc) * cDest[0] + aSrc * cSrc[0]) / alphaI; } break; case splashPipeResultColorAlphaNoBlendRGB: @@ -672,12 +664,9 @@ void Splash::pipeRun(SplashPipe *pipe, int x0, int x1, int y, cResult1 = 0; cResult2 = 0; } else { - cResult0 = state->rgbTransferR[((alphaI - aSrc) * cDest[0] + - aSrc * cSrc[0]) / alphaI]; - cResult1 = state->rgbTransferG[((alphaI - aSrc) * cDest[1] + - aSrc * cSrc[1]) / alphaI]; - cResult2 = state->rgbTransferB[((alphaI - aSrc) * cDest[2] + - aSrc * cSrc[2]) / alphaI]; + cResult0 = ((alphaI - aSrc) * cDest[0] + aSrc * cSrc[0]) / alphaI; + cResult1 = ((alphaI - aSrc) * cDest[1] + aSrc * cSrc[1]) / alphaI; + cResult2 = ((alphaI - aSrc) * cDest[2] + aSrc * cSrc[2]) / alphaI; } break; #if SPLASH_CMYK @@ -688,14 +677,10 @@ void Splash::pipeRun(SplashPipe *pipe, int x0, int x1, int y, cResult2 = 0; cResult3 = 0; } else { - cResult0 = state->cmykTransferC[((alphaI - aSrc) * cDest[0] + - aSrc * cSrc[0]) / alphaI]; - cResult1 = state->cmykTransferM[((alphaI - aSrc) * cDest[1] + - aSrc * cSrc[1]) / alphaI]; - cResult2 = state->cmykTransferY[((alphaI - aSrc) * cDest[2] + - aSrc * cSrc[2]) / alphaI]; - cResult3 = state->cmykTransferK[((alphaI - aSrc) * cDest[3] + - aSrc * cSrc[3]) / alphaI]; + cResult0 = ((alphaI - aSrc) * cDest[0] + aSrc * cSrc[0]) / alphaI; + cResult1 = ((alphaI - aSrc) * cDest[1] + aSrc * cSrc[1]) / alphaI; + cResult2 = ((alphaI - aSrc) * cDest[2] + aSrc * cSrc[2]) / alphaI; + cResult3 = ((alphaI - aSrc) * cDest[3] + aSrc * cSrc[3]) / alphaI; } break; #endif @@ -704,10 +689,10 @@ void Splash::pipeRun(SplashPipe *pipe, int x0, int x1, int y, if (alphaI == 0) { cResult0 = 0; } else { - cResult0 = state->grayTransfer[((alphaI - aSrc) * cDest[0] + - aSrc * ((255 - alphaIm1) * cSrc[0] + - alphaIm1 * cBlend[0]) / 255) / - alphaI]; + cResult0 = ((alphaI - aSrc) * cDest[0] + + aSrc * ((255 - alphaIm1) * cSrc[0] + + alphaIm1 * cBlend[0]) / 255) + / alphaI; } break; case splashPipeResultColorAlphaBlendRGB: @@ -716,18 +701,18 @@ void Splash::pipeRun(SplashPipe *pipe, int x0, int x1, int y, cResult1 = 0; cResult2 = 0; } else { - cResult0 = state->rgbTransferR[((alphaI - aSrc) * cDest[0] + - aSrc * ((255 - alphaIm1) * cSrc[0] + - alphaIm1 * cBlend[0]) / 255) / - alphaI]; - cResult1 = state->rgbTransferG[((alphaI - aSrc) * cDest[1] + - aSrc * ((255 - alphaIm1) * cSrc[1] + - alphaIm1 * cBlend[1]) / 255) / - alphaI]; - cResult2 = state->rgbTransferB[((alphaI - aSrc) * cDest[2] + - aSrc * ((255 - alphaIm1) * cSrc[2] + - alphaIm1 * cBlend[2]) / 255) / - alphaI]; + cResult0 = ((alphaI - aSrc) * cDest[0] + + aSrc * ((255 - alphaIm1) * cSrc[0] + + alphaIm1 * cBlend[0]) / 255) + / alphaI; + cResult1 = ((alphaI - aSrc) * cDest[1] + + aSrc * ((255 - alphaIm1) * cSrc[1] + + alphaIm1 * cBlend[1]) / 255) + / alphaI; + cResult2 = ((alphaI - aSrc) * cDest[2] + + aSrc * ((255 - alphaIm1) * cSrc[2] + + alphaIm1 * cBlend[2]) / 255) + / alphaI; } break; #if SPLASH_CMYK @@ -738,73 +723,69 @@ void Splash::pipeRun(SplashPipe *pipe, int x0, int x1, int y, cResult2 = 0; cResult3 = 0; } else { - cResult0 = - state->cmykTransferC[((alphaI - aSrc) * cDest[0] + - aSrc * ((255 - alphaIm1) * cSrc[0] + - alphaIm1 * cBlend[0]) / 255) / - alphaI]; - cResult1 = - state->cmykTransferM[((alphaI - aSrc) * cDest[1] + - aSrc * ((255 - alphaIm1) * cSrc[1] + - alphaIm1 * cBlend[1]) / 255) / - alphaI]; - cResult2 = - state->cmykTransferY[((alphaI - aSrc) * cDest[2] + - aSrc * ((255 - alphaIm1) * cSrc[2] + - alphaIm1 * cBlend[2]) / 255) / - alphaI]; - cResult3 = - state->cmykTransferK[((alphaI - aSrc) * cDest[3] + - aSrc * ((255 - alphaIm1) * cSrc[3] + - alphaIm1 * cBlend[3]) / 255) / - alphaI]; + cResult0 = ((alphaI - aSrc) * cDest[0] + + aSrc * ((255 - alphaIm1) * cSrc[0] + + alphaIm1 * cBlend[0]) / 255) + / alphaI; + cResult1 = ((alphaI - aSrc) * cDest[1] + + aSrc * ((255 - alphaIm1) * cSrc[1] + + alphaIm1 * cBlend[1]) / 255) + / alphaI; + cResult2 = ((alphaI - aSrc) * cDest[2] + + aSrc * ((255 - alphaIm1) * cSrc[2] + + alphaIm1 * cBlend[2]) / 255) + / alphaI; + cResult3 = ((alphaI - aSrc) * cDest[3] + + aSrc * ((255 - alphaIm1) * cSrc[3] + + alphaIm1 * cBlend[3]) / 255) + / alphaI; } break; #endif } - //----- write destination pixel + } // if (noTransparency && !blendFunc) - switch (bitmap->mode) { - case splashModeMono1: - if (state->screen->test(x, y, cResult0)) { - *destColorPtr |= destColorMask; - } else { - *destColorPtr &= ~destColorMask; - } - destColorPtr += destColorMask & 1; - destColorMask = (destColorMask << 7) | (destColorMask >> 1); - break; - case splashModeMono8: - *destColorPtr++ = cResult0; - break; - case splashModeRGB8: - destColorPtr[0] = cResult0; - destColorPtr[1] = cResult1; - destColorPtr[2] = cResult2; - destColorPtr += 3; - break; - case splashModeBGR8: - destColorPtr[0] = cResult2; - destColorPtr[1] = cResult1; - destColorPtr[2] = cResult0; - destColorPtr += 3; - break; + //----- write destination pixel + + switch (bitmap->mode) { + case splashModeMono1: + if (state->screen->test(x, y, cResult0)) { + *destColorPtr |= destColorMask; + } else { + *destColorPtr &= ~destColorMask; + } + destColorPtr += destColorMask & 1; + destColorMask = (destColorMask << 7) | (destColorMask >> 1); + break; + case splashModeMono8: + *destColorPtr++ = cResult0; + break; + case splashModeRGB8: + destColorPtr[0] = cResult0; + destColorPtr[1] = cResult1; + destColorPtr[2] = cResult2; + destColorPtr += 3; + break; + case splashModeBGR8: + destColorPtr[0] = cResult2; + destColorPtr[1] = cResult1; + destColorPtr[2] = cResult0; + destColorPtr += 3; + break; #if SPLASH_CMYK - case splashModeCMYK8: - destColorPtr[0] = cResult0; - destColorPtr[1] = cResult1; - destColorPtr[2] = cResult2; - destColorPtr[3] = cResult3; - destColorPtr += 4; - break; + case splashModeCMYK8: + destColorPtr[0] = cResult0; + destColorPtr[1] = cResult1; + destColorPtr[2] = cResult2; + destColorPtr[3] = cResult3; + destColorPtr += 4; + break; #endif - } - if (destAlphaPtr) { - *destAlphaPtr++ = aResult; - } - - } // if (noTransparency && !blendFunc) + } + if (destAlphaPtr) { + *destAlphaPtr++ = aResult; + } cSrcPtr += cSrcStride; shapePtr2 += shapeStride; @@ -821,6 +802,7 @@ void Splash::pipeRunSimpleMono1(SplashPipe *pipe, int x0, int x1, int y, Guchar cResult0; SplashColorPtr destColorPtr; Guchar destColorMask; + SplashScreenCursor screenCursor; int cSrcStride, x; if (cSrcPtr) { @@ -839,11 +821,13 @@ void Splash::pipeRunSimpleMono1(SplashPipe *pipe, int x0, int x1, int y, destColorPtr = &bitmap->data[y * bitmap->rowSize + (x0 >> 3)]; destColorMask = 0x80 >> (x0 & 7); + screenCursor = state->screen->getTestCursor(y); + for (x = x0; x <= x1; ++x) { //----- write destination pixel cResult0 = state->grayTransfer[cSrcPtr[0]]; - if (state->screen->test(x, y, cResult0)) { + if (state->screen->testWithCursor(screenCursor, x, cResult0)) { *destColorPtr |= destColorMask; } else { *destColorPtr &= ~destColorMask; @@ -1013,9 +997,10 @@ void Splash::pipeRunSimpleCMYK8(SplashPipe *pipe, int x0, int x1, int y, // bitmap->mode == splashModeMono1 && !bitmap->alpha void Splash::pipeRunShapeMono1(SplashPipe *pipe, int x0, int x1, int y, Guchar *shapePtr, SplashColorPtr cSrcPtr) { - Guchar shape, aSrc, cDest0, cResult0; + Guchar shape, aSrc, cSrc0, cDest0, cResult0; SplashColorPtr destColorPtr; Guchar destColorMask; + SplashScreenCursor screenCursor; int cSrcStride, x, lastX; if (cSrcPtr) { @@ -1041,6 +1026,8 @@ void Splash::pipeRunShapeMono1(SplashPipe *pipe, int x0, int x1, int y, destColorPtr = &bitmap->data[y * bitmap->rowSize + (x0 >> 3)]; destColorMask = 0x80 >> (x0 & 7); + screenCursor = state->screen->getTestCursor(y); + for (x = x0; x <= x1; ++x) { //----- shape @@ -1054,19 +1041,27 @@ void Splash::pipeRunShapeMono1(SplashPipe *pipe, int x0, int x1, int y, } lastX = x; - //----- read destination pixel - cDest0 = (*destColorPtr & destColorMask) ? 0xff : 0x00; + //----- source color + cSrc0 = state->grayTransfer[cSrcPtr[0]]; //----- source alpha aSrc = shape; - //----- result color - // note: aDest = alphaI = aResult = 0xff - cResult0 = state->grayTransfer[(Guchar)div255((0xff - aSrc) * cDest0 + - aSrc * cSrcPtr[0])]; + //----- special case for aSrc = 255 + if (aSrc == 255) { + cResult0 = cSrc0; + } else { + + //----- read destination pixel + cDest0 = (*destColorPtr & destColorMask) ? 0xff : 0x00; + + //----- result color + // note: aDest = alphaI = aResult = 0xff + cResult0 = (Guchar)div255((0xff - aSrc) * cDest0 + aSrc * cSrc0); + } //----- write destination pixel - if (state->screen->test(x, y, cResult0)) { + if (state->screen->testWithCursor(screenCursor, x, cResult0)) { *destColorPtr |= destColorMask; } else { *destColorPtr &= ~destColorMask; @@ -1086,7 +1081,7 @@ void Splash::pipeRunShapeMono1(SplashPipe *pipe, int x0, int x1, int y, // bitmap->mode == splashModeMono8 && bitmap->alpha void Splash::pipeRunShapeMono8(SplashPipe *pipe, int x0, int x1, int y, Guchar *shapePtr, SplashColorPtr cSrcPtr) { - Guchar shape, aSrc, aDest, alphaI, aResult, cDest0, cResult0; + Guchar shape, aSrc, aDest, alphaI, aResult, cSrc0, cDest0, cResult0; SplashColorPtr destColorPtr; Guchar *destAlphaPtr; int cSrcStride, x, lastX; @@ -1127,23 +1122,37 @@ void Splash::pipeRunShapeMono8(SplashPipe *pipe, int x0, int x1, int y, } lastX = x; - //----- read destination pixel - cDest0 = *destColorPtr; - aDest = *destAlphaPtr; + //----- source color + cSrc0 = state->grayTransfer[cSrcPtr[0]]; //----- source alpha aSrc = shape; - //----- result alpha and non-isolated group element correction - aResult = aSrc + aDest - div255(aSrc * aDest); - alphaI = aResult; - - //----- result color - if (alphaI == 0) { - cResult0 = 0; + //----- special case for aSrc = 255 + if (aSrc == 255) { + aResult = 255; + cResult0 = cSrc0; } else { - cResult0 = state->grayTransfer[(Guchar)(((alphaI - aSrc) * cDest0 + - aSrc * cSrcPtr[0]) / alphaI)]; + + //----- read destination alpha + aDest = *destAlphaPtr; + + //----- special case for aDest = 0 + if (aDest == 0) { + aResult = aSrc; + cResult0 = cSrc0; + } else { + + //----- read destination pixel + cDest0 = *destColorPtr; + + //----- result alpha and non-isolated group element correction + aResult = aSrc + aDest - div255(aSrc * aDest); + alphaI = aResult; + + //----- result color + cResult0 = (Guchar)(((alphaI - aSrc) * cDest0 + aSrc * cSrc0) / alphaI); + } } //----- write destination pixel @@ -1163,6 +1172,7 @@ void Splash::pipeRunShapeMono8(SplashPipe *pipe, int x0, int x1, int y, void Splash::pipeRunShapeRGB8(SplashPipe *pipe, int x0, int x1, int y, Guchar *shapePtr, SplashColorPtr cSrcPtr) { Guchar shape, aSrc, aDest, alphaI, aResult; + Guchar cSrc0, cSrc1, cSrc2; Guchar cDest0, cDest1, cDest2; Guchar cResult0, cResult1, cResult2; SplashColorPtr destColorPtr; @@ -1205,31 +1215,47 @@ void Splash::pipeRunShapeRGB8(SplashPipe *pipe, int x0, int x1, int y, } lastX = x; - //----- read destination pixel - cDest0 = destColorPtr[0]; - cDest1 = destColorPtr[1]; - cDest2 = destColorPtr[2]; - aDest = *destAlphaPtr; + //----- source color + cSrc0 = state->rgbTransferR[cSrcPtr[0]]; + cSrc1 = state->rgbTransferG[cSrcPtr[1]]; + cSrc2 = state->rgbTransferB[cSrcPtr[2]]; //----- source alpha aSrc = shape; - //----- result alpha and non-isolated group element correction - aResult = aSrc + aDest - div255(aSrc * aDest); - alphaI = aResult; - - //----- result color - if (alphaI == 0) { - cResult0 = 0; - cResult1 = 0; - cResult2 = 0; + //----- special case for aSrc = 255 + if (aSrc == 255) { + aResult = 255; + cResult0 = cSrc0; + cResult1 = cSrc1; + cResult2 = cSrc2; } else { - cResult0 = state->rgbTransferR[(Guchar)(((alphaI - aSrc) * cDest0 + - aSrc * cSrcPtr[0]) / alphaI)]; - cResult1 = state->rgbTransferG[(Guchar)(((alphaI - aSrc) * cDest1 + - aSrc * cSrcPtr[1]) / alphaI)]; - cResult2 = state->rgbTransferB[(Guchar)(((alphaI - aSrc) * cDest2 + - aSrc * cSrcPtr[2]) / alphaI)]; + + //----- read destination alpha + aDest = *destAlphaPtr; + + //----- special case for aDest = 0 + if (aDest == 0) { + aResult = aSrc; + cResult0 = cSrc0; + cResult1 = cSrc1; + cResult2 = cSrc2; + } else { + + //----- read destination pixel + cDest0 = destColorPtr[0]; + cDest1 = destColorPtr[1]; + cDest2 = destColorPtr[2]; + + //----- result alpha and non-isolated group element correction + aResult = aSrc + aDest - div255(aSrc * aDest); + alphaI = aResult; + + //----- result color + cResult0 = (Guchar)(((alphaI - aSrc) * cDest0 + aSrc * cSrc0) / alphaI); + cResult1 = (Guchar)(((alphaI - aSrc) * cDest1 + aSrc * cSrc1) / alphaI); + cResult2 = (Guchar)(((alphaI - aSrc) * cDest2 + aSrc * cSrc2) / alphaI); + } } //----- write destination pixel @@ -1252,6 +1278,7 @@ void Splash::pipeRunShapeRGB8(SplashPipe *pipe, int x0, int x1, int y, void Splash::pipeRunShapeBGR8(SplashPipe *pipe, int x0, int x1, int y, Guchar *shapePtr, SplashColorPtr cSrcPtr) { Guchar shape, aSrc, aDest, alphaI, aResult; + Guchar cSrc0, cSrc1, cSrc2; Guchar cDest0, cDest1, cDest2; Guchar cResult0, cResult1, cResult2; SplashColorPtr destColorPtr; @@ -1294,31 +1321,47 @@ void Splash::pipeRunShapeBGR8(SplashPipe *pipe, int x0, int x1, int y, } lastX = x; - //----- read destination pixel - cDest0 = destColorPtr[2]; - cDest1 = destColorPtr[1]; - cDest2 = destColorPtr[0]; - aDest = *destAlphaPtr; + //----- source color + cSrc0 = state->rgbTransferR[cSrcPtr[0]]; + cSrc1 = state->rgbTransferG[cSrcPtr[1]]; + cSrc2 = state->rgbTransferB[cSrcPtr[2]]; //----- source alpha aSrc = shape; - //----- result alpha and non-isolated group element correction - aResult = aSrc + aDest - div255(aSrc * aDest); - alphaI = aResult; - - //----- result color - if (alphaI == 0) { - cResult0 = 0; - cResult1 = 0; - cResult2 = 0; + //----- special case for aSrc = 255 + if (aSrc == 255) { + aResult = 255; + cResult0 = cSrc0; + cResult1 = cSrc1; + cResult2 = cSrc2; } else { - cResult0 = state->rgbTransferR[(Guchar)(((alphaI - aSrc) * cDest0 + - aSrc * cSrcPtr[0]) / alphaI)]; - cResult1 = state->rgbTransferG[(Guchar)(((alphaI - aSrc) * cDest1 + - aSrc * cSrcPtr[1]) / alphaI)]; - cResult2 = state->rgbTransferB[(Guchar)(((alphaI - aSrc) * cDest2 + - aSrc * cSrcPtr[2]) / alphaI)]; + + //----- read destination alpha + aDest = *destAlphaPtr; + + //----- special case for aDest = 0 + if (aDest == 0) { + aResult = aSrc; + cResult0 = cSrc0; + cResult1 = cSrc1; + cResult2 = cSrc2; + } else { + + //----- read destination pixel + cDest0 = destColorPtr[2]; + cDest1 = destColorPtr[1]; + cDest2 = destColorPtr[0]; + + //----- result alpha and non-isolated group element correction + aResult = aSrc + aDest - div255(aSrc * aDest); + alphaI = aResult; + + //----- result color + cResult0 = (Guchar)(((alphaI - aSrc) * cDest0 + aSrc * cSrc0) / alphaI); + cResult1 = (Guchar)(((alphaI - aSrc) * cDest1 + aSrc * cSrc1) / alphaI); + cResult2 = (Guchar)(((alphaI - aSrc) * cDest2 + aSrc * cSrc2) / alphaI); + } } //----- write destination pixel @@ -1394,22 +1437,22 @@ void Splash::pipeRunShapeCMYK8(SplashPipe *pipe, int x0, int x1, int y, //----- overprint if (state->overprintMask & 1) { - cSrc0 = cSrcPtr[0]; + cSrc0 = state->cmykTransferC[cSrcPtr[0]]; } else { cSrc0 = div255(aDest * cDest0); } if (state->overprintMask & 2) { - cSrc1 = cSrcPtr[1]; + cSrc1 = state->cmykTransferM[cSrcPtr[1]]; } else { cSrc1 = div255(aDest * cDest1); } if (state->overprintMask & 4) { - cSrc2 = cSrcPtr[2]; + cSrc2 = state->cmykTransferY[cSrcPtr[2]]; } else { cSrc2 = div255(aDest * cDest2); } if (state->overprintMask & 8) { - cSrc3 = cSrcPtr[3]; + cSrc3 = state->cmykTransferK[cSrcPtr[3]]; } else { cSrc3 = div255(aDest * cDest3); } @@ -1417,25 +1460,34 @@ void Splash::pipeRunShapeCMYK8(SplashPipe *pipe, int x0, int x1, int y, //----- source alpha aSrc = shape; - //----- result alpha and non-isolated group element correction - aResult = aSrc + aDest - div255(aSrc * aDest); - alphaI = aResult; - - //----- result color - if (alphaI == 0) { - cResult0 = 0; - cResult1 = 0; - cResult2 = 0; - cResult3 = 0; + //----- special case for aSrc = 255 + if (aSrc == 255) { + aResult = 255; + cResult0 = cSrc0; + cResult1 = cSrc1; + cResult2 = cSrc2; + cResult3 = cSrc3; } else { - cResult0 = state->cmykTransferC[(Guchar)(((alphaI - aSrc) * cDest0 + - aSrc * cSrc0) / alphaI)]; - cResult1 = state->cmykTransferM[(Guchar)(((alphaI - aSrc) * cDest1 + - aSrc * cSrc1) / alphaI)]; - cResult2 = state->cmykTransferY[(Guchar)(((alphaI - aSrc) * cDest2 + - aSrc * cSrc2) / alphaI)]; - cResult3 = state->cmykTransferK[(Guchar)(((alphaI - aSrc) * cDest3 + - aSrc * cSrc3) / alphaI)]; + + //----- special case for aDest = 0 + if (aDest == 0) { + aResult = aSrc; + cResult0 = cSrc0; + cResult1 = cSrc1; + cResult2 = cSrc2; + cResult3 = cSrc3; + } else { + + //----- result alpha and non-isolated group element correction + aResult = aSrc + aDest - div255(aSrc * aDest); + alphaI = aResult; + + //----- result color + cResult0 = (Guchar)(((alphaI - aSrc) * cDest0 + aSrc * cSrc0) / alphaI); + cResult1 = (Guchar)(((alphaI - aSrc) * cDest1 + aSrc * cSrc1) / alphaI); + cResult2 = (Guchar)(((alphaI - aSrc) * cDest2 + aSrc * cSrc2) / alphaI); + cResult3 = (Guchar)(((alphaI - aSrc) * cDest3 + aSrc * cSrc3) / alphaI); + } } //----- write destination pixel @@ -1462,9 +1514,10 @@ void Splash::pipeRunShapeCMYK8(SplashPipe *pipe, int x0, int x1, int y, // bitmap->mode == splashModeMono1 && !bitmap->alpha void Splash::pipeRunAAMono1(SplashPipe *pipe, int x0, int x1, int y, Guchar *shapePtr, SplashColorPtr cSrcPtr) { - Guchar shape, aSrc, cDest0, cResult0; + Guchar shape, aSrc, cSrc0, cDest0, cResult0; SplashColorPtr destColorPtr; Guchar destColorMask; + SplashScreenCursor screenCursor; int cSrcStride, x, lastX; if (cSrcPtr) { @@ -1490,6 +1543,8 @@ void Splash::pipeRunAAMono1(SplashPipe *pipe, int x0, int x1, int y, destColorPtr = &bitmap->data[y * bitmap->rowSize + (x0 >> 3)]; destColorMask = 0x80 >> (x0 & 7); + screenCursor = state->screen->getTestCursor(y); + for (x = x0; x <= x1; ++x) { //----- shape @@ -1506,16 +1561,18 @@ void Splash::pipeRunAAMono1(SplashPipe *pipe, int x0, int x1, int y, //----- read destination pixel cDest0 = (*destColorPtr & destColorMask) ? 0xff : 0x00; + //----- source color + cSrc0 = state->grayTransfer[cSrcPtr[0]]; + //----- source alpha aSrc = div255(pipe->aInput * shape); //----- result color // note: aDest = alphaI = aResult = 0xff - cResult0 = state->grayTransfer[(Guchar)div255((0xff - aSrc) * cDest0 + - aSrc * cSrcPtr[0])]; + cResult0 = (Guchar)div255((0xff - aSrc) * cDest0 + aSrc * cSrc0); //----- write destination pixel - if (state->screen->test(x, y, cResult0)) { + if (state->screen->testWithCursor(screenCursor, x, cResult0)) { *destColorPtr |= destColorMask; } else { *destColorPtr &= ~destColorMask; @@ -1537,7 +1594,7 @@ void Splash::pipeRunAAMono1(SplashPipe *pipe, int x0, int x1, int y, // bitmap->mode == splashModeMono8 && bitmap->alpha void Splash::pipeRunAAMono8(SplashPipe *pipe, int x0, int x1, int y, Guchar *shapePtr, SplashColorPtr cSrcPtr) { - Guchar shape, aSrc, aDest, alphaI, aResult, cDest0, cResult0; + Guchar shape, aSrc, aDest, alphaI, aResult, cSrc0, cDest0, cResult0; SplashColorPtr destColorPtr; Guchar *destAlphaPtr; int cSrcStride, x, lastX; @@ -1582,6 +1639,9 @@ void Splash::pipeRunAAMono8(SplashPipe *pipe, int x0, int x1, int y, cDest0 = *destColorPtr; aDest = *destAlphaPtr; + //----- source color + cSrc0 = state->grayTransfer[cSrcPtr[0]]; + //----- source alpha aSrc = div255(pipe->aInput * shape); @@ -1593,8 +1653,7 @@ void Splash::pipeRunAAMono8(SplashPipe *pipe, int x0, int x1, int y, if (alphaI == 0) { cResult0 = 0; } else { - cResult0 = state->grayTransfer[(Guchar)(((alphaI - aSrc) * cDest0 + - aSrc * cSrcPtr[0]) / alphaI)]; + cResult0 = (Guchar)(((alphaI - aSrc) * cDest0 + aSrc * cSrc0) / alphaI); } //----- write destination pixel @@ -1616,6 +1675,7 @@ void Splash::pipeRunAAMono8(SplashPipe *pipe, int x0, int x1, int y, void Splash::pipeRunAARGB8(SplashPipe *pipe, int x0, int x1, int y, Guchar *shapePtr, SplashColorPtr cSrcPtr) { Guchar shape, aSrc, aDest, alphaI, aResult; + Guchar cSrc0, cSrc1, cSrc2; Guchar cDest0, cDest1, cDest2; Guchar cResult0, cResult1, cResult2; SplashColorPtr destColorPtr; @@ -1664,6 +1724,11 @@ void Splash::pipeRunAARGB8(SplashPipe *pipe, int x0, int x1, int y, cDest2 = destColorPtr[2]; aDest = *destAlphaPtr; + //----- source color + cSrc0 = state->rgbTransferR[cSrcPtr[0]]; + cSrc1 = state->rgbTransferG[cSrcPtr[1]]; + cSrc2 = state->rgbTransferB[cSrcPtr[2]]; + //----- source alpha aSrc = div255(pipe->aInput * shape); @@ -1677,12 +1742,9 @@ void Splash::pipeRunAARGB8(SplashPipe *pipe, int x0, int x1, int y, cResult1 = 0; cResult2 = 0; } else { - cResult0 = state->rgbTransferR[(Guchar)(((alphaI - aSrc) * cDest0 + - aSrc * cSrcPtr[0]) / alphaI)]; - cResult1 = state->rgbTransferG[(Guchar)(((alphaI - aSrc) * cDest1 + - aSrc * cSrcPtr[1]) / alphaI)]; - cResult2 = state->rgbTransferB[(Guchar)(((alphaI - aSrc) * cDest2 + - aSrc * cSrcPtr[2]) / alphaI)]; + cResult0 = (Guchar)(((alphaI - aSrc) * cDest0 + aSrc * cSrc0) / alphaI); + cResult1 = (Guchar)(((alphaI - aSrc) * cDest1 + aSrc * cSrc1) / alphaI); + cResult2 = (Guchar)(((alphaI - aSrc) * cDest2 + aSrc * cSrc2) / alphaI); } //----- write destination pixel @@ -1707,6 +1769,7 @@ void Splash::pipeRunAARGB8(SplashPipe *pipe, int x0, int x1, int y, void Splash::pipeRunAABGR8(SplashPipe *pipe, int x0, int x1, int y, Guchar *shapePtr, SplashColorPtr cSrcPtr) { Guchar shape, aSrc, aDest, alphaI, aResult; + Guchar cSrc0, cSrc1, cSrc2; Guchar cDest0, cDest1, cDest2; Guchar cResult0, cResult1, cResult2; SplashColorPtr destColorPtr; @@ -1755,6 +1818,11 @@ void Splash::pipeRunAABGR8(SplashPipe *pipe, int x0, int x1, int y, cDest2 = destColorPtr[0]; aDest = *destAlphaPtr; + //----- source color + cSrc0 = state->rgbTransferR[cSrcPtr[0]]; + cSrc1 = state->rgbTransferG[cSrcPtr[1]]; + cSrc2 = state->rgbTransferB[cSrcPtr[2]]; + //----- source alpha aSrc = div255(pipe->aInput * shape); @@ -1768,12 +1836,9 @@ void Splash::pipeRunAABGR8(SplashPipe *pipe, int x0, int x1, int y, cResult1 = 0; cResult2 = 0; } else { - cResult0 = state->rgbTransferR[(Guchar)(((alphaI - aSrc) * cDest0 + - aSrc * cSrcPtr[0]) / alphaI)]; - cResult1 = state->rgbTransferG[(Guchar)(((alphaI - aSrc) * cDest1 + - aSrc * cSrcPtr[1]) / alphaI)]; - cResult2 = state->rgbTransferB[(Guchar)(((alphaI - aSrc) * cDest2 + - aSrc * cSrcPtr[2]) / alphaI)]; + cResult0 = (Guchar)(((alphaI - aSrc) * cDest0 + aSrc * cSrc0) / alphaI); + cResult1 = (Guchar)(((alphaI - aSrc) * cDest1 + aSrc * cSrc1) / alphaI); + cResult2 = (Guchar)(((alphaI - aSrc) * cDest2 + aSrc * cSrc2) / alphaI); } //----- write destination pixel @@ -1851,22 +1916,22 @@ void Splash::pipeRunAACMYK8(SplashPipe *pipe, int x0, int x1, int y, //----- overprint if (state->overprintMask & 1) { - cSrc0 = cSrcPtr[0]; + cSrc0 = state->cmykTransferC[cSrcPtr[0]]; } else { cSrc0 = div255(aDest * cDest0); } if (state->overprintMask & 2) { - cSrc1 = cSrcPtr[1]; + cSrc1 = state->cmykTransferM[cSrcPtr[1]]; } else { cSrc1 = div255(aDest * cDest1); } if (state->overprintMask & 4) { - cSrc2 = cSrcPtr[2]; + cSrc2 = state->cmykTransferY[cSrcPtr[2]]; } else { cSrc2 = div255(aDest * cDest2); } if (state->overprintMask & 8) { - cSrc3 = cSrcPtr[3]; + cSrc3 = state->cmykTransferK[cSrcPtr[3]]; } else { cSrc3 = div255(aDest * cDest3); } @@ -1885,14 +1950,10 @@ void Splash::pipeRunAACMYK8(SplashPipe *pipe, int x0, int x1, int y, cResult2 = 0; cResult3 = 0; } else { - cResult0 = state->cmykTransferC[(Guchar)(((alphaI - aSrc) * cDest0 + - aSrc * cSrc0) / alphaI)]; - cResult1 = state->cmykTransferM[(Guchar)(((alphaI - aSrc) * cDest1 + - aSrc * cSrc1) / alphaI)]; - cResult2 = state->cmykTransferY[(Guchar)(((alphaI - aSrc) * cDest2 + - aSrc * cSrc2) / alphaI)]; - cResult3 = state->cmykTransferK[(Guchar)(((alphaI - aSrc) * cDest3 + - aSrc * cSrc3) / alphaI)]; + cResult0 = (Guchar)(((alphaI - aSrc) * cDest0 + aSrc * cSrc0) / alphaI); + cResult1 = (Guchar)(((alphaI - aSrc) * cDest1 + aSrc * cSrc1) / alphaI); + cResult2 = (Guchar)(((alphaI - aSrc) * cDest2 + aSrc * cSrc2) / alphaI); + cResult3 = (Guchar)(((alphaI - aSrc) * cDest3 + aSrc * cSrc3) / alphaI); } //----- write destination pixel @@ -1931,8 +1992,6 @@ inline void Splash::transform(SplashCoord *matrix, Splash::Splash(SplashBitmap *bitmapA, GBool vectorAntialiasA, SplashScreenParams *screenParams) { - int i; - bitmap = bitmapA; bitmapComps = splashColorModeNComps[bitmap->mode]; vectorAntialias = vectorAntialiasA; @@ -1940,13 +1999,12 @@ Splash::Splash(SplashBitmap *bitmapA, GBool vectorAntialiasA, state = new SplashState(bitmap->width, bitmap->height, vectorAntialias, screenParams); scanBuf = (Guchar *)gmalloc(bitmap->width); - if (vectorAntialias) { - for (i = 0; i <= 255; ++i) { - aaGamma[i] = (Guchar)splashRound( - splashPow((SplashCoord)i / (SplashCoord)255, - splashAAGamma) * 255); - } + if (bitmap->mode == splashModeMono1) { + scanBuf2 = (Guchar *)gmalloc(bitmap->width); + } else { + scanBuf2 = NULL; } + groupBackBitmap = NULL; minLineWidth = 0; clearModRegion(); debugMode = gFalse; @@ -1954,8 +2012,6 @@ Splash::Splash(SplashBitmap *bitmapA, GBool vectorAntialiasA, Splash::Splash(SplashBitmap *bitmapA, GBool vectorAntialiasA, SplashScreen *screenA) { - int i; - bitmap = bitmapA; bitmapComps = splashColorModeNComps[bitmap->mode]; vectorAntialias = vectorAntialiasA; @@ -1963,13 +2019,12 @@ Splash::Splash(SplashBitmap *bitmapA, GBool vectorAntialiasA, state = new SplashState(bitmap->width, bitmap->height, vectorAntialias, screenA); scanBuf = (Guchar *)gmalloc(bitmap->width); - if (vectorAntialias) { - for (i = 0; i <= 255; ++i) { - aaGamma[i] = (Guchar)splashRound( - splashPow((SplashCoord)i / (SplashCoord)255, - splashAAGamma) * 255); - } + if (bitmap->mode == splashModeMono1) { + scanBuf2 = (Guchar *)gmalloc(bitmap->width); + } else { + scanBuf2 = NULL; } + groupBackBitmap = NULL; minLineWidth = 0; clearModRegion(); debugMode = gFalse; @@ -1981,6 +2036,7 @@ Splash::~Splash() { } delete state; gfree(scanBuf); + gfree(scanBuf2); } //------------------------------------------------------------------------ @@ -2047,7 +2103,7 @@ SplashCoord Splash::getLineDashPhase() { return state->lineDashPhase; } -GBool Splash::getStrokeAdjust() { +SplashStrokeAdjustMode Splash::getStrokeAdjust() { return state->strokeAdjust; } @@ -2128,7 +2184,7 @@ void Splash::setLineDash(SplashCoord *lineDash, int lineDashLength, state->setLineDash(lineDash, lineDashLength, lineDashPhase); } -void Splash::setStrokeAdjust(GBool strokeAdjust) { +void Splash::setStrokeAdjust(SplashStrokeAdjustMode strokeAdjust) { state->strokeAdjust = strokeAdjust; } @@ -2169,6 +2225,10 @@ void Splash::setOverprintMask(Guint overprintMask) { state->overprintMask = overprintMask; } +void Splash::setEnablePathSimplification(GBool en) { + state->enablePathSimplification = en; +} + //------------------------------------------------------------------------ // state save/restore //------------------------------------------------------------------------ @@ -2300,7 +2360,8 @@ void Splash::clear(SplashColorPtr color, Guchar alpha) { SplashError Splash::stroke(SplashPath *path) { SplashPath *path2, *dPath; - SplashCoord t0, t1, t2, t3, w, w2; + SplashCoord t0, t1, t2, t3, w, w2, lineDashMax, lineDashTotal; + int lineCap, lineJoin, i; if (debugMode) { printf("stroke [dash:%d] [width:%.2f]:\n", @@ -2312,15 +2373,6 @@ SplashError Splash::stroke(SplashPath *path) { return splashErrEmptyPath; } path2 = flattenPath(path, state->matrix, state->flatness); - if (state->lineDashLength > 0) { - dPath = makeDashedPath(path2); - delete path2; - path2 = dPath; - if (path2->length == 0) { - delete path2; - return splashErrEmptyPath; - } - } // Compute an approximation of the transformed line width. // Given a CTM of [m0 m1], @@ -2341,10 +2393,62 @@ SplashError Splash::stroke(SplashPath *path) { w = (t1 < t2) ? t1 : t2; } w2 = w * state->lineWidth; + + // construct the dashed path + if (state->lineDashLength > 0) { + + // check the maximum transformed dash element length (using the + // same approximation as for line width) -- if it's less than 0.1 + // pixel, don't apply the dash pattern; this avoids a huge + // performance/memory hit with PDF files that use absurd dash + // patterns like [0.0007 0.0003] + lineDashTotal = 0; + lineDashMax = 0; + for (i = 0; i < state->lineDashLength; ++i) { + lineDashTotal += state->lineDash[i]; + if (state->lineDash[i] > lineDashMax) { + lineDashMax = state->lineDash[i]; + } + } + // Acrobat simply draws nothing if the dash array is [0] + if (lineDashTotal == 0) { + delete path2; + return splashOk; + } + if (w * lineDashMax > 0.1) { + + dPath = makeDashedPath(path2); + delete path2; + path2 = dPath; + if (path2->length == 0) { + delete path2; + return splashErrEmptyPath; + } + } + } + + // round caps on narrow lines look bad, and can't be + // stroke-adjusted, so use projecting caps instead (but we can't do + // this if there are zero-length dashes or segments, because those + // turn into round dots) + lineCap = state->lineCap; + lineJoin = state->lineJoin; + if (state->strokeAdjust == splashStrokeAdjustCAD && + w2 < 3.5) { + if (lineCap == splashLineCapRound && + !state->lineDashContainsZeroLengthDashes() && + !path->containsZeroLengthSubpaths()) { + lineCap = splashLineCapProjecting; + } + if (lineJoin == splashLineJoinRound) { + lineJoin = splashLineJoinBevel; + } + } + // if there is a min line width set, and the transformed line width // is smaller, use the min line width if (w > 0 && w2 < minLineWidth) { - strokeWide(path2, minLineWidth / w); + strokeWide(path2, minLineWidth / w, splashLineCapButt, splashLineJoinBevel); } else if (bitmap->mode == splashModeMono1) { // in monochrome mode, use 0-width lines for any transformed line // width <= 1 -- lines less than 1 pixel wide look too fat without @@ -2352,7 +2456,7 @@ SplashError Splash::stroke(SplashPath *path) { if (w2 < 1.001) { strokeNarrow(path2); } else { - strokeWide(path2, state->lineWidth); + strokeWide(path2, state->lineWidth, lineCap, lineJoin); } } else { // in gray and color modes, only use 0-width lines if the line @@ -2360,7 +2464,7 @@ SplashError Splash::stroke(SplashPath *path) { if (state->lineWidth == 0) { strokeNarrow(path2); } else { - strokeWide(path2, state->lineWidth); + strokeWide(path2, state->lineWidth, lineCap, lineJoin); } } @@ -2380,7 +2484,9 @@ void Splash::strokeNarrow(SplashPath *path) { nClipRes[0] = nClipRes[1] = nClipRes[2] = 0; - xPath = new SplashXPath(path, state->matrix, state->flatness, gFalse); + xPath = new SplashXPath(path, state->matrix, state->flatness, gFalse, + state->enablePathSimplification, + state->strokeAdjust); pipeInit(&pipe, state->strokePattern, (Guchar)splashRound(state->strokeAlpha * 255), @@ -2497,10 +2603,11 @@ void Splash::drawStrokeSpan(SplashPipe *pipe, int x0, int x1, int y, (this->*pipe->run)(pipe, x0, x1, y, scanBuf + x0, NULL); } -void Splash::strokeWide(SplashPath *path, SplashCoord w) { +void Splash::strokeWide(SplashPath *path, SplashCoord w, + int lineCap, int lineJoin) { SplashPath *path2; - path2 = makeStrokePath(path, w, gFalse); + path2 = makeStrokePath(path, w, lineCap, lineJoin, gFalse); fillWithPattern(path2, gFalse, state->strokePattern, state->strokeAlpha); delete path2; } @@ -2636,8 +2743,8 @@ SplashPath *Splash::makeDashedPath(SplashPath *path) { SplashCoord lineDashTotal; SplashCoord lineDashStartPhase, lineDashDist, segLen; SplashCoord x0, y0, x1, y1, xa, ya; - GBool lineDashStartOn, lineDashOn, newPath; - int lineDashStartIdx, lineDashIdx; + GBool lineDashStartOn, lineDashEndOn, lineDashOn, newPath; + int lineDashStartIdx, lineDashIdx, subpathStart, nDashes; int i, j, k; lineDashTotal = 0; @@ -2649,6 +2756,13 @@ SplashPath *Splash::makeDashedPath(SplashPath *path) { return new SplashPath(); } lineDashStartPhase = state->lineDashPhase; + if (lineDashStartPhase > lineDashTotal * 2) { + i = splashFloor(lineDashStartPhase / (lineDashTotal * 2)); + lineDashStartPhase -= lineDashTotal * i * 2; + } else if (lineDashStartPhase < 0) { + i = splashCeil(-lineDashStartPhase / (lineDashTotal * 2)); + lineDashStartPhase += lineDashTotal * i * 2; + } i = splashFloor(lineDashStartPhase / lineDashTotal); lineDashStartPhase -= (SplashCoord)i * lineDashTotal; lineDashStartOn = gTrue; @@ -2657,7 +2771,9 @@ SplashPath *Splash::makeDashedPath(SplashPath *path) { while (lineDashStartPhase >= state->lineDash[lineDashStartIdx]) { lineDashStartOn = !lineDashStartOn; lineDashStartPhase -= state->lineDash[lineDashStartIdx]; - ++lineDashStartIdx; + if (++lineDashStartIdx == state->lineDashLength) { + lineDashStartIdx = 0; + } } } @@ -2674,8 +2790,11 @@ SplashPath *Splash::makeDashedPath(SplashPath *path) { // initialize the dash parameters lineDashOn = lineDashStartOn; + lineDashEndOn = lineDashStartOn; lineDashIdx = lineDashStartIdx; lineDashDist = state->lineDash[lineDashIdx] - lineDashStartPhase; + subpathStart = dPath->length; + nDashes = 0; // process each segment of the subpath newPath = gTrue; @@ -2691,11 +2810,31 @@ SplashPath *Splash::makeDashedPath(SplashPath *path) { // process the segment while (segLen > 0) { - if (lineDashDist >= segLen) { + // Special case for zero-length dash segments: draw a very + // short -- but not zero-length -- segment. This ensures that + // we get the correct behavior with butt and projecting line + // caps. The PS/PDF specs imply that zero-length segments are + // not drawn unless the line cap is round, but Acrobat and + // Ghostscript both draw very short segments (for butt caps) + // and squares (for projecting caps). + if (lineDashDist == 0) { if (lineDashOn) { if (newPath) { dPath->moveTo(x0, y0); newPath = gFalse; + ++nDashes; + } + xa = x0 + ((SplashCoord)0.001 / segLen) * (x1 - x0); + ya = y0 + ((SplashCoord)0.001 / segLen) * (y1 - y0); + dPath->lineTo(xa, ya); + } + + } else if (lineDashDist >= segLen) { + if (lineDashOn) { + if (newPath) { + dPath->moveTo(x0, y0); + newPath = gFalse; + ++nDashes; } dPath->lineTo(x1, y1); } @@ -2709,6 +2848,7 @@ SplashPath *Splash::makeDashedPath(SplashPath *path) { if (newPath) { dPath->moveTo(x0, y0); newPath = gFalse; + ++nDashes; } dPath->lineTo(xa, ya); } @@ -2718,6 +2858,8 @@ SplashPath *Splash::makeDashedPath(SplashPath *path) { lineDashDist = 0; } + lineDashEndOn = lineDashOn; + // get the next entry in the dash array if (lineDashDist <= 0) { lineDashOn = !lineDashOn; @@ -2729,6 +2871,31 @@ SplashPath *Splash::makeDashedPath(SplashPath *path) { } } } + + // in a closed subpath, where the dash pattern is "on" at both the + // start and end of the subpath, we need to merge the start and + // end to get a proper line join + if ((path->flags[j] & splashPathClosed) && + lineDashStartOn && + lineDashEndOn) { + if (nDashes == 1) { + dPath->close(); + } else if (nDashes > 1) { + k = subpathStart; + do { + ++k; + dPath->lineTo(dPath->pts[k].x, dPath->pts[k].y); + } while (!(dPath->flags[k] & splashPathLast)); + ++k; + memmove(&dPath->pts[subpathStart], &dPath->pts[k], + (dPath->length - k) * sizeof(SplashPathPoint)); + memmove(&dPath->flags[subpathStart], &dPath->flags[k], + (dPath->length - k) * sizeof(Guchar)); + dPath->length -= k - subpathStart; + dPath->curSubpath -= k - subpathStart; + } + } + i = j + 1; } @@ -2750,7 +2917,7 @@ SplashError Splash::fillWithPattern(SplashPath *path, GBool eo, SplashPath *path2; SplashXPath *xPath; SplashXPathScanner *scanner; - int xMin, yMin, xMax, yMax, x, y, t; + int xMin, yMin, xMax, xMin2, xMax2, yMax, y, t; SplashClipResult clipRes; if (path->length == 0) { @@ -2763,7 +2930,9 @@ SplashError Splash::fillWithPattern(SplashPath *path, GBool eo, path2 = tweakFillPath(path); - xPath = new SplashXPath(path2, state->matrix, state->flatness, gTrue); + xPath = new SplashXPath(path2, state->matrix, state->flatness, gTrue, + state->enablePathSimplification, + state->strokeAdjust); if (path2 != path) { delete path2; } @@ -2806,23 +2975,25 @@ SplashError Splash::fillWithPattern(SplashPath *path, GBool eo, // draw the spans if (vectorAntialias && !inShading) { for (y = yMin; y <= yMax; ++y) { - scanner->getSpan(scanBuf, y, xMin, xMax); - if (clipRes != splashClipAllInside) { - state->clip->clipSpan(scanBuf, y, xMin, xMax, state->strokeAdjust); - } - for (x = xMin; x <= xMax; ++x) { - scanBuf[x] = aaGamma[scanBuf[x]]; + scanner->getSpan(scanBuf, y, xMin, xMax, &xMin2, &xMax2); + if (xMin2 <= xMax2) { + if (clipRes != splashClipAllInside) { + state->clip->clipSpan(scanBuf, y, xMin2, xMax2, + state->strokeAdjust); + } + (this->*pipe.run)(&pipe, xMin2, xMax2, y, scanBuf + xMin2, NULL); } - (this->*pipe.run)(&pipe, xMin, xMax, y, scanBuf + xMin, NULL); } } else { for (y = yMin; y <= yMax; ++y) { - scanner->getSpanBinary(scanBuf, y, xMin, xMax); - if (clipRes != splashClipAllInside) { - state->clip->clipSpanBinary(scanBuf, y, xMin, xMax, - state->strokeAdjust); + scanner->getSpanBinary(scanBuf, y, xMin, xMax, &xMin2, &xMax2); + if (xMin2 <= xMax2) { + if (clipRes != splashClipAllInside) { + state->clip->clipSpanBinary(scanBuf, y, xMin2, xMax2, + state->strokeAdjust); + } + (this->*pipe.run)(&pipe, xMin2, xMax2, y, scanBuf + xMin2, NULL); } - (this->*pipe.run)(&pipe, xMin, xMax, y, scanBuf + xMin, NULL); } } } @@ -2849,7 +3020,7 @@ SplashPath *Splash::tweakFillPath(SplashPath *path) { SplashCoord xx0, yy0, xx1, yy1, dx, dy, d, wx, wy, w; int n; - if (!state->strokeAdjust || path->hints) { + if (state->strokeAdjust == splashStrokeAdjustOff || path->hints) { return path; } @@ -2887,7 +3058,7 @@ SplashPath *Splash::tweakFillPath(SplashPath *path) { splashAbs(path->pts[1].y - path->pts[2].y) < 0.001)))) { wx = state->matrix[0] + state->matrix[2]; wy = state->matrix[1] + state->matrix[3]; - w = sqrt(wx*wx + wy*wy); + w = splashSqrt(wx*wx + wy*wy); if (w < 0.001) { w = 0; } else { @@ -2905,7 +3076,7 @@ SplashPath *Splash::tweakFillPath(SplashPath *path) { } dx = xx1 - xx0; dy = yy1 - yy0; - d = sqrt(dx * dx + dy * dy); + d = splashSqrt(dx * dx + dy * dy); if (d < 0.001) { d = 0; } else { @@ -2995,6 +3166,10 @@ GBool Splash::pathAllOutside(SplashPath *path) { } else if (y > yMax2) { yMax2 = y; } + // sanity-check the coordinates - xMinI/yMinI/xMaxI/yMaxI are + // 32-bit integers, so coords need to be < 2^31 + SplashXPath::clampCoords(&xMin2, &yMin2); + SplashXPath::clampCoords(&xMax2, &yMax2); xMinI = splashFloor(xMin2); yMinI = splashFloor(yMin2); xMaxI = splashFloor(xMax2); @@ -3005,77 +3180,6 @@ GBool Splash::pathAllOutside(SplashPath *path) { splashClipAllOutside; } -SplashError Splash::xorFill(SplashPath *path, GBool eo) { - SplashPipe pipe; - SplashXPath *xPath; - SplashXPathScanner *scanner; - int xMin, yMin, xMax, yMax, y, t; - SplashClipResult clipRes; - SplashBlendFunc origBlendFunc; - - if (path->length == 0) { - return splashErrEmptyPath; - } - if (pathAllOutside(path)) { - opClipRes = splashClipAllOutside; - return splashOk; - } - xPath = new SplashXPath(path, state->matrix, state->flatness, gTrue); - xMin = xPath->getXMin(); - yMin = xPath->getYMin(); - xMax = xPath->getXMax(); - yMax = xPath->getYMax(); - if (xMin > xMax || yMin > yMax) { - delete xPath; - return splashOk; - } - scanner = new SplashXPathScanner(xPath, eo, yMin, yMax); - - // check clipping - if ((clipRes = state->clip->testRect(xMin, yMin, xMax, yMax, - state->strokeAdjust)) - != splashClipAllOutside) { - - if ((t = state->clip->getXMinI(state->strokeAdjust)) > xMin) { - xMin = t; - } - if ((t = state->clip->getXMaxI(state->strokeAdjust)) < xMax) { - xMax = t; - } - if ((t = state->clip->getYMinI(state->strokeAdjust)) > yMin) { - yMin = t; - } - if ((t = state->clip->getYMaxI(state->strokeAdjust)) < yMax) { - yMax = t; - } - if (xMin > xMax || yMin > yMax) { - delete scanner; - delete xPath; - return splashOk; - } - - origBlendFunc = state->blendFunc; - state->blendFunc = &blendXor; - pipeInit(&pipe, state->fillPattern, 255, gTrue, gFalse); - - // draw the spans - for (y = yMin; y <= yMax; ++y) { - scanner->getSpanBinary(scanBuf, y, xMin, xMax); - if (clipRes != splashClipAllInside) { - state->clip->clipSpanBinary(scanBuf, y, xMin, xMax, - state->strokeAdjust); - } - (this->*pipe.run)(&pipe, xMin, xMax, y, scanBuf + xMin, NULL); - } - state->blendFunc = origBlendFunc; - } - opClipRes = clipRes; - - delete scanner; - delete xPath; - return splashOk; -} - SplashError Splash::fillChar(SplashCoord x, SplashCoord y, int c, SplashFont *font) { SplashGlyphBitmap glyph; @@ -3208,14 +3312,14 @@ SplashError Splash::fillGlyph2(int x0, int y0, SplashGlyphBitmap *glyph) { void Splash::getImageBounds(SplashCoord xyMin, SplashCoord xyMax, int *xyMinI, int *xyMaxI) { - if (state->strokeAdjust) { - splashStrokeAdjust(xyMin, xyMax, xyMinI, xyMaxI); - } else { + if (state->strokeAdjust == splashStrokeAdjustOff) { *xyMinI = splashFloor(xyMin); *xyMaxI = splashFloor(xyMax); if (*xyMaxI <= *xyMinI) { *xyMaxI = *xyMinI + 1; } + } else { + splashStrokeAdjust(xyMin, xyMax, xyMinI, xyMaxI, state->strokeAdjust); } } @@ -3254,8 +3358,14 @@ SplashError Splash::fillImageMask(SplashImageMaskSource src, void *srcData, // stream-mode upscaling -- this is slower, so we only use it if the // upscaled mask is large (in which case clipping should remove many // pixels) - if (wSize > 2 * w && hSize > 2 * h && wSize * hSize > 1000000) { +#if USE_FIXEDPOINT + if ((wSize > 2 * w && hSize > 2 * h && (int)wSize > 1000000 / (int)hSize) || + (wSize > w && hSize > h && (int)wSize > 10000000 / (int)hSize)) { +#else + if ((wSize > 2 * w && hSize > 2 * h && wSize * hSize > 1000000) || + (wSize > w && hSize > h && wSize * hSize > 10000000)) { upscaleMask(src, srcData, w, h, mat, glyphMode, interpolate); +#endif // scaling only } else if (mat[0] > 0 && minorAxisZero && mat[3] > 0) { @@ -3462,10 +3572,12 @@ void Splash::upscaleMask(SplashImageMaskSource src, void *srcData, if (y1 >= srcHeight) { y1 = srcHeight - 1; } - pix0 = ((SplashCoord)1 - sx) * unscaledImage[y0 * srcWidth + x0] - + sx * unscaledImage[y0 * srcWidth + x1]; - pix1 = ((SplashCoord)1 - sx) * unscaledImage[y1 * srcWidth + x0] - + sx * unscaledImage[y1 * srcWidth + x1]; + pix0 = ((SplashCoord)1 - sx) + * (SplashCoord)unscaledImage[y0 * srcWidth + x0] + + sx * (SplashCoord)unscaledImage[y0 * srcWidth + x1]; + pix1 = ((SplashCoord)1 - sx) + * (SplashCoord)unscaledImage[y1 * srcWidth + x0] + + sx * (SplashCoord)unscaledImage[y1 * srcWidth + x1]; scanBuf[x] = (Guchar)splashRound(((SplashCoord)1 - sy) * pix0 + sy * pix1); } else { @@ -4041,10 +4153,10 @@ void Splash::scaleMaskYuXu(SplashImageMaskSource src, void *srcData, int scaledWidth, int scaledHeight, SplashBitmap *dest) { Guchar *lineBuf; - Guint pix; - Guchar *destPtr0, *destPtr; - int yp, yq, xp, xq, yt, y, yStep, xt, x, xStep, xx; - int i, j; + Guchar pix; + Guchar *srcPtr, *destPtr; + int yp, yq, xp, xq, yt, y, yStep, xt, x, xStep; + int i; // Bresenham parameters for y scale yp = scaledHeight / srcHeight; @@ -4060,7 +4172,7 @@ void Splash::scaleMaskYuXu(SplashImageMaskSource src, void *srcData, // init y scale Bresenham yt = 0; - destPtr0 = dest->data; + destPtr = dest->data; for (y = 0; y < srcHeight; ++y) { // y scale Bresenham @@ -4077,7 +4189,8 @@ void Splash::scaleMaskYuXu(SplashImageMaskSource src, void *srcData, // init x scale Bresenham xt = 0; - xx = 0; + // generate one row + srcPtr = lineBuf; for (x = 0; x < srcWidth; ++x) { // x scale Bresenham @@ -4089,20 +4202,20 @@ void Splash::scaleMaskYuXu(SplashImageMaskSource src, void *srcData, } // compute the final pixel - pix = lineBuf[x] ? 255 : 0; + pix = *srcPtr ? 255 : 0; + ++srcPtr; - // store the pixel - for (i = 0; i < yStep; ++i) { - for (j = 0; j < xStep; ++j) { - destPtr = destPtr0 + i * scaledWidth + xx + j; - *destPtr++ = (Guchar)pix; - } + // duplicate the pixel horizontally + for (i = 0; i < xStep; ++i) { + *destPtr++ = pix; } - - xx += xStep; } - destPtr0 += yStep * scaledWidth; + // duplicate the row vertically + for (i = 1 ; i < yStep; ++i) { + memcpy(destPtr, destPtr - scaledWidth, scaledWidth); + destPtr += scaledWidth; + } } gfree(lineBuf); @@ -4149,11 +4262,11 @@ void Splash::scaleMaskYuXuI(SplashImageMaskSource src, void *srcData, xSrc1 = srcWidth - 1; } lineBuf0[x] = (Guchar)(int) - ((xs * lineBuf0[xSrc0] + - ((SplashCoord)1 - xs) * lineBuf0[xSrc1]) * 255); + ((xs * (int)lineBuf0[xSrc0] + + ((SplashCoord)1 - xs) * (int)lineBuf0[xSrc1]) * 255); lineBuf1[x] = (Guchar)(int) - ((xs * lineBuf1[xSrc0] + - ((SplashCoord)1 - xs) * lineBuf1[xSrc1]) * 255); + ((xs * (int)lineBuf1[xSrc0] + + ((SplashCoord)1 - xs) * (int)lineBuf1[xSrc1]) * 255); } destPtr = dest->data; @@ -4193,8 +4306,8 @@ void Splash::scaleMaskYuXuI(SplashImageMaskSource src, void *srcData, xSrc1 = srcWidth - 1; } lineBuf1[x] = (Guchar)(int) - ((xs * lineBuf1[xSrc0] + - ((SplashCoord)1 - xs) * lineBuf1[xSrc1]) * 255); + ((xs * (int)lineBuf1[xSrc0] + + ((SplashCoord)1 - xs) * (int)lineBuf1[xSrc1]) * 255); } ++yBuf; @@ -4203,8 +4316,8 @@ void Splash::scaleMaskYuXuI(SplashImageMaskSource src, void *srcData, // do the vertical interpolation for (x = 0; x < scaledWidth; ++x) { - pix = (Guchar)(int)(ys * lineBuf0[x] + - ((SplashCoord)1 - ys) * lineBuf1[x]); + pix = (Guchar)(int)(ys * (int)lineBuf0[x] + + ((SplashCoord)1 - ys) * (int)lineBuf1[x]); // store the pixel *destPtr++ = pix; @@ -4329,7 +4442,13 @@ SplashError Splash::drawImage(SplashImageSource src, void *srcData, // stream-mode upscaling -- this is slower, so we only use it if the // upscaled image is large (in which case clipping should remove // many pixels) - if (wSize > 2 * w && hSize > 2 * h && wSize * hSize > 1000000) { +#if USE_FIXEDPOINT + if ((wSize > 2 * w && hSize > 2 * h && (int)wSize > 1000000 / (int)hSize) || + (wSize > w && hSize > h && (int)wSize > 10000000 / (int)hSize)) { +#else + if ((wSize > 2 * w && hSize > 2 * h && wSize * hSize > 1000000) || + (wSize > w && hSize > h && wSize * hSize > 10000000)) { +#endif upscaleImage(src, srcData, srcMode, nComps, srcAlpha, w, h, mat, interpolate); @@ -4367,7 +4486,7 @@ SplashError Splash::drawImage(SplashImageSource src, void *srcData, } // scaling plus horizontal flip - } else if (mat[0] > 0 && minorAxisZero && mat[3] > 0) { + } else if (mat[0] < 0 && minorAxisZero && mat[3] > 0) { getImageBounds(mat[0] + mat[4], mat[4], &x0, &x1); getImageBounds(mat[5], mat[3] + mat[5], &y0, &y1); clipRes = state->clip->testRect(x0, y0, x1 - 1, y1 - 1, @@ -4384,7 +4503,7 @@ SplashError Splash::drawImage(SplashImageSource src, void *srcData, } // scaling plus horizontal and vertical flips - } else if (mat[0] > 0 && minorAxisZero && mat[3] < 0) { + } else if (mat[0] < 0 && minorAxisZero && mat[3] < 0) { getImageBounds(mat[0] + mat[4], mat[4], &x0, &x1); getImageBounds(mat[3] + mat[5], mat[5], &y0, &y1); clipRes = state->clip->testRect(x0, y0, x1 - 1, y1 - 1, @@ -4557,16 +4676,18 @@ void Splash::upscaleImage(SplashImageSource src, void *srcData, q10 = &unscaledImage[(y1 * srcWidth + x0) * nComps]; q11 = &unscaledImage[(y1 * srcWidth + x1) * nComps]; for (i = 0; i < nComps; ++i) { - pix0 = ((SplashCoord)1 - sx) * *q00++ + sx * *q01++; - pix1 = ((SplashCoord)1 - sx) * *q10++ + sx * *q11++; + pix0 = ((SplashCoord)1 - sx) * (int)*q00++ + sx * (int)*q01++; + pix1 = ((SplashCoord)1 - sx) * (int)*q10++ + sx * (int)*q11++; *p++ = (Guchar)splashRound(((SplashCoord)1 - sy) * pix0 + sy * pix1); } if (srcAlpha) { - pix0 = ((SplashCoord)1 - sx) * unscaledAlpha[y0 * srcWidth + x0] - + sx * unscaledAlpha[y0 * srcWidth + x1]; - pix1 = ((SplashCoord)1 - sx) * unscaledAlpha[y1 * srcWidth + x0] - + sx * unscaledAlpha[y1 * srcWidth + x1]; + pix0 = ((SplashCoord)1 - sx) + * (SplashCoord)unscaledAlpha[y0 * srcWidth + x0] + + sx * (SplashCoord)unscaledAlpha[y0 * srcWidth + x1]; + pix1 = ((SplashCoord)1 - sx) + * (SplashCoord)unscaledAlpha[y1 * srcWidth + x0] + + sx * (SplashCoord)unscaledAlpha[y1 * srcWidth + x1]; scanBuf[x] = (Guchar)splashRound(((SplashCoord)1 - sy) * pix0 + sy * pix1); } else { @@ -5139,6 +5260,12 @@ void Splash::scaleImageYdXu(SplashImageSource src, void *srcData, alphaPixBuf = NULL; } + // make gcc happy + pix[0] = pix[1] = pix[2] = 0; +#if SPLASH_CMYK + pix[3] = 0; +#endif + // init y scale Bresenham yt = 0; @@ -5266,6 +5393,12 @@ void Splash::scaleImageYuXd(SplashImageSource src, void *srcData, alphaLineBuf = NULL; } + // make gcc happy + pix[0] = pix[1] = pix[2] = 0; +#if SPLASH_CMYK + pix[3] = 0; +#endif + // init y scale Bresenham yt = 0; @@ -5380,11 +5513,15 @@ void Splash::scaleImageYuXu(SplashImageSource src, void *srcData, int scaledWidth, int scaledHeight, SplashBitmap *dest) { Guchar *lineBuf, *alphaLineBuf; - Guint pix[splashMaxColorComps]; + Guchar pix0, pix1, pix2; +#if SPLASH_CMYK + Guchar pix3; +#endif Guint alpha; - Guchar *destPtr0, *destPtr, *destAlphaPtr0, *destAlphaPtr; - int yp, yq, xp, xq, yt, y, yStep, xt, x, xStep, xx; - int i, j; + Guchar *srcPtr, *srcAlphaPtr; + Guchar *destPtr, *destAlphaPtr; + int yp, yq, xp, xq, yt, y, yStep, xt, x, xStep; + int i; // Bresenham parameters for y scale yp = scaledHeight / srcHeight; @@ -5405,8 +5542,8 @@ void Splash::scaleImageYuXu(SplashImageSource src, void *srcData, // init y scale Bresenham yt = 0; - destPtr0 = dest->data; - destAlphaPtr0 = dest->alpha; + destPtr = dest->data; + destAlphaPtr = dest->alpha; for (y = 0; y < srcHeight; ++y) { // y scale Bresenham @@ -5423,7 +5560,9 @@ void Splash::scaleImageYuXu(SplashImageSource src, void *srcData, // init x scale Bresenham xt = 0; - xx = 0; + // generate one row + srcPtr = lineBuf; + srcAlphaPtr = alphaLineBuf; for (x = 0; x < srcWidth; ++x) { // x scale Bresenham @@ -5434,41 +5573,35 @@ void Splash::scaleImageYuXu(SplashImageSource src, void *srcData, xStep = xp; } - // compute the final pixel - for (i = 0; i < nComps; ++i) { - pix[i] = lineBuf[x * nComps + i]; - } - - // store the pixel + // duplicate the pixel horizontally switch (srcMode) { case splashModeMono8: - for (i = 0; i < yStep; ++i) { - for (j = 0; j < xStep; ++j) { - destPtr = destPtr0 + (i * scaledWidth + xx + j) * nComps; - *destPtr++ = (Guchar)pix[0]; - } + pix0 = *srcPtr++; + for (i = 0; i < xStep; ++i) { + *destPtr++ = pix0; } break; case splashModeRGB8: - for (i = 0; i < yStep; ++i) { - for (j = 0; j < xStep; ++j) { - destPtr = destPtr0 + (i * scaledWidth + xx + j) * nComps; - *destPtr++ = (Guchar)pix[0]; - *destPtr++ = (Guchar)pix[1]; - *destPtr++ = (Guchar)pix[2]; - } + pix0 = *srcPtr++; + pix1 = *srcPtr++; + pix2 = *srcPtr++; + for (i = 0; i < xStep; ++i) { + *destPtr++ = pix0; + *destPtr++ = pix1; + *destPtr++ = pix2; } break; #if SPLASH_CMYK case splashModeCMYK8: - for (i = 0; i < yStep; ++i) { - for (j = 0; j < xStep; ++j) { - destPtr = destPtr0 + (i * scaledWidth + xx + j) * nComps; - *destPtr++ = (Guchar)pix[0]; - *destPtr++ = (Guchar)pix[1]; - *destPtr++ = (Guchar)pix[2]; - *destPtr++ = (Guchar)pix[3]; - } + pix0 = *srcPtr++; + pix1 = *srcPtr++; + pix2 = *srcPtr++; + pix3 = *srcPtr++; + for (i = 0; i < xStep; ++i) { + *destPtr++ = pix0; + *destPtr++ = pix1; + *destPtr++ = pix2; + *destPtr++ = pix3; } break; #endif @@ -5478,23 +5611,26 @@ void Splash::scaleImageYuXu(SplashImageSource src, void *srcData, break; } - // process alpha + // duplicate the alpha value horizontally if (srcAlpha) { - alpha = alphaLineBuf[x]; - for (i = 0; i < yStep; ++i) { - for (j = 0; j < xStep; ++j) { - destAlphaPtr = destAlphaPtr0 + i * scaledWidth + xx + j; - *destAlphaPtr = (Guchar)alpha; - } + alpha = *srcAlphaPtr++; + for (i = 0; i < xStep; ++i) { + *destAlphaPtr++ = alpha; } } - - xx += xStep; } - destPtr0 += yStep * scaledWidth * nComps; + // duplicate the row vertically + for (i = 1; i < yStep; ++i) { + memcpy(destPtr, destPtr - scaledWidth * nComps, + scaledWidth * nComps); + destPtr += scaledWidth * nComps; + } if (srcAlpha) { - destAlphaPtr0 += yStep * scaledWidth; + for (i = 1; i < yStep; ++i) { + memcpy(destAlphaPtr, destAlphaPtr - scaledWidth, scaledWidth); + destAlphaPtr += scaledWidth; + } } } @@ -5555,22 +5691,28 @@ void Splash::scaleImageYuXuI(SplashImageSource src, void *srcData, } for (i = 0; i < nComps; ++i) { lineBuf0[x*nComps+i] = (Guchar)(int) - (xs * lineBuf0[xSrc0*nComps+i] + - ((SplashCoord)1 - xs) * lineBuf0[xSrc1*nComps+i]); + (xs * (int)lineBuf0[xSrc0*nComps+i] + + ((SplashCoord)1 - xs) * (int)lineBuf0[xSrc1*nComps+i]); lineBuf1[x*nComps+i] = (Guchar)(int) - (xs * lineBuf1[xSrc0*nComps+i] + - ((SplashCoord)1 - xs) * lineBuf1[xSrc1*nComps+i]); + (xs * (int)lineBuf1[xSrc0*nComps+i] + + ((SplashCoord)1 - xs) * (int)lineBuf1[xSrc1*nComps+i]); } if (srcAlpha) { alphaLineBuf0[x] = (Guchar)(int) - (xs * alphaLineBuf0[xSrc0] + - ((SplashCoord)1 - xs) * alphaLineBuf0[xSrc1]); + (xs * (int)alphaLineBuf0[xSrc0] + + ((SplashCoord)1 - xs) * (int)alphaLineBuf0[xSrc1]); alphaLineBuf1[x] = (Guchar)(int) - (xs * alphaLineBuf1[xSrc0] + - ((SplashCoord)1 - xs) * alphaLineBuf1[xSrc1]); + (xs * (int)alphaLineBuf1[xSrc0] + + ((SplashCoord)1 - xs) * (int)alphaLineBuf1[xSrc1]); } } + // make gcc happy + pix[0] = pix[1] = pix[2] = 0; +#if SPLASH_CMYK + pix[3] = 0; +#endif + destPtr = dest->data; destAlphaPtr = dest->alpha; for (y = 0; y < scaledHeight; ++y) { @@ -5612,14 +5754,14 @@ void Splash::scaleImageYuXuI(SplashImageSource src, void *srcData, xSrc1 = srcWidth - 1; } for (i = 0; i < nComps; ++i) { - lineBuf1[x*nComps+i] = - (Guchar)(int)(xs * lineBuf1[xSrc0*nComps+i] + - ((SplashCoord)1 - xs) * lineBuf1[xSrc1*nComps+i]); + lineBuf1[x*nComps+i] = (Guchar)(int) + (xs * (int)lineBuf1[xSrc0*nComps+i] + + ((SplashCoord)1 - xs) * (int)lineBuf1[xSrc1*nComps+i]); } if (srcAlpha) { - alphaLineBuf1[x] = - (Guchar)(int)(xs * alphaLineBuf1[xSrc0] + - ((SplashCoord)1 - xs) * alphaLineBuf1[xSrc1]); + alphaLineBuf1[x] = (Guchar)(int) + (xs * (int)alphaLineBuf1[xSrc0] + + ((SplashCoord)1 - xs) * (int)alphaLineBuf1[xSrc1]); } } @@ -5630,8 +5772,9 @@ void Splash::scaleImageYuXuI(SplashImageSource src, void *srcData, for (x = 0; x < scaledWidth; ++x) { for (i = 0; i < nComps; ++i) { - pix[i] = (Guchar)(int)(ys * lineBuf0[x*nComps+i] + - ((SplashCoord)1 - ys) * lineBuf1[x*nComps+i]); + pix[i] = (Guchar)(int) + (ys * (int)lineBuf0[x*nComps+i] + + ((SplashCoord)1 - ys) * (int)lineBuf1[x*nComps+i]); } // store the pixel @@ -5661,8 +5804,8 @@ void Splash::scaleImageYuXuI(SplashImageSource src, void *srcData, // process alpha if (srcAlpha) { *destAlphaPtr++ = (Guchar)(int) - (ys * alphaLineBuf0[x] + - ((SplashCoord)1 - ys) * alphaLineBuf1[x]); + (ys * (int)alphaLineBuf0[x] + + ((SplashCoord)1 - ys) * (int)alphaLineBuf1[x]); } } } @@ -5878,82 +6021,287 @@ SplashError Splash::composite(SplashBitmap *src, int xSrc, int ySrc, int xDest, int yDest, int w, int h, GBool noClip, GBool nonIsolated) { SplashPipe pipe; - int x0, x1, y0, y1, y, t; + Guchar *mono1Ptr, *lineBuf, *linePtr; + Guchar mono1Mask, b; + int x0, x1, x, y0, y1, y, t; - if (src->mode != bitmap->mode) { + if (!(src->mode == bitmap->mode || + (src->mode == splashModeMono8 && bitmap->mode == splashModeMono1) || + (src->mode == splashModeRGB8 && bitmap->mode == splashModeBGR8))) { return splashErrModeMismatch; } pipeInit(&pipe, NULL, (Guchar)splashRound(state->fillAlpha * 255), !noClip || src->alpha != NULL, nonIsolated); - if (noClip) { - if (src->alpha) { - for (y = 0; y < h; ++y) { - // this uses shape instead of alpha, which isn't technically - // correct, but works out the same - (this->*pipe.run)(&pipe, xDest, xDest + w - 1, yDest + y, - src->getAlphaPtr() + - (ySrc + y) * src->getWidth() + xSrc, - src->getDataPtr() + (ySrc + y) * src->getRowSize() + - xSrc * bitmapComps); + if (src->mode == splashModeMono1) { + // in mono1 mode, pipeRun expects the source to be in mono8 + // format, so we need to extract the source color values into + // scanBuf, expanding them from mono1 to mono8 + if (noClip) { + if (src->alpha) { + for (y = 0; y < h; ++y) { + mono1Ptr = src->getDataPtr() + + (ySrc + y) * src->rowSize + (xSrc >> 3); + mono1Mask = 0x80 >> (xSrc & 7); + for (x = 0; x < w; ++x) { + scanBuf[x] = (*mono1Ptr & mono1Mask) ? 0xff : 0x00; + mono1Ptr += mono1Mask & 1; + mono1Mask = (mono1Mask << 7) | (mono1Mask >> 1); + } + // this uses shape instead of alpha, which isn't technically + // correct, but works out the same + (this->*pipe.run)(&pipe, xDest, xDest + w - 1, yDest + y, + src->getAlphaPtr() + + (ySrc + y) * src->getWidth() + xSrc, + scanBuf); + } + } else { + for (y = 0; y < h; ++y) { + mono1Ptr = src->getDataPtr() + + (ySrc + y) * src->rowSize + (xSrc >> 3); + mono1Mask = 0x80 >> (xSrc & 7); + for (x = 0; x < w; ++x) { + scanBuf[x] = (*mono1Ptr & mono1Mask) ? 0xff : 0x00; + mono1Ptr += mono1Mask & 1; + mono1Mask = (mono1Mask << 7) | (mono1Mask >> 1); + } + (this->*pipe.run)(&pipe, xDest, xDest + w - 1, yDest + y, + NULL, + scanBuf); + } } } else { - for (y = 0; y < h; ++y) { - (this->*pipe.run)(&pipe, xDest, xDest + w - 1, yDest + y, - NULL, - src->getDataPtr() + (ySrc + y) * src->getRowSize() + - xSrc * bitmapComps); + x0 = xDest; + if ((t = state->clip->getXMinI(state->strokeAdjust)) > x0) { + x0 = t; + } + x1 = xDest + w; + if ((t = state->clip->getXMaxI(state->strokeAdjust) + 1) < x1) { + x1 = t; + } + y0 = yDest; + if ((t = state->clip->getYMinI(state->strokeAdjust)) > y0) { + y0 = t; + } + y1 = yDest + h; + if ((t = state->clip->getYMaxI(state->strokeAdjust) + 1) < y1) { + y1 = t; + } + if (x0 < x1 && y0 < y1) { + if (src->alpha) { + for (y = y0; y < y1; ++y) { + mono1Ptr = src->getDataPtr() + + (ySrc + y - yDest) * src->rowSize + + ((xSrc + x0 - xDest) >> 3); + mono1Mask = 0x80 >> ((xSrc + x0 - xDest) & 7); + for (x = x0; x < x1; ++x) { + scanBuf[x] = (*mono1Ptr & mono1Mask) ? 0xff : 0x00; + mono1Ptr += mono1Mask & 1; + mono1Mask = (mono1Mask << 7) | (mono1Mask >> 1); + } + memcpy(scanBuf2 + x0, + src->getAlphaPtr() + (ySrc + y - yDest) * src->getWidth() + + (xSrc + x0 - xDest), + x1 - x0); + if (!state->clip->clipSpanBinary(scanBuf2, y, x0, x1 - 1, + state->strokeAdjust)) { + continue; + } + // this uses shape instead of alpha, which isn't technically + // correct, but works out the same + (this->*pipe.run)(&pipe, x0, x1 - 1, y, + scanBuf2 + x0, + scanBuf + x0); + } + } else { + for (y = y0; y < y1; ++y) { + mono1Ptr = src->getDataPtr() + + (ySrc + y - yDest) * src->rowSize + + ((xSrc + x0 - xDest) >> 3); + mono1Mask = 0x80 >> ((xSrc + x0 - xDest) & 7); + for (x = x0; x < x1; ++x) { + scanBuf[x] = (*mono1Ptr & mono1Mask) ? 0xff : 0x00; + mono1Ptr += mono1Mask & 1; + mono1Mask = (mono1Mask << 7) | (mono1Mask >> 1); + } + memset(scanBuf2 + x0, 0xff, x1 - x0); + if (!state->clip->clipSpanBinary(scanBuf2, y, x0, x1 - 1, + state->strokeAdjust)) { + continue; + } + (this->*pipe.run)(&pipe, x0, x1 - 1, y, + scanBuf2 + x0, + scanBuf + x0); + } + } } } - } else { - x0 = xDest; - if ((t = state->clip->getXMinI(state->strokeAdjust)) > x0) { - x0 = t; - } - x1 = xDest + w; - if ((t = state->clip->getXMaxI(state->strokeAdjust) + 1) < x1) { - x1 = t; - } - y0 = yDest; - if ((t = state->clip->getYMinI(state->strokeAdjust)) > y0) { - y0 = t; - } - y1 = yDest + h; - if ((t = state->clip->getYMaxI(state->strokeAdjust) + 1) < y1) { - y1 = t; - } - if (x0 < x1 && y0 < y1) { + + } else if (src->mode == splashModeBGR8) { + // in BGR8 mode, pipeRun expects the source to be in RGB8 format, + // so we need to swap bytes + lineBuf = (Guchar *)gmallocn(w, 3); + if (noClip) { if (src->alpha) { - for (y = y0; y < y1; ++y) { - memcpy(scanBuf + x0, - src->getAlphaPtr() + (ySrc + y - yDest) * src->getWidth() + - (xSrc + x0 - xDest), - x1 - x0); - if (!state->clip->clipSpanBinary(scanBuf, y, x0, x1 - 1, - state->strokeAdjust)) { - continue; + for (y = 0; y < h; ++y) { + memcpy(lineBuf, + src->getDataPtr() + (ySrc + y) * src->rowSize + xSrc * 3, + w * 3); + for (x = 0, linePtr = lineBuf; x < w; ++x, linePtr += 3) { + b = linePtr[0]; + linePtr[0] = linePtr[2]; + linePtr[2] = b; } // this uses shape instead of alpha, which isn't technically // correct, but works out the same - (this->*pipe.run)(&pipe, x0, x1 - 1, y, - scanBuf + x0, - src->getDataPtr() + - (ySrc + y - yDest) * src->getRowSize() + - (xSrc + x0 - xDest) * bitmapComps); + (this->*pipe.run)(&pipe, xDest, xDest + w - 1, yDest + y, + src->getAlphaPtr() + + (ySrc + y) * src->getWidth() + xSrc, + lineBuf); } } else { - for (y = y0; y < y1; ++y) { - memset(scanBuf + x0, 0xff, x1 - x0); - if (!state->clip->clipSpanBinary(scanBuf, y, x0, x1 - 1, - state->strokeAdjust)) { - continue; + for (y = 0; y < h; ++y) { + memcpy(lineBuf, + src->getDataPtr() + (ySrc + y) * src->rowSize + xSrc * 3, + w * 3); + for (x = 0, linePtr = lineBuf; x < w; ++x, linePtr += 3) { + b = linePtr[0]; + linePtr[0] = linePtr[2]; + linePtr[2] = b; } (this->*pipe.run)(&pipe, xDest, xDest + w - 1, yDest + y, - scanBuf + x0, - src->getDataPtr() + - (ySrc + y - yDest) * src->getRowSize() + - (xSrc - xDest) * bitmapComps); + NULL, lineBuf); + } + } + } else { + x0 = xDest; + if ((t = state->clip->getXMinI(state->strokeAdjust)) > x0) { + x0 = t; + } + x1 = xDest + w; + if ((t = state->clip->getXMaxI(state->strokeAdjust) + 1) < x1) { + x1 = t; + } + y0 = yDest; + if ((t = state->clip->getYMinI(state->strokeAdjust)) > y0) { + y0 = t; + } + y1 = yDest + h; + if ((t = state->clip->getYMaxI(state->strokeAdjust) + 1) < y1) { + y1 = t; + } + if (x0 < x1 && y0 < y1) { + if (src->alpha) { + for (y = y0; y < y1; ++y) { + memcpy(scanBuf + x0, + src->getAlphaPtr() + (ySrc + y - yDest) * src->getWidth() + + (xSrc + x0 - xDest), + x1 - x0); + state->clip->clipSpan(scanBuf, y, x0, x1 - 1, state->strokeAdjust); + memcpy(lineBuf, + src->getDataPtr() + + (ySrc + y - yDest) * src->rowSize + + (xSrc + x0 - xDest) * 3, + (x1 - x0) * 3); + for (x = 0, linePtr = lineBuf; x < x1 - x0; ++x, linePtr += 3) { + b = linePtr[0]; + linePtr[0] = linePtr[2]; + linePtr[2] = b; + } + // this uses shape instead of alpha, which isn't technically + // correct, but works out the same + (this->*pipe.run)(&pipe, x0, x1 - 1, y, + scanBuf + x0, lineBuf); + } + } else { + for (y = y0; y < y1; ++y) { + memset(scanBuf + x0, 0xff, x1 - x0); + state->clip->clipSpan(scanBuf, y, x0, x1 - 1, state->strokeAdjust); + memcpy(lineBuf, + src->getDataPtr() + + (ySrc + y - yDest) * src->rowSize + + (xSrc + x0 - xDest) * 3, + (x1 - x0) * 3); + for (x = 0, linePtr = lineBuf; x < x1 - x0; ++x, linePtr += 3) { + b = linePtr[0]; + linePtr[0] = linePtr[2]; + linePtr[2] = b; + } + (this->*pipe.run)(&pipe, x0, x1 - 1, yDest + y, + scanBuf + x0, + src->getDataPtr() + + (ySrc + y - yDest) * src->rowSize + + (xSrc + x0 - xDest) * bitmapComps); + } + } + } + } + gfree(lineBuf); + + } else { // src->mode not mono1 or BGR8 + if (noClip) { + if (src->alpha) { + for (y = 0; y < h; ++y) { + // this uses shape instead of alpha, which isn't technically + // correct, but works out the same + (this->*pipe.run)(&pipe, xDest, xDest + w - 1, yDest + y, + src->getAlphaPtr() + + (ySrc + y) * src->getWidth() + xSrc, + src->getDataPtr() + (ySrc + y) * src->rowSize + + xSrc * bitmapComps); + } + } else { + for (y = 0; y < h; ++y) { + (this->*pipe.run)(&pipe, xDest, xDest + w - 1, yDest + y, + NULL, + src->getDataPtr() + (ySrc + y) * src->rowSize + + xSrc * bitmapComps); + } + } + } else { + x0 = xDest; + if ((t = state->clip->getXMinI(state->strokeAdjust)) > x0) { + x0 = t; + } + x1 = xDest + w; + if ((t = state->clip->getXMaxI(state->strokeAdjust) + 1) < x1) { + x1 = t; + } + y0 = yDest; + if ((t = state->clip->getYMinI(state->strokeAdjust)) > y0) { + y0 = t; + } + y1 = yDest + h; + if ((t = state->clip->getYMaxI(state->strokeAdjust) + 1) < y1) { + y1 = t; + } + if (x0 < x1 && y0 < y1) { + if (src->alpha) { + for (y = y0; y < y1; ++y) { + memcpy(scanBuf + x0, + src->getAlphaPtr() + (ySrc + y - yDest) * src->getWidth() + + (xSrc + x0 - xDest), + x1 - x0); + state->clip->clipSpan(scanBuf, y, x0, x1 - 1, state->strokeAdjust); + // this uses shape instead of alpha, which isn't technically + // correct, but works out the same + (this->*pipe.run)(&pipe, x0, x1 - 1, y, + scanBuf + x0, + src->getDataPtr() + + (ySrc + y - yDest) * src->rowSize + + (xSrc + x0 - xDest) * bitmapComps); + } + } else { + for (y = y0; y < y1; ++y) { + memset(scanBuf + x0, 0xff, x1 - x0); + state->clip->clipSpan(scanBuf, y, x0, x1 - 1, state->strokeAdjust); + (this->*pipe.run)(&pipe, x0, x1 - 1, yDest + y, + scanBuf + x0, + src->getDataPtr() + + (ySrc + y - yDest) * src->rowSize + + (xSrc + x0 - xDest) * bitmapComps); + } } } } @@ -5980,13 +6328,21 @@ void Splash::compositeBackground(SplashColorPtr color) { 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 { - *p &= ~mask; + if (alpha == 0) { + if (color0 & 0x80) { + *p |= mask; + } else { + *p &= ~mask; + } + } else if (alpha != 255) { + alpha1 = 255 - alpha; + c = (*p & mask) ? 0xff : 0x00; + c = div255(alpha1 * color0 + alpha * c); + if (c & 0x80) { + *p |= mask; + } else { + *p &= ~mask; + } } if (!(mask >>= 1)) { mask = 0x80; @@ -6002,8 +6358,12 @@ void Splash::compositeBackground(SplashColorPtr color) { q = &bitmap->alpha[y * bitmap->width]; for (x = 0; x < bitmap->width; ++x) { alpha = *q++; - alpha1 = 255 - alpha; - p[0] = div255(alpha1 * color0 + alpha * p[0]); + if (alpha == 0) { + p[0] = color0; + } else if (alpha != 255) { + alpha1 = 255 - alpha; + p[0] = div255(alpha1 * color0 + alpha * p[0]); + } ++p; } } @@ -6018,10 +6378,16 @@ void Splash::compositeBackground(SplashColorPtr color) { q = &bitmap->alpha[y * bitmap->width]; for (x = 0; x < bitmap->width; ++x) { alpha = *q++; - alpha1 = 255 - alpha; - p[0] = div255(alpha1 * color0 + alpha * p[0]); - p[1] = div255(alpha1 * color1 + alpha * p[1]); - p[2] = div255(alpha1 * color2 + alpha * p[2]); + if (alpha == 0) { + p[0] = color0; + p[1] = color1; + p[2] = color2; + } else if (alpha != 255) { + alpha1 = 255 - alpha; + p[0] = div255(alpha1 * color0 + alpha * p[0]); + p[1] = div255(alpha1 * color1 + alpha * p[1]); + p[2] = div255(alpha1 * color2 + alpha * p[2]); + } p += 3; } } @@ -6037,11 +6403,18 @@ void Splash::compositeBackground(SplashColorPtr color) { q = &bitmap->alpha[y * bitmap->width]; for (x = 0; x < bitmap->width; ++x) { alpha = *q++; - alpha1 = 255 - alpha; - p[0] = div255(alpha1 * color0 + alpha * p[0]); - p[1] = div255(alpha1 * color1 + alpha * p[1]); - p[2] = div255(alpha1 * color2 + alpha * p[2]); - p[3] = div255(alpha1 * color3 + alpha * p[3]); + if (alpha == 0) { + p[0] = color0; + p[1] = color1; + p[2] = color2; + p[3] = color3; + } else if (alpha != 255) { + alpha1 = 255 - alpha; + p[0] = div255(alpha1 * color0 + alpha * p[0]); + p[1] = div255(alpha1 * color1 + alpha * p[1]); + p[2] = div255(alpha1 * color2 + alpha * p[2]); + p[3] = div255(alpha1 * color3 + alpha * p[3]); + } p += 4; } } @@ -6120,11 +6493,95 @@ SplashError Splash::blitTransparent(SplashBitmap *src, int xSrc, int ySrc, return splashOk; } +SplashError Splash::blitCorrectedAlpha(SplashBitmap *dest, int xSrc, int ySrc, + int xDest, int yDest, int w, int h) { + SplashColorPtr p, q; + Guchar *alpha0Ptr; + Guchar alpha0, aSrc; + int x, y, mask, srcMask; + + if (bitmap->mode != dest->mode || + !bitmap->alpha || + !dest->alpha || + !groupBackBitmap) { + return splashErrModeMismatch; + } + + switch (bitmap->mode) { + case splashModeMono1: + for (y = 0; y < h; ++y) { + p = &dest->data[(yDest + y) * dest->rowSize + (xDest >> 3)]; + mask = 0x80 >> (xDest & 7); + q = &bitmap->data[(ySrc + y) * bitmap->rowSize + (xSrc >> 3)]; + srcMask = 0x80 >> (xSrc & 7); + for (x = 0; x < w; ++x) { + if (*q & srcMask) { + *p |= mask; + } else { + *p &= ~mask; + } + if (!(mask >>= 1)) { + mask = 0x80; + ++p; + } + if (!(srcMask >>= 1)) { + srcMask = 0x80; + ++q; + } + } + } + break; + case splashModeMono8: + for (y = 0; y < h; ++y) { + p = &dest->data[(yDest + y) * dest->rowSize + xDest]; + q = &bitmap->data[(ySrc + y) * bitmap->rowSize + xSrc]; + memcpy(p, q, w); + } + break; + case splashModeRGB8: + case splashModeBGR8: + for (y = 0; y < h; ++y) { + p = &dest->data[(yDest + y) * dest->rowSize + 3 * xDest]; + q = &bitmap->data[(ySrc + y) * bitmap->rowSize + 3 * xSrc]; + memcpy(p, q, 3 * w); + } + break; +#if SPLASH_CMYK + case splashModeCMYK8: + for (y = 0; y < h; ++y) { + p = &dest->data[(yDest + y) * dest->rowSize + 4 * xDest]; + q = &bitmap->data[(ySrc + y) * bitmap->rowSize + 4 * xSrc]; + memcpy(p, q, 4 * w); + } + break; +#endif + } + + for (y = 0; y < h; ++y) { + p = &dest->alpha[(yDest + y) * dest->width + xDest]; + q = &bitmap->alpha[(ySrc + y) * bitmap->width + xSrc]; + alpha0Ptr = &groupBackBitmap->alpha[(groupBackY + ySrc + y) + * groupBackBitmap->width + + (groupBackX + xSrc)]; + for (x = 0; x < w; ++x) { + alpha0 = *alpha0Ptr++; + aSrc = *q++; + *p++ = alpha0 + aSrc - div255(alpha0 * aSrc); + } + } + + return splashOk; +} + SplashPath *Splash::makeStrokePath(SplashPath *path, SplashCoord w, - GBool flatten) { + int lineCap, int lineJoin, + GBool flatten) { SplashPath *pathIn, *dashPath, *pathOut; SplashCoord d, dx, dy, wdx, wdy, dxNext, dyNext, wdxNext, wdyNext; SplashCoord crossprod, dotprod, miter, m; + SplashCoord angle, angleNext, dAngle, xc, yc; + SplashCoord dxJoin, dyJoin, dJoin, kappa; + SplashCoord cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4; GBool first, last, closed; int subpathStart0, subpathStart1, seg, i0, i1, j0, j1, k0, k1; int left0, left1, left2, right0, right1, right2, join0, join1, join2; @@ -6184,7 +6641,7 @@ SplashPath *Splash::makeStrokePath(SplashPath *path, SplashCoord w, j1 = j0; } if (pathIn->flags[i1] & splashPathLast) { - if (first && state->lineCap == splashLineCapRound) { + if (first && lineCap == splashLineCapRound) { // special case: zero-length subpath with round line caps --> // draw a circle pathOut->moveTo(pathIn->pts[i0].x + (SplashCoord)0.5 * w, @@ -6250,16 +6707,17 @@ SplashPath *Splash::makeStrokePath(SplashPath *path, SplashCoord w, wdy = (SplashCoord)0.5 * w * dy; // draw the start cap - pathOut->moveTo(pathIn->pts[i0].x - wdy, pathIn->pts[i0].y + wdx); if (i0 == subpathStart0) { - firstPt = pathOut->length - 1; + firstPt = pathOut->length; } if (first && !closed) { - switch (state->lineCap) { + switch (lineCap) { case splashLineCapButt: + pathOut->moveTo(pathIn->pts[i0].x - wdy, pathIn->pts[i0].y + wdx); pathOut->lineTo(pathIn->pts[i0].x + wdy, pathIn->pts[i0].y - wdx); break; case splashLineCapRound: + pathOut->moveTo(pathIn->pts[i0].x - wdy, pathIn->pts[i0].y + wdx); pathOut->curveTo(pathIn->pts[i0].x - wdy - bezierCircle * wdx, pathIn->pts[i0].y + wdx - bezierCircle * wdy, pathIn->pts[i0].x - wdx - bezierCircle * wdy, @@ -6274,29 +6732,27 @@ SplashPath *Splash::makeStrokePath(SplashPath *path, SplashCoord w, pathIn->pts[i0].y - wdx); break; case splashLineCapProjecting: - pathOut->lineTo(pathIn->pts[i0].x - wdx - wdy, + pathOut->moveTo(pathIn->pts[i0].x - wdx - wdy, pathIn->pts[i0].y + wdx - wdy); pathOut->lineTo(pathIn->pts[i0].x - wdx + wdy, pathIn->pts[i0].y - wdx - wdy); - pathOut->lineTo(pathIn->pts[i0].x + wdy, - pathIn->pts[i0].y - wdx); break; } } else { + pathOut->moveTo(pathIn->pts[i0].x - wdy, pathIn->pts[i0].y + wdx); pathOut->lineTo(pathIn->pts[i0].x + wdy, pathIn->pts[i0].y - wdx); } - // draw the left side of the segment rectangle + // draw the left side of the segment rectangle and the end cap left2 = pathOut->length - 1; - pathOut->lineTo(pathIn->pts[j0].x + wdy, pathIn->pts[j0].y - wdx); - - // draw the end cap if (last && !closed) { - switch (state->lineCap) { + switch (lineCap) { case splashLineCapButt: + pathOut->lineTo(pathIn->pts[j0].x + wdy, pathIn->pts[j0].y - wdx); pathOut->lineTo(pathIn->pts[j0].x - wdy, pathIn->pts[j0].y + wdx); break; case splashLineCapRound: + pathOut->lineTo(pathIn->pts[j0].x + wdy, pathIn->pts[j0].y - wdx); pathOut->curveTo(pathIn->pts[j0].x + wdy + bezierCircle * wdx, pathIn->pts[j0].y - wdx + bezierCircle * wdy, pathIn->pts[j0].x + wdx + bezierCircle * wdy, @@ -6315,11 +6771,10 @@ SplashPath *Splash::makeStrokePath(SplashPath *path, SplashCoord w, pathIn->pts[j0].y - wdx + wdy); pathOut->lineTo(pathIn->pts[j0].x - wdy + wdx, pathIn->pts[j0].y + wdx + wdy); - pathOut->lineTo(pathIn->pts[j0].x - wdy, - pathIn->pts[j0].y + wdx); break; } } else { + pathOut->lineTo(pathIn->pts[j0].x + wdy, pathIn->pts[j0].y - wdx); pathOut->lineTo(pathIn->pts[j0].x - wdy, pathIn->pts[j0].y + wdx); } @@ -6327,7 +6782,7 @@ SplashPath *Splash::makeStrokePath(SplashPath *path, SplashCoord w, // (NB: if stroke adjustment is enabled, the closepath operation MUST // add a segment because this segment is used for a hint) right2 = pathOut->length - 1; - pathOut->close(state->strokeAdjust); + pathOut->close(state->strokeAdjust != splashStrokeAdjustOff); // draw the join join2 = pathOut->length; @@ -6372,43 +6827,121 @@ SplashPath *Splash::makeStrokePath(SplashPath *path, SplashCoord w, } // round join - if (state->lineJoin == splashLineJoinRound) { - pathOut->moveTo(pathIn->pts[j0].x + (SplashCoord)0.5 * w, - pathIn->pts[j0].y); - pathOut->curveTo(pathIn->pts[j0].x + (SplashCoord)0.5 * w, - pathIn->pts[j0].y + bezierCircle2 * w, - pathIn->pts[j0].x + bezierCircle2 * w, - pathIn->pts[j0].y + (SplashCoord)0.5 * w, - pathIn->pts[j0].x, - pathIn->pts[j0].y + (SplashCoord)0.5 * w); - pathOut->curveTo(pathIn->pts[j0].x - bezierCircle2 * w, - pathIn->pts[j0].y + (SplashCoord)0.5 * w, - pathIn->pts[j0].x - (SplashCoord)0.5 * w, - pathIn->pts[j0].y + bezierCircle2 * w, - pathIn->pts[j0].x - (SplashCoord)0.5 * w, - pathIn->pts[j0].y); - pathOut->curveTo(pathIn->pts[j0].x - (SplashCoord)0.5 * w, - pathIn->pts[j0].y - bezierCircle2 * w, - pathIn->pts[j0].x - bezierCircle2 * w, - pathIn->pts[j0].y - (SplashCoord)0.5 * w, - pathIn->pts[j0].x, - pathIn->pts[j0].y - (SplashCoord)0.5 * w); - pathOut->curveTo(pathIn->pts[j0].x + bezierCircle2 * w, - pathIn->pts[j0].y - (SplashCoord)0.5 * w, - pathIn->pts[j0].x + (SplashCoord)0.5 * w, - pathIn->pts[j0].y - bezierCircle2 * w, - pathIn->pts[j0].x + (SplashCoord)0.5 * w, - pathIn->pts[j0].y); + if (lineJoin == splashLineJoinRound) { + // join angle < 180 + if (crossprod < 0) { + angle = atan2((double)dx, (double)-dy); + angleNext = atan2((double)dxNext, (double)-dyNext); + if (angle < angleNext) { + angle += 2 * M_PI; + } + dAngle = (angle - angleNext) / M_PI; + if (dAngle < 0.501) { + // span angle is <= 90 degrees -> draw a single arc + kappa = dAngle * bezierCircle * w; + cx1 = pathIn->pts[j0].x - wdy + kappa * dx; + cy1 = pathIn->pts[j0].y + wdx + kappa * dy; + cx2 = pathIn->pts[j0].x - wdyNext - kappa * dxNext; + cy2 = pathIn->pts[j0].y + wdxNext - kappa * dyNext; + pathOut->moveTo(pathIn->pts[j0].x, pathIn->pts[j0].y); + pathOut->lineTo(pathIn->pts[j0].x - wdyNext, + pathIn->pts[j0].y + wdxNext); + pathOut->curveTo(cx2, cy2, cx1, cy1, + pathIn->pts[j0].x - wdy, + pathIn->pts[j0].y + wdx); + } else { + // span angle is > 90 degrees -> split into two arcs + dJoin = splashDist(-wdy, wdx, -wdyNext, wdxNext); + if (dJoin > 0) { + dxJoin = (-wdyNext + wdy) / dJoin; + dyJoin = (wdxNext - wdx) / dJoin; + xc = pathIn->pts[j0].x + + (SplashCoord)0.5 * w + * cos((double)((SplashCoord)0.5 * (angle + angleNext))); + yc = pathIn->pts[j0].y + + (SplashCoord)0.5 * w + * sin((double)((SplashCoord)0.5 * (angle + angleNext))); + kappa = dAngle * bezierCircle2 * w; + cx1 = pathIn->pts[j0].x - wdy + kappa * dx; + cy1 = pathIn->pts[j0].y + wdx + kappa * dy; + cx2 = xc - kappa * dxJoin; + cy2 = yc - kappa * dyJoin; + cx3 = xc + kappa * dxJoin; + cy3 = yc + kappa * dyJoin; + cx4 = pathIn->pts[j0].x - wdyNext - kappa * dxNext; + cy4 = pathIn->pts[j0].y + wdxNext - kappa * dyNext; + pathOut->moveTo(pathIn->pts[j0].x, pathIn->pts[j0].y); + pathOut->lineTo(pathIn->pts[j0].x - wdyNext, + pathIn->pts[j0].y + wdxNext); + pathOut->curveTo(cx4, cy4, cx3, cy3, xc, yc); + pathOut->curveTo(cx2, cy2, cx1, cy1, + pathIn->pts[j0].x - wdy, + pathIn->pts[j0].y + wdx); + } + } + + // join angle >= 180 + } else { + angle = atan2((double)-dx, (double)dy); + angleNext = atan2((double)-dxNext, (double)dyNext); + if (angleNext < angle) { + angleNext += 2 * M_PI; + } + dAngle = (angleNext - angle) / M_PI; + if (dAngle < 0.501) { + // span angle is <= 90 degrees -> draw a single arc + kappa = dAngle * bezierCircle * w; + cx1 = pathIn->pts[j0].x + wdy + kappa * dx; + cy1 = pathIn->pts[j0].y - wdx + kappa * dy; + cx2 = pathIn->pts[j0].x + wdyNext - kappa * dxNext; + cy2 = pathIn->pts[j0].y - wdxNext - kappa * dyNext; + pathOut->moveTo(pathIn->pts[j0].x, pathIn->pts[j0].y); + pathOut->lineTo(pathIn->pts[j0].x + wdy, + pathIn->pts[j0].y - wdx); + pathOut->curveTo(cx1, cy1, cx2, cy2, + pathIn->pts[j0].x + wdyNext, + pathIn->pts[j0].y - wdxNext); + } else { + // span angle is > 90 degrees -> split into two arcs + dJoin = splashDist(wdy, -wdx, wdyNext, -wdxNext); + if (dJoin > 0) { + dxJoin = (wdyNext - wdy) / dJoin; + dyJoin = (-wdxNext + wdx) / dJoin; + xc = pathIn->pts[j0].x + + (SplashCoord)0.5 * w + * cos((double)((SplashCoord)0.5 * (angle + angleNext))); + yc = pathIn->pts[j0].y + + (SplashCoord)0.5 * w + * sin((double)((SplashCoord)0.5 * (angle + angleNext))); + kappa = dAngle * bezierCircle2 * w; + cx1 = pathIn->pts[j0].x + wdy + kappa * dx; + cy1 = pathIn->pts[j0].y - wdx + kappa * dy; + cx2 = xc - kappa * dxJoin; + cy2 = yc - kappa * dyJoin; + cx3 = xc + kappa * dxJoin; + cy3 = yc + kappa * dyJoin; + cx4 = pathIn->pts[j0].x + wdyNext - kappa * dxNext; + cy4 = pathIn->pts[j0].y - wdxNext - kappa * dyNext; + pathOut->moveTo(pathIn->pts[j0].x, pathIn->pts[j0].y); + pathOut->lineTo(pathIn->pts[j0].x + wdy, + pathIn->pts[j0].y - wdx); + pathOut->curveTo(cx1, cy1, cx2, cy2, xc, yc); + pathOut->curveTo(cx3, cy3, cx4, cy4, + pathIn->pts[j0].x + wdyNext, + pathIn->pts[j0].y - wdxNext); + } + } + } } else { pathOut->moveTo(pathIn->pts[j0].x, pathIn->pts[j0].y); - // angle < 180 + // join angle < 180 if (crossprod < 0) { pathOut->lineTo(pathIn->pts[j0].x - wdyNext, pathIn->pts[j0].y + wdxNext); // miter join inside limit - if (state->lineJoin == splashLineJoinMiter && + if (lineJoin == splashLineJoinMiter && splashSqrt(miter) <= state->miterLimit) { pathOut->lineTo(pathIn->pts[j0].x - wdy + wdx * m, pathIn->pts[j0].y + wdx + wdy * m); @@ -6420,12 +6953,12 @@ SplashPath *Splash::makeStrokePath(SplashPath *path, SplashCoord w, pathIn->pts[j0].y + wdx); } - // angle >= 180 + // join angle >= 180 } else { pathOut->lineTo(pathIn->pts[j0].x + wdy, pathIn->pts[j0].y - wdx); // miter join inside limit - if (state->lineJoin == splashLineJoinMiter && + if (lineJoin == splashLineJoinMiter && splashSqrt(miter) <= state->miterLimit) { pathOut->lineTo(pathIn->pts[j0].x + wdy + wdx * m, pathIn->pts[j0].y - wdx + wdy * m); @@ -6443,36 +6976,106 @@ SplashPath *Splash::makeStrokePath(SplashPath *path, SplashCoord w, } // add stroke adjustment hints - if (state->strokeAdjust) { - if (seg == 0 && !closed) { - if (state->lineCap == splashLineCapButt) { + if (state->strokeAdjust != splashStrokeAdjustOff) { + + // subpath with one segment + if (seg == 0 && last) { + switch (lineCap) { + case splashLineCapButt: pathOut->addStrokeAdjustHint(firstPt, left2 + 1, - firstPt, firstPt + 1); - if (last) { - pathOut->addStrokeAdjustHint(firstPt, left2 + 1, - left2 + 1, left2 + 2); - } - } else if (state->lineCap == splashLineCapProjecting) { - if (last) { - pathOut->addStrokeAdjustHint(firstPt + 1, left2 + 2, - firstPt + 1, firstPt + 2); - pathOut->addStrokeAdjustHint(firstPt + 1, left2 + 2, - left2 + 2, left2 + 3); - } else { - pathOut->addStrokeAdjustHint(firstPt + 1, left2 + 1, - firstPt + 1, firstPt + 2); + firstPt, pathOut->length - 1); + break; + case splashLineCapProjecting: + pathOut->addStrokeAdjustHint(firstPt, left2 + 1, + firstPt, pathOut->length - 1, gTrue); + break; + case splashLineCapRound: + break; + } + pathOut->addStrokeAdjustHint(left2, right2, + firstPt, pathOut->length - 1); + } else { + + // start of subpath + if (seg == 1) { + + // start cap + if (!closed) { + switch (lineCap) { + case splashLineCapButt: + pathOut->addStrokeAdjustHint(firstPt, left1 + 1, + firstPt, firstPt + 1); + pathOut->addStrokeAdjustHint(firstPt, left1 + 1, + right1 + 1, right1 + 1); + break; + case splashLineCapProjecting: + pathOut->addStrokeAdjustHint(firstPt, left1 + 1, + firstPt, firstPt + 1, gTrue); + pathOut->addStrokeAdjustHint(firstPt, left1 + 1, + right1 + 1, right1 + 1, gTrue); + break; + case splashLineCapRound: + break; + } } + + // first segment + pathOut->addStrokeAdjustHint(left1, right1, firstPt, left2); + pathOut->addStrokeAdjustHint(left1, right1, right2 + 1, right2 + 1); } - } - if (seg >= 1) { - if (seg >= 2) { + + // middle of subpath + if (seg > 1) { 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); + } + + // end of subpath + if (last) { + + if (closed) { + // first segment + pathOut->addStrokeAdjustHint(leftFirst, rightFirst, + left2 + 1, right2); + pathOut->addStrokeAdjustHint(leftFirst, rightFirst, + join2, pathOut->length - 1); + + // last segment + pathOut->addStrokeAdjustHint(left2, right2, + left1 + 1, right1); + pathOut->addStrokeAdjustHint(left2, right2, + join1, pathOut->length - 1); + pathOut->addStrokeAdjustHint(left2, right2, + leftFirst - 1, leftFirst); + pathOut->addStrokeAdjustHint(left2, right2, + rightFirst + 1, rightFirst + 1); + + } else { + + // last segment + pathOut->addStrokeAdjustHint(left2, right2, + left1 + 1, right1); + pathOut->addStrokeAdjustHint(left2, right2, + join1, pathOut->length - 1); + + // end cap + switch (lineCap) { + case splashLineCapButt: + pathOut->addStrokeAdjustHint(left2 - 1, left2 + 1, + left2 + 1, left2 + 2); + break; + case splashLineCapProjecting: + pathOut->addStrokeAdjustHint(left2 - 1, left2 + 1, + left2 + 1, left2 + 2, gTrue); + break; + case splashLineCapRound: + break; + } + } } - pathOut->addStrokeAdjustHint(left1, right1, right2 + 1, right2 + 1); } + left0 = left1; left1 = left2; right0 = right1; @@ -6483,34 +7086,6 @@ SplashPath *Splash::makeStrokePath(SplashPath *path, SplashCoord w, leftFirst = left2; rightFirst = right2; } - if (last) { - if (seg >= 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); - } - if (!closed && seg > 0) { - if (state->lineCap == splashLineCapButt) { - pathOut->addStrokeAdjustHint(left1 - 1, left1 + 1, - left1 + 1, left1 + 2); - } else if (state->lineCap == splashLineCapProjecting) { - pathOut->addStrokeAdjustHint(left1 - 1, left1 + 2, - left1 + 2, left1 + 3); - } - } - } } i0 = j0; @@ -6525,6 +7100,29 @@ SplashPath *Splash::makeStrokePath(SplashPath *path, SplashCoord w, return pathOut; } +SplashClipResult Splash::limitRectToClipRect(int *xMin, int *yMin, + int *xMax, int *yMax) { + int t; + + if ((t = state->clip->getXMinI(state->strokeAdjust)) > *xMin) { + *xMin = t; + } + if ((t = state->clip->getXMaxI(state->strokeAdjust) + 1) < *xMax) { + *xMax = t; + } + if ((t = state->clip->getYMinI(state->strokeAdjust)) > *yMin) { + *yMin = t; + } + if ((t = state->clip->getYMaxI(state->strokeAdjust) + 1) < *yMax) { + *yMax = t; + } + if (*xMin >= *xMax || *yMin >= *yMax) { + return splashClipAllOutside; + } + return state->clip->testRect(*xMin, *yMin, *xMax - 1, *yMax - 1, + state->strokeAdjust); +} + void Splash::dumpPath(SplashPath *path) { int i; @@ -6536,6 +7134,15 @@ void Splash::dumpPath(SplashPath *path) { (path->flags[i] & splashPathClosed) ? " closed" : "", (path->flags[i] & splashPathCurve) ? " curve" : ""); } + if (path->hintsLength == 0) { + printf(" no hints\n"); + } else { + for (i = 0; i < path->hintsLength; ++i) { + printf(" hint %3d: ctrl0=%d ctrl1=%d pts=%d..%d\n", + i, path->hints[i].ctrl0, path->hints[i].ctrl1, + path->hints[i].firstPt, path->hints[i].lastPt); + } + } } void Splash::dumpXPath(SplashXPath *path) { diff --git a/Build/source/libs/xpdf/xpdf-src/splash/Splash.h b/Build/source/libs/xpdf/xpdf-src/splash/Splash.h index 7409e0cd6b4..3ca57982e15 100644 --- a/Build/source/libs/xpdf/xpdf-src/splash/Splash.h +++ b/Build/source/libs/xpdf/xpdf-src/splash/Splash.h @@ -95,7 +95,7 @@ public: SplashCoord *getLineDash(); int getLineDashLength(); SplashCoord getLineDashPhase(); - GBool getStrokeAdjust(); + SplashStrokeAdjustMode getStrokeAdjust(); SplashClip *getClip(); SplashBitmap *getSoftMask(); GBool getInNonIsolatedGroup(); @@ -118,7 +118,7 @@ public: // the <lineDash> array will be copied void setLineDash(SplashCoord *lineDash, int lineDashLength, SplashCoord lineDashPhase); - void setStrokeAdjust(GBool strokeAdjust); + void setStrokeAdjust(SplashStrokeAdjustMode strokeAdjust); // NB: uses transformed coordinates. void clipResetToRect(SplashCoord x0, SplashCoord y0, SplashCoord x1, SplashCoord y1); @@ -133,6 +133,7 @@ public: GBool nonIsolated, GBool knockout); void setTransfer(Guchar *red, Guchar *green, Guchar *blue, Guchar *gray); void setOverprintMask(Guint overprintMask); + void setEnablePathSimplification(GBool en); //----- state save/restore @@ -150,9 +151,6 @@ public: // Fill a path using the current fill pattern. SplashError fill(SplashPath *path, GBool eo); - // Fill a path, XORing with the current fill pattern. - SplashError xorFill(SplashPath *path, GBool eo); - // Draw a character, using the current fill pattern. SplashError fillChar(SplashCoord x, SplashCoord y, int c, SplashFont *font); @@ -213,6 +211,12 @@ public: SplashError blitTransparent(SplashBitmap *src, int xSrc, int ySrc, int xDest, int yDest, int w, int h); + // Copy a rectangular region from the bitmap belonging to this + // Splash object to <dest>. The alpha values are corrected for a + // non-isolated group. + SplashError blitCorrectedAlpha(SplashBitmap *dest, 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 @@ -220,8 +224,15 @@ public: // the current state. If <flatten> is true, this function will // first flatten the path and handle the linedash. SplashPath *makeStrokePath(SplashPath *path, SplashCoord w, + int lineCap, int lineJoin, GBool flatten = gTrue); + // Reduce the size of a rectangle as much as possible by moving any + // edges that are completely outside the clip region. Returns the + // clipping status of the resulting rectangle. + SplashClipResult limitRectToClipRect(int *xMin, int *yMin, + int *xMax, int *yMax); + // Return the associated bitmap. SplashBitmap *getBitmap() { return bitmap; } @@ -296,7 +307,8 @@ private: void updateModY(int y); void strokeNarrow(SplashPath *path); void drawStrokeSpan(SplashPipe *pipe, int x0, int x1, int y, GBool noClip); - void strokeWide(SplashPath *path, SplashCoord w); + void strokeWide(SplashPath *path, SplashCoord w, + int lineCap, int lineJoin); SplashPath *flattenPath(SplashPath *path, SplashCoord *matrix, SplashCoord flatness); void flattenCurve(SplashCoord x0, SplashCoord y0, @@ -407,10 +419,10 @@ private: int bitmapComps; SplashState *state; Guchar *scanBuf; + Guchar *scanBuf2; SplashBitmap // for transparency groups, this is the bitmap *groupBackBitmap; // containing the alpha0/color0 values int groupBackX, groupBackY; // offset within groupBackBitmap - Guchar aaGamma[256]; SplashCoord minLineWidth; int modXMin, modYMin, modXMax, modYMax; SplashClipResult opClipRes; diff --git a/Build/source/libs/xpdf/xpdf-src/splash/SplashBitmap.cc b/Build/source/libs/xpdf/xpdf-src/splash/SplashBitmap.cc index 3606a917beb..32ecc3fdd03 100644 --- a/Build/source/libs/xpdf/xpdf-src/splash/SplashBitmap.cc +++ b/Build/source/libs/xpdf/xpdf-src/splash/SplashBitmap.cc @@ -15,6 +15,7 @@ #include <stdio.h> #include <limits.h> #include "gmem.h" +#include "gmempp.h" #include "SplashErrorCodes.h" #include "SplashBitmap.h" @@ -154,7 +155,18 @@ SplashError SplashBitmap::writePNMFile(FILE *f) { #if SPLASH_CMYK case splashModeCMYK8: - // PNM doesn't support CMYK + fprintf(f, "P7\n"); + fprintf(f, "WIDTH %d\n", width); + fprintf(f, "HEIGHT %d\n", height); + fprintf(f, "DEPTH 4\n"); + fprintf(f, "MAXVAL 255\n"); + fprintf(f, "TUPLTYPE CMYK\n"); + fprintf(f, "ENDHDR\n"); + row = data; + for (y = 0; y < height; ++y) { + fwrite(row, 1, 4 * width, f); + row += rowSize; + } break; #endif diff --git a/Build/source/libs/xpdf/xpdf-src/splash/SplashClip.cc b/Build/source/libs/xpdf/xpdf-src/splash/SplashClip.cc index 6865c574f4e..bf7b802cf0d 100644 --- a/Build/source/libs/xpdf/xpdf-src/splash/SplashClip.cc +++ b/Build/source/libs/xpdf/xpdf-src/splash/SplashClip.cc @@ -15,6 +15,7 @@ #include <stdlib.h> #include <string.h> #include "gmem.h" +#include "gmempp.h" #include "SplashErrorCodes.h" #include "SplashPath.h" #include "SplashXPath.h" @@ -52,6 +53,8 @@ SplashClip::SplashClip(int hardXMinA, int hardYMinA, eo = NULL; scanners = NULL; length = size = 0; + isSimple = gTrue; + prev = NULL; if ((w = hardXMax + 1) <= 0) { w = 1; } @@ -59,7 +62,7 @@ SplashClip::SplashClip(int hardXMinA, int hardYMinA, } SplashClip::SplashClip(SplashClip *clip) { - int w, i; + int w; hardXMin = clip->hardXMin; hardYMin = clip->hardYMin; @@ -75,17 +78,12 @@ SplashClip::SplashClip(SplashClip *clip) { yMaxI = clip->yMaxI; intBoundsValid = clip->intBoundsValid; intBoundsStrokeAdjust = clip->intBoundsStrokeAdjust; - length = clip->length; - size = clip->size; - paths = (SplashXPath **)gmallocn(size, sizeof(SplashXPath *)); - eo = (Guchar *)gmallocn(size, sizeof(Guchar)); - scanners = (SplashXPathScanner **) - gmallocn(size, sizeof(SplashXPathScanner *)); - for (i = 0; i < length; ++i) { - paths[i] = clip->paths[i]->copy(); - eo[i] = clip->eo[i]; - scanners[i] = new SplashXPathScanner(paths[i], eo[i], yMinI, yMaxI); - } + paths = NULL; + eo = NULL; + scanners = NULL; + length = size = 0; + isSimple = clip->isSimple; + prev = clip; if ((w = splashCeil(xMax)) <= 0) { w = 1; } @@ -96,8 +94,8 @@ SplashClip::~SplashClip() { int i; for (i = 0; i < length; ++i) { - delete paths[i]; delete scanners[i]; + delete paths[i]; } gfree(paths); gfree(eo); @@ -136,6 +134,8 @@ void SplashClip::resetToRect(SplashCoord x0, SplashCoord y0, eo = NULL; scanners = NULL; length = size = 0; + isSimple = gTrue; + prev = NULL; if (x0 < x1) { xMin = x0; @@ -202,11 +202,15 @@ SplashError SplashClip::clipToRect(SplashCoord x0, SplashCoord y0, } SplashError SplashClip::clipToPath(SplashPath *path, SplashCoord *matrix, - SplashCoord flatness, GBool eoA) { + SplashCoord flatness, GBool eoA, + GBool enablePathSimplification, + SplashStrokeAdjustMode strokeAdjust) { SplashXPath *xPath; SplashCoord t; - xPath = new SplashXPath(path, matrix, flatness, gTrue); + xPath = new SplashXPath(path, matrix, flatness, gTrue, + enablePathSimplification, + strokeAdjust); // check for an empty path if (xPath->length == 0) { @@ -218,33 +222,8 @@ SplashError SplashClip::clipToPath(SplashPath *path, SplashCoord *matrix, } // check for a rectangle - if (xPath->length == 4 && - xPath->segs[0].y0 == xPath->segs[0].y1 && - xPath->segs[1].x0 == xPath->segs[1].x1 && - xPath->segs[2].x0 == xPath->segs[2].x1 && - xPath->segs[3].y0 == xPath->segs[3].y1) { - clipToRect(xPath->segs[1].x0, xPath->segs[0].y0, - xPath->segs[2].x0, xPath->segs[3].y0); - delete xPath; - return splashOk; - } - if (xPath->length == 4 && - xPath->segs[0].x0 == xPath->segs[0].x1 && - xPath->segs[1].y0 == xPath->segs[1].y1 && - xPath->segs[2].x0 == xPath->segs[2].x1 && - xPath->segs[3].y0 == xPath->segs[3].y1) { - clipToRect(xPath->segs[0].x0, xPath->segs[1].y0, - xPath->segs[2].x0, xPath->segs[3].y0); - delete xPath; - return splashOk; - } - if (xPath->length == 4 && - xPath->segs[0].x0 == xPath->segs[0].x1 && - xPath->segs[1].x0 == xPath->segs[1].x1 && - xPath->segs[2].y0 == xPath->segs[2].y1 && - xPath->segs[3].y0 == xPath->segs[3].y1) { - clipToRect(xPath->segs[0].x0, xPath->segs[2].y0, - xPath->segs[1].x0, xPath->segs[3].y0); + if (xPath->isRect) { + clipToRect(xPath->rectX0, xPath->rectY0, xPath->rectX1, xPath->rectY1); delete xPath; return splashOk; } @@ -268,13 +247,14 @@ SplashError SplashClip::clipToPath(SplashPath *path, SplashCoord *matrix, scanners[length] = new SplashXPathScanner(xPath, eoA, splashFloor(yMin), splashCeil(yMax) - 1); ++length; + isSimple = gFalse; return splashOk; } SplashClipResult SplashClip::testRect(int rectXMin, int rectYMin, int rectXMax, int rectYMax, - GBool strokeAdjust) { + SplashStrokeAdjustMode strokeAdjust) { // In general, this function tests the rectangle: // x = [rectXMin, rectXMax + 1) (note: coords are ints) // y = [rectYMin, rectYMax + 1) @@ -282,7 +262,7 @@ SplashClipResult SplashClip::testRect(int rectXMin, int rectYMin, // x = [xMin, xMax) (note: coords are fp) // y = [yMin, yMax) - if (strokeAdjust && length == 0) { + if (strokeAdjust != splashStrokeAdjustOff && isSimple) { // special case for stroke adjustment with a simple clipping // rectangle -- the clipping region is: // x = [xMinI, xMaxI + 1) @@ -313,7 +293,7 @@ SplashClipResult SplashClip::testRect(int rectXMin, int rectYMin, (SplashCoord)rectYMin >= yMax) { return splashClipAllOutside; } - if (length == 0 && + if (isSimple && (SplashCoord)rectXMin >= xMin && (SplashCoord)(rectXMax + 1) <= xMax && (SplashCoord)rectYMin >= yMin && @@ -325,9 +305,10 @@ SplashClipResult SplashClip::testRect(int rectXMin, int rectYMin, } void SplashClip::clipSpan(Guchar *line, int y, int x0, int x1, - GBool strokeAdjust) { + SplashStrokeAdjustMode strokeAdjust) { + SplashClip *clip; SplashCoord d; - int x0a, x1a, x, i; + int x0a, x1a, x0b, x1b, x, i; updateIntBounds(strokeAdjust); @@ -360,7 +341,7 @@ void SplashClip::clipSpan(Guchar *line, int y, int x0, int x1, //--- clip to the floating point rectangle // (if stroke adjustment is disabled) - if (!strokeAdjust) { + if (strokeAdjust == splashStrokeAdjustOff) { // clip left edge (xMin) if (x0a == xMinI) { @@ -391,22 +372,31 @@ void SplashClip::clipSpan(Guchar *line, int y, int x0, int x1, } } - if (length == 0) { + if (isSimple) { return; } //--- clip to the paths - for (i = 0; i < length; ++i) { - scanners[i]->getSpan(buf, y, x0a, x1a); - for (x = x0a; x <= x1a; ++x) { - line[x] = mul255(line[x], buf[x]); + for (clip = this; clip; clip = clip->prev) { + for (i = 0; i < clip->length; ++i) { + clip->scanners[i]->getSpan(buf, y, x0a, x1a, &x0b, &x1b); + if (x0a < x0b) { + memset(line + x0a, 0, x0b - x0a); + } + for (x = x0b; x <= x1b; ++x) { + line[x] = mul255(line[x], buf[x]); + } + if (x1b < x1a) { + memset(line + x1b + 1, 0, x1a - x1b); + } } } } GBool SplashClip::clipSpanBinary(Guchar *line, int y, int x0, int x1, - GBool strokeAdjust) { + SplashStrokeAdjustMode strokeAdjust) { + SplashClip *clip; int x0a, x1a, x0b, x1b, x, i; Guchar any; @@ -438,7 +428,7 @@ GBool SplashClip::clipSpanBinary(Guchar *line, int y, int x0, int x1, return gFalse; } - if (length == 0) { + if (isSimple) { for (x = x0a; x <= x1a; ++x) { if (line[x]) { return gTrue; @@ -448,52 +438,63 @@ GBool SplashClip::clipSpanBinary(Guchar *line, int y, int x0, int x1, } any = 0; - for (i = 0; i < length; ++i) { - scanners[i]->getSpanBinary(buf, y, x0a, x1a); - for (x0b = x0a; x0b <= x1a && !buf[x0b]; ++x0b) ; - if (x0a < x0b) { - memset(line + x0a, 0, x0b - x0a); - } - for (x1b = x1a; x1b >= x0b && !buf[x1b]; --x1b) ; - if (x1b < x1a) { - memset(line + x1b + 1, 0, x1a - x1b); - } - for (x = x0b; x <= x1b; ++x) { - line[x] &= buf[x]; - any |= line[x]; + for (clip = this; clip; clip = clip->prev) { + for (i = 0; i < clip->length; ++i) { + clip->scanners[i]->getSpanBinary(buf, y, x0a, x1a, &x0b, &x1b); + if (x0a < x0b) { + memset(line + x0a, 0, x0b - x0a); + } + for (x = x0b; x <= x1b; ++x) { + line[x] &= buf[x]; + any |= line[x]; + } + if (x1b < x1a) { + memset(line + x1b + 1, 0, x1a - x1b); + } } } return any != 0; } -int SplashClip::getXMinI(GBool strokeAdjust) { +int SplashClip::getXMinI(SplashStrokeAdjustMode strokeAdjust) { updateIntBounds(strokeAdjust); return xMinI; } -int SplashClip::getXMaxI(GBool strokeAdjust) { +int SplashClip::getXMaxI(SplashStrokeAdjustMode strokeAdjust) { updateIntBounds(strokeAdjust); return xMaxI; } -int SplashClip::getYMinI(GBool strokeAdjust) { +int SplashClip::getYMinI(SplashStrokeAdjustMode strokeAdjust) { updateIntBounds(strokeAdjust); return yMinI; } -int SplashClip::getYMaxI(GBool strokeAdjust) { +int SplashClip::getYMaxI(SplashStrokeAdjustMode strokeAdjust) { updateIntBounds(strokeAdjust); return yMaxI; } -void SplashClip::updateIntBounds(GBool strokeAdjust) { +int SplashClip::getNumPaths() { + SplashClip *clip; + int n; + + n = 0; + for (clip = this; clip; clip = clip->prev) { + n += clip->length; + } + return n; +} + +void SplashClip::updateIntBounds(SplashStrokeAdjustMode strokeAdjust) { if (intBoundsValid && strokeAdjust == intBoundsStrokeAdjust) { return; } - if (strokeAdjust && length == 0) { - splashStrokeAdjust(xMin, xMax, &xMinI, &xMaxI); - splashStrokeAdjust(yMin, yMax, &yMinI, &yMaxI); + if (strokeAdjust != splashStrokeAdjustOff && isSimple) { + splashStrokeAdjust(xMin, xMax, &xMinI, &xMaxI, strokeAdjust); + splashStrokeAdjust(yMin, yMax, &yMinI, &yMaxI, strokeAdjust); } else { xMinI = splashFloor(xMin); yMinI = splashFloor(yMin); diff --git a/Build/source/libs/xpdf/xpdf-src/splash/SplashClip.h b/Build/source/libs/xpdf/xpdf-src/splash/SplashClip.h index 42986222976..fb86ed8fd72 100644 --- a/Build/source/libs/xpdf/xpdf-src/splash/SplashClip.h +++ b/Build/source/libs/xpdf/xpdf-src/splash/SplashClip.h @@ -57,7 +57,9 @@ public: // Interesect the clip with <path>. SplashError clipToPath(SplashPath *path, SplashCoord *matrix, - SplashCoord flatness, GBool eoA); + SplashCoord flatness, GBool eoA, + GBool enablePathSimplification, + SplashStrokeAdjustMode strokeAdjust); // Tests a rectangle against the clipping region. Returns one of: // - splashClipAllInside if the entire rectangle is inside the @@ -70,18 +72,18 @@ public: // outside the clipping region SplashClipResult testRect(int rectXMin, int rectYMin, int rectXMax, int rectYMax, - GBool strokeAdjust); + SplashStrokeAdjustMode strokeAdjust); // Clip a scan line. Modifies line[] by multiplying with clipping // shape values for one scan line: ([x0, x1], y). void clipSpan(Guchar *line, int y, int x0, int x1, - GBool strokeAdjust); + SplashStrokeAdjustMode strokeAdjust); // Like clipSpan(), but uses the values 0 and 255 only. // Returns true if there are any non-zero values in the result // (i.e., returns false if the entire line is clipped out). GBool clipSpanBinary(Guchar *line, int y, int x0, int x1, - GBool strokeAdjust); + SplashStrokeAdjustMode strokeAdjust); // Get the rectangle part of the clip region. SplashCoord getXMin() { return xMin; } @@ -90,19 +92,19 @@ public: SplashCoord getYMax() { return yMax; } // Get the rectangle part of the clip region, in integer coordinates. - int getXMinI(GBool strokeAdjust); - int getXMaxI(GBool strokeAdjust); - int getYMinI(GBool strokeAdjust); - int getYMaxI(GBool strokeAdjust); + int getXMinI(SplashStrokeAdjustMode strokeAdjust); + int getXMaxI(SplashStrokeAdjustMode strokeAdjust); + int getYMinI(SplashStrokeAdjustMode strokeAdjust); + int getYMaxI(SplashStrokeAdjustMode strokeAdjust); // Get the number of arbitrary paths used by the clip region. - int getNumPaths() { return length; } + int getNumPaths(); private: SplashClip(SplashClip *clip); void grow(int nPaths); - void updateIntBounds(GBool strokeAdjust); + void updateIntBounds(SplashStrokeAdjustMode strokeAdjust); int hardXMin, hardYMin, // coordinates cannot fall outside of hardXMax, hardYMax; // [hardXMin, hardXMax), [hardYMin, hardYMax) @@ -120,6 +122,8 @@ private: Guchar *eo; SplashXPathScanner **scanners; int length, size; + GBool isSimple; + SplashClip *prev; Guchar *buf; }; diff --git a/Build/source/libs/xpdf/xpdf-src/splash/SplashFTFont.cc b/Build/source/libs/xpdf/xpdf-src/splash/SplashFTFont.cc index 6fc6b946b65..884092b050c 100644 --- a/Build/source/libs/xpdf/xpdf-src/splash/SplashFTFont.cc +++ b/Build/source/libs/xpdf/xpdf-src/splash/SplashFTFont.cc @@ -8,7 +8,7 @@ #include <aconf.h> -#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H +#if HAVE_FREETYPE_H #ifdef USE_GCC_PRAGMAS #pragma implementation @@ -19,6 +19,7 @@ #include FT_SIZES_H #include FT_GLYPH_H #include "gmem.h" +#include "gmempp.h" #include "SplashMath.h" #include "SplashGlyphBitmap.h" #include "SplashPath.h" @@ -66,6 +67,10 @@ SplashFTFont::SplashFTFont(SplashFTFontFile *fontFileA, SplashCoord *matA, // if the textMat values are too small, FreeType's fixed point // arithmetic doesn't work so well textScale = splashDist(0, 0, textMat[2], textMat[3]) / size; + // avoid problems with singular (or close-to-singular) matrices + if (textScale < 0.00001) { + textScale = 0.00001; + } div = face->bbox.xMax > 20000 ? 65536 : 1; @@ -220,7 +225,7 @@ GBool SplashFTFont::makeGlyph(int c, int xFrac, int yFrac, SplashFTFontFile *ff; FT_Vector offset; FT_GlyphSlot slot; - FT_UInt gid; + int gid; FT_Int32 flags; int rowSize; Guchar *p, *q; @@ -235,11 +240,11 @@ GBool SplashFTFont::makeGlyph(int c, int xFrac, int yFrac, slot = ff->face->glyph; if (ff->codeToGID && c < ff->codeToGIDLen) { - gid = (FT_UInt)ff->codeToGID[c]; + gid = ff->codeToGID[c]; } else { - gid = (FT_UInt)c; + gid = c; } - if (ff->trueType && gid < 0) { + if (ff->fontType == splashFontTrueType && gid < 0) { // skip the TrueType notdef glyph return gFalse; } @@ -258,13 +263,19 @@ GBool SplashFTFont::makeGlyph(int c, int xFrac, int yFrac, flags = FT_LOAD_NO_BITMAP; if (ff->engine->flags & splashFTNoHinting) { flags |= FT_LOAD_NO_HINTING; - } else if (ff->useLightHinting) { + } else if (ff->fontType == splashFontType1) { flags |= FT_LOAD_TARGET_LIGHT; } else { flags |= FT_LOAD_NO_AUTOHINT; } - if (FT_Load_Glyph(ff->face, gid, flags)) { - return gFalse; + if (FT_Load_Glyph(ff->face, (FT_UInt)gid, flags)) { + // fonts with broken hinting instructions can cause errors here; + // try again with no hinting (this is probably only relevant for + // TrueType fonts) + flags = FT_LOAD_NO_BITMAP | FT_LOAD_NO_HINTING; + if (FT_Load_Glyph(ff->face, (FT_UInt)gid, flags)) { + return gFalse; + } } if (FT_Render_Glyph(slot, aa ? FT_RENDER_MODE_NORMAL : FT_RENDER_MODE_MONO)) { @@ -321,7 +332,7 @@ SplashPath *SplashFTFont::getGlyphPath(int c) { SplashFTFontFile *ff; SplashFTFontPath path; FT_GlyphSlot slot; - FT_UInt gid; + int gid; FT_Glyph glyph; ff = (SplashFTFontFile *)fontFile; @@ -331,14 +342,20 @@ SplashPath *SplashFTFont::getGlyphPath(int c) { if (ff->codeToGID && c < ff->codeToGIDLen) { gid = ff->codeToGID[c]; } else { - gid = (FT_UInt)c; + gid = c; } - if (ff->trueType && gid < 0) { + if (ff->fontType == splashFontTrueType && gid < 0) { // skip the TrueType notdef glyph return NULL; } - if (FT_Load_Glyph(ff->face, gid, FT_LOAD_NO_BITMAP)) { - return NULL; + if (FT_Load_Glyph(ff->face, (FT_UInt)gid, FT_LOAD_NO_BITMAP)) { + // fonts with broken hinting instructions can cause errors here; + // try again with no hinting (this is probably only relevant for + // TrueType fonts) + if (FT_Load_Glyph(ff->face, (FT_UInt)gid, + FT_LOAD_NO_BITMAP | FT_LOAD_NO_HINTING)) { + return NULL; + } } if (FT_Get_Glyph(slot, &glyph)) { return NULL; @@ -429,4 +446,4 @@ static int glyphPathCubicTo(const FT_Vector *ctrl1, const FT_Vector *ctrl2, return 0; } -#endif // HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H +#endif // HAVE_FREETYPE_H diff --git a/Build/source/libs/xpdf/xpdf-src/splash/SplashFTFont.h b/Build/source/libs/xpdf/xpdf-src/splash/SplashFTFont.h index 560b74c3bfe..ac08b007747 100644 --- a/Build/source/libs/xpdf/xpdf-src/splash/SplashFTFont.h +++ b/Build/source/libs/xpdf/xpdf-src/splash/SplashFTFont.h @@ -11,7 +11,7 @@ #include <aconf.h> -#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H +#if HAVE_FREETYPE_H #ifdef USE_GCC_PRAGMAS #pragma interface @@ -55,6 +55,6 @@ private: SplashCoord textScale; }; -#endif // HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H +#endif // HAVE_FREETYPE_H #endif diff --git a/Build/source/libs/xpdf/xpdf-src/splash/SplashFTFontEngine.cc b/Build/source/libs/xpdf/xpdf-src/splash/SplashFTFontEngine.cc index 3ba033c9db3..33939541051 100644 --- a/Build/source/libs/xpdf/xpdf-src/splash/SplashFTFontEngine.cc +++ b/Build/source/libs/xpdf/xpdf-src/splash/SplashFTFontEngine.cc @@ -8,7 +8,7 @@ #include <aconf.h> -#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H +#if HAVE_FREETYPE_H #ifdef USE_GCC_PRAGMAS #pragma implementation @@ -19,6 +19,7 @@ # include <unistd.h> #endif #include "gmem.h" +#include "gmempp.h" #include "GString.h" #include "gfile.h" #include "FoFiTrueType.h" @@ -87,13 +88,13 @@ SplashFontFile *SplashFTFontEngine::loadType1Font(SplashFontFileID *idA, GBool deleteFile, #endif const char **enc) { - return SplashFTFontFile::loadType1Font(this, idA, + return SplashFTFontFile::loadType1Font(this, idA, splashFontType1, #if LOAD_FONTS_FROM_MEM fontBuf, #else fileName, deleteFile, #endif - enc, gTrue); + enc); } SplashFontFile *SplashFTFontEngine::loadType1CFont(SplashFontFileID *idA, @@ -104,13 +105,13 @@ SplashFontFile *SplashFTFontEngine::loadType1CFont(SplashFontFileID *idA, GBool deleteFile, #endif const char **enc) { - return SplashFTFontFile::loadType1Font(this, idA, + return SplashFTFontFile::loadType1Font(this, idA, splashFontType1C, #if LOAD_FONTS_FROM_MEM fontBuf, #else fileName, deleteFile, #endif - enc, gFalse); + enc); } SplashFontFile *SplashFTFontEngine::loadOpenTypeT1CFont(SplashFontFileID *idA, @@ -143,8 +144,8 @@ SplashFontFile *SplashFTFontEngine::loadOpenTypeT1CFont(SplashFontFileID *idA, fontBuf2 = new GString(); ff->convertToType1(NULL, enc, gFalse, &gstringWrite, fontBuf2); delete ff; - ret = SplashFTFontFile::loadType1Font(this, idA, fontBuf2, enc, - gFalse); + ret = SplashFTFontFile::loadType1Font(this, idA, splashFontType1, + fontBuf2, enc); if (ret) { delete fontBuf; } else { @@ -159,8 +160,9 @@ SplashFontFile *SplashFTFontEngine::loadOpenTypeT1CFont(SplashFontFileID *idA, ff->convertToType1(NULL, enc, gFalse, &fileWrite, tmpFile); delete ff; fclose(tmpFile); - ret = SplashFTFontFile::loadType1Font(this, idA, tmpFileName->getCString(), - gTrue, enc, gFalse); + ret = SplashFTFontFile::loadType1Font(this, idA, splashFontType1, + tmpFileName->getCString(), + gTrue, enc); if (ret) { if (deleteFile) { unlink(fileName); @@ -172,32 +174,36 @@ SplashFontFile *SplashFTFontEngine::loadOpenTypeT1CFont(SplashFontFileID *idA, #endif } else { delete ff; - ret = SplashFTFontFile::loadType1Font(this, idA, + ret = SplashFTFontFile::loadType1Font(this, idA, splashFontOpenTypeT1C, #if LOAD_FONTS_FROM_MEM fontBuf, #else fileName, deleteFile, #endif - enc, gFalse); + enc); } return ret; } SplashFontFile *SplashFTFontEngine::loadCIDFont(SplashFontFileID *idA, #if LOAD_FONTS_FROM_MEM - GString *fontBuf + GString *fontBuf, #else char *fileName, - GBool deleteFile + GBool deleteFile, #endif - ) { + int *codeToGID, + int codeToGIDLen) { FoFiType1C *ff; int *cidToGIDMap; int nCIDs; SplashFontFile *ret; // check for a CFF font - if (useCIDs) { + if (codeToGID) { + cidToGIDMap = NULL; + nCIDs = 0; + } else if (useCIDs) { cidToGIDMap = NULL; nCIDs = 0; #if LOAD_FONTS_FROM_MEM @@ -212,13 +218,14 @@ SplashFontFile *SplashFTFontEngine::loadCIDFont(SplashFontFileID *idA, cidToGIDMap = NULL; nCIDs = 0; } - ret = SplashFTFontFile::loadCIDFont(this, idA, + ret = SplashFTFontFile::loadCIDFont(this, idA, splashFontCID, #if LOAD_FONTS_FROM_MEM fontBuf, #else fileName, deleteFile, #endif - cidToGIDMap, nCIDs); + codeToGID ? codeToGID : cidToGIDMap, + codeToGID ? codeToGIDLen : nCIDs); if (!ret) { gfree(cidToGIDMap); } @@ -266,8 +273,8 @@ SplashFontFile *SplashFTFontEngine::loadOpenTypeCFFFont(SplashFontFileID *idA, if (!useCIDs) { cidToGIDMap = ff->getCIDToGIDMap(&nCIDs); } - ret = SplashFTFontFile::loadCIDFont(this, idA, fontBuf2, - cidToGIDMap, nCIDs); + ret = SplashFTFontFile::loadCIDFont(this, idA, splashFontOpenTypeCFF, + fontBuf2, cidToGIDMap, nCIDs); if (ret) { delete fontBuf; } else { @@ -284,7 +291,7 @@ SplashFontFile *SplashFTFontEngine::loadOpenTypeCFFFont(SplashFontFileID *idA, if (!useCIDs) { cidToGIDMap = ff->getCIDToGIDMap(&nCIDs); } - ret = SplashFTFontFile::loadCIDFont(this, idA, + ret = SplashFTFontFile::loadCIDFont(this, idA, splashFontOpenTypeCFF, tmpFileName->getCString(), gTrue, cidToGIDMap, nCIDs); if (ret) { @@ -300,7 +307,7 @@ SplashFontFile *SplashFTFontEngine::loadOpenTypeCFFFont(SplashFontFileID *idA, if (!codeToGID && !useCIDs && ff->isOpenTypeCFF()) { cidToGIDMap = ff->getCIDToGIDMap(&nCIDs); } - ret = SplashFTFontFile::loadCIDFont(this, idA, + ret = SplashFTFontFile::loadCIDFont(this, idA, splashFontOpenTypeCFF, #if LOAD_FONTS_FROM_MEM fontBuf, #else @@ -356,7 +363,7 @@ SplashFontFile *SplashFTFontEngine::loadTrueTypeFont(SplashFontFileID *idA, fclose(tmpFile); #endif delete ff; - ret = SplashFTFontFile::loadTrueTypeFont(this, idA, + ret = SplashFTFontFile::loadTrueTypeFont(this, idA, splashFontTrueType, #if LOAD_FONTS_FROM_MEM fontBuf2, #else @@ -382,4 +389,4 @@ SplashFontFile *SplashFTFontEngine::loadTrueTypeFont(SplashFontFileID *idA, return ret; } -#endif // HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H +#endif // HAVE_FREETYPE_H diff --git a/Build/source/libs/xpdf/xpdf-src/splash/SplashFTFontEngine.h b/Build/source/libs/xpdf/xpdf-src/splash/SplashFTFontEngine.h index 37e882007fe..24db3c6cdba 100644 --- a/Build/source/libs/xpdf/xpdf-src/splash/SplashFTFontEngine.h +++ b/Build/source/libs/xpdf/xpdf-src/splash/SplashFTFontEngine.h @@ -11,7 +11,7 @@ #include <aconf.h> -#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H +#if HAVE_FREETYPE_H #ifdef USE_GCC_PRAGMAS #pragma interface @@ -60,11 +60,11 @@ public: const char **enc); SplashFontFile *loadCIDFont(SplashFontFileID *idA, #if LOAD_FONTS_FROM_MEM - GString *fontBuf + GString *fontBuf, #else - char *fileName, GBool deleteFile + char *fileName, GBool deleteFile, #endif - ); + int *codeToGID, int codeToGIDLen); SplashFontFile *loadOpenTypeCFFFont(SplashFontFileID *idA, #if LOAD_FONTS_FROM_MEM GString *fontBuf, @@ -94,6 +94,6 @@ private: friend class SplashFTFont; }; -#endif // HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H +#endif // HAVE_FREETYPE_H #endif diff --git a/Build/source/libs/xpdf/xpdf-src/splash/SplashFTFontFile.cc b/Build/source/libs/xpdf/xpdf-src/splash/SplashFTFontFile.cc index 5b01fcf490c..b5fd02af4a0 100644 --- a/Build/source/libs/xpdf/xpdf-src/splash/SplashFTFontFile.cc +++ b/Build/source/libs/xpdf/xpdf-src/splash/SplashFTFontFile.cc @@ -8,13 +8,14 @@ #include <aconf.h> -#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H +#if HAVE_FREETYPE_H #ifdef USE_GCC_PRAGMAS #pragma implementation #endif #include "gmem.h" +#include "gmempp.h" #include "GString.h" #include "SplashFTFontEngine.h" #include "SplashFTFont.h" @@ -26,14 +27,14 @@ SplashFontFile *SplashFTFontFile::loadType1Font(SplashFTFontEngine *engineA, SplashFontFileID *idA, + SplashFontType fontTypeA, #if LOAD_FONTS_FROM_MEM GString *fontBufA, #else char *fileNameA, GBool deleteFileA, #endif - const char **encA, - GBool useLightHintingA) { + const char **encA) { FT_Face faceA; int *codeToGIDA; const char *name; @@ -55,18 +56,18 @@ SplashFontFile *SplashFTFontFile::loadType1Font(SplashFTFontEngine *engineA, } } - return new SplashFTFontFile(engineA, idA, + return new SplashFTFontFile(engineA, idA, fontTypeA, #if LOAD_FONTS_FROM_MEM fontBufA, #else fileNameA, deleteFileA, #endif - faceA, codeToGIDA, 256, - gFalse, useLightHintingA); + faceA, codeToGIDA, 256); } SplashFontFile *SplashFTFontFile::loadCIDFont(SplashFTFontEngine *engineA, SplashFontFileID *idA, + SplashFontType fontTypeA, #if LOAD_FONTS_FROM_MEM GString *fontBufA, #else @@ -86,18 +87,18 @@ SplashFontFile *SplashFTFontFile::loadCIDFont(SplashFTFontEngine *engineA, return NULL; } - return new SplashFTFontFile(engineA, idA, + return new SplashFTFontFile(engineA, idA, fontTypeA, #if LOAD_FONTS_FROM_MEM fontBufA, #else fileNameA, deleteFileA, #endif - faceA, codeToGIDA, codeToGIDLenA, - gFalse, gFalse); + faceA, codeToGIDA, codeToGIDLenA); } SplashFontFile *SplashFTFontFile::loadTrueTypeFont(SplashFTFontEngine *engineA, SplashFontFileID *idA, + SplashFontType fontTypeA, #if LOAD_FONTS_FROM_MEM GString *fontBufA, #else @@ -118,38 +119,35 @@ SplashFontFile *SplashFTFontFile::loadTrueTypeFont(SplashFTFontEngine *engineA, return NULL; } - return new SplashFTFontFile(engineA, idA, + return new SplashFTFontFile(engineA, idA, fontTypeA, #if LOAD_FONTS_FROM_MEM fontBufA, #else fileNameA, deleteFileA, #endif - faceA, codeToGIDA, codeToGIDLenA, - gTrue, gFalse); + faceA, codeToGIDA, codeToGIDLenA); } SplashFTFontFile::SplashFTFontFile(SplashFTFontEngine *engineA, SplashFontFileID *idA, + SplashFontType fontTypeA, #if LOAD_FONTS_FROM_MEM GString *fontBufA, #else char *fileNameA, GBool deleteFileA, #endif FT_Face faceA, - int *codeToGIDA, int codeToGIDLenA, - GBool trueTypeA, GBool useLightHintingA): + int *codeToGIDA, int codeToGIDLenA): #if LOAD_FONTS_FROM_MEM - SplashFontFile(idA, fontBufA) + SplashFontFile(idA, fontTypeA, fontBufA) #else - SplashFontFile(idA, fileNameA, deleteFileA) + SplashFontFile(idA, fontTypeA, fileNameA, deleteFileA) #endif { engine = engineA; face = faceA; codeToGID = codeToGIDA; codeToGIDLen = codeToGIDLenA; - trueType = trueTypeA; - useLightHinting = useLightHintingA; } SplashFTFontFile::~SplashFTFontFile() { @@ -170,4 +168,4 @@ SplashFont *SplashFTFontFile::makeFont(SplashCoord *mat, return font; } -#endif // HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H +#endif // HAVE_FREETYPE_H diff --git a/Build/source/libs/xpdf/xpdf-src/splash/SplashFTFontFile.h b/Build/source/libs/xpdf/xpdf-src/splash/SplashFTFontFile.h index 21fa517a594..3a6b9b7aa43 100644 --- a/Build/source/libs/xpdf/xpdf-src/splash/SplashFTFontFile.h +++ b/Build/source/libs/xpdf/xpdf-src/splash/SplashFTFontFile.h @@ -11,7 +11,7 @@ #include <aconf.h> -#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H +#if HAVE_FREETYPE_H #ifdef USE_GCC_PRAGMAS #pragma interface @@ -33,15 +33,16 @@ public: static SplashFontFile *loadType1Font(SplashFTFontEngine *engineA, SplashFontFileID *idA, + SplashFontType fontTypeA, #if LOAD_FONTS_FROM_MEM GString *fontBufA, #else char *fileNameA, GBool deleteFileA, #endif - const char **encA, - GBool useLightHintingA); + const char **encA); static SplashFontFile *loadCIDFont(SplashFTFontEngine *engineA, SplashFontFileID *idA, + SplashFontType fontTypeA, #if LOAD_FONTS_FROM_MEM GString *fontBufA, #else @@ -50,6 +51,7 @@ public: int *codeToGIDA, int codeToGIDLenA); static SplashFontFile *loadTrueTypeFont(SplashFTFontEngine *engineA, SplashFontFileID *idA, + SplashFontType fontTypeA, #if LOAD_FONTS_FROM_MEM GString *fontBufA, #else @@ -71,25 +73,23 @@ private: SplashFTFontFile(SplashFTFontEngine *engineA, SplashFontFileID *idA, + SplashFontType fontTypeA, #if LOAD_FONTS_FROM_MEM GString *fontBufA, #else char *fileNameA, GBool deleteFileA, #endif FT_Face faceA, - int *codeToGIDA, int codeToGIDLenA, - GBool trueTypeA, GBool useLightHintingA); + int *codeToGIDA, int codeToGIDLenA); SplashFTFontEngine *engine; FT_Face face; int *codeToGID; int codeToGIDLen; - GBool trueType; - GBool useLightHinting; friend class SplashFTFont; }; -#endif // HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H +#endif // HAVE_FREETYPE_H #endif diff --git a/Build/source/libs/xpdf/xpdf-src/splash/SplashFont.cc b/Build/source/libs/xpdf/xpdf-src/splash/SplashFont.cc index 37a320050be..add34311756 100644 --- a/Build/source/libs/xpdf/xpdf-src/splash/SplashFont.cc +++ b/Build/source/libs/xpdf/xpdf-src/splash/SplashFont.cc @@ -14,6 +14,7 @@ #include <string.h> #include "gmem.h" +#include "gmempp.h" #include "SplashMath.h" #include "SplashGlyphBitmap.h" #include "SplashFontFile.h" @@ -66,6 +67,12 @@ void SplashFont::initCache() { // deal with rounding errors glyphW = xMax - xMin + 3; glyphH = yMax - yMin + 3; + if (glyphW > 1000 || glyphH > 1000) { + // if the glyphs are too large, don't cache them -- setting the + // cache bitmap size to something tiny will cause getGlyph() to + // fall back to the uncached case + glyphW = glyphH = 1; + } if (aa) { glyphSize = glyphW * glyphH; } else { @@ -76,7 +83,7 @@ void SplashFont::initCache() { cacheAssoc = splashFontCacheAssoc; for (cacheSets = splashFontCacheMaxSets; cacheSets > 1 && - cacheSets * cacheAssoc * glyphSize > splashFontCacheSize; + glyphSize > splashFontCacheSize / (cacheSets * cacheAssoc); cacheSets >>= 1) ; cache = (Guchar *)gmallocn(cacheSets * cacheAssoc, glyphSize); cacheTags = (SplashFontCacheTag *)gmallocn(cacheSets * cacheAssoc, diff --git a/Build/source/libs/xpdf/xpdf-src/splash/SplashFont.h b/Build/source/libs/xpdf/xpdf-src/splash/SplashFont.h index 3d151122a14..2bb96545867 100644 --- a/Build/source/libs/xpdf/xpdf-src/splash/SplashFont.h +++ b/Build/source/libs/xpdf/xpdf-src/splash/SplashFont.h @@ -17,6 +17,7 @@ #include "gtypes.h" #include "SplashTypes.h" +#include "SplashMath.h" struct SplashGlyphBitmap; struct SplashFontCacheTag; @@ -54,10 +55,14 @@ public: 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] && - textMatA[0] == textMat[0] && textMatA[1] == textMat[1] && - textMatA[2] == textMat[2] && textMatA[3] == textMat[3]; + splashAbs(matA[0] - mat[0]) < 0.0001 && + splashAbs(matA[1] - mat[1]) < 0.0001 && + splashAbs(matA[2] - mat[2]) < 0.0001 && + splashAbs(matA[3] - mat[3]) < 0.0001 && + splashAbs(textMatA[0] - textMat[0]) < 0.0001 && + splashAbs(textMatA[1] - textMat[1]) < 0.0001 && + splashAbs(textMatA[2] - textMat[2]) < 0.0001 && + splashAbs(textMatA[3] - textMat[3]) < 0.0001; } // Get a glyph - this does a cache lookup first, and if not found, diff --git a/Build/source/libs/xpdf/xpdf-src/splash/SplashFontEngine.cc b/Build/source/libs/xpdf/xpdf-src/splash/SplashFontEngine.cc index d4673a7a7c4..e435fe80c9a 100644 --- a/Build/source/libs/xpdf/xpdf-src/splash/SplashFontEngine.cc +++ b/Build/source/libs/xpdf/xpdf-src/splash/SplashFontEngine.cc @@ -18,6 +18,7 @@ # include <unistd.h> #endif #include "gmem.h" +#include "gmempp.h" #include "GString.h" #include "SplashMath.h" #include "SplashFTFontEngine.h" @@ -37,7 +38,7 @@ extern "C" int unlink(char *filename); //------------------------------------------------------------------------ SplashFontEngine::SplashFontEngine( -#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H +#if HAVE_FREETYPE_H GBool enableFreeType, Guint freeTypeFlags, #endif @@ -48,7 +49,7 @@ SplashFontEngine::SplashFontEngine( fontCache[i] = NULL; } -#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H +#if HAVE_FREETYPE_H if (enableFreeType) { ftEngine = SplashFTFontEngine::init(aa, freeTypeFlags); } else { @@ -66,7 +67,7 @@ SplashFontEngine::~SplashFontEngine() { } } -#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H +#if HAVE_FREETYPE_H if (ftEngine) { delete ftEngine; } @@ -99,7 +100,7 @@ SplashFontFile *SplashFontEngine::loadType1Font(SplashFontFileID *idA, SplashFontFile *fontFile; fontFile = NULL; -#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H +#if HAVE_FREETYPE_H if (!fontFile && ftEngine) { fontFile = ftEngine->loadType1Font(idA, #if LOAD_FONTS_FROM_MEM @@ -135,7 +136,7 @@ SplashFontFile *SplashFontEngine::loadType1CFont(SplashFontFileID *idA, SplashFontFile *fontFile; fontFile = NULL; -#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H +#if HAVE_FREETYPE_H if (!fontFile && ftEngine) { fontFile = ftEngine->loadType1CFont(idA, #if LOAD_FONTS_FROM_MEM @@ -171,7 +172,7 @@ SplashFontFile *SplashFontEngine::loadOpenTypeT1CFont(SplashFontFileID *idA, SplashFontFile *fontFile; fontFile = NULL; -#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H +#if HAVE_FREETYPE_H if (!fontFile && ftEngine) { fontFile = ftEngine->loadOpenTypeT1CFont(idA, #if LOAD_FONTS_FROM_MEM @@ -198,24 +199,25 @@ SplashFontFile *SplashFontEngine::loadOpenTypeT1CFont(SplashFontFileID *idA, SplashFontFile *SplashFontEngine::loadCIDFont(SplashFontFileID *idA, #if LOAD_FONTS_FROM_MEM - GString *fontBuf + GString *fontBuf, #else char *fileName, - GBool deleteFile + GBool deleteFile, #endif - ) { + int *codeToGID, + int codeToGIDLen) { SplashFontFile *fontFile; fontFile = NULL; -#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H +#if HAVE_FREETYPE_H if (!fontFile && ftEngine) { fontFile = ftEngine->loadCIDFont(idA, #if LOAD_FONTS_FROM_MEM - fontBuf + fontBuf, #else - fileName, deleteFile + fileName, deleteFile, #endif - ); + codeToGID, codeToGIDLen); } #endif @@ -244,7 +246,7 @@ SplashFontFile *SplashFontEngine::loadOpenTypeCFFFont(SplashFontFileID *idA, SplashFontFile *fontFile; fontFile = NULL; -#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H +#if HAVE_FREETYPE_H if (!fontFile && ftEngine) { fontFile = ftEngine->loadOpenTypeCFFFont(idA, #if LOAD_FONTS_FROM_MEM @@ -283,7 +285,7 @@ SplashFontFile *SplashFontEngine::loadTrueTypeFont(SplashFontFileID *idA, SplashFontFile *fontFile; fontFile = NULL; -#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H +#if HAVE_FREETYPE_H if (!fontFile && ftEngine) { fontFile = ftEngine->loadTrueTypeFont(idA, #if LOAD_FONTS_FROM_MEM diff --git a/Build/source/libs/xpdf/xpdf-src/splash/SplashFontEngine.h b/Build/source/libs/xpdf/xpdf-src/splash/SplashFontEngine.h index 43eb6d3eb48..ac2558ee52d 100644 --- a/Build/source/libs/xpdf/xpdf-src/splash/SplashFontEngine.h +++ b/Build/source/libs/xpdf/xpdf-src/splash/SplashFontEngine.h @@ -29,7 +29,7 @@ class SplashFont; #define splashFontCacheSize 16 -#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H +#if HAVE_FREETYPE_H #define splashFTNoHinting (1 << 0) #endif @@ -42,7 +42,7 @@ public: // Create a font engine. SplashFontEngine( -#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H +#if HAVE_FREETYPE_H GBool enableFreeType, Guint freeTypeFlags, #endif @@ -78,11 +78,11 @@ public: const char **enc); SplashFontFile *loadCIDFont(SplashFontFileID *idA, #if LOAD_FONTS_FROM_MEM - GString *fontBuf + GString *fontBuf, #else - char *fileName, GBool deleteFile + char *fileName, GBool deleteFile, #endif - ); + int *codeToGID, int codeToGIDLen); SplashFontFile *loadOpenTypeCFFFont(SplashFontFileID *idA, #if LOAD_FONTS_FROM_MEM GString *fontBuf, @@ -115,7 +115,7 @@ private: SplashFont *fontCache[splashFontCacheSize]; -#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H +#if HAVE_FREETYPE_H SplashFTFontEngine *ftEngine; #endif }; diff --git a/Build/source/libs/xpdf/xpdf-src/splash/SplashFontFile.cc b/Build/source/libs/xpdf/xpdf-src/splash/SplashFontFile.cc index d0e36a20c49..2d260e38239 100644 --- a/Build/source/libs/xpdf/xpdf-src/splash/SplashFontFile.cc +++ b/Build/source/libs/xpdf/xpdf-src/splash/SplashFontFile.cc @@ -16,6 +16,7 @@ #ifndef _WIN32 # include <unistd.h> #endif +#include "gmempp.h" #include "GString.h" #include "SplashFontFile.h" #include "SplashFontFileID.h" @@ -31,6 +32,7 @@ extern "C" int unlink(char *filename); //------------------------------------------------------------------------ SplashFontFile::SplashFontFile(SplashFontFileID *idA, + SplashFontType fontTypeA, #if LOAD_FONTS_FROM_MEM GString *fontBufA #else @@ -38,6 +40,7 @@ SplashFontFile::SplashFontFile(SplashFontFileID *idA, #endif ) { id = idA; + fontType = fontTypeA; #if LOAD_FONTS_FROM_MEM fontBuf = fontBufA; #else @@ -60,11 +63,22 @@ SplashFontFile::~SplashFontFile() { } void SplashFontFile::incRefCnt() { +#if MULTITHREADED + gAtomicIncrement(&refCnt); +#else ++refCnt; +#endif } void SplashFontFile::decRefCnt() { - if (!--refCnt) { + GBool done; + +#if MULTITHREADED + done = gAtomicDecrement(&refCnt) == 0; +#else + done = --refCnt == 0; +#endif + if (done) { delete this; } } diff --git a/Build/source/libs/xpdf/xpdf-src/splash/SplashFontFile.h b/Build/source/libs/xpdf/xpdf-src/splash/SplashFontFile.h index 5f53eced170..133e6ab87dc 100644 --- a/Build/source/libs/xpdf/xpdf-src/splash/SplashFontFile.h +++ b/Build/source/libs/xpdf/xpdf-src/splash/SplashFontFile.h @@ -18,12 +18,30 @@ #include "gtypes.h" #include "SplashTypes.h" +#if MULTITHREADED +#include "GMutex.h" +#endif + class GString; class SplashFontEngine; class SplashFont; class SplashFontFileID; //------------------------------------------------------------------------ +// SplashFontType +//------------------------------------------------------------------------ + +enum SplashFontType { + splashFontType1, // GfxFontType.fontType1 + splashFontType1C, // GfxFontType.fontType1C + splashFontOpenTypeT1C, // GfxFontType.fontType1COT + splashFontCID, // GfxFontType.fontCIDType0/fontCIDType0C + splashFontOpenTypeCFF, // GfxFontType.fontCIDType0COT + splashFontTrueType // GfxFontType.fontTrueType/fontTrueTypeOT/ + // fontCIDType2/fontCIDType2OT +}; + +//------------------------------------------------------------------------ // SplashFontFile //------------------------------------------------------------------------ @@ -49,6 +67,7 @@ public: protected: SplashFontFile(SplashFontFileID *idA, + SplashFontType fontTypeA, #if LOAD_FONTS_FROM_MEM GString *fontBufA #else @@ -57,13 +76,18 @@ protected: ); SplashFontFileID *id; + SplashFontType fontType; #if LOAD_FONTS_FROM_MEM GString *fontBuf; #else GString *fileName; GBool deleteFile; #endif +#if MULTITHREADED + GAtomicCounter refCnt; +#else int refCnt; +#endif friend class SplashFontEngine; }; diff --git a/Build/source/libs/xpdf/xpdf-src/splash/SplashFontFileID.cc b/Build/source/libs/xpdf/xpdf-src/splash/SplashFontFileID.cc index 327484788f6..27f52031d50 100644 --- a/Build/source/libs/xpdf/xpdf-src/splash/SplashFontFileID.cc +++ b/Build/source/libs/xpdf/xpdf-src/splash/SplashFontFileID.cc @@ -12,6 +12,7 @@ #pragma implementation #endif +#include "gmempp.h" #include "SplashFontFileID.h" //------------------------------------------------------------------------ diff --git a/Build/source/libs/xpdf/xpdf-src/splash/SplashMath.h b/Build/source/libs/xpdf/xpdf-src/splash/SplashMath.h index 4b7ab1fdfbd..b57c8fdacc5 100644 --- a/Build/source/libs/xpdf/xpdf-src/splash/SplashMath.h +++ b/Build/source/libs/xpdf/xpdf-src/splash/SplashMath.h @@ -12,9 +12,13 @@ #include <aconf.h> #if USE_FIXEDPONT -#include "FixedPoint.h" +# include "FixedPoint.h" #else -#include <math.h> +# include <math.h> +# if (defined(__GNUC__) && defined(__SSE2__)) || \ + (defined(_WIN32) && (_M_IX86_FP == 2 || defined(_M_X64))) +# include <emmintrin.h> +# endif #endif #include "SplashTypes.h" @@ -26,14 +30,40 @@ static inline SplashCoord splashAbs(SplashCoord x) { #endif } +// floor() and (int)() are implemented separately, which results +// in changing the FPCW multiple times - so we optimize it with +// some inline assembly or SSE intrinsics. static inline int splashFloor(SplashCoord x) { #if USE_FIXEDPOINT + + //--- fixed point + return FixedPoint::floor(x); -#else -#if __GNUC__ && __i386__ - // floor() and (int)() are implemented separately, which results - // in changing the FPCW multiple times - so we optimize it with - // some inline assembly + +#elif (defined(__GNUC__) && defined(__SSE2__)) || \ + (defined(_WIN32) && (_M_IX86_FP == 2 || defined(_M_X64))) + + //--- SSE2 intrinsics + // NB: 64-bit x86 guarantees availability of SSE2. + + __m128d m1, m2; + __m128i m3; + int s, i; + + m1 = _mm_set_sd(x); // m1 = x + i = _mm_cvttsd_si32(m1); // i = trunc(x) + m2 = _mm_cvtsi32_sd(m1, i); // m2 = (double)trunc(x) + m1 = _mm_sub_sd(m1, m2); // m1 = x - trunc(x) + m3 = _mm_castpd_si128(m1); // m3 = m1 (as 64-bit int) + m3 = _mm_srli_epi64(m3, 63); // m3 = m3 >> 63 + s = _mm_cvtsi128_si32(m3); // s = m3 = sign bit of x - trunc(x) + return i - s; // trunc(x) - sign bit + +#elif defined(__GNUC__) && defined(__i386__) && !defined(__APPLE__) + + //--- x87 inline assembly (gcc/clang) + // (this code fails on OSX for reasons I don't understand) + Gushort oldCW, newCW, t; int result; @@ -48,10 +78,11 @@ static inline int splashFloor(SplashCoord x) { : "=m" (oldCW), "=m" (newCW), "=m" (result), "=r" (t) : "t" (x)); return result; + #elif defined(_WIN32) && defined(_M_IX86) - // floor() and (int)() are implemented separately, which results - // in changing the FPCW multiple times - so we optimize it with - // some inline assembly + + //--- x87 inline assembly (VC) + Gushort oldCW, newCW; int result; @@ -65,20 +96,50 @@ static inline int splashFloor(SplashCoord x) { __asm fistp DWORD PTR result __asm fldcw WORD PTR oldCW return result; + #else + + //--- all others + return (int)floor(x); -#endif + #endif } +// ceil() and (int)() are implemented separately, which results +// in changing the FPCW multiple times - so we optimize it with +// some inline assembly or SSE intrinsics. static inline int splashCeil(SplashCoord x) { #if USE_FIXEDPOINT + + //--- fixed point + return FixedPoint::ceil(x); -#else -#if __GNUC__ && __i386__ - // ceil() and (int)() are implemented separately, which results - // in changing the FPCW multiple times - so we optimize it with - // some inline assembly + +#elif (defined(__GNUC__) && defined(__SSE2__)) || \ + (defined(_WIN32) && (_M_IX86_FP == 2 || defined(_M_X64))) + + //--- SSE2 intrinsics + // NB: 64-bit x86 guarantees availability of SSE2. + + __m128d m1, m2; + __m128i m3; + int s, i; + + m1 = _mm_set_sd(x); // m1 = x + i = _mm_cvttsd_si32(m1); // i = trunc(x) + m2 = _mm_cvtsi32_sd(m1, i); // m2 = (double)trunc(x) + m2 = _mm_sub_sd(m2, m1); // m2 = trunc(x) - x + m3 = _mm_castpd_si128(m2); // m3 = m2 (as 64-bit int) + m3 = _mm_srli_epi64(m3, 63); // m3 = m3 >> 63 + s = _mm_cvtsi128_si32(m3); // s = m3 = sign bit of x - trunc(x) + return i + s; // trunc(x) + sign bit + +#elif defined(__GNUC__) && defined(__i386__) && !defined(__APPLE__) + + //--- x87 inline assembly (gcc/clang) + // (this code fails on OSX for reasons I don't understand) + Gushort oldCW, newCW, t; int result; @@ -93,7 +154,11 @@ static inline int splashCeil(SplashCoord x) { : "=m" (oldCW), "=m" (newCW), "=m" (result), "=r" (t) : "t" (x)); return result; + #elif defined(_WIN32) && defined(_M_IX86) + + //--- x87 inline assembly (VC) + // ceil() and (int)() are implemented separately, which results // in changing the FPCW multiple times - so we optimize it with // some inline assembly @@ -110,56 +175,29 @@ static inline int splashCeil(SplashCoord x) { __asm fistp DWORD PTR result __asm fldcw WORD PTR oldCW return result; + #else + + //--- all others + return (int)ceil(x); -#endif + #endif } static inline int splashRound(SplashCoord x) { #if USE_FIXEDPOINT + + //--- fixed point + return FixedPoint::round(x); + #else -#if __GNUC__ && __i386__ - // this could use round-to-nearest mode and avoid the "+0.5", - // but that produces slightly different results (because i+0.5 - // sometimes rounds up and sometimes down using the even rule) - Gushort oldCW, newCW, t; - int result; - x += 0.5; - __asm__ volatile("fnstcw %0\n" - "movw %0, %3\n" - "andw $0xf3ff, %3\n" - "orw $0x0400, %3\n" - "movw %3, %1\n" // round down - "fldcw %1\n" - "fistl %2\n" - "fldcw %0\n" - : "=m" (oldCW), "=m" (newCW), "=m" (result), "=r" (t) - : "t" (x)); - return result; -#elif defined(_WIN32) && defined(_M_IX86) - // this could use round-to-nearest mode and avoid the "+0.5", - // but that produces slightly different results (because i+0.5 - // sometimes rounds up and sometimes down using the even rule) - Gushort oldCW, newCW; - int result; + //--- all others + + return splashFloor(x + 0.5); - x += 0.5; - __asm fld QWORD PTR x - __asm fnstcw WORD PTR oldCW - __asm mov ax, WORD PTR oldCW - __asm and ax, 0xf3ff - __asm or ax, 0x0400 - __asm mov WORD PTR newCW, ax // round down - __asm fldcw WORD PTR newCW - __asm fistp DWORD PTR result - __asm fldcw WORD PTR oldCW - return result; -#else - return (int)floor(x + 0.5); -#endif #endif } @@ -262,23 +300,53 @@ static inline GBool splashCheckDet(SplashCoord m11, SplashCoord m12, // but // xMin = 10.1 xMax = 11.3 (width = 1.2) // --> xMinI = 10 xMaxI = 12 (width = 2) +// +// 4. Use a hybrid approach, choosing between two of the above +// options, based on width. E.g., use #2 if width <= 4, and use #1 +// if width > 4. +// +// If w >= 0 and strokeAdjMode is splashStrokeAdjustCAD then a special +// mode for projecting line caps is enabled, with w being the +// transformed line width. + static inline void splashStrokeAdjust(SplashCoord xMin, SplashCoord xMax, - int *xMinI, int *xMaxI) { + int *xMinI, int *xMaxI, + SplashStrokeAdjustMode strokeAdjMode, + SplashCoord w = -1) { int x0, x1; - // NB: enable exactly one of these. + // this will never be called with strokeAdjMode == splashStrokeAdjustOff + if (strokeAdjMode == splashStrokeAdjustCAD) { + x0 = splashRound(xMin); + if (w >= 0) { + x1 = splashRound(xMax - w) + splashRound(w); + } else { + x1 = x0 + splashRound(xMax - xMin); + } + } else { + // NB: enable exactly one of these. #if 1 // 1. Round both edge coordinates. - x0 = splashRound(xMin); - x1 = splashRound(xMax); + x0 = splashRound(xMin); + x1 = splashRound(xMax); #endif #if 0 // 2. Round the min coordinate; add the ceiling of the width. - x0 = splashRound(xMin); - x1 = x0 + splashCeil(xMax - xMin); + x0 = splashRound(xMin); + x1 = x0 + splashCeil(xMax - xMin); #endif #if 0 // 3. Use floor on the min coord and ceiling on the max coord. - x0 = splashFloor(xMin); - x1 = splashCeil(xMax); + x0 = splashFloor(xMin); + x1 = splashCeil(xMax); #endif +#if 0 // 4. Hybrid. + SplashCoord w = xMax - xMin; + x0 = splashRound(xMin); + if (w > 4) { + x1 = splashRound(xMax); + } else { + x1 = x0 + splashRound(w); + } +#endif + } if (x1 == x0) { ++x1; } diff --git a/Build/source/libs/xpdf/xpdf-src/splash/SplashPath.cc b/Build/source/libs/xpdf/xpdf-src/splash/SplashPath.cc index 4ee8be02809..8bf2575a083 100644 --- a/Build/source/libs/xpdf/xpdf-src/splash/SplashPath.cc +++ b/Build/source/libs/xpdf/xpdf-src/splash/SplashPath.cc @@ -14,6 +14,7 @@ #include <string.h> #include "gmem.h" +#include "gmempp.h" #include "SplashErrorCodes.h" #include "SplashPath.h" @@ -156,7 +157,8 @@ SplashError SplashPath::close(GBool force) { } void SplashPath::addStrokeAdjustHint(int ctrl0, int ctrl1, - int firstPt, int lastPt) { + int firstPt, int lastPt, + GBool projectingCap) { if (hintsLength == hintsSize) { hintsSize = hintsLength ? 2 * hintsLength : 8; hints = (SplashPathHint *)greallocn(hints, hintsSize, @@ -166,6 +168,7 @@ void SplashPath::addStrokeAdjustHint(int ctrl0, int ctrl1, hints[hintsLength].ctrl1 = ctrl1; hints[hintsLength].firstPt = firstPt; hints[hintsLength].lastPt = lastPt; + hints[hintsLength].projectingCap = projectingCap; ++hintsLength; } @@ -186,3 +189,25 @@ GBool SplashPath::getCurPt(SplashCoord *x, SplashCoord *y) { *y = pts[length - 1].y; return gTrue; } + +GBool SplashPath::containsZeroLengthSubpaths() { + GBool zeroLength; + int i; + + zeroLength = gTrue; // make gcc happy + for (i = 0; i < length; ++i) { + if (flags[i] & splashPathFirst) { + zeroLength = gTrue; + } else { + if (pts[i].x != pts[i-1].x || pts[i].y != pts[i-1].y) { + zeroLength = gFalse; + } + if (flags[i] & splashPathLast) { + if (zeroLength) { + return gTrue; + } + } + } + } + return gFalse; +} diff --git a/Build/source/libs/xpdf/xpdf-src/splash/SplashPath.h b/Build/source/libs/xpdf/xpdf-src/splash/SplashPath.h index a8715302042..b5732b8b408 100644 --- a/Build/source/libs/xpdf/xpdf-src/splash/SplashPath.h +++ b/Build/source/libs/xpdf/xpdf-src/splash/SplashPath.h @@ -49,6 +49,7 @@ struct SplashPathPoint { struct SplashPathHint { int ctrl0, ctrl1; int firstPt, lastPt; + GBool projectingCap; }; //------------------------------------------------------------------------ @@ -89,7 +90,10 @@ public: // 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); + // <projectingCap> is true if the points are part of a projecting + // line cap. + void addStrokeAdjustHint(int ctrl0, int ctrl1, int firstPt, int lastPt, + GBool projectingCap = gFalse); // Add (<dx>, <dy>) to every point on this path. void offset(SplashCoord dx, SplashCoord dy); @@ -102,6 +106,10 @@ public: // Get the current point. GBool getCurPt(SplashCoord *x, SplashCoord *y); + // Returns true if the path contains one or more zero length + // subpaths. + GBool containsZeroLengthSubpaths(); + private: SplashPath(SplashPath *path); diff --git a/Build/source/libs/xpdf/xpdf-src/splash/SplashPattern.cc b/Build/source/libs/xpdf/xpdf-src/splash/SplashPattern.cc index 6ca4fb274e8..55ae865111c 100644 --- a/Build/source/libs/xpdf/xpdf-src/splash/SplashPattern.cc +++ b/Build/source/libs/xpdf/xpdf-src/splash/SplashPattern.cc @@ -12,6 +12,7 @@ #pragma implementation #endif +#include "gmempp.h" #include "SplashMath.h" #include "SplashScreen.h" #include "SplashPattern.h" diff --git a/Build/source/libs/xpdf/xpdf-src/splash/SplashScreen.cc b/Build/source/libs/xpdf/xpdf-src/splash/SplashScreen.cc index 68a762f7f2a..41c852531f1 100644 --- a/Build/source/libs/xpdf/xpdf-src/splash/SplashScreen.cc +++ b/Build/source/libs/xpdf/xpdf-src/splash/SplashScreen.cc @@ -18,6 +18,7 @@ #include <algorithm> #endif #include "gmem.h" +#include "gmempp.h" #include "SplashMath.h" #include "SplashScreen.h" diff --git a/Build/source/libs/xpdf/xpdf-src/splash/SplashScreen.h b/Build/source/libs/xpdf/xpdf-src/splash/SplashScreen.h index 4e9767be5f6..560e2759d82 100644 --- a/Build/source/libs/xpdf/xpdf-src/splash/SplashScreen.h +++ b/Build/source/libs/xpdf/xpdf-src/splash/SplashScreen.h @@ -21,6 +21,8 @@ // SplashScreen //------------------------------------------------------------------------ +typedef Guchar *SplashScreenCursor; + class SplashScreen { public: @@ -39,6 +41,20 @@ public: return value < mat[(yy << log2Size) + xx] ? 0 : 1; } + // To do a series of tests with the same y value, call + // getTestCursor(y), and then call testWithCursor(cursor, x, value) + // for each x. + SplashScreenCursor getTestCursor(int y) { + int yy; + yy = y & sizeM1; + return &mat[yy << log2Size]; + } + + int testWithCursor(SplashScreenCursor cursor, int x, Guchar value) { + int xx = x & sizeM1; + return value >= cursor[xx]; + } + // 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. diff --git a/Build/source/libs/xpdf/xpdf-src/splash/SplashState.cc b/Build/source/libs/xpdf/xpdf-src/splash/SplashState.cc index 09c1949eb3d..17ac8d17a19 100644 --- a/Build/source/libs/xpdf/xpdf-src/splash/SplashState.cc +++ b/Build/source/libs/xpdf/xpdf-src/splash/SplashState.cc @@ -14,6 +14,7 @@ #include <string.h> #include "gmem.h" +#include "gmempp.h" #include "SplashPattern.h" #include "SplashScreen.h" #include "SplashClip.h" @@ -55,7 +56,7 @@ SplashState::SplashState(int width, int height, GBool vectorAntialias, lineDash = NULL; lineDashLength = 0; lineDashPhase = 0; - strokeAdjust = gFalse; + strokeAdjust = splashStrokeAdjustOff; clip = new SplashClip(0, 0, width, height); clipIsShared = gFalse; softMask = NULL; @@ -67,12 +68,15 @@ SplashState::SplashState(int width, int height, GBool vectorAntialias, rgbTransferG[i] = (Guchar)i; rgbTransferB[i] = (Guchar)i; grayTransfer[i] = (Guchar)i; +#if SPLASH_CMYK cmykTransferC[i] = (Guchar)i; cmykTransferM[i] = (Guchar)i; cmykTransferY[i] = (Guchar)i; cmykTransferK[i] = (Guchar)i; +#endif } overprintMask = 0xffffffff; + enablePathSimplification = gFalse; next = NULL; } @@ -99,7 +103,7 @@ SplashState::SplashState(int width, int height, GBool vectorAntialias, lineDash = NULL; lineDashLength = 0; lineDashPhase = 0; - strokeAdjust = gFalse; + strokeAdjust = splashStrokeAdjustOff; clip = new SplashClip(0, 0, width, height); clipIsShared = gFalse; softMask = NULL; @@ -111,12 +115,15 @@ SplashState::SplashState(int width, int height, GBool vectorAntialias, rgbTransferG[i] = (Guchar)i; rgbTransferB[i] = (Guchar)i; grayTransfer[i] = (Guchar)i; +#if SPLASH_CMYK cmykTransferC[i] = (Guchar)i; cmykTransferM[i] = (Guchar)i; cmykTransferY[i] = (Guchar)i; cmykTransferK[i] = (Guchar)i; +#endif } overprintMask = 0xffffffff; + enablePathSimplification = gFalse; next = NULL; } @@ -153,11 +160,14 @@ SplashState::SplashState(SplashState *state) { memcpy(rgbTransferG, state->rgbTransferG, 256); memcpy(rgbTransferB, state->rgbTransferB, 256); memcpy(grayTransfer, state->grayTransfer, 256); +#if SPLASH_CMYK memcpy(cmykTransferC, state->cmykTransferC, 256); memcpy(cmykTransferM, state->cmykTransferM, 256); memcpy(cmykTransferY, state->cmykTransferY, 256); memcpy(cmykTransferK, state->cmykTransferK, 256); +#endif overprintMask = state->overprintMask; + enablePathSimplification = state->enablePathSimplification; next = NULL; } @@ -202,6 +212,32 @@ void SplashState::setLineDash(SplashCoord *lineDashA, int lineDashLengthA, lineDashPhase = lineDashPhaseA; } +GBool SplashState::lineDashContainsZeroLengthDashes() { + int i; + + if (lineDashLength == 0) { + return gFalse; + } + + // if the line dash array has an odd number of elements, we need to + // check all of the elements; if the length is even, we only need to + // check even-number elements + if (lineDashLength & 1) { + for (i = 0; i < lineDashLength; ++i) { + if (lineDash[i] == 0) { + return gTrue; + } + } + } else { + for (i = 0; i < lineDashLength; i += 2) { + if (lineDash[i] == 0) { + return gTrue; + } + } + } + return gFalse; +} + void SplashState::clipResetToRect(SplashCoord x0, SplashCoord y0, SplashCoord x1, SplashCoord y1) { if (clipIsShared) { @@ -225,7 +261,8 @@ SplashError SplashState::clipToPath(SplashPath *path, GBool eo) { clip = clip->copy(); clipIsShared = gFalse; } - return clip->clipToPath(path, matrix, flatness, eo); + return clip->clipToPath(path, matrix, flatness, eo, + enablePathSimplification, strokeAdjust); } void SplashState::setSoftMask(SplashBitmap *softMaskA) { @@ -238,16 +275,20 @@ void SplashState::setSoftMask(SplashBitmap *softMaskA) { void SplashState::setTransfer(Guchar *red, Guchar *green, Guchar *blue, Guchar *gray) { +#if SPLASH_CMYK int i; +#endif memcpy(rgbTransferR, red, 256); memcpy(rgbTransferG, green, 256); memcpy(rgbTransferB, blue, 256); memcpy(grayTransfer, gray, 256); +#if SPLASH_CMYK for (i = 0; i < 256; ++i) { cmykTransferC[i] = 255 - rgbTransferR[255 - i]; cmykTransferM[i] = 255 - rgbTransferG[255 - i]; cmykTransferY[i] = 255 - rgbTransferB[255 - i]; cmykTransferK[i] = 255 - grayTransfer[255 - i]; } +#endif } diff --git a/Build/source/libs/xpdf/xpdf-src/splash/SplashState.h b/Build/source/libs/xpdf/xpdf-src/splash/SplashState.h index fe773a5403f..2a957cecd19 100644 --- a/Build/source/libs/xpdf/xpdf-src/splash/SplashState.h +++ b/Build/source/libs/xpdf/xpdf-src/splash/SplashState.h @@ -70,6 +70,10 @@ public: void setLineDash(SplashCoord *lineDashA, int lineDashLengthA, SplashCoord lineDashPhaseA); + // Returns true if the current line dash pattern contains one or + // more zero-length "on" sections (dashes). + GBool lineDashContainsZeroLengthDashes(); + void clipResetToRect(SplashCoord x0, SplashCoord y0, SplashCoord x1, SplashCoord y1); SplashError clipToRect(SplashCoord x0, SplashCoord y0, @@ -101,7 +105,7 @@ private: SplashCoord *lineDash; int lineDashLength; SplashCoord lineDashPhase; - GBool strokeAdjust; + SplashStrokeAdjustMode strokeAdjust; SplashClip *clip; GBool clipIsShared; SplashBitmap *softMask; @@ -112,11 +116,14 @@ private: rgbTransferG[256], rgbTransferB[256]; Guchar grayTransfer[256]; +#if SPLASH_CMYK Guchar cmykTransferC[256], cmykTransferM[256], cmykTransferY[256], cmykTransferK[256]; +#endif Guint overprintMask; + GBool enablePathSimplification; SplashState *next; // used by Splash class diff --git a/Build/source/libs/xpdf/xpdf-src/splash/SplashTypes.h b/Build/source/libs/xpdf/xpdf-src/splash/SplashTypes.h index 240cb6f7b8c..0e1829dcf1d 100644 --- a/Build/source/libs/xpdf/xpdf-src/splash/SplashTypes.h +++ b/Build/source/libs/xpdf/xpdf-src/splash/SplashTypes.h @@ -107,6 +107,16 @@ typedef void (*SplashBlendFunc)(SplashColorPtr src, SplashColorPtr dest, SplashColorPtr blend, SplashColorMode cm); //------------------------------------------------------------------------ +// stroke adjustment mode +//------------------------------------------------------------------------ + +enum SplashStrokeAdjustMode { + splashStrokeAdjustOff, + splashStrokeAdjustNormal, + splashStrokeAdjustCAD +}; + +//------------------------------------------------------------------------ // screen parameters //------------------------------------------------------------------------ diff --git a/Build/source/libs/xpdf/xpdf-src/splash/SplashXPath.cc b/Build/source/libs/xpdf/xpdf-src/splash/SplashXPath.cc index a1599885e2b..f0164a85bd4 100644 --- a/Build/source/libs/xpdf/xpdf-src/splash/SplashXPath.cc +++ b/Build/source/libs/xpdf/xpdf-src/splash/SplashXPath.cc @@ -18,12 +18,18 @@ #include <algorithm> #endif #include "gmem.h" +#include "gmempp.h" #include "SplashMath.h" #include "SplashPath.h" #include "SplashXPath.h" //------------------------------------------------------------------------ +#define minCosSquaredJoinAngle 0.75 +#define maxPointToLineDistanceSquared 0.04 + +//------------------------------------------------------------------------ + struct SplashXPathPoint { SplashCoord x, y; }; @@ -54,29 +60,58 @@ inline void SplashXPath::transform(SplashCoord *matrix, // SplashXPath //------------------------------------------------------------------------ +// SplashXPath segment coords are clipped to +/-maxCoord to avoid +// problems. The xMin/yMin/xMax/yMax fields are 32-bit integers, so +// coords need to be < 2^31 / aa{Horiz,Vert}. +#define maxCoord 100000000.0 + +void SplashXPath::clampCoords(SplashCoord *x, SplashCoord *y) { +#if !USE_FIXEDPOINT + if (*x > maxCoord) { + *x = maxCoord; + } else if (*x < -maxCoord) { + *x = -maxCoord; + } + if (*y > maxCoord) { + *y = maxCoord; + } else if (*y < -maxCoord) { + *y = -maxCoord; + } +#endif +} + SplashXPath::SplashXPath(SplashPath *path, SplashCoord *matrix, - SplashCoord flatness, GBool closeSubpaths) { + SplashCoord flatness, GBool closeSubpaths, + GBool simplify, + SplashStrokeAdjustMode strokeAdjMode) { SplashXPathPoint *pts; - SplashCoord x0, y0, x1, y1, x2, y2, x3, y3, xsp, ysp; - SplashCoord xMinFP, xMaxFP, yMinFP, yMaxFP; - int curSubpath, i; + SplashCoord x0, y0, x1, y1, x2, y2, x3, y3, xsp, ysp, t; + int curSubpath, firstSegInSubpath, i; + GBool adjusted; - // transform the points + //--- 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); + clampCoords(&pts[i].x, &pts[i].y); } - // do stroke adjustment + //--- do stroke adjustment if (path->hints) { - strokeAdjust(pts, path->hints, path->hintsLength); + adjusted = strokeAdjust(pts, path->hints, path->hintsLength, + strokeAdjMode); + } else { + adjusted = gFalse; } + //--- construct the segments + segs = NULL; length = size = 0; x0 = y0 = xsp = ysp = 0; // make gcc happy curSubpath = 0; + firstSegInSubpath = 0; i = 0; while (i < path->length) { @@ -123,66 +158,85 @@ SplashXPath::SplashXPath(SplashPath *path, SplashCoord *matrix, ++i; } - // close a subpath - if (closeSubpaths && - (path->flags[i-1] & splashPathLast) && - (pts[i-1].x != pts[curSubpath].x || - pts[i-1].y != pts[curSubpath].y)) { - addSegment(x0, y0, xsp, ysp); + // end a subpath + if (path->flags[i-1] & splashPathLast) { + if (closeSubpaths && + (pts[i-1].x != pts[curSubpath].x || + pts[i-1].y != pts[curSubpath].y)) { + addSegment(x0, y0, xsp, ysp); + } + if (simplify && !adjusted) { + mergeSegments(firstSegInSubpath); + } + firstSegInSubpath = length; } } } gfree(pts); + finishSegments(); + + //--- check for a rectangle + isRect = gFalse; + rectX0 = rectY0 = rectX1 = rectY1 = 0; + if (length == 4) { #if HAVE_STD_SORT - std::sort(segs, segs + length, SplashXPathSeg::cmpY); + std::sort(segs, segs + length, SplashXPathSeg::cmpY); #else - qsort(segs, length, sizeof(SplashXPathSeg), &SplashXPathSeg::cmpY); + qsort(segs, length, sizeof(SplashXPathSeg), &SplashXPathSeg::cmpY); #endif - - if (length == 0) { - xMin = yMin = xMax = yMax = 0; - } else { - if (segs[0].x0 < segs[0].x1) { - xMinFP = segs[0].x0; - xMaxFP = segs[0].x1; - } else { - xMinFP = segs[0].x1; - xMaxFP = segs[0].x0; + if (segs[0].y0 == segs[0].y1 && + segs[1].x0 == segs[1].x1 && + segs[2].x0 == segs[2].x1 && + segs[3].y0 == segs[3].y1) { + isRect = gTrue; + rectX0 = segs[1].x0; + rectX1 = segs[2].x0; + rectY0 = segs[0].y0; + rectY1 = segs[3].y0; + } else if (segs[0].x0 == segs[0].x1 && + segs[1].y0 == segs[1].y1 && + segs[2].x0 == segs[2].x1 && + segs[3].y0 == segs[3].y1) { + isRect = gTrue; + rectX0 = segs[0].x0; + rectX1 = segs[2].x0; + rectY0 = segs[1].y0; + rectY1 = segs[3].y0; + } else if (segs[0].x0 == segs[0].x1 && + segs[1].x0 == segs[1].x1 && + segs[2].y0 == segs[2].y1 && + segs[3].y0 == segs[3].y1) { + isRect = gTrue; + rectX0 = segs[0].x0; + rectX1 = segs[1].x0; + rectY0 = segs[2].y0; + rectY1 = segs[3].y0; } - yMinFP = segs[0].y0; - yMaxFP = segs[0].y1; - for (i = 1; i < length; ++i) { - if (segs[i].x0 < xMinFP) { - xMinFP = segs[i].x0; - } else if (segs[i].x0 > xMaxFP) { - xMaxFP = segs[i].x0; - } - if (segs[i].x1 < xMinFP) { - xMinFP = segs[i].x1; - } else if (segs[i].x1 > xMaxFP) { - xMaxFP = segs[i].x1; + if (isRect) { + if (rectX0 > rectX1) { + t = rectX0; rectX0 = rectX1; rectX1 = t; } - if (segs[i].y1 > yMaxFP) { - yMaxFP = segs[i].y1; + if (rectY0 > rectY1) { + t = rectY0; rectY0 = rectY1; rectY1 = t; } } - xMin = splashFloor(xMinFP); - yMin = splashFloor(yMinFP); - xMax = splashFloor(xMaxFP); - yMax = splashFloor(yMaxFP); } } -void SplashXPath::strokeAdjust(SplashXPathPoint *pts, - SplashPathHint *hints, int nHints) { +GBool SplashXPath::strokeAdjust(SplashXPathPoint *pts, + SplashPathHint *hints, int nHints, + SplashStrokeAdjustMode strokeAdjMode) { SplashXPathAdjust *adjusts, *adjust; SplashPathHint *hint; SplashCoord x0, y0, x1, y1, x2, y2, x3, y3; - SplashCoord adj0, adj1, d; + SplashCoord adj0, adj1, w, d; int xi0, xi1; int i, j; + GBool adjusted; + + adjusted = gFalse; // set up the stroke adjustment hints adjusts = (SplashXPathAdjust *)gmallocn(nHints, sizeof(SplashXPathAdjust)); @@ -192,14 +246,21 @@ void SplashXPath::strokeAdjust(SplashXPathPoint *pts, 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; + w = -1; if (x0 == x1 && x2 == x3) { adjusts[i].vert = gTrue; adj0 = x0; adj1 = x2; + if (hint->projectingCap) { + w = splashAbs(y1 - y0); + } } else if (y0 == y1 && y2 == y3) { adjusts[i].vert = gFalse; adj0 = y0; adj1 = y2; + if (hint->projectingCap) { + w = splashAbs(x1 - x0); + } } else { goto done; } @@ -220,7 +281,7 @@ void SplashXPath::strokeAdjust(SplashXPathPoint *pts, adjusts[i].xmb = (SplashCoord)0.5 * (adj0 + adj1) + d; adjusts[i].x1a = adj1 - d; adjusts[i].x1b = adj1 + d; - splashStrokeAdjust(adj0, adj1, &xi0, &xi1); + splashStrokeAdjust(adj0, adj1, &xi0, &xi1, strokeAdjMode, w); adjusts[i].x0 = (SplashCoord)xi0; // the "minus epsilon" thing here is needed when vector // antialiasing is turned off -- otherwise stroke adjusted lines @@ -255,9 +316,11 @@ void SplashXPath::strokeAdjust(SplashXPathPoint *pts, } } } + adjusted = gTrue; done: gfree(adjusts); + return adjusted; } SplashXPath::SplashXPath(SplashXPath *xPath) { @@ -380,38 +443,202 @@ void SplashXPath::addCurve(SplashCoord x0, SplashCoord y0, void SplashXPath::addSegment(SplashCoord x0, SplashCoord y0, SplashCoord x1, SplashCoord y1) { grow(1); - if (y0 <= y1) { - segs[length].x0 = x0; - segs[length].y0 = y0; - segs[length].x1 = x1; - segs[length].y1 = y1; - segs[length].count = 1; - } else { - segs[length].x0 = x1; - segs[length].y0 = y1; - segs[length].x1 = x0; - segs[length].y1 = y0; - segs[length].count = -1; + segs[length].x0 = x0; + segs[length].y0 = y0; + segs[length].x1 = x1; + segs[length].y1 = y1; + ++length; +} + +// Returns true if the angle between (x0,y0)-(x1,y1) and +// (x1,y1)-(x2,y2) is close to 180 degrees. +static GBool joinAngleIsFlat(SplashCoord x0, SplashCoord y0, + SplashCoord x1, SplashCoord y1, + SplashCoord x2, SplashCoord y2) { + SplashCoord dx1, dy1, dx2, dy2, d, len1, len2; + + dx1 = x1 - x0; + dy1 = y1 - y0; + dx2 = x2 - x1; + dy2 = y2 - y1; + d = dx1 * dx2 + dy1 * dy2; + len1 = dx1 * dx1 + dy1 * dy1; + len2 = dx2 * dx2 + dy2 * dy2; + return d > 0 && d * d > len1 * len2 * minCosSquaredJoinAngle; +} + +// Returns true if (x1,y1) is sufficiently close to the segment +// (x0,y0)-(x2,y2), looking at the perpendicular point-to-line +// distance. +static GBool pointCloseToSegment(SplashCoord x0, SplashCoord y0, + SplashCoord x1, SplashCoord y1, + SplashCoord x2, SplashCoord y2) { + SplashCoord t1, t2, dx, dy; + + // compute the perpendicular distance from the point to the segment, + // i.e., the projection of (x0,y0)-(x1,y1) onto a unit normal to the + // segment (this actually computes the square of the distance) + dx = x2 - x0; + dy = y2 - y0; + t1 = dx*dx + dy*dy; + if (t1 < 0.0001) { + // degenerate case: (x0,y0) and (x2,y2) are (nearly) identical -- + // just compute the distance to (x1,y1) + dx = x0 - x1; + dy = y0 - y1; + t2 = dx*dx + dy*dy; + return t2 < maxPointToLineDistanceSquared; } -#if USE_FIXEDPOINT - if (y0 == y1 || x0 == x1 || - !FixedPoint::divCheck(x1 - x0, y1 - y0, &segs[length].dxdy) || - !FixedPoint::divCheck(y1 - y0, x1 - x0, &segs[length].dydx)) { - segs[length].dxdy = 0; - segs[length].dydx = 0; + t2 = x1 * dy - dx * y1 - x0 * y2 + x2 * y0; + // actual distance = t2 / sqrt(t1) + return t2 * t2 < t1 * maxPointToLineDistanceSquared; +} + +// Attempt to simplify the path by merging sequences of consecutive +// segments in [first] .. [length]-1. +void SplashXPath::mergeSegments(int first) { + GBool horiz, vert; + int in, out, prev, i, j; + + in = out = first; + while (in < length) { + + // skip zero-length segments + if (segs[in].x0 == segs[in].x1 && segs[in].y0 == segs[in].y1) { + ++in; + continue; + } + + horiz = segs[in].y0 == segs[in].y1; + vert = segs[in].x0 == segs[in].x1; + + // check for a sequence of mergeable segments: in .. i + prev = in; + for (i = in + 1; i < length; ++i) { + + // skip zero-length segments + if (segs[i].x0 == segs[i].x1 && segs[i].y0 == segs[i].y1) { + continue; + } + + // check for a horizontal or vertical segment + if ((horiz && segs[in].y0 != segs[in].y1) || + (vert && segs[in].x0 != segs[in].x1)) { + break; + } + + // check the angle between segs i-1 and i + // (actually, we compare seg i to the previous non-zero-length + // segment, which may not be i-1) + if (!joinAngleIsFlat(segs[prev].x0, segs[prev].y0, + segs[i].x0, segs[i].y0, + segs[i].x1, segs[i].y1)) { + break; + } + + // check the distances from the ends of segs in .. i-1 to the + // proposed new segment + for (j = in; j < i; ++j) { + if (!pointCloseToSegment(segs[in].x0, segs[in].y0, + segs[j].x1, segs[j].y1, + segs[i].x1, segs[i].y1)) { + break; + } + } + if (j < i) { + break; + } + + prev = i; + } + + // we can merge segs: in .. i-1 + // (this may be the single segment: in) + segs[out].x0 = segs[in].x0; + segs[out].y0 = segs[in].y0; + segs[out].x1 = segs[i-1].x1; + segs[out].y1 = segs[i-1].y1; + in = i; + ++out; } + + length = out; +} + +void SplashXPath::finishSegments() { + SplashXPathSeg *seg; + SplashCoord xMinFP, xMaxFP, yMinFP, yMaxFP, t; + int i; + + xMinFP = yMinFP = xMaxFP = yMaxFP = 0; + + for (i = 0; i < length; ++i) { + seg = &segs[i]; + + //--- compute the slopes + if (seg->y0 <= seg->y1) { + seg->count = 1; + } else { + t = seg->x0; seg->x0 = seg->x1; seg->x1 = t; + t = seg->y0; seg->y0 = seg->y1; seg->y1 = t; + seg->count = -1; + } +#if USE_FIXEDPOINT + if (seg->y0 == seg->y1 || seg->x0 == seg->x1 || + !FixedPoint::divCheck(seg->x1 - seg->x0, seg->y1 - seg->y0, + &seg->dxdy) || + !FixedPoint::divCheck(seg->y1 - seg->y0, seg->x1 - seg->x0, + &seg->dydx)) { + seg->dxdy = 0; + seg->dydx = 0; + } #else - if (y0 == y1 || x0 == x1) { - segs[length].dxdy = 0; - segs[length].dydx = 0; - } else { - segs[length].dxdy = (x1 - x0) / (y1 - y0); - if (segs[length].dxdy == 0) { - segs[length].dydx = 0; + if (seg->y0 == seg->y1 || seg->x0 == seg->x1) { + seg->dxdy = 0; + seg->dydx = 0; } else { - segs[length].dydx = 1 / segs[length].dxdy; + seg->dxdy = (seg->x1 - seg->x0) / (seg->y1 - seg->y0); + if (seg->dxdy == 0) { + seg->dydx = 0; + } else { + seg->dydx = 1 / seg->dxdy; + } } - } #endif - ++length; + + //--- update bbox + if (i == 0) { + if (seg->x0 <= seg->x1) { + xMinFP = seg->x0; + xMaxFP = seg->x1; + } else { + xMinFP = seg->x1; + xMaxFP = seg->x0; + } + yMinFP = seg->y0; + yMaxFP = seg->y1; + } else { + if (seg->x0 < xMinFP) { + xMinFP = seg->x0; + } else if (seg->x0 > xMaxFP) { + xMaxFP = seg->x0; + } + if (seg->x1 < xMinFP) { + xMinFP = seg->x1; + } else if (seg->x1 > xMaxFP) { + xMaxFP = seg->x1; + } + if (seg->y0 < yMinFP) { + yMinFP = seg->y0; + } + if (seg->y1 > yMaxFP) { + yMaxFP = seg->y1; + } + } + } + + xMin = splashFloor(xMinFP); + yMin = splashFloor(yMinFP); + xMax = splashFloor(xMaxFP); + yMax = splashFloor(yMaxFP); } diff --git a/Build/source/libs/xpdf/xpdf-src/splash/SplashXPath.h b/Build/source/libs/xpdf/xpdf-src/splash/SplashXPath.h index 5bcec61cd25..82d7889c447 100644 --- a/Build/source/libs/xpdf/xpdf-src/splash/SplashXPath.h +++ b/Build/source/libs/xpdf/xpdf-src/splash/SplashXPath.h @@ -37,36 +37,48 @@ struct SplashXPathSeg { int count; // EO/NZWN counter increment //----- used by SplashXPathScanner - SplashCoord xCur0, xCur1; // current x values + int iy; + SplashCoord sx0, sx1, mx; + SplashXPathSeg *prev, *next; #if HAVE_STD_SORT + + static bool cmpMX(const SplashXPathSeg &s0, + const SplashXPathSeg &s1) { + if (s0.iy != s1.iy) { + return s0.iy < s1.iy; + } + return s0.mx < s1.mx; + } + static bool cmpY(const SplashXPathSeg &seg0, const SplashXPathSeg &seg1) { return seg0.y0 < seg1.y0; } + #else - static int cmpY(const void *seg0, const void *seg1) { + + static int cmpMX(const void *p0, const void *p1) { + SplashXPathSeg *s0 = (SplashXPathSeg *)p0; + SplashXPathSeg *s1 = (SplashXPathSeg *)p1; SplashCoord cmp; - cmp = ((SplashXPathSeg *)seg0)->y0 - - ((SplashXPathSeg *)seg1)->y0; - return (cmp > 0) ? 1 : (cmp < 0) ? -1 : 0; + if (s0->iy != s1->iy) { + return s0->iy - s1->iy; + } + cmp = s0->mx - s1->mx; + return (cmp < 0) ? -1 : (cmp > 0) ? 1 : 0; } -#endif - static int cmpX(SplashXPathSeg *seg0, SplashXPathSeg *seg1) { + static int cmpY(const void *seg0, const void *seg1) { SplashCoord cmp; - if ((cmp = seg0->xCur0 - seg1->xCur0) == 0) { - cmp = seg0->dxdy - seg1->dxdy; - } + cmp = ((SplashXPathSeg *)seg0)->y0 + - ((SplashXPathSeg *)seg1)->y0; return (cmp > 0) ? 1 : (cmp < 0) ? -1 : 0; } - static int cmpXi(const void *p0, const void *p1) { - return cmpX(*(SplashXPathSeg **)p0, *(SplashXPathSeg **)p1); - } - +#endif }; //------------------------------------------------------------------------ @@ -81,7 +93,8 @@ public: // space, via <matrix>. If <closeSubpaths> is true, closes all open // subpaths. SplashXPath(SplashPath *path, SplashCoord *matrix, - SplashCoord flatness, GBool closeSubpaths); + SplashCoord flatness, GBool closeSubpaths, + GBool simplify, SplashStrokeAdjustMode strokeAdjMode); // Copy an expanded path. SplashXPath *copy() { return new SplashXPath(this); } @@ -95,11 +108,13 @@ public: private: + static void clampCoords(SplashCoord *x, SplashCoord *y); SplashXPath(SplashXPath *xPath); void transform(SplashCoord *matrix, SplashCoord xi, SplashCoord yi, SplashCoord *xo, SplashCoord *yo); - void strokeAdjust(SplashXPathPoint *pts, - SplashPathHint *hints, int nHints); + GBool strokeAdjust(SplashXPathPoint *pts, + SplashPathHint *hints, int nHints, + SplashStrokeAdjustMode strokeAdjMode); void grow(int nSegs); void addCurve(SplashCoord x0, SplashCoord y0, SplashCoord x1, SplashCoord y1, @@ -107,14 +122,19 @@ private: SplashCoord x3, SplashCoord y3, SplashCoord flatness, GBool first, GBool last, GBool end0, GBool end1); + void mergeSegments(int first); void addSegment(SplashCoord x0, SplashCoord y0, SplashCoord x1, SplashCoord y1); + void finishSegments(); SplashXPathSeg *segs; int length, size; // length and size of segs array int xMin, xMax; int yMin, yMax; + GBool isRect; + SplashCoord rectX0, rectY0, rectX1, rectY1; + friend class SplashXPathScanner; friend class SplashClip; friend class Splash; diff --git a/Build/source/libs/xpdf/xpdf-src/splash/SplashXPathScanner.cc b/Build/source/libs/xpdf/xpdf-src/splash/SplashXPathScanner.cc index aee60cce61e..3f167b8b311 100644 --- a/Build/source/libs/xpdf/xpdf-src/splash/SplashXPathScanner.cc +++ b/Build/source/libs/xpdf/xpdf-src/splash/SplashXPathScanner.cc @@ -18,6 +18,7 @@ #include <algorithm> #endif #include "gmem.h" +#include "gmempp.h" #include "GList.h" #include "SplashMath.h" #include "SplashXPath.h" @@ -25,543 +26,595 @@ //------------------------------------------------------------------------ -#define minVertStep 0.05 +#if ANTIALIAS_256 + +#define aaVert 15 +#define aaHoriz 17 + +#else + +#define aaVert 4 +#define aaHoriz 4 + +static Guchar map16to255[17] = { + 0, + 16, + 32, + 48, + 64, + 80, + 96, + 112, + 128, + 143, + 159, + 175, + 191, + 207, + 223, + 239, + 255 +}; + +#endif //------------------------------------------------------------------------ -SplashXPathScanner::SplashXPathScanner(SplashXPath *xPathA, GBool eoA, +SplashXPathScanner::SplashXPathScanner(SplashXPath *xPathA, GBool eo, int yMinA, int yMaxA) { xPath = xPathA; - eo = eoA; + eoMask = eo ? 1 : 0xffffffff; yMin = yMinA; yMax = yMaxA; + if (xPath->isRect) { + rectX0I = splashFloor(xPath->rectX0); + rectY0I = splashFloor(xPath->rectY0); + rectX1I = splashFloor(xPath->rectX1); + rectY1I = splashFloor(xPath->rectY1); + } - activeSegs = new GList(); - nextSeg = 0; - yNext = xPath->yMin; + pre = &preSeg; + post = &postSeg; + pre->mx = xPath->xMin - 1; + post->mx = xPath->xMax + 1; + + resetDone = gFalse; + resetAA = gFalse; } SplashXPathScanner::~SplashXPathScanner() { - delete activeSegs; } -void SplashXPathScanner::getSpan(Guchar *line, int y, int x0, int x1) { - SplashXPathSeg *seg, *seg0; - SplashCoord y0, y1, y1p; - GBool intersect, last; - int eoMask, state0, state1, count, i; +void SplashXPathScanner::insertSegmentBefore(SplashXPathSeg *s, + SplashXPathSeg *sNext) { + SplashXPathSeg *sPrev; - //--- clear the scan line buffer - memset(line + x0, 0, x1 - x0 + 1); + sPrev = sNext->prev; + sPrev->next = s; + s->prev = sPrev; + s->next = sNext; + sNext->prev = s; +} + +void SplashXPathScanner::removeSegment(SplashXPathSeg *s) { + SplashXPathSeg *sPrev, *sNext; + + sPrev = s->prev; + sNext = s->next; + sPrev->next = sNext; + sNext->prev = sPrev; + s->prev = s->next = NULL; +} - //--- reset the path - if (yNext != y) { - delete activeSegs; - activeSegs = new GList(); - nextSeg = 0; - while (nextSeg < xPath->length) { - seg = &xPath->segs[nextSeg]; - if (seg->y0 >= y) { - break; +void SplashXPathScanner::moveSegmentAfter(SplashXPathSeg *s, + SplashXPathSeg *sPrev) { + SplashXPathSeg *sNext; + + s->prev->next = s->next; + s->next->prev = s->prev; + + sNext = sPrev->next; + sPrev->next = s; + s->prev = sPrev; + s->next = sNext; + sNext->prev = s; +} + +void SplashXPathScanner::reset(GBool aa, GBool aaChanged) { + SplashXPathSeg *seg; + SplashCoord y; + int i; + + //--- initialize segment parameters + for (i = 0; i < xPath->length; ++i) { + seg = &xPath->segs[i]; + if (aa) { + if (aaChanged) { + seg->iy = splashFloor(seg->y0 * aaVert); } - if (seg->y0 != seg->y1 && seg->y1 > y) { - if (seg->y0 == y) { - seg->xCur0 = seg->x0; - } else { - seg->xCur0 = seg->x0 + ((SplashCoord)y - seg->y0) * seg->dxdy; - } - activeSegs->append(seg); + y = (SplashCoord)(seg->iy + 1) / (SplashCoord)aaVert; + } else { + if (aaChanged) { + seg->iy = splashFloor(seg->y0); } - ++nextSeg; + y = (SplashCoord)(seg->iy + 1); + } + seg->sx0 = seg->x0; + if (seg->y1 <= y) { + seg->sx1 = seg->x1; + } else { + seg->sx1 = seg->x0 + (y - seg->y0) * seg->dxdy; } - activeSegs->sort(&SplashXPathSeg::cmpXi); + seg->mx = (seg->sx0 <= seg->sx1) ? seg->sx0 : seg->sx1; + seg->prev = seg->next = NULL; } - //--- process the scan line - y0 = y; - while (y0 < y + 1) { + //--- sort the inactive segments by iy, mx + if (aaChanged) { +#if HAVE_STD_SORT + std::sort(xPath->segs, xPath->segs + xPath->length, &SplashXPathSeg::cmpMX); +#else + qsort(xPath->segs, xPath->length, sizeof(SplashXPathSeg), + &SplashXPathSeg::cmpMX); +#endif + } - //--- delete finished segs - i = 0; - while (i < activeSegs->getLength()) { - seg = (SplashXPathSeg *)activeSegs->get(i); - if (seg->y1 <= y0) { - activeSegs->del(i); - } else { - ++i; - } - } + //--- initialize the active list + pre->prev = NULL; + pre->next = post; + post->prev = pre; + post->next = NULL; - //--- check for bottom of path - if (!activeSegs->getLength() && nextSeg >= xPath->length) { - break; + //--- initialize the scan state + nextSeg = 0; + if (xPath->length) { + yBottomI = xPath->segs[0].iy; + if (aa) { + yBottomI -= yBottomI % aaVert; } + } else { + yBottomI = 0; + } + yTopI = yBottomI - 1; + if (aa) { + yTop = (SplashCoord)yTopI / (SplashCoord)aaVert; + yBottom = (SplashCoord)yBottomI / (SplashCoord)aaVert; + } else { + yTop = (SplashCoord)yTopI; + yBottom = (SplashCoord)yBottomI; + } + + resetDone = gTrue; + resetAA = aa; +} - //--- sort activeSegs - sortActiveSegs(); +void SplashXPathScanner::skip(int newYBottomI, GBool aa) { + SplashXPathSeg *s0, *s1,*s2; + int iy; + + yTopI = newYBottomI - 1; + yBottomI = newYBottomI; + if (aa) { + yTop = (SplashCoord)yTopI / (SplashCoord)aaVert; + yBottom = (SplashCoord)yBottomI / (SplashCoord)aaVert; + } else { + yTop = (SplashCoord)yTopI; + yBottom = (SplashCoord)yBottomI; + } - //--- add waiting segs - while (nextSeg < xPath->length) { - seg = &xPath->segs[nextSeg]; - if (seg->y0 > y0) { - break; + //--- remove finished segments; update sx0, sx1, mx for active segments + s0 = pre->next; + while (s0 != post) { + s1 = s0->next; + + // check for a finished segment + if (s0->y1 < yTop) { + removeSegment(s0); + + // compute sx0, sx1, mx + } else { + if (s0->y0 >= yTop) { + s0->sx0 = s0->x0; + } else { + s0->sx0 = s0->x0 + (yTop - s0->y0) * s0->dxdy; } - if (seg->y0 != seg->y1) { - seg->xCur0 = seg->x0; - insertActiveSeg(seg); + if (s0->y1 <= yBottom) { + s0->sx1 = s0->x1; + } else { + s0->sx1 = s0->x0 + (yBottom - s0->y0) * s0->dxdy; } - ++nextSeg; + s0->mx = (s0->sx0 <= s0->sx1) ? s0->sx0 : s0->sx1; } - //--- get the next "interesting" y value - y1 = y + 1; - if (nextSeg < xPath->length && xPath->segs[nextSeg].y0 < y1) { - y1 = xPath->segs[nextSeg].y0; - } - for (i = 0; i < activeSegs->getLength(); ++i) { - seg = (SplashXPathSeg *)activeSegs->get(i); - if (seg->y1 < y1) { - y1 = seg->y1; + s0 = s1; + } + + //--- check for intersections + s0 = pre->next; + if (s0 != post) { + s1 = s0->next; + while (s1 != post) { + if (s1->mx < s0->mx) { + for (s2 = s0->prev; s1->mx < s2->mx; s2 = s2->prev) ; + moveSegmentAfter(s1, s2); + } else { + s0 = s1; } + s1 = s0->next; } + } - //--- compute xCur1 values, check for intersections - seg0 = NULL; - intersect = gFalse; - for (i = 0; i < activeSegs->getLength(); ++i) { - seg = (SplashXPathSeg *)activeSegs->get(i); - if (seg->y1 == y1) { - seg->xCur1 = seg->x1; - } else { - seg->xCur1 = seg->x0 + (y1 - seg->y0) * seg->dxdy; + //--- insert new segments with a merge sort + // - this has to be done one (sub)scanline at a time, because the + // inactive list is bin-sorted by (sub)scanline + while (nextSeg < xPath->length && xPath->segs[nextSeg].iy <= yTopI) { + // the first inactive segment determines the next scanline to process + iy = xPath->segs[nextSeg].iy; + s0 = pre->next; + do { + s1 = &xPath->segs[nextSeg]; + ++nextSeg; + if (s1->y1 < yTop) { + continue; } - if (seg0 && seg0->xCur1 > seg->xCur1) { - intersect = gTrue; + if (s1->y0 >= yTop) { + s1->sx0 = s1->x0; + } else { + s1->sx0 = s1->x0 + (yTop - s1->y0) * s1->dxdy; } - seg0 = seg; - } - - //--- draw rectangles - if (intersect) { - for (; y0 < y1; y0 += minVertStep) { - if ((y1p = y0 + minVertStep) >= y1) { - y1p = y1; - last = gTrue; - } else { - last = gFalse; - } - state0 = state1 = count = 0; - seg0 = NULL; - eoMask = eo ? 1 : 0xffffffff; - for (i = 0; i < activeSegs->getLength(); ++i) { - seg = (SplashXPathSeg *)activeSegs->get(i); - if (last && seg->y1 == y1) { - seg->xCur1 = seg->x1; - } else { - seg->xCur1 = seg->x0 + (y1p - seg->y0) * seg->dxdy; - } - count += seg->count; - state1 = count & eoMask; - if (!state0 && state1) { - seg0 = seg; - } else if (state0 && !state1) { - drawRectangle(line, x0, x1, y0, y1p, seg0->xCur0, seg->xCur0); - } - state0 = state1; - } - for (i = 0; i < activeSegs->getLength(); ++i) { - seg = (SplashXPathSeg *)activeSegs->get(i); - seg->xCur0 = seg->xCur1; - } - sortActiveSegs(); + if (s1->y1 <= yBottom) { + s1->sx1 = s1->x1; + } else { + s1->sx1 = s1->x0 + (yBottom - s1->y0) * s1->dxdy; } + s1->mx = (s1->sx0 <= s1->sx1) ? s1->sx0 : s1->sx1; + insertSegmentBefore(s1, s0); + } while (nextSeg < xPath->length && xPath->segs[nextSeg].iy <= iy); + } +} - //--- draw trapezoids - } else { - state0 = state1 = count = 0; - seg0 = NULL; - eoMask = eo ? 1 : 0xffffffff; - for (i = 0; i < activeSegs->getLength(); ++i) { - seg = (SplashXPathSeg *)activeSegs->get(i); - count += seg->count; - state1 = count & eoMask; - if (!state0 && state1) { - seg0 = seg; - } else if (state0 && !state1) { - drawTrapezoid(line, x0, x1, y0, y1, - seg0->xCur0, seg0->xCur1, seg0->dydx, - seg->xCur0, seg->xCur1, seg->dydx); - } - state0 = state1; - } - for (i = 0; i < activeSegs->getLength(); ++i) { - seg = (SplashXPathSeg *)activeSegs->get(i); - seg->xCur0 = seg->xCur1; - } - } +void SplashXPathScanner::advance(GBool aa) { + SplashXPathSeg *s, *sNext, *s1; - //--- next slice - y0 = y1; + yTopI = yBottomI; + yTop = yBottom; + yBottomI = yTopI + 1; + if (aa) { + yBottom = (SplashCoord)yBottomI / (SplashCoord)aaVert; + } else { + yBottom = (SplashCoord)yBottomI; } - yNext = y + 1; -} + s = pre->next; + while (s != post) { + sNext = s->next; -void SplashXPathScanner::getSpanBinary(Guchar *line, int y, int x0, int x1) { - SplashXPathSeg *seg; - int xx0, xx1, xx; - int eoMask, state0, state1, count, i; + // check for a finished segment + if (s->y1 < yTop) { + removeSegment(s); - //--- clear the scan line buffer - memset(line + x0, 0, x1 - x0 + 1); + } else { - //--- reset the path - if (yNext != y) { - delete activeSegs; - activeSegs = new GList(); - nextSeg = 0; - while (nextSeg < xPath->length) { - seg = &xPath->segs[nextSeg]; - if (seg->y0 >= y) { - break; + // compute sx0, sx1, mx + s->sx0 = s->sx1; + if (s->y1 <= yBottom) { + s->sx1 = s->x1; + } else { + s->sx1 = s->x0 + (yBottom - s->y0) * s->dxdy; } - if (seg->y1 > y) { - if (seg->y0 == y) { - seg->xCur0 = seg->x0; - } else { - seg->xCur0 = seg->x0 + ((SplashCoord)y - seg->y0) * seg->dxdy; - } - activeSegs->append(seg); + s->mx = (s->sx0 <= s->sx1) ? s->sx0 : s->sx1; + + // check for intersection + if (s->mx < s->prev->mx) { + for (s1 = s->prev->prev; s->mx < s1->mx; s1 = s1->prev) ; + moveSegmentAfter(s, s1); } - ++nextSeg; } - activeSegs->sort(&SplashXPathSeg::cmpXi); - } - //--- delete finished segs - i = 0; - while (i < activeSegs->getLength()) { - seg = (SplashXPathSeg *)activeSegs->get(i); - if (seg->y1 <= y) { - activeSegs->del(i); - } else { - ++i; - } + s = sNext; } - //--- sort activeSegs - sortActiveSegs(); - - //--- add waiting segs - while (nextSeg < xPath->length) { - seg = &xPath->segs[nextSeg]; - if (seg->y0 >= y + 1) { - break; - } - seg->xCur0 = seg->x0; - insertActiveSeg(seg); + // insert new segments + s = pre->next; + while (nextSeg < xPath->length && xPath->segs[nextSeg].iy <= yTopI) { + s1 = &xPath->segs[nextSeg]; ++nextSeg; - } - - //--- compute xCur1 values - for (i = 0; i < activeSegs->getLength(); ++i) { - seg = (SplashXPathSeg *)activeSegs->get(i); - if (seg->y1 <= y + 1) { - seg->xCur1 = seg->x1; - } else { - seg->xCur1 = seg->x0 + ((SplashCoord)(y + 1) - seg->y0) * seg->dxdy; + while (s1->mx > s->mx) { + s = s->next; } + insertSegmentBefore(s1, s); } +} - //--- draw spans - state0 = state1 = count = 0; - eoMask = eo ? 1 : 0xffffffff; - xx0 = xx1 = 0; // make gcc happy - for (i = 0; i < activeSegs->getLength(); ++i) { - seg = (SplashXPathSeg *)activeSegs->get(i); - if (seg->y0 <= y && seg->y0 < seg->y1) { - count += seg->count; - state1 = count & eoMask; - } - if (state0) { - xx = splashCeil(seg->xCur0) - 1; - if (xx > xx1) { - xx1 = xx; - } - xx = splashFloor(seg->xCur1); - if (xx < xx0) { - xx0 = xx; - } - xx = splashCeil(seg->xCur1) - 1; - if (xx > xx1) { - xx1 = xx; - } - } else { - if (seg->xCur0 < seg->xCur1) { - xx0 = splashFloor(seg->xCur0); - xx1 = splashCeil(seg->xCur1) - 1; - } else { - xx0 = splashFloor(seg->xCur1); - xx1 = splashCeil(seg->xCur0) - 1; - } +void SplashXPathScanner::generatePixels(int x0, int x1, Guchar *line, + int *xMin, int *xMax) { + SplashXPathSeg *s; + int fillCount, x, xEnd, ix0, ix1, t; + + fillCount = 0; + x = x0 * aaHoriz; + xEnd = (x1 + 1) * aaHoriz; + for (s = pre->next; s != post && x < xEnd; s = s->next) { + ix0 = splashFloor(s->sx0 * aaHoriz); + ix1 = splashFloor(s->sx1 * aaHoriz); + if (ix0 > ix1) { + t = ix0; ix0 = ix1; ix1 = t; } - if (!state1) { - if (xx0 < x0) { - xx0 = x0; - } - if (xx1 > x1) { - xx1 = x1; - } - for (xx = xx0; xx <= xx1; ++xx) { - line[xx] = 0xff; + if (!(fillCount & eoMask)) { + if (ix0 > x) { + x = ix0; } } - state0 = state1; + if (ix1 >= xEnd) { + ix1 = xEnd - 1; + } + if (x / aaHoriz < *xMin) { + *xMin = x / aaHoriz; + } + if (ix1 / aaHoriz > *xMax) { + *xMax = ix1 / aaHoriz; + } + for (; x <= ix1; ++x) { + ++line[x / aaHoriz]; + } + if (s->y0 <= yTop && s->y1 > yTop) { + fillCount += s->count; + } } +} - //--- update xCur0 values - for (i = 0; i < activeSegs->getLength(); ++i) { - seg = (SplashXPathSeg *)activeSegs->get(i); - seg->xCur0 = seg->xCur1; +void SplashXPathScanner::generatePixelsBinary(int x0, int x1, Guchar *line, + int *xMin, int *xMax) { + SplashXPathSeg *s; + int fillCount, x, xEnd, ix0, ix1, t; + + fillCount = 0; + x = x0; + xEnd = x1 + 1; + for (s = pre->next; s != post && x < xEnd; s = s->next) { + ix0 = splashFloor(s->sx0); + ix1 = splashFloor(s->sx1); + if (ix0 > ix1) { + t = ix0; ix0 = ix1; ix1 = t; + } + if (!(fillCount & eoMask)) { + if (ix0 > x) { + x = ix0; + } + } + if (ix1 >= xEnd) { + ix1 = xEnd - 1; + } + if (x < *xMin) { + *xMin = x; + } + if (ix1 > *xMax) { + *xMax = ix1; + } + for (; x <= ix1; ++x) { + line[x] = 255; + } + if (s->y0 <= yTop && s->y1 > yTop) { + fillCount += s->count; + } } - - yNext = y + 1; } -inline void SplashXPathScanner::addArea(Guchar *line, int x, SplashCoord a) { - int a2, t; +void SplashXPathScanner::drawRectangleSpan(Guchar *line, int y, + int x0, int x1, + int *xMin, int *xMax) { + SplashCoord edge; + Guchar pix; + int xe, x; - a2 = splashRound(a * 255); - if (a2 <= 0) { + if (rectX0I > x1 || rectX1I < x0) { return; } - t = line[x] + a2; - if (t > 255) { - t = 255; - } - line[x] = t; -} -// Draw a trapezoid with edges: -// top: (xa0, y0) - (xb0, y0) -// left: (xa0, y0) - (xa1, y1) -// right: (xb0, y0) - (xb1, y1) -// bottom: (xa1, y1) - (xb1, y1) -void SplashXPathScanner::drawTrapezoid(Guchar *line, int xMin, int xMax, - SplashCoord y0, SplashCoord y1, - SplashCoord xa0, SplashCoord xa1, - SplashCoord dydxa, - SplashCoord xb0, SplashCoord xb1, - SplashCoord dydxb) { - SplashCoord a, dy; - int x0, x1, x2, x3, x; - - // check for a rectangle - if (dydxa == 0 && dydxb == 0 && xa0 >= xMin && xb0 <= xMax) { - x0 = splashFloor(xa0); - x3 = splashFloor(xb0); - dy = y1 - y0; - if (x0 == x3) { - addArea(line, x0, (xb0 - xa0) * dy); + *xMin = x0 <= rectX0I ? rectX0I : x0; + *xMax = rectX1I <= x1 ? rectX1I : x1; + + //--- upper edge + if (y == rectY0I) { + + // handle a rectangle less than one pixel high + if (rectY0I == rectY1I) { + edge = xPath->rectY1 - xPath->rectY0; + } else { + edge = (SplashCoord)1 - (xPath->rectY0 - rectY0I); + } + + // upper left corner + if (x0 <= rectX0I) { + pix = (Guchar)splashCeil(edge + * ((SplashCoord)1 - (xPath->rectX0 - rectX0I)) + * 255); + if (pix < 16) { + pix = 16; + } + line[rectX0I] = pix; + x = rectX0I + 1; } else { - addArea(line, x0, ((SplashCoord)1 - (xa0 - x0)) * dy); - for (x = x0 + 1; x <= x3 - 1; ++x) { - addArea(line, x, y1 - y0); + x = x0; + } + + // upper right corner + if (rectX1I <= x1) { + pix = (Guchar)splashCeil(edge * (xPath->rectX1 - rectX1I) * 255); + if (pix < 16) { + pix = 16; } - addArea(line, x3, (xb0 - x3) * (y1 - y0)); + line[rectX1I] = pix; + xe = rectX1I - 1; + } else { + xe = x1; } - return; - } - if (dydxa > 0) { - x0 = splashFloor(xa0); - x1 = splashFloor(xa1); - } else { - x0 = splashFloor(xa1); - x1 = splashFloor(xa0); - } - if (x0 < xMin) { - x0 = xMin; - } - if (dydxb > 0) { - x2 = splashFloor(xb0); - x3 = splashFloor(xb1); - } else { - x2 = splashFloor(xb1); - x3 = splashFloor(xb0); - } - if (x3 > xMax) { - x3 = xMax; - } - for (x = x0; x <= x3; ++x) { - a = y1 - y0; - if (x <= x1) { - a -= areaLeft(x, xa0, y0, xa1, y1, dydxa); + // upper edge + pix = (Guchar)splashCeil(edge * 255); + if (pix < 16) { + pix = 16; } - if (x >= x2) { - a -= areaRight(x, xb0, y0, xb1, y1, dydxb); + for (; x <= xe; ++x) { + line[x] = pix; } - addArea(line, x, a); - } -} -// Compute area within a pixel slice ((xp,y0)-(xp+1,y1)) to the left -// of a trapezoid edge ((x0,y0)-(x1,y1)). -SplashCoord SplashXPathScanner::areaLeft(int xp, - SplashCoord x0, SplashCoord y0, - SplashCoord x1, SplashCoord y1, - SplashCoord dydx) { - SplashCoord a, ya, yb; - - if (dydx >= 0) { - if (x0 >= xp) { - if (x1 <= xp + 1) { - a = ((x0 + x1) * 0.5 - xp) * (y1 - y0); - } else { - yb = y0 + ((SplashCoord)(xp + 1) - x0) * dydx; - a = (y1 - y0) - ((SplashCoord)(xp + 1) - x0) * (yb - y0) * 0.5; + //--- lower edge + } else if (y == rectY1I) { + edge = xPath->rectY1 - rectY1I; + + // lower left corner + if (x0 <= rectX0I) { + pix = (Guchar)splashCeil(edge + * ((SplashCoord)1 - (xPath->rectX0 - rectX0I)) + * 255); + if (pix < 16) { + pix = 16; } + line[rectX0I] = pix; + x = rectX0I + 1; } else { - if (x1 <= xp + 1) { - ya = y0 + ((SplashCoord)xp - x0) * dydx; - a = (x1 - xp) * (y1 - ya) * 0.5; - } else { - // ya = y1 - (x1 - xp - 0.5) * dydx; - // a = y1 - ya; - a = (x1 - xp - 0.5) * dydx; - } + x = x0; } - } else { - if (x0 <= xp + 1) { - if (x1 >= xp) { - a = ((x0 + x1) * 0.5 - xp) * (y1 - y0); - } else { - ya = y0 + ((SplashCoord)xp - x0) * dydx; - a = (x0 - xp) * (ya - y0) * 0.5; + + // lower right corner + if (rectX1I <= x1) { + pix = (Guchar)splashCeil(edge * (xPath->rectX1 - rectX1I) * 255); + if (pix < 16) { + pix = 16; } + line[rectX1I] = pix; + xe = rectX1I - 1; } else { - if (x1 >= xp) { - yb = y0 + ((SplashCoord)(xp + 1) - x0) * dydx; - a = (y1 - y0) - ((SplashCoord)(xp + 1) - x1) * (y1 - yb) * 0.5; - } else { - // ya = y0 + (xp - x0 + 0.5) * dydx; - // a = ya - y0; - a = ((SplashCoord)xp - x0 + 0.5) * dydx; - } + xe = x1; } - } - return a; -} -// Compute area within a pixel slice ((xp,y0)-(xp+1,y1)) to the left -// of a trapezoid edge ((x0,y0)-(x1,y1)). -SplashCoord SplashXPathScanner::areaRight(int xp, - SplashCoord x0, SplashCoord y0, - SplashCoord x1, SplashCoord y1, - SplashCoord dydx) { - SplashCoord a, ya, yb; - - if (dydx >= 0) { - if (x0 >= xp) { - if (x1 <= xp + 1) { - a = ((SplashCoord)(xp + 1) - (x0 + x1) * 0.5) * (y1 - y0); - } else { - yb = y0 + ((SplashCoord)(xp + 1) - x0) * dydx; - a = ((SplashCoord)(xp + 1) - x0) * (yb - y0) * 0.5; + // lower edge + pix = (Guchar)splashCeil(edge * 255); + if (pix < 16) { + pix = 16; + } + for (; x <= xe; ++x) { + line[x] = pix; + } + + //--- between the upper and lower edges + } else if (y > rectY0I && y < rectY1I) { + + // left edge + if (x0 <= rectX0I) { + pix = (Guchar)splashCeil(((SplashCoord)1 - (xPath->rectX0 - rectX0I)) + * 255); + if (pix < 16) { + pix = 16; } + line[rectX0I] = pix; + x = rectX0I + 1; } else { - if (x1 <= xp + 1) { - ya = y0 + ((SplashCoord)xp - x0) * dydx; - a = (y1 - y0) - (x1 - xp) * (y1 - ya) * 0.5; - } else { - // ya = y0 + (xp - x0 + 0.5) * dydx; - // a = ya - y0; - a = ((SplashCoord)xp + 0.5 - x0) * dydx; - } + x = x0; } - } else { - if (x0 <= xp + 1) { - if (x1 >= xp) { - a = ((SplashCoord)(xp + 1) - (x0 + x1) * 0.5) * (y1 - y0); - } else { - ya = y0 + ((SplashCoord)xp - x0) * dydx; - a = (y1 - y0) - (x0 - xp) * (ya - y0) * 0.5; + + // right edge + if (rectX1I <= x1) { + pix = (Guchar)splashCeil((xPath->rectX1 - rectX1I) * 255); + if (pix < 16) { + pix = 16; } + line[rectX1I] = pix; + xe = rectX1I - 1; } else { - if (x1 >= xp) { - yb = y0 + ((SplashCoord)(xp + 1) - x0) * dydx; - a = ((SplashCoord)(xp + 1) - x1) * (y1 - yb) * 0.5; - } else { - // ya = y1 - (x1 - xp - 0.5) * dydx; - // a = y1 - ya; - a = (x1 - xp - 0.5) * dydx; - } + xe = x1; + } + + // middle + for (; x <= xe; ++x) { + line[x] = 255; } } - return a; } -void SplashXPathScanner::drawRectangle(Guchar *line, int xMin, int xMax, - SplashCoord y0, SplashCoord y1, - SplashCoord x0, SplashCoord x1) { - SplashCoord dy, a; - int xx0, xx1, x; +void SplashXPathScanner::drawRectangleSpanBinary(Guchar *line, int y, + int x0, int x1, + int *xMin, int *xMax) { + int xe, x; - xx0 = splashFloor(x0); - if (xx0 < xMin) { - xx0 = xMin; - } - xx1 = splashFloor(x1); - if (xx1 > xMax) { - xx1 = xMax; - } - dy = y1 - y0; - for (x = xx0; x <= xx1; ++x) { - a = dy; - if ((SplashCoord)x < x0) { - a -= (x0 - x) * dy; + if (y >= rectY0I && y <= rectY1I) { + if (x0 <= rectX0I) { + x = rectX0I; + } else { + x = x0; } - if ((SplashCoord)(x + 1) > x1) { - a -= ((SplashCoord)(x + 1) - x1) * dy; + *xMin = x; + if (rectX1I <= x1) { + xe = rectX1I; + } else { + xe = x1; + } + *xMax = xe; + for (; x <= xe; ++x) { + line[x] = 255; } - addArea(line, x, a); } } -void SplashXPathScanner::sortActiveSegs() { - SplashXPathSeg *seg0, *seg1; - int i, j, k; +void SplashXPathScanner::getSpan(Guchar *line, int y, int x0, int x1, + int *xMin, int *xMax) { + int iy, x, k; - if (activeSegs->getLength() < 2) { + iy = y * aaVert; + if (!resetDone || !resetAA) { + reset(gTrue, gTrue); + } else if (yBottomI > iy) { + reset(gTrue, gFalse); + } + memset(line + x0, 0, x1 - x0 + 1); + + *xMin = x1 + 1; + *xMax = x0 - 1; + + if (xPath->isRect) { + drawRectangleSpan(line, y, x0, x1, xMin, xMax); return; } - seg0 = (SplashXPathSeg *)activeSegs->get(0); - for (i = 1; i < activeSegs->getLength(); ++i) { - seg1 = (SplashXPathSeg *)activeSegs->get(i); - if (SplashXPathSeg::cmpX(seg0, seg1) > 0) { - for (j = i - 1; j > 0; --j) { - if (SplashXPathSeg::cmpX((SplashXPathSeg *)activeSegs->get(j - 1), - seg1) <= 0) { - break; - } - } - for (k = i; k > j; --k) { - activeSegs->put(k, activeSegs->get(k-1)); - } - activeSegs->put(j, seg1); - } else { - seg0 = seg1; - } + + if (yBottomI < iy) { + skip(iy, gTrue); + } + for (k = 0; k < aaVert; ++k, ++iy) { + advance(gTrue); + generatePixels(x0, x1, line, xMin, xMax); + } + +#if !ANTIALIAS_256 + for (x = *xMin; x <= *xMax; ++x) { + line[x] = map16to255[line[x]]; } +#endif } -void SplashXPathScanner::insertActiveSeg(SplashXPathSeg *seg) { - int i; +void SplashXPathScanner::getSpanBinary(Guchar *line, int y, int x0, int x1, + int *xMin, int *xMax) { + int iy; - for (i = 0; i < activeSegs->getLength(); ++i) { - if (SplashXPathSeg::cmpX(seg, (SplashXPathSeg *)activeSegs->get(i)) < 0) { - break; - } + iy = y; + if (!resetDone || resetAA) { + reset(gFalse, gTrue); + } else if (yBottomI > iy) { + reset(gFalse, gFalse); + } + memset(line + x0, 0, x1 - x0 + 1); + + *xMin = x1 + 1; + *xMax = x0 - 1; + + if (xPath->isRect) { + drawRectangleSpanBinary(line, y, x0, x1, xMin, xMax); + return; + } + + if (yBottomI < iy) { + skip(iy, gFalse); } - activeSegs->insert(i, seg); + advance(gFalse); + generatePixelsBinary(x0, x1, line, xMin, xMax); } diff --git a/Build/source/libs/xpdf/xpdf-src/splash/SplashXPathScanner.h b/Build/source/libs/xpdf/xpdf-src/splash/SplashXPathScanner.h index 519ff4dfcac..39cc0eb022a 100644 --- a/Build/source/libs/xpdf/xpdf-src/splash/SplashXPathScanner.h +++ b/Build/source/libs/xpdf/xpdf-src/splash/SplashXPathScanner.h @@ -16,9 +16,15 @@ #endif #include "SplashTypes.h" +#include "SplashXPath.h" class GList; -class SplashXPath; + +//------------------------------------------------------------------------ + +// Set this to 0 for antialiasing with 16 levels of gray. +// Set it to 1 for (much slower) antialiasing with 256 levels of gray. +#define ANTIALIAS_256 0 //------------------------------------------------------------------------ // SplashXPathScanner @@ -28,48 +34,51 @@ class SplashXPathScanner { public: // Create a new SplashXPathScanner object. <xPathA> must be sorted. - SplashXPathScanner(SplashXPath *xPathA, GBool eoA, + SplashXPathScanner(SplashXPath *xPathA, GBool eo, int yMinA, int yMaxA); ~SplashXPathScanner(); // Compute shape values for a scan line. Fills in line[] with shape // values for one scan line: ([x0, x1], y). The values are in [0, - // 255]. - void getSpan(Guchar *line, int y, int x0, int x1); + // 255]. Also returns the min/max x positions with non-zero shape + // values. + void getSpan(Guchar *line, int y, int x0, int x1, int *xMin, int *xMax); // Like getSpan(), but uses the values 0 and 255 only. Writes 255 // for all pixels which include non-zero area inside the path. - void getSpanBinary(Guchar *line, int y, int x0, int x1); + void getSpanBinary(Guchar *line, int y, int x0, int x1, + int *xMin, int *xMax); private: - inline void addArea(Guchar *line, int x, SplashCoord a); - void drawTrapezoid(Guchar *line, int xMin, int xMax, - SplashCoord y0, SplashCoord y1, - SplashCoord xa0, SplashCoord xa1, SplashCoord dydxa, - SplashCoord xb0, SplashCoord xb1, SplashCoord dydxb); - SplashCoord areaLeft(int xp, - SplashCoord x0, SplashCoord y0, - SplashCoord x1, SplashCoord y1, - SplashCoord dydx); - SplashCoord areaRight(int xp, - SplashCoord x0, SplashCoord y0, - SplashCoord x1, SplashCoord y1, - SplashCoord dydx); - void drawRectangle(Guchar *line, int xMin, int xMax, - SplashCoord y0, SplashCoord y1, - SplashCoord x0, SplashCoord x1); - void sortActiveSegs(); - void insertActiveSeg(SplashXPathSeg *seg); + void insertSegmentBefore(SplashXPathSeg *s, SplashXPathSeg *sNext); + void removeSegment(SplashXPathSeg *s); + void moveSegmentAfter(SplashXPathSeg *s, SplashXPathSeg *sPrev); + void reset(GBool aa, GBool aaChanged); + void skip(int newYBottomI, GBool aa); + void advance(GBool aa); + void generatePixels(int x0, int x1, Guchar *line, int *xMin, int *xMax); + void generatePixelsBinary(int x0, int x1, Guchar *line, + int *xMin, int *xMax); + void drawRectangleSpan(Guchar *line, int y, int x0, int x1, + int *xMin, int *xMax); + void drawRectangleSpanBinary(Guchar *line, int y, int x0, int x1, + int *xMin, int *xMax); SplashXPath *xPath; - GBool eo; + int eoMask; int yMin, yMax; + int rectX0I, rectY0I, rectX1I, rectY1I; + + SplashXPathSeg preSeg, postSeg; + SplashXPathSeg *pre, *post; - GList *activeSegs; // [SplashXPathSeg] + GBool resetDone; + GBool resetAA; int nextSeg; - int yNext; + int yTopI, yBottomI; + SplashCoord yTop, yBottom; }; #endif |