Skip to content

Commit e06249c

Browse files
committed
[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 SVGTextLayout 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::usesSVGTextLayout const): * Source/WebCore/rendering/svg/RenderSVGText.h: * Source/WebCore/rendering/svg/SVGTextLayout.cpp: Added. * Source/WebCore/rendering/svg/SVGTextLayout.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:
1 parent 71c793a commit e06249c

14 files changed

Lines changed: 1328 additions & 24 deletions
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
abc
2+
abc
3+
😀😀😀
4+
😀
5+
XXXX
6+
abc
7+
abc
8+
9+
PASS Absolute x positions are not moved by textLength spacing
10+
PASS textLength spacing is distributed between the characters of a single chunk
11+
PASS textLength spacing on a path counts characters, not code units
12+
PASS textLength with lengthAdjust=spacingAndGlyphs stretches advances and glyphs of a single chunk
13+
PASS Absolute x positions are not moved by textLength spacingAndGlyphs, the glyphs stretch in place
14+
PASS Absolute x positions at the natural advances are not moved by textLength spacingAndGlyphs
15+
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
<!DOCTYPE html><!-- webkit-test-runner [ SVG2TextLayoutAlgorithmEnabled=true ] -->
2+
<meta charset="utf-8">
3+
<title>textLength with absolutely positioned characters</title>
4+
<script src="../../resources/testharness.js"></script>
5+
<script src="../../resources/testharnessreport.js"></script>
6+
<svg width="600" height="200" font-family="Ahem" font-size="20">
7+
<text id="absolute" x="10 100 200" y="30" textLength="300" lengthAdjust="spacing">abc</text>
8+
<text id="single" x="10" y="60" textLength="300" lengthAdjust="spacing">abc</text>
9+
<path id="path" d="M 10 150 L 590 150"/>
10+
<text id="onPath"><textPath href="#path" textLength="300" lengthAdjust="spacing">&#x1F600;&#x1F600;&#x1F600;</textPath></text>
11+
<text id="reference" x="10" y="190">&#x1F600;</text>
12+
<text id="glyphs" x="0 50 100 150" y="120" font-size="50" textLength="100" lengthAdjust="spacingAndGlyphs">XXXX</text>
13+
<text id="glyphsAbsolute" x="10 100 200" y="90" textLength="300" lengthAdjust="spacingAndGlyphs">abc</text>
14+
<text id="glyphsSingle" x="10" y="90" textLength="300" lengthAdjust="spacingAndGlyphs">abc</text>
15+
</svg>
16+
<script>
17+
function startX(id, index)
18+
{
19+
return document.getElementById(id).getStartPositionOfChar(index).x;
20+
}
21+
22+
test(() => {
23+
assert_approx_equals(startX("absolute", 0), 10, 0.01);
24+
assert_approx_equals(startX("absolute", 1), 100, 0.01);
25+
assert_approx_equals(startX("absolute", 2), 200, 0.01);
26+
}, "Absolute x positions are not moved by textLength spacing");
27+
28+
test(() => {
29+
assert_approx_equals(startX("single", 0), 10, 0.01);
30+
assert_approx_equals(startX("single", 1), 150, 0.01);
31+
assert_approx_equals(startX("single", 2), 290, 0.01);
32+
}, "textLength spacing is distributed between the characters of a single chunk");
33+
34+
test(() => {
35+
const advance = document.getElementById("reference").getComputedTextLength();
36+
// Each emoji is a surrogate pair. Spacing goes between the three characters, not the six code units.
37+
const spacing = (300 - 3 * advance) / 2;
38+
assert_approx_equals(startX("onPath", 2) - startX("onPath", 0), advance + spacing, 0.5);
39+
assert_approx_equals(startX("onPath", 4) - startX("onPath", 0), 2 * (advance + spacing), 0.5);
40+
}, "textLength spacing on a path counts characters, not code units");
41+
42+
function assertExtents(id, expectedXs, expectedWidth)
43+
{
44+
const text = document.getElementById(id);
45+
expectedXs.forEach((expectedX, i) => {
46+
const extent = text.getExtentOfChar(i);
47+
assert_approx_equals(extent.x, expectedX, 0.01, `character ${i} x`);
48+
assert_approx_equals(extent.width, expectedWidth, 0.01, `character ${i} width`);
49+
});
50+
}
51+
52+
test(() => {
53+
assertExtents("glyphsSingle", [10, 110, 210], 100);
54+
}, "textLength with lengthAdjust=spacingAndGlyphs stretches advances and glyphs of a single chunk");
55+
56+
test(() => {
57+
assertExtents("glyphsAbsolute", [10, 100, 200], 100);
58+
}, "Absolute x positions are not moved by textLength spacingAndGlyphs, the glyphs stretch in place");
59+
60+
test(() => {
61+
assertExtents("glyphs", [0, 50, 100, 150], 25);
62+
}, "Absolute x positions at the natural advances are not moved by textLength spacingAndGlyphs");
63+
</script>

‎Source/WTF/Scripts/Preferences/UnifiedWebPreferences.yaml‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5245,6 +5245,13 @@ SKAttributionEnabled:
52455245
humanReadableDescription: "SKAttribution"
52465246
defaultValue: true
52475247

5248+
SVG2TextLayoutAlgorithmEnabled:
5249+
type: bool
5250+
status: internal
5251+
humanReadableName: "SVG 2 text layout algorithm"
5252+
humanReadableDescription: "Use the SVG 2 text layout algorithm for SVG text"
5253+
defaultValue: false
5254+
52485255
SVGExternalResourcesEnabled:
52495256
type: bool
52505257
status: stable

‎Source/WebCore/Sources.txt‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3237,6 +3237,7 @@ rendering/svg/SVGRenderingContext.cpp @header:RenderStyleGetters
32373237
rendering/svg/SVGTextBoxPainter.cpp @header:RenderStyleGetters
32383238
rendering/svg/SVGTextChunk.cpp @header:RenderStyleGetters
32393239
rendering/svg/SVGTextChunkBuilder.cpp
3240+
rendering/svg/SVGTextLayout.cpp @header:RenderStyleGetters
32403241
rendering/svg/SVGTextLayoutAttributes.cpp
32413242
rendering/svg/SVGTextLayoutAttributesBuilder.cpp @header:RenderStyleGetters
32423243
rendering/svg/SVGTextLayoutEngine.cpp @header:RenderStyleGetters

‎Source/WebCore/WebCore.xcodeproj/project.pbxproj‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6971,6 +6971,7 @@
69716971
E403B7A2251B11930019E800 /* LayoutIntegrationCoverage.h in Headers */ = {isa = PBXBuildFile; fileRef = E403B7A1251B11930019E800 /* LayoutIntegrationCoverage.h */; };
69726972
E403B7A3251B11C10019E800 /* LayoutIntegrationPagination.h in Headers */ = {isa = PBXBuildFile; fileRef = E4312AB724B3265600678349 /* LayoutIntegrationPagination.h */; };
69736973
C814C569BBA6F36D17A949B9 /* SVGTextDisplayContentBuilder.h in Headers */ = {isa = PBXBuildFile; fileRef = 8C34B552C743CB4BA7256D9A /* SVGTextDisplayContentBuilder.h */; };
6974+
89ACE0522BC1BB06CFFF1775 /* SVGTextLayout.h in Headers */ = {isa = PBXBuildFile; fileRef = 00580A55849484D03A89EE07 /* SVGTextLayout.h */; };
69746975
E406204C2E5F2EC0009144F4 /* StyleRuleFunction.h in Headers */ = {isa = PBXBuildFile; fileRef = E406204B2E5F2EC0009144F4 /* StyleRuleFunction.h */; };
69756976
E415EB13270C351300E8DA1B /* InlineIteratorInlineBox.h in Headers */ = {isa = PBXBuildFile; fileRef = E415EB11270C351200E8DA1B /* InlineIteratorInlineBox.h */; };
69766977
E418025523D4549B00FFB071 /* LayoutIntegrationBoxTreeUpdater.h in Headers */ = {isa = PBXBuildFile; fileRef = E418025323D4549A00FFB071 /* LayoutIntegrationBoxTreeUpdater.h */; };
@@ -23041,6 +23042,8 @@
2304123042
E4312AB724B3265600678349 /* LayoutIntegrationPagination.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LayoutIntegrationPagination.h; sourceTree = "<group>"; };
2304223043
5D3C5B1036F71428B78A1EE2 /* SVGTextDisplayContentBuilder.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = SVGTextDisplayContentBuilder.cpp; sourceTree = "<group>"; };
2304323044
8C34B552C743CB4BA7256D9A /* SVGTextDisplayContentBuilder.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SVGTextDisplayContentBuilder.h; sourceTree = "<group>"; };
23045+
B6422CEB4AEBB2DE83C8EDC7 /* SVGTextLayout.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = SVGTextLayout.cpp; sourceTree = "<group>"; };
23046+
00580A55849484D03A89EE07 /* SVGTextLayout.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SVGTextLayout.h; sourceTree = "<group>"; };
2304423047
E43A023A17EB370A004CDD25 /* RenderElement.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RenderElement.h; sourceTree = "<group>"; };
2304523048
E43A023C17EB3713004CDD25 /* RenderElement.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RenderElement.cpp; sourceTree = "<group>"; };
2304623049
E43AF8E41AC5B7DD00CA717E /* CacheValidation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CacheValidation.cpp; sourceTree = "<group>"; };
@@ -25177,6 +25180,8 @@
2517725180
081668D1125603BF006F25DE /* SVGTextChunkBuilder.cpp */,
2517825181
081668D2125603BF006F25DE /* SVGTextChunkBuilder.h */,
2517925182
08F0BFBF1255C53C00075185 /* SVGTextFragment.h */,
25183+
B6422CEB4AEBB2DE83C8EDC7 /* SVGTextLayout.cpp */,
25184+
00580A55849484D03A89EE07 /* SVGTextLayout.h */,
2518025185
088C2F7512390080003D65CE /* SVGTextLayoutAttributes.cpp */,
2518125186
088C2F7612390080003D65CE /* SVGTextLayoutAttributes.h */,
2518225187
081093D91255F0E700ED9D29 /* SVGTextLayoutAttributesBuilder.cpp */,
@@ -50075,6 +50080,7 @@
5007550080
C814C569BBA6F36D17A949B9 /* SVGTextDisplayContentBuilder.h in Headers */,
5007650081
B2227ACB0D00BF220071B782 /* SVGTextElement.h in Headers */,
5007750082
08F0BFC41255C53C00075185 /* SVGTextFragment.h in Headers */,
50083+
89ACE0522BC1BB06CFFF1775 /* SVGTextLayout.h in Headers */,
5007850084
088C2F7A12390081003D65CE /* SVGTextLayoutAttributes.h in Headers */,
5007950085
081093DC1255F0E700ED9D29 /* SVGTextLayoutAttributesBuilder.h in Headers */,
5008050086
081668DA125603D5006F25DE /* SVGTextLayoutEngine.h in Headers */,

