More work on getting block frames to incrementally update their

maximum width
This commit is contained in:
troy%netscape.com 2000-01-08 03:58:27 +00:00
Родитель 77072606cc
Коммит f08e81815b
14 изменённых файлов: 632 добавлений и 94 удалений

Просмотреть файл

@ -2442,6 +2442,27 @@ nsBlockFrame::PropogateReflowDamage(nsBlockReflowState& aState,
}
}
static PRBool
WrappedLinesAreDirty(nsLineBox* aLine)
{
if (aLine->IsInline()) {
while (aLine->IsLineWrapped()) {
aLine = aLine->mNext;
if (!aLine) {
break;
}
NS_ASSERTION(!aLine->IsBlock(), "didn't expect a block line");
if (aLine->IsDirty()) {
// we found a continuing line that is dirty
return PR_TRUE;
}
}
}
return PR_FALSE;
}
/**
* Reflow the dirty lines
*/
@ -2495,7 +2516,10 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState)
}
#endif
if (line->IsDirty()) {
// If we're supposed to update our maximum width, then we'll also need to
// reflow this line if it's line wrapped and any of the continuing lines
// are dirty
if (line->IsDirty() || (aState.mComputeMaximumWidth && ::WrappedLinesAreDirty(line))) {
// Compute the dirty lines "before" YMost, after factoring in
// the running deltaY value - the running value is implicit in
// aState.mY.
@ -2746,7 +2770,40 @@ nsBlockFrame::ReflowLine(nsBlockReflowState& aState,
}
else {
aLine->SetLineWrapped(PR_FALSE);
rv = ReflowInlineFrames(aState, aLine, aKeepReflowGoing);
// If we're supposed to update the maximum width, then we'll need to reflow
// the line with an unconstrained width (which will give us the new maximum
// width), then we'll reflow it again with the constrained width.
// We only do this if this is a beginning line, i.e., don't do this for
// lines associated with content that line wrapped (see ReflowDirtyLines()
// for details).
// XXX This approach doesn't work when floaters are involved in which case
// we'll either need to recover the floater state that applies to the
// unconstrained reflow or keep it around in a separate space manager...
if (aState.mComputeMaximumWidth && aState.mPrevLine && !aState.mPrevLine->IsLineWrapped()) {
nscoord oldY = aState.mY;
nscoord oldPrevBottomMargin = aState.mPrevBottomMargin;
// First reflow the line with an unconstrained width
ReflowInlineFrames(aState, aLine, aKeepReflowGoing, PR_TRUE);
// Update the line's maximum width
aLine->mMaximumWidth = aLine->mBounds.XMost();
aState.UpdateMaximumWidth(aLine->mMaximumWidth);
// Remove any floaters associated with the line from the space
// manager
aLine->RemoveFloatersFromSpaceManager(aState.mSpaceManager);
// Now reflow the line again this time without having it compute
// the maximum width
aState.mY = oldY;
aState.mPrevBottomMargin = oldPrevBottomMargin;
rv = ReflowInlineFrames(aState, aLine, aKeepReflowGoing);
} else {
rv = ReflowInlineFrames(aState, aLine, aKeepReflowGoing);
}
// We don't really know what changed in the line, so use the union
// of the old and new combined areas
@ -3545,7 +3602,8 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
nsresult
nsBlockFrame::ReflowInlineFrames(nsBlockReflowState& aState,
nsLineBox* aLine,
PRBool* aKeepReflowGoing)
PRBool* aKeepReflowGoing,
PRBool aUpdateMaximumWidth)
{
nsresult rv = NS_OK;
*aKeepReflowGoing = PR_TRUE;
@ -3560,11 +3618,13 @@ nsBlockFrame::ReflowInlineFrames(nsBlockReflowState& aState,
// large.
if (aState.mReflowState.mReflowDepth > 30) {//XXX layout-tune.h?
rv = DoReflowInlineFramesMalloc(aState, aLine, aKeepReflowGoing,
&lineReflowStatus);
&lineReflowStatus,
aUpdateMaximumWidth);
}
else {
rv = DoReflowInlineFramesAuto(aState, aLine, aKeepReflowGoing,
&lineReflowStatus);
&lineReflowStatus,
aUpdateMaximumWidth);
}
if (NS_FAILED(rv)) {
break;
@ -3585,7 +3645,8 @@ nsresult
nsBlockFrame::DoReflowInlineFramesMalloc(nsBlockReflowState& aState,
nsLineBox* aLine,
PRBool* aKeepReflowGoing,
PRUint8* aLineReflowStatus)
PRUint8* aLineReflowStatus,
PRBool aUpdateMaximumWidth)
{
nsLineLayout* ll = new nsLineLayout(aState.mPresContext,
aState.mReflowState.mSpaceManager,
@ -3597,7 +3658,7 @@ nsBlockFrame::DoReflowInlineFramesMalloc(nsBlockReflowState& aState,
ll->Init(&aState, aState.mMinLineHeight, aState.mLineNumber);
ll->SetReflowTextRuns(mTextRuns);
nsresult rv = DoReflowInlineFrames(aState, *ll, aLine, aKeepReflowGoing,
aLineReflowStatus);
aLineReflowStatus, aUpdateMaximumWidth);
ll->EndLineReflow();
delete ll;
return rv;
@ -3607,7 +3668,8 @@ nsresult
nsBlockFrame::DoReflowInlineFramesAuto(nsBlockReflowState& aState,
nsLineBox* aLine,
PRBool* aKeepReflowGoing,
PRUint8* aLineReflowStatus)
PRUint8* aLineReflowStatus,
PRBool aUpdateMaximumWidth)
{
nsLineLayout lineLayout(aState.mPresContext,
aState.mReflowState.mSpaceManager,
@ -3616,17 +3678,19 @@ nsBlockFrame::DoReflowInlineFramesAuto(nsBlockReflowState& aState,
lineLayout.Init(&aState, aState.mMinLineHeight, aState.mLineNumber);
lineLayout.SetReflowTextRuns(mTextRuns);
nsresult rv = DoReflowInlineFrames(aState, lineLayout, aLine,
aKeepReflowGoing, aLineReflowStatus);
aKeepReflowGoing, aLineReflowStatus,
aUpdateMaximumWidth);
lineLayout.EndLineReflow();
return rv;
}
nsresult
nsBlockFrame::DoReflowInlineFrames(nsBlockReflowState& aState,
nsLineLayout& aLineLayout,
nsLineBox* aLine,
PRBool* aKeepReflowGoing,
PRUint8* aLineReflowStatus)
PRUint8* aLineReflowStatus,
PRBool aUpdateMaximumWidth)
{
// Forget all of the floaters on the line
aLine->FreeFloaters(aState.mFloaterCacheFreeList);
@ -3651,6 +3715,9 @@ nsBlockFrame::DoReflowInlineFrames(nsBlockReflowState& aState,
/* XXX get the height right! */
availHeight = aState.mAvailSpaceRect.height;
}
if (aUpdateMaximumWidth) {
availWidth = NS_UNCONSTRAINEDSIZE;
}
aLineLayout.BeginLineReflow(x, aState.mY,
availWidth, availHeight,
impactedByFloaters,
@ -3742,7 +3809,7 @@ nsBlockFrame::DoReflowInlineFrames(nsBlockReflowState& aState,
// If we are propogating out a break-before status then there is
// no point in placing the line.
if (!NS_INLINE_IS_BREAK_BEFORE(aState.mReflowStatus)) {
rv = PlaceLine(aState, aLineLayout, aLine, aKeepReflowGoing);
rv = PlaceLine(aState, aLineLayout, aLine, aKeepReflowGoing, aUpdateMaximumWidth);
}
}
*aLineReflowStatus = lineReflowStatus;
@ -4044,7 +4111,8 @@ nsresult
nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
nsLineLayout& aLineLayout,
nsLineBox* aLine,
PRBool* aKeepReflowGoing)
PRBool* aKeepReflowGoing,
PRBool aUpdateMaximumWidth)
{
nsresult rv = NS_OK;
@ -4190,7 +4258,14 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
ComputeLineMaxElementSize(aState, aLine, &maxElementSize);
}
}
PostPlaceLine(aState, aLine, maxElementSize);
// If we're reflowing the line just to get incrementally update the
// maximum width, then don't post-place the line. It's doing work we
// don't need, and it will update things like aState.mKidXMost that
// we don't want updated...
if (!aUpdateMaximumWidth) {
PostPlaceLine(aState, aLine, maxElementSize);
}
// Add the already placed current-line floaters to the line
aLine->AppendFloaters(aState.mCurrentLineFloaters);

Просмотреть файл

@ -205,7 +205,8 @@ protected:
nsresult PlaceLine(nsBlockReflowState& aState,
nsLineLayout& aLineLayout,
nsLineBox* aLine,
PRBool* aKeepReflowGoing);
PRBool* aKeepReflowGoing,
PRBool aUpdateMaximumWidth);
// XXX blech
void PostPlaceLine(nsBlockReflowState& aState,
@ -233,23 +234,27 @@ protected:
nsresult ReflowInlineFrames(nsBlockReflowState& aState,
nsLineBox* aLine,
PRBool* aKeepLineGoing);
PRBool* aKeepLineGoing,
PRBool aUpdateMaximumWidth = PR_FALSE);
nsresult DoReflowInlineFrames(nsBlockReflowState& aState,
nsLineLayout& aLineLayout,
nsLineBox* aLine,
PRBool* aKeepReflowGoing,
PRUint8* aLineReflowStatus);
PRUint8* aLineReflowStatus,
PRBool aUpdateMaximumWidth);
nsresult DoReflowInlineFramesAuto(nsBlockReflowState& aState,
nsLineBox* aLine,
PRBool* aKeepReflowGoing,
PRUint8* aLineReflowStatus);
PRUint8* aLineReflowStatus,
PRBool aUpdateMaximumWidth);
nsresult DoReflowInlineFramesMalloc(nsBlockReflowState& aState,
nsLineBox* aLine,
PRBool* aKeepReflowGoing,
PRUint8* aLineReflowStatus);
PRUint8* aLineReflowStatus,
PRBool aUpdateMaximumWidth);
nsresult ReflowInlineFrame(nsBlockReflowState& aState,
nsLineLayout& aLineLayout,

Просмотреть файл

@ -262,6 +262,27 @@ nsBlockReflowContext::ReflowBlock(nsIFrame* aFrame,
nscoord tx = x - mOuterReflowState.mComputedBorderPadding.left;
nscoord ty = y - mOuterReflowState.mComputedBorderPadding.top;
mOuterReflowState.mSpaceManager->Translate(tx, ty);
// See if this is the child's initial reflow and we are supposed to
// compute our maximum width
if (mComputeMaximumWidth && (eReflowReason_Initial == reason)) {
nscoord oldAvailableWidth = reflowState.availableWidth;
nscoord oldComputedWidth = reflowState.mComputedWidth;
reflowState.availableWidth = NS_UNCONSTRAINEDSIZE;
reflowState.mComputedWidth = NS_UNCONSTRAINEDSIZE;
rv = aFrame->Reflow(mPresContext, mMetrics, reflowState,
aFrameReflowStatus);
// Update the reflow metrics with the maximum width
mMetrics.mMaximumWidth = mMetrics.width;
// The second reflow is just as a resize reflow with the constrained
// width
reflowState.availableWidth = oldAvailableWidth;
reflowState.mComputedWidth = oldComputedWidth;
reason = eReflowReason_Resize;
}
rv = aFrame->Reflow(mPresContext, mMetrics, reflowState,
aFrameReflowStatus);
mOuterReflowState.mSpaceManager->Translate(-tx, -ty);

Просмотреть файл

@ -2442,6 +2442,27 @@ nsBlockFrame::PropogateReflowDamage(nsBlockReflowState& aState,
}
}
static PRBool
WrappedLinesAreDirty(nsLineBox* aLine)
{
if (aLine->IsInline()) {
while (aLine->IsLineWrapped()) {
aLine = aLine->mNext;
if (!aLine) {
break;
}
NS_ASSERTION(!aLine->IsBlock(), "didn't expect a block line");
if (aLine->IsDirty()) {
// we found a continuing line that is dirty
return PR_TRUE;
}
}
}
return PR_FALSE;
}
/**
* Reflow the dirty lines
*/
@ -2495,7 +2516,10 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState)
}
#endif
if (line->IsDirty()) {
// If we're supposed to update our maximum width, then we'll also need to
// reflow this line if it's line wrapped and any of the continuing lines
// are dirty
if (line->IsDirty() || (aState.mComputeMaximumWidth && ::WrappedLinesAreDirty(line))) {
// Compute the dirty lines "before" YMost, after factoring in
// the running deltaY value - the running value is implicit in
// aState.mY.
@ -2746,7 +2770,40 @@ nsBlockFrame::ReflowLine(nsBlockReflowState& aState,
}
else {
aLine->SetLineWrapped(PR_FALSE);
rv = ReflowInlineFrames(aState, aLine, aKeepReflowGoing);
// If we're supposed to update the maximum width, then we'll need to reflow
// the line with an unconstrained width (which will give us the new maximum
// width), then we'll reflow it again with the constrained width.
// We only do this if this is a beginning line, i.e., don't do this for
// lines associated with content that line wrapped (see ReflowDirtyLines()
// for details).
// XXX This approach doesn't work when floaters are involved in which case
// we'll either need to recover the floater state that applies to the
// unconstrained reflow or keep it around in a separate space manager...
if (aState.mComputeMaximumWidth && aState.mPrevLine && !aState.mPrevLine->IsLineWrapped()) {
nscoord oldY = aState.mY;
nscoord oldPrevBottomMargin = aState.mPrevBottomMargin;
// First reflow the line with an unconstrained width
ReflowInlineFrames(aState, aLine, aKeepReflowGoing, PR_TRUE);
// Update the line's maximum width
aLine->mMaximumWidth = aLine->mBounds.XMost();
aState.UpdateMaximumWidth(aLine->mMaximumWidth);
// Remove any floaters associated with the line from the space
// manager
aLine->RemoveFloatersFromSpaceManager(aState.mSpaceManager);
// Now reflow the line again this time without having it compute
// the maximum width
aState.mY = oldY;
aState.mPrevBottomMargin = oldPrevBottomMargin;
rv = ReflowInlineFrames(aState, aLine, aKeepReflowGoing);
} else {
rv = ReflowInlineFrames(aState, aLine, aKeepReflowGoing);
}
// We don't really know what changed in the line, so use the union
// of the old and new combined areas
@ -3545,7 +3602,8 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
nsresult
nsBlockFrame::ReflowInlineFrames(nsBlockReflowState& aState,
nsLineBox* aLine,
PRBool* aKeepReflowGoing)
PRBool* aKeepReflowGoing,
PRBool aUpdateMaximumWidth)
{
nsresult rv = NS_OK;
*aKeepReflowGoing = PR_TRUE;
@ -3560,11 +3618,13 @@ nsBlockFrame::ReflowInlineFrames(nsBlockReflowState& aState,
// large.
if (aState.mReflowState.mReflowDepth > 30) {//XXX layout-tune.h?
rv = DoReflowInlineFramesMalloc(aState, aLine, aKeepReflowGoing,
&lineReflowStatus);
&lineReflowStatus,
aUpdateMaximumWidth);
}
else {
rv = DoReflowInlineFramesAuto(aState, aLine, aKeepReflowGoing,
&lineReflowStatus);
&lineReflowStatus,
aUpdateMaximumWidth);
}
if (NS_FAILED(rv)) {
break;
@ -3585,7 +3645,8 @@ nsresult
nsBlockFrame::DoReflowInlineFramesMalloc(nsBlockReflowState& aState,
nsLineBox* aLine,
PRBool* aKeepReflowGoing,
PRUint8* aLineReflowStatus)
PRUint8* aLineReflowStatus,
PRBool aUpdateMaximumWidth)
{
nsLineLayout* ll = new nsLineLayout(aState.mPresContext,
aState.mReflowState.mSpaceManager,
@ -3597,7 +3658,7 @@ nsBlockFrame::DoReflowInlineFramesMalloc(nsBlockReflowState& aState,
ll->Init(&aState, aState.mMinLineHeight, aState.mLineNumber);
ll->SetReflowTextRuns(mTextRuns);
nsresult rv = DoReflowInlineFrames(aState, *ll, aLine, aKeepReflowGoing,
aLineReflowStatus);
aLineReflowStatus, aUpdateMaximumWidth);
ll->EndLineReflow();
delete ll;
return rv;
@ -3607,7 +3668,8 @@ nsresult
nsBlockFrame::DoReflowInlineFramesAuto(nsBlockReflowState& aState,
nsLineBox* aLine,
PRBool* aKeepReflowGoing,
PRUint8* aLineReflowStatus)
PRUint8* aLineReflowStatus,
PRBool aUpdateMaximumWidth)
{
nsLineLayout lineLayout(aState.mPresContext,
aState.mReflowState.mSpaceManager,
@ -3616,17 +3678,19 @@ nsBlockFrame::DoReflowInlineFramesAuto(nsBlockReflowState& aState,
lineLayout.Init(&aState, aState.mMinLineHeight, aState.mLineNumber);
lineLayout.SetReflowTextRuns(mTextRuns);
nsresult rv = DoReflowInlineFrames(aState, lineLayout, aLine,
aKeepReflowGoing, aLineReflowStatus);
aKeepReflowGoing, aLineReflowStatus,
aUpdateMaximumWidth);
lineLayout.EndLineReflow();
return rv;
}
nsresult
nsBlockFrame::DoReflowInlineFrames(nsBlockReflowState& aState,
nsLineLayout& aLineLayout,
nsLineBox* aLine,
PRBool* aKeepReflowGoing,
PRUint8* aLineReflowStatus)
PRUint8* aLineReflowStatus,
PRBool aUpdateMaximumWidth)
{
// Forget all of the floaters on the line
aLine->FreeFloaters(aState.mFloaterCacheFreeList);
@ -3651,6 +3715,9 @@ nsBlockFrame::DoReflowInlineFrames(nsBlockReflowState& aState,
/* XXX get the height right! */
availHeight = aState.mAvailSpaceRect.height;
}
if (aUpdateMaximumWidth) {
availWidth = NS_UNCONSTRAINEDSIZE;
}
aLineLayout.BeginLineReflow(x, aState.mY,
availWidth, availHeight,
impactedByFloaters,
@ -3742,7 +3809,7 @@ nsBlockFrame::DoReflowInlineFrames(nsBlockReflowState& aState,
// If we are propogating out a break-before status then there is
// no point in placing the line.
if (!NS_INLINE_IS_BREAK_BEFORE(aState.mReflowStatus)) {
rv = PlaceLine(aState, aLineLayout, aLine, aKeepReflowGoing);
rv = PlaceLine(aState, aLineLayout, aLine, aKeepReflowGoing, aUpdateMaximumWidth);
}
}
*aLineReflowStatus = lineReflowStatus;
@ -4044,7 +4111,8 @@ nsresult
nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
nsLineLayout& aLineLayout,
nsLineBox* aLine,
PRBool* aKeepReflowGoing)
PRBool* aKeepReflowGoing,
PRBool aUpdateMaximumWidth)
{
nsresult rv = NS_OK;
@ -4190,7 +4258,14 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
ComputeLineMaxElementSize(aState, aLine, &maxElementSize);
}
}
PostPlaceLine(aState, aLine, maxElementSize);
// If we're reflowing the line just to get incrementally update the
// maximum width, then don't post-place the line. It's doing work we
// don't need, and it will update things like aState.mKidXMost that
// we don't want updated...
if (!aUpdateMaximumWidth) {
PostPlaceLine(aState, aLine, maxElementSize);
}
// Add the already placed current-line floaters to the line
aLine->AppendFloaters(aState.mCurrentLineFloaters);

Просмотреть файл

@ -2442,6 +2442,27 @@ nsBlockFrame::PropogateReflowDamage(nsBlockReflowState& aState,
}
}
static PRBool
WrappedLinesAreDirty(nsLineBox* aLine)
{
if (aLine->IsInline()) {
while (aLine->IsLineWrapped()) {
aLine = aLine->mNext;
if (!aLine) {
break;
}
NS_ASSERTION(!aLine->IsBlock(), "didn't expect a block line");
if (aLine->IsDirty()) {
// we found a continuing line that is dirty
return PR_TRUE;
}
}
}
return PR_FALSE;
}
/**
* Reflow the dirty lines
*/
@ -2495,7 +2516,10 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState)
}
#endif
if (line->IsDirty()) {
// If we're supposed to update our maximum width, then we'll also need to
// reflow this line if it's line wrapped and any of the continuing lines
// are dirty
if (line->IsDirty() || (aState.mComputeMaximumWidth && ::WrappedLinesAreDirty(line))) {
// Compute the dirty lines "before" YMost, after factoring in
// the running deltaY value - the running value is implicit in
// aState.mY.
@ -2746,7 +2770,40 @@ nsBlockFrame::ReflowLine(nsBlockReflowState& aState,
}
else {
aLine->SetLineWrapped(PR_FALSE);
rv = ReflowInlineFrames(aState, aLine, aKeepReflowGoing);
// If we're supposed to update the maximum width, then we'll need to reflow
// the line with an unconstrained width (which will give us the new maximum
// width), then we'll reflow it again with the constrained width.
// We only do this if this is a beginning line, i.e., don't do this for
// lines associated with content that line wrapped (see ReflowDirtyLines()
// for details).
// XXX This approach doesn't work when floaters are involved in which case
// we'll either need to recover the floater state that applies to the
// unconstrained reflow or keep it around in a separate space manager...
if (aState.mComputeMaximumWidth && aState.mPrevLine && !aState.mPrevLine->IsLineWrapped()) {
nscoord oldY = aState.mY;
nscoord oldPrevBottomMargin = aState.mPrevBottomMargin;
// First reflow the line with an unconstrained width
ReflowInlineFrames(aState, aLine, aKeepReflowGoing, PR_TRUE);
// Update the line's maximum width
aLine->mMaximumWidth = aLine->mBounds.XMost();
aState.UpdateMaximumWidth(aLine->mMaximumWidth);
// Remove any floaters associated with the line from the space
// manager
aLine->RemoveFloatersFromSpaceManager(aState.mSpaceManager);
// Now reflow the line again this time without having it compute
// the maximum width
aState.mY = oldY;
aState.mPrevBottomMargin = oldPrevBottomMargin;
rv = ReflowInlineFrames(aState, aLine, aKeepReflowGoing);
} else {
rv = ReflowInlineFrames(aState, aLine, aKeepReflowGoing);
}
// We don't really know what changed in the line, so use the union
// of the old and new combined areas
@ -3545,7 +3602,8 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
nsresult
nsBlockFrame::ReflowInlineFrames(nsBlockReflowState& aState,
nsLineBox* aLine,
PRBool* aKeepReflowGoing)
PRBool* aKeepReflowGoing,
PRBool aUpdateMaximumWidth)
{
nsresult rv = NS_OK;
*aKeepReflowGoing = PR_TRUE;
@ -3560,11 +3618,13 @@ nsBlockFrame::ReflowInlineFrames(nsBlockReflowState& aState,
// large.
if (aState.mReflowState.mReflowDepth > 30) {//XXX layout-tune.h?
rv = DoReflowInlineFramesMalloc(aState, aLine, aKeepReflowGoing,
&lineReflowStatus);
&lineReflowStatus,
aUpdateMaximumWidth);
}
else {
rv = DoReflowInlineFramesAuto(aState, aLine, aKeepReflowGoing,
&lineReflowStatus);
&lineReflowStatus,
aUpdateMaximumWidth);
}
if (NS_FAILED(rv)) {
break;
@ -3585,7 +3645,8 @@ nsresult
nsBlockFrame::DoReflowInlineFramesMalloc(nsBlockReflowState& aState,
nsLineBox* aLine,
PRBool* aKeepReflowGoing,
PRUint8* aLineReflowStatus)
PRUint8* aLineReflowStatus,
PRBool aUpdateMaximumWidth)
{
nsLineLayout* ll = new nsLineLayout(aState.mPresContext,
aState.mReflowState.mSpaceManager,
@ -3597,7 +3658,7 @@ nsBlockFrame::DoReflowInlineFramesMalloc(nsBlockReflowState& aState,
ll->Init(&aState, aState.mMinLineHeight, aState.mLineNumber);
ll->SetReflowTextRuns(mTextRuns);
nsresult rv = DoReflowInlineFrames(aState, *ll, aLine, aKeepReflowGoing,
aLineReflowStatus);
aLineReflowStatus, aUpdateMaximumWidth);
ll->EndLineReflow();
delete ll;
return rv;
@ -3607,7 +3668,8 @@ nsresult
nsBlockFrame::DoReflowInlineFramesAuto(nsBlockReflowState& aState,
nsLineBox* aLine,
PRBool* aKeepReflowGoing,
PRUint8* aLineReflowStatus)
PRUint8* aLineReflowStatus,
PRBool aUpdateMaximumWidth)
{
nsLineLayout lineLayout(aState.mPresContext,
aState.mReflowState.mSpaceManager,
@ -3616,17 +3678,19 @@ nsBlockFrame::DoReflowInlineFramesAuto(nsBlockReflowState& aState,
lineLayout.Init(&aState, aState.mMinLineHeight, aState.mLineNumber);
lineLayout.SetReflowTextRuns(mTextRuns);
nsresult rv = DoReflowInlineFrames(aState, lineLayout, aLine,
aKeepReflowGoing, aLineReflowStatus);
aKeepReflowGoing, aLineReflowStatus,
aUpdateMaximumWidth);
lineLayout.EndLineReflow();
return rv;
}
nsresult
nsBlockFrame::DoReflowInlineFrames(nsBlockReflowState& aState,
nsLineLayout& aLineLayout,
nsLineBox* aLine,
PRBool* aKeepReflowGoing,
PRUint8* aLineReflowStatus)
PRUint8* aLineReflowStatus,
PRBool aUpdateMaximumWidth)
{
// Forget all of the floaters on the line
aLine->FreeFloaters(aState.mFloaterCacheFreeList);
@ -3651,6 +3715,9 @@ nsBlockFrame::DoReflowInlineFrames(nsBlockReflowState& aState,
/* XXX get the height right! */
availHeight = aState.mAvailSpaceRect.height;
}
if (aUpdateMaximumWidth) {
availWidth = NS_UNCONSTRAINEDSIZE;
}
aLineLayout.BeginLineReflow(x, aState.mY,
availWidth, availHeight,
impactedByFloaters,
@ -3742,7 +3809,7 @@ nsBlockFrame::DoReflowInlineFrames(nsBlockReflowState& aState,
// If we are propogating out a break-before status then there is
// no point in placing the line.
if (!NS_INLINE_IS_BREAK_BEFORE(aState.mReflowStatus)) {
rv = PlaceLine(aState, aLineLayout, aLine, aKeepReflowGoing);
rv = PlaceLine(aState, aLineLayout, aLine, aKeepReflowGoing, aUpdateMaximumWidth);
}
}
*aLineReflowStatus = lineReflowStatus;
@ -4044,7 +4111,8 @@ nsresult
nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
nsLineLayout& aLineLayout,
nsLineBox* aLine,
PRBool* aKeepReflowGoing)
PRBool* aKeepReflowGoing,
PRBool aUpdateMaximumWidth)
{
nsresult rv = NS_OK;
@ -4190,7 +4258,14 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
ComputeLineMaxElementSize(aState, aLine, &maxElementSize);
}
}
PostPlaceLine(aState, aLine, maxElementSize);
// If we're reflowing the line just to get incrementally update the
// maximum width, then don't post-place the line. It's doing work we
// don't need, and it will update things like aState.mKidXMost that
// we don't want updated...
if (!aUpdateMaximumWidth) {
PostPlaceLine(aState, aLine, maxElementSize);
}
// Add the already placed current-line floaters to the line
aLine->AppendFloaters(aState.mCurrentLineFloaters);

Просмотреть файл

@ -333,6 +333,23 @@ nsLineBox::FreeFloaters(nsFloaterCacheFreeList& aFreeList)
}
}
void
nsLineBox::RemoveFloatersFromSpaceManager(nsISpaceManager* aSpaceManager)
{
if (IsInline()) {
if (mInlineData) {
nsFloaterCache* floaterCache = mInlineData->mFloaters.Head();
while (floaterCache) {
nsIFrame* floater = floaterCache->mPlaceholder->GetOutOfFlowFrame();
aSpaceManager->RemoveRegion(floater);
floaterCache = floaterCache->Next();
}
}
}
}
void
nsLineBox::AppendFloaters(nsFloaterCacheFreeList& aFreeList)
{

Просмотреть файл

@ -243,6 +243,7 @@ public:
void FreeFloaters(nsFloaterCacheFreeList& aFreeList);
void AppendFloaters(nsFloaterCacheFreeList& aFreeList);
PRBool RemoveFloater(nsIFrame* aFrame);
void RemoveFloatersFromSpaceManager(nsISpaceManager* aSpaceManager);
// Combined area
void SetCombinedArea(const nsRect& aCombinedArea);

Просмотреть файл

@ -2442,6 +2442,27 @@ nsBlockFrame::PropogateReflowDamage(nsBlockReflowState& aState,
}
}
static PRBool
WrappedLinesAreDirty(nsLineBox* aLine)
{
if (aLine->IsInline()) {
while (aLine->IsLineWrapped()) {
aLine = aLine->mNext;
if (!aLine) {
break;
}
NS_ASSERTION(!aLine->IsBlock(), "didn't expect a block line");
if (aLine->IsDirty()) {
// we found a continuing line that is dirty
return PR_TRUE;
}
}
}
return PR_FALSE;
}
/**
* Reflow the dirty lines
*/
@ -2495,7 +2516,10 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState)
}
#endif
if (line->IsDirty()) {
// If we're supposed to update our maximum width, then we'll also need to
// reflow this line if it's line wrapped and any of the continuing lines
// are dirty
if (line->IsDirty() || (aState.mComputeMaximumWidth && ::WrappedLinesAreDirty(line))) {
// Compute the dirty lines "before" YMost, after factoring in
// the running deltaY value - the running value is implicit in
// aState.mY.
@ -2746,7 +2770,40 @@ nsBlockFrame::ReflowLine(nsBlockReflowState& aState,
}
else {
aLine->SetLineWrapped(PR_FALSE);
rv = ReflowInlineFrames(aState, aLine, aKeepReflowGoing);
// If we're supposed to update the maximum width, then we'll need to reflow
// the line with an unconstrained width (which will give us the new maximum
// width), then we'll reflow it again with the constrained width.
// We only do this if this is a beginning line, i.e., don't do this for
// lines associated with content that line wrapped (see ReflowDirtyLines()
// for details).
// XXX This approach doesn't work when floaters are involved in which case
// we'll either need to recover the floater state that applies to the
// unconstrained reflow or keep it around in a separate space manager...
if (aState.mComputeMaximumWidth && aState.mPrevLine && !aState.mPrevLine->IsLineWrapped()) {
nscoord oldY = aState.mY;
nscoord oldPrevBottomMargin = aState.mPrevBottomMargin;
// First reflow the line with an unconstrained width
ReflowInlineFrames(aState, aLine, aKeepReflowGoing, PR_TRUE);
// Update the line's maximum width
aLine->mMaximumWidth = aLine->mBounds.XMost();
aState.UpdateMaximumWidth(aLine->mMaximumWidth);
// Remove any floaters associated with the line from the space
// manager
aLine->RemoveFloatersFromSpaceManager(aState.mSpaceManager);
// Now reflow the line again this time without having it compute
// the maximum width
aState.mY = oldY;
aState.mPrevBottomMargin = oldPrevBottomMargin;
rv = ReflowInlineFrames(aState, aLine, aKeepReflowGoing);
} else {
rv = ReflowInlineFrames(aState, aLine, aKeepReflowGoing);
}
// We don't really know what changed in the line, so use the union
// of the old and new combined areas
@ -3545,7 +3602,8 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
nsresult
nsBlockFrame::ReflowInlineFrames(nsBlockReflowState& aState,
nsLineBox* aLine,
PRBool* aKeepReflowGoing)
PRBool* aKeepReflowGoing,
PRBool aUpdateMaximumWidth)
{
nsresult rv = NS_OK;
*aKeepReflowGoing = PR_TRUE;
@ -3560,11 +3618,13 @@ nsBlockFrame::ReflowInlineFrames(nsBlockReflowState& aState,
// large.
if (aState.mReflowState.mReflowDepth > 30) {//XXX layout-tune.h?
rv = DoReflowInlineFramesMalloc(aState, aLine, aKeepReflowGoing,
&lineReflowStatus);
&lineReflowStatus,
aUpdateMaximumWidth);
}
else {
rv = DoReflowInlineFramesAuto(aState, aLine, aKeepReflowGoing,
&lineReflowStatus);
&lineReflowStatus,
aUpdateMaximumWidth);
}
if (NS_FAILED(rv)) {
break;
@ -3585,7 +3645,8 @@ nsresult
nsBlockFrame::DoReflowInlineFramesMalloc(nsBlockReflowState& aState,
nsLineBox* aLine,
PRBool* aKeepReflowGoing,
PRUint8* aLineReflowStatus)
PRUint8* aLineReflowStatus,
PRBool aUpdateMaximumWidth)
{
nsLineLayout* ll = new nsLineLayout(aState.mPresContext,
aState.mReflowState.mSpaceManager,
@ -3597,7 +3658,7 @@ nsBlockFrame::DoReflowInlineFramesMalloc(nsBlockReflowState& aState,
ll->Init(&aState, aState.mMinLineHeight, aState.mLineNumber);
ll->SetReflowTextRuns(mTextRuns);
nsresult rv = DoReflowInlineFrames(aState, *ll, aLine, aKeepReflowGoing,
aLineReflowStatus);
aLineReflowStatus, aUpdateMaximumWidth);
ll->EndLineReflow();
delete ll;
return rv;
@ -3607,7 +3668,8 @@ nsresult
nsBlockFrame::DoReflowInlineFramesAuto(nsBlockReflowState& aState,
nsLineBox* aLine,
PRBool* aKeepReflowGoing,
PRUint8* aLineReflowStatus)
PRUint8* aLineReflowStatus,
PRBool aUpdateMaximumWidth)
{
nsLineLayout lineLayout(aState.mPresContext,
aState.mReflowState.mSpaceManager,
@ -3616,17 +3678,19 @@ nsBlockFrame::DoReflowInlineFramesAuto(nsBlockReflowState& aState,
lineLayout.Init(&aState, aState.mMinLineHeight, aState.mLineNumber);
lineLayout.SetReflowTextRuns(mTextRuns);
nsresult rv = DoReflowInlineFrames(aState, lineLayout, aLine,
aKeepReflowGoing, aLineReflowStatus);
aKeepReflowGoing, aLineReflowStatus,
aUpdateMaximumWidth);
lineLayout.EndLineReflow();
return rv;
}
nsresult
nsBlockFrame::DoReflowInlineFrames(nsBlockReflowState& aState,
nsLineLayout& aLineLayout,
nsLineBox* aLine,
PRBool* aKeepReflowGoing,
PRUint8* aLineReflowStatus)
PRUint8* aLineReflowStatus,
PRBool aUpdateMaximumWidth)
{
// Forget all of the floaters on the line
aLine->FreeFloaters(aState.mFloaterCacheFreeList);
@ -3651,6 +3715,9 @@ nsBlockFrame::DoReflowInlineFrames(nsBlockReflowState& aState,
/* XXX get the height right! */
availHeight = aState.mAvailSpaceRect.height;
}
if (aUpdateMaximumWidth) {
availWidth = NS_UNCONSTRAINEDSIZE;
}
aLineLayout.BeginLineReflow(x, aState.mY,
availWidth, availHeight,
impactedByFloaters,
@ -3742,7 +3809,7 @@ nsBlockFrame::DoReflowInlineFrames(nsBlockReflowState& aState,
// If we are propogating out a break-before status then there is
// no point in placing the line.
if (!NS_INLINE_IS_BREAK_BEFORE(aState.mReflowStatus)) {
rv = PlaceLine(aState, aLineLayout, aLine, aKeepReflowGoing);
rv = PlaceLine(aState, aLineLayout, aLine, aKeepReflowGoing, aUpdateMaximumWidth);
}
}
*aLineReflowStatus = lineReflowStatus;
@ -4044,7 +4111,8 @@ nsresult
nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
nsLineLayout& aLineLayout,
nsLineBox* aLine,
PRBool* aKeepReflowGoing)
PRBool* aKeepReflowGoing,
PRBool aUpdateMaximumWidth)
{
nsresult rv = NS_OK;
@ -4190,7 +4258,14 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
ComputeLineMaxElementSize(aState, aLine, &maxElementSize);
}
}
PostPlaceLine(aState, aLine, maxElementSize);
// If we're reflowing the line just to get incrementally update the
// maximum width, then don't post-place the line. It's doing work we
// don't need, and it will update things like aState.mKidXMost that
// we don't want updated...
if (!aUpdateMaximumWidth) {
PostPlaceLine(aState, aLine, maxElementSize);
}
// Add the already placed current-line floaters to the line
aLine->AppendFloaters(aState.mCurrentLineFloaters);

Просмотреть файл

@ -205,7 +205,8 @@ protected:
nsresult PlaceLine(nsBlockReflowState& aState,
nsLineLayout& aLineLayout,
nsLineBox* aLine,
PRBool* aKeepReflowGoing);
PRBool* aKeepReflowGoing,
PRBool aUpdateMaximumWidth);
// XXX blech
void PostPlaceLine(nsBlockReflowState& aState,
@ -233,23 +234,27 @@ protected:
nsresult ReflowInlineFrames(nsBlockReflowState& aState,
nsLineBox* aLine,
PRBool* aKeepLineGoing);
PRBool* aKeepLineGoing,
PRBool aUpdateMaximumWidth = PR_FALSE);
nsresult DoReflowInlineFrames(nsBlockReflowState& aState,
nsLineLayout& aLineLayout,
nsLineBox* aLine,
PRBool* aKeepReflowGoing,
PRUint8* aLineReflowStatus);
PRUint8* aLineReflowStatus,
PRBool aUpdateMaximumWidth);
nsresult DoReflowInlineFramesAuto(nsBlockReflowState& aState,
nsLineBox* aLine,
PRBool* aKeepReflowGoing,
PRUint8* aLineReflowStatus);
PRUint8* aLineReflowStatus,
PRBool aUpdateMaximumWidth);
nsresult DoReflowInlineFramesMalloc(nsBlockReflowState& aState,
nsLineBox* aLine,
PRBool* aKeepReflowGoing,
PRUint8* aLineReflowStatus);
PRUint8* aLineReflowStatus,
PRBool aUpdateMaximumWidth);
nsresult ReflowInlineFrame(nsBlockReflowState& aState,
nsLineLayout& aLineLayout,

Просмотреть файл

@ -262,6 +262,27 @@ nsBlockReflowContext::ReflowBlock(nsIFrame* aFrame,
nscoord tx = x - mOuterReflowState.mComputedBorderPadding.left;
nscoord ty = y - mOuterReflowState.mComputedBorderPadding.top;
mOuterReflowState.mSpaceManager->Translate(tx, ty);
// See if this is the child's initial reflow and we are supposed to
// compute our maximum width
if (mComputeMaximumWidth && (eReflowReason_Initial == reason)) {
nscoord oldAvailableWidth = reflowState.availableWidth;
nscoord oldComputedWidth = reflowState.mComputedWidth;
reflowState.availableWidth = NS_UNCONSTRAINEDSIZE;
reflowState.mComputedWidth = NS_UNCONSTRAINEDSIZE;
rv = aFrame->Reflow(mPresContext, mMetrics, reflowState,
aFrameReflowStatus);
// Update the reflow metrics with the maximum width
mMetrics.mMaximumWidth = mMetrics.width;
// The second reflow is just as a resize reflow with the constrained
// width
reflowState.availableWidth = oldAvailableWidth;
reflowState.mComputedWidth = oldComputedWidth;
reason = eReflowReason_Resize;
}
rv = aFrame->Reflow(mPresContext, mMetrics, reflowState,
aFrameReflowStatus);
mOuterReflowState.mSpaceManager->Translate(-tx, -ty);

Просмотреть файл

@ -2442,6 +2442,27 @@ nsBlockFrame::PropogateReflowDamage(nsBlockReflowState& aState,
}
}
static PRBool
WrappedLinesAreDirty(nsLineBox* aLine)
{
if (aLine->IsInline()) {
while (aLine->IsLineWrapped()) {
aLine = aLine->mNext;
if (!aLine) {
break;
}
NS_ASSERTION(!aLine->IsBlock(), "didn't expect a block line");
if (aLine->IsDirty()) {
// we found a continuing line that is dirty
return PR_TRUE;
}
}
}
return PR_FALSE;
}
/**
* Reflow the dirty lines
*/
@ -2495,7 +2516,10 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState)
}
#endif
if (line->IsDirty()) {
// If we're supposed to update our maximum width, then we'll also need to
// reflow this line if it's line wrapped and any of the continuing lines
// are dirty
if (line->IsDirty() || (aState.mComputeMaximumWidth && ::WrappedLinesAreDirty(line))) {
// Compute the dirty lines "before" YMost, after factoring in
// the running deltaY value - the running value is implicit in
// aState.mY.
@ -2746,7 +2770,40 @@ nsBlockFrame::ReflowLine(nsBlockReflowState& aState,
}
else {
aLine->SetLineWrapped(PR_FALSE);
rv = ReflowInlineFrames(aState, aLine, aKeepReflowGoing);
// If we're supposed to update the maximum width, then we'll need to reflow
// the line with an unconstrained width (which will give us the new maximum
// width), then we'll reflow it again with the constrained width.
// We only do this if this is a beginning line, i.e., don't do this for
// lines associated with content that line wrapped (see ReflowDirtyLines()
// for details).
// XXX This approach doesn't work when floaters are involved in which case
// we'll either need to recover the floater state that applies to the
// unconstrained reflow or keep it around in a separate space manager...
if (aState.mComputeMaximumWidth && aState.mPrevLine && !aState.mPrevLine->IsLineWrapped()) {
nscoord oldY = aState.mY;
nscoord oldPrevBottomMargin = aState.mPrevBottomMargin;
// First reflow the line with an unconstrained width
ReflowInlineFrames(aState, aLine, aKeepReflowGoing, PR_TRUE);
// Update the line's maximum width
aLine->mMaximumWidth = aLine->mBounds.XMost();
aState.UpdateMaximumWidth(aLine->mMaximumWidth);
// Remove any floaters associated with the line from the space
// manager
aLine->RemoveFloatersFromSpaceManager(aState.mSpaceManager);
// Now reflow the line again this time without having it compute
// the maximum width
aState.mY = oldY;
aState.mPrevBottomMargin = oldPrevBottomMargin;
rv = ReflowInlineFrames(aState, aLine, aKeepReflowGoing);
} else {
rv = ReflowInlineFrames(aState, aLine, aKeepReflowGoing);
}
// We don't really know what changed in the line, so use the union
// of the old and new combined areas
@ -3545,7 +3602,8 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
nsresult
nsBlockFrame::ReflowInlineFrames(nsBlockReflowState& aState,
nsLineBox* aLine,
PRBool* aKeepReflowGoing)
PRBool* aKeepReflowGoing,
PRBool aUpdateMaximumWidth)
{
nsresult rv = NS_OK;
*aKeepReflowGoing = PR_TRUE;
@ -3560,11 +3618,13 @@ nsBlockFrame::ReflowInlineFrames(nsBlockReflowState& aState,
// large.
if (aState.mReflowState.mReflowDepth > 30) {//XXX layout-tune.h?
rv = DoReflowInlineFramesMalloc(aState, aLine, aKeepReflowGoing,
&lineReflowStatus);
&lineReflowStatus,
aUpdateMaximumWidth);
}
else {
rv = DoReflowInlineFramesAuto(aState, aLine, aKeepReflowGoing,
&lineReflowStatus);
&lineReflowStatus,
aUpdateMaximumWidth);
}
if (NS_FAILED(rv)) {
break;
@ -3585,7 +3645,8 @@ nsresult
nsBlockFrame::DoReflowInlineFramesMalloc(nsBlockReflowState& aState,
nsLineBox* aLine,
PRBool* aKeepReflowGoing,
PRUint8* aLineReflowStatus)
PRUint8* aLineReflowStatus,
PRBool aUpdateMaximumWidth)
{
nsLineLayout* ll = new nsLineLayout(aState.mPresContext,
aState.mReflowState.mSpaceManager,
@ -3597,7 +3658,7 @@ nsBlockFrame::DoReflowInlineFramesMalloc(nsBlockReflowState& aState,
ll->Init(&aState, aState.mMinLineHeight, aState.mLineNumber);
ll->SetReflowTextRuns(mTextRuns);
nsresult rv = DoReflowInlineFrames(aState, *ll, aLine, aKeepReflowGoing,
aLineReflowStatus);
aLineReflowStatus, aUpdateMaximumWidth);
ll->EndLineReflow();
delete ll;
return rv;
@ -3607,7 +3668,8 @@ nsresult
nsBlockFrame::DoReflowInlineFramesAuto(nsBlockReflowState& aState,
nsLineBox* aLine,
PRBool* aKeepReflowGoing,
PRUint8* aLineReflowStatus)
PRUint8* aLineReflowStatus,
PRBool aUpdateMaximumWidth)
{
nsLineLayout lineLayout(aState.mPresContext,
aState.mReflowState.mSpaceManager,
@ -3616,17 +3678,19 @@ nsBlockFrame::DoReflowInlineFramesAuto(nsBlockReflowState& aState,
lineLayout.Init(&aState, aState.mMinLineHeight, aState.mLineNumber);
lineLayout.SetReflowTextRuns(mTextRuns);
nsresult rv = DoReflowInlineFrames(aState, lineLayout, aLine,
aKeepReflowGoing, aLineReflowStatus);
aKeepReflowGoing, aLineReflowStatus,
aUpdateMaximumWidth);
lineLayout.EndLineReflow();
return rv;
}
nsresult
nsBlockFrame::DoReflowInlineFrames(nsBlockReflowState& aState,
nsLineLayout& aLineLayout,
nsLineBox* aLine,
PRBool* aKeepReflowGoing,
PRUint8* aLineReflowStatus)
PRUint8* aLineReflowStatus,
PRBool aUpdateMaximumWidth)
{
// Forget all of the floaters on the line
aLine->FreeFloaters(aState.mFloaterCacheFreeList);
@ -3651,6 +3715,9 @@ nsBlockFrame::DoReflowInlineFrames(nsBlockReflowState& aState,
/* XXX get the height right! */
availHeight = aState.mAvailSpaceRect.height;
}
if (aUpdateMaximumWidth) {
availWidth = NS_UNCONSTRAINEDSIZE;
}
aLineLayout.BeginLineReflow(x, aState.mY,
availWidth, availHeight,
impactedByFloaters,
@ -3742,7 +3809,7 @@ nsBlockFrame::DoReflowInlineFrames(nsBlockReflowState& aState,
// If we are propogating out a break-before status then there is
// no point in placing the line.
if (!NS_INLINE_IS_BREAK_BEFORE(aState.mReflowStatus)) {
rv = PlaceLine(aState, aLineLayout, aLine, aKeepReflowGoing);
rv = PlaceLine(aState, aLineLayout, aLine, aKeepReflowGoing, aUpdateMaximumWidth);
}
}
*aLineReflowStatus = lineReflowStatus;
@ -4044,7 +4111,8 @@ nsresult
nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
nsLineLayout& aLineLayout,
nsLineBox* aLine,
PRBool* aKeepReflowGoing)
PRBool* aKeepReflowGoing,
PRBool aUpdateMaximumWidth)
{
nsresult rv = NS_OK;
@ -4190,7 +4258,14 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
ComputeLineMaxElementSize(aState, aLine, &maxElementSize);
}
}
PostPlaceLine(aState, aLine, maxElementSize);
// If we're reflowing the line just to get incrementally update the
// maximum width, then don't post-place the line. It's doing work we
// don't need, and it will update things like aState.mKidXMost that
// we don't want updated...
if (!aUpdateMaximumWidth) {
PostPlaceLine(aState, aLine, maxElementSize);
}
// Add the already placed current-line floaters to the line
aLine->AppendFloaters(aState.mCurrentLineFloaters);

Просмотреть файл

@ -2442,6 +2442,27 @@ nsBlockFrame::PropogateReflowDamage(nsBlockReflowState& aState,
}
}
static PRBool
WrappedLinesAreDirty(nsLineBox* aLine)
{
if (aLine->IsInline()) {
while (aLine->IsLineWrapped()) {
aLine = aLine->mNext;
if (!aLine) {
break;
}
NS_ASSERTION(!aLine->IsBlock(), "didn't expect a block line");
if (aLine->IsDirty()) {
// we found a continuing line that is dirty
return PR_TRUE;
}
}
}
return PR_FALSE;
}
/**
* Reflow the dirty lines
*/
@ -2495,7 +2516,10 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState)
}
#endif
if (line->IsDirty()) {
// If we're supposed to update our maximum width, then we'll also need to
// reflow this line if it's line wrapped and any of the continuing lines
// are dirty
if (line->IsDirty() || (aState.mComputeMaximumWidth && ::WrappedLinesAreDirty(line))) {
// Compute the dirty lines "before" YMost, after factoring in
// the running deltaY value - the running value is implicit in
// aState.mY.
@ -2746,7 +2770,40 @@ nsBlockFrame::ReflowLine(nsBlockReflowState& aState,
}
else {
aLine->SetLineWrapped(PR_FALSE);
rv = ReflowInlineFrames(aState, aLine, aKeepReflowGoing);
// If we're supposed to update the maximum width, then we'll need to reflow
// the line with an unconstrained width (which will give us the new maximum
// width), then we'll reflow it again with the constrained width.
// We only do this if this is a beginning line, i.e., don't do this for
// lines associated with content that line wrapped (see ReflowDirtyLines()
// for details).
// XXX This approach doesn't work when floaters are involved in which case
// we'll either need to recover the floater state that applies to the
// unconstrained reflow or keep it around in a separate space manager...
if (aState.mComputeMaximumWidth && aState.mPrevLine && !aState.mPrevLine->IsLineWrapped()) {
nscoord oldY = aState.mY;
nscoord oldPrevBottomMargin = aState.mPrevBottomMargin;
// First reflow the line with an unconstrained width
ReflowInlineFrames(aState, aLine, aKeepReflowGoing, PR_TRUE);
// Update the line's maximum width
aLine->mMaximumWidth = aLine->mBounds.XMost();
aState.UpdateMaximumWidth(aLine->mMaximumWidth);
// Remove any floaters associated with the line from the space
// manager
aLine->RemoveFloatersFromSpaceManager(aState.mSpaceManager);
// Now reflow the line again this time without having it compute
// the maximum width
aState.mY = oldY;
aState.mPrevBottomMargin = oldPrevBottomMargin;
rv = ReflowInlineFrames(aState, aLine, aKeepReflowGoing);
} else {
rv = ReflowInlineFrames(aState, aLine, aKeepReflowGoing);
}
// We don't really know what changed in the line, so use the union
// of the old and new combined areas
@ -3545,7 +3602,8 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
nsresult
nsBlockFrame::ReflowInlineFrames(nsBlockReflowState& aState,
nsLineBox* aLine,
PRBool* aKeepReflowGoing)
PRBool* aKeepReflowGoing,
PRBool aUpdateMaximumWidth)
{
nsresult rv = NS_OK;
*aKeepReflowGoing = PR_TRUE;
@ -3560,11 +3618,13 @@ nsBlockFrame::ReflowInlineFrames(nsBlockReflowState& aState,
// large.
if (aState.mReflowState.mReflowDepth > 30) {//XXX layout-tune.h?
rv = DoReflowInlineFramesMalloc(aState, aLine, aKeepReflowGoing,
&lineReflowStatus);
&lineReflowStatus,
aUpdateMaximumWidth);
}
else {
rv = DoReflowInlineFramesAuto(aState, aLine, aKeepReflowGoing,
&lineReflowStatus);
&lineReflowStatus,
aUpdateMaximumWidth);
}
if (NS_FAILED(rv)) {
break;
@ -3585,7 +3645,8 @@ nsresult
nsBlockFrame::DoReflowInlineFramesMalloc(nsBlockReflowState& aState,
nsLineBox* aLine,
PRBool* aKeepReflowGoing,
PRUint8* aLineReflowStatus)
PRUint8* aLineReflowStatus,
PRBool aUpdateMaximumWidth)
{
nsLineLayout* ll = new nsLineLayout(aState.mPresContext,
aState.mReflowState.mSpaceManager,
@ -3597,7 +3658,7 @@ nsBlockFrame::DoReflowInlineFramesMalloc(nsBlockReflowState& aState,
ll->Init(&aState, aState.mMinLineHeight, aState.mLineNumber);
ll->SetReflowTextRuns(mTextRuns);
nsresult rv = DoReflowInlineFrames(aState, *ll, aLine, aKeepReflowGoing,
aLineReflowStatus);
aLineReflowStatus, aUpdateMaximumWidth);
ll->EndLineReflow();
delete ll;
return rv;
@ -3607,7 +3668,8 @@ nsresult
nsBlockFrame::DoReflowInlineFramesAuto(nsBlockReflowState& aState,
nsLineBox* aLine,
PRBool* aKeepReflowGoing,
PRUint8* aLineReflowStatus)
PRUint8* aLineReflowStatus,
PRBool aUpdateMaximumWidth)
{
nsLineLayout lineLayout(aState.mPresContext,
aState.mReflowState.mSpaceManager,
@ -3616,17 +3678,19 @@ nsBlockFrame::DoReflowInlineFramesAuto(nsBlockReflowState& aState,
lineLayout.Init(&aState, aState.mMinLineHeight, aState.mLineNumber);
lineLayout.SetReflowTextRuns(mTextRuns);
nsresult rv = DoReflowInlineFrames(aState, lineLayout, aLine,
aKeepReflowGoing, aLineReflowStatus);
aKeepReflowGoing, aLineReflowStatus,
aUpdateMaximumWidth);
lineLayout.EndLineReflow();
return rv;
}
nsresult
nsBlockFrame::DoReflowInlineFrames(nsBlockReflowState& aState,
nsLineLayout& aLineLayout,
nsLineBox* aLine,
PRBool* aKeepReflowGoing,
PRUint8* aLineReflowStatus)
PRUint8* aLineReflowStatus,
PRBool aUpdateMaximumWidth)
{
// Forget all of the floaters on the line
aLine->FreeFloaters(aState.mFloaterCacheFreeList);
@ -3651,6 +3715,9 @@ nsBlockFrame::DoReflowInlineFrames(nsBlockReflowState& aState,
/* XXX get the height right! */
availHeight = aState.mAvailSpaceRect.height;
}
if (aUpdateMaximumWidth) {
availWidth = NS_UNCONSTRAINEDSIZE;
}
aLineLayout.BeginLineReflow(x, aState.mY,
availWidth, availHeight,
impactedByFloaters,
@ -3742,7 +3809,7 @@ nsBlockFrame::DoReflowInlineFrames(nsBlockReflowState& aState,
// If we are propogating out a break-before status then there is
// no point in placing the line.
if (!NS_INLINE_IS_BREAK_BEFORE(aState.mReflowStatus)) {
rv = PlaceLine(aState, aLineLayout, aLine, aKeepReflowGoing);
rv = PlaceLine(aState, aLineLayout, aLine, aKeepReflowGoing, aUpdateMaximumWidth);
}
}
*aLineReflowStatus = lineReflowStatus;
@ -4044,7 +4111,8 @@ nsresult
nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
nsLineLayout& aLineLayout,
nsLineBox* aLine,
PRBool* aKeepReflowGoing)
PRBool* aKeepReflowGoing,
PRBool aUpdateMaximumWidth)
{
nsresult rv = NS_OK;
@ -4190,7 +4258,14 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
ComputeLineMaxElementSize(aState, aLine, &maxElementSize);
}
}
PostPlaceLine(aState, aLine, maxElementSize);
// If we're reflowing the line just to get incrementally update the
// maximum width, then don't post-place the line. It's doing work we
// don't need, and it will update things like aState.mKidXMost that
// we don't want updated...
if (!aUpdateMaximumWidth) {
PostPlaceLine(aState, aLine, maxElementSize);
}
// Add the already placed current-line floaters to the line
aLine->AppendFloaters(aState.mCurrentLineFloaters);

Просмотреть файл

@ -333,6 +333,23 @@ nsLineBox::FreeFloaters(nsFloaterCacheFreeList& aFreeList)
}
}
void
nsLineBox::RemoveFloatersFromSpaceManager(nsISpaceManager* aSpaceManager)
{
if (IsInline()) {
if (mInlineData) {
nsFloaterCache* floaterCache = mInlineData->mFloaters.Head();
while (floaterCache) {
nsIFrame* floater = floaterCache->mPlaceholder->GetOutOfFlowFrame();
aSpaceManager->RemoveRegion(floater);
floaterCache = floaterCache->Next();
}
}
}
}
void
nsLineBox::AppendFloaters(nsFloaterCacheFreeList& aFreeList)
{

Просмотреть файл

@ -243,6 +243,7 @@ public:
void FreeFloaters(nsFloaterCacheFreeList& aFreeList);
void AppendFloaters(nsFloaterCacheFreeList& aFreeList);
PRBool RemoveFloater(nsIFrame* aFrame);
void RemoveFloatersFromSpaceManager(nsISpaceManager* aSpaceManager);
// Combined area
void SetCombinedArea(const nsRect& aCombinedArea);