Files
react-native/ReactCommon/react/renderer/components/view/tests/LayoutTest.cpp
T
Andrei Shikov 1953f6f02e Exclude raw props from view shadow nodes
Summary:
With the `MapBuffer`-based props calculated from C++ props, there's no need to keep `rawProps` around for Android views.

This change makes sure that the `rawProps` field is only initialized under the feature flag that is responsible for enabling `MapBuffer` for prop diffing, potentially decreasing memory footprint and speeding up node initialization as JS props don't have to be converted to `folly::dynamic` anymore.

For layout animations, props rely on C++ values, so there's no need to update `rawProps` values either.

Changelog: [Internal][Android] - Do not init `rawProps` when mapbuffer serialization is used for ViewProps.

Reviewed By: mdvacca

Differential Revision: D33793044

fbshipit-source-id: 35873b10d3ca8b152b25344ef2c27aff9641846f
2022-02-22 17:23:05 -08:00

187 lines
9.1 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.
*/
#include <gtest/gtest.h>
#include <react/renderer/componentregistry/ComponentDescriptorProviderRegistry.h>
#include <react/renderer/components/root/RootComponentDescriptor.h>
#include <react/renderer/components/view/ViewComponentDescriptor.h>
#include <react/renderer/element/ComponentBuilder.h>
#include <react/renderer/element/Element.h>
#include <react/renderer/element/testUtils.h>
namespace facebook {
namespace react {
// *******************************************************┌─ABCD:────┐****
// *******************************************************│ {70,-50} │****
// *******************************************************│ {30,60} │****
// *******************************************************│ │****
// *******************************************************│ │****
// *******************┌─A: {0,0}{50,50}──┐****************│ │****
// *******************│ │****************│ │****
// *******************│ ┌─AB:──────┐ │****************│ │****
// *******************│ │ {10,10}{30,90}****************│ │****
// *******************│ │ ┌─ABC: {10,10}{110,20}──────┤ ├───┐
// *******************│ │ │ │ │ │
// *******************│ │ │ └──────────┘ │
// *******************│ │ └──────┬───┬───────────────────────────────┘
// *******************│ │ │ │********************************
// *******************└───┤ ├───┘********************************
// ***********************│ │************************************
// ***********************│ │************************************
// ┌─ABE: {-60,50}{70,20}─┴───┐ │************************************
// │ │ │************************************
// │ │ │************************************
// │ │ │************************************
// │ │ │************************************
// └──────────────────────┬───┘ │************************************
// ***********************│ │************************************
// ***********************└──────────┘************************************
class LayoutTest : public ::testing::Test {
protected:
ComponentBuilder builder_;
std::shared_ptr<RootShadowNode> rootShadowNode_;
std::shared_ptr<ViewShadowNode> viewShadowNodeA_;
std::shared_ptr<ViewShadowNode> viewShadowNodeAB_;
std::shared_ptr<ViewShadowNode> viewShadowNodeABC_;
std::shared_ptr<ViewShadowNode> viewShadowNodeABCD_;
std::shared_ptr<ViewShadowNode> viewShadowNodeABE_;
LayoutTest() : builder_(simpleComponentBuilder()) {}
void initialize(bool enforceClippingForABC) {
// clang-format off
auto element =
Element<RootShadowNode>()
.reference(rootShadowNode_)
.tag(1)
.props([] {
auto sharedProps = std::make_shared<RootProps>();
auto &props = *sharedProps;
props.layoutConstraints = LayoutConstraints{{0,0}, {500, 500}};
auto &yogaStyle = props.yogaStyle;
yogaStyle.dimensions()[YGDimensionWidth] = YGValue{200, YGUnitPoint};
yogaStyle.dimensions()[YGDimensionHeight] = YGValue{200, YGUnitPoint};
return sharedProps;
})
.children({
Element<ViewShadowNode>()
.reference(viewShadowNodeA_)
.props([] {
auto sharedProps = std::make_shared<ViewShadowNodeProps>();
auto &props = *sharedProps;
auto &yogaStyle = props.yogaStyle;
yogaStyle.positionType() = YGPositionTypeAbsolute;
yogaStyle.dimensions()[YGDimensionWidth] = YGValue{50, YGUnitPoint};
yogaStyle.dimensions()[YGDimensionHeight] = YGValue{50, YGUnitPoint};
return sharedProps;
})
.children({
Element<ViewShadowNode>()
.reference(viewShadowNodeAB_)
.props([] {
auto sharedProps = std::make_shared<ViewShadowNodeProps>();
auto &props = *sharedProps;
auto &yogaStyle = props.yogaStyle;
yogaStyle.positionType() = YGPositionTypeAbsolute;
yogaStyle.position()[YGEdgeLeft] = YGValue{10, YGUnitPoint};
yogaStyle.position()[YGEdgeTop] = YGValue{10, YGUnitPoint};
yogaStyle.dimensions()[YGDimensionWidth] = YGValue{30, YGUnitPoint};
yogaStyle.dimensions()[YGDimensionHeight] = YGValue{90, YGUnitPoint};
return sharedProps;
})
.children({
Element<ViewShadowNode>()
.reference(viewShadowNodeABC_)
.props([=] {
auto sharedProps = std::make_shared<ViewShadowNodeProps>();
auto &props = *sharedProps;
auto &yogaStyle = props.yogaStyle;
if (enforceClippingForABC) {
yogaStyle.overflow() = YGOverflowHidden;
}
yogaStyle.positionType() = YGPositionTypeAbsolute;
yogaStyle.position()[YGEdgeLeft] = YGValue{10, YGUnitPoint};
yogaStyle.position()[YGEdgeTop] = YGValue{10, YGUnitPoint};
yogaStyle.dimensions()[YGDimensionWidth] = YGValue{110, YGUnitPoint};
yogaStyle.dimensions()[YGDimensionHeight] = YGValue{20, YGUnitPoint};
return sharedProps;
})
.children({
Element<ViewShadowNode>()
.reference(viewShadowNodeABCD_)
.props([] {
auto sharedProps = std::make_shared<ViewShadowNodeProps>();
auto &props = *sharedProps;
auto &yogaStyle = props.yogaStyle;
yogaStyle.positionType() = YGPositionTypeAbsolute;
yogaStyle.position()[YGEdgeLeft] = YGValue{70, YGUnitPoint};
yogaStyle.position()[YGEdgeTop] = YGValue{-50, YGUnitPoint};
yogaStyle.dimensions()[YGDimensionWidth] = YGValue{30, YGUnitPoint};
yogaStyle.dimensions()[YGDimensionHeight] = YGValue{60, YGUnitPoint};
return sharedProps;
})
}),
Element<ViewShadowNode>()
.reference(viewShadowNodeABE_)
.props([] {
auto sharedProps = std::make_shared<ViewShadowNodeProps>();
auto &props = *sharedProps;
auto &yogaStyle = props.yogaStyle;
yogaStyle.positionType() = YGPositionTypeAbsolute;
yogaStyle.position()[YGEdgeLeft] = YGValue{-60, YGUnitPoint};
yogaStyle.position()[YGEdgeTop] = YGValue{50, YGUnitPoint};
yogaStyle.dimensions()[YGDimensionWidth] = YGValue{70, YGUnitPoint};
yogaStyle.dimensions()[YGDimensionHeight] = YGValue{20, YGUnitPoint};
return sharedProps;
})
})
})
});
// clang-format on
builder_.build(element);
rootShadowNode_->layoutIfNeeded();
}
};
TEST_F(LayoutTest, overflowInsetTest) {
initialize(false);
auto layoutMetrics = viewShadowNodeA_->getLayoutMetrics();
EXPECT_EQ(layoutMetrics.frame.size.width, 50);
EXPECT_EQ(layoutMetrics.frame.size.height, 50);
EXPECT_EQ(layoutMetrics.overflowInset.left, -50);
EXPECT_EQ(layoutMetrics.overflowInset.top, -30);
EXPECT_EQ(layoutMetrics.overflowInset.right, -80);
EXPECT_EQ(layoutMetrics.overflowInset.bottom, -50);
}
TEST_F(LayoutTest, overflowInsetWithClippingTest) {
initialize(true);
auto layoutMetrics = viewShadowNodeA_->getLayoutMetrics();
EXPECT_EQ(layoutMetrics.frame.size.width, 50);
EXPECT_EQ(layoutMetrics.frame.size.height, 50);
EXPECT_EQ(layoutMetrics.overflowInset.left, -50);
EXPECT_EQ(layoutMetrics.overflowInset.top, 0);
EXPECT_EQ(layoutMetrics.overflowInset.right, -80);
EXPECT_EQ(layoutMetrics.overflowInset.bottom, -50);
}
} // namespace react
} // namespace facebook