Title: [276433] trunk
Revision
276433
Author
[email protected]
Date
2021-04-22 07:06:06 -0700 (Thu, 22 Apr 2021)

Log Message

Implement WebXR Input Sources
https://bugs.webkit.org/show_bug.cgi?id=223257

Reviewed by Youenn Fablet.

.:

Enable WPE Gamepad when WebXR is enabled.

* Source/cmake/OptionsWPE.cmake:

LayoutTests/imported/w3c:

Update WebXR Input Source test expectations.

* web-platform-tests/webxr/events_input_source_recreation.https-expected.txt: Added.
* web-platform-tests/webxr/events_input_sources_change.https-expected.txt: Added.
* web-platform-tests/webxr/events_session_select.https-expected.txt: Added.
* web-platform-tests/webxr/events_session_select_subframe.https-expected.txt: Added.
* web-platform-tests/webxr/events_session_squeeze.https-expected.txt: Added.
* web-platform-tests/webxr/getInputPose_handedness.https-expected.txt: Added.
* web-platform-tests/webxr/xrInputSource_add_remove.https-expected.txt: Added.
* web-platform-tests/webxr/xrInputSource_emulatedPosition.https-expected.txt: Added.
* web-platform-tests/webxr/xrInputSource_profiles.https-expected.txt: Added.
* web-platform-tests/webxr/xrInputSource_sameObject.https-expected.txt: Added.
* web-platform-tests/webxr/xrReferenceSpace_originOffset.https-expected.txt: Added.

Source/WebCore:

This patch implements the platform data definition and the DOM bits required to support WebXR Input Sources, the input mechanism used in WebXR.
Example XR input sources include, but are not limited to, handheld controllers, optically tracked hands, and gaze-based input methods.

More info about the API in:
- https://immersive-web.github.io/webxr/#input
- https://immersive-web.github.io/webxr-gamepads-module/#webxr-device-api-integration

Tested by WebXR WPT.

* Modules/gamepad/Gamepad.h: Add setConnected method.

* Modules/webxr/WebXRGamepad.cpp: Bridge between WebXRInputSource and Gamepad
(WebCore::WebXRGamepad::WebXRGamepad):
* Modules/webxr/WebXRGamepad.h:

* Modules/webxr/WebXRInputSpace.cpp: Instance of WebXRSpace used for WebXRInputSource spaces.
(WebCore::WebXRInputSpace::create):
(WebCore::WebXRInputSpace::WebXRInputSpace):
(WebCore::WebXRInputSpace::nativeOrigin const):
* Modules/webxr/WebXRInputSpace.h:

* Modules/webxr/WebXRFrame.cpp:
(WebCore::WebXRFrame::populatePose): set emulatedPosition based on the spaces.

* Modules/webxr/WebXRInputSource.cpp: Complete WebXRInputSource implementation.
(WebCore::WebXRInputSpace::create):
(WebCore::WebXRInputSpace::WebXRInputSpace):
(WebCore::WebXRInputSpace::nativeOrigin const):
(WebCore::WebXRInputSource::create):
(WebCore::WebXRInputSource::WebXRInputSource):
(WebCore::WebXRInputSource::update):
(WebCore::WebXRInputSource::requiresInputSourceChange):
(WebCore::WebXRInputSource::disconnect):
(WebCore::WebXRInputSource::pollEvents):
(WebCore::WebXRInputSource::createEvent):
* Modules/webxr/WebXRInputSource.h:
(WebCore::WebXRInputSource::handle const):
(WebCore::WebXRInputSource::handedness const):
(WebCore::WebXRInputSource::targetRayMode const):
(WebCore::WebXRInputSource::targetRaySpace const):
(WebCore::WebXRInputSource::gripSpace const):
(WebCore::WebXRInputSource::profiles const):
(WebCore::WebXRInputSource::gamepad const):

* Modules/webxr/WebXRInputSource.idl: Add gamepad attribute.

* Modules/webxr/WebXRInputSourceArray.cpp: Implement input source updates and event dispatching.
(WebCore::WebXRInputSourceArray::create):
(WebCore::WebXRInputSourceArray::WebXRInputSourceArray):
(WebCore::WebXRInputSourceArray::length const):
(WebCore::WebXRInputSourceArray::item const):
(WebCore::WebXRInputSourceArray::clear):
(WebCore::WebXRInputSourceArray::update):
(WebCore::WebXRInputSourceArray::handleRemovedInputSources):
(WebCore::WebXRInputSourceArray::handleAddedOrUpdatedInputSources):
* Modules/webxr/WebXRInputSourceArray.h:

* Modules/webxr/WebXRSession.cpp:
(WebCore::WebXRSession::WebXRSession): Set tracking delegate before initializing tracking and rendering.
(WebCore::WebXRSession::isPositionEmulated const): Add helper method.
(WebCore::WebXRSession::shutdown): Clear WebXRInputSourceArray instance.
(WebCore::WebXRSession::sessionDidInitializeInputSources): Dispatch initial InputSource discovery event.
(WebCore::WebXRSession::onFrame): Update WebXRInputSourceArray instance.
* Modules/webxr/WebXRSession.h:

* Modules/webxr/WebXRSpace.cpp: Add virtual class isPositionEmulated to be used in WebXRFrame.
(WebCore::WebXRSpace::isPositionEmulated const):
* Modules/webxr/WebXRSpace.h:

* Modules/webxr/WebXRSystem.cpp:
(WebCore::WebXRSystem::requestSession): update FIXME comment.

* Modules/webxr/XRHandedness.h: Reuse PlatformXR enum.

* Modules/webxr/XRInputSourceEvent.cpp:
(WebCore::XRInputSourceEvent::XRInputSourceEvent):
(WebCore::XRInputSourceEvent::setFrameActive):
* Modules/webxr/XRInputSourceEvent.h:

* Modules/webxr/XRInputSourcesChangeEvent.h:

* Modules/webxr/XRTargetRayMode.h: Reuse PlatformXR enum.

* platform/gamepad/GamepadConstants.cpp:
(WebCore::xrStandardGamepadMappingString): Add xr-standard gamepad mapping name.
* platform/gamepad/GamepadConstants.h:

* platform/xr/PlatformXR.h: Add Input Source frame data.

* testing/WebFakeXRDevice.cpp: Implement required changes to run and pass WebXR Input Source tests.
(WebCore::SimulatedXRDevice::initializeTrackingAndRendering):
(WebCore::SimulatedXRDevice::frameTimerFired):
(WebCore::WebFakeXRDevice::simulateResetPose):
(WebCore::WebFakeXRDevice::simulateInputSourceConnection):
* testing/WebFakeXRDevice.h:
* testing/WebFakeXRInputController.cpp:
(WebCore::WebFakeXRInputController::create):
(WebCore::WebFakeXRInputController::WebFakeXRInputController):
(WebCore::WebFakeXRInputController::setGripOrigin):
(WebCore::WebFakeXRInputController::setPointerOrigin):
(WebCore::WebFakeXRInputController::disconnect):
(WebCore::WebFakeXRInputController::reconnect):
(WebCore::WebFakeXRInputController::setSupportedButtons):
(WebCore::WebFakeXRInputController::updateButtonState):
(WebCore::WebFakeXRInputController::getFrameData):
(WebCore::WebFakeXRInputController::getButtonOrPlaceholder const):
* testing/WebFakeXRInputController.h:

LayoutTests:

Update WebXR Input Source test expectations.

* platform/wpe/TestExpectations:

Modified Paths

Added Paths

Diff

Modified: trunk/ChangeLog (276432 => 276433)


--- trunk/ChangeLog	2021-04-22 12:18:47 UTC (rev 276432)
+++ trunk/ChangeLog	2021-04-22 14:06:06 UTC (rev 276433)
@@ -1,3 +1,14 @@
+2021-04-22  Imanol Fernandez  <[email protected]>
+
+        Implement WebXR Input Sources
+        https://bugs.webkit.org/show_bug.cgi?id=223257
+
+        Reviewed by Youenn Fablet.
+
+        Enable WPE Gamepad when WebXR is enabled.
+
+        * Source/cmake/OptionsWPE.cmake:
+
 2021-04-22  Carlos Garcia Campos  <[email protected]>
 
         [SOUP] Add support for preconnect

Modified: trunk/LayoutTests/ChangeLog (276432 => 276433)


--- trunk/LayoutTests/ChangeLog	2021-04-22 12:18:47 UTC (rev 276432)
+++ trunk/LayoutTests/ChangeLog	2021-04-22 14:06:06 UTC (rev 276433)
@@ -1,3 +1,14 @@
+2021-04-22  Imanol Fernandez  <[email protected]>
+
+        Implement WebXR Input Sources
+        https://bugs.webkit.org/show_bug.cgi?id=223257
+
+        Reviewed by Youenn Fablet.
+
+        Update WebXR Input Source test expectations.
+
+        * platform/wpe/TestExpectations:
+
 2021-04-22  Carlos Garcia Campos  <[email protected]>
 
         [SOUP] Add support for preconnect

Modified: trunk/LayoutTests/imported/w3c/ChangeLog (276432 => 276433)


--- trunk/LayoutTests/imported/w3c/ChangeLog	2021-04-22 12:18:47 UTC (rev 276432)
+++ trunk/LayoutTests/imported/w3c/ChangeLog	2021-04-22 14:06:06 UTC (rev 276433)
@@ -1,3 +1,24 @@
+2021-04-22  Imanol Fernandez  <[email protected]>
+
+        Implement WebXR Input Sources
+        https://bugs.webkit.org/show_bug.cgi?id=223257
+
+        Reviewed by Youenn Fablet.
+
+        Update WebXR Input Source test expectations.
+
+        * web-platform-tests/webxr/events_input_source_recreation.https-expected.txt: Added.
+        * web-platform-tests/webxr/events_input_sources_change.https-expected.txt: Added.
+        * web-platform-tests/webxr/events_session_select.https-expected.txt: Added.
+        * web-platform-tests/webxr/events_session_select_subframe.https-expected.txt: Added.
+        * web-platform-tests/webxr/events_session_squeeze.https-expected.txt: Added.
+        * web-platform-tests/webxr/getInputPose_handedness.https-expected.txt: Added.
+        * web-platform-tests/webxr/xrInputSource_add_remove.https-expected.txt: Added.
+        * web-platform-tests/webxr/xrInputSource_emulatedPosition.https-expected.txt: Added.
+        * web-platform-tests/webxr/xrInputSource_profiles.https-expected.txt: Added.
+        * web-platform-tests/webxr/xrInputSource_sameObject.https-expected.txt: Added.
+        * web-platform-tests/webxr/xrReferenceSpace_originOffset.https-expected.txt: Added.
+
 2021-04-21  Tim Nguyen  <[email protected]>
 
         Import css/css-will-change tests from WPT

Added: trunk/LayoutTests/imported/w3c/web-platform-tests/webxr/events_input_source_recreation.https-expected.txt (0 => 276433)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/webxr/events_input_source_recreation.https-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/webxr/events_input_source_recreation.https-expected.txt	2021-04-22 14:06:06 UTC (rev 276433)
@@ -0,0 +1,3 @@
+
+PASS Input sources are re-created when handedness or target ray mode changes
+

Added: trunk/LayoutTests/imported/w3c/web-platform-tests/webxr/events_input_sources_change.https-expected.txt (0 => 276433)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/webxr/events_input_sources_change.https-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/webxr/events_input_sources_change.https-expected.txt	2021-04-22 14:06:06 UTC (rev 276433)
@@ -0,0 +1,3 @@
+
+PASS Transient input sources fire events in the right order
+

Added: trunk/LayoutTests/imported/w3c/web-platform-tests/webxr/events_session_select.https-expected.txt (0 => 276433)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/webxr/events_session_select.https-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/webxr/events_session_select.https-expected.txt	2021-04-22 14:06:06 UTC (rev 276433)
@@ -0,0 +1,3 @@
+
+PASS XRInputSources primary input presses properly fires off the right events
+

Added: trunk/LayoutTests/imported/w3c/web-platform-tests/webxr/events_session_select_subframe.https-expected.txt (0 => 276433)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/webxr/events_session_select_subframe.https-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/webxr/events_session_select_subframe.https-expected.txt	2021-04-22 14:06:06 UTC (rev 276433)
@@ -0,0 +1,3 @@
+
+PASS Ensures that an XRInputSources primary input being pressed and released in the space of a single frame properly fires off the right events
+

Added: trunk/LayoutTests/imported/w3c/web-platform-tests/webxr/events_session_squeeze.https-expected.txt (0 => 276433)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/webxr/events_session_squeeze.https-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/webxr/events_session_squeeze.https-expected.txt	2021-04-22 14:06:06 UTC (rev 276433)
@@ -0,0 +1,3 @@
+
+PASS XRInputSources primary input presses properly fires off the right events
+

