OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2011, Google Inc. All rights reserved. | 2 * Copyright (C) 2011, Google Inc. All rights reserved. |
3 * | 3 * |
4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
5 * modification, are permitted provided that the following conditions are met: | 5 * modification, are permitted provided that the following conditions are met: |
6 * | 6 * |
7 * 1. Redistributions of source code must retain the above copyright | 7 * 1. Redistributions of source code must retain the above copyright |
8 * notice, this list of conditions and the following disclaimer. | 8 * notice, this list of conditions and the following disclaimer. |
9 * 2. Redistributions in binary form must reproduce the above copyright | 9 * 2. Redistributions in binary form must reproduce the above copyright |
10 * notice, this list of conditions and the following disclaimer in the | 10 * notice, this list of conditions and the following disclaimer in the |
(...skipping 18 matching lines...) Expand all Loading... |
29 #include "RuntimeEnabledFeatures.h" | 29 #include "RuntimeEnabledFeatures.h" |
30 #include "core/dom/Document.h" | 30 #include "core/dom/Document.h" |
31 #include "core/frame/DOMWindow.h" | 31 #include "core/frame/DOMWindow.h" |
32 #include "core/frame/LocalFrame.h" | 32 #include "core/frame/LocalFrame.h" |
33 #include "core/frame/Navigator.h" | 33 #include "core/frame/Navigator.h" |
34 #include "core/page/Page.h" | 34 #include "core/page/Page.h" |
35 #include "modules/gamepad/GamepadDispatcher.h" | 35 #include "modules/gamepad/GamepadDispatcher.h" |
36 #include "modules/gamepad/GamepadEvent.h" | 36 #include "modules/gamepad/GamepadEvent.h" |
37 #include "modules/gamepad/GamepadList.h" | 37 #include "modules/gamepad/GamepadList.h" |
38 #include "modules/gamepad/WebKitGamepadList.h" | 38 #include "modules/gamepad/WebKitGamepadList.h" |
| 39 #include "wtf/TemporaryChange.h" |
39 | 40 |
40 namespace WebCore { | 41 namespace WebCore { |
41 | 42 |
42 template<typename T> | 43 template<typename T> |
43 static void sampleGamepad(unsigned index, T& gamepad, const blink::WebGamepad& w
ebGamepad) | 44 static void sampleGamepad(unsigned index, T& gamepad, const blink::WebGamepad& w
ebGamepad) |
44 { | 45 { |
45 gamepad.setId(webGamepad.id); | 46 gamepad.setId(webGamepad.id); |
46 gamepad.setIndex(index); | 47 gamepad.setIndex(index); |
47 gamepad.setConnected(webGamepad.connected); | 48 gamepad.setConnected(webGamepad.connected); |
48 gamepad.setTimestamp(webGamepad.timestamp); | 49 gamepad.setTimestamp(webGamepad.timestamp); |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
127 visitor->trace(m_gamepads); | 128 visitor->trace(m_gamepads); |
128 visitor->trace(m_webkitGamepads); | 129 visitor->trace(m_webkitGamepads); |
129 WillBeHeapSupplement<Navigator>::trace(visitor); | 130 WillBeHeapSupplement<Navigator>::trace(visitor); |
130 } | 131 } |
131 | 132 |
132 void NavigatorGamepad::didConnectOrDisconnectGamepad(unsigned index, const blink
::WebGamepad& webGamepad, bool connected) | 133 void NavigatorGamepad::didConnectOrDisconnectGamepad(unsigned index, const blink
::WebGamepad& webGamepad, bool connected) |
133 { | 134 { |
134 ASSERT(index < blink::WebGamepads::itemsLengthCap); | 135 ASSERT(index < blink::WebGamepads::itemsLengthCap); |
135 ASSERT(connected == webGamepad.connected); | 136 ASSERT(connected == webGamepad.connected); |
136 | 137 |
137 // We should stop listening once we detached. | |
138 ASSERT(window()); | |
139 | |
140 // We register to the dispatcher before sampling gamepads so we need to chec
k if we actually have an event listener. | 138 // We register to the dispatcher before sampling gamepads so we need to chec
k if we actually have an event listener. |
141 if (!m_hasEventListener) | 139 if (!m_hasEventListener) |
142 return; | 140 return; |
143 | 141 |
144 if (window()->document()->activeDOMObjectsAreStopped() || window()->document
()->activeDOMObjectsAreSuspended()) | |
145 return; | |
146 | |
147 if (!m_gamepads) | 142 if (!m_gamepads) |
148 m_gamepads = GamepadList::create(); | 143 m_gamepads = GamepadList::create(); |
149 | 144 |
150 Gamepad* gamepad = m_gamepads->item(index); | 145 Gamepad* gamepad = m_gamepads->item(index); |
151 if (!gamepad) | 146 if (!gamepad) |
152 gamepad = Gamepad::create(); | 147 gamepad = Gamepad::create(); |
153 sampleGamepad(index, *gamepad, webGamepad); | 148 sampleGamepad(index, *gamepad, webGamepad); |
154 m_gamepads->set(index, gamepad); | 149 m_gamepads->set(index, gamepad); |
155 | 150 |
156 const AtomicString& eventName = connected ? EventTypeNames::gamepadconnected
: EventTypeNames::gamepaddisconnected; | 151 const AtomicString& eventName = connected ? EventTypeNames::gamepadconnected
: EventTypeNames::gamepaddisconnected; |
157 RefPtrWillBeRawPtr<GamepadEvent> event = GamepadEvent::create(eventName, fal
se, true, gamepad); | 152 dispatchDeviceEvent(GamepadEvent::create(eventName, false, true, gamepad)); |
158 window()->dispatchEvent(event); | |
159 } | 153 } |
160 | 154 |
161 NavigatorGamepad::NavigatorGamepad(LocalFrame* frame) | 155 NavigatorGamepad::NavigatorGamepad(LocalFrame* frame) |
162 : DOMWindowProperty(frame) | 156 : DOMWindowProperty(frame) |
163 , DeviceSensorEventController(frame ? frame->page() : 0) | 157 , DeviceSensorEventController(frame ? frame->page() : 0) |
164 , DOMWindowLifecycleObserver(frame ? frame->domWindow() : 0) | 158 , DOMWindowLifecycleObserver(frame ? frame->domWindow() : 0) |
| 159 , m_canContinueDispatchingSentinelPtr(0) |
165 { | 160 { |
166 } | 161 } |
167 | 162 |
168 NavigatorGamepad::~NavigatorGamepad() | 163 NavigatorGamepad::~NavigatorGamepad() |
169 { | 164 { |
170 } | 165 } |
171 | 166 |
172 const char* NavigatorGamepad::supplementName() | 167 const char* NavigatorGamepad::supplementName() |
173 { | 168 { |
174 return "NavigatorGamepad"; | 169 return "NavigatorGamepad"; |
175 } | 170 } |
176 | 171 |
177 void NavigatorGamepad::willDestroyGlobalObjectInFrame() | 172 void NavigatorGamepad::willDestroyGlobalObjectInFrame() |
178 { | 173 { |
179 stopUpdating(); | 174 stopUpdating(); |
| 175 invalidateCanContinueDispatchingSentinel(); |
180 DOMWindowProperty::willDestroyGlobalObjectInFrame(); | 176 DOMWindowProperty::willDestroyGlobalObjectInFrame(); |
181 } | 177 } |
182 | 178 |
183 void NavigatorGamepad::willDetachGlobalObjectFromFrame() | 179 void NavigatorGamepad::willDetachGlobalObjectFromFrame() |
184 { | 180 { |
185 stopUpdating(); | 181 stopUpdating(); |
| 182 invalidateCanContinueDispatchingSentinel(); |
186 DOMWindowProperty::willDetachGlobalObjectFromFrame(); | 183 DOMWindowProperty::willDetachGlobalObjectFromFrame(); |
187 } | 184 } |
188 | 185 |
189 void NavigatorGamepad::registerWithDispatcher() | 186 void NavigatorGamepad::registerWithDispatcher() |
190 { | 187 { |
191 GamepadDispatcher::instance().addClient(this); | 188 GamepadDispatcher::instance().addClient(this); |
192 } | 189 } |
193 | 190 |
194 void NavigatorGamepad::unregisterWithDispatcher() | 191 void NavigatorGamepad::unregisterWithDispatcher() |
195 { | 192 { |
196 GamepadDispatcher::instance().removeClient(this); | 193 GamepadDispatcher::instance().removeClient(this); |
197 } | 194 } |
198 | 195 |
199 bool NavigatorGamepad::hasLastData() | 196 bool NavigatorGamepad::hasLastData() |
200 { | 197 { |
201 // Gamepad data is polled instead of pushed. | 198 // Gamepad data is polled instead of pushed. |
202 return false; | 199 return false; |
203 } | 200 } |
204 | 201 |
205 PassRefPtrWillBeRawPtr<Event> NavigatorGamepad::getLastEvent() | 202 PassRefPtrWillBeRawPtr<Event> NavigatorGamepad::getLastEvent() |
206 { | 203 { |
207 // This is called only when hasLastData() is true. | 204 // This is called only when hasLastData() is true. |
208 ASSERT_NOT_REACHED(); | 205 ASSERT_NOT_REACHED(); |
209 return nullptr; | 206 return nullptr; |
210 } | 207 } |
211 | 208 |
212 bool NavigatorGamepad::isNullEvent(Event*) | 209 bool NavigatorGamepad::isNullEvent(Event*) |
213 { | 210 { |
214 // This is called only when hasLastData() is true. | |
215 ASSERT_NOT_REACHED(); | |
216 return false; | 211 return false; |
217 } | 212 } |
218 | 213 |
219 Document* NavigatorGamepad::document() | 214 Document* NavigatorGamepad::document() |
220 { | 215 { |
221 return window() ? window()->document() : 0; | 216 return window() ? window()->document() : 0; |
222 } | 217 } |
223 | 218 |
224 static bool isGamepadEvent(const AtomicString& eventType) | 219 static bool isGamepadEvent(const AtomicString& eventType) |
225 { | 220 { |
226 return eventType == EventTypeNames::gamepadconnected || eventType == EventTy
peNames::gamepaddisconnected; | 221 return eventType == EventTypeNames::gamepadconnected || eventType == EventTy
peNames::gamepaddisconnected; |
227 } | 222 } |
228 | 223 |
229 void NavigatorGamepad::didAddEventListener(DOMWindow*, const AtomicString& event
Type) | 224 void NavigatorGamepad::didAddEventListener(DOMWindow*, const AtomicString& event
Type) |
230 { | 225 { |
231 if (RuntimeEnabledFeatures::gamepadEnabled() && isGamepadEvent(eventType)) { | 226 if (RuntimeEnabledFeatures::gamepadEnabled() && isGamepadEvent(eventType)) { |
232 if (page() && page()->visibilityState() == PageVisibilityStateVisible) | 227 if (page() && page()->visibilityState() == PageVisibilityStateVisible) |
233 startUpdating(); | 228 startUpdating(); |
234 m_hasEventListener = true; | 229 m_hasEventListener = true; |
235 } | 230 } |
236 } | 231 } |
237 | 232 |
238 void NavigatorGamepad::didRemoveEventListener(DOMWindow*, const AtomicString& ev
entType) | 233 void NavigatorGamepad::didRemoveEventListener(DOMWindow* window, const AtomicStr
ing& eventType) |
239 { | 234 { |
240 if (isGamepadEvent(eventType)) | 235 if (!isGamepadEvent(eventType) || window->hasEventListeners(EventTypeNames::
gamepadconnected) || window->hasEventListeners(EventTypeNames::gamepaddisconnect
ed)) |
241 m_hasEventListener = false; | 236 return; |
| 237 m_hasEventListener = false; |
242 } | 238 } |
243 | 239 |
244 void NavigatorGamepad::didRemoveAllEventListeners(DOMWindow*) | 240 void NavigatorGamepad::didRemoveAllEventListeners(DOMWindow*) |
245 { | 241 { |
246 m_hasEventListener = false; | 242 m_hasEventListener = false; |
247 } | 243 } |
248 | 244 |
| 245 void NavigatorGamepad::willBeDestroyed() |
| 246 { |
| 247 invalidateCanContinueDispatchingSentinel(); |
| 248 } |
| 249 |
| 250 void NavigatorGamepad::pageVisibilityChanged() |
| 251 { |
| 252 DeviceSensorEventController::pageVisibilityChanged(); |
| 253 |
| 254 if (page()->visibilityState() != PageVisibilityStateVisible || !m_hasEventLi
stener) |
| 255 return; |
| 256 |
| 257 // Tell the page what has changed. m_gamepads contains the state before we b
ecame hidden. |
| 258 // We create a new snapshot and compare them. |
| 259 GamepadList* oldGamepads = m_gamepads.release(); |
| 260 gamepads(); |
| 261 GamepadList* newGamepads = m_gamepads.get(); |
| 262 ASSERT(newGamepads); |
| 263 |
| 264 // Set m_gamepads to null so that if we are polled while dispatching it does
n't mess up our snapshot. |
| 265 // After we are done, set it back to the new snapshot otherwise we could rep
ort these changes multiple |
| 266 // times after we go hidden and then visible again. |
| 267 WTF::TemporaryChange<PersistentWillBeMember<GamepadList> > padsScope(m_gamep
ads, nullptr); |
| 268 |
| 269 // We need to dispatch multiple events to the page and we have to deal with
the fact that we can be destroyed by the event handler. |
| 270 // We use a fancy version of the protecting RefPtr idiom because Supplement'
s are not RefCounted. Before we die we change the value |
| 271 // of a local variable via our member pointer. After dispatching the event w
e check this local variable which is safe even if we have died. |
| 272 // TODO(b.kelemen): simplify this when we can rely on Oilpan. |
| 273 bool canContinueDispatchingSentinel = true; |
| 274 WTF::TemporaryChange<bool*> sentinelScope(m_canContinueDispatchingSentinelPt
r, &canContinueDispatchingSentinel); |
| 275 |
| 276 for (unsigned i = 0; i < blink::WebGamepads::itemsLengthCap; ++i) { |
| 277 Gamepad* oldGamepad = oldGamepads ? oldGamepads->item(i) : 0; |
| 278 Gamepad* newGamepad = newGamepads->item(i); |
| 279 bool oldWasConnected = oldGamepad && oldGamepad->connected(); |
| 280 bool newIsConnected = newGamepad && newGamepad->connected(); |
| 281 bool connectedGamepadChanged = oldWasConnected && newIsConnected && oldG
amepad->id() != newGamepad->id(); |
| 282 |
| 283 if (connectedGamepadChanged || (oldWasConnected && !newIsConnected)) { |
| 284 const AtomicString& eventName = EventTypeNames::gamepaddisconnected; |
| 285 dispatchDeviceEvent(GamepadEvent::create(eventName, false, true, old
Gamepad)); |
| 286 if (!canContinueDispatchingSentinel || !m_hasEventListener) |
| 287 return; |
| 288 } |
| 289 if (connectedGamepadChanged || (!oldWasConnected && newIsConnected)) { |
| 290 const AtomicString& eventName = EventTypeNames::gamepadconnected; |
| 291 dispatchDeviceEvent(GamepadEvent::create(eventName, false, true, new
Gamepad)); |
| 292 if (!canContinueDispatchingSentinel || !m_hasEventListener) |
| 293 return; |
| 294 } |
| 295 } |
| 296 } |
| 297 |
| 298 void NavigatorGamepad::invalidateCanContinueDispatchingSentinel() |
| 299 { |
| 300 if (m_canContinueDispatchingSentinelPtr) |
| 301 *m_canContinueDispatchingSentinelPtr = false; |
| 302 } |
| 303 |
249 } // namespace WebCore | 304 } // namespace WebCore |
OLD | NEW |