Expose Unsnapped Dimensions (#1809)

Summary:
Pull Request resolved: https://github.com/facebook/yoga/pull/1809

X-link: 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
This commit is contained in:
Nick Gerleman
2025-05-08 17:45:16 -07:00
committed by Facebook GitHub Bot
parent 4abc1a7d5f
commit 37a94a86de
6 changed files with 54 additions and 6 deletions

View File

@@ -161,3 +161,23 @@ TEST(YogaTest, per_node_point_scale_factor) {
YGConfigFree(config2); YGConfigFree(config2);
YGConfigFree(config3); YGConfigFree(config3);
} }
TEST(YogaTest, raw_layout_dimensions) {
YGConfigRef config = YGConfigNew();
YGConfigSetPointScaleFactor(config, 0.5f);
YGNodeRef root = YGNodeNewWithConfig(config);
YGNodeStyleSetWidth(root, 11.5f);
YGNodeStyleSetHeight(root, 9.5f);
YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
ASSERT_EQ(YGNodeLayoutGetWidth(root), 12.0f);
ASSERT_EQ(YGNodeLayoutGetHeight(root), 10.0f);
ASSERT_EQ(YGNodeLayoutGetRawWidth(root), 11.5f);
ASSERT_EQ(YGNodeLayoutGetRawHeight(root), 9.5f);
YGNodeFreeRecursive(root);
YGConfigFree(config);
}

View File

@@ -90,3 +90,11 @@ float YGNodeLayoutGetPadding(YGNodeConstRef node, YGEdge edge) {
return getResolvedLayoutProperty<&LayoutResults::padding>( return getResolvedLayoutProperty<&LayoutResults::padding>(
node, scopedEnum(edge)); 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);
}

View File

@@ -32,4 +32,14 @@ YG_EXPORT float YGNodeLayoutGetMargin(YGNodeConstRef node, YGEdge edge);
YG_EXPORT float YGNodeLayoutGetBorder(YGNodeConstRef node, YGEdge edge); YG_EXPORT float YGNodeLayoutGetBorder(YGNodeConstRef node, YGEdge edge);
YG_EXPORT float YGNodeLayoutGetPadding(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 YG_EXTERN_C_END

View File

@@ -106,25 +106,25 @@ void roundLayoutResultsToPixelGrid(
const bool hasFractionalHeight = const bool hasFractionalHeight =
!yoga::inexactEquals(round(scaledNodeHeight), scaledNodeHeight); !yoga::inexactEquals(round(scaledNodeHeight), scaledNodeHeight);
node->setLayoutDimension( node->getLayout().setDimension(
Dimension::Width,
roundValueToPixelGrid( roundValueToPixelGrid(
absoluteNodeRight, absoluteNodeRight,
pointScaleFactor, pointScaleFactor,
(textRounding && hasFractionalWidth), (textRounding && hasFractionalWidth),
(textRounding && !hasFractionalWidth)) - (textRounding && !hasFractionalWidth)) -
roundValueToPixelGrid( roundValueToPixelGrid(
absoluteNodeLeft, pointScaleFactor, false, textRounding), absoluteNodeLeft, pointScaleFactor, false, textRounding));
Dimension::Width);
node->setLayoutDimension( node->getLayout().setDimension(
Dimension::Height,
roundValueToPixelGrid( roundValueToPixelGrid(
absoluteNodeBottom, absoluteNodeBottom,
pointScaleFactor, pointScaleFactor,
(textRounding && hasFractionalHeight), (textRounding && hasFractionalHeight),
(textRounding && !hasFractionalHeight)) - (textRounding && !hasFractionalHeight)) -
roundValueToPixelGrid( roundValueToPixelGrid(
absoluteNodeTop, pointScaleFactor, false, textRounding), absoluteNodeTop, pointScaleFactor, false, textRounding));
Dimension::Height);
} }
for (yoga::Node* child : node->getChildren()) { for (yoga::Node* child : node->getChildren()) {

View File

@@ -66,10 +66,18 @@ struct LayoutResults {
return measuredDimensions_[yoga::to_underlying(axis)]; return measuredDimensions_[yoga::to_underlying(axis)];
} }
float rawDimension(Dimension axis) const {
return rawDimensions_[yoga::to_underlying(axis)];
}
void setMeasuredDimension(Dimension axis, float dimension) { void setMeasuredDimension(Dimension axis, float dimension) {
measuredDimensions_[yoga::to_underlying(axis)] = dimension; measuredDimensions_[yoga::to_underlying(axis)] = dimension;
} }
void setRawDimension(Dimension axis, float dimension) {
rawDimensions_[yoga::to_underlying(axis)] = dimension;
}
float position(PhysicalEdge physicalEdge) const { float position(PhysicalEdge physicalEdge) const {
return position_[yoga::to_underlying(physicalEdge)]; return position_[yoga::to_underlying(physicalEdge)];
} }
@@ -113,6 +121,7 @@ struct LayoutResults {
std::array<float, 2> dimensions_ = {{YGUndefined, YGUndefined}}; std::array<float, 2> dimensions_ = {{YGUndefined, YGUndefined}};
std::array<float, 2> measuredDimensions_ = {{YGUndefined, YGUndefined}}; std::array<float, 2> measuredDimensions_ = {{YGUndefined, YGUndefined}};
std::array<float, 2> rawDimensions_ = {{YGUndefined, YGUndefined}};
std::array<float, 4> position_ = {}; std::array<float, 4> position_ = {};
std::array<float, 4> margin_ = {}; std::array<float, 4> margin_ = {};
std::array<float, 4> border_ = {}; std::array<float, 4> border_ = {};

View File

@@ -247,6 +247,7 @@ void Node::setLayoutHadOverflow(bool hadOverflow) {
void Node::setLayoutDimension(float lengthValue, Dimension dimension) { void Node::setLayoutDimension(float lengthValue, Dimension dimension) {
layout_.setDimension(dimension, lengthValue); layout_.setDimension(dimension, lengthValue);
layout_.setRawDimension(dimension, lengthValue);
} }
// If both left and right are defined, then use left. Otherwise return +left or // If both left and right are defined, then use left. Otherwise return +left or