From 8ed5ccca623fd28acdc1e9499e32f74899e83498 Mon Sep 17 00:00:00 2001 From: Nick Gerleman Date: Thu, 8 May 2025 17:45:16 -0700 Subject: [PATCH] Expose Unsnapped Dimensions (#51181) Summary: X-link: https://github.com/facebook/yoga/pull/1809 Pull Request resolved: https://github.com/facebook/react-native/pull/51181 We want to know if an artifact created during measurement can fully be reused after final layout, but the final layout is allowed to be slightly larger due to pixel grid rounding (while still allowing reuse). It's hard to tell after the fact, whether it is larger because of this rounding (though the measure is used), or if it may be a pixel larger for valid reasons. We can expose the unsnapped dimensions of a node to give us this information, and to correlate measurement artifacts. This is most of the time the same as the layout's measured dimension, though I don't think it's safe to use this, since anything else measuring the node after could clobber this (I think `YGNodeLayoutGetOverflow` may also be prone to this as a bug). Changelog: [Internal] Reviewed By: rshest Differential Revision: D74292949 fbshipit-source-id: 05011c66a9a9480544313eb1dfe2c46bf7742bac --- .../ReactCommon/yoga/yoga/YGNodeLayout.cpp | 8 ++++++++ .../ReactCommon/yoga/yoga/YGNodeLayout.h | 10 ++++++++++ .../ReactCommon/yoga/yoga/algorithm/PixelGrid.cpp | 12 ++++++------ .../ReactCommon/yoga/yoga/node/LayoutResults.h | 9 +++++++++ .../react-native/ReactCommon/yoga/yoga/node/Node.cpp | 1 + 5 files changed, 34 insertions(+), 6 deletions(-) diff --git a/packages/react-native/ReactCommon/yoga/yoga/YGNodeLayout.cpp b/packages/react-native/ReactCommon/yoga/yoga/YGNodeLayout.cpp index 93fcf0ad005..50c8766ebdb 100644 --- a/packages/react-native/ReactCommon/yoga/yoga/YGNodeLayout.cpp +++ b/packages/react-native/ReactCommon/yoga/yoga/YGNodeLayout.cpp @@ -90,3 +90,11 @@ float YGNodeLayoutGetPadding(YGNodeConstRef node, YGEdge edge) { return getResolvedLayoutProperty<&LayoutResults::padding>( node, scopedEnum(edge)); } + +float YGNodeLayoutGetRawHeight(YGNodeConstRef node) { + return resolveRef(node)->getLayout().rawDimension(Dimension::Height); +} + +float YGNodeLayoutGetRawWidth(YGNodeConstRef node) { + return resolveRef(node)->getLayout().rawDimension(Dimension::Width); +} diff --git a/packages/react-native/ReactCommon/yoga/yoga/YGNodeLayout.h b/packages/react-native/ReactCommon/yoga/yoga/YGNodeLayout.h index 02ead5883bb..4f25af21377 100644 --- a/packages/react-native/ReactCommon/yoga/yoga/YGNodeLayout.h +++ b/packages/react-native/ReactCommon/yoga/yoga/YGNodeLayout.h @@ -32,4 +32,14 @@ YG_EXPORT float YGNodeLayoutGetMargin(YGNodeConstRef node, YGEdge edge); YG_EXPORT float YGNodeLayoutGetBorder(YGNodeConstRef node, YGEdge edge); YG_EXPORT float YGNodeLayoutGetPadding(YGNodeConstRef node, YGEdge edge); +/** + * Return the measured height of the node, before layout rounding + */ +YG_EXPORT float YGNodeLayoutGetRawHeight(YGNodeConstRef node); + +/** + * Return the measured width of the node, before layout rounding + */ +YG_EXPORT float YGNodeLayoutGetRawWidth(YGNodeConstRef node); + YG_EXTERN_C_END diff --git a/packages/react-native/ReactCommon/yoga/yoga/algorithm/PixelGrid.cpp b/packages/react-native/ReactCommon/yoga/yoga/algorithm/PixelGrid.cpp index 6083f0f2646..61de2be2e8f 100644 --- a/packages/react-native/ReactCommon/yoga/yoga/algorithm/PixelGrid.cpp +++ b/packages/react-native/ReactCommon/yoga/yoga/algorithm/PixelGrid.cpp @@ -106,25 +106,25 @@ void roundLayoutResultsToPixelGrid( const bool hasFractionalHeight = !yoga::inexactEquals(round(scaledNodeHeight), scaledNodeHeight); - node->setLayoutDimension( + node->getLayout().setDimension( + Dimension::Width, roundValueToPixelGrid( absoluteNodeRight, pointScaleFactor, (textRounding && hasFractionalWidth), (textRounding && !hasFractionalWidth)) - roundValueToPixelGrid( - absoluteNodeLeft, pointScaleFactor, false, textRounding), - Dimension::Width); + absoluteNodeLeft, pointScaleFactor, false, textRounding)); - node->setLayoutDimension( + node->getLayout().setDimension( + Dimension::Height, roundValueToPixelGrid( absoluteNodeBottom, pointScaleFactor, (textRounding && hasFractionalHeight), (textRounding && !hasFractionalHeight)) - roundValueToPixelGrid( - absoluteNodeTop, pointScaleFactor, false, textRounding), - Dimension::Height); + absoluteNodeTop, pointScaleFactor, false, textRounding)); } for (yoga::Node* child : node->getChildren()) { diff --git a/packages/react-native/ReactCommon/yoga/yoga/node/LayoutResults.h b/packages/react-native/ReactCommon/yoga/yoga/node/LayoutResults.h index 9f0aeaf7843..6776a423409 100644 --- a/packages/react-native/ReactCommon/yoga/yoga/node/LayoutResults.h +++ b/packages/react-native/ReactCommon/yoga/yoga/node/LayoutResults.h @@ -66,10 +66,18 @@ struct LayoutResults { return measuredDimensions_[yoga::to_underlying(axis)]; } + float rawDimension(Dimension axis) const { + return rawDimensions_[yoga::to_underlying(axis)]; + } + void setMeasuredDimension(Dimension axis, float dimension) { measuredDimensions_[yoga::to_underlying(axis)] = dimension; } + void setRawDimension(Dimension axis, float dimension) { + rawDimensions_[yoga::to_underlying(axis)] = dimension; + } + float position(PhysicalEdge physicalEdge) const { return position_[yoga::to_underlying(physicalEdge)]; } @@ -113,6 +121,7 @@ struct LayoutResults { std::array dimensions_ = {{YGUndefined, YGUndefined}}; std::array measuredDimensions_ = {{YGUndefined, YGUndefined}}; + std::array rawDimensions_ = {{YGUndefined, YGUndefined}}; std::array position_ = {}; std::array margin_ = {}; std::array border_ = {}; diff --git a/packages/react-native/ReactCommon/yoga/yoga/node/Node.cpp b/packages/react-native/ReactCommon/yoga/yoga/node/Node.cpp index dce42fb1658..fbdf5c1bff7 100644 --- a/packages/react-native/ReactCommon/yoga/yoga/node/Node.cpp +++ b/packages/react-native/ReactCommon/yoga/yoga/node/Node.cpp @@ -247,6 +247,7 @@ void Node::setLayoutHadOverflow(bool hadOverflow) { void Node::setLayoutDimension(float lengthValue, Dimension dimension) { layout_.setDimension(dimension, lengthValue); + layout_.setRawDimension(dimension, lengthValue); } // If both left and right are defined, then use left. Otherwise return +left or