mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-02 12:07:52 +00:00
Work in progress on block incremental reflow
This commit is contained in:
parent
e09e86128b
commit
e0a3f308d8
@ -142,6 +142,45 @@ nsBlockReflowState::Initialize(nsIPresContext* aPresContext,
|
|||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Recover the block reflow state to what it should be if aLine is about
|
||||||
|
// to be reflowed. aLine should not be nsnull
|
||||||
|
nsresult nsBlockReflowState::RecoverState(nsLineData* aLine)
|
||||||
|
{
|
||||||
|
NS_PRECONDITION(nsnull != aLine, "null parameter");
|
||||||
|
nsLineData* prevLine = aLine->mPrevLine;
|
||||||
|
|
||||||
|
if (nsnull != prevLine) {
|
||||||
|
// Compute the running y-offset, and the available height
|
||||||
|
mY = prevLine->mBounds.YMost();
|
||||||
|
if (!mUnconstrainedHeight) {
|
||||||
|
mAvailSize.height -= mY;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute the kid x-most
|
||||||
|
for (nsLineData* l = prevLine; nsnull != l; l = l->mPrevLine) {
|
||||||
|
nscoord xmost = l->mBounds.XMost();
|
||||||
|
if (xmost > mKidXMost) {
|
||||||
|
mKidXMost = xmost;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the previous line is a block, then factor in its bottom margin
|
||||||
|
if (prevLine->mIsBlock) {
|
||||||
|
nsStyleSpacing* spacing;
|
||||||
|
nsIFrame* kid = prevLine->mFirstChild;
|
||||||
|
|
||||||
|
kid->GetStyleData(kStyleSpacingSID, (nsStyleStruct*&)spacing);
|
||||||
|
if (spacing->mMargin.bottom < 0) {
|
||||||
|
mPrevMaxNegBottomMargin = -spacing->mMargin.bottom;
|
||||||
|
} else {
|
||||||
|
mPrevMaxPosBottomMargin = spacing->mMargin.bottom;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
@ -780,6 +819,52 @@ done:
|
|||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// XXX This is a short-term hack. It assumes that the caller has already recovered
|
||||||
|
// the state, and that some space has been retrieved from the space manager...
|
||||||
|
nsresult
|
||||||
|
nsBlockFrame::ReflowMappedFrom(nsBlockReflowState& aState, nsLineData* aLine)
|
||||||
|
{
|
||||||
|
nsresult rv = NS_OK;
|
||||||
|
|
||||||
|
nsLineLayout lineLayout(aState);
|
||||||
|
aState.mCurrentLine = &lineLayout;
|
||||||
|
while (nsnull != aLine) {
|
||||||
|
// Initialize the line layout for this line
|
||||||
|
rv = lineLayout.Initialize(aState, aLine);
|
||||||
|
if (NS_OK != rv) {
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
lineLayout.mPrevKidFrame = aState.mPrevKidFrame;
|
||||||
|
|
||||||
|
// Reflow the line
|
||||||
|
nsresult lineReflowStatus = lineLayout.ReflowLine();
|
||||||
|
if (lineReflowStatus < 0) {
|
||||||
|
// Some kind of hard error
|
||||||
|
rv = lineReflowStatus;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
mChildCount += lineLayout.mNewFrames;
|
||||||
|
|
||||||
|
// Now place it. It's possible it won't fit.
|
||||||
|
rv = PlaceLine(aState, lineLayout, aLine);
|
||||||
|
if (NS_LINE_LAYOUT_COMPLETE != rv) {
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
mLastContentOffset = aLine->mLastContentOffset;
|
||||||
|
mLastContentIsComplete = PRBool(aLine->mLastContentIsComplete);
|
||||||
|
aLine = aLine->mNextLine;
|
||||||
|
aState.mPrevKidFrame = lineLayout.mPrevKidFrame;
|
||||||
|
}
|
||||||
|
|
||||||
|
done:
|
||||||
|
aState.mCurrentLine = nsnull;
|
||||||
|
#ifdef NS_DEBUG
|
||||||
|
VerifyLines(PR_TRUE);
|
||||||
|
#endif
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
nsBlockFrame::ReflowUnmapped(nsBlockReflowState& aState)
|
nsBlockFrame::ReflowUnmapped(nsBlockReflowState& aState)
|
||||||
{
|
{
|
||||||
@ -1194,6 +1279,51 @@ nsBlockFrame::ResizeReflow(nsIPresContext* aPresContext,
|
|||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nsLineData* nsBlockFrame::FindLine(nsIFrame* aFrame)
|
||||||
|
{
|
||||||
|
// Find the line that contains the aFrame
|
||||||
|
nsLineData* line = mLines;
|
||||||
|
while (nsnull != line) {
|
||||||
|
nsIFrame* child = line->mFirstChild;
|
||||||
|
for (PRInt32 count = line->mChildCount; count > 0; count--) {
|
||||||
|
if (child == aFrame) {
|
||||||
|
return line;
|
||||||
|
}
|
||||||
|
|
||||||
|
child->GetNextSibling(child);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move to the next line
|
||||||
|
line = line->mNextLine;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nsnull;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsLineData* nsBlockFrame::LastLine()
|
||||||
|
{
|
||||||
|
nsLineData* lastLine = mLines;
|
||||||
|
|
||||||
|
// Get the last line
|
||||||
|
if (nsnull != lastLine) {
|
||||||
|
while (nsnull != lastLine->mNextLine) {
|
||||||
|
lastLine = lastLine->mNextLine;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return lastLine;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult nsBlockFrame::IncrementalReflowAfter(nsBlockReflowState& aState,
|
||||||
|
nsLineData* aLine,
|
||||||
|
nsresult aReflowStatus,
|
||||||
|
const nsRect& aOldBounds)
|
||||||
|
{
|
||||||
|
// Now just reflow all the lines that follow...
|
||||||
|
// XXX Obviously this needs to be more efficient
|
||||||
|
return ReflowMappedFrom(aState, aLine->mNextLine);
|
||||||
|
}
|
||||||
|
|
||||||
NS_METHOD
|
NS_METHOD
|
||||||
nsBlockFrame::IncrementalReflow(nsIPresContext* aPresContext,
|
nsBlockFrame::IncrementalReflow(nsIPresContext* aPresContext,
|
||||||
nsISpaceManager* aSpaceManager,
|
nsISpaceManager* aSpaceManager,
|
||||||
@ -1219,39 +1349,11 @@ nsBlockFrame::IncrementalReflow(nsIPresContext* aPresContext,
|
|||||||
// Is the reflow command target at us?
|
// Is the reflow command target at us?
|
||||||
if (this == aReflowCommand.GetTarget()) {
|
if (this == aReflowCommand.GetTarget()) {
|
||||||
if (aReflowCommand.GetType() == nsReflowCommand::FrameAppended) {
|
if (aReflowCommand.GetType() == nsReflowCommand::FrameAppended) {
|
||||||
nsLineData* lastLine = mLines;
|
nsLineData* lastLine = LastLine();
|
||||||
|
|
||||||
// Get the last line
|
|
||||||
if (nsnull != lastLine) {
|
|
||||||
while (nsnull != lastLine->mNextLine) {
|
|
||||||
lastLine = lastLine->mNextLine;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Restore the state
|
// Restore the state
|
||||||
if ((nsnull != lastLine) && (nsnull != lastLine->mPrevLine)) {
|
if (nsnull != lastLine) {
|
||||||
nsLineData* prevLine = lastLine->mPrevLine;
|
state.RecoverState(lastLine);
|
||||||
|
|
||||||
state.mY = prevLine->mBounds.YMost();
|
|
||||||
if (!state.mUnconstrainedHeight) {
|
|
||||||
state.mAvailSize.height -= state.mY;
|
|
||||||
}
|
|
||||||
|
|
||||||
// XXX This isn't really right...
|
|
||||||
state.mKidXMost = mRect.width - state.mBorderPadding.right;
|
|
||||||
|
|
||||||
// If the previous line is a block, then factor in its bottom margin
|
|
||||||
if (prevLine->mIsBlock) {
|
|
||||||
nsStyleSpacing* spacing;
|
|
||||||
nsIFrame* kid = prevLine->mFirstChild;
|
|
||||||
|
|
||||||
kid->GetStyleData(kStyleSpacingSID, (nsStyleStruct*&)spacing);
|
|
||||||
if (spacing->mMargin.bottom < 0) {
|
|
||||||
state.mPrevMaxNegBottomMargin = -spacing->mMargin.bottom;
|
|
||||||
} else {
|
|
||||||
state.mPrevMaxPosBottomMargin = spacing->mMargin.bottom;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reflow unmapped children
|
// Reflow unmapped children
|
||||||
@ -1267,38 +1369,65 @@ nsBlockFrame::IncrementalReflow(nsIPresContext* aPresContext,
|
|||||||
rv = ReflowUnmapped(state);
|
rv = ReflowUnmapped(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set return status
|
} else if (aReflowCommand.GetType() == nsReflowCommand::ContentChanged) {
|
||||||
aStatus = frComplete;
|
// Restore our state as if the child that changed is the next frame to reflow
|
||||||
if (NS_LINE_LAYOUT_NOT_COMPLETE == rv) {
|
nsLineData* line = FindLine(aReflowCommand.GetChildFrame());
|
||||||
rv = NS_OK;
|
state.RecoverState(line);
|
||||||
aStatus = frNotComplete;
|
|
||||||
}
|
// Get some available space to start reflowing with
|
||||||
|
GetAvailableSpace(state, state.mY);
|
||||||
|
|
||||||
|
// Reflow the affected line, and all the lines that follow...
|
||||||
|
// XXX Obviously this needs to be more efficient
|
||||||
|
rv = ReflowMappedFrom(state, line);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
NS_NOTYETIMPLEMENTED("unexpected reflow command");
|
NS_NOTYETIMPLEMENTED("unexpected reflow command");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
#if 0
|
|
||||||
// The command is passing through us. Get the next frame in the reflow chain
|
// The command is passing through us. Get the next frame in the reflow chain
|
||||||
nsIFrame* nextFrame = aReflowCommand.GetNext();
|
nsIFrame* nextFrame = aReflowCommand.GetNext();
|
||||||
|
|
||||||
// Restore our state as if nextFrame is the next frame to reflow
|
// Restore our state as if nextFrame is the next frame to reflow
|
||||||
RecoverState(aPresContext, state, nextFrame);
|
nsLineData* line = FindLine(nextFrame);
|
||||||
|
state.RecoverState(line);
|
||||||
|
|
||||||
// Get the current bounds. We'll need this to adjust the frames that follow
|
// Get some available space to start reflowing with
|
||||||
nsRect oldBounds;
|
GetAvailableSpace(state, state.mY);
|
||||||
nextFrame->GetRect(oldBounds);
|
|
||||||
|
|
||||||
// Pass along the reflow command
|
// Reflow the affected line
|
||||||
nsRect desiredRect;
|
nsLineLayout lineLayout(state);
|
||||||
aStatus = aReflowCommand.Next(aSpaceManager, desiredRect, aMaxSize, nextFrame);
|
|
||||||
#endif
|
state.mCurrentLine = &lineLayout;
|
||||||
NS_NOTYETIMPLEMENTED("unexpected reflow command");
|
lineLayout.Initialize(state, line);
|
||||||
|
|
||||||
|
// Have the line handle the incremental reflow
|
||||||
|
nsRect oldBounds = line->mBounds;
|
||||||
|
rv = lineLayout.IncrementalReflowFromChild(aReflowCommand, nextFrame);
|
||||||
|
|
||||||
|
// Now place the line. It's possible it won't fit
|
||||||
|
rv = PlaceLine(state, lineLayout, line);
|
||||||
|
// XXX The way NS_LINE_LAYOUT_COMPLETE is being used is very confusing...
|
||||||
|
if (NS_LINE_LAYOUT_COMPLETE == rv) {
|
||||||
|
mLastContentOffset = line->mLastContentOffset;
|
||||||
|
mLastContentIsComplete = PRBool(line->mLastContentIsComplete);
|
||||||
|
state.mPrevKidFrame = lineLayout.mPrevKidFrame;
|
||||||
|
|
||||||
|
// Now figure out what to do with the frames that follow
|
||||||
|
rv = IncrementalReflowAfter(state, line, rv, oldBounds);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return our desired rect
|
// Return our desired rect
|
||||||
ComputeDesiredRect(state, aMaxSize, aDesiredRect);
|
ComputeDesiredRect(state, aMaxSize, aDesiredRect);
|
||||||
|
|
||||||
|
// Set return status
|
||||||
|
aStatus = frComplete;
|
||||||
|
if (NS_LINE_LAYOUT_NOT_COMPLETE == rv) {
|
||||||
|
rv = NS_OK;
|
||||||
|
aStatus = frNotComplete;
|
||||||
|
}
|
||||||
|
|
||||||
// Now that reflow has finished, remove the cached pointer
|
// Now that reflow has finished, remove the cached pointer
|
||||||
shell->RemoveCachedData(this);
|
shell->RemoveCachedData(this);
|
||||||
NS_RELEASE(shell);
|
NS_RELEASE(shell);
|
||||||
|
@ -33,7 +33,7 @@ class nsBlockFrame;
|
|||||||
struct nsBandData;
|
struct nsBandData;
|
||||||
|
|
||||||
struct nsBlockBandData : public nsBandData {
|
struct nsBlockBandData : public nsBandData {
|
||||||
// Trapezoid's used during band processing
|
// Trapezoids used during band processing
|
||||||
nsBandTrapezoid data[12];
|
nsBandTrapezoid data[12];
|
||||||
|
|
||||||
// Bounding rect of available space between any left and right floaters
|
// Bounding rect of available space between any left and right floaters
|
||||||
@ -63,6 +63,8 @@ struct nsBlockReflowState {
|
|||||||
nsSize* aMaxElementSize,
|
nsSize* aMaxElementSize,
|
||||||
nsBlockFrame* aBlock);
|
nsBlockFrame* aBlock);
|
||||||
|
|
||||||
|
nsresult RecoverState(nsLineData* aLine);
|
||||||
|
|
||||||
nsIPresContext* mPresContext;
|
nsIPresContext* mPresContext;
|
||||||
|
|
||||||
nsBlockFrame* mBlock;
|
nsBlockFrame* mBlock;
|
||||||
@ -249,6 +251,14 @@ protected:
|
|||||||
const nsSize& aMaxSize,
|
const nsSize& aMaxSize,
|
||||||
nsRect& aDesiredRect);
|
nsRect& aDesiredRect);
|
||||||
|
|
||||||
|
nsLineData* LastLine();
|
||||||
|
nsLineData* FindLine(nsIFrame* aFrame);
|
||||||
|
|
||||||
|
nsresult IncrementalReflowAfter(nsBlockReflowState& aState,
|
||||||
|
nsLineData* aLine,
|
||||||
|
nsresult aReflowStatus,
|
||||||
|
const nsRect& aOldBounds);
|
||||||
|
|
||||||
void DestroyLines();
|
void DestroyLines();
|
||||||
|
|
||||||
void DrainOverflowList();
|
void DrainOverflowList();
|
||||||
@ -278,6 +288,7 @@ protected:
|
|||||||
nsLineData* aLine);
|
nsLineData* aLine);
|
||||||
|
|
||||||
nsresult ReflowMapped(nsBlockReflowState& aState);
|
nsresult ReflowMapped(nsBlockReflowState& aState);
|
||||||
|
nsresult ReflowMappedFrom(nsBlockReflowState& aState, nsLineData* aLine);
|
||||||
|
|
||||||
nsresult ReflowUnmapped(nsBlockReflowState& aState);
|
nsresult ReflowUnmapped(nsBlockReflowState& aState);
|
||||||
|
|
||||||
|
@ -142,6 +142,45 @@ nsBlockReflowState::Initialize(nsIPresContext* aPresContext,
|
|||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Recover the block reflow state to what it should be if aLine is about
|
||||||
|
// to be reflowed. aLine should not be nsnull
|
||||||
|
nsresult nsBlockReflowState::RecoverState(nsLineData* aLine)
|
||||||
|
{
|
||||||
|
NS_PRECONDITION(nsnull != aLine, "null parameter");
|
||||||
|
nsLineData* prevLine = aLine->mPrevLine;
|
||||||
|
|
||||||
|
if (nsnull != prevLine) {
|
||||||
|
// Compute the running y-offset, and the available height
|
||||||
|
mY = prevLine->mBounds.YMost();
|
||||||
|
if (!mUnconstrainedHeight) {
|
||||||
|
mAvailSize.height -= mY;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute the kid x-most
|
||||||
|
for (nsLineData* l = prevLine; nsnull != l; l = l->mPrevLine) {
|
||||||
|
nscoord xmost = l->mBounds.XMost();
|
||||||
|
if (xmost > mKidXMost) {
|
||||||
|
mKidXMost = xmost;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the previous line is a block, then factor in its bottom margin
|
||||||
|
if (prevLine->mIsBlock) {
|
||||||
|
nsStyleSpacing* spacing;
|
||||||
|
nsIFrame* kid = prevLine->mFirstChild;
|
||||||
|
|
||||||
|
kid->GetStyleData(kStyleSpacingSID, (nsStyleStruct*&)spacing);
|
||||||
|
if (spacing->mMargin.bottom < 0) {
|
||||||
|
mPrevMaxNegBottomMargin = -spacing->mMargin.bottom;
|
||||||
|
} else {
|
||||||
|
mPrevMaxPosBottomMargin = spacing->mMargin.bottom;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
@ -780,6 +819,52 @@ done:
|
|||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// XXX This is a short-term hack. It assumes that the caller has already recovered
|
||||||
|
// the state, and that some space has been retrieved from the space manager...
|
||||||
|
nsresult
|
||||||
|
nsBlockFrame::ReflowMappedFrom(nsBlockReflowState& aState, nsLineData* aLine)
|
||||||
|
{
|
||||||
|
nsresult rv = NS_OK;
|
||||||
|
|
||||||
|
nsLineLayout lineLayout(aState);
|
||||||
|
aState.mCurrentLine = &lineLayout;
|
||||||
|
while (nsnull != aLine) {
|
||||||
|
// Initialize the line layout for this line
|
||||||
|
rv = lineLayout.Initialize(aState, aLine);
|
||||||
|
if (NS_OK != rv) {
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
lineLayout.mPrevKidFrame = aState.mPrevKidFrame;
|
||||||
|
|
||||||
|
// Reflow the line
|
||||||
|
nsresult lineReflowStatus = lineLayout.ReflowLine();
|
||||||
|
if (lineReflowStatus < 0) {
|
||||||
|
// Some kind of hard error
|
||||||
|
rv = lineReflowStatus;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
mChildCount += lineLayout.mNewFrames;
|
||||||
|
|
||||||
|
// Now place it. It's possible it won't fit.
|
||||||
|
rv = PlaceLine(aState, lineLayout, aLine);
|
||||||
|
if (NS_LINE_LAYOUT_COMPLETE != rv) {
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
mLastContentOffset = aLine->mLastContentOffset;
|
||||||
|
mLastContentIsComplete = PRBool(aLine->mLastContentIsComplete);
|
||||||
|
aLine = aLine->mNextLine;
|
||||||
|
aState.mPrevKidFrame = lineLayout.mPrevKidFrame;
|
||||||
|
}
|
||||||
|
|
||||||
|
done:
|
||||||
|
aState.mCurrentLine = nsnull;
|
||||||
|
#ifdef NS_DEBUG
|
||||||
|
VerifyLines(PR_TRUE);
|
||||||
|
#endif
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
nsBlockFrame::ReflowUnmapped(nsBlockReflowState& aState)
|
nsBlockFrame::ReflowUnmapped(nsBlockReflowState& aState)
|
||||||
{
|
{
|
||||||
@ -1194,6 +1279,51 @@ nsBlockFrame::ResizeReflow(nsIPresContext* aPresContext,
|
|||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nsLineData* nsBlockFrame::FindLine(nsIFrame* aFrame)
|
||||||
|
{
|
||||||
|
// Find the line that contains the aFrame
|
||||||
|
nsLineData* line = mLines;
|
||||||
|
while (nsnull != line) {
|
||||||
|
nsIFrame* child = line->mFirstChild;
|
||||||
|
for (PRInt32 count = line->mChildCount; count > 0; count--) {
|
||||||
|
if (child == aFrame) {
|
||||||
|
return line;
|
||||||
|
}
|
||||||
|
|
||||||
|
child->GetNextSibling(child);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move to the next line
|
||||||
|
line = line->mNextLine;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nsnull;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsLineData* nsBlockFrame::LastLine()
|
||||||
|
{
|
||||||
|
nsLineData* lastLine = mLines;
|
||||||
|
|
||||||
|
// Get the last line
|
||||||
|
if (nsnull != lastLine) {
|
||||||
|
while (nsnull != lastLine->mNextLine) {
|
||||||
|
lastLine = lastLine->mNextLine;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return lastLine;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult nsBlockFrame::IncrementalReflowAfter(nsBlockReflowState& aState,
|
||||||
|
nsLineData* aLine,
|
||||||
|
nsresult aReflowStatus,
|
||||||
|
const nsRect& aOldBounds)
|
||||||
|
{
|
||||||
|
// Now just reflow all the lines that follow...
|
||||||
|
// XXX Obviously this needs to be more efficient
|
||||||
|
return ReflowMappedFrom(aState, aLine->mNextLine);
|
||||||
|
}
|
||||||
|
|
||||||
NS_METHOD
|
NS_METHOD
|
||||||
nsBlockFrame::IncrementalReflow(nsIPresContext* aPresContext,
|
nsBlockFrame::IncrementalReflow(nsIPresContext* aPresContext,
|
||||||
nsISpaceManager* aSpaceManager,
|
nsISpaceManager* aSpaceManager,
|
||||||
@ -1219,39 +1349,11 @@ nsBlockFrame::IncrementalReflow(nsIPresContext* aPresContext,
|
|||||||
// Is the reflow command target at us?
|
// Is the reflow command target at us?
|
||||||
if (this == aReflowCommand.GetTarget()) {
|
if (this == aReflowCommand.GetTarget()) {
|
||||||
if (aReflowCommand.GetType() == nsReflowCommand::FrameAppended) {
|
if (aReflowCommand.GetType() == nsReflowCommand::FrameAppended) {
|
||||||
nsLineData* lastLine = mLines;
|
nsLineData* lastLine = LastLine();
|
||||||
|
|
||||||
// Get the last line
|
|
||||||
if (nsnull != lastLine) {
|
|
||||||
while (nsnull != lastLine->mNextLine) {
|
|
||||||
lastLine = lastLine->mNextLine;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Restore the state
|
// Restore the state
|
||||||
if ((nsnull != lastLine) && (nsnull != lastLine->mPrevLine)) {
|
if (nsnull != lastLine) {
|
||||||
nsLineData* prevLine = lastLine->mPrevLine;
|
state.RecoverState(lastLine);
|
||||||
|
|
||||||
state.mY = prevLine->mBounds.YMost();
|
|
||||||
if (!state.mUnconstrainedHeight) {
|
|
||||||
state.mAvailSize.height -= state.mY;
|
|
||||||
}
|
|
||||||
|
|
||||||
// XXX This isn't really right...
|
|
||||||
state.mKidXMost = mRect.width - state.mBorderPadding.right;
|
|
||||||
|
|
||||||
// If the previous line is a block, then factor in its bottom margin
|
|
||||||
if (prevLine->mIsBlock) {
|
|
||||||
nsStyleSpacing* spacing;
|
|
||||||
nsIFrame* kid = prevLine->mFirstChild;
|
|
||||||
|
|
||||||
kid->GetStyleData(kStyleSpacingSID, (nsStyleStruct*&)spacing);
|
|
||||||
if (spacing->mMargin.bottom < 0) {
|
|
||||||
state.mPrevMaxNegBottomMargin = -spacing->mMargin.bottom;
|
|
||||||
} else {
|
|
||||||
state.mPrevMaxPosBottomMargin = spacing->mMargin.bottom;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reflow unmapped children
|
// Reflow unmapped children
|
||||||
@ -1267,38 +1369,65 @@ nsBlockFrame::IncrementalReflow(nsIPresContext* aPresContext,
|
|||||||
rv = ReflowUnmapped(state);
|
rv = ReflowUnmapped(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set return status
|
} else if (aReflowCommand.GetType() == nsReflowCommand::ContentChanged) {
|
||||||
aStatus = frComplete;
|
// Restore our state as if the child that changed is the next frame to reflow
|
||||||
if (NS_LINE_LAYOUT_NOT_COMPLETE == rv) {
|
nsLineData* line = FindLine(aReflowCommand.GetChildFrame());
|
||||||
rv = NS_OK;
|
state.RecoverState(line);
|
||||||
aStatus = frNotComplete;
|
|
||||||
}
|
// Get some available space to start reflowing with
|
||||||
|
GetAvailableSpace(state, state.mY);
|
||||||
|
|
||||||
|
// Reflow the affected line, and all the lines that follow...
|
||||||
|
// XXX Obviously this needs to be more efficient
|
||||||
|
rv = ReflowMappedFrom(state, line);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
NS_NOTYETIMPLEMENTED("unexpected reflow command");
|
NS_NOTYETIMPLEMENTED("unexpected reflow command");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
#if 0
|
|
||||||
// The command is passing through us. Get the next frame in the reflow chain
|
// The command is passing through us. Get the next frame in the reflow chain
|
||||||
nsIFrame* nextFrame = aReflowCommand.GetNext();
|
nsIFrame* nextFrame = aReflowCommand.GetNext();
|
||||||
|
|
||||||
// Restore our state as if nextFrame is the next frame to reflow
|
// Restore our state as if nextFrame is the next frame to reflow
|
||||||
RecoverState(aPresContext, state, nextFrame);
|
nsLineData* line = FindLine(nextFrame);
|
||||||
|
state.RecoverState(line);
|
||||||
|
|
||||||
// Get the current bounds. We'll need this to adjust the frames that follow
|
// Get some available space to start reflowing with
|
||||||
nsRect oldBounds;
|
GetAvailableSpace(state, state.mY);
|
||||||
nextFrame->GetRect(oldBounds);
|
|
||||||
|
|
||||||
// Pass along the reflow command
|
// Reflow the affected line
|
||||||
nsRect desiredRect;
|
nsLineLayout lineLayout(state);
|
||||||
aStatus = aReflowCommand.Next(aSpaceManager, desiredRect, aMaxSize, nextFrame);
|
|
||||||
#endif
|
state.mCurrentLine = &lineLayout;
|
||||||
NS_NOTYETIMPLEMENTED("unexpected reflow command");
|
lineLayout.Initialize(state, line);
|
||||||
|
|
||||||
|
// Have the line handle the incremental reflow
|
||||||
|
nsRect oldBounds = line->mBounds;
|
||||||
|
rv = lineLayout.IncrementalReflowFromChild(aReflowCommand, nextFrame);
|
||||||
|
|
||||||
|
// Now place the line. It's possible it won't fit
|
||||||
|
rv = PlaceLine(state, lineLayout, line);
|
||||||
|
// XXX The way NS_LINE_LAYOUT_COMPLETE is being used is very confusing...
|
||||||
|
if (NS_LINE_LAYOUT_COMPLETE == rv) {
|
||||||
|
mLastContentOffset = line->mLastContentOffset;
|
||||||
|
mLastContentIsComplete = PRBool(line->mLastContentIsComplete);
|
||||||
|
state.mPrevKidFrame = lineLayout.mPrevKidFrame;
|
||||||
|
|
||||||
|
// Now figure out what to do with the frames that follow
|
||||||
|
rv = IncrementalReflowAfter(state, line, rv, oldBounds);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return our desired rect
|
// Return our desired rect
|
||||||
ComputeDesiredRect(state, aMaxSize, aDesiredRect);
|
ComputeDesiredRect(state, aMaxSize, aDesiredRect);
|
||||||
|
|
||||||
|
// Set return status
|
||||||
|
aStatus = frComplete;
|
||||||
|
if (NS_LINE_LAYOUT_NOT_COMPLETE == rv) {
|
||||||
|
rv = NS_OK;
|
||||||
|
aStatus = frNotComplete;
|
||||||
|
}
|
||||||
|
|
||||||
// Now that reflow has finished, remove the cached pointer
|
// Now that reflow has finished, remove the cached pointer
|
||||||
shell->RemoveCachedData(this);
|
shell->RemoveCachedData(this);
|
||||||
NS_RELEASE(shell);
|
NS_RELEASE(shell);
|
||||||
|
@ -142,6 +142,45 @@ nsBlockReflowState::Initialize(nsIPresContext* aPresContext,
|
|||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Recover the block reflow state to what it should be if aLine is about
|
||||||
|
// to be reflowed. aLine should not be nsnull
|
||||||
|
nsresult nsBlockReflowState::RecoverState(nsLineData* aLine)
|
||||||
|
{
|
||||||
|
NS_PRECONDITION(nsnull != aLine, "null parameter");
|
||||||
|
nsLineData* prevLine = aLine->mPrevLine;
|
||||||
|
|
||||||
|
if (nsnull != prevLine) {
|
||||||
|
// Compute the running y-offset, and the available height
|
||||||
|
mY = prevLine->mBounds.YMost();
|
||||||
|
if (!mUnconstrainedHeight) {
|
||||||
|
mAvailSize.height -= mY;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute the kid x-most
|
||||||
|
for (nsLineData* l = prevLine; nsnull != l; l = l->mPrevLine) {
|
||||||
|
nscoord xmost = l->mBounds.XMost();
|
||||||
|
if (xmost > mKidXMost) {
|
||||||
|
mKidXMost = xmost;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the previous line is a block, then factor in its bottom margin
|
||||||
|
if (prevLine->mIsBlock) {
|
||||||
|
nsStyleSpacing* spacing;
|
||||||
|
nsIFrame* kid = prevLine->mFirstChild;
|
||||||
|
|
||||||
|
kid->GetStyleData(kStyleSpacingSID, (nsStyleStruct*&)spacing);
|
||||||
|
if (spacing->mMargin.bottom < 0) {
|
||||||
|
mPrevMaxNegBottomMargin = -spacing->mMargin.bottom;
|
||||||
|
} else {
|
||||||
|
mPrevMaxPosBottomMargin = spacing->mMargin.bottom;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
@ -780,6 +819,52 @@ done:
|
|||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// XXX This is a short-term hack. It assumes that the caller has already recovered
|
||||||
|
// the state, and that some space has been retrieved from the space manager...
|
||||||
|
nsresult
|
||||||
|
nsBlockFrame::ReflowMappedFrom(nsBlockReflowState& aState, nsLineData* aLine)
|
||||||
|
{
|
||||||
|
nsresult rv = NS_OK;
|
||||||
|
|
||||||
|
nsLineLayout lineLayout(aState);
|
||||||
|
aState.mCurrentLine = &lineLayout;
|
||||||
|
while (nsnull != aLine) {
|
||||||
|
// Initialize the line layout for this line
|
||||||
|
rv = lineLayout.Initialize(aState, aLine);
|
||||||
|
if (NS_OK != rv) {
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
lineLayout.mPrevKidFrame = aState.mPrevKidFrame;
|
||||||
|
|
||||||
|
// Reflow the line
|
||||||
|
nsresult lineReflowStatus = lineLayout.ReflowLine();
|
||||||
|
if (lineReflowStatus < 0) {
|
||||||
|
// Some kind of hard error
|
||||||
|
rv = lineReflowStatus;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
mChildCount += lineLayout.mNewFrames;
|
||||||
|
|
||||||
|
// Now place it. It's possible it won't fit.
|
||||||
|
rv = PlaceLine(aState, lineLayout, aLine);
|
||||||
|
if (NS_LINE_LAYOUT_COMPLETE != rv) {
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
mLastContentOffset = aLine->mLastContentOffset;
|
||||||
|
mLastContentIsComplete = PRBool(aLine->mLastContentIsComplete);
|
||||||
|
aLine = aLine->mNextLine;
|
||||||
|
aState.mPrevKidFrame = lineLayout.mPrevKidFrame;
|
||||||
|
}
|
||||||
|
|
||||||
|
done:
|
||||||
|
aState.mCurrentLine = nsnull;
|
||||||
|
#ifdef NS_DEBUG
|
||||||
|
VerifyLines(PR_TRUE);
|
||||||
|
#endif
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
nsBlockFrame::ReflowUnmapped(nsBlockReflowState& aState)
|
nsBlockFrame::ReflowUnmapped(nsBlockReflowState& aState)
|
||||||
{
|
{
|
||||||
@ -1194,6 +1279,51 @@ nsBlockFrame::ResizeReflow(nsIPresContext* aPresContext,
|
|||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nsLineData* nsBlockFrame::FindLine(nsIFrame* aFrame)
|
||||||
|
{
|
||||||
|
// Find the line that contains the aFrame
|
||||||
|
nsLineData* line = mLines;
|
||||||
|
while (nsnull != line) {
|
||||||
|
nsIFrame* child = line->mFirstChild;
|
||||||
|
for (PRInt32 count = line->mChildCount; count > 0; count--) {
|
||||||
|
if (child == aFrame) {
|
||||||
|
return line;
|
||||||
|
}
|
||||||
|
|
||||||
|
child->GetNextSibling(child);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move to the next line
|
||||||
|
line = line->mNextLine;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nsnull;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsLineData* nsBlockFrame::LastLine()
|
||||||
|
{
|
||||||
|
nsLineData* lastLine = mLines;
|
||||||
|
|
||||||
|
// Get the last line
|
||||||
|
if (nsnull != lastLine) {
|
||||||
|
while (nsnull != lastLine->mNextLine) {
|
||||||
|
lastLine = lastLine->mNextLine;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return lastLine;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult nsBlockFrame::IncrementalReflowAfter(nsBlockReflowState& aState,
|
||||||
|
nsLineData* aLine,
|
||||||
|
nsresult aReflowStatus,
|
||||||
|
const nsRect& aOldBounds)
|
||||||
|
{
|
||||||
|
// Now just reflow all the lines that follow...
|
||||||
|
// XXX Obviously this needs to be more efficient
|
||||||
|
return ReflowMappedFrom(aState, aLine->mNextLine);
|
||||||
|
}
|
||||||
|
|
||||||
NS_METHOD
|
NS_METHOD
|
||||||
nsBlockFrame::IncrementalReflow(nsIPresContext* aPresContext,
|
nsBlockFrame::IncrementalReflow(nsIPresContext* aPresContext,
|
||||||
nsISpaceManager* aSpaceManager,
|
nsISpaceManager* aSpaceManager,
|
||||||
@ -1219,39 +1349,11 @@ nsBlockFrame::IncrementalReflow(nsIPresContext* aPresContext,
|
|||||||
// Is the reflow command target at us?
|
// Is the reflow command target at us?
|
||||||
if (this == aReflowCommand.GetTarget()) {
|
if (this == aReflowCommand.GetTarget()) {
|
||||||
if (aReflowCommand.GetType() == nsReflowCommand::FrameAppended) {
|
if (aReflowCommand.GetType() == nsReflowCommand::FrameAppended) {
|
||||||
nsLineData* lastLine = mLines;
|
nsLineData* lastLine = LastLine();
|
||||||
|
|
||||||
// Get the last line
|
|
||||||
if (nsnull != lastLine) {
|
|
||||||
while (nsnull != lastLine->mNextLine) {
|
|
||||||
lastLine = lastLine->mNextLine;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Restore the state
|
// Restore the state
|
||||||
if ((nsnull != lastLine) && (nsnull != lastLine->mPrevLine)) {
|
if (nsnull != lastLine) {
|
||||||
nsLineData* prevLine = lastLine->mPrevLine;
|
state.RecoverState(lastLine);
|
||||||
|
|
||||||
state.mY = prevLine->mBounds.YMost();
|
|
||||||
if (!state.mUnconstrainedHeight) {
|
|
||||||
state.mAvailSize.height -= state.mY;
|
|
||||||
}
|
|
||||||
|
|
||||||
// XXX This isn't really right...
|
|
||||||
state.mKidXMost = mRect.width - state.mBorderPadding.right;
|
|
||||||
|
|
||||||
// If the previous line is a block, then factor in its bottom margin
|
|
||||||
if (prevLine->mIsBlock) {
|
|
||||||
nsStyleSpacing* spacing;
|
|
||||||
nsIFrame* kid = prevLine->mFirstChild;
|
|
||||||
|
|
||||||
kid->GetStyleData(kStyleSpacingSID, (nsStyleStruct*&)spacing);
|
|
||||||
if (spacing->mMargin.bottom < 0) {
|
|
||||||
state.mPrevMaxNegBottomMargin = -spacing->mMargin.bottom;
|
|
||||||
} else {
|
|
||||||
state.mPrevMaxPosBottomMargin = spacing->mMargin.bottom;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reflow unmapped children
|
// Reflow unmapped children
|
||||||
@ -1267,38 +1369,65 @@ nsBlockFrame::IncrementalReflow(nsIPresContext* aPresContext,
|
|||||||
rv = ReflowUnmapped(state);
|
rv = ReflowUnmapped(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set return status
|
} else if (aReflowCommand.GetType() == nsReflowCommand::ContentChanged) {
|
||||||
aStatus = frComplete;
|
// Restore our state as if the child that changed is the next frame to reflow
|
||||||
if (NS_LINE_LAYOUT_NOT_COMPLETE == rv) {
|
nsLineData* line = FindLine(aReflowCommand.GetChildFrame());
|
||||||
rv = NS_OK;
|
state.RecoverState(line);
|
||||||
aStatus = frNotComplete;
|
|
||||||
}
|
// Get some available space to start reflowing with
|
||||||
|
GetAvailableSpace(state, state.mY);
|
||||||
|
|
||||||
|
// Reflow the affected line, and all the lines that follow...
|
||||||
|
// XXX Obviously this needs to be more efficient
|
||||||
|
rv = ReflowMappedFrom(state, line);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
NS_NOTYETIMPLEMENTED("unexpected reflow command");
|
NS_NOTYETIMPLEMENTED("unexpected reflow command");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
#if 0
|
|
||||||
// The command is passing through us. Get the next frame in the reflow chain
|
// The command is passing through us. Get the next frame in the reflow chain
|
||||||
nsIFrame* nextFrame = aReflowCommand.GetNext();
|
nsIFrame* nextFrame = aReflowCommand.GetNext();
|
||||||
|
|
||||||
// Restore our state as if nextFrame is the next frame to reflow
|
// Restore our state as if nextFrame is the next frame to reflow
|
||||||
RecoverState(aPresContext, state, nextFrame);
|
nsLineData* line = FindLine(nextFrame);
|
||||||
|
state.RecoverState(line);
|
||||||
|
|
||||||
// Get the current bounds. We'll need this to adjust the frames that follow
|
// Get some available space to start reflowing with
|
||||||
nsRect oldBounds;
|
GetAvailableSpace(state, state.mY);
|
||||||
nextFrame->GetRect(oldBounds);
|
|
||||||
|
|
||||||
// Pass along the reflow command
|
// Reflow the affected line
|
||||||
nsRect desiredRect;
|
nsLineLayout lineLayout(state);
|
||||||
aStatus = aReflowCommand.Next(aSpaceManager, desiredRect, aMaxSize, nextFrame);
|
|
||||||
#endif
|
state.mCurrentLine = &lineLayout;
|
||||||
NS_NOTYETIMPLEMENTED("unexpected reflow command");
|
lineLayout.Initialize(state, line);
|
||||||
|
|
||||||
|
// Have the line handle the incremental reflow
|
||||||
|
nsRect oldBounds = line->mBounds;
|
||||||
|
rv = lineLayout.IncrementalReflowFromChild(aReflowCommand, nextFrame);
|
||||||
|
|
||||||
|
// Now place the line. It's possible it won't fit
|
||||||
|
rv = PlaceLine(state, lineLayout, line);
|
||||||
|
// XXX The way NS_LINE_LAYOUT_COMPLETE is being used is very confusing...
|
||||||
|
if (NS_LINE_LAYOUT_COMPLETE == rv) {
|
||||||
|
mLastContentOffset = line->mLastContentOffset;
|
||||||
|
mLastContentIsComplete = PRBool(line->mLastContentIsComplete);
|
||||||
|
state.mPrevKidFrame = lineLayout.mPrevKidFrame;
|
||||||
|
|
||||||
|
// Now figure out what to do with the frames that follow
|
||||||
|
rv = IncrementalReflowAfter(state, line, rv, oldBounds);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return our desired rect
|
// Return our desired rect
|
||||||
ComputeDesiredRect(state, aMaxSize, aDesiredRect);
|
ComputeDesiredRect(state, aMaxSize, aDesiredRect);
|
||||||
|
|
||||||
|
// Set return status
|
||||||
|
aStatus = frComplete;
|
||||||
|
if (NS_LINE_LAYOUT_NOT_COMPLETE == rv) {
|
||||||
|
rv = NS_OK;
|
||||||
|
aStatus = frNotComplete;
|
||||||
|
}
|
||||||
|
|
||||||
// Now that reflow has finished, remove the cached pointer
|
// Now that reflow has finished, remove the cached pointer
|
||||||
shell->RemoveCachedData(this);
|
shell->RemoveCachedData(this);
|
||||||
NS_RELEASE(shell);
|
NS_RELEASE(shell);
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
#include "nsPlaceholderFrame.h"
|
#include "nsPlaceholderFrame.h"
|
||||||
#include "nsCSSLayout.h"
|
#include "nsCSSLayout.h"
|
||||||
#include "nsCRT.h"
|
#include "nsCRT.h"
|
||||||
|
#include "nsReflowCommand.h"
|
||||||
|
|
||||||
#undef NOISY_REFLOW
|
#undef NOISY_REFLOW
|
||||||
|
|
||||||
@ -356,7 +357,7 @@ nsLineLayout::WordBreakReflow()
|
|||||||
// Return values: <0 for error
|
// Return values: <0 for error
|
||||||
// 0 == NS_LINE_LAYOUT
|
// 0 == NS_LINE_LAYOUT
|
||||||
nsresult
|
nsresult
|
||||||
nsLineLayout::ReflowChild()
|
nsLineLayout::ReflowChild(nsReflowCommand* aReflowCommand)
|
||||||
{
|
{
|
||||||
// Get kid frame's style context
|
// Get kid frame's style context
|
||||||
nsIStyleContextPtr kidSC;
|
nsIStyleContextPtr kidSC;
|
||||||
@ -413,7 +414,20 @@ nsLineLayout::ReflowChild()
|
|||||||
}
|
}
|
||||||
mReflowResult = NS_LINE_LAYOUT_REFLOW_RESULT_NOT_AWARE;
|
mReflowResult = NS_LINE_LAYOUT_REFLOW_RESULT_NOT_AWARE;
|
||||||
nscoord dx = mReflowData.mX + kidSpacing->mMargin.left;
|
nscoord dx = mReflowData.mX + kidSpacing->mMargin.left;
|
||||||
if (isBlock) {
|
if (aReflowCommand) {
|
||||||
|
nsIFrame* nextFrame;
|
||||||
|
|
||||||
|
mSpaceManager->Translate(dx, mY);
|
||||||
|
kidReflowStatus = aReflowCommand->Next(mSpaceManager, kidRect, kidAvailSize, nextFrame);
|
||||||
|
mSpaceManager->Translate(-dx, -mY);
|
||||||
|
kidRect.x = dx;
|
||||||
|
kidRect.y = mY;
|
||||||
|
kidSize.width = kidRect.width;
|
||||||
|
kidSize.height = kidRect.height;
|
||||||
|
kidSize.ascent = kidRect.height;
|
||||||
|
kidSize.descent = 0;
|
||||||
|
|
||||||
|
} else if (isBlock) {
|
||||||
mSpaceManager->Translate(dx, mY);
|
mSpaceManager->Translate(dx, mY);
|
||||||
rv = mBlock->ReflowBlockChild(mKidFrame, mPresContext,
|
rv = mBlock->ReflowBlockChild(mKidFrame, mPresContext,
|
||||||
mSpaceManager, kidAvailSize, kidRect,
|
mSpaceManager, kidAvailSize, kidRect,
|
||||||
@ -518,6 +532,94 @@ nsLineLayout::ReflowChild()
|
|||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
nsLineLayout::IncrementalReflowFromChild(nsReflowCommand& aReflowCommand,
|
||||||
|
nsIFrame* aChildFrame)
|
||||||
|
{
|
||||||
|
#if 0
|
||||||
|
// Get the current bounds. We'll need this to adjust the frames that follow
|
||||||
|
nsRect oldBounds;
|
||||||
|
aChildFrame->GetRect(oldBounds);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// For the time being reflow all the children, and when we get to aChildFrame
|
||||||
|
// handle it specially
|
||||||
|
nsresult reflowStatus = NS_LINE_LAYOUT_COMPLETE;
|
||||||
|
|
||||||
|
mLine->mBounds.x = mReflowData.mX;
|
||||||
|
mLine->mBounds.y = mY;
|
||||||
|
mKidFrame = mLine->mFirstChild;
|
||||||
|
PRInt32 kidNum = 0;
|
||||||
|
while (kidNum < mLine->mChildCount) {
|
||||||
|
// XXX Code to avoid reflowing a child goes here
|
||||||
|
nsresult childReflowStatus;
|
||||||
|
|
||||||
|
if (mKidFrame == aChildFrame) {
|
||||||
|
childReflowStatus = ReflowChild(&aReflowCommand);
|
||||||
|
} else {
|
||||||
|
childReflowStatus = ReflowChild(nsnull);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (childReflowStatus < 0) {
|
||||||
|
reflowStatus = childReflowStatus;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (childReflowStatus) {
|
||||||
|
default:
|
||||||
|
case NS_LINE_LAYOUT_COMPLETE:
|
||||||
|
mPrevKidFrame = mKidFrame;
|
||||||
|
mKidFrame->GetNextSibling(mKidFrame);
|
||||||
|
mKidIndex++;
|
||||||
|
kidNum++;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NS_LINE_LAYOUT_NOT_COMPLETE:
|
||||||
|
reflowStatus = childReflowStatus;
|
||||||
|
mPrevKidFrame = mKidFrame;
|
||||||
|
mKidFrame->GetNextSibling(mKidFrame);
|
||||||
|
kidNum++;
|
||||||
|
goto split_line;
|
||||||
|
|
||||||
|
case NS_LINE_LAYOUT_BREAK_BEFORE:
|
||||||
|
reflowStatus = childReflowStatus;
|
||||||
|
goto split_line;
|
||||||
|
|
||||||
|
case NS_LINE_LAYOUT_BREAK_AFTER:
|
||||||
|
reflowStatus = childReflowStatus;
|
||||||
|
mPrevKidFrame = mKidFrame;
|
||||||
|
mKidFrame->GetNextSibling(mKidFrame);
|
||||||
|
mKidIndex++;
|
||||||
|
kidNum++;
|
||||||
|
|
||||||
|
split_line:
|
||||||
|
reflowStatus = SplitLine(childReflowStatus, mLine->mChildCount - kidNum);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
done:
|
||||||
|
// Perform alignment operations
|
||||||
|
if (mLine->mIsBlock) {
|
||||||
|
mLineHeight = mReflowData.mMaxAscent + mReflowData.mMaxDescent;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
AlignChildren();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set final bounds of the line
|
||||||
|
mLine->mBounds.height = mLineHeight;
|
||||||
|
mLine->mBounds.width = mReflowData.mX - mLine->mBounds.x;
|
||||||
|
|
||||||
|
NS_ASSERTION(((reflowStatus < 0) ||
|
||||||
|
(reflowStatus == NS_LINE_LAYOUT_COMPLETE) ||
|
||||||
|
(reflowStatus == NS_LINE_LAYOUT_NOT_COMPLETE) ||
|
||||||
|
(reflowStatus == NS_LINE_LAYOUT_BREAK_BEFORE) ||
|
||||||
|
(reflowStatus == NS_LINE_LAYOUT_BREAK_AFTER)),
|
||||||
|
"bad return status from ReflowMapped");
|
||||||
|
return reflowStatus;
|
||||||
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
@ -630,7 +732,7 @@ nsLineLayout::ReflowMapped()
|
|||||||
while (kidNum < mLine->mChildCount) {
|
while (kidNum < mLine->mChildCount) {
|
||||||
// XXX Code to avoid reflowing a child goes here
|
// XXX Code to avoid reflowing a child goes here
|
||||||
|
|
||||||
nsresult childReflowStatus = ReflowChild();
|
nsresult childReflowStatus = ReflowChild(nsnull);
|
||||||
if (childReflowStatus < 0) {
|
if (childReflowStatus < 0) {
|
||||||
reflowStatus = childReflowStatus;
|
reflowStatus = childReflowStatus;
|
||||||
goto done;
|
goto done;
|
||||||
@ -769,7 +871,7 @@ nsLineLayout::PullUpChildren()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Try to reflow it like any other mapped child
|
// Try to reflow it like any other mapped child
|
||||||
nsresult childReflowStatus = ReflowChild();
|
nsresult childReflowStatus = ReflowChild(nsnull);
|
||||||
if (childReflowStatus < 0) {
|
if (childReflowStatus < 0) {
|
||||||
reflowStatus = childReflowStatus;
|
reflowStatus = childReflowStatus;
|
||||||
goto done;
|
goto done;
|
||||||
@ -942,7 +1044,7 @@ nsLineLayout::ReflowUnmapped()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Reflow new child frame
|
// Reflow new child frame
|
||||||
childReflowStatus = ReflowChild();
|
childReflowStatus = ReflowChild(nsnull);
|
||||||
if (childReflowStatus < 0) {
|
if (childReflowStatus < 0) {
|
||||||
reflowStatus = childReflowStatus;
|
reflowStatus = childReflowStatus;
|
||||||
goto done;
|
goto done;
|
||||||
|
@ -100,16 +100,16 @@ struct nsLineLayout {
|
|||||||
*/
|
*/
|
||||||
nsresult ReflowLine();
|
nsresult ReflowLine();
|
||||||
|
|
||||||
|
nsresult IncrementalReflowFromChild(nsReflowCommand& aReflowCommand,
|
||||||
|
nsIFrame* aChildFrame);
|
||||||
|
|
||||||
|
|
||||||
// The presentation context
|
// The presentation context
|
||||||
nsIPresContext* mPresContext;
|
nsIPresContext* mPresContext;
|
||||||
|
|
||||||
// The block behind the line
|
// The block behind the line
|
||||||
nsBlockFrame* mBlock;
|
nsBlockFrame* mBlock;
|
||||||
nsISpaceManager* mSpaceManager;
|
nsISpaceManager* mSpaceManager;
|
||||||
#if 0
|
|
||||||
// XXX I don't think we need this anymore...
|
|
||||||
PRBool mBlockIsPseudo;
|
|
||||||
#endif
|
|
||||||
nsIContent* mBlockContent;
|
nsIContent* mBlockContent;
|
||||||
PRInt32 mKidIndex;
|
PRInt32 mKidIndex;
|
||||||
|
|
||||||
@ -180,7 +180,7 @@ protected:
|
|||||||
|
|
||||||
nsresult WordBreakReflow();
|
nsresult WordBreakReflow();
|
||||||
|
|
||||||
nsresult ReflowChild();
|
nsresult ReflowChild(nsReflowCommand* aReflowCommand);
|
||||||
|
|
||||||
nsresult ReflowMapped();
|
nsresult ReflowMapped();
|
||||||
|
|
||||||
|
@ -142,6 +142,45 @@ nsBlockReflowState::Initialize(nsIPresContext* aPresContext,
|
|||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Recover the block reflow state to what it should be if aLine is about
|
||||||
|
// to be reflowed. aLine should not be nsnull
|
||||||
|
nsresult nsBlockReflowState::RecoverState(nsLineData* aLine)
|
||||||
|
{
|
||||||
|
NS_PRECONDITION(nsnull != aLine, "null parameter");
|
||||||
|
nsLineData* prevLine = aLine->mPrevLine;
|
||||||
|
|
||||||
|
if (nsnull != prevLine) {
|
||||||
|
// Compute the running y-offset, and the available height
|
||||||
|
mY = prevLine->mBounds.YMost();
|
||||||
|
if (!mUnconstrainedHeight) {
|
||||||
|
mAvailSize.height -= mY;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute the kid x-most
|
||||||
|
for (nsLineData* l = prevLine; nsnull != l; l = l->mPrevLine) {
|
||||||
|
nscoord xmost = l->mBounds.XMost();
|
||||||
|
if (xmost > mKidXMost) {
|
||||||
|
mKidXMost = xmost;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the previous line is a block, then factor in its bottom margin
|
||||||
|
if (prevLine->mIsBlock) {
|
||||||
|
nsStyleSpacing* spacing;
|
||||||
|
nsIFrame* kid = prevLine->mFirstChild;
|
||||||
|
|
||||||
|
kid->GetStyleData(kStyleSpacingSID, (nsStyleStruct*&)spacing);
|
||||||
|
if (spacing->mMargin.bottom < 0) {
|
||||||
|
mPrevMaxNegBottomMargin = -spacing->mMargin.bottom;
|
||||||
|
} else {
|
||||||
|
mPrevMaxPosBottomMargin = spacing->mMargin.bottom;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
@ -780,6 +819,52 @@ done:
|
|||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// XXX This is a short-term hack. It assumes that the caller has already recovered
|
||||||
|
// the state, and that some space has been retrieved from the space manager...
|
||||||
|
nsresult
|
||||||
|
nsBlockFrame::ReflowMappedFrom(nsBlockReflowState& aState, nsLineData* aLine)
|
||||||
|
{
|
||||||
|
nsresult rv = NS_OK;
|
||||||
|
|
||||||
|
nsLineLayout lineLayout(aState);
|
||||||
|
aState.mCurrentLine = &lineLayout;
|
||||||
|
while (nsnull != aLine) {
|
||||||
|
// Initialize the line layout for this line
|
||||||
|
rv = lineLayout.Initialize(aState, aLine);
|
||||||
|
if (NS_OK != rv) {
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
lineLayout.mPrevKidFrame = aState.mPrevKidFrame;
|
||||||
|
|
||||||
|
// Reflow the line
|
||||||
|
nsresult lineReflowStatus = lineLayout.ReflowLine();
|
||||||
|
if (lineReflowStatus < 0) {
|
||||||
|
// Some kind of hard error
|
||||||
|
rv = lineReflowStatus;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
mChildCount += lineLayout.mNewFrames;
|
||||||
|
|
||||||
|
// Now place it. It's possible it won't fit.
|
||||||
|
rv = PlaceLine(aState, lineLayout, aLine);
|
||||||
|
if (NS_LINE_LAYOUT_COMPLETE != rv) {
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
mLastContentOffset = aLine->mLastContentOffset;
|
||||||
|
mLastContentIsComplete = PRBool(aLine->mLastContentIsComplete);
|
||||||
|
aLine = aLine->mNextLine;
|
||||||
|
aState.mPrevKidFrame = lineLayout.mPrevKidFrame;
|
||||||
|
}
|
||||||
|
|
||||||
|
done:
|
||||||
|
aState.mCurrentLine = nsnull;
|
||||||
|
#ifdef NS_DEBUG
|
||||||
|
VerifyLines(PR_TRUE);
|
||||||
|
#endif
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
nsBlockFrame::ReflowUnmapped(nsBlockReflowState& aState)
|
nsBlockFrame::ReflowUnmapped(nsBlockReflowState& aState)
|
||||||
{
|
{
|
||||||
@ -1194,6 +1279,51 @@ nsBlockFrame::ResizeReflow(nsIPresContext* aPresContext,
|
|||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nsLineData* nsBlockFrame::FindLine(nsIFrame* aFrame)
|
||||||
|
{
|
||||||
|
// Find the line that contains the aFrame
|
||||||
|
nsLineData* line = mLines;
|
||||||
|
while (nsnull != line) {
|
||||||
|
nsIFrame* child = line->mFirstChild;
|
||||||
|
for (PRInt32 count = line->mChildCount; count > 0; count--) {
|
||||||
|
if (child == aFrame) {
|
||||||
|
return line;
|
||||||
|
}
|
||||||
|
|
||||||
|
child->GetNextSibling(child);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move to the next line
|
||||||
|
line = line->mNextLine;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nsnull;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsLineData* nsBlockFrame::LastLine()
|
||||||
|
{
|
||||||
|
nsLineData* lastLine = mLines;
|
||||||
|
|
||||||
|
// Get the last line
|
||||||
|
if (nsnull != lastLine) {
|
||||||
|
while (nsnull != lastLine->mNextLine) {
|
||||||
|
lastLine = lastLine->mNextLine;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return lastLine;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult nsBlockFrame::IncrementalReflowAfter(nsBlockReflowState& aState,
|
||||||
|
nsLineData* aLine,
|
||||||
|
nsresult aReflowStatus,
|
||||||
|
const nsRect& aOldBounds)
|
||||||
|
{
|
||||||
|
// Now just reflow all the lines that follow...
|
||||||
|
// XXX Obviously this needs to be more efficient
|
||||||
|
return ReflowMappedFrom(aState, aLine->mNextLine);
|
||||||
|
}
|
||||||
|
|
||||||
NS_METHOD
|
NS_METHOD
|
||||||
nsBlockFrame::IncrementalReflow(nsIPresContext* aPresContext,
|
nsBlockFrame::IncrementalReflow(nsIPresContext* aPresContext,
|
||||||
nsISpaceManager* aSpaceManager,
|
nsISpaceManager* aSpaceManager,
|
||||||
@ -1219,39 +1349,11 @@ nsBlockFrame::IncrementalReflow(nsIPresContext* aPresContext,
|
|||||||
// Is the reflow command target at us?
|
// Is the reflow command target at us?
|
||||||
if (this == aReflowCommand.GetTarget()) {
|
if (this == aReflowCommand.GetTarget()) {
|
||||||
if (aReflowCommand.GetType() == nsReflowCommand::FrameAppended) {
|
if (aReflowCommand.GetType() == nsReflowCommand::FrameAppended) {
|
||||||
nsLineData* lastLine = mLines;
|
nsLineData* lastLine = LastLine();
|
||||||
|
|
||||||
// Get the last line
|
|
||||||
if (nsnull != lastLine) {
|
|
||||||
while (nsnull != lastLine->mNextLine) {
|
|
||||||
lastLine = lastLine->mNextLine;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Restore the state
|
// Restore the state
|
||||||
if ((nsnull != lastLine) && (nsnull != lastLine->mPrevLine)) {
|
if (nsnull != lastLine) {
|
||||||
nsLineData* prevLine = lastLine->mPrevLine;
|
state.RecoverState(lastLine);
|
||||||
|
|
||||||
state.mY = prevLine->mBounds.YMost();
|
|
||||||
if (!state.mUnconstrainedHeight) {
|
|
||||||
state.mAvailSize.height -= state.mY;
|
|
||||||
}
|
|
||||||
|
|
||||||
// XXX This isn't really right...
|
|
||||||
state.mKidXMost = mRect.width - state.mBorderPadding.right;
|
|
||||||
|
|
||||||
// If the previous line is a block, then factor in its bottom margin
|
|
||||||
if (prevLine->mIsBlock) {
|
|
||||||
nsStyleSpacing* spacing;
|
|
||||||
nsIFrame* kid = prevLine->mFirstChild;
|
|
||||||
|
|
||||||
kid->GetStyleData(kStyleSpacingSID, (nsStyleStruct*&)spacing);
|
|
||||||
if (spacing->mMargin.bottom < 0) {
|
|
||||||
state.mPrevMaxNegBottomMargin = -spacing->mMargin.bottom;
|
|
||||||
} else {
|
|
||||||
state.mPrevMaxPosBottomMargin = spacing->mMargin.bottom;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reflow unmapped children
|
// Reflow unmapped children
|
||||||
@ -1267,38 +1369,65 @@ nsBlockFrame::IncrementalReflow(nsIPresContext* aPresContext,
|
|||||||
rv = ReflowUnmapped(state);
|
rv = ReflowUnmapped(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set return status
|
} else if (aReflowCommand.GetType() == nsReflowCommand::ContentChanged) {
|
||||||
aStatus = frComplete;
|
// Restore our state as if the child that changed is the next frame to reflow
|
||||||
if (NS_LINE_LAYOUT_NOT_COMPLETE == rv) {
|
nsLineData* line = FindLine(aReflowCommand.GetChildFrame());
|
||||||
rv = NS_OK;
|
state.RecoverState(line);
|
||||||
aStatus = frNotComplete;
|
|
||||||
}
|
// Get some available space to start reflowing with
|
||||||
|
GetAvailableSpace(state, state.mY);
|
||||||
|
|
||||||
|
// Reflow the affected line, and all the lines that follow...
|
||||||
|
// XXX Obviously this needs to be more efficient
|
||||||
|
rv = ReflowMappedFrom(state, line);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
NS_NOTYETIMPLEMENTED("unexpected reflow command");
|
NS_NOTYETIMPLEMENTED("unexpected reflow command");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
#if 0
|
|
||||||
// The command is passing through us. Get the next frame in the reflow chain
|
// The command is passing through us. Get the next frame in the reflow chain
|
||||||
nsIFrame* nextFrame = aReflowCommand.GetNext();
|
nsIFrame* nextFrame = aReflowCommand.GetNext();
|
||||||
|
|
||||||
// Restore our state as if nextFrame is the next frame to reflow
|
// Restore our state as if nextFrame is the next frame to reflow
|
||||||
RecoverState(aPresContext, state, nextFrame);
|
nsLineData* line = FindLine(nextFrame);
|
||||||
|
state.RecoverState(line);
|
||||||
|
|
||||||
// Get the current bounds. We'll need this to adjust the frames that follow
|
// Get some available space to start reflowing with
|
||||||
nsRect oldBounds;
|
GetAvailableSpace(state, state.mY);
|
||||||
nextFrame->GetRect(oldBounds);
|
|
||||||
|
|
||||||
// Pass along the reflow command
|
// Reflow the affected line
|
||||||
nsRect desiredRect;
|
nsLineLayout lineLayout(state);
|
||||||
aStatus = aReflowCommand.Next(aSpaceManager, desiredRect, aMaxSize, nextFrame);
|
|
||||||
#endif
|
state.mCurrentLine = &lineLayout;
|
||||||
NS_NOTYETIMPLEMENTED("unexpected reflow command");
|
lineLayout.Initialize(state, line);
|
||||||
|
|
||||||
|
// Have the line handle the incremental reflow
|
||||||
|
nsRect oldBounds = line->mBounds;
|
||||||
|
rv = lineLayout.IncrementalReflowFromChild(aReflowCommand, nextFrame);
|
||||||
|
|
||||||
|
// Now place the line. It's possible it won't fit
|
||||||
|
rv = PlaceLine(state, lineLayout, line);
|
||||||
|
// XXX The way NS_LINE_LAYOUT_COMPLETE is being used is very confusing...
|
||||||
|
if (NS_LINE_LAYOUT_COMPLETE == rv) {
|
||||||
|
mLastContentOffset = line->mLastContentOffset;
|
||||||
|
mLastContentIsComplete = PRBool(line->mLastContentIsComplete);
|
||||||
|
state.mPrevKidFrame = lineLayout.mPrevKidFrame;
|
||||||
|
|
||||||
|
// Now figure out what to do with the frames that follow
|
||||||
|
rv = IncrementalReflowAfter(state, line, rv, oldBounds);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return our desired rect
|
// Return our desired rect
|
||||||
ComputeDesiredRect(state, aMaxSize, aDesiredRect);
|
ComputeDesiredRect(state, aMaxSize, aDesiredRect);
|
||||||
|
|
||||||
|
// Set return status
|
||||||
|
aStatus = frComplete;
|
||||||
|
if (NS_LINE_LAYOUT_NOT_COMPLETE == rv) {
|
||||||
|
rv = NS_OK;
|
||||||
|
aStatus = frNotComplete;
|
||||||
|
}
|
||||||
|
|
||||||
// Now that reflow has finished, remove the cached pointer
|
// Now that reflow has finished, remove the cached pointer
|
||||||
shell->RemoveCachedData(this);
|
shell->RemoveCachedData(this);
|
||||||
NS_RELEASE(shell);
|
NS_RELEASE(shell);
|
||||||
|
@ -33,7 +33,7 @@ class nsBlockFrame;
|
|||||||
struct nsBandData;
|
struct nsBandData;
|
||||||
|
|
||||||
struct nsBlockBandData : public nsBandData {
|
struct nsBlockBandData : public nsBandData {
|
||||||
// Trapezoid's used during band processing
|
// Trapezoids used during band processing
|
||||||
nsBandTrapezoid data[12];
|
nsBandTrapezoid data[12];
|
||||||
|
|
||||||
// Bounding rect of available space between any left and right floaters
|
// Bounding rect of available space between any left and right floaters
|
||||||
@ -63,6 +63,8 @@ struct nsBlockReflowState {
|
|||||||
nsSize* aMaxElementSize,
|
nsSize* aMaxElementSize,
|
||||||
nsBlockFrame* aBlock);
|
nsBlockFrame* aBlock);
|
||||||
|
|
||||||
|
nsresult RecoverState(nsLineData* aLine);
|
||||||
|
|
||||||
nsIPresContext* mPresContext;
|
nsIPresContext* mPresContext;
|
||||||
|
|
||||||
nsBlockFrame* mBlock;
|
nsBlockFrame* mBlock;
|
||||||
@ -249,6 +251,14 @@ protected:
|
|||||||
const nsSize& aMaxSize,
|
const nsSize& aMaxSize,
|
||||||
nsRect& aDesiredRect);
|
nsRect& aDesiredRect);
|
||||||
|
|
||||||
|
nsLineData* LastLine();
|
||||||
|
nsLineData* FindLine(nsIFrame* aFrame);
|
||||||
|
|
||||||
|
nsresult IncrementalReflowAfter(nsBlockReflowState& aState,
|
||||||
|
nsLineData* aLine,
|
||||||
|
nsresult aReflowStatus,
|
||||||
|
const nsRect& aOldBounds);
|
||||||
|
|
||||||
void DestroyLines();
|
void DestroyLines();
|
||||||
|
|
||||||
void DrainOverflowList();
|
void DrainOverflowList();
|
||||||
@ -278,6 +288,7 @@ protected:
|
|||||||
nsLineData* aLine);
|
nsLineData* aLine);
|
||||||
|
|
||||||
nsresult ReflowMapped(nsBlockReflowState& aState);
|
nsresult ReflowMapped(nsBlockReflowState& aState);
|
||||||
|
nsresult ReflowMappedFrom(nsBlockReflowState& aState, nsLineData* aLine);
|
||||||
|
|
||||||
nsresult ReflowUnmapped(nsBlockReflowState& aState);
|
nsresult ReflowUnmapped(nsBlockReflowState& aState);
|
||||||
|
|
||||||
|
@ -142,6 +142,45 @@ nsBlockReflowState::Initialize(nsIPresContext* aPresContext,
|
|||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Recover the block reflow state to what it should be if aLine is about
|
||||||
|
// to be reflowed. aLine should not be nsnull
|
||||||
|
nsresult nsBlockReflowState::RecoverState(nsLineData* aLine)
|
||||||
|
{
|
||||||
|
NS_PRECONDITION(nsnull != aLine, "null parameter");
|
||||||
|
nsLineData* prevLine = aLine->mPrevLine;
|
||||||
|
|
||||||
|
if (nsnull != prevLine) {
|
||||||
|
// Compute the running y-offset, and the available height
|
||||||
|
mY = prevLine->mBounds.YMost();
|
||||||
|
if (!mUnconstrainedHeight) {
|
||||||
|
mAvailSize.height -= mY;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute the kid x-most
|
||||||
|
for (nsLineData* l = prevLine; nsnull != l; l = l->mPrevLine) {
|
||||||
|
nscoord xmost = l->mBounds.XMost();
|
||||||
|
if (xmost > mKidXMost) {
|
||||||
|
mKidXMost = xmost;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the previous line is a block, then factor in its bottom margin
|
||||||
|
if (prevLine->mIsBlock) {
|
||||||
|
nsStyleSpacing* spacing;
|
||||||
|
nsIFrame* kid = prevLine->mFirstChild;
|
||||||
|
|
||||||
|
kid->GetStyleData(kStyleSpacingSID, (nsStyleStruct*&)spacing);
|
||||||
|
if (spacing->mMargin.bottom < 0) {
|
||||||
|
mPrevMaxNegBottomMargin = -spacing->mMargin.bottom;
|
||||||
|
} else {
|
||||||
|
mPrevMaxPosBottomMargin = spacing->mMargin.bottom;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
@ -780,6 +819,52 @@ done:
|
|||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// XXX This is a short-term hack. It assumes that the caller has already recovered
|
||||||
|
// the state, and that some space has been retrieved from the space manager...
|
||||||
|
nsresult
|
||||||
|
nsBlockFrame::ReflowMappedFrom(nsBlockReflowState& aState, nsLineData* aLine)
|
||||||
|
{
|
||||||
|
nsresult rv = NS_OK;
|
||||||
|
|
||||||
|
nsLineLayout lineLayout(aState);
|
||||||
|
aState.mCurrentLine = &lineLayout;
|
||||||
|
while (nsnull != aLine) {
|
||||||
|
// Initialize the line layout for this line
|
||||||
|
rv = lineLayout.Initialize(aState, aLine);
|
||||||
|
if (NS_OK != rv) {
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
lineLayout.mPrevKidFrame = aState.mPrevKidFrame;
|
||||||
|
|
||||||
|
// Reflow the line
|
||||||
|
nsresult lineReflowStatus = lineLayout.ReflowLine();
|
||||||
|
if (lineReflowStatus < 0) {
|
||||||
|
// Some kind of hard error
|
||||||
|
rv = lineReflowStatus;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
mChildCount += lineLayout.mNewFrames;
|
||||||
|
|
||||||
|
// Now place it. It's possible it won't fit.
|
||||||
|
rv = PlaceLine(aState, lineLayout, aLine);
|
||||||
|
if (NS_LINE_LAYOUT_COMPLETE != rv) {
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
mLastContentOffset = aLine->mLastContentOffset;
|
||||||
|
mLastContentIsComplete = PRBool(aLine->mLastContentIsComplete);
|
||||||
|
aLine = aLine->mNextLine;
|
||||||
|
aState.mPrevKidFrame = lineLayout.mPrevKidFrame;
|
||||||
|
}
|
||||||
|
|
||||||
|
done:
|
||||||
|
aState.mCurrentLine = nsnull;
|
||||||
|
#ifdef NS_DEBUG
|
||||||
|
VerifyLines(PR_TRUE);
|
||||||
|
#endif
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
nsBlockFrame::ReflowUnmapped(nsBlockReflowState& aState)
|
nsBlockFrame::ReflowUnmapped(nsBlockReflowState& aState)
|
||||||
{
|
{
|
||||||
@ -1194,6 +1279,51 @@ nsBlockFrame::ResizeReflow(nsIPresContext* aPresContext,
|
|||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nsLineData* nsBlockFrame::FindLine(nsIFrame* aFrame)
|
||||||
|
{
|
||||||
|
// Find the line that contains the aFrame
|
||||||
|
nsLineData* line = mLines;
|
||||||
|
while (nsnull != line) {
|
||||||
|
nsIFrame* child = line->mFirstChild;
|
||||||
|
for (PRInt32 count = line->mChildCount; count > 0; count--) {
|
||||||
|
if (child == aFrame) {
|
||||||
|
return line;
|
||||||
|
}
|
||||||
|
|
||||||
|
child->GetNextSibling(child);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move to the next line
|
||||||
|
line = line->mNextLine;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nsnull;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsLineData* nsBlockFrame::LastLine()
|
||||||
|
{
|
||||||
|
nsLineData* lastLine = mLines;
|
||||||
|
|
||||||
|
// Get the last line
|
||||||
|
if (nsnull != lastLine) {
|
||||||
|
while (nsnull != lastLine->mNextLine) {
|
||||||
|
lastLine = lastLine->mNextLine;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return lastLine;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult nsBlockFrame::IncrementalReflowAfter(nsBlockReflowState& aState,
|
||||||
|
nsLineData* aLine,
|
||||||
|
nsresult aReflowStatus,
|
||||||
|
const nsRect& aOldBounds)
|
||||||
|
{
|
||||||
|
// Now just reflow all the lines that follow...
|
||||||
|
// XXX Obviously this needs to be more efficient
|
||||||
|
return ReflowMappedFrom(aState, aLine->mNextLine);
|
||||||
|
}
|
||||||
|
|
||||||
NS_METHOD
|
NS_METHOD
|
||||||
nsBlockFrame::IncrementalReflow(nsIPresContext* aPresContext,
|
nsBlockFrame::IncrementalReflow(nsIPresContext* aPresContext,
|
||||||
nsISpaceManager* aSpaceManager,
|
nsISpaceManager* aSpaceManager,
|
||||||
@ -1219,39 +1349,11 @@ nsBlockFrame::IncrementalReflow(nsIPresContext* aPresContext,
|
|||||||
// Is the reflow command target at us?
|
// Is the reflow command target at us?
|
||||||
if (this == aReflowCommand.GetTarget()) {
|
if (this == aReflowCommand.GetTarget()) {
|
||||||
if (aReflowCommand.GetType() == nsReflowCommand::FrameAppended) {
|
if (aReflowCommand.GetType() == nsReflowCommand::FrameAppended) {
|
||||||
nsLineData* lastLine = mLines;
|
nsLineData* lastLine = LastLine();
|
||||||
|
|
||||||
// Get the last line
|
|
||||||
if (nsnull != lastLine) {
|
|
||||||
while (nsnull != lastLine->mNextLine) {
|
|
||||||
lastLine = lastLine->mNextLine;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Restore the state
|
// Restore the state
|
||||||
if ((nsnull != lastLine) && (nsnull != lastLine->mPrevLine)) {
|
if (nsnull != lastLine) {
|
||||||
nsLineData* prevLine = lastLine->mPrevLine;
|
state.RecoverState(lastLine);
|
||||||
|
|
||||||
state.mY = prevLine->mBounds.YMost();
|
|
||||||
if (!state.mUnconstrainedHeight) {
|
|
||||||
state.mAvailSize.height -= state.mY;
|
|
||||||
}
|
|
||||||
|
|
||||||
// XXX This isn't really right...
|
|
||||||
state.mKidXMost = mRect.width - state.mBorderPadding.right;
|
|
||||||
|
|
||||||
// If the previous line is a block, then factor in its bottom margin
|
|
||||||
if (prevLine->mIsBlock) {
|
|
||||||
nsStyleSpacing* spacing;
|
|
||||||
nsIFrame* kid = prevLine->mFirstChild;
|
|
||||||
|
|
||||||
kid->GetStyleData(kStyleSpacingSID, (nsStyleStruct*&)spacing);
|
|
||||||
if (spacing->mMargin.bottom < 0) {
|
|
||||||
state.mPrevMaxNegBottomMargin = -spacing->mMargin.bottom;
|
|
||||||
} else {
|
|
||||||
state.mPrevMaxPosBottomMargin = spacing->mMargin.bottom;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reflow unmapped children
|
// Reflow unmapped children
|
||||||
@ -1267,38 +1369,65 @@ nsBlockFrame::IncrementalReflow(nsIPresContext* aPresContext,
|
|||||||
rv = ReflowUnmapped(state);
|
rv = ReflowUnmapped(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set return status
|
} else if (aReflowCommand.GetType() == nsReflowCommand::ContentChanged) {
|
||||||
aStatus = frComplete;
|
// Restore our state as if the child that changed is the next frame to reflow
|
||||||
if (NS_LINE_LAYOUT_NOT_COMPLETE == rv) {
|
nsLineData* line = FindLine(aReflowCommand.GetChildFrame());
|
||||||
rv = NS_OK;
|
state.RecoverState(line);
|
||||||
aStatus = frNotComplete;
|
|
||||||
}
|
// Get some available space to start reflowing with
|
||||||
|
GetAvailableSpace(state, state.mY);
|
||||||
|
|
||||||
|
// Reflow the affected line, and all the lines that follow...
|
||||||
|
// XXX Obviously this needs to be more efficient
|
||||||
|
rv = ReflowMappedFrom(state, line);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
NS_NOTYETIMPLEMENTED("unexpected reflow command");
|
NS_NOTYETIMPLEMENTED("unexpected reflow command");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
#if 0
|
|
||||||
// The command is passing through us. Get the next frame in the reflow chain
|
// The command is passing through us. Get the next frame in the reflow chain
|
||||||
nsIFrame* nextFrame = aReflowCommand.GetNext();
|
nsIFrame* nextFrame = aReflowCommand.GetNext();
|
||||||
|
|
||||||
// Restore our state as if nextFrame is the next frame to reflow
|
// Restore our state as if nextFrame is the next frame to reflow
|
||||||
RecoverState(aPresContext, state, nextFrame);
|
nsLineData* line = FindLine(nextFrame);
|
||||||
|
state.RecoverState(line);
|
||||||
|
|
||||||
// Get the current bounds. We'll need this to adjust the frames that follow
|
// Get some available space to start reflowing with
|
||||||
nsRect oldBounds;
|
GetAvailableSpace(state, state.mY);
|
||||||
nextFrame->GetRect(oldBounds);
|
|
||||||
|
|
||||||
// Pass along the reflow command
|
// Reflow the affected line
|
||||||
nsRect desiredRect;
|
nsLineLayout lineLayout(state);
|
||||||
aStatus = aReflowCommand.Next(aSpaceManager, desiredRect, aMaxSize, nextFrame);
|
|
||||||
#endif
|
state.mCurrentLine = &lineLayout;
|
||||||
NS_NOTYETIMPLEMENTED("unexpected reflow command");
|
lineLayout.Initialize(state, line);
|
||||||
|
|
||||||
|
// Have the line handle the incremental reflow
|
||||||
|
nsRect oldBounds = line->mBounds;
|
||||||
|
rv = lineLayout.IncrementalReflowFromChild(aReflowCommand, nextFrame);
|
||||||
|
|
||||||
|
// Now place the line. It's possible it won't fit
|
||||||
|
rv = PlaceLine(state, lineLayout, line);
|
||||||
|
// XXX The way NS_LINE_LAYOUT_COMPLETE is being used is very confusing...
|
||||||
|
if (NS_LINE_LAYOUT_COMPLETE == rv) {
|
||||||
|
mLastContentOffset = line->mLastContentOffset;
|
||||||
|
mLastContentIsComplete = PRBool(line->mLastContentIsComplete);
|
||||||
|
state.mPrevKidFrame = lineLayout.mPrevKidFrame;
|
||||||
|
|
||||||
|
// Now figure out what to do with the frames that follow
|
||||||
|
rv = IncrementalReflowAfter(state, line, rv, oldBounds);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return our desired rect
|
// Return our desired rect
|
||||||
ComputeDesiredRect(state, aMaxSize, aDesiredRect);
|
ComputeDesiredRect(state, aMaxSize, aDesiredRect);
|
||||||
|
|
||||||
|
// Set return status
|
||||||
|
aStatus = frComplete;
|
||||||
|
if (NS_LINE_LAYOUT_NOT_COMPLETE == rv) {
|
||||||
|
rv = NS_OK;
|
||||||
|
aStatus = frNotComplete;
|
||||||
|
}
|
||||||
|
|
||||||
// Now that reflow has finished, remove the cached pointer
|
// Now that reflow has finished, remove the cached pointer
|
||||||
shell->RemoveCachedData(this);
|
shell->RemoveCachedData(this);
|
||||||
NS_RELEASE(shell);
|
NS_RELEASE(shell);
|
||||||
|
@ -142,6 +142,45 @@ nsBlockReflowState::Initialize(nsIPresContext* aPresContext,
|
|||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Recover the block reflow state to what it should be if aLine is about
|
||||||
|
// to be reflowed. aLine should not be nsnull
|
||||||
|
nsresult nsBlockReflowState::RecoverState(nsLineData* aLine)
|
||||||
|
{
|
||||||
|
NS_PRECONDITION(nsnull != aLine, "null parameter");
|
||||||
|
nsLineData* prevLine = aLine->mPrevLine;
|
||||||
|
|
||||||
|
if (nsnull != prevLine) {
|
||||||
|
// Compute the running y-offset, and the available height
|
||||||
|
mY = prevLine->mBounds.YMost();
|
||||||
|
if (!mUnconstrainedHeight) {
|
||||||
|
mAvailSize.height -= mY;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute the kid x-most
|
||||||
|
for (nsLineData* l = prevLine; nsnull != l; l = l->mPrevLine) {
|
||||||
|
nscoord xmost = l->mBounds.XMost();
|
||||||
|
if (xmost > mKidXMost) {
|
||||||
|
mKidXMost = xmost;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the previous line is a block, then factor in its bottom margin
|
||||||
|
if (prevLine->mIsBlock) {
|
||||||
|
nsStyleSpacing* spacing;
|
||||||
|
nsIFrame* kid = prevLine->mFirstChild;
|
||||||
|
|
||||||
|
kid->GetStyleData(kStyleSpacingSID, (nsStyleStruct*&)spacing);
|
||||||
|
if (spacing->mMargin.bottom < 0) {
|
||||||
|
mPrevMaxNegBottomMargin = -spacing->mMargin.bottom;
|
||||||
|
} else {
|
||||||
|
mPrevMaxPosBottomMargin = spacing->mMargin.bottom;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
@ -780,6 +819,52 @@ done:
|
|||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// XXX This is a short-term hack. It assumes that the caller has already recovered
|
||||||
|
// the state, and that some space has been retrieved from the space manager...
|
||||||
|
nsresult
|
||||||
|
nsBlockFrame::ReflowMappedFrom(nsBlockReflowState& aState, nsLineData* aLine)
|
||||||
|
{
|
||||||
|
nsresult rv = NS_OK;
|
||||||
|
|
||||||
|
nsLineLayout lineLayout(aState);
|
||||||
|
aState.mCurrentLine = &lineLayout;
|
||||||
|
while (nsnull != aLine) {
|
||||||
|
// Initialize the line layout for this line
|
||||||
|
rv = lineLayout.Initialize(aState, aLine);
|
||||||
|
if (NS_OK != rv) {
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
lineLayout.mPrevKidFrame = aState.mPrevKidFrame;
|
||||||
|
|
||||||
|
// Reflow the line
|
||||||
|
nsresult lineReflowStatus = lineLayout.ReflowLine();
|
||||||
|
if (lineReflowStatus < 0) {
|
||||||
|
// Some kind of hard error
|
||||||
|
rv = lineReflowStatus;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
mChildCount += lineLayout.mNewFrames;
|
||||||
|
|
||||||
|
// Now place it. It's possible it won't fit.
|
||||||
|
rv = PlaceLine(aState, lineLayout, aLine);
|
||||||
|
if (NS_LINE_LAYOUT_COMPLETE != rv) {
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
mLastContentOffset = aLine->mLastContentOffset;
|
||||||
|
mLastContentIsComplete = PRBool(aLine->mLastContentIsComplete);
|
||||||
|
aLine = aLine->mNextLine;
|
||||||
|
aState.mPrevKidFrame = lineLayout.mPrevKidFrame;
|
||||||
|
}
|
||||||
|
|
||||||
|
done:
|
||||||
|
aState.mCurrentLine = nsnull;
|
||||||
|
#ifdef NS_DEBUG
|
||||||
|
VerifyLines(PR_TRUE);
|
||||||
|
#endif
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
nsBlockFrame::ReflowUnmapped(nsBlockReflowState& aState)
|
nsBlockFrame::ReflowUnmapped(nsBlockReflowState& aState)
|
||||||
{
|
{
|
||||||
@ -1194,6 +1279,51 @@ nsBlockFrame::ResizeReflow(nsIPresContext* aPresContext,
|
|||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nsLineData* nsBlockFrame::FindLine(nsIFrame* aFrame)
|
||||||
|
{
|
||||||
|
// Find the line that contains the aFrame
|
||||||
|
nsLineData* line = mLines;
|
||||||
|
while (nsnull != line) {
|
||||||
|
nsIFrame* child = line->mFirstChild;
|
||||||
|
for (PRInt32 count = line->mChildCount; count > 0; count--) {
|
||||||
|
if (child == aFrame) {
|
||||||
|
return line;
|
||||||
|
}
|
||||||
|
|
||||||
|
child->GetNextSibling(child);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move to the next line
|
||||||
|
line = line->mNextLine;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nsnull;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsLineData* nsBlockFrame::LastLine()
|
||||||
|
{
|
||||||
|
nsLineData* lastLine = mLines;
|
||||||
|
|
||||||
|
// Get the last line
|
||||||
|
if (nsnull != lastLine) {
|
||||||
|
while (nsnull != lastLine->mNextLine) {
|
||||||
|
lastLine = lastLine->mNextLine;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return lastLine;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult nsBlockFrame::IncrementalReflowAfter(nsBlockReflowState& aState,
|
||||||
|
nsLineData* aLine,
|
||||||
|
nsresult aReflowStatus,
|
||||||
|
const nsRect& aOldBounds)
|
||||||
|
{
|
||||||
|
// Now just reflow all the lines that follow...
|
||||||
|
// XXX Obviously this needs to be more efficient
|
||||||
|
return ReflowMappedFrom(aState, aLine->mNextLine);
|
||||||
|
}
|
||||||
|
|
||||||
NS_METHOD
|
NS_METHOD
|
||||||
nsBlockFrame::IncrementalReflow(nsIPresContext* aPresContext,
|
nsBlockFrame::IncrementalReflow(nsIPresContext* aPresContext,
|
||||||
nsISpaceManager* aSpaceManager,
|
nsISpaceManager* aSpaceManager,
|
||||||
@ -1219,39 +1349,11 @@ nsBlockFrame::IncrementalReflow(nsIPresContext* aPresContext,
|
|||||||
// Is the reflow command target at us?
|
// Is the reflow command target at us?
|
||||||
if (this == aReflowCommand.GetTarget()) {
|
if (this == aReflowCommand.GetTarget()) {
|
||||||
if (aReflowCommand.GetType() == nsReflowCommand::FrameAppended) {
|
if (aReflowCommand.GetType() == nsReflowCommand::FrameAppended) {
|
||||||
nsLineData* lastLine = mLines;
|
nsLineData* lastLine = LastLine();
|
||||||
|
|
||||||
// Get the last line
|
|
||||||
if (nsnull != lastLine) {
|
|
||||||
while (nsnull != lastLine->mNextLine) {
|
|
||||||
lastLine = lastLine->mNextLine;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Restore the state
|
// Restore the state
|
||||||
if ((nsnull != lastLine) && (nsnull != lastLine->mPrevLine)) {
|
if (nsnull != lastLine) {
|
||||||
nsLineData* prevLine = lastLine->mPrevLine;
|
state.RecoverState(lastLine);
|
||||||
|
|
||||||
state.mY = prevLine->mBounds.YMost();
|
|
||||||
if (!state.mUnconstrainedHeight) {
|
|
||||||
state.mAvailSize.height -= state.mY;
|
|
||||||
}
|
|
||||||
|
|
||||||
// XXX This isn't really right...
|
|
||||||
state.mKidXMost = mRect.width - state.mBorderPadding.right;
|
|
||||||
|
|
||||||
// If the previous line is a block, then factor in its bottom margin
|
|
||||||
if (prevLine->mIsBlock) {
|
|
||||||
nsStyleSpacing* spacing;
|
|
||||||
nsIFrame* kid = prevLine->mFirstChild;
|
|
||||||
|
|
||||||
kid->GetStyleData(kStyleSpacingSID, (nsStyleStruct*&)spacing);
|
|
||||||
if (spacing->mMargin.bottom < 0) {
|
|
||||||
state.mPrevMaxNegBottomMargin = -spacing->mMargin.bottom;
|
|
||||||
} else {
|
|
||||||
state.mPrevMaxPosBottomMargin = spacing->mMargin.bottom;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reflow unmapped children
|
// Reflow unmapped children
|
||||||
@ -1267,38 +1369,65 @@ nsBlockFrame::IncrementalReflow(nsIPresContext* aPresContext,
|
|||||||
rv = ReflowUnmapped(state);
|
rv = ReflowUnmapped(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set return status
|
} else if (aReflowCommand.GetType() == nsReflowCommand::ContentChanged) {
|
||||||
aStatus = frComplete;
|
// Restore our state as if the child that changed is the next frame to reflow
|
||||||
if (NS_LINE_LAYOUT_NOT_COMPLETE == rv) {
|
nsLineData* line = FindLine(aReflowCommand.GetChildFrame());
|
||||||
rv = NS_OK;
|
state.RecoverState(line);
|
||||||
aStatus = frNotComplete;
|
|
||||||
}
|
// Get some available space to start reflowing with
|
||||||
|
GetAvailableSpace(state, state.mY);
|
||||||
|
|
||||||
|
// Reflow the affected line, and all the lines that follow...
|
||||||
|
// XXX Obviously this needs to be more efficient
|
||||||
|
rv = ReflowMappedFrom(state, line);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
NS_NOTYETIMPLEMENTED("unexpected reflow command");
|
NS_NOTYETIMPLEMENTED("unexpected reflow command");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
#if 0
|
|
||||||
// The command is passing through us. Get the next frame in the reflow chain
|
// The command is passing through us. Get the next frame in the reflow chain
|
||||||
nsIFrame* nextFrame = aReflowCommand.GetNext();
|
nsIFrame* nextFrame = aReflowCommand.GetNext();
|
||||||
|
|
||||||
// Restore our state as if nextFrame is the next frame to reflow
|
// Restore our state as if nextFrame is the next frame to reflow
|
||||||
RecoverState(aPresContext, state, nextFrame);
|
nsLineData* line = FindLine(nextFrame);
|
||||||
|
state.RecoverState(line);
|
||||||
|
|
||||||
// Get the current bounds. We'll need this to adjust the frames that follow
|
// Get some available space to start reflowing with
|
||||||
nsRect oldBounds;
|
GetAvailableSpace(state, state.mY);
|
||||||
nextFrame->GetRect(oldBounds);
|
|
||||||
|
|
||||||
// Pass along the reflow command
|
// Reflow the affected line
|
||||||
nsRect desiredRect;
|
nsLineLayout lineLayout(state);
|
||||||
aStatus = aReflowCommand.Next(aSpaceManager, desiredRect, aMaxSize, nextFrame);
|
|
||||||
#endif
|
state.mCurrentLine = &lineLayout;
|
||||||
NS_NOTYETIMPLEMENTED("unexpected reflow command");
|
lineLayout.Initialize(state, line);
|
||||||
|
|
||||||
|
// Have the line handle the incremental reflow
|
||||||
|
nsRect oldBounds = line->mBounds;
|
||||||
|
rv = lineLayout.IncrementalReflowFromChild(aReflowCommand, nextFrame);
|
||||||
|
|
||||||
|
// Now place the line. It's possible it won't fit
|
||||||
|
rv = PlaceLine(state, lineLayout, line);
|
||||||
|
// XXX The way NS_LINE_LAYOUT_COMPLETE is being used is very confusing...
|
||||||
|
if (NS_LINE_LAYOUT_COMPLETE == rv) {
|
||||||
|
mLastContentOffset = line->mLastContentOffset;
|
||||||
|
mLastContentIsComplete = PRBool(line->mLastContentIsComplete);
|
||||||
|
state.mPrevKidFrame = lineLayout.mPrevKidFrame;
|
||||||
|
|
||||||
|
// Now figure out what to do with the frames that follow
|
||||||
|
rv = IncrementalReflowAfter(state, line, rv, oldBounds);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return our desired rect
|
// Return our desired rect
|
||||||
ComputeDesiredRect(state, aMaxSize, aDesiredRect);
|
ComputeDesiredRect(state, aMaxSize, aDesiredRect);
|
||||||
|
|
||||||
|
// Set return status
|
||||||
|
aStatus = frComplete;
|
||||||
|
if (NS_LINE_LAYOUT_NOT_COMPLETE == rv) {
|
||||||
|
rv = NS_OK;
|
||||||
|
aStatus = frNotComplete;
|
||||||
|
}
|
||||||
|
|
||||||
// Now that reflow has finished, remove the cached pointer
|
// Now that reflow has finished, remove the cached pointer
|
||||||
shell->RemoveCachedData(this);
|
shell->RemoveCachedData(this);
|
||||||
NS_RELEASE(shell);
|
NS_RELEASE(shell);
|
||||||
|
@ -272,14 +272,13 @@ NS_METHOD nsBodyFrame::IncrementalReflow(nsIPresContext* aPresContext,
|
|||||||
nsSize columnMaxSize = GetColumnAvailSpace(aPresContext, mySpacing,
|
nsSize columnMaxSize = GetColumnAvailSpace(aPresContext, mySpacing,
|
||||||
aMaxSize);
|
aMaxSize);
|
||||||
|
|
||||||
// Pass the command along to our child frame
|
// Pass the command along to our column pseudo frame
|
||||||
nsIRunaround* reflowRunaround;
|
nsRect desiredRect;
|
||||||
nsRect desiredRect;
|
nsIFrame* nextFrame;
|
||||||
|
|
||||||
NS_ASSERTION(nsnull != mFirstChild, "no first child");
|
NS_ASSERTION(nsnull != mFirstChild, "no first child");
|
||||||
mFirstChild->QueryInterface(kIRunaroundIID, (void**)&reflowRunaround);
|
aStatus = aReflowCommand.Next(mSpaceManager, desiredRect, columnMaxSize,
|
||||||
reflowRunaround->IncrementalReflow(aPresContext, mSpaceManager,
|
nextFrame);
|
||||||
columnMaxSize, desiredRect, aReflowCommand, aStatus);
|
|
||||||
|
|
||||||
// Place and size the frame
|
// Place and size the frame
|
||||||
desiredRect.x += leftInset;
|
desiredRect.x += leftInset;
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
#include "nsPlaceholderFrame.h"
|
#include "nsPlaceholderFrame.h"
|
||||||
#include "nsCSSLayout.h"
|
#include "nsCSSLayout.h"
|
||||||
#include "nsCRT.h"
|
#include "nsCRT.h"
|
||||||
|
#include "nsReflowCommand.h"
|
||||||
|
|
||||||
#undef NOISY_REFLOW
|
#undef NOISY_REFLOW
|
||||||
|
|
||||||
@ -356,7 +357,7 @@ nsLineLayout::WordBreakReflow()
|
|||||||
// Return values: <0 for error
|
// Return values: <0 for error
|
||||||
// 0 == NS_LINE_LAYOUT
|
// 0 == NS_LINE_LAYOUT
|
||||||
nsresult
|
nsresult
|
||||||
nsLineLayout::ReflowChild()
|
nsLineLayout::ReflowChild(nsReflowCommand* aReflowCommand)
|
||||||
{
|
{
|
||||||
// Get kid frame's style context
|
// Get kid frame's style context
|
||||||
nsIStyleContextPtr kidSC;
|
nsIStyleContextPtr kidSC;
|
||||||
@ -413,7 +414,20 @@ nsLineLayout::ReflowChild()
|
|||||||
}
|
}
|
||||||
mReflowResult = NS_LINE_LAYOUT_REFLOW_RESULT_NOT_AWARE;
|
mReflowResult = NS_LINE_LAYOUT_REFLOW_RESULT_NOT_AWARE;
|
||||||
nscoord dx = mReflowData.mX + kidSpacing->mMargin.left;
|
nscoord dx = mReflowData.mX + kidSpacing->mMargin.left;
|
||||||
if (isBlock) {
|
if (aReflowCommand) {
|
||||||
|
nsIFrame* nextFrame;
|
||||||
|
|
||||||
|
mSpaceManager->Translate(dx, mY);
|
||||||
|
kidReflowStatus = aReflowCommand->Next(mSpaceManager, kidRect, kidAvailSize, nextFrame);
|
||||||
|
mSpaceManager->Translate(-dx, -mY);
|
||||||
|
kidRect.x = dx;
|
||||||
|
kidRect.y = mY;
|
||||||
|
kidSize.width = kidRect.width;
|
||||||
|
kidSize.height = kidRect.height;
|
||||||
|
kidSize.ascent = kidRect.height;
|
||||||
|
kidSize.descent = 0;
|
||||||
|
|
||||||
|
} else if (isBlock) {
|
||||||
mSpaceManager->Translate(dx, mY);
|
mSpaceManager->Translate(dx, mY);
|
||||||
rv = mBlock->ReflowBlockChild(mKidFrame, mPresContext,
|
rv = mBlock->ReflowBlockChild(mKidFrame, mPresContext,
|
||||||
mSpaceManager, kidAvailSize, kidRect,
|
mSpaceManager, kidAvailSize, kidRect,
|
||||||
@ -518,6 +532,94 @@ nsLineLayout::ReflowChild()
|
|||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
nsLineLayout::IncrementalReflowFromChild(nsReflowCommand& aReflowCommand,
|
||||||
|
nsIFrame* aChildFrame)
|
||||||
|
{
|
||||||
|
#if 0
|
||||||
|
// Get the current bounds. We'll need this to adjust the frames that follow
|
||||||
|
nsRect oldBounds;
|
||||||
|
aChildFrame->GetRect(oldBounds);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// For the time being reflow all the children, and when we get to aChildFrame
|
||||||
|
// handle it specially
|
||||||
|
nsresult reflowStatus = NS_LINE_LAYOUT_COMPLETE;
|
||||||
|
|
||||||
|
mLine->mBounds.x = mReflowData.mX;
|
||||||
|
mLine->mBounds.y = mY;
|
||||||
|
mKidFrame = mLine->mFirstChild;
|
||||||
|
PRInt32 kidNum = 0;
|
||||||
|
while (kidNum < mLine->mChildCount) {
|
||||||
|
// XXX Code to avoid reflowing a child goes here
|
||||||
|
nsresult childReflowStatus;
|
||||||
|
|
||||||
|
if (mKidFrame == aChildFrame) {
|
||||||
|
childReflowStatus = ReflowChild(&aReflowCommand);
|
||||||
|
} else {
|
||||||
|
childReflowStatus = ReflowChild(nsnull);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (childReflowStatus < 0) {
|
||||||
|
reflowStatus = childReflowStatus;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (childReflowStatus) {
|
||||||
|
default:
|
||||||
|
case NS_LINE_LAYOUT_COMPLETE:
|
||||||
|
mPrevKidFrame = mKidFrame;
|
||||||
|
mKidFrame->GetNextSibling(mKidFrame);
|
||||||
|
mKidIndex++;
|
||||||
|
kidNum++;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NS_LINE_LAYOUT_NOT_COMPLETE:
|
||||||
|
reflowStatus = childReflowStatus;
|
||||||
|
mPrevKidFrame = mKidFrame;
|
||||||
|
mKidFrame->GetNextSibling(mKidFrame);
|
||||||
|
kidNum++;
|
||||||
|
goto split_line;
|
||||||
|
|
||||||
|
case NS_LINE_LAYOUT_BREAK_BEFORE:
|
||||||
|
reflowStatus = childReflowStatus;
|
||||||
|
goto split_line;
|
||||||
|
|
||||||
|
case NS_LINE_LAYOUT_BREAK_AFTER:
|
||||||
|
reflowStatus = childReflowStatus;
|
||||||
|
mPrevKidFrame = mKidFrame;
|
||||||
|
mKidFrame->GetNextSibling(mKidFrame);
|
||||||
|
mKidIndex++;
|
||||||
|
kidNum++;
|
||||||
|
|
||||||
|
split_line:
|
||||||
|
reflowStatus = SplitLine(childReflowStatus, mLine->mChildCount - kidNum);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
done:
|
||||||
|
// Perform alignment operations
|
||||||
|
if (mLine->mIsBlock) {
|
||||||
|
mLineHeight = mReflowData.mMaxAscent + mReflowData.mMaxDescent;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
AlignChildren();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set final bounds of the line
|
||||||
|
mLine->mBounds.height = mLineHeight;
|
||||||
|
mLine->mBounds.width = mReflowData.mX - mLine->mBounds.x;
|
||||||
|
|
||||||
|
NS_ASSERTION(((reflowStatus < 0) ||
|
||||||
|
(reflowStatus == NS_LINE_LAYOUT_COMPLETE) ||
|
||||||
|
(reflowStatus == NS_LINE_LAYOUT_NOT_COMPLETE) ||
|
||||||
|
(reflowStatus == NS_LINE_LAYOUT_BREAK_BEFORE) ||
|
||||||
|
(reflowStatus == NS_LINE_LAYOUT_BREAK_AFTER)),
|
||||||
|
"bad return status from ReflowMapped");
|
||||||
|
return reflowStatus;
|
||||||
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
@ -630,7 +732,7 @@ nsLineLayout::ReflowMapped()
|
|||||||
while (kidNum < mLine->mChildCount) {
|
while (kidNum < mLine->mChildCount) {
|
||||||
// XXX Code to avoid reflowing a child goes here
|
// XXX Code to avoid reflowing a child goes here
|
||||||
|
|
||||||
nsresult childReflowStatus = ReflowChild();
|
nsresult childReflowStatus = ReflowChild(nsnull);
|
||||||
if (childReflowStatus < 0) {
|
if (childReflowStatus < 0) {
|
||||||
reflowStatus = childReflowStatus;
|
reflowStatus = childReflowStatus;
|
||||||
goto done;
|
goto done;
|
||||||
@ -769,7 +871,7 @@ nsLineLayout::PullUpChildren()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Try to reflow it like any other mapped child
|
// Try to reflow it like any other mapped child
|
||||||
nsresult childReflowStatus = ReflowChild();
|
nsresult childReflowStatus = ReflowChild(nsnull);
|
||||||
if (childReflowStatus < 0) {
|
if (childReflowStatus < 0) {
|
||||||
reflowStatus = childReflowStatus;
|
reflowStatus = childReflowStatus;
|
||||||
goto done;
|
goto done;
|
||||||
@ -942,7 +1044,7 @@ nsLineLayout::ReflowUnmapped()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Reflow new child frame
|
// Reflow new child frame
|
||||||
childReflowStatus = ReflowChild();
|
childReflowStatus = ReflowChild(nsnull);
|
||||||
if (childReflowStatus < 0) {
|
if (childReflowStatus < 0) {
|
||||||
reflowStatus = childReflowStatus;
|
reflowStatus = childReflowStatus;
|
||||||
goto done;
|
goto done;
|
||||||
|
@ -100,16 +100,16 @@ struct nsLineLayout {
|
|||||||
*/
|
*/
|
||||||
nsresult ReflowLine();
|
nsresult ReflowLine();
|
||||||
|
|
||||||
|
nsresult IncrementalReflowFromChild(nsReflowCommand& aReflowCommand,
|
||||||
|
nsIFrame* aChildFrame);
|
||||||
|
|
||||||
|
|
||||||
// The presentation context
|
// The presentation context
|
||||||
nsIPresContext* mPresContext;
|
nsIPresContext* mPresContext;
|
||||||
|
|
||||||
// The block behind the line
|
// The block behind the line
|
||||||
nsBlockFrame* mBlock;
|
nsBlockFrame* mBlock;
|
||||||
nsISpaceManager* mSpaceManager;
|
nsISpaceManager* mSpaceManager;
|
||||||
#if 0
|
|
||||||
// XXX I don't think we need this anymore...
|
|
||||||
PRBool mBlockIsPseudo;
|
|
||||||
#endif
|
|
||||||
nsIContent* mBlockContent;
|
nsIContent* mBlockContent;
|
||||||
PRInt32 mKidIndex;
|
PRInt32 mKidIndex;
|
||||||
|
|
||||||
@ -180,7 +180,7 @@ protected:
|
|||||||
|
|
||||||
nsresult WordBreakReflow();
|
nsresult WordBreakReflow();
|
||||||
|
|
||||||
nsresult ReflowChild();
|
nsresult ReflowChild(nsReflowCommand* aReflowCommand);
|
||||||
|
|
||||||
nsresult ReflowMapped();
|
nsresult ReflowMapped();
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user