Diff
Modified: trunk/LayoutTests/ChangeLog (281966 => 281967)
--- trunk/LayoutTests/ChangeLog 2021-09-02 23:39:39 UTC (rev 281966)
+++ trunk/LayoutTests/ChangeLog 2021-09-02 23:54:29 UTC (rev 281967)
@@ -1,3 +1,20 @@
+2021-09-02 Simon Fraser <simon.fra...@apple.com>
+
+ Changes to clip-path and filter SVG elements referenced by CSS don't trigger repaints
+ https://bugs.webkit.org/show_bug.cgi?id=204204
+
+ Reviewed by Antti Koivisto.
+
+ Repaint tests that detect repaints when referenced clips or filters change.
+
+ * css3/filters/reference-filter-change-repaint-expected.txt: Added.
+ * css3/filters/reference-filter-change-repaint.html: Added.
+ * css3/masking/clip-path-reference-local-url-with-base.html:
+ * css3/masking/reference-clip-path-animate-transform-repaint-expected.txt: Added.
+ * css3/masking/reference-clip-path-animate-transform-repaint.html: Added.
+ * css3/masking/reference-clip-path-change-repaint-expected.txt: Added.
+ * css3/masking/reference-clip-path-change-repaint.html: Added.
+
2021-09-02 Chris Dumez <cdu...@apple.com>
[ BigSur arm64 Debug EWS ] ASSERTION FAILED: m_uncommittedState.state == State::Provisional
Added: trunk/LayoutTests/css3/filters/reference-filter-change-repaint-expected.txt (0 => 281967)
--- trunk/LayoutTests/css3/filters/reference-filter-change-repaint-expected.txt (rev 0)
+++ trunk/LayoutTests/css3/filters/reference-filter-change-repaint-expected.txt 2021-09-02 23:54:29 UTC (rev 281967)
@@ -0,0 +1,4 @@
+ (repaint rects
+ (rect 8 8 200 200)
+)
+
Added: trunk/LayoutTests/css3/filters/reference-filter-change-repaint.html (0 => 281967)
--- trunk/LayoutTests/css3/filters/reference-filter-change-repaint.html (rev 0)
+++ trunk/LayoutTests/css3/filters/reference-filter-change-repaint.html 2021-09-02 23:54:29 UTC (rev 281967)
@@ -0,0 +1,47 @@
+<head>
+ <style>
+ .box {
+ width: 200px;
+ height: 200px;
+ background-color: silver;
+ filter: url(#filter);
+ }
+ </style>
+ <script>
+ if (window.testRunner) {
+ testRunner.dumpAsText();
+ testRunner.waitUntilDone();
+ }
+
+ function changeFilterAndFinish()
+ {
+ if (window.internals)
+ window.internals.startTrackingRepaints();
+
+ document.getElementById('turbulence').setAttributeNS(null, 'seed', 6)
+
+ if (window.internals)
+ document.getElementById('log').textContent = window.internals.repaintRectsAsText();
+ if (window.testRunner)
+ testRunner.notifyDone();
+
+ }
+ window.addEventListener('load', () => {
+ setTimeout(() => {
+ changeFilterAndFinish()
+ }, 0);
+ }, false);
+ </script>
+</head>
+<body>
+ <svg xmlns="http://www.w3.org/2000/svg" width="0" height="0" version="1.1">
+ <defs>
+ <filter id="filter">
+ <feTurbulence id="turbulence" type="turbulence" baseFrequency="0.01" numOctaves="1" seed="5" stitchTiles="stitch"/>
+ <feColorMatrix type="saturate" values="0"/>
+ </filter>
+ </defs>
+ </svg>
+ <div class="box"></div>
+<pre id="log"></pre>
+</body>
Modified: trunk/LayoutTests/css3/masking/clip-path-reference-local-url-with-base.html (281966 => 281967)
--- trunk/LayoutTests/css3/masking/clip-path-reference-local-url-with-base.html 2021-09-02 23:39:39 UTC (rev 281966)
+++ trunk/LayoutTests/css3/masking/clip-path-reference-local-url-with-base.html 2021-09-02 23:54:29 UTC (rev 281967)
@@ -14,5 +14,5 @@
<svg>
<clipPath id="clip">
<rect width="100" height="100"/>
- </filter>
+ </clipPath>
</svg>
Added: trunk/LayoutTests/css3/masking/reference-clip-path-animate-transform-repaint-expected.txt (0 => 281967)
--- trunk/LayoutTests/css3/masking/reference-clip-path-animate-transform-repaint-expected.txt (rev 0)
+++ trunk/LayoutTests/css3/masking/reference-clip-path-animate-transform-repaint-expected.txt 2021-09-02 23:54:29 UTC (rev 281967)
@@ -0,0 +1,5 @@
+ PASS repaintRects.indexOf('rect 8 8 220 220') is not -1
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
Added: trunk/LayoutTests/css3/masking/reference-clip-path-animate-transform-repaint.html (0 => 281967)
--- trunk/LayoutTests/css3/masking/reference-clip-path-animate-transform-repaint.html (rev 0)
+++ trunk/LayoutTests/css3/masking/reference-clip-path-animate-transform-repaint.html 2021-09-02 23:54:29 UTC (rev 281967)
@@ -0,0 +1,76 @@
+<!DOCTYPE html>
+<html>
+<head>
+<style>
+div {
+ width: 220px;
+ height: 220px;
+ background-color: green;
+ clip-path: url(#chevron);
+}
+svg {
+ height: 0px;
+ width: 0px;
+}
+</style>
+<script src=""
+<script>
+ jsTestIsAsync = true;
+ let repaintRects;
+
+ async function animationFrame()
+ {
+ return new Promise(requestAnimationFrame);
+ }
+
+ async function delayFor(ms)
+ {
+ return new Promise(resolve => setTimeout(resolve, ms));
+ }
+
+ async function renderingUpdate()
+ {
+ await animationFrame();
+ await delayFor(0);
+ }
+
+ async function changeClipPathAndFinish()
+ {
+ if (!window.internals)
+ return;
+
+ internals.startTrackingRepaints();
+
+ await renderingUpdate();
+ await renderingUpdate();
+ await renderingUpdate();
+
+ repaintRects = internals.repaintRectsAsText();
+ // Look for at least one repaint.
+ shouldNotBe("repaintRects.indexOf('rect 8 8 220 220')", "-1");
+
+ internals.stopTrackingRepaints();
+ finishJSTest();
+ }
+
+ window.addEventListener('load', () => {
+ setTimeout(() => {
+ changeClipPathAndFinish()
+ }, 0);
+ }, false);
+</script>
+</head>
+<body>
+<div></div>
+<svg>
+ <clipPath id="chevron">
+ <polygon points="0,100 22.222,133.333 8.333,147.222 -13.889,113.889 -47.222,91.667 -33.333,77.778">
+ <animateTransform attributeType="XML" attributeName="transform" type="translate"
+ values="0,100;144.444,-44.444" dur="0.5s" repeatCount="indefinite"/>
+ </polygon>
+ </clipPath>
+</svg>
+<div id="console"></div>
+<script src=""
+</body>
+</html>
Added: trunk/LayoutTests/css3/masking/reference-clip-path-change-repaint-expected.txt (0 => 281967)
--- trunk/LayoutTests/css3/masking/reference-clip-path-change-repaint-expected.txt (rev 0)
+++ trunk/LayoutTests/css3/masking/reference-clip-path-change-repaint-expected.txt 2021-09-02 23:54:29 UTC (rev 281967)
@@ -0,0 +1,4 @@
+ (repaint rects
+ (rect 8 8 220 220)
+)
+
Added: trunk/LayoutTests/css3/masking/reference-clip-path-change-repaint.html (0 => 281967)
--- trunk/LayoutTests/css3/masking/reference-clip-path-change-repaint.html (rev 0)
+++ trunk/LayoutTests/css3/masking/reference-clip-path-change-repaint.html 2021-09-02 23:54:29 UTC (rev 281967)
@@ -0,0 +1,52 @@
+<!DOCTYPE html>
+<html>
+<head>
+<style>
+div {
+ width: 220px;
+ height: 220px;
+ background-color: green;
+ clip-path: url(#clip);
+}
+svg {
+ height: 0px;
+ width: 0px;
+}
+</style>
+<script>
+ if (window.testRunner) {
+ testRunner.dumpAsText();
+ testRunner.waitUntilDone();
+ }
+
+ function changeClipPathAndFinish()
+ {
+ if (window.internals)
+ window.internals.startTrackingRepaints();
+
+ const rect = document.getElementById('rect');
+ rect.setAttribute('width', 100);
+ rect.setAttribute('height', 100);
+
+ document.getElementById('log').textContent = window.internals.repaintRectsAsText();
+ if (window.testRunner)
+ testRunner.notifyDone();
+
+ }
+ window.addEventListener('load', () => {
+ setTimeout(() => {
+ changeClipPathAndFinish()
+ }, 0);
+ }, false);
+</script>
+</head>
+<body>
+<div></div>
+<svg>
+ <clipPath id="clip">
+ <rect id="rect" width="200" height="200"/>
+ </clipPath>
+</svg>
+<pre id="log"></pre>
+</body>
+</html>
Modified: trunk/LayoutTests/platform/win/TestExpectations (281966 => 281967)
--- trunk/LayoutTests/platform/win/TestExpectations 2021-09-02 23:39:39 UTC (rev 281966)
+++ trunk/LayoutTests/platform/win/TestExpectations 2021-09-02 23:54:29 UTC (rev 281967)
@@ -1884,6 +1884,7 @@
svg/animations/animate-text-nested-transforms.html [ Failure ]
svg/repaint/text-mask-update.svg [ ImageOnlyFailure ]
svg/text/lengthAdjust-text-metrics.html [ Failure ]
+css3/filters/reference-filter-change-repaint.html [ Failure ]
# Weird black images
imported/mozilla/svg/svg-effects-area-unzoomed.xhtml
Modified: trunk/Source/WebCore/ChangeLog (281966 => 281967)
--- trunk/Source/WebCore/ChangeLog 2021-09-02 23:39:39 UTC (rev 281966)
+++ trunk/Source/WebCore/ChangeLog 2021-09-02 23:54:29 UTC (rev 281967)
@@ -1,3 +1,73 @@
+2021-09-02 Simon Fraser <simon.fra...@apple.com>
+
+ Changes to clip-path and filter SVG elements referenced by CSS don't trigger repaints
+ https://bugs.webkit.org/show_bug.cgi?id=204204
+
+ Reviewed by Antti Koivisto.
+
+ Create a mechanism that allows SVG clipping and filter resources referenced from
+ CSS to trigger repaints when they change. This fixes bugs where change to the
+ SVG, via script or animations, failed to cause CSS-rendered elements that
+ reference them, via clip-path:url(#foo) or filter:url(#foo) to repaint.
+
+ The key is that SVGElement stores a set of SVGResourceElementClients, as it does for
+ element references which are the equivalent for intra-SVG resource refs.
+
+ RenderElementRareData holds a ReferencedSVGResources class, which stores a map
+ of resourceID -> SVGResourceElementClient, and its implementation of SVGResourceElementClients
+ triggers the repaint.
+
+ ReferencedSVGResources are updated after a style change, which works because
+ they only ever find elements, not SVG renderers.
+
+ Change filter and clip-path code go via ReferencedSVGResources to find their
+ appropriate filter element or clipping renderer, for cleanliness.
+
+ Tests: css3/filters/reference-filter-change-repaint.html
+ css3/masking/reference-clip-path-animate-transform-repaint.html
+ css3/masking/reference-clip-path-change-repaint.html
+
+ * Sources.txt:
+ * WebCore.xcodeproj/project.pbxproj:
+ * rendering/CSSFilter.cpp:
+ (WebCore::CSSFilter::buildReferenceFilter): Remove some code related to looking
+ for resources in external documents, since this functionality was removed.
+ * rendering/ReferencedSVGResources.cpp: Added.
+ (WebCore::CSSSVGResourceElementClient::resourceChanged):
+ (WebCore::ReferencedSVGResources::ReferencedSVGResources):
+ (WebCore::ReferencedSVGResources::~ReferencedSVGResources):
+ (WebCore::ReferencedSVGResources::removeClientForTarget):
+ (WebCore::ReferencedSVGResources::referencedSVGResourceIDs):
+ (WebCore::ReferencedSVGResources::updateReferencedResources):
+ (WebCore::ReferencedSVGResources::elementForResourceID):
+ (WebCore::ReferencedSVGResources::referencedFilterElement):
+ (WebCore::ReferencedSVGResources::referencedClipperRenderer):
+ * rendering/ReferencedSVGResources.h: Added.
+ * rendering/RenderElement.cpp:
+ (WebCore::RenderElement::styleDidChange):
+ (WebCore::RenderElement::ensureReferencedSVGResources):
+ (WebCore::RenderElement::clearReferencedSVGResources):
+ (WebCore::RenderElement::updateReferencedSVGResources):
+ * rendering/RenderElement.h:
+ * rendering/RenderLayer.cpp:
+ (WebCore::RenderLayer::setupClipPath):
+ * rendering/RenderObject.cpp:
+ (WebCore::RenderObject::RenderObjectRareData::RenderObjectRareData):
+ * rendering/RenderObject.h:
+ (WebCore::RenderObject::RenderObjectRareData::RenderObjectRareData): Deleted.
+ * rendering/svg/RenderSVGResource.cpp:
+ (WebCore::removeFromCacheAndInvalidateDependencies):
+ * svg/SVGElement.cpp:
+ (WebCore::SVGElement::referencingCSSClients const):
+ (WebCore::SVGElement::addReferencingCSSClient):
+ (WebCore::SVGElement::removeReferencingCSSClient):
+ * svg/SVGElement.h:
+ * svg/SVGElementRareData.h:
+ (WebCore::SVGElementRareData::addReferencingCSSClient):
+ (WebCore::SVGElementRareData::removeReferencingCSSClient):
+ (WebCore::SVGElementRareData::referencingCSSClients const):
+ * svg/SVGResourceElementClient.h: Added.
+
2021-09-02 Aditya Keerthi <akeer...@apple.com>
[iOS] Simplify date picker logic for datetime-local inputs
Modified: trunk/Source/WebCore/Sources.txt (281966 => 281967)
--- trunk/Source/WebCore/Sources.txt 2021-09-02 23:39:39 UTC (rev 281966)
+++ trunk/Source/WebCore/Sources.txt 2021-09-02 23:54:29 UTC (rev 281967)
@@ -2187,6 +2187,7 @@
rendering/MarkedText.cpp
rendering/OrderIterator.cpp
rendering/PointerEventsHitRules.cpp
+rendering/ReferencedSVGResources.cpp
rendering/RenderAttachment.cpp
rendering/RenderBlock.cpp
rendering/RenderBlockFlow.cpp
Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (281966 => 281967)
--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj 2021-09-02 23:39:39 UTC (rev 281966)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj 2021-09-02 23:54:29 UTC (rev 281967)
@@ -6302,6 +6302,9 @@
0FBFCE26256CBD9A00A0B489 /* DisplayBoxClip.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DisplayBoxClip.h; sourceTree = "<group>"; };
0FC05168219B5EBE0031C39E /* ScrollingTreeOverflowScrollingNodeMac.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = ScrollingTreeOverflowScrollingNodeMac.mm; sourceTree = "<group>"; };
0FC0516A219B5EBE0031C39E /* ScrollingTreeOverflowScrollingNodeMac.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ScrollingTreeOverflowScrollingNodeMac.h; sourceTree = "<group>"; };
+ 0FC276B826DAF9B70093E8ED /* ReferencedSVGResources.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ReferencedSVGResources.h; sourceTree = "<group>"; };
+ 0FC276BA26DAF9E90093E8ED /* ReferencedSVGResources.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = ReferencedSVGResources.cpp; sourceTree = "<group>"; };
+ 0FC276BC26DB19000093E8ED /* SVGResourceElementClient.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SVGResourceElementClient.h; sourceTree = "<group>"; };
0FC4B00422B9A02C00CF3B1E /* ScrollingTreeOverflowScrollProxyNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ScrollingTreeOverflowScrollProxyNode.h; sourceTree = "<group>"; };
0FC4B00522B9A02D00CF3B1E /* ScrollingTreeOverflowScrollProxyNode.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ScrollingTreeOverflowScrollProxyNode.mm; sourceTree = "<group>"; };
0FC692BA257C0F400098E3F9 /* ScrollAnimationKinetic.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ScrollAnimationKinetic.h; sourceTree = "<group>"; };
@@ -26362,6 +26365,7 @@
B22279090D00BF210071B782 /* SVGRectElement.idl */,
B222790A0D00BF210071B782 /* SVGRenderingIntent.h */,
B222790B0D00BF210071B782 /* SVGRenderingIntent.idl */,
+ 0FC276BC26DB19000093E8ED /* SVGResourceElementClient.h */,
B222790C0D00BF210071B782 /* SVGScriptElement.cpp */,
B222790D0D00BF210071B782 /* SVGScriptElement.h */,
B222790E0D00BF210071B782 /* SVGScriptElement.idl */,
@@ -29591,6 +29595,8 @@
0885067E11DA045B00182B98 /* PaintPhase.h */,
B2B1F7140D00CAA8004AEA64 /* PointerEventsHitRules.cpp */,
B2B1F7150D00CAA8004AEA64 /* PointerEventsHitRules.h */,
+ 0FC276BA26DAF9E90093E8ED /* ReferencedSVGResources.cpp */,
+ 0FC276B826DAF9B70093E8ED /* ReferencedSVGResources.h */,
B59ED23A18272679006D564C /* RenderAncestorIterator.h */,
7CD494CA1A86EB1D000A87EC /* RenderAttachment.cpp */,
7CD494CB1A86EB1D000A87EC /* RenderAttachment.h */,
Modified: trunk/Source/WebCore/rendering/CSSFilter.cpp (281966 => 281967)
--- trunk/Source/WebCore/rendering/CSSFilter.cpp 2021-09-02 23:39:39 UTC (rev 281966)
+++ trunk/Source/WebCore/rendering/CSSFilter.cpp 2021-09-02 23:54:29 UTC (rev 281967)
@@ -37,6 +37,7 @@
#include "FEMerge.h"
#include "FilterEffectRenderer.h"
#include "Logging.h"
+#include "ReferencedSVGResources.h"
#include "RenderLayer.h"
#include "SVGElement.h"
#include "SVGFilterBuilder.h"
@@ -72,26 +73,14 @@
RefPtr<FilterEffect> CSSFilter::buildReferenceFilter(RenderElement& renderer, FilterEffect& previousEffect, ReferenceFilterOperation& filterOperation)
{
- auto* cachedSVGDocumentReference = filterOperation.cachedSVGDocumentReference();
- auto* cachedSVGDocument = cachedSVGDocumentReference ? cachedSVGDocumentReference->document() : nullptr;
-
- // If we have an SVG document, this is an external reference. Otherwise
- // we look up the referenced node in the current document.
- Document* document;
- if (!cachedSVGDocument)
- document = &renderer.document();
- else {
- document = cachedSVGDocument->document();
- if (!document)
- return nullptr;
- }
-
- auto* filter = document->getElementById(filterOperation.fragment());
- if (!filter) {
+ auto* filterElement = renderer.ensureReferencedSVGResources().referencedFilterElement(renderer.document(), filterOperation);
+ if (!filterElement) {
+ LOG_WITH_STREAM(Filters, stream << "CSSFilter " << this << " buildReferenceFilter: failed to find filter renderer, adding pending resource " << filterOperation.fragment());
// Although we did not find the referenced filter, it might exist later in the document.
// FIXME: This skips anonymous RenderObjects. <https://webkit.org/b/131085>
+ // FIXME: Unclear if this does anything.
if (auto* element = renderer.element())
- document->accessSVGExtensions().addPendingResource(filterOperation.fragment(), *element);
+ renderer.document().accessSVGExtensions().addPendingResource(filterOperation.fragment(), *element);
return nullptr;
}
@@ -101,7 +90,7 @@
RefPtr<FilterEffect> effect;
Vector<Ref<FilterEffect>> referenceEffects;
- for (auto& effectElement : childrenOfType<SVGFilterPrimitiveStandardAttributes>(*filter)) {
+ for (auto& effectElement : childrenOfType<SVGFilterPrimitiveStandardAttributes>(*filterElement)) {
effect = effectElement.build(builder.get(), *this);
if (!effect) {
LOG_WITH_STREAM(Filters, stream << "CSSFilter " << this << " buildReferenceFilter: failed to build effect from " << effectElement);
Added: trunk/Source/WebCore/rendering/ReferencedSVGResources.cpp (0 => 281967)
--- trunk/Source/WebCore/rendering/ReferencedSVGResources.cpp (rev 0)
+++ trunk/Source/WebCore/rendering/ReferencedSVGResources.cpp 2021-09-02 23:54:29 UTC (rev 281967)
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2021 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "ReferencedSVGResources.h"
+
+#include "ClipPathOperation.h"
+#include "FilterOperations.h"
+#include "RenderSVGResourceClipper.h"
+#include "RenderSVGResourceFilter.h"
+#include "RenderStyle.h"
+#include "SVGClipPathElement.h"
+#include "SVGResourceElementClient.h"
+
+namespace WebCore {
+
+class CSSSVGResourceElementClient final : public SVGResourceElementClient {
+ WTF_MAKE_ISO_ALLOCATED(CSSSVGResourceElementClient);
+public:
+ CSSSVGResourceElementClient(RenderElement& clientRenderer)
+ : m_clientRenderer(clientRenderer)
+ {
+ }
+
+ void resourceChanged(SVGElement&) final;
+
+private:
+ RenderElement& m_clientRenderer;
+};
+
+WTF_MAKE_ISO_ALLOCATED_IMPL(CSSSVGResourceElementClient);
+
+void CSSSVGResourceElementClient::resourceChanged(SVGElement&)
+{
+ if (!m_clientRenderer.renderTreeBeingDestroyed())
+ m_clientRenderer.repaint();
+}
+
+WTF_MAKE_ISO_ALLOCATED_IMPL(ReferencedSVGResources);
+
+ReferencedSVGResources::ReferencedSVGResources(RenderElement& renderer)
+ : m_renderer(renderer)
+{
+}
+
+ReferencedSVGResources::~ReferencedSVGResources()
+{
+ auto& document = m_renderer.document();
+
+ for (auto& targetID : copyToVector(m_elementClients.keys()))
+ removeClientForTarget(document, targetID);
+}
+
+void ReferencedSVGResources::addClientForTarget(SVGElement& targetElement, const AtomString& targetID)
+{
+ m_elementClients.ensure(targetID, [&] {
+ auto client = WTF::makeUnique<CSSSVGResourceElementClient>(m_renderer);
+ targetElement.addReferencingCSSClient(*client);
+ return client;
+ });
+}
+
+void ReferencedSVGResources::removeClientForTarget(Document& document, const AtomString& targetID)
+{
+ auto client = m_elementClients.take(targetID);
+
+ auto* targetElement = document.getElementById(targetID);
+ if (is<SVGElement>(targetElement))
+ downcast<SVGElement>(*targetElement).removeReferencingCSSClient(*client);
+}
+
+Vector<std::pair<AtomString, QualifiedName>> ReferencedSVGResources::referencedSVGResourceIDs(const RenderStyle& style)
+{
+ Vector<std::pair<AtomString, QualifiedName>> referencedResources;
+ if (is<ReferenceClipPathOperation>(style.clipPath())) {
+ auto& clipPath = downcast<ReferenceClipPathOperation>(*style.clipPath());
+ if (!clipPath.fragment().isEmpty())
+ referencedResources.append({ clipPath.fragment(), SVGNames::clipPathTag });
+ }
+
+ if (style.hasFilter()) {
+ const auto& filterOperations = style.filter();
+ for (auto& operation : filterOperations.operations()) {
+ auto& filterOperation = *operation;
+ if (filterOperation.type() == FilterOperation::REFERENCE) {
+ const auto& referenceFilterOperation = downcast<ReferenceFilterOperation>(filterOperation);
+ if (!referenceFilterOperation.fragment().isEmpty())
+ referencedResources.append({ referenceFilterOperation.fragment(), SVGNames::filterTag });
+ }
+ }
+ }
+
+ return referencedResources;
+}
+
+void ReferencedSVGResources::updateReferencedResources(Document& document, const Vector<std::pair<AtomString, QualifiedName>>& referencedResources)
+{
+ HashSet<AtomString> oldKeys;
+ for (auto& key : m_elementClients.keys())
+ oldKeys.add(key);
+
+ for (auto& [targetID, tagName] : referencedResources) {
+ auto* element = elementForResourceID(document, targetID, tagName);
+ if (!element)
+ continue;
+
+ addClientForTarget(*element, targetID);
+ oldKeys.remove(targetID);
+ }
+
+ for (auto& targetID : oldKeys)
+ removeClientForTarget(document, targetID);
+}
+
+// SVG code uses getRenderSVGResourceById<>, but that works in terms of renderers. We need to find resources
+// before the render tree is fully constructed, so this works on Elements.
+SVGElement* ReferencedSVGResources::elementForResourceID(Document& document, const AtomString& resourceID, const QualifiedName& tagName)
+{
+ auto* element = document.getElementById(resourceID);
+ if (!element || !element->hasTagName(tagName))
+ return nullptr;
+
+ return downcast<SVGElement>(element);
+}
+
+SVGFilterElement* ReferencedSVGResources::referencedFilterElement(Document& document, const ReferenceFilterOperation& referenceFilter)
+{
+ if (referenceFilter.fragment().isEmpty())
+ return nullptr;
+ auto* element = elementForResourceID(document, referenceFilter.fragment(), SVGNames::filterTag);
+ return element ? downcast<SVGFilterElement>(element) : nullptr;
+}
+
+RenderSVGResourceClipper* ReferencedSVGResources::referencedClipperRenderer(Document& document, const ReferenceClipPathOperation& clipPath)
+{
+ if (clipPath.fragment().isEmpty())
+ return nullptr;
+ // For some reason, SVG stores a cache of id -> renderer, rather than just using getElementById() and renderer().
+ return getRenderSVGResourceById<RenderSVGResourceClipper>(document, clipPath.fragment());
+}
+
+} // namespace WebCore
Added: trunk/Source/WebCore/rendering/ReferencedSVGResources.h (0 => 281967)
--- trunk/Source/WebCore/rendering/ReferencedSVGResources.h (rev 0)
+++ trunk/Source/WebCore/rendering/ReferencedSVGResources.h 2021-09-02 23:54:29 UTC (rev 281967)
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2021 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <wtf/FastMalloc.h>
+#include <wtf/HashMap.h>
+#include <wtf/text/AtomString.h>
+
+namespace WebCore {
+
+class CSSSVGResourceElementClient;
+class ReferenceClipPathOperation;
+class ReferenceFilterOperation;
+class RenderSVGResourceClipper;
+class RenderSVGResourceFilter;
+class RenderStyle;
+class QualifiedName;
+class SVGElement;
+class SVGFilterElement;
+
+class ReferencedSVGResources {
+ WTF_MAKE_ISO_ALLOCATED(ReferencedSVGResources);
+public:
+ ReferencedSVGResources(RenderElement&);
+ ~ReferencedSVGResources();
+
+ static Vector<std::pair<AtomString, QualifiedName>> referencedSVGResourceIDs(const RenderStyle&);
+ void updateReferencedResources(Document&, const Vector<std::pair<AtomString, QualifiedName>>&);
+
+ // Clipping needs a renderer, filters use an element.
+ RenderSVGResourceClipper* referencedClipperRenderer(Document&, const ReferenceClipPathOperation&);
+ SVGFilterElement* referencedFilterElement(Document&, const ReferenceFilterOperation&);
+
+private:
+ static SVGElement* elementForResourceID(Document&, const AtomString& resourceID, const QualifiedName& tagName);
+
+ void addClientForTarget(SVGElement& targetElement, const AtomString&);
+ void removeClientForTarget(Document&, const AtomString&);
+
+ RenderElement& m_renderer;
+ HashMap<AtomString, std::unique_ptr<CSSSVGResourceElementClient>> m_elementClients;
+};
+
+} // namespace WebCore
Modified: trunk/Source/WebCore/rendering/RenderElement.cpp (281966 => 281967)
--- trunk/Source/WebCore/rendering/RenderElement.cpp 2021-09-02 23:39:39 UTC (rev 281966)
+++ trunk/Source/WebCore/rendering/RenderElement.cpp 2021-09-02 23:54:29 UTC (rev 281967)
@@ -46,6 +46,7 @@
#include "Logging.h"
#include "Page.h"
#include "PathUtilities.h"
+#include "ReferencedSVGResources.h"
#include "RenderBlock.h"
#include "RenderChildIterator.h"
#include "RenderCounter.h"
@@ -955,6 +956,9 @@
SVGRenderSupport::styleChanged(*this, oldStyle);
+ if (diff >= StyleDifference::Repaint)
+ updateReferencedSVGResources();
+
if (!m_parent)
return;
@@ -2276,6 +2280,33 @@
child.resetEnclosingFragmentedFlowAndChildInfoIncludingDescendants(fragmentedFlow);
}
+ReferencedSVGResources& RenderElement::ensureReferencedSVGResources()
+{
+ auto& rareData = ensureRareData();
+ if (!rareData.referencedSVGResources)
+ rareData.referencedSVGResources = WTF::makeUnique<ReferencedSVGResources>(*this);
+
+ return *rareData.referencedSVGResources;
+}
+
+void RenderElement::clearReferencedSVGResources()
+{
+ if (!hasRareData())
+ return;
+
+ ensureRareData().referencedSVGResources = nullptr;
+}
+
+// This needs to run when the entire render tree has been constructed, so can't be called from styleDidChange.
+void RenderElement::updateReferencedSVGResources()
+{
+ auto referencedElementIDs = ReferencedSVGResources::referencedSVGResourceIDs(style());
+ if (!referencedElementIDs.isEmpty())
+ ensureReferencedSVGResources().updateReferencedResources(document(), referencedElementIDs);
+ else
+ clearReferencedSVGResources();
+}
+
#if ENABLE(TEXT_AUTOSIZING)
static RenderObject::BlockContentHeightType includeNonFixedHeight(const RenderObject& renderer)
{
Modified: trunk/Source/WebCore/rendering/RenderElement.h (281966 => 281967)
--- trunk/Source/WebCore/rendering/RenderElement.h 2021-09-02 23:39:39 UTC (rev 281966)
+++ trunk/Source/WebCore/rendering/RenderElement.h 2021-09-02 23:54:29 UTC (rev 281967)
@@ -31,6 +31,7 @@
class ContentData;
class ControlStates;
class KeyframeList;
+class ReferencedSVGResources;
class RenderBlock;
class RenderStyle;
class RenderTreeBuilder;
@@ -262,6 +263,8 @@
WeakPtr<RenderBlockFlow> backdropRenderer() const;
void setBackdropRenderer(RenderBlockFlow&);
+ ReferencedSVGResources& ensureReferencedSVGResources();
+
protected:
enum BaseTypeFlag {
RenderLayerModelObjectFlag = 1 << 0,
@@ -361,6 +364,9 @@
bool shouldWillChangeCreateStackingContext() const;
void issueRepaintForOutlineAuto(float outlineSize);
+
+ void updateReferencedSVGResources();
+ void clearReferencedSVGResources();
unsigned m_baseTypeFlags : 6;
unsigned m_ancestorLineBoxDirty : 1;
Modified: trunk/Source/WebCore/rendering/RenderLayer.cpp (281966 => 281967)
--- trunk/Source/WebCore/rendering/RenderLayer.cpp 2021-09-02 23:39:39 UTC (rev 281966)
+++ trunk/Source/WebCore/rendering/RenderLayer.cpp 2021-09-02 23:54:29 UTC (rev 281967)
@@ -87,6 +87,7 @@
#include "OverlapTestRequestClient.h"
#include "Page.h"
#include "PlatformMouseEvent.h"
+#include "ReferencedSVGResources.h"
#include "RenderAncestorIterator.h"
#include "RenderFlexibleBox.h"
#include "RenderFragmentContainer.h"
@@ -3185,16 +3186,15 @@
return true;
}
- if (style.clipPath()->type() == ClipPathOperation::Reference) {
- ReferenceClipPathOperation* referenceClipPathOperation = static_cast<ReferenceClipPathOperation*>(style.clipPath());
- Element* element = renderer().document().getElementById(referenceClipPathOperation->fragment());
- if (element && element->renderer() && is<RenderSVGResourceClipper>(element->renderer())) {
+ if (is<ReferenceClipPathOperation>(style.clipPath())) {
+ auto& referenceClipPathOperation = downcast<ReferenceClipPathOperation>(*style.clipPath());
+ if (auto* clipperRenderer = renderer().ensureReferencedSVGResources().referencedClipperRenderer(renderer().document(), referenceClipPathOperation)) {
context.save();
auto referenceBox = snapRectToDevicePixels(rootRelativeBounds, renderer().document().deviceScaleFactor());
auto offset = referenceBox.location();
context.translate(offset);
FloatRect svgReferenceBox { {}, referenceBox.size() };
- downcast<RenderSVGResourceClipper>(*element->renderer()).applyClippingToContext(context, renderer(), svgReferenceBox, renderer().style().effectiveZoom());
+ clipperRenderer->applyClippingToContext(context, renderer(), svgReferenceBox, renderer().style().effectiveZoom());
context.translate(-offset);
return true;
}
Modified: trunk/Source/WebCore/rendering/RenderObject.cpp (281966 => 281967)
--- trunk/Source/WebCore/rendering/RenderObject.cpp 2021-09-02 23:39:39 UTC (rev 281966)
+++ trunk/Source/WebCore/rendering/RenderObject.cpp 2021-09-02 23:54:29 UTC (rev 281967)
@@ -45,6 +45,7 @@
#include "LogicalSelectionOffsetCaches.h"
#include "Page.h"
#include "PseudoElement.h"
+#include "ReferencedSVGResources.h"
#include "RenderChildIterator.h"
#include "RenderCounter.h"
#include "RenderFragmentedFlow.h"
@@ -1946,6 +1947,15 @@
setHasRareData(false);
}
+RenderObject::RenderObjectRareData::RenderObjectRareData()
+ : m_hasReflection(false)
+ , m_isRenderFragmentedFlow(false)
+ , m_hasOutlineAutoAncestor(false)
+{
+}
+
+RenderObject::RenderObjectRareData::~RenderObjectRareData() = default;
+
bool RenderObject::hasNonEmptyVisibleRectRespectingParentFrames() const
{
auto enclosingFrameRenderer = [] (const RenderObject& renderer) {
Modified: trunk/Source/WebCore/rendering/RenderObject.h (281966 => 281967)
--- trunk/Source/WebCore/rendering/RenderObject.h 2021-09-02 23:39:39 UTC (rev 281966)
+++ trunk/Source/WebCore/rendering/RenderObject.h 2021-09-02 23:54:29 UTC (rev 281967)
@@ -56,6 +56,7 @@
class LegacyInlineBox;
class Path;
class Position;
+class ReferencedSVGResources;
class RenderBoxModelObject;
class RenderInline;
class RenderBlock;
@@ -927,12 +928,9 @@
class RenderObjectRareData {
WTF_MAKE_FAST_ALLOCATED;
public:
- RenderObjectRareData()
- : m_hasReflection(false)
- , m_isRenderFragmentedFlow(false)
- , m_hasOutlineAutoAncestor(false)
- {
- }
+ RenderObjectRareData();
+ ~RenderObjectRareData();
+
ADD_BOOLEAN_BITFIELD(hasReflection, HasReflection);
ADD_BOOLEAN_BITFIELD(isRenderFragmentedFlow, IsRenderFragmentedFlow);
ADD_BOOLEAN_BITFIELD(hasOutlineAutoAncestor, HasOutlineAutoAncestor);
@@ -939,6 +937,7 @@
// From RenderElement
std::unique_ptr<RenderStyle> cachedFirstLineStyle;
+ std::unique_ptr<ReferencedSVGResources> referencedSVGResources;
WeakPtr<RenderBlockFlow> backdropRenderer;
};
Modified: trunk/Source/WebCore/rendering/svg/RenderSVGResource.cpp (281966 => 281967)
--- trunk/Source/WebCore/rendering/svg/RenderSVGResource.cpp 2021-09-02 23:39:39 UTC (rev 281966)
+++ trunk/Source/WebCore/rendering/svg/RenderSVGResource.cpp 2021-09-02 23:54:29 UTC (rev 281967)
@@ -31,6 +31,7 @@
#include "RenderSVGResourceSolidColor.h"
#include "RenderSVGRoot.h"
#include "RenderView.h"
+#include "SVGResourceElementClient.h"
#include "SVGResources.h"
#include "SVGResourcesCache.h"
#include "SVGURIReference.h"
@@ -153,7 +154,7 @@
return s_sharedSolidPaintingResource;
}
-static inline void removeFromCacheAndInvalidateDependencies(RenderElement& renderer, bool needsLayout)
+static void removeFromCacheAndInvalidateDependencies(RenderElement& renderer, bool needsLayout)
{
if (auto* resources = SVGResourcesCache::cachedResourcesForRenderer(renderer)) {
if (RenderSVGResourceFilter* filter = resources->filter())
@@ -169,7 +170,9 @@
if (!is<SVGElement>(renderer.element()))
return;
- for (auto& element : downcast<SVGElement>(*renderer.element()).referencingElements()) {
+ Ref svgElement = downcast<SVGElement>(*renderer.element());
+
+ for (auto& element : svgElement->referencingElements()) {
if (auto* renderer = element->renderer()) {
// We allow cycles in SVGDocumentExtensions reference sets in order to avoid expensive
// reference graph adjustments on changes, so we need to break possible cycles here.
@@ -182,6 +185,12 @@
invalidatingDependencies.get().remove(element.get());
}
}
+
+ for (auto& cssClient : svgElement->referencingCSSClients()) {
+ if (!cssClient)
+ continue;
+ cssClient->resourceChanged(svgElement.get());
+ }
}
void RenderSVGResource::markForLayoutAndParentResourceInvalidation(RenderObject& object, bool needsLayout)
Modified: trunk/Source/WebCore/svg/SVGElement.cpp (281966 => 281967)
--- trunk/Source/WebCore/svg/SVGElement.cpp 2021-09-02 23:39:39 UTC (rev 281966)
+++ trunk/Source/WebCore/svg/SVGElement.cpp 2021-09-02 23:54:29 UTC (rev 281967)
@@ -46,6 +46,7 @@
#include "SVGPropertyAnimatorFactory.h"
#include "SVGRenderStyle.h"
#include "SVGRenderSupport.h"
+#include "SVGResourceElementClient.h"
#include "SVGSVGElement.h"
#include "SVGTitleElement.h"
#include "SVGUseElement.h"
@@ -336,6 +337,25 @@
destination->removeReferencingElement(*this);
}
+Vector<WeakPtr<SVGResourceElementClient>> SVGElement::referencingCSSClients() const
+{
+ if (!m_svgRareData)
+ return { };
+ return copyToVector(m_svgRareData->referencingCSSClients());
+}
+
+void SVGElement::addReferencingCSSClient(SVGResourceElementClient& client)
+{
+ ensureSVGRareData().addReferencingCSSClient(client);
+}
+
+void SVGElement::removeReferencingCSSClient(SVGResourceElementClient& client)
+{
+ if (!m_svgRareData)
+ return;
+ ensureSVGRareData().removeReferencingCSSClient(client);
+}
+
SVGElement* SVGElement::correspondingElement() const
{
return m_svgRareData ? m_svgRareData->correspondingElement() : nullptr;
Modified: trunk/Source/WebCore/svg/SVGElement.h (281966 => 281967)
--- trunk/Source/WebCore/svg/SVGElement.h 2021-09-02 23:39:39 UTC (rev 281966)
+++ trunk/Source/WebCore/svg/SVGElement.h 2021-09-02 23:54:29 UTC (rev 281967)
@@ -41,6 +41,7 @@
class SVGDocumentExtensions;
class SVGElementRareData;
class SVGPropertyAnimatorFactory;
+class SVGResourceElementClient;
class SVGSVGElement;
class SVGUseElement;
@@ -98,6 +99,11 @@
void removeReferencingElement(SVGElement&);
void removeElementReference();
+ Vector<WeakPtr<SVGResourceElementClient>> referencingCSSClients() const;
+ void addReferencingCSSClient(SVGResourceElementClient&);
+ void removeReferencingCSSClient(SVGResourceElementClient&);
+
+
SVGElement* correspondingElement() const;
RefPtr<SVGUseElement> correspondingUseElement() const;
Modified: trunk/Source/WebCore/svg/SVGElementRareData.h (281966 => 281967)
--- trunk/Source/WebCore/svg/SVGElementRareData.h 2021-09-02 23:39:39 UTC (rev 281966)
+++ trunk/Source/WebCore/svg/SVGElementRareData.h 2021-09-02 23:54:29 UTC (rev 281967)
@@ -19,6 +19,7 @@
#pragma once
+#include "SVGResourceElementClient.h"
#include "StyleProperties.h"
#include "StyleResolver.h"
#include <wtf/HashSet.h>
@@ -55,6 +56,10 @@
SVGElement* referenceTarget() const { return m_referenceTarget.get(); }
void setReferenceTarget(WeakPtr<SVGElement>&& element) { m_referenceTarget = WTFMove(element); }
+ void addReferencingCSSClient(SVGResourceElementClient& client) { m_referencingCSSClients.add(client); }
+ void removeReferencingCSSClient(SVGResourceElementClient& client) { m_referencingCSSClients.remove(client); }
+ const WeakHashSet<SVGResourceElementClient>& referencingCSSClients() const { return m_referencingCSSClients; }
+
SVGElement* correspondingElement() { return m_correspondingElement.get(); }
void setCorrespondingElement(SVGElement* correspondingElement) { m_correspondingElement = makeWeakPtr(correspondingElement); }
@@ -86,6 +91,9 @@
private:
WeakHashSet<SVGElement> m_referencingElements;
WeakPtr<SVGElement> m_referenceTarget;
+
+ WeakHashSet<SVGResourceElementClient> m_referencingCSSClients;
+
WeakHashSet<SVGElement> m_instances;
WeakPtr<SVGElement> m_correspondingElement;
bool m_instancesUpdatesBlocked : 1;
Added: trunk/Source/WebCore/svg/SVGResourceElementClient.h (0 => 281967)
--- trunk/Source/WebCore/svg/SVGResourceElementClient.h (rev 0)
+++ trunk/Source/WebCore/svg/SVGResourceElementClient.h 2021-09-02 23:54:29 UTC (rev 281967)
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2021 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <wtf/WeakPtr.h>
+
+namespace WebCore {
+
+class SVGElement;
+
+class SVGResourceElementClient : public CanMakeWeakPtr<SVGResourceElementClient> {
+public:
+ virtual ~SVGResourceElementClient() = default;
+
+ virtual void resourceChanged(SVGElement&) = 0;
+
+};
+
+} // namespace WebCore