SVG use element inside a shadow tree cannot reference an element in the same tree
authorrniwa@webkit.org <rniwa@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 26 Nov 2018 22:48:08 +0000 (22:48 +0000)
committerrniwa@webkit.org <rniwa@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 26 Nov 2018 22:48:08 +0000 (22:48 +0000)
https://bugs.webkit.org/show_bug.cgi?id=174977
<rdar://problem/33665636>

Reviewed by Zalan Bujtas.

Source/WebCore:

Make fragment URL references used by SVGelements within a shadow tree to refer to other elements
in the same shadow tree. To do this, this patch makes targetElementFromIRIString take a TreeScope
instead of a Document, and updates its call sites.

This patch updates the most uses of targetElementFromIRIString except CSS cursor image, altGraph,
and glyphRef since the cursor image isn't really a SVG feature, and there aren't really real world
use cases in which altGraph and glyphRef are used within shadow trees.

Tests: fast/shadow-dom/svg-animate-href-change-in-shadow-tree.html
       fast/shadow-dom/svg-animate-href-in-shadow-tree.html
       fast/shadow-dom/svg-feimage-href-in-shadow-tree.html
       fast/shadow-dom/svg-linear-gradient-href-in-shadow-tree.html
       fast/shadow-dom/svg-mpath-href-change-in-shadow-tree.html
       fast/shadow-dom/svg-mpath-href-in-shadow-tree.html
       fast/shadow-dom/svg-radial-gradient-href-in-shadow-tree.html
       fast/shadow-dom/svg-text-path-href-change-in-shadow-tree.html
       fast/shadow-dom/svg-text-path-href-in-shadow-tree.html
       fast/shadow-dom/svg-thref-href-change-in-shadow-tree.html
       fast/shadow-dom/svg-thref-href-in-shadow-tree.html
       fast/shadow-dom/svg-use-href-change-in-shadow-tree.html
       fast/shadow-dom/svg-use-href-in-shadow-tree.html

* accessibility/AccessibilitySVGElement.cpp:
(WebCore::AccessibilitySVGElement::targetForUseElement const):
* css/CSSCursorImageValue.cpp:
* rendering/svg/RenderSVGTextPath.cpp:
(WebCore::RenderSVGTextPath::layoutPath const):
* svg/SVGAltGlyphElement.cpp:
(WebCore::SVGAltGlyphElement::hasValidGlyphElements const):
* svg/SVGFEImageElement.cpp:
(WebCore::SVGFEImageElement::buildPendingResource):
(WebCore::SVGFEImageElement::build):
* svg/SVGGlyphRefElement.cpp:
(WebCore::SVGGlyphRefElement::hasValidGlyphElement const):
* svg/SVGLinearGradientElement.cpp:
(WebCore::SVGLinearGradientElement::collectGradientAttributes):
* svg/SVGMPathElement.cpp:
(WebCore::SVGMPathElement::buildPendingResource):
(WebCore::SVGMPathElement::pathElement):
* svg/SVGRadialGradientElement.cpp:
(WebCore::SVGRadialGradientElement::collectGradientAttributes):
* svg/SVGTRefElement.cpp:
(WebCore::SVGTRefElement::buildPendingResource):
* svg/SVGTextPathElement.cpp:
(WebCore::SVGTextPathElement::buildPendingResource):
* svg/SVGURIReference.cpp:
(WebCore::SVGURIReference::targetElementFromIRIString):
* svg/SVGURIReference.h:
* svg/SVGUseElement.cpp:
(WebCore::SVGUseElement::updateShadowTree):
(WebCore::SVGUseElement::findTarget const):
* svg/animation/SVGSMILElement.cpp:
(WebCore::SVGSMILElement::buildPendingResource):
(WebCore::SVGSMILElement::insertedIntoAncestor):
* svg/graphics/filters/SVGFEImage.cpp:
(WebCore::FEImage::FEImage):
(WebCore::FEImage::createWithIRIReference):
(WebCore::FEImage::referencedRenderer const):
* svg/graphics/filters/SVGFEImage.h:

LayoutTests:

Added tests for specifying a fragment URL to refer to other elements within shadow trees.

This patch doesn't add a test for updating a fragment URL of linearGradient and radialGradient
since it doesn't work at all even outside shadow trees. See webkit.org/b/191934.

* fast/shadow-dom/svg-animate-href-change-in-shadow-tree-expected.html: Added.
* fast/shadow-dom/svg-animate-href-change-in-shadow-tree.html: Added.
* fast/shadow-dom/svg-animate-href-in-shadow-tree-expected.html: Added.
* fast/shadow-dom/svg-animate-href-in-shadow-tree.html: Added.
* fast/shadow-dom/svg-feimage-href-in-shadow-tree-expected.html: Added.
* fast/shadow-dom/svg-feimage-href-in-shadow-tree.html: Added.
* fast/shadow-dom/svg-linear-gradient-href-in-shadow-tree-expected.html: Added.
* fast/shadow-dom/svg-linear-gradient-href-in-shadow-tree.html: Added.
* fast/shadow-dom/svg-mpath-href-change-in-shadow-tree-expected.html: Added.
* fast/shadow-dom/svg-mpath-href-change-in-shadow-tree.html: Added.
* fast/shadow-dom/svg-mpath-href-in-shadow-tree-expected.html: Added.
* fast/shadow-dom/svg-mpath-href-in-shadow-tree.html: Added.
* fast/shadow-dom/svg-radial-gradient-href-in-shadow-tree-expected.html: Added.
* fast/shadow-dom/svg-radial-gradient-href-in-shadow-tree.html: Added.
* fast/shadow-dom/svg-text-path-href-change-in-shadow-tree-expected.html: Added.
* fast/shadow-dom/svg-text-path-href-change-in-shadow-tree.html: Added.
* fast/shadow-dom/svg-text-path-href-in-shadow-tree-expected.html: Added.
* fast/shadow-dom/svg-text-path-href-in-shadow-tree.html: Added.
* fast/shadow-dom/svg-thref-href-change-in-shadow-tree-expected.html: Added.
* fast/shadow-dom/svg-thref-href-change-in-shadow-tree.html: Added.
* fast/shadow-dom/svg-thref-href-in-shadow-tree-expected.html: Added.
* fast/shadow-dom/svg-thref-href-in-shadow-tree.html: Added.
* fast/shadow-dom/svg-use-href-change-in-shadow-tree-expected.html: Added.
* fast/shadow-dom/svg-use-href-change-in-shadow-tree.html: Added.
* fast/shadow-dom/svg-use-href-in-shadow-tree-expected.html: Added.
* fast/shadow-dom/svg-use-href-in-shadow-tree.html: Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@238524 268f45cc-cd09-0410-ab3c-d52691b4dbfc

