summaryrefslogtreecommitdiff
path: root/Build/source/libs/xpdf/xpdf-src/xpdf/GfxFont.cc
diff options
context:
space:
mode:
authorAkira Kakuto <kakuto@fuk.kindai.ac.jp>2017-08-13 07:14:48 +0000
committerAkira Kakuto <kakuto@fuk.kindai.ac.jp>2017-08-13 07:14:48 +0000
commit4b4995cda35627e06c43e25ecbe07c1bc1859bb5 (patch)
tree143ed02a389bab62f44043a54cbc70f69e312e2f /Build/source/libs/xpdf/xpdf-src/xpdf/GfxFont.cc
parent00d00899c484b81967558f43c4fe4a896ffdf610 (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.cc565
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;
+ }
}