Auto merge of #18504 - servo:media, r=emilio

Some minor HTMLMediaElement improvements

<!-- 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/18504)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2017-09-14 20:51:51 -05:00 committed by GitHub
commit 1b9a5ea719

View file

@ -8,7 +8,7 @@ use dom::attr::Attr;
use dom::bindings::cell::DOMRefCell; use dom::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::AttrBinding::AttrMethods; use dom::bindings::codegen::Bindings::AttrBinding::AttrMethods;
use dom::bindings::codegen::Bindings::HTMLMediaElementBinding::CanPlayTypeResult; use dom::bindings::codegen::Bindings::HTMLMediaElementBinding::CanPlayTypeResult;
use dom::bindings::codegen::Bindings::HTMLMediaElementBinding::HTMLMediaElementConstants::*; use dom::bindings::codegen::Bindings::HTMLMediaElementBinding::HTMLMediaElementConstants;
use dom::bindings::codegen::Bindings::HTMLMediaElementBinding::HTMLMediaElementMethods; use dom::bindings::codegen::Bindings::HTMLMediaElementBinding::HTMLMediaElementMethods;
use dom::bindings::codegen::Bindings::MediaErrorBinding::MediaErrorConstants::*; use dom::bindings::codegen::Bindings::MediaErrorBinding::MediaErrorConstants::*;
use dom::bindings::codegen::Bindings::MediaErrorBinding::MediaErrorMethods; use dom::bindings::codegen::Bindings::MediaErrorBinding::MediaErrorMethods;
@ -45,13 +45,13 @@ use time::{self, Timespec, Duration};
#[dom_struct] #[dom_struct]
pub struct HTMLMediaElement { pub struct HTMLMediaElement {
htmlelement: HTMLElement, htmlelement: HTMLElement,
/// https://html.spec.whatwg.org/multipage/#dom-media-networkstate-2 /// https://html.spec.whatwg.org/multipage/#dom-media-networkstate
// FIXME(nox): Use an enum. // FIXME(nox): Use an enum.
network_state: Cell<u16>, network_state: Cell<NetworkState>,
/// https://html.spec.whatwg.org/multipage/#dom-media-readystate-2 /// https://html.spec.whatwg.org/multipage/#dom-media-readystate
// FIXME(nox): Use an enum. // FIXME(nox): Use an enum.
ready_state: Cell<u16>, ready_state: Cell<ReadyState>,
/// https://html.spec.whatwg.org/multipage/#dom-media-currentsrc-2 /// https://html.spec.whatwg.org/multipage/#dom-media-currentsrc
current_src: DOMRefCell<String>, current_src: DOMRefCell<String>,
// FIXME(nox): Document this one, I have no idea what it is used for. // FIXME(nox): Document this one, I have no idea what it is used for.
generation_id: Cell<u32>, generation_id: Cell<u32>,
@ -59,9 +59,9 @@ pub struct HTMLMediaElement {
/// ///
/// Reset to false every time the load algorithm is invoked. /// Reset to false every time the load algorithm is invoked.
fired_loadeddata_event: Cell<bool>, fired_loadeddata_event: Cell<bool>,
/// https://html.spec.whatwg.org/multipage/#dom-media-error-2 /// https://html.spec.whatwg.org/multipage/#dom-media-error
error: MutNullableJS<MediaError>, error: MutNullableJS<MediaError>,
/// https://html.spec.whatwg.org/multipage/#dom-media-paused-2 /// https://html.spec.whatwg.org/multipage/#dom-media-paused
paused: Cell<bool>, paused: Cell<bool>,
/// https://html.spec.whatwg.org/multipage/#attr-media-autoplay /// https://html.spec.whatwg.org/multipage/#attr-media-autoplay
autoplaying: Cell<bool>, autoplaying: Cell<bool>,
@ -70,6 +70,27 @@ pub struct HTMLMediaElement {
video: DOMRefCell<Option<VideoMedia>>, video: DOMRefCell<Option<VideoMedia>>,
} }
/// https://html.spec.whatwg.org/multipage/#dom-media-networkstate
#[derive(Clone, Copy, HeapSizeOf, JSTraceable, PartialEq)]
#[repr(u8)]
enum NetworkState {
Empty = HTMLMediaElementConstants::NETWORK_EMPTY as u8,
Idle = HTMLMediaElementConstants::NETWORK_IDLE as u8,
Loading = HTMLMediaElementConstants::NETWORK_LOADING as u8,
NoSource = HTMLMediaElementConstants::NETWORK_NO_SOURCE as u8,
}
/// https://html.spec.whatwg.org/multipage/#dom-media-readystate
#[derive(Clone, Copy, HeapSizeOf, JSTraceable, PartialEq, PartialOrd)]
#[repr(u8)]
enum ReadyState {
HaveNothing = HTMLMediaElementConstants::HAVE_NOTHING as u8,
HaveMetadata = HTMLMediaElementConstants::HAVE_METADATA as u8,
HaveCurrentData = HTMLMediaElementConstants::HAVE_CURRENT_DATA as u8,
HaveFutureData = HTMLMediaElementConstants::HAVE_FUTURE_DATA as u8,
HaveEnoughData = HTMLMediaElementConstants::HAVE_ENOUGH_DATA as u8,
}
#[derive(HeapSizeOf, JSTraceable)] #[derive(HeapSizeOf, JSTraceable)]
pub struct VideoMedia { pub struct VideoMedia {
format: String, format: String,
@ -89,8 +110,8 @@ impl HTMLMediaElement {
) -> Self { ) -> Self {
Self { Self {
htmlelement: HTMLElement::new_inherited(tag_name, prefix, document), htmlelement: HTMLElement::new_inherited(tag_name, prefix, document),
network_state: Cell::new(NETWORK_EMPTY), network_state: Cell::new(NetworkState::Empty),
ready_state: Cell::new(HAVE_NOTHING), ready_state: Cell::new(ReadyState::HaveNothing),
current_src: DOMRefCell::new("".to_owned()), current_src: DOMRefCell::new("".to_owned()),
generation_id: Cell::new(0), generation_id: Cell::new(0),
fired_loadeddata_event: Cell::new(false), fired_loadeddata_event: Cell::new(false),
@ -173,11 +194,11 @@ impl HTMLMediaElement {
} }
// https://html.spec.whatwg.org/multipage/#ready-states // https://html.spec.whatwg.org/multipage/#ready-states
fn change_ready_state(&self, ready_state: u16) { fn change_ready_state(&self, ready_state: ReadyState) {
let old_ready_state = self.ready_state.get(); let old_ready_state = self.ready_state.get();
self.ready_state.set(ready_state); self.ready_state.set(ready_state);
if self.network_state.get() == NETWORK_EMPTY { if self.network_state.get() == NetworkState::Empty {
return; return;
} }
@ -186,9 +207,9 @@ impl HTMLMediaElement {
// Step 1 // Step 1
match (old_ready_state, ready_state) { match (old_ready_state, ready_state) {
// previous ready state was HAVE_NOTHING, and the new ready state is // Previous ready state was ReadyState::HaveNothing,
// HAVE_METADATA // and the new ready state is ReadyState::HaveMetadata.
(HAVE_NOTHING, HAVE_METADATA) => { (ReadyState::HaveNothing, ReadyState::HaveMetadata) => {
task_source.queue_simple_event( task_source.queue_simple_event(
self.upcast(), self.upcast(),
atom!("loadedmetadata"), atom!("loadedmetadata"),
@ -196,11 +217,11 @@ impl HTMLMediaElement {
); );
} }
// previous ready state was HAVE_METADATA and the new ready state is // Previous ready state was ReadyState::HaveMetadata, and the new
// HAVE_CURRENT_DATA or greater // ready state is ReadyState::HaveCurrentData or greater.
(HAVE_METADATA, HAVE_CURRENT_DATA) | (ReadyState::HaveMetadata, ReadyState::HaveCurrentData) |
(HAVE_METADATA, HAVE_FUTURE_DATA) | (ReadyState::HaveMetadata, ReadyState::HaveFutureData) |
(HAVE_METADATA, HAVE_ENOUGH_DATA) => { (ReadyState::HaveMetadata, ReadyState::HaveEnoughData) => {
if !self.fired_loadeddata_event.get() { if !self.fired_loadeddata_event.get() {
self.fired_loadeddata_event.set(true); self.fired_loadeddata_event.set(true);
task_source.queue_simple_event( task_source.queue_simple_event(
@ -211,29 +232,29 @@ impl HTMLMediaElement {
} }
} }
// previous ready state was HAVE_FUTURE_DATA or more, and the new ready // previous ready state was ReadyState::HaveFutureData or more,
// state is HAVE_CURRENT_DATA or less // and the new ready state is ReadyState::HaveCurrentData or less.
(HAVE_FUTURE_DATA, HAVE_CURRENT_DATA) | (ReadyState::HaveFutureData, ReadyState::HaveCurrentData) |
(HAVE_ENOUGH_DATA, HAVE_CURRENT_DATA) | (ReadyState::HaveEnoughData, ReadyState::HaveCurrentData) |
(HAVE_FUTURE_DATA, HAVE_METADATA) | (ReadyState::HaveFutureData, ReadyState::HaveMetadata) |
(HAVE_ENOUGH_DATA, HAVE_METADATA) | (ReadyState::HaveEnoughData, ReadyState::HaveMetadata) |
(HAVE_FUTURE_DATA, HAVE_NOTHING) | (ReadyState::HaveFutureData, ReadyState::HaveNothing) |
(HAVE_ENOUGH_DATA, HAVE_NOTHING) => { (ReadyState::HaveEnoughData, ReadyState::HaveNothing) => {
// TODO: timeupdate event logic + waiting // TODO: timeupdate event logic + waiting
} }
_ => (), _ => (),
} }
// Step 1 // Step 1.
// If the new ready state is HAVE_FUTURE_DATA or HAVE_ENOUGH_DATA, // If the new ready state is ReadyState::HaveFutureData or ReadyState::HaveEnoughData,
// then the relevant steps below must then be run also. // then the relevant steps below must then be run also.
match (old_ready_state, ready_state) { match (old_ready_state, ready_state) {
// previous ready state was HAVE_CURRENT_DATA or less, and the new ready // Previous ready state was ReadyState::HaveCurrentData or less,
// state is HAVE_FUTURE_DATA // and the new ready state is ReadyState::HaveFutureData.
(HAVE_CURRENT_DATA, HAVE_FUTURE_DATA) | (ReadyState::HaveCurrentData, ReadyState::HaveFutureData) |
(HAVE_METADATA, HAVE_FUTURE_DATA) | (ReadyState::HaveMetadata, ReadyState::HaveFutureData) |
(HAVE_NOTHING, HAVE_FUTURE_DATA) => { (ReadyState::HaveNothing, ReadyState::HaveFutureData) => {
task_source.queue_simple_event( task_source.queue_simple_event(
self.upcast(), self.upcast(),
atom!("canplay"), atom!("canplay"),
@ -245,9 +266,9 @@ impl HTMLMediaElement {
} }
} }
// new ready state is HAVE_ENOUGH_DATA // New ready state is ReadyState::HaveEnoughData.
(_, HAVE_ENOUGH_DATA) => { (_, ReadyState::HaveEnoughData) => {
if old_ready_state <= HAVE_CURRENT_DATA { if old_ready_state <= ReadyState::HaveCurrentData {
task_source.queue_simple_event( task_source.queue_simple_event(
self.upcast(), self.upcast(),
atom!("canplay"), atom!("canplay"),
@ -294,7 +315,7 @@ impl HTMLMediaElement {
// https://html.spec.whatwg.org/multipage/#concept-media-load-algorithm // https://html.spec.whatwg.org/multipage/#concept-media-load-algorithm
fn invoke_resource_selection_algorithm(&self) { fn invoke_resource_selection_algorithm(&self) {
// Step 1 // Step 1
self.network_state.set(NETWORK_NO_SOURCE); self.network_state.set(NetworkState::NoSource);
// TODO step 2 (show poster) // TODO step 2 (show poster)
// TODO step 3 (delay load event) // TODO step 3 (delay load event)
@ -323,12 +344,12 @@ impl HTMLMediaElement {
// TODO <source> child // TODO <source> child
ResourceSelectionMode::Children(panic!()) ResourceSelectionMode::Children(panic!())
} else { } else {
self.network_state.set(NETWORK_EMPTY); self.network_state.set(NetworkState::Empty);
return; return;
}; };
// Step 7 // Step 7
self.network_state.set(NETWORK_LOADING); self.network_state.set(NetworkState::Loading);
// Step 8 // Step 8
let window = window_from_node(self); let window = window_from_node(self);
@ -384,7 +405,7 @@ impl HTMLMediaElement {
// 4.1 // 4.1
if self.Preload() == "none" && !self.autoplaying.get() { if self.Preload() == "none" && !self.autoplaying.get() {
// 4.1.1 // 4.1.1
self.network_state.set(NETWORK_IDLE); self.network_state.set(NetworkState::Idle);
// 4.1.2 // 4.1.2
let window = window_from_node(self); let window = window_from_node(self);
@ -460,7 +481,7 @@ impl HTMLMediaElement {
// TODO step 2 (forget resource tracks) // TODO step 2 (forget resource tracks)
// Step 3 // Step 3
self.network_state.set(NETWORK_NO_SOURCE); self.network_state.set(NetworkState::NoSource);
// TODO step 4 (show poster) // TODO step 4 (show poster)
@ -487,8 +508,8 @@ impl HTMLMediaElement {
let task_source = window.dom_manipulation_task_source(); let task_source = window.dom_manipulation_task_source();
// Step 3 // Step 3
let network_state = self.NetworkState(); let network_state = self.network_state.get();
if network_state == NETWORK_LOADING || network_state == NETWORK_IDLE { if network_state == NetworkState::Loading || network_state == NetworkState::Idle {
task_source.queue_simple_event( task_source.queue_simple_event(
self.upcast(), self.upcast(),
atom!("abort"), atom!("abort"),
@ -497,7 +518,7 @@ impl HTMLMediaElement {
} }
// Step 4 // Step 4
if network_state != NETWORK_EMPTY { if network_state != NetworkState::Empty {
// 4.1 // 4.1
task_source.queue_simple_event(self.upcast(), atom!("emptied"), &window); task_source.queue_simple_event(self.upcast(), atom!("emptied"), &window);
@ -507,8 +528,8 @@ impl HTMLMediaElement {
// TODO 4.4 (forget resource tracks) // TODO 4.4 (forget resource tracks)
// 4.5 // 4.5
if self.ready_state.get() != HAVE_NOTHING { if self.ready_state.get() != ReadyState::HaveNothing {
self.change_ready_state(HAVE_NOTHING); self.change_ready_state(ReadyState::HaveNothing);
} }
// 4.6 // 4.6
@ -536,12 +557,12 @@ impl HTMLMediaElement {
impl HTMLMediaElementMethods for HTMLMediaElement { impl HTMLMediaElementMethods for HTMLMediaElement {
// https://html.spec.whatwg.org/multipage/#dom-media-networkstate // https://html.spec.whatwg.org/multipage/#dom-media-networkstate
fn NetworkState(&self) -> u16 { fn NetworkState(&self) -> u16 {
self.network_state.get() self.network_state.get() as u16
} }
// https://html.spec.whatwg.org/multipage/#dom-media-readystate // https://html.spec.whatwg.org/multipage/#dom-media-readystate
fn ReadyState(&self) -> u16 { fn ReadyState(&self) -> u16 {
self.ready_state.get() self.ready_state.get() as u16
} }
// https://html.spec.whatwg.org/multipage/#dom-media-autoplay // https://html.spec.whatwg.org/multipage/#dom-media-autoplay
@ -594,7 +615,7 @@ impl HTMLMediaElementMethods for HTMLMediaElement {
// TODO step 3 // TODO step 3
// Step 4 // Step 4
if self.network_state.get() == NETWORK_EMPTY { if self.network_state.get() == NetworkState::Empty {
self.invoke_resource_selection_algorithm(); self.invoke_resource_selection_algorithm();
} }
@ -618,9 +639,9 @@ impl HTMLMediaElementMethods for HTMLMediaElement {
task_source.queue_simple_event(self.upcast(), atom!("play"), &window); task_source.queue_simple_event(self.upcast(), atom!("play"), &window);
// 7.4 // 7.4
if state == HAVE_NOTHING || if state == ReadyState::HaveNothing ||
state == HAVE_METADATA || state == ReadyState::HaveMetadata ||
state == HAVE_CURRENT_DATA { state == ReadyState::HaveCurrentData {
task_source.queue_simple_event( task_source.queue_simple_event(
self.upcast(), self.upcast(),
atom!("waiting"), atom!("waiting"),
@ -631,7 +652,7 @@ impl HTMLMediaElementMethods for HTMLMediaElement {
} }
} }
// Step 8 // Step 8
else if state == HAVE_FUTURE_DATA || state == HAVE_ENOUGH_DATA { else if state == ReadyState::HaveFutureData || state == ReadyState::HaveEnoughData {
// TODO resolve pending play promises // TODO resolve pending play promises
} }
@ -646,7 +667,7 @@ impl HTMLMediaElementMethods for HTMLMediaElement {
// https://html.spec.whatwg.org/multipage/#dom-media-pause // https://html.spec.whatwg.org/multipage/#dom-media-pause
fn Pause(&self) { fn Pause(&self) {
// Step 1 // Step 1
if self.network_state.get() == NETWORK_EMPTY { if self.network_state.get() == NetworkState::Empty {
self.invoke_resource_selection_algorithm(); self.invoke_resource_selection_algorithm();
} }
@ -808,7 +829,7 @@ impl FetchResponseListener for HTMLMediaElementContext {
if !self.have_metadata { if !self.have_metadata {
self.check_metadata(&elem); self.check_metadata(&elem);
} else { } else {
elem.change_ready_state(HAVE_CURRENT_DATA); elem.change_ready_state(ReadyState::HaveCurrentData);
} }
// https://html.spec.whatwg.org/multipage/#concept-media-load-resource step 4, // https://html.spec.whatwg.org/multipage/#concept-media-load-resource step 4,
@ -835,22 +856,22 @@ impl FetchResponseListener for HTMLMediaElementContext {
} }
// => "Once the entire media resource has been fetched..." // => "Once the entire media resource has been fetched..."
else if status.is_ok() { else if status.is_ok() {
elem.change_ready_state(HAVE_ENOUGH_DATA); elem.change_ready_state(ReadyState::HaveEnoughData);
elem.upcast::<EventTarget>().fire_event(atom!("progress")); elem.upcast::<EventTarget>().fire_event(atom!("progress"));
elem.network_state.set(NETWORK_IDLE); elem.network_state.set(NetworkState::Idle);
elem.upcast::<EventTarget>().fire_event(atom!("suspend")); elem.upcast::<EventTarget>().fire_event(atom!("suspend"));
} }
// => "If the connection is interrupted after some media data has been received..." // => "If the connection is interrupted after some media data has been received..."
else if elem.ready_state.get() != HAVE_NOTHING { else if elem.ready_state.get() != ReadyState::HaveNothing {
// Step 2 // Step 2
elem.error.set(Some(&*MediaError::new(&*window_from_node(&*elem), elem.error.set(Some(&*MediaError::new(&*window_from_node(&*elem),
MEDIA_ERR_NETWORK))); MEDIA_ERR_NETWORK)));
// Step 3 // Step 3
elem.network_state.set(NETWORK_IDLE); elem.network_state.set(NetworkState::Idle);
// TODO: Step 4 - update delay load flag // TODO: Step 4 - update delay load flag
@ -901,7 +922,7 @@ impl HTMLMediaElementContext {
audio: meta.audio.audio, audio: meta.audio.audio,
}); });
// Step 6 // Step 6
elem.change_ready_state(HAVE_METADATA); elem.change_ready_state(ReadyState::HaveMetadata);
self.have_metadata = true; self.have_metadata = true;
} }
_ => {} _ => {}