XFA - Fix text positions (bug 1718741)

- font line height is taken into account by acrobat when it isn't with masterpdfeditor: I extracted a font from a pdf, modified some ascent/descent properties thanks to ttx and the reinjected the font in the pdf: only Acrobat is taken it into account. So in this patch, line heights for some substituted fonts are added.
  - it seems that Acrobat is using a line height of 1.2 when the line height in the font is not enough (it's the only way I found to fix correctly bug 1718741).
   - don't use flex in wrapper container (which was causing an horizontal overflow in the above bug).
   - consequently, the above fixes introduced a lot of small regressions, so in order to see real improvements on reftests, I fixed the regressions in this patch:
     - replace margin by padding in some case where padding is a part of a container dimensions;
     - remove some flex display: some containers are wrongly sized when rendered;
     - set letter-spacing to 0.01px: it helps to be sure that text is not broken because of not enough width in Firefox.
This commit is contained in:
Calixte Denizet 2021-07-09 17:29:21 +02:00
parent 0afc785c7d
commit 58e1f51688
15 changed files with 220 additions and 103 deletions

View File

@ -81,6 +81,7 @@ const CalibriBoldFactors = [
0.95794, 0.95794, 0.82616, 0.86513, 0.85162, 0.85162, 0.85162, 0.85162, 0.95794, 0.95794, 0.82616, 0.86513, 0.85162, 0.85162, 0.85162, 0.85162,
0.91133, 0.85162, 0.79492, 0.79492, 0.79492, 0.79492, 0.91133, 0.79109, 0.91133, 0.85162, 0.79492, 0.79492, 0.79492, 0.79492, 0.91133, 0.79109,
]; ];
const CalibriBoldLineHeight = 1.2207;
// Factors to rescale LiberationSans-BoldItalic.ttf to have the same // Factors to rescale LiberationSans-BoldItalic.ttf to have the same
// metrics as calibriz.ttf. // metrics as calibriz.ttf.
@ -152,6 +153,7 @@ const CalibriBoldItalicFactors = [
0.84548, 0.84548, 0.91133, 0.84548, 0.79492, 0.79492, 0.79492, 0.79492, 0.84548, 0.84548, 0.91133, 0.84548, 0.79492, 0.79492, 0.79492, 0.79492,
0.91133, 0.74081, 0.91133, 0.74081,
]; ];
const CalibriBoldItalicLineHeight = 1.2207;
// Factors to rescale LiberationSans-Italic.ttf to have the same // Factors to rescale LiberationSans-Italic.ttf to have the same
// metrics as calibrii.ttf. // metrics as calibrii.ttf.
@ -221,6 +223,7 @@ const CalibriItalicFactors = [
0.84153, 0.89453, 0.89453, 0.89453, 0.89453, 0.91133, 0.89453, 0.79004, 0.84153, 0.89453, 0.89453, 0.89453, 0.89453, 0.91133, 0.89453, 0.79004,
0.79004, 0.79004, 0.79004, 0.91133, 0.75026, 0.79004, 0.79004, 0.79004, 0.91133, 0.75026,
]; ];
const CalibriItalicLineHeight = 1.2207;
// Factors to rescale LiberationSans-Regular.ttf to have the same // Factors to rescale LiberationSans-Regular.ttf to have the same
// metrics as calibri.ttf. // metrics as calibri.ttf.
@ -291,10 +294,15 @@ const CalibriRegularFactors = [
0.83969, 0.90527, 0.90527, 0.90527, 0.90527, 0.91133, 0.90527, 0.79004, 0.83969, 0.90527, 0.90527, 0.90527, 0.90527, 0.91133, 0.90527, 0.79004,
0.79004, 0.79004, 0.79004, 0.91133, 0.78848, 0.79004, 0.79004, 0.79004, 0.91133, 0.78848,
]; ];
const CalibriRegularLineHeight = 1.2207;
export { export {
CalibriBoldFactors, CalibriBoldFactors,
CalibriBoldItalicFactors, CalibriBoldItalicFactors,
CalibriBoldItalicLineHeight,
CalibriBoldLineHeight,
CalibriItalicFactors, CalibriItalicFactors,
CalibriItalicLineHeight,
CalibriRegularFactors, CalibriRegularFactors,
CalibriRegularLineHeight,
}; };

View File

