| {% filter format_blink_cpp_source_code %} |
| |
| {% from 'utilities.cc.tmpl' import declare_enum_validation_variable %} |
| {% include 'copyright_block.txt' %} |
| #include "{{this_include_header_path}}" |
| |
| {% for filename in cpp_includes if filename != '%s.h' % v8_class %} |
| #include "{{filename}}" |
| {% endfor %} |
| |
| namespace blink { |
| |
| {% if members %} |
| static const base::span<const v8::Eternal<v8::Name>> |
| eternal{{v8_class}}Keys(v8::Isolate* isolate) { |
| static const char* const kKeys[] = { |
| {% for member in members %} |
| "{{member.name}}", |
| {% endfor %} |
| }; |
| return V8PerIsolateData::From(isolate)->FindOrCreateEternalNameCache(kKeys, kKeys); |
| } |
| {% endif %} |
| |
| {% from 'utilities.cc.tmpl' import v8_value_to_local_cpp_value %} |
| void {{v8_class}}::ToImpl(v8::Isolate* isolate, v8::Local<v8::Value> v8_value, {{cpp_class}}* impl, ExceptionState& exception_state) { |
| if (IsUndefinedOrNull(v8_value)) { |
| {% if required_member_names %} |
| exception_state.ThrowTypeError("Missing required member(s): {{required_member_names|join(', ')}}."); |
| {% endif %} |
| return; |
| } |
| if (!v8_value->IsObject()) { |
| {% if use_permissive_dictionary_conversion %} |
| // Do nothing. |
| return; |
| {% else %} |
| exception_state.ThrowTypeError("cannot convert to dictionary."); |
| return; |
| {% endif %} |
| } |
| v8::Local<v8::Object> v8Object = v8_value.As<v8::Object>(); |
| ALLOW_UNUSED_LOCAL(v8Object); |
| |
| {% if parent_v8_class %} |
| {{parent_v8_class}}::ToImpl(isolate, v8_value, impl, exception_state); |
| if (exception_state.HadException()) |
| return; |
| |
| {% endif %} |
| |
| {# Declare local variables only when the dictionary has members to avoid unused variable warnings. #} |
| {% if members %} |
| const auto* keys = eternal{{v8_class}}Keys(isolate).data(); |
| v8::TryCatch block(isolate); |
| v8::Local<v8::Context> context = isolate->GetCurrentContext(); |
| {% if has_origin_trial_members %} |
| ExecutionContext* executionContext = ToExecutionContext(context); |
| DCHECK(executionContext); |
| {% endif %}{# has_origin_trial_members #} |
| {% endif %}{# members #} |
| {% for origin_trial_test, origin_trial_member_list in members | stringifykeygroupby('origin_trial_feature_name') %} |
| {% filter origin_trial_enabled(origin_trial_test, "executionContext") %} |
| {% for feature_name, member_list in origin_trial_member_list | stringifykeygroupby('runtime_enabled_feature_name') %} |
| {% filter runtime_enabled(feature_name) %} |
| {% for member in member_list %} |
| v8::Local<v8::Value> {{member.v8_value}}; |
| if (!v8Object->Get(context, keys[{{members.index(member)}}].Get(isolate)).ToLocal(&{{member.v8_value}})) { |
| exception_state.RethrowV8Exception(block.Exception()); |
| return; |
| } |
| if ({{member.v8_value}}.IsEmpty() || {{member.v8_value}}->IsUndefined()) { |
| {% if member.is_required %} |
| exception_state.ThrowTypeError("required member {{member.name}} is undefined."); |
| return; |
| {% else %} |
| // Do nothing. |
| {% endif %} |
| {% if member.is_nullable and not member.is_string_type %}{# String types handle null via V8StringResource #} |
| } else if ({{member.v8_value}}->IsNull()) { |
| impl->{{member.null_setter_name}}(); |
| {% endif %} |
| } else { |
| {% if member.deprecate_as %} |
| Deprecation::CountDeprecation(CurrentExecutionContext(isolate), WebFeature::k{{member.deprecate_as}}); |
| {% endif %} |
| {% if member.is_callback_function_type %} |
| if (!{{member.v8_value}}->IsFunction()) { |
| exception_state.ThrowTypeError("member {{member.name}} is not a function."); |
| return; |
| } |
| {% endif %} |
| {{v8_value_to_local_cpp_value(member) | trim | indent}} |
| {% if member.is_interface_type %} |
| if (!{{member.cpp_value}}) { |
| exception_state.ThrowTypeError("member {{member.name}} is not of type {{member.idl_type}}."); |
| return; |
| } |
| {% endif %} |
| {% if member.enum_values %} |
| {{declare_enum_validation_variable(member.enum_values) | trim | indent}} |
| if (!IsValidEnum({{member.cpp_value}}, kValidValues, base::size(kValidValues), "{{member.enum_type}}", exception_state)) |
| return; |
| {% endif %} |
| impl->{{member.setter_name}}({{member.cpp_value}}); |
| } |
| |
| {% endfor %} |
| {% endfilter %}{# runtime_enabled #} |
| |
| {% endfor %}{# origin_trial_member_list grouped by runtime_enabled #} |
| {% endfilter %}{# origin_trial_enabled #} |
| |
| {% endfor %}{# members grouped by origin_trial_enabled #} |
| } |
| |
| v8::Local<v8::Value> {{cpp_class}}::ToV8Impl(v8::Local<v8::Object> creationContext, v8::Isolate* isolate) const { |
| v8::Local<v8::Object> v8Object = v8::Object::New(isolate); |
| if (!toV8{{cpp_class}}(this, v8Object, creationContext, isolate)) |
| return v8::Undefined(isolate); |
| return v8Object; |
| } |
| |
| bool toV8{{cpp_class}}(const {{cpp_class}}* impl, v8::Local<v8::Object> dictionary, v8::Local<v8::Object> creationContext, v8::Isolate* isolate) { |
| {% if parent_v8_class %} |
| if (!toV8{{parent_cpp_class}}(impl, dictionary, creationContext, isolate)) |
| return false; |
| |
| {% endif %} |
| {% if members %} |
| const auto* keys = eternal{{v8_class}}Keys(isolate).data(); |
| v8::Local<v8::Context> context = isolate->GetCurrentContext(); |
| |
| auto create_property = [dictionary, context, keys, isolate]( |
| size_t key_index, v8::Local<v8::Value> value) { |
| bool added_property; |
| v8::Local<v8::Name> key = keys[key_index].Get(isolate); |
| if (!dictionary->CreateDataProperty(context, key, value) |
| .To(&added_property)) { |
| return false; |
| } |
| return added_property; |
| }; |
| |
| {% if has_origin_trial_members %} |
| ExecutionContext* executionContext = ToExecutionContext(context); |
| DCHECK(executionContext); |
| {% endif %}{# has_origin_trial_members #} |
| {% endif %}{# members #} |
| {% for origin_trial_test, origin_trial_member_list in members | stringifykeygroupby('origin_trial_feature_name') %} |
| {% filter origin_trial_enabled(origin_trial_test, "executionContext") %} |
| {% for feature_name, member_list in origin_trial_member_list | stringifykeygroupby('runtime_enabled_feature_name') %} |
| {% filter runtime_enabled(feature_name) %} |
| {% for member in member_list %} |
| v8::Local<v8::Value> {{member.v8_value}}; |
| bool {{member.has_value_or_default}} = false; |
| if (impl->{{member.has_method_name}}()) { |
| {% if member.is_object %} |
| DCHECK(impl->{{member.getter_name}}().IsObject()); |
| {% endif %} |
| {{member.v8_value}} = {{member.cpp_value_to_v8_value}}; |
| {{member.has_value_or_default}} = true; |
| {% if member.v8_default_value %} |
| } else { |
| {{member.v8_value}} = {{member.v8_default_value}}; |
| {{member.has_value_or_default}} = true; |
| {% elif member.is_nullable and not member.has_explicit_presence %} |
| } else { |
| {{member.v8_value}} = v8::Null(isolate); |
| {{member.has_value_or_default}} = true; |
| {% elif member.is_required %} |
| } else { |
| NOTREACHED(); |
| {% endif %} |
| } |
| {# The _has_value_or_default variable will be optimized out. |
| If there is a default value, the compiler will notice that all branches set it to true. |
| If there is not, then the compiler will inline this call into the only branch that sets it to true. |
| Either way, the code is efficient and the variable is completely elided. #} |
| if ({{member.has_value_or_default}} && |
| !create_property({{members.index(member)}}, {{member.v8_value}})) { |
| return false; |
| } |
| |
| {% endfor %} |
| {% endfilter %}{# runtime_enabled #} |
| |
| {% endfor %}{# origin_trial_member_list grouped by runtime_enabled #} |
| {% endfilter %}{# origin_trial_enabled #} |
| |
| {% endfor %}{# members grouped by origin_trial_enabled #} |
| return true; |
| } |
| |
| {{cpp_class}}* NativeValueTraits<{{cpp_class}}>::NativeValue(v8::Isolate* isolate, v8::Local<v8::Value> value, ExceptionState& exception_state) { |
| {{cpp_class}}* impl = MakeGarbageCollected<{{cpp_class}}>(); |
| {{v8_class}}::ToImpl(isolate, value, impl, exception_state); |
| return impl; |
| } |
| |
| } // namespace blink |
| |
| {% endfilter %}{# format_blink_cpp_source_code #} |