소스 검색

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>
Shannon Booth 1 년 전
부모
커밋
04c094343f
27개의 변경된 파일283개의 추가작업 그리고 68개의 파일을 삭제
  1. 53 18
      Meta/Lagom/Tools/CodeGenerators/LibWeb/BindingsGenerator/IDLGenerators.cpp
  2. 1 0
      Userland/Libraries/LibJS/Forward.h
  3. 1 0
      Userland/Libraries/LibWeb/CMakeLists.txt
  4. 3 2
      Userland/Libraries/LibWeb/Crypto/SubtleCrypto.cpp
  5. 1 1
      Userland/Libraries/LibWeb/Crypto/SubtleCrypto.h
  6. 3 3
      Userland/Libraries/LibWeb/Encoding/TextDecoder.cpp
  7. 1 1
      Userland/Libraries/LibWeb/Encoding/TextDecoder.h
  8. 2 3
      Userland/Libraries/LibWeb/Encoding/TextEncoder.cpp
  9. 2 1
      Userland/Libraries/LibWeb/Encoding/TextEncoder.h
  10. 3 3
      Userland/Libraries/LibWeb/Fetch/BodyInit.cpp
  11. 2 2
      Userland/Libraries/LibWeb/Fetch/BodyInit.h
  12. 3 2
      Userland/Libraries/LibWeb/FileAPI/Blob.cpp
  13. 1 1
      Userland/Libraries/LibWeb/FileAPI/Blob.h
  14. 2 0
      Userland/Libraries/LibWeb/Forward.h
  15. 7 6
      Userland/Libraries/LibWeb/Geometry/DOMMatrix.cpp
  16. 3 2
      Userland/Libraries/LibWeb/Geometry/DOMMatrix.h
  17. 5 4
      Userland/Libraries/LibWeb/Geometry/DOMMatrixReadOnly.cpp
  18. 3 2
      Userland/Libraries/LibWeb/Geometry/DOMMatrixReadOnly.h
  19. 3 2
      Userland/Libraries/LibWeb/WebAssembly/Module.cpp
  20. 1 1
      Userland/Libraries/LibWeb/WebAssembly/Module.h
  21. 7 6
      Userland/Libraries/LibWeb/WebAssembly/WebAssembly.cpp
  22. 3 3
      Userland/Libraries/LibWeb/WebAssembly/WebAssembly.h
  23. 82 0
      Userland/Libraries/LibWeb/WebIDL/Buffers.cpp
  24. 85 0
      Userland/Libraries/LibWeb/WebIDL/Buffers.h
  25. 4 3
      Userland/Libraries/LibWeb/WebSockets/WebSocket.cpp
  26. 1 1
      Userland/Libraries/LibWeb/WebSockets/WebSocket.h
  27. 1 1
      Userland/Libraries/LibWeb/XHR/XMLHttpRequest.h

+ 53 - 18
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<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))
+        //    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() == "ArrayBuffer"; }) || includes_object) {
+            union_generator.append(R"~~~(
+            if (is<JS::ArrayBuffer>(@js_name@@js_suffix@_object))
                 return JS::make_handle(@js_name@@js_suffix@_object);
+        }
 )~~~");
-            }
         }
+
+        // 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 (includes_object) {
+        if (any_of(types, [](auto const& type) { return type->name() == "DataView"; }) || includes_object) {
             union_generator.append(R"~~~(
-            return @js_name@@js_suffix@_object;
+            if (is<JS::DataView>(@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.
+        // 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);
+        });
 
-        // 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.
+        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>)

+ 1 - 0
Userland/Libraries/LibJS/Forward.h

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

+ 1 - 0
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

+ 3 - 2
Userland/Libraries/LibWeb/Crypto/SubtleCrypto.cpp

@@ -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);

+ 1 - 1
Userland/Libraries/LibWeb/Crypto/SubtleCrypto.h

@@ -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&);

+ 3 - 3
Userland/Libraries/LibWeb/Encoding/TextDecoder.cpp

@@ -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();

+ 1 - 1
Userland/Libraries/LibWeb/Encoding/TextDecoder.h

@@ -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; }

+ 2 - 3
Userland/Libraries/LibWeb/Encoding/TextEncoder.cpp

@@ -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;

+ 2 - 1
Userland/Libraries/LibWeb/Encoding/TextEncoder.h

@@ -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();
 

+ 3 - 3
Userland/Libraries/LibWeb/Fetch/BodyInit.cpp

@@ -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> {

+ 2 - 2
Userland/Libraries/LibWeb/Fetch/BodyInit.h

@@ -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);
 

+ 3 - 2
Userland/Libraries/LibWeb/FileAPI/Blob.cpp

@@ -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.

+ 1 - 1
Userland/Libraries/LibWeb/FileAPI/Blob.h

@@ -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 {};

+ 2 - 0
Userland/Libraries/LibWeb/Forward.h

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

+ 7 - 6
Userland/Libraries/LibWeb/Geometry/DOMMatrix.cpp

@@ -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.

+ 3 - 2
Userland/Libraries/LibWeb/Geometry/DOMMatrix.h

@@ -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);

+ 5 - 4
Userland/Libraries/LibWeb/Geometry/DOMMatrixReadOnly.cpp

@@ -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.

+ 3 - 2
Userland/Libraries/LibWeb/Geometry/DOMMatrixReadOnly.h

@@ -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]; }

+ 3 - 2
Userland/Libraries/LibWeb/WebAssembly/Module.cpp

@@ -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);
 }
 

+ 1 - 1
Userland/Libraries/LibWeb/WebAssembly/Module.h

@@ -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;

+ 7 - 6
Userland/Libraries/LibWeb/WebAssembly/WebAssembly.cpp

@@ -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()) {

+ 3 - 3
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<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 {

+ 82 - 0
Userland/Libraries/LibWeb/WebIDL/Buffers.cpp

@@ -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;
+
+}

+ 85 - 0
Userland/Libraries/LibWeb/WebIDL/Buffers.h

@@ -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;
+};
+
+}

+ 4 - 3
Userland/Libraries/LibWeb/WebSockets/WebSocket.cpp

@@ -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 {};
                 },

+ 1 - 1
Userland/Libraries/LibWeb/WebSockets/WebSocket.h

@@ -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();

+ 1 - 1
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<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);