Diff
Modified: trunk/LayoutTests/ChangeLog (292779 => 292780)
--- trunk/LayoutTests/ChangeLog 2022-04-12 18:08:56 UTC (rev 292779)
+++ trunk/LayoutTests/ChangeLog 2022-04-12 18:52:27 UTC (rev 292780)
@@ -1,3 +1,33 @@
+2022-04-12 Ada Chan <[email protected]>
+
+ [WebXR] Implement the WebXRFrame methods for getting joints' poses and radii
+ https://bugs.webkit.org/show_bug.cgi?id=238968
+
+ Reviewed by Dean Jackson.
+
+ Add more constants for a valid joint value and device init dictionary
+ that represents a device with hand tracking support enabled.
+
+ Add new tests for testing hand input related methods in XRFrame.
+
+ * http/wpt/webxr/resources/webxr_test_constants_single_view.js:
+ * http/wpt/webxr/xrFrame_fillJointRadii-expected.txt: Added.
+ * http/wpt/webxr/xrFrame_fillJointRadii.html: Added.
+ * http/wpt/webxr/xrFrame_fillJointRadii_missing_joint_pose-expected.txt: Added.
+ * http/wpt/webxr/xrFrame_fillJointRadii_missing_joint_pose.html: Added.
+ * http/wpt/webxr/xrFrame_fillPoses-expected.txt: Added.
+ * http/wpt/webxr/xrFrame_fillPoses.html: Added.
+ * http/wpt/webxr/xrFrame_fillPoses_missing_joint_pose-expected.txt: Added.
+ * http/wpt/webxr/xrFrame_fillPoses_missing_joint_pose.html: Added.
+ * http/wpt/webxr/xrFrame_getJointPose-expected.txt: Added.
+ * http/wpt/webxr/xrFrame_getJointPose.html: Added.
+ * http/wpt/webxr/xrFrame_getJointPose_missing_joint_pose-expected.txt: Added.
+ * http/wpt/webxr/xrFrame_getJointPose_missing_joint_pose.html: Added.
+ * http/wpt/webxr/xrHand-expected.txt: Added.
+ * http/wpt/webxr/xrHand.html: Added.
+ * http/wpt/webxr/xrHandInput_gc.html:
+ * platform/win/TestExpectations: Skip other folders with WebXR tests
+
2022-04-12 Karl Rackler <[email protected]>
REGRESSION (r292043): [ Mac ] fast/block/positioning/fixed-container-with-relative-parent.html is a flaky image failure
Modified: trunk/LayoutTests/http/wpt/webxr/resources/webxr_test_constants_single_view.js (292779 => 292780)
--- trunk/LayoutTests/http/wpt/webxr/resources/webxr_test_constants_single_view.js 2022-04-12 18:08:56 UTC (rev 292779)
+++ trunk/LayoutTests/http/wpt/webxr/resources/webxr_test_constants_single_view.js 2022-04-12 18:52:27 UTC (rev 292780)
@@ -47,6 +47,74 @@
orientation: [0, 0, 0, 1]
};
+const JOINT_COUNT = 25;
+const TEST_HAND_JOINT_RADIUS = 0.02;
+
+const VALID_HAND_JOINT = {
+ pose: VALID_POSE_TRANSFORM,
+ radius: TEST_HAND_JOINT_RADIUS
+};
+
+const VALID_HAND_JOINTS = [
+ VALID_HAND_JOINT,
+ VALID_HAND_JOINT,
+ VALID_HAND_JOINT,
+ VALID_HAND_JOINT,
+ VALID_HAND_JOINT,
+ VALID_HAND_JOINT,
+ VALID_HAND_JOINT,
+ VALID_HAND_JOINT,
+ VALID_HAND_JOINT,
+ VALID_HAND_JOINT,
+ VALID_HAND_JOINT,
+ VALID_HAND_JOINT,
+ VALID_HAND_JOINT,
+ VALID_HAND_JOINT,
+ VALID_HAND_JOINT,
+ VALID_HAND_JOINT,
+ VALID_HAND_JOINT,
+ VALID_HAND_JOINT,
+ VALID_HAND_JOINT,
+ VALID_HAND_JOINT,
+ VALID_HAND_JOINT,
+ VALID_HAND_JOINT,
+ VALID_HAND_JOINT,
+ VALID_HAND_JOINT,
+ VALID_HAND_JOINT
+];
+
+const INVALID_HAND_JOINT = {
+
+};
+
+const HAND_JOINTS_WITH_ONE_INVALID = [
+ VALID_HAND_JOINT,
+ VALID_HAND_JOINT,
+ VALID_HAND_JOINT,
+ VALID_HAND_JOINT,
+ VALID_HAND_JOINT,
+ VALID_HAND_JOINT,
+ VALID_HAND_JOINT,
+ VALID_HAND_JOINT,
+ VALID_HAND_JOINT,
+ VALID_HAND_JOINT,
+ VALID_HAND_JOINT,
+ VALID_HAND_JOINT,
+ VALID_HAND_JOINT,
+ VALID_HAND_JOINT,
+ VALID_HAND_JOINT,
+ VALID_HAND_JOINT,
+ VALID_HAND_JOINT,
+ VALID_HAND_JOINT,
+ VALID_HAND_JOINT,
+ VALID_HAND_JOINT,
+ VALID_HAND_JOINT,
+ VALID_HAND_JOINT,
+ VALID_HAND_JOINT,
+ VALID_HAND_JOINT,
+ INVALID_HAND_JOINT
+];
+
// A valid input pointer offset for when we don't care about specific values
const VALID_POINTER = [1, 0, 0, 0,
0, 1, 0, 0,
@@ -160,6 +228,17 @@
interactionMode: "world-space"
};
+const TRACKED_IMMERSIVE_DEVICE_WITH_HAND_TRACKING = {
+ supportsImmersive: true,
+ supportedModes: [ "inline", "immersive-vr"],
+ views: VALID_VIEWS,
+ viewerOrigin: IDENTITY_TRANSFORM,
+ supportedFeatures: ALL_FEATURES,
+ enabledFeatures: [ "hand-tracking" ],
+ environmentBlendMode: "opaque",
+ interactionMode: "world-space"
+};
+
const TRACKED_IMMERSIVE_DEVICE_NO_HAND_TRACKING = {
supportsImmersive: true,
supportedModes: [ "inline", "immersive-vr"],
Added: trunk/LayoutTests/http/wpt/webxr/xrFrame_fillJointRadii-expected.txt (0 => 292780)
--- trunk/LayoutTests/http/wpt/webxr/xrFrame_fillJointRadii-expected.txt (rev 0)
+++ trunk/LayoutTests/http/wpt/webxr/xrFrame_fillJointRadii-expected.txt 2022-04-12 18:52:27 UTC (rev 292780)
@@ -0,0 +1,4 @@
+
+PASS Test XRFrame.fillJointRadii - webgl
+PASS Test XRFrame.fillJointRadii - webgl2
+
Added: trunk/LayoutTests/http/wpt/webxr/xrFrame_fillJointRadii.html (0 => 292780)
--- trunk/LayoutTests/http/wpt/webxr/xrFrame_fillJointRadii.html (rev 0)
+++ trunk/LayoutTests/http/wpt/webxr/xrFrame_fillJointRadii.html 2022-04-12 18:52:27 UTC (rev 292780)
@@ -0,0 +1,52 @@
+<!DOCTYPE html>
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+
+<script>
+let testName = "Test XRFrame.fillJointRadii";
+
+let fakeDeviceInitParams = TRACKED_IMMERSIVE_DEVICE_WITH_HAND_TRACKING;
+
+let testFunction = function(session, fakeDeviceController, t, sessionObjects) {
+
+ let input_source = fakeDeviceController.simulateInputSourceConnection({
+ handedness: "none",
+ targetRayMode: "tracked-pointer",
+ pointerOrigin: VALID_POINTER_TRANSFORM,
+ profiles: [],
+ handJoints: VALID_HAND_JOINTS,
+ });
+
+ return session.requestReferenceSpace('local')
+ .then((referenceSpace) => new Promise((resolve) => {
+
+ function onFrame(time, xrFrame) {
+ assert_not_equals(session.inputSources.length, 0);
+ let hand = session.inputSources[0].hand
+ assert_not_equals(hand, null);
+
+ assert_throws_js(TypeError, function() {
+ let radiiArrayWithWrongSize = new Float32Array(JOINT_COUNT - 1);
+ xrFrame.fillJointRadii(hand.values(), radiiArrayWithWrongSize);
+ });
+
+ let radii = new Float32Array(JOINT_COUNT);
+ let allValid = xrFrame.fillJointRadii(hand.values(), radii);
+ assert_true(allValid);
+ for (radius of radii) {
+ assert_approx_equals(radius, TEST_HAND_JOINT_RADIUS, FLOAT_EPSILON);
+ }
+
+ resolve();
+ }
+ session.requestAnimationFrame(onFrame);
+ }));
+};
+
+xr_session_promise_test(
+ testName, testFunction, fakeDeviceInitParams, 'immersive-vr', { optionalFeatures: ["hand-tracking"] });
+
+</script>
Added: trunk/LayoutTests/http/wpt/webxr/xrFrame_fillJointRadii_missing_joint_pose-expected.txt (0 => 292780)
--- trunk/LayoutTests/http/wpt/webxr/xrFrame_fillJointRadii_missing_joint_pose-expected.txt (rev 0)
+++ trunk/LayoutTests/http/wpt/webxr/xrFrame_fillJointRadii_missing_joint_pose-expected.txt 2022-04-12 18:52:27 UTC (rev 292780)
@@ -0,0 +1,4 @@
+
+PASS Test XRFrame.fillJointRadii where the hand has one missing joint pose - webgl
+PASS Test XRFrame.fillJointRadii where the hand has one missing joint pose - webgl2
+
Added: trunk/LayoutTests/http/wpt/webxr/xrFrame_fillJointRadii_missing_joint_pose.html (0 => 292780)
--- trunk/LayoutTests/http/wpt/webxr/xrFrame_fillJointRadii_missing_joint_pose.html (rev 0)
+++ trunk/LayoutTests/http/wpt/webxr/xrFrame_fillJointRadii_missing_joint_pose.html 2022-04-12 18:52:27 UTC (rev 292780)
@@ -0,0 +1,48 @@
+<!DOCTYPE html>
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+
+<script>
+let testName = "Test XRFrame.fillJointRadii where the hand has one missing joint pose";
+
+let fakeDeviceInitParams = TRACKED_IMMERSIVE_DEVICE_WITH_HAND_TRACKING;
+
+let testFunction = function(session, fakeDeviceController, t, sessionObjects) {
+
+ let input_source = fakeDeviceController.simulateInputSourceConnection({
+ handedness: "none",
+ targetRayMode: "tracked-pointer",
+ pointerOrigin: VALID_POINTER_TRANSFORM,
+ profiles: [],
+ handJoints: HAND_JOINTS_WITH_ONE_INVALID,
+ });
+
+ return session.requestReferenceSpace('local')
+ .then((referenceSpace) => new Promise((resolve) => {
+
+ function onFrame(time, xrFrame) {
+ assert_not_equals(session.inputSources.length, 0);
+ let hand = session.inputSources[0].hand
+ assert_not_equals(hand, null);
+ assert_equals(hand.size, JOINT_COUNT);
+
+ let radii = new Float32Array(JOINT_COUNT);
+ let allValid = xrFrame.fillJointRadii(hand.values(), radii);
+ assert_false(allValid);
+ for (radius of radii) {
+ assert_equals(radius, NaN);
+ }
+
+ resolve();
+ }
+ session.requestAnimationFrame(onFrame);
+ }));
+};
+
+xr_session_promise_test(
+ testName, testFunction, fakeDeviceInitParams, 'immersive-vr', { optionalFeatures: ["hand-tracking"] });
+
+</script>
Added: trunk/LayoutTests/http/wpt/webxr/xrFrame_fillPoses-expected.txt (0 => 292780)
--- trunk/LayoutTests/http/wpt/webxr/xrFrame_fillPoses-expected.txt (rev 0)
+++ trunk/LayoutTests/http/wpt/webxr/xrFrame_fillPoses-expected.txt 2022-04-12 18:52:27 UTC (rev 292780)
@@ -0,0 +1,4 @@
+
+PASS Test XRFrame.fillPoses - webgl
+PASS Test XRFrame.fillPoses - webgl2
+
Added: trunk/LayoutTests/http/wpt/webxr/xrFrame_fillPoses.html (0 => 292780)
--- trunk/LayoutTests/http/wpt/webxr/xrFrame_fillPoses.html (rev 0)
+++ trunk/LayoutTests/http/wpt/webxr/xrFrame_fillPoses.html 2022-04-12 18:52:27 UTC (rev 292780)
@@ -0,0 +1,57 @@
+<!DOCTYPE html>
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+
+<script>
+let testName = "Test XRFrame.fillPoses";
+
+let fakeDeviceInitParams = TRACKED_IMMERSIVE_DEVICE_WITH_HAND_TRACKING;
+
+let testFunction = function(session, fakeDeviceController, t, sessionObjects) {
+
+ let input_source = fakeDeviceController.simulateInputSourceConnection({
+ handedness: "none",
+ targetRayMode: "tracked-pointer",
+ pointerOrigin: VALID_POINTER_TRANSFORM,
+ profiles: [],
+ handJoints: VALID_HAND_JOINTS,
+ });
+
+ return session.requestReferenceSpace('local')
+ .then((referenceSpace) => new Promise((resolve) => {
+
+ function onFrame(time, xrFrame) {
+ assert_not_equals(session.inputSources.length, 0);
+ let hand = session.inputSources[0].hand
+ assert_not_equals(hand, null);
+
+ const floatsPerTransform = 16;
+ assert_throws_js(TypeError, function() {
+ let transformsArrayWithWrongSize = new Float32Array(JOINT_COUNT * floatsPerTransform - 1);
+ xrFrame.fillPoses(hand.values(), transformsArrayWithWrongSize);
+ });
+
+ let transforms = new Float32Array(JOINT_COUNT * floatsPerTransform);
+ let allValid = xrFrame.fillPoses(hand.values(), referenceSpace, transforms);
+ assert_true(allValid);
+
+ for (var i = 0; i < JOINT_COUNT; ++i) {
+ let transformStartIndex = i * floatsPerTransform;
+ for (var j = 0; j < floatsPerTransform; ++j) {
+ assert_approx_equals(transforms[transformStartIndex + j], VALID_POSE_MATRIX[j], FLOAT_EPSILON);
+ }
+ }
+
+ resolve();
+ }
+ session.requestAnimationFrame(onFrame);
+ }));
+};
+
+xr_session_promise_test(
+ testName, testFunction, fakeDeviceInitParams, 'immersive-vr', { optionalFeatures: ["hand-tracking"] });
+
+</script>
Added: trunk/LayoutTests/http/wpt/webxr/xrFrame_fillPoses_missing_joint_pose-expected.txt (0 => 292780)
--- trunk/LayoutTests/http/wpt/webxr/xrFrame_fillPoses_missing_joint_pose-expected.txt (rev 0)
+++ trunk/LayoutTests/http/wpt/webxr/xrFrame_fillPoses_missing_joint_pose-expected.txt 2022-04-12 18:52:27 UTC (rev 292780)
@@ -0,0 +1,4 @@
+
+PASS Test XRFrame.fillPoses where the hand has one missing joint pose - webgl
+PASS Test XRFrame.fillPoses where the hand has one missing joint pose - webgl2
+
Added: trunk/LayoutTests/http/wpt/webxr/xrFrame_fillPoses_missing_joint_pose.html (0 => 292780)
--- trunk/LayoutTests/http/wpt/webxr/xrFrame_fillPoses_missing_joint_pose.html (rev 0)
+++ trunk/LayoutTests/http/wpt/webxr/xrFrame_fillPoses_missing_joint_pose.html 2022-04-12 18:52:27 UTC (rev 292780)
@@ -0,0 +1,50 @@
+<!DOCTYPE html>
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+
+<script>
+let testName = "Test XRFrame.fillPoses where the hand has one missing joint pose";
+
+let fakeDeviceInitParams = TRACKED_IMMERSIVE_DEVICE_WITH_HAND_TRACKING;
+
+let testFunction = function(session, fakeDeviceController, t, sessionObjects) {
+
+ let input_source = fakeDeviceController.simulateInputSourceConnection({
+ handedness: "none",
+ targetRayMode: "tracked-pointer",
+ pointerOrigin: VALID_POINTER_TRANSFORM,
+ profiles: [],
+ handJoints: HAND_JOINTS_WITH_ONE_INVALID,
+ });
+
+ return session.requestReferenceSpace('local')
+ .then((referenceSpace) => new Promise((resolve) => {
+
+ function onFrame(time, xrFrame) {
+ assert_not_equals(session.inputSources.length, 0);
+ let hand = session.inputSources[0].hand
+ assert_not_equals(hand, null);
+ assert_equals(hand.size, JOINT_COUNT);
+
+ const floatsPerTransform = 16;
+ let transforms = new Float32Array(JOINT_COUNT * floatsPerTransform);
+ let allValid = xrFrame.fillPoses(hand.values(), referenceSpace, transforms);
+ assert_false(allValid);
+
+ for (var i = 0; i < JOINT_COUNT * floatsPerTransform; ++i) {
+ assert_equals(transforms[i], NaN);
+ }
+
+ resolve();
+ }
+ session.requestAnimationFrame(onFrame);
+ }));
+};
+
+xr_session_promise_test(
+ testName, testFunction, fakeDeviceInitParams, 'immersive-vr', { optionalFeatures: ["hand-tracking"] });
+
+</script>
Added: trunk/LayoutTests/http/wpt/webxr/xrFrame_getJointPose-expected.txt (0 => 292780)
--- trunk/LayoutTests/http/wpt/webxr/xrFrame_getJointPose-expected.txt (rev 0)
+++ trunk/LayoutTests/http/wpt/webxr/xrFrame_getJointPose-expected.txt 2022-04-12 18:52:27 UTC (rev 292780)
@@ -0,0 +1,4 @@
+
+PASS Test XRFrame.getJointPose - webgl
+PASS Test XRFrame.getJointPose - webgl2
+
Added: trunk/LayoutTests/http/wpt/webxr/xrFrame_getJointPose.html (0 => 292780)
--- trunk/LayoutTests/http/wpt/webxr/xrFrame_getJointPose.html (rev 0)
+++ trunk/LayoutTests/http/wpt/webxr/xrFrame_getJointPose.html 2022-04-12 18:52:27 UTC (rev 292780)
@@ -0,0 +1,48 @@
+<!DOCTYPE html>
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+
+<script>
+let testName = "Test XRFrame.getJointPose";
+
+let fakeDeviceInitParams = TRACKED_IMMERSIVE_DEVICE_WITH_HAND_TRACKING;
+
+let testFunction = function(session, fakeDeviceController, t, sessionObjects) {
+
+ let input_source = fakeDeviceController.simulateInputSourceConnection({
+ handedness: "none",
+ targetRayMode: "tracked-pointer",
+ pointerOrigin: VALID_POINTER_TRANSFORM,
+ profiles: [],
+ handJoints: VALID_HAND_JOINTS,
+ });
+
+ return session.requestReferenceSpace('local')
+ .then((referenceSpace) => new Promise((resolve) => {
+
+ function onFrame(time, xrFrame) {
+ assert_not_equals(session.inputSources.length, 0);
+ let hand = session.inputSources[0].hand
+ assert_not_equals(hand, null);
+
+ let jointSpace = hand.get("wrist");
+ assert_not_equals(jointSpace, null);
+
+ let jointPose = xrFrame.getJointPose(jointSpace, referenceSpace);
+ assert_not_equals(jointPose, null);
+ assert_approx_equals(jointPose.radius, TEST_HAND_JOINT_RADIUS, FLOAT_EPSILON);
+ assert_matrix_approx_equals(jointPose.transform.matrix, VALID_POSE_MATRIX, FLOAT_EPSILON);
+
+ resolve();
+ }
+ session.requestAnimationFrame(onFrame);
+ }));
+};
+
+xr_session_promise_test(
+ testName, testFunction, fakeDeviceInitParams, 'immersive-vr', { optionalFeatures: ["hand-tracking"] });
+
+</script>
Added: trunk/LayoutTests/http/wpt/webxr/xrFrame_getJointPose_missing_joint_pose-expected.txt (0 => 292780)
--- trunk/LayoutTests/http/wpt/webxr/xrFrame_getJointPose_missing_joint_pose-expected.txt (rev 0)
+++ trunk/LayoutTests/http/wpt/webxr/xrFrame_getJointPose_missing_joint_pose-expected.txt 2022-04-12 18:52:27 UTC (rev 292780)
@@ -0,0 +1,4 @@
+
+PASS Test XRFrame.getJointPose where the hand has one missing joint pose - webgl
+PASS Test XRFrame.getJointPose where the hand has one missing joint pose - webgl2
+
Added: trunk/LayoutTests/http/wpt/webxr/xrFrame_getJointPose_missing_joint_pose.html (0 => 292780)
--- trunk/LayoutTests/http/wpt/webxr/xrFrame_getJointPose_missing_joint_pose.html (rev 0)
+++ trunk/LayoutTests/http/wpt/webxr/xrFrame_getJointPose_missing_joint_pose.html 2022-04-12 18:52:27 UTC (rev 292780)
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+
+<script>
+let testName = "Test XRFrame.getJointPose where the hand has one missing joint pose";
+
+let fakeDeviceInitParams = TRACKED_IMMERSIVE_DEVICE_WITH_HAND_TRACKING;
+
+let testFunction = function(session, fakeDeviceController, t, sessionObjects) {
+
+ let input_source = fakeDeviceController.simulateInputSourceConnection({
+ handedness: "none",
+ targetRayMode: "tracked-pointer",
+ pointerOrigin: VALID_POINTER_TRANSFORM,
+ profiles: [],
+ handJoints: HAND_JOINTS_WITH_ONE_INVALID,
+ });
+
+ return session.requestReferenceSpace('local')
+ .then((referenceSpace) => new Promise((resolve) => {
+
+ function onFrame(time, xrFrame) {
+ assert_not_equals(session.inputSources.length, 0);
+ let hand = session.inputSources[0].hand
+ assert_not_equals(hand, null);
+ assert_equals(hand.size, JOINT_COUNT);
+
+ let wristJointSpace = hand.get("wrist");
+ assert_not_equals(wristJointSpace, null);
+ assert_equals(xrFrame.getJointPose(wristJointSpace, referenceSpace), null);
+
+ let pinkyTipJointSpace = hand.get("pinky-finger-tip");
+ assert_not_equals(pinkyTipJointSpace, null);
+ assert_equals(xrFrame.getJointPose(pinkyTipJointSpace, referenceSpace), null);
+
+ resolve();
+ }
+ session.requestAnimationFrame(onFrame);
+ }));
+};
+
+xr_session_promise_test(
+ testName, testFunction, fakeDeviceInitParams, 'immersive-vr', { optionalFeatures: ["hand-tracking"] });
+
+</script>
Added: trunk/LayoutTests/http/wpt/webxr/xrHand-expected.txt (0 => 292780)
--- trunk/LayoutTests/http/wpt/webxr/xrHand-expected.txt (rev 0)
+++ trunk/LayoutTests/http/wpt/webxr/xrHand-expected.txt 2022-04-12 18:52:27 UTC (rev 292780)
@@ -0,0 +1,4 @@
+
+PASS Test the XRHand API - webgl
+PASS Test the XRHand API - webgl2
+
Added: trunk/LayoutTests/http/wpt/webxr/xrHand.html (0 => 292780)
--- trunk/LayoutTests/http/wpt/webxr/xrHand.html (rev 0)
+++ trunk/LayoutTests/http/wpt/webxr/xrHand.html 2022-04-12 18:52:27 UTC (rev 292780)
@@ -0,0 +1,50 @@
+<!DOCTYPE html>
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+
+<script>
+let testName = "Test the XRHand API";
+
+let fakeDeviceInitParams = TRACKED_IMMERSIVE_DEVICE_WITH_HAND_TRACKING;
+
+let testFunction = function(session, fakeDeviceController, t, sessionObjects) {
+
+ let input_source = fakeDeviceController.simulateInputSourceConnection({
+ handedness: "none",
+ targetRayMode: "tracked-pointer",
+ pointerOrigin: VALID_POINTER_TRANSFORM,
+ profiles: [],
+ handJoints: VALID_HAND_JOINTS,
+ });
+
+ return session.requestReferenceSpace('local')
+ .then((referenceSpace) => new Promise((resolve) => {
+
+ function onFrame(time, xrFrame) {
+ assert_not_equals(session.inputSources.length, 0);
+ let hand = session.inputSources[0].hand
+ assert_not_equals(hand, null);
+ assert_equals(hand.size, 25);
+
+ let wristJointSpace = hand.get("wrist");
+ assert_equals(wristJointSpace.jointName, "wrist");
+
+ var count = 0;
+ for (const [jointName, jointSpace] of hand) {
+ assert_equals(jointSpace.jointName, jointName);
+ count++;
+ }
+ assert_equals(count, 25);
+
+ resolve();
+ }
+ session.requestAnimationFrame(onFrame);
+ }));
+};
+
+xr_session_promise_test(
+ testName, testFunction, fakeDeviceInitParams, 'immersive-vr', { optionalFeatures: ["hand-tracking"] });
+
+</script>
Modified: trunk/LayoutTests/http/wpt/webxr/xrHandInput_gc.html (292779 => 292780)
--- trunk/LayoutTests/http/wpt/webxr/xrHandInput_gc.html 2022-04-12 18:08:56 UTC (rev 292779)
+++ trunk/LayoutTests/http/wpt/webxr/xrHandInput_gc.html 2022-04-12 18:52:27 UTC (rev 292780)
@@ -17,7 +17,7 @@
let testName = "Test object lifetime of Hand Input module";
-let fakeDeviceInitParams = TRACKED_IMMERSIVE_SINGLE_VIEWDEVICE;
+let fakeDeviceInitParams = TRACKED_IMMERSIVE_DEVICE_WITH_HAND_TRACKING;
let testFunction = function(session, fakeDeviceController, t, sessionObjects) {
@@ -26,7 +26,7 @@
targetRayMode: "tracked-pointer",
pointerOrigin: VALID_POINTER_TRANSFORM,
profiles: [],
- simulateHand: true,
+ handJoints: VALID_HAND_JOINTS,
});
return session.requestReferenceSpace('local')
Modified: trunk/LayoutTests/platform/win/TestExpectations (292779 => 292780)
--- trunk/LayoutTests/platform/win/TestExpectations 2022-04-12 18:08:56 UTC (rev 292779)
+++ trunk/LayoutTests/platform/win/TestExpectations 2022-04-12 18:52:27 UTC (rev 292780)
@@ -4910,6 +4910,8 @@
# WebXR is not enabled on windows.
webxr [ Skip ]
+imported/w3c/web-platform-tests/webxr [ Skip ]
+http/wpt/webxr [ Skip ]
# https://bugs.webkit.org/show_bug.cgi?id=226970
fast/css/parse-border-image-repeat-null-crash.html [ Failure ]
Modified: trunk/Source/WebCore/ChangeLog (292779 => 292780)
--- trunk/Source/WebCore/ChangeLog 2022-04-12 18:08:56 UTC (rev 292779)
+++ trunk/Source/WebCore/ChangeLog 2022-04-12 18:52:27 UTC (rev 292780)
@@ -1,3 +1,106 @@
+2022-04-12 Ada Chan <[email protected]>
+
+ [WebXR] Implement the WebXRFrame methods for getting joints' poses and radii
+ https://bugs.webkit.org/show_bug.cgi?id=238968
+
+ Reviewed by Dean Jackson.
+
+ Tests: http/wpt/webxr/xrFrame_fillJointRadii.html
+ http/wpt/webxr/xrFrame_fillJointRadii_missing_joint_pose.html
+ http/wpt/webxr/xrFrame_fillPoses.html
+ http/wpt/webxr/xrFrame_fillPoses_missing_joint_pose.html
+ http/wpt/webxr/xrFrame_getJointPose.html
+ http/wpt/webxr/xrFrame_getJointPose_missing_joint_pose.html
+ http/wpt/webxr/xrHand.html
+
+ - Implement the methods in WebXRFrame for getting joints' poses and radii.
+ - Add a new InputSourceHandJoint struct to represent joint data, and add
+ a vector of InputSourceHandJoint in PlatformXR::Device::FrameData::InputSource
+ to represent the joints data.
+ - Implement logic for managing a vector of WebXRJointSpaces in WebXRHand and
+ updating it with new hand joints data from PlatformXR::Device::FrameData::InputSource.
+
+ * DerivedSources-input.xcfilelist:
+ * DerivedSources-output.xcfilelist:
+ * DerivedSources.make:
+ * Modules/webxr/WebXRFrame+HandInput.idl:
+ * Modules/webxr/WebXRFrame.cpp:
+ (WebCore::WebXRFrame::populatePose):
+ There are valid cases when the WebXRSpace's effective origin can be null,
+ for example, a joint pose from a hand that has other missing joint poses.
+ Just return null and not throw an exception in that case.
+ (WebCore::WebXRFrame::getJointPose):
+ Populate the joint's pose, and create a WebXRJointPose with the pose's
+ transform and the joint's radius.
+ (WebCore::WebXRFrame::fillJointRadii):
+ Validate the inputs and fill in the radii array. Fill in with NaN
+ if the hand has missing joint poses.
+ (WebCore::WebXRFrame::fillPoses):
+ Validate the inputs and fill in the transforms array. Fill in with NaN
+ if the hand has missing joint poses.
+ * Modules/webxr/WebXRFrame.h:
+ * Modules/webxr/WebXRHand.cpp:
+ (WebCore::WebXRHand::WebXRHand):
+ Initialize the m_joints array.
+ (WebCore::WebXRHand::get):
+ (WebCore::WebXRHand::Iterator::next):
+ (WebCore::WebXRHand::session):
+ (WebCore::WebXRHand::updateFromInputSource):
+ Update m_joints array based on the latest hands data from InputSource.
+ * Modules/webxr/WebXRHand.h:
+ (WebCore::WebXRHand::size):
+ (WebCore::WebXRHand::hasMissingPoses const):
+ * Modules/webxr/WebXRInputSource.cpp:
+ (WebCore::WebXRInputSource::update):
+ * Modules/webxr/WebXRJointPose.cpp:
+ (WebCore::WebXRJointPose::create):
+ (WebCore::WebXRJointPose::WebXRJointPose):
+ Handle joint radius.
+ * Modules/webxr/WebXRJointPose.h:
+ * Modules/webxr/WebXRJointPose.idl:
+ * Modules/webxr/WebXRJointSpace.cpp:
+ (WebCore::WebXRJointSpace::create):
+ (WebCore::WebXRJointSpace::WebXRJointSpace):
+ Handle joint name and the actual pose data. Keep a weak ptr to the WebXRHand.
+ (WebCore::WebXRJointSpace::updateFromJoint):
+ (WebCore::WebXRJointSpace::handHasMissingPoses const):
+ (WebCore::WebXRJointSpace::session const):
+ (WebCore::WebXRJointSpace::nativeOrigin const):
+ Return null pose transforms if there are missing joint poses.
+ * Modules/webxr/WebXRJointSpace.h:
+ (WebCore::WebXRJointSpace::jointName const):
+ (WebCore::WebXRJointSpace::radius const):
+ * Modules/webxr/WebXRJointSpace.idl:
+ * Modules/webxr/WebXRSession.cpp:
+ (WebCore::WebXRSession::isHandTrackingEnabled const):
+ * Modules/webxr/WebXRSession.h:
+ * WebCore.xcodeproj/project.pbxproj:
+ * platform/xr/PlatformXR.h:
+ (PlatformXR::Device::FrameData::InputSourceHandJoint::encode const):
+ (PlatformXR::Device::FrameData::InputSourceHandJoint::decode):
+ (PlatformXR::Device::FrameData::InputSource::encode const):
+ (PlatformXR::Device::FrameData::InputSource::decode):
+ * testing/FakeXRInputSourceInit.h:
+ * testing/FakeXRInputSourceInit.idl:
+ Allow test InputSource to be created with an array of joints.
+ * testing/FakeXRJointStateInit.h: Copied from Source/WebCore/Modules/webxr/WebXRJointPose.idl.
+ * testing/FakeXRJointStateInit.idl: Copied from Source/WebCore/Modules/webxr/WebXRJointPose.idl.
+ Define init dictionary for joint data.
+ * testing/WebFakeXRInputController.cpp:
+ (WebCore::WebFakeXRInputController::WebFakeXRInputController):
+ (WebCore::WebFakeXRInputController::getFrameData):
+ (WebCore::WebFakeXRInputController::updateHandJoints):
+ Update m_handJoints based on joint init dictionaries.
+ * testing/WebFakeXRInputController.h:
+ * testing/WebFakeXRInputController.idl:
+ * testing/WebXRTest.cpp:
+ (WebCore::parseFeatures):
+ (WebCore::WebXRTest::simulateDeviceConnection):
+ Allow test device to specify a list of enabled features that don't need
+ further explicit consent.
+ * testing/WebXRTest.h:
+ * testing/WebXRTest.idl:
+
2022-04-12 Gabriel Nava Marino <[email protected]>
RejectedPromiseTracker can be recreated if we are in a worker / worklet whose execution is terminating
Modified: trunk/Source/WebCore/DerivedSources-input.xcfilelist (292779 => 292780)
--- trunk/Source/WebCore/DerivedSources-input.xcfilelist 2022-04-12 18:08:56 UTC (rev 292779)
+++ trunk/Source/WebCore/DerivedSources-input.xcfilelist 2022-04-12 18:52:27 UTC (rev 292780)
@@ -1622,6 +1622,7 @@
$(PROJECT_DIR)/testing/FakeXRBoundsPoint.idl
$(PROJECT_DIR)/testing/FakeXRButtonStateInit.idl
$(PROJECT_DIR)/testing/FakeXRInputSourceInit.idl
+$(PROJECT_DIR)/testing/FakeXRJointStateInit.idl
$(PROJECT_DIR)/testing/FakeXRRigidTransformInit.idl
$(PROJECT_DIR)/testing/FakeXRViewInit.idl
$(PROJECT_DIR)/testing/GCObservation.idl
Modified: trunk/Source/WebCore/DerivedSources-output.xcfilelist (292779 => 292780)
--- trunk/Source/WebCore/DerivedSources-output.xcfilelist 2022-04-12 18:08:56 UTC (rev 292779)
+++ trunk/Source/WebCore/DerivedSources-output.xcfilelist 2022-04-12 18:52:27 UTC (rev 292780)
@@ -835,6 +835,8 @@
$(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSFakeXRButtonStateInit.h
$(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSFakeXRInputSourceInit.cpp
$(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSFakeXRInputSourceInit.h
+$(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSFakeXRJointStateInit.cpp
+$(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSFakeXRJointStateInit.h
$(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSFakeXRRigidTransformInit.cpp
$(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSFakeXRRigidTransformInit.h
$(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSFakeXRViewInit.cpp
Modified: trunk/Source/WebCore/DerivedSources.make (292779 => 292780)
--- trunk/Source/WebCore/DerivedSources.make 2022-04-12 18:08:56 UTC (rev 292779)
+++ trunk/Source/WebCore/DerivedSources.make 2022-04-12 18:52:27 UTC (rev 292780)
@@ -1462,6 +1462,7 @@
$(WebCore)/testing/FakeXRBoundsPoint.idl \
$(WebCore)/testing/FakeXRButtonStateInit.idl \
$(WebCore)/testing/FakeXRInputSourceInit.idl \
+ $(WebCore)/testing/FakeXRJointStateInit.idl \
$(WebCore)/testing/FakeXRRigidTransformInit.idl \
$(WebCore)/testing/FakeXRViewInit.idl \
$(WebCore)/testing/WebFakeXRDevice.idl \
Modified: trunk/Source/WebCore/Modules/webxr/WebXRFrame+HandInput.idl (292779 => 292780)
--- trunk/Source/WebCore/Modules/webxr/WebXRFrame+HandInput.idl 2022-04-12 18:08:56 UTC (rev 292779)
+++ trunk/Source/WebCore/Modules/webxr/WebXRFrame+HandInput.idl 2022-04-12 18:52:27 UTC (rev 292780)
@@ -28,7 +28,7 @@
Conditional=WEBXR_HANDS,
EnabledBySetting=WebXREnabled&WebXRHandInputModuleEnabled,
] partial interface WebXRFrame {
- WebXRJointPose? getJointPose(WebXRJointSpace joint, WebXRSpace baseSpace);
+ [CallWith=CurrentDocument] WebXRJointPose? getJointPose(WebXRJointSpace joint, WebXRSpace baseSpace);
boolean fillJointRadii(sequence<WebXRJointSpace> jointSpaces, Float32Array radii);
- boolean fillPoses(sequence<WebXRSpace> spaces, WebXRSpace baseSpace, Float32Array transforms);
+ [CallWith=CurrentDocument] boolean fillPoses(sequence<WebXRSpace> spaces, WebXRSpace baseSpace, Float32Array transforms);
};
Modified: trunk/Source/WebCore/Modules/webxr/WebXRFrame.cpp (292779 => 292780)
--- trunk/Source/WebCore/Modules/webxr/WebXRFrame.cpp 2022-04-12 18:08:56 UTC (rev 292779)
+++ trunk/Source/WebCore/Modules/webxr/WebXRFrame.cpp 2022-04-12 18:52:27 UTC (rev 292780)
@@ -136,8 +136,10 @@
return { std::nullopt };
auto effectiveOrigin = space.effectiveOrigin();
+ // A space's effectiveOrigin can be null, such as a joint pose from a hand that has
+ // other missing joint poses.
if (!effectiveOrigin)
- return Exception { InvalidStateError };
+ return { std::nullopt };
auto transform = *baseTransform.value().inverse() * effectiveOrigin.value();
@@ -263,23 +265,115 @@
#if ENABLE(WEBXR_HANDS)
// https://immersive-web.github.io/webxr-hand-input/#dom-xrframe-getjointpose
-ExceptionOr<RefPtr<WebXRJointPose>> WebXRFrame::getJointPose(const WebXRJointSpace& joint, const WebXRSpace& baseSpace)
+ExceptionOr<RefPtr<WebXRJointPose>> WebXRFrame::getJointPose(const Document& document, const WebXRJointSpace& jointSpace, const WebXRSpace& baseSpace)
{
- UNUSED_PARAM(joint);
- UNUSED_PARAM(baseSpace);
- return nullptr;
+ auto populatePoseResult = populatePose(document, jointSpace, baseSpace);
+ if (populatePoseResult.hasException())
+ return populatePoseResult.releaseException();
+
+ auto populateValue = populatePoseResult.releaseReturnValue();
+ if (!populateValue)
+ return nullptr;
+
+ return RefPtr<WebXRJointPose>(WebXRJointPose::create(WebXRRigidTransform::create(populateValue->transform), populateValue->emulatedPosition, jointSpace.radius()));
}
// https://immersive-web.github.io/webxr-hand-input/#dom-xrframe-filljointradii
-ExceptionOr<bool> WebXRFrame::fillJointRadii(const Vector<RefPtr<WebXRJointSpace>>, const Float32Array&)
+ExceptionOr<bool> WebXRFrame::fillJointRadii(const Vector<RefPtr<WebXRJointSpace>>& jointSpaces, Float32Array& radii)
{
- return true;
+ // If frame’s active boolean is false, throw an InvalidStateError and abort these steps.
+ if (!m_active)
+ return Exception { InvalidStateError, "Frame is not active"_s };
+
+ // For each joint in the jointSpaces:
+ // If joint’s session is different from session, throw an InvalidStateError and abort these steps.
+ for (const auto& jointSpace : jointSpaces) {
+ if (!jointSpace || jointSpace->session() != m_session.ptr())
+ return Exception { InvalidStateError, "Joint space's session does not match frame's session"_s };
+ }
+
+ // If the length of jointSpaces is larger than the number of elements in radii, throw a TypeError and abort these steps.
+ if (jointSpaces.size() > radii.length())
+ return Exception { TypeError, "Unexpected length of radii array"_s };
+
+ // Let allValid be true.
+ bool allValid = true;
+
+ // For each joint in the jointSpaces:
+ // 1. Set the float value of radii at offset as follows:
+ // If the user agent can determine the poses of all the joints belonging to the joint’s hand:
+ // Set the float value of radii at offset to that radius.
+ // Otherwise
+ // Set the float value of radii at offset to NaN.
+ // Set allValid to false.
+ // 2. Increase offset by 1.
+ for (size_t i = 0; i < jointSpaces.size(); ++i) {
+ if (jointSpaces[i]->handHasMissingPoses()) {
+ radii.set(i, std::numeric_limits<float>::quiet_NaN());
+ allValid = false;
+ } else
+ radii.set(i, jointSpaces[i]->radius());
+ }
+
+ return allValid;
}
// https://immersive-web.github.io/webxr-hand-input/#dom-xrframe-fillposes
-ExceptionOr<bool> WebXRFrame::fillPoses(const Vector<RefPtr<WebXRSpace>>, const WebXRSpace&, const Float32Array&)
+ExceptionOr<bool> WebXRFrame::fillPoses(const Document& document, const Vector<RefPtr<WebXRSpace>>& spaces, const WebXRSpace& baseSpace, Float32Array& transforms)
{
- return true;
+ // If frame’s active boolean is false, throw an InvalidStateError and abort these steps.
+ if (!m_active)
+ return Exception { InvalidStateError, "Frame is not active"_s };
+
+ // For each space in the spaces sequence:
+ // If space’s session is different from session, throw an InvalidStateError and abort these steps.
+ for (const auto& space : spaces) {
+ if (!space || space->session() != m_session.ptr())
+ return Exception { InvalidStateError, "Space's session does not match frame's session"_s };
+ }
+
+ // If baseSpace’s session is different from session, throw an InvalidStateError and abort these steps.
+ if (baseSpace.session() != m_session.ptr())
+ return Exception { InvalidStateError, "Base space's session does not match frame's session"_s };
+
+ // If the length of spaces multiplied by 16 is larger than the number of elements in transforms,
+ // throw a TypeError and abort these steps.
+ const size_t numberOfFloatsPerTransform = 16;
+ if (spaces.size() * numberOfFloatsPerTransform > transforms.length())
+ return Exception { TypeError, "Unexpected length of transforms array"_s };
+
+ // Check if poses may be reported and, if not, throw a SecurityError and abort these steps.
+ if (!m_session->posesCanBeReported(document))
+ return Exception { SecurityError, "Poses cannot be reported"_s };
+
+ // Let allValid be true.
+ bool allValid = true;
+
+ // For each space in the spaces sequence:
+ for (size_t spaceIndex = 0; spaceIndex < spaces.size(); ++spaceIndex) {
+ // 1. Populate the pose of space in baseSpace at the time represented by frame into pose.
+ auto populatePoseResult = populatePose(document, *(spaces[spaceIndex]), baseSpace);
+ if (populatePoseResult.hasException())
+ return populatePoseResult.releaseException();
+
+ // 2. If pose is null, perform the following steps:
+ // 3. Set 16 consecutive elements of the transforms array starting at offset to NaN.
+ // 4. Set allValid to false.
+ auto populateValue = populatePoseResult.releaseReturnValue();
+ if (!populateValue) {
+ for (size_t transformIndex = 0; transformIndex < numberOfFloatsPerTransform; ++transformIndex)
+ transforms.set(spaceIndex * numberOfFloatsPerTransform + transformIndex, std::numeric_limits<float>::quiet_NaN());
+ allValid = false;
+ } else {
+ // 5. If pose is not null, copy all elements from pose’s matrix member to the transforms array starting at offset.
+ // 6. Increase offset by 16.
+ auto matrix = populateValue->transform.toColumnMajorFloatArray();
+ for (size_t transformIndex = 0; transformIndex < numberOfFloatsPerTransform; ++transformIndex)
+ transforms.set(spaceIndex * numberOfFloatsPerTransform + transformIndex, matrix[transformIndex]);
+ }
+ }
+
+ return allValid;
}
#endif
Modified: trunk/Source/WebCore/Modules/webxr/WebXRFrame.h (292779 => 292780)
--- trunk/Source/WebCore/Modules/webxr/WebXRFrame.h 2022-04-12 18:08:56 UTC (rev 292779)
+++ trunk/Source/WebCore/Modules/webxr/WebXRFrame.h 2022-04-12 18:52:27 UTC (rev 292780)
@@ -60,9 +60,9 @@
ExceptionOr<RefPtr<WebXRPose>> getPose(const Document&, const WebXRSpace&, const WebXRSpace&);
#if ENABLE(WEBXR_HANDS)
- ExceptionOr<RefPtr<WebXRJointPose>> getJointPose(const WebXRJointSpace&, const WebXRSpace&);
- ExceptionOr<bool> fillJointRadii(const Vector<RefPtr<WebXRJointSpace>>, const Float32Array&);
- ExceptionOr<bool> fillPoses(const Vector<RefPtr<WebXRSpace>>, const WebXRSpace&, const Float32Array&);
+ ExceptionOr<RefPtr<WebXRJointPose>> getJointPose(const Document&, const WebXRJointSpace&, const WebXRSpace&);
+ ExceptionOr<bool> fillJointRadii(const Vector<RefPtr<WebXRJointSpace>>&, Float32Array&);
+ ExceptionOr<bool> fillPoses(const Document&, const Vector<RefPtr<WebXRSpace>>&, const WebXRSpace&, Float32Array&);
#endif
void setTime(DOMHighResTimeStamp time) { m_time = time; }
Modified: trunk/Source/WebCore/Modules/webxr/WebXRHand.cpp (292779 => 292780)
--- trunk/Source/WebCore/Modules/webxr/WebXRHand.cpp 2022-04-12 18:08:56 UTC (rev 292779)
+++ trunk/Source/WebCore/Modules/webxr/WebXRHand.cpp 2022-04-12 18:52:27 UTC (rev 292780)
@@ -43,6 +43,17 @@
WebXRHand::WebXRHand(const WebXRInputSource& inputSource)
: m_inputSource(inputSource)
{
+ auto* session = this->session();
+ auto* document = session ? downcast<Document>(session->scriptExecutionContext()) : nullptr;
+ if (!document)
+ return;
+
+ size_t jointCount = static_cast<size_t>(XRHandJoint::Count);
+ Vector<Ref<WebXRJointSpace>> joints;
+ joints.reserveInitialCapacity(jointCount);
+ for (size_t i = 0; i < jointCount; ++i)
+ joints.uncheckedAppend(WebXRJointSpace::create(*document, *this, static_cast<XRHandJoint>(i)));
+ m_joints = WTFMove(joints);
}
WebXRHand::~WebXRHand() = default;
@@ -49,8 +60,11 @@
RefPtr<WebXRJointSpace> WebXRHand::get(const XRHandJoint& key)
{
- UNUSED_PARAM(key);
- return nullptr;
+ size_t jointIndex = static_cast<size_t>(key);
+ if (jointIndex >= m_joints.size())
+ return nullptr;
+
+ return m_joints[jointIndex].ptr();
}
WebXRHand::Iterator::Iterator(WebXRHand& hand)
@@ -60,10 +74,11 @@
std::optional<KeyValuePair<XRHandJoint, RefPtr<WebXRJointSpace>>> WebXRHand::Iterator::next()
{
- if (m_index > m_hand->m_joints.size())
+ if (m_index >= m_hand->m_joints.size())
return std::nullopt;
- return std::nullopt;
+ size_t index = m_index++;
+ return KeyValuePair<XRHandJoint, RefPtr<WebXRJointSpace>> { static_cast<XRHandJoint>(index), m_hand->m_joints[index].ptr() };
}
WebXRSession* WebXRHand::session()
@@ -70,9 +85,33 @@
{
if (!m_inputSource)
return nullptr;
+
return m_inputSource.get()->session();
}
+void WebXRHand::updateFromInputSource(const PlatformXR::Device::FrameData::InputSource& inputSource)
+{
+ if (!inputSource.handJoints) {
+ m_hasMissingPoses = true;
+ return;
+ }
+
+ auto& handJoints = *(inputSource.handJoints);
+ if (handJoints.size() != m_joints.size()) {
+ m_hasMissingPoses = true;
+ return;
+ }
+
+ bool hasMissingPoses = false;
+ for (size_t i = 0; i < handJoints.size(); ++i) {
+ if (!handJoints[i])
+ hasMissingPoses = true;
+
+ m_joints[i]->updateFromJoint(handJoints[i]);
+ }
+ m_hasMissingPoses = hasMissingPoses;
}
+}
+
#endif
Modified: trunk/Source/WebCore/Modules/webxr/WebXRHand.h (292779 => 292780)
--- trunk/Source/WebCore/Modules/webxr/WebXRHand.h 2022-04-12 18:08:56 UTC (rev 292779)
+++ trunk/Source/WebCore/Modules/webxr/WebXRHand.h 2022-04-12 18:52:27 UTC (rev 292780)
@@ -36,10 +36,11 @@
#include <wtf/Ref.h>
#include <wtf/RefCounted.h>
#include <wtf/RefPtr.h>
+#include <wtf/WeakPtr.h>
namespace WebCore {
-class WebXRHand : public RefCounted<WebXRHand> {
+class WebXRHand : public RefCounted<WebXRHand>, public CanMakeWeakPtr<WebXRHand> {
WTF_MAKE_ISO_ALLOCATED(WebXRHand);
public:
@@ -46,7 +47,7 @@
static Ref<WebXRHand> create(const WebXRInputSource&);
~WebXRHand();
- unsigned size() { return m_size; }
+ unsigned size() const { return m_joints.size(); }
RefPtr<WebXRJointSpace> get(const XRHandJoint& key);
@@ -61,16 +62,17 @@
};
Iterator createIterator() { return Iterator(*this); }
- // For GC reachablitiy.
+ // For GC reachability.
WebXRSession* session();
+ bool hasMissingPoses() const { return m_hasMissingPoses; }
+ void updateFromInputSource(const PlatformXR::Device::FrameData::InputSource&);
+
private:
WebXRHand(const WebXRInputSource&);
- unsigned m_size { 0 };
- using HandJointToSpaceMap = HashMap<XRHandJoint, Ref<WebXRJointSpace>, DefaultHash<unsigned>, WTF::UnsignedWithZeroKeyHashTraits<unsigned>>;
- HandJointToSpaceMap m_joints;
-
+ FixedVector<Ref<WebXRJointSpace>> m_joints;
+ bool m_hasMissingPoses { true };
WeakPtr<WebXRInputSource> m_inputSource;
};
Modified: trunk/Source/WebCore/Modules/webxr/WebXRInputSource.cpp (292779 => 292780)
--- trunk/Source/WebCore/Modules/webxr/WebXRInputSource.cpp 2022-04-12 18:08:56 UTC (rev 292779)
+++ trunk/Source/WebCore/Modules/webxr/WebXRInputSource.cpp 2022-04-12 18:52:27 UTC (rev 292780)
@@ -88,16 +88,19 @@
#endif
#if ENABLE(WEBXR_HANDS)
- if (source.simulateHand) {
- // FIXME: This currently creates an object just for use in testing.
- // The real implementation will use actual data and only be visible
- // if hand-tracking was requested at session start.
- if (!m_hand)
+ if (source.handJoints) {
+ // https://www.w3.org/TR/webxr-hand-input-1/#xrinputsource-interface
+ // If the XRInputSource belongs to an XRSession that has not been requested
+ // with the "hand-tracking" feature descriptor, hand MUST be null.
+ if (!m_hand && session->isHandTrackingEnabled())
m_hand = WebXRHand::create(*this);
- } else
- m_hand = nullptr;
+
+ if (m_hand)
+ m_hand->updateFromInputSource(source);
+
+ return;
+ }
#endif
-
}
bool WebXRInputSource::requiresInputSourceChange(const InputSource& source)
Modified: trunk/Source/WebCore/Modules/webxr/WebXRJointPose.cpp (292779 => 292780)
--- trunk/Source/WebCore/Modules/webxr/WebXRJointPose.cpp 2022-04-12 18:08:56 UTC (rev 292779)
+++ trunk/Source/WebCore/Modules/webxr/WebXRJointPose.cpp 2022-04-12 18:52:27 UTC (rev 292780)
@@ -34,13 +34,14 @@
WTF_MAKE_ISO_ALLOCATED_IMPL(WebXRJointPose);
-Ref<WebXRJointPose> WebXRJointPose::create(Ref<WebXRRigidTransform>&& transform, bool emulatedPosition)
+Ref<WebXRJointPose> WebXRJointPose::create(Ref<WebXRRigidTransform>&& transform, bool emulatedPosition, float radius)
{
- return adoptRef(*new WebXRJointPose(WTFMove(transform), emulatedPosition));
+ return adoptRef(*new WebXRJointPose(WTFMove(transform), emulatedPosition, radius));
}
-WebXRJointPose::WebXRJointPose(Ref<WebXRRigidTransform>&& transform, bool emulatedPosition)
+WebXRJointPose::WebXRJointPose(Ref<WebXRRigidTransform>&& transform, bool emulatedPosition, float radius)
: WebXRPose(WTFMove(transform), emulatedPosition)
+ , m_radius(radius)
{
}
Modified: trunk/Source/WebCore/Modules/webxr/WebXRJointPose.h (292779 => 292780)
--- trunk/Source/WebCore/Modules/webxr/WebXRJointPose.h 2022-04-12 18:08:56 UTC (rev 292779)
+++ trunk/Source/WebCore/Modules/webxr/WebXRJointPose.h 2022-04-12 18:52:27 UTC (rev 292780)
@@ -39,13 +39,13 @@
class WebXRJointPose : public WebXRPose {
WTF_MAKE_ISO_ALLOCATED(WebXRJointPose);
public:
- static Ref<WebXRJointPose> create(Ref<WebXRRigidTransform>&&, bool emulatedPosition);
+ static Ref<WebXRJointPose> create(Ref<WebXRRigidTransform>&&, bool emulatedPosition, float radius);
~WebXRJointPose() = default;
float radius() const { return m_radius; }
private:
- WebXRJointPose(Ref<WebXRRigidTransform>&&, bool emulatedPosition);
+ WebXRJointPose(Ref<WebXRRigidTransform>&&, bool emulatedPosition, float radius);
float m_radius { 0 };
};
Modified: trunk/Source/WebCore/Modules/webxr/WebXRJointPose.idl (292779 => 292780)
--- trunk/Source/WebCore/Modules/webxr/WebXRJointPose.idl 2022-04-12 18:08:56 UTC (rev 292779)
+++ trunk/Source/WebCore/Modules/webxr/WebXRJointPose.idl 2022-04-12 18:52:27 UTC (rev 292780)
@@ -26,6 +26,8 @@
[
Conditional=WEBXR_HANDS,
EnabledBySetting=WebXREnabled&WebXRHandInputModuleEnabled,
+ JSGenerateToJSObject,
+ JSGenerateToNativeObject,
SecureContext,
Exposed=Window,
InterfaceName=XRJointPose
Modified: trunk/Source/WebCore/Modules/webxr/WebXRJointSpace.cpp (292779 => 292780)
--- trunk/Source/WebCore/Modules/webxr/WebXRJointSpace.cpp 2022-04-12 18:08:56 UTC (rev 292779)
+++ trunk/Source/WebCore/Modules/webxr/WebXRJointSpace.cpp 2022-04-12 18:52:27 UTC (rev 292780)
@@ -28,6 +28,8 @@
#if ENABLE(WEBXR) && ENABLE(WEBXR_HANDS)
+#include "WebXRFrame.h"
+#include "WebXRHand.h"
#include "WebXRRigidTransform.h"
#include <wtf/IsoMallocInlines.h>
@@ -35,22 +37,47 @@
WTF_MAKE_ISO_ALLOCATED_IMPL(WebXRJointSpace);
-Ref<WebXRJointSpace> WebXRJointSpace::create(Document& document, WebXRSession& session)
+Ref<WebXRJointSpace> WebXRJointSpace::create(Document& document, WebXRHand& hand, XRHandJoint jointName, std::optional<PlatformXR::Device::FrameData::InputSourceHandJoint>&& joint)
{
- return adoptRef(*new WebXRJointSpace(document, session));
+ return adoptRef(*new WebXRJointSpace(document, hand, jointName, WTFMove(joint)));
}
-WebXRJointSpace::WebXRJointSpace(Document& document, WebXRSession& session)
+WebXRJointSpace::WebXRJointSpace(Document& document, WebXRHand& hand, XRHandJoint jointName, std::optional<PlatformXR::Device::FrameData::InputSourceHandJoint>&& joint)
: WebXRSpace(document, WebXRRigidTransform::create())
- , m_session(session)
+ , m_hand(hand)
+ , m_jointName(jointName)
+ , m_joint(WTFMove(joint))
{
}
WebXRJointSpace::~WebXRJointSpace() = default;
+void WebXRJointSpace::updateFromJoint(const std::optional<PlatformXR::Device::FrameData::InputSourceHandJoint>& joint)
+{
+ m_joint = joint;
+}
+
+bool WebXRJointSpace::handHasMissingPoses() const
+{
+ return !m_hand || m_hand->hasMissingPoses();
+}
+
+WebXRSession* WebXRJointSpace::session() const
+{
+ return m_hand ? m_hand->session() : nullptr;
+}
+
std::optional<TransformationMatrix> WebXRJointSpace::nativeOrigin() const
{
- return std::nullopt;
+ // https://immersive-web.github.io/webxr-hand-input/#xrjointspace-interface
+ // The native origin of the XRJointSpace may only be reported when native origins of
+ // all other XRJointSpaces on the same hand are being reported. When a hand is partially
+ // obscured the user agent MUST either emulate the obscured joints, or report null poses
+ // for all of the joints.
+ if (handHasMissingPoses() || !m_joint)
+ return std::nullopt;
+
+ return WebXRFrame::matrixFromPose(m_joint->pose.pose);
}
}
Modified: trunk/Source/WebCore/Modules/webxr/WebXRJointSpace.h (292779 => 292780)
--- trunk/Source/WebCore/Modules/webxr/WebXRJointSpace.h 2022-04-12 18:08:56 UTC (rev 292779)
+++ trunk/Source/WebCore/Modules/webxr/WebXRJointSpace.h 2022-04-12 18:52:27 UTC (rev 292780)
@@ -29,7 +29,6 @@
#include "Document.h"
#include "PlatformXR.h"
-#include "WebXRSession.h"
#include "WebXRSpace.h"
#include "XRHandJoint.h"
#include <wtf/IsoMalloc.h>
@@ -36,24 +35,33 @@
#include <wtf/Ref.h>
#include <wtf/RefCounted.h>
#include <wtf/RefPtr.h>
+#include <wtf/Vector.h>
namespace WebCore {
-class WebXRJointSpace : public RefCounted<WebXRJointSpace>, public WebXRSpace {
+class WebXRHand;
+class WebXRSession;
+
+class WebXRJointSpace final: public RefCounted<WebXRJointSpace>, public WebXRSpace {
WTF_MAKE_ISO_ALLOCATED(WebXRJointSpace);
public:
- static Ref<WebXRJointSpace> create(Document&, WebXRSession&);
+ static Ref<WebXRJointSpace> create(Document&, WebXRHand&, XRHandJoint, std::optional<PlatformXR::Device::FrameData::InputSourceHandJoint>&& = std::nullopt);
virtual ~WebXRJointSpace();
using RefCounted<WebXRJointSpace>::ref;
using RefCounted<WebXRJointSpace>::deref;
- XRHandJoint jointName() const { return XRHandJoint::Wrist; }
+ XRHandJoint jointName() const { return m_jointName; }
+ float radius() const { return m_joint ? m_joint->radius : 0; }
+ void updateFromJoint(const std::optional<PlatformXR::Device::FrameData::InputSourceHandJoint>&);
+ bool handHasMissingPoses() const;
+
+ WebXRSession* session() const final;
+
private:
- WebXRJointSpace(Document&, WebXRSession&);
+ WebXRJointSpace(Document&, WebXRHand&, XRHandJoint, std::optional<PlatformXR::Device::FrameData::InputSourceHandJoint>&&);
- WebXRSession* session() const final { return m_session.get(); };
std::optional<TransformationMatrix> nativeOrigin() const final;
void refEventTarget() final { ref(); }
@@ -61,7 +69,9 @@
bool isJointSpace() const final { return true; }
- WeakPtr<WebXRSession> m_session;
+ WeakPtr<WebXRHand> m_hand;
+ XRHandJoint m_jointName { XRHandJoint::Wrist };
+ std::optional<PlatformXR::Device::FrameData::InputSourceHandJoint> m_joint;
};
}
Modified: trunk/Source/WebCore/Modules/webxr/WebXRJointSpace.idl (292779 => 292780)
--- trunk/Source/WebCore/Modules/webxr/WebXRJointSpace.idl 2022-04-12 18:08:56 UTC (rev 292779)
+++ trunk/Source/WebCore/Modules/webxr/WebXRJointSpace.idl 2022-04-12 18:52:27 UTC (rev 292780)
@@ -26,6 +26,7 @@
[
Conditional=WEBXR_HANDS,
EnabledBySetting=WebXREnabled&WebXRHandInputModuleEnabled,
+ JSGenerateToJSObject,
JSGenerateToNativeObject,
SecureContext,
Exposed=Window,
Modified: trunk/Source/WebCore/Modules/webxr/WebXRSession.cpp (292779 => 292780)
--- trunk/Source/WebCore/Modules/webxr/WebXRSession.cpp 2022-04-12 18:08:56 UTC (rev 292779)
+++ trunk/Source/WebCore/Modules/webxr/WebXRSession.cpp 2022-04-12 18:52:27 UTC (rev 292780)
@@ -645,6 +645,14 @@
return true;
}
+#if ENABLE(WEBXR_HANDS)
+bool WebXRSession::isHandTrackingEnabled() const
+{
+ return m_requestedFeatures.contains(PlatformXR::SessionFeature::HandTracking);
+}
+#endif
+
+
} // namespace WebCore
#endif // ENABLE(WEBXR)
Modified: trunk/Source/WebCore/Modules/webxr/WebXRSession.h (292779 => 292780)
--- trunk/Source/WebCore/Modules/webxr/WebXRSession.h 2022-04-12 18:08:56 UTC (rev 292779)
+++ trunk/Source/WebCore/Modules/webxr/WebXRSession.h 2022-04-12 18:52:27 UTC (rev 292780)
@@ -98,6 +98,10 @@
const PlatformXR::Device::FrameData& frameData() const { return m_frameData; }
const WebXRViewerSpace& viewerReferenceSpace() const { return *m_viewerReferenceSpace; }
bool posesCanBeReported(const Document&) const;
+
+#if ENABLE(WEBXR_HANDS)
+ bool isHandTrackingEnabled() const;
+#endif
private:
WebXRSession(Document&, WebXRSystem&, XRSessionMode, PlatformXR::Device&, FeatureList&&);
Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (292779 => 292780)
--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj 2022-04-12 18:08:56 UTC (rev 292779)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj 2022-04-12 18:52:27 UTC (rev 292780)
@@ -1747,6 +1747,7 @@
5273CCB22564576F00850007 /* JSFakeXRButtonStateInit.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5273CCAD2564576C00850007 /* JSFakeXRButtonStateInit.cpp */; };
5273CCB32564576F00850007 /* JSFakeXRRigidTransformInit.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5273CCAE2564576D00850007 /* JSFakeXRRigidTransformInit.cpp */; };
5273CCB42564576F00850007 /* JSFakeXRViewInit.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5273CCAF2564576E00850007 /* JSFakeXRViewInit.cpp */; };
+ 52A0BE6627C227E10046611E /* JSFakeXRJointStateInit.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 52A0BE6527C227E00046611E /* JSFakeXRJointStateInit.cpp */; };
52B0D4BE1C57FD1E0077CE53 /* PlatformView.h in Headers */ = {isa = PBXBuildFile; fileRef = 52B0D4BD1C57FD1E0077CE53 /* PlatformView.h */; settings = {ATTRIBUTES = (Private, ); }; };
52B0D4C01C57FD660077CE53 /* VideoFullscreenChangeObserver.h in Headers */ = {isa = PBXBuildFile; fileRef = 52B0D4BF1C57FD660077CE53 /* VideoFullscreenChangeObserver.h */; settings = {ATTRIBUTES = (Private, ); }; };
52B0D4C21C57FF910077CE53 /* VideoFullscreenInterfaceMac.h in Headers */ = {isa = PBXBuildFile; fileRef = 52B0D4C11C57FF910077CE53 /* VideoFullscreenInterfaceMac.h */; settings = {ATTRIBUTES = (Private, ); }; };
@@ -10072,6 +10073,8 @@
51FB67D91AE6B5E400D06C5A /* ContentExtensionStyleSheet.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ContentExtensionStyleSheet.cpp; sourceTree = "<group>"; };
51FB67DA1AE6B5E400D06C5A /* ContentExtensionStyleSheet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ContentExtensionStyleSheet.h; sourceTree = "<group>"; };
52131E5A1C4F15610033F802 /* VideoFullscreenInterfaceMac.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = VideoFullscreenInterfaceMac.mm; sourceTree = "<group>"; };
+ 5263BF2027C1B5380085250C /* FakeXRJointStateInit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FakeXRJointStateInit.h; sourceTree = "<group>"; };
+ 5263BF2227C1B53B0085250C /* FakeXRJointStateInit.idl */ = {isa = PBXFileReference; lastKnownFileType = text; path = FakeXRJointStateInit.idl; sourceTree = "<group>"; };
526724F11CB2FDF60075974D /* TextTrackRepresentationCocoa.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = TextTrackRepresentationCocoa.mm; sourceTree = "<group>"; };
526724F21CB2FDF60075974D /* TextTrackRepresentationCocoa.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TextTrackRepresentationCocoa.h; sourceTree = "<group>"; };
52688AA327D6A7DA003577A2 /* ResidentKeyRequirement.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ResidentKeyRequirement.h; sourceTree = "<group>"; };
@@ -10087,6 +10090,7 @@
5273CCAD2564576C00850007 /* JSFakeXRButtonStateInit.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSFakeXRButtonStateInit.cpp; sourceTree = "<group>"; };
5273CCAE2564576D00850007 /* JSFakeXRRigidTransformInit.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSFakeXRRigidTransformInit.cpp; sourceTree = "<group>"; };
5273CCAF2564576E00850007 /* JSFakeXRViewInit.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSFakeXRViewInit.cpp; sourceTree = "<group>"; };
+ 52A0BE6527C227E00046611E /* JSFakeXRJointStateInit.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = JSFakeXRJointStateInit.cpp; path = JSFakeXRJointStateInit.cpp; sourceTree = "<group>"; };
52B0D4BD1C57FD1E0077CE53 /* PlatformView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PlatformView.h; sourceTree = "<group>"; };
52B0D4BF1C57FD660077CE53 /* VideoFullscreenChangeObserver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VideoFullscreenChangeObserver.h; sourceTree = "<group>"; };
52B0D4C11C57FF910077CE53 /* VideoFullscreenInterfaceMac.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VideoFullscreenInterfaceMac.h; sourceTree = "<group>"; };
@@ -21189,6 +21193,8 @@
E18D83E3243F71CF009247D6 /* FakeXRButtonStateInit.idl */,
E18D83EA243F71D4009247D6 /* FakeXRInputSourceInit.h */,
E18D83DC243F71CB009247D6 /* FakeXRInputSourceInit.idl */,
+ 5263BF2027C1B5380085250C /* FakeXRJointStateInit.h */,
+ 5263BF2227C1B53B0085250C /* FakeXRJointStateInit.idl */,
E18D83E5243F71D1009247D6 /* FakeXRRigidTransformInit.h */,
E18D83E6243F71D1009247D6 /* FakeXRRigidTransformInit.idl */,
E18D83DF243F71CD009247D6 /* FakeXRViewInit.h */,
@@ -21284,6 +21290,7 @@
5273CCAC2564576C00850007 /* JSFakeXRBoundsPoint.cpp */,
5273CCAD2564576C00850007 /* JSFakeXRButtonStateInit.cpp */,
5273CCAA2564576B00850007 /* JSFakeXRInputSourceInit.cpp */,
+ 52A0BE6527C227E00046611E /* JSFakeXRJointStateInit.cpp */,
5273CCAE2564576D00850007 /* JSFakeXRRigidTransformInit.cpp */,
5273CCAF2564576E00850007 /* JSFakeXRViewInit.cpp */,
51714EAE1CF6654A004723C4 /* JSGCObservation.cpp */,
@@ -38872,6 +38879,7 @@
5273CCB12564576F00850007 /* JSFakeXRBoundsPoint.cpp in Sources */,
5273CCB22564576F00850007 /* JSFakeXRButtonStateInit.cpp in Sources */,
5273CCB02564576F00850007 /* JSFakeXRInputSourceInit.cpp in Sources */,
+ 52A0BE6627C227E10046611E /* JSFakeXRJointStateInit.cpp in Sources */,
5273CCB32564576F00850007 /* JSFakeXRRigidTransformInit.cpp in Sources */,
5273CCB42564576F00850007 /* JSFakeXRViewInit.cpp in Sources */,
DE5F86121FA239E7006DB63A /* JSGCObservation.cpp in Sources */,
Modified: trunk/Source/WebCore/platform/xr/PlatformXR.h (292779 => 292780)
--- trunk/Source/WebCore/platform/xr/PlatformXR.h 2022-04-12 18:08:56 UTC (rev 292779)
+++ trunk/Source/WebCore/platform/xr/PlatformXR.h 2022-04-12 18:52:27 UTC (rev 292780)
@@ -163,7 +163,7 @@
#if ENABLE(WEBXR_HANDS)
enum class HandJoint : unsigned {
- Wrist,
+ Wrist = 0,
ThumbMetacarpal,
ThumbPhalanxProximal,
ThumbPhalanxDistal,
@@ -187,7 +187,8 @@
PinkyFingerPhalanxProximal,
PinkyFingerPhalanxIntermediate,
PinkyFingerPhalanxDistal,
- PinkyFingerTip
+ PinkyFingerTip,
+ Count
};
#endif
@@ -313,6 +314,18 @@
template<class Decoder> static std::optional<InputSourcePose> decode(Decoder&);
};
+#if ENABLE(WEBXR_HANDS)
+ struct InputSourceHandJoint {
+ InputSourcePose pose;
+ float radius { 0 };
+
+ template<class Encoder> void encode(Encoder&) const;
+ template<class Decoder> static std::optional<InputSourceHandJoint> decode(Decoder&);
+ };
+
+ using HandJointsVector = Vector<std::optional<InputSourceHandJoint>>;
+#endif
+
struct InputSource {
InputSourceHandle handle { 0 };
XRHandedness handeness { XRHandedness::None };
@@ -323,8 +336,7 @@
Vector<InputSourceButton> buttons;
Vector<float> axes;
#if ENABLE(WEBXR_HANDS)
- // FIXME: Actually hold some hand data.
- bool simulateHand { false };
+ std::optional<HandJointsVector> handJoints;
#endif
template<class Encoder> void encode(Encoder&) const;
@@ -624,7 +636,30 @@
return inputSourcePose;
}
+#if ENABLE(WEBXR_HANDS)
template<class Encoder>
+void Device::FrameData::InputSourceHandJoint::encode(Encoder& encoder) const
+{
+ encoder << pose;
+ encoder << radius;
+}
+
+template<class Decoder>
+std::optional<Device::FrameData::InputSourceHandJoint> Device::FrameData::InputSourceHandJoint::decode(Decoder& decoder)
+{
+ std::optional<InputSourcePose> pose;
+ decoder >> pose;
+ if (!pose)
+ return std::nullopt;
+ std::optional<float> radius;
+ decoder >> radius;
+ if (!radius)
+ return std::nullopt;
+ return { { WTFMove(*pose), *radius } };
+}
+#endif
+
+template<class Encoder>
void Device::FrameData::InputSource::encode(Encoder& encoder) const
{
encoder << handle;
@@ -635,6 +670,9 @@
encoder << gripOrigin;
encoder << buttons;
encoder << axes;
+#if ENABLE(WEBXR_HANDS)
+ encoder << handJoints;
+#endif
}
template<class Decoder>
@@ -657,6 +695,10 @@
return std::nullopt;
if (!decoder.decode(source.axes))
return std::nullopt;
+#if ENABLE(WEBXR_HANDS)
+ if (!decoder.decode(source.handJoints))
+ return std::nullopt;
+#endif
return source;
}
Modified: trunk/Source/WebCore/testing/FakeXRInputSourceInit.h (292779 => 292780)
--- trunk/Source/WebCore/testing/FakeXRInputSourceInit.h 2022-04-12 18:08:56 UTC (rev 292779)
+++ trunk/Source/WebCore/testing/FakeXRInputSourceInit.h 2022-04-12 18:52:27 UTC (rev 292780)
@@ -34,6 +34,10 @@
#include "XRTargetRayMode.h"
#include <wtf/Vector.h>
+#if ENABLE(WEBXR_HANDS)
+#include "FakeXRJointStateInit.h"
+#endif
+
namespace WebCore {
struct FakeXRInputSourceInit {
@@ -46,7 +50,7 @@
Vector<FakeXRButtonStateInit> supportedButtons;
FakeXRRigidTransformInit gripOrigin;
#if ENABLE(WEBXR_HANDS)
- bool simulateHand { false };
+ Vector<FakeXRJointStateInit> handJoints;
#endif
};
Modified: trunk/Source/WebCore/testing/FakeXRInputSourceInit.idl (292779 => 292780)
--- trunk/Source/WebCore/testing/FakeXRInputSourceInit.idl 2022-04-12 18:08:56 UTC (rev 292779)
+++ trunk/Source/WebCore/testing/FakeXRInputSourceInit.idl 2022-04-12 18:52:27 UTC (rev 292780)
@@ -43,5 +43,5 @@
FakeXRRigidTransformInit gripOrigin;
// Optional hand input. For now we don't care about the actual
// data. We're just creating the object for testing.
- [Conditional=WEBXR_HANDS] boolean simulateHand = false;
+ [Conditional=WEBXR_HANDS] sequence<FakeXRJointStateInit> handJoints;
};
Copied: trunk/Source/WebCore/testing/FakeXRJointStateInit.h (from rev 292779, trunk/Source/WebCore/Modules/webxr/WebXRJointPose.idl) (0 => 292780)
--- trunk/Source/WebCore/testing/FakeXRJointStateInit.h (rev 0)
+++ trunk/Source/WebCore/testing/FakeXRJointStateInit.h 2022-04-12 18:52:27 UTC (rev 292780)
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2022 Apple Inc. 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_HANDS)
+
+#include "FakeXRRigidTransformInit.h"
+
+namespace WebCore {
+
+struct FakeXRJointStateInit {
+ FakeXRRigidTransformInit pose;
+ float radius;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(WEBXR_HANDS)
Copied: trunk/Source/WebCore/testing/FakeXRJointStateInit.idl (from rev 292779, trunk/Source/WebCore/Modules/webxr/WebXRJointPose.idl) (0 => 292780)
--- trunk/Source/WebCore/testing/FakeXRJointStateInit.idl (rev 0)
+++ trunk/Source/WebCore/testing/FakeXRJointStateInit.idl 2022-04-12 18:52:27 UTC (rev 292780)
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2022 Apple Inc. 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.
+ */
+
+// Used to update the pose and radius of a joint
+[
+ EnabledBySetting=WebXREnabled&WebXRHandInputModuleEnabled,
+ Conditional=WEBXR_HANDS,
+] dictionary FakeXRJointStateInit {
+ FakeXRRigidTransformInit pose;
+ float radius = 0.0;
+};
Modified: trunk/Source/WebCore/testing/WebFakeXRInputController.cpp (292779 => 292780)
--- trunk/Source/WebCore/testing/WebFakeXRInputController.cpp 2022-04-12 18:08:56 UTC (rev 292779)
+++ trunk/Source/WebCore/testing/WebFakeXRInputController.cpp 2022-04-12 18:52:27 UTC (rev 292780)
@@ -28,6 +28,7 @@
#if ENABLE(WEBXR)
#include "WebFakeXRDevice.h"
+#include "XRHandJoint.h"
namespace WebCore {
@@ -36,6 +37,11 @@
using InputSourcePose = PlatformXR::Device::FrameData::InputSourcePose;
using ButtonType = FakeXRButtonStateInit::Type;
+#if ENABLE(WEBXR_HANDS)
+using HandJointsVector = PlatformXR::Device::FrameData::HandJointsVector;
+using InputSourceHandJoint = PlatformXR::Device::FrameData::InputSourceHandJoint;
+#endif
+
// 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 };
@@ -51,13 +57,13 @@
, m_profiles(init.profiles)
, m_primarySelected(init.selectionStarted)
, m_simulateSelect(init.selectionClicked)
-#if ENABLE(WEBXR_HANDS)
- , m_simulateHand(init.simulateHand)
-#endif
{
setPointerOrigin(init.pointerOrigin, false);
setGripOrigin(init.gripOrigin, false);
setSupportedButtons(init.supportedButtons);
+#if ENABLE(WEBXR_HANDS)
+ updateHandJoints(init.handJoints);
+#endif
}
void WebFakeXRInputController::setGripOrigin(FakeXRRigidTransformInit gripOrigin, bool emulatedPosition)
@@ -110,7 +116,7 @@
state.pointerOrigin = m_pointerOrigin;
state.gripOrigin = m_gripOrigin;
#if ENABLE(WEBXR_HANDS)
- state.simulateHand = m_simulateHand;
+ state.handJoints = m_handJoints;
#endif
if (m_simulateSelect)
@@ -182,6 +188,28 @@
return result;
}
+#if ENABLE(WEBXR_HANDS)
+void WebFakeXRInputController::updateHandJoints(const Vector<FakeXRJointStateInit>& handJoints)
+{
+ if (handJoints.isEmpty() || handJoints.size() != static_cast<size_t>(XRHandJoint::Count)) {
+ m_handJoints = std::nullopt;
+ return;
+ }
+
+ HandJointsVector updatedJoints;
+ for (auto handJoint : handJoints) {
+ auto transform = WebFakeXRDevice::parseRigidTransform(handJoint.pose);
+ if (transform.hasException()) {
+ updatedJoints.append(std::nullopt);
+ continue;
+ }
+
+ updatedJoints.append(InputSourceHandJoint { InputSourcePose { transform.releaseReturnValue(), false }, handJoint.radius });
+ }
+ m_handJoints = WTFMove(updatedJoints);
+}
+#endif // ENABLE(WEBXR_HANDS)
+
} // namespace WebCore
#endif // ENABLE(WEBXR)
Modified: trunk/Source/WebCore/testing/WebFakeXRInputController.h (292779 => 292780)
--- trunk/Source/WebCore/testing/WebFakeXRInputController.h 2022-04-12 18:08:56 UTC (rev 292779)
+++ trunk/Source/WebCore/testing/WebFakeXRInputController.h 2022-04-12 18:52:27 UTC (rev 292780)
@@ -37,6 +37,10 @@
#include <wtf/RefCounted.h>
#include <wtf/Vector.h>
+#if ENABLE(WEBXR_HANDS)
+#include "FakeXRJointStateInit.h"
+#endif
+
namespace WebCore {
class WebFakeXRInputController final : public RefCounted<WebFakeXRInputController> {
@@ -57,6 +61,10 @@
void setSupportedButtons(const Vector<FakeXRButtonStateInit>&);
void updateButtonState(const FakeXRButtonStateInit&);
bool isConnected() const { return m_connected; }
+
+#if ENABLE(WEBXR_HANDS)
+ void updateHandJoints(const Vector<FakeXRJointStateInit>&);
+#endif
PlatformXR::Device::FrameData::InputSource getFrameData();
@@ -80,7 +88,7 @@
bool m_primarySelected { false };
bool m_simulateSelect { false };
#if ENABLE(WEBXR_HANDS)
- bool m_simulateHand { false };
+ std::optional<PlatformXR::Device::FrameData::HandJointsVector> m_handJoints;
#endif
};
Modified: trunk/Source/WebCore/testing/WebFakeXRInputController.idl (292779 => 292780)
--- trunk/Source/WebCore/testing/WebFakeXRInputController.idl 2022-04-12 18:08:56 UTC (rev 292779)
+++ trunk/Source/WebCore/testing/WebFakeXRInputController.idl 2022-04-12 18:52:27 UTC (rev 292780)
@@ -73,4 +73,6 @@
// Used to update the state of a button currently supported by the input source
// Will not add support for that button if it is not currently supported.
undefined updateButtonState(FakeXRButtonStateInit buttonState);
+
+ [Conditional=WEBXR_HANDS] undefined updateHandJoints(sequence<FakeXRJointStateInit> handJoints);
};
Modified: trunk/Source/WebCore/testing/WebXRTest.cpp (292779 => 292780)
--- trunk/Source/WebCore/testing/WebXRTest.cpp 2022-04-12 18:08:56 UTC (rev 292779)
+++ trunk/Source/WebCore/testing/WebXRTest.cpp 2022-04-12 18:52:27 UTC (rev 292780)
@@ -39,6 +39,19 @@
WebXRTest::~WebXRTest() = default;
+static PlatformXR::Device::FeatureList parseFeatures(const Vector<JSC::JSValue>& featureList, ScriptExecutionContext& context)
+{
+ PlatformXR::Device::FeatureList features;
+ if (auto* globalObject = context.globalObject()) {
+ for (auto& feature : featureList) {
+ auto featureString = feature.toWTFString(globalObject);
+ if (auto sessionFeature = PlatformXR::parseSessionFeatureDescriptor(featureString))
+ features.append(*sessionFeature);
+ }
+ }
+ return features;
+}
+
void WebXRTest::simulateDeviceConnection(ScriptExecutionContext& context, const FakeXRDeviceInit& init, WebFakeXRDevicePromise&& promise)
{
// https://immersive-web.github.io/webxr-test-api/#dom-xrtest-simulatedeviceconnection
@@ -48,16 +61,12 @@
device->setViews(init.views);
- PlatformXR::Device::FeatureList features;
- if (init.supportedFeatures) {
- if (auto* globalObject = context.globalObject()) {
- for (auto& feature : init.supportedFeatures.value()) {
- auto featureString = feature.toWTFString(globalObject);
- if (auto sessionFeature = PlatformXR::parseSessionFeatureDescriptor(featureString))
- features.append(*sessionFeature);
- }
- }
- }
+ PlatformXR::Device::FeatureList supportedFeatures;
+ if (init.supportedFeatures)
+ supportedFeatures = parseFeatures(init.supportedFeatures.value(), context);
+ PlatformXR::Device::FeatureList enabledFeatures;
+ if (init.enabledFeatures)
+ enabledFeatures = parseFeatures(init.enabledFeatures.value(), context);
if (init.boundsCoordinates) {
if (init.boundsCoordinates->size() < 3) {
@@ -84,8 +93,10 @@
supportedModes.append(XRSessionMode::ImmersiveVr);
}
- for (auto& mode : supportedModes)
- simulatedDevice.setSupportedFeatures(mode, features);
+ for (auto& mode : supportedModes) {
+ simulatedDevice.setSupportedFeatures(mode, supportedFeatures);
+ simulatedDevice.setEnabledFeatures(mode, enabledFeatures);
+ }
m_context->registerSimulatedXRDeviceForTesting(simulatedDevice);
Modified: trunk/Source/WebCore/testing/WebXRTest.h (292779 => 292780)
--- trunk/Source/WebCore/testing/WebXRTest.h 2022-04-12 18:08:56 UTC (rev 292779)
+++ trunk/Source/WebCore/testing/WebXRTest.h 2022-04-12 18:52:27 UTC (rev 292780)
@@ -46,6 +46,7 @@
Vector<FakeXRViewInit> views;
std::optional<Vector<JSC::JSValue>> supportedFeatures;
+ std::optional<Vector<JSC::JSValue>> enabledFeatures;
std::optional<Vector<FakeXRBoundsPoint>> boundsCoordinates;
Modified: trunk/Source/WebCore/testing/WebXRTest.idl (292779 => 292780)
--- trunk/Source/WebCore/testing/WebXRTest.idl 2022-04-12 18:08:56 UTC (rev 292779)
+++ trunk/Source/WebCore/testing/WebXRTest.idl 2022-04-12 18:52:27 UTC (rev 292780)
@@ -61,6 +61,10 @@
// NOTE: This is meant to emulate hardware support, not whether a feature is
// currently available (e.g. bounds not being tracked per below)
sequence<any> supportedFeatures;
+
+ // The list of features that are automatically enabled and do
+ // not need further explicit consent.
+ sequence<any> enabledFeatures;
// The bounds coordinates. If empty, no bounded reference space is currently tracked.
// If not, must have at least three elements.
Modified: trunk/Source/WebKit/ChangeLog (292779 => 292780)
--- trunk/Source/WebKit/ChangeLog 2022-04-12 18:08:56 UTC (rev 292779)
+++ trunk/Source/WebKit/ChangeLog 2022-04-12 18:52:27 UTC (rev 292780)
@@ -1,3 +1,14 @@
+2022-04-12 Ada Chan <[email protected]>
+
+ [WebXR] Implement the WebXRFrame methods for getting joints' poses and radii
+ https://bugs.webkit.org/show_bug.cgi?id=238968
+
+ Reviewed by Dean Jackson.
+
+ * Shared/XR/XRDeviceProxy.cpp:
+ (WebKit::XRDeviceProxy::initializeTrackingAndRendering):
+ Initialize input sources on session start.
+
2022-04-12 Youenn Fablet <[email protected]>
Remove getsockopt from WebProcess sandboxes
Modified: trunk/Source/WebKit/Shared/XR/XRDeviceProxy.cpp (292779 => 292780)
--- trunk/Source/WebKit/Shared/XR/XRDeviceProxy.cpp 2022-04-12 18:08:56 UTC (rev 292779)
+++ trunk/Source/WebKit/Shared/XR/XRDeviceProxy.cpp 2022-04-12 18:52:27 UTC (rev 292780)
@@ -68,8 +68,21 @@
if (sessionMode != PlatformXR::SessionMode::ImmersiveVr)
return;
- if (m_xrSystem)
- m_xrSystem->initializeTrackingAndRendering();
+ if (!m_xrSystem)
+ return;
+
+ m_xrSystem->initializeTrackingAndRendering();
+
+ // This is called from the constructor of WebXRSession. Since sessionDidInitializeInputSources()
+ // ends up calling queueTaskKeepingObjectAlive() which refs the WebXRSession object, we
+ // should delay this call after the WebXRSession has finished construction.
+ callOnMainRunLoop([this, weakThis = WeakPtr { *this }]() {
+ if (!weakThis)
+ return;
+
+ if (trackingAndRenderingClient())
+ trackingAndRenderingClient()->sessionDidInitializeInputSources({ });
+ });
}
void XRDeviceProxy::shutDownTrackingAndRendering()