XFA - Handle correctly subformSet

- it aims to avoid to loop forever when opening pdf in #13213;
  - the idea is to consider subformSet as inexistent when running in the tree. So if we've subformA > subformSet > subformB then subformB will be visited as a direct child of subformA.
This commit is contained in:
Calixte Denizet 2021-06-11 17:49:13 +02:00
parent 7b4fa0a038
commit d1e945998b
5 changed files with 65 additions and 21 deletions

View File

@ -16,6 +16,7 @@
import { import {
$extra, $extra,
$getParent, $getParent,
$getSubformParent,
$nodeName, $nodeName,
$toStyle, $toStyle,
XFAObject, XFAObject,
@ -296,7 +297,7 @@ function computeBbox(node, html, availableSpace) {
} }
function fixDimensions(node) { function fixDimensions(node) {
const parent = node[$getParent](); const parent = node[$getSubformParent]();
if (parent.layout && parent.layout.includes("row")) { if (parent.layout && parent.layout.includes("row")) {
const extra = parent[$extra]; const extra = parent[$extra];
const colSpan = node.colSpan; const colSpan = node.colSpan;

View File

@ -25,8 +25,10 @@ import {
$flushHTML, $flushHTML,
$getAvailableSpace, $getAvailableSpace,
$getChildren, $getChildren,
$getContainedChildren,
$getNextPage, $getNextPage,
$getParent, $getParent,
$getSubformParent,
$hasItem, $hasItem,
$hasSettableValue, $hasSettableValue,
$ids, $ids,
@ -106,6 +108,16 @@ function getRoot(node) {
return parent; return parent;
} }
function* getContainedChildren(node) {
for (const child of node[$getChildren]()) {
if (child instanceof SubformSet) {
yield* child[$getContainedChildren]();
continue;
}
yield child;
}
}
function valueToHtml(value) { function valueToHtml(value) {
return HTMLResult.success({ return HTMLResult.success({
name: "span", name: "span",
@ -338,6 +350,12 @@ class Area extends XFAObject {
this.subformSet = new XFAObjectArray(); this.subformSet = new XFAObjectArray();
} }
*[$getContainedChildren]() {
// This function is overriden in order to fake that subforms under
// this set are in fact under parent subform.
yield* getContainedChildren(this);
}
[$isTransparent]() { [$isTransparent]() {
return true; return true;
} }
@ -4077,6 +4095,12 @@ class Subform extends XFAObject {
this.subformSet = new XFAObjectArray(); this.subformSet = new XFAObjectArray();
} }
*[$getContainedChildren]() {
// This function is overriden in order to fake that subforms under
// this set are in fact under parent subform.
yield* getContainedChildren(this);
}
[$flushHTML]() { [$flushHTML]() {
return flushHTML(this); return flushHTML(this);
} }
@ -4161,7 +4185,7 @@ class Subform extends XFAObject {
]); ]);
if (this.layout.includes("row")) { if (this.layout.includes("row")) {
const columnWidths = this[$getParent]().columnWidths; const columnWidths = this[$getSubformParent]().columnWidths;
if (Array.isArray(columnWidths) && columnWidths.length > 0) { if (Array.isArray(columnWidths) && columnWidths.length > 0) {
this[$extra].columnWidths = columnWidths; this[$extra].columnWidths = columnWidths;
this[$extra].currentColumn = 0; this[$extra].currentColumn = 0;
@ -4292,27 +4316,22 @@ class SubformSet extends XFAObject {
this.breakBefore = new XFAObjectArray(); this.breakBefore = new XFAObjectArray();
this.subform = new XFAObjectArray(); this.subform = new XFAObjectArray();
this.subformSet = new XFAObjectArray(); this.subformSet = new XFAObjectArray();
// TODO: need to handle break stuff and relation.
} }
[$toHTML]() { *[$getContainedChildren]() {
const children = []; // This function is overriden in order to fake that subforms under
if (!this[$extra]) { // this set are in fact under parent subform.
this[$extra] = Object.create(null); yield* getContainedChildren(this);
}
[$getSubformParent]() {
let parent = this[$getParent]();
while (!(parent instanceof Subform)) {
parent = parent[$getParent]();
} }
this[$extra].children = children; return parent;
this[$childrenToHTML]({
filter: new Set(["subform", "subformSet"]),
include: true,
});
return HTMLResult.success({
name: "div",
children,
attributes: {
id: this[$uid],
},
});
} }
} }

View File

@ -43,7 +43,9 @@ const $getChildrenByNameIt = Symbol();
const $getDataValue = Symbol(); const $getDataValue = Symbol();
const $getRealChildrenByNameIt = Symbol(); const $getRealChildrenByNameIt = Symbol();
const $getChildren = Symbol(); const $getChildren = Symbol();
const $getContainedChildren = Symbol();
const $getNextPage = Symbol(); const $getNextPage = Symbol();
const $getSubformParent = Symbol();
const $getParent = Symbol(); const $getParent = Symbol();
const $global = Symbol(); const $global = Symbol();
const $hasItem = Symbol(); const $hasItem = Symbol();
@ -255,6 +257,10 @@ class XFAObject {
return this[_parent]; return this[_parent];
} }
[$getSubformParent]() {
return this[$getParent]();
}
[$getChildren](name = null) { [$getChildren](name = null) {
if (!name) { if (!name) {
return this[_children]; return this[_children];
@ -296,8 +302,15 @@ class XFAObject {
return HTMLResult.EMPTY; return HTMLResult.EMPTY;
} }
*[_filteredChildrenGenerator](filter, include) { *[$getContainedChildren]() {
// This function is overriden in Subform and SubformSet.
for (const node of this[$getChildren]()) { for (const node of this[$getChildren]()) {
yield node;
}
}
*[_filteredChildrenGenerator](filter, include) {
for (const node of this[$getContainedChildren]()) {
if (!filter || include === filter.has(node[$nodeName])) { if (!filter || include === filter.has(node[$nodeName])) {
const availableSpace = this[$getAvailableSpace](); const availableSpace = this[$getAvailableSpace]();
const res = node[$toHTML](availableSpace); const res = node[$toHTML](availableSpace);
@ -965,10 +978,12 @@ export {
$getChildrenByClass, $getChildrenByClass,
$getChildrenByName, $getChildrenByName,
$getChildrenByNameIt, $getChildrenByNameIt,
$getContainedChildren,
$getDataValue, $getDataValue,
$getNextPage, $getNextPage,
$getParent, $getParent,
$getRealChildrenByNameIt, $getRealChildrenByNameIt,
$getSubformParent,
$global, $global,
$hasItem, $hasItem,
$hasSettableValue, $hasSettableValue,

View File

@ -0,0 +1 @@
https://github.com/mozilla/pdf.js/files/6290046/cerfa_12156-05.pdf

View File

@ -938,6 +938,14 @@
"enableXfa": true, "enableXfa": true,
"type": "eq" "type": "eq"
}, },
{ "id": "xfa_issue13213",
"file": "pdfs/xfa_issue13213.pdf",
"md5": "8a0e3179bffbac721589d1b1df863b49",
"link": true,
"rounds": 1,
"enableXfa": true,
"type": "eq"
},
{ "id": "issue10272", { "id": "issue10272",
"file": "pdfs/issue10272.pdf", "file": "pdfs/issue10272.pdf",
"md5": "bf3b2f74c6878d38a70dc0825f1b9a02", "md5": "bf3b2f74c6878d38a70dc0825f1b9a02",