Back out "Back out "[RN][Fabric] Introducing LayoutableShadownode::getContentOriginOffset and use it in ScrollView""

Summary:
This diff reverts a revert of D22456266 (https://github.com/facebook/react-native/commit/0060b5de559cd9c785a2a2a6c66f58088fea4dd2) and fixes the reason why it was reverted. Reverted in D22532594 (https://github.com/facebook/react-native/commit/c0e7e1bd9cf050b4a77a20212603d3468826979c).

For reason why it was introduced in the first place, please refer to D22456266 (https://github.com/facebook/react-native/commit/0060b5de559cd9c785a2a2a6c66f58088fea4dd2).

Problem:
`includeTransform` was not taken into account when calculating offset.

I added a unit test covering this specific scenario.

Reviewed By: shergin

Differential Revision: D22763011

fbshipit-source-id: e7d88fc19608ad1a4c7b5e594a9cc48122a2799b
This commit is contained in:
Samuel Susla
2020-07-27 13:23:53 -07:00
committed by Facebook GitHub Bot
parent b08fff6f86
commit cd6e2b468d
7 changed files with 94 additions and 23 deletions
@@ -37,11 +37,9 @@ void ScrollViewShadowNode::layout(LayoutContext layoutContext) {
updateStateIfNeeded();
}
Transform ScrollViewShadowNode::getTransform() const {
auto transform = ConcreteViewShadowNode::getTransform();
Point ScrollViewShadowNode::getContentOriginOffset() const {
auto contentOffset = getStateData().contentOffset;
return transform *
Transform::Translate(-contentOffset.x, -contentOffset.y, 0);
return {-contentOffset.x, -contentOffset.y};
}
} // namespace react
@@ -32,7 +32,7 @@ class ScrollViewShadowNode final : public ConcreteViewShadowNode<
#pragma mark - LayoutableShadowNode
void layout(LayoutContext layoutContext) override;
Transform getTransform() const override;
Point getContentOriginOffset() const override;
private:
void updateStateIfNeeded();
@@ -84,7 +84,7 @@ LayoutMetrics LayoutableShadowNode::computeRelativeLayoutMetrics(
// Step 3.
// Iterating on a list of nodes computing compound offset.
auto size = shadowNodeList.size();
for (int i = 0; i < size; i++) {
for (size_t i = 0; i < size; i++) {
auto currentShadowNode =
traitCast<LayoutableShadowNode const *>(shadowNodeList.at(i));
@@ -104,6 +104,10 @@ LayoutMetrics LayoutableShadowNode::computeRelativeLayoutMetrics(
}
resultFrame.origin += currentFrame.origin;
if (i != 0 && policy.includeTransform) {
resultFrame.origin += currentShadowNode->getContentOriginOffset();
}
}
return layoutMetrics;
@@ -147,6 +151,10 @@ Transform LayoutableShadowNode::getTransform() const {
return Transform::Identity();
}
Point LayoutableShadowNode::getContentOriginOffset() const {
return {0, 0};
}
LayoutMetrics LayoutableShadowNode::getRelativeLayoutMetrics(
LayoutableShadowNode const &ancestorLayoutableShadowNode,
LayoutInspectingPolicy policy) const {
@@ -217,13 +225,15 @@ ShadowNode::Shared LayoutableShadowNode::findNodeAtPoint(
return nullptr;
}
auto frame = layoutableShadowNode->getLayoutMetrics().frame;
auto isPointInside = frame.containsPoint(point);
auto transformedFrame = frame * layoutableShadowNode->getTransform();
auto isPointInside = transformedFrame.containsPoint(point);
if (!isPointInside) {
return nullptr;
}
auto newPoint = point - frame.origin * layoutableShadowNode->getTransform();
auto newPoint = point - transformedFrame.origin -
layoutableShadowNode->getContentOriginOffset();
for (const auto &childShadowNode : node->getChildren()) {
auto hitView = findNodeAtPoint(childShadowNode, newPoint);
if (hitView) {
@@ -115,6 +115,13 @@ class LayoutableShadowNode : public ShadowNode {
*/
virtual Transform getTransform() const;
/*
* Returns offset which is applied to children's origin in
* `LayoutableShadowNode::getRelativeLayoutMetrics` and
* `LayoutableShadowNode::findNodeAtPoint`.
*/
virtual Point getContentOriginOffset() const;
/*
* Returns layout metrics relatively to the given ancestor node.
* Uses `computeRelativeLayoutMetrics()` under the hood.
@@ -10,6 +10,25 @@
using namespace facebook::react;
/*
*┌─────────────────────────┐
*│nodeA_ │
*│ │
*│ │
*│ │
*│ │
*│ │
*│ │
*│ ┌────────────────┐ │
*│ │nodeAA_ │ │
*│ │ │ │
*│ │ ┌───────┐ │ │
*│ │ │nodeAA_│ │ │
*│ │ │ │ │ │
*│ │ └───────┘ │ │
*│ └────────────────┘ │
*└─────────────────────────┘
*/
class FindNodeAtPointTest : public ::testing::Test {
protected:
FindNodeAtPointTest()
@@ -102,21 +121,19 @@ TEST_F(FindNodeAtPointTest, withoutTransform) {
LayoutableShadowNode::findNodeAtPoint(nodeA_, {1001, 1001}), nullptr);
}
// Uncomment once T69368852 is resolved.
// TEST_F(FindNodeAtPointTest, viewIsTranslated) {
// nodeA_->_transform =
// Transform::Identity() * Transform::Translate(-100, -100, 0);
TEST_F(FindNodeAtPointTest, viewIsTranslated) {
nodeA_->_contentOriginOffset = {-100, -100};
// EXPECT_EQ(
// LayoutableShadowNode::findNodeAtPoint(nodeA_, {15, 15})->getTag(),
// nodeAAA_->getTag());
// EXPECT_EQ(LayoutableShadowNode::findNodeAtPoint(nodeA_, {5, 5}), nodeAA_);
// }
EXPECT_EQ(
LayoutableShadowNode::findNodeAtPoint(nodeA_, {15, 15})->getTag(),
nodeAAA_->getTag());
EXPECT_EQ(LayoutableShadowNode::findNodeAtPoint(nodeA_, {5, 5}), nodeAA_);
}
// TEST_F(FindNodeAtPointTest, viewIsScaled) {
// nodeAAA_->_transform = Transform::Identity() * Transform::Scale(0.5, 0.5,
// 0);
TEST_F(FindNodeAtPointTest, viewIsScaled) {
nodeAAA_->_transform = Transform::Identity() * Transform::Scale(0.5, 0.5, 0);
// EXPECT_EQ(LayoutableShadowNode::findNodeAtPoint(nodeA_, {119,
// 119})->getTag(), nodeAA_->getTag());
// }
EXPECT_EQ(
LayoutableShadowNode::findNodeAtPoint(nodeA_, {119, 119})->getTag(),
nodeAA_->getTag());
}
@@ -130,6 +130,35 @@ TEST_F(LayoutableShadowNodeTest, relativeLayoutMetrics) {
EXPECT_EQ(relativeLayoutMetrics.frame.origin.y, 20);
}
/*
* ┌────────┐
* │nodeA_ │
* │ ┌─────┴───┐
* │ │nodeAA_ │
* │ │ │
* └──┤ │
* │ │
* └─────────┘
*/
TEST_F(LayoutableShadowNodeTest, contentOriginOffset) {
auto layoutMetrics = EmptyLayoutMetrics;
layoutMetrics.frame.origin = {10, 20};
layoutMetrics.frame.size = {100, 200};
nodeA_->_contentOriginOffset = {10, 10};
nodeA_->setLayoutMetrics(layoutMetrics);
nodeAA_->setLayoutMetrics(layoutMetrics);
auto relativeLayoutMetrics = nodeAA_->getRelativeLayoutMetrics(*nodeA_, {});
EXPECT_EQ(relativeLayoutMetrics.frame.origin.x, 20);
EXPECT_EQ(relativeLayoutMetrics.frame.origin.y, 30);
relativeLayoutMetrics = nodeAA_->getRelativeLayoutMetrics(*nodeA_, {false});
EXPECT_EQ(relativeLayoutMetrics.frame.origin.x, 10);
EXPECT_EQ(relativeLayoutMetrics.frame.origin.y, 20);
}
/*
* ┌────────────────────────┐
* │nodeA_ │
@@ -149,6 +178,10 @@ TEST_F(LayoutableShadowNodeTest, relativeLayoutMetricsOnTransformedNode) {
nodeAA_->_transform = Transform::Scale(0.5, 0.5, 1);
nodeAA_->setLayoutMetrics(layoutMetrics);
layoutMetrics.frame.origin = {10, 20};
layoutMetrics.frame.size = {50, 100};
nodeAAA_->setLayoutMetrics(layoutMetrics);
auto relativeLayoutMetrics = nodeAA_->getRelativeLayoutMetrics(*nodeA_, {});
EXPECT_EQ(relativeLayoutMetrics.frame.origin.x, 35);
@@ -58,6 +58,12 @@ class TestShadowNode : public ConcreteViewShadowNode<
Transform getTransform() const override {
return _transform;
}
facebook::react::Point _contentOriginOffset{};
facebook::react::Point getContentOriginOffset() const override {
return _contentOriginOffset;
}
};
class TestComponentDescriptor