summaryrefslogtreecommitdiff
path: root/Userland
diff options
context:
space:
mode:
authorTimothy Flynn <trflynn89@pm.me>2022-11-09 09:56:20 -0500
committerLinus Groh <mail@linusgroh.de>2022-11-09 19:59:26 +0000
commitb57d7e43326437d143708dd18025533cd8b0d8c6 (patch)
tree9d1997d968a3bedadd25c727ded423a06bf3cb54 /Userland
parent9505928fdbd9fd15a201f0371f475c9851a67b83 (diff)
downloadserenity-b57d7e43326437d143708dd18025533cd8b0d8c6.zip
Browser+WebContent+WebDriver: Move Get/Set Window Rect to WebContent
This also lets us more fully implement the "restore the window" method, which requires we block until the document reaches the "visible" state.
Diffstat (limited to 'Userland')
-rw-r--r--Userland/Applications/Browser/WebDriverConnection.cpp14
-rw-r--r--Userland/Applications/Browser/WebDriverConnection.h2
-rw-r--r--Userland/Applications/Browser/WebDriverSessionClient.ipc2
-rw-r--r--Userland/Services/WebContent/PageHost.cpp2
-rw-r--r--Userland/Services/WebContent/WebDriverClient.ipc2
-rw-r--r--Userland/Services/WebContent/WebDriverConnection.cpp136
-rw-r--r--Userland/Services/WebContent/WebDriverConnection.h8
-rw-r--r--Userland/Services/WebDriver/Client.cpp6
-rw-r--r--Userland/Services/WebDriver/Session.cpp84
-rw-r--r--Userland/Services/WebDriver/Session.h2
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);