‎Source/WebCore/rendering/svg/RenderSVGInlineText.cpp‎

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ String RenderSVGInlineText::originalText() const
9494
void RenderSVGInlineText::setTextInternal(const String& newText, bool force)
9595
{
9696
RenderText::setTextInternal(newText, force);
97+
m_hasValidTextMetrics = false;
9798
if (!force)
9899
setRenderedText(newText);
99100
if (auto* textAncestor = RenderSVGText::locateRenderSVGTextAncestor(*this))
@@ -104,6 +105,8 @@ void RenderSVGInlineText::styleDidChange(Style::Difference diff, const Style::Co
104105
{
105106
RenderText::styleDidChange(diff, oldStyle);
106107
updateScaledFont();
108+
if (oldStyle && (oldStyle->writingMode() != style().writingMode() || oldStyle->unicodeBidi() != style().unicodeBidi()))
109+
m_hasValidTextMetrics = false;
107110

108111
bool newPreserves = style().whiteSpaceCollapse() == WhiteSpaceCollapse::Preserve;
109112
bool oldPreserves = oldStyle && oldStyle->whiteSpaceCollapse() == WhiteSpaceCollapse::Preserve;
@@ -225,8 +228,16 @@ PositionWithAffinity RenderSVGInlineText::positionForPoint(const LayoutPoint& po
225228

226229
void RenderSVGInlineText::updateScaledFont()
227230
{
228-
if (computeNewScaledFontForStyle(*this, style(), m_scalingFactor, m_scaledFont))
231+
// FIXME: FontCascade comparison also compares the font list, which FontCascadeCache::invalidate() replaces,
232+
// so the text metrics are dropped after complex text measurement even if the font did not change.
233+
float scalingFactor = 1;
234+
FontCascade scaledFont;
235+
if (computeNewScaledFontForStyle(*this, style(), scalingFactor, scaledFont))
229236
m_canUseSimplifiedTextMeasuring = { };
237+
if (scalingFactor != m_scalingFactor || scaledFont != m_scaledFont)
238+
m_hasValidTextMetrics = false;
239+
m_scalingFactor = scalingFactor;
240+
m_scaledFont = WTF::move(scaledFont);
230241
}
231242

232243
float RenderSVGInlineText::computeScalingFactorForRenderer(const RenderObject& renderer)

‎Source/WebCore/rendering/svg/RenderSVGInlineText.h‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@ class RenderSVGInlineText final : public RenderText {
4242
SVGTextLayoutAttributes* layoutAttributes() LIFETIME_BOUND { return &m_layoutAttributes; }
4343
const SVGTextLayoutAttributes* layoutAttributes() const LIFETIME_BOUND { return &m_layoutAttributes; }
4444

45+
// Used by SVGTextLayout, which measures only when the text or the font changes.
46+
bool hasValidTextMetrics() const { return m_hasValidTextMetrics; }
47+
void setHasValidTextMetrics(bool value) { m_hasValidTextMetrics = value; }
48+
4549
// computeScalingFactor() returns the font-size scaling factor, ignoring the text-rendering mode.
4650
// scalingFactor() takes it into account, and thus returns 1 whenever text-rendering is set to 'geometricPrecision'.
4751
// Therefore if you need access to the vanilla scaling factor, use this method directly (e.g. for non-scaling-stroke).
@@ -71,6 +75,7 @@ class RenderSVGInlineText final : public RenderText {
7175
float m_scalingFactor;
7276
FontCascade m_scaledFont;
7377
SVGTextLayoutAttributes m_layoutAttributes;
78+
bool m_hasValidTextMetrics { false };
7479
};
7580

7681
} // namespace WebCore

‎Source/WebCore/rendering/svg/RenderSVGText.cpp‎

Lines changed: 43 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@
6161
#include "SVGResourcesCache.h"
6262
#include "SVGTextBoxPainter.h"
6363
#include "SVGTextElement.h"
64+
#include "SVGTextLayout.h"
6465
#include "SVGTextLayoutEngine.h"
6566
#include "SVGURIReference.h"
6667
#include "SVGVisitedRendererTracking.h"
@@ -154,6 +155,10 @@ static inline std::tuple<SVGTextLayoutAttributes*, SVGTextLayoutAttributes*> fin
154155

155156
inline bool RenderSVGText::shouldHandleSubtreeMutations() const
156157
{
158+
// SVGTextLayout rebuilds everything except the text metrics on each layout.
159+
// FIXME: Switching back to the old path after a layout leaves m_layoutAttributes empty, and the text disappears.
160+
if (usesSVGTextLayout())
161+
return false;
157162
if (beingDestroyed() || !m_hasPerformedLayout) {
158163
ASSERT(m_layoutAttributes.isEmpty());
159164
ASSERT(!m_layoutAttributesBuilder.numberOfTextPositioningElements());
@@ -275,6 +280,10 @@ void RenderSVGText::subtreeTextDidChange(RenderSVGInlineText* text)
275280
{
276281
ASSERT(text);
277282
ASSERT(!beingDestroyed());
283+
if (usesSVGTextLayout()) {
284+
setNeedsLayout();
285+
return;
286+
}
278287
if (!m_hasPerformedLayout) {
279288
ASSERT(m_layoutAttributes.isEmpty());
280289
ASSERT(!m_layoutAttributesBuilder.numberOfTextPositioningElements());
@@ -341,7 +350,25 @@ void RenderSVGText::layout()
341350
updateCachedBoundariesInParents = true;
342351
}
343352

344-
if (!m_hasPerformedLayout) {
353+
auto isLayoutSizeChanged = [&] {
354+
if (auto* legacyRootObject = lineageOfType<LegacyRenderSVGRoot>(*this).first())
355+
return legacyRootObject->isLayoutSizeChanged();
356+
if (auto* rootObject = lineageOfType<RenderSVGRoot>(*this).first())
357+
return rootObject->isLayoutSizeChanged();
358+
return false;
359+
};
360+
361+
if (usesSVGTextLayout()) {
362+
if (!m_hasPerformedLayout || m_needsTextMetricsUpdate || isLayoutSizeChanged() || m_needsTransformUpdate) {
363+
// Text renderers remeasure if the on-screen font changed.
364+
updateFontInAllDescendants(*this);
365+
updateCachedBoundariesInParents = true;
366+
}
367+
if (m_needsPositioningValuesUpdate)
368+
updateCachedBoundariesInParents = true;
369+
m_needsTextMetricsUpdate = false;
370+
m_needsPositioningValuesUpdate = false;
371+
} else if (!m_hasPerformedLayout) {
345372
// When laying out initially, collect all layout attributes, build the character data map,
346373
// and propogate resulting SVGLayoutAttributes to all RenderSVGInlineText children in the subtree.
347374
ASSERT(m_layoutAttributes.isEmpty());
@@ -362,13 +389,7 @@ void RenderSVGText::layout()
362389
m_needsPositioningValuesUpdate = false;
363390
updateCachedBoundariesInParents = true;
364391
} else {
365-
bool isLayoutSizeChanged = false;
366-
if (auto* legacyRootObject = lineageOfType<LegacyRenderSVGRoot>(*this).first())
367-
isLayoutSizeChanged = legacyRootObject->isLayoutSizeChanged();
368-
else if (auto* rootObject = lineageOfType<RenderSVGRoot>(*this).first())
369-
isLayoutSizeChanged = rootObject->isLayoutSizeChanged();
370-
371-
if (m_needsTextMetricsUpdate || isLayoutSizeChanged || m_needsTransformUpdate) {
392+
if (m_needsTextMetricsUpdate || isLayoutSizeChanged() || m_needsTransformUpdate) {
372393
// If the root layout size changed (eg. window size changes) or the transform to the root
373394
// context has changed then recompute the on-screen font size.
374395
updateFontInAllDescendants(*this);
@@ -380,7 +401,8 @@ void RenderSVGText::layout()
380401
m_layoutAttributesBuilder.rebuildMetricsForSubtree(*this);
381402
}
382403

383-
checkLayoutAttributesConsistency(this, m_layoutAttributes);
404+
if (!usesSVGTextLayout())
405+
checkLayoutAttributesConsistency(this, m_layoutAttributes);
384406

385407
// Reduced version of RenderBlock::layoutBlock(), which only takes care of SVG text.
386408
// All if branches that could cause early exit in RenderBlocks layoutBlock() method are turned into assertions.
@@ -555,13 +577,19 @@ void RenderSVGText::computePerCharacterLayoutInformation()
555577
if (!hasSVGContent)
556578
return;
557579

558-
if (m_layoutAttributes.isEmpty())
580+
if (!usesSVGTextLayout() && m_layoutAttributes.isEmpty())
559581
return;
560582

561583
CheckedRef lineLayout = *inlineLayout();
562584
auto [boxes, fragmentsForBoxes] = lineLayout->resetSVGTextFragments();
563585
ASSERT(!boxes.isEmpty() && boxes[0].isRootInlineBox());
564586

587+
if (usesSVGTextLayout()) {
588+
SVGTextLayout { *layoutBox(), boxes, fragmentsForBoxes }.layout();
589+
updatePositionAndOverflow(lineLayout->applySVGTextFragments());
590+
return;
591+
}
592+
565593
SVGTextLayoutEngine characterLayout(m_layoutAttributes, fragmentsForBoxes);
566594
auto endIndex = layoutCharactersInDisplayBoxes(boxes, 0, &characterLayout);
567595
ASSERT_UNUSED(endIndex, endIndex == boxes.size());
@@ -571,6 +599,11 @@ void RenderSVGText::computePerCharacterLayoutInformation()
571599
updatePositionAndOverflow(lineLayout->applySVGTextFragments());
572600
}
573601

602+
bool RenderSVGText::usesSVGTextLayout() const
603+
{
604+
return document().settings().svg2TextLayoutAlgorithmEnabled();
605+
}
606+
574607
bool RenderSVGText::nodeAtFloatPoint(const HitTestRequest& request, HitTestResult& result, const FloatPoint& pointInParent, HitTestAction hitTestAction)
575608
{
576609
ASSERT(!document().settings().layerBasedSVGEngineEnabled());

‎Source/WebCore/rendering/svg/RenderSVGText.h‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ class RenderSVGText final : public RenderSVGBlock {
4646

4747
void setNeedsPositioningValuesUpdate() { m_needsPositioningValuesUpdate = true; }
4848
void setNeedsTextMetricsUpdate() { m_needsTextMetricsUpdate = true; }
49+
bool usesSVGTextLayout() const;
4950

5051
// FIXME: [LBSE] Only needed for legacy SVG engine.
5152
void setNeedsTransformUpdate() override { m_needsTransformUpdate = true; }

0 commit comments

Comments
 (0)