Bug 1459937 - In DEBUG mode, verify that reparenting direction is correct - r=dbaron draft
authorGerald Squelart <gsquelart@mozilla.com>
Tue, 10 Jul 2018 15:35:48 +1000
changeset 820202 f56a9a4a666fc61e69ba537a69e3161b58083d02
parent 820201 ec99f380c978c6d28135490401beb0bb54c8e2b3
push id116747
push usergsquelart@mozilla.com
push dateThu, 19 Jul 2018 05:17:20 +0000
reviewersdbaron
bugs1459937
milestone63.0a1
Bug 1459937 - In DEBUG mode, verify that reparenting direction is correct - r=dbaron MozReview-Commit-ID: JPfg9YtBm6M
layout/generic/nsBlockFrame.cpp
--- a/layout/generic/nsBlockFrame.cpp
+++ b/layout/generic/nsBlockFrame.cpp
@@ -618,44 +618,70 @@ ReparentFrameInternal(nsIFrame* aFrame, 
   }
 
   // When pushing and pulling frames we need to check for whether any
   // views need to be reparented
   nsContainerFrame::ReparentFrameView(aFrame, aOldParent, aNewParent);
 }
 
 static bool
-ShouldMarkReparentedFramesDirty(nsIFrame* aNewParent,
-                                ReparentingDirection aDirection)
-{
+ShouldMarkReparentedFramesDirty(
+#ifdef DEBUG
+                         nsContainerFrame* aOldParent,
+#endif
+                         nsIFrame* aNewParent,
+                         ReparentingDirection aDirection)
+{
+#ifdef DEBUG
+  MOZ_ASSERT(aOldParent->FirstInFlow() == aNewParent->FirstInFlow(),
+             "Reparenting should be between continuations of the same frame");
+  if (aDirection != ReparentingDirection::Variable &&
+      aOldParent->FirstInFlow() == aNewParent->FirstInFlow()) {
+    auto IndexInFlow =
+      [](const nsIFrame* f) {
+        int i = 0; while ((f = f->GetPrevInFlow())) { ++i; } return i;
+      };
+    MOZ_ASSERT((IndexInFlow(aOldParent) < IndexInFlow(aNewParent)) ==
+               (aDirection == ReparentingDirection::Forwards),
+               "Parents not in expected order");
+  }
+#endif
   // Frames going forward must have already been reflowed, or at least marked
   // dirty. Otherwise frames going backwards (or direction is unknown) may not
   // be marked dirty yet.
   return (aDirection != ReparentingDirection::Forwards) &&
          (aNewParent->GetStateBits() & NS_FRAME_IS_DIRTY);
 }
 
 // Because a frame with NS_FRAME_IS_DIRTY marks all of its children dirty at
 // the start of its reflow, when we move a frame from a later frame backwards to
 // an earlier frame, and the earlier frame has NS_FRAME_IS_DIRTY (though that
 // should corresponded with the later frame having NS_FRAME_IS_DIRTY), we need
 // to add NS_FRAME_IS_DIRTY to the reparented frame.
 static void
 ReparentFrame(nsIFrame* aFrame, nsContainerFrame* aOldParent,
               nsContainerFrame* aNewParent, ReparentingDirection aDirection)
 {
-  const bool markDirty = ShouldMarkReparentedFramesDirty(aNewParent, aDirection);
+  const bool markDirty = ShouldMarkReparentedFramesDirty(
+#ifdef DEBUG
+                                                         aOldParent,
+#endif
+                                                         aNewParent, aDirection);
   ReparentFrameInternal(aFrame, aOldParent, aNewParent, markDirty);
 }
 
 static void
 ReparentFrames(nsFrameList& aFrameList, nsContainerFrame* aOldParent,
                nsContainerFrame* aNewParent, ReparentingDirection aDirection)
 {
-  const bool markDirty = ShouldMarkReparentedFramesDirty(aNewParent, aDirection);
+  const bool markDirty = ShouldMarkReparentedFramesDirty(
+#ifdef DEBUG
+                                                         aOldParent,
+#endif
+                                                         aNewParent, aDirection);
   for (nsFrameList::Enumerator e(aFrameList); !e.AtEnd(); e.Next()) {
     ReparentFrameInternal(e.get(), aOldParent, aNewParent, markDirty);
   }
 }
 
 /**
  * Remove the first line from aFromLines and adjust the associated frame list
  * aFromFrames accordingly.  The removed line is assigned to *aOutLine and