소스 검색

LibWeb+WebContent: Move pending dialog handling from PageHost to Page

Currently, all handling of pending dialogs occurs in PageHost. In order
to re-use this functionality to run WebDriver in a headless move, move
it to Page.
Timothy Flynn 2 년 전
부모
커밋
1f08cb7020

+ 3 - 3
Userland/Libraries/LibWeb/HTML/Window.cpp

@@ -426,20 +426,20 @@ WebIDL::ExceptionOr<JS::GCPtr<HTML::WindowProxy>> 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 {};
 }
 

+ 112 - 0
Userland/Libraries/LibWeb/Page/Page.cpp

@@ -4,9 +4,13 @@
  * SPDX-License-Identifier: BSD-2-Clause
  */
 
+#include <AK/SourceLocation.h>
 #include <LibWeb/DOM/Document.h>
 #include <LibWeb/HTML/BrowsingContext.h>
+#include <LibWeb/HTML/EventLoop/EventLoop.h>
+#include <LibWeb/HTML/Scripting/Environments.h>
 #include <LibWeb/Page/Page.h>
+#include <LibWeb/Platform/EventLoopPlugin.h>
 
 namespace Web {
 
@@ -105,4 +109,112 @@ HTML::BrowsingContext const& Page::top_level_browsing_context() const
     return *m_top_level_browsing_context;
 }
 
+template<typename ResponseType>
+static ResponseType spin_event_loop_until_dialog_closed(PageClient& client, Optional<ResponseType>& 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;
+    }
+}
+
 }

+ 32 - 2
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<String> 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<String> m_pending_dialog_text;
+    Optional<Empty> m_pending_alert_response;
+    Optional<bool> m_pending_confirm_response;
+    Optional<String> 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) { }

+ 14 - 81
Userland/Services/WebContent/PageHost.cpp

@@ -7,17 +7,13 @@
 
 #include "PageHost.h"
 #include "ConnectionFromClient.h"
-#include <AK/SourceLocation.h>
 #include <LibGfx/Painter.h>
 #include <LibGfx/ShareableBitmap.h>
 #include <LibGfx/SystemTheme.h>
 #include <LibWeb/Cookie/ParsedCookie.h>
 #include <LibWeb/HTML/BrowsingContext.h>
-#include <LibWeb/HTML/EventLoop/EventLoop.h>
-#include <LibWeb/HTML/Scripting/Environments.h>
 #include <LibWeb/Layout/InitialContainingBlock.h>
 #include <LibWeb/Painting/PaintableBox.h>
-#include <LibWeb/Platform/EventLoopPlugin.h>
 #include <LibWeb/Platform/Timer.h>
 #include <WebContent/WebContentClientEndpoint.h>
 #include <WebContent/WebDriverConnection.h>
@@ -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<typename ResponseType>
-static ResponseType spin_event_loop_until_dialog_closed(ConnectionFromClient& client, Optional<ResponseType>& 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)

+ 5 - 20
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<String> 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<WebDriverConnection> m_webdriver;
-
-    PendingDialog m_pending_dialog { PendingDialog::None };
-    Optional<String> m_pending_dialog_text;
-    Optional<Empty> m_pending_alert_response;
-    Optional<bool> m_pending_confirm_response;
-    Optional<String> m_pending_prompt_response;
 };
 
 }

+ 16 - 16
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<void, Web::WebDriver::Error> WebDriverConnection::ensure_open_top_level_
 ErrorOr<void, Web::WebDriver::Error> 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<void, Web::WebDriver::Error> 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<void, Web::WebDriver::Error> 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);

+ 7 - 4
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