Bug 764567: Implement column-fill part of CSS3 multicol spec, now with regression fixes [r=roc].
authorScott Johnson <sjohnson@mozilla.com>
Tue, 31 Jul 2012 11:21:19 -0500
changeset 101000 34d30fa24371d1792db800365fc8e67618639037
parent 100999 3e1667c960fc75a84a8684b532426bce419514e6
child 101001 0b03576b81b59a334d5c7fdf8fda701165b212ba
push id23206
push userryanvm@gmail.com
push dateWed, 01 Aug 2012 02:11:21 +0000
treeherdermozilla-central@582d4c67b3a7 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc
bugs764567
milestone17.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 764567: Implement column-fill part of CSS3 multicol spec, now with regression fixes [r=roc].
dom/interfaces/css/nsIDOMCSS2Properties.idl
layout/base/nsStyleConsts.h
layout/generic/crashtests/399412-1.html
layout/generic/crashtests/673770.html
layout/generic/crashtests/crashtests.list
layout/generic/nsColumnSetFrame.cpp
layout/reftests/bugs/368020-1-ref.html
layout/reftests/bugs/368020-1.html
layout/reftests/bugs/379349-2-ref.xhtml
layout/reftests/bugs/379349-2a.xhtml
layout/reftests/bugs/379349-2b.xhtml
layout/reftests/bugs/563584-9c.html
layout/reftests/bugs/563584-9d.html
layout/reftests/columns/ahem.css
layout/reftests/columns/columnfill-auto-ref.html
layout/reftests/columns/columnfill-auto.html
layout/reftests/columns/columnfill-balance-ref.html
layout/reftests/columns/columnfill-balance.html
layout/reftests/columns/columnfill-overflow-ref.html
layout/reftests/columns/columnfill-overflow.html
layout/reftests/columns/reftest.list
layout/reftests/pagination/abspos-overflow-01-cols.xhtml
layout/reftests/pagination/border-breaking-000-cols.xhtml
layout/reftests/pagination/border-breaking-001-cols.ref.xhtml
layout/reftests/pagination/border-breaking-001-cols.xhtml
layout/reftests/pagination/border-breaking-002-cols.ref.xhtml
layout/reftests/pagination/border-breaking-002-cols.xhtml
layout/reftests/pagination/border-breaking-003-cols.xhtml
layout/reftests/pagination/content-inserted-002.ref.xhtml
layout/reftests/pagination/content-inserted-002.xhtml
layout/reftests/pagination/content-inserted-003.xhtml
layout/reftests/pagination/content-inserted-004.xhtml
layout/reftests/pagination/content-inserted-005.xhtml
layout/reftests/pagination/content-inserted-006.xhtml
layout/reftests/pagination/content-inserted-007.xhtml
layout/reftests/pagination/content-inserted-009.xhtml
layout/style/nsCSSKeywordList.h
layout/style/nsCSSPropList.h
layout/style/nsCSSProps.cpp
layout/style/nsCSSProps.h
layout/style/nsComputedDOMStyle.cpp
layout/style/nsComputedDOMStyle.h
layout/style/nsRuleNode.cpp
layout/style/nsStyleStruct.cpp
layout/style/nsStyleStruct.h
layout/style/test/property_database.js
--- a/dom/interfaces/css/nsIDOMCSS2Properties.idl
+++ b/dom/interfaces/css/nsIDOMCSS2Properties.idl
@@ -9,17 +9,17 @@
  * The nsIDOMCSS2Properties interface is a datatype for additional
  * reflection of data already provided in nsIDOMCSSStyleDeclaration in
  * the Document Object Model.
  *
  * For more information on this interface please see
  * http://www.w3.org/TR/DOM-Level-2-Style
  */
 
-[builtinclass, scriptable, uuid(492673d6-039b-4d94-a598-dbf82abc174f)]
+[builtinclass, scriptable, uuid(243898eb-0e13-416d-9a2e-33af084985ed)]
 interface nsIDOMCSS2Properties : nsISupports
 {
            attribute DOMString        background;
                                         // raises(DOMException) on setting
 
            attribute DOMString        backgroundAttachment;
                                         // raises(DOMException) on setting
 
@@ -493,16 +493,19 @@ interface nsIDOMCSS2Properties : nsISupp
                                         // raises(DOMException) on setting
 
            attribute DOMString        MozColumnCount;
                                         // raises(DOMException) on setting
 
            attribute DOMString        MozColumnWidth;
                                         // raises(DOMException) on setting
 
+           attribute DOMString        MozColumnFill;
+                                        // raises(DOMException) on setting
+
            attribute DOMString        MozColumnGap;
                                         // raises(DOMException) on setting
 
            attribute DOMString        MozFloatEdge;
                                         // raises(DOMException) on setting
 
            attribute DOMString        MozFontFeatureSettings;
                                         // raises(DOMException) on setting
--- a/layout/base/nsStyleConsts.h
+++ b/layout/base/nsStyleConsts.h
@@ -801,16 +801,19 @@ static inline mozilla::css::Side operato
 #define NS_STYLE_PAGE_BREAK_AVOID               2
 #define NS_STYLE_PAGE_BREAK_LEFT                3
 #define NS_STYLE_PAGE_BREAK_RIGHT               4
 
 // See nsStyleColumn
 #define NS_STYLE_COLUMN_COUNT_AUTO              0
 #define NS_STYLE_COLUMN_COUNT_UNLIMITED         (-1)
 
+#define NS_STYLE_COLUMN_FILL_AUTO               0
+#define NS_STYLE_COLUMN_FILL_BALANCE            1
+
 // See nsStyleUIReset
 #define NS_STYLE_IME_MODE_AUTO                  0
 #define NS_STYLE_IME_MODE_NORMAL                1
 #define NS_STYLE_IME_MODE_ACTIVE                2
 #define NS_STYLE_IME_MODE_DISABLED              3
 #define NS_STYLE_IME_MODE_INACTIVE              4
 
 // See nsStyleGradient
--- a/layout/generic/crashtests/399412-1.html
+++ b/layout/generic/crashtests/399412-1.html
@@ -12,16 +12,17 @@
   height: 150px;
   border: 1px silver solid;
 }
 body {
   height: 60px;
   width: 300px;
   -moz-column-width: 50px;
   -moz-column-gap: 1px;
+  -moz-column-fill: auto;
 }
 </style>
 
 </head>
 
 <body onload="s=document.getElementById('s'); s.parentNode.removeChild(s);">
 
 <div class="container"><div class="overflow"></div></div>
--- a/layout/generic/crashtests/673770.html
+++ b/layout/generic/crashtests/673770.html
@@ -8,13 +8,13 @@
         document.body.style.height = "8px";
         document.documentElement.style.fontSize = "22050893469px";
         document.documentElement.offsetHeight;
         document.getElementById("x").style.counterReset = "chicken";
         document.documentElement.offsetHeight;
       }
     </script>
   </head>
-  <body style="-moz-column-width: 1px;" onload="boom();">
+  <body style="-moz-column-width: 1px; -moz-column-fill: auto;" onload="boom();">
     <hr size="100" color="blue"><div style="position: absolute;"></div><div id="x" style="height: 5px;"></div>
   </body>
 </html>
 
--- a/layout/generic/crashtests/crashtests.list
+++ b/layout/generic/crashtests/crashtests.list
@@ -370,17 +370,17 @@ load 660451-1.html
 load 665853.html
 load text-overflow-form-elements.html
 load text-overflow-iframe.html
 load text-overflow-bug666751-1.html
 load text-overflow-bug666751-2.html
 asserts(0-1) load text-overflow-bug670564.xhtml
 load text-overflow-bug671796.xhtml
 load 667025.html
-asserts(14) asserts-if(Android,8) load 673770.html # bug 569193 and bug 459597
+asserts-if(Android,8) load 673770.html # bug 569193 and bug 459597
 load 679933-1.html
 load 682649-1.html
 load 683702-1.xhtml
 load 688996-1.html
 load 688996-2.html
 load 683712.html
 load text-overflow-bug713610.html
 load 700031.xhtml
--- a/layout/generic/nsColumnSetFrame.cpp
+++ b/layout/generic/nsColumnSetFrame.cpp
@@ -105,18 +105,23 @@ protected:
     nscoord mMaxHeight;
     // The sum of the "content heights" for all columns
     nscoord mSumHeight;
     // The "content height" of the last column
     nscoord mLastHeight;
     // The maximum "content height" of all columns that overflowed
     // their available height
     nscoord mMaxOverflowingHeight;
