diff options
Diffstat (limited to 'pdf/splash')
45 files changed, 6361 insertions, 0 deletions
diff --git a/pdf/splash/Makefile.dep b/pdf/splash/Makefile.dep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/pdf/splash/Makefile.dep diff --git a/pdf/splash/Makefile.in b/pdf/splash/Makefile.in new file mode 100644 index 0000000..66c449b --- /dev/null +++ b/pdf/splash/Makefile.in @@ -0,0 +1,99 @@ +#======================================================================== +# +# Splash library Makefile +# +# Copyright 2003 Glyph & Cog, LLC +# +#======================================================================== + +SHELL = /bin/sh + +srcdir = @srcdir@ +VPATH = @srcdir@ + +GOOSRCDIR = $(srcdir)/../goo +GOOLIBDIR = ../goo +FOFISRCDIR = $(srcdir)/../fofi +FOFILIBDIR = ../fofi + +CXXFLAGS = @CXXFLAGS@ @DEFS@ -I.. -I$(GOOSRCDIR) -I$(FOFISRCDIR) -I$(srcdir) @t1_CFLAGS@ @freetype2_CFLAGS@ + +CXX = @CXX@ +AR = @AR@ +RANLIB = @RANLIB@ + +LIBPREFIX = @LIBPREFIX@ + +#------------------------------------------------------------------------ + +.SUFFIXES: .cc + +.cc.o: + $(CXX) $(CXXFLAGS) -c $< + +#------------------------------------------------------------------------ + +CXX_SRC = \ + $(srcdir)/Splash.cc \ + $(srcdir)/SplashBitmap.cc \ + $(srcdir)/SplashClip.cc \ + $(srcdir)/SplashFTFont.cc \ + $(srcdir)/SplashFTFontEngine.cc \ + $(srcdir)/SplashFTFontFile.cc \ + $(srcdir)/SplashFont.cc \ + $(srcdir)/SplashFontEngine.cc \ + $(srcdir)/SplashFontFile.cc \ + $(srcdir)/SplashFontFileID.cc \ + $(srcdir)/SplashPath.cc \ + $(srcdir)/SplashPattern.cc \ + $(srcdir)/SplashScreen.cc \ + $(srcdir)/SplashState.cc \ + $(srcdir)/SplashT1Font.cc \ + $(srcdir)/SplashT1FontEngine.cc \ + $(srcdir)/SplashT1FontFile.cc \ + $(srcdir)/SplashXPath.cc \ + $(srcdir)/SplashXPathScanner.cc + +#------------------------------------------------------------------------ + +all: $(LIBPREFIX)splash.a + +#------------------------------------------------------------------------ + +SPLASH_OBJS = \ + Splash.o \ + SplashBitmap.o \ + SplashClip.o \ + SplashFTFont.o \ + SplashFTFontEngine.o \ + SplashFTFontFile.o \ + SplashFont.o \ + SplashFontEngine.o \ + SplashFontFile.o \ + SplashFontFileID.o \ + SplashPath.o \ + SplashPattern.o \ + SplashScreen.o \ + SplashState.o \ + SplashT1Font.o \ + SplashT1FontEngine.o \ + SplashT1FontFile.o \ + SplashXPath.o \ + SplashXPathScanner.o + +$(LIBPREFIX)splash.a: $(SPLASH_OBJS) + rm -f $(LIBPREFIX)splash.a + $(AR) $(LIBPREFIX)splash.a $(SPLASH_OBJS) + $(RANLIB) $(LIBPREFIX)splash.a + +#------------------------------------------------------------------------ + +clean: + rm -f $(SPLASH_OBJS) $(LIBPREFIX)splash.a + +#------------------------------------------------------------------------ + +depend: + $(CXX) $(CXXFLAGS) -MM $(CXX_SRC) >Makefile.dep + +include Makefile.dep diff --git a/pdf/splash/Splash.cc b/pdf/splash/Splash.cc new file mode 100644 index 0000000..f86156d --- /dev/null +++ b/pdf/splash/Splash.cc @@ -0,0 +1,1648 @@ +//======================================================================== +// +// Splash.cc +// +//======================================================================== + +#include <aconf.h> + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include <stdlib.h> +#include <string.h> +#include "gmem.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 "SplashClip.h" +#include "SplashFont.h" +#include "SplashGlyphBitmap.h" +#include "Splash.h" + +//------------------------------------------------------------------------ +// Splash +//------------------------------------------------------------------------ + +Splash::Splash(SplashBitmap *bitmapA) { + bitmap = bitmapA; + state = new SplashState(bitmap->width, bitmap->height); + debugMode = gFalse; +} + +Splash::~Splash() { + while (state->next) { + restoreState(); + } + delete state; +} + +//------------------------------------------------------------------------ +// state read +//------------------------------------------------------------------------ + + +SplashPattern *Splash::getStrokePattern() { + return state->strokePattern; +} + +SplashPattern *Splash::getFillPattern() { + return state->fillPattern; +} + +SplashScreen *Splash::getScreen() { + return state->screen; +} + +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; +} + +SplashClip *Splash::getClip() { + return state->clip; +} + +//------------------------------------------------------------------------ +// state write +//------------------------------------------------------------------------ + +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::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::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->flatness, eo); +} + +//------------------------------------------------------------------------ +// 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(SplashColor color) { + SplashMono1P *mono1; + SplashMono8 *mono8; + SplashRGB8 *rgb8; + SplashBGR8P *bgr8line, *bgr8; + SplashMono1 data; + int n, i, x, y; + + switch (bitmap->mode) { + case splashModeMono1: + n = ((bitmap->width + 7) >> 3) * bitmap->height; + data = color.mono1 ? 0xff : 0x00; + for (i = 0, mono1 = bitmap->data.mono1; i < n; ++i, ++mono1) { + *mono1 = data; + } + break; + case splashModeMono8: + n = bitmap->width * bitmap->height; + for (i = 0, mono8 = bitmap->data.mono8; i < n; ++i, ++mono8) { + *mono8 = color.mono8; + } + break; + case splashModeRGB8: + n = bitmap->width * bitmap->height; + for (i = 0, rgb8 = bitmap->data.rgb8; i < n; ++i, ++rgb8) { + *rgb8 = color.rgb8; + } + break; + case splashModeBGR8Packed: + bgr8line = bitmap->data.bgr8; + for (y = 0; y < bitmap->height; ++y) { + bgr8 = bgr8line; + for (x = 0; x < bitmap->width; ++x) { + bgr8[2] = splashBGR8R(color.bgr8); + bgr8[1] = splashBGR8G(color.bgr8); + bgr8[0] = splashBGR8B(color.bgr8); + bgr8 += 3; + } + bgr8line += bitmap->rowSize; + } + break; + } +} + +SplashError Splash::stroke(SplashPath *path) { + SplashXPath *xPath, *xPath2; + + if (debugMode) { + printf("stroke [dash:%d] [width:%.2f]:\n", + state->lineDashLength, state->lineWidth); + dumpPath(path); + } + if (path->length == 0) { + return splashErrEmptyPath; + } + xPath = new SplashXPath(path, state->flatness, gFalse); + if (state->lineDashLength > 0) { + xPath2 = makeDashedPath(xPath); + delete xPath; + xPath = xPath2; + } + if (state->lineWidth <= 1) { + strokeNarrow(xPath); + } else { + strokeWide(xPath); + } + delete xPath; + return splashOk; +} + +void Splash::strokeNarrow(SplashXPath *xPath) { + SplashXPathSeg *seg; + int x0, x1, x2, x3, y0, y1, x, y, t; + SplashCoord dx, dy, dxdy; + SplashClipResult clipRes; + int i; + + for (i = 0, seg = xPath->segs; i < xPath->length; ++i, ++seg) { + + x0 = splashFloor(seg->x0); + x1 = splashFloor(seg->x1); + y0 = splashFloor(seg->y0); + y1 = splashFloor(seg->y1); + + // horizontal segment + if (y0 == y1) { + if (x0 > x1) { + t = x0; x0 = x1; x1 = t; + } + if ((clipRes = state->clip->testSpan(x0, x1, y0)) + != splashClipAllOutside) { + drawSpan(x0, x1, y0, state->strokePattern, + clipRes == splashClipAllInside); + } + + // segment with |dx| > |dy| + } else if (splashAbs(seg->dxdy) > 1) { + dx = seg->x1 - seg->x0; + dy = seg->y1 - seg->y0; + dxdy = seg->dxdy; + if (y0 > y1) { + t = y0; y0 = y1; y1 = t; + t = x0; x0 = x1; x1 = t; + dx = -dx; + dy = -dy; + } + if ((clipRes = state->clip->testRect(x0 <= x1 ? x0 : x1, y0, + x0 <= x1 ? x1 : x0, y1)) + != splashClipAllOutside) { + if (dx > 0) { + x2 = x0; + for (y = y0; y < y1; ++y) { + x3 = splashFloor(seg->x0 + (y + 1 - seg->y0) * dxdy); + drawSpan(x2, x3 - 1, y, state->strokePattern, + clipRes == splashClipAllInside); + x2 = x3; + } + drawSpan(x2, x1, y, state->strokePattern, + clipRes == splashClipAllInside); + } else { + x2 = x0; + for (y = y0; y < y1; ++y) { + x3 = splashFloor(seg->x0 + (y + 1 - seg->y0) * dxdy); + drawSpan(x3 + 1, x2, y, state->strokePattern, + clipRes == splashClipAllInside); + x2 = x3; + } + drawSpan(x1, x2, y, state->strokePattern, + clipRes == splashClipAllInside); + } + } + + // segment with |dy| > |dx| + } else { + dxdy = seg->dxdy; + if (y0 > y1) { + t = y0; y0 = y1; y1 = t; + } + if ((clipRes = state->clip->testRect(x0 <= x1 ? x0 : x1, y0, + x0 <= x1 ? x1 : x0, y1)) + != splashClipAllOutside) { + for (y = y0; y <= y1; ++y) { + x = splashFloor(seg->x0 + (y - seg->y0) * dxdy); + drawPixel(x, y, state->strokePattern, + clipRes == splashClipAllInside); + } + } + } + } +} + +void Splash::strokeWide(SplashXPath *xPath) { + SplashXPathSeg *seg, *seg2; + SplashPath *widePath; + SplashCoord d, dx, dy, wdx, wdy, dxPrev, dyPrev, wdxPrev, wdyPrev; + SplashCoord dotprod, miter; + int i, j; + + dx = dy = wdx = wdy = 0; // make gcc happy + dxPrev = dyPrev = wdxPrev = wdyPrev = 0; // make gcc happy + + for (i = 0, seg = xPath->segs; i < xPath->length; ++i, ++seg) { + + // save the deltas for the previous segment; if this is the first + // segment on a subpath, compute the deltas for the last segment + // on the subpath (which may be used to draw a line join) + if (seg->flags & splashXPathFirst) { + for (j = i + 1, seg2 = &xPath->segs[j]; j < xPath->length; ++j, ++seg2) { + if (seg2->flags & splashXPathLast) { + d = splashDist(seg2->x0, seg2->y0, seg2->x1, seg2->y1); + if (d == 0) { + //~ not clear what the behavior should be for joins with d==0 + dxPrev = 0; + dyPrev = 1; + } else { + d = 1 / d; + dxPrev = d * (seg2->x1 - seg2->x0); + dyPrev = d * (seg2->y1 - seg2->y0); + } + wdxPrev = 0.5 * state->lineWidth * dxPrev; + wdyPrev = 0.5 * state->lineWidth * dyPrev; + break; + } + } + } else { + dxPrev = dx; + dyPrev = dy; + wdxPrev = wdx; + wdyPrev = wdy; + } + + // compute deltas for this line segment + d = splashDist(seg->x0, seg->y0, seg->x1, seg->y1); + if (d == 0) { + // we need to draw end caps on zero-length lines + //~ not clear what the behavior should be for splashLineCapButt with d==0 + dx = 0; + dy = 1; + } else { + d = 1 / d; + dx = d * (seg->x1 - seg->x0); + dy = d * (seg->y1 - seg->y0); + } + wdx = 0.5 * state->lineWidth * dx; + wdy = 0.5 * state->lineWidth * dy; + + // initialize the path (which will be filled) + widePath = new SplashPath(); + widePath->moveTo(seg->x0 - wdy, seg->y0 + wdx); + + // draw the start cap + if (seg->flags & splashXPathEnd0) { + switch (state->lineCap) { + case splashLineCapButt: + widePath->lineTo(seg->x0 + wdy, seg->y0 - wdx); + break; + case splashLineCapRound: + widePath->arcCWTo(seg->x0 + wdy, seg->y0 - wdx, seg->x0, seg->y0); + break; + case splashLineCapProjecting: + widePath->lineTo(seg->x0 - wdx - wdy, seg->y0 + wdx - wdy); + widePath->lineTo(seg->x0 - wdx + wdy, seg->y0 - wdx - wdy); + widePath->lineTo(seg->x0 + wdy, seg->y0 - wdx); + break; + } + } else { + widePath->lineTo(seg->x0 + wdy, seg->y0 - wdx); + } + + // draw the left side of the segment + widePath->lineTo(seg->x1 + wdy, seg->y1 - wdx); + + // draw the end cap + if (seg->flags & splashXPathEnd1) { + switch (state->lineCap) { + case splashLineCapButt: + widePath->lineTo(seg->x1 - wdy, seg->y1 + wdx); + break; + case splashLineCapRound: + widePath->arcCWTo(seg->x1 - wdy, seg->y1 + wdx, seg->x1, seg->y1); + break; + case splashLineCapProjecting: + widePath->lineTo(seg->x1 + wdx + wdy, seg->y1 - wdx + wdy); + widePath->lineTo(seg->x1 + wdx - wdy, seg->y1 + wdx + wdy); + widePath->lineTo(seg->x1 - wdy, seg->y1 + wdx); + break; + } + } else { + widePath->lineTo(seg->x1 - wdy, seg->y1 + wdx); + } + + // draw the right side of the segment + widePath->lineTo(seg->x0 - wdy, seg->y0 + wdx); + + // fill the segment + fillWithPattern(widePath, gTrue, state->strokePattern); + delete widePath; + + // draw the line join + if (!(seg->flags & splashXPathEnd0)) { + widePath = NULL; + switch (state->lineJoin) { + case splashLineJoinMiter: + dotprod = -(dx * dxPrev + dy * dyPrev); + if (dotprod != 1) { + widePath = new SplashPath(); + widePath->moveTo(seg->x0, seg->y0); + miter = 2 / (1 - dotprod); + if (splashSqrt(miter) <= state->miterLimit) { + miter = splashSqrt(miter - 1); + if (dy * dxPrev > dx * dyPrev) { + widePath->lineTo(seg->x0 + wdyPrev, seg->y0 - wdxPrev); + widePath->lineTo(seg->x0 + wdy - miter * wdx, + seg->y0 - wdx - miter * wdy); + widePath->lineTo(seg->x0 + wdy, seg->y0 - wdx); + } else { + widePath->lineTo(seg->x0 - wdyPrev, seg->y0 + wdxPrev); + widePath->lineTo(seg->x0 - wdy - miter * wdx, + seg->y0 + wdx - miter * wdy); + widePath->lineTo(seg->x0 - wdy, seg->y0 + wdx); + } + } else { + if (dy * dxPrev > dx * dyPrev) { + widePath->lineTo(seg->x0 + wdyPrev, seg->y0 - wdxPrev); + widePath->lineTo(seg->x0 + wdy, seg->y0 - wdx); + } else { + widePath->lineTo(seg->x0 - wdyPrev, seg->y0 + wdxPrev); + widePath->lineTo(seg->x0 - wdy, seg->y0 + wdx); + } + } + } + break; + case splashLineJoinRound: + widePath = new SplashPath(); + widePath->moveTo(seg->x0 + wdy, seg->y0 - wdx); + widePath->arcCWTo(seg->x0 + wdy, seg->y0 - wdx, seg->x0, seg->y0); + break; + case splashLineJoinBevel: + widePath = new SplashPath(); + widePath->moveTo(seg->x0, seg->y0); + if (dy * dxPrev > dx * dyPrev) { + widePath->lineTo(seg->x0 + wdyPrev, seg->y0 - wdxPrev); + widePath->lineTo(seg->x0 + wdy, seg->y0 - wdx); + } else { + widePath->lineTo(seg->x0 - wdyPrev, seg->y0 + wdxPrev); + widePath->lineTo(seg->x0 - wdy, seg->y0 + wdx); + } + break; + } + if (widePath) { + fillWithPattern(widePath, gTrue, state->strokePattern); + delete widePath; + } + } + } +} + +SplashXPath *Splash::makeDashedPath(SplashXPath *xPath) { + SplashXPath *dPath; + GBool lineDashStartOn, lineDashOn; + GBool atSegStart, atSegEnd, atDashStart, atDashEnd; + int lineDashStartIdx, lineDashIdx, subpathStart; + SplashCoord lineDashTotal, lineDashStartPhase, lineDashDist; + int segIdx; + SplashXPathSeg *seg; + SplashCoord sx0, sy0, sx1, sy1, ax0, ay0, ax1, ay1, dist; + int i; + + dPath = new SplashXPath(); + + lineDashTotal = 0; + for (i = 0; i < state->lineDashLength; ++i) { + lineDashTotal += state->lineDash[i]; + } + lineDashStartPhase = state->lineDashPhase; + i = splashFloor(lineDashStartPhase / lineDashTotal); + lineDashStartPhase -= i * lineDashTotal; + lineDashStartOn = gTrue; + lineDashStartIdx = 0; + while (lineDashStartPhase >= state->lineDash[lineDashStartIdx]) { + lineDashStartOn = !lineDashStartOn; + lineDashStartPhase -= state->lineDash[lineDashStartIdx]; + ++lineDashStartIdx; + } + + segIdx = 0; + seg = xPath->segs; + sx0 = seg->x0; + sy0 = seg->y0; + sx1 = seg->x1; + sy1 = seg->y1; + dist = splashDist(sx0, sy0, sx1, sy1); + lineDashOn = lineDashStartOn; + lineDashIdx = lineDashStartIdx; + lineDashDist = state->lineDash[lineDashIdx] - lineDashStartPhase; + atSegStart = gTrue; + atDashStart = gTrue; + subpathStart = dPath->length; + + while (segIdx < xPath->length) { + + ax0 = sx0; + ay0 = sy0; + if (dist <= lineDashDist) { + ax1 = sx1; + ay1 = sy1; + lineDashDist -= dist; + dist = 0; + atSegEnd = gTrue; + atDashEnd = lineDashDist == 0 || (seg->flags & splashXPathLast); + } else { + ax1 = sx0 + (lineDashDist / dist) * (sx1 - sx0); + ay1 = sy0 + (lineDashDist / dist) * (sy1 - sy0); + sx0 = ax1; + sy0 = ay1; + dist -= lineDashDist; + lineDashDist = 0; + atSegEnd = gFalse; + atDashEnd = gTrue; + } + + if (lineDashOn) { + dPath->addSegment(ax0, ay0, ax1, ay1, + atDashStart, atDashEnd, + atDashStart, atDashEnd); + // end of closed subpath + if (atSegEnd && + (seg->flags & splashXPathLast) && + !(seg->flags & splashXPathEnd1)) { + dPath->segs[subpathStart].flags &= ~splashXPathEnd0; + dPath->segs[dPath->length - 1].flags &= ~splashXPathEnd1; + } + } + + if (atDashEnd) { + lineDashOn = !lineDashOn; + if (++lineDashIdx == state->lineDashLength) { + lineDashIdx = 0; + } + lineDashDist = state->lineDash[lineDashIdx]; + atDashStart = gTrue; + } else { + atDashStart = gFalse; + } + if (atSegEnd) { + if (++segIdx < xPath->length) { + ++seg; + sx0 = seg->x0; + sy0 = seg->y0; + sx1 = seg->x1; + sy1 = seg->y1; + dist = splashDist(sx0, sy0, sx1, sy1); + if (seg->flags & splashXPathFirst) { + lineDashOn = lineDashStartOn; + lineDashIdx = lineDashStartIdx; + lineDashDist = state->lineDash[lineDashIdx] - lineDashStartPhase; + atDashStart = gTrue; + subpathStart = dPath->length; + } + } + atSegStart = gTrue; + } else { + atSegStart = gFalse; + } + } + + 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); +} + +SplashError Splash::fillWithPattern(SplashPath *path, GBool eo, + SplashPattern *pattern) { + SplashXPath *xPath; + SplashXPathScanner *scanner; + int xMinI, yMinI, xMaxI, yMaxI, x0, x1, y; + SplashClipResult clipRes, clipRes2; + + if (path->length == 0) { + return splashErrEmptyPath; + } + xPath = new SplashXPath(path, state->flatness, gTrue); + xPath->sort(); + scanner = new SplashXPathScanner(xPath, eo); + + // 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) { + + // draw the spans + for (y = yMinI; y <= yMaxI; ++y) { + while (scanner->getNextSpan(y, &x0, &x1)) { + if (clipRes == splashClipAllInside) { + drawSpan(x0, x1, y, pattern, gTrue); + } else { + clipRes2 = state->clip->testSpan(x0, x1, y); + drawSpan(x0, x1, y, pattern, clipRes2 == splashClipAllInside); + } + } + } + } + + delete scanner; + delete xPath; + return splashOk; +} + +SplashError Splash::xorFill(SplashPath *path, GBool eo) { + SplashXPath *xPath; + SplashXPathScanner *scanner; + int xMinI, yMinI, xMaxI, yMaxI, x0, x1, y; + SplashClipResult clipRes, clipRes2; + + if (path->length == 0) { + return splashErrEmptyPath; + } + xPath = new SplashXPath(path, state->flatness, gTrue); + xPath->sort(); + scanner = new SplashXPathScanner(xPath, eo); + + // 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) { + + // draw the spans + for (y = yMinI; y <= yMaxI; ++y) { + while (scanner->getNextSpan(y, &x0, &x1)) { + if (clipRes == splashClipAllInside) { + xorSpan(x0, x1, y, state->fillPattern, gTrue); + } else { + clipRes2 = state->clip->testSpan(x0, x1, y); + xorSpan(x0, x1, y, state->fillPattern, + clipRes2 == splashClipAllInside); + } + } + } + } + + delete scanner; + delete xPath; + return splashOk; +} + +void Splash::drawPixel(int x, int y, SplashColor *color, GBool noClip) { + SplashMono1P *mono1; + SplashBGR8P *bgr8; + + if (noClip || state->clip->test(x, y)) { + switch (bitmap->mode) { + case splashModeMono1: + mono1 = &bitmap->data.mono8[y * bitmap->rowSize + (x >> 3)]; + if (color->mono1) { + *mono1 |= 0x80 >> (x & 7); + } else { + *mono1 &= ~(0x80 >> (x & 7)); + } + break; + case splashModeMono8: + bitmap->data.mono8[y * bitmap->width + x] = color->mono8; + break; + case splashModeRGB8: + bitmap->data.rgb8[y * bitmap->width + x] = color->rgb8; + break; + case splashModeBGR8Packed: + bgr8 = &bitmap->data.bgr8[y * bitmap->rowSize + 3 * x]; + bgr8[2] = splashBGR8R(color->bgr8); + bgr8[1] = splashBGR8G(color->bgr8); + bgr8[0] = splashBGR8B(color->bgr8); + break; + } + } +} + +void Splash::drawPixel(int x, int y, SplashPattern *pattern, GBool noClip) { + SplashColor color; + SplashMono1P *mono1; + SplashBGR8P *bgr8; + + if (noClip || state->clip->test(x, y)) { + color = pattern->getColor(x, y); + switch (bitmap->mode) { + case splashModeMono1: + mono1 = &bitmap->data.mono8[y * bitmap->rowSize + (x >> 3)]; + if (color.mono1) { + *mono1 |= 0x80 >> (x & 7); + } else { + *mono1 &= ~(0x80 >> (x & 7)); + } + break; + case splashModeMono8: + bitmap->data.mono8[y * bitmap->width + x] = color.mono8; + break; + case splashModeRGB8: + bitmap->data.rgb8[y * bitmap->width + x] = color.rgb8; + break; + case splashModeBGR8Packed: + bgr8 = &bitmap->data.bgr8[y * bitmap->rowSize + 3 * x]; + bgr8[2] = splashBGR8R(color.bgr8); + bgr8[1] = splashBGR8G(color.bgr8); + bgr8[0] = splashBGR8B(color.bgr8); + break; + } + } +} + +void Splash::drawSpan(int x0, int x1, int y, SplashPattern *pattern, + GBool noClip) { + SplashColor color; + SplashMono1P *mono1; + SplashMono8 *mono8; + SplashRGB8 *rgb8; + SplashBGR8P *bgr8; + SplashMono1 mask1; + int i, j, n; + + n = x1 - x0 + 1; + + switch (bitmap->mode) { + case splashModeMono1: + mono1 = &bitmap->data.mono8[y * bitmap->rowSize + (x0 >> 3)]; + i = 0; + if ((j = x0 & 7)) { + mask1 = 0x80 >> j; + for (j = x0 & 7; j < 8 && i < n; ++i, ++j) { + if (noClip || state->clip->test(x0 + i, y)) { + color = pattern->getColor(x0 + i, y); + if (color.mono1) { + *mono1 |= mask1; + } else { + *mono1 &= ~mask1; + } + } + mask1 >>= 1; + } + ++mono1; + } + while (i < n) { + mask1 = 0x80; + for (j = 0; j < 8 && i < n; ++i, ++j) { + if (noClip || state->clip->test(x0 + i, y)) { + color = pattern->getColor(x0 + i, y); + if (color.mono1) { + *mono1 |= mask1; + } else { + *mono1 &= ~mask1; + } + } + mask1 >>= 1; + } + ++mono1; + } + break; + + case splashModeMono8: + mono8 = &bitmap->data.mono8[y * bitmap->width + x0]; + for (i = 0; i < n; ++i) { + if (noClip || state->clip->test(x0 + i, y)) { + color = pattern->getColor(x0 + i, y); + *mono8 = color.mono8; + } + ++mono8; + } + break; + + case splashModeRGB8: + rgb8 = &bitmap->data.rgb8[y * bitmap->width + x0]; + for (i = 0; i < n; ++i) { + if (noClip || state->clip->test(x0 + i, y)) { + color = pattern->getColor(x0 + i, y); + *rgb8 = color.rgb8; + } + ++rgb8; + } + break; + + case splashModeBGR8Packed: + bgr8 = &bitmap->data.bgr8[y * bitmap->rowSize + 3 * x0]; + for (i = 0; i < n; ++i) { + if (noClip || state->clip->test(x0 + i, y)) { + color = pattern->getColor(x0 + i, y); + bgr8[2] = splashBGR8R(color.bgr8); + bgr8[1] = splashBGR8G(color.bgr8); + bgr8[0] = splashBGR8B(color.bgr8); + } + bgr8 += 3; + } + break; + } +} + +void Splash::xorSpan(int x0, int x1, int y, SplashPattern *pattern, + GBool noClip) { + SplashColor color; + SplashMono1P *mono1; + SplashMono8 *mono8; + SplashRGB8 *rgb8; + SplashBGR8P *bgr8; + SplashMono1 mask1; + int i, j, n; + + n = x1 - x0 + 1; + + switch (bitmap->mode) { + case splashModeMono1: + mono1 = &bitmap->data.mono8[y * bitmap->rowSize + (x0 >> 3)]; + i = 0; + if ((j = x0 & 7)) { + mask1 = 0x80 >> j; + for (j = x0 & 7; j < 8 && i < n; ++i, ++j) { + if (noClip || state->clip->test(x0 + i, y)) { + color = pattern->getColor(x0 + i, y); + if (color.mono1) { + *mono1 ^= mask1; + } + } + mask1 >>= 1; + } + ++mono1; + } + while (i < n) { + mask1 = 0x80; + for (j = 0; j < 8 && i < n; ++i, ++j) { + if (noClip || state->clip->test(x0 + i, y)) { + color = pattern->getColor(x0 + i, y); + if (color.mono1) { + *mono1 ^= mask1; + } + } + mask1 >>= 1; + } + ++mono1; + } + break; + + case splashModeMono8: + mono8 = &bitmap->data.mono8[y * bitmap->width + x0]; + for (i = 0; i < n; ++i) { + if (noClip || state->clip->test(x0 + i, y)) { + color = pattern->getColor(x0 + i, y); + *mono8 ^= color.mono8; + } + ++mono8; + } + break; + + case splashModeRGB8: + rgb8 = &bitmap->data.rgb8[y * bitmap->width + x0]; + for (i = 0; i < n; ++i) { + if (noClip || state->clip->test(x0 + i, y)) { + color = pattern->getColor(x0 + i, y); + *rgb8 ^= color.rgb8; + } + ++rgb8; + } + break; + + case splashModeBGR8Packed: + bgr8 = &bitmap->data.bgr8[y * bitmap->rowSize + 3 * x0]; + for (i = 0; i < n; ++i) { + if (noClip || state->clip->test(x0 + i, y)) { + color = pattern->getColor(x0 + i, y); + bgr8[2] ^= splashBGR8R(color.bgr8); + bgr8[1] ^= splashBGR8G(color.bgr8); + bgr8[0] ^= splashBGR8B(color.bgr8); + } + bgr8 += 3; + } + break; + } +} + +void Splash::getPixel(int x, int y, SplashColor *pixel) { + SplashBGR8P *bgr8; + + if (y < 0 || y >= bitmap->height || x < 0 || x >= bitmap->width) { + return; + } + switch (bitmap->mode) { + case splashModeMono1: + pixel->mono1 = (bitmap->data.mono1[y * bitmap->rowSize + (x >> 3)] + >> (7 - (x & 7))) & 1; + break; + case splashModeMono8: + pixel->mono8 = bitmap->data.mono8[y * bitmap->width + x]; + break; + case splashModeRGB8: + pixel->rgb8 = bitmap->data.rgb8[y * bitmap->width + x]; + break; + case splashModeBGR8Packed: + bgr8 = &bitmap->data.bgr8[y * bitmap->rowSize + 3 * x]; + pixel->bgr8 = splashMakeBGR8(bgr8[2], bgr8[1], bgr8[0]); + break; + } +} + +SplashError Splash::fillChar(SplashCoord x, SplashCoord y, + int c, SplashFont *font) { + SplashGlyphBitmap glyph; + int x0, y0, xFrac, yFrac; + SplashError err; + + if (debugMode) { + printf("fillChar: x=%.2f y=%.2f c=%3d=0x%02x='%c'\n", + x, y, c, c, c); + } + x0 = splashFloor(x); + xFrac = splashFloor((x - x0) * splashFontFraction); + y0 = splashFloor(y); + yFrac = splashFloor((y - y0) * splashFontFraction); + if (!font->getGlyph(c, xFrac, yFrac, &glyph)) { + return splashErrNoGlyph; + } + err = fillGlyph(x, y, &glyph); + if (glyph.freeData) { + gfree(glyph.data); + } + return err; +} + +SplashError Splash::fillGlyph(SplashCoord x, SplashCoord y, + SplashGlyphBitmap *glyph) { + int alpha, ialpha; + Guchar *p; + SplashColor fg; + SplashMono1P *mono1Ptr; + SplashMono8 *mono8Ptr; + SplashRGB8 *rgb8Ptr; + SplashBGR8P *bgr8Ptr; + SplashMono8 bgMono8; + int bgR, bgG, bgB; + SplashClipResult clipRes; + GBool noClip; + int x0, y0, x1, y1, xx, xx1, yy; + + x0 = splashFloor(x); + y0 = splashFloor(y); + + if ((clipRes = state->clip->testRect(x0 - glyph->x, + y0 - glyph->y, + x0 - glyph->x + glyph->w - 1, + y0 - glyph->y + glyph->h - 1)) + != splashClipAllOutside) { + noClip = clipRes == splashClipAllInside; + + //~ optimize this + if (glyph->aa) { + p = glyph->data; + for (yy = 0, y1 = y0 - glyph->y; yy < glyph->h; ++yy, ++y1) { + for (xx = 0, x1 = x0 - glyph->x; xx < glyph->w; ++xx, ++x1) { + alpha = *p++; + if (alpha > 0) { + if (noClip || state->clip->test(x1, y1)) { + ialpha = 255 - alpha; + fg = state->fillPattern->getColor(x1, y1); + switch (bitmap->mode) { + case splashModeMono1: + if (alpha >= 0x80) { + mono1Ptr = &bitmap->data.mono1[y1 * bitmap->rowSize + + (x1 >> 3)]; + if (fg.mono1) { + *mono1Ptr |= 0x80 >> (x1 & 7); + } else { + *mono1Ptr &= ~(0x80 >> (x1 & 7)); + } + } + break; + case splashModeMono8: + mono8Ptr = &bitmap->data.mono8[y1 * bitmap->width + x1]; + bgMono8 = *mono8Ptr; + // note: floor(x / 255) = x >> 8 (for 16-bit x) + *mono8Ptr = (alpha * fg.mono8 + ialpha * bgMono8) >> 8; + break; + case splashModeRGB8: + rgb8Ptr = &bitmap->data.rgb8[y1 * bitmap->width + x1]; + bgR = splashRGB8R(*rgb8Ptr); + bgG = splashRGB8G(*rgb8Ptr); + bgB = splashRGB8B(*rgb8Ptr); + *rgb8Ptr = splashMakeRGB8((alpha * splashRGB8R(fg.rgb8) + + ialpha * bgR) >> 8, + (alpha * splashRGB8G(fg.rgb8) + + ialpha * bgG) >> 8, + (alpha * splashRGB8B(fg.rgb8) + + ialpha * bgB) >> 8); + break; + case splashModeBGR8Packed: + bgr8Ptr = &bitmap->data.bgr8[y1 * bitmap->rowSize + 3 * x1]; + bgr8Ptr[2] = + (alpha * splashBGR8R(fg.bgr8) + ialpha * bgr8Ptr[2]) >> 8; + bgr8Ptr[1] = + (alpha * splashBGR8G(fg.bgr8) + ialpha * bgr8Ptr[1]) >> 8; + bgr8Ptr[0] = + (alpha * splashBGR8B(fg.bgr8) + ialpha * bgr8Ptr[0]) >> 8; + break; + } + } + } + } + } + + } else { + p = glyph->data; + for (yy = 0, y1 = y0 - glyph->y; yy < glyph->h; ++yy, ++y1) { + for (xx = 0, x1 = x0 - glyph->x; xx < glyph->w; xx += 8) { + alpha = *p++; + for (xx1 = 0; xx1 < 8 && xx + xx1 < glyph->w; ++xx1, ++x1) { + if (alpha & 0x80) { + if (noClip || state->clip->test(x1, y1)) { + fg = state->fillPattern->getColor(x1, y1); + switch (bitmap->mode) { + case splashModeMono1: + mono1Ptr = &bitmap->data.mono1[y1 * bitmap->rowSize + + (x1 >> 3)]; + if (fg.mono1) { + *mono1Ptr |= 0x80 >> (x1 & 7); + } else { + *mono1Ptr &= ~(0x80 >> (x1 & 7)); + } + break; + case splashModeMono8: + bitmap->data.mono8[y1 * bitmap->width + x1] = fg.mono8; + break; + case splashModeRGB8: + bitmap->data.rgb8[y1 * bitmap->width + x1] = fg.rgb8; + break; + case splashModeBGR8Packed: + bgr8Ptr = &bitmap->data.bgr8[y1 * bitmap->rowSize + 3 * x1]; + bgr8Ptr[2] = splashBGR8R(fg.bgr8); + bgr8Ptr[1] = splashBGR8G(fg.bgr8); + bgr8Ptr[0] = splashBGR8B(fg.bgr8); + break; + } + } + } + alpha <<= 1; + } + } + } + } + } + + return splashOk; +} + +SplashError Splash::fillImageMask(SplashImageMaskSource src, void *srcData, + int w, int h, SplashCoord *mat) { + GBool rot; + SplashCoord xScale, yScale, xShear, yShear; + int tx, ty, scaledWidth, scaledHeight, xSign, ySign; + int ulx, uly, llx, lly, urx, ury, lrx, lry; + int ulx1, uly1, llx1, lly1, urx1, ury1, lrx1, lry1; + int xMin, xMax, yMin, yMax; + SplashClipResult clipRes, clipRes2; + int yp, yq, yt, yStep, lastYStep; + int xp, xq, xt, xStep, xSrc; + int k1, spanXMin, spanXMax, spanY; + SplashMono1 *pixBuf; + SplashMono1 *p; + int pixAcc; + SplashCoord alpha; + SplashColor fg, bg, pix; + int x, y, x1, y1, x2, y2; + int n, m, i, j; + + if (debugMode) { + printf("fillImageMask: w=%d h=%d mat=[%.2f %.2f %.2f %.2f %.2f %.2f]\n", + w, h, mat[0], mat[1], mat[2], mat[3], mat[4], mat[5]); + } + + // check for singular matrix + if (splashAbs(mat[0] * mat[3] - mat[1] * mat[2]) < 0.000001) { + return splashErrSingularMatrix; + } + + // compute scale, shear, rotation, translation parameters + rot = splashAbs(mat[1]) > splashAbs(mat[0]); + if (rot) { + xScale = -mat[1]; + yScale = mat[2] - (mat[0] * mat[3]) / mat[1]; + xShear = -mat[3] / yScale; + yShear = -mat[0] / mat[1]; + } else { + xScale = mat[0]; + yScale = mat[3] - (mat[1] * mat[2]) / mat[0]; + xShear = mat[2] / yScale; + yShear = mat[1] / mat[0]; + } + tx = splashRound(mat[4]); + ty = splashRound(mat[5]); + scaledWidth = abs(splashRound(mat[4] + xScale) - tx) + 1; + scaledHeight = abs(splashRound(mat[5] + yScale) - ty) + 1; + xSign = (xScale < 0) ? -1 : 1; + ySign = (yScale < 0) ? -1 : 1; + + // clipping + ulx1 = 0; + uly1 = 0; + urx1 = xSign * (scaledWidth - 1); + ury1 = splashRound(yShear * urx1); + llx1 = splashRound(xShear * ySign * (scaledHeight - 1)); + lly1 = ySign * (scaledHeight - 1) + splashRound(yShear * llx1); + lrx1 = xSign * (scaledWidth - 1) + + splashRound(xShear * ySign * (scaledHeight - 1)); + lry1 = ySign * (scaledHeight - 1) + splashRound(yShear * lrx1); + if (rot) { + ulx = tx + uly1; uly = ty - ulx1; + urx = tx + ury1; ury = ty - urx1; + llx = tx + lly1; lly = ty - llx1; + lrx = tx + lry1; lry = ty - lrx1; + } else { + ulx = tx + ulx1; uly = ty + uly1; + urx = tx + urx1; ury = ty + ury1; + llx = tx + llx1; lly = ty + lly1; + lrx = tx + lrx1; lry = ty + lry1; + } + xMin = (ulx < urx) ? (ulx < llx) ? (ulx < lrx) ? ulx : lrx + : (llx < lrx) ? llx : lrx + : (urx < llx) ? (urx < lrx) ? urx : lrx + : (llx < lrx) ? llx : lrx; + xMax = (ulx > urx) ? (ulx > llx) ? (ulx > lrx) ? ulx : lrx + : (llx > lrx) ? llx : lrx + : (urx > llx) ? (urx > lrx) ? urx : lrx + : (llx > lrx) ? llx : lrx; + yMin = (uly < ury) ? (uly < lly) ? (uly < lry) ? uly : lry + : (lly < lry) ? lly : lry + : (ury < lly) ? (ury < lry) ? ury : lry + : (lly < lry) ? lly : lry; + yMax = (uly > ury) ? (uly > lly) ? (uly > lry) ? uly : lry + : (lly > lry) ? lly : lry + : (ury > lly) ? (ury > lry) ? ury : lry + : (lly > lry) ? lly : lry; + clipRes = state->clip->testRect(xMin, yMin, xMax, yMax); + + // compute Bresenham parameters for x and y scaling + yp = h / scaledHeight; + yq = h % scaledHeight; + xp = w / scaledWidth; + xq = w % scaledWidth; + + // allocate pixel buffer + pixBuf = (SplashMono1 *)gmalloc((yp + 1) * w * sizeof(SplashMono1)); + + // init y scale Bresenham + yt = 0; + lastYStep = 1; + + for (y = 0; y < scaledHeight; ++y) { + + // y scale Bresenham + yStep = yp; + yt += yq; + if (yt >= scaledHeight) { + yt -= scaledHeight; + ++yStep; + } + + // read row(s) from image + n = (yp > 0) ? yStep : lastYStep; + if (n > 0) { + p = pixBuf; + for (i = 0; i < n; ++i) { + for (j = 0; j < w; ++j) { + (*src)(srcData, p++); + } + } + } + lastYStep = yStep; + + // loop-invariant constants + k1 = splashRound(xShear * ySign * y); + + // clipping test + if (clipRes != splashClipAllInside && + !rot && + splashRound(yShear * k1) == + splashRound(yShear * (xSign * (scaledWidth - 1) + k1))) { + if (xSign > 0) { + spanXMin = tx + k1; + spanXMax = spanXMin + (scaledWidth - 1); + } else { + spanXMax = tx + k1; + spanXMin = spanXMax - (scaledWidth - 1); + } + spanY = ty + ySign * y + splashRound(xShear * ySign * y); + clipRes2 = state->clip->testSpan(spanXMin, spanXMax, spanY); + if (clipRes2 == splashClipAllOutside) { + continue; + } + } else { + clipRes2 = clipRes; + } + + // init x scale Bresenham + xt = 0; + xSrc = 0; + + for (x = 0; x < scaledWidth; ++x) { + + // x scale Bresenham + xStep = xp; + xt += xq; + if (xt >= scaledWidth) { + xt -= scaledWidth; + ++xStep; + } + + // x shear + x1 = xSign * x + k1; + + // y shear + y1 = ySign * y + splashRound(yShear * x1); + + // rotation + if (rot) { + x2 = y1; + y2 = -x1; + } else { + x2 = x1; + y2 = y1; + } + + // compute the alpha value for (x,y) after the x and y scaling + // operations + n = yStep > 0 ? yStep : 1; + m = xStep > 0 ? xStep : 1; + p = pixBuf + xSrc; + pixAcc = 0; + for (i = 0; i < n; ++i) { + for (j = 0; j < m; ++j) { + pixAcc += *p++; + } + p += w - m; + } + + // blend fill color with background + if (pixAcc != 0) { + fg = state->fillPattern->getColor(tx + x2, ty + y2); + if (pixAcc == n * m) { + pix = fg; + } else { + getPixel(tx + x2, ty + y2, &bg); + alpha = (SplashCoord)pixAcc / (SplashCoord)(n * m); + switch (bitmap->mode) { + case splashModeMono1: + pix.mono1 = splashRound(alpha * fg.mono1 + + (1 - alpha) * bg.mono1); + break; + case splashModeMono8: + pix.mono8 = splashRound(alpha * fg.mono8 + + (1 - alpha) * bg.mono8); + break; + case splashModeRGB8: + pix.rgb8 = splashMakeRGB8( + splashRound(alpha * splashRGB8R(fg.rgb8) + + (1 - alpha) * splashRGB8R(bg.rgb8)), + splashRound(alpha * splashRGB8G(fg.rgb8) + + (1 - alpha) * splashRGB8G(bg.rgb8)), + splashRound(alpha * splashRGB8B(fg.rgb8) + + (1 - alpha) * splashRGB8B(bg.rgb8))); + case splashModeBGR8Packed: + pix.bgr8 = splashMakeBGR8( + splashRound(alpha * splashBGR8R(fg.bgr8) + + (1 - alpha) * splashBGR8R(bg.bgr8)), + splashRound(alpha * splashBGR8G(fg.bgr8) + + (1 - alpha) * splashBGR8G(bg.bgr8)), + splashRound(alpha * splashBGR8B(fg.bgr8) + + (1 - alpha) * splashBGR8B(bg.bgr8))); + break; + } + } + drawPixel(tx + x2, ty + y2, &pix, clipRes2 == splashClipAllInside); + } + + // x scale Bresenham + xSrc += xStep; + } + } + + // free memory + gfree(pixBuf); + + return splashOk; +} + +SplashError Splash::drawImage(SplashImageSource src, void *srcData, + SplashColorMode srcMode, + int w, int h, SplashCoord *mat) { + GBool ok, rot, halftone; + SplashCoord xScale, yScale, xShear, yShear; + int tx, ty, scaledWidth, scaledHeight, xSign, ySign; + int ulx, uly, llx, lly, urx, ury, lrx, lry; + int ulx1, uly1, llx1, lly1, urx1, ury1, lrx1, lry1; + int xMin, xMax, yMin, yMax; + SplashClipResult clipRes, clipRes2; + int yp, yq, yt, yStep, lastYStep; + int xp, xq, xt, xStep, xSrc; + int k1, spanXMin, spanXMax, spanY; + SplashColor *pixBuf, *p; + Guchar *alphaBuf, *q; + SplashColor pix; + SplashCoord pixAcc[splashMaxColorComps]; + int alphaAcc; + SplashCoord pixMul, alphaMul, alpha; + int x, y, x1, y1, x2, y2; + int n, m, i, j; + + if (debugMode) { + printf("drawImage: srcMode=%d w=%d h=%d mat=[%.2f %.2f %.2f %.2f %.2f %.2f]\n", + srcMode, w, h, mat[0], mat[1], mat[2], mat[3], mat[4], mat[5]); + } + + // check color modes + ok = gFalse; // make gcc happy + switch (bitmap->mode) { + case splashModeMono1: + ok = srcMode == splashModeMono1 || srcMode == splashModeMono8; + break; + case splashModeMono8: + ok = srcMode == splashModeMono8; + break; + case splashModeRGB8: + ok = srcMode == splashModeRGB8; + break; + case splashModeBGR8Packed: + ok = srcMode == splashModeBGR8Packed; + break; + } + if (!ok) { + return splashErrModeMismatch; + } + halftone = bitmap->mode == splashModeMono1 && srcMode == splashModeMono8; + + // check for singular matrix + if (splashAbs(mat[0] * mat[3] - mat[1] * mat[2]) < 0.000001) { + return splashErrSingularMatrix; + } + + // compute scale, shear, rotation, translation parameters + rot = splashAbs(mat[1]) > splashAbs(mat[0]); + if (rot) { + xScale = -mat[1]; + yScale = mat[2] - (mat[0] * mat[3]) / mat[1]; + xShear = -mat[3] / yScale; + yShear = -mat[0] / mat[1]; + } else { + xScale = mat[0]; + yScale = mat[3] - (mat[1] * mat[2]) / mat[0]; + xShear = mat[2] / yScale; + yShear = mat[1] / mat[0]; + } + tx = splashRound(mat[4]); + ty = splashRound(mat[5]); + scaledWidth = abs(splashRound(mat[4] + xScale) - tx) + 1; + scaledHeight = abs(splashRound(mat[5] + yScale) - ty) + 1; + xSign = (xScale < 0) ? -1 : 1; + ySign = (yScale < 0) ? -1 : 1; + + // clipping + ulx1 = 0; + uly1 = 0; + urx1 = xSign * (scaledWidth - 1); + ury1 = splashRound(yShear * urx1); + llx1 = splashRound(xShear * ySign * (scaledHeight - 1)); + lly1 = ySign * (scaledHeight - 1) + splashRound(yShear * llx1); + lrx1 = xSign * (scaledWidth - 1) + + splashRound(xShear * ySign * (scaledHeight - 1)); + lry1 = ySign * (scaledHeight - 1) + splashRound(yShear * lrx1); + if (rot) { + ulx = tx + uly1; uly = ty - ulx1; + urx = tx + ury1; ury = ty - urx1; + llx = tx + lly1; lly = ty - llx1; + lrx = tx + lry1; lry = ty - lrx1; + } else { + ulx = tx + ulx1; uly = ty + uly1; + urx = tx + urx1; ury = ty + ury1; + llx = tx + llx1; lly = ty + lly1; + lrx = tx + lrx1; lry = ty + lry1; + } + xMin = (ulx < urx) ? (ulx < llx) ? (ulx < lrx) ? ulx : lrx + : (llx < lrx) ? llx : lrx + : (urx < llx) ? (urx < lrx) ? urx : lrx + : (llx < lrx) ? llx : lrx; + xMax = (ulx > urx) ? (ulx > llx) ? (ulx > lrx) ? ulx : lrx + : (llx > lrx) ? llx : lrx + : (urx > llx) ? (urx > lrx) ? urx : lrx + : (llx > lrx) ? llx : lrx; + yMin = (uly < ury) ? (uly < lly) ? (uly < lry) ? uly : lry + : (lly < lry) ? lly : lry + : (ury < lly) ? (ury < lry) ? ury : lry + : (lly < lry) ? lly : lry; + yMax = (uly > ury) ? (uly > lly) ? (uly > lry) ? uly : lry + : (lly > lry) ? lly : lry + : (ury > lly) ? (ury > lry) ? ury : lry + : (lly > lry) ? lly : lry; + if ((clipRes = state->clip->testRect(xMin, yMin, xMax, yMax)) + == splashClipAllOutside) { + return splashOk; + } + + // compute Bresenham parameters for x and y scaling + yp = h / scaledHeight; + yq = h % scaledHeight; + xp = w / scaledWidth; + xq = w % scaledWidth; + + // allocate pixel buffer + pixBuf = (SplashColor *)gmalloc((yp + 1) * w * sizeof(SplashColor)); + alphaBuf = (Guchar *)gmalloc((yp + 1) * w * sizeof(Guchar)); + + // init y scale Bresenham + yt = 0; + lastYStep = 1; + + for (y = 0; y < scaledHeight; ++y) { + + // y scale Bresenham + yStep = yp; + yt += yq; + if (yt >= scaledHeight) { + yt -= scaledHeight; + ++yStep; + } + + // read row(s) from image + n = (yp > 0) ? yStep : lastYStep; + if (n > 0) { + p = pixBuf; + q = alphaBuf; + for (i = 0; i < n; ++i) { + for (j = 0; j < w; ++j) { + (*src)(srcData, p++, q++); + } + } + } + lastYStep = yStep; + + // loop-invariant constants + k1 = splashRound(xShear * ySign * y); + + // clipping test + if (clipRes != splashClipAllInside && + !rot && + splashRound(yShear * k1) == + splashRound(yShear * (xSign * (scaledWidth - 1) + k1))) { + if (xSign > 0) { + spanXMin = tx + k1; + spanXMax = spanXMin + (scaledWidth - 1); + } else { + spanXMax = tx + k1; + spanXMin = spanXMax - (scaledWidth - 1); + } + spanY = ty + ySign * y + splashRound(xShear * ySign * y); + clipRes2 = state->clip->testSpan(spanXMin, spanXMax, spanY); + if (clipRes2 == splashClipAllOutside) { + continue; + } + } else { + clipRes2 = clipRes; + } + + // init x scale Bresenham + xt = 0; + xSrc = 0; + + for (x = 0; x < scaledWidth; ++x) { + + // x scale Bresenham + xStep = xp; + xt += xq; + if (xt >= scaledWidth) { + xt -= scaledWidth; + ++xStep; + } + + // x shear + x1 = xSign * x + k1; + + // y shear + y1 = ySign * y + splashRound(yShear * x1); + + // rotation + if (rot) { + x2 = y1; + y2 = -x1; + } else { + x2 = x1; + y2 = y1; + } + + // compute the filtered pixel at (x,y) after the x and y scaling + // operations + n = yStep > 0 ? yStep : 1; + m = xStep > 0 ? xStep : 1; + p = pixBuf + xSrc; + q = alphaBuf + xSrc; + for (i = 0; i < splashMaxColorComps; ++i) { + pixAcc[i] = 0; + } + alphaAcc = 0; + for (i = 0; i < n; ++i) { + for (j = 0; j < m; ++j) { + switch (srcMode) { + case splashModeMono1: + pixAcc[0] += p->mono1; + break; + case splashModeMono8: + pixAcc[0] += p->mono8; + break; + case splashModeRGB8: + pixAcc[0] += splashRGB8R(p->rgb8); + pixAcc[1] += splashRGB8G(p->rgb8); + pixAcc[2] += splashRGB8B(p->rgb8); + break; + case splashModeBGR8Packed: + pixAcc[0] += splashBGR8R(p->bgr8); + pixAcc[1] += splashBGR8G(p->bgr8); + pixAcc[2] += splashBGR8B(p->bgr8); + break; + } + ++p; + alphaAcc += *q++; + } + p += w - m; + q += w - m; + } + alphaMul = 1 / (SplashCoord)(n * m); + if (halftone) { + pixMul = (SplashCoord)alphaMul / 256.0; + } else { + pixMul = alphaMul; + } + alpha = (SplashCoord)alphaAcc * alphaMul; + + //~ this should blend if 0 < alpha < 1 + if (alpha > 0.75) { + + // mono8 -> mono1 conversion, with halftoning + if (halftone) { + pix.mono1 = state->screen->test(tx + x2, ty + y2, + pixAcc[0] * pixMul); + + // no conversion, no halftoning + } else { + switch (bitmap->mode) { + case splashModeMono1: + pix.mono1 = splashRound(pixAcc[0] * pixMul); + break; + case splashModeMono8: + pix.mono8 = splashRound(pixAcc[0] * pixMul); + break; + case splashModeRGB8: + pix.rgb8 = splashMakeRGB8(splashRound(pixAcc[0] * pixMul), + splashRound(pixAcc[1] * pixMul), + splashRound(pixAcc[2] * pixMul)); + break; + case splashModeBGR8Packed: + pix.bgr8 = splashMakeBGR8(splashRound(pixAcc[0] * pixMul), + splashRound(pixAcc[1] * pixMul), + splashRound(pixAcc[2] * pixMul)); + break; + } + } + + // set pixel + drawPixel(tx + x2, ty + y2, &pix, clipRes2 == splashClipAllInside); + } + + // x scale Bresenham + xSrc += xStep; + } + } + + gfree(pixBuf); + gfree(alphaBuf); + + return splashOk; +} + +void Splash::dumpPath(SplashPath *path) { + int i; + + for (i = 0; i < path->length; ++i) { + printf(" %3d: x=%8.2f y=%8.2f%s%s%s%s%s\n", + i, path->pts[i].x, path->pts[i].y, + (path->flags[i] & splashPathFirst) ? " first" : "", + (path->flags[i] & splashPathLast) ? " last" : "", + (path->flags[i] & splashPathClosed) ? " closed" : "", + (path->flags[i] & splashPathCurve) ? " curve" : "", + (path->flags[i] & splashPathArcCW) ? " arcCW" : ""); + } +} diff --git a/pdf/splash/Splash.h b/pdf/splash/Splash.h new file mode 100644 index 0000000..efcbdab --- /dev/null +++ b/pdf/splash/Splash.h @@ -0,0 +1,176 @@ +//======================================================================== +// +// Splash.h +// +//======================================================================== + +#ifndef SPLASH_H +#define SPLASH_H + +#include <aconf.h> + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "SplashTypes.h" + +class SplashBitmap; +class SplashGlyphBitmap; +class SplashState; +class SplashPattern; +class SplashScreen; +class SplashPath; +class SplashXPath; +class SplashClip; +class SplashFont; + +//------------------------------------------------------------------------ + +// Retrieves the next pixel in an image mask. Normally, fills in +// *<pixel> and returns true. If the image stream is exhausted, +// returns false. +typedef GBool (*SplashImageMaskSource)(void *data, SplashMono1 *pixel); + +// Retrieves the next pixel in an image. Normally, fills in *<pixel> +// (pixel color) and *<alpha> (1 for opaque, 0 for transparent), and +// returns true. If the image stream is exhausted, returns false. +typedef GBool (*SplashImageSource)(void *data, SplashColor *pixel, + Guchar *alpha); + +//------------------------------------------------------------------------ +// Splash +//------------------------------------------------------------------------ + +class Splash { +public: + + // Create a new rasterizer object. + Splash(SplashBitmap *bitmapA); + + ~Splash(); + + //----- state read + + SplashPattern *getStrokePattern(); + SplashPattern *getFillPattern(); + SplashScreen *getScreen(); + SplashCoord getLineWidth(); + int getLineCap(); + int getLineJoin(); + SplashCoord getMiterLimit(); + SplashCoord getFlatness(); + SplashCoord *getLineDash(); + int getLineDashLength(); + SplashCoord getLineDashPhase(); + SplashClip *getClip(); + + //----- state write + + void setStrokePattern(SplashPattern *strokeColor); + void setFillPattern(SplashPattern *fillColor); + void setScreen(SplashScreen *screen); + 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 clipResetToRect(SplashCoord x0, SplashCoord y0, + SplashCoord x1, SplashCoord y1); + SplashError clipToRect(SplashCoord x0, SplashCoord y0, + SplashCoord x1, SplashCoord y1); + SplashError clipToPath(SplashPath *path, GBool eo); + + //----- state save/restore + + void saveState(); + SplashError restoreState(); + + //----- drawing operations + + // Fill the bitmap with <color>. This is not subject to clipping. + void clear(SplashColor color); + + // 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. + SplashError fillGlyph(SplashCoord x, SplashCoord y, + SplashGlyphBitmap *glyph); + + // Draws an image mask using the fill color. This will read <w>*<h> + // pixels from <src>, in raster order, 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); + + // Draw an image. This will read <w>*<h> pixels from <src>, in + // raster order, starting with the top line. These pixels are + // assumed to be in the source mode, <srcMode>. The following + // combinations of source and target modes are supported: + // source target + // ------ ------ + // Mono1 Mono1 + // Mono8 Mono1 -- with dithering + // Mono8 Mono8 + // RGB8 RGB8 + // BGR8packed BGR8Packed + // The matrix behaves as for fillImageMask. + SplashError drawImage(SplashImageSource src, void *srcData, + SplashColorMode srcMode, + int w, int h, SplashCoord *mat); + + //~ drawMaskedImage + + //----- misc + + // Return the associated bitmap. + SplashBitmap *getBitmap() { return bitmap; } + + // Toggle debug mode on or off. + void setDebugMode(GBool debugModeA) { debugMode = debugModeA; } + +private: + + void strokeNarrow(SplashXPath *xPath); + void strokeWide(SplashXPath *xPath); + SplashXPath *makeDashedPath(SplashXPath *xPath); + SplashError fillWithPattern(SplashPath *path, GBool eo, + SplashPattern *pattern); + void drawPixel(int x, int y, SplashColor *color, GBool noClip); + void drawPixel(int x, int y, SplashPattern *pattern, GBool noClip); + void drawSpan(int x0, int x1, int y, SplashPattern *pattern, GBool noClip); + void xorSpan(int x0, int x1, int y, SplashPattern *pattern, GBool noClip); + void putPixel(int x, int y, SplashColor *pixel); + void getPixel(int x, int y, SplashColor *pixel); + void dumpPath(SplashPath *path); + + SplashBitmap *bitmap; + SplashState *state; + GBool debugMode; +}; + +#endif diff --git a/pdf/splash/SplashBitmap.cc b/pdf/splash/SplashBitmap.cc new file mode 100644 index 0000000..5ea304f --- /dev/null +++ b/pdf/splash/SplashBitmap.cc @@ -0,0 +1,134 @@ +//======================================================================== +// +// SplashBitmap.cc +// +//======================================================================== + +#include <aconf.h> + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include <stdio.h> +#include "gmem.h" +#include "SplashErrorCodes.h" +#include "SplashBitmap.h" + +//------------------------------------------------------------------------ +// SplashBitmap +//------------------------------------------------------------------------ + +SplashBitmap::SplashBitmap(int widthA, int heightA, SplashColorMode modeA) { + width = widthA; + height = heightA; + mode = modeA; + switch (mode) { + case splashModeMono1: + rowSize = (width + 7) >> 3; + data.mono1 = (SplashMono1P *) + gmalloc(rowSize * height * sizeof(SplashMono1P)); + break; + case splashModeMono8: + rowSize = width; + data.mono8 = (SplashMono8 *) + gmalloc(width * height * sizeof(SplashMono8)); + break; + case splashModeRGB8: + rowSize = width << 2; + data.rgb8 = (SplashRGB8 *) + gmalloc(width * height * sizeof(SplashRGB8)); + break; + case splashModeBGR8Packed: + rowSize = (width * 3 + 3) & ~3; + data.bgr8 = (SplashBGR8P *) + gmalloc(rowSize * height * sizeof(SplashMono1P)); + } +} + + +SplashBitmap::~SplashBitmap() { + switch (mode) { + case splashModeMono1: + gfree(data.mono1); + break; + case splashModeMono8: + gfree(data.mono8); + break; + case splashModeRGB8: + gfree(data.rgb8); + break; + case splashModeBGR8Packed: + gfree(data.bgr8); + break; + } +} + +SplashError SplashBitmap::writePNMFile(char *fileName) { + FILE *f; + SplashMono1P *mono1; + SplashMono8 *mono8; + SplashRGB8 *rgb8; + SplashBGR8P *bgr8line, *bgr8; + int x, y; + + if (!(f = fopen(fileName, "wb"))) { + return splashErrOpenFile; + } + + switch (mode) { + + case splashModeMono1: + fprintf(f, "P4\n%d %d\n", width, height); + mono1 = data.mono1; + for (y = 0; y < height; ++y) { + for (x = 0; x < width; x += 8) { + fputc(*mono1 ^ 0xff, f); + ++mono1; + } + } + break; + + case splashModeMono8: + fprintf(f, "P5\n%d %d\n255\n", width, height); + mono8 = data.mono8; + for (y = 0; y < height; ++y) { + for (x = 0; x < width; ++x) { + fputc(*mono8, f); + ++mono8; + } + } + break; + + case splashModeRGB8: + fprintf(f, "P6\n%d %d\n255\n", width, height); + rgb8 = data.rgb8; + for (y = 0; y < height; ++y) { + for (x = 0; x < width; ++x) { + fputc(splashRGB8R(*rgb8), f); + fputc(splashRGB8G(*rgb8), f); + fputc(splashRGB8B(*rgb8), f); + ++rgb8; + } + } + break; + + case splashModeBGR8Packed: + fprintf(f, "P6\n%d %d\n255\n", width, height); + bgr8line = data.bgr8; + for (y = 0; y < height; ++y) { + bgr8 = bgr8line; + for (x = 0; x < width; ++x) { + fputc(bgr8[2], f); + fputc(bgr8[1], f); + fputc(bgr8[0], f); + bgr8 += 3; + } + bgr8line += rowSize; + } + break; + } + + fclose(f); + return splashOk; +} diff --git a/pdf/splash/SplashBitmap.h b/pdf/splash/SplashBitmap.h new file mode 100644 index 0000000..75e3217 --- /dev/null +++ b/pdf/splash/SplashBitmap.h @@ -0,0 +1,48 @@ +//======================================================================== +// +// SplashBitmap.h +// +//======================================================================== + +#ifndef SPLASHBITMAP_H +#define SPLASHBITMAP_H + +#include <aconf.h> + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "SplashTypes.h" + +//------------------------------------------------------------------------ +// SplashBitmap +//------------------------------------------------------------------------ + +class SplashBitmap { +public: + + // Create a new bitmap. + SplashBitmap(int widthA, int heightA, SplashColorMode modeA); + + ~SplashBitmap(); + + int getWidth() { return width; } + int getHeight() { return height; } + int getRowSize() { return rowSize; } + SplashColorMode getMode() { return mode; } + SplashColorPtr getDataPtr() { return data; } + + SplashError writePNMFile(char *fileName); + +private: + + int width, height; // size of bitmap + int rowSize; // size of one row of data, in bytes + SplashColorMode mode; // color mode + SplashColorPtr data; + + friend class Splash; +}; + +#endif diff --git a/pdf/splash/SplashClip.cc b/pdf/splash/SplashClip.cc new file mode 100644 index 0000000..4c70c03 --- /dev/null +++ b/pdf/splash/SplashClip.cc @@ -0,0 +1,270 @@ +//======================================================================== +// +// SplashClip.cc +// +//======================================================================== + +#include <aconf.h> + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include <stdlib.h> +#include <string.h> +#include "gmem.h" +#include "SplashErrorCodes.h" +#include "SplashMath.h" +#include "SplashPath.h" +#include "SplashXPath.h" +#include "SplashXPathScanner.h" +#include "SplashClip.h" + +//------------------------------------------------------------------------ +// SplashClip.flags +//------------------------------------------------------------------------ + +#define splashClipEO 0x01 // use even-odd rule + +//------------------------------------------------------------------------ +// SplashClip +//------------------------------------------------------------------------ + +SplashClip::SplashClip(SplashCoord x0, SplashCoord y0, + SplashCoord x1, SplashCoord y1) { + if (x0 < x1) { + xMin = splashFloor(x0); + xMax = splashFloor(x1); + } else { + xMin = splashFloor(x1); + xMax = splashFloor(x0); + } + if (y0 < y1) { + yMin = splashFloor(y0); + yMax = splashFloor(y1); + } else { + yMin = splashFloor(y1); + yMax = splashFloor(y0); + } + paths = NULL; + flags = NULL; + scanners = NULL; + length = size = 0; +} + +SplashClip::SplashClip(SplashClip *clip) { + int i; + + xMin = clip->xMin; + yMin = clip->yMin; + xMax = clip->xMax; + yMax = clip->yMax; + length = clip->length; + size = clip->size; + paths = (SplashXPath **)gmalloc(size * sizeof(SplashXPath *)); + flags = (Guchar *)gmalloc(size * sizeof(Guchar)); + scanners = (SplashXPathScanner **) + gmalloc(size * sizeof(SplashXPathScanner *)); + for (i = 0; i < length; ++i) { + paths[i] = clip->paths[i]->copy(); + flags[i] = clip->flags[i]; + scanners[i] = new SplashXPathScanner(paths[i], flags[i] & splashClipEO); + } +} + +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 **)grealloc(paths, size * sizeof(SplashXPath *)); + flags = (Guchar *)grealloc(flags, size * sizeof(Guchar)); + scanners = (SplashXPathScanner **) + grealloc(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 = splashFloor(x0); + xMax = splashFloor(x1); + } else { + xMin = splashFloor(x1); + xMax = splashFloor(x0); + } + if (y0 < y1) { + yMin = splashFloor(y0); + yMax = splashFloor(y1); + } else { + yMin = splashFloor(y1); + yMax = splashFloor(y0); + } +} + +SplashError SplashClip::clipToRect(SplashCoord x0, SplashCoord y0, + SplashCoord x1, SplashCoord y1) { + int x0I, y0I, x1I, y1I; + + if (x0 < x1) { + x0I = splashFloor(x0); + x1I = splashFloor(x1); + } else { + x0I = splashFloor(x1); + x1I = splashFloor(x0); + } + if (x0I > xMin) { + xMin = x0I; + } + if (x1I < xMax) { + xMax = x1I; + } + if (y0 < y1) { + y0I = splashFloor(y0); + y1I = splashFloor(y1); + } else { + y0I = splashFloor(y1); + y1I = splashFloor(y0); + } + if (y0I > yMin) { + yMin = y0I; + } + if (y1I < yMax) { + yMax = y1I; + } + return splashOk; +} + +SplashError SplashClip::clipToPath(SplashPath *path, SplashCoord flatness, + GBool eo) { + SplashXPath *xPath; + + xPath = new SplashXPath(path, flatness, gTrue); + + // check for an empty path + if (xPath->length == 0) { + xMax = xMin - 1; + yMax = yMin - 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); + xPath->sort(); + paths[length] = xPath; + flags[length] = eo ? splashClipEO : 0; + scanners[length] = new SplashXPathScanner(xPath, eo); + ++length; + } + + return splashOk; +} + +GBool SplashClip::test(int x, int y) { + int i; + + // check the rectangle + if (x < xMin || x > xMax || y < yMin || y > yMax) { + return gFalse; + } + + // check the paths + for (i = 0; i < length; ++i) { + if (!scanners[i]->test(x, y)) { + return gFalse; + } + } + + return gTrue; +} + +SplashClipResult SplashClip::testRect(int rectXMin, int rectYMin, + int rectXMax, int rectYMax) { + if (rectXMax < xMin || rectXMin > xMax || + rectYMax < yMin || rectYMin > yMax) { + return splashClipAllOutside; + } + if (rectXMin >= xMin && rectXMax <= xMax && + rectYMin >= yMin && rectYMax <= yMax && + length == 0) { + return splashClipAllInside; + } + return splashClipPartial; +} + +SplashClipResult SplashClip::testSpan(int spanXMin, int spanXMax, int spanY) { + int i; + + if (spanXMax < xMin || spanXMin > xMax || + spanY < yMin || spanY > yMax) { + return splashClipAllOutside; + } + if (!(spanXMin >= xMin && spanXMax <= xMax && + spanY >= yMin && spanY <= yMax)) { + return splashClipPartial; + } + for (i = 0; i < length; ++i) { + if (!scanners[i]->testSpan(xMin, xMax, spanY)) { + return splashClipPartial; + } + } + return splashClipAllInside; +} diff --git a/pdf/splash/SplashClip.h b/pdf/splash/SplashClip.h new file mode 100644 index 0000000..34a4cc5 --- /dev/null +++ b/pdf/splash/SplashClip.h @@ -0,0 +1,88 @@ +//======================================================================== +// +// SplashClip.h +// +//======================================================================== + +#ifndef SPLASHCLIP_H +#define SPLASHCLIP_H + +#include <aconf.h> + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "SplashTypes.h" + +class SplashPath; +class SplashXPath; +class SplashXPathScanner; + +//------------------------------------------------------------------------ + +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); + + // 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 flatness, + GBool eo); + + // Returns true if (<x>,<y>) is inside the clip. + GBool test(int x, int y); + + // 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); + +private: + + SplashClip(SplashClip *clip); + void grow(int nPaths); + + int xMin, yMin, xMax, yMax; + SplashXPath **paths; + Guchar *flags; + SplashXPathScanner **scanners; + int length, size; +}; + +#endif diff --git a/pdf/splash/SplashErrorCodes.h b/pdf/splash/SplashErrorCodes.h new file mode 100644 index 0000000..2a70d4b --- /dev/null +++ b/pdf/splash/SplashErrorCodes.h @@ -0,0 +1,32 @@ +//======================================================================== +// +// SplashErrorCodes.h +// +//======================================================================== + +#ifndef SPLASHERRORCODES_H +#define SPLASHERRORCODES_H + +#include <aconf.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 + +#endif diff --git a/pdf/splash/SplashFTFont.cc b/pdf/splash/SplashFTFont.cc new file mode 100644 index 0000000..a7d0396 --- /dev/null +++ b/pdf/splash/SplashFTFont.cc @@ -0,0 +1,288 @@ +//======================================================================== +// +// SplashFTFont.cc +// +//======================================================================== + +#include <aconf.h> + +#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include "freetype/ftoutln.h" +#include "freetype/internal/ftobjs.h" // needed for FT_New_Size decl +#include "gmem.h" +#include "SplashMath.h" +#include "SplashGlyphBitmap.h" +#include "SplashPath.h" +#include "SplashFTFontEngine.h" +#include "SplashFTFontFile.h" +#include "SplashFTFont.h" + +//------------------------------------------------------------------------ + +static int glyphPathMoveTo(FT_Vector *pt, void *path); +static int glyphPathLineTo(FT_Vector *pt, void *path); +static int glyphPathConicTo(FT_Vector *ctrl, FT_Vector *pt, void *path); +static int glyphPathCubicTo(FT_Vector *ctrl1, FT_Vector *ctrl2, + FT_Vector *pt, void *path); + +//------------------------------------------------------------------------ +// SplashFTFont +//------------------------------------------------------------------------ + +SplashFTFont::SplashFTFont(SplashFTFontFile *fontFileA, SplashCoord *matA): + SplashFont(fontFileA, matA, fontFileA->engine->aa) +{ + FT_Face face; + SplashCoord size, div; + int x, y; + + face = fontFileA->face; + if (FT_New_Size(face, &sizeObj)) { + return; + } + face->size = sizeObj; + size = splashSqrt(mat[2]*mat[2] + mat[3]*mat[3]); + if (FT_Set_Pixel_Sizes(face, 0, (int)size)) { + return; + } + + div = face->bbox.xMax > 20000 ? 65536 : 1; + + // 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; + } + // 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); + } + + // compute the transform matrix + 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); +} + +SplashFTFont::~SplashFTFont() { +} + +GBool SplashFTFont::getGlyph(int c, int xFrac, int yFrac, + SplashGlyphBitmap *bitmap) { + return SplashFont::getGlyph(c, xFrac, 0, bitmap); +} + +GBool SplashFTFont::makeGlyph(int c, int xFrac, int yFrac, + SplashGlyphBitmap *bitmap) { + 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)(xFrac * splashFontFractionMul * 64); + offset.y = 0; + FT_Set_Transform(ff->face, &matrix, &offset); + slot = ff->face->glyph; + + if (ff->codeToGID && c < ff->codeToGIDLen) { + gid = (FT_UInt)ff->codeToGID[c]; + } else { + gid = (FT_UInt)c; + } + + // if we have the FT2 bytecode interpreter, autohinting won't be used +#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER + if (FT_Load_Glyph(ff->face, gid, + aa ? FT_LOAD_NO_BITMAP : FT_LOAD_DEFAULT)) { + return gFalse; + } +#else + // 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 (FT_Load_Glyph(ff->face, gid, + aa ? FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP + : FT_LOAD_DEFAULT)) { + return gFalse; + } +#endif + if (FT_Render_Glyph(slot, aa ? ft_render_mode_normal + : ft_render_mode_mono)) { + 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 *)gmalloc(rowSize * bitmap->h); + 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; +} + +SplashPath *SplashFTFont::getGlyphPath(int c) { + static FT_Outline_Funcs outlineFuncs = { + &glyphPathMoveTo, + &glyphPathLineTo, + &glyphPathConicTo, + &glyphPathCubicTo, + 0, 0 + }; + SplashFTFontFile *ff; + SplashPath *path; + FT_GlyphSlot slot; + FT_UInt gid; + FT_Glyph glyph; + + ff = (SplashFTFontFile *)fontFile; + ff->face->size = sizeObj; + FT_Set_Transform(ff->face, &matrix, NULL); + slot = ff->face->glyph; + if (ff->codeToGID && c < ff->codeToGIDLen) { + gid = ff->codeToGID[c]; + } else { + gid = (FT_UInt)c; + } + if (FT_Load_Glyph(ff->face, gid, FT_LOAD_DEFAULT)) { + return NULL; + } + if (FT_Get_Glyph(slot, &glyph)) { + return NULL; + } + path = new SplashPath(); + FT_Outline_Decompose(&((FT_OutlineGlyph)glyph)->outline, + &outlineFuncs, path); + return path; +} + +static int glyphPathMoveTo(FT_Vector *pt, void *path) { + ((SplashPath *)path)->moveTo(pt->x / 64.0, -pt->y / 64.0); + return 0; +} + +static int glyphPathLineTo(FT_Vector *pt, void *path) { + ((SplashPath *)path)->lineTo(pt->x / 64.0, -pt->y / 64.0); + return 0; +} + +static int glyphPathConicTo(FT_Vector *ctrl, FT_Vector *pt, void *path) { + SplashCoord x0, y0, x1, y1, x2, y2, x3, y3, xc, yc; + + if (!((SplashPath *)path)->getCurPt(&x0, &y0)) { + return 0; + } + xc = ctrl->x / 64.0; + yc = -ctrl->y / 64.0; + x3 = pt->x / 64.0; + y3 = -pt->y / 64.0; + + // 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 = (1.0 / 3.0) * (x0 + 2 * xc); + y1 = (1.0 / 3.0) * (y0 + 2 * yc); + x2 = (1.0 / 3.0) * (2 * xc + x3); + y2 = (1.0 / 3.0) * (2 * yc + y3); + + ((SplashPath *)path)->curveTo(x1, y1, x2, y2, x3, y3); + return 0; +} + +static int glyphPathCubicTo(FT_Vector *ctrl1, FT_Vector *ctrl2, + FT_Vector *pt, void *path) { + ((SplashPath *)path)->curveTo(ctrl1->x / 64.0, -ctrl1->y / 64.0, + ctrl2->x / 64.0, -ctrl2->y / 64.0, + pt->x / 64.0, -pt->y / 64.0); + return 0; +} + +#endif // HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H diff --git a/pdf/splash/SplashFTFont.h b/pdf/splash/SplashFTFont.h new file mode 100644 index 0000000..7628a2b --- /dev/null +++ b/pdf/splash/SplashFTFont.h @@ -0,0 +1,54 @@ +//======================================================================== +// +// SplashFTFont.h +// +//======================================================================== + +#ifndef SPLASHFTFONT_H +#define SPLASHFTFONT_H + +#include <aconf.h> + +#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include <freetype/freetype.h> +#include "SplashFont.h" + +class SplashFTFontFile; + +//------------------------------------------------------------------------ +// SplashFTFont +//------------------------------------------------------------------------ + +class SplashFTFont: public SplashFont { +public: + + SplashFTFont(SplashFTFontFile *fontFileA, SplashCoord *matA); + + virtual ~SplashFTFont(); + + // Munge xFrac and yFrac before calling SplashFont::getGlyph. + virtual GBool getGlyph(int c, int xFrac, int yFrac, + SplashGlyphBitmap *bitmap); + + // 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); + + // Return the path for a glyph. + virtual SplashPath *getGlyphPath(int c); + +private: + + FT_Size sizeObj; + FT_Matrix matrix; +}; + +#endif // HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H + +#endif diff --git a/pdf/splash/SplashFTFontEngine.cc b/pdf/splash/SplashFTFontEngine.cc new file mode 100644 index 0000000..64dbc75 --- /dev/null +++ b/pdf/splash/SplashFTFontEngine.cc @@ -0,0 +1,134 @@ +//======================================================================== +// +// SplashFTFontEngine.cc +// +//======================================================================== + +#include <aconf.h> + +#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include <stdio.h> +#ifndef WIN32 +# include <unistd.h> +#endif +#include "gmem.h" +#include "GString.h" +#include "gfile.h" +#include "FoFiTrueType.h" +#include "FoFiType1C.h" +#include "SplashFTFontFile.h" +#include "SplashFTFontEngine.h" + +#ifdef VMS +#if (__VMS_VER < 70000000) +extern "C" int unlink(char *filename); +#endif +#endif + +//------------------------------------------------------------------------ + +static void fileWrite(void *stream, char *data, int len) { + fwrite(data, 1, len, (FILE *)stream); +} + +//------------------------------------------------------------------------ +// SplashFTFontEngine +//------------------------------------------------------------------------ + +SplashFTFontEngine::SplashFTFontEngine(GBool aaA, FT_Library libA) { + aa = aaA; + lib = libA; +} + +SplashFTFontEngine *SplashFTFontEngine::init(GBool aaA) { + FT_Library libA; + + if (FT_Init_FreeType(&libA)) { + return NULL; + } + return new SplashFTFontEngine(aaA, libA); +} + +SplashFTFontEngine::~SplashFTFontEngine() { + FT_Done_FreeType(lib); +} + +SplashFontFile *SplashFTFontEngine::loadType1Font(SplashFontFileID *idA, + char *fileName, + GBool deleteFile, + char **enc) { + return SplashFTFontFile::loadType1Font(this, idA, fileName, deleteFile, enc); +} + +SplashFontFile *SplashFTFontEngine::loadType1CFont(SplashFontFileID *idA, + char *fileName, + GBool deleteFile, + char **enc) { + return SplashFTFontFile::loadType1Font(this, idA, fileName, deleteFile, enc); +} + +SplashFontFile *SplashFTFontEngine::loadCIDFont(SplashFontFileID *idA, + char *fileName, + GBool deleteFile) { + FoFiType1C *ff; + Gushort *cidToGIDMap; + int nCIDs; + SplashFontFile *ret; + + // check for a CFF font + if ((ff = FoFiType1C::load(fileName))) { + cidToGIDMap = ff->getCIDToGIDMap(&nCIDs); + delete ff; + } else { + cidToGIDMap = NULL; + nCIDs = 0; + } + ret = SplashFTFontFile::loadCIDFont(this, idA, fileName, deleteFile, + cidToGIDMap, nCIDs); + if (!ret) { + gfree(cidToGIDMap); + } + return ret; +} + +SplashFontFile *SplashFTFontEngine::loadTrueTypeFont(SplashFontFileID *idA, + char *fileName, + GBool deleteFile, + Gushort *codeToGID, + int codeToGIDLen) { + FoFiTrueType *ff; + GString *tmpFileName; + FILE *tmpFile; + SplashFontFile *ret; + + if (!(ff = FoFiTrueType::load(fileName))) { + return NULL; + } + tmpFileName = NULL; + if (!openTempFile(&tmpFileName, &tmpFile, "wb", NULL)) { + delete ff; + return NULL; + } + ff->writeTTF(&fileWrite, tmpFile); + delete ff; + fclose(tmpFile); + ret = SplashFTFontFile::loadTrueTypeFont(this, idA, + tmpFileName->getCString(), + gTrue, codeToGID, codeToGIDLen); + if (ret) { + if (deleteFile) { + unlink(fileName); + } + } else { + unlink(tmpFileName->getCString()); + } + delete tmpFileName; + return ret; +} + +#endif // HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H diff --git a/pdf/splash/SplashFTFontEngine.h b/pdf/splash/SplashFTFontEngine.h new file mode 100644 index 0000000..0497a46 --- /dev/null +++ b/pdf/splash/SplashFTFontEngine.h @@ -0,0 +1,59 @@ +//======================================================================== +// +// SplashFTFontEngine.h +// +//======================================================================== + +#ifndef SPLASHFTFONTENGINE_H +#define SPLASHFTFONTENGINE_H + +#include <aconf.h> + +#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include <freetype/freetype.h> +#include "gtypes.h" + +class SplashFontFile; +class SplashFontFileID; + +//------------------------------------------------------------------------ +// SplashFTFontEngine +//------------------------------------------------------------------------ + +class SplashFTFontEngine { +public: + + static SplashFTFontEngine *init(GBool aaA); + + ~SplashFTFontEngine(); + + // Load fonts. + SplashFontFile *loadType1Font(SplashFontFileID *idA, char *fileName, + GBool deleteFile, char **enc); + SplashFontFile *loadType1CFont(SplashFontFileID *idA, char *fileName, + GBool deleteFile, char **enc); + SplashFontFile *loadCIDFont(SplashFontFileID *idA, char *fileName, + GBool deleteFile); + SplashFontFile *loadTrueTypeFont(SplashFontFileID *idA, char *fileName, + GBool deleteFile, + Gushort *codeToGID, int codeToGIDLen); + +private: + + SplashFTFontEngine(GBool aaA, FT_Library libA); + + GBool aa; + FT_Library lib; + + friend class SplashFTFontFile; + friend class SplashFTFont; +}; + +#endif // HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H + +#endif diff --git a/pdf/splash/SplashFTFontFile.cc b/pdf/splash/SplashFTFontFile.cc new file mode 100644 index 0000000..a750966 --- /dev/null +++ b/pdf/splash/SplashFTFontFile.cc @@ -0,0 +1,111 @@ +//======================================================================== +// +// SplashFTFontFile.cc +// +//======================================================================== + +#include <aconf.h> + +#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include "gmem.h" +#include "SplashFTFontEngine.h" +#include "SplashFTFont.h" +#include "SplashFTFontFile.h" + +//------------------------------------------------------------------------ +// SplashFTFontFile +//------------------------------------------------------------------------ + +SplashFontFile *SplashFTFontFile::loadType1Font(SplashFTFontEngine *engineA, + SplashFontFileID *idA, + char *fileNameA, + GBool deleteFileA, + char **encA) { + FT_Face faceA; + Gushort *codeToGIDA; + char *name; + int i; + + if (FT_New_Face(engineA->lib, fileNameA, 0, &faceA)) { + return NULL; + } + codeToGIDA = (Gushort *)gmalloc(256 * sizeof(int)); + for (i = 0; i < 256; ++i) { + codeToGIDA[i] = 0; + if ((name = encA[i])) { + codeToGIDA[i] = (Gushort)FT_Get_Name_Index(faceA, name); + } + } + + return new SplashFTFontFile(engineA, idA, fileNameA, deleteFileA, + faceA, codeToGIDA, 256); +} + +SplashFontFile *SplashFTFontFile::loadCIDFont(SplashFTFontEngine *engineA, + SplashFontFileID *idA, + char *fileNameA, + GBool deleteFileA, + Gushort *codeToGIDA, + int codeToGIDLenA) { + FT_Face faceA; + + if (FT_New_Face(engineA->lib, fileNameA, 0, &faceA)) { + return NULL; + } + + return new SplashFTFontFile(engineA, idA, fileNameA, deleteFileA, + faceA, codeToGIDA, codeToGIDLenA); +} + +SplashFontFile *SplashFTFontFile::loadTrueTypeFont(SplashFTFontEngine *engineA, + SplashFontFileID *idA, + char *fileNameA, + GBool deleteFileA, + Gushort *codeToGIDA, + int codeToGIDLenA) { + FT_Face faceA; + + if (FT_New_Face(engineA->lib, fileNameA, 0, &faceA)) { + return NULL; + } + + return new SplashFTFontFile(engineA, idA, fileNameA, deleteFileA, + faceA, codeToGIDA, codeToGIDLenA); +} + +SplashFTFontFile::SplashFTFontFile(SplashFTFontEngine *engineA, + SplashFontFileID *idA, + char *fileNameA, GBool deleteFileA, + FT_Face faceA, + Gushort *codeToGIDA, int codeToGIDLenA): + SplashFontFile(idA, fileNameA, deleteFileA) +{ + engine = engineA; + face = faceA; + codeToGID = codeToGIDA; + codeToGIDLen = codeToGIDLenA; +} + +SplashFTFontFile::~SplashFTFontFile() { + if (face) { + FT_Done_Face(face); + } + if (codeToGID) { + gfree(codeToGID); + } +} + +SplashFont *SplashFTFontFile::makeFont(SplashCoord *mat) { + SplashFont *font; + + font = new SplashFTFont(this, mat); + font->initCache(); + return font; +} + +#endif // HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H diff --git a/pdf/splash/SplashFTFontFile.h b/pdf/splash/SplashFTFontFile.h new file mode 100644 index 0000000..522d055 --- /dev/null +++ b/pdf/splash/SplashFTFontFile.h @@ -0,0 +1,69 @@ +//======================================================================== +// +// SplashFTFontFile.h +// +//======================================================================== + +#ifndef SPLASHFTFONTFILE_H +#define SPLASHFTFONTFILE_H + +#include <aconf.h> + +#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include <freetype/freetype.h> +#include "SplashFontFile.h" + +class SplashFontFileID; +class SplashFTFontEngine; + +//------------------------------------------------------------------------ +// SplashFTFontFile +//------------------------------------------------------------------------ + +class SplashFTFontFile: public SplashFontFile { +public: + + static SplashFontFile *loadType1Font(SplashFTFontEngine *engineA, + SplashFontFileID *idA, char *fileNameA, + GBool deleteFileA, char **encA); + static SplashFontFile *loadCIDFont(SplashFTFontEngine *engineA, + SplashFontFileID *idA, char *fileNameA, + GBool deleteFileA, + Gushort *codeToCIDA, int codeToGIDLenA); + static SplashFontFile *loadTrueTypeFont(SplashFTFontEngine *engineA, + SplashFontFileID *idA, + char *fileNameA, + GBool deleteFileA, + Gushort *codeToGIDA, + int codeToGIDLenA); + + virtual ~SplashFTFontFile(); + + // Create a new SplashFTFont, i.e., a scaled instance of this font + // file. + virtual SplashFont *makeFont(SplashCoord *mat); + +private: + + SplashFTFontFile(SplashFTFontEngine *engineA, + SplashFontFileID *idA, + char *fileNameA, GBool deleteFileA, + FT_Face faceA, + Gushort *codeToGIDA, int codeToGIDLenA); + + SplashFTFontEngine *engine; + FT_Face face; + Gushort *codeToGID; + int codeToGIDLen; + + friend class SplashFTFont; +}; + +#endif // HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H + +#endif diff --git a/pdf/splash/SplashFont.cc b/pdf/splash/SplashFont.cc new file mode 100644 index 0000000..461c981 --- /dev/null +++ b/pdf/splash/SplashFont.cc @@ -0,0 +1,166 @@ +//======================================================================== +// +// SplashFont.cc +// +//======================================================================== + +#include <aconf.h> + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include <string.h> +#include "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, + GBool aaA) { + fontFile = fontFileA; + fontFile->incRefCnt(); + mat[0] = matA[0]; + mat[1] = matA[1]; + mat[2] = matA[2]; + mat[3] = matA[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 (aa) { + glyphSize = glyphW * glyphH; + } else { + glyphSize = ((glyphW + 7) >> 3) * glyphH; + } + + // set up the glyph pixmap cache + cacheAssoc = 8; + if (glyphSize <= 256) { + cacheSets = 8; + } else if (glyphSize <= 512) { + cacheSets = 4; + } else if (glyphSize <= 1024) { + cacheSets = 2; + } else { + cacheSets = 1; + } + cache = (Guchar *)gmalloc(cacheSets * cacheAssoc * glyphSize); + cacheTags = (SplashFontCacheTag *)gmalloc(cacheSets * cacheAssoc * + sizeof(SplashFontCacheTag)); + for (i = 0; i < cacheSets * cacheAssoc; ++i) { + cacheTags[i].mru = i & (cacheAssoc - 1); + } +} + +SplashFont::~SplashFont() { + fontFile->decRefCnt(); + if (cache) { + gfree(cache); + } + if (cacheTags) { + gfree(cacheTags); + } +} + +GBool SplashFont::getGlyph(int c, int xFrac, int yFrac, + SplashGlyphBitmap *bitmap) { + SplashGlyphBitmap bitmap2; + int size; + Guchar *p; + int i, j, k; + + // 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; + return gTrue; + } + } + + // generate the glyph bitmap + if (!makeGlyph(c, xFrac, yFrac, &bitmap2)) { + return gFalse; + } + + // 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 + 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/pdf/splash/SplashFont.h b/pdf/splash/SplashFont.h new file mode 100644 index 0000000..49e36c2 --- /dev/null +++ b/pdf/splash/SplashFont.h @@ -0,0 +1,89 @@ +//======================================================================== +// +// SplashFont.h +// +//======================================================================== + +#ifndef SPLASHFONT_H +#define SPLASHFONT_H + +#include <aconf.h> + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "gtypes.h" +#include "SplashTypes.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 (1 / (SplashCoord)splashFontFraction) + +//------------------------------------------------------------------------ +// SplashFont +//------------------------------------------------------------------------ + +class SplashFont { +public: + + SplashFont(SplashFontFile *fontFileA, SplashCoord *matA, 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) { + return fontFileA == fontFile && + matA[0] == mat[0] && matA[1] == mat[1] && + matA[2] == mat[2] && matA[3] == mat[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); + + // 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) = 0; + + // Return the path for a glyph. + virtual SplashPath *getGlyphPath(int c) = 0; + +protected: + + SplashFontFile *fontFile; + SplashCoord mat[4]; // font transform matrix + 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/pdf/splash/SplashFontEngine.cc b/pdf/splash/SplashFontEngine.cc new file mode 100644 index 0000000..b8aef70 --- /dev/null +++ b/pdf/splash/SplashFontEngine.cc @@ -0,0 +1,245 @@ +//======================================================================== +// +// SplashFontEngine.cc +// +//======================================================================== + +#include <aconf.h> + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#if HAVE_T1LIB_H +#include <t1lib.h> +#endif + +#include <stdlib.h> +#include <stdio.h> +#ifndef WIN32 +# include <unistd.h> +#endif +#include "gmem.h" +#include "GString.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 + +//------------------------------------------------------------------------ +// SplashFontEngine +//------------------------------------------------------------------------ + +SplashFontEngine::SplashFontEngine( +#if HAVE_T1LIB_H + GBool enableT1lib, +#endif +#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H + GBool enableFreeType, +#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); + } 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, + char *fileName, + GBool deleteFile, char **enc) { + SplashFontFile *fontFile; + + fontFile = NULL; +#if HAVE_T1LIB_H + if (!fontFile && t1Engine) { + fontFile = t1Engine->loadType1Font(idA, fileName, deleteFile, enc); + } +#endif +#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H + if (!fontFile && ftEngine) { + fontFile = ftEngine->loadType1Font(idA, fileName, deleteFile, 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 (deleteFile) { + unlink(fontFile ? fontFile->fileName->getCString() : fileName); + } + + return fontFile; +} + +SplashFontFile *SplashFontEngine::loadType1CFont(SplashFontFileID *idA, + char *fileName, + GBool deleteFile, + char **enc) { + SplashFontFile *fontFile; + + fontFile = NULL; +#if HAVE_T1LIB_H + if (!fontFile && t1Engine) { + fontFile = t1Engine->loadType1CFont(idA, fileName, deleteFile, enc); + } +#endif +#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H + if (!fontFile && ftEngine) { + fontFile = ftEngine->loadType1CFont(idA, fileName, deleteFile, 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 (deleteFile) { + unlink(fontFile ? fontFile->fileName->getCString() : fileName); + } + + return fontFile; +} + +SplashFontFile *SplashFontEngine::loadCIDFont(SplashFontFileID *idA, + char *fileName, + GBool deleteFile) { + SplashFontFile *fontFile; + + fontFile = NULL; +#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H + if (!fontFile && ftEngine) { + fontFile = ftEngine->loadCIDFont(idA, fileName, deleteFile); + } +#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 (deleteFile) { + unlink(fontFile ? fontFile->fileName->getCString() : fileName); + } + + return fontFile; +} + +SplashFontFile *SplashFontEngine::loadTrueTypeFont(SplashFontFileID *idA, + char *fileName, + GBool deleteFile, + Gushort *codeToGID, + int codeToGIDLen) { + SplashFontFile *fontFile; + + fontFile = NULL; +#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H + if (!fontFile && ftEngine) { + fontFile = ftEngine->loadTrueTypeFont(idA, fileName, deleteFile, + codeToGID, codeToGIDLen); + } +#endif + + if (!fontFile) { + gfree(codeToGID); + } + + // 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 (deleteFile) { + unlink(fontFile ? fontFile->fileName->getCString() : fileName); + } + + return fontFile; +} + +SplashFont *SplashFontEngine::getFont(SplashFontFile *fontFile, + SplashCoord *mat) { + SplashFont *font; + int i, j; + + font = fontCache[0]; + if (font && font->matches(fontFile, mat)) { + return font; + } + for (i = 1; i < splashFontCacheSize; ++i) { + font = fontCache[i]; + if (font && font->matches(fontFile, mat)) { + for (j = i; j > 0; --j) { + fontCache[j] = fontCache[j-1]; + } + fontCache[0] = font; + return font; + } + } + font = fontFile->makeFont(mat); + 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/pdf/splash/SplashFontEngine.h b/pdf/splash/SplashFontEngine.h new file mode 100644 index 0000000..2548221 --- /dev/null +++ b/pdf/splash/SplashFontEngine.h @@ -0,0 +1,85 @@ +//======================================================================== +// +// SplashFontEngine.h +// +//======================================================================== + +#ifndef SPLASHFONTENGINE_H +#define SPLASHFONTENGINE_H + +#include <aconf.h> + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "gtypes.h" + +class SplashT1FontEngine; +class SplashFTFontEngine; +class SplashDTFontEngine; +class SplashFontFile; +class SplashFontFileID; +class SplashFont; + +//------------------------------------------------------------------------ + +#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, +#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, char *fileName, + GBool deleteFile, char **enc); + SplashFontFile *loadType1CFont(SplashFontFileID *idA, char *fileName, + GBool deleteFile, char **enc); + SplashFontFile *loadCIDFont(SplashFontFileID *idA, char *fileName, + GBool deleteFile); + SplashFontFile *loadTrueTypeFont(SplashFontFileID *idA, char *fileName, + GBool deleteFile, + Gushort *codeToGID, int codeToGIDLen); + + // 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[0] mat[1] ] + // [ mat[2] mat[3] ] + // specifies the font transform in PostScript style: + // [x' y'] = [x y] * mat + // Note that the Splash y axis points downward. + SplashFont *getFont(SplashFontFile *fontFile, SplashCoord *mat); + +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/pdf/splash/SplashFontFile.cc b/pdf/splash/SplashFontFile.cc new file mode 100644 index 0000000..acbc12a --- /dev/null +++ b/pdf/splash/SplashFontFile.cc @@ -0,0 +1,55 @@ +//======================================================================== +// +// SplashFontFile.cc +// +//======================================================================== + +#include <aconf.h> + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include <stdio.h> +#ifndef WIN32 +# include <unistd.h> +#endif +#include "GString.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, char *fileNameA, + GBool deleteFileA) { + id = idA; + fileName = new GString(fileNameA); + deleteFile = deleteFileA; + refCnt = 0; +} + +SplashFontFile::~SplashFontFile() { + if (deleteFile) { + unlink(fileName->getCString()); + } + delete fileName; + delete id; +} + +void SplashFontFile::incRefCnt() { + ++refCnt; +} + +void SplashFontFile::decRefCnt() { + if (!--refCnt) { + delete this; + } +} diff --git a/pdf/splash/SplashFontFile.h b/pdf/splash/SplashFontFile.h new file mode 100644 index 0000000..2fe1def --- /dev/null +++ b/pdf/splash/SplashFontFile.h @@ -0,0 +1,60 @@ +//======================================================================== +// +// SplashFontFile.h +// +//======================================================================== + +#ifndef SPLASHFONTFILE_H +#define SPLASHFONTFILE_H + +#include <aconf.h> + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "gtypes.h" +#include "SplashTypes.h" + +class GString; +class SplashFontEngine; +class SplashFont; +class SplashFontFileID; + +//------------------------------------------------------------------------ +// SplashFontFile +//------------------------------------------------------------------------ + +class SplashFontFile { +public: + + virtual ~SplashFontFile(); + + // Create a new SplashFont, i.e., a scaled instance of this font + // file. + virtual SplashFont *makeFont(SplashCoord *mat) = 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(); + +protected: + + SplashFontFile(SplashFontFileID *idA, char *fileNameA, + GBool deleteFileA); + + SplashFontFileID *id; + GString *fileName; + GBool deleteFile; + int refCnt; + + friend class SplashFontEngine; +}; + +#endif diff --git a/pdf/splash/SplashFontFileID.cc b/pdf/splash/SplashFontFileID.cc new file mode 100644 index 0000000..af37cb2 --- /dev/null +++ b/pdf/splash/SplashFontFileID.cc @@ -0,0 +1,23 @@ +//======================================================================== +// +// SplashFontFileID.cc +// +//======================================================================== + +#include <aconf.h> + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include "SplashFontFileID.h" + +//------------------------------------------------------------------------ +// SplashFontFileID +//------------------------------------------------------------------------ + +SplashFontFileID::SplashFontFileID() { +} + +SplashFontFileID::~SplashFontFileID() { +} diff --git a/pdf/splash/SplashFontFileID.h b/pdf/splash/SplashFontFileID.h new file mode 100644 index 0000000..bed11d3 --- /dev/null +++ b/pdf/splash/SplashFontFileID.h @@ -0,0 +1,30 @@ +//======================================================================== +// +// SplashFontFileID.h +// +//======================================================================== + +#ifndef SPLASHFONTFILEID_H +#define SPLASHFONTFILEID_H + +#include <aconf.h> + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "gtypes.h" + +//------------------------------------------------------------------------ +// SplashFontFileID +//------------------------------------------------------------------------ + +class SplashFontFileID { +public: + + SplashFontFileID(); + virtual ~SplashFontFileID(); + virtual GBool matches(SplashFontFileID *id) = 0; +}; + +#endif diff --git a/pdf/splash/SplashGlyphBitmap.h b/pdf/splash/SplashGlyphBitmap.h new file mode 100644 index 0000000..044ba4a --- /dev/null +++ b/pdf/splash/SplashGlyphBitmap.h @@ -0,0 +1,26 @@ +//======================================================================== +// +// SplashGlyphBitmap.h +// +//======================================================================== + +#ifndef SPLASHGLYPHBITMAP_H +#define SPLASHGLYPHBITMAP_H + +#include <aconf.h> + +#include "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/pdf/splash/SplashMath.h b/pdf/splash/SplashMath.h new file mode 100644 index 0000000..f1bde14 --- /dev/null +++ b/pdf/splash/SplashMath.h @@ -0,0 +1,46 @@ +//======================================================================== +// +// SplashMath.h +// +//======================================================================== + +#ifndef SPLASHMATH_H +#define SPLASHMATH_H + +#include <aconf.h> +#include <math.h> +#include "SplashTypes.h" + +static inline SplashCoord splashAbs(SplashCoord x) { + return fabs(x); +} + +static inline int splashFloor(SplashCoord x) { + return (int)floor(x); +} + +static inline int splashCeil(SplashCoord x) { + return (int)ceil(x); +} + +static inline int splashRound(SplashCoord x) { + return (int)floor(x + 0.5); +} + +static inline SplashCoord splashSqrt(SplashCoord x) { + return sqrt(x); +} + +static inline SplashCoord splashPow(SplashCoord x, SplashCoord y) { + return pow(x, y); +} + +static inline SplashCoord splashDist(SplashCoord x0, SplashCoord y0, + SplashCoord x1, SplashCoord y1) { + SplashCoord dx, dy; + dx = x1 - x0; + dy = y1 - y0; + return sqrt(dx * dx + dy * dy); +} + +#endif diff --git a/pdf/splash/SplashPath.cc b/pdf/splash/SplashPath.cc new file mode 100644 index 0000000..465990f --- /dev/null +++ b/pdf/splash/SplashPath.cc @@ -0,0 +1,177 @@ +//======================================================================== +// +// SplashPath.cc +// +//======================================================================== + +#include <aconf.h> + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include <string.h> +#include "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; +} + +SplashPath::SplashPath(SplashPath *path) { + length = path->length; + size = path->size; + pts = (SplashPathPoint *)gmalloc(size * sizeof(SplashPathPoint)); + flags = (Guchar *)gmalloc(size * sizeof(Guchar)); + memcpy(pts, path->pts, length * sizeof(SplashPathPoint)); + memcpy(flags, path->flags, length * sizeof(Guchar)); + curSubpath = path->curSubpath; +} + +SplashPath::~SplashPath() { + gfree(pts); + gfree(flags); +} + +// 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 *)grealloc(pts, size * sizeof(SplashPathPoint)); + flags = (Guchar *)grealloc(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::arcCWTo(SplashCoord x1, SplashCoord y1, + SplashCoord xc, SplashCoord yc) { + if (noCurrentPoint()) { + return splashErrNoCurPt; + } + flags[length-1] &= ~splashPathLast; + grow(2); + pts[length].x = xc; + pts[length].y = yc; + flags[length] = splashPathArcCW; + ++length; + pts[length].x = x1; + pts[length].y = y1; + flags[length] = splashPathLast; + ++length; + return splashOk; +} + +SplashError SplashPath::close() { + if (noCurrentPoint()) { + return splashErrNoCurPt; + } + if (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::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/pdf/splash/SplashPath.h b/pdf/splash/SplashPath.h new file mode 100644 index 0000000..8aa1a8b --- /dev/null +++ b/pdf/splash/SplashPath.h @@ -0,0 +1,107 @@ +//======================================================================== +// +// SplashPath.h +// +//======================================================================== + +#ifndef SPLASHPATH_H +#define SPLASHPATH_H + +#include <aconf.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 + +// clockwise arc center points set this flag +#define splashPathArcCW 0x10 + +//------------------------------------------------------------------------ +// 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); + + // Add a clockwise circular arc with center (xc, yc) and endpoint + // (x1, y1). + SplashError arcCWTo(SplashCoord x1, SplashCoord y1, + SplashCoord xc, SplashCoord yc); + + // Close the last subpath, adding a line segment if necessary. + SplashError close(); + + // Add (<dx>, <dy>) to every point on this path. + void offset(SplashCoord dx, SplashCoord dy); + + // Get the current point. + GBool getCurPt(SplashCoord *x, SplashCoord *y); + +private: + + 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 + + friend class SplashXPath; + friend class Splash; +}; + +#endif diff --git a/pdf/splash/SplashPattern.cc b/pdf/splash/SplashPattern.cc new file mode 100644 index 0000000..1cbd8a9 --- /dev/null +++ b/pdf/splash/SplashPattern.cc @@ -0,0 +1,64 @@ +//======================================================================== +// +// SplashPattern.cc +// +//======================================================================== + +#include <aconf.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(SplashColor colorA) { + color = colorA; +} + +SplashSolidColor::~SplashSolidColor() { +} + +SplashColor SplashSolidColor::getColor(int x, int y) { + return color; +} + +//------------------------------------------------------------------------ +// SplashHalftone +//------------------------------------------------------------------------ + +SplashHalftone::SplashHalftone(SplashColor color0A, SplashColor color1A, + SplashScreen *screenA, SplashCoord valueA) { + color0 = color0A; + color1 = color1A; + screen = screenA; + value = valueA; +} + +SplashPattern *SplashHalftone::copy() { + return new SplashHalftone(color0, color1, screen->copy(), value); +} + +SplashHalftone::~SplashHalftone() { + delete screen; +} + +SplashColor SplashHalftone::getColor(int x, int y) { + return screen->test(x, y, value) ? color1 : color0; +} diff --git a/pdf/splash/SplashPattern.h b/pdf/splash/SplashPattern.h new file mode 100644 index 0000000..4bf4477 --- /dev/null +++ b/pdf/splash/SplashPattern.h @@ -0,0 +1,81 @@ +//======================================================================== +// +// SplashPattern.h +// +//======================================================================== + +#ifndef SPLASHPATTERN_H +#define SPLASHPATTERN_H + +#include <aconf.h> + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "SplashTypes.h" + +class SplashScreen; + +//------------------------------------------------------------------------ +// SplashPattern +//------------------------------------------------------------------------ + +class SplashPattern { +public: + + SplashPattern(); + + virtual SplashPattern *copy() = 0; + + virtual ~SplashPattern(); + + virtual SplashColor getColor(int x, int y) = 0; + +private: +}; + +//------------------------------------------------------------------------ +// SplashSolidColor +//------------------------------------------------------------------------ + +class SplashSolidColor: public SplashPattern { +public: + + SplashSolidColor(SplashColor colorA); + + virtual SplashPattern *copy() { return new SplashSolidColor(color); } + + virtual ~SplashSolidColor(); + + virtual SplashColor getColor(int x, int y); + +private: + + SplashColor color; +}; + +//------------------------------------------------------------------------ +// SplashHalftone +//------------------------------------------------------------------------ + +class SplashHalftone: public SplashPattern { +public: + + SplashHalftone(SplashColor color0A, SplashColor color1A, + SplashScreen *screenA, SplashCoord valueA); + + virtual SplashPattern *copy(); + + virtual ~SplashHalftone(); + + virtual SplashColor getColor(int x, int y); + +private: + + SplashColor color0, color1; + SplashScreen *screen; + SplashCoord value; +}; + +#endif diff --git a/pdf/splash/SplashScreen.cc b/pdf/splash/SplashScreen.cc new file mode 100644 index 0000000..4230856 --- /dev/null +++ b/pdf/splash/SplashScreen.cc @@ -0,0 +1,107 @@ +//======================================================================== +// +// SplashScreen.cc +// +//======================================================================== + +#include <aconf.h> + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include "gmem.h" +#include "SplashMath.h" +#include "SplashScreen.h" + +//------------------------------------------------------------------------ +// SplashScreen +//------------------------------------------------------------------------ + +// This generates a 45 degree screen using a circular dot spot +// function. DPI = resolution / ((size / 2) * sqrt(2)). +// Gamma correction (gamma = 1 / 1.33) is also computed here. +SplashScreen::SplashScreen(int sizeA) { + SplashCoord *dist; + SplashCoord u, v, d; + int x, y, x1, y1, i; + + size = sizeA >> 1; + if (size < 1) { + size = 1; + } + + // initialize the threshold matrix + mat = (SplashCoord *)gmalloc(2 * size * size * sizeof(SplashCoord)); + for (y = 0; y < 2 * size; ++y) { + for (x = 0; x < size; ++x) { + mat[y * size + x] = -1; + } + } + + // build the distance matrix + dist = (SplashCoord *)gmalloc(2 * size * size * sizeof(SplashCoord)); + for (y = 0; y < size; ++y) { + for (x = 0; x < size; ++x) { + if (x + y < size - 1) { + u = (SplashCoord)x + 0.5 - 0; //~ (-0.5); + v = (SplashCoord)y + 0.5 - 0; + } else { + u = (SplashCoord)x + 0.5 - (SplashCoord)size; //~ ((SplashCoord)size - 0.5); + v = (SplashCoord)y + 0.5 - (SplashCoord)size; + } + dist[y * size + x] = u*u + v*v; + } + } + for (y = 0; y < size; ++y) { + for (x = 0; x < size; ++x) { + if (x < y) { + u = (SplashCoord)x + 0.5 - 0; //~ (-0.5); + v = (SplashCoord)y + 0.5 - (SplashCoord)size; + } else { + u = (SplashCoord)x + 0.5 - (SplashCoord)size; //~ ((SplashCoord)size - 0.5); + v = (SplashCoord)y + 0.5 - 0; + } + dist[(size + y) * size + x] = u*u + v*v; + } + } + + // build the threshold matrix + x1 = y1 = 0; // make gcc happy + for (i = 1; i <= 2 * size * size; ++i) { + d = 2 * size * size; + for (y = 0; y < 2 * size; ++y) { + for (x = 0; x < size; ++x) { + if (mat[y * size + x] < 0 && + dist[y * size + x] < d) { + x1 = x; + y1 = y; + d = dist[y1 * size + x1]; + } + } + } + u = 1.0 - (SplashCoord)i / (SplashCoord)(2 * size * size + 1); + mat[y1 * size + x1] = splashPow(u, 1.33); + } + + gfree(dist); +} + +SplashScreen::~SplashScreen() { + gfree(mat); +} + +int SplashScreen::test(int x, int y, SplashCoord value) { + SplashCoord *mat1; + int xx, yy; + + xx = x % (2 * size); + yy = y % (2 * size); + mat1 = mat; + if ((xx / size) ^ (yy / size)) { + mat1 += size * size; + } + xx %= size; + yy %= size; + return value < mat1[yy * size + xx] ? 0 : 1; +} diff --git a/pdf/splash/SplashScreen.h b/pdf/splash/SplashScreen.h new file mode 100644 index 0000000..33024bb --- /dev/null +++ b/pdf/splash/SplashScreen.h @@ -0,0 +1,40 @@ +//======================================================================== +// +// SplashScreen.h +// +//======================================================================== + +#ifndef SPLASHSCREEN_H +#define SPLASHSCREEN_H + +#include <aconf.h> + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "SplashTypes.h" + +//------------------------------------------------------------------------ +// SplashScreen +//------------------------------------------------------------------------ + +class SplashScreen { +public: + + SplashScreen(int sizeA); + ~SplashScreen(); + + SplashScreen *copy() { return new SplashScreen(size << 1); } + + // Return the computed pixel value (0=black, 1=white) for the gray + // level <value> at (<x>, <y>). + int test(int x, int y, SplashCoord value); + +private: + + SplashCoord *mat; // threshold matrix + int size; // size of the threshold matrix +}; + +#endif diff --git a/pdf/splash/SplashState.cc b/pdf/splash/SplashState.cc new file mode 100644 index 0000000..7d5dc83 --- /dev/null +++ b/pdf/splash/SplashState.cc @@ -0,0 +1,99 @@ +//======================================================================== +// +// SplashState.cc +// +//======================================================================== + +#include <aconf.h> + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include <string.h> +#include "gmem.h" +#include "SplashPattern.h" +#include "SplashScreen.h" +#include "SplashClip.h" +#include "SplashState.h" + +//------------------------------------------------------------------------ +// SplashState +//------------------------------------------------------------------------ + +SplashState::SplashState(int width, int height) { + SplashColor color; + + memset(&color, 0, sizeof(SplashColor)); + strokePattern = new SplashSolidColor(color); + fillPattern = new SplashSolidColor(color); + screen = new SplashScreen(10); + lineWidth = 0; + lineCap = splashLineCapButt; + lineJoin = splashLineJoinMiter; + miterLimit = 10; + flatness = 1; + lineDash = NULL; + lineDashLength = 0; + lineDashPhase = 0; + clip = new SplashClip(0, 0, width - 1, height - 1); + next = NULL; +} + +SplashState::SplashState(SplashState *state) { + strokePattern = state->strokePattern->copy(); + fillPattern = state->fillPattern->copy(); + screen = state->screen->copy(); + lineWidth = state->lineWidth; + lineCap = state->lineCap; + lineJoin = state->lineJoin; + miterLimit = state->miterLimit; + flatness = state->flatness; + if (state->lineDash) { + lineDashLength = state->lineDashLength; + lineDash = (SplashCoord *)gmalloc(lineDashLength * sizeof(SplashCoord)); + memcpy(lineDash, state->lineDash, lineDashLength * sizeof(SplashCoord)); + } else { + lineDash = NULL; + lineDashLength = 0; + } + lineDashPhase = state->lineDashPhase; + clip = state->clip->copy(); + next = NULL; +} + +SplashState::~SplashState() { + delete strokePattern; + delete fillPattern; + delete screen; + gfree(lineDash); + delete clip; +} + +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 *)gmalloc(lineDashLength * sizeof(SplashCoord)); + memcpy(lineDash, lineDashA, lineDashLength * sizeof(SplashCoord)); + } else { + lineDash = NULL; + } + lineDashPhase = lineDashPhaseA; +} diff --git a/pdf/splash/SplashState.h b/pdf/splash/SplashState.h new file mode 100644 index 0000000..8fcb54b --- /dev/null +++ b/pdf/splash/SplashState.h @@ -0,0 +1,88 @@ +//======================================================================== +// +// SplashState.h +// +//======================================================================== + +#ifndef SPLASHSTATE_H +#define SPLASHSTATE_H + +#include <aconf.h> + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "SplashTypes.h" + +class SplashPattern; +class SplashScreen; +class SplashClip; + +//------------------------------------------------------------------------ +// 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); + + // 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); + +private: + + SplashState(SplashState *state); + + SplashPattern *strokePattern; + SplashPattern *fillPattern; + SplashScreen *screen; + SplashCoord lineWidth; + int lineCap; + int lineJoin; + SplashCoord miterLimit; + SplashCoord flatness; + SplashCoord *lineDash; + int lineDashLength; + SplashCoord lineDashPhase; + SplashClip *clip; + + SplashState *next; // used by Splash class + + friend class Splash; +}; + +#endif diff --git a/pdf/splash/SplashT1Font.cc b/pdf/splash/SplashT1Font.cc new file mode 100644 index 0000000..8338aba --- /dev/null +++ b/pdf/splash/SplashT1Font.cc @@ -0,0 +1,251 @@ +//======================================================================== +// +// SplashT1Font.cc +// +//======================================================================== + +#include <aconf.h> + +#if HAVE_T1LIB_H + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include <stdlib.h> +#include <t1lib.h> +#include "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): + SplashFont(fontFileA, matA, ((SplashT1FontFile *)fontFileA)->engine->aa) +{ + T1_TMATRIX matrix; + BBox bbox; + SplashCoord bbx0, bby0, bbx1, bby1; + int x, y; + + t1libID = T1_CopyFont(fontFileA->t1libID); + + // compute font size + size = (float)splashSqrt(mat[2]*mat[2] + mat[3]*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 = mat[0] / size; + matrix.cxy = mat[1] / size; + matrix.cyx = mat[2] / size; + matrix.cyy = mat[3] / size; + T1_TransformFont(t1libID, &matrix); +} + +SplashT1Font::~SplashT1Font() { + T1_DeleteFont(t1libID); +} + +GBool SplashT1Font::getGlyph(int c, int xFrac, int yFrac, + SplashGlyphBitmap *bitmap) { + return SplashFont::getGlyph(c, 0, 0, bitmap); +} + +GBool SplashT1Font::makeGlyph(int c, int xFrac, int yFrac, + SplashGlyphBitmap *bitmap) { + 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; + } + + return gTrue; +} + +SplashPath *SplashT1Font::getGlyphPath(int c) { + SplashPath *path; + T1_OUTLINE *outline; + T1_PATHSEGMENT *seg; + T1_BEZIERSEGMENT *bez; + SplashCoord x, y, x1, y1; + + path = new SplashPath(); + outline = T1_GetCharOutline(t1libID, c, size, NULL); + x = 0; + y = 0; + for (seg = outline; seg; seg = seg->link) { + switch (seg->type) { + case T1_PATHTYPE_MOVE: + x += seg->dest.x / 65536.0; + y += seg->dest.y / 65536.0; + path->moveTo(x, y); + break; + case T1_PATHTYPE_LINE: + x += seg->dest.x / 65536.0; + y += seg->dest.y / 65536.0; + path->lineTo(x, y); + break; + case T1_PATHTYPE_BEZIER: + bez = (T1_BEZIERSEGMENT *)seg; + x1 = x + bez->dest.x / 65536.0; + y1 = y + bez->dest.y / 65536.0; + path->curveTo(x + bez->B.x / 65536.0, y + bez->B.y / 65536.0, + x + bez->C.x / 65536.0, y + bez->C.y / 65536.0, + x1, y1); + x = x1; + y = y1; + break; + } + } + T1_FreeOutline(outline); + return path; +} + +#endif // HAVE_T1LIB_H diff --git a/pdf/splash/SplashT1Font.h b/pdf/splash/SplashT1Font.h new file mode 100644 index 0000000..e745e07 --- /dev/null +++ b/pdf/splash/SplashT1Font.h @@ -0,0 +1,51 @@ +//======================================================================== +// +// SplashT1Font.h +// +//======================================================================== + +#ifndef SPLASHT1FONT_H +#define SPLASHT1FONT_H + +#include <aconf.h> + +#if HAVE_T1LIB_H + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "SplashFont.h" + +//------------------------------------------------------------------------ +// SplashT1Font +//------------------------------------------------------------------------ + +class SplashT1Font: public SplashFont { +public: + + SplashT1Font(SplashT1FontFile *fontFileA, SplashCoord *matA); + + virtual ~SplashT1Font(); + + // Munge xFrac and yFrac before calling SplashFont::getGlyph. + virtual GBool getGlyph(int c, int xFrac, int yFrac, + SplashGlyphBitmap *bitmap); + + // 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); + + // Return the path for a glyph. + virtual SplashPath *getGlyphPath(int c); + +private: + + int t1libID; // t1lib font ID + float size; +}; + +#endif // HAVE_T1LIB_H + +#endif diff --git a/pdf/splash/SplashT1FontEngine.cc b/pdf/splash/SplashT1FontEngine.cc new file mode 100644 index 0000000..a1c9342 --- /dev/null +++ b/pdf/splash/SplashT1FontEngine.cc @@ -0,0 +1,124 @@ +//======================================================================== +// +// SplashT1FontEngine.cc +// +//======================================================================== + +#include <aconf.h> + +#if HAVE_T1LIB_H + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include <stdlib.h> +#include <stdio.h> +#ifndef WIN32 +# include <unistd.h> +#endif +#include <t1lib.h> +#include "GString.h" +#include "gfile.h" +#include "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, 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, + char *fileName, + GBool deleteFile, + char **enc) { + return SplashT1FontFile::loadType1Font(this, idA, fileName, deleteFile, enc); +} + +SplashFontFile *SplashT1FontEngine::loadType1CFont(SplashFontFileID *idA, + char *fileName, + GBool deleteFile, + char **enc) { + FoFiType1C *ff; + GString *tmpFileName; + FILE *tmpFile; + SplashFontFile *ret; + + if (!(ff = FoFiType1C::load(fileName))) { + return NULL; + } + tmpFileName = NULL; + if (!openTempFile(&tmpFileName, &tmpFile, "wb", NULL)) { + delete ff; + return NULL; + } + ff->convertToType1(NULL, gTrue, &fileWrite, tmpFile); + delete ff; + fclose(tmpFile); + ret = SplashT1FontFile::loadType1Font(this, idA, tmpFileName->getCString(), + gTrue, enc); + if (ret) { + if (deleteFile) { + unlink(fileName); + } + } else { + unlink(tmpFileName->getCString()); + } + delete tmpFileName; + return ret; +} + +#endif // HAVE_T1LIB_H diff --git a/pdf/splash/SplashT1FontEngine.h b/pdf/splash/SplashT1FontEngine.h new file mode 100644 index 0000000..57a0448 --- /dev/null +++ b/pdf/splash/SplashT1FontEngine.h @@ -0,0 +1,53 @@ +//======================================================================== +// +// SplashT1FontEngine.h +// +//======================================================================== + +#ifndef SPLASHT1FONTENGINE_H +#define SPLASHT1FONTENGINE_H + +#include <aconf.h> + +#if HAVE_T1LIB_H + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "gtypes.h" + +class SplashFontFile; +class SplashFontFileID; + +//------------------------------------------------------------------------ +// SplashT1FontEngine +//------------------------------------------------------------------------ + +class SplashT1FontEngine { +public: + + static SplashT1FontEngine *init(GBool aaA); + + ~SplashT1FontEngine(); + + // Load fonts. + SplashFontFile *loadType1Font(SplashFontFileID *idA, char *fileName, + GBool deleteFile, char **enc); + SplashFontFile *loadType1CFont(SplashFontFileID *idA, char *fileName, + GBool deleteFile, 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/pdf/splash/SplashT1FontFile.cc b/pdf/splash/SplashT1FontFile.cc new file mode 100644 index 0000000..83eaec9 --- /dev/null +++ b/pdf/splash/SplashT1FontFile.cc @@ -0,0 +1,96 @@ +//======================================================================== +// +// SplashT1FontFile.cc +// +//======================================================================== + +#include <aconf.h> + +#if HAVE_T1LIB_H + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include <string.h> +#include <t1lib.h> +#include "gmem.h" +#include "SplashT1FontEngine.h" +#include "SplashT1Font.h" +#include "SplashT1FontFile.h" + +//------------------------------------------------------------------------ +// SplashT1FontFile +//------------------------------------------------------------------------ + +SplashFontFile *SplashT1FontFile::loadType1Font(SplashT1FontEngine *engineA, + SplashFontFileID *idA, + char *fileNameA, + GBool deleteFileA, + char **encA) { + int t1libIDA; + char **encTmp; + char *encStrTmp; + int encStrSize; + char *encPtr; + int i; + + // load the font file + if ((t1libIDA = T1_AddFont(fileNameA)) < 0) { + return NULL; + } + T1_LoadFont(t1libIDA); + + // reencode it + encStrSize = 0; + for (i = 0; i < 256; ++i) { + if (encA[i]) { + encStrSize += strlen(encA[i]) + 1; + } + } + encTmp = (char **)gmalloc(257 * sizeof(char *)); + encStrTmp = (char *)gmalloc(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, encTmp); + + return new SplashT1FontFile(engineA, idA, fileNameA, deleteFileA, + t1libIDA, encTmp, encStrTmp); +} + +SplashT1FontFile::SplashT1FontFile(SplashT1FontEngine *engineA, + SplashFontFileID *idA, + char *fileNameA, GBool deleteFileA, + int t1libIDA, char **encA, char *encStrA): + SplashFontFile(idA, fileNameA, deleteFileA) +{ + engine = engineA; + t1libID = t1libIDA; + enc = encA; + encStr = encStrA; +} + +SplashT1FontFile::~SplashT1FontFile() { + gfree(encStr); + gfree(enc); + T1_DeleteFont(t1libID); +} + +SplashFont *SplashT1FontFile::makeFont(SplashCoord *mat) { + SplashFont *font; + + font = new SplashT1Font(this, mat); + font->initCache(); + return font; +} + +#endif // HAVE_T1LIB_H diff --git a/pdf/splash/SplashT1FontFile.h b/pdf/splash/SplashT1FontFile.h new file mode 100644 index 0000000..c220c04 --- /dev/null +++ b/pdf/splash/SplashT1FontFile.h @@ -0,0 +1,57 @@ +//======================================================================== +// +// SplashT1FontFile.h +// +//======================================================================== + +#ifndef SPLASHT1FONTFILE_H +#define SPLASHT1FONTFILE_H + +#include <aconf.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, + char *fileNameA, GBool deleteFileA, + char **encA); + + virtual ~SplashT1FontFile(); + + // Create a new SplashT1Font, i.e., a scaled instance of this font + // file. + virtual SplashFont *makeFont(SplashCoord *mat); + +private: + + SplashT1FontFile(SplashT1FontEngine *engineA, + SplashFontFileID *idA, + char *fileNameA, GBool deleteFileA, + int t1libIDA, char **encA, char *encStrA); + + SplashT1FontEngine *engine; + int t1libID; // t1lib font ID + char **enc; + char *encStr; + + friend class SplashT1Font; +}; + +#endif // HAVE_T1LIB_H + +#endif diff --git a/pdf/splash/SplashTypes.h b/pdf/splash/SplashTypes.h new file mode 100644 index 0000000..91b120f --- /dev/null +++ b/pdf/splash/SplashTypes.h @@ -0,0 +1,77 @@ +//======================================================================== +// +// SplashTypes.h +// +//======================================================================== + +#ifndef SPLASHTYPES_H +#define SPLASHTYPES_H + +#include <aconf.h> +#include "gtypes.h" + +//------------------------------------------------------------------------ +// coordinates +//------------------------------------------------------------------------ + +typedef double SplashCoord; + +//------------------------------------------------------------------------ +// colors +//------------------------------------------------------------------------ + +enum SplashColorMode { + splashModeMono1, + splashModeMono8, + splashModeRGB8, + splashModeBGR8Packed +}; + +// max number of components in any SplashColor +#define splashMaxColorComps 3 + +// 1-bit gray or alpha +typedef Guchar SplashMono1; +typedef Guchar SplashMono1P; // packed + +// 8-bit gray or alpha +typedef Guchar SplashMono8; + +// 3x8-bit RGB: (MSB) 00RRGGBB (LSB) +typedef Guint SplashRGB8; +#define splashRGB8R(rgb8) (((rgb8) >> 16) & 0xff) +#define splashRGB8G(rgb8) (((rgb8) >> 8) & 0xff) +#define splashRGB8B(rgb8) ((rgb8) & 0xff) +#define splashMakeRGB8(r, g, b) \ + ((((r) & 0xff) << 16) | (((g) & 0xff) << 8) | ((b) & 0xff)) + +// 3x8-bit RGB: (MSB) 00BBGGRR (LSB) +typedef Guint SplashBGR8; +typedef Guchar SplashBGR8P; // packed +#define splashBGR8R(bgr8) ((bgr8) & 0xff) +#define splashBGR8G(bgr8) (((bgr8) >> 8) & 0xff) +#define splashBGR8B(bgr8) (((bgr8) >> 16) & 0xff) +#define splashMakeBGR8(r, g, b) \ + ((((b) & 0xff) << 16) | (((g) & 0xff) << 8) | ((r) & 0xff)) + +union SplashColor { + SplashMono1 mono1; + SplashMono8 mono8; + SplashRGB8 rgb8; + SplashBGR8 bgr8; +}; + +union SplashColorPtr { + SplashMono1P *mono1; + SplashMono8 *mono8; + SplashRGB8 *rgb8; + SplashBGR8P *bgr8; +}; + +//------------------------------------------------------------------------ +// error results +//------------------------------------------------------------------------ + +typedef int SplashError; + +#endif diff --git a/pdf/splash/SplashXPath.cc b/pdf/splash/SplashXPath.cc new file mode 100644 index 0000000..e1a3afb --- /dev/null +++ b/pdf/splash/SplashXPath.cc @@ -0,0 +1,417 @@ +//======================================================================== +// +// SplashXPath.cc +// +//======================================================================== + +#include <aconf.h> + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include <stdlib.h> +#include <string.h> +#include "gmem.h" +#include "SplashMath.h" +#include "SplashPath.h" +#include "SplashXPath.h" + +//------------------------------------------------------------------------ + +#define maxCurveSplits (1 << 10) + +//------------------------------------------------------------------------ +// SplashXPath +//------------------------------------------------------------------------ + +SplashXPath::SplashXPath() { + segs = NULL; + length = size = 0; +} + +SplashXPath::SplashXPath(SplashPath *path, SplashCoord flatness, + GBool closeSubpaths) { + SplashCoord xc, yc, dx, dy, r, x0, y0, x1, y1; + int quad0, quad1, quad; + int i, curSubpath; + GBool last; + + segs = NULL; + length = size = 0; + + i = 0; + curSubpath = 0; + while (i < path->length) { + + // first point in subpath - skip it + if (path->flags[i] & splashPathFirst) { + curSubpath = i; + ++i; + + } else { + + // curve segment + if (path->flags[i] & splashPathCurve) { + addCurve(path->pts[i-1].x, path->pts[i-1].y, + path->pts[i ].x, path->pts[i ].y, + path->pts[i+1].x, path->pts[i+1].y, + path->pts[i+2].x, path->pts[i+2].y, + 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)); + i += 3; + + // clockwise circular arc + } else if (path->flags[i] & splashPathArcCW) { + xc = path->pts[i].x; + yc = path->pts[i].y; + dx = path->pts[i+1].x - xc; + dy = path->pts[i+1].y - yc; + r = splashSqrt(dx * dx + dy * dy); + if (path->pts[i-1].x < xc && path->pts[i-1].y <= yc) { + quad0 = 0; + } else if (path->pts[i-1].x >= xc && path->pts[i-1].y < yc) { + quad0 = 1; + } else if (path->pts[i-1].x > xc && path->pts[i-1].y >= yc) { + quad0 = 2; + } else { + quad0 = 3; + } + if (path->pts[i+1].x <= xc && path->pts[i+1].y < yc) { + quad1 = 0; + } else if (path->pts[i+1].x > xc && path->pts[i+1].y <= yc) { + quad1 = 1; + } else if (path->pts[i+1].x >= xc && path->pts[i+1].y > yc) { + quad1 = 2; + } else { + quad1 = 3; + } + x0 = path->pts[i-1].x; + y0 = path->pts[i-1].y; + x1 = y1 = 0; // make gcc happy + quad = quad0; + while (1) { + switch (quad) { + case 0: x1 = xc; y1 = yc - r; break; + case 1: x1 = xc + r; y1 = yc; break; + case 2: x1 = xc; y1 = yc + r; break; + case 3: x1 = xc - r; y1 = yc; break; + } + last = gFalse; + if (quad == quad1) { + switch (quad) { + case 0: + case 1: last = path->pts[i+1].x > x0; break; + case 2: + case 3: last = path->pts[i+1].x < x0; break; + } + } + if (last) { + addArc(x0, y0, path->pts[i+1].x, path->pts[i+1].y, + xc, yc, r, quad, flatness, + quad == quad0 && (path->flags[i-1] & splashPathFirst), + (path->flags[i+1] & splashPathLast), + quad == quad0 && !closeSubpaths && + (path->flags[i-1] & splashPathFirst) && + !(path->flags[i-1] & splashPathClosed), + !closeSubpaths && + (path->flags[i+1] & splashPathLast) && + !(path->flags[i+1] & splashPathClosed)); + break; + } else { + addArc(x0, y0, x1, y1, + xc, yc, r, quad, flatness, + quad == quad0 && (path->flags[i-1] & splashPathFirst), + gFalse, + quad == quad0 && !closeSubpaths && + (path->flags[i-1] & splashPathFirst) && + !(path->flags[i-1] & splashPathClosed), + gFalse); + x0 = x1; + y0 = y1; + quad = (quad + 1) & 3; + } + } + i += 2; + + // line segment + } else { + addSegment(path->pts[i-1].x, path->pts[i-1].y, + path->pts[i].x, path->pts[i].y, + path->flags[i-1] & splashPathFirst, + path->flags[i] & splashPathLast, + !closeSubpaths && + (path->flags[i-1] & splashPathFirst) && + !(path->flags[i-1] & splashPathClosed), + !closeSubpaths && + (path->flags[i] & splashPathLast) && + !(path->flags[i] & splashPathClosed)); + ++i; + } + + // close a subpath + if (closeSubpaths && + (path->flags[i-1] & splashPathLast) && + (path->pts[i-1].x != path->pts[curSubpath].x || + path->pts[i-1].y != path->pts[curSubpath]. y)) { + addSegment(path->pts[i-1].x, path->pts[i-1].y, + path->pts[curSubpath].x, path->pts[curSubpath].y, + gFalse, gTrue, gFalse, gFalse); + } + } + } +} + +SplashXPath::SplashXPath(SplashXPath *xPath) { + length = xPath->length; + size = xPath->size; + segs = (SplashXPathSeg *)gmalloc(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 *)grealloc(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[maxCurveSplits + 1][3]; + SplashCoord cy[maxCurveSplits + 1][3]; + int cNext[maxCurveSplits + 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; + + flatness2 = flatness * flatness; + + // initial segment + p1 = 0; + p2 = maxCurveSplits; + cx[p1][0] = x0; cy[p1][0] = y0; + cx[p1][1] = x1; cy[p1][1] = y1; + cx[p1][2] = x2; cy[p1][2] = y2; + cx[p2][0] = x3; cy[p2][0] = y3; + cNext[p1] = p2; + + while (p1 < maxCurveSplits) { + + // 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 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; + dx = xx1 - mx; + dy = yy1 - my; + d1 = dx*dx + dy*dy; + dx = xx2 - mx; + dy = yy2 - my; + d2 = dx*dx + dy*dy; + + // if the curve is flat enough, or no more subdivisions are + // allowed, add the straight line segment + if (p2 - p1 == 1 || (d1 <= flatness2 && d2 <= flatness2)) { + addSegment(xl0, yl0, xr3, yr3, + p1 == 0 && first, + p2 == maxCurveSplits && last, + p1 == 0 && end0, + p2 == maxCurveSplits && end1); + 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][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; + } + } +} + +void SplashXPath::addArc(SplashCoord x0, SplashCoord y0, + SplashCoord x1, SplashCoord y1, + SplashCoord xc, SplashCoord yc, + SplashCoord r, int quad, + SplashCoord flatness, + GBool first, GBool last, GBool end0, GBool end1) { + SplashCoord px[maxCurveSplits + 1]; + SplashCoord py[maxCurveSplits + 1]; + int pNext[maxCurveSplits + 1]; + SplashCoord r2, flatness2; + SplashCoord xx0, yy0, xx1, yy1, xm, ym, t, dx, dy; + int p1, p2, p3; + + r2 = r * r; + flatness2 = flatness * flatness; + + // initial segment + p1 = 0; + p2 = maxCurveSplits; + px[p1] = x0; py[p1] = y0; + px[p2] = x1; py[p2] = y1; + pNext[p1] = p2; + + while (p1 < maxCurveSplits) { + + // get the next segment + xx0 = px[p1]; yy0 = py[p1]; + p2 = pNext[p1]; + xx1 = px[p2]; yy1 = py[p2]; + + // compute the arc midpoint + t = (xx0 - xc) * (xx1 - xc) - (yy0 - yc) * (yy1 - yc); + xm = splashSqrt(0.5 * (r2 + t)); + ym = splashSqrt(0.5 * (r2 - t)); + switch (quad) { + case 0: xm = xc - xm; ym = yc - ym; break; + case 1: xm = xc + xm; ym = yc - ym; break; + case 2: xm = xc + xm; ym = yc + ym; break; + case 3: xm = xc - xm; ym = yc + ym; break; + } + + // compute distance from midpoint of straight segment to midpoint + // of arc + dx = 0.5 * (xx0 + xx1) - xm; + dy = 0.5 * (yy0 + yy1) - ym; + + // if the arc is flat enough, or no more subdivisions are allowed, + // add the straight line segment + if (p2 - p1 == 1 || dx * dx + dy * dy <= flatness2) { + addSegment(xx0, yy0, xx1, yy1, + p1 == 0 && first, + p2 == maxCurveSplits && last, + p1 == 0 && end0, + p2 == maxCurveSplits && end1); + p1 = p2; + + // otherwise, subdivide the arc + } else { + p3 = (p1 + p2) / 2; + px[p3] = xm; + py[p3] = ym; + pNext[p1] = p3; + pNext[p3] = p2; + } + } +} + +void SplashXPath::addSegment(SplashCoord x0, SplashCoord y0, + SplashCoord x1, SplashCoord y1, + GBool first, GBool last, GBool end0, GBool end1) { + grow(1); + segs[length].x0 = x0; + segs[length].y0 = y0; + segs[length].x1 = x1; + segs[length].y1 = y1; + segs[length].flags = 0; + if (first) { + segs[length].flags |= splashXPathFirst; + } + if (last) { + segs[length].flags |= splashXPathLast; + } + if (end0) { + segs[length].flags |= splashXPathEnd0; + } + if (end1) { + segs[length].flags |= splashXPathEnd1; + } + if (y1 == y0) { + segs[length].dxdy = segs[length].dydx = 0; + segs[length].flags |= splashXPathHoriz; + if (x1 == x0) { + segs[length].flags |= splashXPathVert; + } + } else if (x1 == x0) { + segs[length].dxdy = segs[length].dydx = 0; + segs[length].flags |= splashXPathVert; + } else { + segs[length].dxdy = (x1 - x0) / (y1 - y0); + segs[length].dydx = 1 / segs[length].dxdy; + } + if (y0 > y1) { + segs[length].flags |= splashXPathFlip; + } + ++length; +} + +static int cmpXPathSegs(const void *arg0, const void *arg1) { + SplashXPathSeg *seg0 = (SplashXPathSeg *)arg0; + SplashXPathSeg *seg1 = (SplashXPathSeg *)arg1; + SplashCoord x0, y0, x1, y1; + + if (seg0->flags & splashXPathFlip) { + x0 = seg0->x1; + y0 = seg0->y1; + } else { + x0 = seg0->x0; + y0 = seg0->y0; + } + if (seg1->flags & splashXPathFlip) { + x1 = seg1->x1; + y1 = seg1->y1; + } else { + x1 = seg1->x0; + y1 = seg1->y0; + } + if (y0 != y1) { + return (y0 > y1) ? 1 : -1; + } + if (x0 != x1) { + return (x0 > x1) ? 1 : -1; + } + return 0; +} + +void SplashXPath::sort() { + qsort(segs, length, sizeof(SplashXPathSeg), &cmpXPathSegs); +} diff --git a/pdf/splash/SplashXPath.h b/pdf/splash/SplashXPath.h new file mode 100644 index 0000000..a9fe9a2 --- /dev/null +++ b/pdf/splash/SplashXPath.h @@ -0,0 +1,92 @@ +//======================================================================== +// +// SplashXPath.h +// +//======================================================================== + +#ifndef SPLASHXPATH_H +#define SPLASHXPATH_H + +#include <aconf.h> + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "SplashTypes.h" + +class SplashPath; + +//------------------------------------------------------------------------ +// 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 splashXPathFirst 0x01 // first segment of a subpath +#define splashXPathLast 0x02 // last segment of a subpath +#define splashXPathEnd0 0x04 // first endpoint is end of an open subpath +#define splashXPathEnd1 0x08 // second endpoint is end of an open subpath +#define splashXPathHoriz 0x10 // segment is vertical (y0 == y1) + // (dxdy is undef) +#define splashXPathVert 0x20 // segment is horizontal (x0 == x1) + // (dydx is undef) +#define splashXPathFlip 0x40 // y0 > y1 + +//------------------------------------------------------------------------ +// SplashXPath +//------------------------------------------------------------------------ + +class SplashXPath { +public: + + // Expands (converts to segments) and flattens (converts curves to + // lines) <path>. If <closeSubpaths> is true, closes all open + // subpaths. + SplashXPath(SplashPath *path, SplashCoord flatness, + GBool closeSubpaths); + + // Copy an expanded path. + SplashXPath *copy() { return new SplashXPath(this); } + + ~SplashXPath(); + + // Sort by upper coordinate (lower y), in y-major order. + void sort(); + +private: + + SplashXPath(); + SplashXPath(SplashXPath *xPath); + 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 addArc(SplashCoord x0, SplashCoord y0, + SplashCoord x1, SplashCoord y1, + SplashCoord xc, SplashCoord yc, + SplashCoord r, int quad, + SplashCoord flatness, + GBool first, GBool last, GBool end0, GBool end1); + void addSegment(SplashCoord x0, SplashCoord y0, + SplashCoord x1, SplashCoord y1, + GBool first, GBool last, GBool end0, GBool end1); + + SplashXPathSeg *segs; + int length, size; // length and size of segs array + + friend class SplashXPathScanner; + friend class SplashClip; + friend class Splash; +}; + +#endif diff --git a/pdf/splash/SplashXPathScanner.cc b/pdf/splash/SplashXPathScanner.cc new file mode 100644 index 0000000..c93cc49 --- /dev/null +++ b/pdf/splash/SplashXPathScanner.cc @@ -0,0 +1,271 @@ +//======================================================================== +// +// SplashXPathScanner.cc +// +//======================================================================== + +#include <aconf.h> + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include <stdlib.h> +#include "gmem.h" +#include "SplashMath.h" +#include "SplashXPath.h" +#include "SplashXPathScanner.h" + +//------------------------------------------------------------------------ + +struct SplashIntersect { + int x0, x1; // intersection of segment with [y, y+1) + int count; // EO/NZWN counter increment +}; + +static int cmpIntersect(const void *p0, const void *p1) { + return ((SplashIntersect *)p0)->x0 - ((SplashIntersect *)p1)->x0; +} + +//------------------------------------------------------------------------ +// SplashXPathScanner +//------------------------------------------------------------------------ + +SplashXPathScanner::SplashXPathScanner(SplashXPath *xPathA, GBool eoA) { + SplashXPathSeg *seg; + SplashCoord xMinFP, yMinFP, xMaxFP, yMaxFP; + int i; + + xPath = xPathA; + eo = eoA; + + // compute the bbox + 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); + + interY = 0; + xPathIdx = 0; + inter = NULL; + interLen = interSize = 0; + computeIntersections(yMin); +} + +SplashXPathScanner::~SplashXPathScanner() { + gfree(inter); +} + +void SplashXPathScanner::getSpanBounds(int y, int *spanXMin, int *spanXMax) { + if (interY != y) { + computeIntersections(y); + } + if (interLen > 0) { + *spanXMin = inter[0].x0; + *spanXMax = inter[interLen - 1].x1; + } else { + *spanXMin = xMax + 1; + *spanXMax = xMax; + } +} + +GBool SplashXPathScanner::test(int x, int y) { + int count, i; + + if (interY != y) { + computeIntersections(y); + } + count = 0; + for (i = 0; i < interLen && inter[i].x0 <= x; ++i) { + if (x <= inter[i].x1) { + return gTrue; + } + count += inter[i].count; + } + return eo ? (count & 1) : (count != 0); +} + +GBool SplashXPathScanner::testSpan(int x0, int x1, int y) { + int count, xx1, i; + + if (interY != y) { + computeIntersections(y); + } + + count = 0; + for (i = 0; i < interLen && inter[i].x1 < x0; ++i) { + count += inter[i].count; + } + + // invariant: the subspan [x0,xx1] is inside the path + xx1 = x0 - 1; + while (xx1 < x1) { + if (i >= interLen) { + return gFalse; + } + if (inter[i].x0 > xx1 + 1 && + !(eo ? (count & 1) : (count != 0))) { + return gFalse; + } + if (inter[i].x1 > xx1) { + xx1 = inter[i].x1; + } + count += inter[i].count; + ++i; + } + + return gTrue; +} + +GBool SplashXPathScanner::getNextSpan(int y, int *x0, int *x1) { + int xx0, xx1; + + if (interY != y) { + computeIntersections(y); + } + if (interIdx >= interLen) { + return gFalse; + } + xx0 = inter[interIdx].x0; + xx1 = inter[interIdx].x1; + interCount += inter[interIdx].count; + ++interIdx; + while (interIdx < interLen && + (inter[interIdx].x0 <= xx1 || + (eo ? (interCount & 1) : (interCount != 0)))) { + if (inter[interIdx].x1 > xx1) { + xx1 = inter[interIdx].x1; + } + interCount += inter[interIdx].count; + ++interIdx; + } + *x0 = xx0; + *x1 = xx1; + return gTrue; +} + +void SplashXPathScanner::computeIntersections(int y) { + SplashCoord ySegMin, ySegMax, xx0, xx1; + SplashXPathSeg *seg; + int i, j; + + // find the first segment that intersects [y, y+1) + i = (y >= interY) ? xPathIdx : 0; + while (i < xPath->length && + xPath->segs[i].y0 < y && xPath->segs[i].y1 < y) { + ++i; + } + xPathIdx = i; + + // find all of the segments that intersect [y, y+1) and create an + // Intersect element for each one + interLen = 0; + for (j = i; j < xPath->length; ++j) { + seg = &xPath->segs[j]; + if (seg->flags & splashXPathFlip) { + ySegMin = seg->y1; + ySegMax = seg->y0; + } else { + ySegMin = seg->y0; + ySegMax = seg->y1; + } + + // ensure that: ySegMin < y+1 + // y <= ySegMax + if (ySegMin >= y + 1) { + break; + } + if (ySegMax < y) { + continue; + } + + if (interLen == interSize) { + if (interSize == 0) { + interSize = 16; + } else { + interSize *= 2; + } + inter = (SplashIntersect *)grealloc(inter, + interSize * sizeof(SplashIntersect)); + } + + if (seg->flags & splashXPathHoriz) { + xx0 = seg->x0; + xx1 = seg->x1; + } else if (seg->flags & splashXPathVert) { + xx0 = xx1 = seg->x0; + } else { + if (ySegMin <= y) { + // intersection with top edge + xx0 = seg->x0 + (y - seg->y0) * seg->dxdy; + } else { + // x coord of segment endpoint with min y coord + xx0 = (seg->flags & splashXPathFlip) ? seg->x1 : seg->x0; + } + if (ySegMax >= y + 1) { + // intersection with bottom edge + xx1 = seg->x0 + (y + 1 - seg->y0) * seg->dxdy; + } else { + // x coord of segment endpoint with max y coord + xx1 = (seg->flags & splashXPathFlip) ? seg->x0 : seg->x1; + } + } + if (xx0 < xx1) { + inter[interLen].x0 = splashFloor(xx0); + inter[interLen].x1 = splashFloor(xx1); + } else { + inter[interLen].x0 = splashFloor(xx1); + inter[interLen].x1 = splashFloor(xx0); + } + if (ySegMin <= y && y < ySegMax && !(seg->flags & splashXPathHoriz)) { + inter[interLen].count = eo ? 1 + : (seg->flags & splashXPathFlip) ? 1 : -1; + } else { + inter[interLen].count = 0; + } + ++interLen; + } + + qsort(inter, interLen, sizeof(SplashIntersect), &cmpIntersect); + + interY = y; + interIdx = 0; + interCount = 0; +} diff --git a/pdf/splash/SplashXPathScanner.h b/pdf/splash/SplashXPathScanner.h new file mode 100644 index 0000000..62484ba --- /dev/null +++ b/pdf/splash/SplashXPathScanner.h @@ -0,0 +1,74 @@ +//======================================================================== +// +// SplashXPathScanner.h +// +//======================================================================== + +#ifndef SPLASHXPATHSCANNER_H +#define SPLASHXPATHSCANNER_H + +#include <aconf.h> + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "SplashTypes.h" + +class SplashXPath; +struct SplashIntersect; + +//------------------------------------------------------------------------ +// SplashXPathScanner +//------------------------------------------------------------------------ + +class SplashXPathScanner { +public: + + // Create a new SplashXPathScanner object. <xPathA> must be sorted. + SplashXPathScanner(SplashXPath *xPathA, GBool eoA); + + ~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 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); + +private: + + void computeIntersections(int y); + + SplashXPath *xPath; + GBool eo; + int xMin, yMin, xMax, yMax; + + int interY; // current y value + int interIdx; // current index into <inter> - used by + // getNextSpan + int interCount; // current EO/NZWN counter - used by + // getNextSpan + int xPathIdx; // current index into <xPath> - used by + // computeIntersections + SplashIntersect *inter; // intersections array for <interY> + int interLen; // number of intersections in <inter> + int interSize; // size of the <inter> array +}; + +#endif diff --git a/pdf/splash/vms_make.com b/pdf/splash/vms_make.com new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/pdf/splash/vms_make.com |