diff --git a/Tests/LibWeb/Text/expected/navigation/remove-iframe-from-timeout-callback.txt b/Tests/LibWeb/Text/expected/navigation/remove-iframe-from-timeout-callback.txt new file mode 100644 index 00000000000..136d06384a4 --- /dev/null +++ b/Tests/LibWeb/Text/expected/navigation/remove-iframe-from-timeout-callback.txt @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Tests/LibWeb/Text/input/navigation/remove-iframe-from-timeout-callback.html b/Tests/LibWeb/Text/input/navigation/remove-iframe-from-timeout-callback.html new file mode 100644 index 00000000000..e6de8c2e329 --- /dev/null +++ b/Tests/LibWeb/Text/input/navigation/remove-iframe-from-timeout-callback.html @@ -0,0 +1,12 @@ + +
+ + +
+ diff --git a/Userland/Libraries/LibWeb/HTML/EventLoop/EventLoop.cpp b/Userland/Libraries/LibWeb/HTML/EventLoop/EventLoop.cpp index b3138ec1f81..bebef552a14 100644 --- a/Userland/Libraries/LibWeb/HTML/EventLoop/EventLoop.cpp +++ b/Userland/Libraries/LibWeb/HTML/EventLoop/EventLoop.cpp @@ -92,9 +92,49 @@ void EventLoop::spin_until(JS::SafeFunction goal_condition) // NOTE: This is achieved by returning from the function. } +void EventLoop::spin_processing_tasks_with_source_until(Task::Source source, JS::SafeFunction goal_condition) +{ + m_vm->save_execution_context_stack(); + m_vm->clear_execution_context_stack(); + + perform_a_microtask_checkpoint(); + + // NOTE: HTML event loop processing steps could run a task with arbitrary source + m_skip_event_loop_processing_steps = true; + + Platform::EventLoopPlugin::the().spin_until([&] { + if (goal_condition()) + return true; + if (m_task_queue.has_runnable_tasks()) { + auto tasks = m_task_queue.take_tasks_matching([&](auto& task) { + return task.source() == source; + }); + + for (auto& task : tasks.value()) { + m_currently_running_task = task.ptr(); + task->execute(); + m_currently_running_task = nullptr; + } + } + + // FIXME: Remove the platform event loop plugin so that this doesn't look out of place + Core::EventLoop::current().wake(); + return goal_condition(); + }); + + m_skip_event_loop_processing_steps = false; + + schedule(); + + m_vm->restore_execution_context_stack(); +} + // https://html.spec.whatwg.org/multipage/webappapis.html#event-loop-processing-model void EventLoop::process() { + if (m_skip_event_loop_processing_steps) + return; + // An event loop must continually run through the following steps for as long as it exists: // 1. Let oldestTask be null. diff --git a/Userland/Libraries/LibWeb/HTML/EventLoop/EventLoop.h b/Userland/Libraries/LibWeb/HTML/EventLoop/EventLoop.h index c186a520553..019c9af1187 100644 --- a/Userland/Libraries/LibWeb/HTML/EventLoop/EventLoop.h +++ b/Userland/Libraries/LibWeb/HTML/EventLoop/EventLoop.h @@ -38,6 +38,7 @@ public: TaskQueue const& microtask_queue() const { return m_microtask_queue; } void spin_until(JS::SafeFunction goal_condition); + void spin_processing_tasks_with_source_until(Task::Source, JS::SafeFunction goal_condition); void process(); // https://html.spec.whatwg.org/multipage/browsing-the-web.html#termination-nesting-level @@ -110,6 +111,8 @@ private: size_t m_termination_nesting_level { 0 }; bool m_execution_paused { false }; + + bool m_skip_event_loop_processing_steps { false }; }; EventLoop& main_thread_event_loop(); diff --git a/Userland/Libraries/LibWeb/HTML/TraversableNavigable.cpp b/Userland/Libraries/LibWeb/HTML/TraversableNavigable.cpp index e43a617e673..dbc3e750538 100644 --- a/Userland/Libraries/LibWeb/HTML/TraversableNavigable.cpp +++ b/Userland/Libraries/LibWeb/HTML/TraversableNavigable.cpp @@ -543,7 +543,7 @@ TraversableNavigable::HistoryStepResult TraversableNavigable::apply_the_history_ // AD-HOC: Since currently populate_session_history_entry_document does not run in parallel // we call spin_until to interrupt execution of this function and let document population // to complete. - Platform::EventLoopPlugin::the().spin_until([&] { + main_thread_event_loop().spin_processing_tasks_with_source_until(Task::Source::NavigationAndTraversal, [&] { return !changing_navigable_continuations.is_empty() || completed_change_jobs == total_change_jobs; }); @@ -679,7 +679,7 @@ TraversableNavigable::HistoryStepResult TraversableNavigable::apply_the_history_ // AD-HOC: Since currently populate_session_history_entry_document does not run in parallel // we call spin_until to interrupt execution of this function and let document population // to complete. - Platform::EventLoopPlugin::the().spin_until([&] { + main_thread_event_loop().spin_processing_tasks_with_source_until(Task::Source::NavigationAndTraversal, [&] { return completed_non_changing_jobs == total_non_changing_jobs; });