Bug 1151212 part 1 - [css-grid] Introduce a few local structs (GridReflowState, Tracks, TrackSizingFunctions) to make it easier to pass around data. r=dholbert
☠☠ backed out by dafa4f1221cb ☠ ☠
authorMats Palmgren <mats@mozilla.com>
Fri, 04 Sep 2015 22:06:57 +0200
changeset 293622 96fd29a6c902d80fa42c38f3cd0c8e8cc9a75371
parent 293621 24cd0974b365f1eebd22167e5c004d00305e86a5
child 293623 1194452bc07184aecf9c94df28b09fdf97be85c2
push id5245
push userraliiev@mozilla.com
push dateThu, 29 Oct 2015 11:30:51 +0000
treeherdermozilla-beta@dac831dc1bd0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdholbert
bugs1151212
milestone43.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 1151212 part 1 - [css-grid] Introduce a few local structs (GridReflowState, Tracks, TrackSizingFunctions) to make it easier to pass around data. r=dholbert
layout/generic/nsGridContainerFrame.cpp
layout/generic/nsGridContainerFrame.h
--- a/layout/generic/nsGridContainerFrame.cpp
+++ b/layout/generic/nsGridContainerFrame.cpp
@@ -15,16 +15,17 @@
 #include "nsAlgorithm.h" // for clamped()
 #include "nsAutoPtr.h"
 #include "nsCSSAnonBoxes.h"
 #include "nsDataHashtable.h"
 #include "nsDisplayList.h"
 #include "nsHashKeys.h"
 #include "nsIFrameInlines.h"
 #include "nsPresContext.h"
+#include "nsRenderingContext.h"
 #include "nsReadableUtils.h"
 #include "nsRuleNode.h"
 #include "nsStyleContext.h"
 
 using namespace mozilla;
 typedef nsGridContainerFrame::TrackSize TrackSize;
 const uint32_t nsGridContainerFrame::kTranslatedMaxLine =
   uint32_t(nsStyleGridLine::kMaxLine - nsStyleGridLine::kMinLine - 1);
@@ -164,16 +165,112 @@ private:
   bool mSkipPlaceholders;
 #ifdef DEBUG
   nsIFrame* mGridContainer;
   nsIFrame::ChildListID mListID;
 #endif
 };
 
 /**
+ * Encapsulates CSS track-sizing functions.
+ */
+struct MOZ_STACK_CLASS nsGridContainerFrame::TrackSizingFunctions
+{
+  const nsStyleCoord& MinSizingFor(uint32_t aTrackIndex) const
+  {
+    if (MOZ_UNLIKELY(aTrackIndex < mExplicitGridOffset)) {
+      return mAutoMinSizing;
+    }
+    uint32_t index = aTrackIndex - mExplicitGridOffset;
+    return index < mMinSizingFunctions.Length() ?
+      mMinSizingFunctions[index] : mAutoMinSizing;
+  }
+  const nsStyleCoord& MaxSizingFor(uint32_t aTrackIndex) const
+  {
+    if (MOZ_UNLIKELY(aTrackIndex < mExplicitGridOffset)) {
+      return mAutoMaxSizing;
+    }
+    uint32_t index = aTrackIndex - mExplicitGridOffset;
+    return index < mMaxSizingFunctions.Length() ?
+      mMaxSizingFunctions[index] : mAutoMaxSizing;
+  }
+
+  const nsTArray<nsStyleCoord>& mMinSizingFunctions;
+  const nsTArray<nsStyleCoord>& mMaxSizingFunctions;
+  const nsStyleCoord& mAutoMinSizing;
+  const nsStyleCoord& mAutoMaxSizing;
+  uint32_t mExplicitGridOffset;
+};
+
+/**
+ * State for the tracks in one dimension.
+ */
+struct MOZ_STACK_CLASS nsGridContainerFrame::Tracks
+{
+  void Initialize(const TrackSizingFunctions& aFunctions,
+                  nscoord                     aPercentageBasis);
+
+  nsAutoTArray<TrackSize, 32> mSizes;
+};
+
+struct MOZ_STACK_CLASS nsGridContainerFrame::GridReflowState
+{
+  GridReflowState(nsGridContainerFrame*    aFrame,
+                  const nsHTMLReflowState& aRS)
+    : GridReflowState(aFrame, *aRS.rendContext, &aRS, aRS.mStylePosition,
+                      aRS.GetWritingMode())
+  {}
+  GridReflowState(nsGridContainerFrame* aFrame,
+                  nsRenderingContext&   aRC)
+    : GridReflowState(aFrame, aRC, nullptr, aFrame->StylePosition(),
+                      aFrame->GetWritingMode())
+  {}
+
+  GridItemCSSOrderIterator mIter;
+  const nsStylePosition* const mGridStyle;
+  Tracks mCols;
+  Tracks mRows;
+  TrackSizingFunctions mColFunctions;
+  TrackSizingFunctions mRowFunctions;
+  /**
+   * @note mReflowState may be null when using the 2nd ctor above. In this case
+   * we'll construct a dummy parent reflow state if we need it to calculate
+   * min/max-content contributions when sizing tracks.
+   */
+  const nsHTMLReflowState* mReflowState;
+  nsRenderingContext& mRenderingContext;
+  const WritingMode mWM;
+
+private:
+  GridReflowState(nsGridContainerFrame*    aFrame,
+                  nsRenderingContext&      aRenderingContext,
+                  const nsHTMLReflowState* aReflowState,
+                  const nsStylePosition*   aGridStyle,
+                  const WritingMode&       aWM)
+    : mIter(aFrame, kPrincipalList)
+    , mGridStyle(aGridStyle)
+    , mColFunctions({
+        mGridStyle->mGridTemplateColumns.mMinTrackSizingFunctions,
+        mGridStyle->mGridTemplateColumns.mMaxTrackSizingFunctions,
+        mGridStyle->mGridAutoColumnsMin,
+        mGridStyle->mGridAutoColumnsMax,
+      })
+    , mRowFunctions({
+        mGridStyle->mGridTemplateRows.mMinTrackSizingFunctions,
+        mGridStyle->mGridTemplateRows.mMaxTrackSizingFunctions,
+        mGridStyle->mGridAutoRowsMin,
+        mGridStyle->mGridAutoRowsMax,
+      })
+    , mReflowState(aReflowState)
+    , mRenderingContext(aRenderingContext)
+    , mWM(aWM)
+  {}
+};
+
+/**
  * Search for the aNth occurrence of aName in aNameList (forward), starting at
  * the zero-based aFromIndex, and return the 1-based index (line number).
  * Also take into account there is an unconditional match at aImplicitLine
  * unless it's zero.
  * Return zero if aNth occurrences can't be found.  In that case, aNth has
  * been decremented with the number of occurrences that were found (if any).
  */
 static uint32_t
