Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/pdf/xpdf/SplashOutputDev.cc
diff options
context:
space:
mode:
Diffstat (limited to 'pdf/xpdf/SplashOutputDev.cc')
-rw-r--r--pdf/xpdf/SplashOutputDev.cc1348
1 files changed, 0 insertions, 1348 deletions
diff --git a/pdf/xpdf/SplashOutputDev.cc b/pdf/xpdf/SplashOutputDev.cc
deleted file mode 100644
index 58da12c..0000000
--- a/pdf/xpdf/SplashOutputDev.cc
+++ /dev/null
@@ -1,1348 +0,0 @@
-//========================================================================
-//
-// SplashOutputDev.cc
-//
-// Copyright 2003 Glyph & Cog, LLC
-//
-//========================================================================
-
-#include <aconf.h>
-
-#ifdef USE_GCC_PRAGMAS
-#pragma implementation
-#endif
-
-#include <string.h>
-#include <math.h>
-#include "gfile.h"
-#include "GlobalParams.h"
-#include "Error.h"
-#include "Object.h"
-#include "GfxState.h"
-#include "GfxFont.h"
-#include "Link.h"
-#include "CharCodeToUnicode.h"
-#include "FontEncodingTables.h"
-#include "FoFiTrueType.h"
-#include "SplashBitmap.h"
-#include "SplashGlyphBitmap.h"
-#include "SplashPattern.h"
-#include "SplashScreen.h"
-#include "SplashPath.h"
-#include "SplashState.h"
-#include "SplashErrorCodes.h"
-#include "SplashFontEngine.h"
-#include "SplashFont.h"
-#include "SplashFontFile.h"
-#include "SplashFontFileID.h"
-#include "Splash.h"
-#include "SplashOutputDev.h"
-
-//------------------------------------------------------------------------
-// Font substitutions
-//------------------------------------------------------------------------
-
-struct SplashOutFontSubst {
- char *name;
- double mWidth;
-};
-
-// index: {symbolic:12, fixed:8, serif:4, sans-serif:0} + bold*2 + italic
-static SplashOutFontSubst splashOutSubstFonts[16] = {
- {"Helvetica", 0.833},
- {"Helvetica-Oblique", 0.833},
- {"Helvetica-Bold", 0.889},
- {"Helvetica-BoldOblique", 0.889},
- {"Times-Roman", 0.788},
- {"Times-Italic", 0.722},
- {"Times-Bold", 0.833},
- {"Times-BoldItalic", 0.778},
- {"Courier", 0.600},
- {"Courier-Oblique", 0.600},
- {"Courier-Bold", 0.600},
- {"Courier-BoldOblique", 0.600},
- {"Symbol", 0.576},
- {"Symbol", 0.576},
- {"Symbol", 0.576},
- {"Symbol", 0.576}
-};
-
-//------------------------------------------------------------------------
-
-#define soutRound(x) ((int)(x + 0.5))
-
-//------------------------------------------------------------------------
-// SplashOutFontFileID
-//------------------------------------------------------------------------
-
-class SplashOutFontFileID: public SplashFontFileID {
-public:
-
- SplashOutFontFileID(Ref *rA) { r = *rA; substIdx = -1; }
-
- ~SplashOutFontFileID() {}
-
- GBool matches(SplashFontFileID *id) {
- return ((SplashOutFontFileID *)id)->r.num == r.num &&
- ((SplashOutFontFileID *)id)->r.gen == r.gen;
- }
-
- void setSubstIdx(int substIdxA) { substIdx = substIdxA; }
- int getSubstIdx() { return substIdx; }
-
-private:
-
- Ref r;
- int substIdx;
-};
-
-//------------------------------------------------------------------------
-// T3FontCache
-//------------------------------------------------------------------------
-
-struct T3FontCacheTag {
- Gushort code;
- Gushort mru; // valid bit (0x8000) and MRU index
-};
-
-class T3FontCache {
-public:
-
- T3FontCache(Ref *fontID, double m11A, double m12A,
- double m21A, double m22A,
- int glyphXA, int glyphYA, int glyphWA, int glyphHA,
- GBool aa);
- ~T3FontCache();
- GBool matches(Ref *idA, double m11A, double m12A,
- double m21A, double m22A)
- { return fontID.num == idA->num && fontID.gen == idA->gen &&
- m11 == m11A && m12 == m12A && m21 == m21A && m22 == m22A; }
-
- Ref fontID; // PDF font ID
- double m11, m12, m21, m22; // transform matrix
- int glyphX, glyphY; // pixel offset of glyph bitmaps
- int glyphW, glyphH; // size of glyph bitmaps, in pixels
- int glyphSize; // size of glyph bitmaps, in bytes
- int cacheSets; // number of sets in cache
- int cacheAssoc; // cache associativity (glyphs per set)
- Guchar *cacheData; // glyph pixmap cache
- T3FontCacheTag *cacheTags; // cache tags, i.e., char codes
-};
-
-T3FontCache::T3FontCache(Ref *fontIDA, double m11A, double m12A,
- double m21A, double m22A,
- int glyphXA, int glyphYA, int glyphWA, int glyphHA,
- GBool aa) {
- int i;
-
- fontID = *fontIDA;
- m11 = m11A;
- m12 = m12A;
- m21 = m21A;
- m22 = m22A;
- glyphX = glyphXA;
- glyphY = glyphYA;
- glyphW = glyphWA;
- glyphH = glyphHA;
- if (aa) {
- glyphSize = glyphW * glyphH;
- } else {
- glyphSize = ((glyphW + 7) >> 3) * glyphH;
- }
- cacheAssoc = 8;
- if (glyphSize <= 256) {
- cacheSets = 8;
- } else if (glyphSize <= 512) {
- cacheSets = 4;
- } else if (glyphSize <= 1024) {
- cacheSets = 2;
- } else {
- cacheSets = 1;
- }
- cacheData = (Guchar *)gmalloc(cacheSets * cacheAssoc * glyphSize);
- cacheTags = (T3FontCacheTag *)gmalloc(cacheSets * cacheAssoc *
- sizeof(T3FontCacheTag));
- for (i = 0; i < cacheSets * cacheAssoc; ++i) {
- cacheTags[i].mru = i & (cacheAssoc - 1);
- }
-}
-
-T3FontCache::~T3FontCache() {
- gfree(cacheData);
- gfree(cacheTags);
-}
-
-struct T3GlyphStack {
- Gushort code; // character code
- double x, y; // position to draw the glyph
-
- //----- cache info
- T3FontCache *cache; // font cache for the current font
- T3FontCacheTag *cacheTag; // pointer to cache tag for the glyph
- Guchar *cacheData; // pointer to cache data for the glyph
-
- //----- saved state
- SplashBitmap *origBitmap;
- Splash *origSplash;
- double origCTM4, origCTM5;
-
- T3GlyphStack *next; // next object on stack
-};
-
-//------------------------------------------------------------------------
-// SplashOutputDev
-//------------------------------------------------------------------------
-
-SplashOutputDev::SplashOutputDev(SplashColorMode colorModeA,
- GBool reverseVideoA,
- SplashColor paperColorA) {
- colorMode = colorModeA;
- reverseVideo = reverseVideoA;
- paperColor = paperColorA;
-
- xref = NULL;
-
- bitmap = new SplashBitmap(1, 1, colorMode);
- splash = new Splash(bitmap);
- splash->clear(paperColor);
-
- fontEngine = NULL;
-
- nT3Fonts = 0;
- t3GlyphStack = NULL;
-
- font = NULL;
- needFontUpdate = gFalse;
- textClipPath = NULL;
-
- underlayCbk = NULL;
- underlayCbkData = NULL;
-}
-
-SplashOutputDev::~SplashOutputDev() {
- int i;
-
- for (i = 0; i < nT3Fonts; ++i) {
- delete t3FontCache[i];
- }
- if (fontEngine) {
- delete fontEngine;
- }
- if (splash) {
- delete splash;
- }
- if (bitmap) {
- delete bitmap;
- }
-}
-
-void SplashOutputDev::startDoc(XRef *xrefA) {
- int i;
-
- xref = xrefA;
- if (fontEngine) {
- delete fontEngine;
- }
- fontEngine = new SplashFontEngine(
-#if HAVE_T1LIB_H
- globalParams->getEnableT1lib(),
-#endif
-#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H
- globalParams->getEnableFreeType(),
-#endif
- globalParams->getAntialias());
- for (i = 0; i < nT3Fonts; ++i) {
- delete t3FontCache[i];
- }
- nT3Fonts = 0;
-}
-
-void SplashOutputDev::startPage(int pageNum, GfxState *state) {
- int w, h;
- SplashColor color;
-
- w = state ? (int)(state->getPageWidth() + 0.5) : 1;
- h = state ? (int)(state->getPageHeight() + 0.5) : 1;
- if (splash) {
- delete splash;
- }
- if (!bitmap || w != bitmap->getWidth() || h != bitmap->getHeight()) {
- if (bitmap) {
- delete bitmap;
- }
- bitmap = new SplashBitmap(w, h, colorMode);
- }
- splash = new Splash(bitmap);
- switch (colorMode) {
- case splashModeMono1: color.mono1 = 0; break;
- case splashModeMono8: color.mono8 = 0; break;
- case splashModeRGB8:
- case splashModeRGB8Packed: color.rgb8 = splashMakeRGB8(0, 0, 0); break;
- case splashModeBGR8Packed: color.bgr8 = splashMakeBGR8(0, 0, 0); break;
- }
- splash->setStrokePattern(new SplashSolidColor(color));
- splash->setFillPattern(new SplashSolidColor(color));
- splash->setLineCap(splashLineCapButt);
- splash->setLineJoin(splashLineJoinMiter);
- splash->setLineDash(NULL, 0, 0);
- splash->setMiterLimit(10);
- splash->setFlatness(1);
- splash->clear(paperColor);
-
- if (underlayCbk) {
- (*underlayCbk)(underlayCbkData);
- }
-}
-
-void SplashOutputDev::endPage() {
-}
-
-void SplashOutputDev::drawLink(Link *link, Catalog *catalog) {
- double x1, y1, x2, y2;
- LinkBorderStyle *borderStyle;
- GfxRGB rgb;
- double gray;
- double *dash;
- int dashLength;
- SplashCoord dashList[20];
- SplashPath *path;
- int x, y, i;
-
- link->getRect(&x1, &y1, &x2, &y2);
- borderStyle = link->getBorderStyle();
- if (borderStyle->getWidth() > 0) {
- borderStyle->getColor(&rgb.r, &rgb.g, &rgb.b);
- gray = 0.299 * rgb.r + 0.587 * rgb.g + 0.114 * rgb.b;
- if (gray > 1) {
- gray = 1;
- }
- splash->setStrokePattern(getColor(gray, &rgb));
- splash->setLineWidth((SplashCoord)borderStyle->getWidth());
- borderStyle->getDash(&dash, &dashLength);
- if (borderStyle->getType() == linkBorderDashed && dashLength > 0) {
- if (dashLength > 20) {
- dashLength = 20;
- }
- for (i = 0; i < dashLength; ++i) {
- dashList[i] = (SplashCoord)dash[i];
- }
- splash->setLineDash(dashList, dashLength, 0);
- }
- path = new SplashPath();
- if (borderStyle->getType() == linkBorderUnderlined) {
- cvtUserToDev(x1, y1, &x, &y);
- path->moveTo((SplashCoord)x, (SplashCoord)y);
- cvtUserToDev(x2, y1, &x, &y);
- path->lineTo((SplashCoord)x, (SplashCoord)y);
- } else {
- cvtUserToDev(x1, y1, &x, &y);
- path->moveTo((SplashCoord)x, (SplashCoord)y);
- cvtUserToDev(x2, y1, &x, &y);
- path->lineTo((SplashCoord)x, (SplashCoord)y);
- cvtUserToDev(x2, y2, &x, &y);
- path->lineTo((SplashCoord)x, (SplashCoord)y);
- cvtUserToDev(x1, y2, &x, &y);
- path->lineTo((SplashCoord)x, (SplashCoord)y);
- path->close();
- }
- splash->stroke(path);
- delete path;
- }
-}
-
-void SplashOutputDev::saveState(GfxState *state) {
- splash->saveState();
-}
-
-void SplashOutputDev::restoreState(GfxState *state) {
- splash->restoreState();
- needFontUpdate = gTrue;
-}
-
-void SplashOutputDev::updateAll(GfxState *state) {
- updateLineDash(state);
- updateLineJoin(state);
- updateLineCap(state);
- updateLineWidth(state);
- updateFlatness(state);
- updateMiterLimit(state);
- updateFillColor(state);
- updateStrokeColor(state);
- needFontUpdate = gTrue;
-}
-
-void SplashOutputDev::updateCTM(GfxState *state, double m11, double m12,
- double m21, double m22,
- double m31, double m32) {
- updateLineDash(state);
- updateLineJoin(state);
- updateLineCap(state);
- updateLineWidth(state);
-}
-
-void SplashOutputDev::updateLineDash(GfxState *state) {
- double *dashPattern;
- int dashLength;
- double dashStart;
- SplashCoord dash[20];
- SplashCoord phase;
- int i;
-
- state->getLineDash(&dashPattern, &dashLength, &dashStart);
- if (dashLength > 20) {
- dashLength = 20;
- }
- for (i = 0; i < dashLength; ++i) {
- dash[i] = (SplashCoord)state->transformWidth(dashPattern[i]);
- if (dash[i] < 1) {
- dash[i] = 1;
- }
- }
- phase = (SplashCoord)state->transformWidth(dashStart);
- splash->setLineDash(dash, dashLength, phase);
-}
-
-void SplashOutputDev::updateFlatness(GfxState *state) {
- splash->setFlatness(state->getFlatness());
-}
-
-void SplashOutputDev::updateLineJoin(GfxState *state) {
- splash->setLineJoin(state->getLineJoin());
-}
-
-void SplashOutputDev::updateLineCap(GfxState *state) {
- splash->setLineCap(state->getLineCap());
-}
-
-void SplashOutputDev::updateMiterLimit(GfxState *state) {
- splash->setMiterLimit(state->getMiterLimit());
-}
-
-void SplashOutputDev::updateLineWidth(GfxState *state) {
- splash->setLineWidth(state->getTransformedLineWidth());
-}
-
-void SplashOutputDev::updateFillColor(GfxState *state) {
- double gray;
- GfxRGB rgb;
-
- state->getFillGray(&gray);
- state->getFillRGB(&rgb);
- splash->setFillPattern(getColor(gray, &rgb));
-}
-
-void SplashOutputDev::updateStrokeColor(GfxState *state) {
- double gray;
- GfxRGB rgb;
-
- state->getStrokeGray(&gray);
- state->getStrokeRGB(&rgb);
- splash->setStrokePattern(getColor(gray, &rgb));
-}
-
-SplashPattern *SplashOutputDev::getColor(double gray, GfxRGB *rgb) {
- SplashPattern *pattern;
- SplashColor color0, color1;
- double r, g, b;
-
- if (reverseVideo) {
- gray = 1 - gray;
- r = 1 - rgb->r;
- g = 1 - rgb->g;
- b = 1 - rgb->b;
- } else {
- r = rgb->r;
- g = rgb->g;
- b = rgb->b;
- }
-
- pattern = NULL; // make gcc happy
- switch (colorMode) {
- case splashModeMono1:
- color0.mono1 = 0;
- color1.mono1 = 1;
- pattern = new SplashHalftone(color0, color1,
- splash->getScreen()->copy(),
- (SplashCoord)gray);
- break;
- case splashModeMono8:
- color1.mono8 = soutRound(255 * gray);
- pattern = new SplashSolidColor(color1);
- break;
- case splashModeRGB8:
- case splashModeRGB8Packed:
- color1.rgb8 = splashMakeRGB8(soutRound(255 * r),
- soutRound(255 * g),
- soutRound(255 * b));
- pattern = new SplashSolidColor(color1);
- break;
- case splashModeBGR8Packed:
- color1.bgr8 = splashMakeBGR8(soutRound(255 * r),
- soutRound(255 * g),
- soutRound(255 * b));
- pattern = new SplashSolidColor(color1);
- break;
- }
-
- return pattern;
-}
-
-void SplashOutputDev::updateFont(GfxState *state) {
- GfxFont *gfxFont;
- GfxFontType fontType;
- SplashOutFontFileID *id;
- SplashFontFile *fontFile;
- FoFiTrueType *ff;
- Ref embRef;
- Object refObj, strObj;
- GString *tmpFileName, *fileName, *substName;
- FILE *tmpFile;
- Gushort *codeToGID;
- DisplayFontParam *dfp;
- double m11, m12, m21, m22, w1, w2;
- SplashCoord mat[4];
- char *name;
- int c, substIdx, n, code;
-
- needFontUpdate = gFalse;
- font = NULL;
- tmpFileName = NULL;
- substIdx = -1;
-
- if (!(gfxFont = state->getFont())) {
- goto err1;
- }
- fontType = gfxFont->getType();
- if (fontType == fontType3) {
- goto err1;
- }
-
- // check the font file cache
- id = new SplashOutFontFileID(gfxFont->getID());
- if ((fontFile = fontEngine->getFontFile(id))) {
- delete id;
-
- } else {
-
- // if there is an embedded font, write it to disk
- if (gfxFont->getEmbeddedFontID(&embRef)) {
- if (!openTempFile(&tmpFileName, &tmpFile, "wb", NULL)) {
- error(-1, "Couldn't create temporary font file");
- goto err2;
- }
- refObj.initRef(embRef.num, embRef.gen);
- refObj.fetch(xref, &strObj);
- refObj.free();
- strObj.streamReset();
- while ((c = strObj.streamGetChar()) != EOF) {
- fputc(c, tmpFile);
- }
- strObj.streamClose();
- strObj.free();
- fclose(tmpFile);
- fileName = tmpFileName;
-
- // if there is an external font file, use it
- } else if (!(fileName = gfxFont->getExtFontFile())) {
-
- // look for a display font mapping or a substitute font
- dfp = NULL;
- if (gfxFont->isCIDFont()) {
- if (((GfxCIDFont *)gfxFont)->getCollection()) {
- dfp = globalParams->
- getDisplayCIDFont(gfxFont->getName(),
- ((GfxCIDFont *)gfxFont)->getCollection());
- }
- } else {
- if (gfxFont->getName()) {
- dfp = globalParams->getDisplayFont(gfxFont->getName());
- }
- if (!dfp) {
- // 8-bit font substitution
- if (gfxFont->isFixedWidth()) {
- substIdx = 8;
- } else if (gfxFont->isSerif()) {
- substIdx = 4;
- } else {
- substIdx = 0;
- }
- if (gfxFont->isBold()) {
- substIdx += 2;
- }
- if (gfxFont->isItalic()) {
- substIdx += 1;
- }
- substName = new GString(splashOutSubstFonts[substIdx].name);
- dfp = globalParams->getDisplayFont(substName);
- delete substName;
- id->setSubstIdx(substIdx);
- }
- }
- if (!dfp) {
- error(-1, "Couldn't find a font for '%s'",
- gfxFont->getName() ? gfxFont->getName()->getCString()
- : "(unnamed)");
- goto err2;
- }
- switch (dfp->kind) {
- case displayFontT1:
- fileName = dfp->t1.fileName;
- fontType = gfxFont->isCIDFont() ? fontCIDType0 : fontType1;
- break;
- case displayFontTT:
- fileName = dfp->tt.fileName;
- fontType = gfxFont->isCIDFont() ? fontCIDType2 : fontTrueType;
- break;
- }
- }
-
- // load the font file
- switch (fontType) {
- case fontType1:
- if (!(fontFile = fontEngine->loadType1Font(
- id,
- fileName->getCString(),
- fileName == tmpFileName,
- ((Gfx8BitFont *)gfxFont)->getEncoding()))) {
- error(-1, "Couldn't create a font for '%s'",
- gfxFont->getName() ? gfxFont->getName()->getCString()
- : "(unnamed)");
- goto err2;
- }
- break;
- case fontType1C:
- if (!(fontFile = fontEngine->loadType1CFont(
- id,
- fileName->getCString(),
- fileName == tmpFileName,
- ((Gfx8BitFont *)gfxFont)->getEncoding()))) {
- error(-1, "Couldn't create a font for '%s'",
- gfxFont->getName() ? gfxFont->getName()->getCString()
- : "(unnamed)");
- goto err2;
- }
- break;
- case fontTrueType:
- if (!(ff = FoFiTrueType::load(fileName->getCString()))) {
- goto err2;
- }
- codeToGID = ((Gfx8BitFont *)gfxFont)->getCodeToGIDMap(ff);
- delete ff;
- if (!(fontFile = fontEngine->loadTrueTypeFont(
- id,
- fileName->getCString(),
- fileName == tmpFileName,
- codeToGID, 256))) {
- error(-1, "Couldn't create a font for '%s'",
- gfxFont->getName() ? gfxFont->getName()->getCString()
- : "(unnamed)");
- goto err2;
- }
- break;
- case fontCIDType0:
- case fontCIDType0C:
- if (!(fontFile = fontEngine->loadCIDFont(
- id,
- fileName->getCString(),
- fileName == tmpFileName))) {
- error(-1, "Couldn't create a font for '%s'",
- gfxFont->getName() ? gfxFont->getName()->getCString()
- : "(unnamed)");
- goto err2;
- }
- break;
- case fontCIDType2:
- n = ((GfxCIDFont *)gfxFont)->getCIDToGIDLen();
- codeToGID = (Gushort *)gmalloc(n * sizeof(Gushort));
- memcpy(codeToGID, ((GfxCIDFont *)gfxFont)->getCIDToGID(),
- n * sizeof(Gushort));
- if (!(fontFile = fontEngine->loadTrueTypeFont(
- id,
- fileName->getCString(),
- fileName == tmpFileName,
- codeToGID, n))) {
- error(-1, "Couldn't create a font for '%s'",
- gfxFont->getName() ? gfxFont->getName()->getCString()
- : "(unnamed)");
- goto err2;
- }
- break;
- default:
- // this shouldn't happen
- goto err2;
- }
- }
-
- // get the font matrix
- state->getFontTransMat(&m11, &m12, &m21, &m22);
- m11 *= state->getHorizScaling();
- m12 *= state->getHorizScaling();
-
- // for substituted fonts: adjust the font matrix -- compare the
- // width of 'm' in the original font and the substituted font
- substIdx = ((SplashOutFontFileID *)fontFile->getID())->getSubstIdx();
- if (substIdx >= 0) {
- for (code = 0; code < 256; ++code) {
- if ((name = ((Gfx8BitFont *)gfxFont)->getCharName(code)) &&
- name[0] == 'm' && name[1] == '\0') {
- break;
- }
- }
- if (code < 256) {
- w1 = ((Gfx8BitFont *)gfxFont)->getWidth(code);
- w2 = splashOutSubstFonts[substIdx].mWidth;
- if (!gfxFont->isSymbolic()) {
- // if real font is substantially narrower than substituted
- // font, reduce the font size accordingly
- if (w1 > 0.01 && w1 < 0.9 * w2) {
- w1 /= w2;
- m11 *= w1;
- m21 *= w1;
- }
- }
- }
- }
-
- // create the scaled font
- mat[0] = m11; mat[1] = -m12;
- mat[2] = m21; mat[3] = -m22;
- font = fontEngine->getFont(fontFile, mat);
-
- if (tmpFileName) {
- delete tmpFileName;
- }
- return;
-
- err2:
- delete id;
- err1:
- if (tmpFileName) {
- delete tmpFileName;
- }
- return;
-}
-
-void SplashOutputDev::stroke(GfxState *state) {
- SplashPath *path;
-
- path = convertPath(state, state->getPath());
- splash->stroke(path);
- delete path;
-}
-
-void SplashOutputDev::fill(GfxState *state) {
- SplashPath *path;
-
- path = convertPath(state, state->getPath());
- splash->fill(path, gFalse);
- delete path;
-}
-
-void SplashOutputDev::eoFill(GfxState *state) {
- SplashPath *path;
-
- path = convertPath(state, state->getPath());
- splash->fill(path, gTrue);
- delete path;
-}
-
-void SplashOutputDev::clip(GfxState *state) {
- SplashPath *path;
-
- path = convertPath(state, state->getPath());
- splash->clipToPath(path, gFalse);
- delete path;
-}
-
-void SplashOutputDev::eoClip(GfxState *state) {
- SplashPath *path;
-
- path = convertPath(state, state->getPath());
- splash->clipToPath(path, gTrue);
- delete path;
-}
-
-SplashPath *SplashOutputDev::convertPath(GfxState *state, GfxPath *path) {
- SplashPath *sPath;
- GfxSubpath *subpath;
- double x1, y1, x2, y2, x3, y3;
- int i, j;
-
- sPath = new SplashPath();
- for (i = 0; i < path->getNumSubpaths(); ++i) {
- subpath = path->getSubpath(i);
- if (subpath->getNumPoints() > 0) {
- state->transform(subpath->getX(0), subpath->getY(0), &x1, &y1);
- sPath->moveTo((SplashCoord)x1, (SplashCoord)y1);
- j = 1;
- while (j < subpath->getNumPoints()) {
- if (subpath->getCurve(j)) {
- state->transform(subpath->getX(j), subpath->getY(j), &x1, &y1);
- state->transform(subpath->getX(j+1), subpath->getY(j+1), &x2, &y2);
- state->transform(subpath->getX(j+2), subpath->getY(j+2), &x3, &y3);
- sPath->curveTo((SplashCoord)x1, (SplashCoord)y1,
- (SplashCoord)x2, (SplashCoord)y2,
- (SplashCoord)x3, (SplashCoord)y3);
- j += 3;
- } else {
- state->transform(subpath->getX(j), subpath->getY(j), &x1, &y1);
- sPath->lineTo((SplashCoord)x1, (SplashCoord)y1);
- ++j;
- }
- }
- if (subpath->isClosed()) {
- sPath->close();
- }
- }
- }
- return sPath;
-}
-
-void SplashOutputDev::drawChar(GfxState *state, double x, double y,
- double dx, double dy,
- double originX, double originY,
- CharCode code, Unicode *u, int uLen) {
- double x1, y1;
- SplashPath *path;
- int render;
-
- if (needFontUpdate) {
- updateFont(state);
- }
- if (!font) {
- return;
- }
-
- // check for invisible text -- this is used by Acrobat Capture
- render = state->getRender();
- if (render == 3) {
- return;
- }
-
- x -= originX;
- y -= originY;
- state->transform(x, y, &x1, &y1);
-
- // fill
- if (!(render & 1)) {
- splash->fillChar((SplashCoord)x1, (SplashCoord)y1, code, font);
- }
-
- // stroke
- if ((render & 3) == 1 || (render & 3) == 2) {
- if ((path = font->getGlyphPath(code))) {
- path->offset((SplashCoord)x1, (SplashCoord)y1);
- splash->stroke(path);
- delete path;
- }
- }
-
- // clip
- if (render & 4) {
- path = font->getGlyphPath(code);
- path->offset((SplashCoord)x1, (SplashCoord)y1);
- if (textClipPath) {
- textClipPath->append(path);
- delete path;
- } else {
- textClipPath = path;
- }
- }
-}
-
-GBool SplashOutputDev::beginType3Char(GfxState *state, double x, double y,
- double dx, double dy,
- CharCode code, Unicode *u, int uLen) {
- GfxFont *gfxFont;
- Ref *fontID;
- double *ctm, *bbox;
- T3FontCache *t3Font;
- T3GlyphStack *t3gs;
- double x1, y1, xMin, yMin, xMax, yMax, xt, yt;
- int i, j;
-
- if (!(gfxFont = state->getFont())) {
- return gFalse;
- }
- fontID = gfxFont->getID();
- ctm = state->getCTM();
- state->transform(0, 0, &xt, &yt);
-
- // is it the first (MRU) font in the cache?
- if (!(nT3Fonts > 0 &&
- t3FontCache[0]->matches(fontID, ctm[0], ctm[1], ctm[2], ctm[3]))) {
-
- // is the font elsewhere in the cache?
- for (i = 1; i < nT3Fonts; ++i) {
- if (t3FontCache[i]->matches(fontID, ctm[0], ctm[1], ctm[2], ctm[3])) {
- t3Font = t3FontCache[i];
- for (j = i; j > 0; --j) {
- t3FontCache[j] = t3FontCache[j - 1];
- }
- t3FontCache[0] = t3Font;
- break;
- }
- }
- if (i >= nT3Fonts) {
-
- // create new entry in the font cache
- if (nT3Fonts == splashOutT3FontCacheSize) {
- delete t3FontCache[nT3Fonts - 1];
- --nT3Fonts;
- }
- for (j = nT3Fonts; j > 0; --j) {
- t3FontCache[j] = t3FontCache[j - 1];
- }
- ++nT3Fonts;
- bbox = gfxFont->getFontBBox();
- if (bbox[0] == 0 && bbox[1] == 0 && bbox[2] == 0 && bbox[3] == 0) {
- // broken bounding box -- just take a guess
- xMin = xt - 5;
- xMax = xMin + 30;
- yMax = yt + 15;
- yMin = yMax - 45;
- } else {
- state->transform(bbox[0], bbox[1], &x1, &y1);
- xMin = xMax = x1;
- yMin = yMax = y1;
- state->transform(bbox[0], bbox[3], &x1, &y1);
- if (x1 < xMin) {
- xMin = x1;
- } else if (x1 > xMax) {
- xMax = x1;
- }
- if (y1 < yMin) {
- yMin = y1;
- } else if (y1 > yMax) {
- yMax = y1;
- }
- state->transform(bbox[2], bbox[1], &x1, &y1);
- if (x1 < xMin) {
- xMin = x1;
- } else if (x1 > xMax) {
- xMax = x1;
- }
- if (y1 < yMin) {
- yMin = y1;
- } else if (y1 > yMax) {
- yMax = y1;
- }
- state->transform(bbox[2], bbox[3], &x1, &y1);
- if (x1 < xMin) {
- xMin = x1;
- } else if (x1 > xMax) {
- xMax = x1;
- }
- if (y1 < yMin) {
- yMin = y1;
- } else if (y1 > yMax) {
- yMax = y1;
- }
- }
- t3FontCache[0] = new T3FontCache(fontID, ctm[0], ctm[1], ctm[2], ctm[3],
- (int)floor(xMin - xt),
- (int)floor(yMin - yt),
- (int)ceil(xMax) - (int)floor(xMin) + 3,
- (int)ceil(yMax) - (int)floor(yMin) + 3,
- colorMode != splashModeMono1);
- }
- }
- t3Font = t3FontCache[0];
-
- // is the glyph in the cache?
- i = (code & (t3Font->cacheSets - 1)) * t3Font->cacheAssoc;
- for (j = 0; j < t3Font->cacheAssoc; ++j) {
- if ((t3Font->cacheTags[i+j].mru & 0x8000) &&
- t3Font->cacheTags[i+j].code == code) {
- drawType3Glyph(t3Font, &t3Font->cacheTags[i+j],
- t3Font->cacheData + (i+j) * t3Font->glyphSize,
- xt, yt);
- return gTrue;
- }
- }
-
- // push a new Type 3 glyph record
- t3gs = new T3GlyphStack();
- t3gs->next = t3GlyphStack;
- t3GlyphStack = t3gs;
- t3GlyphStack->code = code;
- t3GlyphStack->x = xt;
- t3GlyphStack->y = yt;
- t3GlyphStack->cache = t3Font;
- t3GlyphStack->cacheTag = NULL;
- t3GlyphStack->cacheData = NULL;
-
- return gFalse;
-}
-
-void SplashOutputDev::endType3Char(GfxState *state) {
- T3GlyphStack *t3gs;
- double *ctm;
-
- if (t3GlyphStack->cacheTag) {
- memcpy(t3GlyphStack->cacheData, bitmap->getDataPtr().mono8,
- t3GlyphStack->cache->glyphSize);
- delete bitmap;
- delete splash;
- bitmap = t3GlyphStack->origBitmap;
- splash = t3GlyphStack->origSplash;
- ctm = state->getCTM();
- state->setCTM(ctm[0], ctm[1], ctm[2], ctm[3],
- t3GlyphStack->origCTM4, t3GlyphStack->origCTM5);
- drawType3Glyph(t3GlyphStack->cache,
- t3GlyphStack->cacheTag, t3GlyphStack->cacheData,
- t3GlyphStack->x, t3GlyphStack->y);
- }
- t3gs = t3GlyphStack;
- t3GlyphStack = t3gs->next;
- delete t3gs;
-}
-
-void SplashOutputDev::type3D0(GfxState *state, double wx, double wy) {
-}
-
-void SplashOutputDev::type3D1(GfxState *state, double wx, double wy,
- double llx, double lly, double urx, double ury) {
- double *ctm;
- T3FontCache *t3Font;
- SplashColor color;
- double xt, yt, xMin, xMax, yMin, yMax, x1, y1;
- int i, j;
-
- t3Font = t3GlyphStack->cache;
-
- // check for a valid bbox
- state->transform(0, 0, &xt, &yt);
- state->transform(llx, lly, &x1, &y1);
- xMin = xMax = x1;
- yMin = yMax = y1;
- state->transform(llx, ury, &x1, &y1);
- if (x1 < xMin) {
- xMin = x1;
- } else if (x1 > xMax) {
- xMax = x1;
- }
- if (y1 < yMin) {
- yMin = y1;
- } else if (y1 > yMax) {
- yMax = y1;
- }
- state->transform(urx, lly, &x1, &y1);
- if (x1 < xMin) {
- xMin = x1;
- } else if (x1 > xMax) {
- xMax = x1;
- }
- if (y1 < yMin) {
- yMin = y1;
- } else if (y1 > yMax) {
- yMax = y1;
- }
- state->transform(urx, ury, &x1, &y1);
- if (x1 < xMin) {
- xMin = x1;
- } else if (x1 > xMax) {
- xMax = x1;
- }
- if (y1 < yMin) {
- yMin = y1;
- } else if (y1 > yMax) {
- yMax = y1;
- }
- if (xMin - xt < t3Font->glyphX ||
- yMin - yt < t3Font->glyphY ||
- xMax - xt > t3Font->glyphX + t3Font->glyphW ||
- yMax - yt > t3Font->glyphY + t3Font->glyphH) {
- error(-1, "Bad bounding box in Type 3 glyph");
- return;
- }
-
- // allocate a cache entry
- i = (t3GlyphStack->code & (t3Font->cacheSets - 1)) * t3Font->cacheAssoc;
- for (j = 0; j < t3Font->cacheAssoc; ++j) {
- if ((t3Font->cacheTags[i+j].mru & 0x7fff) == t3Font->cacheAssoc - 1) {
- t3Font->cacheTags[i+j].mru = 0x8000;
- t3Font->cacheTags[i+j].code = t3GlyphStack->code;
- t3GlyphStack->cacheTag = &t3Font->cacheTags[i+j];
- t3GlyphStack->cacheData = t3Font->cacheData + (i+j) * t3Font->glyphSize;
- } else {
- ++t3Font->cacheTags[i+j].mru;
- }
- }
-
- // save state
- t3GlyphStack->origBitmap = bitmap;
- t3GlyphStack->origSplash = splash;
- ctm = state->getCTM();
- t3GlyphStack->origCTM4 = ctm[4];
- t3GlyphStack->origCTM5 = ctm[5];
-
- // create the temporary bitmap
- if (colorMode == splashModeMono1) {
- bitmap = new SplashBitmap(t3Font->glyphW, t3Font->glyphH, splashModeMono1);
- splash = new Splash(bitmap);
- color.mono1 = 0;
- splash->clear(color);
- color.mono1 = 1;
- } else {
- bitmap = new SplashBitmap(t3Font->glyphW, t3Font->glyphH, splashModeMono8);
- splash = new Splash(bitmap);
- color.mono8 = 0x00;
- splash->clear(color);
- color.mono8 = 0xff;
- }
- splash->setFillPattern(new SplashSolidColor(color));
- splash->setStrokePattern(new SplashSolidColor(color));
- //~ this should copy other state from t3GlyphStack->origSplash?
- state->setCTM(ctm[0], ctm[1], ctm[2], ctm[3],
- -t3Font->glyphX, -t3Font->glyphY);
-}
-
-void SplashOutputDev::drawType3Glyph(T3FontCache *t3Font,
- T3FontCacheTag *tag, Guchar *data,
- double x, double y) {
- SplashGlyphBitmap glyph;
-
- glyph.x = -t3Font->glyphX;
- glyph.y = -t3Font->glyphY;
- glyph.w = t3Font->glyphW;
- glyph.h = t3Font->glyphH;
- glyph.aa = colorMode != splashModeMono1;
- glyph.data = data;
- glyph.freeData = gFalse;
- splash->fillGlyph((SplashCoord)x, (SplashCoord)y, &glyph);
-}
-
-void SplashOutputDev::endTextObject(GfxState *state) {
- if (textClipPath) {
- splash->clipToPath(textClipPath, gFalse);
- delete textClipPath;
- textClipPath = NULL;
- }
-}
-
-struct SplashOutImageMaskData {
- ImageStream *imgStr;
- int nPixels, idx;
- GBool invert;
-};
-
-GBool SplashOutputDev::imageMaskSrc(void *data, SplashMono1 *pixel) {
- SplashOutImageMaskData *imgMaskData = (SplashOutImageMaskData *)data;
- Guchar pix;
-
- if (imgMaskData->idx >= imgMaskData->nPixels) {
- return gFalse;
- }
- //~ use getLine
- imgMaskData->imgStr->getPixel(&pix);
- if (!imgMaskData->invert) {
- pix ^= 1;
- }
- *pixel = pix;
- ++imgMaskData->idx;
- return gTrue;
-}
-
-void SplashOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
- int width, int height, GBool invert,
- GBool inlineImg) {
- double *ctm;
- SplashCoord mat[6];
- SplashOutImageMaskData imgMaskData;
- Guchar pix;
-
- ctm = state->getCTM();
- mat[0] = ctm[0];
- mat[1] = ctm[1];
- mat[2] = -ctm[2];
- mat[3] = -ctm[3];
- mat[4] = ctm[2] + ctm[4];
- mat[5] = ctm[3] + ctm[5];
-
- imgMaskData.imgStr = new ImageStream(str, width, 1, 1);
- imgMaskData.imgStr->reset();
- imgMaskData.nPixels = width * height;
- imgMaskData.idx = 0;
- imgMaskData.invert = invert;
-
- splash->fillImageMask(&imageMaskSrc, &imgMaskData, width, height, mat);
- if (inlineImg) {
- while (imageMaskSrc(&imgMaskData, &pix)) ;
- }
-
- delete imgMaskData.imgStr;
-}
-
-struct SplashOutImageData {
- ImageStream *imgStr;
- GfxImageColorMap *colorMap;
- int *maskColors;
- SplashOutputDev *out;
- int nPixels, idx;
-};
-
-GBool SplashOutputDev::imageSrc(void *data, SplashColor *pixel,
- Guchar *alpha) {
- SplashOutImageData *imgData = (SplashOutImageData *)data;
- Guchar pix[gfxColorMaxComps];
- GfxRGB rgb;
- double gray;
- int i;
-
- if (imgData->idx >= imgData->nPixels) {
- return gFalse;
- }
-
- //~ use getLine
- imgData->imgStr->getPixel(pix);
- switch (imgData->out->colorMode) {
- case splashModeMono1:
- case splashModeMono8:
- imgData->colorMap->getGray(pix, &gray);
- pixel->mono8 = soutRound(255 * gray);
- break;
- case splashModeRGB8:
- case splashModeRGB8Packed:
- imgData->colorMap->getRGB(pix, &rgb);
- pixel->rgb8 = splashMakeRGB8(soutRound(255 * rgb.r),
- soutRound(255 * rgb.g),
- soutRound(255 * rgb.b));
- break;
- case splashModeBGR8Packed:
- imgData->colorMap->getRGB(pix, &rgb);
- pixel->bgr8 = splashMakeBGR8(soutRound(255 * rgb.r),
- soutRound(255 * rgb.g),
- soutRound(255 * rgb.b));
- break;
- }
-
- if (imgData->maskColors) {
- *alpha = 0;
- for (i = 0; i < imgData->colorMap->getNumPixelComps(); ++i) {
- if (pix[i] < imgData->maskColors[2*i] ||
- pix[i] > imgData->maskColors[2*i+1]) {
- *alpha = 1;
- break;
- }
- }
- } else {
- *alpha = 1;
- }
-
- ++imgData->idx;
- return gTrue;
-}
-
-void SplashOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
- int width, int height,
- GfxImageColorMap *colorMap,
- int *maskColors, GBool inlineImg) {
- double *ctm;
- SplashCoord mat[6];
- SplashOutImageData imgData;
- SplashColor pix;
- Guchar alpha;
-
- ctm = state->getCTM();
- mat[0] = ctm[0];
- mat[1] = ctm[1];
- mat[2] = -ctm[2];
- mat[3] = -ctm[3];
- mat[4] = ctm[2] + ctm[4];
- mat[5] = ctm[3] + ctm[5];
-
- imgData.imgStr = new ImageStream(str, width,
- colorMap->getNumPixelComps(),
- colorMap->getBits());
- imgData.imgStr->reset();
- imgData.colorMap = colorMap;
- imgData.maskColors = maskColors;
- imgData.out = this;
- imgData.nPixels = width * height;
- imgData.idx = 0;
-
- splash->drawImage(&imageSrc, &imgData,
- (colorMode == splashModeMono1) ? splashModeMono8
- : colorMode,
- width, height, mat);
- if (inlineImg) {
- while (imageSrc(&imgData, &pix, &alpha)) ;
- }
-
- delete imgData.imgStr;
-}
-
-int SplashOutputDev::getBitmapWidth() {
- return bitmap->getWidth();
-}
-
-int SplashOutputDev::getBitmapHeight() {
- return bitmap->getHeight();
-}
-
-void SplashOutputDev::xorRectangle(int x0, int y0, int x1, int y1,
- SplashPattern *pattern) {
- SplashPath *path;
-
- path = new SplashPath();
- path->moveTo((SplashCoord)x0, (SplashCoord)y0);
- path->lineTo((SplashCoord)x1, (SplashCoord)y0);
- path->lineTo((SplashCoord)x1, (SplashCoord)y1);
- path->lineTo((SplashCoord)x0, (SplashCoord)y1);
- path->close();
- splash->setFillPattern(pattern);
- splash->xorFill(path, gTrue);
- delete path;
-}
-
-void SplashOutputDev::setFillColor(int r, int g, int b) {
- GfxRGB rgb;
- double gray;
-
- rgb.r = r / 255.0;
- rgb.g = g / 255.0;
- rgb.b = b / 255.0;
- gray = 0.299 * rgb.r + 0.587 * rgb.g + 0.114 * rgb.g;
- splash->setFillPattern(getColor(gray, &rgb));
-}
-
-SplashFont *SplashOutputDev::getFont(GString *name, double *mat) {
- DisplayFontParam *dfp;
- Ref ref;
- SplashOutFontFileID *id;
- SplashFontFile *fontFile;
- SplashFont *fontObj;
- int i;
-
- for (i = 0; i < 16; ++i) {
- if (!name->cmp(splashOutSubstFonts[i].name)) {
- break;
- }
- }
- if (i == 16) {
- return NULL;
- }
- ref.num = i;
- ref.gen = -1;
- id = new SplashOutFontFileID(&ref);
-
- // check the font file cache
- if ((fontFile = fontEngine->getFontFile(id))) {
- delete id;
-
- // load the font file
- } else {
- dfp = globalParams->getDisplayFont(name);
- if (dfp->kind != displayFontT1) {
- return NULL;
- }
- fontFile = fontEngine->loadType1Font(id, dfp->t1.fileName->getCString(),
- gFalse, winAnsiEncoding);
- }
-
- // create the scaled font
- fontObj = fontEngine->getFont(fontFile, (SplashCoord *)mat);
-
- return fontObj;
-}