diff --git a/Ladybird/AppKit/UI/LadybirdWebView.mm b/Ladybird/AppKit/UI/LadybirdWebView.mm index e4d775f181..de3bb103eb 100644 --- a/Ladybird/AppKit/UI/LadybirdWebView.mm +++ b/Ladybird/AppKit/UI/LadybirdWebView.mm @@ -250,7 +250,8 @@ static void copy_data_to_clipboard(StringView data, NSPasteboardType pasteboard_ [self setNeedsDisplay:YES]; }; - m_web_view_bridge->on_new_tab = [self](auto activate_tab) { + m_web_view_bridge->on_new_web_view = [self](auto activate_tab, auto, auto) { + // FIXME: Create a child tab that re-uses the ConnectionFromClient of the parent tab return [self.observer onCreateNewTab:"about:blank"sv activateTab:activate_tab]; }; diff --git a/Ladybird/Qt/BrowserWindow.cpp b/Ladybird/Qt/BrowserWindow.cpp index 1a387cde31..badbc34642 100644 --- a/Ladybird/Qt/BrowserWindow.cpp +++ b/Ladybird/Qt/BrowserWindow.cpp @@ -483,6 +483,31 @@ Tab& BrowserWindow::new_tab_from_content(StringView html, Web::HTML::ActivateTab return tab; } +Tab& BrowserWindow::new_child_tab(Web::HTML::ActivateTab activate_tab, Tab& parent, Web::HTML::WebViewHints hints, Optional page_index) +{ + return create_new_tab(activate_tab, parent, hints, page_index); +} + +Tab& BrowserWindow::create_new_tab(Web::HTML::ActivateTab activate_tab, Tab& parent, Web::HTML::WebViewHints, Optional page_index) +{ + if (!page_index.has_value()) + return create_new_tab(activate_tab); + + // FIXME: Respect hints for: + // popup: Create new window + // width, height: size of window + // screen_x, screen_y: positioning of window on the screen + auto* tab = new Tab(this, m_web_content_options, m_webdriver_content_ipc_path, parent.view().client(), page_index.value()); + + VERIFY(m_current_tab != nullptr); + + m_tabs_container->addTab(tab, "New Tab"); + if (activate_tab == Web::HTML::ActivateTab::Yes) + m_tabs_container->setCurrentWidget(tab); + initialize_tab(tab); + return *tab; +} + Tab& BrowserWindow::create_new_tab(Web::HTML::ActivateTab activate_tab) { auto* tab = new Tab(this, m_web_content_options, m_webdriver_content_ipc_path); @@ -494,6 +519,13 @@ Tab& BrowserWindow::create_new_tab(Web::HTML::ActivateTab activate_tab) m_tabs_container->addTab(tab, "New Tab"); if (activate_tab == Web::HTML::ActivateTab::Yes) m_tabs_container->setCurrentWidget(tab); + initialize_tab(tab); + + return *tab; +} + +void BrowserWindow::initialize_tab(Tab* tab) +{ QObject::connect(tab, &Tab::title_changed, this, &BrowserWindow::tab_title_changed); QObject::connect(tab, &Tab::favicon_changed, this, &BrowserWindow::tab_favicon_changed); @@ -506,9 +538,9 @@ Tab& BrowserWindow::create_new_tab(Web::HTML::ActivateTab activate_tab) new_tab_from_url(ak_url_from_qurl(urls[i]), Web::HTML::ActivateTab::No); }); - tab->view().on_new_tab = [this](auto activate_tab) { - auto& tab = new_tab_from_url("about:blank"sv, activate_tab); - return tab.view().handle(); + tab->view().on_new_web_view = [this, tab](auto activate_tab, Web::HTML::WebViewHints hints, Optional page_index) { + auto& new_tab = new_child_tab(activate_tab, *tab, hints, page_index); + return new_tab.view().handle(); }; tab->view().on_tab_open_request = [this](auto url, auto activate_tab) { @@ -553,7 +585,6 @@ Tab& BrowserWindow::create_new_tab(Web::HTML::ActivateTab activate_tab) }; tab->focus_location_editor(); - return *tab; } void BrowserWindow::activate_tab(int index) diff --git a/Ladybird/Qt/BrowserWindow.h b/Ladybird/Qt/BrowserWindow.h index 144d931f06..0bd6d79954 100644 --- a/Ladybird/Qt/BrowserWindow.h +++ b/Ladybird/Qt/BrowserWindow.h @@ -75,6 +75,7 @@ public slots: void tab_favicon_changed(int index, QIcon const& icon); Tab& new_tab_from_url(AK::URL const&, Web::HTML::ActivateTab); Tab& new_tab_from_content(StringView html, Web::HTML::ActivateTab); + Tab& new_child_tab(Web::HTML::ActivateTab, Tab& parent, Web::HTML::WebViewHints, Optional page_index); void activate_tab(int index); void close_tab(int index); void close_current_tab(); @@ -101,6 +102,8 @@ private: virtual void closeEvent(QCloseEvent*) override; Tab& create_new_tab(Web::HTML::ActivateTab activate_tab); + Tab& create_new_tab(Web::HTML::ActivateTab, Tab& parent, Web::HTML::WebViewHints, Optional page_index); + void initialize_tab(Tab*); void debug_request(ByteString const& request, ByteString const& argument = ""); diff --git a/Ladybird/Qt/WebContentView.h b/Ladybird/Qt/WebContentView.h index 28022ea334..1bfe1c61f5 100644 --- a/Ladybird/Qt/WebContentView.h +++ b/Ladybird/Qt/WebContentView.h @@ -77,6 +77,8 @@ public: }; void update_palette(PaletteMode = PaletteMode::Default); + using ViewImplementation::client; + signals: void urls_dropped(QList const&); diff --git a/Meta/gn/secondary/Userland/Libraries/LibWeb/HTML/BUILD.gn b/Meta/gn/secondary/Userland/Libraries/LibWeb/HTML/BUILD.gn index aa305a4e83..057aaf0a67 100644 --- a/Meta/gn/secondary/Userland/Libraries/LibWeb/HTML/BUILD.gn +++ b/Meta/gn/secondary/Userland/Libraries/LibWeb/HTML/BUILD.gn @@ -157,6 +157,7 @@ source_set("HTML") { "TraversableNavigable.cpp", "VideoTrack.cpp", "VideoTrackList.cpp", + "WebViewHints.cpp", "Window.cpp", "WindowEventHandlers.cpp", "WindowOrWorkerGlobalScope.cpp", diff --git a/Userland/Applications/Browser/Tab.cpp b/Userland/Applications/Browser/Tab.cpp index 6e888d240e..66abd33ec2 100644 --- a/Userland/Applications/Browser/Tab.cpp +++ b/Userland/Applications/Browser/Tab.cpp @@ -593,7 +593,8 @@ Tab::Tab(BrowserWindow& window) update_status(); }; - view().on_new_tab = [this](auto activate_tab) { + view().on_new_web_view = [this](auto activate_tab, auto, auto) { + // FIXME: Create a child tab that re-uses the ConnectionFromClient of the parent tab auto& tab = this->window().create_new_tab(URL("about:blank"), activate_tab); return tab.view().handle(); }; diff --git a/Userland/Libraries/LibWeb/CMakeLists.txt b/Userland/Libraries/LibWeb/CMakeLists.txt index 039941e81d..6b39de94d5 100644 --- a/Userland/Libraries/LibWeb/CMakeLists.txt +++ b/Userland/Libraries/LibWeb/CMakeLists.txt @@ -402,6 +402,7 @@ set(SOURCES HTML/TraversableNavigable.cpp HTML/VideoTrack.cpp HTML/VideoTrackList.cpp + HTML/WebViewHints.cpp HTML/Window.cpp HTML/WindowEventHandlers.cpp HTML/WindowOrWorkerGlobalScope.cpp diff --git a/Userland/Libraries/LibWeb/HTML/BrowsingContext.cpp b/Userland/Libraries/LibWeb/HTML/BrowsingContext.cpp index f75c557671..76741dc9cb 100644 --- a/Userland/Libraries/LibWeb/HTML/BrowsingContext.cpp +++ b/Userland/Libraries/LibWeb/HTML/BrowsingContext.cpp @@ -499,7 +499,7 @@ JS::GCPtr BrowsingContext::currently_focused_area() } // https://html.spec.whatwg.org/#the-rules-for-choosing-a-browsing-context-given-a-browsing-context-name -BrowsingContext::ChosenBrowsingContext BrowsingContext::choose_a_browsing_context(StringView name, TokenizedFeature::NoOpener no_opener, ActivateTab activate_tab) +BrowsingContext::ChosenBrowsingContext BrowsingContext::choose_a_browsing_context(StringView name, TokenizedFeature::NoOpener no_opener, ActivateTab) { // The rules for choosing a browsing context, given a browsing context name name, a browsing context current, and // a boolean noopener are as follows: @@ -591,8 +591,8 @@ BrowsingContext::ChosenBrowsingContext BrowsingContext::choose_a_browsing_contex // 3. If noopener is true, then set chosen to the result of creating a new top-level browsing context. if (no_opener == TokenizedFeature::NoOpener::Yes) { - auto handle = m_page->client().page_did_request_new_tab(activate_tab); - chosen = RemoteBrowsingContext::create_a_new_remote_browsing_context(handle); + // FIXME: This is completely wrong, but all of this should be removed in favor of choose_a_navigable + chosen = this; } // 4. Otherwise: diff --git a/Userland/Libraries/LibWeb/HTML/WebViewHints.cpp b/Userland/Libraries/LibWeb/HTML/WebViewHints.cpp new file mode 100644 index 0000000000..9d699bda0c --- /dev/null +++ b/Userland/Libraries/LibWeb/HTML/WebViewHints.cpp @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2024, Andrew Kaster + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include + +namespace IPC { + +template<> +ErrorOr encode(Encoder& encoder, ::Web::HTML::WebViewHints const& data_holder) +{ + TRY(encoder.encode(data_holder.popup)); + TRY(encoder.encode(data_holder.width)); + TRY(encoder.encode(data_holder.height)); + TRY(encoder.encode(data_holder.screen_x)); + TRY(encoder.encode(data_holder.screen_y)); + + return {}; +} + +template<> +ErrorOr<::Web::HTML::WebViewHints> decode(Decoder& decoder) +{ + auto popup = TRY(decoder.decode()); + auto width = TRY(decoder.decode>()); + auto height = TRY(decoder.decode>()); + auto screen_x = TRY(decoder.decode>()); + auto screen_y = TRY(decoder.decode>()); + + return ::Web::HTML::WebViewHints { + .popup = popup, + .width = width, + .height = height, + .screen_x = screen_x, + .screen_y = screen_y, + }; +} + +} diff --git a/Userland/Libraries/LibWeb/HTML/WebViewHints.h b/Userland/Libraries/LibWeb/HTML/WebViewHints.h new file mode 100644 index 0000000000..e9aa702c3e --- /dev/null +++ b/Userland/Libraries/LibWeb/HTML/WebViewHints.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2024, Andrew Kaster + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include +#include +#include + +namespace Web::HTML { + +struct WebViewHints { + bool popup = false; + Optional width = {}; + Optional height = {}; + Optional screen_x = {}; + Optional screen_y = {}; +}; + +} + +namespace IPC { + +template<> +ErrorOr encode(Encoder&, Web::HTML::WebViewHints const&); + +template<> +ErrorOr decode(Decoder&); + +} diff --git a/Userland/Libraries/LibWeb/Page/Page.h b/Userland/Libraries/LibWeb/Page/Page.h index d08575c207..d44fa05841 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 @@ -268,7 +269,7 @@ 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_tab(HTML::ActivateTab) { return {}; } + virtual String page_did_request_new_web_view(HTML::ActivateTab, HTML::WebViewHints, Optional = {}) { return {}; } virtual void page_did_request_activate_tab() { } virtual void page_did_close_browsing_context(HTML::BrowsingContext const&) { } diff --git a/Userland/Libraries/LibWebView/ViewImplementation.h b/Userland/Libraries/LibWebView/ViewImplementation.h index 005911a954..486da5a9f6 100644 --- a/Userland/Libraries/LibWebView/ViewImplementation.h +++ b/Userland/Libraries/LibWebView/ViewImplementation.h @@ -112,7 +112,7 @@ public: Function on_did_layout; Function on_ready_to_paint; - Function on_new_tab; + Function)> on_new_web_view; Function on_activate_tab; Function on_close; Function on_context_menu_request; diff --git a/Userland/Libraries/LibWebView/WebContentClient.cpp b/Userland/Libraries/LibWebView/WebContentClient.cpp index cad693acc6..41a1ef71cd 100644 --- a/Userland/Libraries/LibWebView/WebContentClient.cpp +++ b/Userland/Libraries/LibWebView/WebContentClient.cpp @@ -328,10 +328,10 @@ void WebContentClient::did_update_cookie(Web::Cookie::Cookie const& cookie) m_view.on_update_cookie(cookie); } -Messages::WebContentClient::DidRequestNewTabResponse WebContentClient::did_request_new_tab(Web::HTML::ActivateTab const& activate_tab) +Messages::WebContentClient::DidRequestNewWebViewResponse WebContentClient::did_request_new_web_view(Web::HTML::ActivateTab const& activate_tab, Web::HTML::WebViewHints const& hints, Optional const& page_index) { - if (m_view.on_new_tab) - return m_view.on_new_tab(activate_tab); + if (m_view.on_new_web_view) + return m_view.on_new_web_view(activate_tab, hints, page_index); return String {}; } diff --git a/Userland/Libraries/LibWebView/WebContentClient.h b/Userland/Libraries/LibWebView/WebContentClient.h index 891fd99e26..121a6501d7 100644 --- a/Userland/Libraries/LibWebView/WebContentClient.h +++ b/Userland/Libraries/LibWebView/WebContentClient.h @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -73,7 +74,7 @@ private: virtual Messages::WebContentClient::DidRequestCookieResponse did_request_cookie(AK::URL const&, Web::Cookie::Source) override; virtual void did_set_cookie(AK::URL const&, Web::Cookie::ParsedCookie const&, Web::Cookie::Source) override; virtual void did_update_cookie(Web::Cookie::Cookie const&) override; - virtual Messages::WebContentClient::DidRequestNewTabResponse did_request_new_tab(Web::HTML::ActivateTab const& activate_tab) override; + virtual Messages::WebContentClient::DidRequestNewWebViewResponse did_request_new_web_view(Web::HTML::ActivateTab const&, Web::HTML::WebViewHints const&, Optional const& page_index) override; virtual void did_request_activate_tab() override; virtual void did_close_browsing_context() override; virtual void did_update_resource_count(i32 count_waiting) override; diff --git a/Userland/Services/WebContent/PageClient.cpp b/Userland/Services/WebContent/PageClient.cpp index 29c7e8485c..0f43068320 100644 --- a/Userland/Services/WebContent/PageClient.cpp +++ b/Userland/Services/WebContent/PageClient.cpp @@ -497,9 +497,14 @@ void PageClient::page_did_update_resource_count(i32 count_waiting) client().async_did_update_resource_count(count_waiting); } -String PageClient::page_did_request_new_tab(Web::HTML::ActivateTab activate_tab) +String PageClient::page_did_request_new_web_view(Web::HTML::ActivateTab activate_tab, Web::HTML::WebViewHints hints, Optional page_index) { - return client().did_request_new_tab(activate_tab); + auto response = client().send_sync_but_allow_failure(activate_tab, hints, page_index); + if (!response) { + dbgln("WebContent client disconnected during DidRequestNewWebView. Exiting peacefully."); + exit(0); + } + return 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 175dd5936c..8558c3b17f 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_tab(Web::HTML::ActivateTab activate_tab) override; + virtual String page_did_request_new_web_view(Web::HTML::ActivateTab, Web::HTML::WebViewHints, Optional page_index = {}) 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; diff --git a/Userland/Services/WebContent/WebContentClient.ipc b/Userland/Services/WebContent/WebContentClient.ipc index b8371d79f1..33a9e818f0 100644 --- a/Userland/Services/WebContent/WebContentClient.ipc +++ b/Userland/Services/WebContent/WebContentClient.ipc @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -58,7 +59,7 @@ endpoint WebContentClient did_set_cookie(URL url, Web::Cookie::ParsedCookie cookie, Web::Cookie::Source source) => () did_update_cookie(Web::Cookie::Cookie cookie) =| did_update_resource_count(i32 count_waiting) =| - did_request_new_tab(Web::HTML::ActivateTab activate_tab) => (String handle) + did_request_new_web_view(Web::HTML::ActivateTab activate_tab, Web::HTML::WebViewHints hints, Optional page_index) => (String handle) did_request_activate_tab() =| did_close_browsing_context() =| did_request_restore_window() =|