Commit f7a90b89 authored by Ella Ge's avatar Ella Ge Committed by Commit Bot

Input Prediction use PointF instead of pos_x and pos_y

This Cl makes InputData in input prediction to use
PointF instead of pos_x and pos_y.
And also adds two extra unit tests to lsq predictor

Bug: 836352
Change-Id: I3e551add7536e55be82f11ed2338b0bb9dfe8e07
Reviewed-on: https://chromium-review.googlesource.com/1093392
Commit-Queue: Ella Ge <eirage@chromium.org>
Reviewed-by: default avatarDave Tapuska <dtapuska@chromium.org>
Reviewed-by: default avatarNavid Zolghadr <nzolghadr@chromium.org>
Cr-Commit-Position: refs/heads/master@{#568031}
parent af2bd3c7
......@@ -23,7 +23,8 @@ namespace {
constexpr char kPredictor[] = "predictor";
constexpr char kInputEventPredictorTypeLsq[] = "lsq";
}
} // namespace
InputEventPrediction::InputEventPrediction() {
std::string predictor_type_ = GetFieldTrialParamValueByFeature(
......@@ -128,8 +129,7 @@ void InputEventPrediction::ResetPredictor(const WebInputEvent& event) {
void InputEventPrediction::UpdateSinglePointer(
const WebPointerProperties& event,
base::TimeTicks event_time) {
ui::InputPredictor::InputData data = {event.PositionInWidget().x,
event.PositionInWidget().y, event_time};
ui::InputPredictor::InputData data = {event.PositionInWidget(), event_time};
if (event.pointer_type == WebPointerProperties::PointerType::kMouse)
mouse_predictor_->Update(data);
else {
......@@ -152,7 +152,7 @@ bool InputEventPrediction::ResampleSinglePointer(base::TimeTicks frame_time,
if (event->pointer_type == WebPointerProperties::PointerType::kMouse) {
if (mouse_predictor_->HasPrediction() &&
mouse_predictor_->GeneratePrediction(frame_time, &predict_result)) {
event->SetPositionInWidget(predict_result.pos_x, predict_result.pos_y);
event->SetPositionInWidget(predict_result.pos);
return true;
}
} else {
......@@ -163,7 +163,7 @@ bool InputEventPrediction::ResampleSinglePointer(base::TimeTicks frame_time,
if (predictor != pointer_id_predictor_map_.end() &&
predictor->second->HasPrediction() &&
predictor->second->GeneratePrediction(frame_time, &predict_result)) {
event->SetPositionInWidget(predict_result.pos_x, predict_result.pos_y);
event->SetPositionInWidget(predict_result.pos);
return true;
}
}
......
......@@ -69,8 +69,8 @@ TEST_F(InputEventPredictionTest, MouseEvent) {
HandleEvents(mouse_move);
EXPECT_EQ(GetPredictorMapSize(), 0);
EXPECT_TRUE(GetPrediction(mouse_move, &last_point));
EXPECT_EQ(last_point.pos_x, 10);
EXPECT_EQ(last_point.pos_y, 10);
EXPECT_EQ(last_point.pos.x(), 10);
EXPECT_EQ(last_point.pos.y(), 10);
WebMouseEvent mouse_down = SyntheticWebMouseEventBuilder::Build(
WebInputEvent::kMouseDown, 10, 10, 0);
......@@ -93,8 +93,8 @@ TEST_F(InputEventPredictionTest, SingleTouchPoint) {
HandleEvents(touch_event);
EXPECT_EQ(GetPredictorMapSize(), 1);
EXPECT_TRUE(GetPrediction(touch_event.touches[0], &last_point));
EXPECT_EQ(last_point.pos_x, 11);
EXPECT_EQ(last_point.pos_y, 12);
EXPECT_EQ(last_point.pos.x(), 11);
EXPECT_EQ(last_point.pos.y(), 12);
touch_event.ReleasePoint(0);
HandleEvents(touch_event);
......@@ -111,8 +111,8 @@ TEST_F(InputEventPredictionTest, MouseEventTypePen) {
HandleEvents(pen_move);
EXPECT_EQ(GetPredictorMapSize(), 1);
EXPECT_TRUE(GetPrediction(pen_move, &last_point));
EXPECT_EQ(last_point.pos_x, 10);
EXPECT_EQ(last_point.pos_y, 10);
EXPECT_EQ(last_point.pos.x(), 10);
EXPECT_EQ(last_point.pos.y(), 10);
WebMouseEvent pen_leave = SyntheticWebMouseEventBuilder::Build(
WebInputEvent::kMouseLeave, 10, 10, 0,
......@@ -145,12 +145,12 @@ TEST_F(InputEventPredictionTest, MultipleTouchPoint) {
ui::InputPredictor::InputData last_point;
EXPECT_TRUE(GetPrediction(touch_event.touches[0], &last_point));
EXPECT_EQ(last_point.pos_x, 11);
EXPECT_EQ(last_point.pos_y, 12);
EXPECT_EQ(last_point.pos.x(), 11);
EXPECT_EQ(last_point.pos.y(), 12);
EXPECT_TRUE(GetPrediction(touch_event.touches[1], &last_point));
EXPECT_EQ(last_point.pos_x, 25);
EXPECT_EQ(last_point.pos_y, 25);
EXPECT_EQ(last_point.pos.x(), 25);
EXPECT_EQ(last_point.pos.y(), 25);
touch_event.ReleasePoint(0);
HandleEvents(touch_event);
......
......@@ -2175,7 +2175,7 @@ TEST_P(InputHandlerProxyEventQueueTest, ScrollPredictorTest) {
HandleGestureEvent(WebInputEvent::kGestureScrollUpdate, -15);
input_handler_proxy_->DeliverInputForBeginFrame();
EXPECT_TRUE(GestureScrollEventPredictionAvailable(&result));
EXPECT_EQ(-35, result.pos_y);
EXPECT_EQ(-35, result.pos.y());
testing::Mock::VerifyAndClearExpectations(&mock_input_handler_);
......
......@@ -27,8 +27,7 @@ bool EmptyPredictor::HasPrediction() const {
bool EmptyPredictor::GeneratePrediction(base::TimeTicks frame_time,
InputData* result) const {
if (!last_input_.time_stamp.is_null()) {
result->pos_x = last_input_.pos_x;
result->pos_y = last_input_.pos_y;
result->pos = last_input_.pos;
return true;
}
return false;
......
......@@ -9,6 +9,7 @@
#include "base/macros.h"
#include "ui/events/base_event_utils.h"
#include "ui/gfx/geometry/point_f.h"
namespace ui {
......@@ -20,8 +21,7 @@ class InputPredictor {
virtual ~InputPredictor() = default;
struct InputData {
double pos_x;
double pos_y;
gfx::PointF pos;
base::TimeTicks time_stamp;
};
......
......@@ -54,8 +54,8 @@ void LeastSquaresPredictor::Update(const InputData& cur_input) {
max_interval_millisecond)
Reset();
x_queue_.push_back(cur_input.pos_x);
y_queue_.push_back(cur_input.pos_y);
x_queue_.push_back(cur_input.pos.x());
y_queue_.push_back(cur_input.pos.y());
time_.push_back(cur_input.time_stamp);
if (time_.size() > kSize) {
x_queue_.pop_front();
......@@ -90,8 +90,8 @@ bool LeastSquaresPredictor::GeneratePrediction(base::TimeTicks frame_time,
SolveLeastSquares(time_matrix, y_queue_, b2)) {
gfx::Vector3dF prediction_time(1, dt, dt * dt);
result->pos_x = gfx::DotProduct(prediction_time, b1);
result->pos_y = gfx::DotProduct(prediction_time, b2);
result->pos.set_x(gfx::DotProduct(prediction_time, b1));
result->pos.set_y(gfx::DotProduct(prediction_time, b2));
return true;
}
}
......
......@@ -5,78 +5,115 @@
#include "ui/events/blink/prediction/least_squares_predictor.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
constexpr double kEpsilon = 0.01;
} // namespace
namespace ui {
// The epsilon of predicted result.
const double kEpsilon = 0.01;
class LSQPredictorTest : public testing::Test {
public:
LSQPredictorTest() {}
base::TimeTicks FromMilliseconds(int64_t ms) {
return base::TimeTicks() + base::TimeDelta::FromMilliseconds(ms);
}
void SetUp() override {
predictor_ = std::make_unique<ui::LeastSquaresPredictor>();
}
static base::TimeTicks FromMilliseconds(int64_t ms) {
return base::TimeTicks() + base::TimeDelta::FromMilliseconds(ms);
}
TEST(LSQPredictorTest, ShouldHasPrediction) {
void ValidateLeastSquaresPredictor(const std::vector<double>& x,
const std::vector<double>& y,
const std::vector<double>& timestamp_ms) {
predictor_->Reset();
ui::InputPredictor::InputData result;
for (size_t i = 0; i < timestamp_ms.size(); i++) {
if (i >= LeastSquaresPredictor::kSize) {
EXPECT_TRUE(predictor_->GeneratePrediction(
FromMilliseconds(timestamp_ms[i]), &result));
EXPECT_NEAR(result.pos.x(), x[i], kEpsilon);
EXPECT_NEAR(result.pos.y(), y[i], kEpsilon);
}
InputPredictor::InputData data = {gfx::PointF(x[i], y[i]),
FromMilliseconds(timestamp_ms[i])};
predictor_->Update(data);
}
}
protected:
std::unique_ptr<LeastSquaresPredictor> predictor_;
DISALLOW_COPY_AND_ASSIGN(LSQPredictorTest);
};
TEST_F(LSQPredictorTest, ShouldHasPrediction) {
LeastSquaresPredictor predictor;
for (size_t i = 0; i < LeastSquaresPredictor::kSize; i++) {
// First |kSize| point do not have prediction available.
EXPECT_FALSE(predictor.HasPrediction());
InputPredictor::InputData data = {1 /* x */, 1 /* y */,
InputPredictor::InputData data = {gfx::PointF(1, 1),
FromMilliseconds(8 * i)};
predictor.Update(data);
}
EXPECT_TRUE(predictor.HasPrediction());
}
// Test the lest squares filter behavior.
// Tests the lest squares filter behavior.
// The data set is generated by a "known to work" quadratic fit.
TEST(LSQPredictorTest, PredictedValue) {
LeastSquaresPredictor predictor;
TEST_F(LSQPredictorTest, PredictedValue) {
std::vector<double> x = {22, 58, 102, 108.094};
std::vector<double> y = {100, 100, 100, 100};
std::vector<double> t = {13, 21, 37, 42};
ValidateLeastSquaresPredictor(x, y, t);
x = {100, 100, 101, 104.126};
y = {120, 280, 600, 1364.93};
t = {101, 126, 148, 180};
ValidateLeastSquaresPredictor(x, y, t);
}
std::vector<double> x = {22, 58, 102};
std::vector<double> y = {100, 100, 100};
std::vector<base::TimeTicks> t = {FromMilliseconds(13), FromMilliseconds(21),
FromMilliseconds(37)};
// Tests the LSQ predictor predict linear value correctly.
TEST_F(LSQPredictorTest, PredictLinearValue) {
std::vector<double> x = {8, 16, 24, 32, 40};
std::vector<double> y = {300, 410, 520, 630, 740};
std::vector<double> t = {8, 16, 24, 32, 40};
ValidateLeastSquaresPredictor(x, y, t);
}
for (int i = 0; i < 3; i++) {
InputPredictor::InputData data = {x[i], y[i], t[i]};
predictor.Update(data);
}
// Tests the LSQ predictor predict quadratic value correctly.
TEST_F(LSQPredictorTest, PredictQuadraticValue) {
std::vector<double> x = {2, 8, 18, 32, 50};
std::vector<double> y = {100, 400, 900, 1600, 2500};
std::vector<double> t = {8, 16, 24, 32, 40};
ValidateLeastSquaresPredictor(x, y, t);
}
// Tests that lsq predictor will not crash when given constant time stamp.
TEST_F(LSQPredictorTest, ConstantTimeStampNotCrash) {
std::vector<double> x = {100, 101, 102};
std::vector<double> y = {101, 102, 103};
std::vector<double> t = {0, 0, 0};
for (size_t i = 0; i < t.size(); i++) {
InputPredictor::InputData data = {gfx::PointF(x[i], y[i]),
FromMilliseconds(t[i])};
predictor_->Update(data);
}
ui::InputPredictor::InputData result;
EXPECT_TRUE(predictor.GeneratePrediction(FromMilliseconds(42), &result));
EXPECT_NEAR(result.pos_x, 108.094, kEpsilon);
EXPECT_NEAR(result.pos_y, 100, kEpsilon);
x = {100, 100, 101};
y = {120, 280, 600};
t = {FromMilliseconds(101), FromMilliseconds(126), FromMilliseconds(148)};
for (int i = 0; i < 3; i++) {
InputPredictor::InputData data = {x[i], y[i], t[i]};
predictor.Update(data);
EXPECT_FALSE(predictor_->GeneratePrediction(FromMilliseconds(42), &result));
x = {100, 100, 100};
y = {100, 100, 100};
t = {100, 100, 100};
for (size_t i = 0; i < t.size(); i++) {
InputPredictor::InputData data = {gfx::PointF(x[i], y[i]),
FromMilliseconds(t[i])};
predictor_->Update(data);
}
EXPECT_TRUE(predictor.GeneratePrediction(FromMilliseconds(180), &result));
EXPECT_NEAR(result.pos_x, 104.126, kEpsilon);
EXPECT_NEAR(result.pos_y, 1364.93, kEpsilon);
}
// Test that lsq predictor will not crash when given constant time stamp.
TEST(LSQPredictorTest, ConstantTimeStampNotCrash) {
LeastSquaresPredictor predictor;
InputPredictor::InputData data = {100 /* x */, 101 /* y */,
FromMilliseconds(0)};
predictor.Update(data);
data = {101 /* x */, 102 /* y */, FromMilliseconds(0)};
predictor.Update(data);
data = {102 /* x */, 103 /* y */, FromMilliseconds(0)};
predictor.Update(data);
EXPECT_FALSE(predictor.GeneratePrediction(FromMilliseconds(42), &data));
data = {100 /* x */, 100 /* y */, FromMilliseconds(100)};
predictor.Update(data);
data = {100 /* x */, 100 /* y */, FromMilliseconds(100)};
predictor.Update(data);
EXPECT_FALSE(predictor.GeneratePrediction(FromMilliseconds(42), &data));
EXPECT_FALSE(predictor_->GeneratePrediction(FromMilliseconds(42), &result));
}
} // namespace ui
......@@ -60,8 +60,7 @@ void ScrollPredictor::UpdatePrediction(const WebScopedInputEvent& event) {
static_cast<const WebGestureEvent&>(*event);
current_accumulated_delta_.Offset(gesture_event.data.scroll_update.delta_x,
gesture_event.data.scroll_update.delta_y);
InputPredictor::InputData data = {current_accumulated_delta_.x(),
current_accumulated_delta_.y(),
InputPredictor::InputData data = {current_accumulated_delta_,
gesture_event.TimeStamp()};
predictor_->Update(data);
}
......@@ -74,8 +73,7 @@ void ScrollPredictor::ResampleEvent(base::TimeTicks time_stamp,
InputPredictor::InputData result;
if (predictor_->HasPrediction() &&
predictor_->GeneratePrediction(time_stamp, &result)) {
gfx::PointF predicted_accumulated_delta_ =
gfx::PointF(result.pos_x, result.pos_y);
gfx::PointF predicted_accumulated_delta_ = result.pos;
gesture_event->data.scroll_update.delta_x =
predicted_accumulated_delta_.x() - last_accumulated_delta_.x();
gesture_event->data.scroll_update.delta_y =
......
......@@ -120,7 +120,7 @@ TEST_F(ScrollPredictorTest, ResampleGestureScrollEvents) {
// Cumulative amount of scroll from the GSB is stored in the empty predictor.
EXPECT_TRUE(PredictionAvailable(&result));
EXPECT_EQ(-80, result.pos_y);
EXPECT_EQ(-80, result.pos.y());
// Send another GSB, Prediction will be reset.
gesture_begin = CreateGestureScrollEvent(WebInputEvent::kGestureScrollBegin);
......@@ -136,7 +136,7 @@ TEST_F(ScrollPredictorTest, ResampleGestureScrollEvents) {
->data.scroll_update.delta_y);
// Total amount of scroll is track from the last GSB.
EXPECT_TRUE(PredictionAvailable(&result));
EXPECT_EQ(-35, result.pos_y);
EXPECT_EQ(-35, result.pos.y());
}
TEST_F(ScrollPredictorTest, ScrollInDifferentDirection) {
......@@ -154,7 +154,7 @@ TEST_F(ScrollPredictorTest, ScrollInDifferentDirection) {
static_cast<const blink::WebGestureEvent*>(gesture_update.get())
->data.scroll_update.delta_y);
EXPECT_TRUE(PredictionAvailable(&result));
EXPECT_EQ(-20, result.pos_y);
EXPECT_EQ(-20, result.pos.y());
// Scroll up.
gesture_update =
......@@ -165,8 +165,8 @@ TEST_F(ScrollPredictorTest, ScrollInDifferentDirection) {
EXPECT_EQ(25, static_cast<const blink::WebGestureEvent*>(gesture_update.get())
->data.scroll_update.delta_y);
EXPECT_TRUE(PredictionAvailable(&result));
EXPECT_EQ(0, result.pos_x);
EXPECT_EQ(5, result.pos_y);
EXPECT_EQ(0, result.pos.x());
EXPECT_EQ(5, result.pos.y());
// Scroll left + right.
gesture_update =
......@@ -180,8 +180,8 @@ TEST_F(ScrollPredictorTest, ScrollInDifferentDirection) {
EXPECT_EQ(0, static_cast<const blink::WebGestureEvent*>(gesture_update.get())
->data.scroll_update.delta_y);
EXPECT_TRUE(PredictionAvailable(&result));
EXPECT_EQ(25, result.pos_x);
EXPECT_EQ(5, result.pos_y);
EXPECT_EQ(25, result.pos.x());
EXPECT_EQ(5, result.pos.y());
}
TEST_F(ScrollPredictorTest, ScrollUpdateWithEmptyOriginalEventList) {
......@@ -221,7 +221,7 @@ TEST_F(ScrollPredictorTest, ScrollUpdateWithEmptyOriginalEventList) {
// Prediction only track GSU with original event list.
EXPECT_TRUE(PredictionAvailable(&result));
EXPECT_EQ(-30, result.pos_y);
EXPECT_EQ(-30, result.pos.y());
}
TEST_F(ScrollPredictorTest, LSQPredictorTest) {
......@@ -270,7 +270,7 @@ TEST_F(ScrollPredictorTest, LSQPredictorTest) {
static_cast<const blink::WebGestureEvent*>(gesture_update.get())
->TimeStamp());
EXPECT_TRUE(PredictionAvailable(&result, 32 /* ms */));
EXPECT_EQ(-120, result.pos_y);
EXPECT_EQ(-120, result.pos.y());
gesture_update = CreateGestureScrollEvent(WebInputEvent::kGestureScrollUpdate,
0, -30, 32 /* ms */);
......@@ -283,7 +283,7 @@ TEST_F(ScrollPredictorTest, LSQPredictorTest) {
static_cast<const blink::WebGestureEvent*>(gesture_update.get())
->TimeStamp());
EXPECT_TRUE(PredictionAvailable(&result, 40 /* ms */));
EXPECT_EQ(-150, result.pos_y);
EXPECT_EQ(-150, result.pos.y());
}
} // namespace test
......
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