45 files changed:
LayoutTests/ChangeLog
LayoutTests/fast/shadow-dom/svg-animate-href-change-in-shadow-tree-expected.html [new file with mode: 0644]
LayoutTests/fast/shadow-dom/svg-animate-href-change-in-shadow-tree.html [new file with mode: 0644]
LayoutTests/fast/shadow-dom/svg-animate-href-in-shadow-tree-expected.html [new file with mode: 0644]
LayoutTests/fast/shadow-dom/svg-animate-href-in-shadow-tree.html [new file with mode: 0644]
LayoutTests/fast/shadow-dom/svg-feimage-href-in-shadow-tree-expected.html [new file with mode: 0644]
LayoutTests/fast/shadow-dom/svg-feimage-href-in-shadow-tree.html [new file with mode: 0644]
LayoutTests/fast/shadow-dom/svg-linear-gradient-href-in-shadow-tree-expected.html [new file with mode: 0644]
LayoutTests/fast/shadow-dom/svg-linear-gradient-href-in-shadow-tree.html [new file with mode: 0644]
LayoutTests/fast/shadow-dom/svg-mpath-href-change-in-shadow-tree-expected.html [new file with mode: 0644]
LayoutTests/fast/shadow-dom/svg-mpath-href-change-in-shadow-tree.html [new file with mode: 0644]
LayoutTests/fast/shadow-dom/svg-mpath-href-in-shadow-tree-expected.html [new file with mode: 0644]
LayoutTests/fast/shadow-dom/svg-mpath-href-in-shadow-tree.html [new file with mode: 0644]
LayoutTests/fast/shadow-dom/svg-radial-gradient-href-in-shadow-tree-expected.html [new file with mode: 0644]
LayoutTests/fast/shadow-dom/svg-radial-gradient-href-in-shadow-tree.html [new file with mode: 0644]
LayoutTests/fast/shadow-dom/svg-text-path-href-change-in-shadow-tree-expected.html [new file with mode: 0644]
LayoutTests/fast/shadow-dom/svg-text-path-href-change-in-shadow-tree.html [new file with mode: 0644]
LayoutTests/fast/shadow-dom/svg-text-path-href-in-shadow-tree-expected.html [new file with mode: 0644]
LayoutTests/fast/shadow-dom/svg-text-path-href-in-shadow-tree.html [new file with mode: 0644]
LayoutTests/fast/shadow-dom/svg-thref-href-change-in-shadow-tree-expected.html [new file with mode: 0644]
LayoutTests/fast/shadow-dom/svg-thref-href-change-in-shadow-tree.html [new file with mode: 0644]
LayoutTests/fast/shadow-dom/svg-thref-href-in-shadow-tree-expected.html [new file with mode: 0644]
LayoutTests/fast/shadow-dom/svg-thref-href-in-shadow-tree.html [new file with mode: 0644]
LayoutTests/fast/shadow-dom/svg-use-href-change-in-shadow-tree-expected.html [new file with mode: 0644]
LayoutTests/fast/shadow-dom/svg-use-href-change-in-shadow-tree.html [new file with mode: 0644]
LayoutTests/fast/shadow-dom/svg-use-href-in-shadow-tree-expected.html [new file with mode: 0644]
LayoutTests/fast/shadow-dom/svg-use-href-in-shadow-tree.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/accessibility/AccessibilitySVGElement.cpp
Source/WebCore/css/CSSCursorImageValue.cpp
Source/WebCore/rendering/svg/RenderSVGTextPath.cpp
Source/WebCore/svg/SVGAltGlyphElement.cpp
Source/WebCore/svg/SVGFEImageElement.cpp
Source/WebCore/svg/SVGGlyphRefElement.cpp
Source/WebCore/svg/SVGLinearGradientElement.cpp
Source/WebCore/svg/SVGMPathElement.cpp
Source/WebCore/svg/SVGRadialGradientElement.cpp
Source/WebCore/svg/SVGTRefElement.cpp
Source/WebCore/svg/SVGTextPathElement.cpp
Source/WebCore/svg/SVGURIReference.cpp
Source/WebCore/svg/SVGURIReference.h
Source/WebCore/svg/SVGUseElement.cpp
Source/WebCore/svg/animation/SVGSMILElement.cpp
Source/WebCore/svg/graphics/filters/SVGFEImage.cpp
Source/WebCore/svg/graphics/filters/SVGFEImage.h

index 9c5029d..2d809b1 100644 (file)
@@ -1,3 +1,43 @@
+2018-11-24  Ryosuke Niwa  <rniwa@webkit.org>
+
+        SVG use element inside a shadow tree cannot reference an element in the same tree
+        https://bugs.webkit.org/show_bug.cgi?id=174977
+        <rdar://problem/33665636>
+
+        Reviewed by Zalan Bujtas.
+
+        Added tests for specifying a fragment URL to refer to other elements within shadow trees.
+
+        This patch doesn't add a test for updating a fragment URL of linearGradient and radialGradient
+        since it doesn't work at all even outside shadow trees. See webkit.org/b/191934.
+
+        * fast/shadow-dom/svg-animate-href-change-in-shadow-tree-expected.html: Added.
+        * fast/shadow-dom/svg-animate-href-change-in-shadow-tree.html: Added.
+        * fast/shadow-dom/svg-animate-href-in-shadow-tree-expected.html: Added.
+        * fast/shadow-dom/svg-animate-href-in-shadow-tree.html: Added.
+        * fast/shadow-dom/svg-feimage-href-in-shadow-tree-expected.html: Added.
+        * fast/shadow-dom/svg-feimage-href-in-shadow-tree.html: Added.
+        * fast/shadow-dom/svg-linear-gradient-href-in-shadow-tree-expected.html: Added.
+        * fast/shadow-dom/svg-linear-gradient-href-in-shadow-tree.html: Added.
+        * fast/shadow-dom/svg-mpath-href-change-in-shadow-tree-expected.html: Added.
+        * fast/shadow-dom/svg-mpath-href-change-in-shadow-tree.html: Added.
+        * fast/shadow-dom/svg-mpath-href-in-shadow-tree-expected.html: Added.
+        * fast/shadow-dom/svg-mpath-href-in-shadow-tree.html: Added.
+        * fast/shadow-dom/svg-radial-gradient-href-in-shadow-tree-expected.html: Added.
+        * fast/shadow-dom/svg-radial-gradient-href-in-shadow-tree.html: Added.
+        * fast/shadow-dom/svg-text-path-href-change-in-shadow-tree-expected.html: Added.
+        * fast/shadow-dom/svg-text-path-href-change-in-shadow-tree.html: Added.
+        * fast/shadow-dom/svg-text-path-href-in-shadow-tree-expected.html: Added.
+        * fast/shadow-dom/svg-text-path-href-in-shadow-tree.html: Added.
+        * fast/shadow-dom/svg-thref-href-change-in-shadow-tree-expected.html: Added.
+        * fast/shadow-dom/svg-thref-href-change-in-shadow-tree.html: Added.
+        * fast/shadow-dom/svg-thref-href-in-shadow-tree-expected.html: Added.
+        * fast/shadow-dom/svg-thref-href-in-shadow-tree.html: Added.
+        * fast/shadow-dom/svg-use-href-change-in-shadow-tree-expected.html: Added.
+        * fast/shadow-dom/svg-use-href-change-in-shadow-tree.html: Added.
+        * fast/shadow-dom/svg-use-href-in-shadow-tree-expected.html: Added.
+        * fast/shadow-dom/svg-use-href-in-shadow-tree.html: Added.
+
 2018-11-26  Daniel Bates  <dabates@apple.com>
 
         Caret disappears at end of password field when caps lock indicator is shown; password field
