зеркало из https://github.com/mozilla/pjs.git
Bug 91423. When recomputing the max width during an inline incremental reflow, we may have to fix-up reflow command chain. Specifically, we may have to replace a continuing frame in the chain with its primary frame, because the continuing frame will be destroyed during the unconstrained reflow used to compute the max width. r=dbaron, sr=attinasi
This commit is contained in:
Родитель
1c3c5dd35a
Коммит
9ede33c690
|
@ -87,7 +87,6 @@
|
||||||
#include "nsPrintfCString.h"
|
#include "nsPrintfCString.h"
|
||||||
#include "nsBlockDebugFlags.h"
|
#include "nsBlockDebugFlags.h"
|
||||||
|
|
||||||
|
|
||||||
PRBool nsBlockFrame::gLamePaintMetrics;
|
PRBool nsBlockFrame::gLamePaintMetrics;
|
||||||
PRBool nsBlockFrame::gLameReflowMetrics;
|
PRBool nsBlockFrame::gLameReflowMetrics;
|
||||||
PRBool nsBlockFrame::gNoisy;
|
PRBool nsBlockFrame::gNoisy;
|
||||||
|
@ -2375,6 +2374,34 @@ nsBlockFrame::DeleteLine(nsBlockReflowState& aState,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
RetargetReflowToPrimaryFrames(nsHTMLReflowCommand *aReflowCommand)
|
||||||
|
{
|
||||||
|
// Get the reflow path, which is stored as a stack (i.e., the next
|
||||||
|
// frame in the reflow is at the _end_ of the array).
|
||||||
|
nsVoidArray *path = aReflowCommand->GetPath();
|
||||||
|
|
||||||
|
for (PRInt32 i = path->Count() - 1; i >= 0; --i) {
|
||||||
|
nsIFrame *frame = NS_STATIC_CAST(nsIFrame *, path->ElementAt(i));
|
||||||
|
|
||||||
|
// Stop if we encounter a non-inline frame in the reflow path.
|
||||||
|
const nsStyleDisplay *display;
|
||||||
|
GetStyleData(frame, &display);
|
||||||
|
|
||||||
|
if (NS_STYLE_DISPLAY_INLINE != display->mDisplay)
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Walk back to the primary frame.
|
||||||
|
nsIFrame *prevFrame;
|
||||||
|
do {
|
||||||
|
frame->GetPrevInFlow(&prevFrame);
|
||||||
|
} while (prevFrame && (frame = prevFrame));
|
||||||
|
|
||||||
|
path->ReplaceElementAt(frame, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reflow a line. The line will either contain a single block frame
|
* Reflow a line. The line will either contain a single block frame
|
||||||
* or contain 1 or more inline frames. aKeepReflowGoing indicates
|
* or contain 1 or more inline frames. aKeepReflowGoing indicates
|
||||||
|
@ -2482,21 +2509,55 @@ nsBlockFrame::ReflowLine(nsBlockReflowState& aState,
|
||||||
PRBool isBeginningLine = aState.mCurrentLine == begin_lines() ||
|
PRBool isBeginningLine = aState.mCurrentLine == begin_lines() ||
|
||||||
!aState.mCurrentLine.prev()->IsLineWrapped();
|
!aState.mCurrentLine.prev()->IsLineWrapped();
|
||||||
if (aState.GetFlag(BRS_COMPUTEMAXWIDTH) && isBeginningLine) {
|
if (aState.GetFlag(BRS_COMPUTEMAXWIDTH) && isBeginningLine) {
|
||||||
|
// First reflow the line with an unconstrained width.
|
||||||
nscoord oldY = aState.mY;
|
nscoord oldY = aState.mY;
|
||||||
nsCollapsingMargin oldPrevBottomMargin(aState.mPrevBottomMargin);
|
nsCollapsingMargin oldPrevBottomMargin(aState.mPrevBottomMargin);
|
||||||
PRBool oldUnconstrainedWidth = aState.GetFlag(BRS_UNCONSTRAINEDWIDTH);
|
PRBool oldUnconstrainedWidth = aState.GetFlag(BRS_UNCONSTRAINEDWIDTH);
|
||||||
|
|
||||||
// First reflow the line with an unconstrained width. When doing this
|
// If this incremental reflow is targeted at a continuing frame,
|
||||||
// we need to set the block reflow state's "mUnconstrainedWidth" variable
|
// we've got to retarget it to the primary frame. The
|
||||||
// to PR_TRUE so if we encounter a placeholder and then reflow its
|
// unconstrained reflow will destroy all of the continuations.
|
||||||
// associated floater we don't end up resetting the line's right edge and
|
//
|
||||||
// have it think the width is unconstrained...
|
// XXXwaterson if we implement some sort of ``reflow root''
|
||||||
|
// frame, rather than requiring incremental reflows to always
|
||||||
|
// walk from the real root frame, this code may not be needed
|
||||||
|
// anymore. Or will it?
|
||||||
|
if (aState.mNextRCFrame) {
|
||||||
|
NS_ASSERTION(aState.GetFlag(BRS_ISINLINEINCRREFLOW),
|
||||||
|
"expected to be inline incremental reflow");
|
||||||
|
|
||||||
|
nsIFrame *prevInFlow;
|
||||||
|
aState.mNextRCFrame->GetPrevInFlow(&prevInFlow);
|
||||||
|
if (prevInFlow) {
|
||||||
|
// Fix aState's mNextRCFrame
|
||||||
|
while (prevInFlow) {
|
||||||
|
aState.mNextRCFrame = prevInFlow;
|
||||||
|
aState.mNextRCFrame->GetPrevInFlow(&prevInFlow);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fix any frames deeper in the reflow path.
|
||||||
|
RetargetReflowToPrimaryFrames(aState.mReflowState.reflowCommand);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// When doing this we need to set the block reflow state's
|
||||||
|
// "mUnconstrainedWidth" variable to PR_TRUE so if we encounter
|
||||||
|
// a placeholder and then reflow its associated floater we don't
|
||||||
|
// end up resetting the line's right edge and have it think the
|
||||||
|
// width is unconstrained...
|
||||||
aState.SetFlag(BRS_UNCONSTRAINEDWIDTH, PR_TRUE);
|
aState.SetFlag(BRS_UNCONSTRAINEDWIDTH, PR_TRUE);
|
||||||
ReflowInlineFrames(aState, aLine, aKeepReflowGoing, aDamageDirtyArea, PR_TRUE);
|
ReflowInlineFrames(aState, aLine, aKeepReflowGoing, aDamageDirtyArea, PR_TRUE);
|
||||||
aState.mY = oldY;
|
aState.mY = oldY;
|
||||||
aState.mPrevBottomMargin = oldPrevBottomMargin;
|
aState.mPrevBottomMargin = oldPrevBottomMargin;
|
||||||
aState.SetFlag(BRS_UNCONSTRAINEDWIDTH, oldUnconstrainedWidth);
|
aState.SetFlag(BRS_UNCONSTRAINEDWIDTH, oldUnconstrainedWidth);
|
||||||
|
|
||||||
|
#ifdef DEBUG_waterson
|
||||||
|
// XXXwaterson if oldUnconstrainedWidth was set, why do we need
|
||||||
|
// to do the second reflow, below?
|
||||||
|
if (oldUnconstrainedWidth)
|
||||||
|
printf("+++ possibly doing an unnecessary second-pass unconstrained reflow\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
// Update the line's maximum width
|
// Update the line's maximum width
|
||||||
aLine->mMaximumWidth = aLine->mBounds.XMost();
|
aLine->mMaximumWidth = aLine->mBounds.XMost();
|
||||||
#ifdef NOISY_MAXIMUM_WIDTH
|
#ifdef NOISY_MAXIMUM_WIDTH
|
||||||
|
|
|
@ -126,6 +126,14 @@ public:
|
||||||
*/
|
*/
|
||||||
nsresult GetAttribute(nsIAtom *& aAttribute) const;
|
nsresult GetAttribute(nsIAtom *& aAttribute) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the reflow command's path. The path is stored in
|
||||||
|
* <em>reverse</em> order in the array; i.e., the first element in
|
||||||
|
* the array is the target frame, the last element in the array is
|
||||||
|
* the current frame.
|
||||||
|
*/
|
||||||
|
nsVoidArray *GetPath() { return &mPath; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the child frame associated with the reflow command.
|
* Get the child frame associated with the reflow command.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -87,7 +87,6 @@
|
||||||
#include "nsPrintfCString.h"
|
#include "nsPrintfCString.h"
|
||||||
#include "nsBlockDebugFlags.h"
|
#include "nsBlockDebugFlags.h"
|
||||||
|
|
||||||
|
|
||||||
PRBool nsBlockFrame::gLamePaintMetrics;
|
PRBool nsBlockFrame::gLamePaintMetrics;
|
||||||
PRBool nsBlockFrame::gLameReflowMetrics;
|
PRBool nsBlockFrame::gLameReflowMetrics;
|
||||||
PRBool nsBlockFrame::gNoisy;
|
PRBool nsBlockFrame::gNoisy;
|
||||||
|
@ -2375,6 +2374,34 @@ nsBlockFrame::DeleteLine(nsBlockReflowState& aState,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
RetargetReflowToPrimaryFrames(nsHTMLReflowCommand *aReflowCommand)
|
||||||
|
{
|
||||||
|
// Get the reflow path, which is stored as a stack (i.e., the next
|
||||||
|
// frame in the reflow is at the _end_ of the array).
|
||||||
|
nsVoidArray *path = aReflowCommand->GetPath();
|
||||||
|
|
||||||
|
for (PRInt32 i = path->Count() - 1; i >= 0; --i) {
|
||||||
|
nsIFrame *frame = NS_STATIC_CAST(nsIFrame *, path->ElementAt(i));
|
||||||
|
|
||||||
|
// Stop if we encounter a non-inline frame in the reflow path.
|
||||||
|
const nsStyleDisplay *display;
|
||||||
|
GetStyleData(frame, &display);
|
||||||
|
|
||||||
|
if (NS_STYLE_DISPLAY_INLINE != display->mDisplay)
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Walk back to the primary frame.
|
||||||
|
nsIFrame *prevFrame;
|
||||||
|
do {
|
||||||
|
frame->GetPrevInFlow(&prevFrame);
|
||||||
|
} while (prevFrame && (frame = prevFrame));
|
||||||
|
|
||||||
|
path->ReplaceElementAt(frame, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reflow a line. The line will either contain a single block frame
|
* Reflow a line. The line will either contain a single block frame
|
||||||
* or contain 1 or more inline frames. aKeepReflowGoing indicates
|
* or contain 1 or more inline frames. aKeepReflowGoing indicates
|
||||||
|
@ -2482,21 +2509,55 @@ nsBlockFrame::ReflowLine(nsBlockReflowState& aState,
|
||||||
PRBool isBeginningLine = aState.mCurrentLine == begin_lines() ||
|
PRBool isBeginningLine = aState.mCurrentLine == begin_lines() ||
|
||||||
!aState.mCurrentLine.prev()->IsLineWrapped();
|
!aState.mCurrentLine.prev()->IsLineWrapped();
|
||||||
if (aState.GetFlag(BRS_COMPUTEMAXWIDTH) && isBeginningLine) {
|
if (aState.GetFlag(BRS_COMPUTEMAXWIDTH) && isBeginningLine) {
|
||||||
|
// First reflow the line with an unconstrained width.
|
||||||
nscoord oldY = aState.mY;
|
nscoord oldY = aState.mY;
|
||||||
nsCollapsingMargin oldPrevBottomMargin(aState.mPrevBottomMargin);
|
nsCollapsingMargin oldPrevBottomMargin(aState.mPrevBottomMargin);
|
||||||
PRBool oldUnconstrainedWidth = aState.GetFlag(BRS_UNCONSTRAINEDWIDTH);
|
PRBool oldUnconstrainedWidth = aState.GetFlag(BRS_UNCONSTRAINEDWIDTH);
|
||||||
|
|
||||||
// First reflow the line with an unconstrained width. When doing this
|
// If this incremental reflow is targeted at a continuing frame,
|
||||||
// we need to set the block reflow state's "mUnconstrainedWidth" variable
|
// we've got to retarget it to the primary frame. The
|
||||||
// to PR_TRUE so if we encounter a placeholder and then reflow its
|
// unconstrained reflow will destroy all of the continuations.
|
||||||
// associated floater we don't end up resetting the line's right edge and
|
//
|
||||||
// have it think the width is unconstrained...
|
// XXXwaterson if we implement some sort of ``reflow root''
|
||||||
|
// frame, rather than requiring incremental reflows to always
|
||||||
|
// walk from the real root frame, this code may not be needed
|
||||||
|
// anymore. Or will it?
|
||||||
|
if (aState.mNextRCFrame) {
|
||||||
|
NS_ASSERTION(aState.GetFlag(BRS_ISINLINEINCRREFLOW),
|
||||||
|
"expected to be inline incremental reflow");
|
||||||
|
|
||||||
|
nsIFrame *prevInFlow;
|
||||||
|
aState.mNextRCFrame->GetPrevInFlow(&prevInFlow);
|
||||||
|
if (prevInFlow) {
|
||||||
|
// Fix aState's mNextRCFrame
|
||||||
|
while (prevInFlow) {
|
||||||
|
aState.mNextRCFrame = prevInFlow;
|
||||||
|
aState.mNextRCFrame->GetPrevInFlow(&prevInFlow);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fix any frames deeper in the reflow path.
|
||||||
|
RetargetReflowToPrimaryFrames(aState.mReflowState.reflowCommand);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// When doing this we need to set the block reflow state's
|
||||||
|
// "mUnconstrainedWidth" variable to PR_TRUE so if we encounter
|
||||||
|
// a placeholder and then reflow its associated floater we don't
|
||||||
|
// end up resetting the line's right edge and have it think the
|
||||||
|
// width is unconstrained...
|
||||||
aState.SetFlag(BRS_UNCONSTRAINEDWIDTH, PR_TRUE);
|
aState.SetFlag(BRS_UNCONSTRAINEDWIDTH, PR_TRUE);
|
||||||
ReflowInlineFrames(aState, aLine, aKeepReflowGoing, aDamageDirtyArea, PR_TRUE);
|
ReflowInlineFrames(aState, aLine, aKeepReflowGoing, aDamageDirtyArea, PR_TRUE);
|
||||||
aState.mY = oldY;
|
aState.mY = oldY;
|
||||||
aState.mPrevBottomMargin = oldPrevBottomMargin;
|
aState.mPrevBottomMargin = oldPrevBottomMargin;
|
||||||
aState.SetFlag(BRS_UNCONSTRAINEDWIDTH, oldUnconstrainedWidth);
|
aState.SetFlag(BRS_UNCONSTRAINEDWIDTH, oldUnconstrainedWidth);
|
||||||
|
|
||||||
|
#ifdef DEBUG_waterson
|
||||||
|
// XXXwaterson if oldUnconstrainedWidth was set, why do we need
|
||||||
|
// to do the second reflow, below?
|
||||||
|
if (oldUnconstrainedWidth)
|
||||||
|
printf("+++ possibly doing an unnecessary second-pass unconstrained reflow\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
// Update the line's maximum width
|
// Update the line's maximum width
|
||||||
aLine->mMaximumWidth = aLine->mBounds.XMost();
|
aLine->mMaximumWidth = aLine->mBounds.XMost();
|
||||||
#ifdef NOISY_MAXIMUM_WIDTH
|
#ifdef NOISY_MAXIMUM_WIDTH
|
||||||
|
|
|
@ -126,6 +126,14 @@ public:
|
||||||
*/
|
*/
|
||||||
nsresult GetAttribute(nsIAtom *& aAttribute) const;
|
nsresult GetAttribute(nsIAtom *& aAttribute) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the reflow command's path. The path is stored in
|
||||||
|
* <em>reverse</em> order in the array; i.e., the first element in
|
||||||
|
* the array is the target frame, the last element in the array is
|
||||||
|
* the current frame.
|
||||||
|
*/
|
||||||
|
nsVoidArray *GetPath() { return &mPath; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the child frame associated with the reflow command.
|
* Get the child frame associated with the reflow command.
|
||||||
*/
|
*/
|
||||||
|
|
Загрузка…
Ссылка в новой задаче