| {% 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 exception_state(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* script_state = ScriptState::ForRelevantRealm(info); |
| {% set getter_arguments = ['script_state'] + getter_arguments %} |
| {% endif %} |
| {% if getter.is_raises_exception %} |
| {% set getter_arguments = getter_arguments + ['exception_state'] %} |
| {% 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 %} |
| {{internal_namespace}}::IndexedPropertyGetter(index, info); |
| {% endif %} |
| |
| {% else %}{# otherwise, named property #} |
| |
| const AtomicString& property_name = AtomicString::Number(index); |
| |
| {% if getter.is_custom %} |
| {{v8_class}}::NamedPropertyGetterCustom(property_name, info); |
| {% else %} |
| {{internal_namespace}}::NamedPropertyGetter(property_name, 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> v8_value, |
| const v8::PropertyCallbackInfo<v8::Value>& info) { |
| {% if setter.has_exception_state %} |
| ExceptionState exception_state( |
| 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 (!property_value{% if setter.is_nullable %} && !IsUndefinedOrNull(v8_value){% endif %}) { |
| exception_state.ThrowTypeError("The provided value is not of type '{{setter.idl_type}}'."); |
| return; |
| } |
| {% endif %} |
| |
| {% set setter_name = setter.name or 'AnonymousIndexedSetter' %} |
| {% set setter_arguments = ['index', 'property_value'] %} |
| {% if setter.is_call_with_script_state %} |
| ScriptState* script_state = ScriptState::ForRelevantRealm(info); |
| {% set setter_arguments = ['script_state'] + setter_arguments %} |
| {% endif %} |
| {% if setter.is_raises_exception %} |
| {% set setter_arguments = setter_arguments + ['exception_state'] %} |
| {% endif %} |
| IndexedPropertySetterResult result = impl->{{setter_name}}({{setter_arguments | join(', ')}}); |
| {% if setter.is_raises_exception %} |
| if (exception_state.HadException()) |
| return; |
| {% endif %} |
| if (result == IndexedPropertySetterResult::kDidNotIntercept) |
| return; |
| V8SetReturnValue(info, v8_value); |
| } |
| |
| {% 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> v8_value, |
| const v8::PropertyCallbackInfo<v8::Value>& info) { |
| {% if indexed_property_setter %} |
| |
| {% if setter.is_custom %} |
| {{v8_class}}::IndexedPropertySetterCustom(index, v8_value, info); |
| {% else %} |
| {{internal_namespace}}::IndexedPropertySetter(index, v8_value, info); |
| {% endif %} |
| |
| {% elif not indexed_property_getter and named_property_setter %} |
| |
| const AtomicString& property_name = AtomicString::Number(index); |
| |
| {% if setter.is_custom %} |
| {{v8_class}}::NamedPropertySetterCustom(property_name, v8_value, info); |
| {% else %} |
| {{internal_namespace}}::NamedPropertySetter(property_name, v8_value, 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 exception_state(info.GetIsolate(), |
| ExceptionState::kIndexedSetterContext, |
| "{{interface_name}}"); |
| {% if setter.is_ce_reactions %} |
| CEReactionsScope ce_reactions_scope; |
| {% endif %} |
| exception_state.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> getter_value = info.GetReturnValue().Get(); |
| if (!getter_value->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(getter_value, {% 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& index_as_name = AtomicString::Number(index); |
| {% if named_property_getter.is_custom_property_query %} |
| {{v8_class}}::NamedPropertyQueryCustom(index_as_name, info); |
| {% else %} |
| {{internal_namespace}}::NamedPropertyQuery(index_as_name, info); |
| {% endif %} |
| v8::Local<v8::Value> getter_value = info.GetReturnValue().Get(); |
| if (!getter_value->IsUndefined()) { |
| DCHECK(getter_value->IsInt32()); |
| const int32_t props = |
| getter_value->ToInt32(info.GetIsolate()->GetCurrentContext()) |
| .ToLocalChecked() |
| ->Value(); |
| v8::PropertyDescriptor desc(V8String(info.GetIsolate(), index_as_name), |
| !(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> getter_value = info.GetReturnValue().Get(); |
| if (!getter_value->IsUndefined()) { |
| v8::PropertyDescriptor desc(getter_value, {% 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 %} |
| {{internal_namespace}}::IndexedPropertyDescriptor(index, info); |
| {% else %}{# The interface only supports named properties. #} |
| {{internal_namespace}}::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 exception_state( |
| 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* script_state = ScriptState::ForRelevantRealm(info); |
| {% set deleter_arguments = ['script_state'] + deleter_arguments %} |
| {% endif %} |
| {% if deleter.is_raises_exception %} |
| {% set deleter_arguments = deleter_arguments + ['exception_state'] %} |
| {% endif %} |
| NamedPropertyDeleterResult result = impl->{{deleter_name}}({{deleter_arguments | join(', ')}}); |
| {% if deleter.is_raises_exception %} |
| if (exception_state.HadException()) |
| return; |
| {% endif %} |
| if (result == NamedPropertyDeleterResult::kDidNotIntercept) |
| return; |
| V8SetReturnValue(info, result == NamedPropertyDeleterResult::kDeleted); |
| } |
| |
| {% 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 %} |
| {{internal_namespace}}::IndexedPropertyDeleter(index, info); |
| {% endif %} |
| |
| {% else %}{# otherwise, named property #} |
| |
| const AtomicString& property_name = AtomicString::Number(index); |
| |
| {% if deleter.is_custom %} |
| {{v8_class}}::NamedPropertyDeleterCustom(property_name, info); |
| {% else %} |
| {{internal_namespace}}::NamedPropertyDeleter(property_name, 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 exception_state(info.GetIsolate(), |
| ExceptionState::kIndexedSetterContext, |
| "{{interface_name}}"); |
| exception_state.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 exception_state(info.GetIsolate(), |
| ExceptionState::kIndexedSetterContext, |
| "{{interface_name}}"); |
| exception_state.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 std::string& name_in_utf8 = name.Utf8(); |
| ExceptionState exception_state( |
| info.GetIsolate(), |
| ExceptionState::kGetterContext, |
| "{{interface_name}}", |
| name_in_utf8.c_str()); |
| {% endif %} |
| {% if getter.is_call_with_script_state %} |
| ScriptState* script_state = 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& property_name = ToCoreAtomicString(name.As<v8::String>()); |
| |
| {% if getter.is_custom %} |
| {{v8_class}}::NamedPropertyGetterCustom(property_name, info); |
| {% else %} |
| {{internal_namespace}}::NamedPropertyGetter(property_name, 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> v8_value, |
| const v8::PropertyCallbackInfo<v8::Value>& info) { |
| {% if setter.has_exception_state %} |
| const std::string& name_in_utf8 = name.Utf8(); |
| ExceptionState exception_state( |
| info.GetIsolate(), |
| ExceptionState::kSetterContext, |
| "{{interface_name}}", |
| name_in_utf8.c_str()); |
| {% endif %} |
| {% if setter.is_ce_reactions %} |
| CEReactionsScope ce_reactions_scope; |
| {% endif %} |
| {% if setter.is_call_with_script_state %} |
| ScriptState* script_state = 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 (!property_value{% if setter.is_nullable %} && !IsUndefinedOrNull(v8_value){% endif %}) { |
| exception_state.ThrowTypeError("The provided value is not of type '{{setter.idl_type}}'."); |
| return; |
| } |
| {% endif %} |
| |
| {% set setter_name = setter.name or 'AnonymousNamedSetter' %} |
| {% set setter_arguments = ['name', 'property_value'] %} |
| {% if setter.is_call_with_script_state %} |
| {% set setter_arguments = ['script_state'] + setter_arguments %} |
| {% endif %} |
| {% if setter.is_raises_exception %} |
| {% set setter_arguments = setter_arguments + ['exception_state'] %} |
| {% endif %} |
| NamedPropertySetterResult result = impl->{{setter_name}}({{setter_arguments | join(', ')}}); |
| {% if setter.is_raises_exception %} |
| if (exception_state.HadException()) |
| return; |
| {% endif %} |
| if (result == NamedPropertySetterResult::kDidNotIntercept) |
| return; |
| V8SetReturnValue(info, v8_value); |
| } |
| |
| {% 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> v8_value, |
| 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& property_name = ToCoreAtomicString(name.As<v8::String>()); |
| |
| {% if setter.is_custom %} |
| {{v8_class}}::NamedPropertySetterCustom(property_name, v8_value, info); |
| {% else %} |
| {{internal_namespace}}::NamedPropertySetter(property_name, v8_value, 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 std::string& name_in_utf8 = name.Utf8(); |
| ExceptionState exception_state( |
| info.GetIsolate(), |
| ExceptionState::kDeletionContext, |
| "{{interface_name}}", |
| name_in_utf8.c_str()); |
| {% endif %} |
| {% if deleter.is_ce_reactions %} |
| CEReactionsScope ce_reactions_scope; |
| {% endif %} |
| {% if deleter.is_call_with_script_state %} |
| ScriptState* script_state = 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 = ['script_state'] + deleter_arguments %} |
| {% endif %} |
| {% if deleter.is_raises_exception %} |
| {% set deleter_arguments = deleter_arguments + ['exception_state'] %} |
| {% endif %} |
| NamedPropertyDeleterResult result = impl->{{deleter_name}}({{deleter_arguments | join(', ')}}); |
| {% if deleter.is_raises_exception %} |
| if (exception_state.HadException()) |
| return; |
| {% endif %} |
| if (result == NamedPropertyDeleterResult::kDidNotIntercept) |
| return; |
| V8SetReturnValue(info, result == NamedPropertyDeleterResult::kDeleted); |
| } |
| |
| {% 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& property_name = ToCoreAtomicString(name.As<v8::String>()); |
| |
| {% if deleter.is_custom %} |
| {{v8_class}}::NamedPropertyDeleterCustom(property_name, info); |
| {% else %} |
| {{internal_namespace}}::NamedPropertyDeleter(property_name, 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 std::string& name_in_utf8 = name.Utf8(); |
| ExceptionState exception_state( |
| info.GetIsolate(), |
| ExceptionState::kGetterContext, |
| "{{interface_name}}", |
| name_in_utf8.c_str()); |
| {% if getter.is_call_with_script_state %} |
| ScriptState* script_state = ScriptState::ForRelevantRealm(info); |
| {% endif %} |
| |
| {{cpp_class}}* impl = {{v8_class}}::ToImpl(info.Holder()); |
| |
| {% set getter_arguments = ['name', 'exception_state'] %} |
| {% if getter.is_call_with_script_state %} |
| {% set getter_arguments = ['script_state'] + 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& property_name = ToCoreAtomicString(name.As<v8::String>()); |
| |
| {% if getter.is_custom_property_query %} |
| {{v8_class}}::NamedPropertyQueryCustom(property_name, info); |
| {% else %} |
| {{internal_namespace}}::NamedPropertyQuery(property_name, 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 exception_state( |
| info.GetIsolate(), |
| ExceptionState::kEnumerationContext, |
| "{{interface_name}}"); |
| |
| {{cpp_class}}* impl = {{v8_class}}::ToImpl(info.Holder()); |
| |
| Vector<String> names; |
| impl->NamedPropertyEnumerator(names, exception_state); |
| if (exception_state.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 %} |
| {{internal_namespace}}::NamedPropertyEnumerator(info); |
| {% endif %} |
| } |
| |
| {% 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 {{snake_case_v8_class}}_constructor_wrapper_type_info = { |
| 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 dom_template_key; // 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, &dom_template_key); |
| if (!result.IsEmpty()) |
| return result; |
| |
| result = v8::FunctionTemplate::New(isolate, {{v8_class}}ConstructorCallback); |
| v8::Local<v8::ObjectTemplate> instance_template = result->InstanceTemplate(); |
| instance_template->SetInternalFieldCount({{v8_class}}::kInternalFieldCount); |
| result->SetClassName(V8AtomicString(isolate, "{{named_constructor.name}}")); |
| result->Inherit({{v8_class}}::DomTemplate(isolate, world)); |
| data->SetInterfaceTemplate(world, &dom_template_key, result); |
| return result; |
| } |
| |
| void {{v8_class}}Constructor::NamedConstructorAttributeGetter( |
| v8::Local<v8::Name> property_name, |
| const v8::PropertyCallbackInfo<v8::Value>& info) { |
| v8::Local<v8::Context> creationContext = info.Holder()->CreationContext(); |
| V8PerContextData* per_context_data = V8PerContextData::From(creationContext); |
| if (!per_context_data) { |
| // TODO(yukishiino): Return a valid named constructor even after the context is detached |
| return; |
| } |
| |
| v8::Local<v8::Function> named_constructor = |
| per_context_data->ConstructorForType({{v8_class}}Constructor::GetWrapperTypeInfo()); |
| |
| // Set the prototype of named constructors to the regular constructor. |
| static const V8PrivateProperty::SymbolKey kPrivatePropertyInitialized; |
| auto private_property = |
| V8PrivateProperty::GetSymbol( |
| info.GetIsolate(), kPrivatePropertyInitialized); |
| v8::Local<v8::Context> current_context = info.GetIsolate()->GetCurrentContext(); |
| v8::Local<v8::Value> private_value; |
| |
| if (!private_property.GetOrUndefined(named_constructor).ToLocal(&private_value) || |
| private_value->IsUndefined()) { |
| v8::Local<v8::Function> interface = |
| per_context_data->ConstructorForType({{v8_class}}::GetWrapperTypeInfo()); |
| v8::Local<v8::Value> interface_prototype = |
| interface->Get(current_context, V8AtomicString(info.GetIsolate(), "prototype")) |
| .ToLocalChecked(); |
| // https://heycam.github.io/webidl/#named-constructors |
| // 8. Perform ! DefinePropertyOrThrow(F, "prototype", |
| // PropertyDescriptor{[[Value]]: proto, [[Writable]]: false, |
| // [[Enumerable]]: false, |
| // [Configurable]]: false}). |
| const v8::PropertyAttribute prototype_attributes = |
| static_cast<v8::PropertyAttribute>(v8::ReadOnly | v8::DontEnum | v8::DontDelete); |
| bool result = named_constructor->DefineOwnProperty( |
| current_context, V8AtomicString(info.GetIsolate(), "prototype"), |
| interface_prototype, prototype_attributes).ToChecked(); |
| CHECK(result); |
| private_property.Set(named_constructor, v8::True(info.GetIsolate())); |
| } |
| |
| V8SetReturnValue(info, named_constructor); |
| } |
| |
| {% endif %} |
| {% endblock %} |
| |
| {##############################################################################} |
| {% block overloaded_constructor %} |
| {% if constructor_overloads %} |
| static void Constructor(const v8::FunctionCallbackInfo<v8::Value>& info) { |
| ExceptionState exception_state(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}}) { |
| {{internal_namespace}}::Constructor{{constructor.overload_index}}(info); |
| return; |
| } |
| {% if "exception_state" in test %} |
| if (exception_state.HadException()) { |
| exception_state.RethrowV8Exception(exception_state.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}}) { |
| exception_state.ThrowTypeError(ExceptionMessages::InvalidArity("{{constructor_overloads.valid_arities}}", info.Length())); |
| return; |
| } |
| {% endif %} |
| {# Otherwise just report "not enough arguments" #} |
| exception_state.ThrowTypeError(ExceptionMessages::NotEnoughArguments({{constructor_overloads.length}}, info.Length())); |
| return; |
| } |
| {# No match, throw error #} |
| exception_state.ThrowTypeError("No matching constructor signature."); |
| } |
| |
| {% endif %} |
| {% endblock %} |
| |
| |
| {##############################################################################} |
| {% block constructor_callback %} |
| {% if constructors or has_custom_constructor or has_html_constructor %} |
| {{exported}}void ConstructorCallback(const v8::FunctionCallbackInfo<v8::Value>& info) { |
| {{ runtime_timer_scope_disabled_by_default(runtime_call_stats.constructor_counter) }} |
| {% if measure_as %} |
| ExecutionContext* execution_context_for_measurement = CurrentExecutionContext(info.GetIsolate()); |
| UseCounter::Count(execution_context_for_measurement, WebFeature::k{{measure_as('Constructor')}}); |
| {% if high_entropy %} |
| Dactyloscoper::Record(execution_context_for_measurement, WebFeature::k{{measure_as('Constructor')}}); |
| {% endif %} |
| {% 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}}::GetWrapperTypeInfo(), HTMLElementType::k{{interface_name}}); |
| {% else %} |
| {{internal_namespace}}::Constructor(info); |
| {% endif %} |
| } |
| |
| {% endif %} |
| {% endblock %} |
| |
| |
| {##############################################################################} |
| {% macro install_origin_safe_method(method, instance_template, prototype_template, interface_template, signature) %} |
| {% 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 function_callback = |
| '%s::%sMethodCallback' % (v8_class_or_partial, method.camel_case_name) %} |
| {% set property_attribute = |
| 'static_cast<v8::PropertyAttribute>(%s)' % |
| ' | '.join(method.property_attributes or ['v8::None']) %} |
| {% set holder_check = 'V8DOMConfiguration::kCheckHolder' %} |
| static const V8DOMConfiguration::MethodConfiguration k{{method.camel_case_name}}OriginSafeMethodConfiguration[] = { |
| {% if method.is_per_world_bindings %} |
| {% set function_callback_for_main_world = '%sForMainWorld' % function_callback %} |
| { |
| "{{method.name}}", |
| {{function_callback_for_main_world}}, |
| {{method.length}}, |
| {{property_attribute}}, |
| {{property_location(method)}}, |
| {{holder_check}}, |
| V8DOMConfiguration::kCheckAccess, |
| V8DOMConfiguration::kHasSideEffect, |
| V8DOMConfiguration::MainWorld, |
| }, |
| { |
| "{{method.name}}", |
| {{function_callback}}, |
| {{method.length}}, |
| {{property_attribute}}, |
| {{property_location(method)}}, |
| {{holder_check}}, |
| V8DOMConfiguration::kCheckAccess, |
| V8DOMConfiguration::kHasSideEffect, |
| V8DOMConfiguration::NonMainWorlds, |
| } |
| {% else %} |
| { |
| "{{method.name}}", |
| {{function_callback}}, |
| {{method.length}}, |
| {{property_attribute}}, |
| {{property_location(method)}}, |
| {{holder_check}}, |
| V8DOMConfiguration::kCheckAccess, |
| V8DOMConfiguration::kHasSideEffect, |
| V8DOMConfiguration::kAllWorlds, |
| } |
| {% endif %} |
| }; |
| for (const auto& method_config : k{{method.camel_case_name}}OriginSafeMethodConfiguration) |
| V8DOMConfiguration::InstallMethod(isolate, world, {{instance_template}}, {{prototype_template}}, {{interface_template}}, {{signature}}, method_config); |
| {%- 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 install_template_function = '%s::install_%s_template_function_' % (v8_class, snake_case_v8_class) if has_partial_interface else 'Install%sTemplate' % v8_class %} |
| return V8DOMConfiguration::DomClassTemplate( |
| isolate, world, const_cast<WrapperTypeInfo*>({{v8_class}}::GetWrapperTypeInfo()), |
| {{install_template_function}}); |
| } |
| |
| {% 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> named_properties_function_template = |
| v8::FunctionTemplate::New(isolate, |
| V8ObjectConstructor::IsValidConstructorMode); |
| named_properties_function_template->SetClassName( |
| V8AtomicString(isolate, "{{interface_name}}Properties")); |
| named_properties_function_template->Inherit(parentTemplate); |
| |
| v8::Local<v8::ObjectTemplate> named_properties_object_template = |
| named_properties_function_template->PrototypeTemplate(); |
| named_properties_object_template->SetInternalFieldCount( |
| {{v8_class}}::kInternalFieldCount); |
| // Named Properties object has SetPrototype method of Immutable Prototype Exotic Objects |
| named_properties_object_template->SetImmutableProto(); |
| V8DOMConfiguration::SetClassString( |
| isolate, named_properties_object_template, "{{interface_name}}Properties"); |
| {{install_named_property_handler('named_properties_object_template') | trim | indent(2)}} |
| |
| return named_properties_function_template; |
| } |
| |
| {% endif %} |
| {% endblock %} |
| |
| |
| {##############################################################################} |
| {% block has_instance %} |
| {% if not is_array_buffer_or_view %} |
| |
| bool {{v8_class}}::HasInstance(v8::Local<v8::Value> v8_value, v8::Isolate* isolate) { |
| return V8PerIsolateData::From(isolate)->HasInstance({{v8_class}}::GetWrapperTypeInfo(), v8_value); |
| } |
| |
| v8::Local<v8::Object> {{v8_class}}::FindInstanceInPrototypeChain( |
| v8::Local<v8::Value> v8_value, v8::Isolate* isolate) { |
| return V8PerIsolateData::From(isolate)->FindInstanceInPrototypeChain( |
| {{v8_class}}::GetWrapperTypeInfo(), v8_value); |
| } |
| |
| {% 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}}>(); |
| // TODO(ahaas): The use of IsExternal is wrong here. Instead we should call |
| // ToScriptWrappable(object)->ToImpl<ArrayBuffer>() and check for nullptr. |
| // We can then also avoid the call to Externalize below. |
| if (v8buffer->IsExternal()) { |
| const WrapperTypeInfo* wrapper_type = ToWrapperTypeInfo(object); |
| CHECK(wrapper_type); |
| CHECK_EQ(wrapper_type->gin_embedder, gin::kEmbedderBlink); |
| return ToScriptWrappable(object)->ToImpl<{{cpp_class}}>(); |
| } |
| |
| // Transfer the ownership of the allocated memory to an {{interface_name}} without |
| // copying. |
| auto backing_store = v8buffer->GetBackingStore(); |
| v8buffer->Externalize(backing_store); |
| ArrayBufferContents contents(std::move(backing_store)); |
| {{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* script_wrappable = ToScriptWrappable(object); |
| if (script_wrappable) |
| return script_wrappable->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 nullptr; |
| } |
| |
| {% elif is_array_buffer_or_view %} |
| {{cpp_class}}* {{v8_class}}::ToImpl(v8::Local<v8::Object> object) { |
| DCHECK(object->Is{{interface_name}}()); |
| ScriptWrappable* script_wrappable = ToScriptWrappable(object); |
| if (script_wrappable) |
| return script_wrappable->ToImpl<{{cpp_class}}>(); |
| |
| v8::Local<v8::{{interface_name}}> v8_view = object.As<v8::{{interface_name}}>(); |
| v8::Local<v8::Object> array_buffer = v8_view->Buffer(); |
| {{cpp_class}}* typed_array = nullptr; |
| if (array_buffer->IsArrayBuffer()) { |
| typed_array = {{cpp_class}}::Create( |
| V8ArrayBuffer::ToImpl(array_buffer), |
| v8_view->ByteOffset(), |
| v8_view->{% if interface_name == 'DataView' %}Byte{% endif %}Length()); |
| } else if (array_buffer->IsSharedArrayBuffer()) { |
| typed_array = {{cpp_class}}::Create( |
| V8SharedArrayBuffer::ToImpl(array_buffer), |
| v8_view->ByteOffset(), |
| v8_view->{% if interface_name == 'DataView' %}Byte{% endif %}Length()); |
| } else { |
| NOTREACHED(); |
| } |
| v8::Local<v8::Object> associated_wrapper = |
| typed_array->AssociateWithWrapper( |
| v8::Isolate::GetCurrent(), typed_array->GetWrapperTypeInfo(), object); |
| DCHECK(associated_wrapper == object); |
| |
| return typed_array->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 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_{{snake_case_v8_class}}_template_function_ = |
| &{{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_{{snake_case_v8_class}}_template_function_ = |
| 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}}::GetWrapperTypeInfo()->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.camel_case_name}}MethodForPartialInterface(void (*method)(const v8::FunctionCallbackInfo<v8::Value>&)) { |
| {{internal_namespace}}::{{method.name}}MethodForPartialInterface = method; |
| } |
| |
| {% endfor %} |
| {% endif %}{# has_partial_interface #} |
| {% endblock %} |