diff --git a/src/core/xfa/html_utils.js b/src/core/xfa/html_utils.js index 88a7c9f85..b645a5809 100644 --- a/src/core/xfa/html_utils.js +++ b/src/core/xfa/html_utils.js @@ -102,24 +102,12 @@ const converters = { style.width = measureToString(width); } else { style.width = "auto"; - if (node.maxW > 0) { - style.maxWidth = measureToString(node.maxW); - } - if (parent.layout === "position") { - style.minWidth = measureToString(node.minW); - } } if (height !== "") { style.height = measureToString(height); } else { style.height = "auto"; - if (node.maxH > 0) { - style.maxHeight = measureToString(node.maxH); - } - if (parent.layout === "position") { - style.minHeight = measureToString(node.minH); - } } }, position(node, style) { @@ -188,6 +176,20 @@ const converters = { }, }; +function setMinMaxDimensions(node, style) { + const parent = node[$getParent](); + if (parent.layout === "position") { + style.minWidth = measureToString(node.minW); + if (node.maxW) { + style.maxWidth = measureToString(node.maxW); + } + style.minHeight = measureToString(node.minH); + if (node.maxH) { + style.maxHeight = measureToString(node.maxH); + } + } +} + function layoutText(text, xfaFont, fonts, width) { const measure = new TextMeasure(xfaFont, fonts); if (typeof text === "string") { @@ -283,16 +285,9 @@ function fixDimensions(node) { } } - if (node.layout === "position") { - // Acrobat doesn't take into account min, max values - // for containers with positioned layout (which makes sense). - node.minW = node.minH = 0; - node.maxW = node.maxH = Infinity; - } else { - if (node.layout === "table") { - if (node.w === "" && Array.isArray(node.columnWidths)) { - node.w = node.columnWidths.reduce((a, x) => a + x, 0); - } + if (node.layout === "table") { + if (node.w === "" && Array.isArray(node.columnWidths)) { + node.w = node.columnWidths.reduce((a, x) => a + x, 0); } } } @@ -471,5 +466,6 @@ export { layoutClass, layoutText, measureToString, + setMinMaxDimensions, toStyle, }; diff --git a/src/core/xfa/layout.js b/src/core/xfa/layout.js index 79b9cbecc..ad12c70dc 100644 --- a/src/core/xfa/layout.js +++ b/src/core/xfa/layout.js @@ -13,7 +13,13 @@ * limitations under the License. */ -import { $extra, $flushHTML } from "./xfa_object.js"; +import { + $extra, + $flushHTML, + $getParent, + $getTemplateRoot, + $isSplittable, +} from "./xfa_object.js"; import { measureToString } from "./html_utils.js"; // Subform and ExclGroup have a layout so they share these functions. @@ -146,59 +152,181 @@ function addHTML(node, html, bbox) { function getAvailableSpace(node) { const availableSpace = node[$extra].availableSpace; - const marginH = node.margin + const marginV = node.margin ? node.margin.topInset + node.margin.bottomInset : 0; + const marginH = node.margin + ? node.margin.leftInset + node.margin.rightInset + : 0; switch (node.layout) { case "lr-tb": case "rl-tb": - switch (node[$extra].attempt) { - case 0: - return { - width: availableSpace.width - node[$extra].currentWidth, - height: availableSpace.height - marginH - node[$extra].prevHeight, - }; - case 1: - return { - width: availableSpace.width, - height: availableSpace.height - marginH - node[$extra].height, - }; - default: - // Overflow must stay in the container. - return { - width: Infinity, - height: Infinity, - }; - } - case "rl-row": - case "row": - if (node[$extra].attempt === 0) { - const width = node[$extra].columnWidths - .slice(node[$extra].currentColumn) - .reduce((a, x) => a + x); - return { width, height: availableSpace.height - marginH }; - } - // Overflow must stay in the container. - return { width: Infinity, height: Infinity }; - case "table": - case "tb": if (node[$extra].attempt === 0) { return { - width: availableSpace.width, - height: availableSpace.height - marginH - node[$extra].height, + width: availableSpace.width - marginH - node[$extra].currentWidth, + height: availableSpace.height - marginV - node[$extra].prevHeight, }; } - // Overflow must stay in the container. - return { width: Infinity, height: Infinity }; + return { + width: availableSpace.width - marginH, + height: availableSpace.height - marginV - node[$extra].height, + }; + case "rl-row": + case "row": + const width = node[$extra].columnWidths + .slice(node[$extra].currentColumn) + .reduce((a, x) => a + x); + return { width, height: availableSpace.height - marginH }; + case "table": + case "tb": + return { + width: availableSpace.width - marginH, + height: availableSpace.height - marginV - node[$extra].height, + }; case "position": default: - if (node[$extra].attempt === 0) { - return availableSpace; - } - // Overflow must stay in the container. - return { width: Infinity, height: Infinity }; + return availableSpace; } } -export { addHTML, flushHTML, getAvailableSpace }; +function getTransformedBBox(node) { + // Take into account rotation and anchor the get the + // real bounding box. + let w = node.w === "" ? NaN : node.w; + let h = node.h === "" ? NaN : node.h; + let [centerX, centerY] = [0, 0]; + switch (node.anchorType || "") { + case "bottomCenter": + [centerX, centerY] = [w / 2, h]; + break; + case "bottomLeft": + [centerX, centerY] = [0, h]; + break; + case "bottomRight": + [centerX, centerY] = [w, h]; + break; + case "middleCenter": + [centerX, centerY] = [w / 2, h / 2]; + break; + case "middleLeft": + [centerX, centerY] = [0, h / 2]; + break; + case "middleRight": + [centerX, centerY] = [w, h / 2]; + break; + case "topCenter": + [centerX, centerY] = [w / 2, 0]; + break; + case "topRight": + [centerX, centerY] = [w, 0]; + break; + } + + let x; + let y; + switch (node.rotate || 0) { + case 0: + [x, y] = [-centerX, -centerY]; + break; + case 90: + [x, y] = [-centerY, centerX]; + [w, h] = [h, -w]; + break; + case 180: + [x, y] = [centerX, centerY]; + [w, h] = [-w, -h]; + break; + case 270: + [x, y] = [centerY, -centerX]; + [w, h] = [-h, w]; + break; + } + + return [ + node.x + x + Math.min(0, w), + node.y + y + Math.min(0, h), + Math.abs(w), + Math.abs(h), + ]; +} + +/** + * Returning true means that the node will be layed out + * else the layout will go to its next step (changing of line + * in case of lr-tb or changing content area...). + */ +function checkDimensions(node, space) { + if (node.w === 0 || node.h === 0) { + return true; + } + + if (space.width <= 0 || space.height <= 0) { + return false; + } + + const parent = node[$getParent](); + const attempt = (node[$extra] && node[$extra].attempt) || 0; + switch (parent.layout) { + case "lr-tb": + case "rl-tb": + switch (attempt) { + case 0: { + let w, h; + if (node.w !== "" || node.h !== "") { + [, , w, h] = getTransformedBBox(node); + } + if (node.h !== "" && Math.round(h - space.height) > 1) { + return false; + } + if (node.w !== "") { + return Math.round(w - space.width) <= 1; + } + + return node.minW <= space.width; + } + case 1: { + if (node.h !== "" && !node[$isSplittable]()) { + const [, , , h] = getTransformedBBox(node); + if (Math.round(h - space.height) > 1) { + return false; + } + } + return true; + } + default: + return true; + } + case "table": + case "tb": + if (attempt !== 1 && node.h !== "" && !node[$isSplittable]()) { + const [, , , h] = getTransformedBBox(node); + if (Math.round(h - space.height) > 1) { + return false; + } + } + return true; + case "position": + const [x, y, w, h] = getTransformedBBox(node); + const isWidthOk = node.w === "" || Math.round(w + x - space.width) <= 1; + const isHeightOk = node.h === "" || Math.round(h + y - space.height) <= 1; + + if (isWidthOk && isHeightOk) { + return true; + } + + const area = node[$getTemplateRoot]()[$extra].currentContentArea; + if (isWidthOk) { + return h + y > area.h; + } + + return w + x > area.w; + case "rl-row": + case "row": + default: + // No layout, so accept everything. + return true; + } +} + +export { addHTML, checkDimensions, flushHTML, getAvailableSpace }; diff --git a/src/core/xfa/template.js b/src/core/xfa/template.js index 8e57f894d..ba4f88c0a 100644 --- a/src/core/xfa/template.js +++ b/src/core/xfa/template.js @@ -30,10 +30,12 @@ import { $getNextPage, $getParent, $getSubformParent, + $getTemplateRoot, $hasItem, $hasSettableValue, $ids, $isCDATAXml, + $isSplittable, $isTransparent, $namespaceId, $nodeName, @@ -55,7 +57,12 @@ import { XFAObjectArray, } from "./xfa_object.js"; import { $buildXFAObject, NamespaceIds } from "./namespaces.js"; -import { addHTML, flushHTML, getAvailableSpace } from "./layout.js"; +import { + addHTML, + checkDimensions, + flushHTML, + getAvailableSpace, +} from "./layout.js"; import { computeBbox, createWrapper, @@ -65,6 +72,7 @@ import { layoutClass, layoutText, measureToString, + setMinMaxDimensions, toStyle, } from "./html_utils.js"; import { @@ -107,14 +115,6 @@ function _setValue(templateNode, value) { templateNode.value[$setValue](value); } -function getRoot(node) { - let parent = node[$getParent](); - while (!(parent instanceof Template)) { - parent = parent[$getParent](); - } - return parent; -} - function* getContainedChildren(node) { for (const child of node[$getChildren]()) { if (child instanceof SubformSet) { @@ -136,90 +136,6 @@ function valueToHtml(value) { }); } -function getTransformedBBox(node) { - // Take into account rotation and anchor the get the - // real bounding box. - let w = node.w === "" ? NaN : node.w; - let h = node.h === "" ? NaN : node.h; - let [centerX, centerY] = [0, 0]; - switch (node.anchorType || "") { - case "bottomCenter": - [centerX, centerY] = [w / 2, h]; - break; - case "bottomLeft": - [centerX, centerY] = [0, h]; - break; - case "bottomRight": - [centerX, centerY] = [w, h]; - break; - case "middleCenter": - [centerX, centerY] = [w / 2, h / 2]; - break; - case "middleLeft": - [centerX, centerY] = [0, h / 2]; - break; - case "middleRight": - [centerX, centerY] = [w, h / 2]; - break; - case "topCenter": - [centerX, centerY] = [w / 2, 0]; - break; - case "topRight": - [centerX, centerY] = [w, 0]; - break; - } - - let x; - let y; - switch (node.rotate || 0) { - case 0: - [x, y] = [-centerX, -centerY]; - break; - case 90: - [x, y] = [-centerY, centerX]; - [w, h] = [h, -w]; - break; - case 180: - [x, y] = [centerX, centerY]; - [w, h] = [-w, -h]; - break; - case 270: - [x, y] = [centerY, -centerX]; - [w, h] = [-h, w]; - break; - } - - return [ - node.x + x + Math.min(0, w), - node.y + y + Math.min(0, h), - Math.abs(w), - Math.abs(h), - ]; -} - -const NOTHING = 0; -const NOSPACE = 1; -const VALID = 2; -function checkDimensions(node, space) { - if (node[$getParent]().layout === "position") { - return VALID; - } - const [x, y, w, h] = getTransformedBBox(node); - if (node.w === 0 || node.h === 0) { - return VALID; - } - - if (node.w !== "" && Math.round(x + w - space.width) > 1) { - return NOSPACE; - } - - if (node.h !== "" && Math.round(y + h - space.height) > 1) { - return NOSPACE; - } - - return VALID; -} - class AppearanceFilter extends StringObject { constructor(attributes) { super(TEMPLATE_NS_ID, "appearanceFilter"); @@ -1525,7 +1441,7 @@ class Draw extends XFAObject { if ((this.w === "" || this.h === "") && this.value) { const maxWidth = this.w === "" ? availableSpace.width : this.w; - const fonts = getRoot(this)[$fonts]; + const fonts = this[$getTemplateRoot]()[$fonts]; let font = this.font; if (!font) { let parent = this[$getParent](); @@ -1571,13 +1487,8 @@ class Draw extends XFAObject { } } - switch (checkDimensions(this, availableSpace)) { - case NOTHING: - return HTMLResult.EMPTY; - case NOSPACE: - return HTMLResult.FAILURE; - default: - break; + if (!checkDimensions(this, availableSpace)) { + return HTMLResult.FAILURE; } const style = toStyle( @@ -1593,6 +1504,8 @@ class Draw extends XFAObject { "margin" ); + setMinMaxDimensions(this, style); + const classNames = ["xfaDraw"]; if (this.font) { classNames.push("xfaFont"); @@ -2062,6 +1975,27 @@ class ExclGroup extends XFAObject { } } + [$isSplittable]() { + // We cannot cache the result here because the contentArea + // can change. + const root = this[$getTemplateRoot](); + const contentArea = root[$extra].currentContentArea; + if (contentArea && Math.max(this.minH, this.h || 0) >= contentArea.h) { + return true; + } + + if (this.layout === "position") { + return false; + } + + const parentLayout = this[$getParent]().layout; + if (parentLayout && parentLayout.includes("row")) { + return false; + } + + return true; + } + [$flushHTML]() { return flushHTML(this); } @@ -2106,13 +2040,8 @@ class ExclGroup extends XFAObject { currentWidth: 0, }); - switch (checkDimensions(this, availableSpace)) { - case NOTHING: - return HTMLResult.EMPTY; - case NOSPACE: - return HTMLResult.FAILURE; - default: - break; + if (!checkDimensions(this, availableSpace)) { + return HTMLResult.FAILURE; } availableSpace = { @@ -2172,7 +2101,7 @@ class ExclGroup extends XFAObject { } } - failure = this[$extra].attempt === 2; + failure = this[$extra].attempt === MAX_ATTEMPTS_FOR_LRTB_LAYOUT; } else { const result = this[$childrenToHTML]({ filter, @@ -2185,12 +2114,16 @@ class ExclGroup extends XFAObject { } if (failure) { - if (this.layout === "position") { + if (this[$isSplittable]()) { delete this[$extra]; } return HTMLResult.FAILURE; } + if (children.length === 0) { + return HTMLResult.EMPTY; + } + let marginH = 0; let marginV = 0; if (this.margin) { @@ -2198,11 +2131,15 @@ class ExclGroup extends XFAObject { marginV = this.margin.topInset + this.margin.bottomInset; } + const width = Math.max(this[$extra].width + marginH, this.w || 0); + const height = Math.max(this[$extra].height + marginV, this.h || 0); + const bbox = [this.x, this.y, width, height]; + if (this.w === "") { - style.width = measureToString(this[$extra].width + marginH); + style.width = measureToString(width); } if (this.h === "") { - style.height = measureToString(this[$extra].height + marginV); + style.height = measureToString(height); } const html = { @@ -2211,16 +2148,6 @@ class ExclGroup extends XFAObject { children, }; - let bbox; - if (this.w !== "" && this.h !== "") { - bbox = [this.x, this.y, this.w, this.h]; - } else { - const width = this.w === "" ? marginH + this[$extra].width : this.w; - const height = this.h === "" ? marginV + this[$extra].height : this.h; - - bbox = [this.x, this.y, width, height]; - } - delete this[$extra]; return HTMLResult.success(createWrapper(this, html), bbox); @@ -2372,13 +2299,8 @@ class Field extends XFAObject { fixDimensions(this); - switch (checkDimensions(this, availableSpace)) { - case NOTHING: - return HTMLResult.EMPTY; - case NOSPACE: - return HTMLResult.FAILURE; - default: - break; + if (!checkDimensions(this, availableSpace)) { + return HTMLResult.FAILURE; } const style = toStyle( @@ -2393,6 +2315,8 @@ class Field extends XFAObject { "hAlign" ); + setMinMaxDimensions(this, style); + const classNames = ["xfaField"]; // If no font, font properties are inherited. if (this.font) { @@ -3374,7 +3298,7 @@ class PageArea extends XFAObject { } [$getAvailableSpace]() { - return { width: Infinity, height: Infinity }; + return this[$extra].space || { width: 0, height: 0 }; } [$toHTML]() { @@ -3392,10 +3316,18 @@ class PageArea extends XFAObject { if (this.medium && this.medium.short && this.medium.long) { style.width = measureToString(this.medium.short); style.height = measureToString(this.medium.long); + this[$extra].space = { + width: this.medium.short, + height: this.medium.long, + }; if (this.medium.orientation === "landscape") { const x = style.width; style.width = style.height; style.height = x; + this[$extra].space = { + width: this.medium.long, + height: this.medium.short, + }; } } else { warn("XFA - No medium specified in pageArea: please file a bug."); @@ -3486,7 +3418,7 @@ class PageSet extends XFAObject { return this[$getNextPage](); } - const pageNumber = getRoot(this)[$extra].pageNumber; + const pageNumber = this[$getTemplateRoot]()[$extra].pageNumber; const parity = pageNumber % 2 === 0 ? "even" : "odd"; const position = pageNumber === 0 ? "first" : "rest"; @@ -4175,6 +4107,36 @@ class Subform extends XFAObject { return getAvailableSpace(this); } + [$isSplittable](x) { + // We cannot cache the result here because the contentArea + // can change. + const root = this[$getTemplateRoot](); + const contentArea = root[$extra].currentContentArea; + if (contentArea && Math.max(this.minH, this.h || 0) >= contentArea.h) { + return true; + } + + if (this.layout === "position") { + return false; + } + + if (this.keep && this.keep.intact !== "none") { + return false; + } + + const parentLayout = this[$getParent]().layout; + if (parentLayout && parentLayout.includes("row")) { + return false; + } + + if (this.overflow && this.overflow.target) { + const target = root[$searchNode](this.overflow.target, this); + return target && target[0] === contentArea; + } + + return true; + } + [$toHTML](availableSpace) { if (this.presence === "hidden" || this.presence === "inactive") { return HTMLResult.EMPTY; @@ -4201,9 +4163,7 @@ class Subform extends XFAObject { } if (this[$extra] && this[$extra].afterBreakAfter) { - const result = this[$extra].afterBreakAfter; - delete this[$extra]; - return result; + return HTMLResult.EMPTY; } // TODO: incomplete. @@ -4228,21 +4188,8 @@ class Subform extends XFAObject { currentWidth: 0, }); - switch (checkDimensions(this, availableSpace)) { - case NOTHING: - return HTMLResult.EMPTY; - case NOSPACE: - return HTMLResult.FAILURE; - default: - break; - } - - let noBreakOnOverflow = false; - if (this.overflow && this.overflow.target) { - const root = getRoot(this); - const target = root[$searchNode](this.overflow.target, this); - noBreakOnOverflow = - target && target[0] === root[$extra].currentContentArea; + if (!checkDimensions(this, availableSpace)) { + return HTMLResult.FAILURE; } const filter = new Set([ @@ -4285,6 +4232,8 @@ class Subform extends XFAObject { attributes.xfaName = this.name; } + const isSplittable = this[$isSplittable](); + // If the container overflows into itself we add an extra // layout step to accept finally the element which caused // the overflow. @@ -4292,7 +4241,7 @@ class Subform extends XFAObject { this.layout === "lr-tb" || this.layout === "rl-tb" ? MAX_ATTEMPTS_FOR_LRTB_LAYOUT : 1; - maxRun += noBreakOnOverflow ? 1 : 0; + maxRun += !isSplittable && this.layout !== "position" ? 1 : 0; for (; this[$extra].attempt < maxRun; this[$extra].attempt++) { const result = this[$childrenToHTML]({ filter, @@ -4308,15 +4257,21 @@ class Subform extends XFAObject { if (this[$extra].attempt === maxRun) { if (this.overflow) { - getRoot(this)[$extra].overflowNode = this.overflow; + this[$getTemplateRoot]()[$extra].overflowNode = this.overflow; } - if (this.layout === "position") { + if (!isSplittable) { + // Since a new try will happen in a new container with maybe + // new dimensions, we invalidate already layed out components. delete this[$extra]; } return HTMLResult.FAILURE; } + if (children.length === 0) { + return HTMLResult.EMPTY; + } + let marginH = 0; let marginV = 0; if (this.margin) { @@ -4324,11 +4279,15 @@ class Subform extends XFAObject { marginV = this.margin.topInset + this.margin.bottomInset; } + const width = Math.max(this[$extra].width + marginH, this.w || 0); + const height = Math.max(this[$extra].height + marginV, this.h || 0); + const bbox = [this.x, this.y, width, height]; + if (this.w === "") { - style.width = measureToString(this[$extra].width + marginH); + style.width = measureToString(width); } if (this.h === "") { - style.height = measureToString(this[$extra].height + marginV); + style.height = measureToString(height); } const html = { @@ -4337,16 +4296,6 @@ class Subform extends XFAObject { children, }; - let bbox; - if (this.w !== "" && this.h !== "") { - bbox = [this.x, this.y, this.w, this.h]; - } else { - const width = this.w === "" ? marginH + this[$extra].width : this.w; - const height = this.h === "" ? marginV + this[$extra].height : this.h; - - bbox = [this.x, this.y, width, height]; - } - const result = HTMLResult.success(createWrapper(this, html), bbox); if (this.breakAfter.children.length >= 1) { @@ -4605,12 +4554,12 @@ class Template extends XFAObject { mainHtml.children.push(page); if (leader) { - page.children.push(leader[$toHTML](page[$extra].space).html); + page.children.push(leader[$toHTML](pageArea[$extra].space).html); leader = null; } if (trailer) { - page.children.push(trailer[$toHTML](page[$extra].space).html); + page.children.push(trailer[$toHTML](pageArea[$extra].space).html); trailer = null; } @@ -4646,7 +4595,10 @@ class Template extends XFAObject { const html = root[$toHTML](space); if (html.success) { if (html.html) { + hasSomething = true; htmlContentAreas[i].children.push(html.html); + } else if (!hasSomething) { + mainHtml.children.pop(); } return mainHtml; } diff --git a/src/core/xfa/xfa_object.js b/src/core/xfa/xfa_object.js index 1ed91cd1c..c59552abd 100644 --- a/src/core/xfa/xfa_object.js +++ b/src/core/xfa/xfa_object.js @@ -47,7 +47,7 @@ const $getContainedChildren = Symbol(); const $getNextPage = Symbol(); const $getSubformParent = Symbol(); const $getParent = Symbol(); -const $pushGlyphs = Symbol(); +const $getTemplateRoot = Symbol(); const $global = Symbol(); const $hasItem = Symbol(); const $hasSettableValue = Symbol(); @@ -57,6 +57,7 @@ const $insertAt = Symbol(); const $isCDATAXml = Symbol(); const $isDataValue = Symbol(); const $isDescendent = Symbol(); +const $isSplittable = Symbol(); const $isTransparent = Symbol(); const $lastAttribute = Symbol(); const $namespaceId = Symbol("namespaceId"); @@ -65,6 +66,7 @@ const $nsAttributes = Symbol(); const $onChild = Symbol(); const $onChildCheck = Symbol(); const $onText = Symbol(); +const $pushGlyphs = Symbol(); const $removeChild = Symbol(); const $root = Symbol("root"); const $resolvePrototypes = Symbol(); @@ -162,6 +164,18 @@ class XFAObject { } } + [$getTemplateRoot]() { + let parent = this[$getParent](); + while (parent[$nodeName] !== "template") { + parent = parent[$getParent](); + } + return parent; + } + + [$isSplittable]() { + return false; + } + [$appendChild](child) { child[_parent] = this; this[_children].push(child); @@ -985,6 +999,7 @@ export { $getParent, $getRealChildrenByNameIt, $getSubformParent, + $getTemplateRoot, $global, $hasItem, $hasSettableValue, @@ -994,6 +1009,7 @@ export { $isCDATAXml, $isDataValue, $isDescendent, + $isSplittable, $isTransparent, $namespaceId, $nodeName, diff --git a/test/pdfs/xfa_candidate_petitions.pdf.link b/test/pdfs/xfa_candidate_petitions.pdf.link new file mode 100644 index 000000000..34a4ca1a2 --- /dev/null +++ b/test/pdfs/xfa_candidate_petitions.pdf.link @@ -0,0 +1 @@ +https://web.archive.org/web/20210509141453/https://www.sos.state.oh.us/globalassets/elections/directives/2020/dir2020-15_independentcandidatepetitions2020signedextended.pdf diff --git a/test/test_manifest.json b/test/test_manifest.json index 67d4549f5..66f2b817a 100644 --- a/test/test_manifest.json +++ b/test/test_manifest.json @@ -946,6 +946,14 @@ "enableXfa": true, "type": "eq" }, + { "id": "xfa_candidate_petitions", + "file": "pdfs/xfa_candidate_petitions.pdf", + "md5": "0db96a00667f8f58f94cf81022e69341", + "link": true, + "rounds": 1, + "enableXfa": true, + "type": "eq" + }, { "id": "xfa_annual_expense_report", "file": "pdfs/xfa_annual_expense_report.pdf", "md5": "06866e7a6bbc0346789208ef5f6e885c", diff --git a/test/unit/xfa_tohtml_spec.js b/test/unit/xfa_tohtml_spec.js index bd3959413..8e5de87eb 100644 --- a/test/unit/xfa_tohtml_spec.js +++ b/test/unit/xfa_tohtml_spec.js @@ -60,6 +60,9 @@ describe("XFAFactory", function () { + + foo + @@ -133,7 +136,7 @@ describe("XFAFactory", function () { - + @@ -146,6 +149,7 @@ describe("XFAFactory", function () { + foo