mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 16:07:47 +00:00
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.
This commit is contained in:
parent
9505928fdb
commit
b57d7e4332
10 changed files with 144 additions and 114 deletions
|
@ -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");
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 {};
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue