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

View File

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

View File

@ -43,7 +43,9 @@ const $getChildrenByNameIt = Symbol();
const $getDataValue = Symbol();
const $getRealChildrenByNameIt = Symbol();
const $getChildren = Symbol();
const $getContainedChildren = Symbol();
const $getNextPage = Symbol();
const $getSubformParent = Symbol();
const $getParent = Symbol();
const $global = Symbol();
const $hasItem = Symbol();
@ -255,6 +257,10 @@ class XFAObject {
return this[_parent];
}
[$getSubformParent]() {
return this[$getParent]();
}
[$getChildren](name = null) {
if (!name) {
return this[_children];
@ -296,8 +302,15 @@ class XFAObject {
return HTMLResult.EMPTY;
}
*[_filteredChildrenGenerator](filter, include) {
*[$getContainedChildren]() {
// This function is overriden in Subform and SubformSet.
for (const node of this[$getChildren]()) {
yield node;
}
}
*[_filteredChildrenGenerator](filter, include) {
for (const node of this[$getContainedChildren]()) {
if (!filter || include === filter.has(node[$nodeName])) {
const availableSpace = this[$getAvailableSpace]();
const res = node[$toHTML](availableSpace);
@ -965,10 +978,12 @@ export {
$getChildrenByClass,
$getChildrenByName,
$getChildrenByNameIt,
$getContainedChildren,
$getDataValue,
$getNextPage,
$getParent,
$getRealChildrenByNameIt,
$getSubformParent,
$global,
$hasItem,
$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,
"type": "eq"
},
{ "id": "xfa_issue13213",
"file": "pdfs/xfa_issue13213.pdf",
"md5": "8a0e3179bffbac721589d1b1df863b49",
"link": true,
"rounds": 1,
"enableXfa": true,
"type": "eq"
},
{ "id": "issue10272",
"file": "pdfs/issue10272.pdf",
"md5": "bf3b2f74c6878d38a70dc0825f1b9a02",