Do not NIH queueing a task to fire an event in htmlmediaelement

This commit is contained in:
Anthony Ramine 2017-09-04 16:14:04 +02:00
parent 6168e898c1
commit 62c73b61b7
2 changed files with 89 additions and 59 deletions

View file

@ -19,7 +19,7 @@ use dom::bindings::reflector::DomObject;
use dom::bindings::str::DOMString;
use dom::document::Document;
use dom::element::{Element, AttributeMutation};
use dom::event::{Event, EventBubbles, EventCancelable};
use dom::eventtarget::EventTarget;
use dom::htmlaudioelement::HTMLAudioElement;
use dom::htmlelement::HTMLElement;
use dom::htmlsourceelement::HTMLSourceElement;
@ -36,7 +36,6 @@ use net_traits::{FetchResponseListener, FetchMetadata, Metadata, NetworkError};
use net_traits::request::{CredentialsMode, Destination, RequestInit, Type as RequestType};
use network_listener::{NetworkListener, PreInvoke};
use script_thread::{Runnable, ScriptThread};
use servo_atoms::Atom;
use servo_url::ServoUrl;
use std::cell::Cell;
use std::sync::{Arc, Mutex};
@ -111,7 +110,12 @@ impl FetchResponseListener for HTMLMediaElementContext {
// 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");
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);
}
}
@ -129,11 +133,11 @@ impl FetchResponseListener for HTMLMediaElementContext {
else if status.is_ok() {
elem.change_ready_state(HAVE_ENOUGH_DATA);
elem.fire_simple_event("progress");
elem.upcast::<EventTarget>().fire_event(atom!("progress"));
elem.network_state.set(NETWORK_IDLE);
elem.fire_simple_event("suspend");
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 {
@ -147,7 +151,7 @@ impl FetchResponseListener for HTMLMediaElementContext {
// TODO: Step 4 - update delay load flag
// Step 5
elem.fire_simple_event("error");
elem.upcast::<EventTarget>().fire_event(atom!("error"));
} else {
// => "If the media data cannot be fetched at all..."
elem.queue_dedicated_media_source_failure_steps();
@ -267,7 +271,7 @@ impl HTMLMediaElement {
// https://html.spec.whatwg.org/multipage/#notify-about-playing
fn notify_about_playing(&self) {
// Step 1
self.fire_simple_event("playing");
self.upcast::<EventTarget>().fire_event(atom!("playing"));
// TODO Step 2
}
@ -297,11 +301,11 @@ impl HTMLMediaElement {
impl Runnable for Task {
fn handler(self: Box<Task>) {
let elem = self.elem.root();
let target = Root::upcast::<EventTarget>(self.elem.root());
// 2.2.1
elem.fire_simple_event("timeupdate");
target.fire_event(atom!("timeupdate"));
// 2.2.2
elem.fire_simple_event("pause");
target.fire_event(atom!("pause"));
// TODO 2.2.3
}
}
@ -313,21 +317,6 @@ impl HTMLMediaElement {
let _ = win.dom_manipulation_task_source().queue(task, win.upcast());
}
fn queue_fire_simple_event(&self, type_: &'static str) {
let win = window_from_node(self);
let task = box FireSimpleEventTask::new(self, type_);
let _ = win.dom_manipulation_task_source().queue(task, win.upcast());
}
fn fire_simple_event(&self, type_: &str) {
let window = window_from_node(self);
let event = Event::new(window.upcast(),
Atom::from(type_),
EventBubbles::DoesNotBubble,
EventCancelable::NotCancelable);
event.fire(self.upcast());
}
// https://html.spec.whatwg.org/multipage/#ready-states
fn change_ready_state(&self, ready_state: u16) {
let old_ready_state = self.ready_state.get();
@ -337,12 +326,19 @@ impl HTMLMediaElement {
return;
}
let window = window_from_node(self);
let task_source = window.dom_manipulation_task_source();
// Step 1
match (old_ready_state, ready_state) {
// previous ready state was HAVE_NOTHING, and the new ready state is
// HAVE_METADATA
(HAVE_NOTHING, HAVE_METADATA) => {
self.queue_fire_simple_event("loadedmetadata");
task_source.queue_simple_event(
self.upcast(),
atom!("loadedmetadata"),
&window,
);
}
// previous ready state was HAVE_METADATA and the new ready state is
@ -352,7 +348,11 @@ impl HTMLMediaElement {
(HAVE_METADATA, HAVE_ENOUGH_DATA) => {
if self.first_data_load.get() {
self.first_data_load.set(false);
self.queue_fire_simple_event("loadeddata");
task_source.queue_simple_event(
self.upcast(),
atom!("loadeddata"),
&window,
);
}
}
@ -379,7 +379,11 @@ impl HTMLMediaElement {
(HAVE_CURRENT_DATA, HAVE_FUTURE_DATA) |
(HAVE_METADATA, HAVE_FUTURE_DATA) |
(HAVE_NOTHING, HAVE_FUTURE_DATA) => {
self.queue_fire_simple_event("canplay");
task_source.queue_simple_event(
self.upcast(),
atom!("canplay"),
&window,
);
if !self.Paused() {
self.queue_notify_about_playing();
@ -389,7 +393,11 @@ impl HTMLMediaElement {
// new ready state is HAVE_ENOUGH_DATA
(_, HAVE_ENOUGH_DATA) => {
if old_ready_state <= HAVE_CURRENT_DATA {
self.queue_fire_simple_event("canplay");
task_source.queue_simple_event(
self.upcast(),
atom!("canplay"),
&window,
);
if !self.Paused() {
self.queue_notify_about_playing();
@ -404,14 +412,22 @@ impl HTMLMediaElement {
self.paused.set(false);
// TODO step 2: show poster
// Step 3
self.queue_fire_simple_event("play");
task_source.queue_simple_event(
self.upcast(),
atom!("play"),
&window,
);
// Step 4
self.queue_notify_about_playing();
// Step 5
self.autoplaying.set(false);
}
self.queue_fire_simple_event("canplaythrough");
task_source.queue_simple_event(
self.upcast(),
atom!("canplaythrough"),
&window,
);
}
_ => (),
@ -460,7 +476,12 @@ impl HTMLMediaElement {
self.network_state.set(NETWORK_LOADING);
// Step 8
self.queue_fire_simple_event("loadstart");
let window = window_from_node(self);
window.dom_manipulation_task_source().queue_simple_event(
self.upcast(),
atom!("loadstart"),
&window,
);
// Step 9
match mode {
@ -511,7 +532,12 @@ impl HTMLMediaElement {
self.network_state.set(NETWORK_IDLE);
// 4.1.2
self.queue_fire_simple_event("suspend");
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)
@ -584,7 +610,7 @@ impl HTMLMediaElement {
// TODO step 4 (show poster)
// Step 5
self.fire_simple_event("error");
self.upcast::<EventTarget>().fire_event(atom!("error"));
// TODO step 6 (resolve pending play promises)
// TODO step 7 (delay load event)
@ -600,16 +626,23 @@ impl HTMLMediaElement {
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
let network_state = self.NetworkState();
if network_state == NETWORK_LOADING || network_state == NETWORK_IDLE {
self.queue_fire_simple_event("abort");
task_source.queue_simple_event(
self.upcast(),
atom!("abort"),
&window,
);
}
// Step 4
if network_state != NETWORK_EMPTY {
// 4.1
self.queue_fire_simple_event("emptied");
task_source.queue_simple_event(self.upcast(), atom!("emptied"), &window);
// TODO 4.2 (abort in-progress fetch)
@ -721,14 +754,21 @@ impl HTMLMediaElementMethods for HTMLMediaElement {
// TODO 7.2 (show poster)
let window = window_from_node(self);
let task_source = window.dom_manipulation_task_source();
// 7.3
self.queue_fire_simple_event("play");
task_source.queue_simple_event(self.upcast(), atom!("play"), &window);
// 7.4
if state == HAVE_NOTHING ||
state == HAVE_METADATA ||
state == HAVE_CURRENT_DATA {
self.queue_fire_simple_event("waiting");
task_source.queue_simple_event(
self.upcast(),
atom!("waiting"),
&window,
);
} else {
self.queue_notify_about_playing();
}
@ -820,27 +860,6 @@ impl MicrotaskRunnable for MediaElementMicrotask {
}
}
struct FireSimpleEventTask {
elem: Trusted<HTMLMediaElement>,
type_: &'static str,
}
impl FireSimpleEventTask {
fn new(target: &HTMLMediaElement, type_: &'static str) -> FireSimpleEventTask {
FireSimpleEventTask {
elem: Trusted::new(target),
type_: type_,
}
}
}
impl Runnable for FireSimpleEventTask {
fn handler(self: Box<FireSimpleEventTask>) {
let elem = self.elem.root();
elem.fire_simple_event(self.type_);
}
}
struct DedicatedMediaSourceFailureTask {
elem: Trusted<HTMLMediaElement>,
}