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

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

Issue 2469593002: [Extensions Bindings] Add Events support (Closed)
Patch Set: jbromans II 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 "gin/arguments.h"
19 #include "gin/per_context_data.h"
20
21 namespace extensions {
22
23 namespace {
24
25 const char kExtensionAPIEventPerContextKey[] = "extension_api_events";
26
27 struct APIEventPerContextData : public base::SupportsUserData::Data {
28 APIEventPerContextData() = default;
29 ~APIEventPerContextData() override {
30 // We explicitly clear the event data map here to remove all references to
31 // v8 objects. This helps us avoid cycles in v8 where an event listener
32 // could hold a reference to the event, which in turn holds the reference
33 // to the listener.
34 event_data.clear();
jbroman 2016/11/03 19:28:04 Apologies for not being clear here. event_data its
Devlin 2016/11/04 17:59:30 Whoops! I understood what you meant, and somewher
jbroman 2016/11/04 18:33:04 No, it shouldn't fail. CHECK or DCHECK sgtm.
35 }
36
37 // A map from event name -> event emitter.
38 std::map<std::string, v8::Global<v8::Object>> event_data;
39 };
40
41 } // namespace
42
43 APIEventHandler::APIEventHandler(const binding::RunJSFunction& call_js)
44 : call_js_(call_js) {}
45 APIEventHandler::~APIEventHandler() {}
46
47 v8::Local<v8::Object> APIEventHandler::CreateEventInstance(
48 const std::string& event_name,
49 v8::Local<v8::Context> context) {
50 gin::PerContextData* per_context_data = gin::PerContextData::From(context);
51 DCHECK(per_context_data);
52 APIEventPerContextData* data = static_cast<APIEventPerContextData*>(
53 per_context_data->GetUserData(kExtensionAPIEventPerContextKey));
54 if (!data) {
55 auto api_data = base::MakeUnique<APIEventPerContextData>();
56 data = api_data.get();
57 per_context_data->SetUserData(kExtensionAPIEventPerContextKey,
58 api_data.release());
59 }
60
61 DCHECK(data->event_data.find(event_name) == data->event_data.end());
62
63 gin::Handle<EventEmitter> emitter_handle =
64 gin::CreateHandle(context->GetIsolate(), new EventEmitter());
65 CHECK(!emitter_handle.IsEmpty());
66 v8::Local<v8::Value> emitter_value = emitter_handle.ToV8();
67 CHECK(emitter_value->IsObject());
68 v8::Local<v8::Object> emitter_object =
69 v8::Local<v8::Object>::Cast(emitter_value);
70 data->event_data[event_name] =
71 v8::Global<v8::Object>(context->GetIsolate(), emitter_object);
72
73 return emitter_object;
74 }
75
76 void APIEventHandler::FireEventInContext(const std::string& event_name,
77 v8::Local<v8::Context> context,
78 const base::ListValue& args) {
79 gin::PerContextData* per_context_data = gin::PerContextData::From(context);
80 DCHECK(per_context_data);
81 APIEventPerContextData* data = static_cast<APIEventPerContextData*>(
82 per_context_data->GetUserData(kExtensionAPIEventPerContextKey));
83 if (!data)
84 return;
85
86 auto iter = data->event_data.find(event_name);
87 if (iter == data->event_data.end())
88 return;
89
90 // Note: since we only convert the arguments once, if a listener modifies an
91 // object (including an array), other listeners will see that modification.
92 // TODO(devlin): This is how it's always been, but should it be?
93 std::vector<v8::Local<v8::Value>> v8_args;
94 v8_args.reserve(args.GetSize());
95 std::unique_ptr<content::V8ValueConverter> converter(
96 content::V8ValueConverter::create());
97 for (const auto& arg : args)
98 v8_args.push_back(converter->ToV8Value(arg.get(), context));
99
100 gin::Handle<EventEmitter> emitter;
101 gin::Converter<gin::Handle<EventEmitter>>::FromV8(
102 context->GetIsolate(), iter->second.Get(context->GetIsolate()), &emitter);
103 CHECK(!emitter.IsEmpty());
104
105 for (const auto& listener : *emitter->listeners()) {
106 call_js_.Run(listener.Get(context->GetIsolate()), context, v8_args.size(),
107 v8_args.data());
108 }
109 }
110
111 size_t APIEventHandler::GetNumEventListenersForTesting(
112 const std::string& event_name,
113 v8::Local<v8::Context> context) {
114 gin::PerContextData* per_context_data = gin::PerContextData::From(context);
115 DCHECK(per_context_data);
116 APIEventPerContextData* data = static_cast<APIEventPerContextData*>(
117 per_context_data->GetUserData(kExtensionAPIEventPerContextKey));
118 DCHECK(data);
119
120 auto iter = data->event_data.find(event_name);
121 DCHECK(iter != data->event_data.end());
122 gin::Handle<EventEmitter> emitter;
123 gin::Converter<gin::Handle<EventEmitter>>::FromV8(
124 context->GetIsolate(), iter->second.Get(context->GetIsolate()), &emitter);
125 CHECK(!emitter.IsEmpty());
126 return emitter->listeners()->size();
127 }
128
129 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698