Added: trunk/LayoutTests/imported/w3c/web-platform-tests/webxr/getInputPose_handedness.https-expected.txt (0 => 276433)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/webxr/getInputPose_handedness.https-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/webxr/getInputPose_handedness.https-expected.txt	2021-04-22 14:06:06 UTC (rev 276433)
@@ -0,0 +1,3 @@
+
+PASS XRInputSources properly communicate their handedness
+

Added: trunk/LayoutTests/imported/w3c/web-platform-tests/webxr/xrInputSource_add_remove.https-expected.txt (0 => 276433)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/webxr/xrInputSource_add_remove.https-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/webxr/xrInputSource_add_remove.https-expected.txt	2021-04-22 14:06:06 UTC (rev 276433)
@@ -0,0 +1,3 @@
+
+PASS XRInputSources can be properly added and removed from the session
+

Added: trunk/LayoutTests/imported/w3c/web-platform-tests/webxr/xrInputSource_emulatedPosition.https-expected.txt (0 => 276433)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/webxr/xrInputSource_emulatedPosition.https-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/webxr/xrInputSource_emulatedPosition.https-expected.txt	2021-04-22 14:06:06 UTC (rev 276433)
@@ -0,0 +1,3 @@
+
+PASS Poses from XRInputSource.gripSpace have emulatedPosition set properly
+

Added: trunk/LayoutTests/imported/w3c/web-platform-tests/webxr/xrInputSource_profiles.https-expected.txt (0 => 276433)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/webxr/xrInputSource_profiles.https-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/webxr/xrInputSource_profiles.https-expected.txt	2021-04-22 14:06:06 UTC (rev 276433)
@@ -0,0 +1,3 @@
+
+PASS WebXR InputSource's profiles list can be set
+

Added: trunk/LayoutTests/imported/w3c/web-platform-tests/webxr/xrInputSource_sameObject.https-expected.txt (0 => 276433)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/webxr/xrInputSource_sameObject.https-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/webxr/xrInputSource_sameObject.https-expected.txt	2021-04-22 14:06:06 UTC (rev 276433)
@@ -0,0 +1,3 @@
+
+PASS XRInputSource attributes meet [SameObject] requirement
+

Added: trunk/LayoutTests/imported/w3c/web-platform-tests/webxr/xrReferenceSpace_originOffset.https-expected.txt (0 => 276433)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/webxr/xrReferenceSpace_originOffset.https-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/webxr/xrReferenceSpace_originOffset.https-expected.txt	2021-04-22 14:06:06 UTC (rev 276433)
@@ -0,0 +1,3 @@
+
+PASS Updating XRReferenceSpace origin offset updates view and input matrices.
+

Modified: trunk/LayoutTests/platform/wpe/TestExpectations (276432 => 276433)


--- trunk/LayoutTests/platform/wpe/TestExpectations	2021-04-22 12:18:47 UTC (rev 276432)
+++ trunk/LayoutTests/platform/wpe/TestExpectations	2021-04-22 14:06:06 UTC (rev 276433)
@@ -610,6 +610,11 @@
 webkit.org/b/213131 http/tests/misc/gamepads-insecure.html [ Skip ]
 
 # WebXR
+imported/w3c/web-platform-tests/webxr/events_input_source_recreation.https.html [ Pass ]
+imported/w3c/web-platform-tests/webxr/events_input_sources_change.https.html [ Pass ]
+imported/w3c/web-platform-tests/webxr/events_session_select_subframe.https.html [ Pass ]
+imported/w3c/web-platform-tests/webxr/events_session_select.https.html [ Pass ]
+imported/w3c/web-platform-tests/webxr/events_session_squeeze.https.html [ Pass ]
 webkit.org/b/212897 imported/w3c/web-platform-tests/webxr/idlharness.https.window.html [ Failure ]
 imported/w3c/web-platform-tests/webxr/xrBoundedReferenceSpace_updates.https.html [ Pass ]
 webkit.org/b/209859 imported/w3c/web-platform-tests/webxr/webGLCanvasContext_create_xrcompatible.https.html [ Pass ]
@@ -624,10 +629,15 @@
 webkit.org/b/209859 imported/w3c/web-platform-tests/webxr/xrDevice_requestSession_no_mode.https.html [ Pass ]
 webkit.org/b/209859 imported/w3c/web-platform-tests/webxr/xrDevice_requestSession_non_immersive_no_gesture.https.html [ Pass ]
 webkit.org/b/209859 imported/w3c/web-platform-tests/webxr/xrDevice_requestSession_optionalFeatures.https.html [ Pass ]
+imported/w3c/web-platform-tests/webxr/getInputPose_handedness.https.html [ Pass ]
 imported/w3c/web-platform-tests/webxr/getViewerPose_emulatedPosition.https.html [ Pass ]
 imported/w3c/web-platform-tests/webxr/xrFrame_getViewerPose_getPose.https.html [ Pass ]
 imported/w3c/web-platform-tests/webxr/xrFrame_getPose.https.html [ Pass ]
 imported/w3c/web-platform-tests/webxr/xrFrame_session_sameObject.https.html [ Pass ]
+imported/w3c/web-platform-tests/webxr/xrInputSource_add_remove.https.html [ Pass ]
+imported/w3c/web-platform-tests/webxr/xrInputSource_emulatedPosition.https.html [ Pass ]
+imported/w3c/web-platform-tests/webxr/xrInputSource_profiles.https.html [ Pass ]
+imported/w3c/web-platform-tests/webxr/xrInputSource_sameObject.https.html [ Pass ]
 imported/w3c/web-platform-tests/webxr/xrSession_viewer_availability.https.html [ Pass ]
 webkit.org/b/209859 imported/w3c/web-platform-tests/webxr/ar-module/idlharness.https.window.html [ Pass ]
 webkit.org/b/209859 imported/w3c/web-platform-tests/webxr/ar-module/xrDevice_isSessionSupported_immersive-ar.https.html [ Pass ]
@@ -635,6 +645,7 @@
 imported/w3c/web-platform-tests/webxr/xrView_match.https.html [ Pass ]
 imported/w3c/web-platform-tests/webxr/xrView_oneframeupdate.https.html [ Pass ]
 imported/w3c/web-platform-tests/webxr/navigator_xr_sameObject.https.html [ Pass ]
+imported/w3c/web-platform-tests/webxr/xrReferenceSpace_originOffset.https.html [ Pass ]
 imported/w3c/web-platform-tests/webxr/xrReferenceSpace_originOffset_viewer.https.html [ Pass ]
 imported/w3c/web-platform-tests/webxr/xrReferenceSpace_relationships.https.html [ Pass ]
 imported/w3c/web-platform-tests/webxr/xrRigidTransform_constructor.https.html [ Pass ]

Modified: trunk/Source/WebCore/ChangeLog (276432 => 276433)


--- trunk/Source/WebCore/ChangeLog	2021-04-22 12:18:47 UTC (rev 276432)
+++ trunk/Source/WebCore/ChangeLog	2021-04-22 14:06:06 UTC (rev 276433)
@@ -1,3 +1,118 @@
+2021-04-22  Imanol Fernandez  <[email protected]>
+
+        Implement WebXR Input Sources
+        https://bugs.webkit.org/show_bug.cgi?id=223257
+
+        Reviewed by Youenn Fablet.
+
+        This patch implements the platform data definition and the DOM bits required to support WebXR Input Sources, the input mechanism used in WebXR.
+        Example XR input sources include, but are not limited to, handheld controllers, optically tracked hands, and gaze-based input methods.
+
+        More info about the API in:
+        - https://immersive-web.github.io/webxr/#input
+        - https://immersive-web.github.io/webxr-gamepads-module/#webxr-device-api-integration
+
+        Tested by WebXR WPT.
+
+        * Modules/gamepad/Gamepad.h: Add setConnected method.
+
+        * Modules/webxr/WebXRGamepad.cpp: Bridge between WebXRInputSource and Gamepad
+        (WebCore::WebXRGamepad::WebXRGamepad):
+        * Modules/webxr/WebXRGamepad.h:
+
+        * Modules/webxr/WebXRInputSpace.cpp: Instance of WebXRSpace used for WebXRInputSource spaces.
+        (WebCore::WebXRInputSpace::create):
+        (WebCore::WebXRInputSpace::WebXRInputSpace):
+        (WebCore::WebXRInputSpace::nativeOrigin const):
+        * Modules/webxr/WebXRInputSpace.h:
+
+        * Modules/webxr/WebXRFrame.cpp:
+        (WebCore::WebXRFrame::populatePose): set emulatedPosition based on the spaces.
+
+        * Modules/webxr/WebXRInputSource.cpp: Complete WebXRInputSource implementation.
+        (WebCore::WebXRInputSpace::create):
+        (WebCore::WebXRInputSpace::WebXRInputSpace):
+        (WebCore::WebXRInputSpace::nativeOrigin const):
+        (WebCore::WebXRInputSource::create):
+        (WebCore::WebXRInputSource::WebXRInputSource):
+        (WebCore::WebXRInputSource::update):
+        (WebCore::WebXRInputSource::requiresInputSourceChange):
+        (WebCore::WebXRInputSource::disconnect):
+        (WebCore::WebXRInputSource::pollEvents):
+        (WebCore::WebXRInputSource::createEvent):
+        * Modules/webxr/WebXRInputSource.h:
+        (WebCore::WebXRInputSource::handle const):
+        (WebCore::WebXRInputSource::handedness const):
+        (WebCore::WebXRInputSource::targetRayMode const):
+        (WebCore::WebXRInputSource::targetRaySpace const):
+        (WebCore::WebXRInputSource::gripSpace const):
+        (WebCore::WebXRInputSource::profiles const):
+        (WebCore::WebXRInputSource::gamepad const):
+
+        * Modules/webxr/WebXRInputSource.idl: Add gamepad attribute.
+
+        * Modules/webxr/WebXRInputSourceArray.cpp: Implement input source updates and event dispatching.
+        (WebCore::WebXRInputSourceArray::create):
+        (WebCore::WebXRInputSourceArray::WebXRInputSourceArray):
+        (WebCore::WebXRInputSourceArray::length const):
+        (WebCore::WebXRInputSourceArray::item const):
+        (WebCore::WebXRInputSourceArray::clear):
+        (WebCore::WebXRInputSourceArray::update):
+        (WebCore::WebXRInputSourceArray::handleRemovedInputSources):
+        (WebCore::WebXRInputSourceArray::handleAddedOrUpdatedInputSources):
+        * Modules/webxr/WebXRInputSourceArray.h:
+
+        * Modules/webxr/WebXRSession.cpp:
+        (WebCore::WebXRSession::WebXRSession): Set tracking delegate before initializing tracking and rendering.
+        (WebCore::WebXRSession::isPositionEmulated const): Add helper method.
+        (WebCore::WebXRSession::shutdown): Clear WebXRInputSourceArray instance.
+        (WebCore::WebXRSession::sessionDidInitializeInputSources): Dispatch initial InputSource discovery event.
+        (WebCore::WebXRSession::onFrame): Update WebXRInputSourceArray instance.
+        * Modules/webxr/WebXRSession.h:
+
+        * Modules/webxr/WebXRSpace.cpp: Add virtual class isPositionEmulated to be used in WebXRFrame.
+        (WebCore::WebXRSpace::isPositionEmulated const):
+        * Modules/webxr/WebXRSpace.h:
+
+        * Modules/webxr/WebXRSystem.cpp:
+        (WebCore::WebXRSystem::requestSession): update FIXME comment.
+
+        * Modules/webxr/XRHandedness.h: Reuse PlatformXR enum.
+
+        * Modules/webxr/XRInputSourceEvent.cpp:
+        (WebCore::XRInputSourceEvent::XRInputSourceEvent):
+        (WebCore::XRInputSourceEvent::setFrameActive):
+        * Modules/webxr/XRInputSourceEvent.h:
+
+        * Modules/webxr/XRInputSourcesChangeEvent.h:
+
+        * Modules/webxr/XRTargetRayMode.h: Reuse PlatformXR enum.
+
+        * platform/gamepad/GamepadConstants.cpp:
+        (WebCore::xrStandardGamepadMappingString): Add xr-standard gamepad mapping name.
+        * platform/gamepad/GamepadConstants.h:
+
+        * platform/xr/PlatformXR.h: Add Input Source frame data.
+
+        * testing/WebFakeXRDevice.cpp: Implement required changes to run and pass WebXR Input Source tests.
+        (WebCore::SimulatedXRDevice::initializeTrackingAndRendering):
+        (WebCore::SimulatedXRDevice::frameTimerFired):
+        (WebCore::WebFakeXRDevice::simulateResetPose):
+        (WebCore::WebFakeXRDevice::simulateInputSourceConnection):
+        * testing/WebFakeXRDevice.h:
+        * testing/WebFakeXRInputController.cpp:
+        (WebCore::WebFakeXRInputController::create):
+        (WebCore::WebFakeXRInputController::WebFakeXRInputController):
+        (WebCore::WebFakeXRInputController::setGripOrigin):
+        (WebCore::WebFakeXRInputController::setPointerOrigin):
+        (WebCore::WebFakeXRInputController::disconnect):
+        (WebCore::WebFakeXRInputController::reconnect):
+        (WebCore::WebFakeXRInputController::setSupportedButtons):
+        (WebCore::WebFakeXRInputController::updateButtonState):
+        (WebCore::WebFakeXRInputController::getFrameData):
+        (WebCore::WebFakeXRInputController::getButtonOrPlaceholder const):
+        * testing/WebFakeXRInputController.h:
+
 2021-04-22  Carlos Garcia Campos  <[email protected]>
 
         [GTK][WPE] Bump libsoup3 version to 2.99.4

