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