1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "third_party/blink/renderer/platform/scheduler/main_thread/user_model.h"
6
7 namespace blink {
8 namespace scheduler {
9
UserModel()10 UserModel::UserModel()
11 : pending_input_event_count_(0),
12 is_gesture_active_(false),
13 is_gesture_expected_(false) {}
14
DidStartProcessingInputEvent(blink::WebInputEvent::Type type,const base::TimeTicks now)15 void UserModel::DidStartProcessingInputEvent(blink::WebInputEvent::Type type,
16 const base::TimeTicks now) {
17 last_input_signal_time_ = now;
18 if (type == blink::WebInputEvent::Type::kTouchStart ||
19 type == blink::WebInputEvent::Type::kGestureScrollBegin ||
20 type == blink::WebInputEvent::Type::kGesturePinchBegin) {
21 // Only update stats once per gesture.
22 if (!is_gesture_active_)
23 last_gesture_start_time_ = now;
24
25 is_gesture_active_ = true;
26 }
27
28 // We need to track continuous gestures seperatly for scroll detection
29 // because taps should not be confused with scrolls.
30 if (type == blink::WebInputEvent::Type::kGestureScrollBegin ||
31 type == blink::WebInputEvent::Type::kGestureScrollEnd ||
32 type == blink::WebInputEvent::Type::kGestureScrollUpdate ||
33 type == blink::WebInputEvent::Type::kGestureFlingStart ||
34 type == blink::WebInputEvent::Type::kGestureFlingCancel ||
35 type == blink::WebInputEvent::Type::kGesturePinchBegin ||
36 type == blink::WebInputEvent::Type::kGesturePinchEnd ||
37 type == blink::WebInputEvent::Type::kGesturePinchUpdate) {
38 last_continuous_gesture_time_ = now;
39 }
40
41 // If the gesture has ended, clear |is_gesture_active_| and record a UMA
42 // metric that tracks its duration.
43 if (type == blink::WebInputEvent::Type::kGestureScrollEnd ||
44 type == blink::WebInputEvent::Type::kGesturePinchEnd ||
45 type == blink::WebInputEvent::Type::kGestureFlingStart ||
46 type == blink::WebInputEvent::Type::kTouchEnd) {
47 is_gesture_active_ = false;
48 }
49
50 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
51 "is_gesture_active", is_gesture_active_);
52
53 pending_input_event_count_++;
54 }
55
DidFinishProcessingInputEvent(const base::TimeTicks now)56 void UserModel::DidFinishProcessingInputEvent(const base::TimeTicks now) {
57 last_input_signal_time_ = now;
58 if (pending_input_event_count_ > 0)
59 pending_input_event_count_--;
60 }
61
TimeLeftInUserGesture(base::TimeTicks now) const62 base::TimeDelta UserModel::TimeLeftInUserGesture(base::TimeTicks now) const {
63 base::TimeDelta escalated_priority_duration =
64 base::TimeDelta::FromMilliseconds(kGestureEstimationLimitMillis);
65
66 // If the input event is still pending, go into input prioritized policy and
67 // check again later.
68 if (pending_input_event_count_ > 0)
69 return escalated_priority_duration;
70 if (last_input_signal_time_.is_null() ||
71 last_input_signal_time_ + escalated_priority_duration < now) {
72 return base::TimeDelta();
73 }
74 return last_input_signal_time_ + escalated_priority_duration - now;
75 }
76
IsGestureExpectedSoon(const base::TimeTicks now,base::TimeDelta * prediction_valid_duration)77 bool UserModel::IsGestureExpectedSoon(
78 const base::TimeTicks now,
79 base::TimeDelta* prediction_valid_duration) {
80 bool was_gesture_expected = is_gesture_expected_;
81 is_gesture_expected_ =
82 IsGestureExpectedSoonImpl(now, prediction_valid_duration);
83
84 // Track when we start expecting a gesture so we can work out later if a
85 // gesture actually happened.
86 if (!was_gesture_expected && is_gesture_expected_)
87 last_gesture_expected_start_time_ = now;
88 return is_gesture_expected_;
89 }
90
IsGestureExpectedSoonImpl(const base::TimeTicks now,base::TimeDelta * prediction_valid_duration) const91 bool UserModel::IsGestureExpectedSoonImpl(
92 const base::TimeTicks now,
93 base::TimeDelta* prediction_valid_duration) const {
94 if (is_gesture_active_) {
95 if (IsGestureExpectedToContinue(now, prediction_valid_duration))
96 return false;
97 *prediction_valid_duration =
98 base::TimeDelta::FromMilliseconds(kExpectSubsequentGestureMillis);
99 return true;
100 } else {
101 // If we have finished a gesture then a subsequent gesture is deemed likely.
102 base::TimeDelta expect_subsequent_gesture_for =
103 base::TimeDelta::FromMilliseconds(kExpectSubsequentGestureMillis);
104 if (last_continuous_gesture_time_.is_null() ||
105 last_continuous_gesture_time_ + expect_subsequent_gesture_for <= now) {
106 return false;
107 }
108 *prediction_valid_duration =
109 last_continuous_gesture_time_ + expect_subsequent_gesture_for - now;
110 return true;
111 }
112 }
113
IsGestureExpectedToContinue(const base::TimeTicks now,base::TimeDelta * prediction_valid_duration) const114 bool UserModel::IsGestureExpectedToContinue(
115 const base::TimeTicks now,
116 base::TimeDelta* prediction_valid_duration) const {
117 if (!is_gesture_active_)
118 return false;
119
120 base::TimeDelta median_gesture_duration =
121 base::TimeDelta::FromMilliseconds(kMedianGestureDurationMillis);
122 base::TimeTicks expected_gesture_end_time =
123 last_gesture_start_time_ + median_gesture_duration;
124
125 if (expected_gesture_end_time > now) {
126 *prediction_valid_duration = expected_gesture_end_time - now;
127 return true;
128 }
129 return false;
130 }
131
Reset(base::TimeTicks now)132 void UserModel::Reset(base::TimeTicks now) {
133 last_input_signal_time_ = base::TimeTicks();
134 last_gesture_start_time_ = base::TimeTicks();
135 last_continuous_gesture_time_ = base::TimeTicks();
136 last_gesture_expected_start_time_ = base::TimeTicks();
137 last_reset_time_ = now;
138 is_gesture_active_ = false;
139 is_gesture_expected_ = false;
140 pending_input_event_count_ = 0;
141 }
142
AsValueInto(base::trace_event::TracedValue * state) const143 void UserModel::AsValueInto(base::trace_event::TracedValue* state) const {
144 auto dictionary_scope = state->BeginDictionaryScoped("user_model");
145 state->SetInteger("pending_input_event_count", pending_input_event_count_);
146 state->SetDouble(
147 "last_input_signal_time",
148 (last_input_signal_time_ - base::TimeTicks()).InMillisecondsF());
149 state->SetDouble(
150 "last_gesture_start_time",
151 (last_gesture_start_time_ - base::TimeTicks()).InMillisecondsF());
152 state->SetDouble(
153 "last_continuous_gesture_time",
154 (last_continuous_gesture_time_ - base::TimeTicks()).InMillisecondsF());
155 state->SetDouble("last_gesture_expected_start_time",
156 (last_gesture_expected_start_time_ - base::TimeTicks())
157 .InMillisecondsF());
158 state->SetDouble("last_reset_time",
159 (last_reset_time_ - base::TimeTicks()).InMillisecondsF());
160 state->SetBoolean("is_gesture_expected", is_gesture_expected_);
161 state->SetBoolean("is_gesture_active", is_gesture_active_);
162 }
163
164 } // namespace scheduler
165 } // namespace blink
166