diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2020-07-16 11:45:35 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2020-07-17 08:59:23 +0000 |
commit | 552906b0f222c5d5dd11b9fd73829d510980461a (patch) | |
tree | 3a11e6ed0538a81dd83b20cf3a4783e297f26d91 /chromium/third_party/blink/renderer/modules/xr | |
parent | 1b05827804eaf047779b597718c03e7d38344261 (diff) | |
download | qtwebengine-chromium-552906b0f222c5d5dd11b9fd73829d510980461a.tar.gz |
BASELINE: Update Chromium to 83.0.4103.122
Change-Id: Ie3a82f5bb0076eec2a7c6a6162326b4301ee291e
Reviewed-by: Michael BrĂ¼ning <michael.bruning@qt.io>
Diffstat (limited to 'chromium/third_party/blink/renderer/modules/xr')
131 files changed, 2772 insertions, 1278 deletions
diff --git a/chromium/third_party/blink/renderer/modules/xr/BUILD.gn b/chromium/third_party/blink/renderer/modules/xr/BUILD.gn index 2559761839d..2bae19df8ad 100644 --- a/chromium/third_party/blink/renderer/modules/xr/BUILD.gn +++ b/chromium/third_party/blink/renderer/modules/xr/BUILD.gn @@ -6,12 +6,11 @@ import("//third_party/blink/renderer/modules/modules.gni") blink_modules_sources("xr") { sources = [ + "element_xr.h", "navigator_xr.cc", "navigator_xr.h", "type_converters.cc", "type_converters.h", - "xr.cc", - "xr.h", "xr_anchor.cc", "xr_anchor.h", "xr_anchor_set.cc", @@ -20,6 +19,10 @@ blink_modules_sources("xr") { "xr_bounded_reference_space.h", "xr_canvas_input_provider.cc", "xr_canvas_input_provider.h", + "xr_cube_map.cc", + "xr_cube_map.h", + "xr_dom_overlay_state.cc", + "xr_dom_overlay_state.h", "xr_frame.cc", "xr_frame.h", "xr_frame_provider.cc", @@ -28,8 +31,6 @@ blink_modules_sources("xr") { "xr_frame_request_callback_collection.h", "xr_grip_space.cc", "xr_grip_space.h", - "xr_hit_result.cc", - "xr_hit_result.h", "xr_hit_test_result.cc", "xr_hit_test_result.h", "xr_hit_test_source.cc", @@ -42,6 +43,12 @@ blink_modules_sources("xr") { "xr_input_source_event.h", "xr_input_sources_change_event.cc", "xr_input_sources_change_event.h", + "xr_light_estimation.cc", + "xr_light_estimation.h", + "xr_light_estimation_state.cc", + "xr_light_estimation_state.h", + "xr_light_probe.cc", + "xr_light_probe.h", "xr_native_origin_information.cc", "xr_native_origin_information.h", "xr_object_space.h", @@ -59,6 +66,8 @@ blink_modules_sources("xr") { "xr_reference_space.h", "xr_reference_space_event.cc", "xr_reference_space_event.h", + "xr_reflection_probe.cc", + "xr_reflection_probe.h", "xr_render_state.cc", "xr_render_state.h", "xr_rigid_transform.cc", @@ -70,6 +79,10 @@ blink_modules_sources("xr") { "xr_setlike.h", "xr_space.cc", "xr_space.h", + "xr_spherical_harmonics.cc", + "xr_spherical_harmonics.h", + "xr_system.cc", + "xr_system.h", "xr_target_ray_space.cc", "xr_target_ray_space.h", "xr_transient_input_hit_test_result.cc", diff --git a/chromium/third_party/blink/renderer/modules/xr/DEPS b/chromium/third_party/blink/renderer/modules/xr/DEPS index ab8648248ac..59d1139c4ec 100644 --- a/chromium/third_party/blink/renderer/modules/xr/DEPS +++ b/chromium/third_party/blink/renderer/modules/xr/DEPS @@ -1,5 +1,4 @@ include_rules = [ - "+mojo/public/cpp/bindings/binding.h", "+mojo/public/cpp/system/platform_handle.h", "+device/vr/public/mojom/vr_service.mojom-blink.h", "+device/vr/public/mojom/vr_service.mojom-blink-forward.h", diff --git a/chromium/third_party/blink/renderer/modules/xr/element_xr.h b/chromium/third_party/blink/renderer/modules/xr/element_xr.h new file mode 100644 index 00000000000..a82293984a2 --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/xr/element_xr.h @@ -0,0 +1,21 @@ +// Copyright 2020 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_ELEMENT_XR_H_ +#define THIRD_PARTY_BLINK_RENDERER_MODULES_XR_ELEMENT_XR_H_ + +#include "third_party/blink/renderer/modules/event_target_modules.h" + +namespace blink { + +class ElementXR { + STATIC_ONLY(ElementXR); + + public: + DEFINE_STATIC_ATTRIBUTE_EVENT_LISTENER(beforexrselect, kBeforexrselect) +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_XR_ELEMENT_XR_H_ diff --git a/chromium/third_party/blink/renderer/modules/xr/element_xr.idl b/chromium/third_party/blink/renderer/modules/xr/element_xr.idl new file mode 100644 index 00000000000..ba69ad6761a --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/xr/element_xr.idl @@ -0,0 +1,12 @@ +// Copyright 2020 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/dom-overlays/#onbeforexrselect + +[ + ImplementedAs=ElementXR +] +partial interface Element { + attribute EventHandler onbeforexrselect; +}; diff --git a/chromium/third_party/blink/renderer/modules/xr/idls.gni b/chromium/third_party/blink/renderer/modules/xr/idls.gni new file mode 100644 index 00000000000..242d0ab9555 --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/xr/idls.gni @@ -0,0 +1,67 @@ +# Copyright 2020 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. + +modules_idl_files = [ + "xr_anchor.idl", + "xr_anchor_set.idl", + "xr_bounded_reference_space.idl", + "xr_dom_overlay_state.idl", + "xr_cube_map.idl", + "xr_frame.idl", + "xr_input_source.idl", + "xr_input_source_array.idl", + "xr_input_source_event.idl", + "xr_input_sources_change_event.idl", + "xr_light_estimation.idl", + "xr_light_estimation_state.idl", + "xr_light_probe.idl", + "xr_plane.idl", + "xr_plane_detection_state.idl", + "xr_plane_set.idl", + "xr_pose.idl", + "xr_ray.idl", + "xr_reference_space.idl", + "xr_reference_space_event.idl", + "xr_reflection_probe.idl", + "xr_render_state.idl", + "xr_rigid_transform.idl", + "xr_hit_test_result.idl", + "xr_hit_test_source.idl", + "xr_session.idl", + "xr_session_event.idl", + "xr_space.idl", + "xr_spherical_harmonics.idl", + "xr_system.idl", + "xr_transient_input_hit_test_result.idl", + "xr_transient_input_hit_test_source.idl", + "xr_view.idl", + "xr_viewer_pose.idl", + "xr_viewport.idl", + "xr_webgl_layer.idl", + "xr_world_information.idl", + "xr_world_tracking_state.idl", +] + +modules_callback_function_idl_files = [ "xr_frame_request_callback.idl" ] + +modules_dictionary_idl_files = [ + "xr_dom_overlay_init.idl", + "xr_hit_test_options_init.idl", + "xr_input_source_event_init.idl", + "xr_input_sources_change_event_init.idl", + "xr_light_estimation_state_init.idl", + "xr_plane_detection_state_init.idl", + "xr_reference_space_event_init.idl", + "xr_render_state_init.idl", + "xr_session_event_init.idl", + "xr_session_init.idl", + "xr_transient_input_hit_test_options_init.idl", + "xr_webgl_layer_init.idl", + "xr_world_tracking_state_init.idl", +] + +modules_dependency_idl_files = [ + "element_xr.idl", + "navigator_xr.idl", +] diff --git a/chromium/third_party/blink/renderer/modules/xr/navigator_xr.cc b/chromium/third_party/blink/renderer/modules/xr/navigator_xr.cc index 039e450a1a1..274cf4078f9 100644 --- a/chromium/third_party/blink/renderer/modules/xr/navigator_xr.cc +++ b/chromium/third_party/blink/renderer/modules/xr/navigator_xr.cc @@ -10,7 +10,8 @@ #include "third_party/blink/renderer/core/frame/local_frame.h" #include "third_party/blink/renderer/core/frame/navigator.h" #include "third_party/blink/renderer/core/inspector/console_message.h" -#include "third_party/blink/renderer/modules/xr/xr.h" +#include "third_party/blink/renderer/modules/xr/xr_system.h" +#include "third_party/blink/renderer/platform/heap/heap.h" namespace blink { @@ -32,7 +33,7 @@ NavigatorXR& NavigatorXR::From(Navigator& navigator) { return *supplement; } -XR* NavigatorXR::xr(Navigator& navigator) { +XRSystem* NavigatorXR::xr(Navigator& navigator) { // Always return null when the navigator is detached. if (!navigator.GetFrame()) { return nullptr; @@ -41,7 +42,7 @@ XR* NavigatorXR::xr(Navigator& navigator) { return NavigatorXR::From(navigator).xr(); } -XR* NavigatorXR::xr() { +XRSystem* NavigatorXR::xr() { auto* document = GetDocument(); // Always return null when the navigator is detached. @@ -57,7 +58,8 @@ XR* NavigatorXR::xr() { } if (!xr_) { - xr_ = XR::Create(*document->GetFrame(), document->UkmSourceID()); + xr_ = MakeGarbageCollected<XRSystem>(*document->GetFrame(), + document->UkmSourceID()); } return xr_; @@ -70,7 +72,7 @@ Document* NavigatorXR::GetDocument() { return GetSupplementable()->GetFrame()->GetDocument(); } -void NavigatorXR::Trace(blink::Visitor* visitor) { +void NavigatorXR::Trace(Visitor* visitor) { visitor->Trace(xr_); Supplement<Navigator>::Trace(visitor); } diff --git a/chromium/third_party/blink/renderer/modules/xr/navigator_xr.h b/chromium/third_party/blink/renderer/modules/xr/navigator_xr.h index 89d1e217d67..78342d32497 100644 --- a/chromium/third_party/blink/renderer/modules/xr/navigator_xr.h +++ b/chromium/third_party/blink/renderer/modules/xr/navigator_xr.h @@ -13,7 +13,7 @@ namespace blink { class Document; -class XR; +class XRSystem; class MODULES_EXPORT NavigatorXR final : public GarbageCollected<NavigatorXR>, public Supplement<Navigator> { @@ -27,15 +27,15 @@ class MODULES_EXPORT NavigatorXR final : public GarbageCollected<NavigatorXR>, explicit NavigatorXR(Navigator&); - static XR* xr(Navigator&); - XR* xr(); + static XRSystem* xr(Navigator&); + XRSystem* xr(); - void Trace(blink::Visitor*) override; + void Trace(Visitor*) override; private: Document* GetDocument(); - Member<XR> xr_; + Member<XRSystem> xr_; // Gates metrics collection once per local DOM window frame. bool did_log_navigator_xr_ = false; diff --git a/chromium/third_party/blink/renderer/modules/xr/navigator_xr.idl b/chromium/third_party/blink/renderer/modules/xr/navigator_xr.idl index 2e3f5133db9..9e90ef3b41a 100644 --- a/chromium/third_party/blink/renderer/modules/xr/navigator_xr.idl +++ b/chromium/third_party/blink/renderer/modules/xr/navigator_xr.idl @@ -7,5 +7,5 @@ ImplementedAs=NavigatorXR ] partial interface Navigator { // Latest API - [SecureContext, RuntimeEnabled=WebXR, MeasureAs=NavigatorXR, SameObject] readonly attribute XR xr; + [SecureContext, RuntimeEnabled=WebXR, MeasureAs=NavigatorXR, SameObject] readonly attribute XRSystem xr; }; diff --git a/chromium/third_party/blink/renderer/modules/xr/type_converters.cc b/chromium/third_party/blink/renderer/modules/xr/type_converters.cc index 7744b485a63..bfea7162f7e 100644 --- a/chromium/third_party/blink/renderer/modules/xr/type_converters.cc +++ b/chromium/third_party/blink/renderer/modules/xr/type_converters.cc @@ -47,9 +47,9 @@ TypeConverter<blink::TransformationMatrix, device::mojom::blink::VRPosePtr>:: } if (pose->position) { - decomp.translate_x = pose->position->X(); - decomp.translate_y = pose->position->Y(); - decomp.translate_z = pose->position->Z(); + decomp.translate_x = pose->position->x(); + decomp.translate_y = pose->position->y(); + decomp.translate_z = pose->position->z(); } result.Recompose(decomp); @@ -77,9 +77,9 @@ TypeConverter<blink::TransformationMatrix, device::mojom::blink::PosePtr>:: decomp.quaternion_z = quat.z(); decomp.quaternion_w = quat.w(); - decomp.translate_x = pose->position.X(); - decomp.translate_y = pose->position.Y(); - decomp.translate_z = pose->position.Z(); + decomp.translate_x = pose->position.x(); + decomp.translate_y = pose->position.y(); + decomp.translate_z = pose->position.z(); result.Recompose(decomp); diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_anchor.cc b/chromium/third_party/blink/renderer/modules/xr/xr_anchor.cc index 739fc6462b1..01770130987 100644 --- a/chromium/third_party/blink/renderer/modules/xr/xr_anchor.cc +++ b/chromium/third_party/blink/renderer/modules/xr/xr_anchor.cc @@ -4,31 +4,30 @@ #include "third_party/blink/renderer/modules/xr/xr_anchor.h" #include "third_party/blink/renderer/modules/xr/type_converters.h" -#include "third_party/blink/renderer/modules/xr/xr.h" #include "third_party/blink/renderer/modules/xr/xr_object_space.h" #include "third_party/blink/renderer/modules/xr/xr_session.h" +#include "third_party/blink/renderer/modules/xr/xr_system.h" namespace blink { -XRAnchor::XRAnchor(uint64_t id, XRSession* session) - : id_(id), session_(session), anchor_data_(base::nullopt) {} - XRAnchor::XRAnchor(uint64_t id, XRSession* session, - const device::mojom::blink::XRAnchorDataPtr& anchor_data, - double timestamp) - : id_(id), - session_(session), - anchor_data_(base::in_place, anchor_data, timestamp) {} + const device::mojom::blink::XRAnchorData& anchor_data) + : id_(id), session_(session) { + // No need for else - if pose is not present, the default-constructed unique + // ptr is fine. + if (anchor_data.pose) { + SetMojoFromAnchor( + mojo::ConvertTo<blink::TransformationMatrix>(anchor_data.pose)); + } +} -void XRAnchor::Update(const device::mojom::blink::XRAnchorDataPtr& anchor_data, - double timestamp) { - if (!anchor_data_) { - anchor_data_ = AnchorData(anchor_data, timestamp); +void XRAnchor::Update(const device::mojom::blink::XRAnchorData& anchor_data) { + if (anchor_data.pose) { + SetMojoFromAnchor( + mojo::ConvertTo<blink::TransformationMatrix>(anchor_data.pose)); } else { - *anchor_data_->pose_matrix_ = - mojo::ConvertTo<blink::TransformationMatrix>(anchor_data->pose); - anchor_data_->last_changed_time_ = timestamp; + mojo_from_anchor_ = nullptr; } } @@ -37,9 +36,7 @@ uint64_t XRAnchor::id() const { } XRSpace* XRAnchor::anchorSpace() const { - if (!anchor_data_) { - return nullptr; - } + DCHECK(mojo_from_anchor_); if (!anchor_space_) { anchor_space_ = @@ -49,43 +46,31 @@ XRSpace* XRAnchor::anchorSpace() const { return anchor_space_; } -TransformationMatrix XRAnchor::poseMatrix() const { - if (anchor_data_) { - return *anchor_data_->pose_matrix_; +base::Optional<TransformationMatrix> XRAnchor::MojoFromObject() const { + if (!mojo_from_anchor_) { + return base::nullopt; } - // |poseMatrix()| shouldn't be called by anyone except XRObjectSpace and if - // XRObjectSpace already exists for this anchor, then anchor_data_ should also - // exist for this anchor. - NOTREACHED(); - return {}; -} - -double XRAnchor::lastChangedTime(bool& is_null) const { - if (!anchor_data_) { - is_null = true; - return 0; - } - - is_null = false; - return anchor_data_->last_changed_time_; + return *mojo_from_anchor_; } void XRAnchor::detach() { session_->xr()->xrEnvironmentProviderRemote()->DetachAnchor(id_); } -void XRAnchor::Trace(blink::Visitor* visitor) { +void XRAnchor::SetMojoFromAnchor(const TransformationMatrix& mojo_from_anchor) { + if (mojo_from_anchor_) { + *mojo_from_anchor_ = mojo_from_anchor; + } else { + mojo_from_anchor_ = + std::make_unique<TransformationMatrix>(mojo_from_anchor); + } +} + +void XRAnchor::Trace(Visitor* visitor) { visitor->Trace(session_); visitor->Trace(anchor_space_); ScriptWrappable::Trace(visitor); } -XRAnchor::AnchorData::AnchorData( - const device::mojom::blink::XRAnchorDataPtr& anchor_data, - double timestamp) - : pose_matrix_(std::make_unique<TransformationMatrix>( - mojo::ConvertTo<blink::TransformationMatrix>(anchor_data->pose))), - last_changed_time_(timestamp) {} - } // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_anchor.h b/chromium/third_party/blink/renderer/modules/xr/xr_anchor.h index f9c2c505d82..6ffbc612ceb 100644 --- a/chromium/third_party/blink/renderer/modules/xr/xr_anchor.h +++ b/chromium/third_party/blink/renderer/modules/xr/xr_anchor.h @@ -21,46 +21,36 @@ class XRAnchor : public ScriptWrappable { DEFINE_WRAPPERTYPEINFO(); public: - XRAnchor(uint64_t id, XRSession* session); - XRAnchor(uint64_t id, XRSession* session, - const device::mojom::blink::XRAnchorDataPtr& anchor_data, - double timestamp); + const device::mojom::blink::XRAnchorData& anchor_data); uint64_t id() const; XRSpace* anchorSpace() const; - TransformationMatrix poseMatrix() const; - - double lastChangedTime(bool& is_null) const; + base::Optional<TransformationMatrix> MojoFromObject() const; void detach(); - void Update(const device::mojom::blink::XRAnchorDataPtr& anchor_data, - double timestamp); + void Update(const device::mojom::blink::XRAnchorData& anchor_data); - void Trace(blink::Visitor* visitor) override; + void Trace(Visitor* visitor) override; private: - // AnchorData will only be present in an XRAnchor after the anchor was updated - // for the first time (CreateAnchor returns a promise that will resolve to an - // XRAnchor prior to first update of the anchor). - struct AnchorData { - // Anchor's pose in device (mojo) space. - std::unique_ptr<TransformationMatrix> pose_matrix_; - double last_changed_time_; - - AnchorData(const device::mojom::blink::XRAnchorDataPtr& anchor_data, - double timestamp); - }; + void SetMojoFromAnchor(const TransformationMatrix& mojo_from_anchor); const uint64_t id_; Member<XRSession> session_; - base::Optional<AnchorData> anchor_data_; + // |mojo_from_anchor_| will be non-null in an XRAnchor after the anchor was + // updated for the first time - this *must* happen in the same frame in which + // the anchor was created for the anchor to be fully usable. It is currently + // ensured by XRSession - anchors that got created prior to receiving the + // result from mojo call to GetFrameData are not returned to the application + // until their poses are known. + std::unique_ptr<TransformationMatrix> mojo_from_anchor_; // Cached anchor space - it will be created by `anchorSpace()` if it's not // set. diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_anchor.idl b/chromium/third_party/blink/renderer/modules/xr/xr_anchor.idl index 337c56ef13f..48ca880cd09 100644 --- a/chromium/third_party/blink/renderer/modules/xr/xr_anchor.idl +++ b/chromium/third_party/blink/renderer/modules/xr/xr_anchor.idl @@ -5,11 +5,10 @@ [ SecureContext, Exposed=Window, - RuntimeEnabled=WebXRAnchors + RuntimeEnabled=WebXRIncubations ] interface XRAnchor { - readonly attribute XRSpace? anchorSpace; - readonly attribute DOMHighResTimeStamp? lastChangedTime; + readonly attribute XRSpace anchorSpace; void detach(); }; diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_anchor_set.cc b/chromium/third_party/blink/renderer/modules/xr/xr_anchor_set.cc index 67e1ad746fd..47588f58545 100644 --- a/chromium/third_party/blink/renderer/modules/xr/xr_anchor_set.cc +++ b/chromium/third_party/blink/renderer/modules/xr/xr_anchor_set.cc @@ -13,7 +13,7 @@ const HeapHashSet<Member<XRAnchor>>& XRAnchorSet::elements() const { return anchors_; } -void XRAnchorSet::Trace(blink::Visitor* visitor) { +void XRAnchorSet::Trace(Visitor* visitor) { visitor->Trace(anchors_); ScriptWrappable::Trace(visitor); } diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_anchor_set.h b/chromium/third_party/blink/renderer/modules/xr/xr_anchor_set.h index cc4e2bec4f1..fecd15421b2 100644 --- a/chromium/third_party/blink/renderer/modules/xr/xr_anchor_set.h +++ b/chromium/third_party/blink/renderer/modules/xr/xr_anchor_set.h @@ -18,7 +18,7 @@ class XRAnchorSet : public ScriptWrappable, public XRSetlike<XRAnchor> { public: explicit XRAnchorSet(HeapHashSet<Member<XRAnchor>> anchors); - void Trace(blink::Visitor* visitor) override; + void Trace(Visitor* visitor) override; protected: const HeapHashSet<Member<XRAnchor>>& elements() const override; diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_anchor_set.idl b/chromium/third_party/blink/renderer/modules/xr/xr_anchor_set.idl index aee2cb2d1bb..ddb69dd718c 100644 --- a/chromium/third_party/blink/renderer/modules/xr/xr_anchor_set.idl +++ b/chromium/third_party/blink/renderer/modules/xr/xr_anchor_set.idl @@ -5,7 +5,7 @@ [ SecureContext, Exposed=Window, - RuntimeEnabled=WebXRAnchors + RuntimeEnabled=WebXRIncubations ] interface XRAnchorSet { readonly setlike<XRAnchor>; diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_bounded_reference_space.cc b/chromium/third_party/blink/renderer/modules/xr/xr_bounded_reference_space.cc index bef36eb3ffc..e0b47c1aea7 100644 --- a/chromium/third_party/blink/renderer/modules/xr/xr_bounded_reference_space.cc +++ b/chromium/third_party/blink/renderer/modules/xr/xr_bounded_reference_space.cc @@ -15,6 +15,10 @@ namespace blink { namespace { + +// Bounds must be a valid polygon (at least 3 vertices). +constexpr wtf_size_t kMinimumNumberOfBoundVertices = 3; + float RoundCm(float val) { // Float round will only round to the nearest whole number. In order to get // two decimal points of precision, we need to move the decimal out then @@ -38,12 +42,6 @@ XRBoundedReferenceSpace::XRBoundedReferenceSpace( XRBoundedReferenceSpace::~XRBoundedReferenceSpace() = default; -// No default pose for bounded reference spaces. -std::unique_ptr<TransformationMatrix> -XRBoundedReferenceSpace::DefaultViewerPose() { - return nullptr; -} - void XRBoundedReferenceSpace::EnsureUpdated() { // Check first to see if the stage parameters have updated since the last // call. We only need to update the transform and bounds if it has. @@ -57,57 +55,52 @@ void XRBoundedReferenceSpace::EnsureUpdated() { if (display_info && display_info->stage_parameters) { // Use the transform given by xrDisplayInfo's stage_parameters if available. - bounded_space_from_mojo_ = std::make_unique<TransformationMatrix>( + bounded_native_from_mojo_ = std::make_unique<TransformationMatrix>( display_info->stage_parameters->standing_transform.matrix()); // In order to ensure that the bounds continue to line up with the user's - // physical environment we need to transform by the inverse of the - // originOffset. TODO(https://crbug.com/1008466): move originOffset to - // separate class? If yes, that class would need to apply a transform - // in the boundsGeometry accessor. - TransformationMatrix bounds_transform = InverseOriginOffsetMatrix(); + // physical environment we need to transform them from native to offset. + // Bounds are provided in our native coordinate space. + // TODO(https://crbug.com/1008466): move originOffset to separate class? If + // yes, that class would need to apply a transform in the boundsGeometry + // accessor. + TransformationMatrix offset_from_native = OffsetFromNativeMatrix(); // We may not have bounds if we've lost tracking after being created. // Whether we have them or not, we need to clear the existing bounds. - bounds_geometry_.clear(); - if (display_info->stage_parameters->bounds) { + offset_bounds_geometry_.clear(); + if (display_info->stage_parameters->bounds && + display_info->stage_parameters->bounds->size() >= + kMinimumNumberOfBoundVertices) { for (const auto& bound : *(display_info->stage_parameters->bounds)) { - FloatPoint3D p = - bounds_transform.MapPoint(FloatPoint3D(bound.X(), 0.0, bound.Z())); - bounds_geometry_.push_back(RoundedDOMPoint(p)); + FloatPoint3D p = offset_from_native.MapPoint( + FloatPoint3D(bound.x(), 0.0, bound.z())); + offset_bounds_geometry_.push_back(RoundedDOMPoint(p)); } } } else { // If stage parameters aren't available set the transform to null, which // will subsequently cause this reference space to return null poses. - bounded_space_from_mojo_.reset(); - bounds_geometry_.clear(); + bounded_native_from_mojo_.reset(); + offset_bounds_geometry_.clear(); } DispatchEvent(*XRReferenceSpaceEvent::Create(event_type_names::kReset, this)); } -// Gets the pose of the mojo origin in this reference space, corresponding to a -// transform from mojo coordinates to reference space coordinates. Ideally in -// the future this reference space can be used without additional transforms, -// with the various XR backends returning poses already in the right space. -std::unique_ptr<TransformationMatrix> XRBoundedReferenceSpace::SpaceFromMojo( - const TransformationMatrix& mojo_from_viewer) { +std::unique_ptr<TransformationMatrix> +XRBoundedReferenceSpace::NativeFromMojo() { EnsureUpdated(); - // If the reference space has a transform apply it to the base pose and return - // that, otherwise return null. - if (bounded_space_from_mojo_) { - std::unique_ptr<TransformationMatrix> space_from_mojo( - std::make_unique<TransformationMatrix>(*bounded_space_from_mojo_)); - return space_from_mojo; - } - return nullptr; + if (!bounded_native_from_mojo_) + return nullptr; + + return std::make_unique<TransformationMatrix>(*bounded_native_from_mojo_); } HeapVector<Member<DOMPointReadOnly>> XRBoundedReferenceSpace::boundsGeometry() { EnsureUpdated(); - return bounds_geometry_; + return offset_bounds_geometry_; } base::Optional<XRNativeOriginInformation> @@ -115,8 +108,8 @@ XRBoundedReferenceSpace::NativeOrigin() const { return XRNativeOriginInformation::Create(this); } -void XRBoundedReferenceSpace::Trace(blink::Visitor* visitor) { - visitor->Trace(bounds_geometry_); +void XRBoundedReferenceSpace::Trace(Visitor* visitor) { + visitor->Trace(offset_bounds_geometry_); XRReferenceSpace::Trace(visitor); } diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_bounded_reference_space.h b/chromium/third_party/blink/renderer/modules/xr/xr_bounded_reference_space.h index 8f871b2a961..faa52fcbd0f 100644 --- a/chromium/third_party/blink/renderer/modules/xr/xr_bounded_reference_space.h +++ b/chromium/third_party/blink/renderer/modules/xr/xr_bounded_reference_space.h @@ -19,15 +19,13 @@ class XRBoundedReferenceSpace final : public XRReferenceSpace { XRBoundedReferenceSpace(XRSession*, XRRigidTransform*); ~XRBoundedReferenceSpace() override; - std::unique_ptr<TransformationMatrix> DefaultViewerPose() override; - std::unique_ptr<TransformationMatrix> SpaceFromMojo( - const TransformationMatrix& mojo_from_viewer) override; + std::unique_ptr<TransformationMatrix> NativeFromMojo() override; HeapVector<Member<DOMPointReadOnly>> boundsGeometry(); base::Optional<XRNativeOriginInformation> NativeOrigin() const override; - void Trace(blink::Visitor*) override; + void Trace(Visitor*) override; void OnReset() override; @@ -37,8 +35,8 @@ class XRBoundedReferenceSpace final : public XRReferenceSpace { void EnsureUpdated(); - HeapVector<Member<DOMPointReadOnly>> bounds_geometry_; - std::unique_ptr<TransformationMatrix> bounded_space_from_mojo_; + HeapVector<Member<DOMPointReadOnly>> offset_bounds_geometry_; + std::unique_ptr<TransformationMatrix> bounded_native_from_mojo_; unsigned int stage_parameters_id_ = 0; }; 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 index 79b58e56eda..2b15f65c0cd 100644 --- 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 @@ -8,10 +8,10 @@ #include "third_party/blink/renderer/core/dom/events/native_event_listener.h" #include "third_party/blink/renderer/core/events/pointer_event.h" #include "third_party/blink/renderer/core/html/canvas/html_canvas_element.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_input_source.h" #include "third_party/blink/renderer/modules/xr/xr_session.h" +#include "third_party/blink/renderer/modules/xr/xr_system.h" #include "third_party/blink/renderer/modules/xr/xr_view.h" namespace blink { @@ -27,7 +27,7 @@ class XRCanvasInputEventListener : public NativeEventListener { if (!input_provider_->ShouldProcessEvents()) return; - PointerEvent* pointer_event = ToPointerEvent(event); + auto* pointer_event = To<PointerEvent>(event); DCHECK(pointer_event); if (!pointer_event->isPrimary()) return; @@ -40,7 +40,7 @@ class XRCanvasInputEventListener : public NativeEventListener { } } - void Trace(blink::Visitor* visitor) override { + void Trace(Visitor* visitor) override { visitor->Trace(input_provider_); EventListener::Trace(visitor); } @@ -128,7 +128,7 @@ void XRCanvasInputProvider::ClearInputSource() { input_source_ = nullptr; } -void XRCanvasInputProvider::Trace(blink::Visitor* visitor) { +void XRCanvasInputProvider::Trace(Visitor* visitor) { visitor->Trace(session_); visitor->Trace(canvas_); visitor->Trace(listener_); 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 index 3662b8d72ad..f66c96e099a 100644 --- 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 @@ -38,7 +38,7 @@ class XRCanvasInputProvider : public GarbageCollected<XRCanvasInputProvider>, XRInputSource* GetInputSource(); - virtual void Trace(blink::Visitor*); + virtual void Trace(Visitor*); const char* NameInHeapSnapshot() const override { return "XRCanvasInputProvider"; } diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_cube_map.cc b/chromium/third_party/blink/renderer/modules/xr/xr_cube_map.cc new file mode 100644 index 00000000000..b2973a05e51 --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/xr/xr_cube_map.cc @@ -0,0 +1,105 @@ +// Copyright 2019 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_cube_map.h" + +#include "device/vr/public/mojom/vr_service.mojom-blink.h" +#include "third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.h" +#include "third_party/blink/renderer/modules/webgl/webgl_texture.h" +#include "third_party/blink/renderer/modules/xr/xr_cube_map.h" +#include "third_party/blink/renderer/platform/bindings/exception_code.h" + +namespace { +bool IsPowerOfTwo(uint32_t value) { + return value && (value & (value - 1)) == 0; +} + +static constexpr char const* kErrorNonCubemapTexture = + "Cannot pass non-cubemap texture"; +static constexpr char const* kErrorContextMismatch = "Context mismatch"; + +} // namespace + +namespace blink { + +XRCubeMap::XRCubeMap(const device::mojom::blink::XRCubeMap& cube_map) { + constexpr auto kNumComponentsPerPixel = + device::mojom::blink::XRCubeMap::kNumComponentsPerPixel; + static_assert(kNumComponentsPerPixel == 4, + "XRCubeMaps are expected to be in the RGBA16F format"); + + // Cube map sides must all be a power-of-two image + bool valid = IsPowerOfTwo(cube_map.width_and_height); + const size_t expected_size = + cube_map.width_and_height * cube_map.width_and_height; + valid &= cube_map.positive_x.size() == expected_size; + valid &= cube_map.negative_x.size() == expected_size; + valid &= cube_map.positive_y.size() == expected_size; + valid &= cube_map.negative_y.size() == expected_size; + valid &= cube_map.positive_z.size() == expected_size; + valid &= cube_map.negative_z.size() == expected_size; + DCHECK(valid); + + width_and_height_ = cube_map.width_and_height; + positive_x_ = cube_map.positive_x; + negative_x_ = cube_map.negative_x; + positive_y_ = cube_map.positive_y; + negative_y_ = cube_map.negative_y; + positive_z_ = cube_map.positive_z; + negative_z_ = cube_map.negative_z; +} + +WebGLTexture* XRCubeMap::updateWebGLEnvironmentCube( + WebGL2RenderingContextBase* context, + WebGLTexture* texture, + ExceptionState& exception_state) const { + // If they haven't supplied us with a texture, Create a new one. + if (!texture) { + texture = MakeGarbageCollected<WebGLTexture>(context); + } else if (texture->HasEverBeenBound() && + texture->GetTarget() != GL_TEXTURE_CUBE_MAP) { + exception_state.ThrowTypeError(kErrorNonCubemapTexture); + return nullptr; + } else if (texture->ContextGroup() != context->ContextGroup()) { + exception_state.ThrowTypeError(kErrorContextMismatch); + return nullptr; + } + + auto* gl = context->ContextGL(); + texture->SetTarget(GL_TEXTURE_CUBE_MAP); + gl->BindTexture(GL_TEXTURE_CUBE_MAP, texture->Object()); + + // Cannot generate mip-maps for half-float textures, so use linear filtering + gl->TexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + gl->TexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + uint16_t const* const cubemap_images[] = { + positive_x_.data()->components, negative_x_.data()->components, + positive_y_.data()->components, negative_y_.data()->components, + positive_z_.data()->components, negative_z_.data()->components, + }; + GLenum const cubemap_targets[] = { + GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL_TEXTURE_CUBE_MAP_NEGATIVE_X, + GL_TEXTURE_CUBE_MAP_POSITIVE_Y, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, + GL_TEXTURE_CUBE_MAP_POSITIVE_Z, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, + }; + + // Update image for each side of the cube map + for (int i = 0; i < 6; ++i) { + auto* image = cubemap_images[i]; + auto target = cubemap_targets[i]; + + gl->TexImage2D(target, 0, GL_RGBA16F, width_and_height_, width_and_height_, + 0, GL_RGBA, GL_HALF_FLOAT, image); + } + + gl->BindTexture(GL_TEXTURE_CUBE_MAP, 0); + + // Debug check for success + DCHECK(gl->GetError() == GL_NO_ERROR); + + return texture; +} + +} // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_cube_map.h b/chromium/third_party/blink/renderer/modules/xr/xr_cube_map.h new file mode 100644 index 00000000000..78241320559 --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/xr/xr_cube_map.h @@ -0,0 +1,42 @@ +// Copyright 2019 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_CUBE_MAP_H_ +#define THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_CUBE_MAP_H_ + +#include "base/util/type_safety/pass_key.h" +#include "device/vr/public/mojom/vr_service.mojom-blink-forward.h" +#include "third_party/blink/renderer/core/typed_arrays/dom_typed_array.h" +#include "third_party/blink/renderer/platform/bindings/script_wrappable.h" + +namespace blink { + +class WebGL2RenderingContextBase; +class WebGLTexture; +class ExceptionState; + +class XRCubeMap : public ScriptWrappable { + DEFINE_WRAPPERTYPEINFO(); + + public: + explicit XRCubeMap(const device::mojom::blink::XRCubeMap& cube_map); + + WebGLTexture* updateWebGLEnvironmentCube( + WebGL2RenderingContextBase* context, + WebGLTexture* texture, + ExceptionState& exception_state) const; + + private: + uint32_t width_and_height_ = 0; + WTF::Vector<device::RgbaTupleF16> positive_x_; + WTF::Vector<device::RgbaTupleF16> negative_x_; + WTF::Vector<device::RgbaTupleF16> positive_y_; + WTF::Vector<device::RgbaTupleF16> negative_y_; + WTF::Vector<device::RgbaTupleF16> positive_z_; + WTF::Vector<device::RgbaTupleF16> negative_z_; +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_CUBE_MAP_H_ diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_cube_map.idl b/chromium/third_party/blink/renderer/modules/xr/xr_cube_map.idl new file mode 100644 index 00000000000..fd68d986f08 --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/xr/xr_cube_map.idl @@ -0,0 +1,14 @@ +// Copyright 2019 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, + Exposed=Window, + RuntimeEnabled=WebXRIncubations +] +interface XRCubeMap { + [RaisesException] + WebGLTexture updateWebGLEnvironmentCube(WebGL2RenderingContext context, WebGLTexture? texture); +}; + diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_dom_overlay_init.idl b/chromium/third_party/blink/renderer/modules/xr/xr_dom_overlay_init.idl new file mode 100644 index 00000000000..7a7d2791d0e --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/xr/xr_dom_overlay_init.idl @@ -0,0 +1,8 @@ +// Copyright 2019 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/dom-overlays/#dictdef-xrdomoverlayinit +dictionary XRDOMOverlayInit { + required Element root; +}; diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_dom_overlay_state.cc b/chromium/third_party/blink/renderer/modules/xr/xr_dom_overlay_state.cc new file mode 100644 index 00000000000..10db7030a66 --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/xr/xr_dom_overlay_state.cc @@ -0,0 +1,31 @@ +// Copyright 2019 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_dom_overlay_state.h" + +#include "third_party/blink/renderer/core/dom/element.h" + +namespace blink { + +namespace { + +const String MapOverlayType(XRDOMOverlayState::DOMOverlayType type) { + switch (type) { + case XRDOMOverlayState::DOMOverlayType::kScreen: + return "screen"; + case XRDOMOverlayState::DOMOverlayType::kFloating: + return "floating"; + } +} + +} // namespace + +XRDOMOverlayState::XRDOMOverlayState(DOMOverlayType type) + : type_string_(MapOverlayType(type)) {} + +void XRDOMOverlayState::Trace(Visitor* visitor) { + ScriptWrappable::Trace(visitor); +} + +} // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_dom_overlay_state.h b/chromium/third_party/blink/renderer/modules/xr/xr_dom_overlay_state.h new file mode 100644 index 00000000000..f39b2705bdb --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/xr/xr_dom_overlay_state.h @@ -0,0 +1,42 @@ +// Copyright 2019 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_DOM_OVERLAY_STATE_H_ +#define THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_DOM_OVERLAY_STATE_H_ + +#include "third_party/blink/renderer/platform/bindings/script_wrappable.h" +#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" + +namespace blink { + +// Implementation of +// https://immersive-web.github.io/dom-overlays/#dictdef-xrdomoverlaystate, used +// as SameObject instances owned by |XRSession|. +class XRDOMOverlayState : public ScriptWrappable { + DEFINE_WRAPPERTYPEINFO(); + + public: + enum class DOMOverlayType { + kScreen = 0, + kFloating, + }; + + explicit XRDOMOverlayState(DOMOverlayType type); + ~XRDOMOverlayState() override = default; + + const String& type() const { return type_string_; } + + void Trace(Visitor*) override; + + private: + const String type_string_; + // Currently, instances of this class are created at session start, on the + // assumption that the objects are very small. If this becomes more complex in + // the future, i.e. when adding additional members, consider switching to lazy + // instantiation. +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_DOM_OVERLAY_STATE_H_ diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_dom_overlay_state.idl b/chromium/third_party/blink/renderer/modules/xr/xr_dom_overlay_state.idl new file mode 100644 index 00000000000..fcc12cfce90 --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/xr/xr_dom_overlay_state.idl @@ -0,0 +1,17 @@ +// Copyright 2019 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/dom-overlays/#enumdef-xrdomoverlaytype +enum XRDOMOverlayType { + "screen", + "floating", +}; + +// https://immersive-web.github.io/dom-overlays/#dictdef-xrdomoverlaystate +[ + SecureContext, + Exposed=Window +] interface XRDOMOverlayState { + readonly attribute XRDOMOverlayType type; +}; diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_frame.cc b/chromium/third_party/blink/renderer/modules/xr/xr_frame.cc index b7cac4f9591..8e3bb4bb818 100644 --- a/chromium/third_party/blink/renderer/modules/xr/xr_frame.cc +++ b/chromium/third_party/blink/renderer/modules/xr/xr_frame.cc @@ -42,6 +42,7 @@ XRFrame::XRFrame(XRSession* session, XRWorldInformation* world_information) XRViewerPose* XRFrame::getViewerPose(XRReferenceSpace* reference_space, ExceptionState& exception_state) const { + DVLOG(3) << __func__; if (!is_active_) { exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError, kInactiveFrame); @@ -55,6 +56,7 @@ XRViewerPose* XRFrame::getViewerPose(XRReferenceSpace* reference_space, } if (!reference_space) { + DVLOG(1) << __func__ << ": reference space not present, returning null"; return nullptr; } @@ -72,18 +74,24 @@ XRViewerPose* XRFrame::getViewerPose(XRReferenceSpace* reference_space, session_->LogGetPose(); - std::unique_ptr<TransformationMatrix> pose = - reference_space->SpaceFromViewerWithDefaultAndOffset( - mojo_from_viewer_.get()); - if (!pose) { + std::unique_ptr<TransformationMatrix> offset_space_from_viewer = + reference_space->OffsetFromViewer(); + + // Can only update an XRViewerPose's views with an invertible matrix. + if (!(offset_space_from_viewer && offset_space_from_viewer->IsInvertible())) { + DVLOG(1) << __func__ + << ": offset_space_from_viewer is invalid or not invertible - " + "returning nullptr, offset_space_from_viewer valid? " + << (offset_space_from_viewer ? true : false); return nullptr; } - return MakeGarbageCollected<XRViewerPose>(session(), *pose); + return MakeGarbageCollected<XRViewerPose>(session(), + *offset_space_from_viewer); } XRAnchorSet* XRFrame::trackedAnchors() const { - return session_->trackedAnchors(); + return session_->TrackedAnchors(); } // Return an XRPose that has a transform of basespace_from_space, while @@ -121,13 +129,7 @@ XRPose* XRFrame::getPose(XRSpace* space, return nullptr; } - return space->getPose(basespace, mojo_from_viewer_.get()); -} - -void XRFrame::SetMojoFromViewer(const TransformationMatrix& mojo_from_viewer, - bool emulated_position) { - mojo_from_viewer_ = std::make_unique<TransformationMatrix>(mojo_from_viewer); - emulated_position_ = emulated_position; + return space->getPose(basespace); } void XRFrame::Deactivate() { @@ -164,7 +166,44 @@ XRFrame::getHitTestResultsForTransientInput( return hit_test_source->Results(); } -void XRFrame::Trace(blink::Visitor* visitor) { +ScriptPromise XRFrame::createAnchor(ScriptState* script_state, + XRRigidTransform* initial_pose, + XRSpace* space, + ExceptionState& exception_state) { + DVLOG(2) << __func__; + + if (!is_active_) { + exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError, + kInactiveFrame); + return {}; + } + + if (!initial_pose) { + exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError, + XRSession::kNoRigidTransformSpecified); + return {}; + } + + if (!space) { + exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError, + XRSession::kNoSpaceSpecified); + return {}; + } + + auto maybe_mojo_from_offset_space = space->MojoFromOffsetMatrix(); + + if (!maybe_mojo_from_offset_space) { + exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError, + XRSession::kUnableToRetrieveMatrix); + return ScriptPromise(); + } + + return session_->CreateAnchor(script_state, initial_pose->TransformMatrix(), + *maybe_mojo_from_offset_space, base::nullopt, + exception_state); +} + +void XRFrame::Trace(Visitor* visitor) { visitor->Trace(session_); visitor->Trace(world_information_); ScriptWrappable::Trace(visitor); diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_frame.h b/chromium/third_party/blink/renderer/modules/xr/xr_frame.h index a6376db5aef..15e9e5996fd 100644 --- a/chromium/third_party/blink/renderer/modules/xr/xr_frame.h +++ b/chromium/third_party/blink/renderer/modules/xr/xr_frame.h @@ -9,6 +9,7 @@ #include "device/vr/public/mojom/vr_service.mojom-blink-forward.h" #include "third_party/blink/renderer/bindings/core/v8/script_promise.h" +#include "third_party/blink/renderer/platform/bindings/script_state.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" @@ -23,6 +24,7 @@ class XRHitTestSource; class XRInputSource; class XRPose; class XRReferenceSpace; +class XRRigidTransform; class XRSession; class XRSpace; class XRTransientInputHitTestResult; @@ -43,9 +45,7 @@ class XRFrame final : public ScriptWrappable { XRWorldInformation* worldInformation() const { return world_information_; } XRAnchorSet* trackedAnchors() const; - void SetMojoFromViewer(const TransformationMatrix&, bool emulated_position); - - void Trace(blink::Visitor*) override; + void Trace(Visitor*) override; void Deactivate(); @@ -62,7 +62,10 @@ class XRFrame final : public ScriptWrappable { XRTransientInputHitTestSource* hit_test_source, ExceptionState& exception_state); - bool EmulatedPosition() const { return emulated_position_; } + ScriptPromise createAnchor(ScriptState* script_state, + XRRigidTransform* initial_pose, + XRSpace* space, + ExceptionState& exception_state); private: std::unique_ptr<TransformationMatrix> GetAdjustedPoseMatrix(XRSpace*) const; @@ -73,10 +76,6 @@ class XRFrame final : public ScriptWrappable { const Member<XRSession> session_; - // Viewer pose in mojo space, the matrix maps from viewer (headset) space to - // mojo space. - std::unique_ptr<TransformationMatrix> mojo_from_viewer_; - // Frames are only active during callbacks. getPose and getViewerPose should // only be called from JS on active frames. bool is_active_ = true; @@ -85,8 +84,6 @@ class XRFrame final : public ScriptWrappable { // animation frames. getViewerPose should only be called from JS on active // animation frames. bool is_animation_frame_ = false; - - bool emulated_position_ = false; }; } // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_frame.idl b/chromium/third_party/blink/renderer/modules/xr/xr_frame.idl index 4c0cdfa69b0..661c06eb709 100644 --- a/chromium/third_party/blink/renderer/modules/xr/xr_frame.idl +++ b/chromium/third_party/blink/renderer/modules/xr/xr_frame.idl @@ -12,9 +12,12 @@ // More details about the real-world understanding APIs can be found here: // https://github.com/immersive-web/real-world-geometry/blob/master/plane-detection-explainer.md - [RuntimeEnabled=WebXRPlaneDetection] readonly attribute XRWorldInformation worldInformation; + [RuntimeEnabled=WebXRIncubations] readonly attribute XRWorldInformation worldInformation; - [RuntimeEnabled=WebXRAnchors] readonly attribute XRAnchorSet trackedAnchors; + [RuntimeEnabled=WebXRIncubations] + readonly attribute XRAnchorSet trackedAnchors; + [RuntimeEnabled=WebXRIncubations, CallWith=ScriptState, RaisesException] + Promise<XRAnchor> createAnchor(XRRigidTransform initial_pose, XRSpace space); [RaisesException] XRViewerPose? getViewerPose(XRReferenceSpace referenceSpace); [RaisesException] XRPose? getPose(XRSpace space, XRSpace relativeTo); 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 index 6b562aab546..5be7af5a8ac 100644 --- a/chromium/third_party/blink/renderer/modules/xr/xr_frame_provider.cc +++ b/chromium/third_party/blink/renderer/modules/xr/xr_frame_provider.cc @@ -13,9 +13,10 @@ #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/core/loader/document_loader.h" -#include "third_party/blink/renderer/modules/xr/xr.h" +#include "third_party/blink/renderer/modules/xr/xr_light_estimation_state.h" #include "third_party/blink/renderer/modules/xr/xr_plane_detection_state.h" #include "third_party/blink/renderer/modules/xr/xr_session.h" +#include "third_party/blink/renderer/modules/xr/xr_system.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/modules/xr/xr_world_tracking_state.h" @@ -39,7 +40,7 @@ class XRFrameProviderRequestCallback frame_provider_->OnNonImmersiveVSync(high_res_time_ms); } - void Trace(blink::Visitor* visitor) override { + void Trace(Visitor* visitor) override { visitor->Trace(frame_provider_); FrameRequestCallbackCollection::FrameCallback::Trace(visitor); @@ -50,7 +51,7 @@ class XRFrameProviderRequestCallback } // namespace -XRFrameProvider::XRFrameProvider(XR* xr) +XRFrameProvider::XRFrameProvider(XRSystem* xr) : xr_(xr), last_has_focus_(xr->IsFrameFocused()) { frame_transport_ = MakeGarbageCollected<XRFrameTransport>(); } @@ -161,7 +162,8 @@ void XRFrameProvider::RequestFrame(XRSession* session) { DCHECK(session); auto options = device::mojom::blink::XRFrameDataRequestOptions::New( - session->worldTrackingState()->planeDetectionState()->enabled()); + session->worldTrackingState()->planeDetectionState()->enabled(), + session->worldTrackingState()->lightEstimationState()->enabled()); // Immersive frame logic. if (session->immersive()) { @@ -255,9 +257,12 @@ void XRFrameProvider::OnImmersiveFrameData( immersive_frame_pose_ = std::move(data->pose); if (immersive_frame_pose_) { + DVLOG(3) << __func__ << ": pose available, emulated_position=" + << immersive_frame_pose_->emulated_position; is_immersive_frame_position_emulated_ = immersive_frame_pose_->emulated_position; } else { + DVLOG(2) << __func__ << ": emulating immersive frame position"; is_immersive_frame_position_emulated_ = true; } @@ -323,7 +328,7 @@ void XRFrameProvider::OnNonImmersiveFrameData( } if (frame_data) { - request->value = std::move(frame_data->pose); + request->value = std::move(frame_data); } else { // Unexpectedly didn't get frame data, and we don't have a timestamp. // Try to request a regular animation frame to avoid getting stuck. @@ -350,7 +355,8 @@ void XRFrameProvider::RequestNonImmersiveFrameData(XRSession* session) { } else { auto& data_provider = provider->value; auto options = device::mojom::blink::XRFrameDataRequestOptions::New( - session->worldTrackingState()->planeDetectionState()->enabled()); + session->worldTrackingState()->planeDetectionState()->enabled(), + session->worldTrackingState()->lightEstimationState()->enabled()); data_provider->GetFrameData( std::move(options), @@ -367,6 +373,11 @@ void XRFrameProvider::ProcessScheduledFrame( TRACE_EVENT2("gpu", "XRFrameProvider::ProcessScheduledFrame", "frame", frame_id_, "timestamp", high_res_now_ms); + LocalFrame* frame = xr_->GetFrame(); + if (!frame) { + return; + } + if (!xr_->IsFrameFocused() && !immersive_session_) { return; // Not currently focused, so we won't expose poses (except to // immersive sessions). @@ -426,7 +437,14 @@ void XRFrameProvider::ProcessScheduledFrame( immersive_session_->UpdateStageParameters(frame_data->stage_parameters); } - immersive_session_->OnFrame(high_res_now_ms, buffer_mailbox_holder_); + // Run immersive_session_->OnFrame() in a posted task to ensure that + // createAnchor promises get a chance to run - the presentation frame state + // is already updated. + frame->GetTaskRunner(blink::TaskType::kInternalMedia) + ->PostTask(FROM_HERE, + WTF::Bind(&XRSession::OnFrame, + WrapWeakPersistent(immersive_session_.Get()), + high_res_now_ms, 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 @@ -443,13 +461,15 @@ void XRFrameProvider::ProcessScheduledFrame( if (session->ended()) continue; - const auto& frame_pose = request.value; + const auto& inline_frame_data = request.value; + device::mojom::blink::VRPosePtr inline_pose_data = + inline_frame_data ? std::move(inline_frame_data->pose) : nullptr; // Prior to updating input source state, update the state needed to create // presentation frame as newly created presentation frame will get passed // to the input source select[/start/end] events. session->UpdatePresentationFrameState( - high_res_now_ms, frame_pose, frame_data, frame_id_, + high_res_now_ms, inline_pose_data, inline_frame_data, frame_id_, true /* Non-immersive positions are always emulated */); // If the input state change caused this session to end, we should stop @@ -457,7 +477,7 @@ void XRFrameProvider::ProcessScheduledFrame( if (session->ended()) continue; - if (frame_data && frame_data->mojo_space_reset) { + if (inline_frame_data && inline_frame_data->mojo_space_reset) { session->OnMojoSpaceReset(); } @@ -465,7 +485,13 @@ void XRFrameProvider::ProcessScheduledFrame( if (session->ended()) continue; - session->OnFrame(high_res_now_ms, base::nullopt); + // Run session->OnFrame() in a posted task to ensure that createAnchor + // promises get a chance to run - the presentation frame state is already + // updated. + frame->GetTaskRunner(blink::TaskType::kInternalMedia) + ->PostTask(FROM_HERE, + WTF::Bind(&XRSession::OnFrame, WrapWeakPersistent(session), + high_res_now_ms, base::nullopt)); } } } @@ -500,8 +526,6 @@ void XRFrameProvider::SubmitWebGLLayer(XRWebGLLayer* layer, bool was_changed) { frame_transport_->FramePreImage(webgl_context->ContextGL()); - std::unique_ptr<viz::SingleReleaseCallback> image_release_callback; - if (frame_transport_->DrawingIntoSharedBuffer()) { // Image is written to shared buffer already. Just submit with a // placeholder. @@ -509,13 +533,12 @@ void XRFrameProvider::SubmitWebGLLayer(XRWebGLLayer* layer, bool was_changed) { DVLOG(3) << __FUNCTION__ << ": FrameSubmit for SharedBuffer mode"; frame_transport_->FrameSubmit(immersive_presentation_provider_.get(), webgl_context->ContextGL(), webgl_context, - std::move(image_ref), - std::move(image_release_callback), frame_id_); + std::move(image_ref), frame_id_); return; } scoped_refptr<StaticBitmapImage> image_ref = - layer->TransferToStaticBitmapImage(&image_release_callback); + layer->TransferToStaticBitmapImage(); if (!image_ref) return; @@ -529,8 +552,7 @@ void XRFrameProvider::SubmitWebGLLayer(XRWebGLLayer* layer, bool was_changed) { frame_transport_->FrameSubmit(immersive_presentation_provider_.get(), webgl_context->ContextGL(), webgl_context, - std::move(image_ref), - std::move(image_release_callback), frame_id_); + std::move(image_ref), frame_id_); // Reset our frame id, since anything we'd want to do (resizing/etc) can // no-longer happen to this frame. @@ -550,25 +572,25 @@ void XRFrameProvider::UpdateWebGLLayerViewports(XRWebGLLayer* layer) { // We may only have one eye view, i.e. in smartphone immersive AR mode. // Use all-zero bounds for unused views. - WebFloatRect left_coords = - left ? WebFloatRect( + gfx::RectF left_coords = + left ? gfx::RectF( 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(); - WebFloatRect right_coords = - right ? WebFloatRect( + : gfx::RectF(); + gfx::RectF right_coords = + right ? gfx::RectF( 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) - : WebFloatRect(); + : gfx::RectF(); immersive_presentation_provider_->UpdateLayerBounds( - frame_id_, left_coords, right_coords, WebSize(width, height)); + frame_id_, left_coords, right_coords, gfx::Size(width, height)); } void XRFrameProvider::Dispose() { @@ -580,7 +602,7 @@ void XRFrameProvider::Dispose() { // TODO(bajones): Do something for outstanding frame requests? } -void XRFrameProvider::Trace(blink::Visitor* visitor) { +void XRFrameProvider::Trace(Visitor* visitor) { visitor->Trace(xr_); visitor->Trace(frame_transport_); visitor->Trace(immersive_session_); 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 index 8fd58cc40a5..6ed8d94dee1 100644 --- a/chromium/third_party/blink/renderer/modules/xr/xr_frame_provider.h +++ b/chromium/third_party/blink/renderer/modules/xr/xr_frame_provider.h @@ -14,16 +14,16 @@ namespace blink { -class XR; -class XRSession; class XRFrameTransport; +class XRSession; +class XRSystem; class XRWebGLLayer; // This class manages requesting and dispatching frame updates, which includes // pose information for a given XRDevice. class XRFrameProvider final : public GarbageCollected<XRFrameProvider> { public: - explicit XRFrameProvider(XR*); + explicit XRFrameProvider(XRSystem*); XRSession* immersive_session() const { return immersive_session_; } @@ -45,7 +45,7 @@ class XRFrameProvider final : public GarbageCollected<XRFrameProvider> { return immersive_data_provider_.get(); } - virtual void Trace(blink::Visitor*); + virtual void Trace(Visitor*); private: void OnImmersiveFrameData(device::mojom::blink::XRFrameDataPtr data); @@ -72,7 +72,7 @@ class XRFrameProvider final : public GarbageCollected<XRFrameProvider> { void ProcessScheduledFrame(device::mojom::blink::XRFrameDataPtr frame_data, double high_res_now_ms); - const Member<XR> xr_; + const Member<XRSystem> xr_; // Immersive session state Member<XRSession> immersive_session_; @@ -88,7 +88,7 @@ class XRFrameProvider final : public GarbageCollected<XRFrameProvider> { HeapHashMap<Member<XRSession>, mojo::Remote<device::mojom::blink::XRFrameDataProvider>> non_immersive_data_providers_; - HeapHashMap<Member<XRSession>, device::mojom::blink::VRPosePtr> + HeapHashMap<Member<XRSession>, device::mojom::blink::XRFrameDataPtr> requesting_sessions_; // This frame ID is XR-specific and is used to track when frames arrive at the 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 index 3232ba45c9c..12ebbb526c9 100644 --- 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 @@ -6,6 +6,7 @@ #include "third_party/blink/renderer/bindings/modules/v8/v8_xr_frame_request_callback.h" #include "third_party/blink/renderer/core/inspector/inspector_trace_events.h" +#include "third_party/blink/renderer/core/probe/async_task_id.h" #include "third_party/blink/renderer/core/probe/core_probes.h" #include "third_party/blink/renderer/modules/xr/xr_frame.h" #include "third_party/blink/renderer/modules/xr/xr_session.h" @@ -20,12 +21,13 @@ XRFrameRequestCallbackCollection::CallbackId XRFrameRequestCallbackCollection::RegisterCallback( V8XRFrameRequestCallback* callback) { CallbackId id = ++next_callback_id_; - auto add_result = - callbacks_.Set(id, CallbackAndAsyncTask(callback, probe::AsyncTaskId())); + auto add_result = callbacks_.Set( + id, + CallbackAndAsyncTask(callback, std::make_unique<probe::AsyncTaskId>())); pending_callbacks_.push_back(id); - probe::AsyncTaskScheduledBreakable(context_, "XRRequestFrame", - &add_result.stored_value->value.second); + probe::AsyncTaskScheduledBreakable( + context_, "XRRequestFrame", add_result.stored_value->value.second.get()); return id; } @@ -60,7 +62,7 @@ void XRFrameRequestCallbackCollection::ExecuteCallbacks(XRSession* session, if (it == current_callbacks_.end()) continue; - probe::AsyncTask async_task(context_, &it->value.second); + probe::AsyncTask async_task(context_, it->value.second.get()); probe::UserCallback probe(context_, "XRRequestFrame", AtomicString(), true); it->value.first->InvokeAndReportException(session, timestamp, frame); } @@ -68,7 +70,7 @@ void XRFrameRequestCallbackCollection::ExecuteCallbacks(XRSession* session, current_callbacks_.clear(); } -void XRFrameRequestCallbackCollection::Trace(blink::Visitor* visitor) { +void XRFrameRequestCallbackCollection::Trace(Visitor* visitor) { visitor->Trace(callbacks_); visitor->Trace(current_callbacks_); visitor->Trace(context_); 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 index d5258abdb28..dfc5344173a 100644 --- 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 @@ -5,7 +5,6 @@ #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/core/probe/async_task_id.h" #include "third_party/blink/renderer/platform/bindings/name_client.h" #include "third_party/blink/renderer/platform/heap/handle.h" @@ -16,6 +15,10 @@ class V8XRFrameRequestCallback; class XRFrame; class XRSession; +namespace probe { +class AsyncTaskId; +} + class XRFrameRequestCallbackCollection final : public GarbageCollected<XRFrameRequestCallbackCollection>, public NameClient { @@ -29,7 +32,7 @@ class XRFrameRequestCallbackCollection final bool IsEmpty() const { return !callbacks_.size(); } - void Trace(blink::Visitor*); + void Trace(Visitor*); const char* NameInHeapSnapshot() const override { return "XRFrameRequestCallbackCollection"; } @@ -41,8 +44,8 @@ class XRFrameRequestCallbackCollection final !WTF::IsHashTraitsEmptyValue<Traits, CallbackId>(id); } - using CallbackAndAsyncTask = - std::pair<Member<V8XRFrameRequestCallback>, probe::AsyncTaskId>; + using CallbackAndAsyncTask = std::pair<Member<V8XRFrameRequestCallback>, + std::unique_ptr<probe::AsyncTaskId>>; using CallbackMap = HeapHashMap<CallbackId, CallbackAndAsyncTask>; CallbackMap callbacks_; diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_grip_space.cc b/chromium/third_party/blink/renderer/modules/xr/xr_grip_space.cc index 0eb6ff3e93b..ac1fe4521ff 100644 --- a/chromium/third_party/blink/renderer/modules/xr/xr_grip_space.cc +++ b/chromium/third_party/blink/renderer/modules/xr/xr_grip_space.cc @@ -14,44 +14,33 @@ namespace blink { XRGripSpace::XRGripSpace(XRSession* session, XRInputSource* source) : XRSpace(session), input_source_(source) {} -XRPose* XRGripSpace::getPose(XRSpace* other_space, - const TransformationMatrix* mojo_from_viewer) { +std::unique_ptr<TransformationMatrix> XRGripSpace::MojoFromNative() { // Grip is only available when using tracked pointer for input. if (input_source_->TargetRayMode() != device::mojom::XRTargetRayMode::POINTING) { return nullptr; } - // Make sure the required pose matrices are available. - if (!mojo_from_viewer || !input_source_->MojoFromInput()) { + if (!input_source_->MojoFromInput()) return nullptr; - } - // Calculate grip pose in other_space, aka other_from_grip - std::unique_ptr<TransformationMatrix> other_from_grip = - other_space->SpaceFromInputForViewer(*(input_source_->MojoFromInput()), - *mojo_from_viewer); - if (!other_from_grip) { - return nullptr; - } + return std::make_unique<TransformationMatrix>( + *(input_source_->MojoFromInput())); +} + +std::unique_ptr<TransformationMatrix> XRGripSpace::NativeFromMojo() { + return TryInvert(MojoFromNative()); +} - // Account for any changes made to the reference space's origin offset so - // that things like teleportation works. - // - // This is offset_from_grip = offset_from_other * other_from_grip, - // where offset_from_other = inverse(other_from_offset). - // TODO(https://crbug.com/1008466): move originOffset to separate class? - TransformationMatrix offset_from_grip = - other_space->InverseOriginOffsetMatrix().Multiply(*other_from_grip); - return MakeGarbageCollected<XRPose>(offset_from_grip, - input_source_->emulatedPosition()); +bool XRGripSpace::EmulatedPosition() const { + return input_source_->emulatedPosition(); } base::Optional<XRNativeOriginInformation> XRGripSpace::NativeOrigin() const { return input_source_->nativeOrigin(); } -void XRGripSpace::Trace(blink::Visitor* visitor) { +void XRGripSpace::Trace(Visitor* visitor) { visitor->Trace(input_source_); XRSpace::Trace(visitor); } diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_grip_space.h b/chromium/third_party/blink/renderer/modules/xr/xr_grip_space.h index 0ffa42e6525..1f396f5efa7 100644 --- a/chromium/third_party/blink/renderer/modules/xr/xr_grip_space.h +++ b/chromium/third_party/blink/renderer/modules/xr/xr_grip_space.h @@ -14,12 +14,14 @@ namespace blink { class XRGripSpace : public XRSpace { public: XRGripSpace(XRSession* session, XRInputSource* input_source); - XRPose* getPose(XRSpace* other_space, - const TransformationMatrix* base_pose_matrix) override; + + std::unique_ptr<TransformationMatrix> MojoFromNative() override; + std::unique_ptr<TransformationMatrix> NativeFromMojo() override; + bool EmulatedPosition() const override; base::Optional<XRNativeOriginInformation> NativeOrigin() const override; - void Trace(blink::Visitor*) override; + void Trace(Visitor*) override; private: Member<XRInputSource> input_source_; diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_hit_result.cc b/chromium/third_party/blink/renderer/modules/xr/xr_hit_result.cc deleted file mode 100644 index b14b3e1ea87..00000000000 --- a/chromium/third_party/blink/renderer/modules/xr/xr_hit_result.cc +++ /dev/null @@ -1,22 +0,0 @@ -// 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_hit_result.h" - -#include "third_party/blink/renderer/modules/xr/xr_utils.h" -#include "third_party/blink/renderer/platform/transforms/transformation_matrix.h" - -namespace blink { -XRHitResult::XRHitResult(const TransformationMatrix& hit_transform) - : hit_transform_(std::make_unique<TransformationMatrix>(hit_transform)) {} - -XRHitResult::~XRHitResult() {} - -DOMFloat32Array* XRHitResult::hitMatrix() const { - if (!hit_transform_) - return nullptr; - return transformationMatrixToDOMFloat32Array(*hit_transform_); -} - -} // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_hit_result.h b/chromium/third_party/blink/renderer/modules/xr/xr_hit_result.h deleted file mode 100644 index 705bffb717d..00000000000 --- a/chromium/third_party/blink/renderer/modules/xr/xr_hit_result.h +++ /dev/null @@ -1,29 +0,0 @@ -// 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_HIT_RESULT_H_ -#define THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_HIT_RESULT_H_ - -#include "third_party/blink/renderer/core/typed_arrays/dom_typed_array.h" - -namespace blink { - -class TransformationMatrix; - -class XRHitResult final : public ScriptWrappable { - DEFINE_WRAPPERTYPEINFO(); - - public: - explicit XRHitResult(const TransformationMatrix&); - ~XRHitResult() override; - - DOMFloat32Array* hitMatrix() const; - - private: - const std::unique_ptr<TransformationMatrix> hit_transform_; -}; - -} // namespace blink - -#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_HIT_RESULT_H_ diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_hit_result.idl b/chromium/third_party/blink/renderer/modules/xr/xr_hit_result.idl deleted file mode 100644 index de430e69503..00000000000 --- a/chromium/third_party/blink/renderer/modules/xr/xr_hit_result.idl +++ /dev/null @@ -1,7 +0,0 @@ -// 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. - -[RuntimeEnabled=WebXRHitTest, SecureContext, Exposed=Window] interface XRHitResult { - readonly attribute Float32Array hitMatrix; -};
\ No newline at end of file diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_hit_test_options_init.idl b/chromium/third_party/blink/renderer/modules/xr/xr_hit_test_options_init.idl index cb535b70824..0973892b598 100644 --- a/chromium/third_party/blink/renderer/modules/xr/xr_hit_test_options_init.idl +++ b/chromium/third_party/blink/renderer/modules/xr/xr_hit_test_options_init.idl @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +[RuntimeEnabled=WebXRHitTestEntityTypes] enum XRHitTestTrackableType { "point", "plane" @@ -9,6 +10,6 @@ enum XRHitTestTrackableType { dictionary XRHitTestOptionsInit { required XRSpace space; - FrozenArray<XRHitTestTrackableType> entityTypes; + [RuntimeEnabled=WebXRHitTestEntityTypes] FrozenArray<XRHitTestTrackableType> entityTypes; XRRay offsetRay; }; diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_hit_test_result.cc b/chromium/third_party/blink/renderer/modules/xr/xr_hit_test_result.cc index 032e9a19bdf..58df9fb6808 100644 --- a/chromium/third_party/blink/renderer/modules/xr/xr_hit_test_result.cc +++ b/chromium/third_party/blink/renderer/modules/xr/xr_hit_test_result.cc @@ -6,26 +6,56 @@ #include "third_party/blink/renderer/modules/xr/xr_hit_test_source.h" #include "third_party/blink/renderer/modules/xr/xr_pose.h" +#include "third_party/blink/renderer/modules/xr/xr_rigid_transform.h" +#include "third_party/blink/renderer/modules/xr/xr_session.h" #include "third_party/blink/renderer/modules/xr/xr_space.h" namespace blink { -XRHitTestResult::XRHitTestResult(const TransformationMatrix& pose) - : pose_(std::make_unique<TransformationMatrix>(pose)) {} +XRHitTestResult::XRHitTestResult( + XRSession* session, + const device::mojom::blink::XRHitResult& hit_result) + : session_(session), + mojo_from_this_(std::make_unique<TransformationMatrix>( + hit_result.hit_matrix.matrix())), + plane_id_(hit_result.plane_id != 0 + ? base::Optional<uint64_t>(hit_result.plane_id) + : base::nullopt) {} -XRPose* XRHitTestResult::getPose(XRSpace* relative_to) { - DCHECK(relative_to->MojoFromSpace()); +XRPose* XRHitTestResult::getPose(XRSpace* other) { + auto maybe_other_space_native_from_mojo = other->NativeFromMojo(); + DCHECK(maybe_other_space_native_from_mojo); - auto mojo_from_this = *pose_; + auto mojo_from_this = *mojo_from_this_; - auto mojo_from_other = *relative_to->MojoFromSpace(); - DCHECK(mojo_from_other.IsInvertible()); + auto other_native_from_mojo = *maybe_other_space_native_from_mojo; + auto other_offset_from_other_native = other->OffsetFromNativeMatrix(); - auto other_from_mojo = mojo_from_other.Inverse(); + auto other_offset_from_mojo = + other_offset_from_other_native * other_native_from_mojo; - auto other_from_this = other_from_mojo * mojo_from_this; + auto other_offset_from_this = other_offset_from_mojo * mojo_from_this; - return MakeGarbageCollected<XRPose>(other_from_this, false); + return MakeGarbageCollected<XRPose>(other_offset_from_this, false); } +ScriptPromise XRHitTestResult::createAnchor(ScriptState* script_state, + XRRigidTransform* initial_pose, + ExceptionState& exception_state) { + DVLOG(2) << __func__; + + if (!initial_pose) { + exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError, + XRSession::kNoRigidTransformSpecified); + return {}; + } + + return session_->CreateAnchor(script_state, initial_pose->TransformMatrix(), + *mojo_from_this_, plane_id_, exception_state); +} + +void XRHitTestResult::Trace(Visitor* visitor) { + visitor->Trace(session_); + ScriptWrappable::Trace(visitor); +} } // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_hit_test_result.h b/chromium/third_party/blink/renderer/modules/xr/xr_hit_test_result.h index 163c1fcac95..9d070373885 100644 --- a/chromium/third_party/blink/renderer/modules/xr/xr_hit_test_result.h +++ b/chromium/third_party/blink/renderer/modules/xr/xr_hit_test_result.h @@ -5,24 +5,43 @@ #ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_HIT_TEST_RESULT_H_ #define THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_HIT_TEST_RESULT_H_ +#include "base/optional.h" +#include "device/vr/public/mojom/vr_service.mojom-blink.h" +#include "third_party/blink/renderer/bindings/core/v8/script_promise.h" #include "third_party/blink/renderer/platform/bindings/script_wrappable.h" namespace blink { +class ExceptionState; +class ScriptState; class TransformationMatrix; class XRPose; +class XRRigidTransform; +class XRSession; class XRSpace; class XRHitTestResult : public ScriptWrappable { DEFINE_WRAPPERTYPEINFO(); public: - explicit XRHitTestResult(const TransformationMatrix& pose); + explicit XRHitTestResult(XRSession* session, + const device::mojom::blink::XRHitResult& hit_result); XRPose* getPose(XRSpace* relative_to); + ScriptPromise createAnchor(ScriptState* script_state, + XRRigidTransform* initial_pose, + ExceptionState& exception_state); + + void Trace(Visitor* visitor) override; + private: - std::unique_ptr<TransformationMatrix> pose_; + Member<XRSession> session_; + + // Hit test results do not have origin-offset so mojo_from_this_ contains + // mojo_from_this with origin-offset (identity) already applied. + std::unique_ptr<TransformationMatrix> mojo_from_this_; + base::Optional<uint64_t> plane_id_; }; } // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_hit_test_result.idl b/chromium/third_party/blink/renderer/modules/xr/xr_hit_test_result.idl index 0019eaa7606..692f78680f3 100644 --- a/chromium/third_party/blink/renderer/modules/xr/xr_hit_test_result.idl +++ b/chromium/third_party/blink/renderer/modules/xr/xr_hit_test_result.idl @@ -4,5 +4,8 @@ [SecureContext, Exposed=Window, RuntimeEnabled=WebXRHitTest] interface XRHitTestResult { - XRPose? getPose(XRSpace relative_to); + XRPose? getPose(XRSpace relative_to); + + [RuntimeEnabled=WebXRIncubations, CallWith=ScriptState, RaisesException] + Promise<XRAnchor> createAnchor(XRRigidTransform initial_pose); }; diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_hit_test_source.cc b/chromium/third_party/blink/renderer/modules/xr/xr_hit_test_source.cc index 8a49f3591a7..9e539e62dc9 100644 --- a/chromium/third_party/blink/renderer/modules/xr/xr_hit_test_source.cc +++ b/chromium/third_party/blink/renderer/modules/xr/xr_hit_test_source.cc @@ -35,7 +35,8 @@ HeapVector<Member<XRHitTestResult>> XRHitTestSource::Results() { HeapVector<Member<XRHitTestResult>> results; for (const auto& result : last_frame_results_) { - results.emplace_back(MakeGarbageCollected<XRHitTestResult>(*result)); + results.emplace_back( + MakeGarbageCollected<XRHitTestResult>(xr_session_, result)); } return results; @@ -46,11 +47,14 @@ void XRHitTestSource::Update( last_frame_results_.clear(); for (auto& result : hit_test_results) { - last_frame_results_.push_back( - std::make_unique<TransformationMatrix>(result->hit_matrix.matrix())); + DVLOG(3) << __func__ << ": processing hit test result, hit matrix: " + << result->hit_matrix.ToString() + << ", plane_id=" << result->plane_id; + last_frame_results_.push_back(*result); } } -void XRHitTestSource::Trace(blink::Visitor* visitor) { + +void XRHitTestSource::Trace(Visitor* visitor) { visitor->Trace(xr_session_); ScriptWrappable::Trace(visitor); } diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_hit_test_source.h b/chromium/third_party/blink/renderer/modules/xr/xr_hit_test_source.h index 419ee803009..672909b3add 100644 --- a/chromium/third_party/blink/renderer/modules/xr/xr_hit_test_source.h +++ b/chromium/third_party/blink/renderer/modules/xr/xr_hit_test_source.h @@ -10,7 +10,6 @@ #include "third_party/blink/renderer/platform/bindings/script_wrappable.h" #include "device/vr/public/mojom/vr_service.mojom-blink-forward.h" -#include "third_party/blink/renderer/platform/transforms/transformation_matrix.h" namespace blink { @@ -35,13 +34,13 @@ class XRHitTestSource : public ScriptWrappable { void Update( const Vector<device::mojom::blink::XRHitResultPtr>& hit_test_results); - void Trace(blink::Visitor*) override; + void Trace(Visitor*) override; private: const uint64_t id_; Member<XRSession> xr_session_; - Vector<std::unique_ptr<TransformationMatrix>> last_frame_results_; + Vector<device::mojom::blink::XRHitResult> last_frame_results_; }; } // namespace blink 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 index af14ac91d1f..b393c0cb3c6 100644 --- a/chromium/third_party/blink/renderer/modules/xr/xr_input_source.cc +++ b/chromium/third_party/blink/renderer/modules/xr/xr_input_source.cc @@ -5,12 +5,19 @@ #include "third_party/blink/renderer/modules/xr/xr_input_source.h" #include "base/time/time.h" +#include "third_party/blink/renderer/core/dom/element.h" +#include "third_party/blink/renderer/core/dom/events/event_dispatcher.h" +#include "third_party/blink/renderer/core/dom/events/event_path.h" #include "third_party/blink/renderer/core/frame/local_frame.h" -#include "third_party/blink/renderer/modules/xr/xr.h" +#include "third_party/blink/renderer/core/html/html_frame_element_base.h" +#include "third_party/blink/renderer/core/input/event_handling_util.h" +#include "third_party/blink/renderer/core/layout/hit_test_location.h" #include "third_party/blink/renderer/modules/xr/xr_grip_space.h" #include "third_party/blink/renderer/modules/xr/xr_input_source_event.h" #include "third_party/blink/renderer/modules/xr/xr_session.h" +#include "third_party/blink/renderer/modules/xr/xr_session_event.h" #include "third_party/blink/renderer/modules/xr/xr_space.h" +#include "third_party/blink/renderer/modules/xr/xr_system.h" #include "third_party/blink/renderer/modules/xr/xr_target_ray_space.h" #include "third_party/blink/renderer/modules/xr/xr_utils.h" @@ -69,7 +76,9 @@ XRInputSource* XRInputSource::CreateOrUpdateFrom( updated_source = MakeGarbageCollected<XRInputSource>(*other); } - updated_source->UpdateGamepad(state->gamepad); + if (updated_source->state_.is_visible) { + updated_source->UpdateGamepad(state->gamepad); + } // Update the input source's description if this state update includes them. if (state->description) { @@ -79,8 +88,10 @@ XRInputSource* XRInputSource::CreateOrUpdateFrom( updated_source->state_.target_ray_mode = desc->target_ray_mode; updated_source->state_.handedness = desc->handedness; - updated_source->input_from_pointer_ = - TryGetTransformationMatrix(desc->input_from_pointer); + if (updated_source->state_.is_visible) { + updated_source->input_from_pointer_ = + TryGetTransformationMatrix(desc->input_from_pointer); + } updated_source->state_.profiles.clear(); for (const auto& name : state->description->profiles) { @@ -88,8 +99,10 @@ XRInputSource* XRInputSource::CreateOrUpdateFrom( } } - updated_source->mojo_from_input_ = - TryGetTransformationMatrix(state->mojo_from_input); + if (updated_source->state_.is_visible) { + updated_source->mojo_from_input_ = + TryGetTransformationMatrix(state->mojo_from_input); + } updated_source->state_.emulated_position = state->emulated_position; @@ -151,6 +164,9 @@ XRSpace* XRInputSource::targetRaySpace() const { } XRSpace* XRInputSource::gripSpace() const { + if (!state_.is_visible) + return nullptr; + if (state_.target_ray_mode == device::mojom::XRTargetRayMode::POINTING) { return grip_space_; } @@ -189,7 +205,9 @@ bool XRInputSource::InvalidatesSameObject( void XRInputSource::SetInputFromPointer( const TransformationMatrix* input_from_pointer) { - input_from_pointer_ = TryGetTransformationMatrix(input_from_pointer); + if (state_.is_visible) { + input_from_pointer_ = TryGetTransformationMatrix(input_from_pointer); + } } void XRInputSource::SetGamepadConnected(bool state) { @@ -216,6 +234,7 @@ base::Optional<XRNativeOriginInformation> XRInputSource::nativeOrigin() const { } void XRInputSource::OnSelectStart() { + DVLOG(3) << __func__; // Discard duplicate events and ones after the session has ended. if (state_.primary_input_pressed || session_->ended()) return; @@ -223,6 +242,7 @@ void XRInputSource::OnSelectStart() { state_.primary_input_pressed = true; state_.selection_cancelled = false; + DVLOG(3) << __func__ << ": dispatch selectstart event"; XRInputSourceEvent* event = CreateInputSourceEvent(event_type_names::kSelectstart); session_->DispatchEvent(*event); @@ -235,6 +255,7 @@ void XRInputSource::OnSelectStart() { } void XRInputSource::OnSelectEnd() { + DVLOG(3) << __func__; // Discard duplicate events and ones after the session has ended. if (!state_.primary_input_pressed || session_->ended()) return; @@ -245,6 +266,7 @@ void XRInputSource::OnSelectEnd() { if (!frame) return; + DVLOG(3) << __func__ << ": dispatch selectend event"; XRInputSourceEvent* event = CreateInputSourceEvent(event_type_names::kSelectend); session_->DispatchEvent(*event); @@ -257,6 +279,7 @@ void XRInputSource::OnSelectEnd() { } void XRInputSource::OnSelect() { + DVLOG(3) << __func__; // If a select was fired but we had not previously started the selection it // indicates a sub-frame or instantaneous select event, and we should fire a // selectstart prior to the selectend. @@ -272,6 +295,7 @@ void XRInputSource::OnSelect() { if (!state_.selection_cancelled && !session_->ended()) { if (!frame) return; + DVLOG(3) << __func__ << ": dispatch select event"; XRInputSourceEvent* event = CreateInputSourceEvent(event_type_names::kSelect); session_->DispatchEvent(*event); @@ -283,16 +307,114 @@ void XRInputSource::OnSelect() { OnSelectEnd(); } -void XRInputSource::UpdateSelectState( - const device::mojom::blink::XRInputSourceStatePtr& state) { - if (!state) +void XRInputSource::OnSqueezeStart() { + DVLOG(3) << __func__; + // Discard duplicate events and ones after the session has ended. + if (state_.primary_squeeze_pressed || session_->ended()) + return; + + state_.primary_squeeze_pressed = true; + state_.squeezing_cancelled = false; + + XRInputSourceEvent* event = + CreateInputSourceEvent(event_type_names::kSqueezestart); + session_->DispatchEvent(*event); + + if (event->defaultPrevented()) + state_.squeezing_cancelled = true; + + // Ensure the frame cannot be used outside of the event handler. + event->frame()->Deactivate(); +} + +void XRInputSource::OnSqueezeEnd() { + DVLOG(3) << __func__; + // Discard duplicate events and ones after the session has ended. + if (!state_.primary_squeeze_pressed || session_->ended()) + return; + + state_.primary_squeeze_pressed = false; + + LocalFrame* frame = session_->xr()->GetFrame(); + if (!frame) + return; + + DVLOG(3) << __func__ << ": dispatch squeezeend event"; + XRInputSourceEvent* event = + CreateInputSourceEvent(event_type_names::kSqueezeend); + session_->DispatchEvent(*event); + + if (event->defaultPrevented()) + state_.squeezing_cancelled = true; + + // Ensure the frame cannot be used outside of the event handler. + event->frame()->Deactivate(); +} + +void XRInputSource::OnSqueeze() { + DVLOG(3) << __func__; + // If a squeeze was fired but we had not previously started the squeezing it + // indicates a sub-frame or instantaneous squeeze event, and we should fire a + // squeezestart prior to the squeezeend. + if (!state_.primary_squeeze_pressed) { + OnSqueezeStart(); + } + + LocalFrame* frame = session_->xr()->GetFrame(); + LocalFrame::NotifyUserActivation(frame); + + // If SelectStart caused the session to end, we shouldn't try to fire the + // select event. + if (!state_.squeezing_cancelled && !session_->ended()) { + if (!frame) + return; + DVLOG(3) << __func__ << ": dispatch squeeze event"; + XRInputSourceEvent* event = + CreateInputSourceEvent(event_type_names::kSqueeze); + session_->DispatchEvent(*event); + + // Ensure the frame cannot be used outside of the event handler. + event->frame()->Deactivate(); + } + + OnSqueezeEnd(); +} + +void XRInputSource::UpdateButtonStates( + const device::mojom::blink::XRInputSourceStatePtr& new_state) { + if (!new_state) return; + DVLOG(3) << __func__ << ": state_.is_visible=" << state_.is_visible + << ", state_.xr_select_events_suppressed=" + << state_.xr_select_events_suppressed + << ", new_state->primary_input_clicked=" + << new_state->primary_input_clicked; + + if (!state_.is_visible) { + DVLOG(3) << __func__ << ": input NOT VISIBLE"; + if (new_state->primary_input_clicked) { + DVLOG(3) << __func__ << ": got click while invisible, SUPPRESS end"; + state_.xr_select_events_suppressed = false; + } + return; + } + if (state_.xr_select_events_suppressed) { + if (new_state->primary_input_clicked) { + DVLOG(3) << __func__ << ": got click, SUPPRESS end"; + state_.xr_select_events_suppressed = false; + } + DVLOG(3) << __func__ << ": overlay input select SUPPRESSED"; + return; + } + + DCHECK(!state_.xr_select_events_suppressed); + // Handle state change of the primary input, which may fire events - if (state->primary_input_clicked) + if (new_state->primary_input_clicked) OnSelect(); - if (state->primary_input_pressed) { + if (new_state->primary_input_pressed) { OnSelectStart(); } else if (state_.primary_input_pressed) { // May get here if the input source was previously pressed but now isn't, @@ -302,6 +424,131 @@ void XRInputSource::UpdateSelectState( // usual select event. OnSelectEnd(); } + + // Handle state change of the primary input, which may fire events + if (new_state->primary_squeeze_clicked) + OnSqueeze(); + + if (new_state->primary_squeeze_pressed) { + OnSqueezeStart(); + } else if (state_.primary_squeeze_pressed) { + // May get here if the input source was previously pressed but now isn't, + // but the input source did not set primary_squeeze_clicked to true. We will + // treat this as a cancelled squeezeing, firing the squeezeend event so the + // page stays in sync with the controller state but won't fire the + // usual squeeze event. + OnSqueezeEnd(); + } +} + +void XRInputSource::ProcessOverlayHitTest( + Element* overlay_element, + const device::mojom::blink::XRInputSourceStatePtr& new_state) { + DVLOG(3) << __func__ << ": state_.xr_select_events_suppressed=" + << state_.xr_select_events_suppressed; + + DCHECK(overlay_element); + DCHECK(new_state->overlay_pointer_position); + + // Do a hit test at the overlay pointer position to see if the pointer + // intersects a cross origin iframe. If yes, set the visibility to false which + // causes targetRaySpace and gripSpace to return null poses. + FloatPoint point(new_state->overlay_pointer_position->x(), + new_state->overlay_pointer_position->y()); + DVLOG(3) << __func__ << ": hit test point=" << point; + + HitTestRequest::HitTestRequestType hit_type = HitTestRequest::kTouchEvent | + HitTestRequest::kReadOnly | + HitTestRequest::kActive; + + HitTestResult result = event_handling_util::HitTestResultInFrame( + overlay_element->GetDocument().GetFrame(), HitTestLocation(point), + hit_type); + DVLOG(3) << __func__ << ": hit test InnerElement=" << result.InnerElement(); + + Element* hit_element = result.InnerElement(); + if (!hit_element) { + return; + } + + // Check if the hit element is cross-origin content. In addition to an iframe, + // this could potentially be an old-style frame in a frameset, so check for + // the common base class to cover both. (There's no intention to actively + // support framesets for DOM Overlay, but this helps prevent them from + // being used as a mechanism for information leaks.) + HTMLFrameElementBase* frame = DynamicTo<HTMLFrameElementBase>(hit_element); + if (frame) { + Document* hit_document = frame->contentDocument(); + if (hit_document) { + Frame* hit_frame = hit_document->GetFrame(); + DCHECK(hit_frame); + if (hit_frame->IsCrossOriginToMainFrame()) { + // Mark the input source as invisible until the primary button is + // released. + state_.is_visible = false; + + // If this is the first touch, also suppress events, even if it + // ends up being released outside the frame later. + if (!state_.primary_input_pressed) { + state_.xr_select_events_suppressed = true; + } + + DVLOG(3) + << __func__ + << ": input source overlaps with cross origin content, is_visible=" + << state_.is_visible << ", xr_select_events_suppressed=" + << state_.xr_select_events_suppressed; + return; + } + } + } + + // If we get here, the touch didn't hit a cross origin frame. Set the + // controller spaces visible. + state_.is_visible = true; + + // Now that the visibility check has finished, mark non-primary input sources + // as suppressed. + if (new_state->is_auxiliary) { + state_.xr_select_events_suppressed = true; + } + + // Now check if this is a new primary button press. If yes, send a + // beforexrselect event to give the application an opportunity to cancel the + // XR input "select" sequence that would normally be caused by this. + + if (state_.xr_select_events_suppressed) { + DVLOG(3) << __func__ << ": using overlay input provider: SUPPRESS ongoing"; + return; + } + + if (state_.primary_input_pressed) { + DVLOG(3) << __func__ << ": ongoing press, not checking again"; + return; + } + + bool is_primary_press = + new_state->primary_input_pressed || new_state->primary_input_clicked; + if (!is_primary_press) { + DVLOG(3) << __func__ << ": no button press, ignoring"; + return; + } + + // The event needs to be cancelable (obviously), bubble (so that parent + // elements can handle it), and composed (so that it crosses shadow DOM + // boundaries, including UA-added shadow DOM). + Event* event = MakeGarbageCollected<XRSessionEvent>( + event_type_names::kBeforexrselect, session_, Event::Bubbles::kYes, + Event::Cancelable::kYes, Event::ComposedMode::kComposed); + + hit_element->DispatchEvent(*event); + bool default_prevented = event->defaultPrevented(); + + // Keep the input source visible, so it's exposed in the input sources array, + // but don't generate XR select events for the current button sequence. + state_.xr_select_events_suppressed = default_prevented; + DVLOG(3) << __func__ << ": state_.xr_select_events_suppressed=" + << state_.xr_select_events_suppressed; } void XRInputSource::OnRemoved() { @@ -319,6 +566,20 @@ void XRInputSource::OnRemoved() { event->frame()->Deactivate(); } + if (state_.primary_squeeze_pressed) { + state_.primary_squeeze_pressed = false; + + XRInputSourceEvent* event = + CreateInputSourceEvent(event_type_names::kSqueezeend); + session_->DispatchEvent(*event); + + if (event->defaultPrevented()) + state_.squeezing_cancelled = true; + + // Ensure the frame cannot be used outside of the event handler. + event->frame()->Deactivate(); + } + SetGamepadConnected(false); } @@ -328,7 +589,7 @@ XRInputSourceEvent* XRInputSource::CreateInputSourceEvent( return XRInputSourceEvent::Create(type, presentation_frame, this); } -void XRInputSource::Trace(blink::Visitor* visitor) { +void XRInputSource::Trace(Visitor* visitor) { visitor->Trace(session_); visitor->Trace(target_ray_space_); visitor->Trace(grip_space_); 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 index c99dca23ad8..d61df78f3a7 100644 --- a/chromium/third_party/blink/renderer/modules/xr/xr_input_source.h +++ b/chromium/third_party/blink/renderer/modules/xr/xr_input_source.h @@ -20,6 +20,7 @@ class Gamepad; namespace blink { +class Element; class XRGripSpace; class XRInputSourceEvent; class XRSession; @@ -85,11 +86,25 @@ class XRInputSource : public ScriptWrappable, public Gamepad::Client { void OnSelectStart(); void OnSelectEnd(); void OnSelect(); - void UpdateSelectState( + + void OnSqueezeStart(); + void OnSqueezeEnd(); + void OnSqueeze(); + + void UpdateButtonStates( const device::mojom::blink::XRInputSourceStatePtr& state); void OnRemoved(); - void Trace(blink::Visitor*) override; + // Check which element within the DOM overlay is hit by the input source's + // pointer ray, and update primary input state based on that, including + // suppressing event data for cross-origin iframes. For background, see + // https://immersive-web.github.io/dom-overlays/#cross-origin-content-events + void ProcessOverlayHitTest( + Element* overlay_element, + const device::mojom::blink::XRInputSourceStatePtr& state); + bool IsVisible() const { return state_.is_visible; } + + void Trace(Visitor*) override; private: // In order to ease copying, any new member variables that can be trivially @@ -98,6 +113,21 @@ class XRInputSource : public ScriptWrappable, public Gamepad::Client { int16_t active_frame_id = -1; bool primary_input_pressed = false; bool selection_cancelled = false; + bool primary_squeeze_pressed = false; + bool squeezing_cancelled = false; + // Input sources have two separate states, visible/invisible and select + // events active/suppressed. All input sources, including auxiliary, should + // use DOM overlay hit test (the ProcessOverlayHitTest() method) to check if + // they intersect cross-origin content. If that's the case, the input source + // is set as invisible, and must not return poses or hit test results. This + // also automatically suppresses select events (this matches the "poses are + // limited" conditional in the main WebXR spec). If the hit test doesn't + // intersect cross-origin content, and if this is the first touch, it fires + // a beforexrselect event and suppresses select events if that's been + // preventDefault()ed. For auxiliary input sources, the event does not need + // to be fired - per spec, their select events need to be suppressed anyway. + bool xr_select_events_suppressed = false; + bool is_visible = true; const uint32_t source_id; device::mojom::XRHandedness handedness = device::mojom::XRHandedness::NONE; device::mojom::XRTargetRayMode target_ray_mode; 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 index 78ee80c2c2c..d1869d2fe85 100644 --- a/chromium/third_party/blink/renderer/modules/xr/xr_input_source.idl +++ b/chromium/third_party/blink/renderer/modules/xr/xr_input_source.idl @@ -23,6 +23,6 @@ enum XRTargetRayMode { readonly attribute XRTargetRayMode targetRayMode; [SameObject] readonly attribute XRSpace targetRaySpace; [SameObject] readonly attribute XRSpace? gripSpace; - [SameObject, Measure, RuntimeEnabled=WebXrGamepadModule] readonly attribute Gamepad? gamepad; + [SameObject, Measure] readonly attribute Gamepad? gamepad; [SameObject, SaveSameObject] readonly attribute FrozenArray<DOMString> profiles; }; diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_input_source_array.cc b/chromium/third_party/blink/renderer/modules/xr/xr_input_source_array.cc index f39325c2c2c..bbd561b3cf1 100644 --- a/chromium/third_party/blink/renderer/modules/xr/xr_input_source_array.cc +++ b/chromium/third_party/blink/renderer/modules/xr/xr_input_source_array.cc @@ -43,7 +43,7 @@ void XRInputSourceArray::SetWithSourceId(uint32_t source_id, input_sources_.Set(source_id, input_source); } -void XRInputSourceArray::Trace(blink::Visitor* visitor) { +void XRInputSourceArray::Trace(Visitor* visitor) { visitor->Trace(input_sources_); ScriptWrappable::Trace(visitor); } diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_input_source_array.h b/chromium/third_party/blink/renderer/modules/xr/xr_input_source_array.h index 0c92eb0d24e..721761149f9 100644 --- a/chromium/third_party/blink/renderer/modules/xr/xr_input_source_array.h +++ b/chromium/third_party/blink/renderer/modules/xr/xr_input_source_array.h @@ -23,7 +23,7 @@ class XRInputSourceArray : public ScriptWrappable { void RemoveWithSourceId(uint32_t source_id); void SetWithSourceId(uint32_t source_id, XRInputSource* input_source); - void Trace(blink::Visitor*) override; + void Trace(Visitor*) override; private: HeapHashMap<uint32_t, Member<XRInputSource>> input_sources_; 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 index a59842c8e74..6e885b9da63 100644 --- 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 @@ -31,7 +31,7 @@ const AtomicString& XRInputSourceEvent::InterfaceName() const { return event_interface_names::kXRInputSourceEvent; } -void XRInputSourceEvent::Trace(blink::Visitor* visitor) { +void XRInputSourceEvent::Trace(Visitor* visitor) { visitor->Trace(frame_); visitor->Trace(input_source_); Event::Trace(visitor); 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 index f7e8c286e5e..a9696357013 100644 --- 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 @@ -5,10 +5,10 @@ #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/bindings/modules/v8/v8_xr_input_source_event_init.h" #include "third_party/blink/renderer/modules/event_modules.h" #include "third_party/blink/renderer/modules/xr/xr_frame.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" namespace blink { @@ -40,7 +40,7 @@ class XRInputSourceEvent final : public Event { const AtomicString& InterfaceName() const override; - void Trace(blink::Visitor*) override; + void Trace(Visitor*) override; private: Member<XRFrame> frame_; 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 index d4e4a92d973..aaaf2931115 100644 --- 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 @@ -5,9 +5,9 @@ [ SecureContext, Exposed=Window, - RuntimeEnabled=WebXR, - Constructor(DOMString type, XRInputSourceEventInit eventInitDict) + RuntimeEnabled=WebXR ] interface XRInputSourceEvent : Event { + constructor(DOMString type, XRInputSourceEventInit eventInitDict); [SameObject] readonly attribute XRFrame frame; [SameObject] readonly attribute XRInputSource inputSource; }; diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_input_sources_change_event.cc b/chromium/third_party/blink/renderer/modules/xr/xr_input_sources_change_event.cc index ca92e785456..ec5dfc9ea36 100644 --- a/chromium/third_party/blink/renderer/modules/xr/xr_input_sources_change_event.cc +++ b/chromium/third_party/blink/renderer/modules/xr/xr_input_sources_change_event.cc @@ -34,7 +34,7 @@ const AtomicString& XRInputSourcesChangeEvent::InterfaceName() const { return event_interface_names::kXRInputSourcesChangeEvent; } -void XRInputSourcesChangeEvent::Trace(blink::Visitor* visitor) { +void XRInputSourcesChangeEvent::Trace(Visitor* visitor) { visitor->Trace(session_); visitor->Trace(added_); visitor->Trace(removed_); diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_input_sources_change_event.h b/chromium/third_party/blink/renderer/modules/xr/xr_input_sources_change_event.h index fe4940c331b..94786139334 100644 --- a/chromium/third_party/blink/renderer/modules/xr/xr_input_sources_change_event.h +++ b/chromium/third_party/blink/renderer/modules/xr/xr_input_sources_change_event.h @@ -5,9 +5,9 @@ #ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_INPUT_SOURCES_CHANGE_EVENT_H_ #define THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_INPUT_SOURCES_CHANGE_EVENT_H_ +#include "third_party/blink/renderer/bindings/modules/v8/v8_xr_input_sources_change_event_init.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_sources_change_event_init.h" #include "third_party/blink/renderer/modules/xr/xr_session.h" namespace blink { @@ -45,7 +45,7 @@ class XRInputSourcesChangeEvent final : public Event { const AtomicString& InterfaceName() const override; - void Trace(blink::Visitor*) override; + void Trace(Visitor*) override; private: Member<XRSession> session_; diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_input_sources_change_event.idl b/chromium/third_party/blink/renderer/modules/xr/xr_input_sources_change_event.idl index 3d3acfa8b02..7a6cfcabd41 100644 --- a/chromium/third_party/blink/renderer/modules/xr/xr_input_sources_change_event.idl +++ b/chromium/third_party/blink/renderer/modules/xr/xr_input_sources_change_event.idl @@ -5,9 +5,9 @@ [ SecureContext, Exposed=Window, - RuntimeEnabled=WebXR, - Constructor(DOMString type, XRInputSourcesChangeEventInit eventInitDict) + RuntimeEnabled=WebXR ] interface XRInputSourcesChangeEvent : Event { + constructor(DOMString type, XRInputSourcesChangeEventInit eventInitDict); [SameObject] readonly attribute XRSession session; [SameObject, SaveSameObject] readonly attribute FrozenArray<XRInputSource> added; [SameObject, SaveSameObject] readonly attribute FrozenArray<XRInputSource> removed; diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_light_estimation.cc b/chromium/third_party/blink/renderer/modules/xr/xr_light_estimation.cc new file mode 100644 index 00000000000..cb4c72bc4b2 --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/xr/xr_light_estimation.cc @@ -0,0 +1,38 @@ +// Copyright 2019 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_light_estimation.h" + +#include "device/vr/public/mojom/vr_service.mojom-blink.h" +#include "third_party/blink/renderer/modules/xr/xr_light_probe.h" +#include "third_party/blink/renderer/modules/xr/xr_reflection_probe.h" + +namespace blink { + +XRLightEstimation::XRLightEstimation( + const device::mojom::blink::XRLightEstimationData& data) { + if (data.light_probe) { + light_probe_ = MakeGarbageCollected<XRLightProbe>(*data.light_probe); + } + if (data.reflection_probe) { + reflection_probe_ = + MakeGarbageCollected<XRReflectionProbe>(*data.reflection_probe); + } +} + +XRLightProbe* XRLightEstimation::lightProbe() const { + return light_probe_.Get(); +} + +XRReflectionProbe* XRLightEstimation::reflectionProbe() const { + return reflection_probe_.Get(); +} + +void XRLightEstimation::Trace(Visitor* visitor) { + visitor->Trace(light_probe_); + visitor->Trace(reflection_probe_); + ScriptWrappable::Trace(visitor); +} + +} // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_light_estimation.h b/chromium/third_party/blink/renderer/modules/xr/xr_light_estimation.h new file mode 100644 index 00000000000..d4d78ab6639 --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/xr/xr_light_estimation.h @@ -0,0 +1,35 @@ +// Copyright 2019 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_LIGHT_ESTIMATION_H_ +#define THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_LIGHT_ESTIMATION_H_ + +#include "device/vr/public/mojom/vr_service.mojom-blink-forward.h" +#include "third_party/blink/renderer/platform/bindings/script_wrappable.h" + +namespace blink { + +class XRLightProbe; +class XRReflectionProbe; + +class XRLightEstimation : public ScriptWrappable { + DEFINE_WRAPPERTYPEINFO(); + + public: + explicit XRLightEstimation( + const device::mojom::blink::XRLightEstimationData& data); + + XRLightProbe* lightProbe() const; + XRReflectionProbe* reflectionProbe() const; + + void Trace(Visitor* visitor) override; + + private: + Member<XRLightProbe> light_probe_; + Member<XRReflectionProbe> reflection_probe_; +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_LIGHT_ESTIMATION_H_ diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_light_estimation.idl b/chromium/third_party/blink/renderer/modules/xr/xr_light_estimation.idl new file mode 100644 index 00000000000..fdc12a618f8 --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/xr/xr_light_estimation.idl @@ -0,0 +1,14 @@ +// Copyright 2019 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, + Exposed=Window, + RuntimeEnabled=WebXRIncubations +] +interface XRLightEstimation { + readonly attribute XRLightProbe? lightProbe; + readonly attribute XRReflectionProbe? reflectionProbe; +}; + diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_light_estimation_state.cc b/chromium/third_party/blink/renderer/modules/xr/xr_light_estimation_state.cc new file mode 100644 index 00000000000..5e7b73d317c --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/xr/xr_light_estimation_state.cc @@ -0,0 +1,20 @@ +// Copyright 2019 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_light_estimation_state.h" + +#include "third_party/blink/renderer/bindings/modules/v8/v8_xr_light_estimation_state_init.h" + +namespace blink { + +XRLightEstimationState::XRLightEstimationState( + XRLightEstimationStateInit* light_estimation_state_init) { + if (light_estimation_state_init) { + if (light_estimation_state_init->hasEnabled()) { + enabled_ = light_estimation_state_init->enabled(); + } + } +} + +} // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_light_estimation_state.h b/chromium/third_party/blink/renderer/modules/xr/xr_light_estimation_state.h new file mode 100644 index 00000000000..c1ab4305167 --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/xr/xr_light_estimation_state.h @@ -0,0 +1,29 @@ +// Copyright 2019 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_LIGHT_ESTIMATION_STATE_H_ +#define THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_LIGHT_ESTIMATION_STATE_H_ + +#include "third_party/blink/renderer/platform/bindings/script_wrappable.h" + +namespace blink { + +class XRLightEstimationStateInit; + +class XRLightEstimationState : public ScriptWrappable { + DEFINE_WRAPPERTYPEINFO(); + + public: + explicit XRLightEstimationState( + XRLightEstimationStateInit* light_estimation_state_init); + + bool enabled() const { return enabled_; } + + private: + bool enabled_ = false; +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_LIGHT_ESTIMATION_STATE_H_ diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_light_estimation_state.idl b/chromium/third_party/blink/renderer/modules/xr/xr_light_estimation_state.idl new file mode 100644 index 00000000000..305f741b4f1 --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/xr/xr_light_estimation_state.idl @@ -0,0 +1,13 @@ +// Copyright 2019 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, + Exposed=Window, + RuntimeEnabled=WebXRIncubations +] +interface XRLightEstimationState { + readonly attribute boolean enabled; +}; + diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_light_estimation_state_init.idl b/chromium/third_party/blink/renderer/modules/xr/xr_light_estimation_state_init.idl new file mode 100644 index 00000000000..379f6d90f6e --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/xr/xr_light_estimation_state_init.idl @@ -0,0 +1,7 @@ +// Copyright 2019 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. + +dictionary XRLightEstimationStateInit { + boolean enabled; +}; diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_light_probe.cc b/chromium/third_party/blink/renderer/modules/xr/xr_light_probe.cc new file mode 100644 index 00000000000..46de95dcb1c --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/xr/xr_light_probe.cc @@ -0,0 +1,47 @@ +// Copyright 2019 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_light_probe.h" + +#include "device/vr/public/mojom/vr_service.mojom-blink.h" +#include "third_party/blink/renderer/core/geometry/dom_point_read_only.h" +#include "third_party/blink/renderer/modules/xr/xr_spherical_harmonics.h" + +namespace blink { + +XRLightProbe::XRLightProbe( + const device::mojom::blink::XRLightProbe& light_probe) { + spherical_harmonics_ = MakeGarbageCollected<XRSphericalHarmonics>( + *light_probe.spherical_harmonics); + + main_light_direction_ = + DOMPointReadOnly::Create(light_probe.main_light_direction.x(), + light_probe.main_light_direction.y(), + light_probe.main_light_direction.z(), 0); + main_light_intensity_ = + DOMPointReadOnly::Create(light_probe.main_light_intensity.red(), + light_probe.main_light_intensity.green(), + light_probe.main_light_intensity.blue(), 1); +} + +XRSphericalHarmonics* XRLightProbe::sphericalHarmonics() const { + return spherical_harmonics_.Get(); +} + +DOMPointReadOnly* XRLightProbe::mainLightDirection() const { + return main_light_direction_.Get(); +} + +DOMPointReadOnly* XRLightProbe::mainLightIntensity() const { + return main_light_intensity_.Get(); +} + +void XRLightProbe::Trace(Visitor* visitor) { + visitor->Trace(spherical_harmonics_); + visitor->Trace(main_light_direction_); + visitor->Trace(main_light_intensity_); + ScriptWrappable::Trace(visitor); +} + +} // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_light_probe.h b/chromium/third_party/blink/renderer/modules/xr/xr_light_probe.h new file mode 100644 index 00000000000..06912d21516 --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/xr/xr_light_probe.h @@ -0,0 +1,36 @@ +// Copyright 2019 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_LIGHT_PROBE_H_ +#define THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_LIGHT_PROBE_H_ + +#include "device/vr/public/mojom/vr_service.mojom-blink-forward.h" +#include "third_party/blink/renderer/platform/bindings/script_wrappable.h" + +namespace blink { + +class XRSphericalHarmonics; +class DOMPointReadOnly; + +class XRLightProbe : public ScriptWrappable { + DEFINE_WRAPPERTYPEINFO(); + + public: + explicit XRLightProbe(const device::mojom::blink::XRLightProbe& light_probe); + + XRSphericalHarmonics* sphericalHarmonics() const; + DOMPointReadOnly* mainLightDirection() const; + DOMPointReadOnly* mainLightIntensity() const; + + void Trace(Visitor* visitor) override; + + private: + Member<XRSphericalHarmonics> spherical_harmonics_; + Member<DOMPointReadOnly> main_light_direction_; + Member<DOMPointReadOnly> main_light_intensity_; +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_LIGHT_PROBE_H_ diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_light_probe.idl b/chromium/third_party/blink/renderer/modules/xr/xr_light_probe.idl new file mode 100644 index 00000000000..691c4c667d2 --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/xr/xr_light_probe.idl @@ -0,0 +1,15 @@ +// Copyright 2019 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, + Exposed=Window, + RuntimeEnabled=WebXRIncubations +] +interface XRLightProbe { + readonly attribute XRSphericalHarmonics sphericalHarmonics; + readonly attribute DOMPointReadOnly mainLightDirection; + readonly attribute DOMPointReadOnly mainLightIntensity; +}; + diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_object_space.h b/chromium/third_party/blink/renderer/modules/xr/xr_object_space.h index a35b6894c01..ed71e679360 100644 --- a/chromium/third_party/blink/renderer/modules/xr/xr_object_space.h +++ b/chromium/third_party/blink/renderer/modules/xr/xr_object_space.h @@ -21,21 +21,24 @@ class XRObjectSpace : public XRSpace { explicit XRObjectSpace(XRSession* session, const T* object) : XRSpace(session), object_(object) {} - std::unique_ptr<TransformationMatrix> MojoFromSpace() override { - auto object_from_mojo = object_->poseMatrix(); - - if (!object_from_mojo.IsInvertible()) { + std::unique_ptr<TransformationMatrix> MojoFromNative() override { + auto maybe_mojo_from_object = object_->MojoFromObject(); + if (maybe_mojo_from_object) { + return std::make_unique<TransformationMatrix>(*maybe_mojo_from_object); + } else { return nullptr; } + } - return std::make_unique<TransformationMatrix>(object_from_mojo.Inverse()); + std::unique_ptr<TransformationMatrix> NativeFromMojo() final { + return TryInvert(MojoFromNative()); } base::Optional<XRNativeOriginInformation> NativeOrigin() const override { return XRNativeOriginInformation::Create(object_); } - void Trace(blink::Visitor* visitor) override { + void Trace(Visitor* visitor) override { visitor->Trace(object_); XRSpace::Trace(visitor); } diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_plane.cc b/chromium/third_party/blink/renderer/modules/xr/xr_plane.cc index d15edc9cd5a..1d3d9f161a4 100644 --- a/chromium/third_party/blink/renderer/modules/xr/xr_plane.cc +++ b/chromium/third_party/blink/renderer/modules/xr/xr_plane.cc @@ -15,27 +15,31 @@ namespace blink { XRPlane::XRPlane(uint64_t id, XRSession* session, - const device::mojom::blink::XRPlaneDataPtr& plane_data, + const device::mojom::blink::XRPlaneData& plane_data, double timestamp) : XRPlane(id, session, mojo::ConvertTo<base::Optional<blink::XRPlane::Orientation>>( - plane_data->orientation), - mojo::ConvertTo<blink::TransformationMatrix>(plane_data->pose), + plane_data.orientation), mojo::ConvertTo<HeapVector<Member<DOMPointReadOnly>>>( - plane_data->polygon), - timestamp) {} + plane_data.polygon), + timestamp) { + // No need for else - if pose is not present, the default-constructed unique + // ptr is fine. + if (plane_data.pose) { + SetMojoFromPlane( + mojo::ConvertTo<blink::TransformationMatrix>(plane_data.pose)); + } +} XRPlane::XRPlane(uint64_t id, XRSession* session, const base::Optional<Orientation>& orientation, - const TransformationMatrix& pose_matrix, const HeapVector<Member<DOMPointReadOnly>>& polygon, double timestamp) : id_(id), polygon_(polygon), orientation_(orientation), - pose_matrix_(std::make_unique<TransformationMatrix>(pose_matrix)), session_(session), last_changed_time_(timestamp) { DVLOG(3) << __func__; @@ -53,13 +57,17 @@ XRSpace* XRPlane::planeSpace() const { return plane_space_; } -TransformationMatrix XRPlane::poseMatrix() const { - return *pose_matrix_; +base::Optional<TransformationMatrix> XRPlane::MojoFromObject() const { + if (!mojo_from_plane_) { + return base::nullopt; + } + + return *mojo_from_plane_; } String XRPlane::orientation() const { - if (orientation_.has_value()) { - switch (orientation_.value()) { + if (orientation_) { + switch (*orientation_) { case Orientation::kHorizontal: return "Horizontal"; case Orientation::kVertical: @@ -85,25 +93,57 @@ ScriptPromise XRPlane::createAnchor(ScriptState* script_state, XRRigidTransform* initial_pose, XRSpace* space, ExceptionState& exception_state) { - return session_->CreateAnchor(script_state, initial_pose, space, this, - exception_state); + if (!initial_pose) { + exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError, + XRSession::kNoRigidTransformSpecified); + return {}; + } + + if (!space) { + exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError, + XRSession::kNoSpaceSpecified); + return {}; + } + + auto maybe_mojo_from_offset = space->MojoFromOffsetMatrix(); + + if (!maybe_mojo_from_offset) { + exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError, + XRSession::kUnableToRetrieveMatrix); + return {}; + } + + return session_->CreateAnchor(script_state, initial_pose->TransformMatrix(), + *maybe_mojo_from_offset, id_, exception_state); } -void XRPlane::Update(const device::mojom::blink::XRPlaneDataPtr& plane_data, +void XRPlane::Update(const device::mojom::blink::XRPlaneData& plane_data, double timestamp) { DVLOG(3) << __func__; last_changed_time_ = timestamp; orientation_ = mojo::ConvertTo<base::Optional<blink::XRPlane::Orientation>>( - plane_data->orientation); - *pose_matrix_ = - mojo::ConvertTo<blink::TransformationMatrix>(plane_data->pose); - polygon_ = mojo::ConvertTo<HeapVector<Member<DOMPointReadOnly>>>( - plane_data->polygon); + plane_data.orientation); + if (plane_data.pose) { + SetMojoFromPlane( + mojo::ConvertTo<blink::TransformationMatrix>(plane_data.pose)); + } else { + mojo_from_plane_ = nullptr; + } + polygon_ = + mojo::ConvertTo<HeapVector<Member<DOMPointReadOnly>>>(plane_data.polygon); +} + +void XRPlane::SetMojoFromPlane(const TransformationMatrix& mojo_from_plane) { + if (mojo_from_plane_) { + *mojo_from_plane_ = mojo_from_plane; + } else { + mojo_from_plane_ = std::make_unique<TransformationMatrix>(mojo_from_plane); + } } -void XRPlane::Trace(blink::Visitor* visitor) { +void XRPlane::Trace(Visitor* visitor) { visitor->Trace(polygon_); visitor->Trace(session_); visitor->Trace(plane_space_); diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_plane.h b/chromium/third_party/blink/renderer/modules/xr/xr_plane.h index f42f4089456..b4e9b877f3c 100644 --- a/chromium/third_party/blink/renderer/modules/xr/xr_plane.h +++ b/chromium/third_party/blink/renderer/modules/xr/xr_plane.h @@ -29,20 +29,14 @@ class XRPlane : public ScriptWrappable { XRPlane(uint64_t id, XRSession* session, - const device::mojom::blink::XRPlaneDataPtr& plane_data, - double timestamp); - XRPlane(uint64_t id, - XRSession* session, - const base::Optional<Orientation>& orientation, - const TransformationMatrix& pose_matrix, - const HeapVector<Member<DOMPointReadOnly>>& polygon, + const device::mojom::blink::XRPlaneData& plane_data, double timestamp); uint64_t id() const; XRSpace* planeSpace() const; - TransformationMatrix poseMatrix() const; + base::Optional<TransformationMatrix> MojoFromObject() const; String orientation() const; HeapVector<Member<DOMPointReadOnly>> polygon() const; @@ -56,18 +50,26 @@ class XRPlane : public ScriptWrappable { // Updates plane data from passed in |plane_data|. The resulting instance // should be equivalent to the instance that would be create by calling // XRPlane(plane_data). - void Update(const device::mojom::blink::XRPlaneDataPtr& plane_data, + void Update(const device::mojom::blink::XRPlaneData& plane_data, double timestamp); - void Trace(blink::Visitor* visitor) override; + void Trace(Visitor* visitor) override; private: + XRPlane(uint64_t id, + XRSession* session, + const base::Optional<Orientation>& orientation, + const HeapVector<Member<DOMPointReadOnly>>& polygon, + double timestamp); + + void SetMojoFromPlane(const TransformationMatrix& mojo_from_plane); + const uint64_t id_; HeapVector<Member<DOMPointReadOnly>> polygon_; base::Optional<Orientation> orientation_; // Plane center's pose in device (mojo) space. - std::unique_ptr<TransformationMatrix> pose_matrix_; + std::unique_ptr<TransformationMatrix> mojo_from_plane_; Member<XRSession> session_; diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_plane.idl b/chromium/third_party/blink/renderer/modules/xr/xr_plane.idl index 2c2f6820fa4..e448c0793bf 100644 --- a/chromium/third_party/blink/renderer/modules/xr/xr_plane.idl +++ b/chromium/third_party/blink/renderer/modules/xr/xr_plane.idl @@ -12,7 +12,7 @@ enum XRPlaneOrientation { [ SecureContext, Exposed=Window, - RuntimeEnabled=WebXRPlaneDetection + RuntimeEnabled=WebXRIncubations ] interface XRPlane { readonly attribute XRSpace planeSpace; @@ -20,5 +20,5 @@ interface XRPlane { readonly attribute XRPlaneOrientation? orientation; readonly attribute DOMHighResTimeStamp lastChangedTime; - [RuntimeEnabled=WebXRAnchors, CallWith=ScriptState, RaisesException] Promise<XRAnchor> createAnchor(XRRigidTransform initial_pose, XRSpace space); + [CallWith=ScriptState, RaisesException] Promise<XRAnchor> createAnchor(XRRigidTransform initial_pose, XRSpace space); }; diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_plane_detection_state.cc b/chromium/third_party/blink/renderer/modules/xr/xr_plane_detection_state.cc index 32d242272c7..800d67a4800 100644 --- a/chromium/third_party/blink/renderer/modules/xr/xr_plane_detection_state.cc +++ b/chromium/third_party/blink/renderer/modules/xr/xr_plane_detection_state.cc @@ -4,7 +4,7 @@ #include "third_party/blink/renderer/modules/xr/xr_plane_detection_state.h" -#include "third_party/blink/renderer/modules/xr/xr_plane_detection_state_init.h" +#include "third_party/blink/renderer/bindings/modules/v8/v8_xr_plane_detection_state_init.h" namespace blink { XRPlaneDetectionState::XRPlaneDetectionState( diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_plane_detection_state.h b/chromium/third_party/blink/renderer/modules/xr/xr_plane_detection_state.h index ff33f51dbad..22499d7629f 100644 --- a/chromium/third_party/blink/renderer/modules/xr/xr_plane_detection_state.h +++ b/chromium/third_party/blink/renderer/modules/xr/xr_plane_detection_state.h @@ -17,8 +17,8 @@ class XRPlaneDetectionState : public ScriptWrappable { DEFINE_WRAPPERTYPEINFO(); public: - XRPlaneDetectionState( - XRPlaneDetectionStateInit* plane_detection_state_init = nullptr); + explicit XRPlaneDetectionState( + XRPlaneDetectionStateInit* plane_detection_state_init); bool enabled() const { return enabled_; } diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_plane_detection_state.idl b/chromium/third_party/blink/renderer/modules/xr/xr_plane_detection_state.idl index 9457324459d..8b41426af0f 100644 --- a/chromium/third_party/blink/renderer/modules/xr/xr_plane_detection_state.idl +++ b/chromium/third_party/blink/renderer/modules/xr/xr_plane_detection_state.idl @@ -7,7 +7,7 @@ [ SecureContext, Exposed=Window, - RuntimeEnabled=WebXRPlaneDetection + RuntimeEnabled=WebXRIncubations ] interface XRPlaneDetectionState { readonly attribute boolean enabled; diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_plane_set.cc b/chromium/third_party/blink/renderer/modules/xr/xr_plane_set.cc index 085315e9393..f941384cf79 100644 --- a/chromium/third_party/blink/renderer/modules/xr/xr_plane_set.cc +++ b/chromium/third_party/blink/renderer/modules/xr/xr_plane_set.cc @@ -12,7 +12,7 @@ const HeapHashSet<Member<XRPlane>>& XRPlaneSet::elements() const { return planes_; } -void XRPlaneSet::Trace(blink::Visitor* visitor) { +void XRPlaneSet::Trace(Visitor* visitor) { visitor->Trace(planes_); ScriptWrappable::Trace(visitor); } diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_plane_set.h b/chromium/third_party/blink/renderer/modules/xr/xr_plane_set.h index 8853f15f3fd..ba27dbe0238 100644 --- a/chromium/third_party/blink/renderer/modules/xr/xr_plane_set.h +++ b/chromium/third_party/blink/renderer/modules/xr/xr_plane_set.h @@ -17,7 +17,7 @@ class XRPlaneSet : public ScriptWrappable, public XRSetlike<XRPlane> { public: explicit XRPlaneSet(HeapHashSet<Member<XRPlane>> planes); - void Trace(blink::Visitor* visitor) override; + void Trace(Visitor* visitor) override; protected: const HeapHashSet<Member<XRPlane>>& elements() const override; diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_plane_set.idl b/chromium/third_party/blink/renderer/modules/xr/xr_plane_set.idl index 8e04e6bd65d..f0d3a0d4ce8 100644 --- a/chromium/third_party/blink/renderer/modules/xr/xr_plane_set.idl +++ b/chromium/third_party/blink/renderer/modules/xr/xr_plane_set.idl @@ -7,7 +7,7 @@ [ SecureContext, Exposed=Window, - RuntimeEnabled=WebXRPlaneDetection + RuntimeEnabled=WebXRIncubations ] interface XRPlaneSet { readonly setlike<XRPlane>; diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_pose.cc b/chromium/third_party/blink/renderer/modules/xr/xr_pose.cc index 91a5d4c3b05..4eeb10dfe14 100644 --- a/chromium/third_party/blink/renderer/modules/xr/xr_pose.cc +++ b/chromium/third_party/blink/renderer/modules/xr/xr_pose.cc @@ -13,7 +13,7 @@ XRPose::XRPose(const TransformationMatrix& pose_model_matrix, : transform_(MakeGarbageCollected<XRRigidTransform>(pose_model_matrix)), emulated_position_(emulated_position) {} -void XRPose::Trace(blink::Visitor* visitor) { +void XRPose::Trace(Visitor* visitor) { visitor->Trace(transform_); ScriptWrappable::Trace(visitor); } diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_pose.h b/chromium/third_party/blink/renderer/modules/xr/xr_pose.h index df99305f51c..fcc0adde4b6 100644 --- a/chromium/third_party/blink/renderer/modules/xr/xr_pose.h +++ b/chromium/third_party/blink/renderer/modules/xr/xr_pose.h @@ -25,7 +25,7 @@ class XRPose : public ScriptWrappable { XRRigidTransform* transform() const { return transform_; } bool emulatedPosition() const { return emulated_position_; } - void Trace(blink::Visitor*) override; + void Trace(Visitor*) override; protected: Member<XRRigidTransform> transform_; diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_ray.cc b/chromium/third_party/blink/renderer/modules/xr/xr_ray.cc index 17139f4e613..41f2ad96b27 100644 --- a/chromium/third_party/blink/renderer/modules/xr/xr_ray.cc +++ b/chromium/third_party/blink/renderer/modules/xr/xr_ray.cc @@ -8,7 +8,7 @@ #include <cmath> #include <utility> -#include "third_party/blink/renderer/core/geometry/dom_point_init.h" +#include "third_party/blink/renderer/bindings/core/v8/v8_dom_point_init.h" #include "third_party/blink/renderer/core/geometry/dom_point_read_only.h" #include "third_party/blink/renderer/modules/xr/xr_rigid_transform.h" #include "third_party/blink/renderer/modules/xr/xr_utils.h" @@ -142,7 +142,7 @@ DOMFloat32Array* XRRay::matrix() { // steps: // Step 1. If the operation IsDetachedBuffer on internal matrix is false, // return transform’s internal matrix. - if (!matrix_ || !matrix_->View() || !matrix_->View()->Data()) { + if (!matrix_ || !matrix_->Data()) { // Returned matrix should represent transformation from ray originating at // (0,0,0) with direction (0,0,-1) into ray originating at |origin_| with // direction |direction_|. @@ -208,7 +208,7 @@ TransformationMatrix XRRay::RawMatrix() { return *raw_matrix_; } -void XRRay::Trace(blink::Visitor* visitor) { +void XRRay::Trace(Visitor* visitor) { visitor->Trace(origin_); visitor->Trace(direction_); visitor->Trace(matrix_); diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_ray.h b/chromium/third_party/blink/renderer/modules/xr/xr_ray.h index f76b7ac2566..c041069c2bc 100644 --- a/chromium/third_party/blink/renderer/modules/xr/xr_ray.h +++ b/chromium/third_party/blink/renderer/modules/xr/xr_ray.h @@ -49,7 +49,7 @@ class XRRay final : public ScriptWrappable { static XRRay* Create(XRRigidTransform* transform, ExceptionState& exception_state); - void Trace(blink::Visitor*) override; + void Trace(Visitor*) override; private: void Set(const TransformationMatrix& matrix, ExceptionState& exception_state); diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_ray.idl b/chromium/third_party/blink/renderer/modules/xr/xr_ray.idl index 38bb19e4100..290203afaa1 100644 --- a/chromium/third_party/blink/renderer/modules/xr/xr_ray.idl +++ b/chromium/third_party/blink/renderer/modules/xr/xr_ray.idl @@ -6,13 +6,12 @@ [ SecureContext, Exposed=Window, - RuntimeEnabled=WebXRHitTest, - Constructor(), - Constructor(DOMPointInit origin), - Constructor(DOMPointInit origin, DOMPointInit direction), - Constructor(XRRigidTransform transform), - RaisesException=Constructor + RuntimeEnabled=WebXRHitTest ] interface XRRay { + [RaisesException] constructor(); + [RaisesException] constructor(DOMPointInit origin); + [RaisesException] constructor(DOMPointInit origin, DOMPointInit direction); + [RaisesException] constructor(XRRigidTransform transform); [SameObject] readonly attribute DOMPointReadOnly origin; [SameObject] readonly attribute DOMPointReadOnly direction; [SameObject] readonly attribute Float32Array matrix; diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_reference_space.cc b/chromium/third_party/blink/renderer/modules/xr/xr_reference_space.cc index cc1d9d673b3..94749357c8f 100644 --- a/chromium/third_party/blink/renderer/modules/xr/xr_reference_space.cc +++ b/chromium/third_party/blink/renderer/modules/xr/xr_reference_space.cc @@ -46,25 +46,23 @@ XRReferenceSpace::XRReferenceSpace(XRSession* session, XRReferenceSpace::~XRReferenceSpace() = default; -XRPose* XRReferenceSpace::getPose( - XRSpace* other_space, - const TransformationMatrix* mojo_from_viewer) { +XRPose* XRReferenceSpace::getPose(XRSpace* other_space) { if (type_ == Type::kTypeViewer) { - std::unique_ptr<TransformationMatrix> other_offsetspace_from_viewer = - other_space->SpaceFromViewerWithDefaultAndOffset(mojo_from_viewer); - if (!other_offsetspace_from_viewer) { + std::unique_ptr<TransformationMatrix> other_offset_from_viewer = + other_space->OffsetFromViewer(); + if (!other_offset_from_viewer) { return nullptr; } - auto viewer_from_offset = OriginOffsetMatrix(); + auto viewer_from_offset = NativeFromOffsetMatrix(); - auto other_offsetspace_from_offset = - *other_offsetspace_from_viewer * viewer_from_offset; + auto other_offset_from_offset = + *other_offset_from_viewer * viewer_from_offset; - return MakeGarbageCollected<XRPose>(other_offsetspace_from_offset, + return MakeGarbageCollected<XRPose>(other_offset_from_offset, session()->EmulatedPosition()); } else { - return XRSpace::getPose(other_space, mojo_from_viewer); + return XRSpace::getPose(other_space); } } @@ -85,16 +83,8 @@ void XRReferenceSpace::SetFloorFromMojo() { display_info_id_ = session()->DisplayInfoPtrId(); } -// Returns a default viewer pose if no actual viewer pose is available. Only -// applicable to viewer reference spaces. -std::unique_ptr<TransformationMatrix> XRReferenceSpace::DefaultViewerPose() { - // A viewer reference space always returns an identity matrix. - return type_ == Type::kTypeViewer ? std::make_unique<TransformationMatrix>() - : nullptr; -} - -std::unique_ptr<TransformationMatrix> XRReferenceSpace::SpaceFromMojo( - const TransformationMatrix& mojo_from_viewer) { +std::unique_ptr<TransformationMatrix> XRReferenceSpace::NativeFromMojo() { + auto mojo_from_viewer = session()->MojoFromViewer(); switch (type_) { case Type::kTypeLocal: // Currently 'local' space is equivalent to mojo space. @@ -111,8 +101,14 @@ std::unique_ptr<TransformationMatrix> XRReferenceSpace::SpaceFromMojo( SetFloorFromMojo(); return std::make_unique<TransformationMatrix>(*floor_from_mojo_); case Type::kTypeViewer: - // Return viewer_from_mojo which is the inverse of mojo_from_viewer. - return std::make_unique<TransformationMatrix>(mojo_from_viewer.Inverse()); + // If we don't have mojo_from_viewer, then it's the default pose, + // which is the identity pose. + if (!mojo_from_viewer) + return std::make_unique<TransformationMatrix>(); + DCHECK(mojo_from_viewer->IsInvertible()); + // Otherwise we need to return viewer_from_mojo which is the inverse. + return std::make_unique<TransformationMatrix>( + mojo_from_viewer->Inverse()); case Type::kTypeUnbounded: // For now we assume that poses returned by systems that support unbounded // reference spaces are already in the correct space. Return an identity. @@ -125,73 +121,36 @@ std::unique_ptr<TransformationMatrix> XRReferenceSpace::SpaceFromMojo( return nullptr; } -// Returns the refspace-from-viewerspace transform, corresponding to the pose of -// the viewer in this space. This takes the mojo_from_viewer transform (viewer -// pose in mojo space) as input, and left-multiplies space_from_mojo onto that. -std::unique_ptr<TransformationMatrix> XRReferenceSpace::SpaceFromViewer( - const TransformationMatrix& mojo_from_viewer) { +std::unique_ptr<TransformationMatrix> XRReferenceSpace::NativeFromViewer( + const TransformationMatrix* mojo_from_viewer) { if (type_ == Type::kTypeViewer) { // Special case for viewer space, always return an identity matrix - // explicitly. In theory the default behavior of multiplying SpaceFromMojo * - // MojoFromViewer would be equivalent, but that would likely return an + // explicitly. In theory the default behavior of multiplying NativeFromMojo + // onto MojoFromViewer would be equivalent, but that would likely return an // almost-identity due to rounding errors. return std::make_unique<TransformationMatrix>(); } - // Return space_from_viewer = space_from_mojo * mojo_from_viewer - auto space_from_viewer = SpaceFromMojo(mojo_from_viewer); - if (!space_from_viewer) + if (!mojo_from_viewer) return nullptr; - space_from_viewer->Multiply(mojo_from_viewer); - return space_from_viewer; -} -std::unique_ptr<TransformationMatrix> XRReferenceSpace::SpaceFromInputForViewer( - const TransformationMatrix& mojo_from_input, - const TransformationMatrix& mojo_from_viewer) { - // Return space_from_input = space_from_mojo * mojo_from_input - auto space_from_input = SpaceFromMojo(mojo_from_viewer); - if (!space_from_input) + // Return native_from_viewer = native_from_mojo * mojo_from_viewer + auto native_from_viewer = NativeFromMojo(); + if (!native_from_viewer) return nullptr; - space_from_input->Multiply(mojo_from_input); - return space_from_input; + native_from_viewer->Multiply(*mojo_from_viewer); + return native_from_viewer; } -std::unique_ptr<TransformationMatrix> XRReferenceSpace::MojoFromSpace() { - // XRReferenceSpace doesn't do anything special with the base pose, but - // derived reference spaces (bounded, unbounded, stationary, etc.) have their - // own custom behavior. - - // Calculate the offset space's pose (including originOffset) in mojo - // space. - // Note that although this calls SpaceFromViewer, because we're passing in - // identity, "viewer" is actually mojo. - TransformationMatrix identity; - std::unique_ptr<TransformationMatrix> base_space_from_mojo = - SpaceFromViewer(identity); - - if (!base_space_from_mojo) { - // Transform wasn't possible. - return nullptr; - } - - // Rigid transforms should always be invertible. - DCHECK(base_space_from_mojo->IsInvertible()); - TransformationMatrix mojo_from_base_space = base_space_from_mojo->Inverse(); - - // Must account for position and orientation defined by origin offset. - // Result is mojo_from_offset = mojo_from_base_space * base_space_from_offset, - // where base_space_from_offset is originOffset's transform matrix. - // TODO(https://crbug.com/1008466): move originOffset to separate class? - return std::make_unique<TransformationMatrix>( - mojo_from_base_space.Multiply(origin_offset_->TransformMatrix())); +std::unique_ptr<TransformationMatrix> XRReferenceSpace::MojoFromNative() { + return TryInvert(NativeFromMojo()); } -TransformationMatrix XRReferenceSpace::OriginOffsetMatrix() { +TransformationMatrix XRReferenceSpace::NativeFromOffsetMatrix() { return origin_offset_->TransformMatrix(); } -TransformationMatrix XRReferenceSpace::InverseOriginOffsetMatrix() { +TransformationMatrix XRReferenceSpace::OffsetFromNativeMatrix() { return origin_offset_->InverseTransformMatrix(); } @@ -202,7 +161,7 @@ XRReferenceSpace::Type XRReferenceSpace::GetType() const { XRReferenceSpace* XRReferenceSpace::getOffsetReferenceSpace( XRRigidTransform* additional_offset) { auto matrix = - OriginOffsetMatrix().Multiply(additional_offset->TransformMatrix()); + NativeFromOffsetMatrix().Multiply(additional_offset->TransformMatrix()); auto* result_transform = MakeGarbageCollected<XRRigidTransform>(matrix); return cloneWithOriginOffset(result_transform); @@ -219,7 +178,7 @@ base::Optional<XRNativeOriginInformation> XRReferenceSpace::NativeOrigin() return XRNativeOriginInformation::Create(this); } -void XRReferenceSpace::Trace(blink::Visitor* visitor) { +void XRReferenceSpace::Trace(Visitor* visitor) { visitor->Trace(origin_offset_); XRSpace::Trace(visitor); } diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_reference_space.h b/chromium/third_party/blink/renderer/modules/xr/xr_reference_space.h index dd112382514..4ad5be6df0e 100644 --- a/chromium/third_party/blink/renderer/modules/xr/xr_reference_space.h +++ b/chromium/third_party/blink/renderer/modules/xr/xr_reference_space.h @@ -36,21 +36,21 @@ class XRReferenceSpace : public XRSpace { Type type); ~XRReferenceSpace() override; - XRPose* getPose(XRSpace* other_space, - const TransformationMatrix* mojo_from_viewer) override; - std::unique_ptr<TransformationMatrix> DefaultViewerPose() override; - std::unique_ptr<TransformationMatrix> SpaceFromMojo( - const TransformationMatrix& mojo_from_viewer) override; - std::unique_ptr<TransformationMatrix> SpaceFromViewer( - const TransformationMatrix& mojo_from_viewer) override; - std::unique_ptr<TransformationMatrix> SpaceFromInputForViewer( - const TransformationMatrix& mojo_from_input, - const TransformationMatrix& mojo_from_viewer) override; - - std::unique_ptr<TransformationMatrix> MojoFromSpace() override; - - TransformationMatrix OriginOffsetMatrix() override; - TransformationMatrix InverseOriginOffsetMatrix() override; + std::unique_ptr<TransformationMatrix> NativeFromMojo() override; + std::unique_ptr<TransformationMatrix> NativeFromViewer( + const TransformationMatrix* mojo_from_viewer) override; + + // MojoFromNative is final to enforce that children should be returning + // NativeFromMojo, since this is simply written to always provide the inverse + // of NativeFromMojo + std::unique_ptr<TransformationMatrix> MojoFromNative() final; + + TransformationMatrix NativeFromOffsetMatrix() override; + TransformationMatrix OffsetFromNativeMatrix() override; + + // We override getPose to ensure that the viewer pose in viewer space returns + // the identity pose instead of the result of multiplying inverse matrices. + XRPose* getPose(XRSpace* other_space) override; Type GetType() const; @@ -60,7 +60,7 @@ class XRReferenceSpace : public XRSpace { base::Optional<XRNativeOriginInformation> NativeOrigin() const override; - void Trace(blink::Visitor*) override; + void Trace(Visitor*) override; virtual void OnReset(); diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_reference_space_event.cc b/chromium/third_party/blink/renderer/modules/xr/xr_reference_space_event.cc index 194959d4934..09a4c970517 100644 --- a/chromium/third_party/blink/renderer/modules/xr/xr_reference_space_event.cc +++ b/chromium/third_party/blink/renderer/modules/xr/xr_reference_space_event.cc @@ -32,7 +32,7 @@ const AtomicString& XRReferenceSpaceEvent::InterfaceName() const { return event_interface_names::kXRReferenceSpaceEvent; } -void XRReferenceSpaceEvent::Trace(blink::Visitor* visitor) { +void XRReferenceSpaceEvent::Trace(Visitor* visitor) { visitor->Trace(reference_space_); visitor->Trace(transform_); Event::Trace(visitor); diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_reference_space_event.h b/chromium/third_party/blink/renderer/modules/xr/xr_reference_space_event.h index 8a017f94558..291b5f8d0c0 100644 --- a/chromium/third_party/blink/renderer/modules/xr/xr_reference_space_event.h +++ b/chromium/third_party/blink/renderer/modules/xr/xr_reference_space_event.h @@ -5,8 +5,8 @@ #ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_REFERENCE_SPACE_EVENT_H_ #define THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_REFERENCE_SPACE_EVENT_H_ +#include "third_party/blink/renderer/bindings/modules/v8/v8_xr_reference_space_event_init.h" #include "third_party/blink/renderer/modules/event_modules.h" -#include "third_party/blink/renderer/modules/xr/xr_reference_space_event_init.h" namespace blink { @@ -41,7 +41,7 @@ class XRReferenceSpaceEvent final : public Event { const AtomicString& InterfaceName() const override; - void Trace(blink::Visitor*) override; + void Trace(Visitor*) override; private: Member<XRReferenceSpace> reference_space_; diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_reference_space_event.idl b/chromium/third_party/blink/renderer/modules/xr/xr_reference_space_event.idl index 3e58aaed15d..9b151dcdbe1 100644 --- a/chromium/third_party/blink/renderer/modules/xr/xr_reference_space_event.idl +++ b/chromium/third_party/blink/renderer/modules/xr/xr_reference_space_event.idl @@ -6,9 +6,9 @@ [ SecureContext, Exposed=Window, - RuntimeEnabled=WebXR, - Constructor(DOMString type, XRReferenceSpaceEventInit eventInitDict) + RuntimeEnabled=WebXR ] interface XRReferenceSpaceEvent : Event { + constructor(DOMString type, XRReferenceSpaceEventInit eventInitDict); [SameObject] readonly attribute XRReferenceSpace referenceSpace; [SameObject] readonly attribute XRRigidTransform transform; }; diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_reflection_probe.cc b/chromium/third_party/blink/renderer/modules/xr/xr_reflection_probe.cc new file mode 100644 index 00000000000..81b55d81f0e --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/xr/xr_reflection_probe.cc @@ -0,0 +1,26 @@ +// Copyright 2019 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_reflection_probe.h" + +#include "device/vr/public/mojom/vr_service.mojom-blink.h" +#include "third_party/blink/renderer/modules/xr/xr_cube_map.h" + +namespace blink { + +XRReflectionProbe::XRReflectionProbe( + const device::mojom::blink::XRReflectionProbe& reflection_probe) { + cube_map_ = MakeGarbageCollected<XRCubeMap>(*reflection_probe.cube_map); +} + +XRCubeMap* XRReflectionProbe::cubeMap() const { + return cube_map_.Get(); +} + +void XRReflectionProbe::Trace(Visitor* visitor) { + visitor->Trace(cube_map_); + ScriptWrappable::Trace(visitor); +} + +} // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_reflection_probe.h b/chromium/third_party/blink/renderer/modules/xr/xr_reflection_probe.h new file mode 100644 index 00000000000..4264caf16a7 --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/xr/xr_reflection_probe.h @@ -0,0 +1,33 @@ +// Copyright 2019 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_REFLECTION_PROBE_H_ +#define THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_REFLECTION_PROBE_H_ + +#include "base/util/type_safety/pass_key.h" +#include "device/vr/public/mojom/vr_service.mojom-blink-forward.h" +#include "third_party/blink/renderer/platform/bindings/script_wrappable.h" + +namespace blink { + +class XRCubeMap; + +class XRReflectionProbe : public ScriptWrappable { + DEFINE_WRAPPERTYPEINFO(); + + public: + explicit XRReflectionProbe( + const device::mojom::blink::XRReflectionProbe& reflection_probe); + + XRCubeMap* cubeMap() const; + + void Trace(Visitor* visitor) override; + + private: + Member<XRCubeMap> cube_map_; +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_REFLECTION_PROBE_H_ diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_reflection_probe.idl b/chromium/third_party/blink/renderer/modules/xr/xr_reflection_probe.idl new file mode 100644 index 00000000000..8d0275ae861 --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/xr/xr_reflection_probe.idl @@ -0,0 +1,13 @@ +// Copyright 2019 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, + Exposed=Window, + RuntimeEnabled=WebXRIncubations +] +interface XRReflectionProbe { + readonly attribute XRCubeMap cubeMap; +}; + diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_render_state.cc b/chromium/third_party/blink/renderer/modules/xr/xr_render_state.cc index 7f62fe21c44..427ae941677 100644 --- a/chromium/third_party/blink/renderer/modules/xr/xr_render_state.cc +++ b/chromium/third_party/blink/renderer/modules/xr/xr_render_state.cc @@ -9,7 +9,7 @@ #include <algorithm> #include <cmath> -#include "third_party/blink/renderer/modules/xr/xr_render_state_init.h" +#include "third_party/blink/renderer/bindings/modules/v8/v8_xr_render_state_init.h" #include "third_party/blink/renderer/modules/xr/xr_webgl_layer.h" namespace blink { @@ -55,12 +55,18 @@ HTMLCanvasElement* XRRenderState::output_canvas() const { return nullptr; } +base::Optional<double> XRRenderState::inlineVerticalFieldOfView() const { + if (immersive_) + return base::nullopt; + return inline_vertical_fov_; +} + double XRRenderState::inlineVerticalFieldOfView(bool& is_null) const { is_null = immersive_ || !inline_vertical_fov_.has_value(); return is_null ? 0 : *inline_vertical_fov_; } -void XRRenderState::Trace(blink::Visitor* visitor) { +void XRRenderState::Trace(Visitor* visitor) { visitor->Trace(base_layer_); visitor->Trace(inline_vertical_fov_); ScriptWrappable::Trace(visitor); diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_render_state.h b/chromium/third_party/blink/renderer/modules/xr/xr_render_state.h index f2837269c3c..c5f77f16e5d 100644 --- a/chromium/third_party/blink/renderer/modules/xr/xr_render_state.h +++ b/chromium/third_party/blink/renderer/modules/xr/xr_render_state.h @@ -25,7 +25,9 @@ class XRRenderState : public ScriptWrappable { // Session's views. double depthNear() const { return depth_near_; } double depthFar() const { return depth_far_; } - double inlineVerticalFieldOfView(bool& is_null) const; + base::Optional<double> inlineVerticalFieldOfView() const; + // TODO(crbug.com/1060971): Remove |is_null| version. + double inlineVerticalFieldOfView(bool& is_null) const; // DEPRECATED XRWebGLLayer* baseLayer() const { return base_layer_; } HTMLCanvasElement* output_canvas() const; @@ -36,7 +38,7 @@ class XRRenderState : public ScriptWrappable { // bound to a different session. void removeOutputContext(); - void Trace(blink::Visitor*) override; + void Trace(Visitor*) override; private: bool immersive_; diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_rigid_transform.cc b/chromium/third_party/blink/renderer/modules/xr/xr_rigid_transform.cc index 1e5b7314c5b..1e0b1364104 100644 --- a/chromium/third_party/blink/renderer/modules/xr/xr_rigid_transform.cc +++ b/chromium/third_party/blink/renderer/modules/xr/xr_rigid_transform.cc @@ -6,7 +6,7 @@ #include <utility> -#include "third_party/blink/renderer/core/geometry/dom_point_init.h" +#include "third_party/blink/renderer/bindings/core/v8/v8_dom_point_init.h" #include "third_party/blink/renderer/core/geometry/dom_point_read_only.h" #include "third_party/blink/renderer/modules/xr/xr_utils.h" #include "third_party/blink/renderer/platform/bindings/exception_state.h" @@ -92,8 +92,7 @@ DOMFloat32Array* XRRigidTransform::matrix() { matrix_array_ = transformationMatrixToDOMFloat32Array(*matrix_); } - if (!matrix_array_ || !matrix_array_->View() || - !matrix_array_->View()->Data()) { + if (!matrix_array_ || !matrix_array_->Data()) { // A page may take the matrix_array_ value and detach it so matrix_array_ is // a detached array buffer. This breaks the inspector, so return null // instead. @@ -156,7 +155,7 @@ void XRRigidTransform::EnsureInverse() { } } -void XRRigidTransform::Trace(blink::Visitor* visitor) { +void XRRigidTransform::Trace(Visitor* visitor) { visitor->Trace(position_); visitor->Trace(orientation_); visitor->Trace(inverse_); diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_rigid_transform.h b/chromium/third_party/blink/renderer/modules/xr/xr_rigid_transform.h index c395827a65d..e00e99bcc6d 100644 --- a/chromium/third_party/blink/renderer/modules/xr/xr_rigid_transform.h +++ b/chromium/third_party/blink/renderer/modules/xr/xr_rigid_transform.h @@ -41,7 +41,7 @@ class MODULES_EXPORT XRRigidTransform : public ScriptWrappable { TransformationMatrix InverseTransformMatrix(); TransformationMatrix TransformMatrix(); // copies matrix_ - void Trace(blink::Visitor*) override; + void Trace(Visitor*) override; private: void DecomposeMatrix(); diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_rigid_transform.idl b/chromium/third_party/blink/renderer/modules/xr/xr_rigid_transform.idl index 1faea2ba3a7..84bd98a9f09 100644 --- a/chromium/third_party/blink/renderer/modules/xr/xr_rigid_transform.idl +++ b/chromium/third_party/blink/renderer/modules/xr/xr_rigid_transform.idl @@ -7,10 +7,9 @@ [ SecureContext, Exposed=Window, - RuntimeEnabled=WebXR, - Constructor(optional DOMPointInit position, optional DOMPointInit orientation), - RaisesException=Constructor + RuntimeEnabled=WebXR ] interface XRRigidTransform { + [RaisesException] constructor(optional DOMPointInit position = {}, optional DOMPointInit orientation = {}); [SameObject] readonly attribute DOMPointReadOnly position; [SameObject] readonly attribute DOMPointReadOnly orientation; [SameObject] readonly attribute Float32Array matrix; diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_session.cc b/chromium/third_party/blink/renderer/modules/xr/xr_session.cc index 03f53ff3659..765532a27d7 100644 --- a/chromium/third_party/blink/renderer/modules/xr/xr_session.cc +++ b/chromium/third_party/blink/renderer/modules/xr/xr_session.cc @@ -15,6 +15,10 @@ #include "services/metrics/public/cpp/ukm_builders.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/bindings/modules/v8/v8_xr_hit_test_options_init.h" +#include "third_party/blink/renderer/bindings/modules/v8/v8_xr_render_state_init.h" +#include "third_party/blink/renderer/bindings/modules/v8/v8_xr_transient_input_hit_test_options_init.h" +#include "third_party/blink/renderer/bindings/modules/v8/v8_xr_world_tracking_state_init.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/frame.h" @@ -24,14 +28,12 @@ #include "third_party/blink/renderer/modules/event_target_modules.h" #include "third_party/blink/renderer/modules/screen_orientation/screen_orientation.h" #include "third_party/blink/renderer/modules/xr/type_converters.h" -#include "third_party/blink/renderer/modules/xr/xr.h" #include "third_party/blink/renderer/modules/xr/xr_anchor_set.h" #include "third_party/blink/renderer/modules/xr/xr_bounded_reference_space.h" #include "third_party/blink/renderer/modules/xr/xr_canvas_input_provider.h" +#include "third_party/blink/renderer/modules/xr/xr_dom_overlay_state.h" #include "third_party/blink/renderer/modules/xr/xr_frame.h" #include "third_party/blink/renderer/modules/xr/xr_frame_provider.h" -#include "third_party/blink/renderer/modules/xr/xr_hit_result.h" -#include "third_party/blink/renderer/modules/xr/xr_hit_test_options_init.h" #include "third_party/blink/renderer/modules/xr/xr_hit_test_source.h" #include "third_party/blink/renderer/modules/xr/xr_input_source_event.h" #include "third_party/blink/renderer/modules/xr/xr_input_sources_change_event.h" @@ -39,15 +41,13 @@ #include "third_party/blink/renderer/modules/xr/xr_ray.h" #include "third_party/blink/renderer/modules/xr/xr_reference_space.h" #include "third_party/blink/renderer/modules/xr/xr_render_state.h" -#include "third_party/blink/renderer/modules/xr/xr_render_state_init.h" #include "third_party/blink/renderer/modules/xr/xr_session_event.h" -#include "third_party/blink/renderer/modules/xr/xr_transient_input_hit_test_options_init.h" +#include "third_party/blink/renderer/modules/xr/xr_system.h" #include "third_party/blink/renderer/modules/xr/xr_transient_input_hit_test_source.h" #include "third_party/blink/renderer/modules/xr/xr_view.h" #include "third_party/blink/renderer/modules/xr/xr_webgl_layer.h" #include "third_party/blink/renderer/modules/xr/xr_world_information.h" #include "third_party/blink/renderer/modules/xr/xr_world_tracking_state.h" -#include "third_party/blink/renderer/modules/xr/xr_world_tracking_state_init.h" #include "third_party/blink/renderer/platform/bindings/v8_throw_exception.h" #include "third_party/blink/renderer/platform/geometry/float_point_3d.h" #include "third_party/blink/renderer/platform/heap/heap.h" @@ -68,20 +68,10 @@ const char kIncompatibleLayer[] = const char kInlineVerticalFOVNotSupported[] = "This session does not support inlineVerticalFieldOfView"; -const char kNoSpaceSpecified[] = "No XRSpace specified."; - -const char kNoRigidTransformSpecified[] = "No XRRigidTransform specified."; - -const char kHitTestNotSupported[] = "Device does not support hit-test!"; - const char kAnchorsNotSupported[] = "Device does not support anchors!"; const char kDeviceDisconnected[] = "The XR device has been disconnected."; -const char kNonInvertibleMatrix[] = - "The operation encountered non-invertible matrix and could not be " - "completed."; - const char kUnableToDecomposeMatrix[] = "The operation was unable to decompose a matrix and could not be " "completed."; @@ -90,6 +80,8 @@ const char kUnableToRetrieveNativeOrigin[] = "The operation was unable to retrieve the native origin from XRSpace and " "could not be completed."; +const char kHitTestFeatureNotSupported[] = "Hit test feature is not supported."; + const char kHitTestSubscriptionFailed[] = "Hit test subscription failed."; const char kEntityTypesNotSpecified[] = @@ -97,8 +89,6 @@ const char kEntityTypesNotSpecified[] = const double kDegToRad = M_PI / 180.0; -constexpr wtf_size_t kMinNumberOfBounds = 2; - // Indices into the views array. const unsigned int kMonoOrStereoLeftView = 0; const unsigned int kStereoRightView = 1; @@ -170,7 +160,8 @@ Vector<device::mojom::blink::EntityTypeForHitTest> GetEntityTypesForHitTest( DCHECK(options_init); HashSet<device::mojom::blink::EntityTypeForHitTest> result_set; - if (options_init->hasEntityTypes()) { + if (RuntimeEnabledFeatures::WebXRHitTestEntityTypesEnabled() && + options_init->hasEntityTypes()) { DVLOG(2) << __func__ << ": options_init->entityTypes().size()=" << options_init->entityTypes().size(); for (const auto& entity_type_string : options_init->entityTypes()) { @@ -245,6 +236,10 @@ bool ValidateHitTestSourceExistsHelper( } // namespace +constexpr char XRSession::kNoRigidTransformSpecified[]; +constexpr char XRSession::kUnableToRetrieveMatrix[]; +constexpr char XRSession::kNoSpaceSpecified[]; + class XRSession::XRSessionResizeObserverDelegate final : public ResizeObserver::Delegate { public: @@ -260,7 +255,7 @@ class XRSession::XRSessionResizeObserverDelegate final session_->UpdateCanvasDimensions(entries[0]->target()); } - void Trace(blink::Visitor* visitor) override { + void Trace(Visitor* visitor) override { visitor->Trace(session_); ResizeObserver::Delegate::Trace(visitor); } @@ -298,24 +293,26 @@ void XRSession::MetricsReporter::ReportFeatureUsed( case XRSessionFeature::REF_SPACE_UNBOUNDED: recorder_->ReportFeatureUsed(XRSessionFeature::REF_SPACE_UNBOUNDED); break; - case XRSessionFeature::DOM_OVERLAY_FOR_HANDHELD_AR: - // Not recording metrics for this feature currently + case XRSessionFeature::DOM_OVERLAY: + case XRSessionFeature::HIT_TEST: + // Not recording metrics for these features currently. break; } } XRSession::XRSession( - XR* xr, + XRSystem* xr, mojo::PendingReceiver<device::mojom::blink::XRSessionClient> client_receiver, - XRSession::SessionMode mode, + device::mojom::blink::XRSessionMode mode, EnvironmentBlendMode environment_blend_mode, bool uses_input_eventing, bool sensorless_session, XRSessionFeatureSet enabled_features) : xr_(xr), mode_(mode), - environment_integration_(mode == kModeImmersiveAR), + environment_integration_( + mode == device::mojom::blink::XRSessionMode::kImmersiveAr), world_tracking_state_(MakeGarbageCollected<XRWorldTrackingState>()), world_information_(MakeGarbageCollected<XRWorldInformation>(this)), enabled_features_(std::move(enabled_features)), @@ -346,6 +343,24 @@ XRSession::XRSession( } } +void XRSession::SetDOMOverlayElement(Element* element) { + DVLOG(2) << __func__ << ": element=" << element; + DCHECK( + enabled_features_.Contains(device::mojom::XRSessionFeature::DOM_OVERLAY)); + DCHECK(element); + + overlay_element_ = element; + + // Set up the domOverlayState attribute. This could be done lazily on first + // access, but it's a tiny object and it's unclear if the memory that might + // save during XR sessions is worth the code size increase to do so. This + // should be revisited if the state gets more complex in the future. + // + // At this time, "screen" is the only supported DOM Overlay type. + dom_overlay_state_ = MakeGarbageCollected<XRDOMOverlayState>( + XRDOMOverlayState::DOMOverlayType::kScreen); +} + const String XRSession::visibilityState() const { switch (visibility_state_) { case XRVisibilityState::VISIBLE: @@ -357,7 +372,7 @@ const String XRSession::visibilityState() const { } } -XRAnchorSet* XRSession::trackedAnchors() const { +XRAnchorSet* XRSession::TrackedAnchors() const { DVLOG(3) << __func__; HeapHashSet<Member<XRAnchor>> result; @@ -373,7 +388,8 @@ XRAnchorSet* XRSession::trackedAnchors() const { } bool XRSession::immersive() const { - return mode_ == kModeImmersiveVR || mode_ == kModeImmersiveAR; + return mode_ == device::mojom::blink::XRSessionMode::kImmersiveVr || + mode_ == device::mojom::blink::XRSessionMode::kImmersiveAr; } ExecutionContext* XRSession::GetExecutionContext() const { @@ -455,6 +471,8 @@ ScriptPromise XRSession::requestReferenceSpace( ScriptState* script_state, const String& type, ExceptionState& exception_state) { + DVLOG(2) << __func__; + if (ended_) { exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError, kSessionEnded); @@ -503,18 +521,13 @@ ScriptPromise XRSession::requestReferenceSpace( MakeGarbageCollected<XRReferenceSpace>(this, requested_type); break; case XRReferenceSpace::Type::kTypeBoundedFloor: { - bool supports_bounded = - immersive() && display_info_->stage_parameters && - display_info_->stage_parameters->bounds && - display_info_->stage_parameters->bounds->size() > kMinNumberOfBounds; - - if (supports_bounded) { + if (immersive()) { reference_space = MakeGarbageCollected<XRBoundedReferenceSpace>(this); } break; } case XRReferenceSpace::Type::kTypeUnbounded: - if (immersive() && environment_integration_) { + if (immersive()) { reference_space = MakeGarbageCollected<XRReferenceSpace>( this, XRReferenceSpace::Type::kTypeUnbounded); } @@ -542,29 +555,20 @@ ScriptPromise XRSession::requestReferenceSpace( return promise; } -ScriptPromise XRSession::CreateAnchor(ScriptState* script_state, - XRRigidTransform* initial_pose, - XRSpace* space, - XRPlane* plane, - ExceptionState& exception_state) { +ScriptPromise XRSession::CreateAnchor( + ScriptState* script_state, + const blink::TransformationMatrix& offset_space_from_anchor, + const blink::TransformationMatrix& mojo_from_offset_space, + base::Optional<uint64_t> plane_id, + ExceptionState& exception_state) { + DVLOG(2) << __func__ << ": plane_id.has_value()=" << plane_id.has_value(); + if (ended_) { exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError, kSessionEnded); return ScriptPromise(); } - if (!initial_pose) { - exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError, - kNoRigidTransformSpecified); - return ScriptPromise(); - } - - if (!space) { - exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError, - kNoSpaceSpecified); - return ScriptPromise(); - } - // Reject the promise if device doesn't support the anchors API. if (!xr_->xrEnvironmentProviderRemote()) { exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError, @@ -572,41 +576,13 @@ ScriptPromise XRSession::CreateAnchor(ScriptState* script_state, return ScriptPromise(); } - auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state); - ScriptPromise promise = resolver->Promise(); - - // Transformation from passed in |space| to mojo space. - std::unique_ptr<TransformationMatrix> mojo_from_space = - space->MojoFromSpace(); - - DVLOG(3) << __func__ - << ": mojo_from_space = " << mojo_from_space->ToString(true); - - // Matrix will be null if transformation from object space to mojo space is - // not invertible, log & bail out in that case. - if (!mojo_from_space || !mojo_from_space->IsInvertible()) { - exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError, - kNonInvertibleMatrix); - return ScriptPromise(); - } - - auto space_from_mojo = mojo_from_space->Inverse(); + auto mojo_from_anchor = mojo_from_offset_space * offset_space_from_anchor; DVLOG(3) << __func__ - << ": space_from_mojo = " << space_from_mojo.ToString(true); - - // Transformation from passed in pose to |space|. - auto mojo_from_initial_pose = initial_pose->TransformMatrix(); - auto space_from_initial_pose = space_from_mojo * mojo_from_initial_pose; - - DVLOG(3) << __func__ << ": mojo_from_initial_pose = " - << mojo_from_initial_pose.ToString(true); - - DVLOG(3) << __func__ << ": space_from_initial_pose = " - << space_from_initial_pose.ToString(true); + << ": mojo_from_anchor = " << mojo_from_anchor.ToString(true); TransformationMatrix::DecomposedType decomposed; - if (!space_from_initial_pose.Decompose(decomposed)) { + if (!mojo_from_anchor.Decompose(decomposed)) { exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError, kUnableToDecomposeMatrix); return ScriptPromise(); @@ -624,9 +600,12 @@ ScriptPromise XRSession::CreateAnchor(ScriptState* script_state, << ": pose_ptr->orientation = " << pose_ptr->orientation.ToString() << ", pose_ptr->position = " << pose_ptr->position.ToString(); - if (plane) { + auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state); + ScriptPromise promise = resolver->Promise(); + + if (plane_id) { xr_->xrEnvironmentProviderRemote()->CreatePlaneAnchor( - std::move(pose_ptr), plane->id(), + std::move(pose_ptr), *plane_id, WTF::Bind(&XRSession::OnCreateAnchorResult, WrapPersistent(this), WrapPersistent(resolver))); } else { @@ -640,15 +619,9 @@ ScriptPromise XRSession::CreateAnchor(ScriptState* script_state, return promise; } -ScriptPromise XRSession::createAnchor(ScriptState* script_state, - XRRigidTransform* initial_pose, - XRSpace* space, - ExceptionState& exception_state) { - return CreateAnchor(script_state, initial_pose, space, nullptr, - exception_state); -} - int XRSession::requestAnimationFrame(V8XRFrameRequestCallback* callback) { + DVLOG(3) << __func__; + TRACE_EVENT0("gpu", __func__); // Don't allow any new frame requests once the session is ended. if (ended_) @@ -664,7 +637,7 @@ void XRSession::cancelAnimationFrame(int id) { } XRInputSourceArray* XRSession::inputSources() const { - Document* doc = To<Document>(GetExecutionContext()); + Document* doc = Document::From(GetExecutionContext()); if (!did_log_getInputSources_ && doc) { ukm::builders::XR_WebXR(xr_->GetSourceId()) .SetDidGetXRInputSources(1) @@ -675,50 +648,6 @@ XRInputSourceArray* XRSession::inputSources() const { return input_sources_; } -ScriptPromise XRSession::requestHitTest(ScriptState* script_state, - XRRay* ray, - XRSpace* space, - ExceptionState& exception_state) { - DVLOG(2) << __func__; - - if (ended_) { - exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError, - kSessionEnded); - return ScriptPromise(); - } - - if (!space) { - exception_state.ThrowTypeError(kNoSpaceSpecified); - return ScriptPromise(); - } - - // Reject the promise if device doesn't support the hit-test API. - if (!xr_->xrEnvironmentProviderRemote()) { - exception_state.ThrowDOMException(DOMExceptionCode::kNotSupportedError, - kHitTestNotSupported); - return ScriptPromise(); - } - - device::mojom::blink::XRRayPtr ray_mojo = device::mojom::blink::XRRay::New(); - - ray_mojo->origin = - FloatPoint3D(ray->origin()->x(), ray->origin()->y(), ray->origin()->z()); - - ray_mojo->direction = {ray->direction()->x(), ray->direction()->y(), - ray->direction()->z()}; - - auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state); - ScriptPromise promise = resolver->Promise(); - - xr_->xrEnvironmentProviderRemote()->RequestHitTest( - std::move(ray_mojo), - WTF::Bind(&XRSession::OnHitTestResults, WrapPersistent(this), - WrapPersistent(resolver))); - hit_test_promises_.insert(resolver); - - return promise; -} - ScriptPromise XRSession::requestHitTestSource( ScriptState* script_state, XRHitTestOptionsInit* options_init, @@ -726,6 +655,18 @@ ScriptPromise XRSession::requestHitTestSource( DVLOG(2) << __func__; DCHECK(options_init); + if (!IsFeatureEnabled(device::mojom::XRSessionFeature::HIT_TEST)) { + exception_state.ThrowDOMException(DOMExceptionCode::kNotSupportedError, + kHitTestFeatureNotSupported); + return {}; + } + + if (ended_) { + exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError, + kSessionEnded); + return {}; + } + // 1. Grab the native origin from the passed in XRSpace. base::Optional<XRNativeOriginInformation> maybe_native_origin = options_init && options_init->hasSpace() @@ -741,13 +682,13 @@ ScriptPromise XRSession::requestHitTestSource( // 2. Convert the XRRay to be expressed in terms of passed in XRSpace. This // should only matter for spaces whose transforms are not fully known on the // device (for example any space containing origin-offset). - TransformationMatrix origin_from_space = - options_init->space() - ->OriginOffsetMatrix(); // Null checks not needed since native origin - // wouldn't be set if options_init or space() - // were null. + // Null checks not needed since native origin wouldn't be set if options_init + // or space() were null. + TransformationMatrix native_from_offset = + options_init->space()->NativeFromOffsetMatrix(); - if (options_init->hasEntityTypes() && options_init->entityTypes().IsEmpty()) { + if (RuntimeEnabledFeatures::WebXRHitTestEntityTypesEnabled() && + options_init->hasEntityTypes() && options_init->entityTypes().IsEmpty()) { exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError, kEntityTypesNotSpecified); return {}; @@ -756,7 +697,7 @@ ScriptPromise XRSession::requestHitTestSource( auto entity_types = GetEntityTypesForHitTest(options_init); DVLOG(3) << __func__ - << ": origin_from_space = " << origin_from_space.ToString(true); + << ": native_from_offset = " << native_from_offset.ToString(true); // Transformation from passed in pose to |space|. @@ -764,7 +705,7 @@ ScriptPromise XRSession::requestHitTestSource( ? options_init->offsetRay() : MakeGarbageCollected<XRRay>(); auto space_from_ray = offsetRay->RawMatrix(); - auto origin_from_ray = origin_from_space * space_from_ray; + auto origin_from_ray = native_from_offset * space_from_ray; DVLOG(3) << __func__ << ": space_from_ray = " << space_from_ray.ToString(true); @@ -803,7 +744,20 @@ ScriptPromise XRSession::requestHitTestSourceForTransientInput( DVLOG(2) << __func__; DCHECK(options_init); - if (options_init->hasEntityTypes() && options_init->entityTypes().IsEmpty()) { + if (!IsFeatureEnabled(device::mojom::XRSessionFeature::HIT_TEST)) { + exception_state.ThrowDOMException(DOMExceptionCode::kNotSupportedError, + kHitTestFeatureNotSupported); + return {}; + } + + if (ended_) { + exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError, + kSessionEnded); + return {}; + } + + if (RuntimeEnabledFeatures::WebXRHitTestEntityTypesEnabled() && + options_init->hasEntityTypes() && options_init->entityTypes().IsEmpty()) { exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError, kEntityTypesNotSpecified); return {}; @@ -834,26 +788,6 @@ ScriptPromise XRSession::requestHitTestSourceForTransientInput( return promise; } -void XRSession::OnHitTestResults( - ScriptPromiseResolver* resolver, - base::Optional<Vector<device::mojom::blink::XRHitResultPtr>> results) { - DCHECK(hit_test_promises_.Contains(resolver)); - hit_test_promises_.erase(resolver); - - if (!results) { - resolver->Reject(); - return; - } - - HeapVector<Member<XRHitResult>> hit_results; - for (const auto& mojom_result : results.value()) { - XRHitResult* hit_result = MakeGarbageCollected<XRHitResult>( - TransformationMatrix(mojom_result->hit_matrix.matrix())); - hit_results.push_back(hit_result); - } - resolver->Resolve(hit_results); -} - void XRSession::OnSubscribeToHitTestResult( ScriptPromiseResolver* resolver, device::mojom::SubscribeToHitTestResult result, @@ -911,11 +845,13 @@ void XRSession::OnCreateAnchorResult(ScriptPromiseResolver* resolver, DCHECK(create_anchor_promises_.Contains(resolver)); create_anchor_promises_.erase(resolver); - XRAnchor* anchor = MakeGarbageCollected<XRAnchor>(id, this); - - anchor_ids_to_anchors_.insert(id, anchor); - - resolver->Resolve(anchor); + if (result == device::mojom::CreateAnchorResult::SUCCESS) { + // Anchor was created successfully on the device. Subsequent frame update + // must contain newly created anchor data. + newly_created_anchor_ids_to_resolvers_.insert(id, resolver); + } else { + resolver->Reject(); + } } void XRSession::OnEnvironmentProviderCreated() { @@ -934,13 +870,6 @@ void XRSession::EnsureEnvironmentErrorHandler() { } void XRSession::OnEnvironmentProviderError() { - HeapHashSet<Member<ScriptPromiseResolver>> hit_test_promises; - hit_test_promises_.swap(hit_test_promises); - for (ScriptPromiseResolver* resolver : hit_test_promises) { - resolver->Reject(MakeGarbageCollected<DOMException>( - DOMExceptionCode::kInvalidStateError, kDeviceDisconnected)); - } - HeapHashSet<Member<ScriptPromiseResolver>> create_anchor_promises; create_anchor_promises_.swap(create_anchor_promises); for (ScriptPromiseResolver* resolver : create_anchor_promises) { @@ -957,7 +886,7 @@ void XRSession::OnEnvironmentProviderError() { } void XRSession::ProcessAnchorsData( - const device::mojom::blink::XRAnchorsDataPtr& tracked_anchors_data, + const device::mojom::blink::XRAnchorsData* tracked_anchors_data, double timestamp) { TRACE_EVENT0("xr", __func__); @@ -985,25 +914,38 @@ void XRSession::ProcessAnchorsData( HeapHashMap<uint64_t, Member<XRAnchor>> updated_anchors; - // First, process all planes that had their information updated (new planes + // First, process all anchors that had their information updated (new anchors // are also processed here). for (const auto& anchor : tracked_anchors_data->updated_anchors_data) { + DCHECK(anchor); + auto it = anchor_ids_to_anchors_.find(anchor->id); if (it != anchor_ids_to_anchors_.end()) { updated_anchors.insert(anchor->id, it->value); - it->value->Update(anchor, timestamp); + it->value->Update(*anchor); } else { - updated_anchors.insert( - anchor->id, - MakeGarbageCollected<XRAnchor>(anchor->id, this, anchor, timestamp)); + auto resolver_it = + newly_created_anchor_ids_to_resolvers_.find(anchor->id); + if (resolver_it == newly_created_anchor_ids_to_resolvers_.end()) { + DCHECK(false) + << "Newly created anchor must have a corresponding resolver!"; + continue; + } + + XRAnchor* xr_anchor = + MakeGarbageCollected<XRAnchor>(anchor->id, this, *anchor); + resolver_it->value->Resolve(xr_anchor); + newly_created_anchor_ids_to_resolvers_.erase(resolver_it); + + updated_anchors.insert(anchor->id, xr_anchor); } } - // Then, copy over the planes that were not updated but are still present. + // Then, copy over the anchors that were not updated but are still present. for (const auto& anchor_id : tracked_anchors_data->all_anchors_ids) { auto it_updated = updated_anchors.find(anchor_id); - // If the plane was already updated, there is nothing to do as it was + // If the anchor was already updated, there is nothing to do as it was // already moved to |updated_anchors|. Otherwise just copy it over as-is. if (it_updated == updated_anchors.end()) { auto it = anchor_ids_to_anchors_.find(anchor_id); @@ -1012,7 +954,16 @@ void XRSession::ProcessAnchorsData( } } + DVLOG(3) << __func__ + << ": anchor count before update=" << anchor_ids_to_anchors_.size() + << ", after update=" << updated_anchors.size(); + anchor_ids_to_anchors_.swap(updated_anchors); + + DCHECK(newly_created_anchor_ids_to_resolvers_.IsEmpty()) + << "All newly created anchors should be updated in subsequent frame, got " + << newly_created_anchor_ids_to_resolvers_.size() + << " anchors that have not been updated"; } void XRSession::CleanUpUnusedHitTestSources() { @@ -1020,10 +971,15 @@ void XRSession::CleanUpUnusedHitTestSources() { CleanUpUnusedHitTestSourcesHelper( &hit_test_source_ids_to_transient_input_hit_test_sources_); + + DVLOG(3) << __func__ << ": Number of active hit test sources: " + << hit_test_source_ids_to_hit_test_sources_.size() + << ", number of active hit test sources for transient input: " + << hit_test_source_ids_to_transient_input_hit_test_sources_.size(); } void XRSession::ProcessHitTestData( - const device::mojom::blink::XRHitTestSubscriptionResultsDataPtr& + const device::mojom::blink::XRHitTestSubscriptionResultsData* hit_test_subscriptions_data) { DVLOG(2) << __func__; @@ -1033,6 +989,11 @@ void XRSession::ProcessHitTestData( // We have received hit test results for hit test subscriptions - process // each result and notify its corresponding hit test source about new // results for the current frame. + DVLOG(3) << __func__ << "hit_test_subscriptions_data->results.size()=" + << hit_test_subscriptions_data->results.size() << ", " + << "hit_test_subscriptions_data->transient_input_results.size()=" + << hit_test_subscriptions_data->transient_input_results.size(); + for (auto& hit_test_subscription_data : hit_test_subscriptions_data->results) { auto it = hit_test_source_ids_to_hit_test_sources_.find( @@ -1054,6 +1015,8 @@ void XRSession::ProcessHitTestData( } } } else { + DVLOG(3) << __func__ << ": hit_test_subscriptions_data unavailable"; + // We have not received hit test results for any of the hit test // subscriptions in the current frame - clean up the results on all hit test // source objects. @@ -1385,8 +1348,8 @@ void XRSession::UpdatePresentationFrameState( int16_t frame_id, bool emulated_position) { TRACE_EVENT0("gpu", __func__); - DVLOG(2) << __func__ << " : frame_data valid? " - << (frame_data ? true : false); + DVLOG(2) << __func__ << " : frame_data valid? " << (frame_data ? true : false) + << ", emulated_position=" << emulated_position; // Don't process any outstanding frames once the session is ended. if (ended_) return; @@ -1405,6 +1368,12 @@ void XRSession::UpdatePresentationFrameState( OnInputStateChangeInternal(frame_id, input_states); + // World understanding includes hit testing for transient input sources, and + // these sources may have been hidden when touching DOM Overlay content + // that's inside cross-origin iframes. Since hit test subscriptions only + // happen for existing input_sources_ entries, these touches will not + // generate hit test results. For this to work, this step must happen + // after OnInputStateChangeInternal which updated input sources. UpdateWorldUnderstandingStateForFrame(timestamp, frame_data); // If this session uses input eventing, XR select events are handled via @@ -1412,6 +1381,8 @@ void XRSession::UpdatePresentationFrameState( if (!uses_input_eventing_) { ProcessInputSourceEvents(input_states); } + } else { + UpdateWorldUnderstandingStateForFrame(timestamp, frame_data); } } @@ -1421,13 +1392,16 @@ void XRSession::UpdateWorldUnderstandingStateForFrame( // Update objects that might change on per-frame basis. if (frame_data) { world_information_->ProcessPlaneInformation( - frame_data->detected_planes_data, timestamp); - ProcessAnchorsData(frame_data->anchors_data, timestamp); - ProcessHitTestData(frame_data->hit_test_subscription_results); + frame_data->detected_planes_data.get(), timestamp); + ProcessAnchorsData(frame_data->anchors_data.get(), timestamp); + ProcessHitTestData(frame_data->hit_test_subscription_results.get()); + world_information_->ProcessLightEstimationData( + frame_data->light_estimation_data.get(), timestamp); } else { world_information_->ProcessPlaneInformation(nullptr, timestamp); ProcessAnchorsData(nullptr, timestamp); ProcessHitTestData(nullptr); + world_information_->ProcessLightEstimationData(nullptr, timestamp); } } @@ -1445,7 +1419,8 @@ void XRSession::OnFrame( double timestamp, const base::Optional<gpu::MailboxHolder>& output_mailbox_holder) { TRACE_EVENT0("gpu", __func__); - DVLOG(2) << __func__; + DVLOG(2) << __func__ << ": ended_=" << ended_ + << ", pending_frame_=" << pending_frame_; // Don't process any outstanding frames once the session is ended. if (ended_) return; @@ -1461,10 +1436,14 @@ void XRSession::OnFrame( // session. That would allow tracking with no associated visuals. XRWebGLLayer* frame_base_layer = render_state_->baseLayer(); if (!frame_base_layer) { + DVLOG(2) << __func__ << ": frame_base_layer not present"; + // If we previously had a frame base layer, we need to still attempt to // submit a frame back to the runtime, as all "GetFrameData" calls need a // matching submit. if (prev_base_layer_) { + DVLOG(2) << __func__ + << ": prev_base_layer_ is valid, submitting frame to it"; prev_base_layer_->OnFrameStart(output_mailbox_holder); prev_base_layer_->OnFrameEnd(); prev_base_layer_ = nullptr; @@ -1474,16 +1453,23 @@ void XRSession::OnFrame( // Don't allow frames to be processed if an inline session doesn't have an // output canvas. - if (!immersive() && !render_state_->output_canvas()) + if (!immersive() && !render_state_->output_canvas()) { + DVLOG(2) << __func__ + << ": frames are not to be processed if an inline session " + "doesn't have an output canvas"; return; + } frame_base_layer->OnFrameStart(output_mailbox_holder); // Don't allow frames to be processed if the session's visibility state is // "hidden". if (visibility_state_ == XRVisibilityState::HIDDEN) { - // If the frame is skipped because of the visibility state, make sure we - // end the frame anyway. + DVLOG(2) << __func__ + << ": frames to be processed if the session's visibility state " + "is \"hidden\""; + // If the frame is skipped because of the visibility state, + // make sure we end the frame anyway. frame_base_layer->OnFrameEnd(); return; } @@ -1514,7 +1500,7 @@ void XRSession::OnFrame( } void XRSession::LogGetPose() const { - Document* doc = To<Document>(GetExecutionContext()); + Document* doc = Document::From(GetExecutionContext()); if (!did_log_getViewerPose_ && doc) { did_log_getViewerPose_ = true; @@ -1524,7 +1510,7 @@ void XRSession::LogGetPose() const { } } -bool XRSession::CanReportPoses() { +bool XRSession::CanReportPoses() const { // The spec has a few requirements for if poses can be reported. // If we have a session, then user intent is understood. Therefore, (due to // the way visibility state is updatd), the rest of the steps really just @@ -1532,21 +1518,25 @@ bool XRSession::CanReportPoses() { return visibility_state_ == XRVisibilityState::VISIBLE; } +base::Optional<TransformationMatrix> XRSession::MojoFromViewer() const { + if (!CanReportPoses()) + return base::nullopt; + + if (!mojo_from_viewer_) { + if (sensorless_session_) + return TransformationMatrix(); + + return base::nullopt; + } + + return *mojo_from_viewer_.get(); +} + XRFrame* XRSession::CreatePresentationFrame() { DVLOG(2) << __func__; XRFrame* presentation_frame = MakeGarbageCollected<XRFrame>(this, world_information_); - - // TODO(https://crbug.com/1004201): Determine if world_information_ should be - // treated similarly to mojo_from_viewer_. - if (mojo_from_viewer_ && visibility_state_ != XRVisibilityState::HIDDEN) { - DVLOG(2) << __func__ << " : mojo_from_viewer_ is set and not hidden," - << " updating presentation frame"; - - presentation_frame->SetMojoFromViewer(*mojo_from_viewer_, - EmulatedPosition()); - } return presentation_frame; } @@ -1600,23 +1590,50 @@ void XRSession::OnInputStateChangeInternal( HeapVector<Member<XRInputSource>> removed; last_frame_id_ = frame_id; + DVLOG(2) << __func__ << ": frame_id=" << frame_id + << " input_states.size()=" << input_states.size(); // Build up our added array, and update the frame id of any active input // sources so we can flag the ones that are no longer active. for (const auto& input_state : input_states) { + DVLOG(2) << __func__ + << ": input_state->source_id=" << input_state->source_id + << " input_state->primary_input_pressed=" + << input_state->primary_input_pressed + << " clicked=" << input_state->primary_input_clicked; + XRInputSource* stored_input_source = input_sources_->GetWithSourceId(input_state->source_id); + DVLOG(2) << __func__ << ": stored_input_source=" << stored_input_source; XRInputSource* input_source = XRInputSource::CreateOrUpdateFrom( stored_input_source, this, input_state); + // Input sources should use DOM overlay hit test to check if they intersect + // cross-origin content. If that's the case, the input source is set as + // invisible, and must not return poses or hit test results. + bool hide_input_source = false; + if (overlay_element_ && input_state->overlay_pointer_position) { + input_source->ProcessOverlayHitTest(overlay_element_, input_state); + if (!stored_input_source && !input_source->IsVisible()) { + DVLOG(2) << __func__ << ": (new) hidden_input_source"; + hide_input_source = true; + } + } + // Using pointer equality to determine if the pointer needs to be set. if (stored_input_source != input_source) { - input_sources_->SetWithSourceId(input_state->source_id, input_source); - added.push_back(input_source); + DVLOG(2) << __func__ << ": stored_input_source != input_source"; + if (!hide_input_source) { + input_sources_->SetWithSourceId(input_state->source_id, input_source); + added.push_back(input_source); + DVLOG(2) << __func__ << ": ADDED input_source " + << input_state->source_id; + } - // If we previously had a stored_input_source, disconnect it's gamepad + // If we previously had a stored_input_source, disconnect its gamepad // and mark that it was removed. if (stored_input_source) { stored_input_source->SetGamepadConnected(false); + DVLOG(2) << __func__ << ": REMOVED stored_input_source"; removed.push_back(stored_input_source); } } @@ -1662,8 +1679,10 @@ void XRSession::ProcessInputSourceEvents( XRInputSource* input_source = input_sources_->GetWithSourceId(input_state->source_id); - DCHECK(input_source); - input_source->UpdateSelectState(input_state); + // The input source might not be in input_sources_ if it was created hidden. + if (input_source) { + input_source->UpdateButtonStates(input_state); + } } } @@ -1836,7 +1855,7 @@ bool XRSession::HasPendingActivity() const { return !callback_collection_->IsEmpty() && !ended_; } -void XRSession::Trace(blink::Visitor* visitor) { +void XRSession::Trace(Visitor* visitor) { visitor->Trace(xr_); visitor->Trace(render_state_); visitor->Trace(world_tracking_state_); @@ -1846,12 +1865,14 @@ void XRSession::Trace(blink::Visitor* visitor) { visitor->Trace(input_sources_); visitor->Trace(resize_observer_); visitor->Trace(canvas_input_provider_); + visitor->Trace(overlay_element_); + visitor->Trace(dom_overlay_state_); visitor->Trace(callback_collection_); - visitor->Trace(hit_test_promises_); visitor->Trace(create_anchor_promises_); visitor->Trace(request_hit_test_source_promises_); visitor->Trace(reference_spaces_); visitor->Trace(anchor_ids_to_anchors_); + visitor->Trace(newly_created_anchor_ids_to_resolvers_); visitor->Trace(prev_base_layer_); visitor->Trace(hit_test_source_ids_to_hit_test_sources_); visitor->Trace(hit_test_source_ids_to_transient_input_hit_test_sources_); diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_session.h b/chromium/third_party/blink/renderer/modules/xr/xr_session.h index afc3a45bd41..384aa39463a 100644 --- a/chromium/third_party/blink/renderer/modules/xr/xr_session.h +++ b/chromium/third_party/blink/renderer/modules/xr/xr_session.h @@ -13,6 +13,7 @@ #include "mojo/public/cpp/bindings/remote.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/core/html/html_element.h" #include "third_party/blink/renderer/core/typed_arrays/array_buffer_view_helpers.h" #include "third_party/blink/renderer/core/typed_arrays/dom_typed_array.h" #include "third_party/blink/renderer/modules/xr/xr_frame_request_callback_collection.h" @@ -35,19 +36,17 @@ class HTMLCanvasElement; class ResizeObserver; class ScriptPromiseResolver; class V8XRFrameRequestCallback; -class XR; class XRAnchor; class XRAnchorSet; class XRCanvasInputProvider; +class XRDOMOverlayState; class XRHitTestOptionsInit; class XRHitTestSource; -class XRPlane; -class XRRay; class XRReferenceSpace; class XRRenderState; class XRRenderStateInit; -class XRRigidTransform; class XRSpace; +class XRSystem; class XRTransientInputHitTestOptionsInit; class XRTransientInputHitTestSource; class XRViewData; @@ -67,7 +66,13 @@ class XRSession final USING_GARBAGE_COLLECTED_MIXIN(XRSession); public: - enum SessionMode { kModeInline = 0, kModeImmersiveVR, kModeImmersiveAR }; + // Error strings used outside of XRSession: + static constexpr char kNoRigidTransformSpecified[] = + "No XRRigidTransform specified."; + static constexpr char kUnableToRetrieveMatrix[] = + "The operation was unable to retrieve a matrix from passed in space and " + "could not be completed."; + static constexpr char kNoSpaceSpecified[] = "No XRSpace specified."; enum EnvironmentBlendMode { kBlendModeOpaque = 0, @@ -91,23 +96,24 @@ class XRSession final HashSet<device::mojom::blink::XRSessionFeature> reported_features_; }; - XRSession(XR* xr, + XRSession(XRSystem* xr, mojo::PendingReceiver<device::mojom::blink::XRSessionClient> client_receiver, - SessionMode mode, + device::mojom::blink::XRSessionMode mode, EnvironmentBlendMode environment_blend_mode, bool uses_input_eventing, bool sensorless_session, XRSessionFeatureSet enabled_features); ~XRSession() override = default; - XR* xr() const { return xr_; } + XRSystem* xr() const { return xr_; } const String& environmentBlendMode() const { return blend_mode_string_; } + XRDOMOverlayState* domOverlayState() const { return dom_overlay_state_; } const String visibilityState() const; XRRenderState* renderState() const { return render_state_; } XRWorldTrackingState* worldTrackingState() { return world_tracking_state_; } XRSpace* viewerSpace() const; - XRAnchorSet* trackedAnchors() const; + XRAnchorSet* TrackedAnchors() const; bool immersive() const; @@ -117,6 +123,9 @@ class XRSession final DEFINE_ATTRIBUTE_EVENT_LISTENER(selectstart, kSelectstart) DEFINE_ATTRIBUTE_EVENT_LISTENER(selectend, kSelectend) DEFINE_ATTRIBUTE_EVENT_LISTENER(visibilitychange, kVisibilitychange) + DEFINE_ATTRIBUTE_EVENT_LISTENER(squeeze, kSqueeze) + DEFINE_ATTRIBUTE_EVENT_LISTENER(squeezestart, kSqueezestart) + DEFINE_ATTRIBUTE_EVENT_LISTENER(squeezeend, kSqueezeend) void updateRenderState(XRRenderStateInit* render_state_init, ExceptionState& exception_state); @@ -127,18 +136,20 @@ class XRSession final const String& type, ExceptionState&); - // IDL-exposed - ScriptPromise createAnchor(ScriptState* script_state, - XRRigidTransform* initial_pose, - XRSpace* space, - ExceptionState& exception_state); - - // helper, not IDL-exposed - ScriptPromise CreateAnchor(ScriptState* script_state, - XRRigidTransform* pose, - XRSpace* space, - XRPlane* plane, - ExceptionState& exception_state); + // Helper, not IDL-exposed + // |offset_space_from_anchor| is a matrix describing transform from offset + // space to the initial anchor's position. + // |mojo_from_offset_space| can be obtained from XRSpace and describes + // transform from mojo space to the offset space in which the anchor pose is + // expressed. + // |plane_id| - optional, id of the plane to which the anchor should be + // attached. + ScriptPromise CreateAnchor( + ScriptState* script_state, + const blink::TransformationMatrix& offset_space_from_anchor, + const blink::TransformationMatrix& mojo_from_offset_space, + base::Optional<uint64_t> plane_id, + ExceptionState& exception_state); int requestAnimationFrame(V8XRFrameRequestCallback* callback); void cancelAnimationFrame(int id); @@ -153,11 +164,6 @@ class XRSession final XRTransientInputHitTestOptionsInit* options_init, ExceptionState& exception_state); - ScriptPromise requestHitTest(ScriptState* script_state, - XRRay* ray, - XRSpace* space, - ExceptionState&); - // Called by JavaScript to manually end the session. ScriptPromise end(ScriptState* script_state, ExceptionState&); @@ -184,6 +190,8 @@ class XRSession final DoubleSize OutputCanvasSize() const; void DetachOutputCanvas(HTMLCanvasElement* output_canvas); + void SetDOMOverlayElement(Element* element); + void LogGetPose() const; // EventTarget overrides. @@ -257,12 +265,13 @@ class XRSession final bool UsesInputEventing() { return uses_input_eventing_; } - void Trace(blink::Visitor* visitor) override; + void Trace(Visitor* visitor) override; // ScriptWrappable bool HasPendingActivity() const override; - bool CanReportPoses(); + bool CanReportPoses() const; + base::Optional<TransformationMatrix> MojoFromViewer() const; // Creates presentation frame based on current state of the session. // State currently used in XRFrame creation is mojo_from_viewer_ and @@ -329,10 +338,6 @@ class XRSession final void UpdateVisibilityState(); - void OnHitTestResults( - ScriptPromiseResolver* resolver, - base::Optional<Vector<device::mojom::blink::XRHitResultPtr>> results); - void OnSubscribeToHitTestResult( ScriptPromiseResolver* resolver, device::mojom::SubscribeToHitTestResult result, @@ -351,19 +356,19 @@ class XRSession final void OnEnvironmentProviderError(); void ProcessAnchorsData( - const device::mojom::blink::XRAnchorsDataPtr& tracked_anchors_data, + const device::mojom::blink::XRAnchorsData* tracked_anchors_data, double timestamp); void CleanUpUnusedHitTestSources(); void ProcessHitTestData( - const device::mojom::blink::XRHitTestSubscriptionResultsDataPtr& + const device::mojom::blink::XRHitTestSubscriptionResultsData* hit_test_data); void HandleShutdown(); - const Member<XR> xr_; - const SessionMode mode_; + const Member<XRSystem> xr_; + const device::mojom::blink::XRSessionMode mode_; const bool environment_integration_; String blend_mode_string_; XRVisibilityState device_visibility_state_ = XRVisibilityState::VISIBLE; @@ -391,6 +396,17 @@ class XRSession final bool is_tracked_anchors_null_ = true; HeapHashMap<uint64_t, Member<XRAnchor>> anchor_ids_to_anchors_; + // Set of promises returned from CreateAnchor that are still in-flight to the + // device. Once the device calls us back with the newly created anchor id, the + // resolver will be moved to |newly_created_anchor_ids_to_resolvers_|. + HeapHashSet<Member<ScriptPromiseResolver>> create_anchor_promises_; + // Promises for which anchors have already been created on the device side but + // have not yet been resolved as their data is not yet available to blink. + // Next frame update should contain the necessary data - the promise will be + // resolved then. + HeapHashMap<uint64_t, Member<ScriptPromiseResolver>> + newly_created_anchor_ids_to_resolvers_; + // Mapping of hit test source ids (aka hit test subscription ids) to hit test // sources. Hit test source has to be stored via weak member - JavaScript side // will communicate that it's no longer interested in the subscription by @@ -407,10 +423,9 @@ class XRSession final Member<XRWebGLLayer> prev_base_layer_; Member<ResizeObserver> resize_observer_; Member<XRCanvasInputProvider> canvas_input_provider_; + Member<Element> overlay_element_; + Member<XRDOMOverlayState> dom_overlay_state_; bool environment_error_handler_subscribed_ = false; - HeapHashSet<Member<ScriptPromiseResolver>> hit_test_promises_; - // Set of promises returned from CreateAnchor that are still in-flight. - HeapHashSet<Member<ScriptPromiseResolver>> create_anchor_promises_; // Set of promises returned from requestHitTestSource and // requestHitTestSourceForTransientInput that are still in-flight. HeapHashSet<Member<ScriptPromiseResolver>> request_hit_test_source_promises_; diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_session.idl b/chromium/third_party/blink/renderer/modules/xr/xr_session.idl index cb85a643d06..18192fb37a0 100644 --- a/chromium/third_party/blink/renderer/modules/xr/xr_session.idl +++ b/chromium/third_party/blink/renderer/modules/xr/xr_session.idl @@ -32,6 +32,7 @@ enum XRVisibilityState { readonly attribute XRVisibilityState visibilityState; [SameObject] readonly attribute XRRenderState renderState; [MeasureAs=XRSessionGetInputSources, SameObject] readonly attribute XRInputSourceArray inputSources; + [SameObject] readonly attribute XRDOMOverlayState domOverlayState; attribute EventHandler onend; attribute EventHandler onselect; @@ -39,28 +40,26 @@ enum XRVisibilityState { attribute EventHandler onselectstart; attribute EventHandler onselectend; attribute EventHandler onvisibilitychange; + attribute EventHandler onsqueeze; + attribute EventHandler onsqueezestart; + attribute EventHandler onsqueezeend; - [RaisesException] void updateRenderState(optional XRRenderStateInit init); + [RaisesException] void updateRenderState(optional XRRenderStateInit init = {}); [CallWith=ScriptState, RaisesException] Promise<XRReferenceSpace> requestReferenceSpace(XRReferenceSpaceType type); long requestAnimationFrame(XRFrameRequestCallback callback); void cancelAnimationFrame(long handle); - [RuntimeEnabled=WebXRHitTest, CallWith=ScriptState, RaisesException] Promise<FrozenArray<XRHitResult>> requestHitTest(XRRay ray, XRSpace space); - // https://github.com/immersive-web/real-world-geometry/blob/master/plane-detection-explainer.md - [RuntimeEnabled=WebXRPlaneDetection] readonly attribute XRWorldTrackingState worldTrackingState; - [RuntimeEnabled=WebXRPlaneDetection, RaisesException] void updateWorldTrackingState(optional XRWorldTrackingStateInit state); - - [RuntimeEnabled=WebXRAnchors] readonly attribute XRAnchorSet trackedAnchors; - [RuntimeEnabled=WebXRAnchors, CallWith=ScriptState, RaisesException] Promise<XRAnchor> createAnchor(XRRigidTransform initial_pose, XRSpace space); + [RuntimeEnabled=WebXRIncubations] readonly attribute XRWorldTrackingState worldTrackingState; + [RuntimeEnabled=WebXRIncubations, RaisesException] void updateWorldTrackingState(optional XRWorldTrackingStateInit state = {}); [CallWith=ScriptState, Measure, RaisesException] Promise<void> end(); // https://github.com/immersive-web/hit-test/blob/master/hit-testing-explainer.md - [RuntimeEnabled=WebXRHitTest, CallWith=ScriptState, RaisesException] + [RuntimeEnabled=WebXRHitTest, CallWith=ScriptState, MeasureAs=XRSessionRequestHitTestSource, RaisesException] Promise<XRHitTestSource> requestHitTestSource(XRHitTestOptionsInit options); - [RuntimeEnabled=WebXRHitTest, CallWith=ScriptState, RaisesException] + [RuntimeEnabled=WebXRHitTest, CallWith=ScriptState, MeasureAs=XRSessionRequestHitTestSourceForTransientInput, RaisesException] Promise<XRTransientInputHitTestSource> requestHitTestSourceForTransientInput(XRTransientInputHitTestOptionsInit options); }; 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 index 8a683ff3768..0fb73b1684b 100644 --- a/chromium/third_party/blink/renderer/modules/xr/xr_session_event.cc +++ b/chromium/third_party/blink/renderer/modules/xr/xr_session_event.cc @@ -12,6 +12,13 @@ XRSessionEvent::XRSessionEvent(const AtomicString& type, XRSession* session) : Event(type, Bubbles::kNo, Cancelable::kYes), session_(session) {} XRSessionEvent::XRSessionEvent(const AtomicString& type, + XRSession* session, + Event::Bubbles bubbles, + Event::Cancelable cancelable, + Event::ComposedMode composed) + : Event(type, bubbles, cancelable, composed), session_(session) {} + +XRSessionEvent::XRSessionEvent(const AtomicString& type, const XRSessionEventInit* initializer) : Event(type, initializer) { if (initializer->hasSession()) @@ -24,7 +31,7 @@ const AtomicString& XRSessionEvent::InterfaceName() const { return event_interface_names::kXRSessionEvent; } -void XRSessionEvent::Trace(blink::Visitor* visitor) { +void XRSessionEvent::Trace(Visitor* visitor) { visitor->Trace(session_); Event::Trace(visitor); } 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 index fba431740bc..dd8d1460ef2 100644 --- a/chromium/third_party/blink/renderer/modules/xr/xr_session_event.h +++ b/chromium/third_party/blink/renderer/modules/xr/xr_session_event.h @@ -5,9 +5,9 @@ #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/bindings/modules/v8/v8_xr_session_event_init.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 { @@ -29,6 +29,11 @@ class XRSessionEvent final : public Event { XRSessionEvent(); XRSessionEvent(const AtomicString& type, XRSession*); + XRSessionEvent(const AtomicString& type, + XRSession*, + Event::Bubbles, + Event::Cancelable, + Event::ComposedMode); XRSessionEvent(const AtomicString& type, const XRSessionEventInit*); ~XRSessionEvent() override; @@ -36,7 +41,7 @@ class XRSessionEvent final : public Event { const AtomicString& InterfaceName() const override; - void Trace(blink::Visitor*) override; + void Trace(Visitor*) override; private: Member<XRSession> session_; 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 index 0079794480d..b26e8f1ea46 100644 --- a/chromium/third_party/blink/renderer/modules/xr/xr_session_event.idl +++ b/chromium/third_party/blink/renderer/modules/xr/xr_session_event.idl @@ -6,8 +6,8 @@ [ SecureContext, Exposed=Window, - RuntimeEnabled=WebXR, - Constructor(DOMString type, XRSessionEventInit eventInitDict) + RuntimeEnabled=WebXR ] interface XRSessionEvent : Event { + constructor(DOMString type, XRSessionEventInit eventInitDict); [SameObject] readonly attribute XRSession session; }; diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_session_init.idl b/chromium/third_party/blink/renderer/modules/xr/xr_session_init.idl index 5de946516c2..11d315b58ae 100644 --- a/chromium/third_party/blink/renderer/modules/xr/xr_session_init.idl +++ b/chromium/third_party/blink/renderer/modules/xr/xr_session_init.idl @@ -6,4 +6,5 @@ dictionary XRSessionInit { sequence<any> requiredFeatures; sequence<any> optionalFeatures; + XRDOMOverlayInit domOverlay; }; diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_setlike.h b/chromium/third_party/blink/renderer/modules/xr/xr_setlike.h index 446ccb0a515..03e89cdde8a 100644 --- a/chromium/third_party/blink/renderer/modules/xr/xr_setlike.h +++ b/chromium/third_party/blink/renderer/modules/xr/xr_setlike.h @@ -57,7 +57,7 @@ class XRSetlike : public SetlikeIterable<Member<ElementType>> { return true; } - void Trace(blink::Visitor* visitor) override { + void Trace(Visitor* visitor) override { visitor->Trace(elements_); SetlikeIterable<Member<ElementType>>::IterationSource::Trace(visitor); } diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_space.cc b/chromium/third_party/blink/renderer/modules/xr/xr_space.cc index e94164996bc..5f61ac748f7 100644 --- a/chromium/third_party/blink/renderer/modules/xr/xr_space.cc +++ b/chromium/third_party/blink/renderer/modules/xr/xr_space.cc @@ -4,6 +4,7 @@ #include "third_party/blink/renderer/modules/xr/xr_space.h" +#include "base/stl_util.h" #include "third_party/blink/renderer/modules/event_target_modules.h" #include "third_party/blink/renderer/modules/xr/xr_input_source.h" #include "third_party/blink/renderer/modules/xr/xr_pose.h" @@ -16,94 +17,97 @@ XRSpace::XRSpace(XRSession* session) : session_(session) {} XRSpace::~XRSpace() = default; -std::unique_ptr<TransformationMatrix> XRSpace::MojoFromSpace() { - // The base XRSpace does not have any relevant information, so can't determine - // a transform here. - return nullptr; -} - -std::unique_ptr<TransformationMatrix> XRSpace::DefaultViewerPose() { - return nullptr; -} +std::unique_ptr<TransformationMatrix> XRSpace::NativeFromViewer( + const TransformationMatrix* mojo_from_viewer) { + if (!mojo_from_viewer) + return nullptr; -std::unique_ptr<TransformationMatrix> XRSpace::SpaceFromMojo( - const TransformationMatrix& mojo_from_viewer) { - return nullptr; -} + std::unique_ptr<TransformationMatrix> native_from_mojo = NativeFromMojo(); + if (!native_from_mojo) + return nullptr; -std::unique_ptr<TransformationMatrix> XRSpace::SpaceFromViewer( - const TransformationMatrix& mojo_from_viewer) { - return nullptr; -} + native_from_mojo->Multiply(*mojo_from_viewer); -std::unique_ptr<TransformationMatrix> XRSpace::SpaceFromInputForViewer( - const TransformationMatrix& mojo_from_input, - const TransformationMatrix& mojo_from_viewer) { - return nullptr; + // This is now native_from_viewer + return native_from_mojo; + ; } -TransformationMatrix XRSpace::OriginOffsetMatrix() { +TransformationMatrix XRSpace::NativeFromOffsetMatrix() { TransformationMatrix identity; return identity; } -TransformationMatrix XRSpace::InverseOriginOffsetMatrix() { +TransformationMatrix XRSpace::OffsetFromNativeMatrix() { TransformationMatrix identity; return identity; } -XRPose* XRSpace::getPose(XRSpace* other_space, - const TransformationMatrix* base_pose_matrix) { - std::unique_ptr<TransformationMatrix> mojo_from_space = MojoFromSpace(); - if (!mojo_from_space) { +std::unique_ptr<TransformationMatrix> XRSpace::MojoFromOffsetMatrix() { + auto maybe_mojo_from_native = MojoFromNative(); + if (!maybe_mojo_from_native) { return nullptr; } - std::unique_ptr<TransformationMatrix> mojo_from_other = - other_space->MojoFromSpace(); - if (!mojo_from_other) { + // Modifies maybe_mojo_from_native - it becomes mojo_from_offset_matrix. + // Saves a heap allocation since there is no need to create a new unique_ptr. + maybe_mojo_from_native->Multiply(NativeFromOffsetMatrix()); + return maybe_mojo_from_native; +} + +std::unique_ptr<TransformationMatrix> XRSpace::TryInvert( + std::unique_ptr<TransformationMatrix> matrix) { + if (!matrix) + return nullptr; + + DCHECK(matrix->IsInvertible()); + return std::make_unique<TransformationMatrix>(matrix->Inverse()); +} + +bool XRSpace::EmulatedPosition() const { + return session()->EmulatedPosition(); +} + +XRPose* XRSpace::getPose(XRSpace* other_space) { + // Named mojo_from_offset because that is what we will leave it as, though it + // starts mojo_from_native. + std::unique_ptr<TransformationMatrix> mojo_from_offset = MojoFromNative(); + if (!mojo_from_offset) { return nullptr; } - // Rigid transforms should always be invertible. - DCHECK(mojo_from_other->IsInvertible()); - TransformationMatrix other_from_mojo = mojo_from_other->Inverse(); + // Add any origin offset now. + mojo_from_offset->Multiply(NativeFromOffsetMatrix()); + + std::unique_ptr<TransformationMatrix> other_from_mojo = + other_space->NativeFromMojo(); + if (!other_from_mojo) + return nullptr; + + // Add any origin offset from the other space now. + TransformationMatrix other_offset_from_mojo = + other_space->OffsetFromNativeMatrix().Multiply(*other_from_mojo); // TODO(crbug.com/969133): Update how EmulatedPosition is determined here once // spec issue https://github.com/immersive-web/webxr/issues/534 has been // resolved. - TransformationMatrix other_from_space = - other_from_mojo.Multiply(*mojo_from_space); - return MakeGarbageCollected<XRPose>(other_from_space, - session()->EmulatedPosition()); + TransformationMatrix other_offset_from_offset = + other_offset_from_mojo.Multiply(*mojo_from_offset); + return MakeGarbageCollected<XRPose>( + other_offset_from_offset, + EmulatedPosition() || other_space->EmulatedPosition()); } -std::unique_ptr<TransformationMatrix> -XRSpace::SpaceFromViewerWithDefaultAndOffset( - const TransformationMatrix* mojo_from_viewer) { - std::unique_ptr<TransformationMatrix> space_from_viewer; - - // If we don't have a valid base pose, request the reference space's default - // viewer pose. Most common when tracking is lost. - if (mojo_from_viewer) { - space_from_viewer = SpaceFromViewer(*mojo_from_viewer); - } else { - space_from_viewer = DefaultViewerPose(); - } +std::unique_ptr<TransformationMatrix> XRSpace::OffsetFromViewer() { + std::unique_ptr<TransformationMatrix> native_from_viewer = + NativeFromViewer(base::OptionalOrNullptr(session()->MojoFromViewer())); - // Can only update an XRViewerPose's views with an invertible matrix. - if (!space_from_viewer || !space_from_viewer->IsInvertible()) { + if (!native_from_viewer) { return nullptr; } - // Account for any changes made to the reference space's origin offset so that - // things like teleportation works. - // - // This is offset_from_viewer = offset_from_space * space_from_viewer, - // where offset_from_viewer = inverse(viewer_from_offset). - // TODO(https://crbug.com/1008466): move originOffset to separate class? return std::make_unique<TransformationMatrix>( - InverseOriginOffsetMatrix().Multiply(*space_from_viewer)); + OffsetFromNativeMatrix().Multiply(*native_from_viewer)); } ExecutionContext* XRSpace::GetExecutionContext() const { @@ -118,7 +122,7 @@ base::Optional<XRNativeOriginInformation> XRSpace::NativeOrigin() const { return base::nullopt; } -void XRSpace::Trace(blink::Visitor* visitor) { +void XRSpace::Trace(Visitor* visitor) { visitor->Trace(session_); ScriptWrappable::Trace(visitor); EventTargetWithInlineData::Trace(visitor); diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_space.h b/chromium/third_party/blink/renderer/modules/xr/xr_space.h index 1ea887c709e..889718800e0 100644 --- a/chromium/third_party/blink/renderer/modules/xr/xr_space.h +++ b/chromium/third_party/blink/renderer/modules/xr/xr_space.h @@ -31,59 +31,65 @@ class XRSpace : public EventTargetWithInlineData { public: ~XRSpace() override; - // Gets a default viewer pose appropriate for this space. This is an identity - // for viewer space, null for everything else. - virtual std::unique_ptr<TransformationMatrix> DefaultViewerPose(); - - // Gets the pose of this space's origin in mojo space. This is a transform - // that maps from this space to mojo space (aka device space). Unless noted - // otherwise, all data returned over vr_service.mojom interfaces is expressed - // in mojo space coordinates. Returns nullptr if computing a transform is not - // possible. - virtual std::unique_ptr<TransformationMatrix> MojoFromSpace(); - - // Gets the pose of the mojo origin in this reference space, corresponding - // to a transform from mojo coordinates to reference space coordinates. - virtual std::unique_ptr<TransformationMatrix> SpaceFromMojo( - const TransformationMatrix& mojo_from_viewer); - - // Gets the viewer pose in this space, corresponding to a transform from - // viewer coordinates to this space's coordinates. (The position elements of - // the transformation matrix are the viewer's location in this space's - // coordinates.) - virtual std::unique_ptr<TransformationMatrix> SpaceFromViewer( - const TransformationMatrix& mojo_from_viewer); - - // Gets an input pose in this space. This requires the viewer pose as - // an additional input since a "viewer" space needs to transform the - // input pose to headset-relative coordinates. - virtual std::unique_ptr<TransformationMatrix> SpaceFromInputForViewer( - const TransformationMatrix& mojo_from_input, - const TransformationMatrix& mojo_from_viewer); - - virtual XRPose* getPose(XRSpace* other_space, - const TransformationMatrix* mojo_from_viewer); - - // Gets the viewer pose in this space, including using an appropriate - // default pose (i.e. if tracking is lost), and applying originOffset - // as applicable. TODO(https://crbug.com/1008466): consider moving - // the originOffset handling to a separate class? - std::unique_ptr<TransformationMatrix> SpaceFromViewerWithDefaultAndOffset( + // Gets the pose of this space's native origin in mojo space. This transform + // maps from this space's native origin to mojo space (aka device space). + // Unless noted otherwise, all data returned over vr_service.mojom interfaces + // is expressed in mojo space coordinates. + // Returns nullptr if computing a transform is not possible. + virtual std::unique_ptr<TransformationMatrix> MojoFromNative() = 0; + + // Convenience method to try to get the inverse of the above. This will return + // the pose of the mojo origin in this space's native origin. + // Returns nullptr if computing a transform is not possible. + virtual std::unique_ptr<TransformationMatrix> NativeFromMojo() = 0; + + // Gets the viewer pose in the native coordinates of this space, corresponding + // to a transform from viewer coordinates to this space's native coordinates. + // (The position elements of the transformation matrix are the viewer's + // location in this space's coordinates.) + // Prefer this helper method over querying NativeFromMojo and multiplying + // on the calling side, as this allows the viewer space to return identity + // instead of something near to, but not quite, identity. + // Returns nullptr if computing a transform is not possible. + virtual std::unique_ptr<TransformationMatrix> NativeFromViewer( const TransformationMatrix* mojo_from_viewer); + // Convenience method for calling NativeFromViewer with the current + // MojoFromViewer of the session associated with this space. This also handles + // the multiplication of OffsetFromNative onto the result of NativeFromViewer. + // Returns nullptr if computing a transform is not possible. + std::unique_ptr<TransformationMatrix> OffsetFromViewer(); + + // Return origin offset matrix, aka native_origin_from_offset_space. + virtual TransformationMatrix NativeFromOffsetMatrix(); + virtual TransformationMatrix OffsetFromNativeMatrix(); + + // Returns transformation from offset space to mojo space. Convenience method, + // returns MojoFromNative() * NativeFromOffsetMatrix() or nullptr if computing + // a transform is not possible. + std::unique_ptr<TransformationMatrix> MojoFromOffsetMatrix(); + + // Indicates whether or not the position portion of the native origin of this + // space is emulated. + virtual bool EmulatedPosition() const; + + // Gets the pose of this space's origin in |other_space|. This is a transform + // that maps from this space to the other's space, or in other words: + // other_from_this. + virtual XRPose* getPose(XRSpace* other_space); XRSession* session() const { return session_; } // EventTarget overrides. ExecutionContext* GetExecutionContext() const override; const AtomicString& InterfaceName() const override; - // Return origin offset matrix, aka native_origin_from_offset_space. - virtual TransformationMatrix OriginOffsetMatrix(); - virtual TransformationMatrix InverseOriginOffsetMatrix(); - virtual base::Optional<XRNativeOriginInformation> NativeOrigin() const = 0; - void Trace(blink::Visitor* visitor) override; + void Trace(Visitor* visitor) override; + + protected: + std::unique_ptr<TransformationMatrix> TryInvert( + std::unique_ptr<TransformationMatrix> matrix); private: const Member<XRSession> session_; diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_spherical_harmonics.cc b/chromium/third_party/blink/renderer/modules/xr/xr_spherical_harmonics.cc new file mode 100644 index 00000000000..7d5ec4600ca --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/xr/xr_spherical_harmonics.cc @@ -0,0 +1,38 @@ +// Copyright 2019 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_spherical_harmonics.h" + +#include "device/vr/public/mojom/vr_service.mojom-blink.h" +#include "third_party/blink/renderer/core/geometry/dom_point_read_only.h" + +namespace blink { + +XRSphericalHarmonics::XRSphericalHarmonics( + const device::mojom::blink::XRSphericalHarmonics& spherical_harmonics) { + DCHECK_EQ(spherical_harmonics.coefficients.size(), 9u); + + coefficients_ = DOMFloat32Array::Create( + spherical_harmonics.coefficients.data()->components, + spherical_harmonics.coefficients.size() * + device::RgbTupleF32::kNumComponents); + + orientation_ = DOMPointReadOnly::Create(0, 0, 0, 1); +} + +DOMPointReadOnly* XRSphericalHarmonics::orientation() const { + return orientation_.Get(); +} + +DOMFloat32Array* XRSphericalHarmonics::coefficients() const { + return coefficients_.Get(); +} + +void XRSphericalHarmonics::Trace(Visitor* visitor) { + visitor->Trace(coefficients_); + visitor->Trace(orientation_); + ScriptWrappable::Trace(visitor); +} + +} // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_spherical_harmonics.h b/chromium/third_party/blink/renderer/modules/xr/xr_spherical_harmonics.h new file mode 100644 index 00000000000..de7378ffdfe --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/xr/xr_spherical_harmonics.h @@ -0,0 +1,35 @@ +// Copyright 2019 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_SPHERICAL_HARMONICS_H_ +#define THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_SPHERICAL_HARMONICS_H_ + +#include "device/vr/public/mojom/vr_service.mojom-blink-forward.h" +#include "third_party/blink/renderer/core/typed_arrays/dom_typed_array.h" +#include "third_party/blink/renderer/platform/bindings/script_wrappable.h" + +namespace blink { + +class DOMPointReadOnly; + +class XRSphericalHarmonics : public ScriptWrappable { + DEFINE_WRAPPERTYPEINFO(); + + public: + XRSphericalHarmonics( + const device::mojom::blink::XRSphericalHarmonics& spherical_harmonics); + + DOMPointReadOnly* orientation() const; + DOMFloat32Array* coefficients() const; + + void Trace(Visitor* visitor) override; + + private: + Member<DOMFloat32Array> coefficients_; + Member<DOMPointReadOnly> orientation_; +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_SPHERICAL_HARMONICS_H_ diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_spherical_harmonics.idl b/chromium/third_party/blink/renderer/modules/xr/xr_spherical_harmonics.idl new file mode 100644 index 00000000000..720ea985d6e --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/xr/xr_spherical_harmonics.idl @@ -0,0 +1,14 @@ +// Copyright 2019 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, + Exposed=Window, + RuntimeEnabled=WebXRIncubations +] +interface XRSphericalHarmonics { + readonly attribute DOMPointReadOnly orientation; + readonly attribute Float32Array coefficients; +}; + diff --git a/chromium/third_party/blink/renderer/modules/xr/xr.cc b/chromium/third_party/blink/renderer/modules/xr/xr_system.cc index 0f0a0c792c2..a94164360dc 100644 --- a/chromium/third_party/blink/renderer/modules/xr/xr.cc +++ b/chromium/third_party/blink/renderer/modules/xr/xr_system.cc @@ -2,20 +2,21 @@ // 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 "third_party/blink/renderer/modules/xr/xr_system.h" #include <utility> #include "services/metrics/public/cpp/ukm_builders.h" #include "third_party/blink/public/common/browser_interface_broker_proxy.h" #include "third_party/blink/public/mojom/feature_policy/feature_policy.mojom-blink.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/bindings/core/v8/v8_fullscreen_options.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/element.h" #include "third_party/blink/renderer/core/frame/local_frame.h" #include "third_party/blink/renderer/core/fullscreen/fullscreen.h" +#include "third_party/blink/renderer/core/fullscreen/scoped_allow_fullscreen.h" #include "third_party/blink/renderer/core/html/html_element.h" #include "third_party/blink/renderer/core/inspector/console_message.h" #include "third_party/blink/renderer/core/layout/layout_view.h" @@ -54,8 +55,8 @@ const char kSessionNotSupported[] = const char kNoDevicesMessage[] = "No XR hardware found."; const char kImmersiveArModeNotValid[] = - "Failed to execute '%s' on 'XR': The provided value 'immersive-ar' is not " - "a valid enum value of type XRSessionMode."; + "Failed to execute '%s' on 'XRSystem': The provided value 'immersive-ar' " + "is not a valid enum value of type XRSessionMode."; constexpr device::mojom::XRSessionFeature kDefaultImmersiveVrFeatures[] = { device::mojom::XRSessionFeature::REF_SPACE_VIEWER, @@ -71,40 +72,29 @@ constexpr device::mojom::XRSessionFeature kDefaultInlineFeatures[] = { device::mojom::XRSessionFeature::REF_SPACE_VIEWER, }; -// Helper method to convert session mode into Mojo options. -device::mojom::blink::XRSessionOptionsPtr convertModeToMojo( - XRSession::SessionMode mode) { - auto session_options = device::mojom::blink::XRSessionOptions::New(); - session_options->immersive = (mode == XRSession::kModeImmersiveVR || - mode == XRSession::kModeImmersiveAR); - session_options->environment_integration = - mode == XRSession::kModeImmersiveAR; - - return session_options; -} - -XRSession::SessionMode stringToSessionMode(const String& mode_string) { +device::mojom::blink::XRSessionMode stringToSessionMode( + const String& mode_string) { if (mode_string == "inline") { - return XRSession::kModeInline; + return device::mojom::blink::XRSessionMode::kInline; } if (mode_string == "immersive-vr") { - return XRSession::kModeImmersiveVR; + return device::mojom::blink::XRSessionMode::kImmersiveVr; } if (mode_string == "immersive-ar") { - return XRSession::kModeImmersiveAR; + return device::mojom::blink::XRSessionMode::kImmersiveAr; } NOTREACHED(); // Only strings in the enum are allowed by IDL. - return XRSession::kModeInline; + return device::mojom::blink::XRSessionMode::kInline; } -const char* SessionModeToString(const XRSession::SessionMode& session_mode) { - switch (session_mode) { - case XRSession::SessionMode::kModeInline: +const char* SessionModeToString(device::mojom::blink::XRSessionMode mode) { + switch (mode) { + case device::mojom::blink::XRSessionMode::kInline: return "inline"; - case XRSession::SessionMode::kModeImmersiveVR: + case device::mojom::blink::XRSessionMode::kImmersiveVr: return "immersive-vr"; - case XRSession::SessionMode::kModeImmersiveAR: + case device::mojom::blink::XRSessionMode::kImmersiveAr: return "immersive-ar"; } @@ -128,16 +118,21 @@ base::Optional<device::mojom::XRSessionFeature> StringToXRSessionFeature( return device::mojom::XRSessionFeature::REF_SPACE_BOUNDED_FLOOR; } else if (feature_string == "unbounded") { return device::mojom::XRSessionFeature::REF_SPACE_UNBOUNDED; - } else if (RuntimeEnabledFeatures::WebXRARDOMOverlayEnabled(doc) && - feature_string == "dom-overlay-for-handheld-ar") { - return device::mojom::XRSessionFeature::DOM_OVERLAY_FOR_HANDHELD_AR; + } else if (RuntimeEnabledFeatures::WebXRHitTestEnabled(doc) && + feature_string == "hit-test") { + return device::mojom::XRSessionFeature::HIT_TEST; + } else if (feature_string == "dom-overlay") { + return device::mojom::XRSessionFeature::DOM_OVERLAY; } return base::nullopt; } bool IsFeatureValidForMode(device::mojom::XRSessionFeature feature, - XRSession::SessionMode mode) { + device::mojom::blink::XRSessionMode mode, + XRSessionInit* session_init, + ExecutionContext* execution_context, + mojom::ConsoleMessageLevel error_level) { switch (feature) { case device::mojom::XRSessionFeature::REF_SPACE_VIEWER: case device::mojom::XRSessionFeature::REF_SPACE_LOCAL: @@ -145,10 +140,20 @@ bool IsFeatureValidForMode(device::mojom::XRSessionFeature feature, return true; case device::mojom::XRSessionFeature::REF_SPACE_BOUNDED_FLOOR: case device::mojom::XRSessionFeature::REF_SPACE_UNBOUNDED: - return mode == XRSession::kModeImmersiveVR || - mode == XRSession::kModeImmersiveAR; - case device::mojom::XRSessionFeature::DOM_OVERLAY_FOR_HANDHELD_AR: - return mode == XRSession::kModeImmersiveAR; + case device::mojom::XRSessionFeature::HIT_TEST: + return mode == device::mojom::blink::XRSessionMode::kImmersiveVr || + mode == device::mojom::blink::XRSessionMode::kImmersiveAr; + case device::mojom::XRSessionFeature::DOM_OVERLAY: + if (mode != device::mojom::blink::XRSessionMode::kImmersiveAr) + return false; + if (!session_init->hasDomOverlay()) { + execution_context->AddConsoleMessage(MakeGarbageCollected< + ConsoleMessage>( + mojom::ConsoleMessageSource::kJavaScript, error_level, + "Must specify a valid domOverlay.root element in XRSessionInit")); + return false; + } + return true; } } @@ -164,8 +169,9 @@ bool HasRequiredFeaturePolicy(const Document* doc, case device::mojom::XRSessionFeature::REF_SPACE_LOCAL_FLOOR: case device::mojom::XRSessionFeature::REF_SPACE_BOUNDED_FLOOR: case device::mojom::XRSessionFeature::REF_SPACE_UNBOUNDED: - case device::mojom::XRSessionFeature::DOM_OVERLAY_FOR_HANDHELD_AR: - return doc->IsFeatureEnabled(mojom::FeaturePolicyFeature::kWebXr, + case device::mojom::XRSessionFeature::DOM_OVERLAY: + case device::mojom::XRSessionFeature::HIT_TEST: + return doc->IsFeatureEnabled(mojom::blink::FeaturePolicyFeature::kWebXr, ReportOptions::kReportOnFailure); } } @@ -196,7 +202,7 @@ const char* CheckImmersiveSessionRequestAllowed(LocalFrame* frame, // Ensure that the inline session request is allowed, if not // return which security error occurred. // https://immersive-web.github.io/webxr/#inline-session-request-is-allowed -const char* XR::CheckInlineSessionRequestAllowed( +const char* XRSystem::CheckInlineSessionRequestAllowed( LocalFrame* frame, const PendingRequestSessionQuery& query) { // Without user activation, we must reject the session if *any* features @@ -225,24 +231,26 @@ const char* XR::CheckInlineSessionRequestAllowed( return nullptr; } -XR::PendingSupportsSessionQuery::PendingSupportsSessionQuery( +XRSystem::PendingSupportsSessionQuery::PendingSupportsSessionQuery( ScriptPromiseResolver* resolver, - XRSession::SessionMode session_mode, + device::mojom::blink::XRSessionMode session_mode, bool throw_on_unsupported) : resolver_(resolver), mode_(session_mode), throw_on_unsupported_(throw_on_unsupported) {} -void XR::PendingSupportsSessionQuery::Trace(blink::Visitor* visitor) { +void XRSystem::PendingSupportsSessionQuery::Trace(Visitor* visitor) { visitor->Trace(resolver_); } -void XR::PendingSupportsSessionQuery::Resolve(bool supported, - ExceptionState* exception_state) { +void XRSystem::PendingSupportsSessionQuery::Resolve( + bool supported, + ExceptionState* exception_state) { if (throw_on_unsupported_) { if (supported) { resolver_->Resolve(); } else { + DVLOG(2) << __func__ << ": session is unsupported - throwing exception"; RejectWithDOMException(DOMExceptionCode::kNotSupportedError, kSessionNotSupported, exception_state); } @@ -251,7 +259,7 @@ void XR::PendingSupportsSessionQuery::Resolve(bool supported, } } -void XR::PendingSupportsSessionQuery::RejectWithDOMException( +void XRSystem::PendingSupportsSessionQuery::RejectWithDOMException( DOMExceptionCode exception_code, const String& message, ExceptionState* exception_state) { @@ -269,7 +277,7 @@ void XR::PendingSupportsSessionQuery::RejectWithDOMException( } } -void XR::PendingSupportsSessionQuery::RejectWithSecurityError( +void XRSystem::PendingSupportsSessionQuery::RejectWithSecurityError( const String& sanitized_message, ExceptionState* exception_state) { if (exception_state) { @@ -284,7 +292,7 @@ void XR::PendingSupportsSessionQuery::RejectWithSecurityError( } } -void XR::PendingSupportsSessionQuery::RejectWithTypeError( +void XRSystem::PendingSupportsSessionQuery::RejectWithTypeError( const String& message, ExceptionState* exception_state) { if (exception_state) { @@ -299,14 +307,15 @@ void XR::PendingSupportsSessionQuery::RejectWithTypeError( } } -XRSession::SessionMode XR::PendingSupportsSessionQuery::mode() const { +device::mojom::blink::XRSessionMode +XRSystem::PendingSupportsSessionQuery::mode() const { return mode_; } -XR::PendingRequestSessionQuery::PendingRequestSessionQuery( +XRSystem::PendingRequestSessionQuery::PendingRequestSessionQuery( int64_t ukm_source_id, ScriptPromiseResolver* resolver, - XRSession::SessionMode session_mode, + device::mojom::blink::XRSessionMode session_mode, RequestedXRSessionFeatureSet required_features, RequestedXRSessionFeatureSet optional_features) : resolver_(resolver), @@ -317,7 +326,7 @@ XR::PendingRequestSessionQuery::PendingRequestSessionQuery( ParseSensorRequirement(); } -void XR::PendingRequestSessionQuery::Resolve( +void XRSystem::PendingRequestSessionQuery::Resolve( XRSession* session, mojo::PendingRemote<device::mojom::blink::XRSessionMetricsRecorder> metrics_recorder) { @@ -326,7 +335,7 @@ void XR::PendingRequestSessionQuery::Resolve( std::move(metrics_recorder)); } -void XR::PendingRequestSessionQuery::RejectWithDOMException( +void XRSystem::PendingRequestSessionQuery::RejectWithDOMException( DOMExceptionCode exception_code, const String& message, ExceptionState* exception_state) { @@ -343,7 +352,7 @@ void XR::PendingRequestSessionQuery::RejectWithDOMException( ReportRequestSessionResult(SessionRequestStatus::kOtherError); } -void XR::PendingRequestSessionQuery::RejectWithSecurityError( +void XRSystem::PendingRequestSessionQuery::RejectWithSecurityError( const String& sanitized_message, ExceptionState* exception_state) { if (exception_state) { @@ -357,7 +366,7 @@ void XR::PendingRequestSessionQuery::RejectWithSecurityError( ReportRequestSessionResult(SessionRequestStatus::kOtherError); } -void XR::PendingRequestSessionQuery::RejectWithTypeError( +void XRSystem::PendingRequestSessionQuery::RejectWithTypeError( const String& message, ExceptionState* exception_state) { if (exception_state) { @@ -372,7 +381,7 @@ void XR::PendingRequestSessionQuery::RejectWithTypeError( } device::mojom::XRSessionFeatureRequestStatus -XR::PendingRequestSessionQuery::GetFeatureRequestStatus( +XRSystem::PendingRequestSessionQuery::GetFeatureRequestStatus( device::mojom::XRSessionFeature feature, const XRSession* session) const { using device::mojom::XRSessionFeatureRequestStatus; @@ -394,7 +403,7 @@ XR::PendingRequestSessionQuery::GetFeatureRequestStatus( return XRSessionFeatureRequestStatus::kNotRequested; } -void XR::PendingRequestSessionQuery::ReportRequestSessionResult( +void XRSystem::PendingRequestSessionQuery::ReportRequestSessionResult( SessionRequestStatus status, XRSession* session, mojo::PendingRemote<device::mojom::blink::XRSessionMetricsRecorder> @@ -416,6 +425,8 @@ void XR::PendingRequestSessionQuery::ReportRequestSessionResult( XRSessionFeature::REF_SPACE_BOUNDED_FLOOR, session); auto feature_request_unbounded = GetFeatureRequestStatus(XRSessionFeature::REF_SPACE_UNBOUNDED, session); + auto feature_request_dom_overlay = + GetFeatureRequestStatus(XRSessionFeature::DOM_OVERLAY, session); ukm::builders::XR_WebXR_SessionRequest(ukm_source_id_) .SetMode(static_cast<int64_t>(mode_)) @@ -428,6 +439,15 @@ void XR::PendingRequestSessionQuery::ReportRequestSessionResult( .SetFeature_Unbounded(static_cast<int64_t>(feature_request_unbounded)) .Record(doc->UkmRecorder()); + // If the session was successfully created and DOM overlay was requested, + // count this as a use of the DOM overlay feature. + if (session && status == SessionRequestStatus::kSuccess && + feature_request_dom_overlay != + device::mojom::XRSessionFeatureRequestStatus::kNotRequested) { + UseCounter::Count(session->GetExecutionContext(), + WebFeature::kXRDOMOverlay); + } + if (session && metrics_recorder) { mojo::Remote<device::mojom::blink::XRSessionMetricsRecorder> recorder( std::move(metrics_recorder)); @@ -436,35 +456,36 @@ void XR::PendingRequestSessionQuery::ReportRequestSessionResult( } } -XRSession::SessionMode XR::PendingRequestSessionQuery::mode() const { +device::mojom::blink::XRSessionMode XRSystem::PendingRequestSessionQuery::mode() + const { return mode_; } -const XRSessionFeatureSet& XR::PendingRequestSessionQuery::RequiredFeatures() - const { +const XRSessionFeatureSet& +XRSystem::PendingRequestSessionQuery::RequiredFeatures() const { return required_features_.valid_features; } -const XRSessionFeatureSet& XR::PendingRequestSessionQuery::OptionalFeatures() - const { +const XRSessionFeatureSet& +XRSystem::PendingRequestSessionQuery::OptionalFeatures() const { return optional_features_.valid_features; } -bool XR::PendingRequestSessionQuery::InvalidRequiredFeatures() const { +bool XRSystem::PendingRequestSessionQuery::InvalidRequiredFeatures() const { return required_features_.invalid_features; } -bool XR::PendingRequestSessionQuery::InvalidOptionalFeatures() const { +bool XRSystem::PendingRequestSessionQuery::InvalidOptionalFeatures() const { return optional_features_.invalid_features; } -ScriptState* XR::PendingRequestSessionQuery::GetScriptState() const { +ScriptState* XRSystem::PendingRequestSessionQuery::GetScriptState() const { return resolver_->GetScriptState(); } -void XR::PendingRequestSessionQuery::ParseSensorRequirement() { +void XRSystem::PendingRequestSessionQuery::ParseSensorRequirement() { // All modes other than inline require sensors. - if (mode_ != XRSession::kModeInline) { + if (mode_ != device::mojom::blink::XRSessionMode::kInline) { sensor_requirement_ = SensorRequirement::kRequired; return; } @@ -489,14 +510,150 @@ void XR::PendingRequestSessionQuery::ParseSensorRequirement() { sensor_requirement_ = kNone; } -void XR::PendingRequestSessionQuery::Trace(blink::Visitor* visitor) { +void XRSystem::PendingRequestSessionQuery::Trace(Visitor* visitor) { visitor->Trace(resolver_); + visitor->Trace(dom_overlay_element_); +} + +XRSystem::OverlayFullscreenEventManager::OverlayFullscreenEventManager( + XRSystem* xr, + XRSystem::PendingRequestSessionQuery* query, + device::mojom::blink::RequestSessionResultPtr result) + : xr_(xr), query_(query), result_(std::move(result)) { + DVLOG(2) << __func__; +} + +XRSystem::OverlayFullscreenEventManager::~OverlayFullscreenEventManager() = + default; + +void XRSystem::OverlayFullscreenEventManager::Invoke( + ExecutionContext* execution_context, + Event* event) { + DVLOG(2) << __func__ << ": event type=" << event->type(); + + // This handler should only be called once, it's unregistered after use. + DCHECK(query_); + DCHECK(result_); + + Element* element = query_->DOMOverlayElement(); + element->GetDocument().removeEventListener( + event_type_names::kFullscreenchange, this, true); + element->GetDocument().removeEventListener(event_type_names::kFullscreenerror, + this, true); + + if (event->type() == event_type_names::kFullscreenchange) { + // Succeeded, proceed with session creation. + element->GetDocument().SetIsXrOverlay(true, element); + xr_->OnRequestSessionReturned(query_, std::move(result_)); + } + + if (event->type() == event_type_names::kFullscreenerror) { + // Failed, reject the session + xr_->OnRequestSessionReturned( + query_, device::mojom::blink::RequestSessionResult::NewFailureReason( + device::mojom::RequestSessionError::INVALID_CLIENT)); + } +} + +void XRSystem::OverlayFullscreenEventManager::RequestFullscreen() { + Element* element = query_->DOMOverlayElement(); + DCHECK(element); + + if (element == Fullscreen::FullscreenElementFrom(element->GetDocument())) { + // It's possible that the requested element is already fullscreen, in which + // case we must not wait for a fullscreenchange event since it won't arrive. + // Detect that and proceed directly with session creation in this case. This + // can happen if the site used Fullscreen API to place the element into + // fullscreen mode before requesting the session, and if the session can + // proceed without needing a consent prompt. (Showing a dialog exits + // fullscreen mode.) + DVLOG(2) << __func__ << ": requested element already fullscreen"; + element->GetDocument().SetIsXrOverlay(true, element); + xr_->OnRequestSessionReturned(query_, std::move(result_)); + return; + } + + // Set up event listeners for success and failure. + element->GetDocument().addEventListener(event_type_names::kFullscreenchange, + this, true); + element->GetDocument().addEventListener(event_type_names::kFullscreenerror, + this, true); + + // Use the event-generating unprefixed version of RequestFullscreen to ensure + // that the fullscreen event listener is informed once this completes. + FullscreenOptions* options = FullscreenOptions::Create(); + options->setNavigationUI("hide"); + + // Grant fullscreen API permission for the following call. Requesting the + // immersive session had required a user activation state, but that may have + // expired by now due to the user taking time to respond to the consent + // prompt. + ScopedAllowFullscreen scope(ScopedAllowFullscreen::kXrOverlay); + + Fullscreen::RequestFullscreen(*element, options, + Fullscreen::RequestType::kUnprefixed); +} + +void XRSystem::OverlayFullscreenEventManager::Trace(Visitor* visitor) { + visitor->Trace(xr_); + visitor->Trace(query_); + EventListener::Trace(visitor); +} + +XRSystem::OverlayFullscreenExitObserver::OverlayFullscreenExitObserver( + XRSystem* xr) + : xr_(xr) { + DVLOG(2) << __func__; +} + +XRSystem::OverlayFullscreenExitObserver::~OverlayFullscreenExitObserver() = + default; + +void XRSystem::OverlayFullscreenExitObserver::Invoke( + ExecutionContext* execution_context, + Event* event) { + DVLOG(2) << __func__ << ": event type=" << event->type(); + + element_->GetDocument().removeEventListener( + event_type_names::kFullscreenchange, this, true); + + if (event->type() == event_type_names::kFullscreenchange) { + // Succeeded, proceed with session shutdown. + xr_->ExitPresent(std::move(on_exited_)); + } +} + +void XRSystem::OverlayFullscreenExitObserver::ExitFullscreen( + Element* element, + base::OnceClosure on_exited) { + DVLOG(2) << __func__; + element_ = element; + on_exited_ = std::move(on_exited); + + element->GetDocument().addEventListener(event_type_names::kFullscreenchange, + this, true); + // "ua_originated" means that the browser process already exited + // fullscreen. Set it to false because we need the browser process + // to get notified that it needs to exit fullscreen. Use + // FullyExitFullscreen to ensure that we return to non-fullscreen mode. + // ExitFullscreen only unfullscreens a single element, potentially + // leaving others in fullscreen mode. + constexpr bool kUaOriginated = false; + + Fullscreen::FullyExitFullscreen(element_->GetDocument(), kUaOriginated); +} + +void XRSystem::OverlayFullscreenExitObserver::Trace(Visitor* visitor) { + visitor->Trace(xr_); + visitor->Trace(element_); + EventListener::Trace(visitor); } -device::mojom::blink::XRSessionOptionsPtr XR::XRSessionOptionsFromQuery( +device::mojom::blink::XRSessionOptionsPtr XRSystem::XRSessionOptionsFromQuery( const PendingRequestSessionQuery& query) { device::mojom::blink::XRSessionOptionsPtr session_options = - convertModeToMojo(query.mode()); + device::mojom::blink::XRSessionOptions::New(); + session_options->mode = query.mode(); CopyToVector(query.RequiredFeatures(), session_options->required_features); CopyToVector(query.OptionalFeatures(), session_options->optional_features); @@ -504,8 +661,8 @@ device::mojom::blink::XRSessionOptionsPtr XR::XRSessionOptionsFromQuery( return session_options; } -XR::XR(LocalFrame& frame, int64_t ukm_source_id) - : ContextLifecycleObserver(frame.GetDocument()), +XRSystem::XRSystem(LocalFrame& frame, int64_t ukm_source_id) + : ExecutionContextLifecycleObserver(frame.GetDocument()), FocusChangedObserver(frame.GetPage()), ukm_source_id_(ukm_source_id), navigation_start_( @@ -518,11 +675,12 @@ XR::XR(LocalFrame& frame, int64_t ukm_source_id) frame.GetBrowserInterfaceBroker().GetInterface( service_.BindNewPipeAndPassReceiver( frame.GetTaskRunner(TaskType::kMiscPlatformAPI))); - service_.set_disconnect_handler(WTF::Bind( - &XR::Dispose, WrapWeakPersistent(this), DisposeType::kDisconnected)); + service_.set_disconnect_handler(WTF::Bind(&XRSystem::Dispose, + WrapWeakPersistent(this), + DisposeType::kDisconnected)); } -void XR::FocusedFrameChanged() { +void XRSystem::FocusedFrameChanged() { // Tell all sessions that focus changed. for (const auto& session : sessions_) { session->OnFocusChanged(); @@ -532,19 +690,19 @@ void XR::FocusedFrameChanged() { frame_provider_->OnFocusChanged(); } -bool XR::IsFrameFocused() { +bool XRSystem::IsFrameFocused() { return FocusChangedObserver::IsFrameFocused(GetFrame()); } -ExecutionContext* XR::GetExecutionContext() const { - return ContextLifecycleObserver::GetExecutionContext(); +ExecutionContext* XRSystem::GetExecutionContext() const { + return ExecutionContextLifecycleObserver::GetExecutionContext(); } -const AtomicString& XR::InterfaceName() const { +const AtomicString& XRSystem::InterfaceName() const { return event_target_names::kXR; } -XRFrameProvider* XR::frameProvider() { +XRFrameProvider* XRSystem::frameProvider() { if (!frame_provider_) { frame_provider_ = MakeGarbageCollected<XRFrameProvider>(this); } @@ -554,23 +712,17 @@ XRFrameProvider* XR::frameProvider() { const mojo::AssociatedRemote< device::mojom::blink::XREnvironmentIntegrationProvider>& -XR::xrEnvironmentProviderRemote() { +XRSystem::xrEnvironmentProviderRemote() { return environment_provider_; } -void XR::AddEnvironmentProviderErrorHandler( +void XRSystem::AddEnvironmentProviderErrorHandler( EnvironmentProviderErrorCallback callback) { environment_provider_error_callbacks_.push_back(std::move(callback)); } -void XR::ExitPresent(base::OnceClosure on_exited) { +void XRSystem::ExitPresent(base::OnceClosure on_exited) { DVLOG(1) << __func__; - if (service_) { - service_->ExitPresent(std::move(on_exited)); - } else { - // The service was already shut down, run the callback immediately. - std::move(on_exited).Run(); - } // If the document was potentially being shown in a DOM overlay via // fullscreened elements, make sure to clear any fullscreen states on exiting @@ -578,40 +730,51 @@ void XR::ExitPresent(base::OnceClosure on_exited) { // - browser side ends session and exits fullscreen (i.e. back button) // - renderer processes WebViewImpl::ExitFullscreen via ChromeClient // - JS application sets a new element to fullscreen, this is allowed - // because doc->IsImmersiveArOverlay() is still true at this point + // because doc->IsXrOverlay() is still true at this point // - renderer processes XR session shutdown (this method) // - browser re-enters fullscreen unexpectedly LocalFrame* frame = GetFrame(); - if (!frame) - return; + if (frame) { + Document* doc = frame->GetDocument(); + DCHECK(doc); + DVLOG(3) << __func__ << ": doc->IsXrOverlay()=" << doc->IsXrOverlay(); + if (doc->IsXrOverlay()) { + Element* fullscreen_element = Fullscreen::FullscreenElementFrom(*doc); + DVLOG(3) << __func__ << ": fullscreen_element=" << fullscreen_element; + doc->SetIsXrOverlay(false, fullscreen_element); + + // Restore the FrameView background color that was changed in + // OnRequestSessionReturned. The layout view can be null on navigation. + auto* layout_view = doc->GetLayoutView(); + if (layout_view) { + auto* frame_view = layout_view->GetFrameView(); + // SetBaseBackgroundColor updates composited layer mappings. + // That DCHECKs IsAllowedToQueryCompositingState which requires + // DocumentLifecycle >= kInCompositingUpdate. + frame_view->UpdateLifecycleToCompositingInputsClean( + DocumentUpdateReason::kBaseColor); + frame_view->SetBaseBackgroundColor(original_base_background_color_); + } - Document* doc = frame->GetDocument(); - DCHECK(doc); - if (doc->IsImmersiveArOverlay()) { - doc->SetIsImmersiveArOverlay(false); - Element* fullscreen_element = Fullscreen::FullscreenElementFrom(*doc); - if (fullscreen_element) { - // "ua_originated" means that the browser process already exited - // fullscreen. Set it to false because we need the browser process - // to get notified that it needs to exit fullscreen. Use - // FullyExitFullscreen to ensure that we return to non-fullscreen mode. - // ExitFullscreen only unfullscreens a single element, potentially - // leaving others in fullscreen mode. - constexpr bool kUaOriginated = false; - Fullscreen::FullyExitFullscreen(*doc, kUaOriginated); + if (fullscreen_element) { + fullscreen_exit_observer_ = + MakeGarbageCollected<OverlayFullscreenExitObserver>(this); + fullscreen_exit_observer_->ExitFullscreen(fullscreen_element, + std::move(on_exited)); + return; + } } - // Restore the FrameView background color that was changed in - // OnRequestSessionReturned. - auto* frame_view = doc->GetLayoutView()->GetFrameView(); - // SetBaseBackgroundColor updates composited layer mappings. - // That DCHECKs IsAllowedToQueryCompositingState which requires - // DocumentLifecycle >= kInCompositingUpdate. - frame_view->UpdateLifecycleToCompositingInputsClean(); - frame_view->SetBaseBackgroundColor(original_base_background_color_); + } + + if (service_) { + service_->ExitPresent(std::move(on_exited)); + } else { + // The service was already shut down, run the callback immediately. + std::move(on_exited).Run(); } } -void XR::SetFramesThrottled(const XRSession* session, bool throttled) { +void XRSystem::SetFramesThrottled(const XRSession* session, bool throttled) { // The service only cares if the immersive session is throttling frames. if (session->immersive()) { // If we have an immersive session, we should have a service. @@ -620,22 +783,23 @@ void XR::SetFramesThrottled(const XRSession* session, bool throttled) { } } -ScriptPromise XR::supportsSession(ScriptState* script_state, - const String& mode, - ExceptionState& exception_state) { +ScriptPromise XRSystem::supportsSession(ScriptState* script_state, + const String& mode, + ExceptionState& exception_state) { return InternalIsSessionSupported(script_state, mode, exception_state, true); } -ScriptPromise XR::isSessionSupported(ScriptState* script_state, - const String& mode, - ExceptionState& exception_state) { +ScriptPromise XRSystem::isSessionSupported(ScriptState* script_state, + const String& mode, + ExceptionState& exception_state) { return InternalIsSessionSupported(script_state, mode, exception_state, false); } -ScriptPromise XR::InternalIsSessionSupported(ScriptState* script_state, - const String& mode, - ExceptionState& exception_state, - bool throw_on_unsupported) { +ScriptPromise XRSystem::InternalIsSessionSupported( + ScriptState* script_state, + const String& mode, + ExceptionState& exception_state, + bool throw_on_unsupported) { LocalFrame* frame = GetFrame(); Document* doc = frame ? frame->GetDocument() : nullptr; if (!doc) { @@ -648,24 +812,27 @@ ScriptPromise XR::InternalIsSessionSupported(ScriptState* script_state, auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state); ScriptPromise promise = resolver->Promise(); - XRSession::SessionMode session_mode = stringToSessionMode(mode); + device::mojom::blink::XRSessionMode session_mode = stringToSessionMode(mode); PendingSupportsSessionQuery* query = MakeGarbageCollected<PendingSupportsSessionQuery>(resolver, session_mode, throw_on_unsupported); - if (session_mode == XRSession::kModeImmersiveAR && + if (session_mode == device::mojom::blink::XRSessionMode::kImmersiveAr && !RuntimeEnabledFeatures::WebXRARModuleEnabled(doc)) { + DVLOG(2) << __func__ + << ": Immersive AR session is only supported if WebXRARModule " + "feature is enabled"; query->Resolve(false); return promise; } - if (session_mode == XRSession::kModeInline) { + if (session_mode == device::mojom::blink::XRSessionMode::kInline) { // inline sessions are always supported. query->Resolve(true); return promise; } - if (!doc->IsFeatureEnabled(mojom::FeaturePolicyFeature::kWebXr, + if (!doc->IsFeatureEnabled(mojom::blink::FeaturePolicyFeature::kWebXr, ReportOptions::kReportOnFailure)) { // Only allow the call to be made if the appropriate feature policy is in // place. @@ -681,21 +848,22 @@ ScriptPromise XR::InternalIsSessionSupported(ScriptState* script_state, } device::mojom::blink::XRSessionOptionsPtr session_options = - convertModeToMojo(query->mode()); + device::mojom::blink::XRSessionOptions::New(); + session_options->mode = query->mode(); outstanding_support_queries_.insert(query); service_->SupportsSession( std::move(session_options), - WTF::Bind(&XR::OnSupportsSessionReturned, WrapPersistent(this), + WTF::Bind(&XRSystem::OnSupportsSessionReturned, WrapPersistent(this), WrapPersistent(query))); return promise; } -void XR::RequestImmersiveSession(LocalFrame* frame, - Document* doc, - PendingRequestSessionQuery* query, - ExceptionState* exception_state) { +void XRSystem::RequestImmersiveSession(LocalFrame* frame, + Document* doc, + PendingRequestSessionQuery* query, + ExceptionState* exception_state) { DVLOG(2) << __func__; // Log an immersive session request if we haven't already if (!did_log_request_immersive_session_) { @@ -732,6 +900,7 @@ void XR::RequestImmersiveSession(LocalFrame* frame, // Reject session if any of the required features were invalid. if (query->InvalidRequiredFeatures()) { + DVLOG(2) << __func__ << ": rejecting session - invalid required features"; query->RejectWithDOMException(DOMExceptionCode::kNotSupportedError, kSessionNotSupported, exception_state); return; @@ -743,15 +912,23 @@ void XR::RequestImmersiveSession(LocalFrame* frame, // Submit the request to VrServiceImpl in the Browser process outstanding_request_queries_.insert(query); auto session_options = XRSessionOptionsFromQuery(*query); - service_->RequestSession( - std::move(session_options), - WTF::Bind(&XR::OnRequestSessionReturned, WrapWeakPersistent(this), - WrapPersistent(query))); + + // In DOM overlay mode, there's an additional step before an immersive-ar + // session can start, we need to enter fullscreen mode by setting the + // appropriate element as fullscreen from the Renderer, then waiting for the + // browser side to send an event indicating success or failure. + auto callback = + query->DOMOverlayElement() + ? WTF::Bind(&XRSystem::OnRequestSessionSetupForDomOverlay, + WrapWeakPersistent(this), WrapPersistent(query)) + : WTF::Bind(&XRSystem::OnRequestSessionReturned, + WrapWeakPersistent(this), WrapPersistent(query)); + service_->RequestSession(std::move(session_options), std::move(callback)); } -void XR::RequestInlineSession(LocalFrame* frame, - PendingRequestSessionQuery* query, - ExceptionState* exception_state) { +void XRSystem::RequestInlineSession(LocalFrame* frame, + PendingRequestSessionQuery* query, + ExceptionState* exception_state) { DVLOG(2) << __func__; // Make sure the inline session request was allowed auto* inline_session_request_error = @@ -793,14 +970,15 @@ void XR::RequestInlineSession(LocalFrame* frame, auto session_options = XRSessionOptionsFromQuery(*query); service_->RequestSession( std::move(session_options), - WTF::Bind(&XR::OnRequestSessionReturned, WrapWeakPersistent(this), + WTF::Bind(&XRSystem::OnRequestSessionReturned, WrapWeakPersistent(this), WrapPersistent(query))); } -XR::RequestedXRSessionFeatureSet XR::ParseRequestedFeatures( +XRSystem::RequestedXRSessionFeatureSet XRSystem::ParseRequestedFeatures( Document* doc, const HeapVector<ScriptValue>& features, - const XRSession::SessionMode& session_mode, + const device::mojom::blink::XRSessionMode& session_mode, + XRSessionInit* session_init, mojom::ConsoleMessageLevel error_level) { RequestedXRSessionFeatureSet result; @@ -812,29 +990,35 @@ XR::RequestedXRSessionFeatureSet XR::ParseRequestedFeatures( auto feature_enum = StringToXRSessionFeature(doc, feature_string); if (!feature_enum) { - GetExecutionContext()->AddConsoleMessage(ConsoleMessage::Create( - mojom::ConsoleMessageSource::kJavaScript, error_level, - "Unrecognized feature requested: " + feature_string)); + GetExecutionContext()->AddConsoleMessage( + MakeGarbageCollected<ConsoleMessage>( + mojom::ConsoleMessageSource::kJavaScript, error_level, + "Unrecognized feature requested: " + feature_string)); result.invalid_features = true; - } else if (!IsFeatureValidForMode(feature_enum.value(), session_mode)) { - GetExecutionContext()->AddConsoleMessage(ConsoleMessage::Create( - mojom::ConsoleMessageSource::kJavaScript, error_level, - "Feature '" + feature_string + "' is not supported for mode: " + - SessionModeToString(session_mode))); + } else if (!IsFeatureValidForMode(feature_enum.value(), session_mode, + session_init, GetExecutionContext(), + error_level)) { + GetExecutionContext()->AddConsoleMessage( + MakeGarbageCollected<ConsoleMessage>( + mojom::ConsoleMessageSource::kJavaScript, error_level, + "Feature '" + feature_string + "' is not supported for mode: " + + SessionModeToString(session_mode))); result.invalid_features = true; } else if (!HasRequiredFeaturePolicy(doc, feature_enum.value())) { - GetExecutionContext()->AddConsoleMessage(ConsoleMessage::Create( - mojom::ConsoleMessageSource::kJavaScript, error_level, - "Feature '" + feature_string + - "' is not permitted by feature policy")); + GetExecutionContext()->AddConsoleMessage( + MakeGarbageCollected<ConsoleMessage>( + mojom::ConsoleMessageSource::kJavaScript, error_level, + "Feature '" + feature_string + + "' is not permitted by feature policy")); result.invalid_features = true; } else { result.valid_features.insert(feature_enum.value()); } } else { GetExecutionContext()->AddConsoleMessage( - ConsoleMessage::Create(mojom::ConsoleMessageSource::kJavaScript, - error_level, "Unrecognized feature value")); + MakeGarbageCollected<ConsoleMessage>( + mojom::ConsoleMessageSource::kJavaScript, error_level, + "Unrecognized feature value")); result.invalid_features = true; } } @@ -842,10 +1026,10 @@ XR::RequestedXRSessionFeatureSet XR::ParseRequestedFeatures( return result; } -ScriptPromise XR::requestSession(ScriptState* script_state, - const String& mode, - XRSessionInit* session_init, - ExceptionState& exception_state) { +ScriptPromise XRSystem::requestSession(ScriptState* script_state, + const String& mode, + XRSessionInit* session_init, + ExceptionState& exception_state) { DVLOG(2) << __func__; // TODO(https://crbug.com/968622): Make sure we don't forget to call // metrics-related methods when the promise gets resolved/rejected. @@ -861,10 +1045,10 @@ ScriptPromise XR::requestSession(ScriptState* script_state, return ScriptPromise(); // Will be rejected by generated bindings } - XRSession::SessionMode session_mode = stringToSessionMode(mode); + device::mojom::blink::XRSessionMode session_mode = stringToSessionMode(mode); // If the request is for immersive-ar, ensure that feature is enabled. - if (session_mode == XRSession::kModeImmersiveAR && + if (session_mode == device::mojom::blink::XRSessionMode::kImmersiveAr && !RuntimeEnabledFeatures::WebXRARModuleEnabled(doc)) { exception_state.ThrowTypeError( String::Format(kImmersiveArModeNotValid, "requestSession")); @@ -883,7 +1067,7 @@ ScriptPromise XR::requestSession(ScriptState* script_state, RequestedXRSessionFeatureSet required_features; if (session_init && session_init->hasRequiredFeatures()) { required_features = ParseRequestedFeatures( - doc, session_init->requiredFeatures(), session_mode, + doc, session_init->requiredFeatures(), session_mode, session_init, mojom::ConsoleMessageLevel::kError); } @@ -891,7 +1075,7 @@ ScriptPromise XR::requestSession(ScriptState* script_state, RequestedXRSessionFeatureSet optional_features; if (session_init && session_init->hasOptionalFeatures()) { optional_features = ParseRequestedFeatures( - doc, session_init->optionalFeatures(), session_mode, + doc, session_init->optionalFeatures(), session_mode, session_init, mojom::ConsoleMessageLevel::kWarning); } @@ -899,13 +1083,13 @@ ScriptPromise XR::requestSession(ScriptState* script_state, // Add those default features as required features now. base::span<const device::mojom::XRSessionFeature> default_features; switch (session_mode) { - case XRSession::kModeImmersiveVR: + case device::mojom::blink::XRSessionMode::kImmersiveVr: default_features = kDefaultImmersiveVrFeatures; break; - case XRSession::kModeImmersiveAR: + case device::mojom::blink::XRSessionMode::kImmersiveAr: default_features = kDefaultImmersiveArFeatures; break; - case XRSession::kModeInline: + case device::mojom::blink::XRSessionMode::kInline: default_features = kDefaultInlineFeatures; break; } @@ -926,12 +1110,17 @@ ScriptPromise XR::requestSession(ScriptState* script_state, GetSourceId(), resolver, session_mode, std::move(required_features), std::move(optional_features)); + if (session_init && session_init->hasDomOverlay()) { + DCHECK(session_init->domOverlay()->hasRoot()) << "required in IDL"; + query->SetDOMOverlayElement(session_init->domOverlay()->root()); + } + switch (session_mode) { - case XRSession::kModeImmersiveVR: - case XRSession::kModeImmersiveAR: + case device::mojom::blink::XRSessionMode::kImmersiveVr: + case device::mojom::blink::XRSessionMode::kImmersiveAr: RequestImmersiveSession(frame, doc, query, &exception_state); break; - case XRSession::kModeInline: + case device::mojom::blink::XRSessionMode::kInline: RequestInlineSession(frame, query, &exception_state); break; } @@ -942,16 +1131,17 @@ ScriptPromise XR::requestSession(ScriptState* script_state, // This will be called when the XR hardware or capabilities have potentially // changed. For example, if a new physical device was connected to the system, // it might be able to support immersive sessions, where it couldn't before. -void XR::OnDeviceChanged() { +void XRSystem::OnDeviceChanged() { LocalFrame* frame = GetFrame(); Document* doc = frame ? frame->GetDocument() : nullptr; - if (doc && doc->IsFeatureEnabled(mojom::FeaturePolicyFeature::kWebXr)) { + if (doc && + doc->IsFeatureEnabled(mojom::blink::FeaturePolicyFeature::kWebXr)) { DispatchEvent(*blink::Event::Create(event_type_names::kDevicechange)); } } -void XR::OnSupportsSessionReturned(PendingSupportsSessionQuery* query, - bool supports_session) { +void XRSystem::OnSupportsSessionReturned(PendingSupportsSessionQuery* query, + bool supports_session) { // The session query has returned and we're about to resolve or reject the // promise, so remove it from our outstanding list. DCHECK(outstanding_support_queries_.Contains(query)); @@ -959,18 +1149,39 @@ void XR::OnSupportsSessionReturned(PendingSupportsSessionQuery* query, query->Resolve(supports_session); } -void XR::OnRequestSessionReturned( +void XRSystem::OnRequestSessionSetupForDomOverlay( + PendingRequestSessionQuery* query, + device::mojom::blink::RequestSessionResultPtr result) { + DCHECK(query->DOMOverlayElement()); + if (result->is_success()) { + // Success. Now request fullscreen mode and continue with + // OnRequestSessionReturned once that completes. + fullscreen_event_manager_ = + MakeGarbageCollected<OverlayFullscreenEventManager>(this, query, + std::move(result)); + fullscreen_event_manager_->RequestFullscreen(); + } else { + // Session request failed, continue processing that normally. + OnRequestSessionReturned(query, std::move(result)); + } +} + +void XRSystem::OnRequestSessionReturned( PendingRequestSessionQuery* query, device::mojom::blink::RequestSessionResultPtr result) { // The session query has returned and we're about to resolve or reject the // promise, so remove it from our outstanding list. DCHECK(outstanding_request_queries_.Contains(query)); outstanding_request_queries_.erase(query); - if (query->mode() == XRSession::kModeImmersiveVR || - query->mode() == XRSession::kModeImmersiveAR) { + if (query->mode() == device::mojom::blink::XRSessionMode::kImmersiveVr || + query->mode() == device::mojom::blink::XRSessionMode::kImmersiveAr) { DCHECK(has_outstanding_immersive_request_); has_outstanding_immersive_request_ = false; } + // Clean up the fullscreen event manager which may have been added for + // DOM overlay setup. We're done with it, and it contains a reference + // to the query and the DOM overlay element. + fullscreen_event_manager_ = nullptr; // TODO(https://crbug.com/872316) Improve the error messaging to indicate why // a request failed. @@ -995,7 +1206,8 @@ void XR::OnRequestSessionReturned( auto session_ptr = std::move(result->get_success()->session); auto metrics_recorder = std::move(result->get_success()->metrics_recorder); - bool environment_integration = query->mode() == XRSession::kModeImmersiveAR; + bool environment_integration = + query->mode() == device::mojom::blink::XRSessionMode::kImmersiveAr; // immersive sessions must supply display info. DCHECK(session_ptr->display_info); @@ -1019,8 +1231,8 @@ void XR::OnRequestSessionReturned( frameProvider()->OnSessionStarted(session, std::move(session_ptr)); - if (query->mode() == XRSession::kModeImmersiveVR || - query->mode() == XRSession::kModeImmersiveAR) { + if (query->mode() == device::mojom::blink::XRSessionMode::kImmersiveVr || + query->mode() == device::mojom::blink::XRSessionMode::kImmersiveAr) { if (environment_integration) { // See Task Sources spreadsheet for more information: // https://docs.google.com/spreadsheets/d/1b-dus1Ug3A8y0lX0blkmOjJILisUASdj8x9YN_XMwYc/view @@ -1030,20 +1242,22 @@ void XR::OnRequestSessionReturned( environment_provider_.BindNewEndpointAndPassReceiver( GetExecutionContext()->GetTaskRunner( TaskType::kMiscPlatformAPI))); - environment_provider_.set_disconnect_handler(WTF::Bind( - &XR::OnEnvironmentProviderDisconnect, WrapWeakPersistent(this))); + environment_provider_.set_disconnect_handler( + WTF::Bind(&XRSystem::OnEnvironmentProviderDisconnect, + WrapWeakPersistent(this))); session->OnEnvironmentProviderCreated(); LocalFrame* frame = GetFrame(); DCHECK(frame); - if (enabled_features.Contains( - device::mojom::XRSessionFeature::DOM_OVERLAY_FOR_HANDHELD_AR)) { - // The session is using DOM overlay mode. + if (query->DOMOverlayElement()) { + // The session is using DOM overlay mode. At this point the overlay + // element is already in fullscreen mode, and the session can + // proceed. Document* doc = frame->GetDocument(); DCHECK(doc); - doc->SetIsImmersiveArOverlay(true); + session->SetDOMOverlayElement(query->DOMOverlayElement()); // Save the current base background color (restored in ExitPresent), // and set a transparent background for the FrameView. @@ -1051,32 +1265,14 @@ void XR::OnRequestSessionReturned( // SetBaseBackgroundColor updates composited layer mappings. // That DCHECKs IsAllowedToQueryCompositingState which requires // DocumentLifecycle >= kInCompositingUpdate. - frame_view->UpdateLifecycleToCompositingInputsClean(); + frame_view->UpdateLifecycleToCompositingInputsClean( + DocumentUpdateReason::kBaseColor); original_base_background_color_ = frame_view->BaseBackgroundColor(); frame_view->SetBaseBackgroundColor(Color::kTransparent); - - // In DOM overlay mode, entering fullscreen mode needs to be triggered - // from the Renderer by actually fullscreening an element. If there - // is no current fullscreen element, fullscreen the <body> element - // for now. The JS application can use enterFullscreen to change this. - // - // A TabObserver on the browser side exits the session if there's - // no longer a fullscreen element, for example if the JS app manually - // unfullscreens the "body" element. That ensures we don't end up in a - // hybrid non-fullscreen AR state. - Element* fullscreen_element = Fullscreen::FullscreenElementFrom(*doc); - if (!fullscreen_element) { - Element* body = doc->body(); - DCHECK(body); - // FIXME: this is the "prefixed" version that doesn't generate a - // fullscreenchange event and auto-hides navigation bars. Should the - // event be generated? - Fullscreen::RequestFullscreen(*body); - } } } - if (query->mode() == XRSession::kModeImmersiveVR && + if (query->mode() == device::mojom::blink::XRSessionMode::kImmersiveVr && session->UsesInputEventing()) { frameProvider()->GetImmersiveDataProvider()->SetInputSourceButtonListener( session->GetInputClickListener()); @@ -1089,7 +1285,7 @@ void XR::OnRequestSessionReturned( query->Resolve(session, std::move(metrics_recorder)); } -void XR::ReportImmersiveSupported(bool supported) { +void XRSystem::ReportImmersiveSupported(bool supported) { Document* doc = GetFrame() ? GetFrame()->GetDocument() : nullptr; if (doc && !did_log_supports_immersive_ && supported) { ukm::builders::XR_WebXR ukm_builder(ukm_source_id_); @@ -1099,8 +1295,9 @@ void XR::ReportImmersiveSupported(bool supported) { } } -void XR::AddedEventListener(const AtomicString& event_type, - RegisteredEventListener& registered_listener) { +void XRSystem::AddedEventListener( + const AtomicString& event_type, + RegisteredEventListener& registered_listener) { EventTargetWithInlineData::AddedEventListener(event_type, registered_listener); @@ -1118,13 +1315,13 @@ void XR::AddedEventListener(const AtomicString& event_type, } } -void XR::ContextDestroyed(ExecutionContext*) { +void XRSystem::ContextDestroyed() { Dispose(DisposeType::kContextDestroyed); } // A session is always created and returned. -XRSession* XR::CreateSession( - XRSession::SessionMode mode, +XRSession* XRSystem::CreateSession( + device::mojom::blink::XRSessionMode mode, XRSession::EnvironmentBlendMode blend_mode, mojo::PendingReceiver<device::mojom::blink::XRSessionClient> client_receiver, @@ -1141,10 +1338,10 @@ XRSession* XR::CreateSession( return session; } -XRSession* XR::CreateSensorlessInlineSession() { +XRSession* XRSystem::CreateSensorlessInlineSession() { // TODO(https://crbug.com/944936): The blend mode could be "additive". XRSession::EnvironmentBlendMode blend_mode = XRSession::kBlendModeOpaque; - return CreateSession(XRSession::kModeInline, blend_mode, + return CreateSession(device::mojom::blink::XRSessionMode::kInline, blend_mode, mojo::NullReceiver() /* client receiver */, nullptr /* display_info */, false /* uses_input_eventing */, @@ -1152,7 +1349,7 @@ XRSession* XR::CreateSensorlessInlineSession() { true /* sensorless_session */); } -void XR::Dispose(DisposeType dispose_type) { +void XRSystem::Dispose(DisposeType dispose_type) { switch (dispose_type) { case DisposeType::kContextDestroyed: is_context_destroyed_ = true; @@ -1190,7 +1387,7 @@ void XR::Dispose(DisposeType dispose_type) { DCHECK(outstanding_support_queries_.IsEmpty()); } -void XR::OnEnvironmentProviderDisconnect() { +void XRSystem::OnEnvironmentProviderDisconnect() { for (auto& callback : environment_provider_error_callbacks_) { std::move(callback).Run(); } @@ -1199,12 +1396,14 @@ void XR::OnEnvironmentProviderDisconnect() { environment_provider_.reset(); } -void XR::Trace(blink::Visitor* visitor) { +void XRSystem::Trace(Visitor* visitor) { visitor->Trace(frame_provider_); visitor->Trace(sessions_); visitor->Trace(outstanding_support_queries_); visitor->Trace(outstanding_request_queries_); - ContextLifecycleObserver::Trace(visitor); + visitor->Trace(fullscreen_event_manager_); + visitor->Trace(fullscreen_exit_observer_); + ExecutionContextLifecycleObserver::Trace(visitor); EventTargetWithInlineData::Trace(visitor); } diff --git a/chromium/third_party/blink/renderer/modules/xr/xr.h b/chromium/third_party/blink/renderer/modules/xr/xr_system.h index bf498cf753a..4a1258d2ec2 100644 --- a/chromium/third_party/blink/renderer/modules/xr/xr.h +++ b/chromium/third_party/blink/renderer/modules/xr/xr_system.h @@ -2,8 +2,8 @@ // 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_ +#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_SYSTEM_H_ +#define THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_SYSTEM_H_ #include "device/vr/public/mojom/vr_service.mojom-blink.h" #include "mojo/public/cpp/bindings/associated_remote.h" @@ -11,12 +11,14 @@ #include "mojo/public/cpp/bindings/receiver.h" #include "mojo/public/cpp/bindings/remote.h" #include "third_party/blink/renderer/bindings/core/v8/script_promise.h" +#include "third_party/blink/renderer/bindings/modules/v8/v8_xr_dom_overlay_init.h" +#include "third_party/blink/renderer/bindings/modules/v8/v8_xr_session_init.h" #include "third_party/blink/renderer/core/dom/dom_exception.h" #include "third_party/blink/renderer/core/dom/events/event_target.h" -#include "third_party/blink/renderer/core/execution_context/context_lifecycle_observer.h" +#include "third_party/blink/renderer/core/dom/events/native_event_listener.h" +#include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_observer.h" #include "third_party/blink/renderer/core/page/focus_changed_observer.h" #include "third_party/blink/renderer/modules/xr/xr_session.h" -#include "third_party/blink/renderer/modules/xr/xr_session_init.h" #include "third_party/blink/renderer/platform/graphics/color.h" #include "third_party/blink/renderer/platform/heap/handle.h" #include "third_party/blink/renderer/platform/scheduler/public/frame_or_worker_scheduler.h" @@ -29,21 +31,43 @@ class ScriptPromiseResolver; class XRFrameProvider; class XRSessionInit; -class XR final : public EventTargetWithInlineData, - public ContextLifecycleObserver, - public device::mojom::blink::VRServiceClient, - public FocusChangedObserver { +// Implementation of the XRSystem interface according to +// https://immersive-web.github.io/webxr/#xrsystem-interface . This is created +// lazily via the NavigatorXR class on first access to the navigator.xr attrib, +// and disposed when the execution context is destroyed or on mojo communication +// errors with the browser/device process. +// +// When the XRSystem is used for promises, it uses query objects to store state +// including the associated ScriptPromiseResolver. These query objects are owned +// by the XRSystem and remain alive until the promise is resolved or rejected. +// (See comments below for PendingSupportsSessionQuery and +// PendingRequestSessionQuery.) These query objects are destroyed and any +// outstanding promises rejected when the XRSystem is disposed. +// +// The XRSystem owns mojo connections with the Browser process through +// VRService, used for capability queries and session lifetime +// management. The XRSystem is also the receiver for the VRServiceClient. +// +// The XRSystem owns mojo connections with the Device process (either a +// separate utility process, or implemented as part of the Browser process, +// depending on the runtime and options) through XRFrameProvider and +// XREnvironmentIntegrationProvider. These are used to transport per-frame data +// such as image data and input poses. These are lazily created when first +// needed for a sensor-backed session (all except sensorless inline sessions), +// and destroyed when the XRSystem is disposed. +// +// The XRSystem keeps weak references to XRSession objects after they were +// returned through a successful requestSession promise, but does not own them. +class XRSystem final : public EventTargetWithInlineData, + public ExecutionContextLifecycleObserver, + public device::mojom::blink::VRServiceClient, + public FocusChangedObserver { DEFINE_WRAPPERTYPEINFO(); - USING_GARBAGE_COLLECTED_MIXIN(XR); + USING_GARBAGE_COLLECTED_MIXIN(XRSystem); public: // TODO(crbug.com/976796): Fix lint errors. - static XR* Create(LocalFrame& frame, int64_t source_id) { - return MakeGarbageCollected<XR>(frame, source_id); - } - - // TODO(crbug.com/976796): Fix lint errors. - XR(LocalFrame& frame, int64_t ukm_source_id); + XRSystem(LocalFrame& frame, int64_t ukm_source_id); DEFINE_ATTRIBUTE_EVENT_LISTENER(devicechange, kDevicechange) @@ -71,9 +95,9 @@ class XR final : public EventTargetWithInlineData, ExecutionContext* GetExecutionContext() const override; const AtomicString& InterfaceName() const override; - // ContextLifecycleObserver overrides. - void ContextDestroyed(ExecutionContext*) override; - void Trace(blink::Visitor*) override; + // ExecutionContextLifecycleObserver overrides. + void ContextDestroyed() override; + void Trace(Visitor*) override; // FocusChangedObserver overrides. void FocusedFrameChanged() override; @@ -120,15 +144,16 @@ class XR final : public EventTargetWithInlineData, bool invalid_features = false; }; - // Encapsulates blink-side `XR::requestSession()` call. It is a wrapper around - // ScriptPromiseResolver that allows us to add additional logic as certain - // things related to promise's life cycle happen. + // Encapsulates blink-side `XRSystem::requestSession()` call. It is a wrapper + // around ScriptPromiseResolver that allows us to add additional logic as + // certain things related to promise's life cycle happen. Instances are owned + // by the XRSystem, see outstanding_request_queries_ below. class PendingRequestSessionQuery final : public GarbageCollected<PendingRequestSessionQuery> { public: PendingRequestSessionQuery(int64_t ukm_source_id, ScriptPromiseResolver* resolver, - XRSession::SessionMode mode, + device::mojom::blink::XRSessionMode mode, RequestedXRSessionFeatureSet required_features, RequestedXRSessionFeatureSet optional_features); virtual ~PendingRequestSessionQuery() = default; @@ -162,7 +187,7 @@ class XR final : public EventTargetWithInlineData, void RejectWithTypeError(const String& message, ExceptionState* exception_state); - XRSession::SessionMode mode() const; + device::mojom::blink::XRSessionMode mode() const; const XRSessionFeatureSet& RequiredFeatures() const; const XRSessionFeatureSet& OptionalFeatures() const; bool InvalidRequiredFeatures() const; @@ -175,7 +200,12 @@ class XR final : public EventTargetWithInlineData, // Returns underlying resolver's script state. ScriptState* GetScriptState() const; - virtual void Trace(blink::Visitor*); + void SetDOMOverlayElement(Element* element) { + dom_overlay_element_ = element; + } + Element* DOMOverlayElement() { return dom_overlay_element_; } + + virtual void Trace(Visitor*); private: void ParseSensorRequirement(); @@ -189,27 +219,29 @@ class XR final : public EventTargetWithInlineData, metrics_recorder = mojo::NullRemote()); Member<ScriptPromiseResolver> resolver_; - const XRSession::SessionMode mode_; + const device::mojom::blink::XRSessionMode mode_; RequestedXRSessionFeatureSet required_features_; RequestedXRSessionFeatureSet optional_features_; SensorRequirement sensor_requirement_ = SensorRequirement::kNone; const int64_t ukm_source_id_; + Member<Element> dom_overlay_element_; DISALLOW_COPY_AND_ASSIGN(PendingRequestSessionQuery); }; static device::mojom::blink::XRSessionOptionsPtr XRSessionOptionsFromQuery( const PendingRequestSessionQuery& query); - // Encapsulates blink-side `XR::supportsSession()` call. It is a wrapper - // around ScriptPromiseResolver that allows us to add additional logic as - // certain things related to promise's life cycle happen. + // Encapsulates blink-side `XRSystem::isSessionSupported()` call. It is a + // wrapper around ScriptPromiseResolver that allows us to add additional logic + // as certain things related to promise's life cycle happen. Instances are + // owned by the XRSystem, see outstanding_support_queries_ below. class PendingSupportsSessionQuery final : public GarbageCollected<PendingSupportsSessionQuery> { public: PendingSupportsSessionQuery(ScriptPromiseResolver*, - XRSession::SessionMode, + device::mojom::blink::XRSessionMode, bool throw_on_unsupported); virtual ~PendingSupportsSessionQuery() = default; @@ -239,13 +271,13 @@ class XR final : public EventTargetWithInlineData, bool ThrowOnUnsupported() const { return throw_on_unsupported_; } - XRSession::SessionMode mode() const; + device::mojom::blink::XRSessionMode mode() const; - virtual void Trace(blink::Visitor*); + virtual void Trace(Visitor*); private: Member<ScriptPromiseResolver> resolver_; - const XRSession::SessionMode mode_; + const device::mojom::blink::XRSessionMode mode_; // Only set when calling the deprecated supportsSession method. const bool throw_on_unsupported_ = false; @@ -253,6 +285,53 @@ class XR final : public EventTargetWithInlineData, DISALLOW_COPY_AND_ASSIGN(PendingSupportsSessionQuery); }; + // Native event listener for fullscreen change / error events when starting an + // immersive-ar session that uses DOM Overlay mode. See + // OnRequestSessionReturned(). + class OverlayFullscreenEventManager : public NativeEventListener { + public: + OverlayFullscreenEventManager( + XRSystem* xr, + XRSystem::PendingRequestSessionQuery*, + device::mojom::blink::RequestSessionResultPtr); + ~OverlayFullscreenEventManager() override; + + // NativeEventListener + void Invoke(ExecutionContext*, Event*) override; + + void RequestFullscreen(); + void OnSessionStarting(); + + void Trace(Visitor*) override; + + private: + Member<XRSystem> xr_; + Member<PendingRequestSessionQuery> query_; + device::mojom::blink::RequestSessionResultPtr result_; + DISALLOW_COPY_AND_ASSIGN(OverlayFullscreenEventManager); + }; + + // Native event listener used when waiting for fullscreen mode to fully exit + // when ending an XR session. + class OverlayFullscreenExitObserver : public NativeEventListener { + public: + OverlayFullscreenExitObserver(XRSystem* xr); + ~OverlayFullscreenExitObserver() override; + + // NativeEventListener + void Invoke(ExecutionContext*, Event*) override; + + void ExitFullscreen(Element* element, base::OnceClosure on_exited); + + void Trace(Visitor*) override; + + private: + Member<XRSystem> xr_; + Member<Element> element_; + base::OnceClosure on_exited_; + DISALLOW_COPY_AND_ASSIGN(OverlayFullscreenExitObserver); + }; + ScriptPromise InternalIsSessionSupported(ScriptState*, const String&, ExceptionState& exception_state, @@ -265,7 +344,8 @@ class XR final : public EventTargetWithInlineData, RequestedXRSessionFeatureSet ParseRequestedFeatures( Document* doc, const HeapVector<ScriptValue>& features, - const XRSession::SessionMode& session_mode, + const device::mojom::blink::XRSessionMode& session_mode, + XRSessionInit* session_init, mojom::ConsoleMessageLevel error_level); void RequestImmersiveSession(LocalFrame* frame, @@ -277,11 +357,18 @@ class XR final : public EventTargetWithInlineData, PendingRequestSessionQuery* query, ExceptionState* exception_state); + void OnRequestSessionSetupForDomOverlay( + PendingRequestSessionQuery*, + device::mojom::blink::RequestSessionResultPtr result); void OnRequestSessionReturned( PendingRequestSessionQuery*, device::mojom::blink::RequestSessionResultPtr result); void OnSupportsSessionReturned(PendingSupportsSessionQuery*, bool supports_session); + void ResolveSessionRequest( + PendingRequestSessionQuery*, + device::mojom::blink::RequestSessionResultPtr result); + void RejectSessionRequest(PendingRequestSessionQuery*); void EnsureDevice(); void ReportImmersiveSupported(bool supported); @@ -290,7 +377,7 @@ class XR final : public EventTargetWithInlineData, RegisteredEventListener&) override; XRSession* CreateSession( - XRSession::SessionMode mode, + device::mojom::blink::XRSessionMode mode, XRSession::EnvironmentBlendMode blend_mode, mojo::PendingReceiver<device::mojom::blink::XRSessionClient> client_receiver, @@ -317,6 +404,8 @@ class XR final : public EventTargetWithInlineData, const int64_t ukm_source_id_; + // The XR object owns outstanding pending session queries, these live until + // the underlying promise is either resolved or rejected. HeapHashSet<Member<PendingSupportsSessionQuery>> outstanding_support_queries_; HeapHashSet<Member<PendingRequestSessionQuery>> outstanding_request_queries_; bool has_outstanding_immersive_request_ = false; @@ -338,6 +427,15 @@ class XR final : public EventTargetWithInlineData, FrameOrWorkerScheduler::SchedulingAffectingFeatureHandle feature_handle_for_scheduler_; + // In DOM overlay mode, use a fullscreen event listener to detect when + // transition to fullscreen mode completes or fails, and reject/resolve + // the pending request session promise accordingly. + Member<OverlayFullscreenEventManager> fullscreen_event_manager_; + // DOM overlay mode uses a separate temporary fullscreen event listener + // if it needs to wait for fullscreen mode to fully exit when ending + // the session. + Member<OverlayFullscreenExitObserver> fullscreen_exit_observer_; + // In DOM overlay mode, save and restore the FrameView background color. Color original_base_background_color_; @@ -346,4 +444,4 @@ class XR final : public EventTargetWithInlineData, } // namespace blink -#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_H_ +#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_SYSTEM_H_ diff --git a/chromium/third_party/blink/renderer/modules/xr/xr.idl b/chromium/third_party/blink/renderer/modules/xr/xr_system.idl index 93aba883d87..31a25a05df6 100644 --- a/chromium/third_party/blink/renderer/modules/xr/xr.idl +++ b/chromium/third_party/blink/renderer/modules/xr/xr_system.idl @@ -2,14 +2,17 @@ // 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/#xr-interface +// https://immersive-web.github.io/webxr/#xrsystem-interface [ SecureContext, Exposed=Window, RuntimeEnabled=WebXR -] interface XR : EventTarget { +] interface XRSystem : EventTarget { attribute EventHandler ondevicechange; [CallWith=ScriptState, DeprecateAs=XRSupportsSession, RaisesException] Promise<void> supportsSession(XRSessionMode mode); [CallWith=ScriptState, MeasureAs=XRIsSessionSupported, RaisesException] Promise<boolean> isSessionSupported(XRSessionMode mode); - [CallWith=ScriptState, MeasureAs=XRRequestSession, RaisesException] Promise<XRSession> requestSession(XRSessionMode mode, optional XRSessionInit options); + [CallWith=ScriptState, MeasureAs=XRRequestSession, RaisesException] Promise<XRSession> requestSession(XRSessionMode mode, optional XRSessionInit options = {}); }; + +// For backwards compatibility with previous interface name. +typedef XRSystem XR; diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_target_ray_space.cc b/chromium/third_party/blink/renderer/modules/xr/xr_target_ray_space.cc index 90eedcfd54b..72e84fae9a3 100644 --- a/chromium/third_party/blink/renderer/modules/xr/xr_target_ray_space.cc +++ b/chromium/third_party/blink/renderer/modules/xr/xr_target_ray_space.cc @@ -8,103 +8,53 @@ #include "third_party/blink/renderer/modules/xr/xr_input_source.h" #include "third_party/blink/renderer/modules/xr/xr_pose.h" +#include "third_party/blink/renderer/modules/xr/xr_session.h" namespace blink { XRTargetRaySpace::XRTargetRaySpace(XRSession* session, XRInputSource* source) : XRSpace(session), input_source_(source) {} -std::unique_ptr<TransformationMatrix> XRTargetRaySpace::OtherSpaceFromScreenTap( - XRSpace* other_space, - const TransformationMatrix& mojo_from_viewer) { - // If the pointer origin is the screen, the input space is viewer space, and - // we need the head's viewer pose and the pointer pose in continue. The - // pointer transform will represent the point the canvas was clicked as an - // offset from the view. - if (!input_source_->InputFromPointer()) { - return nullptr; - } - - // other_from_pointer = other_from_input * input_from_pointer, - // where input space is equivalent to viewer space for screen taps. - std::unique_ptr<TransformationMatrix> other_from_pointer = - other_space->SpaceFromViewer(mojo_from_viewer); - if (!other_from_pointer) { - return nullptr; - } - other_from_pointer->Multiply(*(input_source_->InputFromPointer())); - return other_from_pointer; -} - -std::unique_ptr<TransformationMatrix> -XRTargetRaySpace::OtherSpaceFromTrackedPointer( - XRSpace* other_space, - const TransformationMatrix& mojo_from_viewer) { - if (!input_source_->MojoFromInput()) { - return nullptr; - } - - // Calculate other_from_pointer = other_from_input * input_from_pointer - std::unique_ptr<TransformationMatrix> other_from_pointer = - other_space->SpaceFromInputForViewer(*(input_source_->MojoFromInput()), - mojo_from_viewer); - - if (!other_from_pointer) { - return nullptr; - } - if (input_source_->InputFromPointer()) { - other_from_pointer->Multiply(*(input_source_->InputFromPointer())); - } - return other_from_pointer; -} - -XRPose* XRTargetRaySpace::getPose( - XRSpace* other_space, - const TransformationMatrix* mojo_from_viewer) { - // If we don't have a valid base pose (most common when tracking is lost), - // we can't get a target ray pose regardless of the mode. - if (!mojo_from_viewer) { - DVLOG(2) << __func__ << " : mojo_from_viewer is null, returning nullptr"; - return nullptr; - } - - std::unique_ptr<TransformationMatrix> other_from_ray = nullptr; +std::unique_ptr<TransformationMatrix> XRTargetRaySpace::MojoFromNative() { + auto mojo_from_viewer = session()->MojoFromViewer(); switch (input_source_->TargetRayMode()) { case device::mojom::XRTargetRayMode::TAPPING: { - other_from_ray = OtherSpaceFromScreenTap(other_space, *mojo_from_viewer); - break; + // If the pointer origin is the screen, we need mojo_from_viewer, as the + // viewer space is the input space. + // So our result will be mojo_from_viewer * viewer_from_pointer + if (!(mojo_from_viewer && input_source_->InputFromPointer())) + return nullptr; + + return std::make_unique<TransformationMatrix>( + (*mojo_from_viewer * *(input_source_->InputFromPointer()))); } case device::mojom::XRTargetRayMode::GAZING: { - // If the pointer origin is the users head, this is a gaze cursor and the - // returned pointer is based on the device pose. Just return the head pose - // as the pointer pose. - other_from_ray = other_space->SpaceFromViewer(*mojo_from_viewer); - break; + // If the pointer origin is gaze, then the pointer offset is just + // mojo_from_viewer. + if (!mojo_from_viewer) + return nullptr; + + return std::make_unique<TransformationMatrix>(*(mojo_from_viewer)); } case device::mojom::XRTargetRayMode::POINTING: { - other_from_ray = - OtherSpaceFromTrackedPointer(other_space, *mojo_from_viewer); - break; + // mojo_from_pointer is just: MojoFromInput*InputFromPointer; + if (!(input_source_->MojoFromInput() && + input_source_->InputFromPointer())) + return nullptr; + + return std::make_unique<TransformationMatrix>( + (*(input_source_->MojoFromInput()) * + *(input_source_->InputFromPointer()))); } } +} - if (!other_from_ray) { - DVLOG(2) << __func__ << " : " - << "other_from_ray is null, input_source_->TargetRayMode() = " - << input_source_->TargetRayMode(); - return nullptr; - } +std::unique_ptr<TransformationMatrix> XRTargetRaySpace::NativeFromMojo() { + return TryInvert(MojoFromNative()); +} - // Account for any changes made to the reference space's origin offset so that - // things like teleportation works. - // - // otheroffset_from_ray = otheroffset_from_other * other_from_ray - // where otheroffset_from_other = inverse(other_from_otheroffset) - // TODO(https://crbug.com/1008466): move originOffset to separate class? - TransformationMatrix otheroffset_from_ray = - other_space->InverseOriginOffsetMatrix().Multiply(*other_from_ray); - return MakeGarbageCollected<XRPose>(otheroffset_from_ray, - input_source_->emulatedPosition()); +bool XRTargetRaySpace::EmulatedPosition() const { + return input_source_->emulatedPosition(); } base::Optional<XRNativeOriginInformation> XRTargetRaySpace::NativeOrigin() @@ -112,7 +62,7 @@ base::Optional<XRNativeOriginInformation> XRTargetRaySpace::NativeOrigin() return input_source_->nativeOrigin(); } -void XRTargetRaySpace::Trace(blink::Visitor* visitor) { +void XRTargetRaySpace::Trace(Visitor* visitor) { visitor->Trace(input_source_); XRSpace::Trace(visitor); } diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_target_ray_space.h b/chromium/third_party/blink/renderer/modules/xr/xr_target_ray_space.h index 8df09c58c8a..56d2d9302cb 100644 --- a/chromium/third_party/blink/renderer/modules/xr/xr_target_ray_space.h +++ b/chromium/third_party/blink/renderer/modules/xr/xr_target_ray_space.h @@ -14,21 +14,16 @@ namespace blink { class XRTargetRaySpace : public XRSpace { public: XRTargetRaySpace(XRSession* session, XRInputSource* input_space); - XRPose* getPose(XRSpace* other_space, - const TransformationMatrix* base_pose_matrix) override; + + std::unique_ptr<TransformationMatrix> MojoFromNative() override; + std::unique_ptr<TransformationMatrix> NativeFromMojo() override; + bool EmulatedPosition() const override; base::Optional<XRNativeOriginInformation> NativeOrigin() const override; - void Trace(blink::Visitor*) override; + void Trace(Visitor*) override; private: - std::unique_ptr<TransformationMatrix> OtherSpaceFromScreenTap( - XRSpace* other_space, - const TransformationMatrix& mojo_from_viewer); - std::unique_ptr<TransformationMatrix> OtherSpaceFromTrackedPointer( - XRSpace* other_space, - const TransformationMatrix& mojo_from_viewer); - Member<XRInputSource> input_source_; }; diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_test_utils.h b/chromium/third_party/blink/renderer/modules/xr/xr_test_utils.h index da35d671c1f..6c28ad513ff 100644 --- a/chromium/third_party/blink/renderer/modules/xr/xr_test_utils.h +++ b/chromium/third_party/blink/renderer/modules/xr/xr_test_utils.h @@ -7,7 +7,7 @@ #include <memory> -#include "third_party/blink/renderer/core/geometry/dom_point_init.h" +#include "third_party/blink/renderer/bindings/core/v8/v8_dom_point_init.h" #include "third_party/blink/renderer/core/geometry/dom_point_read_only.h" #include "third_party/blink/renderer/core/typed_arrays/dom_typed_array.h" #include "third_party/blink/renderer/platform/transforms/transformation_matrix.h" diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_transient_input_hit_test_options_init.idl b/chromium/third_party/blink/renderer/modules/xr/xr_transient_input_hit_test_options_init.idl index 10f35402f36..bc143ded892 100644 --- a/chromium/third_party/blink/renderer/modules/xr/xr_transient_input_hit_test_options_init.idl +++ b/chromium/third_party/blink/renderer/modules/xr/xr_transient_input_hit_test_options_init.idl @@ -4,6 +4,6 @@ dictionary XRTransientInputHitTestOptionsInit { required DOMString profile; - FrozenArray<XRHitTestTrackableType> entityTypes; + [RuntimeEnabled=WebXRHitTestEntityTypes] FrozenArray<XRHitTestTrackableType> entityTypes; XRRay offsetRay; }; diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_transient_input_hit_test_result.cc b/chromium/third_party/blink/renderer/modules/xr/xr_transient_input_hit_test_result.cc index 58fb9dbe243..9dd27ba1d84 100644 --- a/chromium/third_party/blink/renderer/modules/xr/xr_transient_input_hit_test_result.cc +++ b/chromium/third_party/blink/renderer/modules/xr/xr_transient_input_hit_test_result.cc @@ -15,8 +15,8 @@ XRTransientInputHitTestResult::XRTransientInputHitTestResult( const Vector<device::mojom::blink::XRHitResultPtr>& results) : input_source_(input_source) { for (const auto& result : results) { - results_.push_back( - MakeGarbageCollected<XRHitTestResult>(result->hit_matrix.matrix())); + results_.push_back(MakeGarbageCollected<XRHitTestResult>( + input_source->session(), *result)); } } @@ -28,7 +28,7 @@ HeapVector<Member<XRHitTestResult>> XRTransientInputHitTestResult::results() { return results_; } -void XRTransientInputHitTestResult::Trace(blink::Visitor* visitor) { +void XRTransientInputHitTestResult::Trace(Visitor* visitor) { visitor->Trace(input_source_); visitor->Trace(results_); ScriptWrappable::Trace(visitor); diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_transient_input_hit_test_result.h b/chromium/third_party/blink/renderer/modules/xr/xr_transient_input_hit_test_result.h index 03fa4ab722f..a6e82790c22 100644 --- a/chromium/third_party/blink/renderer/modules/xr/xr_transient_input_hit_test_result.h +++ b/chromium/third_party/blink/renderer/modules/xr/xr_transient_input_hit_test_result.h @@ -26,7 +26,7 @@ class XRTransientInputHitTestResult : public ScriptWrappable { HeapVector<Member<XRHitTestResult>> results(); - void Trace(blink::Visitor* visitor) override; + void Trace(Visitor* visitor) override; private: Member<XRInputSource> input_source_; diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_transient_input_hit_test_source.cc b/chromium/third_party/blink/renderer/modules/xr/xr_transient_input_hit_test_source.cc index 0afafb68371..a457b32210b 100644 --- a/chromium/third_party/blink/renderer/modules/xr/xr_transient_input_hit_test_source.cc +++ b/chromium/third_party/blink/renderer/modules/xr/xr_transient_input_hit_test_source.cc @@ -60,9 +60,12 @@ void XRTransientInputHitTestSource::Update( if (!input_source) continue; - current_frame_results_.push_back( - MakeGarbageCollected<XRTransientInputHitTestResult>( - input_source, source_id_and_results.value)); + // If the input source is not visible, ignore it. + if (input_source->IsVisible()) { + current_frame_results_.push_back( + MakeGarbageCollected<XRTransientInputHitTestResult>( + input_source, source_id_and_results.value)); + } } } @@ -71,7 +74,7 @@ XRTransientInputHitTestSource::Results() { return current_frame_results_; } -void XRTransientInputHitTestSource::Trace(blink::Visitor* visitor) { +void XRTransientInputHitTestSource::Trace(Visitor* visitor) { visitor->Trace(current_frame_results_); visitor->Trace(xr_session_); ScriptWrappable::Trace(visitor); diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_transient_input_hit_test_source.h b/chromium/third_party/blink/renderer/modules/xr/xr_transient_input_hit_test_source.h index 6a25fc1d008..e23ea2dca20 100644 --- a/chromium/third_party/blink/renderer/modules/xr/xr_transient_input_hit_test_source.h +++ b/chromium/third_party/blink/renderer/modules/xr/xr_transient_input_hit_test_source.h @@ -35,7 +35,7 @@ class XRTransientInputHitTestSource : public ScriptWrappable { HeapVector<Member<XRTransientInputHitTestResult>> Results(); - void Trace(blink::Visitor*) override; + void Trace(Visitor*) override; private: HeapVector<Member<XRTransientInputHitTestResult>> current_frame_results_; diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_view.cc b/chromium/third_party/blink/renderer/modules/xr/xr_view.cc index 35a1381ce3b..6814178a009 100644 --- a/chromium/third_party/blink/renderer/modules/xr/xr_view.cc +++ b/chromium/third_party/blink/renderer/modules/xr/xr_view.cc @@ -34,8 +34,7 @@ XRSession* XRView::session() const { } DOMFloat32Array* XRView::projectionMatrix() const { - if (!projection_matrix_ || !projection_matrix_->View() || - !projection_matrix_->View()->Data()) { + if (!projection_matrix_ || !projection_matrix_->Data()) { // A page may take the projection matrix value and detach it so // projection_matrix_ is a detached array buffer. This breaks the // inspector, so return null instead. @@ -142,7 +141,7 @@ XRRigidTransform* XRView::transform() const { return ref_space_from_eye_; } -void XRView::Trace(blink::Visitor* visitor) { +void XRView::Trace(Visitor* visitor) { visitor->Trace(session_); visitor->Trace(projection_matrix_); visitor->Trace(ref_space_from_eye_); diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_view.h b/chromium/third_party/blink/renderer/modules/xr/xr_view.h index b89cdd0068f..4c20b54ca50 100644 --- a/chromium/third_party/blink/renderer/modules/xr/xr_view.h +++ b/chromium/third_party/blink/renderer/modules/xr/xr_view.h @@ -35,7 +35,7 @@ class MODULES_EXPORT XRView final : public ScriptWrappable { DOMFloat32Array* projectionMatrix() const; XRRigidTransform* transform() const; - void Trace(blink::Visitor*) override; + void Trace(Visitor*) override; private: XREye eye_; diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_viewer_pose.cc b/chromium/third_party/blink/renderer/modules/xr/xr_viewer_pose.cc index fc98618cec6..52b71f98fb1 100644 --- a/chromium/third_party/blink/renderer/modules/xr/xr_viewer_pose.cc +++ b/chromium/third_party/blink/renderer/modules/xr/xr_viewer_pose.cc @@ -13,6 +13,8 @@ namespace blink { XRViewerPose::XRViewerPose(XRSession* session, const TransformationMatrix& pose_model_matrix) : XRPose(pose_model_matrix, session->EmulatedPosition()) { + DVLOG(3) << __func__ << ": emulatedPosition()=" << emulatedPosition(); + Vector<XRViewData>& view_data = session->views(); // Snapshot the session's current views. @@ -22,7 +24,7 @@ XRViewerPose::XRViewerPose(XRSession* session, } } -void XRViewerPose::Trace(blink::Visitor* visitor) { +void XRViewerPose::Trace(Visitor* visitor) { visitor->Trace(views_); XRPose::Trace(visitor); } diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_viewer_pose.h b/chromium/third_party/blink/renderer/modules/xr/xr_viewer_pose.h index 652335f408e..04527284430 100644 --- a/chromium/third_party/blink/renderer/modules/xr/xr_viewer_pose.h +++ b/chromium/third_party/blink/renderer/modules/xr/xr_viewer_pose.h @@ -23,7 +23,7 @@ class XRViewerPose final : public XRPose { const HeapVector<Member<XRView>>& views() const { return views_; } - void Trace(blink::Visitor*) override; + void Trace(Visitor*) override; private: HeapVector<Member<XRView>> views_; 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 index 064dc8f5ce7..d72ffdd38a1 100644 --- a/chromium/third_party/blink/renderer/modules/xr/xr_webgl_layer.cc +++ b/chromium/third_party/blink/renderer/modules/xr/xr_webgl_layer.cc @@ -4,13 +4,15 @@ #include "third_party/blink/renderer/modules/xr/xr_webgl_layer.h" +#include "third_party/blink/renderer/core/frame/web_feature.h" #include "third_party/blink/renderer/core/imagebitmap/image_bitmap.h" +#include "third_party/blink/renderer/core/inspector/console_message.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.h" #include "third_party/blink/renderer/modules/xr/xr_frame_provider.h" #include "third_party/blink/renderer/modules/xr/xr_session.h" +#include "third_party/blink/renderer/modules/xr/xr_system.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/bindings/exception_state.h" @@ -23,6 +25,12 @@ namespace blink { namespace { const double kFramebufferMinScale = 0.2; +const uint32_t kCleanFrameWarningLimit = 5; + +const char kCleanFrameWarning[] = + "Note: The XRSession has completed multiple animation frames without " + "drawing anything to the baseLayer's framebuffer, resulting in no visible " + "output."; // Because including base::ClampToRange would be a dependency violation double ClampToRange(const double value, const double min, const double max) { @@ -121,7 +129,8 @@ XRWebGLLayer* XRWebGLLayer::Create( framebuffers_size.Height() * framebuffer_scale); // Create an opaque WebGL Framebuffer - WebGLFramebuffer* framebuffer = WebGLFramebuffer::CreateOpaque(webgl_context); + WebGLFramebuffer* framebuffer = + WebGLFramebuffer::CreateOpaque(webgl_context, want_stencil_buffer); scoped_refptr<XRWebGLDrawingBuffer> drawing_buffer = XRWebGLDrawingBuffer::Create(webgl_context->GetDrawingBuffer(), @@ -273,9 +282,31 @@ void XRWebGLLayer::OnFrameEnd() { // Submit the frame to the XR compositor. if (session()->immersive()) { + bool framebuffer_dirty = framebuffer_->HaveContentsChanged(); + + // Not drawing to the framebuffer during a session's rAF callback is + // usually a sign that something is wrong, such as the app drawing to the + // wrong render target. Show a warning in the console if we see that + // happen too many times. + if (!framebuffer_dirty) { + // If the session doesn't have a pose then the framebuffer being clean + // may be expected, so we won't count those frames. + bool frame_had_pose = !!session()->MojoFromViewer(); + if (frame_had_pose) { + clean_frame_count++; + if (clean_frame_count == kCleanFrameWarningLimit) { + session()->xr()->GetExecutionContext()->AddConsoleMessage( + MakeGarbageCollected<ConsoleMessage>( + mojom::blink::ConsoleMessageSource::kRendering, + mojom::blink::ConsoleMessageLevel::kWarning, + kCleanFrameWarning)); + } + } + } + // Always call submit, but notify if the contents were changed or not. - session()->xr()->frameProvider()->SubmitWebGLLayer( - this, framebuffer_->HaveContentsChanged()); + session()->xr()->frameProvider()->SubmitWebGLLayer(this, + framebuffer_dirty); } } } @@ -296,15 +327,14 @@ void XRWebGLLayer::OnResize() { viewports_dirty_ = true; } -scoped_refptr<StaticBitmapImage> XRWebGLLayer::TransferToStaticBitmapImage( - std::unique_ptr<viz::SingleReleaseCallback>* out_release_callback) { +scoped_refptr<StaticBitmapImage> XRWebGLLayer::TransferToStaticBitmapImage() { if (drawing_buffer_) { - return drawing_buffer_->TransferToStaticBitmapImage(out_release_callback); + return drawing_buffer_->TransferToStaticBitmapImage(); } return nullptr; } -void XRWebGLLayer::Trace(blink::Visitor* visitor) { +void XRWebGLLayer::Trace(Visitor* visitor) { visitor->Trace(session_); visitor->Trace(left_viewport_); visitor->Trace(right_viewport_); 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 index 24765b01072..03db1338571 100644 --- a/chromium/third_party/blink/renderer/modules/xr/xr_webgl_layer.h +++ b/chromium/third_party/blink/renderer/modules/xr/xr_webgl_layer.h @@ -5,11 +5,11 @@ #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/v8_xr_webgl_layer_init.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_view.h" -#include "third_party/blink/renderer/modules/xr/xr_webgl_layer_init.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/wtf/ref_counted.h" @@ -74,10 +74,9 @@ class XRWebGLLayer final : public ScriptWrappable { // mailbox holder and its size respectively. void HandleBackgroundImage(const gpu::MailboxHolder&, const IntSize&) {} - scoped_refptr<StaticBitmapImage> TransferToStaticBitmapImage( - std::unique_ptr<viz::SingleReleaseCallback>* out_release_callback); + scoped_refptr<StaticBitmapImage> TransferToStaticBitmapImage(); - void Trace(blink::Visitor*) override; + void Trace(Visitor*) override; private: const Member<XRSession> session_; @@ -93,6 +92,8 @@ class XRWebGLLayer final : public ScriptWrappable { bool viewports_dirty_ = true; bool is_direct_draw_frame = false; bool ignore_depth_values_ = false; + + uint32_t clean_frame_count = 0; }; } // namespace blink 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 index 879c476b6e0..1f9e3af5286 100644 --- a/chromium/third_party/blink/renderer/modules/xr/xr_webgl_layer.idl +++ b/chromium/third_party/blink/renderer/modules/xr/xr_webgl_layer.idl @@ -8,11 +8,9 @@ typedef (WebGLRenderingContext or WebGL2RenderingContext) XRWebGLRenderingContex [ SecureContext, Exposed=Window, - RuntimeEnabled=WebXR, - Constructor(XRSession session, XRWebGLRenderingContext context, optional XRWebGLLayerInit layerInit), - RaisesException=Constructor, - Measure + RuntimeEnabled=WebXR ] interface XRWebGLLayer { + [RaisesException, Measure] constructor(XRSession session, XRWebGLRenderingContext context, optional XRWebGLLayerInit layerInit = {}); readonly attribute boolean antialias; readonly attribute boolean ignoreDepthValues; diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_world_information.cc b/chromium/third_party/blink/renderer/modules/xr/xr_world_information.cc index 9ac798dd713..02dff332be9 100644 --- a/chromium/third_party/blink/renderer/modules/xr/xr_world_information.cc +++ b/chromium/third_party/blink/renderer/modules/xr/xr_world_information.cc @@ -5,6 +5,7 @@ #include "third_party/blink/renderer/modules/xr/xr_world_information.h" #include "base/trace_event/trace_event.h" +#include "third_party/blink/renderer/modules/xr/xr_light_estimation.h" #include "third_party/blink/renderer/modules/xr/xr_session.h" namespace blink { @@ -12,8 +13,9 @@ namespace blink { XRWorldInformation::XRWorldInformation(XRSession* session) : session_(session) {} -void XRWorldInformation::Trace(blink::Visitor* visitor) { +void XRWorldInformation::Trace(Visitor* visitor) { visitor->Trace(plane_ids_to_planes_); + visitor->Trace(light_estimation_); visitor->Trace(session_); ScriptWrappable::Trace(visitor); } @@ -33,8 +35,12 @@ XRPlaneSet* XRWorldInformation::detectedPlanes() const { return MakeGarbageCollected<XRPlaneSet>(result); } +XRLightEstimation* XRWorldInformation::lightEstimation() const { + return light_estimation_.Get(); +} + void XRWorldInformation::ProcessPlaneInformation( - const device::mojom::blink::XRPlaneDetectionDataPtr& detected_planes_data, + const device::mojom::blink::XRPlaneDetectionData* detected_planes_data, double timestamp) { TRACE_EVENT0("xr", __FUNCTION__); @@ -64,14 +70,16 @@ void XRWorldInformation::ProcessPlaneInformation( // First, process all planes that had their information updated (new planes // are also processed here). for (const auto& plane : detected_planes_data->updated_planes_data) { + DCHECK(plane); + auto it = plane_ids_to_planes_.find(plane->id); if (it != plane_ids_to_planes_.end()) { updated_planes.insert(plane->id, it->value); - it->value->Update(plane, timestamp); + it->value->Update(*plane, timestamp); } else { updated_planes.insert( - plane->id, - MakeGarbageCollected<XRPlane>(plane->id, session_, plane, timestamp)); + plane->id, MakeGarbageCollected<XRPlane>(plane->id, session_, *plane, + timestamp)); } } @@ -91,4 +99,16 @@ void XRWorldInformation::ProcessPlaneInformation( plane_ids_to_planes_.swap(updated_planes); } +void XRWorldInformation::ProcessLightEstimationData( + const device::mojom::blink::XRLightEstimationData* data, + double timestamp) { + TRACE_EVENT0("xr", __FUNCTION__); + + if (data) { + light_estimation_ = MakeGarbageCollected<XRLightEstimation>(*data); + } else { + light_estimation_ = nullptr; + } +} + } // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_world_information.h b/chromium/third_party/blink/renderer/modules/xr/xr_world_information.h index d39ee9a0699..05ec44afcb6 100644 --- a/chromium/third_party/blink/renderer/modules/xr/xr_world_information.h +++ b/chromium/third_party/blink/renderer/modules/xr/xr_world_information.h @@ -11,6 +11,7 @@ namespace blink { +class XRLightEstimation; class XRSession; class XRWorldInformation : public ScriptWrappable { @@ -23,13 +24,19 @@ class XRWorldInformation : public ScriptWrappable { // disabled. XRPlaneSet* detectedPlanes() const; - void Trace(blink::Visitor* visitor) override; + XRLightEstimation* lightEstimation() const; + + void Trace(Visitor* visitor) override; // Applies changes to the stored plane information based on the contents of // the received frame data. This will update the contents of // plane_ids_to_planes_. void ProcessPlaneInformation( - const device::mojom::blink::XRPlaneDetectionDataPtr& detected_planes_data, + const device::mojom::blink::XRPlaneDetectionData* detected_planes_data, + double timestamp); + + void ProcessLightEstimationData( + const device::mojom::blink::XRLightEstimationData* data, double timestamp); private: @@ -39,6 +46,8 @@ class XRWorldInformation : public ScriptWrappable { bool is_detected_planes_null_ = true; HeapHashMap<uint64_t, Member<XRPlane>> plane_ids_to_planes_; + Member<XRLightEstimation> light_estimation_; + Member<XRSession> session_; }; diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_world_information.idl b/chromium/third_party/blink/renderer/modules/xr/xr_world_information.idl index 7aa695098d9..64ad2fabd19 100644 --- a/chromium/third_party/blink/renderer/modules/xr/xr_world_information.idl +++ b/chromium/third_party/blink/renderer/modules/xr/xr_world_information.idl @@ -7,9 +7,10 @@ [ SecureContext, Exposed=Window, - RuntimeEnabled=WebXRPlaneDetection + RuntimeEnabled=WebXRIncubations ] interface XRWorldInformation { readonly attribute XRPlaneSet? detectedPlanes; + readonly attribute XRLightEstimation? lightEstimation; }; diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_world_tracking_state.cc b/chromium/third_party/blink/renderer/modules/xr/xr_world_tracking_state.cc index 53679567bcf..f545a4d3842 100644 --- a/chromium/third_party/blink/renderer/modules/xr/xr_world_tracking_state.cc +++ b/chromium/third_party/blink/renderer/modules/xr/xr_world_tracking_state.cc @@ -3,8 +3,12 @@ // found in the LICENSE file. #include "third_party/blink/renderer/modules/xr/xr_world_tracking_state.h" + +#include "third_party/blink/renderer/bindings/modules/v8/v8_xr_light_estimation_state_init.h" +#include "third_party/blink/renderer/bindings/modules/v8/v8_xr_plane_detection_state_init.h" +#include "third_party/blink/renderer/bindings/modules/v8/v8_xr_world_tracking_state_init.h" +#include "third_party/blink/renderer/modules/xr/xr_light_estimation_state.h" #include "third_party/blink/renderer/modules/xr/xr_plane_detection_state.h" -#include "third_party/blink/renderer/modules/xr/xr_world_tracking_state_init.h" namespace blink { @@ -15,12 +19,23 @@ XRWorldTrackingState::XRWorldTrackingState( plane_detection_state_ = MakeGarbageCollected<XRPlaneDetectionState>( world_tracking_state_init->planeDetectionState()); } else { - plane_detection_state_ = MakeGarbageCollected<XRPlaneDetectionState>(); + plane_detection_state_ = + MakeGarbageCollected<XRPlaneDetectionState>(nullptr); + } + + if (world_tracking_state_init && + world_tracking_state_init->hasLightEstimationState()) { + light_estimation_state_ = MakeGarbageCollected<XRLightEstimationState>( + world_tracking_state_init->lightEstimationState()); + } else { + light_estimation_state_ = + MakeGarbageCollected<XRLightEstimationState>(nullptr); } } -void XRWorldTrackingState::Trace(blink::Visitor* visitor) { +void XRWorldTrackingState::Trace(Visitor* visitor) { visitor->Trace(plane_detection_state_); + visitor->Trace(light_estimation_state_); ScriptWrappable::Trace(visitor); } diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_world_tracking_state.h b/chromium/third_party/blink/renderer/modules/xr/xr_world_tracking_state.h index 87625a8cda7..425542d1803 100644 --- a/chromium/third_party/blink/renderer/modules/xr/xr_world_tracking_state.h +++ b/chromium/third_party/blink/renderer/modules/xr/xr_world_tracking_state.h @@ -7,12 +7,12 @@ #include "third_party/blink/renderer/platform/bindings/script_wrappable.h" -#include "third_party/blink/renderer/platform/bindings/script_wrappable.h" #include "third_party/blink/renderer/platform/heap/handle.h" namespace blink { class XRPlaneDetectionState; +class XRLightEstimationState; class XRWorldTrackingStateInit; class XRWorldTrackingState : public ScriptWrappable { @@ -26,10 +26,15 @@ class XRWorldTrackingState : public ScriptWrappable { return plane_detection_state_; } - void Trace(blink::Visitor* visitor) override; + XRLightEstimationState* lightEstimationState() const { + return light_estimation_state_; + } + + void Trace(Visitor* visitor) override; private: Member<XRPlaneDetectionState> plane_detection_state_; + Member<XRLightEstimationState> light_estimation_state_; }; } // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_world_tracking_state.idl b/chromium/third_party/blink/renderer/modules/xr/xr_world_tracking_state.idl index 070ee061f96..b637518c578 100644 --- a/chromium/third_party/blink/renderer/modules/xr/xr_world_tracking_state.idl +++ b/chromium/third_party/blink/renderer/modules/xr/xr_world_tracking_state.idl @@ -7,9 +7,10 @@ [ SecureContext, Exposed=Window, - RuntimeEnabled=WebXRPlaneDetection + RuntimeEnabled=WebXRIncubations ] interface XRWorldTrackingState { readonly attribute XRPlaneDetectionState planeDetectionState; + readonly attribute XRLightEstimationState lightEstimationState; }; diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_world_tracking_state_init.idl b/chromium/third_party/blink/renderer/modules/xr/xr_world_tracking_state_init.idl index f8fd6bb64cf..2217591fd84 100644 --- a/chromium/third_party/blink/renderer/modules/xr/xr_world_tracking_state_init.idl +++ b/chromium/third_party/blink/renderer/modules/xr/xr_world_tracking_state_init.idl @@ -6,5 +6,6 @@ // https://github.com/immersive-web/real-world-geometry/blob/master/plane-detection-explainer.md dictionary XRWorldTrackingStateInit { XRPlaneDetectionStateInit planeDetectionState; + XRLightEstimationStateInit lightEstimationState; }; |