Bug 1842773 - Part 5: Add ArrayBuffer.prototype.{maxByteLength,resizable} getters...
[gecko.git] / dom / gamepad / Gamepad.cpp
blobf64bb7f4eb4d005db991a1ba393c96110fe50128
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/. */
7 #include "Gamepad.h"
8 #include "nsPIDOMWindow.h"
9 #include "nsTArray.h"
10 #include "nsVariant.h"
11 #include "mozilla/StaticPrefs_dom.h"
12 #include "mozilla/dom/GamepadBinding.h"
14 namespace mozilla::dom {
16 NS_IMPL_CYCLE_COLLECTING_ADDREF(Gamepad)
17 NS_IMPL_CYCLE_COLLECTING_RELEASE(Gamepad)
19 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Gamepad)
20 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
21 NS_INTERFACE_MAP_ENTRY(nsISupports)
22 NS_INTERFACE_MAP_END
24 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(Gamepad, mParent, mButtons, mPose,
25 mHapticActuators, mLightIndicators,
26 mTouchEvents)
28 void Gamepad::UpdateTimestamp() {
29 nsCOMPtr<nsPIDOMWindowInner> newWindow(do_QueryInterface(mParent));
30 if (newWindow) {
31 Performance* perf = newWindow->GetPerformance();
32 if (perf) {
33 mTimestamp = perf->Now();
38 Gamepad::Gamepad(nsISupports* aParent, const nsAString& aID, int32_t aIndex,
39 GamepadHandle aHandle, GamepadMappingType aMapping,
40 GamepadHand aHand, uint32_t aDisplayID, uint32_t aNumButtons,
41 uint32_t aNumAxes, uint32_t aNumHaptics,
42 uint32_t aNumLightIndicator, uint32_t aNumTouchEvents)
43 : mParent(aParent),
44 mID(aID),
45 mIndex(aIndex),
46 mHandle(aHandle),
47 mDisplayId(aDisplayID),
48 mTouchIdHashValue(0),
49 mMapping(aMapping),
50 mHand(aHand),
51 mConnected(true),
52 mButtons(aNumButtons),
53 mAxes(aNumAxes),
54 mTimestamp(0) {
55 for (unsigned i = 0; i < aNumButtons; i++) {
56 mButtons.InsertElementAt(i, new GamepadButton(mParent));
58 mAxes.InsertElementsAt(0, aNumAxes, 0.0f);
59 mPose = new GamepadPose(aParent);
60 for (uint32_t i = 0; i < aNumHaptics; ++i) {
61 mHapticActuators.AppendElement(
62 new GamepadHapticActuator(mParent, mHandle, i));
64 for (uint32_t i = 0; i < aNumLightIndicator; ++i) {
65 mLightIndicators.AppendElement(
66 new GamepadLightIndicator(mParent, mHandle, i));
68 for (uint32_t i = 0; i < aNumTouchEvents; ++i) {
69 mTouchEvents.AppendElement(new GamepadTouch(mParent));
72 // Mapping touchId(0) to touchIdHash(0) by default.
73 mTouchIdHash.InsertOrUpdate(0, mTouchIdHashValue);
74 ++mTouchIdHashValue;
75 UpdateTimestamp();
78 void Gamepad::SetIndex(int32_t aIndex) { mIndex = aIndex; }
80 void Gamepad::SetConnected(bool aConnected) { mConnected = aConnected; }
82 void Gamepad::SetButton(uint32_t aButton, bool aPressed, bool aTouched,
83 double aValue) {
84 MOZ_ASSERT(aButton < mButtons.Length());
85 mButtons[aButton]->SetPressed(aPressed);
86 mButtons[aButton]->SetTouched(aTouched);
87 mButtons[aButton]->SetValue(aValue);
88 UpdateTimestamp();
91 void Gamepad::SetAxis(uint32_t aAxis, double aValue) {
92 MOZ_ASSERT(aAxis < mAxes.Length());
93 if (mAxes[aAxis] != aValue) {
94 mAxes[aAxis] = aValue;
95 Gamepad_Binding::ClearCachedAxesValue(this);
97 UpdateTimestamp();
100 void Gamepad::SetPose(const GamepadPoseState& aPose) {
101 mPose->SetPoseState(aPose);
102 UpdateTimestamp();
105 void Gamepad::SetLightIndicatorType(uint32_t aLightIndex,
106 GamepadLightIndicatorType aType) {
107 mLightIndicators[aLightIndex]->SetType(aType);
108 UpdateTimestamp();
111 void Gamepad::SetTouchEvent(uint32_t aTouchIndex,
112 const GamepadTouchState& aTouch) {
113 if (aTouchIndex >= mTouchEvents.Length()) {
114 MOZ_CRASH("Touch index exceeds the event array.");
115 return;
118 // Handling cross-origin tracking.
119 GamepadTouchState touchState(aTouch);
120 touchState.touchId = mTouchIdHash.LookupOrInsertWith(
121 touchState.touchId, [&] { return mTouchIdHashValue++; });
122 mTouchEvents[aTouchIndex]->SetTouchState(touchState);
123 UpdateTimestamp();
126 void Gamepad::SetHand(GamepadHand aHand) { mHand = aHand; }
128 void Gamepad::SyncState(Gamepad* aOther) {
129 if (mButtons.Length() != aOther->mButtons.Length() ||
130 mAxes.Length() != aOther->mAxes.Length()) {
131 return;
134 mConnected = aOther->mConnected;
135 for (uint32_t i = 0; i < mButtons.Length(); ++i) {
136 mButtons[i]->SetPressed(aOther->mButtons[i]->Pressed());
137 mButtons[i]->SetTouched(aOther->mButtons[i]->Touched());
138 mButtons[i]->SetValue(aOther->mButtons[i]->Value());
141 bool changed = false;
142 for (uint32_t i = 0; i < mAxes.Length(); ++i) {
143 changed = changed || (mAxes[i] != aOther->mAxes[i]);
144 mAxes[i] = aOther->mAxes[i];
146 if (changed) {
147 Gamepad_Binding::ClearCachedAxesValue(this);
150 if (StaticPrefs::dom_gamepad_extensions_enabled()) {
151 MOZ_ASSERT(aOther->GetPose());
152 mPose->SetPoseState(aOther->GetPose()->GetPoseState());
153 mHand = aOther->Hand();
154 for (uint32_t i = 0; i < mHapticActuators.Length(); ++i) {
155 mHapticActuators[i]->Set(aOther->mHapticActuators[i]);
158 if (StaticPrefs::dom_gamepad_extensions_lightindicator()) {
159 for (uint32_t i = 0; i < mLightIndicators.Length(); ++i) {
160 mLightIndicators[i]->Set(aOther->mLightIndicators[i]);
163 if (StaticPrefs::dom_gamepad_extensions_multitouch()) {
164 for (uint32_t i = 0; i < mTouchEvents.Length(); ++i) {
165 mTouchEvents[i]->Set(aOther->mTouchEvents[i]);
170 UpdateTimestamp();
173 already_AddRefed<Gamepad> Gamepad::Clone(nsISupports* aParent) {
174 RefPtr<Gamepad> out =
175 new Gamepad(aParent, mID, mIndex, mHandle, mMapping, mHand, mDisplayId,
176 mButtons.Length(), mAxes.Length(), mHapticActuators.Length(),
177 mLightIndicators.Length(), mTouchEvents.Length());
178 out->SyncState(this);
179 return out.forget();
182 /* virtual */
183 JSObject* Gamepad::WrapObject(JSContext* aCx,
184 JS::Handle<JSObject*> aGivenProto) {
185 return Gamepad_Binding::Wrap(aCx, this, aGivenProto);
188 } // namespace mozilla::dom