/src/mozilla-central/dom/vr/VRDisplay.cpp
Line | Count | Source (jump to first uncovered line) |
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 "nsWrapperCache.h" |
8 | | |
9 | | #include "mozilla/dom/Element.h" |
10 | | #include "mozilla/dom/ElementBinding.h" |
11 | | #include "mozilla/dom/Promise.h" |
12 | | #include "mozilla/dom/VRDisplay.h" |
13 | | #include "mozilla/HoldDropJSObjects.h" |
14 | | #include "mozilla/dom/VRDisplayBinding.h" |
15 | | #include "mozilla/Base64.h" |
16 | | #include "mozilla/EventStateManager.h" |
17 | | #include "mozilla/gfx/DataSurfaceHelpers.h" |
18 | | #include "Navigator.h" |
19 | | #include "gfxPrefs.h" |
20 | | #include "gfxUtils.h" |
21 | | #include "gfxVR.h" |
22 | | #include "VRDisplayClient.h" |
23 | | #include "VRManagerChild.h" |
24 | | #include "VRDisplayPresentation.h" |
25 | | #include "nsIObserverService.h" |
26 | | #include "nsIFrame.h" |
27 | | #include "nsISupportsPrimitives.h" |
28 | | |
29 | | using namespace mozilla::gfx; |
30 | | |
31 | | namespace mozilla { |
32 | | namespace dom { |
33 | | |
34 | | VRFieldOfView::VRFieldOfView(nsISupports* aParent, |
35 | | double aUpDegrees, double aRightDegrees, |
36 | | double aDownDegrees, double aLeftDegrees) |
37 | | : mParent(aParent) |
38 | | , mUpDegrees(aUpDegrees) |
39 | | , mRightDegrees(aRightDegrees) |
40 | | , mDownDegrees(aDownDegrees) |
41 | | , mLeftDegrees(aLeftDegrees) |
42 | 0 | { |
43 | 0 | } |
44 | | |
45 | | VRFieldOfView::VRFieldOfView(nsISupports* aParent, const gfx::VRFieldOfView& aSrc) |
46 | | : mParent(aParent) |
47 | | , mUpDegrees(aSrc.upDegrees) |
48 | | , mRightDegrees(aSrc.rightDegrees) |
49 | | , mDownDegrees(aSrc.downDegrees) |
50 | | , mLeftDegrees(aSrc.leftDegrees) |
51 | 0 | { |
52 | 0 | } |
53 | | |
54 | | bool |
55 | | VRDisplayCapabilities::HasPosition() const |
56 | 0 | { |
57 | 0 | return bool(mFlags & gfx::VRDisplayCapabilityFlags::Cap_Position); |
58 | 0 | } |
59 | | |
60 | | bool |
61 | | VRDisplayCapabilities::HasOrientation() const |
62 | 0 | { |
63 | 0 | return bool(mFlags & gfx::VRDisplayCapabilityFlags::Cap_Orientation); |
64 | 0 | } |
65 | | |
66 | | bool |
67 | | VRDisplayCapabilities::HasExternalDisplay() const |
68 | 0 | { |
69 | 0 | return bool(mFlags & gfx::VRDisplayCapabilityFlags::Cap_External); |
70 | 0 | } |
71 | | |
72 | | bool |
73 | | VRDisplayCapabilities::CanPresent() const |
74 | 0 | { |
75 | 0 | return bool(mFlags & gfx::VRDisplayCapabilityFlags::Cap_Present); |
76 | 0 | } |
77 | | |
78 | | uint32_t |
79 | | VRDisplayCapabilities::MaxLayers() const |
80 | 0 | { |
81 | 0 | return CanPresent() ? 1 : 0; |
82 | 0 | } |
83 | | |
84 | | /*static*/ bool |
85 | | VRDisplay::RefreshVRDisplays(uint64_t aWindowId) |
86 | 0 | { |
87 | 0 | gfx::VRManagerChild* vm = gfx::VRManagerChild::Get(); |
88 | 0 | return vm && vm->RefreshVRDisplaysWithCallback(aWindowId); |
89 | 0 | } |
90 | | |
91 | | /*static*/ void |
92 | | VRDisplay::UpdateVRDisplays(nsTArray<RefPtr<VRDisplay>>& aDisplays, nsPIDOMWindowInner* aWindow) |
93 | 0 | { |
94 | 0 | nsTArray<RefPtr<VRDisplay>> displays; |
95 | 0 |
|
96 | 0 | gfx::VRManagerChild* vm = gfx::VRManagerChild::Get(); |
97 | 0 | nsTArray<RefPtr<gfx::VRDisplayClient>> updatedDisplays; |
98 | 0 | if (vm && vm->GetVRDisplays(updatedDisplays)) { |
99 | 0 | for (size_t i = 0; i < updatedDisplays.Length(); i++) { |
100 | 0 | RefPtr<gfx::VRDisplayClient> display = updatedDisplays[i]; |
101 | 0 | bool isNewDisplay = true; |
102 | 0 | for (size_t j = 0; j < aDisplays.Length(); j++) { |
103 | 0 | if (aDisplays[j]->GetClient()->GetDisplayInfo().GetDisplayID() == display->GetDisplayInfo().GetDisplayID()) { |
104 | 0 | displays.AppendElement(aDisplays[j]); |
105 | 0 | isNewDisplay = false; |
106 | 0 | } |
107 | 0 | } |
108 | 0 |
|
109 | 0 | if (isNewDisplay) { |
110 | 0 | displays.AppendElement(new VRDisplay(aWindow, display)); |
111 | 0 | } |
112 | 0 | } |
113 | 0 | } |
114 | 0 |
|
115 | 0 | aDisplays = displays; |
116 | 0 | } |
117 | | |
118 | | NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(VRFieldOfView, mParent) |
119 | | NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(VRFieldOfView, AddRef) |
120 | | NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(VRFieldOfView, Release) |
121 | | |
122 | | |
123 | | JSObject* |
124 | | VRFieldOfView::WrapObject(JSContext* aCx, |
125 | | JS::Handle<JSObject*> aGivenProto) |
126 | 0 | { |
127 | 0 | return VRFieldOfView_Binding::Wrap(aCx, this, aGivenProto); |
128 | 0 | } |
129 | | |
130 | | NS_IMPL_CYCLE_COLLECTION_CLASS(VREyeParameters) |
131 | | |
132 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(VREyeParameters) |
133 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK(mParent, mFOV) |
134 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER |
135 | 0 | tmp->mOffset = nullptr; |
136 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK_END |
137 | | |
138 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(VREyeParameters) |
139 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParent, mFOV) |
140 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END |
141 | | |
142 | 0 | NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(VREyeParameters) |
143 | 0 | NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER |
144 | 0 | NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mOffset) |
145 | 0 | NS_IMPL_CYCLE_COLLECTION_TRACE_END |
146 | | |
147 | | NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(VREyeParameters, AddRef) |
148 | | NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(VREyeParameters, Release) |
149 | | |
150 | | VREyeParameters::VREyeParameters(nsISupports* aParent, |
151 | | const gfx::Point3D& aEyeTranslation, |
152 | | const gfx::VRFieldOfView& aFOV, |
153 | | const gfx::IntSize& aRenderSize) |
154 | | : mParent(aParent) |
155 | | , mEyeTranslation(aEyeTranslation) |
156 | | , mRenderSize(aRenderSize) |
157 | 0 | { |
158 | 0 | mFOV = new VRFieldOfView(aParent, aFOV); |
159 | 0 | mozilla::HoldJSObjects(this); |
160 | 0 | } |
161 | | |
162 | | VREyeParameters::~VREyeParameters() |
163 | 0 | { |
164 | 0 | mozilla::DropJSObjects(this); |
165 | 0 | } |
166 | | |
167 | | VRFieldOfView* |
168 | | VREyeParameters::FieldOfView() |
169 | 0 | { |
170 | 0 | return mFOV; |
171 | 0 | } |
172 | | |
173 | | void |
174 | | VREyeParameters::GetOffset(JSContext* aCx, JS::MutableHandle<JSObject*> aRetval, ErrorResult& aRv) |
175 | 0 | { |
176 | 0 | if (!mOffset) { |
177 | 0 | // Lazily create the Float32Array |
178 | 0 | mOffset = dom::Float32Array::Create(aCx, this, 3, mEyeTranslation.components); |
179 | 0 | if (!mOffset) { |
180 | 0 | aRv.NoteJSContextException(aCx); |
181 | 0 | return; |
182 | 0 | } |
183 | 0 | } |
184 | 0 | aRetval.set(mOffset); |
185 | 0 | } |
186 | | |
187 | | JSObject* |
188 | | VREyeParameters::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) |
189 | 0 | { |
190 | 0 | return VREyeParameters_Binding::Wrap(aCx, this, aGivenProto); |
191 | 0 | } |
192 | | |
193 | | VRStageParameters::VRStageParameters(nsISupports* aParent, |
194 | | const gfx::Matrix4x4& aSittingToStandingTransform, |
195 | | const gfx::Size& aSize) |
196 | | : mParent(aParent) |
197 | | , mSittingToStandingTransform(aSittingToStandingTransform) |
198 | | , mSittingToStandingTransformArray(nullptr) |
199 | | , mSize(aSize) |
200 | 0 | { |
201 | 0 | mozilla::HoldJSObjects(this); |
202 | 0 | } |
203 | | |
204 | | VRStageParameters::~VRStageParameters() |
205 | 0 | { |
206 | 0 | mozilla::DropJSObjects(this); |
207 | 0 | } |
208 | | |
209 | | JSObject* |
210 | | VRStageParameters::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) |
211 | 0 | { |
212 | 0 | return VRStageParameters_Binding::Wrap(aCx, this, aGivenProto); |
213 | 0 | } |
214 | | |
215 | | NS_IMPL_CYCLE_COLLECTION_CLASS(VRStageParameters) |
216 | | |
217 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(VRStageParameters) |
218 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK(mParent) |
219 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER |
220 | 0 | tmp->mSittingToStandingTransformArray = nullptr; |
221 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK_END |
222 | | |
223 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(VRStageParameters) |
224 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParent) |
225 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END |
226 | | |
227 | 0 | NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(VRStageParameters) |
228 | 0 | NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER |
229 | 0 | NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mSittingToStandingTransformArray) |
230 | 0 | NS_IMPL_CYCLE_COLLECTION_TRACE_END |
231 | | |
232 | | NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(VRStageParameters, AddRef) |
233 | | NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(VRStageParameters, Release) |
234 | | |
235 | | void |
236 | | VRStageParameters::GetSittingToStandingTransform(JSContext* aCx, |
237 | | JS::MutableHandle<JSObject*> aRetval, |
238 | | ErrorResult& aRv) |
239 | 0 | { |
240 | 0 | if (!mSittingToStandingTransformArray) { |
241 | 0 | // Lazily create the Float32Array |
242 | 0 | mSittingToStandingTransformArray = dom::Float32Array::Create(aCx, this, 16, |
243 | 0 | mSittingToStandingTransform.components); |
244 | 0 | if (!mSittingToStandingTransformArray) { |
245 | 0 | aRv.NoteJSContextException(aCx); |
246 | 0 | return; |
247 | 0 | } |
248 | 0 | } |
249 | 0 | aRetval.set(mSittingToStandingTransformArray); |
250 | 0 | } |
251 | | |
252 | | NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(VRDisplayCapabilities, mParent) |
253 | | NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(VRDisplayCapabilities, AddRef) |
254 | | NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(VRDisplayCapabilities, Release) |
255 | | |
256 | | JSObject* |
257 | | VRDisplayCapabilities::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) |
258 | 0 | { |
259 | 0 | return VRDisplayCapabilities_Binding::Wrap(aCx, this, aGivenProto); |
260 | 0 | } |
261 | | |
262 | | VRPose::VRPose(nsISupports* aParent, const gfx::VRHMDSensorState& aState) |
263 | | : Pose(aParent) |
264 | | , mVRState(aState) |
265 | 0 | { |
266 | 0 | mozilla::HoldJSObjects(this); |
267 | 0 | } |
268 | | |
269 | | VRPose::VRPose(nsISupports* aParent) |
270 | | : Pose(aParent) |
271 | 0 | { |
272 | 0 | mVRState.inputFrameID = 0; |
273 | 0 | mVRState.timestamp = 0.0; |
274 | 0 | mVRState.flags = gfx::VRDisplayCapabilityFlags::Cap_None; |
275 | 0 | mozilla::HoldJSObjects(this); |
276 | 0 | } |
277 | | |
278 | | VRPose::~VRPose() |
279 | 0 | { |
280 | 0 | mozilla::DropJSObjects(this); |
281 | 0 | } |
282 | | |
283 | | void |
284 | | VRPose::GetPosition(JSContext* aCx, |
285 | | JS::MutableHandle<JSObject*> aRetval, |
286 | | ErrorResult& aRv) |
287 | 0 | { |
288 | 0 | SetFloat32Array(aCx, aRetval, mPosition, mVRState.pose.position, 3, |
289 | 0 | !mPosition && bool(mVRState.flags & gfx::VRDisplayCapabilityFlags::Cap_Position), |
290 | 0 | aRv); |
291 | 0 | } |
292 | | |
293 | | void |
294 | | VRPose::GetLinearVelocity(JSContext* aCx, |
295 | | JS::MutableHandle<JSObject*> aRetval, |
296 | | ErrorResult& aRv) |
297 | 0 | { |
298 | 0 | SetFloat32Array(aCx, aRetval, mLinearVelocity, mVRState.pose.linearVelocity, 3, |
299 | 0 | !mLinearVelocity && bool(mVRState.flags & gfx::VRDisplayCapabilityFlags::Cap_Position), |
300 | 0 | aRv); |
301 | 0 | } |
302 | | |
303 | | void |
304 | | VRPose::GetLinearAcceleration(JSContext* aCx, |
305 | | JS::MutableHandle<JSObject*> aRetval, |
306 | | ErrorResult& aRv) |
307 | 0 | { |
308 | 0 | SetFloat32Array(aCx, aRetval, mLinearAcceleration, mVRState.pose.linearAcceleration, 3, |
309 | 0 | !mLinearAcceleration && bool(mVRState.flags & gfx::VRDisplayCapabilityFlags::Cap_LinearAcceleration), |
310 | 0 | aRv); |
311 | 0 |
|
312 | 0 | } |
313 | | |
314 | | void |
315 | | VRPose::GetOrientation(JSContext* aCx, |
316 | | JS::MutableHandle<JSObject*> aRetval, |
317 | | ErrorResult& aRv) |
318 | 0 | { |
319 | 0 | SetFloat32Array(aCx, aRetval, mOrientation, mVRState.pose.orientation, 4, |
320 | 0 | !mOrientation && bool(mVRState.flags & gfx::VRDisplayCapabilityFlags::Cap_Orientation), |
321 | 0 | aRv); |
322 | 0 | } |
323 | | |
324 | | void |
325 | | VRPose::GetAngularVelocity(JSContext* aCx, |
326 | | JS::MutableHandle<JSObject*> aRetval, |
327 | | ErrorResult& aRv) |
328 | 0 | { |
329 | 0 | SetFloat32Array(aCx, aRetval, mAngularVelocity, mVRState.pose.angularVelocity, 3, |
330 | 0 | !mAngularVelocity && bool(mVRState.flags & gfx::VRDisplayCapabilityFlags::Cap_Orientation), |
331 | 0 | aRv); |
332 | 0 | } |
333 | | |
334 | | void |
335 | | VRPose::GetAngularAcceleration(JSContext* aCx, |
336 | | JS::MutableHandle<JSObject*> aRetval, |
337 | | ErrorResult& aRv) |
338 | 0 | { |
339 | 0 | SetFloat32Array(aCx, aRetval, mAngularAcceleration, mVRState.pose.angularAcceleration, 3, |
340 | 0 | !mAngularAcceleration && bool(mVRState.flags & gfx::VRDisplayCapabilityFlags::Cap_AngularAcceleration), |
341 | 0 | aRv); |
342 | 0 | } |
343 | | |
344 | | JSObject* |
345 | | VRPose::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) |
346 | 0 | { |
347 | 0 | return VRPose_Binding::Wrap(aCx, this, aGivenProto); |
348 | 0 | } |
349 | | |
350 | | /* virtual */ JSObject* |
351 | | VRDisplay::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) |
352 | 0 | { |
353 | 0 | return VRDisplay_Binding::Wrap(aCx, this, aGivenProto); |
354 | 0 | } |
355 | | |
356 | | VRDisplay::VRDisplay(nsPIDOMWindowInner* aWindow, gfx::VRDisplayClient* aClient) |
357 | | : DOMEventTargetHelper(aWindow) |
358 | | , mClient(aClient) |
359 | | , mDepthNear(0.01f) // Default value from WebVR Spec |
360 | | , mDepthFar(10000.0f) // Default value from WebVR Spec |
361 | | , mVRNavigationEventDepth(0) |
362 | | , mShutdown(false) |
363 | 0 | { |
364 | 0 | const gfx::VRDisplayInfo& info = aClient->GetDisplayInfo(); |
365 | 0 | mDisplayId = info.GetDisplayID(); |
366 | 0 | mDisplayName = NS_ConvertASCIItoUTF16(info.GetDisplayName()); |
367 | 0 | mCapabilities = new VRDisplayCapabilities(aWindow, info.GetCapabilities()); |
368 | 0 | if (info.GetCapabilities() & gfx::VRDisplayCapabilityFlags::Cap_StageParameters) { |
369 | 0 | mStageParameters = new VRStageParameters(aWindow, |
370 | 0 | info.GetSittingToStandingTransform(), |
371 | 0 | info.GetStageSize()); |
372 | 0 | } |
373 | 0 | mozilla::HoldJSObjects(this); |
374 | 0 | nsCOMPtr<nsIObserverService> obs = services::GetObserverService(); |
375 | 0 | if (MOZ_LIKELY(obs)) { |
376 | 0 | obs->AddObserver(this, "inner-window-destroyed", false); |
377 | 0 | } |
378 | 0 | } |
379 | | |
380 | | VRDisplay::~VRDisplay() |
381 | 0 | { |
382 | 0 | MOZ_ASSERT(mShutdown); |
383 | 0 | mozilla::DropJSObjects(this); |
384 | 0 | } |
385 | | |
386 | | void |
387 | | VRDisplay::LastRelease() |
388 | 0 | { |
389 | 0 | // We don't want to wait for the CC to free up the presentation |
390 | 0 | // for use in other documents, so we do this in LastRelease(). |
391 | 0 | Shutdown(); |
392 | 0 | } |
393 | | |
394 | | already_AddRefed<VREyeParameters> |
395 | | VRDisplay::GetEyeParameters(VREye aEye) |
396 | 0 | { |
397 | 0 | gfx::VRDisplayState::Eye eye = aEye == VREye::Left ? gfx::VRDisplayState::Eye_Left : gfx::VRDisplayState::Eye_Right; |
398 | 0 | RefPtr<VREyeParameters> params = |
399 | 0 | new VREyeParameters(GetParentObject(), |
400 | 0 | mClient->GetDisplayInfo().GetEyeTranslation(eye), |
401 | 0 | mClient->GetDisplayInfo().GetEyeFOV(eye), |
402 | 0 | mClient->GetDisplayInfo().SuggestedEyeResolution()); |
403 | 0 | return params.forget(); |
404 | 0 | } |
405 | | |
406 | | VRDisplayCapabilities* |
407 | | VRDisplay::Capabilities() |
408 | 0 | { |
409 | 0 | return mCapabilities; |
410 | 0 | } |
411 | | |
412 | | VRStageParameters* |
413 | | VRDisplay::GetStageParameters() |
414 | 0 | { |
415 | 0 | return mStageParameters; |
416 | 0 | } |
417 | | |
418 | | void |
419 | | VRDisplay::UpdateFrameInfo() |
420 | 0 | { |
421 | 0 | /** |
422 | 0 | * The WebVR 1.1 spec Requires that VRDisplay.getPose and VRDisplay.getFrameData |
423 | 0 | * must return the same values until the next VRDisplay.submitFrame. |
424 | 0 | * |
425 | 0 | * mFrameInfo is marked dirty at the end of the frame or start of a new |
426 | 0 | * composition and lazily created here in order to receive mid-frame |
427 | 0 | * pose-prediction updates while still ensuring conformance to the WebVR spec |
428 | 0 | * requirements. |
429 | 0 | * |
430 | 0 | * If we are not presenting WebVR content, the frame will never end and we should |
431 | 0 | * return the latest frame data always. |
432 | 0 | */ |
433 | 0 | if (mFrameInfo.IsDirty() || !mPresentation) { |
434 | 0 | gfx::VRHMDSensorState state = mClient->GetSensorState(); |
435 | 0 | const gfx::VRDisplayInfo& info = mClient->GetDisplayInfo(); |
436 | 0 | mFrameInfo.Update(info, state, mDepthNear, mDepthFar); |
437 | 0 | } |
438 | 0 | } |
439 | | |
440 | | bool |
441 | | VRDisplay::GetFrameData(VRFrameData& aFrameData) |
442 | 0 | { |
443 | 0 | UpdateFrameInfo(); |
444 | 0 | if (!(mFrameInfo.mVRState.flags & gfx::VRDisplayCapabilityFlags::Cap_Orientation)) { |
445 | 0 | // We must have at minimum Cap_Orientation for a valid pose. |
446 | 0 | return false; |
447 | 0 | } |
448 | 0 | aFrameData.Update(mFrameInfo); |
449 | 0 | return true; |
450 | 0 | } |
451 | | |
452 | | bool |
453 | | VRDisplay::GetSubmitFrameResult(VRSubmitFrameResult& aResult) |
454 | 0 | { |
455 | 0 | if (!mPresentation) { |
456 | 0 | return false; |
457 | 0 | } |
458 | 0 | |
459 | 0 | VRSubmitFrameResultInfo resultInfo; |
460 | 0 | mClient->GetSubmitFrameResult(resultInfo); |
461 | 0 | if (!resultInfo.mBase64Image.Length()) { |
462 | 0 | return false; // The submit frame result is not ready. |
463 | 0 | } |
464 | 0 | |
465 | 0 | nsAutoCString decodedImg; |
466 | 0 | if (Base64Decode(resultInfo.mBase64Image, decodedImg) != NS_OK) { |
467 | 0 | MOZ_ASSERT(false, "Failed to do decode base64 images."); |
468 | 0 | return false; |
469 | 0 | } |
470 | 0 |
|
471 | 0 | const char* srcData = decodedImg.get(); |
472 | 0 | const gfx::IntSize size(resultInfo.mWidth, resultInfo.mHeight); |
473 | 0 | RefPtr<DataSourceSurface> dataSurface = gfx::CreateDataSourceSurfaceFromData( |
474 | 0 | size, resultInfo.mFormat, (uint8_t*)srcData, |
475 | 0 | StrideForFormatAndWidth(resultInfo.mFormat, resultInfo.mWidth)); |
476 | 0 | if (!dataSurface || !dataSurface->IsValid()) { |
477 | 0 | MOZ_ASSERT(false, "dataSurface is null."); |
478 | 0 | return false; |
479 | 0 | } |
480 | 0 |
|
481 | 0 | nsAutoCString encodedImg(gfxUtils::GetAsDataURI(dataSurface)); |
482 | 0 | aResult.Update(resultInfo.mFrameNum, encodedImg); |
483 | 0 | return true; |
484 | 0 | } |
485 | | |
486 | | already_AddRefed<VRPose> |
487 | | VRDisplay::GetPose() |
488 | 0 | { |
489 | 0 | UpdateFrameInfo(); |
490 | 0 | RefPtr<VRPose> obj = new VRPose(GetParentObject(), mFrameInfo.mVRState); |
491 | 0 |
|
492 | 0 | return obj.forget(); |
493 | 0 | } |
494 | | |
495 | | void |
496 | | VRDisplay::ResetPose() |
497 | 0 | { |
498 | 0 | mClient->ZeroSensor(); |
499 | 0 | } |
500 | | |
501 | | void |
502 | | VRDisplay::StartVRNavigation() |
503 | 0 | { |
504 | 0 | mClient->StartVRNavigation(); |
505 | 0 | } |
506 | | |
507 | | void |
508 | | VRDisplay::StartHandlingVRNavigationEvent() |
509 | 0 | { |
510 | 0 | mHandlingVRNavigationEventStart = TimeStamp::Now(); |
511 | 0 | ++mVRNavigationEventDepth; |
512 | 0 | TimeDuration timeout = TimeDuration::FromMilliseconds(gfxPrefs::VRNavigationTimeout()); |
513 | 0 | // A 0 or negative TimeDuration indicates that content may take |
514 | 0 | // as long as it wishes to respond to the event, as long as |
515 | 0 | // it happens before the event exits. |
516 | 0 | if (timeout.ToMilliseconds() > 0) { |
517 | 0 | mClient->StopVRNavigation(timeout); |
518 | 0 | } |
519 | 0 | } |
520 | | |
521 | | void |
522 | | VRDisplay::StopHandlingVRNavigationEvent() |
523 | 0 | { |
524 | 0 | MOZ_ASSERT(mVRNavigationEventDepth > 0); |
525 | 0 | --mVRNavigationEventDepth; |
526 | 0 | if (mVRNavigationEventDepth == 0) { |
527 | 0 | mClient->StopVRNavigation(TimeDuration::FromMilliseconds(0)); |
528 | 0 | } |
529 | 0 | } |
530 | | |
531 | | bool |
532 | | VRDisplay::IsHandlingVRNavigationEvent() |
533 | 0 | { |
534 | 0 | if (mVRNavigationEventDepth == 0) { |
535 | 0 | return false; |
536 | 0 | } |
537 | 0 | if (mHandlingVRNavigationEventStart.IsNull()) { |
538 | 0 | return false; |
539 | 0 | } |
540 | 0 | TimeDuration timeout = TimeDuration::FromMilliseconds(gfxPrefs::VRNavigationTimeout()); |
541 | 0 | return timeout.ToMilliseconds() <= 0 || |
542 | 0 | (TimeStamp::Now() - mHandlingVRNavigationEventStart) <= timeout; |
543 | 0 | } |
544 | | |
545 | | void |
546 | 0 | VRDisplay::OnPresentationGenerationChanged() { |
547 | 0 | ExitPresentInternal(); |
548 | 0 | } |
549 | | |
550 | | already_AddRefed<Promise> |
551 | | VRDisplay::RequestPresent(const nsTArray<VRLayer>& aLayers, |
552 | | CallerType aCallerType, |
553 | | ErrorResult& aRv) |
554 | 0 | { |
555 | 0 | nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(GetParentObject()); |
556 | 0 | if (!global) { |
557 | 0 | aRv.Throw(NS_ERROR_FAILURE); |
558 | 0 | return nullptr; |
559 | 0 | } |
560 | 0 | |
561 | 0 | RefPtr<Promise> promise = Promise::Create(global, aRv); |
562 | 0 | NS_ENSURE_TRUE(!aRv.Failed(), nullptr); |
563 | 0 |
|
564 | 0 | bool isChromePresentation = aCallerType == CallerType::System; |
565 | 0 | uint32_t presentationGroup = isChromePresentation ? gfx::kVRGroupChrome : gfx::kVRGroupContent; |
566 | 0 |
|
567 | 0 | if (!EventStateManager::IsHandlingUserInput() && |
568 | 0 | !isChromePresentation && |
569 | 0 | !IsHandlingVRNavigationEvent() && |
570 | 0 | gfxPrefs::VRRequireGesture() && |
571 | 0 | !IsPresenting()) { |
572 | 0 | // The WebVR API states that if called outside of a user gesture, the |
573 | 0 | // promise must be rejected. We allow VR presentations to start within |
574 | 0 | // trusted events such as vrdisplayactivate, which triggers in response to |
575 | 0 | // HMD proximity sensors and when navigating within a VR presentation. |
576 | 0 | // This user gesture requirement is not enforced for chrome/system code. |
577 | 0 | promise->MaybeRejectWithUndefined(); |
578 | 0 | } else if (!IsPresenting() && IsAnyPresenting(presentationGroup)) { |
579 | 0 | // Only one presentation allowed per VRDisplay on a |
580 | 0 | // first-come-first-serve basis. |
581 | 0 | // If this Javascript context is presenting, then we can replace our |
582 | 0 | // presentation with a new one containing new layers but we should never |
583 | 0 | // replace the presentation of another context. |
584 | 0 | // Simultaneous presentations in other groups are allowed in separate |
585 | 0 | // Javascript contexts to enable browser UI from chrome/system contexts. |
586 | 0 | // Eventually, this restriction will be loosened to enable multitasking |
587 | 0 | // use cases. |
588 | 0 | promise->MaybeRejectWithUndefined(); |
589 | 0 | } else { |
590 | 0 | if (mPresentation) { |
591 | 0 | mPresentation->UpdateLayers(aLayers); |
592 | 0 | } else { |
593 | 0 | mPresentation = mClient->BeginPresentation(aLayers, presentationGroup); |
594 | 0 | } |
595 | 0 | mFrameInfo.Clear(); |
596 | 0 | promise->MaybeResolve(JS::UndefinedHandleValue); |
597 | 0 | } |
598 | 0 | return promise.forget(); |
599 | 0 | } |
600 | | |
601 | | NS_IMETHODIMP |
602 | | VRDisplay::Observe(nsISupports* aSubject, const char* aTopic, |
603 | | const char16_t* aData) |
604 | 0 | { |
605 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
606 | 0 |
|
607 | 0 | if (strcmp(aTopic, "inner-window-destroyed") == 0) { |
608 | 0 | nsCOMPtr<nsISupportsPRUint64> wrapper = do_QueryInterface(aSubject); |
609 | 0 | NS_ENSURE_TRUE(wrapper, NS_ERROR_FAILURE); |
610 | 0 |
|
611 | 0 | uint64_t innerID; |
612 | 0 | nsresult rv = wrapper->GetData(&innerID); |
613 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
614 | 0 |
|
615 | 0 | if (!GetOwner() || GetOwner()->WindowID() == innerID) { |
616 | 0 | Shutdown(); |
617 | 0 | } |
618 | 0 |
|
619 | 0 | return NS_OK; |
620 | 0 | } |
621 | 0 |
|
622 | 0 | // This should not happen. |
623 | 0 | return NS_ERROR_FAILURE; |
624 | 0 | } |
625 | | |
626 | | already_AddRefed<Promise> |
627 | | VRDisplay::ExitPresent(ErrorResult& aRv) |
628 | 0 | { |
629 | 0 | nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(GetParentObject()); |
630 | 0 | if (!global) { |
631 | 0 | aRv.Throw(NS_ERROR_FAILURE); |
632 | 0 | return nullptr; |
633 | 0 | } |
634 | 0 | |
635 | 0 | |
636 | 0 | RefPtr<Promise> promise = Promise::Create(global, aRv); |
637 | 0 | NS_ENSURE_TRUE(!aRv.Failed(), nullptr); |
638 | 0 |
|
639 | 0 | if (!IsPresenting()) { |
640 | 0 | // We can not exit a presentation outside of the context that |
641 | 0 | // started the presentation. |
642 | 0 | promise->MaybeRejectWithUndefined(); |
643 | 0 | } else { |
644 | 0 | promise->MaybeResolve(JS::UndefinedHandleValue); |
645 | 0 | ExitPresentInternal(); |
646 | 0 | } |
647 | 0 |
|
648 | 0 | return promise.forget(); |
649 | 0 | } |
650 | | |
651 | | void |
652 | | VRDisplay::ExitPresentInternal() |
653 | 0 | { |
654 | 0 | mPresentation = nullptr; |
655 | 0 | } |
656 | | |
657 | | void |
658 | | VRDisplay::Shutdown() |
659 | 0 | { |
660 | 0 | mShutdown = true; |
661 | 0 | ExitPresentInternal(); |
662 | 0 | nsCOMPtr<nsIObserverService> obs = services::GetObserverService(); |
663 | 0 | if (MOZ_LIKELY(obs)) { |
664 | 0 | obs->RemoveObserver(this, "inner-window-destroyed"); |
665 | 0 | } |
666 | 0 | } |
667 | | |
668 | | void |
669 | | VRDisplay::GetLayers(nsTArray<VRLayer>& result) |
670 | 0 | { |
671 | 0 | if (mPresentation) { |
672 | 0 | mPresentation->GetDOMLayers(result); |
673 | 0 | } else { |
674 | 0 | result = nsTArray<VRLayer>(); |
675 | 0 | } |
676 | 0 | } |
677 | | |
678 | | void |
679 | | VRDisplay::SubmitFrame() |
680 | 0 | { |
681 | 0 | AUTO_PROFILER_TRACING("VR", "SubmitFrameAtVRDisplay"); |
682 | 0 |
|
683 | 0 | if (mClient && !mClient->IsPresentationGenerationCurrent()) { |
684 | 0 | mPresentation = nullptr; |
685 | 0 | mClient->MakePresentationGenerationCurrent(); |
686 | 0 | } |
687 | 0 |
|
688 | 0 | if (mPresentation) { |
689 | 0 | mPresentation->SubmitFrame(); |
690 | 0 | } |
691 | 0 | mFrameInfo.Clear(); |
692 | 0 | } |
693 | | |
694 | | int32_t |
695 | | VRDisplay::RequestAnimationFrame(FrameRequestCallback& aCallback, |
696 | | ErrorResult& aError) |
697 | 0 | { |
698 | 0 | if (mShutdown) { |
699 | 0 | return 0; |
700 | 0 | } |
701 | 0 | |
702 | 0 | gfx::VRManagerChild* vm = gfx::VRManagerChild::Get(); |
703 | 0 |
|
704 | 0 | int32_t handle; |
705 | 0 | aError = vm->ScheduleFrameRequestCallback(aCallback, &handle); |
706 | 0 | return handle; |
707 | 0 | } |
708 | | |
709 | | void |
710 | | VRDisplay::CancelAnimationFrame(int32_t aHandle, ErrorResult& aError) |
711 | 0 | { |
712 | 0 | gfx::VRManagerChild* vm = gfx::VRManagerChild::Get(); |
713 | 0 | vm->CancelFrameRequestCallback(aHandle); |
714 | 0 | } |
715 | | |
716 | | |
717 | | bool |
718 | | VRDisplay::IsPresenting() const |
719 | 0 | { |
720 | 0 | // IsPresenting returns true only if this Javascript context is presenting |
721 | 0 | // and will return false if another context is presenting. |
722 | 0 | return mPresentation != nullptr; |
723 | 0 | } |
724 | | |
725 | | bool |
726 | | VRDisplay::IsAnyPresenting(uint32_t aGroupMask) const |
727 | 0 | { |
728 | 0 | // IsAnyPresenting returns true if either this VRDisplay object or any other |
729 | 0 | // from anther Javascript context is presenting with a group matching |
730 | 0 | // aGroupMask. |
731 | 0 | if (mPresentation && (mPresentation->GetGroup() & aGroupMask)) { |
732 | 0 | return true; |
733 | 0 | } |
734 | 0 | if (mClient->GetDisplayInfo().GetPresentingGroups() & aGroupMask) { |
735 | 0 | return true; |
736 | 0 | } |
737 | 0 | return false; |
738 | 0 | } |
739 | | |
740 | | bool |
741 | | VRDisplay::IsConnected() const |
742 | 0 | { |
743 | 0 | return mClient->GetIsConnected(); |
744 | 0 | } |
745 | | |
746 | | uint32_t |
747 | | VRDisplay::PresentingGroups() const |
748 | 0 | { |
749 | 0 | return mClient->GetDisplayInfo().GetPresentingGroups(); |
750 | 0 | } |
751 | | |
752 | | uint32_t |
753 | | VRDisplay::GroupMask() const |
754 | 0 | { |
755 | 0 | return mClient->GetDisplayInfo().GetGroupMask(); |
756 | 0 | } |
757 | | |
758 | | void |
759 | | VRDisplay::SetGroupMask(const uint32_t& aGroupMask) |
760 | 0 | { |
761 | 0 | mClient->SetGroupMask(aGroupMask); |
762 | 0 | } |
763 | | |
764 | | NS_IMPL_CYCLE_COLLECTION_INHERITED(VRDisplay, DOMEventTargetHelper, mCapabilities, mStageParameters) |
765 | | |
766 | | NS_IMPL_ADDREF_INHERITED(VRDisplay, DOMEventTargetHelper) |
767 | | NS_IMPL_RELEASE_INHERITED(VRDisplay, DOMEventTargetHelper) |
768 | | |
769 | 0 | NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(VRDisplay) |
770 | 0 | NS_INTERFACE_MAP_ENTRY(nsIObserver) |
771 | 0 | NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, DOMEventTargetHelper) |
772 | 0 | NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper) |
773 | | |
774 | | NS_IMPL_CYCLE_COLLECTION_CLASS(VRFrameData) |
775 | | |
776 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(VRFrameData) |
777 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK(mParent, mPose) |
778 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER |
779 | 0 | tmp->mLeftProjectionMatrix = nullptr; |
780 | 0 | tmp->mLeftViewMatrix = nullptr; |
781 | 0 | tmp->mRightProjectionMatrix = nullptr; |
782 | 0 | tmp->mRightViewMatrix = nullptr; |
783 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK_END |
784 | | |
785 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(VRFrameData) |
786 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParent, mPose) |
787 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END |
788 | | |
789 | 0 | NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(VRFrameData) |
790 | 0 | NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER |
791 | 0 | NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mLeftProjectionMatrix) |
792 | 0 | NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mLeftViewMatrix) |
793 | 0 | NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mRightProjectionMatrix) |
794 | 0 | NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mRightViewMatrix) |
795 | 0 | NS_IMPL_CYCLE_COLLECTION_TRACE_END |
796 | | |
797 | | NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(VRFrameData, AddRef) |
798 | | NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(VRFrameData, Release) |
799 | | |
800 | | VRFrameData::VRFrameData(nsISupports* aParent) |
801 | | : mParent(aParent) |
802 | | , mLeftProjectionMatrix(nullptr) |
803 | | , mLeftViewMatrix(nullptr) |
804 | | , mRightProjectionMatrix(nullptr) |
805 | | , mRightViewMatrix(nullptr) |
806 | 0 | { |
807 | 0 | mozilla::HoldJSObjects(this); |
808 | 0 | mPose = new VRPose(aParent); |
809 | 0 | } |
810 | | |
811 | | VRFrameData::~VRFrameData() |
812 | 0 | { |
813 | 0 | mozilla::DropJSObjects(this); |
814 | 0 | } |
815 | | |
816 | | /* static */ already_AddRefed<VRFrameData> |
817 | | VRFrameData::Constructor(const GlobalObject& aGlobal, ErrorResult& aRv) |
818 | 0 | { |
819 | 0 | RefPtr<VRFrameData> obj = new VRFrameData(aGlobal.GetAsSupports()); |
820 | 0 | return obj.forget(); |
821 | 0 | } |
822 | | |
823 | | JSObject* |
824 | | VRFrameData::WrapObject(JSContext* aCx, |
825 | | JS::Handle<JSObject*> aGivenProto) |
826 | 0 | { |
827 | 0 | return VRFrameData_Binding::Wrap(aCx, this, aGivenProto); |
828 | 0 | } |
829 | | |
830 | | VRPose* |
831 | | VRFrameData::Pose() |
832 | 0 | { |
833 | 0 | return mPose; |
834 | 0 | } |
835 | | |
836 | | void |
837 | | VRFrameData::LazyCreateMatrix(JS::Heap<JSObject*>& aArray, gfx::Matrix4x4& aMat, JSContext* aCx, |
838 | | JS::MutableHandle<JSObject*> aRetval, ErrorResult& aRv) |
839 | 0 | { |
840 | 0 | if (!aArray) { |
841 | 0 | // Lazily create the Float32Array |
842 | 0 | aArray = dom::Float32Array::Create(aCx, this, 16, aMat.components); |
843 | 0 | if (!aArray) { |
844 | 0 | aRv.NoteJSContextException(aCx); |
845 | 0 | return; |
846 | 0 | } |
847 | 0 | } |
848 | 0 | if (aArray) { |
849 | 0 | JS::ExposeObjectToActiveJS(aArray); |
850 | 0 | } |
851 | 0 | aRetval.set(aArray); |
852 | 0 | } |
853 | | |
854 | | double |
855 | | VRFrameData::Timestamp() const |
856 | 0 | { |
857 | 0 | // Converting from seconds to milliseconds |
858 | 0 | return mFrameInfo.mVRState.timestamp * 1000.0f; |
859 | 0 | } |
860 | | |
861 | | void |
862 | | VRFrameData::GetLeftProjectionMatrix(JSContext* aCx, |
863 | | JS::MutableHandle<JSObject*> aRetval, |
864 | | ErrorResult& aRv) |
865 | 0 | { |
866 | 0 | LazyCreateMatrix(mLeftProjectionMatrix, mFrameInfo.mLeftProjection, aCx, |
867 | 0 | aRetval, aRv); |
868 | 0 | } |
869 | | |
870 | | void |
871 | | VRFrameData::GetLeftViewMatrix(JSContext* aCx, |
872 | | JS::MutableHandle<JSObject*> aRetval, |
873 | | ErrorResult& aRv) |
874 | 0 | { |
875 | 0 | LazyCreateMatrix(mLeftViewMatrix, mFrameInfo.mLeftView, aCx, aRetval, aRv); |
876 | 0 | } |
877 | | |
878 | | void |
879 | | VRFrameData::GetRightProjectionMatrix(JSContext* aCx, |
880 | | JS::MutableHandle<JSObject*> aRetval, |
881 | | ErrorResult& aRv) |
882 | 0 | { |
883 | 0 | LazyCreateMatrix(mRightProjectionMatrix, mFrameInfo.mRightProjection, aCx, |
884 | 0 | aRetval, aRv); |
885 | 0 | } |
886 | | |
887 | | void |
888 | | VRFrameData::GetRightViewMatrix(JSContext* aCx, |
889 | | JS::MutableHandle<JSObject*> aRetval, |
890 | | ErrorResult& aRv) |
891 | 0 | { |
892 | 0 | LazyCreateMatrix(mRightViewMatrix, mFrameInfo.mRightView, aCx, aRetval, aRv); |
893 | 0 | } |
894 | | |
895 | | void |
896 | | VRFrameData::Update(const VRFrameInfo& aFrameInfo) |
897 | 0 | { |
898 | 0 | mFrameInfo = aFrameInfo; |
899 | 0 |
|
900 | 0 | mLeftProjectionMatrix = nullptr; |
901 | 0 | mLeftViewMatrix = nullptr; |
902 | 0 | mRightProjectionMatrix = nullptr; |
903 | 0 | mRightViewMatrix = nullptr; |
904 | 0 |
|
905 | 0 | mPose = new VRPose(GetParentObject(), mFrameInfo.mVRState); |
906 | 0 | } |
907 | | |
908 | | void |
909 | | VRFrameInfo::Update(const gfx::VRDisplayInfo& aInfo, |
910 | | const gfx::VRHMDSensorState& aState, |
911 | | float aDepthNear, |
912 | | float aDepthFar) |
913 | 0 | { |
914 | 0 | mVRState = aState; |
915 | 0 | if (mTimeStampOffset == 0.0f) { |
916 | 0 | /** |
917 | 0 | * A mTimeStampOffset value of 0.0f indicates that this is the first iteration |
918 | 0 | * and an offset has not yet been set. |
919 | 0 | * |
920 | 0 | * Generate a value for mTimeStampOffset such that if aState.timestamp is |
921 | 0 | * monotonically increasing, aState.timestamp + mTimeStampOffset will never |
922 | 0 | * be a negative number and will start at a pseudo-random offset |
923 | 0 | * between 1000.0f and 11000.0f seconds. |
924 | 0 | * |
925 | 0 | * We use a pseudo random offset rather than 0.0f just to discourage users |
926 | 0 | * from making the assumption that the timestamp returned in the WebVR API |
927 | 0 | * has a base of 0, which is not necessarily true in all UA's. |
928 | 0 | */ |
929 | 0 | mTimeStampOffset = float(rand()) / RAND_MAX * 10000.0f + 1000.0f - aState.timestamp; |
930 | 0 | } |
931 | 0 | mVRState.timestamp = aState.timestamp + mTimeStampOffset; |
932 | 0 |
|
933 | 0 | // Avoid division by zero within ConstructProjectionMatrix |
934 | 0 | const float kEpsilon = 0.00001f; |
935 | 0 | if (fabs(aDepthFar - aDepthNear) < kEpsilon) { |
936 | 0 | aDepthFar = aDepthNear + kEpsilon; |
937 | 0 | } |
938 | 0 |
|
939 | 0 | const gfx::VRFieldOfView leftFOV = aInfo.mDisplayState.mEyeFOV[gfx::VRDisplayState::Eye_Left]; |
940 | 0 | mLeftProjection = leftFOV.ConstructProjectionMatrix(aDepthNear, aDepthFar, true); |
941 | 0 | const gfx::VRFieldOfView rightFOV = aInfo.mDisplayState.mEyeFOV[gfx::VRDisplayState::Eye_Right]; |
942 | 0 | mRightProjection = rightFOV.ConstructProjectionMatrix(aDepthNear, aDepthFar, true); |
943 | 0 | memcpy(mLeftView.components, aState.leftViewMatrix, sizeof(aState.leftViewMatrix)); |
944 | 0 | memcpy(mRightView.components, aState.rightViewMatrix, sizeof(aState.rightViewMatrix)); |
945 | 0 | } |
946 | | |
947 | | VRFrameInfo::VRFrameInfo() |
948 | | : mTimeStampOffset(0.0f) |
949 | 0 | { |
950 | 0 | mVRState.inputFrameID = 0; |
951 | 0 | mVRState.timestamp = 0.0; |
952 | 0 | mVRState.flags = gfx::VRDisplayCapabilityFlags::Cap_None; |
953 | 0 | } |
954 | | |
955 | | bool |
956 | | VRFrameInfo::IsDirty() |
957 | 0 | { |
958 | 0 | return mVRState.timestamp == 0; |
959 | 0 | } |
960 | | |
961 | | void |
962 | | VRFrameInfo::Clear() |
963 | 0 | { |
964 | 0 | mVRState.Clear(); |
965 | 0 | } |
966 | | |
967 | | NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(VRSubmitFrameResult, mParent) |
968 | | NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(VRSubmitFrameResult, AddRef) |
969 | | NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(VRSubmitFrameResult, Release) |
970 | | |
971 | | VRSubmitFrameResult::VRSubmitFrameResult(nsISupports* aParent) |
972 | | : mParent(aParent) |
973 | | , mFrameNum(0) |
974 | 0 | { |
975 | 0 | mozilla::HoldJSObjects(this); |
976 | 0 | } |
977 | | |
978 | | VRSubmitFrameResult::~VRSubmitFrameResult() |
979 | 0 | { |
980 | 0 | mozilla::DropJSObjects(this); |
981 | 0 | } |
982 | | |
983 | | /* static */ already_AddRefed<VRSubmitFrameResult> |
984 | | VRSubmitFrameResult::Constructor(const GlobalObject& aGlobal, ErrorResult& aRv) |
985 | 0 | { |
986 | 0 | RefPtr<VRSubmitFrameResult> obj = new VRSubmitFrameResult(aGlobal.GetAsSupports()); |
987 | 0 | return obj.forget(); |
988 | 0 | } |
989 | | |
990 | | JSObject* |
991 | | VRSubmitFrameResult::WrapObject(JSContext* aCx, |
992 | | JS::Handle<JSObject*> aGivenProto) |
993 | 0 | { |
994 | 0 | return VRSubmitFrameResult_Binding::Wrap(aCx, this, aGivenProto); |
995 | 0 | } |
996 | | |
997 | | void |
998 | | VRSubmitFrameResult::Update(uint64_t aFrameNum, const nsACString& aBase64Image) |
999 | 0 | { |
1000 | 0 | mFrameNum = aFrameNum; |
1001 | 0 | mBase64Image = NS_ConvertASCIItoUTF16(aBase64Image); |
1002 | 0 | } |
1003 | | |
1004 | | double |
1005 | | VRSubmitFrameResult::FrameNum() const |
1006 | 0 | { |
1007 | 0 | return mFrameNum; |
1008 | 0 | } |
1009 | | |
1010 | | void |
1011 | | VRSubmitFrameResult::GetBase64Image(nsAString& aImage) const |
1012 | 0 | { |
1013 | 0 | aImage = mBase64Image; |
1014 | 0 | } |
1015 | | |
1016 | | } // namespace dom |
1017 | | } // namespace mozilla |