Bug 1144096 part 1 - [css-grid] Refactor nsGridContainerFrame state and methods. r=dholbert
authorMats Palmgren <mats@mozilla.com>
Fri, 11 Mar 2016 17:39:25 +0100
changeset 288293 a8b7c33f5687a244a3abffb7b02b7c2ca231b7f8
parent 288292 4916251eb38968263c69c633fee264d129570768
child 288294 3737062990186ca27ee7fd31c2afd2fabfedab5c
push id30079
push userryanvm@gmail.com
push dateSat, 12 Mar 2016 20:24:19 +0000
treeherdermozilla-central@d1d47ba19ce9 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdholbert
bugs1144096
milestone48.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 1144096 part 1 - [css-grid] Refactor nsGridContainerFrame state and methods. r=dholbert
layout/generic/nsGridContainerFrame.cpp
layout/generic/nsGridContainerFrame.h
--- a/layout/generic/nsGridContainerFrame.cpp
+++ b/layout/generic/nsGridContainerFrame.cpp
@@ -971,29 +971,62 @@ struct MOZ_STACK_CLASS nsGridContainerFr
                       aRS.GetWritingMode())
   {}
   GridReflowState(nsGridContainerFrame* aFrame,
                   nsRenderingContext&   aRC)
     : GridReflowState(aFrame, aRC, nullptr, aFrame->StylePosition(),
                       aFrame->GetWritingMode())
   {}
 
+  /**
+   * Calculate our track sizes.
+   */
+  void CalculateTrackSizes(const Grid&        aGrid,
+                           const LogicalSize& aContentBox,
+                           IntrinsicISizeType aConstraint);
+
+  /**
+   * Return the containing block for a grid item occupying aArea.
+   */
+  LogicalRect ContainingBlockFor(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 aGridOrigin the origin of the grid
+   * @param aGridCB the grid container containing block (its padding area)
+   */
+  LogicalRect ContainingBlockForAbsPos(const GridArea&     aArea,
+                                       const LogicalPoint& aGridOrigin,
+                                       const LogicalRect&  aGridCB) const;
+
   GridItemCSSOrderIterator mIter;
   const nsStylePosition* const mGridStyle;
   Tracks mCols;
   Tracks mRows;
   TrackSizingFunctions mColFunctions;
   TrackSizingFunctions mRowFunctions;
   /**
+   * Info about each (normal flow) grid item.
+   */
+  nsTArray<GridItemInfo> mGridItems;
+  /**
+   * Info about each grid-aligned abs.pos. child.
+   */
+  nsTArray<GridItemInfo> mAbsPosItems;
+
+  /**
    * @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;
+  const nsHTMLReflowState* const mReflowState;
   nsRenderingContext& mRenderingContext;
+  nsGridContainerFrame* const mFrame;
   const WritingMode mWM;
 
 private:
   GridReflowState(nsGridContainerFrame*    aFrame,
                   nsRenderingContext&      aRenderingContext,
                   const nsHTMLReflowState* aReflowState,
                   const nsStylePosition*   aGridStyle,
                   const WritingMode&       aWM)
@@ -1004,73 +1037,425 @@ private:
     , mColFunctions(mGridStyle->mGridTemplateColumns,
                     mGridStyle->mGridAutoColumnsMin,
                     mGridStyle->mGridAutoColumnsMax)
     , mRowFunctions(mGridStyle->mGridTemplateRows,
                     mGridStyle->mGridAutoRowsMin,
                     mGridStyle->mGridAutoRowsMax)
     , mReflowState(aReflowState)
     , mRenderingContext(aRenderingContext)
+    , mFrame(aFrame)
     , mWM(aWM)
-  {}
+  {
+    MOZ_ASSERT(!aReflowState || aReflowState->frame == mFrame);
+  }
 };
 
-static
-bool IsMinContent(const nsStyleCoord& aCoord)
+/**
+ * The Grid implements grid item placement and the state of the grid -
+ * the size of the explicit/implicit grid, which cells are occupied etc.
+ */
+struct MOZ_STACK_CLASS nsGridContainerFrame::Grid
 {
-  return aCoord.GetUnit() == eStyleUnit_Enumerated &&
-         aCoord.GetIntValue() == NS_STYLE_GRID_TRACK_BREADTH_MIN_CONTENT;
-}
+  /**
+   * 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 aComputedMinSize the container's min-size - used to determine
+   *   the number of repeat(auto-fill/fit) tracks.
+   * @param aComputedSize the container's size - used to determine
+   *   the number of repeat(auto-fill/fit) tracks.
+   * @param aComputedMaxSize the container's max-size - used to determine
+   *   the number of repeat(auto-fill/fit) tracks.
+   */
+  void PlaceGridItems(GridReflowState& aState,
+                      const LogicalSize& aComputedMinSize,
+                      const LogicalSize& aComputedSize,
+                      const LogicalSize& aComputedMaxSize);
+
+  /**
+   * As above but for an abs.pos. child.  Any 'auto' lines will be represented
+   * by kAutoLine in the LineRange result.
+   * @param aGridStart the first line in the final, but untranslated grid
+   * @param aGridEnd the last line in the final, but untranslated grid
+   */
+  LineRange ResolveAbsPosLineRange(const nsStyleGridLine& aStart,
+                                   const nsStyleGridLine& aEnd,
+                                   const LineNameMap& aNameMap,
+                                   uint32_t GridNamedArea::* aAreaStart,
+                                   uint32_t GridNamedArea::* aAreaEnd,
+                                   uint32_t aExplicitGridEnd,
+                                   int32_t aGridStart,
+                                   int32_t aGridEnd,
+                                   const nsStylePosition* aStyle);
+
+  /**
+   * Return a GridArea for abs.pos. item with non-auto lines placed at
+   * a definite line (1-based) with placement errors resolved.  One or both
+   * positions may still be 'auto'.
+   * @param aChild the abs.pos. grid item to place
+   * @param aStyle the StylePosition() for the grid container
+   */
+  GridArea PlaceAbsPos(nsIFrame* aChild,
+                       const LineNameMap& aColLineNameMap,
+                       const LineNameMap& aRowLineNameMap,
+                       const nsStylePosition* aStyle);
+
+  /**
+   * Find the first column in row aLockedRow starting at aStartCol where aArea
+   * could be placed without overlapping other items.  The returned column may
+   * cause aArea to overflow the current implicit grid bounds if placed there.
+   */
+  uint32_t FindAutoCol(uint32_t aStartCol, uint32_t aLockedRow,
+                       const GridArea* aArea) const;
+
+  /**
+   * Place aArea in the first column (in row aArea->mRows.mStart) starting at
+   * aStartCol without overlapping other items.  The resulting aArea may
+   * overflow the current implicit grid bounds.
+   * Pre-condition: aArea->mRows.IsDefinite() is true.
+   * Post-condition: aArea->IsDefinite() is true.
+   */
+  void PlaceAutoCol(uint32_t aStartCol, GridArea* aArea) const;
+
+  /**
+   * Find the first row in column aLockedCol starting at aStartRow where aArea
+   * could be placed without overlapping other items.  The returned row may
+   * cause aArea to overflow the current implicit grid bounds if placed there.
+   */
+  uint32_t FindAutoRow(uint32_t aLockedCol, uint32_t aStartRow,
+                       const GridArea* aArea) const;
+
+  /**
+   * Place aArea in the first row (in column aArea->mCols.mStart) starting at
+   * aStartRow without overlapping other items. The resulting aArea may
+   * overflow the current implicit grid bounds.
+   * Pre-condition: aArea->mCols.IsDefinite() is true.
+   * Post-condition: aArea->IsDefinite() is true.
+   */
+  void PlaceAutoRow(uint32_t aStartRow, GridArea* aArea) const;
+
+  /**
+   * Place aArea in the first column starting at aStartCol,aStartRow without
+   * causing it to overlap other items or overflow mGridColEnd.
+   * If there's no such column in aStartRow, continue in position 1,aStartRow+1.
+   * Pre-condition: aArea->mCols.IsAuto() && aArea->mRows.IsAuto() is true.
+   * Post-condition: aArea->IsDefinite() is true.
+   */
+  void PlaceAutoAutoInRowOrder(uint32_t aStartCol,
+                               uint32_t aStartRow,
+                               GridArea* aArea) const;
+
+  /**
+   * Place aArea in the first row starting at aStartCol,aStartRow without
+   * causing it to overlap other items or overflow mGridRowEnd.
+   * If there's no such row in aStartCol, continue in position aStartCol+1,1.
+   * Pre-condition: aArea->mCols.IsAuto() && aArea->mRows.IsAuto() is true.
+   * Post-condition: aArea->IsDefinite() is true.
+   */
+  void PlaceAutoAutoInColOrder(uint32_t aStartCol,
+                               uint32_t aStartRow,
+                               GridArea* aArea) const;
 
-/**
- * A convenience method to lookup a name in 'grid-template-areas'.
- * @param aStyle the StylePosition() for the grid container
- * @return null if not found
- */
-static const css::GridNamedArea*
-FindNamedArea(const nsSubstring& aName, const nsStylePosition* aStyle)
-{
-  if (!aStyle->mGridTemplateAreas) {
+  /**
+   * Return aLine if it's inside the aMin..aMax range (inclusive),
+   * otherwise return kAutoLine.
+   */
+  static int32_t
+  AutoIfOutside(int32_t aLine, int32_t aMin, int32_t aMax)
+  {
+    MOZ_ASSERT(aMin <= aMax);
+    if (aLine < aMin || aLine > aMax) {
+      return kAutoLine;
+    }
+    return aLine;
+  }
+
+  /**
+   * Inflate the implicit grid to include aArea.
+   * @param aArea may be definite or auto
+   */
+  void InflateGridFor(const GridArea& aArea)
+  {
+    mGridColEnd = std::max(mGridColEnd, aArea.mCols.HypotheticalEnd());
+    mGridRowEnd = std::max(mGridRowEnd, aArea.mRows.HypotheticalEnd());
+    MOZ_ASSERT(mGridColEnd <= kTranslatedMaxLine &&
+               mGridRowEnd <= kTranslatedMaxLine);
+  }
+
+  enum LineRangeSide {
+    eLineRangeSideStart, eLineRangeSideEnd
+  };
+  /**
+   * Return a line number for (non-auto) aLine, per:
+   * http://dev.w3.org/csswg/css-grid/#line-placement
+   * @param aLine style data for the line (must be non-auto)
+   * @param aNth a number of lines to find from aFromIndex, negative if the
+   *             search should be in reverse order.  In the case aLine has
+   *             a specified line name, it's permitted to pass in zero which
+   *             will be treated as one.
+   * @param aFromIndex the zero-based index to start counting from
+   * @param aLineNameList the explicit named lines
+   * @param aAreaStart a pointer to GridNamedArea::mColumnStart/mRowStart
+   * @param aAreaEnd a pointer to GridNamedArea::mColumnEnd/mRowEnd
+   * @param aExplicitGridEnd the last line in the explicit grid
+   * @param aEdge indicates whether we are resolving a start or end line
+   * @param aStyle the StylePosition() for the grid container
+   * @return a definite line (1-based), clamped to the kMinLine..kMaxLine range
+   */
+  int32_t ResolveLine(const nsStyleGridLine& aLine,
+                      int32_t aNth,
+                      uint32_t aFromIndex,
+                      const LineNameMap& aNameMap,
+                      uint32_t GridNamedArea::* aAreaStart,
+                      uint32_t GridNamedArea::* aAreaEnd,
+                      uint32_t aExplicitGridEnd,
+                      LineRangeSide aSide,
+                      const nsStylePosition* aStyle);
+
+  /**
+   * 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,
+                                  const nsStyleGridLine& aEnd,
+                                  const LineNameMap& aNameMap,
+                                  uint32_t GridNamedArea::* aAreaStart,
+                                  uint32_t GridNamedArea::* aAreaEnd,
+                                  uint32_t aExplicitGridEnd,
+                                  const nsStylePosition* aStyle);
+
+  /**
+   * Return a LineRange based on the given style data. Non-auto lines
+   * are resolved to a definite line number (1-based) per:
+   * http://dev.w3.org/csswg/css-grid/#line-placement
+   * with placement errors corrected per:
+   * http://dev.w3.org/csswg/css-grid/#grid-placement-errors
+   * @param aStyle the StylePosition() for the grid container
+   * @param aStart style data for the start line
+   * @param aEnd style data for the end line
+   * @param aLineNameList the explicit named lines
+   * @param aAreaStart a pointer to GridNamedArea::mColumnStart/mRowStart
+   * @param aAreaEnd a pointer to GridNamedArea::mColumnEnd/mRowEnd
+   * @param aExplicitGridEnd the last line in the explicit grid
+   * @param aStyle the StylePosition() for the grid container
+   */
+  LineRange ResolveLineRange(const nsStyleGridLine& aStart,
+                             const nsStyleGridLine& aEnd,
+                             const LineNameMap& aNameMap,
+                             uint32_t GridNamedArea::* aAreaStart,
+                             uint32_t GridNamedArea::* aAreaEnd,
+                             uint32_t aExplicitGridEnd,
+                             const nsStylePosition* aStyle);
+
+  /**
+   * Return a GridArea with non-auto lines placed at a definite line (1-based)
+   * with placement errors resolved.  One or both positions may still
+   * be 'auto'.
+   * @param aChild the grid item
+   * @param aStyle the StylePosition() for the grid container
+   */
+  GridArea PlaceDefinite(nsIFrame*              aChild,
+                         const LineNameMap&     aColLineNameMap,
+                         const LineNameMap&     aRowLineNameMap,
+                         const nsStylePosition* aStyle);
+
+  bool HasImplicitNamedArea(const nsString& aName) const
+  {
+    return mAreas && mAreas->Contains(aName);
+  }
+
+  /**
+   * A convenience method to lookup a name in 'grid-template-areas'.
+   * @param aStyle the StylePosition() for the grid container
+   * @return null if not found
+   */
+  static const css::GridNamedArea*
+  FindNamedArea(const nsSubstring& aName, const nsStylePosition* aStyle)
+  {
+    if (!aStyle->mGridTemplateAreas) {
+      return nullptr;
+    }
+    const nsTArray<css::GridNamedArea>& areas =
+      aStyle->mGridTemplateAreas->mNamedAreas;
+    size_t len = areas.Length();
+    for (size_t i = 0; i < len; ++i) {
+      const css::GridNamedArea& area = areas[i];
+      if (area.mName == aName) {
+        return &area;
+      }
+    }
     return nullptr;
   }
-  const nsTArray<css::GridNamedArea>& areas =
-    aStyle->mGridTemplateAreas->mNamedAreas;
-  size_t len = areas.Length();
-  for (size_t i = 0; i < len; ++i) {
-    const css::GridNamedArea& area = areas[i];
-    if (area.mName == aName) {
-      return &area;
+
+  // Return true if aString ends in aSuffix and has at least one character before
+  // the suffix. Assign aIndex to where the suffix starts.
+  static bool
+  IsNameWithSuffix(const nsString& aString, const nsString& aSuffix,
+                   uint32_t* aIndex)
+  {
+    if (StringEndsWith(aString, aSuffix)) {
+      *aIndex = aString.Length() - aSuffix.Length();
+      return *aIndex != 0;
     }
+    return false;
+  }
+
+  static bool
+  IsNameWithEndSuffix(const nsString& aString, uint32_t* aIndex)
+  {
+    return IsNameWithSuffix(aString, NS_LITERAL_STRING("-end"), aIndex);
+  }
+
+  static bool
+  IsNameWithStartSuffix(const nsString& aString, uint32_t* aIndex)
+  {
+    return IsNameWithSuffix(aString, NS_LITERAL_STRING("-start"), aIndex);
   }
-  return nullptr;
-}
+
+  /**
+   * A CellMap holds state for each cell in the grid.
+   * It's row major.  It's sparse in the sense that it only has enough rows to
+   * cover the last row that has a grid item.  Each row only has enough entries
+   * to cover columns that are occupied *on that row*, i.e. it's not a full
+   * matrix covering the entire implicit grid.  An absent Cell means that it's
+   * unoccupied by any grid item.
+   */
+  struct CellMap {
+    struct Cell {
+      Cell() : mIsOccupied(false) {}
+      bool mIsOccupied : 1;
+    };
+
+    void Fill(const GridArea& aGridArea)
+    {
+      MOZ_ASSERT(aGridArea.IsDefinite());
+      MOZ_ASSERT(aGridArea.mRows.mStart < aGridArea.mRows.mEnd);
+      MOZ_ASSERT(aGridArea.mCols.mStart < aGridArea.mCols.mEnd);
+      const auto numRows = aGridArea.mRows.mEnd;
+      const auto numCols = aGridArea.mCols.mEnd;
+      mCells.EnsureLengthAtLeast(numRows);
+      for (auto i = aGridArea.mRows.mStart; i < numRows; ++i) {
+        nsTArray<Cell>& cellsInRow = mCells[i];
+        cellsInRow.EnsureLengthAtLeast(numCols);
+        for (auto j = aGridArea.mCols.mStart; j < numCols; ++j) {
+          cellsInRow[j].mIsOccupied = true;
+        }
+      }
+    }
+
+    void ClearOccupied()
+    {
+      const size_t numRows = mCells.Length();
+      for (size_t i = 0; i < numRows; ++i) {
+        nsTArray<Cell>& cellsInRow = mCells[i];
+        const size_t numCols = cellsInRow.Length();
+        for (size_t j = 0; j < numCols; ++j) {
+          cellsInRow[j].mIsOccupied = false;
+        }
+      }
+    }
 
-// Return true if aString ends in aSuffix and has at least one character before
-// the suffix. Assign aIndex to where the suffix starts.
-static bool
-IsNameWithSuffix(const nsString& aString, const nsString& aSuffix,
-                 uint32_t* aIndex)
+    uint32_t IsEmptyCol(uint32_t aCol) const
+    {
+      for (auto& row : mCells) {
+        if (aCol < row.Length() && row[aCol].mIsOccupied) {
+          return false;
+        }
+      }
+      return true;
+    }
+    uint32_t IsEmptyRow(uint32_t aRow) const
+    {
+      if (aRow >= mCells.Length()) {
+        return true;
+      }
+      for (const Cell& cell : mCells[aRow]) {
+        if (cell.mIsOccupied) {
+          return false;
+        }
+      }
+      return true;
+    }
+#ifdef DEBUG
+    void Dump() const
+    {
+      const size_t numRows = mCells.Length();
+      for (size_t i = 0; i < numRows; ++i) {
+        const nsTArray<Cell>& cellsInRow = mCells[i];
+        const size_t numCols = cellsInRow.Length();
+        printf("%lu:\t", (unsigned long)i + 1);
+        for (size_t j = 0; j < numCols; ++j) {
+          printf(cellsInRow[j].mIsOccupied ? "X " : ". ");
+        }
+        printf("\n");
+      }
+    }
+#endif
+
+    nsTArray<nsTArray<Cell>> mCells;
+  };
+
+  /**
+   * State for each cell in the grid.
+   */
+  CellMap mCellMap;
+  /**
+   * @see HasImplicitNamedArea.
+   */
+  ImplicitNamedAreas* mAreas;
+  /**
+   * The last column grid line (1-based) in the explicit grid.
+   * (i.e. the number of explicit columns + 1)
+   */
+  uint32_t mExplicitGridColEnd;
+  /**
+   * The last row grid line (1-based) in the explicit grid.
+   * (i.e. the number of explicit rows + 1)
+   */
+  uint32_t mExplicitGridRowEnd;
+  // Same for the implicit grid, except these become zero-based after
+  // resolving definite lines.
+  uint32_t mGridColEnd;
+  uint32_t mGridRowEnd;
+
+  /**
+   * Offsets from the start of the implicit grid to the start of the translated
+   * explicit grid.  They are zero if there are no implicit lines before 1,1.
+   * e.g. "grid-column: span 3 / 1" makes mExplicitGridOffsetCol = 3 and the
+   * corresponding GridArea::mCols will be 0 / 3 in the zero-based translated
+   * grid.
+   */
+  uint32_t mExplicitGridOffsetCol;
+  uint32_t mExplicitGridOffsetRow;
+
+};
+
+void
+nsGridContainerFrame::GridReflowState::CalculateTrackSizes(
+  const Grid&        aGrid,
+  const LogicalSize& aContentBox,
+  IntrinsicISizeType aConstraint)
 {
-  if (StringEndsWith(aString, aSuffix)) {
-    *aIndex = aString.Length() - aSuffix.Length();
-    return *aIndex != 0;
-  }
-  return false;
-}
+  mCols.Initialize(mColFunctions, mGridStyle->mGridColumnGap,
+                   aGrid.mGridColEnd, aContentBox.ISize(mWM));
+  mRows.Initialize(mRowFunctions, mGridStyle->mGridRowGap,
+                   aGrid.mGridRowEnd, aContentBox.BSize(mWM));
 
-static bool
-IsNameWithEndSuffix(const nsString& aString, uint32_t* aIndex)
-{
-  return IsNameWithSuffix(aString, NS_LITERAL_STRING("-end"), aIndex);
-}
+  mIter.Reset(); // XXX cleanup this Reset mess!
+  mCols.CalculateSizes(*this, mGridItems, mColFunctions,
+                       aContentBox.ISize(mWM), &GridArea::mCols,
+                       aConstraint);
 
-static bool
-IsNameWithStartSuffix(const nsString& aString, uint32_t* aIndex)
-{
-  return IsNameWithSuffix(aString, NS_LITERAL_STRING("-start"), aIndex);
+  mIter.Reset(); // XXX cleanup this Reset mess!
+  mRows.CalculateSizes(*this, mGridItems, mRowFunctions,
+                       aContentBox.BSize(mWM), &GridArea::mRows,
+                       aConstraint);
 }
 
 /**
  * (XXX share this utility function with nsFlexContainerFrame at some point)
  *
  * Helper for BuildDisplayList, to implement this special-case for grid
  * items from the spec:
  *   The painting order of grid items is exactly the same as inline blocks,
@@ -1432,18 +1817,18 @@ nsGridContainerFrame::AddImplicitNamedAr
   // Note: recording these names for fast lookup later is just an optimization.
   const uint32_t len =
     std::min(aLineNameLists.Length(), size_t(nsStyleGridLine::kMaxLine));
   nsTHashtable<nsStringHashKey> currentStarts;
   ImplicitNamedAreas* areas = GetImplicitNamedAreas();
   for (uint32_t i = 0; i < len; ++i) {
     for (const nsString& name : aLineNameLists[i]) {
       uint32_t index;
-      if (::IsNameWithStartSuffix(name, &index) ||
-          ::IsNameWithEndSuffix(name, &index)) {
+      if (Grid::IsNameWithStartSuffix(name, &index) ||
+          Grid::IsNameWithEndSuffix(name, &index)) {
         nsDependentSubstring area(name, 0, index);
         if (!areas) {
           areas = new ImplicitNamedAreas;
           Properties().Set(ImplicitNamedAreasProperty(), areas);
         }
         areas->PutEntry(area);
       }
     }
@@ -1462,40 +1847,39 @@ nsGridContainerFrame::InitImplicitNamedA
   AddImplicitNamedAreas(aStyle->mGridTemplateColumns.mLineNameLists);
   AddImplicitNamedAreas(aStyle->mGridTemplateRows.mLineNameLists);
   if (areas && areas->Count() == 0) {
     Properties().Delete(ImplicitNamedAreasProperty());
   }
 }
 
 int32_t
-nsGridContainerFrame::ResolveLine(
-  const nsStyleGridLine& aLine,
-  int32_t aNth,
-  uint32_t aFromIndex,
-  const LineNameMap& aNameMap,
-  uint32_t GridNamedArea::* aAreaStart,
-  uint32_t GridNamedArea::* aAreaEnd,
-  uint32_t aExplicitGridEnd,
-  LineRangeSide aSide,
-  const nsStylePosition* aStyle)
+nsGridContainerFrame::Grid::ResolveLine(const nsStyleGridLine& aLine,
+                                        int32_t aNth,
+                                        uint32_t aFromIndex,
+                                        const LineNameMap& aNameMap,
+                                        uint32_t GridNamedArea::* aAreaStart,
+                                        uint32_t GridNamedArea::* aAreaEnd,
+                                        uint32_t aExplicitGridEnd,
+                                        LineRangeSide aSide,
+                                        const nsStylePosition* aStyle)
 {
   MOZ_ASSERT(!aLine.IsAuto());
   int32_t line = 0;
   if (aLine.mLineName.IsEmpty()) {
     MOZ_ASSERT(aNth != 0, "css-grid 9.2: <integer> must not be zero.");
     line = int32_t(aFromIndex) + aNth;
   } else {
     if (aNth == 0) {
       // <integer> was omitted; treat it as 1.
       aNth = 1;
     }
     bool isNameOnly = !aLine.mHasSpan && aLine.mInteger == 0;
     if (isNameOnly) {
-      const GridNamedArea* area = ::FindNamedArea(aLine.mLineName, aStyle);
+      const GridNamedArea* area = FindNamedArea(aLine.mLineName, aStyle);
       if (area || HasImplicitNamedArea(aLine.mLineName)) {
         // The given name is a named area - look for explicit lines named
         // <name>-start/-end depending on which side we're resolving.
         // http://dev.w3.org/csswg/css-grid/#grid-placement-slot
         uint32_t implicitLine = 0;
         nsAutoString lineName(aLine.mLineName);
         if (aSide == eLineRangeSideStart) {
           lineName.AppendLiteral("-start");
@@ -1509,25 +1893,25 @@ nsGridContainerFrame::ResolveLine(
       }
     }
 
     if (line == 0) {
       // If mLineName ends in -start/-end, try the prefix as a named area.
       uint32_t implicitLine = 0;
       uint32_t index;
       auto GridNamedArea::* areaEdge = aAreaStart;
-      bool found = ::IsNameWithStartSuffix(aLine.mLineName, &index);
+      bool found = IsNameWithStartSuffix(aLine.mLineName, &index);
       if (!found) {
-        found = ::IsNameWithEndSuffix(aLine.mLineName, &index);
+        found = IsNameWithEndSuffix(aLine.mLineName, &index);
         areaEdge = aAreaEnd;
       }
       if (found) {
         const GridNamedArea* area =
-          ::FindNamedArea(nsDependentSubstring(aLine.mLineName, 0, index),
-                          aStyle);
+          FindNamedArea(nsDependentSubstring(aLine.mLineName, 0, index),
+                        aStyle);
         if (area) {
           implicitLine = area->*areaEdge;
         }
       }
       line = aNameMap.FindNamedLine(aLine.mLineName, &aNth, aFromIndex,
                                     implicitLine);
     }
 
@@ -1546,18 +1930,18 @@ nsGridContainerFrame::ResolveLine(
       // "If not enough lines with that name exist, all lines in the implicit
       // grid are assumed to have that name..."
       line = edgeLine + aNth;
     }
   }
   return clamped(line, nsStyleGridLine::kMinLine, nsStyleGridLine::kMaxLine);
 }
 
-nsGridContainerFrame::LinePair
-nsGridContainerFrame::ResolveLineRangeHelper(
+nsGridContainerFrame::Grid::LinePair
+nsGridContainerFrame::Grid::ResolveLineRangeHelper(
   const nsStyleGridLine& aStart,
   const nsStyleGridLine& aEnd,
   const LineNameMap& aNameMap,
   uint32_t GridNamedArea::* aAreaStart,
   uint32_t GridNamedArea::* aAreaEnd,
   uint32_t aExplicitGridEnd,
   const nsStylePosition* aStyle)
 {
@@ -1646,17 +2030,17 @@ nsGridContainerFrame::ResolveLineRangeHe
   if (start == int32_t(kAutoLine)) {
     // auto / definite line
     start = std::max(nsStyleGridLine::kMinLine, end - 1);
   }
   return LinePair(start, end);
 }
 
 nsGridContainerFrame::LineRange
-nsGridContainerFrame::ResolveLineRange(
+nsGridContainerFrame::Grid::ResolveLineRange(
   const nsStyleGridLine& aStart,
   const nsStyleGridLine& aEnd,
   const LineNameMap& aNameMap,
   uint32_t GridNamedArea::* aAreaStart,
   uint32_t GridNamedArea::* aAreaEnd,
   uint32_t aExplicitGridEnd,
   const nsStylePosition* aStyle)
 {
@@ -1679,35 +2063,35 @@ nsGridContainerFrame::ResolveLineRange(
       }
       r.second = r.first + 1; // XXX subgrid explicit size instead of 1?
     }
   }
   return LineRange(r.first, r.second);
 }
 
 nsGridContainerFrame::GridArea
-nsGridContainerFrame::PlaceDefinite(nsIFrame* aChild,
-                                    const LineNameMap& aColLineNameMap,
-                                    const LineNameMap& aRowLineNameMap,
-                                    const nsStylePosition* aStyle)
+nsGridContainerFrame::Grid::PlaceDefinite(nsIFrame* aChild,
+                                          const LineNameMap& aColLineNameMap,
+                                          const LineNameMap& aRowLineNameMap,
+                                          const nsStylePosition* aStyle)
 {
   const nsStylePosition* itemStyle = aChild->StylePosition();
   return GridArea(
     ResolveLineRange(itemStyle->mGridColumnStart, itemStyle->mGridColumnEnd,
                      aColLineNameMap,
                      &GridNamedArea::mColumnStart, &GridNamedArea::mColumnEnd,
                      mExplicitGridColEnd, aStyle),
     ResolveLineRange(itemStyle->mGridRowStart, itemStyle->mGridRowEnd,
                      aRowLineNameMap,
                      &GridNamedArea::mRowStart, &GridNamedArea::mRowEnd,
                      mExplicitGridRowEnd, aStyle));
 }
 
 nsGridContainerFrame::LineRange
-nsGridContainerFrame::ResolveAbsPosLineRange(
+nsGridContainerFrame::Grid::ResolveAbsPosLineRange(
   const nsStyleGridLine& aStart,
   const nsStyleGridLine& aEnd,
   const LineNameMap& aNameMap,
   uint32_t GridNamedArea::* aAreaStart,
   uint32_t GridNamedArea::* aAreaEnd,
   uint32_t aExplicitGridEnd,
   int32_t aGridStart,
   int32_t aGridEnd,
@@ -1750,19 +2134,45 @@ nsGridContainerFrame::ResolveAbsPosLineR
     // case should result in "auto / auto" unlike normal flow grid items.
     return LineRange(kAutoLine, kAutoLine);
   }
 
   return LineRange(AutoIfOutside(r.mUntranslatedStart, aGridStart, aGridEnd),
                    AutoIfOutside(r.mUntranslatedEnd, aGridStart, aGridEnd));
 }
 
+nsGridContainerFrame::GridArea
+nsGridContainerFrame::Grid::PlaceAbsPos(nsIFrame* aChild,
+                                        const LineNameMap& aColLineNameMap,
+                                        const LineNameMap& aRowLineNameMap,
+                                        const nsStylePosition* aStyle)
+{
+  const nsStylePosition* itemStyle = aChild->StylePosition();
+  int32_t gridColStart = 1 - mExplicitGridOffsetCol;
+  int32_t gridRowStart = 1 - mExplicitGridOffsetRow;
+  return GridArea(
+    ResolveAbsPosLineRange(itemStyle->mGridColumnStart,
+                           itemStyle->mGridColumnEnd,
+                           aColLineNameMap,
+                           &GridNamedArea::mColumnStart,
+                           &GridNamedArea::mColumnEnd,
+                           mExplicitGridColEnd, gridColStart, mGridColEnd,
+                           aStyle),
+    ResolveAbsPosLineRange(itemStyle->mGridRowStart,
+                           itemStyle->mGridRowEnd,
+                           aRowLineNameMap,
+                           &GridNamedArea::mRowStart,
+                           &GridNamedArea::mRowEnd,
+                           mExplicitGridRowEnd, gridRowStart, mGridRowEnd,
+                           aStyle));
+}
+
 uint32_t
-nsGridContainerFrame::FindAutoCol(uint32_t aStartCol, uint32_t aLockedRow,
-                                  const GridArea* aArea) const
+nsGridContainerFrame::Grid::FindAutoCol(uint32_t aStartCol, uint32_t aLockedRow,
+                                        const GridArea* aArea) const
 {
   const uint32_t extent = aArea->mCols.Extent();
   const uint32_t iStart = aLockedRow;
   const uint32_t iEnd = iStart + aArea->mRows.Extent();
   uint32_t candidate = aStartCol;
   for (uint32_t i = iStart; i < iEnd; ) {
     if (i >= mCellMap.mCells.Length()) {
       break;
@@ -1786,54 +2196,29 @@ nsGridContainerFrame::FindAutoCol(uint32
       i = iStart;
     } else {
       ++i;
     }
   }
   return candidate;
 }
 
-nsGridContainerFrame::GridArea
-nsGridContainerFrame::PlaceAbsPos(nsIFrame* aChild,
-                                  const LineNameMap& aColLineNameMap,
-                                  const LineNameMap& aRowLineNameMap,
-                                  const nsStylePosition* aStyle)
-{
-  const nsStylePosition* itemStyle = aChild->StylePosition();
-  int32_t gridColStart = 1 - mExplicitGridOffsetCol;
-  int32_t gridRowStart = 1 - mExplicitGridOffsetRow;
-  return GridArea(
-    ResolveAbsPosLineRange(itemStyle->mGridColumnStart,
-                           itemStyle->mGridColumnEnd,
-                           aColLineNameMap,
-                           &GridNamedArea::mColumnStart,
-                           &GridNamedArea::mColumnEnd,
-                           mExplicitGridColEnd, gridColStart, mGridColEnd,
-                           aStyle),
-    ResolveAbsPosLineRange(itemStyle->mGridRowStart,
-                           itemStyle->mGridRowEnd,
-                           aRowLineNameMap,
-                           &GridNamedArea::mRowStart,
-                           &GridNamedArea::mRowEnd,
-                           mExplicitGridRowEnd, gridRowStart, mGridRowEnd,
-                           aStyle));
-}
-
 void
-nsGridContainerFrame::PlaceAutoCol(uint32_t aStartCol, GridArea* aArea) const
+nsGridContainerFrame::Grid::PlaceAutoCol(uint32_t aStartCol,
+                                         GridArea* aArea) const
 {
   MOZ_ASSERT(aArea->mRows.IsDefinite() && aArea->mCols.IsAuto());
   uint32_t col = FindAutoCol(aStartCol, aArea->mRows.mStart, aArea);
   aArea->mCols.ResolveAutoPosition(col, mExplicitGridOffsetCol);
   MOZ_ASSERT(aArea->IsDefinite());
 }
 
 uint32_t
-nsGridContainerFrame::FindAutoRow(uint32_t aLockedCol, uint32_t aStartRow,
-                                  const GridArea* aArea) const
+nsGridContainerFrame::Grid::FindAutoRow(uint32_t aLockedCol, uint32_t aStartRow,
+                                        const GridArea* aArea) const
 {
   const uint32_t extent = aArea->mRows.Extent();
   const uint32_t jStart = aLockedCol;
   const uint32_t jEnd = jStart + aArea->mCols.Extent();
   const uint32_t iEnd = mCellMap.mCells.Length();
   uint32_t candidate = aStartRow;
   // Find the first gap in the rows that's at least 'extent' tall.
   // ('gap' tracks how tall the current row gap is.)
@@ -1851,28 +2236,29 @@ nsGridContainerFrame::FindAutoRow(uint32
         break;
       }
     }
   }
   return candidate;
 }
 
 void
-nsGridContainerFrame::PlaceAutoRow(uint32_t aStartRow, GridArea* aArea) const
+nsGridContainerFrame::Grid::PlaceAutoRow(uint32_t aStartRow,
+                                         GridArea* aArea) const
 {
   MOZ_ASSERT(aArea->mCols.IsDefinite() && aArea->mRows.IsAuto());
   uint32_t row = FindAutoRow(aArea->mCols.mStart, aStartRow, aArea);
   aArea->mRows.ResolveAutoPosition(row, mExplicitGridOffsetRow);
   MOZ_ASSERT(aArea->IsDefinite());
 }
 
 void
-nsGridContainerFrame::PlaceAutoAutoInRowOrder(uint32_t aStartCol,
-                                              uint32_t aStartRow,
-                                              GridArea* aArea) const
+nsGridContainerFrame::Grid::PlaceAutoAutoInRowOrder(uint32_t aStartCol,
+                                                    uint32_t aStartRow,
+                                                    GridArea* aArea) const
 {
   MOZ_ASSERT(aArea->mCols.IsAuto() && aArea->mRows.IsAuto());
   const uint32_t colExtent = aArea->mCols.Extent();
   const uint32_t gridRowEnd = mGridRowEnd;
   const uint32_t gridColEnd = mGridColEnd;
   uint32_t col = aStartCol;
   uint32_t row = aStartRow;
   for (; row < gridRowEnd; ++row) {
@@ -1885,19 +2271,19 @@ nsGridContainerFrame::PlaceAutoAutoInRow
   MOZ_ASSERT(row < gridRowEnd || col == 0,
              "expected column 0 for placing in a new row");
   aArea->mCols.ResolveAutoPosition(col, mExplicitGridOffsetCol);
   aArea->mRows.ResolveAutoPosition(row, mExplicitGridOffsetRow);
   MOZ_ASSERT(aArea->IsDefinite());
 }
 
 void
-nsGridContainerFrame::PlaceAutoAutoInColOrder(uint32_t aStartCol,
-                                              uint32_t aStartRow,
-                                              GridArea* aArea) const
+nsGridContainerFrame::Grid::PlaceAutoAutoInColOrder(uint32_t aStartCol,
+                                                    uint32_t aStartRow,
+                                                    GridArea* aArea) const
 {
   MOZ_ASSERT(aArea->mCols.IsAuto() && aArea->mRows.IsAuto());
   const uint32_t rowExtent = aArea->mRows.Extent();
   const uint32_t gridRowEnd = mGridRowEnd;
   const uint32_t gridColEnd = mGridColEnd;
   uint32_t col = aStartCol;
   uint32_t row = aStartRow;
   for (; col < gridColEnd; ++col) {
@@ -1910,21 +2296,22 @@ nsGridContainerFrame::PlaceAutoAutoInCol
   MOZ_ASSERT(col < gridColEnd || row == 0,
              "expected row 0 for placing in a new column");
   aArea->mCols.ResolveAutoPosition(col, mExplicitGridOffsetCol);
   aArea->mRows.ResolveAutoPosition(row, mExplicitGridOffsetRow);
   MOZ_ASSERT(aArea->IsDefinite());
 }
 
 void
-nsGridContainerFrame::PlaceGridItems(GridReflowState& aState,
-                                     const LogicalSize& aComputedMinSize,
-                                     const LogicalSize& aComputedSize,
-                                     const LogicalSize& aComputedMaxSize)
+nsGridContainerFrame::Grid::PlaceGridItems(GridReflowState& aState,
+                                           const LogicalSize& aComputedMinSize,
+                                           const LogicalSize& aComputedSize,
+                                           const LogicalSize& aComputedMaxSize)
 {
+  mAreas = aState.mFrame->GetImplicitNamedAreas();
   const nsStylePosition* const gridStyle = aState.mGridStyle;
   mCellMap.ClearOccupied();
 
   // http://dev.w3.org/csswg/css-grid/#grid-definition
   // 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.
@@ -1948,26 +2335,26 @@ nsGridContainerFrame::PlaceGridItems(Gri
   mGridRowEnd = mExplicitGridRowEnd =
     aState.mRowFunctions.ComputeExplicitGridEnd(areas ? areas->NRows() + 1 : 1);
   LineNameMap rowLineNameMap(gridStyle->mGridTemplateRows, numRepeatRows);
 
   // 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;
-  mGridItems.ClearAndRetainStorage();
+  aState.mGridItems.ClearAndRetainStorage();
   for (; !aState.mIter.AtEnd(); aState.mIter.Next()) {
     nsIFrame* child = *aState.mIter;
     GridItemInfo* info =
-      mGridItems.AppendElement(GridItemInfo(PlaceDefinite(child,
-                                                          colLineNameMap,
-                                                          rowLineNameMap,
-                                                          gridStyle)));
+      aState.mGridItems.AppendElement(GridItemInfo(PlaceDefinite(child,
+                                                                 colLineNameMap,
+                                                                 rowLineNameMap,
+                                                                 gridStyle)));
 #ifdef DEBUG
-    MOZ_ASSERT(aState.mIter.GridItemIndex() == mGridItems.Length() - 1,
+    MOZ_ASSERT(aState.mIter.GridItemIndex() == aState.mGridItems.Length() - 1,
                "GridItemIndex() is broken");
     info->mFrame = child;
 #endif
     GridArea& area = info->mArea;
     if (area.mCols.IsDefinite()) {
       minCol = std::min(minCol, area.mCols.mUntranslatedStart);
     }
     if (area.mRows.IsDefinite()) {
@@ -1981,17 +2368,17 @@ nsGridContainerFrame::PlaceGridItems(Gri
   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;
   aState.mIter.Reset();
   for (; !aState.mIter.AtEnd(); aState.mIter.Next()) {
-    GridArea& area = mGridItems[aState.mIter.GridItemIndex()].mArea;
+    GridArea& area = aState.mGridItems[aState.mIter.GridItemIndex()].mArea;
     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;
     }
@@ -2008,21 +2395,21 @@ nsGridContainerFrame::PlaceGridItems(Gri
   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;
+    auto placeAutoMinorFunc = isRowOrder ? &Grid::PlaceAutoCol
+                                         : &Grid::PlaceAutoRow;
     aState.mIter.Reset();
     for (; !aState.mIter.AtEnd(); aState.mIter.Next()) {
-      GridArea& area = mGridItems[aState.mIter.GridItemIndex()].mArea;
+      GridArea& area = aState.mGridItems[aState.mIter.GridItemIndex()].mArea;
       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);
         }
@@ -2042,23 +2429,23 @@ nsGridContainerFrame::PlaceGridItems(Gri
   // XXX https://www.w3.org/Bugs/Public/show_bug.cgi?id=16044
   // XXX seems to indicate it shouldn't.
   // 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;
+  auto placeAutoMajorFunc = isRowOrder ? &Grid::PlaceAutoRow
+                                       : &Grid::PlaceAutoCol;
   aState.mIter.Reset();
   for (; !aState.mIter.AtEnd(); aState.mIter.Next()) {
-    GridArea& area = mGridItems[aState.mIter.GridItemIndex()].mArea;
-    MOZ_ASSERT(*aState.mIter == mGridItems[aState.mIter.GridItemIndex()].mFrame,
-               "iterator out of sync with mGridItems");
+    GridArea& area = aState.mGridItems[aState.mIter.GridItemIndex()].mArea;
+    MOZ_ASSERT(*aState.mIter == aState.mGridItems[aState.mIter.GridItemIndex()].mFrame,
+               "iterator out of sync with aState.mGridItems");
     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) {
             ++cursorMajor;
@@ -2090,38 +2477,39 @@ nsGridContainerFrame::PlaceGridItems(Gri
 #endif
         }
       }
       mCellMap.Fill(area);
       InflateGridFor(area);
     }
   }
 
-  if (IsAbsoluteContainer()) {
+  if (aState.mFrame->IsAbsoluteContainer()) {
     // 9.4 Absolutely-positioned Grid Items
     // http://dev.w3.org/csswg/css-grid/#abspos-items
     // We only resolve definite lines here; we'll align auto positions to the
     // grid container later during reflow.
-    nsFrameList children(GetChildList(GetAbsoluteListID()));
+    nsFrameList children(aState.mFrame->GetChildList(
+                           aState.mFrame->GetAbsoluteListID()));
     const int32_t offsetToColZero = int32_t(mExplicitGridOffsetCol) - 1;
     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;
-    mAbsPosItems.ClearAndRetainStorage();
+    aState.mAbsPosItems.ClearAndRetainStorage();
     size_t i = 0;
     for (nsFrameList::Enumerator e(children); !e.AtEnd(); e.Next(), ++i) {
       nsIFrame* child = e.get();
       GridItemInfo* info =
-        mAbsPosItems.AppendElement(GridItemInfo(PlaceAbsPos(child,
-                                                            colLineNameMap,
-                                                            rowLineNameMap,
-                                                            gridStyle)));
+        aState.mAbsPosItems.AppendElement(GridItemInfo(PlaceAbsPos(child,
+                                                                   colLineNameMap,
+                                                                   rowLineNameMap,
+                                                                   gridStyle)));
 #ifdef DEBUG
       info->mFrame = child;
 #endif
       GridArea& area = info->mArea;
       if (area.mCols.mUntranslatedStart != int32_t(kAutoLine)) {
         area.mCols.mStart = area.mCols.mUntranslatedStart + offsetToColZero;
       }
       if (area.mCols.mUntranslatedEnd != int32_t(kAutoLine)) {
@@ -2140,18 +2528,18 @@ nsGridContainerFrame::PlaceGridItems(Gri
   // |colAdjust| will have a count for each line in the grid of how many
   // tracks were empty between the start of the grid and that line.
   Maybe<nsTArray<uint32_t>> colAdjust;
   uint32_t numEmptyCols = 0;
   if (aState.mColFunctions.mHasRepeatAuto &&
       !gridStyle->mGridTemplateColumns.mIsAutoFill &&
       aState.mColFunctions.NumRepeatTracks() > 0) {
     for (uint32_t col = aState.mColFunctions.mRepeatAutoStart,
-                  endRepeat = aState.mColFunctions.mRepeatAutoEnd,
-                  numColLines = mGridColEnd + 1;
+           endRepeat = aState.mColFunctions.mRepeatAutoEnd,
+           numColLines = mGridColEnd + 1;
          col < numColLines; ++col) {
       if (numEmptyCols) {
         (*colAdjust)[col] = numEmptyCols;
       }
       if (col < endRepeat && mCellMap.IsEmptyCol(col)) {
         ++numEmptyCols;
         if (colAdjust.isNothing()) {
           colAdjust.emplace(numColLines);
@@ -2162,18 +2550,18 @@ nsGridContainerFrame::PlaceGridItems(Gri
     }
   }
   Maybe<nsTArray<uint32_t>> rowAdjust;
   uint32_t numEmptyRows = 0;
   if (aState.mRowFunctions.mHasRepeatAuto &&
       !gridStyle->mGridTemplateRows.mIsAutoFill &&
       aState.mRowFunctions.NumRepeatTracks() > 0) {
     for (uint32_t row = aState.mRowFunctions.mRepeatAutoStart,
-                  endRepeat = aState.mRowFunctions.mRepeatAutoEnd,
-                  numRowLines = mGridRowEnd + 1;
+           endRepeat = aState.mRowFunctions.mRepeatAutoEnd,
+           numRowLines = mGridRowEnd + 1;
          row < numRowLines; ++row) {
       if (numEmptyRows) {
         (*rowAdjust)[row] = numEmptyRows;
       }
       if (row < endRepeat && mCellMap.IsEmptyRow(row)) {
         ++numEmptyRows;
         if (rowAdjust.isNothing()) {
           rowAdjust.emplace(numRowLines);
@@ -2181,26 +2569,26 @@ nsGridContainerFrame::PlaceGridItems(Gri
           PodZero(rowAdjust->Elements(), rowAdjust->Length());
         }
       }
     }
   }
   // Remove the empty 'auto-fit' tracks we found above, if any.
   if (numEmptyCols || numEmptyRows) {
     // Adjust the line numbers in the grid areas.
-    for (auto& item : mGridItems) {
+    for (auto& item : aState.mGridItems) {
       GridArea& area = item.mArea;
       if (numEmptyCols) {
         area.mCols.AdjustForRemovedTracks(*colAdjust);
       }
       if (numEmptyRows) {
         area.mRows.AdjustForRemovedTracks(*rowAdjust);
       }
     }
-    for (auto& item : mAbsPosItems) {
+    for (auto& item : aState.mAbsPosItems) {
       GridArea& area = item.mArea;
       if (numEmptyCols) {
         area.mCols.AdjustAbsPosForRemovedTracks(*colAdjust);
       }
       if (numEmptyRows) {
         area.mRows.AdjustAbsPosForRemovedTracks(*rowAdjust);
       }
     }
@@ -2212,16 +2600,23 @@ nsGridContainerFrame::PlaceGridItems(Gri
     // Adjust the track mapping to unmap the removed tracks.
     auto finalColRepeatCount = aState.mColFunctions.NumRepeatTracks() - numEmptyCols;
     aState.mColFunctions.SetNumRepeatTracks(finalColRepeatCount);
     auto finalRowRepeatCount = aState.mRowFunctions.NumRepeatTracks() - numEmptyRows;
     aState.mRowFunctions.SetNumRepeatTracks(finalRowRepeatCount);
   }
 }
 
+static
+bool IsMinContent(const nsStyleCoord& aCoord)
+{
+  return aCoord.GetUnit() == eStyleUnit_Enumerated &&
+         aCoord.GetIntValue() == NS_STYLE_GRID_TRACK_BREADTH_MIN_CONTENT;
+}
+
 void
 nsGridContainerFrame::TrackSize::Initialize(nscoord aPercentageBasis,
                                             const nsStyleCoord& aMinCoord,
                                             const nsStyleCoord& aMaxCoord)
 {
   MOZ_ASSERT(mBase == 0 && mLimit == 0 && mState == 0,
              "track size data is expected to be initialized to zero");
   // http://dev.w3.org/csswg/css-grid/#algo-init
@@ -2419,38 +2814,16 @@ nsGridContainerFrame::Tracks::CalculateS
     if (freeSpace != NS_UNCONSTRAINEDSIZE) {
       freeSpace -= SumOfGridGaps();
     }
     DistributeFreeSpace(freeSpace);
     StretchFlexibleTracks(aState, aGridItems, aFunctions, freeSpace);
   }
 }
 
-void
-nsGridContainerFrame::CalculateTrackSizes(GridReflowState&   aState,
-                                          const LogicalSize& aContentBox,
-                                          IntrinsicISizeType aConstraint)
-{
-  const WritingMode& wm = aState.mWM;
-  const nsStylePosition* stylePos = aState.mGridStyle;
-  aState.mCols.Initialize(aState.mColFunctions, stylePos->mGridColumnGap,
-                          mGridColEnd, aContentBox.ISize(wm));
-  aState.mRows.Initialize(aState.mRowFunctions, stylePos->mGridRowGap,
-                          mGridRowEnd, aContentBox.BSize(wm));
-
-  aState.mCols.CalculateSizes(aState, mGridItems, aState.mColFunctions,
-                              aContentBox.ISize(wm), &GridArea::mCols,
-                              aConstraint);
-
-  aState.mIter.Reset(); // XXX cleanup this Reset mess!
-  aState.mRows.CalculateSizes(aState, mGridItems, aState.mRowFunctions,
-                              aContentBox.BSize(wm), &GridArea::mRows,
-                              aConstraint);
-}
-
 bool
 nsGridContainerFrame::Tracks::HasIntrinsicButNoFlexSizingInRange(
   const LineRange&      aRange,
   IntrinsicISizeType    aConstraint,
   TrackSize::StateBits* aState) const
 {
   MOZ_ASSERT(!aRange.IsAuto(), "must have a definite range");
   const uint32_t start = aRange.mStart;
@@ -3113,43 +3486,41 @@ nsGridContainerFrame::LineRange::ToPosit
       nscoord pos;
       ToPositionAndLength(aTracks.mSizes, &pos, aLength);
       *aPos = aGridOrigin + pos;
     }
   }
 }
 
 LogicalRect
-nsGridContainerFrame::ContainingBlockFor(const GridReflowState& aState,
-                                         const GridArea&        aArea) const
+nsGridContainerFrame::GridReflowState::ContainingBlockFor(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(aState.mCols.mSizes, &i, &iSize);
-  aArea.mRows.ToPositionAndLength(aState.mRows.mSizes, &b, &bSize);
-  return LogicalRect(aState.mWM, i, b, iSize, bSize);
+  aArea.mCols.ToPositionAndLength(mCols.mSizes, &i, &iSize);
+  aArea.mRows.ToPositionAndLength(mRows.mSizes, &b, &bSize);
+  return LogicalRect(mWM, i, b, iSize, bSize);
 }
 
 LogicalRect
-nsGridContainerFrame::ContainingBlockForAbsPos(const GridReflowState& aState,
-                                               const GridArea&        aArea,
-                                               const LogicalPoint& aGridOrigin,
-                                               const LogicalRect& aGridCB) const
+nsGridContainerFrame::GridReflowState::ContainingBlockForAbsPos(
+  const GridArea&     aArea,
+  const LogicalPoint& aGridOrigin,
+  const LogicalRect&  aGridCB) const
 {
-  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, aGridOrigin.I(wm),
+  nscoord i = aGridCB.IStart(mWM);
+  nscoord b = aGridCB.BStart(mWM);
+  nscoord iSize = aGridCB.ISize(mWM);
+  nscoord bSize = aGridCB.BSize(mWM);
+  aArea.mCols.ToPositionAndLengthForAbsPos(mCols, aGridOrigin.I(mWM),
                                            &i, &iSize);
-  aArea.mRows.ToPositionAndLengthForAbsPos(aState.mRows, aGridOrigin.B(wm),
+  aArea.mRows.ToPositionAndLengthForAbsPos(mRows, aGridOrigin.B(mWM),
                                            &b, &bSize);
-  return LogicalRect(wm, i, b, iSize, bSize);
+  return LogicalRect(mWM, i, b, iSize, bSize);
 }
 
 void
 nsGridContainerFrame::ReflowChildren(GridReflowState&     aState,
                                      const LogicalRect&   aContentArea,
                                      nsHTMLReflowMetrics& aDesiredSize,
                                      nsReflowStatus&      aStatus)
 {
@@ -3164,21 +3535,21 @@ nsGridContainerFrame::ReflowChildren(Gri
   nsStyleContext* containerSC = StyleContext();
   LogicalMargin pad(aState.mReflowState->ComputedLogicalPadding());
   const LogicalPoint padStart(wm, pad.IStart(wm), pad.BStart(wm));
   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)) {
-      MOZ_ASSERT(mGridItems[aState.mIter.GridItemIndex()].mFrame == child,
+      MOZ_ASSERT(aState.mGridItems[aState.mIter.GridItemIndex()].mFrame == child,
                  "iterator out of sync with mGridItems");
-      GridArea& area = mGridItems[aState.mIter.GridItemIndex()].mArea;
+      GridArea& area = aState.mGridItems[aState.mIter.GridItemIndex()].mArea;
       MOZ_ASSERT(area.IsDefinite());
-      cb = ContainingBlockFor(aState, area);
+      cb = aState.ContainingBlockFor(area);
       cb += gridOrigin;
     } else {
       cb = aContentArea;
     }
     WritingMode childWM = child->GetWritingMode();
     LogicalSize childCBSize = cb.Size(wm).ConvertTo(childWM, wm);
     LogicalSize percentBasis(childCBSize);
     // XXX temporary workaround to avoid being INCOMPLETE until we have
@@ -3248,21 +3619,21 @@ nsGridContainerFrame::ReflowChildren(Gri
       // with respect to the grid container's padding-box (CB).
       const LogicalRect gridCB(wm, 0, 0,
                                aContentArea.ISize(wm) + pad.IStartEnd(wm),
                                aContentArea.BSize(wm) + pad.BStartEnd(wm));
       const nsSize gridCBPhysicalSize = gridCB.Size(wm).GetPhysicalSize(wm);
       size_t i = 0;
       for (nsFrameList::Enumerator e(children); !e.AtEnd(); e.Next(), ++i) {
         nsIFrame* child = e.get();
-        MOZ_ASSERT(i < mAbsPosItems.Length());
-        MOZ_ASSERT(mAbsPosItems[i].mFrame == child);
-        GridArea& area = mAbsPosItems[i].mArea;
+        MOZ_ASSERT(i < aState.mAbsPosItems.Length());
+        MOZ_ASSERT(aState.mAbsPosItems[i].mFrame == child);
+        GridArea& area = aState.mAbsPosItems[i].mArea;
         LogicalRect itemCB =
-          ContainingBlockForAbsPos(aState, area, padStart, gridCB);
+          aState.ContainingBlockForAbsPos(area, padStart, 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, gridCBPhysicalSize);
@@ -3321,23 +3692,23 @@ nsGridContainerFrame::Reflow(nsPresConte
        cbState->ComputedSize(wm).ISize(wm) == NS_UNCONSTRAINEDSIZE)) {
     computedMinSize.ISize(wm) = NS_UNCONSTRAINEDSIZE;
   }
   if (!stylePos->MinBSize(wm).IsCoordPercentCalcUnit() ||
       (stylePos->MinBSize(wm).HasPercent() && cbState &&
        cbState->ComputedSize(wm).BSize(wm) == NS_UNCONSTRAINEDSIZE)) {
     computedMinSize.BSize(wm) = NS_UNCONSTRAINEDSIZE;
   }
-
-  PlaceGridItems(gridReflowState, computedMinSize, computedSize,
-                 aReflowState.ComputedMaxSize());
+  Grid grid;
+  grid.PlaceGridItems(gridReflowState, computedMinSize, computedSize,
+                      aReflowState.ComputedMaxSize());
 
   gridReflowState.mIter.Reset();
-  CalculateTrackSizes(gridReflowState, computedSize,
-                      nsLayoutUtils::PREF_ISIZE);
+  gridReflowState.CalculateTrackSizes(grid, computedSize,
+                                      nsLayoutUtils::PREF_ISIZE);
 
   // FIXME bug 1229180: Instead of doing this on every reflow, we should only
   // set these properties if they are needed.
   nsTArray<nscoord> colTrackSizes(gridReflowState.mCols.mSizes.Length());
   for (const TrackSize& sz : gridReflowState.mCols.mSizes) {
     colTrackSizes.AppendElement(sz.mBase);
   }
   ComputedGridTrackInfo* colInfo = new ComputedGridTrackInfo(
@@ -3353,17 +3724,18 @@ nsGridContainerFrame::Reflow(nsPresConte
   ComputedGridTrackInfo* rowInfo = new ComputedGridTrackInfo(
     gridReflowState.mRowFunctions.mExplicitGridOffset,
     gridReflowState.mRowFunctions.NumExplicitTracks(),
     Move(rowTrackSizes));
   Properties().Set(GridRowTrackInfo(), rowInfo);
   
   nscoord bSize = 0;
   if (computedBSize == NS_AUTOHEIGHT) {
-    for (uint32_t i = 0; i < mGridRowEnd; ++i) {
+    const uint32_t numRows = gridReflowState.mRows.mSizes.Length();
+    for (uint32_t i = 0; i < numRows; ++i) {
       bSize += gridReflowState.mRows.mSizes[i].mBase;
     }
     bSize += gridReflowState.mRows.SumOfGridGaps();
     bSize = NS_CSS_MINMAX(bSize,
                           aReflowState.ComputedMinBSize(),
                           aReflowState.ComputedMaxBSize());
   } else {
     bSize = computedBSize;
@@ -3393,24 +3765,25 @@ nscoord
 nsGridContainerFrame::IntrinsicISize(nsRenderingContext* aRenderingContext,
                                      IntrinsicISizeType  aConstraint)
 {
   // Calculate the sum of column sizes under aConstraint.
   // http://dev.w3.org/csswg/css-grid/#intrinsic-sizes
   GridReflowState state(this, *aRenderingContext);
   InitImplicitNamedAreas(state.mGridStyle); // XXX optimize
   LogicalSize indefinite(state.mWM, NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
-  PlaceGridItems(state, indefinite, indefinite, indefinite);  // XXX optimize
-  if (mGridColEnd == 0) {
+  Grid grid;
+  grid.PlaceGridItems(state, indefinite, indefinite, indefinite);  // XXX optimize
+  if (grid.mGridColEnd == 0) {
     return 0;
   }
   state.mCols.Initialize(state.mColFunctions, state.mGridStyle->mGridColumnGap,
-                         mGridColEnd, NS_UNCONSTRAINEDSIZE);
+                         grid.mGridColEnd, NS_UNCONSTRAINEDSIZE);
   state.mIter.Reset();
-  state.mCols.CalculateSizes(state, mGridItems, state.mColFunctions,
+  state.mCols.CalculateSizes(state, state.mGridItems, state.mColFunctions,
                              NS_UNCONSTRAINEDSIZE, &GridArea::mCols,
                              aConstraint);
   nscoord length = 0;
   for (const TrackSize& sz : state.mCols.mSizes) {
     length += sz.mBase;
   }
   return length + state.mCols.SumOfGridGaps();
 }
@@ -3485,63 +3858,17 @@ nsGridContainerFrame::BuildDisplayList(n
 #ifdef DEBUG_FRAME_DUMP
 nsresult
 nsGridContainerFrame::GetFrameName(nsAString& aResult) const
 {
   return MakeFrameName(NS_LITERAL_STRING("GridContainer"), aResult);
 }
 #endif
 
-void
-nsGridContainerFrame::CellMap::Fill(const GridArea& aGridArea)
-{
-  MOZ_ASSERT(aGridArea.IsDefinite());
-  MOZ_ASSERT(aGridArea.mRows.mStart < aGridArea.mRows.mEnd);
-  MOZ_ASSERT(aGridArea.mCols.mStart < aGridArea.mCols.mEnd);
-  const auto numRows = aGridArea.mRows.mEnd;
-  const auto numCols = aGridArea.mCols.mEnd;
-  mCells.EnsureLengthAtLeast(numRows);
-  for (auto i = aGridArea.mRows.mStart; i < numRows; ++i) {
-    nsTArray<Cell>& cellsInRow = mCells[i];
-    cellsInRow.EnsureLengthAtLeast(numCols);
-    for (auto j = aGridArea.mCols.mStart; j < numCols; ++j) {
-      cellsInRow[j].mIsOccupied = true;
-    }
-  }
-}
-
-void
-nsGridContainerFrame::CellMap::ClearOccupied()
-{
-  const size_t numRows = mCells.Length();
-  for (size_t i = 0; i < numRows; ++i) {
-    nsTArray<Cell>& cellsInRow = mCells[i];
-    const size_t numCols = cellsInRow.Length();
-    for (size_t j = 0; j < numCols; ++j) {
-      cellsInRow[j].mIsOccupied = false;
-    }
-  }
-}
-
 #ifdef DEBUG
-void
-nsGridContainerFrame::CellMap::Dump() const
-{
-  const size_t numRows = mCells.Length();
-  for (size_t i = 0; i < numRows; ++i) {
-    const nsTArray<Cell>& cellsInRow = mCells[i];
-    const size_t numCols = cellsInRow.Length();
-    printf("%lu:\t", (unsigned long)i + 1);
-    for (size_t j = 0; j < numCols; ++j) {
-      printf(cellsInRow[j].mIsOccupied ? "X " : ". ");
-    }
-    printf("\n");
-  }
-}
-
 static bool
 FrameWantsToBeInAnonymousGridItem(nsIFrame* aFrame)
 {
   // Note: This needs to match the logic in
   // nsCSSFrameConstructor::FrameConstructionItem::NeedsAnonFlexOrGridItem()
   return aFrame->IsFrameOfType(nsIFrame::eLineParticipant);
 }
 
--- a/layout/generic/nsGridContainerFrame.h
+++ b/layout/generic/nsGridContainerFrame.h
@@ -125,16 +125,17 @@ protected:
   static const uint32_t kTranslatedMaxLine;
   typedef mozilla::LogicalPoint LogicalPoint;
   typedef mozilla::LogicalRect LogicalRect;
   typedef mozilla::LogicalSize LogicalSize;
   typedef mozilla::WritingMode WritingMode;
   typedef mozilla::css::GridNamedArea GridNamedArea;
   typedef nsLayoutUtils::IntrinsicISizeType IntrinsicISizeType;
   class GridItemCSSOrderIterator;
+  struct Grid;
   struct TrackSizingFunctions;
   struct Tracks;
   struct GridReflowState;
   class LineNameMap;
   friend nsContainerFrame* NS_NewGridContainerFrame(nsIPresShell* aPresShell,
                                                     nsStyleContext* aContext);
   explicit nsGridContainerFrame(nsStyleContext* aContext)
     : nsContainerFrame(aContext)
@@ -323,58 +324,16 @@ protected:
   struct GridArea {
     GridArea(const LineRange& aCols, const LineRange& aRows)
       : mCols(aCols), mRows(aRows) {}
     bool IsDefinite() const { return mCols.IsDefinite() && mRows.IsDefinite(); }
     LineRange mCols;
     LineRange mRows;
   };
 
-  /**
-   * A CellMap holds state for each cell in the grid.
-   * It's row major.  It's sparse in the sense that it only has enough rows to
-   * cover the last row that has a grid item.  Each row only has enough entries
-   * to cover columns that are occupied *on that row*, i.e. it's not a full
-   * matrix covering the entire implicit grid.  An absent Cell means that it's
-   * unoccupied by any grid item.
-   */
-  struct CellMap {
-    struct Cell {
-      Cell() : mIsOccupied(false) {}
-      bool mIsOccupied : 1;
-    };
-    void Fill(const GridArea& aGridArea);
-    void ClearOccupied();
-    uint32_t IsEmptyCol(uint32_t aCol) const
-    {
-      for (auto& row : mCells) {
-        if (aCol < row.Length() && row[aCol].mIsOccupied) {
-          return false;
-        }
-      }
-      return true;
-    }
-    uint32_t IsEmptyRow(uint32_t aRow) const
-    {
-      if (aRow >= mCells.Length()) {
-        return true;
-      }
-      for (const Cell& cell : mCells[aRow]) {
-        if (cell.mIsOccupied) {
-          return false;
-        }
-      }
-      return true;
-    }
-#if DEBUG
-    void Dump() const;
-#endif
-    nsTArray<nsTArray<Cell>> mCells;
-  };
-
   struct GridItemInfo {
     explicit GridItemInfo(const GridArea& aArea)
       : mArea(aArea)
     {
       mIsFlexing[0] = false;
       mIsFlexing[1] = false;
     }
 
@@ -382,256 +341,30 @@ protected:
     bool mIsFlexing[2]; // does the item span a flex track? (LogicalAxis index)
     static_assert(mozilla::eLogicalAxisBlock == 0, "unexpected index value");
     static_assert(mozilla::eLogicalAxisInline == 1, "unexpected index value");
 #ifdef DEBUG
     nsIFrame* mFrame;
 #endif
   };
 
-  enum LineRangeSide {
-    eLineRangeSideStart, eLineRangeSideEnd
-  };
-  /**
-   * Return a line number for (non-auto) aLine, per:
-   * http://dev.w3.org/csswg/css-grid/#line-placement
-   * @param aLine style data for the line (must be non-auto)
-   * @param aNth a number of lines to find from aFromIndex, negative if the
-   *             search should be in reverse order.  In the case aLine has
-   *             a specified line name, it's permitted to pass in zero which
-   *             will be treated as one.
-   * @param aFromIndex the zero-based index to start counting from
-   * @param aNameMap for looking up explicit named lines
-   * @param aAreaStart a pointer to GridNamedArea::mColumnStart/mRowStart
-   * @param aAreaEnd a pointer to GridNamedArea::mColumnEnd/mRowEnd
-   * @param aExplicitGridEnd the last line in the explicit grid
-   * @param aEdge indicates whether we are resolving a start or end line
-   * @param aStyle the StylePosition() for the grid container
-   * @return a definite line (1-based), clamped to the kMinLine..kMaxLine range
-   */
-  int32_t ResolveLine(const nsStyleGridLine& aLine,
-                      int32_t aNth,
-                      uint32_t aFromIndex,
-                      const LineNameMap& aNameMap,
-                      uint32_t GridNamedArea::* aAreaStart,
-                      uint32_t GridNamedArea::* aAreaEnd,
-                      uint32_t aExplicitGridEnd,
-                      LineRangeSide aEdge,
-                      const nsStylePosition* aStyle);
-  /**
-   * Return a LineRange based on the given style data. Non-auto lines
-   * are resolved to a definite line number (1-based) per:
-   * http://dev.w3.org/csswg/css-grid/#line-placement
-   * with placement errors corrected per:
-   * http://dev.w3.org/csswg/css-grid/#grid-placement-errors
-   * @param aStyle the StylePosition() for the grid container
-   * @param aStart style data for the start line
-   * @param aEnd style data for the end line
-   * @param aNameMap for looking up explicit named lines
-   * @param aAreaStart a pointer to GridNamedArea::mColumnStart/mRowStart
-   * @param aAreaEnd a pointer to GridNamedArea::mColumnEnd/mRowEnd
-   * @param aExplicitGridEnd the last line in the explicit grid
-   * @param aStyle the StylePosition() for the grid container
-   */
-  LineRange ResolveLineRange(const nsStyleGridLine& aStart,
-                             const nsStyleGridLine& aEnd,
-                             const LineNameMap& aNameMap,
-                             uint32_t GridNamedArea::* aAreaStart,
-                             uint32_t GridNamedArea::* aAreaEnd,
-                             uint32_t aExplicitGridEnd,
-                             const nsStylePosition* aStyle);
-
-  /**
-   * As above but for an abs.pos. child.  Any 'auto' lines will be represented
-   * by kAutoLine in the LineRange result.
-   * @param aGridStart the first line in the final, but untranslated grid
-   * @param aGridEnd the last line in the final, but untranslated grid
-   */
-  LineRange
-  ResolveAbsPosLineRange(const nsStyleGridLine& aStart,
-                         const nsStyleGridLine& aEnd,
-                         const LineNameMap& aNameMap,
-                         uint32_t GridNamedArea::* aAreaStart,
-                         uint32_t GridNamedArea::* aAreaEnd,
-                         uint32_t aExplicitGridEnd,
-                         int32_t aGridStart,
-                         int32_t aGridEnd,
-                         const nsStylePosition* aStyle);
-
-  /**
-   * Return a GridArea with non-auto lines placed at a definite line (1-based)
-   * with placement errors resolved.  One or both positions may still
-   * be 'auto'.
-   * @param aChild the grid item
-   * @param aColLineNameMap for looking up explicit named column lines
-   * @param aRowLineNameMap for looking up explicit named row lines
-   * @param aStyle the StylePosition() for the grid container
-   */
-  GridArea PlaceDefinite(nsIFrame* aChild,
-                         const LineNameMap& aColLineNameMap,
-                         const LineNameMap& aRowLineNameMap,
-                         const nsStylePosition* aStyle);
-
-  /**
-   * Place aArea in the first column (in row aArea->mRows.mStart) starting at
-   * aStartCol without overlapping other items.  The resulting aArea may
-   * overflow the current implicit grid bounds.
-   * Pre-condition: aArea->mRows.IsDefinite() is true.
-   * Post-condition: aArea->IsDefinite() is true.
-   */
-  void PlaceAutoCol(uint32_t aStartCol, GridArea* aArea) const;
-
-  /**
-   * Find the first column in row aLockedRow starting at aStartCol where aArea
-   * could be placed without overlapping other items.  The returned column may
-   * cause aArea to overflow the current implicit grid bounds if placed there.
-   */
-  uint32_t FindAutoCol(uint32_t aStartCol, uint32_t aLockedRow,
-                       const GridArea* aArea) const;
-
-  /**
-   * Place aArea in the first row (in column aArea->mCols.mStart) starting at
-   * aStartRow without overlapping other items. The resulting aArea may
-   * overflow the current implicit grid bounds.
-   * Pre-condition: aArea->mCols.IsDefinite() is true.
-   * Post-condition: aArea->IsDefinite() is true.
-   */
-  void PlaceAutoRow(uint32_t aStartRow, GridArea* aArea) const;
-
-  /**
-   * Find the first row in column aLockedCol starting at aStartRow where aArea
-   * could be placed without overlapping other items.  The returned row may
-   * cause aArea to overflow the current implicit grid bounds if placed there.
-   */
-  uint32_t FindAutoRow(uint32_t aLockedCol, uint32_t aStartRow,
-                       const GridArea* aArea) const;
-
-  /**
-   * Place aArea in the first column starting at aStartCol,aStartRow without
-   * causing it to overlap other items or overflow mGridColEnd.
-   * If there's no such column in aStartRow, continue in position 1,aStartRow+1.
-   * Pre-condition: aArea->mCols.IsAuto() && aArea->mRows.IsAuto() is true.
-   * Post-condition: aArea->IsDefinite() is true.
-   */
-  void PlaceAutoAutoInRowOrder(uint32_t aStartCol, uint32_t aStartRow,
-                               GridArea* aArea) const;
-
-  /**
-   * Place aArea in the first row starting at aStartCol,aStartRow without
-   * causing it to overlap other items or overflow mGridRowEnd.
-   * If there's no such row in aStartCol, continue in position aStartCol+1,1.
-   * Pre-condition: aArea->mCols.IsAuto() && aArea->mRows.IsAuto() is true.
-   * Post-condition: aArea->IsDefinite() is true.
-   */
-  void PlaceAutoAutoInColOrder(uint32_t aStartCol, uint32_t aStartRow,
-                               GridArea* aArea) const;
-
-  /**
-   * Return a GridArea for abs.pos. item with non-auto lines placed at
-   * a definite line (1-based) with placement errors resolved.  One or both
-   * positions may still be 'auto'.
-   * @param aChild the abs.pos. grid item to place
-   * @param aColLineNameMap for looking up explicit named column lines
-   * @param aRowLineNameMap for looking up explicit named row lines
-   * @param aStyle the StylePosition() for the grid container
-   */
-  GridArea PlaceAbsPos(nsIFrame* aChild,
-                       const LineNameMap& aColLineNameMap,
-                       const LineNameMap& aRowLineNameMap,
-                       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 aComputedMinSize the container's min-size - used to determine
-   *   the number of repeat(auto-fill/fit) tracks.
-   * @param aComputedSize the container's size - used to determine
-   *   the number of repeat(auto-fill/fit) tracks.
-   * @param aComputedMaxSize the container's max-size - used to determine
-   *   the number of repeat(auto-fill/fit) tracks.
-   */
-  void PlaceGridItems(GridReflowState&   aState,
-                      const LogicalSize& aComputedMinSize,
-                      const LogicalSize& aComputedSize,
-                      const LogicalSize& aComputedMaxSize);
-  // Helper for the above.
-  void PlaceGridItems(GridReflowState&   aState,
-                      const LineNameMap& aColLineNameMap,
-                      const LineNameMap& aRowLineNameMap);
-
-  /**
-   * Inflate the implicit grid to include aArea.
-   * @param aArea may be definite or auto
-   */
-  void InflateGridFor(const GridArea& aArea)
-  {
-    mGridColEnd = std::max(mGridColEnd, aArea.mCols.HypotheticalEnd());
-    mGridRowEnd = std::max(mGridRowEnd, aArea.mRows.HypotheticalEnd());
-    MOZ_ASSERT(mGridColEnd <= kTranslatedMaxLine &&
-               mGridRowEnd <= kTranslatedMaxLine);
-  }
-
-  /**
-   * Calculate track sizes.
-   */
-  void CalculateTrackSizes(GridReflowState&            aState,
-                           const mozilla::LogicalSize& aContentBox,
-                           IntrinsicISizeType          aConstraint);
-
-  /**
-   * 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,
-                                  const nsStyleGridLine& aEnd,
-                                  const LineNameMap& aNameMap,
-                                  uint32_t GridNamedArea::* aAreaStart,
-                                  uint32_t GridNamedArea::* aAreaEnd,
-                                  uint32_t aExplicitGridEnd,
-                                  const nsStylePosition* aStyle);
-
   /**
    * XXX temporary - move the ImplicitNamedAreas stuff to the style system.
    * The implicit area names that come from x-start .. x-end lines in
    * grid-template-columns / grid-template-rows are stored in this frame
    * property when needed, as a ImplicitNamedAreas* value.
    */
   typedef nsTHashtable<nsStringHashKey> ImplicitNamedAreas;
   NS_DECLARE_FRAME_PROPERTY_DELETABLE(ImplicitNamedAreasProperty,
                                       ImplicitNamedAreas)
   void InitImplicitNamedAreas(const nsStylePosition* aStyle);
   void AddImplicitNamedAreas(const nsTArray<nsTArray<nsString>>& aLineNameLists);
   ImplicitNamedAreas* GetImplicitNamedAreas() const {
     return Properties().Get(ImplicitNamedAreasProperty());
   }
-  bool HasImplicitNamedArea(const nsString& aName) const {
-    ImplicitNamedAreas* areas = GetImplicitNamedAreas();
-    return areas && areas->Contains(aName);
-  }
-
-  /**
-   * Return the containing block for a grid item occupying aArea.
-   */
-  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 aGridOrigin the origin of the grid
-   * @param aGridCB the grid container containing block (its padding area)
-   */
-  LogicalRect ContainingBlockForAbsPos(const GridReflowState& aState,
-                                       const GridArea&        aArea,
-                                       const LogicalPoint&    aGridOrigin,
-                                       const LogicalRect&     aGridCB) const;
 
   /**
    * Reflow and place our children.
    */
   void ReflowChildren(GridReflowState&     aState,
                       const LogicalRect&   aContentArea,
                       nsHTMLReflowMetrics& aDesiredSize,
                       nsReflowStatus&      aStatus);
@@ -643,56 +376,16 @@ protected:
                          IntrinsicISizeType  aConstraint);
 
 #ifdef DEBUG
   void SanityCheckAnonymousGridItems() const;
 #endif // DEBUG
 
 private:
   /**
-   * Info about each (normal flow) grid item.
-   */
-  nsTArray<GridItemInfo> mGridItems;
-
-  /**
-   * Info about each grid-aligned abs.pos. child.
-   */
-  nsTArray<GridItemInfo> mAbsPosItems;
-
-  /**
-   * State for each cell in the grid.
-   */
-  CellMap mCellMap;
-
-  /**
-   * The last column grid line (1-based) in the explicit grid.
-   * (i.e. the number of explicit columns + 1)
-   */
-  uint32_t mExplicitGridColEnd;
-  /**
-   * The last row grid line (1-based) in the explicit grid.
-   * (i.e. the number of explicit rows + 1)
-   */
-  uint32_t mExplicitGridRowEnd;
-  // Same for the implicit grid, except these become zero-based after
-  // resolving definite lines.
-  uint32_t mGridColEnd;
-  uint32_t mGridRowEnd;
-
-  /**
-   * Offsets from the start of the implicit grid to the start of the translated
-   * explicit grid.  They are zero if there are no implicit lines before 1,1.
-   * e.g. "grid-column: span 3 / 1" makes mExplicitGridOffsetCol = 3 and the
-   * corresponding GridArea::mCols will be 0 / 3 in the zero-based translated
-   * grid.
-   */
-  uint32_t mExplicitGridOffsetCol;
-  uint32_t mExplicitGridOffsetRow;
-
-  /**
    * Cached values to optimize GetMinISize/GetPrefISize.
    */
   nscoord mCachedMinISize;
   nscoord mCachedPrefISize;
 
   /**
    * True iff the normal flow children are already in CSS 'order' in the
    * order they occur in the child frame list.