| {# |
| # Copyright 2017 Google Inc. All Rights Reserved. |
| # |
| # Licensed under the Apache License, Version 2.0 (the "License"); |
| # you may not use this file except in compliance with the License. |
| # You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| #} |
| |
| {% from 'macros.cc.template' import add_extra_arguments %} |
| {% from 'macros.cc.template' import call_cobalt_function %} |
| {% from 'macros.cc.template' import check_if_object_implements_interface with context %} |
| {% from 'macros.cc.template' import constructor_implementation with context %} |
| {% from 'macros.cc.template' import function_implementation with context %} |
| {% from 'macros.cc.template' import get_impl_class_instance %} |
| {% from 'macros.cc.template' import nonstatic_function_prologue %} |
| {% from 'macros.cc.template' import overload_resolution_implementation with context %} |
| {% from 'macros.cc.template' import set_attribute_implementation with context %} |
| {% from 'macros.cc.template' import static_function_prologue %} |
| |
| {% extends "interface-base.cc.template" %} |
| |
| {% block includes %} |
| {{ super() }} |
| #include "{{generated_conversion_include}}" |
| |
| #include "cobalt/script/callback_interface_traits.h" |
| #include "cobalt/script/v8c/callback_function_conversion.h" |
| #include "cobalt/script/v8c/conversion_helpers.h" |
| #include "cobalt/script/v8c/entry_scope.h" |
| #include "cobalt/script/v8c/native_promise.h" |
| #include "cobalt/script/v8c/type_traits.h" |
| #include "cobalt/script/v8c/v8c_callback_function.h" |
| #include "cobalt/script/v8c/v8c_callback_interface_holder.h" |
| #include "cobalt/script/v8c/v8c_exception_state.h" |
| #include "cobalt/script/v8c/v8c_global_environment.h" |
| #include "cobalt/script/v8c/v8c_value_handle.h" |
| #include "cobalt/script/v8c/wrapper_private.h" |
| #include "v8/include/v8.h" |
| |
| {% endblock includes %} |
| |
| {% block using_directives %} |
| {{ super() }} |
| using cobalt::script::v8c::EntryScope; |
| using cobalt::script::v8c::EscapableEntryScope; |
| using cobalt::script::v8c::FromJSValue; |
| using cobalt::script::v8c::InterfaceData; |
| using cobalt::script::v8c::kConversionFlagClamped; |
| using cobalt::script::v8c::kConversionFlagNullable; |
| using cobalt::script::v8c::kConversionFlagObjectOnly; |
| using cobalt::script::v8c::kConversionFlagRestricted; |
| using cobalt::script::v8c::kConversionFlagTreatNullAsEmptyString; |
| using cobalt::script::v8c::kConversionFlagTreatUndefinedAsEmptyString; |
| using cobalt::script::v8c::kNoConversionFlags; |
| using cobalt::script::v8c::ToJSValue; |
| using cobalt::script::v8c::TypeTraits; |
| using cobalt::script::v8c::V8cExceptionState; |
| using cobalt::script::v8c::V8cGlobalEnvironment; |
| using cobalt::script::v8c::WrapperFactory; |
| using cobalt::script::v8c::WrapperPrivate; |
| {% endblock using_directives %} |
| |
| {% block enumeration_declarations %} |
| {% if enumerations|length %} |
| // Declare and define these in the same namespace that the other overloads |
| // were brought into with the using declaration. |
| {% for enumeration in enumerations %} |
| void ToJSValue( |
| v8::Isolate* isolate, |
| {{impl_class}}::{{enumeration.name}} in_enum, |
| v8::Local<v8::Value>* out_value); |
| void FromJSValue(v8::Isolate* context, v8::Local<v8::Value> value, |
| int conversion_flags, ExceptionState* exception_state, |
| {{impl_class}}::{{enumeration.name}}* out_enum); |
| {% endfor %} |
| {% endif %} |
| {% endblock enumeration_declarations %} |
| |
| {% block top_level_unnamed_namespace %} |
| |
| v8::Local<v8::Object> DummyFunctor(v8::Isolate*, const scoped_refptr<Wrappable>&) { |
| NOTIMPLEMENTED(); |
| return {}; |
| } |
| |
| {% endblock top_level_unnamed_namespace %} |
| |
| {% block implementation %} |
| |
| namespace { |
| |
| {% if constructor %} |
| |
| {% for overload in constructor.overloads if constructor.overloads|length > 1 %} |
| void Constructor{{overload.overload_index}}( |
| const v8::FunctionCallbackInfo<v8::Value>& info) { |
| v8::Isolate* isolate = info.GetIsolate(); |
| {{ constructor_implementation(overload) -}} |
| } |
| {% endfor %} |
| |
| void Constructor(const v8::FunctionCallbackInfo<v8::Value>& info) { |
| {% if constructor.overloads|length == 1 %} |
| v8::Isolate* isolate = info.GetIsolate(); |
| {{ constructor_implementation(constructor.overloads[0]) -}} |
| {% else %} |
| {{ overload_resolution_implementation(constructor, "Constructor")}} |
| {% endif %} |
| } |
| {% endif %} |
| |
| {% for constant in constants %} |
| void {{constant.idl_name}}AttributeGetter( |
| v8::Local<v8::String> property, const v8::PropertyCallbackInfo<v8::Value>& info) { |
| // TODO: Consider just attaching a constant instead. |
| v8::Local<v8::Value> result_value; |
| ToJSValue(info.GetIsolate(), {{constant.value}}, &result_value); |
| info.GetReturnValue().Set(result_value); |
| } |
| {% endfor %} |
| |
| {% for attribute in attributes + static_attributes %} |
| {% if attribute.conditional %} |
| #if defined({{attribute.conditional}}) |
| {% endif %} |
| {% if attribute.is_constructor_attribute %} |
| void {{attribute.idl_name}}AttributeGetter( |
| v8::Local<v8::String> property, const v8::PropertyCallbackInfo<v8::Value>& info) { |
| v8::Isolate* isolate = info.GetIsolate(); |
| v8::Local<v8::Object> object = info.This(); |
| v8::Local<v8::Object> global_object = info.GetIsolate()->GetCurrentContext()->Global(); |
| v8::Local<v8::Object> interface_object = V8c{{attribute.interface_name}}::GetInterfaceObject(isolate, global_object); |
| info.GetReturnValue().Set(interface_object); |
| } |
| {% else %} |
| {% if attribute.is_static %} |
| void {{attribute.idl_name}}StaticAttributeGetter( |
| {% else %} |
| void {{attribute.idl_name}}AttributeGetter( |
| {% endif %} |
| v8::Local<v8::String> property, const v8::PropertyCallbackInfo<v8::Value>& info) { |
| v8::Isolate* isolate = info.GetIsolate(); |
| v8::Local<v8::Object> object = info.This(); |
| |
| {% if attribute.is_static %} |
| {{ static_function_prologue() -}} |
| {% endif %} |
| |
| {% if not attribute.is_static %} |
| {{ check_if_object_implements_interface() }} |
| {{ nonstatic_function_prologue(impl_class) }} |
| {% endif %} |
| {{ call_cobalt_function(impl_class, attribute.type, |
| attribute.getter_function_name, [], |
| attribute.raises_exception, attribute.call_with, |
| attribute.is_static) }} |
| if (!exception_state.is_exception_set()) { |
| info.GetReturnValue().Set(result_value); |
| } |
| } |
| |
| {% if attribute.has_setter %} |
| {% if attribute.is_static %} |
| void {{attribute.idl_name}}StaticAttributeSetter( |
| {% else %} |
| void {{attribute.idl_name}}AttributeSetter( |
| {% endif %} |
| v8::Local<v8::String> property, |
| v8::Local<v8::Value> v8_value, |
| const v8::PropertyCallbackInfo<void>& info) { |
| v8::Isolate* isolate = info.GetIsolate(); |
| v8::Local<v8::Object> object = info.This(); |
| |
| {% if attribute.is_static %} |
| {{ static_function_prologue() }} |
| {% else %} |
| {{ check_if_object_implements_interface() }} |
| {{ nonstatic_function_prologue(impl_class)}} |
| {% endif %} {#- attribute.is_static #} |
| {{ set_attribute_implementation(attribute, impl_class) -}} |
| } |
| {% endif %} {#- attribute.has_setter #} |
| |
| {% endif %} |
| {% if attribute.conditional %} |
| #endif // {{attribute.conditional}} |
| {% endif %} {#- attribute.is_constructor_attribute #} |
| {% endfor %} {#- for attribute in attributes + static_attributes #} |
| |
| {%- for operation in operations + static_operations %} |
| {% if operation.conditional %} |
| #if defined({{operation.conditional}}) |
| {% endif %} |
| {% set boundFunctionSuffix = "StaticMethod" if operation.is_static else "Method" %} |
| |
| {% for overload in operation.overloads if operation.overloads|length > 1 %} |
| void {{operation.idl_name}}{{boundFunctionSuffix}}{{overload.overload_index}}( |
| const v8::FunctionCallbackInfo<v8::Value>& info) { |
| {{ function_implementation(overload) -}} |
| } |
| {% endfor %} |
| |
| void {{operation.idl_name}}{{boundFunctionSuffix}}(const v8::FunctionCallbackInfo<v8::Value>& info) { |
| {% if operation.overloads|length == 1 %} |
| {{ function_implementation(operation.overloads[0]) -}} |
| {% else %} |
| {{ overload_resolution_implementation(operation, operation.idl_name + boundFunctionSuffix) }} |
| {% endif %} |
| } |
| |
| {% if operation.conditional %} |
| #endif // {{operation.conditional}} |
| {% endif %} |
| {% endfor %} |
| |
| void InitializeTemplateAndInterfaceObject(v8::Isolate* isolate, InterfaceData* interface_data) { |
| v8::Local<v8::FunctionTemplate> function_template = v8::FunctionTemplate::New(isolate); |
| function_template->SetClassName( |
| v8::String::NewFromUtf8(isolate, "{{interface_name}}", |
| v8::NewStringType::kInternalized).ToLocalChecked()); |
| v8::Local<v8::ObjectTemplate> instance_template = function_template->InstanceTemplate(); |
| instance_template->SetInternalFieldCount(WrapperPrivate::kInternalFieldCount); |
| |
| {% if parent_interface %} |
| v8::Local<v8::FunctionTemplate> parent_template = {{parent_interface}}::CreateTemplate(isolate); |
| function_template->Inherit(parent_template); |
| {% elif is_exception_interface %} |
| NOTIMPLEMENTED(); |
| {% endif %} |
| |
| v8::Local<v8::ObjectTemplate> prototype_template = function_template->PrototypeTemplate(); |
| |
| {% for constant in constants %} |
| prototype_template->SetAccessor( |
| v8::String::NewFromUtf8(isolate, "{{constant.idl_name}}", |
| v8::NewStringType::kInternalized) |
| .ToLocalChecked(), |
| {{constant.idl_name}}AttributeGetter); |
| {% endfor %} |
| |
| {% for attribute in attributes if not attribute.is_constructor_attribute %} |
| {% if attribute.conditional %} |
| #if defined({{attribute.conditional}}) |
| {% endif %} |
| instance_template->SetAccessor( |
| v8::String::NewFromUtf8(isolate, "{{attribute.idl_name}}", |
| v8::NewStringType::kInternalized) |
| .ToLocalChecked(), |
| {{attribute.idl_name}}AttributeGetter |
| {% if attribute.has_setter %} |
| ,{{attribute.idl_name}}AttributeSetter |
| {% endif %} |
| ); |
| {% if attribute.conditional %} |
| #endif // defined({{attribute.conditional}}) |
| {% endif %} |
| {% endfor %} |
| |
| {% for operation in operations %} |
| {% if operation.conditional %} |
| #if defined({{operation.conditional}}) |
| {% endif %} |
| { |
| v8::Local<v8::FunctionTemplate> method_template = v8::FunctionTemplate::New(isolate, {{operation.idl_name}}Method); |
| method_template->RemovePrototype(); |
| prototype_template->Set( |
| v8::String::NewFromUtf8( |
| isolate, |
| "{{operation.idl_name}}", |
| v8::NewStringType::kInternalized).ToLocalChecked(), |
| method_template); |
| } |
| {% if operation.conditional %} |
| #endif // defined({{operation.conditional}}) |
| {% endif %} |
| |
| {% endfor %} |
| |
| interface_data->function_template.Set(isolate, function_template); |
| } |
| |
| inline InterfaceData* GetInterfaceData(V8cGlobalEnvironment* global_environment) { |
| const int kInterfaceUniqueId = {{unique_id}}; |
| // By convention, the |V8cGlobalEnvironment| that we are associated with |
| // will hold our |InterfaceData| at index |kInterfaceUniqueId|, as we asked |
| // for it to be there in the first place, and could not have conflicted with |
| // any other interface. |
| return global_environment->GetInterfaceData(kInterfaceUniqueId); |
| } |
| |
| } // namespace |
| |
| v8::Local<v8::Object> {{binding_class}}::CreateWrapper(v8::Isolate* isolate, const scoped_refptr<Wrappable>& wrappable) { |
| EscapableEntryScope entry_scope(isolate); |
| v8::Local<v8::Context> context = isolate->GetCurrentContext(); |
| |
| V8cGlobalEnvironment* global_environment = V8cGlobalEnvironment::GetFromIsolate(isolate); |
| InterfaceData* interface_data = GetInterfaceData(global_environment); |
| if (interface_data->function_template.IsEmpty()) { |
| InitializeTemplateAndInterfaceObject(isolate, interface_data); |
| } |
| DCHECK(!interface_data->function_template.IsEmpty()); |
| |
| v8::Local<v8::FunctionTemplate> function_template = interface_data->function_template.Get(isolate); |
| DCHECK(function_template->InstanceTemplate()->InternalFieldCount() == WrapperPrivate::kInternalFieldCount); |
| v8::Local<v8::Object> object = function_template->InstanceTemplate()->NewInstance(context).ToLocalChecked(); |
| DCHECK(object->InternalFieldCount() == WrapperPrivate::kInternalFieldCount); |
| |
| // This |WrapperPrivate|'s lifetime will be managed by V8. |
| new WrapperPrivate(isolate, wrappable, object); |
| return entry_scope.Escape(object); |
| } |
| |
| v8::Local<v8::FunctionTemplate> {{binding_class}}::CreateTemplate(v8::Isolate* isolate) { |
| V8cGlobalEnvironment* global_environment = V8cGlobalEnvironment::GetFromIsolate(isolate); |
| InterfaceData* interface_data = GetInterfaceData(global_environment); |
| if (interface_data->function_template.IsEmpty()) { |
| InitializeTemplateAndInterfaceObject(isolate, interface_data); |
| } |
| |
| return interface_data->function_template.Get(isolate); |
| } |
| |
| {% endblock implementation %} |
| |
| {% block create_global_object_impl %} |
| |
| namespace cobalt { |
| namespace script { |
| namespace v8c { |
| |
| template <typename GlobalInterface> |
| void V8cGlobalEnvironment::CreateGlobalObject( |
| const scoped_refptr<GlobalInterface>& global_interface, |
| EnvironmentSettings* environment_settings) { |
| // Intentionally not an |EntryScope|, since the context doesn't exist yet. |
| v8::Isolate::Scope isolate_scope(isolate_); |
| v8::HandleScope handle_scope(isolate_); |
| v8::Local<v8::ObjectTemplate> global_object_template = {{binding_class}}::CreateTemplate(isolate_)->InstanceTemplate(); |
| |
| {% for interface in all_interfaces %} |
| {% if interface.conditional %} |
| #if defined({{interface.conditional}}) |
| {% endif %} |
| global_object_template->Set( |
| v8::String::NewFromUtf8( |
| isolate_, "{{interface.name}}", |
| v8::NewStringType::kInternalized).ToLocalChecked(), |
| V8c{{interface.name}}::CreateTemplate(isolate_)); |
| {% if interface.conditional %} |
| #endif // defined({{interface.conditional}}) |
| {% endif %} |
| {% endfor %} |
| |
| v8::Local<v8::Context> context = |
| v8::Context::New(isolate_, nullptr, global_object_template); |
| context_.Reset(isolate_, context); |
| v8::Context::Scope context_scope(context); |
| |
| DCHECK(!environment_settings_); |
| DCHECK(environment_settings); |
| environment_settings_ = environment_settings; |
| EvaluateAutomatics(); |
| |
| {% for interface in all_interfaces %} |
| {% if interface.conditional %} |
| #if defined({{interface.conditional}}) |
| {% endif %} |
| {# Pass in a dummy CreateProxy for global interface #} |
| {% if interface.name == impl_class %} |
| wrapper_factory_->RegisterWrappableType( |
| {{interface.name}}::{{interface.name}}WrappableType(), |
| base::Bind(DummyFunctor), |
| base::Bind(V8c{{interface.name}}::CreateTemplate)); |
| {% else %} |
| wrapper_factory_->RegisterWrappableType( |
| {{interface.name}}::{{interface.name}}WrappableType(), |
| base::Bind(V8c{{interface.name}}::CreateWrapper), |
| base::Bind(V8c{{interface.name}}::CreateTemplate)); |
| {% endif %} |
| {% if interface.conditional %} |
| #endif // defined({{interface.conditional}}) |
| {% endif %} |
| {% endfor %} |
| |
| } |
| |
| } // namespace v8c |
| |
| template<> |
| void GlobalEnvironment::CreateGlobalObject<{{impl_class}}>( |
| const scoped_refptr<{{impl_class}}>& global_interface, |
| EnvironmentSettings* environment_settings) { |
| base::polymorphic_downcast<v8c::V8cGlobalEnvironment*>(this)->CreateGlobalObject(global_interface, environment_settings); |
| } |
| |
| } // namespace script |
| } // namespace cobalt |
| |
| {% endblock create_global_object_impl %} |
| |
| {% block enumeration_definitions %} |
| // enum block |
| {% for enumeration in enumerations %} |
| |
| inline void ToJSValue( |
| v8::Isolate* isolate, |
| {{impl_class}}::{{enumeration.name}} in_enum, |
| v8::Local<v8::Value>* out_value) { |
| switch (in_enum) { |
| {% for value, idl_value in enumeration.value_pairs %} |
| case {{impl_class}}::{{value}}: |
| ToJSValue(isolate, std::string("{{idl_value}}"), out_value); |
| return; |
| {% endfor %} |
| default: |
| NOTREACHED(); |
| *out_value = v8::Undefined(isolate); |
| } |
| } |
| |
| inline void FromJSValue( |
| v8::Isolate* isolate, v8::Local<v8::Value> value, |
| int conversion_flags, ExceptionState* exception_state, |
| {{impl_class}}::{{enumeration.name}}* out_enum) { |
| DCHECK_EQ(0, conversion_flags) << "Unexpected conversion flags."; |
| // Value -> IDL enum algorithm described here: |
| // http://heycam.github.io/webidl/#es-enumeration |
| // 1. Let S be the result of calling ToString(V). |
| v8::Local<v8::Context> context = isolate->GetCurrentContext(); |
| v8::MaybeLocal<v8::String> maybe_string = value->ToString(context); |
| v8::Local<v8::String> string; |
| if (!maybe_string.ToLocal(&string)) { |
| exception_state->SetSimpleException(cobalt::script::kConvertToEnumFailed); |
| return; |
| } |
| |
| bool match = false; |
| // 3. Return the enumeration value of type E that is equal to S. |
| {% for value, idl_value in enumeration.value_pairs %} |
| {{-" else " if not loop.first}} |
| if (string == v8::String::NewFromUtf8(isolate, "{{id_value}}", v8::NewStringType::kInternalized).ToLocalChecked()) { |
| *out_enum = {{impl_class}}::{{value}}; |
| } |
| {% endfor %} |
| else { |
| // 2. If S is not one of E's enumeration values, then throw a TypeError. |
| exception_state->SetSimpleException(cobalt::script::kConvertToEnumFailed); |
| return; |
| } |
| } |
| |
| {% endfor %} |
| |
| {% endblock enumeration_definitions %} |