Complete layout even if a block needs relayout due to widows or column balancing.

We cannot just abort in the middle of layoutBlockFlow() when we detect that we
need another layout pass (due to new column height or because we want an
earlier break to satisfy the widows requirement). We might miss our only
opportunity to detect size changes that way, and thus skip necessary layout and
repositioning of absolutely positioned descendants.

BUG=591637

Review-Url: https://codereview.chromium.org/2471623003
Cr-Commit-Position: refs/heads/master@{#436192}
diff --git a/third_party/WebKit/LayoutTests/fast/multicol/abspos-new-width-rebalance.html b/third_party/WebKit/LayoutTests/fast/multicol/abspos-new-width-rebalance.html
new file mode 100644
index 0000000..35d6103
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/multicol/abspos-new-width-rebalance.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<p>There should be a blue <em>square</em> in the top-right corner of this page.</p>
+<div style="position:relative; width:500px; height:100px; ">
+    <div style="position:absolute; right:0; top:0; width:50px; height:25px; background:blue;"></div>
+    <div id="multicol" style="position:absolute; columns:2; top:25px; right:0; width:200px;">
+        <div id="abspos" style="position:absolute; width:50px; height:25px; top:0; right:0; background:blue;"></div>
+        <div style="width:100px; height:100px;"></div>
+    </div>
+</div>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script>
+    test(() => {
+        var multicol = document.getElementById("multicol");
+        var abspos = document.getElementById("abspos");
+        assert_equals(abspos.offsetLeft, 150);
+        multicol.style.width = "300px";
+        assert_equals(abspos.offsetLeft, 250);
+    }, "Resize (multicol) container of right-aligned abspos");
+</script>
diff --git a/third_party/WebKit/LayoutTests/fragmentation/widows-change-width-abspos-percent-width.html b/third_party/WebKit/LayoutTests/fragmentation/widows-change-width-abspos-percent-width.html
new file mode 100644
index 0000000..a11a938
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fragmentation/widows-change-width-abspos-percent-width.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<p>There should be a blue <em>square</em> below.</p>
+<div style="columns:2; column-fill:auto; height:90px; line-height:20px; widows:3;">
+    <div id="lines" style="position:relative; width:400px; height:110px;">
+        <div id="abspos" style="position:absolute; width:25%; height:25px; top:0; left:0; background:blue;"></div>
+        <br>
+        <br>
+        <br>
+        <br>
+        <br>
+    </div>
+</div>
+<script src="../resources/testharness.js"></script>
+<script src="../resources/testharnessreport.js"></script>
+<script>
+    test(() => {
+        var lines = document.getElementById("lines");
+        var abspos = document.getElementById("abspos");
+        assert_equals(abspos.offsetWidth, 100);
+        lines.style.width = "100px";
+        assert_equals(abspos.offsetWidth, 25);
+    }, "Resize container with percent-width abspos and widows");
+</script>
diff --git a/third_party/WebKit/LayoutTests/fragmentation/widows-change-width-abspos-right-aligned.html b/third_party/WebKit/LayoutTests/fragmentation/widows-change-width-abspos-right-aligned.html
new file mode 100644
index 0000000..caafd16
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fragmentation/widows-change-width-abspos-right-aligned.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<p>There should be a blue <em>square</em> below.</p>
+<div style="margin-left:100px; width:50px; height:25px; background:blue;"></div>
+<div style="columns:2; column-fill:auto; height:90px; line-height:20px; widows:3;">
+    <div id="lines" style="position:relative; width:100px; height:110px;">
+        <div id="abspos" style="position:absolute; width:50px; height:25px; top:0; right:0; background:blue;"></div>
+        <br>
+        <br>
+        <br>
+        <br>
+        <br>
+    </div>
+</div>
+<script src="../resources/testharness.js"></script>
+<script src="../resources/testharnessreport.js"></script>
+<script>
+    test(() => {
+        var lines = document.getElementById("lines");
+        var abspos = document.getElementById("abspos");
+        assert_equals(abspos.offsetLeft, 50);
+        lines.style.width = "150px";
+        assert_equals(abspos.offsetLeft, 100);
+    }, "Resize container with right-aligned abspos and widows");
+</script>
diff --git a/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp b/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp
index 704032fc..74ef4383 100644
--- a/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp
@@ -403,9 +403,21 @@
 
   // Multiple passes might be required for column based layout.
   // The number of passes could be as high as the number of columns.
-  bool done = false;
-  while (!done)
-    done = layoutBlockFlow(relayoutChildren, layoutScope);
+  LayoutMultiColumnFlowThread* flowThread = multiColumnFlowThread();
+  do {
+    layoutBlockFlow(relayoutChildren, layoutScope);
+
+    if (flowThread && flowThread->columnHeightsChanged()) {
+      setChildNeedsLayout(MarkOnlyThis);
+      continue;
+    }
+
+    if (shouldBreakAtLineToAvoidWidow()) {
+      setEverHadLayout();
+      continue;
+    }
+    break;
+  } while (true);
 
   updateLayerTransformAfterLayout();
 
@@ -462,7 +474,7 @@
 }
 
 DISABLE_CFI_PERF
-inline bool LayoutBlockFlow::layoutBlockFlow(bool relayoutChildren,
+inline void LayoutBlockFlow::layoutBlockFlow(bool relayoutChildren,
                                              SubtreeLayoutScope& layoutScope) {
   LayoutUnit oldLeft = logicalLeft();
   bool logicalWidthChanged = updateLogicalWidthAndColumnWidth();
@@ -503,7 +515,8 @@
     // potential infinite loop, run layout again with auto scrollbars frozen in
     // their current state.
     PaintLayerScrollableArea::FreezeScrollbarsScope freezeScrollbars;
-    return layoutBlockFlow(relayoutChildren, layoutScope);
+    layoutBlockFlow(relayoutChildren, layoutScope);
+    return;
   }
 
   // Expand our intrinsic height to encompass floats.
@@ -511,18 +524,6 @@
       createsNewFormattingContext())
     setLogicalHeight(lowestFloatLogicalBottom() + afterEdge);
 
-  if (LayoutMultiColumnFlowThread* flowThread = multiColumnFlowThread()) {
-    if (flowThread->columnHeightsChanged()) {
-      setChildNeedsLayout(MarkOnlyThis);
-      return false;
-    }
-  }
-
-  if (shouldBreakAtLineToAvoidWidow()) {
-    setEverHadLayout();
-    return false;
-  }
-
   // Remember the automatic logical height we got from laying out the children.
   LayoutUnit unconstrainedHeight = logicalHeight();
   LayoutUnit unconstrainedClientAfterEdge = clientLogicalBottom();
@@ -546,7 +547,6 @@
   computeOverflow(unconstrainedClientAfterEdge);
 
   m_descendantsWithFloatsMarkedForLayout = false;
-  return true;
 }
 
 void LayoutBlockFlow::addOverhangingFloatsFromChildren(
diff --git a/third_party/WebKit/Source/core/layout/LayoutBlockFlow.h b/third_party/WebKit/Source/core/layout/LayoutBlockFlow.h
index 3ae25bc..4cb02a7 100644
--- a/third_party/WebKit/Source/core/layout/LayoutBlockFlow.h
+++ b/third_party/WebKit/Source/core/layout/LayoutBlockFlow.h
@@ -477,8 +477,7 @@
 
  private:
   void resetLayout();
-  bool layoutBlockFlow(bool relayoutChildren,
-                       SubtreeLayoutScope&);
+  void layoutBlockFlow(bool relayoutChildren, SubtreeLayoutScope&);
   void addOverhangingFloatsFromChildren(LayoutUnit unconstrainedHeight);
   void layoutBlockChildren(bool relayoutChildren,
                            SubtreeLayoutScope&,