Skip to content

[SVG text] Implement the SVG 2 text layout algorithm - #77259

Open
anttijk wants to merge 1 commit into
WebKit:mainfrom
anttijk:eng/svg-text-layout-algorithm-land
Open

anttijk wants to merge 1 commit into
WebKit:mainfrom
anttijk:eng/svg-text-layout-algorithm-land

Conversation

@anttijk

@anttijk anttijk commented Oct 16, 2026 •

Copy link
Copy Markdown
Contributor

9bca990

[SVG text] Implement the SVG 2 text layout algorithm
https://bugs.webkit.org/show_bug.cgi?id=327817
rdar://problem/190204825

Reviewed by NOBODY (OOPS!).

The old SVGTextLayoutEngine is built around assumptions of the legacy line layout. We can do better.

This patch adds SVGTextLayoutAlgorithm which implements the text layout algorithm as described by
the SVG 2 specification (https://w3c.github.io/svgwg/svg2-draft/text.html#TextLayoutAlgorithm). The
code maps directly to spec language making it much more readable than the old code.

It is also more correct. Following the spec steps fixes textLength with x/y lists and on text paths,
and lengthAdjust="spacingAndGlyphs" and whitespace collapsing now match Chrome and Firefox.

It also performs better. The old implementation measured text repeatedly, checked grapheme cluster
boundaries for every character and used hash maps for temporary storage. The new one caches the
measurements, skips the cluster checks for 8-bit text and uses index-based storage.

On a microbenchmark with 10k text labels text changes are about 25% faster. Speedometer
Charts-observable-plot improves by about 1% and React-Stockcharts-SVG by about 0.5%.

The new path is behind the internal SVG2TextLayoutAlgorithmEnabled flag, off by default for now.

* LayoutTests/svg/text/textLength-spacing-absolute-positions-expected.txt: Added.
* LayoutTests/svg/text/textLength-spacing-absolute-positions.html: Added.
* Source/WTF/Scripts/Preferences/UnifiedWebPreferences.yaml:
* Source/WebCore/Sources.txt:
* Source/WebCore/WebCore.xcodeproj/project.pbxproj:
* Source/WebCore/rendering/svg/RenderSVGInlineText.cpp:
(WebCore::RenderSVGInlineText::setTextInternal):
(WebCore::RenderSVGInlineText::styleDidChange):
(WebCore::RenderSVGInlineText::updateScaledFont):

Invalidate the cached text metrics.

* Source/WebCore/rendering/svg/RenderSVGInlineText.h:
* Source/WebCore/rendering/svg/RenderSVGText.cpp:
(WebCore::RenderSVGText::shouldHandleSubtreeMutations const):
(WebCore::RenderSVGText::subtreeTextDidChange):
(WebCore::RenderSVGText::layout):

Skip the layout attribute building with the new path.

(WebCore::RenderSVGText::computePerCharacterLayoutInformation):
(WebCore::RenderSVGText::usesSVGTextLayoutAlgorithm const):
* Source/WebCore/rendering/svg/RenderSVGText.h:
* Source/WebCore/rendering/svg/SVGTextLayoutAlgorithm.cpp: Added.
* Source/WebCore/rendering/svg/SVGTextLayoutAlgorithm.h: Added.
* Source/WebCore/rendering/svg/SVGTextLayoutEngine.cpp:
(WebCore::SVGTextLayoutEngine::layoutTextOnLineOrPath):
* Source/WebCore/rendering/svg/SVGTextLayoutEngineBaseline.cpp:
(WebCore::SVGTextLayoutEngineBaseline::dominantBaselineToAlignmentBaseline const):
(WebCore::SVGTextLayoutEngineBaseline::calculateAlignmentBaselineShift const):

Take the style instead of the renderer so layout boxes can use it.

* Source/WebCore/rendering/svg/SVGTextLayoutEngineBaseline.h:

9bca990

Misc iOS, visionOS, tvOS & watchOS macOS Linux Windows Apple Internal
✅ 🧪 style ✅ 🛠 ios ✅ 🛠 mac ✅ 🛠 wpe ✅ 🛠 win ⏳ 🛠 ios-apple
✅ 🧪 bindings ✅ 🛠 ios-sim ✅ 🛠 mac-AS-debug ✅ 🧪 wpe-wk2 ⏳ 🧪 win-tests ⏳ 🛠 mac-apple
✅ 🧪 webkitperl ✅ 🧪 ios-wk2 ⏳ 🧪 api-mac ✅ 🧪 api-wpe ⏳ 🛠 vision-apple
✅ 🧪 ios-wk2-wpt ⏳ 🧪 api-mac-debug loading 🧪 jsc-wpe
loading 🧪 jsc-x86-64 ⏳ 🧪 api-ios ❌ 🧪 mac-wk2 ✅ 🛠 gtk3-gcc
✅ 🛠 🧪 jsc-debug-arm64 ⏳ 🛠 ios-safer-cpp ⏳ 🧪 mac-AS-debug-wk2 ✅ 🛠 gtk
✅ 🛠 vision ✅ 🧪 mac-wk2-stress ✅ 🧪 gtk-wk2
loading 🛠 🧪 merge ✅ 🛠 vision-sim ⏳ 🧪 mac-intel-wk2 ✅ 🧪 api-gtk
✅ 🧪 vision-wk2 ✅ 🛠 mac-safer-cpp ✅ 🛠 playstation
✅ 🛠 tv ✅ 🧪 mac-site-isolation
⏳ 🛠 tv-sim
loading 🛠 watch
✅ 🛠 watch-sim

@anttijk anttijk self-assigned this Oct 16, 2026
@anttijk anttijk added the SVG For bugs in the SVG implementation. label Oct 16, 2026
@anttijk
anttijk force-pushed the eng/svg-text-layout-algorithm-land branch from a5477af to cdc8c10 Compare October 16, 2026 08:23
@anttijk
anttijk force-pushed the eng/svg-text-layout-algorithm-land branch from cdc8c10 to cf76b45 Compare October 16, 2026 09:14
@webkit-ews-buildbot

Copy link
Copy Markdown
Collaborator

macOS Safer C++ Build #140315 (cf76b45)

❌ Found 1 failing file with 6 issues. Please address these issues before landing. See WebKit Guidelines for Safer C++ Programming.
(cc @rniwa)

@webkit-ews-buildbot webkit-ews-buildbot added the merging-blocked Applied to prevent a change from being merged label Oct 16, 2026
@anttijk anttijk removed the merging-blocked Applied to prevent a change from being merged label Oct 16, 2026
@anttijk
anttijk force-pushed the eng/svg-text-layout-algorithm-land branch from cf76b45 to 9030a53 Compare October 16, 2026 12:41
@anttijk
anttijk force-pushed the eng/svg-text-layout-algorithm-land branch from 9030a53 to 225aa01 Compare October 16, 2026 12:52
@anttijk
anttijk force-pushed the eng/svg-text-layout-algorithm-land branch from 225aa01 to 63210d1 Compare October 16, 2026 13:40

@alanbaradlay alanbaradlay left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

nice!

@anttijk
anttijk force-pushed the eng/svg-text-layout-algorithm-land branch from 63210d1 to e06249c Compare October 16, 2026 14:42
https://bugs.webkit.org/show_bug.cgi?id=327817
rdar://problem/190204825

Reviewed by NOBODY (OOPS!).

The old SVGTextLayoutEngine is built around assumptions of the legacy line layout. We can do better.

This patch adds SVGTextLayoutAlgorithm which implements the text layout algorithm as described by
the SVG 2 specification (https://w3c.github.io/svgwg/svg2-draft/text.html#TextLayoutAlgorithm). The
code maps directly to spec language making it much more readable than the old code.

It is also more correct. Following the spec steps fixes textLength with x/y lists and on text paths,
and lengthAdjust="spacingAndGlyphs" and whitespace collapsing now match Chrome and Firefox.

It also performs better. The old implementation measured text repeatedly, checked grapheme cluster
boundaries for every character and used hash maps for temporary storage. The new one caches the
measurements, skips the cluster checks for 8-bit text and uses index-based storage.

On a microbenchmark with 10k text labels text changes are about 25% faster. Speedometer
Charts-observable-plot improves by about 1% and React-Stockcharts-SVG by about 0.5%.

The new path is behind the internal SVG2TextLayoutAlgorithmEnabled flag, off by default for now.

* LayoutTests/svg/text/textLength-spacing-absolute-positions-expected.txt: Added.
* LayoutTests/svg/text/textLength-spacing-absolute-positions.html: Added.
* Source/WTF/Scripts/Preferences/UnifiedWebPreferences.yaml:
* Source/WebCore/Sources.txt:
* Source/WebCore/WebCore.xcodeproj/project.pbxproj:
* Source/WebCore/rendering/svg/RenderSVGInlineText.cpp:
(WebCore::RenderSVGInlineText::setTextInternal):
(WebCore::RenderSVGInlineText::styleDidChange):
(WebCore::RenderSVGInlineText::updateScaledFont):

Invalidate the cached text metrics.

* Source/WebCore/rendering/svg/RenderSVGInlineText.h:
* Source/WebCore/rendering/svg/RenderSVGText.cpp:
(WebCore::RenderSVGText::shouldHandleSubtreeMutations const):
(WebCore::RenderSVGText::subtreeTextDidChange):
(WebCore::RenderSVGText::layout):

Skip the layout attribute building with the new path.

(WebCore::RenderSVGText::computePerCharacterLayoutInformation):
(WebCore::RenderSVGText::usesSVGTextLayoutAlgorithm const):
* Source/WebCore/rendering/svg/RenderSVGText.h:
* Source/WebCore/rendering/svg/SVGTextLayoutAlgorithm.cpp: Added.
* Source/WebCore/rendering/svg/SVGTextLayoutAlgorithm.h: Added.
* Source/WebCore/rendering/svg/SVGTextLayoutEngine.cpp:
(WebCore::SVGTextLayoutEngine::layoutTextOnLineOrPath):
* Source/WebCore/rendering/svg/SVGTextLayoutEngineBaseline.cpp:
(WebCore::SVGTextLayoutEngineBaseline::dominantBaselineToAlignmentBaseline const):
(WebCore::SVGTextLayoutEngineBaseline::calculateAlignmentBaselineShift const):

Take the style instead of the renderer so layout boxes can use it.

* Source/WebCore/rendering/svg/SVGTextLayoutEngineBaseline.h:
@anttijk
anttijk force-pushed the eng/svg-text-layout-algorithm-land branch from e06249c to 9bca990 Compare October 16, 2026 15:41
@anttijk anttijk added the merge-queue Applied to send a pull request to merge-queue label Oct 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

merge-queue Applied to send a pull request to merge-queue SVG For bugs in the SVG implementation.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants