mirror of
https://github.com/zebrajr/ladybird.git
synced 2025-12-06 12:20:00 +01:00
LibWeb: Consider playback ended when loop is set after ending playback
This allows playback to restart when playing is requested after the end of playback was reached while loop was disabled, regardless of whether loop is then subsequently enabled. This matches other browsers' implementations, but differs from the spec in how the ended attribute is handled. See: https://github.com/whatwg/html/issues/11775
This commit is contained in:
parent
3be6b957f8
commit
4471e8c0ec
|
|
@ -314,6 +314,8 @@ void HTMLMediaElement::set_current_playback_position(double playback_position)
|
|||
// which these steps should be invoked, which is when we've reached the end of the media playback.
|
||||
if (m_current_playback_position == m_duration)
|
||||
reached_end_of_media_playback();
|
||||
|
||||
upon_has_ended_playback_possibly_changed();
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/media.html#dom-media-duration
|
||||
|
|
@ -332,8 +334,10 @@ bool HTMLMediaElement::ended() const
|
|||
{
|
||||
// The ended attribute must return true if, the last time the event loop reached step 1, the media element had ended
|
||||
// playback and the direction of playback was forwards, and false otherwise.
|
||||
// FIXME: Add a hook into EventLoop::process() to be notified when step 1 is reached.
|
||||
return has_ended_playback() && direction_of_playback() == PlaybackDirection::Forwards;
|
||||
// NOTE: We queue a task to set this at event loop step 1 whenever something happens that may affect the resulting value.
|
||||
// Currently, that is when the ready state changes, when the current playback position changes, or the duration
|
||||
// changes.
|
||||
return m_ended;
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/media.html#durationChange
|
||||
|
|
@ -354,6 +358,8 @@ void HTMLMediaElement::set_duration(double duration)
|
|||
|
||||
m_duration = duration;
|
||||
|
||||
upon_has_ended_playback_possibly_changed();
|
||||
|
||||
if (auto* paintable = this->paintable())
|
||||
paintable->set_needs_display();
|
||||
}
|
||||
|
|
@ -1456,6 +1462,7 @@ void HTMLMediaElement::set_ready_state(ReadyState ready_state)
|
|||
{
|
||||
ScopeGuard guard { [&] {
|
||||
m_ready_state = ready_state;
|
||||
upon_has_ended_playback_possibly_changed();
|
||||
set_needs_style_update(true);
|
||||
} };
|
||||
|
||||
|
|
@ -1863,6 +1870,11 @@ void HTMLMediaElement::set_paused(bool paused)
|
|||
set_needs_style_update(true);
|
||||
}
|
||||
|
||||
void HTMLMediaElement::set_ended(bool ended)
|
||||
{
|
||||
m_ended = ended;
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/media.html#dom-media-defaultplaybackrate
|
||||
void HTMLMediaElement::set_default_playback_rate(double new_value)
|
||||
{
|
||||
|
|
@ -1984,7 +1996,11 @@ bool HTMLMediaElement::has_ended_playback() const
|
|||
direction_of_playback() == PlaybackDirection::Forwards &&
|
||||
|
||||
// The media element does not have a loop attribute specified.
|
||||
!has_attribute(HTML::AttributeNames::loop)) {
|
||||
// AD-HOC: Use the value of the loop attribute from the last time we reached end of playback.
|
||||
// Without this change, the ended attribute changes when enabling the loop attribute after
|
||||
// playback has ended, and playback will not restart when playing the element.
|
||||
// See https://github.com/whatwg/html/issues/11775
|
||||
!m_loop_was_specified_when_reaching_end_of_media_resource) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -2001,11 +2017,21 @@ bool HTMLMediaElement::has_ended_playback() const
|
|||
return false;
|
||||
}
|
||||
|
||||
void HTMLMediaElement::upon_has_ended_playback_possibly_changed()
|
||||
{
|
||||
run_when_event_loop_reaches_step_1(GC::Function<void()>::create(heap(), [&] {
|
||||
// The ended attribute must return true if, the last time the event loop reached step 1, the media element had ended
|
||||
// playback and the direction of playback was forwards, and false otherwise.
|
||||
set_ended(has_ended_playback() && direction_of_playback() == PlaybackDirection::Forwards);
|
||||
}));
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/media.html#reaches-the-end
|
||||
void HTMLMediaElement::reached_end_of_media_playback()
|
||||
{
|
||||
// 1. If the media element has a loop attribute specified,
|
||||
if (has_attribute(HTML::AttributeNames::loop)) {
|
||||
m_loop_was_specified_when_reaching_end_of_media_resource = has_attribute(HTML::AttributeNames::loop);
|
||||
if (m_loop_was_specified_when_reaching_end_of_media_resource) {
|
||||
// then seek to the earliest possible position of the media resource and return.
|
||||
seek_element(0);
|
||||
// FIXME: Tell PlaybackManager that we're looping to allow data providers to decode frames ahead when looping
|
||||
|
|
|
|||
|
|
@ -211,6 +211,7 @@ private:
|
|||
void set_show_poster(bool);
|
||||
void set_paused(bool);
|
||||
void set_duration(double);
|
||||
void set_ended(bool);
|
||||
|
||||
void volume_or_muted_attribute_changed();
|
||||
void update_volume();
|
||||
|
|
@ -224,6 +225,7 @@ private:
|
|||
PlaybackDirection direction_of_playback() const;
|
||||
|
||||
bool has_ended_playback() const;
|
||||
void upon_has_ended_playback_possibly_changed();
|
||||
void reached_end_of_media_playback();
|
||||
|
||||
void dispatch_time_update_event();
|
||||
|
|
@ -291,6 +293,9 @@ private:
|
|||
// https://html.spec.whatwg.org/multipage/media.html#dom-media-paused
|
||||
bool m_paused { true };
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/media.html#dom-media-ended
|
||||
bool m_ended { false };
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/media.html#dom-media-defaultplaybackrate
|
||||
double m_default_playback_rate { 1.0 };
|
||||
|
||||
|
|
@ -334,6 +339,8 @@ private:
|
|||
GC::Ptr<VideoTrack> m_selected_video_track;
|
||||
RefPtr<Media::DisplayingVideoSink> m_selected_video_track_sink;
|
||||
|
||||
bool m_loop_was_specified_when_reaching_end_of_media_resource { false };
|
||||
|
||||
// Cached state for layout.
|
||||
Optional<MediaComponent> m_mouse_tracking_component;
|
||||
Optional<MediaComponent> m_hovered_component;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user