mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-06-09 09:34:57 +09:00
Ladybird+LibWebView: Move backing store management code to LibWebView
This lets us share this code on all platforms, and makes resizing the window much faster on SerenityOS as well. :^)
This commit is contained in:
parent
ec2600f246
commit
85c542ab00
Notes:
sideshowbarker
2024-07-17 14:33:07 +09:00
Author: https://github.com/awesomekling
Commit: 85c542ab00
Pull-request: https://github.com/SerenityOS/serenity/pull/18847
7 changed files with 108 additions and 135 deletions
|
@ -77,10 +77,6 @@ WebContentView::WebContentView(StringView webdriver_content_ipc_path, WebView::E
|
|||
});
|
||||
|
||||
create_client(enable_callgrind_profiling);
|
||||
|
||||
m_backing_store_shrink_timer = Core::Timer::create_single_shot(3000, [this] {
|
||||
resize_backing_stores_if_needed(WindowResizeInProgress::No);
|
||||
}).release_value_but_fixme_should_propagate_errors();
|
||||
}
|
||||
|
||||
WebContentView::~WebContentView()
|
||||
|
@ -446,60 +442,8 @@ void WebContentView::paintEvent(QPaintEvent*)
|
|||
void WebContentView::resizeEvent(QResizeEvent* event)
|
||||
{
|
||||
QAbstractScrollArea::resizeEvent(event);
|
||||
handle_resize();
|
||||
m_backing_store_shrink_timer->restart();
|
||||
}
|
||||
|
||||
void WebContentView::handle_resize()
|
||||
{
|
||||
update_viewport_rect();
|
||||
resize_backing_stores_if_needed(WindowResizeInProgress::Yes);
|
||||
}
|
||||
|
||||
void WebContentView::resize_backing_stores_if_needed(WindowResizeInProgress window_resize_in_progress)
|
||||
{
|
||||
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;
|
||||
|
||||
if (m_viewport_rect.is_empty())
|
||||
return;
|
||||
|
||||
Gfx::IntSize 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 = { m_viewport_rect.width() + 256, m_viewport_rect.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 = m_viewport_rect.size();
|
||||
m_client_state.front_bitmap = {};
|
||||
m_client_state.back_bitmap = {};
|
||||
}
|
||||
|
||||
auto reallocate_backing_store_if_needed = [&](SharedBitmap& backing_store) {
|
||||
if (!backing_store.bitmap || !backing_store.bitmap->size().contains(minimum_needed_size)) {
|
||||
if (auto new_bitmap_or_error = Gfx::Bitmap::create_shareable(Gfx::BitmapFormat::BGRx8888, minimum_needed_size); !new_bitmap_or_error.is_error()) {
|
||||
if (backing_store.bitmap)
|
||||
client().async_remove_backing_store(backing_store.id);
|
||||
|
||||
backing_store.pending_paints = 0;
|
||||
backing_store.bitmap = new_bitmap_or_error.release_value();
|
||||
backing_store.id = m_client_state.next_bitmap_id++;
|
||||
client().async_add_backing_store(backing_store.id, backing_store.bitmap->to_shareable_bitmap());
|
||||
}
|
||||
backing_store.last_painted_size = m_viewport_rect.size();
|
||||
}
|
||||
};
|
||||
|
||||
reallocate_backing_store_if_needed(m_client_state.front_bitmap);
|
||||
reallocate_backing_store_if_needed(m_client_state.back_bitmap);
|
||||
|
||||
request_repaint();
|
||||
handle_resize();
|
||||
}
|
||||
|
||||
void WebContentView::set_viewport_rect(Gfx::IntRect rect)
|
||||
|
@ -1131,19 +1075,9 @@ void WebContentView::notify_server_did_request_file(Badge<WebContentClient>, Dep
|
|||
client().async_handle_file_return(0, IPC::File(*file.value()), request_id);
|
||||
}
|
||||
|
||||
void WebContentView::request_repaint()
|
||||
Gfx::IntRect WebContentView::viewport_rect() const
|
||||
{
|
||||
// If this widget was instantiated but not yet added to a window,
|
||||
// it won't have a back bitmap yet, so we can just skip repaint requests.
|
||||
if (!m_client_state.back_bitmap.bitmap)
|
||||
return;
|
||||
// Don't request a repaint until pending paint requests have finished.
|
||||
if (m_client_state.back_bitmap.pending_paints) {
|
||||
m_client_state.got_repaint_requests_while_painting = true;
|
||||
return;
|
||||
}
|
||||
m_client_state.back_bitmap.pending_paints++;
|
||||
client().async_paint(m_viewport_rect, m_client_state.back_bitmap.id);
|
||||
return m_viewport_rect;
|
||||
}
|
||||
|
||||
bool WebContentView::event(QEvent* event)
|
||||
|
|
|
@ -198,16 +198,9 @@ private:
|
|||
// ^WebView::ViewImplementation
|
||||
virtual void create_client(WebView::EnableCallgrindProfiling = WebView::EnableCallgrindProfiling::No) override;
|
||||
virtual void update_zoom() override;
|
||||
virtual Gfx::IntRect viewport_rect() const override;
|
||||
|
||||
void request_repaint();
|
||||
void update_viewport_rect();
|
||||
void handle_resize();
|
||||
|
||||
enum class WindowResizeInProgress {
|
||||
No,
|
||||
Yes,
|
||||
};
|
||||
void resize_backing_stores_if_needed(WindowResizeInProgress);
|
||||
|
||||
void ensure_js_console_widget();
|
||||
void ensure_inspector_widget();
|
||||
|
@ -227,10 +220,5 @@ private:
|
|||
|
||||
void handle_web_content_process_crash();
|
||||
|
||||
RefPtr<Gfx::Bitmap> m_backup_bitmap;
|
||||
Gfx::IntSize m_backup_bitmap_size;
|
||||
|
||||
StringView m_webdriver_content_ipc_path;
|
||||
|
||||
RefPtr<Core::Timer> m_backing_store_shrink_timer;
|
||||
};
|
||||
|
|
|
@ -105,44 +105,13 @@ void OutOfProcessWebView::paint_event(GUI::PaintEvent& event)
|
|||
void OutOfProcessWebView::resize_event(GUI::ResizeEvent& event)
|
||||
{
|
||||
Super::resize_event(event);
|
||||
client().async_set_viewport_rect(Gfx::IntRect({ horizontal_scrollbar().value(), vertical_scrollbar().value() }, available_size()));
|
||||
handle_resize();
|
||||
}
|
||||
|
||||
void OutOfProcessWebView::handle_resize()
|
||||
Gfx::IntRect OutOfProcessWebView::viewport_rect() const
|
||||
{
|
||||
client().async_set_viewport_rect(Gfx::IntRect({ horizontal_scrollbar().value(), vertical_scrollbar().value() }, available_size()));
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (m_client_state.front_bitmap.bitmap)
|
||||
client().async_remove_backing_store(m_client_state.front_bitmap.id);
|
||||
|
||||
if (m_client_state.back_bitmap.bitmap)
|
||||
client().async_remove_backing_store(m_client_state.back_bitmap.id);
|
||||
|
||||
m_client_state.front_bitmap = {};
|
||||
m_client_state.back_bitmap = {};
|
||||
m_client_state.has_usable_bitmap = false;
|
||||
|
||||
if (available_size().is_empty())
|
||||
return;
|
||||
|
||||
if (auto new_bitmap_or_error = Gfx::Bitmap::create_shareable(Gfx::BitmapFormat::BGRx8888, available_size()); !new_bitmap_or_error.is_error()) {
|
||||
m_client_state.front_bitmap.bitmap = new_bitmap_or_error.release_value();
|
||||
m_client_state.front_bitmap.id = m_client_state.next_bitmap_id++;
|
||||
client().async_add_backing_store(m_client_state.front_bitmap.id, m_client_state.front_bitmap.bitmap->to_shareable_bitmap());
|
||||
}
|
||||
|
||||
if (auto new_bitmap_or_error = Gfx::Bitmap::create_shareable(Gfx::BitmapFormat::BGRx8888, available_size()); !new_bitmap_or_error.is_error()) {
|
||||
m_client_state.back_bitmap.bitmap = new_bitmap_or_error.release_value();
|
||||
m_client_state.back_bitmap.id = m_client_state.next_bitmap_id++;
|
||||
client().async_add_backing_store(m_client_state.back_bitmap.id, m_client_state.back_bitmap.bitmap->to_shareable_bitmap());
|
||||
}
|
||||
|
||||
request_repaint();
|
||||
return visible_content_rect();
|
||||
}
|
||||
|
||||
void OutOfProcessWebView::update_zoom()
|
||||
|
@ -556,21 +525,6 @@ void OutOfProcessWebView::did_scroll()
|
|||
request_repaint();
|
||||
}
|
||||
|
||||
void OutOfProcessWebView::request_repaint()
|
||||
{
|
||||
// If this widget was instantiated but not yet added to a window,
|
||||
// it won't have a back bitmap yet, so we can just skip repaint requests.
|
||||
if (!m_client_state.back_bitmap.bitmap)
|
||||
return;
|
||||
// Don't request a repaint until pending paint requests have finished.
|
||||
if (m_client_state.back_bitmap.pending_paints) {
|
||||
m_client_state.got_repaint_requests_while_painting = true;
|
||||
return;
|
||||
}
|
||||
m_client_state.back_bitmap.pending_paints++;
|
||||
client().async_paint(m_client_state.back_bitmap.bitmap->rect().translated(horizontal_scrollbar().value(), vertical_scrollbar().value()), m_client_state.back_bitmap.id);
|
||||
}
|
||||
|
||||
void OutOfProcessWebView::js_console_input(DeprecatedString const& js_source)
|
||||
{
|
||||
client().async_js_console_input(js_source);
|
||||
|
|
|
@ -179,8 +179,7 @@ private:
|
|||
virtual void notify_server_did_request_file(Badge<WebContentClient>, DeprecatedString const& path, i32) override;
|
||||
virtual void notify_server_did_finish_handling_input_event(bool event_was_accepted) override;
|
||||
|
||||
void request_repaint();
|
||||
void handle_resize();
|
||||
virtual Gfx::IntRect viewport_rect() const override;
|
||||
|
||||
void handle_web_content_process_crash();
|
||||
|
||||
|
@ -188,7 +187,6 @@ private:
|
|||
void enqueue_input_event(InputEvent const&);
|
||||
void process_next_input_event();
|
||||
|
||||
RefPtr<Gfx::Bitmap> m_backup_bitmap;
|
||||
RefPtr<GUI::Dialog> m_dialog;
|
||||
|
||||
bool m_is_awaiting_response_for_input_event { false };
|
||||
|
|
|
@ -10,6 +10,13 @@
|
|||
|
||||
namespace WebView {
|
||||
|
||||
ViewImplementation::ViewImplementation()
|
||||
{
|
||||
m_backing_store_shrink_timer = Core::Timer::create_single_shot(3000, [this] {
|
||||
resize_backing_stores_if_needed(WindowResizeInProgress::No);
|
||||
}).release_value_but_fixme_should_propagate_errors();
|
||||
}
|
||||
|
||||
WebContentClient& ViewImplementation::client()
|
||||
{
|
||||
VERIFY(m_client_state.client);
|
||||
|
@ -124,6 +131,12 @@ void ViewImplementation::run_javascript(StringView js_source)
|
|||
client().async_run_javascript(js_source);
|
||||
}
|
||||
|
||||
void ViewImplementation::handle_resize()
|
||||
{
|
||||
resize_backing_stores_if_needed(WindowResizeInProgress::Yes);
|
||||
m_backing_store_shrink_timer->restart();
|
||||
}
|
||||
|
||||
#if !defined(AK_OS_SERENITY)
|
||||
|
||||
ErrorOr<NonnullRefPtr<WebView::WebContentClient>> ViewImplementation::launch_web_content_process(ReadonlySpan<String> candidate_web_content_paths, EnableCallgrindProfiling enable_callgrind_profiling, IsLayoutTestMode is_layout_test_mode)
|
||||
|
@ -196,4 +209,66 @@ ErrorOr<NonnullRefPtr<WebView::WebContentClient>> ViewImplementation::launch_web
|
|||
|
||||
#endif
|
||||
|
||||
void ViewImplementation::resize_backing_stores_if_needed(WindowResizeInProgress window_resize_in_progress)
|
||||
{
|
||||
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_rect = this->viewport_rect();
|
||||
if (viewport_rect.is_empty())
|
||||
return;
|
||||
|
||||
Gfx::IntSize 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_rect.width() + 256, viewport_rect.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_rect.size();
|
||||
m_client_state.front_bitmap = {};
|
||||
m_client_state.back_bitmap = {};
|
||||
}
|
||||
|
||||
auto reallocate_backing_store_if_needed = [&](SharedBitmap& backing_store) {
|
||||
if (!backing_store.bitmap || !backing_store.bitmap->size().contains(minimum_needed_size)) {
|
||||
if (auto new_bitmap_or_error = Gfx::Bitmap::create_shareable(Gfx::BitmapFormat::BGRx8888, minimum_needed_size); !new_bitmap_or_error.is_error()) {
|
||||
if (backing_store.bitmap)
|
||||
client().async_remove_backing_store(backing_store.id);
|
||||
|
||||
backing_store.pending_paints = 0;
|
||||
backing_store.bitmap = new_bitmap_or_error.release_value();
|
||||
backing_store.id = m_client_state.next_bitmap_id++;
|
||||
client().async_add_backing_store(backing_store.id, backing_store.bitmap->to_shareable_bitmap());
|
||||
}
|
||||
backing_store.last_painted_size = viewport_rect.size();
|
||||
}
|
||||
};
|
||||
|
||||
reallocate_backing_store_if_needed(m_client_state.front_bitmap);
|
||||
reallocate_backing_store_if_needed(m_client_state.back_bitmap);
|
||||
|
||||
request_repaint();
|
||||
}
|
||||
|
||||
void ViewImplementation::request_repaint()
|
||||
{
|
||||
// If this widget was instantiated but not yet added to a window,
|
||||
// it won't have a back bitmap yet, so we can just skip repaint requests.
|
||||
if (!m_client_state.back_bitmap.bitmap)
|
||||
return;
|
||||
// Don't request a repaint until pending paint requests have finished.
|
||||
if (m_client_state.back_bitmap.pending_paints) {
|
||||
m_client_state.got_repaint_requests_while_painting = true;
|
||||
return;
|
||||
}
|
||||
m_client_state.back_bitmap.pending_paints++;
|
||||
client().async_paint(viewport_rect(), m_client_state.back_bitmap.id);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -124,15 +124,28 @@ public:
|
|||
virtual void notify_server_did_request_file(Badge<WebContentClient>, DeprecatedString const& path, i32) = 0;
|
||||
virtual void notify_server_did_finish_handling_input_event(bool event_was_accepted) = 0;
|
||||
|
||||
virtual Gfx::IntRect viewport_rect() const = 0;
|
||||
|
||||
protected:
|
||||
static constexpr auto ZOOM_MIN_LEVEL = 0.3f;
|
||||
static constexpr auto ZOOM_MAX_LEVEL = 5.0f;
|
||||
static constexpr auto ZOOM_STEP = 0.1f;
|
||||
|
||||
ViewImplementation();
|
||||
|
||||
WebContentClient& client();
|
||||
WebContentClient const& client() const;
|
||||
virtual void update_zoom() = 0;
|
||||
|
||||
enum class WindowResizeInProgress {
|
||||
No,
|
||||
Yes,
|
||||
};
|
||||
void resize_backing_stores_if_needed(WindowResizeInProgress);
|
||||
|
||||
void request_repaint();
|
||||
void handle_resize();
|
||||
|
||||
virtual void create_client(EnableCallgrindProfiling = EnableCallgrindProfiling::No) {};
|
||||
|
||||
#if !defined(AK_OS_SERENITY)
|
||||
|
@ -160,6 +173,11 @@ protected:
|
|||
|
||||
float m_zoom_level { 1.0 };
|
||||
float m_device_pixel_ratio { 1.0 };
|
||||
|
||||
RefPtr<Core::Timer> m_backing_store_shrink_timer;
|
||||
|
||||
RefPtr<Gfx::Bitmap> m_backup_bitmap;
|
||||
Gfx::IntSize m_backup_bitmap_size;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -59,7 +59,8 @@ public:
|
|||
view->client().async_update_system_theme(move(theme));
|
||||
view->client().async_update_system_fonts(Gfx::FontDatabase::default_font_query(), Gfx::FontDatabase::fixed_width_font_query(), Gfx::FontDatabase::window_title_font_query());
|
||||
|
||||
view->client().async_set_viewport_rect({ { 0, 0 }, window_size });
|
||||
view->m_viewport_rect = { { 0, 0 }, window_size };
|
||||
view->client().async_set_viewport_rect(view->m_viewport_rect);
|
||||
view->client().async_set_window_size(window_size);
|
||||
|
||||
if (!web_driver_ipc_path.is_empty())
|
||||
|
@ -154,6 +155,11 @@ private:
|
|||
void notify_server_did_finish_handling_input_event(bool) override { }
|
||||
void update_zoom() override { }
|
||||
void create_client(WebView::EnableCallgrindProfiling) override { }
|
||||
|
||||
virtual Gfx::IntRect viewport_rect() const override { return m_viewport_rect; }
|
||||
|
||||
private:
|
||||
Gfx::IntRect m_viewport_rect;
|
||||
};
|
||||
|
||||
static ErrorOr<NonnullRefPtr<Core::Timer>> load_page_for_screenshot_and_exit(Core::EventLoop& event_loop, HeadlessWebContentView& view, int screenshot_timeout)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue