| 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 |