Unreviewed, fix build after r192848 and r192849
[WebKit-https.git] / Source / WebCore / Modules / gamepad / GamepadManager.cpp
1 /*
2  * Copyright (C) 2014 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 #include "config.h"
26 #include "GamepadManager.h"
27
28 #if ENABLE(GAMEPAD)
29
30 #include "DOMWindow.h"
31 #include "Document.h"
32 #include "Gamepad.h"
33 #include "GamepadEvent.h"
34 #include "GamepadProvider.h"
35 #include "Logging.h"
36 #include "NavigatorGamepad.h"
37 #include "PlatformGamepad.h"
38
39 namespace WebCore {
40
41 static NavigatorGamepad* navigatorGamepadFromDOMWindow(DOMWindow* window)
42 {
43     Navigator* navigator = window->navigator();
44     if (!navigator)
45         return nullptr;
46
47     return NavigatorGamepad::from(navigator);
48 }
49
50 GamepadManager& GamepadManager::singleton()
51 {
52     static NeverDestroyed<GamepadManager> sharedManager;
53     return sharedManager;
54 }
55
56 GamepadManager::GamepadManager()
57     : m_isMonitoringGamepads(false)
58 {
59 }
60
61 void GamepadManager::platformGamepadConnected(PlatformGamepad& platformGamepad)
62 {
63     // Notify blind Navigators and Windows about all gamepads except for this one.
64     for (auto* gamepad : GamepadProvider::singleton().platformGamepads()) {
65         if (!gamepad || gamepad == &platformGamepad)
66             continue;
67
68         makeGamepadVisible(*gamepad, m_gamepadBlindNavigators, m_gamepadBlindDOMWindows);
69     }
70
71     m_gamepadBlindNavigators.clear();
72     m_gamepadBlindDOMWindows.clear();
73
74     // Notify everyone of this new gamepad.
75     makeGamepadVisible(platformGamepad, m_navigators, m_domWindows);
76 }
77
78 void GamepadManager::platformGamepadDisconnected(PlatformGamepad& platformGamepad)
79 {
80     Vector<WeakPtr<DOMWindow>> weakWindows;
81     for (auto* domWindow : m_domWindows)
82         weakWindows.append(domWindow->createWeakPtr());
83
84     HashSet<NavigatorGamepad*> notifiedNavigators;
85
86     // Handle the disconnect for all DOMWindows with event listeners and their Navigators.
87     for (auto& window : weakWindows) {
88         // Event dispatch might have made this window go away.
89         if (!window)
90             continue;
91
92         // This DOMWindow's Navigator might not be accessible. e.g. The DOMWindow might be in the back/forward cache.
93         // If this happens the DOMWindow will not get this gamepaddisconnected event.
94         NavigatorGamepad* navigator = navigatorGamepadFromDOMWindow(window.get());
95         if (!navigator)
96             continue;
97
98         // If this Navigator hasn't seen gamepads yet then its Window should not get the disconnect event.
99         if (m_gamepadBlindNavigators.contains(navigator))
100             continue;
101
102         Ref<Gamepad> gamepad(navigator->gamepadFromPlatformGamepad(platformGamepad));
103
104         navigator->gamepadDisconnected(platformGamepad);
105         notifiedNavigators.add(navigator);
106
107         window->dispatchEvent(GamepadEvent::create(eventNames().gamepaddisconnectedEvent, gamepad.get()), window->document());
108     }
109
110     // Notify all the Navigators that haven't already been notified.
111     for (auto* navigator : m_navigators) {
112         if (!notifiedNavigators.contains(navigator))
113             navigator->gamepadDisconnected(platformGamepad);
114     }
115 }
116
117 void GamepadManager::platformGamepadInputActivity()
118 {
119     if (m_gamepadBlindNavigators.isEmpty() && m_gamepadBlindDOMWindows.isEmpty())
120         return;
121
122     for (auto* gamepad : GamepadProvider::singleton().platformGamepads())
123         makeGamepadVisible(*gamepad, m_gamepadBlindNavigators, m_gamepadBlindDOMWindows);
124
125     m_gamepadBlindNavigators.clear();
126     m_gamepadBlindDOMWindows.clear();
127 }
128
129 void GamepadManager::makeGamepadVisible(PlatformGamepad& platformGamepad, HashSet<NavigatorGamepad*>& navigatorSet, HashSet<DOMWindow*>& domWindowSet)
130 {
131     if (navigatorSet.isEmpty() && domWindowSet.isEmpty())
132         return;
133
134     for (auto* navigator : navigatorSet)
135         navigator->gamepadConnected(platformGamepad);
136
137     Vector<WeakPtr<DOMWindow>> weakWindows;
138     for (auto* domWindow : m_domWindows)
139         weakWindows.append(domWindow->createWeakPtr());
140
141     for (auto& window : weakWindows) {
142         // Event dispatch might have made this window go away.
143         if (!window)
144             continue;
145
146         // This DOMWindow's Navigator might not be accessible. e.g. The DOMWindow might be in the back/forward cache.
147         // If this happens the DOMWindow will not get this gamepadconnected event.
148         // The new gamepad will still be visibile to it once it is restored from the back/forward cache.
149         NavigatorGamepad* navigator = navigatorGamepadFromDOMWindow(window.get());
150         if (!navigator)
151             continue;
152
153         Ref<Gamepad> gamepad(navigator->gamepadFromPlatformGamepad(platformGamepad));
154         window->dispatchEvent(GamepadEvent::create(eventNames().gamepadconnectedEvent, gamepad.get()), window->document());
155     }
156 }
157
158 void GamepadManager::registerNavigator(NavigatorGamepad* navigator)
159 {
160     LOG(Gamepad, "GamepadManager registering NavigatorGamepad %p", navigator);
161
162     ASSERT(!m_navigators.contains(navigator));
163     m_navigators.add(navigator);
164     m_gamepadBlindNavigators.add(navigator);
165
166     maybeStartMonitoringGamepads();
167 }
168
169 void GamepadManager::unregisterNavigator(NavigatorGamepad* navigator)
170 {
171     LOG(Gamepad, "GamepadManager unregistering NavigatorGamepad %p", navigator);
172
173     ASSERT(m_navigators.contains(navigator));
174     m_navigators.remove(navigator);
175     m_gamepadBlindNavigators.remove(navigator);
176
177     maybeStopMonitoringGamepads();
178 }
179
180 void GamepadManager::registerDOMWindow(DOMWindow* window)
181 {
182     LOG(Gamepad, "GamepadManager registering DOMWindow %p", window);
183
184     ASSERT(!m_domWindows.contains(window));
185     m_domWindows.add(window);
186
187     // Anytime we register a DOMWindow, we should also double check that its NavigatorGamepad is registered.
188     NavigatorGamepad* navigator = navigatorGamepadFromDOMWindow(window);
189     ASSERT(navigator);
190
191     if (m_navigators.add(navigator).isNewEntry)
192         m_gamepadBlindNavigators.add(navigator);
193
194     // If this DOMWindow's NavigatorGamepad was already registered but was still blind,
195     // then this DOMWindow should be blind.
196     if (m_gamepadBlindNavigators.contains(navigator))
197         m_gamepadBlindDOMWindows.add(window);
198
199     maybeStartMonitoringGamepads();
200 }
201
202 void GamepadManager::unregisterDOMWindow(DOMWindow* window)
203 {
204     LOG(Gamepad, "GamepadManager unregistering DOMWindow %p", window);
205
206     ASSERT(m_domWindows.contains(window));
207     m_domWindows.remove(window);
208     m_gamepadBlindDOMWindows.remove(window);
209
210     maybeStopMonitoringGamepads();
211 }
212
213 void GamepadManager::maybeStartMonitoringGamepads()
214 {
215     if (m_isMonitoringGamepads)
216         return;
217
218     if (!m_navigators.isEmpty() || !m_domWindows.isEmpty()) {
219         LOG(Gamepad, "GamepadManager has %i NavigatorGamepads and %i DOMWindows registered, is starting gamepad monitoring", m_navigators.size(), m_domWindows.size());
220         m_isMonitoringGamepads = true;
221         GamepadProvider::singleton().startMonitoringGamepads(this);
222     }
223 }
224
225 void GamepadManager::maybeStopMonitoringGamepads()
226 {
227     if (!m_isMonitoringGamepads)
228         return;
229
230     if (m_navigators.isEmpty() && m_domWindows.isEmpty()) {
231         LOG(Gamepad, "GamepadManager has no NavigatorGamepads or DOMWindows registered, is stopping gamepad monitoring");
232         m_isMonitoringGamepads = false;
233         GamepadProvider::singleton().stopMonitoringGamepads(this);
234     }
235 }
236
237 } // namespace WebCore
238
239 #endif // ENABLE(GAMEPAD)