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 "UserGestureIndicator.h"
28
29#include "Document.h"
30#include "Frame.h"
31#include "ResourceLoadObserver.h"
32#include <wtf/MainThread.h>
33#include <wtf/NeverDestroyed.h>
34#include <wtf/Optional.h>
35
36namespace WebCore {
37
38static RefPtr<UserGestureToken>& currentToken()
39{
40 ASSERT(isMainThread());
41 static NeverDestroyed<RefPtr<UserGestureToken>> token;
42 return token;
43}
44
45UserGestureToken::~UserGestureToken()
46{
47 for (auto& observer : m_destructionObservers)
48 observer(*this);
49}
50
51UserGestureIndicator::UserGestureIndicator(Optional<ProcessingUserGestureState> state, Document* document, UserGestureType gestureType, ProcessInteractionStyle processInteractionStyle)
52 : m_previousToken { currentToken() }
53{
54 ASSERT(isMainThread());
55
56 if (state)
57 currentToken() = UserGestureToken::create(state.value(), gestureType);
58
59 if (document && currentToken()->processingUserGesture()) {
60 document->updateLastHandledUserGestureTimestamp(MonotonicTime::now());
61 if (processInteractionStyle == ProcessInteractionStyle::Immediate)
62 ResourceLoadObserver::shared().logUserInteractionWithReducedTimeResolution(document->topDocument());
63 document->topDocument().setUserDidInteractWithPage(true);
64 if (auto* frame = document->frame()) {
65 if (!frame->hasHadUserInteraction()) {
66 for (; frame; frame = frame->tree().parent())
67 frame->setHasHadUserInteraction();
68 }
69 }
70 }
71}
72
73UserGestureIndicator::UserGestureIndicator(RefPtr<UserGestureToken> token, UserGestureToken::GestureScope scope)
74{
75 // Silently ignore UserGestureIndicators on non main threads.
76 if (!isMainThread())
77 return;
78
79 // It is only safe to use currentToken() on the main thread.
80 m_previousToken = currentToken();
81
82 if (token) {
83 token->setScope(scope);
84 currentToken() = token;
85 }
86}
87
88UserGestureIndicator::~UserGestureIndicator()
89{
90 if (!isMainThread())
91 return;
92
93 if (auto token = currentToken()) {
94 token->resetDOMPasteAccess();
95 token->resetScope();
96 }
97
98 currentToken() = m_previousToken;
99}
100
101RefPtr<UserGestureToken> UserGestureIndicator::currentUserGesture()
102{
103 if (!isMainThread())
104 return nullptr;
105
106 return currentToken();
107}
108
109bool UserGestureIndicator::processingUserGesture()
110{
111 if (!isMainThread())
112 return false;
113
114 return currentToken() ? currentToken()->processingUserGesture() : false;
115}
116
117bool UserGestureIndicator::processingUserGestureForMedia()
118{
119 if (!isMainThread())
120 return false;
121
122 return currentToken() ? currentToken()->processingUserGestureForMedia() : false;
123}
124
125}
126