diff options
Diffstat (limited to 'components/script/dom/htmlmediaelement.rs')
-rw-r--r-- | components/script/dom/htmlmediaelement.rs | 75 |
1 files changed, 51 insertions, 24 deletions
diff --git a/components/script/dom/htmlmediaelement.rs b/components/script/dom/htmlmediaelement.rs index 13986728f32..90efb26e1f3 100644 --- a/components/script/dom/htmlmediaelement.rs +++ b/components/script/dom/htmlmediaelement.rs @@ -3,7 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use audio_video_metadata; -use document_loader::LoadType; +use document_loader::{LoadBlocker, LoadType}; use dom::attr::Attr; use dom::bindings::cell::DOMRefCell; use dom::bindings::codegen::Bindings::AttrBinding::AttrMethods; @@ -71,6 +71,8 @@ pub struct HTMLMediaElement { paused: Cell<bool>, /// https://html.spec.whatwg.org/multipage/#attr-media-autoplay autoplaying: Cell<bool>, + /// https://html.spec.whatwg.org/multipage/#delaying-the-load-event-flag + delaying_the_load_event_flag: DOMRefCell<Option<LoadBlocker>>, /// https://html.spec.whatwg.org/multipage/#list-of-pending-play-promises #[ignore_heap_size_of = "promises are hard"] pending_play_promises: DOMRefCell<Vec<Rc<Promise>>>, @@ -131,6 +133,7 @@ impl HTMLMediaElement { paused: Cell::new(true), // FIXME(nox): Why is this initialised to true? autoplaying: Cell::new(true), + delaying_the_load_event_flag: Default::default(), pending_play_promises: Default::default(), in_flight_play_promises_queue: Default::default(), video: DOMRefCell::new(None), @@ -148,6 +151,21 @@ impl HTMLMediaElement { } } + /// Marks that element as delaying the load event or not. + /// + /// Nothing happens if the element was already delaying the load event and + /// we pass true to that method again. + /// + /// https://html.spec.whatwg.org/multipage/#delaying-the-load-event-flag + fn delay_load_event(&self, delay: bool) { + let mut blocker = self.delaying_the_load_event_flag.borrow_mut(); + if delay && blocker.is_none() { + *blocker = Some(LoadBlocker::new(&document_from_node(self), LoadType::Media)); + } else if !delay && blocker.is_some() { + LoadBlocker::terminate(&mut *blocker); + } + } + /// https://html.spec.whatwg.org/multipage/#dom-media-play // FIXME(nox): Move this back to HTMLMediaElementMethods::Play once // Rc<Promise> doesn't require #[allow(unrooted_must_root)] anymore. @@ -335,10 +353,15 @@ impl HTMLMediaElement { (ReadyState::HaveMetadata, new) if new >= ReadyState::HaveCurrentData => { if !self.fired_loadeddata_event.get() { self.fired_loadeddata_event.set(true); - task_source.queue_simple_event( - self.upcast(), - atom!("loadeddata"), - &window, + let this = Trusted::new(self); + // FIXME(nox): Why are errors silenced here? + let _ = task_source.queue( + task!(media_reached_current_data: move || { + let this = this.root(); + this.upcast::<EventTarget>().fire_event(atom!("loadeddata")); + this.delay_load_event(false); + }), + window.upcast(), ); } @@ -411,7 +434,7 @@ impl HTMLMediaElement { // FIXME(nox): Set show poster flag to true. // Step 3. - // FIXME(nox): Set the delaying-the-load-event flag to true. + self.delay_load_event(true); // Step 4. // If the resource selection mode in the synchronous section is @@ -462,6 +485,8 @@ impl HTMLMediaElement { mode } else { self.network_state.set(NetworkState::Empty); + // https://github.com/whatwg/html/issues/3065 + self.delay_load_event(false); return; }; @@ -549,8 +574,13 @@ impl HTMLMediaElement { ); // Step 4.remote.1.3. - // FIXME(nox): Queue a task to set the delaying-the-load-event - // flag to false. + let this = Trusted::new(self); + window.dom_manipulation_task_source().queue( + task!(set_media_delay_load_event_flag_to_false: move || { + this.root().delay_load_event(false); + }), + window.upcast(), + ).unwrap(); // Steps 4.remote.1.4. // FIXME(nox): Somehow we should wait for the task from previous @@ -571,7 +601,7 @@ impl HTMLMediaElement { HTMLMediaElementTypeId::HTMLVideoElement => RequestType::Video, }; let request = RequestInit { - url: url.clone(), + url, type_, destination: Destination::Media, credentials_mode: CredentialsMode::Include, @@ -583,7 +613,7 @@ impl HTMLMediaElement { .. RequestInit::default() }; - let context = Arc::new(Mutex::new(HTMLMediaElementContext::new(self, url.clone()))); + let context = Arc::new(Mutex::new(HTMLMediaElementContext::new(self))); let (action_sender, action_receiver) = ipc::channel().unwrap(); let window = window_from_node(self); let listener = NetworkListener { @@ -594,7 +624,7 @@ impl HTMLMediaElement { ROUTER.add_route(action_receiver.to_opaque(), box move |message| { listener.notify_fetch(message.to().unwrap()); }); - document.fetch_async(LoadType::Media(url), request, action_sender); + document.loader().fetch_async_background(request, action_sender); }, Resource::Object => { // FIXME(nox): Use the current media resource. @@ -645,7 +675,7 @@ impl HTMLMediaElement { }); // Step 7. - // FIXME(nox): Set the delaying-the-load-event flag to false. + this.delay_load_event(false); }), window.upcast(), ); @@ -952,8 +982,6 @@ struct HTMLMediaElementContext { generation_id: u32, /// Time of last progress notification. next_progress_event: Timespec, - /// Url of resource requested. - url: ServoUrl, /// Whether the media metadata has been completely received. have_metadata: bool, /// True if this response is invalid and should be ignored. @@ -981,11 +1009,9 @@ impl FetchResponseListener for HTMLMediaElementContext { // => "If the media data cannot be fetched at all..." if !status_is_ok { // Ensure that the element doesn't receive any further notifications - // of the aborted fetch. The dedicated failure steps will be - // executed when response_complete runs. - // FIXME(nox): According to the spec, we shouldn't wait to receive - // the whole response before running the dedicated failure steps. + // of the aborted fetch. self.ignore_response = true; + self.elem.root().queue_dedicated_media_source_failure_steps(); } } @@ -1022,6 +1048,10 @@ impl FetchResponseListener for HTMLMediaElementContext { // https://html.spec.whatwg.org/multipage/#media-data-processing-steps-list fn process_response_eof(&mut self, status: Result<(), NetworkError>) { + if self.ignore_response { + // An error was received previously, skip processing the payload. + return; + } let elem = self.elem.root(); // => "If the media data can be fetched but is found by inspection to be in an unsupported @@ -1048,7 +1078,8 @@ impl FetchResponseListener for HTMLMediaElementContext { // Step 3 elem.network_state.set(NetworkState::Idle); - // TODO: Step 4 - update delay load flag + // Step 4. + elem.delay_load_event(false); // Step 5 elem.upcast::<EventTarget>().fire_event(atom!("error")); @@ -1056,9 +1087,6 @@ impl FetchResponseListener for HTMLMediaElementContext { // => "If the media data cannot be fetched at all..." elem.queue_dedicated_media_source_failure_steps(); } - - let document = document_from_node(&*elem); - document.finish_load(LoadType::Media(self.url.clone())); } } @@ -1070,14 +1098,13 @@ impl PreInvoke for HTMLMediaElementContext { } impl HTMLMediaElementContext { - fn new(elem: &HTMLMediaElement, url: ServoUrl) -> HTMLMediaElementContext { + fn new(elem: &HTMLMediaElement) -> HTMLMediaElementContext { HTMLMediaElementContext { elem: Trusted::new(elem), data: vec![], metadata: None, generation_id: elem.generation_id.get(), next_progress_event: time::get_time() + Duration::milliseconds(350), - url: url, have_metadata: false, ignore_response: false, } |