+    // Whether or not we should revert back to 'auto' setting for column-fill.
+    // This happens if we overflow our columns such that we no longer have
+    // enough room to keep balancing.
+    bool mShouldRevertToAuto;
     void Reset() {
       mMaxHeight = mSumHeight = mLastHeight = mMaxOverflowingHeight = 0;
+      mShouldRevertToAuto = false;
     }
   };
   
   /**
    * Similar to nsBlockFrame::DrainOverflowLines. Locate any columns not
    * handled by our prev-in-flow, and any columns sitting on our own
    * overflow list, and put them in our primary child list for reflowing.
    */
@@ -320,16 +325,18 @@ nsColumnSetFrame::ChooseColumnStrategy(c
   const nsStyleColumn* colStyle = GetStyleColumn();
   nscoord availContentWidth = GetAvailableContentWidth(aReflowState);
   if (aReflowState.ComputedWidth() != NS_INTRINSICSIZE) {
     availContentWidth = aReflowState.ComputedWidth();
   }
   nscoord colHeight = GetAvailableContentHeight(aReflowState);
   if (aReflowState.ComputedHeight() != NS_INTRINSICSIZE) {
     colHeight = aReflowState.ComputedHeight();
+  } else if (aReflowState.mComputedMaxHeight != NS_INTRINSICSIZE) {
+    colHeight = aReflowState.mComputedMaxHeight;
   }
 
   nscoord colGap = GetColumnGap(this, colStyle);
   PRInt32 numColumns = colStyle->mColumnCount;
 
   const PRUint32 MAX_NESTED_COLUMN_BALANCING = 2;
   PRUint32 cnt = 1;
   for (const nsHTMLReflowState* rs = aReflowState.parentReflowState; rs && cnt
@@ -389,27 +396,29 @@ nsColumnSetFrame::ChooseColumnStrategy(c
     // Compute extra space and divide it among the columns
     nscoord extraSpace =
       NS_MAX(0, availContentWidth - (colWidth*numColumns + colGap*(numColumns - 1)));
     nscoord extraToColumns = extraSpace/numColumns;
     colWidth += extraToColumns;
     expectedWidthLeftOver = extraSpace - (extraToColumns*numColumns);
   }
 
-  // NOTE that the non-balancing behavior for non-auto computed height
-  // is not in the CSS3 columns draft as of 18 January 2001
-  if (aReflowState.ComputedHeight() == NS_INTRINSICSIZE) {
+  // If column-fill is set to 'balance', then we want to balance the columns.
+  if (colStyle->mColumnFill == NS_STYLE_COLUMN_FILL_BALANCE) {
     // Balancing!
     if (numColumns <= 0) {
       // Hmm, auto column count, column width or available width is unknown,
       // and balancing is required. Let's just use one column then.
       numColumns = 1;
     }
-    colHeight = NS_MIN(mLastBalanceHeight, GetAvailableContentHeight(aReflowState));
+
+    colHeight = NS_MIN(mLastBalanceHeight,
+                       colHeight);
   } else {
+    // This is the case when the column-fill property is set to 'auto'.
     // No balancing, so don't limit the column count
     numColumns = PR_INT32_MAX;
   }
 
 #ifdef DEBUG_roc
   printf("*** nsColumnSetFrame::ChooseColumnStrategy: numColumns=%d, colWidth=%d, expectedWidthLeftOver=%d, colHeight=%d, colGap=%d\n",
          numColumns, colWidth, expectedWidthLeftOver, colHeight, colGap);
 #endif
@@ -729,30 +738,47 @@ nsColumnSetFrame::ReflowChildren(nsHTMLR
           kidNextInFlow->AddStateBits(NS_FRAME_IS_OVERFLOW_CONTAINER);
         }
       }
       else if (kidNextInFlow->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER) {
         aStatus |= NS_FRAME_REFLOW_NEXTINFLOW;
         reflowNext = true;
         kidNextInFlow->RemoveStateBits(NS_FRAME_IS_OVERFLOW_CONTAINER);
       }
-        
+
+
+      if ((contentBottom > aReflowState.mComputedMaxHeight ||
+          contentBottom > aReflowState.ComputedHeight()) &&
+          aConfig.mBalanceColCount < PR_INT32_MAX) {
+        // We overflowed vertically, but have not exceeded the number
+        // of columns. If we're balancing, then we should try reverting
+        // to auto instead.
+        aColData.mShouldRevertToAuto = true;
+      }
+
       if (columnCount >= aConfig.mBalanceColCount) {
-        // No more columns allowed here. Stop.
-        aStatus |= NS_FRAME_REFLOW_NEXTINFLOW;
-        kidNextInFlow->AddStateBits(NS_FRAME_IS_DIRTY);
-        
-        // Move any of our leftover columns to our overflow list. Our
-        // next-in-flow will eventually pick them up.
-        const nsFrameList& continuationColumns = mFrames.RemoveFramesAfter(child);
-        if (continuationColumns.NotEmpty()) {
-          SetOverflowFrames(PresContext(), continuationColumns);
+        if (contentBottom >= aReflowState.availableHeight) {
+          // No more columns allowed here. Stop.
+          aStatus |= NS_FRAME_REFLOW_NEXTINFLOW;
+          kidNextInFlow->AddStateBits(NS_FRAME_IS_DIRTY);
+          // Move any of our leftover columns to our overflow list. Our
+          // next-in-flow will eventually pick them up.
+          const nsFrameList& continuationColumns = mFrames.RemoveFramesAfter(child);
+          if (continuationColumns.NotEmpty()) {
+            SetOverflowFrames(PresContext(), continuationColumns);
+          }
+          child = nsnull;
+          break;
+        } else if (contentBottom > aReflowState.mComputedMaxHeight ||
+                   contentBottom > aReflowState.ComputedHeight()) {
+          aColData.mShouldRevertToAuto = true;
+        } else {
+          // The number of columns required is too high.
+          allFit = false;
         }
-        child = nullptr;
-        break;
       }
     }
 
     if (PresContext()->HasPendingInterrupt()) {
       // Stop the loop now while |child| still points to the frame that bailed
       // out.  We could keep going here and condition a bunch of the code in
       // this loop on whether there's an interrupt, or even just keep going and
       // trying to reflow the blocks (even though we know they'll interrupt
@@ -912,164 +938,182 @@ nsColumnSetFrame::Reflow(nsPresContext* 
   // what the average column height should be, because we can measure
   // the heights of all the columns and sum them up. But don't do this
   // if we have a next in flow because we don't want to suck all its
   // content back here and then have to push it out again!
   nsIFrame* nextInFlow = GetNextInFlow();
   bool unboundedLastColumn = isBalancing && !nextInFlow;
   nsCollapsingMargin carriedOutBottomMargin;
   ColumnBalanceData colData;
-  bool feasible = ReflowChildren(aDesiredSize, aReflowState,
-    aStatus, config, unboundedLastColumn, &carriedOutBottomMargin, colData);
+  colData.mShouldRevertToAuto = false;
+
+  // This loop exists in order to try balancing initially. If the balancing
+  // overflows, then we want to revert to column-fill: auto.
+
+  // Our loop invariant is: colData.mShouldRevertToAuto is true if and only
+  // if we've reflowed our children, and during the most recent reflow of
+  // children, we were balancing and we overflowed in the block direction.
+  do {
+    if (colData.mShouldRevertToAuto) {
+      config = ChooseColumnStrategy(aReflowState);
+      isBalancing = false;
+      config.mBalanceColCount = PR_INT32_MAX;
+    }
 
-  if (isBalancing && !aPresContext->HasPendingInterrupt()) {
-    nscoord availableContentHeight = GetAvailableContentHeight(aReflowState);
-  
-    // Termination of the algorithm below is guaranteed because
-    // knownFeasibleHeight - knownInfeasibleHeight decreases in every
-    // iteration.
-    nscoord knownFeasibleHeight = NS_INTRINSICSIZE;
-    nscoord knownInfeasibleHeight = 0;
-    // We set this flag when we detect that we may contain a frame
-    // that can break anywhere (thus foiling the linear decrease-by-one
-    // search)
-    bool maybeContinuousBreakingDetected = false;
+    bool feasible = ReflowChildren(aDesiredSize, aReflowState,
+      aStatus, config, unboundedLastColumn, &carriedOutBottomMargin, colData);
+
+    if (isBalancing && !aPresContext->HasPendingInterrupt()) {
+      nscoord availableContentHeight = GetAvailableContentHeight(aReflowState);
 
-    while (!aPresContext->HasPendingInterrupt()) {
-      nscoord lastKnownFeasibleHeight = knownFeasibleHeight;
+      // Termination of the algorithm below is guaranteed because
+      // knownFeasibleHeight - knownInfeasibleHeight decreases in every
+      // iteration.
+      nscoord knownFeasibleHeight = NS_INTRINSICSIZE;
+      nscoord knownInfeasibleHeight = 0;
+      // We set this flag when we detect that we may contain a frame
+      // that can break anywhere (thus foiling the linear decrease-by-one
+      // search)
+      bool maybeContinuousBreakingDetected = false;
 
-      // Record what we learned from the last reflow
-      if (feasible) {
-        // maxHeight is feasible. Also, mLastBalanceHeight is feasible.
-        knownFeasibleHeight = NS_MIN(knownFeasibleHeight, colData.mMaxHeight);
-        knownFeasibleHeight = NS_MIN(knownFeasibleHeight, mLastBalanceHeight);
+      while (!aPresContext->HasPendingInterrupt()) {
+        nscoord lastKnownFeasibleHeight = knownFeasibleHeight;
+
+        // Record what we learned from the last reflow
+        if (feasible) {
+          // maxHeight is feasible. Also, mLastBalanceHeight is feasible.
+          knownFeasibleHeight = NS_MIN(knownFeasibleHeight, colData.mMaxHeight);
+          knownFeasibleHeight = NS_MIN(knownFeasibleHeight, mLastBalanceHeight);
 
-        // Furthermore, no height less than the height of the last
-        // column can ever be feasible. (We might be able to reduce the
-        // height of a non-last column by moving content to a later column,
-        // but we can't do that with the last column.)
-        if (mFrames.GetLength() == config.mBalanceColCount) {
+          // Furthermore, no height less than the height of the last
+          // column can ever be feasible. (We might be able to reduce the
+          // height of a non-last column by moving content to a later column,
+          // but we can't do that with the last column.)
+          if (mFrames.GetLength() == config.mBalanceColCount) {
+            knownInfeasibleHeight = NS_MAX(knownInfeasibleHeight,
+                                           colData.mLastHeight - 1);
+          }
+        } else {
+          knownInfeasibleHeight = NS_MAX(knownInfeasibleHeight, mLastBalanceHeight);
+          // If a column didn't fit in its available height, then its current
+          // height must be the minimum height for unbreakable content in
+          // the column, and therefore no smaller height can be feasible.
           knownInfeasibleHeight = NS_MAX(knownInfeasibleHeight,
-                                         colData.mLastHeight - 1);
+                                         colData.mMaxOverflowingHeight - 1);
+
+          if (unboundedLastColumn) {
+            // The last column is unbounded, so all content got reflowed, so the
+            // mColMaxHeight is feasible.
+            knownFeasibleHeight = NS_MIN(knownFeasibleHeight,
+                                         colData.mMaxHeight);
+          }
         }
-      } else {
-        knownInfeasibleHeight = NS_MAX(knownInfeasibleHeight, mLastBalanceHeight);
-        // If a column didn't fit in its available height, then its current
-        // height must be the minimum height for unbreakable content in
-        // the column, and therefore no smaller height can be feasible.
-        knownInfeasibleHeight = NS_MAX(knownInfeasibleHeight,
-                                       colData.mMaxOverflowingHeight - 1);
-
-        if (unboundedLastColumn) {
-          // The last column is unbounded, so all content got reflowed, so the
-          // mColMaxHeight is feasible.
-          knownFeasibleHeight = NS_MIN(knownFeasibleHeight,
-                                       colData.mMaxHeight);
-        }
-      }
 
 #ifdef DEBUG_roc
-      printf("*** nsColumnSetFrame::Reflow balancing knownInfeasible=%d knownFeasible=%d\n",
-             knownInfeasibleHeight, knownFeasibleHeight);
+        printf("*** nsColumnSetFrame::Reflow balancing knownInfeasible=%d knownFeasible=%d\n",
+               knownInfeasibleHeight, knownFeasibleHeight);
 #endif
 
-      if (knownInfeasibleHeight >= knownFeasibleHeight - 1) {
-        // knownFeasibleHeight is where we want to be
-        break;
-      }
+
+        if (knownInfeasibleHeight >= knownFeasibleHeight - 1) {
+          // knownFeasibleHeight is where we want to be
+          break;
+
+        }
+        if (knownInfeasibleHeight >= availableContentHeight) {
+          break;
+        }
+
+        if (lastKnownFeasibleHeight - knownFeasibleHeight == 1) {
+          // We decreased the feasible height by one twip only. This could
+          // indicate that there is a continuously breakable child frame
+          // that we are crawling through.
+          maybeContinuousBreakingDetected = true;
+        }
 
-      if (knownInfeasibleHeight >= availableContentHeight) {
-        break;
-      }
+        nscoord nextGuess = (knownFeasibleHeight + knownInfeasibleHeight)/2;
+        // The constant of 600 twips is arbitrary. It's about two line-heights.
+        if (knownFeasibleHeight - nextGuess < 600 &&
+            !maybeContinuousBreakingDetected) {
+          // We're close to our target, so just try shrinking just the
+          // minimum amount that will cause one of our columns to break
+          // differently.
+          nextGuess = knownFeasibleHeight - 1;
+        } else if (unboundedLastColumn) {
+          // Make a guess by dividing that into N columns. Add some slop
+          // to try to make it on the feasible side.  The constant of
+          // 600 twips is arbitrary. It's about two line-heights.
+          nextGuess = colData.mSumHeight/config.mBalanceColCount + 600;
+          // Sanitize it
+          nextGuess = clamped(nextGuess, knownInfeasibleHeight + 1,
+                                         knownFeasibleHeight - 1);
+        } else if (knownFeasibleHeight == NS_INTRINSICSIZE) {
+          // This can happen when we had a next-in-flow so we didn't
+          // want to do an unbounded height measuring step. Let's just increase
+          // from the infeasible height by some reasonable amount.
+          nextGuess = knownInfeasibleHeight*2 + 600;
+        }
+        // Don't bother guessing more than our height constraint.
+        nextGuess = NS_MIN(availableContentHeight, nextGuess);
 
-      if (lastKnownFeasibleHeight - knownFeasibleHeight == 1) {
-        // We decreased the feasible height by one twip only. This could
-        // indicate that there is a continuously breakable child frame
-        // that we are crawling through.
-        maybeContinuousBreakingDetected = true;
+#ifdef DEBUG_roc
+        printf("*** nsColumnSetFrame::Reflow balancing choosing next guess=%d\n", nextGuess);
+#endif
+
+        config.mColMaxHeight = nextGuess;
+
+        unboundedLastColumn = false;
+        AddStateBits(NS_FRAME_IS_DIRTY);
+        feasible = ReflowChildren(aDesiredSize, aReflowState,
+                                  aStatus, config, false,
+                                  &carriedOutBottomMargin, colData);
       }
 
-      nscoord nextGuess = (knownFeasibleHeight + knownInfeasibleHeight)/2;
-      // The constant of 600 twips is arbitrary. It's about two line-heights.
-      if (knownFeasibleHeight - nextGuess < 600 &&
-          !maybeContinuousBreakingDetected) {
-        // We're close to our target, so just try shrinking just the
-        // minimum amount that will cause one of our columns to break
-        // differently.
-        nextGuess = knownFeasibleHeight - 1;
-      } else if (unboundedLastColumn) {
-        // Make a guess by dividing that into N columns. Add some slop
-        // to try to make it on the feasible side.  The constant of
-        // 600 twips is arbitrary. It's about two line-heights.
-        nextGuess = colData.mSumHeight/config.mBalanceColCount + 600;
-        // Sanitize it
-        nextGuess = clamped(nextGuess, knownInfeasibleHeight + 1,
-                                       knownFeasibleHeight - 1);
-      } else if (knownFeasibleHeight == NS_INTRINSICSIZE) {
-        // This can happen when we had a next-in-flow so we didn't
-        // want to do an unbounded height measuring step. Let's just increase
-        // from the infeasible height by some reasonable amount.
-        nextGuess = knownInfeasibleHeight*2 + 600;
+      if (!feasible && !aPresContext->HasPendingInterrupt()) {
+        // We may need to reflow one more time at the feasible height to
+        // get a valid layout.
+        bool skip = false;
+        if (knownInfeasibleHeight >= availableContentHeight) {
+          config.mColMaxHeight = availableContentHeight;
+          if (mLastBalanceHeight == availableContentHeight) {
+            skip = true;
+          }
+        } else {
+          config.mColMaxHeight = knownFeasibleHeight;
+        }
+        if (!skip) {
+          // If our height is unconstrained, make sure that the last column is
+          // allowed to have arbitrary height here, even though we were balancing.
+          // Otherwise we'd have to split, and it's not clear what we'd do with
+          // that.
+          AddStateBits(NS_FRAME_IS_DIRTY);
+          ReflowChildren(aDesiredSize, aReflowState, aStatus, config,
+                         availableContentHeight == NS_UNCONSTRAINEDSIZE,
+                         &carriedOutBottomMargin, colData);
+        }
       }
-      // Don't bother guessing more than our height constraint.
-      nextGuess = NS_MIN(availableContentHeight, nextGuess);
-
-#ifdef DEBUG_roc
-      printf("*** nsColumnSetFrame::Reflow balancing choosing next guess=%d\n", nextGuess);
-#endif
-
-      config.mColMaxHeight = nextGuess;
-      
-      unboundedLastColumn = false;
-      AddStateBits(NS_FRAME_IS_DIRTY);
-      feasible = ReflowChildren(aDesiredSize, aReflowState,
-                                aStatus, config, false, 
-                                &carriedOutBottomMargin, colData);
     }
 
-    if (!feasible && !aPresContext->HasPendingInterrupt()) {
-      // We may need to reflow one more time at the feasible height to
-      // get a valid layout.
-      bool skip = false;
-      if (knownInfeasibleHeight >= availableContentHeight) {
-        config.mColMaxHeight = availableContentHeight;
-        if (mLastBalanceHeight == availableContentHeight) {
-          skip = true;
-        }
-      } else {
-        config.mColMaxHeight = knownFeasibleHeight;
-      }
-      if (!skip) {
-        // If our height is unconstrained, make sure that the last column is
-        // allowed to have arbitrary height here, even though we were balancing.
-        // Otherwise we'd have to split, and it's not clear what we'd do with
-        // that.
-        AddStateBits(NS_FRAME_IS_DIRTY);
-        ReflowChildren(aDesiredSize, aReflowState, aStatus, config,
-                       availableContentHeight == NS_UNCONSTRAINEDSIZE,
-                       &carriedOutBottomMargin, colData);
-      }
+ } while (colData.mShouldRevertToAuto);
+
+    if (aPresContext->HasPendingInterrupt() &&
+        aReflowState.availableHeight == NS_UNCONSTRAINEDSIZE) {
+      // In this situation, we might be lying about our reflow status, because
+      // our last kid (the one that got interrupted) was incomplete.  Fix that.
+      aStatus = NS_FRAME_COMPLETE;
     }
-  }
+
+    CheckInvalidateSizeChange(aDesiredSize);
 
-  if (aPresContext->HasPendingInterrupt() &&
-      aReflowState.availableHeight == NS_UNCONSTRAINEDSIZE) {
-    // In this situation, we might be lying about our reflow status, because
-    // our last kid (the one that got interrupted) was incomplete.  Fix that.
-    aStatus = NS_FRAME_COMPLETE;
-  }
-  
-  CheckInvalidateSizeChange(aDesiredSize);
+    // XXXjwir3: This call should be replaced with FinishWithAbsoluteFrames
+    //           when bug 724978 is fixed and nsColumnSetFrame is a full absolute
+    //           container.
+    FinishAndStoreOverflow(&aDesiredSize);
 
-  // XXXjwir3: This call should be replaced with FinishWithAbsoluteFrames
-  //           when bug 724978 is fixed and nsColumnSetFrame is a full absolute
-  //           container.
-  FinishAndStoreOverflow(&aDesiredSize);
-
-  aDesiredSize.mCarriedOutBottomMargin = carriedOutBottomMargin;
+    aDesiredSize.mCarriedOutBottomMargin = carriedOutBottomMargin;
 
   NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
 
   NS_ASSERTION(NS_FRAME_IS_FULLY_COMPLETE(aStatus) ||
                aReflowState.availableHeight != NS_UNCONSTRAINEDSIZE,
                "Column set should be complete if the available height is unconstrained");
 
   return NS_OK;
--- a/layout/reftests/bugs/368020-1-ref.html
+++ b/layout/reftests/bugs/368020-1-ref.html
@@ -1,16 +1,16 @@
 <!DOCTYPE HTML>
 <html>
 <head>
 <title>Testcase, bug 368020</title>
 </head>
 <body>
 
-<div style="-moz-column-count: 2; column-count: 2; height: 4.5em; background:yellow">
+<div style="-moz-column-count: 2; column-count: 2; -moz-column-fill: auto; height: 4.5em; background:yellow">
 
   <div style="margin: 7px 1% 2px 2em; border: medium dotted; border-width: 2px 3px 4px 5px;">
     <div style="background: url(repeatable-diagonal-gradient.png);">
       <div style="padding: 8px 6px 4px 2px;">
         blah<br>
         blah<br>
         blah<br>
         blah
--- a/layout/reftests/bugs/368020-1.html
+++ b/layout/reftests/bugs/368020-1.html
@@ -1,16 +1,16 @@
 <!DOCTYPE HTML>
 <html>
 <head>
 <title>Testcase, bug 368020</title>
 </head>
 <body>
 
-<div style="-moz-column-count: 2; column-count: 2; height: 4.5em; background:yellow">
+<div style="-moz-column-count: 2; column-count: 2; -moz-column-fill: auto; height: 4.5em; background:yellow">
 
   <div>
     <div style="background: url(repeatable-diagonal-gradient.png); background-clip: padding-box; background-clip: padding; background-origin: padding-box; background-origin: padding; margin: 7px 1% 2px 2em; border: medium dotted; border-width: 2px 3px 4px 5px; padding: 8px 6px 4px 2px;">
       <div>
         blah<br>
         blah<br>
         blah<br>
         blah
--- a/layout/reftests/bugs/379349-2-ref.xhtml
+++ b/layout/reftests/bugs/379349-2-ref.xhtml
@@ -36,16 +36,17 @@
       width: 200pt;
       border-bottom: 4px solid blue;
     }
     body {
       height: 2.5in;
       width: 300pt;
       -moz-column-width: 100pt;
       -moz-column-gap: 0;
+      -moz-column-fill: auto;
       border: solid gray;
       position: relative;
     }
   </style>
  </head>
  <body>
   <div class="overflow">
   </div>
--- a/layout/reftests/bugs/379349-2a.xhtml
+++ b/layout/reftests/bugs/379349-2a.xhtml
@@ -43,16 +43,17 @@
       height: 800%;
       border-bottom-color: blue;
     }
     body {
       height: 2.5in;
       width: 300pt;
       -moz-column-width: 100pt;
       -moz-column-gap: 0;
+      -moz-column-fill: auto;
       border: solid gray;
     }
   </style>
  </head>
  <body>
   <div class="container no1">
     <div class="overflow">
     </div>
--- a/layout/reftests/bugs/379349-2b.xhtml
+++ b/layout/reftests/bugs/379349-2b.xhtml
@@ -43,16 +43,17 @@
       height: 800%;
       border-bottom-color: blue;
     }
     body {
       height: 2.5in;
       width: 300pt;
       -moz-column-width: 100pt;
       -moz-column-gap: 0;
+      -moz-column-fill: auto;
       border: solid gray;
     }
   </style>
  </head>
  <body onload="document.getElementById('tester1').style.height = '9in';
                document.getElementById('tester1').offsetHeight;
                document.getElementById('tester2').style.height = '29in';
                document.getElementById('tester2').offsetHeight;
--- a/layout/reftests/bugs/563584-9c.html
+++ b/layout/reftests/bugs/563584-9c.html
@@ -1,11 +1,11 @@
 <!DOCTYPE HTML>
 <title>Test for pushing of floats to next column when float breaking in columns is disabled</title>
-<body style="-moz-column-width: 200px; margin: 0; -moz-column-gap: 0; height: 200px;">
+<body style="-moz-column-width: 200px; -moz-column-fill: auto; margin: 0; -moz-column-gap: 0; height: 200px;">
 <div style="float: left;">
   <div style="display: inline-block; vertical-align: top; height: 150px; width: 200px; background: yellow"></div>
 </div>
 <div style="float: left;">
   <div style="display: inline-block; vertical-align: top; height: 150px; width: 200px; background: aqua"></div>
 </div>
 <div style="float: left;">
   <div style="display: inline-block; vertical-align: top; height: 150px; width: 200px; background: fuchsia"></div>
--- a/layout/reftests/bugs/563584-9d.html
+++ b/layout/reftests/bugs/563584-9d.html
@@ -1,11 +1,11 @@
 <!DOCTYPE HTML>
 <title>Test for pushing of floats to next column when float breaking in columns is disabled</title>
-<body style="-moz-column-width: 200px; margin: 0; -moz-column-gap: 0; height: 200px;">
+<body style="-moz-column-width: 200px; margin: 0; -moz-column-fill: auto; -moz-column-gap: 0; height: 200px;">
 <div style="float: left;">
   <div style="display: inline-block; vertical-align: top; height: 150px; width: 200px; background: yellow"></div>
 </div>
 <div>&nbsp;</div>
 <div style="float: left;">
   <div style="display: inline-block; vertical-align: top; height: 150px; width: 200px; background: aqua"></div>
 </div>
 <div>&nbsp;</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/columns/ahem.css
@@ -0,0 +1,4 @@
+@font-face {
+  font-family: "Ahem";
+  src: url(../fonts/Ahem.ttf);
+}
new file mode 100644
--- /dev/null
+++ b/layout/reftests/columns/columnfill-auto-ref.html
@@ -0,0 +1,32 @@
+<html>
+<head>
+  <link rel="stylesheet" type="text/css" href="ahem.css" />
+
+  <style>
+    td.text {
+      width: 200px;
+      text-align: left;
+      font-family: ahem;
+      font-size: 12pt;
+      line-height: 1.1;
+    }
+
+    table {
+      width: 100%;
+      font-family: ahem;
+      font-size: 12pt;
+      line-height: 1.1;
+    }
+  </style>
+</head>
+
+<body>
+  <table cellpadding=0 cellspacing=0>
+    <tr>
+      <td class="text" valign="top">
+        Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Sed feugiat libero vel diam.</td>
+      <td class="text" valign="top">Pellentesque pulvinar commodo lacus. Sed fringilla. Sed lectus. Praesent laoreet orci</td>
+      <td valign="top" class="text">vitae nisi. Duis venenatis tristique massa. Sed commodo diam at mauris.</td>
+    </tr>
+  </table>
+</body>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/columns/columnfill-auto.html
@@ -0,0 +1,19 @@
+<html>
+  <head>
+    <link rel="stylesheet" type="text/css" href="ahem.css" />
+  </head>
+
+  <body>
+    <div style="width: 100%">
+    <div style="-moz-column-width: 200px;
+                -moz-column-gap: 0px;
+                -moz-column-fill: auto;
+                height: 120px;
+                font-family: ahem;
+                font-size: 12pt;
+		line-height: 1.1;">
+      Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Sed feugiat libero vel diam. Pellentesque pulvinar commodo lacus. Sed fringilla. Sed lectus. Praesent laoreet orci vitae nisi. Duis venenatis tristique massa. Sed commodo diam at mauris.
+    </div>
+    </div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/columns/columnfill-balance-ref.html
@@ -0,0 +1,33 @@
+<html>
+  <head>
+    <link rel="stylesheet" type="text/css" href="ahem.css" />
+
+    <style>
+      td {
+        width: 200px;
+        font-family: ahem;
+      }
+
+      table {
+        width: 100%;
+        height: 150px;
+        padding-bottom: 0;
+        margin-bottom: 0;
+        font-family: ahem;
+      }
+    </style>
+  </head>
+  <body>
+    <table cellpadding=0 cellspacing=0>
+      <tr>
+        <td valign="top">
+          Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Sed feugiat libero vel diam.
+        </td>
+        <td valign="top">Pellentesque pulvinar commodo lacus. Sed fringilla. Sed lectus. Praesent laoreet orci
+        </td>
+        <td valign="top">vitae nisi. Duis venenatis tristique massa. Sed commodo diam at mauris.
+        </td>
+      </tr>
+    </table>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/columns/columnfill-balance.html
@@ -0,0 +1,16 @@
+<html>
+  <head>
+      <link rel="stylesheet" type="text/css" href="ahem.css" />
+  </head>
+  <body>
+    <div style="-moz-column-width: 200px;
+                -moz-column-gap: 0px;
+                -moz-column-fill: balance;
+                height: 150px;
+                margin-bottom: 0;
+                padding-bottom: 0;
+                font-family: ahem;">
+      Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Sed feugiat libero vel diam. Pellentesque pulvinar commodo lacus. Sed fringilla. Sed lectus. Praesent laoreet orci vitae nisi. Duis venenatis tristique massa. Sed commodo diam at mauris.
+    </div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/columns/columnfill-overflow-ref.html
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <style type="text/css">
+      div.container {
+        width:54em;
+        background-color: gray;
+      }
+
+      div.multicolumn {
+        height: 5em;
+        overflow: visible;
+
+        column-width:15em;
+        column-gap: 2em;
+        column-rule: 4px solid green;
+        column-fill: auto;
+
+        -moz-column-width:15em;
+        -moz-column-gap: 2em;
+        -moz-column-rule: 4px solid green;
+        -moz-column-fill: auto;
+
+        padding: 5px;
+      }
+
+      p {
+        margin: 0;
+        padding: 0
+      }
+    </style>
+  </head>
+  <body>
+    <div class="container">
+      <div class="multicolumn">
+        <p>Ab cde fgh i jkl. Mnopqr stu vw xyz. A bcdef g hij klm nopqrstuv wxy z. Abc de fghi jklmno. Pqrstu vwx yz. Abc def ghi jkl.M nop qrst uv wx yz. Ab cde fgh i jkl. Mnopqr stu vw xyz. A bcdef g hij klm nopqrstuv wxy z. Abc de fghi jklmno. Pqrstu vwx yz. Abc def ghi jkl.M nop qrst uv wx yz. Ab cde fgh i jkl. Mnopqr stu vw xyz. A bcdef g hij klm nopqrstuv wxy z. Abc de fghi jklmno. Pqrstu vwx yz. Abc def ghi jkl.M nop qrst uv wx yz. Ab cde fgh i jkl. Mnopqr stu vw xyz. A bcdef g hij klm nopqrstuv wxy z. Abc de fghi jklmno. Pqrstu vwx yz. Abc def ghi jkl.M nop qrst uv wx yz. Ab cde fgh i jkl. Mnopqr stu vw xyz. A bcdef g hij klm nopqrstuv wxy z. Abc de fghi jklmno. Pqrstu vwx yz. Abc def ghi jkl.M nop qrst uv wx yz. Ab cde fgh i jkl. Mnopqr stu vw xyz. A bcdef g hij klm nopqrstuv wxy z. Abc de fghi jklmno. Pqrstu vwx yz. Abc def ghi jkl.M nop qrst uv wx yz. Ab cde fgh i jkl. Mnopqr stu vw xyz. A bcdef g hij klm nopqrstuv wxy z. Abc de fghi jklmno. Pqrstu vwx yz. Abc def ghi jkl.M nop qrst uv wx yz. </p>
+      </div>
+    </div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/columns/columnfill-overflow.html
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <style type="text/css">
+      div.container {
+        width:54em;
+        background-color: gray;
+      }
+
+      div.multicolumn {
+        height: 5em;
+        overflow: visible;
+
+        column-width:15em;
+        column-gap: 2em;
+        column-rule: 4px solid green;
+        column-fill: balance;
+
+        -moz-column-width:15em;
+        -moz-column-gap: 2em;
+        -moz-column-rule: 4px solid green;
+        -moz-column-fill: balance;
+
+        padding: 5px;
+      }
+
+      p {
+        margin: 0;
+        padding: 0
+      }
+    </style>
+  </head>
+  <body>
+    <div class="container">
+      <div class="multicolumn">
+        <p>Ab cde fgh i jkl. Mnopqr stu vw xyz. A bcdef g hij klm nopqrstuv wxy z. Abc de fghi jklmno. Pqrstu vwx yz. Abc def ghi jkl.M nop qrst uv wx yz. Ab cde fgh i jkl. Mnopqr stu vw xyz. A bcdef g hij klm nopqrstuv wxy z. Abc de fghi jklmno. Pqrstu vwx yz. Abc def ghi jkl.M nop qrst uv wx yz. Ab cde fgh i jkl. Mnopqr stu vw xyz. A bcdef g hij klm nopqrstuv wxy z. Abc de fghi jklmno. Pqrstu vwx yz. Abc def ghi jkl.M nop qrst uv wx yz. Ab cde fgh i jkl. Mnopqr stu vw xyz. A bcdef g hij klm nopqrstuv wxy z. Abc de fghi jklmno. Pqrstu vwx yz. Abc def ghi jkl.M nop qrst uv wx yz. Ab cde fgh i jkl. Mnopqr stu vw xyz. A bcdef g hij klm nopqrstuv wxy z. Abc de fghi jklmno. Pqrstu vwx yz. Abc def ghi jkl.M nop qrst uv wx yz. Ab cde fgh i jkl. Mnopqr stu vw xyz. A bcdef g hij klm nopqrstuv wxy z. Abc de fghi jklmno. Pqrstu vwx yz. Abc def ghi jkl.M nop qrst uv wx yz. Ab cde fgh i jkl. Mnopqr stu vw xyz. A bcdef g hij klm nopqrstuv wxy z. Abc de fghi jklmno. Pqrstu vwx yz. Abc def ghi jkl.M nop qrst uv wx yz. </p>
+      </div>
+    </div>
+  </body>
+</html>
--- a/layout/reftests/columns/reftest.list
+++ b/layout/reftests/columns/reftest.list
@@ -11,14 +11,17 @@
 == column-balancing-overflow-003.html column-balancing-overflow-003.ref.html
 == column-balancing-overflow-004.html column-balancing-overflow-004.ref.html
 == column-balancing-overflow-005.html column-balancing-overflow-005.ref.html
 == column-balancing-000.html column-balancing-000.ref.html
 == column-balancing-001.html column-balancing-000.ref.html
 == column-balancing-002.html column-balancing-002.ref.html
 == column-balancing-003.html column-balancing-000.ref.html
 == column-balancing-004.html column-balancing-004.ref.html
+HTTP(..) == columnfill-balance.html columnfill-balance-ref.html
+HTTP(..) == columnfill-auto.html columnfill-auto-ref.html
 == columnrule-basic.html columnrule-basic-ref.html
 == columnrule-complex.html columnrule-complex-ref.html
 != columnrule-linestyles.html columnrule-linestyles-notref.html
 == columnrule-padding.html columnrule-padding-ref.html
+== columnfill-overflow.html columnfill-overflow-ref.html
 == margin-collapsing-bug616722-1.html margin-collapsing-bug616722-1-ref.html
 == margin-collapsing-bug616722-2.html margin-collapsing-bug616722-2-ref.html
--- a/layout/reftests/pagination/abspos-overflow-01-cols.xhtml
+++ b/layout/reftests/pagination/abspos-overflow-01-cols.xhtml
@@ -29,16 +29,17 @@
       background: white;
       width: 100pt;
     }
     #colset {
       width: 300pt;
       height: 2in;
       -moz-column-count: 3;
       -moz-column-gap: 0;
+      -moz-column-fill: auto;
       border: silver 2pt;
       border-style: none solid;
     }
     #redline {
       width: 303pt;
       border-top: 4px solid red;
       margin-top: -1in;
       position: relative;
--- a/layout/reftests/pagination/border-breaking-000-cols.xhtml
+++ b/layout/reftests/pagination/border-breaking-000-cols.xhtml
@@ -20,16 +20,17 @@
       height: 200px;
     }
 
     body {
       height: 200px;
       width: 300px;
       -moz-column-width: 150px;
       -moz-column-gap: 0;
+      -moz-column-fill: auto;
       border: solid silver;
       border-style: none solid;
     }
   </style>
  </head>
  <body>
   <div class="container">
     <div class="box">
--- a/layout/reftests/pagination/border-breaking-001-cols.ref.xhtml
+++ b/layout/reftests/pagination/border-breaking-001-cols.ref.xhtml
@@ -15,16 +15,17 @@
       height: 500px;
     }
 
     .body {
       height: 200px;
       width: 300px;
       -moz-column-width: 100px;
       -moz-column-gap: 0;
+      -moz-column-fill: auto;
       border: solid silver;
       border-style: none solid;
       background: yellow;
     }
   </style>
  </head>
  <body>
   <div class="body">
--- a/layout/reftests/pagination/border-breaking-001-cols.xhtml
+++ b/layout/reftests/pagination/border-breaking-001-cols.xhtml
@@ -44,16 +44,17 @@
       height: 100px;
     }
 
     body {
       height: 200px;
       width: 300px;
       -moz-column-width: 100px;
       -moz-column-gap: 0;
+      -moz-column-fill: auto;
       border: solid silver;
       border-style: none solid;
     }
   </style>
  </head>
  <body>
   <div class="abs">
     <div class="container">
--- a/layout/reftests/pagination/border-breaking-002-cols.ref.xhtml
+++ b/layout/reftests/pagination/border-breaking-002-cols.ref.xhtml
@@ -11,16 +11,17 @@
       border-top: solid 10px aqua;
     }
 
     .multicol {
       height: 200px;
       width: 300px;
       -moz-column-width: 150px;
       -moz-column-gap: 0;
+      -moz-column-fill: auto;
       border: solid silver;
     }
   </style>
  </head>
  <body>
   There must be a continuous 10px line at the top
   of the gray box, the left half blue and the right
   half aqua.
--- a/layout/reftests/pagination/border-breaking-002-cols.xhtml
+++ b/layout/reftests/pagination/border-breaking-002-cols.xhtml
@@ -12,16 +12,17 @@
       border-bottom: solid 10px aqua;
     }
 
     .multicol {
       height: 200px;
       width: 300px;
       -moz-column-width: 150px;
       -moz-column-gap: 0;
+      -moz-column-fill: auto;
       border: solid silver;
     }
   </style>
  </head>
  <body>
   There must be a continuous 10px line at the top
   of the gray box, the left half blue and the right
   half aqua.
--- a/layout/reftests/pagination/border-breaking-003-cols.xhtml
+++ b/layout/reftests/pagination/border-breaking-003-cols.xhtml
@@ -15,16 +15,17 @@
       border-bottom: 10px solid aqua;
     }
 
     .multicol {
       height: 200px;
       width: 300px;
       -moz-column-width: 150px;
       -moz-column-gap: 0;
+      -moz-column-fill: auto;
       border: solid silver;
     }
   </style>
  </head>
  <body>
   There must be two continuous 10px lines at the top
   of the gray box, the top one blue and the bottom one
   aqua.
