blob: 4958230e73e02a73e629cc63c3e12cb5d156ce0c [file] [log] [blame]
{#
# Copyright 2015 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.
#}
{% extends "interface-base.cc.template" %}
{% block includes %}
#include "third_party/WebKit/Source/JavaScriptCore/config.h"
{{ super() }}
#include "cobalt/script/javascriptcore/constructor_base.h"
#include "cobalt/script/javascriptcore/conversion_helpers.h"
#include "cobalt/script/javascriptcore/prototype_base.h"
#include "cobalt/script/javascriptcore/jsc_callback_function.h"
#include "cobalt/script/javascriptcore/jsc_callback_interface_holder.h"
#include "cobalt/script/javascriptcore/jsc_exception_state.h"
#include "cobalt/script/javascriptcore/jsc_global_environment.h"
#include "cobalt/script/javascriptcore/jsc_global_object.h"
#include "cobalt/script/javascriptcore/jsc_object_handle.h"
#include "cobalt/script/javascriptcore/jsc_object_handle_holder.h"
{% if named_property_getter %}
#include "cobalt/script/javascriptcore/jsc_property_enumerator.h"
{% endif %}
#include "cobalt/script/javascriptcore/type_traits.h"
#include "cobalt/script/javascriptcore/util/binding_helpers.h"
#include "cobalt/script/javascriptcore/util/exception_helpers.h"
#include "third_party/WebKit/Source/JavaScriptCore/interpreter/Interpreter.h"
#include "third_party/WebKit/Source/JavaScriptCore/runtime/Error.h"
{% if is_exception_interface %}
#include "third_party/WebKit/Source/JavaScriptCore/runtime/ErrorPrototype.h"
{% endif %}
#include "third_party/WebKit/Source/JavaScriptCore/runtime/FunctionPrototype.h"
#include "third_party/WebKit/Source/JavaScriptCore/runtime/Identifier.h"
#include "third_party/WebKit/Source/JavaScriptCore/runtime/JSFunction.h"
#include "third_party/WebKit/Source/JavaScriptCore/runtime/JSGlobalObject.h"
#include "third_party/WebKit/Source/JavaScriptCore/runtime/ObjectPrototype.h"
{% endblock includes %}
{% block using_directives %}
{{ super() }}
using cobalt::script::javascriptcore::kConversionFlagNullable;
using cobalt::script::javascriptcore::kConversionFlagRestricted;
using cobalt::script::javascriptcore::kConversionFlagTreatNullAsEmptyString;
using cobalt::script::javascriptcore::kConversionFlagTreatUndefinedAsEmptyString;
using cobalt::script::javascriptcore::kNoConversionFlags;
using cobalt::script::javascriptcore::ConstructorBase;
using cobalt::script::javascriptcore::GetWrappableOrSetException;
using cobalt::script::javascriptcore::FromJSValue;
using cobalt::script::javascriptcore::FromWTFString;
using cobalt::script::javascriptcore::JSCCallbackFunction;
using cobalt::script::javascriptcore::JSCCallbackFunctionHolder;
using cobalt::script::javascriptcore::JSCCallbackInterfaceHolder;
using cobalt::script::javascriptcore::JSCEngine;
using cobalt::script::javascriptcore::JSCExceptionState;
using cobalt::script::javascriptcore::JSCGlobalEnvironment;
using cobalt::script::javascriptcore::JSCGlobalObject;
using cobalt::script::javascriptcore::JSCObjectHandle;
using cobalt::script::javascriptcore::JSCObjectHandleHolder;
{% if named_property_getter %}
using cobalt::script::javascriptcore::JSCPropertyEnumerator;
{% endif %}
using cobalt::script::javascriptcore::JSObjectToWrappable;
using cobalt::script::javascriptcore::PrototypeBase;
using cobalt::script::javascriptcore::ScriptObjectRegistry;
using cobalt::script::javascriptcore::ThreadLocalHashTable;
using cobalt::script::javascriptcore::ToJSValue;
using cobalt::script::javascriptcore::ToWTFString;
using cobalt::script::javascriptcore::TypeTraits;
using cobalt::script::javascriptcore::WrapperBase;
using cobalt::script::javascriptcore::util::HasPropertyOnPrototype;
using cobalt::script::javascriptcore::util::GetStackTrace;
{% 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 %}
JSC::JSValue ToJSValue(JSCGlobalObject*, {{impl_class}}::{{enumeration.name}} in_enum);
void FromJSValue(JSC::ExecState* exec_state, JSC::JSValue jsvalue,
int conversion_flags, JSCExceptionState* exception_state,
{{impl_class}}::{{enumeration.name}}* out_enum);
{% endfor %}
{% endif %}
{% endblock enumeration_declarations %}
{% from 'macros.cc.template' import add_extra_arguments %}
{% from 'macros.cc.template' import call_function %}
{% from 'macros.cc.template' import constructor_implementation with context %}
{% from 'macros.cc.template' import function_implementation with context %}
{% from 'macros.cc.template' import overload_resolution_implementation with context %}
{% from 'macros.cc.template' import set_attribute_implementation with context %}
{% from 'interface-object.template' import create_interface_object with context %}
{% block implementation %}
namespace {
{% for constant in constants %}
JSC::JSValue getJS{{constant.idl_name}}(
JSC::ExecState* exec_state,
JSC::JSValue slot_base,
JSC::PropertyName property_name);
{% endfor %}
{% for attribute in attributes + static_attributes %}
{% if attribute.conditional %}
#if defined({{attribute.conditional}})
{% endif %}
JSC::JSValue getJS{{attribute.idl_name}}(
JSC::ExecState* exec_state,
JSC::JSValue slot_base,
JSC::PropertyName property_name);
{% if attribute.has_setter %}
void setJS{{attribute.idl_name}}(
JSC::ExecState* exec,
JSC::JSObject* this_object,
JSC::JSValue value);
{% endif %}
{% if attribute.conditional %}
#endif // defined({{attribute.conditional}})
{% endif %}
{% endfor %}
{% if constructor %}
JSC::EncodedJSValue constructorJS{{impl_class}}(JSC::ExecState*);
{% for overload in constructor.overloads if constructor.overloads|length > 1 %}
JSC::EncodedJSValue constructorJS{{impl_class}}{{overload.overload_index}}(JSC::ExecState*);
{% endfor %}
{% endif %}
{% for operation in operations + static_operations %}
{% if operation.conditional %}
#if defined({{operation.conditional}})
{% endif %}
{% set boundFunctionPrefix = "staticFunctionJS" if operation.is_static else "functionJS" %}
JSC::EncodedJSValue {{boundFunctionPrefix}}{{operation.idl_name}}(JSC::ExecState*);
{% for overload in operation.overloads if operation.overloads|length > 1 %}
JSC::EncodedJSValue {{boundFunctionPrefix}}{{overload.idl_name}}{{overload.overload_index}}(JSC::ExecState*);
{% endfor %}
{% if operation.conditional %}
#endif // defined({{operation.conditional}})
{% endif %}
{% endfor %}
{% if indexed_property_getter %}
JSC::JSValue IndexedPropertyGetter(JSC::ExecState* exec_state,
JSC::JSValue slot_base, uint32_t index);
{% endif %}
{% if indexed_property_setter %}
void IndexedPropertySetter(JSC::JSCell* cell,
JSC::ExecState* exec_state, uint32_t index, JSC::JSValue value);
{% endif %}
{% if stringifier %}
JSC::EncodedJSValue StringifierJS(JSC::ExecState*);
{% endif %}
// These are declared unconditionally, but only defined if needed by the
// interface.
JSC::JSValue NamedPropertyGetter(JSC::ExecState* exec_state,
JSC::JSValue slot_base, JSC::PropertyName property_name);
void NamedPropertySetter(JSC::JSCell* cell, JSC::ExecState* exec_state,
JSC::PropertyName property_name, JSC::JSValue jsc_value);
bool NamedPropertyDeleter(JSC::JSCell* cell, JSC::ExecState* exec_state,
JSC::PropertyName property_name);
bool QueryNamedProperty(JSC::JSCell* cell, JSC::ExecState* exec_state,
JSC::PropertyName property_name);
JSC::JSValue OnGetMissingProperty(JSC::ExecState* exec_state,
JSC::JSValue slot_base, JSC::PropertyName property_name);
bool OnSetMissingProperty(JSC::JSCell* cell, JSC::ExecState* exec_state,
JSC::PropertyName property_name, JSC::JSValue value);
const bool s_has_named_getter = {{'true' if named_property_getter else 'false'}};
const bool s_has_named_setter = {{'true' if named_property_setter else 'false'}};
#if !defined(COBALT_BUILD_TYPE_GOLD)
const bool s_use_debug_missing_property_handler = {{'true' if not parent_interface else 'false'}};
#else
const bool s_use_debug_missing_property_handler = false;
#endif
{% if get_opaque_root %}
scoped_refptr<Wrappable> GetOpaqueRootFromWrappable(
const scoped_refptr<Wrappable>& wrappable) {
{{impl_class}}* impl =
base::polymorphic_downcast<{{impl_class}}*>(wrappable.get());
Wrappable* opaque_root = impl->{{get_opaque_root}}();
return make_scoped_refptr<Wrappable>(opaque_root);
}
{% endif %}
} // namespace
{% if has_interface_object %}
{{create_interface_object("InterfaceObject", impl_class)}}
{% endif %}
{% if named_constructor %}
{{create_interface_object("NamedInterfaceObject", named_constructor)}}
{% endif %}
{% include "prototype-object.template" %}
const JSC::HashTableValue {{binding_class}}::property_table_values[] = {
{% for attribute in attributes %}
{% if attribute.conditional %}
#if defined({{attribute.conditional}})
{% endif %}
{ "{{attribute.idl_name}}",
JSC::DontDelete {{'| JSC::ReadOnly' if not attribute.has_setter}},
reinterpret_cast<intptr_t>(getJS{{attribute.idl_name}}),
{% if attribute.has_setter %}
reinterpret_cast<intptr_t>(setJS{{attribute.idl_name}}),
{% else %}
0,
{% endif %}
JSC::NoIntrinsic
},
{% if attribute.conditional %}
#endif // defined({{attribute.conditional}})
{% endif %}
{% endfor %}
{% if is_global_interface %}
{% for operation in operations %}
{% if operation.conditional %}
#if defined({{operation.conditional}})
{% endif %}
{ "{{operation.idl_name}}",
JSC::DontDelete | JSC::Function,
reinterpret_cast<intptr_t>(functionJS{{operation.idl_name}}),
static_cast<intptr_t>({{operation.length}}),
JSC::NoIntrinsic
},
{% if operation.conditional %}
#endif // defined({{operation.conditional}})
{% endif %}
{% endfor %}
{% endif %}
{ 0, 0, 0, 0, static_cast<JSC::Intrinsic>(0) }
}; // {{binding_class}}::property_table_values
// static
const JSC::HashTable {{binding_class}}::property_table_prototype = {
{# This doesn't take into account disabled properties, but this is okay. This
value must be at least as large as the number of properties. #}
{% set num_properties = attributes|length %}
{% if is_global_interface %}
{% set num_properties = num_properties + operations|length %}
{% endif %}
{{ calculate_jsc_lookup_size(num_properties) }}, // compactSize
{{ calculate_jsc_lookup_size_mask(num_properties) }}, // compactSizeMask
property_table_values,
NULL // table allocated at runtime
}; // {{binding_class}}::property_table_prototype
// static
const JSC::HashTable* {{binding_class}}::GetPropertyTable(
JSC::ExecState* exec_state) {
return ThreadLocalHashTable::GetInstance()->GetHashTable(
{{binding_class}}::s_classinfo(), property_table_prototype);
}
#ifdef __LB_SHELL__FORCE_LOGGING__
base::LazyInstance<{{binding_class}}::NonTrivialStaticFields>
{{binding_class}}::non_trivial_static_fields = LAZY_INSTANCE_INITIALIZER;
#endif // __LB_SHELL__FORCE_LOGGING__
const JSC::ClassInfo {{binding_class}}::s_info = {
"{{interface_name}}", // className
BaseClass::s_classinfo(), // parentClass
NULL, // static hash-table of properties (not used)
GetPropertyTable, // function pointer to get hash-table of properties
CREATE_METHOD_TABLE({{binding_class}})
}; // {{binding_class}}::s_info
// static
JSC::JSObject* {{binding_class}}::GetPrototype(
JSC::JSGlobalObject* global_object) {
return Prototype::GetInstance(global_object);
}
{% if has_interface_object %}
// static
JSC::JSObject* {{binding_class}}::GetConstructor(
JSC::ExecState* exec_state) {
return InterfaceObject::GetInstance(exec_state);
}
// static
JSC::JSValue {{binding_class}}::Prototype::GetConstructor(
JSC::ExecState* exec_state,
JSC::JSValue slot_base,
JSC::PropertyName property_name) {
return JSC::JSValue(InterfaceObject::GetInstance(exec_state));
}
{% endif %}
{% if named_constructor %}
JSC::JSObject* {{binding_class}}::GetNamedConstructor(
JSC::ExecState* exec_state) {
return NamedInterfaceObject::GetInstance(exec_state);
}
{% endif %}
{% if is_global_interface %}
// static
script::javascriptcore::JSCGlobalObject* {{binding_class}}::Create(
const scoped_refptr<{{impl_class}}>& global_interface,
script::EnvironmentSettings* environment_settings,
JSC::JSGlobalData* global_data,
ScriptObjectRegistry* script_object_registry) {
scoped_ptr<script::javascriptcore::WrapperFactory> wrapper_factory =
make_scoped_ptr(new script::javascriptcore::WrapperFactory());
{% for interface in all_interfaces %}
{% if interface.conditional %}
#if defined({{interface.conditional}})
{% endif %}
{# Don't register a create method for the global interface, since we do not
create a wrapper for it directly. #}
{% if interface.name != impl_class %}
wrapper_factory->RegisterWrappableType(
{{interface.name}}::{{interface.name}}WrappableType(),
JSC{{interface.name}}::s_classinfo(),
JSC{{interface.name}}::GetCreateWrapperFunction());
{% endif %}
{% if interface.conditional %}
#endif // defined({{interface.conditional}})
{% endif %}
{% endfor %}
JSC::JSLockHolder lock(global_data);
JSC::Structure* structure = JSC::Structure::create(
*global_data,
NULL, // JSC::JSGlobalObject*
JSC::jsNull(), // prototype
JSC::TypeInfo(JSC::GlobalObjectType, StructureFlags),
&s_info);
{{binding_class}}* global_wrapper =
new (NotNull, JSC::allocateCell<{{binding_class}}>(global_data->heap))
{{binding_class}}(
global_data,
structure,
script_object_registry,
wrapper_factory.Pass(),
environment_settings,
global_interface);
global_wrapper->finishCreation(*global_data);
global_data->heap.addFinalizer(global_wrapper, {{binding_class}}::destroy);
global_wrapper->setPrototype(
global_wrapper->globalData(),
{{binding_class}}::GetPrototype(global_wrapper));
return global_wrapper;
}
{% else %}
// static
JSC::JSObject* {{binding_class}}::Create(
JSCGlobalObject* global_object,
const scoped_refptr<Wrappable>& wrappable) {
if (!(wrappable->GetWrappableType() == {{impl_class}}::{{impl_class}}WrappableType())) {
NOTREACHED() << "Type of wrappable does not match {{impl_class}}::{{impl_class}}WrappableType()";
return NULL;
}
{{impl_class}}* impl_ptr =
base::polymorphic_downcast<{{impl_class}}*>(wrappable.get());
JSC::JSGlobalData& global_data = global_object->globalData();
// Get or Create the prototype object for this interface.
JSC::JSObject* prototype = Prototype::GetInstance(global_object);
DCHECK(prototype);
JSC::JSLockHolder lock(global_data);
// Create a JSC::Structure object for this instance.
{% if is_exception_interface %}
JSC::TypeInfo type_info(JSC::ErrorInstanceType, StructureFlags);
{% else %}
JSC::TypeInfo type_info(JSC::ObjectType, StructureFlags);
{% endif %}
JSC::Structure* structure = JSC::Structure::create(
global_data,
global_object,
JSC::JSValue(prototype),
type_info,
&s_info);
// Instantiate a new garbage-collected wrapper object.
{{binding_class}}* wrapper =
new (NotNull, JSC::allocateCell<{{binding_class}}>(global_data.heap))
{{binding_class}}(
&global_data,
structure,
global_object->script_object_registry(),
make_scoped_refptr(impl_ptr));
wrapper->finishCreation(global_data);
{% if is_exception_interface %}
global_data.heap.addFinalizer(wrapper, destroy);
{% endif %}
return wrapper;
}
{% endif %}
{{binding_class}}::{{binding_class}}(
JSC::JSGlobalData* global_data,
JSC::Structure* structure,
ScriptObjectRegistry* script_object_registry,
{% if is_global_interface %}
scoped_ptr<script::javascriptcore::WrapperFactory> wrapper_factory,
script::EnvironmentSettings* environment_settings,
{% endif %}
const scoped_refptr<{{impl_class}}>& impl)
: BaseClass(global_data, structure, script_object_registry, impl{% if is_global_interface %},
wrapper_factory.Pass(), environment_settings{% endif %}) {
{% if get_opaque_root %}
set_get_opaque_root_function(base::Bind(&GetOpaqueRootFromWrappable));
{% endif %}
}
void {{binding_class}}::finishCreation(JSC::JSGlobalData& global_data) {
{% if is_exception_interface %}
WTF::String error_message = ToWTFString(wrappable()->message());
BaseClass::finishCreation(global_data, error_message);
{% else %}
BaseClass::finishCreation(global_data);
{% endif %}
DCHECK(inherits(&s_info));
}
{{binding_class}}::~{{binding_class}}() {
// Empty destructor
}
{% if add_opaque_roots %}
void {{binding_class}}::visitChildren(JSC::JSCell* cell, JSC::SlotVisitor& visitor) {
WrapperBase<JSC::JSDestructibleObject, Wrappable>::visitChildren(
cell, visitor);
JSCGlobalObject* global_object = JSC::jsCast<JSCGlobalObject*>(
JSC::jsCast<JSObject*>(cell)->globalObject());
{{impl_class}}* impl = base::polymorphic_downcast<{{impl_class}}*>(
JSC::jsCast<WrapperBase*>(cell)->wrappable().get());
{% for opaque_root in add_opaque_roots %}
Wrappable* opaque_root{{loop.index0}} = impl->{{opaque_root}}();
if (opaque_root{{loop.index0}}) {
visitor.addOpaqueRoot(opaque_root{{loop.index0}});
}
{% endfor %}
}
{% endif %}
// Look up property slot for querying property values.
bool {{binding_class}}::getOwnPropertySlot(JSC::JSCell* cell,
JSC::ExecState* exec, JSC::PropertyName property_name,
JSC::PropertySlot& slot) {
{{binding_class}}* this_object = JSC::jsCast<{{binding_class}}*>(cell);
ASSERT_GC_OBJECT_INHERITS(this_object, &s_info);
{% if is_global_interface %}
// Global interface may have both operations and properties as own properties
// so we cannot use getStaticValueSlot.
bool found_property_slot = JSC::getStaticPropertySlot<{{binding_class}}, BaseClass>(
exec, GetPropertyTable(exec), this_object, property_name, slot);
{% else %}
bool found_property_slot = JSC::getStaticValueSlot<{{binding_class}}, BaseClass>(
exec, GetPropertyTable(exec), this_object, property_name, slot);
{% endif %}
if (s_has_named_getter || s_use_debug_missing_property_handler) {
bool found_property_on_prototype_chain = false;
if (!found_property_slot && cell->isObject()) {
JSC::JSValue prototype_value = JSC::asObject(cell)->prototype();
if (prototype_value.isObject()) {
JSC::JSObject* prototype = JSC::asObject(prototype_value);
found_property_on_prototype_chain =
prototype->hasProperty(exec, property_name);
}
}
if (s_has_named_getter) {
if (!found_property_slot && !found_property_on_prototype_chain) {
if (QueryNamedProperty(this_object, exec, property_name)) {
slot.setCustom(cell, &NamedPropertyGetter);
found_property_slot = true;
}
}
}
if (s_use_debug_missing_property_handler) {
// The property was not found as an own-property, nor was it found on the
// prototype chain, so set the missing property handler to be called
// when getting this property value.
if (!found_property_slot && !found_property_on_prototype_chain) {
slot.setCustom(cell, &OnGetMissingProperty);
found_property_slot = true;
}
}
}
return found_property_slot;
}
{% if indexed_property_getter or named_property_getter %}
// static
bool {{binding_class}}::getOwnPropertySlotByIndex(JSC::JSCell* cell,
JSC::ExecState* exec_state, uint32_t index, JSC::PropertySlot& slot) {
{{impl_class}}* impl =
GetWrappableOrSetException<{{impl_class}}>(exec_state, cell);
if (!impl) {
return false;
}
{% if indexed_property_getter %}
if (index < impl->length()) {
slot.setCustomIndex(cell, index, IndexedPropertyGetter);
return true;
}
{% endif %}
if (s_has_named_getter) {
{{binding_class}}* this_object = JSC::jsCast<{{binding_class}}*>(cell);
JSC::PropertyName property_name = JSC::Identifier::from(exec_state, index);
bool has_property = HasOwnPropertyOrPrototypeProperty(
cell, exec_state, property_name);
if (!has_property) {
if (QueryNamedProperty(this_object, exec_state, property_name)) {
slot.setCustom(cell, &NamedPropertyGetter);
return true;
}
}
}
return Base::getOwnPropertySlotByIndex(cell, exec_state, index, slot);
}
void {{binding_class}}::getOwnPropertyNames(JSC::JSObject* object,
JSC::ExecState* exec_state, JSC::PropertyNameArray& property_names,
JSC::EnumerationMode mode) {
{{impl_class}}* impl =
GetWrappableOrSetException<{{impl_class}}>(exec_state, object);
if (impl) {
{% if indexed_property_getter %}
for (uint32 i = 0; i < impl->length(); ++i) {
property_names.add(JSC::Identifier::from(exec_state, i));
}
{% endif %}
{% if named_property_getter %}
JSCPropertyEnumerator enumerator(exec_state, &property_names);
impl->EnumerateNamedProperties(&enumerator);
{% endif %}
Base::getOwnPropertyNames(object, exec_state, property_names, mode);
}
}
{% endif %}
// Look up property slot and put the |value|.
void {{binding_class}}::put(JSC::JSCell* cell, JSC::ExecState* exec,
JSC::PropertyName property_name, JSC::JSValue value,
JSC::PutPropertySlot& slot) {
{{binding_class}}* this_object = JSC::jsCast<{{binding_class}}*>(cell);
ASSERT_GC_OBJECT_INHERITS(this_object, &s_info);
bool property_handled = false;
if (s_has_named_setter || s_use_debug_missing_property_handler) {
// Need to look up the property manually.
bool has_property = HasOwnPropertyOrPrototypeProperty(
cell, exec, property_name);
if (s_has_named_setter) {
// We didn't find the property on the object or prototype chain, so
// set or create a new named property.
if (!has_property) {
std::string property_name_utf8 = FromWTFString(property_name.publicName());
NamedPropertySetter(cell, exec, property_name, value);
property_handled = true;
}
}
if (s_use_debug_missing_property_handler) {
if (!has_property && !property_handled) {
property_handled = OnSetMissingProperty(cell, exec, property_name, value);
}
}
{% if not is_global_interface and not parent_interface %}
#ifdef __LB_SHELL__FORCE_LOGGING__
std::string property_name_utf8 = FromWTFString(property_name.publicName());
base::AutoLock lock(non_trivial_static_fields.Get().lock_);
base::hash_set<std::string>& properties_warned_about =
non_trivial_static_fields.Get().properties_warned_about;
if (properties_warned_about.find(property_name_utf8) ==
properties_warned_about.end()) {
properties_warned_about.insert(property_name_utf8);
WTF::String class_name = cell->className();
DLOG_IF(WARNING, !has_property) << "Did not find property named " <<
property_name_utf8 << " to set on wrapper for "
<< FromWTFString(class_name)
<< std::endl << StackTraceToString(GetStackTrace(exec, 32))
<< std::endl;
}
#endif // __LB_SHELL__FORCE_LOGGING__
{% endif %}
}
if (!property_handled) {
JSC::lookupPut<{{binding_class}}, BaseClass>(
exec, property_name, value, GetPropertyTable(exec), this_object, slot);
}
}
{% if indexed_property_setter or named_property_setter %}
// static
void {{binding_class}}::putByIndex(JSC::JSCell* cell,
JSC::ExecState* exec_state, uint32_t index, JSC::JSValue value,
bool should_throw) {
{{impl_class}}* impl =
GetWrappableOrSetException<{{impl_class}}>(exec_state, cell);
if (impl) {
bool property_handled = false;
{% if indexed_property_setter %}
if (index < impl->length()) {
IndexedPropertySetter(cell, exec_state, index, value);
property_handled = true;
}
{% endif %}
if (s_has_named_setter) {
if (!property_handled) {
JSC::PropertyName property_name = JSC::Identifier::from(exec_state, index);
bool has_property = HasOwnPropertyOrPrototypeProperty(
cell, exec_state, property_name);
if (!has_property) {
NamedPropertySetter(cell, exec_state, property_name, value);
property_handled = true;
}
}
}
if (!property_handled) {
Base::putByIndex(cell, exec_state, index, value, should_throw);
}
}
}
{% endif %}
{% if supports_named_properties %}
bool {{binding_class}}::deleteProperty(JSC::JSCell* cell,
JSC::ExecState* exec_state,
JSC::PropertyName property_name) {
TRACE_EVENT1("{{binding_class}}", "deleteProperty", "property",
TRACE_STR_COPY(WTF::String(property_name.publicName()).utf8().data()));
{{impl_class}}* impl =
GetWrappableOrSetException<{{impl_class}}>(exec_state, cell);
if (impl) {
bool has_property = HasOwnPropertyOrPrototypeProperty(
cell, exec_state, property_name);
if (!has_property &&
QueryNamedProperty(cell, exec_state, property_name)) {
return NamedPropertyDeleter(cell, exec_state, property_name);
}
return Base::deleteProperty(cell, exec_state, property_name);
}
return false;
}
{% endif %}
{% if supports_named_properties or supports_indexed_properties %}
bool {{binding_class}}::deletePropertyByIndex(JSC::JSCell* cell,
JSC::ExecState* exec_state,
uint32_t index) {
TRACE_EVENT0("{{binding_class}}", "deletePropertyByIndex");
{{impl_class}}* impl =
GetWrappableOrSetException<{{impl_class}}>(exec_state, cell);
if (impl) {
{% if supports_indexed_properties %}
// https://heycam.github.io/webidl/#delete
// Return true if index is not a supported property index.
return index >= impl->length();
{% elif supports_named_properties %}
JSC::PropertyName property_name = JSC::Identifier::from(exec_state, index);
bool has_property = HasOwnPropertyOrPrototypeProperty(
cell, exec_state, property_name);
if (!has_property &&
QueryNamedProperty(cell, exec_state, property_name)) {
return NamedPropertyDeleter(cell, exec_state, property_name);
}
return Base::deletePropertyByIndex(cell, exec_state, index);
{% endif %}
}
return false;
}
{% endif %}
bool {{binding_class}}::HasOwnPropertyOrPrototypeProperty(
JSC::JSCell* cell, JSC::ExecState* exec_state,
JSC::PropertyName property_name) {
{{binding_class}}* this_object = JSC::jsCast<{{binding_class}}*>(cell);
JSC::PropertySlot lookup_slot;
bool has_property = JSC::getStaticPropertySlot<{{binding_class}}, BaseClass>(
exec_state, GetPropertyTable(exec_state), this_object, property_name,
lookup_slot);
return has_property || HasPropertyOnPrototype(exec_state, cell, property_name);
}
namespace {
{% for constant in constants %}
JSC::JSValue getJS{{constant.idl_name}}(
JSC::ExecState* exec_state, JSC::JSValue, JSC::PropertyName) {
TRACE_EVENT0("{{binding_class}}", "get {{constant.idl_name}}");
{% if constant.can_use_compile_assert %}
COMPILE_ASSERT({{impl_class}}::{{constant.name}} == {{constant.value}},
ValueFor{{impl_class}}_{{constant.name}}DoesNotMatchIDL);
{% else %}
DCHECK_EQ({{constant.value}}, {{impl_class}}::{{constant.name}}) <<
"The value for {{impl_class}}::{{constant.name}} does not match "
"the value in the interface definition.";
{% endif %}
// JSCGlobalObject* is only needed for non-primitive types.
return ToJSValue(NULL, {{constant.value}});
}
{% endfor %}
{% for attribute in attributes + static_attributes %}
{% if attribute.conditional %}
#if defined({{attribute.conditional}})
{% endif %}
JSC::JSValue getJS{{attribute.idl_name}}(
JSC::ExecState* exec_state,
JSC::JSValue slot_base,
JSC::PropertyName property_name) {
TRACE_EVENT0("{{binding_class}}", "get {{attribute.idl_name}}");
JSCGlobalObject* global_object =
JSC::jsCast<JSCGlobalObject*>(exec_state->lexicalGlobalObject());
{% if not attribute.is_static %}
{{impl_class}}* impl =
GetWrappableOrSetException<{{impl_class}}>(exec_state, slot_base);
if (!impl) {
return exec_state->exception();
}
{% endif %}
{% if attribute.raises_exception %}
JSCExceptionState exception_state(global_object);
{% endif %}
{% if attribute.is_named_constructor_attribute %}
JSC::JSObject* constructor_object =
JSC{{attribute.interface_name}}::GetNamedConstructor(
global_object->globalExec());
DCHECK(constructor_object)
<< "NULL constructor returned for {{attribute.interface_name}}.";
return JSC::JSValue(constructor_object);
{% elif attribute.is_constructor_attribute %}
JSC::JSObject* constructor_object =
JSC{{attribute.interface_name}}::GetConstructor(
global_object->globalExec());
DCHECK(constructor_object)
<< "NULL constructor returned for {{attribute.interface_name}}.";
return JSC::JSValue(constructor_object);
{% else %}
{% call(arguments_list) add_extra_arguments('global_object', [], attribute) %}
JSC::JSValue result = ToJSValue(
global_object,
{{ call_function("impl", impl_class, attribute.getter_function_name, arguments_list, attribute.is_static) -}});
{% if attribute.raises_exception %}
if (exception_state.is_exception_set()) {
return JSC::throwError(exec_state, exception_state.exception_object());
}
{% endif %}
return result;
{% endcall %}
{% endif %}
}
{% if attribute.has_setter %}
void setJS{{attribute.idl_name}}(
JSC::ExecState* exec_state,
JSC::JSObject* this_object,
JSC::JSValue value) {
TRACE_EVENT0("{{binding_class}}", "set {{attribute.idl_name}}");
JSCGlobalObject* global_object =
JSC::jsCast<JSCGlobalObject*>(exec_state->lexicalGlobalObject());
JSCExceptionState exception_state(global_object);
{% if not attribute.is_static %}
{{impl_class}}* impl =
GetWrappableOrSetException<{{impl_class}}>(exec_state, this_object);
if (!impl) {
return;
}
{% endif %}
{{ set_attribute_implementation(attribute, impl_class, "impl") }}
}
{% endif %}
{% if attribute.conditional %}
#endif // defined({{attribute.conditional}})
{% endif %}
{% endfor %}
{% if constructor %}
JSC::EncodedJSValue constructorJS{{impl_class}}(JSC::ExecState* exec_state) {
{% if constructor.overloads|length == 1 %}
{{constructor_implementation(constructor.overloads[0])}}
{% else %}
{{overload_resolution_implementation(constructor, 'constructorJS' + impl_class)}}
{% endif %}
}
{% for overload in constructor.overloads if constructor.overloads|length > 1 %}
JSC::EncodedJSValue constructorJS{{impl_class}}{{overload.overload_index}}(JSC::ExecState* exec_state) {
{{constructor_implementation(overload)}}
}
{% endfor %}
{% endif %}
{% for operation in operations + static_operations %}
{% if operation.conditional %}
#if defined({{operation.conditional}})
{% endif %}
{% set boundFunctionPrefix = "staticFunctionJS" if operation.is_static else "functionJS" %}
JSC::EncodedJSValue {{boundFunctionPrefix}}{{operation.idl_name}}(
JSC::ExecState* exec_state) {
TRACE_EVENT0("{{binding_class}}", "call {{operation.idl_name}}");
{% if operation.overloads|length == 1 %}
{{function_implementation(operation.overloads[0])}}
{% else %}
{{overload_resolution_implementation(operation, boundFunctionPrefix + operation.idl_name)}}
{% endif %}
}
{% for overload in operation.overloads if operation.overloads|length > 1 %}
JSC::EncodedJSValue {{boundFunctionPrefix}}{{operation.idl_name}}{{overload.overload_index}}(
JSC::ExecState* exec_state) {
{{function_implementation(overload)}}
}
{% endfor %}
{% if operation.conditional %}
#endif // defined({{operation.conditional}})
{% endif %}
{% endfor %}
{% if indexed_property_getter %}
JSC::JSValue IndexedPropertyGetter(JSC::ExecState* exec_state,
JSC::JSValue slot_base, uint32_t index) {
TRACE_EVENT0("{{binding_class}}", "IndexedPropertyGetter");
{{impl_class}}* impl =
GetWrappableOrSetException<{{impl_class}}>(exec_state, slot_base);
if (!impl) {
return exec_state->exception();
}
JSCGlobalObject* global_object =
JSC::jsCast<JSCGlobalObject*>(exec_state->lexicalGlobalObject());
JSCExceptionState exception_state(global_object);
{% call(arguments_list)
add_extra_arguments('global_object', ['index'], indexed_property_getter) %}
JSC::JSValue result = ToJSValue(
global_object,
{{ call_function("impl", impl_class, indexed_property_getter.name,
arguments_list, False) -}});
{% if indexed_property_getter.raises_exception %}
if (exception_state.is_exception_set()) {
return JSC::throwError(exec_state, exception_state.exception_object());
}
{% endif %}
return result;
{% endcall %}
}
{% endif %}
{% if indexed_property_setter %}
void IndexedPropertySetter(JSC::JSCell* cell,
JSC::ExecState* exec_state, uint32_t index, JSC::JSValue jsc_value) {
TRACE_EVENT0("{{binding_class}}", "IndexedPropertySetter");
{{impl_class}}* impl =
GetWrappableOrSetException<{{impl_class}}>(exec_state, cell);
if (!impl) {
return;
}
JSCGlobalObject* global_object =
JSC::jsCast<JSCGlobalObject*>(exec_state->lexicalGlobalObject());
JSCExceptionState exception_state(global_object);
{{indexed_property_setter.type}} value;
FromJSValue(exec_state, jsc_value,
{{indexed_property_setter.conversion_flags}},
&exception_state, &value);
if (exception_state.is_exception_set()) {
JSC::throwError(exec_state, exception_state.exception_object());
return;
}
{% call(arguments_list) add_extra_arguments(
'global_object', ['index', 'value'], indexed_property_setter) %}
{{ call_function("impl", impl_class, indexed_property_setter.name,
arguments_list, False) -}};
{% if indexed_property_setter.raises_exception %}
if (exception_state.is_exception_set()) {
JSC::throwError(exec_state, exception_state.exception_object());
}
{% endif %}
{% endcall %}
}
{% endif %}
{% if named_property_getter %}
JSC::JSValue NamedPropertyGetter(JSC::ExecState* exec_state,
JSC::JSValue slot_base, JSC::PropertyName property_name) {
TRACE_EVENT0("{{binding_class}}", "NamedPropertyGetter");
{{impl_class}}* impl =
GetWrappableOrSetException<{{impl_class}}>(exec_state, slot_base);
if (!impl) {
return exec_state->exception();
}
JSCGlobalObject* global_object =
JSC::jsCast<JSCGlobalObject*>(exec_state->lexicalGlobalObject());
JSCExceptionState exception_state(global_object);
std::string property_name_utf8 = FromWTFString(property_name.publicName());
{% call(arguments_list) add_extra_arguments('global_object', ['property_name_utf8'], named_property_getter) %}
JSC::JSValue result = ToJSValue(
global_object,
{{ call_function("impl", impl_class, named_property_getter.name, arguments_list, False) -}});
{% if named_property_getter.raises_exception %}
if (exception_state.is_exception_set()) {
return JSC::throwError(exec_state, exception_state.exception_object());
}
{% endif %}
return result;
{% endcall %}
}
bool QueryNamedProperty(JSC::JSCell* cell, JSC::ExecState* exec_state,
JSC::PropertyName property_name) {
{{impl_class}}* impl =
GetWrappableOrSetException<{{impl_class}}>(exec_state, cell);
if (!impl) {
return false;
}
std::string property_name_utf8 = FromWTFString(property_name.publicName());
return impl->CanQueryNamedProperty(property_name_utf8);
}
{% else %}
JSC::JSValue NamedPropertyGetter(JSC::ExecState* exec_state,
JSC::JSValue slot_base, JSC::PropertyName property_name) {
NOTREACHED();
return JSC::jsUndefined();
}
bool QueryNamedProperty(JSC::JSCell* cell, JSC::ExecState* exec_state,
JSC::PropertyName property_name) {
NOTREACHED();
return false;
}
{% endif %}
{% if named_property_setter %}
void NamedPropertySetter(JSC::JSCell* cell, JSC::ExecState* exec_state,
JSC::PropertyName property_name, JSC::JSValue jsc_value) {
TRACE_EVENT0("{{binding_class}}", "NamedPropertySetter");
{{impl_class}}* impl =
GetWrappableOrSetException<{{impl_class}}>(exec_state, cell);
if (!impl) {
return;
}
JSCGlobalObject* global_object =
JSC::jsCast<JSCGlobalObject*>(exec_state->lexicalGlobalObject());
JSCExceptionState exception_state(global_object);
std::string property_name_utf8 = FromWTFString(property_name.publicName());
{{named_property_setter.type}} value;
FromJSValue(exec_state, jsc_value,
{{named_property_setter.conversion_flags}},
&exception_state, &value);
if (exception_state.is_exception_set()) {
JSC::throwError(exec_state, exception_state.exception_object());
return;
}
{% call(arguments_list) add_extra_arguments(
'global_object', ['property_name_utf8', 'value'], named_property_setter) %}
{{ call_function(
"impl", impl_class, named_property_setter.name, arguments_list, False) -}};
{% if named_property_setter.raises_exception %}
if (exception_state.is_exception_set()) {
JSC::throwError(exec_state, exception_state.exception_object());
}
{% endif %}
{% endcall %}
}
{% else %}
void NamedPropertySetter(JSC::JSCell* cell, JSC::ExecState* exec_state,
JSC::PropertyName property_name, JSC::JSValue jsc_value) {
NOTREACHED();
}
{% endif %}
bool NamedPropertyDeleter(JSC::JSCell* cell, JSC::ExecState* exec_state,
JSC::PropertyName property_name) {
{% if named_property_deleter %}
{{impl_class}}* impl =
GetWrappableOrSetException<{{impl_class}}>(exec_state, cell);
if (impl) {
std::string property_name_utf8 = FromWTFString(property_name.publicName());
impl->{{named_property_deleter.name}}(property_name_utf8);
return true;
}
{% endif %}
return false;
}
{% if stringifier %}
JSC::EncodedJSValue StringifierJS(JSC::ExecState* exec_state) {
JSC::JSObject* this_object =
exec_state->hostThisValue().toThisObject(exec_state);
{{impl_class}}* impl =
GetWrappableOrSetException<{{impl_class}}>(exec_state, this_object);
if (!impl) {
return JSC::JSValue::encode(exec_state->exception());
}
JSCGlobalObject* global_object =
JSC::jsCast<JSCGlobalObject*>(exec_state->lexicalGlobalObject());
JSC::JSValue result = ToJSValue(global_object, impl->{{stringifier.name}}());
return JSC::JSValue::encode(result);
}
{% endif %}
#if !defined(COBALT_BUILD_TYPE_GOLD)
JSC::JSValue OnGetMissingProperty(JSC::ExecState* exec_state,
JSC::JSValue slot_base, JSC::PropertyName property_name) {
JSCGlobalObject* global_object =
JSC::jsCast<JSCGlobalObject*>(exec_state->lexicalGlobalObject());
JSC::JSValue callable = global_object->get(
exec_state, JSC::Identifier(exec_state, "__onGetMissingProperty"));
if (!callable.isUndefined()) {
JSC::CallData call_data;
JSC::CallType call_type = JSC::getCallData(callable, call_data);
if (call_type != JSC::CallTypeNone) {
// The function called __onGetMissingProperty exists, so call this and
// return the result as the value for this property.
JSC::MarkedArgumentBuffer args;
args.append(slot_base);
args.append(JSC::JSValue(
JSC::JSString::create(
global_object->globalData(), property_name.publicName())));
JSC::JSValue retval = JSC::call(
exec_state, callable, call_type, call_data, global_object, args);
return retval;
}
}
return JSC::jsUndefined();
}
bool OnSetMissingProperty(JSC::JSCell* cell, JSC::ExecState* exec_state,
JSC::PropertyName property_name, JSC::JSValue value) {
JSCGlobalObject* global_object =
JSC::jsCast<JSCGlobalObject*>(exec_state->lexicalGlobalObject());
JSC::JSValue callable = global_object->get(
exec_state, JSC::Identifier(exec_state, "__onSetMissingProperty"));
if (!callable.isUndefined()) {
JSC::CallData call_data;
JSC::CallType call_type = JSC::getCallData(callable, call_data);
if (call_type != JSC::CallTypeNone) {
// The function called __onSetMissingProperty exists, so call this with
// the value to be set. The missing property handler returns true if it
// has handled the setting of this property.
JSC::MarkedArgumentBuffer args;
args.append(cell);
args.append(JSC::JSValue(
JSC::JSString::create(
global_object->globalData(), property_name.publicName())));
args.append(value);
JSC::JSValue retval = JSC::call(
exec_state, callable, call_type, call_data, global_object, args);
return retval.toBoolean(exec_state);
}
}
return false;
}
#else
JSC::JSValue OnGetMissingProperty(JSC::ExecState* exec_state,
JSC::JSValue slot_base, JSC::PropertyName property_name) {
NOTREACHED();
return JSC::jsUndefined();
}
bool OnSetMissingProperty(JSC::JSCell* cell, JSC::ExecState* exec_state,
JSC::PropertyName property_name, JSC::JSValue value) {
NOTREACHED();
return false;
}
#endif
} // namespace
{% endblock implementation %}
{% block create_global_object_impl %}
JSCGlobalEnvironment* jsc_global_environment =
base::polymorphic_downcast<JSCGlobalEnvironment*>(this);
JSCEngine* jsc_engine = jsc_global_environment->engine();
JSCGlobalObject* global_object = {{binding_class}}::Create(
global_interface, environment_settings,
jsc_engine->global_data(), jsc_engine->script_object_registry());
jsc_global_environment->SetGlobalObject(global_object);
{% endblock create_global_object_impl %}
{% block enumeration_definitions %}
{% for enumeration in enumerations %}
JSC::JSValue ToJSValue(JSCGlobalObject* global_object, {{impl_class}}::{{enumeration.name}} in_enum) {
JSC::JSGlobalData* global_data = &(global_object->globalData());
switch (in_enum) {
{% for value, idl_value in enumeration.value_pairs %}
case {{impl_class}}::{{value}}: return JSC::jsString(global_data, "{{idl_value}}");
{% endfor %}
default:
NOTREACHED();
return JSC::jsUndefined();
}
}
void FromJSValue(JSC::ExecState* exec_state, JSC::JSValue jsvalue,
int conversion_flags, JSCExceptionState* exception_state,
{{impl_class}}::{{enumeration.name}}* out_enum) {
DCHECK_EQ(0, conversion_flags) << "Unexpected conversion flags.";
// JSValue -> IDL enum algorithm described here:
// http://heycam.github.io/webidl/#es-enumeration
// 1. Let S be the result of calling ToString(V).
JSC::JSString* js_string = jsvalue.toString(exec_state);
if (exec_state->hadException()) {
DLOG(WARNING) << "Exception converting value to string";
return;
}
const WTF::String& wtf_string = js_string->tryGetValue();
// 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 (wtf_string == "{{idl_value}}") {
*out_enum = {{impl_class}}::{{value}};
}{% endfor %} else {
// 2. If S is not one of E's enumeration values, then throw a TypeError.
JSC::throwTypeError(exec_state);
}
}
{% endfor %}
{% endblock enumeration_definitions %}