2017-01-09 00:51:30 +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.
|
|
|
|
*/
|
|
|
|
|
2020-08-23 21:04:49 +09:00
|
|
|
import { createIdFactory, XRefMock } from "./test_utils.js";
|
|
|
|
import { Dict, Name, Ref } from "../../src/core/primitives.js";
|
|
|
|
import { PDFDocument } from "../../src/core/document.js";
|
|
|
|
import { StringStream } from "../../src/core/stream.js";
|
2017-01-09 00:51:30 +09:00
|
|
|
|
2020-04-14 19:28:14 +09:00
|
|
|
describe("document", function () {
|
|
|
|
describe("Page", function () {
|
Re-factor the `idFactory` functionality, used in the `core/`-code, and move the `fontID` generation into it
Note how the `getFontID`-method in `src/core/fonts.js` is *completely* global, rather than properly tied to the current document. This means that if you repeatedly open and parse/render, and then close, even the *same* PDF document the `fontID`s will still be incremented continuously.
For comparison the `createObjId` method, on `idFactory`, will always create a *consistent* id, assuming of course that the document and its pages are parsed/rendered in the same order.
In order to address this inconsistency, it thus seems reasonable to add a new `createFontId` method on the `idFactory` and use that when obtaining `fontID`s. (When the current `getFontID` method was added the `idFactory` didn't actually exist yet, which explains why the code looks the way it does.)
*Please note:* Since the document id is (still) part of the `loadedName`, it's thus not possible for different documents to have identical font names.
2020-07-07 23:00:05 +09:00
|
|
|
it("should create correct objId/fontId using the idFactory", function () {
|
2019-04-20 19:36:49 +09:00
|
|
|
const idFactory1 = createIdFactory(/* pageIndex = */ 0);
|
|
|
|
const idFactory2 = createIdFactory(/* pageIndex = */ 1);
|
2017-01-09 00:51:30 +09:00
|
|
|
|
|
|
|
expect(idFactory1.createObjId()).toEqual("p0_1");
|
|
|
|
expect(idFactory1.createObjId()).toEqual("p0_2");
|
Re-factor the `idFactory` functionality, used in the `core/`-code, and move the `fontID` generation into it
Note how the `getFontID`-method in `src/core/fonts.js` is *completely* global, rather than properly tied to the current document. This means that if you repeatedly open and parse/render, and then close, even the *same* PDF document the `fontID`s will still be incremented continuously.
For comparison the `createObjId` method, on `idFactory`, will always create a *consistent* id, assuming of course that the document and its pages are parsed/rendered in the same order.
In order to address this inconsistency, it thus seems reasonable to add a new `createFontId` method on the `idFactory` and use that when obtaining `fontID`s. (When the current `getFontID` method was added the `idFactory` didn't actually exist yet, which explains why the code looks the way it does.)
*Please note:* Since the document id is (still) part of the `loadedName`, it's thus not possible for different documents to have identical font names.
2020-07-07 23:00:05 +09:00
|
|
|
expect(idFactory1.createFontId()).toEqual("f1");
|
|
|
|
expect(idFactory1.createFontId()).toEqual("f2");
|
2019-04-20 19:36:49 +09:00
|
|
|
expect(idFactory1.getDocId()).toEqual("g_d0");
|
2017-01-09 00:51:30 +09:00
|
|
|
|
|
|
|
expect(idFactory2.createObjId()).toEqual("p1_1");
|
|
|
|
expect(idFactory2.createObjId()).toEqual("p1_2");
|
Re-factor the `idFactory` functionality, used in the `core/`-code, and move the `fontID` generation into it
Note how the `getFontID`-method in `src/core/fonts.js` is *completely* global, rather than properly tied to the current document. This means that if you repeatedly open and parse/render, and then close, even the *same* PDF document the `fontID`s will still be incremented continuously.
For comparison the `createObjId` method, on `idFactory`, will always create a *consistent* id, assuming of course that the document and its pages are parsed/rendered in the same order.
In order to address this inconsistency, it thus seems reasonable to add a new `createFontId` method on the `idFactory` and use that when obtaining `fontID`s. (When the current `getFontID` method was added the `idFactory` didn't actually exist yet, which explains why the code looks the way it does.)
*Please note:* Since the document id is (still) part of the `loadedName`, it's thus not possible for different documents to have identical font names.
2020-07-07 23:00:05 +09:00
|
|
|
expect(idFactory2.createFontId()).toEqual("f1");
|
|
|
|
expect(idFactory2.createFontId()).toEqual("f2");
|
2019-04-20 19:36:49 +09:00
|
|
|
expect(idFactory2.getDocId()).toEqual("g_d0");
|
2017-01-09 00:51:30 +09:00
|
|
|
|
|
|
|
expect(idFactory1.createObjId()).toEqual("p0_3");
|
|
|
|
expect(idFactory1.createObjId()).toEqual("p0_4");
|
Re-factor the `idFactory` functionality, used in the `core/`-code, and move the `fontID` generation into it
Note how the `getFontID`-method in `src/core/fonts.js` is *completely* global, rather than properly tied to the current document. This means that if you repeatedly open and parse/render, and then close, even the *same* PDF document the `fontID`s will still be incremented continuously.
For comparison the `createObjId` method, on `idFactory`, will always create a *consistent* id, assuming of course that the document and its pages are parsed/rendered in the same order.
In order to address this inconsistency, it thus seems reasonable to add a new `createFontId` method on the `idFactory` and use that when obtaining `fontID`s. (When the current `getFontID` method was added the `idFactory` didn't actually exist yet, which explains why the code looks the way it does.)
*Please note:* Since the document id is (still) part of the `loadedName`, it's thus not possible for different documents to have identical font names.
2020-07-07 23:00:05 +09:00
|
|
|
expect(idFactory1.createFontId()).toEqual("f3");
|
|
|
|
expect(idFactory1.createFontId()).toEqual("f4");
|
2019-04-20 19:36:49 +09:00
|
|
|
expect(idFactory1.getDocId()).toEqual("g_d0");
|
2017-01-09 00:51:30 +09:00
|
|
|
});
|
|
|
|
});
|
2020-08-23 21:04:49 +09:00
|
|
|
|
|
|
|
describe("PDFDocument", function () {
|
|
|
|
const stream = new StringStream("Dummy_PDF_data");
|
|
|
|
|
2020-10-15 20:20:27 +09:00
|
|
|
function getDocument(acroForm, xref = new XRefMock()) {
|
2020-10-17 22:15:17 +09:00
|
|
|
const catalog = { acroForm };
|
|
|
|
const pdfManager = {
|
|
|
|
get docId() {
|
|
|
|
return "d0";
|
|
|
|
},
|
A couple of small scripting/XFA-related tweaks in the worker-code
- Use `PDFManager.ensureDoc`, rather than `PDFManager.ensure`, in a couple of spots in the code. If there exists a short-hand format, we should obviously use it whenever possible.
- Fix a unit-test helper, to account for the previous changes. (Also, converts a function to be `async` instead.)
- Add one more exists-check in `PDFDocument.loadXfaFonts`, which I missed to suggest in PR 13146, to prevent any possible errors if the method is ever called in a situation where it shouldn't be.
Also, print a warning if the actual font-loading fails since that could help future debugging. (Finally, reduce overall indentation in the loop.)
- Slightly unrelated, but make a small tweak of a comment in `src/core/fonts.js` to reduce possible confusion.
2021-04-17 17:13:42 +09:00
|
|
|
ensureDoc(prop, args) {
|
|
|
|
return pdfManager.ensure(pdfDocument, prop, args);
|
|
|
|
},
|
2020-10-17 22:15:17 +09:00
|
|
|
ensureCatalog(prop, args) {
|
|
|
|
return pdfManager.ensure(catalog, prop, args);
|
|
|
|
},
|
A couple of small scripting/XFA-related tweaks in the worker-code
- Use `PDFManager.ensureDoc`, rather than `PDFManager.ensure`, in a couple of spots in the code. If there exists a short-hand format, we should obviously use it whenever possible.
- Fix a unit-test helper, to account for the previous changes. (Also, converts a function to be `async` instead.)
- Add one more exists-check in `PDFDocument.loadXfaFonts`, which I missed to suggest in PR 13146, to prevent any possible errors if the method is ever called in a situation where it shouldn't be.
Also, print a warning if the actual font-loading fails since that could help future debugging. (Finally, reduce overall indentation in the loop.)
- Slightly unrelated, but make a small tweak of a comment in `src/core/fonts.js` to reduce possible confusion.
2021-04-17 17:13:42 +09:00
|
|
|
async ensure(obj, prop, args) {
|
|
|
|
const value = obj[prop];
|
|
|
|
if (typeof value === "function") {
|
|
|
|
return value.apply(obj, args);
|
|
|
|
}
|
|
|
|
return value;
|
2020-10-17 22:15:17 +09:00
|
|
|
},
|
2022-10-19 00:07:47 +09:00
|
|
|
get evaluatorOptions() {
|
|
|
|
return { isOffscreenCanvasSupported: false };
|
|
|
|
},
|
2020-10-17 22:15:17 +09:00
|
|
|
};
|
2020-08-23 21:04:49 +09:00
|
|
|
const pdfDocument = new PDFDocument(pdfManager, stream);
|
2020-10-15 20:20:27 +09:00
|
|
|
pdfDocument.xref = xref;
|
2020-10-17 22:15:17 +09:00
|
|
|
pdfDocument.catalog = catalog;
|
2020-08-23 21:04:49 +09:00
|
|
|
return pdfDocument;
|
|
|
|
}
|
|
|
|
|
|
|
|
it("should get form info when no form data is present", function () {
|
|
|
|
const pdfDocument = getDocument(null);
|
|
|
|
expect(pdfDocument.formInfo).toEqual({
|
|
|
|
hasAcroForm: false,
|
2021-04-10 23:53:17 +09:00
|
|
|
hasSignatures: false,
|
2020-08-23 21:04:49 +09:00
|
|
|
hasXfa: false,
|
Don't store complex data in `PDFDocument.formInfo`, and replace the `fields` object with a `hasFields` boolean instead
*This patch is based on a couple of smaller things that I noticed when working on PR 12479.*
- Don't store the /Fields on the `formInfo` getter, since that feels like overloading it with unintended (and too complex) data, and utilize a `hasFields` boolean instead.
This functionality was originally added in PR 12271, to help determine what kind of form data a PDF document contains, and I think that we should ensure that the return value of `formInfo` only consists of "simple" data.
With these changes the `fieldObjects` getter instead has to look-up the /Fields manually, however that shouldn't be a problem since the access is guarded by a `formInfo.hasFields` check which ensures that the data both exists and is valid. Furthermore, most documents doesn't even have any /AcroForm data anyway.
- Determine the `hasFields` property *first*, to ensure that it's always correct even if there's errors when checking e.g. the /XFA or /SigFlags entires, since the `fieldObjects` getter depends on it.
- Simplify a loop in `fieldObjects`, since the object being accessed is a `Map` and those have built-in iteration support.
- Use a higher logging level for errors in the `formInfo` getter, and include the actual error message, since that'd have helped with fixing PR 12479 a lot quicker.
- Update the JSDoc comment in `src/display/api.js` to list the return values correctly, and also slightly extend/improve the description.
2020-10-16 19:20:44 +09:00
|
|
|
hasFields: false,
|
2020-08-23 21:04:49 +09:00
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it("should get form info when XFA is present", function () {
|
|
|
|
const acroForm = new Dict();
|
|
|
|
|
|
|
|
// The `XFA` entry can only be a non-empty array or stream.
|
|
|
|
acroForm.set("XFA", []);
|
|
|
|
let pdfDocument = getDocument(acroForm);
|
|
|
|
expect(pdfDocument.formInfo).toEqual({
|
|
|
|
hasAcroForm: false,
|
2021-04-10 23:53:17 +09:00
|
|
|
hasSignatures: false,
|
2020-08-23 21:04:49 +09:00
|
|
|
hasXfa: false,
|
Don't store complex data in `PDFDocument.formInfo`, and replace the `fields` object with a `hasFields` boolean instead
*This patch is based on a couple of smaller things that I noticed when working on PR 12479.*
- Don't store the /Fields on the `formInfo` getter, since that feels like overloading it with unintended (and too complex) data, and utilize a `hasFields` boolean instead.
This functionality was originally added in PR 12271, to help determine what kind of form data a PDF document contains, and I think that we should ensure that the return value of `formInfo` only consists of "simple" data.
With these changes the `fieldObjects` getter instead has to look-up the /Fields manually, however that shouldn't be a problem since the access is guarded by a `formInfo.hasFields` check which ensures that the data both exists and is valid. Furthermore, most documents doesn't even have any /AcroForm data anyway.
- Determine the `hasFields` property *first*, to ensure that it's always correct even if there's errors when checking e.g. the /XFA or /SigFlags entires, since the `fieldObjects` getter depends on it.
- Simplify a loop in `fieldObjects`, since the object being accessed is a `Map` and those have built-in iteration support.
- Use a higher logging level for errors in the `formInfo` getter, and include the actual error message, since that'd have helped with fixing PR 12479 a lot quicker.
- Update the JSDoc comment in `src/display/api.js` to list the return values correctly, and also slightly extend/improve the description.
2020-10-16 19:20:44 +09:00
|
|
|
hasFields: false,
|
2020-08-23 21:04:49 +09:00
|
|
|
});
|
|
|
|
|
|
|
|
acroForm.set("XFA", ["foo", "bar"]);
|
|
|
|
pdfDocument = getDocument(acroForm);
|
|
|
|
expect(pdfDocument.formInfo).toEqual({
|
|
|
|
hasAcroForm: false,
|
2021-04-10 23:53:17 +09:00
|
|
|
hasSignatures: false,
|
2020-08-23 21:04:49 +09:00
|
|
|
hasXfa: true,
|
Don't store complex data in `PDFDocument.formInfo`, and replace the `fields` object with a `hasFields` boolean instead
*This patch is based on a couple of smaller things that I noticed when working on PR 12479.*
- Don't store the /Fields on the `formInfo` getter, since that feels like overloading it with unintended (and too complex) data, and utilize a `hasFields` boolean instead.
This functionality was originally added in PR 12271, to help determine what kind of form data a PDF document contains, and I think that we should ensure that the return value of `formInfo` only consists of "simple" data.
With these changes the `fieldObjects` getter instead has to look-up the /Fields manually, however that shouldn't be a problem since the access is guarded by a `formInfo.hasFields` check which ensures that the data both exists and is valid. Furthermore, most documents doesn't even have any /AcroForm data anyway.
- Determine the `hasFields` property *first*, to ensure that it's always correct even if there's errors when checking e.g. the /XFA or /SigFlags entires, since the `fieldObjects` getter depends on it.
- Simplify a loop in `fieldObjects`, since the object being accessed is a `Map` and those have built-in iteration support.
- Use a higher logging level for errors in the `formInfo` getter, and include the actual error message, since that'd have helped with fixing PR 12479 a lot quicker.
- Update the JSDoc comment in `src/display/api.js` to list the return values correctly, and also slightly extend/improve the description.
2020-10-16 19:20:44 +09:00
|
|
|
hasFields: false,
|
2020-08-23 21:04:49 +09:00
|
|
|
});
|
|
|
|
|
|
|
|
acroForm.set("XFA", new StringStream(""));
|
|
|
|
pdfDocument = getDocument(acroForm);
|
|
|
|
expect(pdfDocument.formInfo).toEqual({
|
|
|
|
hasAcroForm: false,
|
2021-04-10 23:53:17 +09:00
|
|
|
hasSignatures: false,
|
2020-08-23 21:04:49 +09:00
|
|
|
hasXfa: false,
|
Don't store complex data in `PDFDocument.formInfo`, and replace the `fields` object with a `hasFields` boolean instead
*This patch is based on a couple of smaller things that I noticed when working on PR 12479.*
- Don't store the /Fields on the `formInfo` getter, since that feels like overloading it with unintended (and too complex) data, and utilize a `hasFields` boolean instead.
This functionality was originally added in PR 12271, to help determine what kind of form data a PDF document contains, and I think that we should ensure that the return value of `formInfo` only consists of "simple" data.
With these changes the `fieldObjects` getter instead has to look-up the /Fields manually, however that shouldn't be a problem since the access is guarded by a `formInfo.hasFields` check which ensures that the data both exists and is valid. Furthermore, most documents doesn't even have any /AcroForm data anyway.
- Determine the `hasFields` property *first*, to ensure that it's always correct even if there's errors when checking e.g. the /XFA or /SigFlags entires, since the `fieldObjects` getter depends on it.
- Simplify a loop in `fieldObjects`, since the object being accessed is a `Map` and those have built-in iteration support.
- Use a higher logging level for errors in the `formInfo` getter, and include the actual error message, since that'd have helped with fixing PR 12479 a lot quicker.
- Update the JSDoc comment in `src/display/api.js` to list the return values correctly, and also slightly extend/improve the description.
2020-10-16 19:20:44 +09:00
|
|
|
hasFields: false,
|
2020-08-23 21:04:49 +09:00
|
|
|
});
|
|
|
|
|
|
|
|
acroForm.set("XFA", new StringStream("non-empty"));
|
|
|
|
pdfDocument = getDocument(acroForm);
|
|
|
|
expect(pdfDocument.formInfo).toEqual({
|
|
|
|
hasAcroForm: false,
|
2021-04-10 23:53:17 +09:00
|
|
|
hasSignatures: false,
|
2020-08-23 21:04:49 +09:00
|
|
|
hasXfa: true,
|
Don't store complex data in `PDFDocument.formInfo`, and replace the `fields` object with a `hasFields` boolean instead
*This patch is based on a couple of smaller things that I noticed when working on PR 12479.*
- Don't store the /Fields on the `formInfo` getter, since that feels like overloading it with unintended (and too complex) data, and utilize a `hasFields` boolean instead.
This functionality was originally added in PR 12271, to help determine what kind of form data a PDF document contains, and I think that we should ensure that the return value of `formInfo` only consists of "simple" data.
With these changes the `fieldObjects` getter instead has to look-up the /Fields manually, however that shouldn't be a problem since the access is guarded by a `formInfo.hasFields` check which ensures that the data both exists and is valid. Furthermore, most documents doesn't even have any /AcroForm data anyway.
- Determine the `hasFields` property *first*, to ensure that it's always correct even if there's errors when checking e.g. the /XFA or /SigFlags entires, since the `fieldObjects` getter depends on it.
- Simplify a loop in `fieldObjects`, since the object being accessed is a `Map` and those have built-in iteration support.
- Use a higher logging level for errors in the `formInfo` getter, and include the actual error message, since that'd have helped with fixing PR 12479 a lot quicker.
- Update the JSDoc comment in `src/display/api.js` to list the return values correctly, and also slightly extend/improve the description.
2020-10-16 19:20:44 +09:00
|
|
|
hasFields: false,
|
2020-08-23 21:04:49 +09:00
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it("should get form info when AcroForm is present", function () {
|
|
|
|
const acroForm = new Dict();
|
|
|
|
|
|
|
|
// The `Fields` entry can only be a non-empty array.
|
|
|
|
acroForm.set("Fields", []);
|
|
|
|
let pdfDocument = getDocument(acroForm);
|
|
|
|
expect(pdfDocument.formInfo).toEqual({
|
|
|
|
hasAcroForm: false,
|
2021-04-10 23:53:17 +09:00
|
|
|
hasSignatures: false,
|
2020-08-23 21:04:49 +09:00
|
|
|
hasXfa: false,
|
Don't store complex data in `PDFDocument.formInfo`, and replace the `fields` object with a `hasFields` boolean instead
*This patch is based on a couple of smaller things that I noticed when working on PR 12479.*
- Don't store the /Fields on the `formInfo` getter, since that feels like overloading it with unintended (and too complex) data, and utilize a `hasFields` boolean instead.
This functionality was originally added in PR 12271, to help determine what kind of form data a PDF document contains, and I think that we should ensure that the return value of `formInfo` only consists of "simple" data.
With these changes the `fieldObjects` getter instead has to look-up the /Fields manually, however that shouldn't be a problem since the access is guarded by a `formInfo.hasFields` check which ensures that the data both exists and is valid. Furthermore, most documents doesn't even have any /AcroForm data anyway.
- Determine the `hasFields` property *first*, to ensure that it's always correct even if there's errors when checking e.g. the /XFA or /SigFlags entires, since the `fieldObjects` getter depends on it.
- Simplify a loop in `fieldObjects`, since the object being accessed is a `Map` and those have built-in iteration support.
- Use a higher logging level for errors in the `formInfo` getter, and include the actual error message, since that'd have helped with fixing PR 12479 a lot quicker.
- Update the JSDoc comment in `src/display/api.js` to list the return values correctly, and also slightly extend/improve the description.
2020-10-16 19:20:44 +09:00
|
|
|
hasFields: false,
|
2020-08-23 21:04:49 +09:00
|
|
|
});
|
|
|
|
|
|
|
|
acroForm.set("Fields", ["foo", "bar"]);
|
|
|
|
pdfDocument = getDocument(acroForm);
|
|
|
|
expect(pdfDocument.formInfo).toEqual({
|
|
|
|
hasAcroForm: true,
|
2021-04-10 23:53:17 +09:00
|
|
|
hasSignatures: false,
|
2020-08-23 21:04:49 +09:00
|
|
|
hasXfa: false,
|
Don't store complex data in `PDFDocument.formInfo`, and replace the `fields` object with a `hasFields` boolean instead
*This patch is based on a couple of smaller things that I noticed when working on PR 12479.*
- Don't store the /Fields on the `formInfo` getter, since that feels like overloading it with unintended (and too complex) data, and utilize a `hasFields` boolean instead.
This functionality was originally added in PR 12271, to help determine what kind of form data a PDF document contains, and I think that we should ensure that the return value of `formInfo` only consists of "simple" data.
With these changes the `fieldObjects` getter instead has to look-up the /Fields manually, however that shouldn't be a problem since the access is guarded by a `formInfo.hasFields` check which ensures that the data both exists and is valid. Furthermore, most documents doesn't even have any /AcroForm data anyway.
- Determine the `hasFields` property *first*, to ensure that it's always correct even if there's errors when checking e.g. the /XFA or /SigFlags entires, since the `fieldObjects` getter depends on it.
- Simplify a loop in `fieldObjects`, since the object being accessed is a `Map` and those have built-in iteration support.
- Use a higher logging level for errors in the `formInfo` getter, and include the actual error message, since that'd have helped with fixing PR 12479 a lot quicker.
- Update the JSDoc comment in `src/display/api.js` to list the return values correctly, and also slightly extend/improve the description.
2020-10-16 19:20:44 +09:00
|
|
|
hasFields: true,
|
2020-08-23 21:04:49 +09:00
|
|
|
});
|
|
|
|
|
|
|
|
// If the first bit of the `SigFlags` entry is set and the `Fields` array
|
|
|
|
// only contains document signatures, then there is no AcroForm data.
|
|
|
|
acroForm.set("Fields", ["foo", "bar"]);
|
|
|
|
acroForm.set("SigFlags", 2);
|
|
|
|
pdfDocument = getDocument(acroForm);
|
|
|
|
expect(pdfDocument.formInfo).toEqual({
|
|
|
|
hasAcroForm: true,
|
2021-04-10 23:53:17 +09:00
|
|
|
hasSignatures: false,
|
2020-08-23 21:04:49 +09:00
|
|
|
hasXfa: false,
|
Don't store complex data in `PDFDocument.formInfo`, and replace the `fields` object with a `hasFields` boolean instead
*This patch is based on a couple of smaller things that I noticed when working on PR 12479.*
- Don't store the /Fields on the `formInfo` getter, since that feels like overloading it with unintended (and too complex) data, and utilize a `hasFields` boolean instead.
This functionality was originally added in PR 12271, to help determine what kind of form data a PDF document contains, and I think that we should ensure that the return value of `formInfo` only consists of "simple" data.
With these changes the `fieldObjects` getter instead has to look-up the /Fields manually, however that shouldn't be a problem since the access is guarded by a `formInfo.hasFields` check which ensures that the data both exists and is valid. Furthermore, most documents doesn't even have any /AcroForm data anyway.
- Determine the `hasFields` property *first*, to ensure that it's always correct even if there's errors when checking e.g. the /XFA or /SigFlags entires, since the `fieldObjects` getter depends on it.
- Simplify a loop in `fieldObjects`, since the object being accessed is a `Map` and those have built-in iteration support.
- Use a higher logging level for errors in the `formInfo` getter, and include the actual error message, since that'd have helped with fixing PR 12479 a lot quicker.
- Update the JSDoc comment in `src/display/api.js` to list the return values correctly, and also slightly extend/improve the description.
2020-10-16 19:20:44 +09:00
|
|
|
hasFields: true,
|
2020-08-23 21:04:49 +09:00
|
|
|
});
|
|
|
|
|
|
|
|
const annotationDict = new Dict();
|
|
|
|
annotationDict.set("FT", Name.get("Sig"));
|
|
|
|
annotationDict.set("Rect", [0, 0, 0, 0]);
|
|
|
|
const annotationRef = Ref.get(11, 0);
|
|
|
|
|
|
|
|
const kidsDict = new Dict();
|
|
|
|
kidsDict.set("Kids", [annotationRef]);
|
|
|
|
const kidsRef = Ref.get(10, 0);
|
|
|
|
|
2020-10-15 20:20:27 +09:00
|
|
|
const xref = new XRefMock([
|
2020-08-23 21:04:49 +09:00
|
|
|
{ ref: annotationRef, data: annotationDict },
|
|
|
|
{ ref: kidsRef, data: kidsDict },
|
|
|
|
]);
|
|
|
|
|
|
|
|
acroForm.set("Fields", [kidsRef]);
|
|
|
|
acroForm.set("SigFlags", 3);
|
2020-10-15 20:20:27 +09:00
|
|
|
pdfDocument = getDocument(acroForm, xref);
|
2020-08-23 21:04:49 +09:00
|
|
|
expect(pdfDocument.formInfo).toEqual({
|
|
|
|
hasAcroForm: false,
|
2021-04-10 23:53:17 +09:00
|
|
|
hasSignatures: true,
|
2020-08-23 21:04:49 +09:00
|
|
|
hasXfa: false,
|
Don't store complex data in `PDFDocument.formInfo`, and replace the `fields` object with a `hasFields` boolean instead
*This patch is based on a couple of smaller things that I noticed when working on PR 12479.*
- Don't store the /Fields on the `formInfo` getter, since that feels like overloading it with unintended (and too complex) data, and utilize a `hasFields` boolean instead.
This functionality was originally added in PR 12271, to help determine what kind of form data a PDF document contains, and I think that we should ensure that the return value of `formInfo` only consists of "simple" data.
With these changes the `fieldObjects` getter instead has to look-up the /Fields manually, however that shouldn't be a problem since the access is guarded by a `formInfo.hasFields` check which ensures that the data both exists and is valid. Furthermore, most documents doesn't even have any /AcroForm data anyway.
- Determine the `hasFields` property *first*, to ensure that it's always correct even if there's errors when checking e.g. the /XFA or /SigFlags entires, since the `fieldObjects` getter depends on it.
- Simplify a loop in `fieldObjects`, since the object being accessed is a `Map` and those have built-in iteration support.
- Use a higher logging level for errors in the `formInfo` getter, and include the actual error message, since that'd have helped with fixing PR 12479 a lot quicker.
- Update the JSDoc comment in `src/display/api.js` to list the return values correctly, and also slightly extend/improve the description.
2020-10-16 19:20:44 +09:00
|
|
|
hasFields: true,
|
2020-08-23 21:04:49 +09:00
|
|
|
});
|
|
|
|
});
|
2020-10-17 00:15:58 +09:00
|
|
|
|
|
|
|
it("should get calculation order array or null", function () {
|
|
|
|
const acroForm = new Dict();
|
|
|
|
|
|
|
|
let pdfDocument = getDocument(acroForm);
|
|
|
|
expect(pdfDocument.calculationOrderIds).toEqual(null);
|
|
|
|
|
|
|
|
acroForm.set("CO", [Ref.get(1, 0), Ref.get(2, 0), Ref.get(3, 0)]);
|
|
|
|
pdfDocument = getDocument(acroForm);
|
|
|
|
expect(pdfDocument.calculationOrderIds).toEqual(["1R", "2R", "3R"]);
|
|
|
|
|
|
|
|
acroForm.set("CO", []);
|
|
|
|
pdfDocument = getDocument(acroForm);
|
|
|
|
expect(pdfDocument.calculationOrderIds).toEqual(null);
|
2020-12-11 00:02:11 +09:00
|
|
|
|
|
|
|
acroForm.set("CO", ["1", "2"]);
|
|
|
|
pdfDocument = getDocument(acroForm);
|
|
|
|
expect(pdfDocument.calculationOrderIds).toEqual(null);
|
|
|
|
|
|
|
|
acroForm.set("CO", ["1", Ref.get(1, 0), "2"]);
|
|
|
|
pdfDocument = getDocument(acroForm);
|
|
|
|
expect(pdfDocument.calculationOrderIds).toEqual(["1R"]);
|
2020-10-17 00:15:58 +09:00
|
|
|
});
|
2020-10-17 22:15:17 +09:00
|
|
|
|
|
|
|
it("should get field objects array or null", async function () {
|
|
|
|
const acroForm = new Dict();
|
|
|
|
|
|
|
|
let pdfDocument = getDocument(acroForm);
|
|
|
|
let fields = await pdfDocument.fieldObjects;
|
|
|
|
expect(fields).toEqual(null);
|
|
|
|
|
|
|
|
acroForm.set("Fields", []);
|
|
|
|
pdfDocument = getDocument(acroForm);
|
|
|
|
fields = await pdfDocument.fieldObjects;
|
|
|
|
expect(fields).toEqual(null);
|
|
|
|
|
|
|
|
const kid1Ref = Ref.get(314, 0);
|
|
|
|
const kid11Ref = Ref.get(159, 0);
|
|
|
|
const kid2Ref = Ref.get(265, 0);
|
2020-12-17 00:00:12 +09:00
|
|
|
const kid2BisRef = Ref.get(266, 0);
|
2020-10-17 22:15:17 +09:00
|
|
|
const parentRef = Ref.get(358, 0);
|
|
|
|
|
|
|
|
const allFields = Object.create(null);
|
|
|
|
for (const name of ["parent", "kid1", "kid2", "kid11"]) {
|
|
|
|
const buttonWidgetDict = new Dict();
|
|
|
|
buttonWidgetDict.set("Type", Name.get("Annot"));
|
|
|
|
buttonWidgetDict.set("Subtype", Name.get("Widget"));
|
|
|
|
buttonWidgetDict.set("FT", Name.get("Btn"));
|
|
|
|
buttonWidgetDict.set("T", name);
|
|
|
|
allFields[name] = buttonWidgetDict;
|
|
|
|
}
|
|
|
|
|
|
|
|
allFields.kid1.set("Kids", [kid11Ref]);
|
2020-12-17 00:00:12 +09:00
|
|
|
allFields.parent.set("Kids", [kid1Ref, kid2Ref, kid2BisRef]);
|
2020-10-17 22:15:17 +09:00
|
|
|
|
|
|
|
const xref = new XRefMock([
|
|
|
|
{ ref: parentRef, data: allFields.parent },
|
|
|
|
{ ref: kid1Ref, data: allFields.kid1 },
|
|
|
|
{ ref: kid11Ref, data: allFields.kid11 },
|
|
|
|
{ ref: kid2Ref, data: allFields.kid2 },
|
2020-12-17 00:00:12 +09:00
|
|
|
{ ref: kid2BisRef, data: allFields.kid2 },
|
2020-10-17 22:15:17 +09:00
|
|
|
]);
|
|
|
|
|
|
|
|
acroForm.set("Fields", [parentRef]);
|
|
|
|
pdfDocument = getDocument(acroForm, xref);
|
|
|
|
fields = await pdfDocument.fieldObjects;
|
|
|
|
|
|
|
|
for (const [name, objs] of Object.entries(fields)) {
|
|
|
|
fields[name] = objs.map(obj => obj.id);
|
|
|
|
}
|
|
|
|
|
|
|
|
expect(fields["parent.kid1"]).toEqual(["314R"]);
|
|
|
|
expect(fields["parent.kid1.kid11"]).toEqual(["159R"]);
|
2020-12-17 00:00:12 +09:00
|
|
|
expect(fields["parent.kid2"]).toEqual(["265R", "266R"]);
|
2020-10-17 22:15:17 +09:00
|
|
|
expect(fields.parent).toEqual(["358R"]);
|
|
|
|
});
|
2020-10-29 03:16:56 +09:00
|
|
|
|
|
|
|
it("should check if fields have any actions", async function () {
|
|
|
|
const acroForm = new Dict();
|
|
|
|
|
|
|
|
let pdfDocument = getDocument(acroForm);
|
|
|
|
let hasJSActions = await pdfDocument.hasJSActions;
|
|
|
|
expect(hasJSActions).toEqual(false);
|
|
|
|
|
|
|
|
acroForm.set("Fields", []);
|
|
|
|
pdfDocument = getDocument(acroForm);
|
|
|
|
hasJSActions = await pdfDocument.hasJSActions;
|
|
|
|
expect(hasJSActions).toEqual(false);
|
|
|
|
|
|
|
|
const kid1Ref = Ref.get(314, 0);
|
|
|
|
const kid11Ref = Ref.get(159, 0);
|
|
|
|
const kid2Ref = Ref.get(265, 0);
|
|
|
|
const parentRef = Ref.get(358, 0);
|
|
|
|
|
|
|
|
const allFields = Object.create(null);
|
|
|
|
for (const name of ["parent", "kid1", "kid2", "kid11"]) {
|
|
|
|
const buttonWidgetDict = new Dict();
|
|
|
|
buttonWidgetDict.set("Type", Name.get("Annot"));
|
|
|
|
buttonWidgetDict.set("Subtype", Name.get("Widget"));
|
|
|
|
buttonWidgetDict.set("FT", Name.get("Btn"));
|
|
|
|
buttonWidgetDict.set("T", name);
|
|
|
|
allFields[name] = buttonWidgetDict;
|
|
|
|
}
|
|
|
|
|
|
|
|
allFields.kid1.set("Kids", [kid11Ref]);
|
|
|
|
allFields.parent.set("Kids", [kid1Ref, kid2Ref]);
|
|
|
|
|
|
|
|
const xref = new XRefMock([
|
|
|
|
{ ref: parentRef, data: allFields.parent },
|
|
|
|
{ ref: kid1Ref, data: allFields.kid1 },
|
|
|
|
{ ref: kid11Ref, data: allFields.kid11 },
|
|
|
|
{ ref: kid2Ref, data: allFields.kid2 },
|
|
|
|
]);
|
|
|
|
|
|
|
|
acroForm.set("Fields", [parentRef]);
|
|
|
|
pdfDocument = getDocument(acroForm, xref);
|
|
|
|
hasJSActions = await pdfDocument.hasJSActions;
|
|
|
|
expect(hasJSActions).toEqual(false);
|
|
|
|
|
|
|
|
const JS = Name.get("JavaScript");
|
|
|
|
const additionalActionsDict = new Dict();
|
|
|
|
const eDict = new Dict();
|
|
|
|
eDict.set("JS", "hello()");
|
|
|
|
eDict.set("S", JS);
|
|
|
|
additionalActionsDict.set("E", eDict);
|
|
|
|
allFields.kid2.set("AA", additionalActionsDict);
|
|
|
|
|
|
|
|
pdfDocument = getDocument(acroForm, xref);
|
|
|
|
hasJSActions = await pdfDocument.hasJSActions;
|
|
|
|
expect(hasJSActions).toEqual(true);
|
|
|
|
});
|
2020-08-23 21:04:49 +09:00
|
|
|
});
|
2017-01-09 00:51:30 +09:00
|
|
|
});
|