mirror of
https://github.com/servo/servo.git
synced 2025-08-07 06:25:32 +01:00
Fix WebDriverSession::input_cancel_list
related logic (#37010)
- Remove incorrect addition to `input_cancel_list` in `dispatch_keyup_action` - For `KeyDown` and `PointerDown`, delay the addition to `input_cancel_list` until "Dispatching action algorithm" is done to match the spec. Previously the addition is done before notifying constellation. Moreover, this makes sure that `pointerUp` is appended even if `dispatch_pointerdown_action` returns early, so that [Release Actions](https://w3c.github.io/webdriver/#release-actions) always have the correct order. - Remove incorrect addition to `input_cancel_list` in `dispatch_pointerup_action`. This wrongly added "pointerdown" in [Release Actions](https://w3c.github.io/webdriver/#release-actions) - Reduce code duplication - Add TODO for PointerInputState::subtype and pointerID Testing: `./mach test-wpt -r --log-raw "D:\servo test log\perform-actions.txt" tests\wpt\tests\webdriver\tests\classic\perform_actions --product servodriver` has no new failures so no regression. There are a lot more passing tests, but I think mostly are because there is no CI for webdriver. cc @xiaochengh @jdm @PotatoCP @longvatrong111 --------- Signed-off-by: Euclid Ye <yezhizhenjiakang@gmail.com>
This commit is contained in:
parent
e2424fcec7
commit
7ac302f255
1 changed files with 87 additions and 98 deletions
|
@ -33,6 +33,9 @@ pub(crate) enum InputSourceState {
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://w3c.github.io/webdriver/#dfn-pointer-input-source
|
// https://w3c.github.io/webdriver/#dfn-pointer-input-source
|
||||||
|
// TODO: subtype is used for https://w3c.github.io/webdriver/#dfn-get-a-pointer-id
|
||||||
|
// Need to add pointer-id to the following struct
|
||||||
|
#[allow(dead_code)]
|
||||||
pub(crate) struct PointerInputState {
|
pub(crate) struct PointerInputState {
|
||||||
subtype: PointerType,
|
subtype: PointerType,
|
||||||
pressed: HashSet<u64>,
|
pressed: HashSet<u64>,
|
||||||
|
@ -142,7 +145,22 @@ impl Handler {
|
||||||
.or_insert(InputSourceState::Key(KeyInputState::new()));
|
.or_insert(InputSourceState::Key(KeyInputState::new()));
|
||||||
match action {
|
match action {
|
||||||
KeyAction::Down(action) => {
|
KeyAction::Down(action) => {
|
||||||
self.dispatch_keydown_action(source_id, action)
|
self.dispatch_keydown_action(source_id, action);
|
||||||
|
// 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(
|
||||||
|
ActionSequence {
|
||||||
|
id: source_id.into(),
|
||||||
|
actions: ActionsType::Key {
|
||||||
|
actions: vec![KeyActionItem::Key(KeyAction::Up(
|
||||||
|
KeyUpAction {
|
||||||
|
value: action.value.clone(),
|
||||||
|
},
|
||||||
|
))],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
},
|
},
|
||||||
KeyAction::Up(action) => {
|
KeyAction::Up(action) => {
|
||||||
self.dispatch_keyup_action(source_id, action)
|
self.dispatch_keyup_action(source_id, action)
|
||||||
|
@ -172,7 +190,27 @@ impl Handler {
|
||||||
match action {
|
match action {
|
||||||
PointerAction::Cancel => (),
|
PointerAction::Cancel => (),
|
||||||
PointerAction::Down(action) => {
|
PointerAction::Down(action) => {
|
||||||
self.dispatch_pointerdown_action(source_id, action)
|
self.dispatch_pointerdown_action(source_id, action);
|
||||||
|
|
||||||
|
// 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(
|
||||||
|
ActionSequence {
|
||||||
|
id: source_id.into(),
|
||||||
|
actions: ActionsType::Pointer {
|
||||||
|
parameters: PointerActionParameters {
|
||||||
|
pointer_type: parameters.pointer_type,
|
||||||
|
},
|
||||||
|
actions: vec![PointerActionItem::Pointer(
|
||||||
|
PointerAction::Up(PointerUpAction {
|
||||||
|
button: action.button,
|
||||||
|
..Default::default()
|
||||||
|
}),
|
||||||
|
)],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
},
|
},
|
||||||
PointerAction::Move(action) => self.dispatch_pointermove_action(
|
PointerAction::Move(action) => self.dispatch_pointermove_action(
|
||||||
source_id,
|
source_id,
|
||||||
|
@ -215,26 +253,18 @@ impl Handler {
|
||||||
|
|
||||||
// https://w3c.github.io/webdriver/#dfn-dispatch-a-keydown-action
|
// https://w3c.github.io/webdriver/#dfn-dispatch-a-keydown-action
|
||||||
fn dispatch_keydown_action(&mut self, source_id: &str, action: &KeyDownAction) {
|
fn dispatch_keydown_action(&mut self, source_id: &str, action: &KeyDownAction) {
|
||||||
let session = self.session.as_mut().unwrap();
|
// Step 1
|
||||||
|
|
||||||
let raw_key = action.value.chars().next().unwrap();
|
let raw_key = action.value.chars().next().unwrap();
|
||||||
let key_input_state = match session.input_state_table.get_mut(source_id).unwrap() {
|
let key_input_state = self.get_key_input_state_mut(source_id);
|
||||||
InputSourceState::Key(key_input_state) => key_input_state,
|
|
||||||
_ => unreachable!(),
|
|
||||||
};
|
|
||||||
|
|
||||||
session.input_cancel_list.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);
|
let keyboard_event = key_input_state.dispatch_keydown(raw_key);
|
||||||
let cmd_msg =
|
|
||||||
WebDriverCommandMsg::KeyboardAction(session.browsing_context_id, keyboard_event);
|
// Step 12
|
||||||
|
let cmd_msg = WebDriverCommandMsg::KeyboardAction(
|
||||||
|
self.session().unwrap().browsing_context_id,
|
||||||
|
keyboard_event,
|
||||||
|
);
|
||||||
self.constellation_chan
|
self.constellation_chan
|
||||||
.send(EmbedderToConstellationMessage::WebDriverCommand(cmd_msg))
|
.send(EmbedderToConstellationMessage::WebDriverCommand(cmd_msg))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
@ -242,71 +272,57 @@ impl Handler {
|
||||||
|
|
||||||
// https://w3c.github.io/webdriver/#dfn-dispatch-a-keyup-action
|
// https://w3c.github.io/webdriver/#dfn-dispatch-a-keyup-action
|
||||||
fn dispatch_keyup_action(&mut self, source_id: &str, action: &KeyUpAction) {
|
fn dispatch_keyup_action(&mut self, source_id: &str, action: &KeyUpAction) {
|
||||||
let session = self.session.as_mut().unwrap();
|
// Step 1
|
||||||
|
|
||||||
let raw_key = action.value.chars().next().unwrap();
|
let raw_key = action.value.chars().next().unwrap();
|
||||||
let key_input_state = match session.input_state_table.get_mut(source_id).unwrap() {
|
let key_input_state = self.get_key_input_state_mut(source_id);
|
||||||
InputSourceState::Key(key_input_state) => key_input_state,
|
|
||||||
_ => unreachable!(),
|
|
||||||
};
|
|
||||||
|
|
||||||
session.input_cancel_list.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) {
|
if let Some(keyboard_event) = key_input_state.dispatch_keyup(raw_key) {
|
||||||
let cmd_msg =
|
// Step 12
|
||||||
WebDriverCommandMsg::KeyboardAction(session.browsing_context_id, keyboard_event);
|
let cmd_msg = WebDriverCommandMsg::KeyboardAction(
|
||||||
|
self.session().unwrap().browsing_context_id,
|
||||||
|
keyboard_event,
|
||||||
|
);
|
||||||
self.constellation_chan
|
self.constellation_chan
|
||||||
.send(EmbedderToConstellationMessage::WebDriverCommand(cmd_msg))
|
.send(EmbedderToConstellationMessage::WebDriverCommand(cmd_msg))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
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,
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
key_input_state
|
||||||
|
}
|
||||||
|
|
||||||
// https://w3c.github.io/webdriver/#dfn-dispatch-a-pointerdown-action
|
// https://w3c.github.io/webdriver/#dfn-dispatch-a-pointerdown-action
|
||||||
pub(crate) fn dispatch_pointerdown_action(
|
pub(crate) fn dispatch_pointerdown_action(
|
||||||
&mut self,
|
&mut self,
|
||||||
source_id: &str,
|
source_id: &str,
|
||||||
action: &PointerDownAction,
|
action: &PointerDownAction,
|
||||||
) {
|
) {
|
||||||
let session = self.session.as_mut().unwrap();
|
let webview_id = self.session().unwrap().webview_id;
|
||||||
|
let pointer_input_state = self.get_pointer_input_state_mut(source_id);
|
||||||
let pointer_input_state = match session.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) {
|
if pointer_input_state.pressed.contains(&action.button) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
pointer_input_state.pressed.insert(action.button);
|
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,
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
))],
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
let cmd_msg = WebDriverCommandMsg::MouseButtonAction(
|
let cmd_msg = WebDriverCommandMsg::MouseButtonAction(
|
||||||
session.webview_id,
|
webview_id,
|
||||||
MouseButtonAction::Down,
|
MouseButtonAction::Down,
|
||||||
action.button.into(),
|
action.button.into(),
|
||||||
pointer_input_state.x as f32,
|
pointer_input_state.x as f32,
|
||||||
|
@ -319,39 +335,16 @@ impl Handler {
|
||||||
|
|
||||||
// https://w3c.github.io/webdriver/#dfn-dispatch-a-pointerup-action
|
// https://w3c.github.io/webdriver/#dfn-dispatch-a-pointerup-action
|
||||||
pub(crate) fn dispatch_pointerup_action(&mut self, source_id: &str, action: &PointerUpAction) {
|
pub(crate) fn dispatch_pointerup_action(&mut self, source_id: &str, action: &PointerUpAction) {
|
||||||
let session = self.session.as_mut().unwrap();
|
let webview_id = self.session().unwrap().webview_id;
|
||||||
|
let pointer_input_state = self.get_pointer_input_state_mut(source_id);
|
||||||
let pointer_input_state = match session.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) {
|
if !pointer_input_state.pressed.contains(&action.button) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
pointer_input_state.pressed.remove(&action.button);
|
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,
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
))],
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
let cmd_msg = WebDriverCommandMsg::MouseButtonAction(
|
let cmd_msg = WebDriverCommandMsg::MouseButtonAction(
|
||||||
session.webview_id,
|
webview_id,
|
||||||
MouseButtonAction::Up,
|
MouseButtonAction::Up,
|
||||||
action.button.into(),
|
action.button.into(),
|
||||||
pointer_input_state.x as f32,
|
pointer_input_state.x as f32,
|
||||||
|
@ -432,12 +425,9 @@ impl Handler {
|
||||||
target_y: f64,
|
target_y: f64,
|
||||||
tick_start: Instant,
|
tick_start: Instant,
|
||||||
) {
|
) {
|
||||||
let session = self.session.as_mut().unwrap();
|
let webview_id = self.session().unwrap().webview_id;
|
||||||
let pointer_input_state = match session.input_state_table.get_mut(source_id).unwrap() {
|
let constellation_chan = self.constellation_chan.clone();
|
||||||
InputSourceState::Pointer(pointer_input_state) => pointer_input_state,
|
let pointer_input_state = self.get_pointer_input_state_mut(source_id);
|
||||||
_ => unreachable!(),
|
|
||||||
};
|
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
// Step 1
|
// Step 1
|
||||||
let time_delta = tick_start.elapsed().as_millis();
|
let time_delta = tick_start.elapsed().as_millis();
|
||||||
|
@ -469,10 +459,9 @@ impl Handler {
|
||||||
// Step 7
|
// Step 7
|
||||||
if x != current_x || y != current_y {
|
if x != current_x || y != current_y {
|
||||||
// Step 7.2
|
// Step 7.2
|
||||||
let cmd_msg =
|
let cmd_msg = WebDriverCommandMsg::MouseMoveAction(webview_id, x as f32, y as f32);
|
||||||
WebDriverCommandMsg::MouseMoveAction(session.webview_id, x as f32, y as f32);
|
|
||||||
//TODO: Need Synchronization here before updating `pointer_input_state`
|
//TODO: Need Synchronization here before updating `pointer_input_state`
|
||||||
self.constellation_chan
|
constellation_chan
|
||||||
.send(EmbedderToConstellationMessage::WebDriverCommand(cmd_msg))
|
.send(EmbedderToConstellationMessage::WebDriverCommand(cmd_msg))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
// Step 7.3
|
// Step 7.3
|
||||||
|
@ -567,7 +556,7 @@ impl Handler {
|
||||||
mut curr_delta_y: i64,
|
mut curr_delta_y: i64,
|
||||||
tick_start: Instant,
|
tick_start: Instant,
|
||||||
) {
|
) {
|
||||||
let session = self.session.as_mut().unwrap();
|
let session = self.session_mut().unwrap();
|
||||||
|
|
||||||
// Step 1
|
// Step 1
|
||||||
let time_delta = tick_start.elapsed().as_millis();
|
let time_delta = tick_start.elapsed().as_millis();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue