XFA - Improve text layout
- support paragraph margins, line height, letter spacing, ... - compute missing dimensions from fields based almost on the dimensions of caption contents.
This commit is contained in:
parent
d80651e572
commit
f7d3b22480
@ -14,11 +14,15 @@
|
||||
*/
|
||||
|
||||
import {
|
||||
$content,
|
||||
$extra,
|
||||
$getParent,
|
||||
$getSubformParent,
|
||||
$getTemplateRoot,
|
||||
$globalData,
|
||||
$nodeName,
|
||||
$pushGlyphs,
|
||||
$text,
|
||||
$toStyle,
|
||||
XFAObject,
|
||||
} from "./xfa_object.js";
|
||||
@ -191,8 +195,8 @@ function setMinMaxDimensions(node, style) {
|
||||
}
|
||||
}
|
||||
|
||||
function layoutText(text, xfaFont, fontFinder, width) {
|
||||
const measure = new TextMeasure(xfaFont, fontFinder);
|
||||
function layoutText(text, xfaFont, margin, lineHeight, fontFinder, width) {
|
||||
const measure = new TextMeasure(xfaFont, margin, lineHeight, fontFinder);
|
||||
if (typeof text === "string") {
|
||||
measure.addString(text);
|
||||
} else {
|
||||
@ -202,6 +206,86 @@ function layoutText(text, xfaFont, fontFinder, width) {
|
||||
return measure.compute(width);
|
||||
}
|
||||
|
||||
function layoutNode(node, availableSpace) {
|
||||
let height = null;
|
||||
let width = null;
|
||||
|
||||
if ((!node.w || !node.h) && node.value) {
|
||||
let marginH = 0;
|
||||
let marginV = 0;
|
||||
if (node.margin) {
|
||||
marginH = node.margin.leftInset + node.margin.rightInset;
|
||||
marginV = node.margin.topInset + node.margin.bottomInset;
|
||||
}
|
||||
|
||||
let lineHeight = null;
|
||||
let margin = null;
|
||||
if (node.para) {
|
||||
margin = Object.create(null);
|
||||
lineHeight = node.para.lineHeight === "" ? null : node.para.lineHeight;
|
||||
margin.top = node.para.spaceAbove === "" ? 0 : node.para.spaceAbove;
|
||||
margin.bottom = node.para.spaceBelow === "" ? 0 : node.para.spaceBelow;
|
||||
margin.left = node.para.marginLeft === "" ? 0 : node.para.marginLeft;
|
||||
margin.right = node.para.marginRight === "" ? 0 : node.para.marginRight;
|
||||
}
|
||||
|
||||
let font = node.font;
|
||||
if (!font) {
|
||||
const root = node[$getTemplateRoot]();
|
||||
let parent = node[$getParent]();
|
||||
while (parent !== root) {
|
||||
if (parent.font) {
|
||||
font = parent.font;
|
||||
break;
|
||||
}
|
||||
parent = parent[$getParent]();
|
||||
}
|
||||
}
|
||||
|
||||
const maxWidth = !node.w ? availableSpace.width : node.w;
|
||||
const fontFinder = node[$globalData].fontFinder;
|
||||
if (
|
||||
node.value.exData &&
|
||||
node.value.exData[$content] &&
|
||||
node.value.exData.contentType === "text/html"
|
||||
) {
|
||||
const res = layoutText(
|
||||
node.value.exData[$content],
|
||||
font,
|
||||
margin,
|
||||
lineHeight,
|
||||
fontFinder,
|
||||
maxWidth
|
||||
);
|
||||
width = res.width;
|
||||
height = res.height;
|
||||
} else {
|
||||
const text = node.value[$text]();
|
||||
if (text) {
|
||||
const res = layoutText(
|
||||
text,
|
||||
font,
|
||||
margin,
|
||||
lineHeight,
|
||||
fontFinder,
|
||||
maxWidth
|
||||
);
|
||||
width = res.width;
|
||||
height = res.height;
|
||||
}
|
||||
}
|
||||
|
||||
if (width !== null && !node.w) {
|
||||
width += marginH;
|
||||
}
|
||||
|
||||
if (height !== null && !node.h) {
|
||||
height += marginV;
|
||||
}
|
||||
}
|
||||
return [width, height];
|
||||
}
|
||||
|
||||
function computeBbox(node, html, availableSpace) {
|
||||
let bbox;
|
||||
if (node.w !== "" && node.h !== "") {
|
||||
@ -501,7 +585,7 @@ export {
|
||||
fixTextIndent,
|
||||
isPrintOnly,
|
||||
layoutClass,
|
||||
layoutText,
|
||||
layoutNode,
|
||||
measureToString,
|
||||
setAccess,
|
||||
setFontFamily,
|
||||
|
@ -74,7 +74,7 @@ import {
|
||||
fixTextIndent,
|
||||
isPrintOnly,
|
||||
layoutClass,
|
||||
layoutText,
|
||||
layoutNode,
|
||||
measureToString,
|
||||
setAccess,
|
||||
setFontFamily,
|
||||
@ -911,6 +911,26 @@ class Caption extends XFAObject {
|
||||
_setValue(this, value);
|
||||
}
|
||||
|
||||
[$getExtra](availableSpace) {
|
||||
if (!this[$extra]) {
|
||||
let { width, height } = availableSpace;
|
||||
switch (this.placement) {
|
||||
case "left":
|
||||
case "right":
|
||||
case "inline":
|
||||
width = this.reserve <= 0 ? width : this.reserve;
|
||||
break;
|
||||
case "top":
|
||||
case "bottom":
|
||||
height = this.reserve <= 0 ? height : this.reserve;
|
||||
break;
|
||||
}
|
||||
|
||||
this[$extra] = layoutNode(this, { width, height });
|
||||
}
|
||||
return this[$extra];
|
||||
}
|
||||
|
||||
[$toHTML](availableSpace) {
|
||||
// TODO: incomplete.
|
||||
if (!this.value) {
|
||||
@ -921,6 +941,23 @@ class Caption extends XFAObject {
|
||||
if (!value) {
|
||||
return HTMLResult.EMPTY;
|
||||
}
|
||||
|
||||
const savedReserve = this.reserve;
|
||||
if (this.reserve <= 0) {
|
||||
const [w, h] = this[$getExtra](availableSpace);
|
||||
switch (this.placement) {
|
||||
case "left":
|
||||
case "right":
|
||||
case "inline":
|
||||
this.reserve = w;
|
||||
break;
|
||||
case "top":
|
||||
case "bottom":
|
||||
this.reserve = h;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const children = [];
|
||||
if (typeof value === "string") {
|
||||
children.push({
|
||||
@ -937,20 +974,18 @@ class Caption extends XFAObject {
|
||||
case "right":
|
||||
if (this.reserve > 0) {
|
||||
style.width = measureToString(this.reserve);
|
||||
} else {
|
||||
style.minWidth = measureToString(this.reserve);
|
||||
}
|
||||
break;
|
||||
case "top":
|
||||
case "bottom":
|
||||
if (this.reserve > 0) {
|
||||
style.height = measureToString(this.reserve);
|
||||
} else {
|
||||
style.minHeight = measureToString(this.reserve);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
this.reserve = savedReserve;
|
||||
|
||||
return HTMLResult.success({
|
||||
name: "div",
|
||||
attributes: {
|
||||
@ -1569,63 +1604,22 @@ class Draw extends XFAObject {
|
||||
|
||||
fixDimensions(this);
|
||||
|
||||
if ((this.w === "" || this.h === "") && this.value) {
|
||||
let marginH = 0;
|
||||
let marginV = 0;
|
||||
if (this.margin) {
|
||||
marginH = this.margin.leftInset + this.margin.rightInset;
|
||||
marginV = this.margin.topInset + this.margin.bottomInset;
|
||||
}
|
||||
|
||||
const maxWidth = this.w === "" ? availableSpace.width : this.w;
|
||||
const fontFinder = this[$globalData].fontFinder;
|
||||
let font = this.font;
|
||||
if (!font) {
|
||||
let parent = this[$getParent]();
|
||||
while (!(parent instanceof Template)) {
|
||||
if (parent.font) {
|
||||
font = parent.font;
|
||||
break;
|
||||
}
|
||||
parent = parent[$getParent]();
|
||||
}
|
||||
}
|
||||
|
||||
let height = null;
|
||||
let width = null;
|
||||
if (
|
||||
this.value.exData &&
|
||||
this.value.exData[$content] &&
|
||||
this.value.exData.contentType === "text/html"
|
||||
) {
|
||||
const res = layoutText(
|
||||
this.value.exData[$content],
|
||||
font,
|
||||
fontFinder,
|
||||
maxWidth
|
||||
);
|
||||
width = res.width;
|
||||
height = res.height;
|
||||
} else {
|
||||
const text = this.value[$text]();
|
||||
if (text) {
|
||||
const res = layoutText(text, font, fontFinder, maxWidth);
|
||||
width = res.width;
|
||||
height = res.height;
|
||||
}
|
||||
}
|
||||
|
||||
if (width !== null && this.w === "") {
|
||||
this.w = width + marginH;
|
||||
}
|
||||
|
||||
if (height !== null && this.h === "") {
|
||||
this.h = height + marginV;
|
||||
}
|
||||
// If at least one dimension is missing and we've a text
|
||||
// then we can guess it in laying out the text.
|
||||
const savedW = this.w;
|
||||
const savedH = this.h;
|
||||
const [w, h] = layoutNode(this, availableSpace);
|
||||
if (w && this.w === "") {
|
||||
this.w = w;
|
||||
}
|
||||
if (h && this.h === "") {
|
||||
this.h = h;
|
||||
}
|
||||
|
||||
setFirstUnsplittable(this);
|
||||
if (!checkDimensions(this, availableSpace)) {
|
||||
this.w = savedW;
|
||||
this.h = savedH;
|
||||
return HTMLResult.FAILURE;
|
||||
}
|
||||
unsetFirstUnsplittable(this);
|
||||
@ -1673,6 +1667,8 @@ class Draw extends XFAObject {
|
||||
|
||||
const value = this.value ? this.value[$toHTML](availableSpace).html : null;
|
||||
if (value === null) {
|
||||
this.w = savedW;
|
||||
this.h = savedH;
|
||||
return HTMLResult.success(createWrapper(this, html), bbox);
|
||||
}
|
||||
|
||||
@ -1714,6 +1710,9 @@ class Draw extends XFAObject {
|
||||
}
|
||||
}
|
||||
|
||||
this.w = savedW;
|
||||
this.h = savedH;
|
||||
|
||||
return HTMLResult.success(createWrapper(this, html), bbox);
|
||||
}
|
||||
}
|
||||
@ -2460,10 +2459,66 @@ class Field extends XFAObject {
|
||||
return HTMLResult.EMPTY;
|
||||
}
|
||||
|
||||
if (this.caption) {
|
||||
// Maybe we already tried to layout this field with
|
||||
// another availableSpace, so to avoid to use the cached
|
||||
// value just delete it.
|
||||
delete this.caption[$extra];
|
||||
}
|
||||
|
||||
const caption = this.caption
|
||||
? this.caption[$toHTML](availableSpace).html
|
||||
: null;
|
||||
const savedW = this.w;
|
||||
const savedH = this.h;
|
||||
if (this.w === "" || this.h === "") {
|
||||
let marginH = 0;
|
||||
let marginV = 0;
|
||||
if (this.margin) {
|
||||
marginH = this.margin.leftInset + this.margin.rightInset;
|
||||
marginV = this.margin.topInset + this.margin.bottomInset;
|
||||
}
|
||||
|
||||
let width = null;
|
||||
let height = null;
|
||||
|
||||
if (this.caption) {
|
||||
[width, height] = this.caption[$getExtra](availableSpace);
|
||||
if (this.ui instanceof CheckButton) {
|
||||
switch (this.caption.placement) {
|
||||
case "left":
|
||||
case "right":
|
||||
case "inline":
|
||||
width += this.ui.size;
|
||||
break;
|
||||
case "top":
|
||||
case "bottom":
|
||||
height += this.ui.size;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (width && this.w === "") {
|
||||
this.w = Math.min(
|
||||
this.maxW <= 0 ? Infinity : this.maxW,
|
||||
Math.max(this.minW, width + marginH)
|
||||
);
|
||||
}
|
||||
|
||||
if (height && this.h === "") {
|
||||
this.h = Math.min(
|
||||
this.maxH <= 0 ? Infinity : this.maxH,
|
||||
Math.max(this.minH, height + marginV)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fixDimensions(this);
|
||||
|
||||
setFirstUnsplittable(this);
|
||||
if (!checkDimensions(this, availableSpace)) {
|
||||
this.w = savedW;
|
||||
this.h = savedH;
|
||||
return HTMLResult.FAILURE;
|
||||
}
|
||||
unsetFirstUnsplittable(this);
|
||||
@ -2559,12 +2614,14 @@ class Field extends XFAObject {
|
||||
}
|
||||
}
|
||||
|
||||
const caption = this.caption ? this.caption[$toHTML]().html : null;
|
||||
if (!caption) {
|
||||
if (ui.attributes.class) {
|
||||
// Even if no caption this class will help to center the ui.
|
||||
ui.attributes.class.push("xfaLeft");
|
||||
}
|
||||
this.w = savedW;
|
||||
this.h = savedH;
|
||||
|
||||
return HTMLResult.success(createWrapper(this, html), bbox);
|
||||
}
|
||||
|
||||
@ -2605,6 +2662,8 @@ class Field extends XFAObject {
|
||||
break;
|
||||
}
|
||||
|
||||
this.w = savedW;
|
||||
this.h = savedH;
|
||||
return HTMLResult.success(createWrapper(this, html), bbox);
|
||||
}
|
||||
}
|
||||
|
@ -15,17 +15,30 @@
|
||||
|
||||
import { selectFont } from "./fonts.js";
|
||||
|
||||
const WIDTH_FACTOR = 1.2;
|
||||
const HEIGHT_FACTOR = 1.2;
|
||||
const WIDTH_FACTOR = 1.05;
|
||||
|
||||
class FontInfo {
|
||||
constructor(xfaFont, fontFinder) {
|
||||
constructor(xfaFont, margin, lineHeight, fontFinder) {
|
||||
this.lineHeight = lineHeight;
|
||||
this.paraMargin = margin || {
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
};
|
||||
|
||||
if (!xfaFont) {
|
||||
[this.pdfFont, this.xfaFont] = this.defaultFont(fontFinder);
|
||||
return;
|
||||
}
|
||||
|
||||
this.xfaFont = xfaFont;
|
||||
this.xfaFont = {
|
||||
typeface: xfaFont.typeface,
|
||||
posture: xfaFont.posture,
|
||||
weight: xfaFont.weight,
|
||||
size: xfaFont.size,
|
||||
letterSpacing: xfaFont.letterSpacing,
|
||||
};
|
||||
const typeface = fontFinder.find(xfaFont.typeface);
|
||||
if (!typeface) {
|
||||
[this.pdfFont, this.xfaFont] = this.defaultFont(fontFinder);
|
||||
@ -54,6 +67,7 @@ class FontInfo {
|
||||
posture: "normal",
|
||||
weight: "normal",
|
||||
size: 10,
|
||||
letterSpacing: 0,
|
||||
};
|
||||
return [pdfFont, xfaFont];
|
||||
}
|
||||
@ -63,29 +77,60 @@ class FontInfo {
|
||||
posture: "normal",
|
||||
weight: "normal",
|
||||
size: 10,
|
||||
letterSpacing: 0,
|
||||
};
|
||||
return [null, xfaFont];
|
||||
}
|
||||
}
|
||||
|
||||
class FontSelector {
|
||||
constructor(defaultXfaFont, fontFinder) {
|
||||
constructor(
|
||||
defaultXfaFont,
|
||||
defaultParaMargin,
|
||||
defaultLineHeight,
|
||||
fontFinder
|
||||
) {
|
||||
this.fontFinder = fontFinder;
|
||||
this.stack = [new FontInfo(defaultXfaFont, fontFinder)];
|
||||
this.stack = [
|
||||
new FontInfo(
|
||||
defaultXfaFont,
|
||||
defaultParaMargin,
|
||||
defaultLineHeight,
|
||||
fontFinder
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
pushFont(xfaFont) {
|
||||
pushData(xfaFont, margin, lineHeight) {
|
||||
const lastFont = this.stack[this.stack.length - 1];
|
||||
for (const name of ["typeface", "posture", "weight", "size"]) {
|
||||
for (const name of [
|
||||
"typeface",
|
||||
"posture",
|
||||
"weight",
|
||||
"size",
|
||||
"letterSpacing",
|
||||
]) {
|
||||
if (!xfaFont[name]) {
|
||||
xfaFont[name] = lastFont.xfaFont[name];
|
||||
}
|
||||
}
|
||||
|
||||
const fontInfo = new FontInfo(xfaFont, this.fontFinder);
|
||||
for (const name of ["top", "bottom", "left", "right"]) {
|
||||
if (isNaN(margin[name])) {
|
||||
margin[name] = lastFont.paraMargin[name];
|
||||
}
|
||||
}
|
||||
|
||||
const fontInfo = new FontInfo(
|
||||
xfaFont,
|
||||
margin,
|
||||
lineHeight || lastFont.lineHeight,
|
||||
this.fontFinder
|
||||
);
|
||||
if (!fontInfo.pdfFont) {
|
||||
fontInfo.pdfFont = lastFont.pdfFont;
|
||||
}
|
||||
|
||||
this.stack.push(fontInfo);
|
||||
}
|
||||
|
||||
@ -102,19 +147,30 @@ class FontSelector {
|
||||
* Compute a text area dimensions based on font metrics.
|
||||
*/
|
||||
class TextMeasure {
|
||||
constructor(defaultXfaFont, fonts) {
|
||||
constructor(defaultXfaFont, defaultParaMargin, defaultLineHeight, fonts) {
|
||||
this.glyphs = [];
|
||||
this.fontSelector = new FontSelector(defaultXfaFont, fonts);
|
||||
this.fontSelector = new FontSelector(
|
||||
defaultXfaFont,
|
||||
defaultParaMargin,
|
||||
defaultLineHeight,
|
||||
fonts
|
||||
);
|
||||
this.extraHeight = 0;
|
||||
}
|
||||
|
||||
pushFont(xfaFont) {
|
||||
return this.fontSelector.pushFont(xfaFont);
|
||||
pushData(xfaFont, margin, lineHeight) {
|
||||
this.fontSelector.pushData(xfaFont, margin, lineHeight);
|
||||
}
|
||||
|
||||
popFont(xfaFont) {
|
||||
return this.fontSelector.popFont();
|
||||
}
|
||||
|
||||
addPara() {
|
||||
const lastFont = this.fontSelector.topFont();
|
||||
this.extraHeight += lastFont.paraMargin.top + lastFont.paraMargin.bottom;
|
||||
}
|
||||
|
||||
addString(str) {
|
||||
if (!str) {
|
||||
return;
|
||||
@ -123,8 +179,11 @@ class TextMeasure {
|
||||
const lastFont = this.fontSelector.topFont();
|
||||
const fontSize = lastFont.xfaFont.size;
|
||||
if (lastFont.pdfFont) {
|
||||
const letterSpacing = lastFont.xfaFont.letterSpacing;
|
||||
const pdfFont = lastFont.pdfFont;
|
||||
const lineHeight = Math.round(Math.max(1, pdfFont.lineHeight) * fontSize);
|
||||
const lineHeight =
|
||||
lastFont.lineHeight ||
|
||||
Math.round(Math.max(1, pdfFont.lineHeight) * fontSize);
|
||||
const scale = fontSize / 1000;
|
||||
|
||||
for (const line of str.split(/[\u2029\n]/)) {
|
||||
@ -133,7 +192,7 @@ class TextMeasure {
|
||||
|
||||
for (const glyph of glyphs) {
|
||||
this.glyphs.push([
|
||||
glyph.width * scale,
|
||||
glyph.width * scale + letterSpacing,
|
||||
lineHeight,
|
||||
glyph.unicode === " ",
|
||||
false,
|
||||
@ -218,9 +277,9 @@ class TextMeasure {
|
||||
}
|
||||
|
||||
width = Math.max(width, currentLineWidth);
|
||||
height += currentLineHeight;
|
||||
height += currentLineHeight + this.extraHeight;
|
||||
|
||||
return { width: WIDTH_FACTOR * width, height: HEIGHT_FACTOR * height };
|
||||
return { width: WIDTH_FACTOR * width, height };
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -193,25 +193,81 @@ class XhtmlObject extends XmlObject {
|
||||
}
|
||||
}
|
||||
|
||||
[$pushGlyphs](measure) {
|
||||
[$pushGlyphs](measure, mustPop = true) {
|
||||
const xfaFont = Object.create(null);
|
||||
const margin = {
|
||||
top: NaN,
|
||||
bottom: NaN,
|
||||
left: NaN,
|
||||
right: NaN,
|
||||
};
|
||||
let lineHeight = null;
|
||||
for (const [key, value] of this.style
|
||||
.split(";")
|
||||
.map(s => s.split(":", 2))) {
|
||||
if (!key.startsWith("font-")) {
|
||||
continue;
|
||||
}
|
||||
if (key === "font-family") {
|
||||
xfaFont.typeface = stripQuotes(value);
|
||||
} else if (key === "font-size") {
|
||||
xfaFont.size = getMeasurement(value);
|
||||
} else if (key === "font-weight") {
|
||||
xfaFont.weight = value;
|
||||
} else if (key === "font-style") {
|
||||
xfaFont.posture = value;
|
||||
switch (key) {
|
||||
case "font-family":
|
||||
xfaFont.typeface = stripQuotes(value);
|
||||
break;
|
||||
case "font-size":
|
||||
xfaFont.size = getMeasurement(value);
|
||||
break;
|
||||
case "font-weight":
|
||||
xfaFont.weight = value;
|
||||
break;
|
||||
case "font-style":
|
||||
xfaFont.posture = value;
|
||||
break;
|
||||
case "letter-spacing":
|
||||
xfaFont.letterSpacing = getMeasurement(value);
|
||||
break;
|
||||
case "margin":
|
||||
const values = value.split(/ \t/).map(x => getMeasurement(x));
|
||||
switch (values.length) {
|
||||
case 1:
|
||||
margin.top =
|
||||
margin.bottom =
|
||||
margin.left =
|
||||
margin.right =
|
||||
values[0];
|
||||
break;
|
||||
case 2:
|
||||
margin.top = margin.bottom = values[0];
|
||||
margin.left = margin.right = values[1];
|
||||
break;
|
||||
case 3:
|
||||
margin.top = values[0];
|
||||
margin.bottom = values[2];
|
||||
margin.left = margin.right = values[1];
|
||||
break;
|
||||
case 4:
|
||||
margin.top = values[0];
|
||||
margin.left = values[1];
|
||||
margin.bottom = values[2];
|
||||
margin.right = values[3];
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case "margin-top":
|
||||
margin.top = getMeasurement(value);
|
||||
break;
|
||||
case "margin-bottom":
|
||||
margin.bottom = getMeasurement(value);
|
||||
break;
|
||||
case "margin-left":
|
||||
margin.left = getMeasurement(value);
|
||||
break;
|
||||
case "margin-right":
|
||||
margin.right = getMeasurement(value);
|
||||
break;
|
||||
case "line-height":
|
||||
lineHeight = getMeasurement(value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
measure.pushFont(xfaFont);
|
||||
|
||||
measure.pushData(xfaFont, margin, lineHeight);
|
||||
|
||||
if (this[$content]) {
|
||||
measure.addString(this[$content]);
|
||||
} else {
|
||||
@ -223,7 +279,10 @@ class XhtmlObject extends XmlObject {
|
||||
child[$pushGlyphs](measure);
|
||||
}
|
||||
}
|
||||
measure.popFont();
|
||||
|
||||
if (mustPop) {
|
||||
measure.popFont();
|
||||
}
|
||||
}
|
||||
|
||||
[$toHTML](availableSpace) {
|
||||
@ -377,8 +436,10 @@ class P extends XhtmlObject {
|
||||
}
|
||||
|
||||
[$pushGlyphs](measure) {
|
||||
super[$pushGlyphs](measure);
|
||||
super[$pushGlyphs](measure, /* mustPop = */ false);
|
||||
measure.addString("\n");
|
||||
measure.addPara();
|
||||
measure.popFont();
|
||||
}
|
||||
|
||||
[$text]() {
|
||||
|
@ -190,6 +190,8 @@
|
||||
|
||||
.xfaRich {
|
||||
white-space: pre-wrap;
|
||||
width: auto;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.xfaImage {
|
||||
@ -199,11 +201,6 @@
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.xfaRich {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.xfaLrTb,
|
||||
.xfaRlTb,
|
||||
.xfaTb {
|
||||
|
Loading…
x
Reference in New Issue
Block a user