| {% extends 'interface_base.cc.tmpl' %} |
| |
| {% from 'methods.cc.tmpl' import runtime_timer_scope, runtime_timer_scope_disabled_by_default %} |
| |
| {##############################################################################} |
| {% block indexed_property_getter %} |
| {% if indexed_property_getter and not indexed_property_getter.is_custom %} |
| {% set getter = indexed_property_getter %} |
| static void indexedPropertyGetter(uint32_t index, const v8::PropertyCallbackInfo<v8::Value>& info) { |
| {% if getter.is_raises_exception %} |
| ExceptionState exceptionState(info.GetIsolate(), ExceptionState::kIndexedGetterContext, "{{interface_name}}"); |
| {% endif %} |
| |
| {{cpp_class}}* impl = {{v8_class}}::ToImpl(info.Holder()); |
| |
| // We assume that all the implementations support length() method, although |
| // the spec doesn't require that length() must exist. It's okay that |
| // the interface does not have length attribute as long as the |
| // implementation supports length() member function. |
| if (index >= impl->length()) |
| return; // Returns undefined due to out-of-range. |
| |
| {% set getter_name = getter.name or 'AnonymousIndexedGetter' %} |
| {% set getter_arguments = ['index'] %} |
| {% if getter.is_call_with_script_state %} |
| ScriptState* scriptState = ScriptState::ForRelevantRealm(info); |
| {% set getter_arguments = ['scriptState'] + getter_arguments %} |
| {% endif %} |
| {% if getter.is_raises_exception %} |
| {% set getter_arguments = getter_arguments + ['exceptionState'] %} |
| {% endif %} |
| {{getter.cpp_type}} result = impl->{{getter_name}}({{getter_arguments | join(', ')}}); |
| {{getter.v8_set_return_value}}; |
| } |
| |
| {% endif %} |
| {% endblock %} |
| |
| |
| {##############################################################################} |
| {% block indexed_property_getter_callback %} |
| {% if indexed_property_getter or named_property_getter %} |
| {% set getter = indexed_property_getter or named_property_getter %} |
| void {{v8_class_or_partial}}::indexedPropertyGetterCallback(uint32_t index, const v8::PropertyCallbackInfo<v8::Value>& info) { |
| {{ runtime_timer_scope_disabled_by_default(runtime_call_stats.indexed_property_getter_counter) }} |
| {% if indexed_property_getter %} |
| |
| {% if getter.is_custom %} |
| {{v8_class}}::indexedPropertyGetterCustom(index, info); |
| {% else %} |
| {{cpp_class}}V8Internal::indexedPropertyGetter(index, info); |
| {% endif %} |
| |
| {% else %}{# otherwise, named property #} |
| |
| const AtomicString& propertyName = AtomicString::Number(index); |
| |
| {% if getter.is_custom %} |
| {{v8_class}}::namedPropertyGetterCustom(propertyName, info); |
| {% else %} |
| {{cpp_class}}V8Internal::namedPropertyGetter(propertyName, info); |
| {% endif %} |
| |
| {% endif %}{# indexed_property_getter #} |
| } |
| |
| {% endif %} |
| {% endblock %} |
| |
| |
| {##############################################################################} |
| {% block indexed_property_setter %} |
| {% from 'utilities.cc.tmpl' import v8_value_to_local_cpp_value %} |
| {% if indexed_property_setter and not indexed_property_setter.is_custom %} |
| {% set setter = indexed_property_setter %} |
| static void indexedPropertySetter(uint32_t index, v8::Local<v8::Value> v8Value, const v8::PropertyCallbackInfo<v8::Value>& info) { |
| {% if setter.has_exception_state %} |
| ExceptionState exceptionState(info.GetIsolate(), ExceptionState::kIndexedSetterContext, "{{interface_name}}"); |
| {% endif %} |
| {% if setter.is_ce_reactions %} |
| CEReactionsScope ce_reactions_scope; |
| {% endif %} |
| |
| {{cpp_class}}* impl = {{v8_class}}::ToImpl(info.Holder()); |
| {{v8_value_to_local_cpp_value(setter) | trim | indent(2)}} |
| {% if setter.has_type_checking_interface %} |
| {# Type checking for interface types (if interface not implemented, throw |
| TypeError), per http://www.w3.org/TR/WebIDL/#es-interface #} |
| if (!propertyValue{% if setter.is_nullable %} && !IsUndefinedOrNull(v8Value){% endif %}) { |
| exceptionState.ThrowTypeError("The provided value is not of type '{{setter.idl_type}}'."); |
| return; |
| } |
| {% endif %} |
| |
| {% set setter_name = setter.name or 'AnonymousIndexedSetter' %} |
| {% set setter_arguments = ['index', 'propertyValue'] %} |
| {% if setter.is_call_with_script_state %} |
| ScriptState* scriptState = ScriptState::ForRelevantRealm(info); |
| {% set setter_arguments = ['scriptState'] + setter_arguments %} |
| {% endif %} |
| {% if setter.is_raises_exception %} |
| {% set setter_arguments = setter_arguments + ['exceptionState'] %} |
| {% endif %} |
| bool result = impl->{{setter_name}}({{setter_arguments | join(', ')}}); |
| {% if setter.is_raises_exception %} |
| if (exceptionState.HadException()) |
| return; |
| {% endif %} |
| if (!result) |
| return; |
| V8SetReturnValue(info, v8Value); |
| } |
| |
| {% endif %} |
| {% endblock %} |
| |
| |
| {##############################################################################} |
| {% block indexed_property_setter_callback %} |
| {% if indexed_property_getter or named_property_setter %} |
| {% set setter = indexed_property_setter or named_property_setter %} |
| void {{v8_class_or_partial}}::indexedPropertySetterCallback(uint32_t index, v8::Local<v8::Value> v8Value, const v8::PropertyCallbackInfo<v8::Value>& info) { |
| {% if indexed_property_setter %} |
| |
| {% if setter.is_custom %} |
| {{v8_class}}::indexedPropertySetterCustom(index, v8Value, info); |
| {% else %} |
| {{cpp_class}}V8Internal::indexedPropertySetter(index, v8Value, info); |
| {% endif %} |
| |
| {% elif named_property_setter %} |
| |
| const AtomicString& propertyName = AtomicString::Number(index); |
| |
| {% if setter.is_custom %} |
| {{v8_class}}::namedPropertySetterCustom(propertyName, v8Value, info); |
| {% else %} |
| {{cpp_class}}V8Internal::namedPropertySetter(propertyName, v8Value, info); |
| {% endif %} |
| |
| {% else %}{# neither of indexed_property_setter nor named_property_setter #} |
| |
| // No indexed property setter defined. Do not fall back to the default |
| // setter. |
| V8SetReturnValue(info, v8::Null(info.GetIsolate())); |
| if (info.ShouldThrowOnError()) { |
| ExceptionState exceptionState(info.GetIsolate(), |
| ExceptionState::kIndexedSetterContext, |
| "{{interface_name}}"); |
| {% if setter.is_ce_reactions %} |
| CEReactionsScope ce_reactions_scope; |
| {% endif %} |
| exceptionState.ThrowTypeError("Index property setter is not supported."); |
| } |
| |
| {% endif %}{# indexed/named_property_setter #} |
| } |
| |
| {% endif %} |
| {% endblock %} |
| |
| |
| {##############################################################################} |
| {% block indexed_property_descriptor %} |
| {% if indexed_property_getter %} |
| static void indexedPropertyDescriptor(uint32_t index, const v8::PropertyCallbackInfo<v8::Value>& info) { |
| // https://heycam.github.io/webidl/#LegacyPlatformObjectGetOwnProperty |
| // Steps 1.1 to 1.2.4 are covered here: we rely on indexedPropertyGetter() to |
| // call the getter function and check that |index| is a valid property index, |
| // in which case it will have set info.GetReturnValue() to something other |
| // than undefined. |
| {{v8_class_or_partial}}::indexedPropertyGetterCallback(index, info); |
| v8::Local<v8::Value> getterValue = info.GetReturnValue().Get(); |
| if (!getterValue->IsUndefined()) { |
| // 1.2.5. Let |desc| be a newly created Property Descriptor with no fields. |
| // 1.2.6. Set desc.[[Value]] to the result of converting value to an |
| // ECMAScript value. |
| // 1.2.7. If O implements an interface with an indexed property setter, |
| // then set desc.[[Writable]] to true, otherwise set it to false. |
| v8::PropertyDescriptor desc(getterValue, {% if indexed_property_setter %}true{% else %}false{% endif %}); |
| // 1.2.8. Set desc.[[Enumerable]] and desc.[[Configurable]] to true. |
| desc.set_enumerable(true); |
| desc.set_configurable(true); |
| // 1.2.9. Return |desc|. |
| V8SetReturnValue(info, desc); |
| } |
| } |
| |
| {% endif %} |
| {% endblock %} |
| |
| |
| {##############################################################################} |
| {% block named_property_descriptor %} |
| {% if not indexed_property_getter and named_property_getter %} |
| static void namedPropertyDescriptor(uint32_t index, const v8::PropertyCallbackInfo<v8::Value>& info) { |
| // This function is called when an IDL interface supports named properties |
| // but not indexed properties. When a numeric property is queried, V8 calls |
| // indexedPropertyDescriptorCallback(), which calls this function. |
| |
| {% if named_property_getter.is_enumerable %} |
| // Since we initialize our indexed and named property handlers differently |
| // (the former use descriptors and definers, the latter uses a query |
| // callback), we need to inefficiently call the query callback and convert |
| // the v8::PropertyAttribute integer it returns into a v8::PropertyDescriptor |
| // expected by a descriptor callback. |
| // TODO(rakuco): remove this hack once we switch named property handlers to |
| // using descriptor and definer callbacks (bug 764633). |
| const AtomicString& indexAsName = AtomicString::Number(index); |
| {% if named_property_getter.is_custom_property_query %} |
| {{v8_class}}::namedPropertyQueryCustom(indexAsName, info); |
| {% else %} |
| {{cpp_class}}V8Internal::namedPropertyQuery(indexAsName, info); |
| {% endif %} |
| v8::Local<v8::Value> getterValue = info.GetReturnValue().Get(); |
| if (!getterValue->IsUndefined()) { |
| DCHECK(getterValue->IsInt32()); |
| const int32_t props = |
| getterValue->ToInt32(info.GetIsolate()->GetCurrentContext()) |
| .ToLocalChecked() |
| ->Value(); |
| v8::PropertyDescriptor desc(V8String(info.GetIsolate(), indexAsName), |
| !(props & v8::ReadOnly)); |
| desc.set_enumerable(!(props & v8::DontEnum)); |
| desc.set_configurable(!(props & v8::DontDelete)); |
| V8SetReturnValue(info, desc); |
| } |
| {% else %}{# TODO(rakuco): drop this once we remove [NotEnumerable] getters #} |
| // This IDL interface defines a [NotEnumerable] getter. We need to do |
| // something similar to indexedPropertyDescriptor(): call |
| // indexedPropertyGetterCallback, let it end up calling the named property |
| // getter and, if all goes well, we create a v8::PropertyDescriptor with the |
| // right values. |
| {{v8_class_or_partial}}::indexedPropertyGetterCallback(index, info); |
| v8::Local<v8::Value> getterValue = info.GetReturnValue().Get(); |
| if (!getterValue->IsUndefined()) { |
| v8::PropertyDescriptor desc(getterValue, {% if named_property_setter %}true{% else %}false{% endif %}); |
| desc.set_enumerable(false); |
| desc.set_configurable(true); |
| V8SetReturnValue(info, desc); |
| } |
| {% endif %} |
| } |
| |
| {% endif %} |
| {% endblock %} |
| |
| |
| {##############################################################################} |
| {% block indexed_property_descriptor_callback %} |
| {% if indexed_property_getter or named_property_getter %} |
| void {{v8_class_or_partial}}::indexedPropertyDescriptorCallback(uint32_t index, const v8::PropertyCallbackInfo<v8::Value>& info) { |
| {% if indexed_property_getter %} |
| {{cpp_class}}V8Internal::indexedPropertyDescriptor(index, info); |
| {% else %}{# The interface only supports named properties. #} |
| {{cpp_class}}V8Internal::namedPropertyDescriptor(index, info); |
| {% endif %}{# indexed_property_getter #} |
| } |
| |
| {% endif %} |
| {% endblock %} |
| |
| |
| {##############################################################################} |
| {% block indexed_property_deleter %} |
| {% if indexed_property_deleter and not indexed_property_deleter.is_custom %} |
| {% set deleter = indexed_property_deleter %} |
| static void indexedPropertyDeleter(uint32_t index, const v8::PropertyCallbackInfo<v8::Boolean>& info) { |
| {% if deleter.is_raises_exception %} |
| ExceptionState exceptionState(info.GetIsolate(), ExceptionState::kIndexedDeletionContext, "{{interface_name}}"); |
| {% endif %} |
| {% if deleter.is_ce_reactions %} |
| CEReactionsScope ce_reactions_scope; |
| {% endif %} |
| |
| {{cpp_class}}* impl = {{v8_class}}::ToImpl(info.Holder()); |
| |
| {% set deleter_name = deleter.name or 'AnonymousIndexedDeleter' %} |
| {% set deleter_arguments = ['index'] %} |
| {% if deleter.is_call_with_script_state %} |
| ScriptState* scriptState = ScriptState::ForRelevantRealm(info); |
| {% set deleter_arguments = ['scriptState'] + deleter_arguments %} |
| {% endif %} |
| {% if deleter.is_raises_exception %} |
| {% set deleter_arguments = deleter_arguments + ['exceptionState'] %} |
| {% endif %} |
| DeleteResult result = impl->{{deleter_name}}({{deleter_arguments | join(', ')}}); |
| {% if deleter.is_raises_exception %} |
| if (exceptionState.HadException()) |
| return; |
| {% endif %} |
| if (result == kDeleteUnknownProperty) |
| return; |
| V8SetReturnValue(info, result == kDeleteSuccess); |
| } |
| |
| {% endif %} |
| {% endblock %} |
| |
| |
| {##############################################################################} |
| {% block indexed_property_deleter_callback %} |
| {% if indexed_property_deleter or named_property_deleter %} |
| {% set deleter = indexed_property_deleter or named_property_deleter %} |
| void {{v8_class_or_partial}}::indexedPropertyDeleterCallback(uint32_t index, const v8::PropertyCallbackInfo<v8::Boolean>& info) { |
| {% if indexed_property_deleter %} |
| |
| {% if deleter.is_custom %} |
| {{v8_class}}::indexedPropertyDeleterCustom(index, info); |
| {% else %} |
| {{cpp_class}}V8Internal::indexedPropertyDeleter(index, info); |
| {% endif %} |
| |
| {% else %}{# otherwise, named property #} |
| |
| const AtomicString& propertyName = AtomicString::Number(index); |
| |
| {% if deleter.is_custom %} |
| {{v8_class}}::namedPropertyDeleterCustom(propertyName, info); |
| {% else %} |
| {{cpp_class}}V8Internal::namedPropertyDeleter(propertyName, info); |
| {% endif %} |
| |
| {% endif %}{# indexed_property_deleter #} |
| } |
| |
| {% endif %} |
| {% endblock %} |
| |
| |
| {##############################################################################} |
| {% block indexed_property_definer_callback %} |
| {% if indexed_property_getter %} |
| void {{v8_class_or_partial}}::indexedPropertyDefinerCallback( |
| uint32_t index, |
| const v8::PropertyDescriptor& desc, |
| const v8::PropertyCallbackInfo<v8::Value>& info) { |
| {% if indexed_property_setter %} |
| // https://heycam.github.io/webidl/#legacy-platform-object-defineownproperty |
| // 3.9.3. [[DefineOwnProperty]] |
| // step 1.1. If the result of calling IsDataDescriptor(Desc) is false, then |
| // return false. |
| if (desc.has_get() || desc.has_set()) { |
| V8SetReturnValue(info, v8::Null(info.GetIsolate())); |
| if (info.ShouldThrowOnError()) { |
| ExceptionState exceptionState(info.GetIsolate(), |
| ExceptionState::kIndexedSetterContext, |
| "{{interface_name}}"); |
| exceptionState.ThrowTypeError("Accessor properties are not allowed."); |
| } |
| return; |
| } |
| |
| // Return nothing and fall back to indexedPropertySetterCallback. |
| {% else %}{# indexed_property_setter #} |
| // https://heycam.github.io/webidl/#legacy-platform-object-defineownproperty |
| // 3.9.3. [[DefineOwnProperty]] |
| // step 1.2. If O does not implement an interface with an indexed property |
| // setter, then return false. |
| // |
| // https://html.spec.whatwg.org/C/window-object.html#windowproxy-defineownproperty |
| // 7.4.6 [[DefineOwnProperty]] (P, Desc) |
| // step 2.1. If P is an array index property name, return false. |
| V8SetReturnValue(info, v8::Null(info.GetIsolate())); |
| if (info.ShouldThrowOnError()) { |
| ExceptionState exceptionState(info.GetIsolate(), |
| ExceptionState::kIndexedSetterContext, |
| "{{interface_name}}"); |
| exceptionState.ThrowTypeError("Index property setter is not supported."); |
| } |
| {% endif %}{# indexed_property_setter #} |
| } |
| |
| {% endif %}{# indexed_property_getter #} |
| {% endblock %} |
| |
| |
| {##############################################################################} |
| {% block named_property_getter %} |
| {% if named_property_getter and not named_property_getter.is_custom %} |
| {% set getter = named_property_getter %} |
| static void namedPropertyGetter(const AtomicString& name, const v8::PropertyCallbackInfo<v8::Value>& info) { |
| {% if getter.is_raises_exception %} |
| const CString& nameInUtf8 = name.Utf8(); |
| ExceptionState exceptionState(info.GetIsolate(), ExceptionState::kGetterContext, "{{interface_name}}", nameInUtf8.data()); |
| {% endif %} |
| {% if getter.is_call_with_script_state %} |
| ScriptState* scriptState = ScriptState::ForRelevantRealm(info); |
| {% endif %} |
| |
| {{cpp_class}}* impl = {{v8_class}}::ToImpl(info.Holder()); |
| {% if getter.use_output_parameter_for_result %} |
| {{getter.cpp_type}} result; |
| {{getter.cpp_value}}; |
| {% else %} |
| {{getter.cpp_type}} result = {{getter.cpp_value}}; |
| {% endif %} |
| if ({{getter.is_null_expression}}) |
| return; |
| {{getter.v8_set_return_value}}; |
| } |
| |
| {% endif %} |
| {% endblock %} |
| |
| |
| {##############################################################################} |
| {% block named_property_getter_callback %} |
| {% if named_property_getter %} |
| {% set getter = named_property_getter %} |
| void {{v8_class_or_partial}}::namedPropertyGetterCallback(v8::Local<v8::Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) { |
| {{ runtime_timer_scope_disabled_by_default(runtime_call_stats.named_property_getter_counter) }} |
| if (!name->IsString()) |
| return; |
| const AtomicString& propertyName = ToCoreAtomicString(name.As<v8::String>()); |
| |
| {% if getter.is_custom %} |
| {{v8_class}}::namedPropertyGetterCustom(propertyName, info); |
| {% else %} |
| {{cpp_class}}V8Internal::namedPropertyGetter(propertyName, info); |
| {% endif %} |
| } |
| |
| {% endif %} |
| {% endblock %} |
| |
| |
| {##############################################################################} |
| {% block named_property_setter %} |
| {% from 'utilities.cc.tmpl' import v8_value_to_local_cpp_value %} |
| {% if named_property_setter and not named_property_setter.is_custom %} |
| {% set setter = named_property_setter %} |
| static void namedPropertySetter(const AtomicString& name, v8::Local<v8::Value> v8Value, const v8::PropertyCallbackInfo<v8::Value>& info) { |
| {% if setter.has_exception_state %} |
| const CString& nameInUtf8 = name.Utf8(); |
| ExceptionState exceptionState(info.GetIsolate(), ExceptionState::kSetterContext, "{{interface_name}}", nameInUtf8.data()); |
| {% endif %} |
| {% if setter.is_ce_reactions %} |
| CEReactionsScope ce_reactions_scope; |
| {% endif %} |
| {% if setter.is_call_with_script_state %} |
| ScriptState* scriptState = ScriptState::ForRelevantRealm(info); |
| {% endif %} |
| |
| {{cpp_class}}* impl = {{v8_class}}::ToImpl(info.Holder()); |
| {{v8_value_to_local_cpp_value(setter) | trim | indent(2)}} |
| {% if setter.has_type_checking_interface %} |
| {# Type checking for interface types (if interface not implemented, throw |
| TypeError), per http://www.w3.org/TR/WebIDL/#es-interface #} |
| if (!propertyValue{% if setter.is_nullable %} && !IsUndefinedOrNull(v8Value){% endif %}) { |
| exceptionState.ThrowTypeError("The provided value is not of type '{{setter.idl_type}}'."); |
| return; |
| } |
| {% endif %} |
| |
| {% set setter_name = setter.name or 'AnonymousNamedSetter' %} |
| {% set setter_arguments = ['name', 'propertyValue'] %} |
| {% if setter.is_call_with_script_state %} |
| {% set setter_arguments = ['scriptState'] + setter_arguments %} |
| {% endif %} |
| {% if setter.is_raises_exception %} |
| {% set setter_arguments = setter_arguments + ['exceptionState'] %} |
| {% endif %} |
| bool result = impl->{{setter_name}}({{setter_arguments | join(', ')}}); |
| {% if setter.is_raises_exception %} |
| if (exceptionState.HadException()) |
| return; |
| {% endif %} |
| if (!result) |
| return; |
| V8SetReturnValue(info, v8Value); |
| } |
| |
| {% endif %} |
| {% endblock %} |
| |
| |
| {##############################################################################} |
| {% block named_property_setter_callback %} |
| {% if named_property_setter %} |
| {% set setter = named_property_setter %} |
| void {{v8_class_or_partial}}::namedPropertySetterCallback(v8::Local<v8::Name> name, v8::Local<v8::Value> v8Value, const v8::PropertyCallbackInfo<v8::Value>& info) { |
| {{ runtime_timer_scope_disabled_by_default(runtime_call_stats.named_property_setter_counter) }} |
| if (!name->IsString()) |
| return; |
| const AtomicString& propertyName = ToCoreAtomicString(name.As<v8::String>()); |
| |
| {% if setter.is_custom %} |
| {{v8_class}}::namedPropertySetterCustom(propertyName, v8Value, info); |
| {% else %} |
| {{cpp_class}}V8Internal::namedPropertySetter(propertyName, v8Value, info); |
| {% endif %} |
| } |
| |
| {% endif %} |
| {% endblock %} |
| |
| |
| {##############################################################################} |
| {% block named_property_deleter %} |
| {% if named_property_deleter and not named_property_deleter.is_custom %} |
| {% set deleter = named_property_deleter %} |
| static void namedPropertyDeleter(const AtomicString& name, const v8::PropertyCallbackInfo<v8::Boolean>& info) { |
| {% if deleter.is_raises_exception %} |
| const CString& nameInUtf8 = name.Utf8(); |
| ExceptionState exceptionState(info.GetIsolate(), ExceptionState::kDeletionContext, "{{interface_name}}", nameInUtf8.data()); |
| {% endif %} |
| {% if deleter.is_ce_reactions %} |
| CEReactionsScope ce_reactions_scope; |
| {% endif %} |
| {% if deleter.is_call_with_script_state %} |
| ScriptState* scriptState = ScriptState::ForRelevantRealm(info); |
| {% endif %} |
| |
| {{cpp_class}}* impl = {{v8_class}}::ToImpl(info.Holder()); |
| |
| {% set deleter_name = deleter.name or 'AnonymousNamedDeleter' %} |
| {% set deleter_arguments = ['name'] %} |
| {% if deleter.is_call_with_script_state %} |
| {% set deleter_arguments = ['scriptState'] + deleter_arguments %} |
| {% endif %} |
| {% if deleter.is_raises_exception %} |
| {% set deleter_arguments = deleter_arguments + ['exceptionState'] %} |
| {% endif %} |
| DeleteResult result = impl->{{deleter_name}}({{deleter_arguments | join(', ')}}); |
| {% if deleter.is_raises_exception %} |
| if (exceptionState.HadException()) |
| return; |
| {% endif %} |
| if (result == kDeleteUnknownProperty) |
| return; |
| V8SetReturnValue(info, result == kDeleteSuccess); |
| } |
| |
| {% endif %} |
| {% endblock %} |
| |
| |
| {##############################################################################} |
| {% block named_property_deleter_callback %} |
| {% if named_property_deleter %} |
| {% set deleter = named_property_deleter %} |
| void {{v8_class_or_partial}}::namedPropertyDeleterCallback(v8::Local<v8::Name> name, const v8::PropertyCallbackInfo<v8::Boolean>& info) { |
| if (!name->IsString()) |
| return; |
| const AtomicString& propertyName = ToCoreAtomicString(name.As<v8::String>()); |
| |
| {% if deleter.is_custom %} |
| {{v8_class}}::namedPropertyDeleterCustom(propertyName, info); |
| {% else %} |
| {{cpp_class}}V8Internal::namedPropertyDeleter(propertyName, info); |
| {% endif %} |
| } |
| |
| {% endif %} |
| {% endblock %} |
| |
| |
| {##############################################################################} |
| {% block named_property_query %} |
| {% if named_property_getter and named_property_getter.is_enumerable and |
| not named_property_getter.is_custom_property_query %} |
| {% set getter = named_property_getter %} |
| {# If there is an enumerator, there MUST be a query method to properly |
| communicate property attributes. #} |
| {% if indexed_property_getter %} |
| static void namedPropertyQuery(const AtomicString& name, const v8::PropertyCallbackInfo<v8::Integer>& info) { |
| {% else %} |
| {# If we do not have an indexed property getter, this function is called #} |
| {# from namedPropertyDescriptor(), whose v8::PropertyCallbackInfo has a #} |
| {# v8::Value instead of a v8::Integer. We use this template trick to make #} |
| {# the compiler accept the call. #} |
| {# TODO(rakuco): remove this hack once we switch named property handlers to #} |
| {# using descriptor and definer callbacks (bug 764633). #} |
| template <typename T> |
| static void namedPropertyQuery(const AtomicString& name, const v8::PropertyCallbackInfo<T>& info) { |
| {% endif %} |
| const CString& nameInUtf8 = name.Utf8(); |
| ExceptionState exceptionState(info.GetIsolate(), ExceptionState::kGetterContext, "{{interface_name}}", nameInUtf8.data()); |
| {% if getter.is_call_with_script_state %} |
| ScriptState* scriptState = ScriptState::ForRelevantRealm(info); |
| {% endif %} |
| |
| {{cpp_class}}* impl = {{v8_class}}::ToImpl(info.Holder()); |
| |
| {% set getter_arguments = ['name', 'exceptionState'] %} |
| {% if getter.is_call_with_script_state %} |
| {% set getter_arguments = ['scriptState'] + getter_arguments %} |
| {% endif %} |
| bool result = impl->NamedPropertyQuery({{getter_arguments | join(', ')}}); |
| if (!result) |
| return; |
| // https://heycam.github.io/webidl/#LegacyPlatformObjectGetOwnProperty |
| // 2.7. If |O| implements an interface with a named property setter, then set |
| // desc.[[Writable]] to true, otherwise set it to false. |
| // 2.8. If |O| implements an interface with the |
| // [LegacyUnenumerableNamedProperties] extended attribute, then set |
| // desc.[[Enumerable]] to false, otherwise set it to true. |
| {% if named_property_setter %} |
| {% set desc_properties = ['v8::None'] %} |
| {% else %} |
| {% set desc_properties = ['v8::ReadOnly'] %} |
| {% endif %} |
| {% if has_legacy_unenumerable_named_properties %} |
| {% set desc_properties = ['v8::DontEnum'] + desc_properties %} |
| {% endif %} |
| V8SetReturnValueInt(info, {{desc_properties | join(' | ')}}); |
| } |
| |
| {% endif %} |
| {% endblock %} |
| |
| |
| {##############################################################################} |
| {% block named_property_query_callback %} |
| {% if named_property_getter and named_property_getter.is_enumerable %} |
| {% set getter = named_property_getter %} |
| void {{v8_class_or_partial}}::namedPropertyQueryCallback(v8::Local<v8::Name> name, const v8::PropertyCallbackInfo<v8::Integer>& info) { |
| {{ runtime_timer_scope_disabled_by_default(runtime_call_stats.named_property_query_counter) }} |
| if (!name->IsString()) |
| return; |
| const AtomicString& propertyName = ToCoreAtomicString(name.As<v8::String>()); |
| |
| {% if getter.is_custom_property_query %} |
| {{v8_class}}::namedPropertyQueryCustom(propertyName, info); |
| {% else %} |
| {{cpp_class}}V8Internal::namedPropertyQuery(propertyName, info); |
| {% endif %} |
| } |
| |
| {% endif %} |
| {% endblock %} |
| |
| |
| {##############################################################################} |
| {% block named_property_enumerator %} |
| {% if named_property_getter and named_property_getter.is_enumerable and |
| not named_property_getter.is_custom_property_enumerator %} |
| static void namedPropertyEnumerator(const v8::PropertyCallbackInfo<v8::Array>& info) { |
| ExceptionState exceptionState(info.GetIsolate(), ExceptionState::kEnumerationContext, "{{interface_name}}"); |
| |
| {{cpp_class}}* impl = {{v8_class}}::ToImpl(info.Holder()); |
| |
| Vector<String> names; |
| impl->NamedPropertyEnumerator(names, exceptionState); |
| if (exceptionState.HadException()) |
| return; |
| V8SetReturnValue(info, ToV8(names, info.Holder(), info.GetIsolate()).As<v8::Array>()); |
| } |
| |
| {% endif %} |
| {% endblock %} |
| |
| |
| {##############################################################################} |
| {% block named_property_enumerator_callback %} |
| {% if named_property_getter and named_property_getter.is_enumerable %} |
| {% set getter = named_property_getter %} |
| void {{v8_class_or_partial}}::namedPropertyEnumeratorCallback(const v8::PropertyCallbackInfo<v8::Array>& info) { |
| {% if getter.is_custom_property_enumerator %} |
| {{v8_class}}::namedPropertyEnumeratorCustom(info); |
| {% else %} |
| {{cpp_class}}V8Internal::namedPropertyEnumerator(info); |
| {% endif %} |
| } |
| |
| {% endif %} |
| {% endblock %} |
| |
| |
| {##############################################################################} |
| {# TODO(dcheng): Currently, bindings must create a function object for each |
| realm as a hack to support the incumbent realm. Remove this when Blink |
| properly supports the incumbent realm. #} |
| {% block origin_safe_method_setter %} |
| {% if has_origin_safe_method_setter %} |
| static void {{cpp_class}}OriginSafeMethodSetter(v8::Local<v8::Name> name, v8::Local<v8::Value> v8Value, const v8::PropertyCallbackInfo<void>& info) { |
| if (!name->IsString()) |
| return; |
| v8::Local<v8::Object> holder = {{v8_class}}::findInstanceInPrototypeChain(info.Holder(), info.GetIsolate()); |
| if (holder.IsEmpty()) |
| return; |
| {{cpp_class}}* impl = {{v8_class}}::ToImpl(holder); |
| v8::String::Utf8Value methodName(info.GetIsolate(), name); |
| ExceptionState exceptionState(info.GetIsolate(), ExceptionState::kSetterContext, "{{interface_name}}", *methodName); |
| if (!BindingSecurity::ShouldAllowAccessTo(CurrentDOMWindow(info.GetIsolate()), impl, exceptionState)) { |
| return; |
| } |
| |
| {# The findInstanceInPrototypeChain() call above only returns a non-empty handle if info.Holder() is an Object. #} |
| {% raw %} |
| // |methodName| must be same with {{method.name}} in |
| // {{method.name}}OriginSafeMethodGetter{{world_suffix}} defined in |
| // methods.cc.tmpl |
| {% endraw %} |
| V8PrivateProperty::GetSymbol(info.GetIsolate(), *methodName) |
| .Set(v8::Local<v8::Object>::Cast(info.Holder()), v8Value); |
| } |
| {% endif %} |
| {% endblock %} |
| |
| {% block origin_safe_method_setter_callback %} |
| {% if has_origin_safe_method_setter %} |
| void {{v8_class_or_partial}}::{{cpp_class}}OriginSafeMethodSetterCallback(v8::Local<v8::Name> name, v8::Local<v8::Value> v8Value, const v8::PropertyCallbackInfo<void>& info) { |
| {{cpp_class}}V8Internal::{{cpp_class}}OriginSafeMethodSetter(name, v8Value, info); |
| } |
| {% endif %} |
| {% endblock %} |
| |
| |
| {##############################################################################} |
| {% block named_constructor %} |
| {% from 'methods.cc.tmpl' import generate_constructor with context %} |
| {% if named_constructor %} |
| {% set active_scriptwrappable_inheritance = |
| 'kInheritFromActiveScriptWrappable' |
| if active_scriptwrappable else |
| 'kNotInheritFromActiveScriptWrappable' %} |
| // Suppress warning: global constructors, because struct WrapperTypeInfo is trivial |
| // and does not depend on another global objects. |
| #if defined(COMPONENT_BUILD) && defined(WIN32) && defined(__clang__) |
| #pragma clang diagnostic push |
| #pragma clang diagnostic ignored "-Wglobal-constructors" |
| #endif |
| const WrapperTypeInfo {{v8_class}}Constructor::wrapperTypeInfo = { |
| gin::kEmbedderBlink, |
| {{v8_class}}Constructor::domTemplate, |
| {{install_conditional_features_func or 'nullptr'}}, |
| "{{interface_name}}", |
| nullptr, |
| WrapperTypeInfo::kWrapperTypeObjectPrototype, |
| WrapperTypeInfo::{{wrapper_class_id}}, |
| WrapperTypeInfo::{{active_scriptwrappable_inheritance}}, |
| }; |
| #if defined(COMPONENT_BUILD) && defined(WIN32) && defined(__clang__) |
| #pragma clang diagnostic pop |
| #endif |
| |
| {{generate_constructor(named_constructor)}} |
| v8::Local<v8::FunctionTemplate> {{v8_class}}Constructor::domTemplate(v8::Isolate* isolate, const DOMWrapperWorld& world) { |
| static int domTemplateKey; // This address is used for a key to look up the dom template. |
| V8PerIsolateData* data = V8PerIsolateData::From(isolate); |
| v8::Local<v8::FunctionTemplate> result = data->FindInterfaceTemplate(world, &domTemplateKey); |
| if (!result.IsEmpty()) |
| return result; |
| |
| result = v8::FunctionTemplate::New(isolate, {{v8_class}}ConstructorCallback); |
| v8::Local<v8::ObjectTemplate> instanceTemplate = result->InstanceTemplate(); |
| instanceTemplate->SetInternalFieldCount({{v8_class}}::internalFieldCount); |
| result->SetClassName(V8AtomicString(isolate, "{{named_constructor.name}}")); |
| result->Inherit({{v8_class}}::domTemplate(isolate, world)); |
| data->SetInterfaceTemplate(world, &domTemplateKey, result); |
| return result; |
| } |
| |
| void {{v8_class}}Constructor::NamedConstructorAttributeGetter( |
| v8::Local<v8::Name> propertyName, |
| const v8::PropertyCallbackInfo<v8::Value>& info) { |
| v8::Local<v8::Context> creationContext = info.Holder()->CreationContext(); |
| V8PerContextData* perContextData = V8PerContextData::From(creationContext); |
| if (!perContextData) { |
| // TODO(yukishiino): Return a valid named constructor even after the context is detached |
| return; |
| } |
| |
| v8::Local<v8::Function> namedConstructor = perContextData->ConstructorForType(&{{v8_class}}Constructor::wrapperTypeInfo); |
| |
| // Set the prototype of named constructors to the regular constructor. |
| auto privateProperty = V8PrivateProperty::GetNamedConstructorInitialized(info.GetIsolate()); |
| v8::Local<v8::Context> currentContext = info.GetIsolate()->GetCurrentContext(); |
| v8::Local<v8::Value> privateValue; |
| |
| if (!privateProperty.GetOrUndefined(namedConstructor).ToLocal(&privateValue) || privateValue->IsUndefined()) { |
| v8::Local<v8::Function> interface = perContextData->ConstructorForType(&{{v8_class}}::wrapperTypeInfo); |
| v8::Local<v8::Value> interfacePrototype = interface->Get(currentContext, V8AtomicString(info.GetIsolate(), "prototype")).ToLocalChecked(); |
| bool result = namedConstructor->Set(currentContext, V8AtomicString(info.GetIsolate(), "prototype"), interfacePrototype).ToChecked(); |
| if (!result) |
| return; |
| privateProperty.Set(namedConstructor, v8::True(info.GetIsolate())); |
| } |
| |
| V8SetReturnValue(info, namedConstructor); |
| } |
| |
| {% endif %} |
| {% endblock %} |
| |
| {##############################################################################} |
| {% block overloaded_constructor %} |
| {% if constructor_overloads %} |
| static void constructor(const v8::FunctionCallbackInfo<v8::Value>& info) { |
| ExceptionState exceptionState(info.GetIsolate(), ExceptionState::kConstructionContext, "{{interface_name}}"); |
| {# This follows the overload resolution algorithm. #} |
| {# https://heycam.github.io/webidl/#dfn-overload-resolution-algorithm #} |
| {# 3. Initialize argcount to be min(maxarg, n). #} |
| switch (std::min({{constructor_overloads.maxarg}}, info.Length())) { |
| {# 4. Remove from S all entries whose type list is not of length argcount. #} |
| {% for length, tests_constructors in constructor_overloads.length_tests_methods %} |
| {# 12. If i = d, then: #} |
| case {{length}}: |
| {# Then resolve by testing argument #} |
| {% for test, constructor in tests_constructors %} |
| if ({{test}}) { |
| {{cpp_class}}V8Internal::constructor{{constructor.overload_index}}(info); |
| return; |
| } |
| {% if "exceptionState" in test %} |
| if (exceptionState.HadException()) { |
| exceptionState.RethrowV8Exception(exceptionState.GetException()); |
| return; |
| } |
| {% endif %} |
| {% endfor %} |
| break; |
| {% endfor %} |
| default: |
| {# Invalid arity, throw error #} |
| {# Report full list of valid arities if gaps and above minimum #} |
| {% if constructor_overloads.valid_arities %} |
| if (info.Length() >= {{constructor_overloads.length}}) { |
| exceptionState.ThrowTypeError(ExceptionMessages::InvalidArity("{{constructor_overloads.valid_arities}}", info.Length())); |
| return; |
| } |
| {% endif %} |
| {# Otherwise just report "not enough arguments" #} |
| exceptionState.ThrowTypeError(ExceptionMessages::NotEnoughArguments({{constructor_overloads.length}}, info.Length())); |
| return; |
| } |
| {# No match, throw error #} |
| exceptionState.ThrowTypeError("No matching constructor signature."); |
| } |
| |
| {% endif %} |
| {% endblock %} |
| |
| |
| {##############################################################################} |
| {% block constructor_callback %} |
| {% if constructors or has_custom_constructor or has_html_constructor %} |
| void {{v8_class}}::constructorCallback(const v8::FunctionCallbackInfo<v8::Value>& info) { |
| {{ runtime_timer_scope_disabled_by_default(runtime_call_stats.constructor_counter) }} |
| {% if measure_as %} |
| UseCounter::Count(CurrentExecutionContext(info.GetIsolate()), WebFeature::k{{measure_as('Constructor')}}); |
| {% endif %} |
| if (!info.IsConstructCall()) { |
| V8ThrowException::ThrowTypeError(info.GetIsolate(), ExceptionMessages::ConstructorNotCallableAsFunction("{{interface_name}}")); |
| return; |
| } |
| |
| if (ConstructorMode::Current(info.GetIsolate()) == ConstructorMode::kWrapExistingObject) { |
| V8SetReturnValue(info, info.Holder()); |
| return; |
| } |
| |
| {% if has_custom_constructor %} |
| {{v8_class}}::constructorCustom(info); |
| {% elif has_html_constructor %} |
| V8HTMLConstructor::HtmlConstructor(info, {{v8_class}}::wrapperTypeInfo, HTMLElementType::k{{interface_name}}); |
| {% else %} |
| {{cpp_class}}V8Internal::constructor(info); |
| {% endif %} |
| } |
| |
| {% endif %} |
| {% endblock %} |
| |
| |
| {##############################################################################} |
| {% macro install_origin_safe_method(method, instance_template, prototype_template) %} |
| {% from 'utilities.cc.tmpl' import property_location %} |
| {# TODO(dcheng): Currently, bindings must create a function object for each |
| realm as a hack to support the incumbent realm. Clean this up when Blink |
| properly supports the incumbent realm. #} |
| {% set getter_callback = |
| '%s::%sOriginSafeMethodGetterCallback' % |
| (v8_class_or_partial, method.name) %} |
| {% set setter_callback = |
| '%s::%sOriginSafeMethodSetterCallback' % (v8_class_or_partial, cpp_class) |
| if not method.is_unforgeable else 'nullptr' %} |
| {% set property_attribute = |
| 'static_cast<v8::PropertyAttribute>(%s)' % |
| ' | '.join(method.property_attributes or ['v8::None']) %} |
| {% set holder_check = 'V8DOMConfiguration::kCheckHolder' %} |
| static const V8DOMConfiguration::AttributeConfiguration {{method.name}}OriginSafeAttributeConfiguration[] = { |
| {% if method.is_per_world_bindings %} |
| {% set getter_callback_for_main_world = '%sForMainWorld' % getter_callback %} |
| {% set setter_callback_for_main_world = '%sForMainWorld' % setter_callback |
| if not method.is_unforgeable else 'nullptr' %} |
| {"{{method.name}}", {{getter_callback_for_main_world}}, {{setter_callback_for_main_world}}, {{property_attribute}}, {{property_location(method)}}, {{holder_check}}, V8DOMConfiguration::kHasSideEffect, V8DOMConfiguration::kAlwaysCallGetter, V8DOMConfiguration::MainWorld}, |
| {"{{method.name}}", {{getter_callback}}, {{setter_callback}}, {{property_attribute}}, {{property_location(method)}}, {{holder_check}}, V8DOMConfiguration::kHasSideEffect, V8DOMConfiguration::kAlwaysCallGetter, V8DOMConfiguration::NonMainWorlds}} |
| {% else %} |
| {"{{method.name}}", {{getter_callback}}, {{setter_callback}}, {{property_attribute}}, {{property_location(method)}}, {{holder_check}}, V8DOMConfiguration::kHasSideEffect, V8DOMConfiguration::kAlwaysCallGetter, V8DOMConfiguration::kAllWorlds} |
| {% endif %} |
| }; |
| for (const auto& attributeConfig : {{method.name}}OriginSafeAttributeConfiguration) |
| V8DOMConfiguration::InstallAttribute(isolate, world, {{instance_template}}, {{prototype_template}}, attributeConfig); |
| {%- endmacro %} |
| |
| |
| {##############################################################################} |
| {% macro install_indexed_property_handler(target) %} |
| {% set indexed_property_getter_callback = |
| '%s::indexedPropertyGetterCallback' % v8_class_or_partial %} |
| {% set indexed_property_setter_callback = |
| '%s::indexedPropertySetterCallback' % v8_class_or_partial |
| if indexed_property_getter or named_property_setter else 'nullptr' %} |
| {% set indexed_property_descriptor_callback = |
| '%s::indexedPropertyDescriptorCallback' % v8_class_or_partial |
| if indexed_property_getter or named_property_getter else 'nullptr' %} |
| {% set indexed_property_deleter_callback = |
| '%s::indexedPropertyDeleterCallback' % v8_class_or_partial |
| if indexed_property_deleter or named_property_deleter else 'nullptr' %} |
| {% set indexed_property_enumerator_callback = |
| 'IndexedPropertyEnumerator<%s>' % cpp_class |
| if indexed_property_getter.is_enumerable else 'nullptr' %} |
| {% set indexed_property_definer_callback = |
| '%s::indexedPropertyDefinerCallback' % v8_class_or_partial |
| if indexed_property_getter else 'nullptr' %} |
| {% set property_handler_flags = |
| 'v8::PropertyHandlerFlags::kHasNoSideEffect' |
| if indexed_property_getter.has_no_side_effect else 'v8::PropertyHandlerFlags::kNone' %} |
| v8::IndexedPropertyHandlerConfiguration indexedPropertyHandlerConfig( |
| {{indexed_property_getter_callback}}, |
| {{indexed_property_setter_callback}}, |
| {{indexed_property_descriptor_callback}}, |
| {{indexed_property_deleter_callback}}, |
| {{indexed_property_enumerator_callback}}, |
| {{indexed_property_definer_callback}}, |
| v8::Local<v8::Value>(), |
| {{property_handler_flags}}); |
| {{target}}->SetHandler(indexedPropertyHandlerConfig); |
| {%- endmacro %} |
| |
| |
| {##############################################################################} |
| {% macro install_named_property_handler(target) %} |
| {% set named_property_getter_callback = |
| '%s::namedPropertyGetterCallback' % v8_class_or_partial %} |
| {% set named_property_setter_callback = |
| '%s::namedPropertySetterCallback' % v8_class_or_partial |
| if named_property_setter else 'nullptr' %} |
| {% set named_property_query_callback = |
| '%s::namedPropertyQueryCallback' % v8_class_or_partial |
| if named_property_getter.is_enumerable else 'nullptr' %} |
| {% set named_property_deleter_callback = |
| '%s::namedPropertyDeleterCallback' % v8_class_or_partial |
| if named_property_deleter else 'nullptr' %} |
| {% set named_property_enumerator_callback = |
| '%s::namedPropertyEnumeratorCallback' % v8_class_or_partial |
| if named_property_getter.is_enumerable else 'nullptr' %} |
| {% set property_handler_flags_list = |
| ['int(v8::PropertyHandlerFlags::kOnlyInterceptStrings)'] %} |
| {% if not is_override_builtins %} |
| {% set property_handler_flags_list = |
| property_handler_flags_list + ['int(v8::PropertyHandlerFlags::kNonMasking)'] %} |
| {% endif %} |
| {% if named_property_getter.has_no_side_effect %} |
| {% set property_handler_flags_list = |
| property_handler_flags_list + ['int(v8::PropertyHandlerFlags::kHasNoSideEffect)'] %} |
| {% endif %} |
| {% set property_handler_flags = |
| 'static_cast<v8::PropertyHandlerFlags>(%s)' % |
| ' | '.join(property_handler_flags_list) %} |
| v8::NamedPropertyHandlerConfiguration namedPropertyHandlerConfig({{named_property_getter_callback}}, {{named_property_setter_callback}}, {{named_property_query_callback}}, {{named_property_deleter_callback}}, {{named_property_enumerator_callback}}, v8::Local<v8::Value>(), {{property_handler_flags}}); |
| {{target}}->SetHandler(namedPropertyHandlerConfig); |
| {%- endmacro %} |
| |
| |
| {##############################################################################} |
| {% block get_dom_template %} |
| {% if not is_array_buffer_or_view %} |
| v8::Local<v8::FunctionTemplate> {{v8_class}}::domTemplate(v8::Isolate* isolate, const DOMWrapperWorld& world) { |
| {% set installTemplateFunction = '%s::install%sTemplateFunction' % (v8_class, v8_class) if has_partial_interface else 'install%sTemplate' % v8_class %} |
| return V8DOMConfiguration::DomClassTemplate(isolate, world, const_cast<WrapperTypeInfo*>(&wrapperTypeInfo), {{installTemplateFunction}}); |
| } |
| |
| {% endif %} |
| {% endblock %} |
| |
| |
| {##############################################################################} |
| {% block get_dom_template_for_named_properties_object %} |
| {% if has_named_properties_object %} |
| v8::Local<v8::FunctionTemplate> {{v8_class}}::domTemplateForNamedPropertiesObject(v8::Isolate* isolate, const DOMWrapperWorld& world) { |
| v8::Local<v8::FunctionTemplate> parentTemplate = V8{{parent_interface}}::domTemplate(isolate, world); |
| |
| v8::Local<v8::FunctionTemplate> namedPropertiesObjectFunctionTemplate = v8::FunctionTemplate::New(isolate, V8ObjectConstructor::IsValidConstructorMode); |
| namedPropertiesObjectFunctionTemplate->SetClassName(V8AtomicString(isolate, "{{interface_name}}Properties")); |
| namedPropertiesObjectFunctionTemplate->Inherit(parentTemplate); |
| |
| v8::Local<v8::ObjectTemplate> namedPropertiesObjectTemplate = namedPropertiesObjectFunctionTemplate->PrototypeTemplate(); |
| namedPropertiesObjectTemplate->SetInternalFieldCount({{v8_class}}::internalFieldCount); |
| // Named Properties object has SetPrototype method of Immutable Prototype Exotic Objects |
| namedPropertiesObjectTemplate->SetImmutableProto(); |
| V8DOMConfiguration::SetClassString(isolate, namedPropertiesObjectTemplate, "{{interface_name}}Properties"); |
| {{install_named_property_handler('namedPropertiesObjectTemplate') | trim | indent(2)}} |
| |
| return namedPropertiesObjectFunctionTemplate; |
| } |
| |
| {% endif %} |
| {% endblock %} |
| |
| |
| {##############################################################################} |
| {% block has_instance %} |
| {% if not is_array_buffer_or_view %} |
| |
| bool {{v8_class}}::hasInstance(v8::Local<v8::Value> v8Value, v8::Isolate* isolate) { |
| return V8PerIsolateData::From(isolate)->HasInstance(&wrapperTypeInfo, v8Value); |
| } |
| |
| v8::Local<v8::Object> {{v8_class}}::findInstanceInPrototypeChain(v8::Local<v8::Value> v8Value, v8::Isolate* isolate) { |
| return V8PerIsolateData::From(isolate)->FindInstanceInPrototypeChain(&wrapperTypeInfo, v8Value); |
| } |
| |
| {% endif %} |
| {% endblock %} |
| |
| |
| {##############################################################################} |
| {% block to_impl %} |
| {% if interface_name == 'ArrayBuffer' or interface_name == 'SharedArrayBuffer' %} |
| {{cpp_class}}* V8{{interface_name}}::ToImpl(v8::Local<v8::Object> object) { |
| DCHECK(object->Is{{interface_name}}()); |
| v8::Local<v8::{{interface_name}}> v8buffer = object.As<v8::{{interface_name}}>(); |
| if (v8buffer->IsExternal()) { |
| const WrapperTypeInfo* wrapperTypeInfo = ToWrapperTypeInfo(object); |
| CHECK(wrapperTypeInfo); |
| CHECK_EQ(wrapperTypeInfo->gin_embedder, gin::kEmbedderBlink); |
| return ToScriptWrappable(object)->ToImpl<{{cpp_class}}>(); |
| } |
| |
| // Transfer the ownership of the allocated memory to an {{interface_name}} without |
| // copying. |
| v8::{{interface_name}}::Contents v8Contents = v8buffer->Externalize(); |
| WTF::ArrayBufferContents::DataHandle data(v8Contents.Data(), |
| v8Contents.ByteLength(), |
| v8Contents.Deleter(), |
| v8Contents.DeleterData()); |
| WTF::ArrayBufferContents contents(std::move(data), WTF::ArrayBufferContents::k{% if interface_name == 'ArrayBuffer' %}Not{% endif %}Shared); |
| {{cpp_class}}* buffer = {{cpp_class}}::Create(contents); |
| v8::Local<v8::Object> associatedWrapper = buffer->AssociateWithWrapper(v8::Isolate::GetCurrent(), buffer->GetWrapperTypeInfo(), object); |
| DCHECK(associatedWrapper == object); |
| |
| return buffer; |
| } |
| |
| {% elif interface_name == 'ArrayBufferView' %} |
| {{cpp_class}}* V8ArrayBufferView::ToImpl(v8::Local<v8::Object> object) { |
| DCHECK(object->IsArrayBufferView()); |
| ScriptWrappable* scriptWrappable = ToScriptWrappable(object); |
| if (scriptWrappable) |
| return scriptWrappable->ToImpl<{{cpp_class}}>(); |
| |
| if (object->IsInt8Array()) |
| return V8Int8Array::ToImpl(object); |
| if (object->IsInt16Array()) |
| return V8Int16Array::ToImpl(object); |
| if (object->IsInt32Array()) |
| return V8Int32Array::ToImpl(object); |
| if (object->IsUint8Array()) |
| return V8Uint8Array::ToImpl(object); |
| if (object->IsUint8ClampedArray()) |
| return V8Uint8ClampedArray::ToImpl(object); |
| if (object->IsUint16Array()) |
| return V8Uint16Array::ToImpl(object); |
| if (object->IsUint32Array()) |
| return V8Uint32Array::ToImpl(object); |
| if (object->IsBigInt64Array()) |
| return V8BigInt64Array::ToImpl(object); |
| if (object->IsBigUint64Array()) |
| return V8BigUint64Array::ToImpl(object); |
| if (object->IsFloat32Array()) |
| return V8Float32Array::ToImpl(object); |
| if (object->IsFloat64Array()) |
| return V8Float64Array::ToImpl(object); |
| if (object->IsDataView()) |
| return V8DataView::ToImpl(object); |
| |
| NOTREACHED(); |
| return 0; |
| } |
| |
| {% elif is_array_buffer_or_view %} |
| {{cpp_class}}* {{v8_class}}::ToImpl(v8::Local<v8::Object> object) { |
| DCHECK(object->Is{{interface_name}}()); |
| ScriptWrappable* scriptWrappable = ToScriptWrappable(object); |
| if (scriptWrappable) |
| return scriptWrappable->ToImpl<{{cpp_class}}>(); |
| |
| v8::Local<v8::{{interface_name}}> v8View = object.As<v8::{{interface_name}}>(); |
| v8::Local<v8::Object> arrayBuffer = v8View->Buffer(); |
| {{cpp_class}}* typedArray = nullptr; |
| if (arrayBuffer->IsArrayBuffer()) { |
| typedArray = {{cpp_class}}::Create(V8ArrayBuffer::ToImpl(arrayBuffer), v8View->ByteOffset(), v8View->{% if interface_name == 'DataView' %}Byte{% endif %}Length()); |
| } else if (arrayBuffer->IsSharedArrayBuffer()) { |
| typedArray = {{cpp_class}}::Create(V8SharedArrayBuffer::ToImpl(arrayBuffer), v8View->ByteOffset(), v8View->{% if interface_name == 'DataView' %}Byte{% endif %}Length()); |
| } else { |
| NOTREACHED(); |
| } |
| v8::Local<v8::Object> associatedWrapper = typedArray->AssociateWithWrapper(v8::Isolate::GetCurrent(), typedArray->GetWrapperTypeInfo(), object); |
| DCHECK(associatedWrapper == object); |
| |
| return typedArray->ToImpl<{{cpp_class}}>(); |
| } |
| |
| {% endif %} |
| {% endblock %} |
| |
| |
| {##############################################################################} |
| {% block to_impl_with_type_check %} |
| {{cpp_class}}* {{v8_class}}::ToImplWithTypeCheck(v8::Isolate* isolate, v8::Local<v8::Value> value) { |
| {% if is_array_buffer_or_view %} |
| return value->Is{{interface_name}}() ? ToImpl(v8::Local<v8::Object>::Cast(value)) : nullptr; |
| {% else %} |
| return hasInstance(value, isolate) ? ToImpl(v8::Local<v8::Object>::Cast(value)) : nullptr; |
| {% endif %} |
| } |
| |
| {% endblock %} |
| |
| |
| {##############################################################################} |
| {% block native_value_traits %} |
| {{cpp_class}}* NativeValueTraits<{{cpp_class}}>::NativeValue(v8::Isolate* isolate, v8::Local<v8::Value> value, ExceptionState& exceptionState) { |
| {{cpp_class}}* nativeValue = {{v8_class}}::ToImplWithTypeCheck(isolate, value); |
| if (!nativeValue) { |
| exceptionState.ThrowTypeError(ExceptionMessages::FailedToConvertJSValue( |
| "{{interface_name}}")); |
| } |
| return nativeValue; |
| } |
| |
| {% endblock %} |
| |
| |
| {##############################################################################} |
| {% block partial_interface %} |
| {% if has_partial_interface %} |
| {% if needs_runtime_enabled_installer %} |
| InstallRuntimeEnabledFeaturesFunction |
| {{v8_class}}::install_runtime_enabled_features_function_ = |
| &{{v8_class}}::InstallRuntimeEnabledFeaturesImpl; |
| {% endif %} |
| {% if not is_array_buffer_or_view %} |
| InstallRuntimeEnabledFeaturesOnTemplateFunction |
| {{v8_class}}::install_runtime_enabled_features_on_template_function_ = |
| &{{v8_class}}::InstallRuntimeEnabledFeaturesOnTemplate; |
| {% endif %} |
| |
| InstallTemplateFunction {{v8_class}}::install{{v8_class}}TemplateFunction = |
| &{{v8_class}}::install{{v8_class}}Template; |
| |
| void {{v8_class}}::UpdateWrapperTypeInfo( |
| InstallTemplateFunction install_template_function, |
| InstallRuntimeEnabledFeaturesFunction install_runtime_enabled_features_function, |
| InstallRuntimeEnabledFeaturesOnTemplateFunction install_runtime_enabled_features_on_template_function, |
| InstallConditionalFeaturesFunction install_conditional_features_function) { |
| {{v8_class}}::install{{v8_class}}TemplateFunction = |
| install_template_function; |
| |
| {% if needs_runtime_enabled_installer %} |
| CHECK(install_runtime_enabled_features_function); |
| {{v8_class}}::install_runtime_enabled_features_function_ = |
| install_runtime_enabled_features_function; |
| |
| {% endif %} |
| {% if not is_array_buffer_or_view %} |
| CHECK(install_runtime_enabled_features_on_template_function); |
| {{v8_class}}::install_runtime_enabled_features_on_template_function_ = |
| install_runtime_enabled_features_on_template_function; |
| {% endif %} |
| |
| if (install_conditional_features_function) { |
| {{v8_class}}::wrapperTypeInfo.install_conditional_features_function = |
| install_conditional_features_function; |
| } |
| } |
| |
| {% for method in methods if method.overloads and method.overloads.has_partial_overloads %} |
| void {{v8_class}}::register{{method.name | blink_capitalize}}MethodForPartialInterface(void (*method)(const v8::FunctionCallbackInfo<v8::Value>&)) { |
| {{cpp_class}}V8Internal::{{method.name}}MethodForPartialInterface = method; |
| } |
| |
| {% endfor %} |
| {% endif %}{# has_partial_interface #} |
| {% endblock %} |