1
0
Fork 0
mirror of https://github.com/mozilla/pdf.js.git synced 2025-04-28 23:28:16 +02:00

XFA - Add the possibily to layout and measure text

- some containers doesn't always have their 2 dimensions and those dimensions re based on contents;
  - so in order to measure text, we must get the glyph widths (for the xfa fonts) before starting the layout;
  - implement a word-wrap algorithm;
  - handle font change during text layout.
This commit is contained in:
Calixte Denizet 2021-06-14 19:16:42 +02:00
parent 335d4cb2fc
commit 8eeb7ab4a3
12 changed files with 416 additions and 91 deletions

View file

@ -18,18 +18,14 @@ import {
$getParent,
$getSubformParent,
$nodeName,
$pushGlyphs,
$toStyle,
XFAObject,
} from "./xfa_object.js";
import { getMeasurement } from "./utils.js";
import { TextMeasure } from "./text.js";
import { warn } from "../../shared/util.js";
const wordNonWordRegex = new RegExp(
"([\\p{N}\\p{L}\\p{M}]+)|([^\\p{N}\\p{L}\\p{M}]+)",
"gu"
);
const wordFirstRegex = new RegExp("^[\\p{N}\\p{L}\\p{M}]", "u");
function measureToString(m) {
if (typeof m === "string") {
return "0px";
@ -192,65 +188,15 @@ const converters = {
},
};
function layoutText(text, fontSize, space) {
// Try to guess width and height for the given text in taking into
// account the space where the text should fit.
// The computed dimensions are just an overestimation.
// TODO: base this estimation on real metrics.
let width = 0;
let height = 0;
let totalWidth = 0;
const lineHeight = fontSize * 1.5;
const averageCharSize = fontSize * 0.4;
const maxCharOnLine = Math.floor(space.width / averageCharSize);
const chunks = text.match(wordNonWordRegex);
let treatedChars = 0;
let i = 0;
let chunk = chunks[0];
while (chunk) {
const w = chunk.length * averageCharSize;
if (width + w <= space.width) {
width += w;
treatedChars += chunk.length;
chunk = chunks[i++];
continue;
}
if (!wordFirstRegex.test(chunk) || chunk.length > maxCharOnLine) {
const numOfCharOnLine = Math.floor(
(space.width - width) / averageCharSize
);
chunk = chunk.slice(numOfCharOnLine);
treatedChars += numOfCharOnLine;
if (height + lineHeight > space.height) {
return { width: 0, height: 0, splitPos: treatedChars };
}
totalWidth = Math.max(width, totalWidth);
width = 0;
height += lineHeight;
continue;
}
if (height + lineHeight > space.height) {
return { width: 0, height: 0, splitPos: treatedChars };
}
totalWidth = Math.max(width, totalWidth);
width = w;
height += lineHeight;
chunk = chunks[i++];
function layoutText(text, xfaFont, fonts, width) {
const measure = new TextMeasure(xfaFont, fonts);
if (typeof text === "string") {
measure.addString(text);
} else {
text[$pushGlyphs](measure);
}
if (totalWidth === 0) {
totalWidth = width;
}
if (totalWidth !== 0) {
height += lineHeight;
}
return { width: totalWidth, height, splitPos: -1 };
return measure.compute(width);
}
function computeBbox(node, html, availableSpace) {