2 * Copyright (C) 2010 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
27 #include "platform/UserGestureIndicator.h"
29 #include "wtf/Assertions.h"
30 #include "wtf/CurrentTime.h"
31 #include "wtf/MainThread.h"
37 // User gestures timeout in 1 second.
38 const double userGestureTimeout
= 1.0;
40 // For out of process tokens we allow a 10 second delay.
41 const double userGestureOutOfProcessTimeout
= 10.0;
43 class GestureToken
: public UserGestureToken
{
45 static PassRefPtr
<UserGestureToken
> create() { return adoptRef(new GestureToken
); }
47 ~GestureToken() override
{}
48 bool hasGestures() const override
50 // Do not enforce timeouts for gestures which spawned javascript prompts.
51 if (m_consumableGestures
< 1 || (WTF::currentTime() - m_timestamp
> (m_outOfProcess
? userGestureOutOfProcessTimeout
: userGestureTimeout
) && !m_javascriptPrompt
))
58 m_consumableGestures
++;
59 m_timestamp
= WTF::currentTime();
64 m_timestamp
= WTF::currentTime();
69 if (!m_consumableGestures
)
71 m_consumableGestures
--;
75 void setOutOfProcess() override
77 if (WTF::currentTime() - m_timestamp
> userGestureTimeout
)
80 m_outOfProcess
= true;
83 void setJavascriptPrompt() override
85 if (WTF::currentTime() - m_timestamp
> userGestureTimeout
)
88 m_javascriptPrompt
= true;
93 : m_consumableGestures(0)
95 , m_outOfProcess(false)
96 , m_javascriptPrompt(false)
100 size_t m_consumableGestures
;
103 bool m_javascriptPrompt
;
108 static bool isDefinite(ProcessingUserGestureState state
)
110 return state
== DefinitelyProcessingNewUserGesture
|| state
== DefinitelyProcessingUserGesture
|| state
== DefinitelyNotProcessingUserGesture
;
113 ProcessingUserGestureState
UserGestureIndicator::s_state
= DefinitelyNotProcessingUserGesture
;
114 UserGestureIndicator
* UserGestureIndicator::s_topmostIndicator
= 0;
115 bool UserGestureIndicator::s_processedUserGestureSinceLoad
= false;
117 UserGestureIndicator::UserGestureIndicator(ProcessingUserGestureState state
)
118 : m_previousState(DefinitelyNotProcessingUserGesture
)
120 // Silently ignore UserGestureIndicators on non-main threads.
124 m_previousState
= s_state
;
126 // We overwrite s_state only if the caller is definite about the gesture state.
127 if (isDefinite(state
)) {
128 if (!s_topmostIndicator
) {
129 s_topmostIndicator
= this;
130 m_token
= GestureToken::create();
132 m_token
= s_topmostIndicator
->currentToken();
137 if (state
== DefinitelyProcessingNewUserGesture
) {
138 static_cast<GestureToken
*>(m_token
.get())->addGesture();
139 s_processedUserGestureSinceLoad
= true;
140 } else if (state
== DefinitelyProcessingUserGesture
&& s_topmostIndicator
== this) {
141 static_cast<GestureToken
*>(m_token
.get())->addGesture();
142 s_processedUserGestureSinceLoad
= true;
144 ASSERT(isDefinite(s_state
));
147 UserGestureIndicator::UserGestureIndicator(PassRefPtr
<UserGestureToken
> token
)
148 : m_previousState(DefinitelyNotProcessingUserGesture
)
150 // Silently ignore UserGestureIndicators on non-main threads.
154 m_previousState
= s_state
;
157 static_cast<GestureToken
*>(token
.get())->resetTimestamp();
158 if (!s_topmostIndicator
) {
159 s_topmostIndicator
= this;
162 m_token
= s_topmostIndicator
->currentToken();
163 if (static_cast<GestureToken
*>(token
.get())->hasGestures()) {
164 static_cast<GestureToken
*>(m_token
.get())->addGesture();
165 static_cast<GestureToken
*>(token
.get())->consumeGesture();
168 s_state
= DefinitelyProcessingUserGesture
;
171 ASSERT(isDefinite(s_state
));
174 UserGestureIndicator::~UserGestureIndicator()
178 s_state
= m_previousState
;
179 if (s_topmostIndicator
== this)
180 s_topmostIndicator
= 0;
181 ASSERT(isDefinite(s_state
));
184 bool UserGestureIndicator::processingUserGesture()
188 return s_topmostIndicator
&& static_cast<GestureToken
*>(s_topmostIndicator
->currentToken())->hasGestures() && (s_state
== DefinitelyProcessingNewUserGesture
|| s_state
== DefinitelyProcessingUserGesture
);
191 bool UserGestureIndicator::consumeUserGesture()
193 if (!isMainThread() || !s_topmostIndicator
)
195 return static_cast<GestureToken
*>(s_topmostIndicator
->currentToken())->consumeGesture();
198 UserGestureToken
* UserGestureIndicator::currentToken()
200 if (!isMainThread() || !s_topmostIndicator
)
202 return s_topmostIndicator
->m_token
.get();
205 void UserGestureIndicator::clearProcessedUserGestureSinceLoad()
208 s_processedUserGestureSinceLoad
= false;
211 bool UserGestureIndicator::processedUserGestureSinceLoad()
215 return s_processedUserGestureSinceLoad
;