mirror of
https://github.com/servo/servo.git
synced 2025-07-23 07:13:52 +01:00
Decouple media load blockers from their resource URL
A media element can delay the document's load event without having a resource URL, and it can even block it while being inserted into a different document AFAIK.
This commit is contained in:
parent
da392e3524
commit
40a72f3e83
2 changed files with 56 additions and 29 deletions
|
@ -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,
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue