diff --git a/ReactCommon/yoga/yoga/YGNode.cpp b/ReactCommon/yoga/yoga/YGNode.cpp index 14c072fb1a120e..f76a1cb6d4cbc3 100644 --- a/ReactCommon/yoga/yoga/YGNode.cpp +++ b/ReactCommon/yoga/yoga/YGNode.cpp @@ -155,6 +155,10 @@ void YGNode::replaceChild(YGNodeRef child, uint32_t index) { children_[index] = child; } +void YGNode::replaceChild(YGNodeRef oldChild, YGNodeRef newChild) { + std::replace(children_.begin(), children_.end(), oldChild, newChild); +} + void YGNode::insertChild(YGNodeRef child, uint32_t index) { children_.insert(children_.begin() + index, child); } @@ -375,21 +379,33 @@ YGNode::~YGNode() { // deallocate here } -const YGNode& YGNode::defaultValue() { - static const YGNode n = {nullptr, - nullptr, - true, - YGNodeTypeDefault, - nullptr, - nullptr, - gYGNodeStyleDefaults, - gYGNodeLayoutDefaults, - 0, - nullptr, - YGVector(), - nullptr, - nullptr, - false, - {{YGValueUndefined, YGValueUndefined}}}; - return n; +void YGNode::cloneChildrenIfNeeded() { + // YGNodeRemoveChild in yoga.cpp has a forked variant of this algorithm + // optimized for deletions. + + const uint32_t childCount = children_.size(); + if (childCount == 0) { + // This is an empty set. Nothing to clone. + return; + } + + const YGNodeRef firstChild = children_.front(); + if (firstChild->getParent() == this) { + // If the first child has this node as its parent, we assume that it is + // already unique. We can do this because if we have it has a child, that + // means that its parent was at some point cloned which made that subtree + // immutable. We also assume that all its sibling are cloned as well. + return; + } + + const YGNodeClonedFunc cloneNodeCallback = config_->cloneNodeCallback; + for (uint32_t i = 0; i < childCount; ++i) { + const YGNodeRef oldChild = children_[i]; + const YGNodeRef newChild = YGNodeClone(oldChild); + replaceChild(newChild, i); + newChild->setParent(this); + if (cloneNodeCallback) { + cloneNodeCallback(oldChild, newChild, this, i); + } + } } diff --git a/ReactCommon/yoga/yoga/YGNode.h b/ReactCommon/yoga/yoga/YGNode.h index 4e76b35b2924ac..52337dda90f8f2 100644 --- a/ReactCommon/yoga/yoga/YGNode.h +++ b/ReactCommon/yoga/yoga/YGNode.h @@ -106,6 +106,8 @@ struct YGNode { YGValue resolveFlexBasisPtr() const; void resolveDimension(); void clearChildren(); + /// Replaces the occurrences of oldChild with newChild + void replaceChild(YGNodeRef oldChild, YGNodeRef newChild); void replaceChild(YGNodeRef child, uint32_t index); void insertChild(YGNodeRef child, uint32_t index); /// Removes the first occurrence of child @@ -117,6 +119,6 @@ struct YGNode { void setLayoutPadding(float padding, int index); void setLayoutPosition(float position, int index); - // Static methods - static const YGNode& defaultValue(); + // Other methods + void cloneChildrenIfNeeded(); }; diff --git a/ReactCommon/yoga/yoga/Yoga.cpp b/ReactCommon/yoga/yoga/Yoga.cpp index 6f6b2f6f0d7a2d..9712e65c8b791d 100644 --- a/ReactCommon/yoga/yoga/Yoga.cpp +++ b/ReactCommon/yoga/yoga/Yoga.cpp @@ -348,36 +348,6 @@ static void YGNodeMarkDirtyInternal(const YGNodeRef node) { } } -static void YGCloneChildrenIfNeeded(const YGNodeRef parent) { - // YGNodeRemoveChild has a forked variant of this algorithm optimized for deletions. - const uint32_t childCount = YGNodeGetChildCount(parent); - if (childCount == 0) { - // This is an empty set. Nothing to clone. - return; - } - - const YGNodeRef firstChild = YGNodeGetChild(parent, 0); - if (firstChild->getParent() == parent) { - // If the first child has this node as its parent, we assume that it is already unique. - // We can do this because if we have it has a child, that means that its parent was at some - // point cloned which made that subtree immutable. - // We also assume that all its sibling are cloned as well. - return; - } - - const YGNodeClonedFunc cloneNodeCallback = - parent->getConfig()->cloneNodeCallback; - for (uint32_t i = 0; i < childCount; i++) { - const YGNodeRef oldChild = parent->getChild(i); - const YGNodeRef newChild = YGNodeClone(oldChild); - parent->replaceChild(newChild, i); - newChild->setParent(parent); - if (cloneNodeCallback) { - cloneNodeCallback(oldChild, newChild, parent, i); - } - } -} - void YGNodeInsertChild(const YGNodeRef node, const YGNodeRef child, const uint32_t index) { YGAssertWithNode( node, @@ -388,14 +358,15 @@ void YGNodeInsertChild(const YGNodeRef node, const YGNodeRef child, const uint32 node->getMeasure() == nullptr, "Cannot add child: Nodes with measure functions cannot have children."); - YGCloneChildrenIfNeeded(node); + node->cloneChildrenIfNeeded(); node->insertChild(child, index); child->setParent(node); YGNodeMarkDirtyInternal(node); } void YGNodeRemoveChild(const YGNodeRef parent, const YGNodeRef excludedChild) { - // This algorithm is a forked variant from YGCloneChildrenIfNeeded that excludes a child. + // This algorithm is a forked variant from cloneChildrenIfNeeded in YGNode + // that excludes a child. const uint32_t childCount = YGNodeGetChildCount(parent); if (childCount == 0) { @@ -1805,7 +1776,7 @@ static bool YGNodeFixedSizeSetMeasuredDimensions(const YGNodeRef node, static void YGZeroOutLayoutRecursivly(const YGNodeRef node) { memset(&(node->getLayout()), 0, sizeof(YGLayout)); node->setHasNewLayout(true); - YGCloneChildrenIfNeeded(node); + node->cloneChildrenIfNeeded(); const uint32_t childCount = YGNodeGetChildCount(node); for (uint32_t i = 0; i < childCount; i++) { const YGNodeRef child = node->getChild(i); @@ -1993,8 +1964,7 @@ static void YGNodelayoutImpl(const YGNodeRef node, } // At this point we know we're going to perform work. Ensure that each child has a mutable copy. - YGCloneChildrenIfNeeded(node); - + node->cloneChildrenIfNeeded(); // Reset layout flags, as they could have changed. node->setLayoutHadOverflow(false);