Fontique: Cache font queries and metrics in FontContext - #796
Open
nicoburns wants to merge 14 commits into
Open
Conversation
staging-devin-ai-integration
Bot
force-pushed
the
devin/1788393297-font-cache
branch
from
September 9, 2026 13:56
f3463d2 to
e5e21be
Compare
staging-devin-ai-integration
Bot
force-pushed
the
devin/1788393297-font-cache
branch
2 times, most recently
from
September 9, 2026 16:22
533d713 to
2be9fb5
Compare
The root style is always materialised at index 0 and every other style records the index of its enclosing span's style. The tree builder now materialises ancestor spans that contain no direct text so that they can contribute their inline box to line metrics.
`VerticalAlign` mirrors css-inline-3 as a compound of `AlignmentBaseline` (baseline, text-top, text-bottom, middle) and `BaselineShift` (length, sub, super, top, bottom), so callers holding the longhands (e.g. Blitz over Stylo) can pass them through losslessly and values such as `vertical-align: text-top 2px` compose. The CSS 2 keywords are available as associated constants (`VerticalAlign::SUPER` etc.) plus `VerticalAlign::length`. The property is plumbed through `StyleProperty`, `TextStyle`, both builders and `ResolvedStyle`; atomic inline boxes carry their own `vertical_align` and optional `baseline`. No layout behaviour changes yet.
Every style table entry gets `StyleMetrics`: primary-font ascent/descent/ x-height (honouring font variations), the line-height expanded `over`/`under` box with CSS 2 §10.8.1 half-leading, and its baseline offset relative to the root of its aligned subtree. Offsets accumulate parent-first through the style's parent chain (`alignment-baseline` offset plus `baseline-shift`); `top`/`bottom` start a new line-relative aligned subtree. `sub`/`super` use the WebKit/Blink constants (font-size / 5 and / 3). Per-character style indices are reset for each layout so an empty layout's substitute space uses the root style rather than a stale index.
… glyphs/inline boxes Line breaking now seeds every line with the root (strut) inline box, adds each run's style box plus its not-yet-contributed ancestors, and tracks vertical-align: top/bottom subtrees separately. Glyph runs and inline boxes are positioned at their style's shifted baseline. Lines containing only inline boxes now get strut height (snapshots updated). Details folded in from review: - Lines containing only empty or out-of-flow inline boxes have zero height; negative-height in-flow boxes still count as content and keep the strut. - The trailing line after a final newline is sized by the newline's style chain rather than collapsing to the strut. - With `quantize`, the exact baseline offset is accumulated down the style chain and rounded once per style (and once per top/bottom subtree), so glyph baselines are whole pixels without per-level rounding drift, and inline box ascent/descent are not rounded separately. - Font queries and metrics are shared between styles with identical font selection inputs, run box metrics are computed once per run, and the shaped run's metrics are reused for its style; aligned-subtree offsets are stored per layout instead of per line.
…+0020 coverage check CSS Fonts 4 defines the first available font via unicode-range coverage of U+0020, not glyph coverage. Parley has no unicode-range, so every available face qualifies and the first face of the stack is used.
…box" Parley already uses "inline box" for `InlineBox`, an atomic box embedded in the text, so use "span" / "span box" for what CSS calls an inline box (the box generated by a style table entry on a line). Documents the term in the `style_metrics` module docs.
BreakerState::default() is public and can be passed to BreakLines::revert_to, but its LineBoxMetrics had no root aligned subtree, so the next line would index out of bounds. Default now contains the root subtree (without a strut) and reset builds on it, so the breaker is valid from any BreakerState.
Split the font-derived part into BoxMetrics, whose from_font returns a complete value and is what run_box_metrics needs; StyleMetrics::from_font is only meaningful inside resolve_style_metrics, which fills in the remaining tree-position fields.
Each style now resolves its first available font and metrics directly; cross-layout caching of both is left to the FontContext font cache.
Every non-root span's parent must precede it in the style table (debug-asserted); a malformed parent index falls back to the root rather than producing a self-parented orphan, so ancestor walks always end at 0.
Replaces the parallel inline_boxes / inline_box_styles vectors with a single
Vec<LayoutInlineBox { inline_box, style_index }>, so sorting is a plain
stable sort_by_key and the two can no longer get out of step.
Layout::inline_boxes() / inline_boxes_mut() now return ExactSizeIterators
over &InlineBox / &mut InlineBox instead of slices.
Cache fontique primary-font queries (keyed on the FamilyId stack and attributes) and FontMetrics (keyed on blob id, index, size bits and variations) in FontContext so they survive across layouts. The cache is invalidated via a new Collection::generation() counter that is bumped on every mutation of the fontique collection. The shaper uses the cached primary font only for clusters it fully covers; anything else goes through the existing per-cluster fallback query so font fallback behaviour is unchanged.
When the cached primary font does not fully cover a cluster, seed the fallback query with its coverage and skip it when the query yields it again, so that no cluster computes coverage for the same font twice.
staging-devin-ai-integration
Bot
force-pushed
the
devin/1788393297-font-cache
branch
from
September 10, 2026 20:42
2be9fb5 to
1fd0652
Compare
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.
LLM Contributions: Generated with Fable 5.1 Low
vertical-alignstyle #766Add a persistent cache to the
FontContextthat caches the "first available font" and the font metrics.