blob: ef09c6aad52ebdb0eda5ffa66ba3225744f52314 [file] [log] [blame]
/*
* Copyright (C) 2009 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 V8Binding_h
#define V8Binding_h
#include "bindings/core/v8/DOMDataStore.h"
#include "bindings/core/v8/DOMWrapperWorld.h"
#include "bindings/core/v8/ExceptionMessages.h"
#include "bindings/core/v8/ExceptionState.h"
#include "bindings/core/v8/ScriptValue.h"
#include "bindings/core/v8/ScriptWrappable.h"
#include "bindings/core/v8/V8BindingMacros.h"
#include "bindings/core/v8/V8PerIsolateData.h"
#include "bindings/core/v8/V8StringResource.h"
#include "bindings/core/v8/V8ThrowException.h"
#include "bindings/core/v8/V8ValueCache.h"
#include "platform/heap/Heap.h"
#include "wtf/GetPtr.h"
#include "wtf/text/AtomicString.h"
#include <v8.h>
namespace blink {
class LocalDOMWindow;
class Document;
class EventListener;
class ExecutionContext;
class ExceptionState;
class LocalFrame;
class NodeFilter;
class XPathNSResolver;
namespace TraceEvent {
class ConvertableToTraceFormat;
}
const int kMaxRecursionDepth = 22;
// Helpers for throwing JavaScript TypeErrors for arity mismatches.
void setArityTypeError(ExceptionState&, const char* valid, unsigned provided);
v8::Local<v8::Value> createMinimumArityTypeErrorForMethod(v8::Isolate*, const char* method, const char* type, unsigned expected, unsigned provided);
v8::Local<v8::Value> createMinimumArityTypeErrorForConstructor(v8::Isolate*, const char* type, unsigned expected, unsigned provided);
void setMinimumArityTypeError(ExceptionState&, unsigned expected, unsigned provided);
v8::ArrayBuffer::Allocator* v8ArrayBufferAllocator();
template<typename CallbackInfo, typename S>
inline void v8SetReturnValue(const CallbackInfo& info, const v8::Persistent<S>& handle)
{
info.GetReturnValue().Set(handle);
}
template<typename CallbackInfo, typename S>
inline void v8SetReturnValue(const CallbackInfo& info, const v8::Handle<S> handle)
{
info.GetReturnValue().Set(handle);
}
template<typename CallbackInfo>
inline void v8SetReturnValue(const CallbackInfo& info, bool value)
{
info.GetReturnValue().Set(value);
}
template<typename CallbackInfo>
inline void v8SetReturnValue(const CallbackInfo& info, double value)
{
info.GetReturnValue().Set(value);
}
template<typename CallbackInfo>
inline void v8SetReturnValue(const CallbackInfo& info, int32_t value)
{
info.GetReturnValue().Set(value);
}
template<typename CallbackInfo>
inline void v8SetReturnValue(const CallbackInfo& info, uint32_t value)
{
info.GetReturnValue().Set(value);
}
template<typename CallbackInfo>
inline void v8SetReturnValueBool(const CallbackInfo& info, bool v)
{
info.GetReturnValue().Set(v);
}
template<typename CallbackInfo>
inline void v8SetReturnValueInt(const CallbackInfo& info, int v)
{
info.GetReturnValue().Set(v);
}
template<typename CallbackInfo>
inline void v8SetReturnValueUnsigned(const CallbackInfo& info, unsigned v)
{
info.GetReturnValue().Set(v);
}
template<typename CallbackInfo>
inline void v8SetReturnValueNull(const CallbackInfo& info)
{
info.GetReturnValue().SetNull();
}
template<typename CallbackInfo>
inline void v8SetReturnValueUndefined(const CallbackInfo& info)
{
info.GetReturnValue().SetUndefined();
}
template<typename CallbackInfo>
inline void v8SetReturnValueEmptyString(const CallbackInfo& info)
{
info.GetReturnValue().SetEmptyString();
}
template<typename CallbackInfo>
inline void v8SetReturnValueString(const CallbackInfo& info, const String& string, v8::Isolate* isolate)
{
if (string.isNull()) {
v8SetReturnValueEmptyString(info);
return;
}
V8PerIsolateData::from(isolate)->stringCache()->setReturnValueFromString(info.GetReturnValue(), string.impl());
}
template<typename CallbackInfo>
inline void v8SetReturnValueStringOrNull(const CallbackInfo& info, const String& string, v8::Isolate* isolate)
{
if (string.isNull()) {
v8SetReturnValueNull(info);
return;
}
V8PerIsolateData::from(isolate)->stringCache()->setReturnValueFromString(info.GetReturnValue(), string.impl());
}
template<typename CallbackInfo>
inline void v8SetReturnValueStringOrUndefined(const CallbackInfo& info, const String& string, v8::Isolate* isolate)
{
if (string.isNull()) {
v8SetReturnValueUndefined(info);
return;
}
V8PerIsolateData::from(isolate)->stringCache()->setReturnValueFromString(info.GetReturnValue(), string.impl());
}
template<typename CallbackInfo>
inline void v8SetReturnValue(const CallbackInfo& callbackInfo, ScriptWrappable* impl)
{
if (UNLIKELY(!impl)) {
v8SetReturnValueNull(callbackInfo);
return;
}
if (DOMDataStore::setReturnValueNonTemplate(callbackInfo.GetReturnValue(), impl))
return;
v8::Handle<v8::Object> wrapper = impl->wrap(callbackInfo.Holder(), callbackInfo.GetIsolate());
v8SetReturnValue(callbackInfo, wrapper);
}
template<typename CallbackInfo>
inline void v8SetReturnValue(const CallbackInfo& callbackInfo, Node* impl)
{
if (UNLIKELY(!impl)) {
v8SetReturnValueNull(callbackInfo);
return;
}
if (DOMDataStore::setReturnValueNonTemplate(callbackInfo.GetReturnValue(), impl))
return;
v8::Handle<v8::Object> wrapper = ScriptWrappable::fromNode(impl)->wrap(callbackInfo.Holder(), callbackInfo.GetIsolate());
v8SetReturnValue(callbackInfo, wrapper);
}
template<typename CallbackInfo, typename T>
inline void v8SetReturnValue(const CallbackInfo& callbackInfo, PassRefPtr<T> impl)
{
v8SetReturnValue(callbackInfo, impl.get());
}
template<typename CallbackInfo, typename T>
inline void v8SetReturnValue(const CallbackInfo& callbackInfo, RawPtr<T> impl)
{
v8SetReturnValue(callbackInfo, impl.get());
}
template<typename CallbackInfo>
inline void v8SetReturnValueForMainWorld(const CallbackInfo& callbackInfo, ScriptWrappable* impl)
{
ASSERT(DOMWrapperWorld::current(callbackInfo.GetIsolate()).isMainWorld());
if (UNLIKELY(!impl)) {
v8SetReturnValueNull(callbackInfo);
return;
}
if (DOMDataStore::setReturnValueForMainWorldNonTemplate(callbackInfo.GetReturnValue(), impl))
return;
v8::Handle<v8::Object> wrapper = impl->wrap(callbackInfo.Holder(), callbackInfo.GetIsolate());
v8SetReturnValue(callbackInfo, wrapper);
}
template<typename CallbackInfo, typename T>
inline void v8SetReturnValueForMainWorld(const CallbackInfo& callbackInfo, PassRefPtr<T> impl)
{
v8SetReturnValueForMainWorld(callbackInfo, impl.get());
}
template<typename CallbackInfo, typename T>
inline void v8SetReturnValueForMainWorld(const CallbackInfo& callbackInfo, RawPtr<T> impl)
{
v8SetReturnValueForMainWorld(callbackInfo, impl.get());
}
template<typename CallbackInfo>
inline void v8SetReturnValueFast(const CallbackInfo& callbackInfo, ScriptWrappable* impl, const ScriptWrappable* wrappable)
{
if (UNLIKELY(!impl)) {
v8SetReturnValueNull(callbackInfo);
return;
}
if (DOMDataStore::setReturnValueFastNonTemplate(callbackInfo.GetReturnValue(), impl, callbackInfo.Holder(), wrappable))
return;
v8::Handle<v8::Object> wrapper = impl->wrap(callbackInfo.Holder(), callbackInfo.GetIsolate());
v8SetReturnValue(callbackInfo, wrapper);
}
template<typename CallbackInfo>
inline void v8SetReturnValueFast(const CallbackInfo& callbackInfo, Node* impl, const ScriptWrappable* wrappable)
{
if (UNLIKELY(!impl)) {
v8SetReturnValueNull(callbackInfo);
return;
}
if (DOMDataStore::setReturnValueFastNonTemplate(callbackInfo.GetReturnValue(), impl, callbackInfo.Holder(), wrappable))
return;
v8::Handle<v8::Object> wrapper = ScriptWrappable::fromNode(impl)->wrap(callbackInfo.Holder(), callbackInfo.GetIsolate());
v8SetReturnValue(callbackInfo, wrapper);
}
template<typename CallbackInfo>
inline void v8SetReturnValueFast(const CallbackInfo& callbackInfo, ScriptWrappable* impl, const ScriptWrappableBase*)
{
// If the third arg is not ScriptWrappable, there is no fast path.
v8SetReturnValue(callbackInfo, impl);
}
template<typename CallbackInfo, typename T, typename Wrappable>
inline void v8SetReturnValueFast(const CallbackInfo& callbackInfo, PassRefPtr<T> impl, const Wrappable* wrappable)
{
v8SetReturnValueFast(callbackInfo, impl.get(), wrappable);
}
template<typename CallbackInfo, typename T, typename Wrappable>
inline void v8SetReturnValueFast(const CallbackInfo& callbackInfo, RawPtr<T> impl, const Wrappable* wrappable)
{
v8SetReturnValueFast(callbackInfo, impl.get(), wrappable);
}
// Convert v8::String to a WTF::String. If the V8 string is not already
// an external string then it is transformed into an external string at this
// point to avoid repeated conversions.
inline String toCoreString(v8::Handle<v8::String> value)
{
return v8StringToWebCoreString<String>(value, Externalize);
}
inline String toCoreStringWithNullCheck(v8::Handle<v8::String> value)
{
if (value.IsEmpty() || value->IsNull())
return String();
return toCoreString(value);
}
inline String toCoreStringWithUndefinedOrNullCheck(v8::Handle<v8::String> value)
{
if (value.IsEmpty() || value->IsNull() || value->IsUndefined())
return String();
return toCoreString(value);
}
inline AtomicString toCoreAtomicString(v8::Handle<v8::String> value)
{
return v8StringToWebCoreString<AtomicString>(value, Externalize);
}
// This method will return a null String if the v8::Value does not contain a v8::String.
// It will not call ToString() on the v8::Value. If you want ToString() to be called,
// please use the TONATIVE_FOR_V8STRINGRESOURCE_*() macros instead.
inline String toCoreStringWithUndefinedOrNullCheck(v8::Handle<v8::Value> value)
{
if (value.IsEmpty() || !value->IsString())
return String();
return toCoreString(value.As<v8::String>());
}
// Convert a string to a V8 string.
// Return a V8 external string that shares the underlying buffer with the given
// WebCore string. The reference counting mechanism is used to keep the
// underlying buffer alive while the string is still live in the V8 engine.
inline v8::Handle<v8::String> v8String(v8::Isolate* isolate, const String& string)
{
if (string.isNull())
return v8::String::Empty(isolate);
return V8PerIsolateData::from(isolate)->stringCache()->v8ExternalString(string.impl(), isolate);
}
inline v8::Handle<v8::String> v8AtomicString(v8::Isolate* isolate, const char* str)
{
ASSERT(isolate);
return v8::String::NewFromUtf8(isolate, str, v8::String::kInternalizedString, strlen(str));
}
inline v8::Handle<v8::String> v8AtomicString(v8::Isolate* isolate, const char* str, size_t length)
{
ASSERT(isolate);
return v8::String::NewFromUtf8(isolate, str, v8::String::kInternalizedString, length);
}
inline v8::Handle<v8::Value> v8Undefined()
{
return v8::Handle<v8::Value>();
}
inline v8::Handle<v8::Value> toV8(ScriptWrappable* impl, v8::Handle<v8::Object> creationContext, v8::Isolate* isolate)
{
if (UNLIKELY(!impl))
return v8::Null(isolate);
v8::Handle<v8::Value> wrapper = DOMDataStore::getWrapperNonTemplate(impl, isolate);
if (!wrapper.IsEmpty())
return wrapper;
return impl->wrap(creationContext, isolate);
}
inline v8::Handle<v8::Value> toV8(Node* impl, v8::Handle<v8::Object> creationContext, v8::Isolate* isolate)
{
if (UNLIKELY(!impl))
return v8::Null(isolate);
v8::Handle<v8::Value> wrapper = DOMDataStore::getWrapperNonTemplate(impl, isolate);
if (!wrapper.IsEmpty())
return wrapper;
return ScriptWrappable::fromNode(impl)->wrap(creationContext, isolate);
}
template<typename T>
inline v8::Handle<v8::Value> toV8(RefPtr<T>& impl, v8::Handle<v8::Object> creationContext, v8::Isolate* isolate)
{
return toV8(impl.get(), creationContext, isolate);
}
template<typename T>
inline v8::Handle<v8::Value> toV8(PassRefPtr<T> impl, v8::Handle<v8::Object> creationContext, v8::Isolate* isolate)
{
return toV8(impl.get(), creationContext, isolate);
}
template<typename T>
inline v8::Handle<v8::Value> toV8(RawPtr<T> impl, v8::Handle<v8::Object> creationContext, v8::Isolate* isolate)
{
return toV8(impl.get(), creationContext, isolate);
}
// Converts a DOM object to a v8 value. This function is intended to be used
// internally. If you want to convert a DOM object to a V8 value,
// - Use toV8 if you can include V8X.h.
// - Use V8ValueTraits<T>::toV8Value if you cannot include V8X.h.
// Note: Including bindings/{core, modules}/v8/V8*.h from core and modules
// is fine. In such a case, perhaps toV8 is what you want.
// Note: toV8NoInline is a non-inline toV8 and V8ValueTraits::toV8Value offers
// more: You can handle value conversion generally with it.
template<typename T>
v8::Handle<v8::Value> toV8NoInline(T* impl, v8::Handle<v8::Object> creationContext, v8::Isolate*);
template <typename T>
struct V8ValueTraits {
static v8::Handle<v8::Value> toV8Value(const T& value, v8::Handle<v8::Object> creationContext, v8::Isolate* isolate)
{
if (!WTF::getPtr(value))
return v8::Null(isolate);
return toV8NoInline(WTF::getPtr(value), creationContext, isolate);
}
};
template<>
struct V8ValueTraits<String> {
static inline v8::Handle<v8::Value> toV8Value(const String& value, v8::Handle<v8::Object>, v8::Isolate* isolate)
{
return v8String(isolate, value);
}
};
template<>
struct V8ValueTraits<AtomicString> {
static inline v8::Handle<v8::Value> toV8Value(const AtomicString& value, v8::Handle<v8::Object>, v8::Isolate* isolate)
{
return v8String(isolate, value);
}
};
template<size_t n>
struct V8ValueTraits<char[n]> {
static inline v8::Handle<v8::Value> toV8Value(char const (&value)[n], v8::Handle<v8::Object>, v8::Isolate* isolate)
{
return v8String(isolate, value);
}
};
template<size_t n>
struct V8ValueTraits<char const[n]> {
static inline v8::Handle<v8::Value> toV8Value(char const (&value)[n], v8::Handle<v8::Object>, v8::Isolate* isolate)
{
return v8String(isolate, value);
}
};
template<>
struct V8ValueTraits<const char*> {
static inline v8::Handle<v8::Value> toV8Value(const char* const& value, v8::Handle<v8::Object>, v8::Isolate* isolate)
{
if (!value) {
// We return an empty string, not null, in order to align
// with v8String(isolate, String()).
return v8::String::Empty(isolate);
}
return v8String(isolate, value);
}
};
template<>
struct V8ValueTraits<char*> {
static inline v8::Handle<v8::Value> toV8Value(char* const& value, v8::Handle<v8::Object> object, v8::Isolate* isolate)
{
return V8ValueTraits<const char*>::toV8Value(value, object, isolate);
}
};
template<>
struct V8ValueTraits<std::nullptr_t> {
static inline v8::Handle<v8::Value> toV8Value(std::nullptr_t null, v8::Handle<v8::Object> object, v8::Isolate* isolate)
{
// Note: toV8Value(nullptr) returns null and
// toV8Value(static_cast<const char*>(nullptr)) returns an empty string.
// See V8ValueTraits<const char*>.
return v8::Null(isolate);
}
};
template<>
struct V8ValueTraits<int> {
static inline v8::Handle<v8::Value> toV8Value(const int& value, v8::Handle<v8::Object>, v8::Isolate* isolate)
{
return v8::Integer::New(isolate, value);
}
};
template<>
struct V8ValueTraits<long> {
static inline v8::Handle<v8::Value> toV8Value(const long& value, v8::Handle<v8::Object>, v8::Isolate* isolate)
{
return v8::Integer::New(isolate, value);
}
};
template<>
struct V8ValueTraits<unsigned> {
static inline v8::Handle<v8::Value> toV8Value(const unsigned& value, v8::Handle<v8::Object>, v8::Isolate* isolate)
{
return v8::Integer::NewFromUnsigned(isolate, value);
}
};
template<>
struct V8ValueTraits<unsigned long> {
static inline v8::Handle<v8::Value> toV8Value(const unsigned long& value, v8::Handle<v8::Object>, v8::Isolate* isolate)
{
return v8::Integer::NewFromUnsigned(isolate, value);
}
};
template<>
struct V8ValueTraits<float> {
static inline v8::Handle<v8::Value> toV8Value(const float& value, v8::Handle<v8::Object>, v8::Isolate* isolate)
{
return v8::Number::New(isolate, value);
}
};
template<>
struct V8ValueTraits<double> {
static inline v8::Handle<v8::Value> toV8Value(const double& value, v8::Handle<v8::Object>, v8::Isolate* isolate)
{
return v8::Number::New(isolate, value);
}
};
template<>
struct V8ValueTraits<bool> {
static inline v8::Handle<v8::Value> toV8Value(const bool& value, v8::Handle<v8::Object>, v8::Isolate* isolate)
{
return v8::Boolean::New(isolate, value);
}
};
// V8NullType and V8UndefinedType are used only for the value conversion.
class V8NullType { };
class V8UndefinedType { };
template<>
struct V8ValueTraits<V8NullType> {
static inline v8::Handle<v8::Value> toV8Value(const V8NullType&, v8::Handle<v8::Object>, v8::Isolate* isolate)
{
return v8::Null(isolate);
}
};
template<>
struct V8ValueTraits<V8UndefinedType> {
static inline v8::Handle<v8::Value> toV8Value(const V8UndefinedType&, v8::Handle<v8::Object>, v8::Isolate* isolate)
{
return v8::Undefined(isolate);
}
};
template<>
struct V8ValueTraits<ScriptValue> {
static inline v8::Handle<v8::Value> toV8Value(const ScriptValue& value, v8::Handle<v8::Object>, v8::Isolate*)
{
return value.v8Value();
}
};
template<>
struct V8ValueTraits<v8::Handle<v8::Value> > {
static inline v8::Handle<v8::Value> toV8Value(const v8::Handle<v8::Value>& value, v8::Handle<v8::Object>, v8::Isolate*)
{
return value;
}
};
template<>
struct V8ValueTraits<v8::Local<v8::Value> > {
static inline v8::Handle<v8::Value> toV8Value(const v8::Local<v8::Value>& value, v8::Handle<v8::Object>, v8::Isolate*)
{
return value;
}
};
template<typename T, size_t inlineCapacity>
v8::Handle<v8::Value> v8Array(const Vector<T, inlineCapacity>& iterator, v8::Handle<v8::Object> creationContext, v8::Isolate* isolate)
{
v8::Local<v8::Array> result = v8::Array::New(isolate, iterator.size());
int index = 0;
typename Vector<T, inlineCapacity>::const_iterator end = iterator.end();
typedef V8ValueTraits<T> TraitsType;
for (typename Vector<T, inlineCapacity>::const_iterator iter = iterator.begin(); iter != end; ++iter)
result->Set(v8::Integer::New(isolate, index++), TraitsType::toV8Value(*iter, creationContext, isolate));
return result;
}
template <typename T, size_t inlineCapacity, typename Allocator>
struct V8ValueTraits<WTF::Vector<T, inlineCapacity, Allocator> > {
static v8::Handle<v8::Value> toV8Value(const Vector<T, inlineCapacity, Allocator>& value, v8::Handle<v8::Object> creationContext, v8::Isolate* isolate)
{
return v8Array(value, creationContext, isolate);
}
};
template<typename T, size_t inlineCapacity>
v8::Handle<v8::Value> v8Array(const HeapVector<T, inlineCapacity>& iterator, v8::Handle<v8::Object> creationContext, v8::Isolate* isolate)
{
v8::Local<v8::Array> result = v8::Array::New(isolate, iterator.size());
int index = 0;
typename HeapVector<T, inlineCapacity>::const_iterator end = iterator.end();
typedef V8ValueTraits<T> TraitsType;
for (typename HeapVector<T, inlineCapacity>::const_iterator iter = iterator.begin(); iter != end; ++iter)
result->Set(v8::Integer::New(isolate, index++), TraitsType::toV8Value(*iter, creationContext, isolate));
return result;
}
template <typename T, size_t inlineCapacity>
struct V8ValueTraits<HeapVector<T, inlineCapacity> > {
static v8::Handle<v8::Value> toV8Value(const HeapVector<T, inlineCapacity>& value, v8::Handle<v8::Object> creationContext, v8::Isolate* isolate)
{
return v8Array(value, creationContext, isolate);
}
};
// Conversion flags, used in toIntXX/toUIntXX.
enum IntegerConversionConfiguration {
NormalConversion,
EnforceRange,
Clamp
};
// 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
int8_t toInt8(v8::Handle<v8::Value>, IntegerConversionConfiguration, ExceptionState&);
inline int8_t toInt8(v8::Handle<v8::Value> value, ExceptionState& exceptionState)
{
return toInt8(value, NormalConversion, exceptionState);
}
// Convert a value to a 8-bit integer assuming the conversion cannot fail.
int8_t toInt8(v8::Handle<v8::Value>);
// 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
uint8_t toUInt8(v8::Handle<v8::Value>, IntegerConversionConfiguration, ExceptionState&);
inline uint8_t toUInt8(v8::Handle<v8::Value> value, ExceptionState& exceptionState)
{
return toUInt8(value, NormalConversion, exceptionState);
}
// Convert a value to a 8-bit unsigned integer assuming the conversion cannot fail.
uint8_t toUInt8(v8::Handle<v8::Value>);
// 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
int16_t toInt16(v8::Handle<v8::Value>, IntegerConversionConfiguration, ExceptionState&);
inline int16_t toInt16(v8::Handle<v8::Value> value, ExceptionState& exceptionState)
{
return toInt16(value, NormalConversion, exceptionState);
}
// Convert a value to a 16-bit integer assuming the conversion cannot fail.
int16_t toInt16(v8::Handle<v8::Value>);
// 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
uint16_t toUInt16(v8::Handle<v8::Value>, IntegerConversionConfiguration, ExceptionState&);
inline uint16_t toUInt16(v8::Handle<v8::Value> value, ExceptionState& exceptionState)
{
return toUInt16(value, NormalConversion, exceptionState);
}
// Convert a value to a 16-bit unsigned integer assuming the conversion cannot fail.
uint16_t toUInt16(v8::Handle<v8::Value>);
// 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
int32_t toInt32(v8::Handle<v8::Value>, IntegerConversionConfiguration, ExceptionState&);
inline int32_t toInt32(v8::Handle<v8::Value> value, ExceptionState& exceptionState)
{
return toInt32(value, NormalConversion, exceptionState);
}
// Convert a value to a 32-bit integer assuming the conversion cannot fail.
int32_t toInt32(v8::Handle<v8::Value>);
// 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
uint32_t toUInt32(v8::Handle<v8::Value>, IntegerConversionConfiguration, ExceptionState&);
inline uint32_t toUInt32(v8::Handle<v8::Value> value, ExceptionState& exceptionState)
{
return toUInt32(value, NormalConversion, exceptionState);
}
// Convert a value to a 32-bit unsigned integer assuming the conversion cannot fail.
uint32_t toUInt32(v8::Handle<v8::Value>);
// 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
int64_t toInt64(v8::Handle<v8::Value>, IntegerConversionConfiguration, ExceptionState&);
inline int64_t toInt64(v8::Handle<v8::Value> value, ExceptionState& exceptionState)
{
return toInt64(value, NormalConversion, exceptionState);
}
// Convert a value to a 64-bit integer assuming the conversion cannot fail.
int64_t toInt64(v8::Handle<v8::Value>);
// 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
uint64_t toUInt64(v8::Handle<v8::Value>, IntegerConversionConfiguration, ExceptionState&);
inline uint64_t toUInt64(v8::Handle<v8::Value> value, ExceptionState& exceptionState)
{
return toUInt64(value, NormalConversion, exceptionState);
}
// Convert a value to a 64-bit unsigned integer assuming the conversion cannot fail.
uint64_t toUInt64(v8::Handle<v8::Value>);
// Convert a value to a single precision float, which might fail.
float toFloat(v8::Handle<v8::Value>, ExceptionState&);
// Convert a value to a single precision float assuming the conversion cannot fail.
inline float toFloat(v8::Local<v8::Value> value)
{
return static_cast<float>(value->NumberValue());
}
// Convert a value to a double precision float, which might fail.
double toDouble(v8::Handle<v8::Value>, ExceptionState&);
// Converts a value to a String, throwing if any code unit is outside 0-255.
String toByteString(v8::Handle<v8::Value>, ExceptionState&);
// Converts a value to a String, replacing unmatched UTF-16 surrogates with replacement characters.
String toUSVString(v8::Handle<v8::Value>, ExceptionState&);
inline v8::Handle<v8::Boolean> v8Boolean(bool value, v8::Isolate* isolate)
{
return value ? v8::True(isolate) : v8::False(isolate);
}
inline double toCoreDate(v8::Handle<v8::Value> object)
{
if (object->IsDate())
return v8::Handle<v8::Date>::Cast(object)->ValueOf();
if (object->IsNumber())
return object->NumberValue();
return std::numeric_limits<double>::quiet_NaN();
}
inline v8::Handle<v8::Value> v8DateOrNaN(double value, v8::Isolate* isolate)
{
ASSERT(isolate);
return v8::Date::New(isolate, std::isfinite(value) ? value : std::numeric_limits<double>::quiet_NaN());
}
// FIXME: Remove the special casing for NodeFilter and XPathNSResolver.
PassRefPtrWillBeRawPtr<NodeFilter> toNodeFilter(v8::Handle<v8::Value>, v8::Handle<v8::Object>, ScriptState*);
PassRefPtrWillBeRawPtr<XPathNSResolver> toXPathNSResolver(v8::Isolate*, v8::Handle<v8::Value>);
template<class T> struct NativeValueTraits;
bool toV8Sequence(v8::Handle<v8::Value>, uint32_t& length, v8::Isolate*, ExceptionState&);
// Converts a JavaScript value to an array as per the Web IDL specification:
// http://www.w3.org/TR/2012/CR-WebIDL-20120419/#es-array
template <class T, class V8T>
Vector<RefPtr<T> > toRefPtrNativeArrayUnchecked(v8::Local<v8::Value> v8Value, uint32_t length, v8::Isolate* isolate, ExceptionState& exceptionState)
{
Vector<RefPtr<T> > result;
result.reserveInitialCapacity(length);
v8::Local<v8::Object> object = v8::Local<v8::Object>::Cast(v8Value);
v8::TryCatch block;
for (uint32_t i = 0; i < length; ++i) {
v8::Handle<v8::Value> element = object->Get(i);
if (block.HasCaught()) {
exceptionState.rethrowV8Exception(block.Exception());
return Vector<RefPtr<T> >();
}
if (V8T::hasInstance(element, isolate)) {
v8::Handle<v8::Object> elementObject = v8::Handle<v8::Object>::Cast(element);
result.uncheckedAppend(V8T::toImpl(elementObject));
} else {
exceptionState.throwTypeError("Invalid Array element type");
return Vector<RefPtr<T> >();
}
}
return result;
}
template <class T, class V8T>
Vector<RefPtr<T> > toRefPtrNativeArray(v8::Handle<v8::Value> value, int argumentIndex, v8::Isolate* isolate, ExceptionState& exceptionState)
{
v8::Local<v8::Value> v8Value(v8::Local<v8::Value>::New(isolate, value));
uint32_t length = 0;
if (value->IsArray()) {
length = v8::Local<v8::Array>::Cast(v8Value)->Length();
} else if (!toV8Sequence(value, length, isolate, exceptionState)) {
if (!exceptionState.hadException())
exceptionState.throwTypeError(ExceptionMessages::notAnArrayTypeArgumentOrValue(argumentIndex));
return Vector<RefPtr<T> >();
}
return toRefPtrNativeArrayUnchecked<T, V8T>(v8Value, length, isolate, exceptionState);
}
template <class T, class V8T>
Vector<RefPtr<T> > toRefPtrNativeArray(v8::Handle<v8::Value> value, const String& propertyName, v8::Isolate* isolate, ExceptionState& exceptionState)
{
v8::Local<v8::Value> v8Value(v8::Local<v8::Value>::New(isolate, value));
uint32_t length = 0;
if (value->IsArray()) {
length = v8::Local<v8::Array>::Cast(v8Value)->Length();
} else if (!toV8Sequence(value, length, isolate, exceptionState)) {
if (!exceptionState.hadException())
exceptionState.throwTypeError(ExceptionMessages::notASequenceTypeProperty(propertyName));
return Vector<RefPtr<T> >();
}
return toRefPtrNativeArrayUnchecked<T, V8T>(v8Value, length, isolate, exceptionState);
}
template <class T, class V8T>
WillBeHeapVector<RefPtrWillBeMember<T> > toRefPtrWillBeMemberNativeArray(v8::Handle<v8::Value> value, int argumentIndex, v8::Isolate* isolate, ExceptionState& exceptionState)
{
v8::Local<v8::Value> v8Value(v8::Local<v8::Value>::New(isolate, value));
uint32_t length = 0;
if (value->IsArray()) {
length = v8::Local<v8::Array>::Cast(v8Value)->Length();
} else if (!toV8Sequence(value, length, isolate, exceptionState)) {
if (!exceptionState.hadException())
exceptionState.throwTypeError(ExceptionMessages::notAnArrayTypeArgumentOrValue(argumentIndex));
return WillBeHeapVector<RefPtrWillBeMember<T> >();
}
WillBeHeapVector<RefPtrWillBeMember<T> > result;
result.reserveInitialCapacity(length);
v8::Local<v8::Object> object = v8::Local<v8::Object>::Cast(v8Value);
v8::TryCatch block;
for (uint32_t i = 0; i < length; ++i) {
v8::Handle<v8::Value> element = object->Get(i);
if (block.HasCaught()) {
exceptionState.rethrowV8Exception(block.Exception());
return WillBeHeapVector<RefPtrWillBeMember<T> >();
}
if (V8T::hasInstance(element, isolate)) {
v8::Handle<v8::Object> elementObject = v8::Handle<v8::Object>::Cast(element);
result.uncheckedAppend(V8T::toImpl(elementObject));
} else {
exceptionState.throwTypeError("Invalid Array element type");
return WillBeHeapVector<RefPtrWillBeMember<T> >();
}
}
return result;
}
template <class T, class V8T>
WillBeHeapVector<RefPtrWillBeMember<T> > toRefPtrWillBeMemberNativeArray(v8::Handle<v8::Value> value, const String& propertyName, v8::Isolate* isolate, ExceptionState& exceptionState)
{
v8::Local<v8::Value> v8Value(v8::Local<v8::Value>::New(isolate, value));
uint32_t length = 0;
if (value->IsArray()) {
length = v8::Local<v8::Array>::Cast(v8Value)->Length();
} else if (!toV8Sequence(value, length, isolate, exceptionState)) {
if (!exceptionState.hadException())
exceptionState.throwTypeError(ExceptionMessages::notASequenceTypeProperty(propertyName));
return WillBeHeapVector<RefPtrWillBeMember<T> >();
}
WillBeHeapVector<RefPtrWillBeMember<T> > result;
result.reserveInitialCapacity(length);
v8::Local<v8::Object> object = v8::Local<v8::Object>::Cast(v8Value);
v8::TryCatch block;
for (uint32_t i = 0; i < length; ++i) {
v8::Handle<v8::Value> element = object->Get(i);
if (block.HasCaught()) {
exceptionState.rethrowV8Exception(block.Exception());
return WillBeHeapVector<RefPtrWillBeMember<T> >();
}
if (V8T::hasInstance(element, isolate)) {
v8::Handle<v8::Object> elementObject = v8::Handle<v8::Object>::Cast(element);
result.uncheckedAppend(V8T::toImpl(elementObject));
} else {
exceptionState.throwTypeError("Invalid Array element type");
return WillBeHeapVector<RefPtrWillBeMember<T> >();
}
}
return result;
}
template <class T, class V8T>
HeapVector<Member<T> > toMemberNativeArray(v8::Handle<v8::Value> value, int argumentIndex, v8::Isolate* isolate, ExceptionState& exceptionState)
{
v8::Local<v8::Value> v8Value(v8::Local<v8::Value>::New(isolate, value));
uint32_t length = 0;
if (value->IsArray()) {
length = v8::Local<v8::Array>::Cast(v8Value)->Length();
} else if (!toV8Sequence(value, length, isolate, exceptionState)) {
if (!exceptionState.hadException())
exceptionState.throwTypeError(ExceptionMessages::notAnArrayTypeArgumentOrValue(argumentIndex));
return HeapVector<Member<T> >();
}
HeapVector<Member<T> > result;
result.reserveInitialCapacity(length);
v8::Local<v8::Object> object = v8::Local<v8::Object>::Cast(v8Value);
v8::TryCatch block;
for (uint32_t i = 0; i < length; ++i) {
v8::Handle<v8::Value> element = object->Get(i);
if (UNLIKELY(block.HasCaught())) {
exceptionState.rethrowV8Exception(block.Exception());
return HeapVector<Member<T> >();
}
if (V8T::hasInstance(element, isolate)) {
v8::Handle<v8::Object> elementObject = v8::Handle<v8::Object>::Cast(element);
result.uncheckedAppend(V8T::toImpl(elementObject));
} else {
exceptionState.throwTypeError("Invalid Array element type");
return HeapVector<Member<T> >();
}
}
return result;
}
// Converts a JavaScript value to an array as per the Web IDL specification:
// http://www.w3.org/TR/2012/CR-WebIDL-20120419/#es-array
template <class T>
Vector<T> toImplArray(v8::Handle<v8::Value> value, int argumentIndex, v8::Isolate* isolate, ExceptionState& exceptionState)
{
v8::Local<v8::Value> v8Value(v8::Local<v8::Value>::New(isolate, value));
uint32_t length = 0;
if (value->IsArray()) {
length = v8::Local<v8::Array>::Cast(v8Value)->Length();
} else if (!toV8Sequence(value, length, isolate, exceptionState)) {
if (!exceptionState.hadException())
exceptionState.throwTypeError(ExceptionMessages::notAnArrayTypeArgumentOrValue(argumentIndex));
return Vector<T>();
}
Vector<T> result;
result.reserveInitialCapacity(length);
typedef NativeValueTraits<T> TraitsType;
v8::Local<v8::Object> object = v8::Local<v8::Object>::Cast(v8Value);
v8::TryCatch block;
for (uint32_t i = 0; i < length; ++i) {
v8::Handle<v8::Value> element = object->Get(i);
if (UNLIKELY(block.HasCaught())) {
exceptionState.rethrowV8Exception(block.Exception());
return Vector<T>();
}
result.uncheckedAppend(TraitsType::nativeValue(element, isolate, exceptionState));
if (exceptionState.hadException())
return Vector<T>();
}
return result;
}
template <class T>
Vector<T> toImplArguments(const v8::FunctionCallbackInfo<v8::Value>& info, int startIndex, ExceptionState& exceptionState)
{
ASSERT(startIndex <= info.Length());
Vector<T> result;
typedef NativeValueTraits<T> TraitsType;
int length = info.Length();
result.reserveInitialCapacity(length);
for (int i = startIndex; i < length; ++i) {
result.uncheckedAppend(TraitsType::nativeValue(info[i], info.GetIsolate(), exceptionState));
if (exceptionState.hadException())
return Vector<T>();
}
return result;
}
// Validates that the passed object is a sequence type per WebIDL spec
// http://www.w3.org/TR/2012/CR-WebIDL-20120419/#es-sequence
inline bool toV8Sequence(v8::Handle<v8::Value> value, uint32_t& length, v8::Isolate* isolate, ExceptionState& exceptionState)
{
// Attempt converting to a sequence if the value is not already an array but is
// any kind of object except for a native Date object or a native RegExp object.
ASSERT(!value->IsArray());
// FIXME: Do we really need to special case Date and RegExp object?
// https://www.w3.org/Bugs/Public/show_bug.cgi?id=22806
if (!value->IsObject() || value->IsDate() || value->IsRegExp()) {
// The caller is responsible for reporting a TypeError.
return false;
}
v8::Local<v8::Value> v8Value(v8::Local<v8::Value>::New(isolate, value));
v8::Local<v8::Object> object = v8::Local<v8::Object>::Cast(v8Value);
v8::Local<v8::String> lengthSymbol = v8AtomicString(isolate, "length");
// FIXME: The specification states that the length property should be used as fallback, if value
// is not a platform object that supports indexed properties. If it supports indexed properties,
// length should actually be one greater than value’s maximum indexed property index.
v8::TryCatch block;
v8::Local<v8::Value> lengthValue = object->Get(lengthSymbol);
if (block.HasCaught()) {
exceptionState.rethrowV8Exception(block.Exception());
return false;
}
if (lengthValue->IsUndefined() || lengthValue->IsNull()) {
// The caller is responsible for reporting a TypeError.
return false;
}
uint32_t sequenceLength = lengthValue->Int32Value();
if (block.HasCaught()) {
exceptionState.rethrowV8Exception(block.Exception());
return false;
}
length = sequenceLength;
return true;
}
template<>
struct NativeValueTraits<String> {
static inline String nativeValue(const v8::Handle<v8::Value>& value, v8::Isolate* isolate, ExceptionState& exceptionState)
{
V8StringResource<> stringValue(value);
if (!stringValue.prepare(exceptionState))
return String();
return stringValue;
}
};
template<>
struct NativeValueTraits<int> {
static inline int nativeValue(const v8::Handle<v8::Value>& value, v8::Isolate* isolate, ExceptionState& exceptionState)
{
return toInt32(value, exceptionState);
}
};
template<>
struct NativeValueTraits<unsigned> {
static inline unsigned nativeValue(const v8::Handle<v8::Value>& value, v8::Isolate* isolate, ExceptionState& exceptionState)
{
return toUInt32(value, exceptionState);
}
};
template<>
struct NativeValueTraits<float> {
static inline float nativeValue(const v8::Handle<v8::Value>& value, v8::Isolate* isolate, ExceptionState& exceptionState)
{
return toFloat(value, exceptionState);
}
};
template<>
struct NativeValueTraits<double> {
static inline double nativeValue(const v8::Handle<v8::Value>& value, v8::Isolate* isolate, ExceptionState& exceptionState)
{
return toDouble(value, exceptionState);
}
};
template<>
struct NativeValueTraits<v8::Handle<v8::Value> > {
static inline v8::Handle<v8::Value> nativeValue(const v8::Handle<v8::Value>& value, v8::Isolate* isolate, ExceptionState&)
{
return value;
}
};
template<>
struct NativeValueTraits<ScriptValue> {
static inline ScriptValue nativeValue(const v8::Handle<v8::Value>& value, v8::Isolate* isolate, ExceptionState&)
{
return ScriptValue(ScriptState::current(isolate), value);
}
};
template <typename T>
struct NativeValueTraits<Vector<T> > {
static inline Vector<T> nativeValue(const v8::Handle<v8::Value>& value, v8::Isolate* isolate, ExceptionState& exceptionState)
{
return toImplArray<T>(value, 0, isolate, exceptionState);
}
};
v8::Isolate* toIsolate(ExecutionContext*);
v8::Isolate* toIsolate(LocalFrame*);
LocalDOMWindow* toDOMWindow(v8::Handle<v8::Value>, v8::Isolate*);
LocalDOMWindow* toDOMWindow(v8::Handle<v8::Context>);
LocalDOMWindow* enteredDOMWindow(v8::Isolate*);
LocalDOMWindow* currentDOMWindow(v8::Isolate*);
LocalDOMWindow* callingDOMWindow(v8::Isolate*);
ExecutionContext* toExecutionContext(v8::Handle<v8::Context>);
ExecutionContext* currentExecutionContext(v8::Isolate*);
ExecutionContext* callingExecutionContext(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.
v8::Local<v8::Context> toV8Context(ExecutionContext*, DOMWrapperWorld&);
// Returns a V8 context associated with a LocalFrame and a DOMWrapperWorld.
// This method returns an empty context if the frame is already detached.
v8::Local<v8::Context> toV8Context(LocalFrame*, DOMWrapperWorld&);
// Returns the frame object of the window object associated with
// a context, if the window is currently being displayed in the LocalFrame.
LocalFrame* toFrameIfNotDetached(v8::Handle<v8::Context>);
// If the current context causes out of memory, JavaScript setting
// is disabled and it returns true.
bool handleOutOfMemory();
void crashIfV8IsDead();
inline bool isUndefinedOrNull(v8::Handle<v8::Value> value)
{
return value->IsNull() || value->IsUndefined();
}
v8::Handle<v8::Function> getBoundFunction(v8::Handle<v8::Function>);
// Attaches |environment| to |function| and returns it.
inline v8::Local<v8::Function> createClosure(v8::FunctionCallback function, v8::Handle<v8::Value> environment, v8::Isolate* isolate)
{
return v8::Function::New(isolate, function, environment);
}
// FIXME: This will be soon embedded in the generated code.
template<class Collection> static void indexedPropertyEnumerator(const v8::PropertyCallbackInfo<v8::Array>& info)
{
Collection* collection = toScriptWrappableBase(info.Holder())->toImpl<Collection>();
int length = collection->length();
v8::Handle<v8::Array> properties = v8::Array::New(info.GetIsolate(), length);
for (int i = 0; i < length; ++i) {
// FIXME: Do we need to check that the item function returns a non-null value for this index?
v8::Handle<v8::Integer> integer = v8::Integer::New(info.GetIsolate(), i);
properties->Set(integer, integer);
}
v8SetReturnValue(info, properties);
}
// These methods store hidden values into an array that is stored in the internal field of a DOM wrapper.
void addHiddenValueToArray(v8::Isolate*, v8::Handle<v8::Object>, v8::Local<v8::Value>, int cacheIndex);
void removeHiddenValueFromArray(v8::Isolate*, v8::Handle<v8::Object>, v8::Local<v8::Value>, int cacheIndex);
void moveEventListenerToNewWrapper(v8::Isolate*, v8::Handle<v8::Object>, EventListener* oldValue, v8::Local<v8::Value> newValue, int cacheIndex);
PassRefPtr<JSONValue> v8ToJSONValue(v8::Isolate*, v8::Handle<v8::Value>, int);
// Result values for platform object 'deleter' methods,
// http://www.w3.org/TR/WebIDL/#delete
enum DeleteResult {
DeleteSuccess,
DeleteReject,
DeleteUnknownProperty
};
class V8IsolateInterruptor : public ThreadState::Interruptor {
public:
explicit V8IsolateInterruptor(v8::Isolate* isolate) : m_isolate(isolate) { }
static void onInterruptCallback(v8::Isolate* isolate, void* data)
{
reinterpret_cast<V8IsolateInterruptor*>(data)->onInterrupted();
}
virtual void requestInterrupt() override
{
m_isolate->RequestInterrupt(&onInterruptCallback, this);
}
virtual void clearInterrupt() override
{
m_isolate->ClearInterrupt();
}
private:
v8::Isolate* m_isolate;
};
class V8TestingScope {
public:
explicit V8TestingScope(v8::Isolate*);
ScriptState* scriptState() const;
v8::Isolate* isolate() const;
~V8TestingScope();
private:
v8::HandleScope m_handleScope;
v8::Context::Scope m_contextScope;
RefPtr<ScriptState> m_scriptState;
};
void GetDevToolsFunctionInfo(v8::Handle<v8::Function>, v8::Isolate*, int& scriptId, String& resourceName, int& lineNumber);
PassRefPtr<TraceEvent::ConvertableToTraceFormat> devToolsTraceEventData(v8::Isolate*, ExecutionContext*, v8::Handle<v8::Function>);
class V8RethrowTryCatchScope final {
public:
explicit V8RethrowTryCatchScope(v8::TryCatch& block) : m_block(block) { }
~V8RethrowTryCatchScope()
{
// ReThrow() is a no-op if no exception has been caught, so always call.
m_block.ReThrow();
}
private:
v8::TryCatch& m_block;
};
// Returns an object representing {done: true, value: undefined}.
v8::Local<v8::Value> v8DoneIteratorResult(v8::Isolate*);
// Returns an object representing {done: false, value: |value|}.
v8::Local<v8::Value> v8IteratorResult(v8::Isolate*, v8::Handle<v8::Value>);
template <typename T>
v8::Local<v8::Value> v8IteratorResult(ScriptState* scriptState, const T& value)
{
return v8IteratorResult(scriptState->isolate(), V8ValueTraits<T>::toV8Value(value, scriptState->context()->Global(), scriptState->isolate()));
}
typedef void (*InstallTemplateFunction)(v8::Handle<v8::FunctionTemplate>, v8::Isolate*);
} // namespace blink
#endif // V8Binding_h