Index: extensions/renderer/api_event_listeners.h |
diff --git a/extensions/renderer/api_event_listeners.h b/extensions/renderer/api_event_listeners.h |
new file mode 100644 |
index 0000000000000000000000000000000000000000..307730c0f907646387b5024eabaaf42f929925cf |
--- /dev/null |
+++ b/extensions/renderer/api_event_listeners.h |
@@ -0,0 +1,155 @@ |
+// Copyright 2017 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. |
+ |
+#ifndef EXTENSIONS_RENDERER_API_EVENT_LISTENERS_H_ |
+#define EXTENSIONS_RENDERER_API_EVENT_LISTENERS_H_ |
+ |
+#include <string> |
+#include <vector> |
+ |
+#include "base/callback.h" |
+#include "base/macros.h" |
+#include "extensions/common/value_counter.h" |
+#include "extensions/renderer/api_binding_types.h" |
+#include "v8/include/v8.h" |
+ |
+namespace base { |
+class DictionaryValue; |
+} |
+ |
+namespace extensions { |
+class EventFilter; |
+class EventFilteringInfo; |
+ |
+// A base class to hold listeners for a given event. This allows for adding, |
+// removing, and querying listeners in the list, and calling a callback when |
+// transitioning from 0 -> 1 or 1 -> 0 listeners. |
+class APIEventListeners { |
+ public: |
+ using ListenersUpdated = |
+ base::Callback<void(binding::EventListenersChanged, |
+ const base::DictionaryValue* filter, |
+ v8::Local<v8::Context> context)>; |
+ |
+ virtual ~APIEventListeners() = default; |
+ |
+ // Adds the given |listener| to the list, possibly associating it with the |
+ // given |filter|. Returns true if the listener is added. Populates |error| |
+ // with any errors encountered. Note that |error| is *not* always populated |
+ // if false is returned, since we don't consider trying to re-add a listener |
+ // to be an error. |
+ virtual bool AddListener(v8::Local<v8::Function> listener, |
+ v8::Local<v8::Object> filter, |
+ v8::Local<v8::Context> context, |
+ std::string* error) = 0; |
+ |
+ // Removes the given |listener|, if it's present in the list. |
+ virtual void RemoveListener(v8::Local<v8::Function> listener, |
+ v8::Local<v8::Context> context) = 0; |
+ |
+ // Returns true if the given |listener| is in the list. |
+ virtual bool HasListener(v8::Local<v8::Function> listener) = 0; |
+ |
+ // Returns the number of listeners in the list. |
+ virtual size_t GetNumListeners() = 0; |
+ |
+ // Returns the listeners that should be notified for the given |filter|. |
+ virtual std::vector<v8::Local<v8::Function>> GetListeners( |
+ const EventFilteringInfo* filter, |
+ v8::Local<v8::Context> context) = 0; |
+ |
+ // Invalidates the list. |
+ virtual void Invalidate(v8::Local<v8::Context> context) = 0; |
+ |
+ protected: |
+ APIEventListeners() {} |
+ |
+ private: |
+ DISALLOW_COPY_AND_ASSIGN(APIEventListeners); |
+}; |
+ |
+// A listener list implementation that doesn't support filtering. Each event |
+// dispatched is dispatched to all the associated listeners. |
+class UnfilteredEventListeners final : public APIEventListeners { |
+ public: |
+ UnfilteredEventListeners(const ListenersUpdated& listeners_updated); |
+ ~UnfilteredEventListeners() override; |
+ |
+ bool AddListener(v8::Local<v8::Function> listener, |
+ v8::Local<v8::Object> filter, |
+ v8::Local<v8::Context> context, |
+ std::string* error) override; |
+ void RemoveListener(v8::Local<v8::Function> listener, |
+ v8::Local<v8::Context> context) override; |
+ bool HasListener(v8::Local<v8::Function> listener) override; |
+ size_t GetNumListeners() override; |
+ std::vector<v8::Local<v8::Function>> GetListeners( |
+ const EventFilteringInfo* filter, |
+ v8::Local<v8::Context> context) override; |
+ void Invalidate(v8::Local<v8::Context> context) override; |
+ |
+ private: |
+ // The event listeners associated with this event. |
+ // TODO(devlin): Having these listeners held as v8::Globals means that we |
+ // need to worry about cycles when a listener holds a reference to the event, |
+ // e.g. EventEmitter -> Listener -> EventEmitter. Right now, we handle that by |
+ // requiring Invalidate() to be called, but that means that events that aren't |
+ // Invalidate()'d earlier can leak until context destruction. We could |
+ // circumvent this by storing the listeners strongly in a private propery |
+ // (thus traceable by v8), and optionally keep a weak cache on this object. |
+ std::vector<v8::Global<v8::Function>> listeners_; |
+ |
+ ListenersUpdated listeners_updated_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(UnfilteredEventListeners); |
+}; |
+ |
+// A listener list implementation that supports filtering. Events should only |
+// be dispatched to those listeners whose filters match. Additionally, the |
+// updated callback is triggered any time a listener with a new filter is |
+// added, or the last listener with a given filter is removed. |
+class FilteredEventListeners final : public APIEventListeners { |
+ public: |
+ FilteredEventListeners(const ListenersUpdated& listeners_updated, |
+ const std::string& event_name, |
+ EventFilter* event_filter); |
+ ~FilteredEventListeners() override; |
+ |
+ bool AddListener(v8::Local<v8::Function> listener, |
+ v8::Local<v8::Object> filter, |
+ v8::Local<v8::Context> context, |
+ std::string* error) override; |
+ void RemoveListener(v8::Local<v8::Function> listener, |
+ v8::Local<v8::Context> context) override; |
+ bool HasListener(v8::Local<v8::Function> listener) override; |
+ size_t GetNumListeners() override; |
+ std::vector<v8::Local<v8::Function>> GetListeners( |
+ const EventFilteringInfo* filter, |
+ v8::Local<v8::Context> context) override; |
+ void Invalidate(v8::Local<v8::Context> context) override; |
+ |
+ private: |
+ struct ListenerData; |
+ |
+ void InvalidateListener(const ListenerData& listener, |
+ v8::Local<v8::Context> context); |
+ |
+ // Note: See TODO on UnfilteredEventListeners::listeners_. |
+ std::vector<ListenerData> listeners_; |
+ |
+ ListenersUpdated listeners_updated_; |
+ |
+ std::string event_name_; |
+ |
+ // The associated EventFilter; required to outlive this object. |
+ EventFilter* event_filter_ = nullptr; |
+ |
+ ValueCounter value_counter_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(FilteredEventListeners); |
+}; |
+ |
+} // namespace extensions |
+ |
+#endif // EXTENSIONS_RENDERER_API_EVENT_LISTENERS_H_ |