blob: 5759ac836f7839df30863c50f873828c12cfae0e [file] [log] [blame]
{#
# 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 %}