Everywhere: Pass backing store into Navigable::paint()

...instead of Gfx::Bitmap, which makes it possible to access and
directly paint into IOSurface on macOS.
This commit is contained in:
Aliaksandr Kalenik 2024-06-25 16:43:39 +02:00 committed by Alexander Kalenik
parent c4e935aa97
commit c62cc915df
Notes: sideshowbarker 2024-07-17 02:56:25 +09:00
18 changed files with 145 additions and 30 deletions

View file

@ -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);

View file

@ -8,6 +8,7 @@
#include <AK/Forward.h>
#include <AK/Noncopyable.h>
#include <AK/OwnPtr.h>
#include <LibCore/MachPort.h>
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();

View file

@ -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

View file

@ -24,6 +24,7 @@ class XMLDocumentBuilder;
}
namespace Web::Painting {
class BackingStore;
class DisplayListRecorder;
class SVGGradientPaintStyle;
using PaintStyle = RefPtr<SVGGradientPaintStyle>;

View file

@ -1174,8 +1174,10 @@ JS::GCPtr<DOM::Node> 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);

View file

@ -12,6 +12,7 @@
#include <LibWeb/HTML/SessionHistoryTraversalQueue.h>
#include <LibWeb/HTML/VisibilityState.h>
#include <LibWeb/Page/Page.h>
#include <WebContent/BackingStoreManager.h>
namespace Web::HTML {
@ -85,7 +86,7 @@ public:
[[nodiscard]] JS::GCPtr<DOM::Node> 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<Page>);

View file

@ -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() { }

View file

@ -0,0 +1,32 @@
/*
* Copyright (c) 2024, Aliaksandr Kalenik <kalenik.aliaksandr@gmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibGfx/Bitmap.h>
#include <LibWeb/Painting/BackingStore.h>
namespace Web::Painting {
BitmapBackingStore::BitmapBackingStore(RefPtr<Gfx::Bitmap> 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
};

View file

@ -0,0 +1,57 @@
/*
* Copyright (c) 2024, Aliaksandr Kalenik <kalenik.aliaksandr@gmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/Forward.h>
#include <AK/Noncopyable.h>
#include <LibGfx/Size.h>
#ifdef AK_OS_MACOS
# include <LibCore/IOSurface.h>
#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::Bitmap>);
Gfx::IntSize size() const override { return m_bitmap->size(); }
Gfx::Bitmap& bitmap() const override { return *m_bitmap; }
private:
RefPtr<Gfx::Bitmap> 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<Gfx::Bitmap> m_bitmap_wrapper;
};
#endif
}

View file

@ -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; }

View file

@ -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;

View file

@ -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<Web::Painting::IOSurfaceBackingStore>(move(front_iosurface));
m_back_store = make<Web::Painting::IOSurfaceBackingStore>(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<Web::Painting::BitmapBackingStore>(front_bitmap);
m_back_store = make<Web::Painting::BitmapBackingStore>(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<int>())) {
if (!m_front_store || !m_back_store || !m_front_store->size().contains(minimum_needed_size.to_type<int>())) {
reallocate_backing_stores(minimum_needed_size.to_type<int>());
}
}
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);
}

View file

@ -8,6 +8,7 @@
#include <LibCore/Forward.h>
#include <LibWeb/Page/Page.h>
#include <LibWeb/Painting/BackingStore.h>
#include <WebContent/Forward.h>
namespace WebContent {
@ -26,7 +27,7 @@ public:
void reallocate_backing_stores(Gfx::IntSize);
void restart_resize_timer();
RefPtr<Gfx::Bitmap> 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<Gfx::Bitmap> m_front_bitmap;
RefPtr<Gfx::Bitmap> m_back_bitmap;
OwnPtr<Web::Painting::BackingStore> m_front_store;
OwnPtr<Web::Painting::BackingStore> m_back_store;
int m_next_bitmap_id { 0 };
RefPtr<Core::Timer> m_backing_store_shrink_timer;

View file

@ -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<int>()).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<int>()).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<int>(), 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;

View file

@ -44,7 +44,7 @@ public:
ErrorOr<void> 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&);

View file

@ -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<Web::DevicePixels>(), bitmap); },
[&](auto const& rect, auto& bitmap) {
auto backing_store = Web::Painting::BitmapBackingStore(bitmap);
m_page_client->paint(rect.template to_type<Web::DevicePixels>(), 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<Web::DevicePixels>(), bitmap); },
[&](auto const& rect, auto& bitmap) {
auto backing_store = Web::Painting::BitmapBackingStore(bitmap);
m_page_client->paint(rect.template to_type<Web::DevicePixels>(), backing_store);
},
m_page_client->page(),
*element,
element_rect));

View file

@ -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)
{
}

View file

@ -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; }