--- a/layout/reftests/pagination/content-inserted-002.ref.xhtml
+++ b/layout/reftests/pagination/content-inserted-002.ref.xhtml
@@ -8,16 +8,17 @@
       font-size: 16px;
     }
 
     #colset {
       height: 200px;
       width: 450px;
       -moz-column-width: 150px;
       -moz-column-gap: 0;
+      -moz-column-fill: auto;
       border: 3px solid silver;
     }
 
     #mark {
       border-bottom: 4px solid blue;
     }
 
     #shift {
--- a/layout/reftests/pagination/content-inserted-002.xhtml
+++ b/layout/reftests/pagination/content-inserted-002.xhtml
@@ -8,16 +8,17 @@
       font-size: 16px;
     }
 
     #colset {
       height: 200px;
       width: 450px;
       -moz-column-width: 150px;
       -moz-column-gap: 0;
+      -moz-column-fill: auto;
       border: 3px solid silver;
     }
 
     #x {
       height: 500px;
     }
 
     #x:after {
--- a/layout/reftests/pagination/content-inserted-003.xhtml
+++ b/layout/reftests/pagination/content-inserted-003.xhtml
@@ -8,16 +8,17 @@
       font-size: 16px;
     }
 
     #colset {
       height: 200px;
       width: 450px;
       -moz-column-width: 150px;
       -moz-column-gap: 0;
+      -moz-column-fill: auto;
       border: 3px solid silver;
     }
 
     #x {
       height: 500px;
     }
 
     #x:after {
--- a/layout/reftests/pagination/content-inserted-004.xhtml
+++ b/layout/reftests/pagination/content-inserted-004.xhtml
@@ -8,16 +8,17 @@
       font-size: 16px;
     }
 
     #colset {
       height: 200px;
       width: 450px;
       -moz-column-width: 150px;
       -moz-column-gap: 0;
+      -moz-column-fill: auto;
       border: 3px solid silver;
     }
 
     #x {
       height: 500px;
     }
 
     #x:before {
--- a/layout/reftests/pagination/content-inserted-005.xhtml
+++ b/layout/reftests/pagination/content-inserted-005.xhtml
@@ -8,16 +8,17 @@
       font-size: 16px;
     }
 
     #colset {
       height: 200px;
       width: 450px;
       -moz-column-width: 150px;
       -moz-column-gap: 0;
+      -moz-column-fill: auto;
       border: 3px solid silver;
     }
 
     #x {
       border-bottom: 4px solid blue;
     }
 
     #x:before {
--- a/layout/reftests/pagination/content-inserted-006.xhtml
+++ b/layout/reftests/pagination/content-inserted-006.xhtml
@@ -8,16 +8,17 @@
       font-size: 16px;
     }
 
     #colset {
       height: 200px;
       width: 450px;
       -moz-column-width: 150px;
       -moz-column-gap: 0;
