| OLD | NEW |
| 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 Loading... |
| 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(); |
| 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; |
| 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 CHECK(this == UserGestureIndicator::currentToken()); |
| 84 m_usageCallback = callback; |
| 85 } |
| 86 |
| 87 void UserGestureToken::userGestureUtilized() { |
| 88 if (m_usageCallback) { |
| 89 m_usageCallback->userGestureUtilized(); |
| 90 m_usageCallback = nullptr; |
| 91 } |
| 92 } |
| 93 |
| 94 UserGestureToken* UserGestureIndicator::s_rootToken = nullptr; |
| 126 bool UserGestureIndicator::s_processedUserGestureSinceLoad = false; | 95 bool UserGestureIndicator::s_processedUserGestureSinceLoad = false; |
| 127 | 96 |
| 128 UserGestureIndicator::UserGestureIndicator( | 97 UserGestureIndicator::UserGestureIndicator(PassRefPtr<UserGestureToken> token) |
| 129 ProcessingUserGestureState state, | 98 : m_token(token) { |
| 130 UserGestureUtilizedCallback* usageCallback) | |
| 131 : m_previousState(DefinitelyNotProcessingUserGesture), | |
| 132 m_usageCallback(usageCallback) { | |
| 133 // Silently ignore UserGestureIndicators on non-main threads. | 99 // Silently ignore UserGestureIndicators on non-main threads. |
| 134 if (!isMainThread()) | 100 if (!isMainThread() || !m_token) |
| 135 return; | 101 return; |
| 136 | 102 |
| 137 m_previousState = s_state; | 103 if (!s_rootToken) |
| 138 | 104 s_rootToken = m_token.get(); |
| 139 // We overwrite s_state only if the caller is definite about the gesture | 105 else |
| 140 // state. | 106 m_token->transferGestureTo(s_rootToken); |
| 141 if (isDefinite(state)) { | 107 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 } | 108 } |
| 190 | 109 |
| 191 UserGestureIndicator::~UserGestureIndicator() { | 110 UserGestureIndicator::~UserGestureIndicator() { |
| 192 if (!isMainThread()) | 111 if (isMainThread() && m_token && m_token == s_rootToken) { |
| 193 return; | 112 s_rootToken->setUserGestureUtilizedCallback(nullptr); |
| 194 s_state = m_previousState; | 113 s_rootToken = nullptr; |
| 195 if (s_topmostIndicator == this) | 114 } |
| 196 s_topmostIndicator = nullptr; | |
| 197 ASSERT(isDefinite(s_state)); | |
| 198 } | 115 } |
| 199 | 116 |
| 200 // static | 117 // static |
| 201 bool UserGestureIndicator::utilizeUserGesture() { | 118 bool UserGestureIndicator::utilizeUserGesture() { |
| 202 if (UserGestureIndicator::processingUserGesture()) { | 119 if (UserGestureIndicator::processingUserGesture()) { |
| 203 if (s_topmostIndicator->m_usageCallback) { | 120 s_rootToken->userGestureUtilized(); |
| 204 s_topmostIndicator->m_usageCallback->userGestureUtilized(); | |
| 205 s_topmostIndicator->m_usageCallback = nullptr; | |
| 206 } | |
| 207 return true; | 121 return true; |
| 208 } | 122 } |
| 209 return false; | 123 return false; |
| 210 } | 124 } |
| 211 | 125 |
| 212 bool UserGestureIndicator::processingUserGesture() { | 126 bool UserGestureIndicator::processingUserGesture() { |
| 213 if (auto* token = currentToken()) { | 127 if (auto* token = currentToken()) { |
| 214 ASSERT(isMainThread()); | 128 ASSERT(isMainThread()); |
| 215 return isDefiniteUserGesture(s_state) && | 129 return token->hasGestures(); |
| 216 static_cast<GestureToken*>(token)->hasGestures(); | |
| 217 } | 130 } |
| 218 | 131 |
| 219 return false; | 132 return false; |
| 220 } | 133 } |
| 221 | 134 |
| 222 // static | 135 // static |
| 223 bool UserGestureIndicator::consumeUserGesture() { | 136 bool UserGestureIndicator::consumeUserGesture() { |
| 224 if (auto* token = currentToken()) { | 137 if (auto* token = currentToken()) { |
| 225 ASSERT(isMainThread()); | 138 ASSERT(isMainThread()); |
| 226 if (static_cast<GestureToken*>(token)->consumeGesture()) { | 139 if (token->consumeGesture()) { |
| 227 if (s_topmostIndicator->m_usageCallback) { | 140 token->userGestureUtilized(); |
| 228 s_topmostIndicator->m_usageCallback->userGestureUtilized(); | |
| 229 s_topmostIndicator->m_usageCallback = nullptr; | |
| 230 } | |
| 231 return true; | 141 return true; |
| 232 } | 142 } |
| 233 } | 143 } |
| 234 return false; | 144 return false; |
| 235 } | 145 } |
| 236 | 146 |
| 237 // static | 147 // static |
| 238 UserGestureToken* UserGestureIndicator::currentToken() { | 148 UserGestureToken* UserGestureIndicator::currentToken() { |
| 239 if (!isMainThread() || !s_topmostIndicator) | 149 if (!isMainThread() || !s_rootToken) |
| 240 return nullptr; | 150 return nullptr; |
| 241 return s_topmostIndicator->m_token.get(); | 151 return s_rootToken; |
| 242 } | 152 } |
| 243 | 153 |
| 244 // static | 154 // static |
| 245 void UserGestureIndicator::clearProcessedUserGestureSinceLoad() { | 155 void UserGestureIndicator::clearProcessedUserGestureSinceLoad() { |
| 246 if (isMainThread()) | 156 if (isMainThread()) |
| 247 s_processedUserGestureSinceLoad = false; | 157 s_processedUserGestureSinceLoad = false; |
| 248 } | 158 } |
| 249 | 159 |
| 250 // static | 160 // static |
| 251 bool UserGestureIndicator::processedUserGestureSinceLoad() { | 161 bool UserGestureIndicator::processedUserGestureSinceLoad() { |
| 252 if (!isMainThread()) | 162 if (!isMainThread()) |
| 253 return false; | 163 return false; |
| 254 return s_processedUserGestureSinceLoad; | 164 return s_processedUserGestureSinceLoad; |
| 255 } | 165 } |
| 256 | 166 |
| 257 } // namespace blink | 167 } // namespace blink |
| OLD | NEW |