diff options
author | Akira Kakuto <kakuto@fuk.kindai.ac.jp> | 2017-08-13 07:14:48 +0000 |
---|---|---|
committer | Akira Kakuto <kakuto@fuk.kindai.ac.jp> | 2017-08-13 07:14:48 +0000 |
commit | 4b4995cda35627e06c43e25ecbe07c1bc1859bb5 (patch) | |
tree | 143ed02a389bab62f44043a54cbc70f69e312e2f /Build/source/libs/xpdf/xpdf-src/xpdf/GfxFont.cc | |
parent | 00d00899c484b81967558f43c4fe4a896ffdf610 (diff) |
xpdf 4.00
git-svn-id: svn://tug.org/texlive/trunk@45031 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Build/source/libs/xpdf/xpdf-src/xpdf/GfxFont.cc')
-rw-r--r-- | Build/source/libs/xpdf/xpdf-src/xpdf/GfxFont.cc | 565 |
1 files changed, 386 insertions, 179 deletions
diff --git a/Build/source/libs/xpdf/xpdf-src/xpdf/GfxFont.cc b/Build/source/libs/xpdf/xpdf-src/xpdf/GfxFont.cc index 0ebb5b95cc8..201f609adbf 100644 --- a/Build/source/libs/xpdf/xpdf-src/xpdf/GfxFont.cc +++ b/Build/source/libs/xpdf/xpdf-src/xpdf/GfxFont.cc @@ -18,10 +18,10 @@ #include <ctype.h> #include <math.h> #include <limits.h> -#if HAVE_STD_SORT -#include <algorithm> -#endif #include "gmem.h" +#include "gmempp.h" +#include "GList.h" +#include "GHash.h" #include "Error.h" #include "Object.h" #include "Dict.h" @@ -206,6 +206,7 @@ GfxFont::GfxFont(char *tagA, Ref idA, GString *nameA, type = typeA; embFontID = embFontIDA; embFontName = NULL; + hasToUnicode = gFalse; } GfxFont::~GfxFont() { @@ -414,7 +415,7 @@ GfxFontType GfxFont::getFontType(XRef *xref, Dict *fontDict, Ref *embID) { void GfxFont::readFontDescriptor(XRef *xref, Dict *fontDict) { Object obj1, obj2, obj3, obj4; - double t; + double t, t2; int i; // assume Times-Roman by default (for substitution purposes) @@ -444,13 +445,33 @@ void GfxFont::readFontDescriptor(XRef *xref, Dict *fontDict) { } obj2.free(); - // get Ascent and Descent + // get Ascent + // (CapHeight is a little more reliable - so use it if present) obj1.dictLookup("Ascent", &obj2); - if (obj2.isNum()) { - t = 0.001 * obj2.getNum(); - // some broken font descriptors specify a negative ascent - if (t < 0) { - t = -t; + obj1.dictLookup("CapHeight", &obj3); + if (obj2.isNum() || obj3.isNum()) { + if (obj2.isNum()) { + t = 0.001 * obj2.getNum(); + // some broken font descriptors specify a negative ascent + if (t < 0) { + t = -t; + } + } else { + t = 0; + } + if (obj3.isNum()) { + t2 = 0.001 * obj3.getNum(); + // some broken font descriptors specify a negative ascent + if (t2 < 0) { + t2 = -t2; + } + } else { + t2 = 0; + } + // if both Ascent and CapHeight are set, use the smaller one + // (because the most common problem is that Ascent is too large) + if (t2 != 0 && (t == 0 || t2 < t)) { + t = t2; } // some broken font descriptors set ascent and descent to 0; // others set it to ridiculous values (e.g., 32768) @@ -459,6 +480,9 @@ void GfxFont::readFontDescriptor(XRef *xref, Dict *fontDict) { } } obj2.free(); + obj3.free(); + + // get Descent obj1.dictLookup("Descent", &obj2); if (obj2.isNum()) { t = 0.001 * obj2.getNum(); @@ -512,6 +536,7 @@ CharCodeToUnicode *GfxFont::readToUnicodeCMap(Dict *fontDict, int nBits, ctu = CharCodeToUnicode::parseCMap(buf, nBits); } delete buf; + hasToUnicode = gTrue; return ctu; } @@ -847,7 +872,6 @@ Gfx8BitFont::Gfx8BitFont(XRef *xref, char *tagA, Ref idA, GString *nameA, GString *name2; BuiltinFont *builtinFont; const char **baseEnc; - GBool baseEncFromFontFile; char *buf; int len; FoFiType1 *ffT1; @@ -924,9 +948,9 @@ Gfx8BitFont::Gfx8BitFont(XRef *xref, char *tagA, Ref idA, GString *nameA, // get info from font descriptor readFontDescriptor(xref, fontDict); - // for non-embedded fonts, don't trust the ascent/descent/bbox - // values from the font descriptor - if (builtinFont && embFontID.num < 0) { + // for Base-14 fonts (even if embedded), don't trust the + // ascent/descent/bbox values from the font descriptor + if (builtinFont) { ascent = 0.001 * builtinFont->ascent; descent = 0.001 * builtinFont->descent; fontBBox[0] = 0.001 * builtinFont->bbox[0]; @@ -1137,14 +1161,14 @@ Gfx8BitFont::Gfx8BitFont(XRef *xref, char *tagA, Ref idA, GString *nameA, // name that looks like 'Axx' or 'xx', where 'A' is any letter // and 'xx' is two hex digits if ((strlen(charName) == 3 && - isalpha(charName[0]) && - isxdigit(charName[1]) && isxdigit(charName[2]) && + isalpha(charName[0] & 0xff) && + isxdigit(charName[1] & 0xff) && isxdigit(charName[2] & 0xff) && ((charName[1] >= 'a' && charName[1] <= 'f') || (charName[1] >= 'A' && charName[1] <= 'F') || (charName[2] >= 'a' && charName[2] <= 'f') || (charName[2] >= 'A' && charName[2] <= 'F'))) || (strlen(charName) == 2 && - isxdigit(charName[0]) && isxdigit(charName[1]) && + isxdigit(charName[0] & 0xff) && isxdigit(charName[1] & 0xff) && ((charName[0] >= 'a' && charName[0] <= 'f') || (charName[0] >= 'A' && charName[0] <= 'F') || (charName[1] >= 'a' && charName[1] <= 'f') || @@ -1169,35 +1193,40 @@ Gfx8BitFont::Gfx8BitFont(XRef *xref, char *tagA, Ref idA, GString *nameA, // use 'uni0628.medi', etc.) // where 'A' and 'B' are any letters, 'xx' is two hex digits, 'xxxx' // is four hex digits, and 'nn' is 2-4 decimal digits + usedNumericHeuristic = gFalse; if (missing && globalParams->getMapNumericCharNames()) { for (code = 0; code < 256; ++code) { if ((charName = enc[code]) && !toUnicode[code] && strcmp(charName, ".notdef")) { n = (int)strlen(charName); code2 = -1; - if (hex && n == 3 && isalpha(charName[0]) && - isxdigit(charName[1]) && isxdigit(charName[2])) { + if (hex && n == 3 && isalpha(charName[0] & 0xff) && + isxdigit(charName[1] & 0xff) && isxdigit(charName[2] & 0xff)) { sscanf(charName+1, "%x", &code2); } else if (hex && n == 2 && - isxdigit(charName[0]) && isxdigit(charName[1])) { + isxdigit(charName[0] & 0xff) && + isxdigit(charName[1] & 0xff)) { sscanf(charName, "%x", &code2); } else if (!hex && n >= 2 && n <= 4 && - isdigit(charName[0]) && isdigit(charName[1])) { + isdigit(charName[0] & 0xff) && isdigit(charName[1] & 0xff)) { code2 = atoi(charName); } else if (n >= 3 && n <= 5 && - isdigit(charName[1]) && isdigit(charName[2])) { + isdigit(charName[1] & 0xff) && isdigit(charName[2] & 0xff)) { code2 = atoi(charName+1); } else if (n >= 4 && n <= 6 && - isdigit(charName[2]) && isdigit(charName[3])) { + isdigit(charName[2] & 0xff) && isdigit(charName[3] & 0xff)) { code2 = atoi(charName+2); } else if (n >= 7 && charName[0] == 'u' && charName[1] == 'n' && charName[2] == 'i' && - isxdigit(charName[3]) && isxdigit(charName[4]) && - isxdigit(charName[5]) && isxdigit(charName[6])) { + isxdigit(charName[3] & 0xff) && + isxdigit(charName[4] & 0xff) && + isxdigit(charName[5] & 0xff) && + isxdigit(charName[6] & 0xff)) { sscanf(charName + 3, "%x", &code2); } if (code2 >= 0 && code2 <= 0xffff) { toUnicode[code] = (Unicode)code2; + usedNumericHeuristic = gTrue; } } } @@ -1406,7 +1435,7 @@ int *Gfx8BitFont::getCodeToGIDMap(FoFiTrueType *ff) { cmapPlatform = ff->getCmapPlatform(i); cmapEncoding = ff->getCmapEncoding(i); if ((cmapPlatform == 3 && cmapEncoding == 1) || - cmapPlatform == 0) { + (cmapPlatform == 0 && cmapEncoding <= 4)) { unicodeCmap = i; } else if (cmapPlatform == 1 && cmapEncoding == 0) { macRomanCmap = i; @@ -1512,39 +1541,64 @@ Dict *Gfx8BitFont::getResources() { return resources.isDict() ? resources.getDict() : (Dict *)NULL; } -//------------------------------------------------------------------------ -// GfxCIDFont -//------------------------------------------------------------------------ - -#if HAVE_STD_SORT +GBool Gfx8BitFont::problematicForUnicode() { + GString *nameLC; + GBool symbolic; + + // potential inputs: + // - font is embedded (GfxFont.embFontID.num >= 0) + // - font name (GfxFont.name) + // - font type (GfxFont.type) + // - Base-14 font (Gfx8BitFont.base14 != NULL) + // - symbolic (GfxFont.flags & fontSymbolic) + // - has Encoding array (Gfx8BitFont.hasEncoding) + // - extracted base encoding from embedded font file + // (Gfx8BitFont.baseEncFromFontFile) + // - has a ToUnicode map (GfxFont.hasToUnicode) + // - used the numeric glyph name heuristic + // (Gfx8BitFont.usedNumericHeuristic) -struct cmpWidthExcepFunctor { - bool operator()(const GfxFontCIDWidthExcep &w1, - const GfxFontCIDWidthExcep &w2) { - return w1.first < w2.first; + if (name) { + nameLC = name->copy(); + nameLC->lowerCase(); + symbolic = strstr(nameLC->getCString(), "dingbat") || + strstr(nameLC->getCString(), "wingding") || + strstr(nameLC->getCString(), "commpi"); + delete nameLC; + if (symbolic) { + return gFalse; + } } -}; -struct cmpWidthExcepVFunctor { - bool operator()(const GfxFontCIDWidthExcepV &w1, - const GfxFontCIDWidthExcepV &w2) { - return w1.first < w2.first; - } -}; + if (embFontID.num >= 0) { + switch (type) { + case fontType1: + case fontType1C: + case fontType1COT: + return !hasToUnicode && (!hasEncoding || usedNumericHeuristic); -#else // HAVE_STD_SORT + case fontType3: + return !hasToUnicode && !hasEncoding; -static int CDECL cmpWidthExcep(const void *w1, const void *w2) { - return ((GfxFontCIDWidthExcep *)w1)->first - - ((GfxFontCIDWidthExcep *)w2)->first; -} + case fontTrueType: + case fontTrueTypeOT: + return !hasToUnicode && !hasEncoding; -static int CDECL cmpWidthExcepV(const void *w1, const void *w2) { - return ((GfxFontCIDWidthExcepV *)w1)->first - - ((GfxFontCIDWidthExcepV *)w2)->first; + default: + return !hasToUnicode; + } + + } else { + // NB: type will be fontTypeUnknown if the PDF specifies an + // invalid font type -- which is ok, if we have a ToUnicode map or + // an encoding + return !hasToUnicode && !hasEncoding; + } } -#endif +//------------------------------------------------------------------------ +// GfxCIDFont +//------------------------------------------------------------------------ GfxCIDFont::GfxCIDFont(XRef *xref, char *tagA, Ref idA, GString *nameA, GfxFontType typeA, Ref embFontIDA, Dict *fontDict): @@ -1615,6 +1669,7 @@ GfxCIDFont::GfxCIDFont(XRef *xref, char *tagA, Ref idA, GString *nameA, obj1.free(); // look for a ToUnicode CMap + hasKnownCollection = gFalse; if (!(ctu = readToUnicodeCMap(fontDict, 16, NULL))) { ctuUsesCharCode = gFalse; @@ -1625,25 +1680,36 @@ GfxCIDFont::GfxCIDFont(XRef *xref, char *tagA, Ref idA, GString *nameA, ctu = CharCodeToUnicode::makeIdentityMapping(); // look for a user-supplied .cidToUnicode file - } else if (!(ctu = globalParams->getCIDToUnicode(collection))) { + } else if ((ctu = globalParams->getCIDToUnicode(collection))) { + hasKnownCollection = gTrue; + + } else { error(errSyntaxError, -1, "Unknown character collection '{0:t}'", collection); + + // fall back to an identity mapping + ctu = CharCodeToUnicode::makeIdentityMapping(); } } // look for a Unicode-to-Unicode mapping if (name && (utu = globalParams->getUnicodeToUnicode(name))) { if (ctu) { - for (c = 0; c < ctu->getLength(); ++c) { - n = ctu->mapToUnicode(c, uBuf, 8); - if (n >= 1) { - n = utu->mapToUnicode((CharCode)uBuf[0], uBuf, 8); + if (ctu->isIdentity()) { + ctu->decRefCnt(); + ctu = utu; + } else { + for (c = 0; c < ctu->getLength(); ++c) { + n = ctu->mapToUnicode(c, uBuf, 8); if (n >= 1) { - ctu->setMapping(c, uBuf, n); + n = utu->mapToUnicode((CharCode)uBuf[0], uBuf, 8); + if (n >= 1) { + ctu->setMapping(c, uBuf, n); + } } } + utu->decRefCnt(); } - utu->decRefCnt(); } else { ctu = utu; } @@ -1660,29 +1726,31 @@ GfxCIDFont::GfxCIDFont(XRef *xref, char *tagA, Ref idA, GString *nameA, obj1.free(); // CIDToGIDMap - // (the PDF spec only allows these for TrueType fonts, but Acrobat - // apparently also allows them for OpenType CFF fonts) - if (type == fontCIDType2 || type == fontCIDType0COT) { - desFontDict->lookup("CIDToGIDMap", &obj1); - if (obj1.isStream()) { - cidToGIDLen = 0; - i = 64; - cidToGID = (int *)gmallocn(i, sizeof(int)); - obj1.streamReset(); - while ((c1 = obj1.streamGetChar()) != EOF && - (c2 = obj1.streamGetChar()) != EOF) { - if (cidToGIDLen == i) { - i *= 2; - cidToGID = (int *)greallocn(cidToGID, i, sizeof(int)); - } - cidToGID[cidToGIDLen++] = (c1 << 8) + c2; + // (the PDF 1.7 spec only allows these for TrueType fonts, but + // Acrobat apparently also allows them for OpenType CFF fonts -- and + // the PDF 2.0 spec has removed the prohibition) + hasIdentityCIDToGID = gFalse; + desFontDict->lookup("CIDToGIDMap", &obj1); + if (obj1.isStream()) { + cidToGIDLen = 0; + i = 64; + cidToGID = (int *)gmallocn(i, sizeof(int)); + obj1.streamReset(); + while ((c1 = obj1.streamGetChar()) != EOF && + (c2 = obj1.streamGetChar()) != EOF) { + if (cidToGIDLen == i) { + i *= 2; + cidToGID = (int *)greallocn(cidToGID, i, sizeof(int)); } - obj1.streamClose(); - } else if (!obj1.isName("Identity") && !obj1.isNull()) { - error(errSyntaxError, -1, "Invalid CIDToGIDMap entry in CID font"); + cidToGID[cidToGIDLen++] = (c1 << 8) + c2; } - obj1.free(); + obj1.streamClose(); + } else if (obj1.isName("Identity")) { + hasIdentityCIDToGID = gTrue; + } else if (!obj1.isNull()) { + error(errSyntaxError, -1, "Invalid CIDToGIDMap entry in CID font"); } + obj1.free(); //----- character metrics ----- @@ -1744,13 +1812,6 @@ GfxCIDFont::GfxCIDFont(XRef *xref, char *tagA, Ref idA, GString *nameA, obj3.free(); obj2.free(); } -#if HAVE_STD_SORT - std::sort(widths.exceps, widths.exceps + widths.nExceps, - cmpWidthExcepFunctor()); -#else - qsort(widths.exceps, widths.nExceps, sizeof(GfxFontCIDWidthExcep), - &cmpWidthExcep); -#endif } obj1.free(); @@ -1833,13 +1894,6 @@ GfxCIDFont::GfxCIDFont(XRef *xref, char *tagA, Ref idA, GString *nameA, obj3.free(); obj2.free(); } -#if HAVE_STD_SORT - std::sort(widths.excepsV, widths.excepsV + widths.nExcepsV, - cmpWidthExcepVFunctor()); -#else - qsort(widths.excepsV, widths.nExcepsV, sizeof(GfxFontCIDWidthExcepV), - &cmpWidthExcepV); -#endif } obj1.free(); @@ -1879,8 +1933,7 @@ int GfxCIDFont::getNextChar(char *s, int len, CharCode *code, double *dx, double *dy, double *ox, double *oy) { CID cid; CharCode c; - double w, h, vx, vy; - int n, a, b, m; + int n; if (!cMap) { *code = 0; @@ -1902,59 +1955,54 @@ int GfxCIDFont::getNextChar(char *s, int len, CharCode *code, // horizontal if (cMap->getWMode() == 0) { - w = widths.defWidth; - h = vx = vy = 0; - if (widths.nExceps > 0 && cid >= widths.exceps[0].first) { - a = 0; - b = widths.nExceps; - // invariant: widths.exceps[a].first <= cid < widths.exceps[b].first - while (b - a > 1) { - m = (a + b) / 2; - if (widths.exceps[m].first <= cid) { - a = m; - } else { - b = m; - } - } - if (cid <= widths.exceps[a].last) { - w = widths.exceps[a].width; - } - } + getHorizontalMetrics(cid, dx); + *dy = *ox = *oy = 0; // vertical } else { - w = 0; - h = widths.defHeight; - vx = widths.defWidth / 2; - vy = widths.defVY; - if (widths.nExcepsV > 0 && cid >= widths.excepsV[0].first) { - a = 0; - b = widths.nExcepsV; - // invariant: widths.excepsV[a].first <= cid < widths.excepsV[b].first - while (b - a > 1) { - m = (a + b) / 2; - if (widths.excepsV[m].last <= cid) { - a = m; - } else { - b = m; - } - } - if (cid <= widths.excepsV[a].last) { - h = widths.excepsV[a].height; - vx = widths.excepsV[a].vx; - vy = widths.excepsV[a].vy; - } - } + getVerticalMetrics(cid, dy, ox, oy); + *dx = 0; } - *dx = w; - *dy = h; - *ox = vx; - *oy = vy; - return n; } +// NB: Section 9.7.4.3 in the PDF 2.0 spec says that, in the case of +// duplicate entries in the metrics, the first entry should be used. +// This means we need to leave the metrics in the original order and +// perform a linear search. (Or use a more complex data structure.) +void GfxCIDFont::getHorizontalMetrics(CID cid, double *w) { + int i; + for (i = 0; i < widths.nExceps; ++i) { + if (widths.exceps[i].first <= cid && cid <= widths.exceps[i].last) { + *w = widths.exceps[i].width; + return; + } + } + *w = widths.defWidth; +} + +// NB: Section 9.7.4.3 in the PDF 2.0 spec says that, in the case of +// duplicate entries in the metrics, the first entry should be used. +// This means we need to leave the metrics in the original order and +// perform a linear search. (Or use a more complex data structure.) +void GfxCIDFont::getVerticalMetrics(CID cid, double *h, + double *vx, double *vy) { + int i; + for (i = 0; i < widths.nExcepsV; ++i) { + if (widths.excepsV[i].first <= cid && cid <= widths.excepsV[i].last) { + *h = widths.excepsV[i].height; + *vx = widths.excepsV[i].vx; + *vy = widths.excepsV[i].vy; + return; + } + } + *h = widths.defHeight; + getHorizontalMetrics(cid, vx); + *vx /= 2; + *vy = widths.defVY; +} + int GfxCIDFont::getWMode() { return cMap ? cMap->getWMode() : 0; } @@ -1970,43 +2018,97 @@ GString *GfxCIDFont::getCollection() { return cMap ? cMap->getCollection() : (GString *)NULL; } +GBool GfxCIDFont::problematicForUnicode() { + GString *nameLC; + GBool symbolic; + + // potential inputs: + // - font is embedded (GfxFont.embFontID.num >= 0) + // - font name (GfxFont.name) + // - font type (GfxFont.type) + // - symbolic (GfxFont.flags & fontSymbolic) + // - has a ToUnicode map (GfxFont.hasToUnicode) + // - collection is Adobe-Identity or Adobe-UCS + // (GfxCIDFont.collection - compare string) + // - collection is known AdobeCJK (GfxCIDFont.hasKnownCollection) + // - has non-Identity CIDToGIDMap (GfxCIDFont.cidToGID != NULL) + // - has Identity CIDToGIDMap (GfxCIDFont.hasIdentityCIDToGID) + + if (name) { + nameLC = name->copy(); + nameLC->lowerCase(); + symbolic = strstr(nameLC->getCString(), "dingbat") || + strstr(nameLC->getCString(), "wingding") || + strstr(nameLC->getCString(), "commpi"); + delete nameLC; + if (symbolic) { + return gFalse; + } + } + + if (embFontID.num >= 0) { + switch (type) { + case fontCIDType0: + case fontCIDType0C: + case fontCIDType0COT: + return !hasToUnicode && !hasKnownCollection; + + case fontCIDType2: + case fontCIDType2OT: + return !hasToUnicode && !hasKnownCollection; + + default: + return !hasToUnicode; + } + + } else { + return !hasToUnicode; + } +} + //------------------------------------------------------------------------ // GfxFontDict //------------------------------------------------------------------------ GfxFontDict::GfxFontDict(XRef *xref, Ref *fontDictRef, Dict *fontDict) { - int i; + GfxFont *font; + char *tag; Object obj1, obj2; Ref r; + int i; - numFonts = fontDict->getLength(); - fonts = (GfxFont **)gmallocn(numFonts, sizeof(GfxFont *)); - for (i = 0; i < numFonts; ++i) { + fonts = new GHash(gTrue); + uniqueFonts = new GList(); + for (i = 0; i < fontDict->getLength(); ++i) { + tag = fontDict->getKey(i); fontDict->getValNF(i, &obj1); obj1.fetch(xref, &obj2); - if (obj2.isDict()) { + if (!obj2.isDict()) { + error(errSyntaxError, -1, "font resource is not a dictionary"); + } else if (obj1.isRef() && (font = lookupByRef(obj1.getRef()))) { + fonts->add(new GString(tag), font); + } else { if (obj1.isRef()) { r = obj1.getRef(); - } else { - // no indirect reference for this font, so invent a unique one - // (legal generation numbers are five digits, so any 6-digit - // number would be safe) + } else if (fontDictRef) { + // legal generation numbers are five digits, so we use a + // 6-digit number here + r.gen = 100000 + fontDictRef->num; r.num = i; - if (fontDictRef) { - r.gen = 100000 + fontDictRef->num; + } else { + // no indirect reference for this font, or for the containing + // font dict, so hash the font and use that + r.gen = 100000; + r.num = hashFontObject(&obj2); + } + if ((font = GfxFont::makeFont(xref, tag, r, obj2.getDict()))) { + if (!font->isOk()) { + delete font; } else { - r.gen = 999999; + uniqueFonts->append(font); + fonts->add(new GString(tag), font); } } - fonts[i] = GfxFont::makeFont(xref, fontDict->getKey(i), - r, obj2.getDict()); - if (fonts[i] && !fonts[i]->isOk()) { - delete fonts[i]; - fonts[i] = NULL; - } - } else { - error(errSyntaxError, -1, "font resource is not a dictionary"); - fonts[i] = NULL; } obj1.free(); obj2.free(); @@ -2014,36 +2116,141 @@ GfxFontDict::GfxFontDict(XRef *xref, Ref *fontDictRef, Dict *fontDict) { } GfxFontDict::~GfxFontDict() { - int i; - - for (i = 0; i < numFonts; ++i) { - if (fonts[i]) { - delete fonts[i]; - } - } - gfree(fonts); + deleteGList(uniqueFonts, GfxFont); + delete fonts; } GfxFont *GfxFontDict::lookup(char *tag) { + return (GfxFont *)fonts->lookup(tag); +} + +GfxFont *GfxFontDict::lookupByRef(Ref ref) { + GfxFont *font; int i; - for (i = 0; i < numFonts; ++i) { - if (fonts[i] && fonts[i]->matches(tag)) { - return fonts[i]; + for (i = 0; i < uniqueFonts->getLength(); ++i) { + font = (GfxFont *)uniqueFonts->get(i); + if (font->getID()->num == ref.num && + font->getID()->gen == ref.gen) { + return font; } } return NULL; } -GfxFont *GfxFontDict::lookupByRef(Ref ref) { - int i; +int GfxFontDict::getNumFonts() { + return uniqueFonts->getLength(); +} - for (i = 0; i < numFonts; ++i) { - if (fonts[i] && - fonts[i]->getID()->num == ref.num && - fonts[i]->getID()->gen == ref.gen) { - return fonts[i]; +GfxFont *GfxFontDict::getFont(int i) { + return (GfxFont *)uniqueFonts->get(i); +} + +// FNV-1a hash +class FNVHash { +public: + + FNVHash() { + h = 2166136261U; + } + + void hash(char c) { + h ^= c & 0xff; + h *= 16777619; + } + + void hash(char *p, int n) { + int i; + for (i = 0; i < n; ++i) { + hash(p[i]); } } - return NULL; + + int get31() { + return (h ^ (h >> 31)) & 0x7fffffff; + } + +private: + + Guint h; +}; + +int GfxFontDict::hashFontObject(Object *obj) { + FNVHash h; + + hashFontObject1(obj, &h); + return h.get31(); +} + +void GfxFontDict::hashFontObject1(Object *obj, FNVHash *h) { + Object obj2; + GString *s; + char *p; + double r; + int n, i; + + switch (obj->getType()) { + case objBool: + h->hash('b'); + h->hash(obj->getBool() ? 1 : 0); + break; + case objInt: + h->hash('i'); + n = obj->getInt(); + h->hash((char *)&n, sizeof(int)); + break; + case objReal: + h->hash('r'); + r = obj->getReal(); + h->hash((char *)&r, sizeof(double)); + break; + case objString: + h->hash('s'); + s = obj->getString(); + h->hash(s->getCString(), s->getLength()); + break; + case objName: + h->hash('n'); + p = obj->getName(); + h->hash(p, (int)strlen(p)); + break; + case objNull: + h->hash('z'); + break; + case objArray: + h->hash('a'); + n = obj->arrayGetLength(); + h->hash((char *)&n, sizeof(int)); + for (i = 0; i < n; ++i) { + obj->arrayGetNF(i, &obj2); + hashFontObject1(&obj2, h); + obj2.free(); + } + break; + case objDict: + h->hash('d'); + n = obj->dictGetLength(); + h->hash((char *)&n, sizeof(int)); + for (i = 0; i < n; ++i) { + p = obj->dictGetKey(i); + h->hash(p, (int)strlen(p)); + obj->dictGetValNF(i, &obj2); + hashFontObject1(&obj2, h); + obj2.free(); + } + break; + case objStream: + // this should never happen - streams must be indirect refs + break; + case objRef: + h->hash('f'); + n = obj->getRefNum(); + h->hash((char *)&n, sizeof(int)); + n = obj->getRefGen(); + h->hash((char *)&n, sizeof(int)); + break; + default: + h->hash('u'); + break; + } } |