LibWeb: Advance the SVG current text position across text runs - #11030
Merged
AtkinsSJ merged 1 commit intoAug 7, 2026
Merged
Conversation
Problem: All <tspan> elements without explicit positions rendered on top of each other, at the position where their parent <text> element starts. Cause: SVG text layout never advanced the current text position by the advance of each rendered text run. The position handed to a text box’s children was the position before any of the box’s own glyphs got placed. And between sibling boxes, the position was clobbered with the bottom- right corner of the previous box’s ink bounding box. That differs from the glyph advance, and is wrong in y — since the pen must stay on the baseline. In addition, “text-anchor” was applied separately to every box’s own text run. So, anchoring a <text> whose content is split across <tspan>s shifted each run individually, instead of the whole text chunk. Fix: Track the current text position as the spec defines it: each text run advances the position by its own advance; a <tspan> without 'x'/'y' continues at the current position; and a <text> element always starts at its own absolute position — since 'x' and 'y' default to 0 for <text>. Apply “text-anchor” per text chunk: When a box starts a chunk (every <text>, and any <tspan> with an absolute position), measure the total advance of all runs in the chunk, and shift the chunk’s starting position once — instead of shifting every run separately. Fixes LadybirdBrowser#10625
📝 WalkthroughWalkthroughSVG text layout now measures text chunks across descendants, applies chunk-level anchoring and positioning, and propagates the resulting position through Rust layout. New and updated tests validate tspan placement, rendering, and bounding rectangles. ChangesSVG text positioning
Estimated code review effort: 3 (Moderate) | ~25 minutes Sequence Diagram(s)sequenceDiagram
participant SVGTextElement
participant LayoutRustBridge
participant SVGFormattingContext
SVGTextElement->>LayoutRustBridge: provide text positioning attributes
LayoutRustBridge->>LayoutRustBridge: measure chunks and apply text-anchor
LayoutRustBridge-->>SVGFormattingContext: return text_position_after
SVGFormattingContext->>SVGFormattingContext: position descendant and following text
Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
AtkinsSJ
approved these changes
Aug 7, 2026
Contributor
|
Thank you! :) |
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.
Problem: All
<tspan>elements without explicit positions rendered on top of each other, at the position where their parent<text>element starts.Cause: SVG text layout never advanced the current text position by the advance of each rendered text run. The position handed to a text box’s children was the position before any of the box’s own glyphs got placed. And between sibling boxes, the position was clobbered with the bottom-right corner of the previous box’s ink bounding box. That differs from the glyph advance, and is wrong in y — since the pen must stay on the baseline. In addition,
text-anchorwas applied separately to every box’s own text run. So, anchoring a<text>whose content is split across<tspan>s shifted each run individually, instead of the whole text chunk.Fix: Track the current text position as the spec defines it: each text run advances the position by its own advance; a
<tspan>withoutx/ycontinues at the current position; and a<text>element always starts at its own absolute position — sincexandydefault to 0 for<text>. Applytext-anchorper text chunk: When a box starts a chunk (every<text>, and any<tspan>with an absolute position), measure the total advance of all runs in the chunk, and shift the chunk’s starting position once — instead of shifting every run separately. Fixes #10625.