Files
react-native/ReactCommon/react/renderer/graphics/RectangleEdges.h
T
Genki Kondo 96659f8e83 Fix overflowInset to take into account hitSlop
Summary:
Previously, the touch area could never extend past the parent view bounds. Thus, hitSlop would not have any effect if it extended beyond any ancestor view's view bounds.

In this diff, we apply hitSlop when calculating overflowInset. Specifically, we make sure to union the hit slop areas of all children when calculating the contentFrame.

overflowInset is then used for hit testing (as in [TouchTargetHelper.java](https://www.internalfb.com/code/fbsource/[b0f630bb24271d8ed543e98ff144590290e19805]/xplat/js/react-native-github/ReactAndroid/src/main/java/com/facebook/react/uimanager/TouchTargetHelper.java?lines=195)).

A risk is that other optimizations that may potentially rely on overflowInset beyond hit testing (such as clipToBounds) may not be as efficient with a large hitSlop.

Changelog:
[General][Fixed] - Fix touch handling so that hitSlop can extend beyond parent view bounds.

Reviewed By: javache

Differential Revision: D43854774

fbshipit-source-id: 160bef135b8487c28c4ada662577c35a7a36f484
2023-03-07 12:30:14 -08:00

111 lines
2.6 KiB
C++

/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once
#include <tuple>
#include <folly/Hash.h>
#include <react/renderer/graphics/Float.h>
#include <react/renderer/graphics/Rect.h>
namespace facebook {
namespace react {
/*
* Generic data structure describes some values associated with *edges*
* of a rectangle.
*/
template <typename T>
struct RectangleEdges {
T left{};
T top{};
T right{};
T bottom{};
bool operator==(RectangleEdges<T> const &rhs) const noexcept {
return std::tie(this->left, this->top, this->right, this->bottom) ==
std::tie(rhs.left, rhs.top, rhs.right, rhs.bottom);
}
bool operator!=(RectangleEdges<T> const &rhs) const noexcept {
return !(*this == rhs);
}
bool isUniform() const noexcept {
return left == top && left == right && left == bottom;
}
static RectangleEdges<T> const ZERO;
};
template <typename T>
RectangleEdges<T> const RectangleEdges<T>::ZERO = {};
template <typename T>
RectangleEdges<T> operator+(
RectangleEdges<T> const &lhs,
RectangleEdges<T> const &rhs) noexcept {
return RectangleEdges<T>{
lhs.left + rhs.left,
lhs.top + rhs.top,
lhs.right + rhs.right,
lhs.bottom + rhs.bottom};
}
template <typename T>
RectangleEdges<T> operator-(
RectangleEdges<T> const &lhs,
RectangleEdges<T> const &rhs) noexcept {
return RectangleEdges<T>{
lhs.left - rhs.left,
lhs.top - rhs.top,
lhs.right - rhs.right,
lhs.bottom - rhs.bottom};
}
/*
* EdgeInsets
*/
using EdgeInsets = RectangleEdges<Float>;
/*
* Adjusts a rectangle by the given edge insets.
*/
inline Rect insetBy(Rect const &rect, EdgeInsets const &insets) noexcept {
return Rect{
{rect.origin.x + insets.left, rect.origin.y + insets.top},
{rect.size.width - insets.left - insets.right,
rect.size.height - insets.top - insets.bottom}};
}
/*
* Adjusts a rectangle by the given edge outsets.
*/
inline Rect outsetBy(Rect const &rect, EdgeInsets const &outsets) noexcept {
return Rect{
{rect.origin.x - outsets.left, rect.origin.y - outsets.top},
{rect.size.width + outsets.left + outsets.right,
rect.size.height + outsets.top + outsets.bottom}};
}
} // namespace react
} // namespace facebook
namespace std {
template <typename T>
struct hash<facebook::react::RectangleEdges<T>> {
size_t operator()(
facebook::react::RectangleEdges<T> const &edges) const noexcept {
return folly::hash::hash_combine(
0, edges.left, edges.right, edges.top, edges.bottom);
}
};
} // namespace std