1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-20 14:05:08 +00:00

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.
This commit is contained in:
Timothy Flynn 2023-05-22 07:41:34 -04:00 committed by Andreas Kling
parent 76aa17be86
commit b865277275
2 changed files with 23 additions and 6 deletions

View file

@ -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 // NOTE: If there isn't another candidate to check, we implement the "waiting" step by returning until the media
// has a sibling. It might be nicer for the DOM tree to just tell us when the sibling becomes available. // 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]() { m_previously_failed_candidate = previous_candidate;
wait_for_next_candidate(previous_candidate).release_value_but_fixme_should_propagate_errors();
});
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()
{ {

View file

@ -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.