Bug 588237, patch 4: Pull pushed floats back from the next-in-flow at the start of reflow. r=roc

This commit is contained in:
L. David Baron 2013-01-10 21:14:51 -08:00
Родитель a3a9087561
Коммит a859764e31
4 изменённых файлов: 78 добавлений и 9 удалений

Просмотреть файл

@ -1464,9 +1464,9 @@ private:
*/
public:
nsIFrame* GetAbsoluteContainingBlock(nsIFrame* aFrame);
private:
nsIFrame* GetFloatContainingBlock(nsIFrame* aFrame);
private:
nsIContent* PropagateScrollToViewport();
// Build a scroll frame:

Просмотреть файл

@ -4427,6 +4427,27 @@ nsBlockFrame::DrainSelfOverflowList()
return true;
}
/**
* Pushed floats are floats whose placeholders are in a previous
* continuation. They might themselves be next-continuations of a float
* that partially fit in an earlier continuation, or they might be the
* first continuation of a float that couldn't be placed at all.
*
* Pushed floats live permanently at the beginning of a block's float
* list, where they must live *before* any floats whose placeholders are
* in that block.
*
* Temporarily, during reflow, they also live on the pushed floats list,
* which only holds them between (a) when one continuation pushes them to
* its pushed floats list because they don't fit and (b) when the next
* continuation pulls them onto the beginning of its float list.
*
* DrainPushedFloats sets up pushed floats the way we need them at the
* start of reflow; they are then reflowed by ReflowPushedFloats (which
* might push some of them on). Floats with placeholders in this block
* are reflowed by (nsBlockReflowState/nsLineLayout)::AddFloat, which
* also maintains these invariants.
*/
void
nsBlockFrame::DrainPushedFloats(nsBlockReflowState& aState)
{
@ -4439,11 +4460,51 @@ nsBlockFrame::DrainPushedFloats(nsBlockReflowState& aState)
nsLayoutUtils::AssertNoDuplicateContinuations(this, mFloats);
#endif
// If we're getting reflowed multiple times without our
// next-continuation being reflowed, we might need to pull back floats
// that we just put in the list to be pushed to our next-in-flow.
// But we can't pull any next-in-flows of floats on our own float list.
nsFrameList *ourPushedFloats = GetPushedFloats();
if (ourPushedFloats) {
// When we pull back floats, we want to put them with the pushed
// floats, which must live at the start of our float list, but we
// want them at the end of those pushed floats.
nsIFrame *insertionPrevSibling = nullptr; /* beginning of list */
for (nsIFrame* f = mFloats.FirstChild();
f && (f->GetStateBits() & NS_FRAME_IS_PUSHED_FLOAT);
f = f->GetNextSibling()) {
insertionPrevSibling = f;
}
nsPresContext *presContext = PresContext();
for (nsIFrame *f = ourPushedFloats->LastChild(), *next; f; f = next) {
next = f->GetPrevSibling();
if (!f->GetPrevContinuation()) {
nsPlaceholderFrame *placeholder =
presContext->FrameManager()->GetPlaceholderFrameFor(f);
nsIFrame *floatOriginalParent = presContext->PresShell()->
FrameConstructor()->GetFloatContainingBlock(placeholder);
if (floatOriginalParent != this) {
// This is a first continuation that was pushed from one of our
// previous continuations. Take it out of the pushed floats
// list and put it in our floats list, before any of our
// floats, but after other pushed floats.
ourPushedFloats->RemoveFrame(f);
mFloats.InsertFrame(nullptr, insertionPrevSibling, f);
}
}
}
if (ourPushedFloats->IsEmpty()) {
delete RemovePushedFloats();
}
}
// After our prev-in-flow has completed reflow, it may have a pushed
// floats list, containing floats that we need to own. Take these.
nsBlockFrame* prevBlock = static_cast<nsBlockFrame*>(GetPrevInFlow());
if (!prevBlock)
return;
if (prevBlock) {
nsFrameList *list = prevBlock->RemovePushedFloats();
if (list) {
if (list->NotEmpty()) {
@ -4452,6 +4513,7 @@ nsBlockFrame::DrainPushedFloats(nsBlockReflowState& aState)
delete list;
}
}
}
nsBlockFrame::FrameLines*
nsBlockFrame::GetOverflowLines() const
@ -5851,6 +5913,8 @@ nsBlockFrame::ReflowPushedFloats(nsBlockReflowState& aState,
nsReflowStatus& aStatus)
{
nsresult rv = NS_OK;
// Pushed floats live at the start of our float list; see comment
// above nsBlockFrame::DrainPushedFloats.
for (nsIFrame* f = mFloats.FirstChild(), *next;
f && (f->GetStateBits() & NS_FRAME_IS_PUSHED_FLOAT);
f = next) {

Просмотреть файл

@ -783,7 +783,9 @@ protected:
return 0 != (GetStateBits() & NS_BLOCK_HAS_PUSHED_FLOATS);
}
// Get the pushed floats list
// Get the pushed floats list, which is used for *temporary* storage
// of floats during reflow, between when we decide they don't fit in
// this block until our next continuation takes them.
nsFrameList* GetPushedFloats() const;
// Get the pushed floats list, or if there is not currently one,
// make a new empty one.

Просмотреть файл

@ -465,6 +465,9 @@ nsBlockReflowState::AddFloat(nsLineLayout* aLineLayout,
// push it again, though.) Likewise, if that previous reflow
// reflowed this block but not its next continuation, we might need
// to steal it from our own float-continuations list.
//
// For more about pushed floats, see the comment above
// nsBlockFrame::DrainPushedFloats.
nsBlockFrame *floatParent =
static_cast<nsBlockFrame*>(aFloat->GetParent());
floatParent->StealFrame(mPresContext, aFloat);