Commit 5d9d0113 authored by Alex Cooper's avatar Alex Cooper Committed by Commit Bot

[XR] Stop processing input if an input event ends the session

If the javascript callback ends the XRSession, then the input events
should stop being processed.  This check is also needed because ending
the session may have changed the state of other variables that are still
being processed, and access violations could occur.

Bug: 967853
Change-Id: Ia54112cdb806e1ed75c32ac9b202dafb85d9b9cc
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1633749
Commit-Queue: Alexander Cooper <alcooper@chromium.org>
Reviewed-by: default avatarBill Orr <billorr@chromium.org>
Cr-Commit-Position: refs/heads/master@{#664457}
parent 89fe7ce9
......@@ -811,9 +811,14 @@ void XRSession::OnInputStateChange(
event_type_names::kInputsourceschange, this, added, removed));
}
// Now that we've fired the input sources change event (if needed), update and
// fire events for any select state changes.
// Now that we've fired the input sources change event (if needed), update
// and fire events for any select state changes.
for (const auto& input_state : input_states) {
// If anything during the process of updating the select state caused us
// to end our session, we should stop processing select state updates.
if (ended_)
break;
XRInputSource* input_source = input_sources_.at(input_state->source_id);
DCHECK(input_source);
UpdateSelectState(input_source, input_state);
......@@ -821,8 +826,8 @@ void XRSession::OnInputStateChange(
}
void XRSession::OnSelectStart(XRInputSource* input_source) {
// Discard duplicate events
if (input_source->primaryInputPressed())
// Discard duplicate events, or events after the session has ended.
if (input_source->primaryInputPressed() || ended_)
return;
input_source->setPrimaryInputPressed(true);
......@@ -840,8 +845,8 @@ void XRSession::OnSelectStart(XRInputSource* input_source) {
}
void XRSession::OnSelectEnd(XRInputSource* input_source) {
// Discard duplicate events
if (!input_source->primaryInputPressed())
// Discard duplicate events, or events after the session has ended.
if (!input_source->primaryInputPressed() || ended_)
return;
input_source->setPrimaryInputPressed(false);
......@@ -872,7 +877,9 @@ void XRSession::OnSelect(XRInputSource* input_source) {
OnSelectStart(input_source);
}
if (!input_source->selectionCancelled()) {
// If SelectStart caused the session to end, we shouldn't try to fire the
// select event.
if (!input_source->selectionCancelled() && !ended_) {
XRInputSourceEvent* event =
CreateInputSourceEvent(event_type_names::kSelect, input_source);
DispatchEvent(*event);
......
......@@ -140,6 +140,10 @@ class MockXRInputSource {
this.primary_input_pressed_ = value;
}
set primaryInputClicked(value) {
this.primary_input_clicked_ = value;
}
get grip() {
if (this.grip_) {
return this.grip_.matrix;
......
<!DOCTYPE html>
<script src="../resources/testharness.js"></script>
<script src="../resources/testharnessreport.js"></script>
<script src="file:///gen/layout_test_data/mojo/public/js/mojo_bindings.js"></script>
<script src="file:///gen/device/vr/public/mojom/vr_service.mojom.js"></script>
<script src="../external/wpt/resources/chromium/webxr-test.js"></script>
<script src="../external/wpt/webxr/resources/webxr_test_constants.js"></script>
<script src="../xr/resources/xr-internal-device-mocking.js"></script>
<script src="../xr/resources/xr-test-utils.js"></script>
<canvas id="webgl-canvas"></canvas>
<script>
let testName = "Calling end during an input callback stops processing at the right time";
let fakeDeviceInitParams = { supportsImmersive:true };
let requestSessionModes = ['immersive-vr'];
function requestImmersiveSession() {
return new Promise((resolve, reject) => {
runWithUserGesture(() => {
navigator.xr.requestSession('immersive-vr').then((session) => {
resolve(session);
}, (err) => {
reject(err);
});
});
});
}
let testFunction = function(session, t, fakeDeviceController) {
// helper method to send a click and then request a dummy animation frame to
// ensure that the click propagates. We're doing everything in these tests
// from event watchers, we just need to trigger the add/click to make the
// event listeners callback.
function sendClick(session) {
let input_source = new MockXRInputSource();
input_source.primaryInputClicked = true;
fakeDeviceController.addInputSource(input_source);
session.requestAnimationFrame(() => {});
}
function sessionEndTest(endEvent, eventOrder) {
return requestImmersiveSession().then((session) => {
let eventWatcher = new EventWatcher(t, session,
["inputsourceschange", "selectstart", "select", "selectend", "end"]);
let eventPromise = eventWatcher.wait_for(eventOrder);
// Session must have a baseLayer or frame requests will be ignored.
session.updateRenderState({ baseLayer: new XRWebGLLayer(session, gl) });
session.addEventListener(endEvent, ()=> {
session.end();
}, false);
sendClick(session);
return eventPromise;
});
}
// Need to have a valid pose or input events don't process.
fakeDeviceController.setXRPresentationFrameData(VALID_POSE_MATRIX, [{
eye:"left",
projectionMatrix: VALID_PROJECTION_MATRIX,
viewMatrix: VALID_VIEW_MATRIX
}, {
eye:"right",
projectionMatrix: VALID_PROJECTION_MATRIX,
viewMatrix: VALID_VIEW_MATRIX
}]);
// End our first session, just for simplicity, then make end session calls
// during each of our input events, and ensure that events stop processing
// and no crashes occur from calling end inside the event callbacks.
return session.end().then(() => {
return sessionEndTest("inputsourceschange", ["inputsourceschange", "end"]);
}).then(() => {
return sessionEndTest("selectstart", ["inputsourceschange", "selectstart", "end"]);
}).then(() => {
return sessionEndTest("select", ["inputsourceschange", "selectstart", "select", "end"]);
}).then(() => {
return sessionEndTest("selectend", ["inputsourceschange", "selectstart", "select", "selectend", "end"]);
});
};
xr_session_promise_test(
testFunction, fakeDeviceInitParams, requestSessionModes, testName);
</script>
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment