Skip to content

Commit a36f3b3

Browse files
committed
SVG markers don't re-render when marker attributes change dynamically
rdar://130678384 Reviewed by Brent Fulgham and Simon Fraser. When the marker-start, marker-mid, or marker-end attributes are changed dynamically on SVG elements, markers fail to re-render in the legacy SVG engine. This happens because SVGResourcesCache detects style changes for clipPath, mask, filter, fill, and stroke, but not for marker properties. The fix adds missing marker checks to ensure the cache resources are rebuilt correctly. * LayoutTests/svg/dynamic-updates/dynamic-marker-creation-expected.html: Added. * LayoutTests/svg/dynamic-updates/dynamic-marker-creation.html: Added. * Source/WebCore/rendering/svg/legacy/SVGResourcesCache.cpp: (WebCore::SVGResourcesCache::clientStyleChanged): Canonical link: https://commits.webkit.org/304880@main
1 parent c79c6f3 commit a36f3b3

File tree

3 files changed

+130
-0
lines changed

3 files changed

+130
-0
lines changed
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<style>
5+
.line-path {
6+
stroke: #444;
7+
fill: none;
8+
stroke-width: 2;
9+
}
10+
</style>
11+
</head>
12+
<body>
13+
<svg viewBox="0 0 600 100" width="600" height="100">
14+
<defs>
15+
<marker id="arrowStart" viewBox="0 0 10 10" refX="5" refY="5"
16+
markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto">
17+
<path d="M 0 0 L 10 5 L 0 10 z" fill="red"/>
18+
</marker>
19+
<marker id="arrowMid" viewBox="0 0 10 10" refX="5" refY="5"
20+
markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto">
21+
<path d="M 0 0 L 10 5 L 0 10 z" fill="green"/>
22+
</marker>
23+
<marker id="arrowEnd" viewBox="0 0 10 10" refX="5" refY="5"
24+
markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto">
25+
<path d="M 0 0 L 10 5 L 0 10 z" fill="blue"/>
26+
</marker>
27+
</defs>
28+
<path class="line-path" d="M 20 50 L 180 50" marker-start="url(#arrowStart)"/>
29+
<path class="line-path" d="M 220 50 L 300 50 L 380 50" marker-mid="url(#arrowMid)"/>
30+
<path class="line-path" d="M 420 50 L 580 50" marker-end="url(#arrowEnd)"/>
31+
</svg>
32+
</body>
33+
</html>
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<script src="../../resources/ui-helper.js"></script>
5+
<style>
6+
.line-path {
7+
stroke: #444;
8+
fill: none;
9+
stroke-width: 2;
10+
}
11+
</style>
12+
</head>
13+
<body>
14+
<svg viewBox="0 0 600 100" width="600" height="100">
15+
<g></g>
16+
</svg>
17+
<script>
18+
if (window.testRunner) {
19+
testRunner.waitUntilDone();
20+
}
21+
22+
const pathData = [
23+
{ d: 'M 20 50 L 180 50', attr: 'marker-start', val: 'arrowStart' },
24+
{ d: 'M 220 50 L 300 50 L 380 50', attr: 'marker-mid', val: 'arrowMid' },
25+
{ d: 'M 420 50 L 580 50', attr: 'marker-end', val: 'arrowEnd' },
26+
];
27+
28+
function createMarker(parent, id, color) {
29+
const marker = document.createElementNS('http://www.w3.org/2000/svg', 'marker');
30+
marker.setAttribute("id", id);
31+
marker.setAttribute("viewBox", "0 0 10 10");
32+
marker.setAttribute("refX", "5");
33+
marker.setAttribute("refY", "5");
34+
marker.setAttribute("markerUnits", "strokeWidth");
35+
marker.setAttribute("markerWidth", "8");
36+
marker.setAttribute("markerHeight", "6");
37+
marker.setAttribute("orient", "auto");
38+
parent.appendChild(marker);
39+
40+
const path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
41+
path.setAttribute("d", "M 0 0 L 10 5 L 0 10 z");
42+
path.setAttribute("fill", color);
43+
marker.appendChild(path);
44+
}
45+
46+
function render(count) {
47+
const svg = document.querySelector("svg");
48+
const group = svg.querySelector("g");
49+
50+
const paths = Array.from(group.querySelectorAll("line-path"));
51+
52+
while (paths.length < pathData.length) {
53+
paths.push(document.createElementNS('http://www.w3.org/2000/svg', 'path'));
54+
}
55+
56+
paths.forEach((path, idx) => {
57+
path.setAttribute('class', 'line-path');
58+
path.setAttribute('d', pathData[idx].d);
59+
path.setAttribute(pathData[idx].attr, `url(#${pathData[idx].val}${count})`);
60+
61+
group.appendChild(path);
62+
})
63+
64+
svg.querySelectorAll("defs *").forEach(el => el.remove());
65+
66+
let defs = document.querySelector('defs');
67+
if (!defs) {
68+
defs = document.createElementNS('http://www.w3.org/2000/svg', 'defs');
69+
}
70+
71+
group.appendChild(defs);
72+
createMarker(defs, `arrowStart${count}`, "red");
73+
createMarker(defs, `arrowMid${count}`, "green");
74+
createMarker(defs, `arrowEnd${count}`, "blue");
75+
}
76+
77+
window.addEventListener("load", async () => {
78+
render(0);
79+
await UIHelper.renderingUpdate();
80+
render(1);
81+
82+
if (window.testRunner) {
83+
testRunner.notifyDone();
84+
}
85+
});
86+
</script>
87+
</body>
88+
</html>

Source/WebCore/rendering/svg/legacy/SVGResourcesCache.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,15 @@ void SVGResourcesCache::clientStyleChanged(RenderElement& renderer, Style::Diffe
188188
if (oldStyle->stroke().urlDisregardingType() != newStyle.stroke().urlDisregardingType())
189189
return true;
190190

191+
if (oldStyle->markerStart() != newStyle.markerStart())
192+
return true;
193+
194+
if (oldStyle->markerMid() != newStyle.markerMid())
195+
return true;
196+
197+
if (oldStyle->markerEnd() != newStyle.markerEnd())
198+
return true;
199+
191200
return false;
192201
};
193202

0 commit comments

Comments
 (0)