diff --git a/LayoutTests/fast/shadow-dom/svg-animate-href-change-in-shadow-tree-expected.html b/LayoutTests/fast/shadow-dom/svg-animate-href-change-in-shadow-tree-expected.html
new file mode 100644 (file)
index 0000000..e704d24
--- /dev/null
@@ -0,0 +1,7 @@
+<!DOCTYPE html>
+<html>
+<body>
+    <p>Test passes if you see a single 100px by 100px green box below.</p>
+    <div style="width: 100px; height: 100px; background: green;"></div>
+</body>
+</html>
diff --git a/LayoutTests/fast/shadow-dom/svg-animate-href-change-in-shadow-tree.html b/LayoutTests/fast/shadow-dom/svg-animate-href-change-in-shadow-tree.html
new file mode 100644 (file)
index 0000000..e9060bd
--- /dev/null
@@ -0,0 +1,45 @@
+<!DOCTYPE html>
+<html>
+<body>
+<p>Test passes if you see a single 100px by 100px green box below.</p>
+<div id="host" style="width: 100px; height: 100px;"></div>
+<svg>
+    <defs>
+        <rect id="rect" width="50" height="100" fill="red" />
+    </defs>
+</svg>
+<template>
+    <svg viewbox="0 0 100 100" xmlns:xlink="http://www.w3.org/1999/xlink">
+        <rect width="50" height="100" fill="green" />
+        <rect id="rect1" x="-100" width="25" height="100" fill="red" />
+        <rect id="rect2" x="-100" width="50" height="100" fill="green" />
+        <animate attributeName="x" from="0" to="50" dur="0.01s" fill="freeze" xlink:href="#rect1" />
+    </svg>
+</template>
+<script>
+
+if (window.testRunner)
+    testRunner.waitUntilDone();
+
+const shadowRoot = host;//host.attachShadow({mode: 'closed'});
+shadowRoot.appendChild(document.querySelector('template').content.cloneNode(true));
+
+function waitForAnimation() {
+    return new Promise((resolve) => {
+         // 0.01s is 10ms. Wait for twice that time to be safe.
+        requestAnimationFrame(() => setTimeout(resolve, 20));
+    })
+}
+
+window.onload = async () => {
+    await waitForAnimation();
+    shadowRoot.querySelector('animate').setAttributeNS('http://www.w3.org/1999/xlink', 'href', '#rect2');
+    shadowRoot.querySelector('animate').beginElement();
+    await waitForAnimation();
+    if (window.testRunner)
+        requestAnimationFrame(() => testRunner.notifyDone());
+}
+
+</script>
+</body>
+</html>
diff --git a/LayoutTests/fast/shadow-dom/svg-animate-href-in-shadow-tree-expected.html b/LayoutTests/fast/shadow-dom/svg-animate-href-in-shadow-tree-expected.html
new file mode 100644 (file)
index 0000000..e704d24
--- /dev/null
@@ -0,0 +1,7 @@
+<!DOCTYPE html>
+<html>
+<body>
+    <p>Test passes if you see a single 100px by 100px green box below.</p>
+    <div style="width: 100px; height: 100px; background: green;"></div>
+</body>
+</html>
diff --git a/LayoutTests/fast/shadow-dom/svg-animate-href-in-shadow-tree.html b/LayoutTests/fast/shadow-dom/svg-animate-href-in-shadow-tree.html
new file mode 100644 (file)
index 0000000..19c7912
--- /dev/null
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<html>
+<body>
+<p>Test passes if you see a single 100px by 100px green box below.</p>
+<div id="host" style="width: 100px; height: 100px;"></div>
+<svg>
+    <defs>
+        <rect id="rect" width="50" height="100" fill="red" />
+    </defs>
+</svg>
+<template>
+    <svg viewbox="0 0 100 100" xmlns:xlink="http://www.w3.org/1999/xlink">
+        <rect width="50" height="100" fill="green" />
+        <rect id="rect" width="50" height="100" fill="green" />
+        <animate attributeName="x" from="0" to="50" dur="0.01s" fill="freeze" xlink:href="#rect" />
+    </svg>
+</template>
+<script>
+
+if (window.testRunner)
+    testRunner.waitUntilDone();
+
+const shadowRoot = host.attachShadow({mode: 'closed'});
+shadowRoot.appendChild(document.querySelector('template').content.cloneNode(true));
+
+window.onload = () => {
+    requestAnimationFrame(() => {
+        setTimeout(() => {
+            if (window.testRunner)
+                requestAnimationFrame(() => testRunner.notifyDone());
+        }, 20); // 0.01s is 10ms. Wait for twice that time to be safe.
+    });
+}
+
+</script>
+</body>
+</html>
diff --git a/LayoutTests/fast/shadow-dom/svg-feimage-href-in-shadow-tree-expected.html b/LayoutTests/fast/shadow-dom/svg-feimage-href-in-shadow-tree-expected.html
new file mode 100644 (file)
index 0000000..e704d24
--- /dev/null
@@ -0,0 +1,7 @@
+<!DOCTYPE html>
+<html>
+<body>
+    <p>Test passes if you see a single 100px by 100px green box below.</p>
+    <div style="width: 100px; height: 100px; background: green;"></div>
+</body>
+</html>
diff --git a/LayoutTests/fast/shadow-dom/svg-feimage-href-in-shadow-tree.html b/LayoutTests/fast/shadow-dom/svg-feimage-href-in-shadow-tree.html
new file mode 100644 (file)
index 0000000..ce43018
--- /dev/null
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<html>
+<body>
+<p>Test passes if you see a single 100px by 100px green box below.</p>
+<div id="host" style="width: 100px; height: 100px;"></div>
+<svg>
+    <defs>
+        <rect id="rect" width="100" height="100" fill="red" />
+    </defs>
+</svg>
+<template>
+    <svg viewbox="0 0 100 100">
+        <defs>
+            <rect id="rect" width="100" height="100" fill="green" />
+            <filter id="image">
+                <feImage href="#rect" />
+            </filter>
+        </defs>
+        <rect id="rect" width="100" height="100" style="filter:url(#image)">
+    </svg>
+</template>
+<script>
+
+const shadowRoot = host.attachShadow({mode: 'closed'});
+shadowRoot.appendChild(document.querySelector('template').content.cloneNode(true));
+
+</script>
+</body>
+</html>
diff --git a/LayoutTests/fast/shadow-dom/svg-linear-gradient-href-in-shadow-tree-expected.html b/LayoutTests/fast/shadow-dom/svg-linear-gradient-href-in-shadow-tree-expected.html
new file mode 100644 (file)
index 0000000..e704d24
--- /dev/null
@@ -0,0 +1,7 @@
+<!DOCTYPE html>
+<html>
+<body>
+    <p>Test passes if you see a single 100px by 100px green box below.</p>
+    <div style="width: 100px; height: 100px; background: green;"></div>
+</body>
+</html>
diff --git a/LayoutTests/fast/shadow-dom/svg-linear-gradient-href-in-shadow-tree.html b/LayoutTests/fast/shadow-dom/svg-linear-gradient-href-in-shadow-tree.html
new file mode 100644 (file)
index 0000000..f8e3ca3
--- /dev/null
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<html>
+<body>
+<p>Test passes if you see a single 100px by 100px green box below.</p>
+<div id="host" style="width: 100px; height: 100px;"></div>
+<svg>
+    <linearGradient id="gradient">
+        <stop offset="0%" stop-color="red" />
+    </linearGradient>
+</svg>
+<template>
+    <svg viewbox="0 0 100 100">
+        <linearGradient id="gradient">
+            <stop offset="0%" stop-color="green" />
+        </linearGradient>
+        <linearGradient id="gradientUse" fill="red" href="#gradient"></linearGradient>
+        <rect id="rect" width="100" height="100" fill="url(#gradientUse)">
+    </svg>
+</template>
+<script>
+
+const shadowRoot = host.attachShadow({mode: 'closed'});
+shadowRoot.appendChild(document.querySelector('template').content.cloneNode(true));
+
+</script>
+</body>
+</html>
diff --git a/LayoutTests/fast/shadow-dom/svg-mpath-href-change-in-shadow-tree-expected.html b/LayoutTests/fast/shadow-dom/svg-mpath-href-change-in-shadow-tree-expected.html
new file mode 100644 (file)
index 0000000..e704d24
--- /dev/null
@@ -0,0 +1,7 @@
+<!DOCTYPE html>
+<html>
+<body>
+    <p>Test passes if you see a single 100px by 100px green box below.</p>
+    <div style="width: 100px; height: 100px; background: green;"></div>
+</body>
+</html>
diff --git a/LayoutTests/fast/shadow-dom/svg-mpath-href-change-in-shadow-tree.html b/LayoutTests/fast/shadow-dom/svg-mpath-href-change-in-shadow-tree.html
new file mode 100644 (file)
index 0000000..1ca69d3
--- /dev/null
@@ -0,0 +1,46 @@
+<!DOCTYPE html>
+<html>
+<body>
+<p>Test passes if you see a single 100px by 100px green box below.</p>
+<div id="host" style="width: 100px; height: 100px;"></div>
+<template>
+    <svg viewbox="0 0 100 100">
+        <rect id="rect" x="50" y="0" width="50" height="100" fill="red"></rect>
+        <path id="path1" d="M0,0 L25,0" />
+        <path id="path2" d="M0,0 L50,0" />
+        <rect id="rect" width="50" height="100" fill="green" />
+        <g>
+            <rect id="rect" x="0" width="50" height="100" fill="green" />
+            <animateMotion dur="0.01s" calcMode="linear" fill="freeze">
+                <mpath href="#path1" />
+            </animateMotion>
+        </g>
+    </svg>
+</template>
+<script>
+
+if (window.testRunner)
+    testRunner.waitUntilDone();
+
+const shadowRoot = host.attachShadow({mode: 'closed'});
+shadowRoot.appendChild(document.querySelector('template').content.cloneNode(true));
+
+function waitForAnimation() {
+    return new Promise((resolve) => {
+         // 0.01s is 10ms. Wait for twice that time to be safe.
+        requestAnimationFrame(() => setTimeout(resolve, 20));
+    })
+}
+
+window.onload = async () => {
+    await waitForAnimation();
+    shadowRoot.querySelector('mpath').setAttribute('href', '#path2');
+    shadowRoot.querySelector('animateMotion').beginElement();
+    await waitForAnimation();
+    if (window.testRunner)
+        requestAnimationFrame(() => testRunner.notifyDone());
+}
+
+</script>
+</body>
+</html>
diff --git a/LayoutTests/fast/shadow-dom/svg-mpath-href-in-shadow-tree-expected.html b/LayoutTests/fast/shadow-dom/svg-mpath-href-in-shadow-tree-expected.html
new file mode 100644 (file)
index 0000000..e704d24
--- /dev/null
@@ -0,0 +1,7 @@
+<!DOCTYPE html>
+<html>
+<body>
+    <p>Test passes if you see a single 100px by 100px green box below.</p>
+    <div style="width: 100px; height: 100px; background: green;"></div>
+</body>
+</html>
diff --git a/LayoutTests/fast/shadow-dom/svg-mpath-href-in-shadow-tree.html b/LayoutTests/fast/shadow-dom/svg-mpath-href-in-shadow-tree.html
new file mode 100644 (file)
index 0000000..6564b83
--- /dev/null
@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<html>
+<body>
+<p>Test passes if you see a single 100px by 100px green box below.</p>
+<div id="host" style="width: 100px; height: 100px;"></div>
+<svg>
+    <defs>
+        <path id="path" d="M0,0 L25,0" />
+    </defs>
+</svg>
+<template>
+    <svg viewbox="0 0 100 100">
+        <rect id="rect" x="50" y="0" width="50" height="100" fill="red"></rect>
+        <path id="path" d="M0,0 L50,0" />
+        <rect id="rect" width="50" height="100" fill="green" />
+        <g>
+            <rect id="rect" x="0" width="50" height="100" fill="green" />
+            <animateMotion dur="0.01s" calcMode="linear" fill="freeze">
+                <mpath href="#path" />
+            </animateMotion>
+        </g>
+    </svg>
+</template>
+<script>
+
+if (window.testRunner)
+    testRunner.waitUntilDone();
+
+const shadowRoot = host.attachShadow({mode: 'closed'});
+shadowRoot.appendChild(document.querySelector('template').content.cloneNode(true));
+
+window.onload = () => {
+    requestAnimationFrame(() => {
+        setTimeout(() => {
+            if (window.testRunner)
+                requestAnimationFrame(() => testRunner.notifyDone());
+        }, 20); // 0.01s is 10ms. Wait for twice that time to be safe.
+    });
+}
+
+</script>
+</body>
+</html>
diff --git a/LayoutTests/fast/shadow-dom/svg-radial-gradient-href-in-shadow-tree-expected.html b/LayoutTests/fast/shadow-dom/svg-radial-gradient-href-in-shadow-tree-expected.html
new file mode 100644 (file)
index 0000000..e704d24
--- /dev/null
@@ -0,0 +1,7 @@
+<!DOCTYPE html>
+<html>
+<body>
+    <p>Test passes if you see a single 100px by 100px green box below.</p>
+    <div style="width: 100px; height: 100px; background: green;"></div>
+</body>
+</html>
diff --git a/LayoutTests/fast/shadow-dom/svg-radial-gradient-href-in-shadow-tree.html b/LayoutTests/fast/shadow-dom/svg-radial-gradient-href-in-shadow-tree.html
new file mode 100644 (file)
index 0000000..97b1a53
--- /dev/null
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<html>
+<body>
+<p>Test passes if you see a single 100px by 100px green box below.</p>
+<div id="host" style="width: 100px; height: 100px;"></div>
+<svg>
+    <radialGradient id="gradient">
+        <stop offset="0%" stop-color="red" />
+    </radialGradient>
+</svg>
+<template>
+    <svg viewbox="0 0 100 100">
+        <radialGradient id="gradient">
+            <stop offset="0%" stop-color="green" />
+        </radialGradient>
+        <radialGradient id="gradientUse" fill="red" href="#gradient"></radialGradient>
+        <rect id="rect" width="100" height="100" fill="url(#gradientUse)">
+    </svg>
+</template>
+<script>
+
+const shadowRoot = host.attachShadow({mode: 'closed'});
+shadowRoot.appendChild(document.querySelector('template').content.cloneNode(true));
+
+</script>
+</body>
+</html>
diff --git a/LayoutTests/fast/shadow-dom/svg-text-path-href-change-in-shadow-tree-expected.html b/LayoutTests/fast/shadow-dom/svg-text-path-href-change-in-shadow-tree-expected.html
new file mode 100644 (file)
index 0000000..e704d24
--- /dev/null
@@ -0,0 +1,7 @@
+<!DOCTYPE html>
+<html>
+<body>
+    <p>Test passes if you see a single 100px by 100px green box below.</p>
+    <div style="width: 100px; height: 100px; background: green;"></div>
+</body>
+</html>
diff --git a/LayoutTests/fast/shadow-dom/svg-text-path-href-change-in-shadow-tree.html b/LayoutTests/fast/shadow-dom/svg-text-path-href-change-in-shadow-tree.html
new file mode 100644 (file)
index 0000000..058ecb5
--- /dev/null
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<html>
+<body>
+<p>Test passes if you see a single 100px by 100px green box below.</p>
+<div id="host" style="width: 100px; height: 100px;"></div>
+<svg>
+    <defs>
+        <path id="path1" d="M0,30 L100,30 Z">
+    </defs>
+</svg>
+<template>
+    <svg style="width: 100px; height: 100px;" viewbox="0 0 100 100" xmlns:xlink="http://www.w3.org/1999/xlink">
+        <defs>
+            <path id="path1" d="M0,50 L100,50 Z" />
+            <path id="path2" d="M0,-5 L100,-5 Z" />
+        </defs>
+        <rect x="0" y="0" width="100" height="100" fill="green"></rect>
+        <text>
+            <textPath href="#path1">FAIL</textPath>
+        </text>
+    </svg>
+</template>
+<script>
+
+if (window.testRunner)
+    testRunner.waitUntilDone();
+
+const shadowRoot = host.attachShadow({mode: 'closed'});
+shadowRoot.appendChild(document.querySelector('template').content.cloneNode(true));
+
+window.onload = () => {
+    requestAnimationFrame(() => {
+        shadowRoot.querySelector('textPath').setAttribute('href', '#path2');
+        if (window.testRunner)
+            requestAnimationFrame(() => testRunner.notifyDone());
+    });
+}
+
+</script>
+</body>
+</html>
diff --git a/LayoutTests/fast/shadow-dom/svg-text-path-href-in-shadow-tree-expected.html b/LayoutTests/fast/shadow-dom/svg-text-path-href-in-shadow-tree-expected.html
new file mode 100644 (file)
index 0000000..e704d24
--- /dev/null
@@ -0,0 +1,7 @@
+<!DOCTYPE html>
+<html>
+<body>
+    <p>Test passes if you see a single 100px by 100px green box below.</p>
+    <div style="width: 100px; height: 100px; background: green;"></div>
+</body>
+</html>
diff --git a/LayoutTests/fast/shadow-dom/svg-text-path-href-in-shadow-tree.html b/LayoutTests/fast/shadow-dom/svg-text-path-href-in-shadow-tree.html
new file mode 100644 (file)
index 0000000..d07b49b
--- /dev/null
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<html>
+<body>
+<p>Test passes if you see a single 100px by 100px green box below.</p>
+<div id="host" style="width: 100px; height: 100px;"></div>
+<svg>
+    <defs>
+        <path id="path" fill="red" stroke="red" d="M0,50 L100,50 Z">
+    </defs>
+</svg>
+<template>
+    <svg viewbox="0 0 100 100" xmlns:xlink="http://www.w3.org/1999/xlink">
+        <defs>
+            <path id="path" fill="green" d="M0,-5 L100,-5 Z">
+        </defs>
+        <rect x="0" y="0" width="100" height="100" fill="green"></rect>
+        <text>
+            <textPath xlink:href="#path">FAIL</textPath>
+        </text>
+    </svg>
+</template>
+<script>
+
+const shadowRoot = host.attachShadow({mode: 'closed'});
+shadowRoot.appendChild(document.querySelector('template').content.cloneNode(true));
+
+</script>
+</body>
+</html>
diff --git a/LayoutTests/fast/shadow-dom/svg-thref-href-change-in-shadow-tree-expected.html b/LayoutTests/fast/shadow-dom/svg-thref-href-change-in-shadow-tree-expected.html
new file mode 100644 (file)
index 0000000..cce26ea
--- /dev/null
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html>
+<body>
+<p>Test passes if you see a single 100px by 100px green box below with "PASS" in the middle.</p>
+<div id="host" style="width: 100px; height: 100px;">
+    <svg viewbox="0 0 100 100">
+        <rect x="0" y="0" width="100" height="100" fill="green"></rect>
+        <text alignment-baseline="middle" y="50">PASS</text>
+    </svg>
+</div>
+</body>
+</html>
diff --git a/LayoutTests/fast/shadow-dom/svg-thref-href-change-in-shadow-tree.html b/LayoutTests/fast/shadow-dom/svg-thref-href-change-in-shadow-tree.html
new file mode 100644 (file)
index 0000000..7c05617
--- /dev/null
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<html>
+<body>
+<p>Test passes if you see a single 100px by 100px green box below with "PASS" in the middle.</p>
+<div id="host" style="width: 100px; height: 100px;"></div>
+<svg>
+    <defs>
+        <text id="text">FAIL FAIL FAIL</text>
+    </defs>
+</svg>
+<template>
+    <svg viewbox="0 0 100 100" xmlns:xlink="http://www.w3.org/1999/xlink">
+        <defs>
+            <text id="text1">FAIL FAIL</text>
+            <text id="text2">PASS</text>
+        </defs>
+        <rect x="0" y="0" width="100" height="100" fill="green"></rect>
+        <text x="0" y="0">
+            <tref alignment-baseline="middle" y="50" xlink:href="#text1"></tref>
+        </text>
+    </svg>
+</template>
+<script>
+
+if (window.testRunner)
+    testRunner.waitUntilDone();
+
+const shadowRoot = host.attachShadow({mode: 'closed'});
+shadowRoot.appendChild(document.querySelector('template').content.cloneNode(true));
+
+window.onload = () => {
+    requestAnimationFrame(() => {
+        shadowRoot.querySelector('tref').setAttribute('href', '#text2');
+        if (window.testRunner)
+            requestAnimationFrame(() => testRunner.notifyDone());
+    });
+}
+
+</script>
+</body>
+</html>
diff --git a/LayoutTests/fast/shadow-dom/svg-thref-href-in-shadow-tree-expected.html b/LayoutTests/fast/shadow-dom/svg-thref-href-in-shadow-tree-expected.html
new file mode 100644 (file)
index 0000000..cce26ea
--- /dev/null
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html>
+<body>
+<p>Test passes if you see a single 100px by 100px green box below with "PASS" in the middle.</p>
+<div id="host" style="width: 100px; height: 100px;">
+    <svg viewbox="0 0 100 100">
+        <rect x="0" y="0" width="100" height="100" fill="green"></rect>
+        <text alignment-baseline="middle" y="50">PASS</text>
+    </svg>
+</div>
+</body>
+</html>
diff --git a/LayoutTests/fast/shadow-dom/svg-thref-href-in-shadow-tree.html b/LayoutTests/fast/shadow-dom/svg-thref-href-in-shadow-tree.html
new file mode 100644 (file)
index 0000000..33e176c
--- /dev/null
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<html>
+<body>
+<p>Test passes if you see a single 100px by 100px green box below with "PASS" in the middle.</p>
+<div id="host" style="width: 100px; height: 100px;"></div>
+<svg>
+    <defs>
+        <text id="text">FAIL FAIL FAIL</text>
+    </defs>
+</svg>
+<template>
+    <svg viewbox="0 0 100 100" xmlns:xlink="http://www.w3.org/1999/xlink">
+        <defs>
+            <text id="text">PASS</text>
+        </defs>
+        <rect x="0" y="0" width="100" height="100" fill="green"></rect>
+        <text x="0" y="0">
+            <tref alignment-baseline="middle" y="50" xlink:href="#text"></tref>
+        </text>
+    </svg>
+</template>
+<script>
+
+const shadowRoot = host.attachShadow({mode: 'closed'});
+shadowRoot.appendChild(document.querySelector('template').content.cloneNode(true));
+
+</script>
+</body>
+</html>
diff --git a/LayoutTests/fast/shadow-dom/svg-use-href-change-in-shadow-tree-expected.html b/LayoutTests/fast/shadow-dom/svg-use-href-change-in-shadow-tree-expected.html
new file mode 100644 (file)
index 0000000..e704d24
--- /dev/null
@@ -0,0 +1,7 @@
+<!DOCTYPE html>
+<html>
+<body>
+    <p>Test passes if you see a single 100px by 100px green box below.</p>
+    <div style="width: 100px; height: 100px; background: green;"></div>
+</body>
+</html>
diff --git a/LayoutTests/fast/shadow-dom/svg-use-href-change-in-shadow-tree.html b/LayoutTests/fast/shadow-dom/svg-use-href-change-in-shadow-tree.html
new file mode 100644 (file)
index 0000000..b994ee6
--- /dev/null
@@ -0,0 +1,45 @@
+<!DOCTYPE html>
+<html>
+<body>
+<p>Test passes if you see a single 100px by 100px green box below.</p>
+<div id="host" style="width: 100px; height: 100px;"></div>
+<svg>
+    <defs>
+        <rect id="rect1" width="100" height="50" fill="red">
+    </defs>
+</svg>
+<template>
+    <svg viewbox="0 0 100 100">
+        <defs>
+            <rect id="rect1" width="100" height="50" fill="red">
+            <rect id="rect2" width="100" height="50" fill="green">
+        </defs>
+        <g id="rectGroup">
+            <use href="#rect1">
+                <rect width="100" height="25" fill="red">
+            </use>
+        </g>
+        <use href="#rectGroup" y="50">
+            <rect width="50" height="50" fill="red">
+        </use>
+    </svg>
+</template>
+<script>
+
+if (window.testRunner)
+    testRunner.waitUntilDone();
+
+const shadowRoot = host.attachShadow({mode: 'closed'});
+shadowRoot.appendChild(document.querySelector('template').content.cloneNode(true));
+
+window.onload = () => {
+    requestAnimationFrame(() => {
+        shadowRoot.querySelector('use').setAttribute('href', '#rect2');
+        if (window.testRunner)
+            requestAnimationFrame(() => testRunner.notifyDone());
+    });
+}
+
+</script>
+</body>
+</html>
diff --git a/LayoutTests/fast/shadow-dom/svg-use-href-in-shadow-tree-expected.html b/LayoutTests/fast/shadow-dom/svg-use-href-in-shadow-tree-expected.html
new file mode 100644 (file)
index 0000000..e704d24
--- /dev/null
@@ -0,0 +1,7 @@
+<!DOCTYPE html>
+<html>
+<body>
+    <p>Test passes if you see a single 100px by 100px green box below.</p>
+    <div style="width: 100px; height: 100px; background: green;"></div>
+</body>
+</html>
diff --git a/LayoutTests/fast/shadow-dom/svg-use-href-in-shadow-tree.html b/LayoutTests/fast/shadow-dom/svg-use-href-in-shadow-tree.html
new file mode 100644 (file)
index 0000000..43e7a68
--- /dev/null
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<html>
+<body>
+<p>Test passes if you see a single 100px by 100px green box below.</p>
+<div id="host" style="width: 100px; height: 100px;"></div>
+<svg>
+    <defs>
+        <rect id="rect" width="100" height="100" fill="red">
+    </defs>
+</svg>
+<template>
+    <svg viewbox="0 0 100 100">
+        <defs>
+            <rect id="rect" width="100" height="100" fill="green">
+        </defs>
+        <use href="#rect">
+            <rect id="rect" width="50" height="50" fill="red">
+        </use>
+    </svg>
+</template>
+<script>
+
+const shadowRoot = host.attachShadow({mode: 'closed'});
+shadowRoot.appendChild(document.querySelector('template').content.cloneNode(true)); 
+
+</script>
+</body>
+</html>
index 6479d6a..54d01d0 100644 (file)
@@ -1,3 +1,71 @@
+2018-11-24  Ryosuke Niwa  <rniwa@webkit.org>
+
+        SVG use element inside a shadow tree cannot reference an element in the same tree
+        https://bugs.webkit.org/show_bug.cgi?id=174977
+        <rdar://problem/33665636>
+
+        Reviewed by Zalan Bujtas.
+
+        Make fragment URL references used by SVGelements within a shadow tree to refer to other elements
+        in the same shadow tree. To do this, this patch makes targetElementFromIRIString take a TreeScope
+        instead of a Document, and updates its call sites.
+
+        This patch updates the most uses of targetElementFromIRIString except CSS cursor image, altGraph,
+        and glyphRef since the cursor image isn't really a SVG feature, and there aren't really real world
+        use cases in which altGraph and glyphRef are used within shadow trees.
+
+        Tests: fast/shadow-dom/svg-animate-href-change-in-shadow-tree.html
+               fast/shadow-dom/svg-animate-href-in-shadow-tree.html
+               fast/shadow-dom/svg-feimage-href-in-shadow-tree.html
+               fast/shadow-dom/svg-linear-gradient-href-in-shadow-tree.html
+               fast/shadow-dom/svg-mpath-href-change-in-shadow-tree.html
+               fast/shadow-dom/svg-mpath-href-in-shadow-tree.html
+               fast/shadow-dom/svg-radial-gradient-href-in-shadow-tree.html
+               fast/shadow-dom/svg-text-path-href-change-in-shadow-tree.html
+               fast/shadow-dom/svg-text-path-href-in-shadow-tree.html
+               fast/shadow-dom/svg-thref-href-change-in-shadow-tree.html
+               fast/shadow-dom/svg-thref-href-in-shadow-tree.html
+               fast/shadow-dom/svg-use-href-change-in-shadow-tree.html
+               fast/shadow-dom/svg-use-href-in-shadow-tree.html
+
+        * accessibility/AccessibilitySVGElement.cpp:
+        (WebCore::AccessibilitySVGElement::targetForUseElement const):
+        * css/CSSCursorImageValue.cpp:
+        * rendering/svg/RenderSVGTextPath.cpp:
+        (WebCore::RenderSVGTextPath::layoutPath const):
+        * svg/SVGAltGlyphElement.cpp:
+        (WebCore::SVGAltGlyphElement::hasValidGlyphElements const):
+        * svg/SVGFEImageElement.cpp:
+        (WebCore::SVGFEImageElement::buildPendingResource):
+        (WebCore::SVGFEImageElement::build):
+        * svg/SVGGlyphRefElement.cpp:
+        (WebCore::SVGGlyphRefElement::hasValidGlyphElement const):
+        * svg/SVGLinearGradientElement.cpp:
+        (WebCore::SVGLinearGradientElement::collectGradientAttributes):
+        * svg/SVGMPathElement.cpp:
+        (WebCore::SVGMPathElement::buildPendingResource):
+        (WebCore::SVGMPathElement::pathElement):
+        * svg/SVGRadialGradientElement.cpp:
+        (WebCore::SVGRadialGradientElement::collectGradientAttributes):
+        * svg/SVGTRefElement.cpp:
+        (WebCore::SVGTRefElement::buildPendingResource):
+        * svg/SVGTextPathElement.cpp:
+        (WebCore::SVGTextPathElement::buildPendingResource):
+        * svg/SVGURIReference.cpp:
+        (WebCore::SVGURIReference::targetElementFromIRIString):
+        * svg/SVGURIReference.h:
+        * svg/SVGUseElement.cpp:
+        (WebCore::SVGUseElement::updateShadowTree):
+        (WebCore::SVGUseElement::findTarget const):
+        * svg/animation/SVGSMILElement.cpp:
+        (WebCore::SVGSMILElement::buildPendingResource):
+        (WebCore::SVGSMILElement::insertedIntoAncestor):
+        * svg/graphics/filters/SVGFEImage.cpp:
+        (WebCore::FEImage::FEImage):
+        (WebCore::FEImage::createWithIRIReference):
+        (WebCore::FEImage::referencedRenderer const):
+        * svg/graphics/filters/SVGFEImage.h:
+
 2018-11-26  Truitt Savell  <tsavell@apple.com>
 
         Unreviewed, rolling out r238357.
