pdf.js/test/unit/evaluator_spec.js

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

418 lines
13 KiB
JavaScript
Raw Normal View History

2017-01-10 01:40:57 +09:00
/* 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.
*/
2012-05-11 06:11:27 +09:00
import { createIdFactory, XRefMock } from "./test_utils.js";
import { Dict, Name } from "../../src/core/primitives.js";
import { FormatError, OPS } from "../../src/shared/util.js";
import { Stream, StringStream } from "../../src/core/stream.js";
import { OperatorList } from "../../src/core/operator_list.js";
import { PartialEvaluator } from "../../src/core/evaluator.js";
import { WorkerTask } from "../../src/core/worker.js";
2017-01-10 01:40:57 +09:00
describe("evaluator", function () {
2012-05-11 06:11:27 +09:00
function HandlerMock() {
this.inputs = [];
}
HandlerMock.prototype = {
send(name, data) {
this.inputs.push({ name, data });
Fix inconsistent spacing and trailing commas in objects in `test/` files, so we can enable the `comma-dangle` and `object-curly-spacing` ESLint rules later on http://eslint.org/docs/rules/comma-dangle http://eslint.org/docs/rules/object-curly-spacing Given that we currently have quite inconsistent object formatting, fixing this in *one* big patch probably wouldn't be feasible (since I cannot imagine anyone wanting to review that); hence I've opted to try and do this piecewise instead. Please note: This patch was created automatically, using the ESLint `--fix` command line option. In a couple of places this caused lines to become too long, and I've fixed those manually; please refer to the interdiff below for the only hand-edits in this patch. ```diff diff --git a/test/chromium/test-telemetry.js b/test/chromium/test-telemetry.js index cc412a31..2e5bdfa1 100755 --- a/test/chromium/test-telemetry.js +++ b/test/chromium/test-telemetry.js @@ -324,7 +324,7 @@ var tests = [ var window = createExtensionGlobal(); telemetryScript.runInNewContext(window); window.chrome.runtime.getManifest = function() { - return { version: '1.0.1', }; + return { version: '1.0.1', }; }; window.Date.test_now_value += 12 * 36E5; telemetryScript.runInNewContext(window); diff --git a/test/unit/api_spec.js b/test/unit/api_spec.js index 1f00747a..f22988e7 100644 --- a/test/unit/api_spec.js +++ b/test/unit/api_spec.js @@ -503,8 +503,9 @@ describe('api', function() { it('gets destinations, from /Dests dictionary', function(done) { var promise = doc.getDestinations(); promise.then(function(data) { - expect(data).toEqual({ chapter1: [{ gen: 0, num: 17, }, { name: 'XYZ', }, - 0, 841.89, null], }); + expect(data).toEqual({ + chapter1: [{ gen: 0, num: 17, }, { name: 'XYZ', }, 0, 841.89, null], + }); done(); }).catch(function (reason) { done.fail(reason); diff --git a/test/unit/function_spec.js b/test/unit/function_spec.js index 66441212..62127eb9 100644 --- a/test/unit/function_spec.js +++ b/test/unit/function_spec.js @@ -492,9 +492,11 @@ describe('function', function() { 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([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, '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], ```
2017-06-02 19:55:01 +09:00
},
2012-05-11 06:11:27 +09:00
};
function ResourcesMock() {}
ResourcesMock.prototype = {
get(name) {
2012-05-11 06:11:27 +09:00
return this[name];
Fix inconsistent spacing and trailing commas in objects in `test/` files, so we can enable the `comma-dangle` and `object-curly-spacing` ESLint rules later on http://eslint.org/docs/rules/comma-dangle http://eslint.org/docs/rules/object-curly-spacing Given that we currently have quite inconsistent object formatting, fixing this in *one* big patch probably wouldn't be feasible (since I cannot imagine anyone wanting to review that); hence I've opted to try and do this piecewise instead. Please note: This patch was created automatically, using the ESLint `--fix` command line option. In a couple of places this caused lines to become too long, and I've fixed those manually; please refer to the interdiff below for the only hand-edits in this patch. ```diff diff --git a/test/chromium/test-telemetry.js b/test/chromium/test-telemetry.js index cc412a31..2e5bdfa1 100755 --- a/test/chromium/test-telemetry.js +++ b/test/chromium/test-telemetry.js @@ -324,7 +324,7 @@ var tests = [ var window = createExtensionGlobal(); telemetryScript.runInNewContext(window); window.chrome.runtime.getManifest = function() { - return { version: '1.0.1', }; + return { version: '1.0.1', }; }; window.Date.test_now_value += 12 * 36E5; telemetryScript.runInNewContext(window); diff --git a/test/unit/api_spec.js b/test/unit/api_spec.js index 1f00747a..f22988e7 100644 --- a/test/unit/api_spec.js +++ b/test/unit/api_spec.js @@ -503,8 +503,9 @@ describe('api', function() { it('gets destinations, from /Dests dictionary', function(done) { var promise = doc.getDestinations(); promise.then(function(data) { - expect(data).toEqual({ chapter1: [{ gen: 0, num: 17, }, { name: 'XYZ', }, - 0, 841.89, null], }); + expect(data).toEqual({ + chapter1: [{ gen: 0, num: 17, }, { name: 'XYZ', }, 0, 841.89, null], + }); done(); }).catch(function (reason) { done.fail(reason); diff --git a/test/unit/function_spec.js b/test/unit/function_spec.js index 66441212..62127eb9 100644 --- a/test/unit/function_spec.js +++ b/test/unit/function_spec.js @@ -492,9 +492,11 @@ describe('function', function() { 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([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, '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], ```
2017-06-02 19:55:01 +09:00
},
2012-05-11 06:11:27 +09:00
};
async function runOperatorListCheck(evaluator, stream, resources) {
const operatorList = new OperatorList();
const task = new WorkerTask("OperatorListCheck");
await evaluator.getOperatorList({
stream,
task,
resources,
operatorList,
});
return operatorList;
2014-05-10 10:21:15 +09:00
}
let partialEvaluator;
Change the signatures of the `PartialEvaluator` "constructor" and its `getOperatorList`/`getTextContent` methods to take parameter objects Currently these methods accept a large number of parameters, which creates quite unwieldy call-sites. When invoking them, you have to remember not only what arguments to supply, but also the correct order, to avoid runtime errors. Furthermore, since some of the parameters are optional, you also have to remember to pass e.g. `null` or `undefined` for those ones. Also, adding new parameters to these methods (which happens occasionally), often becomes unnecessarily tedious (based on personal experience). Please note that I do *not* think that we need/should convert *every* single method in `evaluator.js` (or elsewhere in `/core` files) to take parameter objects. However, in my opinion, once a method starts relying on approximately five parameter (or even more), passing them in individually becomes quite cumbersome. With these changes, I obviously needed to update the `evaluator_spec.js` unit-tests. The main change there, except the new method signatures[1], is that it's now re-using *one* `PartialEvalutor` instance, since I couldn't see any compelling reason for creating a new one in every single test. *Note:* If this patch is accepted, my intention is to (time permitting) see if it makes sense to convert additional methods in `evaluator.js` (and other `/core` files) in a similar fashion, but I figured that it'd be a good idea to limit the initial scope somewhat. --- [1] A fun fact here, note how the `PartialEvaluator` signature used in `evaluator_spec.js` wasn't even correct in the current `master`.
2017-04-30 06:13:51 +09:00
beforeAll(function () {
Change the signatures of the `PartialEvaluator` "constructor" and its `getOperatorList`/`getTextContent` methods to take parameter objects Currently these methods accept a large number of parameters, which creates quite unwieldy call-sites. When invoking them, you have to remember not only what arguments to supply, but also the correct order, to avoid runtime errors. Furthermore, since some of the parameters are optional, you also have to remember to pass e.g. `null` or `undefined` for those ones. Also, adding new parameters to these methods (which happens occasionally), often becomes unnecessarily tedious (based on personal experience). Please note that I do *not* think that we need/should convert *every* single method in `evaluator.js` (or elsewhere in `/core` files) to take parameter objects. However, in my opinion, once a method starts relying on approximately five parameter (or even more), passing them in individually becomes quite cumbersome. With these changes, I obviously needed to update the `evaluator_spec.js` unit-tests. The main change there, except the new method signatures[1], is that it's now re-using *one* `PartialEvalutor` instance, since I couldn't see any compelling reason for creating a new one in every single test. *Note:* If this patch is accepted, my intention is to (time permitting) see if it makes sense to convert additional methods in `evaluator.js` (and other `/core` files) in a similar fashion, but I figured that it'd be a good idea to limit the initial scope somewhat. --- [1] A fun fact here, note how the `PartialEvaluator` signature used in `evaluator_spec.js` wasn't even correct in the current `master`.
2017-04-30 06:13:51 +09:00
partialEvaluator = new PartialEvaluator({
xref: new XRefMock(),
Change the signatures of the `PartialEvaluator` "constructor" and its `getOperatorList`/`getTextContent` methods to take parameter objects Currently these methods accept a large number of parameters, which creates quite unwieldy call-sites. When invoking them, you have to remember not only what arguments to supply, but also the correct order, to avoid runtime errors. Furthermore, since some of the parameters are optional, you also have to remember to pass e.g. `null` or `undefined` for those ones. Also, adding new parameters to these methods (which happens occasionally), often becomes unnecessarily tedious (based on personal experience). Please note that I do *not* think that we need/should convert *every* single method in `evaluator.js` (or elsewhere in `/core` files) to take parameter objects. However, in my opinion, once a method starts relying on approximately five parameter (or even more), passing them in individually becomes quite cumbersome. With these changes, I obviously needed to update the `evaluator_spec.js` unit-tests. The main change there, except the new method signatures[1], is that it's now re-using *one* `PartialEvalutor` instance, since I couldn't see any compelling reason for creating a new one in every single test. *Note:* If this patch is accepted, my intention is to (time permitting) see if it makes sense to convert additional methods in `evaluator.js` (and other `/core` files) in a similar fashion, but I figured that it'd be a good idea to limit the initial scope somewhat. --- [1] A fun fact here, note how the `PartialEvaluator` signature used in `evaluator_spec.js` wasn't even correct in the current `master`.
2017-04-30 06:13:51 +09:00
handler: new HandlerMock(),
pageIndex: 0,
idFactory: createIdFactory(/* pageIndex = */ 0),
Change the signatures of the `PartialEvaluator` "constructor" and its `getOperatorList`/`getTextContent` methods to take parameter objects Currently these methods accept a large number of parameters, which creates quite unwieldy call-sites. When invoking them, you have to remember not only what arguments to supply, but also the correct order, to avoid runtime errors. Furthermore, since some of the parameters are optional, you also have to remember to pass e.g. `null` or `undefined` for those ones. Also, adding new parameters to these methods (which happens occasionally), often becomes unnecessarily tedious (based on personal experience). Please note that I do *not* think that we need/should convert *every* single method in `evaluator.js` (or elsewhere in `/core` files) to take parameter objects. However, in my opinion, once a method starts relying on approximately five parameter (or even more), passing them in individually becomes quite cumbersome. With these changes, I obviously needed to update the `evaluator_spec.js` unit-tests. The main change there, except the new method signatures[1], is that it's now re-using *one* `PartialEvalutor` instance, since I couldn't see any compelling reason for creating a new one in every single test. *Note:* If this patch is accepted, my intention is to (time permitting) see if it makes sense to convert additional methods in `evaluator.js` (and other `/core` files) in a similar fashion, but I figured that it'd be a good idea to limit the initial scope somewhat. --- [1] A fun fact here, note how the `PartialEvaluator` signature used in `evaluator_spec.js` wasn't even correct in the current `master`.
2017-04-30 06:13:51 +09:00
});
});
afterAll(function () {
Change the signatures of the `PartialEvaluator` "constructor" and its `getOperatorList`/`getTextContent` methods to take parameter objects Currently these methods accept a large number of parameters, which creates quite unwieldy call-sites. When invoking them, you have to remember not only what arguments to supply, but also the correct order, to avoid runtime errors. Furthermore, since some of the parameters are optional, you also have to remember to pass e.g. `null` or `undefined` for those ones. Also, adding new parameters to these methods (which happens occasionally), often becomes unnecessarily tedious (based on personal experience). Please note that I do *not* think that we need/should convert *every* single method in `evaluator.js` (or elsewhere in `/core` files) to take parameter objects. However, in my opinion, once a method starts relying on approximately five parameter (or even more), passing them in individually becomes quite cumbersome. With these changes, I obviously needed to update the `evaluator_spec.js` unit-tests. The main change there, except the new method signatures[1], is that it's now re-using *one* `PartialEvalutor` instance, since I couldn't see any compelling reason for creating a new one in every single test. *Note:* If this patch is accepted, my intention is to (time permitting) see if it makes sense to convert additional methods in `evaluator.js` (and other `/core` files) in a similar fashion, but I figured that it'd be a good idea to limit the initial scope somewhat. --- [1] A fun fact here, note how the `PartialEvaluator` signature used in `evaluator_spec.js` wasn't even correct in the current `master`.
2017-04-30 06:13:51 +09:00
partialEvaluator = null;
});
describe("splitCombinedOperations", function () {
it("should reject unknown operations", async function () {
const stream = new StringStream("fTT");
const result = await runOperatorListCheck(
Change the signatures of the `PartialEvaluator` "constructor" and its `getOperatorList`/`getTextContent` methods to take parameter objects Currently these methods accept a large number of parameters, which creates quite unwieldy call-sites. When invoking them, you have to remember not only what arguments to supply, but also the correct order, to avoid runtime errors. Furthermore, since some of the parameters are optional, you also have to remember to pass e.g. `null` or `undefined` for those ones. Also, adding new parameters to these methods (which happens occasionally), often becomes unnecessarily tedious (based on personal experience). Please note that I do *not* think that we need/should convert *every* single method in `evaluator.js` (or elsewhere in `/core` files) to take parameter objects. However, in my opinion, once a method starts relying on approximately five parameter (or even more), passing them in individually becomes quite cumbersome. With these changes, I obviously needed to update the `evaluator_spec.js` unit-tests. The main change there, except the new method signatures[1], is that it's now re-using *one* `PartialEvalutor` instance, since I couldn't see any compelling reason for creating a new one in every single test. *Note:* If this patch is accepted, my intention is to (time permitting) see if it makes sense to convert additional methods in `evaluator.js` (and other `/core` files) in a similar fashion, but I figured that it'd be a good idea to limit the initial scope somewhat. --- [1] A fun fact here, note how the `PartialEvaluator` signature used in `evaluator_spec.js` wasn't even correct in the current `master`.
2017-04-30 06:13:51 +09:00
partialEvaluator,
stream,
new ResourcesMock()
2014-05-10 10:21:15 +09:00
);
expect(!!result.fnArray && !!result.argsArray).toEqual(true);
expect(result.fnArray.length).toEqual(1);
expect(result.fnArray[0]).toEqual(OPS.fill);
expect(result.argsArray[0]).toEqual(null);
2012-05-11 06:11:27 +09:00
});
it("should handle one operation", async function () {
const stream = new StringStream("Q");
const result = await runOperatorListCheck(
Change the signatures of the `PartialEvaluator` "constructor" and its `getOperatorList`/`getTextContent` methods to take parameter objects Currently these methods accept a large number of parameters, which creates quite unwieldy call-sites. When invoking them, you have to remember not only what arguments to supply, but also the correct order, to avoid runtime errors. Furthermore, since some of the parameters are optional, you also have to remember to pass e.g. `null` or `undefined` for those ones. Also, adding new parameters to these methods (which happens occasionally), often becomes unnecessarily tedious (based on personal experience). Please note that I do *not* think that we need/should convert *every* single method in `evaluator.js` (or elsewhere in `/core` files) to take parameter objects. However, in my opinion, once a method starts relying on approximately five parameter (or even more), passing them in individually becomes quite cumbersome. With these changes, I obviously needed to update the `evaluator_spec.js` unit-tests. The main change there, except the new method signatures[1], is that it's now re-using *one* `PartialEvalutor` instance, since I couldn't see any compelling reason for creating a new one in every single test. *Note:* If this patch is accepted, my intention is to (time permitting) see if it makes sense to convert additional methods in `evaluator.js` (and other `/core` files) in a similar fashion, but I figured that it'd be a good idea to limit the initial scope somewhat. --- [1] A fun fact here, note how the `PartialEvaluator` signature used in `evaluator_spec.js` wasn't even correct in the current `master`.
2017-04-30 06:13:51 +09:00
partialEvaluator,
stream,
new ResourcesMock()
2014-05-10 10:21:15 +09:00
);
expect(!!result.fnArray && !!result.argsArray).toEqual(true);
expect(result.fnArray.length).toEqual(1);
expect(result.fnArray[0]).toEqual(OPS.restore);
2012-05-11 06:11:27 +09:00
});
it("should handle two glued operations", async function () {
const imgDict = new Dict();
imgDict.set("Subtype", Name.get("Image"));
imgDict.set("Width", 1);
imgDict.set("Height", 1);
const imgStream = new Stream([0]);
imgStream.dict = imgDict;
const xObject = new Dict();
xObject.set("Res1", imgStream);
const resources = new ResourcesMock();
resources.XObject = xObject;
const stream = new StringStream("/Res1 DoQ");
const result = await runOperatorListCheck(
partialEvaluator,
stream,
resources
);
expect(result.fnArray.length).toEqual(3);
expect(result.fnArray[0]).toEqual(OPS.dependency);
expect(result.fnArray[1]).toEqual(OPS.paintImageXObject);
expect(result.fnArray[2]).toEqual(OPS.restore);
expect(result.argsArray.length).toEqual(3);
expect(result.argsArray[0]).toEqual(["img_p0_1"]);
expect(result.argsArray[1]).toEqual(["img_p0_1", 1, 1]);
expect(result.argsArray[2]).toEqual(null);
2012-05-11 06:11:27 +09:00
});
it("should handle three glued operations", async function () {
const stream = new StringStream("fff");
const result = await runOperatorListCheck(
Change the signatures of the `PartialEvaluator` "constructor" and its `getOperatorList`/`getTextContent` methods to take parameter objects Currently these methods accept a large number of parameters, which creates quite unwieldy call-sites. When invoking them, you have to remember not only what arguments to supply, but also the correct order, to avoid runtime errors. Furthermore, since some of the parameters are optional, you also have to remember to pass e.g. `null` or `undefined` for those ones. Also, adding new parameters to these methods (which happens occasionally), often becomes unnecessarily tedious (based on personal experience). Please note that I do *not* think that we need/should convert *every* single method in `evaluator.js` (or elsewhere in `/core` files) to take parameter objects. However, in my opinion, once a method starts relying on approximately five parameter (or even more), passing them in individually becomes quite cumbersome. With these changes, I obviously needed to update the `evaluator_spec.js` unit-tests. The main change there, except the new method signatures[1], is that it's now re-using *one* `PartialEvalutor` instance, since I couldn't see any compelling reason for creating a new one in every single test. *Note:* If this patch is accepted, my intention is to (time permitting) see if it makes sense to convert additional methods in `evaluator.js` (and other `/core` files) in a similar fashion, but I figured that it'd be a good idea to limit the initial scope somewhat. --- [1] A fun fact here, note how the `PartialEvaluator` signature used in `evaluator_spec.js` wasn't even correct in the current `master`.
2017-04-30 06:13:51 +09:00
partialEvaluator,
stream,
new ResourcesMock()
2014-05-10 10:21:15 +09:00
);
expect(!!result.fnArray && !!result.argsArray).toEqual(true);
expect(result.fnArray.length).toEqual(3);
expect(result.fnArray[0]).toEqual(OPS.fill);
expect(result.fnArray[1]).toEqual(OPS.fill);
expect(result.fnArray[2]).toEqual(OPS.fill);
2012-05-11 06:11:27 +09:00
});
2012-05-21 03:44:03 +09:00
it("should handle three glued operations #2", async function () {
const resources = new ResourcesMock();
2012-05-21 03:44:03 +09:00
resources.Res1 = {};
const stream = new StringStream("B*Bf*");
const result = await runOperatorListCheck(
partialEvaluator,
stream,
resources
);
expect(!!result.fnArray && !!result.argsArray).toEqual(true);
expect(result.fnArray.length).toEqual(3);
expect(result.fnArray[0]).toEqual(OPS.eoFillStroke);
expect(result.fnArray[1]).toEqual(OPS.fillStroke);
expect(result.fnArray[2]).toEqual(OPS.eoFill);
2012-05-21 03:44:03 +09:00
});
it("should handle glued operations and operands", async function () {
const stream = new StringStream("f5 Ts");
const result = await runOperatorListCheck(
Change the signatures of the `PartialEvaluator` "constructor" and its `getOperatorList`/`getTextContent` methods to take parameter objects Currently these methods accept a large number of parameters, which creates quite unwieldy call-sites. When invoking them, you have to remember not only what arguments to supply, but also the correct order, to avoid runtime errors. Furthermore, since some of the parameters are optional, you also have to remember to pass e.g. `null` or `undefined` for those ones. Also, adding new parameters to these methods (which happens occasionally), often becomes unnecessarily tedious (based on personal experience). Please note that I do *not* think that we need/should convert *every* single method in `evaluator.js` (or elsewhere in `/core` files) to take parameter objects. However, in my opinion, once a method starts relying on approximately five parameter (or even more), passing them in individually becomes quite cumbersome. With these changes, I obviously needed to update the `evaluator_spec.js` unit-tests. The main change there, except the new method signatures[1], is that it's now re-using *one* `PartialEvalutor` instance, since I couldn't see any compelling reason for creating a new one in every single test. *Note:* If this patch is accepted, my intention is to (time permitting) see if it makes sense to convert additional methods in `evaluator.js` (and other `/core` files) in a similar fashion, but I figured that it'd be a good idea to limit the initial scope somewhat. --- [1] A fun fact here, note how the `PartialEvaluator` signature used in `evaluator_spec.js` wasn't even correct in the current `master`.
2017-04-30 06:13:51 +09:00
partialEvaluator,
stream,
new ResourcesMock()
2014-05-10 10:21:15 +09:00
);
expect(!!result.fnArray && !!result.argsArray).toEqual(true);
expect(result.fnArray.length).toEqual(2);
expect(result.fnArray[0]).toEqual(OPS.fill);
expect(result.fnArray[1]).toEqual(OPS.setTextRise);
expect(result.argsArray.length).toEqual(2);
expect(result.argsArray[1].length).toEqual(1);
expect(result.argsArray[1][0]).toEqual(5);
2012-05-21 03:44:03 +09:00
});
2012-05-21 04:05:23 +09:00
it("should handle glued operations and literals", async function () {
const stream = new StringStream("trueifalserinulln");
const result = await runOperatorListCheck(
Change the signatures of the `PartialEvaluator` "constructor" and its `getOperatorList`/`getTextContent` methods to take parameter objects Currently these methods accept a large number of parameters, which creates quite unwieldy call-sites. When invoking them, you have to remember not only what arguments to supply, but also the correct order, to avoid runtime errors. Furthermore, since some of the parameters are optional, you also have to remember to pass e.g. `null` or `undefined` for those ones. Also, adding new parameters to these methods (which happens occasionally), often becomes unnecessarily tedious (based on personal experience). Please note that I do *not* think that we need/should convert *every* single method in `evaluator.js` (or elsewhere in `/core` files) to take parameter objects. However, in my opinion, once a method starts relying on approximately five parameter (or even more), passing them in individually becomes quite cumbersome. With these changes, I obviously needed to update the `evaluator_spec.js` unit-tests. The main change there, except the new method signatures[1], is that it's now re-using *one* `PartialEvalutor` instance, since I couldn't see any compelling reason for creating a new one in every single test. *Note:* If this patch is accepted, my intention is to (time permitting) see if it makes sense to convert additional methods in `evaluator.js` (and other `/core` files) in a similar fashion, but I figured that it'd be a good idea to limit the initial scope somewhat. --- [1] A fun fact here, note how the `PartialEvaluator` signature used in `evaluator_spec.js` wasn't even correct in the current `master`.
2017-04-30 06:13:51 +09:00
partialEvaluator,
stream,
new ResourcesMock()
2014-05-10 10:21:15 +09:00
);
expect(!!result.fnArray && !!result.argsArray).toEqual(true);
expect(result.fnArray.length).toEqual(3);
expect(result.fnArray[0]).toEqual(OPS.setFlatness);
expect(result.fnArray[1]).toEqual(OPS.setRenderingIntent);
expect(result.fnArray[2]).toEqual(OPS.endPath);
expect(result.argsArray.length).toEqual(3);
expect(result.argsArray[0].length).toEqual(1);
expect(result.argsArray[0][0]).toEqual(true);
expect(result.argsArray[1].length).toEqual(1);
expect(result.argsArray[1][0]).toEqual(false);
expect(result.argsArray[2]).toEqual(null);
});
});
describe("validateNumberOfArgs", function () {
it("should execute if correct number of arguments", async function () {
const stream = new StringStream("5 1 d0");
const result = await runOperatorListCheck(
Change the signatures of the `PartialEvaluator` "constructor" and its `getOperatorList`/`getTextContent` methods to take parameter objects Currently these methods accept a large number of parameters, which creates quite unwieldy call-sites. When invoking them, you have to remember not only what arguments to supply, but also the correct order, to avoid runtime errors. Furthermore, since some of the parameters are optional, you also have to remember to pass e.g. `null` or `undefined` for those ones. Also, adding new parameters to these methods (which happens occasionally), often becomes unnecessarily tedious (based on personal experience). Please note that I do *not* think that we need/should convert *every* single method in `evaluator.js` (or elsewhere in `/core` files) to take parameter objects. However, in my opinion, once a method starts relying on approximately five parameter (or even more), passing them in individually becomes quite cumbersome. With these changes, I obviously needed to update the `evaluator_spec.js` unit-tests. The main change there, except the new method signatures[1], is that it's now re-using *one* `PartialEvalutor` instance, since I couldn't see any compelling reason for creating a new one in every single test. *Note:* If this patch is accepted, my intention is to (time permitting) see if it makes sense to convert additional methods in `evaluator.js` (and other `/core` files) in a similar fashion, but I figured that it'd be a good idea to limit the initial scope somewhat. --- [1] A fun fact here, note how the `PartialEvaluator` signature used in `evaluator_spec.js` wasn't even correct in the current `master`.
2017-04-30 06:13:51 +09:00
partialEvaluator,
stream,
new ResourcesMock()
2014-05-10 10:21:15 +09:00
);
expect(result.argsArray[0][0]).toEqual(5);
expect(result.argsArray[0][1]).toEqual(1);
expect(result.fnArray[0]).toEqual(OPS.setCharWidth);
});
it("should execute if too many arguments", async function () {
const stream = new StringStream("5 1 4 d0");
const result = await runOperatorListCheck(
Change the signatures of the `PartialEvaluator` "constructor" and its `getOperatorList`/`getTextContent` methods to take parameter objects Currently these methods accept a large number of parameters, which creates quite unwieldy call-sites. When invoking them, you have to remember not only what arguments to supply, but also the correct order, to avoid runtime errors. Furthermore, since some of the parameters are optional, you also have to remember to pass e.g. `null` or `undefined` for those ones. Also, adding new parameters to these methods (which happens occasionally), often becomes unnecessarily tedious (based on personal experience). Please note that I do *not* think that we need/should convert *every* single method in `evaluator.js` (or elsewhere in `/core` files) to take parameter objects. However, in my opinion, once a method starts relying on approximately five parameter (or even more), passing them in individually becomes quite cumbersome. With these changes, I obviously needed to update the `evaluator_spec.js` unit-tests. The main change there, except the new method signatures[1], is that it's now re-using *one* `PartialEvalutor` instance, since I couldn't see any compelling reason for creating a new one in every single test. *Note:* If this patch is accepted, my intention is to (time permitting) see if it makes sense to convert additional methods in `evaluator.js` (and other `/core` files) in a similar fashion, but I figured that it'd be a good idea to limit the initial scope somewhat. --- [1] A fun fact here, note how the `PartialEvaluator` signature used in `evaluator_spec.js` wasn't even correct in the current `master`.
2017-04-30 06:13:51 +09:00
partialEvaluator,
stream,
new ResourcesMock()
2014-05-10 10:21:15 +09:00
);
expect(result.argsArray[0][0]).toEqual(1);
expect(result.argsArray[0][1]).toEqual(4);
expect(result.fnArray[0]).toEqual(OPS.setCharWidth);
});
it("should execute if nested commands", async function () {
Add local caching of "simple" Graphics State (ExtGState) data in `PartialEvaluator.getOperatorList` (issue 2813) This patch will help pathological cases the most, with issue 2813 being a particularily problematic example. While there's only *four* `/ExtGState` resources, there's a total `29062` of `setGState` operators. Even though parsing of a single `/ExtGState` resource is quite fast, having to re-parse them thousands of times does add up quite significantly. For simplicity we'll only cache "simple" `/ExtGState` resource, since e.g. the general `SMask` case cannot be easily cached (without re-factoring other code, which may have undesirable effects on general parsing). By caching "simple" `/ExtGState` resource, we thus improve performance by: - Not having to fetch/validate/parse the same `/ExtGState` data over and over. - Handling of repeated `setGState` operators becomes *synchronous* during the `OperatorList` building, instead of having to defer to the event-loop/microtask-queue since the `/ExtGState` parsing is done asynchronously. --- Obviously I had intended to include (standard) benchmark results with this patch, but for reasons I don't understand the test run-time (even with `master`) of the document in issue 2813 is *a lot* slower than in the development viewer (making normal benchmarking infeasible). However, testing this manually in the development viewer (using `pdfBug=Stats`) shows a *reduction* of `~10 %` in the rendering time of the PDF document in issue 2813.
2020-07-11 20:52:11 +09:00
const gState = new Dict();
gState.set("LW", 2);
gState.set("CA", 0.5);
const extGState = new Dict();
extGState.set("GS2", gState);
const resources = new ResourcesMock();
resources.ExtGState = extGState;
const stream = new StringStream("/F2 /GS2 gs 5.711 Tf");
const result = await runOperatorListCheck(
partialEvaluator,
stream,
resources
);
expect(result.fnArray.length).toEqual(3);
expect(result.fnArray[0]).toEqual(OPS.setGState);
expect(result.fnArray[1]).toEqual(OPS.dependency);
expect(result.fnArray[2]).toEqual(OPS.setFont);
expect(result.argsArray.length).toEqual(3);
expect(result.argsArray[0]).toEqual([
[
["LW", 2],
["CA", 0.5],
],
]);
expect(result.argsArray[1]).toEqual(["g_font_error"]);
expect(result.argsArray[2]).toEqual(["g_font_error", 5.711]);
});
it("should skip if too few arguments", async function () {
const stream = new StringStream("5 d0");
const result = await runOperatorListCheck(
Change the signatures of the `PartialEvaluator` "constructor" and its `getOperatorList`/`getTextContent` methods to take parameter objects Currently these methods accept a large number of parameters, which creates quite unwieldy call-sites. When invoking them, you have to remember not only what arguments to supply, but also the correct order, to avoid runtime errors. Furthermore, since some of the parameters are optional, you also have to remember to pass e.g. `null` or `undefined` for those ones. Also, adding new parameters to these methods (which happens occasionally), often becomes unnecessarily tedious (based on personal experience). Please note that I do *not* think that we need/should convert *every* single method in `evaluator.js` (or elsewhere in `/core` files) to take parameter objects. However, in my opinion, once a method starts relying on approximately five parameter (or even more), passing them in individually becomes quite cumbersome. With these changes, I obviously needed to update the `evaluator_spec.js` unit-tests. The main change there, except the new method signatures[1], is that it's now re-using *one* `PartialEvalutor` instance, since I couldn't see any compelling reason for creating a new one in every single test. *Note:* If this patch is accepted, my intention is to (time permitting) see if it makes sense to convert additional methods in `evaluator.js` (and other `/core` files) in a similar fashion, but I figured that it'd be a good idea to limit the initial scope somewhat. --- [1] A fun fact here, note how the `PartialEvaluator` signature used in `evaluator_spec.js` wasn't even correct in the current `master`.
2017-04-30 06:13:51 +09:00
partialEvaluator,
stream,
new ResourcesMock()
2014-05-10 10:21:15 +09:00
);
expect(result.argsArray).toEqual([]);
expect(result.fnArray).toEqual([]);
2012-05-21 04:05:23 +09:00
});
it(
"should error if (many) path operators have too few arguments " +
"(bug 1443140)",
async function () {
const NUM_INVALID_OPS = 25;
// Non-path operators, should be ignored.
const invalidMoveText = "10 Td\n".repeat(NUM_INVALID_OPS);
const moveTextStream = new StringStream(invalidMoveText);
const result = await runOperatorListCheck(
partialEvaluator,
moveTextStream,
new ResourcesMock()
);
expect(result.argsArray).toEqual([]);
expect(result.fnArray).toEqual([]);
// Path operators, should throw error.
const invalidLineTo = "20 l\n".repeat(NUM_INVALID_OPS);
const lineToStream = new StringStream(invalidLineTo);
try {
await runOperatorListCheck(
partialEvaluator,
lineToStream,
new ResourcesMock()
);
// Shouldn't get here.
expect(false).toEqual(true);
} catch (reason) {
expect(reason instanceof FormatError).toEqual(true);
expect(reason.message).toEqual(
"Invalid command l: expected 2 args, but received 1 args."
);
}
}
);
it("should close opened saves", async function () {
const stream = new StringStream("qq");
const result = await runOperatorListCheck(
Change the signatures of the `PartialEvaluator` "constructor" and its `getOperatorList`/`getTextContent` methods to take parameter objects Currently these methods accept a large number of parameters, which creates quite unwieldy call-sites. When invoking them, you have to remember not only what arguments to supply, but also the correct order, to avoid runtime errors. Furthermore, since some of the parameters are optional, you also have to remember to pass e.g. `null` or `undefined` for those ones. Also, adding new parameters to these methods (which happens occasionally), often becomes unnecessarily tedious (based on personal experience). Please note that I do *not* think that we need/should convert *every* single method in `evaluator.js` (or elsewhere in `/core` files) to take parameter objects. However, in my opinion, once a method starts relying on approximately five parameter (or even more), passing them in individually becomes quite cumbersome. With these changes, I obviously needed to update the `evaluator_spec.js` unit-tests. The main change there, except the new method signatures[1], is that it's now re-using *one* `PartialEvalutor` instance, since I couldn't see any compelling reason for creating a new one in every single test. *Note:* If this patch is accepted, my intention is to (time permitting) see if it makes sense to convert additional methods in `evaluator.js` (and other `/core` files) in a similar fashion, but I figured that it'd be a good idea to limit the initial scope somewhat. --- [1] A fun fact here, note how the `PartialEvaluator` signature used in `evaluator_spec.js` wasn't even correct in the current `master`.
2017-04-30 06:13:51 +09:00
partialEvaluator,
stream,
new ResourcesMock()
2014-05-10 10:21:15 +09:00
);
expect(!!result.fnArray && !!result.argsArray).toEqual(true);
expect(result.fnArray.length).toEqual(4);
expect(result.fnArray[0]).toEqual(OPS.save);
expect(result.fnArray[1]).toEqual(OPS.save);
expect(result.fnArray[2]).toEqual(OPS.restore);
expect(result.fnArray[3]).toEqual(OPS.restore);
});
it("should error on paintXObject if name is missing", async function () {
const stream = new StringStream("/ Do");
try {
await runOperatorListCheck(
partialEvaluator,
stream,
new ResourcesMock()
);
// Shouldn't get here.
expect(false).toEqual(true);
} catch (reason) {
expect(reason instanceof FormatError).toEqual(true);
expect(reason.message).toEqual("XObject should be a stream");
}
});
it("should skip paintXObject if subtype is PS", async function () {
const xobjStreamDict = new Dict();
xobjStreamDict.set("Subtype", Name.get("PS"));
const xobjStream = new Stream([], 0, 0, xobjStreamDict);
const xobjs = new Dict();
xobjs.set("Res1", xobjStream);
const resources = new Dict();
resources.set("XObject", xobjs);
const stream = new StringStream("/Res1 Do");
const result = await runOperatorListCheck(
partialEvaluator,
stream,
resources
);
expect(result.argsArray).toEqual([]);
expect(result.fnArray).toEqual([]);
});
2012-05-11 06:11:27 +09:00
});
2015-10-21 10:50:32 +09:00
describe("thread control", function () {
it("should abort operator list parsing", async function () {
const stream = new StringStream("qqQQ");
const resources = new ResourcesMock();
const result = new OperatorList();
const task = new WorkerTask("OperatorListAbort");
2016-03-29 23:34:13 +09:00
task.terminate();
try {
await partialEvaluator.getOperatorList({
Change the signatures of the `PartialEvaluator` "constructor" and its `getOperatorList`/`getTextContent` methods to take parameter objects Currently these methods accept a large number of parameters, which creates quite unwieldy call-sites. When invoking them, you have to remember not only what arguments to supply, but also the correct order, to avoid runtime errors. Furthermore, since some of the parameters are optional, you also have to remember to pass e.g. `null` or `undefined` for those ones. Also, adding new parameters to these methods (which happens occasionally), often becomes unnecessarily tedious (based on personal experience). Please note that I do *not* think that we need/should convert *every* single method in `evaluator.js` (or elsewhere in `/core` files) to take parameter objects. However, in my opinion, once a method starts relying on approximately five parameter (or even more), passing them in individually becomes quite cumbersome. With these changes, I obviously needed to update the `evaluator_spec.js` unit-tests. The main change there, except the new method signatures[1], is that it's now re-using *one* `PartialEvalutor` instance, since I couldn't see any compelling reason for creating a new one in every single test. *Note:* If this patch is accepted, my intention is to (time permitting) see if it makes sense to convert additional methods in `evaluator.js` (and other `/core` files) in a similar fashion, but I figured that it'd be a good idea to limit the initial scope somewhat. --- [1] A fun fact here, note how the `PartialEvaluator` signature used in `evaluator_spec.js` wasn't even correct in the current `master`.
2017-04-30 06:13:51 +09:00
stream,
task,
resources,
operatorList: result,
});
// Shouldn't get here.
expect(false).toEqual(true);
} catch {
expect(!!result.fnArray && !!result.argsArray).toEqual(true);
expect(result.fnArray.length).toEqual(0);
}
2015-10-21 10:50:32 +09:00
});
it("should abort text content parsing", async function () {
const resources = new ResourcesMock();
const stream = new StringStream("qqQQ");
const task = new WorkerTask("TextContentAbort");
2016-03-29 23:34:13 +09:00
task.terminate();
try {
await partialEvaluator.getTextContent({
Change the signatures of the `PartialEvaluator` "constructor" and its `getOperatorList`/`getTextContent` methods to take parameter objects Currently these methods accept a large number of parameters, which creates quite unwieldy call-sites. When invoking them, you have to remember not only what arguments to supply, but also the correct order, to avoid runtime errors. Furthermore, since some of the parameters are optional, you also have to remember to pass e.g. `null` or `undefined` for those ones. Also, adding new parameters to these methods (which happens occasionally), often becomes unnecessarily tedious (based on personal experience). Please note that I do *not* think that we need/should convert *every* single method in `evaluator.js` (or elsewhere in `/core` files) to take parameter objects. However, in my opinion, once a method starts relying on approximately five parameter (or even more), passing them in individually becomes quite cumbersome. With these changes, I obviously needed to update the `evaluator_spec.js` unit-tests. The main change there, except the new method signatures[1], is that it's now re-using *one* `PartialEvalutor` instance, since I couldn't see any compelling reason for creating a new one in every single test. *Note:* If this patch is accepted, my intention is to (time permitting) see if it makes sense to convert additional methods in `evaluator.js` (and other `/core` files) in a similar fashion, but I figured that it'd be a good idea to limit the initial scope somewhat. --- [1] A fun fact here, note how the `PartialEvaluator` signature used in `evaluator_spec.js` wasn't even correct in the current `master`.
2017-04-30 06:13:51 +09:00
stream,
task,
resources,
});
// Shouldn't get here.
expect(false).toEqual(true);
} catch {
expect(true).toEqual(true);
}
2015-10-21 10:50:32 +09:00
});
});
describe("operator list", function () {
Use streams for OperatorList chunking (issue 10023) *Please note:* The majority of this patch was written by Yury, and it's simply been rebased and slightly extended to prevent issues when dealing with `RenderingCancelledException`. By leveraging streams this (finally) provides a simple way in which parsing can be aborted on the worker-thread, which will ultimately help save resources. With this patch worker-thread parsing will *only* be aborted when the document is destroyed, and not when rendering is cancelled. There's a couple of reasons for this: - The API currently expects the *entire* OperatorList to be extracted, or an Error to occur, once it's been started. Hence additional re-factoring/re-writing of the API code will be necessary to properly support cancelling and re-starting of OperatorList parsing in cases where the `lastChunk` hasn't yet been seen. - Even with the above addressed, immediately cancelling when encountering a `RenderingCancelledException` will lead to worse performance in e.g. the default viewer. When zooming and/or rotation of the document occurs it's very likely that `cancel` will be (almost) immediately followed by a new `render` call. In that case you'd obviously *not* want to abort parsing on the worker-thread, since then you'd risk throwing away a partially parsed Page and thus be forced to re-parse it again which will regress perceived performance. - This patch is already *somewhat* risky, given that it touches fundamentally important/critical code, and trying to keep it somewhat small should hopefully reduce the risk of regressions (and simplify reviewing as well). Time permitting, once this has landed and been in Nightly for awhile, I'll try to work on the remaining points outlined above. Co-Authored-By: Yury Delendik <ydelendik@mozilla.com> Co-Authored-By: Jonas Jenwald <jonas.jenwald@gmail.com>
2017-11-10 10:58:43 +09:00
class StreamSinkMock {
enqueue() {}
}
it("should get correct total length after flushing", function () {
const operatorList = new OperatorList(null, new StreamSinkMock());
operatorList.addOp(OPS.save, null);
operatorList.addOp(OPS.restore, null);
expect(operatorList.totalLength).toEqual(2);
expect(operatorList.length).toEqual(2);
operatorList.flush();
expect(operatorList.totalLength).toEqual(2);
expect(operatorList.length).toEqual(0);
});
});
2012-05-11 06:11:27 +09:00
});