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

Side by Side Diff: extensions/renderer/api_event_handler.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/api_event_handler.h" 5 #include "extensions/renderer/api_event_handler.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <map> 8 #include <map>
9 #include <memory> 9 #include <memory>
10 #include <vector> 10 #include <vector>
11 11
12 #include "base/bind.h" 12 #include "base/bind.h"
13 #include "base/logging.h" 13 #include "base/logging.h"
14 #include "base/memory/ptr_util.h" 14 #include "base/memory/ptr_util.h"
15 #include "base/supports_user_data.h" 15 #include "base/supports_user_data.h"
16 #include "base/values.h" 16 #include "base/values.h"
17 #include "content/public/child/v8_value_converter.h" 17 #include "content/public/child/v8_value_converter.h"
18 #include "extensions/renderer/api_event_listeners.h"
18 #include "extensions/renderer/event_emitter.h" 19 #include "extensions/renderer/event_emitter.h"
19 #include "gin/handle.h" 20 #include "gin/handle.h"
20 #include "gin/per_context_data.h" 21 #include "gin/per_context_data.h"
21 22
22 namespace extensions { 23 namespace extensions {
23 24
24 namespace { 25 namespace {
25 26
26 void DoNothingOnListenersChanged(binding::EventListenersChanged change, 27 void DoNothingOnListenersChanged(binding::EventListenersChanged change,
28 const base::DictionaryValue* filter,
27 v8::Local<v8::Context> context) {} 29 v8::Local<v8::Context> context) {}
28 30
29 const char kExtensionAPIEventPerContextKey[] = "extension_api_events"; 31 const char kExtensionAPIEventPerContextKey[] = "extension_api_events";
30 32
31 struct APIEventPerContextData : public base::SupportsUserData::Data { 33 struct APIEventPerContextData : public base::SupportsUserData::Data {
32 APIEventPerContextData(v8::Isolate* isolate) : isolate(isolate) {} 34 APIEventPerContextData(v8::Isolate* isolate) : isolate(isolate) {}
33 ~APIEventPerContextData() override { 35 ~APIEventPerContextData() override {
34 DCHECK(emitters.empty()) 36 DCHECK(emitters.empty())
35 << "|emitters| should have been cleared by InvalidateContext()"; 37 << "|emitters| should have been cleared by InvalidateContext()";
36 DCHECK(massagers.empty()) 38 DCHECK(massagers.empty())
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
91 v8::Global<v8::Object>& v8_emitter = iter->second; 93 v8::Global<v8::Object>& v8_emitter = iter->second;
92 94
93 std::vector<v8::Local<v8::Value>> args; 95 std::vector<v8::Local<v8::Value>> args;
94 CHECK(gin::Converter<std::vector<v8::Local<v8::Value>>>::FromV8( 96 CHECK(gin::Converter<std::vector<v8::Local<v8::Value>>>::FromV8(
95 isolate, info[0], &args)); 97 isolate, info[0], &args));
96 98
97 EventEmitter* emitter = nullptr; 99 EventEmitter* emitter = nullptr;
98 gin::Converter<EventEmitter*>::FromV8(isolate, v8_emitter.Get(isolate), 100 gin::Converter<EventEmitter*>::FromV8(isolate, v8_emitter.Get(isolate),
99 &emitter); 101 &emitter);
100 CHECK(emitter); 102 CHECK(emitter);
101 emitter->Fire(context, &args); 103 emitter->Fire(context, &args, nullptr);
102 } 104 }
103 105
104 } // namespace 106 } // namespace
105 107
106 APIEventHandler::APIEventHandler( 108 APIEventHandler::APIEventHandler(
107 const binding::RunJSFunction& call_js, 109 const binding::RunJSFunction& call_js,
108 const EventListenersChangedMethod& listeners_changed) 110 const EventListenersChangedMethod& listeners_changed)
109 : call_js_(call_js), listeners_changed_(listeners_changed) {} 111 : call_js_(call_js), listeners_changed_(listeners_changed) {}
110 APIEventHandler::~APIEventHandler() {} 112 APIEventHandler::~APIEventHandler() {}
111 113
112 v8::Local<v8::Object> APIEventHandler::CreateEventInstance( 114 v8::Local<v8::Object> APIEventHandler::CreateEventInstance(
113 const std::string& event_name, 115 const std::string& event_name,
116 bool supports_filters,
114 v8::Local<v8::Context> context) { 117 v8::Local<v8::Context> context) {
115 // We need a context scope since gin::CreateHandle only takes the isolate 118 // We need a context scope since gin::CreateHandle only takes the isolate
116 // and infers the context from that. 119 // and infers the context from that.
117 // TODO(devlin): This could be avoided if gin::CreateHandle could take a 120 // TODO(devlin): This could be avoided if gin::CreateHandle could take a
118 // context directly. 121 // context directly.
119 v8::Context::Scope context_scope(context); 122 v8::Context::Scope context_scope(context);
120 123
121 APIEventPerContextData* data = GetContextData(context, true); 124 APIEventPerContextData* data = GetContextData(context, true);
122 DCHECK(data->emitters.find(event_name) == data->emitters.end()); 125 DCHECK(data->emitters.find(event_name) == data->emitters.end());
123 126
127 APIEventListeners::ListenersUpdated updated =
128 base::Bind(listeners_changed_, event_name);
129 std::unique_ptr<APIEventListeners> listeners;
130 if (supports_filters) {
131 listeners = base::MakeUnique<FilteredEventListeners>(updated, event_name,
132 &event_filter_);
133 } else {
134 listeners = base::MakeUnique<UnfilteredEventListeners>(updated);
135 }
136
124 gin::Handle<EventEmitter> emitter_handle = gin::CreateHandle( 137 gin::Handle<EventEmitter> emitter_handle = gin::CreateHandle(
125 context->GetIsolate(), 138 context->GetIsolate(),
126 new EventEmitter(call_js_, base::Bind(listeners_changed_, event_name))); 139 new EventEmitter(supports_filters, std::move(listeners), call_js_));
127 CHECK(!emitter_handle.IsEmpty()); 140 CHECK(!emitter_handle.IsEmpty());
128 v8::Local<v8::Value> emitter_value = emitter_handle.ToV8(); 141 v8::Local<v8::Value> emitter_value = emitter_handle.ToV8();
129 CHECK(emitter_value->IsObject()); 142 CHECK(emitter_value->IsObject());
130 v8::Local<v8::Object> emitter_object = 143 v8::Local<v8::Object> emitter_object =
131 v8::Local<v8::Object>::Cast(emitter_value); 144 v8::Local<v8::Object>::Cast(emitter_value);
132 data->emitters[event_name] = 145 data->emitters[event_name] =
133 v8::Global<v8::Object>(context->GetIsolate(), emitter_object); 146 v8::Global<v8::Object>(context->GetIsolate(), emitter_object);
134 147
135 return emitter_object; 148 return emitter_object;
136 } 149 }
137 150
138 v8::Local<v8::Object> APIEventHandler::CreateAnonymousEventInstance( 151 v8::Local<v8::Object> APIEventHandler::CreateAnonymousEventInstance(
139 v8::Local<v8::Context> context) { 152 v8::Local<v8::Context> context) {
140 v8::Context::Scope context_scope(context); 153 v8::Context::Scope context_scope(context);
141 APIEventPerContextData* data = GetContextData(context, true); 154 APIEventPerContextData* data = GetContextData(context, true);
155 bool supports_filters = false;
156 std::unique_ptr<APIEventListeners> listeners =
157 base::MakeUnique<UnfilteredEventListeners>(
158 base::Bind(&DoNothingOnListenersChanged));
142 gin::Handle<EventEmitter> emitter_handle = gin::CreateHandle( 159 gin::Handle<EventEmitter> emitter_handle = gin::CreateHandle(
143 context->GetIsolate(), 160 context->GetIsolate(),
144 new EventEmitter(call_js_, base::Bind(&DoNothingOnListenersChanged))); 161 new EventEmitter(supports_filters, std::move(listeners), call_js_));
145 CHECK(!emitter_handle.IsEmpty()); 162 CHECK(!emitter_handle.IsEmpty());
146 v8::Local<v8::Object> emitter_object = emitter_handle.ToV8().As<v8::Object>(); 163 v8::Local<v8::Object> emitter_object = emitter_handle.ToV8().As<v8::Object>();
147 data->anonymous_emitters.push_back( 164 data->anonymous_emitters.push_back(
148 v8::Global<v8::Object>(context->GetIsolate(), emitter_object)); 165 v8::Global<v8::Object>(context->GetIsolate(), emitter_object));
149 return emitter_object; 166 return emitter_object;
150 } 167 }
151 168
152 void APIEventHandler::InvalidateCustomEvent(v8::Local<v8::Context> context, 169 void APIEventHandler::InvalidateCustomEvent(v8::Local<v8::Context> context,
153 v8::Local<v8::Object> event) { 170 v8::Local<v8::Object> event) {
154 EventEmitter* emitter = nullptr; 171 EventEmitter* emitter = nullptr;
155 APIEventPerContextData* data = GetContextData(context, false); 172 APIEventPerContextData* data = GetContextData(context, false);
156 if (!data || !gin::Converter<EventEmitter*>::FromV8(context->GetIsolate(), 173 if (!data || !gin::Converter<EventEmitter*>::FromV8(context->GetIsolate(),
157 event, &emitter)) { 174 event, &emitter)) {
158 NOTREACHED(); 175 NOTREACHED();
159 return; 176 return;
160 } 177 }
161 178
162 emitter->Invalidate(); 179 emitter->Invalidate(context);
163 auto emitter_entry = std::find(data->anonymous_emitters.begin(), 180 auto emitter_entry = std::find(data->anonymous_emitters.begin(),
164 data->anonymous_emitters.end(), event); 181 data->anonymous_emitters.end(), event);
165 if (emitter_entry == data->anonymous_emitters.end()) { 182 if (emitter_entry == data->anonymous_emitters.end()) {
166 NOTREACHED(); 183 NOTREACHED();
167 return; 184 return;
168 } 185 }
169 186
170 data->anonymous_emitters.erase(emitter_entry); 187 data->anonymous_emitters.erase(emitter_entry);
171 } 188 }
172 189
173 void APIEventHandler::FireEventInContext(const std::string& event_name, 190 void APIEventHandler::FireEventInContext(const std::string& event_name,
174 v8::Local<v8::Context> context, 191 v8::Local<v8::Context> context,
175 const base::ListValue& args) { 192 const base::ListValue& args,
193 const EventFilteringInfo& filter) {
176 APIEventPerContextData* data = GetContextData(context, false); 194 APIEventPerContextData* data = GetContextData(context, false);
177 if (!data) 195 if (!data)
178 return; 196 return;
179 197
180 auto emitter_iter = data->emitters.find(event_name); 198 auto emitter_iter = data->emitters.find(event_name);
181 if (emitter_iter == data->emitters.end()) 199 if (emitter_iter == data->emitters.end())
182 return; 200 return;
183 201
184 EventEmitter* emitter = nullptr; 202 EventEmitter* emitter = nullptr;
185 gin::Converter<EventEmitter*>::FromV8( 203 gin::Converter<EventEmitter*>::FromV8(
186 context->GetIsolate(), emitter_iter->second.Get(context->GetIsolate()), 204 context->GetIsolate(), emitter_iter->second.Get(context->GetIsolate()),
187 &emitter); 205 &emitter);
188 CHECK(emitter); 206 CHECK(emitter);
189 207
190 if (emitter->listeners()->empty()) 208 if (emitter->GetNumListeners() == 0u)
191 return; 209 return;
192 210
193 // Note: since we only convert the arguments once, if a listener modifies an 211 // Note: since we only convert the arguments once, if a listener modifies an
194 // object (including an array), other listeners will see that modification. 212 // object (including an array), other listeners will see that modification.
195 // TODO(devlin): This is how it's always been, but should it be? 213 // TODO(devlin): This is how it's always been, but should it be?
196 std::unique_ptr<content::V8ValueConverter> converter( 214 std::unique_ptr<content::V8ValueConverter> converter(
197 content::V8ValueConverter::create()); 215 content::V8ValueConverter::create());
198 216
199 auto massager_iter = data->massagers.find(event_name); 217 auto massager_iter = data->massagers.find(event_name);
200 if (massager_iter == data->massagers.end()) { 218 if (massager_iter == data->massagers.end()) {
201 std::vector<v8::Local<v8::Value>> v8_args; 219 std::vector<v8::Local<v8::Value>> v8_args;
202 v8_args.reserve(args.GetSize()); 220 v8_args.reserve(args.GetSize());
203 for (const auto& arg : args) 221 for (const auto& arg : args)
204 v8_args.push_back(converter->ToV8Value(arg.get(), context)); 222 v8_args.push_back(converter->ToV8Value(arg.get(), context));
205 emitter->Fire(context, &v8_args); 223 emitter->Fire(context, &v8_args, &filter);
206 } else { 224 } else {
207 v8::Isolate* isolate = context->GetIsolate(); 225 v8::Isolate* isolate = context->GetIsolate();
208 v8::HandleScope handle_scope(isolate); 226 v8::HandleScope handle_scope(isolate);
209 v8::Local<v8::Function> massager = massager_iter->second.Get(isolate); 227 v8::Local<v8::Function> massager = massager_iter->second.Get(isolate);
210 v8::Local<v8::Value> v8_args = converter->ToV8Value(&args, context); 228 v8::Local<v8::Value> v8_args = converter->ToV8Value(&args, context);
211 DCHECK(!v8_args.IsEmpty()); 229 DCHECK(!v8_args.IsEmpty());
212 DCHECK(v8_args->IsArray()); 230 DCHECK(v8_args->IsArray());
213 231
214 // Curry in the native dispatch function. Some argument massagers take 232 // Curry in the native dispatch function. Some argument massagers take
215 // extra liberties and call this asynchronously, so we can't just have the 233 // extra liberties and call this asynchronously, so we can't just have the
(...skipping 30 matching lines...) Expand all
246 v8::HandleScope scope(isolate); 264 v8::HandleScope scope(isolate);
247 265
248 // This loop *shouldn't* allow any self-modification (i.e., no listeners 266 // This loop *shouldn't* allow any self-modification (i.e., no listeners
249 // should be added or removed as a result of the iteration). If that changes, 267 // should be added or removed as a result of the iteration). If that changes,
250 // we'll need to cache the listeners elsewhere before iterating. 268 // we'll need to cache the listeners elsewhere before iterating.
251 for (const auto& pair : data->emitters) { 269 for (const auto& pair : data->emitters) {
252 EventEmitter* emitter = nullptr; 270 EventEmitter* emitter = nullptr;
253 gin::Converter<EventEmitter*>::FromV8(isolate, pair.second.Get(isolate), 271 gin::Converter<EventEmitter*>::FromV8(isolate, pair.second.Get(isolate),
254 &emitter); 272 &emitter);
255 CHECK(emitter); 273 CHECK(emitter);
256 emitter->Invalidate(); 274 emitter->Invalidate(context);
257 // When the context is shut down, all listeners are removed.
258 listeners_changed_.Run(
259 pair.first, binding::EventListenersChanged::NO_LISTENERS, context);
260 } 275 }
261 for (const auto& global : data->anonymous_emitters) { 276 for (const auto& global : data->anonymous_emitters) {
262 EventEmitter* emitter = nullptr; 277 EventEmitter* emitter = nullptr;
263 gin::Converter<EventEmitter*>::FromV8(isolate, global.Get(isolate), 278 gin::Converter<EventEmitter*>::FromV8(isolate, global.Get(isolate),
264 &emitter); 279 &emitter);
265 CHECK(emitter); 280 CHECK(emitter);
266 emitter->Invalidate(); 281 emitter->Invalidate(context);
267 } 282 }
268 283
269 data->emitters.clear(); 284 data->emitters.clear();
270 data->massagers.clear(); 285 data->massagers.clear();
271 data->anonymous_emitters.clear(); 286 data->anonymous_emitters.clear();
272 287
273 // InvalidateContext() is called shortly (and, theoretically, synchronously) 288 // InvalidateContext() is called shortly (and, theoretically, synchronously)
274 // before the PerContextData is deleted. We have a check that guarantees that 289 // before the PerContextData is deleted. We have a check that guarantees that
275 // no new EventEmitters are created after the PerContextData is deleted, so 290 // no new EventEmitters are created after the PerContextData is deleted, so
276 // no new emitters should be created after this point. 291 // no new emitters should be created after this point.
277 } 292 }
278 293
279 size_t APIEventHandler::GetNumEventListenersForTesting( 294 size_t APIEventHandler::GetNumEventListenersForTesting(
280 const std::string& event_name, 295 const std::string& event_name,
281 v8::Local<v8::Context> context) { 296 v8::Local<v8::Context> context) {
282 APIEventPerContextData* data = GetContextData(context, false); 297 APIEventPerContextData* data = GetContextData(context, false);
283 DCHECK(data); 298 DCHECK(data);
284 299
285 auto iter = data->emitters.find(event_name); 300 auto iter = data->emitters.find(event_name);
286 DCHECK(iter != data->emitters.end()); 301 DCHECK(iter != data->emitters.end());
287 EventEmitter* emitter = nullptr; 302 EventEmitter* emitter = nullptr;
288 gin::Converter<EventEmitter*>::FromV8( 303 gin::Converter<EventEmitter*>::FromV8(
289 context->GetIsolate(), iter->second.Get(context->GetIsolate()), &emitter); 304 context->GetIsolate(), iter->second.Get(context->GetIsolate()), &emitter);
290 CHECK(emitter); 305 CHECK(emitter);
291 return emitter->listeners()->size(); 306 return emitter->GetNumListeners();
292 } 307 }
293 308
294 } // namespace extensions 309 } // namespace extensions
OLDNEW
« no previous file with comments | « extensions/renderer/api_event_handler.h ('k') | extensions/renderer/api_event_handler_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698