LibWeb: Stop deadlocking on unit tests

Unit tests on macOS deadlock because the WebContent process is waiting
for the next opportunity to render before a screenshot is taken. For
some reason unknown to myself, this opportunity never arrives. In
order to not deadlock, screenshot requests are now also processed
separately from rendering.
This commit is contained in:
Victor Tran 2024-07-03 22:12:28 +10:00 committed by Alexander Kalenik
commit 31698281b6
Notes: sideshowbarker 2024-07-17 21:16:31 +09:00
6 changed files with 18 additions and 1 deletions

View file

@ -12,6 +12,7 @@
#include <LibWeb/HTML/BrowsingContext.h> #include <LibWeb/HTML/BrowsingContext.h>
#include <LibWeb/HTML/EventLoop/EventLoop.h> #include <LibWeb/HTML/EventLoop/EventLoop.h>
#include <LibWeb/HTML/Scripting/Environments.h> #include <LibWeb/HTML/Scripting/Environments.h>
#include <LibWeb/HTML/TraversableNavigable.h>
#include <LibWeb/HTML/Window.h> #include <LibWeb/HTML/Window.h>
#include <LibWeb/HighResolutionTime/Performance.h> #include <LibWeb/HighResolutionTime/Performance.h>
#include <LibWeb/HighResolutionTime/TimeOrigin.h> #include <LibWeb/HighResolutionTime/TimeOrigin.h>
@ -336,6 +337,13 @@ void EventLoop::process()
} }
}); });
// FIXME: Not in the spec: If there is a screenshot request queued, process it now.
// This prevents tests deadlocking on screenshot requests on macOS.
for (auto& document : docs) {
if (document->page().top_level_traversable()->needs_repaint())
document->page().client().process_screenshot_requests();
}
// 13. If all of the following are true // 13. If all of the following are true
// - this is a window event loop // - this is a window event loop
// - there is no task in this event loop's task queues whose document is fully active // - there is no task in this event loop's task queues whose document is fully active

View file

@ -304,6 +304,7 @@ public:
virtual CSS::PreferredContrast preferred_contrast() const = 0; virtual CSS::PreferredContrast preferred_contrast() const = 0;
virtual CSS::PreferredMotion preferred_motion() const = 0; virtual CSS::PreferredMotion preferred_motion() const = 0;
virtual void paint_next_frame() = 0; virtual void paint_next_frame() = 0;
virtual void process_screenshot_requests() = 0;
virtual void paint(DevicePixelRect const&, Painting::BackingStore&, PaintOptions = {}) = 0; virtual void paint(DevicePixelRect const&, Painting::BackingStore&, PaintOptions = {}) = 0;
virtual void page_did_change_title(ByteString const&) { } virtual void page_did_change_title(ByteString const&) { }
virtual void page_did_change_url(URL::URL const&) { } virtual void page_did_change_url(URL::URL const&) { }

View file

@ -76,6 +76,7 @@ public:
virtual CSS::PreferredMotion preferred_motion() const override { return m_host_page->client().preferred_motion(); } virtual CSS::PreferredMotion preferred_motion() const override { return m_host_page->client().preferred_motion(); }
virtual void request_file(FileRequest) override { } virtual void request_file(FileRequest) override { }
virtual void paint_next_frame() override { } virtual void paint_next_frame() override { }
virtual void process_screenshot_requests() override { }
virtual void paint(DevicePixelRect const&, Painting::BackingStore&, Web::PaintOptions = {}) override { } virtual void paint(DevicePixelRect const&, Painting::BackingStore&, Web::PaintOptions = {}) override { }
virtual void schedule_repaint() override { } virtual void schedule_repaint() override { }
virtual bool is_ready_to_paint() const override { return true; } virtual bool is_ready_to_paint() const override { return true; }

View file

@ -187,7 +187,7 @@ Web::Layout::Viewport* PageClient::layout_root()
return document->layout_node(); return document->layout_node();
} }
void PageClient::paint_next_frame() void PageClient::process_screenshot_requests()
{ {
while (!m_screenshot_tasks.is_empty()) { while (!m_screenshot_tasks.is_empty()) {
auto task = m_screenshot_tasks.dequeue(); auto task = m_screenshot_tasks.dequeue();
@ -210,6 +210,11 @@ void PageClient::paint_next_frame()
client().async_did_take_screenshot(m_id, bitmap->to_shareable_bitmap()); client().async_did_take_screenshot(m_id, bitmap->to_shareable_bitmap());
} }
} }
}
void PageClient::paint_next_frame()
{
process_screenshot_requests();
auto back_store = m_backing_store_manager.back_store(); auto back_store = m_backing_store_manager.back_store();
if (!back_store) if (!back_store)

View file

@ -44,6 +44,7 @@ public:
ErrorOr<void> connect_to_webdriver(ByteString const& webdriver_ipc_path); ErrorOr<void> connect_to_webdriver(ByteString const& webdriver_ipc_path);
virtual void paint_next_frame() override; virtual void paint_next_frame() override;
virtual void process_screenshot_requests() override;
virtual void paint(Web::DevicePixelRect const& content_rect, Web::Painting::BackingStore&, 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_palette_impl(Gfx::PaletteImpl&);

View file

@ -32,6 +32,7 @@ public:
virtual Web::CSS::PreferredContrast preferred_contrast() const override; virtual Web::CSS::PreferredContrast preferred_contrast() const override;
virtual Web::CSS::PreferredMotion preferred_motion() const override; virtual Web::CSS::PreferredMotion preferred_motion() const override;
virtual void paint_next_frame() override {}; virtual void paint_next_frame() override {};
virtual void process_screenshot_requests() override {};
virtual void paint(Web::DevicePixelRect const&, Web::Painting::BackingStore&, Web::PaintOptions = {}) override; virtual void paint(Web::DevicePixelRect const&, Web::Painting::BackingStore&, Web::PaintOptions = {}) override;
virtual void request_file(Web::FileRequest) override; virtual void request_file(Web::FileRequest) override;
virtual void schedule_repaint() override {}; virtual void schedule_repaint() override {};