diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/yoga/YogaErrata.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/yoga/YogaErrata.kt index ff2bcaf1b637..c9196745e8f2 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/yoga/YogaErrata.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/yoga/YogaErrata.kt @@ -16,6 +16,7 @@ public enum class YogaErrata(public val intValue: Int) { ABSOLUTE_PERCENT_AGAINST_INNER_SIZE(4), MIN_SIZE_UNDEFINED_INSTEAD_OF_AUTO(8), FLEX_FIRST_PASS_USES_RUNNING_TOTALS(16), + WRAP_CROSS_ALIGNMENT_IGNORES_MARGIN_AND_INSET(32), ALL(2147483647), CLASSIC(2147483646); @@ -31,6 +32,7 @@ public enum class YogaErrata(public val intValue: Int) { 4 -> ABSOLUTE_PERCENT_AGAINST_INNER_SIZE 8 -> MIN_SIZE_UNDEFINED_INSTEAD_OF_AUTO 16 -> FLEX_FIRST_PASS_USES_RUNNING_TOTALS + 32 -> WRAP_CROSS_ALIGNMENT_IGNORES_MARGIN_AND_INSET 2147483647 -> ALL 2147483646 -> CLASSIC else -> throw IllegalArgumentException("Unknown enum value: $value") diff --git a/packages/react-native/ReactCommon/yoga/yoga/YGEnums.cpp b/packages/react-native/ReactCommon/yoga/yoga/YGEnums.cpp index 017d6ee45ad0..6b82c47ba8a5 100644 --- a/packages/react-native/ReactCommon/yoga/yoga/YGEnums.cpp +++ b/packages/react-native/ReactCommon/yoga/yoga/YGEnums.cpp @@ -121,6 +121,8 @@ const char* YGErrataToString(const YGErrata value) { return "min-size-undefined-instead-of-auto"; case YGErrataFlexFirstPassUsesRunningTotals: return "flex-first-pass-uses-running-totals"; + case YGErrataWrapCrossAlignmentIgnoresMarginAndInset: + return "wrap-cross-alignment-ignores-margin-and-inset"; case YGErrataAll: return "all"; case YGErrataClassic: diff --git a/packages/react-native/ReactCommon/yoga/yoga/YGEnums.h b/packages/react-native/ReactCommon/yoga/yoga/YGEnums.h index c672870023aa..d5c5937b8f25 100644 --- a/packages/react-native/ReactCommon/yoga/yoga/YGEnums.h +++ b/packages/react-native/ReactCommon/yoga/yoga/YGEnums.h @@ -69,6 +69,7 @@ YG_ENUM_DECL( YGErrataAbsolutePercentAgainstInnerSize = 4, YGErrataMinSizeUndefinedInsteadOfAuto = 8, YGErrataFlexFirstPassUsesRunningTotals = 16, + YGErrataWrapCrossAlignmentIgnoresMarginAndInset = 32, YGErrataAll = 2147483647, YGErrataClassic = 2147483646) YG_DEFINE_ENUM_FLAG_OPERATORS(YGErrata) diff --git a/packages/react-native/ReactCommon/yoga/yoga/algorithm/CalculateLayout.cpp b/packages/react-native/ReactCommon/yoga/yoga/algorithm/CalculateLayout.cpp index 192a6af77da9..263d2e6cd8df 100644 --- a/packages/react-native/ReactCommon/yoga/yoga/algorithm/CalculateLayout.cpp +++ b/packages/react-native/ReactCommon/yoga/yoga/algorithm/CalculateLayout.cpp @@ -2325,6 +2325,13 @@ static void calculateLayoutImpl( float leadPerLine = 0; float currentLead = leadingPaddingAndBorderCross; float extraSpacePerLine = 0; + // With wrap-reverse the cross positions set here are mirrored further + // below, so an item's flex end margin is the one that leads here. + const bool isWrapReverse = node->style().flexWrap() == Wrap::WrapReverse; + // The erratum keeps the cross positions this pass produced before it + // honored margins and relative insets. + const bool ignoresCrossMarginAndInset = + node->hasErrata(Errata::WrapCrossAlignmentIgnoresMarginAndInset); const float unclampedCrossDim = sizingModeCrossDim == SizingMode::StretchFit ? availableInnerCrossDim + paddingAndBorderAxisCross @@ -2443,43 +2450,69 @@ static void calculateLayoutImpl( continue; } if (child->style().positionType() != PositionType::Absolute) { + const float flexStartMargin = child->style().computeFlexStartMargin( + crossAxis, direction, availableInnerWidth); + const float flexEndMargin = child->style().computeFlexEndMargin( + crossAxis, direction, availableInnerWidth); + // The erratum leaves the margins unswapped for wrap-reverse and + // drops the inset. Flex start, center and baseline used other + // offsets there, so they check the erratum themselves. + const bool reverseMargins = + isWrapReverse && !ignoresCrossMarginAndInset; + const float leadingCrossMargin = + reverseMargins ? flexEndMargin : flexStartMargin; + const float trailingCrossMargin = + reverseMargins ? flexStartMargin : flexEndMargin; + const float relativePositionCross = ignoresCrossMarginAndInset + ? 0.0f + : child->relativePosition( + crossAxis, direction, availableInnerCrossDim); + switch (resolveChildAlignment(node, child)) { case Align::Start: case Align::End: // Not yet implemented break; case Align::FlexStart: { - child->setLayoutPosition( - currentLead + - child->style().computeFlexStartPosition( - crossAxis, direction, availableInnerWidth), - flexStartEdge(crossAxis)); + if (ignoresCrossMarginAndInset) { + child->setLayoutPosition( + currentLead + + child->style().computeFlexStartPosition( + crossAxis, direction, availableInnerWidth), + flexStartEdge(crossAxis)); + } else { + child->setLayoutPosition( + currentLead + leadingCrossMargin + relativePositionCross, + flexStartEdge(crossAxis)); + } break; } case Align::FlexEnd: { child->setLayoutPosition( - currentLead + lineHeight - - child->style().computeFlexEndMargin( - crossAxis, direction, availableInnerWidth) - + currentLead + lineHeight - trailingCrossMargin - child->getLayout().measuredDimension( - dimension(crossAxis)), + dimension(crossAxis)) + + relativePositionCross, flexStartEdge(crossAxis)); break; } case Align::Center: { - float childHeight = + const float childCrossDim = child->getLayout().measuredDimension(dimension(crossAxis)); + const float childOuterCrossDim = + childCrossDim + leadingCrossMargin + trailingCrossMargin; child->setLayoutPosition( - currentLead + (lineHeight - childHeight) / 2, + ignoresCrossMarginAndInset + ? currentLead + (lineHeight - childCrossDim) / 2 + : currentLead + (lineHeight - childOuterCrossDim) / 2 + + leadingCrossMargin + relativePositionCross, flexStartEdge(crossAxis)); break; } case Align::Stretch: { child->setLayoutPosition( - currentLead + - child->style().computeFlexStartMargin( - crossAxis, direction, availableInnerWidth), + currentLead + leadingCrossMargin + relativePositionCross, flexStartEdge(crossAxis)); // Remeasure child with the line height as it as been only @@ -2528,10 +2561,12 @@ static void calculateLayoutImpl( child->setLayoutPosition( currentLead + maxAscentForCurrentLine - calculateBaseline(child) + - child->style().computeFlexStartPosition( - FlexDirection::Column, - direction, - availableInnerCrossDim), + (ignoresCrossMarginAndInset + ? child->style().computeFlexStartPosition( + FlexDirection::Column, + direction, + availableInnerCrossDim) + : relativePositionCross), PhysicalEdge::Top); break; @@ -2643,14 +2678,28 @@ static void calculateLayoutImpl( } // As we only wrapped in normal direction yet, we need to reverse the - // positions on wrap-reverse. + // positions on wrap-reverse. A relative inset is a physical offset, so it is + // taken out before reversing and added back afterwards (the erratum mirrors + // it with the rest of the position). if (performLayout && node->style().flexWrap() == Wrap::WrapReverse) { + const bool ignoresCrossMarginAndInset = + node->hasErrata(Errata::WrapCrossAlignmentIgnoresMarginAndInset); for (auto child : node->getLayoutChildren()) { if (child->style().positionType() != PositionType::Absolute) { + const float relativePositionCross = + child->style().display() == Display::None || + ignoresCrossMarginAndInset + ? 0.0f + : child->relativePosition( + crossAxis, direction, availableInnerCrossDim); + const float positionInFlow = + child->getLayout().position(flexStartEdge(crossAxis)) - + relativePositionCross; child->setLayoutPosition( node->getLayout().measuredDimension(dimension(crossAxis)) - - child->getLayout().position(flexStartEdge(crossAxis)) - - child->getLayout().measuredDimension(dimension(crossAxis)), + positionInFlow - + child->getLayout().measuredDimension(dimension(crossAxis)) + + relativePositionCross, flexStartEdge(crossAxis)); } } diff --git a/packages/react-native/ReactCommon/yoga/yoga/enums/Errata.h b/packages/react-native/ReactCommon/yoga/yoga/enums/Errata.h index 09e6f83a3eba..a9fdb344f94b 100644 --- a/packages/react-native/ReactCommon/yoga/yoga/enums/Errata.h +++ b/packages/react-native/ReactCommon/yoga/yoga/enums/Errata.h @@ -22,6 +22,7 @@ enum class Errata : uint32_t { AbsolutePercentAgainstInnerSize = YGErrataAbsolutePercentAgainstInnerSize, MinSizeUndefinedInsteadOfAuto = YGErrataMinSizeUndefinedInsteadOfAuto, FlexFirstPassUsesRunningTotals = YGErrataFlexFirstPassUsesRunningTotals, + WrapCrossAlignmentIgnoresMarginAndInset = YGErrataWrapCrossAlignmentIgnoresMarginAndInset, All = YGErrataAll, Classic = YGErrataClassic, }; diff --git a/scripts/cxx-api/api-snapshots/ReactAndroidDebugCxx.api b/scripts/cxx-api/api-snapshots/ReactAndroidDebugCxx.api index 0b8d391a4639..d0f5ce8daf55 100644 --- a/scripts/cxx-api/api-snapshots/ReactAndroidDebugCxx.api +++ b/scripts/cxx-api/api-snapshots/ReactAndroidDebugCxx.api @@ -6930,6 +6930,7 @@ enum facebook::yoga::Errata : uint32_t { MinSizeUndefinedInsteadOfAuto, None, StretchFlexBasis, + WrapCrossAlignmentIgnoresMarginAndInset, } enum facebook::yoga::FlexDirection : uint8_t { diff --git a/scripts/cxx-api/api-snapshots/ReactAndroidFrameworksCxx.api b/scripts/cxx-api/api-snapshots/ReactAndroidFrameworksCxx.api index 063d23740fac..ab27355f4213 100644 --- a/scripts/cxx-api/api-snapshots/ReactAndroidFrameworksCxx.api +++ b/scripts/cxx-api/api-snapshots/ReactAndroidFrameworksCxx.api @@ -11380,6 +11380,7 @@ enum facebook::yoga::Errata : uint32_t { MinSizeUndefinedInsteadOfAuto, None, StretchFlexBasis, + WrapCrossAlignmentIgnoresMarginAndInset, } enum facebook::yoga::FlexDirection : uint8_t { diff --git a/scripts/cxx-api/api-snapshots/ReactAndroidNewarchCxx.api b/scripts/cxx-api/api-snapshots/ReactAndroidNewarchCxx.api index 636dea874c76..e3effbfe8c50 100644 --- a/scripts/cxx-api/api-snapshots/ReactAndroidNewarchCxx.api +++ b/scripts/cxx-api/api-snapshots/ReactAndroidNewarchCxx.api @@ -6779,6 +6779,7 @@ enum facebook::yoga::Errata : uint32_t { MinSizeUndefinedInsteadOfAuto, None, StretchFlexBasis, + WrapCrossAlignmentIgnoresMarginAndInset, } enum facebook::yoga::FlexDirection : uint8_t { diff --git a/scripts/cxx-api/api-snapshots/ReactAndroidReleaseCxx.api b/scripts/cxx-api/api-snapshots/ReactAndroidReleaseCxx.api index 636dea874c76..e3effbfe8c50 100644 --- a/scripts/cxx-api/api-snapshots/ReactAndroidReleaseCxx.api +++ b/scripts/cxx-api/api-snapshots/ReactAndroidReleaseCxx.api @@ -6779,6 +6779,7 @@ enum facebook::yoga::Errata : uint32_t { MinSizeUndefinedInsteadOfAuto, None, StretchFlexBasis, + WrapCrossAlignmentIgnoresMarginAndInset, } enum facebook::yoga::FlexDirection : uint8_t { diff --git a/scripts/cxx-api/api-snapshots/ReactAppleDebugCxx.api b/scripts/cxx-api/api-snapshots/ReactAppleDebugCxx.api index 369407ed545c..86911ca94015 100644 --- a/scripts/cxx-api/api-snapshots/ReactAppleDebugCxx.api +++ b/scripts/cxx-api/api-snapshots/ReactAppleDebugCxx.api @@ -8682,6 +8682,7 @@ enum facebook::yoga::Errata : uint32_t { MinSizeUndefinedInsteadOfAuto, None, StretchFlexBasis, + WrapCrossAlignmentIgnoresMarginAndInset, } enum facebook::yoga::FlexDirection : uint8_t { diff --git a/scripts/cxx-api/api-snapshots/ReactAppleFrameworksCxx.api b/scripts/cxx-api/api-snapshots/ReactAppleFrameworksCxx.api index 1fd4521efc72..2a2809b8d8f4 100644 --- a/scripts/cxx-api/api-snapshots/ReactAppleFrameworksCxx.api +++ b/scripts/cxx-api/api-snapshots/ReactAppleFrameworksCxx.api @@ -13165,6 +13165,7 @@ enum facebook::yoga::Errata : uint32_t { MinSizeUndefinedInsteadOfAuto, None, StretchFlexBasis, + WrapCrossAlignmentIgnoresMarginAndInset, } enum facebook::yoga::FlexDirection : uint8_t { diff --git a/scripts/cxx-api/api-snapshots/ReactAppleNewarchCxx.api b/scripts/cxx-api/api-snapshots/ReactAppleNewarchCxx.api index df4b2417b5af..946d58d82ae7 100644 --- a/scripts/cxx-api/api-snapshots/ReactAppleNewarchCxx.api +++ b/scripts/cxx-api/api-snapshots/ReactAppleNewarchCxx.api @@ -8534,6 +8534,7 @@ enum facebook::yoga::Errata : uint32_t { MinSizeUndefinedInsteadOfAuto, None, StretchFlexBasis, + WrapCrossAlignmentIgnoresMarginAndInset, } enum facebook::yoga::FlexDirection : uint8_t { diff --git a/scripts/cxx-api/api-snapshots/ReactAppleReleaseCxx.api b/scripts/cxx-api/api-snapshots/ReactAppleReleaseCxx.api index 3db0e926dc1e..e8fde4f81ecf 100644 --- a/scripts/cxx-api/api-snapshots/ReactAppleReleaseCxx.api +++ b/scripts/cxx-api/api-snapshots/ReactAppleReleaseCxx.api @@ -8541,6 +8541,7 @@ enum facebook::yoga::Errata : uint32_t { MinSizeUndefinedInsteadOfAuto, None, StretchFlexBasis, + WrapCrossAlignmentIgnoresMarginAndInset, } enum facebook::yoga::FlexDirection : uint8_t { diff --git a/scripts/cxx-api/api-snapshots/ReactCommonDebugCxx.api b/scripts/cxx-api/api-snapshots/ReactCommonDebugCxx.api index dfbc4d44eccf..fdeca96fe01c 100644 --- a/scripts/cxx-api/api-snapshots/ReactCommonDebugCxx.api +++ b/scripts/cxx-api/api-snapshots/ReactCommonDebugCxx.api @@ -4165,6 +4165,7 @@ enum facebook::yoga::Errata : uint32_t { MinSizeUndefinedInsteadOfAuto, None, StretchFlexBasis, + WrapCrossAlignmentIgnoresMarginAndInset, } enum facebook::yoga::FlexDirection : uint8_t { diff --git a/scripts/cxx-api/api-snapshots/ReactCommonFrameworksCxx.api b/scripts/cxx-api/api-snapshots/ReactCommonFrameworksCxx.api index 40d47068ebce..76753b327e6f 100644 --- a/scripts/cxx-api/api-snapshots/ReactCommonFrameworksCxx.api +++ b/scripts/cxx-api/api-snapshots/ReactCommonFrameworksCxx.api @@ -8513,6 +8513,7 @@ enum facebook::yoga::Errata : uint32_t { MinSizeUndefinedInsteadOfAuto, None, StretchFlexBasis, + WrapCrossAlignmentIgnoresMarginAndInset, } enum facebook::yoga::FlexDirection : uint8_t { diff --git a/scripts/cxx-api/api-snapshots/ReactCommonNewarchCxx.api b/scripts/cxx-api/api-snapshots/ReactCommonNewarchCxx.api index 845fb97ab917..35e5ef9137d8 100644 --- a/scripts/cxx-api/api-snapshots/ReactCommonNewarchCxx.api +++ b/scripts/cxx-api/api-snapshots/ReactCommonNewarchCxx.api @@ -4158,6 +4158,7 @@ enum facebook::yoga::Errata : uint32_t { MinSizeUndefinedInsteadOfAuto, None, StretchFlexBasis, + WrapCrossAlignmentIgnoresMarginAndInset, } enum facebook::yoga::FlexDirection : uint8_t { diff --git a/scripts/cxx-api/api-snapshots/ReactCommonReleaseCxx.api b/scripts/cxx-api/api-snapshots/ReactCommonReleaseCxx.api index 845fb97ab917..35e5ef9137d8 100644 --- a/scripts/cxx-api/api-snapshots/ReactCommonReleaseCxx.api +++ b/scripts/cxx-api/api-snapshots/ReactCommonReleaseCxx.api @@ -4158,6 +4158,7 @@ enum facebook::yoga::Errata : uint32_t { MinSizeUndefinedInsteadOfAuto, None, StretchFlexBasis, + WrapCrossAlignmentIgnoresMarginAndInset, } enum facebook::yoga::FlexDirection : uint8_t {