LCOV - code coverage report
Current view: top level - dom/gamepad - GamepadManager.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 1 343 0.3 %
Date: 2017-07-14 16:53:18 Functions: 0 32 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
       5             :  * You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "mozilla/dom/GamepadManager.h"
       8             : 
       9             : #include "mozilla/dom/Gamepad.h"
      10             : #include "mozilla/dom/GamepadAxisMoveEvent.h"
      11             : #include "mozilla/dom/GamepadButtonEvent.h"
      12             : #include "mozilla/dom/GamepadEvent.h"
      13             : #include "mozilla/dom/GamepadEventChannelChild.h"
      14             : #include "mozilla/dom/GamepadMonitoring.h"
      15             : 
      16             : #include "mozilla/ipc/BackgroundChild.h"
      17             : #include "mozilla/ipc/PBackgroundChild.h"
      18             : #include "mozilla/ClearOnShutdown.h"
      19             : #include "mozilla/Preferences.h"
      20             : #include "mozilla/StaticPtr.h"
      21             : 
      22             : #include "nsAutoPtr.h"
      23             : #include "nsContentUtils.h"
      24             : #include "nsGlobalWindow.h"
      25             : #include "nsIDOMEvent.h"
      26             : #include "nsIDOMDocument.h"
      27             : #include "nsIDOMWindow.h"
      28             : #include "nsIObserver.h"
      29             : #include "nsIObserverService.h"
      30             : #include "nsIServiceManager.h"
      31             : #include "nsThreadUtils.h"
      32             : #include "VRManagerChild.h"
      33             : #include "mozilla/Services.h"
      34             : #include "mozilla/Unused.h"
      35             : 
      36             : #include <cstddef>
      37             : 
      38             : using namespace mozilla::ipc;
      39             : 
      40             : namespace mozilla {
      41             : namespace dom {
      42             : 
      43             : namespace {
      44             : 
      45             : const char* kGamepadEnabledPref = "dom.gamepad.enabled";
      46             : const char* kGamepadEventsEnabledPref =
      47             :   "dom.gamepad.non_standard_events.enabled";
      48             : 
      49             : const nsTArray<RefPtr<nsGlobalWindow>>::index_type NoIndex =
      50             :   nsTArray<RefPtr<nsGlobalWindow>>::NoIndex;
      51             : 
      52             : bool sShutdown = false;
      53             : 
      54           3 : StaticRefPtr<GamepadManager> gGamepadManagerSingleton;
      55             : const uint32_t VR_GAMEPAD_IDX_OFFSET = 0x01 << 16;
      56             : 
      57             : } // namespace
      58             : 
      59           0 : NS_IMPL_ISUPPORTS(GamepadManager, nsIObserver)
      60             : 
      61           0 : GamepadManager::GamepadManager()
      62             :   : mEnabled(false),
      63             :     mNonstandardEventsEnabled(false),
      64             :     mShuttingDown(false),
      65           0 :     mPromiseID(0)
      66           0 : {}
      67             : 
      68             : nsresult
      69           0 : GamepadManager::Init()
      70             : {
      71           0 :   mEnabled = IsAPIEnabled();
      72           0 :   mNonstandardEventsEnabled =
      73           0 :     Preferences::GetBool(kGamepadEventsEnabledPref, false);
      74             :   nsCOMPtr<nsIObserverService> observerService =
      75           0 :     mozilla::services::GetObserverService();
      76             : 
      77           0 :   if (NS_WARN_IF(!observerService)) {
      78           0 :     return NS_ERROR_FAILURE;
      79             :   }
      80             : 
      81             :   nsresult rv;
      82           0 :   rv = observerService->AddObserver(this,
      83             :                                     NS_XPCOM_WILL_SHUTDOWN_OBSERVER_ID,
      84           0 :                                     false);
      85             : 
      86           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
      87           0 :     return rv;
      88             :   }
      89             : 
      90           0 :   return NS_OK;
      91             : }
      92             : 
      93             : NS_IMETHODIMP
      94           0 : GamepadManager::Observe(nsISupports* aSubject,
      95             :                         const char* aTopic,
      96             :                         const char16_t* aData)
      97             : {
      98             :   nsCOMPtr<nsIObserverService> observerService =
      99           0 :     mozilla::services::GetObserverService();
     100           0 :   if (observerService) {
     101           0 :     observerService->RemoveObserver(this, NS_XPCOM_WILL_SHUTDOWN_OBSERVER_ID);
     102             :   }
     103           0 :   BeginShutdown();
     104           0 :   return NS_OK;
     105             : }
     106             : 
     107             : void
     108           0 : GamepadManager::StopMonitoring()
     109             : {
     110           0 :   for (uint32_t i = 0; i < mChannelChildren.Length(); ++i) {
     111           0 :     mChannelChildren[i]->SendGamepadListenerRemoved();
     112             :   }
     113           0 :   mChannelChildren.Clear();
     114           0 :   mGamepads.Clear();
     115             : 
     116           0 :   if (gfx::VRManagerChild::IsCreated()) {
     117           0 :     gfx::VRManagerChild* vm = gfx::VRManagerChild::Get();
     118           0 :     vm->SendControllerListenerRemoved();
     119             :   }
     120           0 : }
     121             : 
     122             : void
     123           0 : GamepadManager::BeginShutdown()
     124             : {
     125           0 :   mShuttingDown = true;
     126           0 :   StopMonitoring();
     127             :   // Don't let windows call back to unregister during shutdown
     128           0 :   for (uint32_t i = 0; i < mListeners.Length(); i++) {
     129           0 :     mListeners[i]->SetHasGamepadEventListener(false);
     130             :   }
     131           0 :   mListeners.Clear();
     132           0 :   sShutdown = true;
     133           0 : }
     134             : 
     135             : void
     136           0 : GamepadManager::AddListener(nsGlobalWindow* aWindow)
     137             : {
     138           0 :   MOZ_ASSERT(aWindow);
     139           0 :   MOZ_ASSERT(aWindow->IsInnerWindow());
     140           0 :   MOZ_ASSERT(NS_IsMainThread());
     141             : 
     142             :   // IPDL child has not been created
     143           0 :   if (mChannelChildren.IsEmpty()) {
     144           0 :     PBackgroundChild *actor = BackgroundChild::GetForCurrentThread();
     145             :     //Try to get the PBackground Child actor
     146           0 :     if (actor) {
     147           0 :       ActorCreated(actor);
     148             :     } else {
     149           0 :       Unused << BackgroundChild::GetOrCreateForCurrentThread(this);
     150             :     }
     151             :   }
     152             : 
     153           0 :   if (!mEnabled || mShuttingDown || nsContentUtils::ShouldResistFingerprinting()) {
     154           0 :     return;
     155             :   }
     156             : 
     157           0 :   if (mListeners.IndexOf(aWindow) != NoIndex) {
     158           0 :     return; // already exists
     159             :   }
     160             : 
     161           0 :   mListeners.AppendElement(aWindow);
     162             : }
     163             : 
     164             : void
     165           0 : GamepadManager::RemoveListener(nsGlobalWindow* aWindow)
     166             : {
     167           0 :   MOZ_ASSERT(aWindow);
     168           0 :   MOZ_ASSERT(aWindow->IsInnerWindow());
     169             : 
     170           0 :   if (mShuttingDown) {
     171             :     // Doesn't matter at this point. It's possible we're being called
     172             :     // as a result of our own destructor here, so just bail out.
     173           0 :     return;
     174             :   }
     175             : 
     176           0 :   if (mListeners.IndexOf(aWindow) == NoIndex) {
     177           0 :     return; // doesn't exist
     178             :   }
     179             : 
     180           0 :   for (auto iter = mGamepads.Iter(); !iter.Done(); iter.Next()) {
     181           0 :       aWindow->RemoveGamepad(iter.Key());
     182             :   }
     183             : 
     184           0 :   mListeners.RemoveElement(aWindow);
     185             : 
     186           0 :   if (mListeners.IsEmpty()) {
     187           0 :     StopMonitoring();
     188             :   }
     189             : }
     190             : 
     191             : already_AddRefed<Gamepad>
     192           0 : GamepadManager::GetGamepad(uint32_t aIndex) const
     193             : {
     194           0 :   RefPtr<Gamepad> gamepad;
     195           0 :   if (mGamepads.Get(aIndex, getter_AddRefs(gamepad))) {
     196           0 :     return gamepad.forget();
     197             :   }
     198             : 
     199           0 :   return nullptr;
     200             : }
     201             : 
     202           0 : uint32_t GamepadManager::GetGamepadIndexWithServiceType(uint32_t aIndex,
     203             :                                                         GamepadServiceType aServiceType)
     204             : {
     205           0 :   uint32_t newIndex = 0;
     206             : 
     207           0 :   switch (aServiceType) {
     208             :     case GamepadServiceType::Standard:
     209           0 :       MOZ_ASSERT(aIndex <= VR_GAMEPAD_IDX_OFFSET);
     210           0 :       newIndex = aIndex;
     211           0 :       break;
     212             :     case GamepadServiceType::VR:
     213           0 :       newIndex = aIndex + VR_GAMEPAD_IDX_OFFSET;
     214           0 :       break;
     215             :     default:
     216           0 :       MOZ_ASSERT(false);
     217             :       break;
     218             :   }
     219             : 
     220           0 :   return newIndex;
     221             : }
     222             : 
     223             : void
     224           0 : GamepadManager::AddGamepad(uint32_t aIndex,
     225             :                            const nsAString& aId,
     226             :                            GamepadMappingType aMapping,
     227             :                            GamepadHand aHand,
     228             :                            GamepadServiceType aServiceType,
     229             :                            uint32_t aNumButtons,
     230             :                            uint32_t aNumAxes,
     231             :                            uint32_t aNumHaptics)
     232             : {
     233           0 :    uint32_t newIndex = GetGamepadIndexWithServiceType(aIndex, aServiceType);
     234             : 
     235             :   //TODO: bug 852258: get initial button/axis state
     236             :   RefPtr<Gamepad> gamepad =
     237             :     new Gamepad(nullptr,
     238             :                 aId,
     239             :                 0, // index is set by global window
     240             :                 newIndex,
     241             :                 aMapping,
     242             :                 aHand,
     243             :                 aNumButtons,
     244             :                 aNumAxes,
     245           0 :                 aNumHaptics);
     246             : 
     247             :   // We store the gamepad related to its index given by the parent process,
     248             :   // and no duplicate index is allowed.
     249           0 :   MOZ_ASSERT(!mGamepads.Get(newIndex, nullptr));
     250           0 :   mGamepads.Put(newIndex, gamepad);
     251           0 :   NewConnectionEvent(newIndex, true);
     252           0 : }
     253             : 
     254             : void
     255           0 : GamepadManager::RemoveGamepad(uint32_t aIndex, GamepadServiceType aServiceType)
     256             : {
     257           0 :   uint32_t newIndex = GetGamepadIndexWithServiceType(aIndex, aServiceType);
     258             : 
     259           0 :   RefPtr<Gamepad> gamepad = GetGamepad(newIndex);
     260           0 :   if (!gamepad) {
     261           0 :     NS_WARNING("Trying to delete gamepad with invalid index");
     262           0 :     return;
     263             :   }
     264           0 :   gamepad->SetConnected(false);
     265           0 :   NewConnectionEvent(newIndex, false);
     266           0 :   mGamepads.Remove(newIndex);
     267             : }
     268             : 
     269             : void
     270           0 : GamepadManager::FireButtonEvent(EventTarget* aTarget,
     271             :                                 Gamepad* aGamepad,
     272             :                                 uint32_t aButton,
     273             :                                 double aValue)
     274             : {
     275           0 :   nsString name = aValue == 1.0L ? NS_LITERAL_STRING("gamepadbuttondown") :
     276           0 :                                    NS_LITERAL_STRING("gamepadbuttonup");
     277           0 :   GamepadButtonEventInit init;
     278           0 :   init.mBubbles = false;
     279           0 :   init.mCancelable = false;
     280           0 :   init.mGamepad = aGamepad;
     281           0 :   init.mButton = aButton;
     282             :   RefPtr<GamepadButtonEvent> event =
     283           0 :     GamepadButtonEvent::Constructor(aTarget, name, init);
     284             : 
     285           0 :   event->SetTrusted(true);
     286             : 
     287           0 :   bool defaultActionEnabled = true;
     288           0 :   aTarget->DispatchEvent(event, &defaultActionEnabled);
     289           0 : }
     290             : 
     291             : void
     292           0 : GamepadManager::FireAxisMoveEvent(EventTarget* aTarget,
     293             :                                   Gamepad* aGamepad,
     294             :                                   uint32_t aAxis,
     295             :                                   double aValue)
     296             : {
     297           0 :   GamepadAxisMoveEventInit init;
     298           0 :   init.mBubbles = false;
     299           0 :   init.mCancelable = false;
     300           0 :   init.mGamepad = aGamepad;
     301           0 :   init.mAxis = aAxis;
     302           0 :   init.mValue = aValue;
     303             :   RefPtr<GamepadAxisMoveEvent> event =
     304           0 :     GamepadAxisMoveEvent::Constructor(aTarget,
     305           0 :                                       NS_LITERAL_STRING("gamepadaxismove"),
     306           0 :                                       init);
     307             : 
     308           0 :   event->SetTrusted(true);
     309             : 
     310           0 :   bool defaultActionEnabled = true;
     311           0 :   aTarget->DispatchEvent(event, &defaultActionEnabled);
     312           0 : }
     313             : 
     314             : void
     315           0 : GamepadManager::NewConnectionEvent(uint32_t aIndex, bool aConnected)
     316             : {
     317             :   // Do not fire gamepadconnected and gamepaddisconnected events when
     318             :   // privacy.resistFingerprinting is true.
     319           0 :   if (nsContentUtils::ShouldResistFingerprinting()) {
     320           0 :     return;
     321             :   }
     322             : 
     323           0 :   if (mShuttingDown) {
     324           0 :     return;
     325             :   }
     326             : 
     327           0 :   RefPtr<Gamepad> gamepad = GetGamepad(aIndex);
     328           0 :   if (!gamepad) {
     329           0 :     return;
     330             :   }
     331             : 
     332             :   // Hold on to listeners in a separate array because firing events
     333             :   // can mutate the mListeners array.
     334           0 :   nsTArray<RefPtr<nsGlobalWindow>> listeners(mListeners);
     335           0 :   MOZ_ASSERT(!listeners.IsEmpty());
     336             : 
     337           0 :   if (aConnected) {
     338           0 :     for (uint32_t i = 0; i < listeners.Length(); i++) {
     339             : 
     340           0 :       MOZ_ASSERT(listeners[i]->IsInnerWindow());
     341             : 
     342             :       // Only send events to non-background windows
     343           0 :       if (!listeners[i]->AsInner()->IsCurrentInnerWindow() ||
     344           0 :           listeners[i]->GetOuterWindow()->IsBackground()) {
     345           0 :         continue;
     346             :       }
     347             : 
     348             :       // We don't fire a connected event here unless the window
     349             :       // has seen input from at least one device.
     350           0 :       if (!listeners[i]->HasSeenGamepadInput()) {
     351           0 :         continue;
     352             :       }
     353             : 
     354           0 :       SetWindowHasSeenGamepad(listeners[i], aIndex);
     355             : 
     356           0 :       RefPtr<Gamepad> listenerGamepad = listeners[i]->GetGamepad(aIndex);
     357           0 :       if (listenerGamepad) {
     358             :         // Fire event
     359           0 :         FireConnectionEvent(listeners[i], listenerGamepad, aConnected);
     360             :       }
     361             :     }
     362             :   } else {
     363             :     // For disconnection events, fire one at every window that has received
     364             :     // data from this gamepad.
     365           0 :     for (uint32_t i = 0; i < listeners.Length(); i++) {
     366             : 
     367             :       // Even background windows get these events, so we don't have to
     368             :       // deal with the hassle of syncing the state of removed gamepads.
     369             : 
     370           0 :       if (WindowHasSeenGamepad(listeners[i], aIndex)) {
     371           0 :         RefPtr<Gamepad> listenerGamepad = listeners[i]->GetGamepad(aIndex);
     372           0 :         if (listenerGamepad) {
     373           0 :           listenerGamepad->SetConnected(false);
     374             :           // Fire event
     375           0 :           FireConnectionEvent(listeners[i], listenerGamepad, false);
     376           0 :           listeners[i]->RemoveGamepad(aIndex);
     377             :         }
     378             :       }
     379             :     }
     380             :   }
     381             : }
     382             : 
     383             : void
     384           0 : GamepadManager::FireConnectionEvent(EventTarget* aTarget,
     385             :                                     Gamepad* aGamepad,
     386             :                                     bool aConnected)
     387             : {
     388           0 :   nsString name = aConnected ? NS_LITERAL_STRING("gamepadconnected") :
     389           0 :                                NS_LITERAL_STRING("gamepaddisconnected");
     390           0 :   GamepadEventInit init;
     391           0 :   init.mBubbles = false;
     392           0 :   init.mCancelable = false;
     393           0 :   init.mGamepad = aGamepad;
     394             :   RefPtr<GamepadEvent> event =
     395           0 :     GamepadEvent::Constructor(aTarget, name, init);
     396             : 
     397           0 :   event->SetTrusted(true);
     398             : 
     399           0 :   bool defaultActionEnabled = true;
     400           0 :   aTarget->DispatchEvent(event, &defaultActionEnabled);
     401           0 : }
     402             : 
     403             : void
     404           0 : GamepadManager::SyncGamepadState(uint32_t aIndex, Gamepad* aGamepad)
     405             : {
     406           0 :   if (mShuttingDown || !mEnabled || nsContentUtils::ShouldResistFingerprinting()) {
     407           0 :     return;
     408             :   }
     409             : 
     410           0 :   RefPtr<Gamepad> gamepad = GetGamepad(aIndex);
     411           0 :   if (!gamepad) {
     412           0 :     return;
     413             :   }
     414             : 
     415           0 :   aGamepad->SyncState(gamepad);
     416             : }
     417             : 
     418             : // static
     419             : bool
     420           0 : GamepadManager::IsServiceRunning()
     421             : {
     422           0 :   return !!gGamepadManagerSingleton;
     423             : }
     424             : 
     425             : // static
     426             : already_AddRefed<GamepadManager>
     427           0 : GamepadManager::GetService()
     428             : {
     429           0 :   if (sShutdown) {
     430           0 :     return nullptr;
     431             :   }
     432             : 
     433           0 :   if (!gGamepadManagerSingleton) {
     434           0 :     RefPtr<GamepadManager> manager = new GamepadManager();
     435           0 :     nsresult rv = manager->Init();
     436           0 :     if(NS_WARN_IF(NS_FAILED(rv))) {
     437           0 :       return nullptr;
     438             :     }
     439           0 :     gGamepadManagerSingleton = manager;
     440           0 :     ClearOnShutdown(&gGamepadManagerSingleton);
     441             :   }
     442             : 
     443           0 :   RefPtr<GamepadManager> service(gGamepadManagerSingleton);
     444           0 :   return service.forget();
     445             : }
     446             : 
     447             : // static
     448             : bool
     449           0 : GamepadManager::IsAPIEnabled() {
     450           0 :   return Preferences::GetBool(kGamepadEnabledPref, false);
     451             : }
     452             : 
     453             : bool
     454           0 : GamepadManager::MaybeWindowHasSeenGamepad(nsGlobalWindow* aWindow, uint32_t aIndex)
     455             : {
     456           0 :   if (!WindowHasSeenGamepad(aWindow, aIndex)) {
     457             :     // This window hasn't seen this gamepad before, so
     458             :     // send a connection event first.
     459           0 :     SetWindowHasSeenGamepad(aWindow, aIndex);
     460           0 :     return true;
     461             :   }
     462           0 :   return false;
     463             : }
     464             : 
     465             : bool
     466           0 : GamepadManager::WindowHasSeenGamepad(nsGlobalWindow* aWindow, uint32_t aIndex) const
     467             : {
     468           0 :   RefPtr<Gamepad> gamepad = aWindow->GetGamepad(aIndex);
     469           0 :   return gamepad != nullptr;
     470             : }
     471             : 
     472             : void
     473           0 : GamepadManager::SetWindowHasSeenGamepad(nsGlobalWindow* aWindow,
     474             :                                         uint32_t aIndex,
     475             :                                         bool aHasSeen)
     476             : {
     477           0 :   MOZ_ASSERT(aWindow);
     478           0 :   MOZ_ASSERT(aWindow->IsInnerWindow());
     479             : 
     480           0 :   if (mListeners.IndexOf(aWindow) == NoIndex) {
     481             :     // This window isn't even listening for gamepad events.
     482           0 :     return;
     483             :   }
     484             : 
     485           0 :   if (aHasSeen) {
     486           0 :     aWindow->SetHasSeenGamepadInput(true);
     487           0 :     nsCOMPtr<nsISupports> window = ToSupports(aWindow);
     488           0 :     RefPtr<Gamepad> gamepad = GetGamepad(aIndex);
     489           0 :     if (!gamepad) {
     490           0 :       return;
     491             :     }
     492           0 :     RefPtr<Gamepad> clonedGamepad = gamepad->Clone(window);
     493           0 :     aWindow->AddGamepad(aIndex, clonedGamepad);
     494             :   } else {
     495           0 :     aWindow->RemoveGamepad(aIndex);
     496             :   }
     497             : }
     498             : 
     499             : void
     500           0 : GamepadManager::Update(const GamepadChangeEvent& aEvent)
     501             : {
     502           0 :   if (!mEnabled || mShuttingDown || nsContentUtils::ShouldResistFingerprinting()) {
     503           0 :     return;
     504             :   }
     505             : 
     506           0 :   if (aEvent.type() == GamepadChangeEvent::TGamepadAdded) {
     507           0 :     const GamepadAdded& a = aEvent.get_GamepadAdded();
     508           0 :     AddGamepad(a.index(), a.id(),
     509           0 :                static_cast<GamepadMappingType>(a.mapping()),
     510           0 :                static_cast<GamepadHand>(a.hand()),
     511           0 :                a.service_type(),
     512           0 :                a.num_buttons(), a.num_axes(),
     513           0 :                a.num_haptics());
     514           0 :     return;
     515             :   }
     516           0 :   if (aEvent.type() == GamepadChangeEvent::TGamepadRemoved) {
     517           0 :     const GamepadRemoved& a = aEvent.get_GamepadRemoved();
     518           0 :     RemoveGamepad(a.index(), a.service_type());
     519           0 :     return;
     520             :   }
     521             : 
     522           0 :   if (!SetGamepadByEvent(aEvent)) {
     523           0 :     return;
     524             :   }
     525             : 
     526             :   // Hold on to listeners in a separate array because firing events
     527             :   // can mutate the mListeners array.
     528           0 :   nsTArray<RefPtr<nsGlobalWindow>> listeners(mListeners);
     529           0 :   MOZ_ASSERT(!listeners.IsEmpty());
     530             : 
     531           0 :   for (uint32_t i = 0; i < listeners.Length(); i++) {
     532           0 :     MOZ_ASSERT(listeners[i]->IsInnerWindow());
     533             : 
     534             :     // Only send events to non-background windows
     535           0 :     if (!listeners[i]->AsInner()->IsCurrentInnerWindow() ||
     536           0 :         listeners[i]->GetOuterWindow()->IsBackground()) {
     537           0 :       continue;
     538             :     }
     539             : 
     540           0 :     SetGamepadByEvent(aEvent, listeners[i]);
     541           0 :     MaybeConvertToNonstandardGamepadEvent(aEvent, listeners[i]);
     542             :   }
     543             : }
     544             : 
     545             : void
     546           0 : GamepadManager::MaybeConvertToNonstandardGamepadEvent(const GamepadChangeEvent& aEvent,
     547             :                                                       nsGlobalWindow* aWindow)
     548             : {
     549           0 :   MOZ_ASSERT(aWindow);
     550             : 
     551           0 :   if (!mNonstandardEventsEnabled) {
     552           0 :     return;
     553             :   }
     554             : 
     555           0 :   RefPtr<Gamepad> gamepad;
     556             : 
     557           0 :   switch (aEvent.type()) {
     558             :     case GamepadChangeEvent::TGamepadButtonInformation:
     559             :       {
     560           0 :         const GamepadButtonInformation& a = aEvent.get_GamepadButtonInformation();
     561           0 :         gamepad = aWindow->GetGamepad(a.index());
     562           0 :         if (gamepad) {
     563           0 :           FireButtonEvent(aWindow, gamepad, a.button(), a.value());
     564             :         }
     565             :       }
     566           0 :       break;
     567             :     case GamepadChangeEvent::TGamepadAxisInformation:
     568             :       {
     569           0 :         const GamepadAxisInformation& a = aEvent.get_GamepadAxisInformation();
     570           0 :         gamepad = aWindow->GetGamepad(a.index());
     571           0 :         if (gamepad) {
     572           0 :           FireAxisMoveEvent(aWindow, gamepad, a.axis(), a.value());
     573             :         }
     574             :       }
     575           0 :       break;
     576             :     default:
     577           0 :       break;
     578             :   }
     579             : }
     580             : 
     581             : bool
     582           0 : GamepadManager::SetGamepadByEvent(const GamepadChangeEvent& aEvent, nsGlobalWindow *aWindow)
     583             : {
     584             :   uint32_t index;
     585           0 :   RefPtr<Gamepad> gamepad;
     586           0 :   bool ret = false;
     587           0 :   bool firstTime = false;
     588             : 
     589           0 :   switch (aEvent.type()) {
     590             :     case GamepadChangeEvent::TGamepadButtonInformation:
     591             :     {
     592           0 :       const GamepadButtonInformation& a = aEvent.get_GamepadButtonInformation();
     593           0 :       index = GetGamepadIndexWithServiceType(a.index(), a.service_type());
     594           0 :       if (aWindow) {
     595           0 :         firstTime = MaybeWindowHasSeenGamepad(aWindow, index);
     596             :       }
     597           0 :       gamepad = aWindow ? aWindow->GetGamepad(index) : GetGamepad(index);
     598           0 :       if (gamepad) {
     599           0 :         gamepad->SetButton(a.button(), a.pressed(), a.touched(), a.value());
     600           0 :         ret = true;
     601             :       }
     602           0 :     } break;
     603             :     case GamepadChangeEvent::TGamepadAxisInformation:
     604             :     {
     605           0 :       const GamepadAxisInformation& a = aEvent.get_GamepadAxisInformation();
     606           0 :       index = GetGamepadIndexWithServiceType(a.index(), a.service_type());
     607           0 :       if (aWindow) {
     608           0 :         firstTime = MaybeWindowHasSeenGamepad(aWindow, index);
     609             :       }
     610           0 :       gamepad = aWindow ? aWindow->GetGamepad(index) : GetGamepad(index);
     611           0 :       if (gamepad) {
     612           0 :         gamepad->SetAxis(a.axis(), a.value());
     613           0 :         ret = true;
     614             :       }
     615           0 :     } break;
     616             :     case GamepadChangeEvent::TGamepadPoseInformation:
     617             :     {
     618           0 :       const GamepadPoseInformation& a = aEvent.get_GamepadPoseInformation();
     619           0 :       index = GetGamepadIndexWithServiceType(a.index(), a.service_type());
     620           0 :       if (aWindow) {
     621           0 :         firstTime = MaybeWindowHasSeenGamepad(aWindow, index);
     622             :       }
     623           0 :       gamepad = aWindow ? aWindow->GetGamepad(index) : GetGamepad(index);
     624           0 :       if (gamepad) {
     625           0 :         gamepad->SetPose(a.pose_state());
     626           0 :          ret = true;
     627             :       }
     628           0 :     } break;
     629             :     case GamepadChangeEvent::TGamepadHandInformation:
     630             :     {
     631           0 :       const GamepadHandInformation& a = aEvent.get_GamepadHandInformation();
     632           0 :       index = GetGamepadIndexWithServiceType(a.index(), a.service_type());
     633           0 :       if (aWindow) {
     634           0 :         firstTime = MaybeWindowHasSeenGamepad(aWindow, index);
     635             :       }
     636           0 :       gamepad = aWindow ? aWindow->GetGamepad(index) : GetGamepad(index);
     637           0 :       if (gamepad) {
     638           0 :         gamepad->SetHand(a.hand());
     639           0 :         ret = true;
     640             :       }
     641           0 :     } break;
     642             :     default:
     643           0 :       MOZ_ASSERT(false);
     644             :       break;
     645             :   }
     646             : 
     647           0 :   if (aWindow && firstTime) {
     648           0 :     FireConnectionEvent(aWindow, gamepad, true);
     649             :   }
     650             : 
     651           0 :   return ret;
     652             : }
     653             : 
     654             : already_AddRefed<Promise>
     655           0 : GamepadManager::VibrateHaptic(uint32_t aControllerIdx, uint32_t aHapticIndex,
     656             :                               double aIntensity, double aDuration,
     657             :                               nsIGlobalObject* aGlobal, ErrorResult& aRv)
     658             : {
     659           0 :   RefPtr<Promise> promise = Promise::Create(aGlobal, aRv);
     660           0 :   if (NS_WARN_IF(aRv.Failed())) {
     661           0 :     aRv.Throw(NS_ERROR_FAILURE);
     662           0 :     return nullptr;
     663             :   }
     664             : 
     665           0 :   if (aControllerIdx >= VR_GAMEPAD_IDX_OFFSET) {
     666           0 :     if (gfx::VRManagerChild::IsCreated()) {
     667           0 :       const uint32_t index = aControllerIdx - VR_GAMEPAD_IDX_OFFSET;
     668           0 :       gfx::VRManagerChild* vm = gfx::VRManagerChild::Get();
     669           0 :       vm->AddPromise(mPromiseID, promise);
     670           0 :       vm->SendVibrateHaptic(index, aHapticIndex,
     671             :                             aIntensity, aDuration,
     672           0 :                             mPromiseID);
     673             :     }
     674             :   } else {
     675           0 :     for (const auto& channelChild: mChannelChildren) {
     676           0 :       channelChild->AddPromise(mPromiseID, promise);
     677           0 :       channelChild->SendVibrateHaptic(aControllerIdx, aHapticIndex,
     678             :                                       aIntensity, aDuration,
     679           0 :                                       mPromiseID);
     680             :     }
     681             :   }
     682             : 
     683           0 :   ++mPromiseID;
     684           0 :   return promise.forget();
     685             : }
     686             : 
     687             : void
     688           0 : GamepadManager::StopHaptics()
     689             : {
     690           0 :   for (auto iter = mGamepads.Iter(); !iter.Done(); iter.Next()) {
     691           0 :     const uint32_t gamepadIndex = iter.UserData()->HashKey();
     692           0 :     if (gamepadIndex >= VR_GAMEPAD_IDX_OFFSET) {
     693           0 :       if (gfx::VRManagerChild::IsCreated()) {
     694           0 :         const uint32_t index = gamepadIndex - VR_GAMEPAD_IDX_OFFSET;
     695           0 :         gfx::VRManagerChild* vm = gfx::VRManagerChild::Get();
     696           0 :         vm->SendStopVibrateHaptic(index);
     697             :       }
     698             :     } else {
     699           0 :       for (auto& channelChild : mChannelChildren) {
     700           0 :         channelChild->SendStopVibrateHaptic(gamepadIndex);
     701             :       }
     702             :     }
     703             :   }
     704           0 : }
     705             : 
     706             : //Override nsIIPCBackgroundChildCreateCallback
     707             : void
     708           0 : GamepadManager::ActorCreated(PBackgroundChild *aActor)
     709             : {
     710           0 :   MOZ_ASSERT(aActor);
     711           0 :   GamepadEventChannelChild *child = new GamepadEventChannelChild();
     712             :   PGamepadEventChannelChild *initedChild =
     713           0 :     aActor->SendPGamepadEventChannelConstructor(child);
     714           0 :   if (NS_WARN_IF(!initedChild)) {
     715           0 :     ActorFailed();
     716           0 :     return;
     717             :   }
     718           0 :   MOZ_ASSERT(initedChild == child);
     719           0 :   child->SendGamepadListenerAdded();
     720           0 :   mChannelChildren.AppendElement(child);
     721             : 
     722           0 :   if (gfx::VRManagerChild::IsCreated()) {
     723             :     // Construct VRManagerChannel and ask adding the connected
     724             :     // VR controllers to GamepadManager
     725           0 :     gfx::VRManagerChild* vm = gfx::VRManagerChild::Get();
     726           0 :     vm->SendControllerListenerAdded();
     727             :   }
     728             : }
     729             : 
     730             : //Override nsIIPCBackgroundChildCreateCallback
     731             : void
     732           0 : GamepadManager::ActorFailed()
     733             : {
     734           0 :   MOZ_CRASH("Gamepad IPC actor create failed!");
     735             : }
     736             : 
     737             : } // namespace dom
     738             : } // namespace mozilla

Generated by: LCOV version 1.13