Auto merge of #22348 - germangb:html_media_ended, r=ferjm

Implement Ended media attribute

<!-- Please describe your changes on the following line: -->

This PR should implement:
* New method `HTMLMediaElement::earliest_possible_position()` for the [earliest possible position](https://html.spec.whatwg.org/multipage/media.html#earliest-possible-position)
* `Ended` attribute following https://html.spec.whatwg.org/multipage/media.html#ended-playback
* Queue steps for when the playback position reaches the end

This PR contains placeholders for the following issues (I can rebase changes after the corresponding PRs get merged)
- #22321 (Define the Loop attribute)
- #22293 (To identify playback direction. Either forwards or backwards)

---
<!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: -->
- [X] `./mach build -d` does not report any errors
- [X] `./mach test-tidy` does not report any errors
- [x] These changes fix #22294.

<!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.-->

<!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. -->

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/22348)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2019-01-14 06:35:45 -05:00 committed by GitHub
commit 1f9b134794
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 104 additions and 25 deletions

View file

@ -1119,6 +1119,63 @@ impl HTMLMediaElement {
// an unsupported format, or can otherwise not be rendered at all"
if self.ready_state.get() < ReadyState::HaveMetadata {
self.queue_dedicated_media_source_failure_steps();
} else {
// https://html.spec.whatwg.org/multipage/#reaches-the-end
match self.direction_of_playback() {
PlaybackDirection::Forwards => {
// Step 1.
if self.Loop() {
self.seek(
self.earliest_possible_position(),
/* approximate_for_speed*/ false,
);
} else {
// Step 2.
// The **ended playback** condition is implemented inside of
// the HTMLMediaElementMethods::Ended method
// Step 3.
let window = window_from_node(self);
let this = Trusted::new(self);
let _ = window.task_manager().media_element_task_source().queue(
task!(reaches_the_end_steps: move || {
let this = this.root();
// Step 3.1.
this.upcast::<EventTarget>().fire_event(atom!("timeupdate"));
// Step 3.2.
if this.Ended() && !this.Paused() {
// Step 3.2.1.
this.paused.set(true);
// Step 3.2.2.
this.upcast::<EventTarget>().fire_event(atom!("pause"));
// Step 3.2.3.
this.take_pending_play_promises(Err(Error::Abort));
this.fulfill_in_flight_play_promises(|| ());
}
// Step 3.3.
this.upcast::<EventTarget>().fire_event(atom!("ended"));
}),
window.upcast(),
);
}
},
PlaybackDirection::Backwards => {
if self.playback_position.get() <= self.earliest_possible_position() {
let window = window_from_node(self);
window
.task_manager()
.media_element_task_source()
.queue_simple_event(self.upcast(), atom!("ended"), &window);
}
},
}
}
},
PlayerEvent::Error => {
@ -1261,6 +1318,38 @@ impl HTMLMediaElement {
},
}
}
// https://html.spec.whatwg.org/multipage/#earliest-possible-position
fn earliest_possible_position(&self) -> f64 {
self.played
.borrow()
.start(0)
.unwrap_or_else(|_| self.playback_position.get())
}
}
// XXX Placeholder for [https://github.com/servo/servo/issues/22293]
#[derive(Clone, Copy, JSTraceable, MallocSizeOf, PartialEq)]
enum PlaybackDirection {
Forwards,
#[allow(dead_code)]
Backwards,
}
// XXX Placeholder implementations for:
//
// - https://github.com/servo/servo/issues/22293
// - https://github.com/servo/servo/issues/22321
impl HTMLMediaElement {
// https://github.com/servo/servo/issues/22293
fn direction_of_playback(&self) -> PlaybackDirection {
PlaybackDirection::Forwards
}
// https://github.com/servo/servo/pull/22321
fn Loop(&self) -> bool {
false
}
}
impl HTMLMediaElementMethods for HTMLMediaElement {
@ -1514,6 +1603,20 @@ impl HTMLMediaElementMethods for HTMLMediaElement {
self.seeking.get()
}
// https://html.spec.whatwg.org/multipage/#ended-playback
fn Ended(&self) -> bool {
if self.ready_state.get() < ReadyState::HaveMetadata {
return false;
}
let playback_pos = self.playback_position.get();
match self.direction_of_playback() {
PlaybackDirection::Forwards => playback_pos >= self.Duration() && !self.Loop(),
PlaybackDirection::Backwards => playback_pos <= self.earliest_possible_position(),
}
}
// https://html.spec.whatwg.org/multipage/#dom-media-fastseek
fn FastSeek(&self, time: Finite<f64>) {
self.seek(*time, /* approximate_for_speed */ true);

View file

@ -46,7 +46,7 @@ interface HTMLMediaElement : HTMLElement {
[Throws] attribute double playbackRate;
readonly attribute TimeRanges played;
// readonly attribute TimeRanges seekable;
// readonly attribute boolean ended;
readonly attribute boolean ended;
[CEReactions] attribute boolean autoplay;
// [CEReactions] attribute boolean loop;
Promise<void> play();