From df86871d93690258da873a450c882360e8492eab Mon Sep 17 00:00:00 2001 From: troy Date: Sun, 3 May 1998 03:51:48 +0000 Subject: [PATCH] Changed body to create block pseudo-frame instead of a column pseudo frame, and hooked up the reflow appended code --- layout/base/public/nsIFrame.h | 26 +- layout/base/src/nsPresShell.cpp | 48 +- layout/base/src/nsReflowCommand.cpp | 97 +--- layout/base/src/nsReflowCommand.h | 59 +-- layout/generic/nsBlockFrame.cpp | 118 ++++- layout/generic/nsBlockReflowState.cpp | 118 ++++- layout/generic/nsBlockReflowState.h | 118 ++++- layout/generic/nsHTMLContainerFrame.cpp | 36 ++ layout/generic/nsHTMLContainerFrame.h | 4 + layout/generic/nsIFrame.h | 26 +- layout/generic/nsInlineFrame.cpp | 46 -- layout/generic/nsLineLayout.cpp | 7 + layout/generic/nsLineLayout.h | 3 + layout/html/base/src/deadnsInlineFrame.h | 4 - layout/html/base/src/nsBlockFrame.cpp | 118 ++++- layout/html/base/src/nsBlockReflowState.cpp | 118 ++++- layout/html/base/src/nsBlockReflowState.h | 118 ++++- layout/html/base/src/nsBodyFrame.cpp | 108 ++--- layout/html/base/src/nsColumnFrame.cpp | 416 +++++------------- layout/html/base/src/nsColumnFrame.h | 8 +- layout/html/base/src/nsHTMLContainerFrame.cpp | 36 ++ layout/html/base/src/nsHTMLContainerFrame.h | 4 + layout/html/base/src/nsInlineFrame.cpp | 46 -- layout/html/base/src/nsLineLayout.cpp | 7 + layout/html/base/src/nsLineLayout.h | 3 + layout/html/table/src/nsTableCellFrame.cpp | 2 +- layout/tables/nsTableCellFrame.cpp | 2 +- 27 files changed, 999 insertions(+), 697 deletions(-) diff --git a/layout/base/public/nsIFrame.h b/layout/base/public/nsIFrame.h index 7d3eb818be0..61a58cc6262 100644 --- a/layout/base/public/nsIFrame.h +++ b/layout/base/public/nsIFrame.h @@ -250,12 +250,12 @@ public: ReflowStatus& aStatus) = 0; /** - * This call is invoked when content is appended to the content - * tree. The container frame that maps that content is asked to deal - * with the appended content by creating new frames and updating the - * index-in-parent values for it's affected children. In addition, - * the call must generate reflow commands that will incrementally - * reflow and repair the damaged portion of the frame tree. + * This call is invoked when content is appended to the content tree. + * + * This frame is the frame that maps the content object that has appended + * content. A typical response to this notification is to generate a + * FrameAppended incremental reflow command. You then handle the incremental + * reflow command by creating frames for the appended content. */ NS_IMETHOD ContentAppended(nsIPresShell* aShell, nsIPresContext* aPresContext, @@ -263,11 +263,15 @@ public: /** * This call is invoked when content is inserted in the content - * tree. The container frame that maps that content is asked to deal - * with the inserted content by creating new frames and updating the - * index-in-parent values for it's affected children. In addition, - * the call must generate reflow commands that will incrementally - * reflow and repair the damaged portion of the frame tree. + * tree. + * + * This frame is the frame that maps the content object that has inserted + * content. A typical response to this notification is to update the + * index-in-parent values for the affected child frames, create and insert + * new frame(s), and generate a FrameInserted incremental reflow command. + * + * You respond to the incremental reflow command by reflowing the newly + * inserted frame and any impacted frames. * * @param aIndexInParent the index in the content container where * the new content was inserted. diff --git a/layout/base/src/nsPresShell.cpp b/layout/base/src/nsPresShell.cpp index 10cfeccdb9a..6c34d1c3894 100644 --- a/layout/base/src/nsPresShell.cpp +++ b/layout/base/src/nsPresShell.cpp @@ -476,61 +476,55 @@ void PresShell::ContentChanged(nsIContent* aContent, void PresShell::ContentAppended(nsIContent* aContainer) { NS_PRECONDITION(nsnull != mRootFrame, "null root frame"); - nsReflowCommand* rc = new nsReflowCommand(mPresContext, - FindFrameWithContent(aContainer), - nsReflowCommand::ContentAppended, - aContainer); - AppendReflowCommand(rc); + + nsIFrame* frame = FindFrameWithContent(aContainer); + NS_PRECONDITION(nsnull != frame, "null frame"); + frame->ContentAppended(this, mPresContext, aContainer); ProcessReflowCommands(); } void PresShell::ContentInserted(nsIContent* aContainer, nsIContent* aChild, - PRInt32 aIndexInContainer) + PRInt32 aIndexInContainer) { NS_PRECONDITION(nsnull != mRootFrame, "null root frame"); - nsReflowCommand* rc = new nsReflowCommand(mPresContext, - FindFrameWithContent(aContainer), - nsReflowCommand::ContentInserted, - aContainer, aChild, - aIndexInContainer); - AppendReflowCommand(rc); + + nsIFrame* frame = FindFrameWithContent(aContainer); + NS_PRECONDITION(nsnull != frame, "null frame"); + frame->ContentInserted(this, mPresContext, aContainer, aChild, aIndexInContainer); ProcessReflowCommands(); } void PresShell::ContentReplaced(nsIContent* aContainer, nsIContent* aOldChild, nsIContent* aNewChild, - PRInt32 aIndexInContainer) + PRInt32 aIndexInContainer) { NS_PRECONDITION(nsnull != mRootFrame, "null root frame"); - nsReflowCommand* rc = new nsReflowCommand(mPresContext, - FindFrameWithContent(aContainer), - nsReflowCommand::ContentReplaced, - aContainer, aOldChild, aNewChild, - aIndexInContainer); - AppendReflowCommand(rc); + + nsIFrame* frame = FindFrameWithContent(aContainer); + NS_PRECONDITION(nsnull != frame, "null frame"); + frame->ContentReplaced(this, mPresContext, aContainer, aOldChild, + aNewChild, aIndexInContainer); ProcessReflowCommands(); } // XXX keep this? void PresShell::ContentWillBeRemoved(nsIContent* aContainer, nsIContent* aChild, - PRInt32 aIndexInContainer) + PRInt32 aIndexInContainer) { } void PresShell::ContentHasBeenRemoved(nsIContent* aContainer, nsIContent* aChild, - PRInt32 aIndexInContainer) + PRInt32 aIndexInContainer) { NS_PRECONDITION(nsnull != mRootFrame, "null root frame"); - nsReflowCommand* rc = new nsReflowCommand(mPresContext, - FindFrameWithContent(aContainer), - nsReflowCommand::ContentDeleted, - aContainer, aChild, - aIndexInContainer); - AppendReflowCommand(rc); + + nsIFrame* frame = FindFrameWithContent(aContainer); + NS_PRECONDITION(nsnull != frame, "null frame"); + frame->ContentDeleted(this, mPresContext, aContainer, aChild, aIndexInContainer); ProcessReflowCommands(); } diff --git a/layout/base/src/nsReflowCommand.cpp b/layout/base/src/nsReflowCommand.cpp index 34a72cb37c4..fb72f113e4a 100644 --- a/layout/base/src/nsReflowCommand.cpp +++ b/layout/base/src/nsReflowCommand.cpp @@ -27,13 +27,9 @@ static NS_DEFINE_IID(kIRunaroundIID, NS_IRUNAROUND_IID); // and a reflow command type nsReflowCommand::nsReflowCommand(nsIPresContext* aPresContext, nsIFrame* aTargetFrame, - ReflowType aReflowType, - PRInt32 aIndex) + ReflowType aReflowType) : mType(aReflowType), mTargetFrame(aTargetFrame), mPresContext(aPresContext), - mIndex(aIndex), - mContainer(nsnull), - mChild(nsnull), - mOldChild(nsnull) + mChildFrame(nsnull) { NS_PRECONDITION(mTargetFrame != nsnull, "null target frame"); aPresContext->AddRef(); @@ -42,104 +38,23 @@ nsReflowCommand::nsReflowCommand(nsIPresContext* aPresContext, nsReflowCommand::nsReflowCommand(nsIPresContext* aPresContext, nsIFrame* aTargetFrame, ReflowType aReflowType, - nsIContent* aContainer) + nsIFrame* aChildFrame) : mType(aReflowType), mTargetFrame(aTargetFrame), mPresContext(aPresContext), - mIndex(-1), - mContainer(aContainer), - mChild(nsnull), - mOldChild(nsnull) + mChildFrame(aChildFrame) { NS_PRECONDITION(mTargetFrame != nsnull, "null target frame"); - NS_PRECONDITION(mContainer != nsnull, "null container"); + NS_PRECONDITION(mChildFrame != nsnull, "null child frame"); NS_ADDREF(aPresContext); - NS_ADDREF(aContainer); -} - -nsReflowCommand::nsReflowCommand(nsIPresContext* aPresContext, - nsIFrame* aTargetFrame, - ReflowType aReflowType, - nsIContent* aContainer, - nsIContent* aChild, - PRInt32 aIndexInParent) - : mType(aReflowType), mTargetFrame(aTargetFrame), mPresContext(aPresContext), - mIndex(aIndexInParent), - mContainer(aContainer), - mChild(aChild), - mOldChild(nsnull) -{ - NS_PRECONDITION(mTargetFrame != nsnull, "null target frame"); - NS_PRECONDITION(mContainer != nsnull, "null container"); - NS_PRECONDITION(mChild != nsnull, "null child"); - NS_ADDREF(aPresContext); - NS_ADDREF(aContainer); - NS_ADDREF(aChild); -} - -nsReflowCommand::nsReflowCommand(nsIPresContext* aPresContext, - nsIFrame* aTargetFrame, - ReflowType aReflowType, - nsIContent* aContainer, - nsIContent* aOldChild, - nsIContent* aNewChild, - PRInt32 aIndexInParent) - : mType(aReflowType), mTargetFrame(aTargetFrame), mPresContext(aPresContext), - mIndex(aIndexInParent), - mContainer(aContainer), - mChild(aNewChild), - mOldChild(aOldChild) -{ - NS_PRECONDITION(mTargetFrame != nsnull, "null target frame"); - NS_PRECONDITION(mContainer != nsnull, "null container"); - NS_PRECONDITION(mChild != nsnull, "null new child"); - NS_PRECONDITION(mOldChild != nsnull, "null old child"); - NS_ADDREF(aPresContext); - NS_ADDREF(aContainer); - NS_ADDREF(aNewChild); - NS_ADDREF(aOldChild); } nsReflowCommand::~nsReflowCommand() { NS_IF_RELEASE(mPresContext); - NS_IF_RELEASE(mContainer); - NS_IF_RELEASE(mChild); - NS_IF_RELEASE(mOldChild); } void nsReflowCommand::Dispatch(nsReflowMetrics& aDesiredSize, const nsSize& aMaxSize) { - // Special handling for content tree change commands - nsIPresShell* shell; - switch (mType) { - case nsReflowCommand::ContentAppended: - shell = mPresContext->GetShell(); - mTargetFrame->ContentAppended(shell, mPresContext, mContainer); - NS_RELEASE(shell); - return; - - case nsReflowCommand::ContentInserted: - shell = mPresContext->GetShell(); - mTargetFrame->ContentInserted(shell, mPresContext, mContainer, - mChild, mIndex); - NS_RELEASE(shell); - return; - - case nsReflowCommand::ContentReplaced: - shell = mPresContext->GetShell(); - mTargetFrame->ContentReplaced(shell, mPresContext, mContainer, - mOldChild, mChild, mIndex); - NS_RELEASE(shell); - return; - - case nsReflowCommand::ContentDeleted: - shell = mPresContext->GetShell(); - mTargetFrame->ContentDeleted(shell, mPresContext, mContainer, - mChild, mIndex); - NS_RELEASE(shell); - return; - } - // Build the path from the target frame (index 0) to the root frame mPath.Clear(); for (nsIFrame* f = (nsIFrame*)mTargetFrame; nsnull != f; @@ -151,7 +66,7 @@ void nsReflowCommand::Dispatch(nsReflowMetrics& aDesiredSize, nsIFrame* root = (nsIFrame*)mPath[mPath.Count() - 1]; #ifdef NS_DEBUG - shell = mPresContext->GetShell(); + nsIPresShell* shell = mPresContext->GetShell(); if (nsnull != shell) { NS_ASSERTION(shell->GetRootFrame() == root, "bad root frame"); NS_RELEASE(shell); diff --git a/layout/base/src/nsReflowCommand.h b/layout/base/src/nsReflowCommand.h index 84deb9c47b4..3e92064624c 100644 --- a/layout/base/src/nsReflowCommand.h +++ b/layout/base/src/nsReflowCommand.h @@ -28,20 +28,8 @@ class nsISpaceManager; class nsReflowCommand { public: enum ReflowType { - // These reflow types are used for pre-processing a content - // append, insert or delete. The target frame is responsible for - // creating frames for the new children (or removing frames for - // delete) and then updating it's children's index-in-parent - // values. After that, the frame is responsible for creating new - // reflow commands to deal with the appended, inserted or deleted - // frames. - ContentAppended, - ContentInserted, - ContentReplaced, - ContentDeleted, - - // These are the reflow commands generated after the previous - // commands have completed. + // Reflow commands generated in response to a content insert/delete/append + // notification FrameAppended, FrameInserted, FrameDeleted, @@ -68,33 +56,13 @@ public: // XXX factory methods? nsReflowCommand(nsIPresContext* aPresContext, - nsIFrame* aTargetFrame, - ReflowType aReflowType); + nsIFrame* aTargetFrame, + ReflowType aReflowType); nsReflowCommand(nsIPresContext* aPresContext, - nsIFrame* aTargetFrame, - ReflowType aReflowType, - PRInt32 aIndexValue); - - nsReflowCommand(nsIPresContext* aPresContext, - nsIFrame* aTargetFrame, - ReflowType aReflowType, - nsIContent* aContainer); - - nsReflowCommand(nsIPresContext* aPresContext, - nsIFrame* aTargetFrame, - ReflowType aReflowType, - nsIContent* aContainer, - nsIContent* aChild, - PRInt32 aIndexInParent); - - nsReflowCommand(nsIPresContext* aPresContext, - nsIFrame* aTargetFrame, - ReflowType aReflowType, - nsIContent* aContainer, - nsIContent* aOldChild, - nsIContent* aNewChild, - PRInt32 aIndexInParent); + nsIFrame* aTargetFrame, + ReflowType aReflowType, + nsIFrame* aChildFrame); virtual ~nsReflowCommand(); @@ -124,22 +92,19 @@ public: nsIFrame* GetNext() const; // Get the target of the reflow command - nsIFrame* GetTarget() const { return mTargetFrame; } + nsIFrame* GetTarget() const {return mTargetFrame;} // Get the type of reflow command - ReflowType GetType() const { return mType; } + ReflowType GetType() const {return mType;} - // Get the index value - PRInt32 GetIndex() const { return mIndex; } + // Get the child frame associated with the reflow command + nsIFrame* GetChildFrame() const {return mChildFrame;} private: nsIPresContext* mPresContext; ReflowType mType; - nsIContent* mContainer; - nsIContent* mChild; - nsIContent* mOldChild; - PRInt32 mIndex; nsIFrame* mTargetFrame; + nsIFrame* mChildFrame; nsVoidArray mPath; }; diff --git a/layout/generic/nsBlockFrame.cpp b/layout/generic/nsBlockFrame.cpp index 0228ca80d41..88b8cd207ff 100644 --- a/layout/generic/nsBlockFrame.cpp +++ b/layout/generic/nsBlockFrame.cpp @@ -27,6 +27,7 @@ #include "nsHTMLAtoms.h" #include "nsHTMLIIDs.h" #include "nsHTMLValue.h" +#include "nsReflowCommand.h" // XXX what do we do with catastrophic errors (rv < 0)? What is the // state of the reflow world after such an error? @@ -794,12 +795,12 @@ nsBlockFrame::ReflowUnmapped(nsBlockReflowState& aState) while (nsnull != line->mNextLine) { line = line->mNextLine; } - prevLine = line; + prevLine = line->mPrevLine; // If the last line is not complete then kidPrevInFlow should be // set to the last-line's last child. - if (!prevLine->mLastContentIsComplete) { - kidPrevInFlow = prevLine->GetLastChild(); + if (!line->mLastContentIsComplete) { + kidPrevInFlow = line->GetLastChild(); } } @@ -964,6 +965,8 @@ PRBool nsBlockFrame::MoreToReflow(nsBlockReflowState& aState) { PRBool rv = PR_FALSE; +#if 0 + // XXX Don't need this anymore now that body has changed... if (aState.mBlockIsPseudo) { // Get the next content object that we would like to reflow PRInt32 kidIndex = NextChildOffset(); @@ -986,10 +989,13 @@ nsBlockFrame::MoreToReflow(nsBlockReflowState& aState) } } } else { +#endif if (NextChildOffset() < mContent->ChildCount()) { rv = PR_TRUE; } +#if 0 } +#endif return rv; } @@ -1141,8 +1147,7 @@ nsBlockFrame::ContentAppended(nsIPresShell* aShell, nsIPresContext* aPresContext, nsIContent* aContainer) { - nsresult rv = NS_OK; - return rv; + return nsHTMLContainerFrame::ContentAppended(aShell, aPresContext, aContainer); } NS_METHOD @@ -1217,7 +1222,110 @@ nsBlockFrame::IncrementalReflow(nsIPresContext* aPresContext, nsReflowCommand& aReflowCommand, nsIFrame::ReflowStatus& aStatus) { +#ifdef NS_DEBUG + VerifyLines(PR_TRUE); + PreReflowCheck(); +#endif + nsresult rv = NS_OK; + aStatus = frComplete; + nsBlockReflowState state; + rv = InitializeState(aPresContext, aSpaceManager, aMaxSize, + nsnull, state); + + nsIPresShell* shell = state.mPresContext->GetShell(); + shell->PutCachedData(this, &state); + + // Is the reflow command target at us? + if (this == aReflowCommand.GetTarget()) { + if (aReflowCommand.GetType() == nsReflowCommand::FrameAppended) { + nsLineData* lastLine = mLines; + + // Get the last line + if (nsnull != lastLine) { + while (nsnull != lastLine->mNextLine) { + lastLine = lastLine->mNextLine; + } + } + + // Restore the state + if ((nsnull != lastLine) && (nsnull != lastLine->mPrevLine)) { + nsLineData* prevLine = lastLine->mPrevLine; + + state.mY = prevLine->mBounds.YMost(); + + if (!state.mUnconstrainedHeight) { + state.mAvailSize.height -= state.mY; + } + + state.mKidXMost = mRect.XMost(); + +#if 0 + // XXX Set this... + state.mPrevMaxNegBottomMargin = ?; + state.mPrevMaxPosBottomMargin = ?; +#endif + } + + // Reflow unmapped children + rv = ReflowUnmapped(state); + + // Set return status + aStatus = frComplete; + if (NS_LINE_LAYOUT_NOT_COMPLETE == rv) { + rv = NS_OK; + aStatus = frNotComplete; + } + + } else { + NS_NOTYETIMPLEMENTED("unexpected reflow command"); + } + } else { + NS_NOTYETIMPLEMENTED("unexpected reflow command"); + } + + // Return our desired rect and our status + // XXX Share this code with DoResizeReflow()... + aDesiredRect.x = 0; + aDesiredRect.y = 0; + aDesiredRect.width = state.mKidXMost + state.mBorderPadding.right; + if (!state.mUnconstrainedWidth) { + // Make sure we're at least as wide as the max size we were given + nscoord maxWidth = state.mAvailSize.width + state.mBorderPadding.left + + state.mBorderPadding.right; + if (aDesiredRect.width < maxWidth) { + aDesiredRect.width = maxWidth; + } + } + state.mY += state.mBorderPadding.bottom; + nscoord lastBottomMargin = state.mPrevMaxPosBottomMargin - + state.mPrevMaxNegBottomMargin; + if (!state.mUnconstrainedHeight && (lastBottomMargin > 0)) { + // It's possible that we don't have room for the last bottom + // margin (the last bottom margin is the margin following a block + // element that we contain; it isn't applied immediately because + // of the margin collapsing logic). This can happen when we are + // reflowed in a limited amount of space because we don't know in + // advance what the last bottom margin will be. + nscoord maxY = aMaxSize.height; + if (state.mY + lastBottomMargin > maxY) { + lastBottomMargin = maxY - state.mY; + if (lastBottomMargin < 0) { + lastBottomMargin = 0; + } + } + state.mY += lastBottomMargin; + } + aDesiredRect.height = state.mY; + + // Now that reflow has finished, remove the cached pointer + shell->RemoveCachedData(this); + NS_RELEASE(shell); + +#ifdef NS_DEBUG + VerifyLines(PR_TRUE); + PostReflowCheck(aStatus); +#endif return rv; } diff --git a/layout/generic/nsBlockReflowState.cpp b/layout/generic/nsBlockReflowState.cpp index 0228ca80d41..88b8cd207ff 100644 --- a/layout/generic/nsBlockReflowState.cpp +++ b/layout/generic/nsBlockReflowState.cpp @@ -27,6 +27,7 @@ #include "nsHTMLAtoms.h" #include "nsHTMLIIDs.h" #include "nsHTMLValue.h" +#include "nsReflowCommand.h" // XXX what do we do with catastrophic errors (rv < 0)? What is the // state of the reflow world after such an error? @@ -794,12 +795,12 @@ nsBlockFrame::ReflowUnmapped(nsBlockReflowState& aState) while (nsnull != line->mNextLine) { line = line->mNextLine; } - prevLine = line; + prevLine = line->mPrevLine; // If the last line is not complete then kidPrevInFlow should be // set to the last-line's last child. - if (!prevLine->mLastContentIsComplete) { - kidPrevInFlow = prevLine->GetLastChild(); + if (!line->mLastContentIsComplete) { + kidPrevInFlow = line->GetLastChild(); } } @@ -964,6 +965,8 @@ PRBool nsBlockFrame::MoreToReflow(nsBlockReflowState& aState) { PRBool rv = PR_FALSE; +#if 0 + // XXX Don't need this anymore now that body has changed... if (aState.mBlockIsPseudo) { // Get the next content object that we would like to reflow PRInt32 kidIndex = NextChildOffset(); @@ -986,10 +989,13 @@ nsBlockFrame::MoreToReflow(nsBlockReflowState& aState) } } } else { +#endif if (NextChildOffset() < mContent->ChildCount()) { rv = PR_TRUE; } +#if 0 } +#endif return rv; } @@ -1141,8 +1147,7 @@ nsBlockFrame::ContentAppended(nsIPresShell* aShell, nsIPresContext* aPresContext, nsIContent* aContainer) { - nsresult rv = NS_OK; - return rv; + return nsHTMLContainerFrame::ContentAppended(aShell, aPresContext, aContainer); } NS_METHOD @@ -1217,7 +1222,110 @@ nsBlockFrame::IncrementalReflow(nsIPresContext* aPresContext, nsReflowCommand& aReflowCommand, nsIFrame::ReflowStatus& aStatus) { +#ifdef NS_DEBUG + VerifyLines(PR_TRUE); + PreReflowCheck(); +#endif + nsresult rv = NS_OK; + aStatus = frComplete; + nsBlockReflowState state; + rv = InitializeState(aPresContext, aSpaceManager, aMaxSize, + nsnull, state); + + nsIPresShell* shell = state.mPresContext->GetShell(); + shell->PutCachedData(this, &state); + + // Is the reflow command target at us? + if (this == aReflowCommand.GetTarget()) { + if (aReflowCommand.GetType() == nsReflowCommand::FrameAppended) { + nsLineData* lastLine = mLines; + + // Get the last line + if (nsnull != lastLine) { + while (nsnull != lastLine->mNextLine) { + lastLine = lastLine->mNextLine; + } + } + + // Restore the state + if ((nsnull != lastLine) && (nsnull != lastLine->mPrevLine)) { + nsLineData* prevLine = lastLine->mPrevLine; + + state.mY = prevLine->mBounds.YMost(); + + if (!state.mUnconstrainedHeight) { + state.mAvailSize.height -= state.mY; + } + + state.mKidXMost = mRect.XMost(); + +#if 0 + // XXX Set this... + state.mPrevMaxNegBottomMargin = ?; + state.mPrevMaxPosBottomMargin = ?; +#endif + } + + // Reflow unmapped children + rv = ReflowUnmapped(state); + + // Set return status + aStatus = frComplete; + if (NS_LINE_LAYOUT_NOT_COMPLETE == rv) { + rv = NS_OK; + aStatus = frNotComplete; + } + + } else { + NS_NOTYETIMPLEMENTED("unexpected reflow command"); + } + } else { + NS_NOTYETIMPLEMENTED("unexpected reflow command"); + } + + // Return our desired rect and our status + // XXX Share this code with DoResizeReflow()... + aDesiredRect.x = 0; + aDesiredRect.y = 0; + aDesiredRect.width = state.mKidXMost + state.mBorderPadding.right; + if (!state.mUnconstrainedWidth) { + // Make sure we're at least as wide as the max size we were given + nscoord maxWidth = state.mAvailSize.width + state.mBorderPadding.left + + state.mBorderPadding.right; + if (aDesiredRect.width < maxWidth) { + aDesiredRect.width = maxWidth; + } + } + state.mY += state.mBorderPadding.bottom; + nscoord lastBottomMargin = state.mPrevMaxPosBottomMargin - + state.mPrevMaxNegBottomMargin; + if (!state.mUnconstrainedHeight && (lastBottomMargin > 0)) { + // It's possible that we don't have room for the last bottom + // margin (the last bottom margin is the margin following a block + // element that we contain; it isn't applied immediately because + // of the margin collapsing logic). This can happen when we are + // reflowed in a limited amount of space because we don't know in + // advance what the last bottom margin will be. + nscoord maxY = aMaxSize.height; + if (state.mY + lastBottomMargin > maxY) { + lastBottomMargin = maxY - state.mY; + if (lastBottomMargin < 0) { + lastBottomMargin = 0; + } + } + state.mY += lastBottomMargin; + } + aDesiredRect.height = state.mY; + + // Now that reflow has finished, remove the cached pointer + shell->RemoveCachedData(this); + NS_RELEASE(shell); + +#ifdef NS_DEBUG + VerifyLines(PR_TRUE); + PostReflowCheck(aStatus); +#endif return rv; } diff --git a/layout/generic/nsBlockReflowState.h b/layout/generic/nsBlockReflowState.h index 0228ca80d41..88b8cd207ff 100644 --- a/layout/generic/nsBlockReflowState.h +++ b/layout/generic/nsBlockReflowState.h @@ -27,6 +27,7 @@ #include "nsHTMLAtoms.h" #include "nsHTMLIIDs.h" #include "nsHTMLValue.h" +#include "nsReflowCommand.h" // XXX what do we do with catastrophic errors (rv < 0)? What is the // state of the reflow world after such an error? @@ -794,12 +795,12 @@ nsBlockFrame::ReflowUnmapped(nsBlockReflowState& aState) while (nsnull != line->mNextLine) { line = line->mNextLine; } - prevLine = line; + prevLine = line->mPrevLine; // If the last line is not complete then kidPrevInFlow should be // set to the last-line's last child. - if (!prevLine->mLastContentIsComplete) { - kidPrevInFlow = prevLine->GetLastChild(); + if (!line->mLastContentIsComplete) { + kidPrevInFlow = line->GetLastChild(); } } @@ -964,6 +965,8 @@ PRBool nsBlockFrame::MoreToReflow(nsBlockReflowState& aState) { PRBool rv = PR_FALSE; +#if 0 + // XXX Don't need this anymore now that body has changed... if (aState.mBlockIsPseudo) { // Get the next content object that we would like to reflow PRInt32 kidIndex = NextChildOffset(); @@ -986,10 +989,13 @@ nsBlockFrame::MoreToReflow(nsBlockReflowState& aState) } } } else { +#endif if (NextChildOffset() < mContent->ChildCount()) { rv = PR_TRUE; } +#if 0 } +#endif return rv; } @@ -1141,8 +1147,7 @@ nsBlockFrame::ContentAppended(nsIPresShell* aShell, nsIPresContext* aPresContext, nsIContent* aContainer) { - nsresult rv = NS_OK; - return rv; + return nsHTMLContainerFrame::ContentAppended(aShell, aPresContext, aContainer); } NS_METHOD @@ -1217,7 +1222,110 @@ nsBlockFrame::IncrementalReflow(nsIPresContext* aPresContext, nsReflowCommand& aReflowCommand, nsIFrame::ReflowStatus& aStatus) { +#ifdef NS_DEBUG + VerifyLines(PR_TRUE); + PreReflowCheck(); +#endif + nsresult rv = NS_OK; + aStatus = frComplete; + nsBlockReflowState state; + rv = InitializeState(aPresContext, aSpaceManager, aMaxSize, + nsnull, state); + + nsIPresShell* shell = state.mPresContext->GetShell(); + shell->PutCachedData(this, &state); + + // Is the reflow command target at us? + if (this == aReflowCommand.GetTarget()) { + if (aReflowCommand.GetType() == nsReflowCommand::FrameAppended) { + nsLineData* lastLine = mLines; + + // Get the last line + if (nsnull != lastLine) { + while (nsnull != lastLine->mNextLine) { + lastLine = lastLine->mNextLine; + } + } + + // Restore the state + if ((nsnull != lastLine) && (nsnull != lastLine->mPrevLine)) { + nsLineData* prevLine = lastLine->mPrevLine; + + state.mY = prevLine->mBounds.YMost(); + + if (!state.mUnconstrainedHeight) { + state.mAvailSize.height -= state.mY; + } + + state.mKidXMost = mRect.XMost(); + +#if 0 + // XXX Set this... + state.mPrevMaxNegBottomMargin = ?; + state.mPrevMaxPosBottomMargin = ?; +#endif + } + + // Reflow unmapped children + rv = ReflowUnmapped(state); + + // Set return status + aStatus = frComplete; + if (NS_LINE_LAYOUT_NOT_COMPLETE == rv) { + rv = NS_OK; + aStatus = frNotComplete; + } + + } else { + NS_NOTYETIMPLEMENTED("unexpected reflow command"); + } + } else { + NS_NOTYETIMPLEMENTED("unexpected reflow command"); + } + + // Return our desired rect and our status + // XXX Share this code with DoResizeReflow()... + aDesiredRect.x = 0; + aDesiredRect.y = 0; + aDesiredRect.width = state.mKidXMost + state.mBorderPadding.right; + if (!state.mUnconstrainedWidth) { + // Make sure we're at least as wide as the max size we were given + nscoord maxWidth = state.mAvailSize.width + state.mBorderPadding.left + + state.mBorderPadding.right; + if (aDesiredRect.width < maxWidth) { + aDesiredRect.width = maxWidth; + } + } + state.mY += state.mBorderPadding.bottom; + nscoord lastBottomMargin = state.mPrevMaxPosBottomMargin - + state.mPrevMaxNegBottomMargin; + if (!state.mUnconstrainedHeight && (lastBottomMargin > 0)) { + // It's possible that we don't have room for the last bottom + // margin (the last bottom margin is the margin following a block + // element that we contain; it isn't applied immediately because + // of the margin collapsing logic). This can happen when we are + // reflowed in a limited amount of space because we don't know in + // advance what the last bottom margin will be. + nscoord maxY = aMaxSize.height; + if (state.mY + lastBottomMargin > maxY) { + lastBottomMargin = maxY - state.mY; + if (lastBottomMargin < 0) { + lastBottomMargin = 0; + } + } + state.mY += lastBottomMargin; + } + aDesiredRect.height = state.mY; + + // Now that reflow has finished, remove the cached pointer + shell->RemoveCachedData(this); + NS_RELEASE(shell); + +#ifdef NS_DEBUG + VerifyLines(PR_TRUE); + PostReflowCheck(aStatus); +#endif return rv; } diff --git a/layout/generic/nsHTMLContainerFrame.cpp b/layout/generic/nsHTMLContainerFrame.cpp index 7ea228ca7b2..f85fe800b8d 100644 --- a/layout/generic/nsHTMLContainerFrame.cpp +++ b/layout/generic/nsHTMLContainerFrame.cpp @@ -18,6 +18,7 @@ #include "nsHTMLContainerFrame.h" #include "nsIRenderingContext.h" #include "nsIPresContext.h" +#include "nsIPresShell.h" #include "nsIStyleContext.h" #include "nsStyleConsts.h" #include "nsCSSRendering.h" @@ -29,6 +30,7 @@ #include "nsGUIEvent.h" #include "nsIDocument.h" #include "nsIURL.h" +#include "nsReflowCommand.h" static NS_DEFINE_IID(kStyleBorderSID, NS_STYLEBORDER_SID); static NS_DEFINE_IID(kStyleColorSID, NS_STYLECOLOR_SID); @@ -170,6 +172,40 @@ NS_METHOD nsHTMLContainerFrame::GetCursorAt(nsIPresContext& aPresContext, return NS_OK; } +NS_METHOD nsHTMLContainerFrame::ContentAppended(nsIPresShell* aShell, + nsIPresContext* aPresContext, + nsIContent* aContainer) +{ + // Get the last-in-flow + nsHTMLContainerFrame* lastInFlow = (nsHTMLContainerFrame*)GetLastInFlow(); + + // Generate a reflow command for the frame + nsReflowCommand* cmd = new nsReflowCommand(aPresContext, lastInFlow, + nsReflowCommand::FrameAppended); + aShell->AppendReflowCommand(cmd); + return NS_OK; +} + +#if 0 +void nsHTMLContainerFrame::AdjustIndexInParents(nsIContent* aChild, + PRInt32 aIndexInParent, + ContentChange aChange) +{ + // Walk each child +} + +NS_METHOD nsHTMLContainerFrame::ContentInserted(nsIPresShell* aShell, + nsIPresContext* aPresContext, + nsIContent* aContainer, + nsIContent* aChild, + PRInt32 aIndexInParent) +{ + // Adjust the index-in-parent of each frame that follows the child that was + // inserted + AdjustIndexInParents(aChild, aIndexInParent, ContentInserted); +} +#endif + #if 0 nsIFrame::ReflowStatus nsHTMLContainerFrame::IncrementalReflow(nsIPresContext* aPresContext, diff --git a/layout/generic/nsHTMLContainerFrame.h b/layout/generic/nsHTMLContainerFrame.h index 0d2d6879e04..e89ab1a5182 100644 --- a/layout/generic/nsHTMLContainerFrame.h +++ b/layout/generic/nsHTMLContainerFrame.h @@ -42,6 +42,10 @@ public: nsIFrame** aFrame, PRInt32& aCursor); + NS_IMETHOD ContentAppended(nsIPresShell* aShell, + nsIPresContext* aPresContext, + nsIContent* aContainer); + protected: virtual ~nsHTMLContainerFrame(); diff --git a/layout/generic/nsIFrame.h b/layout/generic/nsIFrame.h index 7d3eb818be0..61a58cc6262 100644 --- a/layout/generic/nsIFrame.h +++ b/layout/generic/nsIFrame.h @@ -250,12 +250,12 @@ public: ReflowStatus& aStatus) = 0; /** - * This call is invoked when content is appended to the content - * tree. The container frame that maps that content is asked to deal - * with the appended content by creating new frames and updating the - * index-in-parent values for it's affected children. In addition, - * the call must generate reflow commands that will incrementally - * reflow and repair the damaged portion of the frame tree. + * This call is invoked when content is appended to the content tree. + * + * This frame is the frame that maps the content object that has appended + * content. A typical response to this notification is to generate a + * FrameAppended incremental reflow command. You then handle the incremental + * reflow command by creating frames for the appended content. */ NS_IMETHOD ContentAppended(nsIPresShell* aShell, nsIPresContext* aPresContext, @@ -263,11 +263,15 @@ public: /** * This call is invoked when content is inserted in the content - * tree. The container frame that maps that content is asked to deal - * with the inserted content by creating new frames and updating the - * index-in-parent values for it's affected children. In addition, - * the call must generate reflow commands that will incrementally - * reflow and repair the damaged portion of the frame tree. + * tree. + * + * This frame is the frame that maps the content object that has inserted + * content. A typical response to this notification is to update the + * index-in-parent values for the affected child frames, create and insert + * new frame(s), and generate a FrameInserted incremental reflow command. + * + * You respond to the incremental reflow command by reflowing the newly + * inserted frame and any impacted frames. * * @param aIndexInParent the index in the content container where * the new content was inserted. diff --git a/layout/generic/nsInlineFrame.cpp b/layout/generic/nsInlineFrame.cpp index 9cd92de6cf5..c87f53b3f2e 100644 --- a/layout/generic/nsInlineFrame.cpp +++ b/layout/generic/nsInlineFrame.cpp @@ -1029,49 +1029,3 @@ nsInlineFrame::AdjustChildren(nsIPresContext* aPresContext, return frComplete; } - -// My container has new content at the end of it. Create frames for -// the appended content and then generate an incremental reflow -// command for ourselves. -NS_METHOD nsInlineFrame::ContentAppended(nsIPresShell* aShell, - nsIPresContext* aPresContext, - nsIContent* aContainer) -{ - // Get the last in flow - nsInlineFrame* flow = (nsInlineFrame*)GetLastInFlow(); - - // Get index of where the content has been appended - PRInt32 kidIndex = flow->NextChildOffset(); - PRInt32 startIndex = kidIndex; - nsIFrame* prevKidFrame; - - flow->LastChild(prevKidFrame); - // Create frames for each new child - for (;;) { - // Get the next content object - nsIContent* kid = mContent->ChildAt(kidIndex); - if (nsnull == kid) { - break; - } - - nsIContentDelegate* del = kid->GetDelegate(aPresContext); - nsIFrame* kidFrame = del->CreateFrame(aPresContext, kid, kidIndex, flow); - NS_RELEASE(del); - NS_RELEASE(kid); - - // Append kidFrame to the sibling list - prevKidFrame->SetNextSibling(kidFrame); - prevKidFrame = kidFrame; - kidIndex++; - } - flow->SetLastContentOffset(prevKidFrame); - - // Now generate a reflow command for flow - if (aContainer == mContent) { - nsReflowCommand* rc = - new nsReflowCommand(aPresContext, flow, nsReflowCommand::FrameAppended, - startIndex); - aShell->AppendReflowCommand(rc); - } - return NS_OK; -} diff --git a/layout/generic/nsLineLayout.cpp b/layout/generic/nsLineLayout.cpp index d3ec7ec2786..77f58c2a536 100644 --- a/layout/generic/nsLineLayout.cpp +++ b/layout/generic/nsLineLayout.cpp @@ -200,7 +200,10 @@ nsLineLayout::nsLineLayout(nsBlockReflowState& aState) mSpaceManager = aState.mSpaceManager; mBlock->GetContent(mBlockContent); mPresContext = aState.mPresContext; +#if 0 + // XXX Do we still need this? mBlockIsPseudo = aState.mBlockIsPseudo; +#endif mUnconstrainedWidth = aState.mUnconstrainedWidth; mUnconstrainedHeight = aState.mUnconstrainedHeight; mMaxElementSizePointer = aState.mMaxElementSizePointer; @@ -856,6 +859,9 @@ nsLineLayout::CreateFrameFor(nsIContent* aKid) switch (kidDisplay->mDisplay) { case NS_STYLE_DISPLAY_BLOCK: case NS_STYLE_DISPLAY_LIST_ITEM: +#if 0 + // XXX Do we still need this? Now that the body code is changed it + // causes a problem... if (mBlockIsPseudo) { // Don't create the frame! It doesn't belong in us. @@ -864,6 +870,7 @@ nsLineLayout::CreateFrameFor(nsIContent* aKid) return NS_LINE_LAYOUT_PSEUDO_BREAK_BEFORE_BLOCK; } +#endif kidDel = aKid->GetDelegate(mPresContext); kidFrame = kidDel->CreateFrame(mPresContext, aKid, mKidIndex, mBlock); NS_RELEASE(kidDel); diff --git a/layout/generic/nsLineLayout.h b/layout/generic/nsLineLayout.h index 575eaa8159d..953bc670ff6 100644 --- a/layout/generic/nsLineLayout.h +++ b/layout/generic/nsLineLayout.h @@ -106,7 +106,10 @@ struct nsLineLayout { // The block behind the line nsBlockFrame* mBlock; nsISpaceManager* mSpaceManager; +#if 0 + // XXX I don't think we need this anymore... PRBool mBlockIsPseudo; +#endif nsIContent* mBlockContent; PRInt32 mKidIndex; diff --git a/layout/html/base/src/deadnsInlineFrame.h b/layout/html/base/src/deadnsInlineFrame.h index 464d604e65d..c3a8b582a45 100644 --- a/layout/html/base/src/deadnsInlineFrame.h +++ b/layout/html/base/src/deadnsInlineFrame.h @@ -43,10 +43,6 @@ public: nsReflowCommand& aReflowCommand, ReflowStatus& aStatus); - NS_IMETHOD ContentAppended(nsIPresShell* aShell, - nsIPresContext* aPresContext, - nsIContent* aContainer); - NS_IMETHOD GetReflowMetrics(nsIPresContext* aPresContext, nsReflowMetrics& aMetrics); diff --git a/layout/html/base/src/nsBlockFrame.cpp b/layout/html/base/src/nsBlockFrame.cpp index 0228ca80d41..88b8cd207ff 100644 --- a/layout/html/base/src/nsBlockFrame.cpp +++ b/layout/html/base/src/nsBlockFrame.cpp @@ -27,6 +27,7 @@ #include "nsHTMLAtoms.h" #include "nsHTMLIIDs.h" #include "nsHTMLValue.h" +#include "nsReflowCommand.h" // XXX what do we do with catastrophic errors (rv < 0)? What is the // state of the reflow world after such an error? @@ -794,12 +795,12 @@ nsBlockFrame::ReflowUnmapped(nsBlockReflowState& aState) while (nsnull != line->mNextLine) { line = line->mNextLine; } - prevLine = line; + prevLine = line->mPrevLine; // If the last line is not complete then kidPrevInFlow should be // set to the last-line's last child. - if (!prevLine->mLastContentIsComplete) { - kidPrevInFlow = prevLine->GetLastChild(); + if (!line->mLastContentIsComplete) { + kidPrevInFlow = line->GetLastChild(); } } @@ -964,6 +965,8 @@ PRBool nsBlockFrame::MoreToReflow(nsBlockReflowState& aState) { PRBool rv = PR_FALSE; +#if 0 + // XXX Don't need this anymore now that body has changed... if (aState.mBlockIsPseudo) { // Get the next content object that we would like to reflow PRInt32 kidIndex = NextChildOffset(); @@ -986,10 +989,13 @@ nsBlockFrame::MoreToReflow(nsBlockReflowState& aState) } } } else { +#endif if (NextChildOffset() < mContent->ChildCount()) { rv = PR_TRUE; } +#if 0 } +#endif return rv; } @@ -1141,8 +1147,7 @@ nsBlockFrame::ContentAppended(nsIPresShell* aShell, nsIPresContext* aPresContext, nsIContent* aContainer) { - nsresult rv = NS_OK; - return rv; + return nsHTMLContainerFrame::ContentAppended(aShell, aPresContext, aContainer); } NS_METHOD @@ -1217,7 +1222,110 @@ nsBlockFrame::IncrementalReflow(nsIPresContext* aPresContext, nsReflowCommand& aReflowCommand, nsIFrame::ReflowStatus& aStatus) { +#ifdef NS_DEBUG + VerifyLines(PR_TRUE); + PreReflowCheck(); +#endif + nsresult rv = NS_OK; + aStatus = frComplete; + nsBlockReflowState state; + rv = InitializeState(aPresContext, aSpaceManager, aMaxSize, + nsnull, state); + + nsIPresShell* shell = state.mPresContext->GetShell(); + shell->PutCachedData(this, &state); + + // Is the reflow command target at us? + if (this == aReflowCommand.GetTarget()) { + if (aReflowCommand.GetType() == nsReflowCommand::FrameAppended) { + nsLineData* lastLine = mLines; + + // Get the last line + if (nsnull != lastLine) { + while (nsnull != lastLine->mNextLine) { + lastLine = lastLine->mNextLine; + } + } + + // Restore the state + if ((nsnull != lastLine) && (nsnull != lastLine->mPrevLine)) { + nsLineData* prevLine = lastLine->mPrevLine; + + state.mY = prevLine->mBounds.YMost(); + + if (!state.mUnconstrainedHeight) { + state.mAvailSize.height -= state.mY; + } + + state.mKidXMost = mRect.XMost(); + +#if 0 + // XXX Set this... + state.mPrevMaxNegBottomMargin = ?; + state.mPrevMaxPosBottomMargin = ?; +#endif + } + + // Reflow unmapped children + rv = ReflowUnmapped(state); + + // Set return status + aStatus = frComplete; + if (NS_LINE_LAYOUT_NOT_COMPLETE == rv) { + rv = NS_OK; + aStatus = frNotComplete; + } + + } else { + NS_NOTYETIMPLEMENTED("unexpected reflow command"); + } + } else { + NS_NOTYETIMPLEMENTED("unexpected reflow command"); + } + + // Return our desired rect and our status + // XXX Share this code with DoResizeReflow()... + aDesiredRect.x = 0; + aDesiredRect.y = 0; + aDesiredRect.width = state.mKidXMost + state.mBorderPadding.right; + if (!state.mUnconstrainedWidth) { + // Make sure we're at least as wide as the max size we were given + nscoord maxWidth = state.mAvailSize.width + state.mBorderPadding.left + + state.mBorderPadding.right; + if (aDesiredRect.width < maxWidth) { + aDesiredRect.width = maxWidth; + } + } + state.mY += state.mBorderPadding.bottom; + nscoord lastBottomMargin = state.mPrevMaxPosBottomMargin - + state.mPrevMaxNegBottomMargin; + if (!state.mUnconstrainedHeight && (lastBottomMargin > 0)) { + // It's possible that we don't have room for the last bottom + // margin (the last bottom margin is the margin following a block + // element that we contain; it isn't applied immediately because + // of the margin collapsing logic). This can happen when we are + // reflowed in a limited amount of space because we don't know in + // advance what the last bottom margin will be. + nscoord maxY = aMaxSize.height; + if (state.mY + lastBottomMargin > maxY) { + lastBottomMargin = maxY - state.mY; + if (lastBottomMargin < 0) { + lastBottomMargin = 0; + } + } + state.mY += lastBottomMargin; + } + aDesiredRect.height = state.mY; + + // Now that reflow has finished, remove the cached pointer + shell->RemoveCachedData(this); + NS_RELEASE(shell); + +#ifdef NS_DEBUG + VerifyLines(PR_TRUE); + PostReflowCheck(aStatus); +#endif return rv; } diff --git a/layout/html/base/src/nsBlockReflowState.cpp b/layout/html/base/src/nsBlockReflowState.cpp index 0228ca80d41..88b8cd207ff 100644 --- a/layout/html/base/src/nsBlockReflowState.cpp +++ b/layout/html/base/src/nsBlockReflowState.cpp @@ -27,6 +27,7 @@ #include "nsHTMLAtoms.h" #include "nsHTMLIIDs.h" #include "nsHTMLValue.h" +#include "nsReflowCommand.h" // XXX what do we do with catastrophic errors (rv < 0)? What is the // state of the reflow world after such an error? @@ -794,12 +795,12 @@ nsBlockFrame::ReflowUnmapped(nsBlockReflowState& aState) while (nsnull != line->mNextLine) { line = line->mNextLine; } - prevLine = line; + prevLine = line->mPrevLine; // If the last line is not complete then kidPrevInFlow should be // set to the last-line's last child. - if (!prevLine->mLastContentIsComplete) { - kidPrevInFlow = prevLine->GetLastChild(); + if (!line->mLastContentIsComplete) { + kidPrevInFlow = line->GetLastChild(); } } @@ -964,6 +965,8 @@ PRBool nsBlockFrame::MoreToReflow(nsBlockReflowState& aState) { PRBool rv = PR_FALSE; +#if 0 + // XXX Don't need this anymore now that body has changed... if (aState.mBlockIsPseudo) { // Get the next content object that we would like to reflow PRInt32 kidIndex = NextChildOffset(); @@ -986,10 +989,13 @@ nsBlockFrame::MoreToReflow(nsBlockReflowState& aState) } } } else { +#endif if (NextChildOffset() < mContent->ChildCount()) { rv = PR_TRUE; } +#if 0 } +#endif return rv; } @@ -1141,8 +1147,7 @@ nsBlockFrame::ContentAppended(nsIPresShell* aShell, nsIPresContext* aPresContext, nsIContent* aContainer) { - nsresult rv = NS_OK; - return rv; + return nsHTMLContainerFrame::ContentAppended(aShell, aPresContext, aContainer); } NS_METHOD @@ -1217,7 +1222,110 @@ nsBlockFrame::IncrementalReflow(nsIPresContext* aPresContext, nsReflowCommand& aReflowCommand, nsIFrame::ReflowStatus& aStatus) { +#ifdef NS_DEBUG + VerifyLines(PR_TRUE); + PreReflowCheck(); +#endif + nsresult rv = NS_OK; + aStatus = frComplete; + nsBlockReflowState state; + rv = InitializeState(aPresContext, aSpaceManager, aMaxSize, + nsnull, state); + + nsIPresShell* shell = state.mPresContext->GetShell(); + shell->PutCachedData(this, &state); + + // Is the reflow command target at us? + if (this == aReflowCommand.GetTarget()) { + if (aReflowCommand.GetType() == nsReflowCommand::FrameAppended) { + nsLineData* lastLine = mLines; + + // Get the last line + if (nsnull != lastLine) { + while (nsnull != lastLine->mNextLine) { + lastLine = lastLine->mNextLine; + } + } + + // Restore the state + if ((nsnull != lastLine) && (nsnull != lastLine->mPrevLine)) { + nsLineData* prevLine = lastLine->mPrevLine; + + state.mY = prevLine->mBounds.YMost(); + + if (!state.mUnconstrainedHeight) { + state.mAvailSize.height -= state.mY; + } + + state.mKidXMost = mRect.XMost(); + +#if 0 + // XXX Set this... + state.mPrevMaxNegBottomMargin = ?; + state.mPrevMaxPosBottomMargin = ?; +#endif + } + + // Reflow unmapped children + rv = ReflowUnmapped(state); + + // Set return status + aStatus = frComplete; + if (NS_LINE_LAYOUT_NOT_COMPLETE == rv) { + rv = NS_OK; + aStatus = frNotComplete; + } + + } else { + NS_NOTYETIMPLEMENTED("unexpected reflow command"); + } + } else { + NS_NOTYETIMPLEMENTED("unexpected reflow command"); + } + + // Return our desired rect and our status + // XXX Share this code with DoResizeReflow()... + aDesiredRect.x = 0; + aDesiredRect.y = 0; + aDesiredRect.width = state.mKidXMost + state.mBorderPadding.right; + if (!state.mUnconstrainedWidth) { + // Make sure we're at least as wide as the max size we were given + nscoord maxWidth = state.mAvailSize.width + state.mBorderPadding.left + + state.mBorderPadding.right; + if (aDesiredRect.width < maxWidth) { + aDesiredRect.width = maxWidth; + } + } + state.mY += state.mBorderPadding.bottom; + nscoord lastBottomMargin = state.mPrevMaxPosBottomMargin - + state.mPrevMaxNegBottomMargin; + if (!state.mUnconstrainedHeight && (lastBottomMargin > 0)) { + // It's possible that we don't have room for the last bottom + // margin (the last bottom margin is the margin following a block + // element that we contain; it isn't applied immediately because + // of the margin collapsing logic). This can happen when we are + // reflowed in a limited amount of space because we don't know in + // advance what the last bottom margin will be. + nscoord maxY = aMaxSize.height; + if (state.mY + lastBottomMargin > maxY) { + lastBottomMargin = maxY - state.mY; + if (lastBottomMargin < 0) { + lastBottomMargin = 0; + } + } + state.mY += lastBottomMargin; + } + aDesiredRect.height = state.mY; + + // Now that reflow has finished, remove the cached pointer + shell->RemoveCachedData(this); + NS_RELEASE(shell); + +#ifdef NS_DEBUG + VerifyLines(PR_TRUE); + PostReflowCheck(aStatus); +#endif return rv; } diff --git a/layout/html/base/src/nsBlockReflowState.h b/layout/html/base/src/nsBlockReflowState.h index 0228ca80d41..88b8cd207ff 100644 --- a/layout/html/base/src/nsBlockReflowState.h +++ b/layout/html/base/src/nsBlockReflowState.h @@ -27,6 +27,7 @@ #include "nsHTMLAtoms.h" #include "nsHTMLIIDs.h" #include "nsHTMLValue.h" +#include "nsReflowCommand.h" // XXX what do we do with catastrophic errors (rv < 0)? What is the // state of the reflow world after such an error? @@ -794,12 +795,12 @@ nsBlockFrame::ReflowUnmapped(nsBlockReflowState& aState) while (nsnull != line->mNextLine) { line = line->mNextLine; } - prevLine = line; + prevLine = line->mPrevLine; // If the last line is not complete then kidPrevInFlow should be // set to the last-line's last child. - if (!prevLine->mLastContentIsComplete) { - kidPrevInFlow = prevLine->GetLastChild(); + if (!line->mLastContentIsComplete) { + kidPrevInFlow = line->GetLastChild(); } } @@ -964,6 +965,8 @@ PRBool nsBlockFrame::MoreToReflow(nsBlockReflowState& aState) { PRBool rv = PR_FALSE; +#if 0 + // XXX Don't need this anymore now that body has changed... if (aState.mBlockIsPseudo) { // Get the next content object that we would like to reflow PRInt32 kidIndex = NextChildOffset(); @@ -986,10 +989,13 @@ nsBlockFrame::MoreToReflow(nsBlockReflowState& aState) } } } else { +#endif if (NextChildOffset() < mContent->ChildCount()) { rv = PR_TRUE; } +#if 0 } +#endif return rv; } @@ -1141,8 +1147,7 @@ nsBlockFrame::ContentAppended(nsIPresShell* aShell, nsIPresContext* aPresContext, nsIContent* aContainer) { - nsresult rv = NS_OK; - return rv; + return nsHTMLContainerFrame::ContentAppended(aShell, aPresContext, aContainer); } NS_METHOD @@ -1217,7 +1222,110 @@ nsBlockFrame::IncrementalReflow(nsIPresContext* aPresContext, nsReflowCommand& aReflowCommand, nsIFrame::ReflowStatus& aStatus) { +#ifdef NS_DEBUG + VerifyLines(PR_TRUE); + PreReflowCheck(); +#endif + nsresult rv = NS_OK; + aStatus = frComplete; + nsBlockReflowState state; + rv = InitializeState(aPresContext, aSpaceManager, aMaxSize, + nsnull, state); + + nsIPresShell* shell = state.mPresContext->GetShell(); + shell->PutCachedData(this, &state); + + // Is the reflow command target at us? + if (this == aReflowCommand.GetTarget()) { + if (aReflowCommand.GetType() == nsReflowCommand::FrameAppended) { + nsLineData* lastLine = mLines; + + // Get the last line + if (nsnull != lastLine) { + while (nsnull != lastLine->mNextLine) { + lastLine = lastLine->mNextLine; + } + } + + // Restore the state + if ((nsnull != lastLine) && (nsnull != lastLine->mPrevLine)) { + nsLineData* prevLine = lastLine->mPrevLine; + + state.mY = prevLine->mBounds.YMost(); + + if (!state.mUnconstrainedHeight) { + state.mAvailSize.height -= state.mY; + } + + state.mKidXMost = mRect.XMost(); + +#if 0 + // XXX Set this... + state.mPrevMaxNegBottomMargin = ?; + state.mPrevMaxPosBottomMargin = ?; +#endif + } + + // Reflow unmapped children + rv = ReflowUnmapped(state); + + // Set return status + aStatus = frComplete; + if (NS_LINE_LAYOUT_NOT_COMPLETE == rv) { + rv = NS_OK; + aStatus = frNotComplete; + } + + } else { + NS_NOTYETIMPLEMENTED("unexpected reflow command"); + } + } else { + NS_NOTYETIMPLEMENTED("unexpected reflow command"); + } + + // Return our desired rect and our status + // XXX Share this code with DoResizeReflow()... + aDesiredRect.x = 0; + aDesiredRect.y = 0; + aDesiredRect.width = state.mKidXMost + state.mBorderPadding.right; + if (!state.mUnconstrainedWidth) { + // Make sure we're at least as wide as the max size we were given + nscoord maxWidth = state.mAvailSize.width + state.mBorderPadding.left + + state.mBorderPadding.right; + if (aDesiredRect.width < maxWidth) { + aDesiredRect.width = maxWidth; + } + } + state.mY += state.mBorderPadding.bottom; + nscoord lastBottomMargin = state.mPrevMaxPosBottomMargin - + state.mPrevMaxNegBottomMargin; + if (!state.mUnconstrainedHeight && (lastBottomMargin > 0)) { + // It's possible that we don't have room for the last bottom + // margin (the last bottom margin is the margin following a block + // element that we contain; it isn't applied immediately because + // of the margin collapsing logic). This can happen when we are + // reflowed in a limited amount of space because we don't know in + // advance what the last bottom margin will be. + nscoord maxY = aMaxSize.height; + if (state.mY + lastBottomMargin > maxY) { + lastBottomMargin = maxY - state.mY; + if (lastBottomMargin < 0) { + lastBottomMargin = 0; + } + } + state.mY += lastBottomMargin; + } + aDesiredRect.height = state.mY; + + // Now that reflow has finished, remove the cached pointer + shell->RemoveCachedData(this); + NS_RELEASE(shell); + +#ifdef NS_DEBUG + VerifyLines(PR_TRUE); + PostReflowCheck(aStatus); +#endif return rv; } diff --git a/layout/html/base/src/nsBodyFrame.cpp b/layout/html/base/src/nsBodyFrame.cpp index 0bd53ecc307..32c15137abe 100644 --- a/layout/html/base/src/nsBodyFrame.cpp +++ b/layout/html/base/src/nsBodyFrame.cpp @@ -26,7 +26,7 @@ #include "nsIPresShell.h" #include "nsIViewManager.h" #include "nsIDeviceContext.h" -#include "nsColumnFrame.h" +#include "nsBlockFrame.h" #include "nsSpaceManager.h" static NS_DEFINE_IID(kIRunaroundIID, NS_IRUNAROUND_IID); @@ -84,7 +84,7 @@ void nsBodyFrame::CreateColumnFrame(nsIPresContext* aPresContext) // Do we have a prev-in-flow? if (nsnull == mPrevInFlow) { // No, create a column pseudo frame - mFirstChild = new ColumnFrame(mContent, mIndexInParent, this); + nsBlockFrame::NewFrame(&mFirstChild, mContent, mIndexInParent, this); mChildCount = 1; // Resolve style and set the style context @@ -278,72 +278,43 @@ NS_METHOD nsBodyFrame::IncrementalReflow(nsIPresContext* aPresContext, mSpaceManager->ClearRegions(); mSpaceManager->Translate(leftInset, topInset); - // Is the reflow command targeted for us? - if (aReflowCommand.GetTarget() == this) { - // Currently we only support appended content - if (aReflowCommand.GetType() != nsReflowCommand::FrameAppended) { - NS_NOTYETIMPLEMENTED("unexpected reflow command"); - } + // The reflow command should never be target for us + NS_ASSERTION(aReflowCommand.GetTarget() != this, "bad reflow command target"); - // Compute the column's max size - nsSize columnMaxSize = GetColumnAvailSpace(aPresContext, mySpacing, - aMaxSize); + // Compute the column's max size + nsSize columnMaxSize = GetColumnAvailSpace(aPresContext, mySpacing, + aMaxSize); - // Pass the command along to our column pseudo frame - nsIRunaround* reflowRunaround; - nsRect aDesiredRect; + // Pass the command along to our column pseudo frame + nsIRunaround* reflowRunaround; + nsRect aDesiredRect; - NS_ASSERTION(nsnull != mFirstChild, "no first child"); - mFirstChild->QueryInterface(kIRunaroundIID, (void**)&reflowRunaround); - reflowRunaround->IncrementalReflow(aPresContext, mSpaceManager, - columnMaxSize, aDesiredRect, aReflowCommand, aStatus); + NS_ASSERTION(nsnull != mFirstChild, "no first child"); + mFirstChild->QueryInterface(kIRunaroundIID, (void**)&reflowRunaround); + reflowRunaround->IncrementalReflow(aPresContext, mSpaceManager, + columnMaxSize, aDesiredRect, aReflowCommand, aStatus); - // Place and size the column - aDesiredRect.x += leftInset; - aDesiredRect.y += topInset; - mFirstChild->SetRect(aDesiredRect); + // Place and size the column + aDesiredRect.x += leftInset; + aDesiredRect.y += topInset; + mFirstChild->SetRect(aDesiredRect); - // Set our last content offset and whether the last content is complete - // based on the state of the pseudo frame - SetLastContentOffset(mFirstChild); + // Set our last content offset and whether the last content is complete + // based on the state of the pseudo frame + SetLastContentOffset(mFirstChild); - // Return our desired size -#if 0 + // Return our desired size + aDesiredSize.height = PR_MAX(aDesiredRect.YMost(), mSpaceManager->YMost()); + if (isPseudoFrame) { aDesiredSize.width = aDesiredRect.XMost(); - aDesiredSize.height = aDesiredRect.YMost(); - if (!isPseudoFrame) { - aDesiredSize.width += mySpacing->mBorderPadding.left + mySpacing->mBorderPadding.right; - aDesiredSize.height += mySpacing->mBorderPadding.top + mySpacing->mBorderPadding.bottom; - } -#else - aDesiredSize.height = PR_MAX(aDesiredRect.YMost(), mSpaceManager->YMost()); - if (isPseudoFrame) { - aDesiredSize.width = aDesiredRect.XMost(); - } - else { - aDesiredSize.width = aMaxSize.width; - aDesiredSize.height += mySpacing->mBorderPadding.top + - mySpacing->mBorderPadding.bottom; - } - aDesiredSize.ascent = aDesiredSize.height; - aDesiredSize.descent = 0; -#endif - } else { - NS_NOTYETIMPLEMENTED("unexpected reflow command"); - nsRect desiredRect; - nsIFrame* child; - - aStatus = aReflowCommand.Next(mSpaceManager, desiredRect, aMaxSize, child); - - // XXX Deal with next in flow, adjusting of siblings, adjusting the - // content length... - - // Return our desired size - aDesiredSize.width = 0; - aDesiredSize.height = 0; - aDesiredSize.ascent = aDesiredSize.height; - aDesiredSize.descent = 0; } + else { + aDesiredSize.width = aMaxSize.width; + aDesiredSize.height += mySpacing->mBorderPadding.top + + mySpacing->mBorderPadding.bottom; + } + aDesiredSize.ascent = aDesiredSize.height; + aDesiredSize.descent = 0; mSpaceManager->Translate(-leftInset, -topInset); return NS_OK; @@ -355,20 +326,9 @@ NS_METHOD nsBodyFrame::ContentAppended(nsIPresShell* aShell, { NS_ASSERTION(mContent == aContainer, "bad content-appended target"); - // Get the last-in-flow - nsBodyFrame* flow = (nsBodyFrame*)GetLastInFlow(); - - // Since body frame's have only a single pseudo-frame in them, - // pass on the content-appended call to the pseudo-frame - PRInt32 oldLastContentOffset = mLastContentOffset; - flow->mFirstChild->ContentAppended(aShell, aPresContext, aContainer); - - // Now generate a frame reflow command aimed at flow - nsReflowCommand* rc = - new nsReflowCommand(aPresContext, flow, nsReflowCommand::FrameAppended, - oldLastContentOffset); - aShell->AppendReflowCommand(rc); - return NS_OK; + // Pass along the notification to our pseudo frame. It will generate a + // reflow command + return mFirstChild->ContentAppended(aShell, aPresContext, aContainer); } void nsBodyFrame::AddAnchoredItem(nsIFrame* aAnchoredItem, diff --git a/layout/html/base/src/nsColumnFrame.cpp b/layout/html/base/src/nsColumnFrame.cpp index 7f481a4bc73..6bb458e26ce 100644 --- a/layout/html/base/src/nsColumnFrame.cpp +++ b/layout/html/base/src/nsColumnFrame.cpp @@ -990,188 +990,117 @@ NS_METHOD ColumnFrame::IncrementalReflow(nsIPresContext* aPresContext, aSpaceManager->GetTranslation(txIn, tyIn); #endif - // Who's the reflow command targeted for? - if (aReflowCommand.GetTarget() == mGeometricParent) { - // It's targeted for our parent frame which passed the reflow - // command along to us. - // - // Currently we only support appended content, but this could also - // be an inserted reflow command. - if (aReflowCommand.GetType() != nsReflowCommand::FrameAppended) { + // Initialize our reflow state + ColumnReflowState state(aPresContext, aSpaceManager, aMaxSize); + + // XXX This nees to be computed the hard way. This value will be + // wrong because it includes our previous border+padding + // values. Since those values may have changed we need to + // recalculate our maxChildWidth based on our children and then we + // can add back in order border+padding + state.kidXMost = mRect.width; + + nsIFrame* target = aReflowCommand.GetTarget(); + if (this == target) { + if (aReflowCommand.GetType() == nsReflowCommand::FrameAppended) { + nsIFrame* prevKidFrame; + LastChild(prevKidFrame); + + // Factor in the previous kid's bottom margin information + if (nsnull != prevKidFrame) { + // When we have a previous kid frame, get it's y most coordinate + // and then setup the state so that the starting y is correct + // and the previous kid's bottom margin information is correct. + nsRect startKidRect; + prevKidFrame->GetRect(startKidRect); + + // Get style info + nsStyleSpacing* kidSpacing; + prevKidFrame->GetStyleData(kStyleSpacingSID, (nsStyleStruct*&)kidSpacing); + + // XXX Style system should do this... + nscoord bottomMargin = ChildIsPseudoFrame(prevKidFrame) + ? 0 + : kidSpacing->mMargin.bottom; + + state.y = startKidRect.YMost(); + if (bottomMargin < 0) { + state.prevMaxNegBottomMargin = -bottomMargin; + } else { + state.prevMaxPosBottomMargin = bottomMargin; + } + + if (PR_FALSE == state.unconstrainedHeight) { + state.availSize.height -= state.y; + } + } + + aSpaceManager->Translate(0, state.y); + + // Now reflow unmapped children + aStatus = ReflowUnmappedChildren(aPresContext, state, nsnull); + + // Restore the coordinate space + aSpaceManager->Translate(0, -state.y); + + } else { NS_NOTYETIMPLEMENTED("unexpected reflow command"); } + } else if (ChildIsPseudoFrame(target)) { + if (aReflowCommand.GetType() == nsReflowCommand::FrameAppended) { + // Because our last child is a pseudo-frame we passed along the content + // appended notification. First let the pseudo-frame reflow unmapped, + // and then we'll reflow unmapped + nsRect kidRect; -#if 0 - // Initialize body reflow state - ColumnReflowState state(aPresContext, aSpaceManager, aMaxSize); - - // Get to the frame that we should begin reflowing (where the - // append occured). - PRInt32 startOffset = aReflowCommand.GetIndex(); - nsIFrame* kidFrame = mFirstChild; - nsIFrame* prevKidFrame = nsnull; - PRInt32 kidIndex = mFirstContentOffset; - for (;;) { - if (ChildIsPseudoFrame(kidFrame)) { - nsBlockFrame* pseudo = (nsBlockFrame*) kidFrame; - PRInt32 fco = pseudo->GetFirstContentOffset(); - PRInt32 lco = pseudo->GetLastContentOffset(); - /* XXX <=? mLastContentIsComplete? */ - if ((fco <= startOffset) && (startOffset <= lco)) { - break; - } - } else { - PRInt32 kidIndexInParent; - - kidFrame->GetIndexInParent(kidIndexInParent); - if (kidIndexInParent == startOffset) { - break; - } - } - prevKidFrame = kidFrame; - kidFrame->GetNextSibling(kidFrame); - } - - // Factor in the previous kid's bottom margin information - // XXX inline version of RecoverState - if (nsnull != prevKidFrame) { - // When we have a previous kid frame, get it's y most coordinate - // and then setup the state so that the starting y is correct - // and the previous kid's bottom margin information is correct. - nsRect startKidRect; - prevKidFrame->GetRect(startKidRect); - - // Get style info - nsIStyleContextPtr kidSC; - - prevKidFrame->GetStyleContext(aPresContext, kidSC.AssignRef()); - nsStyleSpacing* kidSpacing = (nsStyleSpacing*) - kidSC->GetData(kStyleSpacingSID); - // XXX Style system should do this... - nscoord bottomMargin = ChildIsPseudoFrame(prevKidFrame) - ? 0 - : kidSpacing->mMargin.bottom; - - state.y = startKidRect.YMost(); - if (bottomMargin < 0) { - state.prevMaxNegBottomMargin = -bottomMargin; - } else { - state.prevMaxPosBottomMargin = bottomMargin; - } - } else { - state.prevMaxNegBottomMargin = 0; - state.prevMaxPosBottomMargin = 0; - state.y = 0; - } - - aSpaceManager->Translate(0, state.y); - - // XXX This nees to be computed the hard way. This value will be - // wrong because it includes our previous border+padding - // values. Since those values may have changed we need to - // recalculate our maxChildWidth based on our children and then we - // can add back in order border+padding - - // XXX subtract out old border+padding? - state.kidXMost = mRect.width; - - // Now ResizeReflow the appended frames - while (nsnull != kidFrame) { - nsIStyleContextPtr kidSC; - - kidFrame->GetStyleContext(aPresContext, kidSC.AssignRef()); - nsStyleSpacing* kidSpacing = (nsStyleSpacing*) - kidSC->GetData(kStyleSpacingSID); - nscoord topMargin = GetTopMarginFor(aPresContext, state, - kidFrame, kidSpacing); - - nsRect kidRect; - nsSize kidAvailSize(state.availSize); - + // Restore our state's running y-offset and available size + target->GetRect(kidRect); + state.y = kidRect.y; if (PR_FALSE == state.unconstrainedHeight) { - kidAvailSize.height -= topMargin; - } - - // Reflow the child - state.spaceManager->Translate(0, topMargin); - aStatus = ReflowChild(kidFrame, aPresContext, state.spaceManager, - kidAvailSize, kidRect, nsnull); - state.spaceManager->Translate(0, -topMargin); - - // Did it fit? - if ((kidFrame != mFirstChild) && - ((kidAvailSize.height <= 0) || - (kidRect.YMost() > kidAvailSize.height))) - { - // No, it didn't fit. This means we need to push this child - // to our next-in-flow and get it to reflow the appended - // children. - // XXX write me - NS_ABORT(); + state.availSize.height -= state.y; } - // Place the child - state.y += topMargin; - state.spaceManager->Translate(0, topMargin); - nsSize kidMaxElementSize; // XXX unused - kidRect.x += kidSpacing->mMargin.left; - kidRect.y += state.y; - PlaceChild(aPresContext, state, kidFrame, kidSpacing, - kidRect, nsnull, kidMaxElementSize); + nsIRunaround* reflowRunaround; + nsSize kidAvailSize(state.availSize); - // XXX Style system should do this... - nscoord bottomMargin = ChildIsPseudoFrame(kidFrame) - ? 0 - : kidSpacing->mMargin.bottom; - if (bottomMargin < 0) { - state.prevMaxNegBottomMargin = -bottomMargin; - } else { - state.prevMaxPosBottomMargin = bottomMargin; + aSpaceManager->Translate(0, state.y); + target->QueryInterface(kIRunaroundIID, (void**)&reflowRunaround); + reflowRunaround->IncrementalReflow(aPresContext, aSpaceManager, + kidAvailSize, kidRect, aReflowCommand, aStatus); + + // Place and size the child + nsSize kidMaxElementSize; + nsStyleSpacing* kidSpacing; + + target->GetStyleData(kStyleSpacingSID, (nsStyleStruct*&)kidSpacing); + PlaceChild(aPresContext, state, target, kidSpacing, kidRect, + nsnull, kidMaxElementSize); + + // Set our last content offset + SetLastContentOffset(target); + + // If the child's status is complete then reflow unmapped children + if (frComplete == aStatus) { + aStatus = ReflowUnmappedChildren(aPresContext, state, nsnull); } - // Is the child complete? - if (frNotComplete == aStatus) { - // No. Create a continuing frame - nsIFrame* continuingFrame; - - kidFrame->CreateContinuingFrame(aPresContext, this, continuingFrame); + aSpaceManager->Translate(0, -state.y); - // Insert the frame. We'll reflow it next pass through the loop - nsIFrame* nextSibling; - - kidFrame->GetNextSibling(nextSibling); - continuingFrame->SetNextSibling(nextSibling); - kidFrame->SetNextSibling(continuingFrame); - mChildCount++; - } - - // Get the next child frame - prevKidFrame = kidFrame; - kidFrame->GetNextSibling(kidFrame); + } else { + NS_NOTYETIMPLEMENTED("unexpected reflow command"); } - SetLastContentOffset(prevKidFrame); - - // Restore the coordinate space - aSpaceManager->Translate(0, -state.y); - - // Return our desired size - // XXX What about adding in the bottom margin from our last child like we - // did in ResizeReflow()? - aDesiredRect.x = 0; - aDesiredRect.y = 0; - aDesiredRect.width = state.kidXMost;/* XXX */ - aDesiredRect.height = state.y; -#endif - return ResizeReflow(aPresContext, aSpaceManager, aMaxSize, aDesiredRect, - nsnull, aStatus); - } else if (aReflowCommand.GetTarget() == this) { - // The reflow command is targeted for us. This could be a deleted or - // changed reflow command - NS_NOTYETIMPLEMENTED("unexpected reflow command"); } else { NS_NOTYETIMPLEMENTED("unexpected reflow command"); } + // Return our desired size + // XXX What about adding in the bottom margin from our last child like we + // did in ResizeReflow()? + aDesiredRect.x = 0; + aDesiredRect.y = 0; + aDesiredRect.width = state.kidXMost;/* XXX */ + aDesiredRect.height = state.y; + #ifdef NS_DEBUG // Verify we properly restored the coordinate space nscoord txOut, tyOut; @@ -1182,149 +1111,28 @@ NS_METHOD ColumnFrame::IncrementalReflow(nsIPresContext* aPresContext, return NS_OK; } -// XXX factor nicely with reflow-unmapped NS_METHOD ColumnFrame::ContentAppended(nsIPresShell* aShell, nsIPresContext* aPresContext, nsIContent* aContainer) { -#if 0 - // We must only be called by the body frame since we are a - // pseudo-frame; the body frame makes sure that it's dealing with - // it's last-in-flow therefore we must also be a last-in-flow - NS_ASSERTION(nsnull == mNextInFlow, "improper content-appended"); - NS_ASSERTION(mLastContentIsComplete == PR_TRUE, "huh?"); + // Get the last-in-flow + ColumnFrame* lastInFlow = (ColumnFrame*)GetLastInFlow(); - // Get index of where the content has been appended - PRInt32 kidIndex = NextChildOffset(); - PRInt32 startIndex = kidIndex; - nsIContent* content = mContent; - nsIFrame* prevKidFrame; - - LastChild(prevKidFrame); - nsBlockFrame* pseudoFrame = nsnull; - if ((nsnull != prevKidFrame) && ChildIsPseudoFrame(prevKidFrame)) { - pseudoFrame = (nsBlockFrame*) prevKidFrame; + // Get the last child frame, and see if it's a pseudo frame + nsIFrame* lastKidFrame; + LastChild(lastKidFrame); + + if ((nsnull != lastKidFrame) && ChildIsPseudoFrame(lastKidFrame)) { + // Pass along the notification to the pseudo frame + return lastKidFrame->ContentAppended(aShell, aPresContext, aContainer); + + } else { + // Generate a reflow command for the last-in-flow + nsReflowCommand* cmd = new nsReflowCommand(aPresContext, lastInFlow, + nsReflowCommand::FrameAppended); + aShell->AppendReflowCommand(cmd); + return NS_OK; } - - // Create frames for each new child - for (;;) { - // Get the next content object - nsIContentPtr kid = content->ChildAt(kidIndex); - if (nsnull == kid) { - break; - } - - // Get style context for the kid - nsIStyleContextPtr kidStyleContext = - aPresContext->ResolveStyleContextFor(kid, this); - nsStyleDisplay* kidDisplay = (nsStyleDisplay*) - kidStyleContext->GetData(kStyleDisplaySID); - nsStylePosition* kidPosition = (nsStylePosition*) - kidStyleContext->GetData(kStylePositionSID); - - // See what display mode it has - nsIFrame* kidFrame; - nsIContentDelegate* del; - if (NS_STYLE_POSITION_ABSOLUTE == kidPosition->mPosition) { - AbsoluteFrame::NewFrame(&kidFrame, kid, kidIndex, this); - } else { - switch (kidDisplay->mDisplay) { - case NS_STYLE_DISPLAY_NONE: - // Create place holder frame - nsFrame::NewFrame(&kidFrame, kid, kidIndex, this); - kidFrame->SetStyleContext(aPresContext,kidStyleContext); - - // Append it to the child list - if (nsnull == prevKidFrame) { - mFirstChild = kidFrame; - mFirstContentOffset = kidIndex; - } else { - prevKidFrame->SetNextSibling(kidFrame); - } - mChildCount++; - prevKidFrame = kidFrame; - pseudoFrame = nsnull; - kidIndex++; - mLastContentOffset = kidIndex; - break; - - case NS_STYLE_DISPLAY_BLOCK: - case NS_STYLE_DISPLAY_LIST_ITEM: - // Block and list-item's don't go into our pseudo-frames - // therefore we just make a frame. - del = kid->GetDelegate(aPresContext); - kidFrame = del->CreateFrame(aPresContext, kid, kidIndex, this); - NS_RELEASE(del); - kidFrame->SetStyleContext(aPresContext,kidStyleContext); - - // Append it to the child list - if (nsnull == prevKidFrame) { - mFirstChild = kidFrame; - mFirstContentOffset = kidIndex; - } else { - prevKidFrame->SetNextSibling(kidFrame); - } - mChildCount++; - prevKidFrame = kidFrame; - pseudoFrame = nsnull; - kidIndex++; - mLastContentOffset = kidIndex; - break; - - case NS_STYLE_DISPLAY_INLINE: - if (nsnull == pseudoFrame) { - // Inline elements are wrapped in a block pseudo frame; that - // way the body doesn't have to deal with 2D layout - nsBlockFrame::NewFrame(&kidFrame, mContent, mIndexInParent, this); - - // Resolve style for the pseudo-frame (kid's style won't do) - kidStyleContext = aPresContext->ResolveStyleContextFor(mContent, this); - kidFrame->SetStyleContext(aPresContext,kidStyleContext); - - // Append the pseudo frame to the child list - pseudoFrame = (nsBlockFrame*) kidFrame; - if (nsnull == prevKidFrame) { - mFirstChild = kidFrame; - mFirstContentOffset = kidIndex; - } else { - prevKidFrame->SetNextSibling(pseudoFrame); - } - mChildCount++; - - // Set the content offset for the pseudo frame, so it knows - // which content to begin with - pseudoFrame->SetFirstContentOffset(kidIndex); - pseudoFrame->SetLastContentOffset(kidIndex); - prevKidFrame = pseudoFrame; - } - - // The child frame needs to belong to the pseudo-frame (or one - // of it's pseudos). Let it do the content appended frame - // creation. - pseudoFrame->ContentAppended(aShell, aPresContext, aContainer); - - // Update *our* last content offset since this child is our last - // child and it just consumed one or more of the appended - // children. - #ifdef NS_DEBUG - if (pseudoFrame == mFirstChild) { - PRInt32 pfco = pseudoFrame->GetFirstContentOffset(); - NS_ASSERTION(mFirstContentOffset == pfco, "bad pseudo first offset"); - } - #endif - mLastContentOffset = pseudoFrame->GetLastContentOffset(); - - // Pick up where it stopped - kidIndex = NextChildOffset(); - break; - } - } - } - SetLastContentOffset(prevKidFrame); - // Note: Column frames *never* directly generate reflow commands - // because they are always pseudo-frames for bodies. -#endif - return NS_OK; } NS_METHOD ColumnFrame::CreateContinuingFrame(nsIPresContext* aPresContext, diff --git a/layout/html/base/src/nsColumnFrame.h b/layout/html/base/src/nsColumnFrame.h index 148abb9e67a..f5234702511 100644 --- a/layout/html/base/src/nsColumnFrame.h +++ b/layout/html/base/src/nsColumnFrame.h @@ -47,14 +47,14 @@ public: nsReflowCommand& aReflowCommand, ReflowStatus& aStatus); - NS_IMETHOD ContentAppended(nsIPresShell* aShell, - nsIPresContext* aPresContext, - nsIContent* aContainer); - NS_IMETHOD CreateContinuingFrame(nsIPresContext* aPresContext, nsIFrame* aParent, nsIFrame*& aContinuingFrame); + NS_IMETHOD ColumnFrame::ContentAppended(nsIPresShell* aShell, + nsIPresContext* aPresContext, + nsIContent* aContainer); + // Debugging NS_IMETHOD ListTag(FILE* out = stdout) const; diff --git a/layout/html/base/src/nsHTMLContainerFrame.cpp b/layout/html/base/src/nsHTMLContainerFrame.cpp index 7ea228ca7b2..f85fe800b8d 100644 --- a/layout/html/base/src/nsHTMLContainerFrame.cpp +++ b/layout/html/base/src/nsHTMLContainerFrame.cpp @@ -18,6 +18,7 @@ #include "nsHTMLContainerFrame.h" #include "nsIRenderingContext.h" #include "nsIPresContext.h" +#include "nsIPresShell.h" #include "nsIStyleContext.h" #include "nsStyleConsts.h" #include "nsCSSRendering.h" @@ -29,6 +30,7 @@ #include "nsGUIEvent.h" #include "nsIDocument.h" #include "nsIURL.h" +#include "nsReflowCommand.h" static NS_DEFINE_IID(kStyleBorderSID, NS_STYLEBORDER_SID); static NS_DEFINE_IID(kStyleColorSID, NS_STYLECOLOR_SID); @@ -170,6 +172,40 @@ NS_METHOD nsHTMLContainerFrame::GetCursorAt(nsIPresContext& aPresContext, return NS_OK; } +NS_METHOD nsHTMLContainerFrame::ContentAppended(nsIPresShell* aShell, + nsIPresContext* aPresContext, + nsIContent* aContainer) +{ + // Get the last-in-flow + nsHTMLContainerFrame* lastInFlow = (nsHTMLContainerFrame*)GetLastInFlow(); + + // Generate a reflow command for the frame + nsReflowCommand* cmd = new nsReflowCommand(aPresContext, lastInFlow, + nsReflowCommand::FrameAppended); + aShell->AppendReflowCommand(cmd); + return NS_OK; +} + +#if 0 +void nsHTMLContainerFrame::AdjustIndexInParents(nsIContent* aChild, + PRInt32 aIndexInParent, + ContentChange aChange) +{ + // Walk each child +} + +NS_METHOD nsHTMLContainerFrame::ContentInserted(nsIPresShell* aShell, + nsIPresContext* aPresContext, + nsIContent* aContainer, + nsIContent* aChild, + PRInt32 aIndexInParent) +{ + // Adjust the index-in-parent of each frame that follows the child that was + // inserted + AdjustIndexInParents(aChild, aIndexInParent, ContentInserted); +} +#endif + #if 0 nsIFrame::ReflowStatus nsHTMLContainerFrame::IncrementalReflow(nsIPresContext* aPresContext, diff --git a/layout/html/base/src/nsHTMLContainerFrame.h b/layout/html/base/src/nsHTMLContainerFrame.h index 0d2d6879e04..e89ab1a5182 100644 --- a/layout/html/base/src/nsHTMLContainerFrame.h +++ b/layout/html/base/src/nsHTMLContainerFrame.h @@ -42,6 +42,10 @@ public: nsIFrame** aFrame, PRInt32& aCursor); + NS_IMETHOD ContentAppended(nsIPresShell* aShell, + nsIPresContext* aPresContext, + nsIContent* aContainer); + protected: virtual ~nsHTMLContainerFrame(); diff --git a/layout/html/base/src/nsInlineFrame.cpp b/layout/html/base/src/nsInlineFrame.cpp index 9cd92de6cf5..c87f53b3f2e 100644 --- a/layout/html/base/src/nsInlineFrame.cpp +++ b/layout/html/base/src/nsInlineFrame.cpp @@ -1029,49 +1029,3 @@ nsInlineFrame::AdjustChildren(nsIPresContext* aPresContext, return frComplete; } - -// My container has new content at the end of it. Create frames for -// the appended content and then generate an incremental reflow -// command for ourselves. -NS_METHOD nsInlineFrame::ContentAppended(nsIPresShell* aShell, - nsIPresContext* aPresContext, - nsIContent* aContainer) -{ - // Get the last in flow - nsInlineFrame* flow = (nsInlineFrame*)GetLastInFlow(); - - // Get index of where the content has been appended - PRInt32 kidIndex = flow->NextChildOffset(); - PRInt32 startIndex = kidIndex; - nsIFrame* prevKidFrame; - - flow->LastChild(prevKidFrame); - // Create frames for each new child - for (;;) { - // Get the next content object - nsIContent* kid = mContent->ChildAt(kidIndex); - if (nsnull == kid) { - break; - } - - nsIContentDelegate* del = kid->GetDelegate(aPresContext); - nsIFrame* kidFrame = del->CreateFrame(aPresContext, kid, kidIndex, flow); - NS_RELEASE(del); - NS_RELEASE(kid); - - // Append kidFrame to the sibling list - prevKidFrame->SetNextSibling(kidFrame); - prevKidFrame = kidFrame; - kidIndex++; - } - flow->SetLastContentOffset(prevKidFrame); - - // Now generate a reflow command for flow - if (aContainer == mContent) { - nsReflowCommand* rc = - new nsReflowCommand(aPresContext, flow, nsReflowCommand::FrameAppended, - startIndex); - aShell->AppendReflowCommand(rc); - } - return NS_OK; -} diff --git a/layout/html/base/src/nsLineLayout.cpp b/layout/html/base/src/nsLineLayout.cpp index d3ec7ec2786..77f58c2a536 100644 --- a/layout/html/base/src/nsLineLayout.cpp +++ b/layout/html/base/src/nsLineLayout.cpp @@ -200,7 +200,10 @@ nsLineLayout::nsLineLayout(nsBlockReflowState& aState) mSpaceManager = aState.mSpaceManager; mBlock->GetContent(mBlockContent); mPresContext = aState.mPresContext; +#if 0 + // XXX Do we still need this? mBlockIsPseudo = aState.mBlockIsPseudo; +#endif mUnconstrainedWidth = aState.mUnconstrainedWidth; mUnconstrainedHeight = aState.mUnconstrainedHeight; mMaxElementSizePointer = aState.mMaxElementSizePointer; @@ -856,6 +859,9 @@ nsLineLayout::CreateFrameFor(nsIContent* aKid) switch (kidDisplay->mDisplay) { case NS_STYLE_DISPLAY_BLOCK: case NS_STYLE_DISPLAY_LIST_ITEM: +#if 0 + // XXX Do we still need this? Now that the body code is changed it + // causes a problem... if (mBlockIsPseudo) { // Don't create the frame! It doesn't belong in us. @@ -864,6 +870,7 @@ nsLineLayout::CreateFrameFor(nsIContent* aKid) return NS_LINE_LAYOUT_PSEUDO_BREAK_BEFORE_BLOCK; } +#endif kidDel = aKid->GetDelegate(mPresContext); kidFrame = kidDel->CreateFrame(mPresContext, aKid, mKidIndex, mBlock); NS_RELEASE(kidDel); diff --git a/layout/html/base/src/nsLineLayout.h b/layout/html/base/src/nsLineLayout.h index 575eaa8159d..953bc670ff6 100644 --- a/layout/html/base/src/nsLineLayout.h +++ b/layout/html/base/src/nsLineLayout.h @@ -106,7 +106,10 @@ struct nsLineLayout { // The block behind the line nsBlockFrame* mBlock; nsISpaceManager* mSpaceManager; +#if 0 + // XXX I don't think we need this anymore... PRBool mBlockIsPseudo; +#endif nsIContent* mBlockContent; PRInt32 mKidIndex; diff --git a/layout/html/table/src/nsTableCellFrame.cpp b/layout/html/table/src/nsTableCellFrame.cpp index 4a42e1fb09e..4e614cda8f9 100644 --- a/layout/html/table/src/nsTableCellFrame.cpp +++ b/layout/html/table/src/nsTableCellFrame.cpp @@ -30,7 +30,7 @@ #ifdef NS_DEBUG static PRBool gsDebug = PR_FALSE; -#define NOISY_STYLE +//#define NOISY_STYLE //#define NOISY_FLOW #else static const PRBool gsDebug = PR_FALSE; diff --git a/layout/tables/nsTableCellFrame.cpp b/layout/tables/nsTableCellFrame.cpp index 4a42e1fb09e..4e614cda8f9 100644 --- a/layout/tables/nsTableCellFrame.cpp +++ b/layout/tables/nsTableCellFrame.cpp @@ -30,7 +30,7 @@ #ifdef NS_DEBUG static PRBool gsDebug = PR_FALSE; -#define NOISY_STYLE +//#define NOISY_STYLE //#define NOISY_FLOW #else static const PRBool gsDebug = PR_FALSE;