Bug 1459937 - Mark pulled floats (from pulled lines) dirty - r=dbaron draft
authorGerald Squelart <gsquelart@mozilla.com>
Tue, 10 Jul 2018 11:36:33 +1000
changeset 820201 ec99f380c978c6d28135490401beb0bb54c8e2b3
parent 820200 ee55a9ae7408e1f2603c1b2bc80ddcd8dbc837f0
child 820202 f56a9a4a666fc61e69ba537a69e3161b58083d02
push id116747
push usergsquelart@mozilla.com
push dateThu, 19 Jul 2018 05:17:20 +0000
reviewersdbaron
bugs1459937
milestone63.0a1
Bug 1459937 - Mark pulled floats (from pulled lines) dirty - r=dbaron Similar to lines (see previous patch), floats from next-in-flow or overflow frames have probably not been marked dirty (as ReflowInput hasn't dealt with them when it was constructed), so we need to mark them dirty for proper reflow. If we don't do that, and they don't fit in the current column, the next column will only mark its current children dirty, so when pulling back its first floats from the previous column they will not be reflowed as needed. MozReview-Commit-ID: KKrwtzeQMrI
layout/generic/nsBlockFrame.cpp
layout/generic/nsBlockFrame.h
layout/generic/nsContainerFrame.cpp
layout/generic/nsContainerFrame.h
layout/generic/nsInlineFrame.cpp
layout/generic/nsRubyBaseContainerFrame.cpp
layout/generic/nsRubyFrame.cpp
--- a/layout/generic/nsBlockFrame.cpp
+++ b/layout/generic/nsBlockFrame.cpp
@@ -2146,25 +2146,26 @@ static bool LineHasClear(nsLineBox* aLin
 
 /**
  * Reparent a whole list of floats from aOldParent to this block.  The
  * floats might be taken from aOldParent's overflow list. They will be
  * removed from the list. They end up appended to our mFloats list.
  */
 void
 nsBlockFrame::ReparentFloats(nsIFrame* aFirstFrame, nsBlockFrame* aOldParent,
-                             bool aReparentSiblings) {
+                             bool aReparentSiblings,
+                             ReparentingDirection aDirection)
+{
   nsFrameList list;
   aOldParent->CollectFloats(aFirstFrame, list, aReparentSiblings);
   if (list.NotEmpty()) {
     for (nsIFrame* f : list) {
       MOZ_ASSERT(!(f->GetStateBits() & NS_FRAME_IS_PUSHED_FLOAT),
                  "CollectFloats should've removed that bit");
-      // XXX: "Backwards" to force NS_FRAME_IS_DIRTY for now, see next patch.
-      ReparentFrame(f, aOldParent, this, ReparentingDirection::Backwards);
+      ReparentFrame(f, aOldParent, this, aDirection);
     }
     mFloats.AppendFrames(nullptr, list);
   }
 }
 
 static void DumpLine(const BlockReflowInput& aState, nsLineBox* aLine,
                      nscoord aDeltaBCoord, int32_t aDeltaIndent) {
 #ifdef DEBUG
@@ -2668,17 +2669,18 @@ nsBlockFrame::ReflowDirtyLines(BlockRefl
       // Shift pulledLine's frames into our mFrames list.
       mFrames.AppendFrames(nullptr, pulledFrames);
 
       // Add line to our line list, and set its last child as our new prev-child
       line = mLines.before_insert(LinesEnd(), pulledLine);
       aState.mPrevChild = mFrames.LastChild();
 
       // Reparent floats whose placeholders are in the line.
-      ReparentFloats(pulledLine->mFirstChild, nextInFlow, true);
+      ReparentFloats(pulledLine->mFirstChild, nextInFlow, true,
+                     ReparentingDirection::Backwards);
 
       DumpLine(aState, pulledLine, deltaBCoord, 0);
 #ifdef DEBUG
       AutoNoisyIndenter indent2(gNoisyReflow);
 #endif
 
       if (aState.mPresContext->HasPendingInterrupt()) {
         MarkLineDirtyForInterrupt(line);
@@ -2952,17 +2954,18 @@ nsBlockFrame::PullFrameFrom(nsLineBox*  
 
     // When pushing and pulling frames we need to check for whether any
     // views need to be reparented.
     ReparentFrame(frame, aFromContainer, this, ReparentingDirection::Backwards);
     mFrames.AppendFrame(nullptr, frame);
 
     // The frame might have (or contain) floats that need to be brought
     // over too. (pass 'false' since there are no siblings to check)
-    ReparentFloats(frame, aFromContainer, false);
+    ReparentFloats(frame, aFromContainer, false,
+                   ReparentingDirection::Backwards);
   } else {
     MOZ_ASSERT(aLine == aFromLine.prev());
   }
 
   aLine->NoteFrameAdded(frame);
   fromLine->NoteFrameRemoved(frame);
 
   if (fromLine->GetChildCount() > 0) {
--- a/layout/generic/nsBlockFrame.h
+++ b/layout/generic/nsBlockFrame.h
@@ -535,17 +535,17 @@ public:
   };
   void DoRemoveFrame(nsIFrame* aDeletedFrame, uint32_t aFlags)
   {
     AutoPostDestroyData data(PresContext());
     DoRemoveFrameInternal(aDeletedFrame, aFlags, data.mData);
   }
 
   void ReparentFloats(nsIFrame* aFirstFrame, nsBlockFrame* aOldParent,
-                      bool aReparentSiblings);
+                      bool aReparentSiblings, ReparentingDirection aDirection);
 
   virtual bool ComputeCustomOverflow(nsOverflowAreas& aOverflowAreas) override;
 
   virtual void UnionChildOverflow(nsOverflowAreas& aOverflowAreas) override;
 
   /** Load all of aFrame's floats into the float manager iff aFrame is not a
    *  block formatting context. Handles all necessary float manager translations;
    *  assumes float manager is in aFrame's parent's coord system.
--- a/layout/generic/nsContainerFrame.cpp
+++ b/layout/generic/nsContainerFrame.cpp
@@ -1590,17 +1590,18 @@ nsContainerFrame::MoveInlineOverflowToCh
   if (auto prevInFlow = static_cast<nsContainerFrame*>(GetPrevInFlow())) {
     AutoFrameListPtr prevOverflowFrames(PresContext(),
                                         prevInFlow->StealOverflowFrames());
     if (prevOverflowFrames) {
       // We may need to reparent floats from prev-in-flow to our line
       // container if the container has prev continuation.
       if (aLineContainer->GetPrevContinuation()) {
         ReparentFloatsForInlineChild(aLineContainer,
-                                     prevOverflowFrames->FirstChild(), true);
+                                     prevOverflowFrames->FirstChild(), true,
+                                     ReparentingDirection::Forwards);
       }
       // When pushing and pulling frames we need to check for whether
       // any views need to be reparented.
       nsContainerFrame::ReparentFrameViewList(*prevOverflowFrames,
                                               prevInFlow, this);
       // Prepend overflow frames to the list.
       mFrames.InsertFrames(this, nullptr, *prevOverflowFrames);
       result = true;
@@ -1743,17 +1744,18 @@ nsContainerFrame::PullNextInFlowChild(Co
     nsContainerFrame::ReparentFrameView(frame, nextInFlow, this);
   }
   return frame;
 }
 
 /* static */ void
 nsContainerFrame::ReparentFloatsForInlineChild(nsIFrame* aOurLineContainer,
                                                nsIFrame* aFrame,
-                                               bool aReparentSiblings)
+                                               bool aReparentSiblings,
+                                               ReparentingDirection aDirection)
 {
   // XXXbz this would be better if it took a nsFrameList or a frame
   // list slice....
   NS_ASSERTION(aOurLineContainer->GetNextContinuation() ||
                aOurLineContainer->GetPrevContinuation(),
                "Don't call this when we have no continuation, it's a waste");
   if (!aFrame) {
     NS_ASSERTION(aReparentSiblings, "Why did we get called?");
@@ -1764,32 +1766,33 @@ nsContainerFrame::ReparentFloatsForInlin
   if (!frameBlock || frameBlock == aOurLineContainer) {
     return;
   }
 
   nsBlockFrame* ourBlock = nsLayoutUtils::GetAsBlock(aOurLineContainer);
   NS_ASSERTION(ourBlock, "Not a block, but broke vertically?");
 
   while (true) {
-    ourBlock->ReparentFloats(aFrame, frameBlock, false);
+    ourBlock->ReparentFloats(aFrame, frameBlock, false, aDirection);
 
     if (!aReparentSiblings)
       return;
     nsIFrame* next = aFrame->GetNextSibling();
     if (!next)
       return;
     if (next->GetParent() == aFrame->GetParent()) {
       aFrame = next;
       continue;
     }
     // This is paranoid and will hardly ever get hit ... but we can't actually
     // trust that the frames in the sibling chain all have the same parent,
     // because lazy reparenting may be going on. If we find a different
     // parent we need to redo our analysis.
-    ReparentFloatsForInlineChild(aOurLineContainer, next, aReparentSiblings);
+    ReparentFloatsForInlineChild(aOurLineContainer, next, aReparentSiblings,
+                                 aDirection);
     return;
   }
 }
 
 bool
 nsContainerFrame::ResolvedOrientationIsVertical()
 {
   StyleOrient orient = StyleDisplay()->mOrient;
--- a/layout/generic/nsContainerFrame.h
+++ b/layout/generic/nsContainerFrame.h
@@ -669,17 +669,18 @@ protected:
   /**
    * Reparent floats whose placeholders are inline descendants of aFrame from
    * whatever block they're currently parented by to aOurBlock.
    * @param aReparentSiblings if this is true, we follow aFrame's
    * GetNextSibling chain reparenting them all
    */
   static void ReparentFloatsForInlineChild(nsIFrame* aOurBlock,
                                            nsIFrame* aFrame,
-                                           bool aReparentSiblings);
+                                           bool aReparentSiblings,
+                                           ReparentingDirection aDirection);
 
   // ==========================================================================
   /*
    * Convenience methods for traversing continuations
    */
 
   struct ContinuationTraversingState
   {
--- a/layout/generic/nsInlineFrame.cpp
+++ b/layout/generic/nsInlineFrame.cpp
@@ -801,17 +801,18 @@ nsInlineFrame::PullOneFrame(nsPresContex
     if (frame) {
       // If our block has no next continuation, then any floats belonging to
       // the pulled frame must belong to our block already. This check ensures
       // we do no extra work in the common non-vertical-breaking case.
       if (irs.mLineContainer && irs.mLineContainer->GetNextContinuation()) {
         // The blockChildren.ContainsFrame check performed by
         // ReparentFloatsForInlineChild will be fast because frame's ancestor
         // will be the first child of its containing block.
-        ReparentFloatsForInlineChild(irs.mLineContainer, frame, false);
+        ReparentFloatsForInlineChild(irs.mLineContainer, frame, false,
+                                     ReparentingDirection::Backwards);
       }
       nextInFlow->mFrames.RemoveFirstChild();
       // nsFirstLineFrame::PullOneFrame calls ReparentComputedStyle.
 
       mFrames.InsertFrame(this, irs.mPrevFrame, frame);
       isComplete = false;
       if (irs.mLineLayout) {
         irs.mLineLayout->SetDirtyNextLine();
--- a/layout/generic/nsRubyBaseContainerFrame.cpp
+++ b/layout/generic/nsRubyBaseContainerFrame.cpp
@@ -779,17 +779,18 @@ nsRubyBaseContainerFrame::PullOneColumn(
                  "the same old float containing block");
     }
 #endif
     nsBlockFrame* newFloatCB =
       nsLayoutUtils::GetAsBlock(aLineLayout->LineContainerFrame());
     MOZ_ASSERT(newFloatCB, "Must have a float containing block");
     if (oldFloatCB != newFloatCB) {
       for (nsIFrame* frame : aColumn) {
-        newFloatCB->ReparentFloats(frame, oldFloatCB, false);
+        newFloatCB->ReparentFloats(frame, oldFloatCB, false,
+                                   ReparentingDirection::Backwards);
       }
     }
   }
 
   // Pull the frames of this column.
   if (aColumn.mBaseFrame) {
     DebugOnly<nsIFrame*> pulled = PullNextInFlowChild(aPullFrameState.mBase);
     MOZ_ASSERT(pulled == aColumn.mBaseFrame, "pulled a wrong frame?");
--- a/layout/generic/nsRubyFrame.cpp
+++ b/layout/generic/nsRubyFrame.cpp
@@ -416,14 +416,15 @@ nsRubyFrame::PullOneSegment(const nsLine
   while ((nextFrame = GetNextInFlowChild(aState)) != nullptr &&
          nextFrame->IsRubyTextContainerFrame()) {
     PullNextInFlowChild(aState);
   }
 
   if (nsBlockFrame* newFloatCB =
       nsLayoutUtils::GetAsBlock(aLineLayout->LineContainerFrame())) {
     if (oldFloatCB && oldFloatCB != newFloatCB) {
-      newFloatCB->ReparentFloats(baseFrame, oldFloatCB, true);
+      newFloatCB->ReparentFloats(baseFrame, oldFloatCB, true,
+                                 ReparentingDirection::Backwards);
     }
   }
 
   return static_cast<nsRubyBaseContainerFrame*>(baseFrame);
 }