Home | History | Annotate | Download | only in platform
      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 "platform/UserGestureIndicator.h"
     28 
     29 #include "wtf/Assertions.h"
     30 #include "wtf/CurrentTime.h"
     31 #include "wtf/MainThread.h"
     32 
     33 namespace blink {
     34 
     35 namespace {
     36 
     37 // User gestures timeout in 1 second.
     38 const double userGestureTimeout = 1.0;
     39 
     40 // For out of process tokens we allow a 10 second delay.
     41 const double userGestureOutOfProcessTimeout = 10.0;
     42 
     43 class GestureToken : public UserGestureToken {
     44 public:
     45     static PassRefPtr<UserGestureToken> create() { return adoptRef(new GestureToken); }
     46 
     47     virtual ~GestureToken() { }
     48     virtual bool hasGestures() const OVERRIDE
     49     {
     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))
     52             return false;
     53         return true;
     54     }
     55 
     56     void addGesture()
     57     {
     58         m_consumableGestures++;
     59         m_timestamp = WTF::currentTime();
     60     }
     61 
     62     void resetTimestamp()
     63     {
     64         m_timestamp = WTF::currentTime();
     65     }
     66 
     67     bool consumeGesture()
     68     {
     69         if (!m_consumableGestures)
     70             return false;
     71         m_consumableGestures--;
     72         return true;
     73     }
     74 
     75     virtual void setOutOfProcess() OVERRIDE
     76     {
     77         if (WTF::currentTime() - m_timestamp > userGestureTimeout)
     78             return;
     79         if (hasGestures())
     80             m_outOfProcess = true;
     81     }
     82 
     83     virtual void setJavascriptPrompt() OVERRIDE
     84     {
     85         if (WTF::currentTime() - m_timestamp > userGestureTimeout)
     86             return;
     87         if (hasGestures())
     88             m_javascriptPrompt = true;
     89     }
     90 
     91 private:
     92     GestureToken()
     93         : m_consumableGestures(0)
     94         , m_timestamp(0)
     95         , m_outOfProcess(false)
     96         , m_javascriptPrompt(false)
     97     {
     98     }
     99 
    100     size_t m_consumableGestures;
    101     double m_timestamp;
    102     bool m_outOfProcess;
    103     bool m_javascriptPrompt;
    104 };
    105 
    106 }
    107 
    108 static bool isDefinite(ProcessingUserGestureState state)
    109 {
    110     return state == DefinitelyProcessingNewUserGesture || state == DefinitelyProcessingUserGesture || state == DefinitelyNotProcessingUserGesture;
    111 }
    112 
    113 ProcessingUserGestureState UserGestureIndicator::s_state = DefinitelyNotProcessingUserGesture;
    114 UserGestureIndicator* UserGestureIndicator::s_topmostIndicator = 0;
    115 bool UserGestureIndicator::s_processedUserGestureSinceLoad = false;
    116 
    117 UserGestureIndicator::UserGestureIndicator(ProcessingUserGestureState state)
    118     : m_previousState(s_state)
    119 {
    120     // Silently ignore UserGestureIndicators on non-main threads.
    121     if (!isMainThread())
    122         return;
    123 
    124     // We overwrite s_state only if the caller is definite about the gesture state.
    125     if (isDefinite(state)) {
    126         if (!s_topmostIndicator) {
    127             s_topmostIndicator = this;
    128             m_token = GestureToken::create();
    129         } else {
    130             m_token = s_topmostIndicator->currentToken();
    131         }
    132         s_state = state;
    133     }
    134 
    135     if (state == DefinitelyProcessingNewUserGesture) {
    136         static_cast<GestureToken*>(m_token.get())->addGesture();
    137         s_processedUserGestureSinceLoad = true;
    138     } else if (state == DefinitelyProcessingUserGesture && s_topmostIndicator == this) {
    139         static_cast<GestureToken*>(m_token.get())->addGesture();
    140         s_processedUserGestureSinceLoad = true;
    141     }
    142     ASSERT(isDefinite(s_state));
    143 }
    144 
    145 UserGestureIndicator::UserGestureIndicator(PassRefPtr<UserGestureToken> token)
    146     : m_previousState(s_state)
    147 {
    148     // Silently ignore UserGestureIndicators on non-main threads.
    149     if (!isMainThread())
    150         return;
    151 
    152     if (token) {
    153         static_cast<GestureToken*>(token.get())->resetTimestamp();
    154         if (!s_topmostIndicator) {
    155             s_topmostIndicator = this;
    156             m_token = token;
    157         } else {
    158             m_token = s_topmostIndicator->currentToken();
    159             if (static_cast<GestureToken*>(token.get())->hasGestures()) {
    160                 static_cast<GestureToken*>(m_token.get())->addGesture();
    161                 static_cast<GestureToken*>(token.get())->consumeGesture();
    162             }
    163         }
    164         s_state = DefinitelyProcessingUserGesture;
    165     }
    166 
    167     ASSERT(isDefinite(s_state));
    168 }
    169 
    170 UserGestureIndicator::~UserGestureIndicator()
    171 {
    172     if (!isMainThread())
    173         return;
    174     s_state = m_previousState;
    175     if (s_topmostIndicator == this)
    176         s_topmostIndicator = 0;
    177     ASSERT(isDefinite(s_state));
    178 }
    179 
    180 bool UserGestureIndicator::processingUserGesture()
    181 {
    182     if (!isMainThread())
    183         return false;
    184     return s_topmostIndicator && static_cast<GestureToken*>(s_topmostIndicator->currentToken())->hasGestures() && (s_state == DefinitelyProcessingNewUserGesture || s_state == DefinitelyProcessingUserGesture);
    185 }
    186 
    187 bool UserGestureIndicator::consumeUserGesture()
    188 {
    189     if (!isMainThread() || !s_topmostIndicator)
    190         return false;
    191     return static_cast<GestureToken*>(s_topmostIndicator->currentToken())->consumeGesture();
    192 }
    193 
    194 UserGestureToken* UserGestureIndicator::currentToken()
    195 {
    196     if (!isMainThread() || !s_topmostIndicator)
    197         return 0;
    198     return s_topmostIndicator->m_token.get();
    199 }
    200 
    201 void UserGestureIndicator::clearProcessedUserGestureSinceLoad()
    202 {
    203     if (isMainThread())
    204         s_processedUserGestureSinceLoad = false;
    205 }
    206 
    207 bool UserGestureIndicator::processedUserGestureSinceLoad()
    208 {
    209     if (!isMainThread())
    210         return false;
    211     return s_processedUserGestureSinceLoad;
    212 }
    213 
    214 UserGestureIndicatorDisabler::UserGestureIndicatorDisabler()
    215     : m_savedState(UserGestureIndicator::s_state)
    216     , m_savedIndicator(UserGestureIndicator::s_topmostIndicator)
    217 {
    218     RELEASE_ASSERT(isMainThread());
    219     UserGestureIndicator::s_state = DefinitelyNotProcessingUserGesture;
    220     UserGestureIndicator::s_topmostIndicator = 0;
    221 }
    222 
    223 UserGestureIndicatorDisabler::~UserGestureIndicatorDisabler()
    224 {
    225     RELEASE_ASSERT(isMainThread());
    226     UserGestureIndicator::s_state = m_savedState;
    227     UserGestureIndicator::s_topmostIndicator = m_savedIndicator;
    228 }
    229 
    230 }
    231