diff --git a/src/core/evaluator.js b/src/core/evaluator.js index eed42902f..4702bad4f 100644 --- a/src/core/evaluator.js +++ b/src/core/evaluator.js @@ -662,8 +662,8 @@ var PartialEvaluator = (function PartialEvaluatorClosure() { return errorFont(); } - // We are holding font.translated references just for fontRef that are not - // dictionaries (Dict). See explanation below. + // We are holding `font.translated` references just for `fontRef`s that + // are not actually `Ref`s, but rather `Dict`s. See explanation below. if (font.translated) { return font.translated; } @@ -672,7 +672,12 @@ var PartialEvaluator = (function PartialEvaluatorClosure() { var preEvaluatedFont = this.preEvaluateFont(font, xref); var descriptor = preEvaluatedFont.descriptor; - var fontID = fontRef.num + '_' + fontRef.gen; + + var fontRefIsRef = isRef(fontRef), fontID; + if (fontRefIsRef) { + fontID = fontRef.toString(); + } + if (isDict(descriptor)) { if (!descriptor.fontAliases) { descriptor.fontAliases = Object.create(null); @@ -682,36 +687,53 @@ var PartialEvaluator = (function PartialEvaluatorClosure() { var hash = preEvaluatedFont.hash; if (fontAliases[hash]) { var aliasFontRef = fontAliases[hash].aliasRef; - if (aliasFontRef && this.fontCache.has(aliasFontRef)) { + if (fontRefIsRef && aliasFontRef && + this.fontCache.has(aliasFontRef)) { this.fontCache.putAlias(fontRef, aliasFontRef); return this.fontCache.get(fontRef); } - } - - if (!fontAliases[hash]) { + } else { fontAliases[hash] = { fontID: Font.getFontID() }; } - fontAliases[hash].aliasRef = fontRef; + if (fontRefIsRef) { + fontAliases[hash].aliasRef = fontRef; + } fontID = fontAliases[hash].fontID; } - // Workaround for bad PDF generators that don't reference fonts - // properly, i.e. by not using an object identifier. - // Check if the fontRef is a Dict (as opposed to a standard object), - // in which case we don't cache the font and instead reference it by - // fontName in font.loadedName below. - var fontRefIsDict = isDict(fontRef); - if (!fontRefIsDict) { + // Workaround for bad PDF generators that reference fonts incorrectly, + // where `fontRef` is a `Dict` rather than a `Ref` (fixes bug946506.pdf). + // In this case we should not put the font into `this.fontCache` (which is + // a `RefSetCache`), since it's not meaningful to use a `Dict` as a key. + // + // However, if we don't cache the font it's not possible to remove it + // when `cleanup` is triggered from the API, which causes issues on + // subsequent rendering operations (see issue7403.pdf). + // A simple workaround would be to just not hold `font.translated` + // references in this case, but this would force us to unnecessarily load + // the same fonts over and over. + // + // Instead, we cheat a bit by attempting to use a modified `fontID` as a + // key in `this.fontCache`, to allow the font to be cached. + // NOTE: This works because `RefSetCache` calls `toString()` on provided + // keys. Also, since `fontRef` is used when getting cached fonts, + // we'll not accidentally match fonts cached with the `fontID`. + if (fontRefIsRef) { this.fontCache.put(fontRef, fontCapability.promise); + } else { + if (!fontID) { + fontID = (this.uniquePrefix || 'F_') + (++this.idCounters.obj); + } + this.fontCache.put('id_' + fontID, fontCapability.promise); } + assert(fontID, 'The "fontID" must be defined.'); // Keep track of each font we translated so the caller can // load them asynchronously before calling display on a page. - font.loadedName = 'g_' + this.pdfManager.docId + '_f' + (fontRefIsDict ? - fontName.replace(/\W/g, '') : fontID); + font.loadedName = 'g_' + this.pdfManager.docId + '_f' + fontID; font.translated = fontCapability.promise; @@ -2121,7 +2143,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() { if (isName(encoding)) { hash.update(encoding.name); } else if (isRef(encoding)) { - hash.update(encoding.num + '_' + encoding.gen); + hash.update(encoding.toString()); } else if (isDict(encoding)) { var keys = encoding.getKeys(); for (var i = 0, ii = keys.length; i < ii; i++) { @@ -2129,7 +2151,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() { if (isName(entry)) { hash.update(entry.name); } else if (isRef(entry)) { - hash.update(entry.num + '_' + entry.gen); + hash.update(entry.toString()); } else if (isArray(entry)) { // 'Differences' entry. // Ideally we should check the contents of the array, but to avoid // parsing it here and then again in |extractDataStructures|, diff --git a/test/pdfs/.gitignore b/test/pdfs/.gitignore index 3dac08887..7e0a5f6a2 100644 --- a/test/pdfs/.gitignore +++ b/test/pdfs/.gitignore @@ -28,6 +28,7 @@ !issue7180.pdf !issue7200.pdf !issue7229.pdf +!issue7403.pdf !issue7426.pdf !issue7439.pdf !issue7492.pdf diff --git a/test/pdfs/issue7403.pdf b/test/pdfs/issue7403.pdf new file mode 100644 index 000000000..e5f53b510 Binary files /dev/null and b/test/pdfs/issue7403.pdf differ diff --git a/test/test_manifest.json b/test/test_manifest.json index b95d7e84c..4a1604a3d 100644 --- a/test/test_manifest.json +++ b/test/test_manifest.json @@ -962,6 +962,13 @@ "rounds": 1, "type": "eq" }, + { "id": "issue7403", + "file": "pdfs/issue7403.pdf", + "md5": "0f7bb6b3c58e33bbf76ce5161cd665c3", + "link": false, + "rounds": 1, + "type": "eq" + }, { "id": "protectip", "file": "pdfs/protectip.pdf", "md5": "676e7a7b8f96d04825361832b1838a93",