Modified: trunk/Source/WebCore/Modules/gamepad/Gamepad.h (276432 => 276433)


--- trunk/Source/WebCore/Modules/gamepad/Gamepad.h	2021-04-22 12:18:47 UTC (rev 276432)
+++ trunk/Source/WebCore/Modules/gamepad/Gamepad.h	2021-04-22 14:06:06 UTC (rev 276433)
@@ -55,6 +55,7 @@
     const Vector<Ref<GamepadButton>>& buttons() const;
 
     void updateFromPlatformGamepad(const PlatformGamepad&);
+    void setConnected(bool connected) { m_connected = connected; }
 
 private:
     explicit Gamepad(const PlatformGamepad&);

Modified: trunk/Source/WebCore/Modules/webxr/WebXRFrame.cpp (276432 => 276433)


--- trunk/Source/WebCore/Modules/webxr/WebXRFrame.cpp	2021-04-22 12:18:47 UTC (rev 276432)
+++ trunk/Source/WebCore/Modules/webxr/WebXRFrame.cpp	2021-04-22 14:06:06 UTC (rev 276433)
@@ -119,7 +119,7 @@
     // 7. Let transform be pose’s transform.
     // 8. Query the XR device's tracking system for space’s pose relative to baseSpace at the frame’s time.
 
-    if (!m_data.isTrackingValid) {
+    if (m_isAnimationFrame && !m_data.isTrackingValid) {
         // FIXME: check if space’s pose relative to baseSpace has been determined in the past.
         // Anyway this emulation is usually provided by the system in the pose (e.g. OpenXR)
         // so we shouldn't hit this path in most XRPlatform ports.
@@ -131,7 +131,7 @@
         return { WTF::nullopt };
 
     auto transform =  *baseTransform.inverse() * space.effectiveOrigin();
-    bool emulatedPosition = m_data.isPositionEmulated || !m_data.isPositionValid;
+    bool emulatedPosition = space.isPositionEmulated() || baseSpace.isPositionEmulated();
 
     bool limit = mustPosesBeLimited(space, baseSpace);
     if (limit) {

Copied: trunk/Source/WebCore/Modules/webxr/WebXRGamepad.cpp (from rev 276432, trunk/Source/WebCore/testing/WebFakeXRInputController.h) (0 => 276433)


--- trunk/Source/WebCore/Modules/webxr/WebXRGamepad.cpp	                        (rev 0)
+++ trunk/Source/WebCore/Modules/webxr/WebXRGamepad.cpp	2021-04-22 14:06:06 UTC (rev 276433)
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2020 Igalia S.L. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "WebXRGamepad.h"
+
+#if ENABLE(WEBXR) && ENABLE(GAMEPAD)
+
+#include "Gamepad.h"
+#include "GamepadConstants.h"
+#include "XRTargetRayMode.h"
+
+namespace WebCore {
+
+// https://immersive-web.github.io/webxr-gamepads-module/#gamepad-differences
+// Gamepad's index attribute must be -1.
+constexpr int DefaultXRGamepadId = -1;
+
+// https://immersive-web.github.io/webxr-gamepads-module/#gamepad-differences
+WebXRGamepad::WebXRGamepad(double timestamp, double connectTime, const PlatformXR::Device::FrameData::InputSource& source)
+    : PlatformGamepad(DefaultXRGamepadId)
+{
+    m_lastUpdateTime = MonotonicTime::fromRawSeconds(Seconds::fromMilliseconds(timestamp).value());
+    m_connectTime = MonotonicTime::fromRawSeconds(Seconds::fromMilliseconds(connectTime).value());
+    // In order to report a mapping of "xr-standard" the device MUST report a targetRayMode of "tracked-pointer" and MUST have a non-null gripSpace.
+    // It MUST have at least one primary trigger, separate from any touchpads or thumbsticks
+    if (source.targetRayMode == XRTargetRayMode::TrackedPointer && !source.buttons.isEmpty() && source.gripOrigin.hasValue())
+        m_mapping = xrStandardGamepadMappingString();
+    m_axes = source.axes.map([](auto value) {
+        return SharedGamepadValue(value);
+    });
+    m_buttons = source.buttons.map([](auto& value) {
+        return SharedGamepadValue(value.pressedValue);
+    });
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(WEBXR) && ENABLE(GAMEPAD)

Copied: trunk/Source/WebCore/Modules/webxr/WebXRGamepad.h (from rev 276432, trunk/Source/WebCore/Modules/webxr/WebXRInputSourceArray.h) (0 => 276433)


--- trunk/Source/WebCore/Modules/webxr/WebXRGamepad.h	                        (rev 0)
+++ trunk/Source/WebCore/Modules/webxr/WebXRGamepad.h	2021-04-22 14:06:06 UTC (rev 276433)
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2020 Igalia S.L. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(WEBXR) && ENABLE(GAMEPAD)
+
+#include "PlatformGamepad.h"
+#include "PlatformXR.h"
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class WebXRGamepad: public PlatformGamepad {
+public:
+    WebXRGamepad(double timestamp, double connectTime, const PlatformXR::Device::FrameData::InputSource&);
+
+private:
+    const Vector<SharedGamepadValue>& axisValues() const final { return m_axes; }
+    const Vector<SharedGamepadValue>& buttonValues() const final { return m_buttons; }
+
+    Vector<SharedGamepadValue> m_axes;
+    Vector<SharedGamepadValue> m_buttons;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(WEBXR)

Modified: trunk/Source/WebCore/Modules/webxr/WebXRInputSource.cpp (276432 => 276433)


--- trunk/Source/WebCore/Modules/webxr/WebXRInputSource.cpp	2021-04-22 12:18:47 UTC (rev 276432)
+++ trunk/Source/WebCore/Modules/webxr/WebXRInputSource.cpp	2021-04-22 14:06:06 UTC (rev 276433)
@@ -28,7 +28,14 @@
 
 #if ENABLE(WEBXR)
 
-#include "WebXRSpace.h"
+#include "EventNames.h"
+#if ENABLE(GAMEPAD)
+#include "Gamepad.h"
+#include "WebXRGamepad.h"
+#endif
+#include "WebXRFrame.h"
+#include "WebXRSession.h"
+#include "XRInputSourceEvent.h"
 #include <wtf/IsoMallocInlines.h>
 
 namespace WebCore {
@@ -35,43 +42,114 @@
 
 WTF_MAKE_ISO_ALLOCATED_IMPL(WebXRInputSource);
 
-Ref<WebXRInputSource> WebXRInputSource::create(Ref<WebXRSpace>&& targetRaySpace)
+Ref<WebXRInputSource> WebXRInputSource::create(Document& document, Ref<WebXRSession>&& session, double timestamp, const PlatformXR::Device::FrameData::InputSource& source)
 {
-    return adoptRef(*new WebXRInputSource(WTFMove(targetRaySpace)));
+    return adoptRef(*new WebXRInputSource(document, WTFMove(session), timestamp, source));
 }
 
-WebXRInputSource::WebXRInputSource(Ref<WebXRSpace>&& targetRaySpace)
-    : m_handedness(XRHandedness::None)
-    , m_targetRayMode(XRTargetRayMode::Gaze)
-    , m_targetRaySpace(WTFMove(targetRaySpace))
+WebXRInputSource::WebXRInputSource(Document& document, Ref<WebXRSession>&& session, double timestamp, const PlatformXR::Device::FrameData::InputSource& source)
+    : m_session(WTFMove(session))
+    , m_targetRaySpace(WebXRInputSpace::create(document, m_session.copyRef(), source.pointerOrigin))
+    , m_connectTime(timestamp)
+#if ENABLE(GAMEPAD)
+    , m_gamepad(Gamepad::create(WebXRGamepad(timestamp, timestamp, source)))
+#endif
 {
+    update(timestamp, source);
 }
 
 WebXRInputSource::~WebXRInputSource() = default;
 
-XRHandedness WebXRInputSource::handedness() const
+void WebXRInputSource::update(double timestamp, const PlatformXR::Device::FrameData::InputSource& source)
 {
-    return m_handedness;
+#if !ENABLE(GAMEPAD)
+    UNUSED_PARAM(timestamp);
+#endif
+    m_source = source;
+    m_targetRaySpace->setPose(source.pointerOrigin);
+    if (auto gripOrigin = source.gripOrigin) {
+        if (m_gripSpace)
+            m_gripSpace->setPose(*gripOrigin);
+        else if (auto* document = downcast<Document>(m_session->scriptExecutionContext()))
+            m_gripSpace = WebXRInputSpace::create(*document, m_session.copyRef(), *gripOrigin);
+    } else
+        m_gripSpace = nullptr;
+#if ENABLE(GAMEPAD)
+    m_gamepad->updateFromPlatformGamepad(WebXRGamepad(timestamp, m_connectTime, source));
+#endif
 }
 
-XRTargetRayMode WebXRInputSource::targetRayMode() const
+bool WebXRInputSource::requiresInputSourceChange(const InputSource& source)
 {
-    return m_targetRayMode;
+    return m_source.handeness != source.handeness
+        || m_source.targetRayMode != source.targetRayMode
+        || m_source.profiles != source.profiles
+        || static_cast<bool>(m_gripSpace) != source.gripOrigin.hasValue();
 }
 
-const WebXRSpace& WebXRInputSource::targetRaySpace() const
+void WebXRInputSource::disconnect()
 {
-    return m_targetRaySpace;
+    m_connected = false;
+#if ENABLE(GAMEPAD)
+    m_gamepad->setConnected(false);
+#endif
 }
 
-RefPtr<WebXRSpace> WebXRInputSource::gripSpace() const
+void WebXRInputSource::pollEvents(Vector<Ref<XRInputSourceEvent>>& events)
 {
-    return { };
+    if (!m_connected) {
+        // A user agent MUST dispatch a selectend event on an XRSession when one of its XRInputSources ends 
+        // when an XRInputSource that has begun a primary select action is disconnected.
+        if (m_selectStarted)
+            events.append(createEvent(eventNames().selectendEvent));
+
+        // A user agent MUST dispatch a squeezeend event on an XRSession when one of its XRInputSources ends 
+        // when an XRInputSource that has begun a primary squeeze action is disconnected.
+        if (m_squeezeStarted)
+            events.append(createEvent(eventNames().squeezeendEvent));
+
+        return;
+    }
+
+    // https://immersive-web.github.io/webxr-gamepads-module/#xr-standard-gamepad-mapping
+    // Button indices are based on the xr-standard layout.
+    bool selectStarted = !m_source.buttons.isEmpty() && m_source.buttons.first().pressed;
+    bool squeezeStarted = m_source.buttons.size() > 1 && m_source.buttons[1].pressed;
+
+    if (selectStarted != m_selectStarted) {
+        if (selectStarted) {
+            // A user agent MUST dispatch a selectstart event on an XRSession when one of its XRInputSources begins its primary action.
+            events.append(createEvent(eventNames().selectstartEvent));
+        } else {
+            // A user agent MUST dispatch a selectend event on an XRSession when one of its XRInputSources ends its primary action.
+            // A user agent MUST dispatch a select event on an XRSession when one of its XRInputSources has fully completed a primary action
+            events.append(createEvent(eventNames().selectEvent));
+            events.append(createEvent(eventNames().selectendEvent));
+        }
+        m_selectStarted = selectStarted;
+    }
+
+    if (squeezeStarted != m_squeezeStarted) {
+        if (squeezeStarted) {
+            // A user agent MUST dispatch a squeezestart event on an XRSession when one of its XRInputSources begins its primary squeeze action.
+            events.append(createEvent(eventNames().squeezestartEvent));
+        } else {
+            // A user agent MUST dispatch a selectend event on an XRSession when one of its XRInputSources ends its primary squeeze action.
+            // A user agent MUST dispatch a select event on an XRSession when one of its XRInputSources has fully completed a primary squeeze action.
+            events.append(createEvent(eventNames().squeezeEvent));
+            events.append(createEvent(eventNames().squeezeendEvent));
+        }
+        m_squeezeStarted = squeezeStarted;
+    }
 }
 
-const Vector<String>& WebXRInputSource::profiles() const
+Ref<XRInputSourceEvent> WebXRInputSource::createEvent(const AtomString& name)
 {
-    return m_profiles;
+    XRInputSourceEvent::Init init;
+    init.frame = WebXRFrame::create(m_session.copyRef(), WebXRFrame::IsAnimationFrame::No);
+    init.inputSource = makeRefPtr(*this);
+
+    return XRInputSourceEvent::create(name, init);
 }
 
 } // namespace WebCore

Modified: trunk/Source/WebCore/Modules/webxr/WebXRInputSource.h (276432 => 276433)


--- trunk/Source/WebCore/Modules/webxr/WebXRInputSource.h	2021-04-22 12:18:47 UTC (rev 276432)
+++ trunk/Source/WebCore/Modules/webxr/WebXRInputSource.h	2021-04-22 14:06:06 UTC (rev 276433)
@@ -27,6 +27,9 @@
 
 #if ENABLE(WEBXR)
 
+#include "PlatformXR.h"
+#include "WebXRGamepad.h"
+#include "WebXRInputSpace.h"
 #include "XRHandedness.h"
 #include "XRTargetRayMode.h"
 #include <wtf/IsoMalloc.h>
@@ -38,27 +41,54 @@
 
 namespace WebCore {
 
-class WebXRSpace;
+#if ENABLE(GAMEPAD)
+class Gamepad;
+#endif
+class XRInputSourceEvent;
+class WebXRInputSpace;
 
 class WebXRInputSource : public RefCounted<WebXRInputSource> {
     WTF_MAKE_ISO_ALLOCATED(WebXRInputSource);
 public:
-    static Ref<WebXRInputSource> create(Ref<WebXRSpace>&&);
+    using InputSource = PlatformXR::Device::FrameData::InputSource;
+    using InputSourceButton = PlatformXR::Device::FrameData::InputSourceButton;
+
+    static Ref<WebXRInputSource> create(Document&, Ref<WebXRSession>&&, double timestamp, const InputSource&);
     ~WebXRInputSource();
 
-    XRHandedness handedness() const;
-    XRTargetRayMode targetRayMode() const;
-    const WebXRSpace& targetRaySpace() const;
-    RefPtr<WebXRSpace> gripSpace() const;
-    const Vector<String>& profiles() const;
+    PlatformXR::InputSourceHandle handle() const { return m_source.handle; }
+    XRHandedness handedness() const { return m_source.handeness; }
+    XRTargetRayMode targetRayMode() const { return m_source.targetRayMode; };
+    const WebXRSpace& targetRaySpace() const {return m_targetRaySpace.get(); };
+    WebXRSpace* gripSpace() const { return m_gripSpace.get(); }
+    const Vector<String>& profiles() const { return m_source.profiles; };
+#if ENABLE(GAMEPAD)
+    const Gamepad* gamepad() const { return m_gamepad.ptr(); }
+#endif
 
+    void update(double timestamp, const InputSource&);
+    bool requiresInputSourceChange(const InputSource&);
+    void disconnect();
+    
+    void pollEvents(Vector<Ref<XRInputSourceEvent>>&);
+
 private:
-    WebXRInputSource(Ref<WebXRSpace>&&);
+    WebXRInputSource(Document&, Ref<WebXRSession>&&, double timestamp, const InputSource&);
 
-    XRHandedness m_handedness;
-    XRTargetRayMode m_targetRayMode;
-    Ref<WebXRSpace> m_targetRaySpace;
-    Vector<String> m_profiles;
+    Ref<XRInputSourceEvent> createEvent(const AtomString&);
+
+    Ref<WebXRSession> m_session;
+    InputSource m_source;
+    Ref<WebXRInputSpace> m_targetRaySpace;
+    RefPtr<WebXRInputSpace> m_gripSpace;
+    double m_connectTime { 0 };
+    bool m_connected { true };
+#if ENABLE(GAMEPAD)
+    Ref<Gamepad> m_gamepad;
+#endif
+
+    bool m_selectStarted { false };
+    bool m_squeezeStarted { false };
 };
 
 } // namespace WebCore

Modified: trunk/Source/WebCore/Modules/webxr/WebXRInputSource.idl (276432 => 276433)


--- trunk/Source/WebCore/Modules/webxr/WebXRInputSource.idl	2021-04-22 12:18:47 UTC (rev 276432)
+++ trunk/Source/WebCore/Modules/webxr/WebXRInputSource.idl	2021-04-22 14:06:06 UTC (rev 276433)
@@ -35,5 +35,8 @@
     readonly attribute XRTargetRayMode targetRayMode ;
     [SameObject] readonly attribute WebXRSpace targetRaySpace;
     [SameObject] readonly attribute WebXRSpace? gripSpace ;
-    [SameObject] readonly attribute FrozenArray<DOMString> profiles;
+    [CachedAttribute, SameObject] readonly attribute FrozenArray<DOMString> profiles;
+
+    // https://immersive-web.github.io/webxr-gamepads-module/#xrinputsource-interface
+    [Conditional=GAMEPAD, SameObject] readonly attribute Gamepad? gamepad;
 };

Modified: trunk/Source/WebCore/Modules/webxr/WebXRInputSourceArray.cpp (276432 => 276433)


--- trunk/Source/WebCore/Modules/webxr/WebXRInputSourceArray.cpp	2021-04-22 12:18:47 UTC (rev 276432)
+++ trunk/Source/WebCore/Modules/webxr/WebXRInputSourceArray.cpp	2021-04-22 14:06:06 UTC (rev 276433)
@@ -27,7 +27,11 @@
 #include "WebXRInputSourceArray.h"
 
 #if ENABLE(WEBXR)
-
+#include "EventNames.h"
+#include "WebXRInputSource.h"
+#include "WebXRSession.h"
+#include "XRInputSourceEvent.h"
+#include "XRInputSourcesChangeEvent.h"
 #include <wtf/IsoMallocInlines.h>
 
 namespace WebCore {
@@ -34,16 +38,144 @@
 
 WTF_MAKE_ISO_ALLOCATED_IMPL(WebXRInputSourceArray);
 
+Ref<WebXRInputSourceArray> WebXRInputSourceArray::create(Ref<WebXRSession>&& session)
+{
+    return adoptRef(*new WebXRInputSourceArray(WTFMove(session)));
+}
+
+WebXRInputSourceArray::WebXRInputSourceArray(Ref<WebXRSession>&& session)
+    : m_session(WTFMove(session))
+{
+}
+
+WebXRInputSourceArray::~WebXRInputSourceArray() = default;
+
 unsigned WebXRInputSourceArray::length() const
 {
-    return 0;
+    return m_inputSources.size();
 }
 
-WebXRInputSource* WebXRInputSourceArray::item(unsigned) const
+WebXRInputSource* WebXRInputSourceArray::item(unsigned index) const
 {
-    return nullptr;
+    return index >= m_inputSources.size() ? nullptr: m_inputSources[index].ptr();
 }
 
+void WebXRInputSourceArray::clear()
+{
+    m_inputSources.clear();
+}
+
+// https://immersive-web.github.io/webxr/#list-of-active-xr-input-sources
+void WebXRInputSourceArray::update(double timestamp, const InputSourceList& inputSources)
+{
+    Vector<RefPtr<WebXRInputSource>> added;
+    Vector<RefPtr<WebXRInputSource>> removed;
+    Vector<Ref<XRInputSourceEvent>> inputEvents;
+
+    handleRemovedInputSources(inputSources, removed, inputEvents);
+    handleAddedOrUpdatedInputSources(timestamp, inputSources, added, removed, inputEvents);
+
+    if (!added.isEmpty() || !removed.isEmpty()) {
+        // A user agent MUST dispatch an inputsourceschange event on an XRSession when the session’s list of active XR input sources has changed.
+        XRInputSourcesChangeEvent::Init init;
+        init.session = m_session.copyRef();
+        init.added = WTFMove(added);
+        init.removed = WTFMove(removed);
+        
+        auto event = XRInputSourcesChangeEvent::create(eventNames().inputsourceschangeEvent, init);
+        m_session->queueTaskToDispatchEvent(m_session.get(), TaskSource::WebXR, WTFMove(event));
+    }
+
+    if (!inputEvents.isEmpty()) {
+        // When the user agent has to fire an input source event with name name, XRFrame frame, and XRInputSource source it MUST run the following steps:
+        // 1. Create an XRInputSourceEvent event with type name, frame frame, and inputSource source.
+        // 2. Set frame’s active boolean to true.
+        // 3. Apply frame updates for frame.
+        // 4. Dispatch event on frame’s session
+        // 5. Set frame’s active boolean to false.
+
+        for (auto& event : inputEvents) {
+            m_session->queueTaskKeepingObjectAlive(m_session.get(), TaskSource::WebXR, [&session = m_session.get(), event = WTFMove(event)]() {
+                event->setFrameActive(true);
+                session.dispatchEvent(event.copyRef());
+                event->setFrameActive(false);
+            });
+        }
+    }
+}
+
+// https://immersive-web.github.io/webxr/#list-of-active-xr-input-sources
+void WebXRInputSourceArray::handleRemovedInputSources(const InputSourceList& inputSources, Vector<RefPtr<WebXRInputSource>>& removed, Vector<Ref<XRInputSourceEvent>>& inputEvents)
+{
+    // When any previously added XR input sources are no longer available for XRSession session, the user agent MUST run the following steps:
+    // 1. If session's promise resolved flag is not set, abort these steps.
+    // 2. Let removed be a new list.
+    // 3. For each XR input source that is no longer available:
+    //  3.1 Let inputSource be the XRInputSource in session's list of active XR input sources associated with the XR input source.
+    //  3.2 Add inputSource to removed.
+    m_inputSources.removeAllMatching([this, &inputSources, &removed, &inputEvents](auto& source) {
+        if (!WTF::anyOf(inputSources, [&source](auto& item) { return item.handle == source->handle(); })) {
+            removed.append(source.copyRef());
+            source->disconnect();
+            source->pollEvents(inputEvents);
+            return true;
+        }
+        return false;
+    });
+}
+
+// https://immersive-web.github.io/webxr/#list-of-active-xr-input-sources
+void WebXRInputSourceArray::handleAddedOrUpdatedInputSources(double timestamp, const InputSourceList& inputSources, Vector<RefPtr<WebXRInputSource>>& added, Vector<RefPtr<WebXRInputSource>>& removed, Vector<Ref<XRInputSourceEvent>>& inputEvents)
+{
+    auto* document = downcast<Document>(m_session->scriptExecutionContext());
+    if (!document)
+        return;
+
+    for (auto& inputSource : inputSources) {
+        auto index = m_inputSources.findMatching([&inputSource](auto& item) { return item->handle() == inputSource.handle; });
+        if (index == WTF::notFound) {
+            // When new XR input sources become available for XRSession session, the user agent MUST run the following steps:
+            // 1. If session's promise resolved flag is not set, abort these steps.
+            // 2. Let added be a new list.
+            // 3. For each new XR input source:
+            //   3.1 Let inputSource be a new XRInputSource in the relevant realm of this XRSession.
+            //   3.2 Add inputSource to added.
+
+            auto input = WebXRInputSource::create(*document, m_session.copyRef(), timestamp, inputSource);
+            added.append(input.copyRef());
+            input->pollEvents(inputEvents);
+            m_inputSources.append(WTFMove(input));
+            continue;
+        }
+
+        // When the handedness, targetRayMode, profiles, or presence of a gripSpace for any XR input sources change for XRSession session, the user agent MUST run the following steps
+        // 1. If session’s promise resolved flag is not set, abort these steps.
+        // 2. Let added be a new list.
+        // 3. Let removed be a new list.
+        // 4. For each changed XR input source:
+        //  4.1 Let oldInputSource be the XRInputSource in session's list of active XR input sources previously associated with the XR input source.
+        //  4.1 Let newInputSource be a new XRInputSource in the relevant realm of session.
+        //  4.1 Add oldInputSource to removed.
+        //  4.1 Add newInputSource to added.
+        auto& input = m_inputSources[index];
+
+        if (input->requiresInputSourceChange(inputSource)) {
+            removed.append(input.copyRef());
+            input->disconnect();
+            input->pollEvents(inputEvents);
+            m_inputSources.remove(index);
+
+            auto newInputSource = WebXRInputSource::create(*document, m_session.copyRef(), timestamp, inputSource);
+            added.append(newInputSource.copyRef());
+            newInputSource->pollEvents(inputEvents);
+            m_inputSources.append(WTFMove(newInputSource));
+        } else {
+            input->update(timestamp, inputSource);
+            input->pollEvents(inputEvents);
+        }
+    }
+}
+
 } // namespace WebCore
 
 #endif // ENABLE(WEBXR)

Modified: trunk/Source/WebCore/Modules/webxr/WebXRInputSourceArray.h (276432 => 276433)


--- trunk/Source/WebCore/Modules/webxr/WebXRInputSourceArray.h	2021-04-22 12:18:47 UTC (rev 276432)
+++ trunk/Source/WebCore/Modules/webxr/WebXRInputSourceArray.h	2021-04-22 14:06:06 UTC (rev 276433)
@@ -27,6 +27,7 @@
 
 #if ENABLE(WEBXR)
 
+#include "PlatformXR.h"
 #include <wtf/IsoMalloc.h>
 #include <wtf/Ref.h>
 #include <wtf/RefCounted.h>
@@ -33,19 +34,32 @@
 
 namespace WebCore {
 
+class Document;
 class WebXRInputSource;
+class XRInputSourceEvent;
+class WebXRSession;
 
 class WebXRInputSourceArray : public RefCounted<WebXRInputSourceArray> {
     WTF_MAKE_ISO_ALLOCATED(WebXRInputSourceArray);
 public:
-    static Ref<WebXRInputSourceArray> create() { return adoptRef(*new WebXRInputSourceArray()); }
-    ~WebXRInputSourceArray() = default;
+    using InputSourceList = Vector<PlatformXR::Device::FrameData::InputSource>;
+    static Ref<WebXRInputSourceArray> create(Ref<WebXRSession>&&);
+    ~WebXRInputSourceArray();
 
     unsigned length() const;
     WebXRInputSource* item(unsigned) const;
 
+    void clear();
+    void update(double timestamp, const InputSourceList&);
+
 private:
-    WebXRInputSourceArray() = default;
+    WebXRInputSourceArray(Ref<WebXRSession>&&);
+
+    void handleRemovedInputSources(const InputSourceList&, Vector<RefPtr<WebXRInputSource>>&, Vector<Ref<XRInputSourceEvent>>&);
+    void handleAddedOrUpdatedInputSources(double timestamp, const InputSourceList&, Vector<RefPtr<WebXRInputSource>>&, Vector<RefPtr<WebXRInputSource>>&, Vector<Ref<XRInputSourceEvent>>&);
+
+    Ref<WebXRSession> m_session;
+    Vector<Ref<WebXRInputSource>> m_inputSources;
 };
 
 } // namespace WebCore

Copied: trunk/Source/WebCore/Modules/webxr/WebXRInputSpace.cpp (from rev 276432, trunk/Source/WebCore/Modules/webxr/WebXRInputSourceArray.cpp) (0 => 276433)


--- trunk/Source/WebCore/Modules/webxr/WebXRInputSpace.cpp	                        (rev 0)
+++ trunk/Source/WebCore/Modules/webxr/WebXRInputSpace.cpp	2021-04-22 14:06:06 UTC (rev 276433)
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2020 Igalia S.L. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "WebXRInputSpace.h"
+
+#if ENABLE(WEBXR)
+
+#include "WebXRFrame.h"
+#include "WebXRRigidTransform.h"
+#include "WebXRSession.h"
+#include <wtf/IsoMallocInlines.h>
+
+namespace WebCore {
+
+WTF_MAKE_ISO_ALLOCATED_IMPL(WebXRInputSpace);
+
+// WebXRInputSpace
+
+Ref<WebXRInputSpace> WebXRInputSpace::create(Document& document, Ref<WebXRSession>&& session, const PlatformXR::Device::FrameData::InputSourcePose& pose)
+{
+    return adoptRef(*new WebXRInputSpace(document, WTFMove(session), pose));
+}
+
+WebXRInputSpace::WebXRInputSpace(Document& document, Ref<WebXRSession>&& session, const PlatformXR::Device::FrameData::InputSourcePose& pose)
+    : WebXRSpace(document, WebXRRigidTransform::create())
+    , m_session(WTFMove(session))
+    , m_pose(pose)
+{
+}
+
+WebXRInputSpace::~WebXRInputSpace() = default;
+
+TransformationMatrix WebXRInputSpace::nativeOrigin() const
+{
+    return WebXRFrame::matrixFromPose(m_pose.pose);
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(WEBXR)

Copied: trunk/Source/WebCore/Modules/webxr/WebXRInputSpace.h (from rev 276432, trunk/Source/WebCore/Modules/webxr/WebXRInputSource.h) (0 => 276433)


--- trunk/Source/WebCore/Modules/webxr/WebXRInputSpace.h	                        (rev 0)
+++ trunk/Source/WebCore/Modules/webxr/WebXRInputSpace.h	2021-04-22 14:06:06 UTC (rev 276433)
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2020 Igalia S.L. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(WEBXR)
+
+#include "WebXRSpace.h"
+#include "XRHandedness.h"
+#include "XRTargetRayMode.h"
+#include <wtf/IsoMalloc.h>
+#include <wtf/RefCounted.h>
+
+namespace WebCore {
+
+class WebXRInputSpace : public RefCounted<WebXRInputSpace>, public WebXRSpace {
+    WTF_MAKE_ISO_ALLOCATED(WebXRInputSpace);
+public:
+    static Ref<WebXRInputSpace> create(Document&, Ref<WebXRSession>&&, const PlatformXR::Device::FrameData::InputSourcePose&);
+    virtual ~WebXRInputSpace();
+
+    using RefCounted<WebXRInputSpace>::ref;
+    using RefCounted<WebXRInputSpace>::deref;
+
+    bool isPositionEmulated() const final { return m_pose.isPositionEmulated; }
+    void setPose(const PlatformXR::Device::FrameData::InputSourcePose& pose) { m_pose = pose; }
+
+private:
+    WebXRInputSpace(Document&, Ref<WebXRSession>&&, const PlatformXR::Device::FrameData::InputSourcePose&);
+    WebXRSession& session() const final { return m_session.get(); }
+    TransformationMatrix nativeOrigin() const final;
+
+    void refEventTarget() final { ref(); }
+    void derefEventTarget() final { deref(); }
+
+    Ref<WebXRSession> m_session;
+    PlatformXR::Device::FrameData::InputSourcePose m_pose;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(WEBXR)

Modified: trunk/Source/WebCore/Modules/webxr/WebXRSession.cpp (276432 => 276433)


--- trunk/Source/WebCore/Modules/webxr/WebXRSession.cpp	2021-04-22 12:18:47 UTC (rev 276432)
+++ trunk/Source/WebCore/Modules/webxr/WebXRSession.cpp	2021-04-22 14:06:06 UTC (rev 276433)
@@ -52,7 +52,7 @@
 
 WebXRSession::WebXRSession(Document& document, WebXRSystem& system, XRSessionMode mode, PlatformXR::Device& device, FeatureList&& requestedFeatures)
     : ActiveDOMObject(&document)
-    , m_inputSources(WebXRInputSourceArray::create())
+    , m_inputSources(WebXRInputSourceArray::create(*this))
     , m_xrSystem(system)
     , m_mode(mode)
     , m_device(makeWeakPtr(device))
@@ -62,8 +62,8 @@
     , m_timeOrigin(MonotonicTime::now())
     , m_views(device.views(mode))
 {
+    m_device->setTrackingAndRenderingClient(makeWeakPtr(*this));
     m_device->initializeTrackingAndRendering(mode);
-    m_device->setTrackingAndRenderingClient(makeWeakPtr(*this));
 
     // https://immersive-web.github.io/webxr/#ref-for-dom-xrreferencespacetype-viewer%E2%91%A2
     // Every session MUST support viewer XRReferenceSpaces.
@@ -315,6 +315,11 @@
     return m_mode == XRSessionMode::ImmersiveVr && m_device->supportsViewportScaling();
 }
 
+bool WebXRSession::isPositionEmulated() const
+{
+    return m_frameData.isPositionEmulated || !m_frameData.isPositionValid;
+}
+
 // https://immersive-web.github.io/webxr/#shut-down-the-session
 void WebXRSession::shutdown(InitiatedBySystem initiatedBySystem)
 {
@@ -338,6 +343,8 @@
     // 4. Remove session from the list of inline sessions.
     m_xrSystem.sessionEnded(*this);
 
+    m_inputSources->clear();
+
     if (initiatedBySystem == InitiatedBySystem::Yes) {
         // If we get here, the session termination was triggered by the system rather than
         // via XRSession.end(). Since the system has completed the session shutdown, we can
@@ -411,6 +418,26 @@
 {
 }
 
+void WebXRSession::sessionDidInitializeInputSources(Vector<PlatformXR::Device::FrameData::InputSource>&& inputSources)
+{
+    // https://immersive-web.github.io/webxr/#dom-xrsystem-requestsession
+    // 5.4.11 Queue a task to perform the following steps: NOTE: These steps ensure that initial inputsourceschange
+    // events occur after the initial session is resolved.
+    queueTaskKeepingObjectAlive(*this, TaskSource::WebXR, [this, inputSources = WTFMove(inputSources)]() mutable {
+        //  1. Set session's promise resolved flag to true.
+        m_inputInitialized = true;
+        //  2. Let sources be any existing input sources attached to session.
+        //  3. If sources is non-empty, perform the following steps:
+        if (!inputSources.isEmpty()) {
+            auto timestamp = (MonotonicTime::now() - m_timeOrigin).milliseconds();
+            //  3.1. Set session's list of active XR input sources to sources.
+            //  3.2. Fire an XRInputSourcesChangeEvent named inputsourceschange on session with added set to sources.
+            //  Note: 3.1 and 3.2 steps are handled inside the update() call.
+            m_inputSources->update(timestamp, inputSources);
+        }
+    });
+}
+
 void WebXRSession::sessionDidEnd()
 {
     // This can be called as a result of finishing the shutdown initiated
@@ -527,6 +554,9 @@
             frame->setActive(true);
 
             // 6.4.Apply frame updates for frame.
+            if (m_inputInitialized)
+                m_inputSources->update(now, frameData.inputSources);
+
             frame->setFrameData(WTFMove(frameData));
 
             // 6.5.For each entry in session’s list of currently running animation frame callbacks, in order:

Modified: trunk/Source/WebCore/Modules/webxr/WebXRSession.h (276432 => 276433)


--- trunk/Source/WebCore/Modules/webxr/WebXRSession.h	2021-04-22 12:18:47 UTC (rev 276432)
+++ trunk/Source/WebCore/Modules/webxr/WebXRSession.h	2021-04-22 14:06:06 UTC (rev 276433)
@@ -84,6 +84,7 @@
     IntSize nativeWebGLFramebufferResolution() const;
     IntSize recommendedWebGLFramebufferResolution() const;
     bool supportsViewportScaling() const; 
+    bool isPositionEmulated() const;
 
     // EventTarget.
     ScriptExecutionContext* scriptExecutionContext() const final { return ActiveDOMObject::scriptExecutionContext(); }
@@ -111,6 +112,7 @@
     void stop() override;
 
     // PlatformXR::TrackingAndRenderingClient
+    void sessionDidInitializeInputSources(Vector<PlatformXR::Device::FrameData::InputSource>&&) final;
     void sessionDidEnd() final;
 
     enum class InitiatedBySystem : bool { No, Yes };
@@ -152,6 +154,9 @@
     // In meters.
     double m_minimumNearClipPlane { 0.1 };
     double m_maximumFarClipPlane { 1000.0 };
+
+    // https://immersive-web.github.io/webxr/#xrsession-promise-resolved
+    bool m_inputInitialized { false };
 };
 
 } // namespace WebCore

Modified: trunk/Source/WebCore/Modules/webxr/WebXRSpace.cpp (276432 => 276433)


--- trunk/Source/WebCore/Modules/webxr/WebXRSpace.cpp	2021-04-22 12:18:47 UTC (rev 276432)
+++ trunk/Source/WebCore/Modules/webxr/WebXRSpace.cpp	2021-04-22 14:06:06 UTC (rev 276433)
@@ -54,6 +54,11 @@
 }
 
 
+bool WebXRSpace::isPositionEmulated() const
+{
+    return session().isPositionEmulated();
+}
+
 WTF_MAKE_ISO_ALLOCATED_IMPL(WebXRViewerSpace);
 
 WebXRViewerSpace::WebXRViewerSpace(Document& document, WebXRSession& session)

Modified: trunk/Source/WebCore/Modules/webxr/WebXRSpace.h (276432 => 276433)


--- trunk/Source/WebCore/Modules/webxr/WebXRSpace.h	2021-04-22 12:18:47 UTC (rev 276432)
+++ trunk/Source/WebCore/Modules/webxr/WebXRSpace.h	2021-04-22 14:06:06 UTC (rev 276433)
@@ -47,6 +47,7 @@
     virtual WebXRSession& session() const = 0;
     virtual TransformationMatrix nativeOrigin() const = 0;
     TransformationMatrix effectiveOrigin() const;
+    virtual bool isPositionEmulated() const;
 
     virtual bool isReferenceSpace() const { return false; }
     virtual bool isBoundedReferenceSpace() const { return false; }

Modified: trunk/Source/WebCore/Modules/webxr/WebXRSystem.cpp (276432 => 276433)


--- trunk/Source/WebCore/Modules/webxr/WebXRSystem.cpp	2021-04-22 12:18:47 UTC (rev 276432)
+++ trunk/Source/WebCore/Modules/webxr/WebXRSystem.cpp	2021-04-22 14:06:06 UTC (rev 276433)
@@ -446,14 +446,7 @@
         promise.resolve(WTFMove(session));
         rejectPromiseWithNotSupportedError.release();
 
-        // FIXME:
-        // 5.4.10 Queue a task to perform the following steps: NOTE: These steps ensure that initial inputsourceschange
-        // events occur after the initial session is resolved.
-        //     1. Set session's promise resolved flag to true.
-        //     2. Let sources be any existing input sources attached to session.
-        //     3. If sources is non-empty, perform the following steps:
-        //        1. Set session's list of active XR input sources to sources.
-        //        2. Fire an XRInputSourcesChangeEvent named inputsourceschange on session with added set to sources.
+        // 5.4.10 is handled in WebXRSession::sessionDidInitializeInputSources.
     });
 }
 

Modified: trunk/Source/WebCore/Modules/webxr/XRHandedness.h (276432 => 276433)


--- trunk/Source/WebCore/Modules/webxr/XRHandedness.h	2021-04-22 12:18:47 UTC (rev 276432)
+++ trunk/Source/WebCore/Modules/webxr/XRHandedness.h	2021-04-22 14:06:06 UTC (rev 276433)
@@ -27,13 +27,11 @@
 
 #if ENABLE(WEBXR)
 
+#include "PlatformXR.h"
+
 namespace WebCore {
 
-enum class XRHandedness {
-    None,
-    Left,
-    Right,
-};
+using XRHandedness = PlatformXR::XRHandedness;
 
 } // namespace WebCore
 

Modified: trunk/Source/WebCore/Modules/webxr/XRInputSourceEvent.cpp (276432 => 276433)


--- trunk/Source/WebCore/Modules/webxr/XRInputSourceEvent.cpp	2021-04-22 12:18:47 UTC (rev 276432)
+++ trunk/Source/WebCore/Modules/webxr/XRInputSourceEvent.cpp	2021-04-22 14:06:06 UTC (rev 276433)
@@ -30,9 +30,12 @@
 
 #include "WebXRFrame.h"
 #include "WebXRInputSource.h"
+#include <wtf/IsoMallocInlines.h>
 
 namespace WebCore {
 
+WTF_MAKE_ISO_ALLOCATED_IMPL(XRInputSourceEvent);
+
 Ref<XRInputSourceEvent> XRInputSourceEvent::create(const AtomString& type, const Init& initializer, IsTrusted isTrusted)
 {
     return adoptRef(*new XRInputSourceEvent(type, initializer, isTrusted));
@@ -42,7 +45,6 @@
     : Event(type, initializer, isTrusted)
     , m_frame(initializer.frame)
     , m_inputSource(initializer.inputSource)
-    , m_buttonIndex(initializer.buttonIndex)
 {
     ASSERT(m_frame);
     ASSERT(m_inputSource);
@@ -60,9 +62,9 @@
     return *m_inputSource;
 }
 
-Optional<int> XRInputSourceEvent::buttonIndex() const
+void XRInputSourceEvent::setFrameActive(bool active)
 {
-    return m_buttonIndex;
+    m_frame->setActive(active);
 }
 
 } // namespace WebCore

Modified: trunk/Source/WebCore/Modules/webxr/XRInputSourceEvent.h (276432 => 276433)


--- trunk/Source/WebCore/Modules/webxr/XRInputSourceEvent.h	2021-04-22 12:18:47 UTC (rev 276432)
+++ trunk/Source/WebCore/Modules/webxr/XRInputSourceEvent.h	2021-04-22 14:06:06 UTC (rev 276433)
@@ -37,11 +37,11 @@
 class WebXRInputSource;
 
 class XRInputSourceEvent final : public Event {
+    WTF_MAKE_ISO_ALLOCATED(XRInputSourceEvent);
 public:
     struct Init : EventInit {
         RefPtr<WebXRFrame> frame;
         RefPtr<WebXRInputSource> inputSource;
-        Optional<int> buttonIndex;
     };
 
     static Ref<XRInputSourceEvent> create(const AtomString&, const Init&, IsTrusted = IsTrusted::No);
@@ -49,8 +49,10 @@
 
     const WebXRFrame& frame() const;
     const WebXRInputSource& inputSource() const;
-    Optional<int> buttonIndex() const;
+    void setFrameActive(bool);
 
+    EventInterface eventInterface() const final { return XRInputSourceEventInterfaceType; }
+
 private:
     XRInputSourceEvent(const AtomString&, const Init&, IsTrusted);
 

Modified: trunk/Source/WebCore/Modules/webxr/XRInputSourcesChangeEvent.h (276432 => 276433)


--- trunk/Source/WebCore/Modules/webxr/XRInputSourcesChangeEvent.h	2021-04-22 12:18:47 UTC (rev 276432)
+++ trunk/Source/WebCore/Modules/webxr/XRInputSourcesChangeEvent.h	2021-04-22 14:06:06 UTC (rev 276433)
@@ -52,6 +52,8 @@
     const Vector<RefPtr<WebXRInputSource>>& added() const;
     const Vector<RefPtr<WebXRInputSource>>& removed() const;
 
+    EventInterface eventInterface() const final { return XRInputSourcesChangeEventInterfaceType; }
+
 private:
     XRInputSourcesChangeEvent(const AtomString&, const Init&, IsTrusted);
 

Modified: trunk/Source/WebCore/Modules/webxr/XRInputSourcesChangeEvent.idl (276432 => 276433)


--- trunk/Source/WebCore/Modules/webxr/XRInputSourcesChangeEvent.idl	2021-04-22 12:18:47 UTC (rev 276432)
+++ trunk/Source/WebCore/Modules/webxr/XRInputSourcesChangeEvent.idl	2021-04-22 14:06:06 UTC (rev 276433)
@@ -41,6 +41,6 @@
     constructor(DOMString type, XRInputSourcesChangeEventInit eventInitDict);
 
     [SameObject] readonly attribute WebXRSession session;
-    [SameObject] readonly attribute FrozenArray<WebXRInputSource> added;
-    [SameObject] readonly attribute FrozenArray<WebXRInputSource> removed;
+    [CachedAttribute, SameObject] readonly attribute FrozenArray<WebXRInputSource> added;
+    [CachedAttribute, SameObject] readonly attribute FrozenArray<WebXRInputSource> removed;
 };

Modified: trunk/Source/WebCore/Modules/webxr/XRTargetRayMode.h (276432 => 276433)


--- trunk/Source/WebCore/Modules/webxr/XRTargetRayMode.h	2021-04-22 12:18:47 UTC (rev 276432)
+++ trunk/Source/WebCore/Modules/webxr/XRTargetRayMode.h	2021-04-22 14:06:06 UTC (rev 276433)
@@ -27,13 +27,11 @@
 
 #if ENABLE(WEBXR)
 
+#include "PlatformXR.h"
+
 namespace WebCore {
 
-enum class XRTargetRayMode {
-    Gaze,
-    TrackedPointer,
-    Screen,
-};
+using XRTargetRayMode = PlatformXR::XRTargetRayMode;
 
 } // namespace WebCore
 

Modified: trunk/Source/WebCore/Sources.txt (276432 => 276433)


--- trunk/Source/WebCore/Sources.txt	2021-04-22 12:18:47 UTC (rev 276432)
+++ trunk/Source/WebCore/Sources.txt	2021-04-22 14:06:06 UTC (rev 276433)
@@ -426,8 +426,10 @@
 Modules/webxr/NavigatorWebXR.cpp @no-unify
 Modules/webxr/WebXRBoundedReferenceSpace.cpp @no-unify
 Modules/webxr/WebXRFrame.cpp @no-unify
+Modules/webxr/WebXRGamepad.cpp @no-unify
 Modules/webxr/WebXRInputSource.cpp @no-unify
 Modules/webxr/WebXRInputSourceArray.cpp @no-unify
+Modules/webxr/WebXRInputSpace.cpp @no-unify
 Modules/webxr/WebXRLayer.cpp @no-unify
 Modules/webxr/WebXRPose.cpp @no-unify
 Modules/webxr/WebXRReferenceSpace.cpp @no-unify

Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (276432 => 276433)


--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2021-04-22 12:18:47 UTC (rev 276432)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2021-04-22 14:06:06 UTC (rev 276433)
@@ -416,6 +416,10 @@
 		119340A31FEE024000935F1E /* RenderTreeBuilderBlock.h in Headers */ = {isa = PBXBuildFile; fileRef = 119340A11FEE024000935F1E /* RenderTreeBuilderBlock.h */; };
 		1199FA46208E35A3002358CC /* LayoutContainerBox.h in Headers */ = {isa = PBXBuildFile; fileRef = 1199FA44208E35A3002358CC /* LayoutContainerBox.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		11CB2789203BA570004A1DC9 /* RenderTreeBuilderFullScreen.h in Headers */ = {isa = PBXBuildFile; fileRef = 11CB2787203BA570004A1DC9 /* RenderTreeBuilderFullScreen.h */; };
+		11E51638261E1A0600E69F25 /* WebXRInputSpace.h in Headers */ = {isa = PBXBuildFile; fileRef = 11E51635261E1A0500E69F25 /* WebXRInputSpace.h */; };
+		11E51639261E1A0600E69F25 /* WebXRInputSpace.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 11E51637261E1A0500E69F25 /* WebXRInputSpace.cpp */; };
+		11E5163C261E1A1500E69F25 /* WebXRGamepad.h in Headers */ = {isa = PBXBuildFile; fileRef = 11E5163A261E1A1400E69F25 /* WebXRGamepad.h */; };
+		11E5163D261E1A1500E69F25 /* WebXRGamepad.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 11E5163B261E1A1400E69F25 /* WebXRGamepad.cpp */; };
 		1400D7A817136EA70077CE05 /* ScriptWrappableInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = 1400D7A717136EA70077CE05 /* ScriptWrappableInlines.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		1403B99709EB13AF00797C7F /* DOMWindow.h in Headers */ = {isa = PBXBuildFile; fileRef = 1403B99509EB13AF00797C7F /* DOMWindow.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		1403BA0F09EB18F900797C7F /* JSDOMWindow.h in Copy Generated Headers */ = {isa = PBXBuildFile; fileRef = 1403BA0E09EB18F800797C7F /* JSDOMWindow.h */; settings = {ATTRIBUTES = (Private, ); }; };
@@ -6407,6 +6411,10 @@
 		11CB2786203BA570004A1DC9 /* RenderTreeBuilderFullScreen.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = RenderTreeBuilderFullScreen.cpp; sourceTree = "<group>"; };
 		11CB2787203BA570004A1DC9 /* RenderTreeBuilderFullScreen.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RenderTreeBuilderFullScreen.h; sourceTree = "<group>"; };
 		11D19C2E23159BAE008F24D3 /* TableFormattingContextGeometry.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = TableFormattingContextGeometry.cpp; sourceTree = "<group>"; };
+		11E51635261E1A0500E69F25 /* WebXRInputSpace.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebXRInputSpace.h; sourceTree = "<group>"; };
+		11E51637261E1A0500E69F25 /* WebXRInputSpace.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WebXRInputSpace.cpp; sourceTree = "<group>"; };
+		11E5163A261E1A1400E69F25 /* WebXRGamepad.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebXRGamepad.h; sourceTree = "<group>"; };
+		11E5163B261E1A1400E69F25 /* WebXRGamepad.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WebXRGamepad.cpp; sourceTree = "<group>"; };
 		11E6CF1B25F140E30013D3D5 /* JSWebXRReferenceSpaceCustom.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSWebXRReferenceSpaceCustom.cpp; sourceTree = "<group>"; };
 		11E6CF1D25F140E40013D3D5 /* JSWebXRSpaceCustom.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSWebXRSpaceCustom.cpp; sourceTree = "<group>"; };
 		11FF02D520BA3C810083F25B /* Verification.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Verification.cpp; sourceTree = "<group>"; };
@@ -28992,6 +29000,8 @@
 				E1EE8AF02412B17000E794D6 /* WebXRFrame.cpp */,
 				E1EE8AE32412B17000E794D6 /* WebXRFrame.h */,
 				E19490882434F15900416A99 /* WebXRFrame.idl */,
+				11E5163B261E1A1400E69F25 /* WebXRGamepad.cpp */,
+				11E5163A261E1A1400E69F25 /* WebXRGamepad.h */,
 				E1EE8B0D2412B17000E794D6 /* WebXRInputSource.cpp */,
 				E1EE8B172412B17000E794D6 /* WebXRInputSource.h */,
 				E19490892434F15A00416A99 /* WebXRInputSource.idl */,
@@ -28998,6 +29008,8 @@
 				E1EE8AE62412B17000E794D6 /* WebXRInputSourceArray.cpp */,
 				E1EE8ADD2412B17000E794D6 /* WebXRInputSourceArray.h */,
 				E19490932434F16000416A99 /* WebXRInputSourceArray.idl */,
+				11E51637261E1A0500E69F25 /* WebXRInputSpace.cpp */,
+				11E51635261E1A0500E69F25 /* WebXRInputSpace.h */,
 				E12FDAFB24A0FD1C0070236E /* WebXRLayer.cpp */,
 				E12FDAFD24A0FD1E0070236E /* WebXRLayer.h */,
 				E12FDAFE24A0FD1F0070236E /* WebXRLayer.idl */,
@@ -35782,8 +35794,10 @@
 				B10B6982140C174000BC1C26 /* WebVTTTokenizer.h in Headers */,
 				E1EE8B7E2413191F00E794D6 /* WebXRBoundedReferenceSpace.h in Headers */,
 				E1EE8B8A2413191F00E794D6 /* WebXRFrame.h in Headers */,
+				11E5163C261E1A1500E69F25 /* WebXRGamepad.h in Headers */,
 				E1EE8BA82413196300E794D6 /* WebXRInputSource.h in Headers */,
 				E1EE8B862413191F00E794D6 /* WebXRInputSourceArray.h in Headers */,
+				11E51638261E1A0600E69F25 /* WebXRInputSpace.h in Headers */,
 				E12FDB0024A0FD200070236E /* WebXRLayer.h in Headers */,
 				E1EE8B882413191F00E794D6 /* WebXRPose.h in Headers */,
 				E1EE8BA62413196300E794D6 /* WebXRReferenceSpace.h in Headers */,
@@ -37100,8 +37114,10 @@
 				CECDC93C21F2972900976BD1 /* WebVideoFullscreenControllerAVKit.mm in Sources */,
 				E1EE8B802413191F00E794D6 /* WebXRBoundedReferenceSpace.cpp in Sources */,
 				E1EE8B932413195000E794D6 /* WebXRFrame.cpp in Sources */,
+				11E5163D261E1A1500E69F25 /* WebXRGamepad.cpp in Sources */,
 				E1EE8BA12413196300E794D6 /* WebXRInputSource.cpp in Sources */,
 				E1EE8B8C2413191F00E794D6 /* WebXRInputSourceArray.cpp in Sources */,
+				11E51639261E1A0600E69F25 /* WebXRInputSpace.cpp in Sources */,
 				E12FDAFF24A0FD200070236E /* WebXRLayer.cpp in Sources */,
 				E1EE8B8B2413191F00E794D6 /* WebXRPose.cpp in Sources */,
 				E1EE8B7F2413191F00E794D6 /* WebXRReferenceSpace.cpp in Sources */,

Modified: trunk/Source/WebCore/platform/gamepad/GamepadConstants.cpp (276432 => 276433)


--- trunk/Source/WebCore/platform/gamepad/GamepadConstants.cpp	2021-04-22 12:18:47 UTC (rev 276432)
+++ trunk/Source/WebCore/platform/gamepad/GamepadConstants.cpp	2021-04-22 14:06:06 UTC (rev 276433)
@@ -43,7 +43,16 @@
     return standardGamepadMapping;
 }
 
+#if ENABLE(WEBXR)
+// https://immersive-web.github.io/webxr-gamepads-module/#dom-gamepadmappingtype-xr-standard
+const WTF::String& xrStandardGamepadMappingString()
+{
+    static NeverDestroyed<String> xrStandardGamepadMapping = "xr-standard";
+    return xrStandardGamepadMapping;
+}
+#endif
 
+
 } // namespace WebCore
 
 #endif // ENABLE(GAMEPAD)

Modified: trunk/Source/WebCore/platform/gamepad/GamepadConstants.h (276432 => 276433)


--- trunk/Source/WebCore/platform/gamepad/GamepadConstants.h	2021-04-22 12:18:47 UTC (rev 276432)
+++ trunk/Source/WebCore/platform/gamepad/GamepadConstants.h	2021-04-22 14:06:06 UTC (rev 276433)
@@ -62,6 +62,9 @@
 extern const GamepadButtonRole maximumGamepadButton;
 
 const WTF::String& standardGamepadMappingString();
+#if ENABLE(WEBXR)
+const WTF::String& xrStandardGamepadMappingString();
+#endif
 
 } // namespace WebCore
 

Modified: trunk/Source/WebCore/platform/xr/PlatformXR.h (276432 => 276433)


--- trunk/Source/WebCore/platform/xr/PlatformXR.h	2021-04-22 12:18:47 UTC (rev 276432)
+++ trunk/Source/WebCore/platform/xr/PlatformXR.h	2021-04-22 14:06:06 UTC (rev 276433)
@@ -56,16 +56,24 @@
 using LayerHandle = int;
 
 #if ENABLE(WEBXR)
+using InputSourceHandle = int;
 
-class TrackingAndRenderingClient : public CanMakeWeakPtr<TrackingAndRenderingClient> {
-public:
-    virtual ~TrackingAndRenderingClient() = default;
+// https://immersive-web.github.io/webxr/#enumdef-xrhandedness
+enum class XRHandedness {
+    None,
+    Left,
+    Right,
+};
 
-    virtual void sessionDidEnd() = 0;
-    // FIXME: handle frame update
-    // FIXME: handle visibility changes
+// https://immersive-web.github.io/webxr/#enumdef-xrtargetraymode
+enum class XRTargetRayMode {
+    Gaze,
+    TrackedPointer,
+    Screen,
 };
 
+class TrackingAndRenderingClient;
+
 class Device : public ThreadSafeRefCounted<Device>, public CanMakeWeakPtr<Device> {
     WTF_MAKE_FAST_ALLOCATED;
     WTF_MAKE_NONCOPYABLE(Device);
@@ -163,6 +171,28 @@
             template<class Decoder> static Optional<LayerData> decode(Decoder&);
         };
 
+        struct InputSourceButton {
+            bool touched { false };
+            bool pressed { false };
+            float pressedValue { 0 };
+        };
+
+        struct InputSourcePose {
+            Pose pose;
+            bool isPositionEmulated { false };
+        };
+
+        struct InputSource {
+            InputSourceHandle handle { 0 };
+            XRHandedness handeness { XRHandedness::None };
+            XRTargetRayMode targetRayMode { XRTargetRayMode::Gaze };
+            Vector<String> profiles;
+            InputSourcePose pointerOrigin;
+            Optional<InputSourcePose> gripOrigin;
+            Vector<InputSourceButton> buttons;
+            Vector<float> axes;
+        };
+
         bool isTrackingValid { false };
         bool isPositionValid { false };
         bool isPositionEmulated { false };
@@ -173,6 +203,7 @@
         StageParameters stageParameters;
         Vector<View> views;
         HashMap<LayerHandle, LayerData> layers;
+        Vector<InputSource> inputSources;
 
         template<class Encoder> void encode(Encoder&) const;
         template<class Decoder> static Optional<FrameData> decode(Decoder&);
@@ -214,6 +245,19 @@
     WeakPtr<TrackingAndRenderingClient> m_trackingAndRenderingClient;
 };
 
+class TrackingAndRenderingClient : public CanMakeWeakPtr<TrackingAndRenderingClient> {
+public:
+    virtual ~TrackingAndRenderingClient() = default;
+
+    // This event is used to ensure that initial inputsourceschange events occur after the initial session is resolved.
+    // WebxR apps can wait for the input source events before calling requestAnimationFrame.
+    // Per-frame input source updates are handled via session.requestAnimationFrame which calls Device::requestFrame.
+    virtual void sessionDidInitializeInputSources(Vector<Device::FrameData::InputSource>&&) = 0;
+    virtual void sessionDidEnd() = 0;
+    // FIXME: handle frame update
+    // FIXME: handle visibility changes
+};
+
 class Instance {
 public:
     WEBCORE_EXPORT static Instance& singleton();

Modified: trunk/Source/WebCore/testing/WebFakeXRDevice.cpp (276432 => 276433)


--- trunk/Source/WebCore/testing/WebFakeXRDevice.cpp	2021-04-22 12:18:47 UTC (rev 276432)
+++ trunk/Source/WebCore/testing/WebFakeXRDevice.cpp	2021-04-22 14:06:06 UTC (rev 276433)
@@ -106,6 +106,19 @@
     attributes.stencil = false;
     attributes.antialias = false;
     m_gl = GraphicsContextGL::create(attributes, nullptr);
+
+    if (m_trackingAndRenderingClient) {
+        // WebXR FakeDevice waits for simulateInputConnection calls to add input sources-
+        // There is no way to know how many simulateInputConnection calls will the device receive,
+        // so notify the input sources have been initialized with an empty list. This is not a problem because
+        // WPT tests rely on requestAnimationFrame updates to test the input sources.
+        callOnMainThread([this, weakThis = makeWeakPtr(*this)]() {
+            if (!weakThis)
+                return;
+            if (m_trackingAndRenderingClient)
+                m_trackingAndRenderingClient->sessionDidInitializeInputSources({ });
+        });
+    }
 }
 
 void SimulatedXRDevice::shutDownTrackingAndRendering()
@@ -134,6 +147,11 @@
     for (auto& layer : m_layers)
         data.layers.add(layer.key, FrameData::LayerData { .opaqueTexture = layer.value });
 
+    for (auto& input : m_inputConnections) {
+        if (input->isConnected())
+            data.inputSources.append(input->getFrameData());
+    }
+
     if (m_FrameCallback)
         m_FrameCallback(WTFMove(data));
 }
@@ -239,9 +257,12 @@
 {
 }
 
-Ref<WebFakeXRInputController> WebFakeXRDevice::simulateInputSourceConnection(FakeXRInputSourceInit)
+Ref<WebFakeXRInputController> WebFakeXRDevice::simulateInputSourceConnection(const FakeXRInputSourceInit& init)
 {
-    return WebFakeXRInputController::create();
+    auto handle = ++mInputSourceHandleIndex;
+    auto input = WebFakeXRInputController::create(handle, init);
+    m_device.addInputConnection(input.copyRef());
+    return input;
 }
 
 ExceptionOr<PlatformXR::Device::FrameData::Pose> WebFakeXRDevice::parseRigidTransform(const FakeXRRigidTransformInit& init)

Modified: trunk/Source/WebCore/testing/WebFakeXRDevice.h (276432 => 276433)


--- trunk/Source/WebCore/testing/WebFakeXRDevice.h	2021-04-22 12:18:47 UTC (rev 276432)
+++ trunk/Source/WebCore/testing/WebFakeXRDevice.h	2021-04-22 14:06:06 UTC (rev 276433)
@@ -80,6 +80,7 @@
     void setSupportsShutdownNotification(bool supportsShutdownNotification) { m_supportsShutdownNotification = supportsShutdownNotification; }
     void simulateShutdownCompleted();
     void scheduleOnNextFrame(Function<void()>&&);
+    void addInputConnection(Ref<WebFakeXRInputController>&& input) { m_inputConnections.append(WTFMove(input)); };
 private:
     WebCore::IntSize recommendedResolution(PlatformXR::SessionMode) final;
     void initializeTrackingAndRendering(PlatformXR::SessionMode) final;
@@ -101,6 +102,7 @@
     RefPtr<WebCore::GraphicsContextGL> m_gl;
     HashMap<PlatformXR::LayerHandle, PlatformGLObject> m_layers;
     uint32_t m_layerIndex { 0 };
+    Vector<Ref<WebFakeXRInputController>> m_inputConnections;
 };
 
 class WebFakeXRDevice final : public RefCounted<WebFakeXRDevice> {
@@ -116,18 +118,19 @@
     void setFloorOrigin(FakeXRRigidTransformInit);
     void clearFloorOrigin() { m_device.setFloorOrigin(WTF::nullopt); }
     void simulateResetPose();
-    Ref<WebFakeXRInputController> simulateInputSourceConnection(FakeXRInputSourceInit);
+    Ref<WebFakeXRInputController> simulateInputSourceConnection(const FakeXRInputSourceInit&);
     static ExceptionOr<Ref<FakeXRView>> parseView(const FakeXRViewInit&);
     SimulatedXRDevice& simulatedXRDevice() { return m_device; }
     void setSupportsShutdownNotification();
     void simulateShutdown();
 
+    static ExceptionOr<PlatformXR::Device::FrameData::Pose> parseRigidTransform(const FakeXRRigidTransformInit&);
+
 private:
     WebFakeXRDevice();
 
-    static ExceptionOr<PlatformXR::Device::FrameData::Pose> parseRigidTransform(const FakeXRRigidTransformInit&);
-
     SimulatedXRDevice m_device;
+    PlatformXR::InputSourceHandle mInputSourceHandleIndex { 0 };
 };
 
 } // namespace WebCore

Modified: trunk/Source/WebCore/testing/WebFakeXRInputController.cpp (276432 => 276433)


--- trunk/Source/WebCore/testing/WebFakeXRInputController.cpp	2021-04-22 12:18:47 UTC (rev 276432)
+++ trunk/Source/WebCore/testing/WebFakeXRInputController.cpp	2021-04-22 14:06:06 UTC (rev 276433)
@@ -27,63 +27,153 @@
 #include "WebFakeXRInputController.h"
 
 #if ENABLE(WEBXR)
+#include "WebFakeXRDevice.h"
 
 namespace WebCore {
 
-void WebFakeXRInputController::setHandedness(XRHandedness)
-{
-}
+using InputSource = PlatformXR::Device::FrameData::InputSource;
+using InputSourceButton = PlatformXR::Device::FrameData::InputSourceButton;
+using InputSourcePose = PlatformXR::Device::FrameData::InputSourcePose;
+using ButtonType = FakeXRButtonStateInit::Type;
 
-void WebFakeXRInputController::setTargetRayMode(XRTargetRayMode)
+// https://immersive-web.github.io/webxr-gamepads-module/#xr-standard-gamepad-mapping
+constexpr std::array<ButtonType, 5> XR_STANDARD_BUTTONS = { ButtonType::Grip, ButtonType::Touchpad, ButtonType::Thumbstick, ButtonType::OptionalButton, ButtonType::OptionalThumbstick };
+
+Ref<WebFakeXRInputController> WebFakeXRInputController::create(PlatformXR::InputSourceHandle handle, const FakeXRInputSourceInit& init)
 {
+    return adoptRef(*new WebFakeXRInputController(handle, init));
 }
 
-void WebFakeXRInputController::setProfiles(Vector<String>)
+WebFakeXRInputController::WebFakeXRInputController(PlatformXR::InputSourceHandle handle, const FakeXRInputSourceInit& init)
+    : m_handle(handle)
+    , m_handeness(init.handedness)
+    , m_targetRayMode(init.targetRayMode)
+    , m_profiles(init.profiles)
+    , m_primarySelected(init.selectionStarted)
+    , m_simulateSelect(init.selectionClicked)
 {
+    setPointerOrigin(init.pointerOrigin, false);
+    setGripOrigin(init.gripOrigin, false);
+    setSupportedButtons(init.supportedButtons);
 }
 
 void WebFakeXRInputController::setGripOrigin(FakeXRRigidTransformInit gripOrigin, bool emulatedPosition)
 {
-    UNUSED_PARAM(gripOrigin);
-    UNUSED_PARAM(emulatedPosition);
-}
+    auto transform = WebFakeXRDevice::parseRigidTransform(gripOrigin);
+    if (transform.hasException())
+        return;
+    m_gripOrigin = InputSourcePose { transform.releaseReturnValue(), emulatedPosition };
+}   
 
-void WebFakeXRInputController::clearGripOrigin()
-{
-}
-
 void WebFakeXRInputController::setPointerOrigin(FakeXRRigidTransformInit pointerOrigin, bool emulatedPosition)
 {
-    UNUSED_PARAM(pointerOrigin);
-    UNUSED_PARAM(emulatedPosition);
+    auto transform = WebFakeXRDevice::parseRigidTransform(pointerOrigin);
+    if (transform.hasException())
+        return;
+    m_pointerOrigin = { transform.releaseReturnValue(), emulatedPosition };
 }
 
 void WebFakeXRInputController::disconnect()
 {
+    m_connected = false;
 }
 
 void WebFakeXRInputController::reconnect()
 {
+    m_connected = true;
 }
 
-void WebFakeXRInputController::startSelection()
+void WebFakeXRInputController::setSupportedButtons(const Vector<FakeXRButtonStateInit>& buttons)
 {
+    m_buttons.clear();
+    for (auto& button : buttons)
+        m_buttons.add(button.buttonType, button);
 }
 
-void WebFakeXRInputController::endSelection()
+void WebFakeXRInputController::updateButtonState(const FakeXRButtonStateInit& init)
 {
+    auto it = m_buttons.find(init.buttonType);
+    if (it != m_buttons.end())
+        it->value = init;
 }
 
-void WebFakeXRInputController::simulateSelect()
+InputSource WebFakeXRInputController::getFrameData()
 {
+    InputSource state;
+    state.handle = m_handle;
+    state.handeness = m_handeness;
+    state.targetRayMode = m_targetRayMode;
+    state.profiles = m_profiles;
+    state.pointerOrigin = m_pointerOrigin;
+    state.gripOrigin = m_gripOrigin;
+
+    if (m_simulateSelect)
+        m_primarySelected = true;
+
+    // https://immersive-web.github.io/webxr-gamepads-module/#xr-standard-gamepad-mapping
+    // Mimic xr-standard gamepad layout
+
+    // Primary trigger is required and must be at index 0
+    state.buttons.append({
+        .touched = m_primarySelected,
+        .pressed = m_primarySelected,
+        .pressedValue = m_primarySelected ? 1.0f : 0.0f
+    });
+
+    // Next buttons in xr-standard order
+    for (auto buttonType : XR_STANDARD_BUTTONS) {
+        auto data = ""
+        if (data.button)
+            state.buttons.append(*data.button);
+        if (data.axes)
+            state.axes.appendVector(*data.axes);
+
+    }
+
+    if (m_simulateSelect) {
+        m_primarySelected = false;
+        m_simulateSelect = false;
+    }
+
+    return state;
 }
 
-void WebFakeXRInputController::setSupportedButtons(Vector<FakeXRButtonStateInit>)
+WebFakeXRInputController::ButtonOrPlaceholder WebFakeXRInputController::getButtonOrPlaceholder(FakeXRButtonStateInit::Type buttonType) const
 {
-}
+    ButtonOrPlaceholder result;
 
-void WebFakeXRInputController::updateButtonState(FakeXRButtonStateInit)
-{
+    auto it = m_buttons.find(buttonType);
+    if (it != m_buttons.end()) {
+        result.button = InputSourceButton {
+            .touched = it->value.touched,
+            .pressed = it->value.pressed,
+            .pressedValue = it->value.pressedValue
+        };
+
+        if (buttonType == ButtonType::Touchpad || buttonType == ButtonType::Thumbstick)
+            result.axes = Vector<float> { it->value.xValue, it->value.yValue };
+
+    } else {
+        // Add a placeholder if needed
+        // Devices that lack one of the optional inputs listed in the tables above MUST preserve their place in the
+        // buttons or axes array, reporting a placeholder button or placeholder axis, respectively.
+        if (buttonType != ButtonType::OptionalButton || buttonType != ButtonType::OptionalThumbstick) {
+            auto priority = std::find(XR_STANDARD_BUTTONS.begin(), XR_STANDARD_BUTTONS.end(), buttonType);
+            ASSERT(priority != XR_STANDARD_BUTTONS.end());
+
+            for (auto it = priority + 1; it != XR_STANDARD_BUTTONS.end(); ++it) {
+                if (m_buttons.contains(*it)) {
+                    result.button = InputSourceButton();
+                    break;
+                }
+            }
+        }
+
+        if (buttonType == ButtonType::Touchpad && m_buttons.contains(ButtonType::Thumbstick))
+            result.axes = Vector<float> { 0.0, 0.0 };
+    }
+
+    return result;
 }
 
 } // namespace WebCore

Modified: trunk/Source/WebCore/testing/WebFakeXRInputController.h (276432 => 276433)


--- trunk/Source/WebCore/testing/WebFakeXRInputController.h	2021-04-22 12:18:47 UTC (rev 276432)
+++ trunk/Source/WebCore/testing/WebFakeXRInputController.h	2021-04-22 14:06:06 UTC (rev 276433)
@@ -28,9 +28,12 @@
 #if ENABLE(WEBXR)
 
 #include "FakeXRButtonStateInit.h"
+#include "FakeXRInputSourceInit.h"
 #include "FakeXRRigidTransformInit.h"
+#include "PlatformXR.h"
 #include "XRHandedness.h"
 #include "XRTargetRayMode.h"
+#include <wtf/HashMap.h>
 #include <wtf/RefCounted.h>
 #include <wtf/Vector.h>
 
@@ -38,36 +41,44 @@
 
 class WebFakeXRInputController final : public RefCounted<WebFakeXRInputController> {
 public:
-    static Ref<WebFakeXRInputController> create() { return adoptRef(*new WebFakeXRInputController); }
+    static Ref<WebFakeXRInputController> create(PlatformXR::InputSourceHandle, const FakeXRInputSourceInit&);
 
-    void setHandedness(XRHandedness);
-
-    void setTargetRayMode(XRTargetRayMode);
-
-    void setProfiles(Vector<String>);
-
+    void setHandedness(XRHandedness handeness) { m_handeness = handeness; }
+    void setTargetRayMode(XRTargetRayMode mode) { m_targetRayMode = mode; }
+    void setProfiles(Vector<String>&& profiles) { m_profiles = WTFMove(profiles); }
     void setGripOrigin(FakeXRRigidTransformInit gripOrigin, bool emulatedPosition = false);
-
-    void clearGripOrigin();
-
+    void clearGripOrigin() { m_gripOrigin = WTF::nullopt; }
     void setPointerOrigin(FakeXRRigidTransformInit pointerOrigin, bool emulatedPosition = false);
-
     void disconnect();
-
     void reconnect();
+    void startSelection() { m_primarySelected = true; }
+    void endSelection() { m_primarySelected = false; }
+    void simulateSelect() { m_simulateSelect = true; }
+    void setSupportedButtons(const Vector<FakeXRButtonStateInit>&);
+    void updateButtonState(const FakeXRButtonStateInit&);
+    bool isConnected() const { return m_connected; }
 
-    void startSelection();
+    PlatformXR::Device::FrameData::InputSource getFrameData();
 
-    void endSelection();
+private:
+    WebFakeXRInputController(PlatformXR::InputSourceHandle, const FakeXRInputSourceInit&);
 
-    void simulateSelect();
+    struct ButtonOrPlaceholder {
+        Optional<PlatformXR::Device::FrameData::InputSourceButton> button;
+        Optional<Vector<float>> axes;
+    };
+    ButtonOrPlaceholder getButtonOrPlaceholder(FakeXRButtonStateInit::Type) const;
 
-    void setSupportedButtons(Vector<FakeXRButtonStateInit>);
-
-    void updateButtonState(FakeXRButtonStateInit);
-
-private:
-    WebFakeXRInputController() = default;
+    PlatformXR::InputSourceHandle m_handle { 0 };
+    XRHandedness m_handeness { XRHandedness::None };
+    XRTargetRayMode m_targetRayMode { XRTargetRayMode::Gaze };
+    Vector<String> m_profiles;
+    PlatformXR::Device::FrameData::InputSourcePose m_pointerOrigin;
+    Optional<PlatformXR::Device::FrameData::InputSourcePose> m_gripOrigin;
+    HashMap<FakeXRButtonStateInit::Type, FakeXRButtonStateInit, WTF::IntHash<FakeXRButtonStateInit::Type>, WTF::StrongEnumHashTraits<FakeXRButtonStateInit::Type>> m_buttons;
+    bool m_connected { true };
+    bool m_primarySelected { false };
+    bool m_simulateSelect { false };
 };
 
 } // namespace WebCore

Modified: trunk/Source/cmake/OptionsWPE.cmake (276432 => 276433)


--- trunk/Source/cmake/OptionsWPE.cmake	2021-04-22 12:18:47 UTC (rev 276432)
+++ trunk/Source/cmake/OptionsWPE.cmake	2021-04-22 14:06:06 UTC (rev 276433)
@@ -205,6 +205,7 @@
     if (NOT OPENXR_FOUND)
         message(FATAL_ERROR "OpenXR is required to enable WebXR support.")
     endif ()
+    SET_AND_EXPOSE_TO_BUILD(ENABLE_GAMEPAD ON)
     SET_AND_EXPOSE_TO_BUILD(USE_OPENXR ${OpenXR_FOUND})
     SET_AND_EXPOSE_TO_BUILD(XR_USE_PLATFORM_EGL TRUE)
     SET_AND_EXPOSE_TO_BUILD(XR_USE_GRAPHICS_API_OPENGL TRUE)
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to