mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2026-04-19 02:10:26 +00:00
The inert temporary documents used for fragment parsing will never become "fully active" and so any tasks associated with them will never run. To avoid memory leaks, we now simply ignore any attempts to enqueue tasks associated with such documents.
110 lines
2.6 KiB
C++
110 lines
2.6 KiB
C++
/*
|
|
* Copyright (c) 2021-2025, Andreas Kling <andreas@ladybird.org>
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#include <LibGC/RootVector.h>
|
|
#include <LibWeb/DOM/Document.h>
|
|
#include <LibWeb/HTML/EventLoop/EventLoop.h>
|
|
#include <LibWeb/HTML/EventLoop/TaskQueue.h>
|
|
|
|
namespace Web::HTML {
|
|
|
|
GC_DEFINE_ALLOCATOR(TaskQueue);
|
|
|
|
TaskQueue::TaskQueue(HTML::EventLoop& event_loop)
|
|
: m_event_loop(event_loop)
|
|
{
|
|
}
|
|
|
|
TaskQueue::~TaskQueue() = default;
|
|
|
|
void TaskQueue::visit_edges(Visitor& visitor)
|
|
{
|
|
Base::visit_edges(visitor);
|
|
visitor.visit(m_event_loop);
|
|
visitor.visit(m_tasks);
|
|
}
|
|
|
|
void TaskQueue::add(GC::Ref<Task> task)
|
|
{
|
|
// AD-HOC: Don't enqueue tasks for temporary (inert) documents used for fragment parsing.
|
|
// FIXME: There's ongoing spec work to remove such documents: https://github.com/whatwg/html/pull/11970
|
|
if (task->document() && task->document()->is_temporary_document_for_fragment_parsing())
|
|
return;
|
|
|
|
m_tasks.append(task);
|
|
m_event_loop->schedule();
|
|
}
|
|
|
|
GC::Ptr<Task> TaskQueue::take_first_runnable()
|
|
{
|
|
if (m_event_loop->execution_paused())
|
|
return nullptr;
|
|
|
|
for (size_t i = 0; i < m_tasks.size(); ++i) {
|
|
if (m_event_loop->running_rendering_task() && m_tasks[i]->source() == Task::Source::Rendering)
|
|
continue;
|
|
if (m_tasks[i]->is_runnable())
|
|
return m_tasks.take(i);
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
bool TaskQueue::has_runnable_tasks() const
|
|
{
|
|
if (m_event_loop->execution_paused())
|
|
return false;
|
|
|
|
for (auto& task : m_tasks) {
|
|
if (m_event_loop->running_rendering_task() && task->source() == Task::Source::Rendering)
|
|
continue;
|
|
if (task->is_runnable())
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void TaskQueue::remove_tasks_matching(Function<bool(HTML::Task const&)> filter)
|
|
{
|
|
m_tasks.remove_all_matching([&](auto& task) {
|
|
return filter(*task);
|
|
});
|
|
}
|
|
|
|
GC::RootVector<GC::Ref<Task>> TaskQueue::take_tasks_matching(Function<bool(HTML::Task const&)> filter)
|
|
{
|
|
GC::RootVector<GC::Ref<Task>> matching_tasks(heap());
|
|
|
|
for (size_t i = 0; i < m_tasks.size();) {
|
|
auto& task = m_tasks.at(i);
|
|
|
|
if (filter(*task)) {
|
|
matching_tasks.append(task);
|
|
m_tasks.remove(i);
|
|
} else {
|
|
++i;
|
|
}
|
|
}
|
|
|
|
return matching_tasks;
|
|
}
|
|
|
|
Task const* TaskQueue::last_added_task() const
|
|
{
|
|
if (m_tasks.is_empty())
|
|
return nullptr;
|
|
return m_tasks.last();
|
|
}
|
|
|
|
bool TaskQueue::has_rendering_tasks() const
|
|
{
|
|
for (auto const& task : m_tasks) {
|
|
if (task->source() == Task::Source::Rendering)
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
}
|