diff --git a/src/compositor.rs b/src/compositor.rs index 41697e06..3f3070e7 100644 --- a/src/compositor.rs +++ b/src/compositor.rs @@ -47,6 +47,7 @@ use winit::window::WindowId; use crate::rendering::RenderingContext; use crate::touch::{TouchAction, TouchHandler}; +use crate::verso::VersoRuntimeSettings; use crate::window::Window; /// Data used to construct a compositor. @@ -213,6 +214,9 @@ pub struct IOCompositor { /// will want to avoid blocking on UI events, and just /// run the event loop at the vsync interval. pub is_animating: bool, + + /// Verso's runtime settings + verso_settings: Rc, } #[derive(Clone, Copy)] @@ -344,6 +348,7 @@ impl IOCompositor { state: InitialCompositorState, exit_after_load: bool, convert_mouse_to_touch: bool, + verso_settings: Rc, ) -> Self { let compositor = IOCompositor { current_window, @@ -380,6 +385,7 @@ impl IOCompositor { last_animation_tick: Instant::now(), is_animating: false, ready_to_present: false, + verso_settings, }; // Make sure the GL state is OK @@ -1562,7 +1568,9 @@ impl IOCompositor { for scroll_event in self.pending_scroll_zoom_events.drain(..) { match scroll_event { ScrollZoomEvent::PinchZoom(magnification) => { - combined_magnification *= magnification + if self.verso_settings.pinch_zoom { + combined_magnification *= magnification + } } ScrollZoomEvent::Scroll(scroll_event_info) => { let combined_event = match combined_scroll_event.as_mut() { diff --git a/src/config.rs b/src/config.rs index bdac2af2..1918889b 100644 --- a/src/config.rs +++ b/src/config.rs @@ -39,6 +39,8 @@ pub struct CliArgs { /// Path to resource directory. If None, Verso will try to get default directory. And if that /// still doesn't exist, all resource configuration will set to default values. pub resource_dir: Option, + /// Disable pinching motions on touch input enabled devices to scale the web content + pub no_pinch_zoom: bool, } /// Configuration of Verso instance. @@ -121,6 +123,12 @@ fn parse_cli_args() -> Result { "Launch the initial window without maximized", ); + opts.optflag( + "", + "no-pinch-zoom", + "Disable pinching motions on touch input enabled devices to scale the web content", + ); + let matches: getopts::Matches = opts.parse(&args[1..])?; let url = matches .opt_str("url") @@ -208,6 +216,8 @@ fn parse_cli_args() -> Result { window_attributes = window_attributes.with_maximized(true); } + let no_pinch_zoom = matches.opt_present("no-pinch-zoom"); + Ok(CliArgs { url, resource_dir, @@ -216,6 +226,7 @@ fn parse_cli_args() -> Result { window_attributes, devtools_port, profiler_settings, + no_pinch_zoom, }) } diff --git a/src/touch.rs b/src/touch.rs index b87f17b1..3659c171 100644 --- a/src/touch.rs +++ b/src/touch.rs @@ -7,6 +7,8 @@ use self::TouchState::*; /// Minimum number of `DeviceIndependentPixel` to begin touch scrolling. const TOUCH_PAN_MIN_SCREEN_PX: f32 = 20.0; +/// Minimum number of `DeviceIndependentPixel` to begin touch pinch zoom. +const TOUCH_PINCH_ZOOM_MIN_SCREEN_PX: f32 = 50.0; /// Handler of touch inputs and states. pub struct TouchHandler { @@ -133,10 +135,15 @@ impl TouchHandler { 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); + // Only start pinch zooming if the distance between the touch points are big enough + if d0 > TOUCH_PINCH_ZOOM_MIN_SCREEN_PX { + let magnification = d1 / d0; + let scroll_delta = c1 - c0 * Scale::new(magnification); - TouchAction::Zoom(magnification, scroll_delta) + TouchAction::Zoom(magnification, scroll_delta) + } else { + TouchAction::NoAction + } } WaitingForScript => TouchAction::NoAction, MultiTouch => TouchAction::NoAction, diff --git a/src/verso.rs b/src/verso.rs index d222e79a..5f4f52bb 100644 --- a/src/verso.rs +++ b/src/verso.rs @@ -1,6 +1,7 @@ use std::{ borrow::Cow, collections::HashMap, + rc::Rc, sync::{atomic::Ordering, Arc}, }; @@ -48,6 +49,11 @@ use crate::{ window::Window, }; +/// Verso's runtime settings +pub struct VersoRuntimeSettings { + pub(crate) pinch_zoom: bool, +} + /// Main entry point of Verso browser. pub struct Verso { windows: HashMap, @@ -60,6 +66,9 @@ pub struct Verso { _js_engine_setup: Option, /// FIXME: It's None on wayland in Flatpak. Find a way to support this. clipboard: Option, + #[allow(dead_code)] + // TODO: Allow IPC to change some of these settings dynamically + settings: Rc, } impl Verso { @@ -108,6 +117,9 @@ impl Verso { let initial_url = config.args.url.clone(); let with_panel = !config.args.no_panel; let window_settings = config.args.window_attributes.clone(); + let pinch_zoom = !config.args.no_pinch_zoom; + + let settings = Rc::new(VersoRuntimeSettings { pinch_zoom }); config.init(); // Reserving a namespace to create TopLevelBrowsingContextId. @@ -373,6 +385,7 @@ impl Verso { }, opts.exit_after_load, opts.debug.convert_mouse_to_touch, + settings.clone(), ); if with_panel { @@ -392,6 +405,7 @@ impl Verso { embedder_receiver, _js_engine_setup: js_engine_setup, clipboard: Clipboard::new().ok(), + settings, }; verso.setup_logging(); diff --git a/src/window.rs b/src/window.rs index 20a5898d..14c46254 100644 --- a/src/window.rs +++ b/src/window.rs @@ -16,7 +16,7 @@ use muda::{Menu, MenuEvent, MenuEventReceiver, MenuItem}; use raw_window_handle::HasWindowHandle; #[cfg(any(target_os = "macos", target_os = "windows"))] use script_traits::TraversalDirection; -use script_traits::{TouchEventType, WheelDelta, WheelMode}; +use script_traits::{TouchEventType, TouchId, WheelDelta, WheelMode}; use servo_url::ServoUrl; use webrender_api::{ units::{DeviceIntPoint, DeviceIntRect, DeviceIntSize, DevicePoint, LayoutVector2D}, @@ -368,17 +368,17 @@ impl Window { y = 0.0; } - let phase: TouchEventType = match phase { - TouchPhase::Started => TouchEventType::Down, - TouchPhase::Moved => TouchEventType::Move, - TouchPhase::Ended => TouchEventType::Up, - TouchPhase::Cancelled => TouchEventType::Cancel, - }; - compositor.on_scroll_event( ScrollLocation::Delta(LayoutVector2D::new(x as f32, y as f32)), DeviceIntPoint::new(position.x as i32, position.y as i32), - phase, + to_touch_event(*phase), + ); + } + WindowEvent::Touch(touch) => { + compositor.on_touch_event( + to_touch_event(touch.phase), + TouchId(touch.id as i32), + DevicePoint::new(touch.location.x as f32, touch.location.y as f32), ); } WindowEvent::ModifiersChanged(modifier) => self.modifiers_state.set(modifier.state()), @@ -707,3 +707,12 @@ pub unsafe fn decorate_window(view: *mut AnyObject, _position: LogicalPosition TouchEventType { + match phase { + TouchPhase::Started => TouchEventType::Down, + TouchPhase::Moved => TouchEventType::Move, + TouchPhase::Ended => TouchEventType::Up, + TouchPhase::Cancelled => TouchEventType::Cancel, + } +}