blob: daf0df29cb6a9c6ce7f7c42b0333f1ab5de6caeb [file] [log] [blame]
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "services/accessibility/features/v8_utils.h"
#include <string_view>
#include "v8-array-buffer.h"
#include "v8-container.h"
namespace ax {
// static
V8ValueConverter* V8ValueConverter::GetInstance() {
static V8ValueConverter converter;
return &converter;
}
v8::Local<v8::Value> V8ValueConverter::ConvertToV8Value(
base::ValueView value,
v8::Local<v8::Context> context) const {
v8::Context::Scope context_scope(context);
v8::EscapableHandleScope handle_scope(context->GetIsolate());
return handle_scope.Escape(
ToV8Value(context->GetIsolate(), context->Global(), value));
}
v8::Local<v8::Value> V8ValueConverter::ToV8Value(
v8::Isolate* isolate,
v8::Local<v8::Object> creation_context,
base::ValueView value) const {
struct Visitor {
raw_ptr<const V8ValueConverter> converter;
raw_ptr<v8::Isolate> isolate;
v8::Local<v8::Object> creation_context;
v8::Local<v8::Value> operator()(absl::monostate value) {
return v8::Null(isolate);
}
v8::Local<v8::Value> operator()(bool value) {
return v8::Boolean::New(isolate, value);
}
v8::Local<v8::Value> operator()(int value) {
return v8::Integer::New(isolate, value);
}
v8::Local<v8::Value> operator()(double value) {
return v8::Number::New(isolate, value);
}
v8::Local<v8::Value> operator()(std::string_view value) {
return v8::String::NewFromUtf8(isolate, value.data(),
v8::NewStringType::kNormal, value.length())
.ToLocalChecked();
}
v8::Local<v8::Value> operator()(const base::Value::BlobStorage& value) {
return converter->ToArrayBuffer(isolate, creation_context, value);
}
v8::Local<v8::Value> operator()(const base::Value::Dict& value) {
return converter->ToV8Object(isolate, creation_context, value);
}
v8::Local<v8::Value> operator()(const base::Value::List& value) {
return converter->ToV8Array(isolate, creation_context, value);
}
};
return value.Visit(Visitor{.converter = this,
.isolate = isolate,
.creation_context = creation_context});
}
v8::Local<v8::Value> V8ValueConverter::ToArrayBuffer(
v8::Isolate* isolate,
v8::Local<v8::Object> creation_context,
const base::Value::BlobStorage& value) const {
v8::Local<v8::ArrayBuffer> buffer =
v8::ArrayBuffer::New(isolate, value.size());
base::ranges::copy(value,
static_cast<uint8_t*>(buffer->GetBackingStore()->Data()));
return buffer;
}
v8::Local<v8::Value> V8ValueConverter::ToV8Object(
v8::Isolate* isolate,
v8::Local<v8::Object> creation_context,
const base::Value::Dict& val) const {
v8::Local<v8::Object> result(v8::Object::New(isolate));
v8::Local<v8::Context> context = isolate->GetCurrentContext();
for (const auto [key, value] : val) {
v8::Local<v8::Value> child_v8 = ToV8Value(isolate, creation_context, value);
CHECK(!child_v8.IsEmpty());
v8::Maybe<bool> maybe = result->CreateDataProperty(
context,
v8::String::NewFromUtf8(isolate, key.c_str(),
v8::NewStringType::kNormal, key.length())
.ToLocalChecked(),
child_v8);
CHECK(maybe.IsJust());
}
return result;
}
v8::Local<v8::Value> V8ValueConverter::ToV8Array(
v8::Isolate* isolate,
v8::Local<v8::Object> creation_context,
const base::Value::List& val) const {
v8::Local<v8::Array> result(v8::Array::New(isolate, val.size()));
v8::Local<v8::Context> context = isolate->GetCurrentContext();
for (size_t i = 0; i < val.size(); ++i) {
const base::Value& child = val[i];
v8::Local<v8::Value> child_v8 = ToV8Value(isolate, creation_context, child);
CHECK(!child_v8.IsEmpty());
v8::Maybe<bool> maybe =
result->CreateDataProperty(context, static_cast<uint32_t>(i), child_v8);
CHECK(maybe.IsJust());
}
return result;
}
} // namespace ax