diff --git a/components/compositing/compositor.rs b/components/compositing/compositor.rs index 9d9c917672e..814b620c6d6 100644 --- a/components/compositing/compositor.rs +++ b/components/compositing/compositor.rs @@ -20,7 +20,10 @@ use compositing_traits::{ CompositionPipeline, CompositorMsg, CompositorReceiver, ConstellationMsg, SendableFrameTree, }; use crossbeam_channel::Sender; -use embedder_traits::{Cursor, MouseButton, MouseEventType, TouchEventType, TouchId, WheelDelta}; +use embedder_traits::{ + Cursor, InputEvent, MouseButton, MouseButtonAction, MouseButtonEvent, MouseMoveEvent, + TouchEvent, TouchEventAction, TouchId, +}; use euclid::{Point2D, Rect, Scale, Transform3D, Vector2D}; use fnv::{FnvHashMap, FnvHashSet}; use image::{DynamicImage, ImageFormat}; @@ -30,7 +33,6 @@ use log::{debug, error, info, trace, warn}; use pixels::{CorsStatus, Image, PixelFormat}; use profile_traits::time::{self as profile_time, ProfilerCategory}; use profile_traits::time_profile; -use script_traits::CompositorEvent::{MouseButtonEvent, MouseMoveEvent, TouchEvent, WheelEvent}; use script_traits::{ AnimationState, AnimationTickType, ScriptThreadMessage, ScrollState, WindowSizeData, WindowSizeType, @@ -58,9 +60,7 @@ use webrender_traits::{ use crate::gl::RenderTargetInfo; use crate::touch::{TouchAction, TouchHandler}; use crate::webview::{UnknownWebView, WebView, WebViewAlreadyExists, WebViewManager}; -use crate::windowing::{ - self, EmbedderCoordinates, MouseWindowEvent, WebRenderDebugOption, WindowMethods, -}; +use crate::windowing::{self, EmbedderCoordinates, WebRenderDebugOption, WindowMethods}; use crate::{gl, InitialCompositorState}; #[derive(Debug, PartialEq)] @@ -430,7 +430,7 @@ impl IOCompositor { self.webviews_waiting_on_present.iter() } - fn update_cursor(&mut self, result: CompositorHitTestResult) { + fn update_cursor(&mut self, result: &CompositorHitTestResult) { let cursor = match result.cursor { Some(cursor) if cursor != self.cursor => cursor, _ => return, @@ -566,7 +566,7 @@ impl IOCompositor { if recomposite_needed { if let Some(result) = self.hit_test_at_point(self.cursor_pos) { - self.update_cursor(result); + self.update_cursor(&result); } } @@ -584,20 +584,20 @@ impl IOCompositor { } }, - CompositorMsg::WebDriverMouseButtonEvent(mouse_event_type, mouse_button, x, y) => { + CompositorMsg::WebDriverMouseButtonEvent(action, button, x, y) => { let dppx = self.device_pixels_per_page_pixel(); let point = dppx.transform_point(Point2D::new(x, y)); - self.on_mouse_window_event_class(match mouse_event_type { - MouseEventType::Click => MouseWindowEvent::Click(mouse_button, point), - MouseEventType::MouseDown => MouseWindowEvent::MouseDown(mouse_button, point), - MouseEventType::MouseUp => MouseWindowEvent::MouseUp(mouse_button, point), - }); + self.dispatch_input_event(InputEvent::MouseButton(MouseButtonEvent { + point, + action, + button, + })); }, CompositorMsg::WebDriverMouseMoveEvent(x, y) => { let dppx = self.device_pixels_per_page_pixel(); let point = dppx.transform_point(Point2D::new(x, y)); - self.on_mouse_window_move_event_class(DevicePoint::new(point.x, point.y)); + self.dispatch_input_event(InputEvent::MouseMove(MouseMoveEvent { point })); }, CompositorMsg::PendingPaintMetric(pipeline_id, epoch) => { @@ -1326,55 +1326,52 @@ impl IOCompositor { true } - pub fn on_mouse_window_event_class(&mut self, mouse_window_event: MouseWindowEvent) { + fn dispatch_input_event(&mut self, event: InputEvent) { + // Events that do not need to do hit testing are sent directly to the + // constellation to filter down. + let Some(point) = event.point() else { + return; + }; + + // If we can't find a pipeline to send this event to, we cannot continue. + let Some(result) = self.hit_test_at_point(point) else { + return; + }; + + self.update_cursor(&result); + + if let Err(error) = self + .constellation_chan + .send(ConstellationMsg::ForwardInputEvent(event, Some(result))) + { + warn!("Sending event to constellation failed ({error:?})."); + } + } + + pub fn on_input_event(&mut self, event: InputEvent) { if self.shutdown_state != ShutdownState::NotShuttingDown { return; } if self.convert_mouse_to_touch { - match mouse_window_event { - MouseWindowEvent::Click(_, _) => {}, - MouseWindowEvent::MouseDown(_, p) => self.on_touch_down(TouchId(0), p), - MouseWindowEvent::MouseUp(_, p) => self.on_touch_up(TouchId(0), p), + match event { + 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), + } + return; + }, + InputEvent::MouseMove(event) => { + self.on_touch_move(TouchId(0), event.point); + return; + }, + _ => {}, } - return; } - self.dispatch_mouse_window_event_class(mouse_window_event); - } - - fn dispatch_mouse_window_event_class(&mut self, mouse_window_event: MouseWindowEvent) { - let point = match mouse_window_event { - MouseWindowEvent::Click(_, p) => p, - MouseWindowEvent::MouseDown(_, p) => p, - MouseWindowEvent::MouseUp(_, p) => p, - }; - - let Some(result) = self.hit_test_at_point(point) else { - // TODO: Notify embedder that the event failed to hit test to any webview. - // TODO: Also notify embedder if an event hits a webview but isn’t consumed? - return; - }; - - let (button, event_type) = match mouse_window_event { - MouseWindowEvent::Click(button, _) => (button, MouseEventType::Click), - MouseWindowEvent::MouseDown(button, _) => (button, MouseEventType::MouseDown), - MouseWindowEvent::MouseUp(button, _) => (button, MouseEventType::MouseUp), - }; - - let event_to_send = MouseButtonEvent( - event_type, - button, - result.point_in_viewport.to_untyped(), - Some(result.node.into()), - Some(result.point_relative_to_item), - button as u16, - ); - - let msg = ConstellationMsg::ForwardEvent(result.pipeline_id, event_to_send); - if let Err(e) = self.constellation_chan.send(msg) { - warn!("Sending event to constellation failed ({:?}).", e); - } + self.dispatch_input_event(event); } fn hit_test_at_point(&self, point: DevicePoint) -> Option { @@ -1426,89 +1423,44 @@ impl IOCompositor { .collect() } - pub fn on_mouse_window_move_event_class(&mut self, cursor: DevicePoint) { - if self.shutdown_state != ShutdownState::NotShuttingDown { + fn send_touch_event(&self, event: TouchEvent) { + let Some(result) = self.hit_test_at_point(event.point) else { return; - } - - if self.convert_mouse_to_touch { - self.on_touch_move(TouchId(0), cursor); - return; - } - - self.dispatch_mouse_window_move_event_class(cursor); - } - - fn dispatch_mouse_window_move_event_class(&mut self, cursor: DevicePoint) { - let result = match self.hit_test_at_point(cursor) { - Some(result) => result, - None => return, }; - self.cursor_pos = cursor; - let event = MouseMoveEvent(result.point_in_viewport, Some(result.node.into()), 0); - let msg = ConstellationMsg::ForwardEvent(result.pipeline_id, event); - if let Err(e) = self.constellation_chan.send(msg) { + let event = InputEvent::Touch(event); + if let Err(e) = self + .constellation_chan + .send(ConstellationMsg::ForwardInputEvent(event, Some(result))) + { warn!("Sending event to constellation failed ({:?}).", e); } - self.update_cursor(result); } - fn send_touch_event( - &self, - event_type: TouchEventType, - identifier: TouchId, - point: DevicePoint, - ) { - if let Some(result) = self.hit_test_at_point(point) { - let event = TouchEvent( - event_type, - identifier, - result.point_in_viewport, - Some(result.node.into()), - ); - let msg = ConstellationMsg::ForwardEvent(result.pipeline_id, event); - if let Err(e) = self.constellation_chan.send(msg) { - warn!("Sending event to constellation failed ({:?}).", e); - } - } - } - - pub fn send_wheel_event(&mut self, delta: WheelDelta, point: DevicePoint) { - if let Some(result) = self.hit_test_at_point(point) { - let event = WheelEvent(delta, result.point_in_viewport, Some(result.node.into())); - let msg = ConstellationMsg::ForwardEvent(result.pipeline_id, event); - if let Err(e) = self.constellation_chan.send(msg) { - warn!("Sending event to constellation failed ({:?}).", e); - } - } - } - - pub fn on_touch_event( - &mut self, - event_type: TouchEventType, - identifier: TouchId, - location: DevicePoint, - ) { + pub fn on_touch_event(&mut self, event: TouchEvent) { if self.shutdown_state != ShutdownState::NotShuttingDown { return; } - match event_type { - TouchEventType::Down => self.on_touch_down(identifier, location), - TouchEventType::Move => self.on_touch_move(identifier, location), - TouchEventType::Up => self.on_touch_up(identifier, location), - TouchEventType::Cancel => self.on_touch_cancel(identifier, location), + 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), } } - fn on_touch_down(&mut self, identifier: TouchId, point: DevicePoint) { - self.touch_handler.on_touch_down(identifier, point); - self.send_touch_event(TouchEventType::Down, identifier, point); + 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_move(&mut self, identifier: TouchId, point: DevicePoint) { - match self.touch_handler.on_touch_move(identifier, point) { + 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(), @@ -1530,60 +1482,74 @@ impl IOCompositor { event_count: 1, })); }, - TouchAction::DispatchEvent => { - self.send_touch_event(TouchEventType::Move, identifier, point); - }, + TouchAction::DispatchEvent => self.send_touch_event(TouchEvent { + action: TouchEventAction::Move, + id, + point, + }), _ => {}, } } - fn on_touch_up(&mut self, identifier: TouchId, point: DevicePoint) { - self.send_touch_event(TouchEventType::Up, identifier, point); + 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(identifier, point) { + if let TouchAction::Click = self.touch_handler.on_touch_up(id, point) { self.simulate_mouse_click(point); } } - fn on_touch_cancel(&mut self, identifier: TouchId, point: DevicePoint) { + fn on_touch_cancel(&mut self, id: TouchId, point: DevicePoint) { // Send the event to script. - self.touch_handler.on_touch_cancel(identifier, point); - self.send_touch_event(TouchEventType::Cancel, identifier, point); + self.touch_handler.on_touch_cancel(id, point); + self.send_touch_event(TouchEvent { + action: TouchEventAction::Cancel, + id, + point, + }) } /// - fn simulate_mouse_click(&mut self, p: DevicePoint) { + fn simulate_mouse_click(&mut self, point: DevicePoint) { let button = MouseButton::Left; - self.dispatch_mouse_window_move_event_class(p); - self.dispatch_mouse_window_event_class(MouseWindowEvent::MouseDown(button, p)); - self.dispatch_mouse_window_event_class(MouseWindowEvent::MouseUp(button, p)); - self.dispatch_mouse_window_event_class(MouseWindowEvent::Click(button, p)); - } - - pub fn on_wheel_event(&mut self, delta: WheelDelta, p: DevicePoint) { - if self.shutdown_state != ShutdownState::NotShuttingDown { - return; - } - - self.send_wheel_event(delta, p); + self.dispatch_input_event(InputEvent::MouseMove(MouseMoveEvent { point })); + self.dispatch_input_event(InputEvent::MouseButton(MouseButtonEvent { + button, + action: MouseButtonAction::Down, + point, + })); + self.dispatch_input_event(InputEvent::MouseButton(MouseButtonEvent { + button, + action: MouseButtonAction::Up, + point, + })); + self.dispatch_input_event(InputEvent::MouseButton(MouseButtonEvent { + button, + action: MouseButtonAction::Click, + point, + })); } pub fn on_scroll_event( &mut self, scroll_location: ScrollLocation, cursor: DeviceIntPoint, - phase: TouchEventType, + action: TouchEventAction, ) { if self.shutdown_state != ShutdownState::NotShuttingDown { return; } - match phase { - TouchEventType::Move => self.on_scroll_window_event(scroll_location, cursor), - TouchEventType::Up | TouchEventType::Cancel => { + match action { + TouchEventAction::Move => self.on_scroll_window_event(scroll_location, cursor), + TouchEventAction::Up | TouchEventAction::Cancel => { self.on_scroll_window_event(scroll_location, cursor); }, - TouchEventType::Down => { + TouchEventAction::Down => { self.on_scroll_window_event(scroll_location, cursor); }, } diff --git a/components/constellation/constellation.rs b/components/constellation/constellation.rs index ed782036d3f..2715534d098 100644 --- a/components/constellation/constellation.rs +++ b/components/constellation/constellation.rs @@ -115,10 +115,12 @@ use devtools_traits::{ ChromeToDevtoolsControlMsg, DevtoolsControlMsg, DevtoolsPageInfo, NavigationState, ScriptToDevtoolsControlMsg, }; +use embedder_traits::input_events::MouseButtonAction; use embedder_traits::resources::{self, Resource}; use embedder_traits::{ - ClipboardEventType, Cursor, EmbedderMsg, EmbedderProxy, GamepadEvent, MediaSessionActionType, - MediaSessionEvent, MediaSessionPlaybackState, MouseEventType, Theme, TraversalDirection, + Cursor, EmbedderMsg, EmbedderProxy, ImeEvent, InputEvent, MediaSessionActionType, + MediaSessionEvent, MediaSessionPlaybackState, MouseButton, MouseButtonEvent, Theme, + TraversalDirection, }; use euclid::default::Size2D as UntypedSize2D; use euclid::Size2D; @@ -127,7 +129,6 @@ use ipc_channel::ipc::{self, IpcReceiver, IpcSender}; use ipc_channel::router::ROUTER; use ipc_channel::Error as IpcError; use keyboard_types::webdriver::Event as WebDriverInputEvent; -use keyboard_types::{CompositionEvent, KeyboardEvent}; use log::{debug, error, info, trace, warn}; use media::{GLPlayerThreads, WindowGLContext}; use net_traits::pub_domains::reg_host; @@ -136,10 +137,9 @@ use net_traits::storage_thread::{StorageThreadMsg, StorageType}; use net_traits::{self, IpcSend, ReferrerPolicy, ResourceThreads}; use profile_traits::{mem, time}; use script_layout_interface::{LayoutFactory, ScriptThreadFactory}; -use script_traits::CompositorEvent::{MouseButtonEvent, MouseMoveEvent}; use script_traits::{ webdriver_msg, AnimationState, AnimationTickType, AuxiliaryBrowsingContextLoadInfo, - BroadcastMsg, CompositorEvent, DiscardBrowsingContext, DocumentActivity, DocumentState, + BroadcastMsg, ConstellationInputEvent, DiscardBrowsingContext, DocumentActivity, DocumentState, IFrameLoadInfo, IFrameLoadInfoWithData, IFrameSandboxState, IFrameSizeMsg, Job, LayoutMsg as FromLayoutMsg, LoadData, LoadOrigin, LogEntry, MessagePortMsg, NavigationHistoryBehavior, PortMessageTask, SWManagerMsg, SWManagerSenders, @@ -160,7 +160,7 @@ use webgpu::{self, WebGPU, WebGPURequest, WebGPUResponse}; use webrender::RenderApi; use webrender::RenderApiSender; use webrender_api::DocumentId; -use webrender_traits::WebrenderExternalImageRegistry; +use webrender_traits::{CompositorHitTestResult, WebrenderExternalImageRegistry}; use crate::browsingcontext::{ AllBrowsingContextsIterator, BrowsingContext, FullyActiveBrowsingContextsIterator, @@ -1271,15 +1271,6 @@ where FromCompositorMsg::GetFocusTopLevelBrowsingContext(resp_chan) => { let _ = resp_chan.send(self.webviews.focused_webview().map(|(id, _)| id)); }, - FromCompositorMsg::Keyboard(webview_id, key_event) => { - self.handle_key_msg(webview_id, key_event); - }, - FromCompositorMsg::IMECompositionEvent(ime_event) => { - self.handle_ime_msg(ime_event); - }, - FromCompositorMsg::IMEDismissed => { - self.handle_ime_dismissed(); - }, // Perform a navigation previously requested by script, if approved by the embedder. // If there is already a pending page (self.pending_changes), it will not be overridden; // However, if the id is not encompassed by another change, it will be. @@ -1435,8 +1426,8 @@ where FromCompositorMsg::LogEntry(top_level_browsing_context_id, thread_name, entry) => { self.handle_log_entry(top_level_browsing_context_id, thread_name, entry); }, - FromCompositorMsg::ForwardEvent(destination_pipeline_id, event) => { - self.forward_event(destination_pipeline_id, event); + FromCompositorMsg::ForwardInputEvent(event, hit_test) => { + self.forward_input_event(event, hit_test); }, FromCompositorMsg::SetCursor(webview_id, cursor) => { self.handle_set_cursor_msg(webview_id, cursor) @@ -1459,12 +1450,6 @@ where FromCompositorMsg::SetWebViewThrottled(webview_id, throttled) => { self.set_webview_throttled(webview_id, throttled); }, - FromCompositorMsg::Gamepad(gamepad_event) => { - self.handle_gamepad_msg(gamepad_event); - }, - FromCompositorMsg::Clipboard(clipboard_event) => { - self.handle_clipboard_msg(clipboard_event); - }, } } @@ -2893,57 +2878,91 @@ where } } - fn forward_event(&mut self, destination_pipeline_id: PipelineId, event: CompositorEvent) { - if let MouseButtonEvent(event_type, button, ..) = &event { - match event_type { - MouseEventType::MouseDown | MouseEventType::Click => { - self.pressed_mouse_buttons |= *button as u16; - }, - MouseEventType::MouseUp => { - self.pressed_mouse_buttons &= !(*button as u16); - }, + fn update_pressed_mouse_buttons(&mut self, event: &MouseButtonEvent) { + // This value is ultimately used for a DOM mouse event, and the specification says that + // the pressed buttons should be represented as a bitmask with values defined at + // . + let button_as_bitmask = match event.button { + MouseButton::Left => 1, + MouseButton::Right => 2, + MouseButton::Middle => 4, + MouseButton::Back => 8, + MouseButton::Forward => 16, + MouseButton::Other(_) => return, + }; + + match event.action { + MouseButtonAction::Click | MouseButtonAction::Down => { + self.pressed_mouse_buttons |= button_as_bitmask; + }, + MouseButtonAction::Up => { + self.pressed_mouse_buttons &= !(button_as_bitmask); + }, + } + } + + fn forward_input_event( + &mut self, + event: InputEvent, + hit_test_result: Option, + ) { + if let InputEvent::MouseButton(event) = &event { + self.update_pressed_mouse_buttons(event); + } + + // The constellation tracks the state of pressed mouse buttons and updates the event + // here to reflect the current state. + let pressed_mouse_buttons = self.pressed_mouse_buttons; + + // TODO: Click should be handled internally in the `Document`. + if let InputEvent::MouseButton(event) = &event { + if event.action == MouseButtonAction::Click { + self.pressed_mouse_buttons = 0; } } - let event = match event { - MouseButtonEvent(event_type, button, point, node_address, point_in_node, _) => { - MouseButtonEvent( - event_type, - button, - point, - node_address, - point_in_node, - self.pressed_mouse_buttons, - ) - }, - MouseMoveEvent(point, node_address, _) => { - MouseMoveEvent(point, node_address, self.pressed_mouse_buttons) - }, - _ => event, - }; - - if let MouseButtonEvent(MouseEventType::Click, ..) = event { - self.pressed_mouse_buttons = 0; - } - - let pipeline = match self.pipelines.get(&destination_pipeline_id) { + let pipeline_id = match &hit_test_result { + Some(hit_test) => hit_test.pipeline_id, None => { - debug!("{}: Got event after closure", destination_pipeline_id); - return; + // If there's no hit test, send to the currently focused WebView. + let Some(browsing_context_id) = self + .webviews + .focused_webview() + .map(|(_, webview)| webview.focused_browsing_context_id) + else { + warn!("Handling InputEvent with no focused WebView"); + return; + }; + + let Some(pipeline_id) = self + .browsing_contexts + .get(&browsing_context_id) + .map(|context| context.pipeline_id) + else { + warn!("{browsing_context_id}: Got InputEvent for nonexistent browsing context"); + return; + }; + + pipeline_id }, - Some(pipeline) => pipeline, }; - self.embedder_proxy.send(EmbedderMsg::EventDelivered( - pipeline.top_level_browsing_context_id, - (&event).into(), - )); + let Some(pipeline) = self.pipelines.get(&pipeline_id) else { + debug!("Got event for pipeline ({pipeline_id}) after closure"); + return; + }; - if let Err(e) = pipeline.event_loop.send(ScriptThreadMessage::SendEvent( - destination_pipeline_id, + let event = ConstellationInputEvent { + hit_test_result, + pressed_mouse_buttons, event, - )) { - self.handle_send_error(destination_pipeline_id, e); + }; + + if let Err(error) = pipeline + .event_loop + .send(ScriptThreadMessage::SendInputEvent(pipeline_id, event)) + { + self.handle_send_error(pipeline_id, error); } } @@ -4124,144 +4143,6 @@ where session_history.replace_history_state(pipeline_id, history_state_id, url); } - #[cfg_attr( - feature = "tracing", - tracing::instrument(skip_all, fields(servo_profiling = true), level = "trace") - )] - fn handle_ime_dismissed(&mut self) { - // Send to the focused browsing contexts' current pipeline. - let focused_browsing_context_id = self - .webviews - .focused_webview() - .map(|(_, webview)| webview.focused_browsing_context_id); - if let Some(browsing_context_id) = focused_browsing_context_id { - let pipeline_id = match self.browsing_contexts.get(&browsing_context_id) { - Some(ctx) => ctx.pipeline_id, - None => { - return warn!( - "{}: Got IME dismissed event for nonexistent browsing context", - browsing_context_id, - ); - }, - }; - let msg = - ScriptThreadMessage::SendEvent(pipeline_id, CompositorEvent::IMEDismissedEvent); - let result = match self.pipelines.get(&pipeline_id) { - Some(pipeline) => pipeline.event_loop.send(msg), - None => { - return debug!("{}: Got IME dismissed event after closure", pipeline_id); - }, - }; - if let Err(e) = result { - self.handle_send_error(pipeline_id, e); - } - } - } - - #[cfg_attr( - feature = "tracing", - tracing::instrument(skip_all, fields(servo_profiling = true), level = "trace") - )] - fn handle_ime_msg(&mut self, event: CompositionEvent) { - // Send to the focused browsing contexts' current pipeline. - let Some(focused_browsing_context_id) = self - .webviews - .focused_webview() - .map(|(_, webview)| webview.focused_browsing_context_id) - else { - warn!("No focused browsing context! Dropping IME event {event:?}"); - return; - }; - let event = CompositorEvent::CompositionEvent(event); - let pipeline_id = match self.browsing_contexts.get(&focused_browsing_context_id) { - Some(ctx) => ctx.pipeline_id, - None => { - return warn!( - "{}: Got composition event for nonexistent browsing context", - focused_browsing_context_id, - ); - }, - }; - let msg = ScriptThreadMessage::SendEvent(pipeline_id, event); - let result = match self.pipelines.get(&pipeline_id) { - Some(pipeline) => pipeline.event_loop.send(msg), - None => { - return debug!("{}: Got composition event after closure", pipeline_id); - }, - }; - if let Err(e) = result { - self.handle_send_error(pipeline_id, e); - } - } - - #[cfg_attr( - feature = "tracing", - tracing::instrument(skip_all, fields(servo_profiling = true)) - )] - fn handle_key_msg(&mut self, webview_id: WebViewId, event: KeyboardEvent) { - // Send to the focused browsing contexts' current pipeline. If it - // doesn't exist, fall back to sending to the compositor. - let Some(webview) = self.webviews.get(webview_id) else { - warn!("Handling keyboard event for unknown webview: {webview_id}"); - return; - }; - let browsing_context_id = webview.focused_browsing_context_id; - let event = CompositorEvent::KeyboardEvent(event); - let pipeline_id = match self.browsing_contexts.get(&browsing_context_id) { - Some(ctx) => ctx.pipeline_id, - None => { - return warn!( - "{}: Got key event for nonexistent browsing context", - browsing_context_id, - ); - }, - }; - let msg = ScriptThreadMessage::SendEvent(pipeline_id, event); - let result = match self.pipelines.get(&pipeline_id) { - Some(pipeline) => pipeline.event_loop.send(msg), - None => { - return debug!("{}: Got key event after closure", pipeline_id); - }, - }; - if let Err(e) = result { - self.handle_send_error(pipeline_id, e); - } - } - - #[cfg_attr( - feature = "tracing", - tracing::instrument(skip_all, fields(servo_profiling = true)) - )] - fn handle_clipboard_msg(&mut self, event: ClipboardEventType) { - let focused_browsing_context_id = self - .webviews - .focused_webview() - .map(|(_, webview)| webview.focused_browsing_context_id); - - if let Some(browsing_context_id) = focused_browsing_context_id { - let event = CompositorEvent::ClipboardEvent(event); - let pipeline_id = match self.browsing_contexts.get(&browsing_context_id) { - Some(ctx) => ctx.pipeline_id, - None => { - return warn!( - "{}: Got clipboard event for nonexistent browsing context", - browsing_context_id, - ); - }, - }; - let msg = ScriptThreadMessage::SendEvent(pipeline_id, event); - let result = match self.pipelines.get(&pipeline_id) { - Some(pipeline) => pipeline.event_loop.send(msg), - None => { - return debug!("{}: Got clipboard event after closure", pipeline_id); - }, - }; - if let Err(e) = result { - self.handle_send_error(pipeline_id, e); - } - } - } - #[cfg_attr( feature = "tracing", tracing::instrument(skip_all, fields(servo_profiling = true), level = "trace") @@ -4624,14 +4505,18 @@ where }; for event in cmd { let event = match event { - WebDriverInputEvent::Keyboard(event) => { - CompositorEvent::KeyboardEvent(event) + WebDriverInputEvent::Keyboard(event) => ConstellationInputEvent { + pressed_mouse_buttons: self.pressed_mouse_buttons, + hit_test_result: None, + event: InputEvent::Keyboard(event), }, - WebDriverInputEvent::Composition(event) => { - CompositorEvent::CompositionEvent(event) + WebDriverInputEvent::Composition(event) => ConstellationInputEvent { + pressed_mouse_buttons: self.pressed_mouse_buttons, + hit_test_result: None, + event: InputEvent::Ime(ImeEvent::Composition(event)), }, }; - let control_msg = ScriptThreadMessage::SendEvent(pipeline_id, event); + let control_msg = ScriptThreadMessage::SendInputEvent(pipeline_id, event); if let Err(e) = event_loop.send(control_msg) { return self.handle_send_error(pipeline_id, e); } @@ -4648,9 +4533,13 @@ where Some(pipeline) => pipeline.event_loop.clone(), None => return warn!("{}: KeyboardAction after closure", pipeline_id), }; - let control_msg = ScriptThreadMessage::SendEvent( + let control_msg = ScriptThreadMessage::SendInputEvent( pipeline_id, - CompositorEvent::KeyboardEvent(event), + ConstellationInputEvent { + pressed_mouse_buttons: self.pressed_mouse_buttons, + hit_test_result: None, + event: InputEvent::Keyboard(event), + }, ); if let Err(e) = event_loop.send(control_msg) { self.handle_send_error(pipeline_id, e) @@ -5749,44 +5638,4 @@ where error!("Got a media session action but no active media session is registered"); } } - - /// Handle GamepadEvents from the embedder and forward them to the script thread - #[cfg_attr( - feature = "tracing", - tracing::instrument(skip_all, fields(servo_profiling = true), level = "trace") - )] - fn handle_gamepad_msg(&mut self, event: GamepadEvent) { - // Send to the focused browsing contexts' current pipeline. - let focused_browsing_context_id = self - .webviews - .focused_webview() - .map(|(_, webview)| webview.focused_browsing_context_id); - match focused_browsing_context_id { - Some(browsing_context_id) => { - let event = CompositorEvent::GamepadEvent(event); - let pipeline_id = match self.browsing_contexts.get(&browsing_context_id) { - Some(ctx) => ctx.pipeline_id, - None => { - return warn!( - "{}: Got gamepad event for nonexistent browsing context", - browsing_context_id, - ); - }, - }; - let msg = ScriptThreadMessage::SendEvent(pipeline_id, event); - let result = match self.pipelines.get(&pipeline_id) { - Some(pipeline) => pipeline.event_loop.send(msg), - None => { - return debug!("{}: Got gamepad event after closure", pipeline_id); - }, - }; - if let Err(e) = result { - self.handle_send_error(pipeline_id, e); - } - }, - None => { - warn!("No focused webview to handle gamepad event"); - }, - } - } } diff --git a/components/constellation/tracing.rs b/components/constellation/tracing.rs index 97896bef813..bccfdf17b90 100644 --- a/components/constellation/tracing.rs +++ b/components/constellation/tracing.rs @@ -47,6 +47,8 @@ pub(crate) trait LogTarget { } mod from_compositor { + use embedder_traits::InputEvent; + use super::LogTarget; macro_rules! target { @@ -65,8 +67,6 @@ mod from_compositor { target!("GetFocusTopLevelBrowsingContext") }, Self::IsReadyToSaveImage(..) => target!("IsReadyToSaveImage"), - Self::Keyboard(..) => target!("Keyboard"), - Self::IMECompositionEvent(..) => target!("IMECompositionEvent"), Self::AllowNavigationResponse(..) => target!("AllowNavigationResponse"), Self::LoadUrl(..) => target!("LoadUrl"), Self::ClearCache => target!("ClearCache"), @@ -83,37 +83,32 @@ mod from_compositor { Self::SendError(..) => target!("SendError"), Self::FocusWebView(..) => target!("FocusWebView"), Self::BlurWebView => target!("BlurWebView"), - Self::ForwardEvent(_, event) => event.log_target(), + Self::ForwardInputEvent(event, ..) => event.log_target(), Self::SetCursor(..) => target!("SetCursor"), Self::ToggleProfiler(..) => target!("EnableProfiler"), Self::ExitFullScreen(_) => target!("ExitFullScreen"), Self::MediaSessionAction(_) => target!("MediaSessionAction"), Self::SetWebViewThrottled(_, _) => target!("SetWebViewThrottled"), - Self::IMEDismissed => target!("IMEDismissed"), - Self::Gamepad(..) => target!("Gamepad"), - Self::Clipboard(..) => target!("Clipboard"), } } } - impl LogTarget for script_traits::CompositorEvent { + impl LogTarget for InputEvent { fn log_target(&self) -> &'static str { macro_rules! target_variant { ($name:literal) => { - target!("ForwardEvent(" $name ")") + target!("ForwardInputEvent(" $name ")") }; } match self { - Self::ResizeEvent(..) => target_variant!("ResizeEvent"), - Self::MouseButtonEvent(..) => target_variant!("MouseButtonEvent"), - Self::MouseMoveEvent(..) => target_variant!("MouseMoveEvent"), - Self::TouchEvent(..) => target_variant!("TouchEvent"), - Self::WheelEvent(..) => target_variant!("WheelEvent"), - Self::KeyboardEvent(..) => target_variant!("KeyboardEvent"), - Self::CompositionEvent(..) => target_variant!("CompositionEvent"), - Self::IMEDismissedEvent => target_variant!("IMEDismissedEvent"), - Self::GamepadEvent(..) => target_variant!("GamepadEvent"), - Self::ClipboardEvent(..) => target_variant!("ClipboardEvent"), + InputEvent::EditingAction(..) => target_variant!("EditingAction"), + InputEvent::Gamepad(..) => target_variant!("Gamepad"), + InputEvent::Ime(..) => target_variant!("Ime"), + InputEvent::Keyboard(..) => target_variant!("Keyboard"), + InputEvent::MouseButton(..) => target_variant!("MouseButton"), + InputEvent::MouseMove(..) => target_variant!("MouseMove"), + InputEvent::Touch(..) => target_variant!("Touch"), + InputEvent::Wheel(..) => target_variant!("Wheel"), } } } @@ -247,7 +242,6 @@ mod from_script { Self::MediaSessionEvent(..) => target_variant!("MediaSessionEvent"), Self::OnDevtoolsStarted(..) => target_variant!("OnDevtoolsStarted"), Self::RequestDevtoolsConnection(..) => target_variant!("RequestDevtoolsConnection"), - Self::EventDelivered(..) => target_variant!("EventDelivered"), Self::PlayGamepadHapticEffect(..) => target_variant!("PlayGamepadHapticEffect"), Self::StopGamepadHapticEffect(..) => target_variant!("StopGamepadHapticEffect"), } diff --git a/components/profile/time.rs b/components/profile/time.rs index 341f66124f6..73a48efa764 100644 --- a/components/profile/time.rs +++ b/components/profile/time.rs @@ -102,7 +102,6 @@ impl Formattable for ProfilerCategory { ProfilerCategory::ScriptConstellationMsg => "Script Constellation Msg", ProfilerCategory::ScriptDevtoolsMsg => "Script Devtools Msg", ProfilerCategory::ScriptDocumentEvent => "Script Document Event", - ProfilerCategory::ScriptDomEvent => "Script Dom Event", ProfilerCategory::ScriptEvaluate => "Script JS Evaluate", ProfilerCategory::ScriptFileRead => "Script File Read", ProfilerCategory::ScriptHistoryEvent => "Script History Event", diff --git a/components/script/dom/clipboardevent.rs b/components/script/dom/clipboardevent.rs index 768ea5394c9..eccf590e792 100644 --- a/components/script/dom/clipboardevent.rs +++ b/components/script/dom/clipboardevent.rs @@ -18,6 +18,28 @@ use crate::dom::event::{Event, EventBubbles, EventCancelable}; use crate::dom::window::Window; use crate::script_runtime::CanGc; +/// The types of clipboard events in the Clipboard APIs specification: +/// . +#[derive(Clone, Debug)] +pub(crate) enum ClipboardEventType { + Change, + Copy, + Cut, + Paste, +} + +impl ClipboardEventType { + /// Convert this [`ClipboardEventType`] to a `&str` for use in creating DOM events. + pub(crate) fn as_str(&self) -> &str { + match *self { + ClipboardEventType::Change => "clipboardchange", + ClipboardEventType::Copy => "copy", + ClipboardEventType::Cut => "cut", + ClipboardEventType::Paste => "paste", + } + } +} + #[dom_struct] pub struct ClipboardEvent { event: Event, diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index 029b8b8aa27..ff691ec52dc 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -25,8 +25,9 @@ use cssparser::match_ignore_ascii_case; use devtools_traits::ScriptToDevtoolsControlMsg; use dom_struct::dom_struct; use embedder_traits::{ - AllowOrDeny, ClipboardEventType, ContextMenuResult, EmbedderMsg, LoadStatus, MouseButton, - MouseEventType, TouchEventType, TouchId, WheelDelta, + AllowOrDeny, ContextMenuResult, EditingActionEvent, EmbedderMsg, ImeEvent, InputEvent, + LoadStatus, MouseButton, MouseButtonAction, MouseButtonEvent, TouchEvent, TouchEventAction, + TouchId, WheelEvent, }; use encoding_rs::{Encoding, UTF_8}; use euclid::default::{Point2D, Rect, Size2D}; @@ -53,8 +54,7 @@ use profile_traits::ipc as profile_ipc; use profile_traits::time::{TimerMetadata, TimerMetadataFrameType, TimerMetadataReflowType}; use script_layout_interface::{PendingRestyle, TrustedNodeAddress}; use script_traits::{ - AnimationState, AnimationTickType, CompositorEvent, DocumentActivity, ScriptMsg, - UntrustedNodeAddress, + AnimationState, AnimationTickType, ConstellationInputEvent, DocumentActivity, ScriptMsg, }; use servo_arc::Arc; use servo_atoms::Atom; @@ -74,8 +74,10 @@ use uuid::Uuid; #[cfg(feature = "webgpu")] use webgpu::swapchain::WebGPUContextId; use webrender_api::units::DeviceIntRect; +use webrender_traits::CompositorHitTestResult; use super::bindings::codegen::Bindings::XPathEvaluatorBinding::XPathEvaluatorMethods; +use super::clipboardevent::ClipboardEventType; use crate::animation_timeline::AnimationTimeline; use crate::animations::Animations; use crate::document_loader::{DocumentLoader, LoadType}; @@ -179,7 +181,7 @@ use crate::dom::storageevent::StorageEvent; use crate::dom::stylesheetlist::{StyleSheetList, StyleSheetListOwner}; use crate::dom::text::Text; use crate::dom::touch::Touch; -use crate::dom::touchevent::TouchEvent; +use crate::dom::touchevent::TouchEvent as DomTouchEvent; use crate::dom::touchlist::TouchList; use crate::dom::treewalker::TreeWalker; use crate::dom::types::VisibilityStateEntry; @@ -188,7 +190,7 @@ use crate::dom::virtualmethods::vtable_for; use crate::dom::webglrenderingcontext::WebGLRenderingContext; #[cfg(feature = "webgpu")] use crate::dom::webgpu::gpucanvascontext::GPUCanvasContext; -use crate::dom::wheelevent::WheelEvent; +use crate::dom::wheelevent::WheelEvent as DomWheelEvent; use crate::dom::window::Window; use crate::dom::windowproxy::WindowProxy; use crate::dom::xpathevaluator::XPathEvaluator; @@ -482,10 +484,10 @@ pub(crate) struct Document { dirty_root: MutNullableDom, /// declarative_refresh: DomRefCell>, - /// Pending composition events, to be handled at the next rendering opportunity. + /// Pending input events, to be handled at the next rendering opportunity. #[no_trace] #[ignore_malloc_size_of = "CompositorEvent contains data from outside crates"] - pending_compositor_events: DomRefCell>, + pending_input_events: DomRefCell>, /// The index of the last mouse move event in the pending compositor events queue. mouse_move_event_index: DomRefCell>, /// Pending animation ticks, to be handled at the next rendering opportunity. @@ -1267,39 +1269,41 @@ impl Document { } #[allow(unsafe_code)] - #[allow(clippy::too_many_arguments)] - pub(crate) unsafe fn handle_mouse_button_event( + pub(crate) fn handle_mouse_button_event( &self, - button: MouseButton, - client_point: Point2D, - mouse_event_type: MouseEventType, - node_address: Option, - point_in_node: Option>, + event: MouseButtonEvent, + hit_test_result: Option, pressed_mouse_buttons: u16, can_gc: CanGc, ) { - let mouse_event_type_string = match mouse_event_type { - MouseEventType::Click => "click".to_owned(), - MouseEventType::MouseUp => "mouseup".to_owned(), - MouseEventType::MouseDown => "mousedown".to_owned(), + // Ignore all incoming events without a hit test. + let Some(hit_test_result) = hit_test_result else { + return; }; - debug!("{}: at {:?}", mouse_event_type_string, client_point); - let el = node_address.and_then(|address| { - let node = node::from_untrusted_node_address(address); - node.inclusive_ancestors(ShadowIncluding::No) - .filter_map(DomRoot::downcast::) - .next() - }); - let el = match el { - Some(el) => el, - None => return, + let mouse_event_type_string = match event.action { + MouseButtonAction::Click => "click".to_owned(), + MouseButtonAction::Up => "mouseup".to_owned(), + MouseButtonAction::Down => "mousedown".to_owned(), + }; + debug!( + "{}: at {:?}", + mouse_event_type_string, hit_test_result.point_in_viewport + ); + + let node = unsafe { node::from_untrusted_compositor_node_address(hit_test_result.node) }; + let Some(el) = node + .inclusive_ancestors(ShadowIncluding::No) + .filter_map(DomRoot::downcast::) + .next() + else { + return; }; let node = el.upcast::(); debug!("{} on {:?}", mouse_event_type_string, node.debug_str()); // Prevent click event if form control element is disabled. - if let MouseEventType::Click = mouse_event_type { + if let MouseButtonAction::Click = event.action { // The click event is filtered by the disabled state. if el.is_actually_disabled() { return; @@ -1310,10 +1314,10 @@ impl Document { } // https://w3c.github.io/uievents/#event-type-click - let client_x = client_point.x as i32; - let client_y = client_point.y as i32; + let client_x = hit_test_result.point_in_viewport.x as i32; + let client_y = hit_test_result.point_in_viewport.y as i32; let click_count = 1; - let event = MouseEvent::new( + let dom_event = MouseEvent::new( &self.window, DOMString::from(mouse_event_type_string), EventBubbles::Bubbles, @@ -1328,58 +1332,59 @@ impl Document { false, false, false, - match &button { - MouseButton::Left => 0i16, - MouseButton::Middle => 1i16, - MouseButton::Right => 2i16, - }, + event.button.into(), pressed_mouse_buttons, None, - point_in_node, + Some(hit_test_result.point_relative_to_item), can_gc, ); - let event = event.upcast::(); + let dom_event = dom_event.upcast::(); // https://w3c.github.io/uievents/#trusted-events - event.set_trusted(true); + dom_event.set_trusted(true); // https://html.spec.whatwg.org/multipage/#run-authentic-click-activation-steps let activatable = el.as_maybe_activatable(); - match mouse_event_type { - MouseEventType::Click => { + match event.action { + MouseButtonAction::Click => { el.set_click_in_progress(true); - event.fire(node.upcast(), can_gc); + dom_event.fire(node.upcast(), can_gc); el.set_click_in_progress(false); }, - MouseEventType::MouseDown => { + MouseButtonAction::Down => { if let Some(a) = activatable { a.enter_formal_activation_state(); } let target = node.upcast(); - event.fire(target, can_gc); + dom_event.fire(target, can_gc); }, - MouseEventType::MouseUp => { + MouseButtonAction::Up => { if let Some(a) = activatable { a.exit_formal_activation_state(); } let target = node.upcast(); - event.fire(target, can_gc); + dom_event.fire(target, can_gc); }, } - if let MouseEventType::Click = mouse_event_type { + if let MouseButtonAction::Click = event.action { self.commit_focus_transaction(FocusType::Element, can_gc); - self.maybe_fire_dblclick(client_point, node, pressed_mouse_buttons, can_gc); + self.maybe_fire_dblclick( + hit_test_result.point_in_viewport, + node, + pressed_mouse_buttons, + can_gc, + ); } // When the contextmenu event is triggered by right mouse button // the contextmenu event MUST be dispatched after the mousedown event. - if let (MouseEventType::MouseDown, MouseButton::Right) = (mouse_event_type, button) { + if let (MouseButtonAction::Down, MouseButton::Right) = (event.action, event.button) { self.maybe_show_context_menu( node.upcast(), pressed_mouse_buttons, - client_point, + hit_test_result.point_in_viewport, can_gc, ); } @@ -1528,7 +1533,7 @@ impl Document { let client_x = client_point.x.to_i32().unwrap_or(0); let client_y = client_point.y.to_i32().unwrap_or(0); - let mouse_event = MouseEvent::new( + MouseEvent::new( &self.window, DOMString::from(event_name.as_str()), can_bubble, @@ -1548,17 +1553,22 @@ impl Document { None, None, can_gc, - ); - let event = mouse_event.upcast::(); - event.fire(target, can_gc); + ) + .upcast::() + .fire(target, can_gc); + } + + pub(crate) fn handle_editing_action(&self, action: EditingActionEvent, can_gc: CanGc) -> bool { + let clipboard_event = match action { + EditingActionEvent::Copy => ClipboardEventType::Copy, + EditingActionEvent::Cut => ClipboardEventType::Cut, + EditingActionEvent::Paste => ClipboardEventType::Paste, + }; + self.handle_clipboard_action(clipboard_event, can_gc) } /// - pub(crate) fn handle_clipboard_action( - &self, - action: ClipboardEventType, - can_gc: CanGc, - ) -> bool { + fn handle_clipboard_action(&self, action: ClipboardEventType, can_gc: CanGc) -> bool { // The script_triggered flag is set if the action runs because of a script, e.g. document.execCommand() let script_triggered = false; @@ -1762,28 +1772,29 @@ impl Document { #[allow(unsafe_code)] pub(crate) unsafe fn handle_mouse_move_event( &self, - client_point: Point2D, - prev_mouse_over_target: &MutNullableDom, - node_address: Option, + hit_test_result: Option, pressed_mouse_buttons: u16, + prev_mouse_over_target: &MutNullableDom, can_gc: CanGc, ) { - let maybe_new_target = node_address.and_then(|address| { - let node = node::from_untrusted_node_address(address); - node.inclusive_ancestors(ShadowIncluding::No) - .filter_map(DomRoot::downcast::) - .next() - }); + // Ignore all incoming events without a hit test. + let Some(hit_test_result) = hit_test_result else { + return; + }; - let new_target = match maybe_new_target { - Some(ref target) => target, - None => return, + let node = unsafe { node::from_untrusted_compositor_node_address(hit_test_result.node) }; + let Some(new_target) = node + .inclusive_ancestors(ShadowIncluding::No) + .filter_map(DomRoot::downcast::) + .next() + else { + return; }; let target_has_changed = prev_mouse_over_target .get() .as_ref() - .map_or(true, |old_target| old_target != new_target); + .map_or(true, |old_target| old_target != &new_target); // Here we know the target has changed, so we must update the state, // dispatch mouseout to the previous one, mouseover to the new one. @@ -1808,7 +1819,7 @@ impl Document { } self.fire_mouse_event( - client_point, + hit_test_result.point_in_viewport, old_target.upcast(), FireMouseEventType::Out, EventBubbles::Bubbles, @@ -1821,7 +1832,7 @@ impl Document { let event_target = DomRoot::from_ref(old_target.upcast::()); let moving_into = Some(DomRoot::from_ref(new_target.upcast::())); self.handle_mouse_enter_leave_event( - client_point, + hit_test_result.point_in_viewport, FireMouseEventType::Leave, moving_into, event_target, @@ -1844,7 +1855,7 @@ impl Document { } self.fire_mouse_event( - client_point, + hit_test_result.point_in_viewport, new_target.upcast(), FireMouseEventType::Over, EventBubbles::Bubbles, @@ -1858,7 +1869,7 @@ impl Document { .map(|old_target| DomRoot::from_ref(old_target.upcast::())); let event_target = DomRoot::from_ref(new_target.upcast::()); self.handle_mouse_enter_leave_event( - client_point, + hit_test_result.point_in_viewport, FireMouseEventType::Enter, moving_from, event_target, @@ -1870,7 +1881,7 @@ impl Document { // Send mousemove event to topmost target, unless it's an iframe, in which case the // compositor should have also sent an event to the inner document. self.fire_mouse_event( - client_point, + hit_test_result.point_in_viewport, new_target.upcast(), FireMouseEventType::Move, EventBubbles::Bubbles, @@ -1881,7 +1892,7 @@ impl Document { // If the target has changed then store the current mouse over target for next frame. if target_has_changed { - prev_mouse_over_target.set(maybe_new_target.as_deref()); + prev_mouse_over_target.set(Some(&new_target)); } } @@ -1938,89 +1949,93 @@ impl Document { } #[allow(unsafe_code)] - pub(crate) unsafe fn handle_wheel_event( + pub(crate) fn handle_wheel_event( &self, - delta: WheelDelta, - client_point: Point2D, - node_address: Option, + event: WheelEvent, + hit_test_result: Option, can_gc: CanGc, ) { - let wheel_event_type_string = "wheel".to_owned(); - debug!("{}: at {:?}", wheel_event_type_string, client_point); + // Ignore all incoming events without a hit test. + let Some(hit_test_result) = hit_test_result else { + return; + }; - let el = node_address.and_then(|address| { - let node = node::from_untrusted_node_address(address); - node.inclusive_ancestors(ShadowIncluding::No) - .filter_map(DomRoot::downcast::) - .next() - }); - - let el = match el { - Some(el) => el, - None => return, + let node = unsafe { node::from_untrusted_compositor_node_address(hit_test_result.node) }; + let Some(el) = node + .inclusive_ancestors(ShadowIncluding::No) + .filter_map(DomRoot::downcast::) + .next() + else { + return; }; let node = el.upcast::(); - debug!("{}: on {:?}", wheel_event_type_string, node.debug_str()); + let wheel_event_type_string = "wheel".to_owned(); + debug!( + "{}: on {:?} at {:?}", + wheel_event_type_string, + node.debug_str(), + hit_test_result.point_in_viewport + ); // https://w3c.github.io/uievents/#event-wheelevents - let event = WheelEvent::new( + let dom_event = DomWheelEvent::new( &self.window, DOMString::from(wheel_event_type_string), EventBubbles::Bubbles, EventCancelable::Cancelable, Some(&self.window), 0i32, - Finite::wrap(delta.x), - Finite::wrap(delta.y), - Finite::wrap(delta.z), - delta.mode as u32, + Finite::wrap(event.delta.x), + Finite::wrap(event.delta.y), + Finite::wrap(event.delta.z), + event.delta.mode as u32, can_gc, ); - let event = event.upcast::(); - event.set_trusted(true); + let dom_event = dom_event.upcast::(); + dom_event.set_trusted(true); let target = node.upcast(); - event.fire(target, can_gc); + dom_event.fire(target, can_gc); } #[allow(unsafe_code)] - pub(crate) unsafe fn handle_touch_event( + pub(crate) fn handle_touch_event( &self, - event_type: TouchEventType, - touch_id: TouchId, - point: Point2D, - node_address: Option, + event: TouchEvent, + hit_test_result: Option, can_gc: CanGc, ) -> TouchEventResult { - let TouchId(identifier) = touch_id; - - let event_name = match event_type { - TouchEventType::Down => "touchstart", - TouchEventType::Move => "touchmove", - TouchEventType::Up => "touchend", - TouchEventType::Cancel => "touchcancel", + // Ignore all incoming events without a hit test. + let Some(hit_test_result) = hit_test_result else { + return TouchEventResult::Forwarded; }; - let el = node_address.and_then(|address| { - let node = node::from_untrusted_node_address(address); - node.inclusive_ancestors(ShadowIncluding::No) - .filter_map(DomRoot::downcast::) - .next() - }); - let el = match el { - Some(el) => el, - None => return TouchEventResult::Forwarded, + let TouchId(identifier) = event.id; + let event_name = match event.action { + TouchEventAction::Down => "touchstart", + TouchEventAction::Move => "touchmove", + TouchEventAction::Up => "touchend", + TouchEventAction::Cancel => "touchcancel", + }; + + let node = unsafe { node::from_untrusted_compositor_node_address(hit_test_result.node) }; + let Some(el) = node + .inclusive_ancestors(ShadowIncluding::No) + .filter_map(DomRoot::downcast::) + .next() + else { + return TouchEventResult::Forwarded; }; let target = DomRoot::upcast::(el); let window = &*self.window; - let client_x = Finite::wrap(point.x as f64); - let client_y = Finite::wrap(point.y as f64); - let page_x = Finite::wrap(point.x as f64 + window.PageXOffset() as f64); - let page_y = Finite::wrap(point.y as f64 + window.PageYOffset() as f64); + let client_x = Finite::wrap(event.point.x as f64); + let client_y = Finite::wrap(event.point.y as f64); + let page_x = Finite::wrap(event.point.x as f64 + window.PageXOffset() as f64); + let page_y = Finite::wrap(event.point.y as f64 + window.PageYOffset() as f64); let touch = Touch::new( window, identifier, &target, client_x, @@ -2028,14 +2043,14 @@ impl Document { client_x, client_y, page_x, page_y, ); - match event_type { - TouchEventType::Down => { + match event.action { + TouchEventAction::Down => { // Add a new touch point self.active_touch_points .borrow_mut() .push(Dom::from_ref(&*touch)); }, - TouchEventType::Move => { + TouchEventAction::Move => { // Replace an existing touch point let mut active_touch_points = self.active_touch_points.borrow_mut(); match active_touch_points @@ -2046,7 +2061,7 @@ impl Document { None => warn!("Got a touchmove event for a non-active touch point"), } }, - TouchEventType::Up | TouchEventType::Cancel => { + TouchEventAction::Up | TouchEventAction::Cancel => { // Remove an existing touch point let mut active_touch_points = self.active_touch_points.borrow_mut(); match active_touch_points @@ -2068,7 +2083,7 @@ impl Document { TouchList::new(window, touches.r()) }; - let event = TouchEvent::new( + let event = DomTouchEvent::new( window, DOMString::from(event_name), EventBubbles::Bubbles, @@ -2178,19 +2193,19 @@ impl Document { } } - pub(crate) fn ime_dismissed(&self, can_gc: CanGc) { - self.request_focus( - self.GetBody().as_ref().map(|e| e.upcast()), - FocusType::Element, - can_gc, - ) - } + pub(crate) fn dispatch_ime_event(&self, event: ImeEvent, can_gc: CanGc) { + let composition_event = match event { + ImeEvent::Dismissed => { + self.request_focus( + self.GetBody().as_ref().map(|e| e.upcast()), + FocusType::Element, + can_gc, + ); + return; + }, + ImeEvent::Composition(composition_event) => composition_event, + }; - pub(crate) fn dispatch_composition_event( - &self, - composition_event: ::keyboard_types::CompositionEvent, - can_gc: CanGc, - ) { // spec: https://w3c.github.io/uievents/#compositionstart // spec: https://w3c.github.io/uievents/#compositionupdate // spec: https://w3c.github.io/uievents/#compositionend @@ -3721,7 +3736,7 @@ impl Document { dirty_root: Default::default(), declarative_refresh: Default::default(), pending_animation_ticks: Default::default(), - pending_compositor_events: Default::default(), + pending_input_events: Default::default(), mouse_move_event_index: Default::default(), resize_observers: Default::default(), fonts: Default::default(), @@ -3750,9 +3765,9 @@ impl Document { } /// Note a pending compositor event, to be processed at the next `update_the_rendering` task. - pub(crate) fn note_pending_compositor_event(&self, event: CompositorEvent) { - let mut pending_compositor_events = self.pending_compositor_events.borrow_mut(); - if matches!(event, CompositorEvent::MouseMoveEvent { .. }) { + pub(crate) fn note_pending_input_event(&self, event: ConstellationInputEvent) { + let mut pending_compositor_events = self.pending_input_events.borrow_mut(); + if matches!(event.event, InputEvent::MouseMove(..)) { // First try to replace any existing mouse move event. if let Some(mouse_move_event) = self .mouse_move_event_index @@ -3770,10 +3785,10 @@ impl Document { } /// Get pending compositor events, for processing within an `update_the_rendering` task. - pub(crate) fn take_pending_compositor_events(&self) -> Vec { + pub(crate) fn take_pending_input_events(&self) -> Vec { // Reset the mouse event index. *self.mouse_move_event_index.borrow_mut() = None; - mem::take(&mut *self.pending_compositor_events.borrow_mut()) + mem::take(&mut *self.pending_input_events.borrow_mut()) } pub(crate) fn set_csp_list(&self, csp_list: Option) { @@ -5067,7 +5082,7 @@ impl DocumentMethods for Document { "".into(), can_gc, ))), - "touchevent" => Ok(DomRoot::upcast(TouchEvent::new_uninitialized( + "touchevent" => Ok(DomRoot::upcast(DomTouchEvent::new_uninitialized( &self.window, &TouchList::new(&self.window, &[]), &TouchList::new(&self.window, &[]), diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index b623ae18973..225334c2710 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -43,6 +43,7 @@ use style::properties::ComputedValues; use style::selector_parser::{SelectorImpl, SelectorParser}; use style::stylesheets::{Stylesheet, UrlExtraData}; use uuid::Uuid; +use webrender_traits::UntrustedNodeAddress as CompositorUntrustedNodeAddress; use xml5ever::serialize as xml_serialize; use super::globalscope::GlobalScope; @@ -1420,6 +1421,15 @@ pub(crate) unsafe fn from_untrusted_node_address(candidate: UntrustedNodeAddress DomRoot::from_ref(Node::from_untrusted_node_address(candidate)) } +/// If the given untrusted node address represents a valid DOM node in the given runtime, +/// returns it. +#[allow(unsafe_code)] +pub(crate) unsafe fn from_untrusted_compositor_node_address( + candidate: CompositorUntrustedNodeAddress, +) -> DomRoot { + DomRoot::from_ref(Node::from_untrusted_compositor_node_address(candidate)) +} + #[allow(unsafe_code)] pub(crate) trait LayoutNodeHelpers<'dom> { fn type_id_for_layout(self) -> NodeTypeId; @@ -2747,6 +2757,26 @@ impl Node { &*(conversions::private_from_object(object) as *const Self) } + /// If the given untrusted node address represents a valid DOM node in the given runtime, + /// returns it. + /// + /// # Safety + /// + /// Callers should ensure they pass a [`CompositorUntrustedNodeAddress`] that points + /// to a valid [`JSObject`] in memory that represents a [`Node`]. + #[allow(unsafe_code)] + pub(crate) unsafe fn from_untrusted_compositor_node_address( + candidate: CompositorUntrustedNodeAddress, + ) -> &'static Self { + // https://github.com/servo/servo/issues/6383 + let candidate = candidate.0 as usize; + let object = candidate as *mut JSObject; + if object.is_null() { + panic!("Attempted to create a `Node` from an invalid pointer!") + } + &*(conversions::private_from_object(object) as *const Self) + } + pub(crate) fn html_serialize( &self, traversal_scope: html_serialize::TraversalScope, diff --git a/components/script/messaging.rs b/components/script/messaging.rs index 7944a5e8ea4..41dd113c732 100644 --- a/components/script/messaging.rs +++ b/components/script/messaging.rs @@ -58,7 +58,7 @@ impl MixedMessage { ScriptThreadMessage::UnloadDocument(id) => Some(id), ScriptThreadMessage::ExitPipeline(id, ..) => Some(id), ScriptThreadMessage::ExitScriptThread => None, - ScriptThreadMessage::SendEvent(id, ..) => Some(id), + ScriptThreadMessage::SendInputEvent(id, ..) => Some(id), ScriptThreadMessage::Viewport(id, ..) => Some(id), ScriptThreadMessage::GetTitle(id) => Some(id), ScriptThreadMessage::SetDocumentActivity(id, ..) => Some(id), diff --git a/components/script/script_runtime.rs b/components/script/script_runtime.rs index 28e7869bd4f..a51871eadf4 100644 --- a/components/script/script_runtime.rs +++ b/components/script/script_runtime.rs @@ -103,7 +103,6 @@ pub(crate) enum ScriptThreadEventCategory { ConstellationMsg, DevtoolsMsg, DocumentEvent, - DomEvent, FileRead, FormPlannedNavigation, HistoryEvent, @@ -137,7 +136,6 @@ impl From for ProfilerCategory { ScriptThreadEventCategory::ConstellationMsg => ProfilerCategory::ScriptConstellationMsg, ScriptThreadEventCategory::DevtoolsMsg => ProfilerCategory::ScriptDevtoolsMsg, ScriptThreadEventCategory::DocumentEvent => ProfilerCategory::ScriptDocumentEvent, - ScriptThreadEventCategory::DomEvent => ProfilerCategory::ScriptDomEvent, ScriptThreadEventCategory::EnterFullscreen => ProfilerCategory::ScriptEnterFullscreen, ScriptThreadEventCategory::ExitFullscreen => ProfilerCategory::ScriptExitFullscreen, ScriptThreadEventCategory::FileRead => ProfilerCategory::ScriptFileRead, @@ -181,14 +179,13 @@ impl From for ScriptHangAnnotation { ScriptThreadEventCategory::ConstellationMsg => ScriptHangAnnotation::ConstellationMsg, ScriptThreadEventCategory::DevtoolsMsg => ScriptHangAnnotation::DevtoolsMsg, ScriptThreadEventCategory::DocumentEvent => ScriptHangAnnotation::DocumentEvent, - ScriptThreadEventCategory::DomEvent => ScriptHangAnnotation::DomEvent, + ScriptThreadEventCategory::InputEvent => ScriptHangAnnotation::InputEvent, ScriptThreadEventCategory::FileRead => ScriptHangAnnotation::FileRead, ScriptThreadEventCategory::FormPlannedNavigation => { ScriptHangAnnotation::FormPlannedNavigation }, ScriptThreadEventCategory::HistoryEvent => ScriptHangAnnotation::HistoryEvent, ScriptThreadEventCategory::ImageCacheMsg => ScriptHangAnnotation::ImageCacheMsg, - ScriptThreadEventCategory::InputEvent => ScriptHangAnnotation::InputEvent, ScriptThreadEventCategory::NetworkEvent => ScriptHangAnnotation::NetworkEvent, ScriptThreadEventCategory::Rendering => ScriptHangAnnotation::Rendering, ScriptThreadEventCategory::Resize => ScriptHangAnnotation::Resize, diff --git a/components/script/script_thread.rs b/components/script/script_thread.rs index 695b837e9ad..58043823088 100644 --- a/components/script/script_thread.rs +++ b/components/script/script_thread.rs @@ -45,11 +45,8 @@ use devtools_traits::{ CSSError, DevtoolScriptControlMsg, DevtoolsPageInfo, NavigationState, ScriptToDevtoolsControlMsg, WorkerId, }; -use embedder_traits::{ - EmbedderMsg, MediaSessionActionType, MouseButton, MouseEventType, Theme, TouchEventType, - TouchId, WheelDelta, -}; -use euclid::default::{Point2D, Rect}; +use embedder_traits::{EmbedderMsg, InputEvent, MediaSessionActionType, Theme, TouchEventAction}; +use euclid::default::Rect; use fonts::{FontContext, SystemFontServiceProxy}; use headers::{HeaderMapExt, LastModified, ReferrerPolicy as ReferrerPolicyHeader}; use html5ever::{local_name, namespace_url, ns}; @@ -82,10 +79,10 @@ use script_layout_interface::{ }; use script_traits::webdriver_msg::WebDriverScriptCommand; use script_traits::{ - CompositorEvent, DiscardBrowsingContext, DocumentActivity, EventResult, InitialScriptState, - JsEvalResult, LoadData, LoadOrigin, NavigationHistoryBehavior, NewLayoutInfo, Painter, - ProgressiveWebMetricType, ScriptMsg, ScriptThreadMessage, ScriptToConstellationChan, - ScrollState, StructuredSerializedData, UntrustedNodeAddress, UpdatePipelineIdReason, + ConstellationInputEvent, DiscardBrowsingContext, DocumentActivity, EventResult, + InitialScriptState, JsEvalResult, LoadData, LoadOrigin, NavigationHistoryBehavior, + NewLayoutInfo, Painter, ProgressiveWebMetricType, ScriptMsg, ScriptThreadMessage, + ScriptToConstellationChan, ScrollState, StructuredSerializedData, UpdatePipelineIdReason, WindowSizeData, WindowSizeType, }; use servo_atoms::Atom; @@ -98,7 +95,7 @@ use url::Position; #[cfg(feature = "webgpu")] use webgpu::{WebGPUDevice, WebGPUMsg}; use webrender_api::DocumentId; -use webrender_traits::CrossProcessCompositorApi; +use webrender_traits::{CompositorHitTestResult, CrossProcessCompositorApi}; use crate::document_collection::DocumentCollection; use crate::document_loader::DocumentLoader; @@ -1003,9 +1000,7 @@ impl ScriptThread { fn process_mouse_move_event( &self, document: &Document, - window: &Window, - point: Point2D, - node_address: Option, + hit_test_result: Option, pressed_mouse_buttons: u16, can_gc: CanGc, ) { @@ -1014,10 +1009,9 @@ impl ScriptThread { unsafe { document.handle_mouse_move_event( - point, - &self.topmost_mouse_over_target, - node_address, + hit_test_result, pressed_mouse_buttons, + &self.topmost_mouse_over_target, can_gc, ) } @@ -1030,6 +1024,7 @@ impl ScriptThread { let mut state_already_changed = false; // Notify Constellation about the topmost anchor mouse over target. + let window = document.window(); if let Some(target) = self.topmost_mouse_over_target.get() { if let Some(anchor) = target .upcast::() @@ -1045,7 +1040,7 @@ impl ScriptThread { let url = document.url(); url.join(&value).map(|url| url.to_string()).ok() }); - let event = EmbedderMsg::Status(window.webview_id(), status); + let event = EmbedderMsg::Status(document.webview_id(), status); window.send_to_embedder(event); state_already_changed = true; @@ -1070,7 +1065,7 @@ impl ScriptThread { } /// Process compositor events as part of a "update the rendering task". - fn process_pending_compositor_events(&self, pipeline_id: PipelineId, can_gc: CanGc) { + fn proces_pending_input_events(&self, pipeline_id: PipelineId, can_gc: CanGc) { let Some(document) = self.documents.borrow().find_document(pipeline_id) else { warn!("Processing pending compositor events for closed pipeline {pipeline_id}."); return; @@ -1084,54 +1079,30 @@ impl ScriptThread { let window = document.window(); let _realm = enter_realm(document.window()); - for event in document.take_pending_compositor_events().into_iter() { - match event { - CompositorEvent::ResizeEvent(new_size, size_type) => { - window.add_resize_event(new_size, size_type); - }, - - CompositorEvent::MouseButtonEvent( - event_type, - button, - point, - node_address, - point_in_node, - pressed_mouse_buttons, - ) => { - self.handle_mouse_button_event( - pipeline_id, - event_type, - button, - point, - node_address, - point_in_node, - pressed_mouse_buttons, + for event in document.take_pending_input_events().into_iter() { + match event.event { + InputEvent::MouseButton(mouse_button_event) => { + document.handle_mouse_button_event( + mouse_button_event, + event.hit_test_result, + event.pressed_mouse_buttons, can_gc, ); }, - - CompositorEvent::MouseMoveEvent(point, node_address, pressed_mouse_buttons) => { + InputEvent::MouseMove(_) => { + // The event itself is unecessary here, because the point in the viewport is in the hit test. self.process_mouse_move_event( &document, - window, - point, - node_address, - pressed_mouse_buttons, + event.hit_test_result, + event.pressed_mouse_buttons, can_gc, ); }, - - CompositorEvent::TouchEvent(event_type, identifier, point, node_address) => { - let touch_result = self.handle_touch_event( - pipeline_id, - event_type, - identifier, - point, - node_address, - can_gc, - ); - match (event_type, touch_result) { - (TouchEventType::Down, TouchEventResult::Processed(handled)) => { + 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)) => { let result = if handled { // TODO: Wait to see if preventDefault is called on the first touchmove event. EventResult::DefaultAllowed @@ -1149,29 +1120,20 @@ impl ScriptThread { }, } }, - - CompositorEvent::WheelEvent(delta, point, node_address) => { - self.handle_wheel_event(pipeline_id, delta, point, node_address, can_gc); + InputEvent::Wheel(wheel_event) => { + document.handle_wheel_event(wheel_event, event.hit_test_result, can_gc); }, - - CompositorEvent::KeyboardEvent(key_event) => { - document.dispatch_key_event(key_event, can_gc); + InputEvent::Keyboard(keyboard_event) => { + document.dispatch_key_event(keyboard_event, can_gc); }, - - CompositorEvent::IMEDismissedEvent => { - document.ime_dismissed(can_gc); + InputEvent::Ime(ime_event) => { + document.dispatch_ime_event(ime_event, can_gc); }, - - CompositorEvent::CompositionEvent(composition_event) => { - document.dispatch_composition_event(composition_event, can_gc); - }, - - CompositorEvent::GamepadEvent(gamepad_event) => { + InputEvent::Gamepad(gamepad_event) => { window.as_global_scope().handle_gamepad_event(gamepad_event); }, - - CompositorEvent::ClipboardEvent(clipboard_action) => { - document.handle_clipboard_action(clipboard_action, can_gc); + InputEvent::EditingAction(editing_action_event) => { + document.handle_editing_action(editing_action_event, can_gc); }, } } @@ -1244,12 +1206,12 @@ impl ScriptThread { } // TODO(#31581): The steps in the "Revealing the document" section need to be implemente - // `process_pending_compositor_events` handles the focusing steps as well as other events + // `proces_pending_input_events` handles the focusing steps as well as other events // from the compositor. // TODO: Should this be broken and to match the specification more closely? For instance see // https://html.spec.whatwg.org/multipage/#flush-autofocus-candidates. - self.process_pending_compositor_events(*pipeline_id, can_gc); + self.proces_pending_input_events(*pipeline_id, can_gc); // TODO(#31665): Implement the "run the scroll steps" from // https://drafts.csswg.org/cssom-view/#document-run-the-scroll-steps. @@ -1469,8 +1431,8 @@ impl ScriptThread { ) } }, - MixedMessage::FromConstellation(ScriptThreadMessage::SendEvent(id, event)) => { - self.handle_event(id, event) + MixedMessage::FromConstellation(ScriptThreadMessage::SendInputEvent(id, event)) => { + self.handle_input_event(id, event) }, MixedMessage::FromScript(MainThreadScriptMsg::Common(CommonScriptMsg::Task( _, @@ -1594,7 +1556,7 @@ impl ScriptThread { fn categorize_msg(&self, msg: &MixedMessage) -> ScriptThreadEventCategory { match *msg { MixedMessage::FromConstellation(ref inner_msg) => match *inner_msg { - ScriptThreadMessage::SendEvent(_, _) => ScriptThreadEventCategory::DomEvent, + ScriptThreadMessage::SendInputEvent(_, _) => ScriptThreadEventCategory::InputEvent, _ => ScriptThreadEventCategory::ConstellationMsg, }, // TODO https://github.com/servo/servo/issues/18998 @@ -1646,8 +1608,8 @@ impl ScriptThread { profiler_chan, f ), - ScriptThreadEventCategory::DomEvent => { - time_profile!(ProfilerCategory::ScriptDomEvent, None, profiler_chan, f) + ScriptThreadEventCategory::InputEvent => { + time_profile!(ProfilerCategory::ScriptInputEvent, None, profiler_chan, f) }, ScriptThreadEventCategory::FileRead => { time_profile!(ProfilerCategory::ScriptFileRead, None, profiler_chan, f) @@ -1667,9 +1629,6 @@ impl ScriptThread { profiler_chan, f ), - ScriptThreadEventCategory::InputEvent => { - time_profile!(ProfilerCategory::ScriptInputEvent, None, profiler_chan, f) - }, ScriptThreadEventCategory::NetworkEvent => { time_profile!(ProfilerCategory::ScriptNetworkEvent, None, profiler_chan, f) }, @@ -1893,7 +1852,7 @@ impl ScriptThread { msg @ ScriptThreadMessage::Viewport(..) | msg @ ScriptThreadMessage::Resize(..) | msg @ ScriptThreadMessage::ExitFullScreen(..) | - msg @ ScriptThreadMessage::SendEvent(..) | + msg @ ScriptThreadMessage::SendInputEvent(..) | msg @ ScriptThreadMessage::TickAllAnimations(..) | msg @ ScriptThreadMessage::ExitScriptThread => { panic!("should have handled {:?} already", msg) @@ -3318,75 +3277,12 @@ impl ScriptThread { /// Queue compositor events for later dispatching as part of a /// `update_the_rendering` task. - fn handle_event(&self, pipeline_id: PipelineId, event: CompositorEvent) { + fn handle_input_event(&self, pipeline_id: PipelineId, event: ConstellationInputEvent) { let Some(document) = self.documents.borrow().find_document(pipeline_id) else { warn!("Compositor event sent to closed pipeline {pipeline_id}."); return; }; - document.note_pending_compositor_event(event); - } - - #[allow(clippy::too_many_arguments)] - fn handle_mouse_button_event( - &self, - pipeline_id: PipelineId, - mouse_event_type: MouseEventType, - button: MouseButton, - point: Point2D, - node_address: Option, - point_in_node: Option>, - pressed_mouse_buttons: u16, - can_gc: CanGc, - ) { - let Some(document) = self.documents.borrow().find_document(pipeline_id) else { - warn!("Message sent to closed pipeline {pipeline_id}."); - return; - }; - unsafe { - document.handle_mouse_button_event( - button, - point, - mouse_event_type, - node_address, - point_in_node, - pressed_mouse_buttons, - can_gc, - ) - } - } - - fn handle_touch_event( - &self, - pipeline_id: PipelineId, - event_type: TouchEventType, - identifier: TouchId, - point: Point2D, - node_address: Option, - can_gc: CanGc, - ) -> TouchEventResult { - let document = match self.documents.borrow().find_document(pipeline_id) { - Some(document) => document, - None => { - warn!("Message sent to closed pipeline {}.", pipeline_id); - return TouchEventResult::Processed(true); - }, - }; - unsafe { document.handle_touch_event(event_type, identifier, point, node_address, can_gc) } - } - - fn handle_wheel_event( - &self, - pipeline_id: PipelineId, - wheel_delta: WheelDelta, - point: Point2D, - node_address: Option, - can_gc: CanGc, - ) { - let Some(document) = self.documents.borrow().find_document(pipeline_id) else { - warn!("Message sent to closed pipeline {pipeline_id}."); - return; - }; - unsafe { document.handle_wheel_event(wheel_delta, point, node_address, can_gc) }; + document.note_pending_input_event(event); } /// Handle a "navigate an iframe" message from the constellation. diff --git a/components/servo/lib.rs b/components/servo/lib.rs index 84aa5bffd1f..6c62e22cb18 100644 --- a/components/servo/lib.rs +++ b/components/servo/lib.rs @@ -999,11 +999,6 @@ impl Servo { }, ); }, - EmbedderMsg::EventDelivered(webview_id, event) => { - if let Some(webview) = self.get_webview_handle(webview_id) { - webview.delegate().notify_event_delivered(webview, event); - } - }, EmbedderMsg::PlayGamepadHapticEffect( webview_id, gamepad_index, diff --git a/components/servo/webview.rs b/components/servo/webview.rs index 677913ed7d5..a1c47138ce7 100644 --- a/components/servo/webview.rs +++ b/components/servo/webview.rs @@ -8,16 +8,15 @@ use std::rc::{Rc, Weak}; use std::time::Duration; use base::id::WebViewId; -use compositing::windowing::{MouseWindowEvent, WebRenderDebugOption}; +use compositing::windowing::WebRenderDebugOption; use compositing::IOCompositor; use compositing_traits::ConstellationMsg; use embedder_traits::{ - ClipboardEventType, Cursor, GamepadEvent, LoadStatus, MediaSessionActionType, Theme, - TouchEventType, TouchId, TraversalDirection, WheelDelta, + Cursor, InputEvent, LoadStatus, MediaSessionActionType, Theme, TouchEventAction, + TraversalDirection, }; -use keyboard_types::{CompositionEvent, KeyboardEvent}; use url::Url; -use webrender_api::units::{DeviceIntPoint, DevicePoint, DeviceRect}; +use webrender_api::units::{DeviceIntPoint, DeviceRect}; use webrender_api::ScrollLocation; use crate::clipboard_delegate::{ClipboardDelegate, DefaultClipboardDelegate}; @@ -310,68 +309,30 @@ impl WebView { )) } - pub fn notify_pointer_button_event(&self, event: MouseWindowEvent) { - self.inner() - .compositor - .borrow_mut() - .on_mouse_window_event_class(event); - } - - pub fn notify_pointer_move_event(&self, event: DevicePoint) { - self.inner() - .compositor - .borrow_mut() - .on_mouse_window_move_event_class(event); - } - - pub fn notify_touch_event(&self, event_type: TouchEventType, id: TouchId, point: DevicePoint) { - self.inner() - .compositor - .borrow_mut() - .on_touch_event(event_type, id, point); - } - - pub fn notify_wheel_event(&self, delta: WheelDelta, point: DevicePoint) { - self.inner() - .compositor - .borrow_mut() - .on_wheel_event(delta, point); - } - pub fn notify_scroll_event( &self, location: ScrollLocation, point: DeviceIntPoint, - touch_event_type: TouchEventType, + touch_event_action: TouchEventAction, ) { self.inner() .compositor .borrow_mut() - .on_scroll_event(location, point, touch_event_type); + .on_scroll_event(location, point, touch_event_action); } - pub fn notify_keyboard_event(&self, event: KeyboardEvent) { - self.inner() - .constellation_proxy - .send(ConstellationMsg::Keyboard(self.id(), event)) - } + pub fn notify_input_event(&self, event: InputEvent) { + // Events with a `point` first go to the compositor for hit testing. + if event.point().is_some() { + self.inner().compositor.borrow_mut().on_input_event(event); + return; + } - pub fn notify_ime_event(&self, event: CompositionEvent) { self.inner() .constellation_proxy - .send(ConstellationMsg::IMECompositionEvent(event)) - } - - pub fn notify_ime_dismissed_event(&self) { - self.inner() - .constellation_proxy - .send(ConstellationMsg::IMEDismissed); - } - - pub fn notify_gamepad_event(&self, event: GamepadEvent) { - self.inner() - .constellation_proxy - .send(ConstellationMsg::Gamepad(event)); + .send(ConstellationMsg::ForwardInputEvent( + event, None, /* hit_test */ + )) } pub fn notify_media_session_action_event(&self, event: MediaSessionActionType) { @@ -380,12 +341,6 @@ impl WebView { .send(ConstellationMsg::MediaSessionAction(event)); } - pub fn notify_clipboard_event(&self, event: ClipboardEventType) { - self.inner() - .constellation_proxy - .send(ConstellationMsg::Clipboard(event)); - } - pub fn notify_vsync(&self) { self.inner().compositor.borrow_mut().on_vsync(); } diff --git a/components/servo/webview_delegate.rs b/components/servo/webview_delegate.rs index 8499231d8db..204eaf2f4d7 100644 --- a/components/servo/webview_delegate.rs +++ b/components/servo/webview_delegate.rs @@ -7,9 +7,9 @@ use std::path::PathBuf; use base::id::PipelineId; use compositing_traits::ConstellationMsg; use embedder_traits::{ - AllowOrDeny, AuthenticationResponse, CompositorEventVariant, ContextMenuResult, Cursor, - FilterPattern, GamepadHapticEffectType, InputMethodType, LoadStatus, MediaSessionEvent, - PermissionFeature, PromptDefinition, PromptOrigin, WebResourceRequest, WebResourceResponseMsg, + AllowOrDeny, AuthenticationResponse, ContextMenuResult, Cursor, FilterPattern, + GamepadHapticEffectType, InputMethodType, LoadStatus, MediaSessionEvent, PermissionFeature, + PromptDefinition, PromptOrigin, WebResourceRequest, WebResourceResponseMsg, }; use ipc_channel::ipc::IpcSender; use keyboard_types::KeyboardEvent; @@ -170,8 +170,6 @@ pub trait WebViewDelegate { fn notify_ready_to_show(&self, _webview: WebView) {} /// Notify the embedder that it needs to present a new frame. fn notify_new_frame_ready(&self, _webview: WebView) {} - /// The given event was delivered to a pipeline in the given webview. - fn notify_event_delivered(&self, _webview: WebView, _event: CompositorEventVariant) {} /// The history state has changed. // changed pattern; maybe wasteful if embedder doesn’t care? fn notify_history_changed(&self, _webview: WebView, _: Vec, _: usize) {} diff --git a/components/shared/background_hang_monitor/lib.rs b/components/shared/background_hang_monitor/lib.rs index d8118a8808f..ae7e587226a 100644 --- a/components/shared/background_hang_monitor/lib.rs +++ b/components/shared/background_hang_monitor/lib.rs @@ -20,7 +20,6 @@ pub enum ScriptHangAnnotation { ConstellationMsg, DevtoolsMsg, DocumentEvent, - DomEvent, FileRead, FormPlannedNavigation, ImageCacheMsg, diff --git a/components/shared/compositing/constellation_msg.rs b/components/shared/compositing/constellation_msg.rs index a794d7b3044..7165d40ccf5 100644 --- a/components/shared/compositing/constellation_msg.rs +++ b/components/shared/compositing/constellation_msg.rs @@ -8,16 +8,13 @@ use std::time::Duration; use base::id::{BrowsingContextId, PipelineId, TopLevelBrowsingContextId, WebViewId}; use base::Epoch; -use embedder_traits::{ - ClipboardEventType, Cursor, GamepadEvent, MediaSessionActionType, Theme, TraversalDirection, -}; +use embedder_traits::{Cursor, InputEvent, MediaSessionActionType, Theme, TraversalDirection}; use ipc_channel::ipc::IpcSender; -use keyboard_types::{CompositionEvent, KeyboardEvent}; use script_traits::{ - AnimationTickType, CompositorEvent, LogEntry, WebDriverCommandMsg, WindowSizeData, - WindowSizeType, + AnimationTickType, LogEntry, WebDriverCommandMsg, WindowSizeData, WindowSizeType, }; use servo_url::ServoUrl; +use webrender_traits::CompositorHitTestResult; /// Messages to the constellation. pub enum ConstellationMsg { @@ -34,10 +31,6 @@ pub enum ConstellationMsg { GetFocusTopLevelBrowsingContext(IpcSender>), /// Query the constellation to see if the current compositor output is stable IsReadyToSaveImage(HashMap), - /// Inform the constellation of a key event. - Keyboard(WebViewId, KeyboardEvent), - /// Inform the constellation of a composition event (IME). - IMECompositionEvent(CompositionEvent), /// Whether to allow script to navigate. AllowNavigationResponse(PipelineId, bool), /// Request to load a page. @@ -70,8 +63,8 @@ pub enum ConstellationMsg { FocusWebView(TopLevelBrowsingContextId), /// Make none of the webviews focused. BlurWebView, - /// Forward an event to the script task of the given pipeline. - ForwardEvent(PipelineId, CompositorEvent), + /// Forward an input event to an appropriate ScriptTask. + ForwardInputEvent(InputEvent, Option), /// Requesting a change to the onscreen cursor. SetCursor(WebViewId, Cursor), /// Enable the sampling profiler, with a given sampling rate and max total sampling duration. @@ -82,12 +75,6 @@ pub enum ConstellationMsg { MediaSessionAction(MediaSessionActionType), /// Set whether to use less resources, by stopping animations and running timers at a heavily limited rate. SetWebViewThrottled(TopLevelBrowsingContextId, bool), - /// Virtual keyboard was dismissed - IMEDismissed, - /// Gamepad state has changed - Gamepad(GamepadEvent), - /// Inform the constellation of a clipboard event. - Clipboard(ClipboardEventType), } impl fmt::Debug for ConstellationMsg { @@ -106,8 +93,6 @@ impl ConstellationMsg { GetPipeline(..) => "GetPipeline", GetFocusTopLevelBrowsingContext(..) => "GetFocusTopLevelBrowsingContext", IsReadyToSaveImage(..) => "IsReadyToSaveImage", - Keyboard(..) => "Keyboard", - IMECompositionEvent(..) => "IMECompositionEvent", AllowNavigationResponse(..) => "AllowNavigationResponse", LoadUrl(..) => "LoadUrl", TraverseHistory(..) => "TraverseHistory", @@ -123,16 +108,13 @@ impl ConstellationMsg { FocusWebView(..) => "FocusWebView", BlurWebView => "BlurWebView", SendError(..) => "SendError", - ForwardEvent(..) => "ForwardEvent", + ForwardInputEvent(..) => "ForwardEvent", SetCursor(..) => "SetCursor", ToggleProfiler(..) => "EnableProfiler", ExitFullScreen(..) => "ExitFullScreen", MediaSessionAction(..) => "MediaSessionAction", SetWebViewThrottled(..) => "SetWebViewThrottled", - IMEDismissed => "IMEDismissed", ClearCache => "ClearCache", - Gamepad(..) => "Gamepad", - Clipboard(..) => "Clipboard", } } } diff --git a/components/shared/compositing/lib.rs b/components/shared/compositing/lib.rs index 4bd3644ef82..c8dcf2e7ea7 100644 --- a/components/shared/compositing/lib.rs +++ b/components/shared/compositing/lib.rs @@ -12,7 +12,7 @@ use base::id::{PipelineId, TopLevelBrowsingContextId}; use base::Epoch; pub use constellation_msg::ConstellationMsg; use crossbeam_channel::{Receiver, Sender}; -use embedder_traits::{EventLoopWaker, MouseButton, MouseEventType}; +use embedder_traits::{EventLoopWaker, MouseButton, MouseButtonAction}; use euclid::Rect; use ipc_channel::ipc::IpcSender; use log::warn; @@ -93,7 +93,7 @@ pub enum CompositorMsg { /// The load of a page has completed LoadComplete(TopLevelBrowsingContextId), /// WebDriver mouse button event - WebDriverMouseButtonEvent(MouseEventType, MouseButton, f32, f32), + WebDriverMouseButtonEvent(MouseButtonAction, MouseButton, f32, f32), /// WebDriver mouse move event WebDriverMouseMoveEvent(f32, f32), diff --git a/components/shared/embedder/input_events.rs b/components/shared/embedder/input_events.rs new file mode 100644 index 00000000000..c4e3ba0e9b4 --- /dev/null +++ b/components/shared/embedder/input_events.rs @@ -0,0 +1,219 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * 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 keyboard_types::{CompositionEvent, KeyboardEvent}; +use malloc_size_of_derive::MallocSizeOf; +use serde::{Deserialize, Serialize}; +pub use webrender_api::units::DevicePoint; + +/// An input event that is sent from the embedder to Servo. +#[derive(Clone, Debug, Deserialize, Serialize)] +pub enum InputEvent { + EditingAction(EditingActionEvent), + Gamepad(GamepadEvent), + Ime(ImeEvent), + Keyboard(KeyboardEvent), + MouseButton(MouseButtonEvent), + MouseMove(MouseMoveEvent), + Touch(TouchEvent), + Wheel(WheelEvent), +} + +/// An editing action that should be performed on a `WebView`. +#[derive(Clone, Debug, Deserialize, Serialize)] +pub enum EditingActionEvent { + Copy, + Cut, + Paste, +} + +impl InputEvent { + pub fn point(&self) -> Option { + match self { + InputEvent::EditingAction(..) => None, + InputEvent::Gamepad(..) => None, + InputEvent::Ime(..) => None, + InputEvent::Keyboard(..) => None, + InputEvent::MouseButton(event) => Some(event.point), + InputEvent::MouseMove(event) => Some(event.point), + InputEvent::Touch(event) => Some(event.point), + InputEvent::Wheel(event) => Some(event.point), + } + } +} + +#[derive(Clone, Copy, Debug, Deserialize, Serialize)] +pub struct MouseButtonEvent { + pub action: MouseButtonAction, + pub button: MouseButton, + pub point: DevicePoint, +} + +#[derive(Clone, Copy, Debug, Deserialize, Serialize)] +pub enum MouseButton { + Left, + Middle, + Right, + Back, + Forward, + Other(u16), +} + +impl From for MouseButton { + fn from(value: u16) -> Self { + match value { + 0 => MouseButton::Left, + 1 => MouseButton::Middle, + 2 => MouseButton::Right, + 3 => MouseButton::Back, + 4 => MouseButton::Forward, + _ => MouseButton::Other(value), + } + } +} + +impl From for i16 { + fn from(value: MouseButton) -> Self { + match value { + MouseButton::Left => 0, + MouseButton::Middle => 1, + MouseButton::Right => 2, + MouseButton::Back => 3, + MouseButton::Forward => 4, + MouseButton::Other(value) => value as i16, + } + } +} + +/// The types of mouse events +#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize)] +pub enum MouseButtonAction { + /// Mouse button clicked + Click, + /// Mouse button down + Down, + /// Mouse button up + Up, +} + +#[derive(Clone, Copy, Debug, Deserialize, Serialize)] +pub struct MouseMoveEvent { + pub point: DevicePoint, +} + +/// The type of input represented by a multi-touch event. +#[derive(Clone, Copy, Debug, Deserialize, Serialize)] +pub enum TouchEventAction { + /// A new touch point came in contact with the screen. + Down, + /// An existing touch point changed location. + Move, + /// A touch point was removed from the screen. + Up, + /// The system stopped tracking a touch point. + Cancel, +} + +/// An opaque identifier for a touch point. +/// +/// +#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)] +pub struct TouchId(pub i32); + +#[derive(Clone, Copy, Debug, Deserialize, Serialize)] +pub struct TouchEvent { + pub action: TouchEventAction, + pub id: TouchId, + pub point: DevicePoint, +} + +/// Mode to measure WheelDelta floats in +#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] +pub enum WheelMode { + /// Delta values are specified in pixels + DeltaPixel = 0x00, + /// Delta values are specified in lines + DeltaLine = 0x01, + /// Delta values are specified in pages + DeltaPage = 0x02, +} + +/// The Wheel event deltas in every direction +#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] +pub struct WheelDelta { + /// Delta in the left/right direction + pub x: f64, + /// Delta in the up/down direction + pub y: f64, + /// Delta in the direction going into/out of the screen + pub z: f64, + /// Mode to measure the floats in + pub mode: WheelMode, +} + +#[derive(Clone, Copy, Debug, Deserialize, Serialize)] +pub struct WheelEvent { + pub delta: WheelDelta, + pub point: DevicePoint, +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +pub enum ImeEvent { + Composition(CompositionEvent), + Dismissed, +} + +#[derive( + Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, Ord, PartialEq, PartialOrd, Serialize, +)] +/// Index of gamepad in list of system's connected gamepads +pub struct GamepadIndex(pub usize); + +#[derive(Clone, Debug, Deserialize, Serialize)] +/// The minimum and maximum values that can be reported for axis or button input from this gamepad +pub struct GamepadInputBounds { + /// Minimum and maximum axis values + pub axis_bounds: (f64, f64), + /// Minimum and maximum button values + pub button_bounds: (f64, f64), +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +/// The haptic effects supported by this gamepad +pub struct GamepadSupportedHapticEffects { + /// Gamepad support for dual rumble effects + pub supports_dual_rumble: bool, + /// Gamepad support for trigger rumble effects + pub supports_trigger_rumble: bool, +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +/// The type of Gamepad event +pub enum GamepadEvent { + /// A new gamepad has been connected + /// + Connected( + GamepadIndex, + String, + GamepadInputBounds, + GamepadSupportedHapticEffects, + ), + /// An existing gamepad has been disconnected + /// + Disconnected(GamepadIndex), + /// An existing gamepad has been updated + /// + Updated(GamepadIndex, GamepadUpdateType), +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +/// The type of Gamepad input being updated +pub enum GamepadUpdateType { + /// Axis index and input value + /// + Axis(usize, f64), + /// Button index and input value + /// + Button(usize, f64), +} diff --git a/components/shared/embedder/lib.rs b/components/shared/embedder/lib.rs index 7201b150f8a..66d70539e30 100644 --- a/components/shared/embedder/lib.rs +++ b/components/shared/embedder/lib.rs @@ -2,6 +2,7 @@ * 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/. */ +pub mod input_events; pub mod resources; use std::fmt::{Debug, Error, Formatter}; @@ -11,7 +12,7 @@ use base::id::{PipelineId, WebViewId}; use crossbeam_channel::Sender; use http::{HeaderMap, Method, StatusCode}; use ipc_channel::ipc::IpcSender; -use keyboard_types::KeyboardEvent; +pub use keyboard_types::{KeyboardEvent, Modifiers}; use log::warn; use malloc_size_of_derive::MallocSizeOf; use num_derive::FromPrimitive; @@ -19,6 +20,8 @@ use serde::{Deserialize, Serialize}; use servo_url::ServoUrl; use webrender_api::units::{DeviceIntPoint, DeviceIntRect, DeviceIntSize}; +pub use crate::input_events::*; + /// A cursor for the window. This is different from a CSS cursor (see /// `CursorKind`) in that it has no `Auto` value. #[repr(u8)] @@ -250,29 +253,12 @@ pub enum EmbedderMsg { OnDevtoolsStarted(Result, String), /// Ask the user to allow a devtools client to connect. RequestDevtoolsConnection(IpcSender), - /// The given event was delivered to a pipeline in the given browser. - EventDelivered(WebViewId, CompositorEventVariant), /// Request to play a haptic effect on a connected gamepad. PlayGamepadHapticEffect(WebViewId, usize, GamepadHapticEffectType, IpcSender), /// Request to stop a haptic effect on a connected gamepad. StopGamepadHapticEffect(WebViewId, usize, IpcSender), } -/// The variant of CompositorEvent that was delivered to a pipeline. -#[derive(Debug, Deserialize, Serialize)] -pub enum CompositorEventVariant { - ResizeEvent, - MouseButtonEvent, - MouseMoveEvent, - TouchEvent, - WheelEvent, - KeyboardEvent, - CompositionEvent, - IMEDismissedEvent, - GamepadEvent, - ClipboardEvent, -} - impl Debug for EmbedderMsg { fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { match *self { @@ -312,7 +298,6 @@ impl Debug for EmbedderMsg { EmbedderMsg::OnDevtoolsStarted(..) => write!(f, "OnDevtoolsStarted"), EmbedderMsg::RequestDevtoolsConnection(..) => write!(f, "RequestDevtoolsConnection"), EmbedderMsg::ShowContextMenu(..) => write!(f, "ShowContextMenu"), - EmbedderMsg::EventDelivered(..) => write!(f, "HitTestedEvent"), EmbedderMsg::PlayGamepadHapticEffect(..) => write!(f, "PlayGamepadHapticEffect"), EmbedderMsg::StopGamepadHapticEffect(..) => write!(f, "StopGamepadHapticEffect"), } @@ -535,150 +520,6 @@ impl WebResourceResponse { } } -/// The type of input represented by a multi-touch event. -#[derive(Clone, Copy, Debug, Deserialize, Serialize)] -pub enum TouchEventType { - /// A new touch point came in contact with the screen. - Down, - /// An existing touch point changed location. - Move, - /// A touch point was removed from the screen. - Up, - /// The system stopped tracking a touch point. - Cancel, -} - -/// An opaque identifier for a touch point. -/// -/// -#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)] -pub struct TouchId(pub i32); - -#[derive( - Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, Ord, PartialEq, PartialOrd, Serialize, -)] -/// Index of gamepad in list of system's connected gamepads -pub struct GamepadIndex(pub usize); - -#[derive(Clone, Debug, Deserialize, Serialize)] -/// The minimum and maximum values that can be reported for axis or button input from this gamepad -pub struct GamepadInputBounds { - /// Minimum and maximum axis values - pub axis_bounds: (f64, f64), - /// Minimum and maximum button values - pub button_bounds: (f64, f64), -} - -#[derive(Clone, Debug, Deserialize, Serialize)] -/// The haptic effects supported by this gamepad -pub struct GamepadSupportedHapticEffects { - /// Gamepad support for dual rumble effects - pub supports_dual_rumble: bool, - /// Gamepad support for trigger rumble effects - pub supports_trigger_rumble: bool, -} - -#[derive(Clone, Debug, Deserialize, Serialize)] -/// The type of Gamepad event -pub enum GamepadEvent { - /// A new gamepad has been connected - /// - Connected( - GamepadIndex, - String, - GamepadInputBounds, - GamepadSupportedHapticEffects, - ), - /// An existing gamepad has been disconnected - /// - Disconnected(GamepadIndex), - /// An existing gamepad has been updated - /// - Updated(GamepadIndex, GamepadUpdateType), -} - -#[derive(Clone, Debug, Deserialize, Serialize)] -/// The type of Gamepad input being updated -pub enum GamepadUpdateType { - /// Axis index and input value - /// - Axis(usize, f64), - /// Button index and input value - /// - Button(usize, f64), -} - -#[derive(Clone, Copy, Debug, Deserialize, Serialize)] -pub enum MouseButton { - /// The left mouse button. - Left = 1, - /// The right mouse button. - Right = 2, - /// The middle mouse button. - Middle = 4, -} - -/// The types of mouse events -#[derive(Debug, Deserialize, MallocSizeOf, Serialize)] -pub enum MouseEventType { - /// Mouse button clicked - Click, - /// Mouse button down - MouseDown, - /// Mouse button up - MouseUp, -} - -/// Mode to measure WheelDelta floats in -#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] -pub enum WheelMode { - /// Delta values are specified in pixels - DeltaPixel = 0x00, - /// Delta values are specified in lines - DeltaLine = 0x01, - /// Delta values are specified in pages - DeltaPage = 0x02, -} - -/// The Wheel event deltas in every direction -#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] -pub struct WheelDelta { - /// Delta in the left/right direction - pub x: f64, - /// Delta in the up/down direction - pub y: f64, - /// Delta in the direction going into/out of the screen - pub z: f64, - /// Mode to measure the floats in - pub mode: WheelMode, -} - -/// The mouse button involved in the event. -/// The types of clipboard events -#[derive(Clone, Debug, Deserialize, Serialize)] -pub enum ClipboardEventType { - /// Contents of the system clipboard are changed - Change, - /// Copy - Copy, - /// Cut - Cut, - /// Paste - Paste, -} - -impl ClipboardEventType { - /// Convert to event name - pub fn as_str(&self) -> &str { - match *self { - ClipboardEventType::Change => "clipboardchange", - ClipboardEventType::Copy => "copy", - ClipboardEventType::Cut => "cut", - ClipboardEventType::Paste => "paste", - } - } -} - /// The direction of a history traversal #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] pub enum TraversalDirection { diff --git a/components/shared/profile/time.rs b/components/shared/profile/time.rs index a9d1118e7f1..ccb842a2224 100644 --- a/components/shared/profile/time.rs +++ b/components/shared/profile/time.rs @@ -83,7 +83,6 @@ pub enum ProfilerCategory { ScriptConstellationMsg = 0x61, ScriptDevtoolsMsg = 0x62, ScriptDocumentEvent = 0x63, - ScriptDomEvent = 0x64, /// Rust tracing only: the script thread is executing a script. /// This may include time doing layout or parse work initiated by the script. @@ -149,7 +148,6 @@ impl ProfilerCategory { ProfilerCategory::ScriptConstellationMsg => "ScriptConstellationMsg", ProfilerCategory::ScriptDevtoolsMsg => "ScriptDevtoolsMsg", ProfilerCategory::ScriptDocumentEvent => "ScriptDocumentEvent", - ProfilerCategory::ScriptDomEvent => "ScriptDomEvent", ProfilerCategory::ScriptEvaluate => "ScriptEvaluate", ProfilerCategory::ScriptEvent => "ScriptEvent", ProfilerCategory::ScriptFileRead => "ScriptFileRead", diff --git a/components/shared/script/lib.rs b/components/shared/script/lib.rs index 9ec97d717f0..f76faaef79a 100644 --- a/components/shared/script/lib.rs +++ b/components/shared/script/lib.rs @@ -31,17 +31,14 @@ use bluetooth_traits::BluetoothRequest; use canvas_traits::webgl::WebGLPipeline; use crossbeam_channel::{RecvTimeoutError, Sender}; use devtools_traits::{DevtoolScriptControlMsg, ScriptToDevtoolsControlMsg, WorkerId}; -use embedder_traits::{ - ClipboardEventType, CompositorEventVariant, GamepadEvent, MediaSessionActionType, MouseButton, - MouseEventType, Theme, TouchEventType, TouchId, WheelDelta, -}; -use euclid::default::Point2D; +use embedder_traits::input_events::InputEvent; +use embedder_traits::{MediaSessionActionType, MouseButton, MouseButtonAction, Theme}; use euclid::{Rect, Scale, Size2D, UnknownUnit, Vector2D}; use http::{HeaderMap, Method}; use ipc_channel::ipc::{IpcReceiver, IpcSender}; use ipc_channel::Error as IpcError; use keyboard_types::webdriver::Event as WebDriverInputEvent; -use keyboard_types::{CompositionEvent, KeyboardEvent}; +use keyboard_types::KeyboardEvent; use libc::c_void; use log::warn; use malloc_size_of::malloc_size_of_is_0; @@ -62,7 +59,8 @@ use webgpu::WebGPUMsg; use webrender_api::units::{DeviceIntSize, DevicePixel, LayoutPixel}; use webrender_api::{DocumentId, ExternalScrollId, ImageKey}; use webrender_traits::{ - CrossProcessCompositorApi, UntrustedNodeAddress as WebRenderUntrustedNodeAddress, + CompositorHitTestResult, CrossProcessCompositorApi, + UntrustedNodeAddress as WebRenderUntrustedNodeAddress, }; pub use crate::script_msg::{ @@ -315,7 +313,7 @@ pub enum ScriptThreadMessage { /// Notifies the script that the whole thread should be closed. ExitScriptThread, /// Sends a DOM event. - SendEvent(PipelineId, CompositorEvent), + SendInputEvent(PipelineId, ConstellationInputEvent), /// Notifies script of the viewport. Viewport(PipelineId, Rect), /// Requests that the script thread immediately send the constellation the title of a pipeline. @@ -422,7 +420,7 @@ impl fmt::Debug for ScriptThreadMessage { UnloadDocument(..) => "UnloadDocument", ExitPipeline(..) => "ExitPipeline", ExitScriptThread => "ExitScriptThread", - SendEvent(..) => "SendEvent", + SendInputEvent(..) => "SendInputEvent", Viewport(..) => "Viewport", GetTitle(..) => "GetTitle", SetDocumentActivity(..) => "SetDocumentActivity", @@ -476,64 +474,16 @@ pub enum AnimationState { NoAnimationCallbacksPresent, } -/// Events from the compositor that the script thread needs to know about +/// Input events from the embedder that are sent via the `Constellation`` to the `ScriptThread`. #[derive(Debug, Deserialize, Serialize)] -pub enum CompositorEvent { - /// The window was resized. - ResizeEvent(WindowSizeData, WindowSizeType), - /// A mouse button state changed. - MouseButtonEvent( - MouseEventType, - MouseButton, - Point2D, - Option, - Option>, - // Bitmask of MouseButton values representing the currently pressed buttons - u16, - ), - /// The mouse was moved over a point (or was moved out of the recognizable region). - MouseMoveEvent( - Point2D, - Option, - // Bitmask of MouseButton values representing the currently pressed buttons - u16, - ), - /// A touch event was generated with a touch ID and location. - TouchEvent( - TouchEventType, - TouchId, - Point2D, - Option, - ), - /// A wheel event was generated with a delta in the X, Y, and/or Z directions - WheelEvent(WheelDelta, Point2D, Option), - /// A key was pressed. - KeyboardEvent(KeyboardEvent), - /// An event from the IME is dispatched. - CompositionEvent(CompositionEvent), - /// Virtual keyboard was dismissed - IMEDismissedEvent, - /// Connected gamepad state updated - GamepadEvent(GamepadEvent), - /// A clipboard action was requested - ClipboardEvent(ClipboardEventType), -} - -impl From<&CompositorEvent> for CompositorEventVariant { - fn from(value: &CompositorEvent) -> Self { - match value { - CompositorEvent::ResizeEvent(..) => CompositorEventVariant::ResizeEvent, - CompositorEvent::MouseButtonEvent(..) => CompositorEventVariant::MouseButtonEvent, - CompositorEvent::MouseMoveEvent(..) => CompositorEventVariant::MouseMoveEvent, - CompositorEvent::TouchEvent(..) => CompositorEventVariant::TouchEvent, - CompositorEvent::WheelEvent(..) => CompositorEventVariant::WheelEvent, - CompositorEvent::KeyboardEvent(..) => CompositorEventVariant::KeyboardEvent, - CompositorEvent::CompositionEvent(..) => CompositorEventVariant::CompositionEvent, - CompositorEvent::IMEDismissedEvent => CompositorEventVariant::IMEDismissedEvent, - CompositorEvent::GamepadEvent(..) => CompositorEventVariant::GamepadEvent, - CompositorEvent::ClipboardEvent(..) => CompositorEventVariant::ClipboardEvent, - } - } +pub struct ConstellationInputEvent { + /// The hit test result of this input event, if any. + pub hit_test_result: Option, + /// The pressed mouse button state of the constellation when this input + /// event was triggered. + pub pressed_mouse_buttons: u16, + /// The [`InputEvent`] itself. + pub event: InputEvent, } /// Data needed to construct a script thread. @@ -717,7 +667,7 @@ pub enum WebDriverCommandMsg { /// Act as if keys were pressed or release in the browsing context with the given ID. KeyboardAction(BrowsingContextId, KeyboardEvent), /// Act as if the mouse was clicked in the browsing context with the given ID. - MouseButtonAction(MouseEventType, MouseButton, f32, f32), + MouseButtonAction(MouseButtonAction, MouseButton, f32, f32), /// Act as if the mouse was moved in the browsing context with the given ID. MouseMoveAction(f32, f32), /// Set the window size. diff --git a/components/webdriver_server/actions.rs b/components/webdriver_server/actions.rs index e2ba7e0bc9b..c079b699fa9 100644 --- a/components/webdriver_server/actions.rs +++ b/components/webdriver_server/actions.rs @@ -7,7 +7,7 @@ use std::time::{Duration, Instant}; use std::{cmp, thread}; use compositing_traits::ConstellationMsg; -use embedder_traits::{MouseButton, MouseEventType}; +use embedder_traits::MouseButtonAction; use ipc_channel::ipc; use keyboard_types::webdriver::KeyInputState; use script_traits::webdriver_msg::WebDriverScriptCommand; @@ -83,18 +83,6 @@ fn compute_tick_duration(tick_actions: &ActionSequence) -> u64 { duration } -fn u64_to_mouse_button(button: u64) -> Option { - if embedder_traits::MouseButton::Left as u64 == button { - Some(MouseButton::Left) - } else if MouseButton::Middle as u64 == button { - Some(MouseButton::Middle) - } else if MouseButton::Right as u64 == button { - Some(MouseButton::Right) - } else { - None - } -} - impl Handler { // https://w3c.github.io/webdriver/#dfn-dispatch-actions pub(crate) fn dispatch_actions( @@ -291,17 +279,16 @@ impl Handler { }, }); - if let Some(button) = u64_to_mouse_button(action.button) { - let cmd_msg = WebDriverCommandMsg::MouseButtonAction( - MouseEventType::MouseDown, - button, - pointer_input_state.x as f32, - pointer_input_state.y as f32, - ); - self.constellation_chan - .send(ConstellationMsg::WebDriverCommand(cmd_msg)) - .unwrap(); - } + let button = (action.button as u16).into(); + let cmd_msg = WebDriverCommandMsg::MouseButtonAction( + MouseButtonAction::Down, + button, + pointer_input_state.x as f32, + pointer_input_state.y as f32, + ); + self.constellation_chan + .send(ConstellationMsg::WebDriverCommand(cmd_msg)) + .unwrap(); } // https://w3c.github.io/webdriver/#dfn-dispatch-a-pointerup-action @@ -338,17 +325,16 @@ impl Handler { }, }); - if let Some(button) = u64_to_mouse_button(action.button) { - let cmd_msg = WebDriverCommandMsg::MouseButtonAction( - MouseEventType::MouseUp, - button, - pointer_input_state.x as f32, - pointer_input_state.y as f32, - ); - self.constellation_chan - .send(ConstellationMsg::WebDriverCommand(cmd_msg)) - .unwrap(); - } + let button = (action.button as u16).into(); + let cmd_msg = WebDriverCommandMsg::MouseButtonAction( + MouseButtonAction::Up, + button, + pointer_input_state.x as f32, + pointer_input_state.y as f32, + ); + self.constellation_chan + .send(ConstellationMsg::WebDriverCommand(cmd_msg)) + .unwrap(); } // https://w3c.github.io/webdriver/#dfn-dispatch-a-pointermove-action diff --git a/ports/servoshell/desktop/app_state.rs b/ports/servoshell/desktop/app_state.rs index d80e88aaedc..7c2f9eb1a8c 100644 --- a/ports/servoshell/desktop/app_state.rs +++ b/ports/servoshell/desktop/app_state.rs @@ -17,9 +17,9 @@ use servo::ipc_channel::ipc::IpcSender; use servo::webrender_api::units::{DeviceIntPoint, DeviceIntSize}; use servo::webrender_api::ScrollLocation; use servo::{ - AllowOrDenyRequest, AuthenticationRequest, CompositorEventVariant, FilterPattern, - GamepadHapticEffectType, LoadStatus, PermissionRequest, PromptDefinition, PromptOrigin, - PromptResult, Servo, ServoDelegate, ServoError, TouchEventType, WebView, WebViewDelegate, + AllowOrDenyRequest, AuthenticationRequest, FilterPattern, GamepadHapticEffectType, LoadStatus, + PermissionRequest, PromptDefinition, PromptOrigin, PromptResult, Servo, ServoDelegate, + ServoError, TouchEventAction, WebView, WebViewDelegate, }; use tinyfiledialogs::{self, MessageBoxIcon}; use url::Url; @@ -280,36 +280,36 @@ impl RunningAppState { 0.0, -self.inner().window.page_height() + 2.0 * LINE_HEIGHT, )); - webview.notify_scroll_event(scroll_location, origin, TouchEventType::Move); + webview.notify_scroll_event(scroll_location, origin, TouchEventAction::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, TouchEventType::Move); + webview.notify_scroll_event(scroll_location, origin, TouchEventAction::Move); }) .shortcut(Modifiers::empty(), Key::Home, || { - webview.notify_scroll_event(ScrollLocation::Start, origin, TouchEventType::Move); + webview.notify_scroll_event(ScrollLocation::Start, origin, TouchEventAction::Move); }) .shortcut(Modifiers::empty(), Key::End, || { - webview.notify_scroll_event(ScrollLocation::End, origin, TouchEventType::Move); + webview.notify_scroll_event(ScrollLocation::End, origin, TouchEventAction::Move); }) .shortcut(Modifiers::empty(), Key::ArrowUp, || { let location = ScrollLocation::Delta(Vector2D::new(0.0, 3.0 * LINE_HEIGHT)); - webview.notify_scroll_event(location, origin, TouchEventType::Move); + webview.notify_scroll_event(location, origin, TouchEventAction::Move); }) .shortcut(Modifiers::empty(), Key::ArrowDown, || { let location = ScrollLocation::Delta(Vector2D::new(0.0, -3.0 * LINE_HEIGHT)); - webview.notify_scroll_event(location, origin, TouchEventType::Move); + webview.notify_scroll_event(location, origin, TouchEventAction::Move); }) .shortcut(Modifiers::empty(), Key::ArrowLeft, || { let location = ScrollLocation::Delta(Vector2D::new(LINE_HEIGHT, 0.0)); - webview.notify_scroll_event(location, origin, TouchEventType::Move); + webview.notify_scroll_event(location, origin, TouchEventAction::Move); }) .shortcut(Modifiers::empty(), Key::ArrowRight, || { let location = ScrollLocation::Delta(Vector2D::new(-LINE_HEIGHT, 0.0)); - webview.notify_scroll_event(location, origin, TouchEventType::Move); + webview.notify_scroll_event(location, origin, TouchEventAction::Move); }); } } @@ -512,13 +512,6 @@ impl WebViewDelegate for RunningAppState { self.inner_mut().need_present = true; } - fn notify_event_delivered(&self, webview: servo::WebView, event: CompositorEventVariant) { - if let CompositorEventVariant::MouseButtonEvent = event { - webview.raise_to_top(true); - webview.focus(); - } - } - fn play_gamepad_haptic_effect( &self, _webview: servo::WebView, diff --git a/ports/servoshell/desktop/gamepad.rs b/ports/servoshell/desktop/gamepad.rs index e5c80722c4d..5a64da7bf67 100644 --- a/ports/servoshell/desktop/gamepad.rs +++ b/ports/servoshell/desktop/gamepad.rs @@ -128,7 +128,7 @@ impl GamepadSupport { } if let Some(event) = gamepad_event { - active_webview.notify_gamepad_event(event); + active_webview.notify_input_event(servo::InputEvent::Gamepad(event)); } } } diff --git a/ports/servoshell/desktop/headed_window.rs b/ports/servoshell/desktop/headed_window.rs index 24342bba16a..0f68a962fc3 100644 --- a/ports/servoshell/desktop/headed_window.rs +++ b/ports/servoshell/desktop/headed_window.rs @@ -15,7 +15,7 @@ use keyboard_types::{Modifiers, ShortcutMatcher}; use log::{debug, info}; use raw_window_handle::{HasDisplayHandle, HasWindowHandle}; use servo::compositing::windowing::{ - AnimationState, EmbedderCoordinates, MouseWindowEvent, WebRenderDebugOption, WindowMethods, + AnimationState, EmbedderCoordinates, WebRenderDebugOption, WindowMethods, }; use servo::config::opts::Opts; use servo::servo_config::pref; @@ -24,8 +24,9 @@ use servo::webrender_api::units::{DeviceIntPoint, DeviceIntRect, DeviceIntSize, use servo::webrender_api::ScrollLocation; use servo::webrender_traits::SurfmanRenderingContext; use servo::{ - ClipboardEventType, Cursor, Key, KeyState, KeyboardEvent, MouseButton as ServoMouseButton, - Theme, TouchEventType, TouchId, WebView, WheelDelta, WheelMode, + Cursor, InputEvent, Key, KeyState, KeyboardEvent, MouseButton as ServoMouseButton, + MouseButtonAction, MouseButtonEvent, MouseMoveEvent, Theme, TouchEvent, TouchEventAction, + TouchId, WebView, WheelDelta, WheelEvent, WheelMode, }; use surfman::{Context, Device, SurfaceType}; use url::Url; @@ -192,7 +193,7 @@ impl Window { for xr_window_pose in &*xr_poses { xr_window_pose.handle_xr_translation(&event); } - webview.notify_keyboard_event(event); + webview.notify_input_event(InputEvent::Keyboard(event)); } fn handle_keyboard_input(&self, state: Rc, winit_event: KeyEvent) { @@ -233,7 +234,7 @@ impl Window { for xr_window_pose in &*xr_poses { xr_window_pose.handle_xr_rotation(&winit_event, self.modifiers_state.get()); } - webview.notify_keyboard_event(keyboard_event); + webview.notify_input_event(InputEvent::Keyboard(keyboard_event)); } // servoshell also has key bindings that are visible to, and overridable by, the page. @@ -253,35 +254,46 @@ impl Window { MouseButton::Left => ServoMouseButton::Left, MouseButton::Right => ServoMouseButton::Right, MouseButton::Middle => ServoMouseButton::Middle, - _ => ServoMouseButton::Left, + MouseButton::Back => ServoMouseButton::Back, + MouseButton::Forward => ServoMouseButton::Forward, + MouseButton::Other(value) => ServoMouseButton::Other(*value), }; - let event = match action { + + let action = match action { ElementState::Pressed => { self.mouse_down_point.set(coords); self.mouse_down_button.set(Some(button)); - MouseWindowEvent::MouseDown(mouse_button, coords.to_f32()) - }, - ElementState::Released => { - let mouse_up_event = MouseWindowEvent::MouseUp(mouse_button, coords.to_f32()); - match self.mouse_down_button.get() { - None => mouse_up_event, - Some(but) if button == but => { - let pixel_dist = self.mouse_down_point.get() - coords; - let pixel_dist = - ((pixel_dist.x * pixel_dist.x + pixel_dist.y * pixel_dist.y) as f32) - .sqrt(); - if pixel_dist < max_pixel_dist { - webview.notify_pointer_button_event(mouse_up_event); - MouseWindowEvent::Click(mouse_button, coords.to_f32()) - } else { - mouse_up_event - } - }, - Some(_) => mouse_up_event, - } + MouseButtonAction::Down }, + ElementState::Released => MouseButtonAction::Up, }; - webview.notify_pointer_button_event(event); + + webview.notify_input_event(InputEvent::MouseButton(MouseButtonEvent { + action, + button: mouse_button, + point: coords.to_f32(), + })); + + // Also send a 'click' event if this is release and the press was recorded + // to be within a 10 pixels. + // + // TODO: This should be happening within the ScriptThread. + if action != MouseButtonAction::Up { + return; + } + + if let Some(mouse_down_button) = self.mouse_down_button.get() { + let pixel_dist = self.mouse_down_point.get() - coords; + let pixel_dist = + ((pixel_dist.x * pixel_dist.x + pixel_dist.y * pixel_dist.y) as f32).sqrt(); + if mouse_down_button == button && pixel_dist < max_pixel_dist { + webview.notify_input_event(InputEvent::MouseButton(MouseButtonEvent { + action: MouseButtonAction::Click, + button: mouse_button, + point: coords.to_f32(), + })); + } + } } /// Handle key events before sending them to Servo. @@ -315,13 +327,16 @@ impl Window { ); }) .shortcut(CMD_OR_CONTROL, 'X', || { - focused_webview.notify_clipboard_event(ClipboardEventType::Cut); + focused_webview + .notify_input_event(InputEvent::EditingAction(servo::EditingActionEvent::Cut)) }) .shortcut(CMD_OR_CONTROL, 'C', || { - focused_webview.notify_clipboard_event(ClipboardEventType::Copy); + focused_webview + .notify_input_event(InputEvent::EditingAction(servo::EditingActionEvent::Copy)) }) .shortcut(CMD_OR_CONTROL, 'V', || { - focused_webview.notify_clipboard_event(ClipboardEventType::Paste); + focused_webview + .notify_input_event(InputEvent::EditingAction(servo::EditingActionEvent::Paste)) }) .shortcut(Modifiers::CONTROL, Key::F9, || { focused_webview.capture_webrender(); @@ -538,7 +553,9 @@ impl WindowPortsMethods for Window { winit::event::WindowEvent::CursorMoved { position, .. } => { let position = winit_position_to_euclid_point(position); self.mouse_pos.set(position.to_i32()); - webview.notify_pointer_move_event(position.to_f32()); + webview.notify_input_event(InputEvent::MouseMove(MouseMoveEvent { + point: position.to_f32(), + })); }, winit::event::WindowEvent::MouseWheel { delta, phase, .. } => { let (mut dx, mut dy, mode) = match delta { @@ -553,14 +570,14 @@ impl WindowPortsMethods for Window { }; // Create wheel event before snapping to the major axis of movement - let wheel_delta = WheelDelta { + let delta = WheelDelta { x: dx, y: dy, z: 0.0, mode, }; let pos = self.mouse_pos.get(); - let position = Point2D::new(pos.x as f32, pos.y as f32); + let point = Point2D::new(pos.x as f32, pos.y as f32); // Scroll events snap to the major axis of movement, with vertical // preferred over horizontal. @@ -571,18 +588,18 @@ impl WindowPortsMethods for Window { } let scroll_location = ScrollLocation::Delta(Vector2D::new(dx as f32, dy as f32)); - let phase = winit_phase_to_touch_event_type(phase); + let phase = winit_phase_to_touch_event_action(phase); // Send events - webview.notify_wheel_event(wheel_delta, position); + webview.notify_input_event(InputEvent::Wheel(WheelEvent { delta, point })); webview.notify_scroll_event(scroll_location, self.mouse_pos.get(), phase); }, winit::event::WindowEvent::Touch(touch) => { - let touch_event_type = winit_phase_to_touch_event_type(touch.phase); - let id = TouchId(touch.id as i32); - let position = touch.location; - let point = Point2D::new(position.x as f32, position.y as f32); - webview.notify_touch_event(touch_event_type, id, point); + webview.notify_input_event(InputEvent::Touch(TouchEvent { + action: winit_phase_to_touch_event_action(touch.phase), + id: TouchId(touch.id as i32), + point: Point2D::new(touch.location.x as f32, touch.location.y as f32), + })); }, winit::event::WindowEvent::PinchGesture { delta, .. } => { webview.set_pinch_zoom(delta as f32 + 1.0); @@ -673,12 +690,12 @@ impl WindowMethods for Window { } } -fn winit_phase_to_touch_event_type(phase: TouchPhase) -> TouchEventType { +fn winit_phase_to_touch_event_action(phase: TouchPhase) -> TouchEventAction { match phase { - TouchPhase::Started => TouchEventType::Down, - TouchPhase::Moved => TouchEventType::Move, - TouchPhase::Ended => TouchEventType::Up, - TouchPhase::Cancelled => TouchEventType::Cancel, + TouchPhase::Started => TouchEventAction::Down, + TouchPhase::Moved => TouchEventAction::Move, + TouchPhase::Ended => TouchEventAction::Up, + TouchPhase::Cancelled => TouchEventAction::Cancel, } } diff --git a/ports/servoshell/egl/app_state.rs b/ports/servoshell/egl/app_state.rs index 0d426ddad20..23d1f8b81f4 100644 --- a/ports/servoshell/egl/app_state.rs +++ b/ports/servoshell/egl/app_state.rs @@ -11,7 +11,7 @@ use keyboard_types::{CompositionEvent, CompositionState}; use log::{debug, error, info, warn}; use servo::base::id::WebViewId; use servo::compositing::windowing::{ - AnimationState, EmbedderCoordinates, EmbedderMethods, MouseWindowEvent, WindowMethods, + AnimationState, EmbedderCoordinates, EmbedderMethods, WindowMethods, }; use servo::euclid::{Box2D, Point2D, Rect, Scale, Size2D, Vector2D}; use servo::servo_geometry::DeviceIndependentPixel; @@ -19,10 +19,11 @@ use servo::webrender_api::units::{DeviceIntRect, DeviceIntSize, DevicePixel, Dev use servo::webrender_api::ScrollLocation; use servo::webrender_traits::SurfmanRenderingContext; use servo::{ - AllowOrDenyRequest, ContextMenuResult, EmbedderProxy, EventLoopWaker, InputMethodType, Key, - KeyState, KeyboardEvent, LoadStatus, MediaSessionActionType, MediaSessionEvent, MouseButton, + AllowOrDenyRequest, ContextMenuResult, EmbedderProxy, EventLoopWaker, ImeEvent, InputEvent, + InputMethodType, Key, KeyState, KeyboardEvent, LoadStatus, MediaSessionActionType, + MediaSessionEvent, MouseButton, MouseButtonAction, MouseButtonEvent, MouseMoveEvent, NavigationRequest, PermissionRequest, PromptDefinition, PromptOrigin, PromptResult, Servo, - ServoDelegate, ServoError, TouchEventType, TouchId, WebView, WebViewDelegate, + ServoDelegate, ServoError, TouchEvent, TouchEventAction, TouchId, WebView, WebViewDelegate, }; use url::Url; @@ -445,7 +446,7 @@ impl RunningAppState { self.active_webview().notify_scroll_event( scroll_location, Point2D::new(x, y), - TouchEventType::Down, + TouchEventAction::Down, ); self.perform_updates(); } @@ -459,7 +460,7 @@ impl RunningAppState { self.active_webview().notify_scroll_event( scroll_location, Point2D::new(x, y), - TouchEventType::Move, + TouchEventAction::Move, ); self.perform_updates(); } @@ -474,69 +475,83 @@ impl RunningAppState { self.active_webview().notify_scroll_event( scroll_location, Point2D::new(x, y), - TouchEventType::Up, + TouchEventAction::Up, ); self.perform_updates(); } /// Touch event: press down pub fn touch_down(&self, x: f32, y: f32, pointer_id: i32) { - self.active_webview().notify_touch_event( - TouchEventType::Down, - TouchId(pointer_id), - Point2D::new(x, y), - ); + self.active_webview() + .notify_input_event(InputEvent::Touch(TouchEvent { + action: TouchEventAction::Down, + id: TouchId(pointer_id), + point: Point2D::new(x, y), + })); self.perform_updates(); } /// Touch event: move touching finger pub fn touch_move(&self, x: f32, y: f32, pointer_id: i32) { - self.active_webview().notify_touch_event( - TouchEventType::Move, - TouchId(pointer_id), - Point2D::new(x, y), - ); + self.active_webview() + .notify_input_event(InputEvent::Touch(TouchEvent { + action: TouchEventAction::Move, + id: TouchId(pointer_id), + point: Point2D::new(x, y), + })); self.perform_updates(); } /// Touch event: Lift touching finger pub fn touch_up(&self, x: f32, y: f32, pointer_id: i32) { - self.active_webview().notify_touch_event( - TouchEventType::Up, - TouchId(pointer_id), - Point2D::new(x, y), - ); + self.active_webview() + .notify_input_event(InputEvent::Touch(TouchEvent { + action: TouchEventAction::Up, + id: TouchId(pointer_id), + point: Point2D::new(x, y), + })); self.perform_updates(); } /// Cancel touch event pub fn touch_cancel(&self, x: f32, y: f32, pointer_id: i32) { - self.active_webview().notify_touch_event( - TouchEventType::Cancel, - TouchId(pointer_id), - Point2D::new(x, y), - ); + self.active_webview() + .notify_input_event(InputEvent::Touch(TouchEvent { + action: TouchEventAction::Cancel, + id: TouchId(pointer_id), + point: Point2D::new(x, y), + })); self.perform_updates(); } /// Register a mouse movement. pub fn mouse_move(&self, x: f32, y: f32) { self.active_webview() - .notify_pointer_move_event(Point2D::new(x, y)); + .notify_input_event(InputEvent::MouseMove(MouseMoveEvent { + point: Point2D::new(x, y), + })); self.perform_updates(); } /// Register a mouse button press. pub fn mouse_down(&self, x: f32, y: f32, button: MouseButton) { self.active_webview() - .notify_pointer_button_event(MouseWindowEvent::MouseDown(button, Point2D::new(x, y))); + .notify_input_event(InputEvent::MouseButton(MouseButtonEvent { + action: MouseButtonAction::Down, + button, + point: Point2D::new(x, y), + })); self.perform_updates(); } /// Register a mouse button release. pub fn mouse_up(&self, x: f32, y: f32, button: MouseButton) { self.active_webview() - .notify_pointer_button_event(MouseWindowEvent::MouseUp(button, Point2D::new(x, y))); + .notify_input_event(InputEvent::MouseButton(MouseButtonEvent { + action: MouseButtonAction::Up, + button, + point: Point2D::new(x, y), + })); self.perform_updates(); } @@ -564,10 +579,11 @@ impl RunningAppState { /// Perform a click. pub fn click(&self, x: f32, y: f32) { self.active_webview() - .notify_pointer_button_event(MouseWindowEvent::Click( - MouseButton::Left, - Point2D::new(x, y), - )); + .notify_input_event(InputEvent::MouseButton(MouseButtonEvent { + action: MouseButtonAction::Click, + button: MouseButton::Left, + point: Point2D::new(x, y), + })); self.perform_updates(); } @@ -577,7 +593,8 @@ impl RunningAppState { key, ..KeyboardEvent::default() }; - self.active_webview().notify_keyboard_event(key_event); + self.active_webview() + .notify_input_event(InputEvent::Keyboard(key_event)); self.perform_updates(); } @@ -587,15 +604,17 @@ impl RunningAppState { key, ..KeyboardEvent::default() }; - self.active_webview().notify_keyboard_event(key_event); + self.active_webview() + .notify_input_event(InputEvent::Keyboard(key_event)); self.perform_updates(); } pub fn ime_insert_text(&self, text: String) { - self.active_webview().notify_ime_event(CompositionEvent { - state: CompositionState::End, - data: text, - }); + self.active_webview() + .notify_input_event(InputEvent::Ime(ImeEvent::Composition(CompositionEvent { + state: CompositionState::End, + data: text, + }))); self.perform_updates(); } @@ -644,7 +663,8 @@ impl RunningAppState { pub fn ime_dismissed(&self) { info!("ime_dismissed"); - self.active_webview().notify_ime_dismissed_event(); + self.active_webview() + .notify_input_event(InputEvent::Ime(ImeEvent::Dismissed)); self.perform_updates(); }