OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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_bindings.h" | 5 #include "extensions/renderer/event_bindings.h" |
6 | 6 |
7 #include <stdint.h> | 7 #include <stdint.h> |
8 | 8 |
9 #include <map> | 9 #include <map> |
10 #include <memory> | 10 #include <memory> |
(...skipping 220 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
231 context->v8_context()), | 231 context->v8_context()), |
232 listener_ids, | 232 listener_ids, |
233 }; | 233 }; |
234 | 234 |
235 context->module_system()->CallModuleMethodSafe( | 235 context->module_system()->CallModuleMethodSafe( |
236 kEventBindings, "dispatchEvent", arraysize(v8_args), v8_args); | 236 kEventBindings, "dispatchEvent", arraysize(v8_args), v8_args); |
237 } | 237 } |
238 | 238 |
239 void EventBindings::AttachEventHandler( | 239 void EventBindings::AttachEventHandler( |
240 const v8::FunctionCallbackInfo<v8::Value>& args) { | 240 const v8::FunctionCallbackInfo<v8::Value>& args) { |
241 CHECK_EQ(1, args.Length()); | 241 CHECK_EQ(2, args.Length()); |
242 CHECK(args[0]->IsString()); | 242 CHECK(args[0]->IsString()); |
243 AttachEvent(*v8::String::Utf8Value(args[0])); | 243 CHECK(args[1]->IsBoolean()); |
| 244 AttachEvent(*v8::String::Utf8Value(args[0]), args[1]->BooleanValue()); |
244 } | 245 } |
245 | 246 |
246 void EventBindings::AttachEvent(const std::string& event_name) { | 247 void EventBindings::AttachEvent(const std::string& event_name, |
| 248 bool supports_lazy_listeners) { |
247 if (!context()->HasAccessOrThrowError(event_name)) | 249 if (!context()->HasAccessOrThrowError(event_name)) |
248 return; | 250 return; |
249 | 251 |
250 // Record the attachment for this context so that events can be detached when | 252 // Record the attachment for this context so that events can be detached when |
251 // the context is destroyed. | 253 // the context is destroyed. |
252 // | 254 // |
253 // Ideally we'd CHECK that it's not already attached, however that's not | 255 // Ideally we'd CHECK that it's not already attached, however that's not |
254 // possible because extensions can create and attach events themselves. Very | 256 // possible because extensions can create and attach events themselves. Very |
255 // silly, but that's the way it is. For an example of this, see | 257 // silly, but that's the way it is. For an example of this, see |
256 // chrome/test/data/extensions/api_test/events/background.js. | 258 // chrome/test/data/extensions/api_test/events/background.js. |
257 attached_event_names_.insert(event_name); | 259 attached_event_names_.insert(event_name); |
258 | 260 |
259 if (IncrementEventListenerCount(context(), event_name) == 1) { | 261 if (IncrementEventListenerCount(context(), event_name) == 1) { |
260 ipc_message_sender_->SendAddUnfilteredEventListenerIPC(context(), | 262 ipc_message_sender_->SendAddUnfilteredEventListenerIPC(context(), |
261 event_name); | 263 event_name); |
262 } | 264 } |
263 | 265 |
264 // This is called the first time the page has added a listener. Since | 266 // This is called the first time the page has added a listener. Since |
265 // the background page is the only lazy page, we know this is the first | 267 // the background page is the only lazy page, we know this is the first |
266 // time this listener has been registered. | 268 // time this listener has been registered. |
267 if (IsLazyContext(context())) { | 269 if (IsLazyContext(context()) && supports_lazy_listeners) { |
268 ipc_message_sender_->SendAddUnfilteredLazyEventListenerIPC(context(), | 270 ipc_message_sender_->SendAddUnfilteredLazyEventListenerIPC(context(), |
269 event_name); | 271 event_name); |
270 } | 272 } |
271 } | 273 } |
272 | 274 |
273 void EventBindings::DetachEventHandler( | 275 void EventBindings::DetachEventHandler( |
274 const v8::FunctionCallbackInfo<v8::Value>& args) { | 276 const v8::FunctionCallbackInfo<v8::Value>& args) { |
275 CHECK_EQ(2, args.Length()); | 277 CHECK_EQ(3, args.Length()); |
276 CHECK(args[0]->IsString()); | 278 CHECK(args[0]->IsString()); |
277 CHECK(args[1]->IsBoolean()); | 279 CHECK(args[1]->IsBoolean()); |
278 DetachEvent(*v8::String::Utf8Value(args[0]), args[1]->BooleanValue()); | 280 CHECK(args[2]->IsBoolean()); |
| 281 bool was_manual = args[1]->BooleanValue(); |
| 282 bool supports_lazy_listeners = args[2]->BooleanValue(); |
| 283 DetachEvent(*v8::String::Utf8Value(args[0]), |
| 284 was_manual && supports_lazy_listeners); |
279 } | 285 } |
280 | 286 |
281 void EventBindings::DetachEvent(const std::string& event_name, bool is_manual) { | 287 void EventBindings::DetachEvent(const std::string& event_name, |
| 288 bool remove_lazy_listener) { |
282 // See comment in AttachEvent(). | 289 // See comment in AttachEvent(). |
283 attached_event_names_.erase(event_name); | 290 attached_event_names_.erase(event_name); |
284 | 291 |
285 if (DecrementEventListenerCount(context(), event_name) == 0) { | 292 if (DecrementEventListenerCount(context(), event_name) == 0) { |
286 ipc_message_sender_->SendRemoveUnfilteredEventListenerIPC(context(), | 293 ipc_message_sender_->SendRemoveUnfilteredEventListenerIPC(context(), |
287 event_name); | 294 event_name); |
288 } | 295 } |
289 | 296 |
290 // DetachEvent is called when the last listener for the context is | 297 // DetachEvent is called when the last listener for the context is |
291 // removed. If the context is the background page or service worker, and it | 298 // removed. If the context is the background page or service worker, and it |
292 // removes the last listener manually, then we assume that it is no longer | 299 // removes the last listener manually, then we assume that it is no longer |
293 // interested in being awakened for this event. | 300 // interested in being awakened for this event. |
294 if (is_manual && IsLazyContext(context())) { | 301 if (remove_lazy_listener && IsLazyContext(context())) { |
295 ipc_message_sender_->SendRemoveUnfilteredLazyEventListenerIPC(context(), | 302 ipc_message_sender_->SendRemoveUnfilteredLazyEventListenerIPC(context(), |
296 event_name); | 303 event_name); |
297 } | 304 } |
298 } | 305 } |
299 | 306 |
300 // MatcherID AttachFilteredEvent(string event_name, object filter) | 307 // MatcherID AttachFilteredEvent(string event_name, object filter) |
301 // event_name - Name of the event to attach. | 308 // event_name - Name of the event to attach. |
302 // filter - Which instances of the named event are we interested in. | 309 // filter - Which instances of the named event are we interested in. |
303 // returns the id assigned to the listener, which will be provided to calls to | 310 // returns the id assigned to the listener, which will be provided to calls to |
304 // dispatchEvent(). | 311 // dispatchEvent(). |
305 void EventBindings::AttachFilteredEvent( | 312 void EventBindings::AttachFilteredEvent( |
306 const v8::FunctionCallbackInfo<v8::Value>& args) { | 313 const v8::FunctionCallbackInfo<v8::Value>& args) { |
307 CHECK_EQ(2, args.Length()); | 314 CHECK_EQ(3, args.Length()); |
308 CHECK(args[0]->IsString()); | 315 CHECK(args[0]->IsString()); |
309 CHECK(args[1]->IsObject()); | 316 CHECK(args[1]->IsObject()); |
| 317 CHECK(args[2]->IsBoolean()); |
310 | 318 |
311 std::string event_name = *v8::String::Utf8Value(args[0]); | 319 std::string event_name = *v8::String::Utf8Value(args[0]); |
312 if (!context()->HasAccessOrThrowError(event_name)) | 320 if (!context()->HasAccessOrThrowError(event_name)) |
313 return; | 321 return; |
314 | 322 |
315 std::unique_ptr<base::DictionaryValue> filter; | 323 std::unique_ptr<base::DictionaryValue> filter; |
316 { | 324 { |
317 std::unique_ptr<base::Value> filter_value = | 325 std::unique_ptr<base::Value> filter_value = |
318 content::V8ValueConverter::Create()->FromV8Value( | 326 content::V8ValueConverter::Create()->FromV8Value( |
319 v8::Local<v8::Object>::Cast(args[1]), context()->v8_context()); | 327 v8::Local<v8::Object>::Cast(args[1]), context()->v8_context()); |
320 if (!filter_value || !filter_value->IsType(base::Value::Type::DICTIONARY)) { | 328 if (!filter_value || !filter_value->IsType(base::Value::Type::DICTIONARY)) { |
321 args.GetReturnValue().Set(static_cast<int32_t>(-1)); | 329 args.GetReturnValue().Set(static_cast<int32_t>(-1)); |
322 return; | 330 return; |
323 } | 331 } |
324 filter = base::DictionaryValue::From(std::move(filter_value)); | 332 filter = base::DictionaryValue::From(std::move(filter_value)); |
325 } | 333 } |
326 | 334 |
| 335 bool supports_lazy_listeners = args[2]->BooleanValue(); |
| 336 |
327 int id = g_event_filter.Get().AddEventMatcher( | 337 int id = g_event_filter.Get().AddEventMatcher( |
328 event_name, | 338 event_name, |
329 base::MakeUnique<EventMatcher>( | 339 base::MakeUnique<EventMatcher>( |
330 std::move(filter), context()->GetRenderFrame()->GetRoutingID())); | 340 std::move(filter), context()->GetRenderFrame()->GetRoutingID())); |
331 if (id == -1) { | 341 if (id == -1) { |
332 args.GetReturnValue().Set(static_cast<int32_t>(-1)); | 342 args.GetReturnValue().Set(static_cast<int32_t>(-1)); |
333 return; | 343 return; |
334 } | 344 } |
335 attached_matcher_ids_.insert(id); | 345 attached_matcher_ids_.insert(id); |
336 | 346 |
337 // Only send IPCs the first time a filter gets added. | 347 // Only send IPCs the first time a filter gets added. |
338 const EventMatcher* matcher = g_event_filter.Get().GetEventMatcher(id); | 348 const EventMatcher* matcher = g_event_filter.Get().GetEventMatcher(id); |
339 DCHECK(matcher); | 349 DCHECK(matcher); |
340 base::DictionaryValue* filter_weak = matcher->value(); | 350 base::DictionaryValue* filter_weak = matcher->value(); |
341 const ExtensionId& extension_id = context()->GetExtensionID(); | 351 const ExtensionId& extension_id = context()->GetExtensionID(); |
342 if (AddFilter(event_name, extension_id, *filter_weak)) { | 352 if (AddFilter(event_name, extension_id, *filter_weak)) { |
343 bool lazy = ExtensionFrameHelper::IsContextForEventPage(context()); | 353 bool lazy = supports_lazy_listeners && |
| 354 ExtensionFrameHelper::IsContextForEventPage(context()); |
344 ipc_message_sender_->SendAddFilteredEventListenerIPC(context(), event_name, | 355 ipc_message_sender_->SendAddFilteredEventListenerIPC(context(), event_name, |
345 *filter_weak, lazy); | 356 *filter_weak, lazy); |
346 } | 357 } |
347 | 358 |
348 args.GetReturnValue().Set(static_cast<int32_t>(id)); | 359 args.GetReturnValue().Set(static_cast<int32_t>(id)); |
349 } | 360 } |
350 | 361 |
351 void EventBindings::DetachFilteredEventHandler( | 362 void EventBindings::DetachFilteredEventHandler( |
352 const v8::FunctionCallbackInfo<v8::Value>& args) { | 363 const v8::FunctionCallbackInfo<v8::Value>& args) { |
353 CHECK_EQ(2, args.Length()); | 364 CHECK_EQ(3, args.Length()); |
354 CHECK(args[0]->IsInt32()); | 365 CHECK(args[0]->IsInt32()); |
355 CHECK(args[1]->IsBoolean()); | 366 CHECK(args[1]->IsBoolean()); |
356 DetachFilteredEvent(args[0]->Int32Value(), args[1]->BooleanValue()); | 367 CHECK(args[2]->IsBoolean()); |
| 368 bool was_manual = args[1]->BooleanValue(); |
| 369 bool supports_lazy_listeners = args[2]->BooleanValue(); |
| 370 DetachFilteredEvent(args[0]->Int32Value(), |
| 371 was_manual && supports_lazy_listeners); |
357 } | 372 } |
358 | 373 |
359 void EventBindings::DetachFilteredEvent(int matcher_id, bool is_manual) { | 374 void EventBindings::DetachFilteredEvent(int matcher_id, |
| 375 bool remove_lazy_event) { |
360 EventFilter& event_filter = g_event_filter.Get(); | 376 EventFilter& event_filter = g_event_filter.Get(); |
361 EventMatcher* event_matcher = event_filter.GetEventMatcher(matcher_id); | 377 EventMatcher* event_matcher = event_filter.GetEventMatcher(matcher_id); |
362 | 378 |
363 const std::string& event_name = event_filter.GetEventName(matcher_id); | 379 const std::string& event_name = event_filter.GetEventName(matcher_id); |
364 | 380 |
365 // Only send IPCs the last time a filter gets removed. | 381 // Only send IPCs the last time a filter gets removed. |
366 const ExtensionId& extension_id = context()->GetExtensionID(); | 382 const ExtensionId& extension_id = context()->GetExtensionID(); |
367 if (RemoveFilter(event_name, extension_id, event_matcher->value())) { | 383 if (RemoveFilter(event_name, extension_id, event_matcher->value())) { |
368 bool remove_lazy = | 384 bool remove_lazy = remove_lazy_event && |
369 is_manual && ExtensionFrameHelper::IsContextForEventPage(context()); | 385 ExtensionFrameHelper::IsContextForEventPage(context()); |
370 ipc_message_sender_->SendRemoveFilteredEventListenerIPC( | 386 ipc_message_sender_->SendRemoveFilteredEventListenerIPC( |
371 context(), event_name, *event_matcher->value(), remove_lazy); | 387 context(), event_name, *event_matcher->value(), remove_lazy); |
372 } | 388 } |
373 | 389 |
374 event_filter.RemoveEventMatcher(matcher_id); | 390 event_filter.RemoveEventMatcher(matcher_id); |
375 attached_matcher_ids_.erase(matcher_id); | 391 attached_matcher_ids_.erase(matcher_id); |
376 } | 392 } |
377 | 393 |
378 void EventBindings::AttachUnmanagedEvent( | 394 void EventBindings::AttachUnmanagedEvent( |
379 const v8::FunctionCallbackInfo<v8::Value>& args) { | 395 const v8::FunctionCallbackInfo<v8::Value>& args) { |
(...skipping 30 matching lines...) Expand all Loading... |
410 for (int matcher_id : attached_matcher_ids_safe) { | 426 for (int matcher_id : attached_matcher_ids_safe) { |
411 DetachFilteredEvent(matcher_id, false /* is_manual */); | 427 DetachFilteredEvent(matcher_id, false /* is_manual */); |
412 } | 428 } |
413 DCHECK(attached_matcher_ids_.empty()) | 429 DCHECK(attached_matcher_ids_.empty()) |
414 << "Filtered events cannot be attached during invalidation"; | 430 << "Filtered events cannot be attached during invalidation"; |
415 | 431 |
416 g_unmanaged_listeners.Get().erase(context()); | 432 g_unmanaged_listeners.Get().erase(context()); |
417 } | 433 } |
418 | 434 |
419 } // namespace extensions | 435 } // namespace extensions |
OLD | NEW |