From 568718242dc9075a110fa02ea45dad1aee8ab159 Mon Sep 17 00:00:00 2001 From: Nick Gerleman Date: Thu, 17 Oct 2024 22:40:16 -0700 Subject: [PATCH] Remove legacy absolute positioning path (#1725) Summary: X-link: https://github.com/facebook/react-native/pull/46984 Pull Request resolved: https://github.com/facebook/yoga/pull/1725 The legacy (wrong) absolute positioning path positions in two places, including work that is definitely always overwritten in the new absolute layout path. This came up before for position: static, but we didn't clean this up at the time. This code is also now leading display: contents impl being more annoying. This diff tries to converge to the more spec correct implementation of positioning here, that also only happens in one place. Previous path would potentially also incorrectly justify when `justify-content` was non-default, but not handled in the previous few cases? We don't have access to the flexLine at this point later, and apart from the existing tests now passing I reused the new correct logic for justification (spec says we should position child as if its the only child in the container https://www.w3.org/TR/css-flexbox-1/#abspos-items). I added a new, more scoped errata `AbsolutePositionWithoutInsetsExcludesPadding` to preserve some of the legacy behavior that showed as very breaking. I also did not try removing `AbsolutePercentAgainstInnerSize` which I suspect would be more breaking than this change. Changelog: [General][Breaking] - More spec compliant absolute positioning Reviewed By: joevilches Differential Revision: D64244949 fbshipit-source-id: ca97570e0de82e8f0424a0912adfd0b05254559e --- enums.py | 7 +- java/com/facebook/yoga/YogaErrata.java | 4 +- javascript/src/generated/YGEnums.ts | 4 +- yoga/YGEnums.cpp | 4 +- yoga/YGEnums.h | 2 +- yoga/algorithm/AbsoluteLayout.cpp | 150 +++------- yoga/algorithm/CalculateLayout.cpp | 396 ++++++++++--------------- yoga/enums/Errata.h | 2 +- 8 files changed, 213 insertions(+), 356 deletions(-) diff --git a/enums.py b/enums.py index fa212249c0..543ad99152 100755 --- a/enums.py +++ b/enums.py @@ -61,9 +61,10 @@ # Allows main-axis flex basis to be stretched without flexGrow being # set (previously referred to as "UseLegacyStretchBehaviour") ("StretchFlexBasis", 1 << 0), - # Positioning of absolute nodes will have various bugs related to - # justification, alignment, and insets - ("AbsolutePositioningIncorrect", 1 << 1), + # Absolute position in a given axis will be relative to the padding + # edge of the parent container instead of the content edge when a + # specific inset (top/bottom/left/right) is not set. + ("AbsolutePositionWithoutInsetsExcludesPadding", 1 << 1), # Absolute nodes will resolve percentages against the inner size of # their containing node, not the padding box ("AbsolutePercentAgainstInnerSize", 1 << 2), diff --git a/java/com/facebook/yoga/YogaErrata.java b/java/com/facebook/yoga/YogaErrata.java index a0f26bf2a9..e0521b3fbb 100644 --- a/java/com/facebook/yoga/YogaErrata.java +++ b/java/com/facebook/yoga/YogaErrata.java @@ -12,7 +12,7 @@ public enum YogaErrata { NONE(0), STRETCH_FLEX_BASIS(1), - ABSOLUTE_POSITIONING_INCORRECT(2), + ABSOLUTE_POSITION_WITHOUT_INSETS_EXCLUDES_PADDING(2), ABSOLUTE_PERCENT_AGAINST_INNER_SIZE(4), ALL(2147483647), CLASSIC(2147483646); @@ -31,7 +31,7 @@ public static YogaErrata fromInt(int value) { switch (value) { case 0: return NONE; case 1: return STRETCH_FLEX_BASIS; - case 2: return ABSOLUTE_POSITIONING_INCORRECT; + case 2: return ABSOLUTE_POSITION_WITHOUT_INSETS_EXCLUDES_PADDING; case 4: return ABSOLUTE_PERCENT_AGAINST_INNER_SIZE; case 2147483647: return ALL; case 2147483646: return CLASSIC; diff --git a/javascript/src/generated/YGEnums.ts b/javascript/src/generated/YGEnums.ts index 48f27bf9af..ef3f141ef5 100644 --- a/javascript/src/generated/YGEnums.ts +++ b/javascript/src/generated/YGEnums.ts @@ -55,7 +55,7 @@ export enum Edge { export enum Errata { None = 0, StretchFlexBasis = 1, - AbsolutePositioningIncorrect = 2, + AbsolutePositionWithoutInsetsExcludesPadding = 2, AbsolutePercentAgainstInnerSize = 4, All = 2147483647, Classic = 2147483646, @@ -162,7 +162,7 @@ const constants = { EDGE_ALL: Edge.All, ERRATA_NONE: Errata.None, ERRATA_STRETCH_FLEX_BASIS: Errata.StretchFlexBasis, - ERRATA_ABSOLUTE_POSITIONING_INCORRECT: Errata.AbsolutePositioningIncorrect, + ERRATA_ABSOLUTE_POSITION_WITHOUT_INSETS_EXCLUDES_PADDING: Errata.AbsolutePositionWithoutInsetsExcludesPadding, ERRATA_ABSOLUTE_PERCENT_AGAINST_INNER_SIZE: Errata.AbsolutePercentAgainstInnerSize, ERRATA_ALL: Errata.All, ERRATA_CLASSIC: Errata.Classic, diff --git a/yoga/YGEnums.cpp b/yoga/YGEnums.cpp index c0a72918d8..bea2cefa93 100644 --- a/yoga/YGEnums.cpp +++ b/yoga/YGEnums.cpp @@ -105,8 +105,8 @@ const char* YGErrataToString(const YGErrata value) { return "none"; case YGErrataStretchFlexBasis: return "stretch-flex-basis"; - case YGErrataAbsolutePositioningIncorrect: - return "absolute-positioning-incorrect"; + case YGErrataAbsolutePositionWithoutInsetsExcludesPadding: + return "absolute-position-without-insets-excludes-padding"; case YGErrataAbsolutePercentAgainstInnerSize: return "absolute-percent-against-inner-size"; case YGErrataAll: diff --git a/yoga/YGEnums.h b/yoga/YGEnums.h index 83c368a601..a41f723220 100644 --- a/yoga/YGEnums.h +++ b/yoga/YGEnums.h @@ -61,7 +61,7 @@ YG_ENUM_DECL( YGErrata, YGErrataNone = 0, YGErrataStretchFlexBasis = 1, - YGErrataAbsolutePositioningIncorrect = 2, + YGErrataAbsolutePositionWithoutInsetsExcludesPadding = 2, YGErrataAbsolutePercentAgainstInnerSize = 4, YGErrataAll = 2147483647, YGErrataClassic = 2147483646) diff --git a/yoga/algorithm/AbsoluteLayout.cpp b/yoga/algorithm/AbsoluteLayout.cpp index de4eef9df9..852c8fc4f0 100644 --- a/yoga/algorithm/AbsoluteLayout.cpp +++ b/yoga/algorithm/AbsoluteLayout.cpp @@ -19,12 +19,15 @@ static inline void setFlexStartLayoutPosition( const Direction direction, const FlexDirection axis, const float containingBlockWidth) { - child->setLayoutPosition( - child->style().computeFlexStartMargin( - axis, direction, containingBlockWidth) + - parent->getLayout().border(flexStartEdge(axis)) + - parent->getLayout().padding(flexStartEdge(axis)), - flexStartEdge(axis)); + float position = child->style().computeFlexStartMargin( + axis, direction, containingBlockWidth) + + parent->getLayout().border(flexStartEdge(axis)); + + if (!child->hasErrata(Errata::AbsolutePositionWithoutInsetsExcludesPadding)) { + position += parent->getLayout().padding(flexStartEdge(axis)); + } + + child->setLayoutPosition(position, flexStartEdge(axis)); } static inline void setFlexEndLayoutPosition( @@ -33,15 +36,16 @@ static inline void setFlexEndLayoutPosition( const Direction direction, const FlexDirection axis, const float containingBlockWidth) { + float flexEndPosition = parent->getLayout().border(flexEndEdge(axis)) + + child->style().computeFlexEndMargin( + axis, direction, containingBlockWidth); + + if (!child->hasErrata(Errata::AbsolutePositionWithoutInsetsExcludesPadding)) { + flexEndPosition += parent->getLayout().padding(flexEndEdge(axis)); + } + child->setLayoutPosition( - getPositionOfOppositeEdge( - parent->getLayout().border(flexEndEdge(axis)) + - parent->getLayout().padding(flexEndEdge(axis)) + - child->style().computeFlexEndMargin( - axis, direction, containingBlockWidth), - axis, - parent, - child), + getPositionOfOppositeEdge(flexEndPosition, axis, parent, child), flexStartEdge(axis)); } @@ -51,22 +55,30 @@ static inline void setCenterLayoutPosition( const Direction direction, const FlexDirection axis, const float containingBlockWidth) { - const float parentContentBoxSize = + float parentContentBoxSize = parent->getLayout().measuredDimension(dimension(axis)) - parent->getLayout().border(flexStartEdge(axis)) - - parent->getLayout().border(flexEndEdge(axis)) - - parent->getLayout().padding(flexStartEdge(axis)) - - parent->getLayout().padding(flexEndEdge(axis)); + parent->getLayout().border(flexEndEdge(axis)); + + if (!child->hasErrata(Errata::AbsolutePositionWithoutInsetsExcludesPadding)) { + parentContentBoxSize -= parent->getLayout().padding(flexStartEdge(axis)); + parentContentBoxSize -= parent->getLayout().padding(flexEndEdge(axis)); + } + const float childOuterSize = child->getLayout().measuredDimension(dimension(axis)) + child->style().computeMarginForAxis(axis, containingBlockWidth); - child->setLayoutPosition( - (parentContentBoxSize - childOuterSize) / 2.0f + - parent->getLayout().border(flexStartEdge(axis)) + - parent->getLayout().padding(flexStartEdge(axis)) + - child->style().computeFlexStartMargin( - axis, direction, containingBlockWidth), - flexStartEdge(axis)); + + float position = (parentContentBoxSize - childOuterSize) / 2.0f + + parent->getLayout().border(flexStartEdge(axis)) + + child->style().computeFlexStartMargin( + axis, direction, containingBlockWidth); + + if (!child->hasErrata(Errata::AbsolutePositionWithoutInsetsExcludesPadding)) { + position += parent->getLayout().padding(flexStartEdge(axis)); + } + + child->setLayoutPosition(position, flexStartEdge(axis)); } static void justifyAbsoluteChild( @@ -133,62 +145,6 @@ static void alignAbsoluteChild( } } -// To ensure no breaking changes, we preserve the legacy way of positioning -// absolute children and determine if we should use it using an errata. -static void positionAbsoluteChildLegacy( - const yoga::Node* const containingNode, - const yoga::Node* const parent, - yoga::Node* child, - const Direction direction, - const FlexDirection axis, - const bool isMainAxis, - const float containingBlockWidth, - const float containingBlockHeight) { - const bool isAxisRow = isRow(axis); - const bool shouldCenter = isMainAxis - ? parent->style().justifyContent() == Justify::Center - : resolveChildAlignment(parent, child) == Align::Center; - const bool shouldFlexEnd = isMainAxis - ? parent->style().justifyContent() == Justify::FlexEnd - : ((resolveChildAlignment(parent, child) == Align::FlexEnd) ^ - (parent->style().flexWrap() == Wrap::WrapReverse)); - - if (child->style().isFlexEndPositionDefined(axis, direction) && - (!child->style().isFlexStartPositionDefined(axis, direction) || - child->style().isFlexStartPositionAuto(axis, direction))) { - child->setLayoutPosition( - containingNode->getLayout().measuredDimension(dimension(axis)) - - child->getLayout().measuredDimension(dimension(axis)) - - containingNode->style().computeFlexEndBorder(axis, direction) - - child->style().computeFlexEndMargin( - axis, - direction, - isAxisRow ? containingBlockWidth : containingBlockHeight) - - child->style().computeFlexEndPosition( - axis, - direction, - isAxisRow ? containingBlockWidth : containingBlockHeight), - flexStartEdge(axis)); - } else if ( - (!child->style().isFlexStartPositionDefined(axis, direction) || - child->style().isFlexStartPositionAuto(axis, direction)) && - shouldCenter) { - child->setLayoutPosition( - (parent->getLayout().measuredDimension(dimension(axis)) - - child->getLayout().measuredDimension(dimension(axis))) / - 2.0f, - flexStartEdge(axis)); - } else if ( - (!child->style().isFlexStartPositionDefined(axis, direction) || - child->style().isFlexStartPositionAuto(axis, direction)) && - shouldFlexEnd) { - child->setLayoutPosition( - (parent->getLayout().measuredDimension(dimension(axis)) - - child->getLayout().measuredDimension(dimension(axis))), - flexStartEdge(axis)); - } -} - /* * Absolutely positioned nodes do not participate in flex layout and thus their * positions can be determined independently from the rest of their siblings. @@ -205,7 +161,7 @@ static void positionAbsoluteChildLegacy( * This function does that positioning for the given axis. The spec has more * information on this topic: https://www.w3.org/TR/css-flexbox-1/#abspos-items */ -static void positionAbsoluteChildImpl( +static void positionAbsoluteChild( const yoga::Node* const containingNode, const yoga::Node* const parent, yoga::Node* child, @@ -267,36 +223,6 @@ static void positionAbsoluteChildImpl( } } -static void positionAbsoluteChild( - const yoga::Node* const containingNode, - const yoga::Node* const parent, - yoga::Node* child, - const Direction direction, - const FlexDirection axis, - const bool isMainAxis, - const float containingBlockWidth, - const float containingBlockHeight) { - child->hasErrata(Errata::AbsolutePositioningIncorrect) - ? positionAbsoluteChildLegacy( - containingNode, - parent, - child, - direction, - axis, - isMainAxis, - containingBlockWidth, - containingBlockHeight) - : positionAbsoluteChildImpl( - containingNode, - parent, - child, - direction, - axis, - isMainAxis, - containingBlockWidth, - containingBlockHeight); -} - void layoutAbsoluteChild( const yoga::Node* const containingNode, const yoga::Node* const node, diff --git a/yoga/algorithm/CalculateLayout.cpp b/yoga/algorithm/CalculateLayout.cpp index 3a98c9232c..d3c9bd7863 100644 --- a/yoga/algorithm/CalculateLayout.cpp +++ b/yoga/algorithm/CalculateLayout.cpp @@ -981,7 +981,6 @@ static void resolveFlexibleLength( static void justifyMainAxis( yoga::Node* const node, FlexLine& flexLine, - const size_t startOfLineIndex, const FlexDirection mainAxis, const FlexDirection crossAxis, const Direction direction, @@ -1081,102 +1080,69 @@ static void justifyMainAxis( float maxAscentForCurrentLine = 0; float maxDescentForCurrentLine = 0; bool isNodeBaselineLayout = isBaselineLayout(node); - for (size_t i = startOfLineIndex; i < flexLine.endOfLineIndex; i++) { - const auto child = node->getChild(i); - const Style& childStyle = child->style(); + for (auto child : flexLine.itemsInFlow) { const LayoutResults& childLayout = child->getLayout(); - if (childStyle.display() == Display::None) { - continue; + if (child->style().flexStartMarginIsAuto(mainAxis, direction) && + flexLine.layout.remainingFreeSpace > 0.0f) { + flexLine.layout.mainDim += flexLine.layout.remainingFreeSpace / + static_cast(flexLine.numberOfAutoMargins); } - if (childStyle.positionType() == PositionType::Absolute && - child->style().isFlexStartPositionDefined(mainAxis, direction) && - !child->style().isFlexStartPositionAuto(mainAxis, direction)) { - if (performLayout) { - // In case the child is position absolute and has left/top being - // defined, we override the position to whatever the user said (and - // margin/border). - child->setLayoutPosition( - child->style().computeFlexStartPosition( - mainAxis, direction, availableInnerMainDim) + - node->style().computeFlexStartBorder(mainAxis, direction) + - child->style().computeFlexStartMargin( - mainAxis, direction, availableInnerWidth), - flexStartEdge(mainAxis)); - } - } else { - // Now that we placed the element, we need to update the variables. - // We need to do that only for relative elements. Absolute elements do not - // take part in that phase. - if (childStyle.positionType() != PositionType::Absolute) { - if (child->style().flexStartMarginIsAuto(mainAxis, direction) && - flexLine.layout.remainingFreeSpace > 0.0f) { - flexLine.layout.mainDim += flexLine.layout.remainingFreeSpace / - static_cast(flexLine.numberOfAutoMargins); - } - if (performLayout) { - child->setLayoutPosition( - childLayout.position(flexStartEdge(mainAxis)) + - flexLine.layout.mainDim, - flexStartEdge(mainAxis)); - } - - if (child != flexLine.itemsInFlow.back()) { - flexLine.layout.mainDim += betweenMainDim; - } + if (performLayout) { + child->setLayoutPosition( + childLayout.position(flexStartEdge(mainAxis)) + + flexLine.layout.mainDim, + flexStartEdge(mainAxis)); + } - if (child->style().flexEndMarginIsAuto(mainAxis, direction) && - flexLine.layout.remainingFreeSpace > 0.0f) { - flexLine.layout.mainDim += flexLine.layout.remainingFreeSpace / - static_cast(flexLine.numberOfAutoMargins); - } - bool canSkipFlex = - !performLayout && sizingModeCrossDim == SizingMode::StretchFit; - if (canSkipFlex) { - // If we skipped the flex step, then we can't rely on the measuredDims - // because they weren't computed. This means we can't call - // dimensionWithMargin. - flexLine.layout.mainDim += child->style().computeMarginForAxis( - mainAxis, availableInnerWidth) + - childLayout.computedFlexBasis.unwrap(); - flexLine.layout.crossDim = availableInnerCrossDim; - } else { - // The main dimension is the sum of all the elements dimension plus - // the spacing. - flexLine.layout.mainDim += - child->dimensionWithMargin(mainAxis, availableInnerWidth); - - if (isNodeBaselineLayout) { - // If the child is baseline aligned then the cross dimension is - // calculated by adding maxAscent and maxDescent from the baseline. - const float ascent = calculateBaseline(child) + - child->style().computeFlexStartMargin( - FlexDirection::Column, direction, availableInnerWidth); - const float descent = - child->getLayout().measuredDimension(Dimension::Height) + - child->style().computeMarginForAxis( - FlexDirection::Column, availableInnerWidth) - - ascent; + if (child != flexLine.itemsInFlow.back()) { + flexLine.layout.mainDim += betweenMainDim; + } - maxAscentForCurrentLine = - yoga::maxOrDefined(maxAscentForCurrentLine, ascent); - maxDescentForCurrentLine = - yoga::maxOrDefined(maxDescentForCurrentLine, descent); - } else { - // The cross dimension is the max of the elements dimension since - // there can only be one element in that cross dimension in the case - // when the items are not baseline aligned - flexLine.layout.crossDim = yoga::maxOrDefined( - flexLine.layout.crossDim, - child->dimensionWithMargin(crossAxis, availableInnerWidth)); - } - } - } else if (performLayout) { - child->setLayoutPosition( - childLayout.position(flexStartEdge(mainAxis)) + - node->style().computeFlexStartBorder(mainAxis, direction) + - leadingMainDim, - flexStartEdge(mainAxis)); + if (child->style().flexEndMarginIsAuto(mainAxis, direction) && + flexLine.layout.remainingFreeSpace > 0.0f) { + flexLine.layout.mainDim += flexLine.layout.remainingFreeSpace / + static_cast(flexLine.numberOfAutoMargins); + } + bool canSkipFlex = + !performLayout && sizingModeCrossDim == SizingMode::StretchFit; + if (canSkipFlex) { + // If we skipped the flex step, then we can't rely on the measuredDims + // because they weren't computed. This means we can't call + // dimensionWithMargin. + flexLine.layout.mainDim += + child->style().computeMarginForAxis(mainAxis, availableInnerWidth) + + childLayout.computedFlexBasis.unwrap(); + flexLine.layout.crossDim = availableInnerCrossDim; + } else { + // The main dimension is the sum of all the elements dimension plus + // the spacing. + flexLine.layout.mainDim += + child->dimensionWithMargin(mainAxis, availableInnerWidth); + + if (isNodeBaselineLayout) { + // If the child is baseline aligned then the cross dimension is + // calculated by adding maxAscent and maxDescent from the baseline. + const float ascent = calculateBaseline(child) + + child->style().computeFlexStartMargin( + FlexDirection::Column, direction, availableInnerWidth); + const float descent = + child->getLayout().measuredDimension(Dimension::Height) + + child->style().computeMarginForAxis( + FlexDirection::Column, availableInnerWidth) - + ascent; + + maxAscentForCurrentLine = + yoga::maxOrDefined(maxAscentForCurrentLine, ascent); + maxDescentForCurrentLine = + yoga::maxOrDefined(maxDescentForCurrentLine, descent); + } else { + // The cross dimension is the max of the elements dimension since + // there can only be one element in that cross dimension in the case + // when the items are not baseline aligned + flexLine.layout.crossDim = yoga::maxOrDefined( + flexLine.layout.crossDim, + child->dimensionWithMargin(crossAxis, availableInnerWidth)); } } } @@ -1616,7 +1582,6 @@ static void calculateLayoutImpl( justifyMainAxis( node, flexLine, - startOfLineIndex, mainAxis, crossAxis, direction, @@ -1668,151 +1633,116 @@ static void calculateLayoutImpl( // STEP 7: CROSS-AXIS ALIGNMENT // We can skip child alignment if we're just measuring the container. if (performLayout) { - for (size_t i = startOfLineIndex; i < endOfLineIndex; i++) { - const auto child = node->getChild(i); - if (child->style().display() == Display::None) { - continue; - } - if (child->style().positionType() == PositionType::Absolute) { - // If the child is absolutely positioned and has a - // top/left/bottom/right set, override all the previously computed - // positions to set it correctly. - const bool isChildLeadingPosDefined = - child->style().isFlexStartPositionDefined(crossAxis, direction) && - !child->style().isFlexStartPositionAuto(crossAxis, direction); - if (isChildLeadingPosDefined) { - child->setLayoutPosition( - child->style().computeFlexStartPosition( - crossAxis, direction, availableInnerCrossDim) + - node->style().computeFlexStartBorder(crossAxis, direction) + - child->style().computeFlexStartMargin( - crossAxis, direction, availableInnerWidth), - flexStartEdge(crossAxis)); - } - // If leading position is not defined or calculations result in Nan, - // default to border + margin - if (!isChildLeadingPosDefined || - yoga::isUndefined( - child->getLayout().position(flexStartEdge(crossAxis)))) { - child->setLayoutPosition( - node->style().computeFlexStartBorder(crossAxis, direction) + - child->style().computeFlexStartMargin( - crossAxis, direction, availableInnerWidth), - flexStartEdge(crossAxis)); + for (auto child : flexLine.itemsInFlow) { + float leadingCrossDim = leadingPaddingAndBorderCross; + + // For a relative children, we're either using alignItems (owner) or + // alignSelf (child) in order to determine the position in the cross + // axis + const Align alignItem = resolveChildAlignment(node, child); + + // If the child uses align stretch, we need to lay it out one more + // time, this time forcing the cross-axis size to be the computed + // cross size for the current line. + if (alignItem == Align::Stretch && + !child->style().flexStartMarginIsAuto(crossAxis, direction) && + !child->style().flexEndMarginIsAuto(crossAxis, direction)) { + // If the child defines a definite size for its cross axis, there's + // no need to stretch. + if (!child->hasDefiniteLength( + dimension(crossAxis), availableInnerCrossDim)) { + float childMainSize = + child->getLayout().measuredDimension(dimension(mainAxis)); + const auto& childStyle = child->style(); + float childCrossSize = childStyle.aspectRatio().isDefined() + ? child->style().computeMarginForAxis( + crossAxis, availableInnerWidth) + + (isMainAxisRow + ? childMainSize / childStyle.aspectRatio().unwrap() + : childMainSize * childStyle.aspectRatio().unwrap()) + : flexLine.layout.crossDim; + + childMainSize += child->style().computeMarginForAxis( + mainAxis, availableInnerWidth); + + SizingMode childMainSizingMode = SizingMode::StretchFit; + SizingMode childCrossSizingMode = SizingMode::StretchFit; + constrainMaxSizeForMode( + child, + direction, + mainAxis, + availableInnerMainDim, + availableInnerWidth, + &childMainSizingMode, + &childMainSize); + constrainMaxSizeForMode( + child, + direction, + crossAxis, + availableInnerCrossDim, + availableInnerWidth, + &childCrossSizingMode, + &childCrossSize); + + const float childWidth = + isMainAxisRow ? childMainSize : childCrossSize; + const float childHeight = + !isMainAxisRow ? childMainSize : childCrossSize; + + auto alignContent = node->style().alignContent(); + auto crossAxisDoesNotGrow = + alignContent != Align::Stretch && isNodeFlexWrap; + const SizingMode childWidthSizingMode = + yoga::isUndefined(childWidth) || + (!isMainAxisRow && crossAxisDoesNotGrow) + ? SizingMode::MaxContent + : SizingMode::StretchFit; + const SizingMode childHeightSizingMode = + yoga::isUndefined(childHeight) || + (isMainAxisRow && crossAxisDoesNotGrow) + ? SizingMode::MaxContent + : SizingMode::StretchFit; + + calculateLayoutInternal( + child, + childWidth, + childHeight, + direction, + childWidthSizingMode, + childHeightSizingMode, + availableInnerWidth, + availableInnerHeight, + true, + LayoutPassReason::kStretch, + layoutMarkerData, + depth, + generationCount); } } else { - float leadingCrossDim = leadingPaddingAndBorderCross; - - // For a relative children, we're either using alignItems (owner) or - // alignSelf (child) in order to determine the position in the cross - // axis - const Align alignItem = resolveChildAlignment(node, child); - - // If the child uses align stretch, we need to lay it out one more - // time, this time forcing the cross-axis size to be the computed - // cross size for the current line. - if (alignItem == Align::Stretch && - !child->style().flexStartMarginIsAuto(crossAxis, direction) && - !child->style().flexEndMarginIsAuto(crossAxis, direction)) { - // If the child defines a definite size for its cross axis, there's - // no need to stretch. - if (!child->hasDefiniteLength( - dimension(crossAxis), availableInnerCrossDim)) { - float childMainSize = - child->getLayout().measuredDimension(dimension(mainAxis)); - const auto& childStyle = child->style(); - float childCrossSize = childStyle.aspectRatio().isDefined() - ? child->style().computeMarginForAxis( - crossAxis, availableInnerWidth) + - (isMainAxisRow - ? childMainSize / childStyle.aspectRatio().unwrap() - : childMainSize * childStyle.aspectRatio().unwrap()) - : flexLine.layout.crossDim; - - childMainSize += child->style().computeMarginForAxis( - mainAxis, availableInnerWidth); - - SizingMode childMainSizingMode = SizingMode::StretchFit; - SizingMode childCrossSizingMode = SizingMode::StretchFit; - constrainMaxSizeForMode( - child, - direction, - mainAxis, - availableInnerMainDim, - availableInnerWidth, - &childMainSizingMode, - &childMainSize); - constrainMaxSizeForMode( - child, - direction, - crossAxis, - availableInnerCrossDim, - availableInnerWidth, - &childCrossSizingMode, - &childCrossSize); - - const float childWidth = - isMainAxisRow ? childMainSize : childCrossSize; - const float childHeight = - !isMainAxisRow ? childMainSize : childCrossSize; - - auto alignContent = node->style().alignContent(); - auto crossAxisDoesNotGrow = - alignContent != Align::Stretch && isNodeFlexWrap; - const SizingMode childWidthSizingMode = - yoga::isUndefined(childWidth) || - (!isMainAxisRow && crossAxisDoesNotGrow) - ? SizingMode::MaxContent - : SizingMode::StretchFit; - const SizingMode childHeightSizingMode = - yoga::isUndefined(childHeight) || - (isMainAxisRow && crossAxisDoesNotGrow) - ? SizingMode::MaxContent - : SizingMode::StretchFit; - - calculateLayoutInternal( - child, - childWidth, - childHeight, - direction, - childWidthSizingMode, - childHeightSizingMode, - availableInnerWidth, - availableInnerHeight, - true, - LayoutPassReason::kStretch, - layoutMarkerData, - depth, - generationCount); - } + const float remainingCrossDim = containerCrossAxis - + child->dimensionWithMargin(crossAxis, availableInnerWidth); + + if (child->style().flexStartMarginIsAuto(crossAxis, direction) && + child->style().flexEndMarginIsAuto(crossAxis, direction)) { + leadingCrossDim += yoga::maxOrDefined(0.0f, remainingCrossDim / 2); + } else if (child->style().flexEndMarginIsAuto(crossAxis, direction)) { + // No-Op + } else if (child->style().flexStartMarginIsAuto( + crossAxis, direction)) { + leadingCrossDim += yoga::maxOrDefined(0.0f, remainingCrossDim); + } else if (alignItem == Align::FlexStart) { + // No-Op + } else if (alignItem == Align::Center) { + leadingCrossDim += remainingCrossDim / 2; } else { - const float remainingCrossDim = containerCrossAxis - - child->dimensionWithMargin(crossAxis, availableInnerWidth); - - if (child->style().flexStartMarginIsAuto(crossAxis, direction) && - child->style().flexEndMarginIsAuto(crossAxis, direction)) { - leadingCrossDim += - yoga::maxOrDefined(0.0f, remainingCrossDim / 2); - } else if (child->style().flexEndMarginIsAuto( - crossAxis, direction)) { - // No-Op - } else if (child->style().flexStartMarginIsAuto( - crossAxis, direction)) { - leadingCrossDim += yoga::maxOrDefined(0.0f, remainingCrossDim); - } else if (alignItem == Align::FlexStart) { - // No-Op - } else if (alignItem == Align::Center) { - leadingCrossDim += remainingCrossDim / 2; - } else { - leadingCrossDim += remainingCrossDim; - } + leadingCrossDim += remainingCrossDim; } - // And we apply the position - child->setLayoutPosition( - child->getLayout().position(flexStartEdge(crossAxis)) + - totalLineCrossDim + leadingCrossDim, - flexStartEdge(crossAxis)); } + // And we apply the position + child->setLayoutPosition( + child->getLayout().position(flexStartEdge(crossAxis)) + + totalLineCrossDim + leadingCrossDim, + flexStartEdge(crossAxis)); } } diff --git a/yoga/enums/Errata.h b/yoga/enums/Errata.h index 1b43742e03..2f47a94175 100644 --- a/yoga/enums/Errata.h +++ b/yoga/enums/Errata.h @@ -18,7 +18,7 @@ namespace facebook::yoga { enum class Errata : uint32_t { None = YGErrataNone, StretchFlexBasis = YGErrataStretchFlexBasis, - AbsolutePositioningIncorrect = YGErrataAbsolutePositioningIncorrect, + AbsolutePositionWithoutInsetsExcludesPadding = YGErrataAbsolutePositionWithoutInsetsExcludesPadding, AbsolutePercentAgainstInnerSize = YGErrataAbsolutePercentAgainstInnerSize, All = YGErrataAll, Classic = YGErrataClassic,