summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTimothy Flynn <trflynn89@pm.me>2023-05-22 07:41:34 -0400
committerAndreas Kling <kling@serenityos.org>2023-05-22 15:11:08 +0200
commitb86527727556b3f7612004aad6403babb371b64c (patch)
treef9dae86d37260df7e88131fabe61570f07609d7e
parent76aa17be86a7ada4344cf7c53c13155e76a8e9f6 (diff)
downloadserenity-b86527727556b3f7612004aad6403babb371b64c.zip
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.
-rw-r--r--Userland/Libraries/LibWeb/HTML/HTMLMediaElement.cpp28
-rw-r--r--Userland/Libraries/LibWeb/HTML/HTMLMediaElement.h1
2 files changed, 23 insertions, 6 deletions
diff --git a/Userland/Libraries/LibWeb/HTML/HTMLMediaElement.cpp b/Userland/Libraries/LibWeb/HTML/HTMLMediaElement.cpp
index fd4ad61a60..535aeb3b7f 100644
--- a/Userland/Libraries/LibWeb/HTML/HTMLMediaElement.cpp
+++ b/Userland/Libraries/LibWeb/HTML/HTMLMediaElement.cpp
@@ -452,6 +452,7 @@ public:
Base::visit_edges(visitor);
visitor.visit(m_media_element);
visitor.visit(m_candidate);
+ visitor.visit(m_previously_failed_candidate);
}
WebIDL::ExceptionOr<void> process_candidate()
@@ -500,6 +501,15 @@ public:
return {};
}
+ WebIDL::ExceptionOr<void> process_next_candidate()
+ {
+ if (!m_previously_failed_candidate)
+ return {};
+
+ TRY(wait_for_next_candidate(*m_previously_failed_candidate));
+ return {};
+ }
+
private:
WebIDL::ExceptionOr<void> failed_with_elements()
{
@@ -573,16 +583,15 @@ private:
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) {
- 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 {};
}
+ m_previously_failed_candidate = nullptr;
+
// 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 ⌛.)
@@ -601,8 +610,15 @@ private:
JS::NonnullGCPtr<HTMLMediaElement> m_media_element;
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
WebIDL::ExceptionOr<void> HTMLMediaElement::select_resource()
{
diff --git a/Userland/Libraries/LibWeb/HTML/HTMLMediaElement.h b/Userland/Libraries/LibWeb/HTML/HTMLMediaElement.h
index 3f5b0c7d06..a052c17674 100644
--- a/Userland/Libraries/LibWeb/HTML/HTMLMediaElement.h
+++ b/Userland/Libraries/LibWeb/HTML/HTMLMediaElement.h
@@ -93,6 +93,7 @@ protected:
virtual void parse_attribute(DeprecatedFlyString const& name, DeprecatedString const& value) override;
virtual void did_remove_attribute(DeprecatedFlyString const&) 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
// to playing or paused, e.g. to start/stop play timers.