[New Multicolumn] Use the term "content run" in favor of "forced break".

You get one content run even without any forced breaks.

Documentation improvements. In particular for flow thread layout and
column balancing.

Also don't assume that a column set starts at flow thread block offset 0.
This is only true for the first set. So far we only have one set, but this
will soon change, with the introduction of support for column-span:all.
Check with the flow thread portion rectangle to get the correct start offset.

Review URL: https://codereview.chromium.org/267373005

git-svn-id: svn://svn.chromium.org/blink/trunk@173879 bbb929c8-8fbe-4397-9dbb-9b2b20218538
diff --git a/third_party/WebKit/Source/core/rendering/RenderMultiColumnFlowThread.cpp b/third_party/WebKit/Source/core/rendering/RenderMultiColumnFlowThread.cpp
index 070b2f36..c71439b5 100644
--- a/third_party/WebKit/Source/core/rendering/RenderMultiColumnFlowThread.cpp
+++ b/third_party/WebKit/Source/core/rendering/RenderMultiColumnFlowThread.cpp
@@ -297,7 +297,7 @@
 bool RenderMultiColumnFlowThread::addForcedRegionBreak(LayoutUnit offset, RenderObject* /*breakChild*/, bool /*isBefore*/, LayoutUnit* offsetBreakAdjustment)
 {
     if (RenderMultiColumnSet* multicolSet = toRenderMultiColumnSet(regionAtBlockOffset(offset))) {
-        multicolSet->addForcedBreak(offset);
+        multicolSet->addContentRun(offset);
         if (offsetBreakAdjustment)
             *offsetBreakAdjustment = pageLogicalHeightForOffset(offset) ? pageRemainingLogicalHeightForOffset(offset, IncludePageBoundary) : LayoutUnit();
         return true;
diff --git a/third_party/WebKit/Source/core/rendering/RenderMultiColumnFlowThread.h b/third_party/WebKit/Source/core/rendering/RenderMultiColumnFlowThread.h
index a341db8..989fe3fe 100644
--- a/third_party/WebKit/Source/core/rendering/RenderMultiColumnFlowThread.h
+++ b/third_party/WebKit/Source/core/rendering/RenderMultiColumnFlowThread.h
@@ -50,6 +50,40 @@
 // content. Although a RenderMultiColumnFlowThread is laid out, it does not take up any space in its
 // container. It's the RenderMultiColumnSet objects that take up the necessary amount of space, and
 // make sure that the columns are painted and hit-tested correctly.
+//
+// The width of the flow thread is the same as the column width. The width of a column set is the
+// same as the content box width of the multicol container; in other words exactly enough to hold
+// the number of columns to be used, stacked horizontally, plus column gaps between them.
+//
+// Since it's the first child of the multicol container, the flow thread is laid out first, albeit
+// in a slightly special way, since it's not to take up any space in its ancestors. Afterwards, the
+// column sets are laid out. They get their height from the columns that they hold. In single
+// column-row constrained height non-balancing cases this will simply be the same as the content
+// height of the multicol container itself. In most other cases we'll have to calculate optimal
+// column heights ourselves, though. This process is referred to as column balancing, and then we
+// infer the column set height from the flow thread's height.
+//
+// More on column balancing: the columns' height is unknown in the first layout pass when
+// balancing. This means that we cannot insert any implicit (soft / unforced) breaks (and pagination
+// struts) when laying out the contents of the flow thread. We'll just lay out everything in tall
+// single strip. After the initial flow thread layout pass we can determine a tentative / minimal /
+// initial column height. This is calculated by simply dividing the flow thread's height by the
+// number of specified columns. In the layout pass that follows, we can insert breaks (and
+// pagination struts) at column boundaries, since we now have a column height. It may very easily
+// turn out that the calculated height wasn't enough, though. We'll notice this at end of layout. If
+// we end up with too many columns (i.e. columns overflowing the multicol container), it wasn't
+// enough. In this case we need to increase the column heights. We'll increase them by the lowest
+// amount of space that could possibly affect where the breaks occur (see
+// RenderMultiColumnSet::recordSpaceShortage()). We'll relayout (to find new break points and the
+// new lowest amount of space increase that could affect where they occur, in case we need another
+// round) until we've reached an acceptable height (where everything fits perfectly in the number of
+// columns that we have specified). The rule of thumb is that we shouldn't have to perform more of
+// such iterations than the number of columns that we have.
+//
+// For each layout iteration done for column balancing, the flow thread will need a deep layout if
+// column heights changed in the previous pass, since column height changes may affect break points
+// and pagination struts anywhere in the tree, and currently no way exists to do this in a more
+// optimized manner.
 class RenderMultiColumnFlowThread FINAL : public RenderFlowThread {
 public:
     virtual ~RenderMultiColumnFlowThread();
diff --git a/third_party/WebKit/Source/core/rendering/RenderMultiColumnSet.cpp b/third_party/WebKit/Source/core/rendering/RenderMultiColumnSet.cpp
index 7ffece20..9e7602d0 100644
--- a/third_party/WebKit/Source/core/rendering/RenderMultiColumnSet.cpp
+++ b/third_party/WebKit/Source/core/rendering/RenderMultiColumnSet.cpp
@@ -101,7 +101,7 @@
 {
     unsigned indexWithLargestHeight = 0;
     LayoutUnit largestHeight;
-    LayoutUnit previousOffset;
+    LayoutUnit previousOffset = logicalTopInFlowThread();
     size_t runCount = m_contentRuns.size();
     ASSERT(runCount);
     for (size_t i = 0; i < runCount; i++) {
@@ -120,14 +120,14 @@
 {
 #ifndef NDEBUG
     // There should be no implicit breaks assumed at this point.
-    for (unsigned i = 0; i < forcedBreaksCount(); i++)
+    for (unsigned i = 0; i < m_contentRuns.size(); i++)
         ASSERT(!m_contentRuns[i].assumedImplicitBreaks());
 #endif // NDEBUG
 
     // Insert a final content run to encompass all content. This will include overflow if this is
     // the last set.
-    addForcedBreak(logicalBottomInFlowThread());
-    unsigned breakCount = forcedBreaksCount();
+    addContentRun(logicalBottomInFlowThread());
+    unsigned columnCount = m_contentRuns.size();
 
     // If there is room for more breaks (to reach the used value of column-count), imagine that we
     // insert implicit breaks at suitable locations. At any given time, the content run with the
@@ -135,19 +135,22 @@
     // column count by one and shrink its columns' height. Repeat until we have the desired total
     // number of breaks. The largest column height among the runs will then be the initial column
     // height for the balancer to use.
-    while (breakCount < m_computedColumnCount) {
+    while (columnCount < m_computedColumnCount) {
         unsigned index = findRunWithTallestColumns();
         m_contentRuns[index].assumeAnotherImplicitBreak();
-        breakCount++;
+        columnCount++;
     }
 }
 
 LayoutUnit RenderMultiColumnSet::calculateColumnHeight(bool initial) const
 {
     if (initial) {
-        // Start with the lowest imaginable column height.
+        // Start with the lowest imaginable column height. We use the tallest content run (after
+        // having "inserted" implicit breaks), and find its start offset (by looking at the previous
+        // run's end offset, or, if there's no previous run, the set's start offset in the flow
+        // thread).
         unsigned index = findRunWithTallestColumns();
-        LayoutUnit startOffset = index > 0 ? m_contentRuns[index - 1].breakOffset() : LayoutUnit();
+        LayoutUnit startOffset = index > 0 ? m_contentRuns[index - 1].breakOffset() : logicalTopInFlowThread();
         return std::max<LayoutUnit>(m_contentRuns[index].columnLogicalHeight(startOffset), m_minimumColumnHeight);
     }
 
@@ -156,7 +159,7 @@
         return m_computedColumnHeight;
     }
 
-    if (forcedBreaksCount() >= computedColumnCount()) {
+    if (m_contentRuns.size() >= computedColumnCount()) {
         // Too many forced breaks to allow any implicit breaks. Initial balancing should already
         // have set a good height. There's nothing more we should do.
         return m_computedColumnHeight;
@@ -173,21 +176,16 @@
     return m_computedColumnHeight + m_minSpaceShortage;
 }
 
-void RenderMultiColumnSet::clearForcedBreaks()
-{
-    m_contentRuns.clear();
-}
-
-void RenderMultiColumnSet::addForcedBreak(LayoutUnit offsetFromFirstPage)
+void RenderMultiColumnSet::addContentRun(LayoutUnit endOffsetFromFirstPage)
 {
     if (!multiColumnFlowThread()->requiresBalancing())
         return;
-    if (!m_contentRuns.isEmpty() && offsetFromFirstPage <= m_contentRuns.last().breakOffset())
+    if (!m_contentRuns.isEmpty() && endOffsetFromFirstPage <= m_contentRuns.last().breakOffset())
         return;
     // Append another item as long as we haven't exceeded used column count. What ends up in the
     // overflow area shouldn't affect column balancing.
     if (m_contentRuns.size() < m_computedColumnCount)
-        m_contentRuns.append(ContentRun(offsetFromFirstPage));
+        m_contentRuns.append(ContentRun(endOffsetFromFirstPage));
 }
 
 bool RenderMultiColumnSet::recalculateColumnHeight(bool initial)
@@ -195,8 +193,10 @@
     ASSERT(multiColumnFlowThread()->requiresBalancing());
 
     LayoutUnit oldColumnHeight = m_computedColumnHeight;
-    if (initial)
+    if (initial) {
+        // Post-process the content runs and find out where the implicit breaks will occur.
         distributeImplicitBreaks();
+    }
     LayoutUnit newColumnHeight = calculateColumnHeight(initial);
     setAndConstrainColumnHeight(newColumnHeight);
 
@@ -210,7 +210,7 @@
         return false; // No change. We're done.
 
     m_minSpaceShortage = RenderFlowThread::maxLogicalHeight();
-    clearForcedBreaks();
+    m_contentRuns.clear();
     return true; // Need another pass.
 }
 
@@ -279,7 +279,7 @@
         setAndConstrainColumnHeight(heightAdjustedForSetOffset(multiColumnFlowThread()->columnHeightAvailable()));
     }
 
-    clearForcedBreaks();
+    m_contentRuns.clear();
 
     // Nuke previously stored minimum column height. Contents may have changed for all we know.
     m_minimumColumnHeight = 0;
diff --git a/third_party/WebKit/Source/core/rendering/RenderMultiColumnSet.h b/third_party/WebKit/Source/core/rendering/RenderMultiColumnSet.h
index a750eff..7caab51 100644
--- a/third_party/WebKit/Source/core/rendering/RenderMultiColumnSet.h
+++ b/third_party/WebKit/Source/core/rendering/RenderMultiColumnSet.h
@@ -65,6 +65,7 @@
 
     RenderMultiColumnSet* nextSiblingMultiColumnSet() const;
 
+    LayoutUnit logicalTopInFlowThread() const { return isHorizontalWritingMode() ? flowThreadPortionRect().y() : flowThreadPortionRect().x(); }
     LayoutUnit logicalBottomInFlowThread() const { return isHorizontalWritingMode() ? flowThreadPortionRect().maxY() : flowThreadPortionRect().maxX(); }
 
     LayoutUnit logicalHeightInFlowThread() const { return isHorizontalWritingMode() ? flowThreadPortionRect().height() : flowThreadPortionRect().width(); }
@@ -88,9 +89,11 @@
     void updateMinimumColumnHeight(LayoutUnit height) { m_minimumColumnHeight = std::max(height, m_minimumColumnHeight); }
     LayoutUnit minimumColumnHeight() const { return m_minimumColumnHeight; }
 
-    unsigned forcedBreaksCount() const { return m_contentRuns.size(); }
-    void clearForcedBreaks();
-    void addForcedBreak(LayoutUnit offsetFromFirstPage);
+    // Add a content run, specified by its end position. A content run is appended at every
+    // forced/explicit break and at the end of the column set. The content runs are used to
+    // determine where implicit/soft breaks will occur, in order to calculate an initial column
+    // height.
+    void addContentRun(LayoutUnit endOffsetFromFirstPage);
 
     // (Re-)calculate the column height if it's auto. If 'initial' is set, guess an initial column
     // height; otherwise, stretch the column height a tad. Return true if column height changed and
@@ -171,11 +174,11 @@
 
     // A run of content without explicit (forced) breaks; i.e. a flow thread portion between two
     // explicit breaks, between flow thread start and an explicit break, between an explicit break
-    // and flow thread end, or, in cases when there are no explicit breaks at all: between flow flow
-    // thread start and flow thread end. We need to know where the explicit breaks are, in order to
-    // figure out where the implicit breaks will end up, so that we get the columns properly
-    // balanced. A content run starts out as representing one single column, and will represent one
-    // additional column for each implicit break "inserted" there.
+    // and flow thread end, or, in cases when there are no explicit breaks at all: between flow
+    // thread portion start and flow thread portion end. We need to know where the explicit breaks
+    // are, in order to figure out where the implicit breaks will end up, so that we get the columns
+    // properly balanced. A content run starts out as representing one single column, and will
+    // represent one additional column for each implicit break "inserted" there.
     class ContentRun {
     public:
         ContentRun(LayoutUnit breakOffset)