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 #ifndef mozilla_dom_VRDisplay_h_
8 #define mozilla_dom_VRDisplay_h_
9 
10 #include <stdint.h>
11 
12 #include "mozilla/dom/TypedArray.h"
13 #include "mozilla/dom/VRDisplayBinding.h"
14 #include "mozilla/DOMEventTargetHelper.h"
15 #include "mozilla/dom/DOMPoint.h"
16 #include "mozilla/dom/DOMRect.h"
17 #include "mozilla/dom/Pose.h"
18 #include "mozilla/TimeStamp.h"
19 
20 #include "nsCOMPtr.h"
21 #include "nsString.h"
22 #include "nsTArray.h"
23 
24 #include "gfxVR.h"
25 
26 namespace mozilla {
27 class ErrorResult;
28 
29 namespace gfx {
30 class VRDisplayClient;
31 class VRDisplayPresentation;
32 struct VRFieldOfView;
33 enum class VRDisplayCapabilityFlags : uint16_t;
34 struct VRHMDSensorState;
35 }  // namespace gfx
36 namespace dom {
37 class Navigator;
38 
39 class VRFieldOfView final : public nsWrapperCache {
40  public:
41   VRFieldOfView(nsISupports* aParent, double aUpDegrees, double aRightDegrees,
42                 double aDownDegrees, double aLeftDegrees);
43   VRFieldOfView(nsISupports* aParent, const gfx::VRFieldOfView& aSrc);
44 
45   NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(VRFieldOfView)
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(VRFieldOfView)46   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(VRFieldOfView)
47 
48   double UpDegrees() const { return mUpDegrees; }
RightDegrees()49   double RightDegrees() const { return mRightDegrees; }
DownDegrees()50   double DownDegrees() const { return mDownDegrees; }
LeftDegrees()51   double LeftDegrees() const { return mLeftDegrees; }
52 
GetParentObject()53   nsISupports* GetParentObject() const { return mParent; }
54   virtual JSObject* WrapObject(JSContext* aCx,
55                                JS::Handle<JSObject*> aGivenProto) override;
56 
57  protected:
58   virtual ~VRFieldOfView() = default;
59 
60   nsCOMPtr<nsISupports> mParent;
61 
62   double mUpDegrees;
63   double mRightDegrees;
64   double mDownDegrees;
65   double mLeftDegrees;
66 };
67 
68 class VRDisplayCapabilities final : public nsWrapperCache {
69  public:
VRDisplayCapabilities(nsISupports * aParent,const gfx::VRDisplayCapabilityFlags & aFlags)70   VRDisplayCapabilities(nsISupports* aParent,
71                         const gfx::VRDisplayCapabilityFlags& aFlags)
72       : mParent(aParent), mFlags(aFlags) {}
73 
74   NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(VRDisplayCapabilities)
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(VRDisplayCapabilities)75   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(VRDisplayCapabilities)
76 
77   nsISupports* GetParentObject() const { return mParent; }
78 
79   virtual JSObject* WrapObject(JSContext* aCx,
80                                JS::Handle<JSObject*> aGivenProto) override;
81 
82   bool HasPosition() const;
83   bool HasOrientation() const;
84   bool HasExternalDisplay() const;
85   bool CanPresent() const;
86   uint32_t MaxLayers() const;
87 
88  protected:
89   ~VRDisplayCapabilities() = default;
90   nsCOMPtr<nsISupports> mParent;
91   gfx::VRDisplayCapabilityFlags mFlags;
92 };
93 
94 class VRPose final : public Pose {
95  public:
96   VRPose(nsISupports* aParent, const gfx::VRHMDSensorState& aState);
97   explicit VRPose(nsISupports* aParent);
98 
99   virtual void GetPosition(JSContext* aCx, JS::MutableHandle<JSObject*> aRetval,
100                            ErrorResult& aRv) override;
101   virtual void GetLinearVelocity(JSContext* aCx,
102                                  JS::MutableHandle<JSObject*> aRetval,
103                                  ErrorResult& aRv) override;
104   virtual void GetLinearAcceleration(JSContext* aCx,
105                                      JS::MutableHandle<JSObject*> aRetval,
106                                      ErrorResult& aRv) override;
107   virtual void GetOrientation(JSContext* aCx,
108                               JS::MutableHandle<JSObject*> aRetval,
109                               ErrorResult& aRv) override;
110   virtual void GetAngularVelocity(JSContext* aCx,
111                                   JS::MutableHandle<JSObject*> aRetval,
112                                   ErrorResult& aRv) override;
113   virtual void GetAngularAcceleration(JSContext* aCx,
114                                       JS::MutableHandle<JSObject*> aRetval,
115                                       ErrorResult& aRv) override;
116 
117   virtual JSObject* WrapObject(JSContext* aCx,
118                                JS::Handle<JSObject*> aGivenProto) override;
119 
120   void Update(const gfx::VRHMDSensorState& aState);
121 
122  protected:
123   ~VRPose();
124 
125   gfx::VRHMDSensorState mVRState;
126 };
127 
128 struct VRFrameInfo {
129   VRFrameInfo();
130 
131   void Update(const gfx::VRDisplayInfo& aInfo,
132               const gfx::VRHMDSensorState& aState, float aDepthNear,
133               float aDepthFar);
134 
135   void Clear();
136   bool IsDirty();
137 
138   gfx::VRHMDSensorState mVRState;
139   gfx::Matrix4x4 mLeftProjection;
140   gfx::Matrix4x4 mLeftView;
141   gfx::Matrix4x4 mRightProjection;
142   gfx::Matrix4x4 mRightView;
143 
144   /**
145    * In order to avoid leaking information related to the duration of
146    * the user's VR session, we re-base timestamps.
147    * mTimeStampOffset is added to the actual timestamp returned by the
148    * underlying VR platform API when returned through WebVR API's.
149    */
150   double mTimeStampOffset;
151 };
152 
153 class VRFrameData final : public nsWrapperCache {
154  public:
155   NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(VRFrameData)
156   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(VRFrameData)
157 
158   explicit VRFrameData(nsISupports* aParent);
159   static already_AddRefed<VRFrameData> Constructor(const GlobalObject& aGlobal);
160 
161   void Update(const VRFrameInfo& aFrameInfo);
162 
163   // WebIDL Members
164   double Timestamp() const;
165   void GetLeftProjectionMatrix(JSContext* aCx,
166                                JS::MutableHandle<JSObject*> aRetval,
167                                ErrorResult& aRv);
168   void GetLeftViewMatrix(JSContext* aCx, JS::MutableHandle<JSObject*> aRetval,
169                          ErrorResult& aRv);
170   void GetRightProjectionMatrix(JSContext* aCx,
171                                 JS::MutableHandle<JSObject*> aRetval,
172                                 ErrorResult& aRv);
173   void GetRightViewMatrix(JSContext* aCx, JS::MutableHandle<JSObject*> aRetval,
174                           ErrorResult& aRv);
175 
176   VRPose* Pose();
177 
178   // WebIDL Boilerplate
GetParentObject()179   nsISupports* GetParentObject() const { return mParent; }
180   virtual JSObject* WrapObject(JSContext* aCx,
181                                JS::Handle<JSObject*> aGivenProto) override;
182 
183  protected:
184   ~VRFrameData();
185   nsCOMPtr<nsISupports> mParent;
186 
187   VRFrameInfo mFrameInfo;
188   RefPtr<VRPose> mPose;
189   JS::Heap<JSObject*> mLeftProjectionMatrix;
190   JS::Heap<JSObject*> mLeftViewMatrix;
191   JS::Heap<JSObject*> mRightProjectionMatrix;
192   JS::Heap<JSObject*> mRightViewMatrix;
193 
194   void LazyCreateMatrix(JS::Heap<JSObject*>& aArray, gfx::Matrix4x4& aMat,
195                         JSContext* aCx, JS::MutableHandle<JSObject*> aRetval,
196                         ErrorResult& aRv);
197 };
198 
199 class VRStageParameters final : public nsWrapperCache {
200  public:
201   VRStageParameters(nsISupports* aParent,
202                     const gfx::Matrix4x4& aSittingToStandingTransform,
203                     const gfx::Size& aSize);
204 
205   NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(VRStageParameters)
206   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(VRStageParameters)
207 
208   void GetSittingToStandingTransform(JSContext* aCx,
209                                      JS::MutableHandle<JSObject*> aRetval,
210                                      ErrorResult& aRv);
SizeX()211   float SizeX() const { return mSize.width; }
SizeZ()212   float SizeZ() const { return mSize.height; }
213 
GetParentObject()214   nsISupports* GetParentObject() const { return mParent; }
215   virtual JSObject* WrapObject(JSContext* aCx,
216                                JS::Handle<JSObject*> aGivenProto) override;
217 
218  protected:
219   ~VRStageParameters();
220 
221   nsCOMPtr<nsISupports> mParent;
222 
223   gfx::Matrix4x4 mSittingToStandingTransform;
224   JS::Heap<JSObject*> mSittingToStandingTransformArray;
225   gfx::Size mSize;
226 };
227 
228 class VREyeParameters final : public nsWrapperCache {
229  public:
230   VREyeParameters(nsISupports* aParent, const gfx::Point3D& aEyeTranslation,
231                   const gfx::VRFieldOfView& aFOV,
232                   const gfx::IntSize& aRenderSize);
233 
234   NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(VREyeParameters)
235   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(VREyeParameters)
236 
237   void GetOffset(JSContext* aCx, JS::MutableHandle<JSObject*> aRetVal,
238                  ErrorResult& aRv);
239 
240   VRFieldOfView* FieldOfView();
241 
RenderWidth()242   uint32_t RenderWidth() const { return mRenderSize.width; }
RenderHeight()243   uint32_t RenderHeight() const { return mRenderSize.height; }
244 
GetParentObject()245   nsISupports* GetParentObject() const { return mParent; }
246   virtual JSObject* WrapObject(JSContext* aCx,
247                                JS::Handle<JSObject*> aGivenProto) override;
248 
249  protected:
250   ~VREyeParameters();
251 
252   nsCOMPtr<nsISupports> mParent;
253 
254   gfx::Point3D mEyeTranslation;
255   gfx::IntSize mRenderSize;
256   JS::Heap<JSObject*> mOffset;
257   RefPtr<VRFieldOfView> mFOV;
258 };
259 
260 class VRDisplay final : public DOMEventTargetHelper, public nsIObserver {
261  public:
262   NS_DECL_ISUPPORTS_INHERITED
263   NS_DECL_NSIOBSERVER
264   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(VRDisplay, DOMEventTargetHelper)
265 
266   virtual JSObject* WrapObject(JSContext* aCx,
267                                JS::Handle<JSObject*> aGivenProto) override;
268 
269   uint32_t PresentingGroups() const;
270   uint32_t GroupMask() const;
271   void SetGroupMask(const uint32_t& aGroupMask);
272   bool IsAnyPresenting(uint32_t aGroupMask) const;
273   bool IsPresenting() const;
274   bool IsConnected() const;
275 
276   VRDisplayCapabilities* Capabilities();
277   VRStageParameters* GetStageParameters();
278 
279   uint32_t DisplayId() const;
280   void GetDisplayName(nsAString& aDisplayName) const;
281   // Replacing the old VRDisplayClient with the newest one to avoid
282   // JS needs to reload to recover VRDisplay when VRService is shutdown at the
283   // backend.
284   void UpdateDisplayClient(already_AddRefed<gfx::VRDisplayClient> aClient);
285 
286   static bool RefreshVRDisplays(uint64_t aWindowId);
287   static void UpdateVRDisplays(nsTArray<RefPtr<VRDisplay> >& aDisplays,
288                                nsPIDOMWindowInner* aWindow);
289 
GetClient()290   gfx::VRDisplayClient* GetClient() { return mClient; }
291 
292   virtual already_AddRefed<VREyeParameters> GetEyeParameters(VREye aEye);
293 
294   bool GetFrameData(VRFrameData& aFrameData);
295   already_AddRefed<VRPose> GetPose();
296   void ResetPose();
297 
DepthNear()298   double DepthNear() { return mDepthNear; }
299 
DepthFar()300   double DepthFar() { return mDepthFar; }
301 
SetDepthNear(double aDepthNear)302   void SetDepthNear(double aDepthNear) {
303     // XXX When we start sending depth buffers to VRLayer's we will want
304     // to communicate this with the VRDisplayHost
305     mDepthNear = aDepthNear;
306   }
307 
SetDepthFar(double aDepthFar)308   void SetDepthFar(double aDepthFar) {
309     // XXX When we start sending depth buffers to VRLayer's we will want
310     // to communicate this with the VRDisplayHost
311     mDepthFar = aDepthFar;
312   }
313 
314   already_AddRefed<Promise> RequestPresent(const nsTArray<VRLayer>& aLayers,
315                                            CallerType aCallerType,
316                                            ErrorResult& aRv);
317   already_AddRefed<Promise> ExitPresent(ErrorResult& aRv);
318   void GetLayers(nsTArray<VRLayer>& result);
319   void SubmitFrame();
320 
321   int32_t RequestAnimationFrame(mozilla::dom::FrameRequestCallback& aCallback,
322                                 mozilla::ErrorResult& aError);
323   void CancelAnimationFrame(int32_t aHandle, mozilla::ErrorResult& aError);
324   void StartVRNavigation();
325   void StartHandlingVRNavigationEvent();
326   void StopHandlingVRNavigationEvent();
327   bool IsHandlingVRNavigationEvent();
328   void OnPresentationGenerationChanged();
329 
330  protected:
331   VRDisplay(nsPIDOMWindowInner* aWindow, gfx::VRDisplayClient* aClient);
332   virtual ~VRDisplay();
333   virtual void LastRelease() override;
334 
335   void ExitPresentInternal();
336   void Shutdown();
337   void UpdateFrameInfo();
338 
339   RefPtr<gfx::VRDisplayClient> mClient;
340 
341   RefPtr<VRDisplayCapabilities> mCapabilities;
342   RefPtr<VRStageParameters> mStageParameters;
343 
344   double mDepthNear;
345   double mDepthFar;
346 
347   RefPtr<gfx::VRDisplayPresentation> mPresentation;
348 
349   /**
350    * The WebVR 1.1 spec Requires that VRDisplay.getPose and
351    * VRDisplay.getFrameData must return the same values until the next
352    * VRDisplay.submitFrame. mFrameInfo is updated only on the first call to
353    * either function within one frame.  Subsequent calls before the next
354    * SubmitFrame or ExitPresent call will use these cached values.
355    */
356   VRFrameInfo mFrameInfo;
357 
358   // Time at which we began expecting VR navigation.
359   TimeStamp mHandlingVRNavigationEventStart;
360   int32_t mVRNavigationEventDepth;
361   bool mShutdown;
362 };
363 
364 }  // namespace dom
365 }  // namespace mozilla
366 
367 #endif
368