diff options
-rw-r--r-- | Userland/Applications/Browser/WebDriverConnection.cpp | 14 | ||||
-rw-r--r-- | Userland/Applications/Browser/WebDriverConnection.h | 2 | ||||
-rw-r--r-- | Userland/Applications/Browser/WebDriverSessionClient.ipc | 2 | ||||
-rw-r--r-- | Userland/Services/WebContent/PageHost.cpp | 2 | ||||
-rw-r--r-- | Userland/Services/WebContent/WebDriverClient.ipc | 2 | ||||
-rw-r--r-- | Userland/Services/WebContent/WebDriverConnection.cpp | 136 | ||||
-rw-r--r-- | Userland/Services/WebContent/WebDriverConnection.h | 8 | ||||
-rw-r--r-- | Userland/Services/WebDriver/Client.cpp | 6 | ||||
-rw-r--r-- | Userland/Services/WebDriver/Session.cpp | 84 | ||||
-rw-r--r-- | Userland/Services/WebDriver/Session.h | 2 |
10 files changed, 144 insertions, 114 deletions
diff --git a/Userland/Applications/Browser/WebDriverConnection.cpp b/Userland/Applications/Browser/WebDriverConnection.cpp index 8b516ae28e..4f24227c6f 100644 --- a/Userland/Applications/Browser/WebDriverConnection.cpp +++ b/Userland/Applications/Browser/WebDriverConnection.cpp @@ -75,20 +75,6 @@ void WebDriverConnection::restore_window() } } -void WebDriverConnection::set_window_size(Gfx::IntSize const& size) -{ - dbgln_if(WEBDRIVER_DEBUG, "WebDriverConnection: set_window_size {}", size); - if (auto browser_window = m_browser_window.strong_ref()) - browser_window->resize(size); -} - -void WebDriverConnection::set_window_position(Gfx::IntPoint const& position) -{ - dbgln_if(WEBDRIVER_DEBUG, "WebDriverConnection: set_window_position {}", position); - if (auto browser_window = m_browser_window.strong_ref()) - browser_window->move_to(position); -} - void WebDriverConnection::maximize_window() { dbgln_if(WEBDRIVER_DEBUG, "WebDriverConnection: maximize_window"); diff --git a/Userland/Applications/Browser/WebDriverConnection.h b/Userland/Applications/Browser/WebDriverConnection.h index 040b263333..1649eeb037 100644 --- a/Userland/Applications/Browser/WebDriverConnection.h +++ b/Userland/Applications/Browser/WebDriverConnection.h @@ -44,8 +44,6 @@ public: virtual void forward() override; virtual Messages::WebDriverSessionClient::GetWindowRectResponse get_window_rect() override; virtual void restore_window() override; - virtual void set_window_size(Gfx::IntSize const&) override; - virtual void set_window_position(Gfx::IntPoint const&) override; virtual void maximize_window() override; virtual void minimize_window() override; virtual Messages::WebDriverSessionClient::SerializeSourceResponse serialize_source() override; diff --git a/Userland/Applications/Browser/WebDriverSessionClient.ipc b/Userland/Applications/Browser/WebDriverSessionClient.ipc index fe5f3a866b..acf401ec43 100644 --- a/Userland/Applications/Browser/WebDriverSessionClient.ipc +++ b/Userland/Applications/Browser/WebDriverSessionClient.ipc @@ -20,8 +20,6 @@ endpoint WebDriverSessionClient { forward() =| get_window_rect() => (Gfx::IntRect rect) restore_window() =| - set_window_size(Gfx::IntSize size) =| - set_window_position(Gfx::IntPoint position) =| maximize_window() =| minimize_window() =| serialize_source() => (String source) diff --git a/Userland/Services/WebContent/PageHost.cpp b/Userland/Services/WebContent/PageHost.cpp index 3992df2a62..8e48db996d 100644 --- a/Userland/Services/WebContent/PageHost.cpp +++ b/Userland/Services/WebContent/PageHost.cpp @@ -92,7 +92,7 @@ void PageHost::set_window_size(Gfx::IntSize const& size) ErrorOr<void> PageHost::connect_to_webdriver(String const& webdriver_ipc_path) { VERIFY(!m_webdriver); - m_webdriver = TRY(WebDriverConnection::connect(*this, webdriver_ipc_path)); + m_webdriver = TRY(WebDriverConnection::connect(m_client, *this, webdriver_ipc_path)); return {}; } diff --git a/Userland/Services/WebContent/WebDriverClient.ipc b/Userland/Services/WebContent/WebDriverClient.ipc index e2d0ae7a8c..2ef7c66f7e 100644 --- a/Userland/Services/WebContent/WebDriverClient.ipc +++ b/Userland/Services/WebContent/WebDriverClient.ipc @@ -5,4 +5,6 @@ endpoint WebDriverClient { set_is_webdriver_active(bool active) =| navigate_to(JsonValue payload) => (Web::WebDriver::Response response) get_current_url() => (Web::WebDriver::Response response) + get_window_rect() => (Web::WebDriver::Response response) + set_window_rect(JsonValue payload) => (Web::WebDriver::Response response) } diff --git a/Userland/Services/WebContent/WebDriverConnection.cpp b/Userland/Services/WebContent/WebDriverConnection.cpp index 58e7c79c6e..11c4621fe1 100644 --- a/Userland/Services/WebContent/WebDriverConnection.cpp +++ b/Userland/Services/WebContent/WebDriverConnection.cpp @@ -14,7 +14,9 @@ #include <LibWeb/DOM/Document.h> #include <LibWeb/HTML/BrowsingContext.h> #include <LibWeb/Page/Page.h> +#include <LibWeb/Platform/EventLoopPlugin.h> #include <LibWeb/Platform/Timer.h> +#include <WebContent/ConnectionFromClient.h> #include <WebContent/PageHost.h> #include <WebContent/WebDriverConnection.h> @@ -27,17 +29,39 @@ static JsonValue make_success_response(JsonValue value) return result; } -ErrorOr<NonnullRefPtr<WebDriverConnection>> WebDriverConnection::connect(PageHost& page_host, String const& webdriver_ipc_path) +static JsonValue serialize_rect(Gfx::IntRect const& rect) +{ + JsonObject serialized_rect = {}; + serialized_rect.set("x", rect.x()); + serialized_rect.set("y", rect.y()); + serialized_rect.set("width", rect.width()); + serialized_rect.set("height", rect.height()); + + return make_success_response(move(serialized_rect)); +} + +static Gfx::IntRect compute_window_rect(Web::Page const& page) +{ + return { + page.window_position().x(), + page.window_position().y(), + page.window_size().width(), + page.window_size().height() + }; +} + +ErrorOr<NonnullRefPtr<WebDriverConnection>> WebDriverConnection::connect(ConnectionFromClient& web_content_client, PageHost& page_host, String const& webdriver_ipc_path) { dbgln_if(WEBDRIVER_DEBUG, "Trying to connect to {}", webdriver_ipc_path); auto socket = TRY(Core::Stream::LocalSocket::connect(webdriver_ipc_path)); dbgln_if(WEBDRIVER_DEBUG, "Connected to WebDriver"); - return adopt_nonnull_ref_or_enomem(new (nothrow) WebDriverConnection(move(socket), page_host)); + return adopt_nonnull_ref_or_enomem(new (nothrow) WebDriverConnection(move(socket), web_content_client, page_host)); } -WebDriverConnection::WebDriverConnection(NonnullOwnPtr<Core::Stream::LocalSocket> socket, PageHost& page_host) +WebDriverConnection::WebDriverConnection(NonnullOwnPtr<Core::Stream::LocalSocket> socket, ConnectionFromClient& web_content_client, PageHost& page_host) : IPC::ConnectionToServer<WebDriverClientEndpoint, WebDriverServerEndpoint>(*this, move(socket)) + , m_web_content_client(web_content_client) , m_page_host(page_host) { } @@ -106,6 +130,98 @@ Messages::WebDriverClient::GetCurrentUrlResponse WebDriverConnection::get_curren return make_success_response(url); } +// 11.8.1 Get Window Rect, https://w3c.github.io/webdriver/#dfn-get-window-rect +Messages::WebDriverClient::GetWindowRectResponse WebDriverConnection::get_window_rect() +{ + // 1. If the current top-level browsing context is no longer open, return error with error code no such window. + TRY(ensure_open_top_level_browsing_context()); + + // FIXME: 2. Handle any user prompts and return its value if it is an error. + + // 3. Return success with data set to the WindowRect object for the current top-level browsing context. + return serialize_rect(compute_window_rect(m_page_host.page())); +} + +// 11.8.2 Set Window Rect, https://w3c.github.io/webdriver/#dfn-set-window-rect +Messages::WebDriverClient::SetWindowRectResponse WebDriverConnection::set_window_rect(JsonValue const& payload) +{ + if (!payload.is_object()) + return Web::WebDriver::Error::from_code(Web::WebDriver::ErrorCode::InvalidArgument, "Payload is not a JSON object"); + + auto const& properties = payload.as_object(); + + auto resolve_property = [](auto name, auto const* property, auto min, auto max) -> ErrorOr<Optional<i32>, Web::WebDriver::Error> { + if (!property) + return Optional<i32> {}; + if (!property->is_number()) + return Web::WebDriver::Error::from_code(Web::WebDriver::ErrorCode::InvalidArgument, String::formatted("Property '{}' is not a Number", name)); + + auto number = property->template to_number<i64>(); + + if (number < min) + return Web::WebDriver::Error::from_code(Web::WebDriver::ErrorCode::InvalidArgument, String::formatted("Property '{}' value {} exceeds the minimum allowed value {}", name, number, min)); + if (number > max) + return Web::WebDriver::Error::from_code(Web::WebDriver::ErrorCode::InvalidArgument, String::formatted("Property '{}' value {} exceeds the maximum allowed value {}", name, number, max)); + + return static_cast<i32>(number); + }; + + // 1. Let width be the result of getting a property named width from the parameters argument, else let it be null. + auto const* width_property = properties.get_ptr("width"sv); + + // 2. Let height be the result of getting a property named height from the parameters argument, else let it be null. + auto const* height_property = properties.get_ptr("height"sv); + + // 3. Let x be the result of getting a property named x from the parameters argument, else let it be null. + auto const* x_property = properties.get_ptr("x"sv); + + // 4. Let y be the result of getting a property named y from the parameters argument, else let it be null. + auto const* y_property = properties.get_ptr("y"sv); + + // 5. If width or height is neither null nor a Number from 0 to 2^31 β 1, return error with error code invalid argument. + auto width = TRY(resolve_property("width"sv, width_property, 0, NumericLimits<i32>::max())); + auto height = TRY(resolve_property("height"sv, height_property, 0, NumericLimits<i32>::max())); + + // 6. If x or y is neither null nor a Number from β(2^31) to 2^31 β 1, return error with error code invalid argument. + auto x = TRY(resolve_property("x"sv, x_property, NumericLimits<i32>::min(), NumericLimits<i32>::max())); + auto y = TRY(resolve_property("y"sv, y_property, NumericLimits<i32>::min(), NumericLimits<i32>::max())); + + // 7. If the remote end does not support the Set Window Rect command for the current top-level browsing context for any reason, return error with error code unsupported operation. + + // 8. If the current top-level browsing context is no longer open, return error with error code no such window. + TRY(ensure_open_top_level_browsing_context()); + + // FIXME: 9. Handle any user prompts and return its value if it is an error. + // FIXME: 10. Fully exit fullscreen. + + // 11. Restore the window. + restore_the_window(); + + Gfx::IntRect window_rect; + + // 11. If width and height are not null: + if (width.has_value() && height.has_value()) { + // a. Set the width, in CSS pixels, of the operating system window containing the current top-level browsing context, including any browser chrome and externally drawn window decorations to a value that is as close as possible to width. + // b. Set the height, in CSS pixels, of the operating system window containing the current top-level browsing context, including any browser chrome and externally drawn window decorations to a value that is as close as possible to height. + auto size = m_web_content_client.did_request_resize_window({ *width, *height }); + window_rect.set_size(size); + } else { + window_rect.set_size(m_page_host.page().window_size()); + } + + // 12. If x and y are not null: + if (x.has_value() && y.has_value()) { + // a. Run the implementation-specific steps to set the position of the operating system level window containing the current top-level browsing context to the position given by the x and y coordinates. + auto position = m_web_content_client.did_request_reposition_window({ *x, *y }); + window_rect.set_location(position); + } else { + window_rect.set_location(m_page_host.page().window_position()); + } + + // 14. Return success with data set to the WindowRect object for the current top-level browsing context. + return serialize_rect(window_rect); +} + // https://w3c.github.io/webdriver/#dfn-no-longer-open ErrorOr<void, Web::WebDriver::Error> WebDriverConnection::ensure_open_top_level_browsing_context() { @@ -115,4 +231,18 @@ ErrorOr<void, Web::WebDriver::Error> WebDriverConnection::ensure_open_top_level_ return {}; } +// https://w3c.github.io/webdriver/#dfn-restore-the-window +void WebDriverConnection::restore_the_window() +{ + // To restore the window, given an operating system level window with an associated top-level browsing context, run implementation-specific steps to restore or unhide the window to the visible screen. + m_web_content_client.async_did_request_restore_window(); + + // Do not return from this operation until the visibility state of the top-level browsing contextβs active document has reached the visible state, or until the operation times out. + // FIXME: Implement timeouts. + Web::Platform::EventLoopPlugin::the().spin_until([this]() { + auto state = m_page_host.page().top_level_browsing_context().active_document()->visibility_state(); + return state == "visible"sv; + }); +} + } diff --git a/Userland/Services/WebContent/WebDriverConnection.h b/Userland/Services/WebContent/WebDriverConnection.h index 9fec3b2638..2d84e37be1 100644 --- a/Userland/Services/WebContent/WebDriverConnection.h +++ b/Userland/Services/WebContent/WebDriverConnection.h @@ -21,11 +21,11 @@ class WebDriverConnection final C_OBJECT_ABSTRACT(WebDriverConnection) public: - static ErrorOr<NonnullRefPtr<WebDriverConnection>> connect(PageHost& page_host, String const& webdriver_ipc_path); + static ErrorOr<NonnullRefPtr<WebDriverConnection>> connect(ConnectionFromClient& web_content_client, PageHost& page_host, String const& webdriver_ipc_path); virtual ~WebDriverConnection() = default; private: - WebDriverConnection(NonnullOwnPtr<Core::Stream::LocalSocket> socket, PageHost& page_host); + WebDriverConnection(NonnullOwnPtr<Core::Stream::LocalSocket> socket, ConnectionFromClient& web_content_client, PageHost& page_host); virtual void die() override { } @@ -33,9 +33,13 @@ private: virtual void set_is_webdriver_active(bool) override; virtual Messages::WebDriverClient::NavigateToResponse navigate_to(JsonValue const& payload) override; virtual Messages::WebDriverClient::GetCurrentUrlResponse get_current_url() override; + virtual Messages::WebDriverClient::GetWindowRectResponse get_window_rect() override; + virtual Messages::WebDriverClient::SetWindowRectResponse set_window_rect(JsonValue const& payload) override; ErrorOr<void, Web::WebDriver::Error> ensure_open_top_level_browsing_context(); + void restore_the_window(); + ConnectionFromClient& m_web_content_client; PageHost& m_page_host; }; diff --git a/Userland/Services/WebDriver/Client.cpp b/Userland/Services/WebDriver/Client.cpp index 51d318527a..2b92dd77bc 100644 --- a/Userland/Services/WebDriver/Client.cpp +++ b/Userland/Services/WebDriver/Client.cpp @@ -582,8 +582,7 @@ Web::WebDriver::Response Client::handle_get_window_rect(Vector<StringView> const { dbgln_if(WEBDRIVER_DEBUG, "Handling GET /session/<session_id>/window/rect"); auto* session = TRY(find_session_with_id(parameters[0])); - auto result = TRY(session->get_window_rect()); - return make_json_value(result); + return session->web_content_connection().get_window_rect(); } // 11.8.2 Set Window Rect, https://w3c.github.io/webdriver/#dfn-set-window-rect @@ -592,8 +591,7 @@ Web::WebDriver::Response Client::handle_set_window_rect(Vector<StringView> const { dbgln_if(WEBDRIVER_DEBUG, "Handling POST /session/<session_id>/window/rect"); auto* session = TRY(find_session_with_id(parameters[0])); - auto result = TRY(session->set_window_rect(payload)); - return make_json_value(result); + return session->web_content_connection().set_window_rect(payload); } // 11.8.3 Maximize Window, https://w3c.github.io/webdriver/#dfn-maximize-window diff --git a/Userland/Services/WebDriver/Session.cpp b/Userland/Services/WebDriver/Session.cpp index 4754b9dff1..2028e9cf0c 100644 --- a/Userland/Services/WebDriver/Session.cpp +++ b/Userland/Services/WebDriver/Session.cpp @@ -311,90 +311,6 @@ static JsonValue serialize_rect(Gfx::IntRect const& rect) return serialized_rect; } -// 11.8.1 Get Window Rect, https://w3c.github.io/webdriver/#dfn-get-window-rect -Web::WebDriver::Response Session::get_window_rect() -{ - // 1. If the current top-level browsing context is no longer open, return error with error code no such window. - TRY(check_for_open_top_level_browsing_context_or_return_error()); - - // FIXME: 2. Handle any user prompts and return its value if it is an error. - - // 3. Return success with data set to the WindowRect object for the current top-level browsing context. - return serialize_rect(m_browser_connection->get_window_rect()); -} - -// 11.8.2 Set Window Rect, https://w3c.github.io/webdriver/#dfn-set-window-rect -Web::WebDriver::Response Session::set_window_rect(JsonValue const& payload) -{ - if (!payload.is_object()) - return Web::WebDriver::Error::from_code(Web::WebDriver::ErrorCode::InvalidArgument, "Payload is not a JSON object"); - - auto const& properties = payload.as_object(); - - auto resolve_property = [](auto name, auto const* property, auto min, auto max) -> ErrorOr<Optional<i32>, Web::WebDriver::Error> { - if (!property) - return Optional<i32> {}; - if (!property->is_number()) - return Web::WebDriver::Error::from_code(Web::WebDriver::ErrorCode::InvalidArgument, String::formatted("Property '{}' is not a Number", name)); - - auto number = property->template to_number<i64>(); - - if (number < min) - return Web::WebDriver::Error::from_code(Web::WebDriver::ErrorCode::InvalidArgument, String::formatted("Property '{}' value {} exceeds the minimum allowed value {}", name, number, min)); - if (number > max) - return Web::WebDriver::Error::from_code(Web::WebDriver::ErrorCode::InvalidArgument, String::formatted("Property '{}' value {} exceeds the maximum allowed value {}", name, number, max)); - - return static_cast<i32>(number); - }; - - // 1. Let width be the result of getting a property named width from the parameters argument, else let it be null. - auto const* width_property = properties.get_ptr("width"sv); - - // 2. Let height be the result of getting a property named height from the parameters argument, else let it be null. - auto const* height_property = properties.get_ptr("height"sv); - - // 3. Let x be the result of getting a property named x from the parameters argument, else let it be null. - auto const* x_property = properties.get_ptr("x"sv); - - // 4. Let y be the result of getting a property named y from the parameters argument, else let it be null. - auto const* y_property = properties.get_ptr("y"sv); - - // 5. If width or height is neither null nor a Number from 0 to 2^31 β 1, return error with error code invalid argument. - auto width = TRY(resolve_property("width"sv, width_property, 0, NumericLimits<i32>::max())); - auto height = TRY(resolve_property("height"sv, height_property, 0, NumericLimits<i32>::max())); - - // 6. If x or y is neither null nor a Number from β(2^31) to 2^31 β 1, return error with error code invalid argument. - auto x = TRY(resolve_property("x"sv, x_property, NumericLimits<i32>::min(), NumericLimits<i32>::max())); - auto y = TRY(resolve_property("y"sv, y_property, NumericLimits<i32>::min(), NumericLimits<i32>::max())); - - // 7. If the remote end does not support the Set Window Rect command for the current top-level browsing context for any reason, return error with error code unsupported operation. - - // 8. If the current top-level browsing context is no longer open, return error with error code no such window. - TRY(check_for_open_top_level_browsing_context_or_return_error()); - - // FIXME: 9. Handle any user prompts and return its value if it is an error. - // FIXME: 10. Fully exit fullscreen. - - // 11. Restore the window. - m_browser_connection->async_restore_window(); - - // 11. If width and height are not null: - if (width.has_value() && height.has_value()) { - // a. Set the width, in CSS pixels, of the operating system window containing the current top-level browsing context, including any browser chrome and externally drawn window decorations to a value that is as close as possible to width. - // b. Set the height, in CSS pixels, of the operating system window containing the current top-level browsing context, including any browser chrome and externally drawn window decorations to a value that is as close as possible to height. - m_browser_connection->async_set_window_size(Gfx::IntSize { *width, *height }); - } - - // 12. If x and y are not null: - if (x.has_value() && y.has_value()) { - // a. Run the implementation-specific steps to set the position of the operating system level window containing the current top-level browsing context to the position given by the x and y coordinates. - m_browser_connection->async_set_window_position(Gfx::IntPoint { *x, *y }); - } - - // 14. Return success with data set to the WindowRect object for the current top-level browsing context. - return serialize_rect(m_browser_connection->get_window_rect()); -} - // 11.8.3 Maximize Window, https://w3c.github.io/webdriver/#dfn-maximize-window Web::WebDriver::Response Session::maximize_window() { diff --git a/Userland/Services/WebDriver/Session.h b/Userland/Services/WebDriver/Session.h index 414accbcf3..9094d07718 100644 --- a/Userland/Services/WebDriver/Session.h +++ b/Userland/Services/WebDriver/Session.h @@ -58,8 +58,6 @@ public: Web::WebDriver::Response get_window_handle(); ErrorOr<void, Variant<Web::WebDriver::Error, Error>> close_window(); Web::WebDriver::Response get_window_handles() const; - Web::WebDriver::Response get_window_rect(); - Web::WebDriver::Response set_window_rect(JsonValue const& payload); Web::WebDriver::Response maximize_window(); Web::WebDriver::Response minimize_window(); Web::WebDriver::Response find_element(JsonValue const& payload); |