LibWeb: Let queue_global_task() take a JS::HeapFunction

Changes the signature of queue_global_task() from AK:Function to
JS::HeapFunction to be more clear to the user of the function that this
is what it uses internally.
This commit is contained in:
Kenneth Myhra 2024-04-16 22:04:01 +02:00 committed by Andreas Kling
parent 9540af6489
commit a3661fd7f2
Notes: sideshowbarker 2024-07-17 03:05:16 +09:00
23 changed files with 104 additions and 103 deletions

View file

@ -457,9 +457,9 @@ void Animation::cancel(ShouldInvalidate should_invalidate)
scheduled_event_time = m_timeline->convert_a_timeline_time_to_an_origin_relative_time(m_timeline->current_time());
document->append_pending_animation_event({ cancel_event, *this, scheduled_event_time });
} else {
HTML::queue_global_task(HTML::Task::Source::DOMManipulation, realm.global_object(), [this, cancel_event]() {
HTML::queue_global_task(HTML::Task::Source::DOMManipulation, realm.global_object(), JS::create_heap_function(heap(), [this, cancel_event]() {
dispatch_event(cancel_event);
});
}));
}
}

View file

@ -171,7 +171,7 @@ ErrorOr<void> initialize_main_thread_vm()
// 5. Queue a global task on the DOM manipulation task source given global to fire an event named rejectionhandled at global, using PromiseRejectionEvent,
// with the promise attribute initialized to promise, and the reason attribute initialized to the value of promise's [[PromiseResult]] internal slot.
HTML::queue_global_task(HTML::Task::Source::DOMManipulation, global, [&global, &promise] {
HTML::queue_global_task(HTML::Task::Source::DOMManipulation, global, JS::create_heap_function(s_main_thread_vm->heap(), [&global, &promise] {
// FIXME: This currently assumes that global is a WindowObject.
auto& window = verify_cast<HTML::Window>(global);
@ -182,7 +182,7 @@ ErrorOr<void> initialize_main_thread_vm()
};
auto promise_rejection_event = HTML::PromiseRejectionEvent::create(HTML::relevant_realm(global), HTML::EventNames::rejectionhandled, event_init);
window.dispatch_event(promise_rejection_event);
});
}));
break;
}
default:
@ -226,7 +226,7 @@ ErrorOr<void> initialize_main_thread_vm()
auto& global = finalization_registry.realm().global_object();
// 2. Queue a global task on the JavaScript engine task source given global to perform the following steps:
HTML::queue_global_task(HTML::Task::Source::JavaScriptEngine, global, [&finalization_registry] {
HTML::queue_global_task(HTML::Task::Source::JavaScriptEngine, global, JS::create_heap_function(s_main_thread_vm->heap(), [&finalization_registry] {
// 1. Let entry be finalizationRegistry.[[CleanupCallback]].[[Callback]].[[Realm]]'s environment settings object.
auto& entry = host_defined_environment_settings_object(*finalization_registry.cleanup_callback().callback().realm());
@ -246,7 +246,7 @@ ErrorOr<void> initialize_main_thread_vm()
// 6. If result is an abrupt completion, then report the exception given by result.[[Value]].
if (result.is_error())
HTML::report_exception(result, finalization_registry.realm());
});
}));
};
// 8.1.5.4.3 HostEnqueuePromiseJob(job, realm), https://html.spec.whatwg.org/multipage/webappapis.html#hostenqueuepromisejob

View file

@ -158,17 +158,17 @@ JS::NonnullGCPtr<JS::Promise> Clipboard::write_text(String data)
if (!result) {
// 1. Queue a global task on the permission task source, given realms global object, to reject p with
// "NotAllowedError" DOMException in realm.
queue_global_task(HTML::Task::Source::Permissions, realm.global_object(), [&realm, promise]() mutable {
queue_global_task(HTML::Task::Source::Permissions, realm.global_object(), JS::create_heap_function(realm.heap(), [&realm, promise]() mutable {
HTML::TemporaryExecutionContext execution_context { Bindings::host_defined_environment_settings_object(realm) };
WebIDL::reject_promise(realm, promise, WebIDL::NotAllowedError::create(realm, "Clipboard writing is only allowed through user activation"_fly_string));
});
}));
// 2. Abort these steps.
return;
}
// 1. Queue a global task on the clipboard task source, given realms global object, to perform the below steps:
queue_global_task(HTML::Task::Source::Clipboard, realm.global_object(), [&realm, promise, data = move(data)]() mutable {
queue_global_task(HTML::Task::Source::Clipboard, realm.global_object(), JS::create_heap_function(realm.heap(), [&realm, promise, data = move(data)]() mutable {
// 1. Let itemList be an empty sequence<Blob>.
Vector<JS::NonnullGCPtr<FileAPI::Blob>> item_list;
@ -189,7 +189,7 @@ JS::NonnullGCPtr<JS::Promise> Clipboard::write_text(String data)
// 6. Resolve p.
HTML::TemporaryExecutionContext execution_context { Bindings::host_defined_environment_settings_object(realm) };
WebIDL::resolve_promise(realm, promise, JS::js_undefined());
});
}));
});
// 4. Return p.

View file

