blob: 127c565f4c0708467e16017e8236b7da55fd7ef5 [file] [log] [blame]
// Copyright (c) 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/renderer/gpu/actions_parser.h"
#include "base/format_macros.h"
#include "base/memory/ptr_util.h"
#include "base/strings/stringprintf.h"
#include "base/values.h"
#include "cc/output/begin_frame_args.h"
namespace content {
namespace {
SyntheticPointerActionParams::PointerActionType ToSyntheticPointerActionType(
std::string action_type) {
if (action_type == "pointerDown")
return SyntheticPointerActionParams::PointerActionType::PRESS;
if (action_type == "pointerMove")
return SyntheticPointerActionParams::PointerActionType::MOVE;
if (action_type == "pointerUp")
return SyntheticPointerActionParams::PointerActionType::RELEASE;
if (action_type == "pause")
return SyntheticPointerActionParams::PointerActionType::IDLE;
return SyntheticPointerActionParams::PointerActionType::NOT_INITIALIZED;
}
SyntheticGestureParams::GestureSourceType ToSyntheticGestureSourceType(
std::string source_type) {
if (source_type == "touch")
return SyntheticGestureParams::TOUCH_INPUT;
else if (source_type == "mouse")
return SyntheticGestureParams::MOUSE_INPUT;
else if (source_type == "pen")
return SyntheticGestureParams::PEN_INPUT;
else
return SyntheticGestureParams::DEFAULT_INPUT;
}
SyntheticPointerActionParams::Button ToSyntheticMouseButton(
std::string button) {
if (button == "left")
return SyntheticPointerActionParams::Button::LEFT;
if (button == "middle")
return SyntheticPointerActionParams::Button::MIDDLE;
if (button == "right")
return SyntheticPointerActionParams::Button::RIGHT;
NOTREACHED() << "Unexpected button";
return SyntheticPointerActionParams::Button();
}
} // namespace
ActionsParser::ActionsParser(base::Value* pointer_actions_value)
: longest_action_sequence_(0),
pointer_actions_value_(pointer_actions_value),
action_index_(0) {}
ActionsParser::~ActionsParser() {}
bool ActionsParser::ParsePointerActionSequence() {
const base::ListValue* pointer_list;
if (!pointer_actions_value_ ||
!pointer_actions_value_->GetAsList(&pointer_list)) {
error_message_ =
base::StringPrintf("pointer_list is missing or not a list");
return false;
}
for (const auto& pointer_value : *pointer_list) {
const base::DictionaryValue* pointer_actions;
if (!pointer_value.GetAsDictionary(&pointer_actions)) {
error_message_ =
base::StringPrintf("pointer actions is missing or not a dictionary");
return false;
} else if (!ParsePointerActions(*pointer_actions)) {
return false;
}
action_index_++;
}
if (!gesture_params_)
gesture_params_ = base::MakeUnique<SyntheticPointerActionListParams>();
gesture_params_->gesture_source_type =
ToSyntheticGestureSourceType(source_type_);
// Group a list of actions from all pointers into a
// SyntheticPointerActionListParams object, which is a list of actions, which
// will be dispatched together.
for (size_t action_index = 0; action_index < longest_action_sequence_;
++action_index) {
SyntheticPointerActionListParams::ParamList param_list;
for (const auto pointer_list : pointer_actions_list_) {
if (action_index < pointer_list.size())
param_list.push_back(pointer_list[action_index]);
}
gesture_params_->PushPointerActionParamsList(param_list);
}
return true;
}
bool ActionsParser::ParsePointerActions(const base::DictionaryValue& pointer) {
std::string source_type;
if (!pointer.GetString("source", &source_type)) {
error_message_ =
base::StringPrintf("source type is missing or not a string");
return false;
} else if (source_type != "touch" && source_type != "mouse" &&
source_type != "pen") {
error_message_ =
base::StringPrintf("source type is an unsupported input source");
return false;
}
if (source_type_.empty()) {
source_type_ = source_type;
#if defined(OS_MACOSX)
if (source_type == "touch") {
error_message_ =
base::StringPrintf("Mac OS does not support touch events");
return false;
}
#endif // defined(OS_MACOSX)
}
if (source_type_ != source_type) {
error_message_ = base::StringPrintf(
"currently multiple input sources are not not supported");
return false;
}
if (source_type != "touch" && action_index_ > 0) {
error_message_ = base::StringPrintf(
"for input source type of mouse and pen, we only support one device in "
"one sequence");
return false;
}
const base::ListValue* actions;
if (!pointer.GetList("actions", &actions)) {
error_message_ = base::StringPrintf(
"pointer[%d].actions is missing or not a list", action_index_);
return false;
}
if (!ParseActions(*actions))
return false;
return true;
}
bool ActionsParser::ParseActions(const base::ListValue& actions) {
SyntheticPointerActionListParams::ParamList param_list;
for (const auto& action_value : actions) {
const base::DictionaryValue* action;
if (!action_value.GetAsDictionary(&action)) {
error_message_ = base::StringPrintf(
"actions[%d].actions is missing or not a dictionary", action_index_);
return false;
} else if (!ParseAction(*action, param_list)) {
return false;
}
}
if (param_list.size() > longest_action_sequence_)
longest_action_sequence_ = param_list.size();
pointer_actions_list_.push_back(param_list);
return true;
}
bool ActionsParser::ParseAction(
const base::DictionaryValue& action,
SyntheticPointerActionListParams::ParamList& param_list) {
SyntheticPointerActionParams::PointerActionType pointer_action_type =
SyntheticPointerActionParams::PointerActionType::NOT_INITIALIZED;
std::string name;
if (!action.GetString("name", &name)) {
error_message_ = base::StringPrintf(
"actions[%d].actions.name is missing or not a string", action_index_);
return false;
}
pointer_action_type = ToSyntheticPointerActionType(name);
if (pointer_action_type ==
SyntheticPointerActionParams::PointerActionType::NOT_INITIALIZED) {
error_message_ = base::StringPrintf(
"actions[%d].actions.name is an unsupported action name",
action_index_);
return false;
}
double position_x = 0;
double position_y = 0;
if (action.HasKey("x") && !action.GetDouble("x", &position_x)) {
error_message_ = base::StringPrintf("actions[%d].actions.x is not a number",
action_index_);
return false;
}
if (action.HasKey("y") && !action.GetDouble("y", &position_y)) {
error_message_ = base::StringPrintf("actions[%d].actions.y is not a number",
action_index_);
return false;
}
std::string button_name = "left";
if (action.HasKey("button") && !action.GetString("button", &button_name)) {
error_message_ = base::StringPrintf(
"actions[%d].actions.button is not a string", action_index_);
return false;
} else if (button_name != "left" && button_name != "middle" &&
button_name != "right") {
error_message_ = base::StringPrintf(
"actions[%d].actions.button is an unsupported button", action_index_);
return false;
}
SyntheticPointerActionParams::Button button =
ToSyntheticMouseButton(button_name);
double duration = 0;
int num_idle = 0;
if (pointer_action_type ==
SyntheticPointerActionParams::PointerActionType::IDLE) {
num_idle = 1;
if (action.HasKey("duration") && !action.GetDouble("duration", &duration)) {
error_message_ = base::StringPrintf(
"actions[%d].actions.x is not a number", action_index_);
return false;
}
}
// If users pause for given seconds, we convert to the number of idle frames.
if (duration > 0) {
num_idle = static_cast<int>(std::ceil(
duration / cc::BeginFrameArgs::DefaultInterval().InSecondsF()));
}
SyntheticPointerActionParams action_param(pointer_action_type);
action_param.set_index(action_index_);
switch (pointer_action_type) {
case SyntheticPointerActionParams::PointerActionType::PRESS:
action_param.set_position(gfx::PointF(position_x, position_y));
action_param.set_button(button);
break;
case SyntheticPointerActionParams::PointerActionType::MOVE:
action_param.set_position(gfx::PointF(position_x, position_y));
break;
case SyntheticPointerActionParams::PointerActionType::RELEASE:
action_param.set_button(button);
break;
case SyntheticPointerActionParams::PointerActionType::IDLE:
case SyntheticPointerActionParams::PointerActionType::NOT_INITIALIZED:
break;
}
param_list.push_back(action_param);
// We queue all the IDLE actions in the action parameter list to make sure we
// will pause long enough on the given pointer.
for (int count = 1; count < num_idle; ++count)
param_list.push_back(action_param);
return true;
}
} // namespace content