diff --git a/Userland/Libraries/LibCore/IOSurface.cpp b/Userland/Libraries/LibCore/IOSurface.cpp index 5296e49790e..4ede4210c16 100644 --- a/Userland/Libraries/LibCore/IOSurface.cpp +++ b/Userland/Libraries/LibCore/IOSurface.cpp @@ -114,6 +114,11 @@ size_t IOSurfaceHandle::bytes_per_element() const return IOSurfaceGetBytesPerElement(m_ref_wrapper->ref); } +size_t IOSurfaceHandle::bytes_per_row() const +{ + return IOSurfaceGetBytesPerRow(m_ref_wrapper->ref); +} + void* IOSurfaceHandle::data() const { return IOSurfaceGetBaseAddress(m_ref_wrapper->ref); diff --git a/Userland/Libraries/LibCore/IOSurface.h b/Userland/Libraries/LibCore/IOSurface.h index 05056884af2..b33b7078d7a 100644 --- a/Userland/Libraries/LibCore/IOSurface.h +++ b/Userland/Libraries/LibCore/IOSurface.h @@ -8,6 +8,7 @@ #include #include +#include #include namespace Core { @@ -27,6 +28,7 @@ public: size_t width() const; size_t height() const; size_t bytes_per_element() const; + size_t bytes_per_row() const; void* data() const; ~IOSurfaceHandle(); diff --git a/Userland/Libraries/LibWeb/CMakeLists.txt b/Userland/Libraries/LibWeb/CMakeLists.txt index 4cbbe688c02..e0595537e5b 100644 --- a/Userland/Libraries/LibWeb/CMakeLists.txt +++ b/Userland/Libraries/LibWeb/CMakeLists.txt @@ -533,6 +533,7 @@ set(SOURCES Page/Page.cpp Painting/AudioPaintable.cpp Painting/BackgroundPainting.cpp + Painting/BackingStore.cpp Painting/BorderRadiiData.cpp Painting/BorderPainting.cpp Painting/BorderRadiusCornerClipper.cpp diff --git a/Userland/Libraries/LibWeb/Forward.h b/Userland/Libraries/LibWeb/Forward.h index ccbe3463a5a..5c8bfd42009 100644 --- a/Userland/Libraries/LibWeb/Forward.h +++ b/Userland/Libraries/LibWeb/Forward.h @@ -24,6 +24,7 @@ class XMLDocumentBuilder; } namespace Web::Painting { +class BackingStore; class DisplayListRecorder; class SVGGradientPaintStyle; using PaintStyle = RefPtr; diff --git a/Userland/Libraries/LibWeb/HTML/TraversableNavigable.cpp b/Userland/Libraries/LibWeb/HTML/TraversableNavigable.cpp index a1760d60735..9204b33af6a 100644 --- a/Userland/Libraries/LibWeb/HTML/TraversableNavigable.cpp +++ b/Userland/Libraries/LibWeb/HTML/TraversableNavigable.cpp @@ -1174,8 +1174,10 @@ JS::GCPtr TraversableNavigable::currently_focused_area() return candidate; } -void TraversableNavigable::paint(Web::DevicePixelRect const& content_rect, Gfx::Bitmap& target, Web::PaintOptions paint_options) +void TraversableNavigable::paint(Web::DevicePixelRect const& content_rect, Painting::BackingStore& backing_store, Web::PaintOptions paint_options) { + auto& target = backing_store.bitmap(); + Painting::DisplayList display_list; Painting::DisplayListRecorder display_list_recorder(display_list); diff --git a/Userland/Libraries/LibWeb/HTML/TraversableNavigable.h b/Userland/Libraries/LibWeb/HTML/TraversableNavigable.h index 8b68121366b..82388c87ac2 100644 --- a/Userland/Libraries/LibWeb/HTML/TraversableNavigable.h +++ b/Userland/Libraries/LibWeb/HTML/TraversableNavigable.h @@ -12,6 +12,7 @@ #include #include #include +#include namespace Web::HTML { @@ -85,7 +86,7 @@ public: [[nodiscard]] JS::GCPtr currently_focused_area(); - void paint(Web::DevicePixelRect const&, Gfx::Bitmap&, Web::PaintOptions); + void paint(Web::DevicePixelRect const&, Painting::BackingStore&, Web::PaintOptions); private: TraversableNavigable(JS::NonnullGCPtr); diff --git a/Userland/Libraries/LibWeb/Page/Page.h b/Userland/Libraries/LibWeb/Page/Page.h index ca6d1d7004a..07af9f0af6c 100644 --- a/Userland/Libraries/LibWeb/Page/Page.h +++ b/Userland/Libraries/LibWeb/Page/Page.h @@ -304,7 +304,7 @@ public: virtual CSS::PreferredContrast preferred_contrast() const = 0; virtual CSS::PreferredMotion preferred_motion() const = 0; virtual void paint_next_frame() = 0; - virtual void paint(DevicePixelRect const&, Gfx::Bitmap&, PaintOptions = {}) = 0; + virtual void paint(DevicePixelRect const&, Painting::BackingStore&, PaintOptions = {}) = 0; virtual void page_did_change_title(ByteString const&) { } virtual void page_did_change_url(URL::URL const&) { } virtual void page_did_request_navigate_back() { } diff --git a/Userland/Libraries/LibWeb/Painting/BackingStore.cpp b/Userland/Libraries/LibWeb/Painting/BackingStore.cpp new file mode 100644 index 00000000000..df012934297 --- /dev/null +++ b/Userland/Libraries/LibWeb/Painting/BackingStore.cpp @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2024, Aliaksandr Kalenik + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include + +namespace Web::Painting { + +BitmapBackingStore::BitmapBackingStore(RefPtr bitmap) + : m_bitmap(move(bitmap)) +{ +} + +#ifdef AK_OS_MACOS +IOSurfaceBackingStore::IOSurfaceBackingStore(Core::IOSurfaceHandle&& iosurface_handle) + : m_iosurface_handle(move(iosurface_handle)) +{ + auto bytes_per_row = m_iosurface_handle.bytes_per_row(); + auto bitmap = Gfx::Bitmap::create_wrapper(Gfx::BitmapFormat::BGRA8888, size(), bytes_per_row, m_iosurface_handle.data()); + m_bitmap_wrapper = bitmap.release_value(); +} + +Gfx::IntSize IOSurfaceBackingStore::size() const +{ + return { m_iosurface_handle.width(), m_iosurface_handle.height() }; +} +#endif + +}; diff --git a/Userland/Libraries/LibWeb/Painting/BackingStore.h b/Userland/Libraries/LibWeb/Painting/BackingStore.h new file mode 100644 index 00000000000..ecd92d6a0f2 --- /dev/null +++ b/Userland/Libraries/LibWeb/Painting/BackingStore.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2024, Aliaksandr Kalenik + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include +#include + +#ifdef AK_OS_MACOS +# include +#endif + +namespace Web::Painting { + +class BackingStore { + AK_MAKE_NONCOPYABLE(BackingStore); + +public: + virtual Gfx::IntSize size() const = 0; + virtual Gfx::Bitmap& bitmap() const = 0; + + BackingStore() {}; + virtual ~BackingStore() {}; +}; + +class BitmapBackingStore final : public BackingStore { +public: + BitmapBackingStore(RefPtr); + + Gfx::IntSize size() const override { return m_bitmap->size(); } + Gfx::Bitmap& bitmap() const override { return *m_bitmap; } + +private: + RefPtr m_bitmap; +}; + +#ifdef AK_OS_MACOS +class IOSurfaceBackingStore final : public BackingStore { +public: + IOSurfaceBackingStore(Core::IOSurfaceHandle&&); + + Gfx::IntSize size() const override; + + Core::IOSurfaceHandle& iosurface_handle() { return m_iosurface_handle; } + Gfx::Bitmap& bitmap() const override { return *m_bitmap_wrapper; } + +private: + Core::IOSurfaceHandle m_iosurface_handle; + RefPtr m_bitmap_wrapper; +}; +#endif + +} diff --git a/Userland/Libraries/LibWeb/SVG/SVGDecodedImageData.h b/Userland/Libraries/LibWeb/SVG/SVGDecodedImageData.h index bd41f12516c..e66898f6c53 100644 --- a/Userland/Libraries/LibWeb/SVG/SVGDecodedImageData.h +++ b/Userland/Libraries/LibWeb/SVG/SVGDecodedImageData.h @@ -76,7 +76,7 @@ public: virtual CSS::PreferredMotion preferred_motion() const override { return m_host_page->client().preferred_motion(); } virtual void request_file(FileRequest) override { } virtual void paint_next_frame() override { } - virtual void paint(DevicePixelRect const&, Gfx::Bitmap&, Web::PaintOptions = {}) override { } + virtual void paint(DevicePixelRect const&, Painting::BackingStore&, Web::PaintOptions = {}) override { } virtual void schedule_repaint() override { } virtual bool is_ready_to_paint() const override { return true; } diff --git a/Userland/Libraries/LibWebView/ViewImplementation.cpp b/Userland/Libraries/LibWebView/ViewImplementation.cpp index db3fa86f9e6..75c6201b5a2 100644 --- a/Userland/Libraries/LibWebView/ViewImplementation.cpp +++ b/Userland/Libraries/LibWebView/ViewImplementation.cpp @@ -418,8 +418,10 @@ void ViewImplementation::did_allocate_iosurface_backing_stores(i32 front_id, Cor auto front_size = Gfx::IntSize { front_iosurface.width(), front_iosurface.height() }; auto back_size = Gfx::IntSize { back_iosurface.width(), back_iosurface.height() }; - auto front_bitmap = Gfx::Bitmap::create_wrapper(Gfx::BitmapFormat::BGRA8888, front_size, front_size.width() * front_iosurface.bytes_per_element(), front_iosurface.data(), [handle = move(front_iosurface)] {}); - auto back_bitmap = Gfx::Bitmap::create_wrapper(Gfx::BitmapFormat::BGRA8888, back_size, back_size.width() * back_iosurface.bytes_per_element(), back_iosurface.data(), [handle = move(back_iosurface)] {}); + auto bytes_per_row = front_iosurface.bytes_per_row(); + + auto front_bitmap = Gfx::Bitmap::create_wrapper(Gfx::BitmapFormat::BGRA8888, front_size, bytes_per_row, front_iosurface.data(), [handle = move(front_iosurface)] {}); + auto back_bitmap = Gfx::Bitmap::create_wrapper(Gfx::BitmapFormat::BGRA8888, back_size, bytes_per_row, back_iosurface.data(), [handle = move(back_iosurface)] {}); m_client_state.front_bitmap.bitmap = front_bitmap.release_value_but_fixme_should_propagate_errors(); m_client_state.front_bitmap.id = front_id; diff --git a/Userland/Services/WebContent/BackingStoreManager.cpp b/Userland/Services/WebContent/BackingStoreManager.cpp index a354e527921..23c67e09551 100644 --- a/Userland/Services/WebContent/BackingStoreManager.cpp +++ b/Userland/Services/WebContent/BackingStoreManager.cpp @@ -51,9 +51,6 @@ void BackingStoreManager::reallocate_backing_stores(Gfx::IntSize size) m_front_bitmap_id = m_next_bitmap_id++; m_back_bitmap_id = m_next_bitmap_id++; - m_front_bitmap = Gfx::Bitmap::create_wrapper(Gfx::BitmapFormat::BGRA8888, size, size.width() * front_iosurface.bytes_per_element(), front_iosurface.data(), [handle = move(front_iosurface)] {}).release_value(); - m_back_bitmap = Gfx::Bitmap::create_wrapper(Gfx::BitmapFormat::BGRA8888, size, size.width() * back_iosurface.bytes_per_element(), back_iosurface.data(), [handle = move(back_iosurface)] {}).release_value(); - Core::Platform::BackingStoreMetadata metadata; metadata.page_id = m_page_client.m_id; metadata.front_backing_store_id = m_front_bitmap_id; @@ -86,6 +83,9 @@ void BackingStoreManager::reallocate_backing_stores(Gfx::IntSize size) VERIFY_NOT_REACHED(); } + m_front_store = make(move(front_iosurface)); + m_back_store = make(move(back_iosurface)); + return; } #endif @@ -93,10 +93,13 @@ void BackingStoreManager::reallocate_backing_stores(Gfx::IntSize size) m_front_bitmap_id = m_next_bitmap_id++; m_back_bitmap_id = m_next_bitmap_id++; - m_front_bitmap = Gfx::Bitmap::create_shareable(Gfx::BitmapFormat::BGRA8888, size).release_value(); - m_back_bitmap = Gfx::Bitmap::create_shareable(Gfx::BitmapFormat::BGRA8888, size).release_value(); + auto front_bitmap = Gfx::Bitmap::create_shareable(Gfx::BitmapFormat::BGRA8888, size).release_value(); + auto back_bitmap = Gfx::Bitmap::create_shareable(Gfx::BitmapFormat::BGRA8888, size).release_value(); - m_page_client.page_did_allocate_backing_stores(m_front_bitmap_id, m_front_bitmap->to_shareable_bitmap(), m_back_bitmap_id, m_back_bitmap->to_shareable_bitmap()); + m_front_store = make(front_bitmap); + m_back_store = make(back_bitmap); + + m_page_client.page_did_allocate_backing_stores(m_front_bitmap_id, front_bitmap->to_shareable_bitmap(), m_back_bitmap_id, back_bitmap->to_shareable_bitmap()); } void BackingStoreManager::resize_backing_stores_if_needed(WindowResizingInProgress window_resize_in_progress) @@ -114,18 +117,18 @@ void BackingStoreManager::resize_backing_stores_if_needed(WindowResizingInProgre } else { // If we're not in the middle of a resize, we can shrink the backing store size to match the viewport size. minimum_needed_size = viewport_size; - m_front_bitmap.clear(); - m_back_bitmap.clear(); + m_front_store.clear(); + m_back_store.clear(); } - if (!m_front_bitmap || !m_back_bitmap || !m_front_bitmap->size().contains(minimum_needed_size.to_type())) { + if (!m_front_store || !m_back_store || !m_front_store->size().contains(minimum_needed_size.to_type())) { reallocate_backing_stores(minimum_needed_size.to_type()); } } void BackingStoreManager::swap_back_and_front() { - swap(m_front_bitmap, m_back_bitmap); + swap(m_front_store, m_back_store); swap(m_front_bitmap_id, m_back_bitmap_id); } diff --git a/Userland/Services/WebContent/BackingStoreManager.h b/Userland/Services/WebContent/BackingStoreManager.h index 4cb4db19788..c19348db33f 100644 --- a/Userland/Services/WebContent/BackingStoreManager.h +++ b/Userland/Services/WebContent/BackingStoreManager.h @@ -8,6 +8,7 @@ #include #include +#include #include namespace WebContent { @@ -26,7 +27,7 @@ public: void reallocate_backing_stores(Gfx::IntSize); void restart_resize_timer(); - RefPtr back_bitmap() { return m_back_bitmap; } + Web::Painting::BackingStore* back_store() { return m_back_store.ptr(); } i32 front_id() const { return m_front_bitmap_id; } void swap_back_and_front(); @@ -38,8 +39,8 @@ private: i32 m_front_bitmap_id { -1 }; i32 m_back_bitmap_id { -1 }; - RefPtr m_front_bitmap; - RefPtr m_back_bitmap; + OwnPtr m_front_store; + OwnPtr m_back_store; int m_next_bitmap_id { 0 }; RefPtr m_backing_store_shrink_timer; diff --git a/Userland/Services/WebContent/PageClient.cpp b/Userland/Services/WebContent/PageClient.cpp index ddd0fac4a05..41df7597755 100644 --- a/Userland/Services/WebContent/PageClient.cpp +++ b/Userland/Services/WebContent/PageClient.cpp @@ -199,22 +199,24 @@ void PageClient::paint_next_frame() } auto rect = 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(); - paint(rect, *bitmap, { .paint_overlay = Web::PaintOptions::PaintOverlay::No }); + auto backing_store = Web::Painting::BitmapBackingStore(*bitmap); + paint(rect, backing_store, { .paint_overlay = Web::PaintOptions::PaintOverlay::No }); client().async_did_take_screenshot(m_id, bitmap->to_shareable_bitmap()); } else { Web::DevicePixelRect rect { { 0, 0 }, content_size() }; auto bitmap = Gfx::Bitmap::create(Gfx::BitmapFormat::BGRA8888, rect.size().to_type()).release_value_but_fixme_should_propagate_errors(); - paint(rect, *bitmap); + auto backing_store = Web::Painting::BitmapBackingStore(*bitmap); + paint(rect, backing_store); client().async_did_take_screenshot(m_id, bitmap->to_shareable_bitmap()); } } - auto back_bitmap = m_backing_store_manager.back_bitmap(); - if (!back_bitmap) + auto back_store = m_backing_store_manager.back_store(); + if (!back_store) return; auto viewport_rect = page().css_to_device_rect(page().top_level_traversable()->viewport_rect()); - paint(viewport_rect, *back_bitmap); + paint(viewport_rect, *back_store); m_backing_store_manager.swap_back_and_front(); @@ -222,7 +224,7 @@ void PageClient::paint_next_frame() client().async_did_paint(m_id, viewport_rect.to_type(), m_backing_store_manager.front_id()); } -void PageClient::paint(Web::DevicePixelRect const& content_rect, Gfx::Bitmap& target, Web::PaintOptions paint_options) +void PageClient::paint(Web::DevicePixelRect const& content_rect, Web::Painting::BackingStore& target, Web::PaintOptions paint_options) { paint_options.should_show_line_box_borders = m_should_show_line_box_borders; paint_options.has_focus = m_has_focus; diff --git a/Userland/Services/WebContent/PageClient.h b/Userland/Services/WebContent/PageClient.h index 5e16a82846c..a7adb1e51be 100644 --- a/Userland/Services/WebContent/PageClient.h +++ b/Userland/Services/WebContent/PageClient.h @@ -44,7 +44,7 @@ public: ErrorOr connect_to_webdriver(ByteString const& webdriver_ipc_path); virtual void paint_next_frame() override; - virtual void paint(Web::DevicePixelRect const& content_rect, Gfx::Bitmap&, Web::PaintOptions = {}) override; + virtual void paint(Web::DevicePixelRect const& content_rect, Web::Painting::BackingStore&, Web::PaintOptions = {}) override; void set_palette_impl(Gfx::PaletteImpl&); void set_viewport_size(Web::DevicePixelSize const&); diff --git a/Userland/Services/WebContent/WebDriverConnection.cpp b/Userland/Services/WebContent/WebDriverConnection.cpp index c5859cf9cf5..1060288209e 100644 --- a/Userland/Services/WebContent/WebDriverConnection.cpp +++ b/Userland/Services/WebContent/WebDriverConnection.cpp @@ -1802,7 +1802,10 @@ Messages::WebDriverClient::TakeScreenshotResponse WebDriverConnection::take_scre auto root_rect = calculate_absolute_rect_of_element(m_page_client->page(), *document->document_element()); auto encoded_string = TRY(Web::WebDriver::capture_element_screenshot( - [&](auto const& rect, auto& bitmap) { m_page_client->paint(rect.template to_type(), bitmap); }, + [&](auto const& rect, auto& bitmap) { + auto backing_store = Web::Painting::BitmapBackingStore(bitmap); + m_page_client->paint(rect.template to_type(), backing_store); + }, m_page_client->page(), *document->document_element(), root_rect)); @@ -1835,7 +1838,10 @@ Messages::WebDriverClient::TakeElementScreenshotResponse WebDriverConnection::ta auto element_rect = calculate_absolute_rect_of_element(m_page_client->page(), *element); auto encoded_string = TRY(Web::WebDriver::capture_element_screenshot( - [&](auto const& rect, auto& bitmap) { m_page_client->paint(rect.template to_type(), bitmap); }, + [&](auto const& rect, auto& bitmap) { + auto backing_store = Web::Painting::BitmapBackingStore(bitmap); + m_page_client->paint(rect.template to_type(), backing_store); + }, m_page_client->page(), *element, element_rect)); diff --git a/Userland/Services/WebWorker/PageHost.cpp b/Userland/Services/WebWorker/PageHost.cpp index 21f76ebf57b..00e3142c7d1 100644 --- a/Userland/Services/WebWorker/PageHost.cpp +++ b/Userland/Services/WebWorker/PageHost.cpp @@ -77,7 +77,7 @@ Web::CSS::PreferredMotion PageHost::preferred_motion() const return Web::CSS::PreferredMotion::Auto; } -void PageHost::paint(Web::DevicePixelRect const&, Gfx::Bitmap&, Web::PaintOptions) +void PageHost::paint(Web::DevicePixelRect const&, Web::Painting::BackingStore&, Web::PaintOptions) { } diff --git a/Userland/Services/WebWorker/PageHost.h b/Userland/Services/WebWorker/PageHost.h index 32336f75641..fd1f6fedd2f 100644 --- a/Userland/Services/WebWorker/PageHost.h +++ b/Userland/Services/WebWorker/PageHost.h @@ -32,7 +32,7 @@ public: virtual Web::CSS::PreferredContrast preferred_contrast() const override; virtual Web::CSS::PreferredMotion preferred_motion() const override; virtual void paint_next_frame() override {}; - virtual void paint(Web::DevicePixelRect const&, Gfx::Bitmap&, Web::PaintOptions = {}) override; + virtual void paint(Web::DevicePixelRect const&, Web::Painting::BackingStore&, Web::PaintOptions = {}) override; virtual void request_file(Web::FileRequest) override; virtual void schedule_repaint() override {}; virtual bool is_ready_to_paint() const override { return true; }