Skip to content

Commit 0908777

Browse files
committed
Fix display: contents nodes not being cloned with the wrong owner
1 parent 73980a3 commit 0908777

4 files changed

Lines changed: 80 additions & 14 deletions

File tree

tests/YGPersistentNodeCloningTest.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,4 +181,38 @@ TEST_F(
181181
EXPECT_EQ(nodesCloned[0], a.get());
182182
}
183183

184+
TEST_F(
185+
YGPersistentNodeCloningTest,
186+
clone_leaf_display_contents_node) {
187+
// <View id="A">
188+
// <View id="B" style={{ display: 'contents' }} />
189+
// </View>
190+
191+
auto b = std::make_shared<NodeWrapper>(config);
192+
auto a = std::make_shared<NodeWrapper>(config, std::vector{b});
193+
YGNodeStyleSetDisplay(b->node, YGDisplayContents);
194+
195+
// We don't expect any cloning during the first layout
196+
onClone = [](...) { FAIL(); };
197+
198+
YGNodeCalculateLayout(
199+
a->node, YGUndefined, YGUndefined, YGDirectionLTR);
200+
201+
auto aPrime = std::make_shared<NodeWrapper>(config, std::vector{b});
202+
203+
std::vector<NodeWrapper*> nodesCloned;
204+
// We should clone "C"
205+
onClone = [&](YGNodeConstRef oldNode,
206+
YGNodeConstRef /*owner*/,
207+
size_t /*childIndex*/) {
208+
nodesCloned.push_back(static_cast<NodeWrapper*>(YGNodeGetContext(oldNode)));
209+
};
210+
211+
YGNodeCalculateLayout(
212+
aPrime->node, 100, 100, YGDirectionLTR);
213+
214+
EXPECT_EQ(nodesCloned.size(), 1);
215+
EXPECT_EQ(nodesCloned[0], b.get());
216+
}
217+
184218
} // namespace facebook::yoga

yoga/algorithm/CalculateLayout.cpp

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -478,16 +478,19 @@ static void zeroOutLayoutRecursively(yoga::Node* const node) {
478478
}
479479

480480
static void cleanupContentsNodesRecursively(yoga::Node* const node) {
481-
for (auto child : node->getChildren()) {
482-
if (child->style().display() == Display::Contents) {
483-
child->getLayout() = {};
484-
child->setLayoutDimension(0, Dimension::Width);
485-
child->setLayoutDimension(0, Dimension::Height);
486-
child->setHasNewLayout(true);
487-
child->setDirty(false);
488-
child->cloneChildrenIfNeeded();
489-
490-
cleanupContentsNodesRecursively(child);
481+
if (node->hasContentsChildren()) [[unlikely]] {
482+
node->cloneContentsChildrenIfNeeded();
483+
for (auto child : node->getChildren()) {
484+
if (child->style().display() == Display::Contents) {
485+
child->getLayout() = {};
486+
child->setLayoutDimension(0, Dimension::Width);
487+
child->setLayoutDimension(0, Dimension::Height);
488+
child->setHasNewLayout(true);
489+
child->setDirty(false);
490+
child->cloneChildrenIfNeeded();
491+
492+
cleanupContentsNodesRecursively(child);
493+
}
491494
}
492495
}
493496
}

yoga/node/Node.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,17 @@ void Node::setDirty(bool isDirty) {
181181
}
182182
}
183183

184+
void Node::setChildren(const std::vector<Node*>& children) {
185+
children_ = children;
186+
187+
contentsChildrenCount_ = 0;
188+
for (const auto &child : children) {
189+
if (child->style().display() == Display::Contents) {
190+
contentsChildrenCount_++;
191+
}
192+
}
193+
}
194+
184195
bool Node::removeChild(Node* child) {
185196
auto p = std::find(children_.begin(), children_.end(), child);
186197
if (p != children_.end()) {
@@ -380,6 +391,22 @@ void Node::cloneChildrenIfNeeded() {
380391
if (child->getOwner() != this) {
381392
child = resolveRef(config_->cloneNode(child, this, i));
382393
child->setOwner(this);
394+
395+
if (child->hasContentsChildren()) [[unlikely]] {
396+
child->cloneContentsChildrenIfNeeded();
397+
}
398+
}
399+
i += 1;
400+
}
401+
}
402+
403+
void Node::cloneContentsChildrenIfNeeded() {
404+
size_t i = 0;
405+
for (Node*& child : children_) {
406+
if (child->style().display() == Display::Contents && child->getOwner() != this) {
407+
child = resolveRef(config_->cloneNode(child, this, i));
408+
child->setOwner(this);
409+
child->cloneChildrenIfNeeded();
383410
}
384411
i += 1;
385412
}

yoga/node/Node.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,10 @@ class YG_EXPORT Node : public ::YGNode {
9696
return config_->hasErrata(errata);
9797
}
9898

99+
bool hasContentsChildren() const {
100+
return contentsChildrenCount_ != 0;
101+
}
102+
99103
YGDirtiedFunc getDirtiedFunc() const {
100104
return dirtiedFunc_;
101105
}
@@ -244,15 +248,12 @@ class YG_EXPORT Node : public ::YGNode {
244248
owner_ = owner;
245249
}
246250

247-
void setChildren(const std::vector<Node*>& children) {
248-
children_ = children;
249-
}
250-
251251
// TODO: rvalue override for setChildren
252252

253253
void setConfig(Config* config);
254254

255255
void setDirty(bool isDirty);
256+
void setChildren(const std::vector<Node*>& children);
256257
void setLayoutLastOwnerDirection(Direction direction);
257258
void setLayoutComputedFlexBasis(FloatOptional computedFlexBasis);
258259
void setLayoutComputedFlexBasisGeneration(
@@ -286,6 +287,7 @@ class YG_EXPORT Node : public ::YGNode {
286287
void removeChild(size_t index);
287288

288289
void cloneChildrenIfNeeded();
290+
void cloneContentsChildrenIfNeeded();
289291
void markDirtyAndPropagate();
290292
float resolveFlexGrow() const;
291293
float resolveFlexShrink() const;

0 commit comments

Comments
 (0)