1
0
Fork 0
mirror of https://github.com/mozilla/pdf.js.git synced 2025-04-29 07:37:57 +02:00

XFA - Create Form DOM in merging template and data trees

- Spec: http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.364.2157&rep=rep1&type=pdf#page=171;
  - support for the 2 ways of merging: consumeData and matchTemplate;
  - create additional nodes in template DOM when occur node allows it;
  - support for global values in data DOM.
This commit is contained in:
Calixte Denizet 2021-02-24 19:05:04 +01:00
parent 5e3af62d58
commit 3243672727
9 changed files with 1584 additions and 109 deletions

View file

@ -14,11 +14,14 @@
*/
import {
$appendChild,
$getChildrenByClass,
$getChildrenByName,
$getParent,
$namespaceId,
XFAObject,
XFAObjectArray,
XmlObject,
} from "./xfa_object.js";
import { warn } from "../../shared/util.js";
@ -33,17 +36,18 @@ const operators = {
};
const shortcuts = new Map([
["$data", root => root.datasets.data],
["$template", root => root.template],
["$connectionSet", root => root.connectionSet],
["$form", root => root.form],
["$layout", root => root.layout],
["$host", root => root.host],
["$dataWindow", root => root.dataWindow],
["$event", root => root.event],
["!", root => root.datasets],
["$xfa", root => root],
["xfa", root => root],
["$data", (root, current) => root.datasets.data],
["$template", (root, current) => root.template],
["$connectionSet", (root, current) => root.connectionSet],
["$form", (root, current) => root.form],
["$layout", (root, current) => root.layout],
["$host", (root, current) => root.host],
["$dataWindow", (root, current) => root.dataWindow],
["$event", (root, current) => root.event],
["!", (root, current) => root.datasets],
["$xfa", (root, current) => root],
["xfa", (root, current) => root],
["$", (root, current) => current],
]);
const somCache = new WeakMap();
@ -138,17 +142,24 @@ function parseExpression(expr, dotDotAllowed) {
return parsed;
}
function searchNode(root, container, expr, dotDotAllowed = true) {
function searchNode(
root,
container,
expr,
dotDotAllowed = true,
useCache = true
) {
const parsed = parseExpression(expr, dotDotAllowed);
if (!parsed) {
return null;
}
const fn = shortcuts.get(parsed[0].name);
let i = 0;
let isQualified;
if (fn) {
isQualified = true;
root = [fn(root)];
root = [fn(root, container)];
i = 1;
} else {
isQualified = container === null;
@ -163,13 +174,17 @@ function searchNode(root, container, expr, dotDotAllowed = true) {
continue;
}
let cached = somCache.get(node);
if (!cached) {
cached = new Map();
somCache.set(node, cached);
let children, cached;
if (useCache) {
cached = somCache.get(node);
if (!cached) {
cached = new Map();
somCache.set(node, cached);
}
children = cached.get(cacheName);
}
let children = cached.get(cacheName);
if (!children) {
switch (operator) {
case operators.dot:
@ -189,7 +204,9 @@ function searchNode(root, container, expr, dotDotAllowed = true) {
default:
break;
}
cached.set(cacheName, children);
if (useCache) {
cached.set(cacheName, children);
}
}
if (children.length > 0) {
@ -222,11 +239,72 @@ function searchNode(root, container, expr, dotDotAllowed = true) {
return null;
}
if (root.length === 1) {
return root[0];
}
return root;
}
export { searchNode };
function createNodes(root, path) {
let node = null;
for (const { name, index } of path) {
for (let i = 0; i <= index; i++) {
node = new XmlObject(root[$namespaceId], name);
root[$appendChild](node);
}
root = node;
}
return node;
}
function createDataNode(root, container, expr) {
const parsed = parseExpression(expr);
if (!parsed) {
return null;
}
if (parsed.some(x => x.operator === operators.dotDot)) {
return null;
}
const fn = shortcuts.get(parsed[0].name);
let i = 0;
if (fn) {
root = fn(root, container);
i = 1;
} else {
root = container || root;
}
for (let ii = parsed.length; i < ii; i++) {
const { cacheName, index } = parsed[i];
if (!isFinite(index)) {
parsed[i].index = 0;
return createNodes(root, parsed.slice(i));
}
const cached = somCache.get(root);
if (!cached) {
warn(`XFA - createDataNode must be called after searchNode.`);
return null;
}
const children = cached.get(cacheName);
if (children.length === 0) {
return createNodes(root, parsed.slice(i));
}
if (index < children.length) {
const child = children[index];
if (!(child instanceof XFAObject)) {
warn(`XFA - Cannot create a node.`);
return null;
}
root = child;
} else {
parsed[i].index = children.length - index;
return createNodes(root, parsed.slice(i));
}
}
return null;
}
export { createDataNode, searchNode };