Commit 432b256b authored by Lan Wei's avatar Lan Wei Committed by Commit Bot

[ChromeDriver] Refactor ExecutePerformActions function

In ExecutePerformActions function, we dispatch key events first, mouse
events then touch events, but we should dispatch whatever actions come
first in the action sequence. This CL changes high level of structures
of processing actions and dispatching events in the action sequence,
and I still need to refactor some details when procession the actions
in a following CL.

Bug: 606367
Change-Id: I46e02e547d0e5d5c2ddcdc949efc6b141142ea2c
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1759855Reviewed-by: default avatarJohn Chen <johnchen@chromium.org>
Commit-Queue: Lan Wei <lanwei@chromium.org>
Cr-Commit-Position: refs/heads/master@{#688692}
parent d634937a
...@@ -23,8 +23,6 @@ MouseEvent::MouseEvent(MouseEventType type, ...@@ -23,8 +23,6 @@ MouseEvent::MouseEvent(MouseEventType type,
modifiers(modifiers), modifiers(modifiers),
buttons(buttons), buttons(buttons),
click_count(click_count), click_count(click_count),
origin(kViewPort),
element_id(std::string()),
pointer_type(kMouse) {} pointer_type(kMouse) {}
MouseEvent::MouseEvent(const MouseEvent& other) = default; MouseEvent::MouseEvent(const MouseEvent& other) = default;
...@@ -35,13 +33,11 @@ TouchEvent::TouchEvent(TouchEventType type, int x, int y) ...@@ -35,13 +33,11 @@ TouchEvent::TouchEvent(TouchEventType type, int x, int y)
: type(type), : type(type),
x(x), x(x),
y(y), y(y),
origin(kViewPort),
radiusX(1.0), radiusX(1.0),
radiusY(1.0), radiusY(1.0),
rotationAngle(0.0), rotationAngle(0.0),
force(1.0), force(1.0),
id(0), id(0),
element_id(std::string()),
dispatch(true) {} dispatch(true) {}
TouchEvent::TouchEvent(const TouchEvent& other) = default; TouchEvent::TouchEvent(const TouchEvent& other) = default;
......
...@@ -54,8 +54,6 @@ struct MouseEvent { ...@@ -54,8 +54,6 @@ struct MouseEvent {
int buttons; int buttons;
// |click_count| should not be negative. // |click_count| should not be negative.
int click_count; int click_count;
OriginType origin;
std::string element_id;
PointerType pointer_type; PointerType pointer_type;
}; };
...@@ -78,13 +76,11 @@ struct TouchEvent { ...@@ -78,13 +76,11 @@ struct TouchEvent {
TouchEventType type; TouchEventType type;
int x; int x;
int y; int y;
OriginType origin;
double radiusX; double radiusX;
double radiusY; double radiusY;
double rotationAngle; double rotationAngle;
double force; double force;
int id; int id;
std::string element_id;
bool dispatch; bool dispatch;
}; };
......
...@@ -617,7 +617,7 @@ Status ConvertKeysToKeyEvents(const base::string16& client_keys, ...@@ -617,7 +617,7 @@ Status ConvertKeysToKeyEvents(const base::string16& client_keys,
Status ConvertKeyActionToKeyEvent(const base::DictionaryValue* action_object, Status ConvertKeyActionToKeyEvent(const base::DictionaryValue* action_object,
base::DictionaryValue* input_state, base::DictionaryValue* input_state,
bool is_key_down, bool is_key_down,
std::vector<KeyEvent>* key_events) { std::list<KeyEvent>* key_events) {
std::string raw_key; std::string raw_key;
if (!action_object->GetString("value", &raw_key)) if (!action_object->GetString("value", &raw_key))
return Status(kUnknownError, "missing 'value'"); return Status(kUnknownError, "missing 'value'");
......
...@@ -28,6 +28,6 @@ Status ConvertKeysToKeyEvents(const base::string16& keys, ...@@ -28,6 +28,6 @@ Status ConvertKeysToKeyEvents(const base::string16& keys,
Status ConvertKeyActionToKeyEvent(const base::DictionaryValue* action_object, Status ConvertKeyActionToKeyEvent(const base::DictionaryValue* action_object,
base::DictionaryValue* input_state, base::DictionaryValue* input_state,
bool is_key_down, bool is_key_down,
std::vector<KeyEvent>* client_key_events); std::list<KeyEvent>* client_key_events);
#endif // CHROME_TEST_CHROMEDRIVER_KEY_CONVERTER_H_ #endif // CHROME_TEST_CHROMEDRIVER_KEY_CONVERTER_H_
...@@ -374,39 +374,6 @@ Status ProcessPauseAction(const base::DictionaryValue* action_item, ...@@ -374,39 +374,6 @@ Status ProcessPauseAction(const base::DictionaryValue* action_item,
return Status(kOk); return Status(kOk);
} }
// Implements "compute the tick duration" algorithm from W3C spec
// (https://w3c.github.io/webdriver/#dfn-computing-the-tick-duration).
// For convenience, this function computes durations of all ticks, while the
// original algorithm computes duration of one tick.
void ComputeTickDurations(std::vector<int>* tick_durations,
const base::ListValue& actions_list) {
for (size_t i = 0; i < actions_list.GetSize(); i++) {
const base::DictionaryValue* action_sequence = nullptr;
actions_list.GetDictionary(i, &action_sequence);
const base::ListValue* actions = nullptr;
action_sequence->GetList("actions", &actions);
std::string type;
action_sequence->GetString("sourceType", &type);
for (size_t j = 0; j < actions->GetSize(); j++) {
const base::DictionaryValue* action = nullptr;
actions->GetDictionary(j, &action);
std::string subtype;
action->GetString("subtype", &subtype);
if (subtype == "pause" ||
(type == "pointer" && subtype == "pointerMove")) {
if (j >= tick_durations->size())
tick_durations->resize(j + 1);
int duration = 0;
GetOptionalInt(action, "duration", &duration);
if (duration > (*tick_durations)[j])
(*tick_durations)[j] = duration;
}
}
}
}
Status ElementInViewCenter(Session* session, Status ElementInViewCenter(Session* session,
WebView* web_view, WebView* web_view,
std::string element_id, std::string element_id,
...@@ -1033,7 +1000,7 @@ Status ExecuteTouchScroll(Session* session, ...@@ -1033,7 +1000,7 @@ Status ExecuteTouchScroll(Session* session,
Status ProcessInputActionSequence( Status ProcessInputActionSequence(
Session* session, Session* session,
const base::DictionaryValue* action_sequence, const base::DictionaryValue* action_sequence,
std::unique_ptr<base::DictionaryValue>* action_sequence_result) { std::vector<std::unique_ptr<base::DictionaryValue>>* action_list) {
std::string id; std::string id;
std::string type; std::string type;
const base::DictionaryValue* source; const base::DictionaryValue* source;
...@@ -1062,9 +1029,6 @@ Status ProcessInputActionSequence( ...@@ -1062,9 +1029,6 @@ Status ProcessInputActionSequence(
pointer_type = "mouse"; pointer_type = "mouse";
} }
} }
(*action_sequence_result)->SetString("sourceType", type);
(*action_sequence_result)->SetString("pointerType", pointer_type);
(*action_sequence_result)->SetString("id", id);
bool found = false; bool found = false;
for (size_t i = 0; i < session->active_input_sources.GetSize(); i++) { for (size_t i = 0; i < session->active_input_sources.GetSize(); i++) {
...@@ -1135,6 +1099,7 @@ Status ProcessInputActionSequence( ...@@ -1135,6 +1099,7 @@ Status ProcessInputActionSequence(
std::unique_ptr<base::ListValue> actions_result(new base::ListValue); std::unique_ptr<base::ListValue> actions_result(new base::ListValue);
for (size_t i = 0; i < actions->GetSize(); i++) { for (size_t i = 0; i < actions->GetSize(); i++) {
std::unique_ptr<base::DictionaryValue> action(new base::DictionaryValue()); std::unique_ptr<base::DictionaryValue> action(new base::DictionaryValue());
const base::DictionaryValue* action_item; const base::DictionaryValue* action_item;
if (!actions->GetDictionary(i, &action_item)) if (!actions->GetDictionary(i, &action_item))
return Status( return Status(
...@@ -1188,6 +1153,7 @@ Status ProcessInputActionSequence( ...@@ -1188,6 +1153,7 @@ Status ProcessInputActionSequence(
action->SetString("value", key); action->SetString("value", key);
} }
} else if (type == "pointer") { } else if (type == "pointer") {
action->SetString("pointerType", pointer_type);
std::string subtype; std::string subtype;
if (!action_item->GetString("type", &subtype) || if (!action_item->GetString("type", &subtype) ||
(subtype != "pointerUp" && subtype != "pointerDown" && (subtype != "pointerUp" && subtype != "pointerDown" &&
...@@ -1258,9 +1224,8 @@ Status ProcessInputActionSequence( ...@@ -1258,9 +1224,8 @@ Status ProcessInputActionSequence(
return status; return status;
} }
} }
actions_result->Append(std::move(action)); action_list->push_back(std::move(action));
} }
(*action_sequence_result)->SetList("actions", std::move(actions_result));
return Status(kOk); return Status(kOk);
} }
...@@ -1276,334 +1241,270 @@ Status ExecutePerformActions(Session* session, ...@@ -1276,334 +1241,270 @@ Status ExecutePerformActions(Session* session,
return Status(kInvalidArgument, "'actions' must be an array"); return Status(kInvalidArgument, "'actions' must be an array");
// the processed actions // the processed actions
base::ListValue actions_list; std::vector<std::vector<std::unique_ptr<base::DictionaryValue>>> actions_list;
for (size_t i = 0; i < actions_input->GetSize(); i++) { for (size_t i = 0; i < actions_input->GetSize(); i++) {
std::unique_ptr<base::DictionaryValue> input_source_actions(
new base::DictionaryValue());
// proccess input action sequence // proccess input action sequence
const base::DictionaryValue* action_sequence; const base::DictionaryValue* action_sequence;
if (!actions_input->GetDictionary(i, &action_sequence)) if (!actions_input->GetDictionary(i, &action_sequence))
return Status(kInvalidArgument, "each argument must be a dictionary"); return Status(kInvalidArgument, "each argument must be a dictionary");
Status status = ProcessInputActionSequence(session, action_sequence,
&input_source_actions); std::vector<std::unique_ptr<base::DictionaryValue>> action_list;
Status status =
ProcessInputActionSequence(session, action_sequence, &action_list);
actions_list.push_back(std::move(action_list));
if (status.IsError()) if (status.IsError())
return Status(kInvalidArgument, status); return Status(kInvalidArgument, status);
actions_list.Append(std::move(input_source_actions));
} }
std::string input_pointer_type;
std::set<std::string> pointer_id_set; std::set<std::string> pointer_id_set;
std::string type; std::vector<base::DictionaryValue*> action_input_states;
std::vector<std::vector<MouseEvent>> mouse_events_list; std::map<std::string, gfx::Point> action_locations;
std::vector<base::DictionaryValue*> mouse_input_states; std::map<std::string, bool> has_touch_start;
std::vector<gfx::Point> mouse_locations; std::map<std::string, int> buttons;
std::vector<std::vector<TouchEvent>> touch_events_list; std::map<std::string, std::string> button_type;
std::vector<base::DictionaryValue*> touch_input_states; int viewport_width = 0, viewport_height = 0;
std::vector<gfx::Point> touch_locations; int init_x = 0, init_y = 0;
std::vector<std::vector<KeyEvent>> key_events_list;
std::vector<base::DictionaryValue*> key_input_states;
size_t longest_mouse_list_size = 0;
size_t longest_touch_list_size = 0;
size_t longest_key_list_size = 0;
for (size_t i = 0; i < actions_list.GetSize(); i++) {
base::DictionaryValue* action_sequence;
actions_list.GetDictionary(i, &action_sequence);
const base::ListValue* actions;
action_sequence->GetList("actions", &actions);
DCHECK(actions);
action_sequence->GetString("sourceType", &type);
std::string id;
action_sequence->GetString("id", &id);
base::DictionaryValue* input_state;
if (!session->input_state_table.GetDictionary(id, &input_state))
return Status(kUnknownError, "missing input state");
// key actions
if (type == "key") {
KeyEventBuilder builder;
std::vector<KeyEvent> key_events;
for (size_t j = 0; j < actions->GetSize(); j++) {
const base::DictionaryValue* action;
actions->GetDictionary(j, &action);
std::string subtype;
action->GetString("subtype", &subtype);
if (subtype == "pause") {
key_events.push_back(builder.SetType(kPauseEventType)->Build());
} else {
Status status = ConvertKeyActionToKeyEvent(
action, input_state, subtype == "keyDown", &key_events);
if (status.IsError())
return status;
}
}
longest_key_list_size =
std::max(key_events.size(), longest_key_list_size);
key_events_list.push_back(key_events);
key_input_states.push_back(input_state);
} else if (type == "pointer") {
std::string pointer_type;
action_sequence->GetString("pointerType", &pointer_type);
if (input_pointer_type.empty())
input_pointer_type = pointer_type;
if (input_pointer_type != pointer_type) { size_t longest_action_list_size = 0;
return Status(kInvalidArgument, for (size_t i = 0; i < actions_list.size(); i++) {
"multiple input pointer types are not supported now"); longest_action_list_size =
} std::max(longest_action_list_size, actions_list[i].size());
}
std::string pointer_id; for (size_t i = 0; i < longest_action_list_size; i++) {
action_sequence->GetString("id", &pointer_id); // Implements "compute the tick duration" algorithm from W3C spec
if (pointer_id_set.find(pointer_id) != pointer_id_set.end()) // (https://w3c.github.io/webdriver/#dfn-computing-the-tick-duration).
return Status(kInvalidArgument, "'id' already exists"); // This is the duration for actions in one tick.
pointer_id_set.insert(pointer_id); int tick_duration = 0;
for (size_t j = 0; j < actions_list.size(); j++) {
std::vector<MouseEvent> mouse_events; if (actions_list[j].size() > i) {
std::vector<TouchEvent> touch_events; const base::DictionaryValue* action = actions_list[j][i].get();
double x = 0; std::string id;
double y = 0; std::string type;
bool has_touch_start = input_state->FindKey("pressed")->GetInt() != 0;
int buttons = input_state->FindKey("pressed")->GetInt();
std::string button_type;
OriginType origin_type = kPointer;
std::string element_id;
for (size_t j = 0; j < actions->GetSize(); j++) {
const base::DictionaryValue* pointer_action;
actions->GetDictionary(j, &pointer_action);
std::string action_type; std::string action_type;
pointer_action->GetString("subtype", &action_type); action->GetString("id", &id);
if (action_type == "pointerMove") { base::DictionaryValue* input_state;
pointer_action->GetDouble("x", &x); if (!session->input_state_table.GetDictionary(id, &input_state))
pointer_action->GetDouble("y", &y); return Status(kUnknownError, "missing input state");
const base::DictionaryValue* origin_dict;
origin_type = kViewPort; if (i == 0) {
element_id = ""; if (pointer_id_set.find(id) != pointer_id_set.end())
if (pointer_action->HasKey("origin")) { return Status(kInvalidArgument, "'id' already exists");
if (pointer_action->GetDictionary("origin", &origin_dict)) { pointer_id_set.insert(id);
origin_type = kElement; action_input_states.push_back(input_state);
origin_dict->GetString(GetElementKey(), &element_id);
} else {
std::string origin;
pointer_action->GetString("origin", &origin);
if (origin == "pointer")
origin_type = kPointer;
}
}
}
if (pointer_type == "mouse" || pointer_type == "pen") {
int click_count = 0;
if (action_type == "pointerDown" || action_type == "pointerUp") {
pointer_action->GetString("button", &button_type);
click_count = 1;
} else if (buttons == 0) {
button_type.clear();
}
MouseEvent event(StringToMouseEventType(action_type),
StringToMouseButton(button_type), x, y, 0, buttons,
click_count);
event.origin = origin_type;
event.element_id = element_id;
event.pointer_type = StringToPointerType(pointer_type);
mouse_events.push_back(event);
if (action_type == "pointerDown")
buttons |= StringToModifierMouseButton(button_type);
else if (action_type == "pointerUp")
buttons &= ~StringToModifierMouseButton(button_type);
} else if (pointer_type == "touch") {
if (action_type == "pointerDown")
has_touch_start = true;
else if (action_type == "pointerUp")
has_touch_start = false;
TouchEvent event(StringToTouchEventType(action_type), x, y);
event.origin = origin_type;
event.element_id = element_id;
if (action_type == "pointerMove")
event.dispatch = has_touch_start;
touch_events.push_back(event);
} }
}
int init_x = 0;
int init_y = 0;
input_state->GetInteger("x", &init_x);
input_state->GetInteger("y", &init_y);
if (pointer_type == "mouse" || pointer_type == "pen") {
longest_mouse_list_size =
std::max(mouse_events.size(), longest_mouse_list_size);
mouse_events_list.push_back(mouse_events);
mouse_input_states.push_back(input_state);
mouse_locations.emplace_back(init_x, init_y);
} else if (pointer_type == "touch") {
longest_touch_list_size =
std::max(touch_events.size(), longest_touch_list_size);
touch_events_list.push_back(touch_events);
touch_input_states.push_back(input_state);
touch_locations.emplace_back(init_x, init_y);
}
}
}
std::vector<int> tick_durations; action->GetString("type", &type);
ComputeTickDurations(&tick_durations, actions_list); action->GetString("subtype", &action_type);
int duration = 0;
int viewport_width = 0, viewport_height = 0; if (action_type == "pause") {
if (mouse_events_list.size() > 0 || touch_events_list.size() > 0) { GetOptionalInt(action, "duration", &duration);
Status status = WindowViewportSize(session, web_view, &viewport_width, tick_duration = std::max(tick_duration, duration);
&viewport_height);
if (status.IsError())
return status;
}
size_t max_list_length =
std::max({longest_mouse_list_size, longest_touch_list_size,
longest_key_list_size, tick_durations.size()});
for (size_t i = 0; i < max_list_length; i++) {
std::list<KeyEvent> dispatch_key_events;
for (size_t j = 0; j < key_events_list.size(); j++) {
if (i < key_events_list[j].size() &&
key_events_list[j][i].type != kPauseEventType) {
const KeyEvent& event = key_events_list[j][i];
dispatch_key_events.push_back(event);
if (event.type == kKeyDownEventType) {
session->input_cancel_list.emplace_back(key_input_states[j], nullptr,
nullptr, &event);
session->sticky_modifiers |= KeyToKeyModifiers(event.key);
} else if (event.type == kKeyUpEventType) {
session->sticky_modifiers &= ~KeyToKeyModifiers(event.key);
} }
}
}
if (dispatch_key_events.size() > 0) {
Status status = web_view->DispatchKeyEvents(dispatch_key_events);
if (status.IsError())
return status;
}
std::list<MouseEvent> dispatch_mouse_events; if (type == "key") {
for (size_t j = 0; j < mouse_events_list.size(); j++) { std::list<KeyEvent> dispatch_key_events;
if (i < mouse_events_list[j].size() && KeyEventBuilder builder;
mouse_events_list[j][i].type != kPauseMouseEventType) { if (action_type != "pause") {
MouseEvent event = mouse_events_list[j][i]; Status status = ConvertKeyActionToKeyEvent(action, input_state,
if (event.type == kMovedMouseEventType) { action_type == "keyDown",
if (event.origin == kPointer) { &dispatch_key_events);
event.x += mouse_locations[j].x();
event.y += mouse_locations[j].y();
} else if (!event.element_id.empty()) {
int center_x = 0, center_y = 0;
Status status = ElementInViewCenter(
session, web_view, event.element_id, &center_x, &center_y);
if (status.IsError()) if (status.IsError())
return status; return status;
event.x += center_x;
event.y += center_y;
}
if (event.x < 0 || event.x > viewport_width || event.y < 0 ||
event.y > viewport_height)
return Status(kMoveTargetOutOfBounds);
mouse_locations[j] = gfx::Point(event.x, event.y);
} else {
event.x = mouse_locations[j].x();
event.y = mouse_locations[j].y();
}
event.modifiers = session->sticky_modifiers;
if (event.type == kPressedMouseEventType) {
base::TimeTicks timestamp = base::TimeTicks::Now();
bool is_repeated_click = IsRepeatedClickEvent(
event.x, event.y, session->mouse_position.x,
session->mouse_position.y, session->click_count, timestamp,
session->mouse_click_timestamp);
event.click_count = is_repeated_click ? 2 : 1;
session->mouse_position = WebPoint(event.x, event.y);
session->click_count = event.click_count;
session->mouse_click_timestamp = timestamp;
} else if (event.type == kReleasedMouseEventType) {
event.click_count = session->click_count;
}
dispatch_mouse_events.push_back(event);
if (event.type == kPressedMouseEventType) {
session->input_cancel_list.emplace_back(mouse_input_states[j], &event,
nullptr, nullptr);
mouse_input_states[j]->SetInteger(
"pressed", mouse_input_states[j]->FindKey("pressed")->GetInt() |
(1 << event.button));
} else if (event.type == kReleasedMouseEventType) {
mouse_input_states[j]->SetInteger(
"pressed", mouse_input_states[j]->FindKey("pressed")->GetInt() &
~(1 << event.button));
}
}
}
if (dispatch_mouse_events.size() > 0) {
Status status = web_view->DispatchMouseEvents(
dispatch_mouse_events, session->GetCurrentFrameId());
if (status.IsError())
return status;
}
std::list<TouchEvent> dispatch_touch_events; if (dispatch_key_events.size() > 0) {
for (size_t j = 0; j < touch_events_list.size(); j++) { const KeyEvent& event = dispatch_key_events.front();
if (i < touch_events_list[j].size() && if (action_type == "keyDown") {
touch_events_list[j][i].type != kPause) { session->input_cancel_list.emplace_back(
TouchEvent event = touch_events_list[j][i]; action_input_states[j], nullptr, nullptr, &event);
if (event.type == kTouchMove) { session->sticky_modifiers |= KeyToKeyModifiers(event.key);
if (event.origin == kPointer) { } else if (action_type == "keyUp") {
event.x += touch_locations[j].x(); session->sticky_modifiers &= ~KeyToKeyModifiers(event.key);
event.y += touch_locations[j].y(); }
} else if (!event.element_id.empty()) {
int center_x = 0, center_y = 0; Status status = web_view->DispatchKeyEvents(dispatch_key_events);
Status status = ElementInViewCenter( if (status.IsError())
session, web_view, event.element_id, &center_x, &center_y); return status;
}
}
} else if (type == "pointer") {
std::string pointer_type;
action->GetString("pointerType", &pointer_type);
if (i == 0) {
Status status = WindowViewportSize(
session, web_view, &viewport_width, &viewport_height);
if (status.IsError()) if (status.IsError())
return status; return status;
event.x += center_x;
event.y += center_y; input_state->GetInteger("x", &init_x);
input_state->GetInteger("y", &init_y);
action_locations.insert(
std::make_pair(id, gfx::Point(init_x, init_y)));
if (pointer_type == "mouse" || pointer_type == "pen")
buttons[id] = input_state->FindKey("pressed")->GetInt();
else if (pointer_type == "touch")
has_touch_start[id] = false;
} }
if (event.x < 0 || event.x > viewport_width || event.y < 0 ||
event.y > viewport_height) if (action_type != "pause") {
return Status(kMoveTargetOutOfBounds); std::list<MouseEvent> dispatch_mouse_events;
touch_locations[j] = gfx::Point(event.x, event.y); std::list<TouchEvent> dispatch_touch_events;
} else { double x = 0;
event.x = touch_locations[j].x(); double y = 0;
event.y = touch_locations[j].y();
OriginType origin = kViewPort;
std::string element_id = "";
if (action_type == "pointerMove") {
action->GetDouble("x", &x);
action->GetDouble("y", &y);
const base::DictionaryValue* origin_dict;
if (action->HasKey("origin")) {
if (action->GetDictionary("origin", &origin_dict)) {
origin = kElement;
origin_dict->GetString(GetElementKey(), &element_id);
} else {
std::string origin_str;
action->GetString("origin", &origin_str);
if (origin_str == "pointer")
origin = kPointer;
}
}
duration = 0;
GetOptionalInt(action, "duration", &duration);
tick_duration = std::max(tick_duration, duration);
}
if (pointer_type == "mouse" || pointer_type == "pen") {
int click_count = 0;
if (action_type == "pointerDown" || action_type == "pointerUp") {
std::string button;
action->GetString("button", &button);
button_type[id] = button;
click_count = 1;
} else if (buttons[id] == 0) {
button_type[id].clear();
}
MouseEvent event(StringToMouseEventType(action_type),
StringToMouseButton(button_type[id]), x, y, 0,
buttons[id], click_count);
event.pointer_type = StringToPointerType(pointer_type);
if (action_type == "pointerDown")
buttons[id] |= StringToModifierMouseButton(button_type[id]);
else if (action_type == "pointerUp")
buttons[id] &= ~StringToModifierMouseButton(button_type[id]);
if (event.type == kMovedMouseEventType) {
if (origin == kPointer) {
event.x += action_locations[id].x();
event.y += action_locations[id].y();
} else if (!element_id.empty()) {
int center_x = 0, center_y = 0;
Status status = ElementInViewCenter(
session, web_view, element_id, &center_x, &center_y);
if (status.IsError())
return status;
event.x += center_x;
event.y += center_y;
}
if (event.x < 0 || event.x > viewport_width || event.y < 0 ||
event.y > viewport_height) {
return Status(kMoveTargetOutOfBounds);
}
action_locations[id] = gfx::Point(event.x, event.y);
} else {
event.x = action_locations[id].x();
event.y = action_locations[id].y();
}
event.modifiers = session->sticky_modifiers;
if (event.type == kPressedMouseEventType) {
base::TimeTicks timestamp = base::TimeTicks::Now();
bool is_repeated_click = IsRepeatedClickEvent(
event.x, event.y, session->mouse_position.x,
session->mouse_position.y, session->click_count, timestamp,
session->mouse_click_timestamp);
event.click_count = is_repeated_click ? 2 : 1;
session->mouse_position = WebPoint(event.x, event.y);
session->click_count = event.click_count;
session->mouse_click_timestamp = timestamp;
} else if (event.type == kReleasedMouseEventType) {
event.click_count = session->click_count;
}
dispatch_mouse_events.push_back(event);
if (event.type == kPressedMouseEventType) {
session->input_cancel_list.emplace_back(
action_input_states[j], &event, nullptr, nullptr);
action_input_states[j]->SetInteger(
"pressed",
action_input_states[j]->FindKey("pressed")->GetInt() |
(1 << event.button));
} else if (event.type == kReleasedMouseEventType) {
action_input_states[j]->SetInteger(
"pressed",
action_input_states[j]->FindKey("pressed")->GetInt() &
~(1 << event.button));
}
Status status = web_view->DispatchMouseEvents(
dispatch_mouse_events, session->GetCurrentFrameId());
if (status.IsError())
return status;
} else if (pointer_type == "touch") {
if (action_type == "pointerDown")
has_touch_start[id] = true;
TouchEvent event(StringToTouchEventType(action_type), x, y);
if (event.type == kTouchMove) {
if (origin == kPointer) {
event.x += action_locations[id].x();
event.y += action_locations[id].y();
} else if (!element_id.empty()) {
int center_x = 0, center_y = 0;
Status status = ElementInViewCenter(
session, web_view, element_id, &center_x, &center_y);
if (status.IsError())
return status;
event.x += center_x;
event.y += center_y;
}
if (event.x < 0 || event.x > viewport_width || event.y < 0 ||
event.y > viewport_height)
return Status(kMoveTargetOutOfBounds);
action_locations[id] = gfx::Point(event.x, event.y);
} else {
event.x = action_locations[id].x();
event.y = action_locations[id].y();
}
if (event.type == kTouchStart) {
session->input_cancel_list.emplace_back(
action_input_states[j], nullptr, &event, nullptr);
action_input_states[j]->SetInteger("pressed", 1);
} else if (event.type == kTouchEnd) {
action_input_states[j]->SetInteger("pressed", 0);
}
if (has_touch_start[id]) {
dispatch_touch_events.push_back(event);
Status status =
web_view->DispatchTouchEvents(dispatch_touch_events);
if (status.IsError())
return status;
}
if (action_type == "pointerUp")
has_touch_start[id] = false;
}
}
action_input_states[j]->SetInteger("x", action_locations[id].x());
action_input_states[j]->SetInteger("y", action_locations[id].y());
} }
if (event.dispatch)
dispatch_touch_events.push_back(event); if (tick_duration > 0) {
if (event.type == kTouchStart) { base::PlatformThread::Sleep(
session->input_cancel_list.emplace_back(touch_input_states[j], base::TimeDelta::FromMilliseconds(tick_duration));
nullptr, &event, nullptr);
touch_input_states[j]->SetInteger("pressed", 1);
} else if (event.type == kTouchEnd) {
touch_input_states[j]->SetInteger("pressed", 0);
} }
} }
} }
if (dispatch_touch_events.size() > 0) {
Status status = web_view->DispatchTouchEvents(dispatch_touch_events);
if (status.IsError())
return status;
}
if (i < tick_durations.size() && tick_durations[i] > 0) {
base::PlatformThread::Sleep(
base::TimeDelta::FromMilliseconds(tick_durations[i]));
}
}
for (size_t i = 0; i < mouse_events_list.size(); i++) {
mouse_input_states[i]->SetInteger("x", mouse_locations[i].x());
mouse_input_states[i]->SetInteger("y", mouse_locations[i].y());
}
for (size_t i = 0; i < touch_events_list.size(); i++) {
touch_input_states[i]->SetInteger("x", touch_locations[i].x());
touch_input_states[i]->SetInteger("y", touch_locations[i].y());
} }
return Status(kOk); return Status(kOk);
......
...@@ -373,7 +373,7 @@ Status ExecutePerformActions(Session* session, ...@@ -373,7 +373,7 @@ Status ExecutePerformActions(Session* session,
Status ProcessInputActionSequence( Status ProcessInputActionSequence(
Session* session, Session* session,
const base::DictionaryValue* action_sequence, const base::DictionaryValue* action_sequence,
std::unique_ptr<base::DictionaryValue>* result); std::vector<std::unique_ptr<base::DictionaryValue>>* action_list);
Status ExecuteReleaseActions(Session* session, Status ExecuteReleaseActions(Session* session,
WebView* web_view, WebView* web_view,
......
...@@ -66,7 +66,7 @@ TEST(WindowCommandsTest, ExecuteResume) { ...@@ -66,7 +66,7 @@ TEST(WindowCommandsTest, ExecuteResume) {
TEST(WindowCommandsTest, ProcessInputActionSequencePointerMouse) { TEST(WindowCommandsTest, ProcessInputActionSequencePointerMouse) {
Session session("1"); Session session("1");
std::unique_ptr<base::DictionaryValue> result(new base::DictionaryValue()); std::vector<std::unique_ptr<base::DictionaryValue>> action_list;
std::unique_ptr<base::DictionaryValue> action_sequence( std::unique_ptr<base::DictionaryValue> action_sequence(
new base::DictionaryValue()); new base::DictionaryValue());
std::unique_ptr<base::ListValue> actions(new base::ListValue()); std::unique_ptr<base::ListValue> actions(new base::ListValue());
...@@ -94,12 +94,10 @@ TEST(WindowCommandsTest, ProcessInputActionSequencePointerMouse) { ...@@ -94,12 +94,10 @@ TEST(WindowCommandsTest, ProcessInputActionSequencePointerMouse) {
action_sequence->SetList("actions", std::move(actions)); action_sequence->SetList("actions", std::move(actions));
const base::DictionaryValue* input_action_sequence = action_sequence.get(); const base::DictionaryValue* input_action_sequence = action_sequence.get();
Status status = Status status =
ProcessInputActionSequence(&session, input_action_sequence, &result); ProcessInputActionSequence(&session, input_action_sequence, &action_list);
ASSERT_TRUE(status.IsOk()); ASSERT_TRUE(status.IsOk());
// check resulting action dictionary // check resulting action dictionary
const base::ListValue* actions_result;
const base::DictionaryValue* action_result;
std::string pointer_type; std::string pointer_type;
std::string source_type; std::string source_type;
std::string id; std::string id;
...@@ -107,37 +105,49 @@ TEST(WindowCommandsTest, ProcessInputActionSequencePointerMouse) { ...@@ -107,37 +105,49 @@ TEST(WindowCommandsTest, ProcessInputActionSequencePointerMouse) {
int x, y; int x, y;
std::string button; std::string button;
result->GetString("sourceType", &source_type); ASSERT_EQ(3U, action_list.size());
result->GetString("pointerType", &pointer_type); const base::DictionaryValue* action1 = action_list[0].get();
result->GetString("id", &id); action1->GetString("type", &source_type);
action1->GetString("pointerType", &pointer_type);
action1->GetString("id", &id);
ASSERT_EQ("pointer", source_type); ASSERT_EQ("pointer", source_type);
ASSERT_EQ("mouse", pointer_type); ASSERT_EQ("mouse", pointer_type);
ASSERT_EQ("pointer1", id); ASSERT_EQ("pointer1", id);
action1->GetString("subtype", &action_type);
result->GetList("actions", &actions_result); action1->GetInteger("x", &x);
ASSERT_EQ(3U, actions_result->GetSize()); action1->GetInteger("y", &y);
actions_result->GetDictionary(0, &action_result);
action_result->GetString("subtype", &action_type);
action_result->GetInteger("x", &x);
action_result->GetInteger("y", &y);
ASSERT_EQ("pointerMove", action_type); ASSERT_EQ("pointerMove", action_type);
ASSERT_EQ(30, x); ASSERT_EQ(30, x);
ASSERT_EQ(60, y); ASSERT_EQ(60, y);
actions_result->GetDictionary(1, &action_result);
action_result->GetString("subtype", &action_type); const base::DictionaryValue* action2 = action_list[1].get();
action_result->GetString("button", &button); action2->GetString("type", &source_type);
action2->GetString("pointerType", &pointer_type);
action2->GetString("id", &id);
ASSERT_EQ("pointer", source_type);
ASSERT_EQ("mouse", pointer_type);
ASSERT_EQ("pointer1", id);
action2->GetString("subtype", &action_type);
action2->GetString("button", &button);
ASSERT_EQ("pointerDown", action_type); ASSERT_EQ("pointerDown", action_type);
ASSERT_EQ("left", button); ASSERT_EQ("left", button);
actions_result->GetDictionary(2, &action_result);
action_result->GetString("subtype", &action_type); const base::DictionaryValue* action3 = action_list[2].get();
action_result->GetString("button", &button); action3->GetString("type", &source_type);
action3->GetString("pointerType", &pointer_type);
action3->GetString("id", &id);
ASSERT_EQ("pointer", source_type);
ASSERT_EQ("mouse", pointer_type);
ASSERT_EQ("pointer1", id);
action3->GetString("subtype", &action_type);
action3->GetString("button", &button);
ASSERT_EQ("pointerUp", action_type); ASSERT_EQ("pointerUp", action_type);
ASSERT_EQ("left", button); ASSERT_EQ("left", button);
} }
TEST(WindowCommandsTest, ProcessInputActionSequencePointerTouch) { TEST(WindowCommandsTest, ProcessInputActionSequencePointerTouch) {
Session session("1"); Session session("1");
std::unique_ptr<base::DictionaryValue> result(new base::DictionaryValue()); std::vector<std::unique_ptr<base::DictionaryValue>> action_list;
std::unique_ptr<base::DictionaryValue> action_sequence( std::unique_ptr<base::DictionaryValue> action_sequence(
new base::DictionaryValue()); new base::DictionaryValue());
std::unique_ptr<base::ListValue> actions(new base::ListValue()); std::unique_ptr<base::ListValue> actions(new base::ListValue());
...@@ -163,38 +173,48 @@ TEST(WindowCommandsTest, ProcessInputActionSequencePointerTouch) { ...@@ -163,38 +173,48 @@ TEST(WindowCommandsTest, ProcessInputActionSequencePointerTouch) {
action_sequence->SetList("actions", std::move(actions)); action_sequence->SetList("actions", std::move(actions));
const base::DictionaryValue* input_action_sequence = action_sequence.get(); const base::DictionaryValue* input_action_sequence = action_sequence.get();
Status status = Status status =
ProcessInputActionSequence(&session, input_action_sequence, &result); ProcessInputActionSequence(&session, input_action_sequence, &action_list);
ASSERT_TRUE(status.IsOk()); ASSERT_TRUE(status.IsOk());
// check resulting action dictionary // check resulting action dictionary
const base::ListValue* actions_result;
const base::DictionaryValue* action_result;
std::string pointer_type; std::string pointer_type;
std::string source_type; std::string source_type;
std::string id; std::string id;
std::string action_type; std::string action_type;
int x, y; int x, y;
result->GetString("sourceType", &source_type); ASSERT_EQ(3U, action_list.size());
result->GetString("pointerType", &pointer_type); const base::DictionaryValue* action1 = action_list[0].get();
result->GetString("id", &id); action1->GetString("type", &source_type);
action1->GetString("pointerType", &pointer_type);
action1->GetString("id", &id);
ASSERT_EQ("pointer", source_type); ASSERT_EQ("pointer", source_type);
ASSERT_EQ("touch", pointer_type); ASSERT_EQ("touch", pointer_type);
ASSERT_EQ("pointer1", id); ASSERT_EQ("pointer1", id);
action1->GetString("subtype", &action_type);
result->GetList("actions", &actions_result); action1->GetInteger("x", &x);
ASSERT_EQ(3U, actions_result->GetSize()); action1->GetInteger("y", &y);
actions_result->GetDictionary(0, &action_result);
action_result->GetString("subtype", &action_type);
action_result->GetInteger("x", &x);
action_result->GetInteger("y", &y);
ASSERT_EQ("pointerMove", action_type); ASSERT_EQ("pointerMove", action_type);
ASSERT_EQ(30, x); ASSERT_EQ(30, x);
ASSERT_EQ(60, y); ASSERT_EQ(60, y);
actions_result->GetDictionary(1, &action_result);
action_result->GetString("subtype", &action_type); const base::DictionaryValue* action2 = action_list[1].get();
action2->GetString("type", &source_type);
action2->GetString("pointerType", &pointer_type);
action2->GetString("id", &id);
ASSERT_EQ("pointer", source_type);
ASSERT_EQ("touch", pointer_type);
ASSERT_EQ("pointer1", id);
action2->GetString("subtype", &action_type);
ASSERT_EQ("pointerDown", action_type); ASSERT_EQ("pointerDown", action_type);
actions_result->GetDictionary(2, &action_result);
action_result->GetString("subtype", &action_type); const base::DictionaryValue* action3 = action_list[2].get();
action3->GetString("type", &source_type);
action3->GetString("pointerType", &pointer_type);
action3->GetString("id", &id);
ASSERT_EQ("pointer", source_type);
ASSERT_EQ("touch", pointer_type);
ASSERT_EQ("pointer1", id);
action3->GetString("subtype", &action_type);
ASSERT_EQ("pointerUp", action_type); ASSERT_EQ("pointerUp", action_type);
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment