From 26dae9e55bbd941db4d32d2587cd40291a317072 Mon Sep 17 00:00:00 2001 From: "roc+%cs.cmu.edu" Date: Mon, 13 Sep 2004 13:35:46 +0000 Subject: [PATCH] Bug 257216. Fix sundry block issues for columns. In particular, remove overflowing floats from the space manager before we compute the space manager's XMost and YMost to include in the block size. r+sr=dbaron git-svn-id: svn://10.0.0.236/trunk@162210 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/layout/base/nsLayoutUtils.cpp | 18 +++++ mozilla/layout/base/nsLayoutUtils.h | 7 +- mozilla/layout/base/public/nsLayoutUtils.h | 7 +- mozilla/layout/base/src/nsLayoutUtils.cpp | 18 +++++ mozilla/layout/base/src/nsSpaceManager.cpp | 38 +++++++-- mozilla/layout/base/src/nsSpaceManager.h | 19 ++++- mozilla/layout/generic/nsBlockFrame.cpp | 78 ++++++++++++------- mozilla/layout/generic/nsBlockFrame.h | 2 +- mozilla/layout/generic/nsBlockReflowState.cpp | 5 +- mozilla/layout/generic/nsLineLayout.cpp | 34 ++++---- mozilla/layout/generic/nsSpaceManager.cpp | 38 +++++++-- mozilla/layout/generic/nsSpaceManager.h | 19 ++++- mozilla/layout/html/base/src/nsBlockFrame.cpp | 78 ++++++++++++------- mozilla/layout/html/base/src/nsBlockFrame.h | 2 +- .../html/base/src/nsBlockReflowState.cpp | 5 +- mozilla/layout/html/base/src/nsLineLayout.cpp | 34 ++++---- 16 files changed, 286 insertions(+), 116 deletions(-) diff --git a/mozilla/layout/base/nsLayoutUtils.cpp b/mozilla/layout/base/nsLayoutUtils.cpp index ccaa656aa91..247f65d4288 100644 --- a/mozilla/layout/base/nsLayoutUtils.cpp +++ b/mozilla/layout/base/nsLayoutUtils.cpp @@ -45,6 +45,7 @@ #include "nsCSSPseudoElements.h" #include "nsIView.h" #include "nsIScrollableView.h" +#include "nsPlaceholderFrame.h" /** * A namespace class for static layout utilities. @@ -174,6 +175,23 @@ nsLayoutUtils::GetPageFrame(nsIFrame* aFrame) return nsnull; } +nsIFrame* +nsLayoutUtils::GetFloatFromPlaceholder(nsIFrame* aFrame) { + if (nsLayoutAtoms::placeholderFrame != aFrame->GetType()) { + return nsnull; + } + + nsIFrame *outOfFlowFrame = + NS_STATIC_CAST(nsPlaceholderFrame*, aFrame)->GetOutOfFlowFrame(); + // This is a hack. + if (outOfFlowFrame && + !outOfFlowFrame->GetStyleDisplay()->IsAbsolutelyPositioned()) { + return outOfFlowFrame; + } + + return nsnull; +} + // static PRBool nsLayoutUtils::IsGeneratedContentFor(nsIContent* aContent, diff --git a/mozilla/layout/base/nsLayoutUtils.h b/mozilla/layout/base/nsLayoutUtils.h index 7ebd5cf17e9..5e1cc200d7e 100644 --- a/mozilla/layout/base/nsLayoutUtils.h +++ b/mozilla/layout/base/nsLayoutUtils.h @@ -199,7 +199,12 @@ public: } return pseudoContext != nsnull; } - + + /** + * If this frame is a placeholder for a float, then return the float, + * otherwise return nsnull. + */ + static nsIFrame* GetFloatFromPlaceholder(nsIFrame* aPossiblePlaceholder); }; #endif // nsLayoutUtils_h__ diff --git a/mozilla/layout/base/public/nsLayoutUtils.h b/mozilla/layout/base/public/nsLayoutUtils.h index 7ebd5cf17e9..5e1cc200d7e 100644 --- a/mozilla/layout/base/public/nsLayoutUtils.h +++ b/mozilla/layout/base/public/nsLayoutUtils.h @@ -199,7 +199,12 @@ public: } return pseudoContext != nsnull; } - + + /** + * If this frame is a placeholder for a float, then return the float, + * otherwise return nsnull. + */ + static nsIFrame* GetFloatFromPlaceholder(nsIFrame* aPossiblePlaceholder); }; #endif // nsLayoutUtils_h__ diff --git a/mozilla/layout/base/src/nsLayoutUtils.cpp b/mozilla/layout/base/src/nsLayoutUtils.cpp index ccaa656aa91..247f65d4288 100644 --- a/mozilla/layout/base/src/nsLayoutUtils.cpp +++ b/mozilla/layout/base/src/nsLayoutUtils.cpp @@ -45,6 +45,7 @@ #include "nsCSSPseudoElements.h" #include "nsIView.h" #include "nsIScrollableView.h" +#include "nsPlaceholderFrame.h" /** * A namespace class for static layout utilities. @@ -174,6 +175,23 @@ nsLayoutUtils::GetPageFrame(nsIFrame* aFrame) return nsnull; } +nsIFrame* +nsLayoutUtils::GetFloatFromPlaceholder(nsIFrame* aFrame) { + if (nsLayoutAtoms::placeholderFrame != aFrame->GetType()) { + return nsnull; + } + + nsIFrame *outOfFlowFrame = + NS_STATIC_CAST(nsPlaceholderFrame*, aFrame)->GetOutOfFlowFrame(); + // This is a hack. + if (outOfFlowFrame && + !outOfFlowFrame->GetStyleDisplay()->IsAbsolutelyPositioned()) { + return outOfFlowFrame; + } + + return nsnull; +} + // static PRBool nsLayoutUtils::IsGeneratedContentFor(nsIContent* aContent, diff --git a/mozilla/layout/base/src/nsSpaceManager.cpp b/mozilla/layout/base/src/nsSpaceManager.cpp index b58fc392fb4..10b14f8b049 100644 --- a/mozilla/layout/base/src/nsSpaceManager.cpp +++ b/mozilla/layout/base/src/nsSpaceManager.cpp @@ -46,6 +46,7 @@ #include "nsIPresShell.h" #include "nsMemory.h" #include "nsHTMLReflowState.h" +#include "nsHashSets.h" #ifdef DEBUG #include "nsIFrameDebug.h" #endif @@ -105,7 +106,6 @@ MOZ_DECL_CTOR_COUNTER(nsSpaceManager) nsSpaceManager::nsSpaceManager(nsIPresShell* aPresShell, nsIFrame* aFrame) : mFrame(aFrame), - mXMost(0), mLowestTop(NSCOORD_MIN), mFloatDamage(PSArenaAllocCB, PSArenaFreeCB, aPresShell) { @@ -199,7 +199,11 @@ void nsSpaceManager::Shutdown() PRBool nsSpaceManager::XMost(nscoord& aXMost) const { - aXMost = mXMost; + nscoord xMost = 0; + for (FrameInfo* fi = mFrameInfoMap; fi; fi = fi->mNext) { + xMost = PR_MAX(xMost, fi->mRect.XMost()); + } + aXMost = xMost; return !mBandList.IsEmpty(); } @@ -813,10 +817,6 @@ nsSpaceManager::AddRectRegion(nsIFrame* aFrame, const nsRect& aUnavailableSpace) nsRect rect(aUnavailableSpace.x + mX, aUnavailableSpace.y + mY, aUnavailableSpace.width, aUnavailableSpace.height); - nscoord xmost = rect.XMost(); - if (xmost > mXMost) - mXMost = xmost; - if (rect.y > mLowestTop) mLowestTop = rect.y; @@ -843,6 +843,30 @@ nsSpaceManager::AddRectRegion(nsIFrame* aFrame, const nsRect& aUnavailableSpace) return NS_OK; } +nsresult +nsSpaceManager::RemoveTrailingRegions(nsIFrame* aFrameList) { + nsVoidHashSet frameSet; + + frameSet.Init(1); + for (nsIFrame* f = aFrameList; f; f = f->GetNextSibling()) { + frameSet.Put(f); + } + + // Pop frame regions off as long as they're in the set of frames to + // remove + while (mFrameInfoMap && frameSet.Contains(mFrameInfoMap->mFrame)) { + RemoveRegion(mFrameInfoMap->mFrame); + } + +#ifdef DEBUG + for (FrameInfo* frameInfo = mFrameInfoMap; frameInfo; + frameInfo = frameInfo->mNext) { + NS_ASSERTION(!frameSet.Contains(frameInfo->mFrame), + "Frame region deletion was requested but we couldn't delete it"); + } +#endif +} + nsresult nsSpaceManager::RemoveRegion(nsIFrame* aFrame) { @@ -995,7 +1019,6 @@ nsSpaceManager::PushState() state->mX = mX; state->mY = mY; - state->mXMost = mXMost; state->mLowestTop = mLowestTop; if (mFrameInfoMap) { @@ -1042,7 +1065,6 @@ nsSpaceManager::PopState() mX = mSavedStates->mX; mY = mSavedStates->mY; - mXMost = mSavedStates->mXMost; mLowestTop = mSavedStates->mLowestTop; // Now that we've restored our state, pop the topmost diff --git a/mozilla/layout/base/src/nsSpaceManager.h b/mozilla/layout/base/src/nsSpaceManager.h index fb8e4589736..e825ad9cd0d 100644 --- a/mozilla/layout/base/src/nsSpaceManager.h +++ b/mozilla/layout/base/src/nsSpaceManager.h @@ -251,13 +251,28 @@ public: nsresult AddRectRegion(nsIFrame* aFrame, const nsRect& aUnavailableSpace); + /** + * Remove the regions associated with this floating frame and its + * next-sibling list. Some of the frames may never have been added; + * we just skip those. This is not fully general; it only works as + * long as the N frames to be removed are the last N frames to have + * been added; if there's a frame in the middle of them that should + * not be removed, YOU LOSE. + * + * This can only be done at the end of the life of this space manager. The only + * methods it is safe to call after this are XMost() and YMost(). + */ + nsresult RemoveTrailingRegions(nsIFrame* aFrameList); + +protected: /** * Remove the region associated with aFrane. * + * doesn't work in the general case! + * * Returns NS_OK if successful and NS_ERROR_INVALID_ARG if there is no region * tagged with aFrame */ -protected: /* doesn't work in the general case */ nsresult RemoveRegion(nsIFrame* aFrame); public: @@ -335,7 +350,6 @@ protected: struct SpaceManagerState { nscoord mX, mY; nsIFrame *mLastFrame; - nscoord mXMost; nscoord mLowestTop; SpaceManagerState *mNext; }; @@ -408,7 +422,6 @@ protected: nsIFrame* const mFrame; // frame associated with the space manager nscoord mX, mY; // translation from local to global coordinate space BandList mBandList; // header/sentinel for circular linked list of band rects - nscoord mXMost; nscoord mLowestTop; // the lowest *top* FrameInfo* mFrameInfoMap; nsIntervalSet mFloatDamage; diff --git a/mozilla/layout/generic/nsBlockFrame.cpp b/mozilla/layout/generic/nsBlockFrame.cpp index de4ab6f7672..eb78a3b9704 100644 --- a/mozilla/layout/generic/nsBlockFrame.cpp +++ b/mozilla/layout/generic/nsBlockFrame.cpp @@ -78,6 +78,7 @@ #ifdef ACCESSIBILITY #include "nsIAccessibilityService.h" #endif +#include "nsLayoutUtils.h" #ifdef IBMBIDI #include "nsBidiPresUtils.h" @@ -658,6 +659,12 @@ nsBlockFrame::Reflow(nsPresContext* aPresContext, FinishAndStoreOverflow(&aMetrics); +#ifdef DEBUG + if (gNoisy) { + gNoiseIndent--; + } +#endif + return NS_OK; } } @@ -921,8 +928,8 @@ nsBlockFrame::Reflow(nsPresContext* aPresContext, // XXX_perf get rid of this! This is one of the things that makes // incremental reflow O(N^2). - BuildFloatList(); - + BuildFloatList(state); + // Compute our final size ComputeFinalSize(aReflowState, state, aMetrics); FinishAndStoreOverflow(&aMetrics); @@ -2066,6 +2073,20 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState) return rv; } if (!keepGoing) { +#ifdef DEBUG + if (gNoisyReflow) { + gNoiseIndent--; + nsRect lca(line->GetCombinedArea()); + IndentBy(stdout, gNoiseIndent); + printf("line=%p mY=%d newBounds={%d,%d,%d,%d} newCombinedArea={%d,%d,%d,%d} deltaY=%d mPrevBottomMargin=%d childCount=%d\n", + NS_STATIC_CAST(void*, line.get()), aState.mY, + line->mBounds.x, line->mBounds.y, + line->mBounds.width, line->mBounds.height, + lca.x, lca.y, lca.width, lca.height, + deltaY, aState.mPrevBottomMargin.get(), + line->GetChildCount()); + } +#endif if (0 == line->GetChildCount()) { DeleteLine(aState, line, line_end); } @@ -6479,38 +6500,30 @@ nsBlockFrame::ReflowBullet(nsBlockReflowState& aState, // This is used to scan overflow frames for any float placeholders, // and add their floats to the list represented by aHead and aTail. We // only search the inline descendants. -static void CollectOverflowFloats(nsIFrame* aFrame, nsIFrame* aBlockParent, - nsIFrame** aHead, nsIFrame** aTail) { +static void CollectFloats(nsIFrame* aFrame, nsIFrame* aBlockParent, + nsIFrame** aHead, nsIFrame** aTail) { while (aFrame) { // Don't descend into block children if (!aFrame->GetStyleDisplay()->IsBlockLevel()) { - if (nsLayoutAtoms::placeholderFrame == aFrame->GetType()) { - nsIFrame *outOfFlowFrame = - NS_STATIC_CAST(nsPlaceholderFrame*, aFrame)->GetOutOfFlowFrame(); + nsIFrame *outOfFlowFrame = nsLayoutUtils::GetFloatFromPlaceholder(aFrame); + if (outOfFlowFrame) { // Make sure that its parent is the block we care // about. Otherwise we don't want to mess around with it because // it belongs to someone else. I think this could happen if the // overflow lines contain a block descendant which owns its own // floats. - if (outOfFlowFrame && - !outOfFlowFrame->GetStyleDisplay()->IsAbsolutelyPositioned()) { - NS_ASSERTION(outOfFlowFrame->GetParent() == aBlockParent, - "Out of flow frame doesn't have the expected parent"); - // It's not an absolute or fixed positioned frame, so it must - // be a float! - // XXX This is a lame-o way of detecting a float, but it's the - // only way apparently - if (!*aHead) { - *aHead = *aTail = outOfFlowFrame; - } else { - (*aTail)->SetNextSibling(outOfFlowFrame); - *aTail = outOfFlowFrame; - } + NS_ASSERTION(outOfFlowFrame->GetParent() == aBlockParent, + "Out of flow frame doesn't have the expected parent"); + if (!*aHead) { + *aHead = *aTail = outOfFlowFrame; + } else { + (*aTail)->SetNextSibling(outOfFlowFrame); + *aTail = outOfFlowFrame; } } - CollectOverflowFloats(aFrame->GetFirstChild(nsnull), aBlockParent, - aHead, aTail); + CollectFloats(aFrame->GetFirstChild(nsnull), aBlockParent, + aHead, aTail); } aFrame = aFrame->GetNextSibling(); @@ -6519,7 +6532,7 @@ static void CollectOverflowFloats(nsIFrame* aFrame, nsIFrame* aBlockParent, //XXX get rid of this -- its slow void -nsBlockFrame::BuildFloatList() +nsBlockFrame::BuildFloatList(nsBlockReflowState& aState) { // Accumulate float list into mFloats. // Use the float cache to speed up searching the lines for floats. @@ -6558,11 +6571,24 @@ nsBlockFrame::BuildFloatList() head = nsnull; current = nsnull; - CollectOverflowFloats(overflowLines->front()->mFirstChild, - this, &head, ¤t); + CollectFloats(overflowLines->front()->mFirstChild, + this, &head, ¤t); if (current) { current->SetNextSibling(nsnull); + + // Floats that were pushed should be removed from our space + // manager. Otherwise the space manager's YMost or XMost might + // be larger than necessary, causing this block to get an + // incorrect desired height (or width). Some of these floats + // may not actually have been added to the space manager because + // they weren't reflowed before being pushed; that's OK, + // RemoveRegions will ignore them. It is safe to do this here + // because we know from here on the space manager will only be + // used for its XMost and YMost, not to place new floats and + // lines. + aState.mSpaceManager->RemoveTrailingRegions(head); + nsFrameList* frameList = new nsFrameList(head); if (frameList) { SetOverflowOutOfFlows(frameList); diff --git a/mozilla/layout/generic/nsBlockFrame.h b/mozilla/layout/generic/nsBlockFrame.h index 73177fde2dc..d42dcfc7811 100644 --- a/mozilla/layout/generic/nsBlockFrame.h +++ b/mozilla/layout/generic/nsBlockFrame.h @@ -518,7 +518,7 @@ protected: nsLineBox* aLine, nscoord aDeltaY); - void BuildFloatList(); + void BuildFloatList(nsBlockReflowState& aState); //---------------------------------------- // List handling kludge diff --git a/mozilla/layout/generic/nsBlockReflowState.cpp b/mozilla/layout/generic/nsBlockReflowState.cpp index e90efc276c5..c644b5d9a86 100644 --- a/mozilla/layout/generic/nsBlockReflowState.cpp +++ b/mozilla/layout/generic/nsBlockReflowState.cpp @@ -818,7 +818,7 @@ nsBlockReflowState::CanPlaceFloat(const nsRect& aFloatRect, } void -nsBlockReflowState::FlowAndPlaceFloat(nsFloatCache* aFloatCache, +nsBlockReflowState::FlowAndPlaceFloat(nsFloatCache* aFloatCache, PRBool* aIsLeftFloat, nsReflowStatus& aReflowStatus) { @@ -858,6 +858,9 @@ nsBlockReflowState::FlowAndPlaceFloat(nsFloatCache* aFloatCache, GetAvailableSpace(); } + NS_ASSERTION(floatFrame->GetParent() == mBlock, + "Float frame has wrong parent"); + // Reflow the float mBlock->ReflowFloat(*this, placeholder, aFloatCache, aReflowStatus); diff --git a/mozilla/layout/generic/nsLineLayout.cpp b/mozilla/layout/generic/nsLineLayout.cpp index c7d204173c3..03e94b4c984 100644 --- a/mozilla/layout/generic/nsLineLayout.cpp +++ b/mozilla/layout/generic/nsLineLayout.cpp @@ -65,6 +65,7 @@ #include "nsHTMLAtoms.h" #include "nsTextFragment.h" #include "nsBidiUtils.h" +#include "nsLayoutUtils.h" #ifdef DEBUG #undef NOISY_HORIZONTAL_ALIGN @@ -1003,25 +1004,22 @@ nsLineLayout::ReflowFrame(nsIFrame* aFrame, if (frameType) { if (nsLayoutAtoms::placeholderFrame == frameType) { pfd->SetFlag(PFD_ISPLACEHOLDERFRAME, PR_TRUE); - nsIFrame* outOfFlowFrame = ((nsPlaceholderFrame*)aFrame)->GetOutOfFlowFrame(); + nsIFrame* outOfFlowFrame = nsLayoutUtils::GetFloatFromPlaceholder(aFrame); if (outOfFlowFrame) { - // Make sure it's floated and not absolutely positioned - const nsStyleDisplay* display = outOfFlowFrame->GetStyleDisplay(); - if (!display->IsAbsolutelyPositioned()) { - if (eReflowReason_Incremental == reason) { - InitFloat((nsPlaceholderFrame*)aFrame, aReflowStatus); - } - else { - AddFloat((nsPlaceholderFrame*)aFrame, aReflowStatus); - } - if (outOfFlowFrame->GetType() == nsLayoutAtoms::letterFrame) { - SetFlag(LL_FIRSTLETTERSTYLEOK, PR_FALSE); - // An incomplete reflow status means we should split the - // float if the height is constrained (bug 145305). We - // never split floating first letters. - if (NS_FRAME_IS_NOT_COMPLETE(aReflowStatus)) - aReflowStatus = NS_FRAME_COMPLETE; - } + nsPlaceholderFrame* placeholder = NS_STATIC_CAST(nsPlaceholderFrame*, aFrame); + if (eReflowReason_Incremental == reason) { + InitFloat(placeholder, aReflowStatus); + } + else { + AddFloat(placeholder, aReflowStatus); + } + if (outOfFlowFrame->GetType() == nsLayoutAtoms::letterFrame) { + SetFlag(LL_FIRSTLETTERSTYLEOK, PR_FALSE); + // An incomplete reflow status means we should split the + // float if the height is constrained (bug 145305). We + // never split floating first letters. + if (NS_FRAME_IS_NOT_COMPLETE(aReflowStatus)) + aReflowStatus = NS_FRAME_COMPLETE; } } } diff --git a/mozilla/layout/generic/nsSpaceManager.cpp b/mozilla/layout/generic/nsSpaceManager.cpp index b58fc392fb4..10b14f8b049 100644 --- a/mozilla/layout/generic/nsSpaceManager.cpp +++ b/mozilla/layout/generic/nsSpaceManager.cpp @@ -46,6 +46,7 @@ #include "nsIPresShell.h" #include "nsMemory.h" #include "nsHTMLReflowState.h" +#include "nsHashSets.h" #ifdef DEBUG #include "nsIFrameDebug.h" #endif @@ -105,7 +106,6 @@ MOZ_DECL_CTOR_COUNTER(nsSpaceManager) nsSpaceManager::nsSpaceManager(nsIPresShell* aPresShell, nsIFrame* aFrame) : mFrame(aFrame), - mXMost(0), mLowestTop(NSCOORD_MIN), mFloatDamage(PSArenaAllocCB, PSArenaFreeCB, aPresShell) { @@ -199,7 +199,11 @@ void nsSpaceManager::Shutdown() PRBool nsSpaceManager::XMost(nscoord& aXMost) const { - aXMost = mXMost; + nscoord xMost = 0; + for (FrameInfo* fi = mFrameInfoMap; fi; fi = fi->mNext) { + xMost = PR_MAX(xMost, fi->mRect.XMost()); + } + aXMost = xMost; return !mBandList.IsEmpty(); } @@ -813,10 +817,6 @@ nsSpaceManager::AddRectRegion(nsIFrame* aFrame, const nsRect& aUnavailableSpace) nsRect rect(aUnavailableSpace.x + mX, aUnavailableSpace.y + mY, aUnavailableSpace.width, aUnavailableSpace.height); - nscoord xmost = rect.XMost(); - if (xmost > mXMost) - mXMost = xmost; - if (rect.y > mLowestTop) mLowestTop = rect.y; @@ -843,6 +843,30 @@ nsSpaceManager::AddRectRegion(nsIFrame* aFrame, const nsRect& aUnavailableSpace) return NS_OK; } +nsresult +nsSpaceManager::RemoveTrailingRegions(nsIFrame* aFrameList) { + nsVoidHashSet frameSet; + + frameSet.Init(1); + for (nsIFrame* f = aFrameList; f; f = f->GetNextSibling()) { + frameSet.Put(f); + } + + // Pop frame regions off as long as they're in the set of frames to + // remove + while (mFrameInfoMap && frameSet.Contains(mFrameInfoMap->mFrame)) { + RemoveRegion(mFrameInfoMap->mFrame); + } + +#ifdef DEBUG + for (FrameInfo* frameInfo = mFrameInfoMap; frameInfo; + frameInfo = frameInfo->mNext) { + NS_ASSERTION(!frameSet.Contains(frameInfo->mFrame), + "Frame region deletion was requested but we couldn't delete it"); + } +#endif +} + nsresult nsSpaceManager::RemoveRegion(nsIFrame* aFrame) { @@ -995,7 +1019,6 @@ nsSpaceManager::PushState() state->mX = mX; state->mY = mY; - state->mXMost = mXMost; state->mLowestTop = mLowestTop; if (mFrameInfoMap) { @@ -1042,7 +1065,6 @@ nsSpaceManager::PopState() mX = mSavedStates->mX; mY = mSavedStates->mY; - mXMost = mSavedStates->mXMost; mLowestTop = mSavedStates->mLowestTop; // Now that we've restored our state, pop the topmost diff --git a/mozilla/layout/generic/nsSpaceManager.h b/mozilla/layout/generic/nsSpaceManager.h index fb8e4589736..e825ad9cd0d 100644 --- a/mozilla/layout/generic/nsSpaceManager.h +++ b/mozilla/layout/generic/nsSpaceManager.h @@ -251,13 +251,28 @@ public: nsresult AddRectRegion(nsIFrame* aFrame, const nsRect& aUnavailableSpace); + /** + * Remove the regions associated with this floating frame and its + * next-sibling list. Some of the frames may never have been added; + * we just skip those. This is not fully general; it only works as + * long as the N frames to be removed are the last N frames to have + * been added; if there's a frame in the middle of them that should + * not be removed, YOU LOSE. + * + * This can only be done at the end of the life of this space manager. The only + * methods it is safe to call after this are XMost() and YMost(). + */ + nsresult RemoveTrailingRegions(nsIFrame* aFrameList); + +protected: /** * Remove the region associated with aFrane. * + * doesn't work in the general case! + * * Returns NS_OK if successful and NS_ERROR_INVALID_ARG if there is no region * tagged with aFrame */ -protected: /* doesn't work in the general case */ nsresult RemoveRegion(nsIFrame* aFrame); public: @@ -335,7 +350,6 @@ protected: struct SpaceManagerState { nscoord mX, mY; nsIFrame *mLastFrame; - nscoord mXMost; nscoord mLowestTop; SpaceManagerState *mNext; }; @@ -408,7 +422,6 @@ protected: nsIFrame* const mFrame; // frame associated with the space manager nscoord mX, mY; // translation from local to global coordinate space BandList mBandList; // header/sentinel for circular linked list of band rects - nscoord mXMost; nscoord mLowestTop; // the lowest *top* FrameInfo* mFrameInfoMap; nsIntervalSet mFloatDamage; diff --git a/mozilla/layout/html/base/src/nsBlockFrame.cpp b/mozilla/layout/html/base/src/nsBlockFrame.cpp index de4ab6f7672..eb78a3b9704 100644 --- a/mozilla/layout/html/base/src/nsBlockFrame.cpp +++ b/mozilla/layout/html/base/src/nsBlockFrame.cpp @@ -78,6 +78,7 @@ #ifdef ACCESSIBILITY #include "nsIAccessibilityService.h" #endif +#include "nsLayoutUtils.h" #ifdef IBMBIDI #include "nsBidiPresUtils.h" @@ -658,6 +659,12 @@ nsBlockFrame::Reflow(nsPresContext* aPresContext, FinishAndStoreOverflow(&aMetrics); +#ifdef DEBUG + if (gNoisy) { + gNoiseIndent--; + } +#endif + return NS_OK; } } @@ -921,8 +928,8 @@ nsBlockFrame::Reflow(nsPresContext* aPresContext, // XXX_perf get rid of this! This is one of the things that makes // incremental reflow O(N^2). - BuildFloatList(); - + BuildFloatList(state); + // Compute our final size ComputeFinalSize(aReflowState, state, aMetrics); FinishAndStoreOverflow(&aMetrics); @@ -2066,6 +2073,20 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState) return rv; } if (!keepGoing) { +#ifdef DEBUG + if (gNoisyReflow) { + gNoiseIndent--; + nsRect lca(line->GetCombinedArea()); + IndentBy(stdout, gNoiseIndent); + printf("line=%p mY=%d newBounds={%d,%d,%d,%d} newCombinedArea={%d,%d,%d,%d} deltaY=%d mPrevBottomMargin=%d childCount=%d\n", + NS_STATIC_CAST(void*, line.get()), aState.mY, + line->mBounds.x, line->mBounds.y, + line->mBounds.width, line->mBounds.height, + lca.x, lca.y, lca.width, lca.height, + deltaY, aState.mPrevBottomMargin.get(), + line->GetChildCount()); + } +#endif if (0 == line->GetChildCount()) { DeleteLine(aState, line, line_end); } @@ -6479,38 +6500,30 @@ nsBlockFrame::ReflowBullet(nsBlockReflowState& aState, // This is used to scan overflow frames for any float placeholders, // and add their floats to the list represented by aHead and aTail. We // only search the inline descendants. -static void CollectOverflowFloats(nsIFrame* aFrame, nsIFrame* aBlockParent, - nsIFrame** aHead, nsIFrame** aTail) { +static void CollectFloats(nsIFrame* aFrame, nsIFrame* aBlockParent, + nsIFrame** aHead, nsIFrame** aTail) { while (aFrame) { // Don't descend into block children if (!aFrame->GetStyleDisplay()->IsBlockLevel()) { - if (nsLayoutAtoms::placeholderFrame == aFrame->GetType()) { - nsIFrame *outOfFlowFrame = - NS_STATIC_CAST(nsPlaceholderFrame*, aFrame)->GetOutOfFlowFrame(); + nsIFrame *outOfFlowFrame = nsLayoutUtils::GetFloatFromPlaceholder(aFrame); + if (outOfFlowFrame) { // Make sure that its parent is the block we care // about. Otherwise we don't want to mess around with it because // it belongs to someone else. I think this could happen if the // overflow lines contain a block descendant which owns its own // floats. - if (outOfFlowFrame && - !outOfFlowFrame->GetStyleDisplay()->IsAbsolutelyPositioned()) { - NS_ASSERTION(outOfFlowFrame->GetParent() == aBlockParent, - "Out of flow frame doesn't have the expected parent"); - // It's not an absolute or fixed positioned frame, so it must - // be a float! - // XXX This is a lame-o way of detecting a float, but it's the - // only way apparently - if (!*aHead) { - *aHead = *aTail = outOfFlowFrame; - } else { - (*aTail)->SetNextSibling(outOfFlowFrame); - *aTail = outOfFlowFrame; - } + NS_ASSERTION(outOfFlowFrame->GetParent() == aBlockParent, + "Out of flow frame doesn't have the expected parent"); + if (!*aHead) { + *aHead = *aTail = outOfFlowFrame; + } else { + (*aTail)->SetNextSibling(outOfFlowFrame); + *aTail = outOfFlowFrame; } } - CollectOverflowFloats(aFrame->GetFirstChild(nsnull), aBlockParent, - aHead, aTail); + CollectFloats(aFrame->GetFirstChild(nsnull), aBlockParent, + aHead, aTail); } aFrame = aFrame->GetNextSibling(); @@ -6519,7 +6532,7 @@ static void CollectOverflowFloats(nsIFrame* aFrame, nsIFrame* aBlockParent, //XXX get rid of this -- its slow void -nsBlockFrame::BuildFloatList() +nsBlockFrame::BuildFloatList(nsBlockReflowState& aState) { // Accumulate float list into mFloats. // Use the float cache to speed up searching the lines for floats. @@ -6558,11 +6571,24 @@ nsBlockFrame::BuildFloatList() head = nsnull; current = nsnull; - CollectOverflowFloats(overflowLines->front()->mFirstChild, - this, &head, ¤t); + CollectFloats(overflowLines->front()->mFirstChild, + this, &head, ¤t); if (current) { current->SetNextSibling(nsnull); + + // Floats that were pushed should be removed from our space + // manager. Otherwise the space manager's YMost or XMost might + // be larger than necessary, causing this block to get an + // incorrect desired height (or width). Some of these floats + // may not actually have been added to the space manager because + // they weren't reflowed before being pushed; that's OK, + // RemoveRegions will ignore them. It is safe to do this here + // because we know from here on the space manager will only be + // used for its XMost and YMost, not to place new floats and + // lines. + aState.mSpaceManager->RemoveTrailingRegions(head); + nsFrameList* frameList = new nsFrameList(head); if (frameList) { SetOverflowOutOfFlows(frameList); diff --git a/mozilla/layout/html/base/src/nsBlockFrame.h b/mozilla/layout/html/base/src/nsBlockFrame.h index 73177fde2dc..d42dcfc7811 100644 --- a/mozilla/layout/html/base/src/nsBlockFrame.h +++ b/mozilla/layout/html/base/src/nsBlockFrame.h @@ -518,7 +518,7 @@ protected: nsLineBox* aLine, nscoord aDeltaY); - void BuildFloatList(); + void BuildFloatList(nsBlockReflowState& aState); //---------------------------------------- // List handling kludge diff --git a/mozilla/layout/html/base/src/nsBlockReflowState.cpp b/mozilla/layout/html/base/src/nsBlockReflowState.cpp index e90efc276c5..c644b5d9a86 100644 --- a/mozilla/layout/html/base/src/nsBlockReflowState.cpp +++ b/mozilla/layout/html/base/src/nsBlockReflowState.cpp @@ -818,7 +818,7 @@ nsBlockReflowState::CanPlaceFloat(const nsRect& aFloatRect, } void -nsBlockReflowState::FlowAndPlaceFloat(nsFloatCache* aFloatCache, +nsBlockReflowState::FlowAndPlaceFloat(nsFloatCache* aFloatCache, PRBool* aIsLeftFloat, nsReflowStatus& aReflowStatus) { @@ -858,6 +858,9 @@ nsBlockReflowState::FlowAndPlaceFloat(nsFloatCache* aFloatCache, GetAvailableSpace(); } + NS_ASSERTION(floatFrame->GetParent() == mBlock, + "Float frame has wrong parent"); + // Reflow the float mBlock->ReflowFloat(*this, placeholder, aFloatCache, aReflowStatus); diff --git a/mozilla/layout/html/base/src/nsLineLayout.cpp b/mozilla/layout/html/base/src/nsLineLayout.cpp index c7d204173c3..03e94b4c984 100644 --- a/mozilla/layout/html/base/src/nsLineLayout.cpp +++ b/mozilla/layout/html/base/src/nsLineLayout.cpp @@ -65,6 +65,7 @@ #include "nsHTMLAtoms.h" #include "nsTextFragment.h" #include "nsBidiUtils.h" +#include "nsLayoutUtils.h" #ifdef DEBUG #undef NOISY_HORIZONTAL_ALIGN @@ -1003,25 +1004,22 @@ nsLineLayout::ReflowFrame(nsIFrame* aFrame, if (frameType) { if (nsLayoutAtoms::placeholderFrame == frameType) { pfd->SetFlag(PFD_ISPLACEHOLDERFRAME, PR_TRUE); - nsIFrame* outOfFlowFrame = ((nsPlaceholderFrame*)aFrame)->GetOutOfFlowFrame(); + nsIFrame* outOfFlowFrame = nsLayoutUtils::GetFloatFromPlaceholder(aFrame); if (outOfFlowFrame) { - // Make sure it's floated and not absolutely positioned - const nsStyleDisplay* display = outOfFlowFrame->GetStyleDisplay(); - if (!display->IsAbsolutelyPositioned()) { - if (eReflowReason_Incremental == reason) { - InitFloat((nsPlaceholderFrame*)aFrame, aReflowStatus); - } - else { - AddFloat((nsPlaceholderFrame*)aFrame, aReflowStatus); - } - if (outOfFlowFrame->GetType() == nsLayoutAtoms::letterFrame) { - SetFlag(LL_FIRSTLETTERSTYLEOK, PR_FALSE); - // An incomplete reflow status means we should split the - // float if the height is constrained (bug 145305). We - // never split floating first letters. - if (NS_FRAME_IS_NOT_COMPLETE(aReflowStatus)) - aReflowStatus = NS_FRAME_COMPLETE; - } + nsPlaceholderFrame* placeholder = NS_STATIC_CAST(nsPlaceholderFrame*, aFrame); + if (eReflowReason_Incremental == reason) { + InitFloat(placeholder, aReflowStatus); + } + else { + AddFloat(placeholder, aReflowStatus); + } + if (outOfFlowFrame->GetType() == nsLayoutAtoms::letterFrame) { + SetFlag(LL_FIRSTLETTERSTYLEOK, PR_FALSE); + // An incomplete reflow status means we should split the + // float if the height is constrained (bug 145305). We + // never split floating first letters. + if (NS_FRAME_IS_NOT_COMPLETE(aReflowStatus)) + aReflowStatus = NS_FRAME_COMPLETE; } } }