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
commit b8d18ebcf7
Notes: sideshowbarker 2024-07-16 21:45:42 +09:00
7 changed files with 29 additions and 24 deletions

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;