Merge pull request #13141 from calixteman/xfa_text

XFA -- Display text content
This commit is contained in:
Brendan Dahl 2021-04-12 14:34:38 -07:00 committed by GitHub
commit a53cd1cc1e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 552 additions and 164 deletions

View File

@ -13,7 +13,7 @@
* limitations under the License.
*/
import { $getParent, $toStyle, XFAObject } from "./xfa_object.js";
import { $extra, $getParent, $toStyle, XFAObject } from "./xfa_object.js";
import { warn } from "../../shared/util.js";
function measureToString(m) {
@ -56,8 +56,17 @@ const converters = {
}
},
dimensions(node, style) {
if (node.w) {
style.width = measureToString(node.w);
const parent = node[$getParent]();
const extra = parent[$extra];
let width = node.w;
if (extra && extra.columnWidths) {
width = extra.columnWidths[extra.currentColumn];
extra.currentColumn =
(extra.currentColumn + 1) % extra.columnWidths.length;
}
if (width !== "") {
style.width = measureToString(width);
} else {
style.width = "auto";
if (node.maxW > 0) {
@ -66,7 +75,7 @@ const converters = {
style.minWidth = measureToString(node.minW);
}
if (node.h) {
if (node.h !== "") {
style.height = measureToString(node.h);
} else {
style.height = "auto";
@ -108,6 +117,53 @@ const converters = {
break;
}
},
hAlign(node, style) {
switch (node.hAlign) {
case "justifyAll":
style.textAlign = "justify-all";
break;
case "radix":
// TODO: implement this correctly !
style.textAlign = "left";
break;
default:
style.textAlign = node.hAlign;
}
},
borderMarginPadding(node, style) {
// Get border width in order to compute margin and padding.
const borderWidths = [0, 0, 0, 0];
const marginWidths = [0, 0, 0, 0];
const marginNode = node.margin
? [
node.margin.topInset,
node.margin.rightInset,
node.margin.bottomInset,
node.margin.leftInset,
]
: [0, 0, 0, 0];
if (node.border) {
Object.assign(style, node.border[$toStyle](borderWidths, marginWidths));
}
if (borderWidths.every(x => x === 0)) {
// No border: margin & padding are padding
if (node.margin) {
Object.assign(style, node.margin[$toStyle]());
}
style.padding = style.margin;
delete style.margin;
} else {
style.padding =
measureToString(marginNode[0] - borderWidths[0] - marginWidths[0]) +
" " +
measureToString(marginNode[1] - borderWidths[1] - marginWidths[1]) +
" " +
measureToString(marginNode[2] - borderWidths[2] - marginWidths[2]) +
" " +
measureToString(marginNode[3] - borderWidths[3] - marginWidths[3]);
}
},
};
function layoutClass(node) {
@ -155,4 +211,26 @@ function toStyle(node, ...names) {
return style;
}
export { layoutClass, measureToString, toStyle };
function addExtraDivForMargin(html) {
const style = html.attributes.style;
if (style.margin) {
const padding = style.margin;
delete style.margin;
const width = style.width || "auto";
const height = style.height || "auto";
style.width = "100%";
style.height = "100%";
return {
name: "div",
attributes: {
style: { padding, width, height },
},
children: [html],
};
}
return html;
}
export { addExtraDivForMargin, layoutClass, measureToString, toStyle };

View File

@ -14,6 +14,7 @@
*/
import {
$acceptWhitespace,
$clean,
$finalize,
$nsAttributes,
@ -49,6 +50,11 @@ class XFAParser extends XMLParserBase {
}
onText(text) {
if (this._current[$acceptWhitespace]()) {
this._current[$onText](text);
return;
}
if (this._whiteRegex.test(text)) {
return;
}

View File

@ -40,6 +40,12 @@ import {
XFAObjectArray,
} from "./xfa_object.js";
import { $buildXFAObject, NamespaceIds } from "./namespaces.js";
import {
addExtraDivForMargin,
layoutClass,
measureToString,
toStyle,
} from "./html_utils.js";
import {
getBBox,
getColor,
@ -51,7 +57,6 @@ import {
getRelevant,
getStringOption,
} from "./utils.js";
import { layoutClass, measureToString, toStyle } from "./html_utils.js";
import { Util, warn } from "../../shared/util.js";
const TEMPLATE_NS_ID = NamespaceIds.template.id;
@ -131,6 +136,36 @@ class Area extends XFAObject {
[$isTransparent]() {
return true;
}
[$toHTML]() {
// TODO: incomplete.
this[$extra] = Object.create(null);
const style = toStyle(this, "position");
const attributes = {
style,
id: this[$uid],
class: "xfaArea",
};
if (this.name) {
attributes.xfaName = this.name;
}
const children = this[$childrenToHTML]({
// TODO: exObject & exclGroup
filter: new Set(["area", "draw", "field", "subform", "subformSet"]),
include: true,
});
const html = {
name: "div",
attributes,
children,
};
return html;
}
}
class Assist extends XFAObject {
@ -376,56 +411,42 @@ class Border extends XFAObject {
[$toStyle](widths, margins) {
// TODO: incomplete.
const edgeStyles = this.edge.children.map(node => node[$toStyle]());
const cornerStyles = this.edge.children.map(node => node[$toStyle]());
const edges = this.edge.children.slice();
if (edges.length < 4) {
const defaultEdge = edges[edges.length - 1] || new Edge({});
for (let i = edges.length; i < 4; i++) {
edges.push(defaultEdge);
}
}
if (widths) {
for (let i = 0; i < 4; i++) {
widths[i] = edges[i].thickness;
}
}
const edgeStyles = edges.map(node => node[$toStyle]());
const cornerStyles = this.corner.children.map(node => node[$toStyle]());
let style;
if (this.margin) {
style = this.margin[$toStyle]();
if (margins) {
margins.push(
this.margin.topInset,
this.margin.rightInset,
this.margin.bottomInset,
this.margin.leftInset
);
margins[0] = this.margin.topInset;
margins[1] = this.margin.rightInset;
margins[2] = this.margin.bottomInset;
margins[3] = this.margin.leftInset;
}
} else {
style = Object.create(null);
if (margins) {
margins.push(0, 0, 0, 0);
}
}
if (this.fill) {
Object.assign(style, this.fill[$toStyle]());
}
if (edgeStyles.length > 0) {
if (widths) {
this.edge.children.forEach(node => widths.push(node.thickness));
if (widths.length < 4) {
const last = widths[widths.length - 1];
for (let i = widths.length; i < 4; i++) {
widths.push(last);
}
}
}
if (edgeStyles.length === 2 || edgeStyles.length === 3) {
const last = edgeStyles[edgeStyles.length - 1];
for (let i = edgeStyles.length; i < 4; i++) {
edgeStyles.push(last);
}
}
style.borderWidth = edgeStyles.map(s => s.width).join(" ");
style.borderColor = edgeStyles.map(s => s.color).join(" ");
style.borderStyle = edgeStyles.map(s => s.style).join(" ");
} else {
if (widths) {
widths.push(0, 0, 0, 0);
}
}
style.borderWidth = edgeStyles.map(s => s.width).join(" ");
style.borderColor = edgeStyles.map(s => s.color).join(" ");
style.borderStyle = edgeStyles.map(s => s.style).join(" ");
if (cornerStyles.length > 0) {
if (cornerStyles.length === 2 || cornerStyles.length === 3) {
@ -718,7 +739,7 @@ class CheckButton extends XFAObject {
let mark, radius;
if (this.shape === "square") {
mark = "";
mark = "";
radius = "10%";
} else {
mark = "●";
@ -746,7 +767,7 @@ class CheckButton extends XFAObject {
mark = "♦";
break;
case "square":
mark = "";
mark = "";
break;
case "star":
mark = "★";
@ -822,7 +843,7 @@ class ChoiceList extends XFAObject {
{
name: "select",
attributes: {
class: "xfaSxelect",
class: "xfaSelect",
multiple: this.open === "multiSelect",
style,
},
@ -1211,11 +1232,13 @@ class Draw extends XFAObject {
const style = toStyle(
this,
"font",
"hAlign",
"dimensions",
"position",
"presence",
"rotate",
"anchorType"
"anchorType",
"borderMarginPadding"
);
const clazz = ["xfaDraw"];
@ -1233,11 +1256,35 @@ class Draw extends XFAObject {
attributes.xfaName = this.name;
}
return {
let html = {
name: "div",
attributes,
children: [],
};
const value = this.value ? this.value[$toHTML]() : null;
if (value === null) {
return html;
}
html.children.push(value);
if (this.para && value.attributes.class === "xfaRich") {
const paraStyle = this.para[$toStyle]();
if (!value.attributes.style) {
value.attributes.style = paraStyle;
} else {
for (const [key, val] of Object.entries(paraStyle)) {
if (!(key in value.attributes.style)) {
value.attributes.style[key] = val;
}
}
}
}
html = addExtraDivForMargin(html);
return html;
}
}
@ -1494,6 +1541,15 @@ class ExData extends ContentObject {
return false;
}
[$toHTML]() {
if (this.contentType !== "text/html" || !this[$content]) {
// TODO: fix other cases.
return null;
}
return this[$content][$toHTML]();
}
}
class ExObject extends XFAObject {
@ -1793,36 +1849,10 @@ class Field extends XFAObject {
"position",
"rotate",
"anchorType",
"presence"
"presence",
"borderMarginPadding"
);
// Get border width in order to compute margin and padding.
const borderWidths = [];
const marginWidths = [];
if (this.border) {
Object.assign(style, this.border[$toStyle](borderWidths, marginWidths));
}
if (this.margin) {
style.paddingTop = measureToString(
this.margin.topInset - borderWidths[0] - marginWidths[0]
);
style.paddingRight = measureToString(
this.margin.rightInset - borderWidths[1] - marginWidths[1]
);
style.paddingBottom = measureToString(
this.margin.bottomInset - borderWidths[2] - marginWidths[2]
);
style.paddingLeft = measureToString(
this.margin.leftInset - borderWidths[3] - marginWidths[3]
);
} else {
style.paddingTop = measureToString(-borderWidths[0] - marginWidths[0]);
style.paddingRight = measureToString(-borderWidths[1] - marginWidths[1]);
style.paddingBottom = measureToString(-borderWidths[2] - marginWidths[2]);
style.paddingLeft = measureToString(-borderWidths[3] - marginWidths[3]);
}
const clazz = ["xfaField"];
// If no font, font properties are inherited.
if (this.font) {
@ -1840,7 +1870,7 @@ class Field extends XFAObject {
}
const children = [];
const html = {
let html = {
name: "div",
attributes,
children,
@ -1857,8 +1887,7 @@ class Field extends XFAObject {
children.push(ui);
if (this.value && ui.name !== "button") {
// TODO: should be ok with string but html ??
ui.children[0].attributes.value = this.value[$toHTML]();
ui.children[0].attributes.value = this.value[$toHTML]().value;
}
const caption = this.caption ? this.caption[$toHTML]() : null;
@ -1867,8 +1896,8 @@ class Field extends XFAObject {
}
if (ui.name === "button") {
ui.attributes.style.background = style.color;
delete style.color;
ui.attributes.style.background = style.background;
delete style.background;
if (caption.name === "div") {
caption.name = "span";
}
@ -1896,6 +1925,8 @@ class Field extends XFAObject {
break;
}
html = addExtraDivForMargin(html);
return html;
}
}
@ -1938,9 +1969,13 @@ class Fill extends XFAObject {
};
}
return {
color: this.color ? this.color[$toStyle]() : "#000000",
};
if (this.color) {
return {
background: this.color[$toStyle](),
};
}
return {};
}
}
@ -2053,15 +2088,18 @@ class Font extends XFAObject {
[$toStyle]() {
const style = toStyle(this, "fill");
if (style.color) {
if (!style.color.startsWith("#")) {
const color = style.background;
if (color) {
if (color === "#000000") {
delete style.background;
} else if (!color.startsWith("#")) {
// We've a gradient which is not possible for a font color
// so use a workaround.
style.backgroundClip = "text";
style.background = style.color;
style.color = "transparent";
} else if (style.color === "#000000") {
delete style.color;
} else {
style.color = color;
delete style.background;
}
}
@ -2213,6 +2251,7 @@ class Image extends StringObject {
const html = {
name: "img",
attributes: {
class: "xfaImage",
style: {},
},
};
@ -2441,10 +2480,14 @@ class Margin extends XFAObject {
[$toStyle]() {
return {
marginLeft: measureToString(this.leftInset),
marginRight: measureToString(this.rightInset),
marginTop: measureToString(this.topInset),
marginBottom: measureToString(this.bottomInset),
margin:
measureToString(this.topInset) +
" " +
measureToString(this.rightInset) +
" " +
measureToString(this.bottomInset) +
" " +
measureToString(this.leftInset),
};
}
}
@ -2730,26 +2773,40 @@ class Para extends XFAObject {
"right",
]);
this.id = attributes.id || "";
this.lineHeight = getMeasurement(attributes.lineHeight, "0pt");
this.marginLeft = getMeasurement(attributes.marginLeft, "0");
this.marginRight = getMeasurement(attributes.marginRight, "0");
this.lineHeight = attributes.lineHeight
? getMeasurement(attributes.lineHeight, "0pt")
: "";
this.marginLeft = attributes.marginLeft
? getMeasurement(attributes.marginLeft, "0pt")
: "";
this.marginRight = attributes.marginRight
? getMeasurement(attributes.marginRight, "0pt")
: "";
this.orphans = getInteger({
data: attributes.orphans,
defaultValue: 0,
validate: x => x >= 0,
});
this.preserve = attributes.preserve || "";
this.radixOffset = getMeasurement(attributes.radixOffset, "0");
this.spaceAbove = getMeasurement(attributes.spaceAbove, "0");
this.spaceBelow = getMeasurement(attributes.spaceBelow, "0");
this.radixOffset = attributes.radixOffset
? getMeasurement(attributes.radixOffset, "0pt")
: "";
this.spaceAbove = attributes.spaceAbove
? getMeasurement(attributes.spaceAbove, "0pt")
: "";
this.spaceBelow = attributes.spaceBelow
? getMeasurement(attributes.spaceBelow, "0pt")
: "";
this.tabDefault = attributes.tabDefault
? getMeasurement(this.tabDefault)
: null;
: "";
this.tabStops = (attributes.tabStops || "")
.trim()
.split(/\s+/)
.map((x, i) => (i % 2 === 1 ? getMeasurement(x) : x));
this.textIndent = getMeasurement(attributes.textIndent, "0");
this.textIndent = attributes.textIndent
? getMeasurement(attributes.textIndent, "0pt")
: "";
this.use = attributes.use || "";
this.usehref = attributes.usehref || "";
this.vAlign = getStringOption(attributes.vAlign, [
@ -2765,21 +2822,31 @@ class Para extends XFAObject {
this.hyphenation = null;
}
[$toHTML]() {
const style = {
marginLeft: measureToString(this.marginLeft),
marginRight: measureToString(this.marginRight),
paddingTop: measureToString(this.spaceAbove),
paddingBottom: measureToString(this.spaceBelow),
textIndent: measureToString(this.textIndent),
verticalAlign: this.vAlign,
};
[$toStyle]() {
const style = toStyle(this, "hAlign");
if (this.marginLeft !== "") {
style.marginLeft = measureToString(this.marginLeft);
}
if (this.marginRight !== "") {
style.marginRight = measureToString(this.marginRight);
}
if (this.spaceAbove !== "") {
style.marginTop = measureToString(this.spaceAbove);
}
if (this.spaceBelow !== "") {
style.marginBottom = measureToString(this.spaceBelow);
}
if (this.textIndent !== "") {
style.textIndent = measureToString(this.textIndent);
}
if (this.lineHeight.value >= 0) {
// TODO: vAlign
if (this.lineHeight !== "") {
style.lineHeight = measureToString(this.lineHeight);
}
if (this.tabDefault) {
if (this.tabDefault !== "") {
style.tabSize = measureToString(this.tabDefault);
}
@ -2788,7 +2855,7 @@ class Para extends XFAObject {
}
if (this.hyphenatation) {
Object.assign(style, this.hyphenatation[$toHTML]());
Object.assign(style, this.hyphenatation[$toStyle]());
}
return style;
@ -3294,6 +3361,14 @@ class Subform extends XFAObject {
// TODO: incomplete.
this[$extra] = Object.create(null);
if (this.layout === "row") {
const columnWidths = this[$getParent]().columnWidths;
if (Array.isArray(columnWidths) && columnWidths.length > 0) {
this[$extra].columnWidths = columnWidths;
this[$extra].currentColumn = 0;
}
}
const parent = this[$getParent]();
let page = null;
if (parent[$nodeName] === "template") {
@ -3520,8 +3595,67 @@ class Text extends ContentObject {
[$toHTML]() {
if (typeof this[$content] === "string") {
return this[$content];
// \u2028 is a line separator.
// \u2029 is a paragraph separator.
const html = {
name: "span",
attributes: {
class: "xfaRich",
style: {},
},
value: this[$content],
};
if (this[$content].includes("\u2029")) {
// We've plain text containing a paragraph separator
// so convert it into a set of <p>.
html.name = "div";
html.children = [];
this[$content]
.split("\u2029")
.map(para =>
// Convert a paragraph into a set of <span> (for lines)
// separated by <br>.
para.split(/[\u2028\n]/).reduce((acc, line) => {
acc.push(
{
name: "span",
value: line,
},
{
name: "br",
}
);
return acc;
}, [])
)
.forEach(lines => {
html.children.push({
name: "p",
children: lines,
});
});
} else if (/[\u2028\n]/.test(this[$content])) {
html.name = "div";
html.children = [];
// Convert plain text into a set of <span> (for lines)
// separated by <br>.
this[$content].split(/[\u2028\n]/).forEach(line => {
html.children.push(
{
name: "span",
value: line,
},
{
name: "br",
}
);
});
}
return html;
}
return this[$content][$toHTML]();
}
}
@ -3562,10 +3696,11 @@ class TextEdit extends XFAObject {
// TODO: incomplete.
const style = toStyle(this, "border", "font", "margin");
let html;
if (this.multiline === 1) {
if (this.multiLine === 1) {
html = {
name: "textarea",
attributes: {
class: "xfaTextfield",
style,
},
};

View File

@ -19,6 +19,7 @@ import { NamespaceIds } from "./namespaces.js";
// We use these symbols to avoid name conflict between tags
// and properties/methods names.
const $acceptWhitespace = Symbol();
const $appendChild = Symbol();
const $childrenToHTML = Symbol();
const $clean = Symbol();
@ -131,6 +132,10 @@ class XFAObject {
);
}
[$acceptWhitespace]() {
return false;
}
[$setId](ids) {
if (this.id && this[$namespaceId] === NamespaceIds.template.id) {
ids.set(this.id, this);
@ -805,6 +810,7 @@ class Option10 extends IntegerObject {
}
export {
$acceptWhitespace,
$appendChild,
$childrenToHTML,
$clean,

View File

@ -13,8 +13,19 @@
* limitations under the License.
*/
import {
$acceptWhitespace,
$childrenToHTML,
$content,
$nodeName,
$onText,
$text,
$toHTML,
XmlObject,
} from "./xfa_object.js";
import { $buildXFAObject, NamespaceIds } from "./namespaces.js";
import { $text, XmlObject } from "./xfa_object.js";
import { getMeasurement } from "./utils.js";
import { measureToString } from "./html_utils.js";
const XHTML_NS_ID = NamespaceIds.xhtml.id;
@ -39,6 +50,7 @@ const VALID_STYLES = new Set([
"page-break-inside",
"tab-interval",
"tab-stop",
"text-align",
"text-decoration",
"text-indent",
"vertical-align",
@ -46,9 +58,73 @@ const VALID_STYLES = new Set([
"kerning-mode",
"xfa-font-horizontal-scale",
"xfa-font-vertical-scale",
"xfa-spacerun",
"xfa-tab-stops",
]);
const StyleMapping = new Map([
["page-break-after", "breakAfter"],
["page-break-before", "breakBefore"],
["page-break-inside", "breakInside"],
["kerning-mode", value => (value === "none" ? "none" : "normal")],
[
"xfa-font-horizontal-scale",
value =>
`scaleX(${Math.max(0, Math.min(parseInt(value) / 100)).toFixed(2)})`,
],
[
"xfa-font-vertical-scale",
value =>
`scaleY(${Math.max(0, Math.min(parseInt(value) / 100)).toFixed(2)})`,
],
["xfa-spacerun", ""],
["xfa-tab-stops", ""],
["font-size", value => measureToString(getMeasurement(value))],
["letter-spacing", value => measureToString(getMeasurement(value))],
["line-height", value => measureToString(getMeasurement(value))],
["margin", value => measureToString(getMeasurement(value))],
["margin-bottom", value => measureToString(getMeasurement(value))],
["margin-left", value => measureToString(getMeasurement(value))],
["margin-right", value => measureToString(getMeasurement(value))],
["margin-top", value => measureToString(getMeasurement(value))],
]);
const spacesRegExp = /\s+/g;
const crlfRegExp = /[\r\n]+/g;
function mapStyle(styleStr) {
const style = Object.create(null);
if (!styleStr) {
return style;
}
for (const [key, value] of styleStr.split(";").map(s => s.split(":", 2))) {
const mapping = StyleMapping.get(key);
if (mapping === "") {
continue;
}
let newValue = value;
if (mapping) {
if (typeof mapping === "string") {
newValue = mapping;
} else {
newValue = mapping(value);
}
}
if (key.endsWith("scale")) {
if (style.transform) {
style.transform = `${style[key]} ${newValue}`;
} else {
style.transform = newValue;
}
} else {
style[
key.replaceAll(/-([a-zA-Z])/g, (_, x) => x.toUpperCase())
] = newValue;
}
}
return style;
}
function checkStyle(style) {
if (!style) {
return "";
@ -65,99 +141,163 @@ function checkStyle(style) {
.join(";");
}
class A extends XmlObject {
const NoWhites = new Set(["body", "html"]);
class XhtmlObject extends XmlObject {
constructor(attributes, name) {
super(XHTML_NS_ID, name);
this.style = checkStyle(attributes.style);
}
[$acceptWhitespace]() {
return !NoWhites.has(this[$nodeName]);
}
[$onText](str) {
str = str.replace(crlfRegExp, "");
if (!this.style.includes("xfa-spacerun:yes")) {
str = str.replace(spacesRegExp, " ");
}
if (str) {
this[$content] += str;
}
}
[$toHTML]() {
return {
name: this[$nodeName],
attributes: {
href: this.href,
style: mapStyle(this.style),
},
children: this[$childrenToHTML]({}),
value: this[$content] || "",
};
}
}
class A extends XhtmlObject {
constructor(attributes) {
super(XHTML_NS_ID, "a");
super(attributes, "a");
this.href = attributes.href || "";
this.style = checkStyle(attributes.style);
}
}
class B extends XmlObject {
class B extends XhtmlObject {
constructor(attributes) {
super(XHTML_NS_ID, "b");
this.style = checkStyle(attributes.style);
super(attributes, "b");
}
}
class Body extends XmlObject {
class Body extends XhtmlObject {
constructor(attributes) {
super(XHTML_NS_ID, "body");
this.style = checkStyle(attributes.style);
super(attributes, "body");
}
[$toHTML]() {
const html = super[$toHTML]();
html.attributes.class = "xfaRich";
return html;
}
}
class Br extends XmlObject {
class Br extends XhtmlObject {
constructor(attributes) {
super(XHTML_NS_ID, "br");
this.style = checkStyle(attributes.style);
super(attributes, "br");
}
[$text]() {
return "\n";
}
}
class Html extends XmlObject {
constructor(attributes) {
super(XHTML_NS_ID, "html");
this.style = checkStyle(attributes.style);
[$toHTML]() {
return {
name: "br",
};
}
}
class I extends XmlObject {
class Html extends XhtmlObject {
constructor(attributes) {
super(XHTML_NS_ID, "i");
this.style = checkStyle(attributes.style);
super(attributes, "html");
}
[$toHTML]() {
const children = this[$childrenToHTML]({});
if (children.length === 0) {
return {
name: "div",
attributes: {
class: "xfaRich",
style: {},
},
value: this[$content] || "",
};
}
if (children.length === 1) {
const child = children[0];
if (child.attributes && child.attributes.class === "xfaRich") {
return child;
}
}
return {
name: "div",
attributes: {
class: "xfaRich",
style: {},
},
children,
};
}
}
class Li extends XmlObject {
class I extends XhtmlObject {
constructor(attributes) {
super(XHTML_NS_ID, "li");
this.style = checkStyle(attributes.style);
super(attributes, "i");
}
}
class Ol extends XmlObject {
class Li extends XhtmlObject {
constructor(attributes) {
super(XHTML_NS_ID, "ol");
this.style = checkStyle(attributes.style);
super(attributes, "li");
}
}
class P extends XmlObject {
class Ol extends XhtmlObject {
constructor(attributes) {
super(XHTML_NS_ID, "p");
this.style = checkStyle(attributes.style);
super(attributes, "ol");
}
}
class Span extends XmlObject {
class P extends XhtmlObject {
constructor(attributes) {
super(XHTML_NS_ID, "span");
this.style = checkStyle(attributes.style);
super(attributes, "p");
}
}
class Sub extends XmlObject {
class Span extends XhtmlObject {
constructor(attributes) {
super(XHTML_NS_ID, "sub");
this.style = checkStyle(attributes.style);
super(attributes, "span");
}
}
class Sup extends XmlObject {
class Sub extends XhtmlObject {
constructor(attributes) {
super(XHTML_NS_ID, "sup");
this.style = checkStyle(attributes.style);
super(attributes, "sub");
}
}
class Ul extends XmlObject {
class Sup extends XhtmlObject {
constructor(attributes) {
super(XHTML_NS_ID, "ul");
this.style = checkStyle(attributes.style);
super(attributes, "sup");
}
}
class Ul extends XhtmlObject {
constructor(attributes) {
super(attributes, "ul");
}
}

View File

@ -42,6 +42,7 @@
"writer_spec.js",
"xfa_formcalc_spec.js",
"xfa_parser_spec.js",
"xfa_tohtml_spec.js",
"xml_spec.js"
]
}

View File

@ -330,9 +330,9 @@ describe("XFAParser", function () {
);
expect(p[$text]()).toEqual(
[
"The first line of this paragraph is indented a half-inch.\n",
"Successive lines are not indented.\n",
"This is the last line of the paragraph.\n",
" The first line of this paragraph is indented a half-inch.\n",
" Successive lines are not indented.\n",
" This is the last line of the paragraph.\n ",
].join("")
);
});

View File

@ -81,7 +81,9 @@ describe("XFAFactory", function () {
fontSize: "7px",
height: "22px",
left: "2px",
padding: "1px 4px 2px 3px",
position: "absolute",
textAlign: "left",
top: "1px",
transform: "rotate(-90deg)",
transformOrigin: "top left",

View File

@ -1,4 +1,4 @@
*/* Copyright 2021 Mozilla Foundation
/* Copyright 2021 Mozilla Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -30,6 +30,7 @@
text-decoration: inherit;
vertical-align: inherit;
box-sizing: border-box;
background: transparent;
}
.xfaFont {
@ -44,19 +45,23 @@
}
.xfaDraw {
z-index: 200;
z-index: 100;
}
.xfaExclgroup {
z-index: 300;
z-index: 200;
}
.xfaField {
z-index: 300;
}
.xfaRich {
z-index: 300;
}
.xfaSubform {
z-index: 100;
z-index: 200;
}
.xfaLabel {
@ -77,6 +82,7 @@
height: 100%;
flex: 1 1 auto;
border: none;
resize: none;
}
.xfaLabel > input[type="checkbox"] {
@ -123,6 +129,16 @@
background: Highlight;
}
.xfaRich {
white-space: pre-wrap;
}
.xfaImage,
.xfaRich {
width: 100%;
height: 100%;
}
.xfaLrTb,
.xfaRlTb,
.xfaTb,
@ -134,6 +150,10 @@
position: relative;
}
.xfaArea {
position: relative;
}
.xfaValignMiddle {
display: flex;
align-items: center;