Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / modules / gamepad / NavigatorGamepad.cpp
index 4060f0c..37b2d01 100644 (file)
@@ -26,9 +26,8 @@
 #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);
@@ -54,20 +54,20 @@ static void sampleGamepad(unsigned index, T& gamepad, const blink::WebGamepad& w
 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);
         }
     }
 }
@@ -84,7 +84,7 @@ NavigatorGamepad& NavigatorGamepad::from(Navigator& navigator)
 {
     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;
@@ -102,19 +102,23 @@ GamepadList* NavigatorGamepad::getGamepads(Navigator& navigator)
 
 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();
 }
 
@@ -122,13 +126,13 @@ void NavigatorGamepad::trace(Visitor* visitor)
 {
     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());
 
@@ -139,29 +143,47 @@ void NavigatorGamepad::didConnectOrDisconnectGamepad(unsigned index, const blink
     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()
@@ -183,12 +205,14 @@ void NavigatorGamepad::willDetachGlobalObjectFromFrame()
 
 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()
@@ -197,38 +221,77 @@ 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