diff --git a/Userland/Applications/Browser/BrowserWindow.cpp b/Userland/Applications/Browser/BrowserWindow.cpp index 8f2ec40d0c..aea52c5f95 100644 --- a/Userland/Applications/Browser/BrowserWindow.cpp +++ b/Userland/Applications/Browser/BrowserWindow.cpp @@ -631,6 +631,10 @@ void BrowserWindow::create_new_tab(URL url, bool activate) return active_tab().view().get_element_tag_name(element_id); }; + new_tab.webdriver_endpoints().on_get_element_rect = [this](i32 element_id) { + return active_tab().view().get_element_rect(element_id); + }; + new_tab.webdriver_endpoints().on_serialize_source = [this]() { return active_tab().view().serialize_source(); }; diff --git a/Userland/Applications/Browser/WebDriverConnection.cpp b/Userland/Applications/Browser/WebDriverConnection.cpp index aa4f6ba990..d213269054 100644 --- a/Userland/Applications/Browser/WebDriverConnection.cpp +++ b/Userland/Applications/Browser/WebDriverConnection.cpp @@ -283,6 +283,17 @@ Messages::WebDriverSessionClient::GetElementTagNameResponse WebDriverConnection: return { "" }; } +Messages::WebDriverSessionClient::GetElementRectResponse WebDriverConnection::get_element_rect(i32 element_id) +{ + dbgln("WebDriverConnection: get_element_rect {}", element_id); + if (auto browser_window = m_browser_window.strong_ref()) { + auto& tab = browser_window->active_tab(); + if (tab.webdriver_endpoints().on_get_element_rect) + return { tab.webdriver_endpoints().on_get_element_rect(element_id) }; + } + return { {} }; +} + Messages::WebDriverSessionClient::TakeScreenshotResponse WebDriverConnection::take_screenshot() { dbgln_if(WEBDRIVER_DEBUG, "WebDriverConnection: take_screenshot"); diff --git a/Userland/Applications/Browser/WebDriverConnection.h b/Userland/Applications/Browser/WebDriverConnection.h index 6e1af64154..c4415d072c 100644 --- a/Userland/Applications/Browser/WebDriverConnection.h +++ b/Userland/Applications/Browser/WebDriverConnection.h @@ -63,6 +63,7 @@ public: virtual Messages::WebDriverSessionClient::GetComputedValueForElementResponse get_computed_value_for_element(i32 element_id, String const& property_name) override; virtual Messages::WebDriverSessionClient::GetElementTextResponse get_element_text(i32 element_id) override; virtual Messages::WebDriverSessionClient::GetElementTagNameResponse get_element_tag_name(i32 element_id) override; + virtual Messages::WebDriverSessionClient::GetElementRectResponse get_element_rect(i32 element_id) override; virtual Messages::WebDriverSessionClient::TakeScreenshotResponse take_screenshot() override; private: diff --git a/Userland/Applications/Browser/WebDriverEndpoints.h b/Userland/Applications/Browser/WebDriverEndpoints.h index 81f6c4f990..8066e11d69 100644 --- a/Userland/Applications/Browser/WebDriverEndpoints.h +++ b/Userland/Applications/Browser/WebDriverEndpoints.h @@ -8,6 +8,7 @@ #include #include +#include #include namespace Messages::WebContentServer { @@ -29,6 +30,7 @@ public: Function on_get_computed_value_for_element; Function on_get_element_text; Function on_get_element_tag_name; + Function on_get_element_rect; Function on_serialize_source; Function const& json_arguments, Optional const& timeout, bool async)> on_execute_script; }; diff --git a/Userland/Applications/Browser/WebDriverSessionClient.ipc b/Userland/Applications/Browser/WebDriverSessionClient.ipc index 53e67e269d..05e35fa4cc 100644 --- a/Userland/Applications/Browser/WebDriverSessionClient.ipc +++ b/Userland/Applications/Browser/WebDriverSessionClient.ipc @@ -37,5 +37,6 @@ endpoint WebDriverSessionClient { get_computed_value_for_element(i32 element_id, String property_name) => (String computed_value) get_element_text(i32 element_id) => (String text) get_element_tag_name(i32 element_id) => (String tag_name) + get_element_rect(i32 element_id) => (Gfx::IntRect rect) take_screenshot() => (Gfx::ShareableBitmap data) } diff --git a/Userland/Services/WebDriver/Client.cpp b/Userland/Services/WebDriver/Client.cpp index a681d201d9..5d11e82c2d 100644 --- a/Userland/Services/WebDriver/Client.cpp +++ b/Userland/Services/WebDriver/Client.cpp @@ -49,6 +49,7 @@ Vector Client::s_routes = { { HTTP::HttpRequest::Method::GET, { "session", ":session_id", "element", ":element_id", "css", ":property_name" }, &Client::handle_get_element_css_value }, { HTTP::HttpRequest::Method::GET, { "session", ":session_id", "element", ":element_id", "text" }, &Client::handle_get_element_text }, { HTTP::HttpRequest::Method::GET, { "session", ":session_id", "element", ":element_id", "name" }, &Client::handle_get_element_tag_name }, + { HTTP::HttpRequest::Method::GET, { "session", ":session_id", "element", ":element_id", "rect" }, &Client::handle_get_element_rect }, { HTTP::HttpRequest::Method::GET, { "session", ":session_id", "source" }, &Client::handle_get_source }, { HTTP::HttpRequest::Method::POST, { "session", ":session_id", "execute", "sync" }, &Client::handle_execute_script }, { HTTP::HttpRequest::Method::POST, { "session", ":session_id", "execute", "async" }, &Client::handle_execute_async_script }, @@ -688,6 +689,16 @@ ErrorOr Client::handle_get_element_tag_name(Vector Client::handle_get_element_rect(Vector const& parameters, JsonValue const&) +{ + dbgln_if(WEBDRIVER_DEBUG, "Handling GET /session//element//rect"); + auto* session = TRY(find_session_with_id(parameters[0])); + auto result = TRY(session->get_element_rect(parameters[1])); + return make_json_value(result); +} + // 13.1 Get Page Source, https://w3c.github.io/webdriver/#dfn-get-page-source // GET /session/{session id}/source ErrorOr Client::handle_get_source(Vector const& parameters, JsonValue const&) diff --git a/Userland/Services/WebDriver/Client.h b/Userland/Services/WebDriver/Client.h index ffe42120df..ab1511b7dc 100644 --- a/Userland/Services/WebDriver/Client.h +++ b/Userland/Services/WebDriver/Client.h @@ -74,6 +74,7 @@ private: ErrorOr handle_get_element_css_value(Vector const&, JsonValue const& payload); ErrorOr handle_get_element_text(Vector const&, JsonValue const& payload); ErrorOr handle_get_element_tag_name(Vector const&, JsonValue const& payload); + ErrorOr handle_get_element_rect(Vector const&, JsonValue const& payload); ErrorOr handle_get_source(Vector const&, JsonValue const& payload); ErrorOr handle_execute_script(Vector const&, JsonValue const& payload); ErrorOr handle_execute_async_script(Vector const&, JsonValue const& payload); diff --git a/Userland/Services/WebDriver/Session.cpp b/Userland/Services/WebDriver/Session.cpp index 84f6eb4e10..02b50a5d77 100644 --- a/Userland/Services/WebDriver/Session.cpp +++ b/Userland/Services/WebDriver/Session.cpp @@ -900,6 +900,42 @@ ErrorOr Session::get_element_tag_name(JsonValue const return JsonValue(qualified_name); } +// 12.4.7 Get Element Rect, https://w3c.github.io/webdriver/#dfn-get-element-rect +ErrorOr Session::get_element_rect(StringView parameter_element_id) +{ + // 1. If the current 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. Let element be the result of trying to get a known connected element with url variable element id. + // NOTE: The whole concept of "connected elements" is not implemented yet. See get_or_create_a_web_element_reference() + // For now the element is only represented by its ID + auto maybe_element_id = parameter_element_id.to_int(); + if (!maybe_element_id.has_value()) + return WebDriverError::from_code(ErrorCode::InvalidArgument, "Element ID is not an i32"); + + auto element_id = maybe_element_id.release_value(); + + // 4. Calculate the absolute position of element and let it be coordinates. + // 5. Let rect be element’s bounding rectangle. + auto rect = m_browser_connection->get_element_rect(element_id); + + // 6. Let body be a new JSON Object initialized with: + // "x" + // The first value of coordinates. + // "y" + // The second value of coordinates. + // "width" + // Value of rect’s width dimension. + // "height" + // Value of rect’s height dimension. + auto body = serialize_rect(rect); + + // 7. Return success with data body. + return body; +} + // 13.1 Get Page Source, https://w3c.github.io/webdriver/#dfn-get-page-source ErrorOr Session::get_source() { diff --git a/Userland/Services/WebDriver/Session.h b/Userland/Services/WebDriver/Session.h index 1b40f99ed4..bfff084833 100644 --- a/Userland/Services/WebDriver/Session.h +++ b/Userland/Services/WebDriver/Session.h @@ -63,6 +63,7 @@ public: ErrorOr get_element_css_value(JsonValue const& payload, StringView element_id, StringView property_name); ErrorOr get_element_text(JsonValue const& payload, StringView element_id); ErrorOr get_element_tag_name(JsonValue const& payload, StringView element_id); + ErrorOr get_element_rect(StringView element_id); ErrorOr get_source(); ErrorOr execute_script(JsonValue const& payload); ErrorOr execute_async_script(JsonValue const& payload);