Fix YGNodeSetConfig causing excessive dirtying (#37316)

Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/37316

In Fabric, a ShadowNode may re-initialize YGConfig several times throughout the lifetime of a perpetually cloned Yoga Node.

RN sets `pointScaleFactor` lazily, when laying out the rootview. So right now it initializes a config to `pointScaleFactor` of 1.0, sets it, sets a new `pointScaleFactor` on the config, then repeats. This cycles the config between two `pointScaleFactor` values and will excessively dirty the node now that `YGNodeSetConfig` dirties on config change (D45505089)

This change makes it so that we retain previously used `pointScaleFactor` when cloning the Yoga nodes.

Changelog: [Internal]

Reviewed By: rozele

Differential Revision: D45669878

fbshipit-source-id: bfd2e185d9264a1cda64e59132960060385e16f1
This commit is contained in:
Nick Gerleman
2023-05-08 16:30:06 -07:00
committed by Facebook GitHub Bot
parent 86f54e1ec3
commit 68ce28a0ee
4 changed files with 21 additions and 3 deletions
@@ -120,9 +120,13 @@ YogaLayoutableShadowNode::YogaLayoutableShadowNode(
}
}
YGConfigRef previousConfig = YGNodeGetConfig(
&static_cast<YogaLayoutableShadowNode const &>(sourceShadowNode)
.yogaNode_);
yogaNode_.setContext(this);
yogaNode_.setOwner(nullptr);
yogaNode_.setConfig(&initializeYogaConfig(yogaConfig_));
yogaNode_.setConfig(&initializeYogaConfig(yogaConfig_, previousConfig));
updateYogaChildrenOwnersIfNeeded();
// This is the only legit place where we can dirty cloned Yoga node.
@@ -742,10 +746,17 @@ YogaLayoutableShadowNode &YogaLayoutableShadowNode::shadowNodeFromContext(
*static_cast<ShadowNode *>(yogaNode->getContext()));
}
YGConfig &YogaLayoutableShadowNode::initializeYogaConfig(YGConfig &config) {
YGConfig &YogaLayoutableShadowNode::initializeYogaConfig(
YGConfig &config,
const YGConfigRef previousConfig) {
YGConfigSetCloneNodeFunc(
&config, YogaLayoutableShadowNode::yogaNodeCloneCallbackConnector);
YGConfigSetErrata(&config, YGErrataAll);
if (previousConfig != nullptr) {
YGConfigSetPointScaleFactor(
&config, YGConfigGetPointScaleFactor(previousConfig));
}
#ifdef RN_DEBUG_YOGA_LOGGER
YGConfigSetPrintTreeFlag(&config, true);
#endif
@@ -132,7 +132,9 @@ class YogaLayoutableShadowNode : public LayoutableShadowNode {
*/
void adoptYogaChild(size_t index);
static YGConfig &initializeYogaConfig(YGConfig &config);
static YGConfig &initializeYogaConfig(
YGConfig &config,
YGConfigRef previousConfig = nullptr);
static YGNode *yogaNodeCloneCallbackConnector(
YGNode *oldYogaNode,
YGNode *parentYogaNode,
@@ -4075,6 +4075,10 @@ YOGA_EXPORT void YGConfigSetPointScaleFactor(
}
}
YOGA_EXPORT float YGConfigGetPointScaleFactor(const YGConfigRef config) {
return config->getPointScaleFactor();
}
static void YGRoundToPixelGrid(
const YGNodeRef node,
const double pointScaleFactor,
@@ -317,6 +317,7 @@ WIN_EXPORT void YGAssertWithConfig(
WIN_EXPORT void YGConfigSetPointScaleFactor(
YGConfigRef config,
float pixelsInPoint);
WIN_EXPORT float YGConfigGetPointScaleFactor(YGConfigRef config);
// Yoga previously had an error where containers would take the maximum space
// possible instead of the minimum like they are supposed to. In practice this