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
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7 #include "VREventObserver.h"
8
9 #include "nsContentUtils.h"
10 #include "nsGlobalWindow.h"
11
12 #include "mozilla/Telemetry.h"
13
14 namespace mozilla {
15 namespace dom {
16
17 using namespace gfx;
18
19 /**
20 * This class is used by nsGlobalWindow to implement window.onvrdisplayactivate,
21 * window.onvrdisplaydeactivate, window.onvrdisplayconnected,
22 * window.onvrdisplaydisconnected, and window.onvrdisplaypresentchange.
23 */
VREventObserver(nsGlobalWindowInner * aGlobalWindow)24 VREventObserver::VREventObserver(nsGlobalWindowInner* aGlobalWindow)
25 : mWindow(aGlobalWindow),
26 mIs2DView(true),
27 mHasReset(false),
28 mStopActivity(false) {
29 MOZ_ASSERT(aGlobalWindow);
30
31 UpdateSpentTimeIn2DTelemetry(false);
32 VRManagerChild* vmc = VRManagerChild::Get();
33 if (vmc) {
34 vmc->AddListener(this);
35 }
36 }
37
~VREventObserver()38 VREventObserver::~VREventObserver() { DisconnectFromOwner(); }
39
DisconnectFromOwner()40 void VREventObserver::DisconnectFromOwner() {
41 // In the event that nsGlobalWindow is deallocated, VREventObserver may
42 // still be AddRef'ed elsewhere. Ensure that we don't UAF by
43 // dereferencing mWindow.
44 UpdateSpentTimeIn2DTelemetry(true);
45 mWindow = nullptr;
46
47 // Unregister from VRManagerChild
48 if (VRManagerChild::IsCreated()) {
49 VRManagerChild* vmc = VRManagerChild::Get();
50 vmc->RemoveListener(this);
51 }
52 mStopActivity = true;
53 }
54
UpdateSpentTimeIn2DTelemetry(bool aUpdate)55 void VREventObserver::UpdateSpentTimeIn2DTelemetry(bool aUpdate) {
56 // mHasReset for avoiding setting the telemetry continuously
57 // for the telemetry is already been set when it is at the background.
58 // then, it would be set again when the process is exit and calling
59 // VREventObserver::DisconnectFromOwner().
60 if (mWindow && mIs2DView && aUpdate && mHasReset) {
61 // The WebVR content is closed, and we will collect the telemetry info
62 // for the users who view it in 2D view only.
63 Telemetry::Accumulate(Telemetry::WEBVR_USERS_VIEW_IN, 0);
64 Telemetry::AccumulateTimeDelta(Telemetry::WEBVR_TIME_SPENT_VIEWING_IN_2D,
65 mSpendTimeIn2DView);
66 mHasReset = false;
67 } else if (!aUpdate) {
68 mSpendTimeIn2DView = TimeStamp::Now();
69 mHasReset = true;
70 }
71 }
72
StartActivity()73 void VREventObserver::StartActivity() {
74 mStopActivity = false;
75 VRManagerChild* vmc = VRManagerChild::Get();
76 vmc->StartActivity();
77 }
78
StopActivity()79 void VREventObserver::StopActivity() {
80 mStopActivity = true;
81 VRManagerChild* vmc = VRManagerChild::Get();
82 vmc->StopActivity();
83 }
84
GetStopActivityStatus() const85 bool VREventObserver::GetStopActivityStatus() const { return mStopActivity; }
86
NotifyAfterLoad()87 void VREventObserver::NotifyAfterLoad() {
88 if (VRManagerChild::IsCreated()) {
89 VRManagerChild* vmc = VRManagerChild::Get();
90 vmc->FireDOMVRDisplayConnectEventsForLoad(this);
91 }
92 }
93
NotifyVRDisplayMounted(uint32_t aDisplayID)94 void VREventObserver::NotifyVRDisplayMounted(uint32_t aDisplayID) {
95 if (mWindow && mWindow->IsCurrentInnerWindow() && IsWebVR(aDisplayID)) {
96 MOZ_ASSERT(nsContentUtils::IsSafeToRunScript());
97 mWindow->DispatchVRDisplayActivate(aDisplayID,
98 VRDisplayEventReason::Mounted);
99 }
100 }
101
NotifyVRDisplayNavigation(uint32_t aDisplayID)102 void VREventObserver::NotifyVRDisplayNavigation(uint32_t aDisplayID) {
103 if (mWindow && mWindow->IsCurrentInnerWindow() && IsWebVR(aDisplayID)) {
104 MOZ_ASSERT(nsContentUtils::IsSafeToRunScript());
105 mWindow->DispatchVRDisplayActivate(aDisplayID,
106 VRDisplayEventReason::Navigation);
107 }
108 }
109
NotifyVRDisplayRequested(uint32_t aDisplayID)110 void VREventObserver::NotifyVRDisplayRequested(uint32_t aDisplayID) {
111 if (mWindow && mWindow->IsCurrentInnerWindow() && IsWebVR(aDisplayID)) {
112 MOZ_ASSERT(nsContentUtils::IsSafeToRunScript());
113 mWindow->DispatchVRDisplayActivate(aDisplayID,
114 VRDisplayEventReason::Requested);
115 }
116 }
117
NotifyVRDisplayUnmounted(uint32_t aDisplayID)118 void VREventObserver::NotifyVRDisplayUnmounted(uint32_t aDisplayID) {
119 if (mWindow && mWindow->IsCurrentInnerWindow() && IsWebVR(aDisplayID)) {
120 MOZ_ASSERT(nsContentUtils::IsSafeToRunScript());
121 mWindow->DispatchVRDisplayDeactivate(aDisplayID,
122 VRDisplayEventReason::Unmounted);
123 }
124 }
125
NotifyVRDisplayConnect(uint32_t aDisplayID)126 void VREventObserver::NotifyVRDisplayConnect(uint32_t aDisplayID) {
127 /**
128 * We do not call nsGlobalWindow::NotifyActiveVRDisplaysChanged here, as we
129 * can assume that a newly enumerated display is not presenting WebVR
130 * content.
131 */
132 if (mWindow && mWindow->IsCurrentInnerWindow() && IsWebVR(aDisplayID)) {
133 MOZ_ASSERT(nsContentUtils::IsSafeToRunScript());
134 mWindow->DispatchVRDisplayConnect(aDisplayID);
135 }
136 }
137
NotifyVRDisplayDisconnect(uint32_t aDisplayID)138 void VREventObserver::NotifyVRDisplayDisconnect(uint32_t aDisplayID) {
139 if (mWindow && mWindow->IsCurrentInnerWindow() && IsWebVR(aDisplayID)) {
140 mWindow->NotifyActiveVRDisplaysChanged();
141 MOZ_ASSERT(nsContentUtils::IsSafeToRunScript());
142 mWindow->DispatchVRDisplayDisconnect(aDisplayID);
143 }
144 }
145
NotifyVRDisplayPresentChange(uint32_t aDisplayID)146 void VREventObserver::NotifyVRDisplayPresentChange(uint32_t aDisplayID) {
147 // When switching to HMD present mode, it is no longer
148 // to be a 2D view.
149 mIs2DView = false;
150
151 if (mWindow && mWindow->IsCurrentInnerWindow() && IsWebVR(aDisplayID)) {
152 mWindow->NotifyActiveVRDisplaysChanged();
153 MOZ_ASSERT(nsContentUtils::IsSafeToRunScript());
154 mWindow->DispatchVRDisplayPresentChange(aDisplayID);
155 }
156 }
157
NotifyPresentationGenerationChanged(uint32_t aDisplayID)158 void VREventObserver::NotifyPresentationGenerationChanged(uint32_t aDisplayID) {
159 if (mWindow && mWindow->IsCurrentInnerWindow() && IsWebVR(aDisplayID)) {
160 MOZ_ASSERT(nsContentUtils::IsSafeToRunScript());
161 mWindow->NotifyPresentationGenerationChanged(aDisplayID);
162 }
163 }
164
NotifyEnumerationCompleted()165 void VREventObserver::NotifyEnumerationCompleted() {}
166
NotifyDetectRuntimesCompleted()167 void VREventObserver::NotifyDetectRuntimesCompleted() {
168 if (mWindow && mWindow->IsCurrentInnerWindow()) {
169 MOZ_ASSERT(nsContentUtils::IsSafeToRunScript());
170 mWindow->NotifyDetectXRRuntimesCompleted();
171 }
172 }
173
IsWebVR(uint32_t aDisplayID) const174 bool VREventObserver::IsWebVR(uint32_t aDisplayID) const {
175 VRManagerChild* vmc = VRManagerChild::Get();
176 if (vmc) {
177 return vmc->GetVRAPIMode(aDisplayID) == gfx::VRAPIMode::WebVR;
178 }
179 return true;
180 }
181
182 } // namespace dom
183 } // namespace mozilla
184