Bug 1489153 - Push any child next-in-flows in our principal list to OverflowList before starting our reflow. r=dholbert
authorMats Palmgren <mats@mozilla.com>
Tue, 11 Sep 2018 20:07:28 +0200
changeset 435753 1719e0b4140df4657af0c05d18665f0af0f3e6dd
parent 435752 a8de31323a3b52d7f4d6abd9405ba64e2227a653
child 435754 21fc8a773b280d0abc62661591b0440e260e078a
push id107718
push usermpalmgren@mozilla.com
push dateTue, 11 Sep 2018 18:07:45 +0000
treeherdermozilla-inbound@21fc8a773b28 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdholbert
bugs1489153
milestone64.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 1489153 - Push any child next-in-flows in our principal list to OverflowList before starting our reflow. r=dholbert
layout/generic/nsFrameStateBits.h
layout/generic/nsGridContainerFrame.cpp
--- a/layout/generic/nsFrameStateBits.h
+++ b/layout/generic/nsFrameStateBits.h
@@ -351,16 +351,19 @@ FRAME_STATE_BIT(GridContainer, 24, NS_ST
 FRAME_STATE_BIT(GridContainer, 25, NS_STATE_GRID_IS_ROW_SUBGRID)
 
 // The container contains one or more items subgridded in its inline axis.
 FRAME_STATE_BIT(GridContainer, 26, NS_STATE_GRID_HAS_COL_SUBGRID_ITEM)
 
 // The container contains one or more items subgridded in its block axis.
 FRAME_STATE_BIT(GridContainer, 27, NS_STATE_GRID_HAS_ROW_SUBGRID_ITEM)
 
+// We've merged some OverflowList children since last reflow.
+FRAME_STATE_BIT(GridContainer, 28, NS_STATE_GRID_HAS_CHILD_NIFS)
+
 // == Frame state bits that apply to SVG frames ===============================
 
 FRAME_STATE_GROUP(SVG, nsSVGDisplayableFrame)
 FRAME_STATE_GROUP(SVG, nsSVGContainerFrame)
 
 FRAME_STATE_BIT(SVG, 20, NS_STATE_IS_OUTER_SVG)
 
 // If this bit is set, we are a <clipPath> element or descendant.
--- a/layout/generic/nsGridContainerFrame.cpp
+++ b/layout/generic/nsGridContainerFrame.cpp
@@ -3599,17 +3599,18 @@ MeasuringReflow(nsIFrame*           aChi
   // FIXME (perf): It would be faster to do this only if the previous
   // reflow of the child was not a measuring reflow, and only if the
   // child does some of the things that are affected by
   // ReflowInput::COMPUTE_SIZE_USE_AUTO_BSIZE.
   childRI.SetBResize(true);
 
   ReflowOutput childSize(childRI);
   nsReflowStatus childStatus;
-  const uint32_t flags = NS_FRAME_NO_MOVE_FRAME | NS_FRAME_NO_SIZE_VIEW;
+  const uint32_t flags = NS_FRAME_NO_MOVE_FRAME | NS_FRAME_NO_SIZE_VIEW |
+                         NS_FRAME_NO_DELETE_NEXT_IN_FLOW_CHILD;
   parent->ReflowChild(aChild, pc, childSize, childRI, wm,
                       LogicalPoint(wm), nsSize(), flags, childStatus);
   nsContainerFrame::FinishReflowChild(aChild, pc, childSize, &childRI, wm,
                             LogicalPoint(wm), nsSize(), flags);
 #ifdef DEBUG
     parent->DeleteProperty(nsContainerFrame::DebugReflowingWithInfiniteISize());
 #endif
   return childSize.BSize(wm);
@@ -5876,16 +5877,41 @@ nsGridContainerFrame::Reflow(nsPresConte
       }
       ::MergeSortedFrameLists(mFrames, items, GetContent());
       if (ourOverflow->IsEmpty()) {
         DestroyOverflowList();
       }
     }
   }
 
+  // Push any child next-in-flows in our principal list to OverflowList.
+  if (HasAnyStateBits(NS_STATE_GRID_HAS_CHILD_NIFS)) {
+    nsFrameList framesToPush;
+    nsIFrame* firstChild = mFrames.FirstChild();
+    // Note that we potentially modify our mFrames list as we go.
+    for (auto child = firstChild; child; child = child->GetNextSibling()) {
+      if (auto* childNIF = child->GetNextInFlow()) {
+        if (childNIF->GetParent() == this) {
+          for (auto c = child->GetNextSibling(); c; c = c->GetNextSibling()) {
+            if (c == childNIF) {
+              // child's next-in-flow is in our principal child list, push it.
+              mFrames.RemoveFrame(childNIF);
+              framesToPush.AppendFrame(nullptr, childNIF);
+              break;
+            }
+          }
+        }
+      }
+    }
+    if (!framesToPush.IsEmpty()) {
+      MergeSortedOverflow(framesToPush);
+    }
+    RemoveStateBits(NS_STATE_GRID_HAS_CHILD_NIFS);
+  }
+
   // Pull up any first-in-flow children we might have pushed.
   if (HasAnyStateBits(NS_STATE_GRID_DID_PUSH_ITEMS)) {
     RemoveStateBits(NS_STATE_GRID_DID_PUSH_ITEMS);
     nsFrameList items;
     auto nif = static_cast<nsGridContainerFrame*>(GetNextInFlow());
     auto firstNIF = nif;
     DebugOnly<bool> nifNeedPushedItem = false;
     while (nif) {
@@ -6541,20 +6567,24 @@ nsGridContainerFrame::BuildDisplayList(n
   }
 }
 
 bool
 nsGridContainerFrame::DrainSelfOverflowList()
 {
   // Unlike nsContainerFrame::DrainSelfOverflowList we need to merge these lists
   // so that the resulting mFrames is in document content order.
-  // NOTE: nsContainerFrame::AppendFrames/InsertFrames calls this method.
+  // NOTE: nsContainerFrame::AppendFrames/InsertFrames calls this method and
+  // there are also direct calls from the fctor (FindAppendPrevSibling).
   AutoFrameListPtr overflowFrames(PresContext(), StealOverflowFrames());
   if (overflowFrames) {
     ::MergeSortedFrameLists(mFrames, *overflowFrames, GetContent());
+    // We set a frame bit to push them again in Reflow() to avoid creating
+    // multiple grid items per grid container fragment for the same content.
+    AddStateBits(NS_STATE_GRID_HAS_CHILD_NIFS);
     return true;
   }
   return false;
 }
 
 void
 nsGridContainerFrame::AppendFrames(ChildListID aListID, nsFrameList& aFrameList)
 {