mirror of
https://github.com/servo/servo.git
synced 2025-07-22 23:03:42 +01:00
Put HTMLMediaElement first in its module
This commit is contained in:
parent
f5e23a3a90
commit
e169acd1d6
1 changed files with 174 additions and 174 deletions
|
@ -42,180 +42,6 @@ use std::sync::{Arc, Mutex};
|
|||
use task_source::TaskSource;
|
||||
use time::{self, Timespec, Duration};
|
||||
|
||||
struct HTMLMediaElementContext {
|
||||
/// The element that initiated the request.
|
||||
elem: Trusted<HTMLMediaElement>,
|
||||
/// The response body received to date.
|
||||
data: Vec<u8>,
|
||||
/// The response metadata received to date.
|
||||
metadata: Option<Metadata>,
|
||||
/// The generation of the media element when this fetch started.
|
||||
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.
|
||||
ignore_response: bool,
|
||||
}
|
||||
|
||||
impl FetchResponseListener for HTMLMediaElementContext {
|
||||
fn process_request_body(&mut self) {}
|
||||
|
||||
fn process_request_eof(&mut self) {}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#media-data-processing-steps-list
|
||||
fn process_response(&mut self, metadata: Result<FetchMetadata, NetworkError>) {
|
||||
self.metadata = metadata.ok().map(|m| {
|
||||
match m {
|
||||
FetchMetadata::Unfiltered(m) => m,
|
||||
FetchMetadata::Filtered { unsafe_, .. } => unsafe_
|
||||
}
|
||||
});
|
||||
|
||||
// => "If the media data cannot be fetched at all..."
|
||||
let is_failure = self.metadata
|
||||
.as_ref()
|
||||
.and_then(|m| m.status
|
||||
.as_ref()
|
||||
.map(|&(s, _)| s < 200 || s >= 300))
|
||||
.unwrap_or(false);
|
||||
if is_failure {
|
||||
// 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.
|
||||
self.ignore_response = true;
|
||||
}
|
||||
}
|
||||
|
||||
fn process_response_chunk(&mut self, mut payload: Vec<u8>) {
|
||||
if self.ignore_response {
|
||||
return;
|
||||
}
|
||||
|
||||
self.data.append(&mut payload);
|
||||
|
||||
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 {
|
||||
self.check_metadata(&elem);
|
||||
} 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 {
|
||||
let window = window_from_node(&*elem);
|
||||
window.dom_manipulation_task_source().queue_simple_event(
|
||||
elem.upcast(),
|
||||
atom!("progress"),
|
||||
&window,
|
||||
);
|
||||
self.next_progress_event = time::get_time() + Duration::milliseconds(350);
|
||||
}
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#media-data-processing-steps-list
|
||||
fn process_response_eof(&mut self, status: Result<(), NetworkError>) {
|
||||
let elem = self.elem.root();
|
||||
|
||||
// => "If the media data can be fetched but is found by inspection to be in an unsupported
|
||||
// format, or can otherwise not be rendered at all"
|
||||
if !self.have_metadata {
|
||||
elem.queue_dedicated_media_source_failure_steps();
|
||||
}
|
||||
// => "Once the entire media resource has been fetched..."
|
||||
else if status.is_ok() {
|
||||
elem.change_ready_state(HAVE_ENOUGH_DATA);
|
||||
|
||||
elem.upcast::<EventTarget>().fire_event(atom!("progress"));
|
||||
|
||||
elem.network_state.set(NETWORK_IDLE);
|
||||
|
||||
elem.upcast::<EventTarget>().fire_event(atom!("suspend"));
|
||||
}
|
||||
// => "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: Step 4 - update delay load flag
|
||||
|
||||
// Step 5
|
||||
elem.upcast::<EventTarget>().fire_event(atom!("error"));
|
||||
} else {
|
||||
// => "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()));
|
||||
}
|
||||
}
|
||||
|
||||
impl PreInvoke for HTMLMediaElementContext {
|
||||
fn should_invoke(&self) -> bool {
|
||||
//TODO: finish_load needs to run at some point if the generation changes.
|
||||
self.elem.root().generation_id.get() == self.generation_id
|
||||
}
|
||||
}
|
||||
|
||||
impl HTMLMediaElementContext {
|
||||
fn new(elem: &HTMLMediaElement, url: ServoUrl) -> 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,
|
||||
}
|
||||
}
|
||||
|
||||
fn check_metadata(&mut self, elem: &HTMLMediaElement) {
|
||||
match audio_video_metadata::get_format_from_slice(&self.data) {
|
||||
Ok(audio_video_metadata::Metadata::Video(meta)) => {
|
||||
let dur = meta.audio.duration.unwrap_or(::std::time::Duration::new(0, 0));
|
||||
*elem.video.borrow_mut() = Some(VideoMedia {
|
||||
format: format!("{:?}", meta.format),
|
||||
duration: Duration::seconds(dur.as_secs() as i64) +
|
||||
Duration::nanoseconds(dur.subsec_nanos() as i64),
|
||||
width: meta.dimensions.width,
|
||||
height: meta.dimensions.height,
|
||||
video: meta.video.unwrap_or("".to_owned()),
|
||||
audio: meta.audio.audio,
|
||||
});
|
||||
// Step 6
|
||||
elem.change_ready_state(HAVE_METADATA);
|
||||
self.have_metadata = true;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(HeapSizeOf, JSTraceable)]
|
||||
pub struct VideoMedia {
|
||||
format: String,
|
||||
#[ignore_heap_size_of = "defined in time"]
|
||||
duration: Duration,
|
||||
width: u32,
|
||||
height: u32,
|
||||
video: String,
|
||||
audio: Option<String>,
|
||||
}
|
||||
|
||||
#[dom_struct]
|
||||
pub struct HTMLMediaElement {
|
||||
htmlelement: HTMLElement,
|
||||
|
@ -230,6 +56,17 @@ pub struct HTMLMediaElement {
|
|||
video: DOMRefCell<Option<VideoMedia>>,
|
||||
}
|
||||
|
||||
#[derive(HeapSizeOf, JSTraceable)]
|
||||
pub struct VideoMedia {
|
||||
format: String,
|
||||
#[ignore_heap_size_of = "defined in time"]
|
||||
duration: Duration,
|
||||
width: u32,
|
||||
height: u32,
|
||||
video: String,
|
||||
audio: Option<String>,
|
||||
}
|
||||
|
||||
impl HTMLMediaElement {
|
||||
pub fn new_inherited(tag_name: LocalName,
|
||||
prefix: Option<Prefix>, document: &Document)
|
||||
|
@ -888,3 +725,166 @@ enum Resource {
|
|||
Object,
|
||||
Url(ServoUrl),
|
||||
}
|
||||
|
||||
struct HTMLMediaElementContext {
|
||||
/// The element that initiated the request.
|
||||
elem: Trusted<HTMLMediaElement>,
|
||||
/// The response body received to date.
|
||||
data: Vec<u8>,
|
||||
/// The response metadata received to date.
|
||||
metadata: Option<Metadata>,
|
||||
/// The generation of the media element when this fetch started.
|
||||
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.
|
||||
ignore_response: bool,
|
||||
}
|
||||
|
||||
impl FetchResponseListener for HTMLMediaElementContext {
|
||||
fn process_request_body(&mut self) {}
|
||||
|
||||
fn process_request_eof(&mut self) {}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#media-data-processing-steps-list
|
||||
fn process_response(&mut self, metadata: Result<FetchMetadata, NetworkError>) {
|
||||
self.metadata = metadata.ok().map(|m| {
|
||||
match m {
|
||||
FetchMetadata::Unfiltered(m) => m,
|
||||
FetchMetadata::Filtered { unsafe_, .. } => unsafe_
|
||||
}
|
||||
});
|
||||
|
||||
// => "If the media data cannot be fetched at all..."
|
||||
let is_failure = self.metadata
|
||||
.as_ref()
|
||||
.and_then(|m| m.status
|
||||
.as_ref()
|
||||
.map(|&(s, _)| s < 200 || s >= 300))
|
||||
.unwrap_or(false);
|
||||
if is_failure {
|
||||
// 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.
|
||||
self.ignore_response = true;
|
||||
}
|
||||
}
|
||||
|
||||
fn process_response_chunk(&mut self, mut payload: Vec<u8>) {
|
||||
if self.ignore_response {
|
||||
return;
|
||||
}
|
||||
|
||||
self.data.append(&mut payload);
|
||||
|
||||
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 {
|
||||
self.check_metadata(&elem);
|
||||
} 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 {
|
||||
let window = window_from_node(&*elem);
|
||||
window.dom_manipulation_task_source().queue_simple_event(
|
||||
elem.upcast(),
|
||||
atom!("progress"),
|
||||
&window,
|
||||
);
|
||||
self.next_progress_event = time::get_time() + Duration::milliseconds(350);
|
||||
}
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#media-data-processing-steps-list
|
||||
fn process_response_eof(&mut self, status: Result<(), NetworkError>) {
|
||||
let elem = self.elem.root();
|
||||
|
||||
// => "If the media data can be fetched but is found by inspection to be in an unsupported
|
||||
// format, or can otherwise not be rendered at all"
|
||||
if !self.have_metadata {
|
||||
elem.queue_dedicated_media_source_failure_steps();
|
||||
}
|
||||
// => "Once the entire media resource has been fetched..."
|
||||
else if status.is_ok() {
|
||||
elem.change_ready_state(HAVE_ENOUGH_DATA);
|
||||
|
||||
elem.upcast::<EventTarget>().fire_event(atom!("progress"));
|
||||
|
||||
elem.network_state.set(NETWORK_IDLE);
|
||||
|
||||
elem.upcast::<EventTarget>().fire_event(atom!("suspend"));
|
||||
}
|
||||
// => "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: Step 4 - update delay load flag
|
||||
|
||||
// Step 5
|
||||
elem.upcast::<EventTarget>().fire_event(atom!("error"));
|
||||
} else {
|
||||
// => "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()));
|
||||
}
|
||||
}
|
||||
|
||||
impl PreInvoke for HTMLMediaElementContext {
|
||||
fn should_invoke(&self) -> bool {
|
||||
//TODO: finish_load needs to run at some point if the generation changes.
|
||||
self.elem.root().generation_id.get() == self.generation_id
|
||||
}
|
||||
}
|
||||
|
||||
impl HTMLMediaElementContext {
|
||||
fn new(elem: &HTMLMediaElement, url: ServoUrl) -> 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,
|
||||
}
|
||||
}
|
||||
|
||||
fn check_metadata(&mut self, elem: &HTMLMediaElement) {
|
||||
match audio_video_metadata::get_format_from_slice(&self.data) {
|
||||
Ok(audio_video_metadata::Metadata::Video(meta)) => {
|
||||
let dur = meta.audio.duration.unwrap_or(::std::time::Duration::new(0, 0));
|
||||
*elem.video.borrow_mut() = Some(VideoMedia {
|
||||
format: format!("{:?}", meta.format),
|
||||
duration: Duration::seconds(dur.as_secs() as i64) +
|
||||
Duration::nanoseconds(dur.subsec_nanos() as i64),
|
||||
width: meta.dimensions.width,
|
||||
height: meta.dimensions.height,
|
||||
video: meta.video.unwrap_or("".to_owned()),
|
||||
audio: meta.audio.audio,
|
||||
});
|
||||
// Step 6
|
||||
elem.change_ready_state(HAVE_METADATA);
|
||||
self.have_metadata = true;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue