summaryrefslogtreecommitdiff
path: root/Userland/Libraries/LibWeb
diff options
context:
space:
mode:
authorTimothy Flynn <trflynn89@pm.me>2023-04-07 11:10:57 -0400
committerLinus Groh <mail@linusgroh.de>2023-04-08 22:04:14 +0200
commit90921a4f1621f3b068d2a7c47a5eac924778c20e (patch)
treec2c2568f8081af6b35f54174bd962cca991d60d8 /Userland/Libraries/LibWeb
parente130525c24cf0b7cac7fb1f3b39bd406acb6715e (diff)
downloadserenity-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')
-rw-r--r--Userland/Libraries/LibWeb/HTML/HTMLMediaElement.cpp47
-rw-r--r--Userland/Libraries/LibWeb/HTML/HTMLMediaElement.h12
-rw-r--r--Userland/Libraries/LibWeb/HTML/HTMLMediaElement.idl1
-rw-r--r--Userland/Libraries/LibWeb/HTML/HTMLVideoElement.cpp12
-rw-r--r--Userland/Libraries/LibWeb/HTML/HTMLVideoElement.h3
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;