1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-27 13:47:35 +00:00

Browser+WebContent+WebDriver: Move Take Element Screenshot to WebContent

This commit is contained in:
Timothy Flynn 2022-11-10 13:33:18 -05:00 committed by Linus Groh
parent de1e882601
commit ea0561a0b3
15 changed files with 51 additions and 185 deletions

View file

@ -464,35 +464,6 @@ void ConnectionFromClient::js_console_request_messages(i32 start_index)
m_console_client->send_messages(start_index);
}
static Optional<Web::DOM::Element&> find_element_by_id(i32 element_id)
{
auto* node = Web::DOM::Node::from_id(element_id);
if (!node || !node->is_element())
return {};
return verify_cast<Web::DOM::Element>(*node);
}
// https://w3c.github.io/webdriver/#dfn-scrolls-into-view
void ConnectionFromClient::scroll_element_into_view(i32 element_id)
{
auto element = find_element_by_id(element_id);
if (!element.has_value())
return;
// 1. Let options be the following ScrollIntoViewOptions:
Web::DOM::ScrollIntoViewOptions options {};
// Logical scroll position "block"
// "end"
options.block = Web::Bindings::ScrollLogicalPosition::End;
// Logical scroll position "inline"
// "nearest"
options.inline_ = Web::Bindings::ScrollLogicalPosition::Nearest;
// 2. Run Function.[[Call]](scrollIntoView, options) with element as the this value.
element->scroll_into_view(options);
}
// https://w3c.github.io/webdriver/#dfn-calculate-the-absolute-position
static Gfx::IntPoint calculate_absolute_position_of_element(Web::Page const& page, JS::NonnullGCPtr<Web::Geometry::DOMRect> rect)
{
@ -511,36 +482,6 @@ static Gfx::IntPoint calculate_absolute_position_of_element(Web::Page const& pag
return { x, y };
}
static Gfx::IntRect calculate_absolute_rect_of_element(Web::Page const& page, Web::DOM::Element const& element)
{
auto bounding_rect = element.get_bounding_client_rect();
auto coordinates = calculate_absolute_position_of_element(page, bounding_rect);
return Gfx::IntRect {
coordinates.x(),
coordinates.y(),
static_cast<int>(bounding_rect->width()),
static_cast<int>(bounding_rect->height())
};
}
Messages::WebContentServer::TakeElementScreenshotResponse ConnectionFromClient::take_element_screenshot(i32 element_id)
{
auto element = find_element_by_id(element_id);
if (!element.has_value())
return { {} };
auto viewport_rect = page().top_level_browsing_context().viewport_rect();
auto rect = calculate_absolute_rect_of_element(page(), *element);
rect.intersect(viewport_rect);
auto bitmap = Gfx::Bitmap::try_create(Gfx::BitmapFormat::BGRA8888, rect.size()).release_value_but_fixme_should_propagate_errors();
m_page_host->paint(rect, *bitmap);
return { bitmap->to_shareable_bitmap() };
}
Messages::WebContentServer::TakeDocumentScreenshotResponse ConnectionFromClient::take_document_screenshot()
{
auto* document = page().top_level_browsing_context().active_document();

View file

@ -83,8 +83,6 @@ private:
virtual void run_javascript(String const&) override;
virtual void js_console_request_messages(i32) override;
virtual void scroll_element_into_view(i32 element_id) override;
virtual Messages::WebContentServer::TakeElementScreenshotResponse take_element_screenshot(i32 element_id) override;
virtual Messages::WebContentServer::TakeDocumentScreenshotResponse take_document_screenshot() override;
virtual Messages::WebContentServer::GetLocalStorageEntriesResponse get_local_storage_entries() override;

View file

@ -42,8 +42,6 @@ endpoint WebContentServer
js_console_input(String js_source) =|
js_console_request_messages(i32 start_index) =|
scroll_element_into_view(i32 element_id) => ()
take_element_screenshot(i32 element_id) => (Gfx::ShareableBitmap data)
take_document_screenshot() => (Gfx::ShareableBitmap data)
webdriver_execute_script(String body, Vector<String> json_arguments, Optional<u64> timeout, bool async) => (Web::WebDriver::ExecuteScriptResultType result_type, String json_result)

View file

@ -22,4 +22,5 @@ endpoint WebDriverClient {
get_element_rect(String element_id) => (Web::WebDriver::Response response)
is_element_enabled(String element_id) => (Web::WebDriver::Response response)
take_screenshot() => (Web::WebDriver::Response response)
take_element_screenshot(String element_id) => (Web::WebDriver::Response response)
}

View file

@ -139,6 +139,22 @@ static ErrorOr<Web::DOM::Element*, Web::WebDriver::Error> get_known_connected_el
return static_cast<Web::DOM::Element*>(node);
}
// https://w3c.github.io/webdriver/#dfn-scrolls-into-view
static void scroll_element_into_view(Web::DOM::Element& element)
{
// 1. Let options be the following ScrollIntoViewOptions:
Web::DOM::ScrollIntoViewOptions options {};
// Logical scroll position "block"
// "end"
options.block = Web::Bindings::ScrollLogicalPosition::End;
// Logical scroll position "inline"
// "nearest"
options.inline_ = Web::Bindings::ScrollLogicalPosition::Nearest;
// 2. Run Function.[[Call]](scrollIntoView, options) with element as the this value.
element.scroll_into_view(options);
}
static ErrorOr<String, Web::WebDriver::Error> get_property(JsonValue const& payload, StringView key)
{
if (!payload.is_object())
@ -740,6 +756,38 @@ Messages::WebDriverClient::TakeScreenshotResponse WebDriverConnection::take_scre
return make_success_response(move(encoded_string));
}
// 17.2 Take Element Screenshot, https://w3c.github.io/webdriver/#dfn-take-element-screenshot
Messages::WebDriverClient::TakeElementScreenshotResponse WebDriverConnection::take_element_screenshot(String const& element_id)
{
// 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. Let element be the result of trying to get a known connected element with url variable element id.
auto* element = TRY(get_known_connected_element(element_id));
// 4. Scroll into view the element.
scroll_element_into_view(*element);
// 5. When the user agent is next to run the animation frame callbacks:
// a. Let element rect be elements rectangle.
// b. Let screenshot result be the result of trying to call draw a bounding box from the framebuffer, given element rect as an argument.
// c. Let canvas be a canvas element of screenshot results data.
// d. Let encoding result be the result of trying encoding a canvas as Base64 canvas.
// e. Let encoded string be encoding results data.
auto element_rect = calculate_absolute_rect_of_element(m_page_host.page(), *element);
auto encoded_string = TRY(Web::WebDriver::capture_element_screenshot(
[&](auto const& rect, auto& bitmap) { m_page_host.paint(rect, bitmap); },
m_page_host.page(),
*element,
element_rect));
// 6. Return success with data encoded string.
return make_success_response(move(encoded_string));
}
// https://w3c.github.io/webdriver/#dfn-no-longer-open
ErrorOr<void, Web::WebDriver::Error> WebDriverConnection::ensure_open_top_level_browsing_context()
{

View file

@ -52,6 +52,7 @@ private:
virtual Messages::WebDriverClient::GetElementRectResponse get_element_rect(String const& element_id) override;
virtual Messages::WebDriverClient::IsElementEnabledResponse is_element_enabled(String const& element_id) override;
virtual Messages::WebDriverClient::TakeScreenshotResponse take_screenshot() override;
virtual Messages::WebDriverClient::TakeElementScreenshotResponse take_element_screenshot(String const& element_id) override;
ErrorOr<void, Web::WebDriver::Error> ensure_open_top_level_browsing_context();
void restore_the_window();