From c7b34609f5e5a09d7f7b43f5e3ecb3454b8aa00f Mon Sep 17 00:00:00 2001 From: Nick Gerleman Date: Thu, 11 May 2023 03:04:13 -0700 Subject: [PATCH] Add errata "PercentAbsoluteOmitsPadding" (#1290) Summary: X-link: https://github.com/facebook/yoga/pull/1290 This change default-enables a bugfix to Yoga's handling of absolute-positioned children sized using percentages. Yoga previously measured percentage of the box without padding, where the W3C spec, and browser behavior verified by test, use the padding box instead. See https://github.com/facebook/yoga/issues/850 for more details of the backing issue. I have so far left this behind a `YGExperimentalFeature`, because it will change the dimensions of existing views which use absolute percentages with parent padding. This change moves it from a `YGExperimentalFeature` to `YGErrata`. This means the conformant path is enabled by default, but users of `YGErrataClassic` and `YGErrataAll` will stay on the previous behavior. Right now the name is `PercentAbsoluteOmitsPadding` as something that tries to explain the issue in lay-terms and be a little less long than the old one, but I am open to other ideas. Differential Revision: https://internalfb.com/D45763574 fbshipit-source-id: 6658adb99ad997518b17b5070a5939a664239384 --- .../java/com/facebook/yoga/YogaErrata.java | 2 + .../yoga/YogaExperimentalFeature.java | 6 +- .../ReactCommon/yoga/yoga/YGEnums.cpp | 4 +- .../ReactCommon/yoga/yoga/YGEnums.h | 2 +- .../ReactCommon/yoga/yoga/Yoga.cpp | 82 ++++++++++--------- 5 files changed, 49 insertions(+), 47 deletions(-) diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/yoga/YogaErrata.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/yoga/YogaErrata.java index 6ae5ac0e7cbf08..c07c1927635f8d 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/yoga/YogaErrata.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/yoga/YogaErrata.java @@ -12,6 +12,7 @@ public enum YogaErrata { NONE(0), STRETCH_FLEX_BASIS(1), + PERCENT_ABSOLUTE_OMITS_PADDING(2), ALL(2147483647), CLASSIC(2147483646); @@ -29,6 +30,7 @@ public static YogaErrata fromInt(int value) { switch (value) { case 0: return NONE; case 1: return STRETCH_FLEX_BASIS; + case 2: return PERCENT_ABSOLUTE_OMITS_PADDING; case 2147483647: return ALL; case 2147483646: return CLASSIC; default: throw new IllegalArgumentException("Unknown enum value: " + value); diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/yoga/YogaExperimentalFeature.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/yoga/YogaExperimentalFeature.java index 3532e45ec87556..46f9f509ad79e3 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/yoga/YogaExperimentalFeature.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/yoga/YogaExperimentalFeature.java @@ -11,8 +11,7 @@ public enum YogaExperimentalFeature { WEB_FLEX_BASIS(0), - ABSOLUTE_PERCENTAGE_AGAINST_PADDING_EDGE(1), - FIX_ABSOLUTE_TRAILING_COLUMN_MARGIN(2); + FIX_ABSOLUTE_TRAILING_COLUMN_MARGIN(1); private final int mIntValue; @@ -27,8 +26,7 @@ public int intValue() { public static YogaExperimentalFeature fromInt(int value) { switch (value) { case 0: return WEB_FLEX_BASIS; - case 1: return ABSOLUTE_PERCENTAGE_AGAINST_PADDING_EDGE; - case 2: return FIX_ABSOLUTE_TRAILING_COLUMN_MARGIN; + case 1: return FIX_ABSOLUTE_TRAILING_COLUMN_MARGIN; default: throw new 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 96b424a3bfd6e9..57b5552d763550 100644 --- a/packages/react-native/ReactCommon/yoga/yoga/YGEnums.cpp +++ b/packages/react-native/ReactCommon/yoga/yoga/YGEnums.cpp @@ -93,6 +93,8 @@ const char* YGErrataToString(const YGErrata value) { return "none"; case YGErrataStretchFlexBasis: return "stretch-flex-basis"; + case YGErrataPercentAbsoluteOmitsPadding: + return "percent-absolute-omits-padding"; case YGErrataAll: return "all"; case YGErrataClassic: @@ -105,8 +107,6 @@ const char* YGExperimentalFeatureToString(const YGExperimentalFeature value) { switch (value) { case YGExperimentalFeatureWebFlexBasis: return "web-flex-basis"; - case YGExperimentalFeatureAbsolutePercentageAgainstPaddingEdge: - return "absolute-percentage-against-padding-edge"; case YGExperimentalFeatureFixAbsoluteTrailingColumnMargin: return "fix-absolute-trailing-column-margin"; } diff --git a/packages/react-native/ReactCommon/yoga/yoga/YGEnums.h b/packages/react-native/ReactCommon/yoga/yoga/YGEnums.h index 72146fe279867e..ba8fb58fbf7ffa 100644 --- a/packages/react-native/ReactCommon/yoga/yoga/YGEnums.h +++ b/packages/react-native/ReactCommon/yoga/yoga/YGEnums.h @@ -58,6 +58,7 @@ YG_ENUM_DECL( YGErrata, YGErrataNone = 0, YGErrataStretchFlexBasis = 1, + YGErrataPercentAbsoluteOmitsPadding = 2, YGErrataAll = 2147483647, YGErrataClassic = 2147483646) YG_DEFINE_ENUM_FLAG_OPERATORS(YGErrata) @@ -65,7 +66,6 @@ YG_DEFINE_ENUM_FLAG_OPERATORS(YGErrata) YG_ENUM_SEQ_DECL( YGExperimentalFeature, YGExperimentalFeatureWebFlexBasis, - YGExperimentalFeatureAbsolutePercentageAgainstPaddingEdge, YGExperimentalFeatureFixAbsoluteTrailingColumnMargin) YG_ENUM_SEQ_DECL( diff --git a/packages/react-native/ReactCommon/yoga/yoga/Yoga.cpp b/packages/react-native/ReactCommon/yoga/yoga/Yoga.cpp index 1eccddbd0f99a8..ce5acc4bf357f2 100644 --- a/packages/react-native/ReactCommon/yoga/yoga/Yoga.cpp +++ b/packages/react-native/ReactCommon/yoga/yoga/Yoga.cpp @@ -1575,21 +1575,21 @@ static void YGNodeAbsoluteLayoutChild( (node->getLayout().measuredDimensions[dim[mainAxis]] - child->getLayout().measuredDimensions[dim[mainAxis]]), leading[mainAxis]); - } else if ( - node->getConfig()->isExperimentalFeatureEnabled( - YGExperimentalFeatureAbsolutePercentageAgainstPaddingEdge) && - child->isLeadingPositionDefined(mainAxis)) { - child->setLayoutPosition( - child->getLeadingPosition( - mainAxis, node->getLayout().measuredDimensions[dim[mainAxis]]) - .unwrap() + - node->getLeadingBorder(mainAxis) + - child - ->getLeadingMargin( - mainAxis, - node->getLayout().measuredDimensions[dim[mainAxis]]) - .unwrap(), - leading[mainAxis]); + } else if (child->isLeadingPositionDefined(mainAxis)) { + if (!child->hasErrata(YGErrataPercentAbsoluteOmitsPadding)) { + child->setLayoutPosition( + child->getLeadingPosition( + mainAxis, + node->getLayout().measuredDimensions[dim[mainAxis]]) + .unwrap() + + node->getLeadingBorder(mainAxis) + + child + ->getLeadingMargin( + mainAxis, + node->getLayout().measuredDimensions[dim[mainAxis]]) + .unwrap(), + leading[mainAxis]); + } } if (child->isTrailingPosDefined(crossAxis) && @@ -1621,22 +1621,21 @@ static void YGNodeAbsoluteLayoutChild( (node->getLayout().measuredDimensions[dim[crossAxis]] - child->getLayout().measuredDimensions[dim[crossAxis]]), leading[crossAxis]); - } else if ( - node->getConfig()->isExperimentalFeatureEnabled( - YGExperimentalFeatureAbsolutePercentageAgainstPaddingEdge) && - child->isLeadingPositionDefined(crossAxis)) { - child->setLayoutPosition( - child->getLeadingPosition( - crossAxis, - node->getLayout().measuredDimensions[dim[crossAxis]]) - .unwrap() + - node->getLeadingBorder(crossAxis) + - child - ->getLeadingMargin( - crossAxis, - node->getLayout().measuredDimensions[dim[crossAxis]]) - .unwrap(), - leading[crossAxis]); + } else if (child->isLeadingPositionDefined(crossAxis)) { + if (!child->hasErrata(YGErrataPercentAbsoluteOmitsPadding)) { + child->setLayoutPosition( + child->getLeadingPosition( + crossAxis, + node->getLayout().measuredDimensions[dim[crossAxis]]) + .unwrap() + + node->getLeadingBorder(crossAxis) + + child + ->getLeadingMargin( + crossAxis, + node->getLayout().measuredDimensions[dim[crossAxis]]) + .unwrap(), + leading[crossAxis]); + } } } @@ -3553,20 +3552,23 @@ static void YGNodelayoutImpl( child->getStyle().positionType() != YGPositionTypeAbsolute) { continue; } - const bool absolutePercentageAgainstPaddingEdge = - node->getConfig()->isExperimentalFeatureEnabled( - YGExperimentalFeatureAbsolutePercentageAgainstPaddingEdge); + const bool percentAbsoluteOmitsPadding = + child->hasErrata(YGErrataPercentAbsoluteOmitsPadding); + + const float width = percentAbsoluteOmitsPadding + ? availableInnerWidth + : node->getLayout().measuredDimensions[YGDimensionWidth]; + + const float height = percentAbsoluteOmitsPadding + ? availableInnerHeight + : node->getLayout().measuredDimensions[YGDimensionHeight]; YGNodeAbsoluteLayoutChild( node, child, - absolutePercentageAgainstPaddingEdge - ? node->getLayout().measuredDimensions[YGDimensionWidth] - : availableInnerWidth, + width, isMainAxisRow ? measureModeMainDim : measureModeCrossDim, - absolutePercentageAgainstPaddingEdge - ? node->getLayout().measuredDimensions[YGDimensionHeight] - : availableInnerHeight, + height, direction, config, layoutMarkerData,