From 04c094343ffcd9fc2012b1e43658e32e3b935642 Mon Sep 17 00:00:00 2001 From: Shannon Booth Date: Thu, 23 Nov 2023 20:07:25 +1300 Subject: [PATCH] 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 everywhere (and use "any" in the *.idl files). Co-Authored-By: Matthew Olsson --- .../BindingsGenerator/IDLGenerators.cpp | 77 ++++++++++++----- Userland/Libraries/LibJS/Forward.h | 1 + Userland/Libraries/LibWeb/CMakeLists.txt | 1 + .../Libraries/LibWeb/Crypto/SubtleCrypto.cpp | 5 +- .../Libraries/LibWeb/Crypto/SubtleCrypto.h | 2 +- .../Libraries/LibWeb/Encoding/TextDecoder.cpp | 6 +- .../Libraries/LibWeb/Encoding/TextDecoder.h | 2 +- .../Libraries/LibWeb/Encoding/TextEncoder.cpp | 5 +- .../Libraries/LibWeb/Encoding/TextEncoder.h | 3 +- Userland/Libraries/LibWeb/Fetch/BodyInit.cpp | 6 +- Userland/Libraries/LibWeb/Fetch/BodyInit.h | 4 +- Userland/Libraries/LibWeb/FileAPI/Blob.cpp | 5 +- Userland/Libraries/LibWeb/FileAPI/Blob.h | 2 +- Userland/Libraries/LibWeb/Forward.h | 2 + .../Libraries/LibWeb/Geometry/DOMMatrix.cpp | 13 +-- .../Libraries/LibWeb/Geometry/DOMMatrix.h | 5 +- .../LibWeb/Geometry/DOMMatrixReadOnly.cpp | 9 +- .../LibWeb/Geometry/DOMMatrixReadOnly.h | 5 +- .../Libraries/LibWeb/WebAssembly/Module.cpp | 5 +- .../Libraries/LibWeb/WebAssembly/Module.h | 2 +- .../LibWeb/WebAssembly/WebAssembly.cpp | 13 +-- .../LibWeb/WebAssembly/WebAssembly.h | 6 +- Userland/Libraries/LibWeb/WebIDL/Buffers.cpp | 82 ++++++++++++++++++ Userland/Libraries/LibWeb/WebIDL/Buffers.h | 85 +++++++++++++++++++ .../Libraries/LibWeb/WebSockets/WebSocket.cpp | 7 +- .../Libraries/LibWeb/WebSockets/WebSocket.h | 2 +- .../Libraries/LibWeb/XHR/XMLHttpRequest.h | 2 +- 27 files changed, 286 insertions(+), 71 deletions(-) create mode 100644 Userland/Libraries/LibWeb/WebIDL/Buffers.cpp create mode 100644 Userland/Libraries/LibWeb/WebIDL/Buffers.h diff --git a/Meta/Lagom/Tools/CodeGenerators/LibWeb/BindingsGenerator/IDLGenerators.cpp b/Meta/Lagom/Tools/CodeGenerators/LibWeb/BindingsGenerator/IDLGenerators.cpp index 47af5b9eb57..cd09ab37164 100644 --- a/Meta/Lagom/Tools/CodeGenerators/LibWeb/BindingsGenerator/IDLGenerators.cpp +++ b/Meta/Lagom/Tools/CodeGenerators/LibWeb/BindingsGenerator/IDLGenerators.cpp @@ -180,7 +180,10 @@ CppType idl_type_name_to_cpp_type(Type const& type, Interface const& interface) return { .name = "JS::Handle", .sequence_storage_type = SequenceStorageType::Vector }; if (type.name() == "BufferSource") - return { .name = "JS::Handle", .sequence_storage_type = SequenceStorageType::MarkedVector }; + return { .name = "JS::Handle", .sequence_storage_type = SequenceStorageType::MarkedVector }; + + if (type.name() == "ArrayBufferView") + return { .name = "JS::Handle", .sequence_storage_type = SequenceStorageType::MarkedVector }; if (type.name() == "File") return { .name = "JS::Handle", .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> @cpp_name@; + Optional> @cpp_name@; if (!@js_name@@js_suffix@.is_undefined()) { )~~~"); } else { scoped_generator.append(R"~~~( - JS::Handle @cpp_name@; + JS::Handle @cpp_name@; )~~~"); } scoped_generator.append(R"~~~( if (!@js_name@@js_suffix@.is_object() || !(is(@js_name@@js_suffix@.as_object()) || is(@js_name@@js_suffix@.as_object()) || is(@js_name@@js_suffix@.as_object()))) return vm.throw_completion(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(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_name@@js_suffix@.as_object()) || is(@js_name@@js_suffix@.as_object()))) + return vm.throw_completion(JS::ErrorType::NotAnObjectOfType, "@parameter.type.name@"); + + auto @cpp_name@ = JS::make_handle(vm.heap().allocate(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_name@@js_suffix@_object) || is(@js_name@@js_suffix@_object) || is(@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_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_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 V’s [[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 V’s [[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_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(@value@->raw_object().ptr())); )~~~"); } else if (is(type)) { auto& union_type = verify_cast(type); @@ -3359,6 +3391,7 @@ void generate_namespace_implementation(IDL::Interface const& interface, StringBu #include #include #include +#include #include )~~~"); @@ -3570,6 +3603,7 @@ void generate_constructor_implementation(IDL::Interface const& interface, String # include #endif #include +#include #include )~~~"); @@ -4023,6 +4057,7 @@ void generate_prototype_implementation(IDL::Interface const& interface, StringBu #include #include #include +#include #include #if __has_include() diff --git a/Userland/Libraries/LibJS/Forward.h b/Userland/Libraries/LibJS/Forward.h index f733a322571..27545afb4b2 100644 --- a/Userland/Libraries/LibJS/Forward.h +++ b/Userland/Libraries/LibJS/Forward.h @@ -235,6 +235,7 @@ class AsyncGeneratorPrototype; class GeneratorPrototype; class WrapForValidIteratorPrototype; +class TypedArrayBase; class TypedArrayConstructor; class TypedArrayPrototype; diff --git a/Userland/Libraries/LibWeb/CMakeLists.txt b/Userland/Libraries/LibWeb/CMakeLists.txt index 94c64697dd1..c0e155a5e89 100644 --- a/Userland/Libraries/LibWeb/CMakeLists.txt +++ b/Userland/Libraries/LibWeb/CMakeLists.txt @@ -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 diff --git a/Userland/Libraries/LibWeb/Crypto/SubtleCrypto.cpp b/Userland/Libraries/LibWeb/Crypto/SubtleCrypto.cpp index 442e176afca..639ff216aae 100644 --- a/Userland/Libraries/LibWeb/Crypto/SubtleCrypto.cpp +++ b/Userland/Libraries/LibWeb/Crypto/SubtleCrypto.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include namespace Web::Crypto { @@ -35,14 +36,14 @@ void SubtleCrypto::initialize(JS::Realm& realm) } // https://w3c.github.io/webcrypto/#dfn-SubtleCrypto-method-digest -JS::NonnullGCPtr SubtleCrypto::digest(String const& algorithm, JS::Handle const& data) +JS::NonnullGCPtr SubtleCrypto::digest(String const& algorithm, JS::Handle 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); diff --git a/Userland/Libraries/LibWeb/Crypto/SubtleCrypto.h b/Userland/Libraries/LibWeb/Crypto/SubtleCrypto.h index 886e9327e88..697693d5233 100644 --- a/Userland/Libraries/LibWeb/Crypto/SubtleCrypto.h +++ b/Userland/Libraries/LibWeb/Crypto/SubtleCrypto.h @@ -20,7 +20,7 @@ public: virtual ~SubtleCrypto() override; - JS::NonnullGCPtr digest(String const& algorithm, JS::Handle const& data); + JS::NonnullGCPtr digest(String const& algorithm, JS::Handle const& data); private: explicit SubtleCrypto(JS::Realm&); diff --git a/Userland/Libraries/LibWeb/Encoding/TextDecoder.cpp b/Userland/Libraries/LibWeb/Encoding/TextDecoder.cpp index 50c93725114..b8e31ac4b70 100644 --- a/Userland/Libraries/LibWeb/Encoding/TextDecoder.cpp +++ b/Userland/Libraries/LibWeb/Encoding/TextDecoder.cpp @@ -9,6 +9,7 @@ #include #include #include +#include namespace Web::Encoding { @@ -44,14 +45,13 @@ void TextDecoder::initialize(JS::Realm& realm) } // https://encoding.spec.whatwg.org/#dom-textdecoder-decode -WebIDL::ExceptionOr TextDecoder::decode(Optional> const& input, Optional const&) const +WebIDL::ExceptionOr TextDecoder::decode(Optional> const& input, Optional 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(); diff --git a/Userland/Libraries/LibWeb/Encoding/TextDecoder.h b/Userland/Libraries/LibWeb/Encoding/TextDecoder.h index 14cf851136d..72659873add 100644 --- a/Userland/Libraries/LibWeb/Encoding/TextDecoder.h +++ b/Userland/Libraries/LibWeb/Encoding/TextDecoder.h @@ -37,7 +37,7 @@ public: virtual ~TextDecoder() override; - WebIDL::ExceptionOr decode(Optional> const&, Optional const& options = {}) const; + WebIDL::ExceptionOr decode(Optional> const&, Optional const& options = {}) const; FlyString const& encoding() const { return m_encoding; } bool fatal() const { return m_fatal; } diff --git a/Userland/Libraries/LibWeb/Encoding/TextEncoder.cpp b/Userland/Libraries/LibWeb/Encoding/TextEncoder.cpp index 7f63234851e..a84e03d885a 100644 --- a/Userland/Libraries/LibWeb/Encoding/TextEncoder.cpp +++ b/Userland/Libraries/LibWeb/Encoding/TextEncoder.cpp @@ -50,10 +50,9 @@ JS::NonnullGCPtr TextEncoder::encode(String const& input) const } // https://encoding.spec.whatwg.org/#dom-textencoder-encodeinto -TextEncoderEncodeIntoResult TextEncoder::encode_into(String const& source, JS::Handle const& destination) const +TextEncoderEncodeIntoResult TextEncoder::encode_into(String const& source, JS::Handle const& destination) const { - auto& destination_array = static_cast(*destination); - auto data = destination_array.data(); + auto& data = destination->viewed_array_buffer()->buffer(); // 1. Let read be 0. unsigned long long read = 0; diff --git a/Userland/Libraries/LibWeb/Encoding/TextEncoder.h b/Userland/Libraries/LibWeb/Encoding/TextEncoder.h index 044b05d7b17..3e405b43055 100644 --- a/Userland/Libraries/LibWeb/Encoding/TextEncoder.h +++ b/Userland/Libraries/LibWeb/Encoding/TextEncoder.h @@ -12,6 +12,7 @@ #include #include #include +#include namespace Web::Encoding { @@ -32,7 +33,7 @@ public: virtual ~TextEncoder() override; JS::NonnullGCPtr encode(String const& input) const; - TextEncoderEncodeIntoResult encode_into(String const& source, JS::Handle const& destination) const; + TextEncoderEncodeIntoResult encode_into(String const& source, JS::Handle const& destination) const; static FlyString const& encoding(); diff --git a/Userland/Libraries/LibWeb/Fetch/BodyInit.cpp b/Userland/Libraries/LibWeb/Fetch/BodyInit.cpp index 815b0bd6520..4fe430520b6 100644 --- a/Userland/Libraries/LibWeb/Fetch/BodyInit.cpp +++ b/Userland/Libraries/LibWeb/Fetch/BodyInit.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -68,7 +69,6 @@ WebIDL::ExceptionOr extract_body(JS::Realm& realm, Optional type {}; // 10. Switch on object. - // FIXME: Still need to support BufferSource TRY(object.visit( [&](JS::Handle const& blob) -> WebIDL::ExceptionOr { // Set source to object. @@ -85,9 +85,9 @@ WebIDL::ExceptionOr extract_body(JS::Realm& realm, source = TRY_OR_THROW_OOM(vm, ByteBuffer::copy(bytes)); return {}; }, - [&](JS::Handle const& buffer_source) -> WebIDL::ExceptionOr { + [&](JS::Handle const& buffer_source) -> WebIDL::ExceptionOr { // 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 const& form_data) -> WebIDL::ExceptionOr { diff --git a/Userland/Libraries/LibWeb/Fetch/BodyInit.h b/Userland/Libraries/LibWeb/Fetch/BodyInit.h index 787c19ffcb7..62f20a2fca6 100644 --- a/Userland/Libraries/LibWeb/Fetch/BodyInit.h +++ b/Userland/Libraries/LibWeb/Fetch/BodyInit.h @@ -14,9 +14,9 @@ namespace Web::Fetch { // https://fetch.spec.whatwg.org/#bodyinit -using BodyInit = Variant, JS::Handle, JS::Handle, JS::Handle, JS::Handle, String>; +using BodyInit = Variant, JS::Handle, JS::Handle, JS::Handle, JS::Handle, String>; -using BodyInitOrReadableBytes = Variant, JS::Handle, JS::Handle, JS::Handle, JS::Handle, String, ReadonlyBytes>; +using BodyInitOrReadableBytes = Variant, JS::Handle, JS::Handle, JS::Handle, JS::Handle, String, ReadonlyBytes>; WebIDL::ExceptionOr safely_extract_body(JS::Realm&, BodyInitOrReadableBytes const&); WebIDL::ExceptionOr extract_body(JS::Realm&, BodyInitOrReadableBytes const&, bool keepalive = false); diff --git a/Userland/Libraries/LibWeb/FileAPI/Blob.cpp b/Userland/Libraries/LibWeb/FileAPI/Blob.cpp index aaddf967b9c..493a462bd62 100644 --- a/Userland/Libraries/LibWeb/FileAPI/Blob.cpp +++ b/Userland/Libraries/LibWeb/FileAPI/Blob.cpp @@ -19,6 +19,7 @@ #include #include #include +#include namespace Web::FileAPI { @@ -99,8 +100,8 @@ ErrorOr process_blob_parts(Vector 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 const& buffer_source) -> ErrorOr { - auto data_buffer = TRY(WebIDL::get_buffer_source_copy(*buffer_source.cell())); + [&](JS::Handle const& buffer_source) -> ErrorOr { + 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. diff --git a/Userland/Libraries/LibWeb/FileAPI/Blob.h b/Userland/Libraries/LibWeb/FileAPI/Blob.h index 8c9ee266b95..ad9566cab8b 100644 --- a/Userland/Libraries/LibWeb/FileAPI/Blob.h +++ b/Userland/Libraries/LibWeb/FileAPI/Blob.h @@ -15,7 +15,7 @@ namespace Web::FileAPI { -using BlobPart = Variant, JS::Handle, String>; +using BlobPart = Variant, JS::Handle, String>; struct BlobPropertyBag { String type = String {}; diff --git a/Userland/Libraries/LibWeb/Forward.h b/Userland/Libraries/LibWeb/Forward.h index 688b7d43652..6964c226938 100644 --- a/Userland/Libraries/LibWeb/Forward.h +++ b/Userland/Libraries/LibWeb/Forward.h @@ -678,6 +678,8 @@ class WebGLRenderingContextBase; } namespace Web::WebIDL { +class ArrayBufferView; +class BufferSource; class CallbackType; class DOMException; diff --git a/Userland/Libraries/LibWeb/Geometry/DOMMatrix.cpp b/Userland/Libraries/LibWeb/Geometry/DOMMatrix.cpp index 0ca5aba2f14..a000161f7b2 100644 --- a/Userland/Libraries/LibWeb/Geometry/DOMMatrix.cpp +++ b/Userland/Libraries/LibWeb/Geometry/DOMMatrix.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include namespace Web::Geometry { @@ -108,13 +109,13 @@ WebIDL::ExceptionOr> DOMMatrix::from_matrix(JS::VM& } // https://drafts.fxtf.org/geometry/#dom-dommatrix-fromfloat32array -WebIDL::ExceptionOr> DOMMatrix::from_float32_array(JS::VM& vm, JS::Handle const& array32) +WebIDL::ExceptionOr> DOMMatrix::from_float32_array(JS::VM& vm, JS::Handle const& array32) { - if (!is(*array32)) + if (!is(*array32->raw_object())) return vm.throw_completion(JS::ErrorType::NotAnObjectOfType, "Float32Array"); auto& realm = *vm.current_realm(); - auto& float32_array = static_cast(*array32); + auto& float32_array = static_cast(*array32->raw_object()); ReadonlySpan 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> DOMMatrix::from_float32_array(J } // https://drafts.fxtf.org/geometry/#dom-dommatrix-fromfloat64array -WebIDL::ExceptionOr> DOMMatrix::from_float64_array(JS::VM& vm, JS::Handle const& array64) +WebIDL::ExceptionOr> DOMMatrix::from_float64_array(JS::VM& vm, JS::Handle const& array64) { - if (!is(*array64)) + if (!is(*array64->raw_object())) return vm.throw_completion(JS::ErrorType::NotAnObjectOfType, "Float64Array"); auto& realm = *vm.current_realm(); - auto& float64_array = static_cast(*array64); + auto& float64_array = static_cast(*array64->raw_object()); ReadonlySpan 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. diff --git a/Userland/Libraries/LibWeb/Geometry/DOMMatrix.h b/Userland/Libraries/LibWeb/Geometry/DOMMatrix.h index 72ce3378dbc..834bcdb0958 100644 --- a/Userland/Libraries/LibWeb/Geometry/DOMMatrix.h +++ b/Userland/Libraries/LibWeb/Geometry/DOMMatrix.h @@ -8,6 +8,7 @@ #pragma once #include +#include namespace Web::Geometry { @@ -25,8 +26,8 @@ public: virtual ~DOMMatrix() override; static WebIDL::ExceptionOr> from_matrix(JS::VM&, DOMMatrixInit other = {}); - static WebIDL::ExceptionOr> from_float32_array(JS::VM&, JS::Handle const& array32); - static WebIDL::ExceptionOr> from_float64_array(JS::VM&, JS::Handle const& array64); + static WebIDL::ExceptionOr> from_float32_array(JS::VM&, JS::Handle const& array32); + static WebIDL::ExceptionOr> from_float64_array(JS::VM&, JS::Handle const& array64); void set_m11(double value); void set_m12(double value); diff --git a/Userland/Libraries/LibWeb/Geometry/DOMMatrixReadOnly.cpp b/Userland/Libraries/LibWeb/Geometry/DOMMatrixReadOnly.cpp index 2c8c62b1ea0..f8b3a2d1733 100644 --- a/Userland/Libraries/LibWeb/Geometry/DOMMatrixReadOnly.cpp +++ b/Userland/Libraries/LibWeb/Geometry/DOMMatrixReadOnly.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include namespace Web::Geometry { @@ -208,13 +209,13 @@ WebIDL::ExceptionOr> DOMMatrixReadOnly::from } // https://drafts.fxtf.org/geometry/#dom-dommatrixreadonly-fromfloat32array -WebIDL::ExceptionOr> DOMMatrixReadOnly::from_float32_array(JS::VM& vm, JS::Handle const& array32) +WebIDL::ExceptionOr> DOMMatrixReadOnly::from_float32_array(JS::VM& vm, JS::Handle const& array32) { if (!is(*array32)) return vm.throw_completion(JS::ErrorType::NotAnObjectOfType, "Float32Array"); auto& realm = *vm.current_realm(); - auto& float32_array = static_cast(*array32); + auto& float32_array = static_cast(*array32->raw_object()); ReadonlySpan 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> DOMMatrixReadOnly::from } // https://drafts.fxtf.org/geometry/#dom-dommatrixreadonly-fromfloat64array -WebIDL::ExceptionOr> DOMMatrixReadOnly::from_float64_array(JS::VM& vm, JS::Handle const& array64) +WebIDL::ExceptionOr> DOMMatrixReadOnly::from_float64_array(JS::VM& vm, JS::Handle const& array64) { if (!is(*array64)) return vm.throw_completion(JS::ErrorType::NotAnObjectOfType, "Float64Array"); auto& realm = *vm.current_realm(); - auto& float64_array = static_cast(*array64); + auto& float64_array = static_cast(*array64->raw_object()); ReadonlySpan 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. diff --git a/Userland/Libraries/LibWeb/Geometry/DOMMatrixReadOnly.h b/Userland/Libraries/LibWeb/Geometry/DOMMatrixReadOnly.h index 80a48c94981..9b9f49f1355 100644 --- a/Userland/Libraries/LibWeb/Geometry/DOMMatrixReadOnly.h +++ b/Userland/Libraries/LibWeb/Geometry/DOMMatrixReadOnly.h @@ -10,6 +10,7 @@ #include #include #include +#include namespace Web::Geometry { @@ -56,8 +57,8 @@ public: virtual ~DOMMatrixReadOnly() override; static WebIDL::ExceptionOr> from_matrix(JS::VM&, DOMMatrixInit& other); - static WebIDL::ExceptionOr> from_float32_array(JS::VM&, JS::Handle const& array32); - static WebIDL::ExceptionOr> from_float64_array(JS::VM&, JS::Handle const& array64); + static WebIDL::ExceptionOr> from_float32_array(JS::VM&, JS::Handle const& array32); + static WebIDL::ExceptionOr> from_float64_array(JS::VM&, JS::Handle const& array64); // https://drafts.fxtf.org/geometry/#dommatrix-attributes double m11() const { return m_matrix.elements()[0][0]; } diff --git a/Userland/Libraries/LibWeb/WebAssembly/Module.cpp b/Userland/Libraries/LibWeb/WebAssembly/Module.cpp index e83d601ffe5..45e37424422 100644 --- a/Userland/Libraries/LibWeb/WebAssembly/Module.cpp +++ b/Userland/Libraries/LibWeb/WebAssembly/Module.cpp @@ -11,16 +11,17 @@ #include #include #include +#include namespace Web::WebAssembly { JS_DEFINE_ALLOCATOR(Module); -WebIDL::ExceptionOr> Module::construct_impl(JS::Realm& realm, JS::Handle& bytes) +WebIDL::ExceptionOr> Module::construct_impl(JS::Realm& realm, JS::Handle& 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(realm, realm, index); } diff --git a/Userland/Libraries/LibWeb/WebAssembly/Module.h b/Userland/Libraries/LibWeb/WebAssembly/Module.h index 0433ec14052..2786919fdd2 100644 --- a/Userland/Libraries/LibWeb/WebAssembly/Module.h +++ b/Userland/Libraries/LibWeb/WebAssembly/Module.h @@ -21,7 +21,7 @@ class Module : public Bindings::PlatformObject { JS_DECLARE_ALLOCATOR(Module); public: - static WebIDL::ExceptionOr> construct_impl(JS::Realm&, JS::Handle& bytes); + static WebIDL::ExceptionOr> construct_impl(JS::Realm&, JS::Handle& bytes); size_t index() const { return m_index; } Wasm::Module const& module() const; diff --git a/Userland/Libraries/LibWeb/WebAssembly/WebAssembly.cpp b/Userland/Libraries/LibWeb/WebAssembly/WebAssembly.cpp index 358aee16b1b..08bafbd996b 100644 --- a/Userland/Libraries/LibWeb/WebAssembly/WebAssembly.cpp +++ b/Userland/Libraries/LibWeb/WebAssembly/WebAssembly.cpp @@ -24,6 +24,7 @@ #include #include #include +#include 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& bytes) +bool validate(JS::VM& vm, JS::Handle& 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& bytes) } // https://webassembly.github.io/spec/js-api/#dom-webassembly-compile -WebIDL::ExceptionOr compile(JS::VM& vm, JS::Handle& bytes) +WebIDL::ExceptionOr compile(JS::VM& vm, JS::Handle& 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 compile(JS::VM& vm, JS::Handle& bytes } // https://webassembly.github.io/spec/js-api/#dom-webassembly-instantiate -WebIDL::ExceptionOr instantiate(JS::VM& vm, JS::Handle& bytes, Optional>& import_object) +WebIDL::ExceptionOr instantiate(JS::VM& vm, JS::Handle& bytes, Optional>& import_object) { // FIXME: Implement the importObject parameter. (void)import_object; @@ -104,7 +105,7 @@ WebIDL::ExceptionOr instantiate(JS::VM& vm, JS::Handle& 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()) { diff --git a/Userland/Libraries/LibWeb/WebAssembly/WebAssembly.h b/Userland/Libraries/LibWeb/WebAssembly/WebAssembly.h index d3ff02e7c7a..6719b440288 100644 --- a/Userland/Libraries/LibWeb/WebAssembly/WebAssembly.h +++ b/Userland/Libraries/LibWeb/WebAssembly/WebAssembly.h @@ -20,10 +20,10 @@ namespace Web::WebAssembly { void visit_edges(JS::Cell::Visitor&); -bool validate(JS::VM&, JS::Handle& bytes); -WebIDL::ExceptionOr compile(JS::VM&, JS::Handle& bytes); +bool validate(JS::VM&, JS::Handle& bytes); +WebIDL::ExceptionOr compile(JS::VM&, JS::Handle& bytes); -WebIDL::ExceptionOr instantiate(JS::VM&, JS::Handle& bytes, Optional>& import_object); +WebIDL::ExceptionOr instantiate(JS::VM&, JS::Handle& bytes, Optional>& import_object); WebIDL::ExceptionOr instantiate(JS::VM&, Module const& module_object, Optional>& import_object); namespace Detail { diff --git a/Userland/Libraries/LibWeb/WebIDL/Buffers.cpp b/Userland/Libraries/LibWeb/WebIDL/Buffers.cpp new file mode 100644 index 00000000000..7ed150b8025 --- /dev/null +++ b/Userland/Libraries/LibWeb/WebIDL/Buffers.cpp @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2023, Shannon Booth + * Copyright (c) 2023, Matthew Olsson + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include + +namespace Web::WebIDL { + +u32 BufferableObjectBase::byte_length() const +{ + return m_bufferable_object.visit([](auto& obj) { return static_cast(obj->byte_length()); }); +} + +JS::NonnullGCPtr BufferableObjectBase::raw_object() +{ + return m_bufferable_object.visit([](auto const& obj) -> JS::NonnullGCPtr { return obj; }); +} + +JS::GCPtr BufferableObjectBase::viewed_array_buffer() +{ + return m_bufferable_object.visit( + [](JS::NonnullGCPtr array_buffer) -> JS::GCPtr { return array_buffer; }, + [](auto const& view) -> JS::GCPtr { return view->viewed_array_buffer(); }); +} + +BufferableObject BufferableObjectBase::bufferable_object_from_raw_object(JS::NonnullGCPtr object) +{ + if (is(*object)) + return JS::NonnullGCPtr { static_cast(*object) }; + + if (is(*object)) + return JS::NonnullGCPtr { static_cast(*object) }; + + if (is(*object)) + return JS::NonnullGCPtr { static_cast(*object) }; + + VERIFY_NOT_REACHED(); +} + +BufferableObjectBase::BufferableObjectBase(JS::NonnullGCPtr object) + : m_bufferable_object(bufferable_object_from_raw_object(object)) +{ +} + +bool BufferableObjectBase::is_typed_array_base() const +{ + return m_bufferable_object.has>(); +} + +bool BufferableObjectBase::is_data_view() const +{ + return m_bufferable_object.has>(); +} + +bool BufferableObjectBase::is_array_buffer() const +{ + return m_bufferable_object.has>(); +} + +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) -> u32 { VERIFY_NOT_REACHED(); }, + [](auto& view) -> u32 { return static_cast(view->byte_offset()); }); +} + +BufferSource::~BufferSource() = default; + +} diff --git a/Userland/Libraries/LibWeb/WebIDL/Buffers.h b/Userland/Libraries/LibWeb/WebIDL/Buffers.h new file mode 100644 index 00000000000..848239587d6 --- /dev/null +++ b/Userland/Libraries/LibWeb/WebIDL/Buffers.h @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2023, Shannon Booth + * Copyright (c) 2023, Matthew Olsson + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include +#include + +namespace Web::WebIDL { + +using BufferableObject = Variant< + JS::NonnullGCPtr, + JS::NonnullGCPtr, + JS::NonnullGCPtr>; + +class BufferableObjectBase : public JS::Cell { + JS_CELL(BufferableObjectBase, JS::Cell); + +public: + virtual ~BufferableObjectBase() override = default; + + u32 byte_length() const; + + JS::NonnullGCPtr raw_object(); + JS::GCPtr viewed_array_buffer(); + + BufferableObject const& bufferable_object() const { return m_bufferable_object; } + BufferableObject& bufferable_object() { return m_bufferable_object; } + +protected: + BufferableObjectBase(JS::NonnullGCPtr); + + 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); + + 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; +}; + +} diff --git a/Userland/Libraries/LibWeb/WebSockets/WebSocket.cpp b/Userland/Libraries/LibWeb/WebSockets/WebSocket.cpp index aefb786ad57..620aba912fb 100644 --- a/Userland/Libraries/LibWeb/WebSockets/WebSocket.cpp +++ b/Userland/Libraries/LibWeb/WebSockets/WebSocket.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -230,7 +231,7 @@ WebIDL::ExceptionOr WebSocket::close(Optional code, Optional } // https://websockets.spec.whatwg.org/#dom-websocket-send -WebIDL::ExceptionOr WebSocket::send(Variant, JS::Handle, String> const& data) +WebIDL::ExceptionOr WebSocket::send(Variant, JS::Handle, String> const& data) { auto state = ready_state(); if (state == WebSocket::ReadyState::Connecting) @@ -242,10 +243,10 @@ WebIDL::ExceptionOr WebSocket::send(Variant, JS::Ha m_websocket->send(string); return {}; }, - [this](JS::Handle const& buffer_source) -> ErrorOr { + [this](JS::Handle const& buffer_source) -> ErrorOr { // 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 {}; }, diff --git a/Userland/Libraries/LibWeb/WebSockets/WebSocket.h b/Userland/Libraries/LibWeb/WebSockets/WebSocket.h index f8735e9499e..ec71e305ec7 100644 --- a/Userland/Libraries/LibWeb/WebSockets/WebSocket.h +++ b/Userland/Libraries/LibWeb/WebSockets/WebSocket.h @@ -61,7 +61,7 @@ public: void set_binary_type(String const& type) { m_binary_type = type; } WebIDL::ExceptionOr close(Optional code, Optional reason); - WebIDL::ExceptionOr send(Variant, JS::Handle, String> const& data); + WebIDL::ExceptionOr send(Variant, JS::Handle, String> const& data); private: void on_open(); diff --git a/Userland/Libraries/LibWeb/XHR/XMLHttpRequest.h b/Userland/Libraries/LibWeb/XHR/XMLHttpRequest.h index 3b45cf9b79b..8e49692db8f 100644 --- a/Userland/Libraries/LibWeb/XHR/XMLHttpRequest.h +++ b/Userland/Libraries/LibWeb/XHR/XMLHttpRequest.h @@ -26,7 +26,7 @@ namespace Web::XHR { // https://fetch.spec.whatwg.org/#typedefdef-xmlhttprequestbodyinit -using DocumentOrXMLHttpRequestBodyInit = Variant, JS::Handle, JS::Handle, JS::Handle, JS::Handle, AK::String>; +using DocumentOrXMLHttpRequestBodyInit = Variant, JS::Handle, JS::Handle, JS::Handle, JS::Handle, AK::String>; class XMLHttpRequest final : public XMLHttpRequestEventTarget { WEB_PLATFORM_OBJECT(XMLHttpRequest, XMLHttpRequestEventTarget);