Chromium Code Reviews| 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 |