Bug 492627 - Remove Placeholder Continuations [Part V: Reimplement float splitting without placeholder continuations] r=roc

This commit is contained in:
fantasai 2009-08-31 11:25:36 -07:00
Родитель d78db610d2
Коммит 609baa9a48
13 изменённых файлов: 349 добавлений и 183 удалений

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

@ -1645,6 +1645,7 @@ GK_ATOM(boxMetricsProperty, "BoxMetricsProperty") // nsBoxLayoutMetrics*
GK_ATOM(changeListProperty, "ChangeListProperty") // void*
GK_ATOM(collapseOffsetProperty, "CollapseOffsetProperty") // nsPoint*
GK_ATOM(computedOffsetProperty, "ComputedOffsetProperty") // nsPoint*
GK_ATOM(floatContinuationProperty, "FloatContinuationProperty") // nsFrameList*
GK_ATOM(floatRegionProperty, "FloatRegionProperty") // nsRect*
GK_ATOM(generatedContent, "GeneratedContentProperty") // nsCOMArray<nsIContent>*
#ifdef MOZ_MATHML
@ -1663,7 +1664,6 @@ GK_ATOM(overflowContainersProperty, "OverflowContainersProperty") //
GK_ATOM(excessOverflowContainersProperty, "ExcessOverflowContainersProperty") // nsFrameList*
GK_ATOM(overflowLinesProperty, "OverflowLinesProperty") // list of nsLineBox*
GK_ATOM(overflowOutOfFlowsProperty, "OverflowOutOfFlowsProperty") // nsFrameList*
GK_ATOM(overflowPlaceholdersProperty, "OverflowPlaceholdersProperty") // nsFrameList*
GK_ATOM(preEffectsBBoxProperty, "PreEffectsBBoxProperty") // nsRect*
GK_ATOM(preTransformBBoxProperty, "PreTransformBBoxProperty") // nsRect*
GK_ATOM(rowUnpaginatedHeightProperty, "RowUnpaginatedHeightProperty") // nscoord*

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

@ -1574,7 +1574,7 @@ nsLayoutUtils::GetParentOrPlaceholderFor(nsFrameManager* aFrameManager,
nsIFrame* aFrame)
{
if ((aFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW)
&& !(aFrame->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER)) {
&& !aFrame->GetPrevInFlow()) {
return aFrameManager->GetPlaceholderFrameFor(aFrame);
}
return aFrame->GetParent();

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

@ -936,11 +936,10 @@ nsBlockFrame::Reflow(nsPresContext* aPresContext,
// Handle paginated overflow (see nsContainerFrame.h)
// Note: We use a temporary reflow status, which we'll merge into the state's
// reflow status down below.
nsRect overflowContainerBounds;
nsRect ocBounds;
nsReflowStatus ocStatus = NS_FRAME_COMPLETE;
if (GetPrevInFlow()) {
ReflowOverflowContainerChildren(aPresContext, aReflowState,
overflowContainerBounds, 0,
ReflowOverflowContainerChildren(aPresContext, aReflowState, ocBounds, 0,
ocStatus);
}
@ -964,7 +963,13 @@ nsBlockFrame::Reflow(nsPresContext* aPresContext,
// overflow lines hanging around; block reflow depends on the
// overflow line lists being cleared out between reflow passes.
DrainOverflowLines(state);
state.SetupOverflowPlaceholdersProperty();
DrainFloatContinuations(state);
// Handle float continuations
nsRect fcBounds;
nsReflowStatus fcStatus = NS_FRAME_COMPLETE;
rv = ReflowFloatContinuations(state, fcBounds, fcStatus);
NS_ENSURE_SUCCESS(rv, rv);
// If we're not dirty (which means we'll mark everything dirty later)
// and our width has changed, mark the lines dirty that we need to
@ -980,10 +985,11 @@ nsBlockFrame::Reflow(nsPresContext* aPresContext,
if (NS_FAILED(rv)) return rv;
NS_MergeReflowStatusInto(&state.mReflowStatus, ocStatus);
NS_MergeReflowStatusInto(&state.mReflowStatus, fcStatus);
// If the block is complete put continued floats at the beginning
// of the first overflow line.
NS_ASSERTION(state.mOverflowPlaceholders.IsEmpty(), "Where are these coming from? XXXfr");
// Put continued floats at the end of mFloats
if (state.mFloatContinuations.NotEmpty())
mFloats.AppendFrames(nsnull, state.mFloatContinuations);
if (!NS_FRAME_IS_FULLY_COMPLETE(state.mReflowStatus)) {
if (GetOverflowLines()) {
@ -1042,8 +1048,9 @@ nsBlockFrame::Reflow(nsPresContext* aPresContext,
ComputeFinalSize(aReflowState, state, aMetrics, &bottomEdgeOfChildren);
ComputeCombinedArea(aReflowState, aMetrics, bottomEdgeOfChildren);
// Factor overflow container child bounds into the overflow area
aMetrics.mOverflowArea.UnionRect(aMetrics.mOverflowArea,
overflowContainerBounds);
aMetrics.mOverflowArea.UnionRect(aMetrics.mOverflowArea, ocBounds);
// Factor float continuation child bounds into the overflow area
aMetrics.mOverflowArea.UnionRect(aMetrics.mOverflowArea, fcBounds);
// Let the absolutely positioned container reflow any absolutely positioned
// child frames that need to be reflowed, e.g., elements with a percentage
@ -3783,15 +3790,19 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
*aLineReflowStatus = LINE_REFLOW_TRUNCATED;
}
if (NS_FRAME_IS_NOT_COMPLETE(frameReflowStatus)) {
if (!NS_FRAME_IS_FULLY_COMPLETE(frameReflowStatus)) {
// Create a continuation for the incomplete frame. Note that the
// frame may already have a continuation.
nsIAtom* frameType = aFrame->GetType();
PRBool madeContinuation;
if (nsGkAtoms::placeholderFrame == frameType)
NS_ASSERTION(0, "float splitting unimplemented"); //XXXfr SplitFloat(aState, aPlaceholder)
rv = CreateContinuationFor(aState, aLine, aFrame, madeContinuation);
if (nsGkAtoms::placeholderFrame == frameType) {
nsPlaceholderFrame* placeholder = static_cast<nsPlaceholderFrame*>(aFrame);
rv = SplitFloat(aState, placeholder->GetOutOfFlowFrame(), frameReflowStatus);
}
else {
rv = CreateContinuationFor(aState, aLine, aFrame, madeContinuation);
}
NS_ENSURE_SUCCESS(rv, rv);
// Remember that the line has wrapped
@ -3848,13 +3859,20 @@ nsBlockFrame::CreateContinuationFor(nsBlockReflowState& aState,
}
nsresult
nsBlockFrame::SplitPlaceholder(nsBlockReflowState& aState,
nsIFrame* aPlaceholder)
nsBlockFrame::SplitFloat(nsBlockReflowState& aState,
nsIFrame* aFloat,
nsReflowStatus aFloatStatus)
{
NS_PRECONDITION(0,"Unexpected call to SplitPlaceholder, replace with SplitFloat XXXfr");
nsIFrame* nextInFlow;
nsresult rv = CreateNextInFlow(aState.mPresContext, this, aPlaceholder, nextInFlow);
nsresult rv = CreateNextInFlow(aState.mPresContext, this, aFloat, nextInFlow);
NS_ENSURE_SUCCESS(rv, rv);
if (NS_FRAME_OVERFLOW_IS_INCOMPLETE(aFloatStatus))
aFloat->GetNextInFlow()->AddStateBits(NS_FRAME_IS_OVERFLOW_CONTAINER);
// Float continuations can only trigger overflow
NS_FRAME_SET_OVERFLOW_INCOMPLETE(aFloatStatus);
// Make sure the containing block knows about the float's status
NS_MergeReflowStatusInto(&aState.mReflowStatus, aFloatStatus);
if (!nextInFlow) {
// Next in flow was not created because it already exists.
@ -3862,13 +3880,12 @@ nsBlockFrame::SplitPlaceholder(nsBlockReflowState& aState,
}
// put the sibling list back to what it was before the continuation was created
nsIFrame *contFrame = aPlaceholder->GetNextSibling();
nsIFrame *contFrame = aFloat->GetNextSibling();
nsIFrame *next = contFrame->GetNextSibling();
aPlaceholder->SetNextSibling(next);
aFloat->SetNextSibling(next);
contFrame->SetNextSibling(nsnull);
// The new out of flow frame does not get put anywhere; the out-of-flows
// for placeholders in mOverflowPlaceholders are not kept in any child list
aState.AppendFloatContinuation(contFrame);
return NS_OK;
}
@ -4346,9 +4363,6 @@ nsBlockFrame::DrainOverflowLines(nsBlockReflowState& aState)
return PR_FALSE;
}
NS_ASSERTION(aState.mOverflowPlaceholders.IsEmpty(),
"Should have no overflow placeholders yet");
// Now join the line lists into mLines
if (overflowLines) {
if (!overflowLines->empty()) {
@ -4383,6 +4397,65 @@ nsBlockFrame::DrainOverflowLines(nsBlockReflowState& aState)
return PR_TRUE;
}
// This function assumes our prev-in-flow has completed reflow and its
// mFloats contains at most two frames that belong to the same flow chain,
// the second one being a last-in-flow continuation intended for this block.
void
nsBlockFrame::DrainFloatContinuations(nsBlockReflowState& aState)
{
// Cache any continuations of our own floats that we're still holding onto
// so they're out of the way. This should only happen if we're re-Reflow'd
// before our next-in-flow gets a chance to pull these continuations.
nsFrameList floatContinuations;
nsPresContext* presContext = PresContext();
for (nsIFrame* f = mFloats.FirstChild(); f; f = f->GetNextSibling()) {
nsIFrame* nif = f->GetNextInFlow();
if (!nif) continue;
if (nif->GetParent() == this) {
NS_ASSERTION(!nif->GetNextInFlow(),
"Unexpected next-in-flow for float continuation");
StealFrame(presContext, nif);
floatContinuations.AppendFrame(nsnull, nif);
}
}
if (floatContinuations.NotEmpty()) {
aState.SetupFloatContinuationList();
aState.mFloatContinuations.AppendFrames(nsnull, floatContinuations);
}
// Walk our prev-in-flow's floats and prepend their continuations to our
// floats list. This pulls any continuations we need to take from our
// prev-in-flow and makes sure our continuations of its floats are in the
// proper order.
nsBlockFrame* prevBlock = static_cast<nsBlockFrame*>(GetPrevInFlow());
if (!prevBlock)
return;
for (nsIFrame* pf = prevBlock->mFloats.FirstChild(); pf; pf = pf->GetNextSibling()) {
nsIFrame* nif = pf->GetNextInFlow();
if (!nif)
continue;
nsContainerFrame* nifParent = static_cast<nsContainerFrame*>(nif->GetParent());
nifParent->StealFrame(presContext, nif);
if (nif->GetParent() != this) {
NS_ASSERTION(!nif->GetNextInFlow(),
"Unexpected next-in-flow for float continuation");
ReparentFrame(nif, nifParent, this);
}
floatContinuations.AppendFrame(this, nif);
}
if (floatContinuations.NotEmpty())
mFloats.InsertFrames(nsnull, nsnull, floatContinuations);
#ifdef DEBUG
for (nsIFrame* f = mFloats.FirstChild(); f ; f = f->GetNextSibling()) {
for (nsIFrame* c = f->GetFirstInFlow(); c ; c = c->GetNextInFlow()) {
NS_ASSERTION(c == f || c->GetParent() != this || !mFloats.ContainsFrame(c),
"Two floats with same parent in same floats list, expect weird errors.");
}
}
#endif
}
nsLineList*
nsBlockFrame::GetOverflowLines() const
{
@ -4478,18 +4551,6 @@ nsBlockFrame::SetOverflowOutOfFlows(const nsFrameList& aList)
}
}
nsFrameList*
nsBlockFrame::GetOverflowPlaceholders() const
{
if (!(GetStateBits() & NS_BLOCK_HAS_OVERFLOW_PLACEHOLDERS)) {
return nsnull;
}
nsFrameList* result = static_cast<nsFrameList*>
(GetProperty(nsGkAtoms::overflowPlaceholdersProperty));
NS_ASSERTION(result, "value should always be non-empty when state set");
return result;
}
//////////////////////////////////////////////////////////////////////
// Frame list manipulation routines
@ -4773,10 +4834,7 @@ nsBlockFrame::RemoveFloat(nsIFrame* aFloat) {
}
}
// If this is during reflow, it could be the out-of-flow frame for a
// placeholder in our block reflow state's mOverflowPlaceholders. But that's
// OK; it's not part of any child list, so we can just go ahead and delete it.
aFloat->Destroy();
NS_ERROR("Destroying float without removing from a child list.");
return line_end;
}
@ -4889,10 +4947,11 @@ nsBlockFrame::DoRemoveOutOfFlowFrame(nsIFrame* aFrame)
aFrame);
}
else {
// First remove aFrame's next in flow
nsIFrame* nextInFlow = aFrame->GetNextInFlow();
if (nextInFlow) {
nsBlockFrame::DoRemoveOutOfFlowFrame(nextInFlow);
// First remove aFrame's next-in-flows
nsIFrame* nif = aFrame->GetNextInFlow();
if (nif) {
static_cast<nsContainerFrame*>(nif->GetParent())
->DeleteNextInFlowChild(aFrame->PresContext(), nif, PR_FALSE);
}
// Now remove aFrame
// This also destroys the frame.
@ -5094,34 +5153,22 @@ nsBlockFrame::DoRemoveFrame(nsIFrame* aDeletedFrame, PRUint32 aFlags)
ClearLineCursor();
nsPresContext* presContext = PresContext();
if (NS_FRAME_IS_OVERFLOW_CONTAINER & aDeletedFrame->GetStateBits()) {
nsIFrame* nif = aDeletedFrame->GetNextInFlow();
if (nif)
static_cast<nsContainerFrame*>(nif->GetParent())
->nsContainerFrame::DeleteNextInFlowChild(presContext, nif,
(aFlags & FRAMES_ARE_EMPTY) != 0);
nsresult rv = nsContainerFrame::StealFrame(presContext, aDeletedFrame);
NS_ENSURE_SUCCESS(rv, rv);
aDeletedFrame->Destroy();
return NS_OK;
}
if (aDeletedFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
DoRemoveOutOfFlowFrame(aDeletedFrame);
if (aDeletedFrame->GetStateBits() &
(NS_FRAME_OUT_OF_FLOW | NS_FRAME_IS_OVERFLOW_CONTAINER)) {
if (!aDeletedFrame->GetPrevInFlow()) {
NS_ASSERTION(aDeletedFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW,
"Expected out-of-flow frame");
DoRemoveOutOfFlowFrame(aDeletedFrame);
}
else {
nsContainerFrame::DeleteNextInFlowChild(presContext, aDeletedFrame,
(aFlags & FRAMES_ARE_EMPTY) != 0);
}
return NS_OK;
}
nsIPresShell* presShell = presContext->PresShell();
PRBool isPlaceholder = nsGkAtoms::placeholderFrame == aDeletedFrame->GetType();
if (isPlaceholder) {
nsFrameList* overflowPlaceholders = GetOverflowPlaceholders();
if (overflowPlaceholders && overflowPlaceholders->RemoveFrame(aDeletedFrame)) {
NS_ASSERTION(!aDeletedFrame->GetNextContinuation(), "Placeholders can't have continuations.");
aDeletedFrame->Destroy();
}
}
// Find the line and the previous sibling that contains
// deletedFrame; we also find the pointer to the line.
nsLineList::iterator line_start = mLines.begin(),
@ -5335,6 +5382,19 @@ nsBlockFrame::StealFrame(nsPresContext* aPresContext,
{
NS_PRECONDITION(aPresContext && aChild, "null pointer");
if ((aChild->GetStateBits() & NS_FRAME_OUT_OF_FLOW) &&
aChild->GetStyleDisplay()->IsFloating()) {
PRBool removed = mFloats.RemoveFrame(aChild);
if (!removed) {
nsFrameList* list = GetPropTableFrames(aPresContext,
nsGkAtoms::floatContinuationProperty);
if (list) {
removed = list->RemoveFrame(aChild);
}
}
return (removed) ? NS_OK : NS_ERROR_UNEXPECTED;
}
if ((aChild->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER)
&& !aForceNormal)
return nsContainerFrame::StealFrame(aPresContext, aChild);
@ -5408,7 +5468,8 @@ nsBlockFrame::DeleteNextInFlowChild(nsPresContext* aPresContext,
{
NS_PRECONDITION(aNextInFlow->GetPrevInFlow(), "bad next-in-flow");
if (NS_FRAME_IS_OVERFLOW_CONTAINER & aNextInFlow->GetStateBits()) {
if (aNextInFlow->GetPrevInFlow() && (aNextInFlow->GetStateBits() &
(NS_FRAME_OUT_OF_FLOW | NS_FRAME_IS_OVERFLOW_CONTAINER))) {
nsContainerFrame::DeleteNextInFlowChild(aPresContext,
aNextInFlow, aDeletingEmptyFrames);
}
@ -5465,7 +5526,6 @@ nsBlockFrame::AdjustFloatAvailableSpace(nsBlockReflowState& aState,
availHeight = NS_UNCONSTRAINEDSIZE;
}
#endif
availHeight = NS_UNCONSTRAINEDSIZE; //XXXfr Disable float splitting
return nsRect(aState.BorderPadding().left,
aState.BorderPadding().top,
@ -5597,6 +5657,103 @@ nsBlockFrame::ReflowFloat(nsBlockReflowState& aState,
return NS_OK;
}
nsresult
nsBlockFrame::ReflowFloatContinuations(nsBlockReflowState& aState,
nsRect& aBounds,
nsReflowStatus& aStatus)
{
nsresult rv = NS_OK;
for (nsIFrame* f = mFloats.FirstChild(); f && f->GetPrevInFlow();
f = f->GetNextSibling()) {
if (NS_SUBTREE_DIRTY(f) || aState.mReflowState.ShouldReflowAllKids()) {
// Cache old bounds
nsRect oldRect = f->GetRect();
nsRect oldOverflow = f->GetOverflowRect();
// Reflow
nsReflowStatus fStatus = NS_FRAME_COMPLETE;
aState.AddFloat(nsnull, f, aState.mContentArea.width, fStatus);
if (!NS_FRAME_IS_FULLY_COMPLETE(fStatus)) {
rv = SplitFloat(aState, f, fStatus);
NS_ENSURE_SUCCESS(rv, rv);
NS_FRAME_SET_OVERFLOW_INCOMPLETE(fStatus);
}
NS_MergeReflowStatusInto(&aStatus, fStatus);
// Invalidate if there was a position or size change
nsRect rect = f->GetRect();
if (rect != oldRect) {
nsRect dirtyRect = oldOverflow;
dirtyRect.MoveBy(oldRect.x, oldRect.y);
Invalidate(dirtyRect);
dirtyRect = f->GetOverflowRect();
dirtyRect.MoveBy(rect.x, rect.y);
Invalidate(dirtyRect);
}
}
else {
// Just reload the float region into the space manager
nsRect region = nsFloatManager::GetRegionFor(f);
aState.mFloatManager->AddFloat(f, region);
if (f->GetNextInFlow())
NS_MergeReflowStatusInto(&aStatus, NS_FRAME_OVERFLOW_INCOMPLETE);
}
ConsiderChildOverflow(aBounds, f);
}
return rv;
}
void
nsBlockFrame::RecoverFloats(nsFloatManager& aFloatManager)
{
// Recover our own floats
nsIFrame* stop = nsnull; // Stop before we reach float continuations that
// belong to our next-in-flow
for (nsIFrame* f = mFloats.FirstChild(); f && f != stop; f = f->GetNextSibling()) {
nsRect region = nsFloatManager::GetRegionFor(f);
aFloatManager.AddFloat(f, region);
if (!stop && f->GetNextInFlow())
stop = f->GetNextInFlow();
}
// Recurse into our overflow container children
for (nsIFrame* oc = GetFirstChild(nsGkAtoms::overflowContainersList);
oc; oc = oc->GetNextSibling()) {
RecoverFloatsFor(oc, aFloatManager);
}
// Recurse into our normal children
for (nsBlockFrame::line_iterator line = begin_lines(); line != end_lines(); ++line) {
if (line->IsBlock()) {
RecoverFloatsFor(line->mFirstChild, aFloatManager);
}
}
}
void
nsBlockFrame::RecoverFloatsFor(nsIFrame* aFrame,
nsFloatManager& aFloatManager)
{
NS_PRECONDITION(aFrame, "null frame");
// Only blocks have floats
nsBlockFrame* block = nsLayoutUtils::GetAsBlock(aFrame);
// Don't recover any state inside a block that has its own space manager
// (we don't currently have any blocks like this, though, thanks to our
// use of extra frames for 'overflow')
if (block && !nsBlockFrame::BlockNeedsFloatManager(block)) {
// If the element is relatively positioned, then adjust x and y
// accordingly so that we consider relatively positioned frames
// at their original position.
nsPoint pos = block->GetPosition() - block->GetRelativeOffset();
aFloatManager.Translate(pos.x, pos.y);
block->RecoverFloats(aFloatManager);
aFloatManager.Translate(-pos.x, -pos.y);
}
}
//////////////////////////////////////////////////////////////////////
// Painting, event handling
@ -5816,6 +5973,10 @@ nsBlockFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
if (GetPrevInFlow()) {
DisplayOverflowContainers(aBuilder, aDirtyRect, aLists);
for (nsIFrame* f = mFloats.FirstChild(); f; f = f->GetNextSibling()) {
if (f->GetPrevInFlow())
BuildDisplayListForChild(aBuilder, f, aDirtyRect, aLists);
}
}
aBuilder->MarkFramesForDisplayList(this, mFloats, aDirtyRect);
@ -6449,6 +6610,8 @@ nsBlockFrame::CheckFloats(nsBlockReflowState& aState)
PRBool equal = PR_TRUE;
PRUint32 i = 0;
for (nsIFrame* f = mFloats.FirstChild(); f; f = f->GetNextSibling()) {
if (f->GetPrevInFlow())
continue;
storedFloats.AppendElement(f);
if (i < lineFloats.Length() && lineFloats.ElementAt(i) != f) {
equal = PR_FALSE;

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

@ -92,14 +92,10 @@ class nsIntervalSet;
* flow frames whose placeholders are in the overflow list.
* -- A given piece of content has at most one placeholder
* frame in a block's normal child list.
* -- A given piece of content can have an unlimited number
* of placeholder frames in the overflow-lines list.
* -- A line containing a continuation placeholder contains
* only continuation placeholders.
* -- While a block is being reflowed, its overflowPlaceholdersList
* frame property points to an nsFrameList in its
* nsBlockReflowState. This list contains placeholders for
* floats whose prev-in-flow is in the block's regular line
* -- While a block is being reflowed, it may have a floatContinuationProperty
* frame property that points to an nsFrameList in its
* nsBlockReflowState. This list contains continuations for
* floats whose prev-in-flow is in the block's regular float
* list. The list is always empty/non-existent after the
* block has been reflowed.
* -- In all these frame lists, if there are two frames for
@ -123,12 +119,11 @@ class nsIntervalSet;
#define NS_BLOCK_HAS_LINE_CURSOR 0x01000000
#define NS_BLOCK_HAS_OVERFLOW_LINES 0x02000000
#define NS_BLOCK_HAS_OVERFLOW_OUT_OF_FLOWS 0x04000000
#define NS_BLOCK_HAS_OVERFLOW_PLACEHOLDERS 0x08000000
// Set on any block that has descendant frames in the normal
// flow with 'clear' set to something other than 'none'
// (including <BR CLEAR="..."> frames)
#define NS_BLOCK_HAS_CLEAR_CHILDREN 0x10000000
#define NS_BLOCK_HAS_CLEAR_CHILDREN 0x08000000
#define nsBlockFrameSuper nsHTMLContainerFrame
@ -256,7 +251,7 @@ public:
virtual nsresult StealFrame(nsPresContext* aPresContext,
nsIFrame* aChild,
PRBool aForceNormal);
PRBool aForceNormal = PR_FALSE);
virtual void DeleteNextInFlowChild(nsPresContext* aPresContext,
nsIFrame* aNextInFlow,
@ -277,10 +272,6 @@ public:
static nsresult GetCurrentLine(nsBlockReflowState *aState, nsLineBox **aOutCurrentLine);
// Create a contination for aPlaceholder and its out of flow frame and
// add it to the list of overflow floats
nsresult SplitPlaceholder(nsBlockReflowState& aState, nsIFrame* aPlaceholder);
static PRBool BlockIsMarginRoot(nsIFrame* aBlock);
static PRBool BlockNeedsFloatManager(nsIFrame* aBlock);
@ -307,6 +298,17 @@ public:
const nsRect& aFloatAvailableSpace,
nsIFrame* aFrame);
/**
* Creates a contination for aFloat and adds it to the list of overflow floats.
* Also updates aState.mReflowStatus to include the float's incompleteness.
* Must only be called while this block frame is in reflow.
* aFloatStatus must be the float's true, unmodified reflow status.
*
*/
nsresult SplitFloat(nsBlockReflowState& aState,
nsIFrame* aFloat,
nsReflowStatus aFloatStatus);
/**
* Walks up the frame tree, starting with aCandidate, and returns the first
* block frame that it encounters.
@ -431,6 +433,14 @@ public:
nsBlockFrame* aOldParent, PRBool aFromOverflow,
PRBool aReparentSiblings);
/** 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.
* Safe to call on non-blocks (does nothing).
*/
static void RecoverFloatsFor(nsIFrame* aFrame,
nsFloatManager& aFloatManager);
protected:
/** grab overflow lines from this block's prevInFlow, and make them
@ -439,6 +449,22 @@ protected:
*/
PRBool DrainOverflowLines(nsBlockReflowState& aState);
/** grab float continuations from this block's prevInFlow, and splice
* them into this block's mFloats list.
*/
void DrainFloatContinuations(nsBlockReflowState& aState);
/** Load all our floats into the float manager (without reflowing them).
* Assumes float manager is in our own coordinate system.
*/
void RecoverFloats(nsFloatManager& aFloatManager);
/** Reflow float continuations
*/
nsresult ReflowFloatContinuations(nsBlockReflowState& aState,
nsRect& aBounds,
nsReflowStatus& aStatus);
/**
* Remove a float from our float list and also the float cache
* for the line its placeholder is on.
@ -624,8 +650,6 @@ protected:
nsLineList* RemoveOverflowLines();
nsresult SetOverflowLines(nsLineList* aOverflowLines);
nsFrameList* GetOverflowPlaceholders() const;
/**
* This class is useful for efficiently modifying the out of flow
* overflow list. It gives the client direct writable access to

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

@ -142,21 +142,10 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
mMinLineHeight = aReflowState.CalcLineHeight();
}
void
nsBlockReflowState::SetupOverflowPlaceholdersProperty()
{
if (mReflowState.availableHeight != NS_UNCONSTRAINEDSIZE ||
!mOverflowPlaceholders.IsEmpty()) {
mBlock->SetProperty(nsGkAtoms::overflowPlaceholdersProperty,
&mOverflowPlaceholders, nsnull);
mBlock->AddStateBits(NS_BLOCK_HAS_OVERFLOW_PLACEHOLDERS);
}
}
nsBlockReflowState::~nsBlockReflowState()
{
NS_ASSERTION(mOverflowPlaceholders.IsEmpty(),
"Leaking overflow placeholder frames");
NS_ASSERTION(mFloatContinuations.IsEmpty(),
"Leaking float continuation frames");
// Restore the coordinate system, unless the float manager is null,
// which means it was just destroyed.
@ -165,9 +154,8 @@ nsBlockReflowState::~nsBlockReflowState()
mFloatManager->Translate(-borderPadding.left, -borderPadding.top);
}
if (mBlock->GetStateBits() & NS_BLOCK_HAS_OVERFLOW_PLACEHOLDERS) {
mBlock->UnsetProperty(nsGkAtoms::overflowPlaceholdersProperty);
mBlock->RemoveStateBits(NS_BLOCK_HAS_OVERFLOW_PLACEHOLDERS);
if (GetFlag(BRS_PROPTABLE_FLOATCLIST)) {
mBlock->UnsetProperty(nsGkAtoms::floatContinuationProperty);
}
}
@ -438,6 +426,16 @@ nsBlockReflowState::ReconstructMarginAbove(nsLineList::iterator aLine)
}
}
void
nsBlockReflowState::SetupFloatContinuationList()
{
if (!GetFlag(BRS_PROPTABLE_FLOATCLIST)) {
mBlock->SetProperty(nsGkAtoms::floatContinuationProperty,
&mFloatContinuations, nsnull);
SetFlag(BRS_PROPTABLE_FLOATCLIST, PR_TRUE);
}
}
/**
* Restore information about floats into the float manager for an
* incremental reflow, and simultaneously push the floats by
@ -480,38 +478,7 @@ nsBlockReflowState::RecoverFloats(nsLineList::iterator aLine,
fc = fc->Next();
}
} else if (aLine->IsBlock()) {
nsBlockFrame *kid = nsLayoutUtils::GetAsBlock(aLine->mFirstChild);
// don't recover any state inside a block that has its own space
// manager (we don't currently have any blocks like this, though,
// thanks to our use of extra frames for 'overflow')
if (kid && !nsBlockFrame::BlockNeedsFloatManager(kid)) {
nscoord tx = kid->mRect.x, ty = kid->mRect.y;
// If the element is relatively positioned, then adjust x and y
// accordingly so that we consider relatively positioned frames
// at their original position.
if (NS_STYLE_POSITION_RELATIVE == kid->GetStyleDisplay()->mPosition) {
nsPoint *offsets = static_cast<nsPoint*>
(mPresContext->PropertyTable()->GetProperty(kid,
nsGkAtoms::computedOffsetProperty));
if (offsets) {
tx -= offsets->x;
ty -= offsets->y;
}
}
mFloatManager->Translate(tx, ty);
for (nsBlockFrame::line_iterator line = kid->begin_lines(),
line_end = kid->end_lines();
line != line_end;
++line)
// Pass 0, not the real DeltaY, since these floats aren't
// moving relative to their parent block, only relative to
// the float manager.
RecoverFloats(line, 0);
mFloatManager->Translate(-tx, -ty);
}
nsBlockFrame::RecoverFloatsFor(aLine->mFirstChild, *mFloatManager);
}
}
@ -565,12 +532,12 @@ nsBlockReflowState::RecoverStateFrom(nsLineList::iterator aLine,
// float as well unless it won't fit next to what we already have.
// But nobody else implements it that way...
PRBool
nsBlockReflowState::AddFloat(nsLineLayout& aLineLayout,
nsBlockReflowState::AddFloat(nsLineLayout* aLineLayout,
nsIFrame* aFloat,
nscoord aAvailableWidth,
nsReflowStatus& aReflowStatus)
{
NS_PRECONDITION(mBlock->end_lines() != mCurrentLine, "null ptr");
NS_PRECONDITION(!aLineLayout || mBlock->end_lines() != mCurrentLine, "null ptr");
NS_PRECONDITION(aFloat->GetStateBits() & NS_FRAME_OUT_OF_FLOW,
"aFloat must be an out-of-flow frame");
@ -578,9 +545,6 @@ nsBlockReflowState::AddFloat(nsLineLayout& aLineLayout,
aFloat->SetParent(mBlock);
aReflowStatus = NS_FRAME_COMPLETE;
// Allocate a nsFloatCache for the float
nsFloatCache* fc = mFloatCacheFreeList.Alloc();
fc->mFloat = aFloat;
// Because we are in the middle of reflowing a placeholder frame
// within a line (and possibly nested in an inline frame or two
@ -601,14 +565,16 @@ nsBlockReflowState::AddFloat(nsLineLayout& aLineLayout,
// don't let this one go on the current line, since that would violate
// float ordering.
nsRect floatAvailableSpace = GetFloatAvailableSpace().mRect;
if (mBelowCurrentLineFloats.IsEmpty() &&
(aLineLayout.LineIsEmpty() ||
mBlock->ComputeFloatWidth(*this, floatAvailableSpace, aFloat) <=
aAvailableWidth)) {
if (!aLineLayout ||
(mBelowCurrentLineFloats.IsEmpty() &&
(aLineLayout->LineIsEmpty() ||
mBlock->ComputeFloatWidth(*this, floatAvailableSpace, aFloat)
<= aAvailableWidth))) {
// And then place it
// force it to fit if we're at the top of the block and we can't
// break before this
PRBool forceFit = IsAdjacentWithTop() && !aLineLayout.LineIsBreakable();
PRBool forceFit = !aLineLayout ||
(IsAdjacentWithTop() && !aLineLayout->LineIsBreakable());
placed = FlowAndPlaceFloat(aFloat, aReflowStatus, forceFit);
NS_ASSERTION(placed || !forceFit,
"If we asked for force-fit, it should have been placed");
@ -619,10 +585,11 @@ nsBlockReflowState::AddFloat(nsLineLayout& aLineLayout,
nsRect availSpace(nsPoint(floatAvailSpace.mRect.x + BorderPadding().left,
mY),
floatAvailSpace.mRect.Size());
aLineLayout.UpdateBand(availSpace, aFloat);
// Record this float in the current-line list
mCurrentLineFloats.Append(fc);
if (aLineLayout) {
aLineLayout->UpdateBand(availSpace, aFloat);
// Record this float in the current-line list
mCurrentLineFloats.Append(mFloatCacheFreeList.Alloc(aFloat));
}
// If we can't break here, hide the fact that it's truncated
// XXX We can probably do this more cleanly
aReflowStatus &= ~NS_FRAME_TRUNCATED;
@ -631,7 +598,7 @@ nsBlockReflowState::AddFloat(nsLineLayout& aLineLayout,
if (IsAdjacentWithTop()) {
// Pushing the line to the next page won't give us any more space;
// therefore, we break.
NS_ASSERTION(aLineLayout.LineIsBreakable(),
NS_ASSERTION(aLineLayout->LineIsBreakable(),
"We can't get here unless forceFit is false");
aReflowStatus = NS_INLINE_LINE_BREAK_BEFORE();
} else {
@ -639,7 +606,6 @@ nsBlockReflowState::AddFloat(nsLineLayout& aLineLayout,
// block to push the line to the next page.
aReflowStatus |= NS_FRAME_TRUNCATED;
}
delete fc;
}
}
else {
@ -648,7 +614,7 @@ nsBlockReflowState::AddFloat(nsLineLayout& aLineLayout,
placed = PR_TRUE;
// This float will be placed after the line is done (it is a
// below-current-line float).
mBelowCurrentLineFloats.Append(fc);
mBelowCurrentLineFloats.Append(mFloatCacheFreeList.Alloc(aFloat));
}
// Restore coordinate system
@ -1029,8 +995,11 @@ nsBlockReflowState::PlaceBelowCurrentLineFloats(nsFloatCacheFreeList& aList, PRB
// return before processing all of the floats, since the line will be pushed.
return PR_FALSE;
}
else if (NS_FRAME_IS_NOT_COMPLETE(reflowStatus)) {
// Create a continuation for the incomplete float XXXfr
else if (!NS_FRAME_IS_FULLY_COMPLETE(reflowStatus)) {
// Create a continuation for the incomplete float
nsresult rv = mBlock->SplitFloat(*this, fc->mFloat, reflowStatus);
if (NS_FAILED(rv))
return PR_FALSE;
} else {
// XXX We could deal with truncated frames better by breaking before
// the associated placeholder

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

@ -62,7 +62,9 @@
// the current line
#define BRS_LINE_LAYOUT_EMPTY 0x00000080
#define BRS_ISOVERFLOWCONTAINER 0x00000100
#define BRS_LASTFLAG BRS_ISOVERFLOWCONTAINER
// Our mFloatContinuations list is stored on the blocks' proptable
#define BRS_PROPTABLE_FLOATCLIST 0x00000200
#define BRS_LASTFLAG BRS_PROPTABLE_FLOATCLIST
class nsBlockReflowState {
public:
@ -75,13 +77,6 @@ public:
~nsBlockReflowState();
// Set up a property on the block that points to our temporary mOverflowPlaceholders
// list, if that list is or could become non-empty during this reflow. Must be
// called after the block has done DrainOverflowLines because DrainOverflowLines
// can setup mOverflowPlaceholders even if the block is in unconstrained height
// reflow (it may have previously been reflowed with constrained height).
void SetupOverflowPlaceholdersProperty();
/**
* Get the available reflow space (the area not occupied by floats)
* for the current y coordinate. The available space is relative to
@ -108,8 +103,10 @@ public:
* The following functions all return PR_TRUE if they were able to
* place the float, PR_FALSE if the float did not fit in available
* space.
* aLineLayout is null when we are reflowing float continuations (because
* they are not associated with a line box).
*/
PRBool AddFloat(nsLineLayout& aLineLayout,
PRBool AddFloat(nsLineLayout* aLineLayout,
nsIFrame* aFloat,
nscoord aAvailableWidth,
nsReflowStatus& aReflowStatus);
@ -229,13 +226,18 @@ public:
// unconstrained area.
nsSize mContentArea;
// Placeholders for continuation out-of-flow frames that need to
// move to our next in flow are placed here during reflow. At the end of reflow
// they move to the end of the overflow lines.
// Their out-of-flows are not in any child list during reflow, but are added
// to the overflow-out-of-flow list when the placeholders are appended to
// the overflow lines.
nsFrameList mOverflowPlaceholders;
// Continuation out-of-flow float frames that need to move to our
// next in flow are placed here during reflow. At the end of reflow
// they move to the end of the mFloats list.
nsFrameList mFloatContinuations;
// This method makes sure float continuations are accessible to
// StealFrame. Call it before adding any frames to mFloatContinuations.
void SetupFloatContinuationList();
// Use this method to append to mFloatContinuations.
void AppendFloatContinuation(nsIFrame* aFloatCont) {
SetupFloatContinuationList();
mFloatContinuations.AppendFrame(mBlock, aFloatCont);
}
// Track child overflow continuations.
nsOverflowContinuationTracker mOverflowTracker;

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

@ -1066,6 +1066,8 @@ nsContainerFrame::ReflowOverflowContainerChildren(nsPresContext* aPres
}
else {
tracker.Skip(frame, aStatus);
if (aReflowState.mFloatManager)
nsBlockFrame::RecoverFloatsFor(frame, *aReflowState.mFloatManager);
}
ConsiderChildOverflow(aOverflowRect, frame);
}

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

@ -452,7 +452,8 @@ protected:
#define IS_TRUE_OVERFLOW_CONTAINER(frame) \
( (frame->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER) \
&& !(frame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) )
&& !( (frame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) && \
frame->GetStyleDisplay()->IsAbsolutelyPositioned() ) )
//XXXfr This check isn't quite correct, because it doesn't handle cases
// where the out-of-flow has overflow.. but that's rare.
// We'll need to revisit the way abspos continuations are handled later

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

@ -5879,9 +5879,9 @@ nsFrame::DoGetParentStyleContextFrame(nsPresContext* aPresContext,
// For out-of-flow frames, we must resolve underneath the
// placeholder's parent.
nsIFrame* oofFrame = this;
if ((oofFrame->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER)
&& (oofFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW)) {
// Out of flows that are overflow containers do not
if ((oofFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) &&
GetPrevInFlow()) {
// Out of flows that are continuations do not
// have placeholders. Use their first-in-flow's placeholder.
oofFrame = oofFrame->GetFirstInFlow();
}

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

@ -714,10 +714,12 @@ nsInlineFrame::ReflowInlineFrame(nsPresContext* aPresContext,
}
}
}
else if (NS_FRAME_IS_NOT_COMPLETE(aStatus)) {
else if (!NS_FRAME_IS_FULLY_COMPLETE(aStatus)) {
if (nsGkAtoms::placeholderFrame == aFrame->GetType()) {
nsBlockReflowState* blockRS = lineLayout->mBlockRS;
NS_ASSERTION(0, "float splitting unimplemented"); // SplitFloat XXXfr
nsPlaceholderFrame* placeholder = static_cast<nsPlaceholderFrame*>(aFrame);
rv = blockRS->mBlock->SplitFloat(*blockRS, placeholder->GetOutOfFlowFrame(),
aStatus);
// Allow the parent to continue reflowing
aStatus = NS_FRAME_COMPLETE;
}

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

@ -909,8 +909,10 @@ nsFloatCacheFreeList::DeleteAll()
}
nsFloatCache*
nsFloatCacheFreeList::Alloc()
nsFloatCacheFreeList::Alloc(nsIFrame* aFloat)
{
NS_PRECONDITION(aFloat->GetStateBits() & NS_FRAME_OUT_OF_FLOW,
"This is a float cache, why isn't the frame out-of-flow?");
nsFloatCache* fc = mHead;
if (mHead) {
if (mHead == mTail) {
@ -924,6 +926,7 @@ nsFloatCacheFreeList::Alloc()
else {
fc = new nsFloatCache();
}
fc->mFloat = aFloat;
return fc;
}

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

@ -162,8 +162,8 @@ public:
void Remove(nsFloatCache* aElement);
// Remove an nsFloatCache object from this list and return it, or create
// a new one if this one is empty;
nsFloatCache* Alloc();
// a new one if this one is empty; Set its mFloat to aFloat.
nsFloatCache* Alloc(nsIFrame* aFloat);
protected:
nsFloatCache* mTail;

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

@ -213,7 +213,7 @@ public:
nscoord aAvailableWidth,
nsReflowStatus& aReflowStatus)
{
return mBlockRS->AddFloat(*this, aFloat, aAvailableWidth, aReflowStatus);
return mBlockRS->AddFloat(this, aFloat, aAvailableWidth, aReflowStatus);
}
void SetTrimmableWidth(nscoord aTrimmableWidth) {