diff --git a/Userland/Libraries/LibWebView/ViewImplementation.cpp b/Userland/Libraries/LibWebView/ViewImplementation.cpp index 5f2a6bd1f4..c9a0c59b82 100644 --- a/Userland/Libraries/LibWebView/ViewImplementation.cpp +++ b/Userland/Libraries/LibWebView/ViewImplementation.cpp @@ -374,6 +374,22 @@ void ViewImplementation::handle_web_content_process_crash() load_html(builder.to_deprecated_string()); } +static ErrorOr save_screenshot(Gfx::ShareableBitmap const& bitmap) +{ + if (!bitmap.is_valid()) + return Error::from_string_view("Failed to take a screenshot"sv); + + LexicalPath path { Core::StandardPaths::downloads_directory() }; + path = path.append(TRY(Core::DateTime::now().to_string("screenshot-%Y-%m-%d-%H-%M-%S.png"sv))); + + auto encoded = TRY(Gfx::PNGWriter::encode(*bitmap.bitmap())); + + auto screenshot_file = TRY(Core::File::open(path.string(), Core::File::OpenMode::Write)); + TRY(screenshot_file->write_until_depleted(encoded)); + + return {}; +} + ErrorOr ViewImplementation::take_screenshot(ScreenshotType type) { Gfx::ShareableBitmap bitmap; @@ -388,16 +404,14 @@ ErrorOr ViewImplementation::take_screenshot(ScreenshotType type) break; } - if (!bitmap.is_valid()) - return Error::from_string_view("Failed to take a screenshot of the current tab"sv); + TRY(save_screenshot(bitmap)); + return {}; +} - LexicalPath path { Core::StandardPaths::downloads_directory() }; - path = path.append(TRY(Core::DateTime::now().to_string("screenshot-%Y-%m-%d-%H-%M-%S.png"sv))); - - auto encoded = TRY(Gfx::PNGWriter::encode(*bitmap.bitmap())); - - auto screenshot_file = TRY(Core::File::open(path.string(), Core::File::OpenMode::Write)); - TRY(screenshot_file->write_until_depleted(encoded)); +ErrorOr ViewImplementation::take_dom_node_screenshot(i32 node_id) +{ + auto bitmap = client().take_dom_node_screenshot(node_id); + TRY(save_screenshot(bitmap)); return {}; } diff --git a/Userland/Libraries/LibWebView/ViewImplementation.h b/Userland/Libraries/LibWebView/ViewImplementation.h index 8078b2b2f2..fc618f2575 100644 --- a/Userland/Libraries/LibWebView/ViewImplementation.h +++ b/Userland/Libraries/LibWebView/ViewImplementation.h @@ -91,6 +91,7 @@ public: Full, }; ErrorOr take_screenshot(ScreenshotType); + ErrorOr take_dom_node_screenshot(i32); void set_user_style_sheet(String source); // Load Native.css as the User style sheet, which attempts to make WebView content look as close to diff --git a/Userland/Services/WebContent/ConnectionFromClient.cpp b/Userland/Services/WebContent/ConnectionFromClient.cpp index b92be7f29f..69a9adfb5b 100644 --- a/Userland/Services/WebContent/ConnectionFromClient.cpp +++ b/Userland/Services/WebContent/ConnectionFromClient.cpp @@ -825,6 +825,20 @@ Messages::WebContentServer::TakeDocumentScreenshotResponse ConnectionFromClient: return { bitmap->to_shareable_bitmap() }; } +Messages::WebContentServer::TakeDomNodeScreenshotResponse ConnectionFromClient::take_dom_node_screenshot(i32 node_id) +{ + auto* dom_node = Web::DOM::Node::from_unique_id(node_id); + if (!dom_node || !dom_node->paintable_box()) + return { {} }; + + auto rect = page().page().enclosing_device_rect(dom_node->paintable_box()->absolute_border_box_rect()); + + auto bitmap = Gfx::Bitmap::create(Gfx::BitmapFormat::BGRA8888, rect.size().to_type()).release_value_but_fixme_should_propagate_errors(); + page().paint(rect, *bitmap, { .paint_overlay = Web::PaintOptions::PaintOverlay::No }); + + return { bitmap->to_shareable_bitmap() }; +} + Messages::WebContentServer::GetSelectedTextResponse ConnectionFromClient::get_selected_text() { return page().page().focused_context().selected_text(); diff --git a/Userland/Services/WebContent/ConnectionFromClient.h b/Userland/Services/WebContent/ConnectionFromClient.h index e8b9605d24..28350bfb3b 100644 --- a/Userland/Services/WebContent/ConnectionFromClient.h +++ b/Userland/Services/WebContent/ConnectionFromClient.h @@ -118,6 +118,7 @@ private: virtual void enable_inspector_prototype() override; virtual Messages::WebContentServer::TakeDocumentScreenshotResponse take_document_screenshot() override; + virtual Messages::WebContentServer::TakeDomNodeScreenshotResponse take_dom_node_screenshot(i32 node_id) override; virtual Messages::WebContentServer::GetLocalStorageEntriesResponse get_local_storage_entries() override; virtual Messages::WebContentServer::GetSessionStorageEntriesResponse get_session_storage_entries() override; diff --git a/Userland/Services/WebContent/WebContentServer.ipc b/Userland/Services/WebContent/WebContentServer.ipc index 8bc433f4b9..a82b18085b 100644 --- a/Userland/Services/WebContent/WebContentServer.ipc +++ b/Userland/Services/WebContent/WebContentServer.ipc @@ -54,6 +54,7 @@ endpoint WebContentServer get_dom_node_html(i32 node_id) => (Optional html) take_document_screenshot() => (Gfx::ShareableBitmap data) + take_dom_node_screenshot(i32 node_id) => (Gfx::ShareableBitmap data) run_javascript(DeprecatedString js_source) =|