Merge pull request #13738 from Snuffleupagus/empty-Name

Re-factor the handling of *empty* `Name`-instances (PR 13612 follow-up)
This commit is contained in:
Tim van der Meij 2021-07-15 22:07:42 +02:00 committed by GitHub
commit c1f89c76c7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 39 additions and 21 deletions

View File

@ -1540,7 +1540,7 @@ class PartialEvaluator {
timeSlotManager.reset(); timeSlotManager.reset();
const operation = {}; const operation = {};
let stop, i, ii, cs, name; let stop, i, ii, cs, name, isValidName;
while (!(stop = timeSlotManager.check())) { while (!(stop = timeSlotManager.check())) {
// The arguments parsed by read() are used beyond this loop, so we // The arguments parsed by read() are used beyond this loop, so we
// cannot reuse the same array on each iteration. Therefore we pass // cannot reuse the same array on each iteration. Therefore we pass
@ -1556,8 +1556,10 @@ class PartialEvaluator {
switch (fn | 0) { switch (fn | 0) {
case OPS.paintXObject: case OPS.paintXObject:
// eagerly compile XForm objects // eagerly compile XForm objects
isValidName = args[0] instanceof Name;
name = args[0].name; name = args[0].name;
if (name) {
if (isValidName) {
const localImage = localImageCache.getByName(name); const localImage = localImageCache.getByName(name);
if (localImage) { if (localImage) {
operatorList.addOp(localImage.fn, localImage.args); operatorList.addOp(localImage.fn, localImage.args);
@ -1568,7 +1570,7 @@ class PartialEvaluator {
next( next(
new Promise(function (resolveXObject, rejectXObject) { new Promise(function (resolveXObject, rejectXObject) {
if (!name) { if (!isValidName) {
throw new FormatError("XObject must be referred to by name."); throw new FormatError("XObject must be referred to by name.");
} }
@ -1922,8 +1924,10 @@ class PartialEvaluator {
fn = OPS.shadingFill; fn = OPS.shadingFill;
break; break;
case OPS.setGState: case OPS.setGState:
isValidName = args[0] instanceof Name;
name = args[0].name; name = args[0].name;
if (name) {
if (isValidName) {
const localGStateObj = localGStateCache.getByName(name); const localGStateObj = localGStateCache.getByName(name);
if (localGStateObj) { if (localGStateObj) {
if (localGStateObj.length > 0) { if (localGStateObj.length > 0) {
@ -1936,7 +1940,7 @@ class PartialEvaluator {
next( next(
new Promise(function (resolveGState, rejectGState) { new Promise(function (resolveGState, rejectGState) {
if (!name) { if (!isValidName) {
throw new FormatError("GState must be referred to by name."); throw new FormatError("GState must be referred to by name.");
} }
@ -2823,14 +2827,16 @@ class PartialEvaluator {
xobjs = resources.get("XObject") || Dict.empty; xobjs = resources.get("XObject") || Dict.empty;
} }
var isValidName = args[0] instanceof Name;
var name = args[0].name; var name = args[0].name;
if (name && emptyXObjectCache.getByName(name)) {
if (isValidName && emptyXObjectCache.getByName(name)) {
break; break;
} }
next( next(
new Promise(function (resolveXObject, rejectXObject) { new Promise(function (resolveXObject, rejectXObject) {
if (!name) { if (!isValidName) {
throw new FormatError("XObject must be referred to by name."); throw new FormatError("XObject must be referred to by name.");
} }
@ -2935,14 +2941,16 @@ class PartialEvaluator {
); );
return; return;
case OPS.setGState: case OPS.setGState:
isValidName = args[0] instanceof Name;
name = args[0].name; name = args[0].name;
if (name && emptyGStateCache.getByName(name)) {
if (isValidName && emptyGStateCache.getByName(name)) {
break; break;
} }
next( next(
new Promise(function (resolveGState, rejectGState) { new Promise(function (resolveGState, rejectGState) {
if (!name) { if (!isValidName) {
throw new FormatError("GState must be referred to by name."); throw new FormatError("GState must be referred to by name.");
} }

View File

@ -47,7 +47,7 @@ class BaseLocalCache {
class LocalImageCache extends BaseLocalCache { class LocalImageCache extends BaseLocalCache {
set(name, ref = null, data) { set(name, ref = null, data) {
if (!name) { if (typeof name !== "string") {
throw new Error('LocalImageCache.set - expected "name" argument.'); throw new Error('LocalImageCache.set - expected "name" argument.');
} }
if (ref) { if (ref) {
@ -68,7 +68,7 @@ class LocalImageCache extends BaseLocalCache {
class LocalColorSpaceCache extends BaseLocalCache { class LocalColorSpaceCache extends BaseLocalCache {
set(name = null, ref = null, data) { set(name = null, ref = null, data) {
if (!name && !ref) { if (typeof name !== "string" && !ref) {
throw new Error( throw new Error(
'LocalColorSpaceCache.set - expected "name" and/or "ref" argument.' 'LocalColorSpaceCache.set - expected "name" and/or "ref" argument.'
); );
@ -77,7 +77,7 @@ class LocalColorSpaceCache extends BaseLocalCache {
if (this._imageCache.has(ref)) { if (this._imageCache.has(ref)) {
return; return;
} }
if (name) { if (name !== null) {
// Optional when `ref` is defined. // Optional when `ref` is defined.
this._nameRefMap.set(name, ref); this._nameRefMap.set(name, ref);
} }
@ -114,7 +114,7 @@ class LocalFunctionCache extends BaseLocalCache {
class LocalGStateCache extends BaseLocalCache { class LocalGStateCache extends BaseLocalCache {
set(name, ref = null, data) { set(name, ref = null, data) {
if (!name) { if (typeof name !== "string") {
throw new Error('LocalGStateCache.set - expected "name" argument.'); throw new Error('LocalGStateCache.set - expected "name" argument.');
} }
if (ref) { if (ref) {
@ -135,7 +135,7 @@ class LocalGStateCache extends BaseLocalCache {
class LocalTilingPatternCache extends BaseLocalCache { class LocalTilingPatternCache extends BaseLocalCache {
set(name, ref = null, data) { set(name, ref = null, data) {
if (!name) { if (typeof name !== "string") {
throw new Error( throw new Error(
'LocalTilingPatternCache.set - expected "name" argument.' 'LocalTilingPatternCache.set - expected "name" argument.'
); );

View File

@ -1115,7 +1115,6 @@ class Lexer {
warn(`Name token is longer than allowed by the spec: ${strBuf.length}`); warn(`Name token is longer than allowed by the spec: ${strBuf.length}`);
} else if (strBuf.length === 0) { } else if (strBuf.length === 0) {
warn("Name token is empty."); warn("Name token is empty.");
return Name.empty;
} }
return Name.get(strBuf.join("")); return Name.get(strBuf.join(""));
} }

View File

@ -33,12 +33,6 @@ const Name = (function NameClosure() {
return nameValue ? nameValue : (nameCache[name] = new Name(name)); return nameValue ? nameValue : (nameCache[name] = new Name(name));
} }
static get empty() {
// eslint-disable-next-line no-restricted-syntax
const emptyName = new Name({ empty: true });
return shadow(this, "empty", emptyName);
}
static _clearCache() { static _clearCache() {
nameCache = Object.create(null); nameCache = Object.create(null);
} }

View File

@ -50,6 +50,15 @@ describe("primitives", function () {
expect(firstSubtype).toBe(secondSubtype); expect(firstSubtype).toBe(secondSubtype);
expect(firstFont).not.toBe(firstSubtype); expect(firstFont).not.toBe(firstSubtype);
}); });
it("should create only one object for *empty* names and cache it", function () {
const firstEmpty = Name.get("");
const secondEmpty = Name.get("");
const normalName = Name.get("string");
expect(firstEmpty).toBe(secondEmpty);
expect(firstEmpty).not.toBe(normalName);
});
}); });
describe("Cmd", function () { describe("Cmd", function () {
@ -491,6 +500,14 @@ describe("primitives", function () {
expect(isName(name, "Font")).toEqual(true); expect(isName(name, "Font")).toEqual(true);
expect(isName(name, "Subtype")).toEqual(false); expect(isName(name, "Subtype")).toEqual(false);
}); });
it("handles *empty* names, with name check", function () {
const emptyName = Name.get("");
expect(isName(emptyName)).toEqual(true);
expect(isName(emptyName, "")).toEqual(true);
expect(isName(emptyName, "string")).toEqual(false);
});
}); });
describe("isCmd", function () { describe("isCmd", function () {