Skip to content
This repository was archived by the owner on Oct 8, 2025. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion src/compositor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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<VersoRuntimeSettings>,
}

#[derive(Clone, Copy)]
Expand Down Expand Up @@ -344,6 +348,7 @@ impl IOCompositor {
state: InitialCompositorState,
exit_after_load: bool,
convert_mouse_to_touch: bool,
verso_settings: Rc<VersoRuntimeSettings>,
) -> Self {
let compositor = IOCompositor {
current_window,
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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() {
Expand Down
11 changes: 11 additions & 0 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<PathBuf>,
/// Disable pinching motions on touch input enabled devices to scale the web content
pub no_pinch_zoom: bool,
}

/// Configuration of Verso instance.
Expand Down Expand Up @@ -121,6 +123,12 @@ fn parse_cli_args() -> Result<CliArgs, getopts::Fail> {
"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")
Expand Down Expand Up @@ -208,6 +216,8 @@ fn parse_cli_args() -> Result<CliArgs, getopts::Fail> {
window_attributes = window_attributes.with_maximized(true);
}

let no_pinch_zoom = matches.opt_present("no-pinch-zoom");

Ok(CliArgs {
url,
resource_dir,
Expand All @@ -216,6 +226,7 @@ fn parse_cli_args() -> Result<CliArgs, getopts::Fail> {
window_attributes,
devtools_port,
profiler_settings,
no_pinch_zoom,
})
}

Expand Down
13 changes: 10 additions & 3 deletions src/touch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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,
Expand Down
14 changes: 14 additions & 0 deletions src/verso.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use std::{
borrow::Cow,
collections::HashMap,
rc::Rc,
sync::{atomic::Ordering, Arc},
};

Expand Down Expand Up @@ -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<WindowId, (Window, DocumentId)>,
Expand All @@ -60,6 +66,9 @@ pub struct Verso {
_js_engine_setup: Option<JSEngineSetup>,
/// FIXME: It's None on wayland in Flatpak. Find a way to support this.
clipboard: Option<Clipboard>,
#[allow(dead_code)]
// TODO: Allow IPC to change some of these settings dynamically
settings: Rc<VersoRuntimeSettings>,
}

impl Verso {
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -373,6 +385,7 @@ impl Verso {
},
opts.exit_after_load,
opts.debug.convert_mouse_to_touch,
settings.clone(),
);

if with_panel {
Expand All @@ -392,6 +405,7 @@ impl Verso {
embedder_receiver,
_js_engine_setup: js_engine_setup,
clipboard: Clipboard::new().ok(),
settings,
};

verso.setup_logging();
Expand Down
27 changes: 18 additions & 9 deletions src/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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},
Expand Down Expand Up @@ -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()),
Expand Down Expand Up @@ -707,3 +707,12 @@ pub unsafe fn decorate_window(view: *mut AnyObject, _position: LogicalPosition<f
| NSWindowStyleMask::Miniaturizable,
);
}

fn to_touch_event(phase: TouchPhase) -> TouchEventType {
match phase {
TouchPhase::Started => TouchEventType::Down,
TouchPhase::Moved => TouchEventType::Move,
TouchPhase::Ended => TouchEventType::Up,
TouchPhase::Cancelled => TouchEventType::Cancel,
}
}