From 225cecf66126fee386fd071cc9d8caeb8503f536 Mon Sep 17 00:00:00 2001 From: George Roman Date: Sat, 27 Jul 2019 00:20:50 +0300 Subject: [PATCH] Implement pointerDown and pointerUp webdriver actions --- components/compositing/compositor.rs | 17 +++ components/compositing/compositor_thread.rs | 5 +- components/constellation/constellation.rs | 9 ++ components/script_traits/lib.rs | 2 + components/webdriver_server/actions.rs | 155 ++++++++++++++++---- 5 files changed, 160 insertions(+), 28 deletions(-) diff --git a/components/compositing/compositor.rs b/components/compositing/compositor.rs index 98de79cc3f8a..7ac80ee48323 100644 --- a/components/compositing/compositor.rs +++ b/components/compositing/compositor.rs @@ -518,6 +518,23 @@ impl IOCompositor { } }, + ( + Msg::WebDriverMouseButtonEvent(mouse_event_type, mouse_button, x, y), + ShutdownState::NotShuttingDown, + ) => { + self.on_mouse_window_event_class(match mouse_event_type { + MouseEventType::Click => { + MouseWindowEvent::Click(mouse_button, DevicePoint::new(x, y)) + }, + MouseEventType::MouseDown => { + MouseWindowEvent::MouseDown(mouse_button, DevicePoint::new(x, y)) + }, + MouseEventType::MouseUp => { + MouseWindowEvent::MouseUp(mouse_button, DevicePoint::new(x, y)) + }, + }); + }, + (Msg::PendingPaintMetric(pipeline_id, epoch), _) => { self.pending_paint_metrics.insert(pipeline_id, epoch); }, diff --git a/components/compositing/compositor_thread.rs b/components/compositing/compositor_thread.rs index 9250d25e5bf1..f095ab65b1c4 100644 --- a/components/compositing/compositor_thread.rs +++ b/components/compositing/compositor_thread.rs @@ -14,7 +14,7 @@ use msg::constellation_msg::{PipelineId, TopLevelBrowsingContextId}; use net_traits::image::base::Image; use profile_traits::mem; use profile_traits::time; -use script_traits::{AnimationState, ConstellationMsg, EventResult}; +use script_traits::{AnimationState, ConstellationMsg, EventResult, MouseButton, MouseEventType}; use std::fmt::{Debug, Error, Formatter}; use style_traits::viewport::ViewportConstraints; use webrender_api; @@ -106,6 +106,8 @@ pub enum Msg { PendingPaintMetric(PipelineId, Epoch), /// The load of a page has completed LoadComplete(TopLevelBrowsingContextId), + /// WebDriver mouse button event + WebDriverMouseButtonEvent(MouseEventType, MouseButton, f32, f32), /// Get Window Informations size and position. GetClientWindow(IpcSender<(DeviceIntSize, DeviceIntPoint)>), @@ -132,6 +134,7 @@ impl Debug for Msg { Msg::Dispatch(..) => write!(f, "Dispatch"), Msg::PendingPaintMetric(..) => write!(f, "PendingPaintMetric"), Msg::LoadComplete(..) => write!(f, "LoadComplete"), + Msg::WebDriverMouseButtonEvent(..) => write!(f, "WebDriverMouseButtonEvent"), Msg::GetClientWindow(..) => write!(f, "GetClientWindow"), Msg::GetScreenSize(..) => write!(f, "GetScreenSize"), Msg::GetScreenAvailSize(..) => write!(f, "GetScreenAvailSize"), diff --git a/components/constellation/constellation.rs b/components/constellation/constellation.rs index ce163430d0a4..b443163f8d5f 100644 --- a/components/constellation/constellation.rs +++ b/components/constellation/constellation.rs @@ -3490,6 +3490,15 @@ where return self.handle_send_error(pipeline_id, e); } }, + WebDriverCommandMsg::MouseButtonAction(mouse_event_type, mouse_button, x, y) => { + self.compositor_proxy + .send(ToCompositorMsg::WebDriverMouseButtonEvent( + mouse_event_type, + mouse_button, + x, + y, + )); + }, WebDriverCommandMsg::TakeScreenshot(_, reply) => { self.compositor_proxy .send(ToCompositorMsg::CreatePng(reply)); diff --git a/components/script_traits/lib.rs b/components/script_traits/lib.rs index 6a293c68ed0f..5aac6b47e5e7 100644 --- a/components/script_traits/lib.rs +++ b/components/script_traits/lib.rs @@ -800,6 +800,8 @@ pub enum WebDriverCommandMsg { SendKeys(BrowsingContextId, Vec), /// 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), /// Set the window size. SetWindowSize( TopLevelBrowsingContextId, diff --git a/components/webdriver_server/actions.rs b/components/webdriver_server/actions.rs index e86fd7ad0591..0182a16bac31 100644 --- a/components/webdriver_server/actions.rs +++ b/components/webdriver_server/actions.rs @@ -4,12 +4,15 @@ use crate::Handler; use keyboard_types::webdriver::KeyInputState; -use script_traits::{ConstellationMsg, WebDriverCommandMsg}; +use script_traits::{ConstellationMsg, MouseButton, MouseEventType, WebDriverCommandMsg}; use std::cmp; use std::collections::HashSet; use webdriver::actions::{ActionSequence, ActionsType, GeneralAction, NullActionItem}; use webdriver::actions::{KeyAction, KeyActionItem, KeyDownAction, KeyUpAction}; -use webdriver::actions::{PointerAction, PointerActionItem, PointerType}; +use webdriver::actions::{ + PointerAction, PointerActionItem, PointerActionParameters, PointerDownAction, +}; +use webdriver::actions::{PointerType, PointerUpAction}; // https://w3c.github.io/webdriver/#dfn-input-source-state pub(crate) enum InputSourceState { @@ -20,23 +23,23 @@ pub(crate) enum InputSourceState { // https://w3c.github.io/webdriver/#dfn-pointer-input-source pub(crate) struct PointerInputState { - _subtype: PointerType, - _pressed: HashSet, - _x: u64, - _y: u64, + subtype: PointerType, + pressed: HashSet, + x: u64, + y: u64, } impl PointerInputState { pub fn new(subtype: &PointerType) -> PointerInputState { PointerInputState { - _subtype: match subtype { + subtype: match subtype { PointerType::Mouse => PointerType::Mouse, PointerType::Pen => PointerType::Pen, PointerType::Touch => PointerType::Touch, }, - _pressed: HashSet::new(), - _x: 0, - _y: 0, + pressed: HashSet::new(), + x: 0, + y: 0, } } } @@ -69,6 +72,18 @@ fn compute_tick_duration(tick_actions: &ActionSequence) -> u64 { duration } +fn u64_to_mouse_button(button: u64) -> Option { + if 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(&mut self, actions_by_tick: &[ActionSequence]) { @@ -89,7 +104,7 @@ impl Handler { } // https://w3c.github.io/webdriver/#dfn-dispatch-tick-actions - fn dispatch_tick_actions(&mut self, tick_actions: &ActionSequence, tick_duration: u64) { + fn dispatch_tick_actions(&mut self, tick_actions: &ActionSequence, _tick_duration: u64) { let source_id = &tick_actions.id; match &tick_actions.actions { ActionsType::Null { actions } => { @@ -111,10 +126,10 @@ impl Handler { .or_insert(InputSourceState::Key(KeyInputState::new())); match action { KeyAction::Down(action) => { - self.dispatch_keydown_action(&source_id, &action, tick_duration) + self.dispatch_keydown_action(&source_id, &action) }, KeyAction::Up(action) => { - self.dispatch_keyup_action(&source_id, &action, tick_duration) + self.dispatch_keyup_action(&source_id, &action) }, }; }, @@ -140,9 +155,13 @@ impl Handler { ))); match action { PointerAction::Cancel => (), - PointerAction::Down(_action) => (), + PointerAction::Down(action) => { + self.dispatch_pointerdown_action(&source_id, &action) + }, PointerAction::Move(_action) => (), - PointerAction::Up(_action) => (), + PointerAction::Up(action) => { + self.dispatch_pointerup_action(&source_id, &action) + }, } }, } @@ -152,12 +171,7 @@ impl Handler { } // https://w3c.github.io/webdriver/#dfn-dispatch-a-keydown-action - fn dispatch_keydown_action( - &mut self, - source_id: &str, - action: &KeyDownAction, - _tick_duration: u64, - ) { + fn dispatch_keydown_action(&mut self, source_id: &str, action: &KeyDownAction) { let session = self.session.as_mut().unwrap(); let raw_key = action.value.chars().next().unwrap(); @@ -185,12 +199,7 @@ impl Handler { } // https://w3c.github.io/webdriver/#dfn-dispatch-a-keyup-action - fn dispatch_keyup_action( - &mut self, - source_id: &str, - action: &KeyUpAction, - _tick_duration: u64, - ) { + fn dispatch_keyup_action(&mut self, source_id: &str, action: &KeyUpAction) { let session = self.session.as_mut().unwrap(); let raw_key = action.value.chars().next().unwrap(); @@ -217,4 +226,96 @@ impl Handler { .unwrap(); } } + + // https://w3c.github.io/webdriver/#dfn-dispatch-a-pointerdown-action + fn dispatch_pointerdown_action(&mut self, source_id: &str, action: &PointerDownAction) { + let session = self.session.as_mut().unwrap(); + + let pointer_input_state = match session.input_state_table.get_mut(source_id).unwrap() { + InputSourceState::Null => unreachable!(), + InputSourceState::Key(_) => unreachable!(), + InputSourceState::Pointer(pointer_input_state) => pointer_input_state, + }; + + if pointer_input_state.pressed.contains(&action.button) { + return; + } + pointer_input_state.pressed.insert(action.button); + + session.input_cancel_list.push(ActionSequence { + id: source_id.into(), + actions: ActionsType::Pointer { + parameters: PointerActionParameters { + pointer_type: match pointer_input_state.subtype { + PointerType::Mouse => PointerType::Mouse, + PointerType::Pen => PointerType::Pen, + PointerType::Touch => PointerType::Touch, + }, + }, + actions: vec![PointerActionItem::Pointer(PointerAction::Up( + PointerUpAction { + button: action.button, + }, + ))], + }, + }); + + 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(); + } + } + + // https://w3c.github.io/webdriver/#dfn-dispatch-a-pointerup-action + fn dispatch_pointerup_action(&mut self, source_id: &str, action: &PointerUpAction) { + let session = self.session.as_mut().unwrap(); + + let pointer_input_state = match session.input_state_table.get_mut(source_id).unwrap() { + InputSourceState::Null => unreachable!(), + InputSourceState::Key(_) => unreachable!(), + InputSourceState::Pointer(pointer_input_state) => pointer_input_state, + }; + + if !pointer_input_state.pressed.contains(&action.button) { + return; + } + pointer_input_state.pressed.remove(&action.button); + + session.input_cancel_list.push(ActionSequence { + id: source_id.into(), + actions: ActionsType::Pointer { + parameters: PointerActionParameters { + pointer_type: match pointer_input_state.subtype { + PointerType::Mouse => PointerType::Mouse, + PointerType::Pen => PointerType::Pen, + PointerType::Touch => PointerType::Touch, + }, + }, + actions: vec![PointerActionItem::Pointer(PointerAction::Down( + PointerDownAction { + button: action.button, + }, + ))], + }, + }); + + 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(); + } + } }