| Differences between
and this patch
- a/Source/WebCore/ChangeLog +62 lines
Lines 1-3 a/Source/WebCore/ChangeLog_sec1
1
2020-05-14  Sergio Villar Senin  <svillar@igalia.com>
2
3
        [WebXR] Implement requestSession()
4
        https://bugs.webkit.org/show_bug.cgi?id=211888
5
6
        Reviewed by NOBODY (OOPS!).
7
8
        This patch adds a preliminar implementation of the requestSession()
9
        API used to get a WebXRSession from the UA. It includes a fairly good
10
        amount of checks to verify that the request can be satisfied given the
11
        device's enabled features per session modes. The specs also describe how
12
        to request persmission for some actions using the Permissions API which
13
        WebKit does not currently implement. That should be done in a follow up
14
        patch perhaps using a similar approach to other APIs as Geolocation for
15
        example.
16
17
        In order to get some of the requestSession() tests passing the session
18
        finalization (shutdown) had to be implemented too.
19
20
        Several tests where unskipped for WPE port as they're now passing.
21
22
        * Modules/webxr/WebXRRenderState.cpp:
23
        (WebCore::WebXRRenderState::create): Pass XRSessionMode as argument
24
        instead of a WebXRSession.
25
        * Modules/webxr/WebXRRenderState.h: Ditto.
26
        * Modules/webxr/WebXRSession.cpp:
27
        (WebCore::WebXRSession::create): Added.
28
        (WebCore::WebXRSession::WebXRSession): Added.
29
        (WebCore::WebXRSession::renderState const):
30
        (WebCore::WebXRSession::inputSources const):
31
        (WebCore::WebXRSession::shutdown): Shutdown process called on session end.
32
        (WebCore::WebXRSession::end): Implemented session ending.
33
        * Modules/webxr/WebXRSession.h: Added create() and private constructor. Fixed some naming.
34
        * Modules/webxr/WebXRSystem.cpp:
35
        (WebCore::WebXRSystem::DummyInlineDevice::DummyInlineDevice): Contructor for the
36
        dummy inline device.
37
        (WebCore::WebXRSystem::ensureImmersiveXRDeviceIsSelected): Use a counter instead of a boolean
38
        to track testing devices as there might be more than 1.
39
        (WebCore::WebXRSystem::obtainCurrentDevice): Implemented from specs text.
40
        (WebCore::WebXRSystem::immersiveSessionRequestIsAllowedForGlobalObject const): Ditto.
41
        (WebCore::WebXRSystem::inlineSessionRequestIsAllowedForGlobalObject const): Ditto.
42
        (WebCore::WebXRSystem::resolveRequestedFeatures const): Ditto.
43
        (WebCore::WebXRSystem::isXRPermissionGranted const): Ditto.
44
        (WebCore::WebXRSystem::requestSession): Ditto.
45
        (WebCore::WebXRSystem::registerSimulatedXRDeviceForTesting): Use a counter instead of a bool.
46
        (WebCore::WebXRSystem::unregisterSimulatedXRDeviceForTesting): Ditto.
47
        (WebCore::WebXRSystem::sessionEnded): Added, used by sessions to notify the XRSystem.
48
        * Modules/webxr/WebXRSystem.h:
49
        * Modules/webxr/WebXRSystem.idl: Call requestSession with Document.
50
        * dom/TaskSource.h: Added a WebXR task source.
51
        * platform/xr/PlatformXR.h: Specs state that devices have a list of enabled features per session
52
        mode so store them in a hashmap instead of in a Vector.
53
        (PlatformXR::Device::supports const): Use the new Hashmap of session modes.
54
        (PlatformXR::Device::setEnabledFeatures): Ditto.
55
        (PlatformXR::Device::enabledFeatures const): Ditto.
56
        (PlatformXR::Device::setSupportedModes): Deleted.
57
        * platform/xr/openxr/PlatformXR.cpp:
58
        (PlatformXR::Instance::Impl::collectSupportedSessionModes): Return session modes if any.
59
        (PlatformXR::Instance::enumerateImmersiveXRDevices): Fill in features per session mode.
60
        * testing/WebXRTest.cpp:
61
        (WebCore::WebXRTest::simulateDeviceConnection): Fill in features per session mode.
62
1
2020-05-14  Sergio Villar Senin  <svillar@igalia.com>
63
2020-05-14  Sergio Villar Senin  <svillar@igalia.com>
2
64
3
        Unreviewed build fix.
65
        Unreviewed build fix.
- a/Source/WebCore/Modules/webxr/WebXRInputSourceArray.h +3 lines
Lines 39-44 class WebXRInputSourceArray : public RefCounted<WebXRInputSourceArray> { a/Source/WebCore/Modules/webxr/WebXRInputSourceArray.h_sec1
39
public:
39
public:
40
    unsigned length() const;
40
    unsigned length() const;
41
    WebXRInputSource* item(unsigned) const;
41
    WebXRInputSource* item(unsigned) const;
42
43
private:
44
    WebXRInputSourceArray();
42
};
45
};
43
46
44
} // namespace WebCore
47
} // namespace WebCore
- a/Source/WebCore/Modules/webxr/WebXRRenderState.cpp -19 / +4 lines
Lines 37-62 namespace WebCore { a/Source/WebCore/Modules/webxr/WebXRRenderState.cpp_sec1
37
37
38
WTF_MAKE_ISO_ALLOCATED_IMPL(WebXRRenderState);
38
WTF_MAKE_ISO_ALLOCATED_IMPL(WebXRRenderState);
39
39
40
Ref<WebXRRenderState> WebXRRenderState::create(const WebXRSession& session)
40
Ref<WebXRRenderState> WebXRRenderState::create(XRSessionMode mode)
41
{
41
{
42
    // When an XRRenderState object is created for an XRSession session, the user agent MUST initialize the render state by running the following steps:
42
    // https://immersive-web.github.io/webxr/#initialize-the-render-state
43
    //   1. Let state be the newly created XRRenderState object.
43
    // depthNear, depthFar and baseLayer are initialized in the class definition
44
44
    return adoptRef(*new WebXRRenderState(mode == XRSessionMode::Inline ? makeOptional(piOverTwoDouble) : WTF::nullopt));
45
    //   2. Initialize state’s depthNear to 0.1.
46
    //   3. Initialize state’s depthFar to 1000.0.
47
    // (Default-initialized in the XRRenderState class definition.)
48
49
    //   4. If session is an immersive session, initialize state’s inlineVerticalFieldOfView to null.
50
    //   5. Else initialize state’s inlineVerticalFieldOfView to PI * 0.5.
51
    // FIXME: "immersive session" support
52
    UNUSED_PARAM(session);
53
    Optional<double> inlineVerticalFieldOfView { piOverTwoDouble };
54
55
    //   6. Initialize state’s baseLayer to null.
56
    //   7. Initialize state’s outputContext to null.
57
    // (Initialized to null by default.)
58
59
    return adoptRef(*new WebXRRenderState(WTFMove(inlineVerticalFieldOfView)));
60
}
45
}
61
46
62
WebXRRenderState::WebXRRenderState(Optional<double>&& inlineVerticalFieldOfView)
47
WebXRRenderState::WebXRRenderState(Optional<double>&& inlineVerticalFieldOfView)
- a/Source/WebCore/Modules/webxr/WebXRRenderState.h -7 / +8 lines
Lines 27-32 a/Source/WebCore/Modules/webxr/WebXRRenderState.h_sec1
27
27
28
#if ENABLE(WEBXR)
28
#if ENABLE(WEBXR)
29
29
30
#include "XRSessionMode.h"
30
#include <wtf/IsoMalloc.h>
31
#include <wtf/IsoMalloc.h>
31
#include <wtf/Optional.h>
32
#include <wtf/Optional.h>
32
#include <wtf/Ref.h>
33
#include <wtf/Ref.h>
Lines 37-48 namespace WebCore { a/Source/WebCore/Modules/webxr/WebXRRenderState.h_sec2
37
38
38
class WebXRWebGLLayer;
39
class WebXRWebGLLayer;
39
struct XRRenderStateInit;
40
struct XRRenderStateInit;
40
class WebXRSession;
41
41
42
class WebXRRenderState : public RefCounted<WebXRRenderState> {
42
class WebXRRenderState : public RefCounted<WebXRRenderState> {
43
    WTF_MAKE_ISO_ALLOCATED(WebXRRenderState);
43
    WTF_MAKE_ISO_ALLOCATED(WebXRRenderState);
44
public:
44
public:
45
    static Ref<WebXRRenderState> create(const WebXRSession&);
45
    static Ref<WebXRRenderState> create(XRSessionMode);
46
    ~WebXRRenderState();
46
    ~WebXRRenderState();
47
47
48
    double depthNear() const;
48
    double depthNear() const;
Lines 51-64 public: a/Source/WebCore/Modules/webxr/WebXRRenderState.h_sec3
51
    RefPtr<WebXRWebGLLayer> baseLayer() const;
51
    RefPtr<WebXRWebGLLayer> baseLayer() const;
52
52
53
private:
53
private:
54
    WebXRRenderState(Optional<double>&&);
54
    explicit WebXRRenderState(Optional<double>&& fieldOfView);
55
    WebXRRenderState(const XRRenderStateInit&);
55
    explicit WebXRRenderState(const XRRenderStateInit&);
56
56
57
    // https://immersive-web.github.io/webxr/#initialize-the-render-state
57
    struct {
58
    struct {
58
        double near { 0.1 };
59
        double near { 0.1 }; // in meters
59
        double far { 1000 };
60
        double far { 1000 }; // in meters
60
    } m_depth;
61
    } m_depth;
61
    Optional<double> m_inlineVerticalFieldOfView;
62
    Optional<double> m_inlineVerticalFieldOfView; // in radians
62
    RefPtr<WebXRWebGLLayer> m_baseLayer;
63
    RefPtr<WebXRWebGLLayer> m_baseLayer;
63
};
64
};
64
65
- a/Source/WebCore/Modules/webxr/WebXRSession.cpp -2 / +54 lines
Lines 28-39 a/Source/WebCore/Modules/webxr/WebXRSession.cpp_sec1
28
28
29
#if ENABLE(WEBXR)
29
#if ENABLE(WEBXR)
30
30
31
#include "WebXRSystem.h"
31
#include <wtf/IsoMallocInlines.h>
32
#include <wtf/IsoMallocInlines.h>
32
33
33
namespace WebCore {
34
namespace WebCore {
34
35
35
WTF_MAKE_ISO_ALLOCATED_IMPL(WebXRSession);
36
WTF_MAKE_ISO_ALLOCATED_IMPL(WebXRSession);
36
37
38
Ref<WebXRSession> WebXRSession::create(Document& document, Ref<WebXRSystem>&& system, XRSessionMode mode, WeakPtr<PlatformXR::Device>&& device)
39
{
40
    return adoptRef(*new WebXRSession(document, WTFMove(system), mode, WTFMove(device)));
41
}
42
43
WebXRSession::WebXRSession(Document& document, Ref<WebXRSystem>&& system, XRSessionMode mode, WeakPtr<PlatformXR::Device>&& device)
44
    : ActiveDOMObject(&document)
45
    , m_xrSystem(WTFMove(system))
46
    , m_mode(mode)
47
    , m_device(WTFMove(device))
48
    , m_activeRenderState(WebXRRenderState::create(mode))
49
{
50
    // TODO: If no other features of the user agent have done so already,
51
    // perform the necessary platform-specific steps to initialize the device’s
52
    // tracking and rendering capabilities, including showing any necessary
53
    // instructions to the user.
54
}
55
37
WebXRSession::~WebXRSession() = default;
56
WebXRSession::~WebXRSession() = default;
38
57
39
XREnvironmentBlendMode WebXRSession::environmentBlendMode() const
58
XREnvironmentBlendMode WebXRSession::environmentBlendMode() const
Lines 48-54 XRVisibilityState WebXRSession::visibilityState() const a/Source/WebCore/Modules/webxr/WebXRSession.cpp_sec2
48
67
49
const WebXRRenderState& WebXRSession::renderState() const
68
const WebXRRenderState& WebXRSession::renderState() const
50
{
69
{
51
    return *m_renderState;
70
    return *m_activeRenderState;
52
}
71
}
53
72
54
const WebXRInputSourceArray& WebXRSession::inputSources() const
73
const WebXRInputSourceArray& WebXRSession::inputSources() const
Lines 73-80 void WebXRSession::cancelAnimationFrame(int) a/Source/WebCore/Modules/webxr/WebXRSession.cpp_sec3
73
{
92
{
74
}
93
}
75
94
76
void WebXRSession::end(EndPromise&&)
95
// https://immersive-web.github.io/webxr/#shut-down-the-session
96
void WebXRSession::shutdown()
97
{
98
    // 1. Let session be the target XRSession object.
99
    // 2. Set session's ended value to true.
100
    m_ended = true;
101
102
    // 3. If the active immersive session is equal to session, set the active immersive session to null.
103
    // 4. Remove session from the list of inline sessions.
104
    m_xrSystem->sessionEnded(this);
105
106
    // TODO: complete the implementation
107
    // 5. Reject any outstanding promises returned by session with an InvalidStateError, except for any promises returned by end().
108
    // 6. If no other features of the user agent are actively using them, perform the necessary platform-specific steps to shut down the device's tracking and rendering capabilities. This MUST include:
109
    //  6.1. Releasing exclusive access to the XR device if session is an immersive session.
110
    //  6.2. Deallocating any graphics resources acquired by session for presentation to the XR device.
111
    //  6.3. Putting the XR device in a state such that a different source may be able to initiate a session with the same device if session is an immersive session.
112
    // 7. Queue a task that fires an XRSessionEvent named end on session.
113
}
114
115
// https://immersive-web.github.io/webxr/#dom-xrsession-end
116
void WebXRSession::end(EndPromise&& promise)
77
{
117
{
118
    // 1. Let promise be a new Promise.
119
    // 2. Shut down the target XRSession object.
120
    shutdown();
121
122
    // 3. Queue a task to perform the following steps:
123
    queueTaskKeepingObjectAlive(*this, TaskSource::WebXR, [promise = WTFMove(promise)] () mutable {
124
        // 3.1 Wait until any platform-specific steps related to shutting down the session have completed.
125
        // 3.2 Resolve promise.
126
        promise.resolve();
127
    });
128
129
    // 4. Return promise.
78
}
130
}
79
131
80
const char* WebXRSession::activeDOMObjectName() const
132
const char* WebXRSession::activeDOMObjectName() const
- a/Source/WebCore/Modules/webxr/WebXRSession.h -1 / +13 lines
Lines 35-40 a/Source/WebCore/Modules/webxr/WebXRSession.h_sec1
35
#include "WebXRSpace.h"
35
#include "WebXRSpace.h"
36
#include "XREnvironmentBlendMode.h"
36
#include "XREnvironmentBlendMode.h"
37
#include "XRReferenceSpaceType.h"
37
#include "XRReferenceSpaceType.h"
38
#include "XRSessionMode.h"
38
#include "XRVisibilityState.h"
39
#include "XRVisibilityState.h"
39
#include <wtf/Ref.h>
40
#include <wtf/Ref.h>
40
#include <wtf/RefCounted.h>
41
#include <wtf/RefCounted.h>
Lines 45-50 namespace WebCore { a/Source/WebCore/Modules/webxr/WebXRSession.h_sec2
45
46
46
class XRFrameRequestCallback;
47
class XRFrameRequestCallback;
47
class WebXRReferenceSpace;
48
class WebXRReferenceSpace;
49
class WebXRSystem;
48
struct XRRenderStateInit;
50
struct XRRenderStateInit;
49
51
50
class WebXRSession final : public RefCounted<WebXRSession>, public EventTargetWithInlineData, public ActiveDOMObject {
52
class WebXRSession final : public RefCounted<WebXRSession>, public EventTargetWithInlineData, public ActiveDOMObject {
Lines 53-58 public: a/Source/WebCore/Modules/webxr/WebXRSession.h_sec3
53
    using RequestReferenceSpacePromise = DOMPromiseDeferred<IDLInterface<WebXRReferenceSpace>>;
55
    using RequestReferenceSpacePromise = DOMPromiseDeferred<IDLInterface<WebXRReferenceSpace>>;
54
    using EndPromise = DOMPromiseDeferred<void>;
56
    using EndPromise = DOMPromiseDeferred<void>;
55
57
58
    static Ref<WebXRSession> create(Document&, Ref<WebXRSystem>&&, XRSessionMode, WeakPtr<PlatformXR::Device>&&);
56
    virtual ~WebXRSession();
59
    virtual ~WebXRSession();
57
60
58
    using RefCounted<WebXRSession>::ref;
61
    using RefCounted<WebXRSession>::ref;
Lines 74-79 public: a/Source/WebCore/Modules/webxr/WebXRSession.h_sec4
74
    bool ended() const { return m_ended; }
77
    bool ended() const { return m_ended; }
75
78
76
private:
79
private:
80
    WebXRSession(Document&, Ref<WebXRSystem>&&, XRSessionMode, WeakPtr<PlatformXR::Device>&&);
81
77
    // EventTarget
82
    // EventTarget
78
    EventTargetInterface eventTargetInterface() const override { return WebXRSessionEventTargetInterfaceType; }
83
    EventTargetInterface eventTargetInterface() const override { return WebXRSessionEventTargetInterfaceType; }
79
    ScriptExecutionContext* scriptExecutionContext() const override { return ActiveDOMObject::scriptExecutionContext(); }
84
    ScriptExecutionContext* scriptExecutionContext() const override { return ActiveDOMObject::scriptExecutionContext(); }
Lines 84-94 private: a/Source/WebCore/Modules/webxr/WebXRSession.h_sec5
84
    const char* activeDOMObjectName() const override;
89
    const char* activeDOMObjectName() const override;
85
    void stop() override;
90
    void stop() override;
86
91
92
    void shutdown();
93
87
    XREnvironmentBlendMode m_environmentBlendMode;
94
    XREnvironmentBlendMode m_environmentBlendMode;
88
    XRVisibilityState m_visibilityState;
95
    XRVisibilityState m_visibilityState;
89
    RefPtr<WebXRRenderState> m_renderState;
90
    RefPtr<WebXRInputSourceArray> m_inputSources;
96
    RefPtr<WebXRInputSourceArray> m_inputSources;
91
    bool m_ended { false };
97
    bool m_ended { false };
98
99
    Ref<WebXRSystem> m_xrSystem;
100
    XRSessionMode m_mode;
101
    WeakPtr<PlatformXR::Device> m_device;
102
    RefPtr<WebXRRenderState> m_activeRenderState;
103
    RefPtr<WebXRRenderState> m_pendingRenderState;
92
};
104
};
93
105
94
} // namespace WebCore
106
} // namespace WebCore
- a/Source/WebCore/Modules/webxr/WebXRSystem.cpp -23 / +304 lines
Lines 28-44 a/Source/WebCore/Modules/webxr/WebXRSystem.cpp_sec1
28
28
29
#if ENABLE(WEBXR)
29
#if ENABLE(WEBXR)
30
30
31
#include "DOMWindow.h"
31
#include "Document.h"
32
#include "Document.h"
32
#include "FeaturePolicy.h"
33
#include "FeaturePolicy.h"
34
#include "IDLTypes.h"
35
#include "JSWebXRSession.h"
36
#include "JSXRReferenceSpaceType.h"
33
#include "PlatformXR.h"
37
#include "PlatformXR.h"
34
#include "RuntimeEnabledFeatures.h"
38
#include "RuntimeEnabledFeatures.h"
39
#include "SecurityOrigin.h"
40
#include "UserGestureIndicator.h"
35
#include "WebXRSession.h"
41
#include "WebXRSession.h"
42
#include "XRReferenceSpaceType.h"
43
#include "XRSessionInit.h"
44
#include <JavaScriptCore/JSGlobalObject.h>
36
#include <wtf/IsoMallocInlines.h>
45
#include <wtf/IsoMallocInlines.h>
46
#include <wtf/Scope.h>
37
47
38
namespace WebCore {
48
namespace WebCore {
39
49
40
WTF_MAKE_ISO_ALLOCATED_IMPL(WebXRSystem);
50
WTF_MAKE_ISO_ALLOCATED_IMPL(WebXRSystem);
41
51
52
WebXRSystem::DummyInlineDevice::DummyInlineDevice()
53
{
54
    setEnabledFeatures(XRSessionMode::Inline, { XRReferenceSpaceType::Viewer });
55
}
56
42
Ref<WebXRSystem> WebXRSystem::create(ScriptExecutionContext& scriptExecutionContext)
57
Ref<WebXRSystem> WebXRSystem::create(ScriptExecutionContext& scriptExecutionContext)
43
{
58
{
44
    return adoptRef(*new WebXRSystem(scriptExecutionContext));
59
    return adoptRef(*new WebXRSystem(scriptExecutionContext));
Lines 56-63 WebXRSystem::~WebXRSystem() = default; a/Source/WebCore/Modules/webxr/WebXRSystem.cpp_sec2
56
void WebXRSystem::ensureImmersiveXRDeviceIsSelected()
71
void WebXRSystem::ensureImmersiveXRDeviceIsSelected()
57
{
72
{
58
    // Don't ask platform code for XR devices, we're using simulated ones.
73
    // Don't ask platform code for XR devices, we're using simulated ones.
59
    // TODO: should be have a MockPlatformXR implementation instead ?
74
    if (UNLIKELY(m_testingDevices))
60
    if (UNLIKELY(m_testingMode))
61
        return;
75
        return;
62
76
63
    if (m_activeImmersiveDevice)
77
    if (m_activeImmersiveDevice)
Lines 96-101 void WebXRSystem::ensureImmersiveXRDeviceIsSelected() a/Source/WebCore/Modules/webxr/WebXRSystem.cpp_sec3
96
    // TODO: 9. Queue a task to fire an event named devicechange on the context object.
110
    // TODO: 9. Queue a task to fire an event named devicechange on the context object.
97
}
111
}
98
112
113
114
PlatformXR::Device* WebXRSystem::obtainCurrentDevice(XRSessionMode mode, const JSFeaturesArray& requiredFeatures, const JSFeaturesArray& optionalFeatures)
115
{
116
    if (mode == XRSessionMode::ImmersiveAr || mode == XRSessionMode::ImmersiveVr) {
117
        ensureImmersiveXRDeviceIsSelected();
118
        return m_activeImmersiveDevice.get();
119
    }
120
    if (!requiredFeatures.isEmpty() || !optionalFeatures.isEmpty())
121
        return m_inlineXRDevice.get();
122
123
    return &m_defaultInlineDevice;
124
}
125
126
99
// https://immersive-web.github.io/webxr/#dom-xrsystem-issessionsupported
127
// https://immersive-web.github.io/webxr/#dom-xrsystem-issessionsupported
100
void WebXRSystem::isSessionSupported(XRSessionMode mode, IsSessionSupportedPromise&& promise)
128
void WebXRSystem::isSessionSupported(XRSessionMode mode, IsSessionSupportedPromise&& promise)
101
{
129
{
Lines 106-112 void WebXRSystem::isSessionSupported(XRSessionMode mode, IsSessionSupportedPromi a/Source/WebCore/Modules/webxr/WebXRSystem.cpp_sec4
106
        return;
134
        return;
107
    }
135
    }
108
136
109
    // 3. If the requesting document’s origin is not allowed to use the "xr-spatial-tracking" feature policy,
137
    // 3. If the requesting document's origin is not allowed to use the "xr-spatial-tracking" feature policy,
110
    //    reject promise with a "SecurityError" DOMException and return it.
138
    //    reject promise with a "SecurityError" DOMException and return it.
111
    auto document = downcast<Document>(scriptExecutionContext());
139
    auto document = downcast<Document>(scriptExecutionContext());
112
    if (!isFeaturePolicyAllowedByDocumentAndAllOwners(FeaturePolicy::Type::XRSpatialTracking, *document, LogFeaturePolicyFailure::Yes)) {
140
    if (!isFeaturePolicyAllowedByDocumentAndAllOwners(FeaturePolicy::Type::XRSpatialTracking, *document, LogFeaturePolicyFailure::Yes)) {
Lines 136-161 void WebXRSystem::isSessionSupported(XRSessionMode mode, IsSessionSupportedPromi a/Source/WebCore/Modules/webxr/WebXRSystem.cpp_sec5
136
    });
164
    });
137
}
165
}
138
166
139
void WebXRSystem::requestSession(XRSessionMode, const XRSessionInit&, RequestSessionPromise&&)
167
// https://immersive-web.github.io/webxr/#immersive-session-request-is-allowed
168
bool WebXRSystem::immersiveSessionRequestIsAllowedForGlobalObject(DOMWindow& globalObject, Document& document) const
169
{
170
    // 1. If the request was not made while the global object has transient
171
    //    activation or when launching a web application, return false
172
    // TODO: add a check for "not launching a web application".
173
    if (!globalObject.hasTransientActivation())
174
        return false;
175
176
    // 2. If the requesting document is not considered trustworthy, return false.
177
    // https://immersive-web.github.io/webxr/#trustworthy.
178
    if (&document != globalObject.document())
179
        return false;
180
181
    // https://immersive-web.github.io/webxr/#active-and-focused
182
    if (!document.hasFocus() || !document.securityOrigin().isSameOriginAs(globalObject.document()->securityOrigin()))
183
        return false;
184
185
    // 3. If user intent to begin an immersive session is not well understood,
186
    //    either via explicit consent or implicit consent, return false
187
    if (!UserGestureIndicator::processingUserGesture())
188
        return false;
189
190
    return true;
191
}
192
193
// https://immersive-web.github.io/webxr/#inline-session-request-is-allowed
194
bool WebXRSystem::inlineSessionRequestIsAllowedForGlobalObject(DOMWindow& globalObject, Document& document, const XRSessionInit& init) const
195
{
196
    // 1. If the session request contained any required features or optional features and the request was not made
197
    //    while the global object has transient activation or when launching a web application, return false.
198
    bool sessionRequestContainedAnyFeature = !init.optionalFeatures.isEmpty() || !init.requiredFeatures.isEmpty();
199
    if (sessionRequestContainedAnyFeature && !globalObject.hasTransientActivation() /* TODO: || !launching a web app */)
200
        return false;
201
202
    // 2. If the requesting document is not responsible, return false.
203
    if (&document != globalObject.document())
204
        return false;
205
206
    return true;
207
}
208
209
210
struct WebXRSystem::ResolvedRequestedFeatures {
211
    FeaturesArray granted;
212
    FeaturesArray consentRequired;
213
    FeaturesArray consentOptional;
214
};
215
216
#define RETURN_FALSE_OR_CONTINUE(mustReturn) { \
217
    if (mustReturn) {\
218
        return false; \
219
    } \
220
    continue; \
221
}
222
223
// https://immersive-web.github.io/webxr/#resolve-the-requested-features
224
Optional<WebXRSystem::ResolvedRequestedFeatures> WebXRSystem::resolveRequestedFeatures(XRSessionMode mode, const XRSessionInit& init, PlatformXR::Device* device, JSC::JSGlobalObject& globalObject) const
140
{
225
{
141
    PlatformXR::Instance::singleton();
226
    // 1. Let consentRequired be an empty list of DOMString.
227
    // 2. Let consentOptional be an empty list of DOMString.
228
    ResolvedRequestedFeatures resolvedFeatures;
229
230
    // 3. Let device be the result of obtaining the current device for mode, requiredFeatures, and optionalFeatures.
231
    // 4. Let granted be a list of DOMString initialized to device's list of enabled features for mode.
232
    if (device)
233
        resolvedFeatures.granted = device->enabledFeatures(mode);
234
235
    // 5. If device is null or device's list of supported modes does not contain mode, run the following steps:
236
    //  5.1 Return the tuple (consentRequired, consentOptional, granted)
237
    if (!device || !device->supports(mode))
238
        return resolvedFeatures;
239
240
    // 6. Add every feature descriptor in the default features table associated
241
    //    with mode to the indicated feature list if it is not already present.
242
    // https://immersive-web.github.io/webxr/#default-features
243
    auto requiredFeaturesWithDefaultFeatures = init.requiredFeatures;
244
    requiredFeaturesWithDefaultFeatures.append(convertEnumerationToJS(globalObject, XRReferenceSpaceType::Viewer));
245
    if (mode == XRSessionMode::ImmersiveAr || mode == XRSessionMode::ImmersiveVr)
246
        requiredFeaturesWithDefaultFeatures.append(convertEnumerationToJS(globalObject, XRReferenceSpaceType::Local));
247
248
    // 7. For each feature in requiredFeatures|optionalFeatures perform the following steps:
249
    // 8. For each feature in optionalFeatures perform the following steps:
250
    // We're merging both loops in a single lambda. The only difference is that a failure on any required features
251
    // implies cancelling the whole process while failures in optional features are just skipped.
252
    enum class ParsingMode { Strict, Loose };
253
    auto parseFeatures = [&device, &globalObject, mode, &resolvedFeatures] (const JSFeaturesArray& sessionFeatures, ParsingMode parsingMode) -> bool {
254
        bool returnOnFailure = parsingMode == ParsingMode::Strict;
255
        for (const auto& sessionFeature : sessionFeatures) {
256
            // 1. If the feature is null, continue to the next entry.
257
            if (sessionFeature.isNull())
258
                continue;
259
260
            // 2. If feature is not a valid feature descriptor, perform the following steps
261
            //   2.1. Let s be the result of calling ? ToString(feature).
262
            //   2.2. If s is not a valid feature descriptor or is undefined, (return null|continue to next entry).
263
            //   2.3. Set feature to s.
264
            auto feature = parseEnumeration<XRReferenceSpaceType>(globalObject, sessionFeature);
265
            if (!feature)
266
                RETURN_FALSE_OR_CONTINUE(returnOnFailure);
267
268
            // 3. If feature is already in granted, continue to the next entry.
269
            if (resolvedFeatures.granted.contains(feature.value()))
270
                continue;
271
272
            // 4. If the requesting document's origin is not allowed to use any feature policy required by feature
273
            //    as indicated by the feature requirements table, (return null|continue to next entry).
274
275
            // 5. If session's XR device is not capable of supporting the functionality described by feature or the
276
            //    user agent has otherwise determined to reject the feature, (return null|continue to next entry).
277
            if (!device->enabledFeatures(mode).contains(feature.value()))
278
                RETURN_FALSE_OR_CONTINUE(returnOnFailure);
279
280
            // 6. If the functionality described by feature requires explicit consent, append it to (consentRequired|consentOptional).
281
            // 7. Else append feature to granted.
282
            resolvedFeatures.granted.append(feature.value());
283
        }
284
        return true;
285
    };
286
287
    if (!parseFeatures(requiredFeaturesWithDefaultFeatures, ParsingMode::Strict))
288
        return WTF::nullopt;
142
289
143
    // When the requestSession(mode) method is invoked, the user agent MUST return a new Promise promise and run the following steps in parallel:
290
    parseFeatures(init.optionalFeatures, ParsingMode::Loose);
144
    //   1. Let immersive be true if mode is "immersive-vr" or "immersive-ar", and false otherwise.
291
    return resolvedFeatures;
145
    //   2. If immersive is true:
292
}
146
    //     1. If pending immersive session is true or active immersive session is not null, reject promise with an "InvalidStateError" DOMException and abort these steps.
293
147
    //     2. Else set pending immersive session to be true.
294
// https://immersive-web.github.io/webxr/#request-the-xr-permission
148
    //   3. Ensure an XR device is selected.
295
bool WebXRSystem::isXRPermissionGranted(XRSessionMode mode, const XRSessionInit& init, PlatformXR::Device* device, JSC::JSGlobalObject& globalObject) const
149
    //   4. If the XR device is null, reject promise with null.
296
{
150
    //   5. Else if the XR device's list of supported modes does not contain mode, reject promise with a "NotSupportedError" DOMException.
297
    // 1. Set status's granted to an empty FrozenArray.
151
    //   6. Else If immersive is true and the algorithm is not triggered by user activation, reject promise with a "SecurityError" DOMException and abort these steps.
298
    // 2. Let requiredFeatures be descriptor's requiredFeatures.
152
    //   7. If promise was rejected and immersive is true, set pending immersive session to false.
299
    // 3. Let optionalFeatures be descriptor's optionalFeatures.
153
    //   8. If promise was rejected, abort these steps.
300
    // 4. Let device be the result of obtaining the current device for mode, requiredFeatures, and optionalFeatures.
154
    //   9. Let session be a new XRSession object.
301
155
    //   10. Initialize the session with session and mode.
302
    // 5. Let result be the result of resolving the requested features given requiredFeatures,optionalFeatures, and mode.
156
    //   11. If immersive is true, set the active immersive session to session, and set pending immersive session to false.
303
    auto resolvedFeatures = resolveRequestedFeatures(mode, init, device, globalObject);
157
    //   12. Else append session to the list of inline sessions.
304
158
    //   13. Resolve promise with session.
305
    // 6. If result is null, run the following steps:
306
    //  6.1. Set status's state to "denied".
307
    //  6.2. Abort these steps.
308
    if (!resolvedFeatures)
309
        return false;
310
311
    // 7. Let (consentRequired, consentOptional, granted) be the fields of result.
312
    // 8. The user agent MAY at this point ask the user's permission for the calling algorithm to use any of the features
313
    //    in consentRequired and consentOptional. The results of these prompts should be included when determining if there
314
    //    is a clear signal of user intent for enabling these features.
315
    // 9. For each feature in consentRequired perform the following steps:
316
    //  9.1. The user agent MAY at this point ask the user's permission for the calling algorithm to use feature. The results
317
    //       of these prompts should be included when determining if there is a clear signal of user intent to enable feature.
318
    //  9.2. If a clear signal of user intent to enable feature has not been determined, set status's state to "denied" and
319
    //       abort these steps.
320
    //  9.3. If feature is not in granted, append feature to granted.
321
    // 10. For each feature in consentOptional perform the following steps:
322
    //  10.1. The user agent MAY at this point ask the user's permission for the calling algorithm to use feature. The results
323
    //        of these prompts should be included when determining if there is a clear signal of user intent to enable feature.
324
    //  10.2. If a clear signal of user intent to enable feature has not been determined, continue to the next entry.
325
    //  10.3. If feature is not in granted, append feature to granted.
326
    // 11. Set status's granted to granted.
327
    // 12. Set device's list of enabled features for mode to granted.
328
    // 13. Set status's state to "granted".
329
    return true;
330
}
331
332
333
// https://immersive-web.github.io/webxr/#dom-xrsystem-requestsession
334
void WebXRSystem::requestSession(Document& document, XRSessionMode mode, const XRSessionInit& init, RequestSessionPromise&& promise)
335
{
336
    // 1. Let promise be a new Promise.
337
    // 2. Let immersive be true if mode is an immersive session mode, and false otherwise.
338
    // 3. Let global object be the relevant Global object for the XRSystem on which this method was invoked.
339
    bool immersive = mode == XRSessionMode::ImmersiveAr || mode == XRSessionMode::ImmersiveVr;
340
    auto* globalObject = document.domWindow();
341
    if (!globalObject) {
342
        promise.reject(Exception { InvalidAccessError});
343
        return;
344
    }
345
346
    // 4. Check whether the session request is allowed as follows:
347
    if (immersive) {
348
        if (!immersiveSessionRequestIsAllowedForGlobalObject(*globalObject, document)) {
349
            promise.reject(Exception { SecurityError });
350
            return;
351
        }
352
        if (m_pendingImmersiveSession || m_activeImmersiveSession) {
353
            promise.reject(Exception { InvalidStateError });
354
            return;
355
        }
356
        m_pendingImmersiveSession = true;
357
    } else {
358
        if (!inlineSessionRequestIsAllowedForGlobalObject(*globalObject, document, init)) {
359
            promise.reject(Exception { SecurityError });
360
            return;
361
        }
362
    }
363
364
    // 5. Run the following steps in parallel:
365
    document.postTask([this, immersive, init, mode, promise = WTFMove(promise)] (auto& context) mutable {
366
        // 5.1 Let requiredFeatures be options' requiredFeatures.
367
        // 5.2 Let optionalFeatures be options' optionalFeatures.
368
        // 5.3 Set device to the result of obtaining the current device for mode, requiredFeatures, and optionalFeatures.
369
        auto* device = obtainCurrentDevice(mode, init.requiredFeatures, init.optionalFeatures);
370
371
        // 5.4 Queue a task to perform the following steps:
372
        queueTaskKeepingObjectAlive(*this, TaskSource::WebXR, [this, &context, device = makeWeakPtr(device), immersive, init, mode, promise = WTFMove(promise)] () mutable {
373
            auto rejectPromiseWithNotSupportedError = makeScopeExit([&] () {
374
                promise.reject(Exception { NotSupportedError });
375
                m_pendingImmersiveSession = false;
376
            });
377
378
            // 5.4.1 If device is null or device's list of supported modes does not contain mode, run the following steps:
379
            //  - Reject promise with a "NotSupportedError" DOMException.
380
            //  - If immersive is true, set pending immersive session to false.
381
            //  - Abort these steps.
382
            if (!device || !device->supports(mode))
383
                return;
384
385
            auto* globalObject = context.execState();
386
            if (!globalObject)
387
                return;
388
389
            // WebKit does not currently support the Permissions API. https://w3c.github.io/permissions/
390
            // However we do implement here the permission request algorithm without the
391
            // Permissions API bits as it handles, among others, the session features parsing. We also
392
            // do it here before creating the session as there is no need to do it on advance.
393
            // TODO: we just perform basic checks without asking any permission to the user so far. Maybe we should implement
394
            // a mechanism similar to what others do involving passing a message to the UI process.
395
396
            // 5.4.4 Let descriptor be an XRPermissionDescriptor initialized with session, requiredFeatures, and optionalFeatures
397
            // 5.4.5 Let status be an XRPermissionStatus, initially null
398
            // 5.4.6 Request the xr permission with descriptor and status.
399
            // 5.4.7 If status' state is "denied" run the following steps: (same as above in 5.4.1)
400
            if (!isXRPermissionGranted(mode, init, device.get(), *globalObject))
401
                return;
402
403
            // 5.4.2 Let session be a new XRSession object.
404
            // 5.4.3 Initialize the session with session, mode, and device.
405
            ASSERT(is<Document>(context.get()));
406
            auto session = WebXRSession::create(downcast<Document>(context), *this, mode, WTFMove(device));
407
408
            // 5.4.8 Potentially set the active immersive session as follows:
409
            if (immersive) {
410
                m_activeImmersiveSession = session.copyRef();
411
                m_pendingImmersiveSession = false;
412
            } else
413
                m_listOfInlineSessions.append(session.copyRef());
414
415
            // 5.4.9 Resolve promise with session.
416
            promise.resolve(session);
417
            rejectPromiseWithNotSupportedError.release();
418
419
            // TODO:
420
            // 5.4.10 Queue a task to perform the following steps: NOTE: These steps ensure that initial inputsourceschange
421
            // events occur after the initial session is resolved.
422
            //     1. Set session's promise resolved flag to true.
423
            //     2. Let sources be any existing input sources attached to session.
424
            //     3. If sources is non-empty, perform the following steps:
425
            //        1. Set session's list of active XR input sources to sources.
426
            //        2. Fire an XRInputSourcesChangeEvent named inputsourceschange on session with added set to sources.
427
428
        });
429
    });
159
}
430
}
160
431
161
const char* WebXRSystem::activeDOMObjectName() const
432
const char* WebXRSystem::activeDOMObjectName() const
Lines 171-177 void WebXRSystem::registerSimulatedXRDeviceForTesting(const PlatformXR::Device& a/Source/WebCore/Modules/webxr/WebXRSystem.cpp_sec6
171
{
442
{
172
    if (!RuntimeEnabledFeatures::sharedFeatures().webXREnabled())
443
    if (!RuntimeEnabledFeatures::sharedFeatures().webXREnabled())
173
        return;
444
        return;
174
    m_testingMode = true;
445
    m_testingDevices++;
175
    if (device.supports(PlatformXR::SessionMode::ImmersiveVr) || device.supports(PlatformXR::SessionMode::ImmersiveAr)) {
446
    if (device.supports(PlatformXR::SessionMode::ImmersiveVr) || device.supports(PlatformXR::SessionMode::ImmersiveAr)) {
176
        m_immersiveDevices.append(makeWeakPtr(device));
447
        m_immersiveDevices.append(makeWeakPtr(device));
177
        m_activeImmersiveDevice = m_immersiveDevices.last();
448
        m_activeImmersiveDevice = m_immersiveDevices.last();
Lines 185-198 void WebXRSystem::unregisterSimulatedXRDeviceForTesting(PlatformXR::Device* devi a/Source/WebCore/Modules/webxr/WebXRSystem.cpp_sec7
185
    if (!RuntimeEnabledFeatures::sharedFeatures().webXREnabled())
456
    if (!RuntimeEnabledFeatures::sharedFeatures().webXREnabled())
186
        return;
457
        return;
187
    ASSERT(m_immersiveDevices.contains(device));
458
    ASSERT(m_immersiveDevices.contains(device));
459
    ASSERT(m_testingDevices);
188
    m_immersiveDevices.removeFirst(device);
460
    m_immersiveDevices.removeFirst(device);
189
    if (m_activeImmersiveDevice == device)
461
    if (m_activeImmersiveDevice == device)
190
        m_activeImmersiveDevice = nullptr;
462
        m_activeImmersiveDevice = nullptr;
191
    if (m_inlineXRDevice == device)
463
    if (m_inlineXRDevice == device)
192
        m_inlineXRDevice = makeWeakPtr(m_defaultInlineDevice);
464
        m_inlineXRDevice = makeWeakPtr(m_defaultInlineDevice);
193
    m_testingMode = false;
465
    m_testingDevices--;
194
}
466
}
195
467
468
void WebXRSystem::sessionEnded(const WebXRSession* session)
469
{
470
    if (m_activeImmersiveSession == session)
471
        m_activeImmersiveSession = nullptr;
472
473
    m_listOfInlineSessions.removeFirstMatching([session](auto& item) {
474
        return item.ptr() == session;
475
    });
476
}
196
477
197
} // namespace WebCore
478
} // namespace WebCore
198
479
- a/Source/WebCore/Modules/webxr/WebXRSystem.h -7 / +26 lines
Lines 33-45 a/Source/WebCore/Modules/webxr/WebXRSystem.h_sec1
33
#include "JSDOMPromiseDeferred.h"
33
#include "JSDOMPromiseDeferred.h"
34
#include "WebGLContextAttributes.h"
34
#include "WebGLContextAttributes.h"
35
#include "WebGLRenderingContextBase.h"
35
#include "WebGLRenderingContextBase.h"
36
#include "XRReferenceSpaceType.h"
36
#include "XRSessionMode.h"
37
#include "XRSessionMode.h"
37
#include <wtf/IsoMalloc.h>
38
#include <wtf/IsoMalloc.h>
39
#include <wtf/Optional.h>
38
#include <wtf/RefCounted.h>
40
#include <wtf/RefCounted.h>
39
#include <wtf/WeakPtr.h>
41
#include <wtf/WeakPtr.h>
40
42
43
namespace JSC {
44
class JSGlobalObject;
45
}
46
41
namespace WebCore {
47
namespace WebCore {
42
48
49
class DOMWindow;
43
class ScriptExecutionContext;
50
class ScriptExecutionContext;
44
class WebXRSession;
51
class WebXRSession;
45
struct XRSessionInit;
52
struct XRSessionInit;
Lines 57-68 public: a/Source/WebCore/Modules/webxr/WebXRSystem.h_sec2
57
    using RefCounted<WebXRSystem>::deref;
64
    using RefCounted<WebXRSystem>::deref;
58
65
59
    void isSessionSupported(XRSessionMode, IsSessionSupportedPromise&&);
66
    void isSessionSupported(XRSessionMode, IsSessionSupportedPromise&&);
60
    void requestSession(XRSessionMode, const XRSessionInit&, RequestSessionPromise&&);
67
    void requestSession(Document&, XRSessionMode, const XRSessionInit&, RequestSessionPromise&&);
61
68
62
    // This is also needed by WebGLRenderingContextBase::makeXRCompatible() and HTMLCanvasElement::createContextWebGL().
69
    // This is also needed by WebGLRenderingContextBase::makeXRCompatible() and HTMLCanvasElement::createContextWebGL().
63
    void ensureImmersiveXRDeviceIsSelected();
70
    void ensureImmersiveXRDeviceIsSelected();
64
    bool hasActiveImmersiveXRDevice() { return !!m_activeImmersiveDevice; }
71
    bool hasActiveImmersiveXRDevice() { return !!m_activeImmersiveDevice; }
65
72
73
    void sessionEnded(const WebXRSession*);
74
66
    // For testing purpouses only.
75
    // For testing purpouses only.
67
    void registerSimulatedXRDeviceForTesting(const PlatformXR::Device&);
76
    void registerSimulatedXRDeviceForTesting(const PlatformXR::Device&);
68
    void unregisterSimulatedXRDeviceForTesting(PlatformXR::Device*);
77
    void unregisterSimulatedXRDeviceForTesting(PlatformXR::Device*);
Lines 81-100 protected: a/Source/WebCore/Modules/webxr/WebXRSystem.h_sec3
81
private:
90
private:
82
    WebXRSystem(ScriptExecutionContext&);
91
    WebXRSystem(ScriptExecutionContext&);
83
92
93
    using FeaturesArray = PlatformXR::Device::ListOfEnabledFeatures;
94
    using JSFeaturesArray = Vector<JSC::JSValue>;
95
    PlatformXR::Device* obtainCurrentDevice(XRSessionMode, const JSFeaturesArray& requiredFeatures, const JSFeaturesArray& optionalFeatures);
96
97
    bool immersiveSessionRequestIsAllowedForGlobalObject(DOMWindow&, Document&) const;
98
    bool inlineSessionRequestIsAllowedForGlobalObject(DOMWindow&, Document&, const XRSessionInit&) const;
99
100
    struct ResolvedRequestedFeatures;
101
    Optional<ResolvedRequestedFeatures> resolveRequestedFeatures(XRSessionMode, const XRSessionInit&, PlatformXR::Device*, JSC::JSGlobalObject&) const;
102
    bool isXRPermissionGranted(XRSessionMode, const XRSessionInit&, PlatformXR::Device*, JSC::JSGlobalObject&) const;
103
84
    // https://immersive-web.github.io/webxr/#default-inline-xr-device
104
    // https://immersive-web.github.io/webxr/#default-inline-xr-device
85
    class DummyInlineDevice final : public PlatformXR::Device {
105
    class DummyInlineDevice final : public PlatformXR::Device {
86
    public:
106
    public:
87
        DummyInlineDevice()
107
        DummyInlineDevice();
88
        {
89
            m_supportedModes.append(XRSessionMode::Inline);
90
        }
91
    };
108
    };
92
    DummyInlineDevice m_defaultInlineDevice;
109
    DummyInlineDevice m_defaultInlineDevice;
93
110
94
    bool m_immersiveXRDevicesHaveBeenEnumerated { false };
111
    bool m_immersiveXRDevicesHaveBeenEnumerated { false };
95
    bool m_testingMode { false };
112
    uint m_testingDevices { 0 };
96
113
97
    WeakPtr<WebXRSession> m_activeImmersiveSession;
114
    bool m_pendingImmersiveSession { false };
115
    RefPtr<WebXRSession> m_activeImmersiveSession;
116
    Vector<Ref<WebXRSession>> m_listOfInlineSessions;
98
117
99
    WeakPtr<PlatformXR::Device> m_activeImmersiveDevice;
118
    WeakPtr<PlatformXR::Device> m_activeImmersiveDevice;
100
    Vector<WeakPtr<PlatformXR::Device>> m_immersiveDevices;
119
    Vector<WeakPtr<PlatformXR::Device>> m_immersiveDevices;
- a/Source/WebCore/Modules/webxr/WebXRSystem.idl -1 / +1 lines
Lines 33-39 a/Source/WebCore/Modules/webxr/WebXRSystem.idl_sec1
33
] interface WebXRSystem : EventTarget {
33
] interface WebXRSystem : EventTarget {
34
    // Methods
34
    // Methods
35
    Promise<void> isSessionSupported(XRSessionMode mode);
35
    Promise<void> isSessionSupported(XRSessionMode mode);
36
    [NewObject] Promise<WebXRSession> requestSession(XRSessionMode mode, optional XRSessionInit options);
36
    [NewObject, CallWith=Document] Promise<WebXRSession> requestSession(XRSessionMode mode, optional XRSessionInit options);
37
37
38
    // Events
38
    // Events
39
    attribute EventHandler ondevicechange;
39
    attribute EventHandler ondevicechange;
- a/Source/WebCore/dom/TaskSource.h +1 lines
Lines 39-44 enum class TaskSource : uint8_t { a/Source/WebCore/dom/TaskSource.h_sec1
39
    PostedMessageQueue,
39
    PostedMessageQueue,
40
    UserInteraction,
40
    UserInteraction,
41
    WebGL,
41
    WebGL,
42
    WebXR,
42
43
43
    // Internal to WebCore
44
    // Internal to WebCore
44
    InternalAsyncTask, // Safe to re-order or delay.
45
    InternalAsyncTask, // Safe to re-order or delay.
- a/Source/WebCore/platform/xr/PlatformXR.h -8 / +10 lines
Lines 19-30 a/Source/WebCore/platform/xr/PlatformXR.h_sec1
19
#pragma once
19
#pragma once
20
20
21
#include <memory>
21
#include <memory>
22
#include <wtf/HashMap.h>
22
#include <wtf/Vector.h>
23
#include <wtf/Vector.h>
23
#include <wtf/WeakPtr.h>
24
#include <wtf/WeakPtr.h>
24
25
25
namespace PlatformXR {
26
namespace PlatformXR {
26
27
27
enum class SessionMode {
28
enum class SessionMode : uint8_t {
28
    Inline,
29
    Inline,
29
    ImmersiveVr,
30
    ImmersiveVr,
30
    ImmersiveAr,
31
    ImmersiveAr,
Lines 48-65 public: a/Source/WebCore/platform/xr/PlatformXR.h_sec2
48
    Device();
49
    Device();
49
    DeviceId id() const { return m_id; }
50
    DeviceId id() const { return m_id; }
50
51
51
    using ListOfSupportedModes = Vector<SessionMode>;
52
    using ListOfEnabledFeatures = Vector<ReferenceSpaceType>;
52
    using ListOfEnabledFeatures = Vector<ReferenceSpaceType>;
53
53
    bool supports(SessionMode mode) const { return m_enabledFeaturesMap.contains(mode); }
54
    bool supports(SessionMode mode) const { return m_supportedModes.contains(mode); }
54
    void setEnabledFeatures(SessionMode mode, const ListOfEnabledFeatures& features) { m_enabledFeaturesMap.set(mode, features); }
55
    void setSupportedModes(const ListOfSupportedModes& modes) { m_supportedModes = modes; }
55
    ListOfEnabledFeatures enabledFeatures(SessionMode mode) const { return m_enabledFeaturesMap.get(mode); }
56
    void setEnabledFeatures(const ListOfEnabledFeatures& features) { m_enabledFeatures = features; }
57
56
58
    inline bool operator==(const Device& other) const { return m_id == other.m_id; }
57
    inline bool operator==(const Device& other) const { return m_id == other.m_id; }
59
58
60
protected:
59
protected:
61
    ListOfSupportedModes m_supportedModes;
60
    // https://immersive-web.github.io/webxr/#xr-device-concept
62
    ListOfEnabledFeatures m_enabledFeatures;
61
    // Each XR device has a list of enabled features for each XRSessionMode in its list of supported modes,
62
    // which is a list of feature descriptors which MUST be initially an empty list.
63
    using EnabledFeaturesPerModeMap = WTF::HashMap<SessionMode, ListOfEnabledFeatures, WTF::IntHash<SessionMode>, WTF::StrongEnumHashTraits<SessionMode>>;
64
    EnabledFeaturesPerModeMap m_enabledFeaturesMap;
63
65
64
private:
66
private:
65
    DeviceId m_id;
67
    DeviceId m_id;
- a/Source/WebCore/platform/xr/openxr/PlatformXR.cpp -8 / +16 lines
Lines 24-29 a/Source/WebCore/platform/xr/openxr/PlatformXR.cpp_sec1
24
24
25
#if USE_OPENXR
25
#if USE_OPENXR
26
#include <openxr/openxr.h>
26
#include <openxr/openxr.h>
27
#include <wtf/Optional.h>
27
#include <wtf/text/StringConcatenateNumbers.h>
28
#include <wtf/text/StringConcatenateNumbers.h>
28
#include <wtf/text/WTFString.h>
29
#include <wtf/text/WTFString.h>
29
#endif // USE_OPENXR
30
#endif // USE_OPENXR
Lines 67-73 public: a/Source/WebCore/platform/xr/openxr/PlatformXR.cpp_sec2
67
    ~Impl();
68
    ~Impl();
68
69
69
#if USE_OPENXR
70
#if USE_OPENXR
70
    void collectSupportedSessionModes(Device&, XrSystemId);
71
    Optional<Vector<SessionMode>> collectSupportedSessionModes(Device&, XrSystemId);
71
    XrInstance m_instance { XR_NULL_HANDLE };
72
    XrInstance m_instance { XR_NULL_HANDLE };
72
#endif // USE_OPENXR
73
#endif // USE_OPENXR
73
};
74
};
Lines 150-162 Instance::Impl::~Impl() a/Source/WebCore/platform/xr/openxr/PlatformXR.cpp_sec3
150
151
151
#if USE_OPENXR
152
#if USE_OPENXR
152
153
153
void Instance::Impl::collectSupportedSessionModes(Device& device, XrSystemId systemId)
154
Optional<Vector<SessionMode>> Instance::Impl::collectSupportedSessionModes(Device& device, XrSystemId systemId)
154
{
155
{
155
    uint32_t viewConfigurationCount;
156
    uint32_t viewConfigurationCount;
156
    XrResult result = xrEnumerateViewConfigurations(m_instance, systemId, 0, &viewConfigurationCount, nullptr);
157
    XrResult result = xrEnumerateViewConfigurations(m_instance, systemId, 0, &viewConfigurationCount, nullptr);
157
    if (result != XR_SUCCESS) {
158
    if (result != XR_SUCCESS) {
158
        WTFLogAlways("xrEnumerateViewConfigurations(): error %s\n", resultToString(result, m_instance).utf8().data());
159
        WTFLogAlways("xrEnumerateViewConfigurations(): error %s\n", resultToString(result, m_instance).utf8().data());
159
        return;
160
        return WTF::nullopt;
160
    }
161
    }
161
162
162
    XrViewConfigurationType viewConfigurations[viewConfigurationCount];
163
    XrViewConfigurationType viewConfigurations[viewConfigurationCount];
Lines 164-186 void Instance::Impl::collectSupportedSessionModes(Device& device, XrSystemId sys a/Source/WebCore/platform/xr/openxr/PlatformXR.cpp_sec4
164
    if (result != XR_SUCCESS) {
165
    if (result != XR_SUCCESS) {
165
        WTFLogAlways("xrEnumerateViewConfigurations(): error %s\n", resultToString(result, m_instance).utf8().data());
166
        WTFLogAlways("xrEnumerateViewConfigurations(): error %s\n", resultToString(result, m_instance).utf8().data());
166
        WTFLogAlways("xrEnumerateViewConfigurations(): error %s\n", resultToString(result, m_instance).utf8().data());
167
        WTFLogAlways("xrEnumerateViewConfigurations(): error %s\n", resultToString(result, m_instance).utf8().data());
167
        return;
168
        return WTF::nullopt;
168
    }
169
    }
169
170
170
    Device::ListOfSupportedModes supportedModes;
171
    Vector<SessionMode> supportedModes;
171
    for (uint32_t i = 0; i < viewConfigurationCount; ++i) {
172
    for (uint32_t i = 0; i < viewConfigurationCount; ++i) {
172
        auto viewConfigurationProperties = createStructure<XrViewConfigurationProperties, XR_TYPE_VIEW_CONFIGURATION_PROPERTIES>();
173
        auto viewConfigurationProperties = createStructure<XrViewConfigurationProperties, XR_TYPE_VIEW_CONFIGURATION_PROPERTIES>();
173
        result = xrGetViewConfigurationProperties(m_instance, systemId, viewConfigurations[i], &viewConfigurationProperties);
174
        result = xrGetViewConfigurationProperties(m_instance, systemId, viewConfigurations[i], &viewConfigurationProperties);
174
        if (result != XR_SUCCESS) {
175
        if (result != XR_SUCCESS) {
175
            WTFLogAlways("xrGetViewConfigurationProperties(): error %s\n", resultToString(result, m_instance).utf8().data());
176
            WTFLogAlways("xrGetViewConfigurationProperties(): error %s\n", resultToString(result, m_instance).utf8().data());
176
            return;
177
            return WTF::nullopt;
177
        }
178
        }
178
        if (viewConfigurationProperties.viewConfigurationType == XR_VIEW_CONFIGURATION_TYPE_PRIMARY_MONO)
179
        if (viewConfigurationProperties.viewConfigurationType == XR_VIEW_CONFIGURATION_TYPE_PRIMARY_MONO)
179
            supportedModes.append(SessionMode::ImmersiveAr);
180
            supportedModes.append(SessionMode::ImmersiveAr);
180
        else if (viewConfigurationProperties.viewConfigurationType == XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO)
181
        else if (viewConfigurationProperties.viewConfigurationType == XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO)
181
            supportedModes.append(SessionMode::ImmersiveVr);
182
            supportedModes.append(SessionMode::ImmersiveVr);
182
    }
183
    }
183
    device.setSupportedModes(supportedModes);
184
    return supportedModes;
184
}
185
}
185
186
186
#endif // USE_OPENXR
187
#endif // USE_OPENXR
Lines 218-224 void Instance::enumerateImmersiveXRDevices() a/Source/WebCore/platform/xr/openxr/PlatformXR.cpp_sec5
218
    }
219
    }
219
220
220
    auto device = makeUnique<Device>();
221
    auto device = makeUnique<Device>();
221
    m_impl->collectSupportedSessionModes(*device, systemId);
222
    auto sessionModes = m_impl->collectSupportedSessionModes(*device, systemId);
223
    if (sessionModes) {
224
        for (auto& mode : sessionModes.value()) {
225
            // TODO: fill in features
226
            device->setEnabledFeatures(mode, { });
227
        }
228
    }
229
222
    m_immersiveXRDevices.append(WTFMove(device));
230
    m_immersiveXRDevices.append(WTFMove(device));
223
#endif // USE_OPENXR
231
#endif // USE_OPENXR
224
}
232
}
- a/Source/WebCore/testing/WebXRTest.cpp -6 / +9 lines
Lines 54-66 void WebXRTest::simulateDeviceConnection(ScriptExecutionContext& context, const a/Source/WebCore/testing/WebXRTest.cpp_sec1
54
            simulatedDevice.views().append(view.releaseReturnValue());
54
            simulatedDevice.views().append(view.releaseReturnValue());
55
        }
55
        }
56
56
57
        Vector<XRReferenceSpaceType> features;
57
        if (init.supportedFeatures) {
58
        if (init.supportedFeatures) {
58
            Vector<XRReferenceSpaceType> features;
59
            if (auto* globalObject = context.execState()) {
59
            for (auto& feature : init.supportedFeatures.value()) {
60
                for (auto& feature : init.supportedFeatures.value()) {
60
                if (auto referenceSpaceType = parseEnumeration<XRReferenceSpaceType>(*context.execState(), feature))
61
                    if (auto referenceSpaceType = parseEnumeration<XRReferenceSpaceType>(*globalObject, feature))
61
                    features.append(referenceSpaceType.value());
62
                        features.append(referenceSpaceType.value());
63
                }
62
            }
64
            }
63
            simulatedDevice.setEnabledFeatures(features);
64
        }
65
        }
65
66
66
        if (init.boundsCoordinates) {
67
        if (init.boundsCoordinates) {
Lines 87-93 void WebXRTest::simulateDeviceConnection(ScriptExecutionContext& context, const a/Source/WebCore/testing/WebXRTest.cpp_sec2
87
            if (init.supportsImmersive)
88
            if (init.supportsImmersive)
88
                supportedModes.append(XRSessionMode::ImmersiveVr);
89
                supportedModes.append(XRSessionMode::ImmersiveVr);
89
        }
90
        }
90
        simulatedDevice.setSupportedModes(supportedModes);
91
92
        for (auto& mode : supportedModes)
93
            simulatedDevice.setEnabledFeatures(mode, features);
91
94
92
        m_context->registerSimulatedXRDeviceForTesting(simulatedDevice);
95
        m_context->registerSimulatedXRDeviceForTesting(simulatedDevice);
93
96
- a/LayoutTests/ChangeLog +10 lines
Lines 1-3 a/LayoutTests/ChangeLog_sec1
1
2020-05-14  Sergio Villar Senin  <svillar@igalia.com>
2
3
        [WebXR] Implement requestSession()
4
        https://bugs.webkit.org/show_bug.cgi?id=211888
5
6
        Reviewed by NOBODY (OOPS!).
7
8
        * platform/wpe/TestExpectations: Added several previously skipped tests
9
        that are now passing.
10
1
2020-05-14  Diego Pino Garcia  <dpino@igalia.com>
11
2020-05-14  Diego Pino Garcia  <dpino@igalia.com>
2
12
3
        [GTK] Gardening, update expectations after r261609
13
        [GTK] Gardening, update expectations after r261609
- a/LayoutTests/imported/w3c/ChangeLog +16 lines
Lines 1-3 a/LayoutTests/imported/w3c/ChangeLog_sec1
1
2020-05-14  Sergio Villar Senin  <svillar@igalia.com>
2
3
        [WebXR] Implement requestSession()
4
        https://bugs.webkit.org/show_bug.cgi?id=211888
5
6
        Reviewed by NOBODY (OOPS!).
7
8
        * web-platform-tests/webxr/xrDevice_requestSession_immersive.https-expected.txt: Added.
9
        * web-platform-tests/webxr/xrDevice_requestSession_immersive_no_gesture.https-expected.txt: Added.
10
        * web-platform-tests/webxr/xrDevice_requestSession_immersive_unsupported.https-expected.txt: Added.
11
        * web-platform-tests/webxr/xrDevice_requestSession_no_mode.https-expected.txt: Added.
12
        * web-platform-tests/webxr/xrDevice_requestSession_non_immersive_no_gesture.https-expected.txt: Added.
13
        * web-platform-tests/webxr/xrDevice_requestSession_optionalFeatures.https-expected.txt: Added.
14
        * web-platform-tests/webxr/xrDevice_requestSession_requiredFeatures_unknown.https-expected.txt: Added.
15
        * web-platform-tests/webxr/xrSession_features_deviceSupport.https-expected.txt: Added.
16
1
2020-05-12  Alexey Shvayka  <shvaikalesh@gmail.com>
17
2020-05-12  Alexey Shvayka  <shvaikalesh@gmail.com>
2
18
3
        Implement @isConstructor bytecode intrinsic and bytecode for that
19
        Implement @isConstructor bytecode intrinsic and bytecode for that
- a/LayoutTests/imported/w3c/web-platform-tests/webxr/xrDevice_requestSession_immersive.https-expected.txt +5 lines
Line 0 a/LayoutTests/imported/w3c/web-platform-tests/webxr/xrDevice_requestSession_immersive.https-expected.txt_sec1
1
2
PASS Tests requestSession resolves when supported 
3
PASS Tests requestSession accepts XRSessionInit dictionary 
4
PASS Tests requestSession ignores unknown optionalFeatures 
5
- a/LayoutTests/imported/w3c/web-platform-tests/webxr/xrDevice_requestSession_immersive_no_gesture.https-expected.txt +3 lines
Line 0 a/LayoutTests/imported/w3c/web-platform-tests/webxr/xrDevice_requestSession_immersive_no_gesture.https-expected.txt_sec1
1
2
PASS Requesting immersive session outside of a user gesture rejects 
3
- a/LayoutTests/imported/w3c/web-platform-tests/webxr/xrDevice_requestSession_immersive_unsupported.https-expected.txt +3 lines
Line 0 a/LayoutTests/imported/w3c/web-platform-tests/webxr/xrDevice_requestSession_immersive_unsupported.https-expected.txt_sec1
1
2
PASS Requesting an immersive session when unsupported rejects 
3
- a/LayoutTests/imported/w3c/web-platform-tests/webxr/xrDevice_requestSession_no_mode.https-expected.txt +3 lines
Line 0 a/LayoutTests/imported/w3c/web-platform-tests/webxr/xrDevice_requestSession_no_mode.https-expected.txt_sec1
1
2
PASS Requesting a session with no mode rejects 
3
- a/LayoutTests/imported/w3c/web-platform-tests/webxr/xrDevice_requestSession_non_immersive_no_gesture.https-expected.txt +3 lines
Line 0 a/LayoutTests/imported/w3c/web-platform-tests/webxr/xrDevice_requestSession_non_immersive_no_gesture.https-expected.txt_sec1
1
2
PASS Requesting non-immersive session outside of a user gesture succeeds 
3
- a/LayoutTests/imported/w3c/web-platform-tests/webxr/xrDevice_requestSession_optionalFeatures.https-expected.txt +6 lines
Line 0 a/LayoutTests/imported/w3c/web-platform-tests/webxr/xrDevice_requestSession_optionalFeatures.https-expected.txt_sec1
1
2
PASS Tests requestSession accepts XRSessionInit dictionary 
3
PASS Tests requestSession accepts XRSessionInit dictionary with empty feature lists 
4
PASS Tests requestSession ignores unknown strings in optionalFeatures 
5
PASS Tests requestSession ignores unknown objects in optionalFeatures 
6
- a/LayoutTests/imported/w3c/web-platform-tests/webxr/xrDevice_requestSession_requiredFeatures_unknown.https-expected.txt +3 lines
Line 0 a/LayoutTests/imported/w3c/web-platform-tests/webxr/xrDevice_requestSession_requiredFeatures_unknown.https-expected.txt_sec1
1
2
PASS Tests requestSession rejects for unknown requiredFeatures 
3
- a/LayoutTests/imported/w3c/web-platform-tests/webxr/xrSession_features_deviceSupport.https-expected.txt +3 lines
Line 0 a/LayoutTests/imported/w3c/web-platform-tests/webxr/xrSession_features_deviceSupport.https-expected.txt_sec1
1
2
PASS Immersive XRSession requests with no supported device should reject 
3
- a/LayoutTests/platform/wpe/TestExpectations +8 lines
Lines 1022-1027 webkit.org/b/209859 imported/w3c/web-platform-tests/webxr/idlharness.https.windo a/LayoutTests/platform/wpe/TestExpectations_sec1
1022
webkit.org/b/209859 imported/w3c/web-platform-tests/webxr/xrDevice_isSessionSupported_inline.https.html [ Pass ]
1022
webkit.org/b/209859 imported/w3c/web-platform-tests/webxr/xrDevice_isSessionSupported_inline.https.html [ Pass ]
1023
webkit.org/b/209859 imported/w3c/web-platform-tests/webxr/xrDevice_isSessionSupported_immersive.https.html [ Pass ]
1023
webkit.org/b/209859 imported/w3c/web-platform-tests/webxr/xrDevice_isSessionSupported_immersive.https.html [ Pass ]
1024
webkit.org/b/209859 imported/w3c/web-platform-tests/webxr/xrDevice_isSessionSupported_immersive_unsupported.https.html [ Pass ]
1024
webkit.org/b/209859 imported/w3c/web-platform-tests/webxr/xrDevice_isSessionSupported_immersive_unsupported.https.html [ Pass ]
1025
webkit.org/b/209859 imported/w3c/web-platform-tests/webxr/xrDevice_requestSession_immersive.https.html [ Pass ]
1026
webkit.org/b/209859 imported/w3c/web-platform-tests/webxr/xrDevice_requestSession_immersive_no_gesture.https.html [ Pass ]
1027
webkit.org/b/209859 imported/w3c/web-platform-tests/webxr/xrDevice_requestSession_immersive_unsupported.https.html [ Pass ]
1028
webkit.org/b/209859 imported/w3c/web-platform-tests/webxr/xrDevice_requestSession_no_mode.https.html [ Pass ]
1029
webkit.org/b/209859 imported/w3c/web-platform-tests/webxr/xrDevice_requestSession_non_immersive_no_gesture.https.html [ Pass ]
1030
webkit.org/b/209859 imported/w3c/web-platform-tests/webxr/xrDevice_requestSession_optionalFeatures.https.html [ Pass ]
1031
webkit.org/b/209859 imported/w3c/web-platform-tests/webxr/xrDevice_requestSession_requiredFeatures_unknown.https.html [ Pass ]
1032
webkit.org/b/209859 imported/w3c/web-platform-tests/webxr/xrSession_features_deviceSupport.https.html [ Pass ]
1025
1033
1026
# Passing since r259006.
1034
# Passing since r259006.
1027
imported/w3c/web-platform-tests/css/css-grid/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-010.html
1035
imported/w3c/web-platform-tests/css/css-grid/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-010.html

Return to Bug 211888