Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(556)

Unified Diff: Source/modules/gamepad/NavigatorGamepad.cpp

Issue 306363002: Gamepad: honor page visibility (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: just a comment that it will be better with Oilpan Created 6 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « Source/modules/gamepad/NavigatorGamepad.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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
« no previous file with comments | « Source/modules/gamepad/NavigatorGamepad.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698