blob: 42ef29d5bc921f172d7ca2f9081b3d4aff1fe4d2 [file] [log] [blame]
{% 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 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, base::size(kKeys));
}
{% endif %}
{% from 'utilities.cc.tmpl' import v8_value_to_local_cpp_value %}
void {{v8_class}}::ToImpl(v8::Isolate* isolate, v8::Local<v8::Value> v8Value, {{cpp_class}}& impl, ExceptionState& exceptionState) {
if (IsUndefinedOrNull(v8Value)) {
{% if required_member_names %}
exceptionState.ThrowTypeError("Missing required member(s): {{required_member_names|join(', ')}}.");
{% endif %}
return;
}
if (!v8Value->IsObject()) {
{% if use_permissive_dictionary_conversion %}
// Do nothing.
return;
{% else %}
exceptionState.ThrowTypeError("cannot convert to dictionary.");
return;
{% endif %}
}
v8::Local<v8::Object> v8Object = v8Value.As<v8::Object>();
ALLOW_UNUSED_LOCAL(v8Object);
{% if parent_v8_class %}
{{parent_v8_class}}::ToImpl(isolate, v8Value, impl, exceptionState);
if (exceptionState.HadException())
return;
{% endif %}
{# Declare local variables only when the dictionary has members to avoid unused variable warnings. #}
{% if members %}
const v8::Eternal<v8::Name>* keys = eternal{{v8_class}}Keys(isolate);
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 | groupby('origin_trial_feature_name') %}
{% filter origin_trial_enabled(origin_trial_test, "executionContext") %}
{% for feature_name, member_list in origin_trial_member_list | groupby('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}})) {
exceptionState.RethrowV8Exception(block.Exception());
return;
}
if ({{member.v8_value}}.IsEmpty() || {{member.v8_value}}->IsUndefined()) {
{% if member.is_required %}
exceptionState.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 %}
{{v8_value_to_local_cpp_value(member) | trim | indent}}
{% if member.is_interface_type %}
if (!{{member.cpp_value}}) {
exceptionState.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}}, validValues, base::size(validValues), "{{member.enum_type}}", exceptionState))
return;
{% elif member.is_object %}
if (!{{member.cpp_value}}.IsObject()) {
exceptionState.ThrowTypeError("member {{member.name}} is not an object.");
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 v8::Eternal<v8::Name>* keys = eternal{{v8_class}}Keys(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 | groupby('origin_trial_feature_name') %}
{% filter origin_trial_enabled(origin_trial_test, "executionContext") %}
{% for feature_name, member_list in origin_trial_member_list | groupby('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}} &&
!V8CallBoolean(dictionary->CreateDataProperty(context, keys[{{members.index(member)}}].Get(isolate), {{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& exceptionState) {
{{cpp_class}} impl;
{{v8_class}}::ToImpl(isolate, value, impl, exceptionState);
return impl;
}
} // namespace blink
{% endfilter %}{# format_blink_cpp_source_code #}