[FlexNG] MinBlockSizeShouldEncompassIntrinsicSize update

Update the MinBlockSizeShouldEncompassIntrinsicSize() definition to
more accurately handle flex items during fragmentation. Credit to
ikilpatrick@ for figuring out the correct logic.

A couple of row specific tests were updated to match the new behavior,
and a bunch of column specific tests were added to check various
combinations of use cases.

Bug: 660611
Change-Id: I1d9dded7189ab2d7b0c8c3e60c7f24e9c711212b
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3600998
Commit-Queue: Alison Maher <almaher@microsoft.com>
Reviewed-by: Ian Kilpatrick <ikilpatrick@chromium.org>
Cr-Commit-Position: refs/heads/main@{#996810}
diff --git a/third_party/blink/renderer/core/layout/ng/flex/ng_flex_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/flex/ng_flex_layout_algorithm.cc
index 4731f89..088053a 100644
--- a/third_party/blink/renderer/core/layout/ng/flex/ng_flex_layout_algorithm.cc
+++ b/third_party/blink/renderer/core/layout/ng/flex/ng_flex_layout_algorithm.cc
@@ -162,29 +162,6 @@
   return AxisEdge::kStart;
 }
 
-// We are interested in cases where the flex item *may* expand due to
-// fragmentation (lines pushed down by a fragmentation line, etc).
-bool MinBlockSizeShouldEncompassIntrinsicSize(const NGFlexItem& item) {
-  // If this item has (any) descendant that is percentage based, we can end
-  // up in a situation where we'll constantly try and expand the row. E.g.
-  // <div style="display: flex;">
-  //   <div style="min-height: 100px;">
-  //     <div style="height: 200%;"></div>
-  //   </div>
-  // </div>
-  if (item.has_descendant_that_depends_on_percentage_block_size)
-    return false;
-
-  if (item.ng_input_node.IsMonolithic())
-    return false;
-
-  // TODO(almaher): Figure out which cases this should be true. (Should this
-  // only be true when min-block-size is auto in the case of |is_column_|?)
-  // Also, should this be the same in the case of a row flex container?
-  const auto& item_style = item.ng_input_node.Style();
-  return item_style.LogicalHeight().IsAutoOrContentOrIntrinsic();
-}
-
 }  // namespace
 
 void NGFlexLayoutAlgorithm::HandleOutOfFlowPositionedItems(
@@ -2405,6 +2382,57 @@
   return algorithm_with_row_cross_sizes.Layout();
 }
 
