XFA - Elements created outside of XML must have all their properties (bug 1722029)

- an Image element was created, attached to its parent but the $globalData property was not set and that led to an error.
  - the pdf in bug 1722029 has 27 rendered rows (checked in Acrobat) when only one was displayed: this patch some binding issues around the occur element.
This commit is contained in:
Calixte Denizet 2021-07-26 16:14:46 +02:00
parent 777d890268
commit 959120e6c9
5 changed files with 98 additions and 34 deletions

View File

@ -37,6 +37,7 @@ import {
$setValue, $setValue,
$text, $text,
XFAAttribute, XFAAttribute,
XFAObjectArray,
XmlObject, XmlObject,
} from "./xfa_object.js"; } from "./xfa_object.js";
import { BindItems, Field, Items, SetProperty, Text } from "./template.js"; import { BindItems, Field, Items, SetProperty, Text } from "./template.js";
@ -395,6 +396,8 @@ class Binder {
if (matches.length > 1) { if (matches.length > 1) {
// Clone before binding to avoid bad state. // Clone before binding to avoid bad state.
baseClone = formNode[$clone](); baseClone = formNode[$clone]();
baseClone[$removeChild](baseClone.occur);
baseClone.occur = null;
} }
this._bindValue(formNode, matches[0], picture); this._bindValue(formNode, matches[0], picture);
@ -412,9 +415,6 @@ class Binder {
for (let i = 1, ii = matches.length; i < ii; i++) { for (let i = 1, ii = matches.length; i < ii; i++) {
const match = matches[i]; const match = matches[i];
const clone = baseClone[$clone](); const clone = baseClone[$clone]();
clone.occur.min = 1;
clone.occur.max = 1;
clone.occur.initial = 1;
parent[name].push(clone); parent[name].push(clone);
parent[$insertAt](pos + i, clone); parent[$insertAt](pos + i, clone);
@ -437,20 +437,39 @@ class Binder {
const parent = formNode[$getParent](); const parent = formNode[$getParent]();
const name = formNode[$nodeName]; const name = formNode[$nodeName];
for (let i = 0, ii = occur.initial; i < ii; i++) { if (!(parent[name] instanceof XFAObjectArray)) {
const clone = formNode[$clone](); return;
clone.occur.min = 1; }
clone.occur.max = 1;
clone.occur.initial = 1; let currentNumber;
parent[name].push(clone); if (formNode.name) {
parent[$appendChild](clone); currentNumber = parent[name].children.filter(
e => e.name === formNode.name
).length;
} else {
currentNumber = parent[name].children.length;
}
const pos = parent[$indexOf](formNode) + 1;
const ii = occur.initial - currentNumber;
if (ii) {
const nodeClone = formNode[$clone]();
nodeClone[$removeChild](nodeClone.occur);
nodeClone.occur = null;
parent[name].push(nodeClone);
parent[$insertAt](pos, nodeClone);
for (let i = 1; i < ii; i++) {
const clone = nodeClone[$clone]();
parent[name].push(clone);
parent[$insertAt](pos + i, clone);
}
} }
} }
_getOccurInfo(formNode) { _getOccurInfo(formNode) {
const { occur } = formNode; const { name, occur } = formNode;
const dataName = formNode.name; if (!occur || !name) {
if (!occur || !dataName) {
return [1, 1]; return [1, 1];
} }
const max = occur.max === -1 ? Infinity : occur.max; const max = occur.max === -1 ? Infinity : occur.max;
@ -629,12 +648,6 @@ class Binder {
} }
if (match) { if (match) {
if (match.length < min) {
warn(
`XFA - Must have at least ${min} occurrences: ${formNode[$nodeName]}.`
);
continue;
}
this._bindOccurrences(child, match, picture); this._bindOccurrences(child, match, picture);
} else if (min > 0) { } else if (min > 0) {
this._setProperties(child, dataNode); this._setProperties(child, dataNode);

View File

@ -3603,25 +3603,60 @@ class Occur extends XFAObject {
constructor(attributes) { constructor(attributes) {
super(TEMPLATE_NS_ID, "occur", /* hasChildren = */ true); super(TEMPLATE_NS_ID, "occur", /* hasChildren = */ true);
this.id = attributes.id || ""; this.id = attributes.id || "";
this.initial = getInteger({ this.initial =
data: attributes.initial, attributes.initial !== ""
defaultValue: 1, ? getInteger({
validate: x => true, data: attributes.initial,
}); defaultValue: "",
this.max = getInteger({ validate: x => true,
data: attributes.max, })
defaultValue: 1, : "";
validate: x => true, this.max =
}); attributes.max !== ""
this.min = getInteger({ ? getInteger({
data: attributes.min, data: attributes.max,
defaultValue: 1, defaultValue: 1,
validate: x => true, validate: x => true,
}); })
: "";
this.min =
attributes.min !== ""
? getInteger({
data: attributes.min,
defaultValue: 1,
validate: x => true,
})
: "";
this.use = attributes.use || ""; this.use = attributes.use || "";
this.usehref = attributes.usehref || ""; this.usehref = attributes.usehref || "";
this.extras = null; this.extras = null;
} }
[$clean]() {
const parent = this[$getParent]();
const originalMin = this.min;
if (this.min === "") {
this.min =
parent instanceof PageArea || parent instanceof PageSet ? 0 : 1;
}
if (this.max === "") {
if (originalMin === "") {
this.max =
parent instanceof PageArea || parent instanceof PageSet ? -1 : 1;
} else {
this.max = this.min;
}
}
if (this.max !== -1 && this.max < this.min) {
this.max = this.min;
}
if (this.initial === "") {
this.initial = parent instanceof Template ? 1 : this.min;
}
}
} }
class Oid extends StringObject { class Oid extends StringObject {
@ -5705,6 +5740,7 @@ class Value extends XFAObject {
if (parent.ui && parent.ui.imageEdit) { if (parent.ui && parent.ui.imageEdit) {
if (!this.image) { if (!this.image) {
this.image = new Image({}); this.image = new Image({});
this[$appendChild](this.image);
} }
this.image[$content] = value[$content]; this.image[$content] = value[$content];
return; return;

View File

@ -204,6 +204,9 @@ class XFAObject {
[$appendChild](child) { [$appendChild](child) {
child[_parent] = this; child[_parent] = this;
this[_children].push(child); this[_children].push(child);
if (!child[$globalData] && this[$globalData]) {
child[$globalData] = this[$globalData];
}
} }
[$removeChild](child) { [$removeChild](child) {
@ -236,6 +239,9 @@ class XFAObject {
[$insertAt](i, child) { [$insertAt](i, child) {
child[_parent] = this; child[_parent] = this;
this[_children].splice(i, 0, child); this[_children].splice(i, 0, child);
if (!child[$globalData] && this[$globalData]) {
child[$globalData] = this[$globalData];
}
} }
/** /**

View File

@ -0,0 +1 @@
https://bugzilla.mozilla.org/attachment.cgi?id=9233058

View File

@ -952,6 +952,14 @@
"enableXfa": true, "enableXfa": true,
"type": "eq" "type": "eq"
}, },
{ "id": "xfa_bug1722029",
"file": "pdfs/xfa_bug1722029.pdf",
"md5": "d8dd6bb20599fc777b4c7ff7b74dd5e3",
"link": true,
"rounds": 1,
"enableXfa": true,
"type": "eq"
},
{ "id": "xfa_bug1721600", { "id": "xfa_bug1721600",
"file": "pdfs/xfa_bug1721600.pdf", "file": "pdfs/xfa_bug1721600.pdf",
"md5": "5f514f476169eeb7254da380a8db495a", "md5": "5f514f476169eeb7254da380a8db495a",