#include "config.h"
#include "modules/gamepad/NavigatorGamepad.h"
-#include "RuntimeEnabledFeatures.h"
#include "core/dom/Document.h"
-#include "core/frame/DOMWindow.h"
+#include "core/frame/LocalDOMWindow.h"
#include "core/frame/LocalFrame.h"
#include "core/frame/Navigator.h"
#include "core/page/Page.h"
#include "modules/gamepad/GamepadEvent.h"
#include "modules/gamepad/GamepadList.h"
#include "modules/gamepad/WebKitGamepadList.h"
+#include "platform/RuntimeEnabledFeatures.h"
-namespace WebCore {
+namespace blink {
template<typename T>
-static void sampleGamepad(unsigned index, T& gamepad, const blink::WebGamepad& webGamepad)
+static void sampleGamepad(unsigned index, T& gamepad, const WebGamepad& webGamepad)
{
gamepad.setId(webGamepad.id);
gamepad.setIndex(index);
template<typename GamepadType, typename ListType>
static void sampleGamepads(ListType* into)
{
- blink::WebGamepads gamepads;
+ WebGamepads gamepads;
GamepadDispatcher::instance().sampleGamepads(gamepads);
- for (unsigned i = 0; i < blink::WebGamepads::itemsLengthCap; ++i) {
- blink::WebGamepad& webGamepad = gamepads.items[i];
+ for (unsigned i = 0; i < WebGamepads::itemsLengthCap; ++i) {
+ WebGamepad& webGamepad = gamepads.items[i];
if (i < gamepads.length && webGamepad.connected) {
- RefPtrWillBeRawPtr<GamepadType> gamepad = into->item(i);
+ GamepadType* gamepad = into->item(i);
if (!gamepad)
gamepad = GamepadType::create();
sampleGamepad(i, *gamepad, webGamepad);
into->set(i, gamepad);
} else {
- into->set(i, nullptr);
+ into->set(i, 0);
}
}
}
{
NavigatorGamepad* supplement = static_cast<NavigatorGamepad*>(WillBeHeapSupplement<Navigator>::from(navigator, supplementName()));
if (!supplement) {
- supplement = new NavigatorGamepad(*navigator.frame()->document());
+ supplement = new NavigatorGamepad(navigator.frame());
provideTo(navigator, supplementName(), adoptPtrWillBeNoop(supplement));
}
return *supplement;
WebKitGamepadList* NavigatorGamepad::webkitGamepads()
{
- startUpdating();
if (!m_webkitGamepads)
m_webkitGamepads = WebKitGamepadList::create();
- sampleGamepads<WebKitGamepad>(m_webkitGamepads.get());
+ if (window()) {
+ startUpdating();
+ sampleGamepads<WebKitGamepad>(m_webkitGamepads.get());
+ }
return m_webkitGamepads.get();
}
GamepadList* NavigatorGamepad::gamepads()
{
- startUpdating();
if (!m_gamepads)
m_gamepads = GamepadList::create();
- sampleGamepads<Gamepad>(m_gamepads.get());
+ if (window()) {
+ startUpdating();
+ sampleGamepads<Gamepad>(m_gamepads.get());
+ }
return m_gamepads.get();
}
{
visitor->trace(m_gamepads);
visitor->trace(m_webkitGamepads);
+ visitor->trace(m_pendingEvents);
+ WillBeHeapSupplement<Navigator>::trace(visitor);
+ DOMWindowProperty::trace(visitor);
}
-void NavigatorGamepad::didConnectOrDisconnectGamepad(unsigned index, const blink::WebGamepad& webGamepad, bool connected)
+void NavigatorGamepad::didUpdateData()
{
- ASSERT(index < blink::WebGamepads::itemsLengthCap);
- ASSERT(connected == webGamepad.connected);
-
// We should stop listening once we detached.
ASSERT(window());
if (window()->document()->activeDOMObjectsAreStopped() || window()->document()->activeDOMObjectsAreSuspended())
return;
+ const GamepadDispatcher::ConnectionChange& change = GamepadDispatcher::instance().latestConnectionChange();
+
if (!m_gamepads)
m_gamepads = GamepadList::create();
- RefPtrWillBeRawPtr<Gamepad> gamepad = m_gamepads->item(index);
+ Gamepad* gamepad = m_gamepads->item(change.index);
if (!gamepad)
gamepad = Gamepad::create();
- sampleGamepad(index, *gamepad, webGamepad);
- m_gamepads->set(index, gamepad);
+ sampleGamepad(change.index, *gamepad, change.pad);
+ m_gamepads->set(change.index, gamepad);
+
+ m_pendingEvents.append(gamepad);
+ m_dispatchOneEventRunner.runAsync();
+}
+
+void NavigatorGamepad::dispatchOneEvent()
+{
+ ASSERT(window());
+ ASSERT(!m_pendingEvents.isEmpty());
- const AtomicString& eventName = connected ? EventTypeNames::gamepadconnected : EventTypeNames::gamepaddisconnected;
- RefPtr<GamepadEvent> event = GamepadEvent::create(eventName, false, true, gamepad.get());
- window()->dispatchEvent(event);
+ Gamepad* gamepad = m_pendingEvents.takeFirst();
+ const AtomicString& eventName = gamepad->connected() ? EventTypeNames::gamepadconnected : EventTypeNames::gamepaddisconnected;
+ window()->dispatchEvent(GamepadEvent::create(eventName, false, true, gamepad));
+
+ if (!m_pendingEvents.isEmpty())
+ m_dispatchOneEventRunner.runAsync();
}
-NavigatorGamepad::NavigatorGamepad(Document& document)
- : DOMWindowProperty(document.frame())
- , DeviceSensorEventController(document)
- , DOMWindowLifecycleObserver(document.frame()->domWindow())
+NavigatorGamepad::NavigatorGamepad(LocalFrame* frame)
+ : DOMWindowProperty(frame)
+ , PlatformEventController(frame ? frame->page() : 0)
+ , DOMWindowLifecycleObserver(frame ? frame->domWindow() : 0)
+ , m_dispatchOneEventRunner(this, &NavigatorGamepad::dispatchOneEvent)
{
}
NavigatorGamepad::~NavigatorGamepad()
{
+#if ENABLE(OILPAN)
+ stopUpdating();
+#endif
}
const char* NavigatorGamepad::supplementName()
void NavigatorGamepad::registerWithDispatcher()
{
- GamepadDispatcher::instance().addClient(this);
+ GamepadDispatcher::instance().addController(this);
+ m_dispatchOneEventRunner.resume();
}
void NavigatorGamepad::unregisterWithDispatcher()
{
- GamepadDispatcher::instance().removeClient(this);
+ m_dispatchOneEventRunner.suspend();
+ GamepadDispatcher::instance().removeController(this);
}
bool NavigatorGamepad::hasLastData()
return false;
}
-PassRefPtr<Event> NavigatorGamepad::getLastEvent()
-{
- // This is called only when hasLastData() is true.
- ASSERT_NOT_REACHED();
- return nullptr;
-}
-
-bool NavigatorGamepad::isNullEvent(Event*)
+static bool isGamepadEvent(const AtomicString& eventType)
{
- // This is called only when hasLastData() is true.
- ASSERT_NOT_REACHED();
- return false;
+ return eventType == EventTypeNames::gamepadconnected || eventType == EventTypeNames::gamepaddisconnected;
}
-void NavigatorGamepad::didAddEventListener(DOMWindow*, const AtomicString& eventType)
+void NavigatorGamepad::didAddEventListener(LocalDOMWindow*, const AtomicString& eventType)
{
- if (RuntimeEnabledFeatures::gamepadEnabled() && (eventType == EventTypeNames::gamepadconnected || eventType == EventTypeNames::gamepaddisconnected)) {
+ if (RuntimeEnabledFeatures::gamepadEnabled() && isGamepadEvent(eventType)) {
if (page() && page()->visibilityState() == PageVisibilityStateVisible)
startUpdating();
m_hasEventListener = true;
}
}
-void NavigatorGamepad::didRemoveEventListener(DOMWindow*, const AtomicString& eventType)
+void NavigatorGamepad::didRemoveEventListener(LocalDOMWindow* window, const AtomicString& eventType)
{
- if (eventType == EventTypeNames::gamepadconnected || eventType == EventTypeNames::gamepaddisconnected)
- m_hasEventListener = false;
+ if (isGamepadEvent(eventType)
+ && !window->hasEventListeners(EventTypeNames::gamepadconnected)
+ && !window->hasEventListeners(EventTypeNames::gamepaddisconnected)) {
+ didRemoveGamepadEventListeners();
+ }
}
-void NavigatorGamepad::didRemoveAllEventListeners(DOMWindow*)
+void NavigatorGamepad::didRemoveAllEventListeners(LocalDOMWindow*)
+{
+ didRemoveGamepadEventListeners();
+}
+
+void NavigatorGamepad::didRemoveGamepadEventListeners()
{
m_hasEventListener = false;
+ m_dispatchOneEventRunner.stop();
+ m_pendingEvents.clear();
+}
+
+void NavigatorGamepad::pageVisibilityChanged()
+{
+ // Inform the embedder whether it needs to provide gamepad data for us.
+ bool visible = page()->visibilityState() == PageVisibilityStateVisible;
+ if (visible && (m_hasEventListener || m_gamepads || m_webkitGamepads))
+ startUpdating();
+ else
+ stopUpdating();
+
+ if (!visible || !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);
+
+ for (unsigned i = 0; i < 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)) {
+ oldGamepad->setConnected(false);
+ m_pendingEvents.append(oldGamepad);
+ }
+ if (connectedGamepadChanged || (!oldWasConnected && newIsConnected)) {
+ m_pendingEvents.append(newGamepad);
+ }
+ }
+
+ if (!m_pendingEvents.isEmpty())
+ m_dispatchOneEventRunner.runAsync();
}
-} // namespace WebCore
+} // namespace blink