mirror of
https://github.com/mozilla/pdf.js.git
synced 2025-04-28 23:28:16 +02:00
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
5 changed files with 359 additions and 99 deletions
|
@ -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 };
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue