mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-12-11 17:00:37 +00:00
Compare commits
9 commits
24f8b97487
...
8071afd7f7
Author | SHA1 | Date | |
---|---|---|---|
|
8071afd7f7 | ||
|
99073c0561 | ||
|
93f258deb7 | ||
|
19bbfb023a | ||
|
3f572d9ab7 | ||
|
c6d0f87bb7 | ||
|
f110edebd1 | ||
|
719a69215d | ||
|
2b5235b6de |
22 changed files with 357 additions and 313 deletions
|
@ -76,7 +76,7 @@ WebIDL::ExceptionOr<GC::Ref<CompressionStream>> CompressionStream::construct_imp
|
|||
});
|
||||
|
||||
// 6. Set up this's transform with transformAlgorithm set to transformAlgorithm and flushAlgorithm set to flushAlgorithm.
|
||||
Streams::transform_stream_set_up(stream->m_transform, transform_algorithm, flush_algorithm);
|
||||
stream->m_transform->set_up(transform_algorithm, flush_algorithm);
|
||||
|
||||
return stream;
|
||||
}
|
||||
|
|
|
@ -77,7 +77,7 @@ WebIDL::ExceptionOr<GC::Ref<DecompressionStream>> DecompressionStream::construct
|
|||
});
|
||||
|
||||
// 6. Set up this's transform with transformAlgorithm set to transformAlgorithm and flushAlgorithm set to flushAlgorithm.
|
||||
Streams::transform_stream_set_up(stream->m_transform, transform_algorithm, flush_algorithm);
|
||||
stream->m_transform->set_up(transform_algorithm, flush_algorithm);
|
||||
|
||||
return stream;
|
||||
}
|
||||
|
|
|
@ -56,7 +56,7 @@ WebIDL::ExceptionOr<Infrastructure::BodyWithType> extract_body(JS::Realm& realm,
|
|||
// 4. Otherwise, set stream to a new ReadableStream object, and set up stream with byte reading support.
|
||||
else {
|
||||
stream = realm.create<Streams::ReadableStream>(realm);
|
||||
Streams::set_up_readable_stream_controller_with_byte_reading_support(*stream);
|
||||
stream->set_up_with_byte_reading_support();
|
||||
}
|
||||
|
||||
// 5. Assert: stream is a ReadableStream object.
|
||||
|
@ -156,7 +156,7 @@ WebIDL::ExceptionOr<Infrastructure::BodyWithType> extract_body(JS::Realm& realm,
|
|||
auto array_buffer = JS::ArrayBuffer::create(stream->realm(), move(bytes));
|
||||
auto chunk = JS::Uint8Array::create(stream->realm(), array_buffer->byte_length(), *array_buffer);
|
||||
|
||||
Streams::readable_stream_enqueue(*stream->controller(), chunk).release_value_but_fixme_should_propagate_errors();
|
||||
stream->enqueue(chunk).release_value_but_fixme_should_propagate_errors();
|
||||
}
|
||||
|
||||
// When running action is done, close stream.
|
||||
|
|
|
@ -68,7 +68,7 @@ void FetchedDataReceiver::on_data_received(ReadonlyBytes bytes)
|
|||
HTML::TemporaryExecutionContext execution_context { m_stream->realm(), HTML::TemporaryExecutionContext::CallbacksEnabled::Yes };
|
||||
|
||||
// 1. Pull from bytes buffer into stream.
|
||||
if (auto result = Streams::readable_stream_pull_from_bytes(m_stream, move(bytes)); result.is_error()) {
|
||||
if (auto result = m_stream->pull_from_bytes(move(bytes)); result.is_error()) {
|
||||
auto throw_completion = Bindings::exception_to_throw_completion(m_stream->vm(), result.release_error());
|
||||
|
||||
dbgln("FetchedDataReceiver: Stream error pulling bytes");
|
||||
|
|
|
@ -741,7 +741,7 @@ void fetch_response_handover(JS::Realm& realm, Infrastructure::FetchParams const
|
|||
process_response_end_of_body();
|
||||
return WebIDL::create_resolved_promise(realm, JS::js_undefined());
|
||||
});
|
||||
Streams::transform_stream_set_up(transform_stream, identity_transform_algorithm, flush_algorithm);
|
||||
transform_stream->set_up(identity_transform_algorithm, flush_algorithm);
|
||||
|
||||
// 4. Set internalResponse’s body’s stream to the result of internalResponse’s body’s stream piped through transformStream.
|
||||
auto promise = Streams::readable_stream_pipe_to(internal_response->body()->stream(), transform_stream->writable(), false, false, false, {});
|
||||
|
@ -2305,7 +2305,7 @@ WebIDL::ExceptionOr<GC::Ref<PendingResponse>> nonstandard_resource_loader_file_o
|
|||
});
|
||||
|
||||
// 13. Set up stream with byte reading support with pullAlgorithm set to pullAlgorithm, cancelAlgorithm set to cancelAlgorithm.
|
||||
Streams::set_up_readable_stream_controller_with_byte_reading_support(stream, pull_algorithm, cancel_algorithm);
|
||||
stream->set_up_with_byte_reading_support(pull_algorithm, cancel_algorithm);
|
||||
|
||||
auto on_headers_received = GC::create_function(vm.heap(), [&vm, request, pending_response, stream](HTTP::HeaderMap const& response_headers, Optional<u32> status_code, Optional<String> const& reason_phrase) {
|
||||
(void)request;
|
||||
|
|
|
@ -324,7 +324,7 @@ GC::Ref<Streams::ReadableStream> Blob::get_stream()
|
|||
auto stream = realm.create<Streams::ReadableStream>(realm);
|
||||
|
||||
// 2. Set up stream with byte reading support.
|
||||
set_up_readable_stream_controller_with_byte_reading_support(stream);
|
||||
stream->set_up_with_byte_reading_support();
|
||||
|
||||
// FIXME: 3. Run the following steps in parallel:
|
||||
{
|
||||
|
@ -346,7 +346,7 @@ GC::Ref<Streams::ReadableStream> Blob::get_stream()
|
|||
|
||||
// 3. Enqueue chunk in stream.
|
||||
auto maybe_error = Bindings::throw_dom_exception_if_needed(realm.vm(), [&]() {
|
||||
return readable_stream_enqueue(*stream->controller(), chunk);
|
||||
return stream->enqueue(chunk);
|
||||
});
|
||||
|
||||
if (maybe_error.is_error()) {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
* Copyright (c) 2021, Andreas Kling <andreas@ladybird.org>
|
||||
* Copyright (c) 2024, Shannon Booth <shannon@ladybird.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
@ -27,17 +28,23 @@ void HTMLHyperlinkElementUtils::reinitialize_url() const
|
|||
// https://html.spec.whatwg.org/multipage/links.html#concept-hyperlink-url-set
|
||||
void HTMLHyperlinkElementUtils::set_the_url()
|
||||
{
|
||||
// 1. If this element's href content attribute is absent, set this element's url to null.
|
||||
// 1. Set this element's url to null.
|
||||
m_url = {};
|
||||
|
||||
// 2. If this element's href content attribute is absent, then return.
|
||||
auto href_content_attribute = hyperlink_element_utils_href();
|
||||
if (!href_content_attribute.has_value()) {
|
||||
m_url = {};
|
||||
hyperlink_element_utils_element().invalidate_style(DOM::StyleInvalidationReason::HTMLHyperlinkElementHrefChange);
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. Otherwise, parse this element's href content attribute value relative to this element's node document.
|
||||
// If parsing is successful, set this element's url to the result; otherwise, set this element's url to null.
|
||||
m_url = hyperlink_element_utils_document().parse_url(*href_content_attribute);
|
||||
// 3. Let url be the result of encoding-parsing a URL given this element's href content attribute's value, relative to this element's node document.
|
||||
auto url = hyperlink_element_utils_document().encoding_parse_url(*href_content_attribute);
|
||||
|
||||
// 4. If url is not failure, then set this element's url to url.
|
||||
if (url.is_valid())
|
||||
m_url = move(url);
|
||||
|
||||
hyperlink_element_utils_element().invalidate_style(DOM::StyleInvalidationReason::HTMLHyperlinkElementHrefChange);
|
||||
}
|
||||
|
||||
|
|
|
@ -45,6 +45,53 @@
|
|||
|
||||
namespace Web::Streams {
|
||||
|
||||
// https://streams.spec.whatwg.org/#close-sentinel
|
||||
// Non-standard function that implements the "close sentinel" value.
|
||||
static JS::Value create_close_sentinel()
|
||||
{
|
||||
// The close sentinel is a unique value enqueued into [[queue]], in lieu of a chunk, to signal that the stream is closed. It is only used internally, and is never exposed to web developers.
|
||||
// Note: We use the empty Value to signal this as, similarly to the note above, the empty value is not exposed to nor creatable by web developers.
|
||||
return {};
|
||||
}
|
||||
|
||||
// https://streams.spec.whatwg.org/#close-sentinel
|
||||
// Non-standard function that implements the "If value is a close sentinel" check.
|
||||
static bool is_close_sentinel(JS::Value value)
|
||||
{
|
||||
return value.is_empty();
|
||||
}
|
||||
|
||||
// NON-STANDARD: Can be used instead of CreateReadableStream in cases where we need to set up a newly allocated
|
||||
// ReadableStream before initialization of said ReadableStream, i.e. ReadableStream is captured by lambdas in an uninitialized state.
|
||||
// Spec steps are taken from: https://streams.spec.whatwg.org/#create-readable-stream
|
||||
static WebIDL::ExceptionOr<void> set_up_readable_stream(JS::Realm& realm, ReadableStream& stream, GC::Ref<StartAlgorithm> start_algorithm, GC::Ref<PullAlgorithm> pull_algorithm, GC::Ref<CancelAlgorithm> cancel_algorithm, Optional<double> high_water_mark = {}, GC::Ptr<SizeAlgorithm> size_algorithm = {})
|
||||
{
|
||||
// 1. If highWaterMark was not passed, set it to 1.
|
||||
if (!high_water_mark.has_value())
|
||||
high_water_mark = 1.0;
|
||||
|
||||
// 2. If sizeAlgorithm was not passed, set it to an algorithm that returns 1.
|
||||
if (!size_algorithm)
|
||||
size_algorithm = GC::create_function(realm.heap(), [](JS::Value) { return JS::normal_completion(JS::Value(1)); });
|
||||
|
||||
// 3. Assert: ! IsNonNegativeNumber(highWaterMark) is true.
|
||||
VERIFY(is_non_negative_number(JS::Value { *high_water_mark }));
|
||||
|
||||
// 4. Let stream be a new ReadableStream.
|
||||
// NOTE: The ReadableStream is allocated outside the scope of this method.
|
||||
|
||||
// 5. Perform ! InitializeReadableStream(stream).
|
||||
initialize_readable_stream(stream);
|
||||
|
||||
// 6. Let controller be a new ReadableStreamDefaultController.
|
||||
auto controller = realm.create<ReadableStreamDefaultController>(realm);
|
||||
|
||||
// 7. Perform ? SetUpReadableStreamDefaultController(stream, controller, startAlgorithm, pullAlgorithm, cancelAlgorithm, highWaterMark, sizeAlgorithm).
|
||||
TRY(set_up_readable_stream_default_controller(stream, *controller, start_algorithm, pull_algorithm, cancel_algorithm, *high_water_mark, *size_algorithm));
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
// https://streams.spec.whatwg.org/#acquire-readable-stream-reader
|
||||
WebIDL::ExceptionOr<GC::Ref<ReadableStreamDefaultReader>> acquire_readable_stream_default_reader(ReadableStream& stream)
|
||||
{
|
||||
|
@ -2932,37 +2979,6 @@ bool readable_byte_stream_controller_should_call_pull(ReadableByteStreamControll
|
|||
return false;
|
||||
}
|
||||
|
||||
// NON-STANDARD: Can be used instead of CreateReadableStream in cases where we need to set up a newly allocated
|
||||
// ReadableStream before initialization of said ReadableStream, i.e. ReadableStream is captured by lambdas in an uninitialized state.
|
||||
// Spec steps are taken from: https://streams.spec.whatwg.org/#create-readable-stream
|
||||
WebIDL::ExceptionOr<void> set_up_readable_stream(JS::Realm& realm, ReadableStream& stream, GC::Ref<StartAlgorithm> start_algorithm, GC::Ref<PullAlgorithm> pull_algorithm, GC::Ref<CancelAlgorithm> cancel_algorithm, Optional<double> high_water_mark, GC::Ptr<SizeAlgorithm> size_algorithm)
|
||||
{
|
||||
// 1. If highWaterMark was not passed, set it to 1.
|
||||
if (!high_water_mark.has_value())
|
||||
high_water_mark = 1.0;
|
||||
|
||||
// 2. If sizeAlgorithm was not passed, set it to an algorithm that returns 1.
|
||||
if (!size_algorithm)
|
||||
size_algorithm = GC::create_function(realm.heap(), [](JS::Value) { return JS::normal_completion(JS::Value(1)); });
|
||||
|
||||
// 3. Assert: ! IsNonNegativeNumber(highWaterMark) is true.
|
||||
VERIFY(is_non_negative_number(JS::Value { *high_water_mark }));
|
||||
|
||||
// 4. Let stream be a new ReadableStream.
|
||||
// NOTE: The ReadableStream is allocated outside the scope of this method.
|
||||
|
||||
// 5. Perform ! InitializeReadableStream(stream).
|
||||
initialize_readable_stream(stream);
|
||||
|
||||
// 6. Let controller be a new ReadableStreamDefaultController.
|
||||
auto controller = realm.create<ReadableStreamDefaultController>(realm);
|
||||
|
||||
// 7. Perform ? SetUpReadableStreamDefaultController(stream, controller, startAlgorithm, pullAlgorithm, cancelAlgorithm, highWaterMark, sizeAlgorithm).
|
||||
TRY(set_up_readable_stream_default_controller(stream, *controller, start_algorithm, pull_algorithm, cancel_algorithm, *high_water_mark, *size_algorithm));
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
// https://streams.spec.whatwg.org/#create-readable-stream
|
||||
WebIDL::ExceptionOr<GC::Ref<ReadableStream>> create_readable_stream(JS::Realm& realm, GC::Ref<StartAlgorithm> start_algorithm, GC::Ref<PullAlgorithm> pull_algorithm, GC::Ref<CancelAlgorithm> cancel_algorithm, Optional<double> high_water_mark, GC::Ptr<SizeAlgorithm> size_algorithm)
|
||||
{
|
||||
|
@ -3259,39 +3275,6 @@ WebIDL::ExceptionOr<void> set_up_readable_byte_stream_controller(ReadableStream&
|
|||
return {};
|
||||
}
|
||||
|
||||
// https://streams.spec.whatwg.org/#readablestream-enqueue
|
||||
WebIDL::ExceptionOr<void> readable_stream_enqueue(ReadableStreamController& controller, JS::Value chunk)
|
||||
{
|
||||
// 1. If stream.[[controller]] implements ReadableStreamDefaultController,
|
||||
if (controller.has<GC::Ref<ReadableStreamDefaultController>>()) {
|
||||
// 1. Perform ! ReadableStreamDefaultControllerEnqueue(stream.[[controller]], chunk).
|
||||
return readable_stream_default_controller_enqueue(controller.get<GC::Ref<ReadableStreamDefaultController>>(), chunk);
|
||||
}
|
||||
// 2. Otherwise,
|
||||
else {
|
||||
// 1. Assert: stream.[[controller]] implements ReadableByteStreamController.
|
||||
VERIFY(controller.has<GC::Ref<ReadableByteStreamController>>());
|
||||
auto readable_byte_controller = controller.get<GC::Ref<ReadableByteStreamController>>();
|
||||
|
||||
// FIXME: 2. Assert: chunk is an ArrayBufferView.
|
||||
|
||||
// 3. Let byobView be the current BYOB request view for stream.
|
||||
// FIXME: This is not what the spec means by 'current BYOB request view'
|
||||
auto byob_view = readable_byte_controller->raw_byob_request();
|
||||
|
||||
// 4. If byobView is non-null, and chunk.[[ViewedArrayBuffer]] is byobView.[[ViewedArrayBuffer]], then:
|
||||
if (byob_view) {
|
||||
// FIXME: 1. Assert: chunk.[[ByteOffset]] is byobView.[[ByteOffset]].
|
||||
// FIXME: 2. Assert: chunk.[[ByteLength]] ≤ byobView.[[ByteLength]].
|
||||
// FIXME: 3. Perform ? ReadableByteStreamControllerRespond(stream.[[controller]], chunk.[[ByteLength]]).
|
||||
TODO();
|
||||
}
|
||||
|
||||
// 5. Otherwise, perform ? ReadableByteStreamControllerEnqueue(stream.[[controller]], chunk).
|
||||
return readable_byte_stream_controller_enqueue(readable_byte_controller, chunk);
|
||||
}
|
||||
}
|
||||
|
||||
// https://streams.spec.whatwg.org/#readable-byte-stream-controller-enqueue
|
||||
WebIDL::ExceptionOr<void> readable_byte_stream_controller_enqueue(ReadableByteStreamController& controller, JS::Value chunk)
|
||||
{
|
||||
|
@ -3412,49 +3395,6 @@ WebIDL::ExceptionOr<void> readable_byte_stream_controller_enqueue(ReadableByteSt
|
|||
return {};
|
||||
}
|
||||
|
||||
// https://streams.spec.whatwg.org/#readablestream-pull-from-bytes
|
||||
WebIDL::ExceptionOr<void> readable_stream_pull_from_bytes(ReadableStream& stream, ByteBuffer bytes)
|
||||
{
|
||||
// 1. Assert: stream.[[controller]] implements ReadableByteStreamController.
|
||||
auto controller = stream.controller()->get<GC::Ref<ReadableByteStreamController>>();
|
||||
|
||||
// 2. Let available be bytes’s length.
|
||||
auto available = bytes.size();
|
||||
|
||||
// 3. Let desiredSize be available.
|
||||
auto desired_size = available;
|
||||
|
||||
// FIXME: 4. If stream’s current BYOB request view is non-null, then set desiredSize to stream’s current BYOB request
|
||||
// view's byte length.
|
||||
|
||||
// 5. Let pullSize be the smaller value of available and desiredSize.
|
||||
auto pull_size = min(available, desired_size);
|
||||
|
||||
// 6. Let pulled be the first pullSize bytes of bytes.
|
||||
auto pulled = pull_size == available ? move(bytes) : MUST(bytes.slice(0, pull_size));
|
||||
|
||||
// 7. Remove the first pullSize bytes from bytes.
|
||||
if (pull_size != available)
|
||||
bytes = MUST(bytes.slice(pull_size, available - pull_size));
|
||||
|
||||
// FIXME: 8. If stream’s current BYOB request view is non-null, then:
|
||||
// 1. Write pulled into stream’s current BYOB request view.
|
||||
// 2. Perform ? ReadableByteStreamControllerRespond(stream.[[controller]], pullSize).
|
||||
// 9. Otherwise,
|
||||
{
|
||||
auto& realm = HTML::relevant_realm(stream);
|
||||
|
||||
// 1. Set view to the result of creating a Uint8Array from pulled in stream’s relevant Realm.
|
||||
auto array_buffer = JS::ArrayBuffer::create(realm, move(pulled));
|
||||
auto view = JS::Uint8Array::create(realm, array_buffer->byte_length(), *array_buffer);
|
||||
|
||||
// 2. Perform ? ReadableByteStreamControllerEnqueue(stream.[[controller]], view).
|
||||
TRY(readable_byte_stream_controller_enqueue(controller, view));
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
// https://streams.spec.whatwg.org/#transfer-array-buffer
|
||||
WebIDL::ExceptionOr<GC::Ref<JS::ArrayBuffer>> transfer_array_buffer(JS::Realm& realm, JS::ArrayBuffer& buffer)
|
||||
{
|
||||
|
@ -3642,52 +3582,6 @@ PullIntoDescriptor readable_byte_stream_controller_shift_pending_pull_into(Reada
|
|||
return descriptor;
|
||||
}
|
||||
|
||||
// https://streams.spec.whatwg.org/#readablestream-set-up-with-byte-reading-support
|
||||
void set_up_readable_stream_controller_with_byte_reading_support(ReadableStream& stream, GC::Ptr<PullAlgorithm> pull_algorithm, GC::Ptr<CancelAlgorithm> cancel_algorithm, double high_water_mark)
|
||||
{
|
||||
auto& realm = stream.realm();
|
||||
|
||||
// 1. Let startAlgorithm be an algorithm that returns undefined.
|
||||
auto start_algorithm = GC::create_function(realm.heap(), []() -> WebIDL::ExceptionOr<JS::Value> { return JS::js_undefined(); });
|
||||
|
||||
// 2. Let pullAlgorithmWrapper be an algorithm that runs these steps:
|
||||
auto pull_algorithm_wrapper = GC::create_function(realm.heap(), [&realm, pull_algorithm]() {
|
||||
// 1. Let result be the result of running pullAlgorithm, if pullAlgorithm was given, or null otherwise. If this throws an exception e, return a promise rejected with e.
|
||||
GC::Ptr<JS::PromiseCapability> result = nullptr;
|
||||
if (pull_algorithm)
|
||||
result = pull_algorithm->function()();
|
||||
|
||||
// 2. If result is a Promise, then return result.
|
||||
if (result != nullptr)
|
||||
return GC::Ref(*result);
|
||||
|
||||
// 3. Return a promise resolved with undefined.
|
||||
return WebIDL::create_resolved_promise(realm, JS::js_undefined());
|
||||
});
|
||||
|
||||
// 3. Let cancelAlgorithmWrapper be an algorithm that runs these steps:
|
||||
auto cancel_algorithm_wrapper = GC::create_function(realm.heap(), [&realm, cancel_algorithm](JS::Value c) {
|
||||
// 1. Let result be the result of running cancelAlgorithm, if cancelAlgorithm was given, or null otherwise. If this throws an exception e, return a promise rejected with e.
|
||||
GC::Ptr<JS::PromiseCapability> result = nullptr;
|
||||
if (cancel_algorithm)
|
||||
result = cancel_algorithm->function()(c);
|
||||
|
||||
// 2. If result is a Promise, then return result.
|
||||
if (result != nullptr)
|
||||
return GC::Ref(*result);
|
||||
|
||||
// 3. Return a promise resolved with undefined.
|
||||
return WebIDL::create_resolved_promise(realm, JS::js_undefined());
|
||||
});
|
||||
|
||||
// 4. Perform ! InitializeReadableStream(stream).
|
||||
// 5. Let controller be a new ReadableByteStreamController.
|
||||
auto controller = realm.create<ReadableByteStreamController>(realm);
|
||||
|
||||
// 6. Perform ! SetUpReadableByteStreamController(stream, controller, startAlgorithm, pullAlgorithmWrapper, cancelAlgorithmWrapper, highWaterMark, undefined).
|
||||
MUST(set_up_readable_byte_stream_controller(stream, controller, start_algorithm, pull_algorithm_wrapper, cancel_algorithm_wrapper, high_water_mark, JS::js_undefined()));
|
||||
}
|
||||
|
||||
// https://streams.spec.whatwg.org/#writable-stream-abort
|
||||
GC::Ref<WebIDL::Promise> writable_stream_abort(WritableStream& stream, JS::Value reason)
|
||||
{
|
||||
|
@ -5298,84 +5192,6 @@ void transform_stream_set_backpressure(TransformStream& stream, bool backpressur
|
|||
stream.set_backpressure(backpressure);
|
||||
}
|
||||
|
||||
// https://streams.spec.whatwg.org/#transformstream-set-up
|
||||
void transform_stream_set_up(TransformStream& stream, GC::Ref<TransformAlgorithm> transform_algorithm, GC::Ptr<FlushAlgorithm> flush_algorithm, GC::Ptr<CancelAlgorithm> cancel_algorithm)
|
||||
{
|
||||
auto& realm = stream.realm();
|
||||
|
||||
// 1. Let writableHighWaterMark be 1.
|
||||
auto writable_high_water_mark = 1.0;
|
||||
|
||||
// 2. Let writableSizeAlgorithm be an algorithm that returns 1.
|
||||
auto writable_size_algorithm = GC::create_function(realm.heap(), [](JS::Value) {
|
||||
return JS::normal_completion(JS::Value { 1 });
|
||||
});
|
||||
|
||||
// 3. Let readableHighWaterMark be 0.
|
||||
auto readable_high_water_mark = 0.0;
|
||||
|
||||
// 4. Let readableSizeAlgorithm be an algorithm that returns 1.
|
||||
auto readable_size_algorithm = GC::create_function(realm.heap(), [](JS::Value) {
|
||||
return JS::normal_completion(JS::Value { 1 });
|
||||
});
|
||||
|
||||
// 5. Let transformAlgorithmWrapper be an algorithm that runs these steps given a value chunk:
|
||||
auto transform_algorithm_wrapper = GC::create_function(realm.heap(), [&realm, transform_algorithm](JS::Value chunk) -> GC::Ref<WebIDL::Promise> {
|
||||
// 1. Let result be the result of running transformAlgorithm given chunk. If this throws an exception e, return a promise rejected with e.
|
||||
GC::Ptr<JS::PromiseCapability> result = nullptr;
|
||||
result = transform_algorithm->function()(chunk);
|
||||
|
||||
// 2. If result is a Promise, then return result.
|
||||
if (result)
|
||||
return GC::Ref { *result };
|
||||
|
||||
// 3. Return a promise resolved with undefined.
|
||||
return WebIDL::create_resolved_promise(realm, JS::js_undefined());
|
||||
});
|
||||
|
||||
// 6. Let flushAlgorithmWrapper be an algorithm that runs these steps:
|
||||
auto flush_algorithm_wrapper = GC::create_function(realm.heap(), [&realm, flush_algorithm]() -> GC::Ref<WebIDL::Promise> {
|
||||
// 1. Let result be the result of running flushAlgorithm, if flushAlgorithm was given, or null otherwise. If this throws an exception e, return a promise rejected with e.
|
||||
GC::Ptr<JS::PromiseCapability> result = nullptr;
|
||||
if (flush_algorithm)
|
||||
result = flush_algorithm->function()();
|
||||
|
||||
// 2. If result is a Promise, then return result.
|
||||
if (result)
|
||||
return GC::Ref { *result };
|
||||
|
||||
// 3. Return a promise resolved with undefined.
|
||||
return WebIDL::create_resolved_promise(realm, JS::js_undefined());
|
||||
});
|
||||
|
||||
// 7. Let cancelAlgorithmWrapper be an algorithm that runs these steps given a value reason:
|
||||
auto cancel_algorithm_wrapper = GC::create_function(realm.heap(), [&realm, cancel_algorithm](JS::Value reason) -> GC::Ref<WebIDL::Promise> {
|
||||
// 1. Let result be the result of running cancelAlgorithm given reason, if cancelAlgorithm was given, or null otherwise. If this throws an exception e, return a promise rejected with e.
|
||||
GC::Ptr<JS::PromiseCapability> result = nullptr;
|
||||
if (cancel_algorithm)
|
||||
result = cancel_algorithm->function()(reason);
|
||||
|
||||
// 2. If result is a Promise, then return result.
|
||||
if (result)
|
||||
return GC::Ref { *result };
|
||||
|
||||
// 3. Return a promise resolved with undefined.
|
||||
return WebIDL::create_resolved_promise(realm, JS::js_undefined());
|
||||
});
|
||||
|
||||
// 8. Let startPromise be a promise resolved with undefined.
|
||||
auto start_promise = WebIDL::create_resolved_promise(realm, JS::js_undefined());
|
||||
|
||||
// 9. Perform ! InitializeTransformStream(stream, startPromise, writableHighWaterMark, writableSizeAlgorithm, readableHighWaterMark, readableSizeAlgorithm).
|
||||
initialize_transform_stream(stream, start_promise, writable_high_water_mark, writable_size_algorithm, readable_high_water_mark, readable_size_algorithm);
|
||||
|
||||
// 10. Let controller be a new TransformStreamDefaultController.
|
||||
auto controller = realm.create<TransformStreamDefaultController>(realm);
|
||||
|
||||
// 11. Perform ! SetUpTransformStreamDefaultController(stream, controller, transformAlgorithmWrapper, flushAlgorithmWrapper, cancelAlgorithmWrapper).
|
||||
set_up_transform_stream_default_controller(stream, controller, transform_algorithm_wrapper, flush_algorithm_wrapper, cancel_algorithm_wrapper);
|
||||
}
|
||||
|
||||
// https://streams.spec.whatwg.org/#transform-stream-unblock-write
|
||||
void transform_stream_unblock_write(TransformStream& stream)
|
||||
{
|
||||
|
@ -5486,37 +5302,6 @@ WebIDL::ExceptionOr<JS::Value> structured_clone(JS::Realm& realm, JS::Value valu
|
|||
return TRY(HTML::structured_deserialize(vm, serialized, realm));
|
||||
}
|
||||
|
||||
// https://streams.spec.whatwg.org/#close-sentinel
|
||||
// Non-standard function that implements the "close sentinel" value.
|
||||
JS::Value create_close_sentinel()
|
||||
{
|
||||
// The close sentinel is a unique value enqueued into [[queue]], in lieu of a chunk, to signal that the stream is closed. It is only used internally, and is never exposed to web developers.
|
||||
// Note: We use the empty Value to signal this as, similarly to the note above, the empty value is not exposed to nor creatable by web developers.
|
||||
return {};
|
||||
}
|
||||
|
||||
// https://streams.spec.whatwg.org/#close-sentinel
|
||||
// Non-standard function that implements the "If value is a close sentinel" check.
|
||||
bool is_close_sentinel(JS::Value value)
|
||||
{
|
||||
return value.is_empty();
|
||||
}
|
||||
|
||||
// Non-standard function to aid in converting a user-provided function into a WebIDL::Callback. This is essentially
|
||||
// what the Bindings generator would do at compile time, but at runtime instead.
|
||||
JS::ThrowCompletionOr<GC::Root<WebIDL::CallbackType>> property_to_callback(JS::VM& vm, JS::Value value, JS::PropertyKey const& property_key, WebIDL::OperationReturnsPromise operation_returns_promise)
|
||||
{
|
||||
auto property = TRY(value.get(vm, property_key));
|
||||
|
||||
if (property.is_undefined())
|
||||
return GC::Root<WebIDL::CallbackType> {};
|
||||
|
||||
if (!property.is_function())
|
||||
return vm.throw_completion<JS::TypeError>(JS::ErrorType::NotAFunction, property.to_string_without_side_effects());
|
||||
|
||||
return vm.heap().allocate<WebIDL::CallbackType>(property.as_object(), HTML::incumbent_realm(), operation_returns_promise);
|
||||
}
|
||||
|
||||
// https://streams.spec.whatwg.org/#set-up-readable-byte-stream-controller-from-underlying-source
|
||||
WebIDL::ExceptionOr<void> set_up_readable_byte_stream_controller_from_underlying_source(ReadableStream& stream, JS::Value underlying_source, UnderlyingSource const& underlying_source_dict, double high_water_mark)
|
||||
{
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
#include <LibGC/Ptr.h>
|
||||
#include <LibWeb/Forward.h>
|
||||
#include <LibWeb/Streams/Algorithms.h>
|
||||
#include <LibWeb/Streams/ReadableStream.h>
|
||||
#include <LibWeb/WebIDL/CallbackType.h>
|
||||
#include <LibWeb/WebIDL/ExceptionOr.h>
|
||||
|
@ -19,16 +20,6 @@
|
|||
|
||||
namespace Web::Streams {
|
||||
|
||||
using SizeAlgorithm = GC::Function<JS::Completion(JS::Value)>;
|
||||
using PullAlgorithm = GC::Function<GC::Ref<WebIDL::Promise>()>;
|
||||
using CancelAlgorithm = GC::Function<GC::Ref<WebIDL::Promise>(JS::Value)>;
|
||||
using StartAlgorithm = GC::Function<WebIDL::ExceptionOr<JS::Value>()>;
|
||||
using AbortAlgorithm = GC::Function<GC::Ref<WebIDL::Promise>(JS::Value)>;
|
||||
using CloseAlgorithm = GC::Function<GC::Ref<WebIDL::Promise>()>;
|
||||
using WriteAlgorithm = GC::Function<GC::Ref<WebIDL::Promise>(JS::Value)>;
|
||||
using FlushAlgorithm = GC::Function<GC::Ref<WebIDL::Promise>()>;
|
||||
using TransformAlgorithm = GC::Function<GC::Ref<WebIDL::Promise>(JS::Value)>;
|
||||
|
||||
WebIDL::ExceptionOr<GC::Ref<ReadableStreamDefaultReader>> acquire_readable_stream_default_reader(ReadableStream&);
|
||||
WebIDL::ExceptionOr<GC::Ref<ReadableStreamBYOBReader>> acquire_readable_stream_byob_reader(ReadableStream&);
|
||||
bool is_readable_stream_locked(ReadableStream const&);
|
||||
|
@ -83,7 +74,6 @@ Optional<double> readable_stream_default_controller_get_desired_size(ReadableStr
|
|||
bool readable_stream_default_controller_can_close_or_enqueue(ReadableStreamDefaultController&);
|
||||
WebIDL::ExceptionOr<void> set_up_readable_stream_default_controller(ReadableStream&, ReadableStreamDefaultController&, GC::Ref<StartAlgorithm>, GC::Ref<PullAlgorithm>, GC::Ref<CancelAlgorithm>, double high_water_mark, GC::Ref<SizeAlgorithm>);
|
||||
WebIDL::ExceptionOr<void> set_up_readable_stream_default_controller_from_underlying_source(ReadableStream&, JS::Value underlying_source_value, UnderlyingSource, double high_water_mark, GC::Ref<SizeAlgorithm>);
|
||||
void set_up_readable_stream_controller_with_byte_reading_support(ReadableStream&, GC::Ptr<PullAlgorithm> = {}, GC::Ptr<CancelAlgorithm> = {}, double high_water_mark = 0);
|
||||
WebIDL::ExceptionOr<void> set_up_readable_byte_stream_controller(ReadableStream&, ReadableByteStreamController&, GC::Ref<StartAlgorithm>, GC::Ref<PullAlgorithm>, GC::Ref<CancelAlgorithm>, double high_water_mark, JS::Value auto_allocate_chunk_size);
|
||||
WebIDL::ExceptionOr<void> set_up_readable_byte_stream_controller_from_underlying_source(ReadableStream&, JS::Value underlying_source, UnderlyingSource const& underlying_source_dict, double high_water_mark);
|
||||
GC::Ptr<ReadableStreamBYOBRequest> readable_byte_stream_controller_get_byob_request(GC::Ref<ReadableByteStreamController>);
|
||||
|
@ -94,9 +84,7 @@ WebIDL::ExceptionOr<void> readable_byte_stream_controller_respond_internal(Reada
|
|||
WebIDL::ExceptionOr<void> readable_byte_stream_controller_respond(ReadableByteStreamController&, u64 bytes_written);
|
||||
WebIDL::ExceptionOr<void> readable_byte_stream_controller_respond_with_new_view(JS::Realm&, ReadableByteStreamController&, WebIDL::ArrayBufferView&);
|
||||
|
||||
WebIDL::ExceptionOr<void> readable_stream_enqueue(ReadableStreamController& controller, JS::Value chunk);
|
||||
WebIDL::ExceptionOr<void> readable_byte_stream_controller_enqueue(ReadableByteStreamController& controller, JS::Value chunk);
|
||||
WebIDL::ExceptionOr<void> readable_stream_pull_from_bytes(ReadableStream&, ByteBuffer bytes);
|
||||
WebIDL::ExceptionOr<GC::Ref<JS::ArrayBuffer>> transfer_array_buffer(JS::Realm& realm, JS::ArrayBuffer& buffer);
|
||||
WebIDL::ExceptionOr<void> readable_byte_stream_controller_enqueue_detached_pull_into_queue(ReadableByteStreamController& controller, PullIntoDescriptor& pull_into_descriptor);
|
||||
void readable_byte_stream_controller_commit_pull_into_descriptor(ReadableStream&, PullIntoDescriptor const&);
|
||||
|
@ -118,7 +106,6 @@ void readable_byte_stream_controller_handle_queue_drain(ReadableByteStreamContro
|
|||
void readable_byte_stream_controller_invalidate_byob_request(ReadableByteStreamController&);
|
||||
bool readable_byte_stream_controller_should_call_pull(ReadableByteStreamController const&);
|
||||
|
||||
WebIDL::ExceptionOr<void> set_up_readable_stream(JS::Realm& realm, ReadableStream& stream, GC::Ref<StartAlgorithm> start_algorithm, GC::Ref<PullAlgorithm> pull_algorithm, GC::Ref<CancelAlgorithm> cancel_algorithm, Optional<double> high_water_mark = {}, GC::Ptr<SizeAlgorithm> size_algorithm = {});
|
||||
WebIDL::ExceptionOr<GC::Ref<ReadableStream>> create_readable_stream(JS::Realm& realm, GC::Ref<StartAlgorithm> start_algorithm, GC::Ref<PullAlgorithm> pull_algorithm, GC::Ref<CancelAlgorithm> cancel_algorithm, Optional<double> high_water_mark = {}, GC::Ptr<SizeAlgorithm> size_algorithm = {});
|
||||
WebIDL::ExceptionOr<GC::Ref<ReadableStream>> create_readable_byte_stream(JS::Realm& realm, GC::Ref<StartAlgorithm> start_algorithm, GC::Ref<PullAlgorithm> pull_algorithm, GC::Ref<CancelAlgorithm> cancel_algorithm);
|
||||
WebIDL::ExceptionOr<GC::Ref<WritableStream>> create_writable_stream(JS::Realm& realm, GC::Ref<StartAlgorithm> start_algorithm, GC::Ref<WriteAlgorithm> write_algorithm, GC::Ref<CloseAlgorithm> close_algorithm, GC::Ref<AbortAlgorithm> abort_algorithm, double high_water_mark, GC::Ref<SizeAlgorithm> size_algorithm);
|
||||
|
@ -184,7 +171,6 @@ GC::Ref<WebIDL::Promise> transform_stream_default_source_cancel_algorithm(Transf
|
|||
void transform_stream_error(TransformStream&, JS::Value error);
|
||||
void transform_stream_error_writable_and_unblock_write(TransformStream&, JS::Value error);
|
||||
void transform_stream_set_backpressure(TransformStream&, bool backpressure);
|
||||
void transform_stream_set_up(TransformStream&, GC::Ref<TransformAlgorithm>, GC::Ptr<FlushAlgorithm> = {}, GC::Ptr<CancelAlgorithm> = {});
|
||||
void transform_stream_unblock_write(TransformStream&);
|
||||
|
||||
bool is_non_negative_number(JS::Value);
|
||||
|
@ -193,10 +179,6 @@ bool can_transfer_array_buffer(JS::ArrayBuffer const& array_buffer);
|
|||
WebIDL::ExceptionOr<JS::Value> clone_as_uint8_array(JS::Realm&, WebIDL::ArrayBufferView&);
|
||||
WebIDL::ExceptionOr<JS::Value> structured_clone(JS::Realm&, JS::Value value);
|
||||
|
||||
JS::Value create_close_sentinel();
|
||||
bool is_close_sentinel(JS::Value);
|
||||
JS::ThrowCompletionOr<GC::Root<WebIDL::CallbackType>> property_to_callback(JS::VM& vm, JS::Value value, JS::PropertyKey const& property_key, WebIDL::OperationReturnsPromise);
|
||||
|
||||
// https://streams.spec.whatwg.org/#value-with-size
|
||||
struct ValueWithSize {
|
||||
JS::Value value;
|
||||
|
|
26
Libraries/LibWeb/Streams/Algorithms.h
Normal file
26
Libraries/LibWeb/Streams/Algorithms.h
Normal file
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* Copyright (c) 2024, Shannon Booth <shannon@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LibGC/Function.h>
|
||||
#include <LibGC/Ptr.h>
|
||||
#include <LibWeb/WebIDL/ExceptionOr.h>
|
||||
#include <LibWeb/WebIDL/Promise.h>
|
||||
|
||||
namespace Web::Streams {
|
||||
|
||||
using SizeAlgorithm = GC::Function<JS::Completion(JS::Value)>;
|
||||
using PullAlgorithm = GC::Function<GC::Ref<WebIDL::Promise>()>;
|
||||
using CancelAlgorithm = GC::Function<GC::Ref<WebIDL::Promise>(JS::Value)>;
|
||||
using StartAlgorithm = GC::Function<WebIDL::ExceptionOr<JS::Value>()>;
|
||||
using AbortAlgorithm = GC::Function<GC::Ref<WebIDL::Promise>(JS::Value)>;
|
||||
using CloseAlgorithm = GC::Function<GC::Ref<WebIDL::Promise>()>;
|
||||
using WriteAlgorithm = GC::Function<GC::Ref<WebIDL::Promise>(JS::Value)>;
|
||||
using FlushAlgorithm = GC::Function<GC::Ref<WebIDL::Promise>()>;
|
||||
using TransformAlgorithm = GC::Function<GC::Ref<WebIDL::Promise>(JS::Value)>;
|
||||
|
||||
}
|
|
@ -7,6 +7,7 @@
|
|||
*/
|
||||
|
||||
#include <LibJS/Runtime/PromiseCapability.h>
|
||||
#include <LibJS/Runtime/TypedArray.h>
|
||||
#include <LibWeb/Bindings/Intrinsics.h>
|
||||
#include <LibWeb/Bindings/ReadableStreamPrototype.h>
|
||||
#include <LibWeb/DOM/AbortSignal.h>
|
||||
|
@ -258,4 +259,128 @@ bool ReadableStream::is_disturbed() const
|
|||
return m_disturbed;
|
||||
}
|
||||
|
||||
// https://streams.spec.whatwg.org/#readablestream-pull-from-bytes
|
||||
WebIDL::ExceptionOr<void> ReadableStream::pull_from_bytes(ByteBuffer bytes)
|
||||
{
|
||||
auto& realm = this->realm();
|
||||
|
||||
// 1. Assert: stream.[[controller]] implements ReadableByteStreamController.
|
||||
auto& controller = this->controller()->get<GC::Ref<ReadableByteStreamController>>();
|
||||
|
||||
// 2. Let available be bytes’s length.
|
||||
auto available = bytes.size();
|
||||
|
||||
// 3. Let desiredSize be available.
|
||||
auto desired_size = available;
|
||||
|
||||
// FIXME: 4. If stream’s current BYOB request view is non-null, then set desiredSize to stream’s current BYOB request
|
||||
// view's byte length.
|
||||
|
||||
// 5. Let pullSize be the smaller value of available and desiredSize.
|
||||
auto pull_size = min(available, desired_size);
|
||||
|
||||
// 6. Let pulled be the first pullSize bytes of bytes.
|
||||
auto pulled = pull_size == available ? move(bytes) : MUST(bytes.slice(0, pull_size));
|
||||
|
||||
// 7. Remove the first pullSize bytes from bytes.
|
||||
if (pull_size != available)
|
||||
bytes = MUST(bytes.slice(pull_size, available - pull_size));
|
||||
|
||||
// FIXME: 8. If stream’s current BYOB request view is non-null, then:
|
||||
// 1. Write pulled into stream’s current BYOB request view.
|
||||
// 2. Perform ? ReadableByteStreamControllerRespond(stream.[[controller]], pullSize).
|
||||
// 9. Otherwise,
|
||||
{
|
||||
// 1. Set view to the result of creating a Uint8Array from pulled in stream’s relevant Realm.
|
||||
auto array_buffer = JS::ArrayBuffer::create(realm, move(pulled));
|
||||
auto view = JS::Uint8Array::create(realm, array_buffer->byte_length(), *array_buffer);
|
||||
|
||||
// 2. Perform ? ReadableByteStreamControllerEnqueue(stream.[[controller]], view).
|
||||
TRY(readable_byte_stream_controller_enqueue(controller, view));
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
// https://streams.spec.whatwg.org/#readablestream-enqueue
|
||||
WebIDL::ExceptionOr<void> ReadableStream::enqueue(JS::Value chunk)
|
||||
{
|
||||
VERIFY(m_controller.has_value());
|
||||
|
||||
// 1. If stream.[[controller]] implements ReadableStreamDefaultController,
|
||||
if (m_controller->has<GC::Ref<ReadableStreamDefaultController>>()) {
|
||||
// 1. Perform ! ReadableStreamDefaultControllerEnqueue(stream.[[controller]], chunk).
|
||||
return readable_stream_default_controller_enqueue(m_controller->get<GC::Ref<ReadableStreamDefaultController>>(), chunk);
|
||||
}
|
||||
// 2. Otherwise,
|
||||
else {
|
||||
// 1. Assert: stream.[[controller]] implements ReadableByteStreamController.
|
||||
VERIFY(m_controller->has<GC::Ref<ReadableByteStreamController>>());
|
||||
auto readable_byte_controller = m_controller->get<GC::Ref<ReadableByteStreamController>>();
|
||||
|
||||
// FIXME: 2. Assert: chunk is an ArrayBufferView.
|
||||
|
||||
// 3. Let byobView be the current BYOB request view for stream.
|
||||
// FIXME: This is not what the spec means by 'current BYOB request view'
|
||||
auto byob_view = readable_byte_controller->raw_byob_request();
|
||||
|
||||
// 4. If byobView is non-null, and chunk.[[ViewedArrayBuffer]] is byobView.[[ViewedArrayBuffer]], then:
|
||||
if (byob_view) {
|
||||
// FIXME: 1. Assert: chunk.[[ByteOffset]] is byobView.[[ByteOffset]].
|
||||
// FIXME: 2. Assert: chunk.[[ByteLength]] ≤ byobView.[[ByteLength]].
|
||||
// FIXME: 3. Perform ? ReadableByteStreamControllerRespond(stream.[[controller]], chunk.[[ByteLength]]).
|
||||
TODO();
|
||||
}
|
||||
|
||||
// 5. Otherwise, perform ? ReadableByteStreamControllerEnqueue(stream.[[controller]], chunk).
|
||||
return readable_byte_stream_controller_enqueue(readable_byte_controller, chunk);
|
||||
}
|
||||
}
|
||||
|
||||
// https://streams.spec.whatwg.org/#readablestream-set-up-with-byte-reading-support
|
||||
void ReadableStream::set_up_with_byte_reading_support(GC::Ptr<PullAlgorithm> pull_algorithm, GC::Ptr<CancelAlgorithm> cancel_algorithm, double high_water_mark)
|
||||
{
|
||||
auto& realm = this->realm();
|
||||
|
||||
// 1. Let startAlgorithm be an algorithm that returns undefined.
|
||||
auto start_algorithm = GC::create_function(realm.heap(), []() -> WebIDL::ExceptionOr<JS::Value> { return JS::js_undefined(); });
|
||||
|
||||
// 2. Let pullAlgorithmWrapper be an algorithm that runs these steps:
|
||||
auto pull_algorithm_wrapper = GC::create_function(realm.heap(), [&realm, pull_algorithm]() {
|
||||
// 1. Let result be the result of running pullAlgorithm, if pullAlgorithm was given, or null otherwise. If this throws an exception e, return a promise rejected with e.
|
||||
GC::Ptr<JS::PromiseCapability> result = nullptr;
|
||||
if (pull_algorithm)
|
||||
result = pull_algorithm->function()();
|
||||
|
||||
// 2. If result is a Promise, then return result.
|
||||
if (result != nullptr)
|
||||
return GC::Ref(*result);
|
||||
|
||||
// 3. Return a promise resolved with undefined.
|
||||
return WebIDL::create_resolved_promise(realm, JS::js_undefined());
|
||||
});
|
||||
|
||||
// 3. Let cancelAlgorithmWrapper be an algorithm that runs these steps:
|
||||
auto cancel_algorithm_wrapper = GC::create_function(realm.heap(), [&realm, cancel_algorithm](JS::Value c) {
|
||||
// 1. Let result be the result of running cancelAlgorithm, if cancelAlgorithm was given, or null otherwise. If this throws an exception e, return a promise rejected with e.
|
||||
GC::Ptr<JS::PromiseCapability> result = nullptr;
|
||||
if (cancel_algorithm)
|
||||
result = cancel_algorithm->function()(c);
|
||||
|
||||
// 2. If result is a Promise, then return result.
|
||||
if (result != nullptr)
|
||||
return GC::Ref(*result);
|
||||
|
||||
// 3. Return a promise resolved with undefined.
|
||||
return WebIDL::create_resolved_promise(realm, JS::js_undefined());
|
||||
});
|
||||
|
||||
// 4. Perform ! InitializeReadableStream(stream).
|
||||
// 5. Let controller be a new ReadableByteStreamController.
|
||||
auto controller = realm.create<ReadableByteStreamController>(realm);
|
||||
|
||||
// 6. Perform ! SetUpReadableByteStreamController(stream, controller, startAlgorithm, pullAlgorithmWrapper, cancelAlgorithmWrapper, highWaterMark, undefined).
|
||||
MUST(set_up_readable_byte_stream_controller(*this, controller, start_algorithm, pull_algorithm_wrapper, cancel_algorithm_wrapper, high_water_mark, JS::js_undefined()));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include <LibWeb/Bindings/PlatformObject.h>
|
||||
#include <LibWeb/Bindings/ReadableStreamPrototype.h>
|
||||
#include <LibWeb/Forward.h>
|
||||
#include <LibWeb/Streams/Algorithms.h>
|
||||
#include <LibWeb/Streams/QueuingStrategy.h>
|
||||
|
||||
namespace Web::Streams {
|
||||
|
@ -104,6 +105,10 @@ public:
|
|||
State state() const { return m_state; }
|
||||
void set_state(State value) { m_state = value; }
|
||||
|
||||
WebIDL::ExceptionOr<void> pull_from_bytes(ByteBuffer);
|
||||
WebIDL::ExceptionOr<void> enqueue(JS::Value chunk);
|
||||
void set_up_with_byte_reading_support(GC::Ptr<PullAlgorithm> = {}, GC::Ptr<CancelAlgorithm> = {}, double high_water_mark = 0);
|
||||
|
||||
private:
|
||||
explicit ReadableStream(JS::Realm&);
|
||||
|
||||
|
|
|
@ -74,6 +74,84 @@ WebIDL::ExceptionOr<GC::Ref<TransformStream>> TransformStream::construct_impl(JS
|
|||
return stream;
|
||||
}
|
||||
|
||||
// https://streams.spec.whatwg.org/#transformstream-set-up
|
||||
void TransformStream::set_up(GC::Ref<TransformAlgorithm> transform_algorithm, GC::Ptr<FlushAlgorithm> flush_algorithm, GC::Ptr<CancelAlgorithm> cancel_algorithm)
|
||||
{
|
||||
auto& realm = this->realm();
|
||||
|
||||
// 1. Let writableHighWaterMark be 1.
|
||||
auto writable_high_water_mark = 1.0;
|
||||
|
||||
// 2. Let writableSizeAlgorithm be an algorithm that returns 1.
|
||||
auto writable_size_algorithm = GC::create_function(realm.heap(), [](JS::Value) {
|
||||
return JS::normal_completion(JS::Value { 1 });
|
||||
});
|
||||
|
||||
// 3. Let readableHighWaterMark be 0.
|
||||
auto readable_high_water_mark = 0.0;
|
||||
|
||||
// 4. Let readableSizeAlgorithm be an algorithm that returns 1.
|
||||
auto readable_size_algorithm = GC::create_function(realm.heap(), [](JS::Value) {
|
||||
return JS::normal_completion(JS::Value { 1 });
|
||||
});
|
||||
|
||||
// 5. Let transformAlgorithmWrapper be an algorithm that runs these steps given a value chunk:
|
||||
auto transform_algorithm_wrapper = GC::create_function(realm.heap(), [&realm, transform_algorithm](JS::Value chunk) -> GC::Ref<WebIDL::Promise> {
|
||||
// 1. Let result be the result of running transformAlgorithm given chunk. If this throws an exception e, return a promise rejected with e.
|
||||
GC::Ptr<JS::PromiseCapability> result = nullptr;
|
||||
result = transform_algorithm->function()(chunk);
|
||||
|
||||
// 2. If result is a Promise, then return result.
|
||||
if (result)
|
||||
return GC::Ref { *result };
|
||||
|
||||
// 3. Return a promise resolved with undefined.
|
||||
return WebIDL::create_resolved_promise(realm, JS::js_undefined());
|
||||
});
|
||||
|
||||
// 6. Let flushAlgorithmWrapper be an algorithm that runs these steps:
|
||||
auto flush_algorithm_wrapper = GC::create_function(realm.heap(), [&realm, flush_algorithm]() -> GC::Ref<WebIDL::Promise> {
|
||||
// 1. Let result be the result of running flushAlgorithm, if flushAlgorithm was given, or null otherwise. If this throws an exception e, return a promise rejected with e.
|
||||
GC::Ptr<JS::PromiseCapability> result = nullptr;
|
||||
if (flush_algorithm)
|
||||
result = flush_algorithm->function()();
|
||||
|
||||
// 2. If result is a Promise, then return result.
|
||||
if (result)
|
||||
return GC::Ref { *result };
|
||||
|
||||
// 3. Return a promise resolved with undefined.
|
||||
return WebIDL::create_resolved_promise(realm, JS::js_undefined());
|
||||
});
|
||||
|
||||
// 7. Let cancelAlgorithmWrapper be an algorithm that runs these steps given a value reason:
|
||||
auto cancel_algorithm_wrapper = GC::create_function(realm.heap(), [&realm, cancel_algorithm](JS::Value reason) -> GC::Ref<WebIDL::Promise> {
|
||||
// 1. Let result be the result of running cancelAlgorithm given reason, if cancelAlgorithm was given, or null otherwise. If this throws an exception e, return a promise rejected with e.
|
||||
GC::Ptr<JS::PromiseCapability> result = nullptr;
|
||||
if (cancel_algorithm)
|
||||
result = cancel_algorithm->function()(reason);
|
||||
|
||||
// 2. If result is a Promise, then return result.
|
||||
if (result)
|
||||
return GC::Ref { *result };
|
||||
|
||||
// 3. Return a promise resolved with undefined.
|
||||
return WebIDL::create_resolved_promise(realm, JS::js_undefined());
|
||||
});
|
||||
|
||||
// 8. Let startPromise be a promise resolved with undefined.
|
||||
auto start_promise = WebIDL::create_resolved_promise(realm, JS::js_undefined());
|
||||
|
||||
// 9. Perform ! InitializeTransformStream(stream, startPromise, writableHighWaterMark, writableSizeAlgorithm, readableHighWaterMark, readableSizeAlgorithm).
|
||||
initialize_transform_stream(*this, start_promise, writable_high_water_mark, writable_size_algorithm, readable_high_water_mark, readable_size_algorithm);
|
||||
|
||||
// 10. Let controller be a new TransformStreamDefaultController.
|
||||
auto controller = realm.create<TransformStreamDefaultController>(realm);
|
||||
|
||||
// 11. Perform ! SetUpTransformStreamDefaultController(stream, controller, transformAlgorithmWrapper, flushAlgorithmWrapper, cancelAlgorithmWrapper).
|
||||
set_up_transform_stream_default_controller(*this, controller, transform_algorithm_wrapper, flush_algorithm_wrapper, cancel_algorithm_wrapper);
|
||||
}
|
||||
|
||||
TransformStream::TransformStream(JS::Realm& realm)
|
||||
: Bindings::PlatformObject(realm)
|
||||
{
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include <LibJS/Forward.h>
|
||||
#include <LibWeb/Bindings/PlatformObject.h>
|
||||
#include <LibWeb/Forward.h>
|
||||
#include <LibWeb/Streams/Algorithms.h>
|
||||
#include <LibWeb/Streams/QueuingStrategy.h>
|
||||
#include <LibWeb/WebIDL/Promise.h>
|
||||
|
||||
|
@ -40,6 +41,8 @@ public:
|
|||
GC::Ptr<TransformStreamDefaultController> controller() const { return m_controller; }
|
||||
void set_controller(GC::Ptr<TransformStreamDefaultController> value) { m_controller = value; }
|
||||
|
||||
void set_up(GC::Ref<TransformAlgorithm>, GC::Ptr<FlushAlgorithm> = {}, GC::Ptr<CancelAlgorithm> = {});
|
||||
|
||||
private:
|
||||
explicit TransformStream(JS::Realm& realm);
|
||||
|
||||
|
|
|
@ -19,10 +19,10 @@ JS::ThrowCompletionOr<Transformer> Transformer::from_value(JS::VM& vm, JS::Value
|
|||
auto& object = value.as_object();
|
||||
|
||||
Transformer transformer {
|
||||
.start = TRY(property_to_callback(vm, value, "start", WebIDL::OperationReturnsPromise::No)),
|
||||
.transform = TRY(property_to_callback(vm, value, "transform", WebIDL::OperationReturnsPromise::Yes)),
|
||||
.flush = TRY(property_to_callback(vm, value, "flush", WebIDL::OperationReturnsPromise::Yes)),
|
||||
.cancel = TRY(property_to_callback(vm, value, "cancel", WebIDL::OperationReturnsPromise::Yes)),
|
||||
.start = TRY(WebIDL::property_to_callback(vm, value, "start", WebIDL::OperationReturnsPromise::No)),
|
||||
.transform = TRY(WebIDL::property_to_callback(vm, value, "transform", WebIDL::OperationReturnsPromise::Yes)),
|
||||
.flush = TRY(WebIDL::property_to_callback(vm, value, "flush", WebIDL::OperationReturnsPromise::Yes)),
|
||||
.cancel = TRY(WebIDL::property_to_callback(vm, value, "cancel", WebIDL::OperationReturnsPromise::Yes)),
|
||||
.readable_type = {},
|
||||
.writable_type = {},
|
||||
};
|
||||
|
|
|
@ -19,10 +19,10 @@ JS::ThrowCompletionOr<UnderlyingSink> UnderlyingSink::from_value(JS::VM& vm, JS:
|
|||
auto& object = value.as_object();
|
||||
|
||||
UnderlyingSink underlying_sink {
|
||||
.start = TRY(property_to_callback(vm, value, "start", WebIDL::OperationReturnsPromise::No)),
|
||||
.write = TRY(property_to_callback(vm, value, "write", WebIDL::OperationReturnsPromise::Yes)),
|
||||
.close = TRY(property_to_callback(vm, value, "close", WebIDL::OperationReturnsPromise::Yes)),
|
||||
.abort = TRY(property_to_callback(vm, value, "abort", WebIDL::OperationReturnsPromise::Yes)),
|
||||
.start = TRY(WebIDL::property_to_callback(vm, value, "start", WebIDL::OperationReturnsPromise::No)),
|
||||
.write = TRY(WebIDL::property_to_callback(vm, value, "write", WebIDL::OperationReturnsPromise::Yes)),
|
||||
.close = TRY(WebIDL::property_to_callback(vm, value, "close", WebIDL::OperationReturnsPromise::Yes)),
|
||||
.abort = TRY(WebIDL::property_to_callback(vm, value, "abort", WebIDL::OperationReturnsPromise::Yes)),
|
||||
.type = {},
|
||||
};
|
||||
|
||||
|
|
|
@ -22,9 +22,9 @@ JS::ThrowCompletionOr<UnderlyingSource> UnderlyingSource::from_value(JS::VM& vm,
|
|||
auto& object = value.as_object();
|
||||
|
||||
UnderlyingSource underlying_source {
|
||||
.start = TRY(property_to_callback(vm, value, "start", WebIDL::OperationReturnsPromise::No)),
|
||||
.pull = TRY(property_to_callback(vm, value, "pull", WebIDL::OperationReturnsPromise::Yes)),
|
||||
.cancel = TRY(property_to_callback(vm, value, "cancel", WebIDL::OperationReturnsPromise::Yes)),
|
||||
.start = TRY(WebIDL::property_to_callback(vm, value, "start", WebIDL::OperationReturnsPromise::No)),
|
||||
.pull = TRY(WebIDL::property_to_callback(vm, value, "pull", WebIDL::OperationReturnsPromise::Yes)),
|
||||
.cancel = TRY(WebIDL::property_to_callback(vm, value, "cancel", WebIDL::OperationReturnsPromise::Yes)),
|
||||
.type = {},
|
||||
.auto_allocate_chunk_size = {},
|
||||
};
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
*/
|
||||
|
||||
#include <LibJS/Runtime/Object.h>
|
||||
#include <LibJS/Runtime/VM.h>
|
||||
#include <LibWeb/HTML/Scripting/Environments.h>
|
||||
#include <LibWeb/WebIDL/CallbackType.h>
|
||||
|
||||
|
@ -26,4 +27,19 @@ void CallbackType::visit_edges(Cell::Visitor& visitor)
|
|||
visitor.visit(callback_context);
|
||||
}
|
||||
|
||||
// Non-standard function to aid in converting a user-provided function into a WebIDL::Callback. This is essentially
|
||||
// what the Bindings generator would do at compile time, but at runtime instead.
|
||||
JS::ThrowCompletionOr<GC::Root<CallbackType>> property_to_callback(JS::VM& vm, JS::Value value, JS::PropertyKey const& property_key, OperationReturnsPromise operation_returns_promise)
|
||||
{
|
||||
auto property = TRY(value.get(vm, property_key));
|
||||
|
||||
if (property.is_undefined())
|
||||
return GC::Root<CallbackType> {};
|
||||
|
||||
if (!property.is_function())
|
||||
return vm.throw_completion<JS::TypeError>(JS::ErrorType::NotAFunction, property.to_string_without_side_effects());
|
||||
|
||||
return vm.heap().allocate<CallbackType>(property.as_object(), HTML::incumbent_realm(), operation_returns_promise);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -39,4 +39,6 @@ private:
|
|||
virtual void visit_edges(Cell::Visitor&) override;
|
||||
};
|
||||
|
||||
JS::ThrowCompletionOr<GC::Root<WebIDL::CallbackType>> property_to_callback(JS::VM& vm, JS::Value value, JS::PropertyKey const& property_key, WebIDL::OperationReturnsPromise);
|
||||
|
||||
}
|
||||
|
|
|
@ -39,14 +39,12 @@ Optional<URL::URL> sanitize_url(StringView url, Optional<StringView> search_engi
|
|||
}
|
||||
|
||||
ByteString url_with_scheme = url;
|
||||
if (!(url_with_scheme.starts_with("about:"sv) || url_with_scheme.contains("://"sv) || url_with_scheme.starts_with("data:"sv)))
|
||||
if (!(url_with_scheme.starts_with("about:"sv) || url_with_scheme.contains("://"sv) || url_with_scheme.starts_with("data:"sv) || url_with_scheme.contains("."sv)) {
|
||||
url_with_scheme = ByteString::formatted("https://{}"sv, url_with_scheme);
|
||||
|
||||
auto result = URL::create_with_url_or_path(url_with_scheme);
|
||||
if (!result.is_valid())
|
||||
return format_search_engine();
|
||||
|
||||
return result;
|
||||
return URL::create_with_url_or_path(url_with_scheme);
|
||||
}
|
||||
|
||||
return format_search_engine();;
|
||||
}
|
||||
|
||||
Vector<URL::URL> sanitize_urls(ReadonlySpan<ByteString> raw_urls, URL::URL const& new_tab_page_url)
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
%26%2319973%3B
|
|
@ -0,0 +1,16 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="iso-2022-jp">
|
||||
<script src="../include.js"></script>
|
||||
<script>
|
||||
test(() => {
|
||||
const input = "\u4E05"; // 丅
|
||||
const a = document.createElement("a");
|
||||
a.href = "https://ladybird.org/?" + input;
|
||||
println(a.search.substr(1));
|
||||
})
|
||||
</script>
|
||||
</head>
|
||||
<body></body>
|
||||
</html>
|
Loading…
Reference in a new issue