diff --git a/components/compositing/compositor.rs b/components/compositing/compositor.rs index c62f923d0a9..ddf9b069188 100644 --- a/components/compositing/compositor.rs +++ b/components/compositing/compositor.rs @@ -37,7 +37,7 @@ use script_traits::{AnimationState, AnimationTickType, ConstellationControlMsg}; use script_traits::{ConstellationMsg, LayoutControlMsg, MouseButton, MouseEventType}; use script_traits::{StackingContextScrollState, TouchpadPressurePhase, TouchEventType}; use script_traits::{TouchId, WindowSizeData}; -use script_traits::CompositorEvent::{MouseMoveEvent, MouseButtonEvent, TouchEvent}; +use script_traits::CompositorEvent::{self, MouseMoveEvent, MouseButtonEvent, TouchEvent, TouchpadPressureEvent}; use std::collections::{HashMap, HashSet}; use std::collections::hash_map::Entry::{Occupied, Vacant}; use std::fs::File; @@ -1511,12 +1511,27 @@ impl IOCompositor { } } + fn send_event_to_root_pipeline(&self, event: CompositorEvent) { + let root_pipeline_id = match self.get_root_pipeline_id() { + Some(root_pipeline_id) => root_pipeline_id, + None => return, + }; + + if let Some(pipeline) = self.pipeline(root_pipeline_id) { + let msg = ConstellationControlMsg::SendEvent(root_pipeline_id, event); + if let Err(e) = pipeline.script_chan.send(msg) { + warn!("Sending control event to script failed ({}).", e); + } + } + } + fn on_touch_down(&mut self, identifier: TouchId, point: TypedPoint2D) { self.touch_handler.on_touch_down(identifier, point); - if let Some(result) = self.find_topmost_layer_at_point(point / self.scene.scale) { - result.layer.send_event(self, TouchEvent(TouchEventType::Down, identifier, - result.point.to_untyped())); - } + let dppx = self.page_zoom * self.device_pixels_per_screen_px(); + let translated_point = (point / dppx).to_untyped(); + self.send_event_to_root_pipeline(TouchEvent(TouchEventType::Down, + identifier, + translated_point)); } fn on_touch_move(&mut self, identifier: TouchId, point: TypedPoint2D) { @@ -1539,20 +1554,22 @@ impl IOCompositor { self.composite_if_necessary_if_not_using_webrender(CompositingReason::Zoom); } TouchAction::DispatchEvent => { - if let Some(result) = self.find_topmost_layer_at_point(point / self.scene.scale) { - result.layer.send_event(self, TouchEvent(TouchEventType::Move, identifier, - result.point.to_untyped())); - } + let dppx = self.page_zoom * self.device_pixels_per_screen_px(); + let translated_point = (point / dppx).to_untyped(); + self.send_event_to_root_pipeline(TouchEvent(TouchEventType::Move, + identifier, + translated_point)); } _ => {} } } fn on_touch_up(&mut self, identifier: TouchId, point: TypedPoint2D) { - if let Some(result) = self.find_topmost_layer_at_point(point / self.scene.scale) { - result.layer.send_event(self, TouchEvent(TouchEventType::Up, identifier, - result.point.to_untyped())); - } + let dppx = self.page_zoom * self.device_pixels_per_screen_px(); + let translated_point = (point / dppx).to_untyped(); + self.send_event_to_root_pipeline(TouchEvent(TouchEventType::Up, + identifier, + translated_point)); if let TouchAction::Click = self.touch_handler.on_touch_up(identifier, point) { self.simulate_mouse_click(point); } @@ -1561,9 +1578,23 @@ impl IOCompositor { fn on_touch_cancel(&mut self, identifier: TouchId, point: TypedPoint2D) { // Send the event to script. self.touch_handler.on_touch_cancel(identifier, point); - if let Some(result) = self.find_topmost_layer_at_point(point / self.scene.scale) { - result.layer.send_event(self, TouchEvent(TouchEventType::Cancel, identifier, - result.point.to_untyped())); + let dppx = self.page_zoom * self.device_pixels_per_screen_px(); + let translated_point = (point / dppx).to_untyped(); + self.send_event_to_root_pipeline(TouchEvent(TouchEventType::Cancel, + identifier, + translated_point)); + } + + fn on_touchpad_pressure_event(&self, + point: TypedPoint2D, + pressure: f32, + phase: TouchpadPressurePhase) { + if let Some(true) = PREFS.get("dom.forcetouch.enabled").as_boolean() { + let dppx = self.page_zoom * self.device_pixels_per_screen_px(); + let translated_point = (point / dppx).to_untyped(); + self.send_event_to_root_pipeline(TouchpadPressureEvent(translated_point, + pressure, + phase)); } } @@ -1877,16 +1908,6 @@ impl IOCompositor { } } - fn on_touchpad_pressure_event(&self, cursor: TypedPoint2D, pressure: f32, - phase: TouchpadPressurePhase) { - if let Some(true) = PREFS.get("dom.forcetouch.enabled").as_boolean() { - match self.find_topmost_layer_at_point(cursor / self.scene.scale) { - Some(result) => result.layer.send_touchpad_pressure_event(self, result.point, pressure, phase), - None => {}, - } - } - } - fn on_key_event(&self, ch: Option, key: Key, state: KeyState, modifiers: KeyModifiers) { let msg = ConstellationMsg::KeyEvent(ch, key, state, modifiers); if let Err(e) = self.constellation_chan.send(msg) { diff --git a/components/constellation/constellation.rs b/components/constellation/constellation.rs index fa10a76bbdc..0ebde0b4a57 100644 --- a/components/constellation/constellation.rs +++ b/components/constellation/constellation.rs @@ -874,22 +874,10 @@ impl Constellation debug!("constellation got focus message"); self.handle_focus_msg(pipeline_id); } - FromScriptMsg::ForwardMouseButtonEvent(pipeline_id, event_type, button, point) => { - let event = CompositorEvent::MouseButtonEvent(event_type, button, point); + FromScriptMsg::ForwardEvent(pipeline_id, event) => { let msg = ConstellationControlMsg::SendEvent(pipeline_id, event); let result = match self.pipelines.get(&pipeline_id) { - None => { debug!("Pipeline {:?} got mouse button event after closure.", pipeline_id); return; } - Some(pipeline) => pipeline.script_chan.send(msg), - }; - if let Err(e) = result { - self.handle_send_error(pipeline_id, e); - } - } - FromScriptMsg::ForwardMouseMoveEvent(pipeline_id, point) => { - let event = CompositorEvent::MouseMoveEvent(Some(point)); - let msg = ConstellationControlMsg::SendEvent(pipeline_id, event); - let result = match self.pipelines.get(&pipeline_id) { - None => { debug!("Pipeline {:?} got mouse move event after closure.", pipeline_id); return; } + None => { debug!("Pipeline {:?} got event after closure.", pipeline_id); return; } Some(pipeline) => pipeline.script_chan.send(msg), }; if let Err(e) = result { diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index bf2088bc15c..2fdd36667cf 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -106,7 +106,7 @@ use origin::Origin; use parse::{MutNullableParserField, ParserRef, ParserRoot}; use script_layout_interface::message::{Msg, ReflowQueryType}; use script_thread::{MainThreadScriptMsg, Runnable}; -use script_traits::{AnimationState, MouseButton, MouseEventType, MozBrowserEvent}; +use script_traits::{AnimationState, CompositorEvent, MouseButton, MouseEventType, MozBrowserEvent}; use script_traits::{ScriptMsg as ConstellationMsg, TouchpadPressurePhase}; use script_traits::{TouchEventType, TouchId}; use script_traits::UntrustedNodeAddress; @@ -133,6 +133,11 @@ use url::Url; use url::percent_encoding::percent_decode; use util::prefs::PREFS; +pub enum TouchEventResult { + Processed(bool), + Forwarded, +} + #[derive(JSTraceable, PartialEq, HeapSizeOf)] pub enum IsHTMLDocument { HTMLDocument, @@ -723,9 +728,8 @@ impl Document { let child_origin = Point2D::new(rect.X() as f32, rect.Y() as f32); let child_point = client_point - child_origin; - let event = ConstellationMsg::ForwardMouseButtonEvent(pipeline_id, - mouse_event_type, - button, child_point); + let event = CompositorEvent::MouseButtonEvent(mouse_event_type, button, child_point); + let event = ConstellationMsg::ForwardEvent(pipeline_id, event); self.window.upcast::().constellation_chan().send(event).unwrap(); } return; @@ -853,14 +857,6 @@ impl Document { client_point: Point2D, pressure: f32, phase_now: TouchpadPressurePhase) { - let phase_before = self.touchpad_pressure_phase.get(); - self.touchpad_pressure_phase.set(phase_now); - - if phase_before == TouchpadPressurePhase::BeforeClick && - phase_now == TouchpadPressurePhase::BeforeClick { - return; - } - let node = match self.window.hit_test_query(client_point, false) { Some(node_address) => node::from_untrusted_node_address(js_runtime, node_address), None => return @@ -877,6 +873,30 @@ impl Document { }, }; + // If the target is an iframe, forward the event to the child document. + if let Some(iframe) = el.downcast::() { + if let Some(pipeline_id) = iframe.pipeline_id() { + let rect = iframe.upcast::().GetBoundingClientRect(); + let child_origin = Point2D::new(rect.X() as f32, rect.Y() as f32); + let child_point = client_point - child_origin; + + let event = CompositorEvent::TouchpadPressureEvent(child_point, + pressure, + phase_now); + let event = ConstellationMsg::ForwardEvent(pipeline_id, event); + self.window.upcast::().constellation_chan().send(event).unwrap(); + } + return; + } + + let phase_before = self.touchpad_pressure_phase.get(); + self.touchpad_pressure_phase.set(phase_now); + + if phase_before == TouchpadPressurePhase::BeforeClick && + phase_now == TouchpadPressurePhase::BeforeClick { + return; + } + let node = el.upcast::(); let target = node.upcast(); @@ -963,7 +983,8 @@ impl Document { let child_origin = Point2D::new(rect.X() as f32, rect.Y() as f32); let child_point = client_point - child_origin; - let event = ConstellationMsg::ForwardMouseMoveEvent(pipeline_id, child_point); + let event = CompositorEvent::MouseMoveEvent(Some(child_point)); + let event = ConstellationMsg::ForwardEvent(pipeline_id, event); self.window.upcast::().constellation_chan().send(event).unwrap(); } return; @@ -1032,9 +1053,11 @@ impl Document { pub fn handle_touch_event(&self, js_runtime: *mut JSRuntime, event_type: TouchEventType, - TouchId(identifier): TouchId, + touch_id: TouchId, point: Point2D) - -> bool { + -> TouchEventResult { + let TouchId(identifier) = touch_id; + let event_name = match event_type { TouchEventType::Down => "touchstart", TouchEventType::Move => "touchmove", @@ -1044,7 +1067,7 @@ impl Document { let node = match self.window.hit_test_query(point, false) { Some(node_address) => node::from_untrusted_node_address(js_runtime, node_address), - None => return false, + None => return TouchEventResult::Processed(false), }; let el = match node.downcast::() { Some(el) => Root::from_ref(el), @@ -1052,10 +1075,25 @@ impl Document { let parent = node.GetParentNode(); match parent.and_then(Root::downcast::) { Some(parent) => parent, - None => return false, + None => return TouchEventResult::Processed(false), } }, }; + + // If the target is an iframe, forward the event to the child document. + if let Some(iframe) = el.downcast::() { + if let Some(pipeline_id) = iframe.pipeline_id() { + let rect = iframe.upcast::().GetBoundingClientRect(); + let child_origin = Point2D::new(rect.X() as f32, rect.Y() as f32); + let child_point = point - child_origin; + + let event = CompositorEvent::TouchEvent(event_type, touch_id, child_point); + let event = ConstellationMsg::ForwardEvent(pipeline_id, event); + self.window.upcast::().constellation_chan().send(event).unwrap(); + } + return TouchEventResult::Forwarded; + } + let target = Root::upcast::(el); let window = &*self.window; @@ -1132,8 +1170,8 @@ impl Document { ReflowReason::MouseEvent); match result { - EventStatus::Canceled => false, - EventStatus::NotCanceled => true + EventStatus::Canceled => TouchEventResult::Processed(false), + EventStatus::NotCanceled => TouchEventResult::Processed(true), } } diff --git a/components/script/script_thread.rs b/components/script/script_thread.rs index 85f0cc2462e..6e18216ddc4 100644 --- a/components/script/script_thread.rs +++ b/components/script/script_thread.rs @@ -36,7 +36,7 @@ use dom::bindings::str::DOMString; use dom::bindings::trace::JSTraceable; use dom::bindings::utils::WRAP_CALLBACKS; use dom::browsingcontext::BrowsingContext; -use dom::document::{Document, DocumentProgressHandler, DocumentSource, FocusType, IsHTMLDocument}; +use dom::document::{Document, DocumentProgressHandler, DocumentSource, FocusType, IsHTMLDocument, TouchEventResult}; use dom::element::Element; use dom::event::{Event, EventBubbles, EventCancelable}; use dom::globalscope::GlobalScope; @@ -1934,9 +1934,9 @@ impl ScriptThread { } } TouchEvent(event_type, identifier, point) => { - let handled = self.handle_touch_event(pipeline_id, event_type, identifier, point); - match event_type { - TouchEventType::Down => { + let touch_result = self.handle_touch_event(pipeline_id, event_type, identifier, point); + match (event_type, touch_result) { + (TouchEventType::Down, TouchEventResult::Processed(handled)) => { let result = if handled { // TODO: Wait to see if preventDefault is called on the first touchmove event. EventResult::DefaultAllowed @@ -1987,10 +1987,13 @@ impl ScriptThread { event_type: TouchEventType, identifier: TouchId, point: Point2D) - -> bool { + -> TouchEventResult { let document = match self.root_browsing_context().find(pipeline_id) { Some(browsing_context) => browsing_context.active_document(), - None => { warn!("Message sent to closed pipeline {}.", pipeline_id); return true }, + None => { + warn!("Message sent to closed pipeline {}.", pipeline_id); + return TouchEventResult::Processed(true) + }, }; document.handle_touch_event(self.js_runtime.rt(), event_type, identifier, point) } diff --git a/components/script_traits/script_msg.rs b/components/script_traits/script_msg.rs index 52f5fdd1188..8b3283800df 100644 --- a/components/script_traits/script_msg.rs +++ b/components/script_traits/script_msg.rs @@ -3,10 +3,9 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use AnimationState; +use CompositorEvent; use DocumentState; use IFrameLoadInfo; -use MouseButton; -use MouseEventType; use MozBrowserEvent; use WorkerGlobalScopeInit; use WorkerScriptLoadOrigin; @@ -72,10 +71,8 @@ pub enum ScriptMsg { IpcSender, GLLimits), String>>), /// Notifies the constellation that this frame has received focus. Focus(PipelineId), - /// Re-send a mouse button event that was sent to the parent window. - ForwardMouseButtonEvent(PipelineId, MouseEventType, MouseButton, Point2D), - /// Re-send a mouse move event that was sent to the parent window. - ForwardMouseMoveEvent(PipelineId, Point2D), + /// Forward an event that was sent to the parent window. + ForwardEvent(PipelineId, CompositorEvent), /// Requests that the constellation retrieve the current contents of the clipboard GetClipboardContents(IpcSender), /// tag finished parsing