Deprecate ActiveDOMObject::canSuspendForDocumentSuspension()
[WebKit-https.git] / Source / WebCore / Modules / webvr / VRDisplay.cpp
1 /*
2  * Copyright (C) 2017-2018 Igalia S.L. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "VRDisplay.h"
28
29 #include "CanvasRenderingContext.h"
30 #include "Chrome.h"
31 #include "DOMException.h"
32 #include "DOMWindow.h"
33 #include "EventNames.h"
34 #include "JSDOMPromiseDeferred.h"
35 #include "Page.h"
36 #include "ScriptedAnimationController.h"
37 #include "UserGestureIndicator.h"
38 #include "VRDisplayCapabilities.h"
39 #include "VRDisplayEvent.h"
40 #include "VREyeParameters.h"
41 #include "VRFrameData.h"
42 #include "VRLayerInit.h"
43 #include "VRPlatformDisplay.h"
44 #include "VRPose.h"
45 #include "VRStageParameters.h"
46 #include <wtf/IsoMallocInlines.h>
47
48 namespace WebCore {
49
50 WTF_MAKE_ISO_ALLOCATED_IMPL(VRDisplay);
51
52 Ref<VRDisplay> VRDisplay::create(ScriptExecutionContext& context, WeakPtr<VRPlatformDisplay>&& platformDisplay)
53 {
54     return adoptRef(*new VRDisplay(context, WTFMove(platformDisplay)));
55 }
56
57 VRDisplay::VRDisplay(ScriptExecutionContext& context, WeakPtr<VRPlatformDisplay>&& platformDisplay)
58     : ActiveDOMObject(&context)
59     , m_display(WTFMove(platformDisplay))
60 {
61     auto displayInfo = m_display->getDisplayInfo();
62     m_capabilities = VRDisplayCapabilities::create(displayInfo.capabilityFlags());
63     m_leftEyeParameters = VREyeParameters::create(displayInfo.eyeTranslation(VRPlatformDisplayInfo::EyeLeft), displayInfo.eyeFieldOfView(VRPlatformDisplayInfo::EyeLeft), displayInfo.renderSize());
64     m_rightEyeParameters = VREyeParameters::create(displayInfo.eyeTranslation(VRPlatformDisplayInfo::EyeRight), displayInfo.eyeFieldOfView(VRPlatformDisplayInfo::EyeRight), displayInfo.renderSize());
65     m_displayId = displayInfo.displayIdentifier();
66     m_displayName = displayInfo.displayName();
67
68     m_display->setClient(this);
69     suspendIfNeeded();
70 }
71
72 VRDisplay::~VRDisplay()
73 {
74     m_display->setClient(nullptr);
75 }
76
77 bool VRDisplay::isConnected() const
78 {
79     if (!m_display)
80         return false;
81
82     return m_display->getDisplayInfo().isConnected();
83 }
84
85 const VRDisplayCapabilities& VRDisplay::capabilities() const
86 {
87     return *m_capabilities;
88 }
89
90 RefPtr<VRStageParameters> VRDisplay::stageParameters() const
91 {
92     auto displayInfo = m_display->getDisplayInfo();
93     return VRStageParameters::create(displayInfo.sittingToStandingTransform(), displayInfo.playAreaBounds());
94 }
95
96 const VREyeParameters& VRDisplay::getEyeParameters(VREye eye) const
97 {
98     return eye == VREye::Left ? *m_leftEyeParameters : *m_rightEyeParameters;
99 }
100
101 bool VRDisplay::getFrameData(VRFrameData& frameData) const
102 {
103     if (!m_capabilities->hasPosition() || !m_capabilities->hasOrientation())
104         return false;
105
106     // FIXME: ensure that this is only called inside WebVR's rAF.
107     frameData.update(m_display->getTrackingInfo(), getEyeParameters(VREye::Left), getEyeParameters(VREye::Right), m_depthNear, m_depthFar);
108     return true;
109 }
110
111 Ref<VRPose> VRDisplay::getPose() const
112 {
113     return VRPose::create(m_display->getTrackingInfo());
114 }
115
116 void VRDisplay::resetPose()
117 {
118 }
119
120 uint32_t VRDisplay::requestAnimationFrame(Ref<RequestAnimationFrameCallback>&& callback)
121 {
122     if (!m_scriptedAnimationController) {
123         auto* document = downcast<Document>(scriptExecutionContext());
124         m_scriptedAnimationController = ScriptedAnimationController::create(*document);
125     }
126
127     return m_scriptedAnimationController->registerCallback(WTFMove(callback));
128 }
129
130 void VRDisplay::cancelAnimationFrame(uint32_t id)
131 {
132     if (!m_scriptedAnimationController)
133         return;
134
135     m_scriptedAnimationController->cancelCallback(id);
136 }
137
138 void VRDisplay::requestPresent(const Vector<VRLayerInit>& layers, Ref<DeferredPromise>&& promise)
139 {
140     auto rejectRequestAndStopPresenting = [this, &promise] (ExceptionCode exceptionCode, ASCIILiteral message) {
141         promise->reject(Exception { exceptionCode, message });
142         if (m_presentingLayer)
143             stopPresenting();
144     };
145
146     if (!m_capabilities->canPresent()) {
147         rejectRequestAndStopPresenting(NotSupportedError, "VRDisplay cannot present"_s);
148         return;
149     }
150
151     if (!layers.size() || layers.size() > m_capabilities->maxLayers()) {
152         rejectRequestAndStopPresenting(InvalidStateError, layers.size() ? "Too many layers"_s : "Not enough layers"_s);
153         return;
154     }
155
156     if (!m_presentingLayer && !UserGestureIndicator::processingUserGesture()) {
157         rejectRequestAndStopPresenting(InvalidAccessError, "Must request presentation from a user gesture handler."_s);
158         return;
159     }
160
161     RELEASE_ASSERT(layers.size() == 1);
162     auto layer = layers[0];
163
164     if (!layer.source) {
165         rejectRequestAndStopPresenting(InvalidStateError, "Layer does not contain any source"_s);
166         return;
167     }
168
169     auto* canvasContext = layer.source->getContext("webgl");
170     if (!canvasContext || !canvasContext->isWebGL()) {
171         rejectRequestAndStopPresenting(NotSupportedError, "WebVR requires VRLayerInit with WebGL context."_s);
172         return;
173     }
174
175     if ((layer.leftBounds.size() && layer.leftBounds.size() != 4)
176         || (layer.rightBounds.size() && layer.rightBounds.size() != 4)) {
177         rejectRequestAndStopPresenting(InvalidStateError, "Layer bounds must be either 0 or 4"_s);
178         return;
179     }
180
181     m_presentingLayer = layer;
182     promise->resolve();
183 }
184
185 void VRDisplay::stopPresenting()
186 {
187     m_presentingLayer = WTF::nullopt;
188 }
189
190 void VRDisplay::exitPresent(Ref<DeferredPromise>&& promise)
191 {
192     if (!m_presentingLayer) {
193         promise->reject(Exception { InvalidStateError, "VRDisplay is not presenting"_s });
194         return;
195     }
196
197     stopPresenting();
198 }
199
200 Vector<VRLayerInit> VRDisplay::getLayers() const
201 {
202     Vector<VRLayerInit> layers;
203     if (m_presentingLayer)
204         layers.append(m_presentingLayer.value());
205     return layers;
206 }
207
208 void VRDisplay::submitFrame()
209 {
210 }
211
212 void VRDisplay::platformDisplayConnected()
213 {
214     document()->domWindow()->dispatchEvent(VRDisplayEvent::create(eventNames().vrdisplayconnectEvent, makeRefPtr(this), WTF::nullopt));
215 }
216
217 void VRDisplay::platformDisplayDisconnected()
218 {
219     document()->domWindow()->dispatchEvent(VRDisplayEvent::create(eventNames().vrdisplaydisconnectEvent, makeRefPtr(this), WTF::nullopt));
220 }
221
222 void VRDisplay::platformDisplayMounted()
223 {
224     document()->domWindow()->dispatchEvent(VRDisplayEvent::create(eventNames().vrdisplayactivateEvent, makeRefPtr(this), VRDisplayEventReason::Mounted));
225 }
226
227 void VRDisplay::platformDisplayUnmounted()
228 {
229     document()->domWindow()->dispatchEvent(VRDisplayEvent::create(eventNames().vrdisplaydeactivateEvent, makeRefPtr(this), VRDisplayEventReason::Unmounted));
230 }
231
232 bool VRDisplay::hasPendingActivity() const
233 {
234     return false;
235 }
236
237 const char* VRDisplay::activeDOMObjectName() const
238 {
239     return "VRDisplay";
240 }
241
242 // FIXME: This should never prevent entering the back/forward cache.
243 bool VRDisplay::shouldPreventEnteringBackForwardCache_DEPRECATED() const
244 {
245     return true;
246 }
247
248 void VRDisplay::stop()
249 {
250 }
251
252 } // namespace WebCore