Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(69)

Unified Diff: extensions/renderer/api_event_handler.cc

Issue 2727583004: [Extensions Bindings] Add a registerEventArgumentMassager (Closed)
Patch Set: . Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « extensions/renderer/api_event_handler.h ('k') | extensions/renderer/api_event_handler_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: extensions/renderer/api_event_handler.cc
diff --git a/extensions/renderer/api_event_handler.cc b/extensions/renderer/api_event_handler.cc
index 2391607e67ab5955be1ae634c9df4379cd6c6252..d05e9e48c40ad0275f216647b920dc166eb5f1f4 100644
--- a/extensions/renderer/api_event_handler.cc
+++ b/extensions/renderer/api_event_handler.cc
@@ -33,7 +33,7 @@ struct APIEventPerContextData : public base::SupportsUserData::Data {
// v8 objects. This helps us avoid cycles in v8 where an event listener
// could hold a reference to the event, which in turn holds the reference
// to the listener.
- for (const auto& pair : event_data) {
+ for (const auto& pair : emitters) {
EventEmitter* emitter = nullptr;
gin::Converter<EventEmitter*>::FromV8(
isolate, pair.second.Get(isolate), &emitter);
@@ -47,9 +47,59 @@ struct APIEventPerContextData : public base::SupportsUserData::Data {
v8::Isolate* isolate;
// A map from event name -> event emitter.
- std::map<std::string, v8::Global<v8::Object>> event_data;
+ std::map<std::string, v8::Global<v8::Object>> emitters;
+
+ // A map from event name -> argument massager.
+ std::map<std::string, v8::Global<v8::Function>> massagers;
};
+APIEventPerContextData* GetContextData(v8::Local<v8::Context> context,
+ bool should_create) {
+ gin::PerContextData* per_context_data = gin::PerContextData::From(context);
+ if (!per_context_data)
+ return nullptr;
+ auto* data = static_cast<APIEventPerContextData*>(
+ per_context_data->GetUserData(kExtensionAPIEventPerContextKey));
+
+ if (!data && should_create) {
+ auto api_data =
+ base::MakeUnique<APIEventPerContextData>(context->GetIsolate());
+ data = api_data.get();
+ per_context_data->SetUserData(kExtensionAPIEventPerContextKey,
+ api_data.release());
+ }
+
+ return data;
+}
+
+void DispatchEvent(const v8::FunctionCallbackInfo<v8::Value>& info) {
+ v8::Isolate* isolate = info.GetIsolate();
+ v8::HandleScope handle_scope(isolate);
+ if (info.Length() != 1 || !info[0]->IsArray()) {
+ NOTREACHED();
+ return;
+ }
+
+ v8::Local<v8::Context> context = isolate->GetCurrentContext();
+ APIEventPerContextData* data = GetContextData(context, false);
+ DCHECK(data);
+ std::string event_name = gin::V8ToString(info.Data());
+ auto iter = data->emitters.find(event_name);
+ if (iter == data->emitters.end())
+ return;
+ v8::Global<v8::Object>& v8_emitter = iter->second;
+
+ std::vector<v8::Local<v8::Value>> args;
+ CHECK(gin::Converter<std::vector<v8::Local<v8::Value>>>::FromV8(
+ isolate, info[0], &args));
+
+ EventEmitter* emitter = nullptr;
+ gin::Converter<EventEmitter*>::FromV8(isolate, v8_emitter.Get(isolate),
+ &emitter);
+ CHECK(emitter);
+ emitter->Fire(context, &args);
+}
+
} // namespace
APIEventHandler::APIEventHandler(
@@ -67,19 +117,8 @@ v8::Local<v8::Object> APIEventHandler::CreateEventInstance(
// context directly.
v8::Context::Scope context_scope(context);
- gin::PerContextData* per_context_data = gin::PerContextData::From(context);
- DCHECK(per_context_data);
- APIEventPerContextData* data = static_cast<APIEventPerContextData*>(
- per_context_data->GetUserData(kExtensionAPIEventPerContextKey));
- if (!data) {
- auto api_data =
- base::MakeUnique<APIEventPerContextData>(context->GetIsolate());
- data = api_data.get();
- per_context_data->SetUserData(kExtensionAPIEventPerContextKey,
- api_data.release());
- }
-
- DCHECK(data->event_data.find(event_name) == data->event_data.end());
+ APIEventPerContextData* data = GetContextData(context, true);
+ DCHECK(data->emitters.find(event_name) == data->emitters.end());
gin::Handle<EventEmitter> emitter_handle = gin::CreateHandle(
context->GetIsolate(),
@@ -89,7 +128,7 @@ v8::Local<v8::Object> APIEventHandler::CreateEventInstance(
CHECK(emitter_value->IsObject());
v8::Local<v8::Object> emitter_object =
v8::Local<v8::Object>::Cast(emitter_value);
- data->event_data[event_name] =
+ data->emitters[event_name] =
v8::Global<v8::Object>(context->GetIsolate(), emitter_object);
return emitter_object;
@@ -98,46 +137,75 @@ v8::Local<v8::Object> APIEventHandler::CreateEventInstance(
void APIEventHandler::FireEventInContext(const std::string& event_name,
v8::Local<v8::Context> context,
const base::ListValue& args) {
- gin::PerContextData* per_context_data = gin::PerContextData::From(context);
- DCHECK(per_context_data);
- APIEventPerContextData* data = static_cast<APIEventPerContextData*>(
- per_context_data->GetUserData(kExtensionAPIEventPerContextKey));
+ APIEventPerContextData* data = GetContextData(context, false);
if (!data)
return;
- auto iter = data->event_data.find(event_name);
- if (iter == data->event_data.end())
+ auto emitter_iter = data->emitters.find(event_name);
+ if (emitter_iter == data->emitters.end())
+ return;
+
+ EventEmitter* emitter = nullptr;
+ gin::Converter<EventEmitter*>::FromV8(
+ context->GetIsolate(), emitter_iter->second.Get(context->GetIsolate()),
+ &emitter);
+ CHECK(emitter);
+
+ if (emitter->listeners()->empty())
return;
// Note: since we only convert the arguments once, if a listener modifies an
// object (including an array), other listeners will see that modification.
// TODO(devlin): This is how it's always been, but should it be?
- std::vector<v8::Local<v8::Value>> v8_args;
- v8_args.reserve(args.GetSize());
std::unique_ptr<content::V8ValueConverter> converter(
content::V8ValueConverter::create());
- for (const auto& arg : args)
- v8_args.push_back(converter->ToV8Value(arg.get(), context));
- EventEmitter* emitter = nullptr;
- gin::Converter<EventEmitter*>::FromV8(
- context->GetIsolate(), iter->second.Get(context->GetIsolate()), &emitter);
- CHECK(emitter);
+ auto massager_iter = data->massagers.find(event_name);
+ if (massager_iter == data->massagers.end()) {
+ std::vector<v8::Local<v8::Value>> v8_args;
+ v8_args.reserve(args.GetSize());
+ for (const auto& arg : args)
+ v8_args.push_back(converter->ToV8Value(arg.get(), context));
+ emitter->Fire(context, &v8_args);
+ } else {
+ v8::Isolate* isolate = context->GetIsolate();
+ v8::HandleScope handle_scope(isolate);
+ v8::Local<v8::Function> massager = massager_iter->second.Get(isolate);
+ v8::Local<v8::Value> v8_args = converter->ToV8Value(&args, context);
+ DCHECK(!v8_args.IsEmpty());
+ DCHECK(v8_args->IsArray());
+
+ // Curry in the native dispatch function. Some argument massagers take
+ // extra liberties and call this asynchronously, so we can't just have the
+ // massager return a modified array of arguments.
+ // We don't store this in a template because the Data (event name) is
+ // different for each instance. Luckily, this is called during dispatching
+ // an event, rather than e.g. at initialization time.
+ v8::Local<v8::Function> dispatch_event = v8::Function::New(
+ isolate, &DispatchEvent, gin::StringToSymbol(isolate, event_name));
+
+ v8::Local<v8::Value> massager_args[] = {v8_args, dispatch_event};
+ call_js_.Run(massager, context, arraysize(massager_args), massager_args);
+ }
+}
- emitter->Fire(context, &v8_args);
+void APIEventHandler::RegisterArgumentMassager(
+ v8::Local<v8::Context> context,
+ const std::string& event_name,
+ v8::Local<v8::Function> massager) {
+ APIEventPerContextData* data = GetContextData(context, true);
+ DCHECK(data->massagers.find(event_name) == data->massagers.end());
+ data->massagers[event_name].Reset(context->GetIsolate(), massager);
}
size_t APIEventHandler::GetNumEventListenersForTesting(
const std::string& event_name,
v8::Local<v8::Context> context) {
- gin::PerContextData* per_context_data = gin::PerContextData::From(context);
- DCHECK(per_context_data);
- APIEventPerContextData* data = static_cast<APIEventPerContextData*>(
- per_context_data->GetUserData(kExtensionAPIEventPerContextKey));
+ APIEventPerContextData* data = GetContextData(context, false);
DCHECK(data);
- auto iter = data->event_data.find(event_name);
- DCHECK(iter != data->event_data.end());
+ auto iter = data->emitters.find(event_name);
+ DCHECK(iter != data->emitters.end());
EventEmitter* emitter = nullptr;
gin::Converter<EventEmitter*>::FromV8(
context->GetIsolate(), iter->second.Get(context->GetIsolate()), &emitter);
« no previous file with comments | « extensions/renderer/api_event_handler.h ('k') | extensions/renderer/api_event_handler_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698