Home | History | Annotate | Download | only in extensions
      1 // Copyright (c) 2012 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 "chrome/browser/extensions/event_listener_map.h"
      6 
      7 #include "base/values.h"
      8 
      9 #include "chrome/browser/extensions/event_router.h"
     10 #include "ipc/ipc_message.h"
     11 
     12 namespace extensions {
     13 
     14 typedef EventFilter::MatcherID MatcherID;
     15 
     16 EventListener::EventListener(const std::string& event_name,
     17                              const std::string& extension_id,
     18                              content::RenderProcessHost* process,
     19                              scoped_ptr<DictionaryValue> filter)
     20     : event_name(event_name),
     21       extension_id(extension_id),
     22       process(process),
     23       filter(filter.Pass()),
     24       matcher_id(-1) {}
     25 
     26 EventListener::~EventListener() {}
     27 
     28 bool EventListener::Equals(const EventListener* other) const {
     29   // We don't check matcher_id equality because we want a listener with a
     30   // filter that hasn't been added to EventFilter to match one that is
     31   // equivalent but has.
     32   return event_name == other->event_name &&
     33       extension_id == other->extension_id &&
     34       process == other->process &&
     35       ((!!filter.get()) == (!!other->filter.get())) &&
     36       (!filter.get() || filter->Equals(other->filter.get()));
     37 }
     38 
     39 scoped_ptr<EventListener> EventListener::Copy() const {
     40   scoped_ptr<DictionaryValue> filter_copy;
     41   if (filter)
     42     filter_copy.reset(filter->DeepCopy());
     43   return scoped_ptr<EventListener>(new EventListener(event_name, extension_id,
     44                                                      process,
     45                                                      filter_copy.Pass()));
     46 }
     47 
     48 EventListenerMap::EventListenerMap(Delegate* delegate)
     49     : delegate_(delegate) {
     50 }
     51 
     52 EventListenerMap::~EventListenerMap() {}
     53 
     54 bool EventListenerMap::AddListener(scoped_ptr<EventListener> listener) {
     55   if (HasListener(listener.get()))
     56     return false;
     57   if (listener->filter) {
     58     scoped_ptr<EventMatcher> matcher(ParseEventMatcher(listener->filter.get()));
     59     MatcherID id = event_filter_.AddEventMatcher(listener->event_name,
     60                                                  matcher.Pass());
     61     listener->matcher_id = id;
     62     listeners_by_matcher_id_[id] = listener.get();
     63     filtered_events_.insert(listener->event_name);
     64   }
     65   linked_ptr<EventListener> listener_ptr(listener.release());
     66   listeners_[listener_ptr->event_name].push_back(listener_ptr);
     67 
     68   delegate_->OnListenerAdded(listener_ptr.get());
     69 
     70   return true;
     71 }
     72 
     73 scoped_ptr<EventMatcher> EventListenerMap::ParseEventMatcher(
     74     DictionaryValue* filter_dict) {
     75   return scoped_ptr<EventMatcher>(new EventMatcher(
     76       scoped_ptr<DictionaryValue>(filter_dict->DeepCopy()), MSG_ROUTING_NONE));
     77 }
     78 
     79 bool EventListenerMap::RemoveListener(const EventListener* listener) {
     80   ListenerList& listeners = listeners_[listener->event_name];
     81   for (ListenerList::iterator it = listeners.begin(); it != listeners.end();
     82        it++) {
     83     if ((*it)->Equals(listener)) {
     84       CleanupListener(it->get());
     85       // Popping from the back should be cheaper than erase(it).
     86       std::swap(*it, listeners.back());
     87       listeners.pop_back();
     88       delegate_->OnListenerRemoved(listener);
     89       return true;
     90     }
     91   }
     92   return false;
     93 }
     94 
     95 bool EventListenerMap::HasListenerForEvent(const std::string& event_name) {
     96   ListenerMap::iterator it = listeners_.find(event_name);
     97   return it != listeners_.end() && !it->second.empty();
     98 }
     99 
    100 bool EventListenerMap::HasListenerForExtension(
    101     const std::string& extension_id,
    102     const std::string& event_name) {
    103   ListenerMap::iterator it = listeners_.find(event_name);
    104   if (it == listeners_.end())
    105     return false;
    106 
    107   for (ListenerList::iterator it2 = it->second.begin();
    108        it2 != it->second.end(); it2++) {
    109     if ((*it2)->extension_id == extension_id)
    110       return true;
    111   }
    112   return false;
    113 }
    114 
    115 bool EventListenerMap::HasListener(const EventListener* listener) {
    116   ListenerMap::iterator it = listeners_.find(listener->event_name);
    117   if (it == listeners_.end())
    118     return false;
    119   for (ListenerList::iterator it2 = it->second.begin();
    120        it2 != it->second.end(); it2++) {
    121     if ((*it2)->Equals(listener)) {
    122       return true;
    123     }
    124   }
    125   return false;
    126 }
    127 
    128 bool EventListenerMap::HasProcessListener(content::RenderProcessHost* process,
    129                                           const std::string& extension_id) {
    130   for (ListenerMap::iterator it = listeners_.begin(); it != listeners_.end();
    131        it++) {
    132     for (ListenerList::iterator it2 = it->second.begin();
    133          it2 != it->second.end(); it2++) {
    134       if ((*it2)->process == process && (*it2)->extension_id == extension_id)
    135         return true;
    136     }
    137   }
    138   return false;
    139 }
    140 
    141 void EventListenerMap::RemoveLazyListenersForExtension(
    142     const std::string& extension_id) {
    143   for (ListenerMap::iterator it = listeners_.begin(); it != listeners_.end();
    144        it++) {
    145     for (ListenerList::iterator it2 = it->second.begin();
    146          it2 != it->second.end();) {
    147       if (!(*it2)->process && (*it2)->extension_id == extension_id) {
    148         CleanupListener(it2->get());
    149         it2 = it->second.erase(it2);
    150       } else {
    151         it2++;
    152       }
    153     }
    154   }
    155 }
    156 
    157 void EventListenerMap::LoadUnfilteredLazyListeners(
    158     const std::string& extension_id,
    159     const std::set<std::string>& event_names) {
    160   for (std::set<std::string>::const_iterator it = event_names.begin();
    161        it != event_names.end(); ++it) {
    162     AddListener(scoped_ptr<EventListener>(new EventListener(
    163         *it, extension_id, NULL, scoped_ptr<DictionaryValue>())));
    164   }
    165 }
    166 
    167 void EventListenerMap::LoadFilteredLazyListeners(
    168     const std::string& extension_id,
    169     const DictionaryValue& filtered) {
    170   for (DictionaryValue::Iterator it(filtered); !it.IsAtEnd(); it.Advance()) {
    171     // We skip entries if they are malformed.
    172     const base::ListValue* filter_list = NULL;
    173     if (!it.value().GetAsList(&filter_list))
    174       continue;
    175     for (size_t i = 0; i < filter_list->GetSize(); i++) {
    176       const DictionaryValue* filter = NULL;
    177       if (!filter_list->GetDictionary(i, &filter))
    178         continue;
    179       AddListener(scoped_ptr<EventListener>(new EventListener(
    180           it.key(), extension_id, NULL,
    181           scoped_ptr<DictionaryValue>(filter->DeepCopy()))));
    182     }
    183   }
    184 }
    185 
    186 std::set<const EventListener*> EventListenerMap::GetEventListeners(
    187     const Event& event) {
    188   std::set<const EventListener*> interested_listeners;
    189   if (IsFilteredEvent(event)) {
    190     // Look up the interested listeners via the EventFilter.
    191     std::set<MatcherID> ids =
    192         event_filter_.MatchEvent(event.event_name, event.filter_info,
    193             MSG_ROUTING_NONE);
    194     for (std::set<MatcherID>::iterator id = ids.begin(); id != ids.end();
    195          id++) {
    196       EventListener* listener = listeners_by_matcher_id_[*id];
    197       CHECK(listener);
    198       interested_listeners.insert(listener);
    199     }
    200   } else {
    201     ListenerList& listeners = listeners_[event.event_name];
    202     for (ListenerList::const_iterator it = listeners.begin();
    203          it != listeners.end(); it++) {
    204       interested_listeners.insert(it->get());
    205     }
    206   }
    207 
    208   return interested_listeners;
    209 }
    210 
    211 void EventListenerMap::RemoveListenersForProcess(
    212     const content::RenderProcessHost* process) {
    213   CHECK(process);
    214   for (ListenerMap::iterator it = listeners_.begin(); it != listeners_.end();
    215        it++) {
    216     for (ListenerList::iterator it2 = it->second.begin();
    217          it2 != it->second.end();) {
    218       if ((*it2)->process == process) {
    219         linked_ptr<EventListener> listener(*it2);
    220         CleanupListener(it2->get());
    221         it2 = it->second.erase(it2);
    222         delegate_->OnListenerRemoved(listener.get());
    223       } else {
    224         it2++;
    225       }
    226     }
    227   }
    228 }
    229 
    230 void EventListenerMap::CleanupListener(EventListener* listener) {
    231   // If the listener doesn't have a filter then we have nothing to clean up.
    232   if (listener->matcher_id == -1)
    233     return;
    234   event_filter_.RemoveEventMatcher(listener->matcher_id);
    235   CHECK_EQ(1u, listeners_by_matcher_id_.erase(listener->matcher_id));
    236 }
    237 
    238 bool EventListenerMap::IsFilteredEvent(const Event& event) const {
    239   return filtered_events_.count(event.event_name) > 0u;
    240 }
    241 
    242 }  // namespace extensions
    243