Bug 1356452 - Part 6: Simplfying fire events to global window listeners in GamepadManager: r?lenzak draft
authorDaosheng Mu <daoshengmu@gmail.com>
Thu, 20 Apr 2017 10:27:19 +0800
changeset 565591 0828c458ca240f178f8fa6ca2c7e1bbf18a5df38
parent 565590 52491f1927a86789231f238ffa9b236a47006467
child 625026 9b50de7da8d3a6173a087d02f0b2c82c74963cc7
push id54907
push userbmo:dmu@mozilla.com
push dateThu, 20 Apr 2017 02:43:33 +0000
reviewerslenzak
bugs1356452
milestone55.0a1
Bug 1356452 - Part 6: Simplfying fire events to global window listeners in GamepadManager: r?lenzak MozReview-Commit-ID: FLQyVAARwK1
dom/gamepad/GamepadManager.cpp
dom/gamepad/GamepadManager.h
--- a/dom/gamepad/GamepadManager.cpp
+++ b/dom/gamepad/GamepadManager.cpp
@@ -195,18 +195,19 @@ GamepadManager::GetGamepad(uint32_t aInd
   RefPtr<Gamepad> gamepad;
   if (mGamepads.Get(aIndex, getter_AddRefs(gamepad))) {
     return gamepad.forget();
   }
 
   return nullptr;
 }
 
-uint32_t GamepadManager::GetGamepadIndexWithServiceType(uint32_t aIndex,
-                                                        GamepadServiceType aServiceType)
+uint32_t
+GamepadManager::GetGamepadIndexWithServiceType(uint32_t aIndex,
+                                               GamepadServiceType aServiceType)
 {
   uint32_t newIndex = 0;
 
   switch (aServiceType) {
     case GamepadServiceType::Standard:
       MOZ_ASSERT(aIndex <= VR_GAMEPAD_IDX_OFFSET);
       newIndex = aIndex;
       break;
@@ -216,16 +217,86 @@ uint32_t GamepadManager::GetGamepadIndex
     default:
       MOZ_ASSERT(false);
       break;
   }
 
   return newIndex;
 }
 
