blob: e90abc97b7b5dabbb6ab3bf8adb4c5c12dee905f [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/v8c_array_buffer.h"
#include "cobalt/script/v8c/v8c_array_buffer_view.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/helpers.h"
#include "cobalt/script/v8c/native_promise.h"
#include "cobalt/script/v8c/type_traits.h"
#include "cobalt/script/v8c/v8c_typed_arrays.h"
#include "cobalt/script/v8c/v8c_data_view.h"
#include "cobalt/script/v8c/v8c_callback_function.h"
#include "cobalt/script/v8c/v8c_callback_interface_holder.h"
#include "cobalt/script/v8c/v8c_engine.h"
#include "cobalt/script/v8c/v8c_exception_state.h"
#include "cobalt/script/v8c/v8c_global_environment.h"
#include "cobalt/script/v8c/v8c_property_enumerator.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::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::NewInternalString;
using cobalt::script::v8c::ToJSValue;
using cobalt::script::v8c::TypeTraits;
using cobalt::script::v8c::V8cExceptionState;
using cobalt::script::v8c::V8cGlobalEnvironment;
using cobalt::script::v8c::V8cPropertyEnumerator;
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 %}
{% endblock top_level_unnamed_namespace %}
{% block implementation %}
namespace {
const int kInterfaceUniqueId = {{unique_id}};
{% if named_property_getter %}
void NamedPropertyGetterCallback(
v8::Local<v8::Name> property,
const v8::PropertyCallbackInfo<v8::Value>& info) {
v8::Isolate* isolate = info.GetIsolate();
v8::Local<v8::Object> object = info.Holder();
{{ nonstatic_function_prologue(impl_class) }}
std::string property_name = *v8::String::Utf8Value(isolate, property);
if (!impl->CanQueryNamedProperty(property_name)) {
return;
}
{{ call_cobalt_function(impl_class, named_property_getter.type,
named_property_getter.name, ["property_name"],
named_property_getter.raises_exception,
named_property_getter.call_with) }}
if (exception_state.is_exception_set()) {
return;
}
info.GetReturnValue().Set(result_value);
}
{% if not indexed_property_getter %}
void IndexedPropertyGetterCallback(
uint32_t index,
const v8::PropertyCallbackInfo<v8::Value>& info) {
v8::Local<v8::String> as_string = v8::Integer::New(info.GetIsolate(), index)->ToString();
NamedPropertyGetterCallback(as_string, info);
}
{% endif %}
void NamedPropertyQueryCallback(
v8::Local<v8::Name> property,
const v8::PropertyCallbackInfo<v8::Integer>& info) {
v8::Isolate* isolate = info.GetIsolate();
v8::Local<v8::Object> object = info.Holder();
{{ get_impl_class_instance(impl_class) }}
std::string property_name = *v8::String::Utf8Value(isolate, property);
bool result = impl->CanQueryNamedProperty(property_name);
if (!result) {
return;
}
// https://heycam.github.io/webidl/#LegacyPlatformObjectGetOwnProperty
int properties = v8::None;
// 2.7. If |O| implements an interface with a named property setter, then set
// desc.[[Writable]] to true, otherwise set it to false.
{% if named_property_setter %}
{% else %}
properties |= v8::ReadOnly;
{% endif %}
// 2.8. If |O| implements an interface with the
// [LegacyUnenumerableNamedProperties] extended attribute, then set
// desc.[[Enumerable]] to false, otherwise set it to true.
{% if has_legacy_unenumerable_named_properties %}
// TODO: Note that this is never true at the moment, as Cobalt's IDLs and
// IDL compiler do not support this.
properties |= v8::DontEnum;
{% endif %}
info.GetReturnValue().Set(properties);
}
{% if not indexed_property_getter %}
void IndexedPropertyDescriptorCallback(
uint32_t index, const v8::PropertyCallbackInfo<v8::Value>& info) {
// TODO: Figure out under what conditions this gets called. It's not
// getting called in our tests.
NOTIMPLEMENTED();
}
{% endif %}
void NamedPropertyEnumeratorCallback(
const v8::PropertyCallbackInfo<v8::Array>& info) {
v8::Isolate* isolate = info.GetIsolate();
v8::Local<v8::Object> object = info.Holder();
{{ get_impl_class_instance(impl_class) }}
v8::Local<v8::Array> array = v8::Array::New(isolate);
V8cPropertyEnumerator property_enumerator(isolate, &array);
impl->EnumerateNamedProperties(&property_enumerator);
info.GetReturnValue().Set(array);
}
{% endif %}
{% if named_property_setter %}
void NamedPropertySetterCallback(
v8::Local<v8::Name> property,
v8::Local<v8::Value> value,
const v8::PropertyCallbackInfo<v8::Value>& info) {
v8::Isolate* isolate = info.GetIsolate();
v8::Local<v8::Object> object = info.Holder();
{{ nonstatic_function_prologue(impl_class) }}
std::string property_name = *v8::String::Utf8Value(isolate, property);
TypeTraits<{{named_property_setter.type}}>::ConversionType native_value;
FromJSValue(isolate, value, {{named_property_setter.conversion_flags}},
&exception_state, &native_value);
if (exception_state.is_exception_set()) {
return;
}
{{ call_cobalt_function(impl_class, "void",
named_property_setter.name, ["property_name", "native_value"],
named_property_setter.raises_exception,
named_property_setter.call_with) }}
if (exception_state.is_exception_set()) {
return;
}
info.GetReturnValue().Set(value);
}
{% if not indexed_property_setter %}
void IndexedPropertySetterCallback(
uint32_t index,
v8::Local<v8::Value> value,
const v8::PropertyCallbackInfo<v8::Value>& info) {
v8::Local<v8::String> as_string = v8::Integer::New(info.GetIsolate(), index)->ToString();
NamedPropertySetterCallback(as_string, value, info);
}
{% endif %}
{% endif %}
{% if named_property_deleter %}
void NamedPropertyDeleterCallback(
v8::Local<v8::Name> property,
const v8::PropertyCallbackInfo<v8::Boolean>& info) {
v8::Isolate* isolate = info.GetIsolate();
v8::Local<v8::Object> object = info.Holder();
{{ nonstatic_function_prologue(impl_class) }}
std::string property_name = *v8::String::Utf8Value(isolate, property);
if (!impl->CanQueryNamedProperty(property_name)) {
return;
}
{{ call_cobalt_function(impl_class, "void",
named_property_deleter.name, ["property_name"],
named_property_deleter.raises_exception,
named_property_deleter.call_with) }}
if (exception_state.is_exception_set()) {
return;
}
info.GetReturnValue().Set(true);
}
{% if not indexed_property_deleter %}
void IndexedPropertyDeleterCallback(
uint32_t index,
const v8::PropertyCallbackInfo<v8::Boolean>& info) {
v8::Isolate* isolate = info.GetIsolate();
v8::Local<v8::String> as_string = v8::Integer::New(info.GetIsolate(), index)->ToString();
NamedPropertyDeleterCallback(as_string, info);
}
{% endif %}
{% endif %}
{% if indexed_property_getter %}
void IndexedPropertyGetterCallback(
uint32_t index,
const v8::PropertyCallbackInfo<v8::Value>& info) {
v8::Isolate* isolate = info.GetIsolate();
v8::Local<v8::Object> object = info.Holder();
{{ nonstatic_function_prologue(impl_class) }}
if (index >= impl->length()) {
// |index| is out of bounds, so return undefined.
return;
}
{{ call_cobalt_function(impl_class, indexed_property_getter.type,
indexed_property_getter.name, ["index"],
indexed_property_getter.raises_exception,
indexed_property_getter.call_with) }}
info.GetReturnValue().Set(result_value);
}
void IndexedPropertyDescriptorCallback(
uint32_t index, const v8::PropertyCallbackInfo<v8::Value>& info) {
// TODO: Figure out under what conditions this gets called. It's not
// getting called in our tests.
NOTIMPLEMENTED();
}
void IndexedPropertyEnumeratorCallback(
const v8::PropertyCallbackInfo<v8::Array>& info) {
v8::Isolate* isolate = info.GetIsolate();
v8::Local<v8::Object> object = info.Holder();
{{ get_impl_class_instance(impl_class) }}
const uint32_t length = impl->length();
v8::Local<v8::Array> array = v8::Array::New(isolate, length);
for (uint32_t i = 0; i < length; ++i) {
array->Set(i, v8::Integer::New(isolate, i));
}
info.GetReturnValue().Set(array);
}
void IndexedPropertyDefinerCallback(
uint32_t index, const v8::PropertyDescriptor& desc,
const v8::PropertyCallbackInfo<v8::Value>& info) {
// TODO: Figure out under what conditions this gets called. It's not
// getting called in our tests.
NOTIMPLEMENTED();
}
{% endif %}
{% if indexed_property_setter %}
void IndexedPropertySetterCallback(
uint32_t index,
v8::Local<v8::Value> value,
const v8::PropertyCallbackInfo<v8::Value>& info) {
v8::Isolate* isolate = info.GetIsolate();
v8::Local<v8::Object> object = info.Holder();
{{ nonstatic_function_prologue(impl_class) }}
if (index >= impl->length()) {
return;
}
TypeTraits<{{indexed_property_setter.type}}>::ConversionType native_value;
FromJSValue(isolate, value, {{indexed_property_setter.conversion_flags}},
&exception_state, &native_value);
if (exception_state.is_exception_set()) {
return;
}
{{ call_cobalt_function(impl_class, "void",
indexed_property_setter.name, ["index", "native_value"],
indexed_property_setter.raises_exception,
indexed_property_setter.call_with) }}
if (exception_state.is_exception_set()) {
return;
}
info.GetReturnValue().Set(value);
}
{% endif %}
{% if indexed_property_deleter %}
void IndexedPropertyDeleterCallback(
uint32_t index,
const v8::PropertyCallbackInfo<v8::Boolean>& info) {
v8::Isolate* isolate = info.GetIsolate();
v8::Local<v8::Object> object = info.Holder();
{{ nonstatic_function_prologue(impl_class) }}
if (index >= impl->length()) {
return;
}
{{ call_cobalt_function(impl_class, "void",
indexed_property_deleter.name, ["index"],
indexed_property_deleter.raises_exception,
indexed_property_deleter.call_with) }}
if (exception_state.is_exception_set()) {
return;
}
info.GetReturnValue().Set(v8::Boolean::New(isolate, true));
}
{% endif %}
{% 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 %}
}
{% else %}
void DummyConstructor(const v8::FunctionCallbackInfo<v8::Value>& info) {
V8cExceptionState exception(info.GetIsolate());
exception.SetSimpleException(
script::kTypeError, "{{interface_name}} is not constructible.");
}
{% endif %}
{% for attribute in attributes + static_attributes %}
{% if attribute.conditional %}
#if defined({{attribute.conditional}})
{% endif %}
{% if attribute.is_constructor_attribute %}
// Nothing for {{attribute}}. We will just give them the v8::FunctionTemplate.
{% else %}
void {{attribute.idl_name}}AttributeGetter(
const v8::FunctionCallbackInfo<v8::Value>& info) {
v8::Isolate* isolate = info.GetIsolate();
v8::Local<v8::Object> object = info.Holder();
{% 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()) {
return;
}
info.GetReturnValue().Set(result_value);
}
{% if attribute.has_setter %}
void {{attribute.idl_name}}AttributeSetter(
const v8::FunctionCallbackInfo<v8::Value>& info) {
v8::Isolate* isolate = info.GetIsolate();
v8::Local<v8::Object> object = info.Holder();
v8::Local<v8::Value> v8_value = info[0];
{% 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 %}
{% if stringifier %}
void Stringifier(const v8::FunctionCallbackInfo<v8::Value>& info) {
v8::Isolate* isolate = info.GetIsolate();
v8::Local<v8::Object> object = info.Holder();
V8cExceptionState exception_state(isolate);
{{ check_if_object_implements_interface() }}
WrapperPrivate* wrapper_private =
WrapperPrivate::GetFromWrapperObject(object);
// |WrapperPrivate::GetFromObject| can fail if |object| is not a |Wrapper|
// object.
if (!wrapper_private) {
exception_state.SetSimpleException(cobalt::script::kStringifierProblem);
return;
}
{{impl_class}}* impl =
wrapper_private->wrappable<{{impl_class}}>().get();
if (!impl) {
exception_state.SetSimpleException(cobalt::script::kStringifierProblem);
NOTREACHED();
return;
}
std::string stringified = impl->{{stringifier.name}}();
v8::Local<v8::Value> v8_stringified;
ToJSValue(isolate, stringified, &v8_stringified);
info.GetReturnValue().Set(v8_stringified);
}
{% endif %}
void InitializeTemplate(v8::Isolate* isolate) {
// https://heycam.github.io/webidl/#interface-object
// 3.6.1. Interface object
//
// The interface object for a given interface is a built-in function object.
// It has properties that correspond to the constants and static operations
// defined on that interface, as described in sections 3.6.6 Constants and
// 3.6.8 Operations.
//
// If the interface is declared with a [Constructor] extended attribute,
// then the interface object can be called as a constructor to create an
// object that implements that interface. Calling that interface as a
// function will throw an exception.
//
// Interface objects whose interfaces are not declared with a [Constructor]
// extended attribute will throw when called, both as a function and as a
// constructor.
//
// An interface object for a non-callback interface has an associated object
// called the interface prototype object. This object has properties that
// correspond to the regular attributes and regular operations defined on
// the interface, and is described in more detail in 3.6.3 Interface
// prototype object.
{% if constructor %}
v8::Local<v8::FunctionTemplate> function_template =
v8::FunctionTemplate::New(
isolate,
Constructor,
v8::Local<v8::Value>(),
v8::Local<v8::Signature>(),
{{constructor.length}});
function_template->SetLength({{constructor.length}});
{% else %}
v8::Local<v8::FunctionTemplate> function_template =
v8::FunctionTemplate::New(
isolate,
DummyConstructor,
v8::Local<v8::Value>(),
v8::Local<v8::Signature>(),
0);
{% endif %}
function_template->SetClassName(NewInternalString(isolate, "{{interface_name}}"));
function_template->ReadOnlyPrototype();
v8::Local<v8::ObjectTemplate> prototype_template = function_template->PrototypeTemplate();
v8::Local<v8::ObjectTemplate> instance_template = function_template->InstanceTemplate();
instance_template->SetInternalFieldCount(WrapperPrivate::kInternalFieldCount);
V8cGlobalEnvironment* global_environment = V8cGlobalEnvironment::GetFromIsolate(isolate);
global_environment->AddInterfaceData(kInterfaceUniqueId, function_template);
{% if parent_interface %}
{
// An interface can be defined to inherit from another interface. If the
// identifier of the interface is followed by a U+003A COLON (":") character
// and an identifier, then that identifier identifies the inherited
// interface. An object that implements an interface that inherits from
// another also implements that inherited interface. The object therefore
// will also have members that correspond to the interface members from the
// inherited interface.
v8::Local<v8::FunctionTemplate> parent_template = {{parent_interface}}::GetTemplate(isolate);
function_template->Inherit(parent_template);
static_assert(
std::is_base_of<{{parent_interface_name}}, {{interface_name}}>::value,
"Expected {{interface_name}} to have C++ parent class "
"{{parent_interface_name}}, because that is its WebIDL parent.");
}
{% elif is_exception_interface %}
{
// A spicy hack from Chromium in order to achieve
// https://heycam.github.io/webidl/#es-DOMException-specialness
// See https://cs.chromium.org/chromium/src/third_party/WebKit/Source/bindings/templates/interface_base.cpp.tmpl?l=630&rcl=0f7c2c752bb24ad08c17017e4e68401093fe76a0
v8::Local<v8::FunctionTemplate> intrinsic_error_prototype_interface_template =
v8::FunctionTemplate::New(isolate);
intrinsic_error_prototype_interface_template->RemovePrototype();
intrinsic_error_prototype_interface_template->SetIntrinsicDataProperty(
NewInternalString(isolate, "prototype"), v8::kErrorPrototype);
function_template->Inherit(intrinsic_error_prototype_interface_template);
}
{% endif %}
// https://heycam.github.io/webidl/#es-constants
// 3.6.6. Constants
//
// For each exposed constant defined on an interface A, there must be a
// corresponding property. The property has the following characteristics:
{% for constant in constants %}
{
// The name of the property is the identifier of the constant.
v8::Local<v8::String> name = NewInternalString(
isolate,
"{{constant.idl_name}}");
// The value of the property is that which is obtained by converting the
// constant's IDL value to an ECMAScript value.
v8::Local<v8::Value> constant_value;
ToJSValue(isolate, {{constant.value}}, &constant_value);
// The property has attributes { [[Writable]]: false, [[Enumerable]]: true,
// [[Configurable]]: false }.
v8::PropertyAttribute attributes = static_cast<v8::PropertyAttribute>(
v8::ReadOnly | v8::DontDelete);
// The location of the property is determined as follows:
{% if is_global_interface %}
// If the interface was declared with the [Global] extended attribute, then
// the property exists on the single object that implements the interface.
instance_template->Set(name, constant_value, attributes);
{% else %}
// Otherwise, if the interface has an interface prototype object, then the
// property exists on it.
prototype_template->Set(name, constant_value, attributes);
{% endif %}
// In addition, a property with the same characteristics must exist on the
// interface object or the legacy callback interface object, if either of
// those objects exists.
function_template->Set(name, constant_value, attributes);
}
{% endfor %}
// https://heycam.github.io/webidl/#es-attributes
// 3.6.7. Attributes
//
// For each exposed attribute of the interface there must exist a
// corresponding property. The characteristics of this property are as
// follows:
{% for attribute in all_attributes_v8_order_quirk %}
{% if attribute.conditional %}
#if defined({{attribute.conditional}})
{% endif %}
{
// The name of the property is the identifier of the attribute.
v8::Local<v8::String> name = NewInternalString(
isolate,
"{{attribute.idl_name}}");
// The property has attributes { [[Get]]: G, [[Set]]: S, [[Enumerable]]:
// true, [[Configurable]]: configurable }, where: configurable is false if
// the attribute was declared with the [Unforgeable] extended attribute and
// true otherwise;
bool configurable = {{ "false" if attribute.is_unforgeable else "true"}};
v8::PropertyAttribute attributes = static_cast<v8::PropertyAttribute>(
configurable ? v8::None : v8::DontDelete);
// G is the attribute getter created given the attribute, the interface, and
// the relevant Realm of the object that is the location of the property;
// and
//
// S is the attribute setter created given the attribute, the interface, and
// the relevant Realm of the object that is the location of the property.
{% if not attribute.is_constructor_attribute %}
v8::Local<v8::FunctionTemplate> getter =
v8::FunctionTemplate::New(isolate, {{attribute.idl_name}}AttributeGetter);
{% if attribute.has_setter %}
v8::Local<v8::FunctionTemplate> setter =
v8::FunctionTemplate::New(isolate, {{attribute.idl_name}}AttributeSetter);
{% else %}
v8::Local<v8::FunctionTemplate> setter;
{% endif %}
// The location of the property is determined as follows:
{% if attribute.is_static %}
// Operations installed on the interface object must be static methods, so
// no need to specify a signature, i.e. no need to do type check against a
// holder.
// If the attribute is a static attribute, then there is a single
// corresponding property and it exists on the interface's interface object.
function_template->
{% elif attribute.is_unforgeable or is_global_interface %}
// Otherwise, if the attribute is unforgeable on the interface or if the
// interface was declared with the [Global] extended attribute, then the
// property exists on every object that implements the interface.
instance_template->
{% else %}
// Otherwise, the property exists solely on the interface's interface
// prototype object.
prototype_template->
{% endif %}
SetAccessorProperty(
name,
getter,
setter,
attributes);
{% else %} {#- not attribute.is_constructor_attribute #}
{
v8::Local<v8::String> name = NewInternalString(
isolate,
"{{attribute.idl_name}}");
instance_template->Set(
name,
{% if attribute.interface_name == interface_name %}
function_template
{% else %}
// Note that we use "attribute.interface_name", and not
// "attribute.idl_name", because of named constructors.
V8c{{attribute.interface_name}}::GetTemplate(isolate)
{% endif %}
);
}
{% endif %} {#- not attribute.is_constructor_attribute #}
}
{% if attribute.conditional %}
#endif // {{attribute.conditional}}
{% endif %}
{% endfor %}
// https://heycam.github.io/webidl/#es-operations
// 3.6.8. Operations
//
// For each unique identifier of an exposed operation defined on the
// interface, there must exist a corresponding property, unless the effective
// overload set for that identifier and operation and with an argument count
// of 0 has no entries.
//
// The characteristics of this property are as follows:
{% for operation in operations + static_operations %}
{% if operation.conditional %}
#if defined({{operation.conditional}})
{% endif %}
{
// The name of the property is the identifier.
v8::Local<v8::String> name = NewInternalString(
isolate,
"{{operation.idl_name}}");
// The property has attributes { [[Writable]]: B, [[Enumerable]]: true,
// [[Configurable]]: B }, where B is false if the operation is unforgeable
// on the interface, and true otherwise.
bool B = {{ "false" if operation.is_unforgeable else "true"}};
v8::PropertyAttribute attributes = static_cast<v8::PropertyAttribute>(
B ? v8::None : (v8::ReadOnly | v8::DontDelete));
v8::Local<v8::FunctionTemplate> method_template =
v8::FunctionTemplate::New(isolate, {{operation.idl_name}}{{"Static" if operation.is_static else ""}}Method);
method_template->RemovePrototype();
method_template->SetLength({{operation.length}});
// The location of the property is determined as follows:
{% if operation.is_static %}
// If the operation is static, then the property exists on the interface
// object.
function_template->
{% elif operation.is_unforgeable or is_global_interface %}
// Otherwise, if the operation is unforgeable on the interface or if the
// interface was declared with the [Global] extended attribute, then the
// property exists on every object that implements the interface.
instance_template->
{% else %}
// Otherwise, the property exists solely on the interface's interface
// prototype object.
prototype_template->
{% endif %}
Set(name, method_template);
// The value of the property is the result of creating an operation function
// given the operation, the interface, and the relevant Realm of the object
// that is the location of the property.
// Note: that is, even if an includes statement was used to make an
// operation available on the interface, we pass in the interface which
// includes the interface mixin, and not the interface mixin on which the
// operation was originally declared.
}
{% if operation.conditional %}
#endif // {{operation.conditional}}
{% endif %}
{% endfor %}
// https://heycam.github.io/webidl/#es-stringifier
// 3.6.8.2. Stringifiers
prototype_template->Set(
v8::Symbol::GetToStringTag(isolate),
NewInternalString(isolate, "{{interface_name}}"),
static_cast<v8::PropertyAttribute>(v8::ReadOnly | v8::DontEnum));
{% if stringifier %}
{
v8::Local<v8::String> name = NewInternalString(isolate, "toString");
v8::Local<v8::FunctionTemplate> method_template = v8::FunctionTemplate::New(isolate, Stringifier);
prototype_template->Set(
NewInternalString(isolate, "toString"),
method_template);
}
{% endif %}
{% if named_property_getter %}
{
v8::NamedPropertyHandlerConfiguration named_property_handler_configuration = {
NamedPropertyGetterCallback,
{{ "NamedPropertySetterCallback" if named_property_setter else "nullptr" }},
NamedPropertyQueryCallback,
{{ "NamedPropertyDeleterCallback" if named_property_deleter else "nullptr" }},
NamedPropertyEnumeratorCallback,
v8::Local<v8::Value>(),
static_cast<v8::PropertyHandlerFlags>(int(v8::PropertyHandlerFlags::kNonMasking) | int(v8::PropertyHandlerFlags::kOnlyInterceptStrings))
};
instance_template->SetHandler(named_property_handler_configuration);
}
{% endif %}
{% if named_property_getter and not indexed_property_getter %}
{
v8::IndexedPropertyHandlerConfiguration indexed_property_handler_configuration = {
IndexedPropertyGetterCallback,
{{ "IndexedPropertySetterCallback" if named_property_setter else "nullptr" }},
IndexedPropertyDescriptorCallback,
{{ "IndexedPropertyDeleterCallback" if named_property_deleter else "nullptr" }},
nullptr,
nullptr
};
instance_template->SetHandler(indexed_property_handler_configuration);
}
{% endif %}
{% if indexed_property_getter %}
{
v8::IndexedPropertyHandlerConfiguration indexed_property_handler_configuration = {
IndexedPropertyGetterCallback,
{{ "IndexedPropertySetterCallback" if indexed_property_setter else "nullptr" }},
IndexedPropertyDescriptorCallback,
{{ "IndexedPropertyDeleterCallback" if indexed_property_deleter else "nullptr" }},
IndexedPropertyEnumeratorCallback,
IndexedPropertyDefinerCallback
};
instance_template->SetHandler(indexed_property_handler_configuration);
}
{% endif %}
}
} // namespace
{% if is_global_interface %}
// The global interface is special. Just give them the global object proxy.
v8::Local<v8::Object> {{binding_class}}::CreateWrapper(
v8::Isolate* isolate, const scoped_refptr<Wrappable>&) {
return isolate->GetCurrentContext()->Global();
}
{% else %}
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);
if (!global_environment->HasInterfaceData(kInterfaceUniqueId)) {
InitializeTemplate(isolate);
}
v8::Local<v8::FunctionTemplate> function_template = global_environment->GetInterfaceData(kInterfaceUniqueId);
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);
}
{% endif %}
v8::Local<v8::FunctionTemplate> {{binding_class}}::GetTemplate(v8::Isolate* isolate) {
V8cGlobalEnvironment* global_environment = V8cGlobalEnvironment::GetFromIsolate(isolate);
if (!global_environment->HasInterfaceData(kInterfaceUniqueId)) {
InitializeTemplate(isolate);
}
return global_environment->GetInterfaceData(kInterfaceUniqueId);
}
{% 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) {
TRACE_EVENT0("cobalt::script", "V8cGlobalEnvironment::CreateGlobalObject()");
// 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}}::GetTemplate(isolate_)->InstanceTemplate();
v8::Local<v8::Context> context =
v8::Context::New(isolate_, nullptr, global_object_template);
context_.Reset(isolate_, context);
v8::Context::Scope context_scope(context);
global_wrappable_ = global_interface;
DCHECK(!environment_settings_);
DCHECK(environment_settings);
environment_settings_ = environment_settings;
EvaluateAutomatics();
v8::Local<v8::Object> global_object = context->Global();
new WrapperPrivate(isolate_, global_interface, global_object);
auto actual_global_object = global_object->GetPrototype()->ToObject();
new WrapperPrivate(isolate_, global_interface, actual_global_object);
{% for interface in all_interfaces %}
{% if interface.conditional %}
#if defined({{interface.conditional}})
{% endif %}
wrapper_factory_->RegisterWrappableType(
{{interface.name}}::{{interface.name}}WrappableType(),
base::Bind(V8c{{interface.name}}::CreateWrapper),
base::Bind(V8c{{interface.name}}::GetTemplate));
{% 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 == NewInternalString(isolate, "{{id_value}}")) {
*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 %}