[fabric] Fixed updating font size after system change

When updating accessibility text size there is an issue in the current code that would cut the tree enumeration and not update all the shadownodes in the tree - causing the layout in parent elements (of the text element) to not update its layout.

This commit fixes this by simplifying the code a lot - we don't need any optimizations here - we can update the whole tree each time the system font size is changed.

Tested in RN Tester and Expo Go (with the `enableFontScaleChangesUpdatingLayout` feature flag enabled)
This commit is contained in:
Christian Falch
2025-09-14 18:19:54 +02:00
parent 56e5dff73f
commit b74f502029
2 changed files with 9 additions and 72 deletions
@@ -233,75 +233,14 @@ Size SurfaceHandler::measure(
return rootShadowNode->getLayoutMetrics().frame.size;
}
std::shared_ptr<const ShadowNode> SurfaceHandler::dirtyMeasurableNodesRecursive(
std::shared_ptr<const ShadowNode> node) const {
const auto nodeHasChildren = !node->getChildren().empty();
const auto isMeasurableYogaNode =
node->getTraits().check(ShadowNodeTraits::Trait::MeasurableYogaNode);
// Node is not measurable and has no children, its layout will not be affected
if (!nodeHasChildren && !isMeasurableYogaNode) {
return nullptr;
void SurfaceHandler::dirtyMeasurableNodes(std::shared_ptr<const ShadowNode> node) const {
if (auto* layoutableNode = dynamic_cast<const YogaLayoutableShadowNode*>(node.get())) {
// Only cast away const where needed
const_cast<YogaLayoutableShadowNode*>(layoutableNode)->dirtyLayout();
}
ShadowNode::SharedListOfShared newChildren =
ShadowNodeFragment::childrenPlaceholder();
if (nodeHasChildren) {
std::shared_ptr<std::vector<std::shared_ptr<const ShadowNode>>>
newChildrenMutable = nullptr;
for (size_t i = 0; i < node->getChildren().size(); i++) {
const auto& child = node->getChildren()[i];
if (const auto& layoutableNode =
std::dynamic_pointer_cast<const YogaLayoutableShadowNode>(
child)) {
auto newChild = dirtyMeasurableNodesRecursive(layoutableNode);
if (newChild != nullptr) {
if (newChildrenMutable == nullptr) {
newChildrenMutable = std::make_shared<
std::vector<std::shared_ptr<const ShadowNode>>>(
node->getChildren());
newChildren = newChildrenMutable;
}
(*newChildrenMutable)[i] = newChild;
}
}
}
// Node is not measurable and its children were not dirtied, its layout will
// not be affected
if (!isMeasurableYogaNode && newChildrenMutable == nullptr) {
return nullptr;
}
}
const auto newNode = node->getComponentDescriptor().cloneShadowNode(
*node,
{
.children = newChildren,
// Preserve the original state of the node
.state = node->getState(),
});
if (isMeasurableYogaNode) {
std::static_pointer_cast<YogaLayoutableShadowNode>(newNode)->dirtyLayout();
}
return newNode;
}
void SurfaceHandler::dirtyMeasurableNodes(ShadowNode& root) const {
for (const auto& child : root.getChildren()) {
if (const auto& layoutableNode =
std::dynamic_pointer_cast<const YogaLayoutableShadowNode>(child)) {
const auto newChild = dirtyMeasurableNodesRecursive(layoutableNode);
if (newChild != nullptr) {
root.replaceChild(*child, newChild);
}
}
for (const auto& child : node->getChildren()) {
dirtyMeasurableNodes(child);
}
}
@@ -344,7 +283,7 @@ void SurfaceHandler::constraintLayout(
layoutContext.fontSizeMultiplier !=
oldRootShadowNode.getConcreteProps()
.layoutContext.fontSizeMultiplier) {
dirtyMeasurableNodes(*newRoot);
dirtyMeasurableNodes(newRoot);
}
return newRoot;
@@ -158,11 +158,9 @@ class SurfaceHandler {
void applyDisplayMode(DisplayMode displayMode) const;
/*
* An utility for dirtying all measurable shadow nodes present in the tree.
* Marks all measurable shadow nodes in the given tree as dirty
*/
void dirtyMeasurableNodes(ShadowNode& root) const;
std::shared_ptr<const ShadowNode> dirtyMeasurableNodesRecursive(
std::shared_ptr<const ShadowNode> node) const;
void dirtyMeasurableNodes(std::shared_ptr<const ShadowNode> node) const;
#pragma mark - Link & Parameters