servo: Merge #18368 - Do not NIH queueing a task to fire an event in htmlmediaelement (from servo:media-event-cleanup); r=emilio
authorAnthony Ramine <n.oxyde@gmail.com>
Mon, 04 Sep 2017 09:20:53 -0500
changeset 428271 73a429ddd75bc659b92316fa30287f3bb8b5e826
parent 428270 6e5269790022f4dea5aa98df19f6e6344098c5cd
child 428272 827fae5a03b435b0ce8b96cfdbccebdd596e198e
push id7761
push userjlund@mozilla.com
push dateFri, 15 Sep 2017 00:19:52 +0000
treeherdermozilla-beta@c38455951db4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersemilio
bugs18368
milestone57.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
servo: Merge #18368 - Do not NIH queueing a task to fire an event in htmlmediaelement (from servo:media-event-cleanup); r=emilio Source-Repo: https://github.com/servo/servo Source-Revision: 293ffa06daa5cd2c3588833af3ed211ed3935d36
servo/components/atoms/static_atoms.txt
servo/components/script/dom/htmlmediaelement.rs
--- a/servo/components/atoms/static_atoms.txt
+++ b/servo/components/atoms/static_atoms.txt
@@ -1,75 +1,79 @@
-serif
-sans-serif
-cursive
-fantasy
-monospace
-
-left
-center
-right
-
-none
-
-hidden
-submit
+abort
+activate
+beforeunload
 button
-reset
-radio
+canplay
+canplaythrough
+center
+change
+characteristicvaluechanged
 checkbox
-file
-image
-password
-text
-search
-url
-tel
-email
+click
+close
+controllerchange
+cursive
+date
 datetime
-date
-month
-week
-time
 datetime-local
-number
-
 dir
-
 DOMContentLoaded
-select
-input
-load
-loadstart
-loadend
-progress
-transitionend
+email
+emptied
 error
-readystatechange
-message
-close
-storage
-activate
-webglcontextcreationerror
-mouseover
-beforeunload
-message
-click
-keydown
-keypress
-abort
-invalid
-change
-open
-toggle
-statechange
-controllerchange
+fantasy
 fetch
-characteristicvaluechanged
+file
 fullscreenchange
 fullscreenerror
 gattserverdisconnected
+hidden
+image
+input
+invalid
+keydown
+keypress
+left
+load
+loadeddata
+loadedmetadata
+loadend
+loadstart
+message
+message
+monospace
+month
+mouseover
+none
+number
 onchange
-
+open
+password
+pause
+play
+playing
+print
+progress
+radio
+readystatechange
 reftest-wait
-
+reset
+right
+sans-serif
 screen
-print
+search
+select
+serif
+statechange
+storage
+submit
+suspend
+tel
+text
+time
+timeupdate
+toggle
+transitionend
+url
+waiting
+webglcontextcreationerror
+week
--- a/servo/components/script/dom/htmlmediaelement.rs
+++ b/servo/components/script/dom/htmlmediaelement.rs
@@ -14,34 +14,33 @@ use dom::bindings::codegen::Bindings::Me
 use dom::bindings::codegen::Bindings::MediaErrorBinding::MediaErrorMethods;
 use dom::bindings::inheritance::Castable;
 use dom::bindings::js::{MutNullableJS, Root};
 use dom::bindings::refcounted::Trusted;
 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;
 use dom::htmlvideoelement::HTMLVideoElement;
 use dom::mediaerror::MediaError;
 use dom::node::{window_from_node, document_from_node, Node, UnbindContext};
 use dom::virtualmethods::VirtualMethods;
 use dom_struct::dom_struct;
 use html5ever::{LocalName, Prefix};
 use ipc_channel::ipc;
 use ipc_channel::router::ROUTER;
 use microtask::{Microtask, MicrotaskRunnable};
 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};
 use task_source::TaskSource;
 use time::{self, Timespec, Duration};
 
 struct HTMLMediaElementContext {
     /// The element that initiated the request.
@@ -106,17 +105,22 @@ impl FetchResponseListener for HTMLMedia
             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 {
-            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);
         }
     }
 
     // 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();
 
@@ -124,35 +128,35 @@ impl FetchResponseListener for HTMLMedia
         //     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.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 {
             // 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.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();
         }
 
         let document = document_from_node(&*elem);
         document.finish_load(LoadType::Media(self.url.clone()));
     }
