Auto merge of #18368 - servo:media-event-cleanup, r=emilio

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

<!-- Reviewable:start -->
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/18368)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2017-09-04 09:20:53 -05:00 committed by GitHub
commit 293ffa06da
2 changed files with 149 additions and 126 deletions

View file

@ -1,75 +1,79 @@
serif
sans-serif
cursive
fantasy
monospace
left
center
right
none
hidden
submit
button
reset
radio
checkbox
file
image
password
text
search
url
tel
email
datetime
date
month
week
time
datetime-local
number
dir
DOMContentLoaded
select
input
load
loadstart
loadend
progress
transitionend
error
readystatechange
message
close
storage
activate
webglcontextcreationerror
mouseover
beforeunload
message
click
keydown
keypress
abort
invalid
activate
beforeunload
button
canplay
canplaythrough
center
change
open
toggle
statechange
controllerchange
fetch
characteristicvaluechanged
checkbox
click
close
controllerchange
cursive
date
datetime
datetime-local
dir
DOMContentLoaded
email
emptied
error
fantasy
fetch
file
fullscreenchange
fullscreenerror
gattserverdisconnected
hidden
image
input
invalid
keydown
keypress
left
load
loadeddata
loadedmetadata
loadend
loadstart
message
message
monospace
month
mouseover
none
number
onchange
reftest-wait
screen
open
password
pause
play
playing
print
progress
radio
readystatechange
reftest-wait
reset
right
sans-serif
screen
search
select
serif
statechange
storage
submit
suspend
tel
text
time
timeupdate
toggle
transitionend
url
waiting
webglcontextcreationerror
week

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>,
}