fofi/FoFiTrueType.cc | 9 +++++++++ fofi/FoFiTrueType.h | 7 +++++++ poppler/GfxFont.cc | 1 + poppler/GfxFont.h | 9 ++++++++- poppler/PSOutputDev.cc | 26 ++++++++++++++++++++++++++ poppler/PSOutputDev.h | 1 + 6 files changed, 52 insertions(+), 1 deletion(-) diff --git a/fofi/FoFiTrueType.cc b/fofi/FoFiTrueType.cc index 11699dd..ccfa516 100644 --- a/fofi/FoFiTrueType.cc +++ b/fofi/FoFiTrueType.cc @@ -304,6 +304,7 @@ FoFiTrueType::FoFiTrueType(char *fileA, int lenA, GBool freeFileDataA, int faceI nTables = 0; cmaps = NULL; nCmaps = 0; + maxValidGlyph = -1; nameToGID = NULL; parsedOk = gFalse; faceIndex = faceIndexA; @@ -754,6 +755,13 @@ void FoFiTrueType::convertToType0(char *psName, int *cidMap, int nCIDs, // that refers to one of the unused glyphs -- this results in PS // errors if we simply use maxUsedGlyph+1 for the Type 0 font. So // we compromise by always defining at least 256 glyphs.) + // Some fonts have a large nGlyphs but maxUsedGlyph of 0. + // These fonts might reference any glyph. + // Save the last written glyph number in maxValidGlyph. + // PSOutputDev::drawString() can use maxValidGlyph to avoid + // referencing zero-length glyphs that we trimmed. + // This allows pdftops to avoid writing huge files while still + // handling the rare PDF that uses a zero-length glyph. if (cidMap) { n = nCIDs; } else if (nGlyphs > maxUsedGlyph + 256) { @@ -765,6 +773,7 @@ void FoFiTrueType::convertToType0(char *psName, int *cidMap, int nCIDs, } else { n = nGlyphs; } + maxValidGlyph = n-1; for (i = 0; i < n; i += 256) { (*outputFunc)(outputStream, "10 dict begin\n", 14); (*outputFunc)(outputStream, "/FontName /", 11); diff --git a/fofi/FoFiTrueType.h b/fofi/FoFiTrueType.h index b40a44a..1923727 100644 --- a/fofi/FoFiTrueType.h +++ b/fofi/FoFiTrueType.h @@ -163,6 +163,12 @@ public: // setup vert/vrt2 GSUB for specified lang int setupGSUB(const char *scriptName, const char* languageName); + // Return the last glyph written to the font. + // This might be smaller than the number of glyphs in the font if nGlyphs > maxUsedGlyph. + // This value helps detect if a string contains an unused glyph position that we did not + // write into the font when generating PS Level 1 or 2. + int getMaxValidGlyph() { return maxValidGlyph; } + private: FoFiTrueType(char *fileA, int lenA, GBool freeFileDataA, int faceIndexA); @@ -195,6 +201,7 @@ private: TrueTypeCmap *cmaps; int nCmaps; int nGlyphs; + int maxValidGlyph; int locaFmt; int bbox[4]; GooHash *nameToGID; diff --git a/poppler/GfxFont.cc b/poppler/GfxFont.cc index ea23e03..511e882 100644 --- a/poppler/GfxFont.cc +++ b/poppler/GfxFont.cc @@ -251,6 +251,7 @@ GfxFont::GfxFont(const char *tagA, Ref idA, GooString *nameA, refCnt = 1; encodingName = new GooString(""); hasToUnicode = gFalse; + maxValidGlyph = -1; } GfxFont::~GfxFont() { diff --git a/poppler/GfxFont.h b/poppler/GfxFont.h index 85bdea1..9bb1e11 100644 --- a/poppler/GfxFont.h +++ b/poppler/GfxFont.h @@ -199,7 +199,7 @@ public: // Get font weight. Weight getWeight() { return weight; } - // Get the original font name (ignornig any munging that might have + // Get the original font name (ignoring any munging that might have // been done to map to a canonical Base-14 font name). GooString *getName() { return name; } @@ -281,6 +281,12 @@ public: // http://sourceforge.net/adobe/aglfn/wiki/AGL%20Specification/ static const char *getAlternateName(const char *name); + // Return the largest glyph written to the font or -1 if unknown. + int getMaxValidGlyph() { return maxValidGlyph; } + + // Set the largest glyph + void setMaxValidGlyph(int m) { maxValidGlyph = m; } + protected: virtual ~GfxFont(); @@ -310,6 +316,7 @@ protected: GBool ok; GBool hasToUnicode; GooString *encodingName; + int maxValidGlyph; // last glyph in the font or -1 }; //------------------------------------------------------------------------ diff --git a/poppler/PSOutputDev.cc b/poppler/PSOutputDev.cc index 204f16e..dba13bf 100644 --- a/poppler/PSOutputDev.cc +++ b/poppler/PSOutputDev.cc @@ -1101,6 +1101,7 @@ PSOutputDev::PSOutputDev(const char *fileName, PDFDoc *doc, fontIDs = NULL; fontNames = new GooHash(gTrue); + fontMaxValidGlyph = new GooHash(gTrue); t1FontNames = NULL; font8Info = NULL; font16Enc = NULL; @@ -1169,6 +1170,7 @@ PSOutputDev::PSOutputDev(PSOutputFunc outputFuncA, void *outputStreamA, fontIDs = NULL; fontNames = new GooHash(gTrue); + fontMaxValidGlyph = new GooHash(gTrue); t1FontNames = NULL; font8Info = NULL; font16Enc = NULL; @@ -1494,6 +1496,7 @@ PSOutputDev::~PSOutputDev() { gfree(fontIDs); } delete fontNames; + delete fontMaxValidGlyph; if (t1FontNames) { for (i = 0; i < t1FontNameLen; ++i) { delete t1FontNames[i].psName; @@ -2611,6 +2614,8 @@ void PSOutputDev::setupExternalCIDTrueTypeFont(GfxFont *font, needVerticalMetrics, outputFunc, outputStream); } + font->setMaxValidGlyph(ffTT->getMaxValidGlyph()); + fontMaxValidGlyph->replace(font->getName()->copy(), ffTT->getMaxValidGlyph()); gfree(codeToGID); } else { error(errSyntaxError, -1, @@ -2708,6 +2713,8 @@ void PSOutputDev::setupEmbeddedCIDTrueTypeFont(GfxFont *font, Ref *id, needVerticalMetrics, outputFunc, outputStream); } + font->setMaxValidGlyph(ffTT->getMaxValidGlyph()); + fontMaxValidGlyph->replace(font->getName()->copy(), ffTT->getMaxValidGlyph()); delete ffTT; } gfree(fontBuf); @@ -2765,6 +2772,8 @@ void PSOutputDev::setupEmbeddedOpenTypeCFFFont(GfxFont *font, Ref *id, ((GfxCIDFont *)font)->getCIDToGIDLen(), outputFunc, outputStream); } + font->setMaxValidGlyph(ffTT->getMaxValidGlyph()); + fontMaxValidGlyph->replace(font->getName()->copy(), ffTT->getMaxValidGlyph()); } delete ffTT; } @@ -5059,6 +5068,8 @@ void PSOutputDev::drawString(GfxState *state, GooString *s) { char buf[8]; double *dxdy; int dxdySize, len, nChars, uLen, n, m, i, j; + int maxGlyphInt; + CharCode maxGlyph; // for pdftohtml, output PS without text if( displayText == gFalse ) @@ -5078,6 +5089,13 @@ void PSOutputDev::drawString(GfxState *state, GooString *s) { if (!(font = state->getFont())) { return; } + maxGlyphInt = font->getMaxValidGlyph(); + if (maxGlyphInt < 0) { + maxGlyphInt = fontMaxValidGlyph->lookupInt(font->getName()); + if (maxGlyphInt < 0) maxGlyphInt = 0; + font->setMaxValidGlyph( maxGlyphInt ); + } + maxGlyph = (CharCode) maxGlyphInt; wMode = font->getWMode(); // check for a subtitute 16-bit font @@ -5152,6 +5170,14 @@ void PSOutputDev::drawString(GfxState *state, GooString *s) { dxdy[2 * nChars + 1] = dy; ++nChars; } + } else if (maxGlyph > 0 && code > maxGlyph) { + // Ignore this code. + // Using it will exceed the number of glyphs in the font and generate + // /rangecheck in --xyshow-- + if (nChars > 0) { + dxdy[2 * (nChars-1) ] += dx; + dxdy[2 * (nChars-1) + 1 ] += dy; + } } else { if (nChars + 1 > dxdySize) { dxdySize *= 2; diff --git a/poppler/PSOutputDev.h b/poppler/PSOutputDev.h index 3aea223..a595f13 100644 --- a/poppler/PSOutputDev.h +++ b/poppler/PSOutputDev.h @@ -471,6 +471,7 @@ private: int fontIDSize; // size of fontIDs array std::set resourceIDs; // list of object IDs of objects containing Resources we've already set up GooHash *fontNames; // all used font names + GooHash *fontMaxValidGlyph; // max valid glyph of each font PST1FontName *t1FontNames; // font names for Type 1/1C fonts int t1FontNameLen; // number of entries in t1FontNames array int t1FontNameSize; // size of t1FontNames array