From adb5c273315243e9196ba6c972885b2aa66e1af9 Mon Sep 17 00:00:00 2001 From: Andrew Kaster Date: Tue, 30 Jan 2024 20:55:24 -0700 Subject: [PATCH] LibWeb: Create a new WebView for window.open()'d top level traversables --- Userland/Libraries/LibWeb/HTML/Navigable.cpp | 20 +++++++++++++++---- .../LibWeb/HTML/TraversableNavigable.h | 5 +++++ Userland/Libraries/LibWeb/Page/Page.h | 7 ++++++- Userland/Services/WebContent/PageClient.cpp | 17 +++++++++++++--- Userland/Services/WebContent/PageClient.h | 2 +- 5 files changed, 42 insertions(+), 9 deletions(-) diff --git a/Userland/Libraries/LibWeb/HTML/Navigable.cpp b/Userland/Libraries/LibWeb/HTML/Navigable.cpp index 6671d5c92b..e9465a5e33 100644 --- a/Userland/Libraries/LibWeb/HTML/Navigable.cpp +++ b/Userland/Libraries/LibWeb/HTML/Navigable.cpp @@ -412,17 +412,29 @@ Navigable::ChosenNavigable Navigable::choose_a_navigable(StringView name, Tokeni if (!Infra::is_ascii_case_insensitive_match(name, "_blank"sv)) target_name = MUST(String::from_utf8(name)); + auto create_new_traversable_closure = [this, window_type, no_opener, target_name](JS::GCPtr opener) -> JS::NonnullGCPtr { + // FIXME: The popup state for window.open is calculated after this call (somehow?) + // Probably want to deviate from the spec and pass the popup state in here + auto hints = WebViewHints { + .popup = window_type != WindowType::ExistingOrNone, + }; + auto [page, window_handle] = traversable_navigable()->page().client().page_did_request_new_web_view(ActivateTab::Yes, hints, no_opener); + auto traversable = TraversableNavigable::create_a_new_top_level_traversable(*page, opener, target_name).release_value_but_fixme_should_propagate_errors(); + page->set_top_level_traversable(traversable); + traversable->set_window_handle(window_handle); + return traversable; + }; + auto create_new_traversable = JS::create_heap_function(heap(), move(create_new_traversable_closure)); + // 7. If noopener is true, then set chosen to the result of creating a new top-level traversable given null and targetName. if (no_opener == TokenizedFeature::NoOpener::Yes) { - // FIXME: This should do something similar to RemoteBrowsingContext -- but RemoteTraversableNavigable instead - TODO(); + chosen = create_new_traversable->function()(nullptr); } // 8. Otherwise: else { // 1. Set chosen to the result of creating a new top-level traversable given currentNavigable's active browsing context and targetName. - // FIXME: Make this method return WebIDL::ExceptionOr - chosen = TraversableNavigable::create_a_new_top_level_traversable(traversable_navigable()->page(), active_browsing_context(), target_name).release_value_but_fixme_should_propagate_errors(); + chosen = create_new_traversable->function()(active_browsing_context()); // FIXME: 2. If sandboxingFlagSet's sandboxed navigation browsing context flag is set, // then set chosen's active browsing context's one permitted sandboxed navigator to currentNavigable's active browsing context. diff --git a/Userland/Libraries/LibWeb/HTML/TraversableNavigable.h b/Userland/Libraries/LibWeb/HTML/TraversableNavigable.h index 72cc56171a..e252f9b6e3 100644 --- a/Userland/Libraries/LibWeb/HTML/TraversableNavigable.h +++ b/Userland/Libraries/LibWeb/HTML/TraversableNavigable.h @@ -82,6 +82,9 @@ public: Page& page() { return m_page; } Page const& page() const { return m_page; } + String window_handle() const { return m_window_handle; } + void set_window_handle(String window_handle) { m_window_handle = move(window_handle); } + private: TraversableNavigable(JS::NonnullGCPtr); @@ -114,6 +117,8 @@ private: SessionHistoryTraversalQueue m_session_history_traversal_queue; JS::NonnullGCPtr m_page; + + String m_window_handle; }; struct BrowsingContextAndDocument { diff --git a/Userland/Libraries/LibWeb/Page/Page.h b/Userland/Libraries/LibWeb/Page/Page.h index d44fa05841..9d7fda1093 100644 --- a/Userland/Libraries/LibWeb/Page/Page.h +++ b/Userland/Libraries/LibWeb/Page/Page.h @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -269,7 +270,11 @@ public: virtual void page_did_set_cookie(const AK::URL&, Cookie::ParsedCookie const&, Cookie::Source) { } virtual void page_did_update_cookie(Web::Cookie::Cookie) { } virtual void page_did_update_resource_count(i32) { } - virtual String page_did_request_new_web_view(HTML::ActivateTab, HTML::WebViewHints, Optional = {}) { return {}; } + struct NewWebViewResult { + JS::GCPtr page; + String window_handle; + }; + virtual NewWebViewResult page_did_request_new_web_view(HTML::ActivateTab, HTML::WebViewHints, HTML::TokenizedFeature::NoOpener) { return {}; } virtual void page_did_request_activate_tab() { } virtual void page_did_close_browsing_context(HTML::BrowsingContext const&) { } diff --git a/Userland/Services/WebContent/PageClient.cpp b/Userland/Services/WebContent/PageClient.cpp index 0f43068320..8b7c1db04a 100644 --- a/Userland/Services/WebContent/PageClient.cpp +++ b/Userland/Services/WebContent/PageClient.cpp @@ -497,14 +497,25 @@ void PageClient::page_did_update_resource_count(i32 count_waiting) client().async_did_update_resource_count(count_waiting); } -String PageClient::page_did_request_new_web_view(Web::HTML::ActivateTab activate_tab, Web::HTML::WebViewHints hints, Optional page_index) +PageClient::NewWebViewResult PageClient::page_did_request_new_web_view(Web::HTML::ActivateTab activate_tab, Web::HTML::WebViewHints hints, Web::HTML::TokenizedFeature::NoOpener no_opener) { - auto response = client().send_sync_but_allow_failure(activate_tab, hints, page_index); + auto& new_client = m_owner.create_page(); + + Optional page_id; + if (no_opener == Web::HTML::TokenizedFeature::NoOpener::Yes) { + // FIXME: Create an abstraction to let this WebContent process know about a new process we create? + // FIXME: For now, just create a new page in the same process anyway + } + + page_id = new_client.m_id; + + auto response = client().send_sync_but_allow_failure(activate_tab, hints, page_id); if (!response) { dbgln("WebContent client disconnected during DidRequestNewWebView. Exiting peacefully."); exit(0); } - return response->take_handle(); + + return { &new_client.page(), response->take_handle() }; } void PageClient::page_did_request_activate_tab() diff --git a/Userland/Services/WebContent/PageClient.h b/Userland/Services/WebContent/PageClient.h index 8558c3b17f..ca1ef4ad6c 100644 --- a/Userland/Services/WebContent/PageClient.h +++ b/Userland/Services/WebContent/PageClient.h @@ -118,7 +118,7 @@ private: virtual void page_did_set_cookie(const URL&, Web::Cookie::ParsedCookie const&, Web::Cookie::Source) override; virtual void page_did_update_cookie(Web::Cookie::Cookie) override; virtual void page_did_update_resource_count(i32) override; - virtual String page_did_request_new_web_view(Web::HTML::ActivateTab, Web::HTML::WebViewHints, Optional page_index = {}) override; + virtual NewWebViewResult page_did_request_new_web_view(Web::HTML::ActivateTab, Web::HTML::WebViewHints, Web::HTML::TokenizedFeature::NoOpener) override; virtual void page_did_request_activate_tab() override; virtual void page_did_close_browsing_context(Web::HTML::BrowsingContext const&) override; virtual void request_file(Web::FileRequest) override;