Przeglądaj źródła

LibWeb: Only take runnable tasks from the HTML task queue

We were previously willing to execute tasks before they had become
runnable.
Andreas Kling 3 lat temu
rodzic
commit
bbfde63f79

+ 1 - 2
Userland/Libraries/LibWeb/HTML/EventLoop/EventLoop.cpp

@@ -90,9 +90,8 @@ void EventLoop::process()
     // 1. 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.
     // 1. 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.
     auto& task_queue = m_task_queue;
     auto& task_queue = m_task_queue;
 
 
-    if (!task_queue.is_empty()) {
+    if (auto oldest_task = task_queue.take_first_runnable()) {
         // 2. Let oldestTask be the first runnable task in taskQueue, and remove it from taskQueue.
         // 2. Let oldestTask be the first runnable task in taskQueue, and remove it from taskQueue.
-        auto oldest_task = task_queue.take_first_runnable();
 
 
         // 3. Set the event loop's currently running task to oldestTask.
         // 3. Set the event loop's currently running task to oldestTask.
         m_currently_running_task = oldest_task.ptr();
         m_currently_running_task = oldest_task.ptr();

+ 7 - 0
Userland/Libraries/LibWeb/HTML/EventLoop/Task.cpp

@@ -25,4 +25,11 @@ void Task::execute()
     m_steps();
     m_steps();
 }
 }
 
 
+// https://html.spec.whatwg.org/#concept-task-runnable
+bool Task::is_runnable() const
+{
+    // A task is runnable if its document is either null or fully active.
+    return !m_document || m_document->is_fully_active();
+}
+
 }
 }

+ 2 - 0
Userland/Libraries/LibWeb/HTML/EventLoop/Task.h

@@ -40,6 +40,8 @@ public:
     DOM::Document* document() { return m_document; }
     DOM::Document* document() { return m_document; }
     DOM::Document const* document() const { return m_document; }
     DOM::Document const* document() const { return m_document; }
 
 
+    bool is_runnable() const;
+
 private:
 private:
     Task(Source, DOM::Document*, Function<void()> steps);
     Task(Source, DOM::Document*, Function<void()> steps);
 
 

+ 10 - 1
Userland/Libraries/LibWeb/HTML/EventLoop/TaskQueue.cpp

@@ -20,8 +20,17 @@ TaskQueue::~TaskQueue()
 
 
 void TaskQueue::add(NonnullOwnPtr<Task> task)
 void TaskQueue::add(NonnullOwnPtr<Task> task)
 {
 {
-    m_tasks.enqueue(move(task));
+    m_tasks.append(move(task));
     m_event_loop.schedule();
     m_event_loop.schedule();
 }
 }
 
 
+OwnPtr<Task> TaskQueue::take_first_runnable()
+{
+    for (size_t i = 0; i < m_tasks.size(); ++i) {
+        if (m_tasks[i]->is_runnable())
+            return m_tasks.take(i);
+    }
+    return nullptr;
+}
+
 }
 }

+ 3 - 3
Userland/Libraries/LibWeb/HTML/EventLoop/TaskQueue.h

@@ -19,20 +19,20 @@ public:
     bool is_empty() const { return m_tasks.is_empty(); }
     bool is_empty() const { return m_tasks.is_empty(); }
 
 
     void add(NonnullOwnPtr<HTML::Task>);
     void add(NonnullOwnPtr<HTML::Task>);
-    OwnPtr<HTML::Task> take_first_runnable() { return m_tasks.dequeue(); }
+    OwnPtr<HTML::Task> take_first_runnable();
 
 
     void enqueue(NonnullOwnPtr<HTML::Task> task) { add(move(task)); }
     void enqueue(NonnullOwnPtr<HTML::Task> task) { add(move(task)); }
     OwnPtr<HTML::Task> dequeue()
     OwnPtr<HTML::Task> dequeue()
     {
     {
         if (m_tasks.is_empty())
         if (m_tasks.is_empty())
             return {};
             return {};
-        return m_tasks.dequeue();
+        return m_tasks.take_first();
     }
     }
 
 
 private:
 private:
     HTML::EventLoop& m_event_loop;
     HTML::EventLoop& m_event_loop;
 
 
-    Queue<NonnullOwnPtr<HTML::Task>> m_tasks;
+    Vector<NonnullOwnPtr<HTML::Task>> m_tasks;
 };
 };
 
 
 }
 }