Changeset 261863 in webkit


Ignore:
Timestamp:
May 19, 2020 9:08:47 AM (4 years ago)
Author:
svillar@igalia.com
Message:

[WebXR] Implement requestSession()
https://bugs.webkit.org/show_bug.cgi?id=211888

Reviewed by Youenn Fablet.

LayoutTests/imported/w3c:

  • web-platform-tests/webxr/xrDevice_requestSession_immersive.https-expected.txt: Added.
  • web-platform-tests/webxr/xrDevice_requestSession_immersive_no_gesture.https-expected.txt: Added.
  • web-platform-tests/webxr/xrDevice_requestSession_immersive_unsupported.https-expected.txt: Added.
  • web-platform-tests/webxr/xrDevice_requestSession_no_mode.https-expected.txt: Added.
  • web-platform-tests/webxr/xrDevice_requestSession_non_immersive_no_gesture.https-expected.txt: Added.
  • web-platform-tests/webxr/xrDevice_requestSession_optionalFeatures.https-expected.txt: Added.
  • web-platform-tests/webxr/xrDevice_requestSession_requiredFeatures_unknown.https-expected.txt: Added.
  • web-platform-tests/webxr/xrSession_features_deviceSupport.https-expected.txt: Added.

Source/WebCore:

This patch adds a preliminar implementation of the requestSession()
API used to get a WebXRSession from the UA. It includes a fairly good
amount of checks to verify that the request can be satisfied given the
device's enabled features per session modes. The specs also describe how
to request persmission for some actions using the Permissions API which
WebKit does not currently implement. That should be done in a follow up
patch perhaps using a similar approach to other APIs as Geolocation for
example.

In order to get some of the requestSession() tests passing the session
finalization (shutdown) had to be implemented too.

Several tests where unskipped for WPE port as they're now passing.

  • Modules/webxr/WebXRRenderState.cpp:

(WebCore::WebXRRenderState::create): Pass XRSessionMode as argument
instead of a WebXRSession.

  • Modules/webxr/WebXRRenderState.h: Ditto.
  • Modules/webxr/WebXRSession.cpp:

(WebCore::WebXRSession::create): Added.
(WebCore::WebXRSession::WebXRSession): Added.
(WebCore::WebXRSession::renderState const):
(WebCore::WebXRSession::inputSources const):
(WebCore::WebXRSession::shutdown): Shutdown process called on session end.
(WebCore::WebXRSession::end): Implemented session ending.

  • Modules/webxr/WebXRSession.h: Added create() and private constructor. Fixed some naming.
  • Modules/webxr/WebXRSystem.cpp:

(WebCore::WebXRSystem::DummyInlineDevice::DummyInlineDevice): Contructor for the
dummy inline device.
(WebCore::WebXRSystem::ensureImmersiveXRDeviceIsSelected): Use a counter instead of a boolean
to track testing devices as there might be more than 1.
(WebCore::WebXRSystem::obtainCurrentDevice): Implemented from specs text.
(WebCore::WebXRSystem::immersiveSessionRequestIsAllowedForGlobalObject const): Ditto.
(WebCore::WebXRSystem::inlineSessionRequestIsAllowedForGlobalObject const): Ditto.
(WebCore::WebXRSystem::resolveRequestedFeatures const): Ditto.
(WebCore::WebXRSystem::isXRPermissionGranted const): Ditto.
(WebCore::WebXRSystem::requestSession): Ditto.
(WebCore::WebXRSystem::registerSimulatedXRDeviceForTesting): Use a counter instead of a bool.
Also use a reference in the method argument.
(WebCore::WebXRSystem::unregisterSimulatedXRDeviceForTesting): Ditto.
(WebCore::WebXRSystem::sessionEnded): Added, used by sessions to notify the XRSystem.

  • Modules/webxr/WebXRSystem.h:
  • Modules/webxr/WebXRSystem.idl: Call requestSession with Document.
  • dom/TaskSource.h: Added a WebXR task source.
  • platform/xr/PlatformXR.h: Specs state that devices have a list of enabled features per session

mode so store them in a hashmap instead of in a Vector.
(PlatformXR::Device::supports const): Use the new Hashmap of session modes.
(PlatformXR::Device::setEnabledFeatures): Ditto.
(PlatformXR::Device::enabledFeatures const): Ditto.
(PlatformXR::Device::setSupportedModes): Deleted.

  • platform/xr/openxr/PlatformXR.cpp:

(PlatformXR::Instance::Impl::collectSupportedSessionModes): Return session modes if any.
(PlatformXR::Instance::enumerateImmersiveXRDevices): Fill in features per session mode.

  • testing/WebXRTest.cpp:

(WebCore::WebXRTest::simulateDeviceConnection): Fill in features per session mode.
(WebCore::WebXRTest::disconnectAllDevices): Pass a reference to unregister.

LayoutTests:

  • platform/wpe/TestExpectations: Added several previously skipped tests

that are now passing.