index 726f542..791bef0 100644 (file)
@@ -65,7 +65,7 @@ AccessibilityObject* AccessibilitySVGElement::targetForUseElement() const
     if (href.isEmpty())
         href = getAttribute(HTMLNames::hrefAttr);
 
-    auto target = SVGURIReference::targetElementFromIRIString(href, use.document());
+    auto target = SVGURIReference::targetElementFromIRIString(href, use.treeScope());
     if (!target.element)
         return nullptr;
     return axObjectCache()->getOrCreate(target.element.get());
index 6e7f65f..2ad8199 100644 (file)
@@ -64,6 +64,7 @@ String CSSCursorImageValue::customCSSText() const
     return result.toString();
 }
 
+// FIXME: Should this function take a TreeScope instead?
 SVGCursorElement* CSSCursorImageValue::updateCursorElement(const Document& document)
 {
     if (!m_originalURL.hasFragmentIdentifier())
index a74dc11..1961e17 100644 (file)
@@ -46,7 +46,7 @@ SVGTextPathElement& RenderSVGTextPath::textPathElement() const
 
 Path RenderSVGTextPath::layoutPath() const
 {
-    auto target = SVGURIReference::targetElementFromIRIString(textPathElement().href(), document());
+    auto target = SVGURIReference::targetElementFromIRIString(textPathElement().href(), textPathElement().treeScope());
     if (!is<SVGPathElement>(target.element))
         return Path();
 
index d3e41cb..95efcb2 100644 (file)
@@ -81,6 +81,7 @@ RenderPtr<RenderElement> SVGAltGlyphElement::createElementRenderer(RenderStyle&&
 
 bool SVGAltGlyphElement::hasValidGlyphElements(Vector<String>& glyphNames) const
 {
+    // No need to support altGlyph referencing another node inside a shadow tree.
     auto target = targetElementFromIRIString(getAttribute(SVGNames::hrefAttr, XLinkNames::hrefAttr), document());
 
     if (is<SVGGlyphElement>(target.element)) {
index e6570a5..65cfde1 100644 (file)
@@ -94,7 +94,7 @@ void SVGFEImageElement::buildPendingResource()
     if (!isConnected())
         return;
 
-    auto target = SVGURIReference::targetElementFromIRIString(href(), document());
+    auto target = SVGURIReference::targetElementFromIRIString(href(), treeScope());
     if (!target.element) {
         if (target.identifier.isEmpty())
             requestImageResource();
@@ -189,7 +189,7 @@ RefPtr<FilterEffect> SVGFEImageElement::build(SVGFilterBuilder*, Filter& filter)
 {
     if (m_cachedImage)
         return FEImage::createWithImage(filter, m_cachedImage->imageForRenderer(renderer()), preserveAspectRatio());
-    return FEImage::createWithIRIReference(filter, document(), href(), preserveAspectRatio());
+    return FEImage::createWithIRIReference(filter, treeScope(), href(), preserveAspectRatio());
 }
 
 void SVGFEImageElement::addSubresourceAttributeURLs(ListHashSet<URL>& urls) const
index ee2a6e5..51097e4 100644 (file)
@@ -50,6 +50,7 @@ bool SVGGlyphRefElement::hasValidGlyphElement(String& glyphName) const
 {
     // FIXME: We only support xlink:href so far.
     // https://bugs.webkit.org/show_bug.cgi?id=64787
+    // No need to support glyphRef referencing another node inside a shadow tree.
     auto target = targetElementFromIRIString(getAttribute(SVGNames::hrefAttr, XLinkNames::hrefAttr), document());
     glyphName = target.identifier;
     return is<SVGGlyphElement>(target.element);
index 773ecaa..eefdfb5 100644 (file)
@@ -149,7 +149,7 @@ bool SVGLinearGradientElement::collectGradientAttributes(LinearGradientAttribute
 
     while (true) {
         // Respect xlink:href, take attributes from referenced element
-        auto target = SVGURIReference::targetElementFromIRIString(current->href(), document());
+        auto target = SVGURIReference::targetElementFromIRIString(current->href(), treeScope());
         if (is<SVGGradientElement>(target.element)) {
             current = downcast<SVGGradientElement>(*target.element);
 
index c08c8b1..18e9dd5 100644 (file)
@@ -55,7 +55,7 @@ void SVGMPathElement::buildPendingResource()
     if (!isConnected())
         return;
 
-    auto target = SVGURIReference::targetElementFromIRIString(href(), document());
+    auto target = SVGURIReference::targetElementFromIRIString(href(), treeScope());
     if (!target.element) {
         // Do not register as pending if we are already pending this resource.
         if (document().accessSVGExtensions().isPendingResource(this, target.identifier))
@@ -121,7 +121,7 @@ void SVGMPathElement::svgAttributeChanged(const QualifiedName& attrName)
 
 RefPtr<SVGPathElement> SVGMPathElement::pathElement()
 {
-    auto target = targetElementFromIRIString(href(), document());
+    auto target = targetElementFromIRIString(href(), treeScope());
     if (is<SVGPathElement>(target.element))
         return downcast<SVGPathElement>(target.element.get());
     return nullptr;
index 67ccfd3..b88dd56 100644 (file)
@@ -161,7 +161,7 @@ bool SVGRadialGradientElement::collectGradientAttributes(RadialGradientAttribute
 
     while (true) {
         // Respect xlink:href, take attributes from referenced element
-        auto target = SVGURIReference::targetElementFromIRIString(current->href(), document());
+        auto target = SVGURIReference::targetElementFromIRIString(current->href(), treeScope());
         if (is<SVGGradientElement>(target.element)) {
             current = downcast<SVGGradientElement>(target.element.get());
 
index 53eacd0..b73f3cf 100644 (file)
@@ -230,7 +230,7 @@ void SVGTRefElement::buildPendingResource()
     if (!isConnected())
         return;
 
-    auto target = SVGURIReference::targetElementFromIRIString(href(), document());
+    auto target = SVGURIReference::targetElementFromIRIString(href(), treeScope());
     if (!target.element) {
         if (target.identifier.isEmpty())
             return;
index 55f2c3f..a1191f9 100644 (file)
@@ -143,7 +143,7 @@ void SVGTextPathElement::buildPendingResource()
     if (!isConnected())
         return;
 
-    auto target = SVGURIReference::targetElementFromIRIString(href(), document());
+    auto target = SVGURIReference::targetElementFromIRIString(href(), treeScope());
     if (!target.element) {
         // Do not register as pending if we are already pending this resource.
         if (document().accessSVGExtensions().isPendingResource(this, target.identifier))
index 1d6169e..0812428 100644 (file)
@@ -87,7 +87,7 @@ String SVGURIReference::fragmentIdentifierFromIRIString(const String& url, const
     return emptyString();
 }
 
-auto SVGURIReference::targetElementFromIRIString(const String& iri, const Document& document, RefPtr<Document> externalDocument) -> TargetElementResult
+auto SVGURIReference::targetElementFromIRIString(const String& iri, const TreeScope& treeScope, RefPtr<Document> externalDocument) -> TargetElementResult
 {
     // If there's no fragment identifier contained within the IRI string, we can't lookup an element.
     size_t startOfFragmentIdentifier = iri.find('#');
@@ -99,6 +99,7 @@ auto SVGURIReference::targetElementFromIRIString(const String& iri, const Docume
     if (id.isEmpty())
         return { };
 
+    auto& document = treeScope.documentScope();
     auto url = document.completeURL(iri);
     if (externalDocument) {
         // Enforce that the referenced url matches the url of the document that we've loaded for it!
@@ -110,7 +111,7 @@ auto SVGURIReference::targetElementFromIRIString(const String& iri, const Docume
     if (isExternalURIReference(iri, document))
         return { nullptr, WTFMove(id) };
 
-    return { document.getElementById(id), WTFMove(id) };
+    return { treeScope.getElementById(id), WTFMove(id) };
 }
 
 }
index a06a9e5..f4629e0 100644 (file)
@@ -46,7 +46,7 @@ public:
         RefPtr<Element> element;
         String identifier;
     };
-    static TargetElementResult targetElementFromIRIString(const String&, const Document&, RefPtr<Document> externalDocument = nullptr);
+    static TargetElementResult targetElementFromIRIString(const String&, const TreeScope&, RefPtr<Document> externalDocument = nullptr);
 
     static bool isExternalURIReference(const String& uri, const Document& document)
     {
index 28cef68..1fd88c9 100644 (file)
@@ -237,10 +237,6 @@ void SVGUseElement::updateShadowTree()
         return;
     document().removeSVGUseElement(*this);
 
-    // FIXME: Enable SVG use elements in shadow trees.
-    if (isInShadowTree())
-        return;
-
     String targetID;
     auto* target = findTarget(&targetID);
     if (!target) {
@@ -410,7 +406,7 @@ SVGElement* SVGUseElement::findTarget(String* targetID) const
     auto* correspondingElement = this->correspondingElement();
     auto& original = correspondingElement ? downcast<SVGUseElement>(*correspondingElement) : *this;
 
-    auto targetResult = targetElementFromIRIString(original.href(), original.document(), original.externalDocument());
+    auto targetResult = targetElementFromIRIString(original.href(), original.treeScope(), original.externalDocument());
     if (targetID) {
         *targetID = WTFMove(targetResult.identifier);
         // If the reference is external, don't return the target ID to the caller.
index 0dab1ac..bbda240 100644 (file)
@@ -40,6 +40,7 @@
 #include "SVGParserUtilities.h"
 #include "SVGSVGElement.h"
 #include "SVGURIReference.h"
+#include "SVGUseElement.h"
 #include "XLinkNames.h"
 #include <wtf/IsoMallocInlines.h>
 #include <wtf/MathExtras.h>
@@ -184,7 +185,7 @@ void SVGSMILElement::buildPendingResource()
     if (href.isEmpty())
         target = parentElement();
     else {
-        auto result = SVGURIReference::targetElementFromIRIString(href.string(), document());
+        auto result = SVGURIReference::targetElementFromIRIString(href.string(), treeScope());
         target = WTFMove(result.element);
         id = WTFMove(result.identifier);
     }
@@ -265,7 +266,7 @@ Node::InsertedIntoAncestorResult SVGSMILElement::insertedIntoAncestor(InsertionT
         return InsertedIntoAncestorResult::Done;
 
     // Verify we are not in <use> instance tree.
-    ASSERT(!isInShadowTree());
+    ASSERT(!isInShadowTree() || !is<SVGUseElement>(shadowHost()));
 
     updateAttributeName();
 
index c65af74..c584eb5 100644 (file)
@@ -38,14 +38,13 @@ namespace WebCore {
 FEImage::FEImage(Filter& filter, RefPtr<Image> image, const SVGPreserveAspectRatioValue& preserveAspectRatio)
     : FilterEffect(filter)
     , m_image(image)
-    , m_document(nullptr)
     , m_preserveAspectRatio(preserveAspectRatio)
 {
 }
 
-FEImage::FEImage(Filter& filter, Document& document, const String& href, const SVGPreserveAspectRatioValue& preserveAspectRatio)
+FEImage::FEImage(Filter& filter, TreeScope& treeScope, const String& href, const SVGPreserveAspectRatioValue& preserveAspectRatio)
     : FilterEffect(filter)
-    , m_document(&document)
+    , m_treeScope(&treeScope)
     , m_href(href)
     , m_preserveAspectRatio(preserveAspectRatio)
 {
@@ -56,9 +55,9 @@ Ref<FEImage> FEImage::createWithImage(Filter& filter, RefPtr<Image> image, const
     return adoptRef(*new FEImage(filter, image, preserveAspectRatio));
 }
 
-Ref<FEImage> FEImage::createWithIRIReference(Filter& filter, Document& document, const String& href, const SVGPreserveAspectRatioValue& preserveAspectRatio)
+Ref<FEImage> FEImage::createWithIRIReference(Filter& filter, TreeScope& treeScope, const String& href, const SVGPreserveAspectRatioValue& preserveAspectRatio)
 {
-    return adoptRef(*new FEImage(filter, document, href, preserveAspectRatio));
+    return adoptRef(*new FEImage(filter, treeScope, href, preserveAspectRatio));
 }
 
 void FEImage::determineAbsolutePaintRect()
@@ -80,9 +79,9 @@ void FEImage::determineAbsolutePaintRect()
 
 RenderElement* FEImage::referencedRenderer() const
 {
-    if (!m_document)
+    if (!m_treeScope)
         return nullptr;
-    auto target = SVGURIReference::targetElementFromIRIString(m_href, *m_document);
+    auto target = SVGURIReference::targetElementFromIRIString(m_href, *m_treeScope);
     if (!is<SVGElement>(target.element))
         return nullptr;
     return target.element->renderer();
index 67a868d..6874fdf 100644 (file)
@@ -34,12 +34,12 @@ class RenderElement;
 class FEImage final : public FilterEffect {
 public:
     static Ref<FEImage> createWithImage(Filter&, RefPtr<Image>, const SVGPreserveAspectRatioValue&);
-    static Ref<FEImage> createWithIRIReference(Filter&, Document&, const String&, const SVGPreserveAspectRatioValue&);
+    static Ref<FEImage> createWithIRIReference(Filter&, TreeScope&, const String&, const SVGPreserveAspectRatioValue&);
 
 private:
     virtual ~FEImage() = default;
     FEImage(Filter&, RefPtr<Image>, const SVGPreserveAspectRatioValue&);
-    FEImage(Filter&, Document&, const String&, const SVGPreserveAspectRatioValue&);
+    FEImage(Filter&, TreeScope&, const String&, const SVGPreserveAspectRatioValue&);
 
     const char* filterName() const final { return "FEImage"; }
 
@@ -53,8 +53,8 @@ private:
 
     RefPtr<Image> m_image;
 
-    // m_document will never be a dangling reference. See https://bugs.webkit.org/show_bug.cgi?id=99243
-    Document* m_document;
+    // m_treeScope will never be a dangling reference. See https://bugs.webkit.org/show_bug.cgi?id=99243
+    TreeScope* m_treeScope { nullptr };
     String m_href;
     SVGPreserveAspectRatioValue m_preserveAspectRatio;
 };