@@ -262,17 +266,17 @@ impl HTMLMediaElement {
         }
 
         // TODO step 3 (media controller)
     }
 
     // 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
     }
 
     fn queue_notify_about_playing(&self) {
         struct Task {
             elem: Trusted<HTMLMediaElement>,
         }
 
@@ -292,72 +296,68 @@ impl HTMLMediaElement {
     // https://html.spec.whatwg.org/multipage/#internal-pause-steps step 2.2
     fn queue_internal_pause_steps_task(&self) {
         struct Task {
             elem: Trusted<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
             }
         }
 
         let task = box Task {
             elem: Trusted::new(self),
         };
         let win = window_from_node(self);
         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();
         self.ready_state.set(ready_state);
 
         if self.network_state.get() == NETWORK_EMPTY {
             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
             // HAVE_CURRENT_DATA or greater
             (HAVE_METADATA, HAVE_CURRENT_DATA) |
             (HAVE_METADATA, HAVE_FUTURE_DATA) |
             (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,
+                    );
                 }
             }
 
             // previous ready state was HAVE_FUTURE_DATA or more, and the new ready
             // state is HAVE_CURRENT_DATA or less
             (HAVE_FUTURE_DATA, HAVE_CURRENT_DATA) |
             (HAVE_ENOUGH_DATA, HAVE_CURRENT_DATA) |
             (HAVE_FUTURE_DATA, HAVE_METADATA) |
@@ -374,49 +374,65 @@ impl HTMLMediaElement {
         // If the new ready state is HAVE_FUTURE_DATA or HAVE_ENOUGH_DATA,
         // then the relevant steps below must then be run also.
         match (old_ready_state, ready_state) {
             // previous ready state was HAVE_CURRENT_DATA or less, and the new ready
             // state is HAVE_FUTURE_DATA
             (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();
                 }
             }
 
             // 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();
                     }
                 }
 
                 //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
-                    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,
+                );
             }
 
             _ => (),
         }
 
         // TODO Step 2: media controller
     }
 
@@ -455,17 +471,22 @@ impl HTMLMediaElement {
             self.network_state.set(NETWORK_EMPTY);
             return;
         };
 
         // Step 7
         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 {
             ResourceSelectionMode::Object => {
                 // Step 1
                 *self.current_src.borrow_mut() = "".to_owned();
 
                 // Step 4
@@ -506,17 +527,22 @@ impl HTMLMediaElement {
         // Step 4
         if let Resource::Url(url) = resource {
             // 4.1
             if self.Preload() == "none" && !self.autoplaying.get() {
                 // 4.1.1
                 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)
 
                 // TODO 4.1.5-7 (state for load that initiates later)
                 return;
             }
 
             // 4.2
@@ -579,42 +605,49 @@ impl HTMLMediaElement {
         // TODO step 2 (forget resource tracks)
 
         // Step 3
         self.network_state.set(NETWORK_NO_SOURCE);
 
         // 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)
     }
 
     // https://html.spec.whatwg.org/multipage/#media-element-load-algorithm
     fn media_element_load_algorithm(&self) {
         self.first_data_load.set(true);
 
         // TODO Step 1 (abort resource selection algorithm instances)
 
         // Step 2
         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)
 
             // TODO 4.3 (detach media provider object)
             // TODO 4.4 (forget resource tracks)
 
             // 4.5
             if self.ready_state.get() != HAVE_NOTHING {
@@ -716,24 +749,31 @@ impl HTMLMediaElementMethods for HTMLMed
 
         // Step 7
         if self.Paused() {
             // 7.1
             self.paused.set(false);
 
             // 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();
             }
         }
         // Step 8
         else if state == HAVE_FUTURE_DATA || state == HAVE_ENOUGH_DATA {
             // TODO resolve pending play promises
         }
@@ -815,37 +855,16 @@ impl MicrotaskRunnable for MediaElementM
                 if !elem.upcast::<Node>().is_in_doc() {
                     elem.internal_pause_steps();
                 }
             },
         }
     }
 }
 
-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>,
 }
 
 impl DedicatedMediaSourceFailureTask {
     fn new(elem: &HTMLMediaElement) -> DedicatedMediaSourceFailureTask {
         DedicatedMediaSourceFailureTask {
             elem: Trusted::new(elem),