| 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 |