Changeset 261863 in webkit
- Timestamp:
- May 19, 2020 9:08:47 AM (4 years ago)
- Location:
- trunk
- Files:
-
- 8 added
- 16 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r261861 r261863 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 Youenn Fablet. 7 8 * platform/wpe/TestExpectations: Added several previously skipped tests 9 that are now passing. 10 1 11 2020-05-19 Antti Koivisto <antti@apple.com> 2 12 -
trunk/LayoutTests/imported/w3c/ChangeLog
r261859 r261863 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 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 1 17 2020-05-19 Carlos Alberto Lopez Perez <clopez@igalia.com> 2 18 -
trunk/LayoutTests/platform/wpe/TestExpectations
r261859 r261863 1017 1017 webkit.org/b/209859 imported/w3c/web-platform-tests/webxr/xrDevice_isSessionSupported_immersive.https.html [ Pass ] 1018 1018 webkit.org/b/209859 imported/w3c/web-platform-tests/webxr/xrDevice_isSessionSupported_immersive_unsupported.https.html [ Pass ] 1019 webkit.org/b/209859 imported/w3c/web-platform-tests/webxr/xrDevice_requestSession_immersive.https.html [ Pass ] 1020 webkit.org/b/209859 imported/w3c/web-platform-tests/webxr/xrDevice_requestSession_immersive_no_gesture.https.html [ Pass ] 1021 webkit.org/b/209859 imported/w3c/web-platform-tests/webxr/xrDevice_requestSession_immersive_unsupported.https.html [ Pass ] 1022 webkit.org/b/209859 imported/w3c/web-platform-tests/webxr/xrDevice_requestSession_no_mode.https.html [ Pass ] 1023 webkit.org/b/209859 imported/w3c/web-platform-tests/webxr/xrDevice_requestSession_non_immersive_no_gesture.https.html [ Pass ] 1024 webkit.org/b/209859 imported/w3c/web-platform-tests/webxr/xrDevice_requestSession_optionalFeatures.https.html [ Pass ] 1025 webkit.org/b/209859 imported/w3c/web-platform-tests/webxr/xrDevice_requestSession_requiredFeatures_unknown.https.html [ Pass ] 1026 webkit.org/b/209859 imported/w3c/web-platform-tests/webxr/xrSession_features_deviceSupport.https.html [ Pass ] 1019 1027 1020 1028 # Passing since r259006. -
trunk/Source/WebCore/ChangeLog
r261861 r261863 1 2020-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 1 65 2020-05-19 Antti Koivisto <antti@apple.com> 2 66 -
trunk/Source/WebCore/Modules/webxr/WebXRInputSourceArray.h
r258498 r261863 40 40 unsigned length() const; 41 41 WebXRInputSource* item(unsigned) const; 42 43 private: 44 WebXRInputSourceArray(); 42 45 }; 43 46 -
trunk/Source/WebCore/Modules/webxr/WebXRRenderState.cpp
r258498 r261863 38 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: 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)); 60 45 } 61 46 -
trunk/Source/WebCore/Modules/webxr/WebXRRenderState.h
r258498 r261863 28 28 #if ENABLE(WEBXR) 29 29 30 #include "XRSessionMode.h" 30 31 #include <wtf/IsoMalloc.h> 31 32 #include <wtf/Optional.h> … … 38 39 class WebXRWebGLLayer; 39 40 struct XRRenderStateInit; 40 class WebXRSession;41 41 42 42 class WebXRRenderState : public RefCounted<WebXRRenderState> { 43 43 WTF_MAKE_ISO_ALLOCATED(WebXRRenderState); 44 44 public: 45 static Ref<WebXRRenderState> create( const WebXRSession&);45 static Ref<WebXRRenderState> create(XRSessionMode); 46 46 ~WebXRRenderState(); 47 47 … … 52 52 53 53 private: 54 WebXRRenderState(Optional<double>&&);55 WebXRRenderState(const XRRenderStateInit&);54 explicit WebXRRenderState(Optional<double>&& fieldOfView); 55 explicit WebXRRenderState(const XRRenderStateInit&); 56 56 57 // https://immersive-web.github.io/webxr/#initialize-the-render-state 57 58 struct { 58 double near { 0.1 }; 59 double far { 1000 }; 59 double near { 0.1 }; // in meters 60 double far { 1000 }; // in meters 60 61 } m_depth; 61 Optional<double> m_inlineVerticalFieldOfView; 62 Optional<double> m_inlineVerticalFieldOfView; // in radians 62 63 RefPtr<WebXRWebGLLayer> m_baseLayer; 63 64 }; -
trunk/Source/WebCore/Modules/webxr/WebXRSession.cpp
r258498 r261863 29 29 #if ENABLE(WEBXR) 30 30 31 #include "WebXRSystem.h" 31 32 #include <wtf/IsoMallocInlines.h> 32 33 … … 34 35 35 36 WTF_MAKE_ISO_ALLOCATED_IMPL(WebXRSession); 37 38 Ref<WebXRSession> WebXRSession::create(Document& document, WebXRSystem& system, XRSessionMode mode, PlatformXR::Device& device) 39 { 40 return adoptRef(*new WebXRSession(document, system, mode, device)); 41 } 42 43 WebXRSession::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 } 36 55 37 56 WebXRSession::~WebXRSession() = default; … … 49 68 const WebXRRenderState& WebXRSession::renderState() const 50 69 { 51 return *m_ renderState;70 return *m_activeRenderState; 52 71 } 53 72 … … 74 93 } 75 94 76 void WebXRSession::end(EndPromise&&) 95 // https://immersive-web.github.io/webxr/#shut-down-the-session 96 void WebXRSession::shutdown() 77 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) 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. 78 133 } 79 134 -
trunk/Source/WebCore/Modules/webxr/WebXRSession.h
r260415 r261863 36 36 #include "XREnvironmentBlendMode.h" 37 37 #include "XRReferenceSpaceType.h" 38 #include "XRSessionMode.h" 38 39 #include "XRVisibilityState.h" 39 40 #include <wtf/Ref.h> … … 46 47 class XRFrameRequestCallback; 47 48 class WebXRReferenceSpace; 49 class WebXRSystem; 48 50 struct XRRenderStateInit; 49 51 … … 54 56 using EndPromise = DOMPromiseDeferred<void>; 55 57 58 static Ref<WebXRSession> create(Document&, WebXRSystem&, XRSessionMode, PlatformXR::Device&); 56 59 virtual ~WebXRSession(); 57 60 … … 75 78 76 79 private: 80 WebXRSession(Document&, WebXRSystem&, XRSessionMode, PlatformXR::Device&); 81 77 82 // EventTarget 78 83 EventTargetInterface eventTargetInterface() const override { return WebXRSessionEventTargetInterfaceType; } … … 85 90 void stop() override; 86 91 92 void shutdown(); 93 87 94 XREnvironmentBlendMode m_environmentBlendMode; 88 95 XRVisibilityState m_visibilityState; 89 RefPtr<WebXRRenderState> m_renderState;90 96 RefPtr<WebXRInputSourceArray> m_inputSources; 91 97 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; 92 104 }; 93 105 -
trunk/Source/WebCore/Modules/webxr/WebXRSystem.cpp
r261220 r261863 29 29 #if ENABLE(WEBXR) 30 30 31 #include "DOMWindow.h" 31 32 #include "Document.h" 32 33 #include "FeaturePolicy.h" 34 #include "IDLTypes.h" 35 #include "JSWebXRSession.h" 36 #include "JSXRReferenceSpaceType.h" 33 37 #include "PlatformXR.h" 34 38 #include "RuntimeEnabledFeatures.h" 39 #include "SecurityOrigin.h" 40 #include "UserGestureIndicator.h" 35 41 #include "WebXRSession.h" 42 #include "XRReferenceSpaceType.h" 43 #include "XRSessionInit.h" 44 #include <JavaScriptCore/JSGlobalObject.h> 36 45 #include <wtf/IsoMallocInlines.h> 46 #include <wtf/Scope.h> 37 47 38 48 namespace WebCore { 39 49 40 50 WTF_MAKE_ISO_ALLOCATED_IMPL(WebXRSystem); 51 52 WebXRSystem::DummyInlineDevice::DummyInlineDevice() 53 { 54 setEnabledFeatures(XRSessionMode::Inline, { XRReferenceSpaceType::Viewer }); 55 } 41 56 42 57 Ref<WebXRSystem> WebXRSystem::create(ScriptExecutionContext& scriptExecutionContext) … … 57 72 { 58 73 // 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)) 61 75 return; 62 76 … … 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 127 // https://immersive-web.github.io/webxr/#dom-xrsystem-issessionsupported 100 128 void WebXRSystem::isSessionSupported(XRSessionMode mode, IsSessionSupportedPromise&& promise) … … 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 138 // reject promise with a "SecurityError" DOMException and return it. 111 139 auto document = downcast<Document>(scriptExecutionContext()); … … 137 165 } 138 166 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 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 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 294 bool 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 333 void 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 }); 159 426 } 160 427 … … 168 435 } 169 436 170 void WebXRSystem::registerSimulatedXRDeviceForTesting( constPlatformXR::Device& device)437 void WebXRSystem::registerSimulatedXRDeviceForTesting(PlatformXR::Device& device) 171 438 { 172 439 if (!RuntimeEnabledFeatures::sharedFeatures().webXREnabled()) 173 440 return; 174 m_testing Mode = true;441 m_testingDevices++; 175 442 if (device.supports(PlatformXR::SessionMode::ImmersiveVr) || device.supports(PlatformXR::SessionMode::ImmersiveAr)) { 176 m_immersiveDevices.a ppend(makeWeakPtr(device));177 m_activeImmersiveDevice = m _immersiveDevices.last();443 m_immersiveDevices.add(device); 444 m_activeImmersiveDevice = makeWeakPtr(device); 178 445 } 179 446 if (device.supports(PlatformXR::SessionMode::Inline)) … … 181 448 } 182 449 183 void WebXRSystem::unregisterSimulatedXRDeviceForTesting(PlatformXR::Device *device)450 void WebXRSystem::unregisterSimulatedXRDeviceForTesting(PlatformXR::Device& device) 184 451 { 185 452 if (!RuntimeEnabledFeatures::sharedFeatures().webXREnabled()) 186 453 return; 187 454 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) 190 458 m_activeImmersiveDevice = nullptr; 191 if (m_inlineXRDevice == device)459 if (m_inlineXRDevice == &device) 192 460 m_inlineXRDevice = makeWeakPtr(m_defaultInlineDevice); 193 m_testingMode = false; 194 } 195 461 m_testingDevices--; 462 } 463 464 void WebXRSystem::sessionEnded(WebXRSession& session) 465 { 466 if (m_activeImmersiveSession == &session) 467 m_activeImmersiveSession = nullptr; 468 469 m_inlineSessions.remove(session); 470 } 196 471 197 472 } // namespace WebCore -
trunk/Source/WebCore/Modules/webxr/WebXRSystem.h
r261679 r261863 34 34 #include "WebGLContextAttributes.h" 35 35 #include "WebGLRenderingContextBase.h" 36 #include "XRReferenceSpaceType.h" 36 37 #include "XRSessionMode.h" 38 #include <wtf/HashSet.h> 37 39 #include <wtf/IsoMalloc.h> 40 #include <wtf/Optional.h> 38 41 #include <wtf/RefCounted.h> 42 #include <wtf/WeakHashSet.h> 39 43 #include <wtf/WeakPtr.h> 44 45 namespace JSC { 46 class JSGlobalObject; 47 } 40 48 41 49 namespace WebCore { 42 50 51 class DOMWindow; 43 52 class ScriptExecutionContext; 44 53 class WebXRSession; … … 58 67 59 68 void isSessionSupported(XRSessionMode, IsSessionSupportedPromise&&); 60 void requestSession( XRSessionMode, const XRSessionInit&, RequestSessionPromise&&);69 void requestSession(Document&, XRSessionMode, const XRSessionInit&, RequestSessionPromise&&); 61 70 62 71 // This is also needed by WebGLRenderingContextBase::makeXRCompatible() and HTMLCanvasElement::createContextWebGL(). … … 64 73 bool hasActiveImmersiveXRDevice() { return !!m_activeImmersiveDevice; } 65 74 75 void sessionEnded(WebXRSession&); 76 66 77 // For testing purpouses only. 67 void registerSimulatedXRDeviceForTesting( constPlatformXR::Device&);68 void unregisterSimulatedXRDeviceForTesting(PlatformXR::Device *);78 void registerSimulatedXRDeviceForTesting(PlatformXR::Device&); 79 void unregisterSimulatedXRDeviceForTesting(PlatformXR::Device&); 69 80 70 81 protected: … … 82 93 WebXRSystem(ScriptExecutionContext&); 83 94 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 84 106 // https://immersive-web.github.io/webxr/#default-inline-xr-device 85 107 class DummyInlineDevice final : public PlatformXR::Device { 86 108 public: 87 DummyInlineDevice() 88 { 89 m_supportedModes.append(XRSessionMode::Inline); 90 } 109 DummyInlineDevice(); 91 110 }; 92 111 DummyInlineDevice m_defaultInlineDevice; 93 112 94 113 bool m_immersiveXRDevicesHaveBeenEnumerated { false }; 95 bool m_testingMode { false};114 uint m_testingDevices { 0 }; 96 115 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; 98 122 99 123 WeakPtr<PlatformXR::Device> m_activeImmersiveDevice; 100 Vector<WeakPtr<PlatformXR::Device>> m_immersiveDevices;124 WeakHashSet<PlatformXR::Device> m_immersiveDevices; 101 125 WeakPtr<PlatformXR::Device> m_inlineXRDevice; 102 126 }; -
trunk/Source/WebCore/Modules/webxr/WebXRSystem.idl
r260385 r261863 34 34 // Methods 35 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 38 // Events -
trunk/Source/WebCore/dom/TaskSource.h
r259130 r261863 40 40 UserInteraction, 41 41 WebGL, 42 WebXR, 42 43 43 44 // Internal to WebCore -
trunk/Source/WebCore/platform/xr/PlatformXR.h
r261220 r261863 20 20 21 21 #include <memory> 22 #include <wtf/HashMap.h> 22 23 #include <wtf/Vector.h> 23 24 #include <wtf/WeakPtr.h> … … 25 26 namespace PlatformXR { 26 27 27 enum class SessionMode {28 enum class SessionMode : uint8_t { 28 29 Inline, 29 30 ImmersiveVr, … … 49 50 DeviceId id() const { return m_id; } 50 51 51 using ListOfSupportedModes = Vector<SessionMode>;52 52 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); } 57 56 58 57 inline bool operator==(const Device& other) const { return m_id == other.m_id; } 59 58 60 59 protected: 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; 63 65 64 66 private: -
trunk/Source/WebCore/platform/xr/openxr/PlatformXR.cpp
r261220 r261863 25 25 #if USE_OPENXR 26 26 #include <openxr/openxr.h> 27 #include <wtf/Optional.h> 27 28 #include <wtf/text/StringConcatenateNumbers.h> 28 29 #include <wtf/text/WTFString.h> … … 68 69 69 70 #if USE_OPENXR 70 voidcollectSupportedSessionModes(Device&, XrSystemId);71 Optional<Vector<SessionMode>> collectSupportedSessionModes(Device&, XrSystemId); 71 72 XrInstance m_instance { XR_NULL_HANDLE }; 72 73 #endif // USE_OPENXR … … 151 152 #if USE_OPENXR 152 153 153 voidInstance::Impl::collectSupportedSessionModes(Device& device, XrSystemId systemId)154 Optional<Vector<SessionMode>> Instance::Impl::collectSupportedSessionModes(Device& device, XrSystemId systemId) 154 155 { 155 156 uint32_t viewConfigurationCount; … … 157 158 if (result != XR_SUCCESS) { 158 159 WTFLogAlways("xrEnumerateViewConfigurations(): error %s\n", resultToString(result, m_instance).utf8().data()); 159 return ;160 return WTF::nullopt; 160 161 } 161 162 … … 165 166 WTFLogAlways("xrEnumerateViewConfigurations(): error %s\n", resultToString(result, m_instance).utf8().data()); 166 167 WTFLogAlways("xrEnumerateViewConfigurations(): error %s\n", resultToString(result, m_instance).utf8().data()); 167 return ;168 } 169 170 Device::ListOfSupportedModessupportedModes;168 return WTF::nullopt; 169 } 170 171 Vector<SessionMode> supportedModes; 171 172 for (uint32_t i = 0; i < viewConfigurationCount; ++i) { 172 173 auto viewConfigurationProperties = createStructure<XrViewConfigurationProperties, XR_TYPE_VIEW_CONFIGURATION_PROPERTIES>(); … … 174 175 if (result != XR_SUCCESS) { 175 176 WTFLogAlways("xrGetViewConfigurationProperties(): error %s\n", resultToString(result, m_instance).utf8().data()); 176 return ;177 return WTF::nullopt; 177 178 } 178 179 if (viewConfigurationProperties.viewConfigurationType == XR_VIEW_CONFIGURATION_TYPE_PRIMARY_MONO) … … 181 182 supportedModes.append(SessionMode::ImmersiveVr); 182 183 } 183 device.setSupportedModes(supportedModes);184 return supportedModes; 184 185 } 185 186 … … 219 220 220 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 230 m_immersiveXRDevices.append(WTFMove(device)); 223 231 #endif // USE_OPENXR -
trunk/Source/WebCore/testing/WebXRTest.cpp
r261273 r261863 55 55 } 56 56 57 Vector<XRReferenceSpaceType> features; 57 58 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 } 62 64 } 63 simulatedDevice.setEnabledFeatures(features);64 65 } 65 66 … … 88 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 95 m_context->registerSimulatedXRDeviceForTesting(simulatedDevice); … … 108 111 { 109 112 for (auto& device : m_devices) 110 m_context->unregisterSimulatedXRDeviceForTesting( &device->simulatedXRDevice());113 m_context->unregisterSimulatedXRDeviceForTesting(device->simulatedXRDevice()); 111 114 promise.resolve(); 112 115 }
Note: See TracChangeset
for help on using the changeset viewer.