[M108 Migration][VD] Avoid pending frame counter becoming negative
[platform/framework/web/chromium-efl.git] / cc / metrics / event_metrics.cc
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.
4
5 #include "cc/metrics/event_metrics.h"
6
7 #include <algorithm>
8 #include <ostream>
9 #include <string>
10 #include <utility>
11
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"
17
18 namespace cc {
19 namespace {
20
21 constexpr struct {
22   EventMetrics::EventType metrics_event_type;
23   ui::EventType ui_event_type;
24   const char* name;
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,
42                false,
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,
56                false,
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,
64                true,
65                ScrollUpdateEventMetrics::ScrollUpdateType::kContinued),
66 #undef EVENT_TYPE
67 };
68 static_assert(std::size(kInterestingEvents) ==
69                   static_cast<int>(EventMetrics::EventType::kMaxValue) + 1,
70               "EventMetrics::EventType has changed.");
71
72 constexpr struct {
73   ScrollEventMetrics::ScrollType metrics_scroll_type;
74   ui::ScrollInputType ui_input_type;
75   const char* name;
76 } kScrollTypes[] = {
77 #define SCROLL_TYPE(name)                                                  \
78   {                                                                        \
79     ScrollEventMetrics::ScrollType::k##name, ui::ScrollInputType::k##name, \
80         #name                                                              \
81   }
82     SCROLL_TYPE(Autoscroll),
83     SCROLL_TYPE(Scrollbar),
84     SCROLL_TYPE(Touchscreen),
85     SCROLL_TYPE(Wheel),
86 #undef SCROLL_TYPE
87 };
88 static_assert(std::size(kScrollTypes) ==
89                   static_cast<int>(ScrollEventMetrics::ScrollType::kMaxValue) +
90                       1,
91               "ScrollEventMetrics::ScrollType has changed.");
92
93 constexpr struct {
94   PinchEventMetrics::PinchType metrics_pinch_type;
95   ui::ScrollInputType ui_input_type;
96   const char* name;
97 } kPinchTypes[] = {
98 #define PINCH_TYPE(metrics_name, ui_name)              \
99   {                                                    \
100     PinchEventMetrics::PinchType::k##metrics_name,     \
101         ui::ScrollInputType::k##ui_name, #metrics_name \
102   }
103     PINCH_TYPE(Touchpad, Wheel),
104     PINCH_TYPE(Touchscreen, Touchscreen),
105 #undef PINCH_TYPE
106 };
107 static_assert(std::size(kPinchTypes) ==
108                   static_cast<int>(PinchEventMetrics::PinchType::kMaxValue) + 1,
109               "PinchEventMetrics::PinchType has changed.");
110
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;
125     }
126   }
127   return absl::nullopt;
128 }
129
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;
136     }
137   }
138   NOTREACHED();
139   return ScrollEventMetrics::ScrollType::kMaxValue;
140 }
141
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;
148     }
149   }
150   NOTREACHED();
151   return PinchEventMetrics::PinchType::kMaxValue;
152 }
153
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;
158 }
159
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;
164 }
165
166 bool IsGestureScrollUpdate(ui::EventType type) {
167   return type == ui::ET_GESTURE_SCROLL_UPDATE;
168 }
169
170 }  // namespace
171
172 // EventMetrics:
173
174 // static
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.
181
182   DCHECK(!IsGestureScroll(type) && !IsGesturePinch(type));
183
184   std::unique_ptr<EventMetrics> metrics =
185       CreateInternal(type, timestamp, base::DefaultTickClock::GetInstance());
186   if (!metrics)
187     return nullptr;
188
189   metrics->SetDispatchStageTimestamp(
190       DispatchStage::kArrivedInRendererCompositor);
191   return metrics;
192 }
193
194 // static
195 std::unique_ptr<EventMetrics> EventMetrics::CreateForTesting(
196     ui::EventType type,
197     base::TimeTicks timestamp,
198     const base::TickClock* tick_clock) {
199   DCHECK(!timestamp.is_null());
200
201   std::unique_ptr<EventMetrics> metrics =
202       CreateInternal(type, timestamp, tick_clock);
203   if (!metrics)
204     return nullptr;
205
206   metrics->SetDispatchStageTimestamp(
207       DispatchStage::kArrivedInRendererCompositor);
208   return metrics;
209 }
210
211 // static
212 std::unique_ptr<EventMetrics> EventMetrics::CreateFromExisting(
213     ui::EventType type,
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.
221   if (!existing)
222     return nullptr;
223
224   std::unique_ptr<EventMetrics> metrics =
225       CreateInternal(type, base::TimeTicks(), existing->tick_clock_);
226   if (!metrics)
227     return nullptr;
228
229   // Use timestamps of all stages (including "Generated" stage) up to
230   // `last_dispatch_stage` from `existing`.
231   metrics->CopyTimestampsFrom(*existing, last_dispatch_stage);
232
233   return metrics;
234 }
235
236 // static
237 std::unique_ptr<EventMetrics> EventMetrics::CreateInternal(
238     ui::EventType type,
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)
245     return nullptr;
246   return base::WrapUnique(
247       new EventMetrics(*interesting_type, timestamp, tick_clock));
248 }
249
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)] =
255       timestamp;
256 }
257
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;
266 }
267
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);
273 }
274
275 EventMetrics::~EventMetrics() {
276   if (should_record_tracing()) {
277     EventLatencyTracingRecorder::RecordEventLatencyTraceEvent(
278         this, base::TimeTicks::Now(), nullptr, nullptr);
279   }
280 }
281
282 const char* EventMetrics::GetTypeName() const {
283   return kInterestingEvents[static_cast<int>(type_)].name;
284 }
285
286 void EventMetrics::SetHighLatencyStage(const std::string& stage) {
287   high_latency_stages_.push_back(stage);
288 }
289
290 void EventMetrics::SetDispatchStageTimestamp(DispatchStage stage) {
291   DCHECK(dispatch_stage_timestamps_[static_cast<size_t>(stage)].is_null());
292
293   dispatch_stage_timestamps_[static_cast<size_t>(stage)] =
294       tick_clock_->NowTicks();
295 }
296
297 base::TimeTicks EventMetrics::GetDispatchStageTimestamp(
298     DispatchStage stage) const {
299   return dispatch_stage_timestamps_[static_cast<size_t>(stage)];
300 }
301
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);
305        stage_index++) {
306     dispatch_stage_timestamps_[stage_index] = base::TimeTicks();
307   }
308 }
309
310 bool EventMetrics::HasSmoothInputEvent() const {
311   return type_ == EventType::kMouseDragged || type_ == EventType::kTouchMoved;
312 }
313
314 ScrollEventMetrics* EventMetrics::AsScroll() {
315   return nullptr;
316 }
317
318 const ScrollEventMetrics* EventMetrics::AsScroll() const {
319   return const_cast<EventMetrics*>(this)->AsScroll();
320 }
321
322 ScrollUpdateEventMetrics* EventMetrics::AsScrollUpdate() {
323   return nullptr;
324 }
325
326 const ScrollUpdateEventMetrics* EventMetrics::AsScrollUpdate() const {
327   return const_cast<EventMetrics*>(this)->AsScrollUpdate();
328 }
329
330 PinchEventMetrics* EventMetrics::AsPinch() {
331   return nullptr;
332 }
333
334 const PinchEventMetrics* EventMetrics::AsPinch() const {
335   return const_cast<EventMetrics*>(this)->AsPinch();
336 }
337
338 std::unique_ptr<EventMetrics> EventMetrics::Clone() const {
339   return base::WrapUnique(new EventMetrics(*this));
340 }
341
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_);
349 }
350
351 // ScrollEventMetrics
352
353 // static
354 std::unique_ptr<ScrollEventMetrics> ScrollEventMetrics::Create(
355     ui::EventType type,
356     ui::ScrollInputType input_type,
357     bool is_inertial,
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.
364
365   DCHECK(IsGestureScroll(type) && !IsGestureScrollUpdate(type));
366
367   std::unique_ptr<ScrollEventMetrics> metrics = CreateInternal(
368       type, input_type, is_inertial, timestamp,
369       arrived_in_browser_main_timestamp, base::DefaultTickClock::GetInstance());
370   if (!metrics)
371     return nullptr;
372
373   metrics->SetDispatchStageTimestamp(
374       DispatchStage::kArrivedInRendererCompositor);
375   return metrics;
376 }
377
378 // static
379 std::unique_ptr<ScrollEventMetrics> ScrollEventMetrics::CreateForBrowser(
380     ui::EventType type,
381     ui::ScrollInputType input_type,
382     bool is_inertial,
383     base::TimeTicks timestamp) {
384   return Create(type, input_type, is_inertial, timestamp, base::TimeTicks());
385 }
386
387 // static
388 std::unique_ptr<ScrollEventMetrics> ScrollEventMetrics::CreateForTesting(
389     ui::EventType type,
390     ui::ScrollInputType input_type,
391     bool is_inertial,
392     base::TimeTicks timestamp,
393     base::TimeTicks arrived_in_browser_main_timestamp,
394     const base::TickClock* tick_clock) {
395   DCHECK(!timestamp.is_null());
396
397   std::unique_ptr<ScrollEventMetrics> metrics =
398       CreateInternal(type, input_type, is_inertial, timestamp,
399                      arrived_in_browser_main_timestamp, tick_clock);
400   if (!metrics)
401     return nullptr;
402
403   metrics->SetDispatchStageTimestamp(
404       DispatchStage::kArrivedInRendererCompositor);
405   return metrics;
406 }
407
408 // static
409 std::unique_ptr<ScrollEventMetrics> ScrollEventMetrics::CreateFromExisting(
410     ui::EventType type,
411     ui::ScrollInputType input_type,
412     bool is_inertial,
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.
420   if (!existing)
421     return nullptr;
422
423   std::unique_ptr<ScrollEventMetrics> metrics =
424       CreateInternal(type, input_type, is_inertial, base::TimeTicks(),
425                      base::TimeTicks(), existing->tick_clock_);
426   if (!metrics)
427     return nullptr;
428
429   // Use timestamps of all stages (including "Generated" stage) up to
430   // `last_dispatch_stage` from `existing`.
431   metrics->CopyTimestampsFrom(*existing, last_dispatch_stage);
432
433   return metrics;
434 }
435
436 // static
437 std::unique_ptr<ScrollEventMetrics> ScrollEventMetrics::CreateInternal(
438     ui::EventType type,
439     ui::ScrollInputType input_type,
440     bool is_inertial,
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)
448     return nullptr;
449   return base::WrapUnique(new ScrollEventMetrics(
450       *interesting_type, ToScrollType(input_type), timestamp,
451       arrived_in_browser_main_timestamp, tick_clock));
452 }
453
454 ScrollEventMetrics::ScrollEventMetrics(
455     EventType type,
456     ScrollType scroll_type,
457     base::TimeTicks timestamp,
458     base::TimeTicks arrived_in_browser_main_timestamp,
459     const base::TickClock* tick_clock)
460     : EventMetrics(type,
461                    timestamp,
462                    arrived_in_browser_main_timestamp,
463                    tick_clock),
464       scroll_type_(scroll_type) {}
465
466 ScrollEventMetrics::ScrollEventMetrics(const ScrollEventMetrics&) = default;
467
468 ScrollEventMetrics::~ScrollEventMetrics() {
469   if (should_record_tracing()) {
470     EventLatencyTracingRecorder::RecordEventLatencyTraceEvent(
471         this, base::TimeTicks::Now(), nullptr, nullptr);
472   }
473 }
474
475 const char* ScrollEventMetrics::GetScrollTypeName() const {
476   return kScrollTypes[static_cast<int>(scroll_type_)].name;
477 }
478
479 ScrollEventMetrics* ScrollEventMetrics::AsScroll() {
480   return this;
481 }
482
483 std::unique_ptr<EventMetrics> ScrollEventMetrics::Clone() const {
484   return base::WrapUnique(new ScrollEventMetrics(*this));
485 }
486
487 // ScrollUpdateEventMetrics
488
489 // static
490 std::unique_ptr<ScrollUpdateEventMetrics> ScrollUpdateEventMetrics::Create(
491     ui::EventType type,
492     ui::ScrollInputType input_type,
493     bool is_inertial,
494     ScrollUpdateType scroll_update_type,
495     float delta,
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.
502
503   DCHECK(IsGestureScrollUpdate(type));
504
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());
508   if (!metrics)
509     return nullptr;
510
511   metrics->SetDispatchStageTimestamp(
512       DispatchStage::kArrivedInRendererCompositor);
513   return metrics;
514 }
515
516 // static
517 std::unique_ptr<ScrollUpdateEventMetrics>
518 ScrollUpdateEventMetrics::CreateForBrowser(ui::EventType type,
519                                            ui::ScrollInputType input_type,
520                                            bool is_inertial,
521                                            ScrollUpdateType scroll_update_type,
522                                            float delta,
523                                            base::TimeTicks timestamp) {
524   return Create(type, input_type, is_inertial, scroll_update_type, delta,
525                 timestamp, base::TimeTicks());
526 }
527
528 // static
529 std::unique_ptr<ScrollUpdateEventMetrics>
530 ScrollUpdateEventMetrics::CreateForTesting(
531     ui::EventType type,
532     ui::ScrollInputType input_type,
533     bool is_inertial,
534     ScrollUpdateType scroll_update_type,
535     float delta,
536     base::TimeTicks timestamp,
537     base::TimeTicks arrived_in_browser_main_timestamp,
538     const base::TickClock* tick_clock) {
539   DCHECK(!timestamp.is_null());
540
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);
544   if (!metrics)
545     return nullptr;
546
547   metrics->SetDispatchStageTimestamp(
548       DispatchStage::kArrivedInRendererCompositor);
549   return metrics;
550 }
551
552 // static
553 std::unique_ptr<ScrollUpdateEventMetrics>
554 ScrollUpdateEventMetrics::CreateFromExisting(
555     ui::EventType type,
556     ui::ScrollInputType input_type,
557     bool is_inertial,
558     ScrollUpdateType scroll_update_type,
559     float delta,
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.
567   if (!existing)
568     return nullptr;
569
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_);
573   if (!metrics)
574     return nullptr;
575
576   // Use timestamps of all stages (including "Generated" stage) up to
577   // `last_dispatch_stage` from `existing`.
578   metrics->CopyTimestampsFrom(*existing, last_dispatch_stage);
579
580   return metrics;
581 }
582
583 // static
584 std::unique_ptr<ScrollUpdateEventMetrics>
585 ScrollUpdateEventMetrics::CreateInternal(
586     ui::EventType type,
587     ui::ScrollInputType input_type,
588     bool is_inertial,
589     ScrollUpdateType scroll_update_type,
590     float delta,
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)
597     return nullptr;
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));
601 }
602
603 ScrollUpdateEventMetrics::ScrollUpdateEventMetrics(
604     EventType type,
605     ScrollType scroll_type,
606     ScrollUpdateType scroll_update_type,
607     float delta,
608     base::TimeTicks timestamp,
609     base::TimeTicks arrived_in_browser_main_timestamp,
610     const base::TickClock* tick_clock)
611     : ScrollEventMetrics(type,
612                          scroll_type,
613                          timestamp,
614                          arrived_in_browser_main_timestamp,
615                          tick_clock),
616       delta_(delta),
617       predicted_delta_(delta),
618       last_timestamp_(timestamp) {}
619
620 ScrollUpdateEventMetrics::ScrollUpdateEventMetrics(
621     const ScrollUpdateEventMetrics&) = default;
622
623 ScrollUpdateEventMetrics::~ScrollUpdateEventMetrics() {
624   if (should_record_tracing()) {
625     EventLatencyTracingRecorder::RecordEventLatencyTraceEvent(
626         this, base::TimeTicks::Now(), nullptr, nullptr);
627   }
628 }
629
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_;
635 }
636
637 ScrollUpdateEventMetrics* ScrollUpdateEventMetrics::AsScrollUpdate() {
638   return this;
639 }
640
641 std::unique_ptr<EventMetrics> ScrollUpdateEventMetrics::Clone() const {
642   return base::WrapUnique(new ScrollUpdateEventMetrics(*this));
643 }
644
645 // PinchEventMetrics
646
647 // static
648 std::unique_ptr<PinchEventMetrics> PinchEventMetrics::Create(
649     ui::EventType type,
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.
656
657   DCHECK(IsGesturePinch(type));
658
659   std::unique_ptr<PinchEventMetrics> metrics = CreateInternal(
660       type, input_type, timestamp, base::DefaultTickClock::GetInstance());
661   if (!metrics)
662     return nullptr;
663
664   metrics->SetDispatchStageTimestamp(
665       DispatchStage::kArrivedInRendererCompositor);
666   return metrics;
667 }
668
669 // static
670 std::unique_ptr<PinchEventMetrics> PinchEventMetrics::CreateForTesting(
671     ui::EventType type,
672     ui::ScrollInputType input_type,
673     base::TimeTicks timestamp,
674     const base::TickClock* tick_clock) {
675   DCHECK(!timestamp.is_null());
676
677   std::unique_ptr<PinchEventMetrics> metrics =
678       CreateInternal(type, input_type, timestamp, tick_clock);
679   if (!metrics)
680     return nullptr;
681
682   metrics->SetDispatchStageTimestamp(
683       DispatchStage::kArrivedInRendererCompositor);
684   return metrics;
685 }
686
687 // static
688 std::unique_ptr<PinchEventMetrics> PinchEventMetrics::CreateInternal(
689     ui::EventType type,
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)
697     return nullptr;
698   return base::WrapUnique(new PinchEventMetrics(
699       *interesting_type, ToPinchType(input_type), timestamp, tick_clock));
700 }
701
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) {}
707
708 PinchEventMetrics::PinchEventMetrics(const PinchEventMetrics&) = default;
709
710 PinchEventMetrics::~PinchEventMetrics() {
711   if (should_record_tracing()) {
712     EventLatencyTracingRecorder::RecordEventLatencyTraceEvent(
713         this, base::TimeTicks::Now(), nullptr, nullptr);
714   }
715 }
716
717 const char* PinchEventMetrics::GetPinchTypeName() const {
718   return kPinchTypes[static_cast<int>(pinch_type_)].name;
719 }
720
721 PinchEventMetrics* PinchEventMetrics::AsPinch() {
722   return this;
723 }
724
725 std::unique_ptr<EventMetrics> PinchEventMetrics::Clone() const {
726   return base::WrapUnique(new PinchEventMetrics(*this));
727 }
728
729 // EventMetricsSet
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;
738
739 }  // namespace cc