mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-04-27 14:58:46 +00:00
LibWeb: Implement TimeRanges and HTMLMediaElement.seekable()
This commit is contained in:
parent
3952ff4786
commit
aa243000f3
Notes:
github-actions[bot]
2025-02-18 17:46:30 +00:00
Author: https://github.com/Psychpsyo
Commit: aa243000f3
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/3563
Reviewed-by: https://github.com/ADKaster ✅
5 changed files with 103 additions and 18 deletions
|
@ -185,6 +185,18 @@ GC::Ref<TimeRanges> HTMLMediaElement::played() const
|
|||
return time_ranges;
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/media.html#dom-media-seekable
|
||||
GC::Ref<TimeRanges> HTMLMediaElement::seekable() const
|
||||
{
|
||||
auto& realm = this->realm();
|
||||
|
||||
// The seekable attribute must return a new static normalized TimeRanges object that represents the ranges of the media resource, if any, that the
|
||||
// user agent is able to seek to, at the time the attribute is evaluated.
|
||||
auto time_ranges = realm.create<TimeRanges>(realm);
|
||||
time_ranges->add_range(0, m_duration);
|
||||
return time_ranges;
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/media.html#dom-navigator-canplaytype
|
||||
Bindings::CanPlayTypeResult HTMLMediaElement::can_play_type(StringView type) const
|
||||
{
|
||||
|
@ -1566,11 +1578,46 @@ void HTMLMediaElement::seek_element(double playback_position, MediaSeekMode seek
|
|||
if (playback_position < 0)
|
||||
playback_position = 0;
|
||||
|
||||
// FIXME: 8. If the (possibly now changed) new playback position is not in one of the ranges given in the seekable attribute,
|
||||
// 8. If the (possibly now changed) new playback position is not in one of the ranges given in the seekable attribute,
|
||||
auto time_ranges = seekable();
|
||||
if (!time_ranges->in_range(playback_position)) {
|
||||
// then let it be the position in one of the ranges given in the seekable attribute that is the nearest to the new
|
||||
// playback position. If two positions both satisfy that constraint (i.e. the new playback position is exactly in the
|
||||
// middle between two ranges in the seekable attribute) then use the position that is closest to the current playback
|
||||
// position. If there are no ranges given in the seekable attribute then set the seeking IDL attribute to false and return.
|
||||
// playback position.
|
||||
|
||||
// If there are no ranges given in the seekable attribute then set the seeking IDL attribute to false and return.
|
||||
if (time_ranges->length() == 0) {
|
||||
set_seeking(false);
|
||||
return;
|
||||
}
|
||||
|
||||
double nearest_point;
|
||||
Optional<double> other_nearest_point = {};
|
||||
double distance = INFINITY;
|
||||
for (size_t i = 0; i < time_ranges->length(); i++) {
|
||||
for (double point : { MUST(time_ranges->start(i)), MUST(time_ranges->end(i)) }) {
|
||||
auto point_distance = abs(playback_position - point);
|
||||
if (point_distance < distance) {
|
||||
nearest_point = point;
|
||||
other_nearest_point = {};
|
||||
distance = point_distance;
|
||||
} else if (point_distance == distance) {
|
||||
other_nearest_point = point;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If two positions both satisfy that constraint (i.e. the new playback position is exactly in the middle between two ranges
|
||||
// in the seekable attribute) then use the position that is closest to the current playback position.
|
||||
if (other_nearest_point.has_value()) {
|
||||
auto nearest_point_distance = abs(m_current_playback_position - nearest_point);
|
||||
auto other_nearest_point_distance = abs(m_current_playback_position - other_nearest_point.value());
|
||||
if (nearest_point_distance < other_nearest_point_distance) {
|
||||
playback_position = nearest_point;
|
||||
} else {
|
||||
playback_position = other_nearest_point.value();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 9. If the approximate-for-speed flag is set, adjust the new playback position to a value that will allow for playback to resume
|
||||
// promptly. If new playback position before this step is before current playback position, then the adjusted new playback position
|
||||
|
|
|
@ -58,6 +58,7 @@ public:
|
|||
|
||||
[[nodiscard]] GC::Ref<TimeRanges> buffered() const;
|
||||
[[nodiscard]] GC::Ref<TimeRanges> played() const;
|
||||
[[nodiscard]] GC::Ref<TimeRanges> seekable() const;
|
||||
|
||||
static inline constexpr auto supported_video_subtypes = Array {
|
||||
"webm"sv,
|
||||
|
|
|
@ -63,7 +63,7 @@ interface HTMLMediaElement : HTMLElement {
|
|||
attribute double playbackRate;
|
||||
[FIXME] attribute boolean preservesPitch;
|
||||
readonly attribute TimeRanges played;
|
||||
[FIXME] readonly attribute TimeRanges seekable;
|
||||
readonly attribute TimeRanges seekable;
|
||||
readonly attribute boolean ended;
|
||||
[Reflect, CEReactions] attribute boolean autoplay;
|
||||
[Reflect, CEReactions] attribute boolean loop;
|
||||
|
|
|
@ -27,24 +27,44 @@ void TimeRanges::initialize(JS::Realm& realm)
|
|||
// https://html.spec.whatwg.org/multipage/media.html#dom-timeranges-length
|
||||
size_t TimeRanges::length() const
|
||||
{
|
||||
// FIXME: The length IDL attribute must return the number of ranges represented by the object.
|
||||
return 0;
|
||||
return m_ranges.size();
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/media.html#dom-timeranges-start
|
||||
double TimeRanges::start(u32) const
|
||||
WebIDL::ExceptionOr<double> TimeRanges::start(u32 index) const
|
||||
{
|
||||
// FIXME: The start(index) method must return the position of the start of the indexth range represented by the object,
|
||||
// These methods must throw "IndexSizeError" DOMExceptions if called with an index argument greater than or equal to the number of ranges represented by the object.
|
||||
if (index >= m_ranges.size())
|
||||
return WebIDL::IndexSizeError::create(realm(), "Index argument is greater than or equal to the number of ranges represented by this TimeRanges object"_string);
|
||||
|
||||
// The start(index) method must return the position of the start of the indexth range represented by the object,
|
||||
// in seconds measured from the start of the timeline that the object covers.
|
||||
return 0.0;
|
||||
return m_ranges[index].start;
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/media.html#dom-timeranges-end
|
||||
double TimeRanges::end(u32) const
|
||||
WebIDL::ExceptionOr<double> TimeRanges::end(u32 index) const
|
||||
{
|
||||
// FIXME: The end(index) method must return the position of the end of the indexth range represented by the object,
|
||||
// These methods must throw "IndexSizeError" DOMExceptions if called with an index argument greater than or equal to the number of ranges represented by the object.
|
||||
if (index >= m_ranges.size())
|
||||
return WebIDL::IndexSizeError::create(realm(), "Index argument is greater than or equal to the number of ranges represented by this TimeRanges object"_string);
|
||||
|
||||
// The end(index) method must return the position of the end of the indexth range represented by the object,
|
||||
// in seconds measured from the start of the timeline that the object covers.
|
||||
return 0.0;
|
||||
return m_ranges[index].end;
|
||||
}
|
||||
|
||||
void TimeRanges::add_range(double start, double end)
|
||||
{
|
||||
m_ranges.append({ start, end });
|
||||
}
|
||||
bool TimeRanges::in_range(double point)
|
||||
{
|
||||
for (auto range : m_ranges) {
|
||||
if (point >= range.start && point <= range.end)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -8,22 +8,39 @@
|
|||
|
||||
#include <LibJS/Forward.h>
|
||||
#include <LibWeb/Bindings/PlatformObject.h>
|
||||
#include <LibWeb/WebIDL/ExceptionOr.h>
|
||||
|
||||
namespace Web::HTML {
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/media.html#time-ranges
|
||||
class TimeRanges final : public Bindings::PlatformObject {
|
||||
WEB_PLATFORM_OBJECT(TimeRanges, Bindings::PlatformObject);
|
||||
GC_DECLARE_ALLOCATOR(TimeRanges);
|
||||
|
||||
public:
|
||||
// https://html.spec.whatwg.org/multipage/media.html#dom-timeranges-length
|
||||
size_t length() const;
|
||||
double start(u32 index) const;
|
||||
double end(u32 index) const;
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/media.html#dom-timeranges-start
|
||||
WebIDL::ExceptionOr<double> start(u32 index) const;
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/media.html#dom-timeranges-end
|
||||
WebIDL::ExceptionOr<double> end(u32 index) const;
|
||||
|
||||
void add_range(double start, double end);
|
||||
bool in_range(double);
|
||||
|
||||
private:
|
||||
explicit TimeRanges(JS::Realm&);
|
||||
|
||||
virtual void initialize(JS::Realm&) override;
|
||||
|
||||
struct Range {
|
||||
double start;
|
||||
double end;
|
||||
};
|
||||
|
||||
Vector<Range> m_ranges;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue