diff --git a/src/core/annotation.js b/src/core/annotation.js index b659fd1f5..8d38ec8ae 100644 --- a/src/core/annotation.js +++ b/src/core/annotation.js @@ -4007,14 +4007,13 @@ class FreeTextAnnotation extends MarkupAnnotation { // We want to be able to add mouse listeners to the annotation. this.data.noHTML = false; - const { annotationGlobals, evaluatorOptions, xref } = params; + const { annotationGlobals, xref } = params; this.setDefaultAppearance(params); this._hasAppearance = !!this.appearance; if (this._hasAppearance) { const { fontColor, fontSize } = parseAppearanceStream( this.appearance, - evaluatorOptions, xref, annotationGlobals.globalColorSpaceCache ); diff --git a/src/core/default_appearance.js b/src/core/default_appearance.js index 42ad67c86..5756a388c 100644 --- a/src/core/default_appearance.js +++ b/src/core/default_appearance.js @@ -97,10 +97,9 @@ function parseDefaultAppearance(str) { } class AppearanceStreamEvaluator extends EvaluatorPreprocessor { - constructor(stream, evaluatorOptions, xref, globalColorSpaceCache) { + constructor(stream, xref, globalColorSpaceCache) { super(stream); this.stream = stream; - this.evaluatorOptions = evaluatorOptions; this.xref = xref; this.globalColorSpaceCache = globalColorSpaceCache; @@ -202,25 +201,19 @@ class AppearanceStreamEvaluator extends EvaluatorPreprocessor { } get _pdfFunctionFactory() { - const pdfFunctionFactory = new PDFFunctionFactory({ - xref: this.xref, - isEvalSupported: this.evaluatorOptions.isEvalSupported, - }); - return shadow(this, "_pdfFunctionFactory", pdfFunctionFactory); + return shadow( + this, + "_pdfFunctionFactory", + new PDFFunctionFactory({ xref: this.xref }) + ); } } // Parse appearance stream to extract font and color information. // It returns the font properties used to render the first text object. -function parseAppearanceStream( - stream, - evaluatorOptions, - xref, - globalColorSpaceCache -) { +function parseAppearanceStream(stream, xref, globalColorSpaceCache) { return new AppearanceStreamEvaluator( stream, - evaluatorOptions, xref, globalColorSpaceCache ).parse(); diff --git a/src/core/document.js b/src/core/document.js index 66d142d8c..412c80caf 100644 --- a/src/core/document.js +++ b/src/core/document.js @@ -2089,15 +2089,11 @@ class PDFDocument { value.numComps = value.bitsPerComponent = 1; } try { - const pdfFunctionFactory = new PDFFunctionFactory({ - xref: this.xref, - isEvalSupported: this.pdfManager.evaluatorOptions.isEvalSupported, - }); const imageObj = await PDFImage.buildImage({ xref: this.xref, res: Dict.empty, image: value, - pdfFunctionFactory, + pdfFunctionFactory: new PDFFunctionFactory({ xref: this.xref }), globalColorSpaceCache: this.catalog.globalColorSpaceCache, localColorSpaceCache: new LocalColorSpaceCache(), }); diff --git a/src/core/evaluator.js b/src/core/evaluator.js index f443dee13..772bd730d 100644 --- a/src/core/evaluator.js +++ b/src/core/evaluator.js @@ -93,7 +93,6 @@ const DefaultPartialEvaluatorOptions = Object.freeze({ maxImageSize: -1, disableFontFace: false, ignoreErrors: false, - isEvalSupported: true, isOffscreenCanvasSupported: false, isImageDecoderSupported: false, canvasMaxAreaInBytes: -1, @@ -263,11 +262,11 @@ class PartialEvaluator { * `PDFFunctionFactory` instance within this `PartialEvaluator` instance. */ get _pdfFunctionFactory() { - const pdfFunctionFactory = new PDFFunctionFactory({ - xref: this.xref, - isEvalSupported: this.options.isEvalSupported, - }); - return shadow(this, "_pdfFunctionFactory", pdfFunctionFactory); + return shadow( + this, + "_pdfFunctionFactory", + new PDFFunctionFactory({ xref: this.xref }) + ); } get parsingType3Font() { diff --git a/src/core/function.js b/src/core/function.js index 19da40d59..5336f1f76 100644 --- a/src/core/function.js +++ b/src/core/function.js @@ -14,13 +14,7 @@ */ import { Dict, Ref } from "./primitives.js"; -import { - FormatError, - info, - shadow, - unreachable, - warn, -} from "../shared/util.js"; +import { FormatError, info, shadow, warn } from "../shared/util.js"; import { BaseStream } from "./base_stream.js"; import { buildPostScriptJsFunction } from "./postscript/js_evaluator.js"; import { buildPostScriptWasmFunction } from "./postscript/wasm_compiler.js"; @@ -32,12 +26,11 @@ class PDFFunctionFactory { static #useWasm = true; static setOptions({ useWasm }) { - PDFFunctionFactory.#useWasm = useWasm; + this.#useWasm = useWasm; } - constructor({ xref, isEvalSupported = true }) { + constructor({ xref }) { this.xref = xref; - this.isEvalSupported = isEvalSupported !== false; } get useWasm() { @@ -398,732 +391,4 @@ function isPDFFunction(v) { return fnDict.has("FunctionType"); } -class PostScriptStack { - static MAX_STACK_SIZE = 100; - - constructor(initialStack) { - this.stack = initialStack ? Array.from(initialStack) : []; - } - - push(value) { - if (this.stack.length >= PostScriptStack.MAX_STACK_SIZE) { - throw new Error("PostScript function stack overflow."); - } - this.stack.push(value); - } - - pop() { - if (this.stack.length <= 0) { - throw new Error("PostScript function stack underflow."); - } - return this.stack.pop(); - } - - copy(n) { - if (this.stack.length + n >= PostScriptStack.MAX_STACK_SIZE) { - throw new Error("PostScript function stack overflow."); - } - const stack = this.stack; - for (let i = stack.length - n, j = n - 1; j >= 0; j--, i++) { - stack.push(stack[i]); - } - } - - index(n) { - this.push(this.stack[this.stack.length - n - 1]); - } - - // rotate the last n stack elements p times - roll(n, p) { - const stack = this.stack; - const l = stack.length - n; - const r = stack.length - 1; - const c = l + (p - Math.floor(p / n) * n); - - for (let i = l, j = r; i < j; i++, j--) { - const t = stack[i]; - stack[i] = stack[j]; - stack[j] = t; - } - for (let i = l, j = c - 1; i < j; i++, j--) { - const t = stack[i]; - stack[i] = stack[j]; - stack[j] = t; - } - for (let i = c, j = r; i < j; i++, j--) { - const t = stack[i]; - stack[i] = stack[j]; - stack[j] = t; - } - } -} - -class PostScriptEvaluator { - constructor(operators) { - this.operators = operators; - } - - execute(initialStack) { - const stack = new PostScriptStack(initialStack); - let counter = 0; - const operators = this.operators; - const length = operators.length; - let operator, a, b; - while (counter < length) { - operator = operators[counter++]; - if (typeof operator === "number") { - // Operator is really an operand and should be pushed to the stack. - stack.push(operator); - continue; - } - switch (operator) { - // non standard ps operators - case "jz": // jump if false - b = stack.pop(); - a = stack.pop(); - if (!a) { - counter = b; - } - break; - case "j": // jump - a = stack.pop(); - counter = a; - break; - - // all ps operators in alphabetical order (excluding if/ifelse) - case "abs": - a = stack.pop(); - stack.push(Math.abs(a)); - break; - case "add": - b = stack.pop(); - a = stack.pop(); - stack.push(a + b); - break; - case "and": - b = stack.pop(); - a = stack.pop(); - if (typeof a === "boolean" && typeof b === "boolean") { - stack.push(a && b); - } else { - stack.push(a & b); - } - break; - case "atan": - b = stack.pop(); - a = stack.pop(); - a = (Math.atan2(a, b) / Math.PI) * 180; - if (a < 0) { - a += 360; - } - stack.push(a); - break; - case "bitshift": - b = stack.pop(); - a = stack.pop(); - if (a > 0) { - stack.push(a << b); - } else { - stack.push(a >> b); - } - break; - case "ceiling": - a = stack.pop(); - stack.push(Math.ceil(a)); - break; - case "copy": - a = stack.pop(); - stack.copy(a); - break; - case "cos": - a = stack.pop(); - stack.push(Math.cos(((a % 360) / 180) * Math.PI)); - break; - case "cvi": - a = stack.pop() | 0; - stack.push(a); - break; - case "cvr": - // noop - break; - case "div": - b = stack.pop(); - a = stack.pop(); - stack.push(a / b); - break; - case "dup": - stack.copy(1); - break; - case "eq": - b = stack.pop(); - a = stack.pop(); - stack.push(a === b); - break; - case "exch": - stack.roll(2, 1); - break; - case "exp": - b = stack.pop(); - a = stack.pop(); - stack.push(a ** b); - break; - case "false": - stack.push(false); - break; - case "floor": - a = stack.pop(); - stack.push(Math.floor(a)); - break; - case "ge": - b = stack.pop(); - a = stack.pop(); - stack.push(a >= b); - break; - case "gt": - b = stack.pop(); - a = stack.pop(); - stack.push(a > b); - break; - case "idiv": - b = stack.pop(); - a = stack.pop(); - stack.push((a / b) | 0); - break; - case "index": - a = stack.pop(); - stack.index(a); - break; - case "le": - b = stack.pop(); - a = stack.pop(); - stack.push(a <= b); - break; - case "ln": - a = stack.pop(); - stack.push(Math.log(a)); - break; - case "log": - a = stack.pop(); - stack.push(Math.log10(a)); - break; - case "lt": - b = stack.pop(); - a = stack.pop(); - stack.push(a < b); - break; - case "mod": - b = stack.pop(); - a = stack.pop(); - stack.push(a % b); - break; - case "mul": - b = stack.pop(); - a = stack.pop(); - stack.push(a * b); - break; - case "ne": - b = stack.pop(); - a = stack.pop(); - stack.push(a !== b); - break; - case "neg": - a = stack.pop(); - stack.push(-a); - break; - case "not": - a = stack.pop(); - if (typeof a === "boolean") { - stack.push(!a); - } else { - stack.push(~a); - } - break; - case "or": - b = stack.pop(); - a = stack.pop(); - if (typeof a === "boolean" && typeof b === "boolean") { - stack.push(a || b); - } else { - stack.push(a | b); - } - break; - case "pop": - stack.pop(); - break; - case "roll": - b = stack.pop(); - a = stack.pop(); - stack.roll(a, b); - break; - case "round": - a = stack.pop(); - stack.push(Math.round(a)); - break; - case "sin": - a = stack.pop(); - stack.push(Math.sin(((a % 360) / 180) * Math.PI)); - break; - case "sqrt": - a = stack.pop(); - stack.push(Math.sqrt(a)); - break; - case "sub": - b = stack.pop(); - a = stack.pop(); - stack.push(a - b); - break; - case "true": - stack.push(true); - break; - case "truncate": - a = stack.pop(); - a = a < 0 ? Math.ceil(a) : Math.floor(a); - stack.push(a); - break; - case "xor": - b = stack.pop(); - a = stack.pop(); - if (typeof a === "boolean" && typeof b === "boolean") { - stack.push(a !== b); - } else { - stack.push(a ^ b); - } - break; - default: - throw new FormatError(`Unknown operator ${operator}`); - } - } - return stack.stack; - } -} - -class AstNode { - constructor(type) { - this.type = type; - } - - visit(visitor) { - unreachable("abstract method"); - } -} - -class AstArgument extends AstNode { - constructor(index, min, max) { - super("args"); - this.index = index; - this.min = min; - this.max = max; - } - - visit(visitor) { - visitor.visitArgument(this); - } -} - -class AstLiteral extends AstNode { - constructor(number) { - super("literal"); - this.number = number; - this.min = number; - this.max = number; - } - - visit(visitor) { - visitor.visitLiteral(this); - } -} - -class AstBinaryOperation extends AstNode { - constructor(op, arg1, arg2, min, max) { - super("binary"); - this.op = op; - this.arg1 = arg1; - this.arg2 = arg2; - this.min = min; - this.max = max; - } - - visit(visitor) { - visitor.visitBinaryOperation(this); - } -} - -class AstMin extends AstNode { - constructor(arg, max) { - super("max"); - this.arg = arg; - this.min = arg.min; - this.max = max; - } - - visit(visitor) { - visitor.visitMin(this); - } -} - -class AstVariable extends AstNode { - constructor(index, min, max) { - super("var"); - this.index = index; - this.min = min; - this.max = max; - } - - visit(visitor) { - visitor.visitVariable(this); - } -} - -class AstVariableDefinition extends AstNode { - constructor(variable, arg) { - super("definition"); - this.variable = variable; - this.arg = arg; - } - - visit(visitor) { - visitor.visitVariableDefinition(this); - } -} - -class ExpressionBuilderVisitor { - parts = []; - - visitArgument(arg) { - this.parts.push( - "Math.max(", - arg.min, - ", Math.min(", - arg.max, - ", src[srcOffset + ", - arg.index, - "]))" - ); - } - - visitVariable(variable) { - this.parts.push("v", variable.index); - } - - visitLiteral(literal) { - this.parts.push(literal.number); - } - - visitBinaryOperation(operation) { - this.parts.push("("); - operation.arg1.visit(this); - this.parts.push(" ", operation.op, " "); - operation.arg2.visit(this); - this.parts.push(")"); - } - - visitVariableDefinition(definition) { - this.parts.push("var "); - definition.variable.visit(this); - this.parts.push(" = "); - definition.arg.visit(this); - this.parts.push(";"); - } - - visitMin(max) { - this.parts.push("Math.min("); - max.arg.visit(this); - this.parts.push(", ", max.max, ")"); - } - - toString() { - return this.parts.join(""); - } -} - -function buildAddOperation(num1, num2) { - if (num2.type === "literal" && num2.number === 0) { - // optimization: second operand is 0 - return num1; - } - if (num1.type === "literal" && num1.number === 0) { - // optimization: first operand is 0 - return num2; - } - if (num2.type === "literal" && num1.type === "literal") { - // optimization: operands operand are literals - return new AstLiteral(num1.number + num2.number); - } - return new AstBinaryOperation( - "+", - num1, - num2, - num1.min + num2.min, - num1.max + num2.max - ); -} - -function buildMulOperation(num1, num2) { - if (num2.type === "literal") { - // optimization: second operands is a literal... - if (num2.number === 0) { - return new AstLiteral(0); // and it's 0 - } else if (num2.number === 1) { - return num1; // and it's 1 - } else if (num1.type === "literal") { - // ... and first operands is a literal too - return new AstLiteral(num1.number * num2.number); - } - } - if (num1.type === "literal") { - // optimization: first operands is a literal... - if (num1.number === 0) { - return new AstLiteral(0); // and it's 0 - } else if (num1.number === 1) { - return num2; // and it's 1 - } - } - const min = Math.min( - num1.min * num2.min, - num1.min * num2.max, - num1.max * num2.min, - num1.max * num2.max - ); - const max = Math.max( - num1.min * num2.min, - num1.min * num2.max, - num1.max * num2.min, - num1.max * num2.max - ); - return new AstBinaryOperation("*", num1, num2, min, max); -} - -function buildSubOperation(num1, num2) { - if (num2.type === "literal") { - // optimization: second operands is a literal... - if (num2.number === 0) { - return num1; // ... and it's 0 - } else if (num1.type === "literal") { - // ... and first operands is a literal too - return new AstLiteral(num1.number - num2.number); - } - } - if ( - num2.type === "binary" && - num2.op === "-" && - num1.type === "literal" && - num1.number === 1 && - num2.arg1.type === "literal" && - num2.arg1.number === 1 - ) { - // optimization for case: 1 - (1 - x) - return num2.arg2; - } - return new AstBinaryOperation( - "-", - num1, - num2, - num1.min - num2.max, - num1.max - num2.min - ); -} - -function buildMinOperation(num1, max) { - if (num1.min >= max) { - // optimization: num1 min value is not less than required max - return new AstLiteral(max); // just returning max - } else if (num1.max <= max) { - // optimization: num1 max value is not greater than required max - return num1; // just returning an argument - } - return new AstMin(num1, max); -} - -// Most of the PDFs functions consist of simple operations such as: -// roll, exch, sub, cvr, pop, index, dup, mul, if, gt, add. -// -// We can compile most of such programs, and at the same moment, we can -// optimize some expressions using basic math properties. Keeping track of -// min/max values will allow us to avoid extra Math.min/Math.max calls. -class PostScriptCompiler { - compile(code, domain, range) { - const stack = []; - const instructions = []; - const inputSize = domain.length >> 1, - outputSize = range.length >> 1; - let lastRegister = 0; - let n, j; - let num1, num2, ast1, ast2, tmpVar, item; - for (let i = 0; i < inputSize; i++) { - stack.push(new AstArgument(i, domain[i * 2], domain[i * 2 + 1])); - } - - for (let i = 0, ii = code.length; i < ii; i++) { - item = code[i]; - if (typeof item === "number") { - stack.push(new AstLiteral(item)); - continue; - } - - switch (item) { - case "add": - if (stack.length < 2) { - return null; - } - num2 = stack.pop(); - num1 = stack.pop(); - stack.push(buildAddOperation(num1, num2)); - break; - case "cvr": - if (stack.length < 1) { - return null; - } - break; - case "mul": - if (stack.length < 2) { - return null; - } - num2 = stack.pop(); - num1 = stack.pop(); - stack.push(buildMulOperation(num1, num2)); - break; - case "sub": - if (stack.length < 2) { - return null; - } - num2 = stack.pop(); - num1 = stack.pop(); - stack.push(buildSubOperation(num1, num2)); - break; - case "exch": - if (stack.length < 2) { - return null; - } - ast1 = stack.pop(); - ast2 = stack.pop(); - stack.push(ast1, ast2); - break; - case "pop": - if (stack.length < 1) { - return null; - } - stack.pop(); - break; - case "index": - if (stack.length < 1) { - return null; - } - num1 = stack.pop(); - if (num1.type !== "literal") { - return null; - } - n = num1.number; - if (n < 0 || !Number.isInteger(n) || stack.length < n) { - return null; - } - ast1 = stack[stack.length - n - 1]; - if (ast1.type === "literal" || ast1.type === "var") { - stack.push(ast1); - break; - } - tmpVar = new AstVariable(lastRegister++, ast1.min, ast1.max); - stack[stack.length - n - 1] = tmpVar; - stack.push(tmpVar); - instructions.push(new AstVariableDefinition(tmpVar, ast1)); - break; - case "dup": - if (stack.length < 1) { - return null; - } - if ( - typeof code[i + 1] === "number" && - code[i + 2] === "gt" && - code[i + 3] === i + 7 && - code[i + 4] === "jz" && - code[i + 5] === "pop" && - code[i + 6] === code[i + 1] - ) { - // special case of the commands sequence for the min operation - num1 = stack.pop(); - stack.push(buildMinOperation(num1, code[i + 1])); - i += 6; - break; - } - ast1 = stack.at(-1); - if (ast1.type === "literal" || ast1.type === "var") { - // we don't have to save into intermediate variable a literal or - // variable. - stack.push(ast1); - break; - } - tmpVar = new AstVariable(lastRegister++, ast1.min, ast1.max); - stack[stack.length - 1] = tmpVar; - stack.push(tmpVar); - instructions.push(new AstVariableDefinition(tmpVar, ast1)); - break; - case "roll": - if (stack.length < 2) { - return null; - } - num2 = stack.pop(); - num1 = stack.pop(); - if (num2.type !== "literal" || num1.type !== "literal") { - // both roll operands must be numbers - return null; - } - j = num2.number; - n = num1.number; - if ( - n <= 0 || - !Number.isInteger(n) || - !Number.isInteger(j) || - stack.length < n - ) { - // ... and integers - return null; - } - j = ((j % n) + n) % n; - if (j === 0) { - break; // just skipping -- there are nothing to rotate - } - stack.push(...stack.splice(stack.length - n, n - j)); - break; - default: - return null; // unsupported operator - } - } - - if (stack.length !== outputSize) { - return null; - } - - const result = []; - for (const instruction of instructions) { - const statementBuilder = new ExpressionBuilderVisitor(); - instruction.visit(statementBuilder); - result.push(statementBuilder.toString()); - } - for (let i = 0, ii = stack.length; i < ii; i++) { - const expr = stack[i], - statementBuilder = new ExpressionBuilderVisitor(); - expr.visit(statementBuilder); - const min = range[i * 2], - max = range[i * 2 + 1]; - const out = [statementBuilder.toString()]; - if (min > expr.min) { - out.unshift("Math.max(", min, ", "); - out.push(")"); - } - if (max < expr.max) { - out.unshift("Math.min(", max, ", "); - out.push(")"); - } - out.unshift("dest[destOffset + ", i, "] = "); - out.push(";"); - result.push(out.join("")); - } - return result.join("\n"); - } -} - -export { - isPDFFunction, - PDFFunctionFactory, - PostScriptCompiler, - PostScriptEvaluator, -}; +export { isPDFFunction, PDFFunctionFactory }; diff --git a/src/core/ps_parser.js b/src/core/ps_parser.js deleted file mode 100644 index 7ab24e73e..000000000 --- a/src/core/ps_parser.js +++ /dev/null @@ -1,268 +0,0 @@ -/* Copyright 2014 Mozilla Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { FormatError, shadow } from "../shared/util.js"; -import { EOF } from "./primitives.js"; -import { isWhiteSpace } from "./core_utils.js"; - -class PostScriptParser { - constructor(lexer) { - this.lexer = lexer; - this.operators = []; - this.token = null; - this.prev = null; - } - - nextToken() { - this.prev = this.token; - this.token = this.lexer.getToken(); - } - - accept(type) { - if (this.token.type === type) { - this.nextToken(); - return true; - } - return false; - } - - expect(type) { - if (this.accept(type)) { - return true; - } - throw new FormatError( - `Unexpected symbol: found ${this.token.type} expected ${type}.` - ); - } - - parse() { - this.nextToken(); - this.expect(PostScriptTokenTypes.LBRACE); - this.parseBlock(); - this.expect(PostScriptTokenTypes.RBRACE); - return this.operators; - } - - parseBlock() { - while (true) { - if (this.accept(PostScriptTokenTypes.NUMBER)) { - this.operators.push(this.prev.value); - } else if (this.accept(PostScriptTokenTypes.OPERATOR)) { - this.operators.push(this.prev.value); - } else if (this.accept(PostScriptTokenTypes.LBRACE)) { - this.parseCondition(); - } else { - return; - } - } - } - - parseCondition() { - // Add two place holders that will be updated later - const conditionLocation = this.operators.length; - this.operators.push(null, null); - - this.parseBlock(); - this.expect(PostScriptTokenTypes.RBRACE); - if (this.accept(PostScriptTokenTypes.IF)) { - // The true block is right after the 'if' so it just falls through on true - // else it jumps and skips the true block. - this.operators[conditionLocation] = this.operators.length; - this.operators[conditionLocation + 1] = "jz"; - } else if (this.accept(PostScriptTokenTypes.LBRACE)) { - const jumpLocation = this.operators.length; - this.operators.push(null, null); - const endOfTrue = this.operators.length; - this.parseBlock(); - this.expect(PostScriptTokenTypes.RBRACE); - this.expect(PostScriptTokenTypes.IFELSE); - // The jump is added at the end of the true block to skip the false block. - this.operators[jumpLocation] = this.operators.length; - this.operators[jumpLocation + 1] = "j"; - - this.operators[conditionLocation] = endOfTrue; - this.operators[conditionLocation + 1] = "jz"; - } else { - throw new FormatError("PS Function: error parsing conditional."); - } - } -} - -const PostScriptTokenTypes = { - LBRACE: 0, - RBRACE: 1, - NUMBER: 2, - OPERATOR: 3, - IF: 4, - IFELSE: 5, -}; - -class PostScriptToken { - static get opCache() { - return shadow(this, "opCache", Object.create(null)); - } - - constructor(type, value) { - this.type = type; - this.value = value; - } - - static getOperator(op) { - return (PostScriptToken.opCache[op] ||= new PostScriptToken( - PostScriptTokenTypes.OPERATOR, - op - )); - } - - static get LBRACE() { - return shadow( - this, - "LBRACE", - new PostScriptToken(PostScriptTokenTypes.LBRACE, "{") - ); - } - - static get RBRACE() { - return shadow( - this, - "RBRACE", - new PostScriptToken(PostScriptTokenTypes.RBRACE, "}") - ); - } - - static get IF() { - return shadow( - this, - "IF", - new PostScriptToken(PostScriptTokenTypes.IF, "IF") - ); - } - - static get IFELSE() { - return shadow( - this, - "IFELSE", - new PostScriptToken(PostScriptTokenTypes.IFELSE, "IFELSE") - ); - } -} - -class PostScriptLexer { - constructor(stream) { - this.stream = stream; - this.nextChar(); - - this.strBuf = []; - } - - nextChar() { - return (this.currentChar = this.stream.getByte()); - } - - getToken() { - let comment = false; - let ch = this.currentChar; - - // skip comments - while (true) { - if (ch < 0) { - return EOF; - } - - if (comment) { - if (ch === 0x0a || ch === 0x0d) { - comment = false; - } - } else if (ch === /* '%' = */ 0x25) { - comment = true; - } else if (!isWhiteSpace(ch)) { - break; - } - ch = this.nextChar(); - } - switch (ch | 0) { - case 0x30: // '0' - case 0x31: // '1' - case 0x32: // '2' - case 0x33: // '3' - case 0x34: // '4' - case 0x35: // '5' - case 0x36: // '6' - case 0x37: // '7' - case 0x38: // '8' - case 0x39: // '9' - case 0x2b: // '+' - case 0x2d: // '-' - case 0x2e: // '.' - return new PostScriptToken( - PostScriptTokenTypes.NUMBER, - this.getNumber() - ); - case 0x7b: // '{' - this.nextChar(); - return PostScriptToken.LBRACE; - case 0x7d: // '}' - this.nextChar(); - return PostScriptToken.RBRACE; - } - // operator - const strBuf = this.strBuf; - strBuf.length = 0; - strBuf[0] = String.fromCharCode(ch); - - while ( - (ch = this.nextChar()) >= 0 && - ((ch >= /* 'A' = */ 0x41 && ch <= /* 'Z' = */ 0x5a) || - (ch >= /* 'a' = */ 0x61 && ch <= /* 'z' = */ 0x7a)) - ) { - strBuf.push(String.fromCharCode(ch)); - } - const str = strBuf.join(""); - switch (str.toLowerCase()) { - case "if": - return PostScriptToken.IF; - case "ifelse": - return PostScriptToken.IFELSE; - default: - return PostScriptToken.getOperator(str); - } - } - - getNumber() { - let ch = this.currentChar; - const strBuf = this.strBuf; - strBuf.length = 0; - strBuf[0] = String.fromCharCode(ch); - - while ((ch = this.nextChar()) >= 0) { - if ( - (ch >= /* '0' = */ 0x30 && ch <= /* '9' = */ 0x39) || - ch === /* '-' = */ 0x2d || - ch === /* '.' = */ 0x2e - ) { - strBuf.push(String.fromCharCode(ch)); - } else { - break; - } - } - const value = parseFloat(strBuf.join("")); - if (isNaN(value)) { - throw new FormatError(`Invalid floating point number: ${value}`); - } - return value; - } -} - -export { PostScriptLexer, PostScriptParser }; diff --git a/src/display/api.js b/src/display/api.js index feef19b25..2a1790f3d 100644 --- a/src/display/api.js +++ b/src/display/api.js @@ -159,9 +159,6 @@ const RENDERING_CANCELLED_TIMEOUT = 100; // ms * @property {number} [maxImageSize] - The maximum allowed image size in total * pixels, i.e. width * height. Images above this value will not be rendered. * Use -1 for no limit, which is also the default value. - * @property {boolean} [isEvalSupported] - Determines if we can evaluate strings - * as JavaScript. Primarily used to improve performance of PDF functions. - * The default value is `true`. * @property {boolean} [isOffscreenCanvasSupported] - Determines if we can use * `OffscreenCanvas` in the worker. Primarily used to improve performance of * image conversion/rendering. @@ -283,7 +280,6 @@ function getDocument(src = {}) { Number.isInteger(src.maxImageSize) && src.maxImageSize > -1 ? src.maxImageSize : -1; - const isEvalSupported = src.isEvalSupported !== false; const isOffscreenCanvasSupported = typeof src.isOffscreenCanvasSupported === "boolean" ? src.isOffscreenCanvasSupported @@ -397,7 +393,6 @@ function getDocument(src = {}) { maxImageSize, disableFontFace, ignoreErrors, - isEvalSupported, isOffscreenCanvasSupported, isImageDecoderSupported, canvasMaxAreaInBytes, diff --git a/src/shared/util.js b/src/shared/util.js index 4e433fda6..778fcbd89 100644 --- a/src/shared/util.js +++ b/src/shared/util.js @@ -620,25 +620,11 @@ function isLittleEndian() { return view32[0] === 1; } -// Checks if it's possible to eval JS expressions. -function isEvalSupported() { - try { - new Function(""); // eslint-disable-line no-new, no-new-func - return true; - } catch { - return false; - } -} - class FeatureTest { static get isLittleEndian() { return shadow(this, "isLittleEndian", isLittleEndian()); } - static get isEvalSupported() { - return shadow(this, "isEvalSupported", isEvalSupported()); - } - static get isOffscreenCanvasSupported() { return shadow( this, diff --git a/test/unit/annotation_spec.js b/test/unit/annotation_spec.js index 820aacced..28a5a9c27 100644 --- a/test/unit/annotation_spec.js +++ b/test/unit/annotation_spec.js @@ -57,7 +57,6 @@ describe("annotation", function () { }, }; this.evaluatorOptions = { - isEvalSupported: true, isOffscreenCanvasSupported: false, }; } diff --git a/test/unit/clitests.json b/test/unit/clitests.json index 230ed4e51..876f84de7 100644 --- a/test/unit/clitests.json +++ b/test/unit/clitests.json @@ -26,7 +26,6 @@ "event_utils_spec.js", "fetch_stream_spec.js", "font_substitutions_spec.js", - "function_spec.js", "image_utils_spec.js", "message_handler_spec.js", "metadata_spec.js", diff --git a/test/unit/default_appearance_spec.js b/test/unit/default_appearance_spec.js index 5599cedac..b36c7148d 100644 --- a/test/unit/default_appearance_spec.js +++ b/test/unit/default_appearance_spec.js @@ -57,19 +57,14 @@ describe("Default appearance", function () { }); describe("parseAppearanceStream", () => { - let evaluatorOptions, xref, globalColorSpaceCache; + let xref, globalColorSpaceCache; beforeAll(function () { - evaluatorOptions = { - isEvalSupported: true, - isOffscreenCanvasSupported: false, - }; xref = new XRefMock(); globalColorSpaceCache = new GlobalColorSpaceCache(); }); afterAll(function () { - evaluatorOptions = null; xref = null; globalColorSpaceCache = null; }); @@ -105,12 +100,7 @@ describe("Default appearance", function () { fontColor: new Uint8ClampedArray([107, 217, 41]), }; expect( - parseAppearanceStream( - appearance, - evaluatorOptions, - xref, - globalColorSpaceCache - ) + parseAppearanceStream(appearance, xref, globalColorSpaceCache) ).toEqual(result); expect(appearance.pos).toEqual(0); }); @@ -131,12 +121,7 @@ describe("Default appearance", function () { fontColor: new Uint8ClampedArray([237, 43, 112]), }; expect( - parseAppearanceStream( - appearance, - evaluatorOptions, - xref, - globalColorSpaceCache - ) + parseAppearanceStream(appearance, xref, globalColorSpaceCache) ).toEqual(result); expect(appearance.pos).toEqual(0); }); @@ -173,12 +158,7 @@ describe("Default appearance", function () { fontColor: new Uint8ClampedArray([135, 78, 254]), }; expect( - parseAppearanceStream( - appearance, - evaluatorOptions, - xref, - globalColorSpaceCache - ) + parseAppearanceStream(appearance, xref, globalColorSpaceCache) ).toEqual(result); expect(appearance.pos).toEqual(0); }); @@ -201,12 +181,7 @@ describe("Default appearance", function () { fontColor: new Uint8ClampedArray([16, 124, 16]), }; expect( - parseAppearanceStream( - appearance, - evaluatorOptions, - xref, - globalColorSpaceCache - ) + parseAppearanceStream(appearance, xref, globalColorSpaceCache) ).toEqual(result); expect(appearance.pos).toEqual(0); }); @@ -232,12 +207,7 @@ describe("Default appearance", function () { fontColor: new Uint8ClampedArray([149, 63, 60]), }; expect( - parseAppearanceStream( - appearance, - evaluatorOptions, - xref, - globalColorSpaceCache - ) + parseAppearanceStream(appearance, xref, globalColorSpaceCache) ).toEqual(result); expect(appearance.pos).toEqual(0); }); @@ -261,12 +231,7 @@ describe("Default appearance", function () { fontColor: new Uint8ClampedArray([0, 85, 127]), }; expect( - parseAppearanceStream( - appearance, - evaluatorOptions, - xref, - globalColorSpaceCache - ) + parseAppearanceStream(appearance, xref, globalColorSpaceCache) ).toEqual(result); expect(appearance.pos).toEqual(0); }); diff --git a/test/unit/function_spec.js b/test/unit/function_spec.js deleted file mode 100644 index 3e167054a..000000000 --- a/test/unit/function_spec.js +++ /dev/null @@ -1,583 +0,0 @@ -/* Copyright 2017 Mozilla Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { - PostScriptCompiler, - PostScriptEvaluator, -} from "../../src/core/function.js"; -import { PostScriptLexer, PostScriptParser } from "../../src/core/ps_parser.js"; -import { StringStream } from "../../src/core/stream.js"; - -describe("function", function () { - describe("PostScriptParser", function () { - function parse(program) { - const stream = new StringStream(program); - const parser = new PostScriptParser(new PostScriptLexer(stream)); - return parser.parse(); - } - it("parses empty programs", function () { - const output = parse("{}"); - expect(output.length).toEqual(0); - }); - it("parses positive numbers", function () { - const number = 999; - const program = parse("{ " + number + " }"); - const expectedProgram = [number]; - expect(program).toEqual(expectedProgram); - }); - it("parses negative numbers", function () { - const number = -999; - const program = parse("{ " + number + " }"); - const expectedProgram = [number]; - expect(program).toEqual(expectedProgram); - }); - it("parses negative floats", function () { - const number = 3.3; - const program = parse("{ " + number + " }"); - const expectedProgram = [number]; - expect(program).toEqual(expectedProgram); - }); - it("parses operators", function () { - const program = parse("{ sub }"); - const expectedProgram = ["sub"]; - expect(program).toEqual(expectedProgram); - }); - it("parses if statements", function () { - const program = parse("{ { 99 } if }"); - const expectedProgram = [3, "jz", 99]; - expect(program).toEqual(expectedProgram); - }); - it("parses ifelse statements", function () { - const program = parse("{ { 99 } { 44 } ifelse }"); - const expectedProgram = [5, "jz", 99, 6, "j", 44]; - expect(program).toEqual(expectedProgram); - }); - it("handles missing brackets", function () { - expect(function () { - parse("{"); - }).toThrow(new Error("Unexpected symbol: found undefined expected 1.")); - }); - it("handles junk after the end", function () { - const number = 3.3; - const program = parse("{ " + number + " }#"); - const expectedProgram = [number]; - expect(program).toEqual(expectedProgram); - }); - }); - - describe("PostScriptEvaluator", function () { - function evaluate(program) { - const stream = new StringStream(program); - const parser = new PostScriptParser(new PostScriptLexer(stream)); - const code = parser.parse(); - const evaluator = new PostScriptEvaluator(code); - const output = evaluator.execute(); - return output; - } - - it("pushes stack", function () { - const stack = evaluate("{ 99 }"); - const expectedStack = [99]; - expect(stack).toEqual(expectedStack); - }); - it("handles if with true", function () { - const stack = evaluate("{ 1 {99} if }"); - const expectedStack = [99]; - expect(stack).toEqual(expectedStack); - }); - it("handles if with false", function () { - const stack = evaluate("{ 0 {99} if }"); - const expectedStack = []; - expect(stack).toEqual(expectedStack); - }); - it("handles ifelse with true", function () { - const stack = evaluate("{ 1 {99} {77} ifelse }"); - const expectedStack = [99]; - expect(stack).toEqual(expectedStack); - }); - it("handles ifelse with false", function () { - const stack = evaluate("{ 0 {99} {77} ifelse }"); - const expectedStack = [77]; - expect(stack).toEqual(expectedStack); - }); - it("handles nested if", function () { - const stack = evaluate("{ 1 {1 {77} if} if }"); - const expectedStack = [77]; - expect(stack).toEqual(expectedStack); - }); - - it("abs", function () { - const stack = evaluate("{ -2 abs }"); - const expectedStack = [2]; - expect(stack).toEqual(expectedStack); - }); - it("adds", function () { - const stack = evaluate("{ 1 2 add }"); - const expectedStack = [3]; - expect(stack).toEqual(expectedStack); - }); - it("boolean and", function () { - const stack = evaluate("{ true false and }"); - const expectedStack = [false]; - expect(stack).toEqual(expectedStack); - }); - it("bitwise and", function () { - const stack = evaluate("{ 254 1 and }"); - const expectedStack = [254 & 1]; - expect(stack).toEqual(expectedStack); - }); - it("the angle in degrees (0-360) whose tangent is num/den.", function () { - const stack = evaluate("{ 1 -1 atan }"); - const expectedStack = [135]; - expect(stack).toEqual(expectedStack); - }); - it("handles bitshifting ", function () { - const stack = evaluate("{ 50 2 bitshift }"); - const expectedStack = [200]; - expect(stack).toEqual(expectedStack); - }); - it("calculates the ceiling value", function () { - const stack = evaluate("{ 9.9 ceiling }"); - const expectedStack = [10]; - expect(stack).toEqual(expectedStack); - }); - it("copies", function () { - const stack = evaluate("{ 99 98 2 copy }"); - const expectedStack = [99, 98, 99, 98]; - expect(stack).toEqual(expectedStack); - }); - it("calculates the cosine of an angle in degrees", function () { - const stack = evaluate("{ 180 cos }"); - const expectedStack = [-1]; - expect(stack).toEqual(expectedStack); - }); - it("converts to int", function () { - const stack = evaluate("{ 9.9 cvi }"); - const expectedStack = [9]; - expect(stack).toEqual(expectedStack); - }); - it("converts negatives to int", function () { - const stack = evaluate("{ -9.9 cvi }"); - const expectedStack = [-9]; - expect(stack).toEqual(expectedStack); - }); - it("converts to real", function () { - const stack = evaluate("{ 55.34 cvr }"); - const expectedStack = [55.34]; - expect(stack).toEqual(expectedStack); - }); - it("divides", function () { - const stack = evaluate("{ 6 5 div }"); - const expectedStack = [1.2]; - expect(stack).toEqual(expectedStack); - }); - it("maps division by zero to infinity", function () { - const stack = evaluate("{ 6 0 div }"); - const expectedStack = [Infinity]; - expect(stack).toEqual(expectedStack); - }); - it("duplicates", function () { - const stack = evaluate("{ 99 dup }"); - const expectedStack = [99, 99]; - expect(stack).toEqual(expectedStack); - }); - it("accepts an equality", function () { - const stack = evaluate("{ 9 9 eq }"); - const expectedStack = [true]; - expect(stack).toEqual(expectedStack); - }); - it("rejects an inequality", function () { - const stack = evaluate("{ 9 8 eq }"); - const expectedStack = [false]; - expect(stack).toEqual(expectedStack); - }); - it("exchanges", function () { - const stack = evaluate("{ 44 99 exch }"); - const expectedStack = [99, 44]; - expect(stack).toEqual(expectedStack); - }); - it("handles exponentiation", function () { - const stack = evaluate("{ 10 2 exp }"); - const expectedStack = [100]; - expect(stack).toEqual(expectedStack); - }); - it("pushes false onto the stack", function () { - const stack = evaluate("{ false }"); - const expectedStack = [false]; - expect(stack).toEqual(expectedStack); - }); - it("calculates the floor value", function () { - const stack = evaluate("{ 9.9 floor }"); - const expectedStack = [9]; - expect(stack).toEqual(expectedStack); - }); - it("handles greater than or equal to", function () { - const stack = evaluate("{ 10 9 ge }"); - const expectedStack = [true]; - expect(stack).toEqual(expectedStack); - }); - it("rejects less than for greater than or equal to", function () { - const stack = evaluate("{ 8 9 ge }"); - const expectedStack = [false]; - expect(stack).toEqual(expectedStack); - }); - it("handles greater than", function () { - const stack = evaluate("{ 10 9 gt }"); - const expectedStack = [true]; - expect(stack).toEqual(expectedStack); - }); - it("rejects less than or equal for greater than", function () { - const stack = evaluate("{ 9 9 gt }"); - const expectedStack = [false]; - expect(stack).toEqual(expectedStack); - }); - it("divides to integer", function () { - const stack = evaluate("{ 2 3 idiv }"); - const expectedStack = [0]; - expect(stack).toEqual(expectedStack); - }); - it("divides to negative integer", function () { - const stack = evaluate("{ -2 3 idiv }"); - const expectedStack = [0]; - expect(stack).toEqual(expectedStack); - }); - it("duplicates index", function () { - const stack = evaluate("{ 4 3 2 1 2 index }"); - const expectedStack = [4, 3, 2, 1, 3]; - expect(stack).toEqual(expectedStack); - }); - it("handles less than or equal to", function () { - const stack = evaluate("{ 9 10 le }"); - const expectedStack = [true]; - expect(stack).toEqual(expectedStack); - }); - it("rejects greater than for less than or equal to", function () { - const stack = evaluate("{ 10 9 le }"); - const expectedStack = [false]; - expect(stack).toEqual(expectedStack); - }); - it("calculates the natural logarithm", function () { - const stack = evaluate("{ 10 ln }"); - const expectedStack = [Math.log(10)]; - expect(stack).toEqual(expectedStack); - }); - it("calculates the base 10 logarithm", function () { - const stack = evaluate("{ 100 log }"); - const expectedStack = [2]; - expect(stack).toEqual(expectedStack); - }); - it("handles less than", function () { - const stack = evaluate("{ 9 10 lt }"); - const expectedStack = [true]; - expect(stack).toEqual(expectedStack); - }); - it("rejects greater than or equal to for less than", function () { - const stack = evaluate("{ 10 9 lt }"); - const expectedStack = [false]; - expect(stack).toEqual(expectedStack); - }); - it("performs the modulo operation", function () { - const stack = evaluate("{ 4 3 mod }"); - const expectedStack = [1]; - expect(stack).toEqual(expectedStack); - }); - it("multiplies two numbers (positive result)", function () { - const stack = evaluate("{ 9 8 mul }"); - const expectedStack = [72]; - expect(stack).toEqual(expectedStack); - }); - it("multiplies two numbers (negative result)", function () { - const stack = evaluate("{ 9 -8 mul }"); - const expectedStack = [-72]; - expect(stack).toEqual(expectedStack); - }); - it("accepts an inequality", function () { - const stack = evaluate("{ 9 8 ne }"); - const expectedStack = [true]; - expect(stack).toEqual(expectedStack); - }); - it("rejects an equality", function () { - const stack = evaluate("{ 9 9 ne }"); - const expectedStack = [false]; - expect(stack).toEqual(expectedStack); - }); - it("negates", function () { - const stack = evaluate("{ 4.5 neg }"); - const expectedStack = [-4.5]; - expect(stack).toEqual(expectedStack); - }); - it("boolean not", function () { - const stack = evaluate("{ true not }"); - const expectedStack = [false]; - expect(stack).toEqual(expectedStack); - }); - it("bitwise not", function () { - const stack = evaluate("{ 12 not }"); - const expectedStack = [-13]; - expect(stack).toEqual(expectedStack); - }); - it("boolean or", function () { - const stack = evaluate("{ true false or }"); - const expectedStack = [true]; - expect(stack).toEqual(expectedStack); - }); - it("bitwise or", function () { - const stack = evaluate("{ 254 1 or }"); - const expectedStack = [254 | 1]; - expect(stack).toEqual(expectedStack); - }); - it("pops stack", function () { - const stack = evaluate("{ 1 2 pop }"); - const expectedStack = [1]; - expect(stack).toEqual(expectedStack); - }); - it("rolls stack right", function () { - const stack = evaluate("{ 1 3 2 2 4 1 roll }"); - const expectedStack = [2, 1, 3, 2]; - expect(stack).toEqual(expectedStack); - }); - it("rolls stack left", function () { - const stack = evaluate("{ 1 3 2 2 4 -1 roll }"); - const expectedStack = [3, 2, 2, 1]; - expect(stack).toEqual(expectedStack); - }); - it("rounds a number", function () { - const stack = evaluate("{ 9.52 round }"); - const expectedStack = [10]; - expect(stack).toEqual(expectedStack); - }); - it("calculates the sine of an angle in degrees", function () { - const stack = evaluate("{ 90 sin }"); - const expectedStack = [1]; - expect(stack).toEqual(expectedStack); - }); - it("calculates a square root (integer)", function () { - const stack = evaluate("{ 100 sqrt }"); - const expectedStack = [10]; - expect(stack).toEqual(expectedStack); - }); - it("calculates a square root (float)", function () { - const stack = evaluate("{ 99 sqrt }"); - const expectedStack = [Math.sqrt(99)]; - expect(stack).toEqual(expectedStack); - }); - it("subtracts (positive result)", function () { - const stack = evaluate("{ 6 4 sub }"); - const expectedStack = [2]; - expect(stack).toEqual(expectedStack); - }); - it("subtracts (negative result)", function () { - const stack = evaluate("{ 4 6 sub }"); - const expectedStack = [-2]; - expect(stack).toEqual(expectedStack); - }); - it("pushes true onto the stack", function () { - const stack = evaluate("{ true }"); - const expectedStack = [true]; - expect(stack).toEqual(expectedStack); - }); - it("truncates a number", function () { - const stack = evaluate("{ 35.004 truncate }"); - const expectedStack = [35]; - expect(stack).toEqual(expectedStack); - }); - it("calculates an exclusive or value", function () { - const stack = evaluate("{ 3 9 xor }"); - const expectedStack = [10]; - expect(stack).toEqual(expectedStack); - }); - }); - - describe("PostScriptCompiler", function () { - function check(code, domain, range, samples) { - const compiler = new PostScriptCompiler(); - const compiledCode = compiler.compile(code, domain, range); - if (samples === null) { - expect(compiledCode).toBeNull(); - } else { - expect(compiledCode).not.toBeNull(); - // eslint-disable-next-line no-new-func - const fn = new Function( - "src", - "srcOffset", - "dest", - "destOffset", - compiledCode - ); - for (const { input, output } of samples) { - const out = new Float32Array(output.length); - fn(input, 0, out, 0); - expect(Array.from(out)).toEqual(output); - } - } - } - - it("check compiled add", function () { - check([0.25, 0.5, "add"], [], [0, 1], [{ input: [], output: [0.75] }]); - check([0, "add"], [0, 1], [0, 1], [{ input: [0.25], output: [0.25] }]); - check([0.5, "add"], [0, 1], [0, 1], [{ input: [0.25], output: [0.75] }]); - check( - [0, "exch", "add"], - [0, 1], - [0, 1], - [{ input: [0.25], output: [0.25] }] - ); - check( - [0.5, "exch", "add"], - [0, 1], - [0, 1], - [{ input: [0.25], output: [0.75] }] - ); - check( - ["add"], - [0, 1, 0, 1], - [0, 1], - [{ input: [0.25, 0.5], output: [0.75] }] - ); - check(["add"], [0, 1], [0, 1], null); - }); - it("check compiled sub", function () { - check([0.5, 0.25, "sub"], [], [0, 1], [{ input: [], output: [0.25] }]); - check([0, "sub"], [0, 1], [0, 1], [{ input: [0.25], output: [0.25] }]); - check([0.5, "sub"], [0, 1], [0, 1], [{ input: [0.75], output: [0.25] }]); - check( - [0, "exch", "sub"], - [0, 1], - [-1, 1], - [{ input: [0.25], output: [-0.25] }] - ); - check( - [0.75, "exch", "sub"], - [0, 1], - [-1, 1], - [{ input: [0.25], output: [0.5] }] - ); - check( - ["sub"], - [0, 1, 0, 1], - [-1, 1], - [{ input: [0.25, 0.5], output: [-0.25] }] - ); - check(["sub"], [0, 1], [0, 1], null); - - check( - [1, "dup", 3, 2, "roll", "sub", "sub"], - [0, 1], - [0, 1], - [{ input: [0.75], output: [0.75] }] - ); - }); - it("check compiled mul", function () { - check([0.25, 0.5, "mul"], [], [0, 1], [{ input: [], output: [0.125] }]); - check([0, "mul"], [0, 1], [0, 1], [{ input: [0.25], output: [0] }]); - check([0.5, "mul"], [0, 1], [0, 1], [{ input: [0.25], output: [0.125] }]); - check([1, "mul"], [0, 1], [0, 1], [{ input: [0.25], output: [0.25] }]); - check( - [0, "exch", "mul"], - [0, 1], - [0, 1], - [{ input: [0.25], output: [0] }] - ); - check( - [0.5, "exch", "mul"], - [0, 1], - [0, 1], - [{ input: [0.25], output: [0.125] }] - ); - check( - [1, "exch", "mul"], - [0, 1], - [0, 1], - [{ input: [0.25], output: [0.25] }] - ); - check( - ["mul"], - [0, 1, 0, 1], - [0, 1], - [{ input: [0.25, 0.5], output: [0.125] }] - ); - check(["mul"], [0, 1], [0, 1], null); - }); - it("check compiled max", function () { - check( - ["dup", 0.75, "gt", 7, "jz", "pop", 0.75], - [0, 1], - [0, 1], - [{ input: [0.5], output: [0.5] }] - ); - check( - ["dup", 0.75, "gt", 7, "jz", "pop", 0.75], - [0, 1], - [0, 1], - [{ input: [1], output: [0.75] }] - ); - check(["dup", 0.75, "gt", 5, "jz", "pop", 0.75], [0, 1], [0, 1], null); - }); - it("check pop/roll/index", function () { - check([1, "pop"], [0, 1], [0, 1], [{ input: [0.5], output: [0.5] }]); - check( - [1, 3, -1, "roll"], - [0, 1, 0, 1], - [0, 1, 0, 1, 0, 1], - [{ input: [0.25, 0.5], output: [0.5, 1, 0.25] }] - ); - check( - [1, 3, 1, "roll"], - [0, 1, 0, 1], - [0, 1, 0, 1, 0, 1], - [{ input: [0.25, 0.5], output: [1, 0.25, 0.5] }] - ); - check([1, 3, 1.5, "roll"], [0, 1, 0, 1], [0, 1, 0, 1, 0, 1], null); - check( - [1, 1, "index"], - [0, 1], - [0, 1, 0, 1, 0, 1], - [{ input: [0.5], output: [0.5, 1, 0.5] }] - ); - check([1, 3, "index", "pop"], [0, 1], [0, 1], null); - check([1, 0.5, "index", "pop"], [0, 1], [0, 1], null); - }); - it("check input boundaries", function () { - check([], [0, 0.5], [0, 1], [{ input: [1], output: [0.5] }]); - check([], [0.5, 1], [0, 1], [{ input: [0], output: [0.5] }]); - check( - ["dup"], - [0.5, 0.75], - [0, 1, 0, 1], - [{ input: [0], output: [0.5, 0.5] }] - ); - check([], [100, 1001], [0, 10000], [{ input: [1000], output: [1000] }]); - }); - it("check output boundaries", function () { - check([], [0, 1], [0, 0.5], [{ input: [1], output: [0.5] }]); - check([], [0, 1], [0.5, 1], [{ input: [0], output: [0.5] }]); - check( - ["dup"], - [0, 1], - [0.5, 1, 0.75, 1], - [{ input: [0], output: [0.5, 0.75] }] - ); - check([], [0, 10000], [100, 1001], [{ input: [1000], output: [1000] }]); - }); - it("compile optimized", function () { - const compiler = new PostScriptCompiler(); - const code = [0, "add", 1, 1, 3, -1, "roll", "sub", "sub", 1, "mul"]; - const compiledCode = compiler.compile(code, [0, 1], [0, 1]); - expect(compiledCode).toEqual( - "dest[destOffset + 0] = Math.max(0, Math.min(1, src[srcOffset + 0]));" - ); - }); - }); -}); diff --git a/test/unit/jasmine-boot.js b/test/unit/jasmine-boot.js index 7d63428bb..ee341b7e3 100644 --- a/test/unit/jasmine-boot.js +++ b/test/unit/jasmine-boot.js @@ -69,7 +69,6 @@ async function initializePDFJS(callback) { "pdfjs-test/unit/event_utils_spec.js", "pdfjs-test/unit/fetch_stream_spec.js", "pdfjs-test/unit/font_substitutions_spec.js", - "pdfjs-test/unit/function_spec.js", "pdfjs-test/unit/image_utils_spec.js", "pdfjs-test/unit/message_handler_spec.js", "pdfjs-test/unit/metadata_spec.js", diff --git a/web/app_options.js b/web/app_options.js index b8f044926..3a3764e55 100644 --- a/web/app_options.js +++ b/web/app_options.js @@ -486,11 +486,6 @@ const defaultOptions = { : "../web/iccs/", kind: OptionKind.API, }, - isEvalSupported: { - /** @type {boolean} */ - value: true, - kind: OptionKind.API, - }, isOffscreenCanvasSupported: { /** @type {boolean} */ value: true,