| 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/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 Loading... |
| 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 Loading... |
| 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 |
| OLD | NEW |