Skip to content

Commit 886c2c6

Browse files
author
Chris Martin
committed
Bug 1657404 - Implement a strongly-typed, service-dependent gamepad handle r=handyman,aklotz
Currently, the gamepad code uses a uint32_t as a handle and does some trickery with it by trying to create a unique ID and adding an offset to it for VR code. This can (and has) led to errors where the developer forgets to perform the arithmetic and sends the wrong number to the wrong manager. This change created a strongly-typed handle that remembers which service it belongs to. This should eliminate such accidents. Differential Revision: https://phabricator.services.mozilla.com/D96273
1 parent 9191a21 commit 886c2c6

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+855
-675
lines changed

dom/base/nsGlobalWindowInner.cpp

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@
116116
#include "mozilla/dom/EventTarget.h"
117117
#include "mozilla/dom/Fetch.h"
118118
#include "mozilla/dom/Gamepad.h"
119+
#include "mozilla/dom/GamepadHandle.h"
119120
#include "mozilla/dom/GamepadManager.h"
120121
#include "mozilla/dom/HashChangeEvent.h"
121122
#include "mozilla/dom/HashChangeEventBinding.h"
@@ -339,6 +340,7 @@ using namespace mozilla::dom;
339340
using namespace mozilla::dom::ipc;
340341
using mozilla::TimeDuration;
341342
using mozilla::TimeStamp;
343+
using mozilla::dom::GamepadHandle;
342344
using mozilla::dom::cache::CacheStorage;
343345

344346
#define FORWARD_TO_OUTER(method, args, err_rval) \
@@ -6535,7 +6537,7 @@ void nsGlobalWindowInner::AddSizeOfIncludingThis(
65356537
}
65366538
}
65376539

6538-
void nsGlobalWindowInner::AddGamepad(uint32_t aIndex, Gamepad* aGamepad) {
6540+
void nsGlobalWindowInner::AddGamepad(GamepadHandle aHandle, Gamepad* aGamepad) {
65396541
// Create the index we will present to content based on which indices are
65406542
// already taken, as required by the spec.
65416543
// https://w3c.github.io/gamepad/gamepad.html#widl-Gamepad-index
@@ -6545,17 +6547,17 @@ void nsGlobalWindowInner::AddGamepad(uint32_t aIndex, Gamepad* aGamepad) {
65456547
}
65466548
mGamepadIndexSet.Put(index);
65476549
aGamepad->SetIndex(index);
6548-
mGamepads.Put(aIndex, RefPtr{aGamepad});
6550+
mGamepads.Put(aHandle, RefPtr{aGamepad});
65496551
}
65506552

6551-
void nsGlobalWindowInner::RemoveGamepad(uint32_t aIndex) {
6553+
void nsGlobalWindowInner::RemoveGamepad(GamepadHandle aHandle) {
65526554
RefPtr<Gamepad> gamepad;
6553-
if (!mGamepads.Get(aIndex, getter_AddRefs(gamepad))) {
6555+
if (!mGamepads.Get(aHandle, getter_AddRefs(gamepad))) {
65546556
return;
65556557
}
65566558
// Free up the index we were using so it can be reused
65576559
mGamepadIndexSet.Remove(gamepad->Index());
6558-
mGamepads.Remove(aIndex);
6560+
mGamepads.Remove(aHandle);
65596561
}
65606562

65616563
void nsGlobalWindowInner::GetGamepads(nsTArray<RefPtr<Gamepad>>& aGamepads) {
@@ -6576,10 +6578,11 @@ void nsGlobalWindowInner::GetGamepads(nsTArray<RefPtr<Gamepad>>& aGamepads) {
65766578
}
65776579
}
65786580

6579-
already_AddRefed<Gamepad> nsGlobalWindowInner::GetGamepad(uint32_t aIndex) {
6581+
already_AddRefed<Gamepad> nsGlobalWindowInner::GetGamepad(
6582+
GamepadHandle aHandle) {
65806583
RefPtr<Gamepad> gamepad;
65816584

6582-
if (mGamepads.Get(aIndex, getter_AddRefs(gamepad))) {
6585+
if (mGamepads.Get(aHandle, getter_AddRefs(gamepad))) {
65836586
return gamepad.forget();
65846587
}
65856588

dom/base/nsGlobalWindowInner.h

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
#include "mozilla/dom/BindingDeclarations.h"
3636
#include "mozilla/dom/ChromeMessageBroadcaster.h"
3737
#include "mozilla/dom/DebuggerNotificationManager.h"
38+
#include "mozilla/dom/GamepadHandle.h"
3839
#include "mozilla/dom/Location.h"
3940
#include "mozilla/dom/NavigatorBinding.h"
4041
#include "mozilla/dom/StorageEvent.h"
@@ -491,10 +492,12 @@ class nsGlobalWindowInner final : public mozilla::dom::EventTarget,
491492
const double aDuration);
492493

493494
// Inner windows only.
494-
void AddGamepad(uint32_t aIndex, mozilla::dom::Gamepad* aGamepad);
495-
void RemoveGamepad(uint32_t aIndex);
495+
void AddGamepad(mozilla::dom::GamepadHandle aHandle,
496+
mozilla::dom::Gamepad* aGamepad);
497+
void RemoveGamepad(mozilla::dom::GamepadHandle aHandle);
496498
void GetGamepads(nsTArray<RefPtr<mozilla::dom::Gamepad>>& aGamepads);
497-
already_AddRefed<mozilla::dom::Gamepad> GetGamepad(uint32_t aIndex);
499+
already_AddRefed<mozilla::dom::Gamepad> GetGamepad(
500+
mozilla::dom::GamepadHandle aHandle);
498501
void SetHasSeenGamepadInput(bool aHasSeen);
499502
bool HasSeenGamepadInput();
500503
void SyncGamepadState();
@@ -1323,7 +1326,9 @@ class nsGlobalWindowInner final : public mozilla::dom::EventTarget,
13231326
bool mHintedWasLoading : 1;
13241327

13251328
nsCheapSet<nsUint32HashKey> mGamepadIndexSet;
1326-
nsRefPtrHashtable<nsUint32HashKey, mozilla::dom::Gamepad> mGamepads;
1329+
nsRefPtrHashtable<nsGenericHashKey<mozilla::dom::GamepadHandle>,
1330+
mozilla::dom::Gamepad>
1331+
mGamepads;
13271332

13281333
RefPtr<nsScreen> mScreen;
13291334

dom/gamepad/Gamepad.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,14 +36,14 @@ void Gamepad::UpdateTimestamp() {
3636
}
3737

3838
Gamepad::Gamepad(nsISupports* aParent, const nsAString& aID, int32_t aIndex,
39-
uint32_t aHashKey, GamepadMappingType aMapping,
39+
GamepadHandle aHandle, GamepadMappingType aMapping,
4040
GamepadHand aHand, uint32_t aDisplayID, uint32_t aNumButtons,
4141
uint32_t aNumAxes, uint32_t aNumHaptics,
4242
uint32_t aNumLightIndicator, uint32_t aNumTouchEvents)
4343
: mParent(aParent),
4444
mID(aID),
4545
mIndex(aIndex),
46-
mHashKey(aHashKey),
46+
mHandle(aHandle),
4747
mDisplayId(aDisplayID),
4848
mTouchIdHashValue(0),
4949
mMapping(aMapping),
@@ -59,11 +59,11 @@ Gamepad::Gamepad(nsISupports* aParent, const nsAString& aID, int32_t aIndex,
5959
mPose = new GamepadPose(aParent);
6060
for (uint32_t i = 0; i < aNumHaptics; ++i) {
6161
mHapticActuators.AppendElement(
62-
new GamepadHapticActuator(mParent, mHashKey, i));
62+
new GamepadHapticActuator(mParent, mHandle, i));
6363
}
6464
for (uint32_t i = 0; i < aNumLightIndicator; ++i) {
6565
mLightIndicators.AppendElement(
66-
new GamepadLightIndicator(mParent, mHashKey, i));
66+
new GamepadLightIndicator(mParent, mHandle, i));
6767
}
6868
for (uint32_t i = 0; i < aNumTouchEvents; ++i) {
6969
mTouchEvents.AppendElement(new GamepadTouch(mParent));
@@ -177,7 +177,7 @@ void Gamepad::SyncState(Gamepad* aOther) {
177177

178178
already_AddRefed<Gamepad> Gamepad::Clone(nsISupports* aParent) {
179179
RefPtr<Gamepad> out =
180-
new Gamepad(aParent, mID, mIndex, mHashKey, mMapping, mHand, mDisplayId,
180+
new Gamepad(aParent, mID, mIndex, mHandle, mMapping, mHand, mDisplayId,
181181
mButtons.Length(), mAxes.Length(), mHapticActuators.Length(),
182182
mLightIndicators.Length(), mTouchEvents.Length());
183183
out->SyncState(this);

dom/gamepad/Gamepad.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
#include "mozilla/dom/GamepadBinding.h"
1111
#include "mozilla/dom/GamepadButton.h"
12+
#include "mozilla/dom/GamepadHandle.h"
1213
#include "mozilla/dom/GamepadPose.h"
1314
#include "mozilla/dom/GamepadHapticActuator.h"
1415
#include "mozilla/dom/GamepadLightIndicator.h"
@@ -40,7 +41,7 @@ const int kRightStickYAxis = 3;
4041
class Gamepad final : public nsISupports, public nsWrapperCache {
4142
public:
4243
Gamepad(nsISupports* aParent, const nsAString& aID, int32_t aIndex,
43-
uint32_t aHashKey, GamepadMappingType aMapping, GamepadHand aHand,
44+
GamepadHandle aHandle, GamepadMappingType aMapping, GamepadHand aHand,
4445
uint32_t aDisplayID, uint32_t aNumButtons, uint32_t aNumAxes,
4546
uint32_t aNumHaptics, uint32_t aNumLightIndicator,
4647
uint32_t aNumTouchEvents);
@@ -84,8 +85,6 @@ class Gamepad final : public nsISupports, public nsWrapperCache {
8485

8586
int32_t Index() const { return mIndex; }
8687

87-
uint32_t HashKey() const { return mHashKey; }
88-
8988
void GetButtons(nsTArray<RefPtr<GamepadButton>>& aButtons) const {
9089
aButtons = mButtons.Clone();
9190
}
@@ -108,6 +107,8 @@ class Gamepad final : public nsISupports, public nsWrapperCache {
108107
aTouchEvents = mTouchEvents.Clone();
109108
}
110109

110+
GamepadHandle GetHandle() const { return mHandle; }
111+
111112
private:
112113
virtual ~Gamepad() = default;
113114
void UpdateTimestamp();
@@ -117,7 +118,7 @@ class Gamepad final : public nsISupports, public nsWrapperCache {
117118
nsString mID;
118119
int32_t mIndex;
119120
// the gamepad hash key in GamepadManager
120-
uint32_t mHashKey;
121+
GamepadHandle mHandle;
121122
uint32_t mDisplayId;
122123
uint32_t mTouchIdHashValue;
123124
// The mapping in use.

dom/gamepad/GamepadHandle.cpp

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
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
5+
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6+
7+
#include "GamepadHandle.h"
8+
#include "mozilla/Assertions.h"
9+
#include "mozilla/HashFunctions.h"
10+
11+
namespace mozilla::dom {
12+
13+
GamepadHandle::GamepadHandle(uint32_t aValue, GamepadHandleKind aKind)
14+
: mValue(aValue), mKind(aKind) {
15+
MOZ_RELEASE_ASSERT(mValue);
16+
}
17+
18+
GamepadHandleKind GamepadHandle::GetKind() const { return mKind; }
19+
20+
PLDHashNumber GamepadHandle::Hash() const {
21+
return HashGeneric(mValue, uint8_t(mKind));
22+
}
23+
24+
bool operator==(const GamepadHandle& a, const GamepadHandle& b) {
25+
return (a.mValue == b.mValue) && (a.mKind == b.mKind);
26+
}
27+
28+
bool operator!=(const GamepadHandle& a, const GamepadHandle& b) {
29+
return !(a == b);
30+
}
31+
32+
bool operator<(const GamepadHandle& a, const GamepadHandle& b) {
33+
if (a.mKind == b.mKind) {
34+
return a.mValue < b.mValue;
35+
}
36+
// Arbitrarily order them by kind
37+
return uint8_t(a.mKind) < uint8_t(b.mKind);
38+
}
39+
40+
} // namespace mozilla::dom

dom/gamepad/GamepadHandle.h

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
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
5+
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6+
7+
// This file defines a strongly-typed opaque gamepad handle
8+
//
9+
// The handle is designed to be copied around and passed over IPC. It keeps
10+
// track of which "provider" created the handle so it can ensure that
11+
// providers are never mixed. It also allows each provider to have its own
12+
// algorithm for generating gamepad IDs, since the VR and Platform services
13+
// do it differently.
14+
15+
#ifndef mozilla_dom_gamepad_GamepadHandle_h
16+
#define mozilla_dom_gamepad_GamepadHandle_h
17+
#include "mozilla/Tuple.h"
18+
#include "PLDHashTable.h"
19+
#include <type_traits>
20+
#include <cinttypes>
21+
22+
namespace IPC {
23+
24+
template <class>
25+
struct ParamTraits;
26+
27+
} // namespace IPC
28+
29+
namespace mozilla::gfx {
30+
31+
class VRDisplayClient;
32+
class VRManager;
33+
34+
} // namespace mozilla::gfx
35+
36+
namespace mozilla::dom {
37+
38+
class GamepadPlatformService;
39+
class GamepadServiceTest;
40+
class XRInputSource;
41+
42+
// The "kind" of a gamepad handle is based on which provider created it
43+
enum class GamepadHandleKind : uint8_t {
44+
GamepadPlatformManager,
45+
VR,
46+
};
47+
48+
class GamepadHandle {
49+
public:
50+
// Allow handle to be passed around as a simple object
51+
GamepadHandle() = default;
52+
GamepadHandle(const GamepadHandle&) = default;
53+
GamepadHandle& operator=(const GamepadHandle&) = default;
54+
55+
// Helps code know which manager to send requests to
56+
GamepadHandleKind GetKind() const;
57+
58+
// Define operators so the handle can compared and stored in maps
59+
friend bool operator==(const GamepadHandle& a, const GamepadHandle& b);
60+
friend bool operator!=(const GamepadHandle& a, const GamepadHandle& b);
61+
friend bool operator<(const GamepadHandle& a, const GamepadHandle& b);
62+
63+
PLDHashNumber Hash() const;
64+
65+
private:
66+
explicit GamepadHandle(uint32_t aValue, GamepadHandleKind aKind);
67+
uint32_t GetValue() const { return mValue; }
68+
69+
uint32_t mValue{0};
70+
GamepadHandleKind mKind{GamepadHandleKind::GamepadPlatformManager};
71+
72+
// These are the classes that are "gamepad managers". They are allowed to
73+
// create new handles and inspect their actual value
74+
friend class mozilla::dom::GamepadPlatformService;
75+
friend class mozilla::dom::GamepadServiceTest;
76+
friend class mozilla::dom::XRInputSource;
77+
friend class mozilla::gfx::VRDisplayClient;
78+
friend class mozilla::gfx::VRManager;
79+
80+
// Allow IPDL to serialize us
81+
friend struct IPC::ParamTraits<mozilla::dom::GamepadHandle>;
82+
};
83+
84+
static_assert(std::is_trivially_copyable<GamepadHandle>::value,
85+
"GamepadHandle must be trivially copyable");
86+
87+
} // namespace mozilla::dom
88+
89+
#endif // mozilla_dom_gamepad_GamepadHandle_h

dom/gamepad/GamepadHapticActuator.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,10 @@ NS_INTERFACE_MAP_END
2121
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(GamepadHapticActuator, mParent)
2222

2323
GamepadHapticActuator::GamepadHapticActuator(nsISupports* aParent,
24-
uint32_t aGamepadId,
24+
GamepadHandle aGamepadHandle,
2525
uint32_t aIndex)
2626
: mParent(aParent),
27-
mGamepadId(aGamepadId),
27+
mGamepadHandle(aGamepadHandle),
2828
mType(GamepadHapticActuatorType::Vibration),
2929
mIndex(aIndex) {}
3030

@@ -55,7 +55,7 @@ already_AddRefed<Promise> GamepadHapticActuator::Pulse(double aValue,
5555
switch (mType) {
5656
case GamepadHapticActuatorType::Vibration: {
5757
RefPtr<Promise> promise = gamepadManager->VibrateHaptic(
58-
mGamepadId, mIndex, value, duration, global, aRv);
58+
mGamepadHandle, mIndex, value, duration, global, aRv);
5959
if (!promise) {
6060
return nullptr;
6161
}
@@ -72,7 +72,7 @@ already_AddRefed<Promise> GamepadHapticActuator::Pulse(double aValue,
7272
GamepadHapticActuatorType GamepadHapticActuator::Type() const { return mType; }
7373

7474
void GamepadHapticActuator::Set(const GamepadHapticActuator* aOther) {
75-
mGamepadId = aOther->mGamepadId;
75+
mGamepadHandle = aOther->mGamepadHandle;
7676
mType = aOther->mType;
7777
mIndex = aOther->mIndex;
7878
}

dom/gamepad/GamepadHapticActuator.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,15 @@
1111
#include "nsWrapperCache.h"
1212
#include "mozilla/dom/GamepadHapticActuatorBinding.h"
1313
#include "mozilla/dom/Gamepad.h"
14+
#include "mozilla/dom/GamepadHandle.h"
1415

1516
namespace mozilla {
1617
namespace dom {
1718
class Promise;
1819

1920
class GamepadHapticActuator : public nsISupports, public nsWrapperCache {
2021
public:
21-
GamepadHapticActuator(nsISupports* aParent, uint32_t aGamepadId,
22+
GamepadHapticActuator(nsISupports* aParent, GamepadHandle aGamepadHandle,
2223
uint32_t aIndex);
2324

2425
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
@@ -41,7 +42,7 @@ class GamepadHapticActuator : public nsISupports, public nsWrapperCache {
4142

4243
protected:
4344
nsCOMPtr<nsISupports> mParent;
44-
uint32_t mGamepadId;
45+
GamepadHandle mGamepadHandle;
4546
GamepadHapticActuatorType mType;
4647
uint32_t mIndex;
4748
};

0 commit comments

Comments
 (0)