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 DCHECK(!original.empty()); |
| 32 // If the original starts with a digit, prefix it with an underscore. |
| 33 if (base::IsAsciiDigit(original[0])) |
| 34 result.push_back('_'); |
| 35 // Given 'myEnum-Foo': |
| 36 for (size_t i = 0; i < original.size(); ++i) { |
| 37 // Add an underscore between camelcased items: |
| 38 // 'myEnum-Foo' -> 'mY_Enum-Foo' |
| 39 if (i > 0 && base::IsAsciiLower(original[i - 1]) && |
| 40 base::IsAsciiUpper(original[i])) { |
| 41 result.push_back('_'); |
| 42 result.push_back(original[i]); |
| 43 } else if (original[i] == '-') { // 'mY_Enum-Foo' -> 'mY_Enum_Foo' |
| 44 result.push_back('_'); |
| 45 } else { // 'mY_Enum_Foo' -> 'MY_ENUM_FOO' |
| 46 result.push_back(base::ToUpperASCII(original[i])); |
| 47 } |
| 48 } |
| 49 return result; |
| 50 } |
| 51 |
26 const char kExtensionAPIPerContextKey[] = "extension_api_binding"; | 52 const char kExtensionAPIPerContextKey[] = "extension_api_binding"; |
27 | 53 |
28 struct APIPerContextData : public base::SupportsUserData::Data { | 54 struct APIPerContextData : public base::SupportsUserData::Data { |
29 std::vector<std::unique_ptr<APIBinding::HandlerCallback>> context_callbacks; | 55 std::vector<std::unique_ptr<APIBinding::HandlerCallback>> context_callbacks; |
30 }; | 56 }; |
31 | 57 |
32 void CallbackHelper(const v8::FunctionCallbackInfo<v8::Value>& info) { | 58 void CallbackHelper(const v8::FunctionCallbackInfo<v8::Value>& info) { |
33 gin::Arguments args(info); | 59 gin::Arguments args(info); |
34 | 60 |
35 // If the current context (the in which this function was created) has been | 61 // 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; | 107 const base::DictionaryValue* func_dict = nullptr; |
82 CHECK(func->GetAsDictionary(&func_dict)); | 108 CHECK(func->GetAsDictionary(&func_dict)); |
83 std::string name; | 109 std::string name; |
84 CHECK(func_dict->GetString("name", &name)); | 110 CHECK(func_dict->GetString("name", &name)); |
85 | 111 |
86 const base::ListValue* params = nullptr; | 112 const base::ListValue* params = nullptr; |
87 CHECK(func_dict->GetList("parameters", ¶ms)); | 113 CHECK(func_dict->GetList("parameters", ¶ms)); |
88 signatures_[name] = base::MakeUnique<APISignature>(*params); | 114 signatures_[name] = base::MakeUnique<APISignature>(*params); |
89 } | 115 } |
90 } | 116 } |
| 117 |
91 if (type_definitions) { | 118 if (type_definitions) { |
92 for (const auto& type : *type_definitions) { | 119 for (const auto& type : *type_definitions) { |
93 const base::DictionaryValue* type_dict = nullptr; | 120 const base::DictionaryValue* type_dict = nullptr; |
94 CHECK(type->GetAsDictionary(&type_dict)); | 121 CHECK(type->GetAsDictionary(&type_dict)); |
95 std::string id; | 122 std::string id; |
96 CHECK(type_dict->GetString("id", &id)); | 123 CHECK(type_dict->GetString("id", &id)); |
97 DCHECK(type_refs->find(id) == type_refs->end()); | 124 DCHECK(type_refs->find(id) == type_refs->end()); |
98 // TODO(devlin): refs are sometimes preceeded by the API namespace; we | 125 // TODO(devlin): refs are sometimes preceeded by the API namespace; we |
99 // might need to take that into account. | 126 // might need to take that into account. |
100 (*type_refs)[id] = base::MakeUnique<ArgumentSpec>(*type_dict); | 127 auto argument_spec = base::MakeUnique<ArgumentSpec>(*type_dict); |
| 128 const std::set<std::string>& enum_values = argument_spec->enum_values(); |
| 129 if (!enum_values.empty()) { |
| 130 // Type names may be prefixed by the api name. If so, remove the prefix. |
| 131 base::Optional<std::string> stripped_id; |
| 132 if (base::StartsWith(id, api_name_, base::CompareCase::SENSITIVE)) |
| 133 stripped_id = id.substr(api_name_.size() + 1); // +1 for trailing '.' |
| 134 std::vector<EnumEntry>& entries = |
| 135 enums_[stripped_id ? *stripped_id : id]; |
| 136 entries.reserve(enum_values.size()); |
| 137 for (const auto& enum_value : enum_values) { |
| 138 entries.push_back( |
| 139 std::make_pair(enum_value, GetJSEnumEntryName(enum_value))); |
| 140 } |
| 141 } |
| 142 (*type_refs)[id] = std::move(argument_spec); |
101 } | 143 } |
102 } | 144 } |
| 145 |
103 if (event_definitions) { | 146 if (event_definitions) { |
104 event_names_.reserve(event_definitions->GetSize()); | 147 event_names_.reserve(event_definitions->GetSize()); |
105 for (const auto& event : *event_definitions) { | 148 for (const auto& event : *event_definitions) { |
106 const base::DictionaryValue* event_dict = nullptr; | 149 const base::DictionaryValue* event_dict = nullptr; |
107 CHECK(event->GetAsDictionary(&event_dict)); | 150 CHECK(event->GetAsDictionary(&event_dict)); |
108 std::string name; | 151 std::string name; |
109 CHECK(event_dict->GetString("name", &name)); | 152 CHECK(event_dict->GetString("name", &name)); |
110 event_names_.push_back(std::move(name)); | 153 event_names_.push_back(std::move(name)); |
111 } | 154 } |
112 } | 155 } |
(...skipping 14 matching lines...) Expand all Loading... |
127 gin::PerContextData* per_context_data = gin::PerContextData::From(context); | 170 gin::PerContextData* per_context_data = gin::PerContextData::From(context); |
128 DCHECK(per_context_data); | 171 DCHECK(per_context_data); |
129 APIPerContextData* data = static_cast<APIPerContextData*>( | 172 APIPerContextData* data = static_cast<APIPerContextData*>( |
130 per_context_data->GetUserData(kExtensionAPIPerContextKey)); | 173 per_context_data->GetUserData(kExtensionAPIPerContextKey)); |
131 if (!data) { | 174 if (!data) { |
132 auto api_data = base::MakeUnique<APIPerContextData>(); | 175 auto api_data = base::MakeUnique<APIPerContextData>(); |
133 data = api_data.get(); | 176 data = api_data.get(); |
134 per_context_data->SetUserData(kExtensionAPIPerContextKey, | 177 per_context_data->SetUserData(kExtensionAPIPerContextKey, |
135 api_data.release()); | 178 api_data.release()); |
136 } | 179 } |
| 180 |
137 for (const auto& sig : signatures_) { | 181 for (const auto& sig : signatures_) { |
138 std::string full_method_name = | 182 std::string full_method_name = |
139 base::StringPrintf("%s.%s", api_name_.c_str(), sig.first.c_str()); | 183 base::StringPrintf("%s.%s", api_name_.c_str(), sig.first.c_str()); |
140 | 184 |
141 if (!is_available.Run(full_method_name)) | 185 if (!is_available.Run(full_method_name)) |
142 continue; | 186 continue; |
143 | 187 |
144 auto handler_callback = base::MakeUnique<HandlerCallback>( | 188 auto handler_callback = base::MakeUnique<HandlerCallback>( |
145 base::Bind(&APIBinding::HandleCall, weak_factory_.GetWeakPtr(), | 189 base::Bind(&APIBinding::HandleCall, weak_factory_.GetWeakPtr(), |
146 full_method_name, sig.second.get())); | 190 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()); | 206 base::StringPrintf("%s.%s", api_name_.c_str(), event_name.c_str()); |
163 v8::Local<v8::Object> event = | 207 v8::Local<v8::Object> event = |
164 event_handler->CreateEventInstance(full_event_name, context); | 208 event_handler->CreateEventInstance(full_event_name, context); |
165 DCHECK(!event.IsEmpty()); | 209 DCHECK(!event.IsEmpty()); |
166 v8::Maybe<bool> success = object->CreateDataProperty( | 210 v8::Maybe<bool> success = object->CreateDataProperty( |
167 context, gin::StringToSymbol(isolate, event_name), event); | 211 context, gin::StringToSymbol(isolate, event_name), event); |
168 DCHECK(success.IsJust()); | 212 DCHECK(success.IsJust()); |
169 DCHECK(success.FromJust()); | 213 DCHECK(success.FromJust()); |
170 } | 214 } |
171 | 215 |
| 216 for (const auto& entry : enums_) { |
| 217 // TODO(devlin): Store these on an ObjectTemplate. |
| 218 v8::Local<v8::Object> enum_object = v8::Object::New(isolate); |
| 219 for (const auto& enum_entry : entry.second) { |
| 220 v8::Maybe<bool> success = enum_object->CreateDataProperty( |
| 221 context, gin::StringToSymbol(isolate, enum_entry.second), |
| 222 gin::StringToSymbol(isolate, enum_entry.first)); |
| 223 DCHECK(success.IsJust()); |
| 224 DCHECK(success.FromJust()); |
| 225 } |
| 226 v8::Maybe<bool> success = object->CreateDataProperty( |
| 227 context, gin::StringToSymbol(isolate, entry.first), enum_object); |
| 228 DCHECK(success.IsJust()); |
| 229 DCHECK(success.FromJust()); |
| 230 } |
| 231 |
172 binding_hooks_->InitializeInContext(context, api_name_); | 232 binding_hooks_->InitializeInContext(context, api_name_); |
173 | 233 |
174 return object; | 234 return object; |
175 } | 235 } |
176 | 236 |
177 v8::Local<v8::Object> APIBinding::GetJSHookInterface( | 237 v8::Local<v8::Object> APIBinding::GetJSHookInterface( |
178 v8::Local<v8::Context> context) { | 238 v8::Local<v8::Context> context) { |
179 return binding_hooks_->GetJSHookInterface(api_name_, context); | 239 return binding_hooks_->GetJSHookInterface(api_name_, context); |
180 } | 240 } |
181 | 241 |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
243 arguments->ThrowTypeError("Invalid invocation"); | 303 arguments->ThrowTypeError("Invalid invocation"); |
244 return; | 304 return; |
245 } | 305 } |
246 | 306 |
247 DCHECK(converted_arguments); | 307 DCHECK(converted_arguments); |
248 method_callback_.Run(name, std::move(converted_arguments), isolate, context, | 308 method_callback_.Run(name, std::move(converted_arguments), isolate, context, |
249 callback); | 309 callback); |
250 } | 310 } |
251 | 311 |
252 } // namespace extensions | 312 } // namespace extensions |
OLD | NEW |