+template<typename... Storages, typename Method, typename... Args>
+void
+GamepadManager::FireEventsToListener(Method aMethod, uint32_t aIndex, Args&&... aArgs)
+{
+  static_assert(sizeof...(Storages) == sizeof...(Args),
+                "<Storages...> size should be equal to number of arguments");
+  // 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], aIndex);
+
+    RefPtr<Gamepad> listenerGamepad = listeners[i]->GetGamepad(aIndex);
+    if (listenerGamepad) {
+      (listenerGamepad->*aMethod)(mozilla::Forward<Args>(aArgs)...);
+      if (firstTime) {
+        FireConnectionEvent(listeners[i], listenerGamepad, true);
+      }
+    }
+  }
+}
+
+template<typename... Storages, typename Method1, typename Method2, typename... Args>
+void
+GamepadManager::FireEventsToListener(Method1 aMethod1, Method2 aMethod2, uint32_t aIndex, Args&&... aArgs)
+{
+  static_assert(sizeof...(Storages) == sizeof...(Args),
+                "<Storages...> size should be equal to number of arguments");
+  // 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], aIndex);
+
+    RefPtr<Gamepad> listenerGamepad = listeners[i]->GetGamepad(aIndex);
+    if (listenerGamepad) {
+      (listenerGamepad->*aMethod1)(mozilla::Forward<Args>(aArgs)...);
+      if (firstTime) {
+        FireConnectionEvent(listeners[i], listenerGamepad, true);
+      }
+      if (mNonstandardEventsEnabled) {
+        // // Fire event
+        (this->*aMethod2)(listeners[i], listenerGamepad, mozilla::Forward<Args>(aArgs)...);
+      }
+    }
+  }
+}
+
 void
 GamepadManager::AddGamepad(uint32_t aIndex,
                            const nsAString& aId,
                            GamepadMappingType aMapping,
                            GamepadHand aHand,
                            GamepadServiceType aServiceType,
                            uint32_t aNumButtons,
                            uint32_t aNumAxes,
@@ -279,54 +350,34 @@ GamepadManager::NewButtonEvent(uint32_t 
   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);
-      }
-    }
-  }
+  FireEventsToListener<uint32_t, bool, bool, double>(
+    &Gamepad::SetButton, &GamepadManager::FireButtonEvent,
+    newIndex, aButton, aPressed, aTouched, aValue);
 }
 
 void
 GamepadManager::FireButtonEvent(EventTarget* aTarget,
                                 Gamepad* aGamepad,
                                 uint32_t aButton,
+                                bool aPressed,
+                                bool aTouched,
                                 double aValue)
 {
+  // Due to FireEventsToListener(), we have to send
+  // these unused arguments for simplifying the duplicated
+  // code of firing events to global window listeners.
+  Unused << aPressed;
+  Unused << aTouched;
   nsString name = aValue == 1.0L ? NS_LITERAL_STRING("gamepadbuttondown") :
                                    NS_LITERAL_STRING("gamepadbuttonup");
   GamepadButtonEventInit init;
   init.mBubbles = false;
   init.mCancelable = false;
   init.mGamepad = aGamepad;
   init.mButton = aButton;
   RefPtr<GamepadButtonEvent> event =
@@ -348,46 +399,19 @@ GamepadManager::NewAxisMoveEvent(uint32_
 
   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);
-      }
-    }
-  }
+  FireEventsToListener<uint32_t, double>(
+    &Gamepad::SetAxis, &GamepadManager::FireAxisMoveEvent,
+    newIndex, aAxis, aValue);
 }
 
 void
 GamepadManager::FireAxisMoveEvent(EventTarget* aTarget,
                                   Gamepad* aGamepad,
                                   uint32_t aAxis,
                                   double aValue)
 {
@@ -418,42 +442,18 @@ GamepadManager::NewPoseEvent(uint32_t aI
 
   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);
-      }
-    }
-  }
+  FireEventsToListener<const GamepadPoseState&>(
+    &Gamepad::SetPose, newIndex, aPose);
 }
 
 void
 GamepadManager::NewHandChangeEvent(uint32_t aIndex, GamepadServiceType aServiceType,
                                    GamepadHand aHand)
 {
   if (mShuttingDown) {
     return;
@@ -461,42 +461,17 @@ GamepadManager::NewHandChangeEvent(uint3
 
   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);
-      }
-    }
-  }
+  FireEventsToListener<GamepadHand>(&Gamepad::SetHand, newIndex, aHand);
 }
 
 void
 GamepadManager::NewConnectionEvent(uint32_t aIndex, bool aConnected)
 {
   if (mShuttingDown) {
     return;
   }
--- a/dom/gamepad/GamepadManager.h
+++ b/dom/gamepad/GamepadManager.h
@@ -111,16 +111,18 @@ class GamepadManager final : public nsIO
                          uint32_t axis,
                          double value);
 
   // Fire one of gamepadbutton{up,down} event at the window at |aTarget| for
   // |aGamepad|.
   void FireButtonEvent(EventTarget* aTarget,
                        Gamepad* aGamepad,
                        uint32_t aButton,
+                       bool aPressed,
+                       bool aTouched,
                        double aValue);
 
   // Fire one of gamepad{connected,disconnected} event at the window at
   // |aTarget| for |aGamepad|.
   void FireConnectionEvent(EventTarget* aTarget,
                            Gamepad* aGamepad,
                            bool aConnected);
 
@@ -148,16 +150,21 @@ class GamepadManager final : public nsIO
   // 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,
                                bool aHasSeen = true);
   // Our gamepad index has VR_GAMEPAD_IDX_OFFSET while GamepadChannelType
   // is from VRManager.
   uint32_t GetGamepadIndexWithServiceType(uint32_t aIndex, GamepadServiceType aServiceType);
+  // Fire events to global windows and connection events if it's the first time
+  template<typename... Storages, typename Method, typename... Args>
+  void FireEventsToListener(Method aMethod, uint32_t aIndex, Args&&... aArgs);
+  template<typename... Storages, typename Method1, typename Method2, typename... Args>
+  void FireEventsToListener(Method1 aMethod1, Method2 aMethod2, uint32_t aIndex, Args&&... aArgs);
 
   // Gamepads connected to the system. Copies of these are handed out
   // to each window.
   nsRefPtrHashtable<nsUint32HashKey, Gamepad> mGamepads;
   // Inner windows that are listening for gamepad events.
   // has been sent to that window.
   nsTArray<RefPtr<nsGlobalWindow>> mListeners;
   uint32_t mPromiseID;