From b221265f4156992fea932ca74f09ac04662a4a37 Mon Sep 17 00:00:00 2001 From: Nick Gerleman Date: Sat, 16 Dec 2023 01:12:30 -0800 Subject: [PATCH] Fix sizing and alignment issues with multi-line containers (#41916) Summary: X-link: https://github.com/facebook/yoga/pull/1513 Pull Request resolved: https://github.com/facebook/react-native/pull/41916 Fixes https://github.com/facebook/yoga/issues/1300 Fixes https://github.com/facebook/yoga/issues/1008 This fixes a smattering of issues related to both sizing and aligment of multi-line-containers: 1. We were previously incorrectly bounding the size of each flex line to the min/max of the entire container. 2. Per-line leads were sometimes incorrectly contributing to alignment within the line 3. The cross dim size used for multi-line alignment is not correct, or correctly clamped. If the available size comes from a max constraint, that was incorrectly used instead of a definite size, or size of content. Leads were entirely skipped for min constraint. Need to test how breaking this is, to see if it might need to go behind an errata. See related PRs: 1. https://github.com/facebook/yoga/pull/1491 2. https://github.com/facebook/yoga/pull/1493 3. https://github.com/facebook/yoga/pull/1013 Changelog: [General][Fixed] - Fix Yoga sizing and alignment issues with multi-line containers Reviewed By: joevilches Differential Revision: D52087013 fbshipit-source-id: 8d95ad17e58c1fec1cceab9756413d0b3bd4cd8f --- .../yoga/yoga/algorithm/CalculateLayout.cpp | 138 ++++++++++-------- 1 file changed, 74 insertions(+), 64 deletions(-) diff --git a/packages/react-native/ReactCommon/yoga/yoga/algorithm/CalculateLayout.cpp b/packages/react-native/ReactCommon/yoga/yoga/algorithm/CalculateLayout.cpp index 25665dafc5..8b645b9971 100644 --- a/packages/react-native/ReactCommon/yoga/yoga/algorithm/CalculateLayout.cpp +++ b/packages/react-native/ReactCommon/yoga/yoga/algorithm/CalculateLayout.cpp @@ -1569,15 +1569,20 @@ static void calculateLayoutImpl( flexLine.layout.crossDim = availableInnerCrossDim; } - // Clamp to the min/max size specified on the container. - flexLine.layout.crossDim = - boundAxis( - node, - crossAxis, - flexLine.layout.crossDim + paddingAndBorderAxisCross, - crossAxisownerSize, - ownerWidth) - - paddingAndBorderAxisCross; + // As-per https://www.w3.org/TR/css-flexbox-1/#cross-sizing, the + // cross-size of the line within a single-line container should be bound to + // min/max constraints before alignment within the line. In a multi-line + // container, affecting alignment between the lines. + if (!isNodeFlexWrap) { + flexLine.layout.crossDim = + boundAxis( + node, + crossAxis, + flexLine.layout.crossDim + paddingAndBorderAxisCross, + crossAxisownerSize, + ownerWidth) - + paddingAndBorderAxisCross; + } // STEP 7: CROSS-AXIS ALIGNMENT // We can skip child alignment if we're just measuring the container. @@ -1735,59 +1740,65 @@ static void calculateLayoutImpl( // STEP 8: MULTI-LINE CONTENT ALIGNMENT // currentLead stores the size of the cross dim if (performLayout && (isNodeFlexWrap || isBaselineLayout(node))) { - float crossDimLead = 0; + float leadPerLine = 0; float currentLead = leadingPaddingAndBorderCross; - if (yoga::isDefined(availableInnerCrossDim)) { - const float remainingAlignContentDim = - availableInnerCrossDim - totalLineCrossDim; - switch (node->getStyle().alignContent()) { - case Align::FlexEnd: - currentLead += remainingAlignContentDim; - break; - case Align::Center: + + const float unclampedCrossDim = + node->styleDefinesDimension(crossAxis, crossAxisownerSize) + ? yoga::resolveValue( + node->getResolvedDimension(dimension(crossAxis)), + crossAxisownerSize) + .unwrap() + : totalLineCrossDim + paddingAndBorderAxisCross; + + const float innerCrossDim = + boundAxis(node, crossAxis, unclampedCrossDim, ownerHeight, ownerWidth) - + paddingAndBorderAxisCross; + + const float remainingAlignContentDim = innerCrossDim - totalLineCrossDim; + switch (node->getStyle().alignContent()) { + case Align::FlexEnd: + currentLead += remainingAlignContentDim; + break; + case Align::Center: + currentLead += remainingAlignContentDim / 2; + break; + case Align::Stretch: + if (innerCrossDim > totalLineCrossDim) { + leadPerLine = + remainingAlignContentDim / static_cast(lineCount); + } + break; + case Align::SpaceAround: + if (innerCrossDim > totalLineCrossDim) { + currentLead += + remainingAlignContentDim / (2 * static_cast(lineCount)); + leadPerLine = + remainingAlignContentDim / static_cast(lineCount); + } else { currentLead += remainingAlignContentDim / 2; - break; - case Align::Stretch: - if (availableInnerCrossDim > totalLineCrossDim) { - crossDimLead = - remainingAlignContentDim / static_cast(lineCount); - } - break; - case Align::SpaceAround: - if (availableInnerCrossDim > totalLineCrossDim) { - currentLead += - remainingAlignContentDim / (2 * static_cast(lineCount)); - if (lineCount > 1) { - crossDimLead = - remainingAlignContentDim / static_cast(lineCount); - } - } else { - currentLead += remainingAlignContentDim / 2; - } - break; - case Align::SpaceEvenly: - if (availableInnerCrossDim > totalLineCrossDim) { - currentLead += - remainingAlignContentDim / static_cast(lineCount + 1); - if (lineCount > 1) { - crossDimLead = - remainingAlignContentDim / static_cast(lineCount + 1); - } - } else { - currentLead += remainingAlignContentDim / 2; - } - break; - case Align::SpaceBetween: - if (availableInnerCrossDim > totalLineCrossDim && lineCount > 1) { - crossDimLead = - remainingAlignContentDim / static_cast(lineCount - 1); - } - break; - case Align::Auto: - case Align::FlexStart: - case Align::Baseline: - break; - } + } + break; + case Align::SpaceEvenly: + if (innerCrossDim > totalLineCrossDim) { + currentLead += + remainingAlignContentDim / static_cast(lineCount + 1); + leadPerLine = + remainingAlignContentDim / static_cast(lineCount + 1); + } else { + currentLead += remainingAlignContentDim / 2; + } + break; + case Align::SpaceBetween: + if (innerCrossDim > totalLineCrossDim && lineCount > 1) { + leadPerLine = + remainingAlignContentDim / static_cast(lineCount - 1); + } + break; + case Align::Auto: + case Align::FlexStart: + case Align::Baseline: + break; } size_t endIndex = 0; for (size_t i = 0; i < lineCount; i++) { @@ -1832,7 +1843,6 @@ static void calculateLayoutImpl( } } endIndex = ii; - lineHeight += crossDimLead; currentLead += i != 0 ? crossAxisGap : 0; if (performLayout) { @@ -1885,14 +1895,14 @@ static void calculateLayoutImpl( ? (child->getLayout().measuredDimension( Dimension::Width) + child->getMarginForAxis(mainAxis, availableInnerWidth)) - : lineHeight; + : leadPerLine + lineHeight; const float childHeight = !isMainAxisRow ? (child->getLayout().measuredDimension( Dimension::Height) + child->getMarginForAxis( crossAxis, availableInnerWidth)) - : lineHeight; + : leadPerLine + lineHeight; if (!(yoga::inexactEquals( childWidth, @@ -1941,7 +1951,7 @@ static void calculateLayoutImpl( } } } - currentLead += lineHeight; + currentLead = currentLead + leadPerLine + lineHeight; } }