| {% 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 #} |