Chromium Code Reviews| Index: chrome/browser/extensions/event_listener_map.cc |
| diff --git a/chrome/browser/extensions/event_listener_map.cc b/chrome/browser/extensions/event_listener_map.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..f78ecc315a7721a789c8fc33968b8cd6f0abe991 |
| --- /dev/null |
| +++ b/chrome/browser/extensions/event_listener_map.cc |
| @@ -0,0 +1,208 @@ |
| +// Copyright (c) 2012 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 "chrome/browser/extensions/event_listener_map.h" |
| + |
| +#include "base/values.h" |
| + |
| +#include "chrome/browser/extensions/extension_event_router.h" |
| + |
| +EventListener::EventListener(const std::string& event_name, |
| + const std::string& extension_id, |
| + content::RenderProcessHost* process, |
| + scoped_ptr<DictionaryValue> filter) |
| + : event_name(event_name), |
| + extension_id(extension_id), |
| + process(process), |
| + filter(filter.Pass()), |
| + matcher_id(-1) {} |
| + |
| +EventListener::~EventListener() {} |
| + |
| +bool EventListener::Equals(const EventListener* other) { |
| + // We don't check matcher_id equality because we want a listener with a |
| + // filter that hasn't been added to EventFilter to match one that is |
| + // equivalent but has. |
| + return event_name == other->event_name && |
| + extension_id == other->extension_id && |
| + process == other->process && |
| + ((!!filter.get()) == (!!other->filter.get())) && |
| + (!filter.get() || filter->Equals(other->filter.get())); |
| +} |
| + |
| +scoped_ptr<EventListener> EventListener::Copy() const { |
| + scoped_ptr<DictionaryValue> filter_copy; |
| + if (filter.get()) |
| + filter_copy.reset(filter->DeepCopy()); |
| + return scoped_ptr<EventListener>(new EventListener(event_name, extension_id, |
| + process, |
| + filter_copy.Pass())); |
| +} |
| + |
| +EventListenerMap::EventListenerMap() { |
| +} |
| + |
| +EventListenerMap::~EventListenerMap() {} |
| + |
| +bool EventListenerMap::AddListener(scoped_ptr<EventListener> listener) { |
| + if (HasListener(listener.get())) |
| + return false; |
| + if (listener->filter.get()) { |
| + scoped_ptr<EventMatcher> matcher(ParseEventMatcer(listener->filter.get())); |
| + int id = event_filter_.AddEventMatcher(listener->event_name, |
| + matcher.Pass()); |
| + listener->matcher_id = id; |
| + listeners_by_matcher_id_.insert(std::make_pair(id, listener.get())); |
|
Matt Perry
2012/06/13 01:24:27
listeners_by_matcher_id_[id] = listener.get()
koz (OOO until 15th September)
2012/06/14 02:15:55
Done.
|
| + filtered_events_.insert(listener->event_name); |
| + } |
| + linked_ptr<EventListener> listener_ptr(listener.release()); |
| + listeners_[listener_ptr->event_name].push_back(listener_ptr); |
| + |
| + return true; |
| +} |
| + |
| +scoped_ptr<EventMatcher> EventListenerMap::ParseEventMatcer( |
|
Matt Perry
2012/06/13 01:24:27
typo - Matcer
koz (OOO until 15th September)
2012/06/14 02:15:55
Done.
|
| + DictionaryValue* filter_dict) { |
| + return scoped_ptr<EventMatcher>(new EventMatcher( |
| + scoped_ptr<DictionaryValue>(filter_dict->DeepCopy()))); |
| +} |
| + |
| +bool EventListenerMap::RemoveListener(scoped_ptr<EventListener> listener) { |
| + ListenerList& listeners = listeners_[listener->event_name]; |
| + for (ListenerList::iterator it = listeners.begin(); it != listeners.end();) { |
| + if ((*it)->Equals(listener.get())) { |
| + CleanupListener(it->get()); |
| + it = listeners.erase(it); |
| + return true; |
| + } else { |
| + it++; |
| + } |
| + } |
| + return false; |
| +} |
| + |
| +bool EventListenerMap::AnyListenersForEvent(const std::string& event_name) { |
| + ListenerMap::iterator it = listeners_.find(event_name); |
| + return it != listeners_.end() && !it->second.empty(); |
| +} |
| + |
| +bool EventListenerMap::AnyListenersForExtension( |
| + const std::string& extension_id, const std::string& event_name) { |
| + ListenerMap::iterator it = listeners_.find(event_name); |
| + if (it == listeners_.end()) |
| + return false; |
| + |
| + for (ListenerList::iterator it2 = it->second.begin(); |
| + it2 != it->second.end(); it2++) { |
| + if ((*it2)->extension_id == extension_id) |
| + return true; |
| + } |
| + return false; |
| +} |
| + |
| +bool EventListenerMap::HasListener(const EventListener* listener) { |
| + ListenerMap::iterator it = listeners_.find(listener->event_name); |
| + if (it == listeners_.end()) |
| + return false; |
| + for (ListenerList::iterator it2 = it->second.begin(); |
| + it2 != it->second.end(); it2++) { |
| + if ((*it2)->Equals(listener)) { |
| + return true; |
| + } |
| + } |
| + return false; |
| +} |
| + |
| +void EventListenerMap::RemoveLazyListenersFor(const std::string extension_id) { |
| + for (ListenerMap::iterator it = listeners_.begin(); it != listeners_.end(); |
| + it++) { |
| + for (ListenerList::iterator it2 = it->second.begin(); |
| + it2 != it->second.end();) { |
| + if (!(*it2)->process && (*it2)->extension_id == extension_id) { |
| + CleanupListener(it2->get()); |
| + it2 = it->second.erase(it2); |
| + } else { |
| + it2++; |
| + } |
| + } |
| + } |
| +} |
| + |
| +void EventListenerMap::AddLazyListenersFromPreferences( |
| + const std::string& extension_id, |
| + std::set<std::string>& unfiltered, |
| + const DictionaryValue& filtered) { |
| + for (std::set<std::string>::iterator it = unfiltered.begin(); |
| + it != unfiltered.end(); ++it) { |
| + scoped_ptr<EventListener> listener(new EventListener( |
| + *it, extension_id, NULL, |
| + scoped_ptr<DictionaryValue>())); |
| + AddListener(listener.Pass()); |
| + } |
| + |
| + for (DictionaryValue::key_iterator it = filtered.begin_keys(); |
| + it != filtered.end_keys(); ++it) { |
| + DictionaryValue* filter; |
| + CHECK(filtered.GetDictionary(*it, &filter)); |
|
Matt Perry
2012/06/13 01:24:27
Prefs can get corrupted, so don't rely on them bei
koz (OOO until 15th September)
2012/06/14 02:15:55
Done.
|
| + scoped_ptr<EventListener> listener(new EventListener( |
| + *it, extension_id, NULL, |
| + scoped_ptr<DictionaryValue>(filter->DeepCopy()))); |
| + AddListener(listener.Pass()); |
| + } |
| +} |
| + |
| +scoped_ptr<std::set<const EventListener*> > EventListenerMap::GetEventTargets( |
| + const ExtensionEvent& event) { |
| + scoped_ptr<std::set<const EventListener*> > interested_listeners( |
| + new std::set<const EventListener*>); |
| + if (IsFilteredEvent(event)) { |
| + // Look up the interested listeners via the EventFilter. |
| + std::set<int> ids = event_filter_.MatchEvent(event.event_name, event.info); |
| + for (std::set<int>::iterator id = ids.begin(); id != ids.end(); id++) { |
| + EventListener* listener = listeners_by_matcher_id_[*id]; |
| + CHECK(listener); |
| + interested_listeners->insert(listener); |
| + } |
| + } else { |
| + ListenerList& listeners = listeners_[event.event_name]; |
| + for (ListenerList::const_iterator it = listeners.begin(); |
| + it != listeners.end(); it++) { |
| + interested_listeners->insert(it->get()); |
| + } |
| + } |
| + |
| + return interested_listeners.Pass(); |
| +} |
| + |
| +EventListenerMap::ListenerList EventListenerMap::RemoveListenersForProcess( |
| + const content::RenderProcessHost* process) { |
| + CHECK(process); |
| + ListenerList result; |
| + for (ListenerMap::iterator it = listeners_.begin(); it != listeners_.end(); |
| + it++) { |
| + for (ListenerList::iterator it2 = it->second.begin(); |
| + it2 != it->second.end();) { |
| + if ((*it2)->process == process) { |
| + result.push_back(*it2); |
| + CleanupListener(it2->get()); |
| + it2 = it->second.erase(it2); |
| + } else { |
| + it2++; |
| + } |
| + } |
| + } |
| + return result; |
| +} |
| + |
| +void EventListenerMap::CleanupListener(EventListener* listener) { |
| + // If the listener doesn't have a filter then we have nothing to clean up. |
| + if (listener->matcher_id == -1) |
| + return; |
| + event_filter_.RemoveEventMatcher(listener->matcher_id); |
| + CHECK_EQ(1u, listeners_by_matcher_id_.erase(listener->matcher_id)); |
| +} |
| + |
| +bool EventListenerMap::IsFilteredEvent(const ExtensionEvent& event) const { |
| + return filtered_events_.count(event.event_name) > 0u; |
| +} |