blob: e8c947442c05667dcb78072bff319975a77e89e5 [file] [log] [blame]
// Copyright 2018 The Cobalt Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef COBALT_SCRIPT_V8C_V8C_TYPED_ARRAYS_H_
#define COBALT_SCRIPT_V8C_V8C_TYPED_ARRAYS_H_
#include "base/memory/ref_counted.h"
#include "cobalt/script/array_buffer.h"
#include "cobalt/script/array_buffer_view.h"
#include "cobalt/script/exception_message.h"
#include "cobalt/script/script_exception.h"
#include "cobalt/script/script_value.h"
#include "cobalt/script/typed_arrays.h"
#include "cobalt/script/v8c/entry_scope.h"
#include "cobalt/script/v8c/v8c_array_buffer.h"
namespace cobalt {
namespace script {
namespace v8c {
class V8cTypedArray final : public ScopedPersistent<v8::Value>,
public TypedArray {
public:
using BaseType = TypedArray;
// Default constructor should only be used by bindings code.
V8cTypedArray() = default;
V8cTypedArray(v8::Isolate* isolate, v8::Local<v8::Value> value)
: isolate_(isolate), ScopedPersistent(isolate, value) {
DCHECK(value->IsTypedArray());
}
Handle<ArrayBuffer> Buffer() const override {
EntryScope entry_scope(isolate_);
v8::Local<v8::ArrayBuffer> array_buffer = GetInternal()->Buffer();
return Handle<ArrayBuffer>(
new V8cUserObjectHolder<V8cArrayBuffer>(isolate_, array_buffer));
}
size_t Length() const override {
EntryScope entry_scope(isolate_);
return GetInternal()->Length();
}
size_t ByteOffset() const override {
EntryScope entry_scope(isolate_);
return GetInternal()->ByteOffset();
}
size_t ByteLength() const override {
EntryScope entry_scope(isolate_);
return GetInternal()->ByteLength();
}
void* RawData() const override {
EntryScope entry_scope(isolate_);
auto self = GetInternal();
void* data = self->Buffer()->GetContents().Data();
uint8_t* incremented_data =
static_cast<uint8_t*>(data) + self->ByteOffset();
return static_cast<void*>(incremented_data);
}
private:
v8::Local<v8::TypedArray> GetInternal() const {
return this->NewLocal(isolate_).As<v8::TypedArray>();
}
v8::Isolate* isolate_;
};
template <>
struct TypeTraits<TypedArray> {
using ConversionType = V8cUserObjectHolder<V8cTypedArray>;
using ReturnType = const ScriptValue<TypedArray>*;
};
inline void ToJSValue(v8::Isolate* isolate,
const ScriptValue<TypedArray>* typed_array_value,
v8::Local<v8::Value>* out_value) {
if (!typed_array_value) {
*out_value = v8::Null(isolate);
return;
}
const auto* v8c_typed_array_value =
base::polymorphic_downcast<const V8cUserObjectHolder<V8cTypedArray>*>(
typed_array_value);
*out_value = v8c_typed_array_value->v8_value();
}
inline void FromJSValue(v8::Isolate* isolate, v8::Local<v8::Value> value,
int conversion_flags, ExceptionState* exception_state,
V8cUserObjectHolder<V8cTypedArray>* out_typed_array) {
DCHECK_EQ(0, conversion_flags);
DCHECK(out_typed_array);
if (!value->IsObject()) {
exception_state->SetSimpleException(kNotObjectType);
return;
}
if (!value->IsTypedArray()) {
exception_state->SetSimpleException(kTypeError,
"Expected object of type TypedArray");
return;
}
*out_typed_array = std::move(
V8cUserObjectHolder<V8cTypedArray>(isolate, value.As<v8::TypedArray>()));
}
template <typename CType, typename BaseTypeName, typename V8Type,
bool (v8::Value::*V8ValueIsTypeFunction)() const>
class V8cTypedArrayImpl final : public ScopedPersistent<v8::Value>,
public BaseTypeName {
public:
using BaseType = BaseTypeName;
// Default constructor should only be used by bindings code.
V8cTypedArrayImpl() = default;
V8cTypedArrayImpl(v8::Isolate* isolate, v8::Local<v8::Value> value)
: isolate_(isolate), ScopedPersistent(isolate, value) {
DCHECK(((**value).*(V8ValueIsTypeFunction))());
}
Handle<ArrayBuffer> Buffer() const override {
EntryScope entry_scope(isolate_);
v8::Local<v8::ArrayBuffer> array_buffer = GetInternal()->Buffer();
return Handle<ArrayBuffer>(
new V8cUserObjectHolder<V8cArrayBuffer>(isolate_, array_buffer));
}
size_t Length() const override {
EntryScope entry_scope(isolate_);
return GetInternal()->Length();
}
size_t ByteOffset() const override {
EntryScope entry_scope(isolate_);
return GetInternal()->ByteOffset();
}
size_t ByteLength() const override {
EntryScope entry_scope(isolate_);
return GetInternal()->ByteLength();
}
void* RawData() const override {
EntryScope entry_scope(isolate_);
auto self = GetInternal();
void* data = self->Buffer()->GetContents().Data();
uint8_t* incremented_data =
static_cast<uint8_t*>(data) + self->ByteOffset();
return static_cast<void*>(incremented_data);
}
CType* Data() const override { return static_cast<CType*>(RawData()); }
private:
v8::Local<V8Type> GetInternal() const {
return this->NewLocal(isolate_).template As<V8Type>();
}
v8::Isolate* isolate_;
};
#define COBALT_SCRIPT_USING_V8C_ARRAY(array, ctype) \
using V8c##array = \
V8cTypedArrayImpl<ctype, array, v8::array, &v8::Value::Is##array>;
COBALT_SCRIPT_TYPED_ARRAY_LIST(COBALT_SCRIPT_USING_V8C_ARRAY)
#undef COBALT_SCRIPT_USING_V8C_ARRAY
#define COBALT_SCRIPT_CONVERSION_BOILERPLATE(array, ctype) \
template <> \
struct TypeTraits<array> { \
using ConversionType = V8cUserObjectHolder<V8c##array>; \
using ReturnType = const ScriptValue<array>*; \
}; \
\
inline void ToJSValue(v8::Isolate* isolate, \
const ScriptValue<array>* array_value, \
v8::Local<v8::Value>* out_value) { \
if (!array_value) { \
*out_value = v8::Null(isolate); \
return; \
} \
const auto* v8c_array_value = \
base::polymorphic_downcast<const V8cUserObjectHolder<V8c##array>*>( \
array_value); \
*out_value = v8c_array_value->v8_value(); \
} \
\
inline void FromJSValue(v8::Isolate* isolate, v8::Local<v8::Value> value, \
int conversion_flags, \
ExceptionState* exception_state, \
V8cUserObjectHolder<V8c##array>* out_array) { \
DCHECK_EQ(0, conversion_flags); \
DCHECK(out_array); \
if (!value->IsObject()) { \
exception_state->SetSimpleException(kNotObjectType); \
return; \
} \
if (!value->Is##array()) { \
exception_state->SetSimpleException(kTypeError, \
"Expected object of type array"); \
return; \
} \
*out_array = std::move(V8cUserObjectHolder<V8c##array>(isolate, value)); \
}
COBALT_SCRIPT_TYPED_ARRAY_LIST(COBALT_SCRIPT_CONVERSION_BOILERPLATE)
#undef COBALT_SCRIPT_CONVERSION_BOILERPLATE
} // namespace v8c
} // namespace script
} // namespace cobalt
#endif // COBALT_SCRIPT_V8C_V8C_TYPED_ARRAYS_H_