+      -moz-column-fill: auto;
       border: 3px solid silver;
     }
 
     #x {
       height: 500px;
     }
 
     #x:after {
--- a/layout/reftests/pagination/content-inserted-007.xhtml
+++ b/layout/reftests/pagination/content-inserted-007.xhtml
@@ -8,16 +8,17 @@
       font-size: 16px;
     }
 
     #colset {
       height: 200px;
       width: 450px;
       -moz-column-width: 150px;
       -moz-column-gap: 0;
+      -moz-column-fill: auto;
       border: 3px solid silver;
     }
 
     #x {
       height: 500px;
     }
 
     #x:before {
--- a/layout/reftests/pagination/content-inserted-009.xhtml
+++ b/layout/reftests/pagination/content-inserted-009.xhtml
@@ -8,16 +8,17 @@
       font-size: 16px;
     }
 
     #colset {
       height: 200px;
       width: 450px;
       -moz-column-width: 150px;
       -moz-column-gap: 0;
+      -moz-column-fill: auto;
       border: 3px solid silver;
     }
 
     #shift {
       height: 201px;
       border-bottom: 2px solid blue;
     }
     #overflow {
--- a/layout/style/nsCSSKeywordList.h
+++ b/layout/style/nsCSSKeywordList.h
@@ -167,16 +167,17 @@ CSS_KEY(alternate, alternate)
 CSS_KEY(alternate-reverse, alternate_reverse)
 CSS_KEY(always, always)
 CSS_KEY(appworkspace, appworkspace)
 CSS_KEY(armenian, armenian)
 CSS_KEY(auto, auto)
 CSS_KEY(avoid, avoid)
 CSS_KEY(background, background)
 CSS_KEY(backwards, backwards)
