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

Side by Side Diff: extensions/renderer/api_event_handler.cc

Issue 2469593002: [Extensions Bindings] Add Events support (Closed)
Patch Set: asantest Created 4 years, 1 month 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 unified diff | Download patch
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "extensions/renderer/api_event_handler.h"
6
7 #include <algorithm>
8 #include <map>
9 #include <memory>
10 #include <vector>
11
12 #include "base/bind.h"
13 #include "base/logging.h"
14 #include "base/memory/ptr_util.h"
15 #include "base/supports_user_data.h"
16 #include "base/values.h"
17 #include "content/public/child/v8_value_converter.h"
18 #include "extensions/renderer/event_emitter.h"
19 #include "gin/handle.h"
20 #include "gin/per_context_data.h"
21
22 namespace extensions {
23
24 namespace {
25
26 const char kExtensionAPIEventPerContextKey[] = "extension_api_events";
27
28 struct APIEventPerContextData : public base::SupportsUserData::Data {
29 APIEventPerContextData(v8::Isolate* isolate) : isolate(isolate) {}
30 ~APIEventPerContextData() override {
31 v8::HandleScope scope(isolate);
32 // We explicitly clear the event data map here to remove all references to
33 // v8 objects. This helps us avoid cycles in v8 where an event listener
34 // could hold a reference to the event, which in turn holds the reference
35 // to the listener.
36 for (const auto& pair : event_data) {
37 EventEmitter* emitter = nullptr;
38 gin::Converter<EventEmitter*>::FromV8(
39 isolate, pair.second.Get(isolate), &emitter);
40 CHECK(emitter);
41 emitter->listeners()->clear();
42 }
43 }
44
45 // The associated v8::Isolate. Since this object is cleaned up at context
46 // destruction, this should always be valid.
47 v8::Isolate* isolate;
48
49 // A map from event name -> event emitter.
50 std::map<std::string, v8::Global<v8::Object>> event_data;
51 };
52
53 } // namespace
54
55 APIEventHandler::APIEventHandler(const binding::RunJSFunction& call_js)
56 : call_js_(call_js) {}
57 APIEventHandler::~APIEventHandler() {}
58
59 v8::Local<v8::Object> APIEventHandler::CreateEventInstance(
60 const std::string& event_name,
61 v8::Local<v8::Context> context) {
62 gin::PerContextData* per_context_data = gin::PerContextData::From(context);
63 DCHECK(per_context_data);
64 APIEventPerContextData* data = static_cast<APIEventPerContextData*>(
65 per_context_data->GetUserData(kExtensionAPIEventPerContextKey));
66 if (!data) {
67 auto api_data =
68 base::MakeUnique<APIEventPerContextData>(context->GetIsolate());
69 data = api_data.get();
70 per_context_data->SetUserData(kExtensionAPIEventPerContextKey,
71 api_data.release());
72 }
73
74 DCHECK(data->event_data.find(event_name) == data->event_data.end());
75
76 gin::Handle<EventEmitter> emitter_handle =
77 gin::CreateHandle(context->GetIsolate(), new EventEmitter());
78 CHECK(!emitter_handle.IsEmpty());
79 v8::Local<v8::Value> emitter_value = emitter_handle.ToV8();
80 CHECK(emitter_value->IsObject());
81 v8::Local<v8::Object> emitter_object =
82 v8::Local<v8::Object>::Cast(emitter_value);
83 data->event_data[event_name] =
84 v8::Global<v8::Object>(context->GetIsolate(), emitter_object);
85
86 return emitter_object;
87 }
88
89 void APIEventHandler::FireEventInContext(const std::string& event_name,
90 v8::Local<v8::Context> context,
91 const base::ListValue& args) {
92 gin::PerContextData* per_context_data = gin::PerContextData::From(context);
93 DCHECK(per_context_data);
94 APIEventPerContextData* data = static_cast<APIEventPerContextData*>(
95 per_context_data->GetUserData(kExtensionAPIEventPerContextKey));
96 if (!data)
97 return;
98
99 auto iter = data->event_data.find(event_name);
100 if (iter == data->event_data.end())
101 return;
102
103 // Note: since we only convert the arguments once, if a listener modifies an
104 // object (including an array), other listeners will see that modification.
105 // TODO(devlin): This is how it's always been, but should it be?
106 std::vector<v8::Local<v8::Value>> v8_args;
107 v8_args.reserve(args.GetSize());
108 std::unique_ptr<content::V8ValueConverter> converter(
109 content::V8ValueConverter::create());
110 for (const auto& arg : args)
111 v8_args.push_back(converter->ToV8Value(arg.get(), context));
112
113 EventEmitter* emitter = nullptr;
114 gin::Converter<EventEmitter*>::FromV8(
115 context->GetIsolate(), iter->second.Get(context->GetIsolate()), &emitter);
116 CHECK(emitter);
117
118 for (const auto& listener : *emitter->listeners()) {
119 call_js_.Run(listener.Get(context->GetIsolate()), context, v8_args.size(),
120 v8_args.data());
121 }
122 }
123
124 size_t APIEventHandler::GetNumEventListenersForTesting(
125 const std::string& event_name,
126 v8::Local<v8::Context> context) {
127 gin::PerContextData* per_context_data = gin::PerContextData::From(context);
128 DCHECK(per_context_data);
129 APIEventPerContextData* data = static_cast<APIEventPerContextData*>(
130 per_context_data->GetUserData(kExtensionAPIEventPerContextKey));
131 DCHECK(data);
132
133 auto iter = data->event_data.find(event_name);
134 DCHECK(iter != data->event_data.end());
135 EventEmitter* emitter = nullptr;
136 gin::Converter<EventEmitter*>::FromV8(
137 context->GetIsolate(), iter->second.Get(context->GetIsolate()), &emitter);
138 CHECK(emitter);
139 return emitter->listeners()->size();
140 }
141
142 } // namespace extensions
OLDNEW
« 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