Re-subimission of https://codereview.chromium.org/1041213003/
[chromium-blink-merge.git] / extensions / browser / event_listener_map.cc
blob8d1f5cad73f9f1118ec3f6bd77ce2b0e695f864c
1 // Copyright 2013 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.
5 #include "extensions/browser/event_listener_map.h"
7 #include "base/values.h"
8 #include "content/public/browser/render_process_host.h"
9 #include "extensions/browser/event_router.h"
10 #include "ipc/ipc_message.h"
11 #include "url/gurl.h"
13 using base::DictionaryValue;
15 namespace extensions {
17 typedef EventFilter::MatcherID MatcherID;
19 // static
20 scoped_ptr<EventListener> EventListener::ForExtension(
21 const std::string& event_name,
22 const std::string& extension_id,
23 content::RenderProcessHost* process,
24 scoped_ptr<base::DictionaryValue> filter) {
25 return make_scoped_ptr(new EventListener(
26 event_name, extension_id, GURL(), process, filter.Pass()));
29 // static
30 scoped_ptr<EventListener> EventListener::ForURL(
31 const std::string& event_name,
32 const GURL& listener_url,
33 content::RenderProcessHost* process,
34 scoped_ptr<base::DictionaryValue> filter) {
35 return make_scoped_ptr(
36 new EventListener(event_name, "", listener_url, process, filter.Pass()));
39 EventListener::~EventListener() {}
41 bool EventListener::Equals(const EventListener* other) const {
42 // We don't check matcher_id equality because we want a listener with a
43 // filter that hasn't been added to EventFilter to match one that is
44 // equivalent but has.
45 return event_name_ == other->event_name_ &&
46 extension_id_ == other->extension_id_ &&
47 listener_url_ == other->listener_url_ && process_ == other->process_ &&
48 ((!!filter_.get()) == (!!other->filter_.get())) &&
49 (!filter_.get() || filter_->Equals(other->filter_.get()));
52 scoped_ptr<EventListener> EventListener::Copy() const {
53 scoped_ptr<DictionaryValue> filter_copy;
54 if (filter_)
55 filter_copy.reset(filter_->DeepCopy());
56 return scoped_ptr<EventListener>(new EventListener(
57 event_name_, extension_id_, listener_url_, process_, filter_copy.Pass()));
60 bool EventListener::IsLazy() const {
61 return !process_;
64 void EventListener::MakeLazy() {
65 process_ = NULL;
68 content::BrowserContext* EventListener::GetBrowserContext() const {
69 return process_ ? process_->GetBrowserContext() : NULL;
72 EventListener::EventListener(const std::string& event_name,
73 const std::string& extension_id,
74 const GURL& listener_url,
75 content::RenderProcessHost* process,
76 scoped_ptr<DictionaryValue> filter)
77 : event_name_(event_name),
78 extension_id_(extension_id),
79 listener_url_(listener_url),
80 process_(process),
81 filter_(filter.Pass()),
82 matcher_id_(-1) {
85 EventListenerMap::EventListenerMap(Delegate* delegate)
86 : delegate_(delegate) {
89 EventListenerMap::~EventListenerMap() {}
91 bool EventListenerMap::AddListener(scoped_ptr<EventListener> listener) {
92 if (HasListener(listener.get()))
93 return false;
94 if (listener->filter()) {
95 scoped_ptr<EventMatcher> matcher(ParseEventMatcher(listener->filter()));
96 MatcherID id =
97 event_filter_.AddEventMatcher(listener->event_name(), matcher.Pass());
98 listener->set_matcher_id(id);
99 listeners_by_matcher_id_[id] = listener.get();
100 filtered_events_.insert(listener->event_name());
102 linked_ptr<EventListener> listener_ptr(listener.release());
103 listeners_[listener_ptr->event_name()].push_back(listener_ptr);
105 delegate_->OnListenerAdded(listener_ptr.get());
107 return true;
110 scoped_ptr<EventMatcher> EventListenerMap::ParseEventMatcher(
111 DictionaryValue* filter_dict) {
112 return scoped_ptr<EventMatcher>(new EventMatcher(
113 make_scoped_ptr(filter_dict->DeepCopy()), MSG_ROUTING_NONE));
116 bool EventListenerMap::RemoveListener(const EventListener* listener) {
117 ListenerList& listeners = listeners_[listener->event_name()];
118 for (ListenerList::iterator it = listeners.begin(); it != listeners.end();
119 it++) {
120 if ((*it)->Equals(listener)) {
121 CleanupListener(it->get());
122 // Popping from the back should be cheaper than erase(it).
123 std::swap(*it, listeners.back());
124 listeners.pop_back();
125 delegate_->OnListenerRemoved(listener);
126 return true;
129 return false;
132 bool EventListenerMap::HasListenerForEvent(const std::string& event_name) {
133 ListenerMap::iterator it = listeners_.find(event_name);
134 return it != listeners_.end() && !it->second.empty();
137 bool EventListenerMap::HasListenerForExtension(
138 const std::string& extension_id,
139 const std::string& event_name) {
140 ListenerMap::iterator it = listeners_.find(event_name);
141 if (it == listeners_.end())
142 return false;
144 for (ListenerList::iterator it2 = it->second.begin();
145 it2 != it->second.end(); it2++) {
146 if ((*it2)->extension_id() == extension_id)
147 return true;
149 return false;
152 bool EventListenerMap::HasListener(const EventListener* listener) {
153 ListenerMap::iterator it = listeners_.find(listener->event_name());
154 if (it == listeners_.end())
155 return false;
156 for (ListenerList::iterator it2 = it->second.begin();
157 it2 != it->second.end(); it2++) {
158 if ((*it2)->Equals(listener)) {
159 return true;
162 return false;
165 bool EventListenerMap::HasProcessListener(content::RenderProcessHost* process,
166 const std::string& extension_id) {
167 for (ListenerMap::iterator it = listeners_.begin(); it != listeners_.end();
168 it++) {
169 for (ListenerList::iterator it2 = it->second.begin();
170 it2 != it->second.end(); it2++) {
171 if ((*it2)->process() == process &&
172 (*it2)->extension_id() == extension_id)
173 return true;
176 return false;
179 void EventListenerMap::RemoveListenersForExtension(
180 const std::string& extension_id) {
181 for (ListenerMap::iterator it = listeners_.begin(); it != listeners_.end();
182 it++) {
183 for (ListenerList::iterator it2 = it->second.begin();
184 it2 != it->second.end();) {
185 if ((*it2)->extension_id() == extension_id) {
186 linked_ptr<EventListener> listener(*it2);
187 CleanupListener(listener.get());
188 it2 = it->second.erase(it2);
189 delegate_->OnListenerRemoved(listener.get());
190 } else {
191 it2++;
197 void EventListenerMap::LoadUnfilteredLazyListeners(
198 const std::string& extension_id,
199 const std::set<std::string>& event_names) {
200 for (std::set<std::string>::const_iterator it = event_names.begin();
201 it != event_names.end(); ++it) {
202 AddListener(EventListener::ForExtension(
203 *it, extension_id, NULL, scoped_ptr<DictionaryValue>()));
207 void EventListenerMap::LoadFilteredLazyListeners(
208 const std::string& extension_id,
209 const DictionaryValue& filtered) {
210 for (DictionaryValue::Iterator it(filtered); !it.IsAtEnd(); it.Advance()) {
211 // We skip entries if they are malformed.
212 const base::ListValue* filter_list = NULL;
213 if (!it.value().GetAsList(&filter_list))
214 continue;
215 for (size_t i = 0; i < filter_list->GetSize(); i++) {
216 const DictionaryValue* filter = NULL;
217 if (!filter_list->GetDictionary(i, &filter))
218 continue;
219 AddListener(EventListener::ForExtension(
220 it.key(), extension_id, NULL, make_scoped_ptr(filter->DeepCopy())));
225 std::set<const EventListener*> EventListenerMap::GetEventListeners(
226 const Event& event) {
227 std::set<const EventListener*> interested_listeners;
228 if (IsFilteredEvent(event)) {
229 // Look up the interested listeners via the EventFilter.
230 std::set<MatcherID> ids =
231 event_filter_.MatchEvent(event.event_name, event.filter_info,
232 MSG_ROUTING_NONE);
233 for (std::set<MatcherID>::iterator id = ids.begin(); id != ids.end();
234 id++) {
235 EventListener* listener = listeners_by_matcher_id_[*id];
236 CHECK(listener);
237 interested_listeners.insert(listener);
239 } else {
240 ListenerList& listeners = listeners_[event.event_name];
241 for (ListenerList::const_iterator it = listeners.begin();
242 it != listeners.end(); it++) {
243 interested_listeners.insert(it->get());
247 return interested_listeners;
250 void EventListenerMap::RemoveListenersForProcess(
251 const content::RenderProcessHost* process) {
252 CHECK(process);
253 for (ListenerMap::iterator it = listeners_.begin(); it != listeners_.end();
254 it++) {
255 for (ListenerList::iterator it2 = it->second.begin();
256 it2 != it->second.end();) {
257 if ((*it2)->process() == process) {
258 linked_ptr<EventListener> listener(*it2);
259 CleanupListener(it2->get());
260 it2 = it->second.erase(it2);
261 delegate_->OnListenerRemoved(listener.get());
262 } else {
263 it2++;
269 void EventListenerMap::CleanupListener(EventListener* listener) {
270 // If the listener doesn't have a filter then we have nothing to clean up.
271 if (listener->matcher_id() == -1)
272 return;
273 event_filter_.RemoveEventMatcher(listener->matcher_id());
274 CHECK_EQ(1u, listeners_by_matcher_id_.erase(listener->matcher_id()));
277 bool EventListenerMap::IsFilteredEvent(const Event& event) const {
278 return filtered_events_.count(event.event_name) > 0u;
281 } // namespace extensions