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

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

Issue 2704823002: [Extensions Bindings] Add support for custom property types (Closed)
Patch Set: asan fix Created 3 years, 10 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"
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
65 if (!IsContextValid(args.isolate()->GetCurrentContext())) 65 if (!IsContextValid(args.isolate()->GetCurrentContext()))
66 return; 66 return;
67 67
68 v8::Local<v8::External> external; 68 v8::Local<v8::External> external;
69 CHECK(args.GetData(&external)); 69 CHECK(args.GetData(&external));
70 auto* callback = static_cast<APIBinding::HandlerCallback*>(external->Value()); 70 auto* callback = static_cast<APIBinding::HandlerCallback*>(external->Value());
71 71
72 callback->Run(&args); 72 callback->Run(&args);
73 } 73 }
74 74
75 // Decorates |object_template| with the properties specified by |properties|.
76 void DecorateTemplateWithProperties(
77 v8::Isolate* isolate,
78 v8::Local<v8::ObjectTemplate> object_template,
79 const base::DictionaryValue& properties) {
80 static const char kValueKey[] = "value";
81 for (base::DictionaryValue::Iterator iter(properties); !iter.IsAtEnd();
82 iter.Advance()) {
83 const base::DictionaryValue* dict = nullptr;
84 CHECK(iter.value().GetAsDictionary(&dict));
85 bool optional = false;
86 if (dict->GetBoolean("optional", &optional)) {
87 // TODO(devlin): What does optional even mean here? It's only used, it
88 // seems, for lastError and inIncognitoContext, which are both handled
89 // with custom bindings. Investigate, and remove.
90 continue;
91 }
92 std::string ref;
93 if (dict->GetString("$ref", &ref)) {
94 // TODO(devlin): Handle refs. These are tricky(er), because they represent
95 // a type that's defined in (currently) JS.
96 continue;
97 }
98 std::string type;
99 CHECK(dict->GetString("type", &type));
100 if (type != "object" && !dict->HasKey(kValueKey)) {
101 // TODO(devlin): What does a fundamental property not having a value mean?
102 // It doesn't seem useful, and looks like it's only used by runtime.id,
103 // which is set by custom bindings. Investigate, and remove.
104 continue;
105 }
106 if (type == "integer") {
107 int val = 0;
108 CHECK(dict->GetInteger(kValueKey, &val));
109 object_template->Set(isolate, iter.key().c_str(),
110 v8::Integer::New(isolate, val));
111 } else if (type == "boolean") {
112 bool val = false;
113 CHECK(dict->GetBoolean(kValueKey, &val));
114 object_template->Set(isolate, iter.key().c_str(),
115 v8::Boolean::New(isolate, val));
116 } else if (type == "string") {
117 std::string val;
118 CHECK(dict->GetString(kValueKey, &val)) << iter.key();
119 object_template->Set(isolate, iter.key().c_str(),
120 gin::StringToSymbol(isolate, val));
121 } else if (type == "object") {
122 v8::Local<v8::ObjectTemplate> property_template =
123 v8::ObjectTemplate::New(isolate);
124 const base::DictionaryValue* property_dict = nullptr;
125 CHECK(dict->GetDictionary("properties", &property_dict));
126 DecorateTemplateWithProperties(isolate, property_template,
127 *property_dict);
128 object_template->Set(isolate, iter.key().c_str(), property_template);
129 }
130 }
131 }
132
133 } // namespace 75 } // namespace
134 76
135 struct APIBinding::MethodData { 77 struct APIBinding::MethodData {
136 MethodData(std::string full_name, 78 MethodData(std::string full_name,
137 const base::ListValue& method_signature) 79 const base::ListValue& method_signature)
138 : full_name(std::move(full_name)), 80 : full_name(std::move(full_name)),
139 signature(method_signature) {} 81 signature(method_signature) {}
140 82
141 // The fully-qualified name of this api (e.g. runtime.sendMessage instead of 83 // The fully-qualified name of this api (e.g. runtime.sendMessage instead of
142 // sendMessage). 84 // sendMessage).
(...skipping 16 matching lines...) Expand all
159 std::string exposed_name; 101 std::string exposed_name;
160 // The fully-specified name of the event (e.g. tabs.onCreated). 102 // The fully-specified name of the event (e.g. tabs.onCreated).
161 std::string full_name; 103 std::string full_name;
162 // The associated event handler. This raw pointer is safe because the 104 // The associated event handler. This raw pointer is safe because the
163 // EventData is only accessed from the callbacks associated with the 105 // EventData is only accessed from the callbacks associated with the
164 // APIBinding, and both the APIBinding and APIEventHandler are owned by the 106 // APIBinding, and both the APIBinding and APIEventHandler are owned by the
165 // same object (the APIBindingsSystem). 107 // same object (the APIBindingsSystem).
166 APIEventHandler* event_handler; 108 APIEventHandler* event_handler;
167 }; 109 };
168 110
111 struct APIBinding::CustomPropertyData {
112 CustomPropertyData(const std::string& type_name,
113 const std::string& property_name,
114 const CreateCustomType& create_custom_type)
115 : type_name(type_name),
116 property_name(property_name),
117 create_custom_type(create_custom_type) {}
118
119 // The type of the property, e.g. 'storage.StorageArea'.
120 std::string type_name;
121 // The name of the property on the object, e.g. 'local' for
122 // chrome.storage.local.
123 std::string property_name;
124
125 CreateCustomType create_custom_type;
126 };
127
169 APIBinding::APIBinding(const std::string& api_name, 128 APIBinding::APIBinding(const std::string& api_name,
170 const base::ListValue* function_definitions, 129 const base::ListValue* function_definitions,
171 const base::ListValue* type_definitions, 130 const base::ListValue* type_definitions,
172 const base::ListValue* event_definitions, 131 const base::ListValue* event_definitions,
173 const base::DictionaryValue* property_definitions, 132 const base::DictionaryValue* property_definitions,
133 const CreateCustomType& create_custom_type,
174 std::unique_ptr<APIBindingHooks> binding_hooks, 134 std::unique_ptr<APIBindingHooks> binding_hooks,
175 APITypeReferenceMap* type_refs, 135 APITypeReferenceMap* type_refs,
176 APIRequestHandler* request_handler, 136 APIRequestHandler* request_handler,
177 APIEventHandler* event_handler) 137 APIEventHandler* event_handler)
178 : api_name_(api_name), 138 : api_name_(api_name),
179 property_definitions_(property_definitions), 139 property_definitions_(property_definitions),
140 create_custom_type_(create_custom_type),
180 binding_hooks_(std::move(binding_hooks)), 141 binding_hooks_(std::move(binding_hooks)),
181 type_refs_(type_refs), 142 type_refs_(type_refs),
182 request_handler_(request_handler), 143 request_handler_(request_handler),
183 weak_factory_(this) { 144 weak_factory_(this) {
184 // TODO(devlin): It might make sense to instantiate the object_template_ 145 // TODO(devlin): It might make sense to instantiate the object_template_
185 // directly here, which would avoid the need to hold on to 146 // directly here, which would avoid the need to hold on to
186 // |property_definitions_| and |enums_|. However, there are *some* cases where 147 // |property_definitions_| and |enums_|. However, there are *some* cases where
187 // we don't immediately stamp out an API from the template following 148 // we don't immediately stamp out an API from the template following
188 // construction. 149 // construction.
189 150
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after
320 } 281 }
321 282
322 if (property_definitions_) { 283 if (property_definitions_) {
323 DecorateTemplateWithProperties(isolate, object_template, 284 DecorateTemplateWithProperties(isolate, object_template,
324 *property_definitions_); 285 *property_definitions_);
325 } 286 }
326 287
327 object_template_.Set(isolate, object_template); 288 object_template_.Set(isolate, object_template);
328 } 289 }
329 290
291 void APIBinding::DecorateTemplateWithProperties(
292 v8::Isolate* isolate,
293 v8::Local<v8::ObjectTemplate> object_template,
294 const base::DictionaryValue& properties) {
295 static const char kValueKey[] = "value";
296 for (base::DictionaryValue::Iterator iter(properties); !iter.IsAtEnd();
297 iter.Advance()) {
298 const base::DictionaryValue* dict = nullptr;
299 CHECK(iter.value().GetAsDictionary(&dict));
300 bool optional = false;
301 if (dict->GetBoolean("optional", &optional)) {
302 // TODO(devlin): What does optional even mean here? It's only used, it
303 // seems, for lastError and inIncognitoContext, which are both handled
304 // with custom bindings. Investigate, and remove.
305 continue;
306 }
307
308 v8::Local<v8::String> v8_key = gin::StringToSymbol(isolate, iter.key());
309 std::string ref;
310 if (dict->GetString("$ref", &ref)) {
311 auto property_data = base::MakeUnique<CustomPropertyData>(
312 ref, iter.key(), create_custom_type_);
313 object_template->SetLazyDataProperty(
314 v8_key, &APIBinding::GetCustomPropertyObject,
315 v8::External::New(isolate, property_data.get()));
316 custom_properties_.push_back(std::move(property_data));
317 continue;
318 }
319
320 std::string type;
321 CHECK(dict->GetString("type", &type));
322 if (type != "object" && !dict->HasKey(kValueKey)) {
323 // TODO(devlin): What does a fundamental property not having a value mean?
324 // It doesn't seem useful, and looks like it's only used by runtime.id,
325 // which is set by custom bindings. Investigate, and remove.
326 continue;
327 }
328 if (type == "integer") {
329 int val = 0;
330 CHECK(dict->GetInteger(kValueKey, &val));
331 object_template->Set(v8_key, v8::Integer::New(isolate, val));
332 } else if (type == "boolean") {
333 bool val = false;
334 CHECK(dict->GetBoolean(kValueKey, &val));
335 object_template->Set(v8_key, v8::Boolean::New(isolate, val));
336 } else if (type == "string") {
337 std::string val;
338 CHECK(dict->GetString(kValueKey, &val)) << iter.key();
339 object_template->Set(v8_key, gin::StringToSymbol(isolate, val));
340 } else if (type == "object" || !ref.empty()) {
341 v8::Local<v8::ObjectTemplate> property_template =
342 v8::ObjectTemplate::New(isolate);
343 const base::DictionaryValue* property_dict = nullptr;
344 CHECK(dict->GetDictionary("properties", &property_dict));
345 DecorateTemplateWithProperties(isolate, property_template,
346 *property_dict);
347 object_template->Set(v8_key, property_template);
348 }
349 }
350 }
351
330 // static 352 // static
331 void APIBinding::GetEventObject( 353 void APIBinding::GetEventObject(
332 v8::Local<v8::Name> property, 354 v8::Local<v8::Name> property,
333 const v8::PropertyCallbackInfo<v8::Value>& info) { 355 const v8::PropertyCallbackInfo<v8::Value>& info) {
334 v8::Isolate* isolate = info.GetIsolate(); 356 v8::Isolate* isolate = info.GetIsolate();
335 v8::HandleScope handle_scope(isolate); 357 v8::HandleScope handle_scope(isolate);
336 v8::Local<v8::Context> context = info.Holder()->CreationContext(); 358 v8::Local<v8::Context> context = info.Holder()->CreationContext();
337 if (!IsContextValid(context)) 359 if (!IsContextValid(context))
338 return; 360 return;
339 361
340 CHECK(info.Data()->IsExternal()); 362 CHECK(info.Data()->IsExternal());
341 auto* event_data = 363 auto* event_data =
342 static_cast<EventData*>(info.Data().As<v8::External>()->Value()); 364 static_cast<EventData*>(info.Data().As<v8::External>()->Value());
343 info.GetReturnValue().Set(event_data->event_handler->CreateEventInstance( 365 info.GetReturnValue().Set(event_data->event_handler->CreateEventInstance(
344 event_data->full_name, context)); 366 event_data->full_name, context));
345 } 367 }
346 368
369 void APIBinding::GetCustomPropertyObject(
370 v8::Local<v8::Name> property_name,
371 const v8::PropertyCallbackInfo<v8::Value>& info) {
372 v8::Isolate* isolate = info.GetIsolate();
373 v8::HandleScope handle_scope(isolate);
374 v8::Local<v8::Context> context = info.Holder()->CreationContext();
375 if (!IsContextValid(context))
376 return;
377
378 CHECK(info.Data()->IsExternal());
379 auto* property_data =
380 static_cast<CustomPropertyData*>(info.Data().As<v8::External>()->Value());
381
382 v8::Local<v8::Object> property = property_data->create_custom_type.Run(
383 context, property_data->type_name, property_data->property_name);
384 if (property.IsEmpty())
385 return;
386
387 info.GetReturnValue().Set(property);
388 }
389
347 void APIBinding::HandleCall(const std::string& name, 390 void APIBinding::HandleCall(const std::string& name,
348 const APISignature* signature, 391 const APISignature* signature,
349 gin::Arguments* arguments) { 392 gin::Arguments* arguments) {
350 std::string error; 393 std::string error;
351 v8::Isolate* isolate = arguments->isolate(); 394 v8::Isolate* isolate = arguments->isolate();
352 v8::HandleScope handle_scope(isolate); 395 v8::HandleScope handle_scope(isolate);
353 396
354 // Since this is called synchronously from the JS entry point, 397 // Since this is called synchronously from the JS entry point,
355 // GetCurrentContext() should always be correct. 398 // GetCurrentContext() should always be correct.
356 v8::Local<v8::Context> context = isolate->GetCurrentContext(); 399 v8::Local<v8::Context> context = isolate->GetCurrentContext();
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
409 if (invalid_invocation) { 452 if (invalid_invocation) {
410 arguments->ThrowTypeError("Invalid invocation"); 453 arguments->ThrowTypeError("Invalid invocation");
411 return; 454 return;
412 } 455 }
413 456
414 request_handler_->StartRequest(context, name, std::move(converted_arguments), 457 request_handler_->StartRequest(context, name, std::move(converted_arguments),
415 callback, custom_callback); 458 callback, custom_callback);
416 } 459 }
417 460
418 } // namespace extensions 461 } // 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