mirror of
https://github.com/servo/servo.git
synced 2025-08-04 13:10:20 +01:00
libservo: Allow embedders to signal when the cursor has left the WebView
(#37317)
Currently, the hover state will stay when the mouse moves out of the webview, this PR fixes it Testing: Hover on the `About` on servo.org, and then move the mouse up to the browser UI, see the hover state resets Signed-off-by: Tony <legendmastertony@gmail.com>
This commit is contained in:
parent
0896341285
commit
b9fcc95992
7 changed files with 125 additions and 27 deletions
|
@ -360,21 +360,33 @@ impl ServoRenderer {
|
||||||
.send_transaction(self.webrender_document, transaction);
|
.send_transaction(self.webrender_document, transaction);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn update_cursor(&mut self, pos: DevicePoint, result: &CompositorHitTestResult) {
|
pub(crate) fn update_cursor_from_hittest(
|
||||||
self.cursor_pos = pos;
|
&mut self,
|
||||||
|
pos: DevicePoint,
|
||||||
let cursor = match result.cursor {
|
result: &CompositorHitTestResult,
|
||||||
Some(cursor) if cursor != self.cursor => cursor,
|
) {
|
||||||
_ => return,
|
if let Some(webview_id) = self
|
||||||
};
|
|
||||||
|
|
||||||
let Some(webview_id) = self
|
|
||||||
.pipeline_to_webview_map
|
.pipeline_to_webview_map
|
||||||
.get(&result.pipeline_id)
|
.get(&result.pipeline_id)
|
||||||
.cloned()
|
.copied()
|
||||||
else {
|
{
|
||||||
|
self.update_cursor(pos, webview_id, result.cursor);
|
||||||
|
} else {
|
||||||
warn!("Couldn't update cursor for non-WebView-associated pipeline");
|
warn!("Couldn't update cursor for non-WebView-associated pipeline");
|
||||||
return;
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn update_cursor(
|
||||||
|
&mut self,
|
||||||
|
pos: DevicePoint,
|
||||||
|
webview_id: WebViewId,
|
||||||
|
cursor: Option<Cursor>,
|
||||||
|
) {
|
||||||
|
self.cursor_pos = pos;
|
||||||
|
|
||||||
|
let cursor = match cursor {
|
||||||
|
Some(cursor) if cursor != self.cursor => cursor,
|
||||||
|
_ => return,
|
||||||
};
|
};
|
||||||
|
|
||||||
self.cursor = cursor;
|
self.cursor = cursor;
|
||||||
|
@ -631,7 +643,9 @@ impl IOCompositor {
|
||||||
.borrow()
|
.borrow()
|
||||||
.hit_test_at_point(point, details_for_pipeline);
|
.hit_test_at_point(point, details_for_pipeline);
|
||||||
if let Ok(result) = result {
|
if let Ok(result) = result {
|
||||||
self.global.borrow_mut().update_cursor(point, &result);
|
self.global
|
||||||
|
.borrow_mut()
|
||||||
|
.update_cursor_from_hittest(point, &result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -385,8 +385,13 @@ impl WebViewRenderer {
|
||||||
InputEvent::Touch(ref mut touch_event) => {
|
InputEvent::Touch(ref mut touch_event) => {
|
||||||
touch_event.init_sequence_id(self.touch_handler.current_sequence_id);
|
touch_event.init_sequence_id(self.touch_handler.current_sequence_id);
|
||||||
},
|
},
|
||||||
InputEvent::MouseButton(_) | InputEvent::MouseMove(_) | InputEvent::Wheel(_) => {
|
InputEvent::MouseButton(_) |
|
||||||
self.global.borrow_mut().update_cursor(point, &result);
|
InputEvent::MouseLeave(_) |
|
||||||
|
InputEvent::MouseMove(_) |
|
||||||
|
InputEvent::Wheel(_) => {
|
||||||
|
self.global
|
||||||
|
.borrow_mut()
|
||||||
|
.update_cursor_from_hittest(point, &result);
|
||||||
},
|
},
|
||||||
_ => unreachable!("Unexpected input event type: {event:?}"),
|
_ => unreachable!("Unexpected input event type: {event:?}"),
|
||||||
}
|
}
|
||||||
|
@ -428,7 +433,9 @@ impl WebViewRenderer {
|
||||||
touch_event.init_sequence_id(self.touch_handler.current_sequence_id);
|
touch_event.init_sequence_id(self.touch_handler.current_sequence_id);
|
||||||
},
|
},
|
||||||
InputEvent::MouseButton(_) | InputEvent::MouseMove(_) | InputEvent::Wheel(_) => {
|
InputEvent::MouseButton(_) | InputEvent::MouseMove(_) | InputEvent::Wheel(_) => {
|
||||||
self.global.borrow_mut().update_cursor(point, &result);
|
self.global
|
||||||
|
.borrow_mut()
|
||||||
|
.update_cursor_from_hittest(point, &result);
|
||||||
},
|
},
|
||||||
_ => unreachable!("Unexpected input event type: {event:?}"),
|
_ => unreachable!("Unexpected input event type: {event:?}"),
|
||||||
}
|
}
|
||||||
|
|
|
@ -97,6 +97,7 @@ mod from_compositor {
|
||||||
InputEvent::Keyboard(..) => target_variant!("Keyboard"),
|
InputEvent::Keyboard(..) => target_variant!("Keyboard"),
|
||||||
InputEvent::MouseButton(..) => target_variant!("MouseButton"),
|
InputEvent::MouseButton(..) => target_variant!("MouseButton"),
|
||||||
InputEvent::MouseMove(..) => target_variant!("MouseMove"),
|
InputEvent::MouseMove(..) => target_variant!("MouseMove"),
|
||||||
|
InputEvent::MouseLeave(..) => target_variant!("MouseLeave"),
|
||||||
InputEvent::Touch(..) => target_variant!("Touch"),
|
InputEvent::Touch(..) => target_variant!("Touch"),
|
||||||
InputEvent::Wheel(..) => target_variant!("Wheel"),
|
InputEvent::Wheel(..) => target_variant!("Wheel"),
|
||||||
InputEvent::Scroll(..) => target_variant!("Scroll"),
|
InputEvent::Scroll(..) => target_variant!("Scroll"),
|
||||||
|
|
|
@ -2113,6 +2113,49 @@ impl Document {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(unsafe_code)]
|
||||||
|
pub(crate) fn handle_mouse_leave_event(
|
||||||
|
&self,
|
||||||
|
hit_test_result: Option<CompositorHitTestResult>,
|
||||||
|
pressed_mouse_buttons: u16,
|
||||||
|
can_gc: CanGc,
|
||||||
|
) {
|
||||||
|
// Ignore all incoming events without a hit test.
|
||||||
|
let Some(hit_test_result) = hit_test_result else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
self.window()
|
||||||
|
.send_to_embedder(EmbedderMsg::Status(self.webview_id(), None));
|
||||||
|
|
||||||
|
let node = unsafe { node::from_untrusted_node_address(hit_test_result.node) };
|
||||||
|
for element in node
|
||||||
|
.inclusive_ancestors(ShadowIncluding::No)
|
||||||
|
.filter_map(DomRoot::downcast::<Element>)
|
||||||
|
{
|
||||||
|
element.set_hover_state(false);
|
||||||
|
element.set_active_state(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.fire_mouse_event(
|
||||||
|
hit_test_result.point_in_viewport,
|
||||||
|
node.upcast(),
|
||||||
|
FireMouseEventType::Out,
|
||||||
|
EventBubbles::Bubbles,
|
||||||
|
EventCancelable::Cancelable,
|
||||||
|
pressed_mouse_buttons,
|
||||||
|
can_gc,
|
||||||
|
);
|
||||||
|
self.handle_mouse_enter_leave_event(
|
||||||
|
hit_test_result.point_in_viewport,
|
||||||
|
FireMouseEventType::Leave,
|
||||||
|
None,
|
||||||
|
node,
|
||||||
|
pressed_mouse_buttons,
|
||||||
|
can_gc,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
fn handle_mouse_enter_leave_event(
|
fn handle_mouse_enter_leave_event(
|
||||||
&self,
|
&self,
|
||||||
client_point: Point2D<f32>,
|
client_point: Point2D<f32>,
|
||||||
|
|
|
@ -1127,6 +1127,14 @@ impl ScriptThread {
|
||||||
can_gc,
|
can_gc,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
InputEvent::MouseLeave(_) => {
|
||||||
|
self.topmost_mouse_over_target.take();
|
||||||
|
document.handle_mouse_leave_event(
|
||||||
|
event.hit_test_result,
|
||||||
|
event.pressed_mouse_buttons,
|
||||||
|
can_gc,
|
||||||
|
);
|
||||||
|
},
|
||||||
InputEvent::Touch(touch_event) => {
|
InputEvent::Touch(touch_event) => {
|
||||||
let touch_result =
|
let touch_result =
|
||||||
document.handle_touch_event(touch_event, event.hit_test_result, can_gc);
|
document.handle_touch_event(touch_event, event.hit_test_result, can_gc);
|
||||||
|
|
|
@ -20,6 +20,7 @@ pub enum InputEvent {
|
||||||
Keyboard(KeyboardEvent),
|
Keyboard(KeyboardEvent),
|
||||||
MouseButton(MouseButtonEvent),
|
MouseButton(MouseButtonEvent),
|
||||||
MouseMove(MouseMoveEvent),
|
MouseMove(MouseMoveEvent),
|
||||||
|
MouseLeave(MouseLeaveEvent),
|
||||||
Touch(TouchEvent),
|
Touch(TouchEvent),
|
||||||
Wheel(WheelEvent),
|
Wheel(WheelEvent),
|
||||||
Scroll(ScrollEvent),
|
Scroll(ScrollEvent),
|
||||||
|
@ -42,6 +43,7 @@ impl InputEvent {
|
||||||
InputEvent::Keyboard(..) => None,
|
InputEvent::Keyboard(..) => None,
|
||||||
InputEvent::MouseButton(event) => Some(event.point),
|
InputEvent::MouseButton(event) => Some(event.point),
|
||||||
InputEvent::MouseMove(event) => Some(event.point),
|
InputEvent::MouseMove(event) => Some(event.point),
|
||||||
|
InputEvent::MouseLeave(event) => Some(event.point),
|
||||||
InputEvent::Touch(event) => Some(event.point),
|
InputEvent::Touch(event) => Some(event.point),
|
||||||
InputEvent::Wheel(event) => Some(event.point),
|
InputEvent::Wheel(event) => Some(event.point),
|
||||||
InputEvent::Scroll(..) => None,
|
InputEvent::Scroll(..) => None,
|
||||||
|
@ -56,6 +58,7 @@ impl InputEvent {
|
||||||
InputEvent::Keyboard(event) => event.webdriver_id,
|
InputEvent::Keyboard(event) => event.webdriver_id,
|
||||||
InputEvent::MouseButton(event) => event.webdriver_id,
|
InputEvent::MouseButton(event) => event.webdriver_id,
|
||||||
InputEvent::MouseMove(event) => event.webdriver_id,
|
InputEvent::MouseMove(event) => event.webdriver_id,
|
||||||
|
InputEvent::MouseLeave(..) => None,
|
||||||
InputEvent::Touch(..) => None,
|
InputEvent::Touch(..) => None,
|
||||||
InputEvent::Wheel(event) => event.webdriver_id,
|
InputEvent::Wheel(event) => event.webdriver_id,
|
||||||
InputEvent::Scroll(..) => None,
|
InputEvent::Scroll(..) => None,
|
||||||
|
@ -76,6 +79,7 @@ impl InputEvent {
|
||||||
InputEvent::MouseMove(ref mut event) => {
|
InputEvent::MouseMove(ref mut event) => {
|
||||||
event.webdriver_id = webdriver_id;
|
event.webdriver_id = webdriver_id;
|
||||||
},
|
},
|
||||||
|
InputEvent::MouseLeave(..) => {},
|
||||||
InputEvent::Touch(..) => {},
|
InputEvent::Touch(..) => {},
|
||||||
InputEvent::Wheel(ref mut event) => {
|
InputEvent::Wheel(ref mut event) => {
|
||||||
event.webdriver_id = webdriver_id;
|
event.webdriver_id = webdriver_id;
|
||||||
|
@ -214,6 +218,17 @@ impl MouseMoveEvent {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
|
||||||
|
pub struct MouseLeaveEvent {
|
||||||
|
pub point: DevicePoint,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MouseLeaveEvent {
|
||||||
|
pub fn new(point: DevicePoint) -> Self {
|
||||||
|
Self { point }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// The type of input represented by a multi-touch event.
|
/// The type of input represented by a multi-touch event.
|
||||||
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
|
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
|
||||||
pub enum TouchEventType {
|
pub enum TouchEventType {
|
||||||
|
|
|
@ -20,9 +20,10 @@ use servo::webrender_api::ScrollLocation;
|
||||||
use servo::webrender_api::units::{DeviceIntPoint, DeviceIntSize, DevicePixel};
|
use servo::webrender_api::units::{DeviceIntPoint, DeviceIntSize, DevicePixel};
|
||||||
use servo::{
|
use servo::{
|
||||||
Cursor, ImeEvent, InputEvent, Key, KeyState, KeyboardEvent, MouseButton as ServoMouseButton,
|
Cursor, ImeEvent, InputEvent, Key, KeyState, KeyboardEvent, MouseButton as ServoMouseButton,
|
||||||
MouseButtonAction, MouseButtonEvent, MouseMoveEvent, OffscreenRenderingContext,
|
MouseButtonAction, MouseButtonEvent, MouseLeaveEvent, MouseMoveEvent,
|
||||||
RenderingContext, ScreenGeometry, Theme, TouchEvent, TouchEventType, TouchId,
|
OffscreenRenderingContext, RenderingContext, ScreenGeometry, Theme, TouchEvent, TouchEventType,
|
||||||
WebRenderDebugOption, WebView, WheelDelta, WheelEvent, WheelMode, WindowRenderingContext,
|
TouchId, WebRenderDebugOption, WebView, WheelDelta, WheelEvent, WheelMode,
|
||||||
|
WindowRenderingContext,
|
||||||
};
|
};
|
||||||
use surfman::{Context, Device};
|
use surfman::{Context, Device};
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
@ -570,8 +571,22 @@ impl WindowPortsMethods for Window {
|
||||||
let mut point = winit_position_to_euclid_point(position).to_f32();
|
let mut point = winit_position_to_euclid_point(position).to_f32();
|
||||||
point.y -= (self.toolbar_height() * self.hidpi_scale_factor()).0;
|
point.y -= (self.toolbar_height() * self.hidpi_scale_factor()).0;
|
||||||
|
|
||||||
|
let previous_point = self.webview_relative_mouse_point.get();
|
||||||
|
if webview.rect().contains(point) {
|
||||||
|
webview.notify_input_event(InputEvent::MouseMove(MouseMoveEvent::new(point)));
|
||||||
|
} else if webview.rect().contains(previous_point) {
|
||||||
|
webview.notify_input_event(InputEvent::MouseLeave(MouseLeaveEvent::new(
|
||||||
|
previous_point,
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
self.webview_relative_mouse_point.set(point);
|
self.webview_relative_mouse_point.set(point);
|
||||||
webview.notify_input_event(InputEvent::MouseMove(MouseMoveEvent::new(point)));
|
},
|
||||||
|
WindowEvent::CursorLeft { .. } => {
|
||||||
|
let point = self.webview_relative_mouse_point.get();
|
||||||
|
if webview.rect().contains(point) {
|
||||||
|
webview.notify_input_event(InputEvent::MouseLeave(MouseLeaveEvent::new(point)));
|
||||||
|
}
|
||||||
},
|
},
|
||||||
WindowEvent::MouseWheel { delta, phase, .. } => {
|
WindowEvent::MouseWheel { delta, phase, .. } => {
|
||||||
let (mut dx, mut dy, mode) = match delta {
|
let (mut dx, mut dy, mode) = match delta {
|
||||||
|
@ -592,8 +607,7 @@ impl WindowPortsMethods for Window {
|
||||||
z: 0.0,
|
z: 0.0,
|
||||||
mode,
|
mode,
|
||||||
};
|
};
|
||||||
let pos = self.webview_relative_mouse_point.get();
|
let point = self.webview_relative_mouse_point.get();
|
||||||
let point = Point2D::new(pos.x, pos.y);
|
|
||||||
|
|
||||||
// Scroll events snap to the major axis of movement, with vertical
|
// Scroll events snap to the major axis of movement, with vertical
|
||||||
// preferred over horizontal.
|
// preferred over horizontal.
|
||||||
|
@ -608,11 +622,7 @@ impl WindowPortsMethods for Window {
|
||||||
|
|
||||||
// Send events
|
// Send events
|
||||||
webview.notify_input_event(InputEvent::Wheel(WheelEvent::new(delta, point)));
|
webview.notify_input_event(InputEvent::Wheel(WheelEvent::new(delta, point)));
|
||||||
webview.notify_scroll_event(
|
webview.notify_scroll_event(scroll_location, point.to_i32(), phase);
|
||||||
scroll_location,
|
|
||||||
self.webview_relative_mouse_point.get().to_i32(),
|
|
||||||
phase,
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
WindowEvent::Touch(touch) => {
|
WindowEvent::Touch(touch) => {
|
||||||
webview.notify_input_event(InputEvent::Touch(TouchEvent::new(
|
webview.notify_input_event(InputEvent::Touch(TouchEvent::new(
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue