Skip to content

Measure text without a language in the document's language (issue 22258) - #22261

Open
yhay81 wants to merge 2 commits into
mozilla:masterfrom
yhay81:text-layer-empty-lang
Open

yhay81 wants to merge 2 commits into
mozilla:masterfrom
yhay81:text-layer-empty-lang

Conversation

@yhay81

@yhay81 yhay81 commented Oct 20, 2026

Copy link
Copy Markdown

Fixes #22258.

For a PDF without /Lang, TextLayer.#getCtx gives its measuring canvas lang="", which declares the language unknown instead of inheriting the document's one (as intended by #17476), while the spans keep inheriting it. When the generic font families resolve to other fonts for the two, every span is scaled by the wrong ratio: with <html lang="ja">, spans ended 12–15% past their glyphs in Chromium and WebKit, and on a Japanese system with <html lang="en">, 11% short in Firefox.

This leaves the attribute off when the text content has no language. With it, the spans' widths match their items' in all three browsers, on the display API and in the viewer with and without a lang on its root element.

The unit test checks that a text layer without a language creates a measuring canvas without a lang attribute, next to one with a language.

🤖 Generated with Claude Code

For a PDF without /Lang, `TextLayer.#getCtx` gave its measuring canvas
`lang=""`. An empty lang attribute does not inherit the document's
language but declares it unknown, while the text layer's spans keep
inheriting the document's language. The generic font families can then
resolve to different fonts for the canvas and the spans, so every span is
scaled by the wrong ratio: with `<html lang="ja">`, spans ended 12-15%
past their glyphs in Chromium and WebKit, and in Firefox on a Japanese
system with `<html lang="en">`, 11% short of them.

PR 17476 appended the canvas to the document precisely so that it would
inherit the document's language, and PR 17770 then set it to the text
content's language, which is right when the PDF has one. Without one,
leave the attribute off.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

Viewer preview

Commit 0d13991 (build logs).

Viewer Build Preview
Modern (gulp generic) ✅ not published
Legacy (gulp generic-legacy) ✅ not published

🔒 A user with write access must approve this commit with the viewer-preview label to publish the viewers.

@codecov-commenter

codecov-commenter commented Oct 21, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 90.44%. Comparing base (33734f1) to head (0d13991).
⚠️ Report is 15 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master   #22261      +/-   ##
==========================================
- Coverage   90.44%   90.44%   -0.01%     
==========================================
  Files         277      277              
  Lines       68277    68278       +1     
==========================================
- Hits        61756    61753       -3     
- Misses       6521     6525       +4     
Flag Coverage Δ
browsertest 66.30% <100.00%> (-0.02%) ⬇️
fonttest 8.97% <ø> (ø)
integrationtest 69.38% <100.00%> (-0.02%) ⬇️
unittest 60.77% <100.00%> (-0.01%) ⬇️
unittestcli 58.52% <0.00%> (+0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Comment thread src/display/text_layer.js
// Without a language, the canvas must inherit the document's one, as
// the text layer does: an empty lang attribute would instead declare
// the language unknown, which can resolve to other fonts.
if (lang) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we receive a lang that is "" here, and if so do we need to distinguish it from null?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, but rarely. Catalog.lang already returns null for a missing /Lang and for /Lang (), so "" only comes from a non-empty string that decodes to nothing (<FEFF>, or only a language escape sequence), or from a text content object passed to TextLayer directly.

I don't think we need to distinguish them: the canvas is only there to measure text in the fonts the spans are drawn with, and the spans inherit the page's language whether lang is null or "". The PDF specification doesn't distinguish them either: an empty language identifier means the language is unknown, and so does a missing /Lang in the catalog. Both keep sharing the "" cache entry.

@codspeed

codspeed Bot commented Oct 21, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 86 untouched benchmarks


Comparing yhay81:text-layer-empty-lang (0d13991) with master (33734f1)

Open in CodSpeed

@nicolo-ribaudo nicolo-ribaudo left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code looks good, but it needs a second review from somebody else.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Text layer spans are scaled against the wrong font when the PDF has no /Lang and the page has a lang

4 participants