Location:
trunk
Files:
8 added
16 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r261861 r261863  
     12020-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 Youenn Fablet.
     7
     8        * platform/wpe/TestExpectations: Added several previously skipped tests
     9        that are now passing.
     10
    1112020-05-19  Antti Koivisto  <antti@apple.com>
    212
  • trunk/LayoutTests/imported/w3c/ChangeLog

    r261859 r261863  
     12020-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 Youenn Fablet.
     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
    1172020-05-19  Carlos Alberto Lopez Perez  <clopez@igalia.com>
    218
  • trunk/LayoutTests/platform/wpe/TestExpectations

    r261859 r261863  
    10171017webkit.org/b/209859 imported/w3c/web-platform-tests/webxr/xrDevice_isSessionSupported_immersive.https.html [ Pass ]
    10181018webkit.org/b/209859 imported/w3c/web-platform-tests/webxr/xrDevice_isSessionSupported_immersive_unsupported.https.html [ Pass ]
     1019webkit.org/b/209859 imported/w3c/web-platform-tests/webxr/xrDevice_requestSession_immersive.https.html [ Pass ]
     1020webkit.org/b/209859 imported/w3c/web-platform-tests/webxr/xrDevice_requestSession_immersive_no_gesture.https.html [ Pass ]
     1021webkit.org/b/209859 imported/w3c/web-platform-tests/webxr/xrDevice_requestSession_immersive_unsupported.https.html [ Pass ]
     1022webkit.org/b/209859 imported/w3c/web-platform-tests/webxr/xrDevice_requestSession_no_mode.https.html [ Pass ]
     1023webkit.org/b/209859 imported/w3c/web-platform-tests/webxr/xrDevice_requestSession_non_immersive_no_gesture.https.html [ Pass ]
     1024webkit.org/b/209859 imported/w3c/web-platform-tests/webxr/xrDevice_requestSession_optionalFeatures.https.html [ Pass ]
     1025webkit.org/b/209859 imported/w3c/web-platform-tests/webxr/xrDevice_requestSession_requiredFeatures_unknown.https.html [ Pass ]
     1026webkit.org/b/209859 imported/w3c/web-platform-tests/webxr/xrSession_features_deviceSupport.https.html [ Pass ]
    10191027
    10201028# Passing since r259006.
  • trunk/Source/WebCore/ChangeLog

    r261861 r261863  
     12020-05-19  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 Youenn Fablet.
     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        Also use a reference in the method argument.
     47        (WebCore::WebXRSystem::unregisterSimulatedXRDeviceForTesting): Ditto.
     48        (WebCore::WebXRSystem::sessionEnded): Added, used by sessions to notify the XRSystem.
     49        * Modules/webxr/WebXRSystem.h:
     50        * Modules/webxr/WebXRSystem.idl: Call requestSession with Document.
     51        * dom/TaskSource.h: Added a WebXR task source.
     52        * platform/xr/PlatformXR.h: Specs state that devices have a list of enabled features per session
     53        mode so store them in a hashmap instead of in a Vector.
     54        (PlatformXR::Device::supports const): Use the new Hashmap of session modes.
     55        (PlatformXR::Device::setEnabledFeatures): Ditto.
     56        (PlatformXR::Device::enabledFeatures const): Ditto.
     57        (PlatformXR::Device::setSupportedModes): Deleted.
     58        * platform/xr/openxr/PlatformXR.cpp:
     59        (PlatformXR::Instance::Impl::collectSupportedSessionModes): Return session modes if any.
     60        (PlatformXR::Instance::enumerateImmersiveXRDevices): Fill in features per session mode.
     61        * testing/WebXRTest.cpp:
     62        (WebCore::WebXRTest::simulateDeviceConnection): Fill in features per session mode.
     63        (WebCore::WebXRTest::disconnectAllDevices): Pass a reference to unregister.
     64
    1652020-05-19  Antti Koivisto  <antti@apple.com>
    266
  • trunk/Source/WebCore/Modules/webxr/WebXRInputSourceArray.h

    r258498 r261863  
    4040    unsigned length() const;
    4141    WebXRInputSource* item(unsigned) const;
     42
     43private:
     44    WebXRInputSourceArray();
    4245};
    4346
  • trunk/Source/WebCore/Modules/webxr/WebXRRenderState.cpp

    r258498 r261863  
    3838WTF_MAKE_ISO_ALLOCATED_IMPL(WebXRRenderState);
    3939
    40 Ref<WebXRRenderState> WebXRRenderState::create(const WebXRSession& session)
     40Ref<WebXRRenderState> WebXRRenderState::create(XRSessionMode mode)
    4141{
    42     // When an XRRenderState object is created for an XRSession session, the user agent MUST initialize the render state by running the following steps:
    43     //   1. Let state be the newly created XRRenderState object.
    44 
    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)));
     42    // https://immersive-web.github.io/webxr/#initialize-the-render-state
     43    // depthNear, depthFar and baseLayer are initialized in the class definition
     44    return adoptRef(*new WebXRRenderState(mode == XRSessionMode::Inline ? makeOptional(piOverTwoDouble) : WTF::nullopt));
    6045}
    6146
  • trunk/Source/WebCore/Modules/webxr/WebXRRenderState.h

    r258498 r261863  
    2828#if ENABLE(WEBXR)
    2929
     30#include "XRSessionMode.h"
    3031#include <wtf/IsoMalloc.h>
    3132#include <wtf/Optional.h>
     
    3839class WebXRWebGLLayer;
    3940struct XRRenderStateInit;
    40 class WebXRSession;
    4141
    4242class WebXRRenderState : public RefCounted<WebXRRenderState> {
    4343    WTF_MAKE_ISO_ALLOCATED(WebXRRenderState);
    4444public:
    45     static Ref<WebXRRenderState> create(const WebXRSession&);
     45    static Ref<WebXRRenderState> create(XRSessionMode);
    4646    ~WebXRRenderState();
    4747
     
    5252
    5353private:
    54     WebXRRenderState(Optional<double>&&);
    55     WebXRRenderState(const XRRenderStateInit&);
     54    explicit WebXRRenderState(Optional<double>&& fieldOfView);
     55    explicit WebXRRenderState(const XRRenderStateInit&);
    5656
     57    // https://immersive-web.github.io/webxr/#initialize-the-render-state
    5758    struct {
    58         double near { 0.1 };
    59         double far { 1000 };
     59        double near { 0.1 }; // in meters
     60        double far { 1000 }; // in meters
    6061    } m_depth;
    61     Optional<double> m_inlineVerticalFieldOfView;
     62    Optional<double> m_inlineVerticalFieldOfView; // in radians
    6263    RefPtr<WebXRWebGLLayer> m_baseLayer;
    6364};
  • trunk/Source/WebCore/Modules/webxr/WebXRSession.cpp

    r258498 r261863  
    2929#if ENABLE(WEBXR)
    3030
     31#include "WebXRSystem.h"
    3132#include <wtf/IsoMallocInlines.h>
    3233
     
    3435
    3536WTF_MAKE_ISO_ALLOCATED_IMPL(WebXRSession);
     37
     38Ref<WebXRSession> WebXRSession::create(Document& document, WebXRSystem& system, XRSessionMode mode, PlatformXR::Device& device)
     39{
     40    return adoptRef(*new WebXRSession(document, system, mode, device));
     41}
     42
     43WebXRSession::WebXRSession(Document& document, WebXRSystem& system, XRSessionMode mode, PlatformXR::Device& device)
     44    : ActiveDOMObject(&document)
     45    , m_xrSystem(system)
     46    , m_mode(mode)
     47    , m_device(makeWeakPtr(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}
    3655
    3756WebXRSession::~WebXRSession() = default;
     
    4968const WebXRRenderState& WebXRSession::renderState() const
    5069{
    51     return *m_renderState;
     70    return *m_activeRenderState;
    5271}
    5372
     
    7493}
    7594
    76 void WebXRSession::end(EndPromise&&)
     95// https://immersive-web.github.io/webxr/#shut-down-the-session
     96void WebXRSession::shutdown()
    7797{
     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
     116void WebXRSession::end(EndPromise&& promise)
     117{
     118    // The shutdown() call bellow might remove the sole reference to session
     119    // that could exist (the XRSystem owns the sessions) so let's protect this.
     120    Ref<WebXRSession> protectedThis(*this);
     121    // 1. Let promise be a new Promise.
     122    // 2. Shut down the target XRSession object.
     123    shutdown();
     124
     125    // 3. Queue a task to perform the following steps:
     126    queueTaskKeepingObjectAlive(*this, TaskSource::WebXR, [promise = WTFMove(promise)] () mutable {
     127        // 3.1 Wait until any platform-specific steps related to shutting down the session have completed.
     128        // 3.2 Resolve promise.
     129        promise.resolve();
     130    });
     131
     132    // 4. Return promise.
    78133}
    79134
  • trunk/Source/WebCore/Modules/webxr/WebXRSession.h

    r260415 r261863  
    3636#include "XREnvironmentBlendMode.h"
    3737#include "XRReferenceSpaceType.h"
     38#include "XRSessionMode.h"
    3839#include "XRVisibilityState.h"
    3940#include <wtf/Ref.h>
     
    4647class XRFrameRequestCallback;
    4748class WebXRReferenceSpace;
     49class WebXRSystem;
    4850struct XRRenderStateInit;
    4951
     
    5456    using EndPromise = DOMPromiseDeferred<void>;
    5557
     58    static Ref<WebXRSession> create(Document&, WebXRSystem&, XRSessionMode, PlatformXR::Device&);
    5659    virtual ~WebXRSession();
    5760
     
    7578
    7679private:
     80    WebXRSession(Document&, WebXRSystem&, XRSessionMode, PlatformXR::Device&);
     81
    7782    // EventTarget
    7883    EventTargetInterface eventTargetInterface() const override { return WebXRSessionEventTargetInterfaceType; }
     
    8590    void stop() override;
    8691
     92    void shutdown();
     93
    8794    XREnvironmentBlendMode m_environmentBlendMode;
    8895    XRVisibilityState m_visibilityState;
    89     RefPtr<WebXRRenderState> m_renderState;
    9096    RefPtr<WebXRInputSourceArray> m_inputSources;
    9197    bool m_ended { false };
     98
     99    WebXRSystem& m_xrSystem;
     100    XRSessionMode m_mode;
     101    WeakPtr<PlatformXR::Device> m_device;
     102    RefPtr<WebXRRenderState> m_activeRenderState;
     103    RefPtr<WebXRRenderState> m_pendingRenderState;
    92104};
    93105
  • trunk/Source/WebCore/Modules/webxr/WebXRSystem.cpp

    r261220 r261863  
    2929#if ENABLE(WEBXR)
    3030
     31#include "DOMWindow.h"
    3132#include "Document.h"
    3233#include "FeaturePolicy.h"
     34#include "IDLTypes.h"
     35#include "JSWebXRSession.h"
     36#include "JSXRReferenceSpaceType.h"
    3337#include "PlatformXR.h"
    3438#include "RuntimeEnabledFeatures.h"
     39#include "SecurityOrigin.h"
     40#include "UserGestureIndicator.h"
    3541#include "WebXRSession.h"
     42#include "XRReferenceSpaceType.h"
     43#include "XRSessionInit.h"
     44#include <JavaScriptCore/JSGlobalObject.h>
    3645#include <wtf/IsoMallocInlines.h>
     46#include <wtf/Scope.h>
    3747
    3848namespace WebCore {
    3949
    4050WTF_MAKE_ISO_ALLOCATED_IMPL(WebXRSystem);
     51
     52WebXRSystem::DummyInlineDevice::DummyInlineDevice()
     53{
     54    setEnabledFeatures(XRSessionMode::Inline, { XRReferenceSpaceType::Viewer });
     55}
    4156
    4257Ref<WebXRSystem> WebXRSystem::create(ScriptExecutionContext& scriptExecutionContext)
     
    5772{
    5873    // Don't ask platform code for XR devices, we're using simulated ones.
    59     // TODO: should be have a MockPlatformXR implementation instead ?
    60     if (UNLIKELY(m_testingMode))
     74    if (UNLIKELY(m_testingDevices))
    6175        return;
    6276
     
    97111}
    98112
     113
     114PlatformXR::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
    99127// https://immersive-web.github.io/webxr/#dom-xrsystem-issessionsupported
    100128void WebXRSystem::isSessionSupported(XRSessionMode mode, IsSessionSupportedPromise&& promise)
     
    107135    }
    108136
    109     // 3. If the requesting documents 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,
    110138    //    reject promise with a "SecurityError" DOMException and return it.
    111139    auto document = downcast<Document>(scriptExecutionContext());
     
    137165}
    138166
    139 void WebXRSystem::requestSession(XRSessionMode, const XRSessionInit&, RequestSessionPromise&&)
    140 {
    141     PlatformXR::Instance::singleton();
    142 
    143     // When the requestSession(mode) method is invoked, the user agent MUST return a new Promise promise and run the following steps in parallel:
    144     //   1. Let immersive be true if mode is "immersive-vr" or "immersive-ar", and false otherwise.
    145     //   2. If immersive is true:
    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.
    147     //     2. Else set pending immersive session to be true.
    148     //   3. Ensure an XR device is selected.
    149     //   4. If the XR device is null, reject promise with null.
    150     //   5. Else if the XR device's list of supported modes does not contain mode, reject promise with a "NotSupportedError" DOMException.
    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.
    152     //   7. If promise was rejected and immersive is true, set pending immersive session to false.
    153     //   8. If promise was rejected, abort these steps.
    154     //   9. Let session be a new XRSession object.
    155     //   10. Initialize the session with session and mode.
    156     //   11. If immersive is true, set the active immersive session to session, and set pending immersive session to false.
    157     //   12. Else append session to the list of inline sessions.
    158     //   13. Resolve promise with session.
     167// https://immersive-web.github.io/webxr/#immersive-session-request-is-allowed
     168bool 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
     194bool 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
     210struct 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
     224Optional<WebXRSystem::ResolvedRequestedFeatures> WebXRSystem::resolveRequestedFeatures(XRSessionMode mode, const XRSessionInit& init, PlatformXR::Device* device, JSC::JSGlobalObject& globalObject) const
     225{
     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    // 5. If device is null or device's list of supported modes does not contain mode, run the following steps:
     233    //  5.1 Return the tuple (consentRequired, consentOptional, granted)
     234    if (!device || !device->supports(mode))
     235        return resolvedFeatures;
     236
     237    resolvedFeatures.granted = device->enabledFeatures(mode);
     238
     239    // 6. Add every feature descriptor in the default features table associated
     240    //    with mode to the indicated feature list if it is not already present.
     241    // https://immersive-web.github.io/webxr/#default-features
     242    auto requiredFeaturesWithDefaultFeatures = init.requiredFeatures;
     243    requiredFeaturesWithDefaultFeatures.append(convertEnumerationToJS(globalObject, XRReferenceSpaceType::Viewer));
     244    if (mode == XRSessionMode::ImmersiveAr || mode == XRSessionMode::ImmersiveVr)
     245        requiredFeaturesWithDefaultFeatures.append(convertEnumerationToJS(globalObject, XRReferenceSpaceType::Local));
     246
     247    // 7. For each feature in requiredFeatures|optionalFeatures perform the following steps:
     248    // 8. For each feature in optionalFeatures perform the following steps:
     249    // We're merging both loops in a single lambda. The only difference is that a failure on any required features
     250    // implies cancelling the whole process while failures in optional features are just skipped.
     251    enum class ParsingMode { Strict, Loose };
     252    auto parseFeatures = [&device, &globalObject, mode, &resolvedFeatures] (const JSFeaturesArray& sessionFeatures, ParsingMode parsingMode) -> bool {
     253        bool returnOnFailure = parsingMode == ParsingMode::Strict;
     254        for (const auto& sessionFeature : sessionFeatures) {
     255            // 1. If the feature is null, continue to the next entry.
     256            if (sessionFeature.isNull())
     257                continue;
     258
     259            // 2. If feature is not a valid feature descriptor, perform the following steps
     260            //   2.1. Let s be the result of calling ? ToString(feature).
     261            //   2.2. If s is not a valid feature descriptor or is undefined, (return null|continue to next entry).
     262            //   2.3. Set feature to s.
     263            auto feature = parseEnumeration<XRReferenceSpaceType>(globalObject, sessionFeature);
     264            if (!feature)
     265                RETURN_FALSE_OR_CONTINUE(returnOnFailure);
     266
     267            // 3. If feature is already in granted, continue to the next entry.
     268            if (resolvedFeatures.granted.contains(feature.value()))
     269                continue;
     270
     271            // 4. If the requesting document's origin is not allowed to use any feature policy required by feature
     272            //    as indicated by the feature requirements table, (return null|continue to next entry).
     273
     274            // 5. If session's XR device is not capable of supporting the functionality described by feature or the
     275            //    user agent has otherwise determined to reject the feature, (return null|continue to next entry).
     276            if (!device->enabledFeatures(mode).contains(feature.value()))
     277                RETURN_FALSE_OR_CONTINUE(returnOnFailure);
     278
     279            // 6. If the functionality described by feature requires explicit consent, append it to (consentRequired|consentOptional).
     280            // 7. Else append feature to granted.
     281            resolvedFeatures.granted.append(feature.value());
     282        }
     283        return true;
     284    };
     285
     286    if (!parseFeatures(requiredFeaturesWithDefaultFeatures, ParsingMode::Strict))
     287        return WTF::nullopt;
     288
     289    parseFeatures(init.optionalFeatures, ParsingMode::Loose);
     290    return resolvedFeatures;
     291}
     292
     293// https://immersive-web.github.io/webxr/#request-the-xr-permission
     294bool WebXRSystem::isXRPermissionGranted(XRSessionMode mode, const XRSessionInit& init, PlatformXR::Device* device, JSC::JSGlobalObject& globalObject) const
     295{
     296    // 1. Set status's granted to an empty FrozenArray.
     297    // 2. Let requiredFeatures be descriptor's requiredFeatures.
     298    // 3. Let optionalFeatures be descriptor's optionalFeatures.
     299    // 4. Let device be the result of obtaining the current device for mode, requiredFeatures, and optionalFeatures.
     300
     301    // 5. Let result be the result of resolving the requested features given requiredFeatures,optionalFeatures, and mode.
     302    auto resolvedFeatures = resolveRequestedFeatures(mode, init, device, globalObject);
     303
     304    // 6. If result is null, run the following steps:
     305    //  6.1. Set status's state to "denied".
     306    //  6.2. Abort these steps.
     307    if (!resolvedFeatures)
     308        return false;
     309
     310    // 7. Let (consentRequired, consentOptional, granted) be the fields of result.
     311    // 8. The user agent MAY at this point ask the user's permission for the calling algorithm to use any of the features
     312    //    in consentRequired and consentOptional. The results of these prompts should be included when determining if there
     313    //    is a clear signal of user intent for enabling these features.
     314    // 9. For each feature in consentRequired perform the following steps:
     315    //  9.1. The user agent MAY at this point ask the user's permission for the calling algorithm to use feature. The results
     316    //       of these prompts should be included when determining if there is a clear signal of user intent to enable feature.
     317    //  9.2. If a clear signal of user intent to enable feature has not been determined, set status's state to "denied" and
     318    //       abort these steps.
     319    //  9.3. If feature is not in granted, append feature to granted.
     320    // 10. For each feature in consentOptional perform the following steps:
     321    //  10.1. The user agent MAY at this point ask the user's permission for the calling algorithm to use feature. The results
     322    //        of these prompts should be included when determining if there is a clear signal of user intent to enable feature.
     323    //  10.2. If a clear signal of user intent to enable feature has not been determined, continue to the next entry.
     324    //  10.3. If feature is not in granted, append feature to granted.
     325    // 11. Set status's granted to granted.
     326    // 12. Set device's list of enabled features for mode to granted.
     327    // 13. Set status's state to "granted".
     328    return true;
     329}
     330
     331
     332// https://immersive-web.github.io/webxr/#dom-xrsystem-requestsession
     333void WebXRSystem::requestSession(Document& document, XRSessionMode mode, const XRSessionInit& init, RequestSessionPromise&& promise)
     334{
     335    // 1. Let promise be a new Promise.
     336    // 2. Let immersive be true if mode is an immersive session mode, and false otherwise.
     337    // 3. Let global object be the relevant Global object for the XRSystem on which this method was invoked.
     338    bool immersive = mode == XRSessionMode::ImmersiveAr || mode == XRSessionMode::ImmersiveVr;
     339    auto* globalObject = document.domWindow();
     340    if (!globalObject) {
     341        promise.reject(Exception { InvalidAccessError});
     342        return;
     343    }
     344
     345    // 4. Check whether the session request is allowed as follows:
     346    if (immersive) {
     347        if (!immersiveSessionRequestIsAllowedForGlobalObject(*globalObject, document)) {
     348            promise.reject(Exception { SecurityError });
     349            return;
     350        }
     351        if (m_pendingImmersiveSession || m_activeImmersiveSession) {
     352            promise.reject(Exception { InvalidStateError });
     353            return;
     354        }
     355        m_pendingImmersiveSession = true;
     356    } else if (!inlineSessionRequestIsAllowedForGlobalObject(*globalObject, document, init)) {
     357        promise.reject(Exception { SecurityError });
     358        return;
     359    }
     360
     361    // 5. Run the following steps in parallel:
     362    queueTaskKeepingObjectAlive(*this, TaskSource::WebXR, [this, document = makeWeakPtr(document), immersive, init, mode, promise = WTFMove(promise)] () mutable {
     363        // 5.1 Let requiredFeatures be options' requiredFeatures.
     364        // 5.2 Let optionalFeatures be options' optionalFeatures.
     365        // 5.3 Set device to the result of obtaining the current device for mode, requiredFeatures, and optionalFeatures.
     366        auto* device = obtainCurrentDevice(mode, init.requiredFeatures, init.optionalFeatures);
     367
     368        // 5.4 Queue a task to perform the following steps:
     369        queueTaskKeepingObjectAlive(*this, TaskSource::WebXR, [this, document = WTFMove(document), device = makeWeakPtr(device), immersive, init, mode, promise = WTFMove(promise)] () mutable {
     370            auto rejectPromiseWithNotSupportedError = makeScopeExit([&] () {
     371                promise.reject(Exception { NotSupportedError });
     372                m_pendingImmersiveSession = false;
     373            });
     374
     375            // 5.4.1 If device is null or device's list of supported modes does not contain mode, run the following steps:
     376            //  - Reject promise with a "NotSupportedError" DOMException.
     377            //  - If immersive is true, set pending immersive session to false.
     378            //  - Abort these steps.
     379            if (!device || !device->supports(mode))
     380                return;
     381
     382            auto* globalObject = document ? document->execState() : nullptr;
     383            if (!globalObject)
     384                return;
     385
     386            // WebKit does not currently support the Permissions API. https://w3c.github.io/permissions/
     387            // However we do implement here the permission request algorithm without the
     388            // Permissions API bits as it handles, among others, the session features parsing. We also
     389            // do it here before creating the session as there is no need to do it on advance.
     390            // TODO: we just perform basic checks without asking any permission to the user so far. Maybe we should implement
     391            // a mechanism similar to what others do involving passing a message to the UI process.
     392
     393            // 5.4.4 Let descriptor be an XRPermissionDescriptor initialized with session, requiredFeatures, and optionalFeatures
     394            // 5.4.5 Let status be an XRPermissionStatus, initially null
     395            // 5.4.6 Request the xr permission with descriptor and status.
     396            // 5.4.7 If status' state is "denied" run the following steps: (same as above in 5.4.1)
     397            if (!isXRPermissionGranted(mode, init, device.get(), *globalObject))
     398                return;
     399
     400            // 5.4.2 Let session be a new XRSession object.
     401            // 5.4.3 Initialize the session with session, mode, and device.
     402            auto session = WebXRSession::create(*document, *this, mode, *device);
     403
     404            // 5.4.8 Potentially set the active immersive session as follows:
     405            if (immersive) {
     406                m_activeImmersiveSession = session.copyRef();
     407                m_pendingImmersiveSession = false;
     408            } else
     409                m_inlineSessions.add(session.copyRef());
     410
     411            // 5.4.9 Resolve promise with session.
     412            promise.resolve(session);
     413            rejectPromiseWithNotSupportedError.release();
     414
     415            // TODO:
     416            // 5.4.10 Queue a task to perform the following steps: NOTE: These steps ensure that initial inputsourceschange
     417            // events occur after the initial session is resolved.
     418            //     1. Set session's promise resolved flag to true.
     419            //     2. Let sources be any existing input sources attached to session.
     420            //     3. If sources is non-empty, perform the following steps:
     421            //        1. Set session's list of active XR input sources to sources.
     422            //        2. Fire an XRInputSourcesChangeEvent named inputsourceschange on session with added set to sources.
     423
     424        });
     425    });
    159426}
    160427
     
    168435}
    169436
    170 void WebXRSystem::registerSimulatedXRDeviceForTesting(const PlatformXR::Device& device)
     437void WebXRSystem::registerSimulatedXRDeviceForTesting(PlatformXR::Device& device)
    171438{
    172439    if (!RuntimeEnabledFeatures::sharedFeatures().webXREnabled())
    173440        return;
    174     m_testingMode = true;
     441    m_testingDevices++;
    175442    if (device.supports(PlatformXR::SessionMode::ImmersiveVr) || device.supports(PlatformXR::SessionMode::ImmersiveAr)) {
    176         m_immersiveDevices.append(makeWeakPtr(device));
    177         m_activeImmersiveDevice = m_immersiveDevices.last();
     443        m_immersiveDevices.add(device);
     444        m_activeImmersiveDevice = makeWeakPtr(device);
    178445    }
    179446    if (device.supports(PlatformXR::SessionMode::Inline))
     
    181448}
    182449
    183 void WebXRSystem::unregisterSimulatedXRDeviceForTesting(PlatformXR::Device* device)
     450void WebXRSystem::unregisterSimulatedXRDeviceForTesting(PlatformXR::Device& device)
    184451{
    185452    if (!RuntimeEnabledFeatures::sharedFeatures().webXREnabled())
    186453        return;
    187454    ASSERT(m_immersiveDevices.contains(device));
    188     m_immersiveDevices.removeFirst(device);
    189     if (m_activeImmersiveDevice == device)
     455    ASSERT(m_testingDevices);
     456    m_immersiveDevices.remove(device);
     457    if (m_activeImmersiveDevice == &device)
    190458        m_activeImmersiveDevice = nullptr;
    191     if (m_inlineXRDevice == device)
     459    if (m_inlineXRDevice == &device)
    192460        m_inlineXRDevice = makeWeakPtr(m_defaultInlineDevice);
    193     m_testingMode = false;
    194 }
    195 
     461    m_testingDevices--;
     462}
     463
     464void WebXRSystem::sessionEnded(WebXRSession& session)
     465{
     466    if (m_activeImmersiveSession == &session)
     467        m_activeImmersiveSession = nullptr;
     468
     469    m_inlineSessions.remove(session);
     470}
    196471
    197472} // namespace WebCore
  • trunk/Source/WebCore/Modules/webxr/WebXRSystem.h

    r261679 r261863  
    3434#include "WebGLContextAttributes.h"
    3535#include "WebGLRenderingContextBase.h"
     36#include "XRReferenceSpaceType.h"
    3637#include "XRSessionMode.h"
     38#include <wtf/HashSet.h>
    3739#include <wtf/IsoMalloc.h>
     40#include <wtf/Optional.h>
    3841#include <wtf/RefCounted.h>
     42#include <wtf/WeakHashSet.h>
    3943#include <wtf/WeakPtr.h>
     44
     45namespace JSC {
     46class JSGlobalObject;
     47}
    4048
    4149namespace WebCore {
    4250
     51class DOMWindow;
    4352class ScriptExecutionContext;
    4453class WebXRSession;
     
    5867
    5968    void isSessionSupported(XRSessionMode, IsSessionSupportedPromise&&);
    60     void requestSession(XRSessionMode, const XRSessionInit&, RequestSessionPromise&&);
     69    void requestSession(Document&, XRSessionMode, const XRSessionInit&, RequestSessionPromise&&);
    6170
    6271    // This is also needed by WebGLRenderingContextBase::makeXRCompatible() and HTMLCanvasElement::createContextWebGL().
     
    6473    bool hasActiveImmersiveXRDevice() { return !!m_activeImmersiveDevice; }
    6574
     75    void sessionEnded(WebXRSession&);
     76
    6677    // For testing purpouses only.
    67     void registerSimulatedXRDeviceForTesting(const PlatformXR::Device&);
    68     void unregisterSimulatedXRDeviceForTesting(PlatformXR::Device*);
     78    void registerSimulatedXRDeviceForTesting(PlatformXR::Device&);
     79    void unregisterSimulatedXRDeviceForTesting(PlatformXR::Device&);
    6980
    7081protected:
     
    8293    WebXRSystem(ScriptExecutionContext&);
    8394
     95    using FeaturesArray = PlatformXR::Device::ListOfEnabledFeatures;
     96    using JSFeaturesArray = Vector<JSC::JSValue>;
     97    PlatformXR::Device* obtainCurrentDevice(XRSessionMode, const JSFeaturesArray& requiredFeatures, const JSFeaturesArray& optionalFeatures);
     98
     99    bool immersiveSessionRequestIsAllowedForGlobalObject(DOMWindow&, Document&) const;
     100    bool inlineSessionRequestIsAllowedForGlobalObject(DOMWindow&, Document&, const XRSessionInit&) const;
     101
     102    struct ResolvedRequestedFeatures;
     103    Optional<ResolvedRequestedFeatures> resolveRequestedFeatures(XRSessionMode, const XRSessionInit&, PlatformXR::Device*, JSC::JSGlobalObject&) const;
     104    bool isXRPermissionGranted(XRSessionMode, const XRSessionInit&, PlatformXR::Device*, JSC::JSGlobalObject&) const;
     105
    84106    // https://immersive-web.github.io/webxr/#default-inline-xr-device
    85107    class DummyInlineDevice final : public PlatformXR::Device {
    86108    public:
    87         DummyInlineDevice()
    88         {
    89             m_supportedModes.append(XRSessionMode::Inline);
    90         }
     109        DummyInlineDevice();
    91110    };
    92111    DummyInlineDevice m_defaultInlineDevice;
    93112
    94113    bool m_immersiveXRDevicesHaveBeenEnumerated { false };
    95     bool m_testingMode { false };
     114    uint m_testingDevices { 0 };
    96115
    97     WeakPtr<WebXRSession> m_activeImmersiveSession;
     116    bool m_pendingImmersiveSession { false };
     117    RefPtr<WebXRSession> m_activeImmersiveSession;
     118
     119    // We use a set here although the specs talk about a list of inline sessions
     120    // https://immersive-web.github.io/webxr/#list-of-inline-sessions.
     121    HashSet<Ref<WebXRSession>> m_inlineSessions;
    98122
    99123    WeakPtr<PlatformXR::Device> m_activeImmersiveDevice;
    100     Vector<WeakPtr<PlatformXR::Device>> m_immersiveDevices;
     124    WeakHashSet<PlatformXR::Device> m_immersiveDevices;
    101125    WeakPtr<PlatformXR::Device> m_inlineXRDevice;
    102126};
  • trunk/Source/WebCore/Modules/webxr/WebXRSystem.idl

    r260385 r261863  
    3434    // Methods
    3535    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);
    3737
    3838    // Events
  • trunk/Source/WebCore/dom/TaskSource.h

    r259130 r261863  
    4040    UserInteraction,
    4141    WebGL,
     42    WebXR,
    4243
    4344    // Internal to WebCore
  • trunk/Source/WebCore/platform/xr/PlatformXR.h

    r261220 r261863  
    2020
    2121#include <memory>
     22#include <wtf/HashMap.h>
    2223#include <wtf/Vector.h>
    2324#include <wtf/WeakPtr.h>
     
    2526namespace PlatformXR {
    2627
    27 enum class SessionMode {
     28enum class SessionMode : uint8_t {
    2829    Inline,
    2930    ImmersiveVr,
     
    4950    DeviceId id() const { return m_id; }
    5051
    51     using ListOfSupportedModes = Vector<SessionMode>;
    5252    using ListOfEnabledFeatures = Vector<ReferenceSpaceType>;
    53 
    54     bool supports(SessionMode mode) const { return m_supportedModes.contains(mode); }
    55     void setSupportedModes(const ListOfSupportedModes& modes) { m_supportedModes = modes; }
    56     void setEnabledFeatures(const ListOfEnabledFeatures& features) { m_enabledFeatures = features; }
     53    bool supports(SessionMode mode) const { return m_enabledFeaturesMap.contains(mode); }
     54    void setEnabledFeatures(SessionMode mode, const ListOfEnabledFeatures& features) { m_enabledFeaturesMap.set(mode, features); }
     55    ListOfEnabledFeatures enabledFeatures(SessionMode mode) const { return m_enabledFeaturesMap.get(mode); }
    5756
    5857    inline bool operator==(const Device& other) const { return m_id == other.m_id; }
    5958
    6059protected:
    61     ListOfSupportedModes m_supportedModes;
    62     ListOfEnabledFeatures m_enabledFeatures;
     60    // https://immersive-web.github.io/webxr/#xr-device-concept
     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;
    6365
    6466private:
  • trunk/Source/WebCore/platform/xr/openxr/PlatformXR.cpp

    r261220 r261863  
    2525#if USE_OPENXR
    2626#include <openxr/openxr.h>
     27#include <wtf/Optional.h>
    2728#include <wtf/text/StringConcatenateNumbers.h>
    2829#include <wtf/text/WTFString.h>
     
    6869
    6970#if USE_OPENXR
    70     void collectSupportedSessionModes(Device&, XrSystemId);
     71    Optional<Vector<SessionMode>> collectSupportedSessionModes(Device&, XrSystemId);
    7172    XrInstance m_instance { XR_NULL_HANDLE };
    7273#endif // USE_OPENXR
     
    151152#if USE_OPENXR
    152153
    153 void Instance::Impl::collectSupportedSessionModes(Device& device, XrSystemId systemId)
     154Optional<Vector<SessionMode>> Instance::Impl::collectSupportedSessionModes(Device& device, XrSystemId systemId)
    154155{
    155156    uint32_t viewConfigurationCount;
     
    157158    if (result != XR_SUCCESS) {
    158159        WTFLogAlways("xrEnumerateViewConfigurations(): error %s\n", resultToString(result, m_instance).utf8().data());
    159         return;
     160        return WTF::nullopt;
    160161    }
    161162
     
    165166        WTFLogAlways("xrEnumerateViewConfigurations(): error %s\n", resultToString(result, m_instance).utf8().data());
    166167        WTFLogAlways("xrEnumerateViewConfigurations(): error %s\n", resultToString(result, m_instance).utf8().data());
    167         return;
    168     }
    169 
    170     Device::ListOfSupportedModes supportedModes;
     168        return WTF::nullopt;
     169    }
     170
     171    Vector<SessionMode> supportedModes;
    171172    for (uint32_t i = 0; i < viewConfigurationCount; ++i) {
    172173        auto viewConfigurationProperties = createStructure<XrViewConfigurationProperties, XR_TYPE_VIEW_CONFIGURATION_PROPERTIES>();
     
    174175        if (result != XR_SUCCESS) {
    175176            WTFLogAlways("xrGetViewConfigurationProperties(): error %s\n", resultToString(result, m_instance).utf8().data());
    176             return;
     177            return WTF::nullopt;
    177178        }
    178179        if (viewConfigurationProperties.viewConfigurationType == XR_VIEW_CONFIGURATION_TYPE_PRIMARY_MONO)
     
    181182            supportedModes.append(SessionMode::ImmersiveVr);
    182183    }
    183     device.setSupportedModes(supportedModes);
     184    return supportedModes;
    184185}
    185186
     
    219220
    220221    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
    222230    m_immersiveXRDevices.append(WTFMove(device));
    223231#endif // USE_OPENXR
  • trunk/Source/WebCore/testing/WebXRTest.cpp

    r261273 r261863  
    5555        }
    5656
     57        Vector<XRReferenceSpaceType> features;
    5758        if (init.supportedFeatures) {
    58             Vector<XRReferenceSpaceType> features;
    59             for (auto& feature : init.supportedFeatures.value()) {
    60                 if (auto referenceSpaceType = parseEnumeration<XRReferenceSpaceType>(*context.execState(), feature))
    61                     features.append(referenceSpaceType.value());
     59            if (auto* globalObject = context.execState()) {
     60                for (auto& feature : init.supportedFeatures.value()) {
     61                    if (auto referenceSpaceType = parseEnumeration<XRReferenceSpaceType>(*globalObject, feature))
     62                        features.append(referenceSpaceType.value());
     63                }
    6264            }
    63             simulatedDevice.setEnabledFeatures(features);
    6465        }
    6566
     
    8889                supportedModes.append(XRSessionMode::ImmersiveVr);
    8990        }
    90         simulatedDevice.setSupportedModes(supportedModes);
     91
     92        for (auto& mode : supportedModes)
     93            simulatedDevice.setEnabledFeatures(mode, features);
    9194
    9295        m_context->registerSimulatedXRDeviceForTesting(simulatedDevice);
     
    108111{
    109112    for (auto& device : m_devices)
    110         m_context->unregisterSimulatedXRDeviceForTesting(&device->simulatedXRDevice());
     113        m_context->unregisterSimulatedXRDeviceForTesting(device->simulatedXRDevice());
    111114    promise.resolve();
    112115}
Note: See TracChangeset for help on using the changeset viewer.