Bug 1890793: Assert CallArgs::newTarget is not gray. r=spidermonkey-reviewers,sfink...
[gecko.git] / dom / gamepad / GamepadServiceTest.cpp
blob18998dcc4b00f90519ace8ea3611d758ec1da704
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 "GamepadServiceTest.h"
9 #include "mozilla/ErrorResult.h"
10 #include "mozilla/Unused.h"
12 #include "mozilla/dom/GamepadManager.h"
13 #include "mozilla/dom/GamepadPlatformService.h"
14 #include "mozilla/dom/GamepadServiceTestBinding.h"
15 #include "mozilla/dom/GamepadTestChannelChild.h"
17 #include "mozilla/ipc/BackgroundChild.h"
18 #include "mozilla/ipc/PBackgroundChild.h"
20 namespace mozilla::dom {
23 * Implementation of the test service. This is just to provide a simple binding
24 * of the GamepadService to JavaScript via WebIDL so that we can write
25 * Mochitests that add and remove fake gamepads, avoiding the platform-specific
26 * backends.
29 constexpr uint32_t kMaxButtons = 20;
30 constexpr uint32_t kMaxAxes = 10;
31 constexpr uint32_t kMaxHaptics = 2;
32 constexpr uint32_t kMaxLightIndicator = 2;
33 constexpr uint32_t kMaxTouchEvents = 4;
35 NS_IMPL_CYCLE_COLLECTION_INHERITED(GamepadServiceTest, DOMEventTargetHelper,
36 mWindow)
38 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(GamepadServiceTest)
39 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
41 NS_IMPL_ADDREF_INHERITED(GamepadServiceTest, DOMEventTargetHelper)
42 NS_IMPL_RELEASE_INHERITED(GamepadServiceTest, DOMEventTargetHelper)
44 // static
45 already_AddRefed<GamepadServiceTest> GamepadServiceTest::CreateTestService(
46 nsPIDOMWindowInner* aWindow) {
47 MOZ_ASSERT(aWindow);
48 RefPtr<GamepadServiceTest> service = new GamepadServiceTest(aWindow);
49 service->InitPBackgroundActor();
50 return service.forget();
53 void GamepadServiceTest::Shutdown() {
54 MOZ_ASSERT(!mShuttingDown);
55 mShuttingDown = true;
56 DestroyPBackgroundActor();
57 mWindow = nullptr;
60 GamepadServiceTest::GamepadServiceTest(nsPIDOMWindowInner* aWindow)
61 : mService(GamepadManager::GetService()),
62 mWindow(aWindow),
63 mEventNumber(0),
64 mShuttingDown(false),
65 mChild(nullptr) {}
67 GamepadServiceTest::~GamepadServiceTest() {
68 MOZ_ASSERT(mPromiseList.IsEmpty());
71 void GamepadServiceTest::InitPBackgroundActor() {
72 MOZ_ASSERT(!mChild);
74 ::mozilla::ipc::PBackgroundChild* actor =
75 ::mozilla::ipc::BackgroundChild::GetOrCreateForCurrentThread();
76 if (NS_WARN_IF(!actor)) {
77 MOZ_CRASH("Failed to create a PBackgroundChild actor!");
80 mChild = GamepadTestChannelChild::Create(this);
81 PGamepadTestChannelChild* initedChild =
82 actor->SendPGamepadTestChannelConstructor(mChild.get());
83 if (NS_WARN_IF(!initedChild)) {
84 MOZ_CRASH("Failed to create a PBackgroundChild actor!");
88 void GamepadServiceTest::ReplyGamepadHandle(uint32_t aPromiseId,
89 const GamepadHandle& aHandle) {
90 uint32_t handleSlot = AddGamepadHandle(aHandle);
92 RefPtr<Promise> p;
93 if (!mPromiseList.Get(aPromiseId, getter_AddRefs(p))) {
94 MOZ_CRASH("We should always have a promise.");
97 p->MaybeResolve(handleSlot);
98 mPromiseList.Remove(aPromiseId);
101 void GamepadServiceTest::DestroyPBackgroundActor() {
102 MOZ_ASSERT(mChild);
103 PGamepadTestChannelChild::Send__delete__(mChild);
104 mChild = nullptr;
107 already_AddRefed<Promise> GamepadServiceTest::AddGamepad(
108 const nsAString& aID, GamepadMappingType aMapping, GamepadHand aHand,
109 uint32_t aNumButtons, uint32_t aNumAxes, uint32_t aNumHaptics,
110 uint32_t aNumLightIndicator, uint32_t aNumTouchEvents, ErrorResult& aRv) {
111 if (aNumButtons > kMaxButtons || aNumAxes > kMaxAxes ||
112 aNumHaptics > kMaxHaptics || aNumLightIndicator > kMaxLightIndicator ||
113 aNumTouchEvents > kMaxTouchEvents) {
114 aRv.ThrowNotSupportedError("exceeded maximum hardware dimensions");
115 return nullptr;
118 if (mShuttingDown) {
119 aRv.ThrowInvalidStateError("Shutting down");
120 return nullptr;
123 // The values here are ignored, the value just can't be zero to avoid an
124 // assertion
125 GamepadHandle gamepadHandle{1, GamepadHandleKind::GamepadPlatformManager};
127 // Only VR controllers has displayID, we give 0 to the general gamepads.
128 GamepadAdded a(nsString(aID), aMapping, aHand, 0, aNumButtons, aNumAxes,
129 aNumHaptics, aNumLightIndicator, aNumTouchEvents);
130 GamepadChangeEventBody body(a);
131 GamepadChangeEvent e(gamepadHandle, body);
133 RefPtr<Promise> p = Promise::Create(mWindow->AsGlobal(), aRv);
134 if (aRv.Failed()) {
135 return nullptr;
138 uint32_t id = ++mEventNumber;
140 MOZ_ASSERT(!mPromiseList.Contains(id));
141 mPromiseList.InsertOrUpdate(id, RefPtr{p});
143 mChild->SendGamepadTestEvent(id, e);
145 return p.forget();
148 already_AddRefed<Promise> GamepadServiceTest::RemoveGamepad(
149 uint32_t aHandleSlot, ErrorResult& aRv) {
150 if (mShuttingDown) {
151 aRv.ThrowInvalidStateError("Shutting down");
152 return nullptr;
155 GamepadHandle gamepadHandle = GetHandleInSlot(aHandleSlot);
157 GamepadRemoved a;
158 GamepadChangeEventBody body(a);
159 GamepadChangeEvent e(gamepadHandle, body);
161 uint32_t id = ++mEventNumber;
163 RefPtr<Promise> p = Promise::Create(mWindow->AsGlobal(), aRv);
164 if (aRv.Failed()) {
165 return nullptr;
168 MOZ_ASSERT(!mPromiseList.Contains(id));
169 mPromiseList.InsertOrUpdate(id, RefPtr{p});
171 mChild->SendGamepadTestEvent(id, e);
172 return p.forget();
175 already_AddRefed<Promise> GamepadServiceTest::NewButtonEvent(
176 uint32_t aHandleSlot, uint32_t aButton, bool aPressed, bool aTouched,
177 ErrorResult& aRv) {
178 if (mShuttingDown) {
179 aRv.ThrowInvalidStateError("Shutting down");
180 return nullptr;
183 GamepadHandle gamepadHandle = GetHandleInSlot(aHandleSlot);
185 GamepadButtonInformation a(aButton, aPressed ? 1.0 : 0, aPressed, aTouched);
186 GamepadChangeEventBody body(a);
187 GamepadChangeEvent e(gamepadHandle, body);
189 uint32_t id = ++mEventNumber;
190 RefPtr<Promise> p = Promise::Create(mWindow->AsGlobal(), aRv);
191 if (aRv.Failed()) {
192 return nullptr;
195 MOZ_ASSERT(!mPromiseList.Contains(id));
196 mPromiseList.InsertOrUpdate(id, RefPtr{p});
197 mChild->SendGamepadTestEvent(id, e);
198 return p.forget();
201 already_AddRefed<Promise> GamepadServiceTest::NewButtonValueEvent(
202 uint32_t aHandleSlot, uint32_t aButton, bool aPressed, bool aTouched,
203 double aValue, ErrorResult& aRv) {
204 if (mShuttingDown) {
205 aRv.ThrowInvalidStateError("Shutting down");
206 return nullptr;
209 GamepadHandle gamepadHandle = GetHandleInSlot(aHandleSlot);
211 GamepadButtonInformation a(aButton, aValue, aPressed, aTouched);
212 GamepadChangeEventBody body(a);
213 GamepadChangeEvent e(gamepadHandle, body);
215 uint32_t id = ++mEventNumber;
216 RefPtr<Promise> p = Promise::Create(mWindow->AsGlobal(), aRv);
217 if (aRv.Failed()) {
218 return nullptr;
221 MOZ_ASSERT(!mPromiseList.Contains(id));
222 mPromiseList.InsertOrUpdate(id, RefPtr{p});
223 mChild->SendGamepadTestEvent(id, e);
224 return p.forget();
227 already_AddRefed<Promise> GamepadServiceTest::NewAxisMoveEvent(
228 uint32_t aHandleSlot, uint32_t aAxis, double aValue, ErrorResult& aRv) {
229 if (mShuttingDown) {
230 aRv.ThrowInvalidStateError("Shutting down");
231 return nullptr;
234 GamepadHandle gamepadHandle = GetHandleInSlot(aHandleSlot);
236 GamepadAxisInformation a(aAxis, aValue);
237 GamepadChangeEventBody body(a);
238 GamepadChangeEvent e(gamepadHandle, body);
240 uint32_t id = ++mEventNumber;
241 RefPtr<Promise> p = Promise::Create(mWindow->AsGlobal(), aRv);
242 if (aRv.Failed()) {
243 return nullptr;
246 MOZ_ASSERT(!mPromiseList.Contains(id));
247 mPromiseList.InsertOrUpdate(id, RefPtr{p});
248 mChild->SendGamepadTestEvent(id, e);
249 return p.forget();
252 already_AddRefed<Promise> GamepadServiceTest::NewPoseMove(
253 uint32_t aHandleSlot, const Nullable<Float32Array>& aOrient,
254 const Nullable<Float32Array>& aPos,
255 const Nullable<Float32Array>& aAngVelocity,
256 const Nullable<Float32Array>& aAngAcceleration,
257 const Nullable<Float32Array>& aLinVelocity,
258 const Nullable<Float32Array>& aLinAcceleration, ErrorResult& aRv) {
259 if (mShuttingDown) {
260 aRv.ThrowInvalidStateError("Shutting down");
261 return nullptr;
264 GamepadHandle gamepadHandle = GetHandleInSlot(aHandleSlot);
266 GamepadPoseState poseState;
267 poseState.flags = GamepadCapabilityFlags::Cap_Orientation |
268 GamepadCapabilityFlags::Cap_Position |
269 GamepadCapabilityFlags::Cap_AngularAcceleration |
270 GamepadCapabilityFlags::Cap_LinearAcceleration;
271 if (!aOrient.IsNull()) {
272 DebugOnly<bool> ok = aOrient.Value().CopyDataTo(poseState.orientation);
273 MOZ_ASSERT(
274 ok, "aOrient.Value().Length() != ArrayLength(poseState.orientation)");
275 poseState.isOrientationValid = true;
277 if (!aPos.IsNull()) {
278 DebugOnly<bool> ok = aPos.Value().CopyDataTo(poseState.position);
279 MOZ_ASSERT(ok, "aPos.Value().Length() != ArrayLength(poseState.position)");
280 poseState.isPositionValid = true;
282 if (!aAngVelocity.IsNull()) {
283 DebugOnly<bool> ok =
284 aAngVelocity.Value().CopyDataTo(poseState.angularVelocity);
285 MOZ_ASSERT(ok,
286 "aAngVelocity.Value().Length() != "
287 "ArrayLength(poseState.angularVelocity)");
289 if (!aAngAcceleration.IsNull()) {
290 DebugOnly<bool> ok =
291 aAngAcceleration.Value().CopyDataTo(poseState.angularAcceleration);
292 MOZ_ASSERT(ok,
293 "aAngAcceleration.Value().Length() != "
294 "ArrayLength(poseState.angularAcceleration)");
296 if (!aLinVelocity.IsNull()) {
297 DebugOnly<bool> ok =
298 aLinVelocity.Value().CopyDataTo(poseState.linearVelocity);
299 MOZ_ASSERT(ok,
300 "aLinVelocity.Value().Length() != "
301 "ArrayLength(poseState.linearVelocity)");
303 if (!aLinAcceleration.IsNull()) {
304 DebugOnly<bool> ok =
305 aLinAcceleration.Value().CopyDataTo(poseState.linearAcceleration);
306 MOZ_ASSERT(ok,
307 "aLinAcceleration.Value().Length() != "
308 "ArrayLength(poseState.linearAcceleration)");
311 GamepadPoseInformation a(poseState);
312 GamepadChangeEventBody body(a);
313 GamepadChangeEvent e(gamepadHandle, body);
315 uint32_t id = ++mEventNumber;
316 RefPtr<Promise> p = Promise::Create(mWindow->AsGlobal(), aRv);
317 if (aRv.Failed()) {
318 return nullptr;
321 MOZ_ASSERT(!mPromiseList.Contains(id));
322 mPromiseList.InsertOrUpdate(id, RefPtr{p});
323 mChild->SendGamepadTestEvent(id, e);
324 return p.forget();
327 already_AddRefed<Promise> GamepadServiceTest::NewTouch(
328 uint32_t aHandleSlot, uint32_t aTouchArrayIndex, uint32_t aTouchId,
329 uint8_t aSurfaceId, const Float32Array& aPos,
330 const Nullable<Float32Array>& aSurfDim, ErrorResult& aRv) {
331 if (mShuttingDown) {
332 aRv.ThrowInvalidStateError("Shutting down");
333 return nullptr;
336 GamepadHandle gamepadHandle = GetHandleInSlot(aHandleSlot);
338 GamepadTouchState touchState;
339 touchState.touchId = aTouchId;
340 touchState.surfaceId = aSurfaceId;
341 DebugOnly<bool> ok = aPos.CopyDataTo(touchState.position);
342 MOZ_ASSERT(ok, "aPos.Length() != ArrayLength(touchState.position)");
344 if (!aSurfDim.IsNull()) {
345 ok = aSurfDim.Value().CopyDataTo(touchState.surfaceDimensions);
346 MOZ_ASSERT(
347 ok, "aSurfDim.Length() != ArrayLength(touchState.surfaceDimensions)");
348 touchState.isSurfaceDimensionsValid = true;
351 GamepadTouchInformation a(aTouchArrayIndex, touchState);
352 GamepadChangeEventBody body(a);
353 GamepadChangeEvent e(gamepadHandle, body);
355 uint32_t id = ++mEventNumber;
356 RefPtr<Promise> p = Promise::Create(mWindow->AsGlobal(), aRv);
357 if (aRv.Failed()) {
358 return nullptr;
361 MOZ_ASSERT(!mPromiseList.Contains(id));
362 mPromiseList.InsertOrUpdate(id, RefPtr{p});
363 mChild->SendGamepadTestEvent(id, e);
364 return p.forget();
367 JSObject* GamepadServiceTest::WrapObject(JSContext* aCx,
368 JS::Handle<JSObject*> aGivenProto) {
369 return GamepadServiceTest_Binding::Wrap(aCx, this, aGivenProto);
372 uint32_t GamepadServiceTest::AddGamepadHandle(GamepadHandle aHandle) {
373 uint32_t handleSlot = mGamepadHandles.Length();
374 mGamepadHandles.AppendElement(aHandle);
375 return handleSlot;
378 void GamepadServiceTest::RemoveGamepadHandle(uint32_t aHandleSlot) {
379 MOZ_ASSERT(aHandleSlot < mGamepadHandles.Length());
380 return mGamepadHandles.RemoveElementAt(aHandleSlot);
383 GamepadHandle GamepadServiceTest::GetHandleInSlot(uint32_t aHandleSlot) const {
384 MOZ_ASSERT(aHandleSlot < mGamepadHandles.Length());
385 return mGamepadHandles.ElementAt(aHandleSlot);
388 } // namespace mozilla::dom