@ -135,10 +135,10 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<AbortSignal>> AbortSignal::timeout(JS::VM&
// 3. Run steps after a timeout given global, "AbortSignal-timeout", milliseconds, and the following step:
window_or_worker->run_steps_after_a_timeout(milliseconds, [&realm, &global, signal]() {
// 1. Queue a global task on the timer task source given global to signal abort given signal and a new "TimeoutError" DOMException.
HTML::queue_global_task(HTML::Task::Source::TimerTask, global, [&realm, signal]() mutable {
HTML::queue_global_task(HTML::Task::Source::TimerTask, global, JS::create_heap_function(realm.heap(), [&realm, signal]() mutable {
auto reason = WebIDL::TimeoutError::create(realm, "Signal timed out"_fly_string);
signal->signal_abort(reason);
});
}));
});
// 4. Return signal.

View file

@ -3107,7 +3107,7 @@ void Document::destroy()
}
// https://html.spec.whatwg.org/multipage/document-lifecycle.html#destroy-a-document-and-its-descendants
void Document::destroy_a_document_and_its_descendants(JS::SafeFunction<void()> after_all_destruction)
void Document::destroy_a_document_and_its_descendants(JS::GCPtr<JS::HeapFunction<void()>> after_all_destruction)
{
// 1. Let childNavigables be document's child navigables.
auto child_navigables = document_tree_child_navigables();
@ -3118,13 +3118,13 @@ void Document::destroy_a_document_and_its_descendants(JS::SafeFunction<void()> a
// 3. For each childNavigable of childNavigable's, queue a global task on the navigation and traversal task source
// given childNavigable's active window to perform the following steps:
for (auto& child_navigable : child_navigables) {
HTML::queue_global_task(HTML::Task::Source::NavigationAndTraversal, *child_navigable->active_window(), [&number_destroyed, child_navigable = child_navigable.ptr()] {
HTML::queue_global_task(HTML::Task::Source::NavigationAndTraversal, *child_navigable->active_window(), JS::create_heap_function(heap(), [&heap = heap(), &number_destroyed, child_navigable = child_navigable.ptr()] {
// 1. Let incrementDestroyed be an algorithm step which increments numberDestroyed.
auto increment_destroyed = [&number_destroyed] { ++number_destroyed; };
auto increment_destroyed = JS::create_heap_function(heap, [&number_destroyed] { ++number_destroyed; });
// 2. Destroy a document and its descendants given childNavigable's active document and incrementDestroyed.
child_navigable->active_document()->destroy_a_document_and_its_descendants(move(increment_destroyed));
});
}));
}
// 4. Wait until numberDestroyed equals childNavigable's size.
@ -3133,14 +3133,14 @@ void Document::destroy_a_document_and_its_descendants(JS::SafeFunction<void()> a
});
// 4. Queue a global task on the navigation and traversal task source given document's relevant global object to perform the following steps:
HTML::queue_global_task(HTML::Task::Source::NavigationAndTraversal, relevant_global_object(*this), [after_all_destruction = move(after_all_destruction), this] {
HTML::queue_global_task(HTML::Task::Source::NavigationAndTraversal, relevant_global_object(*this), JS::create_heap_function(heap(), [after_all_destruction = move(after_all_destruction), this] {
// 1. Destroy document.
destroy();
// 2. If afterAllDestruction was given, then run it.
if (after_all_destruction)
after_all_destruction();
});
after_all_destruction->function()();
}));
}
// https://html.spec.whatwg.org/multipage/browsing-the-web.html#abort-a-document
@ -3187,7 +3187,7 @@ void Document::abort_a_document_and_its_descendants()
// 3. For each descendantNavigable of descendantNavigables, queue a global task on the navigation and traversal task source given descendantNavigable's active window to perform the following steps:
for (auto& descendant_navigable : descendant_navigables) {
HTML::queue_global_task(HTML::Task::Source::NavigationAndTraversal, *descendant_navigable->active_window(), [this, descendant_navigable = descendant_navigable.ptr()] {
HTML::queue_global_task(HTML::Task::Source::NavigationAndTraversal, *descendant_navigable->active_window(), JS::create_heap_function(heap(), [this, descendant_navigable = descendant_navigable.ptr()] {
// NOTE: This is not in the spec but we need to abort ongoing navigations in all descendant navigables.
// See https://github.com/whatwg/html/issues/9711
descendant_navigable->set_ongoing_navigation({});
@ -3198,7 +3198,7 @@ void Document::abort_a_document_and_its_descendants()
// 2. If descendantNavigable's active document's salvageable is false, then set document's salvageable to false.
if (!descendant_navigable->active_document()->m_salvageable)
m_salvageable = false;
});
}));
}
// 4. Abort document.
@ -3306,7 +3306,7 @@ void Document::unload(JS::GCPtr<Document>)
}
// https://html.spec.whatwg.org/multipage/document-lifecycle.html#unload-a-document-and-its-descendants
void Document::unload_a_document_and_its_descendants(JS::GCPtr<Document> new_document, JS::SafeFunction<void()> after_all_unloads)
void Document::unload_a_document_and_its_descendants(JS::GCPtr<Document> new_document, JS::GCPtr<JS::HeapFunction<void()>> after_all_unloads)
{
// Specification defines this algorithm in the following steps:
// 1. Recursively unload (and destroy) documents in descendant navigables
@ -3342,16 +3342,16 @@ void Document::unload_a_document_and_its_descendants(JS::GCPtr<Document> new_doc
auto unloaded_documents_count = descendant_navigables.size() + 1;
HTML::queue_global_task(HTML::Task::Source::NavigationAndTraversal, HTML::relevant_global_object(*this), [&number_unloaded, this, new_document] {
HTML::queue_global_task(HTML::Task::Source::NavigationAndTraversal, HTML::relevant_global_object(*this), JS::create_heap_function(heap(), [&number_unloaded, this, new_document] {
unload(new_document);
++number_unloaded;
});
}));
for (auto& descendant_navigable : descendant_navigables) {
HTML::queue_global_task(HTML::Task::Source::NavigationAndTraversal, *descendant_navigable->active_window(), [&number_unloaded, descendant_navigable = descendant_navigable.ptr()] {
HTML::queue_global_task(HTML::Task::Source::NavigationAndTraversal, *descendant_navigable->active_window(), JS::create_heap_function(heap(), [&number_unloaded, descendant_navigable = descendant_navigable.ptr()] {
descendant_navigable->active_document()->unload();
++number_unloaded;
});
}));
}
HTML::main_thread_event_loop().spin_until([&] {
@ -3588,7 +3588,7 @@ void Document::queue_intersection_observer_task()
m_intersection_observer_task_queued = true;
// 3. Queue a task on the IntersectionObserver task source associated with the document's event loop to notify intersection observers.
HTML::queue_global_task(HTML::Task::Source::IntersectionObserver, *window, [this]() {
HTML::queue_global_task(HTML::Task::Source::IntersectionObserver, *window, JS::create_heap_function(heap(), [this]() {
auto& realm = this->realm();
// https://www.w3.org/TR/intersection-observer/#notify-intersection-observers
@ -3627,7 +3627,7 @@ void Document::queue_intersection_observer_task()
if (completion.is_abrupt())
HTML::report_exception(completion, realm);
}
});
}));
}
// https://www.w3.org/TR/intersection-observer/#queue-an-intersectionobserverentry
@ -4093,9 +4093,9 @@ void Document::update_for_history_step_application(JS::NonnullGCPtr<HTML::Sessio
hashchange_event_init.old_url = MUST(String::from_byte_string(old_url.serialize()));
hashchange_event_init.new_url = MUST(String::from_byte_string(entry->url().serialize()));
auto hashchange_event = HTML::HashChangeEvent::create(realm(), "hashchange"_fly_string, hashchange_event_init);
HTML::queue_global_task(HTML::Task::Source::DOMManipulation, relevant_global_object, [hashchange_event, &relevant_global_object]() {
HTML::queue_global_task(HTML::Task::Source::DOMManipulation, relevant_global_object, JS::create_heap_function(heap(), [hashchange_event, &relevant_global_object]() {
relevant_global_object.dispatch_event(hashchange_event);
});
}));
}
}
@ -4309,9 +4309,9 @@ void Document::remove_replaced_animations()
// Otherwise, queue a task to dispatch removeEvent at animation. The task source for this task is the DOM
// manipulation task source.
else {
HTML::queue_global_task(HTML::Task::Source::DOMManipulation, realm().global_object(), [animation, remove_event]() {
HTML::queue_global_task(HTML::Task::Source::DOMManipulation, realm().global_object(), JS::create_heap_function(heap(), [animation, remove_event]() {
animation->dispatch_event(remove_event);
});
}));
}
}
}

View file

@ -512,7 +512,7 @@ public:
// https://html.spec.whatwg.org/multipage/document-lifecycle.html#destroy-a-document
void destroy();
// https://html.spec.whatwg.org/multipage/document-lifecycle.html#destroy-a-document-and-its-descendants
void destroy_a_document_and_its_descendants(JS::SafeFunction<void()> after_all_destruction = {});
void destroy_a_document_and_its_descendants(JS::GCPtr<JS::HeapFunction<void()>> after_all_destruction = {});
// https://html.spec.whatwg.org/multipage/browsing-the-web.html#abort-a-document
void abort();
@ -522,7 +522,7 @@ public:
// https://html.spec.whatwg.org/multipage/document-lifecycle.html#unload-a-document
void unload(JS::GCPtr<Document> new_document = nullptr);
// https://html.spec.whatwg.org/multipage/document-lifecycle.html#unload-a-document-and-its-descendants
void unload_a_document_and_its_descendants(JS::GCPtr<Document> new_document, JS::SafeFunction<void()> after_all_unloads = {});
void unload_a_document_and_its_descendants(JS::GCPtr<Document> new_document, JS::GCPtr<JS::HeapFunction<void()>> after_all_unloads = {});
// https://html.spec.whatwg.org/multipage/dom.html#active-parser
JS::GCPtr<HTML::HTMLParser> active_parser();

View file

@ -109,13 +109,13 @@ void Range::update_associated_selection()
// task source to fire an event named selectionchange, which does not bubble and is not cancelable, at the document
// associated with the selection.
auto document = m_associated_selection->document();
queue_global_task(HTML::Task::Source::UserInteraction, relevant_global_object(*document), [document] {
queue_global_task(HTML::Task::Source::UserInteraction, relevant_global_object(*document), JS::create_heap_function(document->heap(), [document] {
EventInit event_init;
event_init.bubbles = false;
event_init.cancelable = false;
auto event = DOM::Event::create(document->realm(), HTML::EventNames::selectionchange, event_init);
document->dispatch_event(event);
});
}));
}
// https://dom.spec.whatwg.org/#concept-range-root

View file

@ -16,7 +16,8 @@ int queue_fetch_task(JS::Object& task_destination, Function<void()> algorithm)
// FIXME: 1. If taskDestination is a parallel queue, then enqueue algorithm to taskDestination.
// 2. Otherwise, queue a global task on the networking task source with taskDestination and algorithm.
return HTML::queue_global_task(HTML::Task::Source::Networking, task_destination, move(algorithm));
auto& vm = task_destination.vm();
return HTML::queue_global_task(HTML::Task::Source::Networking, task_destination, JS::create_heap_function(vm.heap(), move(algorithm)));
}
// AD-HOC: This overload allows tracking the queued task within the fetch controller so that we may cancel queued tasks

View file

@ -314,7 +314,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<Streams::ReadableStream>> Blob::get_stream(
auto bytes = m_byte_buffer;
// 2. Queue a global task on the file reading task source given blobs relevant global object to perform the following steps:
HTML::queue_global_task(HTML::Task::Source::FileReading, realm.global_object(), [stream, bytes = move(bytes)]() {
HTML::queue_global_task(HTML::Task::Source::FileReading, realm.global_object(), JS::create_heap_function(heap(), [stream, bytes = move(bytes)]() {
// NOTE: Using an TemporaryExecutionContext here results in a crash in the method HTML::incumbent_settings_object()
// since we end up in a state where we have no execution context + an event loop with an empty incumbent
// settings object stack. We still need an execution context therefore we push the realm's execution context
@ -348,7 +348,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<Streams::ReadableStream>> Blob::get_stream(
// Nowhere in the spec seems to mention this - but testing against other implementations the stream does appear to be closed after reading all data (closed callback is fired).
// Probably there is a better way of doing this.
readable_stream_close(*stream);
});
}));
}
}

View file

@ -157,9 +157,9 @@ WebIDL::ExceptionOr<void> FileReader::read_operation(Blob& blob, Type type, Opti
// 2. If chunkPromise is fulfilled, and isFirstChunk is true, queue a task to fire a progress event called loadstart at fr.
// NOTE: ISSUE 2 We might change loadstart to be dispatched synchronously, to align with XMLHttpRequest behavior. [Issue #119]
if (chunk_promise->state() == JS::Promise::State::Fulfilled && is_first_chunk) {
HTML::queue_global_task(HTML::Task::Source::FileReading, realm.global_object(), [this, &realm]() {
HTML::queue_global_task(HTML::Task::Source::FileReading, realm.global_object(), JS::create_heap_function(heap(), [this, &realm]() {
dispatch_event(DOM::Event::create(realm, HTML::EventNames::loadstart));
});
}));
}
// 3. Set isFirstChunk to false.
@ -186,7 +186,7 @@ WebIDL::ExceptionOr<void> FileReader::read_operation(Blob& blob, Type type, Opti
}
// 5. Otherwise, if chunkPromise is fulfilled with an object whose done property is true, queue a task to run the following steps and abort this algorithm:
else if (chunk_promise->state() == JS::Promise::State::Fulfilled && done.as_bool()) {
HTML::queue_global_task(HTML::Task::Source::FileReading, realm.global_object(), [this, bytes, type, &realm, encoding_name, blobs_type]() {
HTML::queue_global_task(HTML::Task::Source::FileReading, realm.global_object(), JS::create_heap_function(heap(), [this, bytes, type, &realm, encoding_name, blobs_type]() {
// 1. Set frs state to "done".
m_state = State::Done;
@ -214,13 +214,13 @@ WebIDL::ExceptionOr<void> FileReader::read_operation(Blob& blob, Type type, Opti
dispatch_event(DOM::Event::create(realm, HTML::EventNames::loadend));
// NOTE: Event handler for the load or error events could have started another load, if that happens the loadend event for this load is not fired.
});
}));
return;
}
// 6. Otherwise, if chunkPromise is rejected with an error error, queue a task to run the following steps and abort this algorithm:
else if (chunk_promise->state() == JS::Promise::State::Rejected) {
HTML::queue_global_task(HTML::Task::Source::FileReading, realm.global_object(), [this, &realm]() {
HTML::queue_global_task(HTML::Task::Source::FileReading, realm.global_object(), JS::create_heap_function(heap(), [this, &realm]() {
// 1. Set frs state to "done".
m_state = State::Done;
@ -234,7 +234,7 @@ WebIDL::ExceptionOr<void> FileReader::read_operation(Blob& blob, Type type, Opti
dispatch_event(DOM::Event::create(realm, HTML::EventNames::loadend));
// 5. Note: Event handler for the error event could have started another load, if that happens the loadend event for this load is not fired.
});
}));
}
}
});

View file

@ -370,7 +370,7 @@ void EventLoop::process()
}
// https://html.spec.whatwg.org/multipage/webappapis.html#queue-a-global-task
int queue_global_task(HTML::Task::Source source, JS::Object& global_object, Function<void()> steps)
int queue_global_task(HTML::Task::Source source, JS::Object& global_object, JS::NonnullGCPtr<JS::HeapFunction<void()>> steps)
{
// 1. Let event loop be global's relevant agent's event loop.
auto& global_custom_data = verify_cast<Bindings::WebEngineCustomData>(*global_object.vm().custom_data());
@ -385,7 +385,7 @@ int queue_global_task(HTML::Task::Source source, JS::Object& global_object, Func
// 3. Queue a task given source, event loop, document, and steps.
auto& vm = global_object.vm();
event_loop->task_queue().add(HTML::Task::create(vm, source, document, JS::create_heap_function(vm.heap(), move(steps))));
event_loop->task_queue().add(HTML::Task::create(vm, source, document, steps));
return event_loop->task_queue().last_added_task()->id();
}

View file

@ -116,7 +116,7 @@ private:
};
EventLoop& main_thread_event_loop();
int queue_global_task(HTML::Task::Source, JS::Object&, Function<void()> steps);
int queue_global_task(HTML::Task::Source, JS::Object&, JS::NonnullGCPtr<JS::HeapFunction<void()>> steps);
void queue_a_microtask(DOM::Document const*, JS::NonnullGCPtr<JS::HeapFunction<void()>> steps);
void perform_a_microtask_checkpoint();

View file

@ -252,14 +252,14 @@ ErrorOr<void> MessagePort::send_message_on_socket(SerializedTransferRecord const
void MessagePort::post_port_message(SerializedTransferRecord serialize_with_transfer_result)
{
// FIXME: Use the correct task source?
queue_global_task(Task::Source::PostedMessage, relevant_global_object(*this), [this, serialize_with_transfer_result = move(serialize_with_transfer_result)]() mutable {
queue_global_task(Task::Source::PostedMessage, relevant_global_object(*this), JS::create_heap_function(heap(), [this, serialize_with_transfer_result = move(serialize_with_transfer_result)]() mutable {
if (!m_socket || !m_socket->is_open())
return;
if (auto result = send_message_on_socket(serialize_with_transfer_result); result.is_error()) {
dbgln("Failed to post message: {}", result.error());
disentangle();
}
});
}));
}
ErrorOr<MessagePort::ParseDecision> MessagePort::parse_message()

View file

@ -1084,7 +1084,7 @@ WebIDL::ExceptionOr<void> Navigable::populate_session_history_entry_document(
return {};
// 6. Queue a global task on the navigation and traversal task source, given navigable's active window, to run these steps:
queue_global_task(Task::Source::NavigationAndTraversal, *active_window(), [this, entry, navigation_params = move(navigation_params), navigation_id, completion_steps = move(completion_steps)]() mutable {
queue_global_task(Task::Source::NavigationAndTraversal, *active_window(), JS::create_heap_function(heap(), [this, entry, navigation_params = move(navigation_params), navigation_id, completion_steps = move(completion_steps)]() mutable {
// NOTE: This check is not in the spec but we should not continue navigation if navigable has been destroyed.
if (has_been_destroyed())
return;
@ -1187,7 +1187,7 @@ WebIDL::ExceptionOr<void> Navigable::populate_session_history_entry_document(
// 14. Run completionSteps.
completion_steps();
});
}));
return {};
}
@ -1316,9 +1316,9 @@ WebIDL::ExceptionOr<void> Navigable::navigate(NavigateParams params)
// 18. If url's scheme is "javascript", then:
if (url.scheme() == "javascript"sv) {
// 1. Queue a global task on the navigation and traversal task source given navigable's active window to navigate to a javascript: URL given navigable, url, historyHandling, initiatorOriginSnapshot, and cspNavigationType.
queue_global_task(Task::Source::NavigationAndTraversal, *active_window(), [this, url, history_handling, initiator_origin_snapshot, csp_navigation_type, navigation_id] {
queue_global_task(Task::Source::NavigationAndTraversal, *active_window(), JS::create_heap_function(heap(), [this, url, history_handling, initiator_origin_snapshot, csp_navigation_type, navigation_id] {
(void)navigate_to_a_javascript_url(url, to_history_handling_behavior(history_handling), initiator_origin_snapshot, csp_navigation_type, navigation_id);
});
}));
// 2. Return.
return {};
@ -1379,10 +1379,10 @@ WebIDL::ExceptionOr<void> Navigable::navigate(NavigateParams params)
}
// 3. Queue a global task on the navigation and traversal task source given navigable's active window to abort a document and its descendants given navigable's active document.
queue_global_task(Task::Source::NavigationAndTraversal, *active_window(), [this] {
queue_global_task(Task::Source::NavigationAndTraversal, *active_window(), JS::create_heap_function(heap(), [this] {
VERIFY(this->active_document());
this->active_document()->abort_a_document_and_its_descendants();
});
}));
// 4. Let documentState be a new document state with
// request referrer policy: referrerPolicy
@ -2090,7 +2090,7 @@ void Navigable::inform_the_navigation_api_about_aborting_navigation()
// FIXME: 1. If this algorithm is running on navigable's active window's relevant agent's event loop, then continue on to the following steps.
// Otherwise, queue a global task on the navigation and traversal task source given navigable's active window to run the following steps.
queue_global_task(Task::Source::NavigationAndTraversal, *active_window(), [this] {
queue_global_task(Task::Source::NavigationAndTraversal, *active_window(), JS::create_heap_function(heap(), [this] {
// 2. Let navigation be navigable's active window's navigation API.
auto navigation = active_window()->navigation();
@ -2100,7 +2100,7 @@ void Navigable::inform_the_navigation_api_about_aborting_navigation()
// 4. Abort the ongoing navigation given navigation.
navigation->abort_the_ongoing_navigation();
});
}));
}
void Navigable::paint(Painting::RecordingPainter& recording_painter, PaintConfig config)

View file

@ -275,7 +275,7 @@ void NavigableContainer::destroy_the_child_navigable()
// FIXME: 4. Inform the navigation API about child navigable destruction given navigable.
// 5. Destroy a document and its descendants given navigable's active document.
navigable->active_document()->destroy_a_document_and_its_descendants([this, navigable] {
navigable->active_document()->destroy_a_document_and_its_descendants(JS::create_heap_function(heap(), [this, navigable] {
// 3. Set container's content navigable to null.
m_content_navigable = nullptr;
@ -298,7 +298,7 @@ void NavigableContainer::destroy_the_child_navigable()
// 1. Update for navigable creation/destruction given traversable.
traversable->update_for_navigable_creation_or_destruction();
});
});
}));
}
// https://html.spec.whatwg.org/multipage/iframe-embed-object.html#potentially-delays-the-load-event

View file

@ -679,12 +679,12 @@ WebIDL::ExceptionOr<NavigationResult> Navigation::perform_a_navigation_api_trave
// 1. Queue a global task on the navigation and traversal task source given navigation's relevant global object
// to reject the finished promise for apiMethodTracker with an "InvalidStateError" DOMException.
queue_global_task(HTML::Task::Source::NavigationAndTraversal, relevant_global_object(*this), [this, api_method_tracker] {
queue_global_task(HTML::Task::Source::NavigationAndTraversal, relevant_global_object(*this), JS::create_heap_function(heap(), [this, api_method_tracker] {
auto& reject_realm = relevant_realm(*this);
TemporaryExecutionContext execution_context { relevant_settings_object(*this) };
WebIDL::reject_promise(reject_realm, api_method_tracker->finished_promise,
WebIDL::InvalidStateError::create(reject_realm, "Cannot traverse with stale session history entry"_fly_string));
});
}));
// 2. Abort these steps.
return;
@ -712,20 +712,20 @@ WebIDL::ExceptionOr<NavigationResult> Navigation::perform_a_navigation_api_trave
auto& realm = relevant_realm(*this);
auto& global = relevant_global_object(*this);
if (result == TraversableNavigable::HistoryStepResult::CanceledByBeforeUnload) {
queue_global_task(Task::Source::NavigationAndTraversal, global, [this, api_method_tracker, &realm] {
queue_global_task(Task::Source::NavigationAndTraversal, global, JS::create_heap_function(heap(), [this, api_method_tracker, &realm] {
TemporaryExecutionContext execution_context { relevant_settings_object(*this) };
reject_the_finished_promise(api_method_tracker, WebIDL::AbortError::create(realm, "Navigation cancelled by beforeunload"_fly_string));
});
}));
}
// 6. If result is "initiator-disallowed", then queue a global task on the navigation and traversal task source
// given navigation's relevant global object to reject the finished promise for apiMethodTracker with a
// new "SecurityError" DOMException created in navigation's relevant realm.
if (result == TraversableNavigable::HistoryStepResult::InitiatorDisallowed) {
queue_global_task(Task::Source::NavigationAndTraversal, global, [this, api_method_tracker, &realm] {
queue_global_task(Task::Source::NavigationAndTraversal, global, JS::create_heap_function(heap(), [this, api_method_tracker, &realm] {
TemporaryExecutionContext execution_context { relevant_settings_object(*this) };
reject_the_finished_promise(api_method_tracker, WebIDL::SecurityError::create(realm, "Navigation disallowed from this origin"_fly_string));
});
}));
}
});

View file

@ -291,7 +291,7 @@ void HTMLParser::the_end(JS::NonnullGCPtr<DOM::Document> document, JS::GCPtr<HTM
}
// 6. Queue a global task on the DOM manipulation task source given the Document's relevant global object to run the following substeps:
queue_global_task(HTML::Task::Source::DOMManipulation, *document, [document = document] {
queue_global_task(HTML::Task::Source::DOMManipulation, *document, JS::create_heap_function(document->heap(), [document = document] {
// 1. Set the Document's load timing info's DOM content loaded event start time to the current high resolution time given the Document's relevant global object.
document->load_timing_info().dom_content_loaded_event_start_time = HighResolutionTime::current_high_resolution_time(relevant_global_object(*document));
@ -306,7 +306,7 @@ void HTMLParser::the_end(JS::NonnullGCPtr<DOM::Document> document, JS::GCPtr<HTM
// FIXME: 4. Enable the client message queue of the ServiceWorkerContainer object whose associated service worker client is the Document object's relevant settings object.
// FIXME: 5. Invoke WebDriver BiDi DOM content loaded with the Document's browsing context, and a new WebDriver BiDi navigation status whose id is the Document object's navigation id, status is "pending", and url is the Document object's URL.
});
}));
// 7. Spin the event loop until the set of scripts that will execute as soon as possible and the list of scripts that will execute in order as soon as possible are empty.
main_thread_event_loop().spin_until([&] {
@ -319,7 +319,7 @@ void HTMLParser::the_end(JS::NonnullGCPtr<DOM::Document> document, JS::GCPtr<HTM
});
// 9. Queue a global task on the DOM manipulation task source given the Document's relevant global object to run the following steps:
queue_global_task(HTML::Task::Source::DOMManipulation, *document, [document = document] {
queue_global_task(HTML::Task::Source::DOMManipulation, *document, JS::create_heap_function(document->heap(), [document = document] {
// 1. Update the current document readiness to "complete".
document->update_readiness(HTML::DocumentReadyState::Complete);
@ -358,7 +358,7 @@ void HTMLParser::the_end(JS::NonnullGCPtr<DOM::Document> document, JS::GCPtr<HTM
document->completely_finish_loading();
// FIXME: 13. Queue the navigation timing entry for the Document.
});
}));
// FIXME: 10. If the Document's print when loaded flag is set, then run the printing steps.

View file

@ -239,7 +239,7 @@ void EnvironmentSettingsObject::notify_about_rejected_promises(Badge<EventLoop>)
auto& global = verify_cast<DOM::EventTarget>(global_object());
// 5. Queue a global task on the DOM manipulation task source given global to run the following substep:
queue_global_task(Task::Source::DOMManipulation, global, [this, &global, list = move(list)] {
queue_global_task(Task::Source::DOMManipulation, global, JS::create_heap_function(heap(), [this, &global, list = move(list)] {
auto& realm = global.realm();
// 1. For each promise p in list:
@ -277,7 +277,7 @@ void EnvironmentSettingsObject::notify_about_rejected_promises(Badge<EventLoop>)
if (not_handled)
HTML::report_exception_to_console(promise->result(), realm, ErrorInPromise::Yes);
}
});
}));
}
// https://html.spec.whatwg.org/multipage/webappapis.html#concept-environment-script

View file

@ -625,12 +625,12 @@ void fetch_single_module_script(JS::Realm& realm,
// then queue a task on the networking task source to proceed with running the following steps.
if (module_map.is_fetching(url, module_type)) {
module_map.wait_for_change(realm.heap(), url, module_type, [on_complete, &realm](auto entry) -> void {
HTML::queue_global_task(HTML::Task::Source::Networking, realm.global_object(), [on_complete, entry] {
HTML::queue_global_task(HTML::Task::Source::Networking, realm.global_object(), JS::create_heap_function(realm.heap(), [on_complete, entry] {
// FIXME: This should run other steps, for now we just assume the script loaded.
VERIFY(entry.type == ModuleMap::EntryType::ModuleScript);
on_complete->function()(entry.module_script);
});
}));
});
return;

View file

@ -336,7 +336,7 @@ Vector<JS::Handle<Navigable>> TraversableNavigable::get_all_navigables_that_migh
}
// https://html.spec.whatwg.org/multipage/browsing-the-web.html#deactivate-a-document-for-a-cross-document-navigation
static void deactivate_a_document_for_cross_document_navigation(JS::NonnullGCPtr<DOM::Document> displayed_document, Optional<UserNavigationInvolvement>, JS::NonnullGCPtr<SessionHistoryEntry> target_entry, JS::SafeFunction<void()> after_potential_unloads)
static void deactivate_a_document_for_cross_document_navigation(JS::NonnullGCPtr<DOM::Document> displayed_document, Optional<UserNavigationInvolvement>, JS::NonnullGCPtr<SessionHistoryEntry> target_entry, JS::NonnullGCPtr<JS::HeapFunction<void()>> after_potential_unloads)
{
// 1. Let navigable be displayedDocument's node navigable.
auto navigable = displayed_document->navigable();
@ -358,7 +358,7 @@ static void deactivate_a_document_for_cross_document_navigation(JS::NonnullGCPtr
navigable->set_ongoing_navigation({});
// 3. Unload a document and its descendants given displayedDocument, targetEntry's document, afterPotentialUnloads, and firePageSwapBeforeUnload.
displayed_document->unload_a_document_and_its_descendants(target_entry->document(), move(after_potential_unloads));
displayed_document->unload_a_document_and_its_descendants(target_entry->document(), after_potential_unloads);
}
// FIXME: 6. Otherwise, queue a global task on the navigation and traversal task source given navigable's active window to run the steps:
else {
@ -457,7 +457,7 @@ TraversableNavigable::HistoryStepResult TraversableNavigable::apply_the_history_
// 12. For each navigable of changingNavigables, queue a global task on the navigation and traversal task source of navigable's active window to run the steps:
for (auto& navigable : changing_navigables) {
queue_global_task(Task::Source::NavigationAndTraversal, *navigable->active_window(), [&] {
queue_global_task(Task::Source::NavigationAndTraversal, *navigable->active_window(), JS::create_heap_function(heap(), [&] {
// NOTE: This check is not in the spec but we should not continue navigation if navigable has been destroyed.
if (navigable->has_been_destroyed()) {
completed_change_jobs++;
@ -588,9 +588,9 @@ TraversableNavigable::HistoryStepResult TraversableNavigable::apply_the_history_
// navigable's active window to run afterDocumentPopulated.
Platform::EventLoopPlugin::the().deferred_invoke([populated_target_entry, potentially_target_specific_source_snapshot_params, target_snapshot_params, this, allow_POST, navigable, after_document_populated] {
navigable->populate_session_history_entry_document(populated_target_entry, *potentially_target_specific_source_snapshot_params, target_snapshot_params, {}, Empty {}, CSPNavigationType::Other, allow_POST, [this, after_document_populated, populated_target_entry]() mutable {
queue_global_task(Task::Source::NavigationAndTraversal, *active_window(), [after_document_populated, populated_target_entry]() mutable {
queue_global_task(Task::Source::NavigationAndTraversal, *active_window(), JS::create_heap_function(this->heap(), [after_document_populated, populated_target_entry]() mutable {
after_document_populated(true, populated_target_entry);
});
}));
})
.release_value_but_fixme_should_propagate_errors();
});
@ -599,7 +599,7 @@ TraversableNavigable::HistoryStepResult TraversableNavigable::apply_the_history_
else {
after_document_populated(false, *target_entry);
}
});
}));
}
auto check_if_document_population_tasks_completed = JS::SafeFunction<bool()>([&] {
@ -674,7 +674,7 @@ TraversableNavigable::HistoryStepResult TraversableNavigable::apply_the_history_
auto entries_for_navigation_api = get_session_history_entries_for_the_navigation_api(*navigable, target_step);
// 12. In both cases, let afterPotentialUnloads be the following steps:
auto after_potential_unload = JS::SafeFunction<void()>([changing_navigable_continuation, displayed_document, &completed_change_jobs, script_history_length, script_history_index, entries_for_navigation_api = move(entries_for_navigation_api)] {
auto after_potential_unload = JS::create_heap_function(this->heap(), [changing_navigable_continuation, displayed_document, &completed_change_jobs, script_history_length, script_history_index, entries_for_navigation_api = move(entries_for_navigation_api), &heap = this->heap()] {
auto const& target_entry = changing_navigable_continuation.target_entry;
if (changing_navigable_continuation.populated_cloned_target_session_history_entry) {
auto const& populating_target_entry = changing_navigable_continuation.populated_target_entry;
@ -700,9 +700,9 @@ TraversableNavigable::HistoryStepResult TraversableNavigable::apply_the_history_
}
// 5. Otherwise, queue a global task on the navigation and traversal task source given targetEntry's document's relevant global object to perform updateDocument
else {
queue_global_task(Task::Source::NavigationAndTraversal, relevant_global_object(*target_entry->document()), [update_document = move(update_document)]() {
queue_global_task(Task::Source::NavigationAndTraversal, relevant_global_object(*target_entry->document()), JS::create_heap_function(heap, [update_document = move(update_document)]() {
update_document();
});
}));
}
// 6. Increment completedChangeJobs.
@ -715,7 +715,7 @@ TraversableNavigable::HistoryStepResult TraversableNavigable::apply_the_history_
navigable->set_ongoing_navigation({});
// 2. Queue a global task on the navigation and traversal task source given navigable's active window to perform afterPotentialUnloads.
queue_global_task(Task::Source::NavigationAndTraversal, *navigable->active_window(), move(after_potential_unload));
queue_global_task(Task::Source::NavigationAndTraversal, *navigable->active_window(), after_potential_unload);
}
// 11. Otherwise:
else {
@ -723,7 +723,7 @@ TraversableNavigable::HistoryStepResult TraversableNavigable::apply_the_history_
VERIFY(navigation_type.has_value());
// 2. Deactivate displayedDocument, given userNavigationInvolvement, targetEntry, navigationType, and afterPotentialUnloads.
deactivate_a_document_for_cross_document_navigation(*displayed_document, user_involvement_for_navigate_events, *populated_target_entry, move(after_potential_unload));
deactivate_a_document_for_cross_document_navigation(*displayed_document, user_involvement_for_navigate_events, *populated_target_entry, after_potential_unload);
}
}
@ -749,7 +749,7 @@ TraversableNavigable::HistoryStepResult TraversableNavigable::apply_the_history_
continue;
}
queue_global_task(Task::Source::NavigationAndTraversal, *navigable->active_window(), [&] {
queue_global_task(Task::Source::NavigationAndTraversal, *navigable->active_window(), JS::create_heap_function(heap(), [&] {
// NOTE: This check is not in the spec but we should not continue navigation if navigable has been destroyed.
if (navigable->has_been_destroyed()) {
++completed_non_changing_jobs;
@ -767,7 +767,7 @@ TraversableNavigable::HistoryStepResult TraversableNavigable::apply_the_history_
// 4. Increment completedNonchangingJobs.
++completed_non_changing_jobs;
});
}));
}
// 19. Wait for completedNonchangingJobs to equal totalNonchangingJobs.
@ -1121,9 +1121,9 @@ void TraversableNavigable::set_system_visibility_state(VisibilityState visibilit
// 2. Queue a global task on the user interaction task source given document's relevant global object
// to update the visibility state of document with newState.
queue_global_task(Task::Source::UserInteraction, relevant_global_object(*document), [visibility_state, document] {
queue_global_task(Task::Source::UserInteraction, relevant_global_object(*document), JS::create_heap_function(heap(), [visibility_state, document] {
document->update_the_visibility_state(visibility_state);
});
}));
}
}

View file

@ -635,9 +635,9 @@ void Window::start_an_idle_period()
// 5. Queue a task on the queue associated with the idle-task task source,
// which performs the steps defined in the invoke idle callbacks algorithm with window and getDeadline as parameters.
queue_global_task(Task::Source::IdleTask, *this, [this] {
queue_global_task(Task::Source::IdleTask, *this, JS::create_heap_function(heap(), [this] {
invoke_idle_callbacks();
});
}));
}
// https://w3c.github.io/requestidlecallback/#invoke-idle-callbacks-algorithm
@ -659,9 +659,9 @@ void Window::invoke_idle_callbacks()
report_exception(result, realm());
// 4. If window's list of runnable idle callbacks is not empty, queue a task which performs the steps
// in the invoke idle callbacks algorithm with getDeadline and window as a parameters and return from this algorithm
queue_global_task(Task::Source::IdleTask, *this, [this] {
queue_global_task(Task::Source::IdleTask, *this, JS::create_heap_function(heap(), [this] {
invoke_idle_callbacks();
});
}));
}
}
@ -1120,7 +1120,7 @@ WebIDL::ExceptionOr<void> Window::window_post_message_steps(JS::Value message, W
auto serialize_with_transfer_result = TRY(structured_serialize_with_transfer(target_realm.vm(), message, transfer));
// 8. Queue a global task on the posted message task source given targetWindow to run the following steps:
queue_global_task(Task::Source::PostedMessage, *this, [this, serialize_with_transfer_result = move(serialize_with_transfer_result), target_origin = move(target_origin), &incumbent_settings, &target_realm]() mutable {
queue_global_task(Task::Source::PostedMessage, *this, JS::create_heap_function(heap(), [this, serialize_with_transfer_result = move(serialize_with_transfer_result), target_origin = move(target_origin), &incumbent_settings, &target_realm]() mutable {
// 1. If the targetOrigin argument is not a single literal U+002A ASTERISK character (*) and targetWindow's
// associated Document's origin is not same origin with targetOrigin, then return.
// NOTE: Due to step 4 and 5 above, the only time it's not '*' is if target_origin contains an Origin.
@ -1178,7 +1178,7 @@ WebIDL::ExceptionOr<void> Window::window_post_message_steps(JS::Value message, W
auto message_event = MessageEvent::create(target_realm, EventNames::message, message_event_init);
dispatch_event(message_event);
});
}));
return {};
}

View file

@ -396,9 +396,9 @@ i32 WindowOrWorkerGlobalScopeMixin::run_timer_initialization_steps(TimerHandler
// 11. Let completionStep be an algorithm step which queues a global task on the timer task source given global to run task.
Function<void()> completion_step = [this, task = move(task)]() mutable {
queue_global_task(Task::Source::TimerTask, this_impl(), [task] {
queue_global_task(Task::Source::TimerTask, this_impl(), JS::create_heap_function(this_impl().heap(), [task] {
task->function()();
});
}));
};
// 12. Run steps after a timeout given global, "setTimeout/setInterval", timeout, completionStep, and id.
@ -565,7 +565,7 @@ void WindowOrWorkerGlobalScopeMixin::queue_the_performance_observer_task()
// 3. Queue a task that consists of running the following substeps. The task source for the queued task is the performance
// timeline task source.
queue_global_task(Task::Source::PerformanceTimeline, this_impl(), [this]() {
queue_global_task(Task::Source::PerformanceTimeline, this_impl(), JS::create_heap_function(this_impl().heap(), [this]() {
auto& realm = this_impl().realm();
// 1. Unset performance observer task queued flag of relevantGlobal.
@ -642,7 +642,7 @@ void WindowOrWorkerGlobalScopeMixin::queue_the_performance_observer_task()
if (completion.is_abrupt())
HTML::report_exception(completion, realm);
}
});
}));
}
// https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html#run-steps-after-a-timeout

View file

@ -199,7 +199,7 @@ void XMLDocumentBuilder::document_end()
(void)m_document->scripts_to_execute_when_parsing_has_finished().take_first();
}
// Queue a global task on the DOM manipulation task source given the Document's relevant global object to run the following substeps:
queue_global_task(HTML::Task::Source::DOMManipulation, m_document, [document = m_document] {
queue_global_task(HTML::Task::Source::DOMManipulation, m_document, JS::create_heap_function(m_document->heap(), [document = m_document] {
// Set the Document's load timing info's DOM content loaded event start time to the current high resolution time given the Document's relevant global object.
document->load_timing_info().dom_content_loaded_event_start_time = HighResolutionTime::current_high_resolution_time(relevant_global_object(*document));
@ -214,7 +214,7 @@ void XMLDocumentBuilder::document_end()
// FIXME: Enable the client message queue of the ServiceWorkerContainer object whose associated service worker client is the Document object's relevant settings object.
// FIXME: Invoke WebDriver BiDi DOM content loaded with the Document's browsing context, and a new WebDriver BiDi navigation status whose id is the Document object's navigation id, status is "pending", and url is the Document object's URL.
});
}));
// Spin the event loop until the set of scripts that will execute as soon as possible and the list of scripts that will execute in order as soon as possible are empty.
HTML::main_thread_event_loop().spin_until([&] {
@ -227,7 +227,7 @@ void XMLDocumentBuilder::document_end()
});
// Queue a global task on the DOM manipulation task source given the Document's relevant global object to run the following steps:
queue_global_task(HTML::Task::Source::DOMManipulation, m_document, [document = m_document] {
queue_global_task(HTML::Task::Source::DOMManipulation, m_document, JS::create_heap_function(m_document->heap(), [document = m_document] {
// Update the current document readiness to "complete".
document->update_readiness(HTML::DocumentReadyState::Complete);
@ -266,7 +266,7 @@ void XMLDocumentBuilder::document_end()
document->completely_finish_loading();
// FIXME: Queue the navigation timing entry for the Document.
});
}));
// FIXME: If the Document's print when loaded flag is set, then run the printing steps.