@@ -875,29 +972,30 @@ nsGridContainerFrame::InitializeGridBoun
     std::min(mExplicitGridColEnd, uint32_t(nsStyleGridLine::kMaxLine));
   mExplicitGridRowEnd =
     std::min(mExplicitGridRowEnd, uint32_t(nsStyleGridLine::kMaxLine));
   mGridColEnd = mExplicitGridColEnd;
   mGridRowEnd = mExplicitGridRowEnd;
 }
 
 void
-nsGridContainerFrame::PlaceGridItems(GridItemCSSOrderIterator& aIter,
-                                     const nsStylePosition*    aStyle)
+nsGridContainerFrame::PlaceGridItems(GridReflowState& aState)
 {
+  const nsStylePosition* const gridStyle = aState.mGridStyle;
+
   mCellMap.ClearOccupied();
-  InitializeGridBounds(aStyle);
+  InitializeGridBounds(gridStyle);
 
   // http://dev.w3.org/csswg/css-grid/#line-placement
   // Resolve definite positions per spec chap 9.2.
   int32_t minCol = 1;
   int32_t minRow = 1;
-  for (; !aIter.AtEnd(); aIter.Next()) {
-    nsIFrame* child = *aIter;
-    const GridArea& area = PlaceDefinite(child, aStyle);
+  for (; !aState.mIter.AtEnd(); aState.mIter.Next()) {
+    nsIFrame* child = *aState.mIter;
+    const GridArea& area = PlaceDefinite(child, gridStyle);
     if (area.mCols.IsDefinite()) {
       minCol = std::min(minCol, area.mCols.mUntranslatedStart);
     }
     if (area.mRows.IsDefinite()) {
       minRow = std::min(minRow, area.mRows.mUntranslatedStart);
     }
     GridArea* prop = GetGridAreaForChild(child);
     if (prop) {
@@ -906,23 +1004,25 @@ nsGridContainerFrame::PlaceGridItems(Gri
       prop = new GridArea(area);
       child->Properties().Set(GridAreaProperty(), prop);
     }
   }
 
   // Translate the whole grid so that the top-/left-most area is at 0,0.
   mExplicitGridOffsetCol = 1 - minCol; // minCol/Row is always <= 1, see above
   mExplicitGridOffsetRow = 1 - minRow;
+  aState.mColFunctions.mExplicitGridOffset = mExplicitGridOffsetCol;
+  aState.mRowFunctions.mExplicitGridOffset = mExplicitGridOffsetRow;
   const int32_t offsetToColZero = int32_t(mExplicitGridOffsetCol) - 1;
   const int32_t offsetToRowZero = int32_t(mExplicitGridOffsetRow) - 1;
   mGridColEnd += offsetToColZero;
   mGridRowEnd += offsetToRowZero;
-  aIter.Reset();
-  for (; !aIter.AtEnd(); aIter.Next()) {
-    nsIFrame* child = *aIter;
+  aState.mIter.Reset();
+  for (; !aState.mIter.AtEnd(); aState.mIter.Next()) {
+    nsIFrame* child = *aState.mIter;
     GridArea* area = GetGridAreaForChild(child);
     if (area->mCols.IsDefinite()) {
       area->mCols.mStart = area->mCols.mUntranslatedStart + offsetToColZero;
       area->mCols.mEnd = area->mCols.mUntranslatedEnd + offsetToColZero;
     }
     if (area->mRows.IsDefinite()) {
       area->mRows.mStart = area->mRows.mUntranslatedStart + offsetToRowZero;
       area->mRows.mEnd = area->mRows.mUntranslatedEnd + offsetToRowZero;
@@ -931,30 +1031,30 @@ nsGridContainerFrame::PlaceGridItems(Gri
       mCellMap.Fill(*area);
       InflateGridFor(*area);
     }
   }
 
   // http://dev.w3.org/csswg/css-grid/#auto-placement-algo
   // Step 1, place 'auto' items that have one definite position -
   // definite row (column) for grid-auto-flow:row (column).
-  auto flowStyle = aStyle->mGridAutoFlow;
+  auto flowStyle = gridStyle->mGridAutoFlow;
   const bool isRowOrder = (flowStyle & NS_STYLE_GRID_AUTO_FLOW_ROW);
   const bool isSparse = !(flowStyle & NS_STYLE_GRID_AUTO_FLOW_DENSE);
   // We need 1 cursor per row (or column) if placement is sparse.
   {
     Maybe<nsDataHashtable<nsUint32HashKey, uint32_t>> cursors;
     if (isSparse) {
       cursors.emplace();
     }
     auto placeAutoMinorFunc = isRowOrder ? &nsGridContainerFrame::PlaceAutoCol
                                          : &nsGridContainerFrame::PlaceAutoRow;
-    aIter.Reset();
-    for (; !aIter.AtEnd(); aIter.Next()) {
-      nsIFrame* child = *aIter;
+    aState.mIter.Reset();
+    for (; !aState.mIter.AtEnd(); aState.mIter.Next()) {
+      nsIFrame* child = *aState.mIter;
       GridArea* area = GetGridAreaForChild(child);
       LineRange& major = isRowOrder ? area->mRows : area->mCols;
       LineRange& minor = isRowOrder ? area->mCols : area->mRows;
       if (major.IsDefinite() && minor.IsAuto()) {
         // Items with 'auto' in the minor dimension only.
         uint32_t cursor = 0;
         if (isSparse) {
           cursors->Get(major.mStart, &cursor);
@@ -977,19 +1077,19 @@ nsGridContainerFrame::PlaceGridItems(Gri
   // XXX http://dev.w3.org/csswg/css-grid/#auto-placement-cursor
   // XXX now says it should (but didn't in earlier versions)
 
   // Step 3, place the remaining grid items
   uint32_t cursorMajor = 0; // for 'dense' these two cursors will stay at 0,0
   uint32_t cursorMinor = 0;
   auto placeAutoMajorFunc = isRowOrder ? &nsGridContainerFrame::PlaceAutoRow
                                        : &nsGridContainerFrame::PlaceAutoCol;
-  aIter.Reset();
-  for (; !aIter.AtEnd(); aIter.Next()) {
-    nsIFrame* child = *aIter;
+  aState.mIter.Reset();
+  for (; !aState.mIter.AtEnd(); aState.mIter.Next()) {
+    nsIFrame* child = *aState.mIter;
     GridArea* area = GetGridAreaForChild(child);
     LineRange& major = isRowOrder ? area->mRows : area->mCols;
     LineRange& minor = isRowOrder ? area->mCols : area->mRows;
     if (major.IsAuto()) {
       if (minor.IsDefinite()) {
         // Items with 'auto' in the major dimension only.
         if (isSparse) {
           if (minor.mStart < cursorMinor) {
@@ -1037,17 +1137,17 @@ nsGridContainerFrame::PlaceGridItems(Gri
     const int32_t offsetToRowZero = int32_t(mExplicitGridOffsetRow) - 1;
     // Untranslate the grid again temporarily while resolving abs.pos. lines.
     AutoRestore<uint32_t> save1(mGridColEnd);
     AutoRestore<uint32_t> save2(mGridRowEnd);
     mGridColEnd -= offsetToColZero;
     mGridRowEnd -= offsetToRowZero;
     for (nsFrameList::Enumerator e(children); !e.AtEnd(); e.Next()) {
       nsIFrame* child = e.get();
-      GridArea area(PlaceAbsPos(child, aStyle));
+      GridArea area(PlaceAbsPos(child, gridStyle));
       if (area.mCols.mUntranslatedStart != int32_t(kAutoLine)) {
         area.mCols.mStart = area.mCols.mUntranslatedStart + offsetToColZero;
       }
       if (area.mCols.mUntranslatedEnd != int32_t(kAutoLine)) {
         area.mCols.mEnd = area.mCols.mUntranslatedEnd + offsetToColZero;
       }
       if (area.mRows.mUntranslatedStart != int32_t(kAutoLine)) {
         area.mRows.mStart = area.mRows.mUntranslatedStart + offsetToRowZero;
@@ -1094,70 +1194,61 @@ InitializeTrackSize(nscoord aPercentageB
     default:
       limit = nsRuleNode::ComputeCoordPercentCalc(aMaxCoord, aPercentageBasis);
       if (limit < base) {
         limit = base;
       }
   }
 }
 
-static void
-InitializeTrackSizes(nscoord aPercentageBasis,
-                     const nsTArray<nsStyleCoord>& aMinSizingFunctions,
-                     const nsTArray<nsStyleCoord>& aMaxSizingFunctions,
-                     const nsStyleCoord& aAutoMinFunction,
-                     const nsStyleCoord& aAutoMaxFunction,
-                     uint32_t aExplicitGridOffset,
-                     nsTArray<TrackSize>& aResults)
+void
+nsGridContainerFrame::Tracks::Initialize(const TrackSizingFunctions& aFunctions,
+                                         nscoord            aPercentageBasis)
 {
-  MOZ_ASSERT(aResults.Length() >= aExplicitGridOffset + aMinSizingFunctions.Length());
-  MOZ_ASSERT(aMinSizingFunctions.Length() == aMaxSizingFunctions.Length());
-  size_t i = 0;
-  for (; i < aExplicitGridOffset; ++i) {
+  const uint32_t explicitGridOffset = aFunctions.mExplicitGridOffset;
+  MOZ_ASSERT(mSizes.Length() >=
+               explicitGridOffset + aFunctions.mMinSizingFunctions.Length());
+  MOZ_ASSERT(aFunctions.mMinSizingFunctions.Length() ==
+               aFunctions.mMaxSizingFunctions.Length());
+  uint32_t i = 0;
+  for (; i < explicitGridOffset; ++i) {
     InitializeTrackSize(aPercentageBasis,
-                        aAutoMinFunction, aAutoMaxFunction,
-                        &aResults[i]);
+                        aFunctions.mAutoMinSizing,
+                        aFunctions.mAutoMaxSizing,
+                        &mSizes[i]);
   }
-  size_t j = 0;
-  for (const size_t len = aMinSizingFunctions.Length(); j < len; ++j) {
+  uint32_t j = 0;
+  for (uint32_t len = aFunctions.mMinSizingFunctions.Length(); j < len; ++j) {
     InitializeTrackSize(aPercentageBasis,
-                        aMinSizingFunctions[j], aMaxSizingFunctions[j],
-                        &aResults[i + j]);
+                        aFunctions.mMinSizingFunctions[j],
+                        aFunctions.mMaxSizingFunctions[j],
+                        &mSizes[i + j]);
   }
   i += j;
-  for (; i < aResults.Length(); ++i) {
+  for (; i < mSizes.Length(); ++i) {
     InitializeTrackSize(aPercentageBasis,
-                        aAutoMinFunction, aAutoMaxFunction,
-                        &aResults[i]);
+                        aFunctions.mAutoMinSizing,
+                        aFunctions.mAutoMaxSizing,
+                        &mSizes[i]);
   }
 }
 
 void
-nsGridContainerFrame::CalculateTrackSizes(const LogicalSize& aPercentageBasis,
-                                          const nsStylePosition* aStyle,
-                                          nsTArray<TrackSize>& aColSizes,
-                                          nsTArray<TrackSize>& aRowSizes)
+nsGridContainerFrame::CalculateTrackSizes(GridReflowState&   aState,
+                                          const LogicalSize& aContentBox)
 {
-  aColSizes.SetLength(mGridColEnd);
-  aRowSizes.SetLength(mGridRowEnd);
-  WritingMode wm = GetWritingMode();
-  InitializeTrackSizes(aPercentageBasis.ISize(wm),
-                       aStyle->mGridTemplateColumns.mMinTrackSizingFunctions,
-                       aStyle->mGridTemplateColumns.mMaxTrackSizingFunctions,
-                       aStyle->mGridAutoColumnsMin,
-                       aStyle->mGridAutoColumnsMax,
-                       mExplicitGridOffsetCol,
-                       aColSizes);
-  InitializeTrackSizes(aPercentageBasis.BSize(wm),
-                       aStyle->mGridTemplateRows.mMinTrackSizingFunctions,
-                       aStyle->mGridTemplateRows.mMaxTrackSizingFunctions,
-                       aStyle->mGridAutoRowsMin,
-                       aStyle->mGridAutoRowsMax,
-                       mExplicitGridOffsetRow,
-                       aRowSizes);
+  aState.mCols.mSizes.SetLength(mGridColEnd);
+  aState.mRows.mSizes.SetLength(mGridRowEnd);
+  const WritingMode& wm = aState.mWM;
+  aState.mCols.Initialize(aState.mColFunctions, aContentBox.ISize(wm));
+  nscoord rowPercentageBasis = aContentBox.BSize(wm);
+  if (rowPercentageBasis == NS_AUTOHEIGHT) {
+    rowPercentageBasis = 0;
+  }
+  aState.mRows.Initialize(aState.mRowFunctions, rowPercentageBasis);
 }
 
 void
 nsGridContainerFrame::LineRange::ToPositionAndLength(
   const nsTArray<TrackSize>& aTrackSizes, nscoord* aPos, nscoord* aLength) const
 {
   MOZ_ASSERT(mStart != kAutoLine && mEnd != kAutoLine,
              "expected a definite LineRange");
@@ -1202,80 +1293,76 @@ nsGridContainerFrame::LineRange::ToPosit
       nscoord pos;
       ToPositionAndLength(aTrackSizes, &pos, aLength);
       *aPos = aGridOrigin + pos;
     }
   }
 }
 
 LogicalRect
-nsGridContainerFrame::ContainingBlockFor(
-  const WritingMode& aWM,
-  const GridArea& aArea,
-  const nsTArray<TrackSize>& aColSizes,
-  const nsTArray<TrackSize>& aRowSizes) const
+nsGridContainerFrame::ContainingBlockFor(const GridReflowState& aState,
+                                         const GridArea&        aArea) const
 {
   nscoord i, b, iSize, bSize;
   MOZ_ASSERT(aArea.mCols.Extent() > 0, "grid items cover at least one track");
   MOZ_ASSERT(aArea.mRows.Extent() > 0, "grid items cover at least one track");
-  aArea.mCols.ToPositionAndLength(aColSizes, &i, &iSize);
-  aArea.mRows.ToPositionAndLength(aRowSizes, &b, &bSize);
-  return LogicalRect(aWM, i, b, iSize, bSize);
+  aArea.mCols.ToPositionAndLength(aState.mCols.mSizes, &i, &iSize);
+  aArea.mRows.ToPositionAndLength(aState.mRows.mSizes, &b, &bSize);
+  return LogicalRect(aState.mWM, i, b, iSize, bSize);
 }
 
 LogicalRect
-nsGridContainerFrame::ContainingBlockForAbsPos(
-  const WritingMode& aWM,
-  const GridArea& aArea,
-  const nsTArray<TrackSize>& aColSizes,
-  const nsTArray<TrackSize>& aRowSizes,
-  const LogicalPoint& aGridOrigin,
-  const LogicalRect& aGridCB) const
+nsGridContainerFrame::ContainingBlockForAbsPos(const GridReflowState& aState,
+                                               const GridArea&        aArea,
+                                               const LogicalPoint& aGridOrigin,
+                                               const LogicalRect& aGridCB) const
 {
-  nscoord i = aGridCB.IStart(aWM);
-  nscoord b = aGridCB.BStart(aWM);
-  nscoord iSize = aGridCB.ISize(aWM);
-  nscoord bSize = aGridCB.BSize(aWM);
-  aArea.mCols.ToPositionAndLengthForAbsPos(aColSizes, aGridOrigin.I(aWM),
+  const WritingMode& wm = aState.mWM;
+  nscoord i = aGridCB.IStart(wm);
+  nscoord b = aGridCB.BStart(wm);
+  nscoord iSize = aGridCB.ISize(wm);
+  nscoord bSize = aGridCB.BSize(wm);
+  aArea.mCols.ToPositionAndLengthForAbsPos(aState.mCols.mSizes,
+                                           aGridOrigin.I(wm),
                                            &i, &iSize);
-  aArea.mRows.ToPositionAndLengthForAbsPos(aRowSizes, aGridOrigin.B(aWM),
+  aArea.mRows.ToPositionAndLengthForAbsPos(aState.mRows.mSizes,
+                                           aGridOrigin.B(wm),
                                            &b, &bSize);
   return LogicalRect(aWM, i, b, iSize, bSize);
 }
 
 void
-nsGridContainerFrame::ReflowChildren(GridItemCSSOrderIterator&  aIter,
-                                     const LogicalRect&         aContentArea,
-                                     const nsTArray<TrackSize>& aColSizes,
-                                     const nsTArray<TrackSize>& aRowSizes,
-                                     nsHTMLReflowMetrics&       aDesiredSize,
-                                     const nsHTMLReflowState&   aReflowState,
-                                     nsReflowStatus&            aStatus)
+nsGridContainerFrame::ReflowChildren(GridReflowState&     aState,
+                                     const LogicalRect&   aContentArea,
+                                     nsHTMLReflowMetrics& aDesiredSize,
+                                     nsReflowStatus&      aStatus)
 {
-  WritingMode wm = aReflowState.GetWritingMode();
+  MOZ_ASSERT(aState.mReflowState);
+
+  WritingMode wm = aState.mReflowState->GetWritingMode();
   const LogicalPoint gridOrigin(aContentArea.Origin(wm));
   const nsSize containerSize =
     (aContentArea.Size(wm) +
-     aReflowState.ComputedLogicalBorderPadding().Size(wm)).GetPhysicalSize(wm);
+     aState.mReflowState->ComputedLogicalBorderPadding().Size(wm)).GetPhysicalSize(wm);
   nsPresContext* pc = PresContext();
-  for (; !aIter.AtEnd(); aIter.Next()) {
-    nsIFrame* child = *aIter;
+  for (; !aState.mIter.AtEnd(); aState.mIter.Next()) {
+    nsIFrame* child = *aState.mIter;
     const bool isGridItem = child->GetType() != nsGkAtoms::placeholderFrame;
     LogicalRect cb(wm);
     if (MOZ_LIKELY(isGridItem)) {
       GridArea* area = GetGridAreaForChild(child);
       MOZ_ASSERT(area && area->IsDefinite());
-      cb = ContainingBlockFor(wm, *area, aColSizes, aRowSizes);
+      cb = ContainingBlockFor(aState, *area);
       cb += gridOrigin;
     } else {
       cb = aContentArea;
     }
     WritingMode childWM = child->GetWritingMode();
     LogicalSize childCBSize = cb.Size(wm).ConvertTo(childWM, wm);
-    nsHTMLReflowState childRS(pc, aReflowState, child, childCBSize);
+    nsHTMLReflowState childRS(pc, *aState.mReflowState, child, childCBSize);
     const LogicalMargin margin = childRS.ComputedLogicalMargin();
     if (childRS.ComputedBSize() == NS_AUTOHEIGHT && MOZ_LIKELY(isGridItem)) {
       // XXX the start of an align-self:stretch impl.  Needs min-/max-bsize
       // clamping though, and check the prop value is actually 'stretch'!
       LogicalMargin bp = childRS.ComputedLogicalBorderPadding();
       bp.ApplySkipSides(child->GetLogicalSkipSides());
       nscoord bSize = childCBSize.BSize(childWM) - bp.BStartEnd(childWM) -
                         margin.BStartEnd(childWM);
@@ -1300,46 +1387,45 @@ nsGridContainerFrame::ReflowChildren(Gri
                       containerSize, 0);
     ConsiderChildOverflow(aDesiredSize.mOverflowAreas, child);
     // XXX deal with 'childStatus' not being COMPLETE
   }
 
   if (IsAbsoluteContainer()) {
     nsFrameList children(GetChildList(GetAbsoluteListID()));
     if (!children.IsEmpty()) {
-      LogicalMargin pad(aReflowState.ComputedLogicalPadding());
-      pad.ApplySkipSides(GetLogicalSkipSides(&aReflowState));
+      LogicalMargin pad(aState.mReflowState->ComputedLogicalPadding());
+      pad.ApplySkipSides(GetLogicalSkipSides(aState.mReflowState));
       // 'gridOrigin' is the origin of the grid (the start of the first track),
       // with respect to the grid container's padding-box (CB).
       const LogicalPoint gridOrigin(wm, pad.IStart(wm), pad.BStart(wm));
       const LogicalRect gridCB(wm, 0, 0,
                                aContentArea.ISize(wm) + pad.IStartEnd(wm),
                                aContentArea.BSize(wm) + pad.BStartEnd(wm));
       for (nsFrameList::Enumerator e(children); !e.AtEnd(); e.Next()) {
         nsIFrame* child = e.get();
         GridArea* area = GetGridAreaForChild(child);
         MOZ_ASSERT(area);
-        LogicalRect itemCB(ContainingBlockForAbsPos(wm, *area,
-                                                    aColSizes, aRowSizes,
+        LogicalRect itemCB(ContainingBlockForAbsPos(aState, *area,
                                                     gridOrigin, gridCB));
         // nsAbsoluteContainingBlock::Reflow uses physical coordinates.
         nsRect* cb = static_cast<nsRect*>(child->Properties().Get(
                        GridItemContainingBlockRect()));
         if (!cb) {
           cb = new nsRect;
           child->Properties().Set(GridItemContainingBlockRect(), cb);
         }
         *cb = itemCB.GetPhysicalRect(wm, containerSize);
       }
       // This rect isn't used at all for layout so we use it to optimize
       // away the virtual GetType() call in the callee in most cases.
       // @see nsAbsoluteContainingBlock::Reflow
       nsRect dummyRect(0, 0, VERY_LIKELY_A_GRID_CONTAINER, 0);
-      GetAbsoluteContainingBlock()->Reflow(this, pc, aReflowState, aStatus,
-                                           dummyRect, true,
+      GetAbsoluteContainingBlock()->Reflow(this, pc, *aState.mReflowState,
+                                           aStatus, dummyRect, true,
                                            true, true, // XXX could be optimized
                                            &aDesiredSize.mOverflowAreas);
     }
   }
 }
 
 void
 nsGridContainerFrame::Reflow(nsPresContext*           aPresContext,
@@ -1358,48 +1444,44 @@ nsGridContainerFrame::Reflow(nsPresConte
 #ifdef DEBUG
   SanityCheckAnonymousGridItems();
 #endif // DEBUG
 
   LogicalMargin bp = aReflowState.ComputedLogicalBorderPadding();
   bp.ApplySkipSides(GetLogicalSkipSides());
   const nsStylePosition* stylePos = aReflowState.mStylePosition;
   InitImplicitNamedAreas(stylePos);
-  GridItemCSSOrderIterator normalFlowIter(this, kPrincipalList);
-  mIsNormalFlowInCSSOrder = normalFlowIter.ItemsAreAlreadyInOrder();
-  PlaceGridItems(normalFlowIter, stylePos);
+  GridReflowState gridReflowState(this, aReflowState);
+  mIsNormalFlowInCSSOrder = gridReflowState.mIter.ItemsAreAlreadyInOrder();
+  PlaceGridItems(gridReflowState);
 
-  nsAutoTArray<TrackSize, 32> colSizes;
-  nsAutoTArray<TrackSize, 32> rowSizes;
-  WritingMode wm = aReflowState.GetWritingMode();
   const nscoord computedBSize = aReflowState.ComputedBSize();
   const nscoord computedISize = aReflowState.ComputedISize();
-  LogicalSize percentageBasis(wm, computedISize,
-      computedBSize == NS_AUTOHEIGHT ? 0 : computedBSize);
-  CalculateTrackSizes(percentageBasis, stylePos, colSizes, rowSizes);
+  const WritingMode& wm = gridReflowState.mWM;
+  CalculateTrackSizes(gridReflowState,
+                      LogicalSize(wm, computedISize, computedBSize));
 
   nscoord bSize = 0;
   if (computedBSize == NS_AUTOHEIGHT) {
     for (uint32_t i = 0; i < mGridRowEnd; ++i) {
-      bSize += rowSizes[i].mBase;
+      bSize += gridReflowState.mRows.mSizes[i].mBase;
     }
   } else {
     bSize = computedBSize;
   }
   bSize = std::max(bSize - GetConsumedBSize(), 0);
   LogicalSize desiredSize(wm, computedISize + bp.IStartEnd(wm),
                           bSize + bp.BStartEnd(wm));
   aDesiredSize.SetSize(wm, desiredSize);
   aDesiredSize.SetOverflowAreasToDesiredBounds();
 
   LogicalRect contentArea(wm, bp.IStart(wm), bp.BStart(wm),
                           computedISize, bSize);
-  normalFlowIter.Reset(GridItemCSSOrderIterator::eIncludeAll);
-  ReflowChildren(normalFlowIter, contentArea, colSizes, rowSizes, aDesiredSize,
-                 aReflowState, aStatus);
+  gridReflowState.mIter.Reset(GridItemCSSOrderIterator::eIncludeAll);
+  ReflowChildren(gridReflowState, contentArea, aDesiredSize, aStatus);
 
   FinishAndStoreOverflow(&aDesiredSize);
   aStatus = NS_FRAME_COMPLETE;
   NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
 }
 
 nsIAtom*
 nsGridContainerFrame::GetType() const
--- a/layout/generic/nsGridContainerFrame.h
+++ b/layout/generic/nsGridContainerFrame.h
@@ -63,16 +63,19 @@ protected:
   static const uint32_t kAutoLine;
   // The maximum line number, in the zero-based translated grid.
   static const uint32_t kTranslatedMaxLine;
   typedef mozilla::LogicalPoint LogicalPoint;
   typedef mozilla::LogicalRect LogicalRect;
   typedef mozilla::WritingMode WritingMode;
   typedef mozilla::css::GridNamedArea GridNamedArea;
   class GridItemCSSOrderIterator;
+  struct TrackSizingFunctions;
+  struct Tracks;
+  struct GridReflowState;
   friend nsContainerFrame* NS_NewGridContainerFrame(nsIPresShell* aPresShell,
                                                     nsStyleContext* aContext);
   explicit nsGridContainerFrame(nsStyleContext* aContext) : nsContainerFrame(aContext) {}
 
   /**
    * A LineRange can be definite or auto - when it's definite it represents
    * a consecutive set of tracks between a starting line and an ending line.
    * Before it's definite it can also represent an auto position with a span,
@@ -361,21 +364,18 @@ protected:
    * @param aStyle the StylePosition() for the grid container
    */
   GridArea PlaceAbsPos(nsIFrame* aChild, const nsStylePosition* aStyle);
 
   /**
    * Place all child frames into the grid and expand the (implicit) grid as
    * needed.  The allocated GridAreas are stored in the GridAreaProperty
    * frame property on the child frame.
-   * @param aIter a grid item iterator
-   * @param aStyle the StylePosition() for the grid container
    */
-  void PlaceGridItems(GridItemCSSOrderIterator& aIter,
-                      const nsStylePosition* aStyle);
+  void PlaceGridItems(GridReflowState& aState);
 
   /**
    * Initialize the end lines of the Explicit Grid (mExplicitGridCol[Row]End).
    * This is determined by the larger of the number of rows/columns defined
    * by 'grid-template-areas' and the 'grid-template-rows'/'-columns', plus one.
    * Also initialize the Implicit Grid (mGridCol[Row]End) to the same values.
    * @param aStyle the StylePosition() for the grid container
    */
@@ -391,20 +391,18 @@ protected:
     mGridRowEnd = std::max(mGridRowEnd, aArea.mRows.HypotheticalEnd());
     MOZ_ASSERT(mGridColEnd <= kTranslatedMaxLine &&
                mGridRowEnd <= kTranslatedMaxLine);
   }
 
   /**
    * Calculate track sizes.
    */
-  void CalculateTrackSizes(const mozilla::LogicalSize& aPercentageBasis,
-                           const nsStylePosition*      aStyle,
-                           nsTArray<TrackSize>&        aColSizes,
-                           nsTArray<TrackSize>&        aRowSizes);
+  void CalculateTrackSizes(GridReflowState&            aState,
+                           const mozilla::LogicalSize& aContentBox);
 
   /**
    * Helper method for ResolveLineRange.
    * @see ResolveLineRange
    * @return a pair (start,end) of lines
    */
   typedef std::pair<int32_t, int32_t> LinePair;
   LinePair ResolveLineRangeHelper(const nsStyleGridLine& aStart,
@@ -440,50 +438,39 @@ protected:
    * A convenience method to get the stored GridArea* for a frame.
    */
   static GridArea* GetGridAreaForChild(nsIFrame* aChild) {
     return static_cast<GridArea*>(aChild->Properties().Get(GridAreaProperty()));
   }
 
   /**
    * Return the containing block for a grid item occupying aArea.
-   * @param aColSizes column track sizes
-   * @param aRowSizes row track sizes
    */
-  LogicalRect ContainingBlockFor(const WritingMode& aWM,
-                                 const GridArea& aArea,
-                                 const nsTArray<TrackSize>& aColSizes,
-                                 const nsTArray<TrackSize>& aRowSizes) const;
+  LogicalRect ContainingBlockFor(const GridReflowState& aState,
+                                 const GridArea&        aArea) const;
 
   /**
    * Return the containing block for an abs.pos. grid item occupying aArea.
    * Any 'auto' lines in the grid area will be aligned with grid container
    * containing block on that side.
-   * @param aColSizes column track sizes
-   * @param aRowSizes row track sizes
    * @param aGridOrigin the origin of the grid
    * @param aGridCB the grid container containing block (its padding area)
    */
-  LogicalRect ContainingBlockForAbsPos(const WritingMode& aWM,
-                                       const GridArea& aArea,
-                                       const nsTArray<TrackSize>& aColSizes,
-                                       const nsTArray<TrackSize>& aRowSizes,
-                                       const LogicalPoint& aGridOrigin,
-                                       const LogicalRect& aGridCB) const;
+  LogicalRect ContainingBlockForAbsPos(const GridReflowState& aState,
+                                       const GridArea&        aArea,
+                                       const LogicalPoint&    aGridOrigin,
+                                       const LogicalRect&     aGridCB) const;
 
   /**
    * Reflow and place our children.
    */
-  void ReflowChildren(GridItemCSSOrderIterator&   aIter,
-                      const LogicalRect&          aContentArea,
-                      const nsTArray<TrackSize>&  aColSizes,
-                      const nsTArray<TrackSize>&  aRowSizes,
-                      nsHTMLReflowMetrics&        aDesiredSize,
-                      const nsHTMLReflowState&    aReflowState,
-                      nsReflowStatus&             aStatus);
+  void ReflowChildren(GridReflowState&     aState,
+                      const LogicalRect&   aContentArea,
+                      nsHTMLReflowMetrics& aDesiredSize,
+                      nsReflowStatus&      aStatus);
 
 #ifdef DEBUG
   void SanityCheckAnonymousGridItems() const;
 #endif // DEBUG
 
 private:
   /**
    * State for each cell in the grid.