diff options
Diffstat (limited to 'components/webdriver_server/actions.rs')
-rw-r--r-- | components/webdriver_server/actions.rs | 250 |
1 files changed, 192 insertions, 58 deletions
diff --git a/components/webdriver_server/actions.rs b/components/webdriver_server/actions.rs index 7965120b0fd..cde418f920c 100644 --- a/components/webdriver_server/actions.rs +++ b/components/webdriver_server/actions.rs @@ -98,20 +98,83 @@ fn compute_tick_duration(tick_actions: &ActionSequence) -> u64 { impl Handler { // https://w3c.github.io/webdriver/#dfn-dispatch-actions pub(crate) fn dispatch_actions( - &mut self, + &self, actions_by_tick: &[ActionSequence], ) -> Result<(), ErrorStatus> { + // Step 1. Wait for an action queue token with input state. + let new_token = self.id_generator.next(); + assert!(self.current_action_id.get().is_none()); + self.current_action_id.set(Some(new_token)); + + // Step 2. Let actions result be the result of dispatch actions inner. + let res = self.dispatch_actions_inner(actions_by_tick); + + // Step 3. Dequeue input state's actions queue. + self.current_action_id.set(None); + + // Step 4. Return actions result. + res + } + + // https://w3c.github.io/webdriver/#dfn-dispatch-actions-inner + fn dispatch_actions_inner( + &self, + actions_by_tick: &[ActionSequence], + ) -> Result<(), ErrorStatus> { + // Step 1. For each item tick actions in actions by tick for tick_actions in actions_by_tick.iter() { + // Step 1.2. Let tick duration be the result of + // computing the tick duration with argument tick actions. let tick_duration = compute_tick_duration(tick_actions); + + // Step 1.3. Try to dispatch tick actions self.dispatch_tick_actions(tick_actions, tick_duration)?; + + // Step 1.4. Wait for + // The user agent event loop has spun enough times to process the DOM events + // generated by the last invocation of the dispatch tick actions steps. + // + // To ensure we wait for all events to be processed, only the last event in + // this tick action step holds the message id. + // Whenever a new event is generated, the message id is passed to it. + // + // TO-DO: remove the first match after webdriver_id is implemented in all commands + match tick_actions.actions { + ActionsType::Key { .. } | ActionsType::Wheel { .. } | ActionsType::Null { .. } => { + return Ok(()); + }, + _ => {}, + } + + match self.constellation_receiver.recv() { + Ok(response) => { + let current_waiting_id = self + .current_action_id + .get() + .expect("Current id should be set before dispat_actions_inner is called"); + + if current_waiting_id != response.id { + dbg!("Dispatch actions completed with wrong id in response"); + return Err(ErrorStatus::UnknownError); + } + }, + Err(error) => { + dbg!("Dispatch actions completed with IPC error: {:?}", error); + return Err(ErrorStatus::UnknownError); + }, + }; } + + // Step 2. Return success with data null. + dbg!("Dispatch actions completed successfully"); Ok(()) } - fn dispatch_general_action(&mut self, source_id: &str) { - self.session_mut() + fn dispatch_general_action(&self, source_id: &str) { + self.session() .unwrap() .input_state_table + .borrow_mut() .entry(source_id.to_string()) .or_insert(InputSourceState::Null); // https://w3c.github.io/webdriver/#dfn-dispatch-a-pause-action @@ -120,7 +183,7 @@ impl Handler { // https://w3c.github.io/webdriver/#dfn-dispatch-tick-actions fn dispatch_tick_actions( - &mut self, + &self, tick_actions: &ActionSequence, tick_duration: u64, ) -> Result<(), ErrorStatus> { @@ -138,9 +201,10 @@ impl Handler { self.dispatch_general_action(source_id); }, KeyActionItem::Key(action) => { - self.session_mut() + self.session() .unwrap() .input_state_table + .borrow_mut() .entry(source_id.to_string()) .or_insert(InputSourceState::Key(KeyInputState::new())); match action { @@ -149,7 +213,7 @@ impl Handler { // Step 9. If subtype is "keyDown", append a copy of action // object with the subtype property changed to "keyUp" to // input state's input cancel list. - self.session_mut().unwrap().input_cancel_list.push( + self.session().unwrap().input_cancel_list.borrow_mut().push( ActionSequence { id: source_id.into(), actions: ActionsType::Key { @@ -180,9 +244,10 @@ impl Handler { self.dispatch_general_action(source_id); }, PointerActionItem::Pointer(action) => { - self.session_mut() + self.session() .unwrap() .input_state_table + .borrow_mut() .entry(source_id.to_string()) .or_insert(InputSourceState::Pointer(PointerInputState::new( ¶meters.pointer_type, @@ -195,7 +260,7 @@ impl Handler { // Step 10. If subtype is "pointerDown", append a copy of action // object with the subtype property changed to "pointerUp" to // input state's input cancel list. - self.session_mut().unwrap().input_cancel_list.push( + self.session().unwrap().input_cancel_list.borrow_mut().push( ActionSequence { id: source_id.into(), actions: ActionsType::Pointer { @@ -232,9 +297,10 @@ impl Handler { self.dispatch_general_action(source_id) }, WheelActionItem::Wheel(action) => { - self.session_mut() + self.session() .unwrap() .input_state_table + .borrow_mut() .entry(source_id.to_string()) .or_insert(InputSourceState::Wheel); match action { @@ -252,12 +318,25 @@ impl Handler { } // https://w3c.github.io/webdriver/#dfn-dispatch-a-keydown-action - fn dispatch_keydown_action(&mut self, source_id: &str, action: &KeyDownAction) { - // Step 1 + fn dispatch_keydown_action(&self, source_id: &str, action: &KeyDownAction) { + let session = self.session().unwrap(); + let raw_key = action.value.chars().next().unwrap(); - let key_input_state = self.get_key_input_state_mut(source_id); + let mut input_state_table = session.input_state_table.borrow_mut(); + let key_input_state = match input_state_table.get_mut(source_id).unwrap() { + InputSourceState::Key(key_input_state) => key_input_state, + _ => unreachable!(), + }; + + session.input_cancel_list.borrow_mut().push(ActionSequence { + id: source_id.into(), + actions: ActionsType::Key { + actions: vec![KeyActionItem::Key(KeyAction::Up(KeyUpAction { + value: action.value.clone(), + }))], + }, + }); - // Step 2 - 11. Done by `keyboard-types` crate. let keyboard_event = key_input_state.dispatch_keydown(raw_key); // Step 12 @@ -271,12 +350,25 @@ impl Handler { } // https://w3c.github.io/webdriver/#dfn-dispatch-a-keyup-action - fn dispatch_keyup_action(&mut self, source_id: &str, action: &KeyUpAction) { - // Step 1 + fn dispatch_keyup_action(&self, source_id: &str, action: &KeyUpAction) { + let session = self.session().unwrap(); + let raw_key = action.value.chars().next().unwrap(); - let key_input_state = self.get_key_input_state_mut(source_id); + let mut input_state_table = session.input_state_table.borrow_mut(); + let key_input_state = match input_state_table.get_mut(source_id).unwrap() { + InputSourceState::Key(key_input_state) => key_input_state, + _ => unreachable!(), + }; + + session.input_cancel_list.borrow_mut().push(ActionSequence { + id: source_id.into(), + actions: ActionsType::Key { + actions: vec![KeyActionItem::Key(KeyAction::Up(KeyUpAction { + value: action.value.clone(), + }))], + }, + }); - // Step 2 - 11. Done by `keyboard-types` crate. if let Some(keyboard_event) = key_input_state.dispatch_keyup(raw_key) { // Step 12 let cmd_msg = WebDriverCommandMsg::KeyboardAction( @@ -289,44 +381,49 @@ impl Handler { } } - fn get_pointer_input_state_mut(&mut self, source_id: &str) -> &mut PointerInputState { - let session = self.session_mut().unwrap(); - let pointer_input_state = match session.input_state_table.get_mut(source_id).unwrap() { - InputSourceState::Pointer(pointer_input_state) => pointer_input_state, - _ => unreachable!(), - }; - pointer_input_state - } + /// <https://w3c.github.io/webdriver/#dfn-dispatch-a-pointerdown-action> + pub(crate) fn dispatch_pointerdown_action(&self, source_id: &str, action: &PointerDownAction) { + let session = self.session().unwrap(); - fn get_key_input_state_mut(&mut self, source_id: &str) -> &mut KeyInputState { - let session = self.session_mut().unwrap(); - let key_input_state = match session.input_state_table.get_mut(source_id).unwrap() { - InputSourceState::Key(key_input_state) => key_input_state, + let mut input_state_table = session.input_state_table.borrow_mut(); + let pointer_input_state = match input_state_table.get_mut(source_id).unwrap() { + InputSourceState::Pointer(pointer_input_state) => pointer_input_state, _ => unreachable!(), }; - key_input_state - } - - // https://w3c.github.io/webdriver/#dfn-dispatch-a-pointerdown-action - pub(crate) fn dispatch_pointerdown_action( - &mut self, - source_id: &str, - action: &PointerDownAction, - ) { - let webview_id = self.session().unwrap().webview_id; - let pointer_input_state = self.get_pointer_input_state_mut(source_id); if pointer_input_state.pressed.contains(&action.button) { return; } pointer_input_state.pressed.insert(action.button); + session.input_cancel_list.borrow_mut().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, + ..Default::default() + }, + ))], + }, + }); + + let msg_id = self.current_action_id.get().unwrap(); let cmd_msg = WebDriverCommandMsg::MouseButtonAction( - webview_id, + session.webview_id, MouseButtonAction::Down, action.button.into(), pointer_input_state.x as f32, pointer_input_state.y as f32, + msg_id, + self.constellation_sender.clone(), ); self.constellation_chan .send(EmbedderToConstellationMessage::WebDriverCommand(cmd_msg)) @@ -334,21 +431,48 @@ impl Handler { } // https://w3c.github.io/webdriver/#dfn-dispatch-a-pointerup-action - pub(crate) fn dispatch_pointerup_action(&mut self, source_id: &str, action: &PointerUpAction) { - let webview_id = self.session().unwrap().webview_id; - let pointer_input_state = self.get_pointer_input_state_mut(source_id); + pub(crate) fn dispatch_pointerup_action(&self, source_id: &str, action: &PointerUpAction) { + let session = self.session().unwrap(); + + let mut input_state_table = session.input_state_table.borrow_mut(); + let pointer_input_state = match input_state_table.get_mut(source_id).unwrap() { + InputSourceState::Pointer(pointer_input_state) => pointer_input_state, + _ => unreachable!(), + }; if !pointer_input_state.pressed.contains(&action.button) { return; } pointer_input_state.pressed.remove(&action.button); + session.input_cancel_list.borrow_mut().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, + ..Default::default() + }, + ))], + }, + }); + + let msg_id = self.current_action_id.get().unwrap(); let cmd_msg = WebDriverCommandMsg::MouseButtonAction( - webview_id, + session.webview_id, MouseButtonAction::Up, action.button.into(), pointer_input_state.x as f32, pointer_input_state.y as f32, + msg_id, + self.constellation_sender.clone(), ); self.constellation_chan .send(EmbedderToConstellationMessage::WebDriverCommand(cmd_msg)) @@ -357,7 +481,7 @@ impl Handler { // https://w3c.github.io/webdriver/#dfn-dispatch-a-pointermove-action pub(crate) fn dispatch_pointermove_action( - &mut self, + &self, source_id: &str, action: &PointerMoveAction, tick_duration: u64, @@ -370,10 +494,10 @@ impl Handler { // Steps 3 - 4 let (start_x, start_y) = match self - .session - .as_ref() + .session() .unwrap() .input_state_table + .borrow_mut() .get(source_id) .unwrap() { @@ -416,7 +540,7 @@ impl Handler { /// <https://w3c.github.io/webdriver/#dfn-perform-a-pointer-move> #[allow(clippy::too_many_arguments)] fn perform_pointer_move( - &mut self, + &self, source_id: &str, duration: u64, start_x: f64, @@ -425,9 +549,13 @@ impl Handler { target_y: f64, tick_start: Instant, ) { - let webview_id = self.session().unwrap().webview_id; - let constellation_chan = self.constellation_chan.clone(); - let pointer_input_state = self.get_pointer_input_state_mut(source_id); + let session = self.session().unwrap(); + let mut input_state_table = session.input_state_table.borrow_mut(); + let pointer_input_state = match input_state_table.get_mut(source_id).unwrap() { + InputSourceState::Pointer(pointer_input_state) => pointer_input_state, + _ => unreachable!(), + }; + loop { // Step 1 let time_delta = tick_start.elapsed().as_millis(); @@ -459,9 +587,15 @@ impl Handler { // Step 7 if x != current_x || y != current_y { // Step 7.2 - let cmd_msg = WebDriverCommandMsg::MouseMoveAction(webview_id, x as f32, y as f32); - //TODO: Need Synchronization here before updating `pointer_input_state` - constellation_chan + let msg_id = self.current_action_id.get().unwrap(); + let cmd_msg = WebDriverCommandMsg::MouseMoveAction( + session.webview_id, + x as f32, + y as f32, + msg_id, + self.constellation_sender.clone(), + ); + self.constellation_chan .send(EmbedderToConstellationMessage::WebDriverCommand(cmd_msg)) .unwrap(); // Step 7.3 @@ -481,7 +615,7 @@ impl Handler { /// <https://w3c.github.io/webdriver/#dfn-dispatch-a-scroll-action> fn dispatch_scroll_action( - &mut self, + &self, action: &WheelScrollAction, tick_duration: u64, ) -> Result<(), ErrorStatus> { @@ -546,7 +680,7 @@ impl Handler { /// <https://w3c.github.io/webdriver/#dfn-perform-a-scroll> #[allow(clippy::too_many_arguments)] fn perform_scroll( - &mut self, + &self, duration: u64, x: i64, y: i64, @@ -556,7 +690,7 @@ impl Handler { mut curr_delta_y: i64, tick_start: Instant, ) { - let session = self.session_mut().unwrap(); + let session = self.session().unwrap(); // Step 1 let time_delta = tick_start.elapsed().as_millis(); |