@ -3888,6 +3888,7 @@ class PartialEvaluator {
const standardFontName = getXfaFontName(fontName.name); const standardFontName = getXfaFontName(fontName.name);
if (standardFontName) { if (standardFontName) {
cssFontInfo.fontFamily = `${cssFontInfo.fontFamily}-PdfJS-XFA`; cssFontInfo.fontFamily = `${cssFontInfo.fontFamily}-PdfJS-XFA`;
cssFontInfo.lineHeight = standardFontName.lineHeight || null;
glyphScaleFactors = standardFontName.factors || null; glyphScaleFactors = standardFontName.factors || null;
fontFile = await this.fetchStandardFontData(standardFontName.name); fontFile = await this.fetchStandardFontData(standardFontName.name);
isInternalFont = !!fontFile; isInternalFont = !!fontFile;

View File

@ -2548,7 +2548,12 @@ class Font {
this.ascent = metricsOverride.ascent / metricsOverride.unitsPerEm; this.ascent = metricsOverride.ascent / metricsOverride.unitsPerEm;
this.descent = metricsOverride.descent / metricsOverride.unitsPerEm; this.descent = metricsOverride.descent / metricsOverride.unitsPerEm;
this.lineGap = metricsOverride.lineGap / metricsOverride.unitsPerEm; this.lineGap = metricsOverride.lineGap / metricsOverride.unitsPerEm;
this.lineHeight = this.ascent - this.descent + this.lineGap;
if (this.cssFontInfo && this.cssFontInfo.lineHeight) {
this.lineHeight = this.cssFontInfo.lineHeight;
} else {
this.lineHeight = this.ascent - this.descent + this.lineGap;
}
// The 'post' table has glyphs names. // The 'post' table has glyphs names.
if (tables.post) { if (tables.post) {

View File

@ -94,6 +94,7 @@ const HelveticaBoldFactors = [
1.00022, 1.00022, 0.99973, 0.9993, 0.99973, 0.99973, 0.99973, 0.99973, 1.00022, 1.00022, 0.99973, 0.9993, 0.99973, 0.99973, 0.99973, 0.99973,
0.99973, 0.99973, 1, 1, 1, 1, 0.99973, 0.99902, 0.99973, 0.99973, 1, 1, 1, 1, 0.99973, 0.99902,
]; ];
const HelveticaBoldLineHeight = 1.2;
// Factors to rescale LiberationSans-BoldItalic.ttf to have the same // Factors to rescale LiberationSans-BoldItalic.ttf to have the same
// metrics as NimbusSans-BoldItalic.otf. // metrics as NimbusSans-BoldItalic.otf.
@ -176,6 +177,7 @@ const HelveticaBoldItalicFactors = [
0.99973, 1.00065, 0.99973, 0.99973, 0.99973, 0.99973, 0.99973, 0.99973, 1, 1, 0.99973, 1.00065, 0.99973, 0.99973, 0.99973, 0.99973, 0.99973, 0.99973, 1, 1,
1, 1, 0.99973, 1.00061, 1, 1, 0.99973, 1.00061,
]; ];
const HelveticaBoldItalicLineHeight = 1.35;
// Factors to rescale LiberationSans-Italic.ttf to have the same // Factors to rescale LiberationSans-Italic.ttf to have the same
// metrics as NimbusSans-Italic.otf. // metrics as NimbusSans-Italic.otf.
@ -256,6 +258,7 @@ const HelveticaItalicFactors = [
0.99973, 0.99973, 1, 0.99977, 0.99977, 0.99977, 0.99977, 0.99977, 1, 1.0005, 0.99973, 0.99973, 1, 0.99977, 0.99977, 0.99977, 0.99977, 0.99977, 1, 1.0005,
1, 1, 1, 1, 0.99973, 1, 1, 1, 1, 1, 0.99973, 0.99918, 1, 1, 1, 1, 0.99973, 1, 1, 1, 1, 1, 0.99973, 0.99918,
]; ];
const HelveticaItalicLineHeight = 1.35;
// Factors to rescale LiberationSans-Regular.ttf to have the same // Factors to rescale LiberationSans-Regular.ttf to have the same
// metrics as NimbusSans-Regular.otf. // metrics as NimbusSans-Regular.otf.
@ -336,10 +339,15 @@ const HelveticaRegularFactors = [
0.99977, 0.99977, 0.99977, 1, 1.00055, 1, 1, 1, 1, 0.99973, 1, 1, 1, 1, 1, 0.99977, 0.99977, 0.99977, 1, 1.00055, 1, 1, 1, 1, 0.99973, 1, 1, 1, 1, 1,
0.99973, 1.00019, 0.99973, 1.00019,
]; ];
const HelveticaRegularLineHeight = 1.2;
export { export {
HelveticaBoldFactors, HelveticaBoldFactors,
HelveticaBoldItalicFactors, HelveticaBoldItalicFactors,
HelveticaBoldItalicLineHeight,
HelveticaBoldLineHeight,
HelveticaItalicFactors, HelveticaItalicFactors,
HelveticaItalicLineHeight,
HelveticaRegularFactors, HelveticaRegularFactors,
HelveticaRegularLineHeight,
}; };

View File

@ -77,6 +77,7 @@ const MyriadProBoldFactors = [
0.97579, 0.97579, 0.97579, 0.9332, 1.05993, 0.94039, 0.94039, 0.94039, 0.97579, 0.97579, 0.97579, 0.9332, 1.05993, 0.94039, 0.94039, 0.94039,
0.94039, 0.99793, 0.94039, 0.938, 0.938, 0.938, 0.938, 0.99793, 0.95776, 0.94039, 0.99793, 0.94039, 0.938, 0.938, 0.938, 0.938, 0.99793, 0.95776,
]; ];
const MyriadProBoldLineHeight = 1.2;
// Factors to rescale LiberationSans-BoldItalic.ttf to have the same // Factors to rescale LiberationSans-BoldItalic.ttf to have the same
// metrics as MyriadPro-BoldIt.otf. // metrics as MyriadPro-BoldIt.otf.
@ -143,6 +144,7 @@ const MyriadProBoldItalicFactors = [
0.89544, 1.0051, 0.89364, 0.89364, 0.89364, 0.89364, 0.97276, 0.89364, 0.9, 0.89544, 1.0051, 0.89364, 0.89364, 0.89364, 0.89364, 0.97276, 0.89364, 0.9,
0.9, 0.9, 0.9, 0.97276, 0.86842, 0.9, 0.9, 0.9, 0.97276, 0.86842,
]; ];
const MyriadProBoldItalicLineHeight = 1.2;
// Factors to rescale LiberationSans-Italic.ttf to have the same // Factors to rescale LiberationSans-Italic.ttf to have the same
// metrics as MyriadPro-It.otf. // metrics as MyriadPro-It.otf.
@ -208,6 +210,7 @@ const MyriadProItalicFactors = [
0.979, 0.979, 0.979, 0.979, 0.882, 0.93559, 0.882, 0.882, 0.882, 0.882, 0.979, 0.979, 0.979, 0.979, 0.882, 0.93559, 0.882, 0.882, 0.882, 0.882,
0.88465, 0.882, 0.83, 0.83, 0.83, 0.83, 0.88465, 0.84596, 0.88465, 0.882, 0.83, 0.83, 0.83, 0.83, 0.88465, 0.84596,
]; ];
const MyriadProItalicLineHeight = 1.2;
// Factors to rescale LiberationSans-Regular.ttf to have the same // Factors to rescale LiberationSans-Regular.ttf to have the same
// metrics as MyriadPro-Regular.otf. // metrics as MyriadPro-Regular.otf.
@ -273,10 +276,15 @@ const MyriadProRegularFactors = [
1.01915, 0.926, 0.96705, 0.942, 0.942, 0.942, 0.942, 0.92241, 0.942, 0.856, 1.01915, 0.926, 0.96705, 0.942, 0.942, 0.942, 0.942, 0.92241, 0.942, 0.856,
0.856, 0.856, 0.856, 0.92241, 0.92761, 0.856, 0.856, 0.856, 0.92241, 0.92761,
]; ];
const MyriadProRegularLineHeight = 1.2;
export { export {
MyriadProBoldFactors, MyriadProBoldFactors,
MyriadProBoldItalicFactors, MyriadProBoldItalicFactors,
MyriadProBoldItalicLineHeight,
MyriadProBoldLineHeight,
MyriadProItalicFactors, MyriadProItalicFactors,
MyriadProItalicLineHeight,
MyriadProRegularFactors, MyriadProRegularFactors,
MyriadProRegularLineHeight,
}; };

View File

@ -81,6 +81,7 @@ const SegoeuiBoldFactors = [
1.02511, 0.99298, 1.07237, 0.96752, 0.96752, 0.96752, 0.96752, 1.03424, 1.02511, 0.99298, 1.07237, 0.96752, 0.96752, 0.96752, 0.96752, 1.03424,
0.96752, 0.95801, 0.95801, 0.95801, 0.95801, 1.03424, 1.0106, 0.96752, 0.95801, 0.95801, 0.95801, 0.95801, 1.03424, 1.0106,
]; ];
const SegoeuiBoldLineHeight = 1.33008;
// Factors to rescale LiberationSans-BoldItalic.ttf to have the same // Factors to rescale LiberationSans-BoldItalic.ttf to have the same
// metrics as segoeuiz.ttf. // metrics as segoeuiz.ttf.
@ -151,6 +152,7 @@ const SegoeuiBoldItalicFactors = [
0.96752, 0.96752, 1.036, 0.96752, 0.97168, 0.97168, 0.97168, 0.97168, 1.036, 0.96752, 0.96752, 1.036, 0.96752, 0.97168, 0.97168, 0.97168, 0.97168, 1.036,
0.95134, 0.95134,
]; ];
const SegoeuiBoldItalicLineHeight = 1.33008;
// Factors to rescale LiberationSans-Italic.ttf to have the same // Factors to rescale LiberationSans-Italic.ttf to have the same
// metrics as segoeuii.ttf. // metrics as segoeuii.ttf.
@ -221,6 +223,7 @@ const SegoeuiItalicFactors = [
0.96777, 0.96777, 0.96777, 0.96927, 0.96777, 0.9043, 0.9043, 0.9043, 0.9043, 0.96777, 0.96777, 0.96777, 0.96927, 0.96777, 0.9043, 0.9043, 0.9043, 0.9043,
0.96927, 0.95364, 0.96927, 0.95364,
]; ];
const SegoeuiItalicLineHeight = 1.33008;
// Factors to rescale LiberationSans-Regular.ttf to have the same // Factors to rescale LiberationSans-Regular.ttf to have the same
// metrics as segoeui.ttf. // metrics as segoeui.ttf.
@ -291,10 +294,15 @@ const SegoeuiRegularFactors = [
1.00068, 0.91797, 0.99346, 0.96777, 0.96777, 0.96777, 0.96777, 0.96927, 1.00068, 0.91797, 0.99346, 0.96777, 0.96777, 0.96777, 0.96777, 0.96927,
0.96777, 0.9043, 0.9043, 0.9043, 0.9043, 0.96927, 1.00221, 0.96777, 0.9043, 0.9043, 0.9043, 0.9043, 0.96927, 1.00221,
]; ];
const SegoeuiRegularLineHeight = 1.33008;
export { export {
SegoeuiBoldFactors, SegoeuiBoldFactors,
SegoeuiBoldItalicFactors, SegoeuiBoldItalicFactors,
SegoeuiBoldItalicLineHeight,
SegoeuiBoldLineHeight,
SegoeuiItalicFactors, SegoeuiItalicFactors,
SegoeuiItalicLineHeight,
SegoeuiRegularFactors, SegoeuiRegularFactors,
SegoeuiRegularLineHeight,
}; };

View File

@ -396,6 +396,11 @@ function toStyle(node, ...names) {
if (value === null) { if (value === null) {
continue; continue;
} }
if (converters.hasOwnProperty(name)) {
converters[name](node, style);
continue;
}
if (value instanceof XFAObject) { if (value instanceof XFAObject) {
const newStyle = value[$toStyle](); const newStyle = value[$toStyle]();
if (newStyle) { if (newStyle) {
@ -403,11 +408,6 @@ function toStyle(node, ...names) {
} else { } else {
warn(`(DEBUG) - XFA - style for ${name} not implemented yet`); warn(`(DEBUG) - XFA - style for ${name} not implemented yet`);
} }
continue;
}
if (converters.hasOwnProperty(name)) {
converters[name](node, style);
} }
} }
return style; return style;
@ -560,6 +560,44 @@ function isPrintOnly(node) {
); );
} }
function setPara(node, nodeStyle, value) {
if (value.attributes.class && value.attributes.class.includes("xfaRich")) {
if (nodeStyle) {
if (node.h === "") {
nodeStyle.height = "auto";
}
if (node.w === "") {
nodeStyle.width = "auto";
}
}
if (node.para) {
// By definition exData are external data so para
// has no effect on it.
const valueStyle = value.attributes.style;
valueStyle.display = "flex";
valueStyle.flexDirection = "column";
switch (node.para.vAlign) {
case "top":
valueStyle.justifyContent = "start";
break;
case "bottom":
valueStyle.justifyContent = "end";
break;
case "middle":
valueStyle.justifyContent = "center";
break;
}
const paraStyle = node.para[$toStyle]();
for (const [key, val] of Object.entries(paraStyle)) {
if (!(key in valueStyle)) {
valueStyle[key] = val;
}
}
}
}
}
function setFontFamily(xfaFont, fontFinder, style) { function setFontFamily(xfaFont, fontFinder, style) {
const name = stripQuotes(xfaFont.typeface); const name = stripQuotes(xfaFont.typeface);
const typeface = fontFinder.find(name); const typeface = fontFinder.find(name);
@ -574,9 +612,12 @@ function setFontFamily(xfaFont, fontFinder, style) {
// Already something so don't overwrite. // Already something so don't overwrite.
return; return;
} }
const pdfFont = selectFont(xfaFont, typeface); const pdfFont = selectFont(xfaFont, typeface);
if (pdfFont && pdfFont.lineHeight > 0) { if (pdfFont && pdfFont.lineHeight > 0) {
style.lineHeight = pdfFont.lineHeight; style.lineHeight = Math.max(1.2, pdfFont.lineHeight);
} else {
style.lineHeight = 1.2;
} }
} }
} }
@ -593,5 +634,6 @@ export {
setAccess, setAccess,
setFontFamily, setFontFamily,
setMinMaxDimensions, setMinMaxDimensions,
setPara,
toStyle, toStyle,
}; };

View File

