diff options
Diffstat (limited to 'components/script')
-rw-r--r-- | components/script/devtools.rs | 8 | ||||
-rw-r--r-- | components/script/dom/bindings/trace.rs | 7 | ||||
-rw-r--r-- | components/script/dom/document.rs | 75 | ||||
-rw-r--r-- | components/script/dom/webidls/Window.webidl | 7 | ||||
-rw-r--r-- | components/script/dom/window.rs | 25 | ||||
-rw-r--r-- | components/script/script_task.rs | 11 |
6 files changed, 128 insertions, 5 deletions
diff --git a/components/script/devtools.rs b/components/script/devtools.rs index cdc0537fa15..d67f57b4e4f 100644 --- a/components/script/devtools.rs +++ b/components/script/devtools.rs @@ -14,7 +14,7 @@ use dom::node::{Node, NodeHelpers}; use dom::window::{WindowHelpers, ScriptHelpers}; use dom::element::Element; use dom::document::DocumentHelpers; -use page::Page; +use page::{IterablePage, Page}; use msg::constellation_msg::PipelineId; use script_task::{get_page, ScriptTask}; @@ -147,3 +147,9 @@ pub fn handle_drop_timeline_markers(page: &Rc<Page>, } } } + +pub fn handle_request_animation_frame(page: &Rc<Page>, id: PipelineId, callback: Box<Fn(f64, )>) { + let page = page.find(id).expect("There is no such page"); + let doc = page.document().root(); + doc.r().request_animation_frame(callback); +} diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs index ab325ab804b..31f1a78f717 100644 --- a/components/script/dom/bindings/trace.rs +++ b/components/script/dom/bindings/trace.rs @@ -281,6 +281,13 @@ impl JSTraceable for Box<ScriptChan+Send> { } } +impl JSTraceable for Box<Fn(f64, )> { + #[inline] + fn trace(&self, _trc: *mut JSTracer) { + // Do nothing + } +} + impl<'a> JSTraceable for &'a str { #[inline] fn trace(&self, _: *mut JSTracer) { diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index f96dd134082..b5750f4a30c 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -11,6 +11,8 @@ use dom::bindings::codegen::Bindings::EventHandlerBinding::EventHandlerNonNull; use dom::bindings::codegen::Bindings::EventTargetBinding::EventTargetMethods; use dom::bindings::codegen::Bindings::NodeBinding::NodeMethods; use dom::bindings::codegen::Bindings::NodeFilterBinding::NodeFilter; +use dom::bindings::codegen::Bindings::PerformanceBinding::PerformanceMethods; +use dom::bindings::codegen::Bindings::WindowBinding::WindowMethods; use dom::bindings::codegen::InheritTypes::{DocumentDerived, EventCast, HTMLBodyElementCast}; use dom::bindings::codegen::InheritTypes::{HTMLElementCast, HTMLHeadElementCast, ElementCast}; use dom::bindings::codegen::InheritTypes::{DocumentTypeCast, HTMLHtmlElementCast, NodeCast}; @@ -63,6 +65,7 @@ use dom::window::{Window, WindowHelpers, ReflowReason}; use layout_interface::{HitTestResponse, MouseOverResponse}; use msg::compositor_msg::ScriptListener; +use msg::constellation_msg::AnimationState; use msg::constellation_msg::Msg as ConstellationMsg; use msg::constellation_msg::{ConstellationChan, FocusType, Key, KeyState, KeyModifiers, MozBrowserEvent}; use msg::constellation_msg::{SUPER, ALT, SHIFT, CONTROL}; @@ -82,11 +85,12 @@ use url::Url; use js::jsapi::JSRuntime; use num::ToPrimitive; +use std::iter::FromIterator; use std::borrow::ToOwned; use std::collections::HashMap; use std::collections::hash_map::Entry::{Occupied, Vacant}; use std::ascii::AsciiExt; -use std::cell::{Cell, Ref}; +use std::cell::{Cell, Ref, RefCell}; use std::default::Default; use std::sync::mpsc::channel; use time; @@ -129,6 +133,12 @@ pub struct Document { /// https://html.spec.whatwg.org/multipage/#concept-n-noscript /// True if scripting is enabled for all scripts in this document scripting_enabled: Cell<bool>, + /// https://html.spec.whatwg.org/multipage/#animation-frame-callback-identifier + /// Current identifier of animation frame callback + animation_frame_ident: Cell<i32>, + /// https://html.spec.whatwg.org/multipage/#list-of-animation-frame-callbacks + /// List of animation frame callbacks + animation_frame_list: RefCell<HashMap<i32, Box<Fn(f64)>>>, } impl DocumentDerived for EventTarget { @@ -238,6 +248,12 @@ pub trait DocumentHelpers<'a> { fn set_current_script(self, script: Option<JSRef<HTMLScriptElement>>); fn trigger_mozbrowser_event(self, event: MozBrowserEvent); + /// http://w3c.github.io/animation-timing/#dom-windowanimationtiming-requestanimationframe + fn request_animation_frame(self, callback: Box<Fn(f64, )>) -> i32; + /// http://w3c.github.io/animation-timing/#dom-windowanimationtiming-cancelanimationframe + fn cancel_animation_frame(self, ident: i32); + /// http://w3c.github.io/animation-timing/#dfn-invoke-callbacks-algorithm + fn invoke_animation_callbacks(self); } impl<'a> DocumentHelpers<'a> for JSRef<'a, Document> { @@ -793,6 +809,61 @@ impl<'a> DocumentHelpers<'a> for JSRef<'a, Document> { } } } + + /// http://w3c.github.io/animation-timing/#dom-windowanimationtiming-requestanimationframe + fn request_animation_frame(self, callback: Box<Fn(f64, )>) -> i32 { + let window = self.window.root(); + let window = window.r(); + let ident = self.animation_frame_ident.get() + 1; + + self.animation_frame_ident.set(ident); + self.animation_frame_list.borrow_mut().insert(ident, callback); + + // TODO: Should tick animation only when document is visible + let ConstellationChan(ref chan) = window.constellation_chan(); + let event = ConstellationMsg::ChangeRunningAnimationsState(window.pipeline(), + AnimationState::AnimationCallbacksPresent); + chan.send(event).unwrap(); + + ident + } + + /// http://w3c.github.io/animation-timing/#dom-windowanimationtiming-cancelanimationframe + fn cancel_animation_frame(self, ident: i32) { + self.animation_frame_list.borrow_mut().remove(&ident); + if self.animation_frame_list.borrow().len() == 0 { + let window = self.window.root(); + let window = window.r(); + let ConstellationChan(ref chan) = window.constellation_chan(); + let event = ConstellationMsg::ChangeRunningAnimationsState(window.pipeline(), + AnimationState::NoAnimationCallbacksPresent); + chan.send(event).unwrap(); + } + } + + /// http://w3c.github.io/animation-timing/#dfn-invoke-callbacks-algorithm + fn invoke_animation_callbacks(self) { + let animation_frame_list; + { + let mut list = self.animation_frame_list.borrow_mut(); + animation_frame_list = Vec::from_iter(list.drain()); + + let window = self.window.root(); + let window = window.r(); + let ConstellationChan(ref chan) = window.constellation_chan(); + let event = ConstellationMsg::ChangeRunningAnimationsState(window.pipeline(), + AnimationState::NoAnimationCallbacksPresent); + chan.send(event).unwrap(); + } + let window = self.window.root(); + let window = window.r(); + let performance = window.Performance().root(); + let performance = performance.r(); + + for (_, callback) in animation_frame_list { + callback(*performance.Now()); + } + } } pub enum MouseEventType { @@ -870,6 +941,8 @@ impl Document { focused: Default::default(), current_script: Default::default(), scripting_enabled: Cell::new(true), + animation_frame_ident: Cell::new(0), + animation_frame_list: RefCell::new(HashMap::new()), } } diff --git a/components/script/dom/webidls/Window.webidl b/components/script/dom/webidls/Window.webidl index 8999d9e561d..08caf90004e 100644 --- a/components/script/dom/webidls/Window.webidl +++ b/components/script/dom/webidls/Window.webidl @@ -141,3 +141,10 @@ interface WindowLocalStorage { readonly attribute Storage localStorage; }; Window implements WindowLocalStorage; + +// http://w3c.github.io/animation-timing/#Window-interface-extensions +partial interface Window { + long requestAnimationFrame(FrameRequestCallback callback); + void cancelAnimationFrame(long handle); +}; +callback FrameRequestCallback = void (DOMHighResTimeStamp time); diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs index 37d79625334..296c481a602 100644 --- a/components/script/dom/window.rs +++ b/components/script/dom/window.rs @@ -3,11 +3,11 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use dom::bindings::cell::DOMRefCell; +use dom::bindings::callback::ExceptionHandling; use dom::bindings::codegen::Bindings::EventHandlerBinding::{OnErrorEventHandlerNonNull, EventHandlerNonNull}; -use dom::bindings::codegen::Bindings::FunctionBinding::Function; -use dom::bindings::codegen::Bindings::WindowBinding; -use dom::bindings::codegen::Bindings::WindowBinding::WindowMethods; use dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods; +use dom::bindings::codegen::Bindings::FunctionBinding::Function; +use dom::bindings::codegen::Bindings::WindowBinding::{self, WindowMethods, FrameRequestCallback}; use dom::bindings::codegen::InheritTypes::{NodeCast, EventTargetCast}; use dom::bindings::global::global_object_for_js_object; use dom::bindings::error::{report_pending_exception, Fallible}; @@ -15,6 +15,7 @@ use dom::bindings::error::Error::InvalidCharacter; use dom::bindings::global::GlobalRef; use dom::bindings::js::{JS, JSRef, MutNullableHeap, OptionalRootable}; use dom::bindings::js::{Rootable, RootedReference, Temporary}; +use dom::bindings::num::Finite; use dom::bindings::utils::{GlobalStaticData, Reflectable, WindowProxyHandler}; use dom::browsercontext::BrowserContext; use dom::console::Console; @@ -464,6 +465,24 @@ impl<'a> WindowMethods for JSRef<'a, Window> { fn Atob(self, atob: DOMString) -> Fallible<DOMString> { base64_atob(atob) } + + /// http://w3c.github.io/animation-timing/#dom-windowanimationtiming-requestanimationframe + fn RequestAnimationFrame(self, callback: FrameRequestCallback) -> i32 { + let doc = self.Document().root(); + + let callback = move |now: f64| { + // TODO: @jdm The spec says that any exceptions should be suppressed; + callback.Call__(Finite::wrap(now), ExceptionHandling::Report).unwrap(); + }; + + doc.r().request_animation_frame(Box::new(callback)) + } + + /// http://w3c.github.io/animation-timing/#dom-windowanimationtiming-cancelanimationframe + fn CancelAnimationFrame(self, ident: i32) { + let doc = self.Document().root(); + doc.r().cancel_animation_frame(ident); + } } pub trait WindowHelpers { diff --git a/components/script/script_task.rs b/components/script/script_task.rs index 5efbb6a1deb..a2defc328eb 100644 --- a/components/script/script_task.rs +++ b/components/script/script_task.rs @@ -729,6 +729,8 @@ impl ScriptTask { ConstellationControlMsg::WebDriverCommand(pipeline_id, msg) => { self.handle_webdriver_msg(pipeline_id, msg); } + ConstellationControlMsg::TickAllAnimations(pipeline_id) => + self.handle_tick_all_animations(pipeline_id), } } @@ -778,6 +780,8 @@ impl ScriptTask { devtools::handle_set_timeline_markers(&page, self, marker_types, reply), DevtoolScriptControlMsg::DropTimelineMarkers(_pipeline_id, marker_types) => devtools::handle_drop_timeline_markers(&page, self, marker_types), + DevtoolScriptControlMsg::RequestAnimationFrame(pipeline_id, callback) => + devtools::handle_request_animation_frame(&page, pipeline_id, callback), } } @@ -1018,6 +1022,13 @@ impl ScriptTask { return false; } + /// Handles when layout task finishes all animation in one tick + fn handle_tick_all_animations(&self, id: PipelineId) { + let page = get_page(&self.root_page(), id); + let document = page.document().root(); + document.r().invoke_animation_callbacks(); + } + /// The entry point to document loading. Defines bindings, sets up the window and document /// objects, parses HTML and CSS, and kicks off initial layout. fn load(&self, response: LoadResponse, incomplete: InProgressLoad) { |