diff --git a/Userland/Libraries/LibWeb/HTML/Window.cpp b/Userland/Libraries/LibWeb/HTML/Window.cpp
index e3974b26a8..e30eccb553 100644
--- a/Userland/Libraries/LibWeb/HTML/Window.cpp
+++ b/Userland/Libraries/LibWeb/HTML/Window.cpp
@@ -426,20 +426,20 @@ WebIDL::ExceptionOr> Window::open_impl(StringView u
void Window::alert_impl(String const& message)
{
if (auto* page = this->page())
- page->client().page_did_request_alert(message);
+ page->did_request_alert(message);
}
bool Window::confirm_impl(String const& message)
{
if (auto* page = this->page())
- return page->client().page_did_request_confirm(message);
+ return page->did_request_confirm(message);
return false;
}
String Window::prompt_impl(String const& message, String const& default_)
{
if (auto* page = this->page())
- return page->client().page_did_request_prompt(message, default_);
+ return page->did_request_prompt(message, default_);
return {};
}
diff --git a/Userland/Libraries/LibWeb/Page/Page.cpp b/Userland/Libraries/LibWeb/Page/Page.cpp
index 07a57f9043..4ab8b34152 100644
--- a/Userland/Libraries/LibWeb/Page/Page.cpp
+++ b/Userland/Libraries/LibWeb/Page/Page.cpp
@@ -4,9 +4,13 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
+#include
#include
#include
+#include
+#include
#include
+#include
namespace Web {
@@ -105,4 +109,112 @@ HTML::BrowsingContext const& Page::top_level_browsing_context() const
return *m_top_level_browsing_context;
}
+template
+static ResponseType spin_event_loop_until_dialog_closed(PageClient& client, Optional& response, SourceLocation location = SourceLocation::current())
+{
+ auto& event_loop = Web::HTML::current_settings_object().responsible_event_loop();
+
+ ScopeGuard guard { [&] { event_loop.set_execution_paused(false); } };
+ event_loop.set_execution_paused(true);
+
+ Web::Platform::EventLoopPlugin::the().spin_until([&]() {
+ return response.has_value() || !client.is_connection_open();
+ });
+
+ if (!client.is_connection_open()) {
+ dbgln("WebContent client disconnected during {}. Exiting peacefully.", location.function_name());
+ exit(0);
+ }
+
+ return response.release_value();
+}
+
+void Page::did_request_alert(String const& message)
+{
+ m_pending_dialog = PendingDialog::Alert;
+ m_client.page_did_request_alert(message);
+
+ if (!message.is_empty())
+ m_pending_dialog_text = message;
+
+ spin_event_loop_until_dialog_closed(m_client, m_pending_alert_response);
+}
+
+void Page::alert_closed()
+{
+ if (m_pending_dialog == PendingDialog::Alert) {
+ m_pending_dialog = PendingDialog::None;
+ m_pending_alert_response = Empty {};
+ m_pending_dialog_text.clear();
+ }
+}
+
+bool Page::did_request_confirm(String const& message)
+{
+ m_pending_dialog = PendingDialog::Confirm;
+ m_client.page_did_request_confirm(message);
+
+ if (!message.is_empty())
+ m_pending_dialog_text = message;
+
+ return spin_event_loop_until_dialog_closed(m_client, m_pending_confirm_response);
+}
+
+void Page::confirm_closed(bool accepted)
+{
+ if (m_pending_dialog == PendingDialog::Confirm) {
+ m_pending_dialog = PendingDialog::None;
+ m_pending_confirm_response = accepted;
+ m_pending_dialog_text.clear();
+ }
+}
+
+String Page::did_request_prompt(String const& message, String const& default_)
+{
+ m_pending_dialog = PendingDialog::Prompt;
+ m_client.page_did_request_prompt(message, default_);
+
+ if (!message.is_empty())
+ m_pending_dialog_text = message;
+
+ return spin_event_loop_until_dialog_closed(m_client, m_pending_prompt_response);
+}
+
+void Page::prompt_closed(String response)
+{
+ if (m_pending_dialog == PendingDialog::Prompt) {
+ m_pending_dialog = PendingDialog::None;
+ m_pending_prompt_response = move(response);
+ m_pending_dialog_text.clear();
+ }
+}
+
+void Page::dismiss_dialog()
+{
+ switch (m_pending_dialog) {
+ case PendingDialog::None:
+ break;
+ case PendingDialog::Alert:
+ m_client.page_did_request_accept_dialog();
+ break;
+ case PendingDialog::Confirm:
+ case PendingDialog::Prompt:
+ m_client.page_did_request_dismiss_dialog();
+ break;
+ }
+}
+
+void Page::accept_dialog()
+{
+ switch (m_pending_dialog) {
+ case PendingDialog::None:
+ break;
+ case PendingDialog::Alert:
+ case PendingDialog::Confirm:
+ case PendingDialog::Prompt:
+ m_client.page_did_request_accept_dialog();
+ break;
+ }
+}
+
}
diff --git a/Userland/Libraries/LibWeb/Page/Page.h b/Userland/Libraries/LibWeb/Page/Page.h
index b07541ca04..135281691d 100644
--- a/Userland/Libraries/LibWeb/Page/Page.h
+++ b/Userland/Libraries/LibWeb/Page/Page.h
@@ -83,6 +83,27 @@ public:
Gfx::IntSize const& window_size() const { return m_window_size; }
void set_window_size(Gfx::IntSize const& size) { m_window_size = size; }
+ void did_request_alert(String const& message);
+ void alert_closed();
+
+ bool did_request_confirm(String const& message);
+ void confirm_closed(bool accepted);
+
+ String did_request_prompt(String const& message, String const& default_);
+ void prompt_closed(String response);
+
+ enum class PendingDialog {
+ None,
+ Alert,
+ Confirm,
+ Prompt,
+ };
+ bool has_pending_dialog() const { return m_pending_dialog != PendingDialog::None; }
+ PendingDialog pending_dialog() const { return m_pending_dialog; }
+ Optional const& pending_dialog_text() const { return m_pending_dialog_text; }
+ void dismiss_dialog();
+ void accept_dialog();
+
private:
PageClient& m_client;
@@ -102,10 +123,17 @@ private:
Gfx::IntPoint m_window_position {};
Gfx::IntSize m_window_size {};
+
+ PendingDialog m_pending_dialog { PendingDialog::None };
+ Optional m_pending_dialog_text;
+ Optional m_pending_alert_response;
+ Optional m_pending_confirm_response;
+ Optional m_pending_prompt_response;
};
class PageClient {
public:
+ virtual bool is_connection_open() const = 0;
virtual Gfx::Palette palette() const = 0;
virtual Gfx::IntRect screen_rect() const = 0;
virtual CSS::PreferredColorScheme preferred_color_scheme() const = 0;
@@ -131,8 +159,10 @@ public:
virtual void page_did_request_scroll_to(Gfx::IntPoint const&) { }
virtual void page_did_request_scroll_into_view(Gfx::IntRect const&) { }
virtual void page_did_request_alert(String const&) { }
- virtual bool page_did_request_confirm(String const&) { return false; }
- virtual String page_did_request_prompt(String const&, String const&) { return {}; }
+ virtual void page_did_request_confirm(String const&) { }
+ virtual void page_did_request_prompt(String const&, String const&) { }
+ virtual void page_did_request_accept_dialog() { }
+ virtual void page_did_request_dismiss_dialog() { }
virtual String page_did_request_cookie(const AK::URL&, Cookie::Source) { return {}; }
virtual void page_did_set_cookie(const AK::URL&, Cookie::ParsedCookie const&, Cookie::Source) { }
virtual void page_did_update_resource_count(i32) { }
diff --git a/Userland/Services/WebContent/PageHost.cpp b/Userland/Services/WebContent/PageHost.cpp
index 46837705c1..941d9ff700 100644
--- a/Userland/Services/WebContent/PageHost.cpp
+++ b/Userland/Services/WebContent/PageHost.cpp
@@ -7,17 +7,13 @@
#include "PageHost.h"
#include "ConnectionFromClient.h"
-#include
#include
#include
#include
#include
#include
-#include
-#include
#include
#include
-#include
#include
#include
#include
@@ -54,6 +50,11 @@ void PageHost::setup_palette()
m_palette_impl = Gfx::PaletteImpl::create_with_anonymous_buffer(buffer);
}
+bool PageHost::is_connection_open() const
+{
+ return m_client.is_open();
+}
+
Gfx::Palette PageHost::palette() const
{
return Gfx::Palette(*m_palette_impl);
@@ -237,112 +238,44 @@ void PageHost::page_did_request_link_context_menu(Gfx::IntPoint const& content_p
m_client.async_did_request_link_context_menu(content_position, url, target, modifiers);
}
-template
-static ResponseType spin_event_loop_until_dialog_closed(ConnectionFromClient& client, Optional& response, SourceLocation location = SourceLocation::current())
-{
- auto& event_loop = Web::HTML::current_settings_object().responsible_event_loop();
-
- ScopeGuard guard { [&] { event_loop.set_execution_paused(false); } };
- event_loop.set_execution_paused(true);
-
- Web::Platform::EventLoopPlugin::the().spin_until([&]() {
- return response.has_value() || !client.is_open();
- });
-
- if (!client.is_open()) {
- dbgln("WebContent client disconnected during {}. Exiting peacefully.", location.function_name());
- exit(0);
- }
-
- return response.release_value();
-}
-
void PageHost::page_did_request_alert(String const& message)
{
- m_pending_dialog = PendingDialog::Alert;
m_client.async_did_request_alert(message);
-
- if (!message.is_empty())
- m_pending_dialog_text = message;
-
- spin_event_loop_until_dialog_closed(m_client, m_pending_alert_response);
}
void PageHost::alert_closed()
{
- if (m_pending_dialog == PendingDialog::Alert) {
- m_pending_dialog = PendingDialog::None;
- m_pending_alert_response = Empty {};
- m_pending_dialog_text.clear();
- }
+ page().alert_closed();
}
-bool PageHost::page_did_request_confirm(String const& message)
+void PageHost::page_did_request_confirm(String const& message)
{
- m_pending_dialog = PendingDialog::Confirm;
m_client.async_did_request_confirm(message);
-
- if (!message.is_empty())
- m_pending_dialog_text = message;
-
- return spin_event_loop_until_dialog_closed(m_client, m_pending_confirm_response);
}
void PageHost::confirm_closed(bool accepted)
{
- if (m_pending_dialog == PendingDialog::Confirm) {
- m_pending_dialog = PendingDialog::None;
- m_pending_confirm_response = accepted;
- m_pending_dialog_text.clear();
- }
+ page().confirm_closed(accepted);
}
-String PageHost::page_did_request_prompt(String const& message, String const& default_)
+void PageHost::page_did_request_prompt(String const& message, String const& default_)
{
- m_pending_dialog = PendingDialog::Prompt;
m_client.async_did_request_prompt(message, default_);
-
- if (!message.is_empty())
- m_pending_dialog_text = message;
-
- return spin_event_loop_until_dialog_closed(m_client, m_pending_prompt_response);
}
void PageHost::prompt_closed(String response)
{
- if (m_pending_dialog == PendingDialog::Prompt) {
- m_pending_dialog = PendingDialog::None;
- m_pending_prompt_response = move(response);
- m_pending_dialog_text.clear();
- }
+ page().prompt_closed(move(response));
}
-void PageHost::dismiss_dialog()
+void PageHost::page_did_request_accept_dialog()
{
- switch (m_pending_dialog) {
- case PendingDialog::None:
- break;
- case PendingDialog::Alert:
- m_client.async_did_request_accept_dialog();
- break;
- case PendingDialog::Confirm:
- case PendingDialog::Prompt:
- m_client.async_did_request_dismiss_dialog();
- break;
- }
+ m_client.async_did_request_accept_dialog();
}
-void PageHost::accept_dialog()
+void PageHost::page_did_request_dismiss_dialog()
{
- switch (m_pending_dialog) {
- case PendingDialog::None:
- break;
- case PendingDialog::Alert:
- case PendingDialog::Confirm:
- case PendingDialog::Prompt:
- m_client.async_did_request_accept_dialog();
- break;
- }
+ m_client.async_did_request_dismiss_dialog();
}
void PageHost::page_did_change_favicon(Gfx::Bitmap const& favicon)
diff --git a/Userland/Services/WebContent/PageHost.h b/Userland/Services/WebContent/PageHost.h
index a81ad3fe42..ed70439f00 100644
--- a/Userland/Services/WebContent/PageHost.h
+++ b/Userland/Services/WebContent/PageHost.h
@@ -47,20 +47,9 @@ public:
void confirm_closed(bool accepted);
void prompt_closed(String response);
- enum class PendingDialog {
- None,
- Alert,
- Confirm,
- Prompt,
- };
- bool has_pending_dialog() const { return m_pending_dialog != PendingDialog::None; }
- PendingDialog pending_dialog() const { return m_pending_dialog; }
- Optional const& pending_dialog_text() const { return m_pending_dialog_text; }
- void dismiss_dialog();
- void accept_dialog();
-
private:
// ^PageClient
+ virtual bool is_connection_open() const override;
virtual Gfx::Palette palette() const override;
virtual Gfx::IntRect screen_rect() const override { return m_screen_rect; }
virtual Web::CSS::PreferredColorScheme preferred_color_scheme() const override { return m_preferred_color_scheme; }
@@ -84,8 +73,10 @@ private:
virtual void page_did_create_main_document() override;
virtual void page_did_finish_loading(const URL&) override;
virtual void page_did_request_alert(String const&) override;
- virtual bool page_did_request_confirm(String const&) override;
- virtual String page_did_request_prompt(String const&, String const&) override;
+ virtual void page_did_request_confirm(String const&) override;
+ virtual void page_did_request_prompt(String const&, String const&) override;
+ virtual void page_did_request_accept_dialog() override;
+ virtual void page_did_request_dismiss_dialog() override;
virtual void page_did_change_favicon(Gfx::Bitmap const&) override;
virtual void page_did_request_image_context_menu(Gfx::IntPoint const&, const URL&, String const& target, unsigned modifiers, Gfx::Bitmap const*) override;
virtual String page_did_request_cookie(const URL&, Web::Cookie::Source) override;
@@ -111,12 +102,6 @@ private:
Web::CSS::PreferredColorScheme m_preferred_color_scheme { Web::CSS::PreferredColorScheme::Auto };
RefPtr m_webdriver;
-
- PendingDialog m_pending_dialog { PendingDialog::None };
- Optional m_pending_dialog_text;
- Optional m_pending_alert_response;
- Optional m_pending_confirm_response;
- Optional m_pending_prompt_response;
};
}
diff --git a/Userland/Services/WebContent/WebDriverConnection.cpp b/Userland/Services/WebContent/WebDriverConnection.cpp
index 36a8711ac0..cb09130c91 100644
--- a/Userland/Services/WebContent/WebDriverConnection.cpp
+++ b/Userland/Services/WebContent/WebDriverConnection.cpp
@@ -1389,11 +1389,11 @@ Messages::WebDriverClient::DismissAlertResponse WebDriverConnection::dismiss_ale
TRY(ensure_open_top_level_browsing_context());
// 2. If there is no current user prompt, return error with error code no such alert.
- if (!m_page_host.has_pending_dialog())
+ if (!m_page_host.page().has_pending_dialog())
return Web::WebDriver::Error::from_code(Web::WebDriver::ErrorCode::NoSuchAlert, "No user dialog is currently open"sv);
// 3. Dismiss the current user prompt.
- m_page_host.dismiss_dialog();
+ m_page_host.page().dismiss_dialog();
// 4. Return success with data null.
return JsonValue {};
@@ -1406,11 +1406,11 @@ Messages::WebDriverClient::AcceptAlertResponse WebDriverConnection::accept_alert
TRY(ensure_open_top_level_browsing_context());
// 2. If there is no current user prompt, return error with error code no such alert.
- if (!m_page_host.has_pending_dialog())
+ if (!m_page_host.page().has_pending_dialog())
return Web::WebDriver::Error::from_code(Web::WebDriver::ErrorCode::NoSuchAlert, "No user dialog is currently open"sv);
// 3. Accept the current user prompt.
- m_page_host.accept_dialog();
+ m_page_host.page().accept_dialog();
// 4. Return success with data null.
return JsonValue {};
@@ -1423,11 +1423,11 @@ Messages::WebDriverClient::GetAlertTextResponse WebDriverConnection::get_alert_t
TRY(ensure_open_top_level_browsing_context());
// 2. If there is no current user prompt, return error with error code no such alert.
- if (!m_page_host.has_pending_dialog())
+ if (!m_page_host.page().has_pending_dialog())
return Web::WebDriver::Error::from_code(Web::WebDriver::ErrorCode::NoSuchAlert, "No user dialog is currently open"sv);
// 3. Let message be the text message associated with the current user prompt, or otherwise be null.
- auto const& message = m_page_host.pending_dialog_text();
+ auto const& message = m_page_host.page().pending_dialog_text();
// 4. Return success with data message.
if (message.has_value())
@@ -1446,20 +1446,20 @@ Messages::WebDriverClient::SendAlertTextResponse WebDriverConnection::send_alert
TRY(ensure_open_top_level_browsing_context());
// 4. If there is no current user prompt, return error with error code no such alert.
- if (!m_page_host.has_pending_dialog())
+ if (!m_page_host.page().has_pending_dialog())
return Web::WebDriver::Error::from_code(Web::WebDriver::ErrorCode::NoSuchAlert, "No user dialog is currently open"sv);
// 5. Run the substeps of the first matching current user prompt:
- switch (m_page_host.pending_dialog()) {
+ switch (m_page_host.page().pending_dialog()) {
// -> alert
// -> confirm
- case PageHost::PendingDialog::Alert:
- case PageHost::PendingDialog::Confirm:
+ case Web::Page::PendingDialog::Alert:
+ case Web::Page::PendingDialog::Confirm:
// Return error with error code element not interactable.
return Web::WebDriver::Error::from_code(Web::WebDriver::ErrorCode::ElementNotInteractable, "Only prompt dialogs may receive text"sv);
// -> prompt
- case PageHost::PendingDialog::Prompt:
+ case Web::Page::PendingDialog::Prompt:
// Do nothing.
break;
@@ -1547,7 +1547,7 @@ ErrorOr WebDriverConnection::ensure_open_top_level_
ErrorOr WebDriverConnection::handle_any_user_prompts()
{
// 1. If there is no current user prompt, abort these steps and return success.
- if (!m_page_host.has_pending_dialog())
+ if (!m_page_host.page().has_pending_dialog())
return {};
// 2. Perform the following substeps based on the current session’s user prompt handler:
@@ -1555,19 +1555,19 @@ ErrorOr WebDriverConnection::handle_any_user_prompt
// -> dismiss state
case Web::WebDriver::UnhandledPromptBehavior::Dismiss:
// Dismiss the current user prompt.
- m_page_host.dismiss_dialog();
+ m_page_host.page().dismiss_dialog();
break;
// -> accept state
case Web::WebDriver::UnhandledPromptBehavior::Accept:
// Accept the current user prompt.
- m_page_host.accept_dialog();
+ m_page_host.page().accept_dialog();
break;
// -> dismiss and notify state
case Web::WebDriver::UnhandledPromptBehavior::DismissAndNotify:
// Dismiss the current user prompt.
- m_page_host.dismiss_dialog();
+ m_page_host.page().dismiss_dialog();
// Return an annotated unexpected alert open error.
return Web::WebDriver::Error::from_code(Web::WebDriver::ErrorCode::UnexpectedAlertOpen, "A user dialog is open"sv);
@@ -1575,7 +1575,7 @@ ErrorOr WebDriverConnection::handle_any_user_prompt
// -> accept and notify state
case Web::WebDriver::UnhandledPromptBehavior::AcceptAndNotify:
// Accept the current user prompt.
- m_page_host.accept_dialog();
+ m_page_host.page().accept_dialog();
// Return an annotated unexpected alert open error.
return Web::WebDriver::Error::from_code(Web::WebDriver::ErrorCode::UnexpectedAlertOpen, "A user dialog is open"sv);
diff --git a/Userland/Utilities/headless-browser.cpp b/Userland/Utilities/headless-browser.cpp
index 986387ebcf..8721a90be0 100644
--- a/Userland/Utilities/headless-browser.cpp
+++ b/Userland/Utilities/headless-browser.cpp
@@ -108,6 +108,11 @@ public:
}
// ^Web::PageClient
+ virtual bool is_connection_open() const override
+ {
+ return true;
+ }
+
virtual Gfx::Palette palette() const override
{
return Gfx::Palette(*m_palette_impl);
@@ -199,14 +204,12 @@ public:
{
}
- virtual bool page_did_request_confirm(String const&) override
+ virtual void page_did_request_confirm(String const&) override
{
- return false;
}
- virtual String page_did_request_prompt(String const&, String const&) override
+ virtual void page_did_request_prompt(String const&, String const&) override
{
- return String::empty();
}
virtual String page_did_request_cookie(AK::URL const&, Web::Cookie::Source) override