ladybird/Libraries/LibWeb/FileAPI/FileReaderSync.cpp
Andreas Kling a6dfc74e93 LibWeb: Only set prototype once for object with IDL interface
Before this change, we were going through the chain of base classes for
each IDL interface object and having them set the prototype to their
prototype.

Instead of doing that, reorder things so that we set the right prototype
immediately in Foo::initialize(), and then don't bother in all the base
class overrides.

This knocks off a ~1% profile item on Speedometer 3.
2025-04-20 18:43:11 +02:00

106 lines
3.8 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* Copyright (c) 2025, Tim Ledbetter <tim.ledbetter@ladybird.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibJS/Runtime/ArrayBuffer.h>
#include <LibJS/Runtime/Realm.h>
#include <LibJS/Runtime/TypedArray.h>
#include <LibWeb/Bindings/FileReaderSyncPrototype.h>
#include <LibWeb/Bindings/Intrinsics.h>
#include <LibWeb/FileAPI/Blob.h>
#include <LibWeb/FileAPI/FileReaderSync.h>
#include <LibWeb/HTML/EventLoop/EventLoop.h>
#include <LibWeb/Streams/ReadableStream.h>
#include <LibWeb/Streams/ReadableStreamDefaultReader.h>
#include <LibWeb/WebIDL/ExceptionOr.h>
namespace Web::FileAPI {
GC_DEFINE_ALLOCATOR(FileReaderSync);
FileReaderSync::~FileReaderSync() = default;
FileReaderSync::FileReaderSync(JS::Realm& realm)
: PlatformObject(realm)
{
}
void FileReaderSync::initialize(JS::Realm& realm)
{
WEB_SET_PROTOTYPE_FOR_INTERFACE(FileReaderSync);
Base::initialize(realm);
}
GC::Ref<FileReaderSync> FileReaderSync::create(JS::Realm& realm)
{
return realm.create<FileReaderSync>(realm);
}
GC::Ref<FileReaderSync> FileReaderSync::construct_impl(JS::Realm& realm)
{
return FileReaderSync::create(realm);
}
// https://w3c.github.io/FileAPI/#dfn-readAsArrayBufferSync
WebIDL::ExceptionOr<GC::Root<JS::ArrayBuffer>> FileReaderSync::read_as_array_buffer(Blob& blob)
{
return read_as<GC::Root<JS::ArrayBuffer>>(blob, FileReader::Type::ArrayBuffer);
}
// https://w3c.github.io/FileAPI/#dfn-readAsBinaryStringSync
WebIDL::ExceptionOr<String> FileReaderSync::read_as_binary_string(Blob& blob)
{
return read_as<String>(blob, FileReader::Type::BinaryString);
}
// https://w3c.github.io/FileAPI/#dfn-readAsTextSync
WebIDL::ExceptionOr<String> FileReaderSync::read_as_text(Blob& blob, Optional<String> const& encoding)
{
return read_as<String>(blob, FileReader::Type::Text, encoding);
}
// https://w3c.github.io/FileAPI/#dfn-readAsDataURLSync
WebIDL::ExceptionOr<String> FileReaderSync::read_as_data_url(Blob& blob)
{
return read_as<String>(blob, FileReader::Type::DataURL);
}
template<typename Result>
WebIDL::ExceptionOr<Result> FileReaderSync::read_as(Blob& blob, FileReader::Type type, Optional<String> const& encoding)
{
// 1. Let stream be the result of calling get stream on blob.
auto stream = blob.get_stream();
// 2. Let reader be the result of getting a reader from stream.
auto reader = TRY(stream->get_a_reader());
// 3. Let promise be the result of reading all bytes from stream with reader.
auto promise_capability = reader->read_all_bytes_deprecated();
// FIXME: Try harder to not reach into promise's [[Promise]] slot
auto promise = GC::Ref { as<JS::Promise>(*promise_capability->promise()) };
// 4. Wait for promise to be fulfilled or rejected.
// FIXME: Create spec issue to use WebIDL react to promise steps here instead of this custom logic
HTML::main_thread_event_loop().spin_until(GC::create_function(heap(), [promise]() {
return promise->state() == JS::Promise::State::Fulfilled || promise->state() == JS::Promise::State::Rejected;
}));
// 5. If promise fulfilled with a byte sequence bytes:
auto result = promise->result();
auto* array_buffer = result.extract_pointer<JS::ArrayBuffer>();
if (promise->state() == JS::Promise::State::Fulfilled && array_buffer) {
// AD-HOC: This diverges from the spec as wrritten, where the type argument is specified explicitly for each caller.
// 1. Return the result of package data given bytes, type, blobs type, and encoding.
auto result = TRY(FileReader::blob_package_data(realm(), array_buffer->buffer(), type, blob.type(), encoding));
return result.get<Result>();
}
// 6. Throw promises rejection reason.
VERIFY(promise->state() == JS::Promise::State::Rejected);
return JS::throw_completion(result);
}
}