1 // Copyright 2019 The Chromium Authors. All rights reserved.
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 "third_party/blink/renderer/core/page/scrolling/text_fragment_anchor_metrics.h"
6
7 #include "base/logging.h"
8 #include "base/metrics/histogram_macros.h"
9 #include "base/trace_event/trace_event.h"
10 #include "third_party/blink/renderer/core/frame/web_feature.h"
11 #include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
12
13 namespace blink {
14
15 namespace {
16
17 const size_t kMaxTraceEventStringLength = 1000;
18
19 } // namespace
20
TextFragmentAnchorMetrics(Document * document)21 TextFragmentAnchorMetrics::TextFragmentAnchorMetrics(Document* document)
22 : document_(document) {}
23
DidCreateAnchor(int selector_count)24 void TextFragmentAnchorMetrics::DidCreateAnchor(int selector_count) {
25 UseCounter::Count(document_, WebFeature::kTextFragmentAnchor);
26 create_time_ = base::TimeTicks::Now();
27 selector_count_ = selector_count;
28 }
29
DidFindMatch(const String text)30 void TextFragmentAnchorMetrics::DidFindMatch(const String text) {
31 matches_.push_back(text);
32 }
33
ResetMatchCount()34 void TextFragmentAnchorMetrics::ResetMatchCount() {
35 matches_.clear();
36 }
37
DidFindAmbiguousMatch()38 void TextFragmentAnchorMetrics::DidFindAmbiguousMatch() {
39 ambiguous_match_ = true;
40 }
41
ScrollCancelled()42 void TextFragmentAnchorMetrics::ScrollCancelled() {
43 scroll_cancelled_ = true;
44 }
45
DidScroll()46 void TextFragmentAnchorMetrics::DidScroll() {
47 if (first_scroll_into_view_time_.is_null())
48 first_scroll_into_view_time_ = base::TimeTicks::Now();
49 }
50
DidNonZeroScroll()51 void TextFragmentAnchorMetrics::DidNonZeroScroll() {
52 did_non_zero_scroll_ = true;
53 }
54
ReportMetrics()55 void TextFragmentAnchorMetrics::ReportMetrics() {
56 #ifndef NDEBUG
57 DCHECK(!metrics_reported_);
58 #endif
59 DCHECK(selector_count_);
60 DCHECK(matches_.size() <= selector_count_);
61
62 if (matches_.size() > 0) {
63 UseCounter::Count(document_, WebFeature::kTextFragmentAnchorMatchFound);
64 }
65
66 UMA_HISTOGRAM_COUNTS_100("TextFragmentAnchor.SelectorCount", selector_count_);
67 TRACE_EVENT_INSTANT1("blink", "TextFragmentAnchorMetrics::ReportMetrics",
68 TRACE_EVENT_SCOPE_THREAD, "selector_count",
69 selector_count_);
70
71 const int match_rate_percent =
72 static_cast<int>(100 * ((matches_.size() + 0.0) / selector_count_));
73 UMA_HISTOGRAM_PERCENTAGE("TextFragmentAnchor.MatchRate", match_rate_percent);
74 TRACE_EVENT_INSTANT1("blink", "TextFragmentAnchorMetrics::ReportMetrics",
75 TRACE_EVENT_SCOPE_THREAD, "match_rate",
76 match_rate_percent);
77
78 for (const String& match : matches_) {
79 TRACE_EVENT_INSTANT2("blink", "TextFragmentAnchorMetrics::ReportMetrics",
80 TRACE_EVENT_SCOPE_THREAD, "match_found",
81 match.Utf8().substr(0, kMaxTraceEventStringLength),
82 "match_length", match.length());
83 }
84
85 UMA_HISTOGRAM_BOOLEAN("TextFragmentAnchor.AmbiguousMatch", ambiguous_match_);
86 TRACE_EVENT_INSTANT1("blink", "TextFragmentAnchorMetrics::ReportMetrics",
87 TRACE_EVENT_SCOPE_THREAD, "ambiguous_match",
88 ambiguous_match_);
89
90 UMA_HISTOGRAM_BOOLEAN("TextFragmentAnchor.ScrollCancelled",
91 scroll_cancelled_);
92 TRACE_EVENT_INSTANT1("blink", "TextFragmentAnchorMetrics::ReportMetrics",
93 TRACE_EVENT_SCOPE_THREAD, "scroll_cancelled",
94 scroll_cancelled_);
95
96 if (first_scroll_into_view_time_ > create_time_) {
97 UMA_HISTOGRAM_BOOLEAN("TextFragmentAnchor.DidScrollIntoView",
98 did_non_zero_scroll_);
99 TRACE_EVENT_INSTANT1("blink", "TextFragmentAnchorMetrics::ReportMetrics",
100 TRACE_EVENT_SCOPE_THREAD, "did_scroll_into_view",
101 did_non_zero_scroll_);
102
103 base::TimeDelta time_to_scroll_into_view(first_scroll_into_view_time_ -
104 create_time_);
105 UMA_HISTOGRAM_TIMES("TextFragmentAnchor.TimeToScrollIntoView",
106 time_to_scroll_into_view);
107 TRACE_EVENT_INSTANT1("blink", "TextFragmentAnchorMetrics::ReportMetrics",
108 TRACE_EVENT_SCOPE_THREAD, "time_to_scroll_into_view",
109 time_to_scroll_into_view.InMilliseconds());
110 }
111
112 #ifndef NDEBUG
113 metrics_reported_ = true;
114 #endif
115 }
116
Dismissed()117 void TextFragmentAnchorMetrics::Dismissed() {
118 // We report Dismissed separately from ReportMetrics as it may or may not
119 // get called in the lifetime of the TextFragmentAnchor.
120 UseCounter::Count(document_, WebFeature::kTextFragmentAnchorTapToDismiss);
121 TRACE_EVENT_INSTANT0("blink", "TextFragmentAnchorMetrics::Dismissed",
122 TRACE_EVENT_SCOPE_THREAD);
123 }
124
Trace(Visitor * visitor)125 void TextFragmentAnchorMetrics::Trace(Visitor* visitor) {
126 visitor->Trace(document_);
127 }
128
129 } // namespace blink
130