Просмотр исходного кода

LibWeb: Wait for media candidates without endlessly queueing microtasks

Rather than queueing microtasks ad nauseam to check if a media element
has a new source candidate, let the media element tell us when it might
have a new child to inspect. This removes endless CPU churn in cases
where there is never a candidate that we can play.
Timothy Flynn 2 лет назад
Родитель
Сommit
b865277275

+ 22 - 6
Userland/Libraries/LibWeb/HTML/HTMLMediaElement.cpp

@@ -452,6 +452,7 @@ public:
         Base::visit_edges(visitor);
         Base::visit_edges(visitor);
         visitor.visit(m_media_element);
         visitor.visit(m_media_element);
         visitor.visit(m_candidate);
         visitor.visit(m_candidate);
+        visitor.visit(m_previously_failed_candidate);
     }
     }
 
 
     WebIDL::ExceptionOr<void> process_candidate()
     WebIDL::ExceptionOr<void> process_candidate()
@@ -500,6 +501,15 @@ public:
         return {};
         return {};
     }
     }
 
 
+    WebIDL::ExceptionOr<void> process_next_candidate()
+    {
+        if (!m_previously_failed_candidate)
+            return {};
+
+        TRY(wait_for_next_candidate(*m_previously_failed_candidate));
+        return {};
+    }
+
 private:
 private:
     WebIDL::ExceptionOr<void> failed_with_elements()
     WebIDL::ExceptionOr<void> failed_with_elements()
     {
     {
@@ -573,16 +583,15 @@ private:
 
 
     WebIDL::ExceptionOr<void> wait_for_next_candidate(JS::NonnullGCPtr<DOM::Node> previous_candidate)
     WebIDL::ExceptionOr<void> wait_for_next_candidate(JS::NonnullGCPtr<DOM::Node> previous_candidate)
     {
     {
-        // FIXME: We implement the "waiting" by constantly queueing a microtask to check if the previous candidate now
-        //        has a sibling. It might be nicer for the DOM tree to just tell us when the sibling becomes available.
+        // NOTE: If there isn't another candidate to check, we implement the "waiting" step by returning until the media
+        //       element's children have changed.
         if (previous_candidate->next_sibling() == nullptr) {
         if (previous_candidate->next_sibling() == nullptr) {
-            queue_a_microtask(&m_media_element->document(), [this, previous_candidate]() {
-                wait_for_next_candidate(previous_candidate).release_value_but_fixme_should_propagate_errors();
-            });
-
+            m_previously_failed_candidate = previous_candidate;
             return {};
             return {};
         }
         }
 
 
+        m_previously_failed_candidate = nullptr;
+
         // FIXME: 22. Await a stable state. The synchronous section consists of all the remaining steps of this algorithm until
         // FIXME: 22. Await a stable state. The synchronous section consists of all the remaining steps of this algorithm until
         //            the algorithm says the synchronous section has ended. (Steps in synchronous sections are marked with ⌛.)
         //            the algorithm says the synchronous section has ended. (Steps in synchronous sections are marked with ⌛.)
 
 
@@ -601,8 +610,15 @@ private:
 
 
     JS::NonnullGCPtr<HTMLMediaElement> m_media_element;
     JS::NonnullGCPtr<HTMLMediaElement> m_media_element;
     JS::NonnullGCPtr<HTMLSourceElement> m_candidate;
     JS::NonnullGCPtr<HTMLSourceElement> m_candidate;
+    JS::GCPtr<DOM::Node> m_previously_failed_candidate;
 };
 };
 
 
+void HTMLMediaElement::children_changed()
+{
+    if (m_source_element_selector)
+        m_source_element_selector->process_next_candidate().release_value_but_fixme_should_propagate_errors();
+}
+
 // https://html.spec.whatwg.org/multipage/media.html#concept-media-load-algorithm
 // https://html.spec.whatwg.org/multipage/media.html#concept-media-load-algorithm
 WebIDL::ExceptionOr<void> HTMLMediaElement::select_resource()
 WebIDL::ExceptionOr<void> HTMLMediaElement::select_resource()
 {
 {

+ 1 - 0
Userland/Libraries/LibWeb/HTML/HTMLMediaElement.h

@@ -93,6 +93,7 @@ protected:
     virtual void parse_attribute(DeprecatedFlyString const& name, DeprecatedString const& value) override;
     virtual void parse_attribute(DeprecatedFlyString const& name, DeprecatedString const& value) override;
     virtual void did_remove_attribute(DeprecatedFlyString const&) override;
     virtual void did_remove_attribute(DeprecatedFlyString const&) override;
     virtual void removed_from(DOM::Node*) override;
     virtual void removed_from(DOM::Node*) override;
+    virtual void children_changed() override;
 
 
     // Override in subclasses to handle implementation-specific behavior when the element state changes
     // Override in subclasses to handle implementation-specific behavior when the element state changes
     // to playing or paused, e.g. to start/stop play timers.
     // to playing or paused, e.g. to start/stop play timers.