Repository navigation
Measure intrinsic text width the way the line breaker does - #184
Merged
Merged
Conversation
Intrinsic width summed each character's unshaped advance, while both line breakers measure shaped text. When GPOS kerning widened a word, a content-sized box came out a fraction of a point narrower than the line it had to hold, and the breaker split the word: "Mumbai" in IBM Plex Serif 10pt drew as "Mumba" / "i" in a flex row, as plain text and as a nested run alike. Plain text is now measured with measure_width (the plain breaker's measurement, as min-content already uses) and runs with the new measure_runs_width (the runs breaker's). The StyledChar list is built by one helper for layout and measurement, so both see the same chars. The test lays out the reported strings in IBM Plex Serif, added as an OFL fixture; it fails before this change on all three. Addresses #181. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Styled runs used to sum every run's width, so text with a hard break measured as all its lines laid end to end. Measuring through the StyledChar list split at '\n' takes the widest line instead, as CSS max-content does. The new test fails before the fix (240.15pt for two lines whose wider one is 167.61pt). The HTML invoice fixture's address block (lines split by <br>) is now 110.1pt wide instead of 208.7pt; its drawn PDF is byte-identical, so the structural baseline is accepted. Gallery manifest regenerated. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…haped # Conflicts: # docs/images/templates/manifest.json
danmolitor
enabled auto-merge
October 6, 2026 14:56
This was referenced Oct 6, 2026
Merged
This was referenced Oct 7, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Addresses #181. Thanks @santhiprakash for the detailed report and the measurements.
Intrinsic width summed each character's unshaped advance, while both line breakers measure shaped text. When GPOS kerning widened a word, a content-sized box came out a fraction of a point narrower than its line, and the breaker split the word. In IBM Plex Serif 10pt, "Mumbai" drew as "Mumba" / "i", "Mumbai," as "Mumbai" / ",", and "Bengaluru" as "Bengalur" / "u". This happened for plain text as well as nested runs: with a single font family, plain text also takes the shaped path.
Intrinsic width now uses each breaker's own measurement:
measure_widthfor plain text (as min-content already did) and the newmeasure_runs_widthfor runs. One helper builds the run characters for both layout and measurement, so they always see the same characters.This also fixes a second measurement bug. Runs summed every run's width, so text with a hard break (an HTML
<span>…</span><br><span>…</span>cell) measured as all its lines end to end. It now measures as its widest line, which is CSS max-content.Tests (both fail on main)
content_sized_text_holds_its_shaped_line: the three strings above in a 200pt space-between row, as plain text and as a nested run, in IBM Plex Serif (added as an OFL test fixture). On main:["Mumba", "i"].styled_text_with_a_hard_break_is_as_wide_as_its_wider_line: on main, two lines measure 240.15pt when the wider one is 167.61pt.What moves
<br>) is now 110.1pt wide instead of 208.7pt. The drawn PDF is byte-identical; the structural baseline is updated.<span>/<br>/<span>, so they no longer claim both lines' width. Checked against Chrome with a controlled copy of that table, using explicit units: the Quantity column starts 7pt from Chrome's position instead of 43pt (Price: 3.5pt instead of 21pt). The Crater template on its own drifts the other way, because of differences in that template that the old over-measurement partly offset (unitless font sizes, a narrower table). Those are unrelated to this change. The corpus baseline is refreshed at release time.Performance
Intrinsic width now shapes text instead of summing advances. That's slower for registered fonts, and it adds up where layout measures the same cells repeatedly, as automatic table layout does. Native
forme-html, median of 5 runs:Not noticeable at these sizes, so no cache is added. If large tables in registered fonts ever matter, a per-node intrinsic-width cache is the fix.