Chromium Code Reviews| 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 |