Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -480,6 +480,7 @@ void YogaLayoutableShadowNode::updateYogaProps() {

void YogaLayoutableShadowNode::configureYogaTree(
float pointScaleFactor,
Float fontSizeMultiplier,
YGErrata defaultErrata,
bool swapLeftAndRight) {
ensureUnsealed();
Expand All @@ -489,6 +490,18 @@ void YogaLayoutableShadowNode::configureYogaTree(
YGConfigSetErrata(&yogaConfig_, errata);
YGConfigSetPointScaleFactor(&yogaConfig_, pointScaleFactor);

// A measurable node's measurement depends on `fontSizeMultiplier`, but unlike
// `pointScaleFactor` it is not part of the Yoga config, so a change does not
// invalidate Yoga's layout cache. Dirty the node when it changes to force
// re-measurement. We propagate up to the root so an unchanged, still-cached
// ancestor isn't skipped by `calculateLayoutInternal` before reaching us.
if (ReactNativeFeatureFlags::enableFontScaleChangesUpdatingLayout() &&
getTraits().check(ShadowNodeTraits::Trait::MeasurableYogaNode) &&
!floatEquality(
getLayoutMetrics().fontSizeMultiplier, fontSizeMultiplier)) {
yogaNode_.markDirtyAndPropagate();
}

// TODO: `swapLeftAndRight` modified backing props and cannot be undone
if (swapLeftAndRight) {
swapStyleLeftAndRight();
Expand All @@ -507,6 +520,8 @@ void YogaLayoutableShadowNode::configureYogaTree(

if (child.yogaTreeHasBeenConfigured_ &&
childLayoutMetrics.pointScaleFactor == pointScaleFactor &&
floatEquality(
childLayoutMetrics.fontSizeMultiplier, fontSizeMultiplier) &&
childLayoutMetrics.wasLeftAndRightSwapped == swapLeftAndRight &&
childErrata == child.resolveErrata(errata)) {
continue;
Expand All @@ -515,10 +530,13 @@ void YogaLayoutableShadowNode::configureYogaTree(
if (doesOwn(child)) {
auto& mutableChild = const_cast<YogaLayoutableShadowNode&>(child);
mutableChild.configureYogaTree(
pointScaleFactor, child.resolveErrata(errata), swapLeftAndRight);
pointScaleFactor,
fontSizeMultiplier,
child.resolveErrata(errata),
swapLeftAndRight);
} else {
cloneChildInPlace(i).configureYogaTree(
pointScaleFactor, errata, swapLeftAndRight);
pointScaleFactor, fontSizeMultiplier, errata, swapLeftAndRight);
}
}
}
Expand Down Expand Up @@ -627,6 +645,7 @@ void YogaLayoutableShadowNode::layoutTree(
TraceSection s2("YogaLayoutableShadowNode::configureYogaTree");
configureYogaTree(
layoutContext.pointScaleFactor,
layoutContext.fontSizeMultiplier,
YGErrataAll /*defaultErrata*/,
swapLeftAndRight);
}
Expand Down Expand Up @@ -692,6 +711,7 @@ void YogaLayoutableShadowNode::layoutTree(
if (yogaNode_.getHasNewLayout()) {
auto layoutMetrics = layoutMetricsFromYogaNode(yogaNode_);
layoutMetrics.pointScaleFactor = layoutContext.pointScaleFactor;
layoutMetrics.fontSizeMultiplier = layoutContext.fontSizeMultiplier;
layoutMetrics.wasLeftAndRightSwapped = swapLeftAndRight;
setLayoutMetrics(layoutMetrics);
yogaNode_.setHasNewLayout(false);
Expand Down Expand Up @@ -739,6 +759,7 @@ void YogaLayoutableShadowNode::layout(LayoutContext layoutContext) {

auto newLayoutMetrics = layoutMetricsFromYogaNode(*childYogaNode);
newLayoutMetrics.pointScaleFactor = layoutContext.pointScaleFactor;
newLayoutMetrics.fontSizeMultiplier = layoutContext.fontSizeMultiplier;
newLayoutMetrics.wasLeftAndRightSwapped =
layoutContext.swapLeftAndRightInRTL &&
newLayoutMetrics.layoutDirection == LayoutDirection::RightToLeft;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,8 @@ class YogaLayoutableShadowNode : public LayoutableShadowNode {
* ShadowTree has been constructed, but before it has been is laid out or
* committed.
*/
void configureYogaTree(float pointScaleFactor, YGErrata defaultErrata, bool swapLeftAndRight);
void
configureYogaTree(float pointScaleFactor, Float fontSizeMultiplier, YGErrata defaultErrata, bool swapLeftAndRight);

/**
* Return an errata based on a `layoutConformance` prop if given, otherwise
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ struct LayoutMetrics {
bool wasLeftAndRightSwapped{false};
// Pixel density. Number of device pixels per density-independent pixel.
Float pointScaleFactor{1.0};
// Surface font scale this node was last laid out with.
Float fontSizeMultiplier{1.0};
// How much the children of the node actually overflow in each direction.
// Positive values indicate that children are overflowing outside of the node.
// Negative values indicate that children are clipped inside the node
Expand Down Expand Up @@ -120,6 +122,7 @@ struct hash<facebook::react::LayoutMetrics> {
layoutMetrics.displayType,
layoutMetrics.layoutDirection,
layoutMetrics.pointScaleFactor,
layoutMetrics.fontSizeMultiplier,
layoutMetrics.overflowInset);
}
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@

#include <cxxreact/TraceSection.h>
#include <react/debug/react_native_assert.h>
#include <react/featureflags/ReactNativeFeatureFlags.h>
#include <react/renderer/uimanager/UIManager.h>

namespace facebook::react {
Expand Down Expand Up @@ -213,78 +212,6 @@ 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;
}

std::shared_ptr<const std::vector<std::shared_ptr<const ShadowNode>>>
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);
}
}
}
}

void SurfaceHandler::constraintLayout(
const LayoutConstraints& layoutConstraints,
const LayoutContext& layoutContext) const {
Expand Down Expand Up @@ -315,19 +242,8 @@ void SurfaceHandler::constraintLayout(
link_.shadowTree && "`link_.shadowTree` must not be null.");
link_.shadowTree->commit(
[&](const RootShadowNode& oldRootShadowNode) {
auto newRoot = oldRootShadowNode.clone(
return oldRootShadowNode.clone(
propsParserContext, layoutConstraints, layoutContext);

// Dirty all measurable nodes when the fontSizeMultiplier changes to
// trigger re-measurement.
if (ReactNativeFeatureFlags::enableFontScaleChangesUpdatingLayout() &&
layoutContext.fontSizeMultiplier !=
oldRootShadowNode.getConcreteProps()
.layoutContext.fontSizeMultiplier) {
dirtyMeasurableNodes(*newRoot);
}

return newRoot;
},
{/* default commit options */});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -151,12 +151,6 @@ class SurfaceHandler {

void applyDisplayMode(DisplayMode displayMode) const;

/*
* An utility for dirtying all measurable shadow nodes present in the tree.
*/
void dirtyMeasurableNodes(ShadowNode &root) const;
std::shared_ptr<const ShadowNode> dirtyMeasurableNodesRecursive(std::shared_ptr<const ShadowNode> node) const;

#pragma mark - Link & Parameters

/*
Expand Down
1 change: 1 addition & 0 deletions scripts/cxx-api/api-snapshots/ReactAndroidDebugCxx.api
Original file line number Diff line number Diff line change
Expand Up @@ -7415,6 +7415,7 @@ struct facebook::react::LayoutMetrics {
public facebook::react::EdgeInsets borderWidth;
public facebook::react::EdgeInsets contentInsets;
public facebook::react::EdgeInsets overflowInset;
public facebook::react::Float fontSizeMultiplier;
public facebook::react::Float pointScaleFactor;
public facebook::react::LayoutDirection layoutDirection;
public facebook::react::PositionType positionType;
Expand Down
1 change: 1 addition & 0 deletions scripts/cxx-api/api-snapshots/ReactAndroidNewarchCxx.api
Original file line number Diff line number Diff line change
Expand Up @@ -7198,6 +7198,7 @@ struct facebook::react::LayoutMetrics {
public facebook::react::EdgeInsets borderWidth;
public facebook::react::EdgeInsets contentInsets;
public facebook::react::EdgeInsets overflowInset;
public facebook::react::Float fontSizeMultiplier;
public facebook::react::Float pointScaleFactor;
public facebook::react::LayoutDirection layoutDirection;
public facebook::react::PositionType positionType;
Expand Down
1 change: 1 addition & 0 deletions scripts/cxx-api/api-snapshots/ReactAndroidReleaseCxx.api
Original file line number Diff line number Diff line change
Expand Up @@ -7406,6 +7406,7 @@ struct facebook::react::LayoutMetrics {
public facebook::react::EdgeInsets borderWidth;
public facebook::react::EdgeInsets contentInsets;
public facebook::react::EdgeInsets overflowInset;
public facebook::react::Float fontSizeMultiplier;
public facebook::react::Float pointScaleFactor;
public facebook::react::LayoutDirection layoutDirection;
public facebook::react::PositionType positionType;
Expand Down
1 change: 1 addition & 0 deletions scripts/cxx-api/api-snapshots/ReactAppleDebugCxx.api
Original file line number Diff line number Diff line change
Expand Up @@ -9496,6 +9496,7 @@ struct facebook::react::LayoutMetrics {
public facebook::react::EdgeInsets borderWidth;
public facebook::react::EdgeInsets contentInsets;
public facebook::react::EdgeInsets overflowInset;
public facebook::react::Float fontSizeMultiplier;
public facebook::react::Float pointScaleFactor;
public facebook::react::LayoutDirection layoutDirection;
public facebook::react::PositionType positionType;
Expand Down
1 change: 1 addition & 0 deletions scripts/cxx-api/api-snapshots/ReactAppleNewarchCxx.api
Original file line number Diff line number Diff line change
Expand Up @@ -9331,6 +9331,7 @@ struct facebook::react::LayoutMetrics {
public facebook::react::EdgeInsets borderWidth;
public facebook::react::EdgeInsets contentInsets;
public facebook::react::EdgeInsets overflowInset;
public facebook::react::Float fontSizeMultiplier;
public facebook::react::Float pointScaleFactor;
public facebook::react::LayoutDirection layoutDirection;
public facebook::react::PositionType positionType;
Expand Down
1 change: 1 addition & 0 deletions scripts/cxx-api/api-snapshots/ReactAppleReleaseCxx.api
Original file line number Diff line number Diff line change
Expand Up @@ -9487,6 +9487,7 @@ struct facebook::react::LayoutMetrics {
public facebook::react::EdgeInsets borderWidth;
public facebook::react::EdgeInsets contentInsets;
public facebook::react::EdgeInsets overflowInset;
public facebook::react::Float fontSizeMultiplier;
public facebook::react::Float pointScaleFactor;
public facebook::react::LayoutDirection layoutDirection;
public facebook::react::PositionType positionType;
Expand Down
1 change: 1 addition & 0 deletions scripts/cxx-api/api-snapshots/ReactCommonDebugCxx.api
Original file line number Diff line number Diff line change
Expand Up @@ -5603,6 +5603,7 @@ struct facebook::react::LayoutContext {
}

struct facebook::react::LayoutMetrics {
public Float fontSizeMultiplier;
public Float pointScaleFactor;
public bool operator==(const facebook::react::LayoutMetrics& rhs) const = default;
public bool wasLeftAndRightSwapped;
Expand Down
1 change: 1 addition & 0 deletions scripts/cxx-api/api-snapshots/ReactCommonNewarchCxx.api
Original file line number Diff line number Diff line change
Expand Up @@ -5450,6 +5450,7 @@ struct facebook::react::LayoutContext {
}

struct facebook::react::LayoutMetrics {
public Float fontSizeMultiplier;
public Float pointScaleFactor;
public bool operator==(const facebook::react::LayoutMetrics& rhs) const = default;
public bool wasLeftAndRightSwapped;
Expand Down
1 change: 1 addition & 0 deletions scripts/cxx-api/api-snapshots/ReactCommonReleaseCxx.api
Original file line number Diff line number Diff line change
Expand Up @@ -5594,6 +5594,7 @@ struct facebook::react::LayoutContext {
}

struct facebook::react::LayoutMetrics {
public Float fontSizeMultiplier;
public Float pointScaleFactor;
public bool operator==(const facebook::react::LayoutMetrics& rhs) const = default;
public bool wasLeftAndRightSwapped;
Expand Down
Loading