1 /* 2 * Copyright (C) 2010 Apple Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' 14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS 17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 23 * THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26 #include "config.h" 27 #include "core/dom/UserGestureIndicator.h" 28 #include "wtf/CurrentTime.h" 29 30 namespace WebCore { 31 32 namespace { 33 34 // User gestures timeout in 1 second. 35 const double userGestureTimeout = 1.0; 36 37 // For out of process tokens we allow a 10 second delay. 38 const double userGestureOutOfProcessTimeout = 10.0; 39 40 class GestureToken : public UserGestureToken { 41 public: 42 static PassRefPtr<UserGestureToken> create() { return adoptRef(new GestureToken); } 43 44 virtual ~GestureToken() { } 45 virtual bool hasGestures() const OVERRIDE 46 { 47 // Do not enforce timeouts for gestures which spawned javascript prompts. 48 if (m_consumableGestures < 1 || (WTF::currentTime() - m_timestamp > (m_outOfProcess ? userGestureOutOfProcessTimeout : userGestureTimeout) && !m_javascriptPrompt)) 49 return false; 50 return true; 51 } 52 53 void addGesture() 54 { 55 m_consumableGestures++; 56 m_timestamp = WTF::currentTime(); 57 } 58 59 void resetTimestamp() 60 { 61 m_timestamp = WTF::currentTime(); 62 } 63 64 bool consumeGesture() 65 { 66 if (!m_consumableGestures) 67 return false; 68 m_consumableGestures--; 69 return true; 70 } 71 72 virtual void setOutOfProcess() OVERRIDE 73 { 74 if (WTF::currentTime() - m_timestamp > userGestureTimeout) 75 return; 76 if (hasGestures()) 77 m_outOfProcess = true; 78 } 79 80 virtual void setJavascriptPrompt() OVERRIDE 81 { 82 if (WTF::currentTime() - m_timestamp > userGestureTimeout) 83 return; 84 if (hasGestures()) 85 m_javascriptPrompt = true; 86 } 87 88 private: 89 GestureToken() 90 : m_consumableGestures(0), 91 m_timestamp(0), 92 m_outOfProcess(false), 93 m_javascriptPrompt(false) 94 { 95 } 96 97 size_t m_consumableGestures; 98 double m_timestamp; 99 bool m_outOfProcess; 100 bool m_javascriptPrompt; 101 }; 102 103 } 104 105 static bool isDefinite(ProcessingUserGestureState state) 106 { 107 return state == DefinitelyProcessingNewUserGesture || state == DefinitelyProcessingUserGesture || state == DefinitelyNotProcessingUserGesture; 108 } 109 110 ProcessingUserGestureState UserGestureIndicator::s_state = DefinitelyNotProcessingUserGesture; 111 UserGestureIndicator* UserGestureIndicator::s_topmostIndicator = 0; 112 113 UserGestureIndicator::UserGestureIndicator(ProcessingUserGestureState state) 114 : m_previousState(s_state) 115 { 116 // We overwrite s_state only if the caller is definite about the gesture state. 117 if (isDefinite(state)) { 118 if (!s_topmostIndicator) { 119 s_topmostIndicator = this; 120 m_token = GestureToken::create(); 121 } else 122 m_token = s_topmostIndicator->currentToken(); 123 s_state = state; 124 } 125 126 if (state == DefinitelyProcessingNewUserGesture) 127 static_cast<GestureToken*>(m_token.get())->addGesture(); 128 else if (state == DefinitelyProcessingUserGesture && s_topmostIndicator == this) 129 static_cast<GestureToken*>(m_token.get())->addGesture(); 130 ASSERT(isDefinite(s_state)); 131 } 132 133 UserGestureIndicator::UserGestureIndicator(PassRefPtr<UserGestureToken> token) 134 : m_previousState(s_state) 135 { 136 if (token) { 137 static_cast<GestureToken*>(token.get())->resetTimestamp(); 138 if (!s_topmostIndicator) { 139 s_topmostIndicator = this; 140 m_token = token; 141 } else { 142 m_token = s_topmostIndicator->currentToken(); 143 if (static_cast<GestureToken*>(token.get())->hasGestures()) { 144 static_cast<GestureToken*>(m_token.get())->addGesture(); 145 static_cast<GestureToken*>(token.get())->consumeGesture(); 146 } 147 } 148 s_state = DefinitelyProcessingUserGesture; 149 } 150 151 ASSERT(isDefinite(s_state)); 152 } 153 154 UserGestureIndicator::~UserGestureIndicator() 155 { 156 s_state = m_previousState; 157 if (s_topmostIndicator == this) 158 s_topmostIndicator = 0; 159 ASSERT(isDefinite(s_state)); 160 } 161 162 bool UserGestureIndicator::processingUserGesture() 163 { 164 return s_topmostIndicator && static_cast<GestureToken*>(s_topmostIndicator->currentToken())->hasGestures() && (s_state == DefinitelyProcessingNewUserGesture || s_state == DefinitelyProcessingUserGesture); 165 } 166 167 bool UserGestureIndicator::consumeUserGesture() 168 { 169 if (!s_topmostIndicator) 170 return false; 171 return static_cast<GestureToken*>(s_topmostIndicator->currentToken())->consumeGesture(); 172 } 173 174 UserGestureToken* UserGestureIndicator::currentToken() 175 { 176 if (!s_topmostIndicator) 177 return 0; 178 return s_topmostIndicator->m_token.get(); 179 } 180 181 UserGestureIndicatorDisabler::UserGestureIndicatorDisabler() 182 : m_savedState(UserGestureIndicator::s_state) 183 , m_savedIndicator(UserGestureIndicator::s_topmostIndicator) 184 { 185 UserGestureIndicator::s_state = DefinitelyNotProcessingUserGesture; 186 UserGestureIndicator::s_topmostIndicator = 0; 187 } 188 189 UserGestureIndicatorDisabler::~UserGestureIndicatorDisabler() 190 { 191 UserGestureIndicator::s_state = m_savedState; 192 UserGestureIndicator::s_topmostIndicator = m_savedIndicator; 193 } 194 195 } 196