LibWeb+Meta: Add wrapper for the BufferSource/ArrayBufferView IDL types

These wrappers will make it much easier to do various operations on the
different ArrayBuffer-related classes in LibWeb compared to the current
solution, which is to just accept a Handle<Object> everywhere (and use
"any" in the *.idl files).

Co-Authored-By: Matthew Olsson <mattco@serenityos.org>
This commit is contained in:
Shannon Booth 2023-11-23 20:07:25 +13:00 committed by Andreas Kling
parent 54d0aafff0
commit 04c094343f
Notes: sideshowbarker 2024-07-17 04:34:25 +09:00
27 changed files with 286 additions and 71 deletions

View file

@ -180,7 +180,10 @@ CppType idl_type_name_to_cpp_type(Type const& type, Interface const& interface)
return { .name = "JS::Handle<JS::Object>", .sequence_storage_type = SequenceStorageType::Vector };
if (type.name() == "BufferSource")
return { .name = "JS::Handle<JS::Object>", .sequence_storage_type = SequenceStorageType::MarkedVector };
return { .name = "JS::Handle<WebIDL::BufferSource>", .sequence_storage_type = SequenceStorageType::MarkedVector };
if (type.name() == "ArrayBufferView")
return { .name = "JS::Handle<WebIDL::ArrayBufferView>", .sequence_storage_type = SequenceStorageType::MarkedVector };
if (type.name() == "File")
return { .name = "JS::Handle<FileAPI::File>", .sequence_storage_type = SequenceStorageType::MarkedVector };
@ -611,20 +614,33 @@ static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter
} else if (parameter.type->name() == "BufferSource" || parameter.type->name() == "Float32Array" || parameter.type->name() == "Float64Array" || parameter.type->name() == "Uint8Array") {
if (optional) {
scoped_generator.append(R"~~~(
Optional<JS::Handle<JS::Object>> @cpp_name@;
Optional<JS::Handle<WebIDL::BufferSource>> @cpp_name@;
if (!@js_name@@js_suffix@.is_undefined()) {
)~~~");
} else {
scoped_generator.append(R"~~~(
JS::Handle<JS::Object> @cpp_name@;
JS::Handle<WebIDL::BufferSource> @cpp_name@;
)~~~");
}
scoped_generator.append(R"~~~(
if (!@js_name@@js_suffix@.is_object() || !(is<JS::TypedArrayBase>(@js_name@@js_suffix@.as_object()) || is<JS::ArrayBuffer>(@js_name@@js_suffix@.as_object()) || is<JS::DataView>(@js_name@@js_suffix@.as_object())))
return vm.throw_completion<JS::TypeError>(JS::ErrorType::NotAnObjectOfType, "@parameter.type.name@");
// TODO: Should we make this a Variant?
@cpp_name@ = JS::make_handle(&@js_name@@js_suffix@.as_object());
@cpp_name@ = JS::make_handle(vm.heap().allocate<WebIDL::BufferSource>(realm, @js_name@@js_suffix@.as_object()));
)~~~");
if (optional) {
scoped_generator.append(R"~~~(
}
)~~~");
}
} else if (parameter.type->name() == "ArrayBufferView") {
scoped_generator.append(R"~~~(
if (!@js_name@@js_suffix@.is_object() || !(is<JS::TypedArrayBase>(@js_name@@js_suffix@.as_object()) || is<JS::DataView>(@js_name@@js_suffix@.as_object())))
return vm.throw_completion<JS::TypeError>(JS::ErrorType::NotAnObjectOfType, "@parameter.type.name@");
auto @cpp_name@ = JS::make_handle(vm.heap().allocate<WebIDL::ArrayBufferView>(realm, @js_name@@js_suffix@.as_object()));
)~~~");
if (optional) {
scoped_generator.append(R"~~~(
@ -1124,28 +1140,40 @@ static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter
// 6. If Type(V) is Object and V has an [[ArrayBufferData]] internal slot, then
// 1. If types includes ArrayBuffer, then return the result of converting V to ArrayBuffer.
for (auto& type : types) {
if (type->name() == "BufferSource") {
union_generator.append(R"~~~(
if (is<JS::TypedArrayBase>(@js_name@@js_suffix@_object) || is<JS::ArrayBuffer>(@js_name@@js_suffix@_object) || is<JS::DataView>(@js_name@@js_suffix@_object))
return JS::make_handle(@js_name@@js_suffix@_object);
)~~~");
}
}
// 2. If types includes object, then return the IDL value that is a reference to the object V.
if (includes_object) {
if (any_of(types, [](auto const& type) { return type->name() == "ArrayBuffer"; }) || includes_object) {
union_generator.append(R"~~~(
return @js_name@@js_suffix@_object;
if (is<JS::ArrayBuffer>(@js_name@@js_suffix@_object))
return JS::make_handle(@js_name@@js_suffix@_object);
}
)~~~");
}
// FIXME: 7. If Type(V) is Object and V has a [[DataView]] internal slot, then:
// 1. If types includes DataView, then return the result of converting V to DataView.
// 2. If types includes object, then return the IDL value that is a reference to the object V.
// 7. If Type(V) is Object and V has a [[DataView]] internal slot, then:
// 1. If types includes DataView, then return the result of converting V to DataView.
// 2. If types includes object, then return the IDL value that is a reference to the object V.
if (any_of(types, [](auto const& type) { return type->name() == "DataView"; }) || includes_object) {
union_generator.append(R"~~~(
if (is<JS::DataView>(@js_name@@js_suffix@_object))
return JS::make_handle(@js_name@@js_suffix@_object);
}
)~~~");
}
// FIXME: 8. If Type(V) is Object and V has a [[TypedArrayName]] internal slot, then:
// 1. If types includes a typed array type whose name is the value of Vs [[TypedArrayName]] internal slot, then return the result of converting V to that type.
// 2. If types includes object, then return the IDL value that is a reference to the object V.
// 8. If Type(V) is Object and V has a [[TypedArrayName]] internal slot, then:
// 1. If types includes a typed array type whose name is the value of Vs [[TypedArrayName]] internal slot, then return the result of converting V to that type.
// 2. If types includes object, then return the IDL value that is a reference to the object V.
auto has_typed_array_name = any_of(types, [](auto const& type) {
return type->name().is_one_of("Int8Array"sv, "Int16Array"sv, "Int32Array"sv, "Uint8Array"sv, "Uint16Array"sv, "Uint32Array"sv, "Uint8ClampedArray"sv, "BigInt64Array"sv, "BigUint64Array", "Float32Array"sv, "Float64Array"sv);
});
if (has_typed_array_name || includes_object) {
union_generator.append(R"~~~(
if (is<JS::TypedArrayBase>(@js_name@@js_suffix@_object))
return JS::make_handle(@js_name@@js_suffix@_object);
}
)~~~");
}
// 9. If IsCallable(V) is true, then:
// 1. If types includes a callback function type, then return the result of converting V to that callback function type.
@ -1679,6 +1707,10 @@ static void generate_wrap_statement(SourceGenerator& generator, DeprecatedString
} else if (type.name() == "Location" || type.name() == "Promise" || type.name() == "Uint8Array" || type.name() == "Uint8ClampedArray" || type.name() == "any") {
scoped_generator.append(R"~~~(
@result_expression@ @value@;
)~~~");
} else if (type.name() == "ArrayBufferView" || type.name() == "BufferSource") {
scoped_generator.append(R"~~~(
@result_expression@ JS::Value(const_cast<JS::Object*>(@value@->raw_object().ptr()));
)~~~");
} else if (is<IDL::UnionType>(type)) {
auto& union_type = verify_cast<IDL::UnionType>(type);
@ -3359,6 +3391,7 @@ void generate_namespace_implementation(IDL::Interface const& interface, StringBu
#include <LibWeb/Bindings/Intrinsics.h>
#include <LibWeb/HTML/Window.h>
#include <LibWeb/HTML/WindowProxy.h>
#include <LibWeb/WebIDL/Buffers.h>
#include <LibWeb/WebIDL/OverloadResolution.h>
)~~~");
@ -3570,6 +3603,7 @@ void generate_constructor_implementation(IDL::Interface const& interface, String
# include <LibWeb/URL/@name@.h>
#endif
#include <LibWeb/HTML/WindowProxy.h>
#include <LibWeb/WebIDL/Buffers.h>
#include <LibWeb/WebIDL/CallbackType.h>
)~~~");
@ -4023,6 +4057,7 @@ void generate_prototype_implementation(IDL::Interface const& interface, StringBu
#include <LibWeb/HTML/Scripting/Environments.h>
#include <LibWeb/HTML/Window.h>
#include <LibWeb/HTML/WindowProxy.h>
#include <LibWeb/WebIDL/Buffers.h>
#include <LibWeb/WebIDL/OverloadResolution.h>
#if __has_include(<LibWeb/Bindings/@prototype_base_class@.h>)

View file

@ -235,6 +235,7 @@ class AsyncGeneratorPrototype;
class GeneratorPrototype;
class WrapForValidIteratorPrototype;
class TypedArrayBase;
class TypedArrayConstructor;
class TypedArrayPrototype;

View file

@ -622,6 +622,7 @@ set(SOURCES
WebGL/WebGLRenderingContext.cpp
WebGL/WebGLRenderingContextBase.cpp
WebIDL/AbstractOperations.cpp
WebIDL/Buffers.cpp
WebIDL/CallbackType.cpp
WebIDL/DOMException.cpp
WebIDL/OverloadResolution.cpp

View file

@ -10,6 +10,7 @@
#include <LibWeb/Bindings/Intrinsics.h>
#include <LibWeb/Crypto/SubtleCrypto.h>
#include <LibWeb/WebIDL/AbstractOperations.h>
#include <LibWeb/WebIDL/Buffers.h>
#include <LibWeb/WebIDL/ExceptionOr.h>
namespace Web::Crypto {
@ -35,14 +36,14 @@ void SubtleCrypto::initialize(JS::Realm& realm)
}
// https://w3c.github.io/webcrypto/#dfn-SubtleCrypto-method-digest
JS::NonnullGCPtr<JS::Promise> SubtleCrypto::digest(String const& algorithm, JS::Handle<JS::Object> const& data)
JS::NonnullGCPtr<JS::Promise> SubtleCrypto::digest(String const& algorithm, JS::Handle<WebIDL::BufferSource> const& data)
{
auto& realm = this->realm();
// 1. Let algorithm be the algorithm parameter passed to the digest() method.
// 2. Let data be the result of getting a copy of the bytes held by the data parameter passed to the digest() method.
auto data_buffer_or_error = WebIDL::get_buffer_source_copy(*data.cell());
auto data_buffer_or_error = WebIDL::get_buffer_source_copy(*data->raw_object());
if (data_buffer_or_error.is_error()) {
auto error = WebIDL::OperationError::create(realm, "Failed to copy bytes from ArrayBuffer"_fly_string);
auto promise = JS::Promise::create(realm);

View file

@ -20,7 +20,7 @@ public:
virtual ~SubtleCrypto() override;
JS::NonnullGCPtr<JS::Promise> digest(String const& algorithm, JS::Handle<JS::Object> const& data);
JS::NonnullGCPtr<JS::Promise> digest(String const& algorithm, JS::Handle<WebIDL::BufferSource> const& data);
private:
explicit SubtleCrypto(JS::Realm&);

View file

@ -9,6 +9,7 @@
#include <LibWeb/Bindings/Intrinsics.h>
#include <LibWeb/Encoding/TextDecoder.h>
#include <LibWeb/WebIDL/AbstractOperations.h>
#include <LibWeb/WebIDL/Buffers.h>
namespace Web::Encoding {
@ -44,14 +45,13 @@ void TextDecoder::initialize(JS::Realm& realm)
}
// https://encoding.spec.whatwg.org/#dom-textdecoder-decode
WebIDL::ExceptionOr<String> TextDecoder::decode(Optional<JS::Handle<JS::Object>> const& input, Optional<TextDecodeOptions> const&) const
WebIDL::ExceptionOr<String> TextDecoder::decode(Optional<JS::Handle<WebIDL::BufferSource>> const& input, Optional<TextDecodeOptions> const&) const
{
if (!input.has_value())
return TRY_OR_THROW_OOM(vm(), m_decoder.to_utf8({}));
// FIXME: Implement the streaming stuff.
auto data_buffer_or_error = WebIDL::get_buffer_source_copy(*input->cell());
auto data_buffer_or_error = WebIDL::get_buffer_source_copy(*input.value()->raw_object());
if (data_buffer_or_error.is_error())
return WebIDL::OperationError::create(realm(), "Failed to copy bytes from ArrayBuffer"_fly_string);
auto& data_buffer = data_buffer_or_error.value();

View file

@ -37,7 +37,7 @@ public:
virtual ~TextDecoder() override;
WebIDL::ExceptionOr<String> decode(Optional<JS::Handle<JS::Object>> const&, Optional<TextDecodeOptions> const& options = {}) const;
WebIDL::ExceptionOr<String> decode(Optional<JS::Handle<WebIDL::BufferSource>> const&, Optional<TextDecodeOptions> const& options = {}) const;
FlyString const& encoding() const { return m_encoding; }
bool fatal() const { return m_fatal; }

View file

@ -50,10 +50,9 @@ JS::NonnullGCPtr<JS::Uint8Array> TextEncoder::encode(String const& input) const
}
// https://encoding.spec.whatwg.org/#dom-textencoder-encodeinto
TextEncoderEncodeIntoResult TextEncoder::encode_into(String const& source, JS::Handle<JS::Object> const& destination) const
TextEncoderEncodeIntoResult TextEncoder::encode_into(String const& source, JS::Handle<WebIDL::BufferSource> const& destination) const
{
auto& destination_array = static_cast<JS::Uint8Array&>(*destination);
auto data = destination_array.data();
auto& data = destination->viewed_array_buffer()->buffer();
// 1. Let read be 0.
unsigned long long read = 0;

View file

@ -12,6 +12,7 @@
#include <LibJS/Forward.h>
#include <LibWeb/Bindings/PlatformObject.h>
#include <LibWeb/Forward.h>
#include <LibWeb/WebIDL/Buffers.h>
namespace Web::Encoding {
@ -32,7 +33,7 @@ public:
virtual ~TextEncoder() override;
JS::NonnullGCPtr<JS::Uint8Array> encode(String const& input) const;
TextEncoderEncodeIntoResult encode_into(String const& source, JS::Handle<JS::Object> const& destination) const;
TextEncoderEncodeIntoResult encode_into(String const& source, JS::Handle<WebIDL::BufferSource> const& destination) const;
static FlyString const& encoding();

View file

@ -11,6 +11,7 @@
#include <LibWeb/HTML/FormControlInfrastructure.h>
#include <LibWeb/URL/URLSearchParams.h>
#include <LibWeb/WebIDL/AbstractOperations.h>
#include <LibWeb/WebIDL/Buffers.h>
#include <LibWeb/WebIDL/ExceptionOr.h>
#include <LibWeb/XHR/FormData.h>
@ -68,7 +69,6 @@ WebIDL::ExceptionOr<Infrastructure::BodyWithType> extract_body(JS::Realm& realm,
Optional<ByteBuffer> type {};
// 10. Switch on object.
// FIXME: Still need to support BufferSource
TRY(object.visit(
[&](JS::Handle<FileAPI::Blob> const& blob) -> WebIDL::ExceptionOr<void> {
// Set source to object.
@ -85,9 +85,9 @@ WebIDL::ExceptionOr<Infrastructure::BodyWithType> extract_body(JS::Realm& realm,
source = TRY_OR_THROW_OOM(vm, ByteBuffer::copy(bytes));
return {};
},
[&](JS::Handle<JS::Object> const& buffer_source) -> WebIDL::ExceptionOr<void> {
[&](JS::Handle<WebIDL::BufferSource> const& buffer_source) -> WebIDL::ExceptionOr<void> {
// Set source to a copy of the bytes held by object.
source = TRY_OR_THROW_OOM(vm, WebIDL::get_buffer_source_copy(*buffer_source.cell()));
source = TRY_OR_THROW_OOM(vm, WebIDL::get_buffer_source_copy(*buffer_source->raw_object()));
return {};
},
[&](JS::Handle<XHR::FormData> const& form_data) -> WebIDL::ExceptionOr<void> {

View file

@ -14,9 +14,9 @@
namespace Web::Fetch {
// https://fetch.spec.whatwg.org/#bodyinit
using BodyInit = Variant<JS::Handle<Streams::ReadableStream>, JS::Handle<FileAPI::Blob>, JS::Handle<JS::Object>, JS::Handle<XHR::FormData>, JS::Handle<URL::URLSearchParams>, String>;
using BodyInit = Variant<JS::Handle<Streams::ReadableStream>, JS::Handle<FileAPI::Blob>, JS::Handle<WebIDL::BufferSource>, JS::Handle<XHR::FormData>, JS::Handle<URL::URLSearchParams>, String>;
using BodyInitOrReadableBytes = Variant<JS::Handle<Streams::ReadableStream>, JS::Handle<FileAPI::Blob>, JS::Handle<JS::Object>, JS::Handle<XHR::FormData>, JS::Handle<URL::URLSearchParams>, String, ReadonlyBytes>;
using BodyInitOrReadableBytes = Variant<JS::Handle<Streams::ReadableStream>, JS::Handle<FileAPI::Blob>, JS::Handle<WebIDL::BufferSource>, JS::Handle<XHR::FormData>, JS::Handle<URL::URLSearchParams>, String, ReadonlyBytes>;
WebIDL::ExceptionOr<Infrastructure::BodyWithType> safely_extract_body(JS::Realm&, BodyInitOrReadableBytes const&);
WebIDL::ExceptionOr<Infrastructure::BodyWithType> extract_body(JS::Realm&, BodyInitOrReadableBytes const&, bool keepalive = false);

View file

@ -19,6 +19,7 @@
#include <LibWeb/Streams/AbstractOperations.h>
#include <LibWeb/Streams/ReadableStreamDefaultReader.h>
#include <LibWeb/WebIDL/AbstractOperations.h>
#include <LibWeb/WebIDL/Buffers.h>
namespace Web::FileAPI {
@ -99,8 +100,8 @@ ErrorOr<ByteBuffer> process_blob_parts(Vector<BlobPart> const& blob_parts, Optio
return bytes.try_append(s.bytes());
},
// 2. If element is a BufferSource, get a copy of the bytes held by the buffer source, and append those bytes to bytes.
[&](JS::Handle<JS::Object> const& buffer_source) -> ErrorOr<void> {
auto data_buffer = TRY(WebIDL::get_buffer_source_copy(*buffer_source.cell()));
[&](JS::Handle<WebIDL::BufferSource> const& buffer_source) -> ErrorOr<void> {
auto data_buffer = TRY(WebIDL::get_buffer_source_copy(*buffer_source->raw_object()));
return bytes.try_append(data_buffer.bytes());
},
// 3. If element is a Blob, append the bytes it represents to bytes.

View file

@ -15,7 +15,7 @@
namespace Web::FileAPI {
using BlobPart = Variant<JS::Handle<JS::Object>, JS::Handle<Blob>, String>;
using BlobPart = Variant<JS::Handle<WebIDL::BufferSource>, JS::Handle<Blob>, String>;
struct BlobPropertyBag {
String type = String {};

View file

@ -678,6 +678,8 @@ class WebGLRenderingContextBase;
}
namespace Web::WebIDL {
class ArrayBufferView;
class BufferSource;
class CallbackType;
class DOMException;

View file

@ -8,6 +8,7 @@
#include <LibJS/Runtime/TypedArray.h>
#include <LibWeb/Bindings/Intrinsics.h>
#include <LibWeb/Geometry/DOMMatrix.h>
#include <LibWeb/WebIDL/Buffers.h>
#include <LibWeb/WebIDL/ExceptionOr.h>
namespace Web::Geometry {
@ -108,13 +109,13 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<DOMMatrix>> DOMMatrix::from_matrix(JS::VM&
}
// https://drafts.fxtf.org/geometry/#dom-dommatrix-fromfloat32array
WebIDL::ExceptionOr<JS::NonnullGCPtr<DOMMatrix>> DOMMatrix::from_float32_array(JS::VM& vm, JS::Handle<JS::Object> const& array32)
WebIDL::ExceptionOr<JS::NonnullGCPtr<DOMMatrix>> DOMMatrix::from_float32_array(JS::VM& vm, JS::Handle<WebIDL::BufferSource> const& array32)
{
if (!is<JS::Float32Array>(*array32))
if (!is<JS::Float32Array>(*array32->raw_object()))
return vm.throw_completion<JS::TypeError>(JS::ErrorType::NotAnObjectOfType, "Float32Array");
auto& realm = *vm.current_realm();
auto& float32_array = static_cast<JS::Float32Array&>(*array32);
auto& float32_array = static_cast<JS::Float32Array&>(*array32->raw_object());
ReadonlySpan<float> elements = float32_array.data();
// If array32 has 6 elements, return the result of invoking create a 2d matrix of type DOMMatrixReadOnly or DOMMatrix as appropriate, with a sequence of numbers taking the values from array32 in the provided order.
@ -133,13 +134,13 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<DOMMatrix>> DOMMatrix::from_float32_array(J
}
// https://drafts.fxtf.org/geometry/#dom-dommatrix-fromfloat64array
WebIDL::ExceptionOr<JS::NonnullGCPtr<DOMMatrix>> DOMMatrix::from_float64_array(JS::VM& vm, JS::Handle<JS::Object> const& array64)
WebIDL::ExceptionOr<JS::NonnullGCPtr<DOMMatrix>> DOMMatrix::from_float64_array(JS::VM& vm, JS::Handle<WebIDL::BufferSource> const& array64)
{
if (!is<JS::Float64Array>(*array64))
if (!is<JS::Float64Array>(*array64->raw_object()))
return vm.throw_completion<JS::TypeError>(JS::ErrorType::NotAnObjectOfType, "Float64Array");
auto& realm = *vm.current_realm();
auto& float64_array = static_cast<JS::Float64Array&>(*array64);
auto& float64_array = static_cast<JS::Float64Array&>(*array64->raw_object());
ReadonlySpan<double> elements = float64_array.data();
// If array64 has 6 elements, return the result of invoking create a 2d matrix of type DOMMatrixReadOnly or DOMMatrix as appropriate, with a sequence of numbers taking the values from array64 in the provided order.

View file

@ -8,6 +8,7 @@
#pragma once
#include <LibWeb/Geometry/DOMMatrixReadOnly.h>
#include <LibWeb/WebIDL/Buffers.h>
namespace Web::Geometry {
@ -25,8 +26,8 @@ public:
virtual ~DOMMatrix() override;
static WebIDL::ExceptionOr<JS::NonnullGCPtr<DOMMatrix>> from_matrix(JS::VM&, DOMMatrixInit other = {});
static WebIDL::ExceptionOr<JS::NonnullGCPtr<DOMMatrix>> from_float32_array(JS::VM&, JS::Handle<JS::Object> const& array32);
static WebIDL::ExceptionOr<JS::NonnullGCPtr<DOMMatrix>> from_float64_array(JS::VM&, JS::Handle<JS::Object> const& array64);
static WebIDL::ExceptionOr<JS::NonnullGCPtr<DOMMatrix>> from_float32_array(JS::VM&, JS::Handle<WebIDL::BufferSource> const& array32);
static WebIDL::ExceptionOr<JS::NonnullGCPtr<DOMMatrix>> from_float64_array(JS::VM&, JS::Handle<WebIDL::BufferSource> const& array64);
void set_m11(double value);
void set_m12(double value);

View file

@ -10,6 +10,7 @@
#include <LibWeb/Geometry/DOMMatrix.h>
#include <LibWeb/Geometry/DOMMatrixReadOnly.h>
#include <LibWeb/Geometry/DOMPoint.h>
#include <LibWeb/WebIDL/Buffers.h>
#include <LibWeb/WebIDL/ExceptionOr.h>
namespace Web::Geometry {
@ -208,13 +209,13 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<DOMMatrixReadOnly>> DOMMatrixReadOnly::from
}
// https://drafts.fxtf.org/geometry/#dom-dommatrixreadonly-fromfloat32array
WebIDL::ExceptionOr<JS::NonnullGCPtr<DOMMatrixReadOnly>> DOMMatrixReadOnly::from_float32_array(JS::VM& vm, JS::Handle<JS::Object> const& array32)
WebIDL::ExceptionOr<JS::NonnullGCPtr<DOMMatrixReadOnly>> DOMMatrixReadOnly::from_float32_array(JS::VM& vm, JS::Handle<WebIDL::BufferSource> const& array32)
{
if (!is<JS::Float32Array>(*array32))
return vm.throw_completion<JS::TypeError>(JS::ErrorType::NotAnObjectOfType, "Float32Array");
auto& realm = *vm.current_realm();
auto& float32_array = static_cast<JS::Float32Array&>(*array32);
auto& float32_array = static_cast<JS::Float32Array&>(*array32->raw_object());
ReadonlySpan<float> elements = float32_array.data();
// If array32 has 6 elements, return the result of invoking create a 2d matrix of type DOMMatrixReadOnly or DOMMatrix as appropriate, with a sequence of numbers taking the values from array32 in the provided order.
@ -233,13 +234,13 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<DOMMatrixReadOnly>> DOMMatrixReadOnly::from
}
// https://drafts.fxtf.org/geometry/#dom-dommatrixreadonly-fromfloat64array
WebIDL::ExceptionOr<JS::NonnullGCPtr<DOMMatrixReadOnly>> DOMMatrixReadOnly::from_float64_array(JS::VM& vm, JS::Handle<JS::Object> const& array64)
WebIDL::ExceptionOr<JS::NonnullGCPtr<DOMMatrixReadOnly>> DOMMatrixReadOnly::from_float64_array(JS::VM& vm, JS::Handle<WebIDL::BufferSource> const& array64)
{
if (!is<JS::Float64Array>(*array64))
return vm.throw_completion<JS::TypeError>(JS::ErrorType::NotAnObjectOfType, "Float64Array");
auto& realm = *vm.current_realm();
auto& float64_array = static_cast<JS::Float64Array&>(*array64);
auto& float64_array = static_cast<JS::Float64Array&>(*array64->raw_object());
ReadonlySpan<double> elements = float64_array.data();
// If array64 has 6 elements, return the result of invoking create a 2d matrix of type DOMMatrixReadOnly or DOMMatrix as appropriate, with a sequence of numbers taking the values from array64 in the provided order.

View file

@ -10,6 +10,7 @@
#include <LibGfx/Matrix4x4.h>
#include <LibWeb/Bindings/PlatformObject.h>
#include <LibWeb/Forward.h>
#include <LibWeb/WebIDL/Buffers.h>
namespace Web::Geometry {
@ -56,8 +57,8 @@ public:
virtual ~DOMMatrixReadOnly() override;
static WebIDL::ExceptionOr<JS::NonnullGCPtr<DOMMatrixReadOnly>> from_matrix(JS::VM&, DOMMatrixInit& other);
static WebIDL::ExceptionOr<JS::NonnullGCPtr<DOMMatrixReadOnly>> from_float32_array(JS::VM&, JS::Handle<JS::Object> const& array32);
static WebIDL::ExceptionOr<JS::NonnullGCPtr<DOMMatrixReadOnly>> from_float64_array(JS::VM&, JS::Handle<JS::Object> const& array64);
static WebIDL::ExceptionOr<JS::NonnullGCPtr<DOMMatrixReadOnly>> from_float32_array(JS::VM&, JS::Handle<WebIDL::BufferSource> const& array32);
static WebIDL::ExceptionOr<JS::NonnullGCPtr<DOMMatrixReadOnly>> from_float64_array(JS::VM&, JS::Handle<WebIDL::BufferSource> const& array64);
// https://drafts.fxtf.org/geometry/#dommatrix-attributes
double m11() const { return m_matrix.elements()[0][0]; }

View file

@ -11,16 +11,17 @@
#include <LibWeb/Bindings/ModulePrototype.h>
#include <LibWeb/WebAssembly/Module.h>
#include <LibWeb/WebAssembly/WebAssembly.h>
#include <LibWeb/WebIDL/Buffers.h>
namespace Web::WebAssembly {
JS_DEFINE_ALLOCATOR(Module);
WebIDL::ExceptionOr<JS::NonnullGCPtr<Module>> Module::construct_impl(JS::Realm& realm, JS::Handle<JS::Object>& bytes)
WebIDL::ExceptionOr<JS::NonnullGCPtr<Module>> Module::construct_impl(JS::Realm& realm, JS::Handle<WebIDL::BufferSource>& bytes)
{
auto& vm = realm.vm();
auto index = TRY(Detail::parse_module(vm, bytes.cell()));
auto index = TRY(Detail::parse_module(vm, bytes->raw_object()));
return vm.heap().allocate<Module>(realm, realm, index);
}

View file

@ -21,7 +21,7 @@ class Module : public Bindings::PlatformObject {
JS_DECLARE_ALLOCATOR(Module);
public:
static WebIDL::ExceptionOr<JS::NonnullGCPtr<Module>> construct_impl(JS::Realm&, JS::Handle<JS::Object>& bytes);
static WebIDL::ExceptionOr<JS::NonnullGCPtr<Module>> construct_impl(JS::Realm&, JS::Handle<WebIDL::BufferSource>& bytes);
size_t index() const { return m_index; }
Wasm::Module const& module() const;

View file

@ -24,6 +24,7 @@
#include <LibWeb/WebAssembly/Module.h>
#include <LibWeb/WebAssembly/Table.h>
#include <LibWeb/WebAssembly/WebAssembly.h>
#include <LibWeb/WebIDL/Buffers.h>
namespace Web::WebAssembly {
@ -53,13 +54,13 @@ void visit_edges(JS::Cell::Visitor& visitor)
}
// https://webassembly.github.io/spec/js-api/#dom-webassembly-validate
bool validate(JS::VM& vm, JS::Handle<JS::Object>& bytes)
bool validate(JS::VM& vm, JS::Handle<WebIDL::BufferSource>& bytes)
{
// 1. Let stableBytes be a copy of the bytes held by the buffer bytes.
// Note: There's no need to copy the bytes here as the buffer data cannot change while we're compiling the module.
// 2. Compile stableBytes as a WebAssembly module and store the results as module.
auto maybe_module = Detail::parse_module(vm, bytes.cell());
auto maybe_module = Detail::parse_module(vm, bytes->raw_object());
// 3. If module is error, return false.
if (maybe_module.is_error())
@ -77,12 +78,12 @@ bool validate(JS::VM& vm, JS::Handle<JS::Object>& bytes)
}
// https://webassembly.github.io/spec/js-api/#dom-webassembly-compile
WebIDL::ExceptionOr<JS::Value> compile(JS::VM& vm, JS::Handle<JS::Object>& bytes)
WebIDL::ExceptionOr<JS::Value> compile(JS::VM& vm, JS::Handle<WebIDL::BufferSource>& bytes)
{
auto& realm = *vm.current_realm();
// FIXME: This shouldn't block!
auto module = Detail::parse_module(vm, bytes.cell());
auto module = Detail::parse_module(vm, bytes->raw_object());
auto promise = JS::Promise::create(realm);
if (module.is_error()) {
@ -96,7 +97,7 @@ WebIDL::ExceptionOr<JS::Value> compile(JS::VM& vm, JS::Handle<JS::Object>& bytes
}
// https://webassembly.github.io/spec/js-api/#dom-webassembly-instantiate
WebIDL::ExceptionOr<JS::Value> instantiate(JS::VM& vm, JS::Handle<JS::Object>& bytes, Optional<JS::Handle<JS::Object>>& import_object)
WebIDL::ExceptionOr<JS::Value> instantiate(JS::VM& vm, JS::Handle<WebIDL::BufferSource>& bytes, Optional<JS::Handle<JS::Object>>& import_object)
{
// FIXME: Implement the importObject parameter.
(void)import_object;
@ -104,7 +105,7 @@ WebIDL::ExceptionOr<JS::Value> instantiate(JS::VM& vm, JS::Handle<JS::Object>& b
auto& realm = *vm.current_realm();
// FIXME: This shouldn't block!
auto module = Detail::parse_module(vm, bytes.cell());
auto module = Detail::parse_module(vm, bytes->raw_object());
auto promise = JS::Promise::create(realm);
if (module.is_error()) {

View file

@ -20,10 +20,10 @@ namespace Web::WebAssembly {
void visit_edges(JS::Cell::Visitor&);
bool validate(JS::VM&, JS::Handle<JS::Object>& bytes);
WebIDL::ExceptionOr<JS::Value> compile(JS::VM&, JS::Handle<JS::Object>& bytes);
bool validate(JS::VM&, JS::Handle<WebIDL::BufferSource>& bytes);
WebIDL::ExceptionOr<JS::Value> compile(JS::VM&, JS::Handle<WebIDL::BufferSource>& bytes);
WebIDL::ExceptionOr<JS::Value> instantiate(JS::VM&, JS::Handle<JS::Object>& bytes, Optional<JS::Handle<JS::Object>>& import_object);
WebIDL::ExceptionOr<JS::Value> instantiate(JS::VM&, JS::Handle<WebIDL::BufferSource>& bytes, Optional<JS::Handle<JS::Object>>& import_object);
WebIDL::ExceptionOr<JS::Value> instantiate(JS::VM&, Module const& module_object, Optional<JS::Handle<JS::Object>>& import_object);
namespace Detail {

View file

@ -0,0 +1,82 @@
/*
* Copyright (c) 2023, Shannon Booth <shannon@serenityos.org>
* Copyright (c) 2023, Matthew Olsson <mattco@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibJS/Runtime/DataView.h>
#include <LibJS/Runtime/TypedArray.h>
#include <LibWeb/WebIDL/Buffers.h>
namespace Web::WebIDL {
u32 BufferableObjectBase::byte_length() const
{
return m_bufferable_object.visit([](auto& obj) { return static_cast<u32>(obj->byte_length()); });
}
JS::NonnullGCPtr<JS::Object> BufferableObjectBase::raw_object()
{
return m_bufferable_object.visit([](auto const& obj) -> JS::NonnullGCPtr<JS::Object> { return obj; });
}
JS::GCPtr<JS::ArrayBuffer> BufferableObjectBase::viewed_array_buffer()
{
return m_bufferable_object.visit(
[](JS::NonnullGCPtr<JS::ArrayBuffer> array_buffer) -> JS::GCPtr<JS::ArrayBuffer> { return array_buffer; },
[](auto const& view) -> JS::GCPtr<JS::ArrayBuffer> { return view->viewed_array_buffer(); });
}
BufferableObject BufferableObjectBase::bufferable_object_from_raw_object(JS::NonnullGCPtr<JS::Object> object)
{
if (is<JS::TypedArrayBase>(*object))
return JS::NonnullGCPtr { static_cast<JS::TypedArrayBase&>(*object) };
if (is<JS::DataView>(*object))
return JS::NonnullGCPtr { static_cast<JS::DataView&>(*object) };
if (is<JS::ArrayBuffer>(*object))
return JS::NonnullGCPtr { static_cast<JS::ArrayBuffer&>(*object) };
VERIFY_NOT_REACHED();
}
BufferableObjectBase::BufferableObjectBase(JS::NonnullGCPtr<JS::Object> object)
: m_bufferable_object(bufferable_object_from_raw_object(object))
{
}
bool BufferableObjectBase::is_typed_array_base() const
{
return m_bufferable_object.has<JS::NonnullGCPtr<JS::TypedArrayBase>>();
}
bool BufferableObjectBase::is_data_view() const
{
return m_bufferable_object.has<JS::NonnullGCPtr<JS::DataView>>();
}
bool BufferableObjectBase::is_array_buffer() const
{
return m_bufferable_object.has<JS::NonnullGCPtr<JS::ArrayBuffer>>();
}
void BufferableObjectBase::visit_edges(Visitor& visitor)
{
Base::visit_edges(visitor);
m_bufferable_object.visit([&](auto& obj) { visitor.visit(obj); });
}
ArrayBufferView::~ArrayBufferView() = default;
u32 ArrayBufferView::byte_offset() const
{
return m_bufferable_object.visit(
[](JS::NonnullGCPtr<JS::ArrayBuffer>) -> u32 { VERIFY_NOT_REACHED(); },
[](auto& view) -> u32 { return static_cast<u32>(view->byte_offset()); });
}
BufferSource::~BufferSource() = default;
}

View file

@ -0,0 +1,85 @@
/*
* Copyright (c) 2023, Shannon Booth <shannon@serenityos.org>
* Copyright (c) 2023, Matthew Olsson <mattco@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/Variant.h>
#include <LibJS/Forward.h>
#include <LibJS/Heap/Cell.h>
namespace Web::WebIDL {
using BufferableObject = Variant<
JS::NonnullGCPtr<JS::TypedArrayBase>,
JS::NonnullGCPtr<JS::DataView>,
JS::NonnullGCPtr<JS::ArrayBuffer>>;
class BufferableObjectBase : public JS::Cell {
JS_CELL(BufferableObjectBase, JS::Cell);
public:
virtual ~BufferableObjectBase() override = default;
u32 byte_length() const;
JS::NonnullGCPtr<JS::Object> raw_object();
JS::GCPtr<JS::ArrayBuffer> viewed_array_buffer();
BufferableObject const& bufferable_object() const { return m_bufferable_object; }
BufferableObject& bufferable_object() { return m_bufferable_object; }
protected:
BufferableObjectBase(JS::NonnullGCPtr<JS::Object>);
virtual void visit_edges(Visitor&) override;
bool is_data_view() const;
bool is_typed_array_base() const;
bool is_array_buffer() const;
static BufferableObject bufferable_object_from_raw_object(JS::NonnullGCPtr<JS::Object>);
BufferableObject m_bufferable_object;
};
// https://webidl.spec.whatwg.org/#ArrayBufferView
//
// typedef (Int8Array or Int16Array or Int32Array or
// Uint8Array or Uint16Array or Uint32Array or Uint8ClampedArray or
// BigInt64Array or BigUint64Array or
// Float32Array or Float64Array or DataView) ArrayBufferView;
class ArrayBufferView : public BufferableObjectBase {
JS_CELL(ArrayBufferView, BufferableObjectBase);
public:
using BufferableObjectBase::BufferableObjectBase;
virtual ~ArrayBufferView() override;
using BufferableObjectBase::is_data_view;
using BufferableObjectBase::is_typed_array_base;
u32 byte_offset() const;
};
// https://webidl.spec.whatwg.org/#BufferSource
//
// typedef (ArrayBufferView or ArrayBuffer) BufferSource;
class BufferSource : public BufferableObjectBase {
JS_CELL(BufferSource, BufferableObjectBase);
public:
using BufferableObjectBase::BufferableObjectBase;
virtual ~BufferSource() override;
using BufferableObjectBase::is_array_buffer;
using BufferableObjectBase::is_data_view;
using BufferableObjectBase::is_typed_array_base;
};
}

View file

@ -20,6 +20,7 @@
#include <LibWeb/HTML/Origin.h>
#include <LibWeb/HTML/Window.h>
#include <LibWeb/WebIDL/AbstractOperations.h>
#include <LibWeb/WebIDL/Buffers.h>
#include <LibWeb/WebIDL/DOMException.h>
#include <LibWeb/WebIDL/ExceptionOr.h>
#include <LibWeb/WebSockets/WebSocket.h>
@ -230,7 +231,7 @@ WebIDL::ExceptionOr<void> WebSocket::close(Optional<u16> code, Optional<String>
}
// https://websockets.spec.whatwg.org/#dom-websocket-send
WebIDL::ExceptionOr<void> WebSocket::send(Variant<JS::Handle<JS::Object>, JS::Handle<FileAPI::Blob>, String> const& data)
WebIDL::ExceptionOr<void> WebSocket::send(Variant<JS::Handle<WebIDL::BufferSource>, JS::Handle<FileAPI::Blob>, String> const& data)
{
auto state = ready_state();
if (state == WebSocket::ReadyState::Connecting)
@ -242,10 +243,10 @@ WebIDL::ExceptionOr<void> WebSocket::send(Variant<JS::Handle<JS::Object>, JS::Ha
m_websocket->send(string);
return {};
},
[this](JS::Handle<JS::Object> const& buffer_source) -> ErrorOr<void> {
[this](JS::Handle<WebIDL::BufferSource> const& buffer_source) -> ErrorOr<void> {
// FIXME: While the spec doesn't say to do this, it's not observable except from potentially throwing OOM.
// Can we avoid this copy?
auto data_buffer = TRY(WebIDL::get_buffer_source_copy(*buffer_source.cell()));
auto data_buffer = TRY(WebIDL::get_buffer_source_copy(*buffer_source->raw_object()));
m_websocket->send(data_buffer, false);
return {};
},

View file

@ -61,7 +61,7 @@ public:
void set_binary_type(String const& type) { m_binary_type = type; }
WebIDL::ExceptionOr<void> close(Optional<u16> code, Optional<String> reason);
WebIDL::ExceptionOr<void> send(Variant<JS::Handle<JS::Object>, JS::Handle<FileAPI::Blob>, String> const& data);
WebIDL::ExceptionOr<void> send(Variant<JS::Handle<WebIDL::BufferSource>, JS::Handle<FileAPI::Blob>, String> const& data);
private:
void on_open();

View file

@ -26,7 +26,7 @@
namespace Web::XHR {
// https://fetch.spec.whatwg.org/#typedefdef-xmlhttprequestbodyinit
using DocumentOrXMLHttpRequestBodyInit = Variant<JS::Handle<Web::DOM::Document>, JS::Handle<Web::FileAPI::Blob>, JS::Handle<JS::Object>, JS::Handle<XHR::FormData>, JS::Handle<Web::URL::URLSearchParams>, AK::String>;
using DocumentOrXMLHttpRequestBodyInit = Variant<JS::Handle<Web::DOM::Document>, JS::Handle<Web::FileAPI::Blob>, JS::Handle<WebIDL::BufferSource>, JS::Handle<XHR::FormData>, JS::Handle<Web::URL::URLSearchParams>, AK::String>;
class XMLHttpRequest final : public XMLHttpRequestEventTarget {
WEB_PLATFORM_OBJECT(XMLHttpRequest, XMLHttpRequestEventTarget);