Improve how Type3-fonts with dependencies are handled
While the `CharProcs` streams of Type3-fonts *usually* don't rely on dependencies, such as e.g. images, it does happen in some cases. Currently any dependencies are simply appended to the parent operatorList, which in practice means *only* the operatorList of the *first* page where the Type3-font is being used. However, there's one thing that's slightly unfortunate with that approach: Since fonts are global to the PDF document, we really ought to ensure that any Type3 dependencies are appended to the operatorList of *all* pages where the Type3-font is being used. Otherwise there's a theoretical risk that, if one page has its rendering paused, another page may try to use a Type3-font whose dependencies are not yet fully resolved. In that case there would be errors, since Type3 operatorLists are executed synchronously. Hence this patch, which ensures that all relevant pages will have Type3 dependencies appended to the main operatorList. (Note here that the `OperatorList.addDependencies` method, via `OperatorList.addDependency`, ensures that a dependency is only added *once* to any operatorList.) Finally, these changes also remove the need for the "waiting for the main-thread"-hack that was added to `PartialEvaluator.buildPaintImageXObject` as part of fixing issue 10717.
This commit is contained in:
parent
c7eb79ca66
commit
7c9d0d5939
@ -456,7 +456,7 @@ class PartialEvaluator {
|
||||
const transfers = imgData ? [imgData.data.buffer] : null;
|
||||
|
||||
if (this.parsingType3Font) {
|
||||
return this.handler.sendWithPromise(
|
||||
return this.handler.send(
|
||||
"commonobj",
|
||||
[objId, "FontType3Res", imgData],
|
||||
transfers
|
||||
@ -581,7 +581,7 @@ class PartialEvaluator {
|
||||
operatorList.addDependency(objId);
|
||||
args = [objId, w, h];
|
||||
|
||||
const imgPromise = PDFImage.buildImage({
|
||||
PDFImage.buildImage({
|
||||
xref: this.xref,
|
||||
res: resources,
|
||||
image,
|
||||
@ -600,13 +600,6 @@ class PartialEvaluator {
|
||||
return this._sendImgData(objId, /* imgData = */ null, cacheGlobally);
|
||||
});
|
||||
|
||||
if (this.parsingType3Font) {
|
||||
// In the very rare case where a Type3 image resource is being parsed,
|
||||
// wait for the image to be both decoded *and* sent to simplify the
|
||||
// rendering code on the main-thread (see issue10717.pdf).
|
||||
await imgPromise;
|
||||
}
|
||||
|
||||
operatorList.addOp(OPS.paintImageXObject, args);
|
||||
if (cacheKey) {
|
||||
localImageCache.set(cacheKey, imageRef, {
|
||||
@ -741,8 +734,12 @@ class PartialEvaluator {
|
||||
return translated;
|
||||
}
|
||||
return translated
|
||||
.loadType3Data(this, resources, operatorList, task)
|
||||
.loadType3Data(this, resources, task)
|
||||
.then(function () {
|
||||
// Add the dependencies to the parent operatorList so they are
|
||||
// resolved before Type3 operatorLists are executed synchronously.
|
||||
operatorList.addDependencies(translated.type3Dependencies);
|
||||
|
||||
return translated;
|
||||
})
|
||||
.catch(reason => {
|
||||
@ -3354,6 +3351,7 @@ class TranslatedFont {
|
||||
this.dict = dict;
|
||||
this._extraProperties = extraProperties;
|
||||
this.type3Loaded = null;
|
||||
this.type3Dependencies = font.isType3Font ? new Set() : null;
|
||||
this.sent = false;
|
||||
}
|
||||
|
||||
@ -3386,7 +3384,7 @@ class TranslatedFont {
|
||||
PartialEvaluator.buildFontPaths(this.font, glyphs, handler);
|
||||
}
|
||||
|
||||
loadType3Data(evaluator, resources, parentOperatorList, task) {
|
||||
loadType3Data(evaluator, resources, task) {
|
||||
if (!this.font.isType3Font) {
|
||||
throw new Error("Must be a Type3 font.");
|
||||
}
|
||||
@ -3397,24 +3395,19 @@ class TranslatedFont {
|
||||
// When parsing Type3 glyphs, always ignore them if there are errors.
|
||||
// Compared to the parsing of e.g. an entire page, it doesn't really
|
||||
// make sense to only be able to render a Type3 glyph partially.
|
||||
//
|
||||
// Also, ensure that any Type3 image resources (which should be very rare
|
||||
// in practice) are completely decoded on the worker-thread, to simplify
|
||||
// the rendering code on the main-thread (see issue10717.pdf).
|
||||
var type3Options = Object.create(evaluator.options);
|
||||
type3Options.ignoreErrors = false;
|
||||
var type3Evaluator = evaluator.clone(type3Options);
|
||||
type3Evaluator.parsingType3Font = true;
|
||||
|
||||
var translatedFont = this.font;
|
||||
const translatedFont = this.font,
|
||||
type3Dependencies = this.type3Dependencies;
|
||||
var loadCharProcsPromise = Promise.resolve();
|
||||
var charProcs = this.dict.get("CharProcs");
|
||||
var fontResources = this.dict.get("Resources") || resources;
|
||||
var charProcKeys = charProcs.getKeys();
|
||||
var charProcOperatorList = Object.create(null);
|
||||
|
||||
for (var i = 0, n = charProcKeys.length; i < n; ++i) {
|
||||
const key = charProcKeys[i];
|
||||
for (const key of charProcs.getKeys()) {
|
||||
loadCharProcsPromise = loadCharProcsPromise.then(function () {
|
||||
var glyphStream = charProcs.get(key);
|
||||
var operatorList = new OperatorList();
|
||||
@ -3428,9 +3421,9 @@ class TranslatedFont {
|
||||
.then(function () {
|
||||
charProcOperatorList[key] = operatorList.getIR();
|
||||
|
||||
// Add the dependencies to the parent operator list so they are
|
||||
// resolved before sub operator list is executed synchronously.
|
||||
parentOperatorList.addDependencies(operatorList.dependencies);
|
||||
for (const dependency of operatorList.dependencies) {
|
||||
type3Dependencies.add(dependency);
|
||||
}
|
||||
})
|
||||
.catch(function (reason) {
|
||||
warn(`Type3 font resource "${key}" is not available.`);
|
||||
|
Loading…
x
Reference in New Issue
Block a user