LibWeb+WebContent: Change event loop to synchronously paint next frame

...instead of scheduling repaint timer in PageClient.

This change fixes flickering on Discord that happened because:
- Event loop schedules repainting by activating repaint timer
- `Document::tear_down_layout_tree()` destroys paintable tree
- Repaint timer invokes callback and renders an empty frame because
  paintable tree was destroyed
This commit is contained in:
Aliaksandr Kalenik 2024-05-28 15:51:53 +02:00 committed by Andreas Kling
parent e806136116
commit b8d18ebcf7
7 changed files with 29 additions and 24 deletions

View file

@ -327,7 +327,10 @@ void EventLoop::process()
if (navigable && navigable->needs_repaint()) {
auto* browsing_context = document.browsing_context();
auto& page = browsing_context->page();
page.client().schedule_repaint();
if (navigable->is_traversable()) {
VERIFY(page.client().is_ready_to_paint());
page.client().paint_next_frame();
}
}
});

View file

@ -2133,8 +2133,9 @@ void Navigable::paint(Painting::RecordingPainter& recording_painter, PaintConfig
auto background_color = document->background_color();
recording_painter.fill_rect(bitmap_rect, background_color);
if (!document->paintable())
return;
if (!document->paintable()) {
VERIFY_NOT_REACHED();
}
Web::PaintContext context(recording_painter, page.palette(), page.client().device_pixels_per_css_pixel());
context.set_device_viewport_rect(viewport_rect);

View file

@ -247,6 +247,7 @@ public:
virtual DevicePixelRect screen_rect() const = 0;
virtual double device_pixels_per_css_pixel() const = 0;
virtual CSS::PreferredColorScheme preferred_color_scheme() const = 0;
virtual void paint_next_frame() = 0;
virtual void paint(DevicePixelRect const&, Gfx::Bitmap&, PaintOptions = {}) = 0;
virtual void page_did_change_title(ByteString const&) { }
virtual void page_did_change_url(URL::URL const&) { }

View file

@ -73,6 +73,7 @@ public:
virtual double device_pixels_per_css_pixel() const override { return 1.0; }
virtual CSS::PreferredColorScheme preferred_color_scheme() const override { return m_host_page->client().preferred_color_scheme(); }
virtual void request_file(FileRequest) override { }
virtual void paint_next_frame() override { }
virtual void paint(DevicePixelRect const&, Gfx::Bitmap&, Web::PaintOptions = {}) override { }
virtual void schedule_repaint() override { }
virtual bool is_ready_to_paint() const override { return true; }

View file

@ -57,23 +57,6 @@ PageClient::PageClient(PageHost& owner, u64 id)
{
setup_palette();
m_repaint_timer = Web::Platform::Timer::create_single_shot(0, [this] {
if (!m_backing_stores.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);
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_paint_state = PaintState::WaitingForClient;
client().async_did_paint(m_id, viewport_rect.to_type<int>(), backing_stores.front_bitmap_id);
});
#ifdef HAS_ACCELERATED_GRAPHICS
if (s_use_gpu_painter) {
auto context = AccelGfx::Context::create();
@ -92,9 +75,6 @@ void PageClient::schedule_repaint()
m_paint_state = PaintState::PaintWhenReady;
return;
}
if (!m_repaint_timer->is_active())
m_repaint_timer->start();
}
bool PageClient::is_ready_to_paint() const
@ -197,6 +177,24 @@ Web::Layout::Viewport* PageClient::layout_root()
return document->layout_node();
}
void PageClient::paint_next_frame()
{
if (!m_backing_stores.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);
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_paint_state = PaintState::WaitingForClient;
client().async_did_paint(m_id, viewport_rect.to_type<int>(), backing_stores.front_bitmap_id);
}
void PageClient::paint(Web::DevicePixelRect const& content_rect, Gfx::Bitmap& target, Web::PaintOptions paint_options)
{
Web::Painting::CommandList painting_commands;

View file

@ -39,6 +39,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;
void set_palette_impl(Gfx::PaletteImpl&);
@ -177,7 +178,6 @@ private:
};
PaintState m_paint_state { PaintState::Ready };
RefPtr<Web::Platform::Timer> m_repaint_timer;
Web::CSS::PreferredColorScheme m_preferred_color_scheme { Web::CSS::PreferredColorScheme::Auto };

View file

@ -29,6 +29,7 @@ public:
virtual Web::DevicePixelRect screen_rect() const override;
virtual double device_pixels_per_css_pixel() const override;
virtual Web::CSS::PreferredColorScheme preferred_color_scheme() const override;
virtual void paint_next_frame() override {};
virtual void paint(Web::DevicePixelRect const&, Gfx::Bitmap&, Web::PaintOptions = {}) override;
virtual void request_file(Web::FileRequest) override;
virtual void schedule_repaint() override {};