Bug 1300877 - Expose removed grid auto-fit tracks to devtools API. r=mats, r=ehsan
authorBrad Werth <bwerth@mozilla.com>
Wed, 21 Sep 2016 11:49:29 -0700
changeset 315190 c684f2f380767b95585e0daf0d88a412a1a674d3
parent 315189 282c98c234bbc868e936998598ad8bb4d11371a2
child 315191 526f72b839de022ad2e7f49951c72f841c4945d0
push id32563
push userihsiao@mozilla.com
push dateMon, 26 Sep 2016 11:18:33 +0000
treeherderautoland@eb840c87b5fd [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmats, ehsan
bugs1300877
milestone52.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 1300877 - Expose removed grid auto-fit tracks to devtools API. r=mats, r=ehsan MozReview-Commit-ID: 3E1au3BQyLw
dom/grid/GridLines.cpp
dom/grid/GridLines.h
dom/grid/GridTracks.cpp
dom/grid/test/chrome.ini
dom/grid/test/chrome/test_grid_repeats.html
dom/grid/test/chrome/test_grid_track_state.html
dom/webidl/Grid.webidl
layout/generic/nsGridContainerFrame.cpp
layout/generic/nsGridContainerFrame.h
--- a/dom/grid/GridLines.cpp
+++ b/dom/grid/GridLines.cpp
@@ -75,30 +75,30 @@ GridLines::SetLineInfo(const ComputedGri
   }
 
   uint32_t trackCount = aTrackInfo->mEndFragmentTrack -
                         aTrackInfo->mStartFragmentTrack;
 
   // If there is at least one track, line count is one more
   // than the number of tracks.
   if (trackCount > 0) {
-    double endOfLastTrack = 0.0;
-    double startOfNextTrack;
+    nscoord lastTrackEdge = 0;
+    nscoord startOfNextTrack;
+    uint32_t repeatIndex = 0;
+    uint32_t numRepeatTracks = aTrackInfo->mRemovedRepeatTracks.Length();
+    uint32_t numAddedLines = 0;
 
     for (uint32_t i = aTrackInfo->mStartFragmentTrack;
          i < aTrackInfo->mEndFragmentTrack + 1;
          i++) {
       uint32_t line1Index = i + 1;
 
       startOfNextTrack = (i < aTrackInfo->mEndFragmentTrack) ?
                          aTrackInfo->mPositions[i] :
-                         endOfLastTrack;
-
-      GridLine* line = new GridLine(this);
-      mLines.AppendElement(line);
+                         lastTrackEdge;
 
       nsTArray<nsString> lineNames;
       if (aLineInfo) {
         lineNames = aLineInfo->mNames.SafeElementAt(i, nsTArray<nsString>());
       }
 
       // Add in names from grid areas where this line is used as a boundary.
       for (auto area : aAreas) {
@@ -123,36 +123,129 @@ GridLines::SetLineInfo(const ComputedGri
           }
         }
 
         if (haveNameToAdd && !lineNames.Contains(nameToAdd)) {
           lineNames.AppendElement(nameToAdd);
         }
       }
 
+      if (i >= aTrackInfo->mRepeatFirstTrack &&
+          repeatIndex < numRepeatTracks) {
+        numAddedLines += AppendRemovedAutoFits(aTrackInfo,
+                                               aLineInfo,
+                                               lastTrackEdge,
+                                               repeatIndex,
+                                               numRepeatTracks,
+                                               lineNames);
+      }
+
+      RefPtr<GridLine> line = new GridLine(this);
+      mLines.AppendElement(line);
       line->SetLineValues(
         lineNames,
-        nsPresContext::AppUnitsToDoubleCSSPixels(endOfLastTrack),
+        nsPresContext::AppUnitsToDoubleCSSPixels(lastTrackEdge),
         nsPresContext::AppUnitsToDoubleCSSPixels(startOfNextTrack -
-                                                 endOfLastTrack),
-        line1Index,
+                                                 lastTrackEdge),
+        line1Index + numAddedLines,
         (
           // Implicit if there are no explicit tracks, or if the index
           // is before the first explicit track, or after
           // a track beyond the last explicit track.
           (aTrackInfo->mNumExplicitTracks == 0) ||
           (i < aTrackInfo->mNumLeadingImplicitTracks) ||
           (i > aTrackInfo->mNumLeadingImplicitTracks +
                aTrackInfo->mNumExplicitTracks) ?
             GridDeclaration::Implicit :
             GridDeclaration::Explicit
         )
       );
 
       if (i < aTrackInfo->mEndFragmentTrack) {
-        endOfLastTrack = aTrackInfo->mPositions[i] + aTrackInfo->mSizes[i];
+        lastTrackEdge = aTrackInfo->mPositions[i] + aTrackInfo->mSizes[i];
       }
     }
   }
 }
 
+uint32_t
+GridLines::AppendRemovedAutoFits(const ComputedGridTrackInfo* aTrackInfo,
+                                 const ComputedGridLineInfo* aLineInfo,
+                                 nscoord aLastTrackEdge,
+                                 uint32_t& aRepeatIndex,
+                                 uint32_t aNumRepeatTracks,
+                                 nsTArray<nsString>& aLineNames)
+{
+  // Check to see if lineNames contains ALL of the before line names.
+  bool alreadyHasBeforeLineNames = true;
+  for (const auto& beforeName : aLineInfo->mNamesBefore) {
+    if (!aLineNames.Contains(beforeName)) {
+      alreadyHasBeforeLineNames = false;
+      break;
+    }
+  }
+
+  bool extractedExplicitLineNames = false;
+  nsTArray<nsString> explicitLineNames;
+  uint32_t linesAdded = 0;
+  while (aRepeatIndex < aNumRepeatTracks &&
+         aTrackInfo->mRemovedRepeatTracks[aRepeatIndex]) {
+    // If this is not the very first call to this function, and if we
+    // haven't already added a line this call, pull all the explicit
+    // names to pass along to the next line that will be added after
+    // this function completes.
+    if (aRepeatIndex > 0 &&
+        linesAdded == 0) {
+      // Find the names that didn't match the before or after names,
+      // and extract them.
+      for (const auto& name : aLineNames) {
+        if (!aLineInfo->mNamesBefore.Contains(name) &&
+            !aLineInfo->mNamesAfter.Contains(name)) {
+          explicitLineNames.AppendElement(name);
+        }
+      }
+      for (const auto& extractedName : explicitLineNames) {
+        aLineNames.RemoveElement(extractedName);
+      }
+      extractedExplicitLineNames = true;
+    }
+
+    // If this is the second or later time through, or didn't already
+    // have before names, add them.
+    if (linesAdded > 0 || !alreadyHasBeforeLineNames) {
+      aLineNames.AppendElements(aLineInfo->mNamesBefore);
+    }
+
+    RefPtr<GridLine> line = new GridLine(this);
+    mLines.AppendElement(line);
+    line->SetLineValues(
+      aLineNames,
+      nsPresContext::AppUnitsToDoubleCSSPixels(aLastTrackEdge),
+      nsPresContext::AppUnitsToDoubleCSSPixels(0),
+      aTrackInfo->mRepeatFirstTrack + aRepeatIndex + 1,
+      GridDeclaration::Explicit
+    );
+
+    // No matter what, the next line should have the after names associated
+    // with it. If we go through the loop again, the before names will also
+    // be added.
+    aLineNames = aLineInfo->mNamesAfter;
+    aRepeatIndex++;
+
+    linesAdded++;
+  }
+  aRepeatIndex++;
+
+  if (extractedExplicitLineNames) {
+    // Pass on the explicit names we saved to the next explicit line.
+    aLineNames.AppendElements(explicitLineNames);
+  }
+
+  if (alreadyHasBeforeLineNames && linesAdded > 0) {
+    // If we started with before names, pass them on to the next explicit
+    // line.
+    aLineNames.AppendElements(aLineInfo->mNamesBefore);
+  }
+  return linesAdded;
+}
+
 } // namespace dom
 } // namespace mozilla
--- a/dom/grid/GridLines.h
+++ b/dom/grid/GridLines.h
@@ -40,16 +40,23 @@ public:
   GridLine* IndexedGetter(uint32_t aIndex, bool& aFound);
 
   void SetLineInfo(const ComputedGridTrackInfo* aTrackInfo,
                    const ComputedGridLineInfo* aLineInfo,
                    const nsTArray<RefPtr<GridArea>>& aAreas,
                    bool aIsRow);
 
 protected:
+  uint32_t AppendRemovedAutoFits(const ComputedGridTrackInfo* aTrackInfo,
+                                 const ComputedGridLineInfo* aLineInfo,
+                                 nscoord aLastTrackEdge,
+                                 uint32_t& aRepeatIndex,
+                                 uint32_t aNumRepeatTracks,
+                                 nsTArray<nsString>& aLineNames);
+
   RefPtr<GridDimension> mParent;
   nsTArray<RefPtr<GridLine>> mLines;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif /* mozilla_dom_GridLines_h */
--- a/dom/grid/GridTracks.cpp
+++ b/dom/grid/GridTracks.cpp
@@ -67,32 +67,68 @@ GridTracks::SetTrackInfo(const ComputedG
 {
   // rebuild the tracks based on aTrackInfo
   mTracks.Clear();
 
   if (!aTrackInfo) {
     return;
   }
 
+  nscoord lastTrackEdge = 0;
+  uint32_t repeatIndex = 0;
+  auto AppendRemovedAutoFits = [this, &aTrackInfo, &lastTrackEdge,
+                                &repeatIndex]()
+  {
+    uint32_t numRepeatTracks = aTrackInfo->mRemovedRepeatTracks.Length();
+    // Add in removed auto-fit tracks
+    while (repeatIndex < numRepeatTracks &&
+         aTrackInfo->mRemovedRepeatTracks[repeatIndex]) {
+
+      RefPtr<GridTrack> track = new GridTrack(this);
+      mTracks.AppendElement(track);
+      track->SetTrackValues(
+        nsPresContext::AppUnitsToDoubleCSSPixels(lastTrackEdge),
+        nsPresContext::AppUnitsToDoubleCSSPixels(0),
+        GridDeclaration::Explicit,
+        GridTrackState::Removed
+      );
+      repeatIndex++;
+    }
+    repeatIndex++;
+  };
+
   for (size_t i = aTrackInfo->mStartFragmentTrack;
        i < aTrackInfo->mEndFragmentTrack;
        i++) {
-    GridTrack* track = new GridTrack(this);
+    if (i >= aTrackInfo->mRepeatFirstTrack) {
+      // Append removed auto-fit tracks, if appropriate. The
+      // AppendRemovedAutoFits function exits early once it has been called
+      // aTrackInfo->mRemovedRepeatTracks.Length() times -- a check we don't
+      // replicate here or at subsequent calling sites.
+      AppendRemovedAutoFits();
+    }
+
+    RefPtr<GridTrack> track = new GridTrack(this);
     mTracks.AppendElement(track);
     track->SetTrackValues(
       nsPresContext::AppUnitsToDoubleCSSPixels(aTrackInfo->mPositions[i]),
       nsPresContext::AppUnitsToDoubleCSSPixels(aTrackInfo->mSizes[i]),
       (
         // Implicit if index is before the first explicit track, or after
         // the last explicit track.
         (i < aTrackInfo->mNumLeadingImplicitTracks) ||
         (i >= aTrackInfo->mNumLeadingImplicitTracks +
               aTrackInfo->mNumExplicitTracks) ?
           GridDeclaration::Implicit :
           GridDeclaration::Explicit
       ),
       GridTrackState(aTrackInfo->mStates[i])
     );
+
+    lastTrackEdge = aTrackInfo->mPositions[i] + aTrackInfo->mSizes[i];
   }
+
+  // Append any trailing removed auto-fit tracks.
+  AppendRemovedAutoFits();
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/grid/test/chrome.ini
+++ b/dom/grid/test/chrome.ini
@@ -1,7 +1,7 @@
 [chrome/test_grid_areas.html]
 [chrome/test_grid_fragmentation.html]
 [chrome/test_grid_implicit.html]
 [chrome/test_grid_lines.html]
 [chrome/test_grid_object.html]
-[chrome/test_grid_track_state.html]
+[chrome/test_grid_repeats.html]
 [chrome/test_grid_tracks.html]
rename from dom/grid/test/chrome/test_grid_track_state.html
rename to dom/grid/test/chrome/test_grid_repeats.html
--- a/dom/grid/test/chrome/test_grid_track_state.html
+++ b/dom/grid/test/chrome/test_grid_repeats.html
@@ -10,79 +10,158 @@ body {
 }
 .wrapper {
 	display: grid;
 	width: 600px;
 	grid-gap: 0px;
 	background-color: #f00;
 }
 .grid1 {
-	grid-template-columns: 50px 0 repeat(auto-fit, 100px);
+	grid-template-columns: 50px 0px repeat(auto-fit, 100px);
 }
 .grid2 {
-	grid-template-columns: 50px 0 [real-before] repeat(auto-fit, [before] 100px [after]) [real-after];
+	grid-template-columns: 50px 0px [real-before] repeat(auto-fit, [before] 100px [after]) [real-after] 0px [final];
 }
 .grid3 {
 	grid-template-columns: repeat(3, 66px) [real-before] repeat(auto-fit, [before] 100px [after]) [real-after];
 }
 .grid4 {
 	grid-template-columns: repeat(2, 100px) repeat(auto-fill, 50px);
 }
 .grid5 {
 	grid-template-columns: [real-before] repeat(auto-fit, [before] 100px [after]) [real-after];
 }
+.grid6 {
+	grid-template-columns: [first] 0px [real-before] repeat(auto-fit, [before] 100px [after]) [real-after];
+}
+.grid7 {
+	grid-template-columns: [real-before] repeat(auto-fit, [before] 100px [after]) [real-after] 0px [final];
+}
+.grid8 {
+	grid-template-columns: [real-before] repeat(auto-fit, [before] 1000px [after]) [real-after];
+}
+.grid9 {
+	grid-template-columns: [real-before] repeat(auto-fit, 100px [after]) [real-after];
+}
+.grid10 {
+	grid-template-columns: [real-before] repeat(auto-fit, [before] 100px) [real-after];
+}
 .box {
 	background-color: #444;
 	color: #fff;
 }
 .a {
 	grid-column: auto;
 }
 .b {
 	grid-column: 4;
 }
 .c {
 	grid-column: 6;
 }
 .d {
 	grid-column: 7;
 }
+.e {
+	grid-column: 5;
+}
 
 </style>
 
 <script>
 'use strict';
 
 SimpleTest.waitForExplicitFinish();
 
+function testLines(elementName, grid, expectedValues) {
+	for (let i = 0; i < grid.cols.lines.length; i++) {
+		is(grid.cols.lines[i].number, (i + 1), elementName + " line " + (i + 1) + " has expected number.");
+		is(grid.cols.lines[i].start, expectedValues[i].start, elementName + " line " + (i + 1) + " has expected start.");
+		is(grid.cols.lines[i].breadth, 0, elementName + " line " + (i + 1) + " has zero breadth.");
+		is(grid.cols.lines[i].names + "", expectedValues[i].names, elementName + " line " + (i + 1) + " has expected names.");
+	}
+}
+
 function runTests() {
 	let wrapper = document.getElementById("wrapper1");
 	let grid = wrapper.getGridFragments()[0];
 
-	// test auto-fit count after removal
-	is(grid.cols.tracks.length, 3, "Grid column track array compensates for removed auto-fit columns.");
+	// test auto-fit count
+	is(grid.cols.tracks.length, 7, "Grid column track array reports removed auto-fit columns.");
 
 	// test resolved value of grid-template-columns
 	let templateColumnsText = getComputedStyle(wrapper).gridTemplateColumns;
 	is(templateColumnsText, "50px 0px 0px 100px 0px 0px 0px",
 		"Resolved value of grid-template-columns reports removed auto-fits as '0px'.");
 
-	is(grid.cols.tracks[0].breadth, 50, "Column 1 is breadth 50.");
-	is(grid.cols.tracks[1].breadth, 0, "Column 2 is breadth 0.");
-	is(grid.cols.tracks[2].breadth, 100, "Column 3 is breadth 100.");
+	// test starts, breadths, and states
+	let expectedValues = [
+		{ "start": 0,
+		  "breadth": 50,
+		  "state": "static" },
+		{ "start": 50,
+		  "breadth": 0,
+		  "state": "static" },
+		{ "start": 50,
+		  "breadth": 0,
+		  "state": "removed" },
+		{ "start": 50,
+		  "breadth": 100,
+		  "state": "repeat" },
+		{ "start": 150,
+		  "breadth": 0,
+		  "state": "removed" },
+		{ "start": 150,
+		  "breadth": 0,
+		  "state": "removed" },
+		{ "start": 150,
+		  "breadth": 0,
+		  "state": "removed" },
+	];
+	for (let i = 0; i < grid.cols.tracks.length; i++) {
+		is(grid.cols.tracks[i].start, expectedValues[i].start, "Column " + (i + 1) + " has expected start.");
+		is(grid.cols.tracks[i].breadth, expectedValues[i].breadth, "Column " + (i + 1) + " has expected breadth.");
+		is(grid.cols.tracks[i].state, expectedValues[i].state, "Column " + (i + 1) + " has expected state.");
+	}
 
 
 	wrapper = document.getElementById("wrapper2");
 	grid = wrapper.getGridFragments()[0];
 
+	// test auto-fit count
+	is(grid.cols.lines.length, 9, "Grid column line array reports removed auto-fit columns.");
+
 	// test resolved value of grid-template-columns
 	templateColumnsText = getComputedStyle(wrapper).gridTemplateColumns;
-	is(templateColumnsText, "50px 0px [real-before before] 0px [after before] 100px [after before] 0px [after before] 100px [after before] 0px [after real-after]",
+	is(templateColumnsText, "50px 0px [real-before before] 0px [after before] 100px [after before] 0px [after before] 100px [after before] 0px [after real-after] 0px [final]",
 		"Resolved value of grid-template-columns reports lines for removed tracks.");
 
+	// test starts and names
+	expectedValues = [
+		{ "start": 0,
+		  "names": "" },
+		{ "start": 50,
+		  "names": "" },
+		{ "start": 50,
+		  "names": "real-before,before" },
+		{ "start": 50,
+		  "names": "after,before" },
+		{ "start": 150,
+		  "names": "after,before" },
+		{ "start": 150,
+		  "names": "after,before" },
+		{ "start": 250,
+		  "names": "after,before" },
+		{ "start": 250,
+		  "names": "after,real-after" },
+		{ "start": 250,
+		  "names": "final" },
+	];
+	testLines("wrapper2", grid, expectedValues);
+
 
 	wrapper = document.getElementById("wrapper3");
 	grid = wrapper.getGridFragments()[0];
 
 	// test resolved value of grid-template-columns
 	templateColumnsText = getComputedStyle(wrapper).gridTemplateColumns;
 	is(templateColumnsText, "66px 66px 66px [real-before before] 100px [after before] 0px [after before] 100px [after before] 100px [after real-after]",
 		"Resolved value of grid-template-columns reports lines for removed tracks.");
@@ -101,49 +180,179 @@ function runTests() {
 	}
 
 
 	wrapper = document.getElementById("wrapper5");
 	grid = wrapper.getGridFragments()[0];
 
 	// test resolved value of grid-template-columns
 	templateColumnsText = getComputedStyle(wrapper).gridTemplateColumns;
-	is(templateColumnsText, "[real-before before] 0px [after before] 0px [after before] 0px [after before] 0px [after before] 0px [after before] 0px [after real-after]",
-		"Resolved value of grid-template-columns no longer lists 'none' when all auto-fit tracks are empty.");
+	is(templateColumnsText, "[real-before before] 0px [after before] 0px [after before] 0px [after before] 0px [after before] 0px [after before] 0px [after real-after]", "Resolved value of grid-template-columns no longer lists 'none' when all auto-fit tracks are empty.");
+
+
+	wrapper = document.getElementById("wrapper6");
+	grid = wrapper.getGridFragments()[0];
+
+	// test starts and names
+	expectedValues = [
+		{ "start": 0,
+		  "names": "first" },
+		{ "start": 0,
+		  "names": "real-before,before" },
+		{ "start": 0,
+		  "names": "after,before" },
+		{ "start": 0,
+		  "names": "after,before" },
+		{ "start": 100,
+		  "names": "after,before" },
+		{ "start": 100,
+		  "names": "after,before" },
+		{ "start": 100,
+		  "names": "after,before" },
+		{ "start": 100,
+		  "names": "after,real-after" },
+	];
+	testLines("wrapper6", grid, expectedValues);
+
+
+	wrapper = document.getElementById("wrapper7");
+	grid = wrapper.getGridFragments()[0];
+
+	// test starts and names
+	expectedValues = [
+		{ "start": 0,
+		  "names": "real-before,before" },
+		{ "start": 0,
+		  "names": "after,before" },
+		{ "start": 0,
+		  "names": "after,before" },
+		{ "start": 0,
+		  "names": "after,before" },
+		{ "start": 100,
+		  "names": "after,before" },
+		{ "start": 100,
+		  "names": "after,before" },
+		{ "start": 100,
+		  "names": "after,real-after" },
+		{ "start": 100,
+		  "names": "final" },
+	];
+	testLines("wrapper7", grid, expectedValues);
+
+
+	wrapper = document.getElementById("wrapper8");
+	grid = wrapper.getGridFragments()[0];
+
+	// test starts and names
+	expectedValues = [
+		{ "start": 0,
+		  "names": "real-before,before" },
+		{ "start": 0,
+		  "names": "after,real-after" },
+	];
+	testLines("wrapper8", grid, expectedValues);
+
+
+	wrapper = document.getElementById("wrapper9");
+	grid = wrapper.getGridFragments()[0];
+
+	// test starts and names
+	expectedValues = [
+		{ "start": 0,
+		  "names": "real-before" },
+		{ "start": 0,
+		  "names": "after" },
+		{ "start": 0,
+		  "names": "after" },
+		{ "start": 0,
+		  "names": "after" },
+		{ "start": 100,
+		  "names": "after" },
+		{ "start": 200,
+		  "names": "after" },
+		{ "start": 200,
+		  "names": "after,real-after" },
+	];
+	testLines("wrapper9", grid, expectedValues);
+
+
+	wrapper = document.getElementById("wrapper10");
+	grid = wrapper.getGridFragments()[0];
+
+	// test starts and names
+	expectedValues = [
+		{ "start": 0,
+		  "names": "real-before,before" },
+		{ "start": 0,
+		  "names": "before" },
+		{ "start": 0,
+		  "names": "before" },
+		{ "start": 0,
+		  "names": "before" },
+		{ "start": 100,
+		  "names": "before" },
+		{ "start": 200,
+		  "names": "before" },
+		{ "start": 200,
+		  "names": "real-after" },
+	];
+	testLines("wrapper10", grid, expectedValues);
 
 	SimpleTest.finish();
 }
 </script>
 </head>
 <body onLoad="runTests();">
 
 	<div id="wrapper1" class="wrapper grid1">
 		<div id="boxB" class="box b">B</div>
 	</div>
 
 	<br/>
-
 	<div id="wrapper2" class="wrapper grid2">
 		<div id="boxB" class="box b">B</div>
 		<div id="boxC" class="box c">C</div>
 	</div>
 
 	<br/>
-
 	<div id="wrapper3" class="wrapper grid3">
 		<div id="boxB" class="box b">B</div>
 		<div id="boxC" class="box c">C</div>
 		<div id="boxD" class="box d">D</div>
 	</div>
 
 	<br/>
-
 	<div id="wrapper4" class="wrapper grid4">
 		<div id="boxA" class="box a">A</div>
 	</div>
 
 	<br/>
+	<div id="wrapper5" class="wrapper grid5">
+	</div>
 
-	<div id="wrapper5" class="wrapper grid5">
+	<br/>
+	<div id="wrapper6" class="wrapper grid6">
+		<div id="boxB" class="box b">B</div>
+	</div>
+
+	<br/>
+	<div id="wrapper7" class="wrapper grid7">
+		<div id="boxB" class="box b">B</div>
+	</div>
+
+	<br/>
+	<div id="wrapper8" class="wrapper grid8">
+	</div>
+
+	<br/>
+	<div id="wrapper9" class="wrapper grid9">
+		<div id="boxB" class="box b">B</div>
+		<div id="boxE" class="box e">E</div>
+	</div>
+
+	<br/>
+	<div id="wrapper10" class="wrapper grid10">
+		<div id="boxB" class="box b">B</div>
+		<div id="boxE" class="box e">E</div>
 	</div>
 
 </body>
 </html>
--- a/dom/webidl/Grid.webidl
+++ b/dom/webidl/Grid.webidl
@@ -9,20 +9,20 @@
 /**
  * Explicit and implicit types apply to tracks, lines, and areas.
  * https://drafts.csswg.org/css-grid/#explicit-grids
  * https://drafts.csswg.org/css-grid/#implicit-grids
  */
 enum GridDeclaration { "explicit", "implicit" };
 
 /**
- * Tracks expanded from auto-fill or auto-fit have repeat state, other tracks
- * are static.
+ * Tracks expanded from auto-fill are repeat , auto-fits with elements are
+ * also repeat, auto-fits with no elements are removed, other tracks are static.
  */
-enum GridTrackState { "static", "repeat" };
+enum GridTrackState { "static", "repeat", "removed" };
 
 [ChromeOnly]
 interface Grid
 {
   readonly attribute GridDimension rows;
   readonly attribute GridDimension cols;
   [Cached, Constant]
   readonly attribute sequence<GridArea> areas;
--- a/layout/generic/nsGridContainerFrame.cpp
+++ b/layout/generic/nsGridContainerFrame.cpp
@@ -1639,43 +1639,46 @@ struct nsGridContainerFrame::Tracks
     const nsStyleGridTemplate& aGridTemplate,
     const TrackSizingFunctions& aFunctions,
     uint32_t aIndex)
   {
     nsTArray<nsString> lineNames;
 
     bool hasRepeatAuto = aGridTemplate.HasRepeatAuto();
     const nsTArray<nsTArray<nsString>>& lineNameLists(
-        aGridTemplate.mLineNameLists);
+      aGridTemplate.mLineNameLists);
 
     if (!hasRepeatAuto) {
       if (aIndex < lineNameLists.Length()) {
         lineNames.AppendElements(lineNameLists[aIndex]);
       }
     } else {
       const uint32_t repeatTrackCount = aFunctions.NumRepeatTracks();
       const uint32_t repeatAutoStart = aGridTemplate.mRepeatAutoIndex;
       const uint32_t repeatAutoEnd = (repeatAutoStart + repeatTrackCount);
       const int32_t repeatEndDelta = int32_t(repeatTrackCount - 1);
 
-      if (aIndex < repeatAutoEnd && aIndex >= repeatAutoStart) {
-        lineNames.AppendElements(aGridTemplate.mRepeatAutoLineNameListBefore);
-      } else if (aIndex <= repeatAutoEnd && aIndex > repeatAutoStart) {
-        lineNames.AppendElements(aGridTemplate.mRepeatAutoLineNameListAfter);
-      } else if (aIndex <= repeatAutoStart) {
+      if (aIndex <= repeatAutoStart) {
         if (aIndex < lineNameLists.Length()) {
           lineNames.AppendElements(lineNameLists[aIndex]);
         }
         if (aIndex == repeatAutoEnd) {
           uint32_t i = aIndex + 1;
           if (i < lineNameLists.Length()) {
             lineNames.AppendElements(lineNameLists[i]);
           }
         }
-      } else if (aIndex >= repeatAutoEnd) {
+      }
+      if (aIndex <= repeatAutoEnd && aIndex > repeatAutoStart) {
+        lineNames.AppendElements(aGridTemplate.mRepeatAutoLineNameListAfter);
+      }
+      if (aIndex < repeatAutoEnd && aIndex >= repeatAutoStart) {
+        lineNames.AppendElements(aGridTemplate.mRepeatAutoLineNameListBefore);
+      }
+      if (aIndex >= repeatAutoEnd && aIndex > repeatAutoStart) {
         uint32_t i = aIndex - repeatEndDelta;
         if (i < lineNameLists.Length()) {
           lineNames.AppendElements(lineNameLists[i]);
         }
       }
     }
 
     return lineNames;
@@ -5790,17 +5793,18 @@ nsGridContainerFrame::Reflow(nsPresConte
     ComputedGridTrackInfo* colInfo = new ComputedGridTrackInfo(
       gridReflowInput.mColFunctions.mExplicitGridOffset,
       gridReflowInput.mColFunctions.NumExplicitTracks(),
       0,
       col,
       Move(colTrackPositions),
       Move(colTrackSizes),
       Move(colTrackStates),
-      Move(colRemovedRepeatTracks));
+      Move(colRemovedRepeatTracks),
+      gridReflowInput.mColFunctions.mRepeatAutoStart);
     Properties().Set(GridColTrackInfo(), colInfo);
 
     uint32_t rowTrackCount = gridReflowInput.mRows.mSizes.Length();
     nsTArray<nscoord> rowTrackPositions(rowTrackCount);
     nsTArray<nscoord> rowTrackSizes(rowTrackCount);
     nsTArray<uint32_t> rowTrackStates(rowTrackCount);
     nsTArray<bool> rowRemovedRepeatTracks(
       gridReflowInput.mRowFunctions.mRemovedRepeatTracks);
@@ -5824,17 +5828,18 @@ nsGridContainerFrame::Reflow(nsPresConte
     ComputedGridTrackInfo* rowInfo = new ComputedGridTrackInfo(
       gridReflowInput.mRowFunctions.mExplicitGridOffset,
       gridReflowInput.mRowFunctions.NumExplicitTracks(),
       gridReflowInput.mStartRow,
       row,
       Move(rowTrackPositions),
       Move(rowTrackSizes),
       Move(rowTrackStates),
-      Move(rowRemovedRepeatTracks));
+      Move(rowRemovedRepeatTracks),
+      gridReflowInput.mRowFunctions.mRepeatAutoStart);
     Properties().Set(GridRowTrackInfo(), rowInfo);
 
     if (prevInFlow) {
       // This frame is fragmenting rows from a previous frame, so patch up
       // the prior GridRowTrackInfo with a new end row.
 
       // FIXME: This can be streamlined and/or removed when bug 1151204 lands.
 
@@ -5854,59 +5859,66 @@ nsGridContainerFrame::Reflow(nsPresConte
       ComputedGridTrackInfo* revisedPriorRowInfo = new ComputedGridTrackInfo(
         priorRowInfo->mNumLeadingImplicitTracks,
         priorRowInfo->mNumExplicitTracks,
         priorRowInfo->mStartFragmentTrack,
         gridReflowInput.mStartRow,
         Move(priorRowInfo->mPositions),
         Move(priorRowInfo->mSizes),
         Move(priorRowInfo->mStates),
-        Move(priorRowInfo->mRemovedRepeatTracks));
+        Move(priorRowInfo->mRemovedRepeatTracks),
+        priorRowInfo->mRepeatFirstTrack);
       prevInFlow->Properties().Set(GridRowTrackInfo(), revisedPriorRowInfo);
     }
 
     // Generate the line info properties. We need to provide the number of
     // repeat tracks produced in the reflow. Only explicit names are assigned
     // to lines here; the mozilla::dom::GridLines class will later extract
     // implicit names from grid areas and assign them to the appropriate lines.
 
     // Generate column lines first.
-    uint32_t capacity = gridReflowInput.mColFunctions.NumRepeatTracks() +
-                        gridReflowInput.mCols.mSizes.Length();
+    uint32_t capacity = gridReflowInput.mCols.mSizes.Length();
+    const nsStyleGridTemplate& gridColTemplate =
+      gridReflowInput.mGridStyle->mGridTemplateColumns;
     nsTArray<nsTArray<nsString>> columnLineNames(capacity);
     for (col = 0; col <= gridReflowInput.mCols.mSizes.Length(); col++) {
       // Offset col by the explicit grid offset, to get the original names.
       nsTArray<nsString> explicitNames =
         gridReflowInput.mCols.GetExplicitLineNamesAtIndex(
-          gridReflowInput.mGridStyle->mGridTemplateColumns,
+          gridColTemplate,
           gridReflowInput.mColFunctions,
           col - gridReflowInput.mColFunctions.mExplicitGridOffset);
 
       columnLineNames.AppendElement(explicitNames);
     }
     ComputedGridLineInfo* columnLineInfo = new ComputedGridLineInfo(
-      Move(columnLineNames));
+      Move(columnLineNames),
+      gridColTemplate.mRepeatAutoLineNameListBefore,
+      gridColTemplate.mRepeatAutoLineNameListAfter);
     Properties().Set(GridColumnLineInfo(), columnLineInfo);
 
     // Generate row lines next.
-    capacity = gridReflowInput.mRowFunctions.NumRepeatTracks() +
-               gridReflowInput.mRows.mSizes.Length();
+    capacity = gridReflowInput.mRows.mSizes.Length();
+    const nsStyleGridTemplate& gridRowTemplate =
+      gridReflowInput.mGridStyle->mGridTemplateRows;
     nsTArray<nsTArray<nsString>> rowLineNames(capacity);
     for (row = 0; row <= gridReflowInput.mRows.mSizes.Length(); row++) {
       // Offset row by the explicit grid offset, to get the original names.
       nsTArray<nsString> explicitNames =
         gridReflowInput.mRows.GetExplicitLineNamesAtIndex(
-          gridReflowInput.mGridStyle->mGridTemplateRows,
+          gridRowTemplate,
           gridReflowInput.mRowFunctions,
           row - gridReflowInput.mRowFunctions.mExplicitGridOffset);
 
       rowLineNames.AppendElement(explicitNames);
     }
     ComputedGridLineInfo* rowLineInfo = new ComputedGridLineInfo(
-      Move(rowLineNames));
+      Move(rowLineNames),
+      gridRowTemplate.mRepeatAutoLineNameListBefore,
+      gridRowTemplate.mRepeatAutoLineNameListAfter);
     Properties().Set(GridRowLineInfo(), rowLineInfo);
 
     // Generate area info for explicit areas. Implicit areas are handled
     // elsewhere.
     if (gridReflowInput.mGridStyle->mGridTemplateAreas) {
       nsTArray<css::GridNamedArea>* areas = new nsTArray<css::GridNamedArea>(
           gridReflowInput.mGridStyle->mGridTemplateAreas->mNamedAreas);
       Properties().Set(ExplicitNamedAreasProperty(), areas);
--- a/layout/generic/nsGridContainerFrame.h
+++ b/layout/generic/nsGridContainerFrame.h
@@ -30,42 +30,51 @@ struct ComputedGridTrackInfo
 {
   ComputedGridTrackInfo(uint32_t aNumLeadingImplicitTracks,
                         uint32_t aNumExplicitTracks,
                         uint32_t aStartFragmentTrack,
                         uint32_t aEndFragmentTrack,
                         nsTArray<nscoord>&& aPositions,
                         nsTArray<nscoord>&& aSizes,
                         nsTArray<uint32_t>&& aStates,
-                        nsTArray<bool>&& aRemovedRepeatTracks)
+                        nsTArray<bool>&& aRemovedRepeatTracks,
+                        uint32_t aRepeatFirstTrack)
     : mNumLeadingImplicitTracks(aNumLeadingImplicitTracks)
     , mNumExplicitTracks(aNumExplicitTracks)
     , mStartFragmentTrack(aStartFragmentTrack)
     , mEndFragmentTrack(aEndFragmentTrack)
     , mPositions(aPositions)
     , mSizes(aSizes)
     , mStates(aStates)
     , mRemovedRepeatTracks(aRemovedRepeatTracks)
+    , mRepeatFirstTrack(aRepeatFirstTrack)
   {}
   uint32_t mNumLeadingImplicitTracks;
   uint32_t mNumExplicitTracks;
   uint32_t mStartFragmentTrack;
   uint32_t mEndFragmentTrack;
   nsTArray<nscoord> mPositions;
   nsTArray<nscoord> mSizes;
   nsTArray<uint32_t> mStates;
   nsTArray<bool> mRemovedRepeatTracks;
+  uint32_t mRepeatFirstTrack;
 };
 
 struct ComputedGridLineInfo
 {
-  explicit ComputedGridLineInfo(nsTArray<nsTArray<nsString>>&& aNames)
+  explicit ComputedGridLineInfo(nsTArray<nsTArray<nsString>>&& aNames,
+                                const nsTArray<nsString>& aNamesBefore,
+                                const nsTArray<nsString>& aNamesAfter)
     : mNames(aNames)
+    , mNamesBefore(aNamesBefore)
+    , mNamesAfter(aNamesAfter)
   {}
   nsTArray<nsTArray<nsString>> mNames;
+  nsTArray<nsString> mNamesBefore;
+  nsTArray<nsString> mNamesAfter;
 };
 } // namespace mozilla
 
 class nsGridContainerFrame final : public nsContainerFrame
 {
 public:
   NS_DECL_FRAMEARENA_HELPERS
   NS_DECL_QUERYFRAME_TARGET(nsGridContainerFrame)