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"
13 using base::DictionaryValue
;
15 namespace extensions
{
17 typedef EventFilter::MatcherID MatcherID
;
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()));
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
;
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 {
64 void EventListener::MakeLazy() {
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
),
81 filter_(filter
.Pass()),
85 EventListenerMap::EventListenerMap(Delegate
* delegate
)
86 : delegate_(delegate
) {
89 EventListenerMap::~EventListenerMap() {}
91 bool EventListenerMap::AddListener(scoped_ptr
<EventListener
> listener
) {
92 if (HasListener(listener
.get()))
94 if (listener
->filter()) {
95 scoped_ptr
<EventMatcher
> matcher(ParseEventMatcher(listener
->filter()));
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());
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();
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
);
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())
144 for (ListenerList::iterator it2
= it
->second
.begin();
145 it2
!= it
->second
.end(); it2
++) {
146 if ((*it2
)->extension_id() == extension_id
)
152 bool EventListenerMap::HasListener(const EventListener
* listener
) {
153 ListenerMap::iterator it
= listeners_
.find(listener
->event_name());
154 if (it
== listeners_
.end())
156 for (ListenerList::iterator it2
= it
->second
.begin();
157 it2
!= it
->second
.end(); it2
++) {
158 if ((*it2
)->Equals(listener
)) {
165 bool EventListenerMap::HasProcessListener(content::RenderProcessHost
* process
,
166 const std::string
& extension_id
) {
167 for (ListenerMap::iterator it
= listeners_
.begin(); it
!= listeners_
.end();
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
)
179 void EventListenerMap::RemoveListenersForExtension(
180 const std::string
& extension_id
) {
181 for (ListenerMap::iterator it
= listeners_
.begin(); it
!= listeners_
.end();
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());
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
))
215 for (size_t i
= 0; i
< filter_list
->GetSize(); i
++) {
216 const DictionaryValue
* filter
= NULL
;
217 if (!filter_list
->GetDictionary(i
, &filter
))
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
,
233 for (std::set
<MatcherID
>::iterator id
= ids
.begin(); id
!= ids
.end();
235 EventListener
* listener
= listeners_by_matcher_id_
[*id
];
237 interested_listeners
.insert(listener
);
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
) {
253 for (ListenerMap::iterator it
= listeners_
.begin(); it
!= listeners_
.end();
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());
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)
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