blob: 0ef5eab46189b62a5a6937d0c57773b6e77e9618 [file] [log] [blame]
/*
* Copyright (C) 2017 Google Inc. All rights reserved.
* Copyright (C) 2012 Ericsson AB. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef THIRD_PARTY_BLINK_RENDERER_BINDINGS_CORE_V8_V8_BINDING_FOR_CORE_H_
#define THIRD_PARTY_BLINK_RENDERER_BINDINGS_CORE_V8_V8_BINDING_FOR_CORE_H_
#include "third_party/blink/renderer/bindings/core/v8/native_value_traits.h"
#include "third_party/blink/renderer/bindings/core/v8/script_value.h"
#include "third_party/blink/renderer/bindings/core/v8/to_v8_for_core.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_script_runner.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_string_resource.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/dom/node.h"
#include "third_party/blink/renderer/core/typed_arrays/array_buffer_view_helpers.h"
#include "third_party/blink/renderer/platform/bindings/dom_data_store.h"
#include "third_party/blink/renderer/platform/bindings/dom_wrapper_world.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
#include "third_party/blink/renderer/platform/bindings/script_state.h"
#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
#include "third_party/blink/renderer/platform/bindings/v8_binding.h"
#include "third_party/blink/renderer/platform/bindings/v8_binding_macros.h"
#include "third_party/blink/renderer/platform/bindings/v8_per_isolate_data.h"
#include "third_party/blink/renderer/platform/bindings/v8_throw_exception.h"
#include "third_party/blink/renderer/platform/bindings/v8_value_cache.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/wtf/text/atomic_string.h"
#include "third_party/blink/renderer/platform/wtf/text/string_view.h"
#include "v8/include/v8.h"
namespace blink {
// This file contains core-specific bindings utility functions. For functions
// that are core independent, see platform/bindings/V8Binding.h. When adding a
// new utility function, consider adding it to V8Binding.h instead unless it has
// dependencies to core/.
class DOMWindow;
class ExceptionState;
class ExecutionContext;
class FlexibleArrayBufferView;
class Frame;
class LocalDOMWindow;
class LocalFrame;
class XPathNSResolver;
// Determines how a V8 -> C++ union conversion should be performed: when the
// JavaScript value being converted is either undefined or null, kNullable will
// stop the conversion attempt and the union's IsNull() method will return true.
// If kNotNullable is used, the other conversion steps listed in
// https://heycam.github.io/webidl/#es-union will continue being attempted.
enum class UnionTypeConversionMode {
kNullable,
kNotNullable,
};
template <typename CallbackInfo, typename T>
inline void V8SetReturnValue(const CallbackInfo& callbackInfo,
NotShared<T> notShared) {
V8SetReturnValue(callbackInfo, notShared.View());
}
template <typename CallbackInfo, typename T>
inline void V8SetReturnValueFast(const CallbackInfo& callbackInfo,
NotShared<T> notShared,
const ScriptWrappable* wrappable) {
V8SetReturnValueFast(callbackInfo, notShared.View(), wrappable);
}
template <typename CallbackInfo, typename T>
inline void V8SetReturnValue(const CallbackInfo& callback_info,
MaybeShared<T> maybe_shared) {
V8SetReturnValue(callback_info, maybe_shared.View());
}
template <typename CallbackInfo, typename T>
inline void V8SetReturnValueFast(const CallbackInfo& callback_info,
MaybeShared<T> maybe_shared,
const ScriptWrappable* wrappable) {
V8SetReturnValueFast(callback_info, maybe_shared.View(), wrappable);
}
// Specialized overload, used by interface indexed property handlers in their
// descriptor callbacks, which need an actual V8 Object with the properties of
// a property descriptor.
CORE_EXPORT void V8SetReturnValue(const v8::PropertyCallbackInfo<v8::Value>&,
const v8::PropertyDescriptor&);
// Conversion flags, used in toIntXX/toUIntXX.
enum IntegerConversionConfiguration {
kNormalConversion,
kClamp,
kEnforceRange,
};
// Convert a value to a boolean.
inline bool ToBoolean(v8::Isolate* isolate,
v8::Local<v8::Value> value,
ExceptionState& exception_state) {
if (LIKELY(value->IsBoolean()))
return value.As<v8::Boolean>()->Value();
return value->BooleanValue(isolate);
}
// Convert a value to a 8-bit signed integer. The conversion fails if the
// value cannot be converted to a number or the range violated per WebIDL:
// http://www.w3.org/TR/WebIDL/#es-byte
CORE_EXPORT int8_t ToInt8(v8::Isolate*,
v8::Local<v8::Value>,
IntegerConversionConfiguration,
ExceptionState&);
// Convert a value to a 8-bit unsigned integer. The conversion fails if the
// value cannot be converted to a number or the range violated per WebIDL:
// http://www.w3.org/TR/WebIDL/#es-octet
CORE_EXPORT uint8_t ToUInt8(v8::Isolate*,
v8::Local<v8::Value>,
IntegerConversionConfiguration,
ExceptionState&);
// Convert a value to a 16-bit signed integer. The conversion fails if the
// value cannot be converted to a number or the range violated per WebIDL:
// http://www.w3.org/TR/WebIDL/#es-short
CORE_EXPORT int16_t ToInt16(v8::Isolate*,
v8::Local<v8::Value>,
IntegerConversionConfiguration,
ExceptionState&);
// Convert a value to a 16-bit unsigned integer. The conversion fails if the
// value cannot be converted to a number or the range violated per WebIDL:
// http://www.w3.org/TR/WebIDL/#es-unsigned-short
CORE_EXPORT uint16_t ToUInt16(v8::Isolate*,
v8::Local<v8::Value>,
IntegerConversionConfiguration,
ExceptionState&);
// Convert a value to a 32-bit signed integer. The conversion fails if the
// value cannot be converted to a number or the range violated per WebIDL:
// http://www.w3.org/TR/WebIDL/#es-long
CORE_EXPORT int32_t ToInt32Slow(v8::Isolate*,
v8::Local<v8::Value>,
IntegerConversionConfiguration,
ExceptionState&);
inline int32_t ToInt32(v8::Isolate* isolate,
v8::Local<v8::Value> value,
IntegerConversionConfiguration configuration,
ExceptionState& exception_state) {
// Fast case. The value is already a 32-bit integer.
if (LIKELY(value->IsInt32()))
return value.As<v8::Int32>()->Value();
return ToInt32Slow(isolate, value, configuration, exception_state);
}
// Convert a value to a 32-bit unsigned integer. The conversion fails if the
// value cannot be converted to a number or the range violated per WebIDL:
// http://www.w3.org/TR/WebIDL/#es-unsigned-long
CORE_EXPORT uint32_t ToUInt32Slow(v8::Isolate*,
v8::Local<v8::Value>,
IntegerConversionConfiguration,
ExceptionState&);
inline uint32_t ToUInt32(v8::Isolate* isolate,
v8::Local<v8::Value> value,
IntegerConversionConfiguration configuration,
ExceptionState& exception_state) {
// Fast case. The value is already a 32-bit unsigned integer.
if (LIKELY(value->IsUint32()))
return value.As<v8::Uint32>()->Value();
// Fast case. The value is a 32-bit signed integer with NormalConversion
// configuration.
if (LIKELY(value->IsInt32() && configuration == kNormalConversion))
return value.As<v8::Int32>()->Value();
return ToUInt32Slow(isolate, value, configuration, exception_state);
}
// Convert a value to a 64-bit signed integer. The conversion fails if the
// value cannot be converted to a number or the range violated per WebIDL:
// http://www.w3.org/TR/WebIDL/#es-long-long
CORE_EXPORT int64_t ToInt64Slow(v8::Isolate*,
v8::Local<v8::Value>,
IntegerConversionConfiguration,
ExceptionState&);
inline int64_t ToInt64(v8::Isolate* isolate,
v8::Local<v8::Value> value,
IntegerConversionConfiguration configuration,
ExceptionState& exception_state) {
// Clamping not supported for int64_t/long long int. See
// Source/wtf/MathExtras.h.
DCHECK_NE(configuration, kClamp);
// Fast case. The value is a 32-bit integer.
if (LIKELY(value->IsInt32()))
return value.As<v8::Int32>()->Value();
return ToInt64Slow(isolate, value, configuration, exception_state);
}
// Convert a value to a 64-bit unsigned integer. The conversion fails if the
// value cannot be converted to a number or the range violated per WebIDL:
// http://www.w3.org/TR/WebIDL/#es-unsigned-long-long
CORE_EXPORT uint64_t ToUInt64Slow(v8::Isolate*,
v8::Local<v8::Value>,
IntegerConversionConfiguration,
ExceptionState&);
inline uint64_t ToUInt64(v8::Isolate* isolate,
v8::Local<v8::Value> value,
IntegerConversionConfiguration configuration,
ExceptionState& exception_state) {
// Fast case. The value is a 32-bit unsigned integer.
if (LIKELY(value->IsUint32()))
return value.As<v8::Uint32>()->Value();
if (LIKELY(value->IsInt32() && configuration == kNormalConversion))
return value.As<v8::Int32>()->Value();
return ToUInt64Slow(isolate, value, configuration, exception_state);
}
// NaNs and +/-Infinity should be 0, otherwise modulo 2^64.
// Step 8 - 12 of https://heycam.github.io/webidl/#abstract-opdef-converttoint
inline uint64_t DoubleToInteger(double d) {
if (std::isnan(d) || std::isinf(d))
return 0;
constexpr uint64_t kMaxULL = std::numeric_limits<uint64_t>::max();
// -2^{64} < fmod_value < 2^{64}.
double fmod_value = fmod(trunc(d), kMaxULL + 1.0);
if (fmod_value >= 0) {
// 0 <= fmod_value < 2^{64}.
// 0 <= value < 2^{64}. This cast causes no loss.
return static_cast<uint64_t>(fmod_value);
}
// -2^{64} < fmod_value < 0.
// 0 < fmod_value_in_unsigned_long_long < 2^{64}. This cast causes no loss.
uint64_t fmod_value_in_unsigned_long_long =
static_cast<uint64_t>(-fmod_value);
// -1 < (kMaxULL - fmod_value_in_unsigned_long_long) < 2^{64} - 1.
// 0 < value < 2^{64}.
return kMaxULL - fmod_value_in_unsigned_long_long + 1;
}
// Convert a value to a double precision float, which might fail.
CORE_EXPORT double ToDoubleSlow(v8::Isolate*,
v8::Local<v8::Value>,
ExceptionState&);
inline double ToDouble(v8::Isolate* isolate,
v8::Local<v8::Value> value,
ExceptionState& exception_state) {
if (LIKELY(value->IsNumber()))
return value.As<v8::Number>()->Value();
return ToDoubleSlow(isolate, value, exception_state);
}
// Convert a value to a double precision float, throwing on non-finite values.
CORE_EXPORT double ToRestrictedDouble(v8::Isolate*,
v8::Local<v8::Value>,
ExceptionState&);
// Convert a value to a single precision float, which might fail.
inline float ToFloat(v8::Isolate* isolate,
v8::Local<v8::Value> value,
ExceptionState& exception_state) {
double double_value = ToDouble(isolate, value, exception_state);
if (exception_state.HadException())
return 0;
using Limits = std::numeric_limits<float>;
if (UNLIKELY(double_value > Limits::max()))
return Limits::infinity();
if (UNLIKELY(double_value < Limits::lowest()))
return -Limits::infinity();
return static_cast<float>(double_value);
}
// Convert a value to a single precision float, throwing on non-finite values.
CORE_EXPORT float ToRestrictedFloat(v8::Isolate*,
v8::Local<v8::Value>,
ExceptionState&);
inline base::Optional<base::Time> ToCoreNullableDate(
v8::Isolate* isolate,
v8::Local<v8::Value> object,
ExceptionState& exception_state) {
// https://html.spec.whatwg.org/C/#common-input-element-apis:dom-input-valueasdate-2
// ... otherwise if the new value is null or a Date object representing the
// NaN time value, then set the value of the element to the empty string;
// We'd like to return same values for |null| and an invalid Date object.
if (object->IsNull())
return base::nullopt;
if (!object->IsDate()) {
exception_state.ThrowTypeError("The provided value is not a Date.");
return base::nullopt;
}
double time_value = object.As<v8::Date>()->ValueOf();
if (!std::isfinite(time_value))
return base::nullopt;
return base::Time::FromJsTime(time_value);
}
// USVString conversion helper.
CORE_EXPORT String ReplaceUnmatchedSurrogates(String);
// FIXME: Remove the special casing for XPathNSResolver.
XPathNSResolver* ToXPathNSResolver(ScriptState*, v8::Local<v8::Value>);
template <typename IDLType>
VectorOf<typename NativeValueTraits<IDLType>::ImplType> ToImplArguments(
const v8::FunctionCallbackInfo<v8::Value>& info,
int start_index,
ExceptionState& exception_state) {
using TraitsType = NativeValueTraits<IDLType>;
using VectorType = VectorOf<typename TraitsType::ImplType>;
int length = info.Length();
VectorType result;
if (start_index < length) {
if (static_cast<size_t>(length - start_index) > VectorType::MaxCapacity()) {
exception_state.ThrowRangeError("Array length exceeds supported limit.");
return VectorType();
}
result.ReserveInitialCapacity(length - start_index);
for (int i = start_index; i < length; ++i) {
result.UncheckedAppend(
TraitsType::NativeValue(info.GetIsolate(), info[i], exception_state));
if (exception_state.HadException())
return VectorType();
}
}
return result;
}
template <typename IDLType>
VectorOf<typename NativeValueTraits<IDLType>::ImplType> ToImplArguments(
const v8::FunctionCallbackInfo<v8::Value>& info,
int start_index,
ExceptionState& exception_state,
ExecutionContext* execution_context) {
using TraitsType = NativeValueTraits<IDLType>;
using VectorType = VectorOf<typename TraitsType::ImplType>;
int length = info.Length();
VectorType result;
if (start_index < length) {
if (static_cast<size_t>(length - start_index) > VectorType::MaxCapacity()) {
exception_state.ThrowRangeError("Array length exceeds supported limit.");
return VectorType();
}
result.ReserveInitialCapacity(length - start_index);
for (int i = start_index; i < length; ++i) {
result.UncheckedAppend(TraitsType::NativeValue(
info.GetIsolate(), info[i], exception_state, execution_context));
if (exception_state.HadException())
return VectorType();
}
}
return result;
}
// The functions below implement low-level abstract ES operations for dealing
// with iterators. Most code should use ScriptIterator instead.
//
// Retrieves an ES object's @@iterator method by calling
// ? GetMethod(V, @@iterator)
// per https://tc39.es/ecma262/#sec-getmethod
// Returns the iterator method for an object, or an empty v8::Local if the
// method is null or undefined.
CORE_EXPORT v8::Local<v8::Function> GetEsIteratorMethod(v8::Isolate*,
v8::Local<v8::Object>,
ExceptionState&);
// Retrieves an iterator object from a given ES object whose @@iterator method
// has been retrieved via GetEsIteratorMethod(). It essentially calls
// ? GetIterator(iterable, sync, method)
// per https://tc39.es/ecma262/#sec-getiterator
CORE_EXPORT v8::Local<v8::Object> GetEsIteratorWithMethod(
v8::Isolate*,
v8::Local<v8::Function>,
v8::Local<v8::Object>,
ExceptionState&);
// Wrapper around GetEsIteratorMethod(). It returns true if a given ES value is
// an object that has a valid @@iterator property (i.e. the property exists and
// is callable).
CORE_EXPORT bool HasCallableIteratorSymbol(v8::Isolate*,
v8::Local<v8::Value>,
ExceptionState&);
CORE_EXPORT v8::Isolate* ToIsolate(const LocalFrame*);
CORE_EXPORT DOMWindow* ToDOMWindow(v8::Isolate*, v8::Local<v8::Value>);
CORE_EXPORT LocalDOMWindow* ToLocalDOMWindow(v8::Local<v8::Context>);
LocalDOMWindow* EnteredDOMWindow(v8::Isolate*);
LocalDOMWindow* IncumbentDOMWindow(v8::Isolate*);
CORE_EXPORT LocalDOMWindow* CurrentDOMWindow(v8::Isolate*);
CORE_EXPORT ExecutionContext* ToExecutionContext(v8::Local<v8::Context>);
CORE_EXPORT void RegisterToExecutionContextForModules(ExecutionContext* (
*to_execution_context_for_modules)(v8::Local<v8::Context>));
CORE_EXPORT ExecutionContext* CurrentExecutionContext(v8::Isolate*);
// Returns a V8 context associated with a ExecutionContext and a
// DOMWrapperWorld. This method returns an empty context if there is no frame
// or the frame is already detached.
CORE_EXPORT v8::Local<v8::Context> ToV8Context(ExecutionContext*,
DOMWrapperWorld&);
// Returns a V8 context associated with a Frame and a DOMWrapperWorld.
// This method returns an empty context if the frame is already detached.
CORE_EXPORT v8::Local<v8::Context> ToV8Context(LocalFrame*, DOMWrapperWorld&);
// Like toV8Context but also returns the context if the frame is already
// detached.
CORE_EXPORT v8::Local<v8::Context> ToV8ContextEvenIfDetached(LocalFrame*,
DOMWrapperWorld&);
// These methods can return nullptr if the context associated with the
// ScriptState has already been detached.
CORE_EXPORT ScriptState* ToScriptState(ExecutionContext*, DOMWrapperWorld&);
CORE_EXPORT ScriptState* ToScriptState(LocalFrame*, DOMWrapperWorld&);
// Do not use this method unless you are sure you should use the main world's
// ScriptState
CORE_EXPORT ScriptState* ToScriptStateForMainWorld(LocalFrame*);
// Returns the frame object of the window object associated with
// a context, if the window is currently being displayed in a Frame.
CORE_EXPORT LocalFrame* ToLocalFrameIfNotDetached(v8::Local<v8::Context>);
CORE_EXPORT void ToFlexibleArrayBufferView(v8::Isolate*,
v8::Local<v8::Value>,
FlexibleArrayBufferView&);
CORE_EXPORT bool IsValidEnum(const String& value,
const char* const* valid_values,
size_t length,
const String& enum_name,
ExceptionState&);
CORE_EXPORT bool IsValidEnum(const Vector<String>& values,
const char* const* valid_values,
size_t length,
const String& enum_name,
ExceptionState&);
CORE_EXPORT v8::Local<v8::Value> FromJSONString(v8::Isolate*,
v8::Local<v8::Context>,
const String& stringified_json,
ExceptionState&);
// Ensure that a typed array value is not backed by a SharedArrayBuffer. If it
// is, an exception will be thrown. The return value will use the NotShared
// wrapper type.
template <typename NotSharedType>
NotSharedType ToNotShared(v8::Isolate* isolate,
v8::Local<v8::Value> value,
ExceptionState& exception_state) {
using DOMTypedArray = typename NotSharedType::TypedArrayType;
DOMTypedArray* dom_typed_array =
V8TypeOf<DOMTypedArray>::Type::ToImplWithTypeCheck(isolate, value);
if (dom_typed_array && dom_typed_array->IsShared()) {
exception_state.ThrowTypeError(
"The provided ArrayBufferView value must not be shared.");
return NotSharedType();
}
return NotSharedType(dom_typed_array);
}
// Wrap a typed array value in MaybeShared<>, to signify that it may be backed
// by a SharedArrayBuffer.
template <typename MaybeSharedType>
MaybeSharedType ToMaybeShared(v8::Isolate* isolate,
v8::Local<v8::Value> value,
ExceptionState& exception_state) {
using DOMTypedArray = typename MaybeSharedType::TypedArrayType;
DOMTypedArray* dom_typed_array =
V8TypeOf<DOMTypedArray>::Type::ToImplWithTypeCheck(isolate, value);
return MaybeSharedType(dom_typed_array);
}
CORE_EXPORT Vector<String> GetOwnPropertyNames(v8::Isolate*,
const v8::Local<v8::Object>&,
ExceptionState&);
v8::MicrotaskQueue* ToMicrotaskQueue(ExecutionContext*);
v8::MicrotaskQueue* ToMicrotaskQueue(ScriptState*);
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_BINDINGS_CORE_V8_V8_BINDING_FOR_CORE_H_