1
0
Fork 0
mirror of https://github.com/mozilla/pdf.js.git synced 2025-04-19 06:38:07 +02:00

Merge pull request #18283 from nicolo-ribaudo/ignore-browser-min-font-size

Override the minimum font size when rendering the text layer
This commit is contained in:
Tim van der Meij 2024-06-25 15:57:15 +02:00 committed by GitHub
commit 11cb3a8e11
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 79 additions and 3 deletions

View file

@ -83,6 +83,8 @@ class TextLayer {
static #canvasContexts = new Map();
static #minFontSize = null;
static #pendingTextLayers = new Set();
/**
@ -120,6 +122,8 @@ class TextLayer {
this.#pageWidth = pageWidth;
this.#pageHeight = pageHeight;
TextLayer.#ensureMinFontSizeComputed();
setLayerDimensions(container, viewport);
// Always clean-up the temporary canvas once rendering is no longer pending.
@ -242,7 +246,7 @@ class TextLayer {
if (this.#disableProcessItems) {
return;
}
this.#layoutTextParams.ctx ||= TextLayer.#getCtx(this.#lang);
this.#layoutTextParams.ctx ??= TextLayer.#getCtx(this.#lang);
const textDivs = this.#textDivs,
textContentItemsStr = this.#textContentItemsStr;
@ -326,7 +330,11 @@ class TextLayer {
divStyle.left = `${scaleFactorStr}${left.toFixed(2)}px)`;
divStyle.top = `${scaleFactorStr}${top.toFixed(2)}px)`;
}
divStyle.fontSize = `${scaleFactorStr}${fontHeight.toFixed(2)}px)`;
// We multiply the font size by #minFontSize, and then #layout will
// scale the element by 1/#minFontSize. This allows us to effectively
// ignore the minimum font size enforced by the browser, so that the text
// layer <span>s can always match the size of the text in the canvas.
divStyle.fontSize = `${scaleFactorStr}${(TextLayer.#minFontSize * fontHeight).toFixed(2)}px)`;
divStyle.fontFamily = fontFamily;
textDivProperties.fontSize = fontHeight;
@ -388,7 +396,12 @@ class TextLayer {
#layout(params) {
const { div, properties, ctx, prevFontSize, prevFontFamily } = params;
const { style } = div;
let transform = "";
if (TextLayer.#minFontSize > 1) {
transform = `scale(${1 / TextLayer.#minFontSize})`;
}
if (properties.canvasWidth !== 0 && properties.hasText) {
const { fontFamily } = style;
const { canvasWidth, fontSize } = properties;
@ -403,7 +416,7 @@ class TextLayer {
const { width } = ctx.measureText(div.textContent);
if (width > 0) {
transform = `scaleX(${(canvasWidth * this.#scale) / width})`;
transform = `scaleX(${(canvasWidth * this.#scale) / width}) ${transform}`;
}
}
if (properties.angle !== 0) {
@ -456,6 +469,26 @@ class TextLayer {
return canvasContext;
}
/**
* Compute the minimum font size enforced by the browser.
*/
static #ensureMinFontSizeComputed() {
if (this.#minFontSize !== null) {
return;
}
const div = document.createElement("div");
div.style.opacity = 0;
div.style.lineHeight = 1;
div.style.fontSize = "1px";
div.textContent = "X";
document.body.append(div);
// In `display:block` elements contain a single line of text,
// the height matches the line height (which, when set to 1,
// matches the actual font size).
this.#minFontSize = div.getBoundingClientRect().height;
div.remove();
}
static #getAscent(fontFamily, lang) {
const cachedAscent = this.#ascentCache.get(fontFamily);
if (cachedAscent) {

View file

@ -296,4 +296,47 @@ describe("Text layer", () => {
});
});
});
describe("when the browser enforces a minimum font size", () => {
let browser;
let page;
beforeAll(async () => {
// Only testing in Firefox because, while Chrome has a setting similar to
// font.minimum-size.x-western, it is not exposed through its API.
browser = await startBrowser({
browserName: "firefox",
startUrl: "",
extraPrefsFirefox: { "font.minimum-size.x-western": 40 },
});
page = await browser.newPage();
await page.goto(
`${global.integrationBaseUrl}?file=/test/pdfs/tracemonkey.pdf#zoom=100`
);
await page.bringToFront();
await page.waitForSelector(
`.page[data-page-number = "1"] .endOfContent`,
{ timeout: 0 }
);
});
afterAll(async () => {
await closeSinglePage(page);
await browser.close();
});
it("renders spans with the right size", async () => {
const rect = await getSpanRectFromText(
page,
1,
"Dynamic languages such as JavaScript are more difficult to com-"
);
// The difference between `a` and `b`, as a percentage of the lower one
const getPercentDiff = (a, b) => Math.max(a, b) / Math.min(a, b) - 1;
expect(getPercentDiff(rect.width, 315)).toBeLessThan(0.03);
expect(getPercentDiff(rect.height, 12)).toBeLessThan(0.03);
});
});
});