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
--- 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);
}