summaryrefslogtreecommitdiff
path: root/chromium/third_party/blink/renderer/core/paint/paint_timing.h
blob: ca4b35ebdfff20d4dcf1ac24379414c1fd9d209a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
// Copyright 2015 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.

#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_PAINT_TIMING_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_PAINT_TIMING_H_

#include <memory>

#include "base/macros.h"
#include "third_party/blink/public/platform/web_layer_tree_view.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/paint/first_meaningful_paint_detector.h"
#include "third_party/blink/renderer/core/paint/paint_event.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/supplementable.h"
#include "third_party/blink/renderer/platform/wtf/functional.h"
#include "third_party/blink/renderer/platform/wtf/time.h"

namespace blink {

class LocalFrame;

// PaintTiming is responsible for tracking paint-related timings for a given
// document.
class CORE_EXPORT PaintTiming final
    : public GarbageCollectedFinalized<PaintTiming>,
      public Supplement<Document> {
  USING_GARBAGE_COLLECTED_MIXIN(PaintTiming);
  friend class FirstMeaningfulPaintDetector;
  using ReportTimeCallback =
      WTF::CrossThreadFunction<void(WebLayerTreeView::SwapResult,
                                    base::TimeTicks)>;

 public:
  static const char kSupplementName[];

  explicit PaintTiming(Document&);
  virtual ~PaintTiming() = default;

  static PaintTiming& From(Document&);

  // Mark*() methods record the time for the given paint event and queue a swap
  // promise to record the |first_*_swap_| timestamp. These methods do nothing
  // (early return) if a time has already been recorded for the given paint
  // event.
  void MarkFirstPaint();

  // MarkFirstImagePaint, and MarkFirstContentfulPaint
  // will also record first paint if first paint hasn't been recorded yet.
  void MarkFirstContentfulPaint();

  // MarkFirstImagePaint will also record first contentful paint if first
  // contentful paint hasn't been recorded yet.
  void MarkFirstImagePaint();

  void SetFirstMeaningfulPaintCandidate(TimeTicks timestamp);
  void SetFirstMeaningfulPaint(
      TimeTicks swap_stamp,
      FirstMeaningfulPaintDetector::HadUserInput had_input);
  void NotifyPaint(bool is_first_paint, bool text_painted, bool image_painted);

  // The getters below return monotonically-increasing seconds, or zero if the
  // given paint event has not yet occurred. See the comments for
  // monotonicallyIncreasingTime in wtf/Time.h for additional details.

  // FirstPaint returns the first time that anything was painted for the
  // current document.
  TimeTicks FirstPaint() const { return first_paint_swap_; }

  // FirstContentfulPaint returns the first time that 'contentful' content was
  // painted. For instance, the first time that text or image content was
  // painted.
  TimeTicks FirstContentfulPaint() const {
    return first_contentful_paint_swap_;
  }

  // FirstImagePaint returns the first time that image content was painted.
  TimeTicks FirstImagePaint() const { return first_image_paint_swap_; }

  // FirstMeaningfulPaint returns the first time that page's primary content
  // was painted.
  TimeTicks FirstMeaningfulPaint() const {
    return first_meaningful_paint_swap_;
  }

  // FirstMeaningfulPaintCandidate indicates the first time we considered a
  // paint to qualify as the potentially first meaningful paint. Unlike
  // firstMeaningfulPaint, this signal is available in real time, but it may be
  // an optimistic (i.e., too early) estimate.
  TimeTicks FirstMeaningfulPaintCandidate() const {
    return first_meaningful_paint_candidate_;
  }

  FirstMeaningfulPaintDetector& GetFirstMeaningfulPaintDetector() {
    return *fmp_detector_;
  }

  void RegisterNotifySwapTime(PaintEvent, ReportTimeCallback);
  void ReportSwapTime(PaintEvent,
                      WebLayerTreeView::SwapResult,
                      base::TimeTicks timestamp);

  void ReportSwapResultHistogram(const WebLayerTreeView::SwapResult);

  void Trace(blink::Visitor*) override;

 private:
  LocalFrame* GetFrame() const;
  void NotifyPaintTimingChanged();

  // Set*() set the timing for the given paint event to the given timestamp if
  // the value is currently zero, and queue a swap promise to record the
  // |first_*_swap_| timestamp. These methods can be invoked from other Mark*()
  // or Set*() methods to make sure that first paint is marked as part of
  // marking first contentful paint, or that first contentful paint is marked as
  // part of marking first text/image paint, for example.
  void SetFirstPaint(TimeTicks stamp);

  // setFirstContentfulPaint will also set first paint time if first paint
  // time has not yet been recorded.
  void SetFirstContentfulPaint(TimeTicks stamp);

  // Set*Swap() are called when the SwapPromise is fulfilled and the swap
  // timestamp is available. These methods will record trace events, update Web
  // Perf API (FP and FCP only), and notify that paint timing has changed, which
  // triggers UMAs and UKMS.
  // |stamp| is the swap timestamp used for tracing, UMA, UKM, and Web Perf API.
  void SetFirstPaintSwap(TimeTicks stamp);
  void SetFirstContentfulPaintSwap(TimeTicks stamp);
  void SetFirstImagePaintSwap(TimeTicks stamp);

  void RegisterNotifySwapTime(PaintEvent);
  void ReportUserInputHistogram(
      FirstMeaningfulPaintDetector::HadUserInput had_input);

  TimeTicks FirstPaintRendered() const { return first_paint_; }

  TimeTicks FirstContentfulPaintRendered() const {
    return first_contentful_paint_;
  }

  // TODO(crbug/738235): Non first_*_swap_ variables are only being tracked to
  // compute deltas for reporting histograms and should be removed once we
  // confirm the deltas and discrepancies look reasonable.
  TimeTicks first_paint_;
  TimeTicks first_paint_swap_;
  TimeTicks first_image_paint_;
  TimeTicks first_image_paint_swap_;
  TimeTicks first_contentful_paint_;
  TimeTicks first_contentful_paint_swap_;
  TimeTicks first_meaningful_paint_swap_;
  TimeTicks first_meaningful_paint_candidate_;

  Member<FirstMeaningfulPaintDetector> fmp_detector_;

  FRIEND_TEST_ALL_PREFIXES(FirstMeaningfulPaintDetectorTest, NoFirstPaint);
  FRIEND_TEST_ALL_PREFIXES(FirstMeaningfulPaintDetectorTest, OneLayout);
  FRIEND_TEST_ALL_PREFIXES(FirstMeaningfulPaintDetectorTest,
                           TwoLayoutsSignificantSecond);
  FRIEND_TEST_ALL_PREFIXES(FirstMeaningfulPaintDetectorTest,
                           TwoLayoutsSignificantFirst);
  FRIEND_TEST_ALL_PREFIXES(FirstMeaningfulPaintDetectorTest,
                           FirstMeaningfulPaintCandidate);
  FRIEND_TEST_ALL_PREFIXES(
      FirstMeaningfulPaintDetectorTest,
      OnlyOneFirstMeaningfulPaintCandidateBeforeNetworkStable);
  FRIEND_TEST_ALL_PREFIXES(FirstMeaningfulPaintDetectorTest,
                           NetworkStableBeforeFirstContentfulPaint);
  FRIEND_TEST_ALL_PREFIXES(
      FirstMeaningfulPaintDetectorTest,
      FirstMeaningfulPaintShouldNotBeBeforeFirstContentfulPaint);
  FRIEND_TEST_ALL_PREFIXES(FirstMeaningfulPaintDetectorTest,
                           Network2QuietThen0Quiet);
  FRIEND_TEST_ALL_PREFIXES(FirstMeaningfulPaintDetectorTest,
                           Network0QuietThen2Quiet);
  FRIEND_TEST_ALL_PREFIXES(FirstMeaningfulPaintDetectorTest,
                           Network0QuietTimer);
  FRIEND_TEST_ALL_PREFIXES(FirstMeaningfulPaintDetectorTest,
                           Network2QuietTimer);
  FRIEND_TEST_ALL_PREFIXES(FirstMeaningfulPaintDetectorTest,
                           FirstMeaningfulPaintAfterUserInteraction);
  FRIEND_TEST_ALL_PREFIXES(FirstMeaningfulPaintDetectorTest,
                           UserInteractionBeforeFirstPaint);
  FRIEND_TEST_ALL_PREFIXES(
      FirstMeaningfulPaintDetectorTest,
      WaitForSingleOutstandingSwapPromiseAfterNetworkStable);
  FRIEND_TEST_ALL_PREFIXES(
      FirstMeaningfulPaintDetectorTest,
      WaitForMultipleOutstandingSwapPromisesAfterNetworkStable);
  FRIEND_TEST_ALL_PREFIXES(FirstMeaningfulPaintDetectorTest,
                           WaitForFirstContentfulPaintSwapAfterNetworkStable);
  FRIEND_TEST_ALL_PREFIXES(
      FirstMeaningfulPaintDetectorTest,
      ProvisionalTimestampChangesAfterNetworkQuietWithOutstandingSwapPromise);

  DISALLOW_COPY_AND_ASSIGN(PaintTiming);
};

}  // namespace blink

#endif