Skip to content

Commit

Permalink
Add lang attribute to canvas element
Browse files Browse the repository at this point in the history
Fixes issue mozilla#16843.
In certain cases, the text layer was misaligned
due to a difference between the `lang` attribute
of the viewer and the canvas. This commit addresses
the problem by adding the `lang` attribute to the canvas.

The issue was caused because PDF.js uses serif/sans-serif
fonts to generate the text layer and relies on system fonts.
The difference in the `lang` attribute led to different fonts
being picked, causing the misalignment.
  • Loading branch information
Aditi-1400 committed May 21, 2024
1 parent 59637c1 commit 9348060
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 6 deletions.
18 changes: 12 additions & 6 deletions src/display/text_layer.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,13 @@ const MAX_TEXT_DIVS_TO_RENDER = 100000;
const DEFAULT_FONT_SIZE = 30;
const DEFAULT_FONT_ASCENT = 0.8;
const ascentCache = new Map();
let _canvasContext = null;
const _canvasContexts = new Map();
const pendingTextLayers = new Set();

function getCtx(lang = null) {
if (!_canvasContext) {
lang = lang || "";
let canvasContext = _canvasContexts.get(lang);
if (!canvasContext) {
// We don't use an OffscreenCanvas here because we use serif/sans serif
// fonts with it and they depends on the locale.
// In Firefox, the <html> element get a lang attribute that depends on what
Expand All @@ -78,19 +80,23 @@ function getCtx(lang = null) {
// OffscreenCanvas.
const canvas = document.createElement("canvas");
canvas.className = "hiddenCanvasElement";
canvas.lang = lang;
document.body.append(canvas);
_canvasContext = canvas.getContext("2d", { alpha: false });
canvasContext = canvas.getContext("2d", { alpha: false });
_canvasContexts.set(lang, canvasContext);
}

return _canvasContext;
return canvasContext;
}

function cleanupTextLayer() {
if (pendingTextLayers.size > 0) {
return;
}
_canvasContext?.canvas.remove();
_canvasContext = null;
for (const canvasContext of _canvasContexts.values()) {
canvasContext.canvas.remove();
}
_canvasContexts.clear();
}

function getAscent(fontFamily, lang) {
Expand Down
40 changes: 40 additions & 0 deletions test/integration/text_layer_spec.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -290,4 +290,44 @@ describe("Text layer", () => {
});
});
});
describe("Text layer is aligned with the canvas layer", () => {
let pages;
beforeAll(async () => {
pages = await loadAndWait(
"Misaligned Text Layer.pdf",
`.page[data-page-number = "1"] .endOfContent`
);
});
afterAll(async () => {
await closePages(pages);
});

it("The width of text-span is correct", async () => {
await Promise.all(
pages.map(async ([browserName, page]) => {
const lines = [
"exceeding 1000 mm in Kyushu district, southwestern Japan, in",
"early July 2020. Especially, an elongated and stagnated mesoscale",
"convective system formed around the Kuma River in central",
"Kyushu district produced localized heavy rainfall with precipita-",
"tion amounts larger than 600 mm in 13 hours. Characteristics of",
];
const expectedWidth = 227;
const expectedWidthChrome = 242;
// In Chrome, an extra space character is included at the end
// of the text-span resulting in difference in widths
for (const line of lines) {
const pageNumber = 1;
const spanRect = await getSpanRectFromText(page, pageNumber, line);
const actualWidth = Math.round(spanRect.width);
if (browserName === "chrome") {
expect(actualWidth).toBeCloseTo(expectedWidthChrome, 1);
} else {
expect(actualWidth).toBeCloseTo(expectedWidth, 1);
}
}
})
);
});
});
});
Binary file added web/Misaligned Text Layer.pdf
Binary file not shown.

0 comments on commit 9348060

Please sign in to comment.