Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(134)

Unified Diff: third_party/WebKit/Source/core/svg/SVGElementProxy.cpp

Issue 2490163002: Reland of "Tracking reference filter mutation via SVGElementProxy" (Closed)
Patch Set: Fix double observer unregistration; simplify scope selection; add tests Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: third_party/WebKit/Source/core/svg/SVGElementProxy.cpp
diff --git a/third_party/WebKit/Source/core/svg/SVGElementProxy.cpp b/third_party/WebKit/Source/core/svg/SVGElementProxy.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..596806569640bb0b2dcd41e6440f9b10cb783149
--- /dev/null
+++ b/third_party/WebKit/Source/core/svg/SVGElementProxy.cpp
@@ -0,0 +1,196 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "core/svg/SVGElementProxy.h"
+
+#include "core/dom/IdTargetObserver.h"
+#include "core/fetch/FetchInitiatorTypeNames.h"
+#include "core/fetch/FetchRequest.h"
+#include "core/fetch/ResourceFetcher.h"
+#include "core/svg/SVGElement.h"
+#include "core/svg/SVGFilterElement.h"
+#include "core/svg/SVGResourceClient.h"
+
+namespace blink {
+
+class SVGElementProxy::IdObserver : public IdTargetObserver {
+ public:
+ IdObserver(TreeScope& treeScope, SVGElementProxy& proxy)
+ : IdTargetObserver(treeScope.idTargetObserverRegistry(), proxy.id()),
+ m_treeScope(&treeScope) {}
+
+ void addClient(SVGResourceClient* client) { m_clients.add(client); }
+ bool removeClient(SVGResourceClient* client) {
+ return m_clients.remove(client);
+ }
+ bool hasClients() const { return !m_clients.isEmpty(); }
+
+ TreeScope* treeScope() const { return m_treeScope; }
+ void transferClients(IdObserver& observer) {
+ for (const auto& client : m_clients)
+ observer.m_clients.add(client.key, client.value);
+ m_clients.clear();
+ }
+
+ DEFINE_INLINE_VIRTUAL_TRACE() {
+ visitor->trace(m_clients);
+ visitor->trace(m_treeScope);
+ IdTargetObserver::trace(visitor);
+ }
+
+ void contentChanged() {
+ DCHECK(lifecycle().state() <= DocumentLifecycle::CompositingClean ||
+ lifecycle().state() >= DocumentLifecycle::PaintClean);
+ HeapVector<Member<SVGResourceClient>> clients;
+ copyToVector(m_clients, clients);
+ for (SVGResourceClient* client : clients)
+ client->resourceContentChanged();
+ }
+
+ private:
+ const DocumentLifecycle& lifecycle() const {
+ return m_treeScope->document().lifecycle();
+ }
+ void idTargetChanged() override {
+ DCHECK(lifecycle().stateAllowsTreeMutations());
+ HeapVector<Member<SVGResourceClient>> clients;
+ copyToVector(m_clients, clients);
+ for (SVGResourceClient* client : clients)
+ client->resourceElementChanged();
+ }
+ HeapHashCountedSet<Member<SVGResourceClient>> m_clients;
+ Member<TreeScope> m_treeScope;
+};
+
+SVGElementProxy::SVGElementProxy(const AtomicString& id)
+ : m_id(id), m_isLocal(true) {}
+
+SVGElementProxy::SVGElementProxy(const String& url, const AtomicString& id)
+ : m_id(id), m_url(url), m_isLocal(false) {}
+
+SVGElementProxy::~SVGElementProxy() {}
+
+void SVGElementProxy::addClient(SVGResourceClient* client) {
+ // An empty id will never be a valid element reference.
+ if (m_id.isEmpty())
+ return;
+ if (!m_isLocal) {
+ if (m_document)
+ m_document->addClient(client);
+ return;
+ }
+ TreeScope* clientScope = client->treeScope();
+ if (!clientScope)
+ return;
+ // Ensure sure we have an observer registered for this tree scope.
+ auto& scopeObserver =
+ m_observers.add(clientScope, nullptr).storedValue->value;
+ if (!scopeObserver)
+ scopeObserver = new IdObserver(*clientScope, *this);
+
+ auto& observer = m_clients.add(client, nullptr).storedValue->value;
+ if (!observer)
+ observer = scopeObserver;
+
+ DCHECK(observer && scopeObserver);
+
+ // If the client moved to a different scope, we need to unregister the old
+ // observer and transfer any clients from it before replacing it. Thus any
+ // clients that remain to be removed will be transferred to the new observer,
+ // and hence removed from it instead.
+ if (observer != scopeObserver) {
+ observer->unregister();
+ observer->transferClients(*scopeObserver);
+ observer = scopeObserver;
+ }
+ observer->addClient(client);
+}
+
+void SVGElementProxy::removeClient(SVGResourceClient* client) {
+ // An empty id will never be a valid element reference.
+ if (m_id.isEmpty())
+ return;
+ if (!m_isLocal) {
+ if (m_document)
+ m_document->removeClient(client);
+ return;
+ }
+ auto entry = m_clients.find(client);
+ if (entry == m_clients.end())
+ return;
+ IdObserver* observer = entry->value;
+ DCHECK(observer);
+ // If the client is not the last client in the scope, then no further action
+ // needs to be taken.
+ if (!observer->removeClient(client))
+ return;
+ // Unregister and drop the scope association, then drop the client.
+ if (!observer->hasClients()) {
+ observer->unregister();
+ m_observers.remove(observer->treeScope());
+ }
+ m_clients.remove(entry);
+}
+
+void SVGElementProxy::resolve(Document& document) {
+ if (m_isLocal || m_id.isEmpty() || m_url.isEmpty())
+ return;
+ FetchRequest request(ResourceRequest(m_url), FetchInitiatorTypeNames::css);
+ m_document = DocumentResource::fetchSVGDocument(request, document.fetcher());
+ m_url = String();
+}
+
+TreeScope* SVGElementProxy::treeScopeForLookup(TreeScope& treeScope) const {
+ if (m_isLocal)
+ return &treeScope;
+ if (!m_document)
+ return nullptr;
+ return m_document->document();
+}
+
+SVGElement* SVGElementProxy::findElement(TreeScope& treeScope) {
+ // An empty id will never be a valid element reference.
+ if (m_id.isEmpty())
+ return nullptr;
+ TreeScope* lookupScope = treeScopeForLookup(treeScope);
+ if (!lookupScope)
+ return nullptr;
+ if (Element* targetElement = lookupScope->getElementById(m_id)) {
+ if (isSVGFilterElement(*targetElement)) {
+ toSVGFilterElement(*targetElement).elementProxySet().add(*this);
+ return toSVGElement(targetElement);
+ }
+ }
+ return nullptr;
+}
+
+void SVGElementProxy::contentChanged(TreeScope& treeScope) {
+ if (auto* observer = m_observers.get(&treeScope))
+ observer->contentChanged();
+}
+
+DEFINE_TRACE(SVGElementProxy) {
+ visitor->trace(m_clients);
+ visitor->trace(m_observers);
+ visitor->trace(m_document);
+}
+
+void SVGElementProxySet::add(SVGElementProxy& elementProxy) {
+ m_elementProxies.add(&elementProxy);
+}
+
+bool SVGElementProxySet::isEmpty() const {
+ return m_elementProxies.isEmpty();
+}
+
+void SVGElementProxySet::notifyContentChanged(TreeScope& treeScope) {
+ for (SVGElementProxy* proxy : m_elementProxies)
+ proxy->contentChanged(treeScope);
+}
+
+DEFINE_TRACE(SVGElementProxySet) {
+ visitor->trace(m_elementProxies);
+}
+
+} // namespace blink
« no previous file with comments | « third_party/WebKit/Source/core/svg/SVGElementProxy.h ('k') | third_party/WebKit/Source/core/svg/SVGFilterElement.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698