| // Copyright 2014 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_BINDINGS_TO_V8_H_ |
| #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_BINDINGS_TO_V8_H_ |
| |
| // ToV8() provides C++ -> V8 conversion. Note that ToV8() can return an empty |
| // handle. Call sites must check IsEmpty() before using return value. |
| |
| #include <utility> |
| |
| #include "base/containers/span.h" |
| #include "base/optional.h" |
| #include "third_party/blink/renderer/platform/bindings/callback_function_base.h" |
| #include "third_party/blink/renderer/platform/bindings/callback_interface_base.h" |
| #include "third_party/blink/renderer/platform/bindings/dom_data_store.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/wtf/forward.h" |
| #include "third_party/blink/renderer/platform/wtf/std_lib_extras.h" |
| #include "v8/include/v8.h" |
| |
| namespace blink { |
| |
| // ScriptWrappable |
| |
| inline v8::Local<v8::Value> ToV8(ScriptWrappable* impl, |
| v8::Local<v8::Object> creation_context, |
| v8::Isolate* isolate) { |
| if (UNLIKELY(!impl)) |
| return v8::Null(isolate); |
| v8::Local<v8::Value> wrapper = DOMDataStore::GetWrapper(impl, isolate); |
| if (!wrapper.IsEmpty()) |
| return wrapper; |
| |
| wrapper = impl->Wrap(isolate, creation_context); |
| DCHECK(!wrapper.IsEmpty()); |
| return wrapper; |
| } |
| |
| // Callback function |
| |
| inline v8::Local<v8::Value> ToV8(CallbackFunctionBase* callback, |
| v8::Local<v8::Object> creation_context, |
| v8::Isolate* isolate) { |
| // |creation_context| is intentionally ignored. Callback functions are not |
| // wrappers nor clonable. ToV8 on a callback function must be used only when |
| // it's in the same world. |
| DCHECK(!callback || |
| (&callback->GetWorld() == |
| &ScriptState::From(creation_context->CreationContext())->World())); |
| return callback ? callback->CallbackObject().As<v8::Value>() |
| : v8::Null(isolate).As<v8::Value>(); |
| } |
| |
| // Callback interface |
| |
| inline v8::Local<v8::Value> ToV8(CallbackInterfaceBase* callback, |
| v8::Local<v8::Object> creation_context, |
| v8::Isolate* isolate) { |
| // |creation_context| is intentionally ignored. Callback interface objects |
| // are not wrappers nor clonable. ToV8 on a callback interface object must |
| // be used only when it's the same origin-domain in the same world. |
| DCHECK(!callback || (callback->CallbackRelevantScriptState()->GetContext() == |
| creation_context->CreationContext())); |
| return callback ? callback->CallbackObject().As<v8::Value>() |
| : v8::Null(isolate).As<v8::Value>(); |
| } |
| |
| // Primitives |
| |
| inline v8::Local<v8::Value> ToV8(const String& value, |
| v8::Local<v8::Object> creation_context, |
| v8::Isolate* isolate) { |
| return V8String(isolate, value); |
| } |
| |
| inline v8::Local<v8::Value> ToV8(const char* value, |
| v8::Local<v8::Object> creation_context, |
| v8::Isolate* isolate) { |
| return V8String(isolate, value); |
| } |
| |
| template <size_t sizeOfValue> |
| inline v8::Local<v8::Value> ToV8SignedIntegerInternal(int64_t value, |
| v8::Isolate*); |
| |
| template <> |
| inline v8::Local<v8::Value> ToV8SignedIntegerInternal<4>(int64_t value, |
| v8::Isolate* isolate) { |
| return v8::Integer::New(isolate, static_cast<int32_t>(value)); |
| } |
| |
| template <> |
| inline v8::Local<v8::Value> ToV8SignedIntegerInternal<8>(int64_t value, |
| v8::Isolate* isolate) { |
| int32_t value_in32_bit = static_cast<int32_t>(value); |
| if (value_in32_bit == value) |
| return v8::Integer::New(isolate, value_in32_bit); |
| // V8 doesn't have a 64-bit integer implementation. |
| return v8::Number::New(isolate, value); |
| } |
| |
| template <size_t sizeOfValue> |
| inline v8::Local<v8::Value> ToV8UnsignedIntegerInternal(uint64_t value, |
| v8::Isolate*); |
| |
| template <> |
| inline v8::Local<v8::Value> ToV8UnsignedIntegerInternal<4>( |
| uint64_t value, |
| v8::Isolate* isolate) { |
| return v8::Integer::NewFromUnsigned(isolate, static_cast<uint32_t>(value)); |
| } |
| |
| template <> |
| inline v8::Local<v8::Value> ToV8UnsignedIntegerInternal<8>( |
| uint64_t value, |
| v8::Isolate* isolate) { |
| uint32_t value_in32_bit = static_cast<uint32_t>(value); |
| if (value_in32_bit == value) |
| return v8::Integer::NewFromUnsigned(isolate, value_in32_bit); |
| // V8 doesn't have a 64-bit integer implementation. |
| return v8::Number::New(isolate, value); |
| } |
| |
| inline v8::Local<v8::Value> ToV8(int value, |
| v8::Local<v8::Object> creation_context, |
| v8::Isolate* isolate) { |
| return ToV8SignedIntegerInternal<sizeof value>(value, isolate); |
| } |
| |
| inline v8::Local<v8::Value> ToV8(long value, |
| v8::Local<v8::Object> creation_context, |
| v8::Isolate* isolate) { |
| return ToV8SignedIntegerInternal<sizeof value>(value, isolate); |
| } |
| |
| inline v8::Local<v8::Value> ToV8(long long value, |
| v8::Local<v8::Object> creation_context, |
| v8::Isolate* isolate) { |
| return ToV8SignedIntegerInternal<sizeof value>(value, isolate); |
| } |
| |
| inline v8::Local<v8::Value> ToV8(unsigned value, |
| v8::Local<v8::Object> creation_context, |
| v8::Isolate* isolate) { |
| return ToV8UnsignedIntegerInternal<sizeof value>(value, isolate); |
| } |
| |
| inline v8::Local<v8::Value> ToV8(unsigned long value, |
| v8::Local<v8::Object> creation_context, |
| v8::Isolate* isolate) { |
| return ToV8UnsignedIntegerInternal<sizeof value>(value, isolate); |
| } |
| |
| inline v8::Local<v8::Value> ToV8(unsigned long long value, |
| v8::Local<v8::Object> creation_context, |
| v8::Isolate* isolate) { |
| return ToV8UnsignedIntegerInternal<sizeof value>(value, isolate); |
| } |
| |
| inline v8::Local<v8::Value> ToV8(double value, |
| v8::Local<v8::Object> creation_context, |
| v8::Isolate* isolate) { |
| return v8::Number::New(isolate, value); |
| } |
| |
| inline v8::Local<v8::Value> ToV8(bool value, |
| v8::Local<v8::Object> creation_context, |
| v8::Isolate* isolate) { |
| return v8::Boolean::New(isolate, value); |
| } |
| |
| // Identity operator |
| |
| inline v8::Local<v8::Value> ToV8(v8::Local<v8::Value> value, |
| v8::Local<v8::Object> creation_context, |
| v8::Isolate*) { |
| return value; |
| } |
| |
| // Undefined |
| |
| struct ToV8UndefinedGenerator { |
| DISALLOW_NEW(); |
| }; // Used only for having toV8 return v8::Undefined. |
| |
| inline v8::Local<v8::Value> ToV8(const ToV8UndefinedGenerator& value, |
| v8::Local<v8::Object> creation_context, |
| v8::Isolate* isolate) { |
| return v8::Undefined(isolate); |
| } |
| |
| // Forward declaration to allow interleaving with sequences. |
| template <typename InnerType> |
| inline v8::Local<v8::Value> ToV8(const base::Optional<InnerType>& value, |
| v8::Local<v8::Object> creation_context, |
| v8::Isolate*); |
| |
| // Array |
| |
| // Declare the function here but define it later so it can call the ToV8() |
| // overloads below. |
| template <typename Sequence> |
| inline v8::Local<v8::Value> ToV8SequenceInternal( |
| const Sequence&, |
| v8::Local<v8::Object> creation_context, |
| v8::Isolate*); |
| |
| template <typename T, size_t Extent> |
| inline v8::Local<v8::Value> ToV8(base::span<T, Extent> value, |
| v8::Local<v8::Object> creation_context, |
| v8::Isolate* isolate) { |
| return ToV8SequenceInternal(value, creation_context, isolate); |
| } |
| |
| template <typename T, wtf_size_t inlineCapacity> |
| inline v8::Local<v8::Value> ToV8(const Vector<T, inlineCapacity>& value, |
| v8::Local<v8::Object> creation_context, |
| v8::Isolate* isolate) { |
| return ToV8SequenceInternal(value, creation_context, isolate); |
| } |
| |
| template <typename T, wtf_size_t inlineCapacity> |
| inline v8::Local<v8::Value> ToV8(const HeapVector<T, inlineCapacity>& value, |
| v8::Local<v8::Object> creation_context, |
| v8::Isolate* isolate) { |
| return ToV8SequenceInternal(value, creation_context, isolate); |
| } |
| |
| // The following two overloads are also used to convert record<K,V> IDL types |
| // back into ECMAScript Objects. |
| template <typename T> |
| inline v8::Local<v8::Value> ToV8(const Vector<std::pair<String, T>>& value, |
| v8::Local<v8::Object> creation_context, |
| v8::Isolate* isolate) { |
| v8::Local<v8::Object> object; |
| { |
| v8::Context::Scope context_scope(creation_context->CreationContext()); |
| object = v8::Object::New(isolate); |
| } |
| v8::Local<v8::Context> context = isolate->GetCurrentContext(); |
| for (unsigned i = 0; i < value.size(); ++i) { |
| v8::Local<v8::Value> v8_value = ToV8(value[i].second, object, isolate); |
| if (v8_value.IsEmpty()) |
| v8_value = v8::Undefined(isolate); |
| bool created_property; |
| if (!object |
| ->CreateDataProperty( |
| context, V8AtomicString(isolate, value[i].first), v8_value) |
| .To(&created_property) || |
| !created_property) { |
| return v8::Local<v8::Value>(); |
| } |
| } |
| return object; |
| } |
| |
| template <typename T> |
| inline v8::Local<v8::Value> ToV8(const HeapVector<std::pair<String, T>>& value, |
| v8::Local<v8::Object> creation_context, |
| v8::Isolate* isolate) { |
| v8::Local<v8::Object> object; |
| { |
| v8::Context::Scope context_scope(creation_context->CreationContext()); |
| object = v8::Object::New(isolate); |
| } |
| v8::Local<v8::Context> context = isolate->GetCurrentContext(); |
| for (unsigned i = 0; i < value.size(); ++i) { |
| v8::Local<v8::Value> v8_value = ToV8(value[i].second, object, isolate); |
| if (v8_value.IsEmpty()) |
| v8_value = v8::Undefined(isolate); |
| bool created_property; |
| if (!object |
| ->CreateDataProperty( |
| context, V8AtomicString(isolate, value[i].first), v8_value) |
| .To(&created_property) || |
| !created_property) { |
| return v8::Local<v8::Value>(); |
| } |
| } |
| return object; |
| } |
| |
| template <typename Sequence> |
| inline v8::Local<v8::Value> ToV8SequenceInternal( |
| const Sequence& sequence, |
| v8::Local<v8::Object> creation_context, |
| v8::Isolate* isolate) { |
| RUNTIME_CALL_TIMER_SCOPE(isolate, |
| RuntimeCallStats::CounterId::kToV8SequenceInternal); |
| v8::Local<v8::Array> array; |
| { |
| v8::Context::Scope context_scope(creation_context->CreationContext()); |
| array = v8::Array::New(isolate, SafeCast<int>(sequence.size())); |
| } |
| v8::Local<v8::Context> context = isolate->GetCurrentContext(); |
| uint32_t index = 0; |
| typename Sequence::const_iterator end = sequence.end(); |
| for (typename Sequence::const_iterator iter = sequence.begin(); iter != end; |
| ++iter) { |
| v8::Local<v8::Value> value = ToV8(*iter, array, isolate); |
| if (value.IsEmpty()) |
| value = v8::Undefined(isolate); |
| bool created_property; |
| if (!array->CreateDataProperty(context, index++, value) |
| .To(&created_property) || |
| !created_property) { |
| return v8::Local<v8::Value>(); |
| } |
| } |
| return array; |
| } |
| |
| // Nullable |
| |
| template <typename InnerType> |
| inline v8::Local<v8::Value> ToV8(const base::Optional<InnerType>& value, |
| v8::Local<v8::Object> creation_context, |
| v8::Isolate* isolate) { |
| if (!value) |
| return v8::Null(isolate); |
| return ToV8(*value, creation_context, isolate); |
| } |
| |
| // In all cases allow script state instead of creation context + isolate. |
| // Use this function only if the call site does not otherwise need the global, |
| // since v8::Context::Global is heavy. |
| template <typename T> |
| inline v8::Local<v8::Value> ToV8(T&& value, ScriptState* script_state) { |
| return ToV8(std::forward<T>(value), script_state->GetContext()->Global(), |
| script_state->GetIsolate()); |
| } |
| |
| // Only declare ToV8(void*,...) for checking function overload mismatch. |
| // This ToV8(void*,...) should be never used. So we will find mismatch |
| // because of "unresolved external symbol". |
| // Without ToV8(void*, ...), call to toV8 with T* will match with |
| // ToV8(bool, ...) if T is not a subclass of ScriptWrappable or if T is |
| // declared but not defined (so it's not clear that T is a subclass of |
| // ScriptWrappable). |
| // This hack helps detect such unwanted implicit conversions from T* to bool. |
| v8::Local<v8::Value> ToV8(void* value, |
| v8::Local<v8::Object> creation_context, |
| v8::Isolate*) = delete; |
| |
| } // namespace blink |
| |
| #endif // ToV8ForPlatform_h |