diff options
Diffstat (limited to 'components/script/dom/document.rs')
-rw-r--r-- | components/script/dom/document.rs | 136 |
1 files changed, 116 insertions, 20 deletions
diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index 692c597d7af..9c3b0b00511 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}; @@ -81,14 +84,15 @@ use string_cache::{Atom, QualName}; 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 std::num::ToPrimitive; use time; #[derive(PartialEq)] @@ -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 { @@ -220,8 +230,6 @@ pub trait DocumentHelpers<'a> { fn title_changed(self); fn send_title_to_compositor(self); fn dirty_all_nodes(self); - fn handle_click_event(self, js_runtime: *mut JSRuntime, - button: MouseButton, point: Point2D<f32>); fn dispatch_key_event(self, key: Key, state: KeyState, modifiers: KeyModifiers, compositor: &mut Box<ScriptListener+'static>); fn node_from_nodes_and_strings(self, nodes: Vec<NodeOrString>) @@ -229,6 +237,9 @@ pub trait DocumentHelpers<'a> { fn get_body_attribute(self, local_name: &Atom) -> DOMString; fn set_body_attribute(self, local_name: &Atom, value: DOMString); + fn handle_mouse_event(self, js_runtime: *mut JSRuntime, + button: MouseButton, point: Point2D<f32>, + mouse_event_type: MouseEventType); /// Handles a mouse-move event coming from the compositor. fn handle_mouse_move_event(self, js_runtime: *mut JSRuntime, @@ -237,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> { @@ -511,9 +528,15 @@ impl<'a> DocumentHelpers<'a> for JSRef<'a, Document> { } } - fn handle_click_event(self, js_runtime: *mut JSRuntime, - _button: MouseButton, point: Point2D<f32>) { - debug!("ClickEvent: clicked at {:?}", point); + fn handle_mouse_event(self, js_runtime: *mut JSRuntime, + _button: MouseButton, point: Point2D<f32>, + mouse_event_type: MouseEventType) { + let mouse_event_type_string = match mouse_event_type { + MouseEventType::Click => "click".to_owned(), + MouseEventType::MouseUp => "mouseup".to_owned(), + MouseEventType::MouseDown => "mousedown".to_owned(), + }; + debug!("{}: at {:?}", mouse_event_type_string, point); let node = match self.hit_test(&point) { Some(node_address) => { debug!("node address is {:?}", node_address.0); @@ -525,7 +548,7 @@ impl<'a> DocumentHelpers<'a> for JSRef<'a, Document> { let el = match ElementCast::to_ref(node.r()) { Some(el) => Temporary::from_rooted(el), None => { - let parent = node.r().parent_node(); + let parent = node.r().GetParentNode(); match parent.and_then(ElementCast::to_temporary) { Some(parent) => parent, None => return, @@ -534,13 +557,15 @@ impl<'a> DocumentHelpers<'a> for JSRef<'a, Document> { }.root(); let node: JSRef<Node> = NodeCast::from_ref(el.r()); - debug!("clicked on {:?}", node.debug_str()); + debug!("{} on {:?}", mouse_event_type_string, node.debug_str()); // Prevent click event if form control element is disabled. - if node.click_event_filter_by_disabled_state() { - return; - } + if let MouseEventType::Click = mouse_event_type { + if node.click_event_filter_by_disabled_state() { + return; + } - self.begin_focus_transaction(); + self.begin_focus_transaction(); + } let window = self.window.root(); @@ -548,7 +573,7 @@ impl<'a> DocumentHelpers<'a> for JSRef<'a, Document> { let x = point.x as i32; let y = point.y as i32; let event = MouseEvent::new(window.r(), - "click".to_owned(), + mouse_event_type_string, EventBubbles::Bubbles, EventCancelable::Cancelable, Some(window.r()), @@ -562,9 +587,17 @@ impl<'a> DocumentHelpers<'a> for JSRef<'a, Document> { // https://dvcs.w3.org/hg/dom3events/raw-file/tip/html/DOM3-Events.html#trusted-events event.set_trusted(true); // https://html.spec.whatwg.org/multipage/#run-authentic-click-activation-steps - el.r().authentic_click_activation(event); + match mouse_event_type { + MouseEventType::Click => el.r().authentic_click_activation(event), + _ => { + let target: JSRef<EventTarget> = EventTargetCast::from_ref(node); + event.fire(target); + }, + } - self.commit_focus_transaction(FocusType::Element); + if let MouseEventType::Click = mouse_event_type { + self.commit_focus_transaction(FocusType::Element); + } window.r().reflow(ReflowGoal::ForDisplay, ReflowQueryType::NoQuery, ReflowReason::MouseEvent); } @@ -668,8 +701,8 @@ impl<'a> DocumentHelpers<'a> for JSRef<'a, Document> { let props = KeyboardEvent::key_properties(key, modifiers); let keyevent = KeyboardEvent::new(window.r(), ev_type, true, true, - Some(window.r()), 0, - props.key.to_owned(), props.code.to_owned(), + Some(window.r()), 0, Some(key), + props.key_string.to_owned(), props.code.to_owned(), props.location, is_repeating, is_composing, ctrl, alt, shift, meta, None, props.key_code).root(); @@ -681,8 +714,8 @@ impl<'a> DocumentHelpers<'a> for JSRef<'a, Document> { if state != KeyState::Released && props.is_printable() && !prevented { // https://dvcs.w3.org/hg/dom3events/raw-file/tip/html/DOM3-Events.html#keypress-event-order let event = KeyboardEvent::new(window.r(), "keypress".to_owned(), - true, true, Some(window.r()), - 0, props.key.to_owned(), props.code.to_owned(), + true, true, Some(window.r()), 0, Some(key), + props.key_string.to_owned(), props.code.to_owned(), props.location, is_repeating, is_composing, ctrl, alt, shift, meta, props.char_code, 0).root(); @@ -776,6 +809,67 @@ 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 { + Click, + MouseDown, + MouseUp, } #[derive(PartialEq)] @@ -847,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()), } } |