1 // Copyright 2020 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "cc/metrics/event_metrics.h"
12 #include "base/check.h"
13 #include "base/memory/ptr_util.h"
14 #include "base/notreached.h"
15 #include "base/time/default_tick_clock.h"
16 #include "cc/metrics/event_latency_tracing_recorder.h"
22 EventMetrics::EventType metrics_event_type;
23 ui::EventType ui_event_type;
25 absl::optional<bool> scroll_is_inertial = absl::nullopt;
26 absl::optional<ScrollUpdateEventMetrics::ScrollUpdateType>
27 scroll_update_type = absl::nullopt;
28 } kInterestingEvents[] = {
29 #define EVENT_TYPE(name, ui_type, ...) \
30 { EventMetrics::EventType::k##name, ui_type, #name, __VA_ARGS__ }
31 EVENT_TYPE(MousePressed, ui::ET_MOUSE_PRESSED),
32 EVENT_TYPE(MouseReleased, ui::ET_MOUSE_RELEASED),
33 EVENT_TYPE(MouseWheel, ui::ET_MOUSEWHEEL),
34 EVENT_TYPE(KeyPressed, ui::ET_KEY_PRESSED),
35 EVENT_TYPE(KeyReleased, ui::ET_KEY_RELEASED),
36 EVENT_TYPE(TouchPressed, ui::ET_TOUCH_PRESSED),
37 EVENT_TYPE(TouchReleased, ui::ET_TOUCH_RELEASED),
38 EVENT_TYPE(TouchMoved, ui::ET_TOUCH_MOVED),
39 EVENT_TYPE(GestureScrollBegin, ui::ET_GESTURE_SCROLL_BEGIN, false),
40 EVENT_TYPE(GestureScrollUpdate,
41 ui::ET_GESTURE_SCROLL_UPDATE,
43 ScrollUpdateEventMetrics::ScrollUpdateType::kContinued),
44 EVENT_TYPE(GestureScrollEnd, ui::ET_GESTURE_SCROLL_END, false),
45 EVENT_TYPE(GestureDoubleTap, ui::ET_GESTURE_DOUBLE_TAP),
46 EVENT_TYPE(GestureLongPress, ui::ET_GESTURE_LONG_PRESS),
47 EVENT_TYPE(GestureLongTap, ui::ET_GESTURE_LONG_TAP),
48 EVENT_TYPE(GestureShowPress, ui::ET_GESTURE_SHOW_PRESS),
49 EVENT_TYPE(GestureTap, ui::ET_GESTURE_TAP),
50 EVENT_TYPE(GestureTapCancel, ui::ET_GESTURE_TAP_CANCEL),
51 EVENT_TYPE(GestureTapDown, ui::ET_GESTURE_TAP_DOWN),
52 EVENT_TYPE(GestureTapUnconfirmed, ui::ET_GESTURE_TAP_UNCONFIRMED),
53 EVENT_TYPE(GestureTwoFingerTap, ui::ET_GESTURE_TWO_FINGER_TAP),
54 EVENT_TYPE(FirstGestureScrollUpdate,
55 ui::ET_GESTURE_SCROLL_UPDATE,
57 ScrollUpdateEventMetrics::ScrollUpdateType::kStarted),
58 EVENT_TYPE(MouseDragged, ui::ET_MOUSE_DRAGGED),
59 EVENT_TYPE(GesturePinchBegin, ui::ET_GESTURE_PINCH_BEGIN),
60 EVENT_TYPE(GesturePinchEnd, ui::ET_GESTURE_PINCH_END),
61 EVENT_TYPE(GesturePinchUpdate, ui::ET_GESTURE_PINCH_UPDATE),
62 EVENT_TYPE(InertialGestureScrollUpdate,
63 ui::ET_GESTURE_SCROLL_UPDATE,
65 ScrollUpdateEventMetrics::ScrollUpdateType::kContinued),
68 static_assert(std::size(kInterestingEvents) ==
69 static_cast<int>(EventMetrics::EventType::kMaxValue) + 1,
70 "EventMetrics::EventType has changed.");
73 ScrollEventMetrics::ScrollType metrics_scroll_type;
74 ui::ScrollInputType ui_input_type;
77 #define SCROLL_TYPE(name) \
79 ScrollEventMetrics::ScrollType::k##name, ui::ScrollInputType::k##name, \
82 SCROLL_TYPE(Autoscroll),
83 SCROLL_TYPE(Scrollbar),
84 SCROLL_TYPE(Touchscreen),
88 static_assert(std::size(kScrollTypes) ==
89 static_cast<int>(ScrollEventMetrics::ScrollType::kMaxValue) +
91 "ScrollEventMetrics::ScrollType has changed.");
94 PinchEventMetrics::PinchType metrics_pinch_type;
95 ui::ScrollInputType ui_input_type;
98 #define PINCH_TYPE(metrics_name, ui_name) \
100 PinchEventMetrics::PinchType::k##metrics_name, \
101 ui::ScrollInputType::k##ui_name, #metrics_name \
103 PINCH_TYPE(Touchpad, Wheel),
104 PINCH_TYPE(Touchscreen, Touchscreen),
107 static_assert(std::size(kPinchTypes) ==
108 static_cast<int>(PinchEventMetrics::PinchType::kMaxValue) + 1,
109 "PinchEventMetrics::PinchType has changed.");
111 absl::optional<EventMetrics::EventType> ToInterestingEventType(
112 ui::EventType ui_event_type,
113 absl::optional<bool> scroll_is_inertial,
114 absl::optional<ScrollUpdateEventMetrics::ScrollUpdateType>
115 scroll_update_type) {
116 for (size_t i = 0; i < std::size(kInterestingEvents); i++) {
117 const auto& interesting_event = kInterestingEvents[i];
118 if (ui_event_type == interesting_event.ui_event_type &&
119 scroll_is_inertial == interesting_event.scroll_is_inertial &&
120 scroll_update_type == interesting_event.scroll_update_type) {
121 EventMetrics::EventType metrics_event_type =
122 static_cast<EventMetrics::EventType>(i);
123 DCHECK_EQ(metrics_event_type, interesting_event.metrics_event_type);
124 return metrics_event_type;
127 return absl::nullopt;
130 ScrollEventMetrics::ScrollType ToScrollType(ui::ScrollInputType ui_input_type) {
131 for (size_t i = 0; i < std::size(kScrollTypes); i++) {
132 if (ui_input_type == kScrollTypes[i].ui_input_type) {
133 auto metrics_scroll_type = static_cast<ScrollEventMetrics::ScrollType>(i);
134 DCHECK_EQ(metrics_scroll_type, kScrollTypes[i].metrics_scroll_type);
135 return metrics_scroll_type;
139 return ScrollEventMetrics::ScrollType::kMaxValue;
142 PinchEventMetrics::PinchType ToPinchType(ui::ScrollInputType ui_input_type) {
143 for (size_t i = 0; i < std::size(kPinchTypes); i++) {
144 if (ui_input_type == kPinchTypes[i].ui_input_type) {
145 auto metrics_pinch_type = static_cast<PinchEventMetrics::PinchType>(i);
146 DCHECK_EQ(metrics_pinch_type, kPinchTypes[i].metrics_pinch_type);
147 return metrics_pinch_type;
151 return PinchEventMetrics::PinchType::kMaxValue;
154 bool IsGestureScroll(ui::EventType type) {
155 return type == ui::ET_GESTURE_SCROLL_BEGIN ||
156 type == ui::ET_GESTURE_SCROLL_UPDATE ||
157 type == ui::ET_GESTURE_SCROLL_END;
160 bool IsGesturePinch(ui::EventType type) {
161 return type == ui::ET_GESTURE_PINCH_BEGIN ||
162 type == ui::ET_GESTURE_PINCH_UPDATE ||
163 type == ui::ET_GESTURE_PINCH_END;
166 bool IsGestureScrollUpdate(ui::EventType type) {
167 return type == ui::ET_GESTURE_SCROLL_UPDATE;
175 std::unique_ptr<EventMetrics> EventMetrics::Create(ui::EventType type,
176 base::TimeTicks timestamp) {
177 // TODO(crbug.com/1157090): We expect that `timestamp` is not null, but there
178 // seems to be some tests that are emitting events with null timestamp. We
179 // should investigate and try to fix those cases and add a `DCHECK` here to
180 // assert `timestamp` is not null.
182 DCHECK(!IsGestureScroll(type) && !IsGesturePinch(type));
184 std::unique_ptr<EventMetrics> metrics =
185 CreateInternal(type, timestamp, base::DefaultTickClock::GetInstance());
189 metrics->SetDispatchStageTimestamp(
190 DispatchStage::kArrivedInRendererCompositor);
195 std::unique_ptr<EventMetrics> EventMetrics::CreateForTesting(
197 base::TimeTicks timestamp,
198 const base::TickClock* tick_clock) {
199 DCHECK(!timestamp.is_null());
201 std::unique_ptr<EventMetrics> metrics =
202 CreateInternal(type, timestamp, tick_clock);
206 metrics->SetDispatchStageTimestamp(
207 DispatchStage::kArrivedInRendererCompositor);
212 std::unique_ptr<EventMetrics> EventMetrics::CreateFromExisting(
214 DispatchStage last_dispatch_stage,
215 const EventMetrics* existing) {
216 // Generally, if `existing` is `nullptr` (the existing event is not of an
217 // interesting type), the new event won't be of an interesting type, too, and
218 // we can immediately return `nullptr`. The only exception is some tests that
219 // are not interested in reporting metrics, in which case we can immediately
220 // return `nullptr`, too, as they are not interested in reporting metrics.
224 std::unique_ptr<EventMetrics> metrics =
225 CreateInternal(type, base::TimeTicks(), existing->tick_clock_);
229 // Use timestamps of all stages (including "Generated" stage) up to
230 // `last_dispatch_stage` from `existing`.
231 metrics->CopyTimestampsFrom(*existing, last_dispatch_stage);
237 std::unique_ptr<EventMetrics> EventMetrics::CreateInternal(
239 base::TimeTicks timestamp,
240 const base::TickClock* tick_clock) {
241 absl::optional<EventType> interesting_type =
242 ToInterestingEventType(type, /*scroll_is_inertial=*/absl::nullopt,
243 /*scroll_update_type=*/absl::nullopt);
244 if (!interesting_type)
246 return base::WrapUnique(
247 new EventMetrics(*interesting_type, timestamp, tick_clock));
250 EventMetrics::EventMetrics(EventType type,
251 base::TimeTicks timestamp,
252 const base::TickClock* tick_clock)
253 : type_(type), tick_clock_(tick_clock) {
254 dispatch_stage_timestamps_[static_cast<int>(DispatchStage::kGenerated)] =
258 EventMetrics::EventMetrics(EventType type,
259 base::TimeTicks timestamp,
260 base::TimeTicks arrived_in_browser_main_timestamp,
261 const base::TickClock* tick_clock)
262 : EventMetrics(type, timestamp, tick_clock) {
263 dispatch_stage_timestamps_[static_cast<int>(
264 DispatchStage::kArrivedInBrowserMain)] =
265 arrived_in_browser_main_timestamp;
268 EventMetrics::EventMetrics(const EventMetrics& other)
269 : type_(other.type_),
270 tick_clock_(other.tick_clock_),
271 should_record_tracing_(false) {
272 CopyTimestampsFrom(other, DispatchStage::kMaxValue);
275 EventMetrics::~EventMetrics() {
276 if (should_record_tracing()) {
277 EventLatencyTracingRecorder::RecordEventLatencyTraceEvent(
278 this, base::TimeTicks::Now(), nullptr, nullptr);
282 const char* EventMetrics::GetTypeName() const {
283 return kInterestingEvents[static_cast<int>(type_)].name;
286 void EventMetrics::SetHighLatencyStage(const std::string& stage) {
287 high_latency_stages_.push_back(stage);
290 void EventMetrics::SetDispatchStageTimestamp(DispatchStage stage) {
291 DCHECK(dispatch_stage_timestamps_[static_cast<size_t>(stage)].is_null());
293 dispatch_stage_timestamps_[static_cast<size_t>(stage)] =
294 tick_clock_->NowTicks();
297 base::TimeTicks EventMetrics::GetDispatchStageTimestamp(
298 DispatchStage stage) const {
299 return dispatch_stage_timestamps_[static_cast<size_t>(stage)];
302 void EventMetrics::ResetToDispatchStage(DispatchStage stage) {
303 for (size_t stage_index = static_cast<size_t>(stage) + 1;
304 stage_index <= static_cast<size_t>(DispatchStage::kMaxValue);
306 dispatch_stage_timestamps_[stage_index] = base::TimeTicks();
310 bool EventMetrics::HasSmoothInputEvent() const {
311 return type_ == EventType::kMouseDragged || type_ == EventType::kTouchMoved;
314 ScrollEventMetrics* EventMetrics::AsScroll() {
318 const ScrollEventMetrics* EventMetrics::AsScroll() const {
319 return const_cast<EventMetrics*>(this)->AsScroll();
322 ScrollUpdateEventMetrics* EventMetrics::AsScrollUpdate() {
326 const ScrollUpdateEventMetrics* EventMetrics::AsScrollUpdate() const {
327 return const_cast<EventMetrics*>(this)->AsScrollUpdate();
330 PinchEventMetrics* EventMetrics::AsPinch() {
334 const PinchEventMetrics* EventMetrics::AsPinch() const {
335 return const_cast<EventMetrics*>(this)->AsPinch();
338 std::unique_ptr<EventMetrics> EventMetrics::Clone() const {
339 return base::WrapUnique(new EventMetrics(*this));
342 void EventMetrics::CopyTimestampsFrom(const EventMetrics& other,
343 DispatchStage last_dispatch_stage) {
344 DCHECK_LE(last_dispatch_stage, DispatchStage::kMaxValue);
345 std::copy(other.dispatch_stage_timestamps_,
346 other.dispatch_stage_timestamps_ +
347 static_cast<size_t>(last_dispatch_stage) + 1,
348 dispatch_stage_timestamps_);
351 // ScrollEventMetrics
354 std::unique_ptr<ScrollEventMetrics> ScrollEventMetrics::Create(
356 ui::ScrollInputType input_type,
358 base::TimeTicks timestamp,
359 base::TimeTicks arrived_in_browser_main_timestamp) {
360 // TODO(crbug.com/1157090): We expect that `timestamp` is not null, but there
361 // seems to be some tests that are emitting events with null timestamp. We
362 // should investigate and try to fix those cases and add a `DCHECK` here to
363 // assert `timestamp` is not null.
365 DCHECK(IsGestureScroll(type) && !IsGestureScrollUpdate(type));
367 std::unique_ptr<ScrollEventMetrics> metrics = CreateInternal(
368 type, input_type, is_inertial, timestamp,
369 arrived_in_browser_main_timestamp, base::DefaultTickClock::GetInstance());
373 metrics->SetDispatchStageTimestamp(
374 DispatchStage::kArrivedInRendererCompositor);
379 std::unique_ptr<ScrollEventMetrics> ScrollEventMetrics::CreateForBrowser(
381 ui::ScrollInputType input_type,
383 base::TimeTicks timestamp) {
384 return Create(type, input_type, is_inertial, timestamp, base::TimeTicks());
388 std::unique_ptr<ScrollEventMetrics> ScrollEventMetrics::CreateForTesting(
390 ui::ScrollInputType input_type,
392 base::TimeTicks timestamp,
393 base::TimeTicks arrived_in_browser_main_timestamp,
394 const base::TickClock* tick_clock) {
395 DCHECK(!timestamp.is_null());
397 std::unique_ptr<ScrollEventMetrics> metrics =
398 CreateInternal(type, input_type, is_inertial, timestamp,
399 arrived_in_browser_main_timestamp, tick_clock);
403 metrics->SetDispatchStageTimestamp(
404 DispatchStage::kArrivedInRendererCompositor);
409 std::unique_ptr<ScrollEventMetrics> ScrollEventMetrics::CreateFromExisting(
411 ui::ScrollInputType input_type,
413 DispatchStage last_dispatch_stage,
414 const EventMetrics* existing) {
415 // Generally, if `existing` is `nullptr` (the existing event is not of an
416 // interesting type), the new event won't be of an interesting type, too, and
417 // we can immediately return `nullptr`. The only exception is some tests that
418 // are not interested in reporting metrics, in which case we can immediately
419 // return `nullptr`, too, as they are not interested in reporting metrics.
423 std::unique_ptr<ScrollEventMetrics> metrics =
424 CreateInternal(type, input_type, is_inertial, base::TimeTicks(),
425 base::TimeTicks(), existing->tick_clock_);
429 // Use timestamps of all stages (including "Generated" stage) up to
430 // `last_dispatch_stage` from `existing`.
431 metrics->CopyTimestampsFrom(*existing, last_dispatch_stage);
437 std::unique_ptr<ScrollEventMetrics> ScrollEventMetrics::CreateInternal(
439 ui::ScrollInputType input_type,
441 base::TimeTicks timestamp,
442 base::TimeTicks arrived_in_browser_main_timestamp,
443 const base::TickClock* tick_clock) {
444 absl::optional<EventType> interesting_type =
445 ToInterestingEventType(type, is_inertial,
446 /*scroll_update_type=*/absl::nullopt);
447 if (!interesting_type)
449 return base::WrapUnique(new ScrollEventMetrics(
450 *interesting_type, ToScrollType(input_type), timestamp,
451 arrived_in_browser_main_timestamp, tick_clock));
454 ScrollEventMetrics::ScrollEventMetrics(
456 ScrollType scroll_type,
457 base::TimeTicks timestamp,
458 base::TimeTicks arrived_in_browser_main_timestamp,
459 const base::TickClock* tick_clock)
462 arrived_in_browser_main_timestamp,
464 scroll_type_(scroll_type) {}
466 ScrollEventMetrics::ScrollEventMetrics(const ScrollEventMetrics&) = default;
468 ScrollEventMetrics::~ScrollEventMetrics() {
469 if (should_record_tracing()) {
470 EventLatencyTracingRecorder::RecordEventLatencyTraceEvent(
471 this, base::TimeTicks::Now(), nullptr, nullptr);
475 const char* ScrollEventMetrics::GetScrollTypeName() const {
476 return kScrollTypes[static_cast<int>(scroll_type_)].name;
479 ScrollEventMetrics* ScrollEventMetrics::AsScroll() {
483 std::unique_ptr<EventMetrics> ScrollEventMetrics::Clone() const {
484 return base::WrapUnique(new ScrollEventMetrics(*this));
487 // ScrollUpdateEventMetrics
490 std::unique_ptr<ScrollUpdateEventMetrics> ScrollUpdateEventMetrics::Create(
492 ui::ScrollInputType input_type,
494 ScrollUpdateType scroll_update_type,
496 base::TimeTicks timestamp,
497 base::TimeTicks arrived_in_browser_main_timestamp) {
498 // TODO(crbug.com/1157090): We expect that `timestamp` is not null, but there
499 // seems to be some tests that are emitting events with null timestamp. We
500 // should investigate and try to fix those cases and add a `DCHECK` here to
501 // assert `timestamp` is not null.
503 DCHECK(IsGestureScrollUpdate(type));
505 std::unique_ptr<ScrollUpdateEventMetrics> metrics = CreateInternal(
506 type, input_type, is_inertial, scroll_update_type, delta, timestamp,
507 arrived_in_browser_main_timestamp, base::DefaultTickClock::GetInstance());
511 metrics->SetDispatchStageTimestamp(
512 DispatchStage::kArrivedInRendererCompositor);
517 std::unique_ptr<ScrollUpdateEventMetrics>
518 ScrollUpdateEventMetrics::CreateForBrowser(ui::EventType type,
519 ui::ScrollInputType input_type,
521 ScrollUpdateType scroll_update_type,
523 base::TimeTicks timestamp) {
524 return Create(type, input_type, is_inertial, scroll_update_type, delta,
525 timestamp, base::TimeTicks());
529 std::unique_ptr<ScrollUpdateEventMetrics>
530 ScrollUpdateEventMetrics::CreateForTesting(
532 ui::ScrollInputType input_type,
534 ScrollUpdateType scroll_update_type,
536 base::TimeTicks timestamp,
537 base::TimeTicks arrived_in_browser_main_timestamp,
538 const base::TickClock* tick_clock) {
539 DCHECK(!timestamp.is_null());
541 std::unique_ptr<ScrollUpdateEventMetrics> metrics =
542 CreateInternal(type, input_type, is_inertial, scroll_update_type, delta,
543 timestamp, arrived_in_browser_main_timestamp, tick_clock);
547 metrics->SetDispatchStageTimestamp(
548 DispatchStage::kArrivedInRendererCompositor);
553 std::unique_ptr<ScrollUpdateEventMetrics>
554 ScrollUpdateEventMetrics::CreateFromExisting(
556 ui::ScrollInputType input_type,
558 ScrollUpdateType scroll_update_type,
560 DispatchStage last_dispatch_stage,
561 const EventMetrics* existing) {
562 // Since the new event is of an interesting type, we expect the existing event
563 // to be of an interesting type, too; which means `existing` should not be
564 // `nullptr`. However, some tests that are not interested in reporting
565 // metrics, don't create metrics objects even for events of interesting types.
566 // Return `nullptr` if that's the case.
570 std::unique_ptr<ScrollUpdateEventMetrics> metrics = CreateInternal(
571 type, input_type, is_inertial, scroll_update_type, delta,
572 base::TimeTicks(), base::TimeTicks(), existing->tick_clock_);
576 // Use timestamps of all stages (including "Generated" stage) up to
577 // `last_dispatch_stage` from `existing`.
578 metrics->CopyTimestampsFrom(*existing, last_dispatch_stage);
584 std::unique_ptr<ScrollUpdateEventMetrics>
585 ScrollUpdateEventMetrics::CreateInternal(
587 ui::ScrollInputType input_type,
589 ScrollUpdateType scroll_update_type,
591 base::TimeTicks timestamp,
592 base::TimeTicks arrived_in_browser_main_timestamp,
593 const base::TickClock* tick_clock) {
594 absl::optional<EventType> interesting_type =
595 ToInterestingEventType(type, is_inertial, scroll_update_type);
596 if (!interesting_type)
598 return base::WrapUnique(new ScrollUpdateEventMetrics(
599 *interesting_type, ToScrollType(input_type), scroll_update_type, delta,
600 timestamp, arrived_in_browser_main_timestamp, tick_clock));
603 ScrollUpdateEventMetrics::ScrollUpdateEventMetrics(
605 ScrollType scroll_type,
606 ScrollUpdateType scroll_update_type,
608 base::TimeTicks timestamp,
609 base::TimeTicks arrived_in_browser_main_timestamp,
610 const base::TickClock* tick_clock)
611 : ScrollEventMetrics(type,
614 arrived_in_browser_main_timestamp,
617 predicted_delta_(delta),
618 last_timestamp_(timestamp) {}
620 ScrollUpdateEventMetrics::ScrollUpdateEventMetrics(
621 const ScrollUpdateEventMetrics&) = default;
623 ScrollUpdateEventMetrics::~ScrollUpdateEventMetrics() {
624 if (should_record_tracing()) {
625 EventLatencyTracingRecorder::RecordEventLatencyTraceEvent(
626 this, base::TimeTicks::Now(), nullptr, nullptr);
630 void ScrollUpdateEventMetrics::CoalesceWith(
631 const ScrollUpdateEventMetrics& newer_scroll_update) {
632 last_timestamp_ = newer_scroll_update.last_timestamp_;
633 delta_ += newer_scroll_update.delta_;
634 predicted_delta_ += newer_scroll_update.predicted_delta_;
637 ScrollUpdateEventMetrics* ScrollUpdateEventMetrics::AsScrollUpdate() {
641 std::unique_ptr<EventMetrics> ScrollUpdateEventMetrics::Clone() const {
642 return base::WrapUnique(new ScrollUpdateEventMetrics(*this));
648 std::unique_ptr<PinchEventMetrics> PinchEventMetrics::Create(
650 ui::ScrollInputType input_type,
651 base::TimeTicks timestamp) {
652 // TODO(crbug.com/1157090): We expect that `timestamp` is not null, but there
653 // seems to be some tests that are emitting events with null timestamp. We
654 // should investigate and try to fix those cases and add a `DCHECK` here to
655 // assert `timestamp` is not null.
657 DCHECK(IsGesturePinch(type));
659 std::unique_ptr<PinchEventMetrics> metrics = CreateInternal(
660 type, input_type, timestamp, base::DefaultTickClock::GetInstance());
664 metrics->SetDispatchStageTimestamp(
665 DispatchStage::kArrivedInRendererCompositor);
670 std::unique_ptr<PinchEventMetrics> PinchEventMetrics::CreateForTesting(
672 ui::ScrollInputType input_type,
673 base::TimeTicks timestamp,
674 const base::TickClock* tick_clock) {
675 DCHECK(!timestamp.is_null());
677 std::unique_ptr<PinchEventMetrics> metrics =
678 CreateInternal(type, input_type, timestamp, tick_clock);
682 metrics->SetDispatchStageTimestamp(
683 DispatchStage::kArrivedInRendererCompositor);
688 std::unique_ptr<PinchEventMetrics> PinchEventMetrics::CreateInternal(
690 ui::ScrollInputType input_type,
691 base::TimeTicks timestamp,
692 const base::TickClock* tick_clock) {
693 absl::optional<EventType> interesting_type =
694 ToInterestingEventType(type, /*scroll_is_inertial=*/absl::nullopt,
695 /*scroll_update_type=*/absl::nullopt);
696 if (!interesting_type)
698 return base::WrapUnique(new PinchEventMetrics(
699 *interesting_type, ToPinchType(input_type), timestamp, tick_clock));
702 PinchEventMetrics::PinchEventMetrics(EventType type,
703 PinchType pinch_type,
704 base::TimeTicks timestamp,
705 const base::TickClock* tick_clock)
706 : EventMetrics(type, timestamp, tick_clock), pinch_type_(pinch_type) {}
708 PinchEventMetrics::PinchEventMetrics(const PinchEventMetrics&) = default;
710 PinchEventMetrics::~PinchEventMetrics() {
711 if (should_record_tracing()) {
712 EventLatencyTracingRecorder::RecordEventLatencyTraceEvent(
713 this, base::TimeTicks::Now(), nullptr, nullptr);
717 const char* PinchEventMetrics::GetPinchTypeName() const {
718 return kPinchTypes[static_cast<int>(pinch_type_)].name;
721 PinchEventMetrics* PinchEventMetrics::AsPinch() {
725 std::unique_ptr<EventMetrics> PinchEventMetrics::Clone() const {
726 return base::WrapUnique(new PinchEventMetrics(*this));
730 EventMetricsSet::EventMetricsSet() = default;
731 EventMetricsSet::~EventMetricsSet() = default;
732 EventMetricsSet::EventMetricsSet(EventMetrics::List main_thread_event_metrics,
733 EventMetrics::List impl_thread_event_metrics)
734 : main_event_metrics(std::move(main_thread_event_metrics)),
735 impl_event_metrics(std::move(impl_thread_event_metrics)) {}
736 EventMetricsSet::EventMetricsSet(EventMetricsSet&& other) = default;
737 EventMetricsSet& EventMetricsSet::operator=(EventMetricsSet&& other) = default;