diff options
author | Andreas Kling <kling@serenityos.org> | 2022-09-19 17:46:34 +0200 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2022-09-20 10:32:13 +0200 |
commit | 4ee5dfbe4b269157643d418de9eb97bf3ceaea3c (patch) | |
tree | 427ae5d3f0918095c97899351c260b6f55004f4a /Userland | |
parent | e5f6d36616275f2dd69fb8893478df13a93d4bde (diff) | |
download | serenity-4ee5dfbe4b269157643d418de9eb97bf3ceaea3c.zip |
LibWeb: Flesh out a chunk of the HTML spec's frame navigation algorithms
Diffstat (limited to 'Userland')
-rw-r--r-- | Userland/Libraries/LibWeb/HTML/BrowsingContext.cpp | 417 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/HTML/BrowsingContext.h | 34 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/HTML/BrowsingContextContainer.cpp | 15 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/HTML/EventLoop/TaskQueue.cpp | 7 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/HTML/EventLoop/TaskQueue.h | 2 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/HTML/SessionHistoryEntry.h | 2 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/HTML/Window.cpp | 7 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/HTML/Window.h | 3 |
8 files changed, 479 insertions, 8 deletions
diff --git a/Userland/Libraries/LibWeb/HTML/BrowsingContext.cpp b/Userland/Libraries/LibWeb/HTML/BrowsingContext.cpp index 919259011e..cb0e82e47b 100644 --- a/Userland/Libraries/LibWeb/HTML/BrowsingContext.cpp +++ b/Userland/Libraries/LibWeb/HTML/BrowsingContext.cpp @@ -6,7 +6,9 @@ #include <LibWeb/Bindings/MainThreadVM.h> #include <LibWeb/DOM/Document.h> +#include <LibWeb/DOM/Event.h> #include <LibWeb/DOM/HTMLCollection.h> +#include <LibWeb/Fetch/Infrastructure/HTTP/Requests.h> #include <LibWeb/HTML/BrowsingContext.h> #include <LibWeb/HTML/BrowsingContextContainer.h> #include <LibWeb/HTML/BrowsingContextGroup.h> @@ -222,6 +224,7 @@ NonnullRefPtr<BrowsingContext> BrowsingContext::create_a_new_browsing_context(Pa .policy_container = {}, .scroll_restoration_mode = {}, .browsing_context_name = {}, + .original_source_browsing_context = {}, }); // Non-standard: @@ -797,6 +800,16 @@ DOM::Document* BrowsingContext::active_document() return m_active_document.cell(); } +HTML::Window* BrowsingContext::active_window() +{ + return m_active_document ? &m_active_document->window() : nullptr; +} + +HTML::Window const* BrowsingContext::active_window() const +{ + return m_active_document ? &m_active_document->window() : nullptr; +} + void BrowsingContext::scroll_offset_did_change() { // https://w3c.github.io/csswg-drafts/cssom-view-1/#scrolling-events @@ -845,4 +858,408 @@ void BrowsingContext::remove() // NOTE: This is done by ~BrowsingContextGroup() when the refcount reaches 0. } +// https://html.spec.whatwg.org/multipage/browsing-the-web.html#navigate +DOM::ExceptionOr<void> BrowsingContext::navigate( + Fetch::Infrastructure::Request resource, + BrowsingContext& source_browsing_context, + bool exceptions_enabled, + HistoryHandlingBehavior history_handling, + Optional<PolicyContainer> history_policy_container, + String navigation_type, + Optional<String> navigation_id, + Function<void(NonnullOwnPtr<Fetch::Infrastructure::Response>)> process_response_end_of_body) +{ + // 1. If resource is a URL, then set resource to a new request whose URL is resource. + // NOTE: This function only accepts resources that are already a request, so this is irrelevant. + + // 2. If resource is a request and historyHandling is "reload", then set resource's reload-navigation flag. + if (history_handling == HistoryHandlingBehavior::Reload) + resource.set_reload_navigation(true); + + // 3. If the source browsing context is not allowed to navigate browsingContext, then: + if (!source_browsing_context.is_allowed_to_navigate(*this)) { + // 1. If exceptionsEnabled is given and is true, then throw a "SecurityError" DOMException. + if (exceptions_enabled) { + VERIFY(source_browsing_context.active_document()); + return DOM::SecurityError::create(source_browsing_context.active_document()->global_object(), "Source browsing context not allowed to navigate"sv); + } + + // FIXME: 2. Otherwise, the user agent may instead offer to open resource in a new top-level browsing context + // or in the top-level browsing context of the source browsing context, at the user's option, + // in which case the user agent must navigate that designated top-level browsing context + // to resource as if the user had requested it independently. + } + + // 4. If navigationId is null: + if (!navigation_id.has_value()) { + // 1. If historyHandling is "reload", and browsingContext's active document's navigation id is not null, + if (history_handling == HistoryHandlingBehavior::Reload && active_document()->navigation_id().has_value()) { + // let navigationId be browsingContext's active document's navigation id. + navigation_id = active_document()->navigation_id(); + } else { + // Otherwise let navigation id be the result of generating a random UUID. [UUID] + // FIXME: Generate a UUID. + navigation_id = "FIXME"; + } + } + + // FIXME: 5. If browsingContext's active document's unload counter is greater than 0, + // then invoke WebDriver BiDi navigation failed + // with a WebDriver BiDi navigation status whose id is navigationId, status is "canceled", and url is resource's url + // and return. + + // 6. If historyHandling is "default", and any of the following are true: + // - browsingContext is still on its initial about:blank Document + // - resource is a request whose URL equals browsingContext's active document's URL + // - resource is a request whose URL's scheme is "javascript" + if (history_handling == HistoryHandlingBehavior::Default + && (still_on_its_initial_about_blank_document() + || resource.url().equals(active_document()->url()) + || resource.url().scheme() == "javascript"sv)) { + // then set historyHandling to "replace". + history_handling = HistoryHandlingBehavior::Replace; + } + + // 7. If historyHandling is not "reload", resource is a request, + // resource's URL equals browsingContext's active document's URL with exclude fragments set to true, + // and resource's URL's fragment is non-null, then: + if (history_handling != HistoryHandlingBehavior::Reload + && resource.url().equals(active_document()->url(), AK::URL::ExcludeFragment::Yes) + && !resource.url().fragment().is_null()) { + // 1. Navigate to a fragment given browsingContext, resource's URL, historyHandling, and navigationId. + navigate_to_a_fragment(resource.url(), history_handling, *navigation_id); + + // 2. Return. + return {}; + } + + // FIXME: 8. Let incumbentNavigationOrigin be the origin of the incumbent settings object, + // or if no script was involved, the origin of the node document of the element that initiated the navigation. + + // FIXME: 9. Let initiatorPolicyContainer be a clone of the source browsing context's active document's policy container. + + // FIXME: 10. If resource is a request, then set resource's policy container to initiatorPolicyContainer. + + // FIXME: 11. Cancel any preexisting but not yet mature attempt to navigate browsingContext, + // including canceling any instances of the fetch algorithm started by those attempts. + // If one of those attempts has already created and initialized a new Document object, + // abort that Document also. + // (Navigation attempts that have matured already have session history entries, + // and are therefore handled during the update the session history with the new page algorithm, later.) + + // FIXME: 12. Let unloadPromptResult be the result of calling prompt to unload with the active document of browsingContext. + // If this instance of the navigation algorithm gets canceled while this step is running, + // the prompt to unload algorithm must nonetheless be run to completion. + + // FIXME: 13. If unloadPromptResult is "refuse", then return a new WebDriver BiDi navigation status whose id is navigationId and status is "canceled". + + // FIXME: 14. Abort the active document of browsingContext. + + // FIXME: 15. If browsingContext is a child browsing context, then put it in the delaying load events mode. + // The user agent must take this child browsing context out of the delaying load events mode when this navigation algorithm later matures, + // or when it terminates (whether due to having run all the steps, or being canceled, or being aborted), + // whichever happens first. + + // FIXME: 16. Let sandboxFlags be the result of determining the creation sandboxing flags given browsingContext and browsingContext's container. + + // FIXME: 17. Let allowedToDownload be the result of running the allowed to download algorithm given the source browsing context and browsingContext. + + // 18. Let hasTransientActivation be true if the source browsing context's active window has transient activation; otherwise false. + [[maybe_unused]] bool has_transient_activation = source_browsing_context.active_window()->has_transient_activation(); + + // FIXME: 19. Invoke WebDriver BiDi navigation started with browsingContext, and a new WebDriver BiDi navigation status whose id is navigationId, url is resource's url, and status is "pending". + + // 20. Return, and continue running these steps in parallel. + + // FIXME: Implement the rest of this algorithm + (void)history_policy_container; + (void)navigation_type; + (void)process_response_end_of_body; + + // AD-HOC: + loader().load(resource.url(), FrameLoader::Type::IFrame); + return {}; +} + +// https://html.spec.whatwg.org/multipage/browsing-the-web.html#navigate-fragid +DOM::ExceptionOr<void> BrowsingContext::navigate_to_a_fragment(AK::URL const& url, HistoryHandlingBehavior history_handling, String navigation_id) +{ + // 1. If historyHandling is not "replace", + if (history_handling != HistoryHandlingBehavior::Replace) { + // FIXME: then remove all the entries in browsingContext's session history after the current entry. + // (If the current entry is the last entry in the session history, then no entries are removed.) + } + + // 2. Remove any tasks queued by the history traversal task source that are associated with any Document objects + // in browsingContext's top-level browsing context's document family. + HTML::main_thread_event_loop().task_queue().remove_tasks_matching([&](HTML::Task const& task) { + return task.source() == Task::Source::HistoryTraversal + && task.document() + && top_level_browsing_context().document_family_contains(*task.document()); + }); + + // 3. Append a new session history entry to the session history whose URL is url, + // document is the current entry's document, + // policy container is the current entry's policy-container + // and scroll restoration mode is the current entry's scroll restoration mode. + m_session_history.append(SessionHistoryEntry { + .url = url, + .document = current_entry().document, + .serialized_state = {}, + .policy_container = current_entry().policy_container, + .scroll_restoration_mode = current_entry().scroll_restoration_mode, + .browsing_context_name = {}, + .original_source_browsing_context = {}, + }); + + // 4. Traverse the history to the new entry, with historyHandling set to historyHandling. + // This will scroll to the fragment given in what is now the document's URL. + TRY(traverse_the_history(m_session_history.size() - 1, history_handling)); + + // FIXME: 5. Invoke WebDriver BiDi fragment navigated with browsingContext, + // and a new WebDriver BiDi navigation status whose id is navigationId, url is resource's url, and status is "complete". + (void)navigation_id; + + return {}; +} + +// https://html.spec.whatwg.org/multipage/browsing-the-web.html#traverse-the-history +DOM::ExceptionOr<void> BrowsingContext::traverse_the_history(size_t entry_index, HistoryHandlingBehavior history_handling, bool explicit_history_navigation) +{ + auto* entry = &m_session_history[entry_index]; + + // 1. If entry's document is null, then: + if (!entry->document) { + // 1. Assert: historyHandling is "default". + VERIFY(history_handling == HistoryHandlingBehavior::Default); + + // 2. Let request be a new request whose URL is entry's URL. + auto request = Fetch::Infrastructure::Request(); + request.set_url(entry->url); + + // 3. If explicitHistoryNavigation is true, then set request's history-navigation flag. + if (explicit_history_navigation) + request.set_history_navigation(true); + + // 4. Navigate the browsing context to request with historyHandling set to "entry update" + // and with historyPolicyContainer set to entry's policy container. + // The navigation must be done using the same source browsing context as was used the first time entry was created. + VERIFY(entry->original_source_browsing_context); + TRY(navigate(request, *entry->original_source_browsing_context, false, HistoryHandlingBehavior::EntryUpdate, entry->policy_container)); + + // 5. Return. + return {}; + } + + // FIXME: 2. Save persisted state to the current entry. + + // 3. Let newDocument be entry's document. + JS::GCPtr<DOM::Document> new_document = entry->document.ptr(); + + // 4. Assert: newDocument's is initial about:blank is false, + // i.e., we never traverse back to the initial about:blank Document because it always gets replaced when we navigate away from it. + VERIFY(!new_document->is_initial_about_blank()); + + // 5. If newDocument is different than the current entry's document, or historyHandling is "entry update" or "reload", then: + if (new_document.ptr() != current_entry().document.ptr() + || history_handling == HistoryHandlingBehavior::EntryUpdate) { + // FIXME: 1. If newDocument's suspended timer handles is not empty: + // FIXME: 1. Assert: newDocument's suspension time is not zero. + // FIXME: 2. Let suspendDuration be the current high resolution time minus newDocument's suspension time. + // FIXME: 3. Let activeTimers be newDocument's relevant global object's map of active timers. + // FIXME: 4. For each handle in newDocument's suspended timer handles, if activeTimers[handle] exists, then increase activeTimers[handle] by suspendDuration. + } + + // 2. Remove any tasks queued by the history traversal task source + // that are associated with any Document objects in the top-level browsing context's document family. + HTML::main_thread_event_loop().task_queue().remove_tasks_matching([&](HTML::Task const& task) { + return task.source() == Task::Source::HistoryTraversal + && task.document() + && top_level_browsing_context().document_family_contains(*task.document()); + }); + + // 3. If newDocument's origin is not same origin with the current entry's document's origin, then: + if (!new_document->origin().is_same_origin(current_entry().document->origin())) { + // FIXME: 1. Let entriesToUpdate be all entries in the session history whose document's origin is same origin as the active document + // and that are contiguous with the current entry. + // FIXME: 2. For each entryToUpdate of entriesToUpdate, set entryToUpdate's browsing context name to the current browsing context name. + // FIXME: 3. If the browsing context is a top-level browsing context, but not an auxiliary browsing context whose disowned is false, then set the browsing context's name to the empty string. + } + + // 4. Set the active document of the browsing context to newDocument. + set_active_document(new_document); + + // 5. If entry's browsing context name is not null, then: + if (entry->browsing_context_name.has_value()) { + // 1. Set the browsing context's name to entry's browsing context name. + m_name = *entry->browsing_context_name; + + // FIXME: 2. Let entriesToUpdate be all entries in the session history whose document's origin is same origin as the new active document's origin and that are contiguous with entry. + // FIXME: 3. For each entryToUpdate of entriesToUpdate, set entryToUpdate's browsing context name to null. + } + + // FIXME: 6. If newDocument has any form controls whose autofill field name is "off", invoke the reset algorithm of each of those elements. + + // 7. If newDocument's current document readiness "complete", + if (new_document->ready_state() == "complete"sv) { + // then queue a global task on the DOM manipulation task source given newDocument's relevant global object to run the following steps: + + queue_global_task(Task::Source::DOMManipulation, relevant_global_object(*new_document), [new_document = JS::make_handle(*new_document)]() mutable { + // 1. If newDocument's page showing flag is true, then abort these steps. + if (new_document->page_showing()) + return; + + // 2. Set newDocument's page showing flag to true. + new_document->set_page_showing(true); + + // 3. Update the visibility state of newDocument to "hidden". + new_document->update_the_visibility_state("hidden"); + + // 4. Fire a page transition event named pageshow at newDocument's relevant global object with true. + auto& window = verify_cast<HTML::Window>(relevant_global_object(*new_document)); + window.fire_a_page_transition_event(HTML::EventNames::pageshow, true); + }); + } + + // 6. Set newDocument's URL to entry's URL. + new_document->set_url(entry->url); + + // 7. Let hashChanged be false, and let oldURL and newURL be null. + bool hash_changed = false; + Optional<AK::URL> old_url; + Optional<AK::URL> new_url; + + // 8. If entry's URL's fragment is not identical to the current entry's URL's fragment, + // and entry's document equals the current entry's document, + if (entry->url.fragment() != current_entry().url.fragment() + && entry->document.ptr() == current_entry().document.ptr()) { + // then set hashChanged to true, set oldURL to the current entry's URL, and set newURL to entry's URL. + hash_changed = true; + old_url = current_entry().url; + new_url = entry->url; + } + + // 9. If historyHandling is "replace", then remove the entry immediately before entry in the session history. + if (history_handling == HistoryHandlingBehavior::Replace) { + // FIXME: This is gnarly. + m_session_history.remove(entry_index - 1); + entry_index--; + entry = &m_session_history[entry_index]; + } + + // 10. If entry's persisted user state is null, and its URL's fragment is non-null, then scroll to the fragment. + if (!entry->url.fragment().is_null()) { + // FIXME: Implement the full "scroll to the fragment" algorithm: + // https://html.spec.whatwg.org/multipage/browsing-the-web.html#scroll-to-the-fragment-identifier + scroll_to_anchor(entry->url.fragment()); + } + + // 11. Set the current entry to entry. + m_session_history_index = entry_index; + + // 12. Let targetRealm be the current Realm Record. + auto* target_realm = Bindings::main_thread_vm().current_realm(); + VERIFY(target_realm); + + // FIXME: 13. Let state be null. + // FIXME: 14. If entry's serialized state is not null, then set state to StructuredDeserialize(entry's serialized state, targetRealm). + // If this throws an exception, catch it and ignore the exception. + // FIXME: 15. Set newDocument's History object's state to state. + // FIXME: 16. Let stateChanged be true if newDocument has a latest entry, and that entry is not entry; otherwise let it be false. + // FIXME: 17. Set newDocument's latest entry to entry. + // FIXME: 18. If stateChanged is true, then fire an event named popstate at newDocument's relevant global object, using PopStateEvent, with the state attribute initialized to state. + // FIXME: 19. Restore persisted state from entry. + + // 20. If hashChanged is true, + if (hash_changed) { + // then queue a global task on the DOM manipulation task source given newDocument's relevant global object + queue_global_task(Task::Source::DOMManipulation, relevant_global_object(*new_document), [new_document = JS::make_handle(*new_document)]() mutable { + // to fire an event named hashchange at newDocument's relevant global object, + // using HashChangeEvent, with the oldURL attribute initialized to oldURL + // and the newURL attribute initialized to newURL. + + // FIXME: Implement a proper HashChangeEvent class. + auto event = DOM::Event::create(verify_cast<HTML::Window>(relevant_global_object(*new_document)), HTML::EventNames::hashchange); + new_document->dispatch_event(event); + }); + } + + return {}; +} + +// https://html.spec.whatwg.org/multipage/browsers.html#allowed-to-navigate +bool BrowsingContext::is_allowed_to_navigate(BrowsingContext const& other) const +{ + VERIFY(active_window()); + VERIFY(active_document()); + + // 1. If A is not the same browsing context as B, + // and A is not one of the ancestor browsing contexts of B, + // and B is not a top-level browsing context, + // FIXME: and A's active document's active sandboxing flag set has its sandboxed navigation browsing context flag set, + // then return false. + if (this != &other + && !this->is_ancestor_of(other) + && !other.is_top_level()) { + return false; + } + + // 2. Otherwise, if B is a top-level browsing context, and is one of the ancestor browsing contexts of A, then: + if (other.is_top_level() && other.is_ancestor_of(*this)) { + // 1. If A's active window has transient activation + // and A's active document's active sandboxing flag set has its sandboxed top-level navigation with user activation browsing context flag set, + // then return false. + if (active_window()->has_transient_activation() + && active_document()->active_sandboxing_flag_set().flags & SandboxingFlagSet::SandboxedTopLevelNavigationWithUserActivation) { + return false; + } + + // 2. Otherwise, if A's active window does not have transient activation + // and A's active document's active sandboxing flag set has its sandboxed top-level navigation without user activation browsing context flag set, + // then return false. + if (!active_window()->has_transient_activation() + && active_document()->active_sandboxing_flag_set().flags & SandboxingFlagSet::SandboxedTopLevelNavigationWithoutUserActivation) { + return false; + } + } + + // 3. Otherwise, if B is a top-level browsing context, + // and is neither A nor one of the ancestor browsing contexts of A, + // and A's Document's active sandboxing flag set has its sandboxed navigation browsing context flag set, + // and A is not the one permitted sandboxed navigator of B, + // then return false. + if (other.is_top_level() + && &other != this + && !other.is_ancestor_of(*this) + && active_document()->active_sandboxing_flag_set().flags & SandboxingFlagSet::SandboxedNavigation + && this != other.the_one_permitted_sandboxed_navigator()) { + return false; + } + + // 4. Return true. + return true; +} + +// https://html.spec.whatwg.org/multipage/origin.html#one-permitted-sandboxed-navigator +BrowsingContext const* BrowsingContext::the_one_permitted_sandboxed_navigator() const +{ + // FIXME: Implement this. + return nullptr; +} + +// https://html.spec.whatwg.org/multipage/browsers.html#document-family +bool BrowsingContext::document_family_contains(DOM::Document const& document) const +{ + HashTable<DOM::Document const*> family; + + for (auto& entry : m_session_history) { + if (!entry.document) + continue; + if (family.set(entry.document) == AK::HashSetResult::ReplacedExistingEntry) + continue; + // FIXME: The document family of a Document object consists of the union of all the document families of the browsing contexts in the list of the descendant browsing contexts of the Document object. + } + + return family.contains(&document); +} } diff --git a/Userland/Libraries/LibWeb/HTML/BrowsingContext.h b/Userland/Libraries/LibWeb/HTML/BrowsingContext.h index c2c6e5c88e..ac841455b2 100644 --- a/Userland/Libraries/LibWeb/HTML/BrowsingContext.h +++ b/Userland/Libraries/LibWeb/HTML/BrowsingContext.h @@ -15,6 +15,7 @@ #include <LibGfx/Size.h> #include <LibWeb/DOM/Position.h> #include <LibWeb/HTML/BrowsingContextContainer.h> +#include <LibWeb/HTML/HistoryHandlingBehavior.h> #include <LibWeb/HTML/Origin.h> #include <LibWeb/HTML/SessionHistoryEntry.h> #include <LibWeb/Loader/FrameLoader.h> @@ -47,6 +48,9 @@ public: void set_active_document(DOM::Document*); + HTML::Window* active_window(); + HTML::Window const* active_window() const; + Page* page() { return m_page; } Page const* page() const { return m_page; } @@ -131,6 +135,31 @@ public: // https://html.spec.whatwg.org/multipage/browsers.html#bcg-remove void remove(); + // https://html.spec.whatwg.org/multipage/browsers.html#allowed-to-navigate + bool is_allowed_to_navigate(BrowsingContext const&) const; + + // https://html.spec.whatwg.org/multipage/browsing-the-web.html#navigate + DOM::ExceptionOr<void> navigate( + Fetch::Infrastructure::Request resource, + BrowsingContext& source_browsing_context, + bool exceptions_enabled = false, + HistoryHandlingBehavior history_handling = HistoryHandlingBehavior::Default, + Optional<PolicyContainer> history_policy_container = {}, + String navigation_type = "other", + Optional<String> navigation_id = {}, + Function<void(NonnullOwnPtr<Fetch::Infrastructure::Response>)> process_response_end_of_body = {}); + + // https://html.spec.whatwg.org/multipage/browsing-the-web.html#navigate-fragid + DOM::ExceptionOr<void> navigate_to_a_fragment(AK::URL const&, HistoryHandlingBehavior, String navigation_id); + + // https://html.spec.whatwg.org/multipage/origin.html#one-permitted-sandboxed-navigator + BrowsingContext const* the_one_permitted_sandboxed_navigator() const; + + // https://html.spec.whatwg.org/multipage/browsing-the-web.html#traverse-the-history + DOM::ExceptionOr<void> traverse_the_history(size_t entry_index, HistoryHandlingBehavior = HistoryHandlingBehavior::Default, bool explicit_history_navigation = false); + + bool document_family_contains(DOM::Document const&) const; + private: explicit BrowsingContext(Page&, HTML::BrowsingContextContainer*); @@ -143,6 +172,11 @@ private: FrameLoader m_loader; Web::EventHandler m_event_handler; + // https://html.spec.whatwg.org/multipage/history.html#current-entry + SessionHistoryEntry& current_entry() { return m_session_history[*m_session_history_index]; } + SessionHistoryEntry const& current_entry() const { return m_session_history[*m_session_history_index]; } + Optional<size_t> m_session_history_index { 0 }; + // https://html.spec.whatwg.org/multipage/history.html#session-history Vector<SessionHistoryEntry> m_session_history; diff --git a/Userland/Libraries/LibWeb/HTML/BrowsingContextContainer.cpp b/Userland/Libraries/LibWeb/HTML/BrowsingContextContainer.cpp index dec0c33b80..52ad2f8abf 100644 --- a/Userland/Libraries/LibWeb/HTML/BrowsingContextContainer.cpp +++ b/Userland/Libraries/LibWeb/HTML/BrowsingContextContainer.cpp @@ -213,14 +213,13 @@ void BrowsingContextContainer::navigate_an_iframe_or_frame(Fetch::Infrastructure // given element's node document's relevant global object // to finalize and report timing given response, element's node document's relevant global object, and element's local name. - // FIXME: 4. Navigate element's nested browsing context to resource, - // with historyHandling set to historyHandling, - // the source browsing context set to element's node document's browsing context, - // and processResponseEndOfBody set to reportFrameTiming. - (void)history_handling; - - // AD-HOC: - m_nested_browsing_context->loader().load(resource.url(), FrameLoader::Type::IFrame); + // 4. Navigate element's nested browsing context to resource, + // with historyHandling set to historyHandling, + // the source browsing context set to element's node document's browsing context, + // FIXME: and processResponseEndOfBody set to reportFrameTiming. + auto* source_browsing_context = document().browsing_context(); + VERIFY(source_browsing_context); + m_nested_browsing_context->navigate(move(resource), *source_browsing_context, false, history_handling); } } diff --git a/Userland/Libraries/LibWeb/HTML/EventLoop/TaskQueue.cpp b/Userland/Libraries/LibWeb/HTML/EventLoop/TaskQueue.cpp index 2fe4681d8c..1431b73952 100644 --- a/Userland/Libraries/LibWeb/HTML/EventLoop/TaskQueue.cpp +++ b/Userland/Libraries/LibWeb/HTML/EventLoop/TaskQueue.cpp @@ -40,4 +40,11 @@ bool TaskQueue::has_runnable_tasks() const return false; } +void TaskQueue::remove_tasks_matching(Function<bool(HTML::Task const&)> filter) +{ + m_tasks.remove_all_matching([&](auto& task) { + return filter(*task); + }); +} + } diff --git a/Userland/Libraries/LibWeb/HTML/EventLoop/TaskQueue.h b/Userland/Libraries/LibWeb/HTML/EventLoop/TaskQueue.h index cfc2a15254..f3e31c4fac 100644 --- a/Userland/Libraries/LibWeb/HTML/EventLoop/TaskQueue.h +++ b/Userland/Libraries/LibWeb/HTML/EventLoop/TaskQueue.h @@ -31,6 +31,8 @@ public: return m_tasks.take_first(); } + void remove_tasks_matching(Function<bool(HTML::Task const&)>); + private: HTML::EventLoop& m_event_loop; diff --git a/Userland/Libraries/LibWeb/HTML/SessionHistoryEntry.h b/Userland/Libraries/LibWeb/HTML/SessionHistoryEntry.h index a43b5db176..1ef72d1e71 100644 --- a/Userland/Libraries/LibWeb/HTML/SessionHistoryEntry.h +++ b/Userland/Libraries/LibWeb/HTML/SessionHistoryEntry.h @@ -48,6 +48,8 @@ struct SessionHistoryEntry { // FIXME: persisted user state, which is implementation-defined, initially null // NOTE: This is where we could remember the state of form controls, for example. + + WeakPtr<BrowsingContext> original_source_browsing_context; }; } diff --git a/Userland/Libraries/LibWeb/HTML/Window.cpp b/Userland/Libraries/LibWeb/HTML/Window.cpp index 5cd97faf81..5235112692 100644 --- a/Userland/Libraries/LibWeb/HTML/Window.cpp +++ b/Userland/Libraries/LibWeb/HTML/Window.cpp @@ -629,6 +629,13 @@ void Window::set_name(String const& name) browsing_context()->set_name(name); } +// https://html.spec.whatwg.org/multipage/interaction.html#transient-activation +bool Window::has_transient_activation() const +{ + // FIXME: Implement this. + return false; +} + // https://w3c.github.io/requestidlecallback/#start-an-idle-period-algorithm void Window::start_an_idle_period() { diff --git a/Userland/Libraries/LibWeb/HTML/Window.h b/Userland/Libraries/LibWeb/HTML/Window.h index 5ce1989480..31f0f89206 100644 --- a/Userland/Libraries/LibWeb/HTML/Window.h +++ b/Userland/Libraries/LibWeb/HTML/Window.h @@ -120,6 +120,9 @@ public: AnimationFrameCallbackDriver& animation_frame_callback_driver() { return m_animation_frame_callback_driver; } + // https://html.spec.whatwg.org/multipage/interaction.html#transient-activation + bool has_transient_activation() const; + private: explicit Window(JS::Realm&); virtual void initialize(JS::Realm&) override; |