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

Add resample event to main thread event queue

This CL adds input event predictor in main thread event queue
under a flag kResampleInputEvents.
It is the basic structure for resample events, without only an
empty predictor. The input predictor handled events before the
event is dispatched. And apply current time to the event.

design doc:
https://docs.google.com/document/d/1DLfibi2NkV85p7AfEtNkvy24d283VRBSd3hz1Qh24Jw/edit?usp=sharing

Bug: 836352
Change-Id: I7c17a33b2e0e5e9a51920e54a9b8ce795537f4ef
Reviewed-on: https://chromium-review.googlesource.com/860429Reviewed-by: default avatarDave Tapuska <dtapuska@chromium.org>
Reviewed-by: default avatarAlex Moshchuk <alexmos@chromium.org>
Reviewed-by: default avatarNavid Zolghadr <nzolghadr@chromium.org>
Commit-Queue: Ella Ge <eirage@chromium.org>
Cr-Commit-Position: refs/heads/master@{#553744}
parent ee07658e
...@@ -304,6 +304,10 @@ const base::Feature kRenderingPipelineThrottling{ ...@@ -304,6 +304,10 @@ const base::Feature kRenderingPipelineThrottling{
const base::Feature kRequireCSSExtensionForFile{ const base::Feature kRequireCSSExtensionForFile{
"RequireCSSExtensionForFile", base::FEATURE_ENABLED_BY_DEFAULT}; "RequireCSSExtensionForFile", base::FEATURE_ENABLED_BY_DEFAULT};
// Enables resampling input events on main thread.
const base::Feature kResamplingInputEvents{"ResamplingInputEvents",
base::FEATURE_DISABLED_BY_DEFAULT};
// Loading Dispatcher v0 support with ResourceLoadScheduler (crbug.com/729954). // Loading Dispatcher v0 support with ResourceLoadScheduler (crbug.com/729954).
const base::Feature kResourceLoadScheduler{"ResourceLoadScheduler", const base::Feature kResourceLoadScheduler{"ResourceLoadScheduler",
base::FEATURE_ENABLED_BY_DEFAULT}; base::FEATURE_ENABLED_BY_DEFAULT};
......
...@@ -72,6 +72,7 @@ CONTENT_EXPORT extern const base::Feature kPWAFullCodeCache; ...@@ -72,6 +72,7 @@ CONTENT_EXPORT extern const base::Feature kPWAFullCodeCache;
CONTENT_EXPORT extern const base::Feature kRasterInducingScroll; CONTENT_EXPORT extern const base::Feature kRasterInducingScroll;
CONTENT_EXPORT extern const base::Feature kRenderingPipelineThrottling; CONTENT_EXPORT extern const base::Feature kRenderingPipelineThrottling;
CONTENT_EXPORT extern const base::Feature kRequireCSSExtensionForFile; CONTENT_EXPORT extern const base::Feature kRequireCSSExtensionForFile;
CONTENT_EXPORT extern const base::Feature kResamplingInputEvents;
CONTENT_EXPORT extern const base::Feature kResourceLoadScheduler; CONTENT_EXPORT extern const base::Feature kResourceLoadScheduler;
CONTENT_EXPORT extern const base::Feature kRootLayerScrolling; CONTENT_EXPORT extern const base::Feature kRootLayerScrolling;
CONTENT_EXPORT extern const base::Feature CONTENT_EXPORT extern const base::Feature
......
...@@ -186,6 +186,8 @@ target(link_target_type, "renderer") { ...@@ -186,6 +186,8 @@ target(link_target_type, "renderer") {
"indexed_db/webidbfactory_impl.h", "indexed_db/webidbfactory_impl.h",
"input/frame_input_handler_impl.cc", "input/frame_input_handler_impl.cc",
"input/frame_input_handler_impl.h", "input/frame_input_handler_impl.h",
"input/input_event_prediction.cc",
"input/input_event_prediction.h",
"input/input_target_client_impl.cc", "input/input_target_client_impl.cc",
"input/input_target_client_impl.h", "input/input_target_client_impl.h",
"input/main_thread_event_queue.cc", "input/main_thread_event_queue.cc",
......
// Copyright 2018 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/input/input_event_prediction.h"
#include "base/feature_list.h"
#include "content/public/common/content_features.h"
#include "ui/events/blink/prediction/empty_predictor.h"
using blink::WebInputEvent;
using blink::WebMouseEvent;
using blink::WebPointerEvent;
using blink::WebPointerProperties;
using blink::WebTouchEvent;
namespace content {
namespace {
std::unique_ptr<ui::InputPredictor> SetUpPredictor() {
return std::make_unique<ui::EmptyPredictor>();
}
} // namespace
InputEventPrediction::InputEventPrediction() {
mouse_predictor_ = SetUpPredictor();
}
InputEventPrediction::~InputEventPrediction() {}
void InputEventPrediction::HandleEvents(
const blink::WebCoalescedInputEvent& coalesced_event,
base::TimeTicks frame_time,
blink::WebInputEvent* event) {
switch (event->GetType()) {
case WebInputEvent::kMouseMove:
case WebInputEvent::kTouchMove:
case WebInputEvent::kPointerMove: {
size_t coalesced_size = coalesced_event.CoalescedEventSize();
for (size_t i = 0; i < coalesced_size; i++)
UpdatePrediction(coalesced_event.CoalescedEvent(i));
ApplyResampling(frame_time, event);
break;
}
case WebInputEvent::kTouchScrollStarted:
case WebInputEvent::kPointerCausedUaAction:
pointer_id_predictor_map_.clear();
break;
default:
ResetPredictor(*event);
}
}
void InputEventPrediction::UpdatePrediction(const WebInputEvent& event) {
if (WebInputEvent::IsTouchEventType(event.GetType())) {
DCHECK(event.GetType() == WebInputEvent::kTouchMove);
const WebTouchEvent& touch_event = static_cast<const WebTouchEvent&>(event);
for (unsigned i = 0; i < touch_event.touches_length; ++i) {
if (touch_event.touches[i].state == blink::WebTouchPoint::kStateMoved) {
UpdateSinglePointer(touch_event.touches[i], touch_event.TimeStamp());
}
}
} else if (WebInputEvent::IsMouseEventType(event.GetType())) {
DCHECK(event.GetType() == WebInputEvent::kMouseMove);
UpdateSinglePointer(static_cast<const WebMouseEvent&>(event),
event.TimeStamp());
} else if (WebInputEvent::IsPointerEventType(event.GetType())) {
DCHECK(event.GetType() == WebInputEvent::kPointerMove);
UpdateSinglePointer(static_cast<const WebPointerEvent&>(event),
event.TimeStamp());
}
}
void InputEventPrediction::ApplyResampling(base::TimeTicks frame_time,
WebInputEvent* event) {
if (event->GetType() == WebInputEvent::kTouchMove) {
WebTouchEvent* touch_event = static_cast<WebTouchEvent*>(event);
for (unsigned i = 0; i < touch_event->touches_length; ++i) {
if (ResampleSinglePointer(frame_time, &touch_event->touches[i]))
event->SetTimeStamp(frame_time);
}
} else if (event->GetType() == WebInputEvent::kMouseMove) {
if (ResampleSinglePointer(frame_time, static_cast<WebMouseEvent*>(event)))
event->SetTimeStamp(frame_time);
} else if (event->GetType() == WebInputEvent::kPointerMove) {
if (ResampleSinglePointer(frame_time, static_cast<WebPointerEvent*>(event)))
event->SetTimeStamp(frame_time);
}
}
void InputEventPrediction::ResetPredictor(const WebInputEvent& event) {
if (WebInputEvent::IsTouchEventType(event.GetType())) {
const WebTouchEvent& touch_event = static_cast<const WebTouchEvent&>(event);
for (unsigned i = 0; i < touch_event.touches_length; ++i) {
if (touch_event.touches[i].state != blink::WebTouchPoint::kStateMoved &&
touch_event.touches[i].state !=
blink::WebTouchPoint::kStateStationary)
pointer_id_predictor_map_.erase(touch_event.touches[i].id);
}
} else if (WebInputEvent::IsMouseEventType(event.GetType())) {
ResetSinglePredictor(static_cast<const WebMouseEvent&>(event));
} else if (WebInputEvent::IsPointerEventType(event.GetType())) {
ResetSinglePredictor(static_cast<const WebPointerEvent&>(event));
}
}
void InputEventPrediction::UpdateSinglePointer(
const WebPointerProperties& event,
base::TimeTicks event_time) {
ui::InputPredictor::InputData data = {event.PositionInWidget().x,
event.PositionInWidget().y, event_time};
if (event.pointer_type == WebPointerProperties::PointerType::kMouse)
mouse_predictor_->Update(data);
else {
auto predictor = pointer_id_predictor_map_.find(event.id);
if (predictor != pointer_id_predictor_map_.end()) {
predictor->second->Update(data);
} else {
pointer_id_predictor_map_.insert({event.id, SetUpPredictor()});
pointer_id_predictor_map_[event.id]->Update(data);
}
}
}
bool InputEventPrediction::ResampleSinglePointer(base::TimeTicks frame_time,
WebPointerProperties* event) {
ui::InputPredictor::InputData predict_result;
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);
return true;
}
} else {
// Reset mouse predictor if pointer type is touch or stylus
mouse_predictor_->Reset();
auto predictor = pointer_id_predictor_map_.find(event->id);
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);
return true;
}
}
return false;
}
void InputEventPrediction::ResetSinglePredictor(
const WebPointerProperties& event) {
if (event.pointer_type == WebPointerProperties::PointerType::kMouse)
mouse_predictor_->Reset();
else
pointer_id_predictor_map_.erase(event.id);
}
} // namespace content
// Copyright 2018 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.
#ifndef CONTENT_RENDERER_INPUT_INPUT_EVENT_PREDICTION_H_
#define CONTENT_RENDERER_INPUT_INPUT_EVENT_PREDICTION_H_
#include <list>
#include <unordered_map>
#include "content/renderer/input/scoped_web_input_event_with_latency_info.h"
#include "ui/events/blink/prediction/input_predictor.h"
#include "ui/events/event.h"
using blink::WebInputEvent;
using blink::WebPointerProperties;
namespace content {
// Handle resampling of WebMouseEvent, WebTouchEvent and WebPointerEvent.
// This class stores prediction of all active pointers.
class CONTENT_EXPORT InputEventPrediction {
public:
InputEventPrediction();
~InputEventPrediction();
void HandleEvents(const blink::WebCoalescedInputEvent& coalesced_event,
base::TimeTicks frame_time,
blink::WebInputEvent* event);
private:
// The following three function is for handling multiple TouchPoints in a
// WebTouchEvent. They should be more neat when WebTouchEvent is elimated.
// Cast events from WebInputEvent to WebPointerProperties. Call
// UpdateSinglePointer for each pointer.
void UpdatePrediction(const WebInputEvent& event);
// Cast events from WebInputEvent to WebPointerProperties. Call
// ResamplingSinglePointer for each poitner.
void ApplyResampling(base::TimeTicks frame_time, WebInputEvent* event);
// Cast events from WebInputEvent to WebPointerProperties. Call
// ResetSinglePredictor for each pointer.
void ResetPredictor(const WebInputEvent& event);
// Get single predictor based on event id and type, and update the predictor
// with new events coords.
void UpdateSinglePointer(const WebPointerProperties& event,
base::TimeTicks time);
// Get single predictor based on event id and type, apply resampling event
// coordinates.
bool ResampleSinglePointer(base::TimeTicks time, WebPointerProperties* event);
// Get single predictor based on event id and type. For mouse, reset the
// predictor, for other pointer type, remove it from mapping.
void ResetSinglePredictor(const WebPointerProperties& event);
friend class InputEventPredictionTest;
std::unordered_map<ui::PointerId, std::unique_ptr<ui::InputPredictor>>
pointer_id_predictor_map_;
std::unique_ptr<ui::InputPredictor> mouse_predictor_;
DISALLOW_COPY_AND_ASSIGN(InputEventPrediction);
};
} // namespace content
#endif // CONTENT_RENDERER_INPUT_INPUT_EVENT_PREDICTION_H_
// Copyright 2018 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/input/input_event_prediction.h"
#include "content/common/input/synthetic_web_input_event_builders.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/events/base_event_utils.h"
#include "ui/events/blink/prediction/empty_predictor.h"
using blink::WebInputEvent;
using blink::WebMouseEvent;
using blink::WebPointerProperties;
using blink::WebTouchEvent;
namespace content {
class InputEventPredictionTest : public testing::Test {
public:
InputEventPredictionTest() {
event_predictor_ = std::make_unique<InputEventPrediction>();
}
int GetPredictorMapSize() const {
return event_predictor_->pointer_id_predictor_map_.size();
}
bool GetPrediction(const WebPointerProperties& event,
ui::InputPredictor::InputData* result) const {
if (!event_predictor_)
return false;
if (event.pointer_type == WebPointerProperties::PointerType::kMouse) {
return event_predictor_->mouse_predictor_->GeneratePrediction(
WebInputEvent::GetStaticTimeStampForTests(), result);
} else {
auto predictor =
event_predictor_->pointer_id_predictor_map_.find(event.id);
if (predictor != event_predictor_->pointer_id_predictor_map_.end())
return predictor->second->GeneratePrediction(
WebInputEvent::GetStaticTimeStampForTests(), result);
else
return false;
}
}
void HandleEvents(const WebInputEvent& event) {
blink::WebCoalescedInputEvent coalesced_event(event);
event_predictor_->HandleEvents(coalesced_event,
WebInputEvent::GetStaticTimeStampForTests(),
coalesced_event.EventPointer());
}
protected:
std::unique_ptr<InputEventPrediction> event_predictor_;
DISALLOW_COPY_AND_ASSIGN(InputEventPredictionTest);
};
TEST_F(InputEventPredictionTest, MouseEvent) {
WebMouseEvent mouse_move = SyntheticWebMouseEventBuilder::Build(
WebInputEvent::kMouseMove, 10, 10, 0);
ui::InputPredictor::InputData last_point;
EXPECT_FALSE(GetPrediction(mouse_move, &last_point));
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);
WebMouseEvent mouse_down = SyntheticWebMouseEventBuilder::Build(
WebInputEvent::kMouseDown, 10, 10, 0);
HandleEvents(mouse_down);
EXPECT_FALSE(GetPrediction(mouse_down, &last_point));
}
TEST_F(InputEventPredictionTest, SingleTouchPoint) {
SyntheticWebTouchEvent touch_event;
ui::InputPredictor::InputData last_point;
touch_event.PressPoint(10, 10);
touch_event.touches[0].pointer_type =
WebPointerProperties::PointerType::kTouch;
HandleEvents(touch_event);
EXPECT_FALSE(GetPrediction(touch_event.touches[0], &last_point));
touch_event.MovePoint(0, 11, 12);
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);
touch_event.ReleasePoint(0);
HandleEvents(touch_event);
EXPECT_FALSE(GetPrediction(touch_event.touches[0], &last_point));
}
TEST_F(InputEventPredictionTest, MouseEventTypePen) {
WebMouseEvent pen_move = SyntheticWebMouseEventBuilder::Build(
WebInputEvent::kMouseMove, 10, 10, 0,
WebPointerProperties::PointerType::kPen);
ui::InputPredictor::InputData last_point;
EXPECT_FALSE(GetPrediction(pen_move, &last_point));
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);
WebMouseEvent pen_leave = SyntheticWebMouseEventBuilder::Build(
WebInputEvent::kMouseLeave, 10, 10, 0,
WebPointerProperties::PointerType::kPen);
HandleEvents(pen_leave);
EXPECT_EQ(GetPredictorMapSize(), 0);
EXPECT_FALSE(GetPrediction(pen_leave, &last_point));
}
TEST_F(InputEventPredictionTest, MultipleTouchPoint) {
SyntheticWebTouchEvent touch_event;
// Press and move 1st touch point
touch_event.PressPoint(10, 10);
touch_event.MovePoint(0, 11, 12);
touch_event.touches[0].pointer_type =
WebPointerProperties::PointerType::kTouch;
HandleEvents(touch_event);
// Press 2nd touch point
touch_event.PressPoint(20, 30);
touch_event.touches[1].pointer_type = WebPointerProperties::PointerType::kPen;
HandleEvents(touch_event);
EXPECT_EQ(GetPredictorMapSize(), 1);
// Move 2nd touch point
touch_event.MovePoint(1, 25, 25);
HandleEvents(touch_event);
EXPECT_EQ(GetPredictorMapSize(), 2);
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_TRUE(GetPrediction(touch_event.touches[1], &last_point));
EXPECT_EQ(last_point.pos_x, 25);
EXPECT_EQ(last_point.pos_y, 25);
touch_event.ReleasePoint(0);
HandleEvents(touch_event);
EXPECT_EQ(GetPredictorMapSize(), 1);
}
TEST_F(InputEventPredictionTest, TouchAndStylusResetMousePredictor) {
WebMouseEvent mouse_move = SyntheticWebMouseEventBuilder::Build(
WebInputEvent::kMouseMove, 10, 10, 0);
HandleEvents(mouse_move);
ui::InputPredictor::InputData last_point;
EXPECT_TRUE(GetPrediction(mouse_move, &last_point));
WebMouseEvent pen_move = SyntheticWebMouseEventBuilder::Build(
WebInputEvent::kMouseMove, 20, 20, 0,
WebPointerProperties::PointerType::kPen);
pen_move.id = 1;
HandleEvents(pen_move);
EXPECT_TRUE(GetPrediction(pen_move, &last_point));
EXPECT_FALSE(GetPrediction(mouse_move, &last_point));
HandleEvents(mouse_move);
EXPECT_TRUE(GetPrediction(mouse_move, &last_point));
SyntheticWebTouchEvent touch_event;
touch_event.PressPoint(10, 10);
touch_event.touches[0].pointer_type =
WebPointerProperties::PointerType::kTouch;
HandleEvents(touch_event);
touch_event.MovePoint(0, 10, 10);
HandleEvents(touch_event);
EXPECT_TRUE(GetPrediction(touch_event.touches[0], &last_point));
EXPECT_FALSE(GetPrediction(mouse_move, &last_point));
}
// TouchScrollStarted event removes all touch points.
TEST_F(InputEventPredictionTest, TouchScrollStartedRemoveAllTouchPoints) {
SyntheticWebTouchEvent touch_event;
// Press 1st & 2nd touch point
touch_event.PressPoint(10, 10);
touch_event.touches[0].pointer_type =
WebPointerProperties::PointerType::kTouch;
touch_event.PressPoint(20, 20);
touch_event.touches[1].pointer_type =
WebPointerProperties::PointerType::kTouch;
HandleEvents(touch_event);
// Move 1st & 2nd touch point
touch_event.MovePoint(0, 15, 18);
touch_event.MovePoint(1, 25, 27);
HandleEvents(touch_event);
EXPECT_EQ(GetPredictorMapSize(), 2);
touch_event.SetType(WebInputEvent::kTouchScrollStarted);
HandleEvents(touch_event);
EXPECT_EQ(GetPredictorMapSize(), 0);
}
} // namespace content
\ No newline at end of file
...@@ -240,6 +240,11 @@ MainThreadEventQueue::MainThreadEventQueue( ...@@ -240,6 +240,11 @@ MainThreadEventQueue::MainThreadEventQueue(
} }
} }
raf_fallback_timer_.SetTaskRunner(main_task_runner); raf_fallback_timer_.SetTaskRunner(main_task_runner);
event_predictor_ =
base::FeatureList::IsEnabled(features::kResamplingInputEvents)
? std::make_unique<InputEventPrediction>()
: nullptr;
} }
MainThreadEventQueue::~MainThreadEventQueue() {} MainThreadEventQueue::~MainThreadEventQueue() {}
...@@ -392,6 +397,7 @@ void MainThreadEventQueue::DispatchEvents() { ...@@ -392,6 +397,7 @@ void MainThreadEventQueue::DispatchEvents() {
task = shared_state_.events_.Pop(); task = shared_state_.events_.Pop();
} }
HandleEventResampling(task, base::TimeTicks::Now());
// Dispatching the event is outside of critical section. // Dispatching the event is outside of critical section.
task->Dispatch(this); task->Dispatch(this);
} }
...@@ -450,6 +456,7 @@ void MainThreadEventQueue::DispatchRafAlignedInput(base::TimeTicks frame_time) { ...@@ -450,6 +456,7 @@ void MainThreadEventQueue::DispatchRafAlignedInput(base::TimeTicks frame_time) {
} }
task = shared_state_.events_.Pop(); task = shared_state_.events_.Pop();
} }
HandleEventResampling(task, frame_time);
// Dispatching the event is outside of critical section. // Dispatching the event is outside of critical section.
task->Dispatch(this); task->Dispatch(this);
} }
...@@ -507,6 +514,16 @@ bool MainThreadEventQueue::IsRafAlignedEvent( ...@@ -507,6 +514,16 @@ bool MainThreadEventQueue::IsRafAlignedEvent(
} }
} }
void MainThreadEventQueue::HandleEventResampling(
const std::unique_ptr<MainThreadEventQueueTask>& item,
base::TimeTicks frame_time) {
if (item->IsWebInputEvent() && allow_raf_aligned_input_ && event_predictor_) {
QueuedWebInputEvent* event = static_cast<QueuedWebInputEvent*>(item.get());
event_predictor_->HandleEvents(event->coalesced_event(), frame_time,
&event->event());
}
}
void MainThreadEventQueue::HandleEventOnMainThread( void MainThreadEventQueue::HandleEventOnMainThread(
const blink::WebCoalescedInputEvent& event, const blink::WebCoalescedInputEvent& event,
const ui::LatencyInfo& latency, const ui::LatencyInfo& latency,
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include "content/common/input/input_event_dispatch_type.h" #include "content/common/input/input_event_dispatch_type.h"
#include "content/public/common/content_features.h" #include "content/public/common/content_features.h"
#include "content/public/common/input_event_ack_state.h" #include "content/public/common/input_event_ack_state.h"
#include "content/renderer/input/input_event_prediction.h"
#include "content/renderer/input/main_thread_event_queue_task_list.h" #include "content/renderer/input/main_thread_event_queue_task_list.h"
#include "content/renderer/input/scoped_web_input_event_with_latency_info.h" #include "content/renderer/input/scoped_web_input_event_with_latency_info.h"
#include "third_party/blink/public/platform/scheduler/web_main_thread_scheduler.h" #include "third_party/blink/public/platform/scheduler/web_main_thread_scheduler.h"
...@@ -103,6 +104,11 @@ class CONTENT_EXPORT MainThreadEventQueue ...@@ -103,6 +104,11 @@ class CONTENT_EXPORT MainThreadEventQueue
// Request unbuffered input events until next pointerup. // Request unbuffered input events until next pointerup.
void RequestUnbufferedInputEvents(); void RequestUnbufferedInputEvents();
// Resampling event before dispatch it.
void HandleEventResampling(
const std::unique_ptr<MainThreadEventQueueTask>& item,
base::TimeTicks frame_time);
protected: protected:
friend class base::RefCountedThreadSafe<MainThreadEventQueue>; friend class base::RefCountedThreadSafe<MainThreadEventQueue>;
virtual ~MainThreadEventQueue(); virtual ~MainThreadEventQueue();
...@@ -157,6 +163,8 @@ class CONTENT_EXPORT MainThreadEventQueue ...@@ -157,6 +163,8 @@ class CONTENT_EXPORT MainThreadEventQueue
base::OneShotTimer raf_fallback_timer_; base::OneShotTimer raf_fallback_timer_;
bool use_raf_fallback_timer_; bool use_raf_fallback_timer_;
std::unique_ptr<InputEventPrediction> event_predictor_;
DISALLOW_COPY_AND_ASSIGN(MainThreadEventQueue); DISALLOW_COPY_AND_ASSIGN(MainThreadEventQueue);
}; };
......
...@@ -1595,6 +1595,7 @@ test("content_unittests") { ...@@ -1595,6 +1595,7 @@ test("content_unittests") {
"../renderer/indexed_db/mock_webidbcallbacks.h", "../renderer/indexed_db/mock_webidbcallbacks.h",
"../renderer/indexed_db/webidbcursor_impl_unittest.cc", "../renderer/indexed_db/webidbcursor_impl_unittest.cc",
"../renderer/indexed_db/webidbdatabase_impl_unittest.cc", "../renderer/indexed_db/webidbdatabase_impl_unittest.cc",
"../renderer/input/input_event_prediction_unittest.cc",
"../renderer/input/main_thread_event_queue_unittest.cc", "../renderer/input/main_thread_event_queue_unittest.cc",
"../renderer/loader/resource_dispatcher_unittest.cc", "../renderer/loader/resource_dispatcher_unittest.cc",
"../renderer/loader/shared_memory_data_consumer_handle_unittest.cc", "../renderer/loader/shared_memory_data_consumer_handle_unittest.cc",
......
...@@ -24,6 +24,9 @@ jumbo_source_set("blink") { ...@@ -24,6 +24,9 @@ jumbo_source_set("blink") {
"input_handler_proxy_client.h", "input_handler_proxy_client.h",
"input_scroll_elasticity_controller.cc", "input_scroll_elasticity_controller.cc",
"input_scroll_elasticity_controller.h", "input_scroll_elasticity_controller.h",
"prediction/empty_predictor.cc",
"prediction/empty_predictor.h",
"prediction/input_predictor.h",
"snap_fling_controller.cc", "snap_fling_controller.cc",
"snap_fling_controller.h", "snap_fling_controller.h",
"snap_fling_curve.cc", "snap_fling_curve.cc",
......
// Copyright 2018 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 "ui/events/blink/prediction/empty_predictor.h"
namespace ui {
EmptyPredictor::EmptyPredictor() {
Reset();
};
EmptyPredictor::~EmptyPredictor() = default;
void EmptyPredictor::Reset() {
last_input_.time_stamp = base::TimeTicks();
}
void EmptyPredictor::Update(const InputData& cur_input) {
last_input_ = cur_input;
}
bool EmptyPredictor::HasPrediction() const {
return false;
}
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;
return true;
}
return false;
}
} // namespace ui
// Copyright 2018 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.
#ifndef UI_EVENTS_BLINK_PREDICTION_EMPTY_PREDICTOR_H_
#define UI_EVENTS_BLINK_PREDICTION_EMPTY_PREDICTOR_H_
#include "ui/events/blink/prediction/input_predictor.h"
namespace ui {
// An empty predictor class. This will not generate any prediction.
class EmptyPredictor : public InputPredictor {
public:
EmptyPredictor();
~EmptyPredictor() override;
void Reset() override;
// store the cur_input in last_input_
void Update(const InputData& cur_input) override;
// Always returns false;
bool HasPrediction() const override;
// Returns the last_input_ for testing.
bool GeneratePrediction(base::TimeTicks frame_time,
InputData* result) const override;
private:
// store the last_input_ point for testing
InputData last_input_;
DISALLOW_COPY_AND_ASSIGN(EmptyPredictor);
};
} // namespace ui
#endif // UI_EVENTS_BLINK_PREDICTION_EMPTY_PREDICTOR_H_
// Copyright 2018 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.
#ifndef UI_EVENTS_BLINK_PREDICTION_INPUT_PREDICTOR_H_
#define UI_EVENTS_BLINK_PREDICTION_INPUT_PREDICTOR_H_
#include <memory>
#include "base/macros.h"
#include "ui/events/base_event_utils.h"
namespace ui {
// This class expects a sequence of inputs with their coordinates and timestamps
// and models the input path. It then can predict the coordinates at any given
// time.
class InputPredictor {
public:
virtual ~InputPredictor() = default;
struct InputData {
double pos_x;
double pos_y;
base::TimeTicks time_stamp;
};
// Reset should be called each time when a new line start.
virtual void Reset() = 0;
// Update the predictor with new input points.
virtual void Update(const InputData& new_input) = 0;
// Return true if the predictor is able to predict points.
virtual bool HasPrediction() const = 0;
// Generate the prediction based on current points.
virtual bool GeneratePrediction(base::TimeTicks frame_time,
InputData* result) const = 0;
};
} // namespace ui
#endif // UI_EVENTS_BLINK_PREDICTION_INPUT_PREDICTOR_H_
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