Skip to content

Commit

Permalink
[api-minor] Simplify the TextLayer.#getAscent fallback (PR 12896 fo…
Browse files Browse the repository at this point in the history
…llow-up)

At the time of PR 12896 the `fontBoundingBox{Ascent, Descent}` properties were not yet available by default in Fírefox, however that's no longer the case since Firefox 116; please see https://bugzilla.mozilla.org/show_bug.cgi?id=1801198.

Hence this patch which replaces the "full" fallback with a warning and uses the `ascent`/`descent` values from the fonts in the PDF document (as we did previously). Obviously the TextLayer won't look as good in that case, but it's a simpler and shorter solution.
  • Loading branch information
Snuffleupagus committed Feb 1, 2025
1 parent b48717a commit c8be02f
Showing 1 changed file with 21 additions and 46 deletions.
67 changes: 21 additions & 46 deletions src/display/text_layer.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ import { setLayerDimensions } from "./display_utils.js";

const MAX_TEXT_DIVS_TO_RENDER = 100000;
const DEFAULT_FONT_SIZE = 30;
const DEFAULT_FONT_ASCENT = 0.8;

class TextLayer {
#capability = Promise.withResolvers();
Expand Down Expand Up @@ -332,7 +331,7 @@ class TextLayer {
fontFamily = TextLayer.fontFamilyMap.get(fontFamily) || fontFamily;
const fontHeight = Math.hypot(tx[2], tx[3]);
const fontAscent =
fontHeight * TextLayer.#getAscent(fontFamily, this.#lang);
fontHeight * TextLayer.#getAscent(fontFamily, style, this.#lang);

let left, top;
if (angle === 0) {
Expand Down Expand Up @@ -523,7 +522,7 @@ class TextLayer {
div.remove();
}

static #getAscent(fontFamily, lang) {
static #getAscent(fontFamily, style, lang) {
const cachedAscent = this.#ascentCache.get(fontFamily);
if (cachedAscent) {
return cachedAscent;
Expand All @@ -534,55 +533,31 @@ class TextLayer {
this.#ensureCtxFont(ctx, DEFAULT_FONT_SIZE, fontFamily);
const metrics = ctx.measureText("");

// Both properties aren't available by default in Firefox.
let ascent = metrics.fontBoundingBoxAscent;
let descent = Math.abs(metrics.fontBoundingBoxDescent);
if (ascent) {
const ratio = ascent / (ascent + descent);
this.#ascentCache.set(fontFamily, ratio);
const ascent = metrics.fontBoundingBoxAscent;
const descent = Math.abs(metrics.fontBoundingBoxDescent);

ctx.canvas.width = ctx.canvas.height = 0;
return ratio;
}
ctx.canvas.width = ctx.canvas.height = 0;
let ratio = 0.8; // DEFAULT_FONT_ASCENT

// Try basic heuristic to guess ascent/descent.
// Draw a g with baseline at 0,0 and then get the line
// number where a pixel has non-null red component (starting
// from bottom).
ctx.strokeStyle = "red";
ctx.clearRect(0, 0, DEFAULT_FONT_SIZE, DEFAULT_FONT_SIZE);
ctx.strokeText("g", 0, 0);
let pixels = ctx.getImageData(
0,
0,
DEFAULT_FONT_SIZE,
DEFAULT_FONT_SIZE
).data;
descent = 0;
for (let i = pixels.length - 1 - 3; i >= 0; i -= 4) {
if (pixels[i] > 0) {
descent = Math.ceil(i / 4 / DEFAULT_FONT_SIZE);
break;
if (ascent) {
ratio = ascent / (ascent + descent);
} else {
if (
(typeof PDFJSDev !== "undefined" && PDFJSDev.test("MOZCENTRAL")) ||
FeatureTest.platform.isFirefox
) {
warn(
"Enable the `dom.textMetrics.fontBoundingBox.enabled` preference " +
"in `about:config` to improve TextLayer rendering."
);
}
}

// Draw an A with baseline at 0,DEFAULT_FONT_SIZE and then get the line
// number where a pixel has non-null red component (starting
// from top).
ctx.clearRect(0, 0, DEFAULT_FONT_SIZE, DEFAULT_FONT_SIZE);
ctx.strokeText("A", 0, DEFAULT_FONT_SIZE);
pixels = ctx.getImageData(0, 0, DEFAULT_FONT_SIZE, DEFAULT_FONT_SIZE).data;
ascent = 0;
for (let i = 0, ii = pixels.length; i < ii; i += 4) {
if (pixels[i] > 0) {
ascent = DEFAULT_FONT_SIZE - Math.floor(i / 4 / DEFAULT_FONT_SIZE);
break;
if (style.ascent) {
ratio = style.ascent;
} else if (style.descent) {
ratio = 1 + style.descent;
}
}

ctx.canvas.width = ctx.canvas.height = 0;

const ratio = ascent ? ascent / (ascent + descent) : DEFAULT_FONT_ASCENT;
this.#ascentCache.set(fontFamily, ratio);
return ratio;
}
Expand Down

0 comments on commit c8be02f

Please sign in to comment.