mirror of
https://github.com/servo/servo.git
synced 2025-06-06 00:25:37 +00:00
Incorporate suggestions.
Co-authored-by: Jonathan Schwender <55576758+jschwe@users.noreply.github.com> Signed-off-by: Narfinger <Narfinger@users.noreply.github.com>
This commit is contained in:
parent
7de9716dc0
commit
d1389378ad
6 changed files with 163 additions and 126 deletions
|
@ -381,84 +381,83 @@ impl TouchHandler {
|
|||
// As `TouchHandler` is per `WebViewRenderer` which is per `WebView` we might get a Touch Sequence Move that
|
||||
// started with a down on a different webview. As the touch_sequence id is only changed on touch_down this
|
||||
// move event gets a touch id which is already cleaned up.
|
||||
if let Some(touch_sequence) = self.try_get_current_touch_sequence_mut() {
|
||||
let idx = match touch_sequence
|
||||
.active_touch_points
|
||||
.iter_mut()
|
||||
.position(|t| t.id == id)
|
||||
{
|
||||
Some(i) => i,
|
||||
None => {
|
||||
error!("Got a touchmove event for a non-active touch point");
|
||||
return TouchMoveAction::NoAction;
|
||||
},
|
||||
};
|
||||
let old_point = touch_sequence.active_touch_points[idx].point;
|
||||
let delta = point - old_point;
|
||||
let Some(touch_sequence) = self.try_get_current_touch_sequence_mut() else {
|
||||
return TouchMoveAction::NoAction;
|
||||
};
|
||||
let idx = match touch_sequence
|
||||
.active_touch_points
|
||||
.iter_mut()
|
||||
.position(|t| t.id == id)
|
||||
{
|
||||
Some(i) => i,
|
||||
None => {
|
||||
error!("Got a touchmove event for a non-active touch point");
|
||||
return TouchMoveAction::NoAction;
|
||||
},
|
||||
};
|
||||
let old_point = touch_sequence.active_touch_points[idx].point;
|
||||
let delta = point - old_point;
|
||||
|
||||
let action = match touch_sequence.touch_count() {
|
||||
1 => {
|
||||
if let Panning { ref mut velocity } = touch_sequence.state {
|
||||
// TODO: Probably we should track 1-3 more points and use a smarter algorithm
|
||||
*velocity += delta;
|
||||
*velocity /= 2.0;
|
||||
// update the touch point every time when panning.
|
||||
touch_sequence.active_touch_points[idx].point = point;
|
||||
TouchMoveAction::Scroll(delta, point)
|
||||
} else if delta.x.abs() > TOUCH_PAN_MIN_SCREEN_PX ||
|
||||
delta.y.abs() > TOUCH_PAN_MIN_SCREEN_PX
|
||||
{
|
||||
touch_sequence.state = Panning {
|
||||
velocity: Vector2D::new(delta.x, delta.y),
|
||||
};
|
||||
// No clicks should be issued after we transitioned to move.
|
||||
touch_sequence.prevent_click = true;
|
||||
// update the touch point
|
||||
touch_sequence.active_touch_points[idx].point = point;
|
||||
TouchMoveAction::Scroll(delta, point)
|
||||
} else {
|
||||
// We don't update the touchpoint, so multiple small moves can
|
||||
// accumulate and merge into a larger move.
|
||||
TouchMoveAction::NoAction
|
||||
}
|
||||
},
|
||||
2 => {
|
||||
if touch_sequence.state == Pinching ||
|
||||
delta.x.abs() > TOUCH_PAN_MIN_SCREEN_PX ||
|
||||
delta.y.abs() > TOUCH_PAN_MIN_SCREEN_PX
|
||||
{
|
||||
touch_sequence.state = Pinching;
|
||||
let (d0, c0) = touch_sequence.pinch_distance_and_center();
|
||||
// update the touch point with the enough distance or pinching.
|
||||
touch_sequence.active_touch_points[idx].point = point;
|
||||
let (d1, c1) = touch_sequence.pinch_distance_and_center();
|
||||
let magnification = d1 / d0;
|
||||
let scroll_delta = c1 - c0 * Scale::new(magnification);
|
||||
TouchMoveAction::Zoom(magnification, scroll_delta)
|
||||
} else {
|
||||
// We don't update the touchpoint, so multiple small moves can
|
||||
// accumulate and merge into a larger move.
|
||||
TouchMoveAction::NoAction
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
let action = match touch_sequence.touch_count() {
|
||||
1 => {
|
||||
if let Panning { ref mut velocity } = touch_sequence.state {
|
||||
// TODO: Probably we should track 1-3 more points and use a smarter algorithm
|
||||
*velocity += delta;
|
||||
*velocity /= 2.0;
|
||||
// update the touch point every time when panning.
|
||||
touch_sequence.active_touch_points[idx].point = point;
|
||||
touch_sequence.state = MultiTouch;
|
||||
TouchMoveAction::Scroll(delta, point)
|
||||
} else if delta.x.abs() > TOUCH_PAN_MIN_SCREEN_PX ||
|
||||
delta.y.abs() > TOUCH_PAN_MIN_SCREEN_PX
|
||||
{
|
||||
touch_sequence.state = Panning {
|
||||
velocity: Vector2D::new(delta.x, delta.y),
|
||||
};
|
||||
// No clicks should be issued after we transitioned to move.
|
||||
touch_sequence.prevent_click = true;
|
||||
// update the touch point
|
||||
touch_sequence.active_touch_points[idx].point = point;
|
||||
TouchMoveAction::Scroll(delta, point)
|
||||
} else {
|
||||
// We don't update the touchpoint, so multiple small moves can
|
||||
// accumulate and merge into a larger move.
|
||||
TouchMoveAction::NoAction
|
||||
},
|
||||
};
|
||||
// If the touch action is not `NoAction` and the first move has not been processed,
|
||||
// set pending_touch_move_action.
|
||||
if TouchMoveAction::NoAction != action &&
|
||||
touch_sequence.prevent_move == TouchMoveAllowed::Pending
|
||||
{
|
||||
touch_sequence.update_pending_touch_move_action(action);
|
||||
}
|
||||
|
||||
action
|
||||
} else {
|
||||
TouchMoveAction::NoAction
|
||||
}
|
||||
},
|
||||
2 => {
|
||||
if touch_sequence.state == Pinching ||
|
||||
delta.x.abs() > TOUCH_PAN_MIN_SCREEN_PX ||
|
||||
delta.y.abs() > TOUCH_PAN_MIN_SCREEN_PX
|
||||
{
|
||||
touch_sequence.state = Pinching;
|
||||
let (d0, c0) = touch_sequence.pinch_distance_and_center();
|
||||
// update the touch point with the enough distance or pinching.
|
||||
touch_sequence.active_touch_points[idx].point = point;
|
||||
let (d1, c1) = touch_sequence.pinch_distance_and_center();
|
||||
let magnification = d1 / d0;
|
||||
let scroll_delta = c1 - c0 * Scale::new(magnification);
|
||||
TouchMoveAction::Zoom(magnification, scroll_delta)
|
||||
} else {
|
||||
// We don't update the touchpoint, so multiple small moves can
|
||||
// accumulate and merge into a larger move.
|
||||
TouchMoveAction::NoAction
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
touch_sequence.active_touch_points[idx].point = point;
|
||||
touch_sequence.state = MultiTouch;
|
||||
TouchMoveAction::NoAction
|
||||
},
|
||||
};
|
||||
// If the touch action is not `NoAction` and the first move has not been processed,
|
||||
// set pending_touch_move_action.
|
||||
if TouchMoveAction::NoAction != action &&
|
||||
touch_sequence.prevent_move == TouchMoveAllowed::Pending
|
||||
{
|
||||
touch_sequence.update_pending_touch_move_action(action);
|
||||
}
|
||||
|
||||
action
|
||||
}
|
||||
|
||||
pub fn on_touch_up(&mut self, id: TouchId, point: Point2D<f32, DevicePixel>) {
|
||||
|
@ -540,23 +539,24 @@ impl TouchHandler {
|
|||
|
||||
pub fn on_touch_cancel(&mut self, id: TouchId, _point: Point2D<f32, DevicePixel>) {
|
||||
// A similar thing with touch move can happen here where the event is coming from a different webview.
|
||||
if let Some(touch_sequence) = self.try_get_current_touch_sequence_mut() {
|
||||
match touch_sequence
|
||||
.active_touch_points
|
||||
.iter()
|
||||
.position(|t| t.id == id)
|
||||
{
|
||||
Some(i) => {
|
||||
touch_sequence.active_touch_points.swap_remove(i);
|
||||
},
|
||||
None => {
|
||||
warn!("Got a touchcancel event for a non-active touch point");
|
||||
return;
|
||||
},
|
||||
}
|
||||
if touch_sequence.active_touch_points.is_empty() {
|
||||
touch_sequence.state = Finished;
|
||||
}
|
||||
let Some(touch_sequence) = self.try_get_current_touch_sequence_mut() else {
|
||||
return;
|
||||
};
|
||||
match touch_sequence
|
||||
.active_touch_points
|
||||
.iter()
|
||||
.position(|t| t.id == id)
|
||||
{
|
||||
Some(i) => {
|
||||
touch_sequence.active_touch_points.swap_remove(i);
|
||||
},
|
||||
None => {
|
||||
warn!("Got a touchcancel event for a non-active touch point");
|
||||
return;
|
||||
},
|
||||
}
|
||||
if touch_sequence.active_touch_points.is_empty() {
|
||||
touch_sequence.state = Finished;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -404,7 +404,8 @@ impl WebViewRenderer {
|
|||
self.dispatch_input_event(event);
|
||||
}
|
||||
|
||||
/// Send touch event to the pipeline. Returns true if the event was send
|
||||
/// Send a [`TouchEvent`] to the Constellation for this [`WebViewRenderer`].
|
||||
/// Returns true if the event was send
|
||||
fn send_touch_event(&self, mut event: TouchEvent) -> bool {
|
||||
let get_pipeline_details = |pipeline_id| self.pipelines.get(&pipeline_id);
|
||||
let Some(result) = self
|
||||
|
|
|
@ -124,7 +124,7 @@ pub enum TouchEventType {
|
|||
pub struct TouchId(pub i32);
|
||||
|
||||
/// An ID for a sequence of touch events between a `Down` and the `Up` or `Cancel` event.
|
||||
/// The ID is the same for all events between `Down`` and `Up`` or `Cancel``
|
||||
/// The ID is the same for all events between `Down` and `Up` or `Cancel`
|
||||
#[repr(transparent)]
|
||||
#[derive(Clone, Copy, Debug, Default, Deserialize, Eq, Hash, PartialEq, Serialize)]
|
||||
pub struct TouchSequenceId(u32);
|
||||
|
|
|
@ -337,13 +337,9 @@ impl RunningAppState {
|
|||
self.inner_mut().webviews.insert(webview.id(), webview);
|
||||
}
|
||||
|
||||
pub(crate) fn activate_webview(&self, id: u32) {
|
||||
let inner = self.inner();
|
||||
let webview = inner
|
||||
.creation_order
|
||||
.get(id as usize)
|
||||
.and_then(|id| inner.webviews.get(id));
|
||||
if let Some(webview) = webview {
|
||||
/// The focused webview will not be immediately valid via `active_webview()`
|
||||
pub(crate) fn focus_webview(&self, id: WebViewId) {
|
||||
if let Some(webview) = self.inner().webviews.get(&id) {
|
||||
webview.focus();
|
||||
} else {
|
||||
error!("We could not find the webview with this id {id}");
|
||||
|
@ -366,14 +362,14 @@ impl RunningAppState {
|
|||
Ok(webview_id)
|
||||
}
|
||||
|
||||
fn newest_webview(&self) -> Option<WebView> {
|
||||
pub(crate) fn newest_webview(&self) -> Option<WebView> {
|
||||
self.inner()
|
||||
.creation_order
|
||||
.last()
|
||||
.and_then(|id| self.inner().webviews.get(id).cloned())
|
||||
}
|
||||
|
||||
fn active_webview(&self) -> WebView {
|
||||
pub(crate) fn active_webview(&self) -> WebView {
|
||||
self.inner()
|
||||
.focused_webview_id
|
||||
.and_then(|id| self.inner().webviews.get(&id).cloned())
|
||||
|
|
|
@ -24,7 +24,7 @@ use ohos_ime_sys::types::InputMethod_EnterKeyType;
|
|||
use servo::style::Zero;
|
||||
use servo::{
|
||||
AlertResponse, EventLoopWaker, InputMethodType, LoadStatus, MediaSessionPlaybackState,
|
||||
PermissionRequest, SimpleDialog, WebView,
|
||||
PermissionRequest, SimpleDialog, WebView, WebViewId,
|
||||
};
|
||||
use xcomponent_sys::{
|
||||
OH_NativeXComponent, OH_NativeXComponent_Callback, OH_NativeXComponent_GetKeyEvent,
|
||||
|
@ -131,10 +131,19 @@ static PROMPT_TOAST: OnceLock<
|
|||
ThreadsafeFunction<String, (), String, false, false, PROMPT_QUEUE_SIZE>,
|
||||
> = OnceLock::new();
|
||||
|
||||
/// Storing webview related items
|
||||
struct NativeWebViewComponents {
|
||||
/// The id of the related webview
|
||||
id: WebViewId,
|
||||
/// The XComponentWrapper for the above webview
|
||||
xcomponent: XComponentWrapper,
|
||||
/// The WindowWrapper for the above webview
|
||||
window: WindowWrapper,
|
||||
}
|
||||
|
||||
/// Currently we do not support different contexts for different windows but we might want to change tabs.
|
||||
/// For this we store the window context for every tab and change the compositor by hand.
|
||||
static WEBVIEW_TO_RAW_HANDLE: Mutex<Vec<(XComponentWrapper, WindowWrapper)>> =
|
||||
Mutex::new(Vec::new());
|
||||
static NATIVE_WEBVIEWS: Mutex<Vec<NativeWebViewComponents>> = Mutex::new(Vec::new());
|
||||
|
||||
impl ServoAction {
|
||||
fn dispatch_touch_event(
|
||||
|
@ -194,28 +203,55 @@ impl ServoAction {
|
|||
servo.present_if_needed();
|
||||
},
|
||||
Resize { width, height } => servo.resize(Coordinates::new(0, 0, *width, *height)),
|
||||
FocusWebview(id) => {
|
||||
servo.activate_webview(id.clone());
|
||||
servo.pause_compositor();
|
||||
let webview_lock = WEBVIEW_TO_RAW_HANDLE.lock().unwrap();
|
||||
let (xcomponent_wrapper, window_wrapper) = webview_lock
|
||||
.get(*id as usize)
|
||||
.clone()
|
||||
.expect("Could not find window handle to webview");
|
||||
let (window_handle, _, coordinates) =
|
||||
simpleservo::get_raw_window_handle(xcomponent_wrapper.0, window_wrapper.0);
|
||||
servo.resume_compositor(window_handle, coordinates);
|
||||
FocusWebview(arkts_id) => {
|
||||
if let Some(native_webview_components) =
|
||||
NATIVE_WEBVIEWS.lock().unwrap().get(*arkts_id as usize)
|
||||
{
|
||||
if (servo.active_webview().id() != native_webview_components.id) {
|
||||
servo.focus_webview(native_webview_components.id);
|
||||
servo.pause_compositor();
|
||||
let (window_handle, _, coordinates) = simpleservo::get_raw_window_handle(
|
||||
native_webview_components.xcomponent.0,
|
||||
native_webview_components.window.0,
|
||||
);
|
||||
servo.resume_compositor(window_handle, coordinates);
|
||||
let url = servo
|
||||
.active_webview()
|
||||
.url()
|
||||
.map(|u| u.to_string())
|
||||
.unwrap_or(String::from("about:blank"));
|
||||
SET_URL_BAR_CB
|
||||
.get()
|
||||
.map(|f| f.call(url, ThreadsafeFunctionCallMode::Blocking));
|
||||
}
|
||||
} else {
|
||||
error!("Could not find webview to focus");
|
||||
}
|
||||
},
|
||||
NewWebview(xcomponent, window) => {
|
||||
servo.pause_compositor();
|
||||
servo.new_toplevel_webview("about:blank".parse().unwrap());
|
||||
let (window_handle, _, coordinates) =
|
||||
simpleservo::get_raw_window_handle(xcomponent.0, window.0);
|
||||
WEBVIEW_TO_RAW_HANDLE
|
||||
|
||||
servo.resume_compositor(window_handle, coordinates);
|
||||
let webview = servo.newest_webview().expect("There should always be one");
|
||||
let id = webview.id();
|
||||
NATIVE_WEBVIEWS
|
||||
.lock()
|
||||
.unwrap()
|
||||
.push((xcomponent.clone(), window.clone()));
|
||||
servo.resume_compositor(window_handle, coordinates);
|
||||
.push(NativeWebViewComponents {
|
||||
id: id,
|
||||
xcomponent: xcomponent.clone(),
|
||||
window: window.clone(),
|
||||
});
|
||||
let url = webview
|
||||
.url()
|
||||
.map(|u| u.to_string())
|
||||
.unwrap_or(String::from("about:blank"));
|
||||
SET_URL_BAR_CB
|
||||
.get()
|
||||
.map(|f| f.call(url, ThreadsafeFunctionCallMode::Blocking));
|
||||
},
|
||||
};
|
||||
}
|
||||
|
@ -273,11 +309,6 @@ extern "C" fn on_surface_created_cb(xcomponent: *mut OH_NativeXComponent, window
|
|||
let xc = xc_wrapper;
|
||||
let window = window_wrapper;
|
||||
|
||||
WEBVIEW_TO_RAW_HANDLE
|
||||
.lock()
|
||||
.unwrap()
|
||||
.push((xc.clone(), window.clone()));
|
||||
|
||||
let init_opts = if let Ok(ServoAction::Initialize(init_opts)) = rx.recv() {
|
||||
init_opts
|
||||
} else {
|
||||
|
@ -286,6 +317,15 @@ extern "C" fn on_surface_created_cb(xcomponent: *mut OH_NativeXComponent, window
|
|||
let servo = simpleservo::init(*init_opts, window.0, xc.0, wakeup, callbacks)
|
||||
.expect("Servo initialization failed");
|
||||
|
||||
NATIVE_WEBVIEWS
|
||||
.lock()
|
||||
.unwrap()
|
||||
.push(NativeWebViewComponents {
|
||||
id: servo.active_webview().id(),
|
||||
xcomponent: xc,
|
||||
window,
|
||||
});
|
||||
|
||||
info!("Surface created!");
|
||||
let native_vsync =
|
||||
ohos_vsync::NativeVsync::new("ServoVsync").expect("Failed to create NativeVsync");
|
||||
|
|
|
@ -29,11 +29,11 @@ pub(crate) fn get_raw_window_handle(
|
|||
) -> (RawWindowHandle, euclid::default::Size2D<i32>, Coordinates) {
|
||||
let window_size = unsafe { super::get_xcomponent_size(xcomponent, window) }
|
||||
.expect("Could not get native window size");
|
||||
let (x, y) = unsafe { super::get_xcomponent_offset(xcomponent, window)}.expect("Could not get native window offset");
|
||||
let (x, y) = unsafe { super::get_xcomponent_offset(xcomponent, window) }
|
||||
.expect("Could not get native window offset");
|
||||
let coordinates = Coordinates::new(x, y, window_size.width, window_size.height);
|
||||
let native_window = NonNull::new(window).expect("Could not get native window");
|
||||
let window_handle = RawWindowHandle::OhosNdk(OhosNdkWindowHandle::new(native_window));
|
||||
let coordinates = Coordinates::new(0, 0, window_size.width, window_size.height);
|
||||
(window_handle, window_size, coordinates)
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue