#include "device/vr/openxr/openxr_hand_utils.h"
#include <iomanip>
#include <sstream>
#include "base/containers/span.h"
#include "base/memory/raw_ptr_exclusion.h"
#include "base/trace_event/trace_event.h"
#include "device/vr/public/mojom/xr_hand_tracking_data.mojom.h"
#include "ui/gfx/geometry/transform.h"
#include "ui/gfx/geometry/vector3d_f.h"
namespace device {
namespace {
static_assert(XR_HAND_JOINT_PALM_EXT == 0u,
"OpenXR palm joint expected to be the 0th joint");
static_assert(kNumWebXRJoints == XR_HAND_JOINT_COUNT_EXT - 1u);
static_assert(mojom::XRHandJoint::kWrist ==
OpenXRHandJointToMojomJoint(XR_HAND_JOINT_WRIST_EXT),
"WebXR - OpenXR joint enum value mismatch");
static_assert(
mojom::XRHandJoint::kThumbMetacarpal ==
OpenXRHandJointToMojomJoint(XR_HAND_JOINT_THUMB_METACARPAL_EXT),
"WebXR - OpenXR joint enum value mismatch");
static_assert(mojom::XRHandJoint::kThumbPhalanxProximal ==
OpenXRHandJointToMojomJoint(XR_HAND_JOINT_THUMB_PROXIMAL_EXT),
"WebXR - OpenXR joint enum value mismatch");
static_assert(mojom::XRHandJoint::kThumbPhalanxDistal ==
OpenXRHandJointToMojomJoint(XR_HAND_JOINT_THUMB_DISTAL_EXT),
"WebXR - OpenXR joint enum value mismatch");
static_assert(mojom::XRHandJoint::kThumbTip ==
OpenXRHandJointToMojomJoint(XR_HAND_JOINT_THUMB_TIP_EXT),
"WebXR - OpenXR joint enum value mismatch");
static_assert(
mojom::XRHandJoint::kIndexFingerMetacarpal ==
OpenXRHandJointToMojomJoint(XR_HAND_JOINT_INDEX_METACARPAL_EXT),
"WebXR - OpenXR joint enum value mismatch");
static_assert(mojom::XRHandJoint::kIndexFingerPhalanxProximal ==
OpenXRHandJointToMojomJoint(XR_HAND_JOINT_INDEX_PROXIMAL_EXT),
"WebXR - OpenXR joint enum value mismatch");
static_assert(
mojom::XRHandJoint::kIndexFingerPhalanxIntermediate ==
OpenXRHandJointToMojomJoint(XR_HAND_JOINT_INDEX_INTERMEDIATE_EXT),
"WebXR - OpenXR joint enum value mismatch");
static_assert(mojom::XRHandJoint::kIndexFingerPhalanxDistal ==
OpenXRHandJointToMojomJoint(XR_HAND_JOINT_INDEX_DISTAL_EXT),
"WebXR - OpenXR joint enum value mismatch");
static_assert(mojom::XRHandJoint::kIndexFingerTip ==
OpenXRHandJointToMojomJoint(XR_HAND_JOINT_INDEX_TIP_EXT),
"WebXR - OpenXR joint enum value mismatch");
static_assert(
mojom::XRHandJoint::kMiddleFingerMetacarpal ==
OpenXRHandJointToMojomJoint(XR_HAND_JOINT_MIDDLE_METACARPAL_EXT),
"WebXR - OpenXR joint enum value mismatch");
static_assert(
mojom::XRHandJoint::kMiddleFingerPhalanxProximal ==
OpenXRHandJointToMojomJoint(XR_HAND_JOINT_MIDDLE_PROXIMAL_EXT),
"WebXR - OpenXR joint enum value mismatch");
static_assert(
mojom::XRHandJoint::kMiddleFingerPhalanxIntermediate ==
OpenXRHandJointToMojomJoint(XR_HAND_JOINT_MIDDLE_INTERMEDIATE_EXT),
"WebXR - OpenXR joint enum value mismatch");
static_assert(mojom::XRHandJoint::kMiddleFingerPhalanxDistal ==
OpenXRHandJointToMojomJoint(XR_HAND_JOINT_MIDDLE_DISTAL_EXT),
"WebXR - OpenXR joint enum value mismatch");
static_assert(mojom::XRHandJoint::kMiddleFingerTip ==
OpenXRHandJointToMojomJoint(XR_HAND_JOINT_MIDDLE_TIP_EXT),
"WebXR - OpenXR joint enum value mismatch");
static_assert(
mojom::XRHandJoint::kRingFingerMetacarpal ==
OpenXRHandJointToMojomJoint(XR_HAND_JOINT_RING_METACARPAL_EXT),
"WebXR - OpenXR joint enum value mismatch");
static_assert(mojom::XRHandJoint::kRingFingerPhalanxProximal ==
OpenXRHandJointToMojomJoint(XR_HAND_JOINT_RING_PROXIMAL_EXT),
"WebXR - OpenXR joint enum value mismatch");
static_assert(
mojom::XRHandJoint::kRingFingerPhalanxIntermediate ==
OpenXRHandJointToMojomJoint(XR_HAND_JOINT_RING_INTERMEDIATE_EXT),
"WebXR - OpenXR joint enum value mismatch");
static_assert(mojom::XRHandJoint::kRingFingerPhalanxDistal ==
OpenXRHandJointToMojomJoint(XR_HAND_JOINT_RING_DISTAL_EXT),
"WebXR - OpenXR joint enum value mismatch");
static_assert(mojom::XRHandJoint::kRingFingerTip ==
OpenXRHandJointToMojomJoint(XR_HAND_JOINT_RING_TIP_EXT),
"WebXR - OpenXR joint enum value mismatch");
static_assert(
mojom::XRHandJoint::kPinkyFingerMetacarpal ==
OpenXRHandJointToMojomJoint(XR_HAND_JOINT_LITTLE_METACARPAL_EXT),
"WebXR - OpenXR joint enum value mismatch");
static_assert(
mojom::XRHandJoint::kPinkyFingerPhalanxProximal ==
OpenXRHandJointToMojomJoint(XR_HAND_JOINT_LITTLE_PROXIMAL_EXT),
"WebXR - OpenXR joint enum value mismatch");
static_assert(
mojom::XRHandJoint::kPinkyFingerPhalanxIntermediate ==
OpenXRHandJointToMojomJoint(XR_HAND_JOINT_LITTLE_INTERMEDIATE_EXT),
"WebXR - OpenXR joint enum value mismatch");
static_assert(mojom::XRHandJoint::kPinkyFingerPhalanxDistal ==
OpenXRHandJointToMojomJoint(XR_HAND_JOINT_LITTLE_DISTAL_EXT),
"WebXR - OpenXR joint enum value mismatch");
static_assert(mojom::XRHandJoint::kPinkyFingerTip ==
OpenXRHandJointToMojomJoint(XR_HAND_JOINT_LITTLE_TIP_EXT),
"WebXR - OpenXR joint enum value mismatch");
constexpr size_t kThumbJointCount = 4;
constexpr size_t kIndexJointCount = 5;
constexpr size_t kMiddleJointCount = 5;
constexpr size_t kRingJointCount = 5;
constexpr size_t kPinkyJointCount = 5;
static_assert(1 + kThumbJointCount + kIndexJointCount + kMiddleJointCount +
kRingJointCount + kPinkyJointCount ==
kNumWebXRJoints);
constexpr std::array<float, kNumWebXRJoints> kJointRadii = {
0.01, 0.0194, .0123, 0.0098, 0.0088, 0.0212, 0.0103, 0.0085, 0.0076,
0.0066, 0.0212, 0.0112, 0.0080, 0.0076, 0.0066, 0.0191, 0.0099, 0.0076,
0.0072, 0.0062, 0.0181, 0.0085, 0.0068, 0.0064, 0.0054};
constexpr std::array<float, kThumbJointCount> kThumbDistances = {
0.0486, 0.0325, 0.0338, 0.0246};
constexpr std::array<float, kIndexJointCount> kIndexDistances = {
0.0425, 0.0597, 0.0379, 0.0243, 0.0224};
constexpr std::array<float, kMiddleJointCount> kMiddleDistances = {
0.0353, 0.0616, 0.0429, 0.0275, 0.0250};
constexpr std::array<float, kRingJointCount> kRingDistances = {
0.0383, 0.0540, 0.0390, 0.0266, 0.0244};
constexpr std::array<float, kPinkyJointCount> kPinkyDistances = {
0.0422, 0.0457, 0.0307, 0.0203, 0.0220};
constexpr size_t kThumbOrigin = static_cast<size_t>(mojom::XRHandJoint::kWrist);
constexpr size_t kIndexOrigin = static_cast<size_t>(mojom::XRHandJoint::kWrist);
constexpr size_t kMiddleOrigin =
static_cast<size_t>(mojom::XRHandJoint::kWrist);
constexpr size_t kRingOrigin = static_cast<size_t>(mojom::XRHandJoint::kWrist);
constexpr size_t kPinkyOrigin = static_cast<size_t>(mojom::XRHandJoint::kWrist);
constexpr size_t kThumbStartIndex =
static_cast<size_t>(mojom::XRHandJoint::kThumbMetacarpal);
constexpr size_t kIndexStartIndex =
static_cast<size_t>(mojom::XRHandJoint::kIndexFingerMetacarpal);
constexpr size_t kMiddleStartIndex =
static_cast<size_t>(mojom::XRHandJoint::kMiddleFingerMetacarpal);
constexpr size_t kRingStartIndex =
static_cast<size_t>(mojom::XRHandJoint::kRingFingerMetacarpal);
constexpr size_t kPinkyStartIndex =
static_cast<size_t>(mojom::XRHandJoint::kPinkyFingerMetacarpal);
struct XRFingerMapping {
const size_t origin_index;
const size_t start_index;
RAW_PTR_EXCLUSION const base::span<const float> standard_joint_sizes;
size_t JointCount() const { return standard_joint_sizes.size(); }
};
constexpr std::array<XRFingerMapping, 5> kHandMapping({
{kThumbOrigin, kThumbStartIndex, kThumbDistances},
{kIndexOrigin, kIndexStartIndex, kIndexDistances},
{kMiddleOrigin, kMiddleStartIndex, kMiddleDistances},
{kRingOrigin, kRingStartIndex, kRingDistances},
{kPinkyOrigin, kPinkyStartIndex, kPinkyDistances},
});
}
bool AnonymizeHand(base::span<mojom::XRHandJointDataPtr> hand_data) {
TRACE_EVENT0("xr", "AnonymizeHand");
for (const auto& joint : hand_data) {
joint->radius = kJointRadii[static_cast<uint32_t>(joint->joint)];
}
for (const auto& finger_info : kHandMapping) {
const auto& base_joint = hand_data[finger_info.origin_index];
if (!base_joint->mojo_from_joint) {
return false;
}
const auto& base_transform = base_joint->mojo_from_joint.value();
gfx::Vector3dF previous_joint_real_position =
base_transform.To3dTranslation();
gfx::Vector3dF previous_joint_anonymized_position =
base_transform.To3dTranslation();
base::span<mojom::XRHandJointDataPtr> joints =
hand_data.subspan(finger_info.start_index, finger_info.JointCount());
for (size_t i = 0; i < joints.size(); i++) {
if (!joints[i]->mojo_from_joint.has_value()) {
return false;
}
gfx::Transform& current_joint_transform =
joints[i]->mojo_from_joint.value();
auto previous_joint_to_current_joint =
current_joint_transform.To3dTranslation() -
previous_joint_real_position;
if (previous_joint_to_current_joint.Length() <
std::numeric_limits<float>::epsilon()) {
return false;
}
float scale_factor = finger_info.standard_joint_sizes[i] /
previous_joint_to_current_joint.Length();
previous_joint_to_current_joint.Scale(scale_factor);
previous_joint_real_position = current_joint_transform.To3dTranslation();
const auto current_joint_anonymized_position =
previous_joint_anonymized_position + previous_joint_to_current_joint;
current_joint_transform.set_rc(0, 3,
current_joint_anonymized_position.x());
current_joint_transform.set_rc(1, 3,
current_joint_anonymized_position.y());
current_joint_transform.set_rc(2, 3,
current_joint_anonymized_position.z());
previous_joint_anonymized_position = current_joint_anonymized_position;
}
}
return true;
}
}