diff options
author | Peter Breitenlohner <peb@mppmu.mpg.de> | 2015-06-12 09:16:27 +0000 |
---|---|---|
committer | Peter Breitenlohner <peb@mppmu.mpg.de> | 2015-06-12 09:16:27 +0000 |
commit | 651ca331cd7943896e894fd42cf13fa1d012347f (patch) | |
tree | 8a911c2b5c3f6fb05b53a5a03ccd2614c24ac2c1 /Build/source/libs/poppler/poppler-0.33.0/splash | |
parent | 4403160cd26a0ba4eb014d69bfb9dcd568f64fc6 (diff) |
freetype 2.6
git-svn-id: svn://tug.org/texlive/trunk@37505 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Build/source/libs/poppler/poppler-0.33.0/splash')
43 files changed, 14382 insertions, 0 deletions
diff --git a/Build/source/libs/poppler/poppler-0.33.0/splash/Makefile.am b/Build/source/libs/poppler/poppler-0.33.0/splash/Makefile.am new file mode 100644 index 00000000000..5c265d6360c --- /dev/null +++ b/Build/source/libs/poppler/poppler-0.33.0/splash/Makefile.am @@ -0,0 +1,73 @@ +noinst_LTLIBRARIES = libsplash.la + +if ENABLE_XPDF_HEADERS + +poppler_splash_includedir = $(includedir)/poppler/splash +poppler_splash_include_HEADERS = \ + Splash.h \ + SplashBitmap.h \ + SplashClip.h \ + SplashErrorCodes.h \ + SplashFTFont.h \ + SplashFTFontEngine.h \ + SplashFTFontFile.h \ + SplashFont.h \ + SplashFontEngine.h \ + SplashFontFile.h \ + SplashFontFileID.h \ + SplashGlyphBitmap.h \ + SplashMath.h \ + SplashPath.h \ + SplashPattern.h \ + SplashScreen.h \ + SplashState.h \ + SplashT1Font.h \ + SplashT1FontEngine.h \ + SplashT1FontFile.h \ + SplashTypes.h \ + SplashXPath.h \ + SplashXPathScanner.h + +endif + +libsplash_la_SOURCES = \ + 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 \ + SplashT1Font.cc \ + SplashT1FontEngine.cc \ + SplashT1FontFile.cc \ + SplashXPath.cc \ + SplashXPathScanner.cc + +# SplashBitmap includes JpegWriter.h, TiffWriter.h, PNGWriter.h +if BUILD_LIBJPEG +libjpeg_includes = $(LIBJPEG_CFLAGS) +endif + +if BUILD_LIBTIFF +libtiff_includes = $(LIBTIFF_CFLAGS) +endif + +if BUILD_LIBPNG +libpng_includes = $(LIBPNG_CFLAGS) +endif + +libsplash_la_CPPFLAGS = \ + -I$(top_srcdir) \ + -I$(top_srcdir)/goo \ + $(libjpeg_includes) \ + $(libtiff_includes) \ + $(libpng_includes) \ + $(FREETYPE_CFLAGS) diff --git a/Build/source/libs/poppler/poppler-0.33.0/splash/Splash.cc b/Build/source/libs/poppler/poppler-0.33.0/splash/Splash.cc new file mode 100644 index 00000000000..d8ee6409605 --- /dev/null +++ b/Build/source/libs/poppler/poppler-0.33.0/splash/Splash.cc @@ -0,0 +1,6450 @@ +//======================================================================== +// +// Splash.cc +// +//======================================================================== + +//======================================================================== +// +// Modified under the Poppler project - http://poppler.freedesktop.org +// +// All changes made under the Poppler project to this file are licensed +// under GPL version 2 or later +// +// Copyright (C) 2005-2015 Albert Astals Cid <aacid@kde.org> +// Copyright (C) 2005 Marco Pesenti Gritti <mpg@redhat.com> +// Copyright (C) 2010-2014 Thomas Freitag <Thomas.Freitag@alfa.de> +// Copyright (C) 2010 Christian Feuersänger <cfeuersaenger@googlemail.com> +// Copyright (C) 2011-2013, 2015 William Bader <williambader@hotmail.com> +// Copyright (C) 2012 Markus Trippelsdorf <markus@trippelsdorf.de> +// Copyright (C) 2012 Adrian Johnson <ajohnson@redneon.com> +// Copyright (C) 2012 Matthias Kramm <kramm@quiss.org> +// +// To see a description of the changes please see the Changelog file that +// came with your tarball or type make ChangeLog if you are building from git +// +//======================================================================== + +#include <config.h> + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include <stdlib.h> +#include <string.h> +#include <limits.h> +#include <assert.h> +#include <math.h> +#include "goo/gmem.h" +#include "goo/GooLikely.h" +#include "goo/GooList.h" +#include "poppler/Error.h" +#include "SplashErrorCodes.h" +#include "SplashMath.h" +#include "SplashBitmap.h" +#include "SplashState.h" +#include "SplashPath.h" +#include "SplashXPath.h" +#include "SplashXPathScanner.h" +#include "SplashPattern.h" +#include "SplashScreen.h" +#include "SplashFont.h" +#include "SplashGlyphBitmap.h" +#include "Splash.h" +#include <algorithm> + +//------------------------------------------------------------------------ + +#define splashAAGamma 1.5 + +// distance of Bezier control point from center for circle approximation +// = (4 * (sqrt(2) - 1) / 3) * r +#define bezierCircle ((SplashCoord)0.55228475) +#define bezierCircle2 ((SplashCoord)(0.5 * 0.55228475)) + +// Divide a 16-bit value (in [0, 255*255]) by 255, returning an 8-bit result. +static inline Guchar div255(int x) { + return (Guchar)((x + (x >> 8) + 0x80) >> 8); +} + +// Clip x to lie in [0, 255]. +static inline Guchar clip255(int x) { + return x < 0 ? 0 : x > 255 ? 255 : x; +} + +template<typename T> +inline void Guswap( T&a, T&b ) { T tmp = a; a=b; b=tmp; } + +// The PDF spec says that all pixels whose *centers* lie within the +// image target region get painted, so we want to round n+0.5 down to +// n. But this causes problems, e.g., with PDF files that fill a +// rectangle with black and then draw an image to the exact same +// rectangle, so we instead use the fill scan conversion rule. +// However, the correct rule works better for glyphs, so we also +// provide that option in fillImageMask. +#if 0 +static inline int imgCoordMungeLower(SplashCoord x) { + return splashCeil(x + 0.5) - 1; +} +static inline int imgCoordMungeUpper(SplashCoord x) { + return splashCeil(x + 0.5) - 1; +} +#else +static inline int imgCoordMungeLower(SplashCoord x) { + return splashFloor(x); +} +static inline int imgCoordMungeUpper(SplashCoord x) { + return splashFloor(x) + 1; +} +static inline int imgCoordMungeLowerC(SplashCoord x, GBool glyphMode) { + return glyphMode ? (splashCeil(x + 0.5) - 1) : splashFloor(x); +} +static inline int imgCoordMungeUpperC(SplashCoord x, GBool glyphMode) { + return glyphMode ? (splashCeil(x + 0.5) - 1) : (splashFloor(x) + 1); +} +#endif + +// Used by drawImage and fillImageMask to divide the target +// quadrilateral into sections. +struct ImageSection { + int y0, y1; // actual y range + int ia0, ia1; // vertex indices for edge A + int ib0, ib1; // vertex indices for edge A + SplashCoord xa0, ya0, xa1, ya1; // edge A + SplashCoord dxdya; // slope of edge A + SplashCoord xb0, yb0, xb1, yb1; // edge B + SplashCoord dxdyb; // slope of edge B +}; + +//------------------------------------------------------------------------ +// SplashPipe +//------------------------------------------------------------------------ + +#define splashPipeMaxStages 9 + +struct SplashPipe { + // pixel coordinates + int x, y; + + // source pattern + SplashPattern *pattern; + + // source alpha and color + Guchar aInput; + GBool usesShape; + SplashColorPtr cSrc; + SplashColor cSrcVal; + + // non-isolated group alpha0 + Guchar *alpha0Ptr; + + // knockout groups + GBool knockout; + Guchar knockoutOpacity; + + // soft mask + SplashColorPtr softMaskPtr; + + // destination alpha and color + SplashColorPtr destColorPtr; + int destColorMask; + Guchar *destAlphaPtr; + + // shape + Guchar shape; + + // result alpha and color + GBool noTransparency; + SplashPipeResultColorCtrl resultColorCtrl; + + // non-isolated group correction + GBool nonIsolatedGroup; + + // the "run" function + void (Splash::*run)(SplashPipe *pipe); +}; + +SplashPipeResultColorCtrl Splash::pipeResultColorNoAlphaBlend[] = { + splashPipeResultColorNoAlphaBlendMono, + splashPipeResultColorNoAlphaBlendMono, + splashPipeResultColorNoAlphaBlendRGB, + splashPipeResultColorNoAlphaBlendRGB, + splashPipeResultColorNoAlphaBlendRGB +#if SPLASH_CMYK + , + splashPipeResultColorNoAlphaBlendCMYK, + splashPipeResultColorNoAlphaBlendDeviceN +#endif +}; + +SplashPipeResultColorCtrl Splash::pipeResultColorAlphaNoBlend[] = { + splashPipeResultColorAlphaNoBlendMono, + splashPipeResultColorAlphaNoBlendMono, + splashPipeResultColorAlphaNoBlendRGB, + splashPipeResultColorAlphaNoBlendRGB, + splashPipeResultColorAlphaNoBlendRGB +#if SPLASH_CMYK + , + splashPipeResultColorAlphaNoBlendCMYK, + splashPipeResultColorAlphaNoBlendDeviceN +#endif +}; + +SplashPipeResultColorCtrl Splash::pipeResultColorAlphaBlend[] = { + splashPipeResultColorAlphaBlendMono, + splashPipeResultColorAlphaBlendMono, + splashPipeResultColorAlphaBlendRGB, + splashPipeResultColorAlphaBlendRGB, + splashPipeResultColorAlphaBlendRGB +#if SPLASH_CMYK + , + splashPipeResultColorAlphaBlendCMYK, + splashPipeResultColorAlphaBlendDeviceN +#endif +}; + +//------------------------------------------------------------------------ + +static void blendXor(SplashColorPtr src, SplashColorPtr dest, + SplashColorPtr blend, SplashColorMode cm) { + int i; + + for (i = 0; i < splashColorModeNComps[cm]; ++i) { + blend[i] = src[i] ^ dest[i]; + } +} + +//------------------------------------------------------------------------ +// modified region +//------------------------------------------------------------------------ + +void Splash::clearModRegion() { + modXMin = bitmap->getWidth(); + modYMin = bitmap->getHeight(); + modXMax = -1; + modYMax = -1; +} + +inline void Splash::updateModX(int x) { + if (x < modXMin) { + modXMin = x; + } + if (x > modXMax) { + modXMax = x; + } +} + +inline void Splash::updateModY(int y) { + if (y < modYMin) { + modYMin = y; + } + if (y > modYMax) { + modYMax = y; + } +} + +//------------------------------------------------------------------------ +// pipeline +//------------------------------------------------------------------------ + +inline void Splash::pipeInit(SplashPipe *pipe, int x, int y, + SplashPattern *pattern, SplashColorPtr cSrc, + Guchar aInput, GBool usesShape, + GBool nonIsolatedGroup, + GBool knockout, Guchar knockoutOpacity) { + pipeSetXY(pipe, x, y); + pipe->pattern = NULL; + + // source color + if (pattern) { + if (pattern->isStatic()) { + pattern->getColor(x, y, pipe->cSrcVal); + } else { + pipe->pattern = pattern; + } + pipe->cSrc = pipe->cSrcVal; + } else { + pipe->cSrc = cSrc; + } + + // source alpha + pipe->aInput = aInput; + pipe->usesShape = usesShape; + pipe->shape = 0; + + // knockout + pipe->knockout = knockout; + pipe->knockoutOpacity = knockoutOpacity; + + // result alpha + if (aInput == 255 && !state->softMask && !usesShape && + !state->inNonIsolatedGroup && !nonIsolatedGroup) { + pipe->noTransparency = gTrue; + } else { + pipe->noTransparency = gFalse; + } + + // result color + if (pipe->noTransparency) { + // the !state->blendFunc case is handled separately in pipeRun + pipe->resultColorCtrl = pipeResultColorNoAlphaBlend[bitmap->mode]; + } else if (!state->blendFunc) { + pipe->resultColorCtrl = pipeResultColorAlphaNoBlend[bitmap->mode]; + } else { + pipe->resultColorCtrl = pipeResultColorAlphaBlend[bitmap->mode]; + } + + // non-isolated group correction + pipe->nonIsolatedGroup = nonIsolatedGroup; + + // select the 'run' function + pipe->run = &Splash::pipeRun; + if (!pipe->pattern && pipe->noTransparency && !state->blendFunc) { + if (bitmap->mode == splashModeMono1 && !pipe->destAlphaPtr) { + pipe->run = &Splash::pipeRunSimpleMono1; + } else if (bitmap->mode == splashModeMono8 && pipe->destAlphaPtr) { + pipe->run = &Splash::pipeRunSimpleMono8; + } else if (bitmap->mode == splashModeRGB8 && pipe->destAlphaPtr) { + pipe->run = &Splash::pipeRunSimpleRGB8; + } else if (bitmap->mode == splashModeXBGR8 && pipe->destAlphaPtr) { + pipe->run = &Splash::pipeRunSimpleXBGR8; + } else if (bitmap->mode == splashModeBGR8 && pipe->destAlphaPtr) { + pipe->run = &Splash::pipeRunSimpleBGR8; +#if SPLASH_CMYK + } else if (bitmap->mode == splashModeCMYK8 && pipe->destAlphaPtr) { + pipe->run = &Splash::pipeRunSimpleCMYK8; + } else if (bitmap->mode == splashModeDeviceN8 && pipe->destAlphaPtr) { + pipe->run = &Splash::pipeRunSimpleDeviceN8; +#endif + } + } else if (!pipe->pattern && !pipe->noTransparency && !state->softMask && + pipe->usesShape && + !(state->inNonIsolatedGroup && alpha0Bitmap->alpha) && + !state->blendFunc && !pipe->nonIsolatedGroup) { + if (bitmap->mode == splashModeMono1 && !pipe->destAlphaPtr) { + pipe->run = &Splash::pipeRunAAMono1; + } else if (bitmap->mode == splashModeMono8 && pipe->destAlphaPtr) { + pipe->run = &Splash::pipeRunAAMono8; + } else if (bitmap->mode == splashModeRGB8 && pipe->destAlphaPtr) { + pipe->run = &Splash::pipeRunAARGB8; + } else if (bitmap->mode == splashModeXBGR8 && pipe->destAlphaPtr) { + pipe->run = &Splash::pipeRunAAXBGR8; + } else if (bitmap->mode == splashModeBGR8 && pipe->destAlphaPtr) { + pipe->run = &Splash::pipeRunAABGR8; +#if SPLASH_CMYK + } else if (bitmap->mode == splashModeCMYK8 && pipe->destAlphaPtr) { + pipe->run = &Splash::pipeRunAACMYK8; + } else if (bitmap->mode == splashModeDeviceN8 && pipe->destAlphaPtr) { + pipe->run = &Splash::pipeRunAADeviceN8; +#endif + } + } +} + +// general case +void Splash::pipeRun(SplashPipe *pipe) { + Guchar aSrc, aDest, alphaI, alphaIm1, alpha0, aResult; + SplashColor cSrcNonIso, cDest, cBlend; + SplashColorPtr cSrc; + Guchar cResult0, cResult1, cResult2, cResult3; + int t; +#if SPLASH_CMYK + int cp, mask; + Guchar cResult[SPOT_NCOMPS+4]; +#endif + + //----- source color + + // static pattern: handled in pipeInit + // fixed color: handled in pipeInit + + // dynamic pattern + if (pipe->pattern) { + if (!pipe->pattern->getColor(pipe->x, pipe->y, pipe->cSrcVal)) { + pipeIncX(pipe); + return; + } +#if SPLASH_CMYK + if (bitmap->mode == splashModeCMYK8 || bitmap->mode == splashModeDeviceN8) { + if (state->fillOverprint && state->overprintMode && pipe->pattern->isCMYK()) { + Guint mask = 15; + if (pipe->cSrcVal[0] == 0) { + mask &= ~1; + } + if (pipe->cSrcVal[1] == 0) { + mask &= ~2; + } + if (pipe->cSrcVal[2] == 0) { + mask &= ~4; + } + if (pipe->cSrcVal[3] == 0) { + mask &= ~8; + } + state->overprintMask = mask; + } + } +#endif + } + + if (pipe->noTransparency && !state->blendFunc) { + + //----- write destination pixel + + switch (bitmap->mode) { + case splashModeMono1: + cResult0 = state->grayTransfer[pipe->cSrc[0]]; + if (state->screen->test(pipe->x, pipe->y, cResult0)) { + *pipe->destColorPtr |= pipe->destColorMask; + } else { + *pipe->destColorPtr &= ~pipe->destColorMask; + } + if (!(pipe->destColorMask >>= 1)) { + pipe->destColorMask = 0x80; + ++pipe->destColorPtr; + } + break; + case splashModeMono8: + *pipe->destColorPtr++ = state->grayTransfer[pipe->cSrc[0]]; + break; + case splashModeRGB8: + *pipe->destColorPtr++ = state->rgbTransferR[pipe->cSrc[0]]; + *pipe->destColorPtr++ = state->rgbTransferG[pipe->cSrc[1]]; + *pipe->destColorPtr++ = state->rgbTransferB[pipe->cSrc[2]]; + break; + case splashModeXBGR8: + *pipe->destColorPtr++ = state->rgbTransferB[pipe->cSrc[2]]; + *pipe->destColorPtr++ = state->rgbTransferG[pipe->cSrc[1]]; + *pipe->destColorPtr++ = state->rgbTransferR[pipe->cSrc[0]]; + *pipe->destColorPtr++ = 255; + break; + case splashModeBGR8: + *pipe->destColorPtr++ = state->rgbTransferB[pipe->cSrc[2]]; + *pipe->destColorPtr++ = state->rgbTransferG[pipe->cSrc[1]]; + *pipe->destColorPtr++ = state->rgbTransferR[pipe->cSrc[0]]; + break; +#if SPLASH_CMYK + case splashModeCMYK8: + if (state->overprintMask & 1) { + pipe->destColorPtr[0] = (state->overprintAdditive) ? + std::min<int>(pipe->destColorPtr[0] + state->cmykTransferC[pipe->cSrc[0]], 255) : + state->cmykTransferC[pipe->cSrc[0]]; + } + if (state->overprintMask & 2) { + pipe->destColorPtr[1] = (state->overprintAdditive) ? + std::min<int>(pipe->destColorPtr[1] + state->cmykTransferM[pipe->cSrc[1]], 255) : + state->cmykTransferM[pipe->cSrc[1]]; + } + if (state->overprintMask & 4) { + pipe->destColorPtr[2] = (state->overprintAdditive) ? + std::min<int>(pipe->destColorPtr[2] + state->cmykTransferY[pipe->cSrc[2]], 255) : + state->cmykTransferY[pipe->cSrc[2]]; + } + if (state->overprintMask & 8) { + pipe->destColorPtr[3] = (state->overprintAdditive) ? + std::min<int>(pipe->destColorPtr[3] + state->cmykTransferK[pipe->cSrc[3]], 255) : + state->cmykTransferK[pipe->cSrc[3]]; + } + pipe->destColorPtr += 4; + break; + case splashModeDeviceN8: + mask = 1; + for (cp = 0; cp < SPOT_NCOMPS + 4; cp ++) { + if (state->overprintMask & mask) { + pipe->destColorPtr[cp] = state->deviceNTransfer[cp][pipe->cSrc[cp]]; + } + mask <<= 1; + } + pipe->destColorPtr += (SPOT_NCOMPS+4); + break; +#endif + } + if (pipe->destAlphaPtr) { + *pipe->destAlphaPtr++ = 255; + } + + } else { + + //----- read destination pixel + + Guchar *destColorPtr; + if (pipe->shape && state->blendFunc && pipe->knockout && alpha0Bitmap != NULL) { + destColorPtr = alpha0Bitmap->data + (alpha0Y+pipe->y)*alpha0Bitmap->rowSize; + switch (bitmap->mode) { + case splashModeMono1: + destColorPtr += (alpha0X+pipe->x) / 8; + break; + case splashModeMono8: + destColorPtr += (alpha0X+pipe->x); + break; + case splashModeRGB8: + case splashModeBGR8: + destColorPtr += (alpha0X+pipe->x) * 3; + break; + case splashModeXBGR8: +#if SPLASH_CMYK + case splashModeCMYK8: +#endif + destColorPtr += (alpha0X+pipe->x) * 4; + break; +#if SPLASH_CMYK + case splashModeDeviceN8: + destColorPtr += (alpha0X+pipe->x) * (SPOT_NCOMPS + 4); + break; +#endif + } + } else { + destColorPtr = pipe->destColorPtr; + } + switch (bitmap->mode) { + case splashModeMono1: + cDest[0] = (*destColorPtr & pipe->destColorMask) ? 0xff : 0x00; + break; + case splashModeMono8: + cDest[0] = *destColorPtr; + break; + case splashModeRGB8: + cDest[0] = destColorPtr[0]; + cDest[1] = destColorPtr[1]; + cDest[2] = destColorPtr[2]; + break; + case splashModeXBGR8: + cDest[0] = destColorPtr[2]; + cDest[1] = destColorPtr[1]; + cDest[2] = destColorPtr[0]; + cDest[3] = 255; + break; + case splashModeBGR8: + cDest[0] = destColorPtr[2]; + cDest[1] = destColorPtr[1]; + cDest[2] = destColorPtr[0]; + break; +#if SPLASH_CMYK + case splashModeCMYK8: + cDest[0] = destColorPtr[0]; + cDest[1] = destColorPtr[1]; + cDest[2] = destColorPtr[2]; + cDest[3] = destColorPtr[3]; + break; + case splashModeDeviceN8: + for (cp = 0; cp < SPOT_NCOMPS + 4; cp++) + cDest[cp] = destColorPtr[cp]; + break; +#endif + } + if (pipe->destAlphaPtr) { + aDest = *pipe->destAlphaPtr; + } else { + aDest = 0xff; + } + + //----- source alpha + + if (state->softMask) { + if (pipe->usesShape) { + aSrc = div255(div255(pipe->aInput * *pipe->softMaskPtr++) * + pipe->shape); + } else { + aSrc = div255(pipe->aInput * *pipe->softMaskPtr++); + } + } else if (pipe->usesShape) { + aSrc = div255(pipe->aInput * pipe->shape); + } else { + aSrc = pipe->aInput; + } + + //----- non-isolated group correction + + if (pipe->nonIsolatedGroup) { + // This path is only used when Splash::composite() is called to + // composite a non-isolated group onto the backdrop. In this + // case, pipe->shape is the source (group) alpha. + if (pipe->shape == 0) { + // this value will be multiplied by zero later, so it doesn't + // matter what we use + cSrc = pipe->cSrc; + } else { + t = (aDest * 255) / pipe->shape - aDest; + switch (bitmap->mode) { +#if SPLASH_CMYK + case splashModeDeviceN8: + for (cp = 0; cp < SPOT_NCOMPS + 4; cp++) + cSrcNonIso[cp] = clip255(pipe->cSrc[cp] + + ((pipe->cSrc[cp] - cDest[cp]) * t) / 255); + break; + case splashModeCMYK8: + for (cp = 0; cp < 4; cp++) + cSrcNonIso[cp] = clip255(pipe->cSrc[cp] + + ((pipe->cSrc[cp] - cDest[cp]) * t) / 255); + break; +#endif + case splashModeXBGR8: + cSrcNonIso[3] = 255; + case splashModeRGB8: + case splashModeBGR8: + cSrcNonIso[2] = clip255(pipe->cSrc[2] + + ((pipe->cSrc[2] - cDest[2]) * t) / 255); + cSrcNonIso[1] = clip255(pipe->cSrc[1] + + ((pipe->cSrc[1] - cDest[1]) * t) / 255); + case splashModeMono1: + case splashModeMono8: + cSrcNonIso[0] = clip255(pipe->cSrc[0] + + ((pipe->cSrc[0] - cDest[0]) * t) / 255); + break; + } + cSrc = cSrcNonIso; + // knockout: remove backdrop color + if (pipe->knockout && pipe->shape >= pipe->knockoutOpacity) { + aDest = 0; + } + } + } else { + cSrc = pipe->cSrc; + } + + //----- blend function + + if (state->blendFunc) { +#ifdef SPLASH_CMYK + if (bitmap->mode == splashModeDeviceN8) { + for (int k = 4; k < 4 + SPOT_NCOMPS; k++) { + cBlend[k] = 0; + } + } +#endif + (*state->blendFunc)(cSrc, cDest, cBlend, bitmap->mode); + } + + //----- result alpha and non-isolated group element correction + + if (pipe->noTransparency) { + alphaI = alphaIm1 = aResult = 255; + } else { + aResult = aSrc + aDest - div255(aSrc * aDest); + + // alphaI = alpha_i + // alphaIm1 = alpha_(i-1) + if (pipe->alpha0Ptr) { + alpha0 = *pipe->alpha0Ptr++; + alphaI = aResult + alpha0 - div255(aResult * alpha0); + alphaIm1 = alpha0 + aDest - div255(alpha0 * aDest); + } else { + alphaI = aResult; + alphaIm1 = aDest; + } + } + + //----- 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])]; + break; + case splashPipeResultColorNoAlphaBlendRGB: + cResult0 = state->rgbTransferR[div255((255 - aDest) * cSrc[0] + + aDest * cBlend[0])]; + cResult1 = state->rgbTransferG[div255((255 - aDest) * cSrc[1] + + aDest * cBlend[1])]; + cResult2 = state->rgbTransferB[div255((255 - aDest) * cSrc[2] + + aDest * cBlend[2])]; + break; +#if SPLASH_CMYK + case splashPipeResultColorNoAlphaBlendCMYK: + cResult0 = state->cmykTransferC[div255((255 - aDest) * cSrc[0] + + aDest * cBlend[0])]; + cResult1 = state->cmykTransferM[div255((255 - aDest) * cSrc[1] + + aDest * cBlend[1])]; + cResult2 = state->cmykTransferY[div255((255 - aDest) * cSrc[2] + + aDest * cBlend[2])]; + cResult3 = state->cmykTransferK[div255((255 - aDest) * cSrc[3] + + aDest * cBlend[3])]; + break; + case splashPipeResultColorNoAlphaBlendDeviceN: + for (cp = 0; cp < SPOT_NCOMPS+4; cp++) + cResult[cp] = state->deviceNTransfer[cp][div255((255 - aDest) * cSrc[cp] + + aDest * cBlend[cp])]; + break; +#endif + + case splashPipeResultColorAlphaNoBlendMono: + if (alphaI == 0) { + cResult0 = 0; + } else { + cResult0 = state->grayTransfer[((alphaI - aSrc) * cDest[0] + + aSrc * cSrc[0]) / alphaI]; + } + break; + case splashPipeResultColorAlphaNoBlendRGB: + if (alphaI == 0) { + cResult0 = 0; + 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]; + } + break; +#if SPLASH_CMYK + case splashPipeResultColorAlphaNoBlendCMYK: + if (alphaI == 0) { + cResult0 = 0; + cResult1 = 0; + 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]; + } + break; + case splashPipeResultColorAlphaNoBlendDeviceN: + if (alphaI == 0) { + for (cp = 0; cp < SPOT_NCOMPS+4; cp++) + cResult[cp] = 0; + } else { + for (cp = 0; cp < SPOT_NCOMPS+4; cp++) + cResult[cp] = state->deviceNTransfer[cp][((alphaI - aSrc) * cDest[cp] + + aSrc * cSrc[cp]) / alphaI]; + } + break; +#endif + + case splashPipeResultColorAlphaBlendMono: + if (alphaI == 0) { + cResult0 = 0; + } else { + cResult0 = state->grayTransfer[((alphaI - aSrc) * cDest[0] + + aSrc * ((255 - alphaIm1) * cSrc[0] + + alphaIm1 * cBlend[0]) / 255) / + alphaI]; + } + break; + case splashPipeResultColorAlphaBlendRGB: + if (alphaI == 0) { + cResult0 = 0; + 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]; + } + break; +#if SPLASH_CMYK + case splashPipeResultColorAlphaBlendCMYK: + if (alphaI == 0) { + cResult0 = 0; + cResult1 = 0; + 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]; + } + break; + case splashPipeResultColorAlphaBlendDeviceN: + if (alphaI == 0) { + for (cp = 0; cp < SPOT_NCOMPS+4; cp++) + cResult[cp] = 0; + } else { + for (cp = 0; cp < SPOT_NCOMPS+4; cp++) + cResult[cp] = state->deviceNTransfer[cp][((alphaI - aSrc) * cDest[cp] + + aSrc * ((255 - alphaIm1) * cSrc[cp] + + alphaIm1 * cBlend[cp]) / 255) / + alphaI]; + } + break; +#endif + } + + //----- write destination pixel + + switch (bitmap->mode) { + case splashModeMono1: + if (state->screen->test(pipe->x, pipe->y, cResult0)) { + *pipe->destColorPtr |= pipe->destColorMask; + } else { + *pipe->destColorPtr &= ~pipe->destColorMask; + } + if (!(pipe->destColorMask >>= 1)) { + pipe->destColorMask = 0x80; + ++pipe->destColorPtr; + } + break; + case splashModeMono8: + *pipe->destColorPtr++ = cResult0; + break; + case splashModeRGB8: + *pipe->destColorPtr++ = cResult0; + *pipe->destColorPtr++ = cResult1; + *pipe->destColorPtr++ = cResult2; + break; + case splashModeXBGR8: + *pipe->destColorPtr++ = cResult2; + *pipe->destColorPtr++ = cResult1; + *pipe->destColorPtr++ = cResult0; + *pipe->destColorPtr++ = 255; + break; + case splashModeBGR8: + *pipe->destColorPtr++ = cResult2; + *pipe->destColorPtr++ = cResult1; + *pipe->destColorPtr++ = cResult0; + break; +#if SPLASH_CMYK + case splashModeCMYK8: + if (state->overprintMask & 1) { + pipe->destColorPtr[0] = (state->overprintAdditive) ? + std::min<int>(pipe->destColorPtr[0] + cResult0, 255) : + cResult0; + } + if (state->overprintMask & 2) { + pipe->destColorPtr[1] = (state->overprintAdditive) ? + std::min<int>(pipe->destColorPtr[1] + cResult1, 255) : + cResult1; + } + if (state->overprintMask & 4) { + pipe->destColorPtr[2] = (state->overprintAdditive) ? + std::min<int>(pipe->destColorPtr[2] + cResult2, 255) : + cResult2; + } + if (state->overprintMask & 8) { + pipe->destColorPtr[3] = (state->overprintAdditive) ? + std::min<int>(pipe->destColorPtr[3] + cResult3, 255) : + cResult3; + } + pipe->destColorPtr += 4; + break; + case splashModeDeviceN8: + mask = 1; + for (cp = 0; cp < SPOT_NCOMPS+4; cp++) { + if (state->overprintMask & mask) { + pipe->destColorPtr[cp] = cResult[cp]; + } + mask <<=1; + } + pipe->destColorPtr += (SPOT_NCOMPS+4); + break; +#endif + } + if (pipe->destAlphaPtr) { + *pipe->destAlphaPtr++ = aResult; + } + + } + + ++pipe->x; +} + +// special case: +// !pipe->pattern && pipe->noTransparency && !state->blendFunc && +// bitmap->mode == splashModeMono1 && !pipe->destAlphaPtr) { +void Splash::pipeRunSimpleMono1(SplashPipe *pipe) { + Guchar cResult0; + + //----- write destination pixel + cResult0 = state->grayTransfer[pipe->cSrc[0]]; + if (state->screen->test(pipe->x, pipe->y, cResult0)) { + *pipe->destColorPtr |= pipe->destColorMask; + } else { + *pipe->destColorPtr &= ~pipe->destColorMask; + } + if (!(pipe->destColorMask >>= 1)) { + pipe->destColorMask = 0x80; + ++pipe->destColorPtr; + } + + ++pipe->x; +} + +// special case: +// !pipe->pattern && pipe->noTransparency && !state->blendFunc && +// bitmap->mode == splashModeMono8 && pipe->destAlphaPtr) { +void Splash::pipeRunSimpleMono8(SplashPipe *pipe) { + //----- write destination pixel + *pipe->destColorPtr++ = state->grayTransfer[pipe->cSrc[0]]; + *pipe->destAlphaPtr++ = 255; + + ++pipe->x; +} + +// special case: +// !pipe->pattern && pipe->noTransparency && !state->blendFunc && +// bitmap->mode == splashModeRGB8 && pipe->destAlphaPtr) { +void Splash::pipeRunSimpleRGB8(SplashPipe *pipe) { + //----- write destination pixel + *pipe->destColorPtr++ = state->rgbTransferR[pipe->cSrc[0]]; + *pipe->destColorPtr++ = state->rgbTransferG[pipe->cSrc[1]]; + *pipe->destColorPtr++ = state->rgbTransferB[pipe->cSrc[2]]; + *pipe->destAlphaPtr++ = 255; + + ++pipe->x; +} + +// special case: +// !pipe->pattern && pipe->noTransparency && !state->blendFunc && +// bitmap->mode == splashModeXBGR8 && pipe->destAlphaPtr) { +void Splash::pipeRunSimpleXBGR8(SplashPipe *pipe) { + //----- write destination pixel + *pipe->destColorPtr++ = state->rgbTransferB[pipe->cSrc[2]]; + *pipe->destColorPtr++ = state->rgbTransferG[pipe->cSrc[1]]; + *pipe->destColorPtr++ = state->rgbTransferR[pipe->cSrc[0]]; + *pipe->destColorPtr++ = 255; + *pipe->destAlphaPtr++ = 255; + + ++pipe->x; +} + +// special case: +// !pipe->pattern && pipe->noTransparency && !state->blendFunc && +// bitmap->mode == splashModeBGR8 && pipe->destAlphaPtr) { +void Splash::pipeRunSimpleBGR8(SplashPipe *pipe) { + //----- write destination pixel + *pipe->destColorPtr++ = state->rgbTransferB[pipe->cSrc[2]]; + *pipe->destColorPtr++ = state->rgbTransferG[pipe->cSrc[1]]; + *pipe->destColorPtr++ = state->rgbTransferR[pipe->cSrc[0]]; + *pipe->destAlphaPtr++ = 255; + + ++pipe->x; +} + +#if SPLASH_CMYK +// special case: +// !pipe->pattern && pipe->noTransparency && !state->blendFunc && +// bitmap->mode == splashModeCMYK8 && pipe->destAlphaPtr) { +void Splash::pipeRunSimpleCMYK8(SplashPipe *pipe) { + //----- write destination pixel + if (state->overprintMask & 1) { + pipe->destColorPtr[0] = (state->overprintAdditive) ? + std::min<int>(pipe->destColorPtr[0] + state->cmykTransferC[pipe->cSrc[0]], 255) : + state->cmykTransferC[pipe->cSrc[0]]; + } + if (state->overprintMask & 2) { + pipe->destColorPtr[1] = (state->overprintAdditive) ? + std::min<int>(pipe->destColorPtr[1] + state->cmykTransferM[pipe->cSrc[1]], 255) : + state->cmykTransferM[pipe->cSrc[1]]; + } + if (state->overprintMask & 4) { + pipe->destColorPtr[2] = (state->overprintAdditive) ? + std::min<int>(pipe->destColorPtr[2] + state->cmykTransferY[pipe->cSrc[2]], 255) : + state->cmykTransferY[pipe->cSrc[2]]; + } + if (state->overprintMask & 8) { + pipe->destColorPtr[3] = (state->overprintAdditive) ? + std::min<int>(pipe->destColorPtr[3] + state->cmykTransferK[pipe->cSrc[3]], 255) : + state->cmykTransferK[pipe->cSrc[3]]; + } + pipe->destColorPtr += 4; + *pipe->destAlphaPtr++ = 255; + + ++pipe->x; +} + +// special case: +// !pipe->pattern && pipe->noTransparency && !state->blendFunc && +// bitmap->mode == splashModeDeviceN8 && pipe->destAlphaPtr) { +void Splash::pipeRunSimpleDeviceN8(SplashPipe *pipe) { + //----- write destination pixel + int mask = 1; + for (int cp = 0; cp < SPOT_NCOMPS+4; cp++) { + if (state->overprintMask & mask) { + pipe->destColorPtr[cp] = state->deviceNTransfer[cp][pipe->cSrc[cp]]; + } + mask <<=1; + } + pipe->destColorPtr += (SPOT_NCOMPS+4); + *pipe->destAlphaPtr++ = 255; + + ++pipe->x; +} +#endif + +// special case: +// !pipe->pattern && !pipe->noTransparency && !state->softMask && +// pipe->usesShape && !pipe->alpha0Ptr && !state->blendFunc && +// !pipe->nonIsolatedGroup && +// bitmap->mode == splashModeMono1 && !pipe->destAlphaPtr +void Splash::pipeRunAAMono1(SplashPipe *pipe) { + Guchar aSrc; + SplashColor cDest; + Guchar cResult0; + + //----- read destination pixel + cDest[0] = (*pipe->destColorPtr & pipe->destColorMask) ? 0xff : 0x00; + + //----- source alpha + aSrc = div255(pipe->aInput * pipe->shape); + + //----- result color + // note: aDest = alpha2 = aResult = 0xff + cResult0 = state->grayTransfer[(Guchar)div255((0xff - aSrc) * cDest[0] + + aSrc * pipe->cSrc[0])]; + + //----- write destination pixel + if (state->screen->test(pipe->x, pipe->y, cResult0)) { + *pipe->destColorPtr |= pipe->destColorMask; + } else { + *pipe->destColorPtr &= ~pipe->destColorMask; + } + if (!(pipe->destColorMask >>= 1)) { + pipe->destColorMask = 0x80; + ++pipe->destColorPtr; + } + + ++pipe->x; +} + +// special case: +// !pipe->pattern && !pipe->noTransparency && !state->softMask && +// pipe->usesShape && !pipe->alpha0Ptr && !state->blendFunc && +// !pipe->nonIsolatedGroup && +// bitmap->mode == splashModeMono8 && pipe->destAlphaPtr +void Splash::pipeRunAAMono8(SplashPipe *pipe) { + Guchar aSrc, aDest, alpha2, aResult; + SplashColor cDest; + Guchar cResult0; + + //----- read destination pixel + cDest[0] = *pipe->destColorPtr; + aDest = *pipe->destAlphaPtr; + + //----- source alpha + aSrc = div255(pipe->aInput * pipe->shape); + + //----- result alpha and non-isolated group element correction + aResult = aSrc + aDest - div255(aSrc * aDest); + alpha2 = aResult; + + //----- result color + if (alpha2 == 0) { + cResult0 = 0; + } else { + cResult0 = state->grayTransfer[(Guchar)(((alpha2 - aSrc) * cDest[0] + + aSrc * pipe->cSrc[0]) / alpha2)]; + } + + //----- write destination pixel + *pipe->destColorPtr++ = cResult0; + *pipe->destAlphaPtr++ = aResult; + + ++pipe->x; +} + +// special case: +// !pipe->pattern && !pipe->noTransparency && !state->softMask && +// pipe->usesShape && !pipe->alpha0Ptr && !state->blendFunc && +// !pipe->nonIsolatedGroup && +// bitmap->mode == splashModeRGB8 && pipe->destAlphaPtr +void Splash::pipeRunAARGB8(SplashPipe *pipe) { + Guchar aSrc, aDest, alpha2, aResult; + SplashColor cDest; + Guchar cResult0, cResult1, cResult2; + + //----- read destination pixel + cDest[0] = pipe->destColorPtr[0]; + cDest[1] = pipe->destColorPtr[1]; + cDest[2] = pipe->destColorPtr[2]; + aDest = *pipe->destAlphaPtr; + + //----- source alpha + aSrc = div255(pipe->aInput * pipe->shape); + + //----- result alpha and non-isolated group element correction + aResult = aSrc + aDest - div255(aSrc * aDest); + alpha2 = aResult; + + //----- result color + if (alpha2 == 0) { + cResult0 = 0; + cResult1 = 0; + cResult2 = 0; + } else { + cResult0 = state->rgbTransferR[(Guchar)(((alpha2 - aSrc) * cDest[0] + + aSrc * pipe->cSrc[0]) / alpha2)]; + cResult1 = state->rgbTransferG[(Guchar)(((alpha2 - aSrc) * cDest[1] + + aSrc * pipe->cSrc[1]) / alpha2)]; + cResult2 = state->rgbTransferB[(Guchar)(((alpha2 - aSrc) * cDest[2] + + aSrc * pipe->cSrc[2]) / alpha2)]; + } + + //----- write destination pixel + *pipe->destColorPtr++ = cResult0; + *pipe->destColorPtr++ = cResult1; + *pipe->destColorPtr++ = cResult2; + *pipe->destAlphaPtr++ = aResult; + + ++pipe->x; +} + +// special case: +// !pipe->pattern && !pipe->noTransparency && !state->softMask && +// pipe->usesShape && !pipe->alpha0Ptr && !state->blendFunc && +// !pipe->nonIsolatedGroup && +// bitmap->mode == splashModeXBGR8 && pipe->destAlphaPtr +void Splash::pipeRunAAXBGR8(SplashPipe *pipe) { + Guchar aSrc, aDest, alpha2, aResult; + SplashColor cDest; + Guchar cResult0, cResult1, cResult2; + + //----- read destination pixel + cDest[0] = pipe->destColorPtr[2]; + cDest[1] = pipe->destColorPtr[1]; + cDest[2] = pipe->destColorPtr[0]; + aDest = *pipe->destAlphaPtr; + + //----- source alpha + aSrc = div255(pipe->aInput * pipe->shape); + + //----- result alpha and non-isolated group element correction + aResult = aSrc + aDest - div255(aSrc * aDest); + alpha2 = aResult; + + //----- result color + if (alpha2 == 0) { + cResult0 = 0; + cResult1 = 0; + cResult2 = 0; + } else { + cResult0 = state->rgbTransferR[(Guchar)(((alpha2 - aSrc) * cDest[0] + + aSrc * pipe->cSrc[0]) / alpha2)]; + cResult1 = state->rgbTransferG[(Guchar)(((alpha2 - aSrc) * cDest[1] + + aSrc * pipe->cSrc[1]) / alpha2)]; + cResult2 = state->rgbTransferB[(Guchar)(((alpha2 - aSrc) * cDest[2] + + aSrc * pipe->cSrc[2]) / alpha2)]; + } + + //----- write destination pixel + *pipe->destColorPtr++ = cResult2; + *pipe->destColorPtr++ = cResult1; + *pipe->destColorPtr++ = cResult0; + *pipe->destColorPtr++ = 255; + *pipe->destAlphaPtr++ = aResult; + + ++pipe->x; +} + +// special case: +// !pipe->pattern && !pipe->noTransparency && !state->softMask && +// pipe->usesShape && !pipe->alpha0Ptr && !state->blendFunc && +// !pipe->nonIsolatedGroup && +// bitmap->mode == splashModeBGR8 && pipe->destAlphaPtr +void Splash::pipeRunAABGR8(SplashPipe *pipe) { + Guchar aSrc, aDest, alpha2, aResult; + SplashColor cDest; + Guchar cResult0, cResult1, cResult2; + + //----- read destination pixel + cDest[0] = pipe->destColorPtr[2]; + cDest[1] = pipe->destColorPtr[1]; + cDest[2] = pipe->destColorPtr[0]; + aDest = *pipe->destAlphaPtr; + + //----- source alpha + aSrc = div255(pipe->aInput * pipe->shape); + + //----- result alpha and non-isolated group element correction + aResult = aSrc + aDest - div255(aSrc * aDest); + alpha2 = aResult; + + //----- result color + if (alpha2 == 0) { + cResult0 = 0; + cResult1 = 0; + cResult2 = 0; + } else { + cResult0 = state->rgbTransferR[(Guchar)(((alpha2 - aSrc) * cDest[0] + + aSrc * pipe->cSrc[0]) / alpha2)]; + cResult1 = state->rgbTransferG[(Guchar)(((alpha2 - aSrc) * cDest[1] + + aSrc * pipe->cSrc[1]) / alpha2)]; + cResult2 = state->rgbTransferB[(Guchar)(((alpha2 - aSrc) * cDest[2] + + aSrc * pipe->cSrc[2]) / alpha2)]; + } + + //----- write destination pixel + *pipe->destColorPtr++ = cResult2; + *pipe->destColorPtr++ = cResult1; + *pipe->destColorPtr++ = cResult0; + *pipe->destAlphaPtr++ = aResult; + + ++pipe->x; +} + +#if SPLASH_CMYK +// special case: +// !pipe->pattern && !pipe->noTransparency && !state->softMask && +// pipe->usesShape && !pipe->alpha0Ptr && !state->blendFunc && +// !pipe->nonIsolatedGroup && +// bitmap->mode == splashModeCMYK8 && pipe->destAlphaPtr +void Splash::pipeRunAACMYK8(SplashPipe *pipe) { + Guchar aSrc, aDest, alpha2, aResult; + SplashColor cDest; + Guchar cResult0, cResult1, cResult2, cResult3; + + //----- read destination pixel + cDest[0] = pipe->destColorPtr[0]; + cDest[1] = pipe->destColorPtr[1]; + cDest[2] = pipe->destColorPtr[2]; + cDest[3] = pipe->destColorPtr[3]; + aDest = *pipe->destAlphaPtr; + + //----- source alpha + aSrc = div255(pipe->aInput * pipe->shape); + + //----- result alpha and non-isolated group element correction + aResult = aSrc + aDest - div255(aSrc * aDest); + alpha2 = aResult; + + //----- result color + if (alpha2 == 0) { + cResult0 = 0; + cResult1 = 0; + cResult2 = 0; + cResult3 = 0; + } else { + cResult0 = state->cmykTransferC[(Guchar)(((alpha2 - aSrc) * cDest[0] + + aSrc * pipe->cSrc[0]) / alpha2)]; + cResult1 = state->cmykTransferM[(Guchar)(((alpha2 - aSrc) * cDest[1] + + aSrc * pipe->cSrc[1]) / alpha2)]; + cResult2 = state->cmykTransferY[(Guchar)(((alpha2 - aSrc) * cDest[2] + + aSrc * pipe->cSrc[2]) / alpha2)]; + cResult3 = state->cmykTransferK[(Guchar)(((alpha2 - aSrc) * cDest[3] + + aSrc * pipe->cSrc[3]) / alpha2)]; + } + + //----- write destination pixel + if (state->overprintMask & 1) { + pipe->destColorPtr[0] = (state->overprintAdditive && pipe->shape != 0) ? + std::min<int>(pipe->destColorPtr[0] + cResult0, 255) : + cResult0; + } + if (state->overprintMask & 2) { + pipe->destColorPtr[1] = (state->overprintAdditive && pipe->shape != 0) ? + std::min<int>(pipe->destColorPtr[1] + cResult1, 255) : + cResult1; + } + if (state->overprintMask & 4) { + pipe->destColorPtr[2] = (state->overprintAdditive && pipe->shape != 0) ? + std::min<int>(pipe->destColorPtr[2] + cResult2, 255) : + cResult2; + } + if (state->overprintMask & 8) { + pipe->destColorPtr[3] = (state->overprintAdditive && pipe->shape != 0) ? + std::min<int>(pipe->destColorPtr[3] + cResult3, 255) : + cResult3; + } + pipe->destColorPtr += 4; + *pipe->destAlphaPtr++ = aResult; + + ++pipe->x; +} + +// special case: +// !pipe->pattern && !pipe->noTransparency && !state->softMask && +// pipe->usesShape && !pipe->alpha0Ptr && !state->blendFunc && +// !pipe->nonIsolatedGroup && +// bitmap->mode == splashModeDeviceN8 && pipe->destAlphaPtr +void Splash::pipeRunAADeviceN8(SplashPipe *pipe) { + Guchar aSrc, aDest, alpha2, aResult; + SplashColor cDest; + Guchar cResult[SPOT_NCOMPS+4]; + int cp, mask; + + //----- read destination pixel + for (cp=0; cp < SPOT_NCOMPS+4; cp++) + cDest[cp] = pipe->destColorPtr[cp]; + aDest = *pipe->destAlphaPtr; + + //----- source alpha + aSrc = div255(pipe->aInput * pipe->shape); + + //----- result alpha and non-isolated group element correction + aResult = aSrc + aDest - div255(aSrc * aDest); + alpha2 = aResult; + + //----- result color + if (alpha2 == 0) { + for (cp=0; cp < SPOT_NCOMPS+4; cp++) + cResult[cp] = 0; + } else { + for (cp=0; cp < SPOT_NCOMPS+4; cp++) + cResult[cp] = state->deviceNTransfer[cp][(Guchar)(((alpha2 - aSrc) * cDest[cp] + + aSrc * pipe->cSrc[cp]) / alpha2)]; + } + + //----- write destination pixel + mask = 1; + for (cp=0; cp < SPOT_NCOMPS+4; cp++) { + if (state->overprintMask & mask) { + pipe->destColorPtr[cp] = cResult[cp]; + } + mask <<= 1; + } + pipe->destColorPtr += (SPOT_NCOMPS+4); + *pipe->destAlphaPtr++ = aResult; + + ++pipe->x; +} +#endif + +inline void Splash::pipeSetXY(SplashPipe *pipe, int x, int y) { + pipe->x = x; + pipe->y = y; + if (state->softMask) { + pipe->softMaskPtr = + &state->softMask->data[y * state->softMask->rowSize + x]; + } + switch (bitmap->mode) { + case splashModeMono1: + pipe->destColorPtr = &bitmap->data[y * bitmap->rowSize + (x >> 3)]; + pipe->destColorMask = 0x80 >> (x & 7); + break; + case splashModeMono8: + pipe->destColorPtr = &bitmap->data[y * bitmap->rowSize + x]; + break; + case splashModeRGB8: + case splashModeBGR8: + pipe->destColorPtr = &bitmap->data[y * bitmap->rowSize + 3 * x]; + break; + case splashModeXBGR8: + pipe->destColorPtr = &bitmap->data[y * bitmap->rowSize + 4 * x]; + break; +#if SPLASH_CMYK + case splashModeCMYK8: + pipe->destColorPtr = &bitmap->data[y * bitmap->rowSize + 4 * x]; + break; + case splashModeDeviceN8: + pipe->destColorPtr = &bitmap->data[y * bitmap->rowSize + (SPOT_NCOMPS + 4) * x]; + break; +#endif + } + if (bitmap->alpha) { + pipe->destAlphaPtr = &bitmap->alpha[y * bitmap->width + x]; + } else { + pipe->destAlphaPtr = NULL; + } + if (state->inNonIsolatedGroup && alpha0Bitmap->alpha) { + pipe->alpha0Ptr = + &alpha0Bitmap->alpha[(alpha0Y + y) * alpha0Bitmap->width + + (alpha0X + x)]; + } else { + pipe->alpha0Ptr = NULL; + } +} + +inline void Splash::pipeIncX(SplashPipe *pipe) { + ++pipe->x; + if (state->softMask) { + ++pipe->softMaskPtr; + } + switch (bitmap->mode) { + case splashModeMono1: + if (!(pipe->destColorMask >>= 1)) { + pipe->destColorMask = 0x80; + ++pipe->destColorPtr; + } + break; + case splashModeMono8: + ++pipe->destColorPtr; + break; + case splashModeRGB8: + case splashModeBGR8: + pipe->destColorPtr += 3; + break; + case splashModeXBGR8: + pipe->destColorPtr += 4; + break; +#if SPLASH_CMYK + case splashModeCMYK8: + pipe->destColorPtr += 4; + break; + case splashModeDeviceN8: + pipe->destColorPtr += (SPOT_NCOMPS+4); + break; +#endif + } + if (pipe->destAlphaPtr) { + ++pipe->destAlphaPtr; + } + if (pipe->alpha0Ptr) { + ++pipe->alpha0Ptr; + } +} + +inline void Splash::drawPixel(SplashPipe *pipe, int x, int y, GBool noClip) { + if (unlikely(y < 0)) + return; + + if (noClip || state->clip->test(x, y)) { + pipeSetXY(pipe, x, y); + (this->*pipe->run)(pipe); + updateModX(x); + updateModY(y); + } +} + +inline void Splash::drawAAPixelInit() { + aaBufY = -1; +} + +inline void Splash::drawAAPixel(SplashPipe *pipe, int x, int y) { +#if splashAASize == 4 + static int bitCount4[16] = { 0, 1, 1, 2, 1, 2, 2, 3, + 1, 2, 2, 3, 2, 3, 3, 4 }; + int w; +#else + int xx, yy; +#endif + SplashColorPtr p; + int x0, x1, t; + + if (x < 0 || x >= bitmap->width || + y < state->clip->getYMinI() || y > state->clip->getYMaxI()) { + return; + } + + // update aaBuf + if (y != aaBufY) { + memset(aaBuf->getDataPtr(), 0xff, + aaBuf->getRowSize() * aaBuf->getHeight()); + x0 = 0; + x1 = bitmap->width - 1; + state->clip->clipAALine(aaBuf, &x0, &x1, y); + aaBufY = y; + } + + // compute the shape value +#if splashAASize == 4 + p = aaBuf->getDataPtr() + (x >> 1); + w = aaBuf->getRowSize(); + if (x & 1) { + t = bitCount4[*p & 0x0f] + bitCount4[p[w] & 0x0f] + + bitCount4[p[2*w] & 0x0f] + bitCount4[p[3*w] & 0x0f]; + } else { + t = bitCount4[*p >> 4] + bitCount4[p[w] >> 4] + + bitCount4[p[2*w] >> 4] + bitCount4[p[3*w] >> 4]; + } +#else + t = 0; + for (yy = 0; yy < splashAASize; ++yy) { + for (xx = 0; xx < splashAASize; ++xx) { + p = aaBuf->getDataPtr() + yy * aaBuf->getRowSize() + + ((x * splashAASize + xx) >> 3); + t += (*p >> (7 - ((x * splashAASize + xx) & 7))) & 1; + } + } +#endif + + // draw the pixel + if (t != 0) { + pipeSetXY(pipe, x, y); + pipe->shape = div255(aaGamma[t] * pipe->shape); + (this->*pipe->run)(pipe); + updateModX(x); + updateModY(y); + } +} + +inline void Splash::drawSpan(SplashPipe *pipe, int x0, int x1, int y, + GBool noClip) { + int x; + + if (noClip) { + pipeSetXY(pipe, x0, y); + for (x = x0; x <= x1; ++x) { + (this->*pipe->run)(pipe); + } + updateModX(x0); + updateModX(x1); + updateModY(y); + } else { + if (x0 < state->clip->getXMinI()) { + x0 = state->clip->getXMinI(); + } + if (x1 > state->clip->getXMaxI()) { + x1 = state->clip->getXMaxI(); + } + pipeSetXY(pipe, x0, y); + for (x = x0; x <= x1; ++x) { + if (state->clip->test(x, y)) { + (this->*pipe->run)(pipe); + updateModX(x); + updateModY(y); + } else { + pipeIncX(pipe); + } + } + } +} + +inline void Splash::drawAALine(SplashPipe *pipe, int x0, int x1, int y, GBool adjustLine, Guchar lineOpacity) { +#if splashAASize == 4 + static int bitCount4[16] = { 0, 1, 1, 2, 1, 2, 2, 3, + 1, 2, 2, 3, 2, 3, 3, 4 }; + SplashColorPtr p0, p1, p2, p3; + int t; +#else + SplashColorPtr p; + int xx, yy, t; +#endif + int x; + +#if splashAASize == 4 + p0 = aaBuf->getDataPtr() + (x0 >> 1); + p1 = p0 + aaBuf->getRowSize(); + p2 = p1 + aaBuf->getRowSize(); + p3 = p2 + aaBuf->getRowSize(); +#endif + pipeSetXY(pipe, x0, y); + for (x = x0; x <= x1; ++x) { + + // compute the shape value +#if splashAASize == 4 + if (x & 1) { + t = bitCount4[*p0 & 0x0f] + bitCount4[*p1 & 0x0f] + + bitCount4[*p2 & 0x0f] + bitCount4[*p3 & 0x0f]; + ++p0; ++p1; ++p2; ++p3; + } else { + t = bitCount4[*p0 >> 4] + bitCount4[*p1 >> 4] + + bitCount4[*p2 >> 4] + bitCount4[*p3 >> 4]; + } +#else + t = 0; + for (yy = 0; yy < splashAASize; ++yy) { + for (xx = 0; xx < splashAASize; ++xx) { + p = aaBuf->getDataPtr() + yy * aaBuf->getRowSize() + + ((x * splashAASize + xx) >> 3); + t += (*p >> (7 - ((x * splashAASize + xx) & 7))) & 1; + } + } +#endif + + if (t != 0) { + pipe->shape = (adjustLine) ? div255((int) lineOpacity * (double)aaGamma[t]) : (double)aaGamma[t]; + (this->*pipe->run)(pipe); + updateModX(x); + updateModY(y); + } else { + pipeIncX(pipe); + } + } +} + +//------------------------------------------------------------------------ + +// Transform a point from user space to device space. +inline void Splash::transform(SplashCoord *matrix, + SplashCoord xi, SplashCoord yi, + SplashCoord *xo, SplashCoord *yo) { + // [ m[0] m[1] 0 ] + // [xo yo 1] = [xi yi 1] * [ m[2] m[3] 0 ] + // [ m[4] m[5] 1 ] + *xo = xi * matrix[0] + yi * matrix[2] + matrix[4]; + *yo = xi * matrix[1] + yi * matrix[3] + matrix[5]; +} + +//------------------------------------------------------------------------ +// Splash +//------------------------------------------------------------------------ + +Splash::Splash(SplashBitmap *bitmapA, GBool vectorAntialiasA, + SplashScreenParams *screenParams) { + int i; + + bitmap = bitmapA; + vectorAntialias = vectorAntialiasA; + inShading = gFalse; + state = new SplashState(bitmap->width, bitmap->height, vectorAntialias, + screenParams); + if (vectorAntialias) { + aaBuf = new SplashBitmap(splashAASize * bitmap->width, splashAASize, + 1, splashModeMono1, gFalse); + for (i = 0; i <= splashAASize * splashAASize; ++i) { + aaGamma[i] = (Guchar)splashRound( + splashPow((SplashCoord)i / + (SplashCoord)(splashAASize * splashAASize), + splashAAGamma) * 255); + } + } else { + aaBuf = NULL; + } + minLineWidth = 0; + thinLineMode = splashThinLineDefault; + clearModRegion(); + debugMode = gFalse; + alpha0Bitmap = NULL; +} + +Splash::Splash(SplashBitmap *bitmapA, GBool vectorAntialiasA, + SplashScreen *screenA) { + int i; + + bitmap = bitmapA; + inShading = gFalse; + vectorAntialias = vectorAntialiasA; + state = new SplashState(bitmap->width, bitmap->height, vectorAntialias, + screenA); + if (vectorAntialias) { + aaBuf = new SplashBitmap(splashAASize * bitmap->width, splashAASize, + 1, splashModeMono1, gFalse); + for (i = 0; i <= splashAASize * splashAASize; ++i) { + aaGamma[i] = (Guchar)splashRound( + splashPow((SplashCoord)i / + (SplashCoord)(splashAASize * splashAASize), + splashAAGamma) * 255); + } + } else { + aaBuf = NULL; + } + minLineWidth = 0; + thinLineMode = splashThinLineDefault; + clearModRegion(); + debugMode = gFalse; + alpha0Bitmap = NULL; +} + +Splash::~Splash() { + while (state->next) { + restoreState(); + } + delete state; + if (vectorAntialias) { + delete aaBuf; + } +} + +//------------------------------------------------------------------------ +// state read +//------------------------------------------------------------------------ + +SplashCoord *Splash::getMatrix() { + return state->matrix; +} + +SplashPattern *Splash::getStrokePattern() { + return state->strokePattern; +} + +SplashPattern *Splash::getFillPattern() { + return state->fillPattern; +} + +SplashScreen *Splash::getScreen() { + return state->screen; +} + +SplashBlendFunc Splash::getBlendFunc() { + return state->blendFunc; +} + +SplashCoord Splash::getStrokeAlpha() { + return state->strokeAlpha; +} + +SplashCoord Splash::getFillAlpha() { + return state->fillAlpha; +} + +SplashCoord Splash::getLineWidth() { + return state->lineWidth; +} + +int Splash::getLineCap() { + return state->lineCap; +} + +int Splash::getLineJoin() { + return state->lineJoin; +} + +SplashCoord Splash::getMiterLimit() { + return state->miterLimit; +} + +SplashCoord Splash::getFlatness() { + return state->flatness; +} + +SplashCoord *Splash::getLineDash() { + return state->lineDash; +} + +int Splash::getLineDashLength() { + return state->lineDashLength; +} + +SplashCoord Splash::getLineDashPhase() { + return state->lineDashPhase; +} + +GBool Splash::getStrokeAdjust() { + return state->strokeAdjust; +} + +SplashClip *Splash::getClip() { + return state->clip; +} + +SplashBitmap *Splash::getSoftMask() { + return state->softMask; +} + +GBool Splash::getInNonIsolatedGroup() { + return state->inNonIsolatedGroup; +} + +//------------------------------------------------------------------------ +// state write +//------------------------------------------------------------------------ + +void Splash::setMatrix(SplashCoord *matrix) { + memcpy(state->matrix, matrix, 6 * sizeof(SplashCoord)); +} + +void Splash::setStrokePattern(SplashPattern *strokePattern) { + state->setStrokePattern(strokePattern); +} + +void Splash::setFillPattern(SplashPattern *fillPattern) { + state->setFillPattern(fillPattern); +} + +void Splash::setScreen(SplashScreen *screen) { + state->setScreen(screen); +} + +void Splash::setBlendFunc(SplashBlendFunc func) { + state->blendFunc = func; +} + +void Splash::setStrokeAlpha(SplashCoord alpha) { + state->strokeAlpha = alpha; +} + +void Splash::setFillAlpha(SplashCoord alpha) { + state->fillAlpha = alpha; +} + +void Splash::setFillOverprint(GBool fop) { + state->fillOverprint = fop; +} + +void Splash::setStrokeOverprint(GBool gop) { + state->strokeOverprint = gop; +} + +void Splash::setOverprintMode(int opm) { + state->overprintMode = opm; +} + +void Splash::setLineWidth(SplashCoord lineWidth) { + state->lineWidth = lineWidth; +} + +void Splash::setLineCap(int lineCap) { + state->lineCap = lineCap; +} + +void Splash::setLineJoin(int lineJoin) { + state->lineJoin = lineJoin; +} + +void Splash::setMiterLimit(SplashCoord miterLimit) { + state->miterLimit = miterLimit; +} + +void Splash::setFlatness(SplashCoord flatness) { + if (flatness < 1) { + state->flatness = 1; + } else { + state->flatness = flatness; + } +} + +void Splash::setLineDash(SplashCoord *lineDash, int lineDashLength, + SplashCoord lineDashPhase) { + state->setLineDash(lineDash, lineDashLength, lineDashPhase); +} + +void Splash::setStrokeAdjust(GBool strokeAdjust) { + state->strokeAdjust = strokeAdjust; +} + +void Splash::clipResetToRect(SplashCoord x0, SplashCoord y0, + SplashCoord x1, SplashCoord y1) { + state->clip->resetToRect(x0, y0, x1, y1); +} + +SplashError Splash::clipToRect(SplashCoord x0, SplashCoord y0, + SplashCoord x1, SplashCoord y1) { + return state->clip->clipToRect(x0, y0, x1, y1); +} + +SplashError Splash::clipToPath(SplashPath *path, GBool eo) { + return state->clip->clipToPath(path, state->matrix, state->flatness, eo); +} + +void Splash::setSoftMask(SplashBitmap *softMask) { + state->setSoftMask(softMask); +} + +void Splash::setInNonIsolatedGroup(SplashBitmap *alpha0BitmapA, + int alpha0XA, int alpha0YA) { + alpha0Bitmap = alpha0BitmapA; + alpha0X = alpha0XA; + alpha0Y = alpha0YA; + state->inNonIsolatedGroup = gTrue; +} + +void Splash::setTransfer(Guchar *red, Guchar *green, Guchar *blue, + Guchar *gray) { + state->setTransfer(red, green, blue, gray); +} + +void Splash::setOverprintMask(Guint overprintMask, GBool additive) { + state->overprintMask = overprintMask; + state->overprintAdditive = additive; +} + +//------------------------------------------------------------------------ +// state save/restore +//------------------------------------------------------------------------ + +void Splash::saveState() { + SplashState *newState; + + newState = state->copy(); + newState->next = state; + state = newState; +} + +SplashError Splash::restoreState() { + SplashState *oldState; + + if (!state->next) { + return splashErrNoSave; + } + oldState = state; + state = state->next; + delete oldState; + return splashOk; +} + +//------------------------------------------------------------------------ +// drawing operations +//------------------------------------------------------------------------ + +void Splash::clear(SplashColorPtr color, Guchar alpha) { + SplashColorPtr row, p; + Guchar mono; + int x, y; + + switch (bitmap->mode) { + case splashModeMono1: + mono = (color[0] & 0x80) ? 0xff : 0x00; + if (bitmap->rowSize < 0) { + memset(bitmap->data + bitmap->rowSize * (bitmap->height - 1), + mono, -bitmap->rowSize * bitmap->height); + } else { + memset(bitmap->data, mono, bitmap->rowSize * bitmap->height); + } + break; + case splashModeMono8: + if (bitmap->rowSize < 0) { + memset(bitmap->data + bitmap->rowSize * (bitmap->height - 1), + color[0], -bitmap->rowSize * bitmap->height); + } else { + memset(bitmap->data, color[0], bitmap->rowSize * bitmap->height); + } + break; + case splashModeRGB8: + if (color[0] == color[1] && color[1] == color[2]) { + if (bitmap->rowSize < 0) { + memset(bitmap->data + bitmap->rowSize * (bitmap->height - 1), + color[0], -bitmap->rowSize * bitmap->height); + } else { + memset(bitmap->data, color[0], bitmap->rowSize * bitmap->height); + } + } else { + row = bitmap->data; + for (y = 0; y < bitmap->height; ++y) { + p = row; + for (x = 0; x < bitmap->width; ++x) { + *p++ = color[2]; + *p++ = color[1]; + *p++ = color[0]; + } + row += bitmap->rowSize; + } + } + break; + case splashModeXBGR8: + if (color[0] == color[1] && color[1] == color[2]) { + if (bitmap->rowSize < 0) { + memset(bitmap->data + bitmap->rowSize * (bitmap->height - 1), + color[0], -bitmap->rowSize * bitmap->height); + } else { + memset(bitmap->data, color[0], bitmap->rowSize * bitmap->height); + } + } else { + row = bitmap->data; + for (y = 0; y < bitmap->height; ++y) { + p = row; + for (x = 0; x < bitmap->width; ++x) { + *p++ = color[0]; + *p++ = color[1]; + *p++ = color[2]; + *p++ = 255; + } + row += bitmap->rowSize; + } + } + break; + case splashModeBGR8: + if (color[0] == color[1] && color[1] == color[2]) { + if (bitmap->rowSize < 0) { + memset(bitmap->data + bitmap->rowSize * (bitmap->height - 1), + color[0], -bitmap->rowSize * bitmap->height); + } else { + memset(bitmap->data, color[0], bitmap->rowSize * bitmap->height); + } + } else { + row = bitmap->data; + for (y = 0; y < bitmap->height; ++y) { + p = row; + for (x = 0; x < bitmap->width; ++x) { + *p++ = color[0]; + *p++ = color[1]; + *p++ = color[2]; + } + row += bitmap->rowSize; + } + } + break; +#if SPLASH_CMYK + case splashModeCMYK8: + if (color[0] == color[1] && color[1] == color[2] && color[2] == color[3]) { + if (bitmap->rowSize < 0) { + memset(bitmap->data + bitmap->rowSize * (bitmap->height - 1), + color[0], -bitmap->rowSize * bitmap->height); + } else { + memset(bitmap->data, color[0], bitmap->rowSize * bitmap->height); + } + } else { + row = bitmap->data; + for (y = 0; y < bitmap->height; ++y) { + p = row; + for (x = 0; x < bitmap->width; ++x) { + *p++ = color[0]; + *p++ = color[1]; + *p++ = color[2]; + *p++ = color[3]; + } + row += bitmap->rowSize; + } + } + break; + case splashModeDeviceN8: + row = bitmap->data; + for (y = 0; y < bitmap->height; ++y) { + p = row; + for (x = 0; x < bitmap->width; ++x) { + for (int cp = 0; cp < SPOT_NCOMPS+4; cp++) + *p++ = color[cp]; + } + row += bitmap->rowSize; + } + break; +#endif + } + + if (bitmap->alpha) { + memset(bitmap->alpha, alpha, bitmap->width * bitmap->height); + } + + updateModX(0); + updateModY(0); + updateModX(bitmap->width - 1); + updateModY(bitmap->height - 1); +} + +SplashError Splash::stroke(SplashPath *path) { + SplashPath *path2, *dPath; + SplashCoord d1, d2, t1, t2, w; + + if (debugMode) { + printf("stroke [dash:%d] [width:%.2f]:\n", + state->lineDashLength, (double)state->lineWidth); + dumpPath(path); + } + opClipRes = splashClipAllOutside; + if (path->length == 0) { + 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; + } + } + + // transform a unit square, and take the half the max of the two + // diagonals; the product of this number and the line width is the + // (approximate) transformed line width + t1 = state->matrix[0] + state->matrix[2]; + t2 = state->matrix[1] + state->matrix[3]; + d1 = t1 * t1 + t2 * t2; + t1 = state->matrix[0] - state->matrix[2]; + t2 = state->matrix[1] - state->matrix[3]; + d2 = t1 * t1 + t2 * t2; + if (d2 > d1) { + d1 = d2; + } + d1 *= 0.5; + if (d1 > 0 && + d1 * state->lineWidth * state->lineWidth < minLineWidth * minLineWidth) { + w = minLineWidth / splashSqrt(d1); + strokeWide(path2, w); + } else if (bitmap->mode == splashModeMono1) { + // this gets close to Adobe's behavior in mono mode + if (d1 * state->lineWidth <= 2) { + strokeNarrow(path2); + } else { + strokeWide(path2, state->lineWidth); + } + } else { + if (state->lineWidth == 0) { + strokeNarrow(path2); + } else { + strokeWide(path2, state->lineWidth); + } + } + + delete path2; + return splashOk; +} + +void Splash::strokeNarrow(SplashPath *path) { + SplashPipe pipe; + SplashXPath *xPath; + SplashXPathSeg *seg; + int x0, x1, y0, y1, xa, xb, y; + SplashCoord dxdy; + SplashClipResult clipRes; + int nClipRes[3]; + int i; + + nClipRes[0] = nClipRes[1] = nClipRes[2] = 0; + + xPath = new SplashXPath(path, state->matrix, state->flatness, gFalse); + + pipeInit(&pipe, 0, 0, state->strokePattern, NULL, + (Guchar)splashRound(state->strokeAlpha * 255), + gFalse, gFalse); + + for (i = 0, seg = xPath->segs; i < xPath->length; ++i, ++seg) { + if (seg->y0 <= seg->y1) { + y0 = splashFloor(seg->y0); + y1 = splashFloor(seg->y1); + x0 = splashFloor(seg->x0); + x1 = splashFloor(seg->x1); + } else { + y0 = splashFloor(seg->y1); + y1 = splashFloor(seg->y0); + x0 = splashFloor(seg->x1); + x1 = splashFloor(seg->x0); + } + if ((clipRes = state->clip->testRect(x0 <= x1 ? x0 : x1, y0, + x0 <= x1 ? x1 : x0, y1)) + != splashClipAllOutside) { + if (y0 == y1) { + if (x0 <= x1) { + drawSpan(&pipe, x0, x1, y0, clipRes == splashClipAllInside); + } else { + drawSpan(&pipe, x1, x0, y0, clipRes == splashClipAllInside); + } + } else { + dxdy = seg->dxdy; + if (y0 < state->clip->getYMinI()) { + y0 = state->clip->getYMinI(); + x0 = splashFloor(seg->x0 + ((SplashCoord)y0 - seg->y0) * dxdy); + } + if (y1 > state->clip->getYMaxI()) { + y1 = state->clip->getYMaxI(); + x1 = splashFloor(seg->x0 + ((SplashCoord)y1 - seg->y0) * dxdy); + } + if (x0 <= x1) { + xa = x0; + for (y = y0; y <= y1; ++y) { + if (y < y1) { + xb = splashFloor(seg->x0 + + ((SplashCoord)y + 1 - seg->y0) * dxdy); + } else { + xb = x1 + 1; + } + if (xa == xb) { + drawPixel(&pipe, xa, y, clipRes == splashClipAllInside); + } else { + drawSpan(&pipe, xa, xb - 1, y, clipRes == splashClipAllInside); + } + xa = xb; + } + } else { + xa = x0; + for (y = y0; y <= y1; ++y) { + if (y < y1) { + xb = splashFloor(seg->x0 + + ((SplashCoord)y + 1 - seg->y0) * dxdy); + } else { + xb = x1 - 1; + } + if (xa == xb) { + drawPixel(&pipe, xa, y, clipRes == splashClipAllInside); + } else { + drawSpan(&pipe, xb + 1, xa, y, clipRes == splashClipAllInside); + } + xa = xb; + } + } + } + } + ++nClipRes[clipRes]; + } + if (nClipRes[splashClipPartial] || + (nClipRes[splashClipAllInside] && nClipRes[splashClipAllOutside])) { + opClipRes = splashClipPartial; + } else if (nClipRes[splashClipAllInside]) { + opClipRes = splashClipAllInside; + } else { + opClipRes = splashClipAllOutside; + } + + delete xPath; +} + +void Splash::strokeWide(SplashPath *path, SplashCoord w) { + SplashPath *path2; + + path2 = makeStrokePath(path, w, gFalse); + fillWithPattern(path2, gFalse, state->strokePattern, state->strokeAlpha); + delete path2; +} + +SplashPath *Splash::flattenPath(SplashPath *path, SplashCoord *matrix, + SplashCoord flatness) { + SplashPath *fPath; + SplashCoord flatness2; + Guchar flag; + int i; + + fPath = new SplashPath(); +#if USE_FIXEDPOINT + flatness2 = flatness; +#else + flatness2 = flatness * flatness; +#endif + i = 0; + while (i < path->length) { + flag = path->flags[i]; + if (flag & splashPathFirst) { + fPath->moveTo(path->pts[i].x, path->pts[i].y); + ++i; + } else { + if (flag & splashPathCurve) { + flattenCurve(path->pts[i-1].x, path->pts[i-1].y, + path->pts[i ].x, path->pts[i ].y, + path->pts[i+1].x, path->pts[i+1].y, + path->pts[i+2].x, path->pts[i+2].y, + matrix, flatness2, fPath); + i += 3; + } else { + fPath->lineTo(path->pts[i].x, path->pts[i].y); + ++i; + } + if (path->flags[i-1] & splashPathClosed) { + fPath->close(); + } + } + } + return fPath; +} + +void Splash::flattenCurve(SplashCoord x0, SplashCoord y0, + SplashCoord x1, SplashCoord y1, + SplashCoord x2, SplashCoord y2, + SplashCoord x3, SplashCoord y3, + SplashCoord *matrix, SplashCoord flatness2, + SplashPath *fPath) { + SplashCoord cx[splashMaxCurveSplits + 1][3]; + SplashCoord cy[splashMaxCurveSplits + 1][3]; + int cNext[splashMaxCurveSplits + 1]; + SplashCoord xl0, xl1, xl2, xr0, xr1, xr2, xr3, xx1, xx2, xh; + SplashCoord yl0, yl1, yl2, yr0, yr1, yr2, yr3, yy1, yy2, yh; + SplashCoord dx, dy, mx, my, tx, ty, d1, d2; + int p1, p2, p3; + + // initial segment + p1 = 0; + p2 = splashMaxCurveSplits; + cx[p1][0] = x0; cy[p1][0] = y0; + cx[p1][1] = x1; cy[p1][1] = y1; + cx[p1][2] = x2; cy[p1][2] = y2; + cx[p2][0] = x3; cy[p2][0] = y3; + cNext[p1] = p2; + + while (p1 < splashMaxCurveSplits) { + + // get the next segment + xl0 = cx[p1][0]; yl0 = cy[p1][0]; + xx1 = cx[p1][1]; yy1 = cy[p1][1]; + xx2 = cx[p1][2]; yy2 = cy[p1][2]; + p2 = cNext[p1]; + xr3 = cx[p2][0]; yr3 = cy[p2][0]; + + // compute the distances (in device space) from the control points + // to the midpoint of the straight line (this is a bit of a hack, + // but it's much faster than computing the actual distances to the + // line) + transform(matrix, (xl0 + xr3) * 0.5, (yl0 + yr3) * 0.5, &mx, &my); + transform(matrix, xx1, yy1, &tx, &ty); +#if USE_FIXEDPOINT + d1 = splashDist(tx, ty, mx, my); +#else + dx = tx - mx; + dy = ty - my; + d1 = dx*dx + dy*dy; +#endif + transform(matrix, xx2, yy2, &tx, &ty); +#if USE_FIXEDPOINT + d2 = splashDist(tx, ty, mx, my); +#else + dx = tx - mx; + dy = ty - my; + d2 = dx*dx + dy*dy; +#endif + + // if the curve is flat enough, or no more subdivisions are + // allowed, add the straight line segment + if (p2 - p1 == 1 || (d1 <= flatness2 && d2 <= flatness2)) { + fPath->lineTo(xr3, yr3); + p1 = p2; + + // otherwise, subdivide the curve + } else { + xl1 = splashAvg(xl0, xx1); + yl1 = splashAvg(yl0, yy1); + xh = splashAvg(xx1, xx2); + yh = splashAvg(yy1, yy2); + xl2 = splashAvg(xl1, xh); + yl2 = splashAvg(yl1, yh); + xr2 = splashAvg(xx2, xr3); + yr2 = splashAvg(yy2, yr3); + xr1 = splashAvg(xh, xr2); + yr1 = splashAvg(yh, yr2); + xr0 = splashAvg(xl2, xr1); + yr0 = splashAvg(yl2, yr1); + // add the new subdivision points + p3 = (p1 + p2) / 2; + cx[p1][1] = xl1; cy[p1][1] = yl1; + cx[p1][2] = xl2; cy[p1][2] = yl2; + cNext[p1] = p3; + cx[p3][0] = xr0; cy[p3][0] = yr0; + cx[p3][1] = xr1; cy[p3][1] = yr1; + cx[p3][2] = xr2; cy[p3][2] = yr2; + cNext[p3] = p2; + } + } +} + +SplashPath *Splash::makeDashedPath(SplashPath *path) { + SplashPath *dPath; + SplashCoord lineDashTotal; + SplashCoord lineDashStartPhase, lineDashDist, segLen; + SplashCoord x0, y0, x1, y1, xa, ya; + GBool lineDashStartOn, lineDashOn, newPath; + int lineDashStartIdx, lineDashIdx; + int i, j, k; + + lineDashTotal = 0; + for (i = 0; i < state->lineDashLength; ++i) { + lineDashTotal += state->lineDash[i]; + } + // Acrobat simply draws nothing if the dash array is [0] + if (lineDashTotal == 0) { + return new SplashPath(); + } + lineDashStartPhase = state->lineDashPhase; + i = splashFloor(lineDashStartPhase / lineDashTotal); + lineDashStartPhase -= (SplashCoord)i * lineDashTotal; + lineDashStartOn = gTrue; + lineDashStartIdx = 0; + if (lineDashStartPhase > 0) { + while (lineDashStartIdx < state->lineDashLength && lineDashStartPhase >= state->lineDash[lineDashStartIdx]) { + lineDashStartOn = !lineDashStartOn; + lineDashStartPhase -= state->lineDash[lineDashStartIdx]; + ++lineDashStartIdx; + } + if (unlikely(lineDashStartIdx == state->lineDashLength)) { + return new SplashPath(); + } + } + + dPath = new SplashPath(); + + // process each subpath + i = 0; + while (i < path->length) { + + // find the end of the subpath + for (j = i; + j < path->length - 1 && !(path->flags[j] & splashPathLast); + ++j) ; + + // initialize the dash parameters + lineDashOn = lineDashStartOn; + lineDashIdx = lineDashStartIdx; + lineDashDist = state->lineDash[lineDashIdx] - lineDashStartPhase; + + // process each segment of the subpath + newPath = gTrue; + for (k = i; k < j; ++k) { + + // grab the segment + x0 = path->pts[k].x; + y0 = path->pts[k].y; + x1 = path->pts[k+1].x; + y1 = path->pts[k+1].y; + segLen = splashDist(x0, y0, x1, y1); + + // process the segment + while (segLen > 0) { + + if (lineDashDist >= segLen) { + if (lineDashOn) { + if (newPath) { + dPath->moveTo(x0, y0); + newPath = gFalse; + } + dPath->lineTo(x1, y1); + } + lineDashDist -= segLen; + segLen = 0; + + } else { + xa = x0 + (lineDashDist / segLen) * (x1 - x0); + ya = y0 + (lineDashDist / segLen) * (y1 - y0); + if (lineDashOn) { + if (newPath) { + dPath->moveTo(x0, y0); + newPath = gFalse; + } + dPath->lineTo(xa, ya); + } + x0 = xa; + y0 = ya; + segLen -= lineDashDist; + lineDashDist = 0; + } + + // get the next entry in the dash array + if (lineDashDist <= 0) { + lineDashOn = !lineDashOn; + if (++lineDashIdx == state->lineDashLength) { + lineDashIdx = 0; + } + lineDashDist = state->lineDash[lineDashIdx]; + newPath = gTrue; + } + } + } + i = j + 1; + } + + if (dPath->length == 0) { + GBool allSame = gTrue; + for (int i = 0; allSame && i < path->length - 1; ++i) { + allSame = path->pts[i].x == path->pts[i + 1].x && path->pts[i].y == path->pts[i + 1].y; + } + if (allSame) { + x0 = path->pts[0].x; + y0 = path->pts[0].y; + dPath->moveTo(x0, y0); + dPath->lineTo(x0, y0); + } + } + + return dPath; +} + +SplashError Splash::fill(SplashPath *path, GBool eo) { + if (debugMode) { + printf("fill [eo:%d]:\n", eo); + dumpPath(path); + } + return fillWithPattern(path, eo, state->fillPattern, state->fillAlpha); +} + +inline void Splash::getBBoxFP(SplashPath *path, SplashCoord *xMinA, SplashCoord *yMinA, + SplashCoord *xMaxA, SplashCoord *yMaxA) { + SplashCoord xMinFP, yMinFP, xMaxFP, yMaxFP, tx, ty; + + // make compiler happy: + xMinFP = xMaxFP = yMinFP = yMaxFP = 0; + for (int i = 0; i < path->length; ++i) { + transform(state->matrix, path->pts[i].x, path->pts[i].y, &tx, &ty); + if (i == 0) { + xMinFP = xMaxFP = tx; + yMinFP = yMaxFP = ty; + } else { + if (tx < xMinFP) xMinFP = tx; + if (tx > xMaxFP) xMaxFP = tx; + if (ty < yMinFP) yMinFP = ty; + if (ty > yMaxFP) yMaxFP = ty; + } + } + + *xMinA = xMinFP; + *yMinA = yMinFP; + *xMaxA = xMaxFP; + *yMaxA = yMaxFP; +} + +SplashError Splash::fillWithPattern(SplashPath *path, GBool eo, + SplashPattern *pattern, + SplashCoord alpha) { + SplashPipe pipe; + SplashXPath *xPath; + SplashXPathScanner *scanner; + int xMinI, yMinI, xMaxI, yMaxI, x0, x1, y; + SplashClipResult clipRes, clipRes2; + GBool adjustLine = gFalse; + int linePosI = 0; + + if (path->length == 0) { + return splashErrEmptyPath; + } + if (pathAllOutside(path)) { + opClipRes = splashClipAllOutside; + return splashOk; + } + + // add stroke adjustment hints for filled rectangles -- this only + // applies to paths that consist of a single subpath + // (this appears to match Acrobat's behavior) + if (state->strokeAdjust && !path->hints) { + int n; + n = path->getLength(); + if (n == 4 && + !(path->flags[0] & splashPathClosed) && + !(path->flags[1] & splashPathLast) && + !(path->flags[2] & splashPathLast)) { + path->close(gTrue); + path->addStrokeAdjustHint(0, 2, 0, 4); + path->addStrokeAdjustHint(1, 3, 0, 4); + } else if (n == 5 && + (path->flags[0] & splashPathClosed) && + !(path->flags[1] & splashPathLast) && + !(path->flags[2] & splashPathLast) && + !(path->flags[3] & splashPathLast)) { + path->addStrokeAdjustHint(0, 2, 0, 4); + path->addStrokeAdjustHint(1, 3, 0, 4); + } + } + + if (thinLineMode != splashThinLineDefault) { + if (state->clip->getXMinI() == state->clip->getXMaxI()) { + linePosI = state->clip->getXMinI(); + adjustLine = gTrue; + } else if (state->clip->getXMinI() == state->clip->getXMaxI() - 1) { + adjustLine = gTrue; + linePosI = splashFloor(state->clip->getXMin() + state->lineWidth); + } else if (state->clip->getYMinI() == state->clip->getYMaxI()) { + linePosI = state->clip->getYMinI(); + adjustLine = gTrue; + } else if (state->clip->getYMinI() == state->clip->getYMaxI() - 1) { + adjustLine = gTrue; + linePosI = splashFloor(state->clip->getYMin() + state->lineWidth); + } + } + + xPath = new SplashXPath(path, state->matrix, state->flatness, gTrue, + adjustLine, linePosI); + if (vectorAntialias && !inShading) { + xPath->aaScale(); + } + xPath->sort(); + yMinI = state->clip->getYMinI(); + yMaxI = state->clip->getYMaxI(); + if (vectorAntialias && !inShading) { + yMinI = yMinI * splashAASize; + yMaxI = (yMaxI + 1) * splashAASize - 1; + } + scanner = new SplashXPathScanner(xPath, eo, yMinI, yMaxI); + + // get the min and max x and y values + if (vectorAntialias && !inShading) { + scanner->getBBoxAA(&xMinI, &yMinI, &xMaxI, &yMaxI); + } else { + scanner->getBBox(&xMinI, &yMinI, &xMaxI, &yMaxI); + } + + if (eo && (yMinI == yMaxI || xMinI == xMaxI) && thinLineMode != splashThinLineDefault) { + SplashCoord delta, xMinFP, yMinFP, xMaxFP, yMaxFP; + getBBoxFP(path, &xMinFP, &yMinFP, &xMaxFP, &yMaxFP); + delta = (yMinI == yMaxI) ? yMaxFP - yMinFP : xMaxFP - xMinFP; + if (delta < 0.2) { + opClipRes = splashClipAllOutside; + delete scanner; + delete xPath; + return splashOk; + } + } + + // check clipping + if ((clipRes = state->clip->testRect(xMinI, yMinI, xMaxI, yMaxI)) + != splashClipAllOutside) { + if (scanner->hasPartialClip()) { + clipRes = splashClipPartial; + } + + pipeInit(&pipe, 0, yMinI, pattern, NULL, (Guchar)splashRound(alpha * 255), + vectorAntialias && !inShading, gFalse); + + // draw the spans + if (vectorAntialias && !inShading) { + for (y = yMinI; y <= yMaxI; ++y) { + scanner->renderAALine(aaBuf, &x0, &x1, y, thinLineMode != splashThinLineDefault && xMinI == xMaxI); + if (clipRes != splashClipAllInside) { + state->clip->clipAALine(aaBuf, &x0, &x1, y, thinLineMode != splashThinLineDefault && xMinI == xMaxI); + } + Guchar lineShape = 255; + GBool adjustLine = gFalse; + if (thinLineMode == splashThinLineShape && (xMinI == xMaxI || yMinI == yMaxI)) { + // compute line shape for thin lines: + SplashCoord mx, my, delta; + transform(state->matrix, 0, 0, &mx, &my); + transform(state->matrix, state->lineWidth, 0, &delta, &my); + adjustLine = gTrue; + lineShape = clip255((delta - mx) * 255); + } + drawAALine(&pipe, x0, x1, y, adjustLine, lineShape); + } + } else { + for (y = yMinI; y <= yMaxI; ++y) { + while (scanner->getNextSpan(y, &x0, &x1)) { + if (clipRes == splashClipAllInside) { + drawSpan(&pipe, x0, x1, y, gTrue); + } else { + // limit the x range + if (x0 < state->clip->getXMinI()) { + x0 = state->clip->getXMinI(); + } + if (x1 > state->clip->getXMaxI()) { + x1 = state->clip->getXMaxI(); + } + clipRes2 = state->clip->testSpan(x0, x1, y); + drawSpan(&pipe, x0, x1, y, clipRes2 == splashClipAllInside); + } + } + } + } + } + opClipRes = clipRes; + + delete scanner; + delete xPath; + return splashOk; +} + +GBool Splash::pathAllOutside(SplashPath *path) { + SplashCoord xMin1, yMin1, xMax1, yMax1; + SplashCoord xMin2, yMin2, xMax2, yMax2; + SplashCoord x, y; + int xMinI, yMinI, xMaxI, yMaxI; + int i; + + xMin1 = xMax1 = path->pts[0].x; + yMin1 = yMax1 = path->pts[0].y; + for (i = 1; i < path->length; ++i) { + if (path->pts[i].x < xMin1) { + xMin1 = path->pts[i].x; + } else if (path->pts[i].x > xMax1) { + xMax1 = path->pts[i].x; + } + if (path->pts[i].y < yMin1) { + yMin1 = path->pts[i].y; + } else if (path->pts[i].y > yMax1) { + yMax1 = path->pts[i].y; + } + } + + transform(state->matrix, xMin1, yMin1, &x, &y); + xMin2 = xMax2 = x; + yMin2 = yMax2 = y; + transform(state->matrix, xMin1, yMax1, &x, &y); + if (x < xMin2) { + xMin2 = x; + } else if (x > xMax2) { + xMax2 = x; + } + if (y < yMin2) { + yMin2 = y; + } else if (y > yMax2) { + yMax2 = y; + } + transform(state->matrix, xMax1, yMin1, &x, &y); + if (x < xMin2) { + xMin2 = x; + } else if (x > xMax2) { + xMax2 = x; + } + if (y < yMin2) { + yMin2 = y; + } else if (y > yMax2) { + yMax2 = y; + } + transform(state->matrix, xMax1, yMax1, &x, &y); + if (x < xMin2) { + xMin2 = x; + } else if (x > xMax2) { + xMax2 = x; + } + if (y < yMin2) { + yMin2 = y; + } else if (y > yMax2) { + yMax2 = y; + } + xMinI = splashFloor(xMin2); + yMinI = splashFloor(yMin2); + xMaxI = splashFloor(xMax2); + yMaxI = splashFloor(yMax2); + + return state->clip->testRect(xMinI, yMinI, xMaxI, yMaxI) == + splashClipAllOutside; +} + +SplashError Splash::xorFill(SplashPath *path, GBool eo) { + SplashPipe pipe; + SplashXPath *xPath; + SplashXPathScanner *scanner; + int xMinI, yMinI, xMaxI, yMaxI, x0, x1, y; + SplashClipResult clipRes, clipRes2; + SplashBlendFunc origBlendFunc; + + if (path->length == 0) { + return splashErrEmptyPath; + } + xPath = new SplashXPath(path, state->matrix, state->flatness, gTrue); + xPath->sort(); + scanner = new SplashXPathScanner(xPath, eo, state->clip->getYMinI(), + state->clip->getYMaxI()); + + // get the min and max x and y values + scanner->getBBox(&xMinI, &yMinI, &xMaxI, &yMaxI); + + // check clipping + if ((clipRes = state->clip->testRect(xMinI, yMinI, xMaxI, yMaxI)) + != splashClipAllOutside) { + if (scanner->hasPartialClip()) { + clipRes = splashClipPartial; + } + + origBlendFunc = state->blendFunc; + state->blendFunc = &blendXor; + pipeInit(&pipe, 0, yMinI, state->fillPattern, NULL, 255, gFalse, gFalse); + + // draw the spans + for (y = yMinI; y <= yMaxI; ++y) { + while (scanner->getNextSpan(y, &x0, &x1)) { + if (clipRes == splashClipAllInside) { + drawSpan(&pipe, x0, x1, y, gTrue); + } else { + // limit the x range + if (x0 < state->clip->getXMinI()) { + x0 = state->clip->getXMinI(); + } + if (x1 > state->clip->getXMaxI()) { + x1 = state->clip->getXMaxI(); + } + clipRes2 = state->clip->testSpan(x0, x1, y); + drawSpan(&pipe, x0, x1, y, clipRes2 == splashClipAllInside); + } + } + } + state->blendFunc = origBlendFunc; + } + opClipRes = clipRes; + + delete scanner; + delete xPath; + return splashOk; +} + +SplashError Splash::fillChar(SplashCoord x, SplashCoord y, + int c, SplashFont *font) { + SplashGlyphBitmap glyph; + SplashCoord xt, yt; + int x0, y0, xFrac, yFrac; + SplashClipResult clipRes; + + if (debugMode) { + printf("fillChar: x=%.2f y=%.2f c=%3d=0x%02x='%c'\n", + (double)x, (double)y, c, c, c); + } + transform(state->matrix, x, y, &xt, &yt); + x0 = splashFloor(xt); + xFrac = splashFloor((xt - x0) * splashFontFraction); + y0 = splashFloor(yt); + yFrac = splashFloor((yt - y0) * splashFontFraction); + if (!font->getGlyph(c, xFrac, yFrac, &glyph, x0, y0, state->clip, &clipRes)) { + return splashErrNoGlyph; + } + if (clipRes != splashClipAllOutside) { + fillGlyph2(x0, y0, &glyph, clipRes == splashClipAllInside); + } + opClipRes = clipRes; + if (glyph.freeData) { + gfree(glyph.data); + } + return splashOk; +} + +void Splash::fillGlyph(SplashCoord x, SplashCoord y, + SplashGlyphBitmap *glyph) { + SplashCoord xt, yt; + int x0, y0; + + transform(state->matrix, x, y, &xt, &yt); + x0 = splashFloor(xt); + y0 = splashFloor(yt); + SplashClipResult clipRes = state->clip->testRect(x0 - glyph->x, + y0 - glyph->y, + x0 - glyph->x + glyph->w - 1, + y0 - glyph->y + glyph->h - 1); + if (clipRes != splashClipAllOutside) { + fillGlyph2(x0, y0, glyph, clipRes == splashClipAllInside); + } + opClipRes = clipRes; +} + +void Splash::fillGlyph2(int x0, int y0, SplashGlyphBitmap *glyph, GBool noClip) { + SplashPipe pipe; + int alpha0; + Guchar alpha; + Guchar *p; + int x1, y1, xx, xx1, yy; + + p = glyph->data; + int xStart = x0 - glyph->x; + int yStart = y0 - glyph->y; + int xxLimit = glyph->w; + int yyLimit = glyph->h; + int xShift = 0; + + if (yStart < 0) + { + p += (glyph->aa ? glyph->w : splashCeil(glyph->w / 8.0)) * -yStart; // move p to the beginning of the first painted row + yyLimit += yStart; + yStart = 0; + } + + if (xStart < 0) + { + if (glyph->aa) { + p += -xStart; + } else { + p += (-xStart) / 8; + xShift = (-xStart) % 8; + } + xxLimit += xStart; + xStart = 0; + } + + if (xxLimit + xStart >= bitmap->width) xxLimit = bitmap->width - xStart; + if (yyLimit + yStart >= bitmap->height) yyLimit = bitmap->height - yStart; + + if (noClip) { + if (glyph->aa) { + pipeInit(&pipe, xStart, yStart, + state->fillPattern, NULL, (Guchar)splashRound(state->fillAlpha * 255), gTrue, gFalse); + for (yy = 0, y1 = yStart; yy < yyLimit; ++yy, ++y1) { + pipeSetXY(&pipe, xStart, y1); + for (xx = 0, x1 = xStart; xx < xxLimit; ++xx, ++x1) { + alpha = p[xx]; + if (alpha != 0) { + pipe.shape = alpha; + (this->*pipe.run)(&pipe); + updateModX(x1); + updateModY(y1); + } else { + pipeIncX(&pipe); + } + } + p += glyph->w; + } + } else { + const int widthEight = splashCeil(glyph->w / 8.0); + + pipeInit(&pipe, xStart, yStart, + state->fillPattern, NULL, (Guchar)splashRound(state->fillAlpha * 255), gFalse, gFalse); + for (yy = 0, y1 = yStart; yy < yyLimit; ++yy, ++y1) { + pipeSetXY(&pipe, xStart, y1); + for (xx = 0, x1 = xStart; xx < xxLimit; xx += 8) { + alpha0 = (xShift > 0 ? (p[xx / 8] << xShift) | (p[xx / 8 + 1] >> (8 - xShift)) : p[xx / 8]); + for (xx1 = 0; xx1 < 8 && xx + xx1 < xxLimit; ++xx1, ++x1) { + if (alpha0 & 0x80) { + (this->*pipe.run)(&pipe); + updateModX(x1); + updateModY(y1); + } else { + pipeIncX(&pipe); + } + alpha0 <<= 1; + } + } + p += widthEight; + } + } + } else { + if (glyph->aa) { + pipeInit(&pipe, xStart, yStart, + state->fillPattern, NULL, (Guchar)splashRound(state->fillAlpha * 255), gTrue, gFalse); + for (yy = 0, y1 = yStart; yy < yyLimit; ++yy, ++y1) { + pipeSetXY(&pipe, xStart, y1); + for (xx = 0, x1 = xStart; xx < xxLimit; ++xx, ++x1) { + if (state->clip->test(x1, y1)) { + alpha = p[xx]; + if (alpha != 0) { + pipe.shape = alpha; + (this->*pipe.run)(&pipe); + updateModX(x1); + updateModY(y1); + } else { + pipeIncX(&pipe); + } + } else { + pipeIncX(&pipe); + } + } + p += glyph->w; + } + } else { + const int widthEight = splashCeil(glyph->w / 8.0); + + pipeInit(&pipe, xStart, yStart, + state->fillPattern, NULL, (Guchar)splashRound(state->fillAlpha * 255), gFalse, gFalse); + for (yy = 0, y1 = yStart; yy < yyLimit; ++yy, ++y1) { + pipeSetXY(&pipe, xStart, y1); + for (xx = 0, x1 = xStart; xx < xxLimit; xx += 8) { + alpha0 = (xShift > 0 ? (p[xx / 8] << xShift) | (p[xx / 8 + 1] >> (8 - xShift)) : p[xx / 8]); + for (xx1 = 0; xx1 < 8 && xx + xx1 < xxLimit; ++xx1, ++x1) { + if (state->clip->test(x1, y1)) { + if (alpha0 & 0x80) { + (this->*pipe.run)(&pipe); + updateModX(x1); + updateModY(y1); + } else { + pipeIncX(&pipe); + } + } else { + pipeIncX(&pipe); + } + alpha0 <<= 1; + } + } + p += widthEight; + } + } + } +} + +SplashError Splash::fillImageMask(SplashImageMaskSource src, void *srcData, + int w, int h, SplashCoord *mat, + GBool glyphMode) { + SplashBitmap *scaledMask; + SplashClipResult clipRes; + GBool minorAxisZero; + int x0, y0, x1, y1, scaledWidth, scaledHeight; + int yp; + + if (debugMode) { + printf("fillImageMask: w=%d h=%d mat=[%.2f %.2f %.2f %.2f %.2f %.2f]\n", + w, h, (double)mat[0], (double)mat[1], (double)mat[2], + (double)mat[3], (double)mat[4], (double)mat[5]); + } + + if (w == 0 && h == 0) return splashErrZeroImage; + + // check for singular matrix + if (!splashCheckDet(mat[0], mat[1], mat[2], mat[3], 0.000001)) { + return splashErrSingularMatrix; + } + + minorAxisZero = mat[1] == 0 && mat[2] == 0; + + // scaling only + if (mat[0] > 0 && minorAxisZero && mat[3] > 0) { + x0 = imgCoordMungeLowerC(mat[4], glyphMode); + y0 = imgCoordMungeLowerC(mat[5], glyphMode); + x1 = imgCoordMungeUpperC(mat[0] + mat[4], glyphMode); + y1 = imgCoordMungeUpperC(mat[3] + mat[5], glyphMode); + // make sure narrow images cover at least one pixel + if (x0 == x1) { + ++x1; + } + if (y0 == y1) { + ++y1; + } + clipRes = state->clip->testRect(x0, y0, x1 - 1, y1 - 1); + opClipRes = clipRes; + if (clipRes != splashClipAllOutside) { + scaledWidth = x1 - x0; + scaledHeight = y1 - y0; + yp = h / scaledHeight; + if (yp < 0 || yp > INT_MAX - 1) { + return splashErrBadArg; + } + scaledMask = scaleMask(src, srcData, w, h, scaledWidth, scaledHeight); + blitMask(scaledMask, x0, y0, clipRes); + delete scaledMask; + } + + // scaling plus vertical flip + } else if (mat[0] > 0 && minorAxisZero && mat[3] < 0) { + x0 = imgCoordMungeLowerC(mat[4], glyphMode); + y0 = imgCoordMungeLowerC(mat[3] + mat[5], glyphMode); + x1 = imgCoordMungeUpperC(mat[0] + mat[4], glyphMode); + y1 = imgCoordMungeUpperC(mat[5], glyphMode); + // make sure narrow images cover at least one pixel + if (x0 == x1) { + ++x1; + } + if (y0 == y1) { + ++y1; + } + clipRes = state->clip->testRect(x0, y0, x1 - 1, y1 - 1); + opClipRes = clipRes; + if (clipRes != splashClipAllOutside) { + scaledWidth = x1 - x0; + scaledHeight = y1 - y0; + yp = h / scaledHeight; + if (yp < 0 || yp > INT_MAX - 1) { + return splashErrBadArg; + } + scaledMask = scaleMask(src, srcData, w, h, scaledWidth, scaledHeight); + vertFlipImage(scaledMask, scaledWidth, scaledHeight, 1); + blitMask(scaledMask, x0, y0, clipRes); + delete scaledMask; + } + + // all other cases + } else { + arbitraryTransformMask(src, srcData, w, h, mat, glyphMode); + } + + return splashOk; +} + +void Splash::arbitraryTransformMask(SplashImageMaskSource src, void *srcData, + int srcWidth, int srcHeight, + SplashCoord *mat, GBool glyphMode) { + SplashBitmap *scaledMask; + SplashClipResult clipRes, clipRes2; + SplashPipe pipe; + int scaledWidth, scaledHeight, t0, t1; + SplashCoord r00, r01, r10, r11, det, ir00, ir01, ir10, ir11; + SplashCoord vx[4], vy[4]; + int xMin, yMin, xMax, yMax; + ImageSection section[3]; + int nSections; + int y, xa, xb, x, i, xx, yy; + + // compute the four vertices of the target quadrilateral + vx[0] = mat[4]; vy[0] = mat[5]; + vx[1] = mat[2] + mat[4]; vy[1] = mat[3] + mat[5]; + vx[2] = mat[0] + mat[2] + mat[4]; vy[2] = mat[1] + mat[3] + mat[5]; + vx[3] = mat[0] + mat[4]; vy[3] = mat[1] + mat[5]; + + // clipping + xMin = imgCoordMungeLowerC(vx[0], glyphMode); + xMax = imgCoordMungeUpperC(vx[0], glyphMode); + yMin = imgCoordMungeLowerC(vy[0], glyphMode); + yMax = imgCoordMungeUpperC(vy[0], glyphMode); + for (i = 1; i < 4; ++i) { + t0 = imgCoordMungeLowerC(vx[i], glyphMode); + if (t0 < xMin) { + xMin = t0; + } + t0 = imgCoordMungeUpperC(vx[i], glyphMode); + if (t0 > xMax) { + xMax = t0; + } + t1 = imgCoordMungeLowerC(vy[i], glyphMode); + if (t1 < yMin) { + yMin = t1; + } + t1 = imgCoordMungeUpperC(vy[i], glyphMode); + if (t1 > yMax) { + yMax = t1; + } + } + clipRes = state->clip->testRect(xMin, yMin, xMax - 1, yMax - 1); + opClipRes = clipRes; + if (clipRes == splashClipAllOutside) { + return; + } + + // compute the scale factors + if (mat[0] >= 0) { + t0 = imgCoordMungeUpperC(mat[0] + mat[4], glyphMode) - + imgCoordMungeLowerC(mat[4], glyphMode); + } else { + t0 = imgCoordMungeUpperC(mat[4], glyphMode) - + imgCoordMungeLowerC(mat[0] + mat[4], glyphMode); + } + if (mat[1] >= 0) { + t1 = imgCoordMungeUpperC(mat[1] + mat[5], glyphMode) - + imgCoordMungeLowerC(mat[5], glyphMode); + } else { + t1 = imgCoordMungeUpperC(mat[5], glyphMode) - + imgCoordMungeLowerC(mat[1] + mat[5], glyphMode); + } + scaledWidth = t0 > t1 ? t0 : t1; + if (mat[2] >= 0) { + t0 = imgCoordMungeUpperC(mat[2] + mat[4], glyphMode) - + imgCoordMungeLowerC(mat[4], glyphMode); + } else { + t0 = imgCoordMungeUpperC(mat[4], glyphMode) - + imgCoordMungeLowerC(mat[2] + mat[4], glyphMode); + } + if (mat[3] >= 0) { + t1 = imgCoordMungeUpperC(mat[3] + mat[5], glyphMode) - + imgCoordMungeLowerC(mat[5], glyphMode); + } else { + t1 = imgCoordMungeUpperC(mat[5], glyphMode) - + imgCoordMungeLowerC(mat[3] + mat[5], glyphMode); + } + scaledHeight = t0 > t1 ? t0 : t1; + if (scaledWidth == 0) { + scaledWidth = 1; + } + if (scaledHeight == 0) { + scaledHeight = 1; + } + + // compute the inverse transform (after scaling) matrix + r00 = mat[0] / scaledWidth; + r01 = mat[1] / scaledWidth; + r10 = mat[2] / scaledHeight; + r11 = mat[3] / scaledHeight; + det = r00 * r11 - r01 * r10; + if (splashAbs(det) < 1e-6) { + // this should be caught by the singular matrix check in fillImageMask + return; + } + ir00 = r11 / det; + ir01 = -r01 / det; + ir10 = -r10 / det; + ir11 = r00 / det; + + // scale the input image + scaledMask = scaleMask(src, srcData, srcWidth, srcHeight, + scaledWidth, scaledHeight); + if (scaledMask->data == NULL) { + error(errInternal, -1, "scaledMask->data is NULL in Splash::arbitraryTransformMask"); + delete scaledMask; + return; + } + + // construct the three sections + i = (vy[2] <= vy[3]) ? 2 : 3; + if (vy[1] <= vy[i]) { + i = 1; + } + if (vy[0] < vy[i] || (i != 3 && vy[0] == vy[i])) { + i = 0; + } + if (vy[i] == vy[(i+1) & 3]) { + section[0].y0 = imgCoordMungeLowerC(vy[i], glyphMode); + section[0].y1 = imgCoordMungeUpperC(vy[(i+2) & 3], glyphMode) - 1; + if (vx[i] < vx[(i+1) & 3]) { + section[0].ia0 = i; + section[0].ia1 = (i+3) & 3; + section[0].ib0 = (i+1) & 3; + section[0].ib1 = (i+2) & 3; + } else { + section[0].ia0 = (i+1) & 3; + section[0].ia1 = (i+2) & 3; + section[0].ib0 = i; + section[0].ib1 = (i+3) & 3; + } + nSections = 1; + } else { + section[0].y0 = imgCoordMungeLowerC(vy[i], glyphMode); + section[2].y1 = imgCoordMungeUpperC(vy[(i+2) & 3], glyphMode) - 1; + section[0].ia0 = section[0].ib0 = i; + section[2].ia1 = section[2].ib1 = (i+2) & 3; + if (vx[(i+1) & 3] < vx[(i+3) & 3]) { + section[0].ia1 = section[2].ia0 = (i+1) & 3; + section[0].ib1 = section[2].ib0 = (i+3) & 3; + } else { + section[0].ia1 = section[2].ia0 = (i+3) & 3; + section[0].ib1 = section[2].ib0 = (i+1) & 3; + } + if (vy[(i+1) & 3] < vy[(i+3) & 3]) { + section[1].y0 = imgCoordMungeLowerC(vy[(i+1) & 3], glyphMode); + section[2].y0 = imgCoordMungeUpperC(vy[(i+3) & 3], glyphMode); + if (vx[(i+1) & 3] < vx[(i+3) & 3]) { + section[1].ia0 = (i+1) & 3; + section[1].ia1 = (i+2) & 3; + section[1].ib0 = i; + section[1].ib1 = (i+3) & 3; + } else { + section[1].ia0 = i; + section[1].ia1 = (i+3) & 3; + section[1].ib0 = (i+1) & 3; + section[1].ib1 = (i+2) & 3; + } + } else { + section[1].y0 = imgCoordMungeLowerC(vy[(i+3) & 3], glyphMode); + section[2].y0 = imgCoordMungeUpperC(vy[(i+1) & 3], glyphMode); + if (vx[(i+1) & 3] < vx[(i+3) & 3]) { + section[1].ia0 = i; + section[1].ia1 = (i+1) & 3; + section[1].ib0 = (i+3) & 3; + section[1].ib1 = (i+2) & 3; + } else { + section[1].ia0 = (i+3) & 3; + section[1].ia1 = (i+2) & 3; + section[1].ib0 = i; + section[1].ib1 = (i+1) & 3; + } + } + section[0].y1 = section[1].y0 - 1; + section[1].y1 = section[2].y0 - 1; + nSections = 3; + } + for (i = 0; i < nSections; ++i) { + section[i].xa0 = vx[section[i].ia0]; + section[i].ya0 = vy[section[i].ia0]; + section[i].xa1 = vx[section[i].ia1]; + section[i].ya1 = vy[section[i].ia1]; + section[i].xb0 = vx[section[i].ib0]; + section[i].yb0 = vy[section[i].ib0]; + section[i].xb1 = vx[section[i].ib1]; + section[i].yb1 = vy[section[i].ib1]; + section[i].dxdya = (section[i].xa1 - section[i].xa0) / + (section[i].ya1 - section[i].ya0); + section[i].dxdyb = (section[i].xb1 - section[i].xb0) / + (section[i].yb1 - section[i].yb0); + } + + // initialize the pixel pipe + pipeInit(&pipe, 0, 0, state->fillPattern, NULL, + (Guchar)splashRound(state->fillAlpha * 255), gTrue, gFalse); + if (vectorAntialias) { + drawAAPixelInit(); + } + + // make sure narrow images cover at least one pixel + if (nSections == 1) { + if (section[0].y0 == section[0].y1) { + ++section[0].y1; + clipRes = opClipRes = splashClipPartial; + } + } else { + if (section[0].y0 == section[2].y1) { + ++section[1].y1; + clipRes = opClipRes = splashClipPartial; + } + } + + // scan all pixels inside the target region + for (i = 0; i < nSections; ++i) { + for (y = section[i].y0; y <= section[i].y1; ++y) { + xa = imgCoordMungeLowerC(section[i].xa0 + + ((SplashCoord)y + 0.5 - section[i].ya0) * + section[i].dxdya, + glyphMode); + xb = imgCoordMungeUpperC(section[i].xb0 + + ((SplashCoord)y + 0.5 - section[i].yb0) * + section[i].dxdyb, + glyphMode); + // make sure narrow images cover at least one pixel + if (xa == xb) { + ++xb; + } + if (clipRes != splashClipAllInside) { + clipRes2 = state->clip->testSpan(xa, xb - 1, y); + } else { + clipRes2 = clipRes; + } + for (x = xa; x < xb; ++x) { + // map (x+0.5, y+0.5) back to the scaled image + xx = splashFloor(((SplashCoord)x + 0.5 - mat[4]) * ir00 + + ((SplashCoord)y + 0.5 - mat[5]) * ir10); + yy = splashFloor(((SplashCoord)x + 0.5 - mat[4]) * ir01 + + ((SplashCoord)y + 0.5 - mat[5]) * ir11); + // xx should always be within bounds, but floating point + // inaccuracy can cause problems + if (xx < 0) { + xx = 0; + } else if (xx >= scaledWidth) { + xx = scaledWidth - 1; + } + if (yy < 0) { + yy = 0; + } else if (yy >= scaledHeight) { + yy = scaledHeight - 1; + } + pipe.shape = scaledMask->data[yy * scaledWidth + xx]; + if (vectorAntialias && clipRes2 != splashClipAllInside) { + drawAAPixel(&pipe, x, y); + } else { + drawPixel(&pipe, x, y, clipRes2 == splashClipAllInside); + } + } + } + } + + delete scaledMask; +} + +// Scale an image mask into a SplashBitmap. +SplashBitmap *Splash::scaleMask(SplashImageMaskSource src, void *srcData, + int srcWidth, int srcHeight, + int scaledWidth, int scaledHeight) { + SplashBitmap *dest; + + dest = new SplashBitmap(scaledWidth, scaledHeight, 1, splashModeMono8, + gFalse); + if (scaledHeight < srcHeight) { + if (scaledWidth < srcWidth) { + scaleMaskYdXd(src, srcData, srcWidth, srcHeight, + scaledWidth, scaledHeight, dest); + } else { + scaleMaskYdXu(src, srcData, srcWidth, srcHeight, + scaledWidth, scaledHeight, dest); + } + } else { + if (scaledWidth < srcWidth) { + scaleMaskYuXd(src, srcData, srcWidth, srcHeight, + scaledWidth, scaledHeight, dest); + } else { + scaleMaskYuXu(src, srcData, srcWidth, srcHeight, + scaledWidth, scaledHeight, dest); + } + } + return dest; +} + +void Splash::scaleMaskYdXd(SplashImageMaskSource src, void *srcData, + int srcWidth, int srcHeight, + int scaledWidth, int scaledHeight, + SplashBitmap *dest) { + Guchar *lineBuf; + Guint *pixBuf; + Guint pix; + Guchar *destPtr; + int yp, yq, xp, xq, yt, y, yStep, xt, x, xStep, xx, d, d0, d1; + int i, j; + + // Bresenham parameters for y scale + yp = srcHeight / scaledHeight; + yq = srcHeight % scaledHeight; + + // Bresenham parameters for x scale + xp = srcWidth / scaledWidth; + xq = srcWidth % scaledWidth; + + // allocate buffers + lineBuf = (Guchar *)gmalloc(srcWidth); + pixBuf = (Guint *)gmallocn(srcWidth, sizeof(int)); + + // init y scale Bresenham + yt = 0; + + destPtr = dest->data; + for (y = 0; y < scaledHeight; ++y) { + + // y scale Bresenham + if ((yt += yq) >= scaledHeight) { + yt -= scaledHeight; + yStep = yp + 1; + } else { + yStep = yp; + } + + // read rows from image + memset(pixBuf, 0, srcWidth * sizeof(int)); + for (i = 0; i < yStep; ++i) { + (*src)(srcData, lineBuf); + for (j = 0; j < srcWidth; ++j) { + pixBuf[j] += lineBuf[j]; + } + } + + // init x scale Bresenham + xt = 0; + d0 = (255 << 23) / (yStep * xp); + d1 = (255 << 23) / (yStep * (xp + 1)); + + xx = 0; + for (x = 0; x < scaledWidth; ++x) { + + // x scale Bresenham + if ((xt += xq) >= scaledWidth) { + xt -= scaledWidth; + xStep = xp + 1; + d = d1; + } else { + xStep = xp; + d = d0; + } + + // compute the final pixel + pix = 0; + for (i = 0; i < xStep; ++i) { + pix += pixBuf[xx++]; + } + // (255 * pix) / xStep * yStep + pix = (pix * d) >> 23; + + // store the pixel + *destPtr++ = (Guchar)pix; + } + } + + gfree(pixBuf); + gfree(lineBuf); +} + +void Splash::scaleMaskYdXu(SplashImageMaskSource src, void *srcData, + int srcWidth, int srcHeight, + int scaledWidth, int scaledHeight, + SplashBitmap *dest) { + Guchar *lineBuf; + Guint *pixBuf; + Guint pix; + Guchar *destPtr; + int yp, yq, xp, xq, yt, y, yStep, xt, x, xStep, d; + int i, j; + + destPtr = dest->data; + if (destPtr == NULL) { + error(errInternal, -1, "dest->data is NULL in Splash::scaleMaskYdXu"); + return; + } + + // Bresenham parameters for y scale + yp = srcHeight / scaledHeight; + yq = srcHeight % scaledHeight; + + // Bresenham parameters for x scale + xp = scaledWidth / srcWidth; + xq = scaledWidth % srcWidth; + + // allocate buffers + lineBuf = (Guchar *)gmalloc(srcWidth); + pixBuf = (Guint *)gmallocn(srcWidth, sizeof(int)); + + // init y scale Bresenham + yt = 0; + + for (y = 0; y < scaledHeight; ++y) { + + // y scale Bresenham + if ((yt += yq) >= scaledHeight) { + yt -= scaledHeight; + yStep = yp + 1; + } else { + yStep = yp; + } + + // read rows from image + memset(pixBuf, 0, srcWidth * sizeof(int)); + for (i = 0; i < yStep; ++i) { + (*src)(srcData, lineBuf); + for (j = 0; j < srcWidth; ++j) { + pixBuf[j] += lineBuf[j]; + } + } + + // init x scale Bresenham + xt = 0; + d = (255 << 23) / yStep; + + for (x = 0; x < srcWidth; ++x) { + + // x scale Bresenham + if ((xt += xq) >= srcWidth) { + xt -= srcWidth; + xStep = xp + 1; + } else { + xStep = xp; + } + + // compute the final pixel + pix = pixBuf[x]; + // (255 * pix) / yStep + pix = (pix * d) >> 23; + + // store the pixel + for (i = 0; i < xStep; ++i) { + *destPtr++ = (Guchar)pix; + } + } + } + + gfree(pixBuf); + gfree(lineBuf); +} + +void Splash::scaleMaskYuXd(SplashImageMaskSource src, void *srcData, + int srcWidth, int srcHeight, + int scaledWidth, int scaledHeight, + SplashBitmap *dest) { + Guchar *lineBuf; + Guint pix; + Guchar *destPtr0, *destPtr; + int yp, yq, xp, xq, yt, y, yStep, xt, x, xStep, xx, d, d0, d1; + int i; + + destPtr0 = dest->data; + if (destPtr0 == NULL) { + error(errInternal, -1, "dest->data is NULL in Splash::scaleMaskYuXd"); + return; + } + + // Bresenham parameters for y scale + yp = scaledHeight / srcHeight; + yq = scaledHeight % srcHeight; + + // Bresenham parameters for x scale + xp = srcWidth / scaledWidth; + xq = srcWidth % scaledWidth; + + // allocate buffers + lineBuf = (Guchar *)gmalloc(srcWidth); + + // init y scale Bresenham + yt = 0; + + for (y = 0; y < srcHeight; ++y) { + + // y scale Bresenham + if ((yt += yq) >= srcHeight) { + yt -= srcHeight; + yStep = yp + 1; + } else { + yStep = yp; + } + + // read row from image + (*src)(srcData, lineBuf); + + // init x scale Bresenham + xt = 0; + d0 = (255 << 23) / xp; + d1 = (255 << 23) / (xp + 1); + + xx = 0; + for (x = 0; x < scaledWidth; ++x) { + + // x scale Bresenham + if ((xt += xq) >= scaledWidth) { + xt -= scaledWidth; + xStep = xp + 1; + d = d1; + } else { + xStep = xp; + d = d0; + } + + // compute the final pixel + pix = 0; + for (i = 0; i < xStep; ++i) { + pix += lineBuf[xx++]; + } + // (255 * pix) / xStep + pix = (pix * d) >> 23; + + // store the pixel + for (i = 0; i < yStep; ++i) { + destPtr = destPtr0 + i * scaledWidth + x; + *destPtr = (Guchar)pix; + } + } + + destPtr0 += yStep * scaledWidth; + } + + gfree(lineBuf); +} + +void Splash::scaleMaskYuXu(SplashImageMaskSource src, void *srcData, + int srcWidth, int srcHeight, + int scaledWidth, int scaledHeight, + SplashBitmap *dest) { + Guchar *lineBuf; + Guint pix; + Guchar *destPtr0, *destPtr; + int yp, yq, xp, xq, yt, y, yStep, xt, x, xStep, xx; + int i, j; + + destPtr0 = dest->data; + if (destPtr0 == NULL) { + error(errInternal, -1, "dest->data is NULL in Splash::scaleMaskYuXu"); + return; + } + + // Bresenham parameters for y scale + yp = scaledHeight / srcHeight; + yq = scaledHeight % srcHeight; + + // Bresenham parameters for x scale + xp = scaledWidth / srcWidth; + xq = scaledWidth % srcWidth; + + // allocate buffers + lineBuf = (Guchar *)gmalloc(srcWidth); + + // init y scale Bresenham + yt = 0; + + for (y = 0; y < srcHeight; ++y) { + + // y scale Bresenham + if ((yt += yq) >= srcHeight) { + yt -= srcHeight; + yStep = yp + 1; + } else { + yStep = yp; + } + + // read row from image + (*src)(srcData, lineBuf); + + // init x scale Bresenham + xt = 0; + + xx = 0; + for (x = 0; x < srcWidth; ++x) { + + // x scale Bresenham + if ((xt += xq) >= srcWidth) { + xt -= srcWidth; + xStep = xp + 1; + } else { + xStep = xp; + } + + // compute the final pixel + pix = lineBuf[x] ? 255 : 0; + + // store the pixel + for (i = 0; i < yStep; ++i) { + for (j = 0; j < xStep; ++j) { + destPtr = destPtr0 + i * scaledWidth + xx + j; + *destPtr++ = (Guchar)pix; + } + } + + xx += xStep; + } + + destPtr0 += yStep * scaledWidth; + } + + gfree(lineBuf); +} + +void Splash::blitMask(SplashBitmap *src, int xDest, int yDest, + SplashClipResult clipRes) { + SplashPipe pipe; + Guchar *p; + int w, h, x, y; + + w = src->getWidth(); + h = src->getHeight(); + p = src->getDataPtr(); + if (p == NULL) { + error(errInternal, -1, "src->getDataPtr() is NULL in Splash::blitMask"); + return; + } + if (vectorAntialias && clipRes != splashClipAllInside) { + pipeInit(&pipe, xDest, yDest, state->fillPattern, NULL, + (Guchar)splashRound(state->fillAlpha * 255), gTrue, gFalse); + drawAAPixelInit(); + for (y = 0; y < h; ++y) { + for (x = 0; x < w; ++x) { + pipe.shape = *p++; + drawAAPixel(&pipe, xDest + x, yDest + y); + } + } + } else { + pipeInit(&pipe, xDest, yDest, state->fillPattern, NULL, + (Guchar)splashRound(state->fillAlpha * 255), gTrue, gFalse); + if (clipRes == splashClipAllInside) { + for (y = 0; y < h; ++y) { + pipeSetXY(&pipe, xDest, yDest + y); + for (x = 0; x < w; ++x) { + if (*p) { + pipe.shape = *p; + (this->*pipe.run)(&pipe); + } else { + pipeIncX(&pipe); + } + ++p; + } + } + updateModX(xDest); + updateModX(xDest + w - 1); + updateModY(yDest); + updateModY(yDest + h - 1); + } else { + for (y = 0; y < h; ++y) { + pipeSetXY(&pipe, xDest, yDest + y); + for (x = 0; x < w; ++x) { + if (*p && state->clip->test(xDest + x, yDest + y)) { + pipe.shape = *p; + (this->*pipe.run)(&pipe); + updateModX(xDest + x); + updateModY(yDest + y); + } else { + pipeIncX(&pipe); + } + ++p; + } + } + } + } +} + +SplashError Splash::drawImage(SplashImageSource src, void *srcData, + SplashColorMode srcMode, GBool srcAlpha, + int w, int h, SplashCoord *mat, GBool interpolate, + GBool tilingPattern) { + GBool ok; + SplashBitmap *scaledImg; + SplashClipResult clipRes; + GBool minorAxisZero; + int x0, y0, x1, y1, scaledWidth, scaledHeight; + int nComps; + int yp; + + if (debugMode) { + printf("drawImage: srcMode=%d srcAlpha=%d w=%d h=%d mat=[%.2f %.2f %.2f %.2f %.2f %.2f]\n", + srcMode, srcAlpha, w, h, (double)mat[0], (double)mat[1], (double)mat[2], + (double)mat[3], (double)mat[4], (double)mat[5]); + } + + // check color modes + ok = gFalse; // make gcc happy + nComps = 0; // make gcc happy + switch (bitmap->mode) { + case splashModeMono1: + case splashModeMono8: + ok = srcMode == splashModeMono8; + nComps = 1; + break; + case splashModeRGB8: + ok = srcMode == splashModeRGB8; + nComps = 3; + break; + case splashModeXBGR8: + ok = srcMode == splashModeXBGR8; + nComps = 4; + break; + case splashModeBGR8: + ok = srcMode == splashModeBGR8; + nComps = 3; + break; +#if SPLASH_CMYK + case splashModeCMYK8: + ok = srcMode == splashModeCMYK8; + nComps = 4; + break; + case splashModeDeviceN8: + ok = srcMode == splashModeDeviceN8; + nComps = SPOT_NCOMPS+4; + break; +#endif + default: + ok = gFalse; + break; + } + if (!ok) { + return splashErrModeMismatch; + } + + // check for singular matrix + if (!splashCheckDet(mat[0], mat[1], mat[2], mat[3], 0.000001)) { + return splashErrSingularMatrix; + } + + minorAxisZero = mat[1] == 0 && mat[2] == 0; + + // scaling only + if (mat[0] > 0 && minorAxisZero && mat[3] > 0) { + x0 = imgCoordMungeLower(mat[4]); + y0 = imgCoordMungeLower(mat[5]); + x1 = imgCoordMungeUpper(mat[0] + mat[4]); + y1 = imgCoordMungeUpper(mat[3] + mat[5]); + // make sure narrow images cover at least one pixel + if (x0 == x1) { + ++x1; + } + if (y0 == y1) { + ++y1; + } + clipRes = state->clip->testRect(x0, y0, x1 - 1, y1 - 1); + opClipRes = clipRes; + if (clipRes != splashClipAllOutside) { + scaledWidth = x1 - x0; + scaledHeight = y1 - y0; + yp = h / scaledHeight; + if (yp < 0 || yp > INT_MAX - 1) { + return splashErrBadArg; + } + scaledImg = scaleImage(src, srcData, srcMode, nComps, srcAlpha, w, h, + scaledWidth, scaledHeight, interpolate, tilingPattern); + if (scaledImg == NULL) { + return splashErrBadArg; + } + blitImage(scaledImg, srcAlpha, x0, y0, clipRes); + delete scaledImg; + } + + // scaling plus vertical flip + } else if (mat[0] > 0 && minorAxisZero && mat[3] < 0) { + x0 = imgCoordMungeLower(mat[4]); + y0 = imgCoordMungeLower(mat[3] + mat[5]); + x1 = imgCoordMungeUpper(mat[0] + mat[4]); + y1 = imgCoordMungeUpper(mat[5]); + if (x0 == x1) { + if (mat[4] + mat[0] * 0.5 < x0) { + --x0; + } else { + ++x1; + } + } + if (y0 == y1) { + if (mat[5] + mat[1] * 0.5 < y0) { + --y0; + } else { + ++y1; + } + } + clipRes = state->clip->testRect(x0, y0, x1 - 1, y1 - 1); + opClipRes = clipRes; + if (clipRes != splashClipAllOutside) { + scaledWidth = x1 - x0; + scaledHeight = y1 - y0; + yp = h / scaledHeight; + if (yp < 0 || yp > INT_MAX - 1) { + return splashErrBadArg; + } + scaledImg = scaleImage(src, srcData, srcMode, nComps, srcAlpha, w, h, + scaledWidth, scaledHeight, interpolate, tilingPattern); + if (scaledImg == NULL) { + return splashErrBadArg; + } + vertFlipImage(scaledImg, scaledWidth, scaledHeight, nComps); + blitImage(scaledImg, srcAlpha, x0, y0, clipRes); + delete scaledImg; + } + + // all other cases + } else { + return arbitraryTransformImage(src, srcData, srcMode, nComps, srcAlpha, + w, h, mat, interpolate, tilingPattern); + } + + return splashOk; +} + +SplashError Splash::arbitraryTransformImage(SplashImageSource src, void *srcData, + SplashColorMode srcMode, int nComps, + GBool srcAlpha, + int srcWidth, int srcHeight, + SplashCoord *mat, GBool interpolate, + GBool tilingPattern) { + SplashBitmap *scaledImg; + SplashClipResult clipRes, clipRes2; + SplashPipe pipe; + SplashColor pixel; + int scaledWidth, scaledHeight, t0, t1, th; + SplashCoord r00, r01, r10, r11, det, ir00, ir01, ir10, ir11; + SplashCoord vx[4], vy[4]; + int xMin, yMin, xMax, yMax; + ImageSection section[3]; + int nSections; + int y, xa, xb, x, i, xx, yy, yp; + + // compute the four vertices of the target quadrilateral + vx[0] = mat[4]; vy[0] = mat[5]; + vx[1] = mat[2] + mat[4]; vy[1] = mat[3] + mat[5]; + vx[2] = mat[0] + mat[2] + mat[4]; vy[2] = mat[1] + mat[3] + mat[5]; + vx[3] = mat[0] + mat[4]; vy[3] = mat[1] + mat[5]; + + // clipping + xMin = imgCoordMungeLower(vx[0]); + xMax = imgCoordMungeUpper(vx[0]); + yMin = imgCoordMungeLower(vy[0]); + yMax = imgCoordMungeUpper(vy[0]); + for (i = 1; i < 4; ++i) { + t0 = imgCoordMungeLower(vx[i]); + if (t0 < xMin) { + xMin = t0; + } + t0 = imgCoordMungeUpper(vx[i]); + if (t0 > xMax) { + xMax = t0; + } + t1 = imgCoordMungeLower(vy[i]); + if (t1 < yMin) { + yMin = t1; + } + t1 = imgCoordMungeUpper(vy[i]); + if (t1 > yMax) { + yMax = t1; + } + } + clipRes = state->clip->testRect(xMin, yMin, xMax, yMax); + opClipRes = clipRes; + if (clipRes == splashClipAllOutside) { + return splashOk; + } + + // compute the scale factors + if (splashAbs(mat[0]) >= splashAbs(mat[1])) { + scaledWidth = xMax - xMin; + scaledHeight = yMax - yMin; + } else { + scaledWidth = yMax - yMin; + scaledHeight = xMax - xMin; + } + if (scaledHeight <= 1 || scaledWidth <= 1 || tilingPattern) { + if (mat[0] >= 0) { + t0 = imgCoordMungeUpper(mat[0] + mat[4]) - imgCoordMungeLower(mat[4]); + } else { + t0 = imgCoordMungeUpper(mat[4]) - imgCoordMungeLower(mat[0] + mat[4]); + } + if (mat[1] >= 0) { + t1 = imgCoordMungeUpper(mat[1] + mat[5]) - imgCoordMungeLower(mat[5]); + } else { + t1 = imgCoordMungeUpper(mat[5]) - imgCoordMungeLower(mat[1] + mat[5]); + } + scaledWidth = t0 > t1 ? t0 : t1; + if (mat[2] >= 0) { + t0 = imgCoordMungeUpper(mat[2] + mat[4]) - imgCoordMungeLower(mat[4]); + if (splashAbs(mat[1]) >= 1) { + th = imgCoordMungeUpper(mat[2]) - imgCoordMungeLower(mat[0] * mat[3] / mat[1]); + if (th > t0) t0 = th; + } + } else { + t0 = imgCoordMungeUpper(mat[4]) - imgCoordMungeLower(mat[2] + mat[4]); + if (splashAbs(mat[1]) >= 1) { + th = imgCoordMungeUpper(mat[0] * mat[3] / mat[1]) - imgCoordMungeLower(mat[2]); + if (th > t0) t0 = th; + } + } + if (mat[3] >= 0) { + t1 = imgCoordMungeUpper(mat[3] + mat[5]) - imgCoordMungeLower(mat[5]); + if (splashAbs(mat[0]) >= 1) { + th = imgCoordMungeUpper(mat[3]) - imgCoordMungeLower(mat[1] * mat[2] / mat[0]); + if (th > t1) t1 = th; + } + } else { + t1 = imgCoordMungeUpper(mat[5]) - imgCoordMungeLower(mat[3] + mat[5]); + if (splashAbs(mat[0]) >= 1) { + th = imgCoordMungeUpper(mat[1] * mat[2] / mat[0]) - imgCoordMungeLower(mat[3]); + if (th > t1) t1 = th; + } + } + scaledHeight = t0 > t1 ? t0 : t1; + } + if (scaledWidth == 0) { + scaledWidth = 1; + } + if (scaledHeight == 0) { + scaledHeight = 1; + } + + // compute the inverse transform (after scaling) matrix + r00 = mat[0] / scaledWidth; + r01 = mat[1] / scaledWidth; + r10 = mat[2] / scaledHeight; + r11 = mat[3] / scaledHeight; + det = r00 * r11 - r01 * r10; + if (splashAbs(det) < 1e-6) { + // this should be caught by the singular matrix check in drawImage + return splashErrBadArg; + } + ir00 = r11 / det; + ir01 = -r01 / det; + ir10 = -r10 / det; + ir11 = r00 / det; + + // scale the input image + yp = srcHeight / scaledHeight; + if (yp < 0 || yp > INT_MAX - 1) { + return splashErrBadArg; + } + scaledImg = scaleImage(src, srcData, srcMode, nComps, srcAlpha, + srcWidth, srcHeight, scaledWidth, scaledHeight, interpolate); + + if (scaledImg == NULL) { + return splashErrBadArg; + } + + // construct the three sections + i = 0; + if (vy[1] < vy[i]) { + i = 1; + } + if (vy[2] < vy[i]) { + i = 2; + } + if (vy[3] < vy[i]) { + i = 3; + } + // NB: if using fixed point, 0.000001 will be truncated to zero, + // so these two comparisons must be <=, not < + if (splashAbs(vy[i] - vy[(i-1) & 3]) <= 0.000001 && + vy[(i-1) & 3] < vy[(i+1) & 3]) { + i = (i-1) & 3; + } + if (splashAbs(vy[i] - vy[(i+1) & 3]) <= 0.000001) { + section[0].y0 = imgCoordMungeLower(vy[i]); + section[0].y1 = imgCoordMungeUpper(vy[(i+2) & 3]) - 1; + if (vx[i] < vx[(i+1) & 3]) { + section[0].ia0 = i; + section[0].ia1 = (i+3) & 3; + section[0].ib0 = (i+1) & 3; + section[0].ib1 = (i+2) & 3; + } else { + section[0].ia0 = (i+1) & 3; + section[0].ia1 = (i+2) & 3; + section[0].ib0 = i; + section[0].ib1 = (i+3) & 3; + } + nSections = 1; + } else { + section[0].y0 = imgCoordMungeLower(vy[i]); + section[2].y1 = imgCoordMungeUpper(vy[(i+2) & 3]) - 1; + section[0].ia0 = section[0].ib0 = i; + section[2].ia1 = section[2].ib1 = (i+2) & 3; + if (vx[(i+1) & 3] < vx[(i+3) & 3]) { + section[0].ia1 = section[2].ia0 = (i+1) & 3; + section[0].ib1 = section[2].ib0 = (i+3) & 3; + } else { + section[0].ia1 = section[2].ia0 = (i+3) & 3; + section[0].ib1 = section[2].ib0 = (i+1) & 3; + } + if (vy[(i+1) & 3] < vy[(i+3) & 3]) { + section[1].y0 = imgCoordMungeLower(vy[(i+1) & 3]); + section[2].y0 = imgCoordMungeUpper(vy[(i+3) & 3]); + if (vx[(i+1) & 3] < vx[(i+3) & 3]) { + section[1].ia0 = (i+1) & 3; + section[1].ia1 = (i+2) & 3; + section[1].ib0 = i; + section[1].ib1 = (i+3) & 3; + } else { + section[1].ia0 = i; + section[1].ia1 = (i+3) & 3; + section[1].ib0 = (i+1) & 3; + section[1].ib1 = (i+2) & 3; + } + } else { + section[1].y0 = imgCoordMungeLower(vy[(i+3) & 3]); + section[2].y0 = imgCoordMungeUpper(vy[(i+1) & 3]); + if (vx[(i+1) & 3] < vx[(i+3) & 3]) { + section[1].ia0 = i; + section[1].ia1 = (i+1) & 3; + section[1].ib0 = (i+3) & 3; + section[1].ib1 = (i+2) & 3; + } else { + section[1].ia0 = (i+3) & 3; + section[1].ia1 = (i+2) & 3; + section[1].ib0 = i; + section[1].ib1 = (i+1) & 3; + } + } + section[0].y1 = section[1].y0 - 1; + section[1].y1 = section[2].y0 - 1; + nSections = 3; + } + for (i = 0; i < nSections; ++i) { + section[i].xa0 = vx[section[i].ia0]; + section[i].ya0 = vy[section[i].ia0]; + section[i].xa1 = vx[section[i].ia1]; + section[i].ya1 = vy[section[i].ia1]; + section[i].xb0 = vx[section[i].ib0]; + section[i].yb0 = vy[section[i].ib0]; + section[i].xb1 = vx[section[i].ib1]; + section[i].yb1 = vy[section[i].ib1]; + section[i].dxdya = (section[i].xa1 - section[i].xa0) / + (section[i].ya1 - section[i].ya0); + section[i].dxdyb = (section[i].xb1 - section[i].xb0) / + (section[i].yb1 - section[i].yb0); + } + + // initialize the pixel pipe + pipeInit(&pipe, 0, 0, NULL, pixel, + (Guchar)splashRound(state->fillAlpha * 255), + srcAlpha || (vectorAntialias && clipRes != splashClipAllInside), + gFalse); + if (vectorAntialias) { + drawAAPixelInit(); + } + + // make sure narrow images cover at least one pixel + if (nSections == 1) { + if (section[0].y0 == section[0].y1) { + ++section[0].y1; + clipRes = opClipRes = splashClipPartial; + } + } else { + if (section[0].y0 == section[2].y1) { + ++section[1].y1; + clipRes = opClipRes = splashClipPartial; + } + } + + // scan all pixels inside the target region + for (i = 0; i < nSections; ++i) { + for (y = section[i].y0; y <= section[i].y1; ++y) { + xa = imgCoordMungeLower(section[i].xa0 + + ((SplashCoord)y + 0.5 - section[i].ya0) * + section[i].dxdya); + if (unlikely(xa < 0)) + xa = 0; + xb = imgCoordMungeUpper(section[i].xb0 + + ((SplashCoord)y + 0.5 - section[i].yb0) * + section[i].dxdyb); + // make sure narrow images cover at least one pixel + if (xa == xb) { + ++xb; + } + if (clipRes != splashClipAllInside) { + clipRes2 = state->clip->testSpan(xa, xb - 1, y); + } else { + clipRes2 = clipRes; + } + for (x = xa; x < xb; ++x) { + // map (x+0.5, y+0.5) back to the scaled image + xx = splashFloor(((SplashCoord)x + 0.5 - mat[4]) * ir00 + + ((SplashCoord)y + 0.5 - mat[5]) * ir10); + yy = splashFloor(((SplashCoord)x + 0.5 - mat[4]) * ir01 + + ((SplashCoord)y + 0.5 - mat[5]) * ir11); + // xx should always be within bounds, but floating point + // inaccuracy can cause problems + if (xx < 0) { + xx = 0; + } else if (xx >= scaledWidth) { + xx = scaledWidth - 1; + } + if (yy < 0) { + yy = 0; + } else if (yy >= scaledHeight) { + yy = scaledHeight - 1; + } + scaledImg->getPixel(xx, yy, pixel); + if (srcAlpha) { + pipe.shape = scaledImg->alpha[yy * scaledWidth + xx]; + } else { + pipe.shape = 255; + } + if (vectorAntialias && clipRes2 != splashClipAllInside) { + drawAAPixel(&pipe, x, y); + } else { + drawPixel(&pipe, x, y, clipRes2 == splashClipAllInside); + } + } + } + } + + delete scaledImg; + return splashOk; +} + +// determine if a scaled image requires interpolation based on the scale and +// the interpolate flag from the image dictionary +static GBool isImageInterpolationRequired(int srcWidth, int srcHeight, + int scaledWidth, int scaledHeight, + GBool interpolate) { + if (interpolate) + return gTrue; + + /* When scale factor is >= 400% we don't interpolate. See bugs #25268, #9860 */ + if (scaledWidth / srcWidth >= 4 || scaledHeight / srcHeight >= 4) + return gFalse; + + return gTrue; +} + +// Scale an image into a SplashBitmap. +SplashBitmap *Splash::scaleImage(SplashImageSource src, void *srcData, + SplashColorMode srcMode, int nComps, + GBool srcAlpha, int srcWidth, int srcHeight, + int scaledWidth, int scaledHeight, GBool interpolate, GBool tilingPattern) { + SplashBitmap *dest; + + dest = new SplashBitmap(scaledWidth, scaledHeight, 1, srcMode, srcAlpha, gTrue, bitmap->getSeparationList()); + if (dest->getDataPtr() != NULL) { + if (scaledHeight < srcHeight) { + if (scaledWidth < srcWidth) { + scaleImageYdXd(src, srcData, srcMode, nComps, srcAlpha, + srcWidth, srcHeight, scaledWidth, scaledHeight, dest); + } else { + scaleImageYdXu(src, srcData, srcMode, nComps, srcAlpha, + srcWidth, srcHeight, scaledWidth, scaledHeight, dest); + } + } else { + if (scaledWidth < srcWidth) { + scaleImageYuXd(src, srcData, srcMode, nComps, srcAlpha, + srcWidth, srcHeight, scaledWidth, scaledHeight, dest); + } else { + if (!tilingPattern && isImageInterpolationRequired(srcWidth, srcHeight, scaledWidth, scaledHeight, interpolate)) { + scaleImageYuXuBilinear(src, srcData, srcMode, nComps, srcAlpha, + srcWidth, srcHeight, scaledWidth, scaledHeight, dest); + } else { + scaleImageYuXu(src, srcData, srcMode, nComps, srcAlpha, + srcWidth, srcHeight, scaledWidth, scaledHeight, dest); + } + } + } + } else { + delete dest; + dest = NULL; + } + return dest; +} + +void Splash::scaleImageYdXd(SplashImageSource src, void *srcData, + SplashColorMode srcMode, int nComps, + GBool srcAlpha, int srcWidth, int srcHeight, + int scaledWidth, int scaledHeight, + SplashBitmap *dest) { + Guchar *lineBuf, *alphaLineBuf; + Guint *pixBuf, *alphaPixBuf; + Guint pix0, pix1, pix2; +#if SPLASH_CMYK + Guint pix3; + Guint pix[SPOT_NCOMPS+4], cp; +#endif + Guint alpha; + Guchar *destPtr, *destAlphaPtr; + int yp, yq, xp, xq, yt, y, yStep, xt, x, xStep, xx, xxa, d, d0, d1; + int i, j; + + // Bresenham parameters for y scale + yp = srcHeight / scaledHeight; + yq = srcHeight % scaledHeight; + + // Bresenham parameters for x scale + xp = srcWidth / scaledWidth; + xq = srcWidth % scaledWidth; + + // allocate buffers + lineBuf = (Guchar *)gmallocn(srcWidth, nComps); + pixBuf = (Guint *)gmallocn(srcWidth, nComps * sizeof(int)); + if (srcAlpha) { + alphaLineBuf = (Guchar *)gmalloc(srcWidth); + alphaPixBuf = (Guint *)gmallocn(srcWidth, sizeof(int)); + } else { + alphaLineBuf = NULL; + alphaPixBuf = NULL; + } + + // init y scale Bresenham + yt = 0; + + destPtr = dest->data; + destAlphaPtr = dest->alpha; + for (y = 0; y < scaledHeight; ++y) { + + // y scale Bresenham + if ((yt += yq) >= scaledHeight) { + yt -= scaledHeight; + yStep = yp + 1; + } else { + yStep = yp; + } + + // read rows from image + memset(pixBuf, 0, srcWidth * nComps * sizeof(int)); + if (srcAlpha) { + memset(alphaPixBuf, 0, srcWidth * sizeof(int)); + } + for (i = 0; i < yStep; ++i) { + (*src)(srcData, lineBuf, alphaLineBuf); + for (j = 0; j < srcWidth * nComps; ++j) { + pixBuf[j] += lineBuf[j]; + } + if (srcAlpha) { + for (j = 0; j < srcWidth; ++j) { + alphaPixBuf[j] += alphaLineBuf[j]; + } + } + } + + // init x scale Bresenham + xt = 0; + d0 = (1 << 23) / (yStep * xp); + d1 = (1 << 23) / (yStep * (xp + 1)); + + xx = xxa = 0; + for (x = 0; x < scaledWidth; ++x) { + + // x scale Bresenham + if ((xt += xq) >= scaledWidth) { + xt -= scaledWidth; + xStep = xp + 1; + d = d1; + } else { + xStep = xp; + d = d0; + } + + switch (srcMode) { + + case splashModeMono8: + + // compute the final pixel + pix0 = 0; + for (i = 0; i < xStep; ++i) { + pix0 += pixBuf[xx++]; + } + // pix / xStep * yStep + pix0 = (pix0 * d) >> 23; + + // store the pixel + *destPtr++ = (Guchar)pix0; + break; + + case splashModeRGB8: + + // compute the final pixel + pix0 = pix1 = pix2 = 0; + for (i = 0; i < xStep; ++i) { + pix0 += pixBuf[xx]; + pix1 += pixBuf[xx+1]; + pix2 += pixBuf[xx+2]; + xx += 3; + } + // pix / xStep * yStep + pix0 = (pix0 * d) >> 23; + pix1 = (pix1 * d) >> 23; + pix2 = (pix2 * d) >> 23; + + // store the pixel + *destPtr++ = (Guchar)pix0; + *destPtr++ = (Guchar)pix1; + *destPtr++ = (Guchar)pix2; + break; + + case splashModeXBGR8: + + // compute the final pixel + pix0 = pix1 = pix2 = 0; + for (i = 0; i < xStep; ++i) { + pix0 += pixBuf[xx]; + pix1 += pixBuf[xx+1]; + pix2 += pixBuf[xx+2]; + xx += 4; + } + // pix / xStep * yStep + pix0 = (pix0 * d) >> 23; + pix1 = (pix1 * d) >> 23; + pix2 = (pix2 * d) >> 23; + + // store the pixel + *destPtr++ = (Guchar)pix2; + *destPtr++ = (Guchar)pix1; + *destPtr++ = (Guchar)pix0; + *destPtr++ = (Guchar)255; + break; + + case splashModeBGR8: + + // compute the final pixel + pix0 = pix1 = pix2 = 0; + for (i = 0; i < xStep; ++i) { + pix0 += pixBuf[xx]; + pix1 += pixBuf[xx+1]; + pix2 += pixBuf[xx+2]; + xx += 3; + } + // pix / xStep * yStep + pix0 = (pix0 * d) >> 23; + pix1 = (pix1 * d) >> 23; + pix2 = (pix2 * d) >> 23; + + // store the pixel + *destPtr++ = (Guchar)pix2; + *destPtr++ = (Guchar)pix1; + *destPtr++ = (Guchar)pix0; + break; + +#if SPLASH_CMYK + case splashModeCMYK8: + + // compute the final pixel + pix0 = pix1 = pix2 = pix3 = 0; + for (i = 0; i < xStep; ++i) { + pix0 += pixBuf[xx]; + pix1 += pixBuf[xx+1]; + pix2 += pixBuf[xx+2]; + pix3 += pixBuf[xx+3]; + xx += 4; + } + // pix / xStep * yStep + pix0 = (pix0 * d) >> 23; + pix1 = (pix1 * d) >> 23; + pix2 = (pix2 * d) >> 23; + pix3 = (pix3 * d) >> 23; + + // store the pixel + *destPtr++ = (Guchar)pix0; + *destPtr++ = (Guchar)pix1; + *destPtr++ = (Guchar)pix2; + *destPtr++ = (Guchar)pix3; + break; + case splashModeDeviceN8: + + // compute the final pixel + for (cp = 0; cp < SPOT_NCOMPS+4; cp++) + pix[cp] = 0; + for (i = 0; i < xStep; ++i) { + for (cp = 0; cp < SPOT_NCOMPS+4; cp++) { + pix[cp] += pixBuf[xx + cp]; + } + xx += (SPOT_NCOMPS+4); + } + // pix / xStep * yStep + for (cp = 0; cp < SPOT_NCOMPS+4; cp++) + pix[cp] = (pix[cp] * d) >> 23; + + // store the pixel + for (cp = 0; cp < SPOT_NCOMPS+4; cp++) + *destPtr++ = (Guchar)pix[cp]; + break; +#endif + + + case splashModeMono1: // mono1 is not allowed + default: + break; + } + + // process alpha + if (srcAlpha) { + alpha = 0; + for (i = 0; i < xStep; ++i, ++xxa) { + alpha += alphaPixBuf[xxa]; + } + // alpha / xStep * yStep + alpha = (alpha * d) >> 23; + *destAlphaPtr++ = (Guchar)alpha; + } + } + } + + gfree(alphaPixBuf); + gfree(alphaLineBuf); + gfree(pixBuf); + gfree(lineBuf); +} + +void Splash::scaleImageYdXu(SplashImageSource src, void *srcData, + SplashColorMode srcMode, int nComps, + GBool srcAlpha, int srcWidth, int srcHeight, + int scaledWidth, int scaledHeight, + SplashBitmap *dest) { + Guchar *lineBuf, *alphaLineBuf; + Guint *pixBuf, *alphaPixBuf; + Guint pix[splashMaxColorComps]; + Guint alpha; + Guchar *destPtr, *destAlphaPtr; + int yp, yq, xp, xq, yt, y, yStep, xt, x, xStep, d; + int i, j; + + // Bresenham parameters for y scale + yp = srcHeight / scaledHeight; + yq = srcHeight % scaledHeight; + + // Bresenham parameters for x scale + xp = scaledWidth / srcWidth; + xq = scaledWidth % srcWidth; + + // allocate buffers + lineBuf = (Guchar *)gmallocn(srcWidth, nComps); + pixBuf = (Guint *)gmallocn(srcWidth, nComps * sizeof(int)); + if (srcAlpha) { + alphaLineBuf = (Guchar *)gmalloc(srcWidth); + alphaPixBuf = (Guint *)gmallocn(srcWidth, sizeof(int)); + } else { + alphaLineBuf = NULL; + alphaPixBuf = NULL; + } + + // init y scale Bresenham + yt = 0; + + destPtr = dest->data; + destAlphaPtr = dest->alpha; + for (y = 0; y < scaledHeight; ++y) { + + // y scale Bresenham + if ((yt += yq) >= scaledHeight) { + yt -= scaledHeight; + yStep = yp + 1; + } else { + yStep = yp; + } + + // read rows from image + memset(pixBuf, 0, srcWidth * nComps * sizeof(int)); + if (srcAlpha) { + memset(alphaPixBuf, 0, srcWidth * sizeof(int)); + } + for (i = 0; i < yStep; ++i) { + (*src)(srcData, lineBuf, alphaLineBuf); + for (j = 0; j < srcWidth * nComps; ++j) { + pixBuf[j] += lineBuf[j]; + } + if (srcAlpha) { + for (j = 0; j < srcWidth; ++j) { + alphaPixBuf[j] += alphaLineBuf[j]; + } + } + } + + // init x scale Bresenham + xt = 0; + d = (1 << 23) / yStep; + + for (x = 0; x < srcWidth; ++x) { + + // x scale Bresenham + if ((xt += xq) >= srcWidth) { + xt -= srcWidth; + xStep = xp + 1; + } else { + xStep = xp; + } + + // compute the final pixel + for (i = 0; i < nComps; ++i) { + // pixBuf[] / yStep + pix[i] = (pixBuf[x * nComps + i] * d) >> 23; + } + + // store the pixel + switch (srcMode) { + case splashModeMono1: // mono1 is not allowed + break; + case splashModeMono8: + for (i = 0; i < xStep; ++i) { + *destPtr++ = (Guchar)pix[0]; + } + break; + case splashModeRGB8: + for (i = 0; i < xStep; ++i) { + *destPtr++ = (Guchar)pix[0]; + *destPtr++ = (Guchar)pix[1]; + *destPtr++ = (Guchar)pix[2]; + } + break; + case splashModeXBGR8: + for (i = 0; i < xStep; ++i) { + *destPtr++ = (Guchar)pix[2]; + *destPtr++ = (Guchar)pix[1]; + *destPtr++ = (Guchar)pix[0]; + *destPtr++ = (Guchar)255; + } + break; + case splashModeBGR8: + for (i = 0; i < xStep; ++i) { + *destPtr++ = (Guchar)pix[2]; + *destPtr++ = (Guchar)pix[1]; + *destPtr++ = (Guchar)pix[0]; + } + break; +#if SPLASH_CMYK + case splashModeCMYK8: + for (i = 0; i < xStep; ++i) { + *destPtr++ = (Guchar)pix[0]; + *destPtr++ = (Guchar)pix[1]; + *destPtr++ = (Guchar)pix[2]; + *destPtr++ = (Guchar)pix[3]; + } + break; + case splashModeDeviceN8: + for (i = 0; i < xStep; ++i) { + for (int cp = 0; cp < SPOT_NCOMPS+4; cp++) + *destPtr++ = (Guchar)pix[cp]; + } + break; +#endif + } + + // process alpha + if (srcAlpha) { + // alphaPixBuf[] / yStep + alpha = (alphaPixBuf[x] * d) >> 23; + for (i = 0; i < xStep; ++i) { + *destAlphaPtr++ = (Guchar)alpha; + } + } + } + } + + gfree(alphaPixBuf); + gfree(alphaLineBuf); + gfree(pixBuf); + gfree(lineBuf); +} + +void Splash::scaleImageYuXd(SplashImageSource src, void *srcData, + SplashColorMode srcMode, int nComps, + GBool srcAlpha, int srcWidth, int srcHeight, + int scaledWidth, int scaledHeight, + SplashBitmap *dest) { + Guchar *lineBuf, *alphaLineBuf; + Guint pix[splashMaxColorComps]; + Guint alpha; + Guchar *destPtr0, *destPtr, *destAlphaPtr0, *destAlphaPtr; + int yp, yq, xp, xq, yt, y, yStep, xt, x, xStep, xx, xxa, d, d0, d1; + int i, j; + + // Bresenham parameters for y scale + yp = scaledHeight / srcHeight; + yq = scaledHeight % srcHeight; + + // Bresenham parameters for x scale + xp = srcWidth / scaledWidth; + xq = srcWidth % scaledWidth; + + // allocate buffers + lineBuf = (Guchar *)gmallocn_checkoverflow(srcWidth, nComps); + if (unlikely(!lineBuf)) + return; + if (srcAlpha) { + alphaLineBuf = (Guchar *)gmalloc(srcWidth); + } else { + alphaLineBuf = NULL; + } + + // init y scale Bresenham + yt = 0; + + destPtr0 = dest->data; + destAlphaPtr0 = dest->alpha; + for (y = 0; y < srcHeight; ++y) { + + // y scale Bresenham + if ((yt += yq) >= srcHeight) { + yt -= srcHeight; + yStep = yp + 1; + } else { + yStep = yp; + } + + // read row from image + (*src)(srcData, lineBuf, alphaLineBuf); + + // init x scale Bresenham + xt = 0; + d0 = (1 << 23) / xp; + d1 = (1 << 23) / (xp + 1); + + xx = xxa = 0; + for (x = 0; x < scaledWidth; ++x) { + + // x scale Bresenham + if ((xt += xq) >= scaledWidth) { + xt -= scaledWidth; + xStep = xp + 1; + d = d1; + } else { + xStep = xp; + d = d0; + } + + // compute the final pixel + for (i = 0; i < nComps; ++i) { + pix[i] = 0; + } + for (i = 0; i < xStep; ++i) { + for (j = 0; j < nComps; ++j, ++xx) { + pix[j] += lineBuf[xx]; + } + } + for (i = 0; i < nComps; ++i) { + // pix[] / xStep + pix[i] = (pix[i] * d) >> 23; + } + + // store the pixel + switch (srcMode) { + case splashModeMono1: // mono1 is not allowed + break; + case splashModeMono8: + for (i = 0; i < yStep; ++i) { + destPtr = destPtr0 + (i * scaledWidth + x) * nComps; + *destPtr++ = (Guchar)pix[0]; + } + break; + case splashModeRGB8: + for (i = 0; i < yStep; ++i) { + destPtr = destPtr0 + (i * scaledWidth + x) * nComps; + *destPtr++ = (Guchar)pix[0]; + *destPtr++ = (Guchar)pix[1]; + *destPtr++ = (Guchar)pix[2]; + } + break; + case splashModeXBGR8: + for (i = 0; i < yStep; ++i) { + destPtr = destPtr0 + (i * scaledWidth + x) * nComps; + *destPtr++ = (Guchar)pix[2]; + *destPtr++ = (Guchar)pix[1]; + *destPtr++ = (Guchar)pix[0]; + *destPtr++ = (Guchar)255; + } + break; + case splashModeBGR8: + for (i = 0; i < yStep; ++i) { + destPtr = destPtr0 + (i * scaledWidth + x) * nComps; + *destPtr++ = (Guchar)pix[2]; + *destPtr++ = (Guchar)pix[1]; + *destPtr++ = (Guchar)pix[0]; + } + break; +#if SPLASH_CMYK + case splashModeCMYK8: + for (i = 0; i < yStep; ++i) { + destPtr = destPtr0 + (i * scaledWidth + x) * nComps; + *destPtr++ = (Guchar)pix[0]; + *destPtr++ = (Guchar)pix[1]; + *destPtr++ = (Guchar)pix[2]; + *destPtr++ = (Guchar)pix[3]; + } + break; + case splashModeDeviceN8: + for (i = 0; i < yStep; ++i) { + destPtr = destPtr0 + (i * scaledWidth + x) * nComps; + for (int cp = 0; cp < SPOT_NCOMPS+4; cp++) + *destPtr++ = (Guchar)pix[cp]; + } + break; +#endif + } + + // process alpha + if (srcAlpha) { + alpha = 0; + for (i = 0; i < xStep; ++i, ++xxa) { + alpha += alphaLineBuf[xxa]; + } + // alpha / xStep + alpha = (alpha * d) >> 23; + for (i = 0; i < yStep; ++i) { + destAlphaPtr = destAlphaPtr0 + i * scaledWidth + x; + *destAlphaPtr = (Guchar)alpha; + } + } + } + + destPtr0 += yStep * scaledWidth * nComps; + if (srcAlpha) { + destAlphaPtr0 += yStep * scaledWidth; + } + } + + gfree(alphaLineBuf); + gfree(lineBuf); +} + +void Splash::scaleImageYuXu(SplashImageSource src, void *srcData, + SplashColorMode srcMode, int nComps, + GBool srcAlpha, int srcWidth, int srcHeight, + int scaledWidth, int scaledHeight, + SplashBitmap *dest) { + Guchar *lineBuf, *alphaLineBuf; + Guint pix[splashMaxColorComps]; + Guint alpha; + Guchar *destPtr0, *destPtr, *destAlphaPtr0, *destAlphaPtr; + int yp, yq, xp, xq, yt, y, yStep, xt, x, xStep, xx; + int i, j; + + // Bresenham parameters for y scale + yp = scaledHeight / srcHeight; + yq = scaledHeight % srcHeight; + + // Bresenham parameters for x scale + xp = scaledWidth / srcWidth; + xq = scaledWidth % srcWidth; + + // allocate buffers + lineBuf = (Guchar *)gmallocn(srcWidth, nComps); + if (srcAlpha) { + alphaLineBuf = (Guchar *)gmalloc(srcWidth); + } else { + alphaLineBuf = NULL; + } + + // init y scale Bresenham + yt = 0; + + destPtr0 = dest->data; + destAlphaPtr0 = dest->alpha; + for (y = 0; y < srcHeight; ++y) { + + // y scale Bresenham + if ((yt += yq) >= srcHeight) { + yt -= srcHeight; + yStep = yp + 1; + } else { + yStep = yp; + } + + // read row from image + (*src)(srcData, lineBuf, alphaLineBuf); + + // init x scale Bresenham + xt = 0; + + xx = 0; + for (x = 0; x < srcWidth; ++x) { + + // x scale Bresenham + if ((xt += xq) >= srcWidth) { + xt -= srcWidth; + xStep = xp + 1; + } else { + xStep = xp; + } + + // compute the final pixel + for (i = 0; i < nComps; ++i) { + pix[i] = lineBuf[x * nComps + i]; + } + + // store the pixel + switch (srcMode) { + case splashModeMono1: // mono1 is not allowed + break; + case splashModeMono8: + for (i = 0; i < yStep; ++i) { + for (j = 0; j < xStep; ++j) { + destPtr = destPtr0 + (i * scaledWidth + xx + j) * nComps; + *destPtr++ = (Guchar)pix[0]; + } + } + break; + case splashModeRGB8: + for (i = 0; i < yStep; ++i) { + for (j = 0; j < xStep; ++j) { + destPtr = destPtr0 + (i * scaledWidth + xx + j) * nComps; + *destPtr++ = (Guchar)pix[0]; + *destPtr++ = (Guchar)pix[1]; + *destPtr++ = (Guchar)pix[2]; + } + } + break; + case splashModeXBGR8: + for (i = 0; i < yStep; ++i) { + for (j = 0; j < xStep; ++j) { + destPtr = destPtr0 + (i * scaledWidth + xx + j) * nComps; + *destPtr++ = (Guchar)pix[2]; + *destPtr++ = (Guchar)pix[1]; + *destPtr++ = (Guchar)pix[0]; + *destPtr++ = (Guchar)255; + } + } + break; + case splashModeBGR8: + for (i = 0; i < yStep; ++i) { + for (j = 0; j < xStep; ++j) { + destPtr = destPtr0 + (i * scaledWidth + xx + j) * nComps; + *destPtr++ = (Guchar)pix[2]; + *destPtr++ = (Guchar)pix[1]; + *destPtr++ = (Guchar)pix[0]; + } + } + break; +#if SPLASH_CMYK + case splashModeCMYK8: + for (i = 0; i < yStep; ++i) { + for (j = 0; j < xStep; ++j) { + destPtr = destPtr0 + (i * scaledWidth + xx + j) * nComps; + *destPtr++ = (Guchar)pix[0]; + *destPtr++ = (Guchar)pix[1]; + *destPtr++ = (Guchar)pix[2]; + *destPtr++ = (Guchar)pix[3]; + } + } + break; + case splashModeDeviceN8: + for (i = 0; i < yStep; ++i) { + for (j = 0; j < xStep; ++j) { + destPtr = destPtr0 + (i * scaledWidth + xx + j) * nComps; + for (int cp = 0; cp < SPOT_NCOMPS+4; cp++) + *destPtr++ = (Guchar)pix[cp]; + } + } + break; +#endif + } + + // process alpha + if (srcAlpha) { + alpha = alphaLineBuf[x]; + for (i = 0; i < yStep; ++i) { + for (j = 0; j < xStep; ++j) { + destAlphaPtr = destAlphaPtr0 + i * scaledWidth + xx + j; + *destAlphaPtr = (Guchar)alpha; + } + } + } + + xx += xStep; + } + + destPtr0 += yStep * scaledWidth * nComps; + if (srcAlpha) { + destAlphaPtr0 += yStep * scaledWidth; + } + } + + gfree(alphaLineBuf); + gfree(lineBuf); +} + +// expand source row to scaledWidth using linear interpolation +static void expandRow(Guchar *srcBuf, Guchar *dstBuf, int srcWidth, int scaledWidth, int nComps) +{ + double xStep = (double)srcWidth/scaledWidth; + double xSrc = 0.0; + double xFrac, xInt; + int p; + + // pad the source with an extra pixel equal to the last pixel + // so that when xStep is inside the last pixel we still have two + // pixels to interpolate between. + for (int i = 0; i < nComps; i++) + srcBuf[srcWidth*nComps + i] = srcBuf[(srcWidth-1)*nComps + i]; + + for (int x = 0; x < scaledWidth; x++) { + xFrac = modf(xSrc, &xInt); + p = (int)xInt; + for (int c = 0; c < nComps; c++) { + dstBuf[nComps*x + c] = srcBuf[nComps*p + c]*(1.0 - xFrac) + srcBuf[nComps*(p+1) + c]*xFrac; + } + xSrc += xStep; + } +} + +// Scale up image using bilinear interpolation +void Splash::scaleImageYuXuBilinear(SplashImageSource src, void *srcData, + SplashColorMode srcMode, int nComps, + GBool srcAlpha, int srcWidth, int srcHeight, + int scaledWidth, int scaledHeight, + SplashBitmap *dest) { + Guchar *srcBuf, *lineBuf1, *lineBuf2, *alphaSrcBuf, *alphaLineBuf1, *alphaLineBuf2; + Guint pix[splashMaxColorComps]; + Guchar *destPtr0, *destPtr, *destAlphaPtr0, *destAlphaPtr; + int i; + + if (srcWidth < 1 || srcHeight < 1) + return; + + // allocate buffers + srcBuf = (Guchar *)gmallocn(srcWidth+1, nComps); // + 1 pixel of padding + lineBuf1 = (Guchar *)gmallocn(scaledWidth, nComps); + lineBuf2 = (Guchar *)gmallocn(scaledWidth, nComps); + if (srcAlpha) { + alphaSrcBuf = (Guchar *)gmalloc(srcWidth+1); // + 1 pixel of padding + alphaLineBuf1 = (Guchar *)gmalloc(scaledWidth); + alphaLineBuf2 = (Guchar *)gmalloc(scaledWidth); + } else { + alphaSrcBuf = NULL; + alphaLineBuf1 = NULL; + alphaLineBuf2 = NULL; + } + + double ySrc = 0.0; + double yStep = (double)srcHeight/scaledHeight; + double yFrac, yInt; + int currentSrcRow = -1; + (*src)(srcData, srcBuf, alphaSrcBuf); + expandRow(srcBuf, lineBuf2, srcWidth, scaledWidth, nComps); + if (srcAlpha) + expandRow(alphaSrcBuf, alphaLineBuf2, srcWidth, scaledWidth, 1); + + destPtr0 = dest->data; + destAlphaPtr0 = dest->alpha; + for (int y = 0; y < scaledHeight; y++) { + yFrac = modf(ySrc, &yInt); + if ((int)yInt > currentSrcRow) { + currentSrcRow++; + // Copy line2 data to line1 and get next line2 data. + // If line2 already contains the last source row we don't touch it. + // This effectively adds an extra row of padding for interpolating the + // last source row with. + memcpy(lineBuf1, lineBuf2, scaledWidth * nComps); + if (srcAlpha) + memcpy(alphaLineBuf1, alphaLineBuf2, scaledWidth); + if (currentSrcRow < srcHeight) { + (*src)(srcData, srcBuf, alphaSrcBuf); + expandRow(srcBuf, lineBuf2, srcWidth, scaledWidth, nComps); + if (srcAlpha) + expandRow(alphaSrcBuf, alphaLineBuf2, srcWidth, scaledWidth, 1); + } + } + + // write row y using linear interpolation on lineBuf1 and lineBuf2 + for (int x = 0; x < scaledWidth; ++x) { + // compute the final pixel + for (i = 0; i < nComps; ++i) { + pix[i] = lineBuf1[x*nComps + i]*(1.0 - yFrac) + lineBuf2[x*nComps + i]*yFrac; + } + + // store the pixel + destPtr = destPtr0 + (y * scaledWidth + x) * nComps; + switch (srcMode) { + case splashModeMono1: // mono1 is not allowed + break; + case splashModeMono8: + *destPtr++ = (Guchar)pix[0]; + break; + case splashModeRGB8: + *destPtr++ = (Guchar)pix[0]; + *destPtr++ = (Guchar)pix[1]; + *destPtr++ = (Guchar)pix[2]; + break; + case splashModeXBGR8: + *destPtr++ = (Guchar)pix[2]; + *destPtr++ = (Guchar)pix[1]; + *destPtr++ = (Guchar)pix[0]; + *destPtr++ = (Guchar)255; + break; + case splashModeBGR8: + *destPtr++ = (Guchar)pix[2]; + *destPtr++ = (Guchar)pix[1]; + *destPtr++ = (Guchar)pix[0]; + break; +#if SPLASH_CMYK + case splashModeCMYK8: + *destPtr++ = (Guchar)pix[0]; + *destPtr++ = (Guchar)pix[1]; + *destPtr++ = (Guchar)pix[2]; + *destPtr++ = (Guchar)pix[3]; + break; + case splashModeDeviceN8: + for (int cp = 0; cp < SPOT_NCOMPS+4; cp++) + *destPtr++ = (Guchar)pix[cp]; + break; +#endif + } + + // process alpha + if (srcAlpha) { + destAlphaPtr = destAlphaPtr0 + y*scaledWidth + x; + *destAlphaPtr = alphaLineBuf1[x]*(1.0 - yFrac) + alphaLineBuf2[x]*yFrac; + } + } + + ySrc += yStep; + } + + gfree(alphaSrcBuf); + gfree(alphaLineBuf1); + gfree(alphaLineBuf2); + gfree(srcBuf); + gfree(lineBuf1); + gfree(lineBuf2); +} + +void Splash::vertFlipImage(SplashBitmap *img, int width, int height, + int nComps) { + Guchar *lineBuf; + Guchar *p0, *p1; + int w; + + if (unlikely(img->data == NULL)) { + error(errInternal, -1, "img->data is NULL in Splash::vertFlipImage"); + return; + } + + w = width * nComps; + lineBuf = (Guchar *)gmalloc(w); + for (p0 = img->data, p1 = img->data + (height - 1) * w; + p0 < p1; + p0 += w, p1 -= w) { + memcpy(lineBuf, p0, w); + memcpy(p0, p1, w); + memcpy(p1, lineBuf, w); + } + if (img->alpha) { + for (p0 = img->alpha, p1 = img->alpha + (height - 1) * width; + p0 < p1; + p0 += width, p1 -= width) { + memcpy(lineBuf, p0, width); + memcpy(p0, p1, width); + memcpy(p1, lineBuf, width); + } + } + gfree(lineBuf); +} + +void Splash::blitImage(SplashBitmap *src, GBool srcAlpha, int xDest, int yDest) { + SplashClipResult clipRes = state->clip->testRect(xDest, yDest, xDest + src->getWidth() - 1, yDest + src->getHeight() - 1); + if (clipRes != splashClipAllOutside) { + blitImage(src, srcAlpha, xDest, yDest, clipRes); + } +} + +void Splash::blitImage(SplashBitmap *src, GBool srcAlpha, int xDest, int yDest, + SplashClipResult clipRes) { + SplashPipe pipe; + SplashColor pixel; + Guchar *ap; + int w, h, x0, y0, x1, y1, x, y; + + // split the image into clipped and unclipped regions + w = src->getWidth(); + h = src->getHeight(); + if (clipRes == splashClipAllInside) { + x0 = 0; + y0 = 0; + x1 = w; + y1 = h; + } else { + if (state->clip->getNumPaths()) { + x0 = x1 = w; + y0 = y1 = h; + } else { + if ((x0 = splashCeil(state->clip->getXMin()) - xDest) < 0) { + x0 = 0; + } + if ((y0 = splashCeil(state->clip->getYMin()) - yDest) < 0) { + y0 = 0; + } + if ((x1 = splashFloor(state->clip->getXMax()) - xDest) > w) { + x1 = w; + } + if (x1 < x0) { + x1 = x0; + } + if ((y1 = splashFloor(state->clip->getYMax()) - yDest) > h) { + y1 = h; + } + if (y1 < y0) { + y1 = y0; + } + } + } + + // draw the unclipped region + if (x0 < w && y0 < h && x0 < x1 && y0 < y1) { + pipeInit(&pipe, xDest + x0, yDest + y0, NULL, pixel, + (Guchar)splashRound(state->fillAlpha * 255), srcAlpha, gFalse); + if (srcAlpha) { + for (y = y0; y < y1; ++y) { + pipeSetXY(&pipe, xDest + x0, yDest + y); + ap = src->getAlphaPtr() + y * w + x0; + for (x = x0; x < x1; ++x) { + src->getPixel(x, y, pixel); + pipe.shape = *ap++; + (this->*pipe.run)(&pipe); + } + } + } else { + for (y = y0; y < y1; ++y) { + pipeSetXY(&pipe, xDest + x0, yDest + y); + for (x = x0; x < x1; ++x) { + src->getPixel(x, y, pixel); + (this->*pipe.run)(&pipe); + } + } + } + updateModX(xDest + x0); + updateModX(xDest + x1 - 1); + updateModY(yDest + y0); + updateModY(yDest + y1 - 1); + } + + // draw the clipped regions + if (y0 > 0) { + blitImageClipped(src, srcAlpha, 0, 0, xDest, yDest, w, y0); + } + if (y1 < h) { + blitImageClipped(src, srcAlpha, 0, y1, xDest, yDest + y1, w, h - y1); + } + if (x0 > 0 && y0 < y1) { + blitImageClipped(src, srcAlpha, 0, y0, xDest, yDest + y0, x0, y1 - y0); + } + if (x1 < w && y0 < y1) { + blitImageClipped(src, srcAlpha, x1, y0, xDest + x1, yDest + y0, + w - x1, y1 - y0); + } +} + +void Splash::blitImageClipped(SplashBitmap *src, GBool srcAlpha, + int xSrc, int ySrc, int xDest, int yDest, + int w, int h) { + SplashPipe pipe; + SplashColor pixel; + Guchar *ap; + int x, y; + + if (vectorAntialias) { + pipeInit(&pipe, xDest, yDest, NULL, pixel, + (Guchar)splashRound(state->fillAlpha * 255), gTrue, gFalse); + drawAAPixelInit(); + if (srcAlpha) { + for (y = 0; y < h; ++y) { + ap = src->getAlphaPtr() + (ySrc + y) * src->getWidth() + xSrc; + for (x = 0; x < w; ++x) { + src->getPixel(xSrc + x, ySrc + y, pixel); + pipe.shape = *ap++; + drawAAPixel(&pipe, xDest + x, yDest + y); + } + } + } else { + for (y = 0; y < h; ++y) { + for (x = 0; x < w; ++x) { + src->getPixel(xSrc + x, ySrc + y, pixel); + pipe.shape = 255; + drawAAPixel(&pipe, xDest + x, yDest + y); + } + } + } + } else { + pipeInit(&pipe, xDest, yDest, NULL, pixel, + (Guchar)splashRound(state->fillAlpha * 255), srcAlpha, gFalse); + if (srcAlpha) { + for (y = 0; y < h; ++y) { + ap = src->getAlphaPtr() + (ySrc + y) * src->getWidth() + xSrc; + pipeSetXY(&pipe, xDest, yDest + y); + for (x = 0; x < w; ++x) { + if (state->clip->test(xDest + x, yDest + y)) { + src->getPixel(xSrc + x, ySrc + y, pixel); + pipe.shape = *ap++; + (this->*pipe.run)(&pipe); + updateModX(xDest + x); + updateModY(yDest + y); + } else { + pipeIncX(&pipe); + ++ap; + } + } + } + } else { + for (y = 0; y < h; ++y) { + pipeSetXY(&pipe, xDest, yDest + y); + for (x = 0; x < w; ++x) { + if (state->clip->test(xDest + x, yDest + y)) { + src->getPixel(xSrc + x, ySrc + y, pixel); + (this->*pipe.run)(&pipe); + updateModX(xDest + x); + updateModY(yDest + y); + } else { + pipeIncX(&pipe); + } + } + } + } + } +} + +SplashError Splash::composite(SplashBitmap *src, int xSrc, int ySrc, + int xDest, int yDest, int w, int h, + GBool noClip, GBool nonIsolated, + GBool knockout, SplashCoord knockoutOpacity) { + SplashPipe pipe; + SplashColor pixel; + Guchar alpha; + Guchar *ap; + int x, y; + + if (src->mode != bitmap->mode) { + return splashErrModeMismatch; + } + + if (unlikely(!bitmap->data)) { + return splashErrZeroImage; + } + + if(src->getSeparationList()->getLength() > bitmap->getSeparationList()->getLength()) { + for (x = bitmap->getSeparationList()->getLength(); x < src->getSeparationList()->getLength(); x++) + bitmap->getSeparationList()->append(((GfxSeparationColorSpace *)src->getSeparationList()->get(x))->copy()); + } + if (src->alpha) { + pipeInit(&pipe, xDest, yDest, NULL, pixel, + (Guchar)splashRound(state->fillAlpha * 255), gTrue, nonIsolated, + knockout, (Guchar)splashRound(knockoutOpacity * 255)); + if (noClip) { + for (y = 0; y < h; ++y) { + pipeSetXY(&pipe, xDest, yDest + y); + ap = src->getAlphaPtr() + (ySrc + y) * src->getWidth() + xSrc; + for (x = 0; x < w; ++x) { + src->getPixel(xSrc + x, ySrc + y, pixel); + alpha = *ap++; + // this uses shape instead of alpha, which isn't technically + // correct, but works out the same + pipe.shape = alpha; + (this->*pipe.run)(&pipe); + } + } + updateModX(xDest); + updateModX(xDest + w - 1); + updateModY(yDest); + updateModY(yDest + h - 1); + } else { + for (y = 0; y < h; ++y) { + pipeSetXY(&pipe, xDest, yDest + y); + ap = src->getAlphaPtr() + (ySrc + y) * src->getWidth() + xSrc; + for (x = 0; x < w; ++x) { + src->getPixel(xSrc + x, ySrc + y, pixel); + alpha = *ap++; + if (state->clip->test(xDest + x, yDest + y)) { + // this uses shape instead of alpha, which isn't technically + // correct, but works out the same + pipe.shape = alpha; + (this->*pipe.run)(&pipe); + updateModX(xDest + x); + updateModY(yDest + y); + } else { + pipeIncX(&pipe); + } + } + } + } + } else { + pipeInit(&pipe, xDest, yDest, NULL, pixel, + (Guchar)splashRound(state->fillAlpha * 255), gFalse, nonIsolated); + if (noClip) { + for (y = 0; y < h; ++y) { + pipeSetXY(&pipe, xDest, yDest + y); + for (x = 0; x < w; ++x) { + src->getPixel(xSrc + x, ySrc + y, pixel); + (this->*pipe.run)(&pipe); + } + } + updateModX(xDest); + updateModX(xDest + w - 1); + updateModY(yDest); + updateModY(yDest + h - 1); + } else { + for (y = 0; y < h; ++y) { + pipeSetXY(&pipe, xDest, yDest + y); + for (x = 0; x < w; ++x) { + src->getPixel(xSrc + x, ySrc + y, pixel); + if (state->clip->test(xDest + x, yDest + y)) { + (this->*pipe.run)(&pipe); + updateModX(xDest + x); + updateModY(yDest + y); + } else { + pipeIncX(&pipe); + } + } + } + } + } + + return splashOk; +} + +void Splash::compositeBackground(SplashColorPtr color) { + SplashColorPtr p; + Guchar *q; + Guchar alpha, alpha1, c, color0, color1, color2; +#if SPLASH_CMYK + Guchar color3; + Guchar colorsp[SPOT_NCOMPS+4], cp; +#endif + int x, y, mask; + + if (unlikely(bitmap->alpha == NULL)) { + error(errInternal, -1, "bitmap->alpha is NULL in Splash::compositeBackground"); + return; + } + + switch (bitmap->mode) { + case splashModeMono1: + color0 = color[0]; + for (y = 0; y < bitmap->height; ++y) { + p = &bitmap->data[y * bitmap->rowSize]; + q = &bitmap->alpha[y * bitmap->width]; + mask = 0x80; + for (x = 0; x < bitmap->width; ++x) { + alpha = *q++; + alpha1 = 255 - alpha; + c = (*p & mask) ? 0xff : 0x00; + c = div255(alpha1 * color0 + alpha * c); + if (c & 0x80) { + *p |= mask; + } else { + *p &= ~mask; + } + if (!(mask >>= 1)) { + mask = 0x80; + ++p; + } + } + } + break; + case splashModeMono8: + color0 = color[0]; + for (y = 0; y < bitmap->height; ++y) { + p = &bitmap->data[y * bitmap->rowSize]; + q = &bitmap->alpha[y * bitmap->width]; + for (x = 0; x < bitmap->width; ++x) { + alpha = *q++; + alpha1 = 255 - alpha; + p[0] = div255(alpha1 * color0 + alpha * p[0]); + ++p; + } + } + break; + case splashModeRGB8: + case splashModeBGR8: + color0 = color[0]; + color1 = color[1]; + color2 = color[2]; + for (y = 0; y < bitmap->height; ++y) { + p = &bitmap->data[y * bitmap->rowSize]; + q = &bitmap->alpha[y * bitmap->width]; + for (x = 0; x < bitmap->width; ++x) { + alpha = *q++; + 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; + } + } + break; + case splashModeXBGR8: + color0 = color[0]; + color1 = color[1]; + color2 = color[2]; + for (y = 0; y < bitmap->height; ++y) { + p = &bitmap->data[y * bitmap->rowSize]; + q = &bitmap->alpha[y * bitmap->width]; + for (x = 0; x < bitmap->width; ++x) { + alpha = *q++; + 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] = 255; + p += 4; + } + } + break; +#if SPLASH_CMYK + case splashModeCMYK8: + color0 = color[0]; + color1 = color[1]; + color2 = color[2]; + color3 = color[3]; + for (y = 0; y < bitmap->height; ++y) { + p = &bitmap->data[y * bitmap->rowSize]; + q = &bitmap->alpha[y * bitmap->width]; + for (x = 0; x < bitmap->width; ++x) { + alpha = *q++; + 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; + } + } + break; + case splashModeDeviceN8: + for (cp = 0; cp < SPOT_NCOMPS+4; cp++) + colorsp[cp] = color[cp]; + for (y = 0; y < bitmap->height; ++y) { + p = &bitmap->data[y * bitmap->rowSize]; + q = &bitmap->alpha[y * bitmap->width]; + for (x = 0; x < bitmap->width; ++x) { + alpha = *q++; + if (alpha == 0) + { + for (cp = 0; cp < SPOT_NCOMPS+4; cp++) + p[cp] = colorsp[cp]; + } + else if (alpha != 255) + { + alpha1 = 255 - alpha; + for (cp = 0; cp < SPOT_NCOMPS+4; cp++) + p[cp] = div255(alpha1 * colorsp[cp] + alpha * p[cp]); + } + p += (SPOT_NCOMPS+4); + } + } + break; +#endif + } + memset(bitmap->alpha, 255, bitmap->width * bitmap->height); +} + +GBool Splash::gouraudTriangleShadedFill(SplashGouraudColor *shading) +{ + double xdbl[3] = {0., 0., 0.}; + double ydbl[3] = {0., 0., 0.}; + int x[3] = {0, 0, 0}; + int y[3] = {0, 0, 0}; + double xt=0., xa=0., yt=0.; + double ca=0., ct=0.; + + // triangle interpolation: + // + double scanLimitMapL[2] = {0., 0.}; + double scanLimitMapR[2] = {0., 0.}; + double scanColorMapL[2] = {0., 0.}; + double scanColorMapR[2] = {0., 0.}; + double scanColorMap[2] = {0., 0.}; + int scanEdgeL[2] = { 0, 0 }; + int scanEdgeR[2] = { 0, 0 }; + GBool hasFurtherSegment = gFalse; + + int scanLineOff = 0; + int bitmapOff = 0; + int scanLimitR = 0, scanLimitL = 0; + + int bitmapWidth = bitmap->getWidth(); + SplashClip* clip = getClip(); + SplashBitmap *blitTarget = bitmap; + SplashColorPtr bitmapData = bitmap->getDataPtr(); + int bitmapOffLimit = bitmap->getHeight() * bitmap->getRowSize(); + SplashColorPtr bitmapAlpha = bitmap->getAlphaPtr(); + SplashColorPtr cur = NULL; + SplashCoord* userToCanvasMatrix = getMatrix(); + SplashColorMode bitmapMode = bitmap->getMode(); + GBool hasAlpha = (bitmapAlpha != NULL); + int rowSize = bitmap->getRowSize(); + int colorComps = 0; + switch (bitmapMode) { + case splashModeMono1: + break; + case splashModeMono8: + colorComps=1; + break; + case splashModeRGB8: + colorComps=3; + break; + case splashModeBGR8: + colorComps=3; + break; + case splashModeXBGR8: + colorComps=4; + break; +#if SPLASH_CMYK + case splashModeCMYK8: + colorComps=4; + break; + case splashModeDeviceN8: + colorComps=SPOT_NCOMPS+4; + break; +#endif + } + + SplashPipe pipe; + SplashColor cSrcVal; + + pipeInit(&pipe, 0, 0, NULL, cSrcVal, (Guchar)splashRound(state->strokeAlpha * 255), gFalse, gFalse); + + if (vectorAntialias) { + if (aaBuf == NULL) + return gFalse; // fall back to old behaviour + drawAAPixelInit(); + } + + // idea: + // 1. If pipe->noTransparency && !state->blendFunc + // -> blit directly into the drawing surface! + // -> disable alpha manually. + // 2. Otherwise: + // - blit also directly, but into an intermediate surface. + // Afterwards, blit the intermediate surface using the drawing pipeline. + // This is necessary because triangle elements can be on top of each + // other, so the complete shading needs to be drawn before opacity is + // applied. + // - the final step, is performed using a SplashPipe: + // - assign the actual color into cSrcVal: pipe uses cSrcVal by reference + // - invoke drawPixel(&pipe,X,Y,bNoClip); + GBool bDirectBlit = vectorAntialias ? gFalse : pipe.noTransparency && !state->blendFunc; + if (!bDirectBlit) { + blitTarget = new SplashBitmap(bitmap->getWidth(), + bitmap->getHeight(), + bitmap->getRowPad(), + bitmap->getMode(), + gTrue, + bitmap->getRowSize() >= 0); + bitmapData = blitTarget->getDataPtr(); + bitmapAlpha = blitTarget->getAlphaPtr(); + + // initialisation seems to be necessary: + int S = bitmap->getWidth() * bitmap->getHeight(); + for (int i = 0; i < S; ++i) + bitmapAlpha[i] = 0; + hasAlpha = gTrue; + } + + if (shading->isParameterized()) { + double color[3]; + double colorinterp; + + for (int i = 0; i < shading->getNTriangles(); ++i) { + shading->getTriangle(i, + xdbl + 0, ydbl + 0, color + 0, + xdbl + 1, ydbl + 1, color + 1, + xdbl + 2, ydbl + 2, color + 2); + for (int m = 0; m < 3; ++m) { + xt = xdbl[m] * (double)userToCanvasMatrix[0] + ydbl[m] * (double)userToCanvasMatrix[2] + (double)userToCanvasMatrix[4]; + yt = xdbl[m] * (double)userToCanvasMatrix[1] + ydbl[m] * (double)userToCanvasMatrix[3] + (double)userToCanvasMatrix[5]; + xdbl[m] = xt; + ydbl[m] = yt; + // we operate on scanlines which are integer offsets into the + // raster image. The double offsets are of no use here. + x[m] = splashRound(xt); + y[m] = splashRound(yt); + } + // sort according to y coordinate to simplify sweep through scanlines: + // INSERTION SORT. + if (y[0] > y[1]) { + Guswap(x[0], x[1]); + Guswap(y[0], y[1]); + Guswap(color[0], color[1]); + } + // first two are sorted. + assert(y[0] <= y[1]); + if (y[1] > y[2]) { + int tmpX = x[2]; + int tmpY = y[2]; + double tmpC = color[2]; + x[2] = x[1]; y[2] = y[1]; color[2] = color[1]; + + if (y[0] > tmpY) { + x[1] = x[0]; y[1] = y[0]; color[1] = color[0]; + x[0] = tmpX; y[0] = tmpY; color[0] = tmpC; + } else { + x[1] = tmpX; y[1] = tmpY; color[1] = tmpC; + } + } + // first three are sorted + assert(y[0] <= y[1]); + assert(y[1] <= y[2]); + ///// + + // this here is det( T ) == 0 + // where T is the matrix to map to barycentric coordinates. + if ((x[0] - x[2]) * (y[1] - y[2]) - (x[1] - x[2]) * (y[0] - y[2]) == 0) + continue; // degenerate triangle. + + // this here initialises the scanline generation. + // We start with low Y coordinates and sweep up to the large Y + // coordinates. + // + // scanEdgeL[m] in {0,1,2} m=0,1 + // scanEdgeR[m] in {0,1,2} m=0,1 + // + // are the two edges between which scanlines are (currently) + // sweeped. The values {0,1,2} are indices into 'x' and 'y'. + // scanEdgeL[0] = 0 means: the left scan edge has (x[0],y[0]) as vertex. + // + scanEdgeL[0] = 0; + scanEdgeR[0] = 0; + if (y[0] == y[1]) { + scanEdgeL[0] = 1; + scanEdgeL[1] = scanEdgeR[1] = 2; + + } else { + scanEdgeL[1] = 1; scanEdgeR[1] = 2; + } + assert(y[scanEdgeL[0]] < y[scanEdgeL[1]]); + assert(y[scanEdgeR[0]] < y[scanEdgeR[1]]); + + // Ok. Now prepare the linear maps which map the y coordinate of + // the current scanline to the corresponding LEFT and RIGHT x + // coordinate (which define the scanline). + scanLimitMapL[0] = double(x[scanEdgeL[1]] - x[scanEdgeL[0]]) / (y[scanEdgeL[1]] - y[scanEdgeL[0]]); + scanLimitMapL[1] = x[scanEdgeL[0]] - y[scanEdgeL[0]] * scanLimitMapL[0]; + scanLimitMapR[0] = double(x[scanEdgeR[1]] - x[scanEdgeR[0]]) / (y[scanEdgeR[1]] - y[scanEdgeR[0]]); + scanLimitMapR[1] = x[scanEdgeR[0]] - y[scanEdgeR[0]] * scanLimitMapR[0]; + + xa = y[1] * scanLimitMapL[0] + scanLimitMapL[1]; + xt = y[1] * scanLimitMapR[0] + scanLimitMapR[1]; + if (xa > xt) { + // I have "left" is to the right of "right". + // Exchange sides! + Guswap(scanEdgeL[0], scanEdgeR[0]); + Guswap(scanEdgeL[1], scanEdgeR[1]); + Guswap(scanLimitMapL[0], scanLimitMapR[0]); + Guswap(scanLimitMapL[1], scanLimitMapR[1]); + // FIXME I'm sure there is a more efficient way to check this. + } + + // Same game: we can linearly interpolate the color based on the + // current y coordinate (that's correct for triangle + // interpolation due to linearity. We could also have done it in + // barycentric coordinates, but that's slightly more involved) + scanColorMapL[0] = (color[scanEdgeL[1]] - color[scanEdgeL[0]]) / (y[scanEdgeL[1]] - y[scanEdgeL[0]]); + scanColorMapL[1] = color[scanEdgeL[0]] - y[scanEdgeL[0]] * scanColorMapL[0]; + scanColorMapR[0] = (color[scanEdgeR[1]] - color[scanEdgeR[0]]) / (y[scanEdgeR[1]] - y[scanEdgeR[0]]); + scanColorMapR[1] = color[scanEdgeR[0]] - y[scanEdgeR[0]] * scanColorMapR[0]; + + hasFurtherSegment = (y[1] < y[2]); + scanLineOff = y[0] * rowSize; + + for (int Y = y[0]; Y <= y[2]; ++Y, scanLineOff += rowSize) { + if (hasFurtherSegment && Y == y[1]) { + // SWEEP EVENT: we encountered the next segment. + // + // switch to next segment, either at left end or at right + // end: + if (scanEdgeL[1] == 1) { + scanEdgeL[0] = 1; + scanEdgeL[1] = 2; + scanLimitMapL[0] = double(x[scanEdgeL[1]] - x[scanEdgeL[0]]) / (y[scanEdgeL[1]] - y[scanEdgeL[0]]); + scanLimitMapL[1] = x[scanEdgeL[0]] - y[scanEdgeL[0]] * scanLimitMapL[0]; + + scanColorMapL[0] = (color[scanEdgeL[1]] - color[scanEdgeL[0]]) / (y[scanEdgeL[1]] - y[scanEdgeL[0]]); + scanColorMapL[1] = color[scanEdgeL[0]] - y[scanEdgeL[0]] * scanColorMapL[0]; + } else if (scanEdgeR[1] == 1) { + scanEdgeR[0] = 1; + scanEdgeR[1] = 2; + scanLimitMapR[0] = double(x[scanEdgeR[1]] - x[scanEdgeR[0]]) / (y[scanEdgeR[1]] - y[scanEdgeR[0]]); + scanLimitMapR[1] = x[scanEdgeR[0]] - y[scanEdgeR[0]] * scanLimitMapR[0]; + + scanColorMapR[0] = (color[scanEdgeR[1]] - color[scanEdgeR[0]]) / (y[scanEdgeR[1]] - y[scanEdgeR[0]]); + scanColorMapR[1] = color[scanEdgeR[0]] - y[scanEdgeR[0]] * scanColorMapR[0]; + } + assert( y[scanEdgeL[0]] < y[scanEdgeL[1]] ); + assert( y[scanEdgeR[0]] < y[scanEdgeR[1]] ); + hasFurtherSegment = gFalse; + } + + yt = Y; + + xa = yt * scanLimitMapL[0] + scanLimitMapL[1]; + xt = yt * scanLimitMapR[0] + scanLimitMapR[1]; + + ca = yt * scanColorMapL[0] + scanColorMapL[1]; + ct = yt * scanColorMapR[0] + scanColorMapR[1]; + + scanLimitL = splashRound(xa); + scanLimitR = splashRound(xt); + + // Ok. Now: init the color interpolation depending on the X + // coordinate inside of the current scanline: + scanColorMap[0] = (scanLimitR == scanLimitL) ? 0. : ((ct - ca) / (scanLimitR - scanLimitL)); + scanColorMap[1] = ca - scanLimitL * scanColorMap[0]; + + // handled by clipping: + // assert( scanLimitL >= 0 && scanLimitR < bitmap->getWidth() ); + assert(scanLimitL <= scanLimitR || abs(scanLimitL - scanLimitR) <= 2); // allow rounding inaccuracies + assert(scanLineOff == Y * rowSize); + + colorinterp = scanColorMap[0] * scanLimitL + scanColorMap[1]; + + bitmapOff = scanLineOff + scanLimitL * colorComps; + for (int X = scanLimitL; X <= scanLimitR && bitmapOff + colorComps <= bitmapOffLimit; ++X, colorinterp += scanColorMap[0], bitmapOff += colorComps) { + // FIXME : standard rectangular clipping can be done for a + // complete scanline which is faster + // --> see SplashClip and its methods + if (!clip->test(X, Y)) + continue; + + assert(fabs(colorinterp - (scanColorMap[0] * X + scanColorMap[1])) < 1e-10); + assert(bitmapOff == Y * rowSize + colorComps * X && scanLineOff == Y * rowSize); + + shading->getParameterizedColor(colorinterp, bitmapMode, &bitmapData[bitmapOff]); + + // make the shading visible. + // Note that opacity is handled by the bDirectBlit stuff, see + // above for comments and below for implementation. + if (hasAlpha) + bitmapAlpha[Y * bitmapWidth + X] = 255; + } + } + } + } else { + return gFalse; + } + + if (!bDirectBlit) { + // ok. Finalize the stuff by blitting the shading into the final + // geometry, this time respecting the rendering pipe. + int W = blitTarget->getWidth(); + int H = blitTarget->getHeight(); + cur = cSrcVal; + + for (int X = 0; X < W; ++X) { + for (int Y = 0; Y < H; ++Y) { + if (!bitmapAlpha[Y * bitmapWidth + X]) + continue; // draw only parts of the shading! + bitmapOff = Y * rowSize + colorComps * X; + + for (int m = 0; m < colorComps; ++m) + cur[m] = bitmapData[bitmapOff + m]; + if (vectorAntialias) { + drawAAPixel(&pipe, X, Y); + } else { + drawPixel(&pipe, X, Y, gTrue); // no clipping - has already been done. + } + } + } + + delete blitTarget; + blitTarget = NULL; + } + + return gTrue; +} + +SplashError Splash::blitTransparent(SplashBitmap *src, int xSrc, int ySrc, + int xDest, int yDest, int w, int h) { + SplashColorPtr p, sp; + Guchar *q; + int x, y, mask, srcMask; + + if (src->mode != bitmap->mode) { + return splashErrModeMismatch; + } + + if (unlikely(!bitmap->data)) { + return splashErrZeroImage; + } + + switch (bitmap->mode) { + case splashModeMono1: + for (y = 0; y < h; ++y) { + p = &bitmap->data[(yDest + y) * bitmap->rowSize + (xDest >> 3)]; + mask = 0x80 >> (xDest & 7); + sp = &src->data[(ySrc + y) * src->rowSize + (xSrc >> 3)]; + srcMask = 0x80 >> (xSrc & 7); + for (x = 0; x < w; ++x) { + if (*sp & srcMask) { + *p |= mask; + } else { + *p &= ~mask; + } + if (!(mask >>= 1)) { + mask = 0x80; + ++p; + } + if (!(srcMask >>= 1)) { + srcMask = 0x80; + ++sp; + } + } + } + break; + case splashModeMono8: + for (y = 0; y < h; ++y) { + p = &bitmap->data[(yDest + y) * bitmap->rowSize + xDest]; + sp = &src->data[(ySrc + y) * bitmap->rowSize + xSrc]; + for (x = 0; x < w; ++x) { + *p++ = *sp++; + } + } + break; + case splashModeRGB8: + case splashModeBGR8: + for (y = 0; y < h; ++y) { + p = &bitmap->data[(yDest + y) * bitmap->rowSize + 3 * xDest]; + sp = &src->data[(ySrc + y) * src->rowSize + 3 * xSrc]; + for (x = 0; x < w; ++x) { + *p++ = *sp++; + *p++ = *sp++; + *p++ = *sp++; + } + } + break; + case splashModeXBGR8: + for (y = 0; y < h; ++y) { + p = &bitmap->data[(yDest + y) * bitmap->rowSize + 4 * xDest]; + sp = &src->data[(ySrc + y) * src->rowSize + 4 * xSrc]; + for (x = 0; x < w; ++x) { + *p++ = *sp++; + *p++ = *sp++; + *p++ = *sp++; + *p++ = 255; + sp++; + } + } + break; +#if SPLASH_CMYK + case splashModeCMYK8: + for (y = 0; y < h; ++y) { + p = &bitmap->data[(yDest + y) * bitmap->rowSize + 4 * xDest]; + sp = &src->data[(ySrc + y) * src->rowSize + 4 * xSrc]; + for (x = 0; x < w; ++x) { + *p++ = *sp++; + *p++ = *sp++; + *p++ = *sp++; + *p++ = *sp++; + } + } + break; + case splashModeDeviceN8: + for (y = 0; y < h; ++y) { + p = &bitmap->data[(yDest + y) * bitmap->rowSize + (SPOT_NCOMPS+4) * xDest]; + sp = &src->data[(ySrc + y) * src->rowSize + (SPOT_NCOMPS+4) * xSrc]; + for (x = 0; x < w; ++x) { + for (int cp=0; cp < SPOT_NCOMPS+4; cp++) + *p++ = *sp++; + } + } + break; +#endif + } + + if (bitmap->alpha) { + for (y = 0; y < h; ++y) { + q = &bitmap->alpha[(yDest + y) * bitmap->width + xDest]; + memset(q, 0x00, w); + } + } + + return splashOk; +} + +SplashPath *Splash::makeStrokePath(SplashPath *path, SplashCoord w, + GBool flatten) { +SplashPath *pathIn, *dashPath, *pathOut; + SplashCoord d, dx, dy, wdx, wdy, dxNext, dyNext, wdxNext, wdyNext; + SplashCoord crossprod, dotprod, miter, m; + GBool first, last, closed; + int subpathStart0, subpathStart1, seg, i0, i1, j0, j1, k0, k1; + int left0, left1, left2, right0, right1, right2, join0, join1, join2; + int leftFirst, rightFirst, firstPt; + + pathOut = new SplashPath(); + + if (path->length == 0) { + return pathOut; + } + + if (flatten) { + pathIn = flattenPath(path, state->matrix, state->flatness); + if (state->lineDashLength > 0) { + dashPath = makeDashedPath(pathIn); + delete pathIn; + pathIn = dashPath; + if (pathIn->length == 0) { + delete pathIn; + return pathOut; + } + } + } else { + pathIn = path; + } + + subpathStart0 = subpathStart1 = 0; // make gcc happy + seg = 0; // make gcc happy + closed = gFalse; // make gcc happy + left0 = left1 = right0 = right1 = join0 = join1 = 0; // make gcc happy + leftFirst = rightFirst = firstPt = 0; // make gcc happy + + i0 = 0; + for (i1 = i0; + !(pathIn->flags[i1] & splashPathLast) && + i1 + 1 < pathIn->length && + pathIn->pts[i1+1].x == pathIn->pts[i1].x && + pathIn->pts[i1+1].y == pathIn->pts[i1].y; + ++i1) ; + + while (i1 < pathIn->length) { + if ((first = pathIn->flags[i0] & splashPathFirst)) { + subpathStart0 = i0; + subpathStart1 = i1; + seg = 0; + closed = pathIn->flags[i0] & splashPathClosed; + } + j0 = i1 + 1; + if (j0 < pathIn->length) { + for (j1 = j0; + !(pathIn->flags[j1] & splashPathLast) && + j1 + 1 < pathIn->length && + pathIn->pts[j1+1].x == pathIn->pts[j1].x && + pathIn->pts[j1+1].y == pathIn->pts[j1].y; + ++j1) ; + } else { + j1 = j0; + } + if (pathIn->flags[i1] & splashPathLast) { + if (first && state->lineCap == splashLineCapRound) { + // special case: zero-length subpath with round line caps --> + // draw a circle + pathOut->moveTo(pathIn->pts[i0].x + (SplashCoord)0.5 * w, + pathIn->pts[i0].y); + pathOut->curveTo(pathIn->pts[i0].x + (SplashCoord)0.5 * w, + pathIn->pts[i0].y + bezierCircle2 * w, + pathIn->pts[i0].x + bezierCircle2 * w, + pathIn->pts[i0].y + (SplashCoord)0.5 * w, + pathIn->pts[i0].x, + pathIn->pts[i0].y + (SplashCoord)0.5 * w); + pathOut->curveTo(pathIn->pts[i0].x - bezierCircle2 * w, + pathIn->pts[i0].y + (SplashCoord)0.5 * w, + pathIn->pts[i0].x - (SplashCoord)0.5 * w, + pathIn->pts[i0].y + bezierCircle2 * w, + pathIn->pts[i0].x - (SplashCoord)0.5 * w, + pathIn->pts[i0].y); + pathOut->curveTo(pathIn->pts[i0].x - (SplashCoord)0.5 * w, + pathIn->pts[i0].y - bezierCircle2 * w, + pathIn->pts[i0].x - bezierCircle2 * w, + pathIn->pts[i0].y - (SplashCoord)0.5 * w, + pathIn->pts[i0].x, + pathIn->pts[i0].y - (SplashCoord)0.5 * w); + pathOut->curveTo(pathIn->pts[i0].x + bezierCircle2 * w, + pathIn->pts[i0].y - (SplashCoord)0.5 * w, + pathIn->pts[i0].x + (SplashCoord)0.5 * w, + pathIn->pts[i0].y - bezierCircle2 * w, + pathIn->pts[i0].x + (SplashCoord)0.5 * w, + pathIn->pts[i0].y); + pathOut->close(); + } + i0 = j0; + i1 = j1; + continue; + } + last = pathIn->flags[j1] & splashPathLast; + if (last) { + k0 = subpathStart1 + 1; + } else { + k0 = j1 + 1; + } + for (k1 = k0; + !(pathIn->flags[k1] & splashPathLast) && + k1 + 1 < pathIn->length && + pathIn->pts[k1+1].x == pathIn->pts[k1].x && + pathIn->pts[k1+1].y == pathIn->pts[k1].y; + ++k1) ; + + // compute the deltas for segment (i1, j0) +#if USE_FIXEDPOINT + // the 1/d value can be small, which introduces significant + // inaccuracies in fixed point mode + d = splashDist(pathIn->pts[i1].x, pathIn->pts[i1].y, + pathIn->pts[j0].x, pathIn->pts[j0].y); + dx = (pathIn->pts[j0].x - pathIn->pts[i1].x) / d; + dy = (pathIn->pts[j0].y - pathIn->pts[i1].y) / d; +#else + d = (SplashCoord)1 / splashDist(pathIn->pts[i1].x, pathIn->pts[i1].y, + pathIn->pts[j0].x, pathIn->pts[j0].y); + dx = d * (pathIn->pts[j0].x - pathIn->pts[i1].x); + dy = d * (pathIn->pts[j0].y - pathIn->pts[i1].y); +#endif + wdx = (SplashCoord)0.5 * w * dx; + wdy = (SplashCoord)0.5 * w * dy; + + // draw the start cap + pathOut->moveTo(pathIn->pts[i0].x - wdy, pathIn->pts[i0].y + wdx); + if (i0 == subpathStart0) { + firstPt = pathOut->length - 1; + } + if (first && !closed) { + switch (state->lineCap) { + case splashLineCapButt: + pathOut->lineTo(pathIn->pts[i0].x + wdy, pathIn->pts[i0].y - wdx); + break; + case splashLineCapRound: + pathOut->curveTo(pathIn->pts[i0].x - wdy - bezierCircle * wdx, + pathIn->pts[i0].y + wdx - bezierCircle * wdy, + pathIn->pts[i0].x - wdx - bezierCircle * wdy, + pathIn->pts[i0].y - wdy + bezierCircle * wdx, + pathIn->pts[i0].x - wdx, + pathIn->pts[i0].y - wdy); + pathOut->curveTo(pathIn->pts[i0].x - wdx + bezierCircle * wdy, + pathIn->pts[i0].y - wdy - bezierCircle * wdx, + pathIn->pts[i0].x + wdy - bezierCircle * wdx, + pathIn->pts[i0].y - wdx - bezierCircle * wdy, + pathIn->pts[i0].x + wdy, + pathIn->pts[i0].y - wdx); + break; + case splashLineCapProjecting: + pathOut->lineTo(pathIn->pts[i0].x - wdx - wdy, + pathIn->pts[i0].y + wdx - wdy); + pathOut->lineTo(pathIn->pts[i0].x - wdx + wdy, + pathIn->pts[i0].y - wdx - wdy); + pathOut->lineTo(pathIn->pts[i0].x + wdy, + pathIn->pts[i0].y - wdx); + break; + } + } else { + pathOut->lineTo(pathIn->pts[i0].x + wdy, pathIn->pts[i0].y - wdx); + } + + // draw the left side of the segment rectangle + 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) { + case splashLineCapButt: + pathOut->lineTo(pathIn->pts[j0].x - wdy, pathIn->pts[j0].y + wdx); + break; + case splashLineCapRound: + pathOut->curveTo(pathIn->pts[j0].x + wdy + bezierCircle * wdx, + pathIn->pts[j0].y - wdx + bezierCircle * wdy, + pathIn->pts[j0].x + wdx + bezierCircle * wdy, + pathIn->pts[j0].y + wdy - bezierCircle * wdx, + pathIn->pts[j0].x + wdx, + pathIn->pts[j0].y + wdy); + pathOut->curveTo(pathIn->pts[j0].x + wdx - bezierCircle * wdy, + pathIn->pts[j0].y + wdy + bezierCircle * wdx, + pathIn->pts[j0].x - wdy + bezierCircle * wdx, + pathIn->pts[j0].y + wdx + bezierCircle * wdy, + pathIn->pts[j0].x - wdy, + pathIn->pts[j0].y + wdx); + break; + case splashLineCapProjecting: + pathOut->lineTo(pathIn->pts[j0].x + wdy + wdx, + pathIn->pts[j0].y - wdx + wdy); + pathOut->lineTo(pathIn->pts[j0].x - wdy + wdx, + pathIn->pts[j0].y + wdx + wdy); + pathOut->lineTo(pathIn->pts[j0].x - wdy, + pathIn->pts[j0].y + wdx); + break; + } + } else { + pathOut->lineTo(pathIn->pts[j0].x - wdy, pathIn->pts[j0].y + wdx); + } + + // draw the right side of the segment rectangle + // (NB: if stroke adjustment is enabled, the closepath operation MUST + // add a segment because this segment is used for a hint) + right2 = pathOut->length - 1; + pathOut->close(state->strokeAdjust); + + // draw the join + join2 = pathOut->length; + if (!last || closed) { + + // compute the deltas for segment (j1, k0) +#if USE_FIXEDPOINT + // the 1/d value can be small, which introduces significant + // inaccuracies in fixed point mode + d = splashDist(pathIn->pts[j1].x, pathIn->pts[j1].y, + pathIn->pts[k0].x, pathIn->pts[k0].y); + dxNext = (pathIn->pts[k0].x - pathIn->pts[j1].x) / d; + dyNext = (pathIn->pts[k0].y - pathIn->pts[j1].y) / d; +#else + d = (SplashCoord)1 / splashDist(pathIn->pts[j1].x, pathIn->pts[j1].y, + pathIn->pts[k0].x, pathIn->pts[k0].y); + dxNext = d * (pathIn->pts[k0].x - pathIn->pts[j1].x); + dyNext = d * (pathIn->pts[k0].y - pathIn->pts[j1].y); +#endif + wdxNext = (SplashCoord)0.5 * w * dxNext; + wdyNext = (SplashCoord)0.5 * w * dyNext; + + // compute the join parameters + crossprod = dx * dyNext - dy * dxNext; + dotprod = -(dx * dxNext + dy * dyNext); + if (dotprod > 0.9999) { + // avoid a divide-by-zero -- set miter to something arbitrary + // such that sqrt(miter) will exceed miterLimit (and m is never + // used in that situation) + // (note: the comparison value (0.9999) has to be less than + // 1-epsilon, where epsilon is the smallest value + // representable in the fixed point format) + miter = (state->miterLimit + 1) * (state->miterLimit + 1); + m = 0; + } else { + miter = (SplashCoord)2 / ((SplashCoord)1 - dotprod); + if (miter < 1) { + // this can happen because of floating point inaccuracies + miter = 1; + } + m = splashSqrt(miter - 1); + } + + // round join + if (state->lineJoin == splashLineJoinRound) { + pathOut->moveTo(pathIn->pts[j0].x + (SplashCoord)0.5 * w, + pathIn->pts[j0].y); + pathOut->curveTo(pathIn->pts[j0].x + (SplashCoord)0.5 * w, + pathIn->pts[j0].y + bezierCircle2 * w, + pathIn->pts[j0].x + bezierCircle2 * w, + pathIn->pts[j0].y + (SplashCoord)0.5 * w, + pathIn->pts[j0].x, + pathIn->pts[j0].y + (SplashCoord)0.5 * w); + pathOut->curveTo(pathIn->pts[j0].x - bezierCircle2 * w, + pathIn->pts[j0].y + (SplashCoord)0.5 * w, + pathIn->pts[j0].x - (SplashCoord)0.5 * w, + pathIn->pts[j0].y + bezierCircle2 * w, + pathIn->pts[j0].x - (SplashCoord)0.5 * w, + pathIn->pts[j0].y); + pathOut->curveTo(pathIn->pts[j0].x - (SplashCoord)0.5 * w, + pathIn->pts[j0].y - bezierCircle2 * w, + pathIn->pts[j0].x - bezierCircle2 * w, + pathIn->pts[j0].y - (SplashCoord)0.5 * w, + pathIn->pts[j0].x, + pathIn->pts[j0].y - (SplashCoord)0.5 * w); + pathOut->curveTo(pathIn->pts[j0].x + bezierCircle2 * w, + pathIn->pts[j0].y - (SplashCoord)0.5 * w, + pathIn->pts[j0].x + (SplashCoord)0.5 * w, + pathIn->pts[j0].y - bezierCircle2 * w, + pathIn->pts[j0].x + (SplashCoord)0.5 * w, + pathIn->pts[j0].y); + + } else { + pathOut->moveTo(pathIn->pts[j0].x, pathIn->pts[j0].y); + + // 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 && + splashSqrt(miter) <= state->miterLimit) { + pathOut->lineTo(pathIn->pts[j0].x - wdy + wdx * m, + pathIn->pts[j0].y + wdx + wdy * m); + pathOut->lineTo(pathIn->pts[j0].x - wdy, + pathIn->pts[j0].y + wdx); + // bevel join or miter join outside limit + } else { + pathOut->lineTo(pathIn->pts[j0].x - wdy, + pathIn->pts[j0].y + wdx); + } + + // angle >= 180 + } else { + pathOut->lineTo(pathIn->pts[j0].x + wdy, + pathIn->pts[j0].y - wdx); + // miter join inside limit + if (state->lineJoin == splashLineJoinMiter && + splashSqrt(miter) <= state->miterLimit) { + pathOut->lineTo(pathIn->pts[j0].x + wdy + wdx * m, + pathIn->pts[j0].y - wdx + wdy * m); + pathOut->lineTo(pathIn->pts[j0].x + wdyNext, + pathIn->pts[j0].y - wdxNext); + // bevel join or miter join outside limit + } else { + pathOut->lineTo(pathIn->pts[j0].x + wdyNext, + pathIn->pts[j0].y - wdxNext); + } + } + } + + pathOut->close(); + } + + // add stroke adjustment hints + if (state->strokeAdjust) { + if (seg == 0 && !closed) { + if (state->lineCap == splashLineCapButt) { + pathOut->addStrokeAdjustHint(firstPt, left2 + 1, + firstPt, firstPt + 1); + if (last) { + pathOut->addStrokeAdjustHint(firstPt, left2 + 1, + left2 + 1, left2 + 2); + } + } else if (state->lineCap == splashLineCapProjecting) { + if (last) { + pathOut->addStrokeAdjustHint(firstPt + 1, left2 + 2, + firstPt + 1, firstPt + 2); + pathOut->addStrokeAdjustHint(firstPt + 1, left2 + 2, + left2 + 2, left2 + 3); + } else { + pathOut->addStrokeAdjustHint(firstPt + 1, left2 + 1, + firstPt + 1, firstPt + 2); + } + } + } + if (seg >= 1) { + if (seg >= 2) { + pathOut->addStrokeAdjustHint(left1, right1, left0 + 1, right0); + pathOut->addStrokeAdjustHint(left1, right1, join0, left2); + } else { + pathOut->addStrokeAdjustHint(left1, right1, firstPt, left2); + } + pathOut->addStrokeAdjustHint(left1, right1, right2 + 1, right2 + 1); + } + left0 = left1; + left1 = left2; + right0 = right1; + right1 = right2; + join0 = join1; + join1 = join2; + if (seg == 0) { + 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; + i1 = j1; + ++seg; + } + + if (pathIn != path) { + delete pathIn; + } + + return pathOut; +} + +void Splash::dumpPath(SplashPath *path) { + int i; + + for (i = 0; i < path->length; ++i) { + printf(" %3d: x=%8.2f y=%8.2f%s%s%s%s\n", + i, (double)path->pts[i].x, (double)path->pts[i].y, + (path->flags[i] & splashPathFirst) ? " first" : "", + (path->flags[i] & splashPathLast) ? " last" : "", + (path->flags[i] & splashPathClosed) ? " closed" : "", + (path->flags[i] & splashPathCurve) ? " curve" : ""); + } +} + +void Splash::dumpXPath(SplashXPath *path) { + int i; + + for (i = 0; i < path->length; ++i) { + printf(" %4d: x0=%8.2f y0=%8.2f x1=%8.2f y1=%8.2f %s%s%s\n", + i, (double)path->segs[i].x0, (double)path->segs[i].y0, + (double)path->segs[i].x1, (double)path->segs[i].y1, + (path->segs[i].flags & splashXPathHoriz) ? "H" : " ", + (path->segs[i].flags & splashXPathVert) ? "V" : " ", + (path->segs[i].flags & splashXPathFlip) ? "P" : " "); + } +} + +SplashError Splash::shadedFill(SplashPath *path, GBool hasBBox, + SplashPattern *pattern) { + SplashPipe pipe; + SplashXPath *xPath; + SplashXPathScanner *scanner; + int xMinI, yMinI, xMaxI, yMaxI, x0, x1, y; + SplashClipResult clipRes; + + if (vectorAntialias && aaBuf == NULL) { // should not happen, but to be secure + return splashErrGeneric; + } + if (path->length == 0) { + return splashErrEmptyPath; + } + xPath = new SplashXPath(path, state->matrix, state->flatness, gTrue); + if (vectorAntialias) { + xPath->aaScale(); + } + xPath->sort(); + yMinI = state->clip->getYMinI(); + yMaxI = state->clip->getYMaxI(); + if (vectorAntialias && !inShading) { + yMinI = yMinI * splashAASize; + yMaxI = (yMaxI + 1) * splashAASize - 1; + } + scanner = new SplashXPathScanner(xPath, gFalse, yMinI, yMaxI); + + // get the min and max x and y values + if (vectorAntialias) { + scanner->getBBoxAA(&xMinI, &yMinI, &xMaxI, &yMaxI); + } else { + scanner->getBBox(&xMinI, &yMinI, &xMaxI, &yMaxI); + } + + // check clipping + if ((clipRes = state->clip->testRect(xMinI, yMinI, xMaxI, yMaxI)) != splashClipAllOutside) { + // limit the y range + if (yMinI < state->clip->getYMinI()) { + yMinI = state->clip->getYMinI(); + } + if (yMaxI > state->clip->getYMaxI()) { + yMaxI = state->clip->getYMaxI(); + } + + pipeInit(&pipe, 0, yMinI, pattern, NULL, (Guchar)splashRound(state->fillAlpha * 255), vectorAntialias && !hasBBox, gFalse); + + // draw the spans + if (vectorAntialias) { + for (y = yMinI; y <= yMaxI; ++y) { + scanner->renderAALine(aaBuf, &x0, &x1, y); + if (clipRes != splashClipAllInside) { + state->clip->clipAALine(aaBuf, &x0, &x1, y); + } +#if splashAASize == 4 + if (!hasBBox && y > yMinI && y < yMaxI) { + // correct shape on left side if clip is + // vertical through the middle of shading: + Guchar *p0, *p1, *p2, *p3; + Guchar c1, c2, c3, c4; + p0 = aaBuf->getDataPtr() + (x0 >> 1); + p1 = p0 + aaBuf->getRowSize(); + p2 = p1 + aaBuf->getRowSize(); + p3 = p2 + aaBuf->getRowSize(); + if (x0 & 1) { + c1 = (*p0 & 0x0f); c2 =(*p1 & 0x0f); c3 = (*p2 & 0x0f) ; c4 = (*p3 & 0x0f); + } else { + c1 = (*p0 >> 4); c2 = (*p1 >> 4); c3 = (*p2 >> 4); c4 = (*p3 >> 4); + } + if ( (c1 & 0x03) == 0x03 && (c2 & 0x03) == 0x03 && (c3 & 0x03) == 0x03 && (c4 & 0x03) == 0x03 + && c1 == c2 && c2 == c3 && c3 == c4 && + pattern->testPosition(x0 - 1, y) ) + { + Guchar shapeCorrection = (x0 & 1) ? 0x0f : 0xf0; + *p0 |= shapeCorrection; + *p1 |= shapeCorrection; + *p2 |= shapeCorrection; + *p3 |= shapeCorrection; + } + // correct shape on right side if clip is + // through the middle of shading: + p0 = aaBuf->getDataPtr() + (x1 >> 1); + p1 = p0 + aaBuf->getRowSize(); + p2 = p1 + aaBuf->getRowSize(); + p3 = p2 + aaBuf->getRowSize(); + if (x1 & 1) { + c1 = (*p0 & 0x0f); c2 =(*p1 & 0x0f); c3 = (*p2 & 0x0f) ; c4 = (*p3 & 0x0f); + } else { + c1 = (*p0 >> 4); c2 = (*p1 >> 4); c3 = (*p2 >> 4); c4 = (*p3 >> 4); + } + + if ( (c1 & 0xc) == 0x0c && (c2 & 0x0c) == 0x0c && (c3 & 0x0c) == 0x0c && (c4 & 0x0c) == 0x0c + && c1 == c2 && c2 == c3 && c3 == c4 && + pattern->testPosition(x1 + 1, y) ) + { + Guchar shapeCorrection = (x1 & 1) ? 0x0f : 0xf0; + *p0 |= shapeCorrection; + *p1 |= shapeCorrection; + *p2 |= shapeCorrection; + *p3 |= shapeCorrection; + } + } +#endif + drawAALine(&pipe, x0, x1, y); + } + } else { + SplashClipResult clipRes2; + for (y = yMinI; y <= yMaxI; ++y) { + while (scanner->getNextSpan(y, &x0, &x1)) { + if (clipRes == splashClipAllInside) { + drawSpan(&pipe, x0, x1, y, gTrue); + } else { + // limit the x range + if (x0 < state->clip->getXMinI()) { + x0 = state->clip->getXMinI(); + } + if (x1 > state->clip->getXMaxI()) { + x1 = state->clip->getXMaxI(); + } + clipRes2 = state->clip->testSpan(x0, x1, y); + drawSpan(&pipe, x0, x1, y, clipRes2 == splashClipAllInside); + } + } + } + } + } + opClipRes = clipRes; + + delete scanner; + delete xPath; + return splashOk; +} diff --git a/Build/source/libs/poppler/poppler-0.33.0/splash/Splash.h b/Build/source/libs/poppler/poppler-0.33.0/splash/Splash.h new file mode 100644 index 00000000000..cf98e6c6824 --- /dev/null +++ b/Build/source/libs/poppler/poppler-0.33.0/splash/Splash.h @@ -0,0 +1,426 @@ +//======================================================================== +// +// Splash.h +// +//======================================================================== + +//======================================================================== +// +// Modified under the Poppler project - http://poppler.freedesktop.org +// +// All changes made under the Poppler project to this file are licensed +// under GPL version 2 or later +// +// Copyright (C) 2005 Marco Pesenti Gritti <mpg@redhat.com> +// Copyright (C) 2007, 2011 Albert Astals Cid <aacid@kde.org> +// Copyright (C) 2010-2013 Thomas Freitag <Thomas.Freitag@alfa.de> +// Copyright (C) 2010 Christian Feuersänger <cfeuersaenger@googlemail.com> +// Copyright (C) 2012 Adrian Johnson <ajohnson@redneon.com> +// +// To see a description of the changes please see the Changelog file that +// came with your tarball or type make ChangeLog if you are building from git +// +//======================================================================== + +#ifndef SPLASH_H +#define SPLASH_H + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include <stddef.h> +#include "SplashTypes.h" +#include "SplashClip.h" +#include "SplashPattern.h" + +class SplashBitmap; +struct SplashGlyphBitmap; +class SplashState; +class SplashScreen; +class SplashPath; +class SplashXPath; +class SplashFont; +struct SplashPipe; + +//------------------------------------------------------------------------ + +// Retrieves the next line of pixels in an image mask. Normally, +// fills in *<line> and returns true. If the image stream is +// exhausted, returns false. +typedef GBool (*SplashImageMaskSource)(void *data, SplashColorPtr pixel); + +// Retrieves the next line of pixels in an image. Normally, fills in +// *<line> and returns true. If the image stream is exhausted, +// returns false. +typedef GBool (*SplashImageSource)(void *data, SplashColorPtr colorLine, + Guchar *alphaLine); + +//------------------------------------------------------------------------ + +enum SplashPipeResultColorCtrl { +#if SPLASH_CMYK + splashPipeResultColorNoAlphaBlendCMYK, + splashPipeResultColorNoAlphaBlendDeviceN, +#endif + splashPipeResultColorNoAlphaBlendRGB, + splashPipeResultColorNoAlphaBlendMono, + splashPipeResultColorAlphaNoBlendMono, + splashPipeResultColorAlphaNoBlendRGB, +#if SPLASH_CMYK + splashPipeResultColorAlphaNoBlendCMYK, + splashPipeResultColorAlphaNoBlendDeviceN, +#endif + splashPipeResultColorAlphaBlendMono, + splashPipeResultColorAlphaBlendRGB +#if SPLASH_CMYK + , + splashPipeResultColorAlphaBlendCMYK, + splashPipeResultColorAlphaBlendDeviceN +#endif +}; + +//------------------------------------------------------------------------ +// Splash +//------------------------------------------------------------------------ + +class Splash { +public: + + // Create a new rasterizer object. + Splash(SplashBitmap *bitmapA, GBool vectorAntialiasA, + SplashScreenParams *screenParams = NULL); + Splash(SplashBitmap *bitmapA, GBool vectorAntialiasA, + SplashScreen *screenA); + + ~Splash(); + + //----- state read + + SplashCoord *getMatrix(); + SplashPattern *getStrokePattern(); + SplashPattern *getFillPattern(); + SplashScreen *getScreen(); + SplashBlendFunc getBlendFunc(); + SplashCoord getStrokeAlpha(); + SplashCoord getFillAlpha(); + SplashCoord getLineWidth(); + int getLineCap(); + int getLineJoin(); + SplashCoord getMiterLimit(); + SplashCoord getFlatness(); + SplashCoord *getLineDash(); + int getLineDashLength(); + SplashCoord getLineDashPhase(); + GBool getStrokeAdjust(); + SplashClip *getClip(); + SplashBitmap *getSoftMask(); + GBool getInNonIsolatedGroup(); + + //----- state write + + void setMatrix(SplashCoord *matrix); + void setStrokePattern(SplashPattern *strokeColor); + void setFillPattern(SplashPattern *fillColor); + void setScreen(SplashScreen *screen); + void setBlendFunc(SplashBlendFunc func); + void setStrokeAlpha(SplashCoord alpha); + void setFillAlpha(SplashCoord alpha); + void setFillOverprint(GBool fop); + void setStrokeOverprint(GBool sop); + void setOverprintMode(int opm); + void setLineWidth(SplashCoord lineWidth); + void setLineCap(int lineCap); + void setLineJoin(int lineJoin); + void setMiterLimit(SplashCoord miterLimit); + void setFlatness(SplashCoord flatness); + // the <lineDash> array will be copied + void setLineDash(SplashCoord *lineDash, int lineDashLength, + SplashCoord lineDashPhase); + void setStrokeAdjust(GBool strokeAdjust); + // NB: uses transformed coordinates. + void clipResetToRect(SplashCoord x0, SplashCoord y0, + SplashCoord x1, SplashCoord y1); + // NB: uses transformed coordinates. + SplashError clipToRect(SplashCoord x0, SplashCoord y0, + SplashCoord x1, SplashCoord y1); + // NB: uses untransformed coordinates. + SplashError clipToPath(SplashPath *path, GBool eo); + void setSoftMask(SplashBitmap *softMask); + void setInNonIsolatedGroup(SplashBitmap *alpha0BitmapA, + int alpha0XA, int alpha0YA); + void setTransfer(Guchar *red, Guchar *green, Guchar *blue, Guchar *gray); + void setOverprintMask(Guint overprintMask, GBool additive); + + //----- state save/restore + + void saveState(); + SplashError restoreState(); + + //----- drawing operations + + // Fill the bitmap with <color>. This is not subject to clipping. + void clear(SplashColorPtr color, Guchar alpha = 0x00); + + // Stroke a path using the current stroke pattern. + SplashError stroke(SplashPath *path); + + // 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); + + // Draw a glyph, using the current fill pattern. This function does + // not free any data, i.e., it ignores glyph->freeData. + void fillGlyph(SplashCoord x, SplashCoord y, + SplashGlyphBitmap *glyph); + + // Draws an image mask using the fill color. This will read <h> + // lines of <w> pixels from <src>, starting with the top line. "1" + // pixels will be drawn with the current fill color; "0" pixels are + // transparent. The matrix: + // [ mat[0] mat[1] 0 ] + // [ mat[2] mat[3] 0 ] + // [ mat[4] mat[5] 1 ] + // maps a unit square to the desired destination for the image, in + // PostScript style: + // [x' y' 1] = [x y 1] * mat + // Note that the Splash y axis points downward, and the image source + // is assumed to produce pixels in raster order, starting from the + // top line. + SplashError fillImageMask(SplashImageMaskSource src, void *srcData, + int w, int h, SplashCoord *mat, + GBool glyphMode); + + // Draw an image. This will read <h> lines of <w> pixels from + // <src>, starting with the top line. These pixels are assumed to + // be in the source mode, <srcMode>. If <srcAlpha> is true, the + // alpha values returned by <src> are used; otherwise they are + // ignored. The following combinations of source and target modes + // are supported: + // source target + // ------ ------ + // Mono1 Mono1 + // Mono8 Mono1 -- with dithering + // Mono8 Mono8 + // RGB8 RGB8 + // BGR8 BGR8 + // CMYK8 CMYK8 + // The matrix behaves as for fillImageMask. + SplashError drawImage(SplashImageSource src, void *srcData, + SplashColorMode srcMode, GBool srcAlpha, + int w, int h, SplashCoord *mat, GBool interpolate, + GBool tilingPattern = gFalse); + + // Composite a rectangular region from <src> onto this Splash + // object. + SplashError composite(SplashBitmap *src, int xSrc, int ySrc, + int xDest, int yDest, int w, int h, + GBool noClip, GBool nonIsolated, + GBool knockout = gFalse, SplashCoord knockoutOpacity = 1.0); + + // Composite this Splash object onto a background color. The + // background alpha is assumed to be 1. + void compositeBackground(SplashColorPtr color); + + // Copy a rectangular region from <src> onto the bitmap belonging to + // this Splash object. The destination alpha values are all set to + // zero. + SplashError blitTransparent(SplashBitmap *src, int xSrc, int ySrc, + int xDest, int yDest, int w, int h); + void blitImage(SplashBitmap *src, GBool srcAlpha, int xDest, int yDest); + + //----- misc + + // Construct a path for a stroke, given the path to be stroked and + // the line width <w>. All other stroke parameters are taken from + // the current state. If <flatten> is true, this function will + // first flatten the path and handle the linedash. + SplashPath *makeStrokePath(SplashPath *path, SplashCoord w, + GBool flatten = gTrue); + + // Return the associated bitmap. + SplashBitmap *getBitmap() { return bitmap; } + + // Set the minimum line width. + void setMinLineWidth(SplashCoord w) { minLineWidth = w; } + + // Setter/Getter for thin line mode + void setThinLineMode(SplashThinLineMode thinLineModeA) { thinLineMode = thinLineModeA; } + SplashThinLineMode getThinLineMode() { return thinLineMode; } + + // Get a bounding box which includes all modifications since the + // last call to clearModRegion. + void getModRegion(int *xMin, int *yMin, int *xMax, int *yMax) + { *xMin = modXMin; *yMin = modYMin; *xMax = modXMax; *yMax = modYMax; } + + // Clear the modified region bounding box. + void clearModRegion(); + + // Get clipping status for the last drawing operation subject to + // clipping. + SplashClipResult getClipRes() { return opClipRes; } + + // Toggle debug mode on or off. + void setDebugMode(GBool debugModeA) { debugMode = debugModeA; } + +#if 1 //~tmp: turn off anti-aliasing temporarily + void setInShading(GBool sh) { inShading = sh; } + GBool getVectorAntialias() { return vectorAntialias; } + void setVectorAntialias(GBool vaa) { vectorAntialias = vaa; } +#endif + + // Do shaded fills with dynamic patterns + SplashError shadedFill(SplashPath *path, GBool hasBBox, + SplashPattern *pattern); + // Draw a gouraud triangle shading. + GBool gouraudTriangleShadedFill(SplashGouraudColor *shading); + +private: + + void pipeInit(SplashPipe *pipe, int x, int y, + SplashPattern *pattern, SplashColorPtr cSrc, + Guchar aInput, GBool usesShape, + GBool nonIsolatedGroup, + GBool knockout = gFalse, Guchar knockoutOpacity = 255); + void pipeRun(SplashPipe *pipe); + void pipeRunSimpleMono1(SplashPipe *pipe); + void pipeRunSimpleMono8(SplashPipe *pipe); + void pipeRunSimpleRGB8(SplashPipe *pipe); + void pipeRunSimpleXBGR8(SplashPipe *pipe); + void pipeRunSimpleBGR8(SplashPipe *pipe); +#if SPLASH_CMYK + void pipeRunSimpleCMYK8(SplashPipe *pipe); + void pipeRunSimpleDeviceN8(SplashPipe *pipe); +#endif + void pipeRunAAMono1(SplashPipe *pipe); + void pipeRunAAMono8(SplashPipe *pipe); + void pipeRunAARGB8(SplashPipe *pipe); + void pipeRunAAXBGR8(SplashPipe *pipe); + void pipeRunAABGR8(SplashPipe *pipe); +#if SPLASH_CMYK + void pipeRunAACMYK8(SplashPipe *pipe); + void pipeRunAADeviceN8(SplashPipe *pipe); +#endif + void pipeSetXY(SplashPipe *pipe, int x, int y); + void pipeIncX(SplashPipe *pipe); + void drawPixel(SplashPipe *pipe, int x, int y, GBool noClip); + void drawAAPixelInit(); + void drawAAPixel(SplashPipe *pipe, int x, int y); + void drawSpan(SplashPipe *pipe, int x0, int x1, int y, GBool noClip); + void drawAALine(SplashPipe *pipe, int x0, int x1, int y, GBool adjustLine = gFalse, Guchar lineOpacity = 0); + void transform(SplashCoord *matrix, SplashCoord xi, SplashCoord yi, + SplashCoord *xo, SplashCoord *yo); + void updateModX(int x); + void updateModY(int y); + void strokeNarrow(SplashPath *path); + void strokeWide(SplashPath *path, SplashCoord w); + SplashPath *flattenPath(SplashPath *path, SplashCoord *matrix, + SplashCoord flatness); + void flattenCurve(SplashCoord x0, SplashCoord y0, + SplashCoord x1, SplashCoord y1, + SplashCoord x2, SplashCoord y2, + SplashCoord x3, SplashCoord y3, + SplashCoord *matrix, SplashCoord flatness2, + SplashPath *fPath); + SplashPath *makeDashedPath(SplashPath *xPath); + void getBBoxFP(SplashPath *path, SplashCoord *xMinA, SplashCoord *yMinA, SplashCoord *xMaxA, SplashCoord *yMaxA); + SplashError fillWithPattern(SplashPath *path, GBool eo, + SplashPattern *pattern, SplashCoord alpha); + GBool pathAllOutside(SplashPath *path); + void fillGlyph2(int x0, int y0, SplashGlyphBitmap *glyph, GBool noclip); + void arbitraryTransformMask(SplashImageMaskSource src, void *srcData, + int srcWidth, int srcHeight, + SplashCoord *mat, GBool glyphMode); + SplashBitmap *scaleMask(SplashImageMaskSource src, void *srcData, + int srcWidth, int srcHeight, + int scaledWidth, int scaledHeight); + void scaleMaskYdXd(SplashImageMaskSource src, void *srcData, + int srcWidth, int srcHeight, + int scaledWidth, int scaledHeight, + SplashBitmap *dest); + void scaleMaskYdXu(SplashImageMaskSource src, void *srcData, + int srcWidth, int srcHeight, + int scaledWidth, int scaledHeight, + SplashBitmap *dest); + void scaleMaskYuXd(SplashImageMaskSource src, void *srcData, + int srcWidth, int srcHeight, + int scaledWidth, int scaledHeight, + SplashBitmap *dest); + void scaleMaskYuXu(SplashImageMaskSource src, void *srcData, + int srcWidth, int srcHeight, + int scaledWidth, int scaledHeight, + SplashBitmap *dest); + void blitMask(SplashBitmap *src, int xDest, int yDest, + SplashClipResult clipRes); + SplashError arbitraryTransformImage(SplashImageSource src, void *srcData, + SplashColorMode srcMode, int nComps, + GBool srcAlpha, + int srcWidth, int srcHeight, + SplashCoord *mat, GBool interpolate, GBool tilingPattern = gFalse); + SplashBitmap *scaleImage(SplashImageSource src, void *srcData, + SplashColorMode srcMode, int nComps, + GBool srcAlpha, int srcWidth, int srcHeight, + int scaledWidth, int scaledHeight, GBool interpolate, GBool tilingPattern = gFalse); + void scaleImageYdXd(SplashImageSource src, void *srcData, + SplashColorMode srcMode, int nComps, + GBool srcAlpha, int srcWidth, int srcHeight, + int scaledWidth, int scaledHeight, + SplashBitmap *dest); + void scaleImageYdXu(SplashImageSource src, void *srcData, + SplashColorMode srcMode, int nComps, + GBool srcAlpha, int srcWidth, int srcHeight, + int scaledWidth, int scaledHeight, + SplashBitmap *dest); + void scaleImageYuXd(SplashImageSource src, void *srcData, + SplashColorMode srcMode, int nComps, + GBool srcAlpha, int srcWidth, int srcHeight, + int scaledWidth, int scaledHeight, + SplashBitmap *dest); + void scaleImageYuXu(SplashImageSource src, void *srcData, + SplashColorMode srcMode, int nComps, + GBool srcAlpha, int srcWidth, int srcHeight, + int scaledWidth, int scaledHeight, + SplashBitmap *dest); + void scaleImageYuXuBilinear(SplashImageSource src, void *srcData, + SplashColorMode srcMode, int nComps, + GBool srcAlpha, int srcWidth, int srcHeight, + int scaledWidth, int scaledHeight, + SplashBitmap *dest); + void vertFlipImage(SplashBitmap *img, int width, int height, + int nComps); + void blitImage(SplashBitmap *src, GBool srcAlpha, int xDest, int yDest, + SplashClipResult clipRes); + void blitImageClipped(SplashBitmap *src, GBool srcAlpha, + int xSrc, int ySrc, int xDest, int yDest, + int w, int h); + void dumpPath(SplashPath *path); + void dumpXPath(SplashXPath *path); + + static SplashPipeResultColorCtrl pipeResultColorNoAlphaBlend[]; + static SplashPipeResultColorCtrl pipeResultColorAlphaNoBlend[]; + static SplashPipeResultColorCtrl pipeResultColorAlphaBlend[]; + static int pipeNonIsoGroupCorrection[]; + + SplashBitmap *bitmap; + SplashState *state; + SplashBitmap *aaBuf; + int aaBufY; + SplashBitmap *alpha0Bitmap; // for non-isolated groups, this is the + // bitmap containing the alpha0 values + int alpha0X, alpha0Y; // offset within alpha0Bitmap + SplashCoord aaGamma[splashAASize * splashAASize + 1]; + SplashCoord minLineWidth; + SplashThinLineMode thinLineMode; + int modXMin, modYMin, modXMax, modYMax; + SplashClipResult opClipRes; + GBool vectorAntialias; + GBool inShading; + GBool debugMode; +}; + +#endif diff --git a/Build/source/libs/poppler/poppler-0.33.0/splash/SplashBitmap.cc b/Build/source/libs/poppler/poppler-0.33.0/splash/SplashBitmap.cc new file mode 100644 index 00000000000..e886683fd41 --- /dev/null +++ b/Build/source/libs/poppler/poppler-0.33.0/splash/SplashBitmap.cc @@ -0,0 +1,750 @@ +//======================================================================== +// +// SplashBitmap.cc +// +//======================================================================== + +//======================================================================== +// +// Modified under the Poppler project - http://poppler.freedesktop.org +// +// All changes made under the Poppler project to this file are licensed +// under GPL version 2 or later +// +// Copyright (C) 2006, 2009, 2010, 2012, 2015 Albert Astals Cid <aacid@kde.org> +// Copyright (C) 2007 Ilmari Heikkinen <ilmari.heikkinen@gmail.com> +// Copyright (C) 2009 Shen Liang <shenzhuxi@gmail.com> +// Copyright (C) 2009 Stefan Thomas <thomas@eload24.com> +// Copyright (C) 2010, 2012 Adrian Johnson <ajohnson@redneon.com> +// Copyright (C) 2010 Harry Roberts <harry.roberts@midnight-labs.org> +// Copyright (C) 2010 Christian Feuersänger <cfeuersaenger@googlemail.com> +// Copyright (C) 2010 William Bader <williambader@hotmail.com> +// Copyright (C) 2011-2013 Thomas Freitag <Thomas.Freitag@alfa.de> +// Copyright (C) 2012 Anthony Wesley <awesley@smartnetworks.com.au> +// +// To see a description of the changes please see the Changelog file that +// came with your tarball or type make ChangeLog if you are building from git +// +//======================================================================== + +#include <config.h> + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <limits.h> +#include "goo/gmem.h" +#include "SplashErrorCodes.h" +#include "SplashBitmap.h" +#include "poppler/Error.h" +#include "goo/JpegWriter.h" +#include "goo/PNGWriter.h" +#include "goo/TiffWriter.h" +#include "goo/ImgWriter.h" +#include "goo/GooList.h" + +//------------------------------------------------------------------------ +// SplashBitmap +//------------------------------------------------------------------------ + +SplashBitmap::SplashBitmap(int widthA, int heightA, int rowPadA, + SplashColorMode modeA, GBool alphaA, + GBool topDown, GooList *separationListA) { + width = widthA; + height = heightA; + mode = modeA; + rowPad = rowPadA; + switch (mode) { + case splashModeMono1: + if (width > 0) { + rowSize = (width + 7) >> 3; + } else { + rowSize = -1; + } + break; + case splashModeMono8: + if (width > 0) { + rowSize = width; + } else { + rowSize = -1; + } + break; + case splashModeRGB8: + case splashModeBGR8: + if (width > 0 && width <= INT_MAX / 3) { + rowSize = width * 3; + } else { + rowSize = -1; + } + break; + case splashModeXBGR8: + if (width > 0 && width <= INT_MAX / 4) { + rowSize = width * 4; + } else { + rowSize = -1; + } + break; +#if SPLASH_CMYK + case splashModeCMYK8: + if (width > 0 && width <= INT_MAX / 4) { + rowSize = width * 4; + } else { + rowSize = -1; + } + break; + case splashModeDeviceN8: + if (width > 0 && width <= INT_MAX / 4) { + rowSize = width * (SPOT_NCOMPS + 4); + } else { + rowSize = -1; + } + break; +#endif + } + if (rowSize > 0) { + rowSize += rowPad - 1; + rowSize -= rowSize % rowPad; + } + data = (SplashColorPtr)gmallocn_checkoverflow(rowSize, height); + if (data != NULL) { + if (!topDown) { + data += (height - 1) * rowSize; + rowSize = -rowSize; + } + if (alphaA) { + alpha = (Guchar *)gmallocn(width, height); + } else { + alpha = NULL; + } + } else { + alpha = NULL; + } + separationList = new GooList(); + if (separationListA != NULL) + for (int i = 0; i < separationListA->getLength(); i++) + separationList->append(((GfxSeparationColorSpace *) separationListA->get(i))->copy()); +} + +SplashBitmap *SplashBitmap::copy(SplashBitmap *src) { + SplashBitmap *result = new SplashBitmap(src->getWidth(), src->getHeight(), src->getRowPad(), + src->getMode(), src->getAlphaPtr() != NULL, src->getRowSize() >= 0, src->getSeparationList()); + Guchar *dataSource = src->getDataPtr(); + Guchar *dataDest = result->getDataPtr(); + int amount = src->getRowSize(); + if (amount < 0) { + dataSource = dataSource + (src->getHeight() - 1) * amount; + dataDest = dataDest + (src->getHeight() - 1) * amount; + amount *= -src->getHeight(); + } else { + amount *= src->getHeight(); + } + memcpy(dataDest, dataSource, amount); + if (src->getAlphaPtr() != NULL) { + memcpy(result->getAlphaPtr(), src->getAlphaPtr(), src->getWidth() * src->getHeight()); + } + return result; +} + +SplashBitmap::~SplashBitmap() { + if (data) { + if (rowSize < 0) { + gfree(data + (height - 1) * rowSize); + } else { + gfree(data); + } + } + gfree(alpha); + deleteGooList(separationList, GfxSeparationColorSpace); +} + + +SplashError SplashBitmap::writePNMFile(char *fileName) { + FILE *f; + SplashError e; + + if (!(f = fopen(fileName, "wb"))) { + return splashErrOpenFile; + } + + e = this->writePNMFile(f); + + fclose(f); + return e; +} + + +SplashError SplashBitmap::writePNMFile(FILE *f) { + SplashColorPtr row, p; + int x, y; + + switch (mode) { + + case splashModeMono1: + fprintf(f, "P4\n%d %d\n", width, height); + row = data; + for (y = 0; y < height; ++y) { + p = row; + for (x = 0; x < width; x += 8) { + fputc(*p ^ 0xff, f); + ++p; + } + row += rowSize; + } + break; + + case splashModeMono8: + fprintf(f, "P5\n%d %d\n255\n", width, height); + row = data; + for (y = 0; y < height; ++y) { + fwrite(row, 1, width, f); + row += rowSize; + } + break; + + case splashModeRGB8: + fprintf(f, "P6\n%d %d\n255\n", width, height); + row = data; + for (y = 0; y < height; ++y) { + fwrite(row, 1, 3 * width, f); + row += rowSize; + } + break; + + case splashModeXBGR8: + fprintf(f, "P6\n%d %d\n255\n", width, height); + row = data; + for (y = 0; y < height; ++y) { + p = row; + for (x = 0; x < width; ++x) { + fputc(splashBGR8R(p), f); + fputc(splashBGR8G(p), f); + fputc(splashBGR8B(p), f); + p += 4; + } + row += rowSize; + } + break; + + + case splashModeBGR8: + fprintf(f, "P6\n%d %d\n255\n", width, height); + row = data; + for (y = 0; y < height; ++y) { + p = row; + for (x = 0; x < width; ++x) { + fputc(splashBGR8R(p), f); + fputc(splashBGR8G(p), f); + fputc(splashBGR8B(p), f); + p += 3; + } + row += rowSize; + } + break; + +#if SPLASH_CMYK + case splashModeCMYK8: + case splashModeDeviceN8: + // PNM doesn't support CMYK + error(errInternal, -1, "unsupported SplashBitmap mode"); + return splashErrGeneric; + break; +#endif + } + return splashOk; +} + +SplashError SplashBitmap::writeAlphaPGMFile(char *fileName) { + FILE *f; + + if (!alpha) { + return splashErrModeMismatch; + } + if (!(f = fopen(fileName, "wb"))) { + return splashErrOpenFile; + } + fprintf(f, "P5\n%d %d\n255\n", width, height); + fwrite(alpha, 1, width * height, f); + fclose(f); + return splashOk; +} + +void SplashBitmap::getPixel(int x, int y, SplashColorPtr pixel) { + SplashColorPtr p; + + if (y < 0 || y >= height || x < 0 || x >= width || !data) { + return; + } + switch (mode) { + case splashModeMono1: + p = &data[y * rowSize + (x >> 3)]; + pixel[0] = (p[0] & (0x80 >> (x & 7))) ? 0xff : 0x00; + break; + case splashModeMono8: + p = &data[y * rowSize + x]; + pixel[0] = p[0]; + break; + case splashModeRGB8: + p = &data[y * rowSize + 3 * x]; + pixel[0] = p[0]; + pixel[1] = p[1]; + pixel[2] = p[2]; + break; + case splashModeXBGR8: + p = &data[y * rowSize + 4 * x]; + pixel[0] = p[2]; + pixel[1] = p[1]; + pixel[2] = p[0]; + pixel[3] = p[3]; + break; + case splashModeBGR8: + p = &data[y * rowSize + 3 * x]; + pixel[0] = p[2]; + pixel[1] = p[1]; + pixel[2] = p[0]; + break; +#if SPLASH_CMYK + case splashModeCMYK8: + p = &data[y * rowSize + 4 * x]; + pixel[0] = p[0]; + pixel[1] = p[1]; + pixel[2] = p[2]; + pixel[3] = p[3]; + break; + case splashModeDeviceN8: + p = &data[y * rowSize + (SPOT_NCOMPS + 4) * x]; + for (int cp = 0; cp < SPOT_NCOMPS + 4; cp++) + pixel[cp] = p[cp]; + break; +#endif + } +} + +Guchar SplashBitmap::getAlpha(int x, int y) { + return alpha[y * width + x]; +} + +SplashColorPtr SplashBitmap::takeData() { + SplashColorPtr data2; + + data2 = data; + data = NULL; + return data2; +} + +SplashError SplashBitmap::writeImgFile(SplashImageFileFormat format, char *fileName, int hDPI, int vDPI, const char *compressionString) { + FILE *f; + SplashError e; + + if (!(f = fopen(fileName, "wb"))) { + return splashErrOpenFile; + } + + e = writeImgFile(format, f, hDPI, vDPI, compressionString); + + fclose(f); + return e; +} + +SplashError SplashBitmap::writeImgFile(SplashImageFileFormat format, FILE *f, int hDPI, int vDPI, const char *compressionString) { + ImgWriter *writer; + SplashError e; + + switch (format) { + #ifdef ENABLE_LIBPNG + case splashFormatPng: + writer = new PNGWriter(); + break; + #endif + + #ifdef ENABLE_LIBJPEG + #ifdef SPLASH_CMYK + case splashFormatJpegCMYK: + writer = new JpegWriter(JpegWriter::CMYK); + break; + #endif + case splashFormatJpeg: + writer = new JpegWriter(); + break; + #endif + + #ifdef ENABLE_LIBTIFF + case splashFormatTiff: + switch (mode) { + case splashModeMono1: + writer = new TiffWriter(TiffWriter::MONOCHROME); + break; + case splashModeMono8: + writer = new TiffWriter(TiffWriter::GRAY); + break; + case splashModeRGB8: + case splashModeBGR8: + writer = new TiffWriter(TiffWriter::RGB); + break; +#if SPLASH_CMYK + case splashModeCMYK8: + case splashModeDeviceN8: + writer = new TiffWriter(TiffWriter::CMYK); + break; +#endif + default: + fprintf(stderr, "TiffWriter: Mode %d not supported\n", mode); + writer = new TiffWriter(); + } + if (writer) { + ((TiffWriter *)writer)->setCompressionString(compressionString); + } + break; + #endif + + default: + // Not the greatest error message, but users of this function should + // have already checked whether their desired format is compiled in. + error(errInternal, -1, "Support for this image type not compiled in"); + return splashErrGeneric; + } + + e = writeImgFile(writer, f, hDPI, vDPI); + delete writer; + return e; +} + +#include "poppler/GfxState_helpers.h" + +void SplashBitmap::getRGBLine(int yl, SplashColorPtr line) { + SplashColor col; + double c, m, y, k, c1, m1, y1, k1, r, g, b; + + for (int x = 0; x < width; x++) { + getPixel(x, yl, col); + c = byteToDbl(col[0]); + m = byteToDbl(col[1]); + y = byteToDbl(col[2]); + k = byteToDbl(col[3]); +#if SPLASH_CMYK + if (separationList->getLength() > 0) { + for (int i = 0; i < separationList->getLength(); i++) { + if (col[i+4] > 0) { + GfxCMYK cmyk; + GfxColor input; + input.c[0] = byteToCol(col[i+4]); + GfxSeparationColorSpace *sepCS = (GfxSeparationColorSpace *)separationList->get(i); + sepCS->getCMYK(&input, &cmyk); + col[0] = colToByte(cmyk.c); + col[1] = colToByte(cmyk.m); + col[2] = colToByte(cmyk.y); + col[3] = colToByte(cmyk.k); + c += byteToDbl(col[0]); + m += byteToDbl(col[1]); + y += byteToDbl(col[2]); + k += byteToDbl(col[3]); + } + } + if (c > 1) c = 1; + if (m > 1) m = 1; + if (y > 1) y = 1; + if (k > 1) k = 1; + } +#endif + c1 = 1 - c; + m1 = 1 - m; + y1 = 1 - y; + k1 = 1 - k; + cmykToRGBMatrixMultiplication(c, m, y, k, c1, m1, y1, k1, r, g, b); + *line++ = dblToByte(clip01(r)); + *line++ = dblToByte(clip01(g)); + *line++ = dblToByte(clip01(b)); + } +} + +void SplashBitmap::getXBGRLine(int yl, SplashColorPtr line) { + SplashColor col; + double c, m, y, k, c1, m1, y1, k1, r, g, b; + + for (int x = 0; x < width; x++) { + getPixel(x, yl, col); + c = byteToDbl(col[0]); + m = byteToDbl(col[1]); + y = byteToDbl(col[2]); + k = byteToDbl(col[3]); +#if SPLASH_CMYK + if (separationList->getLength() > 0) { + for (int i = 0; i < separationList->getLength(); i++) { + if (col[i+4] > 0) { + GfxCMYK cmyk; + GfxColor input; + input.c[0] = byteToCol(col[i+4]); + GfxSeparationColorSpace *sepCS = (GfxSeparationColorSpace *)separationList->get(i); + sepCS->getCMYK(&input, &cmyk); + col[0] = colToByte(cmyk.c); + col[1] = colToByte(cmyk.m); + col[2] = colToByte(cmyk.y); + col[3] = colToByte(cmyk.k); + c += byteToDbl(col[0]); + m += byteToDbl(col[1]); + y += byteToDbl(col[2]); + k += byteToDbl(col[3]); + } + } + if (c > 1) c = 1; + if (m > 1) m = 1; + if (y > 1) y = 1; + if (k > 1) k = 1; + } +#endif + c1 = 1 - c; + m1 = 1 - m; + y1 = 1 - y; + k1 = 1 - k; + cmykToRGBMatrixMultiplication(c, m, y, k, c1, m1, y1, k1, r, g, b); + *line++ = dblToByte(clip01(b)); + *line++ = dblToByte(clip01(g)); + *line++ = dblToByte(clip01(r)); + *line++ = 255; + } +} + +GBool SplashBitmap::convertToXBGR() { + if (mode == splashModeXBGR8) + return gTrue; + + int newrowSize = width * 4; + SplashColorPtr newdata = (SplashColorPtr)gmallocn_checkoverflow(newrowSize, height); + if (newdata != NULL) { + for (int y = 0; y < height; y++) { + unsigned char *row = newdata + y * newrowSize; + getXBGRLine(y, row); + } + if (rowSize < 0) { + gfree(data + (height - 1) * rowSize); + } else { + gfree(data); + } + data = newdata; + rowSize = newrowSize; + mode = splashModeXBGR8; + } + return newdata != NULL; +} + +#if SPLASH_CMYK +void SplashBitmap::getCMYKLine(int yl, SplashColorPtr line) { + SplashColor col; + + for (int x = 0; x < width; x++) { + getPixel(x, yl, col); + if (separationList->getLength() > 0) { + double c, m, y, k; + c = byteToDbl(col[0]); + m = byteToDbl(col[1]); + y = byteToDbl(col[2]); + k = byteToDbl(col[3]); + for (int i = 0; i < separationList->getLength(); i++) { + if (col[i+4] > 0) { + GfxCMYK cmyk; + GfxColor input; + input.c[0] = byteToCol(col[i+4]); + GfxSeparationColorSpace *sepCS = (GfxSeparationColorSpace *)separationList->get(i); + sepCS->getCMYK(&input, &cmyk); + col[0] = colToByte(cmyk.c); + col[1] = colToByte(cmyk.m); + col[2] = colToByte(cmyk.y); + col[3] = colToByte(cmyk.k); + c += byteToDbl(col[0]); + m += byteToDbl(col[1]); + y += byteToDbl(col[2]); + k += byteToDbl(col[3]); + } + } + col[0] = dblToByte(clip01(c)); + col[1] = dblToByte(clip01(m)); + col[2] = dblToByte(clip01(y)); + col[3] = dblToByte(clip01(k)); + } + *line++ = col[0]; + *line++ = col[1]; + *line++ = col[2]; + *line++ = col[3]; + } +} +#endif + +SplashError SplashBitmap::writeImgFile(ImgWriter *writer, FILE *f, int hDPI, int vDPI) { + if (mode != splashModeRGB8 && mode != splashModeMono8 && mode != splashModeMono1 && mode != splashModeXBGR8 && mode != splashModeBGR8 +#if SPLASH_CMYK + && mode != splashModeCMYK8 && mode != splashModeDeviceN8 +#endif + ) { + error(errInternal, -1, "unsupported SplashBitmap mode"); + return splashErrGeneric; + } + + if (!writer->init(f, width, height, hDPI, vDPI)) { + return splashErrGeneric; + } + + switch (mode) { +#if SPLASH_CMYK + case splashModeCMYK8: + if (writer->supportCMYK()) { + SplashColorPtr row; + unsigned char **row_pointers = new unsigned char*[height]; + row = data; + + for (int y = 0; y < height; ++y) { + row_pointers[y] = row; + row += rowSize; + } + if (!writer->writePointers(row_pointers, height)) { + delete[] row_pointers; + return splashErrGeneric; + } + delete[] row_pointers; + } else { + unsigned char *row = new unsigned char[3 * width]; + for (int y = 0; y < height; y++) { + getRGBLine(y, row); + if (!writer->writeRow(&row)) { + delete[] row; + return splashErrGeneric; + } + } + delete[] row; + } + break; + case splashModeDeviceN8: + if (writer->supportCMYK()) { + unsigned char *row = new unsigned char[4 * width]; + for (int y = 0; y < height; y++) { + getCMYKLine(y, row); + if (!writer->writeRow(&row)) { + delete[] row; + return splashErrGeneric; + } + } + delete[] row; + } else { + unsigned char *row = new unsigned char[3 * width]; + for (int y = 0; y < height; y++) { + getRGBLine(y, row); + if (!writer->writeRow(&row)) { + delete[] row; + return splashErrGeneric; + } + } + delete[] row; + } + break; +#endif + case splashModeRGB8: + { + SplashColorPtr row; + unsigned char **row_pointers = new unsigned char*[height]; + row = data; + + for (int y = 0; y < height; ++y) { + row_pointers[y] = row; + row += rowSize; + } + if (!writer->writePointers(row_pointers, height)) { + delete[] row_pointers; + return splashErrGeneric; + } + delete[] row_pointers; + } + break; + + case splashModeBGR8: + { + unsigned char *row = new unsigned char[3 * width]; + for (int y = 0; y < height; y++) { + // Convert into a PNG row + for (int x = 0; x < width; x++) { + row[3*x] = data[y * rowSize + x * 3 + 2]; + row[3*x+1] = data[y * rowSize + x * 3 + 1]; + row[3*x+2] = data[y * rowSize + x * 3]; + } + + if (!writer->writeRow(&row)) { + delete[] row; + return splashErrGeneric; + } + } + delete[] row; + } + break; + + case splashModeXBGR8: + { + unsigned char *row = new unsigned char[3 * width]; + for (int y = 0; y < height; y++) { + // Convert into a PNG row + for (int x = 0; x < width; x++) { + row[3*x] = data[y * rowSize + x * 4 + 2]; + row[3*x+1] = data[y * rowSize + x * 4 + 1]; + row[3*x+2] = data[y * rowSize + x * 4]; + } + + if (!writer->writeRow(&row)) { + delete[] row; + return splashErrGeneric; + } + } + delete[] row; + } + break; + + case splashModeMono8: + { + unsigned char *row = new unsigned char[3 * width]; + for (int y = 0; y < height; y++) { + // Convert into a PNG row + for (int x = 0; x < width; x++) { + row[3*x] = data[y * rowSize + x]; + row[3*x+1] = data[y * rowSize + x]; + row[3*x+2] = data[y * rowSize + x]; + } + + if (!writer->writeRow(&row)) { + delete[] row; + return splashErrGeneric; + } + } + delete[] row; + } + break; + + case splashModeMono1: + { + unsigned char *row = new unsigned char[3 * width]; + for (int y = 0; y < height; y++) { + // Convert into a PNG row + for (int x = 0; x < width; x++) { + getPixel(x, y, &row[3*x]); + row[3*x+1] = row[3*x]; + row[3*x+2] = row[3*x]; + } + + if (!writer->writeRow(&row)) { + delete[] row; + return splashErrGeneric; + } + } + delete[] row; + } + break; + + default: + // can't happen + break; + } + + if (!writer->close()) { + return splashErrGeneric; + } + + return splashOk; +} diff --git a/Build/source/libs/poppler/poppler-0.33.0/splash/SplashBitmap.h b/Build/source/libs/poppler/poppler-0.33.0/splash/SplashBitmap.h new file mode 100644 index 00000000000..70509abcfaa --- /dev/null +++ b/Build/source/libs/poppler/poppler-0.33.0/splash/SplashBitmap.h @@ -0,0 +1,108 @@ +//======================================================================== +// +// SplashBitmap.h +// +//======================================================================== + +//======================================================================== +// +// Modified under the Poppler project - http://poppler.freedesktop.org +// +// All changes made under the Poppler project to this file are licensed +// under GPL version 2 or later +// +// Copyright (C) 2007 Ilmari Heikkinen <ilmari.heikkinen@gmail.com> +// Copyright (C) 2009 Shen Liang <shenzhuxi@gmail.com> +// Copyright (C) 2009, 2012 Albert Astals Cid <aacid@kde.org> +// Copyright (C) 2009 Stefan Thomas <thomas@eload24.com> +// Copyright (C) 2010 Adrian Johnson <ajohnson@redneon.com> +// Copyright (C) 2010 Harry Roberts <harry.roberts@midnight-labs.org> +// Copyright (C) 2010 Christian Feuersänger <cfeuersaenger@googlemail.com> +// Copyright (C) 2010 William Bader <williambader@hotmail.com> +// Copyright (C) 2012 Thomas Freitag <Thomas.Freitag@alfa.de> +// +// To see a description of the changes please see the Changelog file that +// came with your tarball or type make ChangeLog if you are building from git +// +//======================================================================== + +#ifndef SPLASHBITMAP_H +#define SPLASHBITMAP_H + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "SplashTypes.h" +#include "poppler/GfxState.h" +#include <stdio.h> + +class ImgWriter; + +//------------------------------------------------------------------------ +// SplashBitmap +//------------------------------------------------------------------------ + +class SplashBitmap { +public: + + // Create a new bitmap. It will have <widthA> x <heightA> pixels in + // color mode <modeA>. Rows will be padded out to a multiple of + // <rowPad> bytes. If <topDown> is false, the bitmap will be stored + // upside-down, i.e., with the last row first in memory. + SplashBitmap(int widthA, int heightA, int rowPad, + SplashColorMode modeA, GBool alphaA, + GBool topDown = gTrue, GooList *separationList = NULL); + static SplashBitmap *copy(SplashBitmap *src); + + ~SplashBitmap(); + + int getWidth() { return width; } + int getHeight() { return height; } + int getRowSize() { return rowSize; } + int getAlphaRowSize() { return width; } + int getRowPad() { return rowPad; } + SplashColorMode getMode() { return mode; } + SplashColorPtr getDataPtr() { return data; } + Guchar *getAlphaPtr() { return alpha; } + GooList *getSeparationList() { return separationList; } + + SplashError writePNMFile(char *fileName); + SplashError writePNMFile(FILE *f); + SplashError writeAlphaPGMFile(char *fileName); + + SplashError writeImgFile(SplashImageFileFormat format, char *fileName, int hDPI, int vDPI, const char *compressionString = ""); + SplashError writeImgFile(SplashImageFileFormat format, FILE *f, int hDPI, int vDPI, const char *compressionString = ""); + SplashError writeImgFile(ImgWriter *writer, FILE *f, int hDPI, int vDPI); + + GBool convertToXBGR(); + + void getPixel(int x, int y, SplashColorPtr pixel); + void getRGBLine(int y, SplashColorPtr line); + void getXBGRLine(int y, SplashColorPtr line); +#if SPLASH_CMYK + void getCMYKLine(int y, SplashColorPtr line); +#endif + Guchar getAlpha(int x, int y); + + // Caller takes ownership of the bitmap data. The SplashBitmap + // object is no longer valid -- the next call should be to the + // destructor. + SplashColorPtr takeData(); + +private: + + int width, height; // size of bitmap + int rowPad; + int rowSize; // size of one row of data, in bytes + // - negative for bottom-up bitmaps + SplashColorMode mode; // color mode + SplashColorPtr data; // pointer to row zero of the color data + Guchar *alpha; // pointer to row zero of the alpha data + // (always top-down) + GooList *separationList; // list of spot colorants and their mapping functions + + friend class Splash; +}; + +#endif diff --git a/Build/source/libs/poppler/poppler-0.33.0/splash/SplashClip.cc b/Build/source/libs/poppler/poppler-0.33.0/splash/SplashClip.cc new file mode 100644 index 00000000000..85c6b11473d --- /dev/null +++ b/Build/source/libs/poppler/poppler-0.33.0/splash/SplashClip.cc @@ -0,0 +1,411 @@ +//======================================================================== +// +// SplashClip.cc +// +//======================================================================== + +//======================================================================== +// +// Modified under the Poppler project - http://poppler.freedesktop.org +// +// All changes made under the Poppler project to this file are licensed +// under GPL version 2 or later +// +// Copyright (C) 2010 Albert Astals Cid <aacid@kde.org> +// Copyright (C) 2013 Thomas Freitag <Thomas.Freitag@alfa.de> +// +// To see a description of the changes please see the Changelog file that +// came with your tarball or type make ChangeLog if you are building from git +// +//======================================================================== + +#include <config.h> + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include <stdlib.h> +#include <string.h> +#include "goo/gmem.h" +#include "SplashErrorCodes.h" +#include "SplashPath.h" +#include "SplashXPath.h" +#include "SplashXPathScanner.h" +#include "SplashBitmap.h" +#include "SplashClip.h" + +//------------------------------------------------------------------------ +// SplashClip.flags +//------------------------------------------------------------------------ + +#define splashClipEO 0x01 // use even-odd rule + +//------------------------------------------------------------------------ +// SplashClip +//------------------------------------------------------------------------ + +SplashClip::SplashClip(SplashCoord x0, SplashCoord y0, + SplashCoord x1, SplashCoord y1, + GBool antialiasA) { + antialias = antialiasA; + if (x0 < x1) { + xMin = x0; + xMax = x1; + } else { + xMin = x1; + xMax = x0; + } + if (y0 < y1) { + yMin = y0; + yMax = y1; + } else { + yMin = y1; + yMax = y0; + } + xMinI = splashFloor(xMin); + yMinI = splashFloor(yMin); + xMaxI = splashCeil(xMax) - 1; + yMaxI = splashCeil(yMax) - 1; + paths = NULL; + flags = NULL; + scanners = NULL; + length = size = 0; +} + +SplashClip::SplashClip(SplashClip *clip) { + int yMinAA, yMaxAA; + int i; + + antialias = clip->antialias; + xMin = clip->xMin; + yMin = clip->yMin; + xMax = clip->xMax; + yMax = clip->yMax; + xMinI = clip->xMinI; + yMinI = clip->yMinI; + xMaxI = clip->xMaxI; + yMaxI = clip->yMaxI; + length = clip->length; + size = clip->size; + paths = (SplashXPath **)gmallocn(size, sizeof(SplashXPath *)); + flags = (Guchar *)gmallocn(size, sizeof(Guchar)); + scanners = (SplashXPathScanner **) + gmallocn(size, sizeof(SplashXPathScanner *)); + for (i = 0; i < length; ++i) { + paths[i] = clip->paths[i]->copy(); + flags[i] = clip->flags[i]; + if (antialias) { + yMinAA = yMinI * splashAASize; + yMaxAA = (yMaxI + 1) * splashAASize - 1; + } else { + yMinAA = yMinI; + yMaxAA = yMaxI; + } + scanners[i] = new SplashXPathScanner(paths[i], flags[i] & splashClipEO, + yMinAA, yMaxAA); + } +} + +SplashClip::~SplashClip() { + int i; + + for (i = 0; i < length; ++i) { + delete paths[i]; + delete scanners[i]; + } + gfree(paths); + gfree(flags); + gfree(scanners); +} + +void SplashClip::grow(int nPaths) { + if (length + nPaths > size) { + if (size == 0) { + size = 32; + } + while (size < length + nPaths) { + size *= 2; + } + paths = (SplashXPath **)greallocn(paths, size, sizeof(SplashXPath *)); + flags = (Guchar *)greallocn(flags, size, sizeof(Guchar)); + scanners = (SplashXPathScanner **) + greallocn(scanners, size, sizeof(SplashXPathScanner *)); + } +} + +void SplashClip::resetToRect(SplashCoord x0, SplashCoord y0, + SplashCoord x1, SplashCoord y1) { + int i; + + for (i = 0; i < length; ++i) { + delete paths[i]; + delete scanners[i]; + } + gfree(paths); + gfree(flags); + gfree(scanners); + paths = NULL; + flags = NULL; + scanners = NULL; + length = size = 0; + + if (x0 < x1) { + xMin = x0; + xMax = x1; + } else { + xMin = x1; + xMax = x0; + } + if (y0 < y1) { + yMin = y0; + yMax = y1; + } else { + yMin = y1; + yMax = y0; + } + xMinI = splashFloor(xMin); + yMinI = splashFloor(yMin); + xMaxI = splashCeil(xMax) - 1; + yMaxI = splashCeil(yMax) - 1; +} + +SplashError SplashClip::clipToRect(SplashCoord x0, SplashCoord y0, + SplashCoord x1, SplashCoord y1) { + if (x0 < x1) { + if (x0 > xMin) { + xMin = x0; + xMinI = splashFloor(xMin); + } + if (x1 < xMax) { + xMax = x1; + xMaxI = splashCeil(xMax) - 1; + } + } else { + if (x1 > xMin) { + xMin = x1; + xMinI = splashFloor(xMin); + } + if (x0 < xMax) { + xMax = x0; + xMaxI = splashCeil(xMax) - 1; + } + } + if (y0 < y1) { + if (y0 > yMin) { + yMin = y0; + yMinI = splashFloor(yMin); + } + if (y1 < yMax) { + yMax = y1; + yMaxI = splashCeil(yMax) - 1; + } + } else { + if (y1 > yMin) { + yMin = y1; + yMinI = splashFloor(yMin); + } + if (y0 < yMax) { + yMax = y0; + yMaxI = splashCeil(yMax) - 1; + } + } + return splashOk; +} + +SplashError SplashClip::clipToPath(SplashPath *path, SplashCoord *matrix, + SplashCoord flatness, GBool eo) { + SplashXPath *xPath; + int yMinAA, yMaxAA; + + xPath = new SplashXPath(path, matrix, flatness, gTrue); + + // check for an empty path + if (xPath->length == 0) { + xMax = xMin - 1; + yMax = yMin - 1; + xMaxI = splashCeil(xMax) - 1; + yMaxI = splashCeil(yMax) - 1; + delete xPath; + + // check for a rectangle + } else if (xPath->length == 4 && + ((xPath->segs[0].x0 == xPath->segs[0].x1 && + xPath->segs[0].x0 == xPath->segs[1].x0 && + xPath->segs[0].x0 == xPath->segs[3].x1 && + xPath->segs[2].x0 == xPath->segs[2].x1 && + xPath->segs[2].x0 == xPath->segs[1].x1 && + xPath->segs[2].x0 == xPath->segs[3].x0 && + xPath->segs[1].y0 == xPath->segs[1].y1 && + xPath->segs[1].y0 == xPath->segs[0].y1 && + xPath->segs[1].y0 == xPath->segs[2].y0 && + xPath->segs[3].y0 == xPath->segs[3].y1 && + xPath->segs[3].y0 == xPath->segs[0].y0 && + xPath->segs[3].y0 == xPath->segs[2].y1) || + (xPath->segs[0].y0 == xPath->segs[0].y1 && + xPath->segs[0].y0 == xPath->segs[1].y0 && + xPath->segs[0].y0 == xPath->segs[3].y1 && + xPath->segs[2].y0 == xPath->segs[2].y1 && + xPath->segs[2].y0 == xPath->segs[1].y1 && + xPath->segs[2].y0 == xPath->segs[3].y0 && + xPath->segs[1].x0 == xPath->segs[1].x1 && + xPath->segs[1].x0 == xPath->segs[0].x1 && + xPath->segs[1].x0 == xPath->segs[2].x0 && + xPath->segs[3].x0 == xPath->segs[3].x1 && + xPath->segs[3].x0 == xPath->segs[0].x0 && + xPath->segs[3].x0 == xPath->segs[2].x1))) { + clipToRect(xPath->segs[0].x0, xPath->segs[0].y0, + xPath->segs[2].x0, xPath->segs[2].y0); + delete xPath; + + } else { + grow(1); + if (antialias) { + xPath->aaScale(); + } + xPath->sort(); + paths[length] = xPath; + flags[length] = eo ? splashClipEO : 0; + if (antialias) { + yMinAA = yMinI * splashAASize; + yMaxAA = (yMaxI + 1) * splashAASize - 1; + } else { + yMinAA = yMinI; + yMaxAA = yMaxI; + } + scanners[length] = new SplashXPathScanner(xPath, eo, yMinAA, yMaxAA); + ++length; + } + + return splashOk; +} + +SplashClipResult SplashClip::testRect(int rectXMin, int rectYMin, + int rectXMax, int rectYMax) { + // This tests the rectangle: + // x = [rectXMin, rectXMax + 1) (note: rect coords are ints) + // y = [rectYMin, rectYMax + 1) + // against the clipping region: + // x = [xMin, xMax) (note: clipping coords are fp) + // y = [yMin, yMax) + if ((SplashCoord)(rectXMax + 1) <= xMin || (SplashCoord)rectXMin >= xMax || + (SplashCoord)(rectYMax + 1) <= yMin || (SplashCoord)rectYMin >= yMax) { + return splashClipAllOutside; + } + if ((SplashCoord)rectXMin >= xMin && (SplashCoord)(rectXMax + 1) <= xMax && + (SplashCoord)rectYMin >= yMin && (SplashCoord)(rectYMax + 1) <= yMax && + length == 0) { + return splashClipAllInside; + } + return splashClipPartial; +} + +SplashClipResult SplashClip::testSpan(int spanXMin, int spanXMax, int spanY) { + int i; + + // This tests the rectangle: + // x = [spanXMin, spanXMax + 1) (note: span coords are ints) + // y = [spanY, spanY + 1) + // against the clipping region: + // x = [xMin, xMax) (note: clipping coords are fp) + // y = [yMin, yMax) + if ((SplashCoord)(spanXMax + 1) <= xMin || (SplashCoord)spanXMin >= xMax || + (SplashCoord)(spanY + 1) <= yMin || (SplashCoord)spanY >= yMax) { + return splashClipAllOutside; + } + if (!((SplashCoord)spanXMin >= xMin && (SplashCoord)(spanXMax + 1) <= xMax && + (SplashCoord)spanY >= yMin && (SplashCoord)(spanY + 1) <= yMax)) { + return splashClipPartial; + } + if (antialias) { + for (i = 0; i < length; ++i) { + if (!scanners[i]->testSpan(spanXMin * splashAASize, + spanXMax * splashAASize + (splashAASize - 1), + spanY * splashAASize)) { + return splashClipPartial; + } + } + } else { + for (i = 0; i < length; ++i) { + if (!scanners[i]->testSpan(spanXMin, spanXMax, spanY)) { + return splashClipPartial; + } + } + } + return splashClipAllInside; +} + +void SplashClip::clipAALine(SplashBitmap *aaBuf, int *x0, int *x1, int y, GBool adjustVertLine) { + int xx0, xx1, xx, yy, i; + SplashColorPtr p; + + // zero out pixels with x < xMin + xx0 = *x0 * splashAASize; + xx1 = splashFloor(xMin * splashAASize); + if (xx1 > aaBuf->getWidth()) { + xx1 = aaBuf->getWidth(); + } + if (xx0 < xx1) { + xx0 &= ~7; + for (yy = 0; yy < splashAASize; ++yy) { + p = aaBuf->getDataPtr() + yy * aaBuf->getRowSize() + (xx0 >> 3); + for (xx = xx0; xx + 7 < xx1; xx += 8) { + *p++ = 0; + } + if (xx < xx1 && !adjustVertLine) { + *p &= 0xff >> (xx1 & 7); + } + } + *x0 = splashFloor(xMin); + } + + // zero out pixels with x > xMax + xx0 = splashFloor(xMax * splashAASize) + 1; + if (xx0 < 0) { + xx0 = 0; + } + xx1 = (*x1 + 1) * splashAASize; + if (xx0 < xx1 && !adjustVertLine) { + for (yy = 0; yy < splashAASize; ++yy) { + p = aaBuf->getDataPtr() + yy * aaBuf->getRowSize() + (xx0 >> 3); + xx = xx0; + if (xx & 7) { + *p &= 0xff00 >> (xx & 7); + xx = (xx & ~7) + 8; + ++p; + } + for (; xx < xx1; xx += 8) { + *p++ = 0; + } + } + *x1 = splashFloor(xMax); + } + + // check the paths + for (i = 0; i < length; ++i) { + scanners[i]->clipAALine(aaBuf, x0, x1, y); + } + if (*x0 > *x1) { + *x0 = *x1; + } + if (*x0 < 0) { + *x0 = 0; + } + if ((*x0>>1) >= aaBuf->getRowSize()) { + xx0 = *x0; + *x0 = (aaBuf->getRowSize() - 1) << 1; + if (xx0 & 1) { + *x0 = *x0 + 1; + } + } + if (*x1 < *x0) { + *x1 = *x0; + } + if ((*x1>>1) >= aaBuf->getRowSize()) { + xx0 = *x1; + *x1 = (aaBuf->getRowSize() - 1) << 1; + if (xx0 & 1) { + *x1 = *x1 + 1; + } + } +} diff --git a/Build/source/libs/poppler/poppler-0.33.0/splash/SplashClip.h b/Build/source/libs/poppler/poppler-0.33.0/splash/SplashClip.h new file mode 100644 index 00000000000..5c0fdba99a7 --- /dev/null +++ b/Build/source/libs/poppler/poppler-0.33.0/splash/SplashClip.h @@ -0,0 +1,152 @@ +//======================================================================== +// +// SplashClip.h +// +//======================================================================== + +//======================================================================== +// +// Modified under the Poppler project - http://poppler.freedesktop.org +// +// All changes made under the Poppler project to this file are licensed +// under GPL version 2 or later +// +// Copyright (C) 2010 Albert Astals Cid <aacid@kde.org> +// Copyright (C) 2013 Thomas Freitag <Thomas.Freitag@alfa.de> +// +// To see a description of the changes please see the Changelog file that +// came with your tarball or type make ChangeLog if you are building from git +// +//======================================================================== + +#ifndef SPLASHCLIP_H +#define SPLASHCLIP_H + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "SplashTypes.h" +#include "SplashMath.h" +#include "SplashXPathScanner.h" + +class SplashPath; +class SplashXPath; +class SplashBitmap; + +//------------------------------------------------------------------------ + +enum SplashClipResult { + splashClipAllInside, + splashClipAllOutside, + splashClipPartial +}; + +//------------------------------------------------------------------------ +// SplashClip +//------------------------------------------------------------------------ + +class SplashClip { +public: + + // Create a clip, for the given rectangle. + SplashClip(SplashCoord x0, SplashCoord y0, + SplashCoord x1, SplashCoord y1, + GBool antialiasA); + + // Copy a clip. + SplashClip *copy() { return new SplashClip(this); } + + ~SplashClip(); + + // Reset the clip to a rectangle. + void resetToRect(SplashCoord x0, SplashCoord y0, + SplashCoord x1, SplashCoord y1); + + // Intersect the clip with a rectangle. + SplashError clipToRect(SplashCoord x0, SplashCoord y0, + SplashCoord x1, SplashCoord y1); + + // Interesect the clip with <path>. + SplashError clipToPath(SplashPath *path, SplashCoord *matrix, + SplashCoord flatness, GBool eo); + + // Returns true if (<x>,<y>) is inside the clip. + GBool test(int x, int y) + { + int i; + + // check the rectangle + if (x < xMinI || x > xMaxI || y < yMinI || y > yMaxI) { + return gFalse; + } + + // check the paths + if (antialias) { + for (i = 0; i < length; ++i) { + if (!scanners[i]->test(x * splashAASize, y * splashAASize)) { + return gFalse; + } + } + } else { + for (i = 0; i < length; ++i) { + if (!scanners[i]->test(x, y)) { + return gFalse; + } + } + } + + return gTrue; + } + + // Tests a rectangle against the clipping region. Returns one of: + // - splashClipAllInside if the entire rectangle is inside the + // clipping region, i.e., all pixels in the rectangle are + // visible + // - splashClipAllOutside if the entire rectangle is outside the + // clipping region, i.e., all the pixels in the rectangle are + // clipped + // - splashClipPartial if the rectangle is part inside and part + // outside the clipping region + SplashClipResult testRect(int rectXMin, int rectYMin, + int rectXMax, int rectYMax); + + // Similar to testRect, but tests a horizontal span. + SplashClipResult testSpan(int spanXMin, int spanXMax, int spanY); + + // Clips an anti-aliased line by setting pixels to zero. On entry, + // all non-zero pixels are between <x0> and <x1>. This function + // will update <x0> and <x1>. + void clipAALine(SplashBitmap *aaBuf, int *x0, int *x1, int y, + GBool adjustVertLine = gFalse); + + // Get the rectangle part of the clip region. + SplashCoord getXMin() { return xMin; } + SplashCoord getXMax() { return xMax; } + SplashCoord getYMin() { return yMin; } + SplashCoord getYMax() { return yMax; } + + // Get the rectangle part of the clip region, in integer coordinates. + int getXMinI() { return xMinI; } + int getXMaxI() { return xMaxI; } + int getYMinI() { return yMinI; } + int getYMaxI() { return yMaxI; } + + // Get the number of arbitrary paths used by the clip region. + int getNumPaths() { return length; } + +protected: + + SplashClip(SplashClip *clip); + void grow(int nPaths); + + GBool antialias; + SplashCoord xMin, yMin, xMax, yMax; + int xMinI, yMinI, xMaxI, yMaxI; + SplashXPath **paths; + Guchar *flags; + SplashXPathScanner **scanners; + int length, size; +}; + +#endif diff --git a/Build/source/libs/poppler/poppler-0.33.0/splash/SplashErrorCodes.h b/Build/source/libs/poppler/poppler-0.33.0/splash/SplashErrorCodes.h new file mode 100644 index 00000000000..d1f81f85dd8 --- /dev/null +++ b/Build/source/libs/poppler/poppler-0.33.0/splash/SplashErrorCodes.h @@ -0,0 +1,50 @@ +//======================================================================== +// +// SplashErrorCodes.h +// +//======================================================================== + +//======================================================================== +// +// Modified under the Poppler project - http://poppler.freedesktop.org +// +// All changes made under the Poppler project to this file are licensed +// under GPL version 2 or later +// +// Copyright (C) 2006, 2009 Albert Astals Cid <aacid@kde.org> +// +// To see a description of the changes please see the Changelog file that +// came with your tarball or type make ChangeLog if you are building from git +// +//======================================================================== + +#ifndef SPLASHERRORCODES_H +#define SPLASHERRORCODES_H + +//------------------------------------------------------------------------ + +#define splashOk 0 // no error + +#define splashErrNoCurPt 1 // no current point + +#define splashErrEmptyPath 2 // zero points in path + +#define splashErrBogusPath 3 // only one point in subpath + +#define splashErrNoSave 4 // state stack is empty + +#define splashErrOpenFile 5 // couldn't open file + +#define splashErrNoGlyph 6 // couldn't get the requested glyph + +#define splashErrModeMismatch 7 // invalid combination of color modes + +#define splashErrSingularMatrix 8 // matrix is singular + +#define splashErrBadArg 9 // bad argument + +#define splashErrZeroImage 254 // image of 0x0 + +#define splashErrGeneric 255 + +#endif diff --git a/Build/source/libs/poppler/poppler-0.33.0/splash/SplashFTFont.cc b/Build/source/libs/poppler/poppler-0.33.0/splash/SplashFTFont.cc new file mode 100644 index 00000000000..b785826d66b --- /dev/null +++ b/Build/source/libs/poppler/poppler-0.33.0/splash/SplashFTFont.cc @@ -0,0 +1,513 @@ +//======================================================================== +// +// SplashFTFont.cc +// +//======================================================================== + +//======================================================================== +// +// Modified under the Poppler project - http://poppler.freedesktop.org +// +// All changes made under the Poppler project to this file are licensed +// under GPL version 2 or later +// +// Copyright (C) 2005, 2007-2011, 2014 Albert Astals Cid <aacid@kde.org> +// Copyright (C) 2006 Kristian Høgsberg <krh@bitplanet.net> +// Copyright (C) 2009 Petr Gajdos <pgajdos@novell.com> +// Copyright (C) 2010 Suzuki Toshiya <mpsuzuki@hiroshima-u.ac.jp> +// Copyright (C) 2011 Andreas Hartmetz <ahartmetz@gmail.com> +// Copyright (C) 2012 Thomas Freitag <Thomas.Freitag@alfa.de> +// +// To see a description of the changes please see the Changelog file that +// came with your tarball or type make ChangeLog if you are building from git +// +//======================================================================== + +#include <config.h> + +#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include <ft2build.h> +#include FT_OUTLINE_H +#include FT_SIZES_H +#include FT_GLYPH_H +#include "goo/gmem.h" +#include "SplashMath.h" +#include "SplashGlyphBitmap.h" +#include "SplashPath.h" +#include "SplashFTFontEngine.h" +#include "SplashFTFontFile.h" +#include "SplashFTFont.h" + +//------------------------------------------------------------------------ + +static int glyphPathMoveTo(const FT_Vector *pt, void *path); +static int glyphPathLineTo(const FT_Vector *pt, void *path); +static int glyphPathConicTo(const FT_Vector *ctrl, const FT_Vector *pt, + void *path); +static int glyphPathCubicTo(const FT_Vector *ctrl1, const FT_Vector *ctrl2, + const FT_Vector *pt, void *path); + +//------------------------------------------------------------------------ +// SplashFTFont +//------------------------------------------------------------------------ + +SplashFTFont::SplashFTFont(SplashFTFontFile *fontFileA, SplashCoord *matA, + SplashCoord *textMatA): + SplashFont(fontFileA, matA, textMatA, fontFileA->engine->aa), + enableFreeTypeHinting(fontFileA->engine->enableFreeTypeHinting), + enableSlightHinting(fontFileA->engine->enableSlightHinting) +{ + FT_Face face; + int div; + int x, y; +#if USE_FIXEDPOINT + SplashCoord scale; +#endif + + face = fontFileA->face; + if (FT_New_Size(face, &sizeObj)) { + return; + } + face->size = sizeObj; + size = splashRound(splashDist(0, 0, mat[2], mat[3])); + if (size < 1) { + size = 1; + } + if (FT_Set_Pixel_Sizes(face, 0, size)) { + return; + } + // if the textMat values are too small, FreeType's fixed point + // arithmetic doesn't work so well + textScale = splashDist(0, 0, textMat[2], textMat[3]) / size; + + div = face->bbox.xMax > 20000 ? 65536 : 1; + +#if USE_FIXEDPOINT + scale = (SplashCoord)1 / (SplashCoord)face->units_per_EM; + + // transform the four corners of the font bounding box -- the min + // and max values form the bounding box of the transformed font + x = (int)(mat[0] * (scale * (face->bbox.xMin / div)) + + mat[2] * (scale * (face->bbox.yMin / div))); + xMin = xMax = x; + y = (int)(mat[1] * (scale * (face->bbox.xMin / div)) + + mat[3] * (scale * (face->bbox.yMin / div))); + yMin = yMax = y; + x = (int)(mat[0] * (scale * (face->bbox.xMin / div)) + + mat[2] * (scale * (face->bbox.yMax / div))); + if (x < xMin) { + xMin = x; + } else if (x > xMax) { + xMax = x; + } + y = (int)(mat[1] * (scale * (face->bbox.xMin / div)) + + mat[3] * (scale * (face->bbox.yMax / div))); + if (y < yMin) { + yMin = y; + } else if (y > yMax) { + yMax = y; + } + x = (int)(mat[0] * (scale * (face->bbox.xMax / div)) + + mat[2] * (scale * (face->bbox.yMin / div))); + if (x < xMin) { + xMin = x; + } else if (x > xMax) { + xMax = x; + } + y = (int)(mat[1] * (scale * (face->bbox.xMax / div)) + + mat[3] * (scale * (face->bbox.yMin / div))); + if (y < yMin) { + yMin = y; + } else if (y > yMax) { + yMax = y; + } + x = (int)(mat[0] * (scale * (face->bbox.xMax / div)) + + mat[2] * (scale * (face->bbox.yMax / div))); + if (x < xMin) { + xMin = x; + } else if (x > xMax) { + xMax = x; + } + y = (int)(mat[1] * (scale * (face->bbox.xMax / div)) + + mat[3] * (scale * (face->bbox.yMax / div))); + if (y < yMin) { + yMin = y; + } else if (y > yMax) { + yMax = y; + } +#else // USE_FIXEDPOINT + // transform the four corners of the font bounding box -- the min + // and max values form the bounding box of the transformed font + x = (int)((mat[0] * face->bbox.xMin + mat[2] * face->bbox.yMin) / + (div * face->units_per_EM)); + xMin = xMax = x; + y = (int)((mat[1] * face->bbox.xMin + mat[3] * face->bbox.yMin) / + (div * face->units_per_EM)); + yMin = yMax = y; + x = (int)((mat[0] * face->bbox.xMin + mat[2] * face->bbox.yMax) / + (div * face->units_per_EM)); + if (x < xMin) { + xMin = x; + } else if (x > xMax) { + xMax = x; + } + y = (int)((mat[1] * face->bbox.xMin + mat[3] * face->bbox.yMax) / + (div * face->units_per_EM)); + if (y < yMin) { + yMin = y; + } else if (y > yMax) { + yMax = y; + } + x = (int)((mat[0] * face->bbox.xMax + mat[2] * face->bbox.yMin) / + (div * face->units_per_EM)); + if (x < xMin) { + xMin = x; + } else if (x > xMax) { + xMax = x; + } + y = (int)((mat[1] * face->bbox.xMax + mat[3] * face->bbox.yMin) / + (div * face->units_per_EM)); + if (y < yMin) { + yMin = y; + } else if (y > yMax) { + yMax = y; + } + x = (int)((mat[0] * face->bbox.xMax + mat[2] * face->bbox.yMax) / + (div * face->units_per_EM)); + if (x < xMin) { + xMin = x; + } else if (x > xMax) { + xMax = x; + } + y = (int)((mat[1] * face->bbox.xMax + mat[3] * face->bbox.yMax) / + (div * face->units_per_EM)); + if (y < yMin) { + yMin = y; + } else if (y > yMax) { + yMax = y; + } +#endif // USE_FIXEDPOINT + // This is a kludge: some buggy PDF generators embed fonts with + // zero bounding boxes. + if (xMax == xMin) { + xMin = 0; + xMax = size; + } + if (yMax == yMin) { + yMin = 0; + yMax = (int)((SplashCoord)1.2 * size); + } + + // compute the transform matrix +#if USE_FIXEDPOINT + matrix.xx = (FT_Fixed)((mat[0] / size).get16Dot16()); + matrix.yx = (FT_Fixed)((mat[1] / size).get16Dot16()); + matrix.xy = (FT_Fixed)((mat[2] / size).get16Dot16()); + matrix.yy = (FT_Fixed)((mat[3] / size).get16Dot16()); + textMatrix.xx = (FT_Fixed)((textMat[0] / (textScale * size)).get16Dot16()); + textMatrix.yx = (FT_Fixed)((textMat[1] / (textScale * size)).get16Dot16()); + textMatrix.xy = (FT_Fixed)((textMat[2] / (textScale * size)).get16Dot16()); + textMatrix.yy = (FT_Fixed)((textMat[3] / (textScale * size)).get16Dot16()); +#else + matrix.xx = (FT_Fixed)((mat[0] / size) * 65536); + matrix.yx = (FT_Fixed)((mat[1] / size) * 65536); + matrix.xy = (FT_Fixed)((mat[2] / size) * 65536); + matrix.yy = (FT_Fixed)((mat[3] / size) * 65536); + textMatrix.xx = (FT_Fixed)((textMat[0] / (textScale * size)) * 65536); + textMatrix.yx = (FT_Fixed)((textMat[1] / (textScale * size)) * 65536); + textMatrix.xy = (FT_Fixed)((textMat[2] / (textScale * size)) * 65536); + textMatrix.yy = (FT_Fixed)((textMat[3] / (textScale * size)) * 65536); +#endif +} + +SplashFTFont::~SplashFTFont() { +} + +GBool SplashFTFont::getGlyph(int c, int xFrac, int yFrac, + SplashGlyphBitmap *bitmap, int x0, int y0, SplashClip *clip, SplashClipResult *clipRes) { + return SplashFont::getGlyph(c, xFrac, 0, bitmap, x0, y0, clip, clipRes); +} + +static FT_Int32 getFTLoadFlags(GBool type1, GBool trueType, GBool aa, GBool enableFreeTypeHinting, GBool enableSlightHinting) +{ + int ret = FT_LOAD_DEFAULT; + if (aa) + ret |= FT_LOAD_NO_BITMAP; + + if (enableFreeTypeHinting) { + if (enableSlightHinting) { + ret |= FT_LOAD_TARGET_LIGHT; + } else { + if (trueType) { + // FT2's autohinting doesn't always work very well (especially with + // font subsets), so turn it off if anti-aliasing is enabled; if + // anti-aliasing is disabled, this seems to be a tossup - some fonts + // look better with hinting, some without, so leave hinting on + if (aa) { + ret |= FT_LOAD_NO_AUTOHINT; + } + } else if (type1) { + // Type 1 fonts seem to look better with 'light' hinting mode + ret |= FT_LOAD_TARGET_LIGHT; + } + } + } else { + ret |= FT_LOAD_NO_HINTING; + } + return ret; +} + +GBool SplashFTFont::makeGlyph(int c, int xFrac, int yFrac, + SplashGlyphBitmap *bitmap, int x0, int y0, SplashClip *clip, SplashClipResult *clipRes) { + SplashFTFontFile *ff; + FT_Vector offset; + FT_GlyphSlot slot; + FT_UInt gid; + int rowSize; + Guchar *p, *q; + int i; + + ff = (SplashFTFontFile *)fontFile; + + ff->face->size = sizeObj; + offset.x = (FT_Pos)(int)((SplashCoord)xFrac * splashFontFractionMul * 64); + offset.y = 0; + FT_Set_Transform(ff->face, &matrix, &offset); + slot = ff->face->glyph; + + if (ff->codeToGID && c < ff->codeToGIDLen && c >= 0) { + gid = (FT_UInt)ff->codeToGID[c]; + } else { + gid = (FT_UInt)c; + } + + if (FT_Load_Glyph(ff->face, gid, getFTLoadFlags(ff->type1, ff->trueType, aa, enableFreeTypeHinting, enableSlightHinting))) { + return gFalse; + } + + // prelimirary values based on FT_Outline_Get_CBox + // we add two pixels to each side to be in the safe side + FT_BBox cbox; + FT_Outline_Get_CBox(&ff->face->glyph->outline, &cbox); + bitmap->x = -(cbox.xMin / 64) + 2; + bitmap->y = (cbox.yMax / 64) + 2; + bitmap->w = ((cbox.xMax - cbox.xMin) / 64) + 4; + bitmap->h = ((cbox.yMax - cbox.yMin) / 64) + 4; + + *clipRes = clip->testRect(x0 - bitmap->x, + y0 - bitmap->y, + x0 - bitmap->x + bitmap->w, + y0 - bitmap->y + bitmap->h); + if (*clipRes == splashClipAllOutside) { + bitmap->freeData = gFalse; + return gTrue; + } + + if (FT_Render_Glyph(slot, aa ? ft_render_mode_normal + : ft_render_mode_mono)) { + return gFalse; + } + + if (slot->bitmap.width == 0 || slot->bitmap.rows == 0) { + // this can happen if (a) the glyph is really tiny or (b) the + // metrics in the TrueType file are broken + return gFalse; + } + + bitmap->x = -slot->bitmap_left; + bitmap->y = slot->bitmap_top; + bitmap->w = slot->bitmap.width; + bitmap->h = slot->bitmap.rows; + bitmap->aa = aa; + if (aa) { + rowSize = bitmap->w; + } else { + rowSize = (bitmap->w + 7) >> 3; + } + bitmap->data = (Guchar *)gmallocn_checkoverflow(rowSize, bitmap->h); + if (!bitmap->data) { + return gFalse; + } + bitmap->freeData = gTrue; + for (i = 0, p = bitmap->data, q = slot->bitmap.buffer; + i < bitmap->h; + ++i, p += rowSize, q += slot->bitmap.pitch) { + memcpy(p, q, rowSize); + } + + return gTrue; +} + +double SplashFTFont::getGlyphAdvance(int c) +{ + SplashFTFontFile *ff; + FT_Vector offset; + FT_UInt gid; + FT_Matrix identityMatrix; + + ff = (SplashFTFontFile *)fontFile; + + // init the matrix + identityMatrix.xx = 65536; // 1 in 16.16 format + identityMatrix.xy = 0; + identityMatrix.yx = 0; + identityMatrix.yy = 65536; // 1 in 16.16 format + + // init the offset + offset.x = 0; + offset.y = 0; + + ff->face->size = sizeObj; + FT_Set_Transform(ff->face, &identityMatrix, &offset); + + if (ff->codeToGID && c < ff->codeToGIDLen) { + gid = (FT_UInt)ff->codeToGID[c]; + } else { + gid = (FT_UInt)c; + } + + if (FT_Load_Glyph(ff->face, gid, getFTLoadFlags(ff->type1, ff->trueType, aa, enableFreeTypeHinting, enableSlightHinting))) { + return -1; + } + + // 64.0 is 1 in 26.6 format + return ff->face->glyph->metrics.horiAdvance / 64.0 / size; +} + +struct SplashFTFontPath { + SplashPath *path; + SplashCoord textScale; + GBool needClose; +}; + +SplashPath *SplashFTFont::getGlyphPath(int c) { + static FT_Outline_Funcs outlineFuncs = { +#if FREETYPE_MINOR <= 1 + (int (*)(FT_Vector *, void *))&glyphPathMoveTo, + (int (*)(FT_Vector *, void *))&glyphPathLineTo, + (int (*)(FT_Vector *, FT_Vector *, void *))&glyphPathConicTo, + (int (*)(FT_Vector *, FT_Vector *, FT_Vector *, void *))&glyphPathCubicTo, +#else + &glyphPathMoveTo, + &glyphPathLineTo, + &glyphPathConicTo, + &glyphPathCubicTo, +#endif + 0, 0 + }; + SplashFTFontFile *ff; + SplashFTFontPath path; + FT_GlyphSlot slot; + FT_UInt gid; + FT_Glyph glyph; + + ff = (SplashFTFontFile *)fontFile; + ff->face->size = sizeObj; + FT_Set_Transform(ff->face, &textMatrix, NULL); + slot = ff->face->glyph; + if (ff->codeToGID && c < ff->codeToGIDLen && c >= 0) { + gid = ff->codeToGID[c]; + } else { + gid = (FT_UInt)c; + } + if (FT_Load_Glyph(ff->face, gid, getFTLoadFlags(ff->type1, ff->trueType, aa, enableFreeTypeHinting, enableSlightHinting))) { + return NULL; + } + if (FT_Get_Glyph(slot, &glyph)) { + return NULL; + } + if (FT_Outline_Check(&((FT_OutlineGlyph)glyph)->outline)) { + return NULL; + } + path.path = new SplashPath(); + path.textScale = textScale; + path.needClose = gFalse; + FT_Outline_Decompose(&((FT_OutlineGlyph)glyph)->outline, + &outlineFuncs, &path); + if (path.needClose) { + path.path->close(); + } + FT_Done_Glyph(glyph); + return path.path; +} + +static int glyphPathMoveTo(const FT_Vector *pt, void *path) { + SplashFTFontPath *p = (SplashFTFontPath *)path; + + if (p->needClose) { + p->path->close(); + p->needClose = gFalse; + } + p->path->moveTo((SplashCoord)pt->x * p->textScale / 64.0, + (SplashCoord)pt->y * p->textScale / 64.0); + return 0; +} + +static int glyphPathLineTo(const FT_Vector *pt, void *path) { + SplashFTFontPath *p = (SplashFTFontPath *)path; + + p->path->lineTo((SplashCoord)pt->x * p->textScale / 64.0, + (SplashCoord)pt->y * p->textScale / 64.0); + p->needClose = gTrue; + return 0; +} + +static int glyphPathConicTo(const FT_Vector *ctrl, const FT_Vector *pt, + void *path) { + SplashFTFontPath *p = (SplashFTFontPath *)path; + SplashCoord x0, y0, x1, y1, x2, y2, x3, y3, xc, yc; + + if (!p->path->getCurPt(&x0, &y0)) { + return 0; + } + xc = (SplashCoord)ctrl->x * p->textScale / 64.0; + yc = (SplashCoord)ctrl->y * p->textScale / 64.0; + x3 = (SplashCoord)pt->x * p->textScale / 64.0; + y3 = (SplashCoord)pt->y * p->textScale / 64.0; + + // A second-order Bezier curve is defined by two endpoints, p0 and + // p3, and one control point, pc: + // + // p(t) = (1-t)^2*p0 + t*(1-t)*pc + t^2*p3 + // + // A third-order Bezier curve is defined by the same two endpoints, + // p0 and p3, and two control points, p1 and p2: + // + // p(t) = (1-t)^3*p0 + 3t*(1-t)^2*p1 + 3t^2*(1-t)*p2 + t^3*p3 + // + // Applying some algebra, we can convert a second-order curve to a + // third-order curve: + // + // p1 = (1/3) * (p0 + 2pc) + // p2 = (1/3) * (2pc + p3) + + x1 = (SplashCoord)(1.0 / 3.0) * (x0 + (SplashCoord)2 * xc); + y1 = (SplashCoord)(1.0 / 3.0) * (y0 + (SplashCoord)2 * yc); + x2 = (SplashCoord)(1.0 / 3.0) * ((SplashCoord)2 * xc + x3); + y2 = (SplashCoord)(1.0 / 3.0) * ((SplashCoord)2 * yc + y3); + + p->path->curveTo(x1, y1, x2, y2, x3, y3); + p->needClose = gTrue; + return 0; +} + +static int glyphPathCubicTo(const FT_Vector *ctrl1, const FT_Vector *ctrl2, + const FT_Vector *pt, void *path) { + SplashFTFontPath *p = (SplashFTFontPath *)path; + + p->path->curveTo((SplashCoord)ctrl1->x * p->textScale / 64.0, + (SplashCoord)ctrl1->y * p->textScale / 64.0, + (SplashCoord)ctrl2->x * p->textScale / 64.0, + (SplashCoord)ctrl2->y * p->textScale / 64.0, + (SplashCoord)pt->x * p->textScale / 64.0, + (SplashCoord)pt->y * p->textScale / 64.0); + p->needClose = gTrue; + return 0; +} + +#endif // HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H diff --git a/Build/source/libs/poppler/poppler-0.33.0/splash/SplashFTFont.h b/Build/source/libs/poppler/poppler-0.33.0/splash/SplashFTFont.h new file mode 100644 index 00000000000..98cb29dfbba --- /dev/null +++ b/Build/source/libs/poppler/poppler-0.33.0/splash/SplashFTFont.h @@ -0,0 +1,80 @@ +//======================================================================== +// +// SplashFTFont.h +// +//======================================================================== + +//======================================================================== +// +// Modified under the Poppler project - http://poppler.freedesktop.org +// +// All changes made under the Poppler project to this file are licensed +// under GPL version 2 or later +// +// Copyright (C) 2007-2009, 2011 Albert Astals Cid <aacid@kde.org> +// Copyright (C) 2009 Petr Gajdos <pgajdos@novell.com> +// Copyright (C) 2011 Andreas Hartmetz <ahartmetz@gmail.com> +// +// To see a description of the changes please see the Changelog file that +// came with your tarball or type make ChangeLog if you are building from git +// +//======================================================================== + +#ifndef SPLASHFTFONT_H +#define SPLASHFTFONT_H + +#include "poppler-config.h" + +#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include <ft2build.h> +#include FT_FREETYPE_H +#include "SplashFont.h" + +class SplashFTFontFile; + +//------------------------------------------------------------------------ +// SplashFTFont +//------------------------------------------------------------------------ + +class SplashFTFont: public SplashFont { +public: + + SplashFTFont(SplashFTFontFile *fontFileA, SplashCoord *matA, + SplashCoord *textMatA); + + virtual ~SplashFTFont(); + + // Munge xFrac and yFrac before calling SplashFont::getGlyph. + virtual GBool getGlyph(int c, int xFrac, int yFrac, + SplashGlyphBitmap *bitmap, int x0, int y0, SplashClip *clip, SplashClipResult *clipRes); + + // Rasterize a glyph. The <xFrac> and <yFrac> values are the same + // as described for getGlyph. + virtual GBool makeGlyph(int c, int xFrac, int yFrac, + SplashGlyphBitmap *bitmap, int x0, int y0, SplashClip *clip, SplashClipResult *clipRes); + + // Return the path for a glyph. + virtual SplashPath *getGlyphPath(int c); + + // Return the advance of a glyph. (in 0..1 range) + virtual double getGlyphAdvance(int c); + +private: + + FT_Size sizeObj; + FT_Matrix matrix; + FT_Matrix textMatrix; + SplashCoord textScale; + int size; + GBool enableFreeTypeHinting; + GBool enableSlightHinting; +}; + +#endif // HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H + +#endif diff --git a/Build/source/libs/poppler/poppler-0.33.0/splash/SplashFTFontEngine.cc b/Build/source/libs/poppler/poppler-0.33.0/splash/SplashFTFontEngine.cc new file mode 100644 index 00000000000..9fef8f007d1 --- /dev/null +++ b/Build/source/libs/poppler/poppler-0.33.0/splash/SplashFTFontEngine.cc @@ -0,0 +1,180 @@ +//======================================================================== +// +// SplashFTFontEngine.cc +// +//======================================================================== + +//======================================================================== +// +// Modified under the Poppler project - http://poppler.freedesktop.org +// +// All changes made under the Poppler project to this file are licensed +// under GPL version 2 or later +// +// Copyright (C) 2006 Takashi Iwai <tiwai@suse.de> +// Copyright (C) 2009, 2011, 2012 Albert Astals Cid <aacid@kde.org> +// Copyright (C) 2009 Petr Gajdos <pgajdos@novell.com> +// Copyright (C) 2011 Andreas Hartmetz <ahartmetz@gmail.com> +// +// To see a description of the changes please see the Changelog file that +// came with your tarball or type make ChangeLog if you are building from git +// +//======================================================================== + +#include <config.h> + +#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include <stdio.h> +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#include "goo/gmem.h" +#include "goo/GooString.h" +#include "goo/gfile.h" +#include "fofi/FoFiTrueType.h" +#include "fofi/FoFiType1C.h" +#include "SplashFTFontFile.h" +#include "SplashFTFontEngine.h" + +#ifdef VMS +#if (__VMS_VER < 70000000) +extern "C" int unlink(char *filename); +#endif +#endif + +//------------------------------------------------------------------------ +// SplashFTFontEngine +//------------------------------------------------------------------------ + +SplashFTFontEngine::SplashFTFontEngine(GBool aaA, GBool enableFreeTypeHintingA, + GBool enableSlightHintingA, FT_Library libA) { + FT_Int major, minor, patch; + + aa = aaA; + enableFreeTypeHinting = enableFreeTypeHintingA; + enableSlightHinting = enableSlightHintingA; + lib = libA; + + // as of FT 2.1.8, CID fonts are indexed by CID instead of GID + FT_Library_Version(lib, &major, &minor, &patch); + useCIDs = major > 2 || + (major == 2 && (minor > 1 || (minor == 1 && patch > 7))); +} + +SplashFTFontEngine *SplashFTFontEngine::init(GBool aaA, GBool enableFreeTypeHintingA, + GBool enableSlightHintingA) { + FT_Library libA; + + if (FT_Init_FreeType(&libA)) { + return NULL; + } + return new SplashFTFontEngine(aaA, enableFreeTypeHintingA, enableSlightHintingA, libA); +} + +SplashFTFontEngine::~SplashFTFontEngine() { + FT_Done_FreeType(lib); +} + +SplashFontFile *SplashFTFontEngine::loadType1Font(SplashFontFileID *idA, + SplashFontSrc *src, + const char **enc) { + return SplashFTFontFile::loadType1Font(this, idA, src, enc); +} + +SplashFontFile *SplashFTFontEngine::loadType1CFont(SplashFontFileID *idA, + SplashFontSrc *src, + const char **enc) { + return SplashFTFontFile::loadType1Font(this, idA, src, enc); +} + +SplashFontFile *SplashFTFontEngine::loadOpenTypeT1CFont(SplashFontFileID *idA, + SplashFontSrc *src, + const char **enc) { + return SplashFTFontFile::loadType1Font(this, idA, src, enc); +} + +SplashFontFile *SplashFTFontEngine::loadCIDFont(SplashFontFileID *idA, + SplashFontSrc *src) { + FoFiType1C *ff; + int *cidToGIDMap; + int nCIDs; + SplashFontFile *ret; + + // check for a CFF font + if (useCIDs) { + cidToGIDMap = NULL; + nCIDs = 0; + } else { + if (src->isFile) { + ff = FoFiType1C::load(src->fileName->getCString()); + } else { + ff = FoFiType1C::make(src->buf, src->bufLen); + } + if (ff) { + cidToGIDMap = ff->getCIDToGIDMap(&nCIDs); + delete ff; + } else { + cidToGIDMap = NULL; + nCIDs = 0; + } + } + ret = SplashFTFontFile::loadCIDFont(this, idA, src, cidToGIDMap, nCIDs); + if (!ret) { + gfree(cidToGIDMap); + } + return ret; +} + +SplashFontFile *SplashFTFontEngine::loadOpenTypeCFFFont(SplashFontFileID *idA, + SplashFontSrc *src, + int *codeToGID, + int codeToGIDLen) { + FoFiTrueType *ff; + int *cidToGIDMap; + int nCIDs; + SplashFontFile *ret; + + cidToGIDMap = NULL; + nCIDs = 0; + if (!codeToGID) { + if (!useCIDs) { + if (src->isFile) { + ff = FoFiTrueType::load(src->fileName->getCString()); + } else { + ff = FoFiTrueType::make(src->buf, src->bufLen); + } + if (ff) { + if (ff->isOpenTypeCFF()) { + cidToGIDMap = ff->getCIDToGIDMap(&nCIDs); + } + delete ff; + } + } + } + ret = SplashFTFontFile::loadCIDFont(this, idA, src, + codeToGID ? codeToGID : cidToGIDMap, + codeToGID ? codeToGIDLen : nCIDs); + if (!ret) { + gfree(cidToGIDMap); + } + return ret; +} + +SplashFontFile *SplashFTFontEngine::loadTrueTypeFont(SplashFontFileID *idA, + SplashFontSrc *src, + int *codeToGID, + int codeToGIDLen, + int faceIndex) { + SplashFontFile *ret; + ret = SplashFTFontFile::loadTrueTypeFont(this, idA, src, + codeToGID, codeToGIDLen, + faceIndex); + return ret; +} + +#endif // HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H diff --git a/Build/source/libs/poppler/poppler-0.33.0/splash/SplashFTFontEngine.h b/Build/source/libs/poppler/poppler-0.33.0/splash/SplashFTFontEngine.h new file mode 100644 index 00000000000..11bbea74a80 --- /dev/null +++ b/Build/source/libs/poppler/poppler-0.33.0/splash/SplashFTFontEngine.h @@ -0,0 +1,81 @@ +//======================================================================== +// +// SplashFTFontEngine.h +// +//======================================================================== + +//======================================================================== +// +// Modified under the Poppler project - http://poppler.freedesktop.org +// +// All changes made under the Poppler project to this file are licensed +// under GPL version 2 or later +// +// Copyright (C) 2006 Takashi Iwai <tiwai@suse.de> +// Copyright (C) 2009 Petr Gajdos <pgajdos@novell.com> +// Copyright (C) 2009 Albert Astals Cid <aacid@kde.org> +// Copyright (C) 2011 Andreas Hartmetz <ahartmetz@gmail.com> +// Copyright (C) 2013 Thomas Freitag <Thomas.Freitag@alfa.de> +// +// To see a description of the changes please see the Changelog file that +// came with your tarball or type make ChangeLog if you are building from git +// +//======================================================================== + +#ifndef SPLASHFTFONTENGINE_H +#define SPLASHFTFONTENGINE_H + +#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include <ft2build.h> +#include FT_FREETYPE_H +#include "goo/gtypes.h" + +class SplashFontFile; +class SplashFontFileID; +class SplashFontSrc; + +//------------------------------------------------------------------------ +// SplashFTFontEngine +//------------------------------------------------------------------------ + +class SplashFTFontEngine { +public: + + static SplashFTFontEngine *init(GBool aaA, GBool enableFreeTypeHintingA, GBool enableSlightHinting); + + ~SplashFTFontEngine(); + + // Load fonts. + SplashFontFile *loadType1Font(SplashFontFileID *idA, SplashFontSrc *src, const char **enc); + SplashFontFile *loadType1CFont(SplashFontFileID *idA, SplashFontSrc *src, const char **enc); + SplashFontFile *loadOpenTypeT1CFont(SplashFontFileID *idA, SplashFontSrc *src, const char **enc); + SplashFontFile *loadCIDFont(SplashFontFileID *idA, SplashFontSrc *src); + SplashFontFile *loadOpenTypeCFFFont(SplashFontFileID *idA, SplashFontSrc *src, + int *codeToGID, int codeToGIDLen); + SplashFontFile *loadTrueTypeFont(SplashFontFileID *idA, SplashFontSrc *src, + int *codeToGID, int codeToGIDLen, int faceIndex = 0); + GBool getAA() { return aa; } + void setAA(GBool aaA) { aa = aaA; } + +private: + + SplashFTFontEngine(GBool aaA, GBool enableFreeTypeHintingA, GBool enableSlightHintingA, FT_Library libA); + + GBool aa; + GBool enableFreeTypeHinting; + GBool enableSlightHinting; + FT_Library lib; + GBool useCIDs; + + friend class SplashFTFontFile; + friend class SplashFTFont; +}; + +#endif // HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H + +#endif diff --git a/Build/source/libs/poppler/poppler-0.33.0/splash/SplashFTFontFile.cc b/Build/source/libs/poppler/poppler-0.33.0/splash/SplashFTFontFile.cc new file mode 100644 index 00000000000..f0dcf50384b --- /dev/null +++ b/Build/source/libs/poppler/poppler-0.33.0/splash/SplashFTFontFile.cc @@ -0,0 +1,148 @@ +//======================================================================== +// +// SplashFTFontFile.cc +// +//======================================================================== + +//======================================================================== +// +// Modified under the Poppler project - http://poppler.freedesktop.org +// +// All changes made under the Poppler project to this file are licensed +// under GPL version 2 or later +// +// Copyright (C) 2006 Takashi Iwai <tiwai@suse.de> +// Copyright (C) 2014 Adrian Johnson <ajohnson@redneon.com> +// +// To see a description of the changes please see the Changelog file that +// came with your tarball or type make ChangeLog if you are building from git +// +//======================================================================== + +#include <config.h> + +#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include "goo/gmem.h" +#include "goo/GooString.h" +#include "poppler/GfxFont.h" +#include "SplashFTFontEngine.h" +#include "SplashFTFont.h" +#include "SplashFTFontFile.h" + +//------------------------------------------------------------------------ +// SplashFTFontFile +//------------------------------------------------------------------------ + +SplashFontFile *SplashFTFontFile::loadType1Font(SplashFTFontEngine *engineA, + SplashFontFileID *idA, + SplashFontSrc *src, + const char **encA) { + FT_Face faceA; + int *codeToGIDA; + const char *name; + int i; + + if (src->isFile) { + if (FT_New_Face(engineA->lib, src->fileName->getCString(), 0, &faceA)) + return NULL; + } else { + if (FT_New_Memory_Face(engineA->lib, (const FT_Byte *)src->buf, src->bufLen, 0, &faceA)) + return NULL; + } + codeToGIDA = (int *)gmallocn(256, sizeof(int)); + for (i = 0; i < 256; ++i) { + codeToGIDA[i] = 0; + if ((name = encA[i])) { + codeToGIDA[i] = (int)FT_Get_Name_Index(faceA, (char *)name); + if (codeToGIDA[i] == 0) { + name = GfxFont::getAlternateName(name); + if (name) { + codeToGIDA[i] = FT_Get_Name_Index(faceA, (char *)name); + } + } + } + } + + return new SplashFTFontFile(engineA, idA, src, + faceA, codeToGIDA, 256, gFalse, gTrue); +} + +SplashFontFile *SplashFTFontFile::loadCIDFont(SplashFTFontEngine *engineA, + SplashFontFileID *idA, + SplashFontSrc *src, + int *codeToGIDA, + int codeToGIDLenA) { + FT_Face faceA; + + if (src->isFile) { + if (FT_New_Face(engineA->lib, src->fileName->getCString(), 0, &faceA)) + return NULL; + } else { + if (FT_New_Memory_Face(engineA->lib, (const FT_Byte *)src->buf, src->bufLen, 0, &faceA)) + return NULL; + } + + return new SplashFTFontFile(engineA, idA, src, + faceA, codeToGIDA, codeToGIDLenA, gFalse, gFalse); +} + +SplashFontFile *SplashFTFontFile::loadTrueTypeFont(SplashFTFontEngine *engineA, + SplashFontFileID *idA, + SplashFontSrc *src, + int *codeToGIDA, + int codeToGIDLenA, + int faceIndexA) { + FT_Face faceA; + + if (src->isFile) { + if (FT_New_Face(engineA->lib, src->fileName->getCString(), faceIndexA, &faceA)) + return NULL; + } else { + if (FT_New_Memory_Face(engineA->lib, (const FT_Byte *)src->buf, src->bufLen, faceIndexA, &faceA)) + return NULL; + } + + return new SplashFTFontFile(engineA, idA, src, + faceA, codeToGIDA, codeToGIDLenA, gTrue, gFalse); +} + +SplashFTFontFile::SplashFTFontFile(SplashFTFontEngine *engineA, + SplashFontFileID *idA, + SplashFontSrc *src, + FT_Face faceA, + int *codeToGIDA, int codeToGIDLenA, + GBool trueTypeA, GBool type1A): + SplashFontFile(idA, src) +{ + engine = engineA; + face = faceA; + codeToGID = codeToGIDA; + codeToGIDLen = codeToGIDLenA; + trueType = trueTypeA; + type1 = type1A; +} + +SplashFTFontFile::~SplashFTFontFile() { + if (face) { + FT_Done_Face(face); + } + if (codeToGID) { + gfree(codeToGID); + } +} + +SplashFont *SplashFTFontFile::makeFont(SplashCoord *mat, + SplashCoord *textMat) { + SplashFont *font; + + font = new SplashFTFont(this, mat, textMat); + font->initCache(); + return font; +} + +#endif // HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H diff --git a/Build/source/libs/poppler/poppler-0.33.0/splash/SplashFTFontFile.h b/Build/source/libs/poppler/poppler-0.33.0/splash/SplashFTFontFile.h new file mode 100644 index 00000000000..d642af0a0ab --- /dev/null +++ b/Build/source/libs/poppler/poppler-0.33.0/splash/SplashFTFontFile.h @@ -0,0 +1,86 @@ +//======================================================================== +// +// SplashFTFontFile.h +// +//======================================================================== + +//======================================================================== +// +// Modified under the Poppler project - http://poppler.freedesktop.org +// +// All changes made under the Poppler project to this file are licensed +// under GPL version 2 or later +// +// Copyright (C) 2006 Takashi Iwai <tiwai@suse.de> +// +// To see a description of the changes please see the Changelog file that +// came with your tarball or type make ChangeLog if you are building from git +// +//======================================================================== + +#ifndef SPLASHFTFONTFILE_H +#define SPLASHFTFONTFILE_H + +#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include <ft2build.h> +#include FT_FREETYPE_H +#include "SplashFontFile.h" + +class SplashFontFileID; +class SplashFTFontEngine; + +//------------------------------------------------------------------------ +// SplashFTFontFile +//------------------------------------------------------------------------ + +class SplashFTFontFile: public SplashFontFile { +public: + + static SplashFontFile *loadType1Font(SplashFTFontEngine *engineA, + SplashFontFileID *idA, + SplashFontSrc *src, const char **encA); + static SplashFontFile *loadCIDFont(SplashFTFontEngine *engineA, + SplashFontFileID *idA, + SplashFontSrc *src, + int *codeToCIDA, int codeToGIDLenA); + static SplashFontFile *loadTrueTypeFont(SplashFTFontEngine *engineA, + SplashFontFileID *idA, + SplashFontSrc *src, + int *codeToGIDA, + int codeToGIDLenA, + int faceIndexA=0); + + virtual ~SplashFTFontFile(); + + // Create a new SplashFTFont, i.e., a scaled instance of this font + // file. + virtual SplashFont *makeFont(SplashCoord *mat, + SplashCoord *textMat); + +private: + + SplashFTFontFile(SplashFTFontEngine *engineA, + SplashFontFileID *idA, + SplashFontSrc *src, + FT_Face faceA, + int *codeToGIDA, int codeToGIDLenA, + GBool trueTypeA, GBool type1A); + + SplashFTFontEngine *engine; + FT_Face face; + int *codeToGID; + int codeToGIDLen; + GBool trueType; + GBool type1; + + friend class SplashFTFont; +}; + +#endif // HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H + +#endif diff --git a/Build/source/libs/poppler/poppler-0.33.0/splash/SplashFont.cc b/Build/source/libs/poppler/poppler-0.33.0/splash/SplashFont.cc new file mode 100644 index 00000000000..3d6d6b2343e --- /dev/null +++ b/Build/source/libs/poppler/poppler-0.33.0/splash/SplashFont.cc @@ -0,0 +1,224 @@ +//======================================================================== +// +// SplashFont.cc +// +//======================================================================== + +//======================================================================== +// +// Modified under the Poppler project - http://poppler.freedesktop.org +// +// All changes made under the Poppler project to this file are licensed +// under GPL version 2 or later +// +// Copyright (C) 2007-2008, 2010, 2014 Albert Astals Cid <aacid@kde.org> +// +// To see a description of the changes please see the Changelog file that +// came with your tarball or type make ChangeLog if you are building from git +// +//======================================================================== + +#include <config.h> + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include <limits.h> +#include <string.h> +#include "goo/gmem.h" +#include "SplashMath.h" +#include "SplashGlyphBitmap.h" +#include "SplashFontFile.h" +#include "SplashFont.h" + +//------------------------------------------------------------------------ + +struct SplashFontCacheTag { + int c; + short xFrac, yFrac; // x and y fractions + int mru; // valid bit (0x80000000) and MRU index + int x, y, w, h; // offset and size of glyph +}; + +//------------------------------------------------------------------------ +// SplashFont +//------------------------------------------------------------------------ + +SplashFont::SplashFont(SplashFontFile *fontFileA, SplashCoord *matA, + SplashCoord *textMatA, GBool aaA) { + fontFile = fontFileA; + fontFile->incRefCnt(); + mat[0] = matA[0]; + mat[1] = matA[1]; + mat[2] = matA[2]; + mat[3] = matA[3]; + textMat[0] = textMatA[0]; + textMat[1] = textMatA[1]; + textMat[2] = textMatA[2]; + textMat[3] = textMatA[3]; + aa = aaA; + + cache = NULL; + cacheTags = NULL; + + xMin = yMin = xMax = yMax = 0; +} + +void SplashFont::initCache() { + int i; + + // this should be (max - min + 1), but we add some padding to + // deal with rounding errors + glyphW = xMax - xMin + 3; + glyphH = yMax - yMin + 3; + if (glyphW > INT_MAX / glyphH) { + glyphSize = -1; + } else { + if (aa) { + glyphSize = glyphW * glyphH; + } else { + glyphSize = ((glyphW + 7) >> 3) * glyphH; + } + } + + // set up the glyph pixmap cache + cacheAssoc = 8; + if (glyphSize <= 64) { + cacheSets = 32; + } else if (glyphSize <= 128) { + cacheSets = 16; + } else if (glyphSize <= 256) { + cacheSets = 8; + } else if (glyphSize <= 512) { + cacheSets = 4; + } else if (glyphSize <= 1024) { + cacheSets = 2; + } else { + cacheSets = 1; + } + cache = (Guchar *)gmallocn_checkoverflow(cacheSets* cacheAssoc, glyphSize); + if (cache != NULL) { + cacheTags = (SplashFontCacheTag *)gmallocn(cacheSets * cacheAssoc, + sizeof(SplashFontCacheTag)); + for (i = 0; i < cacheSets * cacheAssoc; ++i) { + cacheTags[i].mru = i & (cacheAssoc - 1); + } + } else { + cacheAssoc = 0; + } +} + +SplashFont::~SplashFont() { + fontFile->decRefCnt(); + if (cache) { + gfree(cache); + } + if (cacheTags) { + gfree(cacheTags); + } +} + +GBool SplashFont::getGlyph(int c, int xFrac, int yFrac, + SplashGlyphBitmap *bitmap, int x0, int y0, SplashClip *clip, SplashClipResult *clipRes) { + SplashGlyphBitmap bitmap2; + int size; + Guchar *p; + int i, j, k; + + // no fractional coordinates for large glyphs or non-anti-aliased + // glyphs + if (!aa || glyphH > 50) { + xFrac = yFrac = 0; + } + + // check the cache + i = (c & (cacheSets - 1)) * cacheAssoc; + for (j = 0; j < cacheAssoc; ++j) { + if ((cacheTags[i+j].mru & 0x80000000) && + cacheTags[i+j].c == c && + (int)cacheTags[i+j].xFrac == xFrac && + (int)cacheTags[i+j].yFrac == yFrac) { + bitmap->x = cacheTags[i+j].x; + bitmap->y = cacheTags[i+j].y; + bitmap->w = cacheTags[i+j].w; + bitmap->h = cacheTags[i+j].h; + for (k = 0; k < cacheAssoc; ++k) { + if (k != j && + (cacheTags[i+k].mru & 0x7fffffff) < + (cacheTags[i+j].mru & 0x7fffffff)) { + ++cacheTags[i+k].mru; + } + } + cacheTags[i+j].mru = 0x80000000; + bitmap->aa = aa; + bitmap->data = cache + (i+j) * glyphSize; + bitmap->freeData = gFalse; + + *clipRes = clip->testRect(x0 - bitmap->x, + y0 - bitmap->y, + x0 - bitmap->x + bitmap->w - 1, + y0 - bitmap->y + bitmap->h - 1); + + return gTrue; + } + } + + // generate the glyph bitmap + if (!makeGlyph(c, xFrac, yFrac, &bitmap2, x0, y0, clip, clipRes)) { + return gFalse; + } + + if (*clipRes == splashClipAllOutside) + { + bitmap->freeData = gFalse; + if (bitmap2.freeData) gfree(bitmap2.data); + return gTrue; + } + + // if the glyph doesn't fit in the bounding box, return a temporary + // uncached bitmap + if (bitmap2.w > glyphW || bitmap2.h > glyphH) { + *bitmap = bitmap2; + return gTrue; + } + + // insert glyph pixmap in cache + if (aa) { + size = bitmap2.w * bitmap2.h; + } else { + size = ((bitmap2.w + 7) >> 3) * bitmap2.h; + } + p = NULL; // make gcc happy + if (cacheAssoc == 0) + { + // we had problems on the malloc of the cache, so ignore it + *bitmap = bitmap2; + } + else + { + for (j = 0; j < cacheAssoc; ++j) { + if ((cacheTags[i+j].mru & 0x7fffffff) == cacheAssoc - 1) { + cacheTags[i+j].mru = 0x80000000; + cacheTags[i+j].c = c; + cacheTags[i+j].xFrac = (short)xFrac; + cacheTags[i+j].yFrac = (short)yFrac; + cacheTags[i+j].x = bitmap2.x; + cacheTags[i+j].y = bitmap2.y; + cacheTags[i+j].w = bitmap2.w; + cacheTags[i+j].h = bitmap2.h; + p = cache + (i+j) * glyphSize; + memcpy(p, bitmap2.data, size); + } else { + ++cacheTags[i+j].mru; + } + } + *bitmap = bitmap2; + bitmap->data = p; + bitmap->freeData = gFalse; + if (bitmap2.freeData) { + gfree(bitmap2.data); + } + } + return gTrue; +} diff --git a/Build/source/libs/poppler/poppler-0.33.0/splash/SplashFont.h b/Build/source/libs/poppler/poppler-0.33.0/splash/SplashFont.h new file mode 100644 index 00000000000..78b00d2dcaf --- /dev/null +++ b/Build/source/libs/poppler/poppler-0.33.0/splash/SplashFont.h @@ -0,0 +1,121 @@ +//======================================================================== +// +// SplashFont.h +// +//======================================================================== + +//======================================================================== +// +// Modified under the Poppler project - http://poppler.freedesktop.org +// +// All changes made under the Poppler project to this file are licensed +// under GPL version 2 or later +// +// Copyright (C) 2007-2008 Albert Astals Cid <aacid@kde.org> +// +// To see a description of the changes please see the Changelog file that +// came with your tarball or type make ChangeLog if you are building from git +// +//======================================================================== + +#ifndef SPLASHFONT_H +#define SPLASHFONT_H + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "goo/gtypes.h" +#include "SplashTypes.h" +#include "SplashClip.h" + +struct SplashGlyphBitmap; +struct SplashFontCacheTag; +class SplashFontFile; +class SplashPath; + +//------------------------------------------------------------------------ + +// Fractional positioning uses this many bits to the right of the +// decimal points. +#define splashFontFractionBits 2 +#define splashFontFraction (1 << splashFontFractionBits) +#define splashFontFractionMul \ + ((SplashCoord)1 / (SplashCoord)splashFontFraction) + +//------------------------------------------------------------------------ +// SplashFont +//------------------------------------------------------------------------ + +class SplashFont { +public: + + SplashFont(SplashFontFile *fontFileA, SplashCoord *matA, + SplashCoord *textMatA, GBool aaA); + + // This must be called after the constructor, so that the subclass + // constructor has a chance to compute the bbox. + void initCache(); + + virtual ~SplashFont(); + + SplashFontFile *getFontFile() { return fontFile; } + + // Return true if <this> matches the specified font file and matrix. + 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]; + } + + // Get a glyph - this does a cache lookup first, and if not found, + // creates a new bitmap and adds it to the cache. The <xFrac> and + // <yFrac> values are splashFontFractionBits bits each, representing + // the numerators of fractions in [0, 1), where the denominator is + // splashFontFraction = 1 << splashFontFractionBits. Subclasses + // should override this to zero out xFrac and/or yFrac if they don't + // support fractional coordinates. + virtual GBool getGlyph(int c, int xFrac, int yFrac, + SplashGlyphBitmap *bitmap, int x0, int y0, SplashClip *clip, SplashClipResult *clipRes); + + // Rasterize a glyph. The <xFrac> and <yFrac> values are the same + // as described for getGlyph. + virtual GBool makeGlyph(int c, int xFrac, int yFrac, + SplashGlyphBitmap *bitmap, int x0, int y0, SplashClip *clip, SplashClipResult *clipRes) = 0; + + // Return the path for a glyph. + virtual SplashPath *getGlyphPath(int c) = 0; + + // Return the advance of a glyph. (in 0..1 range) + // < 0 means not known + virtual double getGlyphAdvance(int c) { return -1; } + + // Return the font transform matrix. + SplashCoord *getMatrix() { return mat; } + + // Return the glyph bounding box. + void getBBox(int *xMinA, int *yMinA, int *xMaxA, int *yMaxA) + { *xMinA = xMin; *yMinA = yMin; *xMaxA = xMax; *yMaxA = yMax; } + +protected: + + SplashFontFile *fontFile; + SplashCoord mat[4]; // font transform matrix + // (text space -> device space) + SplashCoord textMat[4]; // text transform matrix + // (text space -> user space) + GBool aa; // anti-aliasing + int xMin, yMin, xMax, yMax; // glyph bounding box + Guchar *cache; // glyph bitmap cache + SplashFontCacheTag * // cache tags + cacheTags; + int glyphW, glyphH; // size of glyph bitmaps + int glyphSize; // size of glyph bitmaps, in bytes + int cacheSets; // number of sets in cache + int cacheAssoc; // cache associativity (glyphs per set) +}; + +#endif diff --git a/Build/source/libs/poppler/poppler-0.33.0/splash/SplashFontEngine.cc b/Build/source/libs/poppler/poppler-0.33.0/splash/SplashFontEngine.cc new file mode 100644 index 00000000000..968e8207362 --- /dev/null +++ b/Build/source/libs/poppler/poppler-0.33.0/splash/SplashFontEngine.cc @@ -0,0 +1,344 @@ +//======================================================================== +// +// SplashFontEngine.cc +// +//======================================================================== + +//======================================================================== +// +// Modified under the Poppler project - http://poppler.freedesktop.org +// +// All changes made under the Poppler project to this file are licensed +// under GPL version 2 or later +// +// Copyright (C) 2006 Takashi Iwai <tiwai@suse.de> +// Copyright (C) 2009 Petr Gajdos <pgajdos@novell.com> +// Copyright (C) 2009 Kovid Goyal <kovid@kovidgoyal.net> +// Copyright (C) 2009 Albert Astals Cid <aacid@kde.org> +// Copyright (C) 2011 Andreas Hartmetz <ahartmetz@gmail.com> +// Copyright (C) 2013 Thomas Freitag <Thomas.Freitag@alfa.de> +// +// To see a description of the changes please see the Changelog file that +// came with your tarball or type make ChangeLog if you are building from git +// +//======================================================================== + +#include <config.h> + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#if HAVE_T1LIB_H +#include <t1lib.h> +#endif + +#include <stdlib.h> +#include <stdio.h> +#ifdef HAVE_UNISTD_H +# include <unistd.h> +#endif +#include "goo/gmem.h" +#include "goo/GooString.h" +#include "SplashMath.h" +#include "SplashT1FontEngine.h" +#include "SplashFTFontEngine.h" +#include "SplashFontFile.h" +#include "SplashFontFileID.h" +#include "SplashFont.h" +#include "SplashFontEngine.h" + +#ifdef VMS +#if (__VMS_VER < 70000000) +extern "C" int unlink(char *filename); +#endif +#endif + +#ifdef VMS +#if (__VMS_VER < 70000000) +extern "C" int unlink(char *filename); +#endif +#endif + +//------------------------------------------------------------------------ +// SplashFontEngine +//------------------------------------------------------------------------ + +SplashFontEngine::SplashFontEngine( +#if HAVE_T1LIB_H + GBool enableT1lib, +#endif +#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H + GBool enableFreeType, + GBool enableFreeTypeHinting, + GBool enableSlightHinting, +#endif + GBool aa) { + int i; + + for (i = 0; i < splashFontCacheSize; ++i) { + fontCache[i] = NULL; + } + +#if HAVE_T1LIB_H + if (enableT1lib) { + t1Engine = SplashT1FontEngine::init(aa); + } else { + t1Engine = NULL; + } +#endif +#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H + if (enableFreeType) { + ftEngine = SplashFTFontEngine::init(aa, enableFreeTypeHinting, enableSlightHinting); + } else { + ftEngine = NULL; + } +#endif +} + +SplashFontEngine::~SplashFontEngine() { + int i; + + for (i = 0; i < splashFontCacheSize; ++i) { + if (fontCache[i]) { + delete fontCache[i]; + } + } + +#if HAVE_T1LIB_H + if (t1Engine) { + delete t1Engine; + } +#endif +#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H + if (ftEngine) { + delete ftEngine; + } +#endif +} + +SplashFontFile *SplashFontEngine::getFontFile(SplashFontFileID *id) { + SplashFontFile *fontFile; + int i; + + for (i = 0; i < splashFontCacheSize; ++i) { + if (fontCache[i]) { + fontFile = fontCache[i]->getFontFile(); + if (fontFile && fontFile->getID()->matches(id)) { + return fontFile; + } + } + } + return NULL; +} + +SplashFontFile *SplashFontEngine::loadType1Font(SplashFontFileID *idA, + SplashFontSrc *src, + const char **enc) { + SplashFontFile *fontFile; + + fontFile = NULL; +#if HAVE_T1LIB_H + if (!fontFile && t1Engine) { + fontFile = t1Engine->loadType1Font(idA, src, enc); + } +#endif +#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H + if (!fontFile && ftEngine) { + fontFile = ftEngine->loadType1Font(idA, src, enc); + } +#endif + +#ifndef _WIN32 + // delete the (temporary) font file -- with Unix hard link + // semantics, this will remove the last link; otherwise it will + // return an error, leaving the file to be deleted later (if + // loadXYZFont failed, the file will always be deleted) + if (src->isFile) + src->unref(); +#endif + + return fontFile; +} + +SplashFontFile *SplashFontEngine::loadType1CFont(SplashFontFileID *idA, + SplashFontSrc *src, + const char **enc) { + SplashFontFile *fontFile; + + fontFile = NULL; +#if HAVE_T1LIB_H + if (!fontFile && t1Engine) { + fontFile = t1Engine->loadType1CFont(idA, src, enc); + } +#endif +#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H + if (!fontFile && ftEngine) { + fontFile = ftEngine->loadType1CFont(idA, src, enc); + } +#endif + +#ifndef _WIN32 + // delete the (temporary) font file -- with Unix hard link + // semantics, this will remove the last link; otherwise it will + // return an error, leaving the file to be deleted later (if + // loadXYZFont failed, the file will always be deleted) + if (src->isFile) + src->unref(); +#endif + + return fontFile; +} + +SplashFontFile *SplashFontEngine::loadOpenTypeT1CFont(SplashFontFileID *idA, + SplashFontSrc *src, + const char **enc) { + SplashFontFile *fontFile; + + fontFile = NULL; +#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H + if (!fontFile && ftEngine) { + fontFile = ftEngine->loadOpenTypeT1CFont(idA, src, enc); + } +#endif + + // delete the (temporary) font file -- with Unix hard link + // semantics, this will remove the last link; otherwise it will + // return an error, leaving the file to be deleted later (if + // loadXYZFont failed, the file will always be deleted) + if (src->isFile) + src->unref(); + + return fontFile; +} + +SplashFontFile *SplashFontEngine::loadCIDFont(SplashFontFileID *idA, + SplashFontSrc *src) { + SplashFontFile *fontFile; + + fontFile = NULL; +#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H + if (!fontFile && ftEngine) { + fontFile = ftEngine->loadCIDFont(idA, src); + } +#endif + +#ifndef _WIN32 + // delete the (temporary) font file -- with Unix hard link + // semantics, this will remove the last link; otherwise it will + // return an error, leaving the file to be deleted later (if + // loadXYZFont failed, the file will always be deleted) + if (src->isFile) + src->unref(); +#endif + + return fontFile; +} + +SplashFontFile *SplashFontEngine::loadOpenTypeCFFFont(SplashFontFileID *idA, + SplashFontSrc *src, + int *codeToGID, + int codeToGIDLen) { + SplashFontFile *fontFile; + + fontFile = NULL; +#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H + if (!fontFile && ftEngine) { + fontFile = ftEngine->loadOpenTypeCFFFont(idA, src, codeToGID, codeToGIDLen); + } +#endif + + // delete the (temporary) font file -- with Unix hard link + // semantics, this will remove the last link; otherwise it will + // return an error, leaving the file to be deleted later (if + // loadXYZFont failed, the file will always be deleted) + if (src->isFile) + src->unref(); + + return fontFile; +} + +SplashFontFile *SplashFontEngine::loadTrueTypeFont(SplashFontFileID *idA, + SplashFontSrc *src, + int *codeToGID, + int codeToGIDLen, + int faceIndex) { + SplashFontFile *fontFile; + + fontFile = NULL; +#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H + if (!fontFile && ftEngine) { + fontFile = ftEngine->loadTrueTypeFont(idA, src, + codeToGID, codeToGIDLen, faceIndex); + } +#endif + + if (!fontFile) { + gfree(codeToGID); + } + +#ifndef _WIN32 + // delete the (temporary) font file -- with Unix hard link + // semantics, this will remove the last link; otherwise it will + // return an error, leaving the file to be deleted later (if + // loadXYZFont failed, the file will always be deleted) + if (src->isFile) + src->unref(); +#endif + + return fontFile; +} + +#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H +GBool SplashFontEngine::getAA() { + return (ftEngine == NULL) ? gFalse : ftEngine->getAA(); +} + +void SplashFontEngine::setAA(GBool aa) { + if (ftEngine != NULL) { + ftEngine->setAA(aa); + } +} +#endif + +SplashFont *SplashFontEngine::getFont(SplashFontFile *fontFile, + SplashCoord *textMat, + SplashCoord *ctm) { + SplashCoord mat[4]; + SplashFont *font; + int i, j; + + mat[0] = textMat[0] * ctm[0] + textMat[1] * ctm[2]; + mat[1] = -(textMat[0] * ctm[1] + textMat[1] * ctm[3]); + mat[2] = textMat[2] * ctm[0] + textMat[3] * ctm[2]; + mat[3] = -(textMat[2] * ctm[1] + textMat[3] * ctm[3]); + if (!splashCheckDet(mat[0], mat[1], mat[2], mat[3], 0.01)) { + // avoid a singular (or close-to-singular) matrix + mat[0] = 0.01; mat[1] = 0; + mat[2] = 0; mat[3] = 0.01; + } + + font = fontCache[0]; + if (font && font->matches(fontFile, mat, textMat)) { + return font; + } + for (i = 1; i < splashFontCacheSize; ++i) { + font = fontCache[i]; + if (font && font->matches(fontFile, mat, textMat)) { + for (j = i; j > 0; --j) { + fontCache[j] = fontCache[j-1]; + } + fontCache[0] = font; + return font; + } + } + font = fontFile->makeFont(mat, textMat); + if (fontCache[splashFontCacheSize - 1]) { + delete fontCache[splashFontCacheSize - 1]; + } + for (j = splashFontCacheSize - 1; j > 0; --j) { + fontCache[j] = fontCache[j-1]; + } + fontCache[0] = font; + return font; +} diff --git a/Build/source/libs/poppler/poppler-0.33.0/splash/SplashFontEngine.h b/Build/source/libs/poppler/poppler-0.33.0/splash/SplashFontEngine.h new file mode 100644 index 00000000000..6502ea5a7fa --- /dev/null +++ b/Build/source/libs/poppler/poppler-0.33.0/splash/SplashFontEngine.h @@ -0,0 +1,110 @@ +//======================================================================== +// +// SplashFontEngine.h +// +//======================================================================== + +//======================================================================== +// +// Modified under the Poppler project - http://poppler.freedesktop.org +// +// All changes made under the Poppler project to this file are licensed +// under GPL version 2 or later +// +// Copyright (C) 2006 Takashi Iwai <tiwai@suse.de> +// Copyright (C) 2009 Petr Gajdos <pgajdos@novell.com> +// Copyright (C) 2009, 2011 Albert Astals Cid <aacid@kde.org> +// Copyright (C) 2011 Andreas Hartmetz <ahartmetz@gmail.com> +// Copyright (C) 2013 Thomas Freitag <Thomas.Freitag@alfa.de> +// +// To see a description of the changes please see the Changelog file that +// came with your tarball or type make ChangeLog if you are building from git +// +//======================================================================== + +#ifndef SPLASHFONTENGINE_H +#define SPLASHFONTENGINE_H + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "goo/gtypes.h" +#include "SplashTypes.h" + +class SplashT1FontEngine; +class SplashFTFontEngine; +class SplashDTFontEngine; +class SplashDT4FontEngine; +class SplashFontFile; +class SplashFontFileID; +class SplashFont; +class SplashFontSrc; + +//------------------------------------------------------------------------ + +#define splashFontCacheSize 16 + +//------------------------------------------------------------------------ +// SplashFontEngine +//------------------------------------------------------------------------ + +class SplashFontEngine { +public: + + // Create a font engine. + SplashFontEngine( +#if HAVE_T1LIB_H + GBool enableT1lib, +#endif +#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H + GBool enableFreeType, + GBool enableFreeTypeHinting, + GBool enableSlightHinting, +#endif + GBool aa); + + ~SplashFontEngine(); + + // Get a font file from the cache. Returns NULL if there is no + // matching entry in the cache. + SplashFontFile *getFontFile(SplashFontFileID *id); + + // Load fonts - these create new SplashFontFile objects. + SplashFontFile *loadType1Font(SplashFontFileID *idA, SplashFontSrc *src, const char **enc); + SplashFontFile *loadType1CFont(SplashFontFileID *idA, SplashFontSrc *src, const char **enc); + SplashFontFile *loadOpenTypeT1CFont(SplashFontFileID *idA, SplashFontSrc *src, const char **enc); + SplashFontFile *loadCIDFont(SplashFontFileID *idA, SplashFontSrc *src); + SplashFontFile *loadOpenTypeCFFFont(SplashFontFileID *idA, SplashFontSrc *src, + int *codeToGID, int codeToGIDLen); + SplashFontFile *loadTrueTypeFont(SplashFontFileID *idA, SplashFontSrc *src, + int *codeToGID, int codeToGIDLen, int faceIndex = 0); + + // Get a font - this does a cache lookup first, and if not found, + // creates a new SplashFont object and adds it to the cache. The + // matrix, mat = textMat * ctm: + // [ mat[0] mat[1] ] + // [ mat[2] mat[3] ] + // specifies the font transform in PostScript style: + // [x' y'] = [x y] * mat + // Note that the Splash y axis points downward. + SplashFont *getFont(SplashFontFile *fontFile, + SplashCoord *textMat, SplashCoord *ctm); +#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H + GBool getAA(); + void setAA(GBool aa); +#endif + +private: + + SplashFont *fontCache[splashFontCacheSize]; + +#if HAVE_T1LIB_H + SplashT1FontEngine *t1Engine; +#endif +#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H + SplashFTFontEngine *ftEngine; +#endif +}; + +#endif diff --git a/Build/source/libs/poppler/poppler-0.33.0/splash/SplashFontFile.cc b/Build/source/libs/poppler/poppler-0.33.0/splash/SplashFontFile.cc new file mode 100644 index 00000000000..68e8608b6a7 --- /dev/null +++ b/Build/source/libs/poppler/poppler-0.33.0/splash/SplashFontFile.cc @@ -0,0 +1,124 @@ +//======================================================================== +// +// SplashFontFile.cc +// +//======================================================================== + +//======================================================================== +// +// Modified under the Poppler project - http://poppler.freedesktop.org +// +// All changes made under the Poppler project to this file are licensed +// under GPL version 2 or later +// +// Copyright (C) 2006 Takashi Iwai <tiwai@suse.de> +// Copyright (C) 2008 Albert Astals Cid <aacid@kde.org> +// +// To see a description of the changes please see the Changelog file that +// came with your tarball or type make ChangeLog if you are building from git +// +//======================================================================== + +#include <config.h> + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include <stdio.h> +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#include "goo/gmem.h" +#include "goo/GooString.h" +#include "SplashFontFile.h" +#include "SplashFontFileID.h" + +#ifdef VMS +#if (__VMS_VER < 70000000) +extern "C" int unlink(char *filename); +#endif +#endif + +//------------------------------------------------------------------------ +// SplashFontFile +//------------------------------------------------------------------------ + +SplashFontFile::SplashFontFile(SplashFontFileID *idA, SplashFontSrc *srcA) { + id = idA; + src = srcA; + src->ref(); + refCnt = 0; + doAdjustMatrix = gFalse; +} + +SplashFontFile::~SplashFontFile() { + src->unref(); + delete id; +} + +void SplashFontFile::incRefCnt() { + ++refCnt; +} + +void SplashFontFile::decRefCnt() { + if (!--refCnt) { + delete this; + } +} + +// + +SplashFontSrc::SplashFontSrc() { + isFile = gFalse; + deleteSrc = gFalse; + fileName = NULL; + buf = NULL; + refcnt = 1; +} + +SplashFontSrc::~SplashFontSrc() { + if (deleteSrc) { + if (isFile) { + if (fileName) + unlink(fileName->getCString()); + } else { + if (buf) + gfree(buf); + } + } + + if (isFile && fileName) + delete fileName; +} + +void SplashFontSrc::ref() { + refcnt++; +} + +void SplashFontSrc::unref() { + if (! --refcnt) + delete this; +} + +void SplashFontSrc::setFile(GooString *file, GBool del) +{ + isFile = gTrue; + fileName = file->copy(); + deleteSrc = del; +} + +void SplashFontSrc::setFile(const char *file, GBool del) +{ + isFile = gTrue; + fileName = new GooString(file); + deleteSrc = del; +} + +void SplashFontSrc::setBuf(char *bufA, int bufLenA, GBool del) +{ + isFile = gFalse; + buf = bufA; + bufLen = bufLenA; + deleteSrc = del; +} diff --git a/Build/source/libs/poppler/poppler-0.33.0/splash/SplashFontFile.h b/Build/source/libs/poppler/poppler-0.33.0/splash/SplashFontFile.h new file mode 100644 index 00000000000..ec87504b9bc --- /dev/null +++ b/Build/source/libs/poppler/poppler-0.33.0/splash/SplashFontFile.h @@ -0,0 +1,95 @@ +//======================================================================== +// +// SplashFontFile.h +// +//======================================================================== + +//======================================================================== +// +// Modified under the Poppler project - http://poppler.freedesktop.org +// +// All changes made under the Poppler project to this file are licensed +// under GPL version 2 or later +// +// Copyright (C) 2006 Takashi Iwai <tiwai@suse.de> +// Copyright (C) 2008, 2010 Albert Astals Cid <aacid@kde.org> +// +// To see a description of the changes please see the Changelog file that +// came with your tarball or type make ChangeLog if you are building from git +// +//======================================================================== + +#ifndef SPLASHFONTFILE_H +#define SPLASHFONTFILE_H + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "goo/gtypes.h" +#include "SplashTypes.h" + +class GooString; +class SplashFontEngine; +class SplashFont; +class SplashFontFileID; + +//------------------------------------------------------------------------ +// SplashFontFile +//------------------------------------------------------------------------ + +class SplashFontSrc { +public: + SplashFontSrc(); + + void setFile(GooString *file, GBool del); + void setFile(const char *file, GBool del); + void setBuf(char *bufA, int buflenA, GBool del); + + void ref(); + void unref(); + + GBool isFile; + GooString *fileName; + char *buf; + int bufLen; + +private: + ~SplashFontSrc(); + int refcnt; + GBool deleteSrc; +}; + +class SplashFontFile { +public: + + virtual ~SplashFontFile(); + + // Create a new SplashFont, i.e., a scaled instance of this font + // file. + virtual SplashFont *makeFont(SplashCoord *mat, SplashCoord *textMat) = 0; + + // Get the font file ID. + SplashFontFileID *getID() { return id; } + + // Increment the reference count. + void incRefCnt(); + + // Decrement the reference count. If the new value is zero, delete + // the SplashFontFile object. + void decRefCnt(); + + GBool doAdjustMatrix; + +protected: + + SplashFontFile(SplashFontFileID *idA, SplashFontSrc *srcA); + + SplashFontFileID *id; + SplashFontSrc *src; + int refCnt; + + friend class SplashFontEngine; +}; + +#endif diff --git a/Build/source/libs/poppler/poppler-0.33.0/splash/SplashFontFileID.cc b/Build/source/libs/poppler/poppler-0.33.0/splash/SplashFontFileID.cc new file mode 100644 index 00000000000..a66dabf61e3 --- /dev/null +++ b/Build/source/libs/poppler/poppler-0.33.0/splash/SplashFontFileID.cc @@ -0,0 +1,23 @@ +//======================================================================== +// +// SplashFontFileID.cc +// +//======================================================================== + +#include <config.h> + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include "SplashFontFileID.h" + +//------------------------------------------------------------------------ +// SplashFontFileID +//------------------------------------------------------------------------ + +SplashFontFileID::SplashFontFileID() { +} + +SplashFontFileID::~SplashFontFileID() { +} diff --git a/Build/source/libs/poppler/poppler-0.33.0/splash/SplashFontFileID.h b/Build/source/libs/poppler/poppler-0.33.0/splash/SplashFontFileID.h new file mode 100644 index 00000000000..cfd89ebb56a --- /dev/null +++ b/Build/source/libs/poppler/poppler-0.33.0/splash/SplashFontFileID.h @@ -0,0 +1,28 @@ +//======================================================================== +// +// SplashFontFileID.h +// +//======================================================================== + +#ifndef SPLASHFONTFILEID_H +#define SPLASHFONTFILEID_H + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "goo/gtypes.h" + +//------------------------------------------------------------------------ +// SplashFontFileID +//------------------------------------------------------------------------ + +class SplashFontFileID { +public: + + SplashFontFileID(); + virtual ~SplashFontFileID(); + virtual GBool matches(SplashFontFileID *id) = 0; +}; + +#endif diff --git a/Build/source/libs/poppler/poppler-0.33.0/splash/SplashGlyphBitmap.h b/Build/source/libs/poppler/poppler-0.33.0/splash/SplashGlyphBitmap.h new file mode 100644 index 00000000000..c062c106e6a --- /dev/null +++ b/Build/source/libs/poppler/poppler-0.33.0/splash/SplashGlyphBitmap.h @@ -0,0 +1,24 @@ +//======================================================================== +// +// SplashGlyphBitmap.h +// +//======================================================================== + +#ifndef SPLASHGLYPHBITMAP_H +#define SPLASHGLYPHBITMAP_H + +#include "goo/gtypes.h" + +//------------------------------------------------------------------------ +// SplashGlyphBitmap +//------------------------------------------------------------------------ + +struct SplashGlyphBitmap { + int x, y, w, h; // offset and size of glyph + GBool aa; // anti-aliased: true means 8-bit alpha + // bitmap; false means 1-bit + Guchar *data; // bitmap data + GBool freeData; // true if data memory should be freed +}; + +#endif diff --git a/Build/source/libs/poppler/poppler-0.33.0/splash/SplashMath.h b/Build/source/libs/poppler/poppler-0.33.0/splash/SplashMath.h new file mode 100644 index 00000000000..ca73c2bd1f3 --- /dev/null +++ b/Build/source/libs/poppler/poppler-0.33.0/splash/SplashMath.h @@ -0,0 +1,245 @@ +//======================================================================== +// +// SplashMath.h +// +//======================================================================== + +//======================================================================== +// +// Modified under the Poppler project - http://poppler.freedesktop.org +// +// All changes made under the Poppler project to this file are licensed +// under GPL version 2 or later +// +// Copyright (C) 2009-2011 Albert Astals Cid <aacid@kde.org> +// +// To see a description of the changes please see the Changelog file that +// came with your tarball or type make ChangeLog if you are building from git +// +//======================================================================== + +#ifndef SPLASHMATH_H +#define SPLASHMATH_H + +#include "poppler-config.h" + +#if USE_FIXEDPOINT +#include "goo/FixedPoint.h" +#else +#include <math.h> +#endif +#include "SplashTypes.h" + +static inline SplashCoord splashAbs(SplashCoord x) { +#if USE_FIXEDPOINT + return FixedPoint::abs(x); +#elif USE_FLOAT + return fabsf(x); +#else + return fabs(x); +#endif +} + +static inline int splashFloor(SplashCoord x) { + #if USE_FIXEDPOINT + return FixedPoint::floor(x); + #elif USE_FLOAT + return (int)floorf(x); + #elif __GNUC__ && __i386__ + // floor() and (int)() are implemented separately, which results + // in changing the FPCW multiple times - so we optimize it with + // some inline assembly + Gushort oldCW, newCW, t; + int result; + + __asm__ volatile("fldl %4\n" + "fnstcw %0\n" + "movw %0, %3\n" + "andw $0xf3ff, %3\n" + "orw $0x0400, %3\n" + "movw %3, %1\n" // round down + "fldcw %1\n" + "fistpl %2\n" + "fldcw %0\n" + : "=m" (oldCW), "=m" (newCW), "=m" (result), "=r" (t) + : "m" (x)); + return result; + #elif defined(WIN32) && defined(_M_IX86) + // floor() and (int)() are implemented separately, which results + // in changing the FPCW multiple times - so we optimize it with + // some inline assembly + Gushort oldCW, newCW; + int result; + + __asm fld QWORD PTR x + __asm fnstcw WORD PTR oldCW + __asm mov ax, WORD PTR oldCW + __asm and ax, 0xf3ff + __asm or ax, 0x0400 + __asm mov WORD PTR newCW, ax // round down + __asm fldcw WORD PTR newCW + __asm fistp DWORD PTR result + __asm fldcw WORD PTR oldCW + return result; + #else + if (x > 0) return (int)x; + else return (int)floor(x); + #endif +} + +static inline int splashCeil(SplashCoord x) { +#if USE_FIXEDPOINT + return FixedPoint::ceil(x); +#elif USE_FLOAT + return (int)ceilf(x); +#elif __GNUC__ && __i386__ + // ceil() and (int)() are implemented separately, which results + // in changing the FPCW multiple times - so we optimize it with + // some inline assembly + Gushort oldCW, newCW, t; + int result; + + __asm__ volatile("fldl %4\n" + "fnstcw %0\n" + "movw %0, %3\n" + "andw $0xf3ff, %3\n" + "orw $0x0800, %3\n" + "movw %3, %1\n" // round up + "fldcw %1\n" + "fistpl %2\n" + "fldcw %0\n" + : "=m" (oldCW), "=m" (newCW), "=m" (result), "=r" (t) + : "m" (x)); + return result; +#elif defined(WIN32) && defined(_M_IX86) + // ceil() and (int)() are implemented separately, which results + // in changing the FPCW multiple times - so we optimize it with + // some inline assembly + Gushort oldCW, newCW; + int result; + + __asm fld QWORD PTR x + __asm fnstcw WORD PTR oldCW + __asm mov ax, WORD PTR oldCW + __asm and ax, 0xf3ff + __asm or ax, 0x0800 + __asm mov WORD PTR newCW, ax // round up + __asm fldcw WORD PTR newCW + __asm fistp DWORD PTR result + __asm fldcw WORD PTR oldCW + return result; +#else + return (int)ceil(x); +#endif +} + +static inline int splashRound(SplashCoord x) { +#if USE_FIXEDPOINT + return FixedPoint::round(x); +#elif __GNUC__ && __i386__ + // this could use round-to-nearest mode and avoid the "+0.5", + // but that produces slightly different results (because i+0.5 + // sometimes rounds up and sometimes down using the even rule) + Gushort oldCW, newCW, t; + int result; + + x += 0.5; + __asm__ volatile("fldl %4\n" + "fnstcw %0\n" + "movw %0, %3\n" + "andw $0xf3ff, %3\n" + "orw $0x0400, %3\n" + "movw %3, %1\n" // round down + "fldcw %1\n" + "fistpl %2\n" + "fldcw %0\n" + : "=m" (oldCW), "=m" (newCW), "=m" (result), "=r" (t) + : "m" (x)); + return result; +#elif defined(WIN32) && defined(_M_IX86) + // this could use round-to-nearest mode and avoid the "+0.5", + // but that produces slightly different results (because i+0.5 + // sometimes rounds up and sometimes down using the even rule) + Gushort oldCW, newCW; + int result; + + x += 0.5; + __asm fld QWORD PTR x + __asm fnstcw WORD PTR oldCW + __asm mov ax, WORD PTR oldCW + __asm and ax, 0xf3ff + __asm or ax, 0x0400 + __asm mov WORD PTR newCW, ax // round down + __asm fldcw WORD PTR newCW + __asm fistp DWORD PTR result + __asm fldcw WORD PTR oldCW + return result; +#else + return (int)splashFloor(x + 0.5); +#endif +} + +static inline SplashCoord splashAvg(SplashCoord x, SplashCoord y) { +#if USE_FIXEDPOINT + return FixedPoint::avg(x, y); +#else + return 0.5 * (x + y); +#endif +} + +static inline SplashCoord splashSqrt(SplashCoord x) { +#if USE_FIXEDPOINT + return FixedPoint::sqrt(x); +#elif USE_FLOAT + return sqrtf(x); +#else + return sqrt(x); +#endif +} + +static inline SplashCoord splashPow(SplashCoord x, SplashCoord y) { +#if USE_FIXEDPOINT + return FixedPoint::pow(x, y); +#elif USE_FLOAT + return powf(x, y); +#else + return pow(x, y); +#endif +} + +static inline SplashCoord splashDist(SplashCoord x0, SplashCoord y0, + SplashCoord x1, SplashCoord y1) { + SplashCoord dx, dy; + dx = x1 - x0; + dy = y1 - y0; +#if USE_FIXEDPOINT + // this handles the situation where dx*dx or dy*dy is too large to + // fit in the 16.16 fixed point format + SplashCoord dxa, dya, d; + dxa = splashAbs(dx); + dya = splashAbs(dy); + if (dxa == 0 && dya == 0) { + return 0; + } else if (dxa > dya) { + d = dya / dxa; + return dxa * FixedPoint::sqrt(d*d + 1); + } else { + d = dxa / dya; + return dya * FixedPoint::sqrt(d*d + 1); + } +#else + return splashSqrt(dx * dx + dy * dy); +#endif +} + +static inline GBool splashCheckDet(SplashCoord m11, SplashCoord m12, + SplashCoord m21, SplashCoord m22, + SplashCoord epsilon) { +#if USE_FIXEDPOINT + return FixedPoint::checkDet(m11, m12, m21, m22, epsilon); +#else + return fabs(m11 * m22 - m12 * m21) >= epsilon; +#endif +} + +#endif diff --git a/Build/source/libs/poppler/poppler-0.33.0/splash/SplashPath.cc b/Build/source/libs/poppler/poppler-0.33.0/splash/SplashPath.cc new file mode 100644 index 00000000000..bc4ccd524a4 --- /dev/null +++ b/Build/source/libs/poppler/poppler-0.33.0/splash/SplashPath.cc @@ -0,0 +1,185 @@ +//======================================================================== +// +// SplashPath.cc +// +//======================================================================== + +#include <config.h> + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include <string.h> +#include "goo/gmem.h" +#include "SplashErrorCodes.h" +#include "SplashPath.h" + +//------------------------------------------------------------------------ +// SplashPath +//------------------------------------------------------------------------ + +// A path can be in three possible states: +// +// 1. no current point -- zero or more finished subpaths +// [curSubpath == length] +// +// 2. one point in subpath +// [curSubpath == length - 1] +// +// 3. open subpath with two or more points +// [curSubpath < length - 1] + +SplashPath::SplashPath() { + pts = NULL; + flags = NULL; + length = size = 0; + curSubpath = 0; + hints = NULL; + hintsLength = hintsSize = 0; +} + +SplashPath::SplashPath(SplashPath *path) { + length = path->length; + size = path->size; + pts = (SplashPathPoint *)gmallocn(size, sizeof(SplashPathPoint)); + flags = (Guchar *)gmallocn(size, sizeof(Guchar)); + memcpy(pts, path->pts, length * sizeof(SplashPathPoint)); + memcpy(flags, path->flags, length * sizeof(Guchar)); + curSubpath = path->curSubpath; + if (path->hints) { + hintsLength = hintsSize = path->hintsLength; + hints = (SplashPathHint *)gmallocn(hintsSize, sizeof(SplashPathHint)); + memcpy(hints, path->hints, hintsLength * sizeof(SplashPathHint)); + } else { + hints = NULL; + } +} + +SplashPath::~SplashPath() { + gfree(pts); + gfree(flags); + gfree(hints); +} + +// Add space for <nPts> more points. +void SplashPath::grow(int nPts) { + if (length + nPts > size) { + if (size == 0) { + size = 32; + } + while (size < length + nPts) { + size *= 2; + } + pts = (SplashPathPoint *)greallocn(pts, size, sizeof(SplashPathPoint)); + flags = (Guchar *)greallocn(flags, size, sizeof(Guchar)); + } +} + +void SplashPath::append(SplashPath *path) { + int i; + + curSubpath = length + path->curSubpath; + grow(path->length); + for (i = 0; i < path->length; ++i) { + pts[length] = path->pts[i]; + flags[length] = path->flags[i]; + ++length; + } +} + +SplashError SplashPath::moveTo(SplashCoord x, SplashCoord y) { + if (onePointSubpath()) { + return splashErrBogusPath; + } + grow(1); + pts[length].x = x; + pts[length].y = y; + flags[length] = splashPathFirst | splashPathLast; + curSubpath = length++; + return splashOk; +} + +SplashError SplashPath::lineTo(SplashCoord x, SplashCoord y) { + if (noCurrentPoint()) { + return splashErrNoCurPt; + } + flags[length-1] &= ~splashPathLast; + grow(1); + pts[length].x = x; + pts[length].y = y; + flags[length] = splashPathLast; + ++length; + return splashOk; +} + +SplashError SplashPath::curveTo(SplashCoord x1, SplashCoord y1, + SplashCoord x2, SplashCoord y2, + SplashCoord x3, SplashCoord y3) { + if (noCurrentPoint()) { + return splashErrNoCurPt; + } + flags[length-1] &= ~splashPathLast; + grow(3); + pts[length].x = x1; + pts[length].y = y1; + flags[length] = splashPathCurve; + ++length; + pts[length].x = x2; + pts[length].y = y2; + flags[length] = splashPathCurve; + ++length; + pts[length].x = x3; + pts[length].y = y3; + flags[length] = splashPathLast; + ++length; + return splashOk; +} + +SplashError SplashPath::close(GBool force) { + if (noCurrentPoint()) { + return splashErrNoCurPt; + } + if (force || + curSubpath == length - 1 || + pts[length - 1].x != pts[curSubpath].x || + pts[length - 1].y != pts[curSubpath].y) { + lineTo(pts[curSubpath].x, pts[curSubpath].y); + } + flags[curSubpath] |= splashPathClosed; + flags[length - 1] |= splashPathClosed; + curSubpath = length; + return splashOk; +} + +void SplashPath::addStrokeAdjustHint(int ctrl0, int ctrl1, + int firstPt, int lastPt) { + if (hintsLength == hintsSize) { + hintsSize = hintsLength ? 2 * hintsLength : 8; + hints = (SplashPathHint *)greallocn(hints, hintsSize, + sizeof(SplashPathHint)); + } + hints[hintsLength].ctrl0 = ctrl0; + hints[hintsLength].ctrl1 = ctrl1; + hints[hintsLength].firstPt = firstPt; + hints[hintsLength].lastPt = lastPt; + ++hintsLength; +} + +void SplashPath::offset(SplashCoord dx, SplashCoord dy) { + int i; + + for (i = 0; i < length; ++i) { + pts[i].x += dx; + pts[i].y += dy; + } +} + +GBool SplashPath::getCurPt(SplashCoord *x, SplashCoord *y) { + if (noCurrentPoint()) { + return gFalse; + } + *x = pts[length - 1].x; + *y = pts[length - 1].y; + return gTrue; +} diff --git a/Build/source/libs/poppler/poppler-0.33.0/splash/SplashPath.h b/Build/source/libs/poppler/poppler-0.33.0/splash/SplashPath.h new file mode 100644 index 00000000000..81273c613e5 --- /dev/null +++ b/Build/source/libs/poppler/poppler-0.33.0/splash/SplashPath.h @@ -0,0 +1,123 @@ +//======================================================================== +// +// SplashPath.h +// +//======================================================================== + +#ifndef SPLASHPATH_H +#define SPLASHPATH_H + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "SplashTypes.h" + +//------------------------------------------------------------------------ +// SplashPathPoint +//------------------------------------------------------------------------ + +struct SplashPathPoint { + SplashCoord x, y; +}; + +//------------------------------------------------------------------------ +// SplashPath.flags +//------------------------------------------------------------------------ + +// first point on each subpath sets this flag +#define splashPathFirst 0x01 + +// last point on each subpath sets this flag +#define splashPathLast 0x02 + +// if the subpath is closed, its first and last points must be +// identical, and must set this flag +#define splashPathClosed 0x04 + +// curve control points set this flag +#define splashPathCurve 0x08 + +//------------------------------------------------------------------------ +// SplashPathHint +//------------------------------------------------------------------------ + +struct SplashPathHint { + int ctrl0, ctrl1; + int firstPt, lastPt; +}; + +//------------------------------------------------------------------------ +// SplashPath +//------------------------------------------------------------------------ + +class SplashPath { +public: + + // Create an empty path. + SplashPath(); + + // Copy a path. + SplashPath *copy() { return new SplashPath(this); } + + ~SplashPath(); + + // Append <path> to <this>. + void append(SplashPath *path); + + // Start a new subpath. + SplashError moveTo(SplashCoord x, SplashCoord y); + + // Add a line segment to the last subpath. + SplashError lineTo(SplashCoord x, SplashCoord y); + + // Add a third-order (cubic) Bezier curve segment to the last + // subpath. + SplashError curveTo(SplashCoord x1, SplashCoord y1, + SplashCoord x2, SplashCoord y2, + SplashCoord x3, SplashCoord y3); + + // Close the last subpath, adding a line segment if necessary. If + // <force> is true, this adds a line segment even if the current + // point is equal to the first point in the subpath. + SplashError close(GBool force = gFalse); + + // Add a stroke adjustment hint. The controlling segments are + // <ctrl0> and <ctrl1> (where segments are identified by their first + // point), and the points to be adjusted are <firstPt> .. <lastPt>. + void addStrokeAdjustHint(int ctrl0, int ctrl1, int firstPt, int lastPt); + + // Add (<dx>, <dy>) to every point on this path. + void offset(SplashCoord dx, SplashCoord dy); + + // Get the points on the path. + int getLength() { return length; } + void getPoint(int i, double *x, double *y, Guchar *f) + { *x = pts[i].x; *y = pts[i].y; *f = flags[i]; } + + // Get the current point. + GBool getCurPt(SplashCoord *x, SplashCoord *y); + +protected: + + SplashPath(SplashPath *path); + void grow(int nPts); + GBool noCurrentPoint() { return curSubpath == length; } + GBool onePointSubpath() { return curSubpath == length - 1; } + GBool openSubpath() { return curSubpath < length - 1; } + + SplashPathPoint *pts; // array of points + Guchar *flags; // array of flags + int length, size; // length/size of the pts and flags arrays + int curSubpath; // index of first point in last subpath + + SplashPathHint *hints; // list of hints + int hintsLength, hintsSize; + + friend class SplashXPath; + friend class Splash; + // this is a temporary hack, until we read FreeType paths directly + friend class ArthurOutputDev; +}; + +#endif diff --git a/Build/source/libs/poppler/poppler-0.33.0/splash/SplashPattern.cc b/Build/source/libs/poppler/poppler-0.33.0/splash/SplashPattern.cc new file mode 100644 index 00000000000..28ca4995882 --- /dev/null +++ b/Build/source/libs/poppler/poppler-0.33.0/splash/SplashPattern.cc @@ -0,0 +1,55 @@ +//======================================================================== +// +// SplashPattern.cc +// +//======================================================================== + +//======================================================================== +// +// Modified under the Poppler project - http://poppler.freedesktop.org +// +// All changes made under the Poppler project to this file are licensed +// under GPL version 2 or later +// +// Copyright (C) 2010, 2011 Thomas Freitag <Thomas.Freitag@alfa.de> +// +// To see a description of the changes please see the Changelog file that +// came with your tarball or type make ChangeLog if you are building from git +// +//======================================================================== + +#include <config.h> + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include "SplashMath.h" +#include "SplashScreen.h" +#include "SplashPattern.h" + +//------------------------------------------------------------------------ +// SplashPattern +//------------------------------------------------------------------------ + +SplashPattern::SplashPattern() { +} + +SplashPattern::~SplashPattern() { +} + +//------------------------------------------------------------------------ +// SplashSolidColor +//------------------------------------------------------------------------ + +SplashSolidColor::SplashSolidColor(SplashColorPtr colorA) { + splashColorCopy(color, colorA); +} + +SplashSolidColor::~SplashSolidColor() { +} + +GBool SplashSolidColor::getColor(int x, int y, SplashColorPtr c) { + splashColorCopy(c, color); + return gTrue; +} diff --git a/Build/source/libs/poppler/poppler-0.33.0/splash/SplashPattern.h b/Build/source/libs/poppler/poppler-0.33.0/splash/SplashPattern.h new file mode 100644 index 00000000000..e678c9e20e6 --- /dev/null +++ b/Build/source/libs/poppler/poppler-0.33.0/splash/SplashPattern.h @@ -0,0 +1,104 @@ +//======================================================================== +// +// SplashPattern.h +// +//======================================================================== + +//======================================================================== +// +// Modified under the Poppler project - http://poppler.freedesktop.org +// +// All changes made under the Poppler project to this file are licensed +// under GPL version 2 or later +// +// Copyright (C) 2010, 2011, 2014 Thomas Freitag <Thomas.Freitag@alfa.de> +// +// To see a description of the changes please see the Changelog file that +// came with your tarball or type make ChangeLog if you are building from git +// +//======================================================================== + +#ifndef SPLASHPATTERN_H +#define SPLASHPATTERN_H + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "SplashTypes.h" + +class SplashScreen; + +//------------------------------------------------------------------------ +// SplashPattern +//------------------------------------------------------------------------ + +class SplashPattern { +public: + + SplashPattern(); + + virtual SplashPattern *copy() = 0; + + virtual ~SplashPattern(); + + // Return the color value for a specific pixel. + virtual GBool getColor(int x, int y, SplashColorPtr c) = 0; + + // Test if x,y-position is inside pattern. + virtual GBool testPosition(int x, int y) = 0; + + // Returns true if this pattern object will return the same color + // value for all pixels. + virtual GBool isStatic() = 0; + + // Returns true if this pattern colorspace is CMYK. + virtual GBool isCMYK() = 0; +private: +}; + +//------------------------------------------------------------------------ +// SplashSolidColor +//------------------------------------------------------------------------ + +class SplashSolidColor: public SplashPattern { +public: + + SplashSolidColor(SplashColorPtr colorA); + + virtual SplashPattern *copy() { return new SplashSolidColor(color); } + + virtual ~SplashSolidColor(); + + virtual GBool getColor(int x, int y, SplashColorPtr c); + + virtual GBool testPosition(int x, int y) { return gFalse; } + + virtual GBool isStatic() { return gTrue; } + + virtual GBool isCMYK() { return gFalse; } + +private: + + SplashColor color; +}; + +//------------------------------------------------------------------------ +// SplashGouraudColor (needed for gouraudTriangleShadedFill) +//------------------------------------------------------------------------ + +class SplashGouraudColor: public SplashPattern { +public: + + virtual GBool isParameterized() = 0; + + virtual int getNTriangles() = 0; + + virtual void getTriangle(int i, double *x0, double *y0, double *color0, + double *x1, double *y1, double *color1, + double *x2, double *y2, double *color2) = 0; + + virtual void getParameterizedColor(double t, SplashColorMode mode, SplashColorPtr c) = 0; +}; + +#endif diff --git a/Build/source/libs/poppler/poppler-0.33.0/splash/SplashScreen.cc b/Build/source/libs/poppler/poppler-0.33.0/splash/SplashScreen.cc new file mode 100644 index 00000000000..68ccd7ddda0 --- /dev/null +++ b/Build/source/libs/poppler/poppler-0.33.0/splash/SplashScreen.cc @@ -0,0 +1,387 @@ +//======================================================================== +// +// SplashScreen.cc +// +//======================================================================== + +//======================================================================== +// +// Modified under the Poppler project - http://poppler.freedesktop.org +// +// All changes made under the Poppler project to this file are licensed +// under GPL version 2 or later +// +// Copyright (C) 2009 Albert Astals Cid <aacid@kde.org> +// Copyright (C) 2012 Fabio D'Urso <fabiodurso@hotmail.it> +// +// To see a description of the changes please see the Changelog file that +// came with your tarball or type make ChangeLog if you are building from git +// +//======================================================================== + +#include <config.h> + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include <stdlib.h> +#include <string.h> +#include <algorithm> +#include "goo/gmem.h" +#include "goo/grandom.h" +#include "SplashMath.h" +#include "SplashScreen.h" + +static SplashScreenParams defaultParams = { + splashScreenDispersed, // type + 2, // size + 2, // dotRadius + 1.0, // gamma + 0.0, // blackThreshold + 1.0 // whiteThreshold +}; + +//------------------------------------------------------------------------ + +struct SplashScreenPoint { + int x, y; + int dist; +}; + + +struct cmpDistancesFunctor { + bool operator()(const SplashScreenPoint &p0, const SplashScreenPoint &p1) { + return p0.dist < p1.dist; + } +}; + +//------------------------------------------------------------------------ +// SplashScreen +//------------------------------------------------------------------------ + +// If <clustered> is true, this generates a 45 degree screen using a +// circular dot spot function. DPI = resolution / ((size / 2) * +// sqrt(2)). If <clustered> is false, this generates an optimal +// threshold matrix using recursive tesselation. Gamma correction +// (gamma = 1 / 1.33) is also computed here. +SplashScreen::SplashScreen(SplashScreenParams *params) { + + if (!params) { + params = &defaultParams; + } + + screenParams = params; + mat = NULL; + size = 0; + maxVal = 0; + minVal = 0; +} + +void SplashScreen::createMatrix() +{ + Guchar u; + int black, white, i; + + SplashScreenParams *params = screenParams; + + // size must be a power of 2, and at least 2 + for (size = 2, log2Size = 1; size < params->size; size <<= 1, ++log2Size) ; + + switch (params->type) { + + case splashScreenDispersed: + mat = (Guchar *)gmallocn(size * size, sizeof(Guchar)); + buildDispersedMatrix(size/2, size/2, 1, size/2, 1); + break; + + case splashScreenClustered: + mat = (Guchar *)gmallocn(size * size, sizeof(Guchar)); + buildClusteredMatrix(); + break; + + case splashScreenStochasticClustered: + // size must be at least 2*r + while (size < (params->dotRadius << 1)) { + size <<= 1; + ++log2Size; + } + mat = (Guchar *)gmallocn(size * size, sizeof(Guchar)); + buildSCDMatrix(params->dotRadius); + break; + } + + sizeM1 = size - 1; + + // do gamma correction and compute minVal/maxVal + minVal = 255; + maxVal = 0; + black = splashRound((SplashCoord)255.0 * params->blackThreshold); + if (black < 1) { + black = 1; + } + int whiteAux = splashRound((SplashCoord)255.0 * params->whiteThreshold); + if (whiteAux > 255) { + white = 255; + } else { + white = whiteAux; + } + for (i = 0; i < size * size; ++i) { + u = splashRound((SplashCoord)255.0 * + splashPow((SplashCoord)mat[i] / 255.0, params->gamma)); + if (u < black) { + u = (Guchar)black; + } else if (u >= white) { + u = (Guchar)white; + } + mat[i] = u; + if (u < minVal) { + minVal = u; + } else if (u > maxVal) { + maxVal = u; + } + } +} + +void SplashScreen::buildDispersedMatrix(int i, int j, int val, + int delta, int offset) { + if (delta == 0) { + // map values in [1, size^2] --> [1, 255] + mat[(i << log2Size) + j] = 1 + (254 * (val - 1)) / (size * size - 1); + } else { + buildDispersedMatrix(i, j, + val, delta / 2, 4*offset); + buildDispersedMatrix((i + delta) % size, (j + delta) % size, + val + offset, delta / 2, 4*offset); + buildDispersedMatrix((i + delta) % size, j, + val + 2*offset, delta / 2, 4*offset); + buildDispersedMatrix((i + 2*delta) % size, (j + delta) % size, + val + 3*offset, delta / 2, 4*offset); + } +} + +void SplashScreen::buildClusteredMatrix() { + SplashCoord *dist; + SplashCoord u, v, d; + Guchar val; + int size2, x, y, x1, y1, i; + + size2 = size >> 1; + + // initialize the threshold matrix + for (y = 0; y < size; ++y) { + for (x = 0; x < size; ++x) { + mat[(y << log2Size) + x] = 0; + } + } + + // build the distance matrix + dist = (SplashCoord *)gmallocn(size * size2, sizeof(SplashCoord)); + for (y = 0; y < size2; ++y) { + for (x = 0; x < size2; ++x) { + if (x + y < size2 - 1) { + u = (SplashCoord)x + 0.5 - 0; + v = (SplashCoord)y + 0.5 - 0; + } else { + u = (SplashCoord)x + 0.5 - (SplashCoord)size2; + v = (SplashCoord)y + 0.5 - (SplashCoord)size2; + } + dist[y * size2 + x] = u*u + v*v; + } + } + for (y = 0; y < size2; ++y) { + for (x = 0; x < size2; ++x) { + if (x < y) { + u = (SplashCoord)x + 0.5 - 0; + v = (SplashCoord)y + 0.5 - (SplashCoord)size2; + } else { + u = (SplashCoord)x + 0.5 - (SplashCoord)size2; + v = (SplashCoord)y + 0.5 - 0; + } + dist[(size2 + y) * size2 + x] = u*u + v*v; + } + } + + // build the threshold matrix + x1 = y1 = 0; // make gcc happy + for (i = 0; i < size * size2; ++i) { + d = -1; + for (y = 0; y < size; ++y) { + for (x = 0; x < size2; ++x) { + if (mat[(y << log2Size) + x] == 0 && + dist[y * size2 + x] > d) { + x1 = x; + y1 = y; + d = dist[y1 * size2 + x1]; + } + } + } + // map values in [0, 2*size*size2-1] --> [1, 255] + val = 1 + (254 * (2*i)) / (2*size*size2 - 1); + mat[(y1 << log2Size) + x1] = val; + val = 1 + (254 * (2*i+1)) / (2*size*size2 - 1); + if (y1 < size2) { + mat[((y1 + size2) << log2Size) + x1 + size2] = val; + } else { + mat[((y1 - size2) << log2Size) + x1 + size2] = val; + } + } + + gfree(dist); +} + +// Compute the distance between two points on a toroid. +int SplashScreen::distance(int x0, int y0, int x1, int y1) { + int dx0, dx1, dx, dy0, dy1, dy; + + dx0 = abs(x0 - x1); + dx1 = size - dx0; + dx = dx0 < dx1 ? dx0 : dx1; + dy0 = abs(y0 - y1); + dy1 = size - dy0; + dy = dy0 < dy1 ? dy0 : dy1; + return dx * dx + dy * dy; +} + +// Algorithm taken from: +// Victor Ostromoukhov and Roger D. Hersch, "Stochastic Clustered-Dot +// Dithering" in Color Imaging: Device-Independent Color, Color +// Hardcopy, and Graphic Arts IV, SPIE Vol. 3648, pp. 496-505, 1999. +void SplashScreen::buildSCDMatrix(int r) { + SplashScreenPoint *dots, *pts; + int dotsLen, dotsSize; + char *tmpl; + char *grid; + int *region, *dist; + int x, y, xx, yy, x0, x1, y0, y1, i, j, d, iMin, dMin, n; + + // generate the random space-filling curve + pts = (SplashScreenPoint *)gmallocn(size * size, sizeof(SplashScreenPoint)); + i = 0; + for (y = 0; y < size; ++y) { + for (x = 0; x < size; ++x) { + pts[i].x = x; + pts[i].y = y; + ++i; + } + } + for (i = 0; i < size * size; ++i) { + j = i + (int)((double)(size * size - i) * grandom_double()); + x = pts[i].x; + y = pts[i].y; + pts[i].x = pts[j].x; + pts[i].y = pts[j].y; + pts[j].x = x; + pts[j].y = y; + } + + // construct the circle template + tmpl = (char *)gmallocn((r+1)*(r+1), sizeof(char)); + for (y = 0; y <= r; ++y) { + for (x = 0; x <= r; ++x) { + tmpl[y*(r+1) + x] = (x * y <= r * r) ? 1 : 0; + } + } + + // mark all grid cells as free + grid = (char *)gmallocn(size * size, sizeof(char)); + for (y = 0; y < size; ++y) { + for (x = 0; x < size; ++x) { + grid[(y << log2Size) + x] = 0; + } + } + + // walk the space-filling curve, adding dots + dotsLen = 0; + dotsSize = 32; + dots = (SplashScreenPoint *)gmallocn(dotsSize, sizeof(SplashScreenPoint)); + for (i = 0; i < size * size; ++i) { + x = pts[i].x; + y = pts[i].y; + if (!grid[(y << log2Size) + x]) { + if (dotsLen == dotsSize) { + dotsSize *= 2; + dots = (SplashScreenPoint *)greallocn(dots, dotsSize, + sizeof(SplashScreenPoint)); + } + dots[dotsLen++] = pts[i]; + for (yy = 0; yy <= r; ++yy) { + y0 = (y + yy) % size; + y1 = (y - yy + size) % size; + for (xx = 0; xx <= r; ++xx) { + if (tmpl[yy*(r+1) + xx]) { + x0 = (x + xx) % size; + x1 = (x - xx + size) % size; + grid[(y0 << log2Size) + x0] = 1; + grid[(y0 << log2Size) + x1] = 1; + grid[(y1 << log2Size) + x0] = 1; + grid[(y1 << log2Size) + x1] = 1; + } + } + } + } + } + + gfree(tmpl); + gfree(grid); + + // assign each cell to a dot, compute distance to center of dot + region = (int *)gmallocn(size * size, sizeof(int)); + dist = (int *)gmallocn(size * size, sizeof(int)); + for (y = 0; y < size; ++y) { + for (x = 0; x < size; ++x) { + iMin = 0; + dMin = distance(dots[0].x, dots[0].y, x, y); + for (i = 1; i < dotsLen; ++i) { + d = distance(dots[i].x, dots[i].y, x, y); + if (d < dMin) { + iMin = i; + dMin = d; + } + } + region[(y << log2Size) + x] = iMin; + dist[(y << log2Size) + x] = dMin; + } + } + + // compute threshold values + for (i = 0; i < dotsLen; ++i) { + n = 0; + for (y = 0; y < size; ++y) { + for (x = 0; x < size; ++x) { + if (region[(y << log2Size) + x] == i) { + pts[n].x = x; + pts[n].y = y; + pts[n].dist = distance(dots[i].x, dots[i].y, x, y); + ++n; + } + } + } + std::sort(pts, pts + n, cmpDistancesFunctor()); + for (j = 0; j < n; ++j) { + // map values in [0 .. n-1] --> [255 .. 1] + mat[(pts[j].y << log2Size) + pts[j].x] = 255 - (254 * j) / (n - 1); + } + } + + gfree(pts); + gfree(region); + gfree(dist); + + gfree(dots); +} + +SplashScreen::SplashScreen(SplashScreen *screen) { + screenParams = screen->screenParams; + size = screen->size; + sizeM1 = screen->sizeM1; + log2Size = screen->log2Size; + mat = (Guchar *)gmallocn(size * size, sizeof(Guchar)); + memcpy(mat, screen->mat, size * size * sizeof(Guchar)); + minVal = screen->minVal; + maxVal = screen->maxVal; +} + +SplashScreen::~SplashScreen() { + gfree(mat); +} diff --git a/Build/source/libs/poppler/poppler-0.33.0/splash/SplashScreen.h b/Build/source/libs/poppler/poppler-0.33.0/splash/SplashScreen.h new file mode 100644 index 00000000000..a7fc4559148 --- /dev/null +++ b/Build/source/libs/poppler/poppler-0.33.0/splash/SplashScreen.h @@ -0,0 +1,80 @@ +//======================================================================== +// +// SplashScreen.h +// +//======================================================================== + +//======================================================================== +// +// Modified under the Poppler project - http://poppler.freedesktop.org +// +// All changes made under the Poppler project to this file are licensed +// under GPL version 2 or later +// +// Copyright (C) 2009 Albert Astals Cid <aacid@kde.org> +// +// To see a description of the changes please see the Changelog file that +// came with your tarball or type make ChangeLog if you are building from git +// +//======================================================================== + +#ifndef SPLASHSCREEN_H +#define SPLASHSCREEN_H + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "SplashTypes.h" + +#include <stdlib.h> + +//------------------------------------------------------------------------ +// SplashScreen +//------------------------------------------------------------------------ + +class SplashScreen { +public: + + SplashScreen(SplashScreenParams *params); + SplashScreen(SplashScreen *screen); + ~SplashScreen(); + + SplashScreen *copy() { return new SplashScreen(this); } + + // Return the computed pixel value (0=black, 1=white) for the gray + // level <value> at (<x>, <y>). + int test(int x, int y, Guchar value) { + int xx, yy; + if (mat == NULL) createMatrix(); + xx = x & sizeM1; + yy = y & sizeM1; + return value < mat[(yy << log2Size) + xx] ? 0 : 1; + } + + // Returns true if value is above the white threshold or below the + // black threshold, i.e., if the corresponding halftone will be + // solid white or black. + GBool isStatic(Guchar value) { if (mat == NULL) createMatrix(); return value < minVal || value >= maxVal; } + +private: + void createMatrix(); + + void buildDispersedMatrix(int i, int j, int val, + int delta, int offset); + void buildClusteredMatrix(); + int distance(int x0, int y0, int x1, int y1); + void buildSCDMatrix(int r); + + SplashScreenParams *screenParams; // params to create the other members + Guchar *mat; // threshold matrix + int size; // size of the threshold matrix + int sizeM1; // size - 1 + int log2Size; // log2(size) + Guchar minVal; // any pixel value below minVal generates + // solid black + Guchar maxVal; // any pixel value above maxVal generates + // solid white +}; + +#endif diff --git a/Build/source/libs/poppler/poppler-0.33.0/splash/SplashState.cc b/Build/source/libs/poppler/poppler-0.33.0/splash/SplashState.cc new file mode 100644 index 00000000000..fd2789d02f9 --- /dev/null +++ b/Build/source/libs/poppler/poppler-0.33.0/splash/SplashState.cc @@ -0,0 +1,263 @@ +//======================================================================== +// +// SplashState.cc +// +//======================================================================== + +//======================================================================== +// +// Modified under the Poppler project - http://poppler.freedesktop.org +// +// All changes made under the Poppler project to this file are licensed +// under GPL version 2 or later +// +// Copyright (C) 2009, 2011, 2012 Thomas Freitag <Thomas.Freitag@alfa.de> +// +// To see a description of the changes please see the Changelog file that +// came with your tarball or type make ChangeLog if you are building from git +// +//======================================================================== + +#include <config.h> + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include <string.h> +#include "goo/gmem.h" +#include "SplashPattern.h" +#include "SplashScreen.h" +#include "SplashClip.h" +#include "SplashBitmap.h" +#include "SplashState.h" + +//------------------------------------------------------------------------ +// SplashState +//------------------------------------------------------------------------ + +// number of components in each color mode +int splashColorModeNComps[] = { + 1, 1, 3, 3, 4 +#if SPLASH_CMYK + , 4, 4 + SPOT_NCOMPS +#endif +}; + +SplashState::SplashState(int width, int height, GBool vectorAntialias, + SplashScreenParams *screenParams) { + SplashColor color; + int i; + + matrix[0] = 1; matrix[1] = 0; + matrix[2] = 0; matrix[3] = 1; + matrix[4] = 0; matrix[5] = 0; + memset(&color, 0, sizeof(SplashColor)); + strokePattern = new SplashSolidColor(color); + fillPattern = new SplashSolidColor(color); + screen = new SplashScreen(screenParams); + blendFunc = NULL; + strokeAlpha = 1; + fillAlpha = 1; + lineWidth = 0; + lineCap = splashLineCapButt; + lineJoin = splashLineJoinMiter; + miterLimit = 10; + flatness = 1; + lineDash = NULL; + lineDashLength = 0; + lineDashPhase = 0; + strokeAdjust = gFalse; + clip = new SplashClip(0, 0, width - 0.001, height - 0.001, vectorAntialias); + softMask = NULL; + deleteSoftMask = gFalse; + inNonIsolatedGroup = gFalse; + fillOverprint = gFalse; + strokeOverprint = gFalse; + overprintMode = 0; + for (i = 0; i < 256; ++i) { + rgbTransferR[i] = (Guchar)i; + rgbTransferG[i] = (Guchar)i; + rgbTransferB[i] = (Guchar)i; + grayTransfer[i] = (Guchar)i; +#if SPLASH_CMYK + cmykTransferC[i] = (Guchar)i; + cmykTransferM[i] = (Guchar)i; + cmykTransferY[i] = (Guchar)i; + cmykTransferK[i] = (Guchar)i; + for (int cp = 0; cp < SPOT_NCOMPS+4; cp++) + deviceNTransfer[cp][i] = (Guchar)i; +#endif + } + overprintMask = 0xffffffff; + overprintAdditive = gFalse; + next = NULL; +} + +SplashState::SplashState(int width, int height, GBool vectorAntialias, + SplashScreen *screenA) { + SplashColor color; + int i; + + matrix[0] = 1; matrix[1] = 0; + matrix[2] = 0; matrix[3] = 1; + matrix[4] = 0; matrix[5] = 0; + memset(&color, 0, sizeof(SplashColor)); + strokePattern = new SplashSolidColor(color); + fillPattern = new SplashSolidColor(color); + screen = screenA->copy(); + blendFunc = NULL; + strokeAlpha = 1; + fillAlpha = 1; + lineWidth = 0; + lineCap = splashLineCapButt; + lineJoin = splashLineJoinMiter; + miterLimit = 10; + flatness = 1; + lineDash = NULL; + lineDashLength = 0; + lineDashPhase = 0; + strokeAdjust = gFalse; + clip = new SplashClip(0, 0, width - 0.001, height - 0.001, vectorAntialias); + softMask = NULL; + deleteSoftMask = gFalse; + inNonIsolatedGroup = gFalse; + fillOverprint = gFalse; + strokeOverprint = gFalse; + overprintMode = 0; + for (i = 0; i < 256; ++i) { + rgbTransferR[i] = (Guchar)i; + rgbTransferG[i] = (Guchar)i; + rgbTransferB[i] = (Guchar)i; + grayTransfer[i] = (Guchar)i; +#if SPLASH_CMYK + cmykTransferC[i] = (Guchar)i; + cmykTransferM[i] = (Guchar)i; + cmykTransferY[i] = (Guchar)i; + cmykTransferK[i] = (Guchar)i; + for (int cp = 0; cp < SPOT_NCOMPS+4; cp++) + deviceNTransfer[cp][i] = (Guchar)i; +#endif + } + overprintMask = 0xffffffff; + overprintAdditive = gFalse; + next = NULL; +} + +SplashState::SplashState(SplashState *state) { + memcpy(matrix, state->matrix, 6 * sizeof(SplashCoord)); + strokePattern = state->strokePattern->copy(); + fillPattern = state->fillPattern->copy(); + screen = state->screen->copy(); + blendFunc = state->blendFunc; + strokeAlpha = state->strokeAlpha; + fillAlpha = state->fillAlpha; + lineWidth = state->lineWidth; + lineCap = state->lineCap; + lineJoin = state->lineJoin; + miterLimit = state->miterLimit; + flatness = state->flatness; + if (state->lineDash) { + lineDashLength = state->lineDashLength; + lineDash = (SplashCoord *)gmallocn(lineDashLength, sizeof(SplashCoord)); + memcpy(lineDash, state->lineDash, lineDashLength * sizeof(SplashCoord)); + } else { + lineDash = NULL; + lineDashLength = 0; + } + lineDashPhase = state->lineDashPhase; + strokeAdjust = state->strokeAdjust; + clip = state->clip->copy(); + softMask = state->softMask; + deleteSoftMask = gFalse; + inNonIsolatedGroup = state->inNonIsolatedGroup; + fillOverprint = state->fillOverprint; + strokeOverprint = state->strokeOverprint; + overprintMode = state->overprintMode; + memcpy(rgbTransferR, state->rgbTransferR, 256); + memcpy(rgbTransferG, state->rgbTransferG, 256); + memcpy(rgbTransferB, state->rgbTransferB, 256); + memcpy(grayTransfer, state->grayTransfer, 256); +#if SPLASH_CMYK + memcpy(cmykTransferC, state->cmykTransferC, 256); + memcpy(cmykTransferM, state->cmykTransferM, 256); + memcpy(cmykTransferY, state->cmykTransferY, 256); + memcpy(cmykTransferK, state->cmykTransferK, 256); + for (int cp = 0; cp < SPOT_NCOMPS+4; cp++) + memcpy(deviceNTransfer[cp], state->deviceNTransfer[cp], 256); +#endif + overprintMask = state->overprintMask; + overprintAdditive = state->overprintAdditive; + next = NULL; +} + +SplashState::~SplashState() { + delete strokePattern; + delete fillPattern; + delete screen; + gfree(lineDash); + delete clip; + if (deleteSoftMask && softMask) { + delete softMask; + } +} + +void SplashState::setStrokePattern(SplashPattern *strokePatternA) { + delete strokePattern; + strokePattern = strokePatternA; +} + +void SplashState::setFillPattern(SplashPattern *fillPatternA) { + delete fillPattern; + fillPattern = fillPatternA; +} + +void SplashState::setScreen(SplashScreen *screenA) { + delete screen; + screen = screenA; +} + +void SplashState::setLineDash(SplashCoord *lineDashA, int lineDashLengthA, + SplashCoord lineDashPhaseA) { + gfree(lineDash); + lineDashLength = lineDashLengthA; + if (lineDashLength > 0) { + lineDash = (SplashCoord *)gmallocn(lineDashLength, sizeof(SplashCoord)); + memcpy(lineDash, lineDashA, lineDashLength * sizeof(SplashCoord)); + } else { + lineDash = NULL; + } + lineDashPhase = lineDashPhaseA; +} + +void SplashState::setSoftMask(SplashBitmap *softMaskA) { + if (deleteSoftMask) { + delete softMask; + } + softMask = softMaskA; + deleteSoftMask = gTrue; +} + +void SplashState::setTransfer(Guchar *red, Guchar *green, Guchar *blue, + Guchar *gray) { +#if SPLASH_CMYK + int i; + + 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]; + } + for (i = 0; i < 256; ++i) { + deviceNTransfer[0][i] = 255 - rgbTransferR[255 - i]; + deviceNTransfer[1][i] = 255 - rgbTransferG[255 - i]; + deviceNTransfer[2][i] = 255 - rgbTransferB[255 - i]; + deviceNTransfer[3][i] = 255 - grayTransfer[255 - i]; + } +#endif + memcpy(rgbTransferR, red, 256); + memcpy(rgbTransferG, green, 256); + memcpy(rgbTransferB, blue, 256); + memcpy(grayTransfer, gray, 256); +} diff --git a/Build/source/libs/poppler/poppler-0.33.0/splash/SplashState.h b/Build/source/libs/poppler/poppler-0.33.0/splash/SplashState.h new file mode 100644 index 00000000000..2c603531cfd --- /dev/null +++ b/Build/source/libs/poppler/poppler-0.33.0/splash/SplashState.h @@ -0,0 +1,139 @@ +//======================================================================== +// +// SplashState.h +// +//======================================================================== + +//======================================================================== +// +// Modified under the Poppler project - http://poppler.freedesktop.org +// +// All changes made under the Poppler project to this file are licensed +// under GPL version 2 or later +// +// Copyright (C) 2011, 2012 Thomas Freitag <Thomas.Freitag@alfa.de> +// +// To see a description of the changes please see the Changelog file that +// came with your tarball or type make ChangeLog if you are building from git +// +//======================================================================== + +#ifndef SPLASHSTATE_H +#define SPLASHSTATE_H + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "SplashTypes.h" + +class SplashPattern; +class SplashScreen; +class SplashClip; +class SplashBitmap; + +//------------------------------------------------------------------------ +// line cap values +//------------------------------------------------------------------------ + +#define splashLineCapButt 0 +#define splashLineCapRound 1 +#define splashLineCapProjecting 2 + +//------------------------------------------------------------------------ +// line join values +//------------------------------------------------------------------------ + +#define splashLineJoinMiter 0 +#define splashLineJoinRound 1 +#define splashLineJoinBevel 2 + +//------------------------------------------------------------------------ +// SplashState +//------------------------------------------------------------------------ + +class SplashState { +public: + + // Create a new state object, initialized with default settings. + SplashState(int width, int height, GBool vectorAntialias, + SplashScreenParams *screenParams); + SplashState(int width, int height, GBool vectorAntialias, + SplashScreen *screenA); + + // Copy a state object. + SplashState *copy() { return new SplashState(this); } + + ~SplashState(); + + // Set the stroke pattern. This does not copy <strokePatternA>. + void setStrokePattern(SplashPattern *strokePatternA); + + // Set the fill pattern. This does not copy <fillPatternA>. + void setFillPattern(SplashPattern *fillPatternA); + + // Set the screen. This does not copy <screenA>. + void setScreen(SplashScreen *screenA); + + // Set the line dash pattern. This copies the <lineDashA> array. + void setLineDash(SplashCoord *lineDashA, int lineDashLengthA, + SplashCoord lineDashPhaseA); + + // Set the soft mask bitmap. + void setSoftMask(SplashBitmap *softMaskA); + + // Set the overprint parametes. + void setFillOverprint(GBool fillOverprintA) { fillOverprint = fillOverprintA; } + void setStrokeOverprint(GBool strokeOverprintA) { strokeOverprint = strokeOverprintA; } + void setOverprintMode(int overprintModeA) { overprintMode = overprintModeA; } + + // Set the transfer function. + void setTransfer(Guchar *red, Guchar *green, Guchar *blue, Guchar *gray); + +private: + + SplashState(SplashState *state); + + SplashCoord matrix[6]; + SplashPattern *strokePattern; + SplashPattern *fillPattern; + SplashScreen *screen; + SplashBlendFunc blendFunc; + SplashCoord strokeAlpha; + SplashCoord fillAlpha; + SplashCoord lineWidth; + int lineCap; + int lineJoin; + SplashCoord miterLimit; + SplashCoord flatness; + SplashCoord *lineDash; + int lineDashLength; + SplashCoord lineDashPhase; + GBool strokeAdjust; + SplashClip *clip; + SplashBitmap *softMask; + GBool deleteSoftMask; + GBool inNonIsolatedGroup; + GBool fillOverprint; + GBool strokeOverprint; + int overprintMode; + Guchar rgbTransferR[256], + rgbTransferG[256], + rgbTransferB[256]; + Guchar grayTransfer[256]; +#if SPLASH_CMYK + Guchar cmykTransferC[256], + cmykTransferM[256], + cmykTransferY[256], + cmykTransferK[256]; + Guchar deviceNTransfer[SPOT_NCOMPS+4][256]; +#endif + Guint overprintMask; + GBool overprintAdditive; + + SplashState *next; // used by Splash class + + friend class Splash; +}; + +#endif diff --git a/Build/source/libs/poppler/poppler-0.33.0/splash/SplashT1Font.cc b/Build/source/libs/poppler/poppler-0.33.0/splash/SplashT1Font.cc new file mode 100644 index 00000000000..0fdfaaf5150 --- /dev/null +++ b/Build/source/libs/poppler/poppler-0.33.0/splash/SplashT1Font.cc @@ -0,0 +1,309 @@ +//======================================================================== +// +// SplashT1Font.cc +// +//======================================================================== + +//======================================================================== +// +// Modified under the Poppler project - http://poppler.freedesktop.org +// +// All changes made under the Poppler project to this file are licensed +// under GPL version 2 or later +// +// Copyright (C) 2007 Albert Astals Cid <aacid@kde.org> +// +// To see a description of the changes please see the Changelog file that +// came with your tarball or type make ChangeLog if you are building from git +// +//======================================================================== + +#include <config.h> + +#if HAVE_T1LIB_H + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include <stdlib.h> +#include <t1lib.h> +#include "goo/gmem.h" +#include "SplashMath.h" +#include "SplashGlyphBitmap.h" +#include "SplashPath.h" +#include "SplashT1FontEngine.h" +#include "SplashT1FontFile.h" +#include "SplashT1Font.h" + +//------------------------------------------------------------------------ + +static Guchar bitReverse[256] = { + 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, + 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, + 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, + 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, + 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, + 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, + 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, + 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, + 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, + 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, + 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, + 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, + 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, + 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, + 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, + 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, + 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, + 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, + 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, + 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, + 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, + 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, + 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, + 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, + 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, + 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, + 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, + 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, + 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, + 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, + 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, + 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff +}; + +//------------------------------------------------------------------------ +// SplashT1Font +//------------------------------------------------------------------------ + +SplashT1Font::SplashT1Font(SplashT1FontFile *fontFileA, SplashCoord *matA, + SplashCoord *textMatA): + SplashFont(fontFileA, matA, textMatA, fontFileA->engine->aa) +{ + T1_TMATRIX matrix; + BBox bbox; + SplashCoord bbx0, bby0, bbx1, bby1; + int x, y; + + t1libID = T1_CopyFont(fontFileA->t1libID); + outlineID = -1; + + // compute font size + size = (float)splashDist(0, 0, mat[2], mat[3]); + + // transform the four corners of the font bounding box -- the min + // and max values form the bounding box of the transformed font + bbox = T1_GetFontBBox(t1libID); + bbx0 = 0.001 * bbox.llx; + bby0 = 0.001 * bbox.lly; + bbx1 = 0.001 * bbox.urx; + bby1 = 0.001 * bbox.ury; + // some fonts are completely broken, so we fake it (with values + // large enough that most glyphs should fit) + if (bbx0 == 0 && bby0 == 0 && bbx1 == 0 && bby1 == 0) { + bbx0 = bby0 = -0.5; + bbx1 = bby1 = 1.5; + } + x = (int)(mat[0] * bbx0 + mat[2] * bby0); + xMin = xMax = x; + y = (int)(mat[1] * bbx0 + mat[3] * bby0); + yMin = yMax = y; + x = (int)(mat[0] * bbx0 + mat[2] * bby1); + if (x < xMin) { + xMin = x; + } else if (x > xMax) { + xMax = x; + } + y = (int)(mat[1] * bbx0 + mat[3] * bby1); + if (y < yMin) { + yMin = y; + } else if (y > yMax) { + yMax = y; + } + x = (int)(mat[0] * bbx1 + mat[2] * bby0); + if (x < xMin) { + xMin = x; + } else if (x > xMax) { + xMax = x; + } + y = (int)(mat[1] * bbx1 + mat[3] * bby0); + if (y < yMin) { + yMin = y; + } else if (y > yMax) { + yMax = y; + } + x = (int)(mat[0] * bbx1 + mat[2] * bby1); + if (x < xMin) { + xMin = x; + } else if (x > xMax) { + xMax = x; + } + y = (int)(mat[1] * bbx1 + mat[3] * bby1); + if (y < yMin) { + yMin = y; + } else if (y > yMax) { + yMax = y; + } + // This is a kludge: some buggy PDF generators embed fonts with + // zero bounding boxes. + if (xMax == xMin) { + xMin = 0; + xMax = (int)size; + } + if (yMax == yMin) { + yMin = 0; + yMax = (int)(1.2 * size); + } + // Another kludge: an unusually large xMin or yMin coordinate is + // probably wrong. + if (xMin > 0) { + xMin = 0; + } + if (yMin > 0) { + yMin = 0; + } + // Another kludge: t1lib doesn't correctly handle fonts with + // real (non-integer) bounding box coordinates. + if (xMax - xMin > 5000) { + xMin = 0; + xMax = (int)size; + } + if (yMax - yMin > 5000) { + yMin = 0; + yMax = (int)(1.2 * size); + } + + // transform the font + matrix.cxx = (double)mat[0] / size; + matrix.cxy = (double)mat[1] / size; + matrix.cyx = (double)mat[2] / size; + matrix.cyy = (double)mat[3] / size; + T1_TransformFont(t1libID, &matrix); +} + +SplashT1Font::~SplashT1Font() { + T1_DeleteFont(t1libID); + if (outlineID >= 0) { + T1_DeleteFont(outlineID); + } +} + +GBool SplashT1Font::getGlyph(int c, int xFrac, int yFrac, + SplashGlyphBitmap *bitmap, int x0, int y0, SplashClip *clip, SplashClipResult *clipRes) { + return SplashFont::getGlyph(c, 0, 0, bitmap, x0, y0, clip, clipRes); +} + +GBool SplashT1Font::makeGlyph(int c, int xFrac, int yFrac, + SplashGlyphBitmap *bitmap, int x0, int y0, SplashClip *clip, SplashClipResult *clipRes) { + GLYPH *glyph; + int n, i; + + if (aa) { + glyph = T1_AASetChar(t1libID, c, size, NULL); + } else { + glyph = T1_SetChar(t1libID, c, size, NULL); + } + if (!glyph) { + return gFalse; + } + + bitmap->x = -glyph->metrics.leftSideBearing; + bitmap->y = glyph->metrics.ascent; + bitmap->w = glyph->metrics.rightSideBearing - glyph->metrics.leftSideBearing; + bitmap->h = glyph->metrics.ascent - glyph->metrics.descent; + bitmap->aa = aa; + if (aa) { + bitmap->data = (Guchar *)glyph->bits; + bitmap->freeData = gFalse; + } else { + n = bitmap->h * ((bitmap->w + 7) >> 3); + bitmap->data = (Guchar *)gmalloc(n); + for (i = 0; i < n; ++i) { + bitmap->data[i] = bitReverse[glyph->bits[i] & 0xff]; + } + bitmap->freeData = gTrue; + } + + *clipRes = clip->testRect(x0 - bitmap->x, + y0 - bitmap->y, + x0 - bitmap->x + bitmap->w - 1, + y0 - bitmap->y + bitmap->h - 1); + + return gTrue; +} + +SplashPath *SplashT1Font::getGlyphPath(int c) { + T1_TMATRIX matrix; + SplashPath *path; + T1_OUTLINE *outline; + T1_PATHSEGMENT *seg; + T1_BEZIERSEGMENT *bez; + int x, y, x1, y1; + GBool needClose; + + if (outlineID < 0) { + outlineID = T1_CopyFont(((SplashT1FontFile *)fontFile)->t1libID); + outlineSize = (float)splashDist(0, 0, textMat[2], textMat[3]); + matrix.cxx = (double)textMat[0] / outlineSize; + matrix.cxy = (double)textMat[1] / outlineSize; + matrix.cyx = (double)textMat[2] / outlineSize; + matrix.cyy = (double)textMat[3] / outlineSize; + // t1lib doesn't seem to handle small sizes correctly here, so set + // the size to 1000, and scale the resulting coordinates later + outlineMul = (float)(outlineSize / 65536000.0); + outlineSize = 1000; + T1_TransformFont(outlineID, &matrix); + } + + path = new SplashPath(); + if ((outline = T1_GetCharOutline(outlineID, c, outlineSize, NULL))) { + // NB: t1lib uses integer coordinates here; we keep a running + // (x,y) total as integers, so that the final point in the path is + // exactly the same as the first point, thus avoiding weird + // mitered join glitches + x = y = 0; + needClose = gFalse; + for (seg = outline; seg; seg = seg->link) { + switch (seg->type) { + case T1_PATHTYPE_MOVE: + if (needClose) { + path->close(); + needClose = gFalse; + } + x += seg->dest.x; + y += seg->dest.y; + path->moveTo(outlineMul * x, -outlineMul * y); + break; + case T1_PATHTYPE_LINE: + x += seg->dest.x; + y += seg->dest.y; + path->lineTo(outlineMul * x, -outlineMul * y); + needClose = gTrue; + break; + case T1_PATHTYPE_BEZIER: + bez = (T1_BEZIERSEGMENT *)seg; + x1 = x + bez->dest.x; + y1 = y + bez->dest.y; + path->curveTo(outlineMul * (x + bez->B.x), + -outlineMul * (y + bez->B.y), + outlineMul * (x + bez->C.x), + -outlineMul * (y + bez->C.y), + outlineMul * x1, + -outlineMul * y1); + x = x1; + y = y1; + needClose = gTrue; + break; + } + } + if (needClose) { + path->close(); + } + T1_FreeOutline(outline); + } + + return path; +} + +#endif // HAVE_T1LIB_H diff --git a/Build/source/libs/poppler/poppler-0.33.0/splash/SplashT1Font.h b/Build/source/libs/poppler/poppler-0.33.0/splash/SplashT1Font.h new file mode 100644 index 00000000000..1dbe66cd7fc --- /dev/null +++ b/Build/source/libs/poppler/poppler-0.33.0/splash/SplashT1Font.h @@ -0,0 +1,69 @@ +//======================================================================== +// +// SplashT1Font.h +// +//======================================================================== + +//======================================================================== +// +// Modified under the Poppler project - http://poppler.freedesktop.org +// +// All changes made under the Poppler project to this file are licensed +// under GPL version 2 or later +// +// Copyright (C) 2007 Albert Astals Cid <aacid@kde.org> +// +// To see a description of the changes please see the Changelog file that +// came with your tarball or type make ChangeLog if you are building from git +// +//======================================================================== + +#ifndef SPLASHT1FONT_H +#define SPLASHT1FONT_H + +#if HAVE_T1LIB_H + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "SplashFont.h" + +class SplashT1FontFile; + +//------------------------------------------------------------------------ +// SplashT1Font +//------------------------------------------------------------------------ + +class SplashT1Font: public SplashFont { +public: + + SplashT1Font(SplashT1FontFile *fontFileA, SplashCoord *matA, + SplashCoord *textMatA); + + virtual ~SplashT1Font(); + + // Munge xFrac and yFrac before calling SplashFont::getGlyph. + virtual GBool getGlyph(int c, int xFrac, int yFrac, + SplashGlyphBitmap *bitmap, int x0, int y0, SplashClip *clip, SplashClipResult *clipRes); + + // Rasterize a glyph. The <xFrac> and <yFrac> values are the same + // as described for getGlyph. + virtual GBool makeGlyph(int c, int xFrac, int yFrac, + SplashGlyphBitmap *bitmap, int x0, int y0, SplashClip *clip, SplashClipResult *clipRes); + + // Return the path for a glyph. + virtual SplashPath *getGlyphPath(int c); + +private: + + int t1libID; // t1lib font ID + int outlineID; // t1lib font ID for glyph outlines + float size; + float outlineSize; // size for glyph outlines + float outlineMul; +}; + +#endif // HAVE_T1LIB_H + +#endif diff --git a/Build/source/libs/poppler/poppler-0.33.0/splash/SplashT1FontEngine.cc b/Build/source/libs/poppler/poppler-0.33.0/splash/SplashT1FontEngine.cc new file mode 100644 index 00000000000..fb4b38dae88 --- /dev/null +++ b/Build/source/libs/poppler/poppler-0.33.0/splash/SplashT1FontEngine.cc @@ -0,0 +1,138 @@ +//======================================================================== +// +// SplashT1FontEngine.cc +// +//======================================================================== + +//======================================================================== +// +// Modified under the Poppler project - http://poppler.freedesktop.org +// +// All changes made under the Poppler project to this file are licensed +// under GPL version 2 or later +// +// Copyright (C) 2006 Takashi Iwai <tiwai@suse.de> +// Copyright (C) 2009 Albert Astals Cid <aacid@kde.org> +// +// To see a description of the changes please see the Changelog file that +// came with your tarball or type make ChangeLog if you are building from git +// +//======================================================================== + +#include <config.h> + +#if HAVE_T1LIB_H + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include <stdlib.h> +#include <stdio.h> +#ifdef HAVE_UNISTD_H +# include <unistd.h> +#endif +#include <t1lib.h> +#include "goo/GooString.h" +#include "goo/gfile.h" +#include "fofi/FoFiType1C.h" +#include "SplashT1FontFile.h" +#include "SplashT1FontEngine.h" + +#ifdef VMS +#if (__VMS_VER < 70000000) +extern "C" int unlink(char *filename); +#endif +#endif + +//------------------------------------------------------------------------ + +int SplashT1FontEngine::t1libInitCount = 0; + +//------------------------------------------------------------------------ + +static void fileWrite(void *stream, const char *data, int len) { + fwrite(data, 1, len, (FILE *)stream); +} + +//------------------------------------------------------------------------ +// SplashT1FontEngine +//------------------------------------------------------------------------ + +SplashT1FontEngine::SplashT1FontEngine(GBool aaA) { + aa = aaA; +} + +SplashT1FontEngine *SplashT1FontEngine::init(GBool aaA) { + // grayVals[i] = round(i * 255 / 16) + static unsigned long grayVals[17] = { + 0, 16, 32, 48, 64, 80, 96, 112, 128, 143, 159, 175, 191, 207, 223, 239, 255 + }; + + //~ for multithreading: need a mutex here + if (t1libInitCount == 0) { + T1_SetBitmapPad(8); + if (!T1_InitLib(NO_LOGFILE | IGNORE_CONFIGFILE | IGNORE_FONTDATABASE | + T1_NO_AFM)) { + return NULL; + } + if (aaA) { + T1_AASetBitsPerPixel(8); + T1_AASetLevel(T1_AA_HIGH); + T1_AAHSetGrayValues(grayVals); + } else { + T1_AANSetGrayValues(0, 1); + } + } + ++t1libInitCount; + + return new SplashT1FontEngine(aaA); +} + +SplashT1FontEngine::~SplashT1FontEngine() { + //~ for multithreading: need a mutex here + if (--t1libInitCount == 0) { + T1_CloseLib(); + } +} + +SplashFontFile *SplashT1FontEngine::loadType1Font(SplashFontFileID *idA, + SplashFontSrc *src, + const char **enc) { + return SplashT1FontFile::loadType1Font(this, idA, src, enc); +} + +SplashFontFile *SplashT1FontEngine::loadType1CFont(SplashFontFileID *idA, + SplashFontSrc *src, + const char **enc) { + FoFiType1C *ff; + GooString *tmpFileName; + FILE *tmpFile; + SplashFontFile *ret; + + SplashFontSrc *newsrc; + + if (src->isFile) + ff = FoFiType1C::load(src->fileName->getCString()); + else + ff = FoFiType1C::make(src->buf, src->bufLen); + if (! ff) + return NULL; + + tmpFileName = NULL; + if (!openTempFile(&tmpFileName, &tmpFile, "wb")) { + delete ff; + return NULL; + } + ff->convertToType1(NULL, NULL, gTrue, &fileWrite, tmpFile); + delete ff; + fclose(tmpFile); + newsrc = new SplashFontSrc; + newsrc->setFile(tmpFileName, gTrue); + delete tmpFileName; + ret = SplashT1FontFile::loadType1Font(this, idA, newsrc, enc); + newsrc->unref(); + return ret; +} + +#endif // HAVE_T1LIB_H diff --git a/Build/source/libs/poppler/poppler-0.33.0/splash/SplashT1FontEngine.h b/Build/source/libs/poppler/poppler-0.33.0/splash/SplashT1FontEngine.h new file mode 100644 index 00000000000..268a01479b0 --- /dev/null +++ b/Build/source/libs/poppler/poppler-0.33.0/splash/SplashT1FontEngine.h @@ -0,0 +1,50 @@ +//======================================================================== +// +// SplashT1FontEngine.h +// +//======================================================================== + +#ifndef SPLASHT1FONTENGINE_H +#define SPLASHT1FONTENGINE_H + +#if HAVE_T1LIB_H + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "goo/gtypes.h" + +class SplashFontFile; +class SplashFontFileID; +class SplashFontSrc; + +//------------------------------------------------------------------------ +// SplashT1FontEngine +//------------------------------------------------------------------------ + +class SplashT1FontEngine { +public: + + static SplashT1FontEngine *init(GBool aaA); + + ~SplashT1FontEngine(); + + // Load fonts. + SplashFontFile *loadType1Font(SplashFontFileID *idA, SplashFontSrc *src, const char **enc); + SplashFontFile *loadType1CFont(SplashFontFileID *idA, SplashFontSrc *src, const char **enc); + +private: + + SplashT1FontEngine(GBool aaA); + + static int t1libInitCount; + GBool aa; + + friend class SplashT1FontFile; + friend class SplashT1Font; +}; + +#endif // HAVE_T1LIB_H + +#endif diff --git a/Build/source/libs/poppler/poppler-0.33.0/splash/SplashT1FontFile.cc b/Build/source/libs/poppler/poppler-0.33.0/splash/SplashT1FontFile.cc new file mode 100644 index 00000000000..1832a916d9a --- /dev/null +++ b/Build/source/libs/poppler/poppler-0.33.0/splash/SplashT1FontFile.cc @@ -0,0 +1,134 @@ +//======================================================================== +// +// SplashT1FontFile.cc +// +//======================================================================== + +//======================================================================== +// +// Modified under the Poppler project - http://poppler.freedesktop.org +// +// All changes made under the Poppler project to this file are licensed +// under GPL version 2 or later +// +// Copyright (C) 2006 Takashi Iwai <tiwai@suse.de> +// Copyright (C) 2009 Albert Astals Cid <aacid@kde.org> +// +// To see a description of the changes please see the Changelog file that +// came with your tarball or type make ChangeLog if you are building from git +// +//======================================================================== + +#include <config.h> + +#if HAVE_T1LIB_H + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include <string.h> +#include <t1lib.h> +#include "goo/GooString.h" +#include "goo/gfile.h" +#include "goo/gmem.h" +#include "SplashT1FontEngine.h" +#include "SplashT1Font.h" +#include "SplashT1FontFile.h" + +//------------------------------------------------------------------------ +// SplashT1FontFile +//------------------------------------------------------------------------ + +SplashFontFile *SplashT1FontFile::loadType1Font(SplashT1FontEngine *engineA, + SplashFontFileID *idA, + SplashFontSrc *src, + const char **encA) { + int t1libIDA; + const char **encTmp; + char *encStrTmp; + int encStrSize; + char *encPtr; + int i; + + GooString *fileNameA; + SplashFontSrc *newsrc = NULL; + SplashFontFile *ff; + + if (! src->isFile) { + GooString *tmpFileName; + FILE *tmpFile; + if (!openTempFile(&tmpFileName, &tmpFile, "wb")) + return NULL; + fwrite(src->buf, 1, src->bufLen, tmpFile); + fclose(tmpFile); + newsrc = new SplashFontSrc; + newsrc->setFile(tmpFileName, gTrue); + src = newsrc; + delete tmpFileName; + } + fileNameA = src->fileName; + // load the font file + if ((t1libIDA = T1_AddFont(fileNameA->getCString())) < 0) { + delete newsrc; + return NULL; + } + T1_LoadFont(t1libIDA); + + // reencode it + encStrSize = 0; + for (i = 0; i < 256; ++i) { + if (encA[i]) { + encStrSize += strlen(encA[i]) + 1; + } + } + encTmp = (const char **)gmallocn(257, sizeof(char *)); + encStrTmp = (char *)gmallocn(encStrSize, sizeof(char)); + encPtr = encStrTmp; + for (i = 0; i < 256; ++i) { + if (encA[i]) { + strcpy(encPtr, encA[i]); + encTmp[i] = encPtr; + encPtr += strlen(encPtr) + 1; + } else { + encTmp[i] = ".notdef"; + } + } + encTmp[256] = "custom"; + T1_ReencodeFont(t1libIDA, (char **)encTmp); + + ff = new SplashT1FontFile(engineA, idA, src, + t1libIDA, encTmp, encStrTmp); + if (newsrc) + newsrc->unref(); + return ff; +} + +SplashT1FontFile::SplashT1FontFile(SplashT1FontEngine *engineA, + SplashFontFileID *idA, + SplashFontSrc *srcA, + int t1libIDA, const char **encA, char *encStrA): + SplashFontFile(idA, srcA) +{ + engine = engineA; + t1libID = t1libIDA; + enc = encA; + encStr = encStrA; +} + +SplashT1FontFile::~SplashT1FontFile() { + gfree(encStr); + gfree(enc); + T1_DeleteFont(t1libID); +} + +SplashFont *SplashT1FontFile::makeFont(SplashCoord *mat, + SplashCoord *textMat) { + SplashFont *font; + + font = new SplashT1Font(this, mat, textMat); + font->initCache(); + return font; +} + +#endif // HAVE_T1LIB_H diff --git a/Build/source/libs/poppler/poppler-0.33.0/splash/SplashT1FontFile.h b/Build/source/libs/poppler/poppler-0.33.0/splash/SplashT1FontFile.h new file mode 100644 index 00000000000..c094b6d8b29 --- /dev/null +++ b/Build/source/libs/poppler/poppler-0.33.0/splash/SplashT1FontFile.h @@ -0,0 +1,70 @@ +//======================================================================== +// +// SplashT1FontFile.h +// +//======================================================================== + +//======================================================================== +// +// Modified under the Poppler project - http://poppler.freedesktop.org +// +// All changes made under the Poppler project to this file are licensed +// under GPL version 2 or later +// +// Copyright (C) 2006 Takashi Iwai <tiwai@suse.de> +// +// To see a description of the changes please see the Changelog file that +// came with your tarball or type make ChangeLog if you are building from git +// +//======================================================================== + +#ifndef SPLASHT1FONTFILE_H +#define SPLASHT1FONTFILE_H + +#if HAVE_T1LIB_H + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "SplashFontFile.h" + +class SplashT1FontEngine; + +//------------------------------------------------------------------------ +// SplashT1FontFile +//------------------------------------------------------------------------ + +class SplashT1FontFile: public SplashFontFile { +public: + + static SplashFontFile *loadType1Font(SplashT1FontEngine *engineA, + SplashFontFileID *idA, + SplashFontSrc *src, + const char **encA); + + virtual ~SplashT1FontFile(); + + // Create a new SplashT1Font, i.e., a scaled instance of this font + // file. + virtual SplashFont *makeFont(SplashCoord *mat, + SplashCoord *textMat); + +private: + + SplashT1FontFile(SplashT1FontEngine *engineA, + SplashFontFileID *idA, + SplashFontSrc *src, + int t1libIDA, const char **encA, char *encStrA); + + SplashT1FontEngine *engine; + int t1libID; // t1lib font ID + const char **enc; + char *encStr; + + friend class SplashT1Font; +}; + +#endif // HAVE_T1LIB_H + +#endif diff --git a/Build/source/libs/poppler/poppler-0.33.0/splash/SplashTypes.h b/Build/source/libs/poppler/poppler-0.33.0/splash/SplashTypes.h new file mode 100644 index 00000000000..5ea816007f8 --- /dev/null +++ b/Build/source/libs/poppler/poppler-0.33.0/splash/SplashTypes.h @@ -0,0 +1,199 @@ +//======================================================================== +// +// SplashTypes.h +// +//======================================================================== + +//======================================================================== +// +// Modified under the Poppler project - http://poppler.freedesktop.org +// +// All changes made under the Poppler project to this file are licensed +// under GPL version 2 or later +// +// Copyright (C) 2006, 2010 Albert Astals Cid <aacid@kde.org> +// Copyright (C) 2008 Tomas Are Haavet <tomasare@gmail.com> +// Copyright (C) 2009, 2011-2013 Thomas Freitag <Thomas.Freitag@alfa.de> +// Copyright (C) 2009 Stefan Thomas <thomas@eload24.com> +// Copyright (C) 2010 William Bader <williambader@hotmail.com> +// +// To see a description of the changes please see the Changelog file that +// came with your tarball or type make ChangeLog if you are building from git +// +//======================================================================== + +#ifndef SPLASHTYPES_H +#define SPLASHTYPES_H + +#include "goo/gtypes.h" + +//------------------------------------------------------------------------ +// coordinates +//------------------------------------------------------------------------ + +#if USE_FIXEDPOINT +#include "goo/FixedPoint.h" +typedef FixedPoint SplashCoord; +#elif USE_FLOAT +typedef float SplashCoord; +#else +typedef double SplashCoord; +#endif + +//------------------------------------------------------------------------ +// antialiasing +//------------------------------------------------------------------------ + +#define splashAASize 4 + +#ifndef SPOT_NCOMPS +#define SPOT_NCOMPS 4 +#endif + +//------------------------------------------------------------------------ +// colors +//------------------------------------------------------------------------ + +enum SplashColorMode { + splashModeMono1, // 1 bit per component, 8 pixels per byte, + // MSbit is on the left + splashModeMono8, // 1 byte per component, 1 byte per pixel + splashModeRGB8, // 1 byte per component, 3 bytes per pixel: + // RGBRGB... + splashModeBGR8, // 1 byte per component, 3 bytes per pixel: + // BGRBGR... + splashModeXBGR8 // 1 byte per component, 4 bytes per pixel: + // XBGRXBGR... +#if SPLASH_CMYK + , + splashModeCMYK8, // 1 byte per component, 4 bytes per pixel: + // CMYKCMYK... + splashModeDeviceN8 // 1 byte per component, + // 4 bytes + n bytes spot colors per pixel: + // CMYKSSSSCMYKSSSS... +#endif +}; + +enum SplashThinLineMode { + splashThinLineDefault, // if SA on: draw solid if requested line width, transformed into + // device space, is less than half a pixel and a shaped line else + splashThinLineSolid, // draw line solid at least with 1 pixel + splashThinLineShape // draw line shaped at least with 1 pixel +}; +// number of components in each color mode +// (defined in SplashState.cc) +extern int splashColorModeNComps[]; + +// max number of components in any SplashColor +#if SPLASH_CMYK +#define splashMaxColorComps SPOT_NCOMPS+4 +#else +#define splashMaxColorComps 4 +#endif + +typedef Guchar SplashColor[splashMaxColorComps]; +typedef Guchar *SplashColorPtr; + +// RGB8 +static inline Guchar splashRGB8R(SplashColorPtr rgb8) { return rgb8[0]; } +static inline Guchar splashRGB8G(SplashColorPtr rgb8) { return rgb8[1]; } +static inline Guchar splashRGB8B(SplashColorPtr rgb8) { return rgb8[2]; } + +// BGR8 +static inline Guchar splashBGR8R(SplashColorPtr bgr8) { return bgr8[2]; } +static inline Guchar splashBGR8G(SplashColorPtr bgr8) { return bgr8[1]; } +static inline Guchar splashBGR8B(SplashColorPtr bgr8) { return bgr8[0]; } + +#if SPLASH_CMYK +// CMYK8 +static inline Guchar splashCMYK8C(SplashColorPtr cmyk8) { return cmyk8[0]; } +static inline Guchar splashCMYK8M(SplashColorPtr cmyk8) { return cmyk8[1]; } +static inline Guchar splashCMYK8Y(SplashColorPtr cmyk8) { return cmyk8[2]; } +static inline Guchar splashCMYK8K(SplashColorPtr cmyk8) { return cmyk8[3]; } + +// DEVICEN8 +static inline Guchar splashDeviceN8C(SplashColorPtr deviceN8) { return deviceN8[0]; } +static inline Guchar splashDeviceN8M(SplashColorPtr deviceN8) { return deviceN8[1]; } +static inline Guchar splashDeviceN8Y(SplashColorPtr deviceN8) { return deviceN8[2]; } +static inline Guchar splashDeviceN8K(SplashColorPtr deviceN8) { return deviceN8[3]; } +static inline Guchar splashDeviceN8S(SplashColorPtr deviceN8, int nSpot) { return deviceN8[4 + nSpot]; } +#endif + +static inline void splashClearColor(SplashColorPtr dest) { + dest[0] = 0; + dest[1] = 0; + dest[2] = 0; +#if SPLASH_CMYK + dest[3] = 0; + for (int i = SPOT_NCOMPS; i < SPOT_NCOMPS + 4; i++) + dest[i] = 0; +#endif +} + +static inline void splashColorCopy(SplashColorPtr dest, SplashColorPtr src) { + dest[0] = src[0]; + dest[1] = src[1]; + dest[2] = src[2]; +#if SPLASH_CMYK + dest[3] = src[3]; + for (int i = SPOT_NCOMPS; i < SPOT_NCOMPS + 4; i++) + dest[i] = src[i]; +#endif +} + +static inline void splashColorXor(SplashColorPtr dest, SplashColorPtr src) { + dest[0] ^= src[0]; + dest[1] ^= src[1]; + dest[2] ^= src[2]; +#if SPLASH_CMYK + dest[3] ^= src[3]; + for (int i = SPOT_NCOMPS; i < SPOT_NCOMPS + 4; i++) + dest[i] ^= src[i]; +#endif +} + +//------------------------------------------------------------------------ +// blend functions +//------------------------------------------------------------------------ + +typedef void (*SplashBlendFunc)(SplashColorPtr src, SplashColorPtr dest, + SplashColorPtr blend, SplashColorMode cm); + +//------------------------------------------------------------------------ +// screen parameters +//------------------------------------------------------------------------ + +enum SplashScreenType { + splashScreenDispersed, + splashScreenClustered, + splashScreenStochasticClustered +}; + +struct SplashScreenParams { + SplashScreenType type; + int size; + int dotRadius; + SplashCoord gamma; + SplashCoord blackThreshold; + SplashCoord whiteThreshold; +}; + +//------------------------------------------------------------------------ +// error results +//------------------------------------------------------------------------ + +typedef int SplashError; + + +//------------------------------------------------------------------------ +// image file formats +//------------------------------------------------------------------------ + +enum SplashImageFileFormat { + splashFormatJpeg, + splashFormatPng, + splashFormatTiff, + splashFormatJpegCMYK +}; + +#endif diff --git a/Build/source/libs/poppler/poppler-0.33.0/splash/SplashXPath.cc b/Build/source/libs/poppler/poppler-0.33.0/splash/SplashXPath.cc new file mode 100644 index 00000000000..27106ee3d14 --- /dev/null +++ b/Build/source/libs/poppler/poppler-0.33.0/splash/SplashXPath.cc @@ -0,0 +1,472 @@ +//======================================================================== +// +// SplashXPath.cc +// +//======================================================================== + +//======================================================================== +// +// Modified under the Poppler project - http://poppler.freedesktop.org +// +// All changes made under the Poppler project to this file are licensed +// under GPL version 2 or later +// +// Copyright (C) 2010 PaweÅ‚ Wiejacha <pawel.wiejacha@gmail.com> +// Copyright (C) 2010, 2011 Albert Astals Cid <aacid@kde.org> +// Copyright (C) 2013 Thomas Freitag <Thomas.Freitag@alfa.de> +// +// To see a description of the changes please see the Changelog file that +// came with your tarball or type make ChangeLog if you are building from git +// +//======================================================================== + +#include <config.h> + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include <stdlib.h> +#include <string.h> +#include <algorithm> +#include "goo/gmem.h" +#include "SplashMath.h" +#include "SplashPath.h" +#include "SplashXPath.h" + +//------------------------------------------------------------------------ + +struct SplashXPathPoint { + SplashCoord x, y; +}; + +struct SplashXPathAdjust { + int firstPt, lastPt; // range of points + GBool vert; // vertical or horizontal hint + SplashCoord x0a, x0b, // hint boundaries + xma, xmb, + x1a, x1b; + SplashCoord x0, x1, xm; // adjusted coordinates +}; + +//------------------------------------------------------------------------ + +// Transform a point from user space to device space. +inline void SplashXPath::transform(SplashCoord *matrix, + SplashCoord xi, SplashCoord yi, + SplashCoord *xo, SplashCoord *yo) { + // [ m[0] m[1] 0 ] + // [xo yo 1] = [xi yi 1] * [ m[2] m[3] 0 ] + // [ m[4] m[5] 1 ] + *xo = xi * matrix[0] + yi * matrix[2] + matrix[4]; + *yo = xi * matrix[1] + yi * matrix[3] + matrix[5]; +} + +//------------------------------------------------------------------------ +// SplashXPath +//------------------------------------------------------------------------ + +SplashXPath::SplashXPath(SplashPath *path, SplashCoord *matrix, + SplashCoord flatness, GBool closeSubpaths, + GBool adjustLines, int linePosI) { + SplashPathHint *hint; + SplashXPathPoint *pts; + SplashXPathAdjust *adjusts, *adjust; + SplashCoord x0, y0, x1, y1, x2, y2, x3, y3, xsp, ysp; + SplashCoord adj0, adj1; + int curSubpath, i, j; + + // transform the points + pts = (SplashXPathPoint *)gmallocn(path->length, sizeof(SplashXPathPoint)); + for (i = 0; i < path->length; ++i) { + transform(matrix, path->pts[i].x, path->pts[i].y, &pts[i].x, &pts[i].y); + } + + // set up the stroke adjustment hints + if (path->hints) { + adjusts = (SplashXPathAdjust *)gmallocn(path->hintsLength, + sizeof(SplashXPathAdjust)); + for (i = 0; i < path->hintsLength; ++i) { + hint = &path->hints[i]; + if (hint->ctrl0 + 1 >= path->length || hint->ctrl1 + 1 >= path->length) { + gfree(adjusts); + adjusts = NULL; + break; + } + x0 = pts[hint->ctrl0 ].x; y0 = pts[hint->ctrl0 ].y; + x1 = pts[hint->ctrl0 + 1].x; y1 = pts[hint->ctrl0 + 1].y; + x2 = pts[hint->ctrl1 ].x; y2 = pts[hint->ctrl1 ].y; + x3 = pts[hint->ctrl1 + 1].x; y3 = pts[hint->ctrl1 + 1].y; + if (x0 == x1 && x2 == x3) { + adjusts[i].vert = gTrue; + adj0 = x0; + adj1 = x2; + } else if (y0 == y1 && y2 == y3) { + adjusts[i].vert = gFalse; + adj0 = y0; + adj1 = y2; + } else { + gfree(adjusts); + adjusts = NULL; + break; + } + if (adj0 > adj1) { + x0 = adj0; + adj0 = adj1; + adj1 = x0; + } + adjusts[i].x0a = adj0 - 0.01; + adjusts[i].x0b = adj0 + 0.01; + adjusts[i].xma = (SplashCoord)0.5 * (adj0 + adj1) - 0.01; + adjusts[i].xmb = (SplashCoord)0.5 * (adj0 + adj1) + 0.01; + adjusts[i].x1a = adj1 - 0.01; + adjusts[i].x1b = adj1 + 0.01; + // rounding both edge coordinates can result in lines of + // different widths (e.g., adj=10.1, adj1=11.3 --> x0=10, x1=11; + // adj0=10.4, adj1=11.6 --> x0=10, x1=12), but it has the + // benefit of making adjacent strokes/fills line up without any + // gaps between them + x0 = splashRound(adj0); + x1 = splashRound(adj1); + if (x1 == x0) { + if (adjustLines) { + // the adjustment moves thin lines (clip rectangle with + // empty width or height) out of clip area, here we need + // a special adjustment: + x0 = linePosI; + x1 = x0 + 1; + } else { + x1 = x1 + 1; + } + } + adjusts[i].x0 = (SplashCoord)x0; + adjusts[i].x1 = (SplashCoord)x1 - 0.01; + adjusts[i].xm = (SplashCoord)0.5 * (adjusts[i].x0 + adjusts[i].x1); + adjusts[i].firstPt = hint->firstPt; + adjusts[i].lastPt = hint->lastPt; + } + + } else { + adjusts = NULL; + } + + // perform stroke adjustment + if (adjusts) { + for (i = 0, adjust = adjusts; i < path->hintsLength; ++i, ++adjust) { + for (j = adjust->firstPt; j <= adjust->lastPt; ++j) { + strokeAdjust(adjust, &pts[j].x, &pts[j].y); + } + } + gfree(adjusts); + } + + segs = NULL; + length = size = 0; + + x0 = y0 = xsp = ysp = 0; // make gcc happy + adj0 = adj1 = 0; // make gcc happy + curSubpath = 0; + i = 0; + while (i < path->length) { + + // first point in subpath - skip it + if (path->flags[i] & splashPathFirst) { + x0 = pts[i].x; + y0 = pts[i].y; + xsp = x0; + ysp = y0; + curSubpath = i; + ++i; + + } else { + + // curve segment + if (path->flags[i] & splashPathCurve) { + x1 = pts[i].x; + y1 = pts[i].y; + x2 = pts[i+1].x; + y2 = pts[i+1].y; + x3 = pts[i+2].x; + y3 = pts[i+2].y; + addCurve(x0, y0, x1, y1, x2, y2, x3, y3, + flatness, + (path->flags[i-1] & splashPathFirst), + (path->flags[i+2] & splashPathLast), + !closeSubpaths && + (path->flags[i-1] & splashPathFirst) && + !(path->flags[i-1] & splashPathClosed), + !closeSubpaths && + (path->flags[i+2] & splashPathLast) && + !(path->flags[i+2] & splashPathClosed)); + x0 = x3; + y0 = y3; + i += 3; + + // line segment + } else { + x1 = pts[i].x; + y1 = pts[i].y; + addSegment(x0, y0, x1, y1); + x0 = x1; + y0 = y1; + ++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); + } + } + } + + gfree(pts); +} + +// Apply the stroke adjust hints to point <pt>: (*<xp>, *<yp>). +void SplashXPath::strokeAdjust(SplashXPathAdjust *adjust, + SplashCoord *xp, SplashCoord *yp) { + SplashCoord x, y; + + if (adjust->vert) { + x = *xp; + if (x > adjust->x0a && x < adjust->x0b) { + *xp = adjust->x0; + } else if (x > adjust->xma && x < adjust->xmb) { + *xp = adjust->xm; + } else if (x > adjust->x1a && x < adjust->x1b) { + *xp = adjust->x1; + } + } else { + y = *yp; + if (y > adjust->x0a && y < adjust->x0b) { + *yp = adjust->x0; + } else if (y > adjust->xma && y < adjust->xmb) { + *yp = adjust->xm; + } else if (y > adjust->x1a && y < adjust->x1b) { + *yp = adjust->x1; + } + } +} + +SplashXPath::SplashXPath(SplashXPath *xPath) { + length = xPath->length; + size = xPath->size; + segs = (SplashXPathSeg *)gmallocn(size, sizeof(SplashXPathSeg)); + memcpy(segs, xPath->segs, length * sizeof(SplashXPathSeg)); +} + +SplashXPath::~SplashXPath() { + gfree(segs); +} + +// Add space for <nSegs> more segments +void SplashXPath::grow(int nSegs) { + if (length + nSegs > size) { + if (size == 0) { + size = 32; + } + while (size < length + nSegs) { + size *= 2; + } + segs = (SplashXPathSeg *)greallocn(segs, size, sizeof(SplashXPathSeg)); + } +} + +void SplashXPath::addCurve(SplashCoord x0, SplashCoord y0, + SplashCoord x1, SplashCoord y1, + SplashCoord x2, SplashCoord y2, + SplashCoord x3, SplashCoord y3, + SplashCoord flatness, + GBool first, GBool last, GBool end0, GBool end1) { + SplashCoord *cx = new SplashCoord[(splashMaxCurveSplits + 1) * 3]; + SplashCoord *cy = new SplashCoord[(splashMaxCurveSplits + 1) * 3]; + int *cNext = new int[splashMaxCurveSplits + 1]; + SplashCoord xl0, xl1, xl2, xr0, xr1, xr2, xr3, xx1, xx2, xh; + SplashCoord yl0, yl1, yl2, yr0, yr1, yr2, yr3, yy1, yy2, yh; + SplashCoord dx, dy, mx, my, d1, d2, flatness2; + int p1, p2, p3; + +#if USE_FIXEDPOINT + flatness2 = flatness; +#else + flatness2 = flatness * flatness; +#endif + + // initial segment + p1 = 0; + p2 = splashMaxCurveSplits; + + *(cx + p1 * 3 + 0) = x0; + *(cx + p1 * 3 + 1) = x1; + *(cx + p1 * 3 + 2) = x2; + *(cx + p2 * 3 + 0) = x3; + + *(cy + p1 * 3 + 0) = y0; + *(cy + p1 * 3 + 1) = y1; + *(cy + p1 * 3 + 2) = y2; + *(cy + p2 * 3 + 0) = y3; + + *(cNext + p1) = p2; + + while (p1 < splashMaxCurveSplits) { + + // get the next segment + xl0 = *(cx + p1 * 3 + 0); + xx1 = *(cx + p1 * 3 + 1); + xx2 = *(cx + p1 * 3 + 2); + + yl0 = *(cy + p1 * 3 + 0); + yy1 = *(cy + p1 * 3 + 1); + yy2 = *(cy + p1 * 3 + 2); + + p2 = *(cNext + p1); + + xr3 = *(cx + p2 * 3 + 0); + yr3 = *(cy + p2 * 3 + 0); + + // compute the distances from the control points to the + // midpoint of the straight line (this is a bit of a hack, but + // it's much faster than computing the actual distances to the + // line) + mx = (xl0 + xr3) * 0.5; + my = (yl0 + yr3) * 0.5; +#if USE_FIXEDPOINT + d1 = splashDist(xx1, yy1, mx, my); + d2 = splashDist(xx2, yy2, mx, my); +#else + dx = xx1 - mx; + dy = yy1 - my; + d1 = dx*dx + dy*dy; + dx = xx2 - mx; + dy = yy2 - my; + d2 = dx*dx + dy*dy; +#endif + + // if the curve is flat enough, or no more subdivisions are + // allowed, add the straight line segment + if (p2 - p1 == 1 || (d1 <= flatness2 && d2 <= flatness2)) { + addSegment(xl0, yl0, xr3, yr3); + p1 = p2; + + // otherwise, subdivide the curve + } else { + xl1 = (xl0 + xx1) * 0.5; + yl1 = (yl0 + yy1) * 0.5; + xh = (xx1 + xx2) * 0.5; + yh = (yy1 + yy2) * 0.5; + xl2 = (xl1 + xh) * 0.5; + yl2 = (yl1 + yh) * 0.5; + xr2 = (xx2 + xr3) * 0.5; + yr2 = (yy2 + yr3) * 0.5; + xr1 = (xh + xr2) * 0.5; + yr1 = (yh + yr2) * 0.5; + xr0 = (xl2 + xr1) * 0.5; + yr0 = (yl2 + yr1) * 0.5; + // add the new subdivision points + p3 = (p1 + p2) / 2; + + *(cx + p1 * 3 + 1) = xl1; + *(cx + p1 * 3 + 2) = xl2; + + *(cy + p1 * 3 + 1) = yl1; + *(cy + p1 * 3 + 2) = yl2; + + *(cNext + p1) = p3; + + *(cx + p3 * 3 + 0) = xr0; + *(cx + p3 * 3 + 1) = xr1; + *(cx + p3 * 3 + 2) = xr2; + + *(cy + p3 * 3 + 0) = yr0; + *(cy + p3 * 3 + 1) = yr1; + *(cy + p3 * 3 + 2) = yr2; + + *(cNext + p3) = p2; + } + } + + delete [] cx; + delete [] cy; + delete [] cNext; +} + +void SplashXPath::addSegment(SplashCoord x0, SplashCoord y0, + SplashCoord x1, SplashCoord y1) { + grow(1); + segs[length].x0 = x0; + segs[length].y0 = y0; + segs[length].x1 = x1; + segs[length].y1 = y1; + segs[length].flags = 0; + if (y1 == y0) { + segs[length].dxdy = segs[length].dydx = 0; + segs[length].flags |= splashXPathHoriz; + if (x1 == x0) { + segs[length].flags |= splashXPathVert; + } + } else if (x1 == x0) { + segs[length].dxdy = segs[length].dydx = 0; + segs[length].flags |= splashXPathVert; + } else { +#if USE_FIXEDPOINT + if (FixedPoint::divCheck(x1 - x0, y1 - y0, &segs[length].dxdy)) { + segs[length].dydx = (SplashCoord)1 / segs[length].dxdy; + } else { + segs[length].dxdy = segs[length].dydx = 0; + if (splashAbs(x1 - x0) > splashAbs(y1 - y0)) { + segs[length].flags |= splashXPathHoriz; + } else { + segs[length].flags |= splashXPathVert; + } + } +#else + segs[length].dxdy = (x1 - x0) / (y1 - y0); + segs[length].dydx = (SplashCoord)1 / segs[length].dxdy; +#endif + } + if (y0 > y1) { + segs[length].flags |= splashXPathFlip; + } + ++length; +} + +struct cmpXPathSegsFunctor { + bool operator()(const SplashXPathSeg &seg0, const SplashXPathSeg &seg1) { + SplashCoord x0, y0, x1, y1; + + if (seg0.flags & splashXPathFlip) { + x0 = seg0.x1; + y0 = seg0.y1; + } else { + x0 = seg0.x0; + y0 = seg0.y0; + } + if (seg1.flags & splashXPathFlip) { + x1 = seg1.x1; + y1 = seg1.y1; + } else { + x1 = seg1.x0; + y1 = seg1.y0; + } + return (y0 != y1) ? (y0 < y1) : (x0 < x1); + } +}; + +void SplashXPath::aaScale() { + SplashXPathSeg *seg; + int i; + + for (i = 0, seg = segs; i < length; ++i, ++seg) { + seg->x0 *= splashAASize; + seg->y0 *= splashAASize; + seg->x1 *= splashAASize; + seg->y1 *= splashAASize; + } +} + +void SplashXPath::sort() { + std::sort(segs, segs + length, cmpXPathSegsFunctor()); +} diff --git a/Build/source/libs/poppler/poppler-0.33.0/splash/SplashXPath.h b/Build/source/libs/poppler/poppler-0.33.0/splash/SplashXPath.h new file mode 100644 index 00000000000..1c7040daa23 --- /dev/null +++ b/Build/source/libs/poppler/poppler-0.33.0/splash/SplashXPath.h @@ -0,0 +1,107 @@ +//======================================================================== +// +// SplashXPath.h +// +//======================================================================== + +//======================================================================== +// +// Modified under the Poppler project - http://poppler.freedesktop.org +// +// All changes made under the Poppler project to this file are licensed +// under GPL version 2 or later +// +// Copyright (C) 2013 Thomas Freitag <Thomas.Freitag@alfa.de> +// +// To see a description of the changes please see the Changelog file that +// came with your tarball or type make ChangeLog if you are building from git +// +//======================================================================== + +#ifndef SPLASHXPATH_H +#define SPLASHXPATH_H + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "SplashTypes.h" + +class SplashPath; +struct SplashXPathAdjust; + +//------------------------------------------------------------------------ + +#define splashMaxCurveSplits (1 << 10) + +//------------------------------------------------------------------------ +// SplashXPathSeg +//------------------------------------------------------------------------ + +struct SplashXPathSeg { + SplashCoord x0, y0; // first endpoint + SplashCoord x1, y1; // second endpoint + SplashCoord dxdy; // slope: delta-x / delta-y + SplashCoord dydx; // slope: delta-y / delta-x + Guint flags; +}; + +#define splashXPathHoriz 0x01 // segment is vertical (y0 == y1) + // (dxdy is undef) +#define splashXPathVert 0x02 // segment is horizontal (x0 == x1) + // (dydx is undef) +#define splashXPathFlip 0x04 // y0 > y1 + +//------------------------------------------------------------------------ +// SplashXPath +//------------------------------------------------------------------------ + +class SplashXPath { +public: + + // Expands (converts to segments) and flattens (converts curves to + // lines) <path>. Transforms all points from user space to device + // space, via <matrix>. If <closeSubpaths> is true, closes all open + // subpaths. + SplashXPath(SplashPath *path, SplashCoord *matrix, + SplashCoord flatness, GBool closeSubpaths, + GBool adjustLines = gFalse, int linePosI = 0); + + // Copy an expanded path. + SplashXPath *copy() { return new SplashXPath(this); } + + ~SplashXPath(); + + // Multiply all coordinates by splashAASize, in preparation for + // anti-aliased rendering. + void aaScale(); + + // Sort by upper coordinate (lower y), in y-major order. + void sort(); + +protected: + + SplashXPath(SplashXPath *xPath); + void transform(SplashCoord *matrix, SplashCoord xi, SplashCoord yi, + SplashCoord *xo, SplashCoord *yo); + void strokeAdjust(SplashXPathAdjust *adjust, + SplashCoord *xp, SplashCoord *yp); + void grow(int nSegs); + void addCurve(SplashCoord x0, SplashCoord y0, + SplashCoord x1, SplashCoord y1, + SplashCoord x2, SplashCoord y2, + SplashCoord x3, SplashCoord y3, + SplashCoord flatness, + GBool first, GBool last, GBool end0, GBool end1); + void addSegment(SplashCoord x0, SplashCoord y0, + SplashCoord x1, SplashCoord y1); + + SplashXPathSeg *segs; + int length, size; // length and size of segs array + + friend class SplashXPathScanner; + friend class SplashClip; + friend class Splash; +}; + +#endif diff --git a/Build/source/libs/poppler/poppler-0.33.0/splash/SplashXPathScanner.cc b/Build/source/libs/poppler/poppler-0.33.0/splash/SplashXPathScanner.cc new file mode 100644 index 00000000000..ac47881cb4f --- /dev/null +++ b/Build/source/libs/poppler/poppler-0.33.0/splash/SplashXPathScanner.cc @@ -0,0 +1,544 @@ +//======================================================================== +// +// SplashXPathScanner.cc +// +//======================================================================== + +//======================================================================== +// +// Modified under the Poppler project - http://poppler.freedesktop.org +// +// All changes made under the Poppler project to this file are licensed +// under GPL version 2 or later +// +// Copyright (C) 2008, 2010, 2014 Albert Astals Cid <aacid@kde.org> +// Copyright (C) 2010 PaweÅ‚ Wiejacha <pawel.wiejacha@gmail.com> +// Copyright (C) 2013, 2014 Thomas Freitag <Thomas.Freitag@alfa.de> +// +// To see a description of the changes please see the Changelog file that +// came with your tarball or type make ChangeLog if you are building from git +// +//======================================================================== + +#include <config.h> + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include <stdlib.h> +#include <string.h> +#include <algorithm> +#include "goo/gmem.h" +#include "SplashMath.h" +#include "SplashXPath.h" +#include "SplashBitmap.h" +#include "SplashXPathScanner.h" + +//------------------------------------------------------------------------ + +struct SplashIntersect { + int y; + int x0, x1; // intersection of segment with [y, y+1) + int count; // EO/NZWN counter increment +}; + +struct cmpIntersectFunctor { + bool operator()(const SplashIntersect &i0, const SplashIntersect &i1) { + return (i0.y != i1.y) ? (i0.y < i1.y) : (i0.x0 < i1.x0); + } +}; + +//------------------------------------------------------------------------ +// SplashXPathScanner +//------------------------------------------------------------------------ + +SplashXPathScanner::SplashXPathScanner(SplashXPath *xPathA, GBool eoA, + int clipYMin, int clipYMax) { + SplashXPathSeg *seg; + SplashCoord xMinFP, yMinFP, xMaxFP, yMaxFP; + int i; + + xPath = xPathA; + eo = eoA; + partialClip = gFalse; + + // compute the bbox + if (xPath->length == 0) { + xMin = yMin = 1; + xMax = yMax = 0; + } else { + seg = &xPath->segs[0]; + if (seg->x0 <= seg->x1) { + xMinFP = seg->x0; + xMaxFP = seg->x1; + } else { + xMinFP = seg->x1; + xMaxFP = seg->x0; + } + if (seg->flags & splashXPathFlip) { + yMinFP = seg->y1; + yMaxFP = seg->y0; + } else { + yMinFP = seg->y0; + yMaxFP = seg->y1; + } + for (i = 1; i < xPath->length; ++i) { + seg = &xPath->segs[i]; + 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->flags & splashXPathFlip) { + if (seg->y0 > yMaxFP) { + yMaxFP = seg->y0; + } + } else { + if (seg->y1 > yMaxFP) { + yMaxFP = seg->y1; + } + } + } + xMin = splashFloor(xMinFP); + xMax = splashFloor(xMaxFP); + yMin = splashFloor(yMinFP); + yMax = splashFloor(yMaxFP); + if (clipYMin > yMin) { + yMin = clipYMin; + partialClip = gTrue; + } + if (clipYMax < yMax) { + yMax = clipYMax; + partialClip = gTrue; + } + } + + allInter = NULL; + inter = NULL; + computeIntersections(); + interY = yMin - 1; +} + +SplashXPathScanner::~SplashXPathScanner() { + gfree(inter); + gfree(allInter); +} + +void SplashXPathScanner::getBBoxAA(int *xMinA, int *yMinA, + int *xMaxA, int *yMaxA) { + *xMinA = xMin / splashAASize; + *yMinA = yMin / splashAASize; + *xMaxA = xMax / splashAASize; + *yMaxA = yMax / splashAASize; +} + +void SplashXPathScanner::getSpanBounds(int y, int *spanXMin, int *spanXMax) { + int interBegin, interEnd, xx, i; + + if (y < yMin || y > yMax) { + interBegin = interEnd = 0; + } else { + interBegin = inter[y - yMin]; + interEnd = inter[y - yMin + 1]; + } + if (interBegin < interEnd) { + *spanXMin = allInter[interBegin].x0; + xx = allInter[interBegin].x1; + for (i = interBegin + 1; i < interEnd; ++i) { + if (allInter[i].x1 > xx) { + xx = allInter[i].x1; + } + } + *spanXMax = xx; + } else { + *spanXMin = xMax + 1; + *spanXMax = xMax; + } +} + +GBool SplashXPathScanner::test(int x, int y) { + int interBegin, interEnd, count, i; + + if (y < yMin || y > yMax) { + return gFalse; + } + interBegin = inter[y - yMin]; + interEnd = inter[y - yMin + 1]; + count = 0; + for (i = interBegin; i < interEnd && allInter[i].x0 <= x; ++i) { + if (x <= allInter[i].x1) { + return gTrue; + } + count += allInter[i].count; + } + return eo ? (count & 1) : (count != 0); +} + +GBool SplashXPathScanner::testSpan(int x0, int x1, int y) { + int interBegin, interEnd, count, xx1, i; + + if (y < yMin || y > yMax) { + return gFalse; + } + interBegin = inter[y - yMin]; + interEnd = inter[y - yMin + 1]; + count = 0; + for (i = interBegin; i < interEnd && allInter[i].x1 < x0; ++i) { + count += allInter[i].count; + } + + // invariant: the subspan [x0,xx1] is inside the path + xx1 = x0 - 1; + while (xx1 < x1) { + if (i >= interEnd) { + return gFalse; + } + if (allInter[i].x0 > xx1 + 1 && + !(eo ? (count & 1) : (count != 0))) { + return gFalse; + } + if (allInter[i].x1 > xx1) { + xx1 = allInter[i].x1; + } + count += allInter[i].count; + ++i; + } + + return gTrue; +} + +GBool SplashXPathScanner::getNextSpan(int y, int *x0, int *x1) { + int interEnd, xx0, xx1; + + if (y < yMin || y > yMax) { + return gFalse; + } + if (interY != y) { + interY = y; + interIdx = inter[y - yMin]; + interCount = 0; + } + interEnd = inter[y - yMin + 1]; + if (interIdx >= interEnd) { + return gFalse; + } + xx0 = allInter[interIdx].x0; + xx1 = allInter[interIdx].x1; + interCount += allInter[interIdx].count; + ++interIdx; + while (interIdx < interEnd && + (allInter[interIdx].x0 <= xx1 || + (eo ? (interCount & 1) : (interCount != 0)))) { + if (allInter[interIdx].x1 > xx1) { + xx1 = allInter[interIdx].x1; + } + interCount += allInter[interIdx].count; + ++interIdx; + } + *x0 = xx0; + *x1 = xx1; + return gTrue; +} + +void SplashXPathScanner::computeIntersections() { + SplashXPathSeg *seg; + SplashCoord segXMin, segXMax, segYMin, segYMax, xx0, xx1; + int x, y, y0, y1, i; + + if (yMin > yMax) { + return; + } + + // build the list of all intersections + allInterLen = 0; + allInterSize = 16; + allInter = (SplashIntersect *)gmallocn(allInterSize, + sizeof(SplashIntersect)); + for (i = 0; i < xPath->length; ++i) { + seg = &xPath->segs[i]; + if (seg->flags & splashXPathFlip) { + segYMin = seg->y1; + segYMax = seg->y0; + } else { + segYMin = seg->y0; + segYMax = seg->y1; + } + if (seg->flags & splashXPathHoriz) { + y = splashFloor(seg->y0); + if (y >= yMin && y <= yMax) { + if (!addIntersection(segYMin, segYMax, seg->flags, + y, splashFloor(seg->x0), splashFloor(seg->x1))) + break; + } + } else if (seg->flags & splashXPathVert) { + y0 = splashFloor(segYMin); + if (y0 < yMin) { + y0 = yMin; + } + y1 = splashFloor(segYMax); + if (y1 > yMax) { + y1 = yMax; + } + x = splashFloor(seg->x0); + for (y = y0; y <= y1; ++y) { + if (!addIntersection(segYMin, segYMax, seg->flags, y, x, x)) + break; + } + } else { + if (seg->x0 < seg->x1) { + segXMin = seg->x0; + segXMax = seg->x1; + } else { + segXMin = seg->x1; + segXMax = seg->x0; + } + y0 = splashFloor(segYMin); + if (y0 < yMin) { + y0 = yMin; + } + y1 = splashFloor(segYMax); + if (y1 > yMax) { + y1 = yMax; + } + // this loop could just add seg->dxdy to xx1 on each iteration, + // but that introduces numerical accuracy problems + xx1 = seg->x0 + ((SplashCoord)y0 - seg->y0) * seg->dxdy; + for (y = y0; y <= y1; ++y) { + xx0 = xx1; + xx1 = seg->x0 + ((SplashCoord)(y + 1) - seg->y0) * seg->dxdy; + // the segment may not actually extend to the top and/or bottom edges + if (xx0 < segXMin) { + xx0 = segXMin; + } else if (xx0 > segXMax) { + xx0 = segXMax; + } + if (xx1 < segXMin) { + xx1 = segXMin; + } else if (xx1 > segXMax) { + xx1 = segXMax; + } + if (!addIntersection(segYMin, segYMax, seg->flags, y, + splashFloor(xx0), splashFloor(xx1))) + break; + } + } + } + std::sort(allInter, allInter + allInterLen, cmpIntersectFunctor()); + + // build the list of y pointers + inter = (int *)gmallocn(yMax - yMin + 2, sizeof(int)); + i = 0; + for (y = yMin; y <= yMax; ++y) { + inter[y - yMin] = i; + while (i < allInterLen && allInter[i].y <= y) { + ++i; + } + } + inter[yMax - yMin + 1] = i; +} + +GBool SplashXPathScanner::addIntersection(double segYMin, double segYMax, + Guint segFlags, + int y, int x0, int x1) { + if (allInterLen == allInterSize) { + unsigned int newInterSize = ((unsigned int) allInterSize * 2 > INT_MAX / sizeof(SplashIntersect)) ? allInterSize + 32768 : allInterSize * 2; + if (newInterSize >= INT_MAX / sizeof(SplashIntersect)) { + error(errInternal, -1, "Bogus memory allocation size in SplashXPathScanner::addIntersection {0:d}", newInterSize); + return gFalse; + } + allInterSize = newInterSize; + allInter = (SplashIntersect *)greallocn(allInter, newInterSize, + sizeof(SplashIntersect)); + } + allInter[allInterLen].y = y; + if (x0 < x1) { + allInter[allInterLen].x0 = x0; + allInter[allInterLen].x1 = x1; + } else { + allInter[allInterLen].x0 = x1; + allInter[allInterLen].x1 = x0; + } + if (segYMin <= y && + (SplashCoord)y < segYMax && + !(segFlags & splashXPathHoriz)) { + allInter[allInterLen].count = eo ? 1 + : (segFlags & splashXPathFlip) ? 1 : -1; + } else { + allInter[allInterLen].count = 0; + } + ++allInterLen; + return gTrue; +} + +void SplashXPathScanner::renderAALine(SplashBitmap *aaBuf, + int *x0, int *x1, int y, GBool adjustVertLine) { + int xx0, xx1, xx, xxMin, xxMax, yy, interEnd; + Guchar mask; + SplashColorPtr p; + + memset(aaBuf->getDataPtr(), 0, aaBuf->getRowSize() * aaBuf->getHeight()); + xxMin = aaBuf->getWidth(); + xxMax = -1; + if (yMin <= yMax) { + if (splashAASize * y < yMin) { + interIdx = inter[0]; + } else if (splashAASize * y > yMax) { + interIdx = inter[yMax - yMin + 1]; + } else { + interIdx = inter[splashAASize * y - yMin]; + } + for (yy = 0; yy < splashAASize; ++yy) { + if (splashAASize * y + yy < yMin) { + interEnd = inter[0]; + } else if (splashAASize * y + yy > yMax) { + interEnd = inter[yMax - yMin + 1]; + } else { + interEnd = inter[splashAASize * y + yy - yMin + 1]; + } + interCount = 0; + while (interIdx < interEnd) { + xx0 = allInter[interIdx].x0; + xx1 = allInter[interIdx].x1; + interCount += allInter[interIdx].count; + ++interIdx; + while (interIdx < interEnd && + (allInter[interIdx].x0 <= xx1 || + (eo ? (interCount & 1) : (interCount != 0)))) { + if (allInter[interIdx].x1 > xx1) { + xx1 = allInter[interIdx].x1; + } + interCount += allInter[interIdx].count; + ++interIdx; + } + if (xx0 < 0) { + xx0 = 0; + } + ++xx1; + if (xx1 > aaBuf->getWidth()) { + xx1 = aaBuf->getWidth(); + } + // set [xx0, xx1) to 1 + if (xx0 < xx1) { + xx = xx0; + p = aaBuf->getDataPtr() + yy * aaBuf->getRowSize() + (xx >> 3); + if (xx & 7) { + mask = adjustVertLine ? 0xff : 0xff >> (xx & 7); + if (!adjustVertLine && (xx & ~7) == (xx1 & ~7)) { + mask &= (Guchar)(0xff00 >> (xx1 & 7)); + } + *p++ |= mask; + xx = (xx & ~7) + 8; + } + for (; xx + 7 < xx1; xx += 8) { + *p++ |= 0xff; + } + if (xx < xx1) { + *p |= adjustVertLine ? 0xff : (Guchar)(0xff00 >> (xx1 & 7)); + } + } + if (xx0 < xxMin) { + xxMin = xx0; + } + if (xx1 > xxMax) { + xxMax = xx1; + } + } + } + } + if (xxMin > xxMax) { + xxMin = xxMax; + } + *x0 = xxMin / splashAASize; + *x1 = (xxMax - 1) / splashAASize; +} + +void SplashXPathScanner::clipAALine(SplashBitmap *aaBuf, + int *x0, int *x1, int y) { + int xx0, xx1, xx, yy, interEnd; + Guchar mask; + SplashColorPtr p; + + for (yy = 0; yy < splashAASize; ++yy) { + xx = *x0 * splashAASize; + if (yMin <= yMax) { + if (splashAASize * y + yy < yMin) { + interIdx = interEnd = inter[0]; + } else if (splashAASize * y + yy > yMax) { + interIdx = interEnd = inter[yMax - yMin + 1]; + } else { + interIdx = inter[splashAASize * y + yy - yMin]; + if (splashAASize * y + yy > yMax) { + interEnd = inter[yMax - yMin + 1]; + } else { + interEnd = inter[splashAASize * y + yy - yMin + 1]; + } + } + interCount = 0; + while (interIdx < interEnd && xx < (*x1 + 1) * splashAASize) { + xx0 = allInter[interIdx].x0; + xx1 = allInter[interIdx].x1; + interCount += allInter[interIdx].count; + ++interIdx; + while (interIdx < interEnd && + (allInter[interIdx].x0 <= xx1 || + (eo ? (interCount & 1) : (interCount != 0)))) { + if (allInter[interIdx].x1 > xx1) { + xx1 = allInter[interIdx].x1; + } + interCount += allInter[interIdx].count; + ++interIdx; + } + if (xx0 > aaBuf->getWidth()) { + xx0 = aaBuf->getWidth(); + } + // set [xx, xx0) to 0 + if (xx < xx0) { + p = aaBuf->getDataPtr() + yy * aaBuf->getRowSize() + (xx >> 3); + if (xx & 7) { + mask = (Guchar)(0xff00 >> (xx & 7)); + if ((xx & ~7) == (xx0 & ~7)) { + mask |= 0xff >> (xx0 & 7); + } + *p++ &= mask; + xx = (xx & ~7) + 8; + } + for (; xx + 7 < xx0; xx += 8) { + *p++ = 0x00; + } + if (xx < xx0) { + *p &= 0xff >> (xx0 & 7); + } + } + if (xx1 >= xx) { + xx = xx1 + 1; + } + } + } + xx0 = (*x1 + 1) * splashAASize; + if (xx0 > aaBuf->getWidth()) xx0 = aaBuf->getWidth(); + // set [xx, xx0) to 0 + if (xx < xx0 && xx >= 0) { + p = aaBuf->getDataPtr() + yy * aaBuf->getRowSize() + (xx >> 3); + if (xx & 7) { + mask = (Guchar)(0xff00 >> (xx & 7)); + if ((xx & ~7) == (xx0 & ~7)) { + mask &= 0xff >> (xx0 & 7); + } + *p++ &= mask; + xx = (xx & ~7) + 8; + } + for (; xx + 7 < xx0; xx += 8) { + *p++ = 0x00; + } + if (xx < xx0) { + *p &= 0xff >> (xx0 & 7); + } + } + } +} diff --git a/Build/source/libs/poppler/poppler-0.33.0/splash/SplashXPathScanner.h b/Build/source/libs/poppler/poppler-0.33.0/splash/SplashXPathScanner.h new file mode 100644 index 00000000000..cc295cb68fe --- /dev/null +++ b/Build/source/libs/poppler/poppler-0.33.0/splash/SplashXPathScanner.h @@ -0,0 +1,108 @@ +//======================================================================== +// +// SplashXPathScanner.h +// +//======================================================================== + +//======================================================================== +// +// Modified under the Poppler project - http://poppler.freedesktop.org +// +// All changes made under the Poppler project to this file are licensed +// under GPL version 2 or later +// +// Copyright (C) 2013, 2014 Thomas Freitag <Thomas.Freitag@alfa.de> +// +// To see a description of the changes please see the Changelog file that +// came with your tarball or type make ChangeLog if you are building from git +// +//======================================================================== + +#ifndef SPLASHXPATHSCANNER_H +#define SPLASHXPATHSCANNER_H + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "SplashTypes.h" + +class SplashXPath; +class SplashBitmap; +struct SplashIntersect; + +//------------------------------------------------------------------------ +// SplashXPathScanner +//------------------------------------------------------------------------ + +class SplashXPathScanner { +public: + + // Create a new SplashXPathScanner object. <xPathA> must be sorted. + SplashXPathScanner(SplashXPath *xPathA, GBool eoA, + int clipYMin, int clipYMax); + + ~SplashXPathScanner(); + + // Return the path's bounding box. + void getBBox(int *xMinA, int *yMinA, int *xMaxA, int *yMaxA) + { *xMinA = xMin; *yMinA = yMin; *xMaxA = xMax; *yMaxA = yMax; } + + // Return the path's bounding box. + void getBBoxAA(int *xMinA, int *yMinA, int *xMaxA, int *yMaxA); + + // Returns true if at least part of the path was outside the + // clipYMin/clipYMax bounds passed to the constructor. + GBool hasPartialClip() { return partialClip; } + + // Return the min/max x values for the span at <y>. + void getSpanBounds(int y, int *spanXMin, int *spanXMax); + + // Returns true if (<x>,<y>) is inside the path. + GBool test(int x, int y); + + // Returns true if the entire span ([<x0>,<x1>], <y>) is inside the + // path. + GBool testSpan(int x0, int x1, int y); + + // Returns the next span inside the path at <y>. If <y> is + // different than the previous call to getNextSpan, this returns the + // first span at <y>; otherwise it returns the next span (relative + // to the previous call to getNextSpan). Returns false if there are + // no more spans at <y>. + GBool getNextSpan(int y, int *x0, int *x1); + + // Renders one anti-aliased line into <aaBuf>. Returns the min and + // max x coordinates with non-zero pixels in <x0> and <x1>. + void renderAALine(SplashBitmap *aaBuf, int *x0, int *x1, int y, + GBool adjustVertLine = gFalse); + + // Clips an anti-aliased line by setting pixels to zero. On entry, + // all non-zero pixels are between <x0> and <x1>. This function + // will update <x0> and <x1>. + void clipAALine(SplashBitmap *aaBuf, int *x0, int *x1, int y); + +private: + + void computeIntersections(); + GBool addIntersection(double segYMin, double segYMax, + Guint segFlags, + int y, int x0, int x1); + + SplashXPath *xPath; + GBool eo; + int xMin, yMin, xMax, yMax; + GBool partialClip; + + SplashIntersect *allInter; // array of intersections + int allInterLen; // number of intersections in <allInter> + int allInterSize; // size of the <allInter> array + int *inter; // indexes into <allInter> for each y value + int interY; // current y value - used by getNextSpan + int interIdx; // current index into <inter> - used by + // getNextSpan + int interCount; // current EO/NZWN counter - used by + // getNextSpan +}; + +#endif |