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

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

Issue 2615773002: [Extensions Bindings] Add enum support (Closed)
Patch Set: rebase Created 3 years, 11 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 unified diff | Download patch
« no previous file with comments | « extensions/renderer/api_binding.h ('k') | extensions/renderer/api_binding_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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_binding.h" 5 #include "extensions/renderer/api_binding.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 8
9 #include "base/bind.h" 9 #include "base/bind.h"
10 #include "base/logging.h" 10 #include "base/logging.h"
11 #include "base/memory/ptr_util.h" 11 #include "base/memory/ptr_util.h"
12 #include "base/strings/string_util.h"
12 #include "base/strings/stringprintf.h" 13 #include "base/strings/stringprintf.h"
13 #include "base/values.h" 14 #include "base/values.h"
14 #include "extensions/common/extension_api.h" 15 #include "extensions/common/extension_api.h"
15 #include "extensions/renderer/api_binding_hooks.h" 16 #include "extensions/renderer/api_binding_hooks.h"
16 #include "extensions/renderer/api_event_handler.h" 17 #include "extensions/renderer/api_event_handler.h"
17 #include "extensions/renderer/api_signature.h" 18 #include "extensions/renderer/api_signature.h"
18 #include "extensions/renderer/v8_helpers.h" 19 #include "extensions/renderer/v8_helpers.h"
19 #include "gin/arguments.h" 20 #include "gin/arguments.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
27 // Returns the name of the enum value for use in JavaScript; JS enum entries use
28 // SCREAMING_STYLE.
29 std::string GetJSEnumEntryName(const std::string& original) {
30 std::string result;
31 // If the original starts with a digit, prefix it with an underscore.
32 if (base::IsAsciiDigit(original[0]))
lazyboy 2017/01/05 23:09:13 DCHECK(!original.empty()) CHECK might be too expen
Devlin 2017/01/06 22:33:52 Done.
33 result.push_back('_');
34 // Given 'myEnum-Foo':
35 for (size_t i = 0; i < original.size(); ++i) {
36 // Add an underscore between camelcased items:
37 // 'myEnum-Foo' -> 'mY_Enum-Foo'
38 if (i > 0 && base::IsAsciiLower(original[i - 1]) &&
39 base::IsAsciiUpper(original[i])) {
40 result.push_back('_');
41 result.push_back(original[i]);
42 } else if (original[i] == '-') { // 'mY_Enum-Foo' -> 'mY_Enum_Foo'
43 result.push_back('_');
44 } else { // 'mY_Enum_Foo' -> 'MY_ENUM_FOO'
45 result.push_back(base::ToUpperASCII(original[i]));
46 }
47 }
48 return result;
49 }
50
26 const char kExtensionAPIPerContextKey[] = "extension_api_binding"; 51 const char kExtensionAPIPerContextKey[] = "extension_api_binding";
27 52
28 struct APIPerContextData : public base::SupportsUserData::Data { 53 struct APIPerContextData : public base::SupportsUserData::Data {
29 std::vector<std::unique_ptr<APIBinding::HandlerCallback>> context_callbacks; 54 std::vector<std::unique_ptr<APIBinding::HandlerCallback>> context_callbacks;
30 }; 55 };
31 56
32 void CallbackHelper(const v8::FunctionCallbackInfo<v8::Value>& info) { 57 void CallbackHelper(const v8::FunctionCallbackInfo<v8::Value>& info) {
33 gin::Arguments args(info); 58 gin::Arguments args(info);
34 59
35 // If the current context (the in which this function was created) has been 60 // If the current context (the in which this function was created) has been
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
81 const base::DictionaryValue* func_dict = nullptr; 106 const base::DictionaryValue* func_dict = nullptr;
82 CHECK(func->GetAsDictionary(&func_dict)); 107 CHECK(func->GetAsDictionary(&func_dict));
83 std::string name; 108 std::string name;
84 CHECK(func_dict->GetString("name", &name)); 109 CHECK(func_dict->GetString("name", &name));
85 110
86 const base::ListValue* params = nullptr; 111 const base::ListValue* params = nullptr;
87 CHECK(func_dict->GetList("parameters", &params)); 112 CHECK(func_dict->GetList("parameters", &params));
88 signatures_[name] = base::MakeUnique<APISignature>(*params); 113 signatures_[name] = base::MakeUnique<APISignature>(*params);
89 } 114 }
90 } 115 }
116
91 if (type_definitions) { 117 if (type_definitions) {
92 for (const auto& type : *type_definitions) { 118 for (const auto& type : *type_definitions) {
93 const base::DictionaryValue* type_dict = nullptr; 119 const base::DictionaryValue* type_dict = nullptr;
94 CHECK(type->GetAsDictionary(&type_dict)); 120 CHECK(type->GetAsDictionary(&type_dict));
95 std::string id; 121 std::string id;
96 CHECK(type_dict->GetString("id", &id)); 122 CHECK(type_dict->GetString("id", &id));
97 DCHECK(type_refs->find(id) == type_refs->end()); 123 DCHECK(type_refs->find(id) == type_refs->end());
98 // TODO(devlin): refs are sometimes preceeded by the API namespace; we 124 // TODO(devlin): refs are sometimes preceeded by the API namespace; we
99 // might need to take that into account. 125 // might need to take that into account.
100 (*type_refs)[id] = base::MakeUnique<ArgumentSpec>(*type_dict); 126 auto argument_spec = base::MakeUnique<ArgumentSpec>(*type_dict);
127 const std::set<std::string>& enum_values = argument_spec->enum_values();
128 if (!enum_values.empty()) {
129 // Type names may be prefixed by the api name. If so, remove the prefix.
130 base::Optional<std::string> stripped_id;
131 if (base::StartsWith(id, api_name_, base::CompareCase::SENSITIVE))
132 stripped_id = id.substr(api_name_.size() + 1); // +1 for trailing '.'
133 std::vector<EnumEntry>& entries =
134 enums_[stripped_id ? *stripped_id : id];
135 entries.reserve(enum_values.size());
136 for (const auto& enum_value : enum_values) {
137 entries.push_back(
138 std::make_pair(enum_value, GetJSEnumEntryName(enum_value)));
139 }
140 }
141 (*type_refs)[id] = std::move(argument_spec);
101 } 142 }
102 } 143 }
144
103 if (event_definitions) { 145 if (event_definitions) {
104 event_names_.reserve(event_definitions->GetSize()); 146 event_names_.reserve(event_definitions->GetSize());
105 for (const auto& event : *event_definitions) { 147 for (const auto& event : *event_definitions) {
106 const base::DictionaryValue* event_dict = nullptr; 148 const base::DictionaryValue* event_dict = nullptr;
107 CHECK(event->GetAsDictionary(&event_dict)); 149 CHECK(event->GetAsDictionary(&event_dict));
108 std::string name; 150 std::string name;
109 CHECK(event_dict->GetString("name", &name)); 151 CHECK(event_dict->GetString("name", &name));
110 event_names_.push_back(std::move(name)); 152 event_names_.push_back(std::move(name));
111 } 153 }
112 } 154 }
(...skipping 14 matching lines...) Expand all
127 gin::PerContextData* per_context_data = gin::PerContextData::From(context); 169 gin::PerContextData* per_context_data = gin::PerContextData::From(context);
128 DCHECK(per_context_data); 170 DCHECK(per_context_data);
129 APIPerContextData* data = static_cast<APIPerContextData*>( 171 APIPerContextData* data = static_cast<APIPerContextData*>(
130 per_context_data->GetUserData(kExtensionAPIPerContextKey)); 172 per_context_data->GetUserData(kExtensionAPIPerContextKey));
131 if (!data) { 173 if (!data) {
132 auto api_data = base::MakeUnique<APIPerContextData>(); 174 auto api_data = base::MakeUnique<APIPerContextData>();
133 data = api_data.get(); 175 data = api_data.get();
134 per_context_data->SetUserData(kExtensionAPIPerContextKey, 176 per_context_data->SetUserData(kExtensionAPIPerContextKey,
135 api_data.release()); 177 api_data.release());
136 } 178 }
179
137 for (const auto& sig : signatures_) { 180 for (const auto& sig : signatures_) {
138 std::string full_method_name = 181 std::string full_method_name =
139 base::StringPrintf("%s.%s", api_name_.c_str(), sig.first.c_str()); 182 base::StringPrintf("%s.%s", api_name_.c_str(), sig.first.c_str());
140 183
141 if (!is_available.Run(full_method_name)) 184 if (!is_available.Run(full_method_name))
142 continue; 185 continue;
143 186
144 auto handler_callback = base::MakeUnique<HandlerCallback>( 187 auto handler_callback = base::MakeUnique<HandlerCallback>(
145 base::Bind(&APIBinding::HandleCall, weak_factory_.GetWeakPtr(), 188 base::Bind(&APIBinding::HandleCall, weak_factory_.GetWeakPtr(),
146 full_method_name, sig.second.get())); 189 full_method_name, sig.second.get()));
(...skipping 15 matching lines...) Expand all
162 base::StringPrintf("%s.%s", api_name_.c_str(), event_name.c_str()); 205 base::StringPrintf("%s.%s", api_name_.c_str(), event_name.c_str());
163 v8::Local<v8::Object> event = 206 v8::Local<v8::Object> event =
164 event_handler->CreateEventInstance(full_event_name, context); 207 event_handler->CreateEventInstance(full_event_name, context);
165 DCHECK(!event.IsEmpty()); 208 DCHECK(!event.IsEmpty());
166 v8::Maybe<bool> success = object->CreateDataProperty( 209 v8::Maybe<bool> success = object->CreateDataProperty(
167 context, gin::StringToSymbol(isolate, event_name), event); 210 context, gin::StringToSymbol(isolate, event_name), event);
168 DCHECK(success.IsJust()); 211 DCHECK(success.IsJust());
169 DCHECK(success.FromJust()); 212 DCHECK(success.FromJust());
170 } 213 }
171 214
215 for (const auto& entry : enums_) {
jbroman 2017/01/05 22:31:24 This seems like it would be very easy to stamp out
Devlin 2017/01/06 22:33:52 Good point. Added a TODO
216 v8::Local<v8::Object> enum_object = v8::Object::New(isolate);
217 for (const auto& enum_entry : entry.second) {
218 v8::Maybe<bool> success = enum_object->CreateDataProperty(
219 context, gin::StringToSymbol(isolate, enum_entry.second),
220 gin::StringToSymbol(isolate, enum_entry.first));
221 DCHECK(success.IsJust());
222 DCHECK(success.FromJust());
223 }
224 v8::Maybe<bool> success = object->CreateDataProperty(
225 context, gin::StringToSymbol(isolate, entry.first), enum_object);
226 DCHECK(success.IsJust());
227 DCHECK(success.FromJust());
228 }
229
172 binding_hooks_->InitializeInContext(context, api_name_); 230 binding_hooks_->InitializeInContext(context, api_name_);
173 231
174 return object; 232 return object;
175 } 233 }
176 234
177 v8::Local<v8::Object> APIBinding::GetJSHookInterface( 235 v8::Local<v8::Object> APIBinding::GetJSHookInterface(
178 v8::Local<v8::Context> context) { 236 v8::Local<v8::Context> context) {
179 return binding_hooks_->GetJSHookInterface(api_name_, context); 237 return binding_hooks_->GetJSHookInterface(api_name_, context);
180 } 238 }
181 239
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
223 arguments->ThrowTypeError("Invalid invocation"); 281 arguments->ThrowTypeError("Invalid invocation");
224 return; 282 return;
225 } 283 }
226 284
227 DCHECK(converted_arguments); 285 DCHECK(converted_arguments);
228 method_callback_.Run(name, std::move(converted_arguments), isolate, context, 286 method_callback_.Run(name, std::move(converted_arguments), isolate, context,
229 callback); 287 callback);
230 } 288 }
231 289
232 } // namespace extensions 290 } // namespace extensions
OLDNEW
« no previous file with comments | « extensions/renderer/api_binding.h ('k') | extensions/renderer/api_binding_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698