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

Side by Side Diff: third_party/WebKit/Source/core/svg/SVGElementProxy.cpp

Issue 2401343002: Tracking filter mutation via SVGElementProxy (Closed)
Patch Set: Tweak lifecycle checks 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 unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "core/svg/SVGElementProxy.h"
6
7 #include "core/dom/IdTargetObserver.h"
8 #include "core/fetch/FetchInitiatorTypeNames.h"
9 #include "core/fetch/FetchRequest.h"
10 #include "core/fetch/ResourceFetcher.h"
11 #include "core/svg/SVGElement.h"
12 #include "core/svg/SVGFilterElement.h"
13 #include "core/svg/SVGResourceClient.h"
14
15 namespace blink {
16
17 class SVGElementProxy::IdObserver : public IdTargetObserver {
18 public:
19 IdObserver(TreeScope& treeScope, SVGElementProxy& proxy)
20 : IdTargetObserver(treeScope.idTargetObserverRegistry(), proxy.id()),
21 m_treeScope(&treeScope) {}
22
23 void addClient(SVGResourceClient* client) { m_clients.add(client); }
24 bool removeClient(SVGResourceClient* client) {
25 return m_clients.remove(client);
26 }
27
28 TreeScope* treeScope() const { return m_treeScope; }
29 void transferClients(IdObserver& observer) {
30 for (const auto& client : m_clients)
31 observer.m_clients.add(client.key, client.value);
32 m_clients.clear();
33 }
34
35 DEFINE_INLINE_VIRTUAL_TRACE() {
36 visitor->trace(m_clients);
37 visitor->trace(m_treeScope);
38 IdTargetObserver::trace(visitor);
39 }
40
41 void contentChanged() {
42 DCHECK(lifecycle().state() <= DocumentLifecycle::CompositingClean ||
43 lifecycle().state() >= DocumentLifecycle::PaintClean);
44 HeapVector<Member<SVGResourceClient>> clients;
45 copyToVector(m_clients, clients);
46 for (SVGResourceClient* client : clients)
47 client->resourceContentChanged();
48 }
49
50 private:
51 const DocumentLifecycle& lifecycle() const {
52 return m_treeScope->document().lifecycle();
53 }
54 void idTargetChanged() override {
55 DCHECK(lifecycle().stateAllowsTreeMutations());
56 DCHECK(lifecycle().state() <= DocumentLifecycle::CompositingClean ||
esprehn 2016/11/04 23:58:07 I'm not sure this holds true, can't something like
fs 2016/11/07 12:59:20 Since both of these are not strict less/greater th
57 lifecycle().state() >= DocumentLifecycle::PaintClean);
58 HeapVector<Member<SVGResourceClient>> clients;
59 copyToVector(m_clients, clients);
60 for (SVGResourceClient* client : clients)
61 client->resourceElementChanged();
62 }
63 HeapHashCountedSet<Member<SVGResourceClient>> m_clients;
64 Member<TreeScope> m_treeScope;
65 };
66
67 SVGElementProxy::SVGElementProxy(const AtomicString& id)
68 : m_id(id), m_isLocal(true) {}
69
70 SVGElementProxy::SVGElementProxy(const String& url, const AtomicString& id)
71 : m_id(id), m_url(url), m_isLocal(false) {}
72
73 SVGElementProxy::~SVGElementProxy() {}
74
75 void SVGElementProxy::addClient(SVGResourceClient* client) {
76 // An empty id will never be a valid element reference.
77 if (m_id.isEmpty())
78 return;
79 if (m_document) {
80 m_document->addClient(client);
81 return;
82 }
83 TreeScope* clientScope = client->treeScope();
84 TreeScope* lookupScope =
85 clientScope ? treeScopeForLookup(*clientScope) : nullptr;
86 if (!lookupScope)
87 return;
88 // Ensure sure we have an observer registered for this tree scope.
89 auto& scopeObserver =
90 m_observers.add(lookupScope, nullptr).storedValue->value;
91 if (!scopeObserver)
92 scopeObserver = new IdObserver(*lookupScope, *this);
93
94 auto& observer = m_clients.add(client, nullptr).storedValue->value;
95 if (!observer)
96 observer = scopeObserver;
97
98 DCHECK(observer && scopeObserver);
99
100 // If the client moved to a different scope, we need to unregister the old
101 // observer and transfer any clients from it before replacing it. Thus any
102 // clients that remain to be removed will be transferred to the new observer,
103 // and hence removed from it instead.
104 if (observer != scopeObserver) {
105 observer->unregister();
106 observer->transferClients(*scopeObserver);
107 observer = scopeObserver;
108 }
109 observer->addClient(client);
110 }
111
112 void SVGElementProxy::removeClient(SVGResourceClient* client) {
113 // An empty id will never be a valid element reference.
114 if (m_id.isEmpty())
115 return;
116 if (m_document) {
117 m_document->removeClient(client);
118 return;
119 }
120 auto entry = m_clients.find(client);
121 if (entry == m_clients.end())
122 return;
123 IdObserver* observer = entry->value;
124 DCHECK(observer);
125 // If the client is not the last client in the scope, then no further action
126 // needs to be taken.
127 if (!observer->removeClient(client))
128 return;
129 // Unregister and drop the scope association, then drop the client.
130 observer->unregister();
131 m_observers.remove(observer->treeScope());
132 m_clients.remove(entry);
133 }
134
135 void SVGElementProxy::resolve(Document& document) {
136 if (m_isLocal || m_id.isEmpty() || m_url.isEmpty())
137 return;
138 FetchRequest request(ResourceRequest(m_url), FetchInitiatorTypeNames::css);
139 m_document = DocumentResource::fetchSVGDocument(request, document.fetcher());
140 m_url = String();
141 }
142
143 TreeScope* SVGElementProxy::treeScopeForLookup(TreeScope& treeScope) const {
144 if (m_isLocal)
145 return &treeScope;
146 if (!m_document)
147 return nullptr;
148 return m_document->document();
149 }
150
151 SVGElement* SVGElementProxy::findElement(TreeScope& treeScope) {
152 // An empty id will never be a valid element reference.
153 if (m_id.isEmpty())
154 return nullptr;
155 TreeScope* lookupScope = treeScopeForLookup(treeScope);
156 if (!lookupScope)
157 return nullptr;
158 if (Element* targetElement = lookupScope->getElementById(m_id)) {
159 if (isSVGFilterElement(*targetElement)) {
160 toSVGFilterElement(*targetElement).elementProxySet().add(*this);
161 return toSVGElement(targetElement);
162 }
163 }
164 return nullptr;
165 }
166
167 void SVGElementProxy::contentChanged(TreeScope& treeScope) {
168 if (auto observer = m_observers.get(&treeScope))
esprehn 2016/11/04 23:58:07 We usually do auto* or auto& to make it clear you'
fs 2016/11/07 12:59:20 Fixed.
169 observer->contentChanged();
170 }
171
172 DEFINE_TRACE(SVGElementProxy) {
173 visitor->trace(m_clients);
174 visitor->trace(m_observers);
175 visitor->trace(m_document);
176 }
177
178 void SVGElementProxySet::add(SVGElementProxy& elementProxy) {
179 m_elementProxies.add(&elementProxy);
180 }
181
182 bool SVGElementProxySet::isEmpty() const {
183 return m_elementProxies.isEmpty();
184 }
185
186 void SVGElementProxySet::notifyContentChanged(TreeScope& treeScope) {
187 for (SVGElementProxy* proxy : m_elementProxies)
188 proxy->contentChanged(treeScope);
189 }
190
191 DEFINE_TRACE(SVGElementProxySet) {
192 visitor->trace(m_elementProxies);
193 }
194
195 } // namespace blink
OLDNEW
« 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