+CSS_KEY(balance, balance)
 CSS_KEY(baseline, baseline)
 CSS_KEY(bidi-override, bidi_override)
 CSS_KEY(blink, blink)
 CSS_KEY(block, block)
 CSS_KEY(block-axis, block_axis)
 CSS_KEY(bold, bold)
 CSS_KEY(bolder, bolder)
 CSS_KEY(border-box, border_box)
--- a/layout/style/nsCSSPropList.h
+++ b/layout/style/nsCSSPropList.h
@@ -1386,16 +1386,26 @@ CSS_PROP_COLUMN(
         // need to change NS_STYLE_COLUMN_COUNT_AUTO to something else.
         CSS_PROPERTY_VALUE_AT_LEAST_ONE,
     "",
     VARIANT_AHI,
     nullptr,
     offsetof(nsStyleColumn, mColumnCount),
     eStyleAnimType_Custom)
 CSS_PROP_COLUMN(
+    -moz-column-fill,
+    _moz_column_fill,
+    CSS_PROP_DOMPROP_PREFIXED(ColumnFill),
+    CSS_PROPERTY_PARSE_VALUE,
+    "",
+    VARIANT_HK,
+    kColumnFillKTable,
+    CSS_PROP_NO_OFFSET,
+    eStyleAnimType_None)
+CSS_PROP_COLUMN(
     -moz-column-width,
     _moz_column_width,
     CSS_PROP_DOMPROP_PREFIXED(ColumnWidth),
     CSS_PROPERTY_PARSE_VALUE |
         CSS_PROPERTY_VALUE_NONNEGATIVE,
     "",
     VARIANT_AHL | VARIANT_CALC,
     nullptr,
--- a/layout/style/nsCSSProps.cpp
+++ b/layout/style/nsCSSProps.cpp
@@ -1590,16 +1590,22 @@ const PRInt32 nsCSSProps::kVectorEffectK
 
 const PRInt32 nsCSSProps::kColorInterpolationKTable[] = {
   eCSSKeyword_auto, NS_STYLE_COLOR_INTERPOLATION_AUTO,
   eCSSKeyword_srgb, NS_STYLE_COLOR_INTERPOLATION_SRGB,
   eCSSKeyword_linearrgb, NS_STYLE_COLOR_INTERPOLATION_LINEARRGB,
   eCSSKeyword_UNKNOWN, -1
 };
 
+const PRInt32 nsCSSProps::kColumnFillKTable[] = {
+  eCSSKeyword_auto, NS_STYLE_COLUMN_FILL_AUTO,
+  eCSSKeyword_balance, NS_STYLE_COLUMN_FILL_BALANCE,
+  eCSSKeyword_UNKNOWN, -1
+};
+
 bool
 nsCSSProps::FindKeyword(nsCSSKeyword aKeyword, const PRInt32 aTable[], PRInt32& aResult)
 {
   PRInt32 index = 0;
   while (eCSSKeyword_UNKNOWN != nsCSSKeyword(aTable[index])) {
     if (aKeyword == nsCSSKeyword(aTable[index])) {
       aResult = aTable[index+1];
       return true;
--- a/layout/style/nsCSSProps.h
+++ b/layout/style/nsCSSProps.h
@@ -354,16 +354,17 @@ public:
   static const PRInt32 kImageRenderingKTable[];
   static const PRInt32 kShapeRenderingKTable[];
   static const PRInt32 kStrokeLinecapKTable[];
   static const PRInt32 kStrokeLinejoinKTable[];
   static const PRInt32 kVectorEffectKTable[];
   static const PRInt32 kTextAnchorKTable[];
   static const PRInt32 kTextRenderingKTable[];
   static const PRInt32 kColorInterpolationKTable[];
+  static const PRInt32 kColumnFillKTable[];
   static const PRInt32 kBoxPropSourceKTable[];
   static const PRInt32 kBoxShadowTypeKTable[];
   static const PRInt32 kBoxSizingKTable[];
   static const PRInt32 kCaptionSideKTable[];
   static const PRInt32 kClearKTable[];
   static const PRInt32 kColorKTable[];
   static const PRInt32 kContentKTable[];
   static const PRInt32 kCursorKTable[];
--- a/layout/style/nsComputedDOMStyle.cpp
+++ b/layout/style/nsComputedDOMStyle.cpp
@@ -695,16 +695,26 @@ nsComputedDOMStyle::DoGetColumnGap()
   } else {
     SetValueToCoord(val, GetStyleColumn()->mColumnGap, true);
   }
 
   return val;
 }
 
 nsIDOMCSSValue*
+nsComputedDOMStyle::DoGetColumnFill()
+{
+  nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
+  val->SetIdent(
+    nsCSSProps::ValueToKeywordEnum(GetStyleColumn()->mColumnFill,
+                                   nsCSSProps::kColumnFillKTable));
+  return val;
+}
+
+nsIDOMCSSValue*
 nsComputedDOMStyle::DoGetColumnRuleWidth()
 {
   nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
   val->SetAppUnits(GetStyleColumn()->GetComputedColumnRuleWidth());
   return val;
 }
 
 nsIDOMCSSValue*
@@ -4763,16 +4773,17 @@ nsComputedDOMStyle::GetQueryableProperty
     COMPUTED_STYLE_MAP_ENTRY(box_align,                     BoxAlign),
     COMPUTED_STYLE_MAP_ENTRY(box_direction,                 BoxDirection),
     COMPUTED_STYLE_MAP_ENTRY(box_flex,                      BoxFlex),
     COMPUTED_STYLE_MAP_ENTRY(box_ordinal_group,             BoxOrdinalGroup),
     COMPUTED_STYLE_MAP_ENTRY(box_orient,                    BoxOrient),
     COMPUTED_STYLE_MAP_ENTRY(box_pack,                      BoxPack),
     COMPUTED_STYLE_MAP_ENTRY(box_sizing,                    BoxSizing),
     COMPUTED_STYLE_MAP_ENTRY(_moz_column_count,             ColumnCount),
+    COMPUTED_STYLE_MAP_ENTRY(_moz_column_fill,              ColumnFill),
     COMPUTED_STYLE_MAP_ENTRY(_moz_column_gap,               ColumnGap),
     //// COMPUTED_STYLE_MAP_ENTRY(_moz_column_rule,         ColumnRule),
     COMPUTED_STYLE_MAP_ENTRY(_moz_column_rule_color,        ColumnRuleColor),
     COMPUTED_STYLE_MAP_ENTRY(_moz_column_rule_style,        ColumnRuleStyle),
     COMPUTED_STYLE_MAP_ENTRY(_moz_column_rule_width,        ColumnRuleWidth),
     COMPUTED_STYLE_MAP_ENTRY(_moz_column_width,             ColumnWidth),
 #ifdef MOZ_FLEXBOX
     COMPUTED_STYLE_MAP_ENTRY(flex_basis,                    FlexBasis),
--- a/layout/style/nsComputedDOMStyle.h
+++ b/layout/style/nsComputedDOMStyle.h
@@ -328,16 +328,17 @@ private:
   nsIDOMCSSValue* DoGetIMEMode();
   nsIDOMCSSValue* DoGetUserFocus();
   nsIDOMCSSValue* DoGetUserInput();
   nsIDOMCSSValue* DoGetUserModify();
   nsIDOMCSSValue* DoGetUserSelect();
 
   /* Column properties */
   nsIDOMCSSValue* DoGetColumnCount();
+  nsIDOMCSSValue* DoGetColumnFill();
   nsIDOMCSSValue* DoGetColumnWidth();
   nsIDOMCSSValue* DoGetColumnGap();
   nsIDOMCSSValue* DoGetColumnRuleWidth();
   nsIDOMCSSValue* DoGetColumnRuleStyle();
   nsIDOMCSSValue* DoGetColumnRuleColor();
 
   /* CSS Transitions */
   nsIDOMCSSValue* DoGetTransitionProperty();
--- a/layout/style/nsRuleNode.cpp
+++ b/layout/style/nsRuleNode.cpp
@@ -7092,16 +7092,23 @@ nsRuleNode::ComputeColumnData(void* aSta
            eCSSUnit_Enumerated == colorValue.GetUnit()) {
     column->mColumnRuleColorIsForeground = true;
   }
   else if (SetColor(colorValue, 0, mPresContext, aContext,
                     column->mColumnRuleColor, canStoreInRuleTree)) {
     column->mColumnRuleColorIsForeground = false;
   }
 
+  // column-fill: enum
+  SetDiscrete(*aRuleData->ValueForColumnFill(),
+                column->mColumnFill, canStoreInRuleTree,
+                SETDSC_ENUMERATED, parent->mColumnFill,
+                NS_STYLE_COLUMN_FILL_BALANCE,
+                0, 0, 0, 0);
+
   COMPUTE_END_RESET(Column, column)
 }
 
 static void
 SetSVGPaint(const nsCSSValue& aValue, const nsStyleSVGPaint& parentPaint,
             nsPresContext* aPresContext, nsStyleContext *aContext,
             nsStyleSVGPaint& aResult, nsStyleSVGPaintType aInitialPaintType,
             bool& aCanStoreInRuleTree)
--- a/layout/style/nsStyleStruct.cpp
+++ b/layout/style/nsStyleStruct.cpp
@@ -769,16 +769,17 @@ nsChangeHint nsStyleXUL::MaxDifference()
 // nsStyleColumn
 //
 nsStyleColumn::nsStyleColumn(nsPresContext* aPresContext)
 {
   MOZ_COUNT_CTOR(nsStyleColumn);
   mColumnCount = NS_STYLE_COLUMN_COUNT_AUTO;
   mColumnWidth.SetAutoValue();
   mColumnGap.SetNormalValue();
+  mColumnFill = NS_STYLE_COLUMN_FILL_BALANCE;
 
   mColumnRuleWidth = (aPresContext->GetBorderWidthTable())[NS_STYLE_BORDER_WIDTH_MEDIUM];
   mColumnRuleStyle = NS_STYLE_BORDER_STYLE_NONE;
   mColumnRuleColor = NS_RGB(0, 0, 0);
   mColumnRuleColorIsForeground = true;
 
   mTwipsPerPixel = aPresContext->AppUnitsPerDevPixel();
 }
@@ -800,17 +801,18 @@ nsChangeHint nsStyleColumn::CalcDifferen
       != (aOther.mColumnWidth.GetUnit() == eStyleUnit_Auto) ||
       mColumnCount != aOther.mColumnCount)
     // We force column count changes to do a reframe, because it's tricky to handle
     // some edge cases where the column count gets smaller and content overflows.
     // XXX not ideal
     return NS_STYLE_HINT_FRAMECHANGE;
 
   if (mColumnWidth != aOther.mColumnWidth ||
-      mColumnGap != aOther.mColumnGap)
+      mColumnGap != aOther.mColumnGap ||
+      mColumnFill != aOther.mColumnFill)
     return NS_STYLE_HINT_REFLOW;
 
   if (GetComputedColumnRuleWidth() != aOther.GetComputedColumnRuleWidth() ||
       mColumnRuleStyle != aOther.mColumnRuleStyle ||
       mColumnRuleColor != aOther.mColumnRuleColor ||
       mColumnRuleColorIsForeground != aOther.mColumnRuleColorIsForeground)
     return NS_STYLE_HINT_VISUAL;
 
