*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.
164 lines
5.3 KiB
JavaScript
164 lines
5.3 KiB
JavaScript
/* 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 { 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";
|
|
|
|
describe("document", function () {
|
|
describe("Page", function () {
|
|
it("should create correct objId/fontId using the idFactory", function () {
|
|
const idFactory1 = createIdFactory(/* pageIndex = */ 0);
|
|
const idFactory2 = createIdFactory(/* pageIndex = */ 1);
|
|
|
|
expect(idFactory1.createObjId()).toEqual("p0_1");
|
|
expect(idFactory1.createObjId()).toEqual("p0_2");
|
|
expect(idFactory1.createFontId()).toEqual("f1");
|
|
expect(idFactory1.createFontId()).toEqual("f2");
|
|
expect(idFactory1.getDocId()).toEqual("g_d0");
|
|
|
|
expect(idFactory2.createObjId()).toEqual("p1_1");
|
|
expect(idFactory2.createObjId()).toEqual("p1_2");
|
|
expect(idFactory2.createFontId()).toEqual("f1");
|
|
expect(idFactory2.createFontId()).toEqual("f2");
|
|
expect(idFactory2.getDocId()).toEqual("g_d0");
|
|
|
|
expect(idFactory1.createObjId()).toEqual("p0_3");
|
|
expect(idFactory1.createObjId()).toEqual("p0_4");
|
|
expect(idFactory1.createFontId()).toEqual("f3");
|
|
expect(idFactory1.createFontId()).toEqual("f4");
|
|
expect(idFactory1.getDocId()).toEqual("g_d0");
|
|
});
|
|
});
|
|
|
|
describe("PDFDocument", function () {
|
|
const pdfManager = {
|
|
get docId() {
|
|
return "d0";
|
|
},
|
|
};
|
|
const stream = new StringStream("Dummy_PDF_data");
|
|
|
|
function getDocument(acroForm, xref = new XRefMock()) {
|
|
const pdfDocument = new PDFDocument(pdfManager, stream);
|
|
pdfDocument.xref = xref;
|
|
pdfDocument.catalog = { acroForm };
|
|
return pdfDocument;
|
|
}
|
|
|
|
it("should get form info when no form data is present", function () {
|
|
const pdfDocument = getDocument(null);
|
|
expect(pdfDocument.formInfo).toEqual({
|
|
hasAcroForm: false,
|
|
hasXfa: false,
|
|
hasFields: false,
|
|
});
|
|
});
|
|
|
|
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,
|
|
hasXfa: false,
|
|
hasFields: false,
|
|
});
|
|
|
|
acroForm.set("XFA", ["foo", "bar"]);
|
|
pdfDocument = getDocument(acroForm);
|
|
expect(pdfDocument.formInfo).toEqual({
|
|
hasAcroForm: false,
|
|
hasXfa: true,
|
|
hasFields: false,
|
|
});
|
|
|
|
acroForm.set("XFA", new StringStream(""));
|
|
pdfDocument = getDocument(acroForm);
|
|
expect(pdfDocument.formInfo).toEqual({
|
|
hasAcroForm: false,
|
|
hasXfa: false,
|
|
hasFields: false,
|
|
});
|
|
|
|
acroForm.set("XFA", new StringStream("non-empty"));
|
|
pdfDocument = getDocument(acroForm);
|
|
expect(pdfDocument.formInfo).toEqual({
|
|
hasAcroForm: false,
|
|
hasXfa: true,
|
|
hasFields: false,
|
|
});
|
|
});
|
|
|
|
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,
|
|
hasXfa: false,
|
|
hasFields: false,
|
|
});
|
|
|
|
acroForm.set("Fields", ["foo", "bar"]);
|
|
pdfDocument = getDocument(acroForm);
|
|
expect(pdfDocument.formInfo).toEqual({
|
|
hasAcroForm: true,
|
|
hasXfa: false,
|
|
hasFields: true,
|
|
});
|
|
|
|
// 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,
|
|
hasXfa: false,
|
|
hasFields: true,
|
|
});
|
|
|
|
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);
|
|
|
|
const xref = new XRefMock([
|
|
{ ref: annotationRef, data: annotationDict },
|
|
{ ref: kidsRef, data: kidsDict },
|
|
]);
|
|
|
|
acroForm.set("Fields", [kidsRef]);
|
|
acroForm.set("SigFlags", 3);
|
|
pdfDocument = getDocument(acroForm, xref);
|
|
expect(pdfDocument.formInfo).toEqual({
|
|
hasAcroForm: false,
|
|
hasXfa: false,
|
|
hasFields: true,
|
|
});
|
|
});
|
|
});
|
|
});
|