Bug 523468. Make sure we reflow the next line when content is pushed or pulled from an inline frame. r=dbaron

This commit is contained in:
Robert O'Callahan 2009-10-27 14:43:56 +13:00
parent 45ab6b1eff
commit 40e5fe01a0
8 changed files with 73 additions and 32 deletions

View File

@ -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<nsBlockFrame*>(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();
}
}
}

View File

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

View File

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

View File

@ -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;

View File

@ -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) {

View File

@ -0,0 +1,8 @@
<!DOCTYPE html>
<html>
<body>
c<br>
da<br>
b
</body>
</html>

View File

@ -0,0 +1,10 @@
<!DOCTYPE HTML>
<html style="width:1px">
<body><span><span id="y"></span>a b</span>
<script>
var y = document.getElementById("y");
document.documentElement.offsetHeight;
y.appendChild(document.createTextNode("c d"));
</script>
</body>
</html>

View File

@ -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