2046bf9073931ee3b8ff34ddc294343a39110546
[WebKit-https.git] / Source / WebKit2 / UIProcess / Gamepad / UIGamepadProvider.cpp
1 /*
2  * Copyright (C) 2016 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 "UIGamepadProvider.h"
28
29 #if ENABLE(GAMEPAD)
30
31 #include "GamepadData.h"
32 #include "UIGamepad.h"
33 #include "WebProcessPool.h"
34 #include <WebCore/HIDGamepadProvider.h>
35 #include <wtf/NeverDestroyed.h>
36
37 using namespace WebCore;
38
39 namespace WebKit {
40
41 static const double maximumGamepadUpdateInterval = 1 / 120.0;
42
43 UIGamepadProvider& UIGamepadProvider::singleton()
44 {
45     static NeverDestroyed<UIGamepadProvider> sharedProvider;
46     return sharedProvider;
47 }
48
49 UIGamepadProvider::UIGamepadProvider()
50     : m_gamepadSyncTimer(RunLoop::main(), this, &UIGamepadProvider::gamepadSyncTimerFired)
51 {
52 }
53
54 UIGamepadProvider::~UIGamepadProvider()
55 {
56     if (!m_processPoolsUsingGamepads.isEmpty())
57         platformStopMonitoringGamepads();
58 }
59
60 void UIGamepadProvider::gamepadSyncTimerFired()
61 {
62     auto webPageProxy = platformWebPageProxyForGamepadInput();
63     if (!webPageProxy || !m_processPoolsUsingGamepads.contains(&webPageProxy->process().processPool()))
64         return;
65
66     webPageProxy->gamepadActivity(snapshotGamepads());
67 }
68
69 void UIGamepadProvider::scheduleGamepadStateSync()
70 {
71     if (!m_isMonitoringGamepads || m_gamepadSyncTimer.isActive())
72         return;
73
74     if (m_gamepads.isEmpty() || m_processPoolsUsingGamepads.isEmpty()) {
75         m_gamepadSyncTimer.stop();
76         return;
77     }
78
79     m_gamepadSyncTimer.startOneShot(maximumGamepadUpdateInterval);
80 }
81
82 void UIGamepadProvider::setInitialConnectedGamepads(const Vector<PlatformGamepad*>& initialGamepads)
83 {
84     ASSERT(!m_hasInitialGamepads);
85
86     m_gamepads.resize(initialGamepads.size());
87
88     for (auto* gamepad : initialGamepads) {
89         if (!gamepad)
90             continue;
91         m_gamepads[gamepad->index()] = std::make_unique<UIGamepad>(*gamepad);
92     }
93
94     for (auto& pool : m_processPoolsUsingGamepads)
95         pool->setInitialConnectedGamepads(m_gamepads);
96
97     m_hasInitialGamepads = true;
98 }
99
100 void UIGamepadProvider::platformGamepadConnected(PlatformGamepad& gamepad)
101 {
102     if (m_gamepads.size() <= gamepad.index())
103         m_gamepads.resize(gamepad.index() + 1);
104
105     ASSERT(!m_gamepads[gamepad.index()]);
106     m_gamepads[gamepad.index()] = std::make_unique<UIGamepad>(gamepad);
107
108     scheduleGamepadStateSync();
109
110     for (auto& pool : m_processPoolsUsingGamepads)
111         pool->gamepadConnected(*m_gamepads[gamepad.index()]);
112 }
113
114 void UIGamepadProvider::platformGamepadDisconnected(PlatformGamepad& gamepad)
115 {
116     ASSERT(gamepad.index() < m_gamepads.size());
117     ASSERT(m_gamepads[gamepad.index()]);
118
119     std::unique_ptr<UIGamepad> disconnectedGamepad = WTFMove(m_gamepads[gamepad.index()]);
120
121     scheduleGamepadStateSync();
122
123     for (auto& pool : m_processPoolsUsingGamepads)
124         pool->gamepadDisconnected(*disconnectedGamepad);
125 }
126
127 void UIGamepadProvider::platformGamepadInputActivity()
128 {
129     auto platformGamepads = this->platformGamepads();
130     ASSERT(platformGamepads.size() == m_gamepads.size());
131
132     for (size_t i = 0; i < platformGamepads.size(); ++i) {
133         if (!platformGamepads[i]) {
134             ASSERT(!m_gamepads[i]);
135             continue;
136         }
137
138         ASSERT(m_gamepads[i]);
139         m_gamepads[i]->updateFromPlatformGamepad(*platformGamepads[i]);
140     }
141
142     scheduleGamepadStateSync();
143 }
144
145 void UIGamepadProvider::processPoolStartedUsingGamepads(WebProcessPool& pool)
146 {
147     ASSERT(!m_processPoolsUsingGamepads.contains(&pool));
148     m_processPoolsUsingGamepads.add(&pool);
149
150     if (!m_isMonitoringGamepads && platformWebPageProxyForGamepadInput())
151         startMonitoringGamepads();
152
153     scheduleGamepadStateSync();
154 }
155
156 void UIGamepadProvider::processPoolStoppedUsingGamepads(WebProcessPool& pool)
157 {
158     ASSERT(m_processPoolsUsingGamepads.contains(&pool));
159     m_processPoolsUsingGamepads.remove(&pool);
160
161     if (m_isMonitoringGamepads && !platformWebPageProxyForGamepadInput())
162         platformStopMonitoringInput();
163
164     scheduleGamepadStateSync();
165 }
166
167 void UIGamepadProvider::viewBecameActive(WebPageProxy& page)
168 {
169     if (!m_processPoolsUsingGamepads.contains(&page.process().processPool()))
170         return;
171
172     if (!m_isMonitoringGamepads)
173         startMonitoringGamepads();
174
175     if (platformWebPageProxyForGamepadInput())
176         platformStartMonitoringInput();
177 }
178
179 void UIGamepadProvider::viewBecameInactive(WebPageProxy& page)
180 {
181     auto pageForGamepadInput = platformWebPageProxyForGamepadInput();
182     if (pageForGamepadInput == &page)
183         platformStopMonitoringInput();
184 }
185
186 void UIGamepadProvider::startMonitoringGamepads()
187 {
188     if (m_isMonitoringGamepads)
189         return;
190
191     m_isMonitoringGamepads = true;
192     platformStartMonitoringGamepads();
193 }
194
195 void UIGamepadProvider::stopMonitoringGamepads()
196 {
197     if (!m_isMonitoringGamepads)
198         return;
199
200     m_isMonitoringGamepads = false;
201     platformStopMonitoringGamepads();
202     m_gamepads.clear();
203 }
204
205 Vector<GamepadData> UIGamepadProvider::snapshotGamepads()
206 {
207     Vector<GamepadData> gamepadDatas;
208     gamepadDatas.reserveInitialCapacity(m_gamepads.size());
209
210     for (auto& gamepad : m_gamepads) {
211         if (gamepad)
212             gamepadDatas.uncheckedAppend(gamepad->gamepadData());
213         else
214             gamepadDatas.uncheckedAppend({ });
215     }
216
217     return gamepadDatas;
218 }
219
220 #if !PLATFORM(MAC)
221
222 void UIGamepadProvider::platformStartMonitoringGamepads()
223 {
224     // FIXME: Implement for other platforms
225 }
226
227 void UIGamepadProvider::platformStopMonitoringGamepads()
228 {
229     // FIXME: Implement for other platforms
230 }
231
232 const Vector<PlatformGamepad*>& UIGamepadProvider::platformGamepads()
233 {
234     static NeverDestroyed<Vector<PlatformGamepad*>> emptyGamepads;
235     return emptyGamepads;
236
237     // FIXME: Implement for other platforms
238 }
239
240 WebProcessProxy* UIGamepadProvider::platformWebProcessProxyForGamepadInput()
241 {
242     // FIXME: Implement for other platforms
243 }
244
245 void UIGamepadProvider::platformStopMonitoringInput()
246 {
247 }
248
249 void UIGamepadProvider::platformStartMonitoringInput()
250 {
251 }
252
253 #endif // !PLATFORM(MAC)
254
255 }
256
257 #endif // ENABLE(GAMEPAD)