diff --git a/mozilla/layout/base/public/nsIFrame.h b/mozilla/layout/base/public/nsIFrame.h index 23a67da613c..2546d163b9b 100644 --- a/mozilla/layout/base/public/nsIFrame.h +++ b/mozilla/layout/base/public/nsIFrame.h @@ -209,6 +209,10 @@ typedef PRUint32 nsFrameState; // If this bit is set the frame has descendant with a view #define NS_FRAME_HAS_CHILD_WITH_VIEW 0x00040000 +// If this bit is set, then reflow may be dispatched from the current +// frame instead of the root frame. +#define NS_FRAME_REFLOW_ROOT 0x00080000 + // The lower 20 bits of the frame state word are reserved by this API. #define NS_FRAME_RESERVED 0x000FFFFF diff --git a/mozilla/layout/generic/nsBlockFrame.cpp b/mozilla/layout/generic/nsBlockFrame.cpp index 0b859c4021b..0ae0ea021ac 100644 --- a/mozilla/layout/generic/nsBlockFrame.cpp +++ b/mozilla/layout/generic/nsBlockFrame.cpp @@ -845,24 +845,21 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext, NS_ASSERTION(NS_SUCCEEDED(rv), "reflow dirty lines failed"); if (NS_FAILED(rv)) return rv; - if (!state.GetFlag(BRS_ISINLINEINCRREFLOW)) { - // XXXwaterson are we sure we don't need to do this work if BRS_ISINLINEINCRREFLOW? - aStatus = state.mReflowStatus; - if (NS_FRAME_IS_NOT_COMPLETE(aStatus)) { - if (NS_STYLE_OVERFLOW_HIDDEN == aReflowState.mStyleDisplay->mOverflow) { - aStatus = NS_FRAME_COMPLETE; - } - else { -#ifdef DEBUG_kipp - ListTag(stdout); printf(": block is not complete\n"); -#endif - } + aStatus = state.mReflowStatus; + if (NS_FRAME_IS_NOT_COMPLETE(aStatus)) { + if (NS_STYLE_OVERFLOW_HIDDEN == aReflowState.mStyleDisplay->mOverflow) { + aStatus = NS_FRAME_COMPLETE; + } + else { +#ifdef DEBUG_kipp + ListTag(stdout); printf(": block is not complete\n"); +#endif } - - // XXX_perf get rid of this! This is one of the things that makes - // incremental reflow O(N^2). - BuildFloaterList(); } + + // XXX_perf get rid of this! This is one of the things that makes + // incremental reflow O(N^2). + BuildFloaterList(); // Compute our final size ComputeFinalSize(aReflowState, state, aMetrics); @@ -919,10 +916,7 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext, // If this is an incremental reflow and we changed size, then make sure our // border is repainted if necessary - // - // XXXwaterson are we sure we can skip this if BRS_ISINLINEINCRREFLOW? - if (!state.GetFlag(BRS_ISINLINEINCRREFLOW) && - (eReflowReason_Incremental == aReflowState.reason || + if ((eReflowReason_Incremental == aReflowState.reason || eReflowReason_Dirty == aReflowState.reason)) { if (isStyleChange) { // This is only true if it's a style change reflow targeted at this @@ -1005,10 +999,7 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext, // Let the absolutely positioned container reflow any absolutely positioned // child frames that need to be reflowed, e.g., elements with a percentage // based width/height - // - // XXXwaterson are we sure we can skip this if BRS_ISINLINEINCRREFLOW? - if (NS_SUCCEEDED(rv) && mAbsoluteContainer.HasAbsoluteFrames() - && !state.GetFlag(BRS_ISINLINEINCRREFLOW)) { + if (NS_SUCCEEDED(rv) && mAbsoluteContainer.HasAbsoluteFrames()) { nscoord containingBlockWidth; nscoord containingBlockHeight; nsRect childBounds; @@ -1576,8 +1567,6 @@ nsBlockFrame::PrepareChildIncrementalReflow(nsBlockReflowState& aState) } if (line->IsInline()) { - aState.SetFlag(BRS_ISINLINEINCRREFLOW, PR_TRUE); - if (aState.GetFlag(BRS_COMPUTEMAXWIDTH)) { // We've been asked to compute the maximum width of the block // frame, which ReflowLine() will handle this by performing an @@ -2131,9 +2120,8 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState) aState.mReflowState.reflowCommand->GetType(type); IndentBy(stdout, gNoiseIndent); ListTag(stdout); - printf(": incrementally reflowing dirty lines: type=%s(%d) isInline=%s", - kReflowCommandType[type], type, - aState.GetFlag(BRS_ISINLINEINCRREFLOW) ? "true" : "false"); + printf(": incrementally reflowing dirty lines: type=%s(%d)", + kReflowCommandType[type], type); } else { IndentBy(stdout, gNoiseIndent); diff --git a/mozilla/layout/generic/nsBlockReflowState.cpp b/mozilla/layout/generic/nsBlockReflowState.cpp index bc54241b672..06ec84c67a0 100644 --- a/mozilla/layout/generic/nsBlockReflowState.cpp +++ b/mozilla/layout/generic/nsBlockReflowState.cpp @@ -176,8 +176,6 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState, mMinLineHeight = nsHTMLReflowState::CalcLineHeight(mPresContext, aReflowState.rendContext, aReflowState.frame); - - SetFlag(BRS_DAMAGECONSTRAINED, IsIncrementalDamageConstrained(aFrame)); } nsBlockReflowState::~nsBlockReflowState() @@ -190,32 +188,6 @@ nsBlockReflowState::~nsBlockReflowState() } } -PRBool -nsBlockReflowState::IsIncrementalDamageConstrained(nsIFrame* aBlockFrame) const -{ - // see if the reflow will go through a text control. if so, we can optimize - // because we know the text control won't change size. - if ((eReflowReason_Incremental == mReflowState.reason) && (mReflowState.reflowCommand)) { - nsIFrame* target; - mReflowState.reflowCommand->GetTarget(target); - while (target) { - // starting with the target's parent, scan for a text control - nsIFrame* parent; - target->GetParent(&parent); - if ((aBlockFrame == parent) || !parent) // the null check is paranoia, it should never happen - break; // we found the block, so we know there's no text control between the block and target - nsCOMPtr frameType; - parent->GetFrameType(getter_AddRefs(frameType)); - if (frameType) { - if (nsLayoutAtoms::textInputFrame == frameType.get()) - return PR_TRUE; // damage is constrained to the text control innards - } - target = parent; // advance the loop up the frame tree - } - } - return PR_FALSE; // default case, damage is not constrained (or unknown) -} - nsLineBox* nsBlockReflowState::NewLineBox(nsIFrame* aFrame, PRInt32 aCount, diff --git a/mozilla/layout/generic/nsBlockReflowState.h b/mozilla/layout/generic/nsBlockReflowState.h index 58918bf0965..34c87a26e77 100644 --- a/mozilla/layout/generic/nsBlockReflowState.h +++ b/mozilla/layout/generic/nsBlockReflowState.h @@ -112,10 +112,6 @@ public: protected: void RecoverFloaters(nsLineList::iterator aLine, nscoord aDeltaY); - // return PR_TRUE if the incremental reflow is 100% contained - // within the bounds of an ancestor frame, relative to aBlockFrame - PRBool IsIncrementalDamageConstrained(nsIFrame* aBlockFrame) const; - public: void RecoverStateFrom(nsLineList::iterator aLine, nscoord aDeltaY); @@ -248,14 +244,13 @@ public: #define BRS_UNCONSTRAINEDHEIGHT 0x00000002 #define BRS_SHRINKWRAPWIDTH 0x00000004 #define BRS_NEEDRESIZEREFLOW 0x00000008 -#define BRS_ISINLINEINCRREFLOW 0x00000010 -#define BRS_NOWRAP 0x00000020 -#define BRS_ISTOPMARGINROOT 0x00000040 // Is this frame a root for top/bottom margin collapsing? -#define BRS_ISBOTTOMMARGINROOT 0x00000080 -#define BRS_APPLYTOPMARGIN 0x00000100 // See ShouldApplyTopMargin -#define BRS_COMPUTEMAXELEMENTSIZE 0x00000200 -#define BRS_COMPUTEMAXWIDTH 0x00000400 -#define BRS_DAMAGECONSTRAINED 0x00000800 // is the target of an incremental reflow command inside a text control +#define BRS_NOWRAP 0x00000010 +#define BRS_ISTOPMARGINROOT 0x00000020 // Is this frame a root for top/bottom margin collapsing? +#define BRS_ISBOTTOMMARGINROOT 0x00000040 +#define BRS_APPLYTOPMARGIN 0x00000080 // See ShouldApplyTopMargin +#define BRS_COMPUTEMAXELEMENTSIZE 0x00000100 +#define BRS_COMPUTEMAXWIDTH 0x00000200 +#define BRS_DAMAGECONSTRAINED 0x00000400 // is the target of an incremental reflow command inside a text control #define BRS_LASTFLAG BRS_DAMAGECONSTRAINED PRInt16 mFlags; diff --git a/mozilla/layout/generic/nsHTMLReflowCommand.cpp b/mozilla/layout/generic/nsHTMLReflowCommand.cpp index 14c7e811611..24be6e2b877 100644 --- a/mozilla/layout/generic/nsHTMLReflowCommand.cpp +++ b/mozilla/layout/generic/nsHTMLReflowCommand.cpp @@ -46,7 +46,7 @@ #include "nsHTMLIIDs.h" #include "nsFrame.h" #include "nsContainerFrame.h" - +#include "nsLayoutAtoms.h" nsresult NS_NewHTMLReflowCommand(nsHTMLReflowCommand** aInstancePtrResult, @@ -144,13 +144,6 @@ nsHTMLReflowCommand::~nsHTMLReflowCommand() NS_IF_RELEASE(mListName); } -nsIFrame* nsHTMLReflowCommand::GetContainingBlock(nsIFrame* aFloater) const -{ - nsIFrame* containingBlock; - aFloater->GetParent(&containingBlock); - return containingBlock; -} - void nsHTMLReflowCommand::BuildPath() { #ifdef DEBUG_jesup @@ -164,22 +157,15 @@ void nsHTMLReflowCommand::BuildPath() mPath.Clear(); - // Floating frames are handled differently. The path goes from the target - // frame to the containing block, and then up the hierarchy - const nsStyleDisplay* display; - mTargetFrame->GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&)display); - if (NS_STYLE_FLOAT_NONE != display->mFloats) { - mPath.AppendElement((void*)mTargetFrame); - - for (nsIFrame* f = GetContainingBlock(mTargetFrame); nsnull != f; f->GetParent(&f)) { - mPath.AppendElement((void*)f); - } - - } else { - for (nsIFrame* f = mTargetFrame; nsnull != f; f->GetParent(&f)) { - mPath.AppendElement((void*)f); - } - } + // Construct the reflow path by walking up the through the frames' + // parent chain until we reach either a `reflow root' or the root + // frame in the frame hierarchy. + nsIFrame *f = mTargetFrame; + nsFrameState state; + do { + mPath.AppendElement(f); + f->GetFrameState(&state); + } while (!(state & NS_FRAME_REFLOW_ROOT) && (f->GetParent(&f), f != nsnull)); } nsresult @@ -188,41 +174,61 @@ nsHTMLReflowCommand::Dispatch(nsIPresContext* aPresContext, const nsSize& aMaxSize, nsIRenderingContext& aRendContext) { - // Build the path from the target frame (index 0) to the root frame + // Build the path from the target frame (index 0) BuildPath(); - // Send an incremental reflow notification to the root frame - nsIFrame* root = (nsIFrame*)mPath[mPath.Count() - 1]; + // Send an incremental reflow notification to the first frame in the + // path. + nsIFrame* first = (nsIFrame*)mPath[mPath.Count() - 1]; -#ifdef NS_DEBUG nsCOMPtr shell; aPresContext->GetShell(getter_AddRefs(shell)); - if (shell) { - nsIFrame* rootFrame; - shell->GetRootFrame(&rootFrame); - NS_ASSERTION(rootFrame == root, "bad root frame"); - } -#endif - if (nsnull != root) { - mPath.RemoveElementAt(mPath.Count() - 1); + nsIFrame* root; + shell->GetRootFrame(&root); - nsHTMLReflowState reflowState(aPresContext, root, *this, - &aRendContext, aMaxSize); - nsReflowStatus status; + // Remove the first frame from the path and reflow it. + mPath.RemoveElementAt(mPath.Count() - 1); - root->WillReflow(aPresContext); - nsContainerFrame::PositionFrameView(aPresContext, root); - root->Reflow(aPresContext, aDesiredSize, reflowState, status); - root->SizeTo(aPresContext, aDesiredSize.width, aDesiredSize.height); - nsIView* view; - root->GetView(aPresContext, &view); - if (view) { - nsContainerFrame::SyncFrameViewAfterReflow(aPresContext, root, view, - nsnull); - } - root->DidReflow(aPresContext, nsnull, NS_FRAME_REFLOW_FINISHED); - } + first->WillReflow(aPresContext); + nsContainerFrame::PositionFrameView(aPresContext, first); + + // If the first frame in the path is the root of the frame + // hierarchy, then use all the available space. If it's simply a + // `reflow root', then use the first frame's size as the available + // space. + // + // XXXwaterson Beware that this is not sufficiently general to allow + // arbitrary frames to be reflow roots. For example, and inline + // frame cannot be a reflow root because nsHTMLReflowState::Init() + // will try to walk up through the reflow state chain to find the + // containing block. + nsSize size; + if (first == root) + size = aMaxSize; + else + first->GetSize(size); + + nsHTMLReflowState reflowState(aPresContext, first, *this, + &aRendContext, size); + + nsReflowStatus status; + first->Reflow(aPresContext, aDesiredSize, reflowState, status); + + // If an incremental reflow is initiated at a frame other than the + // root frame, then its desired size had better not change! + NS_ASSERTION(first == root || + (aDesiredSize.width == size.width && aDesiredSize.height == size.height), + "non-root frame's desired size changed during an incremental reflow"); + + first->SizeTo(aPresContext, aDesiredSize.width, aDesiredSize.height); + + nsIView* view; + first->GetView(aPresContext, &view); + if (view) + nsContainerFrame::SyncFrameViewAfterReflow(aPresContext, first, view, nsnull); + + first->DidReflow(aPresContext, nsnull, NS_FRAME_REFLOW_FINISHED); return NS_OK; } @@ -344,17 +350,8 @@ nsHTMLReflowCommand::List(FILE* out) const // Show the path, but without using mPath which is in an undefined // state at this point. if (mTargetFrame) { - // Floating frames are handled differently. The path goes from the target - // frame to the containing block, and then up the hierarchy PRBool didOne = PR_FALSE; - nsIFrame* start = mTargetFrame; - const nsStyleDisplay* display; - mTargetFrame->GetStyleData(eStyleStruct_Display, - (const nsStyleStruct*&) display); - if (NS_STYLE_FLOAT_NONE != display->mFloats) { - start = GetContainingBlock(mTargetFrame); - } - for (nsIFrame* f = start; nsnull != f; f->GetParent(&f)) { + for (nsIFrame* f = mTargetFrame; nsnull != f; f->GetParent(&f)) { if (f != mTargetFrame) { fprintf(out, " "); nsFrame::ListTag(out, f); diff --git a/mozilla/layout/generic/nsHTMLReflowCommand.h b/mozilla/layout/generic/nsHTMLReflowCommand.h index 69d4e039249..e486321c6b8 100644 --- a/mozilla/layout/generic/nsHTMLReflowCommand.h +++ b/mozilla/layout/generic/nsHTMLReflowCommand.h @@ -175,7 +175,6 @@ public: protected: void BuildPath(); - nsIFrame* GetContainingBlock(nsIFrame* aFloater) const; private: nsReflowType mType; diff --git a/mozilla/layout/generic/nsIFrame.h b/mozilla/layout/generic/nsIFrame.h index 23a67da613c..2546d163b9b 100644 --- a/mozilla/layout/generic/nsIFrame.h +++ b/mozilla/layout/generic/nsIFrame.h @@ -209,6 +209,10 @@ typedef PRUint32 nsFrameState; // If this bit is set the frame has descendant with a view #define NS_FRAME_HAS_CHILD_WITH_VIEW 0x00040000 +// If this bit is set, then reflow may be dispatched from the current +// frame instead of the root frame. +#define NS_FRAME_REFLOW_ROOT 0x00080000 + // The lower 20 bits of the frame state word are reserved by this API. #define NS_FRAME_RESERVED 0x000FFFFF diff --git a/mozilla/layout/html/base/src/nsBlockFrame.cpp b/mozilla/layout/html/base/src/nsBlockFrame.cpp index 0b859c4021b..0ae0ea021ac 100644 --- a/mozilla/layout/html/base/src/nsBlockFrame.cpp +++ b/mozilla/layout/html/base/src/nsBlockFrame.cpp @@ -845,24 +845,21 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext, NS_ASSERTION(NS_SUCCEEDED(rv), "reflow dirty lines failed"); if (NS_FAILED(rv)) return rv; - if (!state.GetFlag(BRS_ISINLINEINCRREFLOW)) { - // XXXwaterson are we sure we don't need to do this work if BRS_ISINLINEINCRREFLOW? - aStatus = state.mReflowStatus; - if (NS_FRAME_IS_NOT_COMPLETE(aStatus)) { - if (NS_STYLE_OVERFLOW_HIDDEN == aReflowState.mStyleDisplay->mOverflow) { - aStatus = NS_FRAME_COMPLETE; - } - else { -#ifdef DEBUG_kipp - ListTag(stdout); printf(": block is not complete\n"); -#endif - } + aStatus = state.mReflowStatus; + if (NS_FRAME_IS_NOT_COMPLETE(aStatus)) { + if (NS_STYLE_OVERFLOW_HIDDEN == aReflowState.mStyleDisplay->mOverflow) { + aStatus = NS_FRAME_COMPLETE; + } + else { +#ifdef DEBUG_kipp + ListTag(stdout); printf(": block is not complete\n"); +#endif } - - // XXX_perf get rid of this! This is one of the things that makes - // incremental reflow O(N^2). - BuildFloaterList(); } + + // XXX_perf get rid of this! This is one of the things that makes + // incremental reflow O(N^2). + BuildFloaterList(); // Compute our final size ComputeFinalSize(aReflowState, state, aMetrics); @@ -919,10 +916,7 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext, // If this is an incremental reflow and we changed size, then make sure our // border is repainted if necessary - // - // XXXwaterson are we sure we can skip this if BRS_ISINLINEINCRREFLOW? - if (!state.GetFlag(BRS_ISINLINEINCRREFLOW) && - (eReflowReason_Incremental == aReflowState.reason || + if ((eReflowReason_Incremental == aReflowState.reason || eReflowReason_Dirty == aReflowState.reason)) { if (isStyleChange) { // This is only true if it's a style change reflow targeted at this @@ -1005,10 +999,7 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext, // Let the absolutely positioned container reflow any absolutely positioned // child frames that need to be reflowed, e.g., elements with a percentage // based width/height - // - // XXXwaterson are we sure we can skip this if BRS_ISINLINEINCRREFLOW? - if (NS_SUCCEEDED(rv) && mAbsoluteContainer.HasAbsoluteFrames() - && !state.GetFlag(BRS_ISINLINEINCRREFLOW)) { + if (NS_SUCCEEDED(rv) && mAbsoluteContainer.HasAbsoluteFrames()) { nscoord containingBlockWidth; nscoord containingBlockHeight; nsRect childBounds; @@ -1576,8 +1567,6 @@ nsBlockFrame::PrepareChildIncrementalReflow(nsBlockReflowState& aState) } if (line->IsInline()) { - aState.SetFlag(BRS_ISINLINEINCRREFLOW, PR_TRUE); - if (aState.GetFlag(BRS_COMPUTEMAXWIDTH)) { // We've been asked to compute the maximum width of the block // frame, which ReflowLine() will handle this by performing an @@ -2131,9 +2120,8 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState) aState.mReflowState.reflowCommand->GetType(type); IndentBy(stdout, gNoiseIndent); ListTag(stdout); - printf(": incrementally reflowing dirty lines: type=%s(%d) isInline=%s", - kReflowCommandType[type], type, - aState.GetFlag(BRS_ISINLINEINCRREFLOW) ? "true" : "false"); + printf(": incrementally reflowing dirty lines: type=%s(%d)", + kReflowCommandType[type], type); } else { IndentBy(stdout, gNoiseIndent); diff --git a/mozilla/layout/html/base/src/nsBlockReflowState.cpp b/mozilla/layout/html/base/src/nsBlockReflowState.cpp index bc54241b672..06ec84c67a0 100644 --- a/mozilla/layout/html/base/src/nsBlockReflowState.cpp +++ b/mozilla/layout/html/base/src/nsBlockReflowState.cpp @@ -176,8 +176,6 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState, mMinLineHeight = nsHTMLReflowState::CalcLineHeight(mPresContext, aReflowState.rendContext, aReflowState.frame); - - SetFlag(BRS_DAMAGECONSTRAINED, IsIncrementalDamageConstrained(aFrame)); } nsBlockReflowState::~nsBlockReflowState() @@ -190,32 +188,6 @@ nsBlockReflowState::~nsBlockReflowState() } } -PRBool -nsBlockReflowState::IsIncrementalDamageConstrained(nsIFrame* aBlockFrame) const -{ - // see if the reflow will go through a text control. if so, we can optimize - // because we know the text control won't change size. - if ((eReflowReason_Incremental == mReflowState.reason) && (mReflowState.reflowCommand)) { - nsIFrame* target; - mReflowState.reflowCommand->GetTarget(target); - while (target) { - // starting with the target's parent, scan for a text control - nsIFrame* parent; - target->GetParent(&parent); - if ((aBlockFrame == parent) || !parent) // the null check is paranoia, it should never happen - break; // we found the block, so we know there's no text control between the block and target - nsCOMPtr frameType; - parent->GetFrameType(getter_AddRefs(frameType)); - if (frameType) { - if (nsLayoutAtoms::textInputFrame == frameType.get()) - return PR_TRUE; // damage is constrained to the text control innards - } - target = parent; // advance the loop up the frame tree - } - } - return PR_FALSE; // default case, damage is not constrained (or unknown) -} - nsLineBox* nsBlockReflowState::NewLineBox(nsIFrame* aFrame, PRInt32 aCount, diff --git a/mozilla/layout/html/base/src/nsBlockReflowState.h b/mozilla/layout/html/base/src/nsBlockReflowState.h index 58918bf0965..34c87a26e77 100644 --- a/mozilla/layout/html/base/src/nsBlockReflowState.h +++ b/mozilla/layout/html/base/src/nsBlockReflowState.h @@ -112,10 +112,6 @@ public: protected: void RecoverFloaters(nsLineList::iterator aLine, nscoord aDeltaY); - // return PR_TRUE if the incremental reflow is 100% contained - // within the bounds of an ancestor frame, relative to aBlockFrame - PRBool IsIncrementalDamageConstrained(nsIFrame* aBlockFrame) const; - public: void RecoverStateFrom(nsLineList::iterator aLine, nscoord aDeltaY); @@ -248,14 +244,13 @@ public: #define BRS_UNCONSTRAINEDHEIGHT 0x00000002 #define BRS_SHRINKWRAPWIDTH 0x00000004 #define BRS_NEEDRESIZEREFLOW 0x00000008 -#define BRS_ISINLINEINCRREFLOW 0x00000010 -#define BRS_NOWRAP 0x00000020 -#define BRS_ISTOPMARGINROOT 0x00000040 // Is this frame a root for top/bottom margin collapsing? -#define BRS_ISBOTTOMMARGINROOT 0x00000080 -#define BRS_APPLYTOPMARGIN 0x00000100 // See ShouldApplyTopMargin -#define BRS_COMPUTEMAXELEMENTSIZE 0x00000200 -#define BRS_COMPUTEMAXWIDTH 0x00000400 -#define BRS_DAMAGECONSTRAINED 0x00000800 // is the target of an incremental reflow command inside a text control +#define BRS_NOWRAP 0x00000010 +#define BRS_ISTOPMARGINROOT 0x00000020 // Is this frame a root for top/bottom margin collapsing? +#define BRS_ISBOTTOMMARGINROOT 0x00000040 +#define BRS_APPLYTOPMARGIN 0x00000080 // See ShouldApplyTopMargin +#define BRS_COMPUTEMAXELEMENTSIZE 0x00000100 +#define BRS_COMPUTEMAXWIDTH 0x00000200 +#define BRS_DAMAGECONSTRAINED 0x00000400 // is the target of an incremental reflow command inside a text control #define BRS_LASTFLAG BRS_DAMAGECONSTRAINED PRInt16 mFlags; diff --git a/mozilla/layout/html/base/src/nsHTMLReflowCommand.cpp b/mozilla/layout/html/base/src/nsHTMLReflowCommand.cpp index 14c7e811611..24be6e2b877 100644 --- a/mozilla/layout/html/base/src/nsHTMLReflowCommand.cpp +++ b/mozilla/layout/html/base/src/nsHTMLReflowCommand.cpp @@ -46,7 +46,7 @@ #include "nsHTMLIIDs.h" #include "nsFrame.h" #include "nsContainerFrame.h" - +#include "nsLayoutAtoms.h" nsresult NS_NewHTMLReflowCommand(nsHTMLReflowCommand** aInstancePtrResult, @@ -144,13 +144,6 @@ nsHTMLReflowCommand::~nsHTMLReflowCommand() NS_IF_RELEASE(mListName); } -nsIFrame* nsHTMLReflowCommand::GetContainingBlock(nsIFrame* aFloater) const -{ - nsIFrame* containingBlock; - aFloater->GetParent(&containingBlock); - return containingBlock; -} - void nsHTMLReflowCommand::BuildPath() { #ifdef DEBUG_jesup @@ -164,22 +157,15 @@ void nsHTMLReflowCommand::BuildPath() mPath.Clear(); - // Floating frames are handled differently. The path goes from the target - // frame to the containing block, and then up the hierarchy - const nsStyleDisplay* display; - mTargetFrame->GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&)display); - if (NS_STYLE_FLOAT_NONE != display->mFloats) { - mPath.AppendElement((void*)mTargetFrame); - - for (nsIFrame* f = GetContainingBlock(mTargetFrame); nsnull != f; f->GetParent(&f)) { - mPath.AppendElement((void*)f); - } - - } else { - for (nsIFrame* f = mTargetFrame; nsnull != f; f->GetParent(&f)) { - mPath.AppendElement((void*)f); - } - } + // Construct the reflow path by walking up the through the frames' + // parent chain until we reach either a `reflow root' or the root + // frame in the frame hierarchy. + nsIFrame *f = mTargetFrame; + nsFrameState state; + do { + mPath.AppendElement(f); + f->GetFrameState(&state); + } while (!(state & NS_FRAME_REFLOW_ROOT) && (f->GetParent(&f), f != nsnull)); } nsresult @@ -188,41 +174,61 @@ nsHTMLReflowCommand::Dispatch(nsIPresContext* aPresContext, const nsSize& aMaxSize, nsIRenderingContext& aRendContext) { - // Build the path from the target frame (index 0) to the root frame + // Build the path from the target frame (index 0) BuildPath(); - // Send an incremental reflow notification to the root frame - nsIFrame* root = (nsIFrame*)mPath[mPath.Count() - 1]; + // Send an incremental reflow notification to the first frame in the + // path. + nsIFrame* first = (nsIFrame*)mPath[mPath.Count() - 1]; -#ifdef NS_DEBUG nsCOMPtr shell; aPresContext->GetShell(getter_AddRefs(shell)); - if (shell) { - nsIFrame* rootFrame; - shell->GetRootFrame(&rootFrame); - NS_ASSERTION(rootFrame == root, "bad root frame"); - } -#endif - if (nsnull != root) { - mPath.RemoveElementAt(mPath.Count() - 1); + nsIFrame* root; + shell->GetRootFrame(&root); - nsHTMLReflowState reflowState(aPresContext, root, *this, - &aRendContext, aMaxSize); - nsReflowStatus status; + // Remove the first frame from the path and reflow it. + mPath.RemoveElementAt(mPath.Count() - 1); - root->WillReflow(aPresContext); - nsContainerFrame::PositionFrameView(aPresContext, root); - root->Reflow(aPresContext, aDesiredSize, reflowState, status); - root->SizeTo(aPresContext, aDesiredSize.width, aDesiredSize.height); - nsIView* view; - root->GetView(aPresContext, &view); - if (view) { - nsContainerFrame::SyncFrameViewAfterReflow(aPresContext, root, view, - nsnull); - } - root->DidReflow(aPresContext, nsnull, NS_FRAME_REFLOW_FINISHED); - } + first->WillReflow(aPresContext); + nsContainerFrame::PositionFrameView(aPresContext, first); + + // If the first frame in the path is the root of the frame + // hierarchy, then use all the available space. If it's simply a + // `reflow root', then use the first frame's size as the available + // space. + // + // XXXwaterson Beware that this is not sufficiently general to allow + // arbitrary frames to be reflow roots. For example, and inline + // frame cannot be a reflow root because nsHTMLReflowState::Init() + // will try to walk up through the reflow state chain to find the + // containing block. + nsSize size; + if (first == root) + size = aMaxSize; + else + first->GetSize(size); + + nsHTMLReflowState reflowState(aPresContext, first, *this, + &aRendContext, size); + + nsReflowStatus status; + first->Reflow(aPresContext, aDesiredSize, reflowState, status); + + // If an incremental reflow is initiated at a frame other than the + // root frame, then its desired size had better not change! + NS_ASSERTION(first == root || + (aDesiredSize.width == size.width && aDesiredSize.height == size.height), + "non-root frame's desired size changed during an incremental reflow"); + + first->SizeTo(aPresContext, aDesiredSize.width, aDesiredSize.height); + + nsIView* view; + first->GetView(aPresContext, &view); + if (view) + nsContainerFrame::SyncFrameViewAfterReflow(aPresContext, first, view, nsnull); + + first->DidReflow(aPresContext, nsnull, NS_FRAME_REFLOW_FINISHED); return NS_OK; } @@ -344,17 +350,8 @@ nsHTMLReflowCommand::List(FILE* out) const // Show the path, but without using mPath which is in an undefined // state at this point. if (mTargetFrame) { - // Floating frames are handled differently. The path goes from the target - // frame to the containing block, and then up the hierarchy PRBool didOne = PR_FALSE; - nsIFrame* start = mTargetFrame; - const nsStyleDisplay* display; - mTargetFrame->GetStyleData(eStyleStruct_Display, - (const nsStyleStruct*&) display); - if (NS_STYLE_FLOAT_NONE != display->mFloats) { - start = GetContainingBlock(mTargetFrame); - } - for (nsIFrame* f = start; nsnull != f; f->GetParent(&f)) { + for (nsIFrame* f = mTargetFrame; nsnull != f; f->GetParent(&f)) { if (f != mTargetFrame) { fprintf(out, " "); nsFrame::ListTag(out, f); diff --git a/mozilla/layout/html/base/src/nsHTMLReflowCommand.h b/mozilla/layout/html/base/src/nsHTMLReflowCommand.h index 69d4e039249..e486321c6b8 100644 --- a/mozilla/layout/html/base/src/nsHTMLReflowCommand.h +++ b/mozilla/layout/html/base/src/nsHTMLReflowCommand.h @@ -175,7 +175,6 @@ public: protected: void BuildPath(); - nsIFrame* GetContainingBlock(nsIFrame* aFloater) const; private: nsReflowType mType; diff --git a/mozilla/layout/html/forms/src/nsGfxTextControlFrame2.cpp b/mozilla/layout/html/forms/src/nsGfxTextControlFrame2.cpp index 7f5f085a6a4..b48d0b49702 100644 --- a/mozilla/layout/html/forms/src/nsGfxTextControlFrame2.cpp +++ b/mozilla/layout/html/forms/src/nsGfxTextControlFrame2.cpp @@ -3342,6 +3342,14 @@ nsGfxTextControlFrame2::SetInitialChildList(nsIPresContext* aPresContext, nsIFrame *first; FirstChild(aPresContext,nsnull, &first); + // Mark the scroll frame as being a reflow root. This will allow + // incremental reflows to be initiated at the scroll frame, rather + // than descending from the root frame of the frame hierarchy. + nsFrameState state; + first->GetFrameState(&state); + state |= NS_FRAME_REFLOW_ROOT; + first->SetFrameState(state); + //we must turn off scrollbars for singleline text controls PRInt32 type; GetType(&type);