| Index: Source/modules/gamepad/NavigatorGamepad.cpp
|
| diff --git a/Source/modules/gamepad/NavigatorGamepad.cpp b/Source/modules/gamepad/NavigatorGamepad.cpp
|
| index d1c006ef9a76fdb2b6725626b327a8a675a79c49..38ac468eaba9b6ade51f98a4ea237bd53467cb01 100644
|
| --- a/Source/modules/gamepad/NavigatorGamepad.cpp
|
| +++ b/Source/modules/gamepad/NavigatorGamepad.cpp
|
| @@ -36,6 +36,7 @@
|
| #include "modules/gamepad/GamepadEvent.h"
|
| #include "modules/gamepad/GamepadList.h"
|
| #include "modules/gamepad/WebKitGamepadList.h"
|
| +#include "wtf/TemporaryChange.h"
|
|
|
| namespace WebCore {
|
|
|
| @@ -134,16 +135,10 @@ void NavigatorGamepad::didConnectOrDisconnectGamepad(unsigned index, const blink
|
| ASSERT(index < blink::WebGamepads::itemsLengthCap);
|
| ASSERT(connected == webGamepad.connected);
|
|
|
| - // We should stop listening once we detached.
|
| - ASSERT(window());
|
| -
|
| // We register to the dispatcher before sampling gamepads so we need to check if we actually have an event listener.
|
| if (!m_hasEventListener)
|
| return;
|
|
|
| - if (window()->document()->activeDOMObjectsAreStopped() || window()->document()->activeDOMObjectsAreSuspended())
|
| - return;
|
| -
|
| if (!m_gamepads)
|
| m_gamepads = GamepadList::create();
|
|
|
| @@ -154,14 +149,14 @@ void NavigatorGamepad::didConnectOrDisconnectGamepad(unsigned index, const blink
|
| m_gamepads->set(index, gamepad);
|
|
|
| const AtomicString& eventName = connected ? EventTypeNames::gamepadconnected : EventTypeNames::gamepaddisconnected;
|
| - RefPtrWillBeRawPtr<GamepadEvent> event = GamepadEvent::create(eventName, false, true, gamepad);
|
| - window()->dispatchEvent(event);
|
| + dispatchDeviceEvent(GamepadEvent::create(eventName, false, true, gamepad));
|
| }
|
|
|
| NavigatorGamepad::NavigatorGamepad(LocalFrame* frame)
|
| : DOMWindowProperty(frame)
|
| , DeviceSensorEventController(frame ? frame->page() : 0)
|
| , DOMWindowLifecycleObserver(frame ? frame->domWindow() : 0)
|
| + , m_canContinueDispatchingSentinelPtr(0)
|
| {
|
| }
|
|
|
| @@ -177,12 +172,14 @@ const char* NavigatorGamepad::supplementName()
|
| void NavigatorGamepad::willDestroyGlobalObjectInFrame()
|
| {
|
| stopUpdating();
|
| + invalidateCanContinueDispatchingSentinel();
|
| DOMWindowProperty::willDestroyGlobalObjectInFrame();
|
| }
|
|
|
| void NavigatorGamepad::willDetachGlobalObjectFromFrame()
|
| {
|
| stopUpdating();
|
| + invalidateCanContinueDispatchingSentinel();
|
| DOMWindowProperty::willDetachGlobalObjectFromFrame();
|
| }
|
|
|
| @@ -211,8 +208,6 @@ PassRefPtrWillBeRawPtr<Event> NavigatorGamepad::getLastEvent()
|
|
|
| bool NavigatorGamepad::isNullEvent(Event*)
|
| {
|
| - // This is called only when hasLastData() is true.
|
| - ASSERT_NOT_REACHED();
|
| return false;
|
| }
|
|
|
| @@ -235,10 +230,11 @@ void NavigatorGamepad::didAddEventListener(DOMWindow*, const AtomicString& event
|
| }
|
| }
|
|
|
| -void NavigatorGamepad::didRemoveEventListener(DOMWindow*, const AtomicString& eventType)
|
| +void NavigatorGamepad::didRemoveEventListener(DOMWindow* window, const AtomicString& eventType)
|
| {
|
| - if (isGamepadEvent(eventType))
|
| - m_hasEventListener = false;
|
| + if (!isGamepadEvent(eventType) || window->hasEventListeners(EventTypeNames::gamepadconnected) || window->hasEventListeners(EventTypeNames::gamepaddisconnected))
|
| + return;
|
| + m_hasEventListener = false;
|
| }
|
|
|
| void NavigatorGamepad::didRemoveAllEventListeners(DOMWindow*)
|
| @@ -246,4 +242,63 @@ void NavigatorGamepad::didRemoveAllEventListeners(DOMWindow*)
|
| m_hasEventListener = false;
|
| }
|
|
|
| +void NavigatorGamepad::willBeDestroyed()
|
| +{
|
| + invalidateCanContinueDispatchingSentinel();
|
| +}
|
| +
|
| +void NavigatorGamepad::pageVisibilityChanged()
|
| +{
|
| + DeviceSensorEventController::pageVisibilityChanged();
|
| +
|
| + if (page()->visibilityState() != PageVisibilityStateVisible || !m_hasEventListener)
|
| + return;
|
| +
|
| + // Tell the page what has changed. m_gamepads contains the state before we became hidden.
|
| + // We create a new snapshot and compare them.
|
| + GamepadList* oldGamepads = m_gamepads.release();
|
| + gamepads();
|
| + GamepadList* newGamepads = m_gamepads.get();
|
| + ASSERT(newGamepads);
|
| +
|
| + // Set m_gamepads to null so that if we are polled while dispatching it doesn't mess up our snapshot.
|
| + // After we are done, set it back to the new snapshot otherwise we could report these changes multiple
|
| + // times after we go hidden and then visible again.
|
| + WTF::TemporaryChange<PersistentWillBeMember<GamepadList> > padsScope(m_gamepads, nullptr);
|
| +
|
| + // 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.
|
| + // We use a fancy version of the protecting RefPtr idiom because Supplement's are not RefCounted. Before we die we change the value
|
| + // of a local variable via our member pointer. After dispatching the event we check this local variable which is safe even if we have died.
|
| + // TODO(b.kelemen): simplify this when we can rely on Oilpan.
|
| + bool canContinueDispatchingSentinel = true;
|
| + WTF::TemporaryChange<bool*> sentinelScope(m_canContinueDispatchingSentinelPtr, &canContinueDispatchingSentinel);
|
| +
|
| + for (unsigned i = 0; i < blink::WebGamepads::itemsLengthCap; ++i) {
|
| + Gamepad* oldGamepad = oldGamepads ? oldGamepads->item(i) : 0;
|
| + Gamepad* newGamepad = newGamepads->item(i);
|
| + bool oldWasConnected = oldGamepad && oldGamepad->connected();
|
| + bool newIsConnected = newGamepad && newGamepad->connected();
|
| + bool connectedGamepadChanged = oldWasConnected && newIsConnected && oldGamepad->id() != newGamepad->id();
|
| +
|
| + if (connectedGamepadChanged || (oldWasConnected && !newIsConnected)) {
|
| + const AtomicString& eventName = EventTypeNames::gamepaddisconnected;
|
| + dispatchDeviceEvent(GamepadEvent::create(eventName, false, true, oldGamepad));
|
| + if (!canContinueDispatchingSentinel || !m_hasEventListener)
|
| + return;
|
| + }
|
| + if (connectedGamepadChanged || (!oldWasConnected && newIsConnected)) {
|
| + const AtomicString& eventName = EventTypeNames::gamepadconnected;
|
| + dispatchDeviceEvent(GamepadEvent::create(eventName, false, true, newGamepad));
|
| + if (!canContinueDispatchingSentinel || !m_hasEventListener)
|
| + return;
|
| + }
|
| + }
|
| +}
|
| +
|
| +void NavigatorGamepad::invalidateCanContinueDispatchingSentinel()
|
| +{
|
| + if (m_canContinueDispatchingSentinelPtr)
|
| + *m_canContinueDispatchingSentinelPtr = false;
|
| +}
|
| +
|
| } // namespace WebCore
|
|
|