Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(151)

Side by Side Diff: extensions/renderer/event_emitter.cc

Issue 2768093002: [Reland][Extensions Bindings] Add support for filtered events (Closed)
Patch Set: Fix Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "extensions/renderer/event_emitter.h" 5 #include "extensions/renderer/event_emitter.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 8
9 #include "extensions/renderer/api_event_listeners.h"
9 #include "gin/object_template_builder.h" 10 #include "gin/object_template_builder.h"
10 #include "gin/per_context_data.h" 11 #include "gin/per_context_data.h"
11 12
12 namespace extensions { 13 namespace extensions {
13 14
14 gin::WrapperInfo EventEmitter::kWrapperInfo = {gin::kEmbedderNativeGin}; 15 gin::WrapperInfo EventEmitter::kWrapperInfo = {gin::kEmbedderNativeGin};
15 16
16 EventEmitter::EventEmitter(const binding::RunJSFunction& run_js, 17 EventEmitter::EventEmitter(bool supports_filters,
17 const ListenersChangedMethod& listeners_changed) 18 std::unique_ptr<APIEventListeners> listeners,
18 : run_js_(run_js), listeners_changed_(listeners_changed) {} 19 const binding::RunJSFunction& run_js)
20 : supports_filters_(supports_filters),
21 listeners_(std::move(listeners)),
22 run_js_(run_js) {}
19 23
20 EventEmitter::~EventEmitter() {} 24 EventEmitter::~EventEmitter() {}
21 25
22 gin::ObjectTemplateBuilder EventEmitter::GetObjectTemplateBuilder( 26 gin::ObjectTemplateBuilder EventEmitter::GetObjectTemplateBuilder(
23 v8::Isolate* isolate) { 27 v8::Isolate* isolate) {
24 return Wrappable<EventEmitter>::GetObjectTemplateBuilder(isolate) 28 return Wrappable<EventEmitter>::GetObjectTemplateBuilder(isolate)
25 .SetMethod("addListener", &EventEmitter::AddListener) 29 .SetMethod("addListener", &EventEmitter::AddListener)
26 .SetMethod("removeListener", &EventEmitter::RemoveListener) 30 .SetMethod("removeListener", &EventEmitter::RemoveListener)
27 .SetMethod("hasListener", &EventEmitter::HasListener) 31 .SetMethod("hasListener", &EventEmitter::HasListener)
28 .SetMethod("hasListeners", &EventEmitter::HasListeners) 32 .SetMethod("hasListeners", &EventEmitter::HasListeners)
29 // The following methods aren't part of the public API, but are used 33 // The following methods aren't part of the public API, but are used
30 // by our custom bindings and exposed on the public event object. :( 34 // by our custom bindings and exposed on the public event object. :(
31 // TODO(devlin): Once we convert all custom bindings that use these, 35 // TODO(devlin): Once we convert all custom bindings that use these,
32 // they can be removed. 36 // they can be removed.
33 .SetMethod("dispatch", &EventEmitter::Dispatch); 37 .SetMethod("dispatch", &EventEmitter::Dispatch);
34 } 38 }
35 39
36 void EventEmitter::Fire(v8::Local<v8::Context> context, 40 void EventEmitter::Fire(v8::Local<v8::Context> context,
37 std::vector<v8::Local<v8::Value>>* args) { 41 std::vector<v8::Local<v8::Value>>* args,
38 // We create a local copy of listeners_ since the array can be modified during 42 const EventFilteringInfo* filter) {
39 // handling. 43 // Note that |listeners_| can be modified during handling.
40 std::vector<v8::Local<v8::Function>> listeners; 44 std::vector<v8::Local<v8::Function>> listeners =
41 listeners.reserve(listeners_.size()); 45 listeners_->GetListeners(filter, context);
42 for (const auto& listener : listeners_)
43 listeners.push_back(listener.Get(context->GetIsolate()));
44 46
45 for (const auto& listener : listeners) { 47 for (const auto& listener : listeners) {
46 v8::TryCatch try_catch(context->GetIsolate()); 48 v8::TryCatch try_catch(context->GetIsolate());
47 // SetVerbose() means the error will still get logged, which is what we 49 // SetVerbose() means the error will still get logged, which is what we
48 // want. We don't let it bubble up any further to prevent it from being 50 // want. We don't let it bubble up any further to prevent it from being
49 // surfaced in e.g. JS code that triggered the event. 51 // surfaced in e.g. JS code that triggered the event.
50 try_catch.SetVerbose(true); 52 try_catch.SetVerbose(true);
51 run_js_.Run(listener, context, args->size(), args->data()); 53 run_js_.Run(listener, context, args->size(), args->data());
52 } 54 }
53 } 55 }
54 56
55 void EventEmitter::Invalidate() { 57 void EventEmitter::Invalidate(v8::Local<v8::Context> context) {
56 valid_ = false; 58 valid_ = false;
57 listeners_.clear(); 59 listeners_->Invalidate(context);
60 }
61
62 size_t EventEmitter::GetNumListeners() const {
63 return listeners_->GetNumListeners();
58 } 64 }
59 65
60 void EventEmitter::AddListener(gin::Arguments* arguments) { 66 void EventEmitter::AddListener(gin::Arguments* arguments) {
61 // If script from another context maintains a reference to this object, it's 67 // If script from another context maintains a reference to this object, it's
62 // possible that functions can be called after this object's owning context 68 // possible that functions can be called after this object's owning context
63 // is torn down and released by blink. We don't support this behavior, but 69 // is torn down and released by blink. We don't support this behavior, but
64 // we need to make sure nothing crashes, so early out of methods. 70 // we need to make sure nothing crashes, so early out of methods.
65 if (!valid_) 71 if (!valid_)
66 return; 72 return;
67 73
68 v8::Local<v8::Function> listener; 74 v8::Local<v8::Function> listener;
69 // TODO(devlin): For some reason, we don't throw an error when someone calls 75 // TODO(devlin): For some reason, we don't throw an error when someone calls
70 // add/removeListener with no argument. We probably should. For now, keep 76 // add/removeListener with no argument. We probably should. For now, keep
71 // the status quo, but we should revisit this. 77 // the status quo, but we should revisit this.
72 if (!arguments->GetNext(&listener)) 78 if (!arguments->GetNext(&listener))
73 return; 79 return;
74 80
81 if (!arguments->PeekNext().IsEmpty() && !supports_filters_) {
82 arguments->ThrowTypeError("This event does not support filters");
83 return;
84 }
85
86 v8::Local<v8::Object> filter;
87 if (!arguments->PeekNext().IsEmpty() && !arguments->GetNext(&filter)) {
88 arguments->ThrowTypeError("Invalid invocation");
89 return;
90 }
91
75 v8::Local<v8::Object> holder; 92 v8::Local<v8::Object> holder;
76 CHECK(arguments->GetHolder(&holder)); 93 CHECK(arguments->GetHolder(&holder));
77 CHECK(!holder.IsEmpty()); 94 CHECK(!holder.IsEmpty());
78 v8::Local<v8::Context> context = holder->CreationContext(); 95 v8::Local<v8::Context> context = holder->CreationContext();
79 if (!gin::PerContextData::From(context)) 96 if (!gin::PerContextData::From(context))
80 return; 97 return;
81 98
82 if (!HasListener(listener)) { 99 std::string error;
83 listeners_.push_back( 100 if (!listeners_->AddListener(listener, filter, context, &error) &&
84 v8::Global<v8::Function>(arguments->isolate(), listener)); 101 !error.empty()) {
85 if (listeners_.size() == 1) { 102 arguments->ThrowTypeError(error);
86 listeners_changed_.Run(binding::EventListenersChanged::HAS_LISTENERS,
87 context);
88 }
89 } 103 }
90 } 104 }
91 105
92 void EventEmitter::RemoveListener(gin::Arguments* arguments) { 106 void EventEmitter::RemoveListener(gin::Arguments* arguments) {
93 // See comment in AddListener(). 107 // See comment in AddListener().
94 if (!valid_) 108 if (!valid_)
95 return; 109 return;
96 110
97 v8::Local<v8::Function> listener; 111 v8::Local<v8::Function> listener;
98 // See comment in AddListener(). 112 // See comment in AddListener().
99 if (!arguments->GetNext(&listener)) 113 if (!arguments->GetNext(&listener))
100 return; 114 return;
101 115
102 auto iter = std::find(listeners_.begin(), listeners_.end(), listener); 116 v8::Local<v8::Object> holder;
103 if (iter != listeners_.end()) { 117 CHECK(arguments->GetHolder(&holder));
104 listeners_.erase(iter); 118 CHECK(!holder.IsEmpty());
105 if (listeners_.empty()) { 119 v8::Local<v8::Context> context = holder->CreationContext();
106 v8::Local<v8::Object> holder; 120 listeners_->RemoveListener(listener, context);
107 CHECK(arguments->GetHolder(&holder));
108 CHECK(!holder.IsEmpty());
109 v8::Local<v8::Context> context = holder->CreationContext();
110 listeners_changed_.Run(binding::EventListenersChanged::NO_LISTENERS,
111 context);
112 }
113 }
114 } 121 }
115 122
116 bool EventEmitter::HasListener(v8::Local<v8::Function> listener) { 123 bool EventEmitter::HasListener(v8::Local<v8::Function> listener) {
117 return std::find(listeners_.begin(), listeners_.end(), listener) != 124 return listeners_->HasListener(listener);
118 listeners_.end();
119 } 125 }
120 126
121 bool EventEmitter::HasListeners() { 127 bool EventEmitter::HasListeners() {
122 return !listeners_.empty(); 128 return listeners_->GetNumListeners() != 0;
123 } 129 }
124 130
125 void EventEmitter::Dispatch(gin::Arguments* arguments) { 131 void EventEmitter::Dispatch(gin::Arguments* arguments) {
126 if (!valid_) 132 if (!valid_)
127 return; 133 return;
128 134
129 if (listeners_.empty()) 135 if (listeners_->GetNumListeners() == 0)
130 return; 136 return;
131 v8::HandleScope handle_scope(arguments->isolate()); 137 v8::HandleScope handle_scope(arguments->isolate());
132 v8::Local<v8::Context> context = 138 v8::Local<v8::Context> context =
133 arguments->isolate()->GetCurrentContext(); 139 arguments->isolate()->GetCurrentContext();
134 std::vector<v8::Local<v8::Value>> v8_args; 140 std::vector<v8::Local<v8::Value>> v8_args;
135 if (arguments->Length() > 0) { 141 if (arguments->Length() > 0) {
136 // Converting to v8::Values should never fail. 142 // Converting to v8::Values should never fail.
137 CHECK(arguments->GetRemaining(&v8_args)); 143 CHECK(arguments->GetRemaining(&v8_args));
138 } 144 }
139 Fire(context, &v8_args); 145 Fire(context, &v8_args, nullptr);
140 } 146 }
141 147
142 } // namespace extensions 148 } // namespace extensions
OLDNEW
« no previous file with comments | « extensions/renderer/event_emitter.h ('k') | extensions/renderer/native_extension_bindings_system.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698