diff --git a/Cargo.lock b/Cargo.lock index a54fd197530..f937897c3ae 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1853,6 +1853,7 @@ dependencies = [ "base", "cfg-if", "crossbeam-channel", + "euclid", "http 1.2.0", "hyper_serde", "ipc-channel", diff --git a/components/compositing/compositor.rs b/components/compositing/compositor.rs index ecf3a95495d..54527b72de6 100644 --- a/components/compositing/compositor.rs +++ b/components/compositing/compositor.rs @@ -21,7 +21,7 @@ use compositing_traits::{ use crossbeam_channel::Sender; use embedder_traits::{ Cursor, InputEvent, MouseButton, MouseButtonAction, MouseButtonEvent, MouseMoveEvent, - TouchEvent, TouchEventAction, TouchId, + TouchAction, TouchEvent, TouchEventType, TouchId, }; use euclid::{Point2D, Rect, Scale, Size2D, Transform3D, Vector2D}; use fnv::{FnvHashMap, FnvHashSet}; @@ -33,8 +33,8 @@ use pixels::{CorsStatus, Image, PixelFormat}; use profile_traits::time::{self as profile_time, ProfilerCategory}; use profile_traits::time_profile; use script_traits::{ - AnimationState, AnimationTickType, ScriptThreadMessage, ScrollState, WindowSizeData, - WindowSizeType, + AnimationState, AnimationTickType, EventResult, ScriptThreadMessage, ScrollState, + WindowSizeData, WindowSizeType, }; use servo_geometry::DeviceIndependentPixel; use style_traits::{CSSPixel, PinchZoomFactor}; @@ -56,7 +56,7 @@ use webrender_traits::{ CompositorHitTestResult, CrossProcessCompositorMessage, ImageUpdate, UntrustedNodeAddress, }; -use crate::touch::{TouchAction, TouchHandler}; +use crate::touch::TouchHandler; use crate::webview::{UnknownWebView, WebView, WebViewAlreadyExists, WebViewManager}; use crate::windowing::{self, EmbedderCoordinates, WebRenderDebugOption, WindowMethods}; use crate::InitialCompositorState; @@ -501,7 +501,7 @@ impl IOCompositor { }, CompositorMsg::TouchEventProcessed(result) => { - self.touch_handler.on_event_processed(result); + self.on_touch_event_processed(result); }, CompositorMsg::CreatePng(page_rect, reply) => { @@ -1338,13 +1338,28 @@ impl IOCompositor { InputEvent::MouseButton(event) => { match event.action { MouseButtonAction::Click => {}, - MouseButtonAction::Down => self.on_touch_down(TouchId(0), event.point), - MouseButtonAction::Up => self.on_touch_up(TouchId(0), event.point), + MouseButtonAction::Down => self.on_touch_down(TouchEvent { + event_type: TouchEventType::Down, + id: TouchId(0), + point: event.point, + action: TouchAction::NoAction, + }), + MouseButtonAction::Up => self.on_touch_up(TouchEvent { + event_type: TouchEventType::Up, + id: TouchId(0), + point: event.point, + action: TouchAction::NoAction, + }), } return; }, InputEvent::MouseMove(event) => { - self.on_touch_move(TouchId(0), event.point); + self.on_touch_move(TouchEvent { + event_type: TouchEventType::Move, + id: TouchId(0), + point: event.point, + action: TouchAction::NoAction, + }); return; }, _ => {}, @@ -1422,75 +1437,113 @@ impl IOCompositor { return; } - match event.action { - TouchEventAction::Down => self.on_touch_down(event.id, event.point), - TouchEventAction::Move => self.on_touch_move(event.id, event.point), - TouchEventAction::Up => self.on_touch_up(event.id, event.point), - TouchEventAction::Cancel => self.on_touch_cancel(event.id, event.point), + match event.event_type { + TouchEventType::Down => self.on_touch_down(event), + TouchEventType::Move => self.on_touch_move(event), + TouchEventType::Up => self.on_touch_up(event), + TouchEventType::Cancel => self.on_touch_cancel(event), } } - fn on_touch_down(&mut self, id: TouchId, point: DevicePoint) { - self.touch_handler.on_touch_down(id, point); - self.send_touch_event(TouchEvent { - action: TouchEventAction::Down, - id, - point, - }) + fn on_touch_down(&mut self, event: TouchEvent) { + self.touch_handler.on_touch_down(event.id, event.point); + self.send_touch_event(event); } - fn on_touch_move(&mut self, id: TouchId, point: DevicePoint) { - match self.touch_handler.on_touch_move(id, point) { - TouchAction::Scroll(delta) => self.on_scroll_window_event( - ScrollLocation::Delta(LayoutVector2D::from_untyped(delta.to_untyped())), - point.cast(), - ), - TouchAction::Zoom(magnification, scroll_delta) => { - let cursor = Point2D::new(-1, -1); // Make sure this hits the base layer. + fn on_touch_move(&mut self, mut event: TouchEvent) { + let action: TouchAction = self.touch_handler.on_touch_move(event.id, event.point); + if TouchAction::NoAction != action { + if !self.touch_handler.prevent_move { + match action { + TouchAction::Scroll(delta, point) => self.on_scroll_window_event( + ScrollLocation::Delta(LayoutVector2D::from_untyped(delta.to_untyped())), + point.cast(), + ), + TouchAction::Zoom(magnification, scroll_delta) => { + let cursor = Point2D::new(-1, -1); // Make sure this hits the base layer. - // The order of these events doesn't matter, because zoom is handled by - // a root display list and the scroll event here is handled by the scroll - // applied to the content display list. - self.pending_scroll_zoom_events - .push(ScrollZoomEvent::PinchZoom(magnification)); - self.pending_scroll_zoom_events - .push(ScrollZoomEvent::Scroll(ScrollEvent { - scroll_location: ScrollLocation::Delta(LayoutVector2D::from_untyped( - scroll_delta.to_untyped(), - )), - cursor, - event_count: 1, - })); - }, - TouchAction::DispatchEvent => self.send_touch_event(TouchEvent { - action: TouchEventAction::Move, - id, - point, - }), - _ => {}, + // The order of these events doesn't matter, because zoom is handled by + // a root display list and the scroll event here is handled by the scroll + // applied to the content display list. + self.pending_scroll_zoom_events + .push(ScrollZoomEvent::PinchZoom(magnification)); + self.pending_scroll_zoom_events + .push(ScrollZoomEvent::Scroll(ScrollEvent { + scroll_location: ScrollLocation::Delta( + LayoutVector2D::from_untyped(scroll_delta.to_untyped()), + ), + cursor, + event_count: 1, + })); + }, + _ => {}, + } + } else { + event.action = action; + } + self.send_touch_event(event); } } - fn on_touch_up(&mut self, id: TouchId, point: DevicePoint) { - self.send_touch_event(TouchEvent { - action: TouchEventAction::Up, - id, - point, - }); - - if let TouchAction::Click = self.touch_handler.on_touch_up(id, point) { - self.simulate_mouse_click(point); - } + fn on_touch_up(&mut self, mut event: TouchEvent) { + let action = self.touch_handler.on_touch_up(event.id, event.point); + event.action = action; + self.send_touch_event(event); } - fn on_touch_cancel(&mut self, id: TouchId, point: DevicePoint) { + fn on_touch_cancel(&mut self, event: TouchEvent) { // Send the event to script. - self.touch_handler.on_touch_cancel(id, point); - self.send_touch_event(TouchEvent { - action: TouchEventAction::Cancel, - id, - point, - }) + self.touch_handler.on_touch_cancel(event.id, event.point); + self.send_touch_event(event) + } + + fn on_touch_event_processed(&mut self, result: EventResult) { + match result { + EventResult::DefaultPrevented(event_type) => { + match event_type { + TouchEventType::Down | TouchEventType::Move => { + self.touch_handler.prevent_move = true; + }, + _ => {}, + } + self.touch_handler.prevent_click = true; + }, + EventResult::DefaultAllowed(action) => { + self.touch_handler.prevent_move = false; + match action { + TouchAction::Click(point) => { + if !self.touch_handler.prevent_click { + self.simulate_mouse_click(point); + } + }, + TouchAction::Flinging(velocity, point) => { + self.touch_handler.on_fling(velocity, point); + }, + TouchAction::Scroll(delta, point) => self.on_scroll_window_event( + ScrollLocation::Delta(LayoutVector2D::from_untyped(delta.to_untyped())), + point.cast(), + ), + TouchAction::Zoom(magnification, scroll_delta) => { + let cursor = Point2D::new(-1, -1); // Make sure this hits the base layer. + + // The order of these events doesn't matter, because zoom is handled by + // a root display list and the scroll event here is handled by the scroll + // applied to the content display list. + self.pending_scroll_zoom_events + .push(ScrollZoomEvent::PinchZoom(magnification)); + self.pending_scroll_zoom_events + .push(ScrollZoomEvent::Scroll(ScrollEvent { + scroll_location: ScrollLocation::Delta( + LayoutVector2D::from_untyped(scroll_delta.to_untyped()), + ), + cursor, + event_count: 1, + })); + }, + _ => {}, + } + }, + } } /// @@ -1518,18 +1571,18 @@ impl IOCompositor { &mut self, scroll_location: ScrollLocation, cursor: DeviceIntPoint, - action: TouchEventAction, + event_type: TouchEventType, ) { if self.shutdown_state != ShutdownState::NotShuttingDown { return; } - match action { - TouchEventAction::Move => self.on_scroll_window_event(scroll_location, cursor), - TouchEventAction::Up | TouchEventAction::Cancel => { + match event_type { + TouchEventType::Move => self.on_scroll_window_event(scroll_location, cursor), + TouchEventType::Up | TouchEventType::Cancel => { self.on_scroll_window_event(scroll_location, cursor); }, - TouchEventAction::Down => { + TouchEventType::Down => { self.on_scroll_window_event(scroll_location, cursor); }, } diff --git a/components/compositing/touch.rs b/components/compositing/touch.rs index b12384e1fd6..ef87323a0b0 100644 --- a/components/compositing/touch.rs +++ b/components/compositing/touch.rs @@ -2,10 +2,9 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -use embedder_traits::TouchId; +use embedder_traits::{TouchAction, TouchId}; use euclid::{Point2D, Scale, Vector2D}; use log::{debug, warn}; -use script_traits::EventResult; use webrender_api::units::{DeviceIntPoint, DevicePixel, LayoutVector2D}; use self::TouchState::*; @@ -25,6 +24,8 @@ const FLING_MAX_SCREEN_PX: f32 = 4000.0; pub struct TouchHandler { pub state: TouchState, pub active_touch_points: Vec, + pub prevent_move: bool, + pub prevent_click: bool, } #[derive(Clone, Copy, Debug)] @@ -44,11 +45,6 @@ impl TouchPoint { pub enum TouchState { /// Not tracking any touch point Nothing, - /// A touchstart event was dispatched to the page, but the response wasn't received yet. - /// Contains the initial touch point. - WaitingForScript, - /// Script is consuming the current touch sequence; don't perform default actions. - DefaultPrevented, /// A single touch point is active and may perform click or pan default actions. /// Contains the initial touch location. Touching, @@ -67,21 +63,6 @@ pub enum TouchState { MultiTouch, } -/// The action to take in response to a touch event -#[derive(Clone, Copy, Debug)] -pub enum TouchAction { - /// Simulate a mouse click. - Click, - /// Scroll by the provided offset. - Scroll(Vector2D), - /// Zoom by a magnification factor and scroll by the provided offset. - Zoom(f32, Vector2D), - /// Send a JavaScript event to content. - DispatchEvent, - /// Don't do anything. - NoAction, -} - pub(crate) struct FlingAction { pub delta: LayoutVector2D, pub cursor: DeviceIntPoint, @@ -92,20 +73,21 @@ impl TouchHandler { TouchHandler { state: Nothing, active_touch_points: Vec::new(), + prevent_move: true, + prevent_click: false, } } pub fn on_touch_down(&mut self, id: TouchId, point: Point2D) { let point = TouchPoint::new(id, point); self.active_touch_points.push(point); - - self.state = match self.state { - Nothing => WaitingForScript, - Flinging { .. } => Touching, - Touching | Panning { .. } => Pinching, - WaitingForScript => WaitingForScript, - DefaultPrevented => DefaultPrevented, - Pinching | MultiTouch => MultiTouch, + self.state = Touching; + self.prevent_click = match self.touch_count() { + 1 => { + self.prevent_move = true; + false + }, + _ => true, }; } @@ -140,51 +122,51 @@ impl TouchHandler { }, }; let old_point = self.active_touch_points[idx].point; + let delta = point - old_point; - let action = match self.state { - Touching => { - let delta = point - old_point; - - if delta.x.abs() > TOUCH_PAN_MIN_SCREEN_PX || + let action = match self.touch_count() { + 1 => { + if let Panning { ref mut velocity } = self.state { + // TODO: Probably we should track 1-3 more points and use a smarter algorithm + *velocity += delta; + *velocity /= 2.0; + TouchAction::Scroll(delta, point) + } else if delta.x.abs() > TOUCH_PAN_MIN_SCREEN_PX || delta.y.abs() > TOUCH_PAN_MIN_SCREEN_PX { self.state = Panning { velocity: Vector2D::new(delta.x, delta.y), }; - TouchAction::Scroll(delta) + self.prevent_click = true; + TouchAction::Scroll(delta, point) } else { TouchAction::NoAction } }, - Panning { ref mut velocity } => { - let delta = point - old_point; - // TODO: Probably we should track 1-3 more points and use a smarter algorithm - *velocity += delta; - *velocity /= 2.0; - TouchAction::Scroll(delta) + 2 => { + if self.state == Pinching || + delta.x.abs() > TOUCH_PAN_MIN_SCREEN_PX || + delta.y.abs() > TOUCH_PAN_MIN_SCREEN_PX + { + self.state = Pinching; + let (d0, c0) = self.pinch_distance_and_center(); + self.active_touch_points[idx].point = point; + let (d1, c1) = self.pinch_distance_and_center(); + let magnification = d1 / d0; + let scroll_delta = c1 - c0 * Scale::new(magnification); + TouchAction::Zoom(magnification, scroll_delta) + } else { + TouchAction::NoAction + } }, - Flinging { .. } => { - unreachable!("Touch Move event received without preceding down.") + _ => { + self.state = MultiTouch; + TouchAction::NoAction }, - DefaultPrevented => TouchAction::DispatchEvent, - Pinching => { - let (d0, c0) = self.pinch_distance_and_center(); - self.active_touch_points[idx].point = point; - let (d1, c1) = self.pinch_distance_and_center(); - - let magnification = d1 / d0; - let scroll_delta = c1 - c0 * Scale::new(magnification); - - TouchAction::Zoom(magnification, scroll_delta) - }, - WaitingForScript => TouchAction::NoAction, - MultiTouch => TouchAction::NoAction, - Nothing => unreachable!(), }; - // If we're still waiting to see whether this is a click or pan, remember the original - // location. Otherwise, update the touch point with the latest location. - if self.state != Touching && self.state != WaitingForScript { + // update the touch point with the latest location. + if self.state != Touching { self.active_touch_points[idx].point = point; } action @@ -198,56 +180,37 @@ impl TouchHandler { None }, }; - match self.state { - Touching => { - // FIXME: If the duration exceeds some threshold, send a contextmenu event instead. - // FIXME: Don't send a click if preventDefault is called on the touchend event. - self.state = Nothing; - TouchAction::Click - }, - Nothing => { - self.state = Nothing; - TouchAction::NoAction - }, - Panning { velocity } if velocity.length().abs() >= FLING_MIN_SCREEN_PX => { - // TODO: point != old. Not sure which one is better to take as cursor for flinging. - debug!( - "Transitioning to Fling. Cursor is {point:?}. Old cursor was {old:?}. \ - Raw velocity is {velocity:?}." - ); - debug_assert!((point.x as i64) < (i32::MAX as i64)); - debug_assert!((point.y as i64) < (i32::MAX as i64)); - let cursor = DeviceIntPoint::new(point.x as i32, point.y as i32); - // Multiplying the initial velocity gives the fling a much more snappy feel - // and serves well as a poor-mans acceleration algorithm. - let velocity = (velocity * 2.0).with_max_length(FLING_MAX_SCREEN_PX); - self.state = Flinging { velocity, cursor }; - TouchAction::NoAction - }, - Panning { .. } => { - self.state = Nothing; - TouchAction::NoAction - }, - Pinching => { - self.state = Panning { - velocity: Vector2D::new(0.0, 0.0), - }; - TouchAction::NoAction - }, - Flinging { .. } => { - unreachable!("On touchup received, but already flinging.") - }, - WaitingForScript => { - if self.active_touch_points.is_empty() { + match self.touch_count() { + 0 => { + if let Panning { velocity } = self.state { + if velocity.length().abs() >= FLING_MIN_SCREEN_PX { + // TODO: point != old. Not sure which one is better to take as cursor for flinging. + debug!( + "Transitioning to Fling. Cursor is {point:?}. Old cursor was {old:?}. \ + Raw velocity is {velocity:?}." + ); + debug_assert!((point.x as i64) < (i32::MAX as i64)); + debug_assert!((point.y as i64) < (i32::MAX as i64)); + let cursor = DeviceIntPoint::new(point.x as i32, point.y as i32); + // Multiplying the initial velocity gives the fling a much more snappy feel + // and serves well as a poor-mans acceleration algorithm. + let velocity = (velocity * 2.0).with_max_length(FLING_MAX_SCREEN_PX); + TouchAction::Flinging(velocity, cursor) + } else { + self.state = Nothing; + TouchAction::NoAction + } + } else { self.state = Nothing; - return TouchAction::Click; + if !self.prevent_click { + TouchAction::Click(point) + } else { + TouchAction::NoAction + } } - TouchAction::NoAction }, - DefaultPrevented | MultiTouch => { - if self.active_touch_points.is_empty() { - self.state = Nothing; - } + _ => { + self.state = Touching; TouchAction::NoAction }, } @@ -263,35 +226,11 @@ impl TouchHandler { return; }, } - match self.state { - Nothing => {}, - Touching | Panning { .. } | Flinging { .. } => { - self.state = Nothing; - }, - Pinching => { - self.state = Panning { - velocity: Vector2D::new(0.0, 0.0), - }; - }, - WaitingForScript | DefaultPrevented | MultiTouch => { - if self.active_touch_points.is_empty() { - self.state = Nothing; - } - }, - } + self.state = Nothing; } - pub fn on_event_processed(&mut self, result: EventResult) { - if let WaitingForScript = self.state { - self.state = match result { - EventResult::DefaultPrevented => DefaultPrevented, - EventResult::DefaultAllowed => match self.touch_count() { - 1 => Touching, - 2 => Pinching, - _ => MultiTouch, - }, - } - } + pub fn on_fling(&mut self, velocity: Vector2D, cursor: DeviceIntPoint) { + self.state = Flinging { velocity, cursor }; } fn touch_count(&self) -> usize { diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index 05da711d35e..f7bc139aac5 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -26,7 +26,7 @@ use devtools_traits::ScriptToDevtoolsControlMsg; use dom_struct::dom_struct; use embedder_traits::{ AllowOrDeny, ContextMenuResult, EditingActionEvent, EmbedderMsg, ImeEvent, InputEvent, - LoadStatus, MouseButton, MouseButtonAction, MouseButtonEvent, TouchEvent, TouchEventAction, + LoadStatus, MouseButton, MouseButtonAction, MouseButtonEvent, TouchEvent, TouchEventType, TouchId, WheelEvent, }; use encoding_rs::{Encoding, UTF_8}; @@ -2013,11 +2013,11 @@ impl Document { }; let TouchId(identifier) = event.id; - let event_name = match event.action { - TouchEventAction::Down => "touchstart", - TouchEventAction::Move => "touchmove", - TouchEventAction::Up => "touchend", - TouchEventAction::Cancel => "touchcancel", + let event_name = match event.event_type { + TouchEventType::Down => "touchstart", + TouchEventType::Move => "touchmove", + TouchEventType::Up => "touchend", + TouchEventType::Cancel => "touchcancel", }; let node = unsafe { node::from_untrusted_compositor_node_address(hit_test_result.node) }; @@ -2043,14 +2043,14 @@ impl Document { client_x, client_y, page_x, page_y, ); - match event.action { - TouchEventAction::Down => { + match event.event_type { + TouchEventType::Down => { // Add a new touch point self.active_touch_points .borrow_mut() .push(Dom::from_ref(&*touch)); }, - TouchEventAction::Move => { + TouchEventType::Move => { // Replace an existing touch point let mut active_touch_points = self.active_touch_points.borrow_mut(); match active_touch_points @@ -2061,7 +2061,7 @@ impl Document { None => warn!("Got a touchmove event for a non-active touch point"), } }, - TouchEventAction::Up | TouchEventAction::Cancel => { + TouchEventType::Up | TouchEventType::Cancel => { // Remove an existing touch point let mut active_touch_points = self.active_touch_points.borrow_mut(); match active_touch_points diff --git a/components/script/script_thread.rs b/components/script/script_thread.rs index 58043823088..8992b457f0f 100644 --- a/components/script/script_thread.rs +++ b/components/script/script_thread.rs @@ -45,7 +45,7 @@ use devtools_traits::{ CSSError, DevtoolScriptControlMsg, DevtoolsPageInfo, NavigationState, ScriptToDevtoolsControlMsg, WorkerId, }; -use embedder_traits::{EmbedderMsg, InputEvent, MediaSessionActionType, Theme, TouchEventAction}; +use embedder_traits::{EmbedderMsg, InputEvent, MediaSessionActionType, Theme}; use euclid::default::Rect; use fonts::{FontContext, SystemFontServiceProxy}; use headers::{HeaderMapExt, LastModified, ReferrerPolicy as ReferrerPolicyHeader}; @@ -1101,13 +1101,12 @@ impl ScriptThread { InputEvent::Touch(touch_event) => { let touch_result = document.handle_touch_event(touch_event, event.hit_test_result, can_gc); - match (touch_event.action, touch_result) { - (TouchEventAction::Down, TouchEventResult::Processed(handled)) => { + match touch_result { + TouchEventResult::Processed(handled) => { let result = if handled { - // TODO: Wait to see if preventDefault is called on the first touchmove event. - EventResult::DefaultAllowed + EventResult::DefaultAllowed(touch_event.action) } else { - EventResult::DefaultPrevented + EventResult::DefaultPrevented(touch_event.event_type) }; let message = ScriptMsg::TouchEventProcessed(result); self.senders diff --git a/components/servo/webview.rs b/components/servo/webview.rs index 060272e01ac..e659e5d3073 100644 --- a/components/servo/webview.rs +++ b/components/servo/webview.rs @@ -12,7 +12,7 @@ use compositing::windowing::WebRenderDebugOption; use compositing::IOCompositor; use compositing_traits::ConstellationMsg; use embedder_traits::{ - Cursor, InputEvent, LoadStatus, MediaSessionActionType, Theme, TouchEventAction, + Cursor, InputEvent, LoadStatus, MediaSessionActionType, Theme, TouchEventType, TraversalDirection, }; use url::Url; @@ -313,7 +313,7 @@ impl WebView { &self, location: ScrollLocation, point: DeviceIntPoint, - touch_event_action: TouchEventAction, + touch_event_action: TouchEventType, ) { self.inner() .compositor diff --git a/components/shared/embedder/Cargo.toml b/components/shared/embedder/Cargo.toml index b4128bfba2b..3076d1c4896 100644 --- a/components/shared/embedder/Cargo.toml +++ b/components/shared/embedder/Cargo.toml @@ -18,6 +18,7 @@ webxr = ["dep:webxr-api"] base = { workspace = true } cfg-if = { workspace = true } crossbeam-channel = { workspace = true } +euclid = { workspace = true } http = { workspace = true } hyper_serde = { workspace = true } ipc-channel = { workspace = true } diff --git a/components/shared/embedder/input_events.rs b/components/shared/embedder/input_events.rs index c4e3ba0e9b4..b7c56c21178 100644 --- a/components/shared/embedder/input_events.rs +++ b/components/shared/embedder/input_events.rs @@ -2,10 +2,11 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +use euclid::Vector2D; use keyboard_types::{CompositionEvent, KeyboardEvent}; use malloc_size_of_derive::MallocSizeOf; use serde::{Deserialize, Serialize}; -pub use webrender_api::units::DevicePoint; +use webrender_api::units::{DeviceIntPoint, DevicePixel, DevicePoint}; /// An input event that is sent from the embedder to Servo. #[derive(Clone, Debug, Deserialize, Serialize)] @@ -104,7 +105,7 @@ pub struct MouseMoveEvent { /// The type of input represented by a multi-touch event. #[derive(Clone, Copy, Debug, Deserialize, Serialize)] -pub enum TouchEventAction { +pub enum TouchEventType { /// A new touch point came in contact with the screen. Down, /// An existing touch point changed location. @@ -115,6 +116,21 @@ pub enum TouchEventAction { Cancel, } +/// The action to take in response to a touch event +#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] +pub enum TouchAction { + /// Simulate a mouse click. + Click(DevicePoint), + /// Fling by the provided offset + Flinging(Vector2D, DeviceIntPoint), + /// Scroll by the provided offset. + Scroll(Vector2D, DevicePoint), + /// Zoom by a magnification factor and scroll by the provided offset. + Zoom(f32, Vector2D), + /// Don't do anything. + NoAction, +} + /// An opaque identifier for a touch point. /// /// @@ -123,9 +139,10 @@ pub struct TouchId(pub i32); #[derive(Clone, Copy, Debug, Deserialize, Serialize)] pub struct TouchEvent { - pub action: TouchEventAction, + pub event_type: TouchEventType, pub id: TouchId, pub point: DevicePoint, + pub action: TouchAction, } /// Mode to measure WheelDelta floats in diff --git a/components/shared/script/script_msg.rs b/components/shared/script/script_msg.rs index 3a503414d27..f3f3a417898 100644 --- a/components/shared/script/script_msg.rs +++ b/components/shared/script/script_msg.rs @@ -13,7 +13,9 @@ use base::id::{ use base::Epoch; use canvas_traits::canvas::{CanvasId, CanvasMsg}; use devtools_traits::{ScriptToDevtoolsControlMsg, WorkerId}; -use embedder_traits::{EmbedderMsg, MediaSessionEvent, TraversalDirection}; +use embedder_traits::{ + EmbedderMsg, MediaSessionEvent, TouchAction, TouchEventType, TraversalDirection, +}; use euclid::default::Size2D as UntypedSize2D; use euclid::Size2D; use ipc_channel::ipc::{IpcReceiver, IpcSender}; @@ -64,9 +66,9 @@ impl fmt::Debug for LayoutMsg { #[derive(Debug, Deserialize, Serialize)] pub enum EventResult { /// Allowed by web content - DefaultAllowed, + DefaultAllowed(TouchAction), /// Prevented by web content - DefaultPrevented, + DefaultPrevented(TouchEventType), } /// A log entry reported to the constellation diff --git a/ports/servoshell/desktop/app_state.rs b/ports/servoshell/desktop/app_state.rs index cd920e90683..848c78b8dd4 100644 --- a/ports/servoshell/desktop/app_state.rs +++ b/ports/servoshell/desktop/app_state.rs @@ -19,7 +19,7 @@ use servo::webrender_api::ScrollLocation; use servo::{ AllowOrDenyRequest, AuthenticationRequest, FilterPattern, GamepadHapticEffectType, LoadStatus, PermissionRequest, PromptDefinition, PromptOrigin, PromptResult, Servo, ServoDelegate, - ServoError, TouchEventAction, WebView, WebViewDelegate, + ServoError, TouchEventType, WebView, WebViewDelegate, }; #[cfg(target_os = "linux")] use tinyfiledialogs::MessageBoxIcon; @@ -274,36 +274,36 @@ impl RunningAppState { 0.0, -self.inner().window.page_height() + 2.0 * LINE_HEIGHT, )); - webview.notify_scroll_event(scroll_location, origin, TouchEventAction::Move); + webview.notify_scroll_event(scroll_location, origin, TouchEventType::Move); }) .shortcut(Modifiers::empty(), Key::PageUp, || { let scroll_location = ScrollLocation::Delta(Vector2D::new( 0.0, self.inner().window.page_height() - 2.0 * LINE_HEIGHT, )); - webview.notify_scroll_event(scroll_location, origin, TouchEventAction::Move); + webview.notify_scroll_event(scroll_location, origin, TouchEventType::Move); }) .shortcut(Modifiers::empty(), Key::Home, || { - webview.notify_scroll_event(ScrollLocation::Start, origin, TouchEventAction::Move); + webview.notify_scroll_event(ScrollLocation::Start, origin, TouchEventType::Move); }) .shortcut(Modifiers::empty(), Key::End, || { - webview.notify_scroll_event(ScrollLocation::End, origin, TouchEventAction::Move); + webview.notify_scroll_event(ScrollLocation::End, origin, TouchEventType::Move); }) .shortcut(Modifiers::empty(), Key::ArrowUp, || { let location = ScrollLocation::Delta(Vector2D::new(0.0, 3.0 * LINE_HEIGHT)); - webview.notify_scroll_event(location, origin, TouchEventAction::Move); + webview.notify_scroll_event(location, origin, TouchEventType::Move); }) .shortcut(Modifiers::empty(), Key::ArrowDown, || { let location = ScrollLocation::Delta(Vector2D::new(0.0, -3.0 * LINE_HEIGHT)); - webview.notify_scroll_event(location, origin, TouchEventAction::Move); + webview.notify_scroll_event(location, origin, TouchEventType::Move); }) .shortcut(Modifiers::empty(), Key::ArrowLeft, || { let location = ScrollLocation::Delta(Vector2D::new(LINE_HEIGHT, 0.0)); - webview.notify_scroll_event(location, origin, TouchEventAction::Move); + webview.notify_scroll_event(location, origin, TouchEventType::Move); }) .shortcut(Modifiers::empty(), Key::ArrowRight, || { let location = ScrollLocation::Delta(Vector2D::new(-LINE_HEIGHT, 0.0)); - webview.notify_scroll_event(location, origin, TouchEventAction::Move); + webview.notify_scroll_event(location, origin, TouchEventType::Move); }); } } diff --git a/ports/servoshell/desktop/headed_window.rs b/ports/servoshell/desktop/headed_window.rs index b68f50ae284..aeefe56b16b 100644 --- a/ports/servoshell/desktop/headed_window.rs +++ b/ports/servoshell/desktop/headed_window.rs @@ -26,8 +26,8 @@ use servo::webrender_traits::rendering_context::{OffscreenRenderingContext, Rend use servo::webrender_traits::SurfmanRenderingContext; use servo::{ Cursor, InputEvent, Key, KeyState, KeyboardEvent, MouseButton as ServoMouseButton, - MouseButtonAction, MouseButtonEvent, MouseMoveEvent, Theme, TouchEvent, TouchEventAction, - TouchId, WebView, WheelDelta, WheelEvent, WheelMode, + MouseButtonAction, MouseButtonEvent, MouseMoveEvent, Theme, TouchAction, TouchEvent, + TouchEventType, TouchId, WebView, WheelDelta, WheelEvent, WheelMode, }; use surfman::{Connection, Context, Device, SurfaceType}; use url::Url; @@ -606,7 +606,7 @@ impl WindowPortsMethods for Window { } let scroll_location = ScrollLocation::Delta(Vector2D::new(dx as f32, dy as f32)); - let phase = winit_phase_to_touch_event_action(phase); + let phase = winit_phase_to_touch_event_type(phase); // Send events webview.notify_input_event(InputEvent::Wheel(WheelEvent { delta, point })); @@ -618,9 +618,10 @@ impl WindowPortsMethods for Window { }, WindowEvent::Touch(touch) => { webview.notify_input_event(InputEvent::Touch(TouchEvent { - action: winit_phase_to_touch_event_action(touch.phase), + event_type: winit_phase_to_touch_event_type(touch.phase), id: TouchId(touch.id as i32), point: Point2D::new(touch.location.x as f32, touch.location.y as f32), + action: TouchAction::NoAction, })); }, WindowEvent::PinchGesture { delta, .. } => { @@ -729,12 +730,12 @@ impl WindowMethods for Window { } } -fn winit_phase_to_touch_event_action(phase: TouchPhase) -> TouchEventAction { +fn winit_phase_to_touch_event_type(phase: TouchPhase) -> TouchEventType { match phase { - TouchPhase::Started => TouchEventAction::Down, - TouchPhase::Moved => TouchEventAction::Move, - TouchPhase::Ended => TouchEventAction::Up, - TouchPhase::Cancelled => TouchEventAction::Cancel, + TouchPhase::Started => TouchEventType::Down, + TouchPhase::Moved => TouchEventType::Move, + TouchPhase::Ended => TouchEventType::Up, + TouchPhase::Cancelled => TouchEventType::Cancel, } } diff --git a/ports/servoshell/egl/app_state.rs b/ports/servoshell/egl/app_state.rs index 1dc99f6c2d8..085c931cfb3 100644 --- a/ports/servoshell/egl/app_state.rs +++ b/ports/servoshell/egl/app_state.rs @@ -23,7 +23,8 @@ use servo::{ InputMethodType, Key, KeyState, KeyboardEvent, LoadStatus, MediaSessionActionType, MediaSessionEvent, MouseButton, MouseButtonAction, MouseButtonEvent, MouseMoveEvent, NavigationRequest, PermissionRequest, PromptDefinition, PromptOrigin, PromptResult, Servo, - ServoDelegate, ServoError, TouchEvent, TouchEventAction, TouchId, WebView, WebViewDelegate, + ServoDelegate, ServoError, TouchAction, TouchEvent, TouchEventType, TouchId, WebView, + WebViewDelegate, }; use url::Url; @@ -449,7 +450,7 @@ impl RunningAppState { self.active_webview().notify_scroll_event( scroll_location, Point2D::new(x, y), - TouchEventAction::Down, + TouchEventType::Down, ); self.perform_updates(); } @@ -463,7 +464,7 @@ impl RunningAppState { self.active_webview().notify_scroll_event( scroll_location, Point2D::new(x, y), - TouchEventAction::Move, + TouchEventType::Move, ); self.perform_updates(); } @@ -478,7 +479,7 @@ impl RunningAppState { self.active_webview().notify_scroll_event( scroll_location, Point2D::new(x, y), - TouchEventAction::Up, + TouchEventType::Up, ); self.perform_updates(); } @@ -487,9 +488,10 @@ impl RunningAppState { pub fn touch_down(&self, x: f32, y: f32, pointer_id: i32) { self.active_webview() .notify_input_event(InputEvent::Touch(TouchEvent { - action: TouchEventAction::Down, + event_type: TouchEventType::Down, id: TouchId(pointer_id), point: Point2D::new(x, y), + action: TouchAction::NoAction, })); self.perform_updates(); } @@ -498,9 +500,10 @@ impl RunningAppState { pub fn touch_move(&self, x: f32, y: f32, pointer_id: i32) { self.active_webview() .notify_input_event(InputEvent::Touch(TouchEvent { - action: TouchEventAction::Move, + event_type: TouchEventType::Move, id: TouchId(pointer_id), point: Point2D::new(x, y), + action: TouchAction::NoAction, })); self.perform_updates(); } @@ -509,9 +512,10 @@ impl RunningAppState { pub fn touch_up(&self, x: f32, y: f32, pointer_id: i32) { self.active_webview() .notify_input_event(InputEvent::Touch(TouchEvent { - action: TouchEventAction::Up, + event_type: TouchEventType::Up, id: TouchId(pointer_id), point: Point2D::new(x, y), + action: TouchAction::NoAction, })); self.perform_updates(); } @@ -520,9 +524,10 @@ impl RunningAppState { pub fn touch_cancel(&self, x: f32, y: f32, pointer_id: i32) { self.active_webview() .notify_input_event(InputEvent::Touch(TouchEvent { - action: TouchEventAction::Cancel, + event_type: TouchEventType::Cancel, id: TouchId(pointer_id), point: Point2D::new(x, y), + action: TouchAction::NoAction, })); self.perform_updates(); }