blob: 75a7b274008048b892a4e2365ee1393fd9f2fdd5 [file] [log] [blame]
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_INPUT_SOURCE_H_
#define THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_INPUT_SOURCE_H_
#include "base/optional.h"
#include "device/vr/public/mojom/vr_service.mojom-blink.h"
#include "third_party/blink/renderer/modules/gamepad/gamepad.h"
#include "third_party/blink/renderer/modules/xr/xr_native_origin_information.h"
#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/transforms/transformation_matrix.h"
#include "third_party/blink/renderer/platform/wtf/forward.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
namespace device {
class Gamepad;
}
namespace blink {
class Element;
class XRGripSpace;
class XRHand;
class XRInputSourceEvent;
class XRSession;
class XRSpace;
class XRTargetRaySpace;
class XRInputSource : public ScriptWrappable, public Gamepad::Client {
DEFINE_WRAPPERTYPEINFO();
public:
static XRInputSource* CreateOrUpdateFrom(
XRInputSource* other /* may be null, input */,
XRSession* session,
const device::mojom::blink::XRInputSourceStatePtr& state);
XRInputSource(XRSession*,
uint32_t source_id,
device::mojom::XRTargetRayMode target_ray_mode =
device::mojom::XRTargetRayMode::GAZING);
XRInputSource(const XRInputSource& other);
~XRInputSource() override = default;
int16_t activeFrameId() const { return state_.active_frame_id; }
void setActiveFrameId(int16_t id) { state_.active_frame_id = id; }
XRSession* session() const { return session_; }
device::mojom::XRHandedness xr_handedness() const {
return state_.handedness;
}
const String handedness() const;
const String targetRayMode() const;
bool emulatedPosition() const { return state_.emulated_position; }
XRSpace* targetRaySpace() const;
XRSpace* gripSpace() const;
Gamepad* gamepad() const { return gamepad_; }
XRHand* hand() const { return hand_; }
Vector<String> profiles() const { return state_.profiles; }
uint32_t source_id() const { return state_.source_id; }
void SetInputFromPointer(const TransformationMatrix*);
void SetGamepadConnected(bool state);
// Gamepad::Client
GamepadHapticActuator* GetVibrationActuatorForGamepad(
const Gamepad&) override {
// TODO(https://crbug.com/955097): XRInputSource implementation of
// Gamepad::Client must manage vibration actuator state in a similar way to
// NavigatorGamepad.
return nullptr;
}
device::mojom::XRTargetRayMode TargetRayMode() const {
return state_.target_ray_mode;
}
base::Optional<TransformationMatrix> MojoFromInput() const;
base::Optional<TransformationMatrix> InputFromPointer() const;
base::Optional<device::mojom::blink::XRNativeOriginInformation> nativeOrigin()
const;
void OnSelectStart();
void OnSelectEnd();
void OnSelect();
void OnSqueezeStart();
void OnSqueezeEnd();
void OnSqueeze();
void UpdateButtonStates(
const device::mojom::blink::XRInputSourceStatePtr& state);
void OnRemoved();
// 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*) const override;
private:
// In order to ease copying, any new member variables that can be trivially
// copied (except for Member<T> variables), should go here
struct InternalState {
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;
bool emulated_position = false;
base::TimeTicks base_timestamp;
Vector<String> profiles;
InternalState(uint32_t source_id,
device::mojom::XRTargetRayMode,
base::TimeTicks base_timestamp);
InternalState(const InternalState& other);
~InternalState();
};
// Use to check if the updates that would/should be made by a given
// XRInputSourceState would invalidate any SameObject properties guaranteed
// by the idl, and thus require the xr_input_source to be recreated.
bool InvalidatesSameObject(
const device::mojom::blink::XRInputSourceStatePtr& state);
// Note that UpdateGamepad should only be called after a check/recreation
// from InvalidatesSameObject
void UpdateGamepad(const base::Optional<device::Gamepad>& gamepad);
XRInputSourceEvent* CreateInputSourceEvent(const AtomicString& type);
// These member variables all require special behavior when being copied or
// are Member<T> type variables. When adding another one, be sure to keep the
// deep-copy constructor updated, when adding any new variable.
InternalState state_;
const Member<XRSession> session_;
Member<XRTargetRaySpace> target_ray_space_;
Member<XRGripSpace> grip_space_;
Member<Gamepad> gamepad_;
Member<XRHand> hand_;
// Input device pose in mojo space. This is the grip pose for
// tracked controllers, and the viewer pose for screen input.
std::unique_ptr<TransformationMatrix> mojo_from_input_;
// Pointer pose in input device space, this is the transform to apply to
// mojo_from_input_ to get the pointer matrix. In most cases it should be
// static.
std::unique_ptr<TransformationMatrix> input_from_pointer_;
};
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_INPUT_SOURCE_H_