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 |