LibWebView+WebContent: Move backing store allocation into WebContent

In the upcoming changes, we are going to switch macOS to using an
IOSurface for the backing store. This change will simplify the process
of sharing an IOSurface between processes because we already have the
MachPortServer running in the browser, and WebContent knows how to
locate the corresponding server.
This commit is contained in:
Aliaksandr Kalenik 2024-06-17 18:50:57 +03:00 committed by Andreas Kling
parent cbbe49cdf0
commit be2c484bb6
Notes: sideshowbarker 2024-07-17 05:13:53 +09:00
14 changed files with 158 additions and 94 deletions

View file

@ -6,6 +6,7 @@ set(WEBCONTENT_SOURCE_DIR ${LADYBIRD_SOURCE_DIR}/Userland/Services/WebContent/)
set(WEBCONTENT_SOURCES
${WEBCONTENT_SOURCE_DIR}/ConnectionFromClient.cpp
${WEBCONTENT_SOURCE_DIR}/ConsoleGlobalEnvironmentExtensions.cpp
${WEBCONTENT_SOURCE_DIR}/BackingStoreManager.cpp
${WEBCONTENT_SOURCE_DIR}/PageClient.cpp
${WEBCONTENT_SOURCE_DIR}/PageHost.cpp
${WEBCONTENT_SOURCE_DIR}/WebContentConsoleClient.cpp

View file

@ -18,6 +18,7 @@
#include <LibGfx/Palette.h>
#include <LibGfx/Point.h>
#include <LibGfx/Rect.h>
#include <LibGfx/ShareableBitmap.h>
#include <LibGfx/Size.h>
#include <LibGfx/StandardCursor.h>
#include <LibIPC/Forward.h>
@ -346,6 +347,7 @@ public:
virtual void page_did_request_activate_tab() { }
virtual void page_did_close_top_level_traversable() { }
virtual void page_did_update_navigation_buttons_state([[maybe_unused]] bool back_enabled, [[maybe_unused]] bool forward_enabled) { }
virtual void page_did_allocate_backing_stores([[maybe_unused]] i32 front_bitmap_id, [[maybe_unused]] Gfx::ShareableBitmap front_bitmap, [[maybe_unused]] i32 back_bitmap_id, [[maybe_unused]] Gfx::ShareableBitmap back_bitmap) { }
virtual void request_file(FileRequest) = 0;

View file

@ -16,10 +16,6 @@ namespace WebView {
ViewImplementation::ViewImplementation()
{
m_backing_store_shrink_timer = Core::Timer::create_single_shot(3000, [this] {
resize_backing_stores_if_needed(WindowResizeInProgress::No);
});
m_repeated_crash_timer = Core::Timer::create_single_shot(1000, [this] {
// Reset the "crashing a lot" counter after 1 second in case we just
// happen to be visiting crashy websites a lot.
@ -386,62 +382,24 @@ void ViewImplementation::did_update_navigation_buttons_state(Badge<WebContentCli
on_navigation_buttons_state_changed(back_enabled, forward_enabled);
}
void ViewImplementation::handle_resize()
{
resize_backing_stores_if_needed(WindowResizeInProgress::Yes);
m_backing_store_shrink_timer->restart();
}
void ViewImplementation::resize_backing_stores_if_needed(WindowResizeInProgress window_resize_in_progress)
void ViewImplementation::did_allocate_backing_stores(Badge<WebContentClient>, i32 front_bitmap_id, Gfx::ShareableBitmap const& front_bitmap, i32 back_bitmap_id, Gfx::ShareableBitmap const& back_bitmap)
{
if (m_client_state.has_usable_bitmap) {
// NOTE: We keep the outgoing front bitmap as a backup so we have something to paint until we get a new one.
m_backup_bitmap = m_client_state.front_bitmap.bitmap;
m_backup_bitmap_size = m_client_state.front_bitmap.last_painted_size;
}
m_client_state.has_usable_bitmap = false;
auto viewport_size = this->viewport_size();
if (viewport_size.is_empty())
return;
m_client_state.front_bitmap.bitmap = front_bitmap.bitmap();
m_client_state.front_bitmap.id = front_bitmap_id;
m_client_state.back_bitmap.bitmap = back_bitmap.bitmap();
m_client_state.back_bitmap.id = back_bitmap_id;
}
Web::DevicePixelSize minimum_needed_size;
if (window_resize_in_progress == WindowResizeInProgress::Yes) {
// Pad the minimum needed size so that we don't have to keep reallocating backing stores while the window is being resized.
minimum_needed_size = { viewport_size.width() + 256, viewport_size.height() + 256 };
} 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_client_state.front_bitmap = {};
m_client_state.back_bitmap = {};
}
auto old_front_bitmap_id = m_client_state.front_bitmap.id;
auto old_back_bitmap_id = m_client_state.back_bitmap.id;
auto reallocate_backing_store_if_needed = [&](SharedBitmap& backing_store) {
if (!backing_store.bitmap || !backing_store.bitmap->size().contains(minimum_needed_size.to_type<int>())) {
if (auto new_bitmap_or_error = Gfx::Bitmap::create_shareable(Gfx::BitmapFormat::BGRA8888, minimum_needed_size.to_type<int>()); !new_bitmap_or_error.is_error()) {
backing_store.bitmap = new_bitmap_or_error.release_value();
backing_store.id = m_client_state.next_bitmap_id++;
}
backing_store.last_painted_size = viewport_size;
}
};
reallocate_backing_store_if_needed(m_client_state.front_bitmap);
reallocate_backing_store_if_needed(m_client_state.back_bitmap);
auto& front_bitmap = m_client_state.front_bitmap;
auto& back_bitmap = m_client_state.back_bitmap;
if (front_bitmap.id != old_front_bitmap_id || back_bitmap.id != old_back_bitmap_id) {
client().async_add_backing_store(page_id(), front_bitmap.id, front_bitmap.bitmap->to_shareable_bitmap(), back_bitmap.id,
back_bitmap.bitmap->to_shareable_bitmap());
client().async_set_viewport_size(page_id(), viewport_size);
}
void ViewImplementation::handle_resize()
{
client().async_set_viewport_size(page_id(), this->viewport_size());
}
void ViewImplementation::handle_web_content_process_crash()

View file

@ -117,6 +117,8 @@ public:
void did_update_navigation_buttons_state(Badge<WebContentClient>, bool back_enabled, bool forward_enabled) const;
void did_allocate_backing_stores(Badge<WebContentClient>, i32 front_bitmap_id, Gfx::ShareableBitmap const&, i32 back_bitmap_id, Gfx::ShareableBitmap const&);
enum class ScreenshotType {
Visible,
Full,
@ -222,12 +224,6 @@ protected:
u64 page_id() const;
virtual void update_zoom() = 0;
enum class WindowResizeInProgress {
No,
Yes,
};
void resize_backing_stores_if_needed(WindowResizeInProgress);
void handle_resize();
enum class CreateNewClient {
@ -250,7 +246,6 @@ protected:
SharedBitmap front_bitmap;
SharedBitmap back_bitmap;
u64 page_index { 0 };
i32 next_bitmap_id { 0 };
bool has_usable_bitmap { false };
} m_client_state;

View file

@ -593,6 +593,12 @@ void WebContentClient::did_update_navigation_buttons_state(u64 page_id, bool bac
view->did_update_navigation_buttons_state({}, back_enabled, forward_enabled);
}
void WebContentClient::did_allocate_backing_stores(u64 page_id, i32 front_bitmap_id, Gfx::ShareableBitmap const& front_bitmap, i32 back_bitmap_id, Gfx::ShareableBitmap const& back_bitmap)
{
if (auto view = view_for_page_id(page_id); view.has_value())
view->did_allocate_backing_stores({}, front_bitmap_id, front_bitmap, back_bitmap_id, back_bitmap);
}
void WebContentClient::inspector_did_load(u64 page_id)
{
if (auto view = view_for_page_id(page_id); view.has_value()) {

View file

@ -100,6 +100,7 @@ private:
virtual void did_insert_clipboard_entry(u64 page_id, String const& data, String const& presentation_style, String const& mime_type) override;
virtual void did_change_audio_play_state(u64 page_id, Web::HTML::AudioPlayState) override;
virtual void did_update_navigation_buttons_state(u64 page_id, bool back_enabled, bool forward_enabled) override;
virtual void did_allocate_backing_stores(u64 page_id, i32 front_bitmap_id, Gfx::ShareableBitmap const&, i32 back_bitmap_id, Gfx::ShareableBitmap const&) override;
virtual void inspector_did_load(u64 page_id) override;
virtual void inspector_did_select_dom_node(u64 page_id, i32 node_id, Optional<Web::CSS::Selector::PseudoElement::Type> const& pseudo_element) override;
virtual void inspector_did_set_dom_node_text(u64 page_id, i32 node_id, String const& text) override;

View file

@ -0,0 +1,75 @@
/*
* Copyright (c) 2024, Aliaksandr Kalenik <kalenik.aliaksandr@gmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibCore/Timer.h>
#include <LibWeb/HTML/TraversableNavigable.h>
#include <WebContent/BackingStoreManager.h>
#include <WebContent/PageClient.h>
namespace WebContent {
BackingStoreManager::BackingStoreManager(PageClient& page_client)
: m_page_client(page_client)
{
m_backing_store_shrink_timer = Core::Timer::create_single_shot(3000, [this] {
resize_backing_stores_if_needed(WindowResizingInProgress::No);
});
}
void BackingStoreManager::restart_resize_timer()
{
m_backing_store_shrink_timer->restart();
}
void BackingStoreManager::resize_backing_stores_if_needed(WindowResizingInProgress window_resize_in_progress)
{
auto css_pixels_viewport_rect = m_page_client.page().top_level_traversable()->viewport_rect();
auto viewport_size = m_page_client.page().css_to_device_rect(css_pixels_viewport_rect).size();
if (viewport_size.is_empty())
return;
Web::DevicePixelSize minimum_needed_size;
if (window_resize_in_progress == WindowResizingInProgress::Yes) {
// Pad the minimum needed size so that we don't have to keep reallocating backing stores while the window is being resized.
minimum_needed_size = { viewport_size.width() + 256, viewport_size.height() + 256 };
} 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();
}
auto old_front_bitmap_id = m_front_bitmap_id;
auto old_back_bitmap_id = m_back_bitmap_id;
auto reallocate_backing_store_if_needed = [&](RefPtr<Gfx::Bitmap>& bitmap, int& id) {
if (!bitmap || !bitmap->size().contains(minimum_needed_size.to_type<int>())) {
if (auto new_bitmap_or_error = Gfx::Bitmap::create_shareable(Gfx::BitmapFormat::BGRA8888, minimum_needed_size.to_type<int>()); !new_bitmap_or_error.is_error()) {
bitmap = new_bitmap_or_error.release_value();
id = m_next_bitmap_id++;
}
}
};
reallocate_backing_store_if_needed(m_front_bitmap, m_front_bitmap_id);
reallocate_backing_store_if_needed(m_back_bitmap, m_back_bitmap_id);
auto& front_bitmap = m_front_bitmap;
auto& back_bitmap = m_back_bitmap;
if (m_front_bitmap_id != old_front_bitmap_id || m_back_bitmap_id != old_back_bitmap_id) {
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::swap_back_and_front()
{
swap(m_front_bitmap, m_back_bitmap);
swap(m_front_bitmap_id, m_back_bitmap_id);
}
}

View file

@ -0,0 +1,42 @@
/*
* Copyright (c) 2024, Aliaksandr Kalenik <kalenik.aliaksandr@gmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <LibWeb/Page/Page.h>
#include <WebContent/Forward.h>
namespace WebContent {
class BackingStoreManager {
public:
enum class WindowResizingInProgress {
No,
Yes
};
void resize_backing_stores_if_needed(WindowResizingInProgress window_resize_in_progress);
void restart_resize_timer();
RefPtr<Gfx::Bitmap> back_bitmap() { return m_back_bitmap; }
i32 front_id() const { return m_front_bitmap_id; }
void swap_back_and_front();
BackingStoreManager(PageClient&);
private:
PageClient& m_page_client;
i32 m_front_bitmap_id { -1 };
i32 m_back_bitmap_id { -1 };
RefPtr<Gfx::Bitmap> m_front_bitmap;
RefPtr<Gfx::Bitmap> m_back_bitmap;
int m_next_bitmap_id { 0 };
RefPtr<Core::Timer> m_backing_store_shrink_timer;
};
}

View file

@ -155,12 +155,6 @@ void ConnectionFromClient::set_viewport_size(u64 page_id, Web::DevicePixelSize c
page->set_viewport_size(size);
}
void ConnectionFromClient::add_backing_store(u64 page_id, i32 front_bitmap_id, Gfx::ShareableBitmap const& front_bitmap, i32 back_bitmap_id, Gfx::ShareableBitmap const& back_bitmap)
{
if (auto page = this->page(page_id); page.has_value())
page->add_backing_store(front_bitmap_id, front_bitmap, back_bitmap_id, back_bitmap);
}
void ConnectionFromClient::ready_to_paint(u64 page_id)
{
if (auto page = this->page(page_id); page.has_value())

View file

@ -63,7 +63,6 @@ private:
virtual void set_viewport_size(u64 page_id, Web::DevicePixelSize const) override;
virtual void key_event(u64 page_id, Web::KeyEvent const&) override;
virtual void mouse_event(u64 page_id, Web::MouseEvent const&) override;
virtual void add_backing_store(u64 page_id, i32 front_bitmap_id, Gfx::ShareableBitmap const& front_bitmap, i32 back_bitmap_id, Gfx::ShareableBitmap const& back_bitmap) override;
virtual void ready_to_paint(u64 page_id) override;
virtual void debug_request(u64 page_id, ByteString const&, ByteString const&) override;
virtual void get_source(u64 page_id) override;

View file

@ -55,6 +55,7 @@ PageClient::PageClient(PageHost& owner, u64 id)
: m_owner(owner)
, m_page(Web::Page::create(Web::Bindings::main_thread_vm(), *this))
, m_id(id)
, m_backing_store_manager(*this)
{
setup_palette();
@ -96,14 +97,6 @@ void PageClient::ready_to_paint()
}
}
void PageClient::add_backing_store(i32 front_bitmap_id, Gfx::ShareableBitmap const& front_bitmap, i32 back_bitmap_id, Gfx::ShareableBitmap const& back_bitmap)
{
m_backing_stores.front_bitmap_id = front_bitmap_id;
m_backing_stores.back_bitmap_id = back_bitmap_id;
m_backing_stores.front_bitmap = *const_cast<Gfx::ShareableBitmap&>(front_bitmap).bitmap();
m_backing_stores.back_bitmap = *const_cast<Gfx::ShareableBitmap&>(back_bitmap).bitmap();
}
void PageClient::visit_edges(JS::Cell::Visitor& visitor)
{
Base::visit_edges(visitor);
@ -216,20 +209,17 @@ void PageClient::paint_next_frame()
}
}
if (!m_backing_stores.back_bitmap) {
auto back_bitmap = m_backing_store_manager.back_bitmap();
if (!back_bitmap)
return;
}
auto& back_bitmap = *m_backing_stores.back_bitmap;
auto viewport_rect = page().css_to_device_rect(page().top_level_traversable()->viewport_rect());
paint(viewport_rect, back_bitmap);
paint(viewport_rect, *back_bitmap);
auto& backing_stores = m_backing_stores;
swap(backing_stores.front_bitmap, backing_stores.back_bitmap);
swap(backing_stores.front_bitmap_id, backing_stores.back_bitmap_id);
m_backing_store_manager.swap_back_and_front();
m_paint_state = PaintState::WaitingForClient;
client().async_did_paint(m_id, viewport_rect.to_type<int>(), backing_stores.front_bitmap_id);
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)
@ -245,6 +235,9 @@ void PageClient::paint(Web::DevicePixelRect const& content_rect, Gfx::Bitmap& ta
void PageClient::set_viewport_size(Web::DevicePixelSize const& size)
{
page().top_level_traversable()->set_viewport_size(page().device_to_css_size(size));
m_backing_store_manager.restart_resize_timer();
m_backing_store_manager.resize_backing_stores_if_needed(BackingStoreManager::WindowResizingInProgress::Yes);
}
void PageClient::page_did_request_cursor_change(Gfx::StandardCursor cursor)
@ -596,6 +589,11 @@ void PageClient::page_did_change_audio_play_state(Web::HTML::AudioPlayState play
client().async_did_change_audio_play_state(m_id, play_state);
}
void PageClient::page_did_allocate_backing_stores(i32 front_bitmap_id, Gfx::ShareableBitmap front_bitmap, i32 back_bitmap_id, Gfx::ShareableBitmap back_bitmap)
{
client().async_did_allocate_backing_stores(m_id, front_bitmap_id, front_bitmap, back_bitmap_id, back_bitmap);
}
IPC::File PageClient::request_worker_agent()
{
auto response = client().send_sync_but_allow_failure<Messages::WebContentClient::RequestWorkerAgent>(m_id);
@ -756,5 +754,4 @@ void PageClient::queue_screenshot_task(Optional<i32> node_id)
m_screenshot_tasks.enqueue({ node_id });
page().top_level_traversable()->set_needs_display();
}
}

View file

@ -14,6 +14,7 @@
#include <LibWeb/HTML/FileFilter.h>
#include <LibWeb/Page/Page.h>
#include <LibWeb/PixelUnits.h>
#include <WebContent/BackingStoreManager.h>
#include <WebContent/Forward.h>
#ifdef HAS_ACCELERATED_GRAPHICS
@ -75,8 +76,6 @@ public:
void ready_to_paint();
void add_backing_store(i32 front_bitmap_id, Gfx::ShareableBitmap const& front_bitmap, i32 back_bitmap_id, Gfx::ShareableBitmap const& back_bitmap);
void initialize_js_console(Web::DOM::Document& document);
void destroy_js_console(Web::DOM::Document& document);
void js_console_input(ByteString const& js_source);
@ -92,6 +91,8 @@ public:
void queue_screenshot_task(Optional<i32> node_id);
friend class BackingStoreManager;
private:
PageClient(PageHost&, u64 id);
@ -156,6 +157,7 @@ private:
virtual void page_did_change_theme_color(Gfx::Color color) override;
virtual void page_did_insert_clipboard_entry(String data, String presentation_style, String mime_type) override;
virtual void page_did_change_audio_play_state(Web::HTML::AudioPlayState) override;
virtual void page_did_allocate_backing_stores(i32 front_bitmap_id, Gfx::ShareableBitmap front_bitmap, i32 back_bitmap_id, Gfx::ShareableBitmap back_bitmap) override;
virtual IPC::File request_worker_agent() override;
virtual void inspector_did_load() override;
virtual void inspector_did_select_dom_node(i32 node_id, Optional<Web::CSS::Selector::PseudoElement::Type> const& pseudo_element) override;
@ -203,13 +205,7 @@ private:
OwnPtr<AccelGfx::Context> m_accelerated_graphics_context;
#endif
struct BackingStores {
i32 front_bitmap_id { -1 };
i32 back_bitmap_id { -1 };
RefPtr<Gfx::Bitmap> front_bitmap;
RefPtr<Gfx::Bitmap> back_bitmap;
};
BackingStores m_backing_stores;
BackingStoreManager m_backing_store_manager;
// NOTE: These documents are not visited, but manually removed from the map on document finalization.
HashMap<JS::RawGCPtr<Web::DOM::Document>, JS::NonnullGCPtr<WebContentConsoleClient>> m_console_clients;

View file

@ -80,6 +80,7 @@ endpoint WebContentClient
did_change_theme_color(u64 page_id, Gfx::Color color) =|
did_insert_clipboard_entry(u64 page_id, String data, String presentation_style, String mime_type) =|
did_update_navigation_buttons_state(u64 page_id, bool back_enabled, bool forward_enabled) =|
did_allocate_backing_stores(u64 page_id, i32 front_bitmap_id, Gfx::ShareableBitmap front_bitmap, i32 back_bitmap_id, Gfx::ShareableBitmap back_bitmap) =|
did_change_audio_play_state(u64 page_id, Web::HTML::AudioPlayState play_state) =|

View file

@ -1,8 +1,6 @@
#include <LibURL/URL.h>
#include <LibIPC/File.h>
#include <LibCore/AnonymousBuffer.h>
#include <LibGfx/Rect.h>
#include <LibGfx/ShareableBitmap.h>
#include <LibWeb/CSS/PreferredColorScheme.h>
#include <LibWeb/CSS/PreferredContrast.h>
#include <LibWeb/CSS/PreferredMotion.h>
@ -28,7 +26,6 @@ endpoint WebContentServer
reload(u64 page_id) =|
traverse_the_history_by_delta(u64 page_id, i32 delta) =|
add_backing_store(u64 page_id, i32 front_bitmap_id, Gfx::ShareableBitmap front_bitmap, i32 back_bitmap_id, Gfx::ShareableBitmap back_bitmap) =|
ready_to_paint(u64 page_id) =|
set_viewport_size(u64 page_id, Web::DevicePixelSize size) =|