diff --git a/Userland/Libraries/LibWeb/HTML/EventLoop/EventLoop.cpp b/Userland/Libraries/LibWeb/HTML/EventLoop/EventLoop.cpp index 0c3d586f9c9..dfcd55c15d9 100644 --- a/Userland/Libraries/LibWeb/HTML/EventLoop/EventLoop.cpp +++ b/Userland/Libraries/LibWeb/HTML/EventLoop/EventLoop.cpp @@ -605,4 +605,46 @@ double EventLoop::compute_deadline() const return deadline; } +EventLoop::PauseHandle::PauseHandle(EventLoop& event_loop, JS::Object const& global, HighResolutionTime::DOMHighResTimeStamp time_before_pause) + : event_loop(event_loop) + , global(global) + , time_before_pause(time_before_pause) +{ +} + +EventLoop::PauseHandle::~PauseHandle() +{ + event_loop->unpause({}, *global, time_before_pause); +} + +// https://html.spec.whatwg.org/multipage/webappapis.html#pause +EventLoop::PauseHandle EventLoop::pause() +{ + // 1. Let global be the current global object. + auto& global = current_principal_global_object(); + + // 2. Let timeBeforePause be the current high resolution time given global. + auto time_before_pause = HighResolutionTime::current_high_resolution_time(global); + + // 3. If necessary, update the rendering or user interface of any Document or navigable to reflect the current state. + if (!m_is_running_rendering_task) + update_the_rendering(); + + // 4. Wait until the condition goal is met. While a user agent has a paused task, the corresponding event loop must + // not run further tasks, and any script in the currently running task must block. User agents should remain + // responsive to user input while paused, however, albeit in a reduced capacity since the event loop will not be + // doing anything. + m_execution_paused = true; + + return PauseHandle { *this, global, time_before_pause }; +} + +void EventLoop::unpause(Badge, JS::Object const& global, HighResolutionTime::DOMHighResTimeStamp time_before_pause) +{ + m_execution_paused = false; + + // FIXME: 5. Record pause duration given the duration from timeBeforePause to the current high resolution time given global. + [[maybe_unused]] auto pause_duration = HighResolutionTime::current_high_resolution_time(global) - time_before_pause; +} + } diff --git a/Userland/Libraries/LibWeb/HTML/EventLoop/EventLoop.h b/Userland/Libraries/LibWeb/HTML/EventLoop/EventLoop.h index b743ab6ab40..f33ca7faa99 100644 --- a/Userland/Libraries/LibWeb/HTML/EventLoop/EventLoop.h +++ b/Userland/Libraries/LibWeb/HTML/EventLoop/EventLoop.h @@ -7,10 +7,13 @@ #pragma once #include +#include #include #include #include +#include #include +#include namespace Web::HTML { @@ -18,6 +21,18 @@ class EventLoop : public JS::Cell { JS_CELL(EventLoop, JS::Cell); JS_DECLARE_ALLOCATOR(EventLoop); + struct PauseHandle { + PauseHandle(EventLoop&, JS::Object const& global, HighResolutionTime::DOMHighResTimeStamp); + ~PauseHandle(); + + AK_MAKE_NONCOPYABLE(PauseHandle); + AK_MAKE_NONMOVABLE(PauseHandle); + + JS::NonnullGCPtr event_loop; + JS::NonnullGCPtr global; + HighResolutionTime::DOMHighResTimeStamp const time_before_pause; + }; + public: enum class Type { // https://html.spec.whatwg.org/multipage/webappapis.html#window-event-loop @@ -71,8 +86,8 @@ public: double compute_deadline() const; - // https://html.spec.whatwg.org/multipage/webappapis.html#pause - void set_execution_paused(bool execution_paused) { m_execution_paused = execution_paused; } + [[nodiscard]] PauseHandle pause(); + void unpause(Badge, JS::Object const& global, HighResolutionTime::DOMHighResTimeStamp); bool execution_paused() const { return m_execution_paused; } private: diff --git a/Userland/Libraries/LibWeb/Page/Page.cpp b/Userland/Libraries/LibWeb/Page/Page.cpp index d14bfc957ea..08336a847ed 100644 --- a/Userland/Libraries/LibWeb/Page/Page.cpp +++ b/Userland/Libraries/LibWeb/Page/Page.cpp @@ -6,7 +6,6 @@ * SPDX-License-Identifier: BSD-2-Clause */ -#include #include #include #include @@ -265,9 +264,7 @@ template static ResponseType spin_event_loop_until_dialog_closed(PageClient& client, Optional& response, SourceLocation location = SourceLocation::current()) { auto& event_loop = Web::HTML::current_principal_settings_object().responsible_event_loop(); - - ScopeGuard guard { [&] { event_loop.set_execution_paused(false); } }; - event_loop.set_execution_paused(true); + auto pause_handle = event_loop.pause(); Web::Platform::EventLoopPlugin::the().spin_until(JS::create_heap_function(event_loop.heap(), [&]() { return response.has_value() || !client.is_connection_open();