Bug 1358064 - Simplify Gamepad Event processing; r=daoshengmu
authorChih-Yi Leu <cleu@mozilla.com>
Fri, 21 Apr 2017 11:34:30 +0800
changeset 391186 2981a5649a3a14a6c6034efa3a79754e811bef09
parent 391185 d3261993daa1437b49fe72a806cecc4090f242ed
child 391187 a208e1be391020ad135d5dc3add7fd08184cd341
push id53
push userfmarier@mozilla.com
push dateMon, 15 May 2017 17:28:28 +0000
reviewersdaoshengmu
bugs1358064
milestone55.0a1
Bug 1358064 - Simplify Gamepad Event processing; r=daoshengmu MozReview-Commit-ID: 6CLyWx5w5Qu
dom/gamepad/GamepadManager.cpp
dom/gamepad/GamepadManager.h
--- a/dom/gamepad/GamepadManager.cpp
+++ b/dom/gamepad/GamepadManager.cpp
@@ -263,65 +263,16 @@ GamepadManager::RemoveGamepad(uint32_t a
     return;
   }
   gamepad->SetConnected(false);
   NewConnectionEvent(newIndex, false);
   mGamepads.Remove(newIndex);
 }
 
 void
-GamepadManager::NewButtonEvent(uint32_t aIndex, GamepadServiceType aServiceType,
-                               uint32_t aButton, bool aPressed, bool aTouched,
-                               double aValue)
-{
-  if (mShuttingDown) {
-    return;
-  }
-
-  uint32_t newIndex = GetGamepadIndexWithServiceType(aIndex, aServiceType);
-
-  RefPtr<Gamepad> gamepad = GetGamepad(newIndex);
-  if (!gamepad) {
-    return;
-  }
-
-  gamepad->SetButton(aButton, aPressed, aTouched, aValue);
-
-  // Hold on to listeners in a separate array because firing events
-  // can mutate the mListeners array.
-  nsTArray<RefPtr<nsGlobalWindow>> listeners(mListeners);
-  MOZ_ASSERT(!listeners.IsEmpty());
-
-  for (uint32_t i = 0; i < listeners.Length(); i++) {
-
-    MOZ_ASSERT(listeners[i]->IsInnerWindow());
-
-    // Only send events to non-background windows
-    if (!listeners[i]->AsInner()->IsCurrentInnerWindow() ||
-        listeners[i]->GetOuterWindow()->IsBackground()) {
-      continue;
-    }
-
-    bool firstTime = MaybeWindowHasSeenGamepad(listeners[i], newIndex);
-
-    RefPtr<Gamepad> listenerGamepad = listeners[i]->GetGamepad(newIndex);
-    if (listenerGamepad) {
-      listenerGamepad->SetButton(aButton, aPressed, aTouched, aValue);
-      if (firstTime) {
-        FireConnectionEvent(listeners[i], listenerGamepad, true);
-      }
-      if (mNonstandardEventsEnabled) {
-        // Fire event
-        FireButtonEvent(listeners[i], listenerGamepad, aButton, aValue);
-      }
-    }
-  }
-}
-
-void
 GamepadManager::FireButtonEvent(EventTarget* aTarget,
                                 Gamepad* aGamepad,
                                 uint32_t aButton,
                                 double aValue)
 {
   nsString name = aValue == 1.0L ? NS_LITERAL_STRING("gamepadbuttondown") :
                                    NS_LITERAL_STRING("gamepadbuttonup");
   GamepadButtonEventInit init;
@@ -334,63 +285,16 @@ GamepadManager::FireButtonEvent(EventTar
 
   event->SetTrusted(true);
 
   bool defaultActionEnabled = true;
   aTarget->DispatchEvent(event, &defaultActionEnabled);
 }
 
 void
-GamepadManager::NewAxisMoveEvent(uint32_t aIndex, GamepadServiceType aServiceType,
-                                 uint32_t aAxis, double aValue)
-{
-  if (mShuttingDown) {
-    return;
-  }
-
-  uint32_t newIndex = GetGamepadIndexWithServiceType(aIndex, aServiceType);
-
-  RefPtr<Gamepad> gamepad = GetGamepad(newIndex);
-  if (!gamepad) {
-    return;
-  }
-  gamepad->SetAxis(aAxis, aValue);
-
-  // Hold on to listeners in a separate array because firing events
-  // can mutate the mListeners array.
-  nsTArray<RefPtr<nsGlobalWindow>> listeners(mListeners);
-  MOZ_ASSERT(!listeners.IsEmpty());
-
-  for (uint32_t i = 0; i < listeners.Length(); i++) {
-
-    MOZ_ASSERT(listeners[i]->IsInnerWindow());
-
-    // Only send events to non-background windows
-    if (!listeners[i]->AsInner()->IsCurrentInnerWindow() ||
-        listeners[i]->GetOuterWindow()->IsBackground()) {
-      continue;
-    }
-
-    bool firstTime = MaybeWindowHasSeenGamepad(listeners[i], newIndex);
-
-    RefPtr<Gamepad> listenerGamepad = listeners[i]->GetGamepad(newIndex);
-    if (listenerGamepad) {
-      listenerGamepad->SetAxis(aAxis, aValue);
-      if (firstTime) {
-        FireConnectionEvent(listeners[i], listenerGamepad, true);
-      }
-      if (mNonstandardEventsEnabled) {
-        // Fire event
-        FireAxisMoveEvent(listeners[i], listenerGamepad, aAxis, aValue);
-      }
-    }
-  }
-}
-
-void
 GamepadManager::FireAxisMoveEvent(EventTarget* aTarget,
                                   Gamepad* aGamepad,
                                   uint32_t aAxis,
                                   double aValue)
 {
   GamepadAxisMoveEventInit init;
   init.mBubbles = false;
   init.mCancelable = false;
@@ -404,102 +308,16 @@ GamepadManager::FireAxisMoveEvent(EventT
 
   event->SetTrusted(true);
 
   bool defaultActionEnabled = true;
   aTarget->DispatchEvent(event, &defaultActionEnabled);
 }
 
 void
-GamepadManager::NewPoseEvent(uint32_t aIndex, GamepadServiceType aServiceType,
-                             const GamepadPoseState& aPose)
-{
-  if (mShuttingDown) {
-    return;
-  }
-
-  uint32_t newIndex = GetGamepadIndexWithServiceType(aIndex, aServiceType);
-
-  RefPtr<Gamepad> gamepad = GetGamepad(newIndex);
-  if (!gamepad) {
-    return;
-  }
-  gamepad->SetPose(aPose);
-
-  // Hold on to listeners in a separate array because firing events
-  // can mutate the mListeners array.
-  nsTArray<RefPtr<nsGlobalWindow>> listeners(mListeners);
-  MOZ_ASSERT(!listeners.IsEmpty());
-
-  for (uint32_t i = 0; i < listeners.Length(); i++) {
-
-    MOZ_ASSERT(listeners[i]->IsInnerWindow());
-
-    // Only send events to non-background windows
-    if (!listeners[i]->AsInner()->IsCurrentInnerWindow() ||
-        listeners[i]->GetOuterWindow()->IsBackground()) {
-      continue;
-    }
-
-    bool firstTime = MaybeWindowHasSeenGamepad(listeners[i], newIndex);
-
-    RefPtr<Gamepad> listenerGamepad = listeners[i]->GetGamepad(newIndex);
-    if (listenerGamepad) {
-      listenerGamepad->SetPose(aPose);
-      if (firstTime) {
-        FireConnectionEvent(listeners[i], listenerGamepad, true);
-      }
-    }
-  }
-}
-
-void
-GamepadManager::NewHandChangeEvent(uint32_t aIndex, GamepadServiceType aServiceType,
-                                   GamepadHand aHand)
-{
-  if (mShuttingDown) {
-    return;
-  }
-
-  uint32_t newIndex = GetGamepadIndexWithServiceType(aIndex, aServiceType);
-
-  RefPtr<Gamepad> gamepad = GetGamepad(newIndex);
-  if (!gamepad) {
-    return;
-  }
-  gamepad->SetHand(aHand);
-
-  // Hold on to listeners in a separate array because firing events
-  // can mutate the mListeners array.
-  nsTArray<RefPtr<nsGlobalWindow>> listeners(mListeners);
-  MOZ_ASSERT(!listeners.IsEmpty());
-
-  for (uint32_t i = 0; i < listeners.Length(); i++) {
-
-    MOZ_ASSERT(listeners[i]->IsInnerWindow());
-
-    // Only send events to non-background windows
-    if (!listeners[i]->AsInner()->IsCurrentInnerWindow() ||
-        listeners[i]->GetOuterWindow()->IsBackground()) {
-      continue;
-    }
-
-    bool firstTime = MaybeWindowHasSeenGamepad(listeners[i], newIndex);
-
-    RefPtr<Gamepad> listenerGamepad = listeners[i]->GetGamepad(newIndex);
-    if (listenerGamepad) {
-      listenerGamepad->SetHand(aHand);
-      if (firstTime) {
-        FireConnectionEvent(listeners[i], listenerGamepad, true);
-      }
-    }
-  }
-}
-
-void
 GamepadManager::NewConnectionEvent(uint32_t aIndex, bool aConnected)
 {
   if (mShuttingDown) {
     return;
   }
 
   RefPtr<Gamepad> gamepad = GetGamepad(aIndex);
   if (!gamepad) {
@@ -671,55 +489,166 @@ GamepadManager::SetWindowHasSeenGamepad(
   } else {
     aWindow->RemoveGamepad(aIndex);
   }
 }
 
 void
 GamepadManager::Update(const GamepadChangeEvent& aEvent)
 {
+  if (mShuttingDown) {
+    return;
+  }
+
   if (aEvent.type() == GamepadChangeEvent::TGamepadAdded) {
     const GamepadAdded& a = aEvent.get_GamepadAdded();
     AddGamepad(a.index(), a.id(),
                static_cast<GamepadMappingType>(a.mapping()),
                static_cast<GamepadHand>(a.hand()),
                a.service_type(),
                a.num_buttons(), a.num_axes(),
                a.num_haptics());
     return;
   }
   if (aEvent.type() == GamepadChangeEvent::TGamepadRemoved) {
     const GamepadRemoved& a = aEvent.get_GamepadRemoved();
     RemoveGamepad(a.index(), a.service_type());
     return;
   }
-  if (aEvent.type() == GamepadChangeEvent::TGamepadButtonInformation) {
-    const GamepadButtonInformation& a = aEvent.get_GamepadButtonInformation();
-    NewButtonEvent(a.index(), a.service_type(), a.button(),
-                   a.pressed(), a.touched(), a.value());
+
+  if (!SetGamepadByEvent(aEvent)) {
     return;
   }
-  if (aEvent.type() == GamepadChangeEvent::TGamepadAxisInformation) {
-    const GamepadAxisInformation& a = aEvent.get_GamepadAxisInformation();
-    NewAxisMoveEvent(a.index(), a.service_type(), a.axis(), a.value());
-    return;
+
+  // Hold on to listeners in a separate array because firing events
+  // can mutate the mListeners array.
+  nsTArray<RefPtr<nsGlobalWindow>> listeners(mListeners);
+  MOZ_ASSERT(!listeners.IsEmpty());
+
+  for (uint32_t i = 0; i < listeners.Length(); i++) {
+    MOZ_ASSERT(listeners[i]->IsInnerWindow());
+
+    // Only send events to non-background windows
+    if (!listeners[i]->AsInner()->IsCurrentInnerWindow() ||
+        listeners[i]->GetOuterWindow()->IsBackground()) {
+      continue;
+    }
+
+    SetGamepadByEvent(aEvent, listeners[i]);
+    MaybeConvertToNonstandardGamepadEvent(aEvent, listeners[i]);
   }
-  if (aEvent.type() == GamepadChangeEvent::TGamepadPoseInformation) {
-    const GamepadPoseInformation& a = aEvent.get_GamepadPoseInformation();
-    NewPoseEvent(a.index(), a.service_type(), a.pose_state());
-    return;
-  }
-   if (aEvent.type() == GamepadChangeEvent::TGamepadHandInformation) {
-    const GamepadHandInformation& a = aEvent.get_GamepadHandInformation();
-    NewHandChangeEvent(a.index(), a.service_type(), a.hand());
+}
+
+void
+GamepadManager::MaybeConvertToNonstandardGamepadEvent(const GamepadChangeEvent& aEvent,
+                                                      nsGlobalWindow* aWindow)
+{
+  MOZ_ASSERT(aWindow);
+
+  if (!mNonstandardEventsEnabled) {
     return;
   }
 
-  MOZ_CRASH("We shouldn't be here!");
+  RefPtr<Gamepad> gamepad;
+
+  switch (aEvent.type()) {
+    case GamepadChangeEvent::TGamepadButtonInformation:
+      {
+        const GamepadButtonInformation& a = aEvent.get_GamepadButtonInformation();
+        gamepad = aWindow->GetGamepad(a.index());
+        if (gamepad) {
+          FireButtonEvent(aWindow, gamepad, a.button(), a.value());
+        }
+      }
+      break;
+    case GamepadChangeEvent::TGamepadAxisInformation:
+      {
+        const GamepadAxisInformation& a = aEvent.get_GamepadAxisInformation();
+        gamepad = aWindow->GetGamepad(a.index());
+        if (gamepad) {
+          FireAxisMoveEvent(aWindow, gamepad, a.axis(), a.value());
+        }
+      }
+      break;
+    default:
+      break;
+  }
+}
+
+bool
+GamepadManager::SetGamepadByEvent(const GamepadChangeEvent& aEvent, nsGlobalWindow *aWindow)
+{
+  uint32_t index;
+  RefPtr<Gamepad> gamepad;
+  bool ret = false;
+  bool firstTime = false;
 
+  switch (aEvent.type()) {
+    case GamepadChangeEvent::TGamepadButtonInformation:
+    {
+      const GamepadButtonInformation& a = aEvent.get_GamepadButtonInformation();
+      index = GetGamepadIndexWithServiceType(a.index(), a.service_type());
+      if (aWindow) {
+        firstTime = MaybeWindowHasSeenGamepad(aWindow, index);
+      }
+      gamepad = aWindow ? aWindow->GetGamepad(index) : GetGamepad(index);
+      if (gamepad) {
+        gamepad->SetButton(a.button(), a.pressed(), a.touched(), a.value());
+        ret = true;
+      }
+    } break;
+    case GamepadChangeEvent::TGamepadAxisInformation:
+    {
+      const GamepadAxisInformation& a = aEvent.get_GamepadAxisInformation();
+      index = GetGamepadIndexWithServiceType(a.index(), a.service_type());
+      if (aWindow) {
+        firstTime = MaybeWindowHasSeenGamepad(aWindow, index);
+      }
+      gamepad = aWindow ? aWindow->GetGamepad(index) : GetGamepad(index);
+      if (gamepad) {
+        gamepad->SetAxis(a.axis(), a.value());
+        ret = true;
+      }
+    } break;
+    case GamepadChangeEvent::TGamepadPoseInformation:
+    {
+      const GamepadPoseInformation& a = aEvent.get_GamepadPoseInformation();
+      index = GetGamepadIndexWithServiceType(a.index(), a.service_type());
+      if (aWindow) {
+        firstTime = MaybeWindowHasSeenGamepad(aWindow, index);
+      }
+      gamepad = aWindow ? aWindow->GetGamepad(index) : GetGamepad(index);
+      if (gamepad) {
+        gamepad->SetPose(a.pose_state());
+         ret = true;
+      }
+    } break;
+    case GamepadChangeEvent::TGamepadHandInformation:
+    {
+      const GamepadHandInformation& a = aEvent.get_GamepadHandInformation();
+      index = GetGamepadIndexWithServiceType(a.index(), a.service_type());
+      if (aWindow) {
+        firstTime = MaybeWindowHasSeenGamepad(aWindow, index);
+      }
+      gamepad = aWindow ? aWindow->GetGamepad(index) : GetGamepad(index);
+      if (gamepad) {
+        gamepad->SetHand(a.hand());
+        ret = true;
+      }
+    } break;
+    default:
+      MOZ_ASSERT(false);
+      break;
+  }
+
+  if (aWindow && firstTime) {
+    FireConnectionEvent(aWindow, gamepad, true);
+  }
+
+  return ret;
 }
 
 already_AddRefed<Promise>
 GamepadManager::VibrateHaptic(uint32_t aControllerIdx, uint32_t aHapticIndex,
                               double aIntensity, double aDuration,
                               nsIGlobalObject* aGlobal, ErrorResult& aRv)
 {
   RefPtr<Promise> promise = Promise::Create(aGlobal, aRv);
--- a/dom/gamepad/GamepadManager.h
+++ b/dom/gamepad/GamepadManager.h
@@ -52,39 +52,16 @@ class GamepadManager final : public nsIO
   // Add a gamepad to the list of known gamepads.
   void AddGamepad(uint32_t aIndex, const nsAString& aID, GamepadMappingType aMapping,
                   GamepadHand aHand, GamepadServiceType aServiceType,
                   uint32_t aNumButtons, uint32_t aNumAxes, uint32_t aNumHaptics);
 
   // Remove the gamepad at |aIndex| from the list of known gamepads.
   void RemoveGamepad(uint32_t aIndex, GamepadServiceType aServiceType);
 
-  // Update the state of |aButton| for the gamepad at |aIndex| for all
-  // windows that are listening and visible, and fire one of
-  // a gamepadbutton{up,down} event at them as well.
-  // aPressed is used for digital buttons, aValue is for analog buttons.
-  void NewButtonEvent(uint32_t aIndex, GamepadServiceType aServiceType, uint32_t aButton,
-                      bool aPressed, bool aTouched, double aValue);
-
-  // Update the state of |aAxis| for the gamepad at |aIndex| for all
-  // windows that are listening and visible, and fire a gamepadaxismove
-  // event at them as well.
-  void NewAxisMoveEvent(uint32_t aIndex, GamepadServiceType aServiceType,
-                        uint32_t aAxis, double aValue);
-
-  // Update the state of |aState| for the gamepad at |aIndex| for all
-  // windows that are listening and visible.
-  void NewPoseEvent(uint32_t aIndex, GamepadServiceType aServiceType,
-                    const GamepadPoseState& aState);
-
-  // Update the hand of |aHand| for the gamepad at |aIndex| for all
-  // windows that are listening and visible.
-  void NewHandChangeEvent(uint32_t aIndex, GamepadServiceType aServiceType,
-                          GamepadHand aHand);
-
   // Synchronize the state of |aGamepad| to match the gamepad stored at |aIndex|
   void SyncGamepadState(uint32_t aIndex, Gamepad* aGamepad);
 
   // Returns gamepad object if index exists, null otherwise
   already_AddRefed<Gamepad> GetGamepad(uint32_t aIndex) const;
 
   // Receive GamepadChangeEvent messages from parent process to fire DOM events
   void Update(const GamepadChangeEvent& aGamepadEvent);
@@ -136,16 +113,21 @@ class GamepadManager final : public nsIO
   // will be destroyed during the IPDL shutdown chain, so we
   // don't need to refcount it here.
   nsTArray<GamepadEventChannelChild *> mChannelChildren;
 
  private:
 
   nsresult Init();
 
+  void MaybeConvertToNonstandardGamepadEvent(const GamepadChangeEvent& aEvent,
+                                             nsGlobalWindow* aWindow);
+
+  bool SetGamepadByEvent(const GamepadChangeEvent& aEvent, nsGlobalWindow* aWindow = nullptr);
+
   bool MaybeWindowHasSeenGamepad(nsGlobalWindow* aWindow, uint32_t aIndex);
   // Returns true if we have already sent data from this gamepad
   // to this window. This should only return true if the user
   // explicitly interacted with a gamepad while this window
   // was focused, by pressing buttons or similar actions.
   bool WindowHasSeenGamepad(nsGlobalWindow* aWindow, uint32_t aIndex) const;
   // Indicate that a window has received data from a gamepad.
   void SetWindowHasSeenGamepad(nsGlobalWindow* aWindow, uint32_t aIndex,