diff options
author | Timothy Flynn <trflynn89@pm.me> | 2023-04-07 11:10:57 -0400 |
---|---|---|
committer | Linus Groh <mail@linusgroh.de> | 2023-04-08 22:04:14 +0200 |
commit | 90921a4f1621f3b068d2a7c47a5eac924778c20e (patch) | |
tree | c2c2568f8081af6b35f54174bd962cca991d60d8 /Userland/Libraries/LibWeb | |
parent | e130525c24cf0b7cac7fb1f3b39bd406acb6715e (diff) | |
download | serenity-90921a4f1621f3b068d2a7c47a5eac924778c20e.zip |
LibWeb: Implement the HTMLMediaElement paused attribute
Note that the default value of the attribute is true. We were previously
autoplaying videos as soon as they loaded - this will prevent that from
happening until the paused attribute is set to false.
Diffstat (limited to 'Userland/Libraries/LibWeb')
5 files changed, 68 insertions, 7 deletions
diff --git a/Userland/Libraries/LibWeb/HTML/HTMLMediaElement.cpp b/Userland/Libraries/LibWeb/HTML/HTMLMediaElement.cpp index 8038c1791e..036376ebb8 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLMediaElement.cpp +++ b/Userland/Libraries/LibWeb/HTML/HTMLMediaElement.cpp @@ -179,9 +179,14 @@ WebIDL::ExceptionOr<void> HTMLMediaElement::load_element() if (m_ready_state != ReadyState::HaveNothing) set_ready_state(ReadyState::HaveNothing); - // FIXME: 6. If the paused attribute is false, then: - // 1. Set the paused attribute to true. - // 2. Take pending play promises and reject pending play promises with the result and an "AbortError" DOMException. + // 6. If the paused attribute is false, then: + if (!paused()) { + // 1. Set the paused attribute to true. + set_paused(true); + + // FIXME 2. Take pending play promises and reject pending play promises with the result and an "AbortError" DOMException. + } + // FIXME: 7. If seeking is true, set it to false. // FIXME: 8. Set the current playback position to 0. // Set the official playback position to 0. @@ -737,7 +742,10 @@ void HTMLMediaElement::set_ready_state(ReadyState ready_state) dispatch_event(DOM::Event::create(this->realm(), HTML::EventNames::canplay).release_value_but_fixme_should_propagate_errors()); }); - // FIXME: If the element's paused attribute is false, the user agent must notify about playing for the element. + // If the element's paused attribute is false, the user agent must notify about playing for the element. + if (!paused()) + notify_about_playing(); + return; } @@ -746,10 +754,12 @@ void HTMLMediaElement::set_ready_state(ReadyState ready_state) // If the previous ready state was HAVE_CURRENT_DATA or less, the user agent must queue a media element task given the media element to fire an event // named canplay at the element, and, if the element's paused attribute is false, notify about playing for the element. if (m_ready_state <= ReadyState::HaveCurrentData) { - // FIXME: Handle the paused attribute. queue_a_media_element_task([this] { dispatch_event(DOM::Event::create(this->realm(), HTML::EventNames::canplay).release_value_but_fixme_should_propagate_errors()); }); + + if (!paused()) + notify_about_playing(); } // The user agent must queue a media element task given the media element to fire an event named canplaythrough at the element. @@ -774,4 +784,31 @@ void HTMLMediaElement::set_ready_state(ReadyState ready_state) } } +// https://html.spec.whatwg.org/multipage/media.html#notify-about-playing +void HTMLMediaElement::notify_about_playing() +{ + // FIXME: 1. Take pending play promises and let promises be the result. + + // 2. Queue a media element task given the element and the following steps: + queue_a_media_element_task([this]() { + // 1. Fire an event named playing at the element. + dispatch_event(DOM::Event::create(realm(), HTML::EventNames::playing).release_value_but_fixme_should_propagate_errors()); + + // FIXME: 2. Resolve pending play promises with promises. + }); + + on_playing(); +} + +void HTMLMediaElement::set_paused(bool paused) +{ + if (m_paused == paused) + return; + + m_paused = paused; + + if (m_paused) + on_paused(); +} + } diff --git a/Userland/Libraries/LibWeb/HTML/HTMLMediaElement.h b/Userland/Libraries/LibWeb/HTML/HTMLMediaElement.h index 041989a5e3..f98bf13525 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLMediaElement.h +++ b/Userland/Libraries/LibWeb/HTML/HTMLMediaElement.h @@ -45,6 +45,7 @@ public: WebIDL::ExceptionOr<void> load(); double duration() const; + bool paused() const { return m_paused; } void pause() const; JS::NonnullGCPtr<VideoTrackList> video_tracks() const { return *m_video_tracks; } @@ -55,6 +56,11 @@ protected: virtual JS::ThrowCompletionOr<void> initialize(JS::Realm&) override; virtual void visit_edges(Cell::Visitor&) 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. + virtual void on_playing() { } + virtual void on_paused() { } + private: struct EntireResource { }; using ByteRange = Variant<EntireResource>; // FIXME: This will need to include "until end" and an actual byte range. @@ -71,6 +77,9 @@ private: WebIDL::ExceptionOr<void> handle_media_source_failure(); void forget_media_resource_specific_tracks(); void set_ready_state(ReadyState); + + void notify_about_playing(); + void set_paused(bool); void set_duration(double); // https://html.spec.whatwg.org/multipage/media.html#media-element-event-task-source @@ -86,6 +95,9 @@ private: // https://html.spec.whatwg.org/multipage/media.html#dom-media-duration double m_duration { NAN }; + // 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-videotracks JS::GCPtr<VideoTrackList> m_video_tracks; diff --git a/Userland/Libraries/LibWeb/HTML/HTMLMediaElement.idl b/Userland/Libraries/LibWeb/HTML/HTMLMediaElement.idl index 48cf818406..6be3e29bd9 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLMediaElement.idl +++ b/Userland/Libraries/LibWeb/HTML/HTMLMediaElement.idl @@ -31,6 +31,7 @@ interface HTMLMediaElement : HTMLElement { // playback state readonly attribute unrestricted double duration; + readonly attribute boolean paused; [Reflect, CEReactions] attribute boolean autoplay; [Reflect, CEReactions] attribute boolean loop; undefined pause(); diff --git a/Userland/Libraries/LibWeb/HTML/HTMLVideoElement.cpp b/Userland/Libraries/LibWeb/HTML/HTMLVideoElement.cpp index 94907a8e2e..6f50bb5b55 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLVideoElement.cpp +++ b/Userland/Libraries/LibWeb/HTML/HTMLVideoElement.cpp @@ -1,5 +1,6 @@ /* * Copyright (c) 2020, the SerenityOS developers. + * Copyright (c) 2023, Tim Flynn <trflynn89@serenityos.org> * * SPDX-License-Identifier: BSD-2-Clause */ @@ -84,9 +85,10 @@ void HTMLVideoElement::set_video_track(JS::GCPtr<HTML::VideoTrack> video_track) m_video_timer->stop(); m_video_track = video_track; - if (!m_video_track) - return; +} +void HTMLVideoElement::on_playing() +{ if (!m_video_timer) { m_video_timer = Platform::Timer::create_repeating(s_frame_delay_ms, [this]() { if (auto frame = m_video_track->next_frame()) @@ -101,4 +103,10 @@ void HTMLVideoElement::set_video_track(JS::GCPtr<HTML::VideoTrack> video_track) m_video_timer->start(); } +void HTMLVideoElement::on_paused() +{ + if (m_video_timer) + m_video_timer->stop(); +} + } diff --git a/Userland/Libraries/LibWeb/HTML/HTMLVideoElement.h b/Userland/Libraries/LibWeb/HTML/HTMLVideoElement.h index d054370336..51012a2b84 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLVideoElement.h +++ b/Userland/Libraries/LibWeb/HTML/HTMLVideoElement.h @@ -38,6 +38,9 @@ private: virtual JS::GCPtr<Layout::Node> create_layout_node(NonnullRefPtr<CSS::StyleProperties>) override; + virtual void on_playing() override; + virtual void on_paused() override; + JS::GCPtr<HTML::VideoTrack> m_video_track; RefPtr<Platform::Timer> m_video_timer; RefPtr<Gfx::Bitmap> m_current_frame; |