Compare commits
1 Commits
potato520h
...
export-D70
Author | SHA1 | Date | |
---|---|---|---|
|
7305a5f7c8 |
@@ -1,184 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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 <yoga/Yoga.h>
|
|
||||||
#include <yoga/config/Config.h>
|
|
||||||
#include <yoga/node/Node.h>
|
|
||||||
|
|
||||||
#include <functional>
|
|
||||||
#include <memory>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
namespace facebook::yoga {
|
|
||||||
|
|
||||||
struct YGPersistentNodeCloningTest : public ::testing::Test {
|
|
||||||
struct NodeWrapper {
|
|
||||||
explicit NodeWrapper(
|
|
||||||
YGConfigRef config,
|
|
||||||
std::vector<std::shared_ptr<NodeWrapper>> children = {})
|
|
||||||
: node{YGNodeNewWithConfig(config)}, children{std::move(children)} {
|
|
||||||
YGNodeSetContext(node, this);
|
|
||||||
|
|
||||||
auto privateNode = resolveRef(node);
|
|
||||||
for (const auto& child : this->children) {
|
|
||||||
auto privateChild = resolveRef(child->node);
|
|
||||||
// Claim first ownership of not yet owned nodes, to avoid immediately
|
|
||||||
// cloning them
|
|
||||||
if (YGNodeGetOwner(child->node) == nullptr) {
|
|
||||||
privateChild->setOwner(privateNode);
|
|
||||||
}
|
|
||||||
privateNode->insertChild(privateChild, privateNode->getChildCount());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clone, with current children, for mutation
|
|
||||||
NodeWrapper(const NodeWrapper& other)
|
|
||||||
: node{YGNodeClone(other.node)}, children{other.children} {
|
|
||||||
YGNodeSetContext(node, this);
|
|
||||||
|
|
||||||
auto privateNode = resolveRef(node);
|
|
||||||
privateNode->setOwner(nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clone, with new children
|
|
||||||
NodeWrapper(
|
|
||||||
const NodeWrapper& other,
|
|
||||||
std::vector<std::shared_ptr<NodeWrapper>> children)
|
|
||||||
: node{YGNodeClone(other.node)}, children{std::move(children)} {
|
|
||||||
YGNodeSetContext(node, this);
|
|
||||||
|
|
||||||
auto privateNode = resolveRef(node);
|
|
||||||
privateNode->setOwner(nullptr);
|
|
||||||
privateNode->setChildren({});
|
|
||||||
privateNode->setDirty(true);
|
|
||||||
|
|
||||||
for (const auto& child : this->children) {
|
|
||||||
auto privateChild = resolveRef(child->node);
|
|
||||||
// Claim first ownership of not yet owned nodes, to avoid immediately
|
|
||||||
// cloning them
|
|
||||||
if (YGNodeGetOwner(child->node) == nullptr) {
|
|
||||||
privateChild->setOwner(privateNode);
|
|
||||||
}
|
|
||||||
privateNode->insertChild(privateChild, privateNode->getChildCount());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
NodeWrapper(NodeWrapper&&) = delete;
|
|
||||||
|
|
||||||
~NodeWrapper() {
|
|
||||||
YGNodeFree(node);
|
|
||||||
}
|
|
||||||
|
|
||||||
NodeWrapper& operator=(const NodeWrapper& other) = delete;
|
|
||||||
NodeWrapper& operator=(NodeWrapper&& other) = delete;
|
|
||||||
|
|
||||||
YGNodeRef node;
|
|
||||||
std::vector<std::shared_ptr<NodeWrapper>> children;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ConfigWrapper {
|
|
||||||
ConfigWrapper() {
|
|
||||||
YGConfigSetCloneNodeFunc(
|
|
||||||
config,
|
|
||||||
[](YGNodeConstRef oldNode, YGNodeConstRef owner, size_t childIndex) {
|
|
||||||
onClone(oldNode, owner, childIndex);
|
|
||||||
auto wrapper = static_cast<NodeWrapper*>(YGNodeGetContext(owner));
|
|
||||||
auto old = static_cast<NodeWrapper*>(YGNodeGetContext(oldNode));
|
|
||||||
|
|
||||||
wrapper->children[childIndex] = std::make_shared<NodeWrapper>(*old);
|
|
||||||
return wrapper->children[childIndex]->node;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
ConfigWrapper(const ConfigWrapper&) = delete;
|
|
||||||
ConfigWrapper(ConfigWrapper&&) = delete;
|
|
||||||
|
|
||||||
~ConfigWrapper() {
|
|
||||||
YGConfigFree(config);
|
|
||||||
}
|
|
||||||
|
|
||||||
ConfigWrapper& operator=(const ConfigWrapper&) = delete;
|
|
||||||
ConfigWrapper& operator=(ConfigWrapper&&) = delete;
|
|
||||||
|
|
||||||
YGConfigRef config{YGConfigNew()};
|
|
||||||
};
|
|
||||||
|
|
||||||
ConfigWrapper configWrapper;
|
|
||||||
YGConfigRef config{configWrapper.config};
|
|
||||||
|
|
||||||
void SetUp() override {
|
|
||||||
onClone = [](...) {};
|
|
||||||
}
|
|
||||||
|
|
||||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
|
||||||
static inline std::function<void(YGNodeConstRef, YGNodeConstRef, size_t)>
|
|
||||||
onClone;
|
|
||||||
};
|
|
||||||
|
|
||||||
TEST_F(
|
|
||||||
YGPersistentNodeCloningTest,
|
|
||||||
changing_sibling_height_does_not_clone_neighbors) {
|
|
||||||
// <ScrollView>
|
|
||||||
// <View id="Sibling" style={{ height: 1 }} />
|
|
||||||
// <View id="A" style={{ height: 1 }}>
|
|
||||||
// <View id="B">
|
|
||||||
// <View id="C">
|
|
||||||
// <View id="D"/>
|
|
||||||
// </View>
|
|
||||||
// </View>
|
|
||||||
// </View>
|
|
||||||
// </ScrollView>
|
|
||||||
|
|
||||||
auto sibling = std::make_shared<NodeWrapper>(config);
|
|
||||||
YGNodeStyleSetHeight(sibling->node, 1);
|
|
||||||
|
|
||||||
auto d = std::make_shared<NodeWrapper>(config);
|
|
||||||
auto c = std::make_shared<NodeWrapper>(config, std::vector{d});
|
|
||||||
auto b = std::make_shared<NodeWrapper>(config, std::vector{c});
|
|
||||||
auto a = std::make_shared<NodeWrapper>(config, std::vector{b});
|
|
||||||
YGNodeStyleSetHeight(a->node, 1);
|
|
||||||
|
|
||||||
auto scrollContentView =
|
|
||||||
std::make_shared<NodeWrapper>(config, std::vector{sibling, a});
|
|
||||||
YGNodeStyleSetPositionType(scrollContentView->node, YGPositionTypeAbsolute);
|
|
||||||
|
|
||||||
auto scrollView =
|
|
||||||
std::make_shared<NodeWrapper>(config, std::vector{scrollContentView});
|
|
||||||
YGNodeStyleSetWidth(scrollView->node, 100);
|
|
||||||
YGNodeStyleSetHeight(scrollView->node, 100);
|
|
||||||
|
|
||||||
// We don't expect any cloning during the first layout
|
|
||||||
onClone = [](...) { FAIL(); };
|
|
||||||
|
|
||||||
YGNodeCalculateLayout(
|
|
||||||
scrollView->node, YGUndefined, YGUndefined, YGDirectionLTR);
|
|
||||||
|
|
||||||
auto siblingPrime = std::make_shared<NodeWrapper>(config);
|
|
||||||
YGNodeStyleSetHeight(siblingPrime->node, 2);
|
|
||||||
|
|
||||||
auto scrollContentViewPrime = std::make_shared<NodeWrapper>(
|
|
||||||
*scrollContentView, std::vector{siblingPrime, a});
|
|
||||||
auto scrollViewPrime = std::make_shared<NodeWrapper>(
|
|
||||||
*scrollView, std::vector{scrollContentViewPrime});
|
|
||||||
|
|
||||||
std::vector<NodeWrapper*> nodesCloned;
|
|
||||||
// We should only need to clone "A"
|
|
||||||
onClone = [&](YGNodeConstRef oldNode,
|
|
||||||
YGNodeConstRef /*owner*/,
|
|
||||||
size_t /*childIndex*/) {
|
|
||||||
nodesCloned.push_back(static_cast<NodeWrapper*>(YGNodeGetContext(oldNode)));
|
|
||||||
};
|
|
||||||
|
|
||||||
YGNodeCalculateLayout(
|
|
||||||
scrollViewPrime->node, YGUndefined, YGUndefined, YGDirectionLTR);
|
|
||||||
|
|
||||||
EXPECT_EQ(nodesCloned.size(), 1);
|
|
||||||
EXPECT_EQ(nodesCloned[0], a.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace facebook::yoga
|
|
@@ -161,23 +161,3 @@ TEST(YogaTest, per_node_point_scale_factor) {
|
|||||||
YGConfigFree(config2);
|
YGConfigFree(config2);
|
||||||
YGConfigFree(config3);
|
YGConfigFree(config3);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(YogaTest, raw_layout_dimensions) {
|
|
||||||
YGConfigRef config = YGConfigNew();
|
|
||||||
YGConfigSetPointScaleFactor(config, 0.5f);
|
|
||||||
|
|
||||||
YGNodeRef root = YGNodeNewWithConfig(config);
|
|
||||||
YGNodeStyleSetWidth(root, 11.5f);
|
|
||||||
YGNodeStyleSetHeight(root, 9.5f);
|
|
||||||
|
|
||||||
YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
|
|
||||||
|
|
||||||
ASSERT_EQ(YGNodeLayoutGetWidth(root), 12.0f);
|
|
||||||
ASSERT_EQ(YGNodeLayoutGetHeight(root), 10.0f);
|
|
||||||
ASSERT_EQ(YGNodeLayoutGetRawWidth(root), 11.5f);
|
|
||||||
ASSERT_EQ(YGNodeLayoutGetRawHeight(root), 9.5f);
|
|
||||||
|
|
||||||
YGNodeFreeRecursive(root);
|
|
||||||
|
|
||||||
YGConfigFree(config);
|
|
||||||
}
|
|
||||||
|
@@ -17,15 +17,15 @@ has effect when items are wrapped to multiple lines using [flex wrap](/docs/styl
|
|||||||
|
|
||||||
**Center**: Align wrapped lines in the center of the container's cross axis.
|
**Center**: Align wrapped lines in the center of the container's cross axis.
|
||||||
|
|
||||||
**Space between**: Evenly space wrapped lines across the container's cross axis, distributing
|
**Space between**: Evenly space wrapped lines across the container's main axis, distributing
|
||||||
remaining space between the lines.
|
remaining space between the lines.
|
||||||
|
|
||||||
**Space around**: Evenly space wrapped lines across the container's cross axis, distributing
|
**Space around**: Evenly space wrapped lines across the container's main axis, distributing
|
||||||
remaining space around the lines. Compared to space between using
|
remaining space around the lines. Compared to space between using
|
||||||
space around will result in space being distributed to the beginning of
|
space around will result in space being distributed to the beginning of
|
||||||
the first lines and end of the last line.
|
the first lines and end of the last line.
|
||||||
|
|
||||||
**Space evenly**: Evenly space wrapped lines across the container's cross axis, distributing
|
**Space evenly**: Evenly space wrapped lines across the container's main axis, distributing
|
||||||
remaining space around the lines. Compared to space around, space evenly will not
|
remaining space around the lines. Compared to space around, space evenly will not
|
||||||
double the gaps between children. The size of gaps between children and between
|
double the gaps between children. The size of gaps between children and between
|
||||||
the parent's edges and the first/last child will all be equal.
|
the parent's edges and the first/last child will all be equal.
|
||||||
|
@@ -90,11 +90,3 @@ float YGNodeLayoutGetPadding(YGNodeConstRef node, YGEdge edge) {
|
|||||||
return getResolvedLayoutProperty<&LayoutResults::padding>(
|
return getResolvedLayoutProperty<&LayoutResults::padding>(
|
||||||
node, scopedEnum(edge));
|
node, scopedEnum(edge));
|
||||||
}
|
}
|
||||||
|
|
||||||
float YGNodeLayoutGetRawHeight(YGNodeConstRef node) {
|
|
||||||
return resolveRef(node)->getLayout().rawDimension(Dimension::Height);
|
|
||||||
}
|
|
||||||
|
|
||||||
float YGNodeLayoutGetRawWidth(YGNodeConstRef node) {
|
|
||||||
return resolveRef(node)->getLayout().rawDimension(Dimension::Width);
|
|
||||||
}
|
|
||||||
|
@@ -32,14 +32,4 @@ YG_EXPORT float YGNodeLayoutGetMargin(YGNodeConstRef node, YGEdge edge);
|
|||||||
YG_EXPORT float YGNodeLayoutGetBorder(YGNodeConstRef node, YGEdge edge);
|
YG_EXPORT float YGNodeLayoutGetBorder(YGNodeConstRef node, YGEdge edge);
|
||||||
YG_EXPORT float YGNodeLayoutGetPadding(YGNodeConstRef node, YGEdge edge);
|
YG_EXPORT float YGNodeLayoutGetPadding(YGNodeConstRef node, YGEdge edge);
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the measured height of the node, before layout rounding
|
|
||||||
*/
|
|
||||||
YG_EXPORT float YGNodeLayoutGetRawHeight(YGNodeConstRef node);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the measured width of the node, before layout rounding
|
|
||||||
*/
|
|
||||||
YG_EXPORT float YGNodeLayoutGetRawWidth(YGNodeConstRef node);
|
|
||||||
|
|
||||||
YG_EXTERN_C_END
|
YG_EXTERN_C_END
|
||||||
|
@@ -106,25 +106,25 @@ void roundLayoutResultsToPixelGrid(
|
|||||||
const bool hasFractionalHeight =
|
const bool hasFractionalHeight =
|
||||||
!yoga::inexactEquals(round(scaledNodeHeight), scaledNodeHeight);
|
!yoga::inexactEquals(round(scaledNodeHeight), scaledNodeHeight);
|
||||||
|
|
||||||
node->getLayout().setDimension(
|
node->setLayoutDimension(
|
||||||
Dimension::Width,
|
|
||||||
roundValueToPixelGrid(
|
roundValueToPixelGrid(
|
||||||
absoluteNodeRight,
|
absoluteNodeRight,
|
||||||
pointScaleFactor,
|
pointScaleFactor,
|
||||||
(textRounding && hasFractionalWidth),
|
(textRounding && hasFractionalWidth),
|
||||||
(textRounding && !hasFractionalWidth)) -
|
(textRounding && !hasFractionalWidth)) -
|
||||||
roundValueToPixelGrid(
|
roundValueToPixelGrid(
|
||||||
absoluteNodeLeft, pointScaleFactor, false, textRounding));
|
absoluteNodeLeft, pointScaleFactor, false, textRounding),
|
||||||
|
Dimension::Width);
|
||||||
|
|
||||||
node->getLayout().setDimension(
|
node->setLayoutDimension(
|
||||||
Dimension::Height,
|
|
||||||
roundValueToPixelGrid(
|
roundValueToPixelGrid(
|
||||||
absoluteNodeBottom,
|
absoluteNodeBottom,
|
||||||
pointScaleFactor,
|
pointScaleFactor,
|
||||||
(textRounding && hasFractionalHeight),
|
(textRounding && hasFractionalHeight),
|
||||||
(textRounding && !hasFractionalHeight)) -
|
(textRounding && !hasFractionalHeight)) -
|
||||||
roundValueToPixelGrid(
|
roundValueToPixelGrid(
|
||||||
absoluteNodeTop, pointScaleFactor, false, textRounding));
|
absoluteNodeTop, pointScaleFactor, false, textRounding),
|
||||||
|
Dimension::Height);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (yoga::Node* child : node->getChildren()) {
|
for (yoga::Node* child : node->getChildren()) {
|
||||||
|
@@ -27,7 +27,7 @@ enum class SizingMode {
|
|||||||
StretchFit,
|
StretchFit,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A box's "ideal" size in a given axis when given infinite available space.
|
* A box’s “ideal” size in a given axis when given infinite available space.
|
||||||
* Usually this is the smallest size the box could take in that axis while
|
* Usually this is the smallest size the box could take in that axis while
|
||||||
* still fitting around its contents, i.e. minimizing unfilled space while
|
* still fitting around its contents, i.e. minimizing unfilled space while
|
||||||
* avoiding overflow.
|
* avoiding overflow.
|
||||||
|
@@ -19,7 +19,6 @@ namespace facebook::yoga {
|
|||||||
#if defined(__cpp_exceptions)
|
#if defined(__cpp_exceptions)
|
||||||
throw std::logic_error(message);
|
throw std::logic_error(message);
|
||||||
#else
|
#else
|
||||||
static_cast<void>(message); // Unused
|
|
||||||
std::terminate();
|
std::terminate();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@@ -36,12 +36,12 @@ enum struct LayoutPassReason : int {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct LayoutData {
|
struct LayoutData {
|
||||||
int layouts = 0;
|
int layouts;
|
||||||
int measures = 0;
|
int measures;
|
||||||
uint32_t maxMeasureCache = 0;
|
uint32_t maxMeasureCache;
|
||||||
int cachedLayouts = 0;
|
int cachedLayouts;
|
||||||
int cachedMeasures = 0;
|
int cachedMeasures;
|
||||||
int measureCallbacks = 0;
|
int measureCallbacks;
|
||||||
std::array<int, static_cast<uint8_t>(LayoutPassReason::COUNT)>
|
std::array<int, static_cast<uint8_t>(LayoutPassReason::COUNT)>
|
||||||
measureCallbackReasonsCount;
|
measureCallbackReasonsCount;
|
||||||
};
|
};
|
||||||
|
@@ -66,18 +66,10 @@ struct LayoutResults {
|
|||||||
return measuredDimensions_[yoga::to_underlying(axis)];
|
return measuredDimensions_[yoga::to_underlying(axis)];
|
||||||
}
|
}
|
||||||
|
|
||||||
float rawDimension(Dimension axis) const {
|
|
||||||
return rawDimensions_[yoga::to_underlying(axis)];
|
|
||||||
}
|
|
||||||
|
|
||||||
void setMeasuredDimension(Dimension axis, float dimension) {
|
void setMeasuredDimension(Dimension axis, float dimension) {
|
||||||
measuredDimensions_[yoga::to_underlying(axis)] = dimension;
|
measuredDimensions_[yoga::to_underlying(axis)] = dimension;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setRawDimension(Dimension axis, float dimension) {
|
|
||||||
rawDimensions_[yoga::to_underlying(axis)] = dimension;
|
|
||||||
}
|
|
||||||
|
|
||||||
float position(PhysicalEdge physicalEdge) const {
|
float position(PhysicalEdge physicalEdge) const {
|
||||||
return position_[yoga::to_underlying(physicalEdge)];
|
return position_[yoga::to_underlying(physicalEdge)];
|
||||||
}
|
}
|
||||||
@@ -121,7 +113,6 @@ struct LayoutResults {
|
|||||||
|
|
||||||
std::array<float, 2> dimensions_ = {{YGUndefined, YGUndefined}};
|
std::array<float, 2> dimensions_ = {{YGUndefined, YGUndefined}};
|
||||||
std::array<float, 2> measuredDimensions_ = {{YGUndefined, YGUndefined}};
|
std::array<float, 2> measuredDimensions_ = {{YGUndefined, YGUndefined}};
|
||||||
std::array<float, 2> rawDimensions_ = {{YGUndefined, YGUndefined}};
|
|
||||||
std::array<float, 4> position_ = {};
|
std::array<float, 4> position_ = {};
|
||||||
std::array<float, 4> margin_ = {};
|
std::array<float, 4> margin_ = {};
|
||||||
std::array<float, 4> border_ = {};
|
std::array<float, 4> border_ = {};
|
||||||
|
@@ -247,7 +247,6 @@ void Node::setLayoutHadOverflow(bool hadOverflow) {
|
|||||||
|
|
||||||
void Node::setLayoutDimension(float lengthValue, Dimension dimension) {
|
void Node::setLayoutDimension(float lengthValue, Dimension dimension) {
|
||||||
layout_.setDimension(dimension, lengthValue);
|
layout_.setDimension(dimension, lengthValue);
|
||||||
layout_.setRawDimension(dimension, lengthValue);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If both left and right are defined, then use left. Otherwise return +left or
|
// If both left and right are defined, then use left. Otherwise return +left or
|
||||||
|
Reference in New Issue
Block a user