Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/pdf/splash
diff options
context:
space:
mode:
Diffstat (limited to 'pdf/splash')
-rw-r--r--pdf/splash/Makefile.dep0
-rw-r--r--pdf/splash/Makefile.in99
-rw-r--r--pdf/splash/Splash.cc1648
-rw-r--r--pdf/splash/Splash.h176
-rw-r--r--pdf/splash/SplashBitmap.cc134
-rw-r--r--pdf/splash/SplashBitmap.h48
-rw-r--r--pdf/splash/SplashClip.cc270
-rw-r--r--pdf/splash/SplashClip.h88
-rw-r--r--pdf/splash/SplashErrorCodes.h32
-rw-r--r--pdf/splash/SplashFTFont.cc288
-rw-r--r--pdf/splash/SplashFTFont.h54
-rw-r--r--pdf/splash/SplashFTFontEngine.cc134
-rw-r--r--pdf/splash/SplashFTFontEngine.h59
-rw-r--r--pdf/splash/SplashFTFontFile.cc111
-rw-r--r--pdf/splash/SplashFTFontFile.h69
-rw-r--r--pdf/splash/SplashFont.cc166
-rw-r--r--pdf/splash/SplashFont.h89
-rw-r--r--pdf/splash/SplashFontEngine.cc245
-rw-r--r--pdf/splash/SplashFontEngine.h85
-rw-r--r--pdf/splash/SplashFontFile.cc55
-rw-r--r--pdf/splash/SplashFontFile.h60
-rw-r--r--pdf/splash/SplashFontFileID.cc23
-rw-r--r--pdf/splash/SplashFontFileID.h30
-rw-r--r--pdf/splash/SplashGlyphBitmap.h26
-rw-r--r--pdf/splash/SplashMath.h46
-rw-r--r--pdf/splash/SplashPath.cc177
-rw-r--r--pdf/splash/SplashPath.h107
-rw-r--r--pdf/splash/SplashPattern.cc64
-rw-r--r--pdf/splash/SplashPattern.h81
-rw-r--r--pdf/splash/SplashScreen.cc107
-rw-r--r--pdf/splash/SplashScreen.h40
-rw-r--r--pdf/splash/SplashState.cc99
-rw-r--r--pdf/splash/SplashState.h88
-rw-r--r--pdf/splash/SplashT1Font.cc251
-rw-r--r--pdf/splash/SplashT1Font.h51
-rw-r--r--pdf/splash/SplashT1FontEngine.cc124
-rw-r--r--pdf/splash/SplashT1FontEngine.h53
-rw-r--r--pdf/splash/SplashT1FontFile.cc96
-rw-r--r--pdf/splash/SplashT1FontFile.h57
-rw-r--r--pdf/splash/SplashTypes.h77
-rw-r--r--pdf/splash/SplashXPath.cc417
-rw-r--r--pdf/splash/SplashXPath.h92
-rw-r--r--pdf/splash/SplashXPathScanner.cc271
-rw-r--r--pdf/splash/SplashXPathScanner.h74
-rw-r--r--pdf/splash/vms_make.com0
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