diff --git a/components/script/dom/htmlmediaelement.rs b/components/script/dom/htmlmediaelement.rs
index 59ebbd10aea..594c0ea221e 100644
--- a/components/script/dom/htmlmediaelement.rs
+++ b/components/script/dom/htmlmediaelement.rs
@@ -12,6 +12,8 @@ use dom::bindings::codegen::Bindings::HTMLMediaElementBinding::HTMLMediaElementC
use dom::bindings::codegen::Bindings::HTMLMediaElementBinding::HTMLMediaElementMethods;
use dom::bindings::codegen::Bindings::MediaErrorBinding::MediaErrorConstants::*;
use dom::bindings::codegen::Bindings::MediaErrorBinding::MediaErrorMethods;
+use dom::bindings::codegen::InheritTypes::{ElementTypeId, HTMLElementTypeId};
+use dom::bindings::codegen::InheritTypes::{HTMLMediaElementTypeId, NodeTypeId};
use dom::bindings::inheritance::Castable;
use dom::bindings::js::{MutNullableJS, Root};
use dom::bindings::refcounted::Trusted;
@@ -20,10 +22,8 @@ use dom::bindings::str::DOMString;
use dom::document::Document;
use dom::element::{Element, AttributeMutation};
use dom::eventtarget::EventTarget;
-use dom::htmlaudioelement::HTMLAudioElement;
use dom::htmlelement::HTMLElement;
use dom::htmlsourceelement::HTMLSourceElement;
-use dom::htmlvideoelement::HTMLVideoElement;
use dom::mediaerror::MediaError;
use dom::node::{window_from_node, document_from_node, Node, UnbindContext};
use dom::virtualmethods::VirtualMethods;
@@ -32,6 +32,7 @@ use html5ever::{LocalName, Prefix};
use ipc_channel::ipc;
use ipc_channel::router::ROUTER;
use microtask::{Microtask, MicrotaskRunnable};
+use mime::{Mime, SubLevel, TopLevel};
use net_traits::{FetchResponseListener, FetchMetadata, Metadata, NetworkError};
use net_traits::request::{CredentialsMode, Destination, RequestInit, Type as RequestType};
use network_listener::{NetworkListener, PreInvoke};
@@ -123,6 +124,17 @@ impl HTMLMediaElement {
}
}
+ fn media_type_id(&self) -> HTMLMediaElementTypeId {
+ match self.upcast::().type_id() {
+ NodeTypeId::Element(ElementTypeId::HTMLElement(
+ HTMLElementTypeId::HTMLMediaElement(media_type_id),
+ )) => {
+ media_type_id
+ },
+ _ => unreachable!(),
+ }
+ }
+
/// https://html.spec.whatwg.org/multipage/#internal-pause-steps
fn internal_pause_steps(&self) {
// Step 1.
@@ -199,23 +211,19 @@ impl HTMLMediaElement {
let window = window_from_node(self);
let task_source = window.dom_manipulation_task_source();
- // Step 1
+ // Step 1.
match (old_ready_state, ready_state) {
- // Previous ready state was ReadyState::HaveNothing,
- // and the new ready state is ReadyState::HaveMetadata.
(ReadyState::HaveNothing, ReadyState::HaveMetadata) => {
task_source.queue_simple_event(
self.upcast(),
atom!("loadedmetadata"),
&window,
);
- }
- // Previous ready state was ReadyState::HaveMetadata, and the new
- // ready state is ReadyState::HaveCurrentData or greater.
- (ReadyState::HaveMetadata, ReadyState::HaveCurrentData) |
- (ReadyState::HaveMetadata, ReadyState::HaveFutureData) |
- (ReadyState::HaveMetadata, ReadyState::HaveEnoughData) => {
+ // No other steps are applicable in this case.
+ return;
+ },
+ (ReadyState::HaveMetadata, new) if new >= ReadyState::HaveCurrentData => {
if !self.fired_loadeddata_event.get() {
self.fired_loadeddata_event.set(true);
task_source.queue_simple_event(
@@ -224,128 +232,127 @@ impl HTMLMediaElement {
&window,
);
}
- }
- // previous ready state was ReadyState::HaveFutureData or more,
- // and the new ready state is ReadyState::HaveCurrentData or less.
- (ReadyState::HaveFutureData, ReadyState::HaveCurrentData) |
- (ReadyState::HaveEnoughData, ReadyState::HaveCurrentData) |
- (ReadyState::HaveFutureData, ReadyState::HaveMetadata) |
- (ReadyState::HaveEnoughData, ReadyState::HaveMetadata) |
- (ReadyState::HaveFutureData, ReadyState::HaveNothing) |
- (ReadyState::HaveEnoughData, ReadyState::HaveNothing) => {
- // TODO: timeupdate event logic + waiting
- }
+ // Steps for the transition from HaveMetadata to HaveCurrentData
+ // or HaveFutureData also apply here, as per the next match
+ // expression.
+ },
+ (ReadyState::HaveFutureData, new) if new <= ReadyState::HaveCurrentData => {
+ // FIXME(nox): Queue a task to fire timeupdate and waiting
+ // events if the conditions call from the spec are met.
+
+ // No other steps are applicable in this case.
+ return;
+ },
_ => (),
}
- // Step 1.
- // If the new ready state is ReadyState::HaveFutureData or ReadyState::HaveEnoughData,
- // then the relevant steps below must then be run also.
- match (old_ready_state, ready_state) {
- // Previous ready state was ReadyState::HaveCurrentData or less,
- // and the new ready state is ReadyState::HaveFutureData.
- (ReadyState::HaveCurrentData, ReadyState::HaveFutureData) |
- (ReadyState::HaveMetadata, ReadyState::HaveFutureData) |
- (ReadyState::HaveNothing, ReadyState::HaveFutureData) => {
- task_source.queue_simple_event(
- self.upcast(),
- atom!("canplay"),
- &window,
- );
+ if old_ready_state <= ReadyState::HaveCurrentData && ready_state >= ReadyState::HaveFutureData {
+ task_source.queue_simple_event(
+ self.upcast(),
+ atom!("canplay"),
+ &window,
+ );
- if !self.Paused() {
- self.notify_about_playing();
- }
+ if !self.Paused() {
+ self.notify_about_playing();
}
-
- // New ready state is ReadyState::HaveEnoughData.
- (_, ReadyState::HaveEnoughData) => {
- if old_ready_state <= ReadyState::HaveCurrentData {
- task_source.queue_simple_event(
- self.upcast(),
- atom!("canplay"),
- &window,
- );
-
- if !self.Paused() {
- self.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 step 2: show poster
- // Step 3
- task_source.queue_simple_event(
- self.upcast(),
- atom!("play"),
- &window,
- );
- // Step 4
- self.notify_about_playing();
- // Step 5
- self.autoplaying.set(false);
- }
-
- task_source.queue_simple_event(
- self.upcast(),
- atom!("canplaythrough"),
- &window,
- );
- }
-
- _ => (),
}
- // TODO Step 2: media controller
+ if ready_state == ReadyState::HaveEnoughData {
+ // TODO: Check sandboxed automatic features browsing context flag.
+ // FIXME(nox): I have no idea what this TODO is about.
+
+ // FIXME(nox): Review this block.
+ if self.autoplaying.get() &&
+ self.Paused() &&
+ self.Autoplay() {
+ // Step 1
+ self.paused.set(false);
+ // TODO step 2: show poster
+ // Step 3
+ task_source.queue_simple_event(
+ self.upcast(),
+ atom!("play"),
+ &window,
+ );
+ // Step 4
+ self.notify_about_playing();
+ // Step 5
+ self.autoplaying.set(false);
+ }
+
+ // FIXME(nox): According to the spec, this should come *before* the
+ // "play" event.
+ task_source.queue_simple_event(
+ self.upcast(),
+ atom!("canplaythrough"),
+ &window,
+ );
+ }
+
+ // TODO Step 2: Media controller.
+ // FIXME(nox): There is no step 2 in the spec.
}
// https://html.spec.whatwg.org/multipage/#concept-media-load-algorithm
fn invoke_resource_selection_algorithm(&self) {
- // Step 1
+ // Step 1.
self.network_state.set(NetworkState::NoSource);
- // TODO step 2 (show poster)
- // TODO step 3 (delay load event)
+ // Step 2.
+ // FIXME(nox): Set show poster flag to true.
- // Step 4
+ // Step 3.
+ // FIXME(nox): Set the delaying-the-load-event flag to true.
+
+ // Step 4.
+ // If the resource selection mode in the synchronous section is
+ // "attribute", the URL of the resource to fetch is relative to the
+ // media element's node document when the src attribute was last
+ // changed, which is why we need to pass the base URL in the task
+ // right here.
let doc = document_from_node(self);
let task = MediaElementMicrotask::ResourceSelectionTask {
elem: Root::from_ref(self),
base_url: doc.base_url()
};
+
+ // FIXME(nox): This will later call the resource_selection_algorith_sync
+ // method from below, if microtasks were trait objects, we would be able
+ // to put the code directly in this method, without the boilerplate
+ // indirections.
ScriptThread::await_stable_state(Microtask::MediaElement(task));
}
// https://html.spec.whatwg.org/multipage/#concept-media-load-algorithm
- #[allow(unreachable_code)]
+ // FIXME(nox): Why does this need to be passed the base URL?
fn resource_selection_algorithm_sync(&self, base_url: ServoUrl) {
- // TODO step 5 (populate pending text tracks)
+ // Step 5.
+ // FIXME(nox): Maybe populate the list of pending text tracks.
- // Step 6
- let mode = if false {
- // TODO media provider object
- ResourceSelectionMode::Object
- } else if let Some(attr) = self.upcast::().get_attribute(&ns!(), &local_name!("src")) {
- ResourceSelectionMode::Attribute(attr.Value().to_string())
- } else if false { // TODO: when implementing this remove #[allow(unreachable_code)] above.
- // TODO child
- ResourceSelectionMode::Children(panic!())
+ // Step 6.
+ enum Mode {
+ // FIXME(nox): Support media object provider.
+ #[allow(dead_code)]
+ Object,
+ Attribute(String),
+ // FIXME(nox): Support source element child.
+ #[allow(dead_code)]
+ Children(Root),
+ }
+ let mode = if let Some(attr) = self.upcast::().get_attribute(&ns!(), &local_name!("src")) {
+ Mode::Attribute(attr.Value().into())
} else {
self.network_state.set(NetworkState::Empty);
return;
};
- // Step 7
+ // Step 7.
self.network_state.set(NetworkState::Loading);
- // Step 8
+ // Step 8.
let window = window_from_node(self);
window.dom_manipulation_task_source().queue_simple_event(
self.upcast(),
@@ -353,110 +360,130 @@ impl HTMLMediaElement {
&window,
);
- // Step 9
+ // Step 9.
match mode {
- ResourceSelectionMode::Object => {
- // Step 1
+ // Step 9.obj.
+ Mode::Object => {
+ // Step 9.obj.1.
*self.current_src.borrow_mut() = "".to_owned();
- // Step 4
- self.resource_fetch_algorithm(Resource::Object);
- }
+ // Step 9.obj.2.
+ // FIXME(nox): The rest of the steps should be ran in parallel.
- ResourceSelectionMode::Attribute(src) => {
- // Step 1
+ // Step 9.obj.3.
+ // Note that the resource fetch algorithm itself takes care
+ // of the cleanup in case of failure itself.
+ // FIXME(nox): Pass the assigned media provider here.
+ self.resource_fetch_algorithm(Resource::Object);
+ },
+ Mode::Attribute(src) => {
+ // Step 9.attr.1.
if src.is_empty() {
self.queue_dedicated_media_source_failure_steps();
return;
}
- // Step 2
- let absolute_url = base_url.join(&src).map_err(|_| ());
+ // Step 9.attr.2.
+ let url_record = match base_url.join(&src) {
+ Ok(url) => url,
+ Err(_) => {
+ self.queue_dedicated_media_source_failure_steps();
+ return;
+ }
+ };
- // Step 3
- if let Ok(url) = absolute_url {
- *self.current_src.borrow_mut() = url.as_str().into();
- // Step 4
- self.resource_fetch_algorithm(Resource::Url(url));
- } else {
- self.queue_dedicated_media_source_failure_steps();
- }
- }
+ // Step 9.attr.3.
+ *self.current_src.borrow_mut() = url_record.as_str().into();
- ResourceSelectionMode::Children(_child) => {
- // TODO
+ // Step 9.attr.4.
+ // Note that the resource fetch algorithm itself takes care
+ // of the cleanup in case of failure itself.
+ self.resource_fetch_algorithm(Resource::Url(url_record));
+ },
+ Mode::Children(_source) => {
+ // Step 9.children.
self.queue_dedicated_media_source_failure_steps()
- }
+ },
}
}
// https://html.spec.whatwg.org/multipage/#concept-media-load-resource
fn resource_fetch_algorithm(&self, resource: Resource) {
- // TODO step 3 (remove text tracks)
+ // Steps 1-2.
+ // Unapplicable, the `resource` variable already conveys which mode
+ // is in use.
- // Step 4
- if let Resource::Url(url) = resource {
- // 4.1
- if self.Preload() == "none" && !self.autoplaying.get() {
- // 4.1.1
- self.network_state.set(NetworkState::Idle);
+ // Step 3.
+ // FIXME(nox): Remove all media-resource-specific text tracks.
- // 4.1.2
+ // Step 4.
+ match resource {
+ Resource::Url(url) => {
+ // Step 4.remote.1.
+ if self.Preload() == "none" && !self.autoplaying.get() {
+ // Step 4.remote.1.1.
+ self.network_state.set(NetworkState::Idle);
+
+ // Step 4.remote.1.2.
+ let window = window_from_node(self);
+ window.dom_manipulation_task_source().queue_simple_event(
+ self.upcast(),
+ atom!("suspend"),
+ &window,
+ );
+
+ // Step 4.remote.1.3.
+ // FIXME(nox): Queue a task to set the delaying-the-load-event
+ // flag to false.
+
+ // Steps 4.remote.1.4.
+ // FIXME(nox): Somehow we should wait for the task from previous
+ // step to be ran before continuing.
+
+ // Steps 4.remote.1.5-4.remote.1.7.
+ // FIXME(nox): Wait for an implementation-defined event and
+ // then continue with the normal set of steps instead of just
+ // returning.
+ return;
+ }
+
+ // Step 4.remote.2.
+ // FIXME(nox): Handle CORS setting from crossorigin attribute.
+ let document = document_from_node(self);
+ let type_ = match self.media_type_id() {
+ HTMLMediaElementTypeId::HTMLAudioElement => RequestType::Audio,
+ HTMLMediaElementTypeId::HTMLVideoElement => RequestType::Video,
+ };
+ let request = RequestInit {
+ url: url.clone(),
+ type_,
+ destination: Destination::Media,
+ credentials_mode: CredentialsMode::Include,
+ use_url_credentials: true,
+ origin: document.origin().immutable().clone(),
+ pipeline_id: Some(self.global().pipeline_id()),
+ referrer_url: Some(document.url()),
+ referrer_policy: document.get_referrer_policy(),
+ .. RequestInit::default()
+ };
+
+ let context = Arc::new(Mutex::new(HTMLMediaElementContext::new(self, url.clone())));
+ let (action_sender, action_receiver) = ipc::channel().unwrap();
let window = window_from_node(self);
- window.dom_manipulation_task_source().queue_simple_event(
- self.upcast(),
- atom!("suspend"),
- &window,
- );
-
- // TODO 4.1.3 (delay load flag)
-
- // TODO 4.1.5-7 (state for load that initiates later)
- return;
- }
-
- // 4.2
- let context = Arc::new(Mutex::new(HTMLMediaElementContext::new(self, url.clone())));
- let (action_sender, action_receiver) = ipc::channel().unwrap();
- let window = window_from_node(self);
- let listener = NetworkListener {
- context: context,
- task_source: window.networking_task_source(),
- canceller: Some(window.task_canceller())
- };
-
- ROUTER.add_route(action_receiver.to_opaque(), box move |message| {
- listener.notify_fetch(message.to().unwrap());
- });
-
- // FIXME: we're supposed to block the load event much earlier than now
- let document = document_from_node(self);
-
- let ty = if self.is::() {
- RequestType::Audio
- } else if self.is::() {
- RequestType::Video
- } else {
- unreachable!("Unexpected HTMLMediaElement")
- };
-
- let request = RequestInit {
- url: url.clone(),
- type_: ty,
- destination: Destination::Media,
- credentials_mode: CredentialsMode::Include,
- use_url_credentials: true,
- origin: document.origin().immutable().clone(),
- pipeline_id: Some(self.global().pipeline_id()),
- referrer_url: Some(document.url()),
- referrer_policy: document.get_referrer_policy(),
- .. RequestInit::default()
- };
-
- document.fetch_async(LoadType::Media(url), request, action_sender);
- } else {
- // TODO local resource fetch
- self.queue_dedicated_media_source_failure_steps();
+ let listener = NetworkListener {
+ context: context,
+ task_source: window.networking_task_source(),
+ canceller: Some(window.task_canceller())
+ };
+ 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);
+ },
+ Resource::Object => {
+ // FIXME(nox): Use the current media resource.
+ self.queue_dedicated_media_source_failure_steps();
+ },
}
}
@@ -505,59 +532,78 @@ impl HTMLMediaElement {
// this invokation of the load algorithm.
self.fired_loadeddata_event.set(false);
- // TODO Step 1 (abort resource selection algorithm instances)
+ // Step 1.
+ // FIXME(nox): Abort any already-running instance of the
+ // resource selection algorithm.
- // Step 2
+ // Steps 2-4.
+ // FIXME(nox): Cancel all tasks related to this element and resolve or
+ // reject all pending play promises.
self.generation_id.set(self.generation_id.get() + 1);
- // TODO reject pending play promises
let window = window_from_node(self);
let task_source = window.dom_manipulation_task_source();
- // Step 3
+ // Step 5.
let network_state = self.network_state.get();
if network_state == NetworkState::Loading || network_state == NetworkState::Idle {
- task_source.queue_simple_event(
- self.upcast(),
- atom!("abort"),
- &window,
- );
+ task_source.queue_simple_event(self.upcast(), atom!("abort"), &window);
}
- // Step 4
+ // Step 6.
if network_state != NetworkState::Empty {
- // 4.1
+ // Step 6.1.
task_source.queue_simple_event(self.upcast(), atom!("emptied"), &window);
- // TODO 4.2 (abort in-progress fetch)
+ // Step 6.2.
+ // FIXME(nox): Abort in-progress fetching process.
- // TODO 4.3 (detach media provider object)
- // TODO 4.4 (forget resource tracks)
+ // Step 6.3.
+ // FIXME(nox): Detach MediaSource media provider object.
- // 4.5
+ // Step 6.4.
+ // FIXME(nox): Forget the media-resource-specific tracks.
+
+ // Step 6.5.
if self.ready_state.get() != ReadyState::HaveNothing {
self.change_ready_state(ReadyState::HaveNothing);
}
- // 4.6
+ // Step 6.6.
if !self.Paused() {
+ // Step 6.6.1.
self.paused.set(true);
+
+ // Step 6.6.2.
+ // FIXME(nox): Reject pending play promises.
}
- // TODO 4.7 (seeking)
- // TODO 4.8 (playback position)
- // TODO 4.9 (timeline offset)
- // TODO 4.10 (duration)
+
+ // Step 6.7.
+ // FIXME(nox): If seeking is true, set it to false.
+
+ // Step 6.8.
+ // FIXME(nox): Set current and official playback position to 0 and
+ // maybe queue a task to fire a timeupdate event.
+
+ // Step 6.9.
+ // FIXME(nox): Set timeline offset to NaN.
+
+ // Step 6.10.
+ // FIXME(nox): Set duration to NaN.
}
- // TODO step 5 (playback rate)
- // Step 6
+ // Step 7.
+ // FIXME(nox): Set playbackRate to defaultPlaybackRate.
+
+ // Step 8.
self.error.set(None);
self.autoplaying.set(true);
- // Step 7
+ // Step 9.
self.invoke_resource_selection_algorithm();
- // TODO step 8 (stop previously playing resource)
+ // Step 10.
+ // FIXME(nox): Stop playback of any previously running media resource.
}
}
@@ -599,9 +645,14 @@ impl HTMLMediaElementMethods for HTMLMediaElement {
}
// https://html.spec.whatwg.org/multipage/#dom-navigator-canplaytype
- fn CanPlayType(&self, _type_: DOMString) -> CanPlayTypeResult {
- // TODO: application/octet-stream
- CanPlayTypeResult::Maybe
+ fn CanPlayType(&self, type_: DOMString) -> CanPlayTypeResult {
+ match type_.parse::() {
+ Ok(Mime(TopLevel::Application, SubLevel::OctetStream, _)) |
+ Err(_) => {
+ CanPlayTypeResult::_empty
+ },
+ _ => CanPlayTypeResult::Maybe
+ }
}
// https://html.spec.whatwg.org/multipage/#dom-media-error
@@ -610,65 +661,70 @@ impl HTMLMediaElementMethods for HTMLMediaElement {
}
// https://html.spec.whatwg.org/multipage/#dom-media-play
+ // FIXME(nox): This should return a promise.
fn Play(&self) {
- // TODO step 1
+ // Step 1.
+ // FIXME(nox): Return a rejected promise if not allowed to play.
- // Step 2
+ // Step 2.
if self.error.get().map_or(false, |e| e.Code() == MEDIA_ERR_SRC_NOT_SUPPORTED) {
- // TODO return rejected promise
+ // FIXME(nox): This should return a rejected promise.
return;
}
- // TODO step 3
+ // Step 3.
+ // Create promise and add it to list of pending play promises.
- // Step 4
+ // Step 4.
if self.network_state.get() == NetworkState::Empty {
self.invoke_resource_selection_algorithm();
}
- // TODO step 5 (seek backwards)
-
- // TODO step 6 (media controller)
+ // Step 5.
+ // FIXME(nox): Seek to earliest possible position if playback has ended
+ // and direction of playback is forwards.
let state = self.ready_state.get();
- // Step 7
if self.Paused() {
- // 7.1
+ // Step 6.1.
self.paused.set(false);
- // TODO 7.2 (show poster)
+ // Step 6.2.
+ // FIXME(nox): Set show poster flag to false and run time marches on
+ // steps if show poster flag is true.
+ // Step 6.3.
let window = window_from_node(self);
let task_source = window.dom_manipulation_task_source();
-
- // 7.3
task_source.queue_simple_event(self.upcast(), atom!("play"), &window);
- // 7.4
- if state == ReadyState::HaveNothing ||
- state == ReadyState::HaveMetadata ||
- state == ReadyState::HaveCurrentData {
- task_source.queue_simple_event(
- self.upcast(),
- atom!("waiting"),
- &window,
- );
- } else {
- self.notify_about_playing();
+ // Step 7.4.
+ match state {
+ ReadyState::HaveNothing |
+ ReadyState::HaveMetadata |
+ ReadyState::HaveCurrentData => {
+ task_source.queue_simple_event(
+ self.upcast(),
+ atom!("waiting"),
+ &window,
+ );
+ },
+ ReadyState::HaveFutureData |
+ ReadyState::HaveEnoughData => {
+ self.notify_about_playing();
+ }
}
- }
- // Step 8
- else if state == ReadyState::HaveFutureData || state == ReadyState::HaveEnoughData {
- // TODO resolve pending play promises
+ } else if state == ReadyState::HaveFutureData || state == ReadyState::HaveEnoughData {
+ // Step 7.
+ // FIXME(nox): Queue a task to resolve pending play promises.
}
- // Step 9
+ // Step 8.
self.autoplaying.set(false);
- // TODO step 10 (media controller)
-
- // TODO return promise
+ // Step 9.
+ // FIXME(nox): Return promise created in step 3.
}
// https://html.spec.whatwg.org/multipage/#dom-media-pause
@@ -745,12 +801,6 @@ impl MicrotaskRunnable for MediaElementMicrotask {
}
}
-enum ResourceSelectionMode {
- Object,
- Attribute(String),
- Children(Root),
-}
-
enum Resource {
Object,
Url(ServoUrl),
@@ -775,12 +825,12 @@ struct HTMLMediaElementContext {
ignore_response: bool,
}
+// https://html.spec.whatwg.org/multipage/#media-data-processing-steps-list
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) {
self.metadata = metadata.ok().map(|m| {
match m {
@@ -789,23 +839,24 @@ impl FetchResponseListener for HTMLMediaElementContext {
}
});
+ let status_is_ok = self.metadata.as_ref()
+ .and_then(|m| m.status.as_ref())
+ .map_or(true, |s| s.0 >= 200 && s.0 < 300);
+
// => "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 {
+ 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.
+ // 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.
self.ignore_response = true;
}
}
fn process_response_chunk(&mut self, mut payload: Vec) {
if self.ignore_response {
+ // An error was received previously, skip processing the payload.
return;
}
diff --git a/tests/wpt/metadata/html/semantics/embedded-content/media-elements/mime-types/canPlayType.html.ini b/tests/wpt/metadata/html/semantics/embedded-content/media-elements/mime-types/canPlayType.html.ini
index c5491bf470e..dc43bf6b602 100644
--- a/tests/wpt/metadata/html/semantics/embedded-content/media-elements/mime-types/canPlayType.html.ini
+++ b/tests/wpt/metadata/html/semantics/embedded-content/media-elements/mime-types/canPlayType.html.ini
@@ -1,8 +1,5 @@
[canPlayType.html]
type: testharness
- [application/octet-stream]
- expected: FAIL
-
[video/x-new-fictional-format]
expected: FAIL