commit b703ee2a8c4d6dfa15e987edbfa81586ab7dfa83
parent 4c5d9a5ef0092bf4f1d59226748e390ce1e8000f
Author: Alexander Cooper <alcooper@chromium.org>
Date: Thu, 6 Nov 2025 21:37:21 +0000
Bug 1997976 [wpt PR 55829] - Write a WPT for XRVisibilityMaskChange, a=testonly
Automatic update from web-platform-tests
Write a WPT for XRVisibilityMaskChange
Bug: 450538226
Change-Id: I58500a27c827e8660da2bf16bd70d0da54a97419
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7108463
Auto-Submit: Alexander Cooper <alcooper@chromium.org>
Reviewed-by: Brandon Jones <bajones@chromium.org>
Commit-Queue: Alexander Cooper <alcooper@chromium.org>
Commit-Queue: Brandon Jones <bajones@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1539433}
--
wpt-commits: c9ccd5080793cf32a8369885f214933eac5e1902
wpt-pr: 55829
Diffstat:
2 files changed, 114 insertions(+), 1 deletion(-)
diff --git a/testing/web-platform/tests/resources/chromium/webxr-test.js b/testing/web-platform/tests/resources/chromium/webxr-test.js
@@ -382,6 +382,7 @@ class MockRuntime {
this.send_mojo_space_reset_ = false;
this.stageParameters_ = null;
this.stageParametersId_ = 1;
+ this.nextVisibilityMaskId_ = 1;
this.service_ = service;
@@ -886,6 +887,18 @@ class MockRuntime {
break;
}
+ let visibilityMask = null;
+ if (fakeXRViewInit.visibilityMask) {
+ let maskInit = fakeXRViewInit.visibilityMask;
+ visibilityMask = {
+ unvalidatedIndices: maskInit.indices,
+ vertices: []
+ };
+ for (let i = 0; i + 1 < maskInit.vertices.length; i+= 2) {
+ visibilityMask.vertices.push( { x: maskInit.vertices[i], y: maskInit.vertices[i+1]});
+ }
+ }
+
return {
eye: viewEye,
geometry: {
@@ -903,7 +916,8 @@ class MockRuntime {
},
isFirstPersonObserver: fakeXRViewInit.isFirstPersonObserver ? true : false,
viewOffset: composeGFXTransform(fakeXRViewInit.viewOffset),
- visibilityMaskId: { idValue : 0 }
+ visibilityMask: visibilityMask,
+ visibilityMaskId: { idValue : this.nextVisibilityMaskId_++ }
};
}
diff --git a/testing/web-platform/tests/webxr/xrView_visibility_mask_change.https.html b/testing/web-platform/tests/webxr/xrView_visibility_mask_change.https.html
@@ -0,0 +1,99 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/webxr_util.js"></script>
+<script src="resources/webxr_test_constants.js"></script>
+<script src="resources/webxr_test_asserts.js"></script>
+
+<script>
+
+let testName = "VisibilityMaskChangeEvent properly fires with expected values";
+
+let fakeViews = [{
+ eye:"left",
+ viewOffset: LEFT_OFFSET,
+ resolution: VALID_RESOLUTION,
+ fieldOfView: VALID_FIELD_OF_VIEW,
+ // The webxr-test-api requires that we still set this for now, but it is
+ // supposed to be ignored.
+ projectionMatrix: IDENTITY_MATRIX
+ }, {
+ eye:"right",
+ viewOffset: RIGHT_OFFSET,
+ resolution: VALID_RESOLUTION,
+ fieldOfView: VALID_FIELD_OF_VIEW,
+ // The webxr-test-api requires that we still set this for now, but it is
+ // supposed to be ignored.
+ projectionMatrix: IDENTITY_MATRIX
+ },
+];
+
+const leftMask = {
+ vertices: [ 0, 0, 0, 1, 1, 0, 1, 1 ],
+ indices: [0, 1, 2, 0, 2, 3]
+};
+
+const rightMask = {
+ vertices: [ 1, 1, 1, 2, 2, 1, 2, 2 ],
+ indices: [0, 2, 3, 0, 1, 2]
+};
+
+let fakeDeviceInitParams = {
+ supportsImmersive: true,
+ supportedModes: ["inline", "immersive-vr"],
+ views: fakeViews,
+ viewerOrigin: IDENTITY_TRANSFORM,
+ supportedFeatures: ALL_FEATURES
+};
+
+function assert_list_approx_equals(actual, expected, prefix) {
+ assert_equals(expected.length, actual.length, prefix + ": lengths not equal");
+ for (let i = 0; i < expected.length; i++) {
+ assert_approx_equals(actual[i], expected[i], FLOAT_EPSILON, prefix +
+ ": mismatch in list at component: " + i +
+ ", expected=" + expected, " actual=" + actual);
+ }
+}
+
+function validateMask(fakeView, mask) {
+ assert_equals(mask.eye, fakeView.eye);
+ assert_list_approx_equals(mask.vertices, fakeView.visibilityMask.vertices, fakeView.eye);
+ assert_list_approx_equals(mask.indices, fakeView.visibilityMask.indices, fakeView.eye);
+}
+
+let testFunction = function(session, fakeDeviceController, t) {
+ let eventWatcher = new EventWatcher(t, session, ["watcherdone"]);
+ let visibilityMaskEvents = 0;
+ session.addEventListener('visibilitymaskchange', (mask)=> {
+ visibilityMaskEvents++;
+ t.step(() => {
+ assert_equals(mask.session, session);
+ assert_less_than(mask.index, fakeViews.length, "Received an unexpected view");
+ validateMask(fakeViews[mask.index], mask);
+
+
+ if (visibilityMaskEvents >= 2) {
+ session.dispatchEvent(new Event("watcherdone"))
+ }
+ });
+ });
+
+ // We *could* set the visibilityMasks on the views by default; but UAs do not
+ // HAVE to, but MAY send events during the session resolution. By setting this
+ // after the session is resolved and the event is subscribed, we ensure we
+ // don't miss the event due to UA allowable differences.
+ fakeViews[0].visibilityMask = leftMask;
+ fakeViews[1].visibilityMask = rightMask;
+ fakeDeviceController.setViews(fakeViews);
+
+ // We don't need to do anything on the next animation frame, the act of
+ // requesting it after we update the views should be enough to trigger our
+ // events.
+ session.requestAnimationFrame(()=>{});
+ return eventWatcher.wait_for(["watcherdone"]);
+};
+
+xr_session_promise_test(
+ testName, testFunction, fakeDeviceInitParams, 'immersive-vr');
+
+</script>