blob: bd243fd5d943cc8d3c6b992f906f54501cc26067 [file] [log] [blame]
svillar@igalia.com29e449b2017-09-13 11:17:27 +00001/*
2 * Copyright (C) 2017 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
svillar@igalia.comebd98312018-04-13 15:19:00 +000029#include "CanvasRenderingContext.h"
svillar@igalia.com2bd2a9f2018-04-09 14:40:51 +000030#include "Chrome.h"
svillar@igalia.comebd98312018-04-13 15:19:00 +000031#include "DOMException.h"
svillar@igalia.com2bd2a9f2018-04-09 14:40:51 +000032#include "Page.h"
33#include "ScriptedAnimationController.h"
svillar@igalia.comebd98312018-04-13 15:19:00 +000034#include "UserGestureIndicator.h"
svillar@igalia.com29e449b2017-09-13 11:17:27 +000035#include "VRDisplayCapabilities.h"
36#include "VREyeParameters.h"
svillar@igalia.com2bd2a9f2018-04-09 14:40:51 +000037#include "VRFrameData.h"
svillar@igalia.com29e449b2017-09-13 11:17:27 +000038#include "VRLayerInit.h"
svillar@igalia.com81ed8402018-02-19 13:16:13 +000039#include "VRPlatformDisplay.h"
svillar@igalia.com29e449b2017-09-13 11:17:27 +000040#include "VRPose.h"
svillar@igalia.comd08c2352018-02-21 10:47:14 +000041#include "VRStageParameters.h"
svillar@igalia.com29e449b2017-09-13 11:17:27 +000042
43namespace WebCore {
44
svillar@igalia.com81ed8402018-02-19 13:16:13 +000045Ref<VRDisplay> VRDisplay::create(ScriptExecutionContext& context, WeakPtr<VRPlatformDisplay>&& platformDisplay)
svillar@igalia.com29e449b2017-09-13 11:17:27 +000046{
svillar@igalia.com81ed8402018-02-19 13:16:13 +000047 auto display = adoptRef(*new VRDisplay(context, WTFMove(platformDisplay)));
svillar@igalia.com29e449b2017-09-13 11:17:27 +000048 display->suspendIfNeeded();
49 return display;
50}
51
svillar@igalia.com81ed8402018-02-19 13:16:13 +000052VRDisplay::VRDisplay(ScriptExecutionContext& context, WeakPtr<VRPlatformDisplay>&& platformDisplay)
svillar@igalia.com29e449b2017-09-13 11:17:27 +000053 : ActiveDOMObject(&context)
svillar@igalia.com81ed8402018-02-19 13:16:13 +000054 , m_display(WTFMove(platformDisplay))
svillar@igalia.com29e449b2017-09-13 11:17:27 +000055{
svillar@igalia.comb52fff92018-02-20 15:52:01 +000056 auto displayInfo = m_display->getDisplayInfo();
svillar@igalia.com764247c2018-02-28 08:45:26 +000057 m_capabilities = VRDisplayCapabilities::create(displayInfo.capabilityFlags());
58 m_leftEyeParameters = VREyeParameters::create(displayInfo.eyeTranslation(VRPlatformDisplayInfo::EyeLeft), displayInfo.eyeFieldOfView(VRPlatformDisplayInfo::EyeLeft), displayInfo.renderSize());
59 m_rightEyeParameters = VREyeParameters::create(displayInfo.eyeTranslation(VRPlatformDisplayInfo::EyeRight), displayInfo.eyeFieldOfView(VRPlatformDisplayInfo::EyeRight), displayInfo.renderSize());
60 m_displayId = displayInfo.displayIdentifier();
61 m_displayName = displayInfo.displayName();
svillar@igalia.com29e449b2017-09-13 11:17:27 +000062}
63
64VRDisplay::~VRDisplay() = default;
65
66bool VRDisplay::isConnected() const
67{
svillar@igalia.com81ed8402018-02-19 13:16:13 +000068 if (!m_display)
69 return false;
70
svillar@igalia.com764247c2018-02-28 08:45:26 +000071 return m_display->getDisplayInfo().isConnected();
svillar@igalia.com29e449b2017-09-13 11:17:27 +000072}
73
svillar@igalia.com29e449b2017-09-13 11:17:27 +000074const VRDisplayCapabilities& VRDisplay::capabilities() const
75{
svillar@igalia.comb52fff92018-02-20 15:52:01 +000076 return *m_capabilities;
svillar@igalia.com29e449b2017-09-13 11:17:27 +000077}
78
svillar@igalia.comd08c2352018-02-21 10:47:14 +000079RefPtr<VRStageParameters> VRDisplay::stageParameters() const
svillar@igalia.com29e449b2017-09-13 11:17:27 +000080{
svillar@igalia.comd08c2352018-02-21 10:47:14 +000081 auto displayInfo = m_display->getDisplayInfo();
svillar@igalia.com764247c2018-02-28 08:45:26 +000082 return VRStageParameters::create(displayInfo.sittingToStandingTransform(), displayInfo.playAreaBounds());
svillar@igalia.com29e449b2017-09-13 11:17:27 +000083}
84
svillar@igalia.comb52fff92018-02-20 15:52:01 +000085const VREyeParameters& VRDisplay::getEyeParameters(VREye eye) const
svillar@igalia.com29e449b2017-09-13 11:17:27 +000086{
svillar@igalia.comb52fff92018-02-20 15:52:01 +000087 return eye == VREye::Left ? *m_leftEyeParameters : *m_rightEyeParameters;
svillar@igalia.com29e449b2017-09-13 11:17:27 +000088}
89
svillar@igalia.com2bd2a9f2018-04-09 14:40:51 +000090bool VRDisplay::getFrameData(VRFrameData& frameData) const
svillar@igalia.com29e449b2017-09-13 11:17:27 +000091{
svillar@igalia.com2bd2a9f2018-04-09 14:40:51 +000092 if (!m_capabilities->hasPosition() || !m_capabilities->hasOrientation())
93 return false;
94
95 // FIXME: ensure that this is only called inside WebVR's rAF.
96 frameData.update(m_display->getTrackingInfo(), getEyeParameters(VREye::Left), getEyeParameters(VREye::Right), m_depthNear, m_depthFar);
97 return true;
svillar@igalia.com29e449b2017-09-13 11:17:27 +000098}
99
100Ref<VRPose> VRDisplay::getPose() const
101{
svillar@igalia.com2bd2a9f2018-04-09 14:40:51 +0000102 return VRPose::create(m_display->getTrackingInfo());
svillar@igalia.com29e449b2017-09-13 11:17:27 +0000103}
104
105void VRDisplay::resetPose()
106{
107}
108
svillar@igalia.com2bd2a9f2018-04-09 14:40:51 +0000109uint32_t VRDisplay::requestAnimationFrame(Ref<RequestAnimationFrameCallback>&& callback)
svillar@igalia.com29e449b2017-09-13 11:17:27 +0000110{
svillar@igalia.com2bd2a9f2018-04-09 14:40:51 +0000111 if (!m_scriptedAnimationController) {
112 auto* document = downcast<Document>(scriptExecutionContext());
graouts@webkit.org32e70bb2018-06-25 09:54:34 +0000113 m_scriptedAnimationController = ScriptedAnimationController::create(*document);
svillar@igalia.com2bd2a9f2018-04-09 14:40:51 +0000114 }
115
116 return m_scriptedAnimationController->registerCallback(WTFMove(callback));
svillar@igalia.com29e449b2017-09-13 11:17:27 +0000117}
118
svillar@igalia.com2bd2a9f2018-04-09 14:40:51 +0000119void VRDisplay::cancelAnimationFrame(uint32_t id)
svillar@igalia.com29e449b2017-09-13 11:17:27 +0000120{
svillar@igalia.com2bd2a9f2018-04-09 14:40:51 +0000121 if (!m_scriptedAnimationController)
122 return;
123
124 m_scriptedAnimationController->cancelCallback(id);
svillar@igalia.com29e449b2017-09-13 11:17:27 +0000125}
126
svillar@igalia.comebd98312018-04-13 15:19:00 +0000127void VRDisplay::requestPresent(const Vector<VRLayerInit>& layers, Ref<DeferredPromise>&& promise)
svillar@igalia.com29e449b2017-09-13 11:17:27 +0000128{
svillar@igalia.comebd98312018-04-13 15:19:00 +0000129 auto rejectRequestAndStopPresenting = [this, &promise] (ExceptionCode exceptionCode, ASCIILiteral message) {
130 promise->reject(Exception { exceptionCode, message });
131 if (m_presentingLayer)
132 stopPresenting();
133 };
134
135 if (!m_capabilities->canPresent()) {
utatane.tea@gmail.com84077632018-06-23 08:39:34 +0000136 rejectRequestAndStopPresenting(NotSupportedError, "VRDisplay cannot present"_s);
svillar@igalia.comebd98312018-04-13 15:19:00 +0000137 return;
138 }
139
140 if (!layers.size() || layers.size() > m_capabilities->maxLayers()) {
utatane.tea@gmail.com84077632018-06-23 08:39:34 +0000141 rejectRequestAndStopPresenting(InvalidStateError, layers.size() ? "Too many layers"_s : "Not enough layers"_s);
svillar@igalia.comebd98312018-04-13 15:19:00 +0000142 return;
143 }
144
145 if (!m_presentingLayer && !UserGestureIndicator::processingUserGesture()) {
utatane.tea@gmail.com84077632018-06-23 08:39:34 +0000146 rejectRequestAndStopPresenting(InvalidAccessError, "Must request presentation from a user gesture handler."_s);
svillar@igalia.comebd98312018-04-13 15:19:00 +0000147 return;
148 }
149
150 RELEASE_ASSERT(layers.size() == 1);
151 auto layer = layers[0];
152
153 if (!layer.source) {
utatane.tea@gmail.com84077632018-06-23 08:39:34 +0000154 rejectRequestAndStopPresenting(InvalidStateError, "Layer does not contain any source"_s);
svillar@igalia.comebd98312018-04-13 15:19:00 +0000155 return;
156 }
157
158 auto* canvasContext = layer.source->getContext("webgl");
159 if (!canvasContext || !canvasContext->isWebGL()) {
utatane.tea@gmail.com84077632018-06-23 08:39:34 +0000160 rejectRequestAndStopPresenting(NotSupportedError, "WebVR requires VRLayerInit with WebGL context."_s);
svillar@igalia.comebd98312018-04-13 15:19:00 +0000161 return;
162 }
163
164 if ((layer.leftBounds.size() && layer.leftBounds.size() != 4)
165 || (layer.rightBounds.size() && layer.rightBounds.size() != 4)) {
utatane.tea@gmail.com84077632018-06-23 08:39:34 +0000166 rejectRequestAndStopPresenting(InvalidStateError, "Layer bounds must be either 0 or 4"_s);
svillar@igalia.comebd98312018-04-13 15:19:00 +0000167 return;
168 }
169
170 m_presentingLayer = layer;
171 promise->resolve();
svillar@igalia.com29e449b2017-09-13 11:17:27 +0000172}
173
svillar@igalia.comebd98312018-04-13 15:19:00 +0000174void VRDisplay::stopPresenting()
svillar@igalia.com29e449b2017-09-13 11:17:27 +0000175{
svillar@igalia.comebd98312018-04-13 15:19:00 +0000176 m_presentingLayer = std::nullopt;
svillar@igalia.com29e449b2017-09-13 11:17:27 +0000177}
178
svillar@igalia.comebd98312018-04-13 15:19:00 +0000179void VRDisplay::exitPresent(Ref<DeferredPromise>&& promise)
svillar@igalia.com29e449b2017-09-13 11:17:27 +0000180{
svillar@igalia.comebd98312018-04-13 15:19:00 +0000181 if (!m_presentingLayer) {
utatane.tea@gmail.com84077632018-06-23 08:39:34 +0000182 promise->reject(Exception { InvalidStateError, "VRDisplay is not presenting"_s });
svillar@igalia.comebd98312018-04-13 15:19:00 +0000183 return;
184 }
185
186 stopPresenting();
187}
188
189Vector<VRLayerInit> VRDisplay::getLayers() const
190{
191 Vector<VRLayerInit> layers;
192 if (m_presentingLayer)
193 layers.append(m_presentingLayer.value());
194 return layers;
svillar@igalia.com29e449b2017-09-13 11:17:27 +0000195}
196
197void VRDisplay::submitFrame()
198{
199}
200
201bool VRDisplay::hasPendingActivity() const
202{
203 return false;
204}
205
206const char* VRDisplay::activeDOMObjectName() const
207{
208 return "VRDisplay";
209}
210
211bool VRDisplay::canSuspendForDocumentSuspension() const
212{
213 return false;
214}
215
216void VRDisplay::stop()
217{
218}
219
220} // namespace WebCore