From 8876d68b6fedb8bc9ad54f12820b5f0131c6d249 Mon Sep 17 00:00:00 2001 From: "buster%netscape.com" Date: Tue, 22 Feb 2000 22:06:19 +0000 Subject: [PATCH] fixed bug 25510 and 28084 r=troy a=jar git-svn-id: svn://10.0.0.236/trunk@61440 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/layout/generic/nsBlockFrame.cpp | 90 +++++++++++++++---- mozilla/layout/generic/nsBlockReflowState.cpp | 90 +++++++++++++++---- mozilla/layout/generic/nsBlockReflowState.h | 90 +++++++++++++++---- mozilla/layout/html/base/src/nsBlockFrame.cpp | 90 +++++++++++++++---- .../html/base/src/nsBlockReflowState.cpp | 90 +++++++++++++++---- .../layout/html/base/src/nsBlockReflowState.h | 90 +++++++++++++++---- 6 files changed, 426 insertions(+), 114 deletions(-) diff --git a/mozilla/layout/generic/nsBlockFrame.cpp b/mozilla/layout/generic/nsBlockFrame.cpp index a39729ff592..7b3cc5630b3 100644 --- a/mozilla/layout/generic/nsBlockFrame.cpp +++ b/mozilla/layout/generic/nsBlockFrame.cpp @@ -451,6 +451,7 @@ public: PRPackedBool mUnconstrainedHeight; PRPackedBool mShrinkWrapWidth; PRPackedBool mNeedResizeReflow; + PRPackedBool mIsInlineIncrReflow; // The content area to reflow child frames within. The x/y // coordinates are known to be mBorderPadding.left and @@ -579,7 +580,8 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState, mPrevBottomMargin(0), mFreeLineList(nsnull), mLineNumber(0), - mNeedResizeReflow(PR_FALSE) + mNeedResizeReflow(PR_FALSE), + mIsInlineIncrReflow(PR_FALSE) { const nsMargin& borderPadding = BorderPadding(); @@ -1463,6 +1465,7 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext, nsresult rv = NS_OK; PRBool isStyleChange = PR_FALSE; + state.mIsInlineIncrReflow = PR_FALSE; nsIFrame* target; switch (aReflowState.reason) { case eReflowReason_Initial: @@ -1518,6 +1521,7 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext, // in the normal case, this just marks the line dirty // but, it causes an incremental reflow targeted at a frame // inside a continued span to get dropped on the floor. see bug 25510 + // This will be yanked as soon as we have high confidence in the enabled code below rv = PrepareChildIncrementalReflow(state); #else // this code does a correct job of propogating incremental reflows (bug 25510) @@ -1531,21 +1535,35 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext, { if (!isFloater) // punt if isFloater! { - nsBlockReflowState incrState(aReflowState, aPresContext, this, aMetrics, - NS_BLOCK_MARGIN_ROOT & mState); - incrState.mNextRCFrame = state.mNextRCFrame; - PRBool keepGoing; - rv = ReflowLine(incrState, line, &keepGoing, PR_TRUE); - line->RemoveFloatersFromSpaceManager(aReflowState.mSpaceManager); - state.mNextRCFrame = nsnull; + // reflow the line containing the target of the incr. reflow + // first mark the line dirty and set up the state object + rv = PrepareChildIncrementalReflow(state); + state.mIsInlineIncrReflow = PR_TRUE; + state.mPrevLine = prevLine; + state.mCurrentLine = line; + state.mNextRCFrame = state.mNextRCFrame; + // let ReflowDirtyLines do all the work + rv = ReflowDirtyLines(state); + if (NS_FAILED(rv)) { + NS_ASSERTION(0, "Reflow failed\n"); + return rv; + } + // compute the final size + ComputeFinalSize(aReflowState, state, aMetrics); + + // finally, mark this block frame as having a dirty child and return + // XXX: we should be able to optimize this so we only call ReflowDirtyChild + // if it's absolutely necessary: something on the line changed size. + nsCOMPtr shell; + aPresContext->GetShell(getter_AddRefs(shell)); + rv = ReflowDirtyChild(shell, state.mNextRCFrame); + //XXX: it's possible we need to do some work regarding incremental painting + // here, see code below "ReflowDirtyLines() after this switch statement. + // It might be right to factor the tail end of this method into a new method + // and call that here before calling ReflowDirtyChild(). + return rv; } } - // XXX To Do: we need to check some metrics here to see if anything changed - // if nothing changed, we're done - // otherwise, we should mark the line and the previous line both dirty - // and do a resize reflow - // Now just mark the line dirty every time. We call PrepareChildIncrementalReflow - // because it includes a hack for floaters that we don't want to duplicate here. rv = PrepareChildIncrementalReflow(state); #endif } @@ -1562,8 +1580,17 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext, break; } + if (NS_FAILED(rv)) { + NS_ASSERTION(0, "setting up reflow failed.\n"); + return rv; + } + // Now reflow... rv = ReflowDirtyLines(state); + if (NS_FAILED(rv)) { + NS_ASSERTION(0, "reflow dirty lines failed.\n"); + return rv; + } aStatus = state.mReflowStatus; if (NS_FRAME_IS_NOT_COMPLETE(aStatus)) { if (NS_STYLE_OVERFLOW_HIDDEN == aReflowState.mStyleDisplay->mOverflow) { @@ -2567,8 +2594,9 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState) aState.mReflowState.reflowCommand->GetType(type); IndentBy(stdout, gNoiseIndent); ListTag(stdout); - printf(": incrementally reflowing dirty lines: type=%s(%d)", - kReflowCommandType[type], type); + printf(": incrementally reflowing dirty lines: type=%s(%d) isInline=%s", + kReflowCommandType[type], type, + aState.mIsInlineIncrReflow ? "true" : "false"); } else { IndentBy(stdout, gNoiseIndent); @@ -2586,10 +2614,30 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState) aState.mReflowState.reason == eReflowReason_Dirty; + nscoord deltaY = 0; + // Reflow the lines that are already ours aState.mPrevLine = nsnull; nsLineBox* line = mLines; - nscoord deltaY = 0; + if (aState.mIsInlineIncrReflow && aState.mNextRCFrame) + { + const nsLineBox* incrTargetLine = aState.mCurrentLine; + aState.mCurrentLine = line; + aState.mPrevLine = nsnull; + while (line && (line != incrTargetLine)) + { + nsRect damageRect; + RecoverStateFrom(aState, line, deltaY, incrementalReflow ? + &damageRect : 0); + if (incrementalReflow && !damageRect.IsEmpty()) { + Invalidate(aState.mPresContext, damageRect); + } + aState.mPrevLine = line; + line = line->mNext; + aState.AdvanceToNextLine(); + } + } + while (nsnull != line) { #ifdef DEBUG if (gNoisyReflow) { @@ -2623,6 +2671,10 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState) if (NS_FAILED(rv)) { return rv; } + if (!(NS_FRAME_IS_COMPLETE(aState.mReflowStatus))) + { + printf("line %p is not complete\n", line); + } if (!keepGoing) { if (0 == line->GetChildCount()) { DeleteLine(aState, line); @@ -3522,7 +3574,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState, // Try to place the child block PRBool isAdjacentWithTop = aState.IsAdjacentWithTop(); nscoord collapsedBottomMargin; - nsRect combinedArea; + nsRect combinedArea(0,0,0,0); *aKeepReflowGoing = brc.PlaceBlock(isAdjacentWithTop, computedOffsets, &collapsedBottomMargin, aLine->mBounds, combinedArea); @@ -4356,7 +4408,7 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState, // Stop reflow and whack the reflow status if reflow hasn't // already been stopped. if (*aKeepReflowGoing) { - NS_ASSERTION(NS_FRAME_COMPLETE == aState.mReflowStatus, + NS_ASSERTION(NS_FRAME_COMPLETE == aState.mReflowStatus, "lost reflow status"); aState.mReflowStatus = NS_FRAME_NOT_COMPLETE; *aKeepReflowGoing = PR_FALSE; diff --git a/mozilla/layout/generic/nsBlockReflowState.cpp b/mozilla/layout/generic/nsBlockReflowState.cpp index a39729ff592..7b3cc5630b3 100644 --- a/mozilla/layout/generic/nsBlockReflowState.cpp +++ b/mozilla/layout/generic/nsBlockReflowState.cpp @@ -451,6 +451,7 @@ public: PRPackedBool mUnconstrainedHeight; PRPackedBool mShrinkWrapWidth; PRPackedBool mNeedResizeReflow; + PRPackedBool mIsInlineIncrReflow; // The content area to reflow child frames within. The x/y // coordinates are known to be mBorderPadding.left and @@ -579,7 +580,8 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState, mPrevBottomMargin(0), mFreeLineList(nsnull), mLineNumber(0), - mNeedResizeReflow(PR_FALSE) + mNeedResizeReflow(PR_FALSE), + mIsInlineIncrReflow(PR_FALSE) { const nsMargin& borderPadding = BorderPadding(); @@ -1463,6 +1465,7 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext, nsresult rv = NS_OK; PRBool isStyleChange = PR_FALSE; + state.mIsInlineIncrReflow = PR_FALSE; nsIFrame* target; switch (aReflowState.reason) { case eReflowReason_Initial: @@ -1518,6 +1521,7 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext, // in the normal case, this just marks the line dirty // but, it causes an incremental reflow targeted at a frame // inside a continued span to get dropped on the floor. see bug 25510 + // This will be yanked as soon as we have high confidence in the enabled code below rv = PrepareChildIncrementalReflow(state); #else // this code does a correct job of propogating incremental reflows (bug 25510) @@ -1531,21 +1535,35 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext, { if (!isFloater) // punt if isFloater! { - nsBlockReflowState incrState(aReflowState, aPresContext, this, aMetrics, - NS_BLOCK_MARGIN_ROOT & mState); - incrState.mNextRCFrame = state.mNextRCFrame; - PRBool keepGoing; - rv = ReflowLine(incrState, line, &keepGoing, PR_TRUE); - line->RemoveFloatersFromSpaceManager(aReflowState.mSpaceManager); - state.mNextRCFrame = nsnull; + // reflow the line containing the target of the incr. reflow + // first mark the line dirty and set up the state object + rv = PrepareChildIncrementalReflow(state); + state.mIsInlineIncrReflow = PR_TRUE; + state.mPrevLine = prevLine; + state.mCurrentLine = line; + state.mNextRCFrame = state.mNextRCFrame; + // let ReflowDirtyLines do all the work + rv = ReflowDirtyLines(state); + if (NS_FAILED(rv)) { + NS_ASSERTION(0, "Reflow failed\n"); + return rv; + } + // compute the final size + ComputeFinalSize(aReflowState, state, aMetrics); + + // finally, mark this block frame as having a dirty child and return + // XXX: we should be able to optimize this so we only call ReflowDirtyChild + // if it's absolutely necessary: something on the line changed size. + nsCOMPtr shell; + aPresContext->GetShell(getter_AddRefs(shell)); + rv = ReflowDirtyChild(shell, state.mNextRCFrame); + //XXX: it's possible we need to do some work regarding incremental painting + // here, see code below "ReflowDirtyLines() after this switch statement. + // It might be right to factor the tail end of this method into a new method + // and call that here before calling ReflowDirtyChild(). + return rv; } } - // XXX To Do: we need to check some metrics here to see if anything changed - // if nothing changed, we're done - // otherwise, we should mark the line and the previous line both dirty - // and do a resize reflow - // Now just mark the line dirty every time. We call PrepareChildIncrementalReflow - // because it includes a hack for floaters that we don't want to duplicate here. rv = PrepareChildIncrementalReflow(state); #endif } @@ -1562,8 +1580,17 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext, break; } + if (NS_FAILED(rv)) { + NS_ASSERTION(0, "setting up reflow failed.\n"); + return rv; + } + // Now reflow... rv = ReflowDirtyLines(state); + if (NS_FAILED(rv)) { + NS_ASSERTION(0, "reflow dirty lines failed.\n"); + return rv; + } aStatus = state.mReflowStatus; if (NS_FRAME_IS_NOT_COMPLETE(aStatus)) { if (NS_STYLE_OVERFLOW_HIDDEN == aReflowState.mStyleDisplay->mOverflow) { @@ -2567,8 +2594,9 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState) aState.mReflowState.reflowCommand->GetType(type); IndentBy(stdout, gNoiseIndent); ListTag(stdout); - printf(": incrementally reflowing dirty lines: type=%s(%d)", - kReflowCommandType[type], type); + printf(": incrementally reflowing dirty lines: type=%s(%d) isInline=%s", + kReflowCommandType[type], type, + aState.mIsInlineIncrReflow ? "true" : "false"); } else { IndentBy(stdout, gNoiseIndent); @@ -2586,10 +2614,30 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState) aState.mReflowState.reason == eReflowReason_Dirty; + nscoord deltaY = 0; + // Reflow the lines that are already ours aState.mPrevLine = nsnull; nsLineBox* line = mLines; - nscoord deltaY = 0; + if (aState.mIsInlineIncrReflow && aState.mNextRCFrame) + { + const nsLineBox* incrTargetLine = aState.mCurrentLine; + aState.mCurrentLine = line; + aState.mPrevLine = nsnull; + while (line && (line != incrTargetLine)) + { + nsRect damageRect; + RecoverStateFrom(aState, line, deltaY, incrementalReflow ? + &damageRect : 0); + if (incrementalReflow && !damageRect.IsEmpty()) { + Invalidate(aState.mPresContext, damageRect); + } + aState.mPrevLine = line; + line = line->mNext; + aState.AdvanceToNextLine(); + } + } + while (nsnull != line) { #ifdef DEBUG if (gNoisyReflow) { @@ -2623,6 +2671,10 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState) if (NS_FAILED(rv)) { return rv; } + if (!(NS_FRAME_IS_COMPLETE(aState.mReflowStatus))) + { + printf("line %p is not complete\n", line); + } if (!keepGoing) { if (0 == line->GetChildCount()) { DeleteLine(aState, line); @@ -3522,7 +3574,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState, // Try to place the child block PRBool isAdjacentWithTop = aState.IsAdjacentWithTop(); nscoord collapsedBottomMargin; - nsRect combinedArea; + nsRect combinedArea(0,0,0,0); *aKeepReflowGoing = brc.PlaceBlock(isAdjacentWithTop, computedOffsets, &collapsedBottomMargin, aLine->mBounds, combinedArea); @@ -4356,7 +4408,7 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState, // Stop reflow and whack the reflow status if reflow hasn't // already been stopped. if (*aKeepReflowGoing) { - NS_ASSERTION(NS_FRAME_COMPLETE == aState.mReflowStatus, + NS_ASSERTION(NS_FRAME_COMPLETE == aState.mReflowStatus, "lost reflow status"); aState.mReflowStatus = NS_FRAME_NOT_COMPLETE; *aKeepReflowGoing = PR_FALSE; diff --git a/mozilla/layout/generic/nsBlockReflowState.h b/mozilla/layout/generic/nsBlockReflowState.h index a39729ff592..7b3cc5630b3 100644 --- a/mozilla/layout/generic/nsBlockReflowState.h +++ b/mozilla/layout/generic/nsBlockReflowState.h @@ -451,6 +451,7 @@ public: PRPackedBool mUnconstrainedHeight; PRPackedBool mShrinkWrapWidth; PRPackedBool mNeedResizeReflow; + PRPackedBool mIsInlineIncrReflow; // The content area to reflow child frames within. The x/y // coordinates are known to be mBorderPadding.left and @@ -579,7 +580,8 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState, mPrevBottomMargin(0), mFreeLineList(nsnull), mLineNumber(0), - mNeedResizeReflow(PR_FALSE) + mNeedResizeReflow(PR_FALSE), + mIsInlineIncrReflow(PR_FALSE) { const nsMargin& borderPadding = BorderPadding(); @@ -1463,6 +1465,7 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext, nsresult rv = NS_OK; PRBool isStyleChange = PR_FALSE; + state.mIsInlineIncrReflow = PR_FALSE; nsIFrame* target; switch (aReflowState.reason) { case eReflowReason_Initial: @@ -1518,6 +1521,7 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext, // in the normal case, this just marks the line dirty // but, it causes an incremental reflow targeted at a frame // inside a continued span to get dropped on the floor. see bug 25510 + // This will be yanked as soon as we have high confidence in the enabled code below rv = PrepareChildIncrementalReflow(state); #else // this code does a correct job of propogating incremental reflows (bug 25510) @@ -1531,21 +1535,35 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext, { if (!isFloater) // punt if isFloater! { - nsBlockReflowState incrState(aReflowState, aPresContext, this, aMetrics, - NS_BLOCK_MARGIN_ROOT & mState); - incrState.mNextRCFrame = state.mNextRCFrame; - PRBool keepGoing; - rv = ReflowLine(incrState, line, &keepGoing, PR_TRUE); - line->RemoveFloatersFromSpaceManager(aReflowState.mSpaceManager); - state.mNextRCFrame = nsnull; + // reflow the line containing the target of the incr. reflow + // first mark the line dirty and set up the state object + rv = PrepareChildIncrementalReflow(state); + state.mIsInlineIncrReflow = PR_TRUE; + state.mPrevLine = prevLine; + state.mCurrentLine = line; + state.mNextRCFrame = state.mNextRCFrame; + // let ReflowDirtyLines do all the work + rv = ReflowDirtyLines(state); + if (NS_FAILED(rv)) { + NS_ASSERTION(0, "Reflow failed\n"); + return rv; + } + // compute the final size + ComputeFinalSize(aReflowState, state, aMetrics); + + // finally, mark this block frame as having a dirty child and return + // XXX: we should be able to optimize this so we only call ReflowDirtyChild + // if it's absolutely necessary: something on the line changed size. + nsCOMPtr shell; + aPresContext->GetShell(getter_AddRefs(shell)); + rv = ReflowDirtyChild(shell, state.mNextRCFrame); + //XXX: it's possible we need to do some work regarding incremental painting + // here, see code below "ReflowDirtyLines() after this switch statement. + // It might be right to factor the tail end of this method into a new method + // and call that here before calling ReflowDirtyChild(). + return rv; } } - // XXX To Do: we need to check some metrics here to see if anything changed - // if nothing changed, we're done - // otherwise, we should mark the line and the previous line both dirty - // and do a resize reflow - // Now just mark the line dirty every time. We call PrepareChildIncrementalReflow - // because it includes a hack for floaters that we don't want to duplicate here. rv = PrepareChildIncrementalReflow(state); #endif } @@ -1562,8 +1580,17 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext, break; } + if (NS_FAILED(rv)) { + NS_ASSERTION(0, "setting up reflow failed.\n"); + return rv; + } + // Now reflow... rv = ReflowDirtyLines(state); + if (NS_FAILED(rv)) { + NS_ASSERTION(0, "reflow dirty lines failed.\n"); + return rv; + } aStatus = state.mReflowStatus; if (NS_FRAME_IS_NOT_COMPLETE(aStatus)) { if (NS_STYLE_OVERFLOW_HIDDEN == aReflowState.mStyleDisplay->mOverflow) { @@ -2567,8 +2594,9 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState) aState.mReflowState.reflowCommand->GetType(type); IndentBy(stdout, gNoiseIndent); ListTag(stdout); - printf(": incrementally reflowing dirty lines: type=%s(%d)", - kReflowCommandType[type], type); + printf(": incrementally reflowing dirty lines: type=%s(%d) isInline=%s", + kReflowCommandType[type], type, + aState.mIsInlineIncrReflow ? "true" : "false"); } else { IndentBy(stdout, gNoiseIndent); @@ -2586,10 +2614,30 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState) aState.mReflowState.reason == eReflowReason_Dirty; + nscoord deltaY = 0; + // Reflow the lines that are already ours aState.mPrevLine = nsnull; nsLineBox* line = mLines; - nscoord deltaY = 0; + if (aState.mIsInlineIncrReflow && aState.mNextRCFrame) + { + const nsLineBox* incrTargetLine = aState.mCurrentLine; + aState.mCurrentLine = line; + aState.mPrevLine = nsnull; + while (line && (line != incrTargetLine)) + { + nsRect damageRect; + RecoverStateFrom(aState, line, deltaY, incrementalReflow ? + &damageRect : 0); + if (incrementalReflow && !damageRect.IsEmpty()) { + Invalidate(aState.mPresContext, damageRect); + } + aState.mPrevLine = line; + line = line->mNext; + aState.AdvanceToNextLine(); + } + } + while (nsnull != line) { #ifdef DEBUG if (gNoisyReflow) { @@ -2623,6 +2671,10 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState) if (NS_FAILED(rv)) { return rv; } + if (!(NS_FRAME_IS_COMPLETE(aState.mReflowStatus))) + { + printf("line %p is not complete\n", line); + } if (!keepGoing) { if (0 == line->GetChildCount()) { DeleteLine(aState, line); @@ -3522,7 +3574,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState, // Try to place the child block PRBool isAdjacentWithTop = aState.IsAdjacentWithTop(); nscoord collapsedBottomMargin; - nsRect combinedArea; + nsRect combinedArea(0,0,0,0); *aKeepReflowGoing = brc.PlaceBlock(isAdjacentWithTop, computedOffsets, &collapsedBottomMargin, aLine->mBounds, combinedArea); @@ -4356,7 +4408,7 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState, // Stop reflow and whack the reflow status if reflow hasn't // already been stopped. if (*aKeepReflowGoing) { - NS_ASSERTION(NS_FRAME_COMPLETE == aState.mReflowStatus, + NS_ASSERTION(NS_FRAME_COMPLETE == aState.mReflowStatus, "lost reflow status"); aState.mReflowStatus = NS_FRAME_NOT_COMPLETE; *aKeepReflowGoing = PR_FALSE; diff --git a/mozilla/layout/html/base/src/nsBlockFrame.cpp b/mozilla/layout/html/base/src/nsBlockFrame.cpp index a39729ff592..7b3cc5630b3 100644 --- a/mozilla/layout/html/base/src/nsBlockFrame.cpp +++ b/mozilla/layout/html/base/src/nsBlockFrame.cpp @@ -451,6 +451,7 @@ public: PRPackedBool mUnconstrainedHeight; PRPackedBool mShrinkWrapWidth; PRPackedBool mNeedResizeReflow; + PRPackedBool mIsInlineIncrReflow; // The content area to reflow child frames within. The x/y // coordinates are known to be mBorderPadding.left and @@ -579,7 +580,8 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState, mPrevBottomMargin(0), mFreeLineList(nsnull), mLineNumber(0), - mNeedResizeReflow(PR_FALSE) + mNeedResizeReflow(PR_FALSE), + mIsInlineIncrReflow(PR_FALSE) { const nsMargin& borderPadding = BorderPadding(); @@ -1463,6 +1465,7 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext, nsresult rv = NS_OK; PRBool isStyleChange = PR_FALSE; + state.mIsInlineIncrReflow = PR_FALSE; nsIFrame* target; switch (aReflowState.reason) { case eReflowReason_Initial: @@ -1518,6 +1521,7 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext, // in the normal case, this just marks the line dirty // but, it causes an incremental reflow targeted at a frame // inside a continued span to get dropped on the floor. see bug 25510 + // This will be yanked as soon as we have high confidence in the enabled code below rv = PrepareChildIncrementalReflow(state); #else // this code does a correct job of propogating incremental reflows (bug 25510) @@ -1531,21 +1535,35 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext, { if (!isFloater) // punt if isFloater! { - nsBlockReflowState incrState(aReflowState, aPresContext, this, aMetrics, - NS_BLOCK_MARGIN_ROOT & mState); - incrState.mNextRCFrame = state.mNextRCFrame; - PRBool keepGoing; - rv = ReflowLine(incrState, line, &keepGoing, PR_TRUE); - line->RemoveFloatersFromSpaceManager(aReflowState.mSpaceManager); - state.mNextRCFrame = nsnull; + // reflow the line containing the target of the incr. reflow + // first mark the line dirty and set up the state object + rv = PrepareChildIncrementalReflow(state); + state.mIsInlineIncrReflow = PR_TRUE; + state.mPrevLine = prevLine; + state.mCurrentLine = line; + state.mNextRCFrame = state.mNextRCFrame; + // let ReflowDirtyLines do all the work + rv = ReflowDirtyLines(state); + if (NS_FAILED(rv)) { + NS_ASSERTION(0, "Reflow failed\n"); + return rv; + } + // compute the final size + ComputeFinalSize(aReflowState, state, aMetrics); + + // finally, mark this block frame as having a dirty child and return + // XXX: we should be able to optimize this so we only call ReflowDirtyChild + // if it's absolutely necessary: something on the line changed size. + nsCOMPtr shell; + aPresContext->GetShell(getter_AddRefs(shell)); + rv = ReflowDirtyChild(shell, state.mNextRCFrame); + //XXX: it's possible we need to do some work regarding incremental painting + // here, see code below "ReflowDirtyLines() after this switch statement. + // It might be right to factor the tail end of this method into a new method + // and call that here before calling ReflowDirtyChild(). + return rv; } } - // XXX To Do: we need to check some metrics here to see if anything changed - // if nothing changed, we're done - // otherwise, we should mark the line and the previous line both dirty - // and do a resize reflow - // Now just mark the line dirty every time. We call PrepareChildIncrementalReflow - // because it includes a hack for floaters that we don't want to duplicate here. rv = PrepareChildIncrementalReflow(state); #endif } @@ -1562,8 +1580,17 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext, break; } + if (NS_FAILED(rv)) { + NS_ASSERTION(0, "setting up reflow failed.\n"); + return rv; + } + // Now reflow... rv = ReflowDirtyLines(state); + if (NS_FAILED(rv)) { + NS_ASSERTION(0, "reflow dirty lines failed.\n"); + return rv; + } aStatus = state.mReflowStatus; if (NS_FRAME_IS_NOT_COMPLETE(aStatus)) { if (NS_STYLE_OVERFLOW_HIDDEN == aReflowState.mStyleDisplay->mOverflow) { @@ -2567,8 +2594,9 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState) aState.mReflowState.reflowCommand->GetType(type); IndentBy(stdout, gNoiseIndent); ListTag(stdout); - printf(": incrementally reflowing dirty lines: type=%s(%d)", - kReflowCommandType[type], type); + printf(": incrementally reflowing dirty lines: type=%s(%d) isInline=%s", + kReflowCommandType[type], type, + aState.mIsInlineIncrReflow ? "true" : "false"); } else { IndentBy(stdout, gNoiseIndent); @@ -2586,10 +2614,30 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState) aState.mReflowState.reason == eReflowReason_Dirty; + nscoord deltaY = 0; + // Reflow the lines that are already ours aState.mPrevLine = nsnull; nsLineBox* line = mLines; - nscoord deltaY = 0; + if (aState.mIsInlineIncrReflow && aState.mNextRCFrame) + { + const nsLineBox* incrTargetLine = aState.mCurrentLine; + aState.mCurrentLine = line; + aState.mPrevLine = nsnull; + while (line && (line != incrTargetLine)) + { + nsRect damageRect; + RecoverStateFrom(aState, line, deltaY, incrementalReflow ? + &damageRect : 0); + if (incrementalReflow && !damageRect.IsEmpty()) { + Invalidate(aState.mPresContext, damageRect); + } + aState.mPrevLine = line; + line = line->mNext; + aState.AdvanceToNextLine(); + } + } + while (nsnull != line) { #ifdef DEBUG if (gNoisyReflow) { @@ -2623,6 +2671,10 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState) if (NS_FAILED(rv)) { return rv; } + if (!(NS_FRAME_IS_COMPLETE(aState.mReflowStatus))) + { + printf("line %p is not complete\n", line); + } if (!keepGoing) { if (0 == line->GetChildCount()) { DeleteLine(aState, line); @@ -3522,7 +3574,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState, // Try to place the child block PRBool isAdjacentWithTop = aState.IsAdjacentWithTop(); nscoord collapsedBottomMargin; - nsRect combinedArea; + nsRect combinedArea(0,0,0,0); *aKeepReflowGoing = brc.PlaceBlock(isAdjacentWithTop, computedOffsets, &collapsedBottomMargin, aLine->mBounds, combinedArea); @@ -4356,7 +4408,7 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState, // Stop reflow and whack the reflow status if reflow hasn't // already been stopped. if (*aKeepReflowGoing) { - NS_ASSERTION(NS_FRAME_COMPLETE == aState.mReflowStatus, + NS_ASSERTION(NS_FRAME_COMPLETE == aState.mReflowStatus, "lost reflow status"); aState.mReflowStatus = NS_FRAME_NOT_COMPLETE; *aKeepReflowGoing = PR_FALSE; diff --git a/mozilla/layout/html/base/src/nsBlockReflowState.cpp b/mozilla/layout/html/base/src/nsBlockReflowState.cpp index a39729ff592..7b3cc5630b3 100644 --- a/mozilla/layout/html/base/src/nsBlockReflowState.cpp +++ b/mozilla/layout/html/base/src/nsBlockReflowState.cpp @@ -451,6 +451,7 @@ public: PRPackedBool mUnconstrainedHeight; PRPackedBool mShrinkWrapWidth; PRPackedBool mNeedResizeReflow; + PRPackedBool mIsInlineIncrReflow; // The content area to reflow child frames within. The x/y // coordinates are known to be mBorderPadding.left and @@ -579,7 +580,8 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState, mPrevBottomMargin(0), mFreeLineList(nsnull), mLineNumber(0), - mNeedResizeReflow(PR_FALSE) + mNeedResizeReflow(PR_FALSE), + mIsInlineIncrReflow(PR_FALSE) { const nsMargin& borderPadding = BorderPadding(); @@ -1463,6 +1465,7 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext, nsresult rv = NS_OK; PRBool isStyleChange = PR_FALSE; + state.mIsInlineIncrReflow = PR_FALSE; nsIFrame* target; switch (aReflowState.reason) { case eReflowReason_Initial: @@ -1518,6 +1521,7 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext, // in the normal case, this just marks the line dirty // but, it causes an incremental reflow targeted at a frame // inside a continued span to get dropped on the floor. see bug 25510 + // This will be yanked as soon as we have high confidence in the enabled code below rv = PrepareChildIncrementalReflow(state); #else // this code does a correct job of propogating incremental reflows (bug 25510) @@ -1531,21 +1535,35 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext, { if (!isFloater) // punt if isFloater! { - nsBlockReflowState incrState(aReflowState, aPresContext, this, aMetrics, - NS_BLOCK_MARGIN_ROOT & mState); - incrState.mNextRCFrame = state.mNextRCFrame; - PRBool keepGoing; - rv = ReflowLine(incrState, line, &keepGoing, PR_TRUE); - line->RemoveFloatersFromSpaceManager(aReflowState.mSpaceManager); - state.mNextRCFrame = nsnull; + // reflow the line containing the target of the incr. reflow + // first mark the line dirty and set up the state object + rv = PrepareChildIncrementalReflow(state); + state.mIsInlineIncrReflow = PR_TRUE; + state.mPrevLine = prevLine; + state.mCurrentLine = line; + state.mNextRCFrame = state.mNextRCFrame; + // let ReflowDirtyLines do all the work + rv = ReflowDirtyLines(state); + if (NS_FAILED(rv)) { + NS_ASSERTION(0, "Reflow failed\n"); + return rv; + } + // compute the final size + ComputeFinalSize(aReflowState, state, aMetrics); + + // finally, mark this block frame as having a dirty child and return + // XXX: we should be able to optimize this so we only call ReflowDirtyChild + // if it's absolutely necessary: something on the line changed size. + nsCOMPtr shell; + aPresContext->GetShell(getter_AddRefs(shell)); + rv = ReflowDirtyChild(shell, state.mNextRCFrame); + //XXX: it's possible we need to do some work regarding incremental painting + // here, see code below "ReflowDirtyLines() after this switch statement. + // It might be right to factor the tail end of this method into a new method + // and call that here before calling ReflowDirtyChild(). + return rv; } } - // XXX To Do: we need to check some metrics here to see if anything changed - // if nothing changed, we're done - // otherwise, we should mark the line and the previous line both dirty - // and do a resize reflow - // Now just mark the line dirty every time. We call PrepareChildIncrementalReflow - // because it includes a hack for floaters that we don't want to duplicate here. rv = PrepareChildIncrementalReflow(state); #endif } @@ -1562,8 +1580,17 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext, break; } + if (NS_FAILED(rv)) { + NS_ASSERTION(0, "setting up reflow failed.\n"); + return rv; + } + // Now reflow... rv = ReflowDirtyLines(state); + if (NS_FAILED(rv)) { + NS_ASSERTION(0, "reflow dirty lines failed.\n"); + return rv; + } aStatus = state.mReflowStatus; if (NS_FRAME_IS_NOT_COMPLETE(aStatus)) { if (NS_STYLE_OVERFLOW_HIDDEN == aReflowState.mStyleDisplay->mOverflow) { @@ -2567,8 +2594,9 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState) aState.mReflowState.reflowCommand->GetType(type); IndentBy(stdout, gNoiseIndent); ListTag(stdout); - printf(": incrementally reflowing dirty lines: type=%s(%d)", - kReflowCommandType[type], type); + printf(": incrementally reflowing dirty lines: type=%s(%d) isInline=%s", + kReflowCommandType[type], type, + aState.mIsInlineIncrReflow ? "true" : "false"); } else { IndentBy(stdout, gNoiseIndent); @@ -2586,10 +2614,30 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState) aState.mReflowState.reason == eReflowReason_Dirty; + nscoord deltaY = 0; + // Reflow the lines that are already ours aState.mPrevLine = nsnull; nsLineBox* line = mLines; - nscoord deltaY = 0; + if (aState.mIsInlineIncrReflow && aState.mNextRCFrame) + { + const nsLineBox* incrTargetLine = aState.mCurrentLine; + aState.mCurrentLine = line; + aState.mPrevLine = nsnull; + while (line && (line != incrTargetLine)) + { + nsRect damageRect; + RecoverStateFrom(aState, line, deltaY, incrementalReflow ? + &damageRect : 0); + if (incrementalReflow && !damageRect.IsEmpty()) { + Invalidate(aState.mPresContext, damageRect); + } + aState.mPrevLine = line; + line = line->mNext; + aState.AdvanceToNextLine(); + } + } + while (nsnull != line) { #ifdef DEBUG if (gNoisyReflow) { @@ -2623,6 +2671,10 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState) if (NS_FAILED(rv)) { return rv; } + if (!(NS_FRAME_IS_COMPLETE(aState.mReflowStatus))) + { + printf("line %p is not complete\n", line); + } if (!keepGoing) { if (0 == line->GetChildCount()) { DeleteLine(aState, line); @@ -3522,7 +3574,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState, // Try to place the child block PRBool isAdjacentWithTop = aState.IsAdjacentWithTop(); nscoord collapsedBottomMargin; - nsRect combinedArea; + nsRect combinedArea(0,0,0,0); *aKeepReflowGoing = brc.PlaceBlock(isAdjacentWithTop, computedOffsets, &collapsedBottomMargin, aLine->mBounds, combinedArea); @@ -4356,7 +4408,7 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState, // Stop reflow and whack the reflow status if reflow hasn't // already been stopped. if (*aKeepReflowGoing) { - NS_ASSERTION(NS_FRAME_COMPLETE == aState.mReflowStatus, + NS_ASSERTION(NS_FRAME_COMPLETE == aState.mReflowStatus, "lost reflow status"); aState.mReflowStatus = NS_FRAME_NOT_COMPLETE; *aKeepReflowGoing = PR_FALSE; diff --git a/mozilla/layout/html/base/src/nsBlockReflowState.h b/mozilla/layout/html/base/src/nsBlockReflowState.h index a39729ff592..7b3cc5630b3 100644 --- a/mozilla/layout/html/base/src/nsBlockReflowState.h +++ b/mozilla/layout/html/base/src/nsBlockReflowState.h @@ -451,6 +451,7 @@ public: PRPackedBool mUnconstrainedHeight; PRPackedBool mShrinkWrapWidth; PRPackedBool mNeedResizeReflow; + PRPackedBool mIsInlineIncrReflow; // The content area to reflow child frames within. The x/y // coordinates are known to be mBorderPadding.left and @@ -579,7 +580,8 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState, mPrevBottomMargin(0), mFreeLineList(nsnull), mLineNumber(0), - mNeedResizeReflow(PR_FALSE) + mNeedResizeReflow(PR_FALSE), + mIsInlineIncrReflow(PR_FALSE) { const nsMargin& borderPadding = BorderPadding(); @@ -1463,6 +1465,7 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext, nsresult rv = NS_OK; PRBool isStyleChange = PR_FALSE; + state.mIsInlineIncrReflow = PR_FALSE; nsIFrame* target; switch (aReflowState.reason) { case eReflowReason_Initial: @@ -1518,6 +1521,7 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext, // in the normal case, this just marks the line dirty // but, it causes an incremental reflow targeted at a frame // inside a continued span to get dropped on the floor. see bug 25510 + // This will be yanked as soon as we have high confidence in the enabled code below rv = PrepareChildIncrementalReflow(state); #else // this code does a correct job of propogating incremental reflows (bug 25510) @@ -1531,21 +1535,35 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext, { if (!isFloater) // punt if isFloater! { - nsBlockReflowState incrState(aReflowState, aPresContext, this, aMetrics, - NS_BLOCK_MARGIN_ROOT & mState); - incrState.mNextRCFrame = state.mNextRCFrame; - PRBool keepGoing; - rv = ReflowLine(incrState, line, &keepGoing, PR_TRUE); - line->RemoveFloatersFromSpaceManager(aReflowState.mSpaceManager); - state.mNextRCFrame = nsnull; + // reflow the line containing the target of the incr. reflow + // first mark the line dirty and set up the state object + rv = PrepareChildIncrementalReflow(state); + state.mIsInlineIncrReflow = PR_TRUE; + state.mPrevLine = prevLine; + state.mCurrentLine = line; + state.mNextRCFrame = state.mNextRCFrame; + // let ReflowDirtyLines do all the work + rv = ReflowDirtyLines(state); + if (NS_FAILED(rv)) { + NS_ASSERTION(0, "Reflow failed\n"); + return rv; + } + // compute the final size + ComputeFinalSize(aReflowState, state, aMetrics); + + // finally, mark this block frame as having a dirty child and return + // XXX: we should be able to optimize this so we only call ReflowDirtyChild + // if it's absolutely necessary: something on the line changed size. + nsCOMPtr shell; + aPresContext->GetShell(getter_AddRefs(shell)); + rv = ReflowDirtyChild(shell, state.mNextRCFrame); + //XXX: it's possible we need to do some work regarding incremental painting + // here, see code below "ReflowDirtyLines() after this switch statement. + // It might be right to factor the tail end of this method into a new method + // and call that here before calling ReflowDirtyChild(). + return rv; } } - // XXX To Do: we need to check some metrics here to see if anything changed - // if nothing changed, we're done - // otherwise, we should mark the line and the previous line both dirty - // and do a resize reflow - // Now just mark the line dirty every time. We call PrepareChildIncrementalReflow - // because it includes a hack for floaters that we don't want to duplicate here. rv = PrepareChildIncrementalReflow(state); #endif } @@ -1562,8 +1580,17 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext, break; } + if (NS_FAILED(rv)) { + NS_ASSERTION(0, "setting up reflow failed.\n"); + return rv; + } + // Now reflow... rv = ReflowDirtyLines(state); + if (NS_FAILED(rv)) { + NS_ASSERTION(0, "reflow dirty lines failed.\n"); + return rv; + } aStatus = state.mReflowStatus; if (NS_FRAME_IS_NOT_COMPLETE(aStatus)) { if (NS_STYLE_OVERFLOW_HIDDEN == aReflowState.mStyleDisplay->mOverflow) { @@ -2567,8 +2594,9 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState) aState.mReflowState.reflowCommand->GetType(type); IndentBy(stdout, gNoiseIndent); ListTag(stdout); - printf(": incrementally reflowing dirty lines: type=%s(%d)", - kReflowCommandType[type], type); + printf(": incrementally reflowing dirty lines: type=%s(%d) isInline=%s", + kReflowCommandType[type], type, + aState.mIsInlineIncrReflow ? "true" : "false"); } else { IndentBy(stdout, gNoiseIndent); @@ -2586,10 +2614,30 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState) aState.mReflowState.reason == eReflowReason_Dirty; + nscoord deltaY = 0; + // Reflow the lines that are already ours aState.mPrevLine = nsnull; nsLineBox* line = mLines; - nscoord deltaY = 0; + if (aState.mIsInlineIncrReflow && aState.mNextRCFrame) + { + const nsLineBox* incrTargetLine = aState.mCurrentLine; + aState.mCurrentLine = line; + aState.mPrevLine = nsnull; + while (line && (line != incrTargetLine)) + { + nsRect damageRect; + RecoverStateFrom(aState, line, deltaY, incrementalReflow ? + &damageRect : 0); + if (incrementalReflow && !damageRect.IsEmpty()) { + Invalidate(aState.mPresContext, damageRect); + } + aState.mPrevLine = line; + line = line->mNext; + aState.AdvanceToNextLine(); + } + } + while (nsnull != line) { #ifdef DEBUG if (gNoisyReflow) { @@ -2623,6 +2671,10 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState) if (NS_FAILED(rv)) { return rv; } + if (!(NS_FRAME_IS_COMPLETE(aState.mReflowStatus))) + { + printf("line %p is not complete\n", line); + } if (!keepGoing) { if (0 == line->GetChildCount()) { DeleteLine(aState, line); @@ -3522,7 +3574,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState, // Try to place the child block PRBool isAdjacentWithTop = aState.IsAdjacentWithTop(); nscoord collapsedBottomMargin; - nsRect combinedArea; + nsRect combinedArea(0,0,0,0); *aKeepReflowGoing = brc.PlaceBlock(isAdjacentWithTop, computedOffsets, &collapsedBottomMargin, aLine->mBounds, combinedArea); @@ -4356,7 +4408,7 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState, // Stop reflow and whack the reflow status if reflow hasn't // already been stopped. if (*aKeepReflowGoing) { - NS_ASSERTION(NS_FRAME_COMPLETE == aState.mReflowStatus, + NS_ASSERTION(NS_FRAME_COMPLETE == aState.mReflowStatus, "lost reflow status"); aState.mReflowStatus = NS_FRAME_NOT_COMPLETE; *aKeepReflowGoing = PR_FALSE;