diff options
-rw-r--r-- | components/script/dom/htmlmediaelement.rs | 180 | ||||
-rw-r--r-- | components/script/dom/webidls/MediaError.webidl | 1 |
2 files changed, 135 insertions, 46 deletions
diff --git a/components/script/dom/htmlmediaelement.rs b/components/script/dom/htmlmediaelement.rs index 3d7fd6fa850..25e1c9bbb66 100644 --- a/components/script/dom/htmlmediaelement.rs +++ b/components/script/dom/htmlmediaelement.rs @@ -10,6 +10,7 @@ use dom::bindings::codegen::Bindings::HTMLMediaElementBinding::CanPlayTypeResult use dom::bindings::codegen::Bindings::HTMLMediaElementBinding::HTMLMediaElementConstants::*; use dom::bindings::codegen::Bindings::HTMLMediaElementBinding::HTMLMediaElementMethods; use dom::bindings::codegen::Bindings::MediaErrorBinding::MediaErrorConstants::*; +use dom::bindings::codegen::Bindings::MediaErrorBinding::MediaErrorMethods; use dom::bindings::global::GlobalRef; use dom::bindings::inheritance::Castable; use dom::bindings::js::{Root, MutNullableHeap, JS}; @@ -31,8 +32,8 @@ use script_thread::{Runnable, ScriptThread}; use std::cell::Cell; use std::sync::{Arc, Mutex}; use string_cache::Atom; -use task_source::dom_manipulation::DOMManipulationTask; use task_source::TaskSource; +use task_source::dom_manipulation::DOMManipulationTask; use time::{self, Timespec, Duration}; use url::Url; use util::str::DOMString; @@ -56,7 +57,6 @@ struct HTMLMediaElementContext { ignore_response: bool, } -// https://html.spec.whatwg.org/multipage/#media-data-processing-steps-list impl AsyncResponseListener for HTMLMediaElementContext { // https://html.spec.whatwg.org/multipage/#media-data-processing-steps-list fn headers_available(&mut self, metadata: Result<Metadata, NetworkError>) { @@ -87,14 +87,20 @@ impl AsyncResponseListener for HTMLMediaElementContext { let elem = self.elem.root(); + // https://html.spec.whatwg.org/multipage/#media-data-processing-steps-list + // => "Once enough of the media data has been fetched to determine the duration..." if !self.have_metadata { //TODO: actually check if the payload contains the full metadata + + // Step 6 elem.change_ready_state(HAVE_METADATA); self.have_metadata = true; } else { elem.change_ready_state(HAVE_CURRENT_DATA); } + // https://html.spec.whatwg.org/multipage/#concept-media-load-resource step 4, + // => "If mode is remote" step 2 if time::get_time() > self.next_progress_event { elem.queue_fire_simple_event("progress"); self.next_progress_event = time::get_time() + Duration::milliseconds(350); @@ -105,6 +111,7 @@ impl AsyncResponseListener for HTMLMediaElementContext { fn response_complete(&mut self, status: Result<(), NetworkError>) { let elem = self.elem.root(); + // => "Once the entire media resource has been fetched..." if status.is_ok() { elem.change_ready_state(HAVE_ENOUGH_DATA); @@ -113,16 +120,23 @@ impl AsyncResponseListener for HTMLMediaElementContext { elem.network_state.set(NETWORK_IDLE); elem.fire_simple_event("suspend"); - } else if elem.ready_state.get() != HAVE_NOTHING { + } + // => "If the connection is interrupted after some media data has been received..." + else if elem.ready_state.get() != HAVE_NOTHING { + // Step 2 elem.error.set(Some(&*MediaError::new(&*window_from_node(&*elem), MEDIA_ERR_NETWORK))); + // Step 3 elem.network_state.set(NETWORK_IDLE); - // TODO: update delay load flag + // TODO: Step 4 - update delay load flag + // Step 5 elem.fire_simple_event("error"); - } else { + } + // => "If the media data cannot be fetched at all..." + else { elem.queue_dedicated_media_source_failure_steps(); } @@ -189,7 +203,7 @@ impl HTMLMediaElement { &self.htmlelement } - // https://html.spec.whatwg.org/multipage/#playing-the-media-resource:internal-pause-steps + // https://html.spec.whatwg.org/multipage/#internal-pause-steps fn internal_pause_steps(&self) { // Step 1 self.autoplaying.set(false); @@ -200,17 +214,63 @@ impl HTMLMediaElement { self.paused.set(true); // 2.2 - self.queue_fire_simple_event("timeupdate"); - - // 2.3 - self.queue_fire_simple_event("pause"); + self.queue_internal_pause_steps_task(); - // TODO 2.4 (official playback position) + // TODO 2.3 (official playback position) } // TODO step 3 (media controller) } + // https://html.spec.whatwg.org/multipage/#notify-about-playing + fn notify_about_playing(&self) { + // Step 1 + self.fire_simple_event("playing"); + // TODO Step 2 + } + + fn queue_notify_about_playing(&self) { + struct Task { + elem: Trusted<HTMLMediaElement>, + } + + impl Runnable for Task { + fn handler(self: Box<Task>) { + self.elem.root().notify_about_playing(); + } + } + + let task = Task { + elem: Trusted::new(self), + }; + let win = window_from_node(self); + let _ = win.dom_manipulation_task_source().queue(DOMManipulationTask::MediaTask(box task)); + } + + // https://html.spec.whatwg.org/multipage/#internal-pause-steps step 2.2 + fn queue_internal_pause_steps_task(&self) { + struct Task { + elem: Trusted<HTMLMediaElement>, + } + + impl Runnable for Task { + fn handler(self: Box<Task>) { + let elem = self.elem.root(); + // 2.2.1 + elem.fire_simple_event("timeupdate"); + // 2.2.2 + elem.fire_simple_event("pause"); + // TODO 2.2.3 + } + } + + let task = Task { + elem: Trusted::new(self), + }; + let win = window_from_node(self); + let _ = win.dom_manipulation_task_source().queue(DOMManipulationTask::MediaTask(box task)); + } + fn queue_fire_simple_event(&self, type_: &'static str) { let win = window_from_node(self); let task = FireSimpleEventTask::new(self, type_); @@ -235,6 +295,7 @@ impl HTMLMediaElement { return; } + // Step 1 match (old_ready_state, ready_state) { // previous ready state was HAVE_NOTHING, and the new ready state is // HAVE_METADATA @@ -267,6 +328,7 @@ impl HTMLMediaElement { _ => (), } + // Step 1 // If the new ready state is HAVE_FUTURE_DATA or HAVE_ENOUGH_DATA, // then the relevant steps below must then be run also. match (old_ready_state, ready_state) { @@ -277,8 +339,9 @@ impl HTMLMediaElement { (HAVE_NOTHING, HAVE_FUTURE_DATA) => { self.queue_fire_simple_event("canplay"); - // TODO: check paused state - self.queue_fire_simple_event("playing"); + if !self.Paused() { + self.queue_notify_about_playing(); + } } // new ready state is HAVE_ENOUGH_DATA @@ -287,17 +350,23 @@ impl HTMLMediaElement { self.queue_fire_simple_event("canplay"); if !self.Paused() { - self.queue_fire_simple_event("playing"); + self.queue_notify_about_playing(); } } + //TODO: check sandboxed automatic features browsing context flag if self.autoplaying.get() && self.Paused() && self.Autoplay() { + // Step 1 self.paused.set(false); - // TODO: show poster + // TODO step 2: show poster + // Step 3 self.queue_fire_simple_event("play"); - self.queue_fire_simple_event("playing"); + // Step 4 + self.queue_notify_about_playing(); + // Step 5 + self.autoplaying.set(false); } self.queue_fire_simple_event("canplaythrough"); @@ -305,6 +374,8 @@ impl HTMLMediaElement { _ => (), } + + // TODO Step 2: media controller } // https://html.spec.whatwg.org/multipage/#concept-media-load-algorithm @@ -447,7 +518,8 @@ impl HTMLMediaElement { // Step 5 self.fire_simple_event("error"); - // TODO step 6 (delay load event) + // TODO step 6 (resolve pending play promises) + // TODO step 7 (delay load event) } // https://html.spec.whatwg.org/multipage/#media-element-load-algorithm @@ -458,15 +530,12 @@ impl HTMLMediaElement { // Step 2 self.generation_id.set(self.generation_id.get() + 1); + // TODO reject pending play promises // Step 3 let network_state = self.NetworkState(); - match network_state { - NETWORK_LOADING | - NETWORK_IDLE => { - self.queue_fire_simple_event("abort"); - } - _ => (), + if network_state == NETWORK_LOADING || network_state == NETWORK_IDLE { + self.queue_fire_simple_event("abort"); } // Step 4 @@ -476,18 +545,22 @@ impl HTMLMediaElement { // TODO 4.2 (abort in-progress fetch) - // TODO 4.3 (forget resource tracks) + // TODO 4.3 (detach media provider object) + // TODO 4.4 (forget resource tracks) - // 4.4 - self.change_ready_state(HAVE_NOTHING); + // 4.5 + if self.ready_state.get() != HAVE_NOTHING { + self.change_ready_state(HAVE_NOTHING); + } + // 4.6 if !self.Paused() { self.paused.set(true); } - // TODO 4.6 (seeking) - // TODO 4.7 (playback position) - // TODO 4.8 (timeline offset) - // TODO 4.9 (duration) + // TODO 4.7 (seeking) + // TODO 4.8 (playback position) + // TODO 4.9 (timeline offset) + // TODO 4.10 (duration) } // TODO step 5 (playback rate) @@ -552,40 +625,57 @@ impl HTMLMediaElementMethods for HTMLMediaElement { // https://html.spec.whatwg.org/multipage/#dom-media-play fn Play(&self) { - // Step 1 + // TODO step 1 + + // Step 2 + if self.error.get().map_or(false, |e| e.Code() == MEDIA_ERR_SRC_NOT_SUPPORTED) { + // TODO return rejected promise + return; + } + + // TODO step 3 + + // Step 4 if self.network_state.get() == NETWORK_EMPTY { self.invoke_resource_selection_algorithm(); } - // TODO step 2 (seek backwards) + // TODO step 5 (seek backwards) - // TODO step 3 (media controller) + // TODO step 6 (media controller) - // Step 4 + let state = self.ready_state.get(); + + // Step 7 if self.Paused() { - // 4.1 + // 7.1 self.paused.set(false); - // TODO 4.2 (show poster) + // TODO 7.2 (show poster) - // 4.3 + // 7.3 self.queue_fire_simple_event("play"); - // 4.4 - let state = self.ready_state.get(); + // 7.4 if state == HAVE_NOTHING || state == HAVE_METADATA || state == HAVE_CURRENT_DATA { self.queue_fire_simple_event("waiting"); } else { - self.queue_fire_simple_event("playing"); + self.queue_notify_about_playing(); } + } + // Step 8 + else if state == HAVE_FUTURE_DATA || state == HAVE_ENOUGH_DATA { + // TODO resolve pending play promises + } - // 4.5 - self.autoplaying.set(false); + // Step 9 + self.autoplaying.set(false); - // TODO 4.6 (media controller) - } + // TODO step 10 (media controller) + + // TODO return promise } // https://html.spec.whatwg.org/multipage/#dom-media-pause @@ -623,7 +713,7 @@ impl VirtualMethods for HTMLMediaElement { }; } - // https://html.spec.whatwg.org/multipage/#playing-the-media-resource:media-element-75 + // https://html.spec.whatwg.org/multipage/#playing-the-media-resource:remove-an-element-from-a-document fn unbind_from_tree(&self, context: &UnbindContext) { self.super_type().unwrap().unbind_from_tree(context); diff --git a/components/script/dom/webidls/MediaError.webidl b/components/script/dom/webidls/MediaError.webidl index 7bebcb655cc..4363ae911ba 100644 --- a/components/script/dom/webidls/MediaError.webidl +++ b/components/script/dom/webidls/MediaError.webidl @@ -1,4 +1,3 @@ -/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |