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/VRServiceTest.h"
8 #include "mozilla/dom/VRServiceTestBinding.h"
9 #include "mozilla/dom/GamepadPoseState.h"
10 #include "mozilla/dom/Promise.h"
11 #include "VRManagerChild.h"
12 #include "VRPuppetCommandBuffer.h"
13 #include <type_traits>
14 
15 namespace mozilla {
16 using namespace gfx;
17 namespace dom {
18 
19 NS_IMPL_CYCLE_COLLECTION_INHERITED(VRMockDisplay, DOMEventTargetHelper,
20                                    mVRServiceTest)
21 
22 NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED_0(VRMockDisplay,
23                                                DOMEventTargetHelper)
24 
25 namespace {
26 template <class T>
ReadFloat32Array(T & aDestination,const Float32Array & aSource,ErrorResult & aRv)27 bool ReadFloat32Array(T& aDestination, const Float32Array& aSource,
28                       ErrorResult& aRv) {
29   constexpr size_t length = std::extent<T>::value;
30   aSource.ComputeState();
31   if (aSource.Length() != length) {
32     aRv.Throw(NS_ERROR_INVALID_ARG);
33     // We don't want to MOZ_ASSERT here, as that would cause the
34     // browser to crash, making it difficult to debug the problem
35     // in JS code calling this API.
36     return false;
37   }
38   for (size_t i = 0; i < length; i++) {
39     aDestination[i] = aSource.Data()[i];
40   }
41   return true;
42 }
43 };  // anonymous namespace
44 
VRMockDisplay(VRServiceTest * aVRServiceTest)45 VRMockDisplay::VRMockDisplay(VRServiceTest* aVRServiceTest)
46     : DOMEventTargetHelper(aVRServiceTest->GetOwner()),
47       mVRServiceTest(aVRServiceTest) {}
48 
WrapObject(JSContext * aCx,JS::Handle<JSObject * > aGivenProto)49 JSObject* VRMockDisplay::WrapObject(JSContext* aCx,
50                                     JS::Handle<JSObject*> aGivenProto) {
51   return VRMockDisplay_Binding::Wrap(aCx, this, aGivenProto);
52 }
53 
SensorState() const54 VRHMDSensorState& VRMockDisplay::SensorState() const {
55   return mVRServiceTest->SystemState().sensorState;
56 }
57 
DisplayState() const58 VRDisplayState& VRMockDisplay::DisplayState() const {
59   return mVRServiceTest->SystemState().displayState;
60 }
61 
Clear()62 void VRMockDisplay::Clear() {
63   VRDisplayState& displayState = DisplayState();
64   displayState.Clear();
65   VRHMDSensorState& sensorState = SensorState();
66   sensorState.Clear();
67 }
68 
Create()69 void VRMockDisplay::Create() {
70   Clear();
71   VRDisplayState& state = DisplayState();
72 
73   strncpy(state.displayName, "Puppet HMD", kVRDisplayNameMaxLen);
74   state.eightCC = GFX_VR_EIGHTCC('P', 'u', 'p', 'p', 'e', 't', ' ', ' ');
75   state.isConnected = true;
76   state.isMounted = false;
77   state.capabilityFlags = VRDisplayCapabilityFlags::Cap_None |
78                           VRDisplayCapabilityFlags::Cap_Orientation |
79                           VRDisplayCapabilityFlags::Cap_Position |
80                           VRDisplayCapabilityFlags::Cap_External |
81                           VRDisplayCapabilityFlags::Cap_Present |
82                           VRDisplayCapabilityFlags::Cap_StageParameters |
83                           VRDisplayCapabilityFlags::Cap_MountDetection |
84                           VRDisplayCapabilityFlags::Cap_ImmersiveVR;
85   state.blendMode = VRDisplayBlendMode::Opaque;
86 
87   // 1836 x 2040 resolution is arbitrary and can be overridden.
88   // This default resolution was chosen to be within range of a
89   // typical VR eye buffer size.  This value is derived by
90   // scaling a 1080x1200 per-eye panel resolution by the
91   // commonly used pre-lens-distortion pass scaling factor of 1.7x.
92   // 1.7x is commonly used in HMD's employing fresnel lenses to ensure
93   // a sufficient fragment shading rate in the peripheral area of the
94   // post-warp eye buffers.
95   state.eyeResolution.width = 1836;   // 1080 * 1.7
96   state.eyeResolution.height = 2040;  // 1200 * 1.7
97 
98   for (uint32_t eye = 0; eye < VRDisplayState::NumEyes; ++eye) {
99     state.eyeTranslation[eye].x = 0.0f;
100     state.eyeTranslation[eye].y = 0.0f;
101     state.eyeTranslation[eye].z = 0.0f;
102     state.eyeFOV[eye] = gfx::VRFieldOfView(45.0, 45.0, 45.0, 45.0);
103   }
104 
105   // default: 1m x 1m space, 0.75m high in seated position
106   state.stageSize.width = 1.0f;
107   state.stageSize.height = 1.0f;
108 
109   state.sittingToStandingTransform[0] = 1.0f;
110   state.sittingToStandingTransform[1] = 0.0f;
111   state.sittingToStandingTransform[2] = 0.0f;
112   state.sittingToStandingTransform[3] = 0.0f;
113 
114   state.sittingToStandingTransform[4] = 0.0f;
115   state.sittingToStandingTransform[5] = 1.0f;
116   state.sittingToStandingTransform[6] = 0.0f;
117   state.sittingToStandingTransform[7] = 0.0f;
118 
119   state.sittingToStandingTransform[8] = 0.0f;
120   state.sittingToStandingTransform[9] = 0.0f;
121   state.sittingToStandingTransform[10] = 1.0f;
122   state.sittingToStandingTransform[11] = 0.0f;
123 
124   state.sittingToStandingTransform[12] = 0.0f;
125   state.sittingToStandingTransform[13] = 0.75f;
126   state.sittingToStandingTransform[14] = 0.0f;
127   state.sittingToStandingTransform[15] = 1.0f;
128 
129   VRHMDSensorState& sensorState = SensorState();
130   gfx::Quaternion rot;
131   sensorState.flags |= VRDisplayCapabilityFlags::Cap_Orientation;
132   sensorState.pose.orientation[0] = rot.x;
133   sensorState.pose.orientation[1] = rot.y;
134   sensorState.pose.orientation[2] = rot.z;
135   sensorState.pose.orientation[3] = rot.w;
136   sensorState.pose.angularVelocity[0] = 0.0f;
137   sensorState.pose.angularVelocity[1] = 0.0f;
138   sensorState.pose.angularVelocity[2] = 0.0f;
139 
140   sensorState.flags |= VRDisplayCapabilityFlags::Cap_Position;
141   sensorState.pose.position[0] = 0.0f;
142   sensorState.pose.position[1] = 0.0f;
143   sensorState.pose.position[2] = 0.0f;
144   sensorState.pose.linearVelocity[0] = 0.0f;
145   sensorState.pose.linearVelocity[1] = 0.0f;
146   sensorState.pose.linearVelocity[2] = 0.0f;
147 }
148 
SetConnected(bool aConnected)149 void VRMockDisplay::SetConnected(bool aConnected) {
150   DisplayState().isConnected = aConnected;
151 }
Connected() const152 bool VRMockDisplay::Connected() const { return DisplayState().isConnected; }
153 
SetMounted(bool aMounted)154 void VRMockDisplay::SetMounted(bool aMounted) {
155   DisplayState().isMounted = aMounted;
156 }
157 
Mounted() const158 bool VRMockDisplay::Mounted() const { return DisplayState().isMounted; }
159 
SetCapFlag(VRDisplayCapabilityFlags aFlag,bool aEnabled)160 void VRMockDisplay::SetCapFlag(VRDisplayCapabilityFlags aFlag, bool aEnabled) {
161   if (aEnabled) {
162     DisplayState().capabilityFlags |= aFlag;
163   } else {
164     DisplayState().capabilityFlags &= ~aFlag;
165   }
166 }
GetCapFlag(VRDisplayCapabilityFlags aFlag) const167 bool VRMockDisplay::GetCapFlag(VRDisplayCapabilityFlags aFlag) const {
168   return ((DisplayState().capabilityFlags & aFlag) !=
169           VRDisplayCapabilityFlags::Cap_None);
170 }
171 
SetCapPosition(bool aEnabled)172 void VRMockDisplay::SetCapPosition(bool aEnabled) {
173   SetCapFlag(VRDisplayCapabilityFlags::Cap_Position, aEnabled);
174 }
175 
SetCapOrientation(bool aEnabled)176 void VRMockDisplay::SetCapOrientation(bool aEnabled) {
177   SetCapFlag(VRDisplayCapabilityFlags::Cap_Orientation, aEnabled);
178 }
179 
SetCapPresent(bool aEnabled)180 void VRMockDisplay::SetCapPresent(bool aEnabled) {
181   SetCapFlag(VRDisplayCapabilityFlags::Cap_Present, aEnabled);
182 }
183 
SetCapExternal(bool aEnabled)184 void VRMockDisplay::SetCapExternal(bool aEnabled) {
185   SetCapFlag(VRDisplayCapabilityFlags::Cap_External, aEnabled);
186 }
187 
SetCapAngularAcceleration(bool aEnabled)188 void VRMockDisplay::SetCapAngularAcceleration(bool aEnabled) {
189   SetCapFlag(VRDisplayCapabilityFlags::Cap_AngularAcceleration, aEnabled);
190 }
191 
SetCapLinearAcceleration(bool aEnabled)192 void VRMockDisplay::SetCapLinearAcceleration(bool aEnabled) {
193   SetCapFlag(VRDisplayCapabilityFlags::Cap_LinearAcceleration, aEnabled);
194 }
195 
SetCapStageParameters(bool aEnabled)196 void VRMockDisplay::SetCapStageParameters(bool aEnabled) {
197   SetCapFlag(VRDisplayCapabilityFlags::Cap_StageParameters, aEnabled);
198 }
199 
SetCapMountDetection(bool aEnabled)200 void VRMockDisplay::SetCapMountDetection(bool aEnabled) {
201   SetCapFlag(VRDisplayCapabilityFlags::Cap_MountDetection, aEnabled);
202 }
203 
SetCapPositionEmulated(bool aEnabled)204 void VRMockDisplay::SetCapPositionEmulated(bool aEnabled) {
205   SetCapFlag(VRDisplayCapabilityFlags::Cap_PositionEmulated, aEnabled);
206 }
207 
SetEyeFOV(VREye aEye,double aUpDegree,double aRightDegree,double aDownDegree,double aLeftDegree)208 void VRMockDisplay::SetEyeFOV(VREye aEye, double aUpDegree, double aRightDegree,
209                               double aDownDegree, double aLeftDegree) {
210   gfx::VRDisplayState::Eye eye = aEye == VREye::Left
211                                      ? gfx::VRDisplayState::Eye_Left
212                                      : gfx::VRDisplayState::Eye_Right;
213   VRDisplayState& state = DisplayState();
214   state.eyeFOV[eye] =
215       gfx::VRFieldOfView(aUpDegree, aRightDegree, aDownDegree, aLeftDegree);
216 }
217 
SetEyeOffset(VREye aEye,double aOffsetX,double aOffsetY,double aOffsetZ)218 void VRMockDisplay::SetEyeOffset(VREye aEye, double aOffsetX, double aOffsetY,
219                                  double aOffsetZ) {
220   gfx::VRDisplayState::Eye eye = aEye == VREye::Left
221                                      ? gfx::VRDisplayState::Eye_Left
222                                      : gfx::VRDisplayState::Eye_Right;
223   VRDisplayState& state = DisplayState();
224   state.eyeTranslation[eye].x = (float)aOffsetX;
225   state.eyeTranslation[eye].y = (float)aOffsetY;
226   state.eyeTranslation[eye].z = (float)aOffsetZ;
227 }
228 
CapPosition() const229 bool VRMockDisplay::CapPosition() const {
230   return GetCapFlag(VRDisplayCapabilityFlags::Cap_Position);
231 }
232 
CapOrientation() const233 bool VRMockDisplay::CapOrientation() const {
234   return GetCapFlag(VRDisplayCapabilityFlags::Cap_Orientation);
235 }
236 
CapPresent() const237 bool VRMockDisplay::CapPresent() const {
238   return GetCapFlag(VRDisplayCapabilityFlags::Cap_Present);
239 }
240 
CapExternal() const241 bool VRMockDisplay::CapExternal() const {
242   return GetCapFlag(VRDisplayCapabilityFlags::Cap_External);
243 }
244 
CapAngularAcceleration() const245 bool VRMockDisplay::CapAngularAcceleration() const {
246   return GetCapFlag(VRDisplayCapabilityFlags::Cap_AngularAcceleration);
247 }
248 
CapLinearAcceleration() const249 bool VRMockDisplay::CapLinearAcceleration() const {
250   return GetCapFlag(VRDisplayCapabilityFlags::Cap_LinearAcceleration);
251 }
252 
CapStageParameters() const253 bool VRMockDisplay::CapStageParameters() const {
254   return GetCapFlag(VRDisplayCapabilityFlags::Cap_StageParameters);
255 }
256 
CapMountDetection() const257 bool VRMockDisplay::CapMountDetection() const {
258   return GetCapFlag(VRDisplayCapabilityFlags::Cap_MountDetection);
259 }
260 
CapPositionEmulated() const261 bool VRMockDisplay::CapPositionEmulated() const {
262   return GetCapFlag(VRDisplayCapabilityFlags::Cap_PositionEmulated);
263 }
264 
SetEyeResolution(uint32_t aRenderWidth,uint32_t aRenderHeight)265 void VRMockDisplay::SetEyeResolution(uint32_t aRenderWidth,
266                                      uint32_t aRenderHeight) {
267   DisplayState().eyeResolution.width = aRenderWidth;
268   DisplayState().eyeResolution.height = aRenderHeight;
269 }
270 
SetStageSize(double aWidth,double aHeight)271 void VRMockDisplay::SetStageSize(double aWidth, double aHeight) {
272   VRDisplayState& displayState = DisplayState();
273   displayState.stageSize.width = (float)aWidth;
274   displayState.stageSize.height = (float)aHeight;
275 }
276 
SetSittingToStandingTransform(const Float32Array & aTransform,ErrorResult & aRv)277 void VRMockDisplay::SetSittingToStandingTransform(
278     const Float32Array& aTransform, ErrorResult& aRv) {
279   Unused << ReadFloat32Array(DisplayState().sittingToStandingTransform,
280                              aTransform, aRv);
281 }
282 
SetPose(const Nullable<Float32Array> & aPosition,const Nullable<Float32Array> & aLinearVelocity,const Nullable<Float32Array> & aLinearAcceleration,const Nullable<Float32Array> & aOrientation,const Nullable<Float32Array> & aAngularVelocity,const Nullable<Float32Array> & aAngularAcceleration,ErrorResult & aRv)283 void VRMockDisplay::SetPose(const Nullable<Float32Array>& aPosition,
284                             const Nullable<Float32Array>& aLinearVelocity,
285                             const Nullable<Float32Array>& aLinearAcceleration,
286                             const Nullable<Float32Array>& aOrientation,
287                             const Nullable<Float32Array>& aAngularVelocity,
288                             const Nullable<Float32Array>& aAngularAcceleration,
289                             ErrorResult& aRv) {
290   VRHMDSensorState& sensorState = mVRServiceTest->SystemState().sensorState;
291   sensorState.Clear();
292   sensorState.flags = VRDisplayCapabilityFlags::Cap_None;
293   // sensorState.timestamp will be set automatically during
294   // puppet script execution
295 
296   if (!aOrientation.IsNull()) {
297     if (!ReadFloat32Array(sensorState.pose.orientation, aOrientation.Value(),
298                           aRv)) {
299       return;
300     }
301     sensorState.flags |= VRDisplayCapabilityFlags::Cap_Orientation;
302   }
303   if (!aAngularVelocity.IsNull()) {
304     if (!ReadFloat32Array(sensorState.pose.angularVelocity,
305                           aAngularVelocity.Value(), aRv)) {
306       return;
307     }
308     sensorState.flags |= VRDisplayCapabilityFlags::Cap_AngularAcceleration;
309   }
310   if (!aAngularAcceleration.IsNull()) {
311     if (!ReadFloat32Array(sensorState.pose.angularAcceleration,
312                           aAngularAcceleration.Value(), aRv)) {
313       return;
314     }
315     sensorState.flags |= VRDisplayCapabilityFlags::Cap_AngularAcceleration;
316   }
317   if (!aPosition.IsNull()) {
318     if (!ReadFloat32Array(sensorState.pose.position, aPosition.Value(), aRv)) {
319       return;
320     }
321     sensorState.flags |= VRDisplayCapabilityFlags::Cap_Position;
322   }
323   if (!aLinearVelocity.IsNull()) {
324     if (!ReadFloat32Array(sensorState.pose.linearVelocity,
325                           aLinearVelocity.Value(), aRv)) {
326       return;
327     }
328     sensorState.flags |= VRDisplayCapabilityFlags::Cap_LinearAcceleration;
329   }
330   if (!aLinearAcceleration.IsNull()) {
331     if (!ReadFloat32Array(sensorState.pose.linearAcceleration,
332                           aLinearAcceleration.Value(), aRv)) {
333       return;
334     }
335     sensorState.flags |= VRDisplayCapabilityFlags::Cap_LinearAcceleration;
336   }
337 }
338 
NS_IMPL_CYCLE_COLLECTION_INHERITED(VRMockController,DOMEventTargetHelper,mVRServiceTest)339 NS_IMPL_CYCLE_COLLECTION_INHERITED(VRMockController, DOMEventTargetHelper,
340                                    mVRServiceTest)
341 
342 NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED_0(VRMockController,
343                                                DOMEventTargetHelper)
344 
345 VRMockController::VRMockController(VRServiceTest* aVRServiceTest,
346                                    uint32_t aControllerIdx)
347     : DOMEventTargetHelper(aVRServiceTest->GetOwner()),
348       mVRServiceTest(aVRServiceTest),
349       mControllerIdx(aControllerIdx) {
350   MOZ_ASSERT(aControllerIdx < kVRControllerMaxCount);
351 }
352 
WrapObject(JSContext * aCx,JS::Handle<JSObject * > aGivenProto)353 JSObject* VRMockController::WrapObject(JSContext* aCx,
354                                        JS::Handle<JSObject*> aGivenProto) {
355   return VRMockController_Binding::Wrap(aCx, this, aGivenProto);
356 }
357 
ControllerState() const358 VRControllerState& VRMockController::ControllerState() const {
359   return mVRServiceTest->SystemState().controllerState[mControllerIdx];
360 }
361 
Create()362 void VRMockController::Create() {
363   // Initialize with a 6dof, left-handed gamepad with one haptic actuator
364   // Tests are expected to modify the controller before it is sent to the
365   // puppet.
366   Clear();
367   VRControllerState& state = ControllerState();
368   strncpy(state.controllerName, "Puppet Gamepad", kVRControllerNameMaxLen);
369   state.hand = GamepadHand::Left;
370   state.flags = GamepadCapabilityFlags::Cap_Position |
371                 GamepadCapabilityFlags::Cap_Orientation;
372   state.numButtons = 1;
373   state.numHaptics = 1;
374   state.triggerValue[0] = 0.0f;
375 }
376 
Clear()377 void VRMockController::Clear() {
378   mVRServiceTest->ClearController(mControllerIdx);
379 }
380 
SetCapFlag(GamepadCapabilityFlags aFlag,bool aEnabled)381 void VRMockController::SetCapFlag(GamepadCapabilityFlags aFlag, bool aEnabled) {
382   if (aEnabled) {
383     ControllerState().flags |= aFlag;
384   } else {
385     ControllerState().flags &= ~aFlag;
386   }
387 }
GetCapFlag(GamepadCapabilityFlags aFlag) const388 bool VRMockController::GetCapFlag(GamepadCapabilityFlags aFlag) const {
389   return (ControllerState().flags & aFlag) != GamepadCapabilityFlags::Cap_None;
390 }
391 
SetHand(GamepadHand aHand)392 void VRMockController::SetHand(GamepadHand aHand) {
393   ControllerState().hand = aHand;
394 }
395 
Hand() const396 GamepadHand VRMockController::Hand() const { return ControllerState().hand; }
397 
SetCapPosition(bool aEnabled)398 void VRMockController::SetCapPosition(bool aEnabled) {
399   SetCapFlag(GamepadCapabilityFlags::Cap_Position, aEnabled);
400 }
401 
CapPosition() const402 bool VRMockController::CapPosition() const {
403   return GetCapFlag(GamepadCapabilityFlags::Cap_Position);
404 }
405 
SetCapOrientation(bool aEnabled)406 void VRMockController::SetCapOrientation(bool aEnabled) {
407   SetCapFlag(GamepadCapabilityFlags::Cap_Orientation, aEnabled);
408 }
409 
CapOrientation() const410 bool VRMockController::CapOrientation() const {
411   return GetCapFlag(GamepadCapabilityFlags::Cap_Orientation);
412 }
413 
SetCapAngularAcceleration(bool aEnabled)414 void VRMockController::SetCapAngularAcceleration(bool aEnabled) {
415   SetCapFlag(GamepadCapabilityFlags::Cap_AngularAcceleration, aEnabled);
416 }
417 
CapAngularAcceleration() const418 bool VRMockController::CapAngularAcceleration() const {
419   return GetCapFlag(GamepadCapabilityFlags::Cap_AngularAcceleration);
420 }
421 
SetCapLinearAcceleration(bool aEnabled)422 void VRMockController::SetCapLinearAcceleration(bool aEnabled) {
423   SetCapFlag(GamepadCapabilityFlags::Cap_LinearAcceleration, aEnabled);
424 }
425 
CapLinearAcceleration() const426 bool VRMockController::CapLinearAcceleration() const {
427   return GetCapFlag(GamepadCapabilityFlags::Cap_LinearAcceleration);
428 }
429 
SetAxisCount(uint32_t aCount)430 void VRMockController::SetAxisCount(uint32_t aCount) {
431   MOZ_ASSERT(aCount <= kVRControllerMaxAxis);
432   ControllerState().numAxes = aCount;
433 }
434 
AxisCount() const435 uint32_t VRMockController::AxisCount() const {
436   return ControllerState().numAxes;
437 }
438 
SetButtonCount(uint32_t aCount)439 void VRMockController::SetButtonCount(uint32_t aCount) {
440   MOZ_ASSERT(aCount <= kVRControllerMaxButtons);
441   ControllerState().numButtons = aCount;
442 }
443 
ButtonCount() const444 uint32_t VRMockController::ButtonCount() const {
445   return ControllerState().numButtons;
446 }
447 
SetHapticCount(uint32_t aCount)448 void VRMockController::SetHapticCount(uint32_t aCount) {
449   ControllerState().numHaptics = aCount;
450 }
451 
HapticCount() const452 uint32_t VRMockController::HapticCount() const {
453   return ControllerState().numHaptics;
454 }
455 
SetButtonPressed(uint32_t aButtonIdx,bool aPressed)456 void VRMockController::SetButtonPressed(uint32_t aButtonIdx, bool aPressed) {
457   MOZ_ASSERT(aButtonIdx < kVRControllerMaxButtons);
458   if (aPressed) {
459     ControllerState().buttonPressed |= (1 << aButtonIdx);
460   } else {
461     ControllerState().buttonPressed &= ~(1 << aButtonIdx);
462   }
463 }
464 
SetButtonTouched(uint32_t aButtonIdx,bool aTouched)465 void VRMockController::SetButtonTouched(uint32_t aButtonIdx, bool aTouched) {
466   MOZ_ASSERT(aButtonIdx < kVRControllerMaxButtons);
467   if (aTouched) {
468     ControllerState().buttonTouched |= (1 << aButtonIdx);
469   } else {
470     ControllerState().buttonTouched &= ~(1 << aButtonIdx);
471   }
472 }
473 
SetButtonTrigger(uint32_t aButtonIdx,double aTrigger)474 void VRMockController::SetButtonTrigger(uint32_t aButtonIdx, double aTrigger) {
475   MOZ_ASSERT(aButtonIdx < kVRControllerMaxButtons);
476 
477   ControllerState().triggerValue[aButtonIdx] = (float)aTrigger;
478 }
479 
SetAxisValue(uint32_t aAxisIdx,double aValue)480 void VRMockController::SetAxisValue(uint32_t aAxisIdx, double aValue) {
481   MOZ_ASSERT(aAxisIdx < kVRControllerMaxAxis);
482   ControllerState().axisValue[aAxisIdx] = (float)aValue;
483 }
484 
SetPose(const Nullable<Float32Array> & aPosition,const Nullable<Float32Array> & aLinearVelocity,const Nullable<Float32Array> & aLinearAcceleration,const Nullable<Float32Array> & aOrientation,const Nullable<Float32Array> & aAngularVelocity,const Nullable<Float32Array> & aAngularAcceleration,ErrorResult & aRv)485 void VRMockController::SetPose(
486     const Nullable<Float32Array>& aPosition,
487     const Nullable<Float32Array>& aLinearVelocity,
488     const Nullable<Float32Array>& aLinearAcceleration,
489     const Nullable<Float32Array>& aOrientation,
490     const Nullable<Float32Array>& aAngularVelocity,
491     const Nullable<Float32Array>& aAngularAcceleration, ErrorResult& aRv) {
492   VRControllerState& controllerState = ControllerState();
493   controllerState.flags = GamepadCapabilityFlags::Cap_None;
494 
495   if (!aOrientation.IsNull()) {
496     if (!ReadFloat32Array(controllerState.pose.orientation,
497                           aOrientation.Value(), aRv)) {
498       return;
499     }
500     controllerState.flags |= GamepadCapabilityFlags::Cap_Orientation;
501   }
502   if (!aAngularVelocity.IsNull()) {
503     if (!ReadFloat32Array(controllerState.pose.angularVelocity,
504                           aAngularVelocity.Value(), aRv)) {
505       return;
506     }
507     controllerState.flags |= GamepadCapabilityFlags::Cap_AngularAcceleration;
508   }
509   if (!aAngularAcceleration.IsNull()) {
510     if (!ReadFloat32Array(controllerState.pose.angularAcceleration,
511                           aAngularAcceleration.Value(), aRv)) {
512       return;
513     }
514     controllerState.flags |= GamepadCapabilityFlags::Cap_AngularAcceleration;
515   }
516   if (!aPosition.IsNull()) {
517     if (!ReadFloat32Array(controllerState.pose.position, aPosition.Value(),
518                           aRv)) {
519       return;
520     }
521     controllerState.flags |= GamepadCapabilityFlags::Cap_Position;
522   }
523   if (!aLinearVelocity.IsNull()) {
524     if (!ReadFloat32Array(controllerState.pose.linearVelocity,
525                           aLinearVelocity.Value(), aRv)) {
526       return;
527     }
528     controllerState.flags |= GamepadCapabilityFlags::Cap_LinearAcceleration;
529   }
530   if (!aLinearAcceleration.IsNull()) {
531     if (!ReadFloat32Array(controllerState.pose.linearAcceleration,
532                           aLinearAcceleration.Value(), aRv)) {
533       return;
534     }
535     controllerState.flags |= GamepadCapabilityFlags::Cap_LinearAcceleration;
536   }
537 }
538 
NS_IMPL_CYCLE_COLLECTION_INHERITED(VRServiceTest,DOMEventTargetHelper,mDisplay,mControllers,mWindow)539 NS_IMPL_CYCLE_COLLECTION_INHERITED(VRServiceTest, DOMEventTargetHelper,
540                                    mDisplay, mControllers, mWindow)
541 
542 NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED_0(VRServiceTest,
543                                                DOMEventTargetHelper)
544 
545 JSObject* VRServiceTest::WrapObject(JSContext* aCx,
546                                     JS::Handle<JSObject*> aGivenProto) {
547   return VRServiceTest_Binding::Wrap(aCx, this, aGivenProto);
548 }
549 
550 // static
CreateTestService(nsPIDOMWindowInner * aWindow)551 already_AddRefed<VRServiceTest> VRServiceTest::CreateTestService(
552     nsPIDOMWindowInner* aWindow) {
553   MOZ_ASSERT(aWindow);
554   RefPtr<VRServiceTest> service = new VRServiceTest(aWindow);
555   return service.forget();
556 }
557 
VRServiceTest(nsPIDOMWindowInner * aWindow)558 VRServiceTest::VRServiceTest(nsPIDOMWindowInner* aWindow)
559     : mWindow(aWindow), mPendingState{}, mEncodedState{}, mShuttingDown(false) {
560   mDisplay = new VRMockDisplay(this);
561   for (int i = 0; i < kVRControllerMaxCount; i++) {
562     mControllers.AppendElement(new VRMockController(this, i));
563   }
564   ClearAll();
565 }
566 
SystemState()567 gfx::VRSystemState& VRServiceTest::SystemState() { return mPendingState; }
568 
GetVRDisplay()569 VRMockDisplay* VRServiceTest::GetVRDisplay() { return mDisplay; }
570 
GetVRController(uint32_t aControllerIdx,ErrorResult & aRv)571 VRMockController* VRServiceTest::GetVRController(uint32_t aControllerIdx,
572                                                  ErrorResult& aRv) {
573   if (aControllerIdx >= kVRControllerMaxCount) {
574     aRv.Throw(NS_ERROR_INVALID_ARG);
575     return nullptr;
576   }
577   return mControllers[aControllerIdx];
578 }
579 
Shutdown()580 void VRServiceTest::Shutdown() {
581   MOZ_ASSERT(!mShuttingDown);
582   mShuttingDown = true;
583   mWindow = nullptr;
584 }
585 
AddCommand(uint64_t aCommand)586 void VRServiceTest::AddCommand(uint64_t aCommand) {
587   EncodeData();
588   mCommandBuffer.AppendElement(aCommand);
589 }
590 
End()591 void VRServiceTest::End() {
592   AddCommand((uint64_t)VRPuppet_Command::VRPuppet_End);
593 }
594 
ClearAll()595 void VRServiceTest::ClearAll() {
596   memset(&mPendingState, 0, sizeof(VRSystemState));
597   memset(&mEncodedState, 0, sizeof(VRSystemState));
598   AddCommand((uint64_t)VRPuppet_Command::VRPuppet_ClearAll);
599 }
600 
ClearController(uint32_t aControllerIdx)601 void VRServiceTest::ClearController(uint32_t aControllerIdx) {
602   MOZ_ASSERT(aControllerIdx < kVRControllerMaxCount);
603   mPendingState.controllerState[aControllerIdx].Clear();
604   mEncodedState.controllerState[aControllerIdx].Clear();
605   AddCommand((uint64_t)VRPuppet_Command::VRPuppet_ClearController |
606              (uint64_t)aControllerIdx);
607 }
608 
Timeout(uint32_t aDuration)609 void VRServiceTest::Timeout(uint32_t aDuration) {
610   AddCommand((uint64_t)VRPuppet_Command::VRPuppet_Timeout |
611              (uint64_t)aDuration);
612 }
613 
Wait(uint32_t aDuration)614 void VRServiceTest::Wait(uint32_t aDuration) {
615   AddCommand((uint64_t)VRPuppet_Command::VRPuppet_Wait | (uint64_t)aDuration);
616 }
617 
WaitHapticIntensity(uint32_t aControllerIdx,uint32_t aHapticIdx,double aIntensity,ErrorResult & aRv)618 void VRServiceTest::WaitHapticIntensity(uint32_t aControllerIdx,
619                                         uint32_t aHapticIdx, double aIntensity,
620                                         ErrorResult& aRv) {
621   if (aControllerIdx >= kVRControllerMaxCount) {
622     aRv.Throw(NS_ERROR_INVALID_ARG);
623     return;
624   }
625   if (aHapticIdx >= kVRHapticsMaxCount) {
626     aRv.Throw(NS_ERROR_INVALID_ARG);
627     return;
628   }
629   // convert to 16.16 fixed point.  This must match conversion in
630   // VRPuppetCommandBuffer::RunCommand
631   uint64_t iIntensity = round((float)aIntensity * (1 << 16));
632   if (iIntensity > 0xffffffff) {
633     iIntensity = 0xffffffff;
634   }
635   AddCommand((uint64_t)VRPuppet_Command::VRPuppet_WaitHapticIntensity |
636              ((uint64_t)aControllerIdx << 40) | ((uint64_t)aHapticIdx << 32) |
637              iIntensity);
638 }
639 
WaitSubmit()640 void VRServiceTest::WaitSubmit() {
641   AddCommand((uint64_t)VRPuppet_Command::VRPuppet_WaitSubmit);
642 }
643 
WaitPresentationStart()644 void VRServiceTest::WaitPresentationStart() {
645   AddCommand((uint64_t)VRPuppet_Command::VRPuppet_WaitPresentationStart);
646 }
WaitPresentationEnd()647 void VRServiceTest::WaitPresentationEnd() {
648   AddCommand((uint64_t)VRPuppet_Command::VRPuppet_WaitPresentationEnd);
649 }
650 
EncodeData()651 void VRServiceTest::EncodeData() {
652   VRPuppetCommandBuffer::EncodeStruct(
653       mCommandBuffer, (uint8_t*)&mPendingState.displayState,
654       (uint8_t*)&mEncodedState.displayState, sizeof(VRDisplayState),
655       VRPuppet_Command::VRPuppet_UpdateDisplay);
656   VRPuppetCommandBuffer::EncodeStruct(
657       mCommandBuffer, (uint8_t*)&mPendingState.sensorState,
658       (uint8_t*)&mEncodedState.sensorState, sizeof(VRHMDSensorState),
659       VRPuppet_Command::VRPuppet_UpdateSensor);
660   VRPuppetCommandBuffer::EncodeStruct(
661       mCommandBuffer, (uint8_t*)&mPendingState.controllerState,
662       (uint8_t*)&mEncodedState.controllerState,
663       sizeof(VRControllerState) * kVRControllerMaxCount,
664       VRPuppet_Command::VRPuppet_UpdateControllers);
665 }
666 
CaptureFrame()667 void VRServiceTest::CaptureFrame() {
668   AddCommand((uint64_t)VRPuppet_Command::VRPuppet_CaptureFrame);
669 }
670 
AcknowledgeFrame()671 void VRServiceTest::AcknowledgeFrame() {
672   AddCommand((uint64_t)VRPuppet_Command::VRPuppet_AcknowledgeFrame);
673 }
674 
RejectFrame()675 void VRServiceTest::RejectFrame() {
676   AddCommand((uint64_t)VRPuppet_Command::VRPuppet_RejectFrame);
677 }
678 
StartTimer()679 void VRServiceTest::StartTimer() {
680   AddCommand((uint64_t)VRPuppet_Command::VRPuppet_StartTimer);
681 }
682 
StopTimer()683 void VRServiceTest::StopTimer() {
684   AddCommand((uint64_t)VRPuppet_Command::VRPuppet_StopTimer);
685 }
686 
Commit()687 void VRServiceTest::Commit() {
688   AddCommand((uint64_t)VRPuppet_Command::VRPuppet_Commit);
689 }
690 
Run(ErrorResult & aRv)691 already_AddRefed<Promise> VRServiceTest::Run(ErrorResult& aRv) {
692   if (mShuttingDown) {
693     return nullptr;
694   }
695 
696   AddCommand((uint64_t)VRPuppet_Command::VRPuppet_End);
697 
698   RefPtr<dom::Promise> runPuppetPromise =
699       Promise::Create(mWindow->AsGlobal(), aRv);
700   if (NS_WARN_IF(aRv.Failed())) {
701     return nullptr;
702   }
703 
704   gfx::VRManagerChild* vm = gfx::VRManagerChild::Get();
705   vm->RunPuppet(mCommandBuffer, runPuppetPromise, aRv);
706   if (NS_WARN_IF(aRv.Failed())) {
707     return nullptr;
708   }
709 
710   mCommandBuffer.Clear();
711 
712   return runPuppetPromise.forget();
713 }
714 
Reset(ErrorResult & aRv)715 already_AddRefed<Promise> VRServiceTest::Reset(ErrorResult& aRv) {
716   if (mShuttingDown) {
717     return nullptr;
718   }
719 
720   RefPtr<dom::Promise> resetPuppetPromise =
721       Promise::Create(mWindow->AsGlobal(), aRv);
722   if (NS_WARN_IF(aRv.Failed())) {
723     return nullptr;
724   }
725 
726   gfx::VRManagerChild* vm = gfx::VRManagerChild::Get();
727   vm->ResetPuppet(resetPuppetPromise, aRv);
728   if (NS_WARN_IF(aRv.Failed())) {
729     return nullptr;
730   }
731 
732   memset(&mPendingState, 0, sizeof(VRSystemState));
733   memset(&mEncodedState, 0, sizeof(VRSystemState));
734   mCommandBuffer.Clear();
735 
736   return resetPuppetPromise.forget();
737 }
738 
739 }  // namespace dom
740 }  // namespace mozilla
741