Browse Source

Slightly refactor the `fontRef` handling in `PartialEvaluator_loadFont` (issue 7403 and issue 7402)

Originally, I was just going to change this code to use `Ref_toString` in a couple more places. When I started reading the code, I figured that it wouldn't hurt to clean up a couple of comments. While doing this, I noticed that the logic for the (rare) `isDict(fontRef)` case could do with a few improvements.

There should be no functional changes with this patch, but given the added reference checks, we will now avoid bogus `Ref`s when resolving font aliases. In practice, as issue 7403 shows, the current code can break certain PDF files even if it's very rare.

Note that the only thing that this patch will change, is the `font.loadedName` in the case where a `fontRef` is a reference *and* the font doesn't have a descriptor. Previously for `fontRef = Ref(4, 0)` we'd get `font.loadedName = 'g_d0_f4_0'`, and with this patch `font.loadedName = g_d0_f4R`, which is actually one character shorted in most cases. (Given that `Ref_toString` contains an optimization for the `gen === 0` case, which is by far the most common `gen` value.)

In the already existing fallback case, where the `fontName` is used to when creating the `font.loadedName`, we allow any alphanumeric character. Hence I don't see how (as mentioned above) e.g. `font.loadedName = g_d0_f4R` would be an issue here.
Jonas Jenwald 9 years ago
parent
commit
2e9cd3ea64
  1. 45
      src/core/evaluator.js

45
src/core/evaluator.js

@ -662,8 +662,8 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
return errorFont(); return errorFont();
} }
// We are holding font.translated references just for fontRef that are not // We are holding `font.translated` references just for `fontRef`s that
// dictionaries (Dict). See explanation below. // are not actually `Ref`s, but rather `Dict`s. See explanation below.
if (font.translated) { if (font.translated) {
return font.translated; return font.translated;
} }
@ -672,7 +672,12 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
var preEvaluatedFont = this.preEvaluateFont(font, xref); var preEvaluatedFont = this.preEvaluateFont(font, xref);
var descriptor = preEvaluatedFont.descriptor; var descriptor = preEvaluatedFont.descriptor;
var fontID = fontRef.num + '_' + fontRef.gen;
var fontRefIsRef = isRef(fontRef), fontID;
if (fontRefIsRef) {
fontID = fontRef.toString();
}
if (isDict(descriptor)) { if (isDict(descriptor)) {
if (!descriptor.fontAliases) { if (!descriptor.fontAliases) {
descriptor.fontAliases = Object.create(null); descriptor.fontAliases = Object.create(null);
@ -682,36 +687,40 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
var hash = preEvaluatedFont.hash; var hash = preEvaluatedFont.hash;
if (fontAliases[hash]) { if (fontAliases[hash]) {
var aliasFontRef = fontAliases[hash].aliasRef; var aliasFontRef = fontAliases[hash].aliasRef;
if (aliasFontRef && this.fontCache.has(aliasFontRef)) { if (fontRefIsRef && aliasFontRef &&
this.fontCache.has(aliasFontRef)) {
this.fontCache.putAlias(fontRef, aliasFontRef); this.fontCache.putAlias(fontRef, aliasFontRef);
return this.fontCache.get(fontRef); return this.fontCache.get(fontRef);
} }
} } else {
if (!fontAliases[hash]) {
fontAliases[hash] = { fontAliases[hash] = {
fontID: Font.getFontID() fontID: Font.getFontID()
}; };
} }
if (fontRefIsRef) {
fontAliases[hash].aliasRef = fontRef; fontAliases[hash].aliasRef = fontRef;
}
fontID = fontAliases[hash].fontID; fontID = fontAliases[hash].fontID;
} }
// Workaround for bad PDF generators that don't reference fonts // Workaround for bad PDF generators that reference fonts incorrectly,
// properly, i.e. by not using an object identifier. // where `fontRef` is a `Dict` rather than a `Ref` (fixes bug946506.pdf).
// Check if the fontRef is a Dict (as opposed to a standard object), // In this case we cannot cache the font, since it's not possible to use
// in which case we don't cache the font and instead reference it by // a `Dict` as a key in `this.fontCache` (since it's a `RefSetCache`).
// fontName in font.loadedName below. // Furthermore, if the `fontID` is undefined, we instead reference
var fontRefIsDict = isDict(fontRef); // the font by `fontName` in `font.loadedName` below.
if (!fontRefIsDict) { if (fontRefIsRef) {
this.fontCache.put(fontRef, fontCapability.promise); this.fontCache.put(fontRef, fontCapability.promise);
} else {
if (!fontID) {
fontID = (this.uniquePrefix || 'F_') + (++this.idCounters.obj);
}
} }
// Keep track of each font we translated so the caller can // Keep track of each font we translated so the caller can
// load them asynchronously before calling display on a page. // load them asynchronously before calling display on a page.
font.loadedName = 'g_' + this.pdfManager.docId + '_f' + (fontRefIsDict ? font.loadedName = 'g_' + this.pdfManager.docId + '_f' + fontID;
fontName.replace(/\W/g, '') : fontID);
font.translated = fontCapability.promise; font.translated = fontCapability.promise;
@ -2115,7 +2124,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
if (isName(encoding)) { if (isName(encoding)) {
hash.update(encoding.name); hash.update(encoding.name);
} else if (isRef(encoding)) { } else if (isRef(encoding)) {
hash.update(encoding.num + '_' + encoding.gen); hash.update(encoding.toString());
} else if (isDict(encoding)) { } else if (isDict(encoding)) {
var keys = encoding.getKeys(); var keys = encoding.getKeys();
for (var i = 0, ii = keys.length; i < ii; i++) { for (var i = 0, ii = keys.length; i < ii; i++) {
@ -2123,7 +2132,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
if (isName(entry)) { if (isName(entry)) {
hash.update(entry.name); hash.update(entry.name);
} else if (isRef(entry)) { } else if (isRef(entry)) {
hash.update(entry.num + '_' + entry.gen); hash.update(entry.toString());
} else if (isArray(entry)) { // 'Differences' entry. } else if (isArray(entry)) { // 'Differences' entry.
// Ideally we should check the contents of the array, but to avoid // Ideally we should check the contents of the array, but to avoid
// parsing it here and then again in |extractDataStructures|, // parsing it here and then again in |extractDataStructures|,

Loading…
Cancel
Save