+// We are interested in cases where the flex item *may* expand due to
+// fragmentation (lines pushed down by a fragmentation line, etc).
+bool NGFlexLayoutAlgorithm::MinBlockSizeShouldEncompassIntrinsicSize(
+    const NGFlexItem& item) const {
+  // If this item has (any) descendant that is percentage based, we can end
+  // up in a situation where we'll constantly try and expand the row. E.g.
+  // <div style="display: flex;">
+  //   <div style="min-height: 100px;">
+  //     <div style="height: 200%;"></div>
+  //   </div>
+  // </div>
+  if (item.has_descendant_that_depends_on_percentage_block_size)
+    return false;
+
+  if (item.ng_input_node.IsMonolithic())
+    return false;
+
+  const auto& item_style = item.ng_input_node.Style();
+
+  // NOTE: We currently assume that writing-mode roots are monolithic, but
+  // this may change in the future.
+  DCHECK_EQ(ConstraintSpace().GetWritingDirection().GetWritingMode(),
+            item_style.GetWritingMode());
+
+  if (is_column_) {
+    bool can_shrink = item_style.ResolvedFlexShrink(Style()) != 0.f &&
+                      !Style().LogicalHeight().IsAutoOrContentOrIntrinsic();
+
+    // Only allow growth if the item can't shrink and the flex-basis is
+    // content-based.
+    if (!IsUsedFlexBasisDefinite(item.ng_input_node) && !can_shrink)
+      return true;
+
+    // Only allow growth if the item's block-size is auto and either the item
+    // can't shrink or its min-height is auto.
+    if (item_style.LogicalHeight().IsAutoOrContentOrIntrinsic() &&
+        (!can_shrink || algorithm_.ShouldApplyMinSizeAutoForChild(
+                            *item.ng_input_node.GetLayoutBox())))
+      return true;
+  } else {
+    // Don't grow if the item's block-size should be the same as its container.
+    if (WillChildCrossSizeBeContainerCrossSize(item.ng_input_node))
+      return false;
+
+    // Only allow growth if the item's cross size is auto.
+    if (DoesItemCrossSizeComputeToAuto(item.ng_input_node))
+      return true;
+  }
+  return false;
+}
+
 #if DCHECK_IS_ON()
 void NGFlexLayoutAlgorithm::CheckFlexLines(
     HeapVector<NGFlexLine>& flex_line_outputs) const {
diff --git a/third_party/blink/renderer/core/layout/ng/flex/ng_flex_layout_algorithm.h b/third_party/blink/renderer/core/layout/ng/flex/ng_flex_layout_algorithm.h
index 5278b1f..abc4629 100644
--- a/third_party/blink/renderer/core/layout/ng/flex/ng_flex_layout_algorithm.h
+++ b/third_party/blink/renderer/core/layout/ng/flex/ng_flex_layout_algorithm.h
@@ -17,6 +17,7 @@
 class NGBlockBreakToken;
 class NGBoxFragment;
 struct DevtoolsFlexInfo;
+struct NGFlexItem;
 
 class CORE_EXPORT NGFlexLayoutAlgorithm
     : public NGLayoutAlgorithm<NGBlockNode,
@@ -174,6 +175,10 @@
   // cross-size adjustments.
   const NGLayoutResult* RelayoutWithNewRowSizes();
 
+  // Used to determine when to allow an item to expand as a result of
+  // fragmentation.
+  bool MinBlockSizeShouldEncompassIntrinsicSize(const NGFlexItem& item) const;
+
 #if DCHECK_IS_ON()
   void CheckFlexLines(HeapVector<NGFlexLine>& flex_line_outputs) const;
 #endif
diff --git a/third_party/blink/web_tests/FlagExpectations/disable-layout-ng b/third_party/blink/web_tests/FlagExpectations/disable-layout-ng
index 6b305c8..b78a6f0 100644
--- a/third_party/blink/web_tests/FlagExpectations/disable-layout-ng
+++ b/third_party/blink/web_tests/FlagExpectations/disable-layout-ng
@@ -158,6 +158,8 @@
 crbug.com/660611 external/wpt/css/css-break/flexbox/multi-line-column-flex-fragmentation-039.html [ Failure ]
 crbug.com/660611 external/wpt/css/css-break/flexbox/multi-line-column-flex-fragmentation-040.html [ Failure ]
 crbug.com/660611 external/wpt/css/css-break/flexbox/multi-line-column-flex-fragmentation-047.html [ Failure ]
+crbug.com/660611 external/wpt/css/css-break/flexbox/multi-line-column-flex-fragmentation-048.html [ Failure ]
+crbug.com/660611 external/wpt/css/css-break/flexbox/multi-line-column-flex-fragmentation-049.html [ Failure ]
 crbug.com/660611 external/wpt/css/css-break/flexbox/multi-line-row-flex-fragmentation-007.html [ Failure ]
 crbug.com/660611 external/wpt/css/css-break/flexbox/multi-line-row-flex-fragmentation-008.html [ Failure ]
 crbug.com/660611 external/wpt/css/css-break/flexbox/multi-line-row-flex-fragmentation-010.html [ Failure ]
@@ -216,6 +218,8 @@
 crbug.com/660611 external/wpt/css/css-break/flexbox/single-line-column-flex-fragmentation-044.html [ Failure ]
 crbug.com/660611 external/wpt/css/css-break/flexbox/single-line-column-flex-fragmentation-045.html [ Failure ]
 crbug.com/660611 external/wpt/css/css-break/flexbox/single-line-column-flex-fragmentation-046.html [ Failure ]
+crbug.com/660611 external/wpt/css/css-break/flexbox/single-line-column-flex-fragmentation-050.html [ Failure ]
+crbug.com/660611 external/wpt/css/css-break/flexbox/single-line-column-flex-fragmentation-054.html [ Failure ]
 crbug.com/660611 external/wpt/css/css-break/flexbox/single-line-row-flex-fragmentation-008.html [ Failure ]
 crbug.com/660611 external/wpt/css/css-break/flexbox/single-line-row-flex-fragmentation-014.html [ Failure ]
 crbug.com/660611 external/wpt/css/css-break/flexbox/single-line-row-flex-fragmentation-015.html [ Failure ]
diff --git a/third_party/blink/web_tests/external/wpt/css/css-break/flexbox/multi-line-column-flex-fragmentation-048.html b/third_party/blink/web_tests/external/wpt/css/css-break/flexbox/multi-line-column-flex-fragmentation-048.html
new file mode 100644
index 0000000..8280041
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-break/flexbox/multi-line-column-flex-fragmentation-048.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<title>
+  Tests that a flex-item that shrinks *doesn't* expand.
+</title>
+<link rel="help" href="https://drafts.csswg.org/css-flexbox-1/#pagination">
+<link rel="match" href="../../reference/ref-filled-green-100px-square.xht">
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div style="width: 100px; height: 100px; columns: 2; column-gap: 0; background: red;">
+  <div style="display: flex; flex-direction: column; flex-wrap: wrap; height: 200px;">
+    <div style="background: green; flex-basis: fit-content; height: 10px; width: 25px;">
+      <div style="contain: size; width: 25px; height: 50px;"></div>
+      <div style="contain: size; width: 25px; height: 100px;"></div>
+    </div>
+    <div style="background: green; width: 25px; height: 50px;"></div>
+    <div style="background: green; flex-basis: min-content; height: 10px; width: 25px;">
+      <div style="contain: size; width: 25px; height: 50px;"></div>
+      <div style="contain: size; width: 25px; height: 100px;"></div>
+    </div>
+    <div style="background: green; width: 25px; height: 50px;"></div>
+  </div>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-break/flexbox/multi-line-column-flex-fragmentation-049.html b/third_party/blink/web_tests/external/wpt/css/css-break/flexbox/multi-line-column-flex-fragmentation-049.html
new file mode 100644
index 0000000..0ede74a
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-break/flexbox/multi-line-column-flex-fragmentation-049.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<title>
+  Tests that a flex-item with an indefinite flex-basis expands if the
+  container hieght is auto.
+</title>
+<link rel="help" href="https://drafts.csswg.org/css-flexbox-1/#pagination">
+<link rel="match" href="../../reference/ref-filled-green-100px-square.xht">
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div style="width: 100px; height: 100px; columns: 2; column-gap: 0; background: red;">
+  <div style="display: flex; flex-direction: column;">
+    <div style="background: green; flex-basis: content; height: 10px;">
+      <div style="contain: size; width: 50px; height: 50px;"></div>
+      <div style="contain: size; width: 50px; height: 100px;"></div>
+    </div>
+  </div>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-break/flexbox/single-line-column-flex-fragmentation-050.html b/third_party/blink/web_tests/external/wpt/css/css-break/flexbox/single-line-column-flex-fragmentation-050.html
new file mode 100644
index 0000000..ae683e93
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-break/flexbox/single-line-column-flex-fragmentation-050.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<title>
+  Tests that a flex-item with an indefinite flex-basis expands if the
+  container height is auto.
+</title>
+<link rel="help" href="https://drafts.csswg.org/css-flexbox-1/#pagination">
+<link rel="match" href="../../reference/ref-filled-green-100px-square.xht">
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div style="width: 100px; height: 100px; columns: 2; column-gap: 0; background: red;">
+  <div style="display: flex; flex-direction: column;">
+    <div style="background: green; flex-basis: content; height: 10px;">
+      <div style="contain: size; width: 50px; height: 50px;"></div>
+      <div style="contain: size; width: 50px; height: 100px;"></div>
+    </div>
+  </div>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-break/flexbox/single-line-column-flex-fragmentation-051.html b/third_party/blink/web_tests/external/wpt/css/css-break/flexbox/single-line-column-flex-fragmentation-051.html
new file mode 100644
index 0000000..9fc2a6e
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-break/flexbox/single-line-column-flex-fragmentation-051.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<title>
+  Tests that a flex-item with a definite flex-basis *doesn't* expand.
+</title>
+<link rel="help" href="https://drafts.csswg.org/css-flexbox-1/#pagination">
+<link rel="match" href="../../reference/ref-filled-green-100px-square.xht">
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div style="width: 100px; height: 100px; columns: 2; column-gap: 0; background: red;">
+  <div style="display: flex; flex-direction: column;">
+    <div style="background: green; flex-basis: 10px; height: 10px;">
+      <div style="contain: size; width: 50px; height: 50px;"></div>
+      <div style="contain: size; width: 50px; height: 100px;"></div>
+    </div>
+    <div style="background: green; width: 50px; height: 190px;"></div>
+  </div>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-break/flexbox/single-line-column-flex-fragmentation-052.html b/third_party/blink/web_tests/external/wpt/css/css-break/flexbox/single-line-column-flex-fragmentation-052.html
new file mode 100644
index 0000000..faa0d130
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-break/flexbox/single-line-column-flex-fragmentation-052.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<title>
+  Tests that a flex-item with an definite flex-basis but an indefinite height expands.
+</title>
+<link rel="help" href="https://drafts.csswg.org/css-flexbox-1/#pagination">
+<link rel="match" href="../../reference/ref-filled-green-100px-square.xht">
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div style="width: 100px; height: 100px; columns: 2; column-gap: 0; background: red;">
+  <div style="display: flex; flex-direction: column;">
+    <div style="background: green; flex-basis: 10px;">
+      <div style="contain: size; width: 50px; height: 50px;"></div>
+      <div style="contain: size; width: 50px; height: 100px;"></div>
+    </div>
+  </div>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-break/flexbox/single-line-column-flex-fragmentation-053.html b/third_party/blink/web_tests/external/wpt/css/css-break/flexbox/single-line-column-flex-fragmentation-053.html
new file mode 100644
index 0000000..524870e
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-break/flexbox/single-line-column-flex-fragmentation-053.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<title>
+  Tests that a flex-item that can't shrink and has a definite flex-basis, an
+  indefinite height, and a non-auto min-height *doesn't* expand.
+</title>
+<link rel="help" href="https://drafts.csswg.org/css-flexbox-1/#pagination">
+<link rel="match" href="../../reference/ref-filled-green-100px-square.xht">
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div style="width: 100px; height: 100px; columns: 2; column-gap: 0; background: red;">
+  <div style="display: flex; flex-direction: column; height: 100px;">
+    <div style="background: green; flex-basis: 10px; min-height: 10px;">
+      <div style="contain: size; width: 50px; height: 50px;"></div>
+      <div style="contain: size; width: 50px; height: 100px;"></div>
+    </div>
+    <div style="background: green; width: 50px; height: 190px;"></div>
+  </div>
+  <div style="background: green; width: 50px; height: 100px;"></div>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-break/flexbox/single-line-column-flex-fragmentation-054.html b/third_party/blink/web_tests/external/wpt/css/css-break/flexbox/single-line-column-flex-fragmentation-054.html
new file mode 100644
index 0000000..60c130e
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-break/flexbox/single-line-column-flex-fragmentation-054.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<title>
+  Tests that a flex-item with an definite flex-basis, an indefinite height, and
+  a non-auto min-height does expand.
+</title>
+<link rel="help" href="https://drafts.csswg.org/css-flexbox-1/#pagination">
+<link rel="match" href="../../reference/ref-filled-green-100px-square.xht">
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div style="width: 100px; height: 100px; columns: 2; column-gap: 0; background: red;">
+  <div style="display: flex; flex-direction: column;">
+    <div style="background: green; flex-basis: 10px; min-height: 10px;">
+      <div style="contain: size; width: 50px; height: 50px;"></div>
+      <div style="contain: size; width: 50px; height: 100px;"></div>
+    </div>
+  </div>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-break/flexbox/single-line-column-flex-fragmentation-055.html b/third_party/blink/web_tests/external/wpt/css/css-break/flexbox/single-line-column-flex-fragmentation-055.html
new file mode 100644
index 0000000..2958e616
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-break/flexbox/single-line-column-flex-fragmentation-055.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<title>
+  Tests that a flex-item with an definite flex-basis, an indefinite height, and
+  can't shrink does expand.
+</title>
+<link rel="help" href="https://drafts.csswg.org/css-flexbox-1/#pagination">
+<link rel="match" href="../../reference/ref-filled-green-100px-square.xht">
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div style="width: 100px; height: 100px; columns: 2; column-gap: 0; background: red;">
+  <div style="display: flex; flex-direction: column;">
+    <div style="background: green; flex-basis: 10px; justify-self: flex-start;">
+      <div style="contain: size; width: 50px; height: 50px;"></div>
+      <div style="contain: size; width: 50px; height: 100px;"></div>
+    </div>
+  </div>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-break/flexbox/single-line-row-flex-fragmentation-008.html b/third_party/blink/web_tests/external/wpt/css/css-break/flexbox/single-line-row-flex-fragmentation-008.html
index 562cb61..dfade0f 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-break/flexbox/single-line-row-flex-fragmentation-008.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-break/flexbox/single-line-row-flex-fragmentation-008.html
@@ -1,6 +1,7 @@
 <!DOCTYPE html>
 <title>
-  Tests that a flex-item with a fixed block-size container grows due to fragmentation.
+  Tests that a flex-item with a fixed block-size container *doesn't* grow due to fragmentation
+  if stretched.
 </title>
 <link rel="help" href="https://drafts.csswg.org/css-flexbox-1/#pagination">
 <link rel="match" href="../../reference/ref-filled-green-100px-square.xht">
@@ -12,4 +13,5 @@
       <div style="display: inline-block; width: 50px; height: 100px;"></div>
     </div>
   </div>
+  <div style="background: green; width: 50px; height: 100px;"></div>
 </div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-break/flexbox/single-line-row-flex-fragmentation-009.html b/third_party/blink/web_tests/external/wpt/css/css-break/flexbox/single-line-row-flex-fragmentation-009.html
index b51c7883..8dbaa692 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-break/flexbox/single-line-row-flex-fragmentation-009.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-break/flexbox/single-line-row-flex-fragmentation-009.html
@@ -8,7 +8,7 @@
 <p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
 <div style="width: 100px; height: 100px; columns: 2; column-gap: 0; column-fill: auto; background: red;">
   <div style="display: flex; background: green;">
-    <div style="display: flex;">
+    <div style="display: flex; align-self: flex-start;">
       <div style="line-height: 0;">
         <div style="display: inline-block; width: 50px; height: 50px;"></div>
         <div style="display: inline-block; width: 50px; height: 100px;"></div>