Home | History | Annotate | Download | only in dom
      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