Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(258)

Unified Diff: chrome/browser/page_load_metrics/user_input_tracker.cc

Issue 2540183003: Add UserInputTracker, which keeps track of recent user input events. (Closed)
Patch Set: Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/page_load_metrics/user_input_tracker.cc
diff --git a/chrome/browser/page_load_metrics/user_input_tracker.cc b/chrome/browser/page_load_metrics/user_input_tracker.cc
new file mode 100644
index 0000000000000000000000000000000000000000..4fb96f6f6749a294af28151c893128b51739037c
--- /dev/null
+++ b/chrome/browser/page_load_metrics/user_input_tracker.cc
@@ -0,0 +1,113 @@
+// Copyright 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 "chrome/browser/page_load_metrics/user_input_tracker.h"
+
+#include <algorithm>
+
+#include "third_party/WebKit/public/platform/WebInputEvent.h"
+
+namespace page_load_metrics {
+
+namespace {
+
+// Blink's UserGestureIndicator allows events to be associated with gestures
+// that are up to 1 second old, based on guidance in the HTML spec:
+// https://html.spec.whatwg.org/multipage/interaction.html#triggered-by-user-activation.
+const int kMaxEventAgeSeconds = 1;
+
+bool IsInterestingInputEvent(const blink::WebInputEvent& event) {
+ // Ignore synthesized auto repeat events.
+ if (event.modifiers & blink::WebInputEvent::IsAutoRepeat)
+ return false;
+
+ switch (event.type) {
+ case blink::WebInputEvent::MouseDown:
+ case blink::WebInputEvent::MouseUp:
+ case blink::WebInputEvent::RawKeyDown:
+ case blink::WebInputEvent::KeyDown:
+ case blink::WebInputEvent::Char:
+ case blink::WebInputEvent::TouchStart:
+ case blink::WebInputEvent::TouchEnd:
+ return true;
+ default:
+ return false;
+ }
+}
+
+} // namespace
+
+UserInputTracker::UserInputTracker() {}
+UserInputTracker::~UserInputTracker() {}
+
+// static
+base::TimeTicks UserInputTracker::GetEventTime(
+ const blink::WebInputEvent& event) {
+ return base::TimeTicks() +
Charlie Harrison 2016/12/02 02:58:44 Can you document why this conversion is correct?
Bryan McQuade 2016/12/02 20:43:01 Done
+ base::TimeDelta::FromSecondsD(event.timeStampSeconds);
+}
+
+void UserInputTracker::OnInputEvent(const blink::WebInputEvent& event) {
+ RemoveOldInputEvents();
+
+ if (!IsInterestingInputEvent(event))
+ return;
+
+ // TODO(bmcquade): ideally we'd limit tracking to events generated by a user
+ // action, as opposed to those generated from JavaScript. The JS API isTrusted
+ // can be used to distinguish these cases. isTrusted isn't yet a property of
+ // WebInputEvent. We should consider adding it.
+
Charlie Harrison 2016/12/02 02:58:44 Should we trim event_times_ here too, to avoid it
Bryan McQuade 2016/12/02 20:43:01 Yep - moved to the rate limiting model we talked a
+ event_times_.insert(GetEventTime(event));
+}
+
+base::TimeTicks UserInputTracker::FindMostRecentUserInputEventBefore(
+ base::TimeTicks time) {
+ RemoveOldInputEvents();
+
+ if (event_times_.empty())
+ return base::TimeTicks();
+
+ // lower_bound finds the first element >= |time|.
+ auto it = event_times_.lower_bound(time);
+
+ // If all times are after the requested time, then we don't have a time to
+ // return.
+ if (it == event_times_.begin())
+ return base::TimeTicks();
+
+ // |it| points to the first event >= the specified time, so decrement once to
+ // find the greatest event before the specified time.
+ --it;
+ base::TimeTicks candidate = *it;
+ DCHECK(candidate < time);
+
+ // If the most recent event is too old, then don't return it.
+ if (candidate < time - base::TimeDelta::FromSeconds(kMaxEventAgeSeconds))
+ return base::TimeTicks();
+
+ return candidate;
+}
+
+void UserInputTracker::ConsumeUserInputEventsUpTo(base::TimeTicks time) {
+ RemoveInputEventsUpTo(std::max(time, GetOldestAllowedEventTime()));
+}
+
+void UserInputTracker::RemoveOldInputEvents() {
+ RemoveInputEventsUpTo(GetOldestAllowedEventTime());
+}
+
+void UserInputTracker::RemoveInputEventsUpTo(base::TimeTicks cutoff) {
+ event_times_.erase(event_times_.begin(), event_times_.upper_bound(cutoff));
+}
+
+// static
+base::TimeTicks UserInputTracker::GetOldestAllowedEventTime() {
Charlie Harrison 2016/12/02 02:58:44 Why don't we limit to 1s old instead of 2s old eve
Bryan McQuade 2016/12/02 20:43:01 The idea here is that if someone calls FindMostRec
+ // Allow for up to 2x the oldest time. This allows consumers to continue to
+ // find events for timestamps up to 1 second in the past.
+ return base::TimeTicks::Now() -
+ base::TimeDelta::FromSeconds(kMaxEventAgeSeconds * 2);
+}
+
+} // namespace page_load_metrics

Powered by Google App Engine
This is Rietveld 408576698