Commit 48315306 authored by Brandon Jones's avatar Brandon Jones Committed by Commit Bot

Added VRSession creation.

This CL only enables the creation of exclusive VRSession objects. It
does not provide the ability to present to a headset, or many of the
functions of a VRSession. Those will be added in follow up CLs to allow
the more complicated logic to be reviewed independently.

Bug: 670510
Change-Id: Ic2b3b1801bf8f3ee4263d009daab8215b0b179d5
Reviewed-on: https://chromium-review.googlesource.com/685396
Commit-Queue: Brandon Jones <bajones@chromium.org>
Reviewed-by: default avatarKentaro Hara <haraken@chromium.org>
Reviewed-by: default avatarMichael Thiessen <mthiesse@chromium.org>
Cr-Commit-Position: refs/heads/master@{#505305}
parent 2243abee
<!DOCTYPE html>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<script src="../resources/fake-vr-displays.js"></script>
<script src="file:///gen/layout_test_data/mojo/public/js/mojo_bindings.js"></script>
<script src="file:///gen/device/vr/vr_service.mojom.js"></script>
<script src="../resources/mock-vr-service.js"></script>
<canvas id="webgl-canvas"></canvas>
<script src="../resources/presentation-setup.js"></script>
<script>
let fakeDisplays = fakeVRDisplays();
vr_test((t, mockService) => {
let watcherDone = new Event("watcherdone");
navigator.vr.getDevices().then( (devices) => {
let pixel = devices[0];
runWithUserGesture( () => {
pixel.requestSession({ exclusive: true }).then( (session) => {
let eventWatcher = new EventWatcher(t, session, ["end", "watcherdone"]);
let eventPromise = eventWatcher.wait_for(["end", "watcherdone"]);
function onSessionEnd(event) {
t.step( () => {
assert_equals(event.session, session);
session.dispatchEvent(watcherDone);
});
}
session.addEventListener("end", onSessionEnd, false);
session.end();
return eventPromise;
}, (err) => {
t.step( () => {
assert_unreached("requestSession rejected");
});
}).then( () => {
t.done();
});
});
}, (err) => {
t.step( () => {
assert_unreached("getDevices rejected");
});
});
}, [fakeDisplays["Pixel"]],
"Test deviceconnect fires when devices are connected.");
</script>
......@@ -31,10 +31,17 @@ vr_test( (t) => {
magicWindowOnly.requestSession({ exclusive: true }));
}, "requestSession rejected for device that only supports non-exclusive sessions.");
// TODO: Once implemented, ensure that the pixel device can create an
// exclusive session.
t.done();
pixel.requestSession({ exclusive: true }).then( (session) => {
t.step( () => {
assert_true(session.exclusive);
}, "requestSession returned correct results");
}, (err) => {
t.step( () => {
assert_unreached("requestSession rejected");
});
}).then( () => {
t.done();
});
});
}, (err) => {
t.step( () => {
......
<!DOCTYPE html>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<script src="../resources/fake-vr-displays.js"></script>
<script src="file:///gen/layout_test_data/mojo/public/js/mojo_bindings.js"></script>
<script src="file:///gen/device/vr/vr_service.mojom.js"></script>
<script src="../resources/mock-vr-service.js"></script>
<script src="../resources/test-constants.js"></script>
<canvas id="webgl-canvas"></canvas>
<script src="../resources/presentation-setup.js"></script>
<script>
let fakeDisplays = fakeVRDisplays();
vr_test( (t) => {
return navigator.vr.getDevices().then( (devices) => {
let pixel = devices[0];
runWithUserGesture( () => {
pixel.requestSession({ exclusive: true }).then( (session) => {
t.step( () => {
assert_true(session.exclusive);
assert_equals(session.device, pixel);
assert_approx_equals(session.depthNear, 0.1, FLOAT_EPSILON);
assert_approx_equals(session.depthFar, 1000.0, FLOAT_EPSILON);
}, "requestSession returned correct results");
}, (err) => {
t.step( () => {
assert_unreached("requestSession rejected");
});
}).then( () => {
t.done();
});
});
}, (err) => {
t.step( () => {
assert_unreached("getDevices rejected");
});
});
}, [fakeDisplays["Pixel"]],
"supportsSession returns expected exclusive session");
</script>
......@@ -7245,6 +7245,28 @@ interface VRPose
getter orientation
getter position
method constructor
interface VRSession : EventTarget
attribute @@toStringTag
getter depthFar
getter depthNear
getter device
getter exclusive
getter onblur
getter onend
getter onfocus
getter onresetpose
method constructor
method end
setter depthFar
setter depthNear
setter onblur
setter onend
setter onfocus
setter onresetpose
interface VRSessionEvent : Event
attribute @@toStringTag
getter session
method constructor
interface VRStageParameters
attribute @@toStringTag
getter sittingToStandingTransform
......
......@@ -56,6 +56,7 @@ generate_event_interfaces("modules_bindings_generated_event_interfaces") {
"//third_party/WebKit/Source/modules/storage/StorageEvent.idl",
"//third_party/WebKit/Source/modules/vr/VRDisplayEvent.idl",
"//third_party/WebKit/Source/modules/vr/latest/VRDeviceEvent.idl",
"//third_party/WebKit/Source/modules/vr/latest/VRSessionEvent.idl",
"//third_party/WebKit/Source/modules/webaudio/AudioProcessingEvent.idl",
"//third_party/WebKit/Source/modules/webaudio/OfflineAudioCompletionEvent.idl",
"//third_party/WebKit/Source/modules/webgl/WebGLContextEvent.idl",
......
......@@ -212,6 +212,7 @@
"removetrack",
"repeatEvent",
"reset",
"resetpose",
"resize",
"resourcetimingbufferfull",
"result",
......
......@@ -46,6 +46,7 @@
"modules/vr/VRDisplay",
"modules/vr/latest/VR",
"modules/vr/latest/VRDevice",
"modules/vr/latest/VRSession",
"modules/webaudio/AudioContext",
"modules/webaudio/AudioNode",
"modules/webmidi/MIDIAccess",
......
......@@ -304,6 +304,8 @@ modules_idl_files =
"vr/latest/VR.idl",
"vr/latest/VRDevice.idl",
"vr/latest/VRDeviceEvent.idl",
"vr/latest/VRSession.idl",
"vr/latest/VRSessionEvent.idl",
"webaudio/AnalyserNode.idl",
"webaudio/AudioBuffer.idl",
"webaudio/AudioBufferSourceNode.idl",
......@@ -567,6 +569,7 @@ modules_dictionary_idl_files =
"vr/VRLayerInit.idl",
"vr/latest/VRDeviceEventInit.idl",
"vr/latest/VRSessionCreationOptions.idl",
"vr/latest/VRSessionEventInit.idl",
"webaudio/AnalyserOptions.idl",
"webaudio/AudioBufferOptions.idl",
"webaudio/AudioBufferSourceOptions.idl",
......
......@@ -33,6 +33,10 @@ blink_modules_sources("vr") {
"latest/VRDevice.h",
"latest/VRDeviceEvent.cpp",
"latest/VRDeviceEvent.h",
"latest/VRSession.cpp",
"latest/VRSession.h",
"latest/VRSessionEvent.cpp",
"latest/VRSessionEvent.h",
]
deps = [
......
......@@ -9,6 +9,7 @@
#include "core/dom/UserGestureIndicator.h"
#include "modules/EventTargetModules.h"
#include "modules/vr/latest/VR.h"
#include "modules/vr/latest/VRSession.h"
namespace blink {
......@@ -23,9 +24,6 @@ const char kNonExclusiveNotSupported[] =
const char kRequestNotInUserGesture[] =
"Exclusive sessions can only be requested during a user gesture.";
const char kSessionCreationNotImplemented[] =
"Session creation not implemented.";
} // namespace
VRDevice::VRDevice(VR* vr,
......@@ -105,10 +103,16 @@ ScriptPromise VRDevice::requestSession(
}
}
// TODO: Session creation will be implemented in a follow up CL.
return ScriptPromise::RejectWithDOMException(
script_state,
DOMException::Create(kNotSupportedError, kSessionCreationNotImplemented));
ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state);
ScriptPromise promise = resolver->Promise();
VRSession* session = new VRSession(this, options.exclusive());
// TODO: A follow up CL will establish a VRPresentationProvider connection
// before resolving the promise.
resolver->Resolve(session);
return promise;
}
// TODO: Forward these calls on to the sessions once they've been implemented.
......
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "modules/vr/latest/VRSession.h"
#include "bindings/core/v8/ScriptPromiseResolver.h"
#include "core/dom/DOMException.h"
#include "core/frame/LocalFrame.h"
#include "modules/EventTargetModules.h"
#include "modules/vr/latest/VR.h"
#include "modules/vr/latest/VRDevice.h"
#include "modules/vr/latest/VRSessionEvent.h"
namespace blink {
namespace {
const char kSessionEnded[] = "VRSession has already ended.";
} // namespace
VRSession::VRSession(VRDevice* device, bool exclusive)
: device_(device), exclusive_(exclusive) {}
void VRSession::setDepthNear(double value) {
depth_near_ = value;
}
void VRSession::setDepthFar(double value) {
depth_far_ = value;
}
ExecutionContext* VRSession::GetExecutionContext() const {
return device_->GetExecutionContext();
}
const AtomicString& VRSession::InterfaceName() const {
return EventTargetNames::VRSession;
}
ScriptPromise VRSession::end(ScriptState* script_state) {
// Don't allow a session to end twice.
if (detached_) {
return ScriptPromise::RejectWithDOMException(
script_state, DOMException::Create(kInvalidStateError, kSessionEnded));
}
ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state);
ScriptPromise promise = resolver->Promise();
// TODO(bajones): If there's any work that needs to be done asynchronously on
// session end it should be completed before this promise is resolved.
ForceEnd();
resolver->Resolve();
return promise;
}
void VRSession::ForceEnd() {
// Detach this session from the device.
detached_ = true;
DispatchEvent(VRSessionEvent::Create(EventTypeNames::end, this));
}
void VRSession::OnFocus() {
if (!blurred_)
return;
blurred_ = false;
DispatchEvent(VRSessionEvent::Create(EventTypeNames::focus, this));
}
void VRSession::OnBlur() {
if (blurred_)
return;
blurred_ = true;
DispatchEvent(VRSessionEvent::Create(EventTypeNames::blur, this));
}
DEFINE_TRACE(VRSession) {
visitor->Trace(device_);
EventTargetWithInlineData::Trace(visitor);
}
} // namespace blink
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef VRSession_h
#define VRSession_h
#include "bindings/core/v8/ScriptPromise.h"
#include "core/dom/events/EventTarget.h"
#include "platform/heap/Handle.h"
#include "platform/wtf/Forward.h"
namespace blink {
class VRDevice;
class VRSession final : public EventTargetWithInlineData {
DEFINE_WRAPPERTYPEINFO();
public:
VRSession(VRDevice*, bool exclusive);
VRDevice* device() const { return device_; }
bool exclusive() const { return exclusive_; }
// Near and far depths are used when computing projection matrices for this
// Session's views. Changes will propegate to the appropriate matrices on the
// next frame after these values are updated.
double depthNear() const { return depth_near_; }
void setDepthNear(double value);
double depthFar() const { return depth_far_; }
void setDepthFar(double value);
DEFINE_ATTRIBUTE_EVENT_LISTENER(blur);
DEFINE_ATTRIBUTE_EVENT_LISTENER(focus);
DEFINE_ATTRIBUTE_EVENT_LISTENER(resetpose);
DEFINE_ATTRIBUTE_EVENT_LISTENER(end);
// Called by JavaScript to manually end the session.
ScriptPromise end(ScriptState*);
// Called when the session is ended, either via calling the "end" function or
// when the presentation service connection is closed.
void ForceEnd();
// EventTarget overrides.
ExecutionContext* GetExecutionContext() const override;
const AtomicString& InterfaceName() const override;
void OnFocus();
void OnBlur();
DECLARE_VIRTUAL_TRACE();
private:
const Member<VRDevice> device_;
const bool exclusive_;
double depth_near_ = 0.1;
double depth_far_ = 1000.0;
bool blurred_ = false;
bool detached_ = false;
};
} // namespace blink
#endif // VRWebGLLayer_h
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// https://w3c.github.io/webvr/spec/latest/#vrsession-interface
[
RuntimeEnabled=WebVR2
] interface VRSession : EventTarget {
readonly attribute VRDevice device;
readonly attribute boolean exclusive;
attribute double depthNear;
attribute double depthFar;
attribute EventHandler onblur;
attribute EventHandler onfocus;
attribute EventHandler onresetpose;
attribute EventHandler onend;
[CallWith=ScriptState] Promise end();
};
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "modules/vr/latest/VRSessionEvent.h"
namespace blink {
VRSessionEvent::VRSessionEvent() {}
VRSessionEvent::VRSessionEvent(const AtomicString& type, VRSession* session)
: Event(type, true, false), session_(session) {}
VRSessionEvent::VRSessionEvent(const AtomicString& type,
const VRSessionEventInit& initializer)
: Event(type, initializer) {
if (initializer.hasSession())
session_ = initializer.session();
}
VRSessionEvent::~VRSessionEvent() {}
const AtomicString& VRSessionEvent::InterfaceName() const {
return EventNames::VRSessionEvent;
}
DEFINE_TRACE(VRSessionEvent) {
visitor->Trace(session_);
Event::Trace(visitor);
}
} // namespace blink
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef VRSessionEvent_h
#define VRSessionEvent_h
#include "modules/EventModules.h"
#include "modules/vr/latest/VRSession.h"
#include "modules/vr/latest/VRSessionEventInit.h"
namespace blink {
class VRSessionEvent final : public Event {
DEFINE_WRAPPERTYPEINFO();
public:
static VRSessionEvent* Create() { return new VRSessionEvent; }
static VRSessionEvent* Create(const AtomicString& type, VRSession* session) {
return new VRSessionEvent(type, session);
}
static VRSessionEvent* Create(const AtomicString& type,
const VRSessionEventInit& initializer) {
return new VRSessionEvent(type, initializer);
}
~VRSessionEvent() override;
VRSession* session() const { return session_.Get(); }
const AtomicString& InterfaceName() const override;
DECLARE_VIRTUAL_TRACE();
private:
VRSessionEvent();
VRSessionEvent(const AtomicString& type, VRSession*);
VRSessionEvent(const AtomicString& type, const VRSessionEventInit&);
Member<VRSession> session_;
};
} // namespace blink
#endif // VRDisplayEvent_h
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// https://w3c.github.io/webvr/spec/latest/#vrsessionevent-interface
[
SecureContext,
RuntimeEnabled=WebVR2,
Constructor(DOMString type, VRSessionEventInit eventInitDict)
] interface VRSessionEvent : Event {
readonly attribute VRSession session;
};
\ No newline at end of file
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// https://w3c.github.io/webvr/spec/latest/#vrsessionevent-interface
[
SecureContext
] dictionary VRSessionEventInit : EventInit {
required VRSession session;
};
\ No newline at end of file
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