diff --git a/gentest/fixtures/YGFlexBasisFitContentTest.html b/gentest/fixtures/YGFlexBasisFitContentTest.html
index a9176e4ce6..1a1479c1ac 100644
--- a/gentest/fixtures/YGFlexBasisFitContentTest.html
+++ b/gentest/fixtures/YGFlexBasisFitContentTest.html
@@ -53,16 +53,3 @@
-
-
-
diff --git a/java/tests/generated/com/facebook/yoga/YGFlexBasisFitContentTest.java b/java/tests/generated/com/facebook/yoga/YGFlexBasisFitContentTest.java
index 3941362bb5..35cb154122 100644
--- a/java/tests/generated/com/facebook/yoga/YGFlexBasisFitContentTest.java
+++ b/java/tests/generated/com/facebook/yoga/YGFlexBasisFitContentTest.java
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
- * @generated SignedSource<<43053b7b4f9b08ef644e0bb63c44e78f>>
+ * @generated SignedSource<<94d885664d3bbf8c72280e1b61102fce>>
* generated by gentest/src/GentestDriver.ts from gentest/fixtures/YGFlexBasisFitContentTest.html
*/
@@ -385,74 +385,6 @@ public void test_explicit_and_container_children_column() {
assertEquals(500f, root_child1_child0.getLayoutHeight(), 0.0f);
}
- @Test
- public void test_flex_basis_in_scroll_content_container() {
- YogaConfig config = YogaConfigFactory.create();
- config.setExperimentalFeatureEnabled(YogaExperimentalFeature.FIX_FLEX_BASIS_FIT_CONTENT, true);
-
- final YogaNode root = createNode(config);
- root.setPositionType(YogaPositionType.ABSOLUTE);
- root.setWidth(200f);
- root.setHeight(300f);
- root.setOverflow(YogaOverflow.SCROLL);
-
- final YogaNode root_child0 = createNode(config);
- root.addChildAt(root_child0, 0);
-
- final YogaNode root_child0_child0 = createNode(config);
- root_child0_child0.setFlexBasis(200f);
- root_child0.addChildAt(root_child0_child0, 0);
-
- final YogaNode root_child0_child1 = createNode(config);
- root_child0_child1.setFlexBasis(300f);
- root_child0.addChildAt(root_child0_child1, 1);
- root.setDirection(YogaDirection.LTR);
- root.calculateLayout(YogaConstants.UNDEFINED, YogaConstants.UNDEFINED);
-
- assertEquals(0f, root.getLayoutX(), 0.0f);
- assertEquals(0f, root.getLayoutY(), 0.0f);
- assertEquals(200f, root.getLayoutWidth(), 0.0f);
- assertEquals(300f, root.getLayoutHeight(), 0.0f);
-
- assertEquals(0f, root_child0.getLayoutX(), 0.0f);
- assertEquals(0f, root_child0.getLayoutY(), 0.0f);
- assertEquals(200f, root_child0.getLayoutWidth(), 0.0f);
- assertEquals(500f, root_child0.getLayoutHeight(), 0.0f);
-
- assertEquals(0f, root_child0_child0.getLayoutX(), 0.0f);
- assertEquals(0f, root_child0_child0.getLayoutY(), 0.0f);
- assertEquals(200f, root_child0_child0.getLayoutWidth(), 0.0f);
- assertEquals(200f, root_child0_child0.getLayoutHeight(), 0.0f);
-
- assertEquals(0f, root_child0_child1.getLayoutX(), 0.0f);
- assertEquals(200f, root_child0_child1.getLayoutY(), 0.0f);
- assertEquals(200f, root_child0_child1.getLayoutWidth(), 0.0f);
- assertEquals(300f, root_child0_child1.getLayoutHeight(), 0.0f);
-
- root.setDirection(YogaDirection.RTL);
- root.calculateLayout(YogaConstants.UNDEFINED, YogaConstants.UNDEFINED);
-
- assertEquals(0f, root.getLayoutX(), 0.0f);
- assertEquals(0f, root.getLayoutY(), 0.0f);
- assertEquals(200f, root.getLayoutWidth(), 0.0f);
- assertEquals(300f, root.getLayoutHeight(), 0.0f);
-
- assertEquals(0f, root_child0.getLayoutX(), 0.0f);
- assertEquals(0f, root_child0.getLayoutY(), 0.0f);
- assertEquals(200f, root_child0.getLayoutWidth(), 0.0f);
- assertEquals(500f, root_child0.getLayoutHeight(), 0.0f);
-
- assertEquals(0f, root_child0_child0.getLayoutX(), 0.0f);
- assertEquals(0f, root_child0_child0.getLayoutY(), 0.0f);
- assertEquals(200f, root_child0_child0.getLayoutWidth(), 0.0f);
- assertEquals(200f, root_child0_child0.getLayoutHeight(), 0.0f);
-
- assertEquals(0f, root_child0_child1.getLayoutX(), 0.0f);
- assertEquals(200f, root_child0_child1.getLayoutY(), 0.0f);
- assertEquals(200f, root_child0_child1.getLayoutWidth(), 0.0f);
- assertEquals(300f, root_child0_child1.getLayoutHeight(), 0.0f);
- }
-
private YogaNode createNode(YogaConfig config) {
return mNodeFactory.create(config);
}
diff --git a/javascript/tests/generated/YGFlexBasisFitContentTest.test.ts b/javascript/tests/generated/YGFlexBasisFitContentTest.test.ts
index 1606c49697..906e8925f5 100644
--- a/javascript/tests/generated/YGFlexBasisFitContentTest.test.ts
+++ b/javascript/tests/generated/YGFlexBasisFitContentTest.test.ts
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
- * @generated SignedSource<<52cb2c57af8b80a23fa8217c15d0000a>>
+ * @generated SignedSource<<8265f8738bd09131df2e6ef29f0e34d7>>
* generated by gentest/src/GentestDriver.ts from gentest/fixtures/YGFlexBasisFitContentTest.html
*/
@@ -362,68 +362,3 @@ test('explicit_and_container_children_column', () => {
expect(root_child1_child0.getComputedWidth()).toBe(200);
expect(root_child1_child0.getComputedHeight()).toBe(500);
});
-test('flex_basis_in_scroll_content_container', () => {
- const config = Yoga.Config.create();
-
- config.setExperimentalFeatureEnabled(ExperimentalFeature.FixFlexBasisFitContent, true);
-
- const root = Yoga.Node.create(config);
- root.setPositionType(PositionType.Absolute);
- root.setWidth(200);
- root.setHeight(300);
- root.setOverflow(Overflow.Scroll);
-
- const root_child0 = Yoga.Node.create(config);
- root.insertChild(root_child0, 0);
-
- const root_child0_child0 = Yoga.Node.create(config);
- root_child0_child0.setFlexBasis(200);
- root_child0.insertChild(root_child0_child0, 0);
-
- const root_child0_child1 = Yoga.Node.create(config);
- root_child0_child1.setFlexBasis(300);
- root_child0.insertChild(root_child0_child1, 1);
- root.calculateLayout(undefined, undefined, Direction.LTR);
-
- expect(root.getComputedLeft()).toBe(0);
- expect(root.getComputedTop()).toBe(0);
- expect(root.getComputedWidth()).toBe(200);
- expect(root.getComputedHeight()).toBe(300);
-
- expect(root_child0.getComputedLeft()).toBe(0);
- expect(root_child0.getComputedTop()).toBe(0);
- expect(root_child0.getComputedWidth()).toBe(200);
- expect(root_child0.getComputedHeight()).toBe(500);
-
- expect(root_child0_child0.getComputedLeft()).toBe(0);
- expect(root_child0_child0.getComputedTop()).toBe(0);
- expect(root_child0_child0.getComputedWidth()).toBe(200);
- expect(root_child0_child0.getComputedHeight()).toBe(200);
-
- expect(root_child0_child1.getComputedLeft()).toBe(0);
- expect(root_child0_child1.getComputedTop()).toBe(200);
- expect(root_child0_child1.getComputedWidth()).toBe(200);
- expect(root_child0_child1.getComputedHeight()).toBe(300);
-
- root.calculateLayout(undefined, undefined, Direction.RTL);
-
- expect(root.getComputedLeft()).toBe(0);
- expect(root.getComputedTop()).toBe(0);
- expect(root.getComputedWidth()).toBe(200);
- expect(root.getComputedHeight()).toBe(300);
-
- expect(root_child0.getComputedLeft()).toBe(0);
- expect(root_child0.getComputedTop()).toBe(0);
- expect(root_child0.getComputedWidth()).toBe(200);
- expect(root_child0.getComputedHeight()).toBe(500);
-
- expect(root_child0_child0.getComputedLeft()).toBe(0);
- expect(root_child0_child0.getComputedTop()).toBe(0);
- expect(root_child0_child0.getComputedWidth()).toBe(200);
- expect(root_child0_child0.getComputedHeight()).toBe(200);
-
- expect(root_child0_child1.getComputedLeft()).toBe(0);
- expect(root_child0_child1.getComputedTop()).toBe(200);
- expect(root_child0_child1.getComputedWidth()).toBe(200);
- expect(root_child0_child1.getComputedHeight()).toBe(300);
-});
diff --git a/tests/generated/YGFlexBasisFitContentTest.cpp b/tests/generated/YGFlexBasisFitContentTest.cpp
index b1dea09665..2d404f3e2f 100644
--- a/tests/generated/YGFlexBasisFitContentTest.cpp
+++ b/tests/generated/YGFlexBasisFitContentTest.cpp
@@ -5,7 +5,7 @@
* LICENSE file in the root directory of this source tree.
*
* clang-format off
- * @generated SignedSource<>
+ * @generated SignedSource<<19f491407474ad588c9bece89d20c226>>
* generated by gentest/src/GentestDriver.ts from gentest/fixtures/YGFlexBasisFitContentTest.html
*/
@@ -376,72 +376,3 @@ TEST(YogaTest, explicit_and_container_children_column) {
YGConfigFree(config);
}
-
-TEST(YogaTest, flex_basis_in_scroll_content_container) {
- YGConfigRef config = YGConfigNew();
- YGConfigSetExperimentalFeatureEnabled(config, YGExperimentalFeatureFixFlexBasisFitContent, true);
-
- YGNodeRef root = YGNodeNewWithConfig(config);
- YGNodeStyleSetPositionType(root, YGPositionTypeAbsolute);
- YGNodeStyleSetWidth(root, 200);
- YGNodeStyleSetHeight(root, 300);
- YGNodeStyleSetOverflow(root, YGOverflowScroll);
-
- YGNodeRef root_child0 = YGNodeNewWithConfig(config);
- YGNodeInsertChild(root, root_child0, 0);
-
- YGNodeRef root_child0_child0 = YGNodeNewWithConfig(config);
- YGNodeStyleSetFlexBasis(root_child0_child0, 200);
- YGNodeInsertChild(root_child0, root_child0_child0, 0);
-
- YGNodeRef root_child0_child1 = YGNodeNewWithConfig(config);
- YGNodeStyleSetFlexBasis(root_child0_child1, 300);
- YGNodeInsertChild(root_child0, root_child0_child1, 1);
- YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
-
- ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
- ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
- ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root));
- ASSERT_FLOAT_EQ(300, YGNodeLayoutGetHeight(root));
-
- ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
- ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
- ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root_child0));
- ASSERT_FLOAT_EQ(500, YGNodeLayoutGetHeight(root_child0));
-
- ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0));
- ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0));
- ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root_child0_child0));
- ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root_child0_child0));
-
- ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child1));
- ASSERT_FLOAT_EQ(200, YGNodeLayoutGetTop(root_child0_child1));
- ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root_child0_child1));
- ASSERT_FLOAT_EQ(300, YGNodeLayoutGetHeight(root_child0_child1));
-
- YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
-
- ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
- ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
- ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root));
- ASSERT_FLOAT_EQ(300, YGNodeLayoutGetHeight(root));
-
- ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
- ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
- ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root_child0));
- ASSERT_FLOAT_EQ(500, YGNodeLayoutGetHeight(root_child0));
-
- ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0));
- ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0));
- ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root_child0_child0));
- ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root_child0_child0));
-
- ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child1));
- ASSERT_FLOAT_EQ(200, YGNodeLayoutGetTop(root_child0_child1));
- ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root_child0_child1));
- ASSERT_FLOAT_EQ(300, YGNodeLayoutGetHeight(root_child0_child1));
-
- YGNodeFreeRecursive(root);
-
- YGConfigFree(config);
-}
diff --git a/yoga/algorithm/CalculateLayout.cpp b/yoga/algorithm/CalculateLayout.cpp
index e9d62492da..89fbe3cbbb 100644
--- a/yoga/algorithm/CalculateLayout.cpp
+++ b/yoga/algorithm/CalculateLayout.cpp
@@ -6,9 +6,11 @@
*/
#include
+#include
#include
#include
#include
+#include
#include
#include
@@ -35,6 +37,172 @@ namespace facebook::yoga {
std::atomic gCurrentGenerationCount(0);
+static bool hasAutoHorizontalMargin(const Style& style) {
+ for (const auto direction : {Direction::LTR, Direction::RTL}) {
+ if (style.flexStartMarginIsAuto(FlexDirection::Row, direction) ||
+ style.flexEndMarginIsAuto(FlexDirection::Row, direction)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+static bool isColumnStretchEdge(
+ const yoga::Node* const owner,
+ const yoga::Node* const child) {
+ if (owner == nullptr || child == nullptr) {
+ return false;
+ }
+ const auto& ownerStyle = owner->style();
+ const auto& childStyle = child->style();
+ const auto childWidth = child->getProcessedDimension(Dimension::Width);
+ return ownerStyle.display() == Display::Flex &&
+ isColumn(ownerStyle.flexDirection()) &&
+ ownerStyle.flexWrap() == Wrap::NoWrap &&
+ childStyle.positionType() != PositionType::Absolute &&
+ !childStyle.aspectRatio().isDefined() &&
+ (childWidth.isAuto() || childWidth.isUndefined()) &&
+ !hasAutoHorizontalMargin(childStyle) &&
+ resolveChildAlignment(owner, child) == Align::Stretch;
+}
+
+static bool isInColumnStretchScrollSubtree(const yoga::Node* const node) {
+ auto current = node;
+ while (current != nullptr) {
+ auto owner = current->getOwner();
+ while (owner != nullptr && owner->style().display() == Display::Contents) {
+ owner = owner->getOwner();
+ }
+ if (owner == nullptr || !isColumnStretchEdge(owner, current)) {
+ return false;
+ }
+ if (owner->style().overflow() == Overflow::Scroll) {
+ return true;
+ }
+ current = owner;
+ }
+ return false;
+}
+
+static bool isNonZeroLength(const Style::Length& length) {
+ return length.isAuto() ||
+ (length.value().isDefined() && length.value().unwrap() != 0.0f);
+}
+
+static bool hasNonZeroVerticalSpacing(const Style& style) {
+ constexpr std::array verticalEdges = {
+ Edge::Top, Edge::Bottom, Edge::Vertical, Edge::All};
+ for (const auto edge : verticalEdges) {
+ if (isNonZeroLength(style.margin(edge)) ||
+ isNonZeroLength(style.padding(edge)) ||
+ isNonZeroLength(style.border(edge))) {
+ return true;
+ }
+ }
+ return false;
+}
+
+static bool hasPercentageLength(const Style& style) {
+ constexpr std::array edges = {
+ Edge::Left,
+ Edge::Top,
+ Edge::Right,
+ Edge::Bottom,
+ Edge::Start,
+ Edge::End,
+ Edge::Horizontal,
+ Edge::Vertical,
+ Edge::All};
+ for (const auto edge : edges) {
+ if (style.margin(edge).isPercent() || style.position(edge).isPercent() ||
+ style.padding(edge).isPercent() || style.border(edge).isPercent()) {
+ return true;
+ }
+ }
+
+ constexpr std::array dimensions = {
+ Dimension::Width, Dimension::Height};
+ for (const auto dimension : dimensions) {
+ if (style.dimension(dimension).isPercent() ||
+ style.minDimension(dimension).isPercent() ||
+ style.maxDimension(dimension).isPercent()) {
+ return true;
+ }
+ }
+
+ return style.flexBasis().isPercent() ||
+ style.gap(Gutter::Column).isPercent() ||
+ style.gap(Gutter::Row).isPercent() || style.gap(Gutter::All).isPercent();
+}
+
+static bool hasNonZeroFlex(const yoga::Node& node) {
+ const auto& style = node.style();
+ const auto flex = style.flex();
+ const auto flexGrow = style.flexGrow();
+ const auto flexShrink = style.flexShrink();
+ const auto config = node.getConfig();
+ const bool canGrow = flexGrow.isDefined()
+ ? flexGrow.unwrap() != 0.0f
+ : flex.isDefined() && flex.unwrap() > 0.0f;
+ const bool canShrink = flexShrink.isDefined()
+ ? flexShrink.unwrap() != 0.0f
+ : (config != nullptr && config->useWebDefaults()) ||
+ (flex.isDefined() && flex.unwrap() < 0.0f);
+ return canGrow || canShrink;
+}
+
+static bool isHeightFitContentIndependent(const yoga::Node& node) {
+ const auto& style = node.style();
+ const auto height = style.dimension(Dimension::Height);
+ const auto flexBasis = style.flexBasis();
+ const bool hasRelativePercentPosition =
+ style.position(Edge::Top).isPercent() ||
+ style.position(Edge::Bottom).isPercent() ||
+ style.position(Edge::Vertical).isPercent() ||
+ style.position(Edge::All).isPercent();
+ return !node.hasMeasureFunc() && !node.hasMinContentMeasureFunc() &&
+ !node.hasBaselineFunc() && !node.isReferenceBaseline() &&
+ (height.isAuto() || height.isUndefined()) &&
+ style.minDimension(Dimension::Height).isUndefined() &&
+ style.maxDimension(Dimension::Height).isUndefined() &&
+ (flexBasis.isAuto() || flexBasis.isUndefined()) &&
+ !hasNonZeroFlex(node) && style.boxSizing() == BoxSizing::BorderBox &&
+ !style.aspectRatio().isDefined() &&
+ style.positionType() != PositionType::Absolute &&
+ style.overflow() != Overflow::Scroll &&
+ style.display() == Display::Flex && isColumn(style.flexDirection()) &&
+ style.alignItems() == Align::Stretch &&
+ (style.alignSelf() == Align::Auto ||
+ style.alignSelf() == Align::Stretch) &&
+ style.justifyContent() == Justify::FlexStart &&
+ style.flexWrap() == Wrap::NoWrap && !style.gap(Gutter::All).isDefined() &&
+ !style.gap(Gutter::Row).isDefined() && !hasRelativePercentPosition &&
+ !hasNonZeroVerticalSpacing(style) && !hasPercentageLength(style);
+}
+
+static bool canSkipHeightFitContent(const yoga::Node* const root) {
+ if (root == nullptr) {
+ return false;
+ }
+
+ constexpr std::size_t maxPendingNodes = 64;
+ std::array stack{root};
+ std::size_t stackSize = 1;
+ while (stackSize > 0) {
+ const auto node = stack[--stackSize];
+ if (node == nullptr || !isHeightFitContentIndependent(*node)) {
+ return false;
+ }
+ for (const auto child : node->getLayoutChildren()) {
+ if (stackSize == stack.size()) {
+ return false;
+ }
+ stack[stackSize++] = child;
+ }
+ }
+ return true;
+}
+
void constrainMaxSizeForMode(
const yoga::Node* node,
Direction direction,
@@ -98,12 +266,8 @@ static void computeFlexBasisForChild(
node->getConfig()->isExperimentalFeatureEnabled(
ExperimentalFeature::FixFlexBasisFitContent);
- bool useResolvedFlexBasis =
+ const bool useResolvedFlexBasis =
resolvedFlexBasis.isDefined() && yoga::isDefined(mainAxisSize);
- if (fixFlexBasisFitContent && resolvedFlexBasis.isDefined() &&
- resolvedFlexBasis.unwrap() > 0) {
- useResolvedFlexBasis = true;
- }
if (useResolvedFlexBasis) {
if (child->getLayout().computedFlexBasis.isUndefined() ||
@@ -175,32 +339,27 @@ static void computeFlexBasisForChild(
}
}
- // For height in the main axis (column direction): when the
- // FixFlexBasisFitContent feature is enabled, skip FitContent for
- // non-measure container children inside scroll subtrees. This makes the
- // flex basis independent of content-determined heights, preventing
- // unnecessary re-measurement cascades when a sibling changes size in a
- // ScrollView, while preserving viewport bounds for wrappers outside the
- // scroll subtree.
- //
- // We only optimize the height (column) axis because text wrapping depends
- // on width constraints propagating through container nodes. Removing
- // FitContent from the width axis would cause text inside nested
- // containers to stop wrapping.
- bool applyHeightFitContent =
- isMainAxisRow || node->style().overflow() != Overflow::Scroll;
+ // A zero-intrinsic-height column subtree has the same layout with an
+ // unbounded height, allowing its measurement cache to survive unrelated
+ // size changes elsewhere in a vertical scroll subtree.
+ const bool parentDoesNotScroll =
+ node != nullptr && node->style().overflow() != Overflow::Scroll;
+ bool applyHeightFitContent = isMainAxisRow || parentDoesNotScroll;
if (fixFlexBasisFitContent) {
- bool nodeHasScrollAncestor = false;
- for (auto owner = node->getOwner(); owner != nullptr;
- owner = owner->getOwner()) {
- if (owner->style().overflow() == Overflow::Scroll) {
- nodeHasScrollAncestor = true;
- break;
- }
+ const bool childHadOverflow = child != nullptr && child->isDirty() &&
+ child->getLayout().hadOverflow();
+ const bool hasHeightIndependentSubtree = node != nullptr &&
+ child != nullptr && !isMainAxisRow && parentDoesNotScroll &&
+ yoga::isUndefined(childHeight) && yoga::isDefined(height) &&
+ isColumnStretchEdge(node, child) &&
+ isInColumnStretchScrollSubtree(node) &&
+ canSkipHeightFitContent(child);
+ if (hasHeightIndependentSubtree && childHadOverflow) {
+ child->setLayoutHadOverflow(false);
+ }
+ if (hasHeightIndependentSubtree) {
+ applyHeightFitContent = false;
}
- applyHeightFitContent = isMainAxisRow ||
- ((child->hasMeasureFunc() || !nodeHasScrollAncestor) &&
- node->style().overflow() != Overflow::Scroll);
}
if (applyHeightFitContent && yoga::isUndefined(childHeight) &&
yoga::isDefined(height)) {
@@ -1565,6 +1724,12 @@ static void calculateLayoutImpl(
// Set the resolved resolution in the node's layout.
const Direction direction = node->resolveDirection(ownerDirection);
node->setLayoutDirection(direction);
+ const bool fixFlexBasisFitContent =
+ node->getConfig()->isExperimentalFeatureEnabled(
+ ExperimentalFeature::FixFlexBasisFitContent);
+ if (fixFlexBasisFitContent && performLayout) {
+ node->setLayoutHadOverflow(false);
+ }
const FlexDirection flexRowDirection =
resolveDirection(FlexDirection::Row, direction);
@@ -1680,9 +1845,9 @@ static void calculateLayoutImpl(
// At this point we know we're going to perform work. Ensure that each child
// has a mutable copy.
node->cloneChildrenIfNeeded();
- // Reset layout flags, as they could have changed.
- node->setLayoutHadOverflow(false);
-
+ if (!fixFlexBasisFitContent || !performLayout) {
+ node->setLayoutHadOverflow(false);
+ }
// Clean and update all display: contents nodes with a direct path to the
// current node as they will not be traversed
cleanupContentsNodesRecursively(node, performLayout);
@@ -1741,53 +1906,14 @@ static void calculateLayoutImpl(
// STEP 3: DETERMINE FLEX BASIS FOR EACH ITEM
- // When this node is measured with MaxContent (FixFlexBasisFitContent
- // behavior), availableInnerHeight is NaN.
- // To preserve percentage resolution for descendants, derive a definite
- // owner-size from the parent-provided ownerHeight.
- float ownerWidthForChildren = availableInnerWidth;
- float ownerHeightForChildren = availableInnerHeight;
-
- if (node->getConfig()->isExperimentalFeatureEnabled(
- ExperimentalFeature::FixFlexBasisFitContent)) {
- const auto* owner = node->getOwner();
- const bool isChildOfScrollContainer =
- owner != nullptr && owner->style().overflow() == Overflow::Scroll;
-
- if (!isChildOfScrollContainer) {
- if (yoga::isUndefined(ownerWidthForChildren) &&
- yoga::isDefined(ownerWidth)) {
- ownerWidthForChildren = calculateAvailableInnerDimension(
- node,
- direction,
- Dimension::Width,
- ownerWidth - marginAxisRow,
- paddingAndBorderAxisRow,
- ownerWidth,
- ownerWidth);
- }
- if (yoga::isUndefined(ownerHeightForChildren) &&
- yoga::isDefined(ownerHeight)) {
- ownerHeightForChildren = calculateAvailableInnerDimension(
- node,
- direction,
- Dimension::Height,
- ownerHeight - marginAxisColumn,
- paddingAndBorderAxisColumn,
- ownerHeight,
- ownerWidth);
- }
- }
- }
-
// Computed basis + margins + gap
float totalMainDim = 0;
totalMainDim += computeFlexBasisForChildren(
node,
availableInnerWidth,
availableInnerHeight,
- ownerWidthForChildren,
- ownerHeightForChildren,
+ availableInnerWidth,
+ availableInnerHeight,
widthSizingMode,
heightSizingMode,
direction,
@@ -2724,7 +2850,8 @@ void calculateLayout(
// Increment the generation count. This will force the recursive routine to
// visit all dirty nodes at least once. Subsequent visits will be skipped if
// the input parameters don't change.
- gCurrentGenerationCount.fetch_add(1, std::memory_order_relaxed);
+ const uint32_t currentGenerationCount =
+ gCurrentGenerationCount.fetch_add(1, std::memory_order_relaxed) + 1;
node->processDimensions();
const Direction direction = node->resolveDirection(ownerDirection);
float width = YGUndefined;
@@ -2781,6 +2908,11 @@ void calculateLayout(
heightSizingMode = yoga::isUndefined(height) ? SizingMode::MaxContent
: SizingMode::StretchFit;
}
+ const uint32_t generationCount =
+ node->getConfig()->isExperimentalFeatureEnabled(
+ ExperimentalFeature::FixFlexBasisFitContent)
+ ? currentGenerationCount
+ : gCurrentGenerationCount.load(std::memory_order_relaxed);
if (calculateLayoutInternal(
node,
width,
@@ -2794,7 +2926,7 @@ void calculateLayout(
LayoutPassReason::kInitial,
markerData,
0, // tree root
- gCurrentGenerationCount.load(std::memory_order_relaxed))) {
+ generationCount)) {
node->setPosition(node->getLayout().direction(), ownerWidth, ownerHeight);
roundLayoutResultsToPixelGrid(node, 0.0f, 0.0f);
}