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 "extensions/browser/event_router.h"
9 #include "ipc/ipc_message.h"
11 using base::DictionaryValue
;
13 namespace extensions
{
15 typedef EventFilter::MatcherID MatcherID
;
17 EventListener::EventListener(const std::string
& event_name
,
18 const std::string
& extension_id
,
19 content::RenderProcessHost
* process
,
20 scoped_ptr
<DictionaryValue
> filter
)
21 : event_name(event_name
),
22 extension_id(extension_id
),
24 filter(filter
.Pass()),
27 EventListener::~EventListener() {}
29 bool EventListener::Equals(const EventListener
* other
) const {
30 // We don't check matcher_id equality because we want a listener with a
31 // filter that hasn't been added to EventFilter to match one that is
32 // equivalent but has.
33 return event_name
== other
->event_name
&&
34 extension_id
== other
->extension_id
&&
35 process
== other
->process
&&
36 ((!!filter
.get()) == (!!other
->filter
.get())) &&
37 (!filter
.get() || filter
->Equals(other
->filter
.get()));
40 scoped_ptr
<EventListener
> EventListener::Copy() const {
41 scoped_ptr
<DictionaryValue
> filter_copy
;
43 filter_copy
.reset(filter
->DeepCopy());
44 return scoped_ptr
<EventListener
>(new EventListener(event_name
, extension_id
,
49 EventListenerMap::EventListenerMap(Delegate
* delegate
)
50 : delegate_(delegate
) {
53 EventListenerMap::~EventListenerMap() {}
55 bool EventListenerMap::AddListener(scoped_ptr
<EventListener
> listener
) {
56 if (HasListener(listener
.get()))
58 if (listener
->filter
) {
59 scoped_ptr
<EventMatcher
> matcher(ParseEventMatcher(listener
->filter
.get()));
60 MatcherID id
= event_filter_
.AddEventMatcher(listener
->event_name
,
62 listener
->matcher_id
= id
;
63 listeners_by_matcher_id_
[id
] = listener
.get();
64 filtered_events_
.insert(listener
->event_name
);
66 linked_ptr
<EventListener
> listener_ptr(listener
.release());
67 listeners_
[listener_ptr
->event_name
].push_back(listener_ptr
);
69 delegate_
->OnListenerAdded(listener_ptr
.get());
74 scoped_ptr
<EventMatcher
> EventListenerMap::ParseEventMatcher(
75 DictionaryValue
* filter_dict
) {
76 return scoped_ptr
<EventMatcher
>(new EventMatcher(
77 scoped_ptr
<DictionaryValue
>(filter_dict
->DeepCopy()), MSG_ROUTING_NONE
));
80 bool EventListenerMap::RemoveListener(const EventListener
* listener
) {
81 ListenerList
& listeners
= listeners_
[listener
->event_name
];
82 for (ListenerList::iterator it
= listeners
.begin(); it
!= listeners
.end();
84 if ((*it
)->Equals(listener
)) {
85 CleanupListener(it
->get());
86 // Popping from the back should be cheaper than erase(it).
87 std::swap(*it
, listeners
.back());
89 delegate_
->OnListenerRemoved(listener
);
96 bool EventListenerMap::HasListenerForEvent(const std::string
& event_name
) {
97 ListenerMap::iterator it
= listeners_
.find(event_name
);
98 return it
!= listeners_
.end() && !it
->second
.empty();
101 bool EventListenerMap::HasListenerForExtension(
102 const std::string
& extension_id
,
103 const std::string
& event_name
) {
104 ListenerMap::iterator it
= listeners_
.find(event_name
);
105 if (it
== listeners_
.end())
108 for (ListenerList::iterator it2
= it
->second
.begin();
109 it2
!= it
->second
.end(); it2
++) {
110 if ((*it2
)->extension_id
== extension_id
)
116 bool EventListenerMap::HasListener(const EventListener
* listener
) {
117 ListenerMap::iterator it
= listeners_
.find(listener
->event_name
);
118 if (it
== listeners_
.end())
120 for (ListenerList::iterator it2
= it
->second
.begin();
121 it2
!= it
->second
.end(); it2
++) {
122 if ((*it2
)->Equals(listener
)) {
129 bool EventListenerMap::HasProcessListener(content::RenderProcessHost
* process
,
130 const std::string
& extension_id
) {
131 for (ListenerMap::iterator it
= listeners_
.begin(); it
!= listeners_
.end();
133 for (ListenerList::iterator it2
= it
->second
.begin();
134 it2
!= it
->second
.end(); it2
++) {
135 if ((*it2
)->process
== process
&& (*it2
)->extension_id
== extension_id
)
142 void EventListenerMap::RemoveLazyListenersForExtension(
143 const std::string
& extension_id
) {
144 for (ListenerMap::iterator it
= listeners_
.begin(); it
!= listeners_
.end();
146 for (ListenerList::iterator it2
= it
->second
.begin();
147 it2
!= it
->second
.end();) {
148 if (!(*it2
)->process
&& (*it2
)->extension_id
== extension_id
) {
149 CleanupListener(it2
->get());
150 it2
= it
->second
.erase(it2
);
158 void EventListenerMap::LoadUnfilteredLazyListeners(
159 const std::string
& extension_id
,
160 const std::set
<std::string
>& event_names
) {
161 for (std::set
<std::string
>::const_iterator it
= event_names
.begin();
162 it
!= event_names
.end(); ++it
) {
163 AddListener(scoped_ptr
<EventListener
>(new EventListener(
164 *it
, extension_id
, NULL
, scoped_ptr
<DictionaryValue
>())));
168 void EventListenerMap::LoadFilteredLazyListeners(
169 const std::string
& extension_id
,
170 const DictionaryValue
& filtered
) {
171 for (DictionaryValue::Iterator
it(filtered
); !it
.IsAtEnd(); it
.Advance()) {
172 // We skip entries if they are malformed.
173 const base::ListValue
* filter_list
= NULL
;
174 if (!it
.value().GetAsList(&filter_list
))
176 for (size_t i
= 0; i
< filter_list
->GetSize(); i
++) {
177 const DictionaryValue
* filter
= NULL
;
178 if (!filter_list
->GetDictionary(i
, &filter
))
180 AddListener(scoped_ptr
<EventListener
>(new EventListener(
181 it
.key(), extension_id
, NULL
,
182 scoped_ptr
<DictionaryValue
>(filter
->DeepCopy()))));
187 std::set
<const EventListener
*> EventListenerMap::GetEventListeners(
188 const Event
& event
) {
189 std::set
<const EventListener
*> interested_listeners
;
190 if (IsFilteredEvent(event
)) {
191 // Look up the interested listeners via the EventFilter.
192 std::set
<MatcherID
> ids
=
193 event_filter_
.MatchEvent(event
.event_name
, event
.filter_info
,
195 for (std::set
<MatcherID
>::iterator id
= ids
.begin(); id
!= ids
.end();
197 EventListener
* listener
= listeners_by_matcher_id_
[*id
];
199 interested_listeners
.insert(listener
);
202 ListenerList
& listeners
= listeners_
[event
.event_name
];
203 for (ListenerList::const_iterator it
= listeners
.begin();
204 it
!= listeners
.end(); it
++) {
205 interested_listeners
.insert(it
->get());
209 return interested_listeners
;
212 void EventListenerMap::RemoveListenersForProcess(
213 const content::RenderProcessHost
* process
) {
215 for (ListenerMap::iterator it
= listeners_
.begin(); it
!= listeners_
.end();
217 for (ListenerList::iterator it2
= it
->second
.begin();
218 it2
!= it
->second
.end();) {
219 if ((*it2
)->process
== process
) {
220 linked_ptr
<EventListener
> listener(*it2
);
221 CleanupListener(it2
->get());
222 it2
= it
->second
.erase(it2
);
223 delegate_
->OnListenerRemoved(listener
.get());
231 void EventListenerMap::CleanupListener(EventListener
* listener
) {
232 // If the listener doesn't have a filter then we have nothing to clean up.
233 if (listener
->matcher_id
== -1)
235 event_filter_
.RemoveEventMatcher(listener
->matcher_id
);
236 CHECK_EQ(1u, listeners_by_matcher_id_
.erase(listener
->matcher_id
));
239 bool EventListenerMap::IsFilteredEvent(const Event
& event
) const {
240 return filtered_events_
.count(event
.event_name
) > 0u;
243 } // namespace extensions