Index: extensions/renderer/api_binding.cc |
diff --git a/extensions/renderer/api_binding.cc b/extensions/renderer/api_binding.cc |
index d3364792157c05b5ca7ab93826f2fdaf21ad8c9a..dc786821f75d7d84474154e4c9fb9f18de90ba82 100644 |
--- a/extensions/renderer/api_binding.cc |
+++ b/extensions/renderer/api_binding.cc |
@@ -72,64 +72,6 @@ void CallbackHelper(const v8::FunctionCallbackInfo<v8::Value>& info) { |
callback->Run(&args); |
} |
-// Decorates |object_template| with the properties specified by |properties|. |
-void DecorateTemplateWithProperties( |
- v8::Isolate* isolate, |
- v8::Local<v8::ObjectTemplate> object_template, |
- const base::DictionaryValue& properties) { |
- static const char kValueKey[] = "value"; |
- for (base::DictionaryValue::Iterator iter(properties); !iter.IsAtEnd(); |
- iter.Advance()) { |
- const base::DictionaryValue* dict = nullptr; |
- CHECK(iter.value().GetAsDictionary(&dict)); |
- bool optional = false; |
- if (dict->GetBoolean("optional", &optional)) { |
- // TODO(devlin): What does optional even mean here? It's only used, it |
- // seems, for lastError and inIncognitoContext, which are both handled |
- // with custom bindings. Investigate, and remove. |
- continue; |
- } |
- std::string ref; |
- if (dict->GetString("$ref", &ref)) { |
- // TODO(devlin): Handle refs. These are tricky(er), because they represent |
- // a type that's defined in (currently) JS. |
- continue; |
- } |
- std::string type; |
- CHECK(dict->GetString("type", &type)); |
- if (type != "object" && !dict->HasKey(kValueKey)) { |
- // TODO(devlin): What does a fundamental property not having a value mean? |
- // It doesn't seem useful, and looks like it's only used by runtime.id, |
- // which is set by custom bindings. Investigate, and remove. |
- continue; |
- } |
- if (type == "integer") { |
- int val = 0; |
- CHECK(dict->GetInteger(kValueKey, &val)); |
- object_template->Set(isolate, iter.key().c_str(), |
- v8::Integer::New(isolate, val)); |
- } else if (type == "boolean") { |
- bool val = false; |
- CHECK(dict->GetBoolean(kValueKey, &val)); |
- object_template->Set(isolate, iter.key().c_str(), |
- v8::Boolean::New(isolate, val)); |
- } else if (type == "string") { |
- std::string val; |
- CHECK(dict->GetString(kValueKey, &val)) << iter.key(); |
- object_template->Set(isolate, iter.key().c_str(), |
- gin::StringToSymbol(isolate, val)); |
- } else if (type == "object") { |
- v8::Local<v8::ObjectTemplate> property_template = |
- v8::ObjectTemplate::New(isolate); |
- const base::DictionaryValue* property_dict = nullptr; |
- CHECK(dict->GetDictionary("properties", &property_dict)); |
- DecorateTemplateWithProperties(isolate, property_template, |
- *property_dict); |
- object_template->Set(isolate, iter.key().c_str(), property_template); |
- } |
- } |
-} |
- |
} // namespace |
struct APIBinding::MethodData { |
@@ -166,17 +108,32 @@ struct APIBinding::EventData { |
APIEventHandler* event_handler; |
}; |
+struct APIBinding::CustomPropertyData { |
+ CustomPropertyData(const std::string& type_name, |
+ const std::string& property_name, |
+ const CreateCustomType& create_custom_type) |
+ : type_name(type_name), |
+ property_name(property_name), |
+ create_custom_type(create_custom_type) {} |
+ |
+ std::string type_name; |
lazyboy
2017/02/22 03:37:03
I find giving examples of these are helpful to nav
Devlin
2017/02/22 20:56:45
Done.
|
+ std::string property_name; |
+ CreateCustomType create_custom_type; |
+}; |
+ |
APIBinding::APIBinding(const std::string& api_name, |
const base::ListValue* function_definitions, |
const base::ListValue* type_definitions, |
const base::ListValue* event_definitions, |
const base::DictionaryValue* property_definitions, |
+ const CreateCustomType& create_custom_type, |
std::unique_ptr<APIBindingHooks> binding_hooks, |
APITypeReferenceMap* type_refs, |
APIRequestHandler* request_handler, |
APIEventHandler* event_handler) |
: api_name_(api_name), |
property_definitions_(property_definitions), |
+ create_custom_type_(create_custom_type), |
binding_hooks_(std::move(binding_hooks)), |
type_refs_(type_refs), |
request_handler_(request_handler), |
@@ -327,6 +284,67 @@ void APIBinding::InitializeTemplate(v8::Isolate* isolate) { |
object_template_.Set(isolate, object_template); |
} |
+void APIBinding::DecorateTemplateWithProperties( |
+ v8::Isolate* isolate, |
+ v8::Local<v8::ObjectTemplate> object_template, |
+ const base::DictionaryValue& properties) { |
+ static const char kValueKey[] = "value"; |
+ for (base::DictionaryValue::Iterator iter(properties); !iter.IsAtEnd(); |
+ iter.Advance()) { |
+ const base::DictionaryValue* dict = nullptr; |
+ CHECK(iter.value().GetAsDictionary(&dict)); |
+ bool optional = false; |
+ if (dict->GetBoolean("optional", &optional)) { |
+ // TODO(devlin): What does optional even mean here? It's only used, it |
+ // seems, for lastError and inIncognitoContext, which are both handled |
+ // with custom bindings. Investigate, and remove. |
+ continue; |
+ } |
+ |
+ v8::Local<v8::String> v8_key = gin::StringToSymbol(isolate, iter.key()); |
+ std::string ref; |
+ if (dict->GetString("$ref", &ref)) { |
lazyboy
2017/02/22 03:37:03
For storage, we would get "StorageArea" as $ref in
Devlin
2017/02/22 20:56:45
In our json generation/compression, we fully speci
|
+ auto property_data = base::MakeUnique<CustomPropertyData>( |
+ ref, iter.key(), create_custom_type_); |
+ object_template->SetLazyDataProperty( |
+ v8_key, &APIBinding::GetCustomPropertyObject, |
+ v8::External::New(isolate, property_data.get())); |
+ custom_properties_.push_back(std::move(property_data)); |
+ continue; |
+ } |
+ |
+ std::string type; |
+ CHECK(dict->GetString("type", &type)); |
+ if (type != "object" && !dict->HasKey(kValueKey)) { |
+ // TODO(devlin): What does a fundamental property not having a value mean? |
+ // It doesn't seem useful, and looks like it's only used by runtime.id, |
+ // which is set by custom bindings. Investigate, and remove. |
+ continue; |
+ } |
+ if (type == "integer") { |
+ int val = 0; |
+ CHECK(dict->GetInteger(kValueKey, &val)); |
+ object_template->Set(v8_key, v8::Integer::New(isolate, val)); |
+ } else if (type == "boolean") { |
+ bool val = false; |
+ CHECK(dict->GetBoolean(kValueKey, &val)); |
+ object_template->Set(v8_key, v8::Boolean::New(isolate, val)); |
+ } else if (type == "string") { |
+ std::string val; |
+ CHECK(dict->GetString(kValueKey, &val)) << iter.key(); |
+ object_template->Set(v8_key, gin::StringToSymbol(isolate, val)); |
+ } else if (type == "object" || !ref.empty()) { |
+ v8::Local<v8::ObjectTemplate> property_template = |
+ v8::ObjectTemplate::New(isolate); |
+ const base::DictionaryValue* property_dict = nullptr; |
+ CHECK(dict->GetDictionary("properties", &property_dict)); |
+ DecorateTemplateWithProperties(isolate, property_template, |
+ *property_dict); |
+ object_template->Set(v8_key, property_template); |
+ } |
+ } |
+} |
+ |
// static |
void APIBinding::GetEventObject( |
v8::Local<v8::Name> property, |
@@ -344,6 +362,27 @@ void APIBinding::GetEventObject( |
event_data->full_name, context)); |
} |
+void APIBinding::GetCustomPropertyObject( |
+ v8::Local<v8::Name> property_name, |
+ const v8::PropertyCallbackInfo<v8::Value>& info) { |
+ v8::Isolate* isolate = info.GetIsolate(); |
+ v8::HandleScope handle_scope(isolate); |
+ v8::Local<v8::Context> context = info.Holder()->CreationContext(); |
+ if (!IsContextValid(context)) |
+ return; |
+ |
+ CHECK(info.Data()->IsExternal()); |
+ auto* property_data = |
+ static_cast<CustomPropertyData*>(info.Data().As<v8::External>()->Value()); |
+ |
+ v8::Local<v8::Object> property = property_data->create_custom_type.Run( |
+ context, property_data->type_name, property_data->property_name); |
+ if (property.IsEmpty()) |
+ return; |
+ |
+ info.GetReturnValue().Set(property); |
+} |
+ |
void APIBinding::HandleCall(const std::string& name, |
const APISignature* signature, |
gin::Arguments* arguments) { |