--- a/layout/style/nsStyleStruct.h
+++ b/layout/style/nsStyleStruct.h
@@ -2093,16 +2093,18 @@ struct nsStyleColumn {
   static bool ForceCompare() { return false; }
 
   PRUint32     mColumnCount; // [reset] see nsStyleConsts.h
   nsStyleCoord mColumnWidth; // [reset] coord, auto
   nsStyleCoord mColumnGap;   // [reset] coord, normal
 
   nscolor      mColumnRuleColor;  // [reset]
   PRUint8      mColumnRuleStyle;  // [reset]
+  PRUint8      mColumnFill;  // [reset] see nsStyleConsts.h
+
   // See https://bugzilla.mozilla.org/show_bug.cgi?id=271586#c43 for why
   // this is hard to replace with 'currentColor'.
   bool mColumnRuleColorIsForeground;
 
   void SetColumnRuleWidth(nscoord aWidth) {
     mColumnRuleWidth = NS_ROUND_BORDER_TO_PIXELS(aWidth, mTwipsPerPixel);
   }
 
--- a/layout/style/test/property_database.js
+++ b/layout/style/test/property_database.js
@@ -514,16 +514,24 @@ var gCSSProperties = {
 		domProp: "MozColumnCount",
 		inherited: false,
 		type: CSS_TYPE_LONGHAND,
 		initial_values: [ "auto" ],
 		other_values: [ "1", "17" ],
 		// negative and zero invalid per editor's draft
 		invalid_values: [ "-1", "0", "3px" ]
 	},
+        "-moz-column-fill": {
+                domProp: "MozColumnFill",
+                inherited: false,
+                type: CSS_TYPE_LONGHAND,
+                initial_values: [ "balance" ],
+                other_values: [ "auto" ],
+                invalid_values: [ "2px", "dotted", "5em" ]
+        },
 	"-moz-column-gap": {
 		domProp: "MozColumnGap",
 		inherited: false,
 		type: CSS_TYPE_LONGHAND,
 		initial_values: [ "normal", "1em", "calc(-2em + 3em)" ],
 		other_values: [ "2px", "4em",
 			"calc(2px)",
 			"calc(-2px)",