From 1d1646afd1ff4f068fc41d8b142b08d53e6cd91a Mon Sep 17 00:00:00 2001 From: zhongwuzw Date: Fri, 16 Aug 2024 01:00:07 -0700 Subject: [PATCH] Fixes findNodeAtPoint when views were inverted (#45519) Summary: FIxes https://github.com/facebook/react-native/issues/45502 . cc realsoelynn ## Changelog: [GENERAL] [FIXED] - Fixes findNodeAtPoint when views were inverted Pull Request resolved: https://github.com/facebook/react-native/pull/45519 Test Plan: Demo in https://github.com/facebook/react-native/issues/45502 . Reviewed By: cipolleschi Differential Revision: D59920660 Pulled By: realsoelynn fbshipit-source-id: 9e1075406830aa3a3ec436d70d539ca0674f8d34 --- .../renderer/core/LayoutableShadowNode.cpp | 24 ++++++++- .../core/tests/FindNodeAtPointTest.cpp | 49 +++++++++++++++++++ .../react/renderer/graphics/Transform.cpp | 5 +- 3 files changed, 75 insertions(+), 3 deletions(-) diff --git a/packages/react-native/ReactCommon/react/renderer/core/LayoutableShadowNode.cpp b/packages/react-native/ReactCommon/react/renderer/core/LayoutableShadowNode.cpp index a5f56b4ea9c..8aee6ef9953 100644 --- a/packages/react-native/ReactCommon/react/renderer/core/LayoutableShadowNode.cpp +++ b/packages/react-native/ReactCommon/react/renderer/core/LayoutableShadowNode.cpp @@ -261,8 +261,9 @@ ShadowNode::Shared LayoutableShadowNode::findNodeAtPoint( return nullptr; } + auto transform = layoutableShadowNode->getTransform(); auto frame = layoutableShadowNode->getLayoutMetrics().frame; - auto transformedFrame = frame * layoutableShadowNode->getTransform(); + auto transformedFrame = frame * transform; auto isPointInside = transformedFrame.containsPoint(point); if (!isPointInside) { @@ -271,6 +272,27 @@ ShadowNode::Shared LayoutableShadowNode::findNodeAtPoint( return node; } + if (Transform::isVerticalInversion(transform) || + Transform::isHorizontalInversion(transform)) { + auto centerX = + transformedFrame.origin.x + transformedFrame.size.width / 2.0; + auto centerY = + transformedFrame.origin.y + transformedFrame.size.height / 2.0; + + auto relativeX = point.x - centerX; + auto relativeY = point.y - centerY; + + if (Transform::isVerticalInversion(transform)) { + relativeY = -relativeY; + } + if (Transform::isHorizontalInversion(transform)) { + relativeX = -relativeX; + } + + point.x = centerX + relativeX; + point.y = centerY + relativeY; + } + auto newPoint = point - transformedFrame.origin - layoutableShadowNode->getContentOriginOffset(false); diff --git a/packages/react-native/ReactCommon/react/renderer/core/tests/FindNodeAtPointTest.cpp b/packages/react-native/ReactCommon/react/renderer/core/tests/FindNodeAtPointTest.cpp index 0b95fc5443b..c167f86591a 100644 --- a/packages/react-native/ReactCommon/react/renderer/core/tests/FindNodeAtPointTest.cpp +++ b/packages/react-native/ReactCommon/react/renderer/core/tests/FindNodeAtPointTest.cpp @@ -366,3 +366,52 @@ TEST(FindNodeAtPointTest, overlappingViewsWithParentPointerEventsNone) { EXPECT_EQ( LayoutableShadowNode::findNodeAtPoint(parentShadowNode, {50, 50}), nullptr); } + +TEST(FindNodeAtPointTest, invertedList) { + auto builder = simpleComponentBuilder(); + + // clang-format off + auto element = + Element() + .props([] { + auto sharedProps = std::make_shared(); + sharedProps->transform = Transform::VerticalInversion(); + return sharedProps; + }) + .tag(1) + .finalize([](ScrollViewShadowNode &shadowNode){ + auto layoutMetrics = EmptyLayoutMetrics; + layoutMetrics.frame.size = {100, 200}; + shadowNode.setLayoutMetrics(layoutMetrics); + }) + .children({ + Element() + .tag(2) + .finalize([](ViewShadowNode &shadowNode){ + auto layoutMetrics = EmptyLayoutMetrics; + layoutMetrics.frame.origin = {0, 0}; + layoutMetrics.frame.size = {100, 100}; + shadowNode.setLayoutMetrics(layoutMetrics); + }), + Element() + .tag(3) + .finalize([](ViewShadowNode &shadowNode){ + auto layoutMetrics = EmptyLayoutMetrics; + layoutMetrics.frame.origin = {0, 100}; + layoutMetrics.frame.size = {100, 100}; + shadowNode.setLayoutMetrics(layoutMetrics); + }) + }); + // clang-format on + + auto parentShadowNode = builder.build(element); + + EXPECT_EQ( + LayoutableShadowNode::findNodeAtPoint(parentShadowNode, {10, 10}) + ->getTag(), + 3); + EXPECT_EQ( + LayoutableShadowNode::findNodeAtPoint(parentShadowNode, {10, 105}) + ->getTag(), + 2); +} diff --git a/packages/react-native/ReactCommon/react/renderer/graphics/Transform.cpp b/packages/react-native/ReactCommon/react/renderer/graphics/Transform.cpp index d65299a25d3..1fe176f0cbc 100644 --- a/packages/react-native/ReactCommon/react/renderer/graphics/Transform.cpp +++ b/packages/react-native/ReactCommon/react/renderer/graphics/Transform.cpp @@ -11,6 +11,7 @@ #include #include +#include namespace facebook::react { @@ -305,11 +306,11 @@ Transform Transform::Interpolate( } bool Transform::isVerticalInversion(const Transform& transform) { - return transform.at(1, 1) == -1; + return facebook::react::floatEquality(transform.at(1, 1), -1.0f); } bool Transform::isHorizontalInversion(const Transform& transform) { - return transform.at(0, 0) == -1; + return facebook::react::floatEquality(transform.at(0, 0), -1.0f); } bool Transform::operator==(const Transform& rhs) const {