From 132bf4d93dbe786ba91abe70ebe9c7e1e176e01a Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Tue, 27 Oct 2009 14:43:56 +1300 Subject: [PATCH] Bug 523468. Make sure we reflow the next line when content is pushed or pulled from an inline frame. r=dbaron --- layout/generic/nsBlockFrame.cpp | 40 +++++++++++++++----------- layout/generic/nsInlineFrame.cpp | 16 ++++++++--- layout/generic/nsInlineFrame.h | 5 +++- layout/generic/nsLineLayout.h | 12 +++++++- layout/generic/nsTextFrameThebes.cpp | 9 +----- layout/reftests/bugs/523468-1-ref.html | 8 ++++++ layout/reftests/bugs/523468-1.html | 10 +++++++ layout/reftests/bugs/reftest.list | 5 ++-- 8 files changed, 73 insertions(+), 32 deletions(-) create mode 100644 layout/reftests/bugs/523468-1-ref.html create mode 100644 layout/reftests/bugs/523468-1.html diff --git a/layout/generic/nsBlockFrame.cpp b/layout/generic/nsBlockFrame.cpp index 3c900f3f4457..047a0f762369 100644 --- a/layout/generic/nsBlockFrame.cpp +++ b/layout/generic/nsBlockFrame.cpp @@ -3683,6 +3683,28 @@ nsBlockFrame::DoReflowInlineFrames(nsBlockReflowState& aState, printf("Line reflow status = %s\n", LineReflowStatusNames[lineReflowStatus]); } #endif + + if (aLineLayout.GetDirtyNextLine()) { + // aLine may have been pushed to the overflow lines. + nsLineList* overflowLines = GetOverflowLines(); + // We can't just compare iterators front() to aLine here, since they may be in + // different lists. + PRBool pushedToOverflowLines = overflowLines && + overflowLines->front() == aLine.get(); + if (pushedToOverflowLines) { + // aLine is stale, it's associated with the main line list but it should + // be associated with the overflow line list now + aLine = overflowLines->begin(); + } + nsBlockInFlowLineIterator iter(this, aLine, pushedToOverflowLines); + if (iter.Next() && iter.GetLine()->IsInline()) { + iter.GetLine()->MarkDirty(); + if (iter.GetContainer() != this) { + aState.mReflowStatus |= NS_FRAME_REFLOW_NEXTINFLOW; + } + } + } + *aLineReflowStatus = lineReflowStatus; return rv; @@ -3723,16 +3745,7 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState, NS_ENSURE_SUCCESS(rv, rv); if (frameReflowStatus & NS_FRAME_REFLOW_NEXTINFLOW) { - // we need to ensure that the frame's nextinflow gets reflowed. - aState.mReflowStatus |= NS_FRAME_REFLOW_NEXTINFLOW; - nsBlockFrame* ourNext = static_cast(GetNextInFlow()); - if (ourNext && aFrame->GetNextInFlow()) { - PRBool isValid; - nsBlockInFlowLineIterator iter(ourNext, aFrame->GetNextInFlow(), &isValid); - if (isValid) { - iter.GetLine()->MarkDirty(); - } - } + aLineLayout.SetDirtyNextLine(); } NS_ENSURE_SUCCESS(rv, rv); @@ -3819,12 +3832,7 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState, if (NS_INLINE_IS_BREAK_AFTER(frameReflowStatus) && !aLineLayout.GetLineEndsInBR()) { - // Mark next line dirty in case SplitLine didn't end up - // pushing any frames. - nsLineList_iterator next = aLine.next(); - if (next != end_lines() && !next->IsBlock()) { - next->MarkDirty(); - } + aLineLayout.SetDirtyNextLine(); } } } diff --git a/layout/generic/nsInlineFrame.cpp b/layout/generic/nsInlineFrame.cpp index 816d63e3006f..f6ffec499502 100644 --- a/layout/generic/nsInlineFrame.cpp +++ b/layout/generic/nsInlineFrame.cpp @@ -400,6 +400,7 @@ nsInlineFrame::Reflow(nsPresContext* aPresContext, InlineReflowState irs; irs.mPrevFrame = nsnull; irs.mLineContainer = lineContainer; + irs.mLineLayout = aReflowState.mLineLayout; irs.mNextInFlow = (nsInlineFrame*) GetNextInFlow(); irs.mSetParentPointer = lazilySetParentPointer; @@ -693,7 +694,7 @@ nsInlineFrame::ReflowInlineFrame(nsPresContext* aPresContext, aStatus = NS_FRAME_NOT_COMPLETE | NS_INLINE_BREAK | NS_INLINE_BREAK_AFTER | (aStatus & NS_INLINE_BREAK_TYPE_MASK); - PushFrames(aPresContext, aFrame, irs.mPrevFrame); + PushFrames(aPresContext, aFrame, irs.mPrevFrame, irs); } else { // Preserve reflow status when breaking-before our first child @@ -725,7 +726,7 @@ nsInlineFrame::ReflowInlineFrame(nsPresContext* aPresContext, nsIFrame* nextFrame = aFrame->GetNextSibling(); if (nextFrame) { NS_FRAME_SET_INCOMPLETE(aStatus); - PushFrames(aPresContext, nextFrame, aFrame); + PushFrames(aPresContext, nextFrame, aFrame, irs); } else if (nsnull != GetNextInFlow()) { // We must return an incomplete status if there are more child @@ -759,7 +760,7 @@ nsInlineFrame::ReflowInlineFrame(nsPresContext* aPresContext, if (!reflowingFirstLetter) { nsIFrame* nextFrame = aFrame->GetNextSibling(); if (nextFrame) { - PushFrames(aPresContext, nextFrame, aFrame); + PushFrames(aPresContext, nextFrame, aFrame, irs); } } } @@ -791,6 +792,9 @@ nsInlineFrame::PullOneFrame(nsPresContext* aPresContext, nextInFlow->mFrames.RemoveFirstChild(); mFrames.InsertFrame(this, irs.mPrevFrame, frame); isComplete = PR_FALSE; + if (irs.mLineLayout) { + irs.mLineLayout->SetDirtyNextLine(); + } nsHTMLContainerFrame::ReparentFrameView(aPresContext, frame, nextInFlow, this); break; } @@ -805,7 +809,8 @@ nsInlineFrame::PullOneFrame(nsPresContext* aPresContext, void nsInlineFrame::PushFrames(nsPresContext* aPresContext, nsIFrame* aFromChild, - nsIFrame* aPrevSibling) + nsIFrame* aPrevSibling, + InlineReflowState& aState) { NS_PRECONDITION(aFromChild, "null pointer"); NS_PRECONDITION(aPrevSibling, "pushing first child"); @@ -819,6 +824,9 @@ nsInlineFrame::PushFrames(nsPresContext* aPresContext, // Add the frames to our overflow list (let our next in flow drain // our overflow list when it is ready) SetOverflowFrames(aPresContext, mFrames.RemoveFramesAfter(aPrevSibling)); + if (aState.mLineLayout) { + aState.mLineLayout->SetDirtyNextLine(); + } } diff --git a/layout/generic/nsInlineFrame.h b/layout/generic/nsInlineFrame.h index d94c72a88226..aaed4326f345 100644 --- a/layout/generic/nsInlineFrame.h +++ b/layout/generic/nsInlineFrame.h @@ -154,6 +154,7 @@ protected: nsIFrame* mPrevFrame; nsInlineFrame* mNextInFlow; nsIFrame* mLineContainer; + nsLineLayout* mLineLayout; PRPackedBool mSetParentPointer; // when reflowing child frame first set its // parent frame pointer @@ -161,6 +162,7 @@ protected: mPrevFrame = nsnull; mNextInFlow = nsnull; mLineContainer = nsnull; + mLineLayout = nsnull; mSetParentPointer = PR_FALSE; } }; @@ -196,7 +198,8 @@ protected: virtual void PushFrames(nsPresContext* aPresContext, nsIFrame* aFromChild, - nsIFrame* aPrevSibling); + nsIFrame* aPrevSibling, + InlineReflowState& aState); }; diff --git a/layout/generic/nsLineLayout.h b/layout/generic/nsLineLayout.h index 1028e97d9490..04b535bffd1f 100644 --- a/layout/generic/nsLineLayout.h +++ b/layout/generic/nsLineLayout.h @@ -156,7 +156,8 @@ protected: #define LL_GOTLINEBOX 0x00001000 #define LL_INFIRSTLETTER 0x00002000 #define LL_HASBULLET 0x00004000 -#define LL_LASTFLAG LL_HASBULLET +#define LL_DIRTYNEXTLINE 0x00008000 +#define LL_LASTFLAG LL_DIRTYNEXTLINE void SetFlag(PRUint32 aFlag, PRBool aValue) { @@ -246,6 +247,15 @@ public: SetFlag(LL_INFIRSTLINE, aSetting); } + // Calling this during block reflow ensures that the next line of inlines + // will be marked dirty, if there is one. + void SetDirtyNextLine() { + SetFlag(LL_DIRTYNEXTLINE, PR_TRUE); + } + PRBool GetDirtyNextLine() { + return GetFlag(LL_DIRTYNEXTLINE); + } + //---------------------------------------- nsPresContext* mPresContext; diff --git a/layout/generic/nsTextFrameThebes.cpp b/layout/generic/nsTextFrameThebes.cpp index a92358383571..c2ed65b38aaf 100644 --- a/layout/generic/nsTextFrameThebes.cpp +++ b/layout/generic/nsTextFrameThebes.cpp @@ -5987,14 +5987,7 @@ nsTextFrame::SetLength(PRInt32 aLength, nsLineLayout* aLineLayout) // and ChildIsDirty to handle a range of frames would be worse. if (aLineLayout && (end != f->mContentOffset || (f->GetStateBits() & NS_FRAME_IS_DIRTY))) { - const nsLineList::iterator* line = aLineLayout->GetLine(); - nsBlockFrame* block = do_QueryFrame(aLineLayout->GetLineContainerFrame()); - if (line && block) { - nsLineList::iterator next = line->next(); - if (next != block->end_lines() && !next->IsBlock()) { - next->MarkDirty(); - } - } + aLineLayout->SetDirtyNextLine(); } if (end < f->mContentOffset) { diff --git a/layout/reftests/bugs/523468-1-ref.html b/layout/reftests/bugs/523468-1-ref.html new file mode 100644 index 000000000000..d396cde11f04 --- /dev/null +++ b/layout/reftests/bugs/523468-1-ref.html @@ -0,0 +1,8 @@ + + + +c
+da
+b + + diff --git a/layout/reftests/bugs/523468-1.html b/layout/reftests/bugs/523468-1.html new file mode 100644 index 000000000000..4d428d927d39 --- /dev/null +++ b/layout/reftests/bugs/523468-1.html @@ -0,0 +1,10 @@ + + +a b + + + diff --git a/layout/reftests/bugs/reftest.list b/layout/reftests/bugs/reftest.list index bd96c6652df6..a25dfceb3151 100644 --- a/layout/reftests/bugs/reftest.list +++ b/layout/reftests/bugs/reftest.list @@ -1325,11 +1325,12 @@ fails-if(MOZ_WIDGET_TOOLKIT!="cocoa") == 488692-1.html 488692-1-ref.html # needs == 513318-1.xul 513318-1-ref.xul != 513318-2.xul 513318-2-ref.xul != 513318-3.xul 513318-3-ref.xul +== 520421-1.html 520421-1-ref.html == 520563-1.xhtml 520563-1-ref.xhtml == 521525-1.html 521525-1-ref.html == 521525-2.html 521525-2-ref.html == 521539-1.html 521539-1-ref.html -== 520421-1.html 520421-1-ref.html == 521685-1.html 521685-1-ref.html -== 524175-1.html 524175-1-ref.html == 523096-1.html 523096-1-ref.html +== 523468-1.html 523468-1-ref.html +== 524175-1.html 524175-1-ref.html