@ -80,6 +80,7 @@ import {
setAccess, setAccess,
setFontFamily, setFontFamily,
setMinMaxDimensions, setMinMaxDimensions,
setPara,
toStyle, toStyle,
} from "./html_utils.js"; } from "./html_utils.js";
import { import {
@ -134,12 +135,20 @@ function* getContainedChildren(node) {
function valueToHtml(value) { function valueToHtml(value) {
return HTMLResult.success({ return HTMLResult.success({
name: "span", name: "div",
attributes: { attributes: {
class: ["xfaRich"], class: ["xfaRich"],
style: Object.create(null), style: Object.create(null),
}, },
value, children: [
{
name: "span",
attributes: {
style: Object.create(null),
},
value,
},
],
}); });
} }
@ -225,6 +234,15 @@ function handleBreak(node) {
return true; return true;
} }
function handleOverflow(node, extraNode, space) {
const root = node[$getTemplateRoot]();
const saved = root[$extra].noLayoutFailure;
root[$extra].noLayoutFailure = true;
const res = extraNode[$toHTML](space);
node[$addHTML](res.html, res.bbox);
root[$extra].noLayoutFailure = saved;
}
class AppearanceFilter extends StringObject { class AppearanceFilter extends StringObject {
constructor(attributes) { constructor(attributes) {
super(TEMPLATE_NS_ID, "appearanceFilter"); super(TEMPLATE_NS_ID, "appearanceFilter");
@ -973,7 +991,7 @@ class Caption extends XFAObject {
children.push(value); children.push(value);
} }
const style = toStyle(this, "font", "margin", "para", "visibility"); const style = toStyle(this, "font", "margin", "visibility");
switch (this.placement) { switch (this.placement) {
case "left": case "left":
case "right": case "right":
@ -989,6 +1007,8 @@ class Caption extends XFAObject {
break; break;
} }
setPara(this, null, value);
this.reserve = savedReserve; this.reserve = savedReserve;
return HTMLResult.success({ return HTMLResult.success({
@ -1654,6 +1674,11 @@ class Draw extends XFAObject {
setMinMaxDimensions(this, style); setMinMaxDimensions(this, style);
if (style.margin) {
style.padding = style.margin;
delete style.margin;
}
const classNames = ["xfaDraw"]; const classNames = ["xfaDraw"];
if (this.font) { if (this.font) {
classNames.push("xfaFont"); classNames.push("xfaFont");
@ -1688,42 +1713,7 @@ class Draw extends XFAObject {
} }
html.children.push(value); html.children.push(value);
if (value.attributes.class && value.attributes.class.includes("xfaRich")) { setPara(this, style, value);
if (this.h === "") {
style.height = "auto";
}
if (this.w === "") {
style.width = "auto";
}
if (this.para) {
// By definition exData are external data so para
// has no effect on it.
attributes.style.display = "flex";
attributes.style.flexDirection = "column";
switch (this.para.vAlign) {
case "top":
attributes.style.justifyContent = "start";
break;
case "bottom":
attributes.style.justifyContent = "end";
break;
case "middle":
attributes.style.justifyContent = "center";
break;
}
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;
}
}
}
}
}
this.w = savedW; this.w = savedW;
this.h = savedH; this.h = savedH;
@ -2510,20 +2500,21 @@ class Field extends XFAObject {
width = w; width = w;
height = h; height = h;
if (this.ui instanceof CheckButton) { if (this.ui.checkButton) {
switch (this.caption.placement) { switch (this.caption.placement) {
case "left": case "left":
case "right": case "right":
case "inline": case "inline":
width += this.ui.size; width += this.ui.checkButton.size;
break; break;
case "top": case "top":
case "bottom": case "bottom":
height += this.ui.size; height += this.ui.checkButton.size;
break; break;
} }
} }
} }
if (width && this.w === "") { if (width && this.w === "") {
this.w = Math.min( this.w = Math.min(
this.maxW <= 0 ? Infinity : this.maxW, this.maxW <= 0 ? Infinity : this.maxW,
@ -2579,6 +2570,11 @@ class Field extends XFAObject {
class: classNames, class: classNames,
}; };
if (style.margin) {
style.padding = style.margin;
delete style.margin;
}
setAccess(this, classNames); setAccess(this, classNames);
if (this.name) { if (this.name) {
@ -2623,7 +2619,7 @@ class Field extends XFAObject {
} else { } else {
const htmlValue = this.value[$toHTML]().html; const htmlValue = this.value[$toHTML]().html;
if (htmlValue !== null) { if (htmlValue !== null) {
value = htmlValue.value; value = htmlValue.children[0].value;
} }
} }
if (this.ui.textEdit && this.value.text && this.value.text.maxChars) { if (this.ui.textEdit && this.value.text && this.value.text.maxChars) {
@ -2652,6 +2648,9 @@ class Field extends XFAObject {
} }
if (this.ui.button) { if (this.ui.button) {
if (style.padding) {
delete style.padding;
}
if (caption.name === "div") { if (caption.name === "div") {
caption.name = "span"; caption.name = "span";
} }
@ -2910,11 +2909,7 @@ class Font extends XFAObject {
// TODO: overlinePeriod // TODO: overlinePeriod
style.fontStyle = this.posture; style.fontStyle = this.posture;
style.fontSize = measureToString(0.99 * this.size);
const fontSize = measureToString(0.99 * this.size);
if (fontSize !== "10px") {
style.fontSize = fontSize;
}
setFontFamily(this, this[$globalData].fontFinder, style); setFontFamily(this, this[$globalData].fontFinder, style);
@ -3513,8 +3508,14 @@ class Overflow extends XFAObject {
const parent = this[$getParent](); const parent = this[$getParent]();
const root = this[$getTemplateRoot](); const root = this[$getTemplateRoot]();
const target = root[$searchNode](this.target, parent); const target = root[$searchNode](this.target, parent);
const leader = root[$searchNode](this.leader, parent);
const trailer = root[$searchNode](this.trailer, parent);
this[$extra] = { this[$extra] = {
target: (target && target[0]) || null, target: (target && target[0]) || null,
leader: (leader && leader[0]) || null,
trailer: (trailer && trailer[0]) || null,
addLeader: false,
addTrailer: false,
}; };
} }
return this[$extra]; return this[$extra];
@ -3834,16 +3835,16 @@ class Para extends XFAObject {
[$toStyle]() { [$toStyle]() {
const style = toStyle(this, "hAlign"); const style = toStyle(this, "hAlign");
if (this.marginLeft !== "") { if (this.marginLeft !== "") {
style.marginLeft = measureToString(this.marginLeft); style.paddingLeft = measureToString(this.marginLeft);
} }
if (this.marginRight !== "") { if (this.marginRight !== "") {
style.marginRight = measureToString(this.marginRight); style.paddingight = measureToString(this.marginRight);
} }
if (this.spaceAbove !== "") { if (this.spaceAbove !== "") {
style.marginTop = measureToString(this.spaceAbove); style.paddingTop = measureToString(this.spaceAbove);
} }
if (this.spaceBelow !== "") { if (this.spaceBelow !== "") {
style.marginBottom = measureToString(this.spaceBelow); style.paddingBottom = measureToString(this.spaceBelow);
} }
if (this.textIndent !== "") { if (this.textIndent !== "") {
style.textIndent = measureToString(this.textIndent); style.textIndent = measureToString(this.textIndent);
@ -4658,6 +4659,14 @@ class Subform extends XFAObject {
attributes.xfaName = this.name; attributes.xfaName = this.name;
} }
if (this.overflow) {
const overflowExtra = this.overflow[$getExtra]();
if (overflowExtra.addLeader) {
overflowExtra.addLeader = false;
handleOverflow(this, overflowExtra.leader, availableSpace);
}
}
const maxRun = const maxRun =
this.layout === "lr-tb" || this.layout === "rl-tb" this.layout === "lr-tb" || this.layout === "rl-tb"
? MAX_ATTEMPTS_FOR_LRTB_LAYOUT ? MAX_ATTEMPTS_FOR_LRTB_LAYOUT
@ -4699,6 +4708,14 @@ class Subform extends XFAObject {
return HTMLResult.FAILURE; return HTMLResult.FAILURE;
} }
if (this.overflow) {
const overflowExtra = this.overflow[$getExtra]();
if (overflowExtra.addTrailer) {
overflowExtra.addTrailer = false;
handleOverflow(this, overflowExtra.trailer, availableSpace);
}
}
let marginH = 0; let marginH = 0;
let marginV = 0; let marginV = 0;
if (this.margin) { if (this.margin) {
@ -5095,24 +5112,13 @@ class Template extends XFAObject {
const node = this[$extra].overflowNode; const node = this[$extra].overflowNode;
this[$extra].overflowNode = null; this[$extra].overflowNode = null;
const overflowExtra = node[$getExtra]();
const target = overflowExtra.target;
overflowExtra.addLeader = overflowExtra.leader !== null;
overflowExtra.addTrailer = overflowExtra.trailer !== null;
flush(i); flush(i);
if (node.leader) {
leader = this[$searchNode](node.leader, node[$getParent]());
leader = leader ? leader[0] : null;
}
if (node.trailer) {
trailer = this[$searchNode](node.trailer, node[$getParent]());
trailer = trailer ? trailer[0] : null;
}
let target = null;
if (node.target) {
target = this[$searchNode](node.target, node[$getParent]());
target = target ? target[0] : target;
}
i = Infinity; i = Infinity;
if (target instanceof PageArea) { if (target instanceof PageArea) {
// We must stop the contentAreas filling and go to the next page. // We must stop the contentAreas filling and go to the next page.

View File

@ -15,7 +15,7 @@
import { selectFont } from "./fonts.js"; import { selectFont } from "./fonts.js";
const WIDTH_FACTOR = 1.05; const WIDTH_FACTOR = 1.01;
class FontInfo { class FontInfo {
constructor(xfaFont, margin, lineHeight, fontFinder) { constructor(xfaFont, margin, lineHeight, fontFinder) {
@ -183,7 +183,7 @@ class TextMeasure {
const pdfFont = lastFont.pdfFont; const pdfFont = lastFont.pdfFont;
const lineHeight = const lineHeight =
lastFont.lineHeight || lastFont.lineHeight ||
Math.round(Math.max(1, pdfFont.lineHeight) * fontSize); Math.ceil(Math.max(1.2, pdfFont.lineHeight) * fontSize);
const scale = fontSize / 1000; const scale = fontSize / 1000;
for (const line of str.split(/[\u2029\n]/)) { for (const line of str.split(/[\u2029\n]/)) {

View File

@ -84,7 +84,13 @@ const StyleMapping = new Map([
], ],
["xfa-spacerun", ""], ["xfa-spacerun", ""],
["xfa-tab-stops", ""], ["xfa-tab-stops", ""],
["font-size", value => measureToString(getMeasurement(value))], [
"font-size",
(value, original) => {
value = original.fontSize = getMeasurement(value);
return measureToString(0.99 * value);
},
],
["letter-spacing", value => measureToString(getMeasurement(value))], ["letter-spacing", value => measureToString(getMeasurement(value))],
["line-height", value => measureToString(getMeasurement(value))], ["line-height", value => measureToString(getMeasurement(value))],
["margin", value => measureToString(getMeasurement(value))], ["margin", value => measureToString(getMeasurement(value))],
@ -104,6 +110,7 @@ function mapStyle(styleStr, fontFinder) {
if (!styleStr) { if (!styleStr) {
return style; return style;
} }
const original = Object.create(null);
for (const [key, value] of styleStr.split(";").map(s => s.split(":", 2))) { for (const [key, value] of styleStr.split(";").map(s => s.split(":", 2))) {
const mapping = StyleMapping.get(key); const mapping = StyleMapping.get(key);
if (mapping === "") { if (mapping === "") {
@ -114,7 +121,7 @@ function mapStyle(styleStr, fontFinder) {
if (typeof mapping === "string") { if (typeof mapping === "string") {
newValue = mapping; newValue = mapping;
} else { } else {
newValue = mapping(value, fontFinder); newValue = mapping(value, original);
} }
} }
if (key.endsWith("scale")) { if (key.endsWith("scale")) {
@ -135,6 +142,7 @@ function mapStyle(styleStr, fontFinder) {
typeface: style.fontFamily, typeface: style.fontFamily,
weight: style.fontWeight || "normal", weight: style.fontWeight || "normal",
posture: style.fontStyle || "normal", posture: style.fontStyle || "normal",
size: original.fontSize || 0,
}, },
fontFinder, fontFinder,
style style

View File

@ -16,14 +16,22 @@
import { import {
CalibriBoldFactors, CalibriBoldFactors,
CalibriBoldItalicFactors, CalibriBoldItalicFactors,
CalibriBoldItalicLineHeight,
CalibriBoldLineHeight,
CalibriItalicFactors, CalibriItalicFactors,
CalibriItalicLineHeight,
CalibriRegularFactors, CalibriRegularFactors,
CalibriRegularLineHeight,
} from "./calibri_factors.js"; } from "./calibri_factors.js";
import { import {
HelveticaBoldFactors, HelveticaBoldFactors,
HelveticaBoldItalicFactors, HelveticaBoldItalicFactors,
HelveticaBoldItalicLineHeight,
HelveticaBoldLineHeight,
HelveticaItalicFactors, HelveticaItalicFactors,
HelveticaItalicLineHeight,
HelveticaRegularFactors, HelveticaRegularFactors,
HelveticaRegularLineHeight,
} from "./helvetica_factors.js"; } from "./helvetica_factors.js";
import { import {
LiberationSansBoldItalicWidths, LiberationSansBoldItalicWidths,
@ -34,14 +42,22 @@ import {
import { import {
MyriadProBoldFactors, MyriadProBoldFactors,
MyriadProBoldItalicFactors, MyriadProBoldItalicFactors,
MyriadProBoldItalicLineHeight,
MyriadProBoldLineHeight,
MyriadProItalicFactors, MyriadProItalicFactors,
MyriadProItalicLineHeight,
MyriadProRegularFactors, MyriadProRegularFactors,
MyriadProRegularLineHeight,
} from "./myriadpro_factors.js"; } from "./myriadpro_factors.js";
import { import {
SegoeuiBoldFactors, SegoeuiBoldFactors,
SegoeuiBoldItalicFactors, SegoeuiBoldItalicFactors,
SegoeuiBoldItalicLineHeight,
SegoeuiBoldLineHeight,
SegoeuiItalicFactors, SegoeuiItalicFactors,
SegoeuiItalicLineHeight,
SegoeuiRegularFactors, SegoeuiRegularFactors,
SegoeuiRegularLineHeight,
} from "./segoeui_factors.js"; } from "./segoeui_factors.js";
import { getLookupTableFactory } from "./core_utils.js"; import { getLookupTableFactory } from "./core_utils.js";
import { normalizeFontName } from "./fonts_utils.js"; import { normalizeFontName } from "./fonts_utils.js";
@ -51,21 +67,25 @@ const getXFAFontMap = getLookupTableFactory(function (t) {
name: "LiberationSans-Regular", name: "LiberationSans-Regular",
factors: MyriadProRegularFactors, factors: MyriadProRegularFactors,
baseWidths: LiberationSansRegularWidths, baseWidths: LiberationSansRegularWidths,
lineHeight: MyriadProRegularLineHeight,
}; };
t["MyriadPro-Bold"] = { t["MyriadPro-Bold"] = {
name: "LiberationSans-Bold", name: "LiberationSans-Bold",
factors: MyriadProBoldFactors, factors: MyriadProBoldFactors,
baseWidths: LiberationSansBoldWidths, baseWidths: LiberationSansBoldWidths,
lineHeight: MyriadProBoldLineHeight,
}; };
t["MyriadPro-It"] = { t["MyriadPro-It"] = {
name: "LiberationSans-Italic", name: "LiberationSans-Italic",
factors: MyriadProItalicFactors, factors: MyriadProItalicFactors,
baseWidths: LiberationSansItalicWidths, baseWidths: LiberationSansItalicWidths,
lineHeight: MyriadProItalicLineHeight,
}; };
t["MyriadPro-BoldIt"] = { t["MyriadPro-BoldIt"] = {
name: "LiberationSans-BoldItalic", name: "LiberationSans-BoldItalic",
factors: MyriadProBoldItalicFactors, factors: MyriadProBoldItalicFactors,
baseWidths: LiberationSansBoldItalicWidths, baseWidths: LiberationSansBoldItalicWidths,
lineHeight: MyriadProBoldItalicLineHeight,
}; };
t.ArialMT = t.ArialMT =
t.Arial = t.Arial =
@ -90,61 +110,73 @@ const getXFAFontMap = getLookupTableFactory(function (t) {
name: "LiberationSans-Regular", name: "LiberationSans-Regular",
factors: CalibriRegularFactors, factors: CalibriRegularFactors,
baseWidths: LiberationSansRegularWidths, baseWidths: LiberationSansRegularWidths,
lineHeight: CalibriRegularLineHeight,
}; };
t["Calibri-Bold"] = { t["Calibri-Bold"] = {
name: "LiberationSans-Bold", name: "LiberationSans-Bold",
factors: CalibriBoldFactors, factors: CalibriBoldFactors,
baseWidths: LiberationSansBoldWidths, baseWidths: LiberationSansBoldWidths,
lineHeight: CalibriBoldLineHeight,
}; };
t["Calibri-Italic"] = { t["Calibri-Italic"] = {
name: "LiberationSans-Italic", name: "LiberationSans-Italic",
factors: CalibriItalicFactors, factors: CalibriItalicFactors,
baseWidths: LiberationSansItalicWidths, baseWidths: LiberationSansItalicWidths,
lineHeight: CalibriItalicLineHeight,
}; };
t["Calibri-BoldItalic"] = { t["Calibri-BoldItalic"] = {
name: "LiberationSans-BoldItalic", name: "LiberationSans-BoldItalic",
factors: CalibriBoldItalicFactors, factors: CalibriBoldItalicFactors,
baseWidths: LiberationSansBoldItalicWidths, baseWidths: LiberationSansBoldItalicWidths,
lineHeight: CalibriBoldItalicLineHeight,
}; };
t["Segoeui-Regular"] = { t["Segoeui-Regular"] = {
name: "LiberationSans-Regular", name: "LiberationSans-Regular",
factors: SegoeuiRegularFactors, factors: SegoeuiRegularFactors,
baseWidths: LiberationSansRegularWidths, baseWidths: LiberationSansRegularWidths,
lineHeight: SegoeuiRegularLineHeight,
}; };
t["Segoeui-Bold"] = { t["Segoeui-Bold"] = {
name: "LiberationSans-Bold", name: "LiberationSans-Bold",
factors: SegoeuiBoldFactors, factors: SegoeuiBoldFactors,
baseWidths: LiberationSansBoldWidths, baseWidths: LiberationSansBoldWidths,
lineHeight: SegoeuiBoldLineHeight,
}; };
t["Segoeui-Italic"] = { t["Segoeui-Italic"] = {
name: "LiberationSans-Italic", name: "LiberationSans-Italic",
factors: SegoeuiItalicFactors, factors: SegoeuiItalicFactors,
baseWidths: LiberationSansItalicWidths, baseWidths: LiberationSansItalicWidths,
lineHeight: SegoeuiItalicLineHeight,
}; };
t["Segoeui-BoldItalic"] = { t["Segoeui-BoldItalic"] = {
name: "LiberationSans-BoldItalic", name: "LiberationSans-BoldItalic",
factors: SegoeuiBoldItalicFactors, factors: SegoeuiBoldItalicFactors,
baseWidths: LiberationSansBoldItalicWidths, baseWidths: LiberationSansBoldItalicWidths,
lineHeight: SegoeuiBoldItalicLineHeight,
}; };
t["Helvetica-Regular"] = { t["Helvetica-Regular"] = {
name: "LiberationSans-Regular", name: "LiberationSans-Regular",
factors: HelveticaRegularFactors, factors: HelveticaRegularFactors,
baseWidths: LiberationSansRegularWidths, baseWidths: LiberationSansRegularWidths,
lineHeight: HelveticaRegularLineHeight,
}; };
t["Helvetica-Bold"] = { t["Helvetica-Bold"] = {
name: "LiberationSans-Bold", name: "LiberationSans-Bold",
factors: HelveticaBoldFactors, factors: HelveticaBoldFactors,
baseWidths: LiberationSansBoldWidths, baseWidths: LiberationSansBoldWidths,
lineHeight: HelveticaBoldLineHeight,
}; };
t["Helvetica-Italic"] = { t["Helvetica-Italic"] = {
name: "LiberationSans-Italic", name: "LiberationSans-Italic",
factors: HelveticaItalicFactors, factors: HelveticaItalicFactors,
baseWidths: LiberationSansItalicWidths, baseWidths: LiberationSansItalicWidths,
lineHeight: HelveticaItalicLineHeight,
}; };
t["Helvetica-BoldItalic"] = { t["Helvetica-BoldItalic"] = {
name: "LiberationSans-BoldItalic", name: "LiberationSans-BoldItalic",
factors: HelveticaBoldItalicFactors, factors: HelveticaBoldItalicFactors,
baseWidths: LiberationSansBoldItalicWidths, baseWidths: LiberationSansBoldItalicWidths,
lineHeight: HelveticaBoldItalicLineHeight,
}; };
}); });

View File

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

View File

@ -960,6 +960,14 @@
"enableXfa": true, "enableXfa": true,
"type": "eq" "type": "eq"
}, },
{ "id": "xfa_bug1718741",
"file": "pdfs/xfa_bug1718741.pdf",
"md5": "1b80f8287cdbf9a67e4bff8be20b1bbd",
"link": true,
"rounds": 1,
"enableXfa": true,
"type": "eq"
},
{ "id": "xfa_bug1718670_1", { "id": "xfa_bug1718670_1",
"file": "pdfs/xfa_bug1718670_1.pdf", "file": "pdfs/xfa_bug1718670_1.pdf",
"md5": "06745be56a89acd80e5bdeddabb7cb7b", "md5": "06745be56a89acd80e5bdeddabb7cb7b",

View File

@ -126,7 +126,7 @@ describe("XFAFactory", function () {
fontStyle: "normal", fontStyle: "normal",
fontWeight: "normal", fontWeight: "normal",
fontSize: "6.93px", fontSize: "6.93px",
margin: "1px 4px 2px 3px", padding: "1px 4px 2px 3px",
verticalAlign: "2px", verticalAlign: "2px",
}); });

View File

@ -41,7 +41,7 @@
font-style: inherit; font-style: inherit;
font-weight: inherit; font-weight: inherit;
font-kerning: inherit; font-kerning: inherit;
letter-spacing: inherit; letter-spacing: -0.01px;
text-align: inherit; text-align: inherit;
text-decoration: inherit; text-decoration: inherit;
vertical-align: inherit; vertical-align: inherit;
@ -118,13 +118,9 @@
pointer-events: none; pointer-events: none;
} }
.xfaWrapper {
display: flex;
align-items: stretch;
}
.xfaWrapped { .xfaWrapped {
flex: 1 1 auto; width: 100%;
height: 100%;
} }
.xfaTextfield, .xfaTextfield,
@ -169,8 +165,8 @@
.xfaRich { .xfaRich {
white-space: pre-wrap; white-space: pre-wrap;
width: auto; width: 100%;
height: auto; height: 100%;
} }
.xfaImage { .xfaImage {
@ -188,12 +184,6 @@
align-items: stretch; align-items: stretch;
} }
.xfaLr,
.xfaRl,
.xfaTb > div {
flex: 1 1 auto;
}
.xfaLr { .xfaLr {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
@ -229,20 +219,12 @@
align-items: stretch; align-items: stretch;
} }
.xfaTable > div {
flex: 1 1 auto;
}
.xfaTable .xfaRow { .xfaTable .xfaRow {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
align-items: stretch; align-items: stretch;
} }
.xfaTable .xfaRow > div {
flex: 1 1 auto;
}
.xfaTable .xfaRlRow { .xfaTable .xfaRlRow {
display: flex; display: flex;
flex-direction: row-reverse; flex-direction: row-reverse;