summaryrefslogtreecommitdiff
path: root/chromium/third_party/blink/renderer/modules/xr
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2018-05-15 10:20:33 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2018-05-15 10:28:57 +0000
commitd17ea114e5ef69ad5d5d7413280a13e6428098aa (patch)
tree2c01a75df69f30d27b1432467cfe7c1467a498da /chromium/third_party/blink/renderer/modules/xr
parent8c5c43c7b138c9b4b0bf56d946e61d3bbc111bec (diff)
downloadqtwebengine-chromium-d17ea114e5ef69ad5d5d7413280a13e6428098aa.tar.gz
BASELINE: Update Chromium to 67.0.3396.47
Change-Id: Idcb1341782e417561a2473eeecc82642dafda5b7 Reviewed-by: Michal Klocek <michal.klocek@qt.io>
Diffstat (limited to 'chromium/third_party/blink/renderer/modules/xr')
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/BUILD.gn56
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/DEPS8
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/OWNERS4
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr.cc193
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr.h72
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr.idl12
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_canvas_input_provider.cc125
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_canvas_input_provider.h59
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_coordinate_system.cc37
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_coordinate_system.h43
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_coordinate_system.idl11
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_device.cc209
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_device.h109
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_device.idl12
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_device_pose.cc47
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_device_pose.h36
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_device_pose.idl13
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_frame_of_reference.cc158
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_frame_of_reference.h53
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_frame_of_reference.idl19
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_frame_of_reference_options.idl11
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_frame_provider.cc460
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_frame_provider.h97
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_frame_request_callback.idl6
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_frame_request_callback_collection.cc71
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_frame_request_callback_collection.h58
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_input_pose.cc36
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_input_pose.h39
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_input_pose.idl12
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_input_source.cc77
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_input_source.h71
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_input_source.idl22
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_input_source_event.cc40
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_input_source_event.h53
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_input_source_event.idl12
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_input_source_event_init.idl10
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_layer.cc24
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_layer.h41
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_layer.idl9
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_presentation_context.cc32
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_presentation_context.h58
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_presentation_context.idl12
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_presentation_frame.cc129
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_presentation_frame.h47
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_presentation_frame.idl16
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_session.cc616
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_session.h162
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_session.idl32
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_session_creation_options.idl11
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_session_event.cc32
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_session_event.h46
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_session_event.idl12
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_session_event_init.idl10
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_stage_bounds.cc14
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_stage_bounds.h31
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_stage_bounds.idl11
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_stage_bounds_point.h30
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_stage_bounds_point.idl12
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_utils.cc24
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_utils.h18
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_view.cc151
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_view.h69
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_view.idl12
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_viewport.h35
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_viewport.idl14
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_webgl_layer.cc335
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_webgl_layer.h108
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_webgl_layer.idl27
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_webgl_layer_init.idl15
69 files changed, 4546 insertions, 0 deletions
diff --git a/chromium/third_party/blink/renderer/modules/xr/BUILD.gn b/chromium/third_party/blink/renderer/modules/xr/BUILD.gn
new file mode 100644
index 00000000000..0bd7b4656c6
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/BUILD.gn
@@ -0,0 +1,56 @@
+# 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.
+
+import("//third_party/blink/renderer/modules/modules.gni")
+
+blink_modules_sources("xr") {
+ sources = [
+ "xr.cc",
+ "xr.h",
+ "xr_canvas_input_provider.cc",
+ "xr_canvas_input_provider.h",
+ "xr_coordinate_system.cc",
+ "xr_coordinate_system.h",
+ "xr_device.cc",
+ "xr_device.h",
+ "xr_device_pose.cc",
+ "xr_device_pose.h",
+ "xr_frame_of_reference.cc",
+ "xr_frame_of_reference.h",
+ "xr_frame_provider.cc",
+ "xr_frame_provider.h",
+ "xr_frame_request_callback_collection.cc",
+ "xr_frame_request_callback_collection.h",
+ "xr_input_pose.cc",
+ "xr_input_pose.h",
+ "xr_input_source.cc",
+ "xr_input_source.h",
+ "xr_input_source_event.cc",
+ "xr_input_source_event.h",
+ "xr_layer.cc",
+ "xr_layer.h",
+ "xr_presentation_context.cc",
+ "xr_presentation_context.h",
+ "xr_presentation_frame.cc",
+ "xr_presentation_frame.h",
+ "xr_session.cc",
+ "xr_session.h",
+ "xr_session_event.cc",
+ "xr_session_event.h",
+ "xr_stage_bounds.cc",
+ "xr_stage_bounds.h",
+ "xr_stage_bounds_point.h",
+ "xr_utils.cc",
+ "xr_utils.h",
+ "xr_view.cc",
+ "xr_view.h",
+ "xr_viewport.h",
+ "xr_webgl_layer.cc",
+ "xr_webgl_layer.h",
+ ]
+
+ deps = [
+ "//device/vr/public/mojom:mojom_blink",
+ ]
+}
diff --git a/chromium/third_party/blink/renderer/modules/xr/DEPS b/chromium/third_party/blink/renderer/modules/xr/DEPS
new file mode 100644
index 00000000000..c86cbe78e9a
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/DEPS
@@ -0,0 +1,8 @@
+include_rules = [
+ "+mojo/public/cpp/bindings/binding.h",
+ "+mojo/public/cpp/system/platform_handle.h",
+ "+device/vr/public/mojom/vr_service.mojom-blink.h",
+ "+gpu/command_buffer/client/gles2_interface.h",
+ "+gpu/command_buffer/common/mailbox_holder.h",
+ "+ui/gfx/geometry",
+]
diff --git a/chromium/third_party/blink/renderer/modules/xr/OWNERS b/chromium/third_party/blink/renderer/modules/xr/OWNERS
new file mode 100644
index 00000000000..26c48a27959
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/OWNERS
@@ -0,0 +1,4 @@
+bajones@chromium.org
+klausw@chromium.org
+
+# COMPONENT: Blink>WebVR \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr.cc b/chromium/third_party/blink/renderer/modules/xr/xr.cc
new file mode 100644
index 00000000000..245b2701529
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr.cc
@@ -0,0 +1,193 @@
+// 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 "third_party/blink/renderer/modules/xr/xr.h"
+
+#include "services/service_manager/public/cpp/interface_provider.h"
+#include "third_party/blink/public/platform/interface_provider.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
+#include "third_party/blink/renderer/core/dom/document.h"
+#include "third_party/blink/renderer/core/dom/dom_exception.h"
+#include "third_party/blink/renderer/core/frame/local_frame.h"
+#include "third_party/blink/renderer/modules/event_modules.h"
+#include "third_party/blink/renderer/modules/event_target_modules.h"
+#include "third_party/blink/renderer/modules/xr/xr_device.h"
+#include "third_party/blink/renderer/platform/feature_policy/feature_policy.h"
+namespace blink {
+
+namespace {
+
+const char kNavigatorDetachedError[] =
+ "The navigator.xr object is no longer associated with a document.";
+
+const char kFeaturePolicyBlocked[] =
+ "Access to the feature \"xr\" is disallowed by feature policy.";
+
+const char kCrossOriginSubframeBlocked[] =
+ "Blocked call to navigator.xr.requestDevice inside a cross-origin "
+ "iframe because the frame has never been activated by the user.";
+
+const char kNoDevicesMessage[] = "No devices found.";
+
+} // namespace
+
+XR::XR(LocalFrame& frame)
+ : ContextLifecycleObserver(frame.GetDocument()),
+ FocusChangedObserver(frame.GetPage()),
+ devices_synced_(false),
+ binding_(this) {
+ frame.GetInterfaceProvider().GetInterface(mojo::MakeRequest(&service_));
+ service_.set_connection_error_handler(
+ WTF::Bind(&XR::Dispose, WrapWeakPersistent(this)));
+
+ device::mojom::blink::VRServiceClientPtr client;
+ binding_.Bind(mojo::MakeRequest(&client));
+
+ // Setting the client kicks off a request for the details of any connected
+ // XRDevices.
+ service_->SetClient(std::move(client),
+ WTF::Bind(&XR::OnDevicesSynced, WrapPersistent(this)));
+}
+
+void XR::FocusedFrameChanged() {
+ // Tell devices that focus changed.
+ for (const auto& device : devices_)
+ device->OnFrameFocusChanged();
+}
+
+bool XR::IsFrameFocused() {
+ return FocusChangedObserver::IsFrameFocused(GetFrame());
+}
+
+ExecutionContext* XR::GetExecutionContext() const {
+ return ContextLifecycleObserver::GetExecutionContext();
+}
+
+const AtomicString& XR::InterfaceName() const {
+ return EventTargetNames::XR;
+}
+
+ScriptPromise XR::requestDevice(ScriptState* script_state) {
+ LocalFrame* frame = GetFrame();
+ if (!frame) {
+ // Reject if the frame is inaccessible.
+ return ScriptPromise::RejectWithDOMException(
+ script_state,
+ DOMException::Create(kInvalidStateError, kNavigatorDetachedError));
+ }
+
+ if (IsSupportedInFeaturePolicy(mojom::FeaturePolicyFeature::kWebVr)) {
+ if (!frame->IsFeatureEnabled(mojom::FeaturePolicyFeature::kWebVr)) {
+ // Only allow the call to be made if the appropraite feature policy is in
+ // place.
+ return ScriptPromise::RejectWithDOMException(
+ script_state,
+ DOMException::Create(kSecurityError, kFeaturePolicyBlocked));
+ }
+ } else if (!frame->HasBeenActivated() && frame->IsCrossOriginSubframe()) {
+ // Block calls from cross-origin iframes that have never had a user gesture.
+ return ScriptPromise::RejectWithDOMException(
+ script_state,
+ DOMException::Create(kSecurityError, kCrossOriginSubframeBlocked));
+ }
+
+ // If we're still waiting for a previous call to resolve return that promise
+ // again.
+ if (pending_devices_resolver_) {
+ return pending_devices_resolver_->Promise();
+ }
+
+ ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state);
+ ScriptPromise promise = resolver->Promise();
+
+ // If we've previously synced the XRDevices or no longer have a valid service
+ // connection just use the current list. In the case of the service being
+ // disconnected this will be an empty array.
+ if (!service_ || devices_synced_) {
+ // TODO (offenwanger): When we have a prioritized order of devices, or some
+ // other method of getting the prefered device, insert that here. For now,
+ // just get the first device out of the list, if there is one.
+ if (devices_.size() == 0) {
+ resolver->Reject(DOMException::Create(kNotFoundError, kNoDevicesMessage));
+ } else {
+ resolver->Resolve(devices_[0]);
+ }
+
+ return promise;
+ }
+
+ // Otherwise wait for the full list of devices to be populated and resolve
+ // when onDevicesSynced is called.
+ pending_devices_resolver_ = resolver;
+
+ return promise;
+}
+
+// Each time a new XRDevice is connected we'll recieve a XRDisplayPtr for it
+// here. Upon calling SetClient in the constructor we should receive one call
+// for each XRDevice that was already connected at the time.
+void XR::OnDisplayConnected(
+ device::mojom::blink::VRMagicWindowProviderPtr magic_window_provider,
+ device::mojom::blink::VRDisplayHostPtr display,
+ device::mojom::blink::VRDisplayClientRequest client_request,
+ device::mojom::blink::VRDisplayInfoPtr display_info) {
+ XRDevice* xr_device =
+ new XRDevice(this, std::move(magic_window_provider), std::move(display),
+ std::move(client_request), std::move(display_info));
+
+ devices_.push_back(xr_device);
+
+ DispatchEvent(blink::Event::Create(EventTypeNames::devicechange));
+}
+
+// Called when the XRService has called OnDevicesConnected for all active
+// XRDevices.
+void XR::OnDevicesSynced() {
+ devices_synced_ = true;
+ ResolveRequestDevice();
+}
+
+// Called when details for every connected XRDevice has been received.
+void XR::ResolveRequestDevice() {
+ if (pending_devices_resolver_) {
+ if (devices_.size() == 0) {
+ pending_devices_resolver_->Reject(
+ DOMException::Create(kNotFoundError, kNoDevicesMessage));
+ } else {
+ pending_devices_resolver_->Resolve(devices_[0]);
+ }
+
+ pending_devices_resolver_ = nullptr;
+ }
+}
+
+void XR::ContextDestroyed(ExecutionContext*) {
+ Dispose();
+}
+
+void XR::Dispose() {
+ // If the document context was destroyed, shut down the client connection
+ // and never call the mojo service again.
+ service_.reset();
+ binding_.Close();
+
+ // Shutdown all devices' message pipe
+ for (const auto& device : devices_)
+ device->Dispose();
+
+ devices_.clear();
+
+ // Ensure that any outstanding requestDevice promises are resolved. They will
+ // receive a null result.
+ ResolveRequestDevice();
+}
+
+void XR::Trace(blink::Visitor* visitor) {
+ visitor->Trace(devices_);
+ visitor->Trace(pending_devices_resolver_);
+ ContextLifecycleObserver::Trace(visitor);
+ EventTargetWithInlineData::Trace(visitor);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr.h b/chromium/third_party/blink/renderer/modules/xr/xr.h
new file mode 100644
index 00000000000..777e54f98b2
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr.h
@@ -0,0 +1,72 @@
+// 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 THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_H_
+
+#include "device/vr/public/mojom/vr_service.mojom-blink.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "third_party/blink/public/platform/web_callbacks.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
+#include "third_party/blink/renderer/core/dom/context_lifecycle_observer.h"
+#include "third_party/blink/renderer/core/dom/events/event_target.h"
+#include "third_party/blink/renderer/core/page/focus_changed_observer.h"
+#include "third_party/blink/renderer/platform/heap/handle.h"
+#include "third_party/blink/renderer/platform/wtf/forward.h"
+
+namespace blink {
+
+class ScriptPromiseResolver;
+class XRDevice;
+
+class XR final : public EventTargetWithInlineData,
+ public ContextLifecycleObserver,
+ public device::mojom::blink::VRServiceClient,
+ public FocusChangedObserver {
+ DEFINE_WRAPPERTYPEINFO();
+ USING_GARBAGE_COLLECTED_MIXIN(XR);
+
+ public:
+ static XR* Create(LocalFrame& frame) { return new XR(frame); }
+
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(devicechange);
+
+ ScriptPromise requestDevice(ScriptState*);
+
+ // XRServiceClient overrides.
+ void OnDisplayConnected(device::mojom::blink::VRMagicWindowProviderPtr,
+ device::mojom::blink::VRDisplayHostPtr,
+ device::mojom::blink::VRDisplayClientRequest,
+ device::mojom::blink::VRDisplayInfoPtr) override;
+
+ // EventTarget overrides.
+ ExecutionContext* GetExecutionContext() const override;
+ const AtomicString& InterfaceName() const override;
+
+ // ContextLifecycleObserver overrides.
+ void ContextDestroyed(ExecutionContext*) override;
+ void Trace(blink::Visitor*) override;
+
+ // FocusChangedObserver overrides.
+ void FocusedFrameChanged() override;
+ bool IsFrameFocused();
+
+ private:
+ explicit XR(LocalFrame& frame);
+
+ void OnDevicesSynced();
+ void ResolveRequestDevice();
+ void Dispose();
+
+ bool devices_synced_;
+
+ HeapVector<Member<XRDevice>> devices_;
+ Member<ScriptPromiseResolver> pending_devices_resolver_;
+ device::mojom::blink::VRServicePtr service_;
+ mojo::Binding<device::mojom::blink::VRServiceClient> binding_;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_H_
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr.idl b/chromium/third_party/blink/renderer/modules/xr/xr.idl
new file mode 100644
index 00000000000..f28b866153d
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr.idl
@@ -0,0 +1,12 @@
+// 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://immersive-web.github.io/webxr/spec/latest/#xr-interface
+[
+ SecureContext,
+ OriginTrialEnabled=WebXR
+] interface XR : EventTarget {
+ attribute EventHandler ondevicechange;
+ [CallWith=ScriptState, MeasureAs=XRRequestDevice] Promise requestDevice();
+};
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_canvas_input_provider.cc b/chromium/third_party/blink/renderer/modules/xr/xr_canvas_input_provider.cc
new file mode 100644
index 00000000000..cf77afbb829
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_canvas_input_provider.cc
@@ -0,0 +1,125 @@
+// Copyright 2018 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 "third_party/blink/renderer/modules/xr/xr_canvas_input_provider.h"
+
+#include "third_party/blink/renderer/core/events/mouse_event.h"
+#include "third_party/blink/renderer/core/html/canvas/html_canvas_element.h"
+#include "third_party/blink/renderer/modules/xr/xr_device.h"
+#include "third_party/blink/renderer/modules/xr/xr_frame_provider.h"
+#include "third_party/blink/renderer/modules/xr/xr_input_source.h"
+#include "third_party/blink/renderer/modules/xr/xr_session.h"
+#include "third_party/blink/renderer/modules/xr/xr_view.h"
+
+namespace blink {
+
+namespace {
+
+class XRCanvasInputEventListener : public EventListener {
+ public:
+ XRCanvasInputEventListener(XRCanvasInputProvider* input_provider)
+ : EventListener(kCPPEventListenerType), input_provider_(input_provider) {}
+
+ bool operator==(const EventListener& that) const override {
+ return this == &that;
+ }
+
+ void handleEvent(ExecutionContext* execution_context, Event* event) override {
+ if (!input_provider_->ShouldProcessEvents())
+ return;
+
+ if (event->type() == EventTypeNames::click) {
+ input_provider_->OnClick(ToMouseEvent(event));
+ }
+ }
+
+ void Trace(blink::Visitor* visitor) override {
+ visitor->Trace(input_provider_);
+ EventListener::Trace(visitor);
+ }
+
+ private:
+ Member<XRCanvasInputProvider> input_provider_;
+};
+
+} // namespace
+
+XRCanvasInputProvider::XRCanvasInputProvider(XRSession* session,
+ HTMLCanvasElement* canvas)
+ : session_(session), canvas_(canvas) {
+ listener_ = new XRCanvasInputEventListener(this);
+ canvas->addEventListener(EventTypeNames::click, listener_);
+}
+
+XRCanvasInputProvider::~XRCanvasInputProvider() {
+ Stop();
+}
+
+void XRCanvasInputProvider::Stop() {
+ if (!listener_) {
+ return;
+ }
+ canvas_->removeEventListener(EventTypeNames::click, listener_);
+ canvas_ = nullptr;
+ listener_ = nullptr;
+}
+
+bool XRCanvasInputProvider::ShouldProcessEvents() {
+ // Don't process canvas gestures if there's an active exclusive session.
+ return !(session_->device()->frameProvider()->exclusive_session());
+}
+
+void XRCanvasInputProvider::OnClick(MouseEvent* event) {
+ UpdateInputSource(event);
+ session_->OnSelect(input_source_);
+ ClearInputSource();
+}
+
+XRInputSource* XRCanvasInputProvider::GetInputSource() {
+ return input_source_;
+}
+
+void XRCanvasInputProvider::UpdateInputSource(MouseEvent* event) {
+ if (!canvas_)
+ return;
+
+ if (!input_source_) {
+ input_source_ = new XRInputSource(session_, 0);
+ input_source_->SetPointerOrigin(XRInputSource::kOriginScreen);
+ }
+
+ // Get the event location relative to the canvas element.
+ double element_x = event->pageX() - canvas_->OffsetLeft();
+ double element_y = event->pageY() - canvas_->OffsetTop();
+
+ // Unproject the event location into a pointer matrix. This takes the 2D
+ // position of the screen interaction and shoves it backwards through the
+ // projection matrix to get a 3D point in space, which is then returned in
+ // matrix form so we can use it as an XRInputSource's pointerMatrix.
+ XRView* view = session_->views()[0];
+ std::unique_ptr<TransformationMatrix> pointer_transform_matrix =
+ view->UnprojectPointer(element_x, element_y, canvas_->OffsetWidth(),
+ canvas_->OffsetHeight());
+
+ // Update the input source's pointer matrix.
+ input_source_->SetPointerTransformMatrix(std::move(pointer_transform_matrix));
+}
+
+void XRCanvasInputProvider::ClearInputSource() {
+ input_source_ = nullptr;
+}
+
+void XRCanvasInputProvider::Trace(blink::Visitor* visitor) {
+ visitor->Trace(session_);
+ visitor->Trace(canvas_);
+ visitor->Trace(listener_);
+ visitor->Trace(input_source_);
+}
+
+void XRCanvasInputProvider::TraceWrappers(
+ const blink::ScriptWrappableVisitor* visitor) const {
+ visitor->TraceWrappers(input_source_);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_canvas_input_provider.h b/chromium/third_party/blink/renderer/modules/xr/xr_canvas_input_provider.h
new file mode 100644
index 00000000000..1ad49c8b505
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_canvas_input_provider.h
@@ -0,0 +1,59 @@
+// Copyright 2018 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 THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_CANVAS_INPUT_PROVIDER_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_CANVAS_INPUT_PROVIDER_H_
+
+#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
+#include "third_party/blink/renderer/platform/bindings/trace_wrapper_member.h"
+#include "third_party/blink/renderer/platform/heap/handle.h"
+#include "third_party/blink/renderer/platform/transforms/transformation_matrix.h"
+#include "third_party/blink/renderer/platform/wtf/forward.h"
+#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
+
+namespace blink {
+
+class EventListener;
+class HTMLCanvasElement;
+class MouseEvent;
+class XRInputSource;
+class XRSession;
+
+class XRCanvasInputProvider
+ : public GarbageCollectedFinalized<XRCanvasInputProvider>,
+ public TraceWrapperBase {
+ public:
+ XRCanvasInputProvider(XRSession*, HTMLCanvasElement*);
+ virtual ~XRCanvasInputProvider();
+
+ XRSession* session() const { return session_; }
+
+ // Remove all event listeners.
+ void Stop();
+
+ bool ShouldProcessEvents();
+
+ void OnClick(MouseEvent*);
+
+ XRInputSource* GetInputSource();
+
+ virtual void Trace(blink::Visitor*);
+ virtual void TraceWrappers(const blink::ScriptWrappableVisitor*) const;
+ const char* NameInHeapSnapshot() const override {
+ return "XRCanvasInputProvider";
+ }
+
+ private:
+ void UpdateInputSource(MouseEvent*);
+ void ClearInputSource();
+
+ const Member<XRSession> session_;
+ Member<HTMLCanvasElement> canvas_;
+ Member<EventListener> listener_;
+ TraceWrapperMember<XRInputSource> input_source_;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_CANVAS_INPUT_PROVIDER_H_
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_coordinate_system.cc b/chromium/third_party/blink/renderer/modules/xr/xr_coordinate_system.cc
new file mode 100644
index 00000000000..0d4bd264f26
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_coordinate_system.cc
@@ -0,0 +1,37 @@
+// 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 "third_party/blink/renderer/modules/xr/xr_coordinate_system.h"
+
+#include "third_party/blink/renderer/modules/xr/xr_session.h"
+
+namespace blink {
+
+XRCoordinateSystem::XRCoordinateSystem(XRSession* session)
+ : session_(session) {}
+
+XRCoordinateSystem::~XRCoordinateSystem() = default;
+
+// If possible, get the matrix required to transform between two coordinate
+// systems.
+DOMFloat32Array* XRCoordinateSystem::getTransformTo(
+ XRCoordinateSystem* other) const {
+ if (session_ != other->session()) {
+ // Cannot get relationships between coordinate systems that belong to
+ // different sessions.
+ return nullptr;
+ }
+
+ // TODO(bajones): Track relationship to other coordinate systems and return
+ // the transforms here. In the meantime we're allowed to return null to
+ // indicate that the transform between the two coordinate systems is unknown.
+ return nullptr;
+}
+
+void XRCoordinateSystem::Trace(blink::Visitor* visitor) {
+ visitor->Trace(session_);
+ ScriptWrappable::Trace(visitor);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_coordinate_system.h b/chromium/third_party/blink/renderer/modules/xr/xr_coordinate_system.h
new file mode 100644
index 00000000000..cd6497cdad1
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_coordinate_system.h
@@ -0,0 +1,43 @@
+// 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 THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_COORDINATE_SYSTEM_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_COORDINATE_SYSTEM_H_
+
+#include "third_party/blink/renderer/core/typed_arrays/dom_typed_array.h"
+#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
+#include "third_party/blink/renderer/platform/heap/handle.h"
+#include "third_party/blink/renderer/platform/wtf/forward.h"
+
+namespace blink {
+
+class TransformationMatrix;
+class XRSession;
+
+class XRCoordinateSystem : public ScriptWrappable {
+ DEFINE_WRAPPERTYPEINFO();
+
+ public:
+ explicit XRCoordinateSystem(XRSession*);
+ virtual ~XRCoordinateSystem();
+
+ DOMFloat32Array* getTransformTo(XRCoordinateSystem*) const;
+
+ XRSession* session() { return session_; }
+
+ virtual std::unique_ptr<TransformationMatrix> TransformBasePose(
+ const TransformationMatrix& base_pose) = 0;
+ virtual std::unique_ptr<TransformationMatrix> TransformBaseInputPose(
+ const TransformationMatrix& base_input_pose,
+ const TransformationMatrix& base_pose) = 0;
+
+ virtual void Trace(blink::Visitor*);
+
+ private:
+ const Member<XRSession> session_;
+};
+
+} // namespace blink
+
+#endif // XRWebGLLayer_h
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_coordinate_system.idl b/chromium/third_party/blink/renderer/modules/xr/xr_coordinate_system.idl
new file mode 100644
index 00000000000..06fd42fe3c5
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_coordinate_system.idl
@@ -0,0 +1,11 @@
+// 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://immersive-web.github.io/webxr/spec/latest/#xrcoordinatesystem-interface
+[
+ SecureContext,
+ OriginTrialEnabled=WebXR
+] interface XRCoordinateSystem {
+ Float32Array? getTransformTo(XRCoordinateSystem other);
+};
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_device.cc b/chromium/third_party/blink/renderer/modules/xr/xr_device.cc
new file mode 100644
index 00000000000..b360cf5b8b5
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_device.cc
@@ -0,0 +1,209 @@
+// 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 "third_party/blink/renderer/modules/xr/xr_device.h"
+
+#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
+#include "third_party/blink/renderer/core/dom/dom_exception.h"
+#include "third_party/blink/renderer/core/frame/frame.h"
+#include "third_party/blink/renderer/core/frame/local_frame.h"
+#include "third_party/blink/renderer/modules/event_target_modules.h"
+#include "third_party/blink/renderer/modules/xr/xr.h"
+#include "third_party/blink/renderer/modules/xr/xr_frame_provider.h"
+#include "third_party/blink/renderer/modules/xr/xr_session.h"
+
+namespace blink {
+
+namespace {
+
+const char kActiveExclusiveSession[] =
+ "XRDevice already has an active, exclusive session";
+
+const char kExclusiveNotSupported[] =
+ "XRDevice does not support the creation of exclusive sessions.";
+
+const char kNoOutputContext[] =
+ "Non-exclusive sessions must be created with an outputContext.";
+
+const char kRequestNotInUserGesture[] =
+ "Exclusive sessions can only be requested during a user gesture.";
+
+} // namespace
+
+XRDevice::XRDevice(
+ XR* xr,
+ device::mojom::blink::VRMagicWindowProviderPtr magic_window_provider,
+ device::mojom::blink::VRDisplayHostPtr display,
+ device::mojom::blink::VRDisplayClientRequest client_request,
+ device::mojom::blink::VRDisplayInfoPtr display_info)
+ : xr_(xr),
+ magic_window_provider_(std::move(magic_window_provider)),
+ display_(std::move(display)),
+ display_client_binding_(this, std::move(client_request)) {
+ SetXRDisplayInfo(std::move(display_info));
+}
+
+ExecutionContext* XRDevice::GetExecutionContext() const {
+ return xr_->GetExecutionContext();
+}
+
+const AtomicString& XRDevice::InterfaceName() const {
+ return EventTargetNames::XRDevice;
+}
+
+const char* XRDevice::checkSessionSupport(
+ const XRSessionCreationOptions& options) const {
+ if (options.exclusive()) {
+ // Validation for exclusive sessions.
+ if (!supports_exclusive_) {
+ return kExclusiveNotSupported;
+ }
+ } else {
+ // Validation for non-exclusive sessions.
+ if (!options.hasOutputContext()) {
+ return kNoOutputContext;
+ }
+ }
+
+ return nullptr;
+}
+
+ScriptPromise XRDevice::supportsSession(
+ ScriptState* script_state,
+ const XRSessionCreationOptions& options) const {
+ // Check to see if the device is capable of supporting the requested session
+ // options. Note that reporting support here does not guarantee that creating
+ // a session with those options will succeed, as other external and
+ // time-sensitve factors (focus state, existance of another exclusive session,
+ // etc.) may prevent the creation of a session as well.
+ const char* reject_reason = checkSessionSupport(options);
+ if (reject_reason) {
+ return ScriptPromise::RejectWithDOMException(
+ script_state, DOMException::Create(kNotSupportedError, reject_reason));
+ }
+
+ // If the above checks pass, resolve without a value. Future API iterations
+ // may specify a value to be returned here.
+ ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state);
+ ScriptPromise promise = resolver->Promise();
+ resolver->Resolve();
+ return promise;
+}
+
+ScriptPromise XRDevice::requestSession(
+ ScriptState* script_state,
+ const XRSessionCreationOptions& options) {
+ // Check first to see if the device is capable of supporting the requested
+ // options.
+ const char* reject_reason = checkSessionSupport(options);
+ if (reject_reason) {
+ return ScriptPromise::RejectWithDOMException(
+ script_state, DOMException::Create(kNotSupportedError, reject_reason));
+ }
+
+ // Check if the current page state prevents the requested session from being
+ // created.
+ if (options.exclusive()) {
+ if (frameProvider()->exclusive_session()) {
+ return ScriptPromise::RejectWithDOMException(
+ script_state,
+ DOMException::Create(kInvalidStateError, kActiveExclusiveSession));
+ }
+
+ Document* doc = ToDocumentOrNull(ExecutionContext::From(script_state));
+ if (!Frame::HasTransientUserActivation(doc ? doc->GetFrame() : nullptr)) {
+ return ScriptPromise::RejectWithDOMException(
+ script_state,
+ DOMException::Create(kInvalidStateError, kRequestNotInUserGesture));
+ }
+ }
+
+ ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state);
+ ScriptPromise promise = resolver->Promise();
+
+ XRPresentationContext* output_context = nullptr;
+ if (options.hasOutputContext()) {
+ output_context = options.outputContext();
+ }
+
+ XRSession* session = new XRSession(this, options.exclusive(), output_context);
+ sessions_.insert(session);
+
+ if (options.exclusive()) {
+ frameProvider()->BeginExclusiveSession(session, resolver);
+ } else {
+ resolver->Resolve(session);
+ }
+
+ return promise;
+}
+
+void XRDevice::OnFrameFocusChanged() {
+ OnFocusChanged();
+}
+
+void XRDevice::OnFocusChanged() {
+ // Tell all sessions that focus changed.
+ for (const auto& session : sessions_) {
+ session->OnFocusChanged();
+ }
+
+ if (frame_provider_)
+ frame_provider_->OnFocusChanged();
+}
+
+bool XRDevice::IsFrameFocused() {
+ return xr_->IsFrameFocused();
+}
+
+// TODO: Forward these calls on to the sessions once they've been implemented.
+void XRDevice::OnChanged(device::mojom::blink::VRDisplayInfoPtr display_info) {
+ SetXRDisplayInfo(std::move(display_info));
+}
+void XRDevice::OnExitPresent() {}
+void XRDevice::OnBlur() {
+ // The device is reporting to us that it is blurred. This could happen for a
+ // variety of reasons, such as browser UI, a different application using the
+ // headset, or another page entering an exclusive session.
+ has_device_focus_ = false;
+ OnFocusChanged();
+}
+void XRDevice::OnFocus() {
+ has_device_focus_ = true;
+ OnFocusChanged();
+}
+void XRDevice::OnActivate(device::mojom::blink::VRDisplayEventReason,
+ OnActivateCallback on_handled) {}
+void XRDevice::OnDeactivate(device::mojom::blink::VRDisplayEventReason) {}
+
+XRFrameProvider* XRDevice::frameProvider() {
+ if (!frame_provider_) {
+ frame_provider_ = new XRFrameProvider(this);
+ }
+
+ return frame_provider_;
+}
+
+void XRDevice::Dispose() {
+ display_client_binding_.Close();
+ if (frame_provider_)
+ frame_provider_->Dispose();
+}
+
+void XRDevice::SetXRDisplayInfo(
+ device::mojom::blink::VRDisplayInfoPtr display_info) {
+ display_info_id_++;
+ display_info_ = std::move(display_info);
+ is_external_ = display_info_->capabilities->hasExternalDisplay;
+ supports_exclusive_ = (display_info_->capabilities->canPresent);
+}
+
+void XRDevice::Trace(blink::Visitor* visitor) {
+ visitor->Trace(xr_);
+ visitor->Trace(frame_provider_);
+ visitor->Trace(sessions_);
+ EventTargetWithInlineData::Trace(visitor);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_device.h b/chromium/third_party/blink/renderer/modules/xr/xr_device.h
new file mode 100644
index 00000000000..d2266136b3f
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_device.h
@@ -0,0 +1,109 @@
+// 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 THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_DEVICE_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_DEVICE_H_
+
+#include "device/vr/public/mojom/vr_service.mojom-blink.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
+#include "third_party/blink/renderer/core/dom/events/event_target.h"
+#include "third_party/blink/renderer/modules/xr/xr_session_creation_options.h"
+#include "third_party/blink/renderer/platform/heap/handle.h"
+#include "third_party/blink/renderer/platform/wtf/forward.h"
+#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
+
+namespace blink {
+
+class XR;
+class XRFrameProvider;
+class XRSession;
+
+class XRDevice final : public EventTargetWithInlineData,
+ public device::mojom::blink::VRDisplayClient {
+ DEFINE_WRAPPERTYPEINFO();
+
+ public:
+ XRDevice(XR*,
+ device::mojom::blink::VRMagicWindowProviderPtr,
+ device::mojom::blink::VRDisplayHostPtr,
+ device::mojom::blink::VRDisplayClientRequest,
+ device::mojom::blink::VRDisplayInfoPtr);
+ XR* xr() const { return xr_; }
+
+ bool external() const { return is_external_; }
+
+ ScriptPromise supportsSession(ScriptState*,
+ const XRSessionCreationOptions&) const;
+ ScriptPromise requestSession(ScriptState*, const XRSessionCreationOptions&);
+
+ // EventTarget overrides.
+ ExecutionContext* GetExecutionContext() const override;
+ const AtomicString& InterfaceName() const override;
+ void Trace(blink::Visitor*) override;
+
+ // XRDisplayClient
+ void OnChanged(device::mojom::blink::VRDisplayInfoPtr) override;
+ void OnExitPresent() override;
+ void OnBlur() override;
+ void OnFocus() override;
+ void OnActivate(device::mojom::blink::VRDisplayEventReason,
+ OnActivateCallback on_handled) override;
+ void OnDeactivate(device::mojom::blink::VRDisplayEventReason) override;
+
+ XRFrameProvider* frameProvider();
+
+ void Dispose();
+
+ const device::mojom::blink::VRDisplayHostPtr& xrDisplayHostPtr() const {
+ return display_;
+ }
+ const device::mojom::blink::VRMagicWindowProviderPtr&
+ xrMagicWindowProviderPtr() const {
+ return magic_window_provider_;
+ }
+ const device::mojom::blink::VRDisplayInfoPtr& xrDisplayInfoPtr() const {
+ return display_info_;
+ }
+ // Incremented every time display_info_ is changed, so that other objects that
+ // depend on it can know when they need to update.
+ unsigned int xrDisplayInfoPtrId() const { return display_info_id_; }
+
+ void OnFrameFocusChanged();
+ // The device may report focus to us - for example if another application is
+ // using the headset, or some browsing UI is shown, we may not have device
+ // focus.
+ bool HasDeviceFocus() { return has_device_focus_; }
+ bool HasDeviceAndFrameFocus() { return IsFrameFocused() && HasDeviceFocus(); }
+
+ private:
+ void SetXRDisplayInfo(device::mojom::blink::VRDisplayInfoPtr);
+
+ const char* checkSessionSupport(const XRSessionCreationOptions&) const;
+
+ // There are two components to focus - whether the frame itself has
+ // traditional focus and whether the device reports that we have focus. These
+ // are aggregated so we can hand out focus/blur events on sessions and
+ // determine when to call animation frame callbacks.
+ void OnFocusChanged();
+ bool IsFrameFocused();
+
+ Member<XR> xr_;
+ Member<XRFrameProvider> frame_provider_;
+ HeapHashSet<WeakMember<XRSession>> sessions_;
+ bool is_external_;
+ bool supports_exclusive_;
+ bool has_device_focus_ = true;
+
+ device::mojom::blink::VRMagicWindowProviderPtr magic_window_provider_;
+ device::mojom::blink::VRDisplayHostPtr display_;
+ device::mojom::blink::VRDisplayInfoPtr display_info_;
+ unsigned int display_info_id_ = 0;
+
+ mojo::Binding<device::mojom::blink::VRDisplayClient> display_client_binding_;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_DEVICE_H_
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_device.idl b/chromium/third_party/blink/renderer/modules/xr/xr_device.idl
new file mode 100644
index 00000000000..6466153b297
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_device.idl
@@ -0,0 +1,12 @@
+// 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://immersive-web.github.io/webxr/spec/latest/#xrdevice-interface
+[
+ SecureContext,
+ OriginTrialEnabled=WebXR
+] interface XRDevice : EventTarget {
+ [CallWith=ScriptState, MeasureAs=XRSupportsSession] Promise supportsSession([PermissiveDictionaryConversion] optional XRSessionCreationOptions options);
+ [CallWith=ScriptState, MeasureAs=XRRequestSession] Promise requestSession([PermissiveDictionaryConversion] optional XRSessionCreationOptions options);
+};
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_device_pose.cc b/chromium/third_party/blink/renderer/modules/xr/xr_device_pose.cc
new file mode 100644
index 00000000000..10e154755e6
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_device_pose.cc
@@ -0,0 +1,47 @@
+// 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 "third_party/blink/renderer/modules/xr/xr_device_pose.h"
+
+#include "third_party/blink/renderer/modules/xr/xr_session.h"
+#include "third_party/blink/renderer/modules/xr/xr_utils.h"
+#include "third_party/blink/renderer/modules/xr/xr_view.h"
+
+namespace blink {
+
+XRDevicePose::XRDevicePose(
+ XRSession* session,
+ std::unique_ptr<TransformationMatrix> pose_model_matrix)
+ : session_(session), pose_model_matrix_(std::move(pose_model_matrix)) {}
+
+DOMFloat32Array* XRDevicePose::poseModelMatrix() const {
+ if (!pose_model_matrix_)
+ return nullptr;
+ return transformationMatrixToFloat32Array(*pose_model_matrix_);
+}
+
+DOMFloat32Array* XRDevicePose::getViewMatrix(XRView* view) {
+ if (view->session() != session_)
+ return nullptr;
+
+ if (!pose_model_matrix_->IsInvertible())
+ return nullptr;
+
+ TransformationMatrix view_matrix(pose_model_matrix_->Inverse());
+
+ // Transform by the negative offset, since we're operating on the inverted
+ // matrix
+ const FloatPoint3D& view_offset = view->offset();
+ view_matrix.PostTranslate3d(-view_offset.X(), -view_offset.Y(),
+ -view_offset.Z());
+
+ return transformationMatrixToFloat32Array(view_matrix);
+}
+
+void XRDevicePose::Trace(blink::Visitor* visitor) {
+ visitor->Trace(session_);
+ ScriptWrappable::Trace(visitor);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_device_pose.h b/chromium/third_party/blink/renderer/modules/xr/xr_device_pose.h
new file mode 100644
index 00000000000..074e6e71acf
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_device_pose.h
@@ -0,0 +1,36 @@
+// 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 THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_DEVICE_POSE_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_DEVICE_POSE_H_
+
+#include "third_party/blink/renderer/core/typed_arrays/dom_typed_array.h"
+#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
+#include "third_party/blink/renderer/platform/heap/handle.h"
+#include "third_party/blink/renderer/platform/transforms/transformation_matrix.h"
+
+namespace blink {
+
+class XRSession;
+class XRView;
+
+class XRDevicePose final : public ScriptWrappable {
+ DEFINE_WRAPPERTYPEINFO();
+
+ public:
+ XRDevicePose(XRSession*, std::unique_ptr<TransformationMatrix>);
+
+ DOMFloat32Array* poseModelMatrix() const;
+ DOMFloat32Array* getViewMatrix(XRView*);
+
+ virtual void Trace(blink::Visitor*);
+
+ private:
+ const Member<XRSession> session_;
+ std::unique_ptr<TransformationMatrix> pose_model_matrix_;
+};
+
+} // namespace blink
+
+#endif // XRWebGLLayer_h
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_device_pose.idl b/chromium/third_party/blink/renderer/modules/xr/xr_device_pose.idl
new file mode 100644
index 00000000000..abdb9c8f86a
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_device_pose.idl
@@ -0,0 +1,13 @@
+// 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://immersive-web.github.io/webxr/spec/latest/#xrdevicepose-interface
+[
+ SecureContext,
+ OriginTrialEnabled=WebXR
+] interface XRDevicePose {
+ readonly attribute Float32Array poseModelMatrix;
+
+ Float32Array getViewMatrix(XRView view);
+};
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_frame_of_reference.cc b/chromium/third_party/blink/renderer/modules/xr/xr_frame_of_reference.cc
new file mode 100644
index 00000000000..3bc1dc4813c
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_frame_of_reference.cc
@@ -0,0 +1,158 @@
+// 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 "third_party/blink/renderer/modules/xr/xr_frame_of_reference.h"
+
+#include "device/vr/public/mojom/vr_service.mojom-blink.h"
+#include "third_party/blink/renderer/modules/xr/xr_device.h"
+#include "third_party/blink/renderer/modules/xr/xr_session.h"
+#include "third_party/blink/renderer/modules/xr/xr_stage_bounds.h"
+
+namespace blink {
+
+// Rough estimate of avg human eye height in meters.
+const double kDefaultEmulationHeight = 1.6;
+
+XRFrameOfReference::XRFrameOfReference(XRSession* session, Type type)
+ : XRCoordinateSystem(session), type_(type) {}
+
+XRFrameOfReference::~XRFrameOfReference() = default;
+
+void XRFrameOfReference::UpdatePoseTransform(
+ std::unique_ptr<TransformationMatrix> transform) {
+ pose_transform_ = std::move(transform);
+}
+
+void XRFrameOfReference::UpdateStageBounds(XRStageBounds* bounds) {
+ bounds_ = bounds;
+ // TODO(bajones): Fire a boundschange event
+}
+
+void XRFrameOfReference::UpdateStageTransform() {
+ const device::mojom::blink::VRDisplayInfoPtr& display_info =
+ session()->device()->xrDisplayInfoPtr();
+
+ if (display_info->stageParameters) {
+ // Use the transform given by xrDisplayInfo's stageParamters if available.
+ const WTF::Vector<float>& m =
+ display_info->stageParameters->standingTransform;
+ pose_transform_ = TransformationMatrix::Create(
+ m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8], m[9], m[10],
+ m[11], m[12], m[13], m[14], m[15]);
+ } else if (emulated_height_ != 0.0) {
+ // Otherwise, if this frame of reference has specified that an emulated
+ // height may be used, create a transform based on that.
+ pose_transform_ = TransformationMatrix::Create();
+ pose_transform_->Translate3d(0, emulated_height_, 0);
+ } else {
+ // If stage parameters aren't available and emulation is disabled, set the
+ // transform to null, which will subsequently cause this frame of reference
+ // to return null poses.
+ pose_transform_.reset();
+ }
+
+ display_info_id_ = session()->device()->xrDisplayInfoPtrId();
+}
+
+// Enables emulated height when using a stage frame of reference, which should
+// only be used if the sytem does not have a native concept of how far above the
+// floor the XRDevice is at any given moment. This applies a static vertical
+// offset to the coordinate system so that the user feels approximately like
+// they are standing on a floor plane located at Y = 0. An explicit offset in
+// meters can be given if the page has specific needs.
+void XRFrameOfReference::UseEmulatedHeight(double value) {
+ if (value == 0.0)
+ value = kDefaultEmulationHeight;
+
+ emulated_height_ = value;
+ UpdateStageTransform();
+}
+
+// Transforms a given pose from a "base" coordinate system used by the XR
+// service to the frame of reference's coordinate system. This model is a bit
+// over-simplified and will need to be made more robust when we start dealing
+// with world-scale 6DoF tracking.
+std::unique_ptr<TransformationMatrix> XRFrameOfReference::TransformBasePose(
+ const TransformationMatrix& base_pose) {
+ switch (type_) {
+ case kTypeHeadModel: {
+ // TODO(bajones): Detect if base pose is already neck modeled and return
+ // it unchanged if so for better performance.
+
+ // Strip out translation component.
+ std::unique_ptr<TransformationMatrix> pose(
+ TransformationMatrix::Create(base_pose));
+ pose->SetM41(0.0);
+ pose->SetM42(0.0);
+ pose->SetM43(0.0);
+ // TODO(bajones): Apply our own neck model
+ return pose;
+ } break;
+ case kTypeEyeLevel:
+ // For now we assume that all base poses are delivered as eye-level poses.
+ // Thus in this case we just return the pose without transformation.
+ return TransformationMatrix::Create(base_pose);
+ break;
+ case kTypeStage:
+ // Check first to see if the xrDisplayInfo has updated since the last
+ // call. If so, update the pose transform.
+ if (display_info_id_ != session()->device()->xrDisplayInfoPtrId())
+ UpdateStageTransform();
+
+ // If the stage has a transform apply it to the base pose and return that,
+ // otherwise return null.
+ if (pose_transform_) {
+ std::unique_ptr<TransformationMatrix> pose(
+ TransformationMatrix::Create(*pose_transform_));
+ pose->Multiply(base_pose);
+ return pose;
+ }
+ break;
+ }
+
+ return nullptr;
+}
+
+// Serves the same purpose as TransformBasePose, but for input poses. Needs to
+// know the head pose so that cases like the headModel frame of reference can
+// properly adjust the input's relative position.
+std::unique_ptr<TransformationMatrix>
+XRFrameOfReference::TransformBaseInputPose(
+ const TransformationMatrix& base_input_pose,
+ const TransformationMatrix& base_pose) {
+ switch (type_) {
+ case kTypeHeadModel: {
+ std::unique_ptr<TransformationMatrix> head_model_pose(
+ TransformBasePose(base_pose));
+
+ // Get the positional delta between the base pose and the head model pose.
+ float dx = head_model_pose->M41() - base_pose.M41();
+ float dy = head_model_pose->M42() - base_pose.M42();
+ float dz = head_model_pose->M43() - base_pose.M43();
+
+ // Translate the controller by the same delta so that it shows up in the
+ // right relative position.
+ std::unique_ptr<TransformationMatrix> pose(
+ TransformationMatrix::Create(base_input_pose));
+ pose->SetM41(pose->M41() + dx);
+ pose->SetM42(pose->M42() + dy);
+ pose->SetM43(pose->M43() + dz);
+
+ return pose;
+ } break;
+ case kTypeEyeLevel:
+ case kTypeStage:
+ return TransformBasePose(base_input_pose);
+ break;
+ }
+
+ return nullptr;
+}
+
+void XRFrameOfReference::Trace(blink::Visitor* visitor) {
+ visitor->Trace(bounds_);
+ XRCoordinateSystem::Trace(visitor);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_frame_of_reference.h b/chromium/third_party/blink/renderer/modules/xr/xr_frame_of_reference.h
new file mode 100644
index 00000000000..eca778a2208
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_frame_of_reference.h
@@ -0,0 +1,53 @@
+// 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 THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_FRAME_OF_REFERENCE_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_FRAME_OF_REFERENCE_H_
+
+#include "third_party/blink/renderer/modules/xr/xr_coordinate_system.h"
+#include "third_party/blink/renderer/platform/transforms/transformation_matrix.h"
+
+namespace blink {
+
+class XRStageBounds;
+
+class XRFrameOfReference final : public XRCoordinateSystem {
+ DEFINE_WRAPPERTYPEINFO();
+
+ public:
+ enum Type { kTypeHeadModel, kTypeEyeLevel, kTypeStage };
+
+ XRFrameOfReference(XRSession*, Type);
+ ~XRFrameOfReference() override;
+
+ void UpdatePoseTransform(std::unique_ptr<TransformationMatrix>);
+ void UpdateStageBounds(XRStageBounds*);
+ void UseEmulatedHeight(double value);
+
+ std::unique_ptr<TransformationMatrix> TransformBasePose(
+ const TransformationMatrix& base_pose) override;
+ std::unique_ptr<TransformationMatrix> TransformBaseInputPose(
+ const TransformationMatrix& base_input_pose,
+ const TransformationMatrix& base_pose) override;
+
+ XRStageBounds* bounds() const { return bounds_; }
+ double emulatedHeight() const { return emulated_height_; }
+
+ Type type() const { return type_; }
+
+ void Trace(blink::Visitor*) override;
+
+ private:
+ void UpdateStageTransform();
+
+ Member<XRStageBounds> bounds_;
+ double emulated_height_ = 0.0;
+ Type type_;
+ std::unique_ptr<TransformationMatrix> pose_transform_;
+ unsigned int display_info_id_ = 0;
+};
+
+} // namespace blink
+
+#endif // XRWebGLLayer_h
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_frame_of_reference.idl b/chromium/third_party/blink/renderer/modules/xr/xr_frame_of_reference.idl
new file mode 100644
index 00000000000..e3906654d45
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_frame_of_reference.idl
@@ -0,0 +1,19 @@
+// 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://immersive-web.github.io/webxr/spec/latest/#xrframeofreference-interface
+
+enum XRFrameOfReferenceType {
+ "headModel",
+ "eyeLevel",
+ "stage",
+};
+
+[
+ SecureContext,
+ OriginTrialEnabled=WebXR
+] interface XRFrameOfReference : XRCoordinateSystem {
+ readonly attribute XRStageBounds? bounds;
+ readonly attribute double emulatedHeight;
+};
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_frame_of_reference_options.idl b/chromium/third_party/blink/renderer/modules/xr/xr_frame_of_reference_options.idl
new file mode 100644
index 00000000000..e1bf41d728f
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_frame_of_reference_options.idl
@@ -0,0 +1,11 @@
+// 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://immersive-web.github.io/webxr/spec/latest/#xrframeofreference-interface
+[
+ SecureContext
+] dictionary XRFrameOfReferenceOptions {
+ boolean disableStageEmulation = false;
+ double stageEmulationHeight = 0.0;
+};
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_frame_provider.cc b/chromium/third_party/blink/renderer/modules/xr/xr_frame_provider.cc
new file mode 100644
index 00000000000..ee7b59ec2d5
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_frame_provider.cc
@@ -0,0 +1,460 @@
+// 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 "third_party/blink/renderer/modules/xr/xr_frame_provider.h"
+
+#include "build/build_config.h"
+#include "third_party/blink/public/platform/platform.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
+#include "third_party/blink/renderer/core/dom/document.h"
+#include "third_party/blink/renderer/core/dom/dom_exception.h"
+#include "third_party/blink/renderer/core/dom/frame_request_callback_collection.h"
+#include "third_party/blink/renderer/core/frame/local_frame.h"
+#include "third_party/blink/renderer/core/imagebitmap/image_bitmap.h"
+#include "third_party/blink/renderer/modules/xr/xr.h"
+#include "third_party/blink/renderer/modules/xr/xr_device.h"
+#include "third_party/blink/renderer/modules/xr/xr_presentation_context.h"
+#include "third_party/blink/renderer/modules/xr/xr_session.h"
+#include "third_party/blink/renderer/modules/xr/xr_viewport.h"
+#include "third_party/blink/renderer/modules/xr/xr_webgl_layer.h"
+#include "third_party/blink/renderer/platform/graphics/gpu/xr_frame_transport.h"
+#include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
+#include "third_party/blink/renderer/platform/transforms/transformation_matrix.h"
+#include "third_party/blink/renderer/platform/wtf/time.h"
+
+namespace blink {
+
+namespace {
+
+class XRFrameProviderRequestCallback
+ : public FrameRequestCallbackCollection::FrameCallback {
+ public:
+ explicit XRFrameProviderRequestCallback(XRFrameProvider* frame_provider)
+ : frame_provider_(frame_provider) {}
+ ~XRFrameProviderRequestCallback() override = default;
+ void Invoke(double high_res_time_ms) override {
+ frame_provider_->OnNonExclusiveVSync(high_res_time_ms / 1000.0);
+ }
+
+ virtual void Trace(blink::Visitor* visitor) {
+ visitor->Trace(frame_provider_);
+
+ FrameRequestCallbackCollection::FrameCallback::Trace(visitor);
+ }
+
+ Member<XRFrameProvider> frame_provider_;
+};
+
+std::unique_ptr<TransformationMatrix> getPoseMatrix(
+ const device::mojom::blink::VRPosePtr& pose) {
+ if (!pose)
+ return nullptr;
+
+ std::unique_ptr<TransformationMatrix> pose_matrix =
+ TransformationMatrix::Create();
+
+ TransformationMatrix::DecomposedType decomp;
+
+ memset(&decomp, 0, sizeof(decomp));
+ decomp.perspective_w = 1;
+ decomp.scale_x = 1;
+ decomp.scale_y = 1;
+ decomp.scale_z = 1;
+
+ if (pose->orientation) {
+ decomp.quaternion_x = -pose->orientation.value()[0];
+ decomp.quaternion_y = -pose->orientation.value()[1];
+ decomp.quaternion_z = -pose->orientation.value()[2];
+ decomp.quaternion_w = pose->orientation.value()[3];
+ } else {
+ decomp.quaternion_w = 1.0;
+ }
+
+ if (pose->position) {
+ decomp.translate_x = pose->position.value()[0];
+ decomp.translate_y = pose->position.value()[1];
+ decomp.translate_z = pose->position.value()[2];
+ }
+
+ pose_matrix->Recompose(decomp);
+
+ return pose_matrix;
+}
+
+} // namespace
+
+XRFrameProvider::XRFrameProvider(XRDevice* device)
+ : device_(device), last_has_focus_(device->HasDeviceAndFrameFocus()) {}
+
+void XRFrameProvider::BeginExclusiveSession(XRSession* session,
+ ScriptPromiseResolver* resolver) {
+ // Make sure the session is indeed an exclusive one.
+ DCHECK(session && session->exclusive());
+
+ // Ensure we can only have one exclusive session at a time.
+ DCHECK(!exclusive_session_);
+ DCHECK(!exclusive_session_can_send_frames_);
+
+ exclusive_session_ = session;
+ exclusive_session_can_send_frames_ = false;
+
+ pending_exclusive_session_resolver_ = resolver;
+
+ // Establish the connection with the VSyncProvider if needed.
+ if (!presentation_provider_.is_bound()) {
+ frame_transport_ = new XRFrameTransport();
+
+ // Set up RequestPresentOptions based on canvas properties.
+ device::mojom::blink::VRRequestPresentOptionsPtr options =
+ device::mojom::blink::VRRequestPresentOptions::New();
+ options->preserve_drawing_buffer = false;
+ options->webxr_input = true;
+ options->shared_buffer_draw_supported = true;
+
+ // TODO(offenwanger): Once device activation is sorted out for WebXR, either
+ // pass in the value for metrics, or remove it as soon as legacy API has
+ // been removed.
+ device_->xrDisplayHostPtr()->RequestPresent(
+ frame_transport_->GetSubmitFrameClient(),
+ mojo::MakeRequest(&presentation_provider_), std::move(options), false,
+ WTF::Bind(&XRFrameProvider::OnPresentComplete, WrapPersistent(this)));
+
+ presentation_provider_.set_connection_error_handler(
+ WTF::Bind(&XRFrameProvider::OnPresentationProviderConnectionError,
+ WrapWeakPersistent(this)));
+ }
+}
+
+void XRFrameProvider::OnPresentComplete(
+ bool success,
+ device::mojom::blink::VRDisplayFrameTransportOptionsPtr transport_options) {
+ if (success) {
+ frame_transport_->SetTransportOptions(std::move(transport_options));
+ frame_transport_->PresentChange();
+ pending_exclusive_session_resolver_->Resolve(exclusive_session_);
+ exclusive_session_can_send_frames_ = true;
+ } else {
+ exclusive_session_->ForceEnd();
+ exclusive_session_can_send_frames_ = false;
+
+ if (pending_exclusive_session_resolver_) {
+ DOMException* exception = DOMException::Create(
+ kNotAllowedError, "Request for exclusive XRSession was denied.");
+ pending_exclusive_session_resolver_->Reject(exception);
+ }
+ }
+
+ pending_exclusive_session_resolver_ = nullptr;
+}
+
+void XRFrameProvider::OnFocusChanged() {
+ bool focus = device_->HasDeviceAndFrameFocus();
+
+ // If we are gaining focus, schedule a frame for magic window. This accounts
+ // for skipping RAFs in ProcessScheduledFrame. Only do this when there are
+ // magic window sessions but no exclusive session. Note that exclusive
+ // sessions don't stop scheduling RAFs when focus is lost, so there is no need
+ // to schedule exclusive frames when focus is acquired.
+ if (focus && !last_has_focus_ && requesting_sessions_.size() > 0 &&
+ !exclusive_session_) {
+ ScheduleNonExclusiveFrame();
+ }
+ last_has_focus_ = focus;
+}
+
+void XRFrameProvider::OnPresentationProviderConnectionError() {
+ if (pending_exclusive_session_resolver_) {
+ DOMException* exception = DOMException::Create(
+ kNotAllowedError,
+ "Error occured while requesting exclusive XRSession.");
+ pending_exclusive_session_resolver_->Reject(exception);
+ pending_exclusive_session_resolver_ = nullptr;
+ }
+ presentation_provider_.reset();
+ if (vsync_connection_failed_)
+ return;
+ exclusive_session_->ForceEnd();
+ exclusive_session_can_send_frames_ = false;
+ vsync_connection_failed_ = true;
+}
+
+// Called by the exclusive session when it is ended.
+void XRFrameProvider::OnExclusiveSessionEnded() {
+ if (!exclusive_session_)
+ return;
+
+ device_->xrDisplayHostPtr()->ExitPresent();
+
+ exclusive_session_ = nullptr;
+ exclusive_session_can_send_frames_ = false;
+ pending_exclusive_vsync_ = false;
+ frame_id_ = -1;
+
+ if (presentation_provider_.is_bound()) {
+ presentation_provider_.reset();
+ }
+
+ frame_transport_ = nullptr;
+
+ // When we no longer have an active exclusive session schedule all the
+ // outstanding frames that were requested while the exclusive session was
+ // active.
+ if (requesting_sessions_.size() > 0)
+ ScheduleNonExclusiveFrame();
+}
+
+// Schedule a session to be notified when the next XR frame is available.
+void XRFrameProvider::RequestFrame(XRSession* session) {
+ DVLOG(2) << __FUNCTION__;
+
+ // If a previous session has already requested a frame don't fire off another
+ // request. All requests will be fullfilled at once when OnVSync is called.
+ if (session->exclusive()) {
+ ScheduleExclusiveFrame();
+ } else {
+ requesting_sessions_.push_back(session);
+
+ // If there's an active exclusive session save the request but suppress
+ // processing it until the exclusive session is no longer active.
+ if (exclusive_session_)
+ return;
+
+ ScheduleNonExclusiveFrame();
+ }
+}
+
+void XRFrameProvider::ScheduleExclusiveFrame() {
+ if (pending_exclusive_vsync_)
+ return;
+
+ pending_exclusive_vsync_ = true;
+
+ presentation_provider_->GetVSync(
+ WTF::Bind(&XRFrameProvider::OnExclusiveVSync, WrapWeakPersistent(this)));
+}
+
+void XRFrameProvider::ScheduleNonExclusiveFrame() {
+ if (pending_non_exclusive_vsync_)
+ return;
+
+ LocalFrame* frame = device_->xr()->GetFrame();
+ if (!frame)
+ return;
+
+ Document* doc = frame->GetDocument();
+ if (!doc)
+ return;
+
+ pending_non_exclusive_vsync_ = true;
+
+ device_->xrMagicWindowProviderPtr()->GetPose(WTF::Bind(
+ &XRFrameProvider::OnNonExclusivePose, WrapWeakPersistent(this)));
+ doc->RequestAnimationFrame(new XRFrameProviderRequestCallback(this));
+}
+
+void XRFrameProvider::OnExclusiveVSync(
+ device::mojom::blink::VRPosePtr pose,
+ WTF::TimeDelta time_delta,
+ int16_t frame_id,
+ device::mojom::blink::VRPresentationProvider::VSyncStatus status,
+ const base::Optional<gpu::MailboxHolder>& buffer_holder) {
+ DVLOG(2) << __FUNCTION__;
+ vsync_connection_failed_ = false;
+ switch (status) {
+ case device::mojom::blink::VRPresentationProvider::VSyncStatus::SUCCESS:
+ break;
+ case device::mojom::blink::VRPresentationProvider::VSyncStatus::CLOSING:
+ return;
+ }
+
+ // We may have lost the exclusive session since the last VSync request.
+ if (!exclusive_session_) {
+ return;
+ }
+
+ frame_pose_ = std::move(pose);
+ frame_id_ = frame_id;
+ buffer_mailbox_holder_ = buffer_holder;
+
+ pending_exclusive_vsync_ = false;
+
+ // Post a task to handle scheduled animations after the current
+ // execution context finishes, so that we yield to non-mojo tasks in
+ // between frames. Executing mojo tasks back to back within the same
+ // execution context caused extreme input delay due to processing
+ // multiple frames without yielding, see crbug.com/701444.
+ Platform::Current()->CurrentThread()->GetTaskRunner()->PostTask(
+ FROM_HERE, WTF::Bind(&XRFrameProvider::ProcessScheduledFrame,
+ WrapWeakPersistent(this), time_delta.InSecondsF()));
+}
+
+void XRFrameProvider::OnNonExclusiveVSync(double timestamp) {
+ DVLOG(2) << __FUNCTION__;
+
+ pending_non_exclusive_vsync_ = false;
+
+ // Suppress non-exclusive vsyncs when there's an exclusive session active.
+ if (exclusive_session_)
+ return;
+
+ Platform::Current()->CurrentThread()->GetTaskRunner()->PostTask(
+ FROM_HERE, WTF::Bind(&XRFrameProvider::ProcessScheduledFrame,
+ WrapWeakPersistent(this), timestamp));
+}
+
+void XRFrameProvider::OnNonExclusivePose(device::mojom::blink::VRPosePtr pose) {
+ frame_pose_ = std::move(pose);
+}
+
+void XRFrameProvider::ProcessScheduledFrame(double timestamp) {
+ DVLOG(2) << __FUNCTION__;
+
+ TRACE_EVENT1("gpu", "XRFrameProvider::ProcessScheduledFrame", "frame",
+ frame_id_);
+
+ if (!device_->HasDeviceAndFrameFocus() && !exclusive_session_) {
+ return; // Not currently focused, so we won't expose poses (except to
+ // exclusive sessions).
+ }
+
+ if (exclusive_session_can_send_frames_) {
+ if (frame_pose_ && frame_pose_->input_state.has_value()) {
+ exclusive_session_->OnInputStateChange(frame_id_,
+ frame_pose_->input_state.value());
+ }
+
+ // If there's an exclusive session active only process its frame.
+ std::unique_ptr<TransformationMatrix> pose_matrix =
+ getPoseMatrix(frame_pose_);
+ // Sanity check: if drawing into a shared buffer, the optional mailbox
+ // holder must be present.
+ DCHECK(!frame_transport_->DrawingIntoSharedBuffer() ||
+ buffer_mailbox_holder_);
+ exclusive_session_->OnFrame(std::move(pose_matrix), buffer_mailbox_holder_);
+ } else {
+ // In the process of fulfilling the frame requests for each session they are
+ // extremely likely to request another frame. Work off of a separate list
+ // from the requests to prevent infinite loops.
+ HeapVector<Member<XRSession>> processing_sessions;
+ swap(requesting_sessions_, processing_sessions);
+
+ // Inform sessions with a pending request of the new frame
+ for (unsigned i = 0; i < processing_sessions.size(); ++i) {
+ XRSession* session = processing_sessions.at(i).Get();
+
+ if (frame_pose_ && frame_pose_->input_state.has_value()) {
+ session->OnInputStateChange(frame_id_,
+ frame_pose_->input_state.value());
+ }
+
+ std::unique_ptr<TransformationMatrix> pose_matrix =
+ getPoseMatrix(frame_pose_);
+ session->OnFrame(std::move(pose_matrix), base::nullopt);
+ }
+ }
+}
+
+void XRFrameProvider::SubmitWebGLLayer(XRWebGLLayer* layer, bool was_changed) {
+ DCHECK(layer);
+ DCHECK(layer->session() == exclusive_session_);
+ if (!presentation_provider_.is_bound())
+ return;
+
+ TRACE_EVENT1("gpu", "XRFrameProvider::SubmitWebGLLayer", "frame", frame_id_);
+
+ WebGLRenderingContextBase* webgl_context = layer->context();
+
+ if (!was_changed) {
+ // Just tell the device side that there was no submitted frame instead
+ // of executing the implicit end-of-frame submit.
+ frame_transport_->FrameSubmitMissing(presentation_provider_.get(),
+ webgl_context->ContextGL(), frame_id_);
+ return;
+ }
+
+ frame_transport_->FramePreImage(webgl_context->ContextGL());
+
+ std::unique_ptr<viz::SingleReleaseCallback> image_release_callback;
+
+ DCHECK(exclusive_session_can_send_frames_);
+ if (frame_transport_->DrawingIntoSharedBuffer()) {
+ // Image is written to shared buffer already. Just submit with a
+ // placeholder.
+ scoped_refptr<Image> image_ref = nullptr;
+ bool needs_copy = false;
+ DVLOG(3) << __FUNCTION__ << ": FrameSubmit for SharedBuffer mode";
+ frame_transport_->FrameSubmit(
+ presentation_provider_.get(), webgl_context->ContextGL(), webgl_context,
+ std::move(image_ref), std::move(image_release_callback), frame_id_,
+ needs_copy);
+ return;
+ }
+
+ scoped_refptr<StaticBitmapImage> image_ref =
+ layer->TransferToStaticBitmapImage(&image_release_callback);
+
+ if (!image_ref)
+ return;
+
+ // Hardware-accelerated rendering should always be texture backed. Ensure this
+ // is the case, don't attempt to render if using an unexpected drawing path.
+ if (!image_ref->IsTextureBacked()) {
+ NOTREACHED() << "WebXR requires hardware-accelerated rendering to texture";
+ return;
+ }
+
+ // TODO(bajones): Remove this when the Windows path has been updated to no
+ // longer require a texture copy.
+ bool needs_copy = device_->external();
+
+ frame_transport_->FrameSubmit(
+ presentation_provider_.get(), webgl_context->ContextGL(), webgl_context,
+ std::move(image_ref), std::move(image_release_callback), frame_id_,
+ needs_copy);
+
+ // Reset our frame id, since anything we'd want to do (resizing/etc) can
+ // no-longer happen to this frame.
+ frame_id_ = -1;
+}
+
+// TODO(bajones): This only works because we're restricted to a single layer at
+// the moment. Will need an overhaul when we get more robust layering support.
+void XRFrameProvider::UpdateWebGLLayerViewports(XRWebGLLayer* layer) {
+ DCHECK(layer->session() == exclusive_session_);
+ DCHECK(presentation_provider_);
+
+ XRViewport* left = layer->GetViewportForEye(XRView::kEyeLeft);
+ XRViewport* right = layer->GetViewportForEye(XRView::kEyeRight);
+ float width = layer->framebufferWidth();
+ float height = layer->framebufferHeight();
+
+ WebFloatRect left_coords(
+ static_cast<float>(left->x()) / width,
+ static_cast<float>(height - (left->y() + left->height())) / height,
+ static_cast<float>(left->width()) / width,
+ static_cast<float>(left->height()) / height);
+ WebFloatRect right_coords(
+ static_cast<float>(right->x()) / width,
+ static_cast<float>(height - (right->y() + right->height())) / height,
+ static_cast<float>(right->width()) / width,
+ static_cast<float>(right->height()) / height);
+
+ presentation_provider_->UpdateLayerBounds(
+ frame_id_, left_coords, right_coords, WebSize(width, height));
+}
+
+void XRFrameProvider::Dispose() {
+ presentation_provider_.reset();
+ // TODO(bajones): Do something for outstanding frame requests?
+}
+
+void XRFrameProvider::Trace(blink::Visitor* visitor) {
+ visitor->Trace(device_);
+ visitor->Trace(pending_exclusive_session_resolver_);
+ visitor->Trace(frame_transport_);
+ visitor->Trace(exclusive_session_);
+ visitor->Trace(requesting_sessions_);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_frame_provider.h b/chromium/third_party/blink/renderer/modules/xr/xr_frame_provider.h
new file mode 100644
index 00000000000..4aa8ea2cc3a
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_frame_provider.h
@@ -0,0 +1,97 @@
+// 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 THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_FRAME_PROVIDER_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_FRAME_PROVIDER_H_
+
+#include "device/vr/public/mojom/vr_service.mojom-blink.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
+#include "third_party/blink/renderer/platform/heap/handle.h"
+#include "third_party/blink/renderer/platform/wtf/forward.h"
+
+namespace blink {
+
+class ScriptPromiseResolver;
+class XRDevice;
+class XRSession;
+class XRFrameTransport;
+class XRWebGLLayer;
+
+// This class manages requesting and dispatching frame updates, which includes
+// pose information for a given XRDevice.
+class XRFrameProvider final
+ : public GarbageCollectedFinalized<XRFrameProvider> {
+ public:
+ explicit XRFrameProvider(XRDevice*);
+
+ XRSession* exclusive_session() const { return exclusive_session_; }
+
+ void BeginExclusiveSession(XRSession*, ScriptPromiseResolver*);
+ void OnExclusiveSessionEnded();
+
+ void RequestFrame(XRSession*);
+
+ void OnNonExclusiveVSync(double timestamp);
+
+ void SubmitWebGLLayer(XRWebGLLayer*, bool was_changed);
+ void UpdateWebGLLayerViewports(XRWebGLLayer*);
+
+ void Dispose();
+ void OnFocusChanged();
+
+ virtual void Trace(blink::Visitor*);
+
+ private:
+ void OnExclusiveVSync(
+ device::mojom::blink::VRPosePtr,
+ WTF::TimeDelta,
+ int16_t frame_id,
+ device::mojom::blink::VRPresentationProvider::VSyncStatus,
+ const base::Optional<gpu::MailboxHolder>& buffer_holder);
+ void OnNonExclusivePose(device::mojom::blink::VRPosePtr);
+
+ void ScheduleExclusiveFrame();
+ void ScheduleNonExclusiveFrame();
+
+ void OnPresentComplete(
+ bool success,
+ device::mojom::blink::VRDisplayFrameTransportOptionsPtr);
+ void OnPresentationProviderConnectionError();
+ void ProcessScheduledFrame(double timestamp);
+
+ const Member<XRDevice> device_;
+ Member<XRSession> exclusive_session_;
+ Member<ScriptPromiseResolver> pending_exclusive_session_resolver_;
+ Member<XRFrameTransport> frame_transport_;
+
+ // Careful, exclusive_session_ being true does not mean it's OK to send
+ // frames. The initialization handshake may not be complete yet. This boolean
+ // starts out false at the start of a session, becomes true after a
+ // successful OnPresentComplete(), and remains true for the lifetime of the
+ // exclusive session.
+ bool exclusive_session_can_send_frames_ = false;
+
+ // Non-exclusive Sessions which have requested a frame update.
+ HeapVector<Member<XRSession>> requesting_sessions_;
+
+ device::mojom::blink::VRPresentationProviderPtr presentation_provider_;
+ device::mojom::blink::VRMagicWindowProviderPtr magic_window_provider_;
+ device::mojom::blink::VRPosePtr frame_pose_;
+
+ // This frame ID is XR-specific and is used to track when frames arrive at the
+ // XR compositor so that it knows which poses to use, when to apply bounds
+ // updates, etc.
+ int16_t frame_id_ = -1;
+ bool pending_exclusive_vsync_ = false;
+ bool pending_non_exclusive_vsync_ = false;
+ bool vsync_connection_failed_ = false;
+
+ base::Optional<gpu::MailboxHolder> buffer_mailbox_holder_;
+ bool last_has_focus_ = false;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_FRAME_PROVIDER_H_
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_frame_request_callback.idl b/chromium/third_party/blink/renderer/modules/xr/xr_frame_request_callback.idl
new file mode 100644
index 00000000000..fc182d9b396
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_frame_request_callback.idl
@@ -0,0 +1,6 @@
+// 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://immersive-web.github.io/webxr/spec/latest/#callbackdef-xrframerequestcallback
+callback XRFrameRequestCallback = void (DOMHighResTimeStamp time, XRPresentationFrame frame);
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_frame_request_callback_collection.cc b/chromium/third_party/blink/renderer/modules/xr/xr_frame_request_callback_collection.cc
new file mode 100644
index 00000000000..c66b5e2ec9d
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_frame_request_callback_collection.cc
@@ -0,0 +1,71 @@
+// 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 "third_party/blink/renderer/modules/xr/xr_frame_request_callback_collection.h"
+
+#include "third_party/blink/renderer/bindings/modules/v8/v8_xr_frame_request_callback.h"
+#include "third_party/blink/renderer/core/inspector/InspectorTraceEvents.h"
+#include "third_party/blink/renderer/core/probe/core_probes.h"
+#include "third_party/blink/renderer/modules/xr/xr_presentation_frame.h"
+#include "third_party/blink/renderer/modules/xr/xr_session.h"
+
+namespace blink {
+
+XRFrameRequestCallbackCollection::XRFrameRequestCallbackCollection(
+ ExecutionContext* context)
+ : context_(context) {}
+
+XRFrameRequestCallbackCollection::CallbackId
+XRFrameRequestCallbackCollection::RegisterCallback(
+ V8XRFrameRequestCallback* callback) {
+ CallbackId id = ++next_callback_id_;
+ callbacks_.Set(id, callback);
+ pending_callbacks_.push_back(id);
+
+ probe::AsyncTaskScheduledBreakable(context_, "XRRequestFrame", callback);
+ return id;
+}
+
+void XRFrameRequestCallbackCollection::CancelCallback(CallbackId id) {
+ if (IsValidCallbackId(id)) {
+ callbacks_.erase(id);
+ }
+}
+
+void XRFrameRequestCallbackCollection::ExecuteCallbacks(
+ XRSession* session,
+ XRPresentationFrame* frame) {
+ // First, generate a list of callbacks to consider. Callbacks registered from
+ // this point on are considered only for the "next" frame, not this one.
+ DCHECK(callbacks_to_invoke_.IsEmpty());
+ callbacks_to_invoke_.swap(pending_callbacks_);
+
+ for (const auto& id : callbacks_to_invoke_) {
+ V8XRFrameRequestCallback* callback = callbacks_.Take(id);
+
+ // Callback won't be found if it was cancelled.
+ if (!callback)
+ continue;
+
+ probe::AsyncTask async_task(context_, callback);
+ probe::UserCallback probe(context_, "XRRequestFrame", AtomicString(), true);
+ callback->InvokeAndReportException(session, 0, frame);
+ }
+
+ callbacks_to_invoke_.clear();
+}
+
+void XRFrameRequestCallbackCollection::Trace(blink::Visitor* visitor) {
+ visitor->Trace(callbacks_);
+ visitor->Trace(context_);
+}
+
+void XRFrameRequestCallbackCollection::TraceWrappers(
+ const blink::ScriptWrappableVisitor* visitor) const {
+ for (const auto& callback : callbacks_.Values()) {
+ visitor->TraceWrappers(callback);
+ }
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_frame_request_callback_collection.h b/chromium/third_party/blink/renderer/modules/xr/xr_frame_request_callback_collection.h
new file mode 100644
index 00000000000..4bc51f240b4
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_frame_request_callback_collection.h
@@ -0,0 +1,58 @@
+// 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 THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_FRAME_REQUEST_CALLBACK_COLLECTION_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_FRAME_REQUEST_CALLBACK_COLLECTION_H_
+
+#include "third_party/blink/renderer/platform/bindings/trace_wrapper_member.h"
+#include "third_party/blink/renderer/platform/heap/handle.h"
+
+namespace blink {
+
+class ExecutionContext;
+class V8XRFrameRequestCallback;
+class XRPresentationFrame;
+class XRSession;
+
+class XRFrameRequestCallbackCollection final : public TraceWrapperBase {
+ DISALLOW_NEW();
+
+ public:
+ explicit XRFrameRequestCallbackCollection(ExecutionContext*);
+
+ using CallbackId = int;
+ CallbackId RegisterCallback(V8XRFrameRequestCallback*);
+ void CancelCallback(CallbackId);
+ void ExecuteCallbacks(XRSession*, XRPresentationFrame*);
+
+ bool IsEmpty() const { return !callbacks_.size(); }
+
+ void Trace(blink::Visitor*);
+ void TraceWrappers(const blink::ScriptWrappableVisitor*) const override;
+ const char* NameInHeapSnapshot() const override {
+ return "XRFrameRequestCallbackCollection";
+ }
+
+ private:
+ bool IsValidCallbackId(int id) {
+ using Traits = HashTraits<CallbackId>;
+ return !Traits::IsDeletedValue(id) &&
+ !WTF::IsHashTraitsEmptyValue<Traits, CallbackId>(id);
+ }
+
+ using CallbackMap =
+ HeapHashMap<CallbackId, TraceWrapperMember<V8XRFrameRequestCallback>>;
+ CallbackMap callbacks_;
+ Vector<CallbackId> pending_callbacks_;
+ // Only non-empty while inside executeCallbacks.
+ Vector<CallbackId> callbacks_to_invoke_;
+
+ CallbackId next_callback_id_ = 0;
+
+ Member<ExecutionContext> context_;
+};
+
+} // namespace blink
+
+#endif // FrameRequestCallbackCollection_h
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_input_pose.cc b/chromium/third_party/blink/renderer/modules/xr/xr_input_pose.cc
new file mode 100644
index 00000000000..c40afa39796
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_input_pose.cc
@@ -0,0 +1,36 @@
+// Copyright 2018 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 "third_party/blink/renderer/modules/xr/xr_input_pose.h"
+
+#include "third_party/blink/renderer/modules/xr/xr_utils.h"
+
+namespace blink {
+
+XRInputPose::XRInputPose(std::unique_ptr<TransformationMatrix> pointer_matrix,
+ std::unique_ptr<TransformationMatrix> grip_matrix,
+ bool emulated_position)
+ : pointer_matrix_(std::move(pointer_matrix)),
+ grip_matrix_(std::move(grip_matrix)),
+ emulated_position_(emulated_position) {}
+
+XRInputPose::~XRInputPose() {}
+
+DOMFloat32Array* XRInputPose::pointerMatrix() const {
+ if (!pointer_matrix_)
+ return nullptr;
+ return transformationMatrixToFloat32Array(*pointer_matrix_);
+}
+
+DOMFloat32Array* XRInputPose::gripMatrix() const {
+ if (!grip_matrix_)
+ return nullptr;
+ return transformationMatrixToFloat32Array(*grip_matrix_);
+}
+
+void XRInputPose::Trace(blink::Visitor* visitor) {
+ ScriptWrappable::Trace(visitor);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_input_pose.h b/chromium/third_party/blink/renderer/modules/xr/xr_input_pose.h
new file mode 100644
index 00000000000..ec5d269eb85
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_input_pose.h
@@ -0,0 +1,39 @@
+// Copyright 2018 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 THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_INPUT_POSE_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_INPUT_POSE_H_
+
+#include "third_party/blink/renderer/core/typed_arrays/dom_typed_array.h"
+#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
+#include "third_party/blink/renderer/platform/heap/handle.h"
+#include "third_party/blink/renderer/platform/transforms/transformation_matrix.h"
+#include "third_party/blink/renderer/platform/wtf/forward.h"
+
+namespace blink {
+
+class XRInputPose final : public ScriptWrappable {
+ DEFINE_WRAPPERTYPEINFO();
+
+ public:
+ XRInputPose(std::unique_ptr<TransformationMatrix> pointer_matrix,
+ std::unique_ptr<TransformationMatrix> grip_matrix,
+ bool emulated_position = false);
+ ~XRInputPose();
+
+ DOMFloat32Array* pointerMatrix() const;
+ DOMFloat32Array* gripMatrix() const;
+ bool emulatedPosition() const { return emulated_position_; }
+
+ virtual void Trace(blink::Visitor*);
+
+ private:
+ const std::unique_ptr<TransformationMatrix> pointer_matrix_;
+ const std::unique_ptr<TransformationMatrix> grip_matrix_;
+ const bool emulated_position_;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_INPUT_POSE_H_
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_input_pose.idl b/chromium/third_party/blink/renderer/modules/xr/xr_input_pose.idl
new file mode 100644
index 00000000000..6113cc72548
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_input_pose.idl
@@ -0,0 +1,12 @@
+// Copyright 2018 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.
+
+[
+ SecureContext,
+ OriginTrialEnabled=WebXR
+] interface XRInputPose {
+ readonly attribute Float32Array pointerMatrix;
+ readonly attribute Float32Array? gripMatrix;
+ readonly attribute boolean emulatedPosition;
+}; \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_input_source.cc b/chromium/third_party/blink/renderer/modules/xr/xr_input_source.cc
new file mode 100644
index 00000000000..761a46d50c6
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_input_source.cc
@@ -0,0 +1,77 @@
+// Copyright 2018 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 "third_party/blink/renderer/modules/xr/xr_input_source.h"
+#include "third_party/blink/renderer/modules/xr/xr_session.h"
+
+namespace blink {
+
+XRInputSource::XRInputSource(XRSession* session, uint32_t source_id)
+ : session_(session), source_id_(source_id) {
+ SetPointerOrigin(kOriginHead);
+ SetHandedness(kHandNone);
+}
+
+void XRInputSource::SetPointerOrigin(PointerOrigin pointer_origin) {
+ if (pointer_origin_ == pointer_origin)
+ return;
+
+ pointer_origin_ = pointer_origin;
+
+ switch (pointer_origin_) {
+ case kOriginHead:
+ pointer_origin_string_ = "head";
+ break;
+ case kOriginHand:
+ pointer_origin_string_ = "hand";
+ break;
+ case kOriginScreen:
+ pointer_origin_string_ = "screen";
+ break;
+ default:
+ NOTREACHED() << "Unknown pointer origin: " << pointer_origin_;
+ }
+}
+
+void XRInputSource::SetHandedness(Handedness handedness) {
+ if (handedness_ == handedness)
+ return;
+
+ handedness_ = handedness;
+
+ switch (handedness_) {
+ case kHandNone:
+ handedness_string_ = "";
+ break;
+ case kHandLeft:
+ handedness_string_ = "left";
+ break;
+ case kHandRight:
+ handedness_string_ = "right";
+ break;
+ default:
+ NOTREACHED() << "Unknown handedness: " << handedness_;
+ }
+}
+
+void XRInputSource::SetEmulatedPosition(bool emulated_position) {
+ emulated_position_ = emulated_position;
+}
+
+void XRInputSource::SetBasePoseMatrix(
+ std::unique_ptr<TransformationMatrix> base_pose_matrix) {
+ base_pose_matrix_ = std::move(base_pose_matrix);
+}
+
+void XRInputSource::SetPointerTransformMatrix(
+ std::unique_ptr<TransformationMatrix> pointer_transform_matrix) {
+ pointer_transform_matrix_ = std::move(pointer_transform_matrix);
+}
+
+void XRInputSource::Trace(blink::Visitor* visitor) {
+ visitor->Trace(session_);
+ ScriptWrappable::Trace(visitor);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_input_source.h b/chromium/third_party/blink/renderer/modules/xr/xr_input_source.h
new file mode 100644
index 00000000000..f1786bfb098
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_input_source.h
@@ -0,0 +1,71 @@
+// Copyright 2018 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 THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_INPUT_SOURCE_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_INPUT_SOURCE_H_
+
+#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
+#include "third_party/blink/renderer/platform/heap/handle.h"
+#include "third_party/blink/renderer/platform/transforms/transformation_matrix.h"
+#include "third_party/blink/renderer/platform/wtf/forward.h"
+#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
+
+namespace blink {
+
+class XRSession;
+
+class XRInputSource : public ScriptWrappable {
+ DEFINE_WRAPPERTYPEINFO();
+
+ public:
+ enum Handedness { kHandNone = 0, kHandLeft = 1, kHandRight = 2 };
+ enum PointerOrigin { kOriginHead = 1, kOriginHand = 2, kOriginScreen = 3 };
+
+ XRInputSource(XRSession*, uint32_t source_id);
+ virtual ~XRInputSource() = default;
+
+ XRSession* session() const { return session_; }
+
+ const String& handedness() const { return handedness_string_; }
+ const String& pointerOrigin() const { return pointer_origin_string_; }
+ bool emulatedPosition() const { return emulated_position_; }
+
+ uint32_t source_id() const { return source_id_; }
+
+ void SetPointerOrigin(PointerOrigin);
+ void SetHandedness(Handedness);
+ void SetEmulatedPosition(bool emulated_position);
+ void SetBasePoseMatrix(std::unique_ptr<TransformationMatrix>);
+ void SetPointerTransformMatrix(std::unique_ptr<TransformationMatrix>);
+
+ virtual void Trace(blink::Visitor*);
+
+ int16_t active_frame_id = -1;
+ bool primary_input_pressed = false;
+ bool selection_cancelled = false;
+
+ private:
+ friend class XRPresentationFrame;
+
+ const Member<XRSession> session_;
+ const uint32_t source_id_;
+
+ Handedness handedness_;
+ String handedness_string_;
+
+ PointerOrigin pointer_origin_;
+ String pointer_origin_string_;
+
+ bool emulated_position_ = false;
+
+ std::unique_ptr<TransformationMatrix> base_pose_matrix_;
+
+ // This is the transform to apply to the base_pose_matrix_ to get the pointer
+ // matrix. In most cases it should be static.
+ std::unique_ptr<TransformationMatrix> pointer_transform_matrix_;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_INPUT_SOURCE_H_
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_input_source.idl b/chromium/third_party/blink/renderer/modules/xr/xr_input_source.idl
new file mode 100644
index 00000000000..bc084732141
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_input_source.idl
@@ -0,0 +1,22 @@
+// Copyright 2018 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.
+
+enum XRHandedness {
+ "left",
+ "right"
+};
+
+enum XRPointerOrigin {
+ "head",
+ "grip",
+ "screen"
+};
+
+[
+ SecureContext,
+ OriginTrialEnabled=WebXR
+] interface XRInputSource {
+ readonly attribute XRHandedness handedness;
+ readonly attribute XRPointerOrigin pointerOrigin;
+}; \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_input_source_event.cc b/chromium/third_party/blink/renderer/modules/xr/xr_input_source_event.cc
new file mode 100644
index 00000000000..ce47b89c169
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_input_source_event.cc
@@ -0,0 +1,40 @@
+// Copyright 2018 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 "third_party/blink/renderer/modules/xr/xr_input_source_event.h"
+
+namespace blink {
+
+XRInputSourceEvent::XRInputSourceEvent() {}
+
+XRInputSourceEvent::XRInputSourceEvent(const AtomicString& type,
+ XRPresentationFrame* frame,
+ XRInputSource* input_source)
+ : Event(type, Bubbles::kYes, Cancelable::kNo),
+ frame_(frame),
+ input_source_(input_source) {}
+
+XRInputSourceEvent::XRInputSourceEvent(
+ const AtomicString& type,
+ const XRInputSourceEventInit& initializer)
+ : Event(type, initializer) {
+ if (initializer.hasFrame())
+ frame_ = initializer.frame();
+ if (initializer.hasInputSource())
+ input_source_ = initializer.inputSource();
+}
+
+XRInputSourceEvent::~XRInputSourceEvent() {}
+
+const AtomicString& XRInputSourceEvent::InterfaceName() const {
+ return EventNames::XRInputSourceEvent;
+}
+
+void XRInputSourceEvent::Trace(blink::Visitor* visitor) {
+ visitor->Trace(frame_);
+ visitor->Trace(input_source_);
+ Event::Trace(visitor);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_input_source_event.h b/chromium/third_party/blink/renderer/modules/xr/xr_input_source_event.h
new file mode 100644
index 00000000000..bd9649588d9
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_input_source_event.h
@@ -0,0 +1,53 @@
+// Copyright 2018 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 THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_INPUT_SOURCE_EVENT_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_INPUT_SOURCE_EVENT_H_
+
+#include "third_party/blink/renderer/modules/event_modules.h"
+#include "third_party/blink/renderer/modules/xr/xr_input_source.h"
+#include "third_party/blink/renderer/modules/xr/xr_input_source_event_init.h"
+#include "third_party/blink/renderer/modules/xr/xr_presentation_frame.h"
+
+namespace blink {
+
+class XRInputSourceEvent final : public Event {
+ DEFINE_WRAPPERTYPEINFO();
+
+ public:
+ static XRInputSourceEvent* Create() { return new XRInputSourceEvent; }
+ static XRInputSourceEvent* Create(const AtomicString& type,
+ XRPresentationFrame* frame,
+ XRInputSource* input_source) {
+ return new XRInputSourceEvent(type, frame, input_source);
+ }
+
+ static XRInputSourceEvent* Create(const AtomicString& type,
+ const XRInputSourceEventInit& initializer) {
+ return new XRInputSourceEvent(type, initializer);
+ }
+
+ ~XRInputSourceEvent() override;
+
+ XRPresentationFrame* frame() const { return frame_.Get(); }
+ XRInputSource* inputSource() const { return input_source_.Get(); }
+
+ const AtomicString& InterfaceName() const override;
+
+ virtual void Trace(blink::Visitor*);
+
+ private:
+ XRInputSourceEvent();
+ XRInputSourceEvent(const AtomicString& type,
+ XRPresentationFrame*,
+ XRInputSource*);
+ XRInputSourceEvent(const AtomicString&, const XRInputSourceEventInit&);
+
+ Member<XRPresentationFrame> frame_;
+ Member<XRInputSource> input_source_;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_INPUT_SOURCE_EVENT_H_
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_input_source_event.idl b/chromium/third_party/blink/renderer/modules/xr/xr_input_source_event.idl
new file mode 100644
index 00000000000..cbcb28c9150
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_input_source_event.idl
@@ -0,0 +1,12 @@
+// Copyright 2018 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.
+
+[
+ SecureContext,
+ OriginTrialEnabled=WebXR,
+ Constructor(DOMString type, XRInputSourceEventInit eventInitDict)
+] interface XRInputSourceEvent : Event {
+ readonly attribute XRPresentationFrame frame;
+ readonly attribute XRInputSource inputSource;
+};
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_input_source_event_init.idl b/chromium/third_party/blink/renderer/modules/xr/xr_input_source_event_init.idl
new file mode 100644
index 00000000000..b24af31a375
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_input_source_event_init.idl
@@ -0,0 +1,10 @@
+// Copyright 2018 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.
+
+[
+ SecureContext
+] dictionary XRInputSourceEventInit : EventInit {
+ required XRPresentationFrame frame;
+ required XRInputSource inputSource;
+}; \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_layer.cc b/chromium/third_party/blink/renderer/modules/xr/xr_layer.cc
new file mode 100644
index 00000000000..6dd1aeaa952
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_layer.cc
@@ -0,0 +1,24 @@
+// 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 "third_party/blink/renderer/modules/xr/xr_layer.h"
+#include "third_party/blink/renderer/modules/xr/xr_session.h"
+
+#include "device/vr/public/mojom/vr_service.mojom-blink.h"
+
+namespace blink {
+
+XRLayer::XRLayer(XRSession* session, XRLayerType layer_type)
+ : session_(session), layer_type_(layer_type) {}
+
+void XRLayer::OnFrameStart(const base::Optional<gpu::MailboxHolder>&) {}
+void XRLayer::OnFrameEnd() {}
+void XRLayer::OnResize() {}
+
+void XRLayer::Trace(blink::Visitor* visitor) {
+ visitor->Trace(session_);
+ ScriptWrappable::Trace(visitor);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_layer.h b/chromium/third_party/blink/renderer/modules/xr/xr_layer.h
new file mode 100644
index 00000000000..d6368242885
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_layer.h
@@ -0,0 +1,41 @@
+// 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 THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_LAYER_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_LAYER_H_
+
+#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
+#include "third_party/blink/renderer/platform/graphics/gpu/xr_webgl_drawing_buffer.h"
+#include "third_party/blink/renderer/platform/heap/handle.h"
+#include "third_party/blink/renderer/platform/wtf/forward.h"
+
+namespace blink {
+
+class XRSession;
+
+enum XRLayerType { kXRWebGLLayerType };
+
+class XRLayer : public ScriptWrappable {
+ DEFINE_WRAPPERTYPEINFO();
+
+ public:
+ XRLayer(XRSession*, XRLayerType);
+
+ XRSession* session() const { return session_; }
+ XRLayerType layerType() const { return layer_type_; }
+
+ virtual void OnFrameStart(const base::Optional<gpu::MailboxHolder>&);
+ virtual void OnFrameEnd();
+ virtual void OnResize();
+
+ virtual void Trace(blink::Visitor*);
+
+ private:
+ const Member<XRSession> session_;
+ XRLayerType layer_type_;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_LAYER_H_
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_layer.idl b/chromium/third_party/blink/renderer/modules/xr/xr_layer.idl
new file mode 100644
index 00000000000..1b411d681ab
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_layer.idl
@@ -0,0 +1,9 @@
+// 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://immersive-web.github.io/webxr/spec/latest/#xrlayer-interface
+[
+ SecureContext,
+ OriginTrialEnabled=WebXR
+] interface XRLayer {};
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_presentation_context.cc b/chromium/third_party/blink/renderer/modules/xr/xr_presentation_context.cc
new file mode 100644
index 00000000000..ba46309b911
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_presentation_context.cc
@@ -0,0 +1,32 @@
+// Copyright 2018 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 "third_party/blink/renderer/modules/xr/xr_presentation_context.h"
+
+#include "third_party/blink/renderer/bindings/modules/v8/rendering_context.h"
+#include "third_party/blink/renderer/core/origin_trials/origin_trials.h"
+
+namespace blink {
+
+XRPresentationContext::XRPresentationContext(
+ CanvasRenderingContextHost* host,
+ const CanvasContextCreationAttributesCore& attrs)
+ : ImageBitmapRenderingContextBase(host, attrs) {}
+
+XRPresentationContext::~XRPresentationContext() {}
+
+void XRPresentationContext::SetCanvasGetContextResult(
+ RenderingContext& result) {
+ result.SetXRPresentationContext(this);
+}
+
+CanvasRenderingContext* XRPresentationContext::Factory::Create(
+ CanvasRenderingContextHost* host,
+ const CanvasContextCreationAttributesCore& attrs) {
+ if (!OriginTrials::webXREnabled(host->GetTopExecutionContext()))
+ return nullptr;
+ return new XRPresentationContext(host, attrs);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_presentation_context.h b/chromium/third_party/blink/renderer/modules/xr/xr_presentation_context.h
new file mode 100644
index 00000000000..0cace4708a2
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_presentation_context.h
@@ -0,0 +1,58 @@
+// Copyright 2018 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 THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_PRESENTATION_CONTEXT_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_PRESENTATION_CONTEXT_H_
+
+#include "base/memory/scoped_refptr.h"
+#include "third_party/blink/renderer/core/html/canvas/canvas_rendering_context_factory.h"
+#include "third_party/blink/renderer/modules/canvas/imagebitmap/image_bitmap_rendering_context_base.h"
+#include "third_party/blink/renderer/modules/modules_export.h"
+
+namespace blink {
+
+class MODULES_EXPORT XRPresentationContext final
+ : public ImageBitmapRenderingContextBase {
+ DEFINE_WRAPPERTYPEINFO();
+
+ public:
+ class Factory : public CanvasRenderingContextFactory {
+ WTF_MAKE_NONCOPYABLE(Factory);
+
+ public:
+ Factory() {}
+ ~Factory() override {}
+
+ CanvasRenderingContext* Create(
+ CanvasRenderingContextHost*,
+ const CanvasContextCreationAttributesCore&) override;
+ CanvasRenderingContext::ContextType GetContextType() const override {
+ return CanvasRenderingContext::kContextXRPresent;
+ }
+ };
+
+ // CanvasRenderingContext implementation
+ ContextType GetContextType() const override {
+ return CanvasRenderingContext::kContextXRPresent;
+ }
+ void SetCanvasGetContextResult(RenderingContext&) final;
+
+ virtual ~XRPresentationContext();
+
+ private:
+ XRPresentationContext(CanvasRenderingContextHost*,
+ const CanvasContextCreationAttributesCore&);
+};
+
+DEFINE_TYPE_CASTS(XRPresentationContext,
+ CanvasRenderingContext,
+ context,
+ context->GetContextType() ==
+ CanvasRenderingContext::kContextXRPresent,
+ context.GetContextType() ==
+ CanvasRenderingContext::kContextXRPresent);
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_PRESENTATION_CONTEXT_H_
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_presentation_context.idl b/chromium/third_party/blink/renderer/modules/xr/xr_presentation_context.idl
new file mode 100644
index 00000000000..c490176a130
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_presentation_context.idl
@@ -0,0 +1,12 @@
+// Copyright 2018 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://immersive-web.github.io/webxr/spec/latest/#xrpresentationcontext-interface
+[
+ SecureContext,
+ OriginTrialEnabled=WebXR
+] interface XRPresentationContext {
+ // back-reference to the canvas
+ readonly attribute HTMLCanvasElement canvas;
+}; \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_presentation_frame.cc b/chromium/third_party/blink/renderer/modules/xr/xr_presentation_frame.cc
new file mode 100644
index 00000000000..cb1aa151016
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_presentation_frame.cc
@@ -0,0 +1,129 @@
+// 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 "third_party/blink/renderer/modules/xr/xr_presentation_frame.h"
+
+#include "third_party/blink/renderer/modules/xr/xr_coordinate_system.h"
+#include "third_party/blink/renderer/modules/xr/xr_device_pose.h"
+#include "third_party/blink/renderer/modules/xr/xr_input_pose.h"
+#include "third_party/blink/renderer/modules/xr/xr_input_source.h"
+#include "third_party/blink/renderer/modules/xr/xr_session.h"
+#include "third_party/blink/renderer/modules/xr/xr_view.h"
+
+namespace blink {
+
+XRPresentationFrame::XRPresentationFrame(XRSession* session)
+ : session_(session) {}
+
+const HeapVector<Member<XRView>>& XRPresentationFrame::views() const {
+ return session_->views();
+}
+
+XRDevicePose* XRPresentationFrame::getDevicePose(
+ XRCoordinateSystem* coordinate_system) const {
+ // If we don't have a valid base pose return null. Most common when tracking
+ // is lost.
+ if (!base_pose_matrix_ || !coordinate_system) {
+ return nullptr;
+ }
+
+ // Must use a coordinate system created from the same session.
+ if (coordinate_system->session() != session_) {
+ return nullptr;
+ }
+
+ std::unique_ptr<TransformationMatrix> pose =
+ coordinate_system->TransformBasePose(*base_pose_matrix_);
+
+ if (!pose) {
+ return nullptr;
+ }
+
+ return new XRDevicePose(session(), std::move(pose));
+}
+
+XRInputPose* XRPresentationFrame::getInputPose(
+ XRInputSource* input_source,
+ XRCoordinateSystem* coordinate_system) const {
+ if (!input_source || !coordinate_system) {
+ return nullptr;
+ }
+
+ // Must use an input source and coordinate system from the same session.
+ if (input_source->session() != session_ ||
+ coordinate_system->session() != session_) {
+ return nullptr;
+ }
+
+ switch (input_source->pointer_origin_) {
+ case XRInputSource::kOriginScreen: {
+ // If the pointer origin is the screen we need the head's base pose and
+ // the pointer transform matrix to continue. The pointer transform will
+ // represent the point the canvas was clicked as an offset from the view.
+ if (!base_pose_matrix_ || !input_source->pointer_transform_matrix_) {
+ return nullptr;
+ }
+
+ // Multiply the head pose and pointer transform to get the final pointer.
+ std::unique_ptr<TransformationMatrix> pointer_pose =
+ coordinate_system->TransformBasePose(*base_pose_matrix_);
+ pointer_pose->Multiply(*(input_source->pointer_transform_matrix_));
+
+ return new XRInputPose(std::move(pointer_pose), nullptr);
+ }
+ case XRInputSource::kOriginHead: {
+ // If the pointer origin is the users head, this is a gaze cursor and the
+ // returned pointer is based on the device pose. If we don't have a valid
+ // base pose (most common when tracking is lost) return null.
+ if (!base_pose_matrix_) {
+ return nullptr;
+ }
+
+ // Just return the head pose as the pointer pose.
+ std::unique_ptr<TransformationMatrix> pointer_pose =
+ coordinate_system->TransformBasePose(*base_pose_matrix_);
+
+ return new XRInputPose(std::move(pointer_pose), nullptr,
+ input_source->emulatedPosition());
+ }
+ case XRInputSource::kOriginHand: {
+ // If the input source doesn't have a base pose return null;
+ if (!input_source->base_pose_matrix_) {
+ return nullptr;
+ }
+
+ std::unique_ptr<TransformationMatrix> grip_pose =
+ coordinate_system->TransformBaseInputPose(
+ *(input_source->base_pose_matrix_), *base_pose_matrix_);
+
+ if (!grip_pose) {
+ return nullptr;
+ }
+
+ std::unique_ptr<TransformationMatrix> pointer_pose(
+ TransformationMatrix::Create(*grip_pose));
+
+ if (input_source->pointer_transform_matrix_) {
+ pointer_pose->Multiply(*(input_source->pointer_transform_matrix_));
+ }
+
+ return new XRInputPose(std::move(pointer_pose), std::move(grip_pose),
+ input_source->emulatedPosition());
+ }
+ }
+
+ return nullptr;
+}
+
+void XRPresentationFrame::SetBasePoseMatrix(
+ const TransformationMatrix& base_pose_matrix) {
+ base_pose_matrix_ = TransformationMatrix::Create(base_pose_matrix);
+}
+
+void XRPresentationFrame::Trace(blink::Visitor* visitor) {
+ visitor->Trace(session_);
+ ScriptWrappable::Trace(visitor);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_presentation_frame.h b/chromium/third_party/blink/renderer/modules/xr/xr_presentation_frame.h
new file mode 100644
index 00000000000..efbfa207eb3
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_presentation_frame.h
@@ -0,0 +1,47 @@
+// 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 THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_PRESENTATION_FRAME_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_PRESENTATION_FRAME_H_
+
+#include "device/vr/public/mojom/vr_service.mojom-blink.h"
+#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
+#include "third_party/blink/renderer/platform/bindings/trace_wrapper_member.h"
+#include "third_party/blink/renderer/platform/heap/handle.h"
+#include "third_party/blink/renderer/platform/transforms/transformation_matrix.h"
+#include "third_party/blink/renderer/platform/wtf/forward.h"
+
+namespace blink {
+
+class XRCoordinateSystem;
+class XRDevicePose;
+class XRInputPose;
+class XRInputSource;
+class XRSession;
+class XRView;
+
+class XRPresentationFrame final : public ScriptWrappable {
+ DEFINE_WRAPPERTYPEINFO();
+
+ public:
+ explicit XRPresentationFrame(XRSession*);
+
+ XRSession* session() const { return session_; }
+
+ const HeapVector<Member<XRView>>& views() const;
+ XRDevicePose* getDevicePose(XRCoordinateSystem*) const;
+ XRInputPose* getInputPose(XRInputSource*, XRCoordinateSystem*) const;
+
+ void SetBasePoseMatrix(const TransformationMatrix&);
+
+ virtual void Trace(blink::Visitor*);
+
+ private:
+ const Member<XRSession> session_;
+ std::unique_ptr<TransformationMatrix> base_pose_matrix_;
+};
+
+} // namespace blink
+
+#endif // XRWebGLLayer_h
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_presentation_frame.idl b/chromium/third_party/blink/renderer/modules/xr/xr_presentation_frame.idl
new file mode 100644
index 00000000000..51bb3b3df6a
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_presentation_frame.idl
@@ -0,0 +1,16 @@
+// 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://immersive-web.github.io/webxr/spec/latest/#xrpresentationframe-interface
+[
+ SecureContext,
+ OriginTrialEnabled=WebXR
+] interface XRPresentationFrame {
+ readonly attribute XRSession session;
+ readonly attribute FrozenArray<XRView> views;
+
+ XRDevicePose? getDevicePose(XRCoordinateSystem coordinateSystem);
+ XRInputPose? getInputPose(XRInputSource inputSource,
+ XRCoordinateSystem coordinateSystem);
+};
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_session.cc b/chromium/third_party/blink/renderer/modules/xr/xr_session.cc
new file mode 100644
index 00000000000..8217f882cc7
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_session.cc
@@ -0,0 +1,616 @@
+// 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 "third_party/blink/renderer/modules/xr/xr_session.h"
+
+#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_xr_frame_request_callback.h"
+#include "third_party/blink/renderer/core/dom/dom_exception.h"
+#include "third_party/blink/renderer/core/dom/element.h"
+#include "third_party/blink/renderer/core/frame/local_frame.h"
+#include "third_party/blink/renderer/core/resize_observer/resize_observer.h"
+#include "third_party/blink/renderer/core/resize_observer/resize_observer_entry.h"
+#include "third_party/blink/renderer/modules/event_target_modules.h"
+#include "third_party/blink/renderer/modules/xr/xr.h"
+#include "third_party/blink/renderer/modules/xr/xr_canvas_input_provider.h"
+#include "third_party/blink/renderer/modules/xr/xr_device.h"
+#include "third_party/blink/renderer/modules/xr/xr_frame_of_reference.h"
+#include "third_party/blink/renderer/modules/xr/xr_frame_of_reference_options.h"
+#include "third_party/blink/renderer/modules/xr/xr_frame_provider.h"
+#include "third_party/blink/renderer/modules/xr/xr_input_source_event.h"
+#include "third_party/blink/renderer/modules/xr/xr_layer.h"
+#include "third_party/blink/renderer/modules/xr/xr_presentation_context.h"
+#include "third_party/blink/renderer/modules/xr/xr_presentation_frame.h"
+#include "third_party/blink/renderer/modules/xr/xr_session_event.h"
+#include "third_party/blink/renderer/modules/xr/xr_view.h"
+#include "third_party/blink/renderer/platform/wtf/auto_reset.h"
+
+namespace blink {
+
+namespace {
+
+const char kSessionEnded[] = "XRSession has already ended.";
+
+const char kUnknownFrameOfReference[] = "Unknown frame of reference type.";
+
+const char kNonEmulatedStageNotSupported[] =
+ "This device does not support a non-emulated 'stage' frame of reference.";
+
+const double kDegToRad = M_PI / 180.0;
+
+// TODO(bajones): This is something that we probably want to make configurable.
+const double kMagicWindowVerticalFieldOfView = 75.0f * M_PI / 180.0f;
+
+void UpdateViewFromEyeParameters(
+ XRView* view,
+ const device::mojom::blink::VREyeParametersPtr& eye,
+ double depth_near,
+ double depth_far) {
+ const device::mojom::blink::VRFieldOfViewPtr& fov = eye->fieldOfView;
+
+ view->UpdateProjectionMatrixFromFoV(
+ fov->upDegrees * kDegToRad, fov->downDegrees * kDegToRad,
+ fov->leftDegrees * kDegToRad, fov->rightDegrees * kDegToRad, depth_near,
+ depth_far);
+
+ view->UpdateOffset(eye->offset[0], eye->offset[1], eye->offset[2]);
+}
+
+} // namespace
+
+class XRSession::XRSessionResizeObserverDelegate final
+ : public ResizeObserver::Delegate {
+ public:
+ explicit XRSessionResizeObserverDelegate(XRSession* session)
+ : session_(session) {
+ DCHECK(session);
+ }
+ ~XRSessionResizeObserverDelegate() override = default;
+
+ void OnResize(
+ const HeapVector<Member<ResizeObserverEntry>>& entries) override {
+ DCHECK_EQ(1u, entries.size());
+ session_->UpdateCanvasDimensions(entries[0]->target());
+ }
+
+ void Trace(blink::Visitor* visitor) {
+ visitor->Trace(session_);
+ ResizeObserver::Delegate::Trace(visitor);
+ }
+
+ private:
+ Member<XRSession> session_;
+};
+
+XRSession::XRSession(XRDevice* device,
+ bool exclusive,
+ XRPresentationContext* output_context)
+ : device_(device),
+ exclusive_(exclusive),
+ output_context_(output_context),
+ callback_collection_(device->GetExecutionContext()) {
+ blurred_ = !HasAppropriateFocus();
+
+ // When an output context is provided, monitor it for resize events.
+ if (output_context_) {
+ HTMLCanvasElement* canvas = outputContext()->canvas();
+ if (canvas) {
+ resize_observer_ = ResizeObserver::Create(
+ canvas->GetDocument(), new XRSessionResizeObserverDelegate(this));
+ resize_observer_->observe(canvas);
+
+ // Begin processing input events on the output context's canvas.
+ if (!exclusive_) {
+ canvas_input_provider_ = new XRCanvasInputProvider(this, canvas);
+ }
+
+ // Get the initial canvas dimensions
+ UpdateCanvasDimensions(canvas);
+ }
+ }
+}
+
+void XRSession::setDepthNear(double value) {
+ if (depth_near_ != value) {
+ update_views_next_frame_ = true;
+ depth_near_ = value;
+ }
+}
+
+void XRSession::setDepthFar(double value) {
+ if (depth_far_ != value) {
+ update_views_next_frame_ = true;
+ depth_far_ = value;
+ }
+}
+
+void XRSession::setBaseLayer(XRLayer* value) {
+ base_layer_ = value;
+ // Make sure that the layer's drawing buffer is updated to the right size
+ // if this is a non-exclusive session.
+ if (!exclusive_ && base_layer_) {
+ base_layer_->OnResize();
+ }
+}
+
+ExecutionContext* XRSession::GetExecutionContext() const {
+ return device_->GetExecutionContext();
+}
+
+const AtomicString& XRSession::InterfaceName() const {
+ return EventTargetNames::XRSession;
+}
+
+ScriptPromise XRSession::requestFrameOfReference(
+ ScriptState* script_state,
+ const String& type,
+ const XRFrameOfReferenceOptions& options) {
+ if (ended_) {
+ return ScriptPromise::RejectWithDOMException(
+ script_state, DOMException::Create(kInvalidStateError, kSessionEnded));
+ }
+
+ XRFrameOfReference* frameOfRef = nullptr;
+ if (type == "headModel") {
+ frameOfRef =
+ new XRFrameOfReference(this, XRFrameOfReference::kTypeHeadModel);
+ } else if (type == "eyeLevel") {
+ frameOfRef =
+ new XRFrameOfReference(this, XRFrameOfReference::kTypeEyeLevel);
+ } else if (type == "stage") {
+ if (!options.disableStageEmulation()) {
+ frameOfRef = new XRFrameOfReference(this, XRFrameOfReference::kTypeStage);
+ frameOfRef->UseEmulatedHeight(options.stageEmulationHeight());
+ } else if (device_->xrDisplayInfoPtr()->stageParameters) {
+ frameOfRef = new XRFrameOfReference(this, XRFrameOfReference::kTypeStage);
+ } else {
+ return ScriptPromise::RejectWithDOMException(
+ script_state, DOMException::Create(kNotSupportedError,
+ kNonEmulatedStageNotSupported));
+ }
+ }
+
+ if (!frameOfRef) {
+ return ScriptPromise::RejectWithDOMException(
+ script_state,
+ DOMException::Create(kNotSupportedError, kUnknownFrameOfReference));
+ }
+
+ ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state);
+ ScriptPromise promise = resolver->Promise();
+ resolver->Resolve(frameOfRef);
+
+ return promise;
+}
+
+int XRSession::requestAnimationFrame(V8XRFrameRequestCallback* callback) {
+ // Don't allow any new frame requests once the session is ended.
+ if (ended_)
+ return 0;
+
+ // Don't allow frames to be scheduled if there's no layers attached to the
+ // session. That would allow tracking with no associated visuals.
+ if (!base_layer_)
+ return 0;
+
+ int id = callback_collection_.RegisterCallback(callback);
+ if (!pending_frame_) {
+ // Kick off a request for a new XR frame.
+ device_->frameProvider()->RequestFrame(this);
+ pending_frame_ = true;
+ }
+ return id;
+}
+
+void XRSession::cancelAnimationFrame(int id) {
+ callback_collection_.CancelCallback(id);
+}
+
+HeapVector<Member<XRInputSource>> XRSession::getInputSources() const {
+ HeapVector<Member<XRInputSource>> source_array;
+ for (const auto& input_source : input_sources_.Values()) {
+ source_array.push_back(input_source);
+ }
+
+ if (canvas_input_provider_) {
+ XRInputSource* input_source = canvas_input_provider_->GetInputSource();
+ if (input_source) {
+ source_array.push_back(input_source);
+ }
+ }
+
+ return source_array;
+}
+
+ScriptPromise XRSession::end(ScriptState* script_state) {
+ // Don't allow a session to end twice.
+ if (ended_) {
+ return ScriptPromise::RejectWithDOMException(
+ script_state, DOMException::Create(kInvalidStateError, kSessionEnded));
+ }
+
+ ForceEnd();
+
+ 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.
+
+ resolver->Resolve();
+ return promise;
+}
+
+void XRSession::ForceEnd() {
+ // Detach this session from the device.
+ ended_ = true;
+ pending_frame_ = false;
+
+ if (canvas_input_provider_) {
+ canvas_input_provider_->Stop();
+ canvas_input_provider_ = nullptr;
+ }
+
+ // If this session is the active exclusive session for the device, notify the
+ // frameProvider that it's ended.
+ if (device_->frameProvider()->exclusive_session() == this) {
+ device_->frameProvider()->OnExclusiveSessionEnded();
+ }
+
+ DispatchEvent(XRSessionEvent::Create(EventTypeNames::end, this));
+}
+
+double XRSession::DefaultFramebufferScale() const {
+ if (exclusive_)
+ return device_->xrDisplayInfoPtr()->webxr_default_framebuffer_scale;
+ return 1.0;
+}
+
+DoubleSize XRSession::IdealFramebufferSize() const {
+ if (!exclusive_) {
+ return OutputCanvasSize();
+ }
+
+ double width = device_->xrDisplayInfoPtr()->leftEye->renderWidth +
+ device_->xrDisplayInfoPtr()->rightEye->renderWidth;
+ double height = std::max(device_->xrDisplayInfoPtr()->leftEye->renderHeight,
+ device_->xrDisplayInfoPtr()->rightEye->renderHeight);
+ return DoubleSize(width, height);
+}
+
+DoubleSize XRSession::OutputCanvasSize() const {
+ if (!output_context_) {
+ return DoubleSize();
+ }
+
+ return DoubleSize(output_width_, output_height_);
+}
+
+void XRSession::OnFocus() {
+ if (!blurred_)
+ return;
+
+ blurred_ = false;
+ DispatchEvent(XRSessionEvent::Create(EventTypeNames::focus, this));
+}
+
+void XRSession::OnBlur() {
+ if (blurred_)
+ return;
+
+ blurred_ = true;
+ DispatchEvent(XRSessionEvent::Create(EventTypeNames::blur, this));
+}
+
+// Exclusive sessions may still not be blurred in headset even if the page isn't
+// focused. This prevents the in-headset experience from freezing on an
+// external display headset when the user clicks on another tab.
+bool XRSession::HasAppropriateFocus() {
+ return exclusive_ ? device_->HasDeviceFocus()
+ : device_->HasDeviceAndFrameFocus();
+}
+
+void XRSession::OnFocusChanged() {
+ if (HasAppropriateFocus()) {
+ OnFocus();
+ } else {
+ OnBlur();
+ }
+}
+
+void XRSession::OnFrame(
+ std::unique_ptr<TransformationMatrix> base_pose_matrix,
+ const base::Optional<gpu::MailboxHolder>& buffer_mailbox_holder) {
+ DVLOG(2) << __FUNCTION__;
+ // Don't process any outstanding frames once the session is ended.
+ if (ended_)
+ return;
+
+ base_pose_matrix_ = std::move(base_pose_matrix);
+
+ // Don't allow frames to be processed if there's no layers attached to the
+ // session. That would allow tracking with no associated visuals.
+ if (!base_layer_)
+ return;
+
+ XRPresentationFrame* presentation_frame = CreatePresentationFrame();
+
+ if (pending_frame_) {
+ pending_frame_ = false;
+
+ // Make sure that any frame-bounded changed to the views array take effect.
+ if (update_views_next_frame_) {
+ views_dirty_ = true;
+ update_views_next_frame_ = false;
+ }
+
+ // Cache the base layer, since it could change during the frame callback.
+ XRLayer* frame_base_layer = base_layer_;
+ frame_base_layer->OnFrameStart(buffer_mailbox_holder);
+
+ // Resolve the queued requestAnimationFrame callbacks. All XR rendering will
+ // happen within these calls. resolving_frame_ will be true for the duration
+ // of the callbacks.
+ AutoReset<bool> resolving(&resolving_frame_, true);
+ callback_collection_.ExecuteCallbacks(this, presentation_frame);
+
+ // The session might have ended in the middle of the frame. Only call
+ // OnFrameEnd if it's still valid.
+ if (!ended_)
+ frame_base_layer->OnFrameEnd();
+ }
+}
+
+XRPresentationFrame* XRSession::CreatePresentationFrame() {
+ XRPresentationFrame* presentation_frame = new XRPresentationFrame(this);
+ if (base_pose_matrix_) {
+ presentation_frame->SetBasePoseMatrix(*base_pose_matrix_);
+ }
+ return presentation_frame;
+}
+
+// Called when the canvas element for this session's output context is resized.
+void XRSession::UpdateCanvasDimensions(Element* element) {
+ DCHECK(element);
+
+ double devicePixelRatio = 1.0;
+ LocalFrame* frame = device_->xr()->GetFrame();
+ if (frame) {
+ devicePixelRatio = frame->DevicePixelRatio();
+ }
+
+ update_views_next_frame_ = true;
+ output_width_ = element->OffsetWidth() * devicePixelRatio;
+ output_height_ = element->OffsetHeight() * devicePixelRatio;
+
+ if (base_layer_) {
+ base_layer_->OnResize();
+ }
+}
+
+void XRSession::OnInputStateChange(
+ int16_t frame_id,
+ const WTF::Vector<device::mojom::blink::XRInputSourceStatePtr>&
+ input_states) {
+ bool devices_changed = false;
+
+ // Update any input sources with new state information. Any updated input
+ // sources are marked as active.
+ for (const auto& input_state : input_states) {
+ XRInputSource* input_source = input_sources_.at(input_state->source_id);
+ if (!input_source) {
+ input_source = new XRInputSource(this, input_state->source_id);
+ input_sources_.Set(input_state->source_id, input_source);
+ devices_changed = true;
+ }
+ input_source->active_frame_id = frame_id;
+ UpdateInputSourceState(input_source, input_state);
+ }
+
+ // Remove any input sources that are inactive..
+ std::vector<uint32_t> inactive_sources;
+ for (const auto& input_source : input_sources_.Values()) {
+ if (input_source->active_frame_id != frame_id) {
+ inactive_sources.push_back(input_source->source_id());
+ devices_changed = true;
+ }
+ }
+
+ if (inactive_sources.size()) {
+ for (uint32_t source_id : inactive_sources) {
+ input_sources_.erase(source_id);
+ }
+ }
+
+ if (devices_changed) {
+ DispatchEvent(
+ XRSessionEvent::Create(EventTypeNames::inputsourceschange, this));
+ }
+}
+
+void XRSession::OnSelectStart(XRInputSource* input_source) {
+ // Discard duplicate events
+ if (input_source->primary_input_pressed)
+ return;
+
+ input_source->primary_input_pressed = true;
+ input_source->selection_cancelled = false;
+
+ XRInputSourceEvent* event =
+ CreateInputSourceEvent(EventTypeNames::selectstart, input_source);
+ DispatchEvent(event);
+
+ if (event->defaultPrevented())
+ input_source->selection_cancelled = true;
+}
+
+void XRSession::OnSelectEnd(XRInputSource* input_source) {
+ // Discard duplicate events
+ if (!input_source->primary_input_pressed)
+ return;
+
+ input_source->primary_input_pressed = false;
+
+ LocalFrame* frame = device_->xr()->GetFrame();
+ if (!frame)
+ return;
+
+ std::unique_ptr<UserGestureIndicator> gesture_indicator =
+ LocalFrame::CreateUserGesture(frame);
+
+ XRInputSourceEvent* event =
+ CreateInputSourceEvent(EventTypeNames::selectend, input_source);
+ DispatchEvent(event);
+
+ if (event->defaultPrevented())
+ input_source->selection_cancelled = true;
+}
+
+void XRSession::OnSelect(XRInputSource* input_source) {
+ // If a select was fired but we had not previously started the selection it
+ // indictes a sub-frame or instantanous select event, and we should fire a
+ // selectstart prior to the selectend.
+ if (!input_source->primary_input_pressed) {
+ OnSelectStart(input_source);
+ }
+
+ // Make sure we end the selection prior to firing the select event.
+ OnSelectEnd(input_source);
+
+ if (!input_source->selection_cancelled) {
+ XRInputSourceEvent* event =
+ CreateInputSourceEvent(EventTypeNames::select, input_source);
+ DispatchEvent(event);
+ }
+}
+
+void XRSession::UpdateInputSourceState(
+ XRInputSource* input_source,
+ const device::mojom::blink::XRInputSourceStatePtr& state) {
+ if (!input_source || !state)
+ return;
+
+ // Update the input source's description if this state update
+ // includes them.
+ if (state->description) {
+ const device::mojom::blink::XRInputSourceDescriptionPtr& desc =
+ state->description;
+
+ input_source->SetPointerOrigin(
+ static_cast<XRInputSource::PointerOrigin>(desc->pointer_origin));
+
+ input_source->SetHandedness(
+ static_cast<XRInputSource::Handedness>(desc->handedness));
+
+ input_source->SetEmulatedPosition(desc->emulated_position);
+
+ if (desc->pointer_offset && desc->pointer_offset->matrix.has_value()) {
+ const WTF::Vector<float>& m = desc->pointer_offset->matrix.value();
+ std::unique_ptr<TransformationMatrix> pointer_matrix =
+ TransformationMatrix::Create(m[0], m[1], m[2], m[3], m[4], m[5], m[6],
+ m[7], m[8], m[9], m[10], m[11], m[12],
+ m[13], m[14], m[15]);
+ input_source->SetPointerTransformMatrix(std::move(pointer_matrix));
+ }
+ }
+
+ if (state->grip && state->grip->matrix.has_value()) {
+ const Vector<float>& m = state->grip->matrix.value();
+ std::unique_ptr<TransformationMatrix> grip_matrix =
+ TransformationMatrix::Create(m[0], m[1], m[2], m[3], m[4], m[5], m[6],
+ m[7], m[8], m[9], m[10], m[11], m[12],
+ m[13], m[14], m[15]);
+ input_source->SetBasePoseMatrix(std::move(grip_matrix));
+ }
+
+ // Handle state change of the primary input, which may fire events
+ if (state->primary_input_clicked)
+ OnSelect(input_source);
+
+ if (state->primary_input_pressed) {
+ OnSelectStart(input_source);
+ } else if (input_source->primary_input_pressed) {
+ // May get here if the input source was previously pressed but now isn't,
+ // but the input source did not set primary_input_clicked to true. We will
+ // treat this as a cancelled selection, firing the selectend event so the
+ // page stays in sync with the controller state but won't fire the
+ // usual select event.
+ OnSelectEnd(input_source);
+ }
+}
+
+XRInputSourceEvent* XRSession::CreateInputSourceEvent(
+ const AtomicString& type,
+ XRInputSource* input_source) {
+ XRPresentationFrame* presentation_frame = CreatePresentationFrame();
+ return XRInputSourceEvent::Create(type, presentation_frame, input_source);
+}
+
+const HeapVector<Member<XRView>>& XRSession::views() {
+ // TODO(bajones): For now we assume that exclusive sessions render a stereo
+ // pair of views and non-exclusive sessions render a single view. That doesn't
+ // always hold true, however, so the view configuration should ultimately come
+ // from the backing service.
+ if (views_dirty_) {
+ if (exclusive_) {
+ // If we don't already have the views allocated, do so now.
+ if (views_.IsEmpty()) {
+ views_.push_back(new XRView(this, XRView::kEyeLeft));
+ views_.push_back(new XRView(this, XRView::kEyeRight));
+ }
+
+ // In exclusive mode the projection and view matrices must be aligned with
+ // the device's physical optics.
+ UpdateViewFromEyeParameters(views_[XRView::kEyeLeft],
+ device_->xrDisplayInfoPtr()->leftEye,
+ depth_near_, depth_far_);
+ UpdateViewFromEyeParameters(views_[XRView::kEyeRight],
+ device_->xrDisplayInfoPtr()->rightEye,
+ depth_near_, depth_far_);
+ } else {
+ if (views_.IsEmpty()) {
+ views_.push_back(new XRView(this, XRView::kEyeLeft));
+ views_[XRView::kEyeLeft]->UpdateOffset(0, 0, 0);
+ }
+
+ float aspect = 1.0f;
+ if (output_width_ && output_height_) {
+ aspect = static_cast<float>(output_width_) /
+ static_cast<float>(output_height_);
+ }
+
+ // In non-exclusive mode the projection matrix must be aligned with the
+ // output canvas dimensions.
+ views_[XRView::kEyeLeft]->UpdateProjectionMatrixFromAspect(
+ kMagicWindowVerticalFieldOfView, aspect, depth_near_, depth_far_);
+ }
+
+ views_dirty_ = false;
+ }
+
+ return views_;
+}
+
+void XRSession::Trace(blink::Visitor* visitor) {
+ visitor->Trace(device_);
+ visitor->Trace(output_context_);
+ visitor->Trace(base_layer_);
+ visitor->Trace(views_);
+ visitor->Trace(input_sources_);
+ visitor->Trace(resize_observer_);
+ visitor->Trace(canvas_input_provider_);
+ visitor->Trace(callback_collection_);
+ EventTargetWithInlineData::Trace(visitor);
+}
+
+void XRSession::TraceWrappers(
+ const blink::ScriptWrappableVisitor* visitor) const {
+ for (const auto& input_source : input_sources_.Values())
+ visitor->TraceWrappers(input_source);
+
+ visitor->TraceWrappers(callback_collection_);
+ EventTargetWithInlineData::TraceWrappers(visitor);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_session.h b/chromium/third_party/blink/renderer/modules/xr/xr_session.h
new file mode 100644
index 00000000000..d2e45423ccb
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_session.h
@@ -0,0 +1,162 @@
+// 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 THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_SESSION_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_SESSION_H_
+
+#include "device/vr/public/mojom/vr_service.mojom-blink.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
+#include "third_party/blink/renderer/core/dom/events/event_target.h"
+#include "third_party/blink/renderer/modules/xr/xr_frame_request_callback_collection.h"
+#include "third_party/blink/renderer/modules/xr/xr_input_source.h"
+#include "third_party/blink/renderer/platform/bindings/trace_wrapper_member.h"
+#include "third_party/blink/renderer/platform/geometry/double_size.h"
+#include "third_party/blink/renderer/platform/heap/handle.h"
+#include "third_party/blink/renderer/platform/transforms/transformation_matrix.h"
+#include "third_party/blink/renderer/platform/wtf/forward.h"
+
+namespace blink {
+
+class Element;
+class ResizeObserver;
+class V8XRFrameRequestCallback;
+class XRCanvasInputProvider;
+class XRDevice;
+class XRFrameOfReferenceOptions;
+class XRInputSourceEvent;
+class XRLayer;
+class XRPresentationContext;
+class XRView;
+
+class XRSession final : public EventTargetWithInlineData {
+ DEFINE_WRAPPERTYPEINFO();
+
+ public:
+ XRSession(XRDevice*, bool exclusive, XRPresentationContext* output_context);
+ ~XRSession() override = default;
+
+ XRDevice* device() const { return device_; }
+ bool exclusive() const { return exclusive_; }
+ XRPresentationContext* outputContext() const { return output_context_; }
+
+ // 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);
+
+ XRLayer* baseLayer() const { return base_layer_; }
+ void setBaseLayer(XRLayer* value);
+
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(blur);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(focus);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(resetpose);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(end);
+
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(selectstart);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(selectend);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(select);
+
+ ScriptPromise requestFrameOfReference(ScriptState*,
+ const String& type,
+ const XRFrameOfReferenceOptions&);
+
+ int requestAnimationFrame(V8XRFrameRequestCallback*);
+ void cancelAnimationFrame(int id);
+
+ using InputSourceMap =
+ HeapHashMap<uint32_t, TraceWrapperMember<XRInputSource>>;
+
+ HeapVector<Member<XRInputSource>> getInputSources() const;
+
+ // Called by JavaScript to manually end the session.
+ ScriptPromise end(ScriptState*);
+
+ bool ended() { return ended_; }
+
+ // Called when the session is ended, either via calling the "end" function or
+ // when the presentation service connection is closed.
+ void ForceEnd();
+
+ // Describes the default scalar to be applied to the ideal framebuffer
+ // dimensions when the developer does not specify one. Should be a value that
+ // provides a good balance between quality and performance.
+ double DefaultFramebufferScale() const;
+
+ // Describes the ideal dimensions of layer framebuffers, preferrably defined
+ // as the size which gives 1:1 pixel ratio at the center of the user's view.
+ DoubleSize IdealFramebufferSize() const;
+
+ // Reports the size of the output context's, if one is available. If not
+ // reports (0, 0);
+ DoubleSize OutputCanvasSize() const;
+
+ // EventTarget overrides.
+ ExecutionContext* GetExecutionContext() const override;
+ const AtomicString& InterfaceName() const override;
+
+ void OnFocusChanged();
+ void OnFrame(std::unique_ptr<TransformationMatrix>,
+ const base::Optional<gpu::MailboxHolder>&);
+ void OnInputStateChange(
+ int16_t frame_id,
+ const WTF::Vector<device::mojom::blink::XRInputSourceStatePtr>&);
+
+ const HeapVector<Member<XRView>>& views();
+
+ void OnSelectStart(XRInputSource*);
+ void OnSelectEnd(XRInputSource*);
+ void OnSelect(XRInputSource*);
+
+ void Trace(blink::Visitor*) override;
+ virtual void TraceWrappers(const blink::ScriptWrappableVisitor*) const;
+
+ private:
+ class XRSessionResizeObserverDelegate;
+
+ XRPresentationFrame* CreatePresentationFrame();
+ void UpdateCanvasDimensions(Element*);
+
+ void UpdateInputSourceState(
+ XRInputSource*,
+ const device::mojom::blink::XRInputSourceStatePtr&);
+ XRInputSourceEvent* CreateInputSourceEvent(const AtomicString&,
+ XRInputSource*);
+
+ void OnFocus();
+ void OnBlur();
+ bool HasAppropriateFocus();
+
+ const Member<XRDevice> device_;
+ const bool exclusive_;
+ const Member<XRPresentationContext> output_context_;
+ Member<XRLayer> base_layer_;
+ HeapVector<Member<XRView>> views_;
+ InputSourceMap input_sources_;
+ Member<ResizeObserver> resize_observer_;
+ Member<XRCanvasInputProvider> canvas_input_provider_;
+
+ XRFrameRequestCallbackCollection callback_collection_;
+ std::unique_ptr<TransformationMatrix> base_pose_matrix_;
+
+ double depth_near_ = 0.1;
+ double depth_far_ = 1000.0;
+ bool blurred_;
+ bool ended_ = false;
+ bool pending_frame_ = false;
+ bool resolving_frame_ = false;
+ bool update_views_next_frame_ = false;
+ bool views_dirty_ = true;
+
+ // Dimensions of the output canvas.
+ int output_width_ = 1;
+ int output_height_ = 1;
+};
+
+} // namespace blink
+
+#endif // XRWebGLLayer_h
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_session.idl b/chromium/third_party/blink/renderer/modules/xr/xr_session.idl
new file mode 100644
index 00000000000..7a07c8efe00
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_session.idl
@@ -0,0 +1,32 @@
+// 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://immersive-web.github.io/webxr/spec/latest/#xrsession-interface
+[
+ SecureContext,
+ OriginTrialEnabled=WebXR
+] interface XRSession : EventTarget {
+ readonly attribute XRDevice device;
+ readonly attribute boolean exclusive;
+ readonly attribute XRPresentationContext outputContext;
+
+ attribute double depthNear;
+ attribute double depthFar;
+
+ attribute XRLayer baseLayer;
+
+ attribute EventHandler onblur;
+ attribute EventHandler onfocus;
+ attribute EventHandler onresetpose;
+ attribute EventHandler onend;
+
+ [CallWith=ScriptState] Promise<XRFrameOfReference> requestFrameOfReference(XRFrameOfReferenceType type, [PermissiveDictionaryConversion] optional XRFrameOfReferenceOptions options);
+
+ long requestAnimationFrame(XRFrameRequestCallback callback);
+ void cancelAnimationFrame(long handle);
+
+ [MeasureAs=XRSessionGetInputSources] FrozenArray<XRInputSource> getInputSources();
+
+ [CallWith=ScriptState] Promise<void> end();
+};
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_session_creation_options.idl b/chromium/third_party/blink/renderer/modules/xr/xr_session_creation_options.idl
new file mode 100644
index 00000000000..960e60d3ea2
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_session_creation_options.idl
@@ -0,0 +1,11 @@
+// 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://immersive-web.github.io/webxr/spec/latest/#xrsessioncreationoptions-interface
+[
+ SecureContext
+] dictionary XRSessionCreationOptions {
+ boolean exclusive = false;
+ XRPresentationContext outputContext;
+};
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_session_event.cc b/chromium/third_party/blink/renderer/modules/xr/xr_session_event.cc
new file mode 100644
index 00000000000..bb7fdbd862e
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_session_event.cc
@@ -0,0 +1,32 @@
+// 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 "third_party/blink/renderer/modules/xr/xr_session_event.h"
+
+namespace blink {
+
+XRSessionEvent::XRSessionEvent() = default;
+
+XRSessionEvent::XRSessionEvent(const AtomicString& type, XRSession* session)
+ : Event(type, Bubbles::kNo, Cancelable::kYes), session_(session) {}
+
+XRSessionEvent::XRSessionEvent(const AtomicString& type,
+ const XRSessionEventInit& initializer)
+ : Event(type, initializer) {
+ if (initializer.hasSession())
+ session_ = initializer.session();
+}
+
+XRSessionEvent::~XRSessionEvent() = default;
+
+const AtomicString& XRSessionEvent::InterfaceName() const {
+ return EventNames::XRSessionEvent;
+}
+
+void XRSessionEvent::Trace(blink::Visitor* visitor) {
+ visitor->Trace(session_);
+ Event::Trace(visitor);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_session_event.h b/chromium/third_party/blink/renderer/modules/xr/xr_session_event.h
new file mode 100644
index 00000000000..fa99848c3e4
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_session_event.h
@@ -0,0 +1,46 @@
+// 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 THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_SESSION_EVENT_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_SESSION_EVENT_H_
+
+#include "third_party/blink/renderer/modules/event_modules.h"
+#include "third_party/blink/renderer/modules/xr/xr_session.h"
+#include "third_party/blink/renderer/modules/xr/xr_session_event_init.h"
+
+namespace blink {
+
+class XRSessionEvent final : public Event {
+ DEFINE_WRAPPERTYPEINFO();
+
+ public:
+ static XRSessionEvent* Create() { return new XRSessionEvent; }
+ static XRSessionEvent* Create(const AtomicString& type, XRSession* session) {
+ return new XRSessionEvent(type, session);
+ }
+
+ static XRSessionEvent* Create(const AtomicString& type,
+ const XRSessionEventInit& initializer) {
+ return new XRSessionEvent(type, initializer);
+ }
+
+ ~XRSessionEvent() override;
+
+ XRSession* session() const { return session_.Get(); }
+
+ const AtomicString& InterfaceName() const override;
+
+ void Trace(blink::Visitor*) override;
+
+ private:
+ XRSessionEvent();
+ XRSessionEvent(const AtomicString& type, XRSession*);
+ XRSessionEvent(const AtomicString& type, const XRSessionEventInit&);
+
+ Member<XRSession> session_;
+};
+
+} // namespace blink
+
+#endif // XRDisplayEvent_h
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_session_event.idl b/chromium/third_party/blink/renderer/modules/xr/xr_session_event.idl
new file mode 100644
index 00000000000..aa6b1d9e4a1
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_session_event.idl
@@ -0,0 +1,12 @@
+// 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://immersive-web.github.io/webxr/spec/latest/#xrsessionevent-interface
+[
+ SecureContext,
+ OriginTrialEnabled=WebXR,
+ Constructor(DOMString type, XRSessionEventInit eventInitDict)
+] interface XRSessionEvent : Event {
+ readonly attribute XRSession session;
+}; \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_session_event_init.idl b/chromium/third_party/blink/renderer/modules/xr/xr_session_event_init.idl
new file mode 100644
index 00000000000..cb2d268f844
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_session_event_init.idl
@@ -0,0 +1,10 @@
+// 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://immersive-web.github.io/webxr/spec/latest/#xrsessionevent-interface
+[
+ SecureContext
+] dictionary XRSessionEventInit : EventInit {
+ required XRSession session;
+}; \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_stage_bounds.cc b/chromium/third_party/blink/renderer/modules/xr/xr_stage_bounds.cc
new file mode 100644
index 00000000000..a85149eb32b
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_stage_bounds.cc
@@ -0,0 +1,14 @@
+// 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 "third_party/blink/renderer/modules/xr/xr_stage_bounds.h"
+
+namespace blink {
+
+void XRStageBounds::Trace(blink::Visitor* visitor) {
+ visitor->Trace(geometry_);
+ ScriptWrappable::Trace(visitor);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_stage_bounds.h b/chromium/third_party/blink/renderer/modules/xr/xr_stage_bounds.h
new file mode 100644
index 00000000000..0250f810766
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_stage_bounds.h
@@ -0,0 +1,31 @@
+// 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 THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_STAGE_BOUNDS_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_STAGE_BOUNDS_H_
+
+#include "third_party/blink/renderer/modules/xr/xr_stage_bounds_point.h"
+#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
+#include "third_party/blink/renderer/platform/heap/handle.h"
+#include "third_party/blink/renderer/platform/wtf/forward.h"
+
+namespace blink {
+
+class XRStageBounds final : public ScriptWrappable {
+ DEFINE_WRAPPERTYPEINFO();
+
+ public:
+ XRStageBounds() = default;
+
+ HeapVector<Member<XRStageBoundsPoint>> geometry() const { return geometry_; }
+
+ virtual void Trace(blink::Visitor*);
+
+ private:
+ HeapVector<Member<XRStageBoundsPoint>> geometry_;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_STAGE_BOUNDS_H_
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_stage_bounds.idl b/chromium/third_party/blink/renderer/modules/xr/xr_stage_bounds.idl
new file mode 100644
index 00000000000..e924eea3ffa
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_stage_bounds.idl
@@ -0,0 +1,11 @@
+// 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://immersive-web.github.io/webxr/spec/latest/#xrstagebounds-interface
+[
+ SecureContext,
+ OriginTrialEnabled=WebXR
+] interface XRStageBounds {
+ readonly attribute FrozenArray<XRStageBoundsPoint> geometry;
+};
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_stage_bounds_point.h b/chromium/third_party/blink/renderer/modules/xr/xr_stage_bounds_point.h
new file mode 100644
index 00000000000..a29055b11b4
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_stage_bounds_point.h
@@ -0,0 +1,30 @@
+// 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 THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_STAGE_BOUNDS_POINT_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_STAGE_BOUNDS_POINT_H_
+
+#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
+#include "third_party/blink/renderer/platform/heap/handle.h"
+#include "third_party/blink/renderer/platform/wtf/forward.h"
+
+namespace blink {
+
+class XRStageBoundsPoint final : public ScriptWrappable {
+ DEFINE_WRAPPERTYPEINFO();
+
+ public:
+ XRStageBoundsPoint(double x, double z) : x_(x), z_(z) {}
+
+ double x() const { return x_; }
+ double z() const { return z_; }
+
+ private:
+ double x_;
+ double z_;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_STAGE_BOUNDS_POINT_H_
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_stage_bounds_point.idl b/chromium/third_party/blink/renderer/modules/xr/xr_stage_bounds_point.idl
new file mode 100644
index 00000000000..96c169e3f88
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_stage_bounds_point.idl
@@ -0,0 +1,12 @@
+// 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://immersive-web.github.io/webxr/spec/latest/#xrstageboundspoint-interface
+[
+ SecureContext,
+ OriginTrialEnabled=WebXR
+] interface XRStageBoundsPoint {
+ readonly attribute double x;
+ readonly attribute double z;
+};
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_utils.cc b/chromium/third_party/blink/renderer/modules/xr/xr_utils.cc
new file mode 100644
index 00000000000..34ef2243b7d
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_utils.cc
@@ -0,0 +1,24 @@
+// Copyright 2018 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 "third_party/blink/renderer/modules/xr/xr_utils.h"
+
+namespace blink {
+
+DOMFloat32Array* transformationMatrixToFloat32Array(
+ const TransformationMatrix& matrix) {
+ float array[] = {
+ static_cast<float>(matrix.M11()), static_cast<float>(matrix.M12()),
+ static_cast<float>(matrix.M13()), static_cast<float>(matrix.M14()),
+ static_cast<float>(matrix.M21()), static_cast<float>(matrix.M22()),
+ static_cast<float>(matrix.M23()), static_cast<float>(matrix.M24()),
+ static_cast<float>(matrix.M31()), static_cast<float>(matrix.M32()),
+ static_cast<float>(matrix.M33()), static_cast<float>(matrix.M34()),
+ static_cast<float>(matrix.M41()), static_cast<float>(matrix.M42()),
+ static_cast<float>(matrix.M43()), static_cast<float>(matrix.M44())};
+
+ return DOMFloat32Array::Create(array, 16);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_utils.h b/chromium/third_party/blink/renderer/modules/xr/xr_utils.h
new file mode 100644
index 00000000000..d484e5bc914
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_utils.h
@@ -0,0 +1,18 @@
+// Copyright 2018 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 THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_UTILS_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_UTILS_H_
+
+#include "third_party/blink/renderer/core/typed_arrays/dom_typed_array.h"
+#include "third_party/blink/renderer/platform/transforms/transformation_matrix.h"
+
+namespace blink {
+
+DOMFloat32Array* transformationMatrixToFloat32Array(
+ const TransformationMatrix&);
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_UTILS_H_
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_view.cc b/chromium/third_party/blink/renderer/modules/xr/xr_view.cc
new file mode 100644
index 00000000000..6880f24d07f
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_view.cc
@@ -0,0 +1,151 @@
+// 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 "third_party/blink/renderer/modules/xr/xr_view.h"
+
+#include "third_party/blink/renderer/modules/xr/xr_presentation_frame.h"
+#include "third_party/blink/renderer/modules/xr/xr_session.h"
+#include "third_party/blink/renderer/platform/geometry/float_point_3d.h"
+
+namespace blink {
+
+XRView::XRView(XRSession* session, Eye eye)
+ : eye_(eye),
+ session_(session),
+ projection_matrix_(DOMFloat32Array::Create(16)) {
+ eye_string_ = (eye_ == kEyeLeft ? "left" : "right");
+}
+
+XRSession* XRView::session() const {
+ return session_;
+}
+
+void XRView::UpdateProjectionMatrixFromFoV(float up_rad,
+ float down_rad,
+ float left_rad,
+ float right_rad,
+ float near_depth,
+ float far_depth) {
+ float up_tan = tanf(up_rad);
+ float down_tan = tanf(down_rad);
+ float left_tan = tanf(left_rad);
+ float right_tan = tanf(right_rad);
+ float x_scale = 2.0f / (left_tan + right_tan);
+ float y_scale = 2.0f / (up_tan + down_tan);
+ float inv_nf = 1.0f / (near_depth - far_depth);
+
+ float* out = projection_matrix_->Data();
+ out[0] = x_scale;
+ out[1] = 0.0f;
+ out[2] = 0.0f;
+ out[3] = 0.0f;
+ out[4] = 0.0f;
+ out[5] = y_scale;
+ out[6] = 0.0f;
+ out[7] = 0.0f;
+ out[8] = -((left_tan - right_tan) * x_scale * 0.5);
+ out[9] = ((up_tan - down_tan) * y_scale * 0.5);
+ out[10] = (near_depth + far_depth) * inv_nf;
+ out[11] = -1.0f;
+ out[12] = 0.0f;
+ out[13] = 0.0f;
+ out[14] = (2.0f * far_depth * near_depth) * inv_nf;
+ out[15] = 0.0f;
+
+ inv_projection_dirty_ = true;
+}
+
+void XRView::UpdateProjectionMatrixFromAspect(float fovy,
+ float aspect,
+ float near_depth,
+ float far_depth) {
+ float f = 1.0f / tanf(fovy / 2);
+ float inv_nf = 1.0f / (near_depth - far_depth);
+
+ float* out = projection_matrix_->Data();
+ out[0] = f / aspect;
+ out[1] = 0.0f;
+ out[2] = 0.0f;
+ out[3] = 0.0f;
+ out[4] = 0.0f;
+ out[5] = f;
+ out[6] = 0.0f;
+ out[7] = 0.0f;
+ out[8] = 0.0f;
+ out[9] = 0.0f;
+ out[10] = (far_depth + near_depth) * inv_nf;
+ out[11] = -1.0f;
+ out[12] = 0.0f;
+ out[13] = 0.0f;
+ out[14] = (2.0f * far_depth * near_depth) * inv_nf;
+ out[15] = 0.0f;
+
+ inv_projection_dirty_ = true;
+}
+
+void XRView::UpdateOffset(float x, float y, float z) {
+ offset_.Set(x, y, z);
+}
+
+std::unique_ptr<TransformationMatrix> XRView::UnprojectPointer(
+ double x,
+ double y,
+ double canvas_width,
+ double canvas_height) {
+ // Recompute the inverse projection matrix if needed.
+ if (inv_projection_dirty_) {
+ float* m = projection_matrix_->Data();
+ std::unique_ptr<TransformationMatrix> projection =
+ TransformationMatrix::Create(m[0], m[1], m[2], m[3], m[4], m[5], m[6],
+ m[7], m[8], m[9], m[10], m[11], m[12],
+ m[13], m[14], m[15]);
+ inv_projection_ = TransformationMatrix::Create(projection->Inverse());
+ inv_projection_dirty_ = false;
+ }
+
+ // Transform the x/y coordinate into WebGL normalized device coordinates.
+ // Z coordinate of -1 means the point will be projected onto the projection
+ // matrix near plane.
+ FloatPoint3D point_in_projection_space(
+ x / canvas_width * 2.0 - 1.0,
+ (canvas_height - y) / canvas_height * 2.0 - 1.0, -1.0);
+
+ FloatPoint3D point_in_view_space =
+ inv_projection_->MapPoint(point_in_projection_space);
+
+ const FloatPoint3D kOrigin(0.0, 0.0, 0.0);
+ const FloatPoint3D kUp(0.0, 1.0, 0.0);
+
+ // Generate a "Look At" matrix
+ FloatPoint3D z_axis = kOrigin - point_in_view_space;
+ z_axis.Normalize();
+
+ FloatPoint3D x_axis = kUp.Cross(z_axis);
+ x_axis.Normalize();
+
+ FloatPoint3D y_axis = z_axis.Cross(x_axis);
+ y_axis.Normalize();
+
+ // TODO(bajones): There's probably a more efficent way to do this?
+ TransformationMatrix inv_pointer(x_axis.X(), y_axis.X(), z_axis.X(), 0.0,
+ x_axis.Y(), y_axis.Y(), z_axis.Y(), 0.0,
+ x_axis.Z(), y_axis.Z(), z_axis.Z(), 0.0, 0.0,
+ 0.0, 0.0, 1.0);
+ inv_pointer.Translate3d(-point_in_view_space.X(), -point_in_view_space.Y(),
+ -point_in_view_space.Z());
+
+ // LookAt matrices are view matrices (inverted), so invert before returning.
+ std::unique_ptr<TransformationMatrix> pointer =
+ TransformationMatrix::Create(inv_pointer.Inverse());
+
+ return pointer;
+}
+
+void XRView::Trace(blink::Visitor* visitor) {
+ visitor->Trace(session_);
+ visitor->Trace(projection_matrix_);
+ ScriptWrappable::Trace(visitor);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_view.h b/chromium/third_party/blink/renderer/modules/xr/xr_view.h
new file mode 100644
index 00000000000..93b51598d62
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_view.h
@@ -0,0 +1,69 @@
+// 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 THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_VIEW_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_VIEW_H_
+
+#include "third_party/blink/renderer/core/typed_arrays/dom_typed_array.h"
+#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
+#include "third_party/blink/renderer/platform/geometry/float_point_3d.h"
+#include "third_party/blink/renderer/platform/heap/handle.h"
+#include "third_party/blink/renderer/platform/transforms/transformation_matrix.h"
+#include "third_party/blink/renderer/platform/wtf/forward.h"
+#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
+
+namespace blink {
+
+class XRSession;
+
+class XRView final : public ScriptWrappable {
+ DEFINE_WRAPPERTYPEINFO();
+
+ public:
+ enum Eye { kEyeLeft = 0, kEyeRight = 1 };
+
+ XRView(XRSession*, Eye);
+
+ const String& eye() const { return eye_string_; }
+ Eye EyeValue() const { return eye_; }
+
+ XRSession* session() const;
+ DOMFloat32Array* projectionMatrix() const { return projection_matrix_; }
+
+ void UpdateProjectionMatrixFromFoV(float up_rad,
+ float down_rad,
+ float left_rad,
+ float right_rad,
+ float near_depth,
+ float far_depth);
+
+ void UpdateProjectionMatrixFromAspect(float fovy,
+ float aspect,
+ float near_depth,
+ float far_depth);
+
+ std::unique_ptr<TransformationMatrix> UnprojectPointer(double x,
+ double y,
+ double canvas_width,
+ double canvas_height);
+
+ // TODO(bajones): Should eventually represent this as a full transform.
+ const FloatPoint3D& offset() const { return offset_; }
+ void UpdateOffset(float x, float y, float z);
+
+ virtual void Trace(blink::Visitor*);
+
+ private:
+ const Eye eye_;
+ String eye_string_;
+ Member<XRSession> session_;
+ Member<DOMFloat32Array> projection_matrix_;
+ FloatPoint3D offset_;
+ std::unique_ptr<TransformationMatrix> inv_projection_;
+ bool inv_projection_dirty_ = true;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_VIEW_H_
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_view.idl b/chromium/third_party/blink/renderer/modules/xr/xr_view.idl
new file mode 100644
index 00000000000..6a5f325c6b6
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_view.idl
@@ -0,0 +1,12 @@
+// 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://immersive-web.github.io/webxr/spec/latest/#xrview-interface
+[
+ SecureContext,
+ OriginTrialEnabled=WebXR
+] interface XRView {
+ readonly attribute VREye? eye;
+ readonly attribute Float32Array projectionMatrix;
+};
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_viewport.h b/chromium/third_party/blink/renderer/modules/xr/xr_viewport.h
new file mode 100644
index 00000000000..aa5ff93041b
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_viewport.h
@@ -0,0 +1,35 @@
+// 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 THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_VIEWPORT_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_VIEWPORT_H_
+
+#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
+#include "third_party/blink/renderer/platform/heap/handle.h"
+#include "third_party/blink/renderer/platform/wtf/forward.h"
+
+namespace blink {
+
+class XRViewport final : public ScriptWrappable {
+ DEFINE_WRAPPERTYPEINFO();
+
+ public:
+ XRViewport(int x, int y, int width, int height)
+ : x_(x), y_(y), width_(width), height_(height) {}
+
+ int x() const { return x_; }
+ int y() const { return y_; }
+ int width() const { return width_; }
+ int height() const { return height_; }
+
+ private:
+ int x_;
+ int y_;
+ int width_;
+ int height_;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_VIEWPORT_H_
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_viewport.idl b/chromium/third_party/blink/renderer/modules/xr/xr_viewport.idl
new file mode 100644
index 00000000000..6ce2abdae15
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_viewport.idl
@@ -0,0 +1,14 @@
+// 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://immersive-web.github.io/webxr/spec/latest/#xrviewport-interface
+[
+ SecureContext,
+ OriginTrialEnabled=WebXR
+] interface XRViewport {
+ readonly attribute long x;
+ readonly attribute long y;
+ readonly attribute long width;
+ readonly attribute long height;
+};
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_webgl_layer.cc b/chromium/third_party/blink/renderer/modules/xr/xr_webgl_layer.cc
new file mode 100644
index 00000000000..84b1201ccc2
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_webgl_layer.cc
@@ -0,0 +1,335 @@
+// 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 "third_party/blink/renderer/modules/xr/xr_webgl_layer.h"
+
+#include "third_party/blink/renderer/bindings/core/v8/exception_messages.h"
+#include "third_party/blink/renderer/bindings/core/v8/exception_state.h"
+#include "third_party/blink/renderer/core/imagebitmap/image_bitmap.h"
+#include "third_party/blink/renderer/modules/webgl/webgl2_rendering_context.h"
+#include "third_party/blink/renderer/modules/webgl/webgl_framebuffer.h"
+#include "third_party/blink/renderer/modules/webgl/webgl_rendering_context.h"
+#include "third_party/blink/renderer/modules/xr/xr_device.h"
+#include "third_party/blink/renderer/modules/xr/xr_frame_provider.h"
+#include "third_party/blink/renderer/modules/xr/xr_presentation_context.h"
+#include "third_party/blink/renderer/modules/xr/xr_session.h"
+#include "third_party/blink/renderer/modules/xr/xr_view.h"
+#include "third_party/blink/renderer/modules/xr/xr_viewport.h"
+#include "third_party/blink/renderer/platform/geometry/double_size.h"
+#include "third_party/blink/renderer/platform/geometry/float_point.h"
+#include "third_party/blink/renderer/platform/geometry/int_size.h"
+
+namespace blink {
+
+namespace {
+
+const double kFramebufferMinScale = 0.2;
+const double kFramebufferMaxScale = 1.0;
+
+const double kViewportMinScale = 0.2;
+const double kViewportMaxScale = 1.0;
+
+// Because including base::ClampToRange would be a dependency violation
+double ClampToRange(const double value, const double min, const double max) {
+ return std::min(std::max(value, min), max);
+}
+
+} // namespace
+
+XRWebGLLayer* XRWebGLLayer::Create(
+ XRSession* session,
+ const WebGLRenderingContextOrWebGL2RenderingContext& context,
+ const XRWebGLLayerInit& initializer,
+ ExceptionState& exception_state) {
+ if (session->ended()) {
+ exception_state.ThrowDOMException(kInvalidStateError,
+ "Cannot create an XRWebGLLayer for an "
+ "XRSession which has already ended.");
+ return nullptr;
+ }
+
+ WebGLRenderingContextBase* webgl_context;
+ if (context.IsWebGL2RenderingContext()) {
+ webgl_context = context.GetAsWebGL2RenderingContext();
+ } else {
+ webgl_context = context.GetAsWebGLRenderingContext();
+ }
+
+ if (webgl_context->isContextLost()) {
+ exception_state.ThrowDOMException(kInvalidStateError,
+ "Cannot create an XRWebGLLayer with a "
+ "lost WebGL context.");
+ return nullptr;
+ }
+
+ if (!webgl_context->IsXRDeviceCompatible(session->device())) {
+ exception_state.ThrowDOMException(
+ kInvalidStateError,
+ "The session's device is not the compatible device for this context.");
+ return nullptr;
+ }
+
+ bool want_antialiasing = initializer.antialias();
+ bool want_depth_buffer = initializer.depth();
+ bool want_stencil_buffer = initializer.stencil();
+ bool want_alpha_channel = initializer.alpha();
+ bool want_multiview = initializer.multiview();
+
+ double framebuffer_scale = session->DefaultFramebufferScale();
+
+ if (initializer.hasFramebufferScaleFactor() &&
+ initializer.framebufferScaleFactor() != 0.0) {
+ // Clamp the developer-requested framebuffer size to ensure it's not too
+ // small to see or unreasonably large.
+ framebuffer_scale =
+ ClampToRange(initializer.framebufferScaleFactor(), kFramebufferMinScale,
+ kFramebufferMaxScale);
+ }
+
+ DoubleSize framebuffers_size = session->IdealFramebufferSize();
+
+ IntSize desired_size(framebuffers_size.Width() * framebuffer_scale,
+ framebuffers_size.Height() * framebuffer_scale);
+
+ // Create an opaque WebGL Framebuffer
+ WebGLFramebuffer* framebuffer = WebGLFramebuffer::CreateOpaque(webgl_context);
+
+ scoped_refptr<XRWebGLDrawingBuffer> drawing_buffer =
+ XRWebGLDrawingBuffer::Create(
+ webgl_context->GetDrawingBuffer(), framebuffer->Object(),
+ desired_size, want_alpha_channel, want_depth_buffer,
+ want_stencil_buffer, want_antialiasing, want_multiview);
+
+ if (!drawing_buffer) {
+ exception_state.ThrowDOMException(kOperationError,
+ "Unable to create a framebuffer.");
+ return nullptr;
+ }
+
+ return new XRWebGLLayer(session, webgl_context, std::move(drawing_buffer),
+ framebuffer, framebuffer_scale);
+}
+
+XRWebGLLayer::XRWebGLLayer(XRSession* session,
+ WebGLRenderingContextBase* webgl_context,
+ scoped_refptr<XRWebGLDrawingBuffer> drawing_buffer,
+ WebGLFramebuffer* framebuffer,
+ double framebuffer_scale)
+ : XRLayer(session, kXRWebGLLayerType),
+ webgl_context_(webgl_context),
+ drawing_buffer_(drawing_buffer),
+ framebuffer_(framebuffer),
+ framebuffer_scale_(framebuffer_scale) {
+ DCHECK(drawing_buffer);
+ // If the contents need mirroring, indicate that to the drawing buffer.
+ if (session->exclusive() && session->outputContext() &&
+ session->device()->external()) {
+ mirroring_ = true;
+ drawing_buffer_->SetMirrorClient(this);
+ }
+ UpdateViewports();
+}
+
+XRWebGLLayer::~XRWebGLLayer() {
+ if (mirroring_)
+ drawing_buffer_->SetMirrorClient(nullptr);
+}
+
+void XRWebGLLayer::getXRWebGLRenderingContext(
+ WebGLRenderingContextOrWebGL2RenderingContext& result) const {
+ if (webgl_context_->Version() == 2) {
+ result.SetWebGL2RenderingContext(
+ static_cast<WebGL2RenderingContext*>(webgl_context_.Get()));
+ } else {
+ result.SetWebGLRenderingContext(
+ static_cast<WebGLRenderingContext*>(webgl_context_.Get()));
+ }
+}
+
+XRViewport* XRWebGLLayer::getViewport(XRView* view) {
+ if (!view || view->session() != session())
+ return nullptr;
+
+ return GetViewportForEye(view->EyeValue());
+}
+
+XRViewport* XRWebGLLayer::GetViewportForEye(XRView::Eye eye) {
+ if (viewports_dirty_)
+ UpdateViewports();
+
+ if (eye == XRView::kEyeLeft)
+ return left_viewport_;
+
+ return right_viewport_;
+}
+
+void XRWebGLLayer::requestViewportScaling(double scale_factor) {
+ if (!session()->exclusive()) {
+ // TODO(bajones): For the moment we're just going to ignore viewport changes
+ // in non-exclusive mode. This is legal, but probably not what developers
+ // would like to see. Look into making viewport scale apply properly.
+ scale_factor = 1.0;
+ } else {
+ // Clamp the developer-requested viewport size to ensure it's not too
+ // small to see or larger than the framebuffer.
+ scale_factor =
+ ClampToRange(scale_factor, kViewportMinScale, kViewportMaxScale);
+ }
+
+ // Don't set this as the viewport_scale_ directly, since that would allow the
+ // viewports to change mid-frame.
+ requested_viewport_scale_ = scale_factor;
+}
+
+void XRWebGLLayer::UpdateViewports() {
+ long framebuffer_width = framebufferWidth();
+ long framebuffer_height = framebufferHeight();
+
+ viewports_dirty_ = false;
+
+ if (session()->exclusive()) {
+ left_viewport_ =
+ new XRViewport(0, 0, framebuffer_width * 0.5 * viewport_scale_,
+ framebuffer_height * viewport_scale_);
+ right_viewport_ =
+ new XRViewport(framebuffer_width * 0.5 * viewport_scale_, 0,
+ framebuffer_width * 0.5 * viewport_scale_,
+ framebuffer_height * viewport_scale_);
+
+ session()->device()->frameProvider()->UpdateWebGLLayerViewports(this);
+
+ // When mirroring make sure to also update the mirrored canvas UVs so it
+ // only shows a single eye's data, cropped to display proportionally.
+ if (session()->outputContext()) {
+ float left = 0;
+ float top = 0;
+ float right = static_cast<float>(left_viewport_->width()) /
+ static_cast<float>(framebuffer_width);
+ float bottom = static_cast<float>(left_viewport_->height()) /
+ static_cast<float>(framebuffer_height);
+
+ // Adjust the UVs so that the mirrored content always fills the canvas
+ // and is centered while staying proportional.
+ DoubleSize output_size = session()->OutputCanvasSize();
+ double output_aspect = output_size.Width() / output_size.Height();
+ double viewport_aspect = static_cast<float>(left_viewport_->width()) /
+ static_cast<float>(left_viewport_->height());
+
+ if (output_aspect > viewport_aspect) {
+ float viewport_scale = bottom;
+ output_aspect = viewport_aspect / output_aspect;
+ top = 0.5 - (output_aspect * 0.5);
+ bottom = top + output_aspect;
+ top *= viewport_scale;
+ bottom *= viewport_scale;
+ } else {
+ float viewport_scale = right;
+ output_aspect = output_aspect / viewport_aspect;
+ left = 0.5 - (output_aspect * 0.5);
+ right = left + output_aspect;
+ left *= viewport_scale;
+ right *= viewport_scale;
+ }
+
+ session()->outputContext()->SetUV(FloatPoint(left, top),
+ FloatPoint(right, bottom));
+ }
+ } else {
+ left_viewport_ = new XRViewport(0, 0, framebuffer_width * viewport_scale_,
+ framebuffer_height * viewport_scale_);
+ }
+}
+
+void XRWebGLLayer::OnFrameStart(
+ const base::Optional<gpu::MailboxHolder>& buffer_mailbox_holder) {
+ // If the requested scale has changed since the last from, update it now.
+ if (viewport_scale_ != requested_viewport_scale_) {
+ viewport_scale_ = requested_viewport_scale_;
+ viewports_dirty_ = true;
+ }
+
+ framebuffer_->MarkOpaqueBufferComplete(true);
+ framebuffer_->SetContentsChanged(false);
+ if (buffer_mailbox_holder) {
+ drawing_buffer_->UseSharedBuffer(buffer_mailbox_holder.value());
+ is_direct_draw_frame = true;
+ } else {
+ is_direct_draw_frame = false;
+ }
+}
+
+void XRWebGLLayer::OnFrameEnd() {
+ framebuffer_->MarkOpaqueBufferComplete(false);
+ if (is_direct_draw_frame) {
+ drawing_buffer_->DoneWithSharedBuffer();
+ is_direct_draw_frame = false;
+ }
+
+ // Submit the frame to the XR compositor.
+ if (session()->exclusive()) {
+ // Always call submit, but notify if the contents were changed or not.
+ session()->device()->frameProvider()->SubmitWebGLLayer(
+ this, framebuffer_->HaveContentsChanged());
+ } else if (session()->outputContext()) {
+ // Nothing to do if the framebuffer contents have not changed.
+ if (framebuffer_->HaveContentsChanged()) {
+ ImageBitmap* image_bitmap =
+ ImageBitmap::Create(TransferToStaticBitmapImage(nullptr));
+ session()->outputContext()->SetImage(image_bitmap);
+ }
+ }
+}
+
+void XRWebGLLayer::OnResize() {
+ if (!session()->exclusive()) {
+ // For non-exclusive sessions a resize indicates we should adjust the
+ // drawing buffer size to match the canvas.
+ DoubleSize framebuffers_size = session()->IdealFramebufferSize();
+
+ IntSize desired_size(framebuffers_size.Width() * framebuffer_scale_,
+ framebuffers_size.Height() * framebuffer_scale_);
+ drawing_buffer_->Resize(desired_size);
+ }
+
+ // With both exclusive and non-exclusive session the viewports should be
+ // recomputed when the output canvas resizes.
+ viewports_dirty_ = true;
+}
+
+scoped_refptr<StaticBitmapImage> XRWebGLLayer::TransferToStaticBitmapImage(
+ std::unique_ptr<viz::SingleReleaseCallback>* out_release_callback) {
+ return drawing_buffer_->TransferToStaticBitmapImage(out_release_callback);
+}
+
+void XRWebGLLayer::OnMirrorImageAvailable(
+ scoped_refptr<StaticBitmapImage> image,
+ std::unique_ptr<viz::SingleReleaseCallback> release_callback) {
+ ImageBitmap* image_bitmap = ImageBitmap::Create(std::move(image));
+
+ session()->outputContext()->SetImage(image_bitmap);
+
+ if (mirror_release_callback_) {
+ // TODO(bajones): We should probably have the compositor report to us when
+ // it's done with the image, rather than reporting back that it's usable as
+ // soon as we receive a new one.
+ mirror_release_callback_->Run(gpu::SyncToken(), false /* lost_resource */);
+ }
+
+ mirror_release_callback_ = std::move(release_callback);
+}
+
+void XRWebGLLayer::Trace(blink::Visitor* visitor) {
+ visitor->Trace(left_viewport_);
+ visitor->Trace(right_viewport_);
+ visitor->Trace(webgl_context_);
+ visitor->Trace(framebuffer_);
+ XRLayer::Trace(visitor);
+}
+
+void XRWebGLLayer::TraceWrappers(const ScriptWrappableVisitor* visitor) const {
+ visitor->TraceWrappers(webgl_context_);
+ XRLayer::TraceWrappers(visitor);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_webgl_layer.h b/chromium/third_party/blink/renderer/modules/xr/xr_webgl_layer.h
new file mode 100644
index 00000000000..862cdbb7981
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_webgl_layer.h
@@ -0,0 +1,108 @@
+// 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 THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_WEBGL_LAYER_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_WEBGL_LAYER_H_
+
+#include "third_party/blink/renderer/bindings/modules/v8/webgl_rendering_context_or_webgl2_rendering_context.h"
+#include "third_party/blink/renderer/modules/webgl/webgl2_rendering_context.h"
+#include "third_party/blink/renderer/modules/webgl/webgl_rendering_context.h"
+#include "third_party/blink/renderer/modules/xr/xr_layer.h"
+#include "third_party/blink/renderer/modules/xr/xr_view.h"
+#include "third_party/blink/renderer/modules/xr/xr_webgl_layer_init.h"
+#include "third_party/blink/renderer/platform/graphics/gpu/xr_webgl_drawing_buffer.h"
+#include "third_party/blink/renderer/platform/wtf/ref_counted.h"
+
+namespace viz {
+class SingleReleaseCallback;
+}
+
+namespace blink {
+
+class ExceptionState;
+class WebGLFramebuffer;
+class WebGLRenderingContextBase;
+class XRSession;
+class XRViewport;
+
+class XRWebGLLayer final : public XRLayer,
+ public XRWebGLDrawingBuffer::MirrorClient {
+ DEFINE_WRAPPERTYPEINFO();
+
+ public:
+ virtual ~XRWebGLLayer();
+
+ static XRWebGLLayer* Create(
+ XRSession*,
+ const WebGLRenderingContextOrWebGL2RenderingContext&,
+ const XRWebGLLayerInit&,
+ ExceptionState&);
+
+ WebGLRenderingContextBase* context() const { return webgl_context_; }
+ void getXRWebGLRenderingContext(
+ WebGLRenderingContextOrWebGL2RenderingContext&) const;
+
+ WebGLFramebuffer* framebuffer() const { return framebuffer_; }
+ unsigned long framebufferWidth() const {
+ return drawing_buffer_->size().Width();
+ }
+ unsigned long framebufferHeight() const {
+ return drawing_buffer_->size().Height();
+ }
+
+ bool antialias() const { return drawing_buffer_->antialias(); }
+ bool depth() const { return drawing_buffer_->depth(); }
+ bool stencil() const { return drawing_buffer_->stencil(); }
+ bool alpha() const { return drawing_buffer_->alpha(); }
+ bool multiview() const { return drawing_buffer_->multiview(); }
+
+ XRViewport* getViewport(XRView*);
+ void requestViewportScaling(double scale_factor);
+
+ XRViewport* GetViewportForEye(XRView::Eye);
+
+ void UpdateViewports();
+
+ void OnFrameStart(const base::Optional<gpu::MailboxHolder>&) override;
+ void OnFrameEnd() override;
+ void OnResize() override;
+
+ scoped_refptr<StaticBitmapImage> TransferToStaticBitmapImage(
+ std::unique_ptr<viz::SingleReleaseCallback>* out_release_callback);
+
+ // XRWebGLDrawingBuffer::MirrorClient impementation
+ void OnMirrorImageAvailable(
+ scoped_refptr<StaticBitmapImage>,
+ std::unique_ptr<viz::SingleReleaseCallback>) override;
+
+ virtual void Trace(blink::Visitor*);
+ virtual void TraceWrappers(const ScriptWrappableVisitor*) const;
+
+ private:
+ XRWebGLLayer(XRSession*,
+ WebGLRenderingContextBase*,
+ scoped_refptr<XRWebGLDrawingBuffer>,
+ WebGLFramebuffer*,
+ double framebuffer_scale);
+
+ Member<XRViewport> left_viewport_;
+ Member<XRViewport> right_viewport_;
+
+ TraceWrapperMember<WebGLRenderingContextBase> webgl_context_;
+ scoped_refptr<XRWebGLDrawingBuffer> drawing_buffer_;
+ Member<WebGLFramebuffer> framebuffer_;
+
+ std::unique_ptr<viz::SingleReleaseCallback> mirror_release_callback_;
+
+ double framebuffer_scale_ = 1.0;
+ double requested_viewport_scale_ = 1.0;
+ double viewport_scale_ = 1.0;
+ bool viewports_dirty_ = true;
+ bool mirroring_ = false;
+ bool is_direct_draw_frame = false;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_WEBGL_LAYER_H_
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_webgl_layer.idl b/chromium/third_party/blink/renderer/modules/xr/xr_webgl_layer.idl
new file mode 100644
index 00000000000..18a9ef9576a
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_webgl_layer.idl
@@ -0,0 +1,27 @@
+// 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.
+
+typedef (WebGLRenderingContext or WebGL2RenderingContext) XRWebGLRenderingContext;
+
+// https://immersive-web.github.io/webxr/spec/latest/#xrwebgllayer-interface
+[
+ SecureContext,
+ OriginTrialEnabled=WebXR,
+ Constructor(XRSession session, XRWebGLRenderingContext context, optional XRWebGLLayerInit layerInit),
+ RaisesException=Constructor
+] interface XRWebGLLayer : XRLayer {
+ [ImplementedAs=getXRWebGLRenderingContext] readonly attribute XRWebGLRenderingContext context;
+ readonly attribute boolean antialias;
+ readonly attribute boolean depth;
+ readonly attribute boolean stencil;
+ readonly attribute boolean alpha;
+ readonly attribute boolean multiview;
+
+ readonly attribute unsigned long framebufferWidth;
+ readonly attribute unsigned long framebufferHeight;
+ readonly attribute WebGLFramebuffer framebuffer;
+
+ XRViewport? getViewport(XRView view);
+ void requestViewportScaling(double viewportScaleFactor);
+};
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_webgl_layer_init.idl b/chromium/third_party/blink/renderer/modules/xr/xr_webgl_layer_init.idl
new file mode 100644
index 00000000000..0071cc51571
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_webgl_layer_init.idl
@@ -0,0 +1,15 @@
+// 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://immersive-web.github.io/webxr/spec/latest/#xrwebgllayerinit-dictionary
+[
+ SecureContext
+] dictionary XRWebGLLayerInit {
+ boolean antialias = true;
+ boolean depth = true;
+ boolean stencil = false;
+ boolean alpha = true;
+ boolean multiview = false;
+ double framebufferScaleFactor;
+};