From 0650edc7d76f05195319b1280bd581b2e59cb458 Mon Sep 17 00:00:00 2001 From: Andrew Kaster Date: Fri, 22 Sep 2023 18:30:40 -0600 Subject: [PATCH] LibWeb: Implement Navigation AOs that are called during event firing These Navigation API Method Tracker AOs are called by the inner navigate event firing algorithm. Implement them beforehand to make the diff look pretty :^). --- Userland/Libraries/LibWeb/HTML/Navigation.cpp | 95 +++++++++++++++++++ Userland/Libraries/LibWeb/HTML/Navigation.h | 4 + 2 files changed, 99 insertions(+) diff --git a/Userland/Libraries/LibWeb/HTML/Navigation.cpp b/Userland/Libraries/LibWeb/HTML/Navigation.cpp index b54d1af5fa..568f8cf222 100644 --- a/Userland/Libraries/LibWeb/HTML/Navigation.cpp +++ b/Userland/Libraries/LibWeb/HTML/Navigation.cpp @@ -20,6 +20,7 @@ #include #include #include +#include namespace Web::HTML { @@ -766,4 +767,98 @@ void Navigation::abort_the_ongoing_navigation(Optional destination_key) +{ + // 1. Assert: navigation's ongoing API method tracker is null. + VERIFY(m_ongoing_api_method_tracker == nullptr); + + // 2. If destinationKey is not null, then: + if (destination_key.has_value()) { + // 1. Assert: navigation's upcoming non-traverse API method tracker is null. + VERIFY(m_upcoming_non_traverse_api_method_tracker == nullptr); + + // 2. If navigation's upcoming traverse API method trackers[destinationKey] exists, then: + if (auto tracker = m_upcoming_traverse_api_method_trackers.get(destination_key.value()); tracker.has_value()) { + // 1. Set navigation's ongoing API method tracker to navigation's upcoming traverse API method trackers[destinationKey]. + m_ongoing_api_method_tracker = tracker.value(); + + // 2. Remove navigation's upcoming traverse API method trackers[destinationKey]. + m_upcoming_traverse_api_method_trackers.remove(destination_key.value()); + } + } + + // 3. Otherwise: + else { + VERIFY(m_upcoming_non_traverse_api_method_tracker != nullptr); + + // 1. Set navigation's ongoing API method tracker to navigation's upcoming non-traverse API method tracker. + m_ongoing_api_method_tracker = m_upcoming_non_traverse_api_method_tracker; + + // 2. Set navigation's upcoming non-traverse API method tracker to null. + m_upcoming_non_traverse_api_method_tracker = nullptr; + } +} + +// https://html.spec.whatwg.org/multipage/nav-history-apis.html#navigation-api-method-tracker-clean-up +void Navigation::clean_up(JS::NonnullGCPtr api_method_tracker) +{ + // 1. Let navigation be apiMethodTracker's navigation object. + VERIFY(api_method_tracker->navigation == this); + + // 2. If navigation's ongoing API method tracker is apiMethodTracker, then set navigation's ongoing API method tracker to null. + if (m_ongoing_api_method_tracker == api_method_tracker) { + m_ongoing_api_method_tracker = nullptr; + } + // 3. Otherwise: + else { + // 1. Let key be apiMethodTracker's key. + auto& key = api_method_tracker->key; + + // 2. Assert: key is not null. + VERIFY(key.has_value()); + + // 3. Assert: navigation's upcoming traverse API method trackers[key] exists. + VERIFY(m_upcoming_traverse_api_method_trackers.contains(*key)); + + // 4. Remove navigation's upcoming traverse API method trackers[key]. + m_upcoming_traverse_api_method_trackers.remove(*key); + } +} + +// https://html.spec.whatwg.org/multipage/nav-history-apis.html#resolve-the-finished-promise +void Navigation::resolve_the_finished_promise(JS::NonnullGCPtr api_method_tracker) +{ + auto& realm = this->realm(); + + // 1. Resolve apiMethodTracker's committed promise with its committed-to entry. + // NOTE: Usually, notify about the committed-to entry has previously been called on apiMethodTracker, + // and so this will do nothing. However, in some cases resolve the finished promise is called + // directly, in which case this step is necessary. + WebIDL::resolve_promise(realm, api_method_tracker->committed_promise, api_method_tracker->commited_to_entry); + + // 2. Resolve apiMethodTracker's finished promise with its committed-to entry. + WebIDL::resolve_promise(realm, api_method_tracker->finished_promise, api_method_tracker->commited_to_entry); + + // 3. Clean up apiMethodTracker. + clean_up(api_method_tracker); +} + +// https://html.spec.whatwg.org/multipage/nav-history-apis.html#reject-the-finished-promise +void Navigation::reject_the_finished_promise(JS::NonnullGCPtr api_method_tracker, JS::Value exception) +{ + auto& realm = this->realm(); + + // 1. Reject apiMethodTracker's committed promise with exception. + // NOTE: This will do nothing if apiMethodTracker's committed promise was previously resolved + // via notify about the committed-to entry. + WebIDL::reject_promise(realm, api_method_tracker->committed_promise, exception); + + // 2. Reject apiMethodTracker's finished promise with exception. + WebIDL::reject_promise(realm, api_method_tracker->finished_promise, exception); + + // 3. Clean up apiMethodTracker. + clean_up(api_method_tracker); +} + } diff --git a/Userland/Libraries/LibWeb/HTML/Navigation.h b/Userland/Libraries/LibWeb/HTML/Navigation.h index 2f40c7fab4..b1f144b53d 100644 --- a/Userland/Libraries/LibWeb/HTML/Navigation.h +++ b/Userland/Libraries/LibWeb/HTML/Navigation.h @@ -128,6 +128,10 @@ private: JS::NonnullGCPtr maybe_set_the_upcoming_non_traverse_api_method_tracker(JS::Value info, Optional); JS::NonnullGCPtr add_an_upcoming_traverse_api_method_tracker(String destination_key, JS::Value info); WebIDL::ExceptionOr perform_a_navigation_api_traversal(String key, NavigationOptions const&); + void promote_an_upcoming_api_method_tracker_to_ongoing(Optional destination_key); + void resolve_the_finished_promise(JS::NonnullGCPtr); + void reject_the_finished_promise(JS::NonnullGCPtr, JS::Value exception); + void clean_up(JS::NonnullGCPtr); // https://html.spec.whatwg.org/multipage/nav-history-apis.html#navigation-entry-list // Each Navigation has an associated entry list, a list of NavigationHistoryEntry objects, initially empty.