blob: 9b34872e79fb095f8d116bfd36d4a6c36a822775 [file] [log] [blame]
{% filter format_blink_cpp_source_code %}
{% include 'copyright_block.txt' %}
#include "{{this_include_header_name}}"
{% for filename in cpp_includes %}
#include "{{filename}}"
{% endfor %}
namespace blink {
{# TODO(yukishiino): Remove |method.is_custom| once we support the author
function\'s return value. #}
{% for method in methods if not method.is_custom %}
{% set return_success = 'return' if method.cpp_type == 'void' else 'return true' %}
{% set return_failure = 'return' if method.cpp_type == 'void' else 'return false' %}
{{method.cpp_type}} {{v8_class}}::{{method.name}}({{method.argument_declarations | join(', ')}}) {
// This function implements "call a user object's operation".
// https://heycam.github.io/webidl/#call-a-user-objects-operation
{# TODO(yukishiino): Add |ScriptWrappable* callback_this_value| as the first
argument of the IDL operations. The callsites must pass callback_this_value
explicitly. #}
ScriptWrappable* callback_this_value = nullptr;
if (!IsCallbackFunctionRunnable(CallbackRelevantScriptState())) {
{{return_success}};
}
// step 7. Prepare to run script with relevant settings.
ScriptState::Scope callback_relevant_context_scope(
CallbackRelevantScriptState());
// step 8. Prepare to run a callback with stored settings.
{# TODO(yukishiino): Callback interface type value must make the incumbent
environment alive, i.e. the reference to v8::Context must be strong. #}
if (IncumbentScriptState()->GetContext().IsEmpty()) {
{{return_success}};
}
v8::Context::BackupIncumbentScope backup_incumbent_scope(
IncumbentScriptState()->GetContext());
v8::TryCatch try_catch(GetIsolate());
try_catch.SetVerbose(true);
v8::Local<v8::Function> function;
if (IsCallbackObjectCallable()) {
// step 9.1. If value's interface is a single operation callback interface
// and !IsCallable(O) is true, then set X to O.
function = CallbackObject().As<v8::Function>();
} else {
// step 9.2.1. Let getResult be Get(O, opName).
// step 9.2.2. If getResult is an abrupt completion, set completion to
// getResult and jump to the step labeled return.
v8::Local<v8::Value> value;
if (!CallbackObject()->Get(CallbackRelevantScriptState()->GetContext(),
V8String(GetIsolate(), "{{method.name}}"))
.ToLocal(&value)) {
{{return_failure}};
}
// step 10. If !IsCallable(X) is false, then set completion to a new
// Completion{[[Type]]: throw, [[Value]]: a newly created TypeError
// object, [[Target]]: empty}, and jump to the step labeled return.
if (!value->IsFunction()) {
V8ThrowException::ThrowTypeError(
GetIsolate(),
ExceptionMessages::FailedToExecute(
"{{method.name}}",
"{{cpp_class}}",
"The provided callback is not callable."));
{{return_failure}};
}
}
v8::Local<v8::Value> this_arg;
if (!IsCallbackObjectCallable()) {
// step 11. If value's interface is not a single operation callback
// interface, or if !IsCallable(O) is false, set thisArg to O (overriding
// the provided value).
this_arg = CallbackObject();
} else if (!callback_this_value) {
// step 2. If thisArg was not given, let thisArg be undefined.
this_arg = v8::Undefined(GetIsolate());
} else {
this_arg = ToV8(callback_this_value, CallbackRelevantScriptState());
}
{% for argument in arguments if argument.enum_values %}
// Enum values provided by Blink must be valid, otherwise typo.
#if DCHECK_IS_ON()
{
{% set valid_enum_variables = 'valid_' + argument.name + '_values' %}
{{declare_enum_validation_variable(argument.enum_values, valid_enum_variables) | indent(4)}}
ExceptionState exception_state(GetIsolate(),
ExceptionState::kExecutionContext,
"{{cpp_class}}",
"{{method.name}}");
if (!IsValidEnum({{argument.name}}, {{valid_enum_variables}}, WTF_ARRAY_LENGTH({{valid_enum_variables}}), "{{argument.enum_type}}", exception_state)) {
NOTREACHED();
return false;
}
}
#endif
{% endfor %}
// step 12. Let esArgs be the result of converting args to an ECMAScript
// arguments list. If this throws an exception, set completion to the
// completion value representing the thrown exception and jump to the step
// labeled return.
v8::Local<v8::Object> argument_creation_context =
CallbackRelevantScriptState()->GetContext()->Global();
ALLOW_UNUSED_LOCAL(argument_creation_context);
{% for argument in method.arguments %}
v8::Local<v8::Value> {{argument.handle}} = {{argument.cpp_value_to_v8_value}};
{% endfor %}
{% if method.arguments %}
v8::Local<v8::Value> argv[] = { {{method.arguments | join(', ', 'handle')}} };
{% else %}
{# Zero-length arrays are ill-formed in C++. #}
v8::Local<v8::Value> *argv = nullptr;
{% endif %}
// step 13. Let callResult be Call(X, thisArg, esArgs).
v8::Local<v8::Value> call_result;
if (!V8ScriptRunner::CallFunction(
function,
ExecutionContext::From(CallbackRelevantScriptState()),
this_arg,
{{method.arguments | length}},
argv,
GetIsolate()).ToLocal(&call_result)) {
// step 14. If callResult is an abrupt completion, set completion to
// callResult and jump to the step labeled return.
{{return_failure}};
}
// step 15. Set completion to the result of converting callResult.[[Value]] to
// an IDL value of the same type as the operation's return type.
{% if method.idl_type == 'void' %}
ALLOW_UNUSED_LOCAL(call_result);
return;
{% else %}
{
ExceptionState exception_state(GetIsolate(),
ExceptionState::kExecutionContext,
"{{cpp_class}}",
"{{method.name}}");
{% set idl_return_type = 'IDLBoolean' if method.cpp_type == 'bool' %}
auto native_result =
NativeValueTraits<{{idl_return_type}}>::NativeValue(
GetIsolate(), call_result, exception_state);
ALLOW_UNUSED_LOCAL(native_result);
return !exception_state.HadException();
}
{% endif %}
}
{% endfor %}
} // namespace blink
{% endfilter %}{# format_blink_cpp_source_code #}