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_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 Loading... | |
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", ¶ms)); | 112 CHECK(func_dict->GetList("parameters", ¶ms)); |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |