2021-09-08 23:09:18 +02:00
/*
* Copyright ( c ) 2021 , Andreas Kling < kling @ serenityos . org >
2022-03-31 21:55:01 +02:00
* Copyright ( c ) 2022 , the SerenityOS developers .
2021-09-08 23:09:18 +02:00
*
* SPDX - License - Identifier : BSD - 2 - Clause
*/
2024-01-18 13:02:24 -07:00
# include <LibCore/EventLoop.h>
2021-09-08 23:09:18 +02:00
# include <LibJS/Runtime/VM.h>
# include <LibWeb/Bindings/MainThreadVM.h>
2021-10-03 16:07:21 +02:00
# include <LibWeb/DOM/Document.h>
2021-11-18 15:01:28 +01:00
# include <LibWeb/HTML/BrowsingContext.h>
2021-09-08 23:09:18 +02:00
# include <LibWeb/HTML/EventLoop/EventLoop.h>
2021-10-14 16:12:53 +01:00
# include <LibWeb/HTML/Scripting/Environments.h>
2022-03-07 23:08:26 +01:00
# include <LibWeb/HTML/Window.h>
2021-10-03 16:28:14 +02:00
# include <LibWeb/HighResolutionTime/Performance.h>
2022-10-04 21:30:29 +01:00
# include <LibWeb/HighResolutionTime/TimeOrigin.h>
2024-02-18 19:40:11 +01:00
# include <LibWeb/Page/Page.h>
2022-09-07 20:30:31 +02:00
# include <LibWeb/Platform/EventLoopPlugin.h>
# include <LibWeb/Platform/Timer.h>
2021-09-08 23:09:18 +02:00
namespace Web : : HTML {
EventLoop : : EventLoop ( )
2021-09-09 00:38:43 +02:00
: m_task_queue ( * this )
2021-09-26 14:36:20 +02:00
, m_microtask_queue ( * this )
2021-09-08 23:09:18 +02:00
{
}
2022-03-14 13:21:51 -06:00
EventLoop : : ~ EventLoop ( ) = default ;
2021-09-08 23:09:18 +02:00
2021-09-09 00:38:43 +02:00
void EventLoop : : schedule ( )
{
if ( ! m_system_event_loop_timer ) {
2022-09-07 20:30:31 +02:00
m_system_event_loop_timer = Platform : : Timer : : create_single_shot ( 0 , [ this ] {
2021-09-09 00:38:43 +02:00
process ( ) ;
} ) ;
}
if ( ! m_system_event_loop_timer - > is_active ( ) )
m_system_event_loop_timer - > restart ( ) ;
}
2021-09-09 00:27:06 +02:00
void EventLoop : : set_vm ( JS : : VM & vm )
{
VERIFY ( ! m_vm ) ;
m_vm = & vm ;
}
2021-09-08 23:09:18 +02:00
EventLoop & main_thread_event_loop ( )
{
return static_cast < Bindings : : WebEngineCustomData * > ( Bindings : : main_thread_vm ( ) . custom_data ( ) ) - > event_loop ;
}
2021-09-08 23:50:32 +02:00
// https://html.spec.whatwg.org/multipage/webappapis.html#spin-the-event-loop
2023-04-21 12:13:04 +01:00
void EventLoop : : spin_until ( JS : : SafeFunction < bool ( ) > goal_condition )
2021-09-08 23:50:32 +02:00
{
2024-01-18 13:02:24 -07:00
// FIXME: The spec wants us to do the rest of the enclosing algorithm (i.e. the caller)
// in the context of the currently running task on entry. That's not possible with this implementation.
// 1. Let task be the event loop's currently running task.
// 2. Let task source be task's source.
2021-09-08 23:50:32 +02:00
2021-10-03 14:54:01 +02:00
// 3. Let old stack be a copy of the JavaScript execution context stack.
// 4. Empty the JavaScript execution context stack.
2024-01-18 13:02:24 -07:00
m_vm - > save_execution_context_stack ( ) ;
m_vm - > clear_execution_context_stack ( ) ;
2021-09-08 23:50:32 +02:00
2021-10-03 14:54:01 +02:00
// 5. Perform a microtask checkpoint.
perform_a_microtask_checkpoint ( ) ;
2021-09-08 23:50:32 +02:00
2021-10-03 14:54:01 +02:00
// 6. In parallel:
2024-01-18 13:02:24 -07:00
// 1. Wait until the condition goal is met.
2021-10-03 14:54:01 +02:00
// 2. Queue a task on task source to:
// 1. Replace the JavaScript execution context stack with old stack.
// 2. Perform any steps that appear after this spin the event loop instance in the original algorithm.
// NOTE: This is achieved by returning from the function.
2021-09-08 23:50:32 +02:00
2024-01-18 13:02:24 -07:00
Platform : : EventLoopPlugin : : the ( ) . spin_until ( [ & ] {
if ( goal_condition ( ) )
return true ;
if ( m_task_queue . has_runnable_tasks ( ) ) {
schedule ( ) ;
// FIXME: Remove the platform event loop plugin so that this doesn't look out of place
Core : : EventLoop : : current ( ) . wake ( ) ;
}
return goal_condition ( ) ;
} ) ;
m_vm - > restore_execution_context_stack ( ) ;
2021-09-08 23:50:32 +02:00
2021-10-03 14:54:01 +02:00
// 7. Stop task, allowing whatever algorithm that invoked it to resume.
// NOTE: This is achieved by returning from the function.
2021-09-08 23:50:32 +02:00
}
2021-09-09 00:18:04 +02:00
// https://html.spec.whatwg.org/multipage/webappapis.html#event-loop-processing-model
void EventLoop : : process ( )
{
// An event loop must continually run through the following steps for as long as it exists:
2022-03-31 21:55:01 +02:00
// 1. Let oldestTask be null.
OwnPtr < Task > oldest_task ;
// 2. Let taskStartTime be the current high resolution time.
// FIXME: 'current high resolution time' in hr-time-3 takes a global object,
// the HTML spec has not been updated to reflect this, let's use the shared timer.
// - https://github.com/whatwg/html/issues/7776
2022-10-04 21:25:00 +01:00
double task_start_time = HighResolutionTime : : unsafe_shared_current_time ( ) ;
2022-03-31 21:55:01 +02:00
// 3. Let taskQueue be one of the event loop's task queues, chosen in an implementation-defined manner,
// with the constraint that the chosen task queue must contain at least one runnable task.
// If there is no such task queue, then jump to the microtasks step below.
2021-09-09 00:18:04 +02:00
auto & task_queue = m_task_queue ;
2022-03-31 21:55:01 +02:00
// 4. Set oldestTask to the first runnable task in taskQueue, and remove it from taskQueue.
oldest_task = task_queue . take_first_runnable ( ) ;
2021-09-09 00:18:04 +02:00
2022-03-31 21:55:01 +02:00
if ( oldest_task ) {
// 5. Set the event loop's currently running task to oldestTask.
2021-09-26 14:36:20 +02:00
m_currently_running_task = oldest_task . ptr ( ) ;
2021-09-09 00:38:43 +02:00
2022-03-31 21:55:01 +02:00
// 6. Perform oldestTask's steps.
2021-09-26 14:36:20 +02:00
oldest_task - > execute ( ) ;
2021-09-09 00:18:04 +02:00
2022-03-31 21:55:01 +02:00
// 7. Set the event loop's currently running task back to null.
2021-09-26 14:36:20 +02:00
m_currently_running_task = nullptr ;
}
2021-09-09 00:18:04 +02:00
2022-03-31 21:55:01 +02:00
// 8. Microtasks: Perform a microtask checkpoint.
2021-09-26 14:36:20 +02:00
perform_a_microtask_checkpoint ( ) ;
2021-09-09 00:18:04 +02:00
2022-03-31 21:55:01 +02:00
// 9. Let hasARenderingOpportunity be false.
2021-09-09 00:18:04 +02:00
[[maybe_unused]] bool has_a_rendering_opportunity = false ;
2022-03-31 21:55:01 +02:00
// FIXME: 10. Let now be the current high resolution time. [HRT]
2021-09-09 00:18:04 +02:00
2022-03-31 21:55:01 +02:00
// FIXME: 11. If oldestTask is not null, then:
2021-09-09 00:18:04 +02:00
// FIXME: 1. Let top-level browsing contexts be an empty set.
// FIXME: 2. For each environment settings object settings of oldestTask's script evaluation environment settings object set, append setting's top-level browsing context to top-level browsing contexts.
// FIXME: 3. Report long tasks, passing in taskStartTime, now (the end time of the task), top-level browsing contexts, and oldestTask.
2022-03-31 21:55:01 +02:00
// FIXME: 12. Update the rendering: if this is a window event loop, then:
2021-09-09 00:18:04 +02:00
// FIXME: 1. Let docs be all Document objects whose relevant agent's event loop is this event loop, sorted arbitrarily except that the following conditions must be met:
// - Any Document B whose browsing context's container document is A must be listed after A in the list.
// - If there are two documents A and B whose browsing contexts are both child browsing contexts whose container documents are another Document C, then the order of A and B in the list must match the shadow-including tree order of their respective browsing context containers in C's node tree.
2021-10-03 16:28:14 +02:00
// FIXME: NOTE: The sort order specified above is missing here!
2022-08-28 13:42:07 +02:00
Vector < JS : : Handle < DOM : : Document > > docs = documents_in_this_event_loop ( ) ;
2021-10-03 16:28:14 +02:00
auto for_each_fully_active_document_in_docs = [ & ] ( auto & & callback ) {
for ( auto & document : docs ) {
2022-08-28 13:42:07 +02:00
if ( document - > is_fully_active ( ) )
callback ( * document ) ;
2021-10-03 16:28:14 +02:00
}
} ;
2021-09-09 00:18:04 +02:00
2023-09-20 08:09:59 +02:00
// 2. Rendering opportunities: Remove from docs all Document objects whose node navigables do not have a rendering opportunity.
2021-10-03 17:05:58 +02:00
docs . remove_all_matching ( [ & ] ( auto & document ) {
2023-09-20 08:09:59 +02:00
return document - > navigable ( ) & & ! document - > navigable ( ) - > has_a_rendering_opportunity ( ) ;
2021-10-03 17:05:58 +02:00
} ) ;
2021-09-09 00:18:04 +02:00
2022-03-31 21:55:01 +02:00
// 3. If docs is not empty, then set hasARenderingOpportunity to true
// and set this event loop's last render opportunity time to taskStartTime.
if ( ! docs . is_empty ( ) ) {
2021-10-03 16:28:14 +02:00
has_a_rendering_opportunity = true ;
2022-03-31 21:55:01 +02:00
m_last_render_opportunity_time = task_start_time ;
}
2021-09-09 00:18:04 +02:00
// FIXME: 4. Unnecessary rendering: Remove from docs all Document objects which meet both of the following conditions:
// - The user agent believes that updating the rendering of the Document's browsing context would have no visible effect, and
// - The Document's map of animation frame callbacks is empty.
2023-07-06 23:44:07 +01:00
// https://www.w3.org/TR/intersection-observer/#pending-initial-observation
// In the HTML Event Loops Processing Model, under the "Update the rendering" step, the "Unnecessary rendering" step should be
// modified to add an additional requirement for skipping the rendering update:
// - The document does not have pending initial IntersectionObserver targets.
2021-09-09 00:18:04 +02:00
2022-05-29 11:50:10 +01:00
// FIXME: 5. Remove from docs all Document objects for which the user agent believes that it's preferable to skip updating the rendering for other reasons.
2021-09-09 00:18:04 +02:00
// FIXME: 6. For each fully active Document in docs, flush autofocus candidates for that Document if its browsing context is a top-level browsing context.
2021-10-03 16:42:03 +02:00
// 7. For each fully active Document in docs, run the resize steps for that Document, passing in now as the timestamp. [CSSOMVIEW]
for_each_fully_active_document_in_docs ( [ & ] ( DOM : : Document & document ) {
document . run_the_resize_steps ( ) ;
} ) ;
2021-09-09 00:18:04 +02:00
2022-09-17 17:40:26 +02:00
// 8. For each fully active Document in docs, run the scroll steps for that Document, passing in now as the timestamp. [CSSOMVIEW]
for_each_fully_active_document_in_docs ( [ & ] ( DOM : : Document & document ) {
document . run_the_scroll_steps ( ) ;
} ) ;
2021-09-09 00:18:04 +02:00
2021-10-04 17:41:35 +01:00
// 9. For each fully active Document in docs, evaluate media queries and report changes for that Document, passing in now as the timestamp. [CSSOMVIEW]
for_each_fully_active_document_in_docs ( [ & ] ( DOM : : Document & document ) {
document . evaluate_media_queries_and_report_changes ( ) ;
} ) ;
2021-09-09 00:18:04 +02:00
// FIXME: 10. For each fully active Document in docs, update animations and send events for that Document, passing in now as the timestamp. [WEBANIMATIONS]
// FIXME: 11. For each fully active Document in docs, run the fullscreen steps for that Document, passing in now as the timestamp. [FULLSCREEN]
// FIXME: 12. For each fully active Document in docs, if the user agent detects that the backing storage associated with a CanvasRenderingContext2D or an OffscreenCanvasRenderingContext2D, context, has been lost, then it must run the context lost steps for each such context:
// FIXME: 13. For each fully active Document in docs, run the animation frame callbacks for that Document, passing in now as the timestamp.
2023-03-06 19:50:46 +00:00
auto now = HighResolutionTime : : unsafe_shared_current_time ( ) ;
2021-10-03 16:28:14 +02:00
for_each_fully_active_document_in_docs ( [ & ] ( DOM : : Document & document ) {
2023-03-06 19:50:46 +00:00
run_animation_frame_callbacks ( document , now ) ;
2021-10-03 16:28:14 +02:00
} ) ;
2021-09-09 00:18:04 +02:00
2024-02-19 05:10:05 +01:00
// FIXME: This step is implemented following the latest specification, while the rest of this method uses an outdated spec.
// NOTE: Gathering and broadcasting of resize observations need to happen after evaluating media queries but before
// updating intersection observations steps.
for_each_fully_active_document_in_docs ( [ & ] ( DOM : : Document & document ) {
// 1. Let resizeObserverDepth be 0.
size_t resize_observer_depth = 0 ;
// 2. While true:
while ( true ) {
// 1. Recalculate styles and update layout for doc.
// NOTE: Recalculation of styles is handled by update_layout()
document . update_layout ( ) ;
// FIXME: 2. Let hadInitialVisibleContentVisibilityDetermination be false.
// FIXME: 3. For each element element with 'auto' used value of 'content-visibility':
// FIXME: 4. If hadInitialVisibleContentVisibilityDetermination is true, then continue.
// 5. Gather active resize observations at depth resizeObserverDepth for doc.
document . gather_active_observations_at_depth ( resize_observer_depth ) ;
// 6. If doc has active resize observations:
if ( document . has_active_resize_observations ( ) ) {
// 1. Set resizeObserverDepth to the result of broadcasting active resize observations given doc.
resize_observer_depth = document . broadcast_active_resize_observations ( ) ;
// 2. Continue.
continue ;
}
// 7. Otherwise, break.
break ;
}
// 3. If doc has skipped resize observations, then deliver resize loop error given doc.
if ( document . has_skipped_resize_observations ( ) ) {
// FIXME: Deliver resize loop error.
}
} ) ;
2023-07-06 23:44:07 +01:00
// 14. For each fully active Document in docs, run the update intersection observations steps for that Document, passing in now as the timestamp. [INTERSECTIONOBSERVER]
for_each_fully_active_document_in_docs ( [ & ] ( DOM : : Document & document ) {
document . run_the_update_intersection_observations_steps ( now ) ;
} ) ;
2021-09-09 00:18:04 +02:00
// FIXME: 15. Invoke the mark paint timing algorithm for each Document object in docs.
2024-02-18 19:40:11 +01:00
// 16. For each fully active Document in docs, update the rendering or user interface of that Document and its browsing context to reflect the current state.
for_each_fully_active_document_in_docs ( [ & ] ( DOM : : Document & document ) {
auto * browsing_context = document . browsing_context ( ) ;
auto & page = browsing_context - > page ( ) ;
page . client ( ) . schedule_repaint ( ) ;
} ) ;
2021-09-09 00:18:04 +02:00
2022-03-31 21:55:01 +02:00
// 13. If all of the following are true
// - this is a window event loop
// - there is no task in this event loop's task queues whose document is fully active
// - this event loop's microtask queue is empty
// - hasARenderingOpportunity is false
// FIXME: has_a_rendering_opportunity is always true
if ( m_type = = Type : : Window & & ! task_queue . has_runnable_tasks ( ) & & m_microtask_queue . is_empty ( ) /*&& !has_a_rendering_opportunity*/ ) {
// 1. Set this event loop's last idle period start time to the current high resolution time.
2022-10-04 21:25:00 +01:00
m_last_idle_period_start_time = HighResolutionTime : : unsafe_shared_current_time ( ) ;
2022-03-31 21:55:01 +02:00
// 2. Let computeDeadline be the following steps:
// NOTE: instead of passing around a function we use this event loop, which has compute_deadline()
// 3. For each win of the same-loop windows for this event loop,
// perform the start an idle period algorithm for win with computeDeadline. [REQUESTIDLECALLBACK]
for ( auto & win : same_loop_windows ( ) )
2022-08-28 13:42:07 +02:00
win - > start_an_idle_period ( ) ;
2022-03-31 21:55:01 +02:00
}
2021-09-09 00:18:04 +02:00
2022-03-31 21:55:01 +02:00
// FIXME: 14. If this is a worker event loop, then:
2021-09-09 00:18:04 +02:00
// FIXME: 1. If this event loop's agent's single realm's global object is a supported DedicatedWorkerGlobalScope and the user agent believes that it would benefit from having its rendering updated at this time, then:
// FIXME: 1. Let now be the current high resolution time. [HRT]
// FIXME: 2. Run the animation frame callbacks for that DedicatedWorkerGlobalScope, passing in now as the timestamp.
// FIXME: 3. Update the rendering of that dedicated worker to reflect the current state.
// FIXME: 2. If there are no tasks in the event loop's task queues and the WorkerGlobalScope object's closing flag is true, then destroy the event loop, aborting these steps, resuming the run a worker steps described in the Web workers section below.
2021-09-09 00:38:43 +02:00
2023-04-01 11:11:36 +02:00
// If there are eligible tasks in the queue, schedule a new round of processing. :^)
if ( m_task_queue . has_runnable_tasks ( ) | | ( ! m_microtask_queue . is_empty ( ) & & ! m_performing_a_microtask_checkpoint ) )
2021-09-09 00:38:43 +02:00
schedule ( ) ;
2021-09-09 00:18:04 +02:00
}
2021-10-14 16:12:53 +01:00
// https://html.spec.whatwg.org/multipage/webappapis.html#queue-a-global-task
2022-09-24 12:04:06 +02:00
void queue_global_task ( HTML : : Task : : Source source , JS : : Object & global_object , JS : : SafeFunction < void ( ) > steps )
2021-10-14 16:12:53 +01:00
{
// 1. Let event loop be global's relevant agent's event loop.
auto & global_custom_data = verify_cast < Bindings : : WebEngineCustomData > ( * global_object . vm ( ) . custom_data ( ) ) ;
auto & event_loop = global_custom_data . event_loop ;
// 2. Let document be global's associated Document, if global is a Window object; otherwise null.
DOM : : Document * document { nullptr } ;
2022-08-28 13:42:07 +02:00
if ( is < HTML : : Window > ( global_object ) ) {
auto & window_object = verify_cast < HTML : : Window > ( global_object ) ;
2022-09-21 17:45:18 +01:00
document = & window_object . associated_document ( ) ;
2021-10-14 16:12:53 +01:00
}
// 3. Queue a task given source, event loop, document, and steps.
event_loop . task_queue ( ) . add ( HTML : : Task : : create ( source , document , move ( steps ) ) ) ;
}
2021-09-26 14:36:20 +02:00
// https://html.spec.whatwg.org/#queue-a-microtask
2023-02-25 10:44:51 -07:00
void queue_a_microtask ( DOM : : Document const * document , JS : : SafeFunction < void ( ) > steps )
2021-09-26 14:36:20 +02:00
{
// 1. If event loop was not given, set event loop to the implied event loop.
auto & event_loop = HTML : : main_thread_event_loop ( ) ;
// FIXME: 2. If document was not given, set document to the implied document.
// 3. Let microtask be a new task.
// 4. Set microtask's steps to steps.
// 5. Set microtask's source to the microtask task source.
// 6. Set microtask's document to document.
2021-10-14 16:12:53 +01:00
auto microtask = HTML : : Task : : create ( HTML : : Task : : Source : : Microtask , document , move ( steps ) ) ;
2021-09-26 14:36:20 +02:00
// FIXME: 7. Set microtask's script evaluation environment settings object set to an empty set.
// 8. Enqueue microtask on event loop's microtask queue.
event_loop . microtask_queue ( ) . enqueue ( move ( microtask ) ) ;
}
2022-03-28 03:21:57 +04:30
void perform_a_microtask_checkpoint ( )
{
main_thread_event_loop ( ) . perform_a_microtask_checkpoint ( ) ;
}
2021-09-26 14:36:20 +02:00
// https://html.spec.whatwg.org/#perform-a-microtask-checkpoint
void EventLoop : : perform_a_microtask_checkpoint ( )
{
// 1. If the event loop's performing a microtask checkpoint is true, then return.
if ( m_performing_a_microtask_checkpoint )
return ;
// 2. Set the event loop's performing a microtask checkpoint to true.
m_performing_a_microtask_checkpoint = true ;
// 3. While the event loop's microtask queue is not empty:
while ( ! m_microtask_queue . is_empty ( ) ) {
// 1. Let oldestMicrotask be the result of dequeuing from the event loop's microtask queue.
auto oldest_microtask = m_microtask_queue . dequeue ( ) ;
// 2. Set the event loop's currently running task to oldestMicrotask.
m_currently_running_task = oldest_microtask ;
// 3. Run oldestMicrotask.
oldest_microtask - > execute ( ) ;
// 4. Set the event loop's currently running task back to null.
m_currently_running_task = nullptr ;
}
2021-10-14 16:12:53 +01:00
// 4. For each environment settings object whose responsible event loop is this event loop, notify about rejected promises on that environment settings object.
for ( auto & environment_settings_object : m_related_environment_settings_objects )
2023-02-26 16:09:02 -07:00
environment_settings_object - > notify_about_rejected_promises ( { } ) ;
2021-09-26 14:36:20 +02:00
// FIXME: 5. Cleanup Indexed Database transactions.
2022-02-06 03:32:26 +00:00
// 6. Perform ClearKeptObjects().
vm ( ) . finish_execution_generation ( ) ;
2021-09-26 14:36:20 +02:00
// 7. Set the event loop's performing a microtask checkpoint to false.
m_performing_a_microtask_checkpoint = false ;
}
2022-08-28 13:42:07 +02:00
Vector < JS : : Handle < DOM : : Document > > EventLoop : : documents_in_this_event_loop ( ) const
2021-10-03 16:07:21 +02:00
{
2022-08-28 13:42:07 +02:00
Vector < JS : : Handle < DOM : : Document > > documents ;
2021-10-03 16:07:21 +02:00
for ( auto & document : m_documents ) {
VERIFY ( document ) ;
2022-12-14 18:37:37 +00:00
documents . append ( JS : : make_handle ( * document ) ) ;
2021-10-03 16:07:21 +02:00
}
return documents ;
}
void EventLoop : : register_document ( Badge < DOM : : Document > , DOM : : Document & document )
{
m_documents . append ( & document ) ;
}
void EventLoop : : unregister_document ( Badge < DOM : : Document > , DOM : : Document & document )
{
bool did_remove = m_documents . remove_first_matching ( [ & ] ( auto & entry ) { return entry . ptr ( ) = = & document ; } ) ;
VERIFY ( did_remove ) ;
}
2021-10-14 16:12:53 +01:00
void EventLoop : : push_onto_backup_incumbent_settings_object_stack ( Badge < EnvironmentSettingsObject > , EnvironmentSettingsObject & environment_settings_object )
{
m_backup_incumbent_settings_object_stack . append ( environment_settings_object ) ;
}
void EventLoop : : pop_backup_incumbent_settings_object_stack ( Badge < EnvironmentSettingsObject > )
{
m_backup_incumbent_settings_object_stack . take_last ( ) ;
}
EnvironmentSettingsObject & EventLoop : : top_of_backup_incumbent_settings_object_stack ( )
{
return m_backup_incumbent_settings_object_stack . last ( ) ;
}
void EventLoop : : register_environment_settings_object ( Badge < EnvironmentSettingsObject > , EnvironmentSettingsObject & environment_settings_object )
{
m_related_environment_settings_objects . append ( environment_settings_object ) ;
}
void EventLoop : : unregister_environment_settings_object ( Badge < EnvironmentSettingsObject > , EnvironmentSettingsObject & environment_settings_object )
{
2023-02-26 16:09:02 -07:00
bool did_remove = m_related_environment_settings_objects . remove_first_matching ( [ & ] ( auto & entry ) { return entry . ptr ( ) = = & environment_settings_object ; } ) ;
2021-10-14 16:12:53 +01:00
VERIFY ( did_remove ) ;
}
2022-03-31 21:55:01 +02:00
// https://html.spec.whatwg.org/multipage/webappapis.html#same-loop-windows
2022-08-28 13:42:07 +02:00
Vector < JS : : Handle < HTML : : Window > > EventLoop : : same_loop_windows ( ) const
2022-03-31 21:55:01 +02:00
{
2022-08-28 13:42:07 +02:00
Vector < JS : : Handle < HTML : : Window > > windows ;
2022-09-25 16:38:21 -06:00
for ( auto & document : documents_in_this_event_loop ( ) ) {
if ( document - > is_fully_active ( ) )
windows . append ( JS : : make_handle ( document - > window ( ) ) ) ;
}
2022-03-31 21:55:01 +02:00
return windows ;
}
// https://html.spec.whatwg.org/multipage/webappapis.html#event-loop-processing-model:last-idle-period-start-time
double EventLoop : : compute_deadline ( ) const
{
// 1. Let deadline be this event loop's last idle period start time plus 50.
auto deadline = m_last_idle_period_start_time + 50 ;
// 2. Let hasPendingRenders be false.
auto has_pending_renders = false ;
// 3. For each windowInSameLoop of the same-loop windows for this event loop:
for ( auto & window : same_loop_windows ( ) ) {
// 1. If windowInSameLoop's map of animation frame callbacks is not empty,
// or if the user agent believes that the windowInSameLoop might have pending rendering updates,
// set hasPendingRenders to true.
2022-08-28 13:42:07 +02:00
if ( window - > has_animation_frame_callbacks ( ) )
2022-03-31 21:55:01 +02:00
has_pending_renders = true ;
// FIXME: 2. Let timerCallbackEstimates be the result of getting the values of windowInSameLoop's map of active timers.
// FIXME: 3. For each timeoutDeadline of timerCallbackEstimates, if timeoutDeadline is less than deadline, set deadline to timeoutDeadline.
}
// 4. If hasPendingRenders is true, then:
if ( has_pending_renders ) {
// 1. Let nextRenderDeadline be this event loop's last render opportunity time plus (1000 divided by the current refresh rate).
// FIXME: Hardcoded to 60Hz
auto next_render_deadline = m_last_render_opportunity_time + ( 1000.0 / 60.0 ) ;
// 2. If nextRenderDeadline is less than deadline, then return nextRenderDeadline.
if ( next_render_deadline < deadline )
return next_render_deadline ;
}
// 5. Return deadline.
return deadline ;
}
2021-09-08 23:09:18 +02:00
}