Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(895)

Side by Side Diff: third_party/WebKit/Source/platform/UserGestureIndicator.cpp

Issue 2401123002: UserGestureIndicator is a mess. Clean it up. (Closed)
Patch Set: Fix tests Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * Copyright (C) 2010 Apple Inc. All rights reserved. 2 * Copyright (C) 2010 Apple Inc. All rights reserved.
3 * 3 *
4 * Redistribution and use in source and binary forms, with or without 4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions 5 * modification, are permitted provided that the following conditions
6 * are met: 6 * are met:
7 * 1. Redistributions of source code must retain the above copyright 7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer. 8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright 9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the 10 * notice, this list of conditions and the following disclaimer in the
(...skipping 12 matching lines...) Expand all
23 * THE POSSIBILITY OF SUCH DAMAGE. 23 * THE POSSIBILITY OF SUCH DAMAGE.
24 */ 24 */
25 25
26 #include "platform/UserGestureIndicator.h" 26 #include "platform/UserGestureIndicator.h"
27 27
28 #include "wtf/Assertions.h" 28 #include "wtf/Assertions.h"
29 #include "wtf/CurrentTime.h" 29 #include "wtf/CurrentTime.h"
30 30
31 namespace blink { 31 namespace blink {
32 32
33 namespace {
34
35 // User gestures timeout in 1 second. 33 // User gestures timeout in 1 second.
36 const double userGestureTimeout = 1.0; 34 const double userGestureTimeout = 1.0;
37 35
38 // For out of process tokens we allow a 10 second delay. 36 // For out of process tokens we allow a 10 second delay.
39 const double userGestureOutOfProcessTimeout = 10.0; 37 const double userGestureOutOfProcessTimeout = 10.0;
40 38
41 class GestureToken final : public UserGestureToken { 39 UserGestureToken::UserGestureToken(Status status)
42 WTF_MAKE_NONCOPYABLE(GestureToken); 40 : m_consumableGestures(0),
43 41 m_timestamp(WTF::currentTime()),
44 public: 42 m_timeoutPolicy(Default),
45 static PassRefPtr<UserGestureToken> create() { 43 m_usageCallback(nullptr) {
46 return adoptRef(new GestureToken); 44 if (status == NewGesture || !UserGestureIndicator::currentToken())
47 }
48
49 ~GestureToken() final {}
50
51 bool hasGestures() const override {
52 // Do not enforce timeouts for gestures which spawned javascript prompts or
53 // debugger pause.
54 if (m_consumableGestures < 1 ||
55 (!m_javascriptPrompt && !m_pauseInDebugger &&
56 hasTimedOut(m_outOfProcess ? userGestureOutOfProcessTimeout
57 : userGestureTimeout)))
58 return false;
59 return true;
60 }
61
62 void addGesture() {
63 m_consumableGestures++; 45 m_consumableGestures++;
64 m_timestamp = WTF::currentTime();
65 }
66
67 void resetTimestamp() { m_timestamp = WTF::currentTime(); }
68
69 bool consumeGesture() {
70 if (!m_consumableGestures)
71 return false;
72 m_consumableGestures--;
73 return true;
74 }
75
76 void setOutOfProcess() final {
77 if (!hasTimedOut(userGestureTimeout) && hasGestures())
78 m_outOfProcess = true;
79 }
80
81 void setJavascriptPrompt() final {
82 if (!hasTimedOut(userGestureTimeout) && hasGestures())
83 m_javascriptPrompt = true;
84 }
85
86 void setPauseInDebugger() final {
87 if (!hasTimedOut(userGestureTimeout) && hasGestures())
88 m_pauseInDebugger = true;
89 }
90
91 private:
92 GestureToken()
93 : m_consumableGestures(0),
94 m_timestamp(0),
95 m_outOfProcess(false),
96 m_javascriptPrompt(false),
97 m_pauseInDebugger(false) {}
98
99 bool hasTimedOut(double timeout) const {
100 return WTF::currentTime() - m_timestamp > timeout;
101 }
102
103 size_t m_consumableGestures;
104 double m_timestamp;
105 bool m_outOfProcess;
106 bool m_javascriptPrompt;
107 bool m_pauseInDebugger;
108 };
109
110 bool isDefinite(ProcessingUserGestureState state) {
111 return state == DefinitelyProcessingNewUserGesture ||
112 state == DefinitelyProcessingUserGesture ||
113 state == DefinitelyNotProcessingUserGesture;
114 } 46 }
115 47
116 bool isDefiniteUserGesture(ProcessingUserGestureState state) { 48 bool UserGestureToken::hasGestures() {
117 return state == DefinitelyProcessingNewUserGesture || 49 return m_consumableGestures && !hasTimedOut();
118 state == DefinitelyProcessingUserGesture;
119 } 50 }
120 51
121 } // namespace 52 void UserGestureToken::transferGestureTo(UserGestureToken* other) {
53 if (!hasGestures())
54 return;
55 m_consumableGestures--;
56 other->m_consumableGestures++;
57 other->m_timestamp = WTF::currentTime();
Nate Chapin 2016/10/10 22:26:46 I kept the old behavior here when a UserGestureTok
dtapuska 2016/10/11 14:00:03 Why are we using currentTime and not monotonic tim
jochen (gone - plz use gerrit) 2016/10/11 17:06:00 at the time I wrote the transfer of tokens, Adam a
Nate Chapin 2016/10/11 17:27:00 Ok, all that makes sense. I'm going to change the
58 }
122 59
123 ProcessingUserGestureState UserGestureIndicator::s_state = 60 bool UserGestureToken::consumeGesture() {
124 DefinitelyNotProcessingUserGesture; 61 if (!m_consumableGestures)
125 UserGestureIndicator* UserGestureIndicator::s_topmostIndicator = 0; 62 return false;
Nate Chapin 2016/10/10 22:26:46 Fun fact! s_topmostIndicator was actually the bott
jochen (gone - plz use gerrit) 2016/10/11 17:06:00 well, on this stack, you push to the top...
Nate Chapin 2016/10/11 17:27:00 Of course. But s_topmostIndicator was initialized
63 m_consumableGestures--;
64 return true;
65 }
66
67 void UserGestureToken::setTimeoutPolicy(TimeoutPolicy policy) {
68 if (!hasTimedOut() && hasGestures() && policy > m_timeoutPolicy)
69 m_timeoutPolicy = policy;
70 }
71
72 bool UserGestureToken::hasTimedOut() const {
73 if (m_timeoutPolicy == HasPaused)
74 return false;
75 double timeout = m_timeoutPolicy == OutOfProcess
76 ? userGestureOutOfProcessTimeout
77 : userGestureTimeout;
78 return WTF::currentTime() - m_timestamp > timeout;
79 }
80
81 void UserGestureToken::setUserGestureUtilizedCallback(
82 UserGestureUtilizedCallback* callback) {
83 m_usageCallback = callback;
84 }
85
86 void UserGestureToken::userGestureUtilized() {
87 if (m_usageCallback) {
88 m_usageCallback->userGestureUtilized();
89 m_usageCallback = nullptr;
90 }
91 }
92
93 UserGestureToken* UserGestureIndicator::s_rootToken = nullptr;
126 bool UserGestureIndicator::s_processedUserGestureSinceLoad = false; 94 bool UserGestureIndicator::s_processedUserGestureSinceLoad = false;
127 95
128 UserGestureIndicator::UserGestureIndicator( 96 UserGestureIndicator::UserGestureIndicator(PassRefPtr<UserGestureToken> token)
129 ProcessingUserGestureState state, 97 : m_token(token) {
130 UserGestureUtilizedCallback* usageCallback)
131 : m_previousState(DefinitelyNotProcessingUserGesture),
132 m_usageCallback(usageCallback) {
133 // Silently ignore UserGestureIndicators on non-main threads. 98 // Silently ignore UserGestureIndicators on non-main threads.
134 if (!isMainThread()) 99 if (!isMainThread() || !m_token)
135 return; 100 return;
136 101
137 m_previousState = s_state; 102 if (!s_rootToken)
138 103 s_rootToken = m_token.get();
139 // We overwrite s_state only if the caller is definite about the gesture 104 else
140 // state. 105 m_token->transferGestureTo(s_rootToken);
141 if (isDefinite(state)) { 106 s_processedUserGestureSinceLoad = true;
142 if (!s_topmostIndicator) {
143 s_topmostIndicator = this;
144 m_token = GestureToken::create();
145 } else {
146 m_token = currentToken();
147 }
148 s_state = state;
149 }
150
151 if (state == DefinitelyProcessingNewUserGesture) {
152 static_cast<GestureToken*>(m_token.get())->addGesture();
153 s_processedUserGestureSinceLoad = true;
154 } else if (state == DefinitelyProcessingUserGesture &&
155 s_topmostIndicator == this) {
156 static_cast<GestureToken*>(m_token.get())->addGesture();
157 s_processedUserGestureSinceLoad = true;
158 }
159 ASSERT(isDefinite(s_state));
160 }
161
162 UserGestureIndicator::UserGestureIndicator(
163 PassRefPtr<UserGestureToken> token,
164 UserGestureUtilizedCallback* usageCallback)
165 : m_previousState(DefinitelyNotProcessingUserGesture),
166 m_usageCallback(usageCallback) {
167 // Silently ignore UserGestureIndicators on non-main threads.
168 if (!isMainThread())
169 return;
170
171 m_previousState = s_state;
172
173 if (token) {
174 static_cast<GestureToken*>(token.get())->resetTimestamp();
175 if (!s_topmostIndicator) {
176 s_topmostIndicator = this;
177 m_token = token;
178 } else {
179 m_token = currentToken();
180 if (static_cast<GestureToken*>(token.get())->hasGestures()) {
181 static_cast<GestureToken*>(m_token.get())->addGesture();
182 static_cast<GestureToken*>(token.get())->consumeGesture();
183 }
184 }
185 s_state = DefinitelyProcessingUserGesture;
186 }
187
188 ASSERT(isDefinite(s_state));
189 } 107 }
190 108
191 UserGestureIndicator::~UserGestureIndicator() { 109 UserGestureIndicator::~UserGestureIndicator() {
192 if (!isMainThread()) 110 if (isMainThread() && m_token && m_token == s_rootToken) {
Rick Byers 2016/10/11 18:00:19 The callback lifetime semantics seem tricky. I ha
Nate Chapin 2016/10/11 18:18:42 Given how UserGestureUtilizedCallback are currentl
Nate Chapin 2016/10/11 19:17:55 Done (3).
193 return; 111 s_rootToken->setUserGestureUtilizedCallback(nullptr);
194 s_state = m_previousState; 112 s_rootToken = nullptr;
195 if (s_topmostIndicator == this) 113 }
196 s_topmostIndicator = nullptr;
197 ASSERT(isDefinite(s_state));
198 } 114 }
199 115
200 // static 116 // static
201 bool UserGestureIndicator::utilizeUserGesture() { 117 bool UserGestureIndicator::utilizeUserGesture() {
202 if (UserGestureIndicator::processingUserGesture()) { 118 if (UserGestureIndicator::processingUserGesture()) {
203 if (s_topmostIndicator->m_usageCallback) { 119 s_rootToken->userGestureUtilized();
204 s_topmostIndicator->m_usageCallback->userGestureUtilized();
205 s_topmostIndicator->m_usageCallback = nullptr;
206 }
207 return true; 120 return true;
208 } 121 }
209 return false; 122 return false;
210 } 123 }
211 124
212 bool UserGestureIndicator::processingUserGesture() { 125 bool UserGestureIndicator::processingUserGesture() {
213 if (auto* token = currentToken()) { 126 if (auto* token = currentToken()) {
214 ASSERT(isMainThread()); 127 ASSERT(isMainThread());
215 return isDefiniteUserGesture(s_state) && 128 return token->hasGestures();
216 static_cast<GestureToken*>(token)->hasGestures();
217 } 129 }
218 130
219 return false; 131 return false;
220 } 132 }
221 133
222 // static 134 // static
223 bool UserGestureIndicator::consumeUserGesture() { 135 bool UserGestureIndicator::consumeUserGesture() {
224 if (auto* token = currentToken()) { 136 if (auto* token = currentToken()) {
225 ASSERT(isMainThread()); 137 ASSERT(isMainThread());
226 if (static_cast<GestureToken*>(token)->consumeGesture()) { 138 if (token->consumeGesture()) {
227 if (s_topmostIndicator->m_usageCallback) { 139 token->userGestureUtilized();
228 s_topmostIndicator->m_usageCallback->userGestureUtilized();
229 s_topmostIndicator->m_usageCallback = nullptr;
230 }
231 return true; 140 return true;
232 } 141 }
233 } 142 }
234 return false; 143 return false;
235 } 144 }
236 145
237 // static 146 // static
238 UserGestureToken* UserGestureIndicator::currentToken() { 147 UserGestureToken* UserGestureIndicator::currentToken() {
239 if (!isMainThread() || !s_topmostIndicator) 148 if (!isMainThread() || !s_rootToken)
240 return nullptr; 149 return nullptr;
241 return s_topmostIndicator->m_token.get(); 150 return s_rootToken;
242 } 151 }
243 152
244 // static 153 // static
245 void UserGestureIndicator::clearProcessedUserGestureSinceLoad() { 154 void UserGestureIndicator::clearProcessedUserGestureSinceLoad() {
246 if (isMainThread()) 155 if (isMainThread())
247 s_processedUserGestureSinceLoad = false; 156 s_processedUserGestureSinceLoad = false;
248 } 157 }
249 158
250 // static 159 // static
251 bool UserGestureIndicator::processedUserGestureSinceLoad() { 160 bool UserGestureIndicator::processedUserGestureSinceLoad() {
252 if (!isMainThread()) 161 if (!isMainThread())
253 return false; 162 return false;
254 return s_processedUserGestureSinceLoad; 163 return s_processedUserGestureSinceLoad;
255 } 164 }
256 165
257 } // namespace blink 166 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698